[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug Report\nabout: Report a bug in Context Hub CLI\nlabels: bug\n---\n\n## Description\n\nA clear description of the bug.\n\n## Steps to Reproduce\n\n1. Run `chub ...`\n2. ...\n\n## Expected Behavior\n\nWhat should happen.\n\n## Actual Behavior\n\nWhat actually happens.\n\n## Environment\n\n- OS: (e.g., macOS 15, Ubuntu 24.04)\n- Node.js version: (e.g., 22.0.0)\n- chub version: (run `chub --version`)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature Request\nabout: Suggest a new feature or improvement\nlabels: enhancement\n---\n\n## Problem\n\nWhat problem does this solve? What's the current limitation?\n\n## Proposed Solution\n\nDescribe the feature or change you'd like.\n\n## Alternatives Considered\n\nAny alternative approaches you've thought about.\n\n## Additional Context\n\nAny relevant links, screenshots, or examples.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## What\n\nBrief description of the change.\n\n## Why\n\nWhat problem does this solve?\n\n## Testing\n\n- [ ] `npm test` passes\n- [ ] `chub build sample-content/ --validate-only` succeeds\n- [ ] Manual testing done (describe below)\n\n## Notes\n\nAny additional context for reviewers.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [18, 20, 22]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n      - run: rm -f package-lock.json && npm install\n      - run: cd cli && npm test\n      - run: node cli/bin/chub build content/ --validate-only\n      - run: cd cli && npm audit --audit-level=high\n"
  },
  {
    "path": ".github/workflows/deploy-content.yml",
    "content": "name: Deploy Content to CDN\n\non:\n  push:\n    branches: [main]\n    paths:\n      - 'content/**'\n\n  # Allow manual trigger\n  workflow_dispatch:\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - run: rm -f package-lock.json && npm install\n\n      # Validate content first\n      - name: Validate content\n        run: node cli/bin/chub build content/ --validate-only\n\n      # Build registry + search index + content tree\n      - name: Build content\n        run: node cli/bin/chub build content/ -o dist/ --base-url https://cdn.aichub.org/v1\n\n      # Sync to S3\n      - name: Deploy to S3\n        run: aws s3 sync dist/ s3://${{ secrets.CDN_BUCKET_NAME }}/v1/ --delete\n        env:\n          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n          AWS_REGION: ${{ secrets.AWS_REGION }}\n\n      # Invalidate CloudFront cache\n      - name: Invalidate CloudFront cache\n        run: |\n          aws cloudfront create-invalidation \\\n            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \\\n            --paths \"/v1/*\"\n        env:\n          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n          AWS_REGION: ${{ secrets.AWS_REGION }}\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish to npm\n\non:\n  release:\n    types: [created]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      id-token: write\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 22\n          registry-url: 'https://registry.npmjs.org'\n      - run: npm install\n      - run: cd cli && npm test\n      - run: cd cli && npm publish --access public\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\n.DS_Store\ndist/\n*.log\n.env\n.env.*\ncoverage/\n.chub/\n*.tgz\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior:\n\n* The use of sexualized language or imagery and unwelcome sexual attention\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information without explicit permission\n* Other conduct which could reasonably be considered inappropriate\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by [opening a GitHub issue](https://github.com/andrewyng/context-hub/issues/new).\n\nAll complaints will be reviewed and investigated promptly and fairly.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),\nversion 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Context Hub\n\nThank you for your interest in contributing to Context Hub! This guide covers both code contributions and documentation/skill contributions.\n\n## Development Setup\n\n### Prerequisites\n\n- Node.js >= 18.0.0\n- npm (comes with Node.js)\n\n### Getting Started\n\n```bash\ngit clone https://github.com/andrewyng/context-hub.git\ncd context-hub\nnpm install\n```\n\n### Running the CLI locally\n\n```bash\nnode cli/bin/chub --help\nnode cli/bin/chub build content/ --validate-only\n```\n\n### Running Tests\n\n```bash\ncd cli\nnpm test              # run all tests\nnpm run test:watch    # watch mode\nnpm run test:coverage # with coverage\n```\n\n## Code Contributions\n\n### Pull Request Process\n\n1. Fork the repo and create a branch from `main`\n2. Make your changes\n3. Add or update tests as needed\n4. Ensure all tests pass: `cd cli && npm test`\n5. Validate the build: `node cli/bin/chub build content/ --validate-only`\n6. Submit a pull request\n\n### Code Style\n\n- ES modules (`import`/`export`, not `require`)\n- No build step — native Node.js ES modules\n- Minimal dependencies — prefer Node.js built-ins\n- Dual-mode output: every command supports `--json` for machine-readable output\n\n### Project Structure\n\n```\ncli/\n  bin/chub              # Executable entry point\n  src/\n    index.js            # CLI setup (Commander)\n    commands/           # Command implementations\n    lib/                # Core utilities\n  tests/                # Vitest tests\ncontent/                # Public content registry source\ndocs/                   # Design docs\n```\n\n## Content Contributions\n\nContext Hub is only as useful as its content. Contributing curated documentation or skills is one of the most impactful ways to help.\n\n### Contributing a Doc\n\n1. Create a directory under `<author>/docs/<name>/`\n2. Add a `DOC.md` with YAML frontmatter:\n\n```yaml\n---\nname: my-api\ndescription: Short description of what this doc covers\nmetadata:\n  languages: \"python,javascript\"\n  versions: \"1.0.0\"\n  source: community\n  tags: \"api,rest\"\n  updated-on: \"2026-02-22\"\n---\n# Content here...\n```\n\n3. Add reference files in a `references/` subdirectory if needed\n4. Validate: `chub build <content-dir> --validate-only`\n\n### Contributing a Skill\n\n1. Create a directory under `<author>/skills/<name>/`\n2. Add a `SKILL.md` with YAML frontmatter:\n\n```yaml\n---\nname: my-skill\ndescription: What this skill teaches agents to do\nmetadata:\n  source: community\n  tags: \"automation,testing\"\n  updated-on: \"2026-02-22\"\n---\n# Skill content here...\n```\n\n### Content Quality Guidelines\n\n- Write for LLMs: clear structure, code examples, explicit parameter names\n- Use progressive disclosure: entry point (DOC.md/SKILL.md) should be < 500 lines\n- Put detailed references in companion files with relative links\n- Keep content up to date with the latest API versions\n- Include practical code examples, not just API signatures\n\n## Reporting Issues\n\n- **Bugs**: Use the [bug report template](https://github.com/andrewyng/context-hub/issues/new?template=bug_report.md)\n- **Features**: Use the [feature request template](https://github.com/andrewyng/context-hub/issues/new?template=feature_request.md)\n- **Security**: See [SECURITY.md](SECURITY.md)\n\n## License\n\nBy contributing, you agree that your contributions will be licensed under the [MIT License](LICENSE).\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2026 Context Hub Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Context Hub\n\nCoding agents hallucinate APIs and forget what they learn in a session. Context Hub gives them curated, versioned docs, plus the ability to get smarter with every task. All content is open and maintained as markdown in this repo — you can inspect exactly what your agent reads, and contribute back. \n\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![npm](https://img.shields.io/npm/v/@aisuite/chub)](https://www.npmjs.com/package/@aisuite/chub)\n[![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)\n\n## Quick Start\n\n```bash\nnpm install -g @aisuite/chub\nchub search openai                 # find what's available\nchub get openai/chat --lang py     # fetch current docs (Python version) \n```\n\n## How It Works\n\nChub is designed for your coding agent to use (not for you to use!). You can prompt your agent to use it (e.g., \"Use the CLI command chub to get the latest API documentation for calling OpenAI. Run 'chub help' to understand how it works.\") Or by creating an agent skill to use Chub using [SKILL.md](cli/skills/get-api-docs/SKILL.md), and ideally prompting your agent to remember to use this skill. (If you are using Claude Code, create the directory ~/.claude/skills/get-api-docs and put SKILL.md there.) \n\n**Most of the time, it's simple — search, fetch, use:**\n\n```bash\nchub search \"stripe payments\"        # find relevant docs\nchub get stripe/api --lang js        # fetch the doc\n# Agent reads the doc, writes correct code. Done.\n```\n\n**When the agent discovers a gap**, it can annotate locally for next time:\n\n```bash\nchub annotate stripe/api \"Needs raw body for webhook verification\"\n\n# Next session, the annotation appears automatically on chub get.\n```\n\n**Feedback flows back to authors** — `chub feedback stripe/api up` or `down` — vote the docs up or down so they can get better for everyone over time.\n\n## Content Types\n\nVersioned, language-specific. \"What to know.\"\n\n```bash\nchub get openai/chat --lang py       # Python variant\nchub get openai/chat --lang js       # JavaScript variant\n```\n\nMore content types than API documentation (such as agent skills) are on the roadmap. \n\n## Commands\n\n| Command | Purpose |\n|---------|---------|\n| `chub search [query]` | Search docs and skills (no query = list all) |\n| `chub get <id> [--lang py\\|js]` | Fetch docs or skills by ID |\n| `chub annotate <id> <note>` | Attach a note to a doc or skill |\n| `chub annotate <id> --clear` | Remove annotations |\n| `chub annotate --list` | List all annotations |\n| `chub feedback <id> <up\\|down>` | Upvote or downvote a doc (sent to maintainers) |\n\nFor the full list of commands, flags, and piping patterns, see the [CLI Reference](docs/cli-reference.md).\n\n## Self-Improving Agents\n\nContext Hub is designed for a loop where agents get better over time.\n\n**Annotations** are local notes that agents attach to docs. They persist across sessions and appear automatically on future fetches — so agents learn from past experience. See [Feedback and Annotations](docs/feedback-and-annotations.md).\n\n**Feedback** (up/down ratings with optional labels) goes to doc authors, who update the content based on what's working and what isn't. The docs get better for everyone — not just your local annotations.\n\n```\n  Without Context Hub                          With Context Hub\n  ───────────────────                          ─────────────────\n  Search the web                               Fetch curated docs\n  Noisy results                                Higher chance of code working\n  Code breaks                                  Agent notes any gaps/workarounds\n  Effort in fixing                             ↗ Even smarter next session\n  Knowledge forgotten\n  ↻ Repeat next session\n```\n\n## Key Features\n\n### Incremental Fetch\n\nDocs can have multiple reference files beyond the main entry point. Fetch only what you need — no wasted tokens. Use `--file` to grab specific references, or `--full` for everything. See the [CLI Reference](docs/cli-reference.md).\n\n### Annotations & Feedback\n\nAnnotations are local notes that agents attach to docs — they persist across sessions and appear automatically on future fetches. Feedback (up/down ratings) goes to doc authors to improve the content for everyone. See [Feedback and Annotations](docs/feedback-and-annotations.md).\n\n## Contributing\n\nAnyone can contribute docs and skills — API providers, framework authors, and the community. Content is plain markdown with YAML frontmatter, submitted as pull requests. See the [Content Guide](docs/content-guide.md) for the format and structure.\n\nAgent feedback (up/down ratings from real usage) flows back to authors, helping surface what needs fixing and improving overall quality over time.\n\n## License\n\n[MIT](LICENSE)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Reporting a Vulnerability\n\nIf you discover a security vulnerability, please report it by [opening a GitHub issue](https://github.com/andrewyng/context-hub/issues/new) with the label `security`.\n\nInclude:\n\n1. A description of the vulnerability\n2. Steps to reproduce\n3. Potential impact\n4. Suggested fix (if any)\n\nWe will respond promptly and aim to provide a fix within 7 days for critical issues.\n\n## Supported Versions\n\n| Version | Supported |\n|---------|-----------|\n| 0.1.x   | Yes       |\n\n## Scope\n\nThis policy covers the `@aisuite/chub` CLI package and the Context Hub API at `api.aichub.org`.\n\n## Telemetry & Privacy\n\nContext Hub collects optional, anonymous telemetry (disabled with `telemetry: false` in `~/.chub/config.yaml`). No personally identifiable information is collected. See [DESIGN.md](docs/design.md) for details on the hashed machine identifier.\n"
  },
  {
    "path": "cli/.npmignore",
    "content": "tests/\n*.test.js\ncoverage/\n.DS_Store\n"
  },
  {
    "path": "cli/README.md",
    "content": "# Context Hub CLI\n\nInstall the CLI and give your AI agent access to curated, versioned documentation.\n\n## Install\n\n```bash\nnpm install -g @aisuite/chub\n```\n\n## Use as an Agent Skill\n\nThe CLI ships with a skill that teaches agents to fetch docs automatically instead of guessing from training data. Install it into your agent tool of choice:\n\n### Claude Code\n\nCopy the skill into your project:\n\n```bash\nmkdir -p .claude/skills\ncp $(npm root -g)/@aisuite/chub/skills/get-api-docs/SKILL.md .claude/skills/get-api-docs.md\n```\n\nOr install it globally (applies to all projects):\n\n```bash\nmkdir -p ~/.claude/skills\ncp $(npm root -g)/@aisuite/chub/skills/get-api-docs/SKILL.md ~/.claude/skills/get-api-docs.md\n```\n\n### Cursor\n\nCopy the skill into your project's rules directory:\n\n```bash\nmkdir -p .cursor/rules\ncp $(npm root -g)/@aisuite/chub/skills/get-api-docs/SKILL.md .cursor/rules/get-api-docs.md\n```\n\n### Other Agent Tools\n\nThe skill is a standard markdown file at `skills/get-api-docs/SKILL.md`. Copy it to wherever your agent tool reads custom instructions from.\n\n## Commands\n\n```bash\nchub search \"stripe\"                 # find docs\nchub get stripe/api                  # fetch a doc\nchub get stripe/api --lang js        # specific language\nchub get stripe/api --version 19.1.0 # specific version\nchub annotate stripe/api \"note\"      # local annotation\nchub feedback stripe/api up          # rate a doc\n```\n\nFor the full command reference, see [CLI Reference](../docs/cli-reference.md).\n"
  },
  {
    "path": "cli/bin/chub",
    "content": "#!/usr/bin/env node\nimport '../src/index.js';\n"
  },
  {
    "path": "cli/bin/chub-mcp",
    "content": "#!/usr/bin/env node\nimport '../src/mcp/server.js';\n"
  },
  {
    "path": "cli/package.json",
    "content": "{\n  \"name\": \"@aisuite/chub\",\n  \"version\": \"0.1.3\",\n  \"description\": \"CLI for Context Hub - search and retrieve LLM-optimized docs and skills\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"chub\": \"./bin/chub\",\n    \"chub-mcp\": \"./bin/chub-mcp\"\n  },\n  \"files\": [\n    \"bin/\",\n    \"src/\",\n    \"dist/\",\n    \"skills/\"\n  ],\n  \"engines\": {\n    \"node\": \">=18.0.0\"\n  },\n  \"keywords\": [\n    \"ai\",\n    \"llm\",\n    \"documentation\",\n    \"agent\",\n    \"cli\",\n    \"context\",\n    \"skills\",\n    \"mcp\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/andrewyng/context-hub\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/andrewyng/context-hub/issues\"\n  },\n  \"homepage\": \"https://github.com/andrewyng/context-hub#readme\",\n  \"scripts\": {\n    \"prepublish\": \"node bin/chub build ../content -o dist --base-url https://cdn.aichub.org/v1\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"test:coverage\": \"vitest run --coverage\"\n  },\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.27.1\",\n    \"chalk\": \"^5.3.0\",\n    \"commander\": \"^12.0.0\",\n    \"posthog-node\": \"^5.24.17\",\n    \"tar\": \"^7.5.8\",\n    \"yaml\": \"^2.3.0\",\n    \"zod\": \"^4.3.6\"\n  },\n  \"devDependencies\": {\n    \"vitest\": \"^4.0.18\"\n  }\n}\n"
  },
  {
    "path": "cli/skills/get-api-docs/SKILL.md",
    "content": "---\nname: get-api-docs\ndescription: >\n  Use this skill when you need documentation for a third-party library, SDK, or API\n  before writing code that uses it — for example, \"use the OpenAI API\", \"call the\n  Stripe API\", \"use the Anthropic SDK\", \"query Pinecone\", or any time the user asks\n  you to write code against an external service and you need current API reference.\n  Fetch the docs with chub before answering, rather than relying on training knowledge.\n---\n\n# Get API Docs via chub\n\nWhen you need documentation for a library or API, fetch it with the `chub` CLI\nrather than guessing from training data. This gives you the current, correct API.\n\n## Step 1 — Find the right doc ID\n\n```bash\nchub search \"<library name>\" --json\n```\n\nPick the best-matching `id` from the results (e.g. `openai/chat`, `anthropic/sdk`,\n`stripe/api`). If nothing matches, try a broader term.\n\n## Step 2 — Fetch the docs\n\n```bash\nchub get <id> --lang py    # or --lang js, --lang ts\n```\n\nOmit `--lang` if the doc has only one language variant — it will be auto-selected.\n\n## Step 3 — Use the docs\n\nRead the fetched content and use it to write accurate code or answer the question.\nDo not rely on memorized API shapes — use what the docs say.\n\n## Step 4 — Annotate what you learned\n\nAfter completing the task, if you discovered something not in the doc — a gotcha,\nworkaround, version quirk, or project-specific detail — save it so future sessions\nstart smarter:\n\n```bash\nchub annotate <id> \"Webhook verification requires raw body — do not parse before verifying\"\n```\n\nAnnotations are local, persist across sessions, and appear automatically on future\n`chub get` calls. Keep notes concise and actionable. Don't repeat what's already in\nthe doc.\n\n## Step 5 — Give feedback\n\nAlways rate the doc after using it. This helps authors fix outdated or incorrect\ndocs and prioritize improvements. Include a label and a brief comment explaining\nwhat was good or what needs fixing — specific feedback is the most valuable.\n\n```bash\nchub feedback <id> up --label accurate \"Clear examples, models are current\"\nchub feedback <id> down --label outdated \"Lists gpt-4o as latest but gpt-5.4 is out\"\n```\n\nAvailable labels: `outdated`, `inaccurate`, `incomplete`, `wrong-examples`,\n`wrong-version`, `poorly-structured`, `accurate`, `well-structured`, `helpful`,\n`good-examples`.\n\nIf you notice the doc has wrong model names, deprecated APIs, missing features,\nor incorrect code patterns, always leave a downvote with details so it can be fixed.\n\n## Quick reference\n\n| Goal | Command |\n|------|---------|\n| List everything | `chub search` |\n| Find a doc | `chub search \"stripe\"` |\n| Exact id detail | `chub search stripe/api` |\n| Fetch Python docs | `chub get stripe/api --lang py` |\n| Fetch JS docs | `chub get openai/chat --lang js` |\n| Save to file | `chub get anthropic/sdk --lang py -o docs.md` |\n| Fetch multiple | `chub get openai/chat stripe/api --lang py` |\n| Save a note | `chub annotate stripe/api \"needs raw body\"` |\n| List notes | `chub annotate --list` |\n| Rate a doc | `chub feedback stripe/api up` |\n\n## Notes\n\n- `chub search` with no query lists everything available\n- IDs are `<author>/<name>` — confirm the ID from search before fetching\n- If multiple languages exist and you don't pass `--lang`, chub will tell you which are available\n"
  },
  {
    "path": "cli/src/commands/annotate.js",
    "content": "import chalk from 'chalk';\nimport { readAnnotation, writeAnnotation, clearAnnotation, listAnnotations } from '../lib/annotations.js';\nimport { output, error, info } from '../lib/output.js';\n\nexport function registerAnnotateCommand(program) {\n  program\n    .command('annotate [id] [note]')\n    .description('Attach agent notes to a doc or skill')\n    .option('--clear', 'Remove annotation for this entry')\n    .option('--list', 'List all annotations')\n    .action((id, note, opts) => {\n      const globalOpts = program.optsWithGlobals();\n\n      if (opts.list) {\n        const annotations = listAnnotations();\n        output(\n          annotations,\n          (data) => {\n            if (data.length === 0) {\n              console.log('No annotations.');\n              return;\n            }\n            for (const a of data) {\n              console.log(`${chalk.bold(a.id)} ${chalk.dim(`(${a.updatedAt})`)}`);\n              console.log(`  ${a.note}`);\n              console.log();\n            }\n          },\n          globalOpts\n        );\n        return;\n      }\n\n      if (!id) {\n        error('Missing required argument: <id>. Run: chub annotate <id> <note> | chub annotate <id> --clear | chub annotate --list', globalOpts);\n      }\n\n      if (opts.clear) {\n        const removed = clearAnnotation(id);\n        output(\n          { id, cleared: removed },\n          (data) => {\n            if (data.cleared) {\n              console.log(`Annotation cleared for ${chalk.bold(id)}.`);\n            } else {\n              console.log(`No annotation found for ${chalk.bold(id)}.`);\n            }\n          },\n          globalOpts\n        );\n        return;\n      }\n\n      if (!note) {\n        // Show existing annotation\n        const existing = readAnnotation(id);\n        if (existing) {\n          output(\n            existing,\n            (data) => {\n              console.log(`${chalk.bold(data.id)} ${chalk.dim(`(${data.updatedAt})`)}`);\n              console.log(data.note);\n            },\n            globalOpts\n          );\n        } else {\n          output(\n            { id, note: null },\n            () => console.log(`No annotation for ${chalk.bold(id)}.`),\n            globalOpts\n          );\n        }\n        return;\n      }\n\n      const data = writeAnnotation(id, note);\n      output(\n        data,\n        (d) => console.log(`Annotation saved for ${chalk.bold(d.id)}.`),\n        globalOpts\n      );\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/build.js",
    "content": "import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, mkdirSync, cpSync } from 'node:fs';\nimport { join, relative, dirname, basename } from 'node:path';\nimport chalk from 'chalk';\nimport { parseFrontmatter } from '../lib/frontmatter.js';\nimport { info } from '../lib/output.js';\nimport { trackEvent } from '../lib/analytics.js';\nimport { buildIndex } from '../lib/bm25.js';\n\n/**\n * Normalize a path to use forward slashes so registry.json is\n * consistent regardless of which OS ran the build.\n */\nfunction toPosix(p) {\n  return p.split('\\\\').join('/');\n}\n\n/**\n * Recursively find all DOC.md and SKILL.md files under a directory.\n */\nfunction findEntryFiles(dir, base = dir) {\n  const results = [];\n  for (const entry of readdirSync(dir, { withFileTypes: true })) {\n    const full = join(dir, entry.name);\n    if (entry.isDirectory()) {\n      results.push(...findEntryFiles(full, base));\n    } else if (entry.name === 'DOC.md' || entry.name === 'SKILL.md') {\n      results.push({ path: full, relPath: relative(base, full), type: entry.name === 'SKILL.md' ? 'skill' : 'doc' });\n    }\n  }\n  return results;\n}\n\n/**\n * Get all files in a directory (relative to that directory).\n */\nfunction listDirFiles(dir) {\n  const results = [];\n  const walk = (d) => {\n    for (const entry of readdirSync(d, { withFileTypes: true })) {\n      const full = join(d, entry.name);\n      if (entry.isDirectory()) walk(full);\n      else results.push(toPosix(relative(dir, full)));\n    }\n  };\n  walk(dir);\n  return results;\n}\n\n/**\n * Compute total size of all files in a directory.\n */\nfunction dirSize(dir) {\n  let total = 0;\n  const walk = (d) => {\n    for (const entry of readdirSync(d, { withFileTypes: true })) {\n      const full = join(d, entry.name);\n      if (entry.isDirectory()) walk(full);\n      else total += statSync(full).size;\n    }\n  };\n  walk(dir);\n  return total;\n}\n\n/**\n * Process an author directory with auto-discovery.\n */\nfunction discoverAuthor(authorDir, authorName, contentDir) {\n  const entryFiles = findEntryFiles(authorDir);\n  const docs = new Map(); // name → { description, source, tags, languages: Map<lang, versions[]> }\n  const skills = new Map(); // name → skill entry\n  const warnings = [];\n  const errors = [];\n\n  for (const ef of entryFiles) {\n    const content = readFileSync(ef.path, 'utf8');\n    const { attributes } = parseFrontmatter(content);\n\n    if (!attributes.name) {\n      errors.push(`${ef.relPath}: missing 'name' in frontmatter`);\n      continue;\n    }\n    if (!attributes.description) {\n      warnings.push(`${ef.relPath}: missing 'description' in frontmatter`);\n    }\n\n    const meta = attributes.metadata || {};\n    const name = attributes.name;\n    const description = attributes.description || '';\n    const source = meta.source || 'community';\n    const tags = meta.tags ? meta.tags.split(',').map((t) => t.trim()) : [];\n    const updatedOn = meta['updated-on'] || new Date().toISOString().split('T')[0];\n    const entryDir = dirname(ef.path);\n    const entryPath = toPosix(relative(contentDir, entryDir));\n    const files = listDirFiles(entryDir);\n    const size = dirSize(entryDir);\n\n    if (!meta.source) {\n      warnings.push(`${ef.relPath}: missing 'metadata.source', defaulting to 'community'`);\n    }\n\n    if (ef.type === 'skill') {\n      // Skills are flat — no language/version\n      if (skills.has(name)) {\n        errors.push(`${ef.relPath}: duplicate skill name '${name}'`);\n        continue;\n      }\n      skills.set(name, {\n        id: `${authorName}/${name}`,\n        name,\n        description,\n        source,\n        tags,\n        path: entryPath,\n        files,\n        size,\n        lastUpdated: updatedOn,\n      });\n    } else {\n      // Docs need language and version\n      const languages = meta.languages\n        ? meta.languages.split(',').map((l) => l.trim().toLowerCase())\n        : null;\n      const versions = meta.versions\n        ? meta.versions.split(',').map((v) => v.trim())\n        : null;\n\n      if (!languages || languages.length === 0) {\n        errors.push(`${ef.relPath}: missing 'metadata.languages' in frontmatter`);\n        continue;\n      }\n      if (!versions || versions.length === 0) {\n        errors.push(`${ef.relPath}: missing 'metadata.versions' in frontmatter`);\n        continue;\n      }\n\n      if (!docs.has(name)) {\n        docs.set(name, { description, source, tags, languages: new Map() });\n      }\n\n      const doc = docs.get(name);\n\n      for (const lang of languages) {\n        if (!doc.languages.has(lang)) {\n          doc.languages.set(lang, []);\n        }\n        for (const ver of versions) {\n          doc.languages.get(lang).push({\n            version: ver,\n            path: entryPath,\n            files,\n            size,\n            lastUpdated: updatedOn,\n          });\n        }\n      }\n    }\n  }\n\n  // Convert docs map to array format\n  const docsArray = [];\n  for (const [name, doc] of docs) {\n    const languages = [];\n    for (const [lang, versions] of doc.languages) {\n      // Sort versions descending (simple string sort, good enough for semver)\n      versions.sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true }));\n      languages.push({\n        language: lang,\n        versions,\n        recommendedVersion: versions[0].version,\n      });\n    }\n    docsArray.push({\n      id: `${authorName}/${name}`,\n      name,\n      description: doc.description,\n      source: doc.source,\n      tags: doc.tags,\n      languages,\n    });\n  }\n\n  return {\n    docs: docsArray,\n    skills: [...skills.values()],\n    warnings,\n    errors,\n  };\n}\n\nexport function registerBuildCommand(program) {\n  program\n    .command('build <content-dir>')\n    .description('Build registry.json from a content directory')\n    .option('-o, --output <dir>', 'Output directory')\n    .option('--base-url <url>', 'Base URL for CDN deployment')\n    .option('--validate-only', 'Validate without writing output')\n    .action((contentDir, opts) => {\n      const globalOpts = program.optsWithGlobals();\n\n      if (!existsSync(contentDir)) {\n        process.stderr.write(`Error: Content directory not found: ${contentDir}\\n`);\n        process.exit(1);\n      }\n\n      const outputDir = opts.output || join(contentDir, 'dist');\n      const allDocs = [];\n      const allSkills = [];\n      const allWarnings = [];\n      const allErrors = [];\n\n      // List top-level directories (author directories)\n      const topLevel = readdirSync(contentDir, { withFileTypes: true })\n        .filter((e) => e.isDirectory() && e.name !== 'dist' && !e.name.startsWith('.'));\n\n      for (const authorEntry of topLevel) {\n        const authorDir = join(contentDir, authorEntry.name);\n        const authorRegistry = join(authorDir, 'registry.json');\n\n        if (existsSync(authorRegistry)) {\n          // Author provides registry.json — use it directly\n          try {\n            const reg = JSON.parse(readFileSync(authorRegistry, 'utf8'));\n            // Prefix paths with author dir name\n            if (reg.docs) {\n              for (const doc of reg.docs) {\n                if (!doc.id) doc.id = `${authorEntry.name}/${doc.name}`;\n                else if (!doc.id.includes('/')) doc.id = `${authorEntry.name}/${doc.id}`;\n                for (const lang of doc.languages || []) {\n                  for (const ver of lang.versions || []) {\n                    ver.path = `${authorEntry.name}/${ver.path}`;\n                  }\n                }\n                allDocs.push(doc);\n              }\n            }\n            if (reg.skills) {\n              for (const skill of reg.skills) {\n                if (!skill.id) skill.id = `${authorEntry.name}/${skill.name}`;\n                else if (!skill.id.includes('/')) skill.id = `${authorEntry.name}/${skill.id}`;\n                skill.path = `${authorEntry.name}/${skill.path}`;\n                allSkills.push(skill);\n              }\n            }\n            info(`${authorEntry.name}: loaded registry.json`);\n          } catch (err) {\n            allErrors.push(`${authorEntry.name}/registry.json: ${err.message}`);\n          }\n        } else {\n          // Auto-discover\n          const result = discoverAuthor(authorDir, authorEntry.name, contentDir);\n          allDocs.push(...result.docs);\n          allSkills.push(...result.skills);\n          allWarnings.push(...result.warnings);\n          allErrors.push(...result.errors);\n        }\n      }\n\n      // Check for id collisions (should be rare since ids are author/name)\n      const docIds = new Map();\n      for (const doc of allDocs) {\n        if (docIds.has(doc.id)) {\n          allErrors.push(`Duplicate doc id '${doc.id}'`);\n        }\n        docIds.set(doc.id, true);\n      }\n      const skillIds = new Map();\n      for (const skill of allSkills) {\n        if (skillIds.has(skill.id)) {\n          allErrors.push(`Duplicate skill id '${skill.id}'`);\n        }\n        skillIds.set(skill.id, true);\n      }\n\n      // Print warnings\n      for (const w of allWarnings) {\n        process.stderr.write(chalk.yellow(`Warning: ${w}\\n`));\n      }\n\n      // Print errors\n      if (allErrors.length > 0) {\n        for (const e of allErrors) {\n          process.stderr.write(chalk.red(`Error: ${e}\\n`));\n        }\n        process.exit(1);\n      }\n\n      const registry = {\n        version: '1.0.0',\n        generated: new Date().toISOString(),\n        docs: allDocs,\n        skills: allSkills,\n      };\n\n      if (opts.baseUrl) {\n        registry.base_url = opts.baseUrl;\n      }\n\n      if (opts.validateOnly) {\n        const summary = { docs: allDocs.length, skills: allSkills.length, warnings: allWarnings.length };\n        if (globalOpts.json) {\n          console.log(JSON.stringify(summary));\n        } else {\n          console.log(chalk.green(`Valid: ${summary.docs} docs, ${summary.skills} skills, ${summary.warnings} warnings`));\n        }\n        return;\n      }\n\n      // Write output\n      mkdirSync(outputDir, { recursive: true });\n      writeFileSync(join(outputDir, 'registry.json'), JSON.stringify(registry, null, 2));\n\n      // Build and write BM25 search index\n      const allEntries = [\n        ...allDocs.map((d) => ({ ...d, _type: 'doc' })),\n        ...allSkills.map((s) => ({ ...s, _type: 'skill' })),\n      ];\n      const searchIndex = buildIndex(allEntries);\n      writeFileSync(join(outputDir, 'search-index.json'), JSON.stringify(searchIndex));\n\n      // Copy content tree\n      for (const authorEntry of topLevel) {\n        const src = join(contentDir, authorEntry.name);\n        const dest = join(outputDir, authorEntry.name);\n        // Skip registry.json in author dirs\n        cpSync(src, dest, {\n          recursive: true,\n          filter: (s) => basename(s) !== 'registry.json',\n        });\n      }\n\n      const summary = { docs: allDocs.length, skills: allSkills.length, warnings: allWarnings.length };\n      trackEvent('build', { doc_count: allDocs.length, skill_count: allSkills.length }).catch(() => {});\n      if (globalOpts.json) {\n        console.log(JSON.stringify({ ...summary, output: outputDir }));\n      } else {\n        console.log(chalk.green(`Built: ${summary.docs} docs, ${summary.skills} skills → ${outputDir}`));\n      }\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/cache.js",
    "content": "import chalk from 'chalk';\nimport { getCacheStats, clearCache } from '../lib/cache.js';\nimport { output } from '../lib/output.js';\n\nexport function registerCacheCommand(program) {\n  const cache = program\n    .command('cache')\n    .description('Manage the local cache');\n\n  cache\n    .command('status')\n    .description('Show cache information')\n    .action(() => {\n      const globalOpts = program.optsWithGlobals();\n      const stats = getCacheStats();\n\n      output(stats, (s) => {\n        if (!s.exists || s.sources.length === 0) {\n          console.log(chalk.yellow('No cache found. Run `chub update` to initialize.'));\n          return;\n        }\n        console.log(chalk.bold('Cache Status\\n'));\n        for (const src of s.sources) {\n          if (src.type === 'local') {\n            console.log(`  ${chalk.bold(src.name)} ${chalk.dim('(local)')}`);\n            console.log(`    Path: ${src.path}`);\n          } else {\n            console.log(`  ${chalk.bold(src.name)} ${chalk.dim('(remote)')}`);\n            console.log(`    Registry: ${src.hasRegistry ? chalk.green('yes') : chalk.red('no')}`);\n            console.log(`    Last updated: ${src.lastUpdated || 'never'}`);\n            console.log(`    Full bundle: ${src.fullBundle ? 'yes' : 'no'}`);\n            console.log(`    Cached files: ${src.fileCount}`);\n            console.log(`    Size: ${(src.dataSize / 1024).toFixed(1)} KB`);\n          }\n        }\n      }, globalOpts);\n    });\n\n  cache\n    .command('clear')\n    .description('Clear cached data')\n    .option('--force', 'Skip confirmation')\n    .action((opts) => {\n      const globalOpts = program.optsWithGlobals();\n      clearCache();\n      output(\n        { status: 'cleared' },\n        () => console.log(chalk.green('Cache cleared.')),\n        globalOpts\n      );\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/feedback.js",
    "content": "import chalk from 'chalk';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { getEntry } from '../lib/registry.js';\nimport { sendFeedback, isFeedbackEnabled, isTelemetryEnabled, getTelemetryUrl } from '../lib/telemetry.js';\nimport { getOrCreateClientId } from '../lib/identity.js';\nimport { output, error } from '../lib/output.js';\nimport { trackEvent } from '../lib/analytics.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst VALID_LABELS = [\n  'accurate', 'well-structured', 'helpful', 'good-examples',\n  'outdated', 'inaccurate', 'incomplete', 'wrong-examples',\n  'wrong-version', 'poorly-structured',\n];\n\nfunction collect(val, acc) {\n  acc.push(val);\n  return acc;\n}\n\nexport function registerFeedbackCommand(program) {\n  program\n    .command('feedback [id] [rating] [comment]')\n    .description('Rate a doc or skill (up/down)')\n    .option('--type <type>', 'Explicit type: doc or skill')\n    .option('--lang <language>', 'Language variant of the doc')\n    .option('--doc-version <version>', 'Version of the doc')\n    .option('--file <file>', 'Specific file within the entry (e.g. references/streaming.md)')\n    .option('--label <label>', 'Feedback label (repeatable: --label outdated --label wrong-examples)', collect, [])\n    .option('--agent <name>', 'AI coding tool name')\n    .option('--model <model>', 'LLM model name')\n    .option('--status', 'Show feedback and telemetry status')\n    .action(async (id, rating, comment, opts) => {\n      const globalOpts = program.optsWithGlobals();\n\n      // --status flag\n      if (opts.status) {\n        const feedbackEnabled = isFeedbackEnabled();\n        const telemetryEnabled = isTelemetryEnabled();\n        if (globalOpts.json) {\n          let clientId = null;\n          try { clientId = await getOrCreateClientId(); } catch {}\n          console.log(JSON.stringify({\n            feedback: feedbackEnabled,\n            telemetry: telemetryEnabled,\n            client_id_prefix: clientId ? clientId.slice(0, 8) : null,\n            endpoint: getTelemetryUrl(),\n            valid_labels: VALID_LABELS,\n          }));\n        } else {\n          console.log(`Feedback:  ${feedbackEnabled ? chalk.green('enabled') : chalk.red('disabled')}`);\n          console.log(`Telemetry: ${telemetryEnabled ? chalk.green('enabled') : chalk.red('disabled')}`);\n          try {\n            const cid = await getOrCreateClientId();\n            console.log(`Client ID: ${cid.slice(0, 8)}...`);\n          } catch {}\n          console.log(`Endpoint:  ${getTelemetryUrl()}`);\n          console.log(`Labels:    ${VALID_LABELS.join(', ')}`);\n        }\n        return;\n      }\n\n      // BUG #1 FIX: Validation errors respect --json flag\n      if (!id || !rating) {\n        error('Missing required arguments: <id> and <rating>. Run: chub feedback <id> <up|down> [comment]', globalOpts);\n      }\n\n      if (rating !== 'up' && rating !== 'down') {\n        error('Rating must be \"up\" or \"down\".', globalOpts);\n      }\n\n      if (!isFeedbackEnabled()) {\n        output(\n          { status: 'skipped', reason: 'feedback_disabled' },\n          () => console.log(chalk.yellow('Feedback is disabled. Enable with: feedback: true in ~/.chub/config.yaml')),\n          globalOpts\n        );\n        return;\n      }\n\n      // BUG #2 FIX: Only auto-detect type if --type not explicitly set\n      let entryType = opts.type || null;\n      let docLang = opts.lang || undefined;\n      let docVersion = opts.docVersion || undefined;\n      let source;\n      try {\n        const result = getEntry(id);\n        if (result.entry) {\n          if (!entryType) {\n            entryType = result.entry.languages ? 'doc' : 'skill';\n          }\n          source = result.entry._source;\n\n          // If doc and user didn't specify lang/version, try to infer from entry\n          if (result.entry.languages && !docLang && result.entry.languages.length === 1) {\n            docLang = result.entry.languages[0].language;\n          }\n          if (result.entry.languages && !docVersion) {\n            const lang = result.entry.languages.find((l) => l.language === docLang) || result.entry.languages[0];\n            if (lang) docVersion = lang.recommendedVersion;\n          }\n        }\n      } catch {\n        // Registry not loaded — use explicit flags\n      }\n      if (!entryType) entryType = 'doc'; // Final fallback\n\n      // Parse labels (--label is repeatable, collected into an array)\n      let labels;\n      if (opts.label && opts.label.length > 0) {\n        labels = opts.label.map((l) => l.trim().toLowerCase()).filter((l) => VALID_LABELS.includes(l));\n        if (labels.length === 0) labels = undefined;\n      }\n\n      // Read CLI version\n      let cliVersion;\n      try {\n        const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8'));\n        cliVersion = pkg.version;\n      } catch {}\n\n      const result = await sendFeedback(id, entryType, rating, {\n        comment,\n        docLang,\n        docVersion,\n        targetFile: opts.file,\n        labels,\n        agent: opts.agent,\n        model: opts.model,\n        cliVersion,\n        source,\n      });\n\n      if (result.status === 'sent') {\n        trackEvent('feedback_sent', { entry_id: id, rating, entry_type: entryType }).catch(() => {});\n      }\n\n      output(result, (data) => {\n        if (data.status === 'sent') {\n          const parts = [chalk.green(`Feedback recorded for ${id}`)];\n          if (docLang) parts.push(chalk.dim(`lang=${docLang}`));\n          if (docVersion) parts.push(chalk.dim(`version=${docVersion}`));\n          if (opts.file) parts.push(chalk.dim(`file=${opts.file}`));\n          console.log(parts.join(' '));\n        } else if (data.status === 'error') {\n          process.stderr.write(chalk.red(`Failed to send feedback: ${data.reason || `HTTP ${data.code}`}\\n`));\n        }\n      }, globalOpts);\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/get.js",
    "content": "import { writeFileSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport chalk from 'chalk';\nimport { getEntry, resolveDocPath, resolveEntryFile } from '../lib/registry.js';\nimport { fetchDoc, fetchDocFull } from '../lib/cache.js';\nimport { output, error, info } from '../lib/output.js';\nimport { trackEvent } from '../lib/analytics.js';\nimport { readAnnotation } from '../lib/annotations.js';\n\n/**\n * Fetch one or more entries by ID. Auto-detects doc vs skill per entry.\n */\nasync function fetchEntries(ids, opts, globalOpts) {\n  const results = [];\n\n  for (const id of ids) {\n    const fetchStart = Date.now();\n\n    // Search both docs and skills — auto-detect type\n    const result = getEntry(id);\n\n    if (result.ambiguous) {\n      error(\n        `Multiple entries match \"${id}\". Use a source prefix:\\n  ${result.alternatives.map((a) => `chub get ${a}`).join('\\n  ')}`,\n        globalOpts\n      );\n    }\n\n    if (!result.entry) {\n      await trackEvent('doc_not_found', { entry_id: id });\n      error(`No doc or skill found with id \"${id}\".`, globalOpts);\n    }\n\n    const entry = result.entry;\n    const type = entry.languages ? 'doc' : 'skill';\n    const resolved = resolveDocPath(entry, opts.lang, opts.version);\n\n    if (!resolved) {\n      if (opts.lang && entry.languages) {\n        const available = entry.languages.map((l) => l.language).join(', ');\n        error(`Language \"${opts.lang}\" is not available for \"${id}\". Available languages: ${available}.`, globalOpts);\n      } else {\n        error(`No content found for \"${id}\".`, globalOpts);\n      }\n    }\n\n    if (resolved.versionNotFound) {\n      error(\n        `Version \"${resolved.requested}\" not found for \"${id}\". Available versions: ${resolved.available.join(', ')}`,\n        globalOpts\n      );\n    }\n\n    if (resolved.needsLanguage) {\n      error(\n        `Multiple languages available for \"${id}\": ${resolved.available.join(', ')}. Specify --lang.`,\n        globalOpts\n      );\n    }\n\n    const entryFile = resolveEntryFile(resolved, type);\n    if (entryFile.error) {\n      error(`No content available for \"${id}\". Check that the source contains a valid DOC.md or SKILL.md, or run \\`chub update\\` to refresh remote registries.`, globalOpts);\n    }\n\n    // Determine which reference files exist (beyond DOC.md/SKILL.md)\n    const entryFileName = type === 'skill' ? 'SKILL.md' : 'DOC.md';\n    const refFiles = resolved.files.filter((f) => f !== entryFileName);\n\n    try {\n      if (opts.file) {\n        // --file mode: fetch specific file(s) by path\n        const requested = opts.file.split(',').map((f) => f.trim());\n        const invalid = requested.filter((f) => !resolved.files.includes(f));\n        if (invalid.length > 0) {\n          const available = refFiles.length > 0 ? refFiles.join(', ') : '(none)';\n          error(`File \"${invalid[0]}\" not found in ${id}. Available: ${available}`, globalOpts);\n        }\n        if (requested.length === 1) {\n          const content = await fetchDoc(resolved.source, join(resolved.path, requested[0]));\n          results.push({ id: entry.id, type, content, path: join(resolved.path, requested[0]), source: entry._source, fetchStart, fetchDone: Date.now() });\n        } else {\n          const allFiles = await fetchDocFull(resolved.source, resolved.path, requested);\n          results.push({ id: entry.id, type, files: allFiles, path: resolved.path, source: entry._source, fetchStart, fetchDone: Date.now() });\n        }\n      } else if (opts.full && resolved.files.length > 0) {\n        const allFiles = await fetchDocFull(resolved.source, resolved.path, resolved.files);\n        results.push({ id: entry.id, type, files: allFiles, path: resolved.path, source: entry._source, fetchStart, fetchDone: Date.now() });\n      } else {\n        const content = await fetchDoc(resolved.source, entryFile.filePath);\n        results.push({ id: entry.id, type, content, path: entryFile.filePath, additionalFiles: refFiles, source: entry._source, fetchStart, fetchDone: Date.now() });\n      }\n    } catch (err) {\n      await trackEvent('fetch_error', {\n        entry_id: entry.id,\n        error_type: err.code || err.name || 'unknown',\n      });\n      error(`Failed to load \"${id}\": ${err.message}`, globalOpts);\n    }\n  }\n\n  // Track fetches\n  for (const r of results) {\n    trackEvent(r.type === 'doc' ? 'doc_fetched' : 'skill_fetched', {\n      entry_id: r.id,\n      full: !!opts.full,\n      file: opts.file || undefined,\n      lang: opts.lang || undefined,\n      source: r.source || undefined,\n      duration_ms: r.fetchDone - r.fetchStart,\n    }).catch(() => {});\n  }\n\n  // Output\n  if (opts.output) {\n    if (opts.full) {\n      for (const r of results) {\n        if (r.files) {\n          const baseDir = ids.length > 1 ? join(opts.output, r.id) : opts.output;\n          mkdirSync(baseDir, { recursive: true });\n          for (const f of r.files) {\n            const outPath = join(baseDir, f.name);\n            mkdirSync(dirname(outPath), { recursive: true });\n            writeFileSync(outPath, f.content);\n          }\n          info(`Written ${r.files.length} files to ${baseDir}`);\n        } else {\n          const outPath = join(opts.output, `${r.id}.md`);\n          mkdirSync(dirname(outPath), { recursive: true });\n          writeFileSync(outPath, r.content);\n          info(`Written to ${outPath}`);\n        }\n      }\n    } else {\n      const isDir = opts.output.endsWith('/') || opts.output.endsWith('\\\\');\n      if (isDir && results.length > 1) {\n        mkdirSync(opts.output, { recursive: true });\n        for (const r of results) {\n          const outPath = join(opts.output, `${r.id}.md`);\n          mkdirSync(dirname(outPath), { recursive: true });\n          writeFileSync(outPath, r.content);\n          info(`Written to ${outPath}`);\n        }\n      } else {\n        const outPath = isDir ? join(opts.output, `${results[0].id}.md`) : opts.output;\n        mkdirSync(dirname(outPath), { recursive: true });\n        const combined = results.map((r) => r.content).join('\\n\\n---\\n\\n');\n        writeFileSync(outPath, combined);\n        info(`Written to ${outPath}`);\n      }\n    }\n    if (globalOpts.json) {\n      console.log(JSON.stringify(results.map((r) => ({ id: r.id, type: r.type, path: opts.output }))));\n    }\n  } else {\n    if (results.length === 1 && !results[0].files) {\n      const r = results[0];\n      const extraFiles = r.additionalFiles || [];\n      const annotation = readAnnotation(r.id);\n      const jsonData = { id: r.id, type: r.type, content: r.content, path: r.path };\n      if (extraFiles.length > 0) jsonData.additionalFiles = extraFiles;\n      if (annotation) jsonData.annotation = annotation;\n      output(\n        jsonData,\n        (data) => {\n          process.stdout.write(data.content);\n          if (annotation) {\n            process.stdout.write(`\\n\\n---\\n[Agent note — ${annotation.updatedAt}]\\n${annotation.note}\\n`);\n          }\n          const langFlag = opts.lang ? ` --lang ${opts.lang}` : '';\n          process.stdout.write(`\\n\\n---\\nAfter using this doc, share your experience:\\n`);\n          process.stdout.write(`  chub feedback ${r.id} up${langFlag}\\n`);\n          process.stdout.write(`  chub feedback ${r.id} down${langFlag} --label outdated\\n`);\n          process.stdout.write(`Available labels: accurate, well-structured, helpful, good-examples, outdated, inaccurate, incomplete, wrong-examples, wrong-version, poorly-structured\\n`);\n          process.stdout.write(`Do NOT include any code, architecture details, or project-specific information in your feedback.\\n`);\n          if (extraFiles.length > 0) {\n            const fileList = extraFiles.map((f) => `  ${f}`).join('\\n');\n            const example = `chub get ${r.id} --file ${extraFiles[0]}`;\n            process.stdout.write(`\\n\\n---\\nAdditional files available (use --file to fetch):\\n${fileList}\\nExample: ${example}\\n`);\n          }\n        },\n        globalOpts\n      );\n    } else {\n      const parts = results.flatMap((r) => {\n        if (r.files) {\n          return r.files.map((f) => `# FILE: ${f.name}\\n\\n${f.content}`);\n        }\n        return [r.content];\n      });\n      const combined = parts.join('\\n\\n---\\n\\n');\n      output(\n        results.map((r) => ({ id: r.id, type: r.type, path: r.path })),\n        () => process.stdout.write(combined),\n        globalOpts\n      );\n    }\n  }\n}\n\nexport function registerGetCommand(program) {\n  program\n    .command('get <ids...>')\n    .description('Fetch docs or skills by ID (auto-detects type)')\n    .option('--lang <language>', 'Language variant (required for docs): py, js, ts, rb, cs (or full names: python, javascript, typescript, ruby, csharp)')\n    .option('--version <version>', 'Specific version (for docs)')\n    .option('-o, --output <path>', 'Write to file or directory')\n    .option('--full', 'Fetch all files (not just entry point)')\n    .option('--file <paths>', 'Fetch specific file(s) by path (comma-separated)')\n    .action(async (ids, opts) => {\n      const globalOpts = program.optsWithGlobals();\n      await fetchEntries(ids, opts, globalOpts);\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/search.js",
    "content": "import chalk from 'chalk';\nimport { searchEntries, listEntries, getEntry, getDisplayId, isMultiSource } from '../lib/registry.js';\nimport { displayLanguage } from '../lib/normalize.js';\nimport { output } from '../lib/output.js';\nimport { trackEvent } from '../lib/analytics.js';\n\nfunction formatEntryList(entries) {\n  const multi = isMultiSource();\n  for (const entry of entries) {\n    const id = getDisplayId(entry);\n    const source = entry.source ? chalk.dim(`[${entry.source}]`) : '';\n    const sourceName = multi ? chalk.cyan(`(${entry._source})`) : '';\n    const type = entry._type === 'skill' ? chalk.magenta('[skill]') : chalk.blue('[doc]');\n    const langs = (entry.languages || []).map((l) => displayLanguage(l.language)).join(', ');\n    const desc = entry.description\n      ? entry.description.length > 60\n        ? entry.description.slice(0, 57) + '...'\n        : entry.description\n      : '';\n    console.log(`  ${chalk.bold(id)}  ${type}  ${chalk.dim(langs)}  ${source} ${sourceName}`.trimEnd());\n    if (desc) console.log(`       ${chalk.dim(desc)}`);\n  }\n}\n\nfunction formatEntryDetail(entry) {\n  console.log(chalk.bold(entry.name));\n  if (isMultiSource()) console.log(`  Source: ${entry._source}`);\n  if (entry.source) console.log(`  Quality: ${entry.source}`);\n  if (entry.description) console.log(`  ${chalk.dim(entry.description)}`);\n  if (entry.tags?.length) console.log(`  Tags: ${entry.tags.join(', ')}`);\n  console.log();\n  if (entry.languages) {\n    for (const lang of entry.languages) {\n      console.log(`  ${chalk.bold(displayLanguage(lang.language))}`);\n      console.log(`    Recommended: ${lang.recommendedVersion}`);\n      for (const v of lang.versions || []) {\n        const size = v.size ? ` (${(v.size / 1024).toFixed(1)} KB)` : '';\n        console.log(`    ${v.version}${size}  updated: ${v.lastUpdated}`);\n      }\n    }\n  } else {\n    // Skill — flat structure\n    const size = entry.size ? ` (${(entry.size / 1024).toFixed(1)} KB)` : '';\n    console.log(`  Path: ${entry.path}${size}`);\n    if (entry.lastUpdated) console.log(`  Updated: ${entry.lastUpdated}`);\n    if (entry.files?.length) console.log(`  Files: ${entry.files.join(', ')}`);\n  }\n}\n\nexport function registerSearchCommand(program) {\n  program\n    .command('search [query]')\n    .description('Search docs and skills (no query lists all)')\n    .option('--tags <tags>', 'Filter by tags (comma-separated)')\n    .option('--lang <language>', 'Filter by language')\n    .option('--limit <n>', 'Max results', '20')\n    .action((query, opts) => {\n      const globalOpts = program.optsWithGlobals();\n      const limit = parseInt(opts.limit, 10);\n      const normalizedQuery = typeof query === 'string' ? query.trim().replace(/\\s+/g, ' ') : query;\n\n      // No query: list all\n      if (!normalizedQuery) {\n        const entries = listEntries(opts).slice(0, limit);\n        output({ results: entries, total: entries.length }, (data) => {\n          if (data.results.length === 0) {\n            console.log(chalk.yellow('No entries found.'));\n            return;\n          }\n          console.log(chalk.bold(`${data.total} entries:\\n`));\n          formatEntryList(data.results);\n        }, globalOpts);\n        return;\n      }\n\n      // Exact id match: show detail\n      const result = getEntry(normalizedQuery);\n      if (result.ambiguous) {\n        output(\n          { error: 'ambiguous', alternatives: result.alternatives },\n          () => {\n            console.log(chalk.yellow(`Multiple entries with id \"${normalizedQuery}\". Be specific:`));\n            for (const alt of result.alternatives) {\n              console.log(`  ${chalk.bold(alt)}`);\n            }\n          },\n          globalOpts\n        );\n        return;\n      }\n      if (result.entry) {\n        output(result.entry, formatEntryDetail, globalOpts);\n        return;\n      }\n\n      // Fuzzy search\n      const searchStart = Date.now();\n      const results = searchEntries(normalizedQuery, opts).slice(0, limit);\n      const duration_ms = Date.now() - searchStart;\n      const resultIds = results.map((e) => e.id || e.name || 'unknown');\n      trackEvent('search', {\n        query: normalizedQuery.slice(0, 1000),\n        query_length: normalizedQuery.length,\n        result_count: results.length,\n        results: resultIds,\n        duration_ms,\n        has_tags: !!opts.tags,\n        has_lang: !!opts.lang,\n        tags: opts.tags || undefined,\n        lang: opts.lang || undefined,\n      }).catch(() => {});\n      output({ results, total: results.length, query: normalizedQuery }, (data) => {\n        if (data.results.length === 0) {\n          console.log(chalk.yellow(`No results for \"${normalizedQuery}\".`));\n          return;\n        }\n        console.log(chalk.bold(`${data.total} results for \"${normalizedQuery}\":\\n`));\n        formatEntryList(data.results);\n      }, globalOpts);\n    });\n}\n"
  },
  {
    "path": "cli/src/commands/update.js",
    "content": "import chalk from 'chalk';\nimport { fetchAllRegistries, fetchFullBundle } from '../lib/cache.js';\nimport { loadConfig } from '../lib/config.js';\nimport { output, info } from '../lib/output.js';\n\nexport function registerUpdateCommand(program) {\n  program\n    .command('update')\n    .description('Refresh the cached registry index')\n    .option('--force', 'Force re-download even if cache is fresh')\n    .option('--full', 'Download the full bundle for offline use')\n    .action(async (opts) => {\n      const globalOpts = program.optsWithGlobals();\n      const config = loadConfig();\n\n      try {\n        if (opts.full) {\n          // Download full bundle for each remote source\n          for (const source of config.sources) {\n            if (source.path) {\n              info(`Skipping local source: ${source.name}`);\n              continue;\n            }\n            info(`Downloading full bundle for ${source.name}...`);\n            await fetchFullBundle(source.name);\n          }\n          output(\n            { status: 'ok', mode: 'full' },\n            () => console.log(chalk.green('Full bundle(s) downloaded and extracted.')),\n            globalOpts\n          );\n        } else {\n          info('Updating registries...');\n          const errors = await fetchAllRegistries(opts.force || true);\n          if (errors.length > 0) {\n            for (const e of errors) {\n              process.stderr.write(chalk.yellow(`Warning: ${e.source}: ${e.error}\\n`));\n            }\n          }\n          const updated = config.sources.filter((s) => !s.path).length - errors.length;\n          output(\n            { status: 'ok', mode: 'registry', updated, errors },\n            () => console.log(chalk.green(`Registry updated (${updated} remote source(s)).`)),\n            globalOpts\n          );\n        }\n      } catch (err) {\n        output(\n          { error: err.message },\n          () => console.error(chalk.red(`Update failed: ${err.message}`)),\n          globalOpts\n        );\n        process.exit(1);\n      }\n    });\n}\n"
  },
  {
    "path": "cli/src/index.js",
    "content": "import chalk from 'chalk';\nimport { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { ensureRegistry } from './lib/cache.js';\nimport { registerUpdateCommand } from './commands/update.js';\nimport { registerCacheCommand } from './commands/cache.js';\nimport { registerSearchCommand } from './commands/search.js';\nimport { registerGetCommand } from './commands/get.js';\nimport { registerBuildCommand } from './commands/build.js';\nimport { registerFeedbackCommand } from './commands/feedback.js';\nimport { registerAnnotateCommand } from './commands/annotate.js';\nimport { trackEvent, shutdownAnalytics, setCliVersion } from './lib/analytics.js';\nimport { error } from './lib/output.js';\nimport { showWelcomeIfNeeded } from './lib/welcome.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));\nsetCliVersion(pkg.version);\n\nfunction printUsage() {\n  console.log(`\n${chalk.bold('chub')} — Context Hub CLI v${pkg.version}\nSearch and retrieve LLM-optimized docs and skills.\n\n${chalk.bold.underline('Getting Started')}\n\n  ${chalk.dim('$')} chub update                                ${chalk.dim('# download the registry')}\n  ${chalk.dim('$')} chub search                                ${chalk.dim('# list everything available')}\n  ${chalk.dim('$')} chub search \"stripe\"                       ${chalk.dim('# fuzzy search')}\n  ${chalk.dim('$')} chub search stripe/payments                ${chalk.dim('# exact id → full detail')}\n  ${chalk.dim('$')} chub get stripe/api                        ${chalk.dim('# print doc to terminal')}\n  ${chalk.dim('$')} chub get stripe/api -o doc.md              ${chalk.dim('# save to file')}\n  ${chalk.dim('$')} chub get openai/chat --lang py             ${chalk.dim('# specific language')}\n  ${chalk.dim('$')} chub get pw-community/login-flows          ${chalk.dim('# fetch a skill')}\n  ${chalk.dim('$')} chub get openai/chat stripe/api            ${chalk.dim('# fetch multiple')}\n\n${chalk.bold.underline('Learn & Improve')}\n\n  After using a doc, save what you learned so future sessions start smarter:\n\n  ${chalk.dim('$')} chub annotate stripe/api \"Webhook needs raw body\"   ${chalk.dim('# persists across sessions')}\n  ${chalk.dim('$')} chub annotate --list                                 ${chalk.dim('# see all saved notes')}\n  ${chalk.dim('$')} chub annotate stripe/api --clear                     ${chalk.dim('# remove a note')}\n\n  Always rate docs after using them — helps authors fix issues and prioritize:\n\n  ${chalk.dim('$')} chub feedback stripe/api up --label accurate \"Clear examples\"\n  ${chalk.dim('$')} chub feedback stripe/api down --label outdated \"Missing v3 API\"\n\n${chalk.bold.underline('Commands')}\n\n  ${chalk.bold('search')} [query]              Search docs and skills (no query = list all)\n  ${chalk.bold('get')} <ids...>                 Fetch docs or skills by ID\n  ${chalk.bold('annotate')} [id] [note]        Save a note — appears on future fetches\n  ${chalk.bold('feedback')} <id> <up|down>     Rate a doc (helps authors improve it)\n  ${chalk.bold('update')}                      Refresh the cached registry\n  ${chalk.bold('cache')} status|clear          Manage the local cache\n  ${chalk.bold('build')} <content-dir>        Build registry from content directory\n\n${chalk.bold.underline('Flags')}\n\n  --json                 Structured JSON output (for agents and piping)\n  --tags <csv>           Filter by tags (e.g. docs, skill, openai, browser)\n  --lang <language>      Language variant (required for docs): py | js | ts | rb | cs (or full name)\n  --full                 Fetch all files, not just the entry point\n  -o, --output <path>    Write content to file or directory\n\n${chalk.bold.underline('Agent Piping Patterns')}\n\n  ${chalk.dim('# Get the top result id')}\n  ${chalk.dim('$')} chub search \"stripe\" --json | jq -r '.results[0].id'\n\n  ${chalk.dim('# Search → pick → fetch → save')}\n  ${chalk.dim('$')} ID=$(chub search \"stripe\" --json | jq -r '.results[0].id')\n  ${chalk.dim('$')} chub get \"$ID\" --lang js -o .context/stripe.md\n\n  ${chalk.dim('# Fetch multiple at once')}\n  ${chalk.dim('$')} chub get openai/chat stripe/api -o .context/\n\n${chalk.bold.underline('Multi-Source Config')} ${chalk.dim('(~/.chub/config.yaml)')}\n\n  ${chalk.dim('sources:')}\n  ${chalk.dim('  - name: community')}\n  ${chalk.dim('    url: https://cdn.aichub.org/v1')}\n  ${chalk.dim('  - name: internal')}\n  ${chalk.dim('    path: /path/to/local/docs')}\n\n  ${chalk.dim('# On id collision, use source: prefix: chub get internal:openai/chat')}\n`);\n}\n\nconst program = new Command();\n\nprogram\n  .name('chub')\n  .description('Context Hub - search and retrieve LLM-optimized docs and skills')\n  .version(pkg.version, '-V, --cli-version')\n  .option('--json', 'Output as JSON (machine-readable)')\n  .action(() => {\n    printUsage();\n  });\n\n// Commands that don't need registry\nconst SKIP_REGISTRY = ['update', 'cache', 'build', 'feedback', 'annotate', 'help'];\n\nprogram.hook('preAction', async (thisCommand) => {\n  const globalOpts = thisCommand.optsWithGlobals?.() || {};\n  showWelcomeIfNeeded(globalOpts);\n\n  const cmdName = thisCommand.args?.[0] || thisCommand.name();\n  if (cmdName !== 'chub') {\n    // Only initialize identity and track if telemetry is enabled\n    // Respects CHUB_TELEMETRY=0 — no client_id file created, no events sent\n    try {\n      const { isTelemetryEnabled } = await import('./lib/telemetry.js');\n      if (isTelemetryEnabled()) {\n        const { getOrCreateClientId, isFirstRun } = await import('./lib/identity.js');\n        await getOrCreateClientId();\n\n        // Fire-and-forget — don't block command on PostHog network I/O\n        trackEvent('command_run', { command: cmdName }).catch(() => {});\n        if (isFirstRun()) {\n          trackEvent('first_run', { command: cmdName }).catch(() => {});\n        }\n      }\n    } catch {\n      // Identity/telemetry failure — silently skip, don't block the command\n    }\n  }\n  if (SKIP_REGISTRY.includes(cmdName)) return;\n  if (thisCommand.parent?.name() === 'cache') return;\n  // Don't fetch registry for default action (no command)\n  if (cmdName === 'chub') return;\n  try {\n    await ensureRegistry();\n  } catch (err) {\n    await trackEvent('command_error', { command: cmdName, error_type: 'registry_unavailable' });\n    error(`Registry not available: ${err.message}. Run \\`chub update\\` to refresh remote registries, or check that local source paths in ~/.chub/config.yaml are correct.`, globalOpts);\n  }\n});\n\nregisterUpdateCommand(program);\nregisterCacheCommand(program);\nregisterSearchCommand(program);\nregisterGetCommand(program);\nregisterBuildCommand(program);\nregisterFeedbackCommand(program);\nregisterAnnotateCommand(program);\n\nprogram.parse();\n\n// Flush analytics before exit (best-effort)\nprocess.on('beforeExit', () => shutdownAnalytics().catch(() => {}));\n"
  },
  {
    "path": "cli/src/lib/analytics.js",
    "content": "/**\n * PostHog Cloud analytics for general CLI usage tracking.\n *\n * Tracks: command usage, search patterns, doc/skill popularity, errors.\n * Does NOT track feedback ratings (those go to the custom API via telemetry.js).\n *\n * Respects telemetry opt-out: `telemetry: false` in config or CHUB_TELEMETRY=0.\n * Feedback has a separate opt-out: `feedback: false` in config or CHUB_FEEDBACK=0.\n */\n\nimport { isTelemetryEnabled } from './telemetry.js';\n\n// PostHog project API key (public — standard for client-side analytics)\nconst POSTHOG_KEY = 'phc_tO9mXIgcCuBccfN2Ut0quf6UFsd06u3Y6g1kqMaYdQX';\nconst POSTHOG_HOST = 'https://us.i.posthog.com';\n\nlet _posthog = null;\nlet _initFailed = false;\n\n/**\n * Lazily initialize PostHog client. Returns null if telemetry is disabled\n * or posthog-node is not installed.\n */\nasync function getClient() {\n  if (_initFailed) return null;\n  if (_posthog) return _posthog;\n\n  if (!isTelemetryEnabled()) {\n    _initFailed = true;\n    return null;\n  }\n\n  try {\n    const { PostHog } = await import('posthog-node');\n    _posthog = new PostHog(POSTHOG_KEY, {\n      host: POSTHOG_HOST,\n      flushAt: 1,        // Send immediately (CLI is short-lived)\n      flushInterval: 0,  // Don't batch\n    });\n    return _posthog;\n  } catch {\n    // posthog-node not installed — skip analytics silently\n    _initFailed = true;\n    return null;\n  }\n}\n\n/**\n * Track an analytics event. Fire-and-forget — never throws, never blocks.\n *\n * @param {string} event - Event name (e.g., 'command_run', 'search', 'doc_fetched')\n * @param {object} properties - Event properties\n */\nexport async function trackEvent(event, properties = {}) {\n  try {\n    const client = await getClient();\n    if (!client) return;\n\n    const { getOrCreateClientId } = await import('./identity.js');\n    const distinctId = await getOrCreateClientId();\n\n    client.capture({\n      distinctId,\n      event,\n      properties: {\n        ...properties,\n        platform: process.platform,\n        node_version: process.version,\n        cli_version: _cliVersion || undefined,\n      },\n    });\n\n    // Flush immediately since CLI process exits soon\n    await client.flush();\n  } catch {\n    // Silent fail — analytics should never disrupt CLI\n  }\n}\n\nlet _cliVersion;\n/**\n * Set the CLI version for inclusion in all events.\n * Called once from index.js at startup.\n */\nexport function setCliVersion(version) {\n  _cliVersion = version;\n}\n\n/**\n * Shut down the PostHog client gracefully.\n * Call this before process exit if possible.\n */\nexport async function shutdownAnalytics() {\n  if (_posthog) {\n    try {\n      await _posthog.shutdown();\n    } catch {\n      // Silent\n    }\n  }\n}\n"
  },
  {
    "path": "cli/src/lib/annotations.js",
    "content": "import { readFileSync, writeFileSync, mkdirSync, unlinkSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getChubDir } from './config.js';\n\nfunction getAnnotationsDir() {\n  return join(getChubDir(), 'annotations');\n}\n\nfunction annotationPath(entryId) {\n  const safe = entryId.replace(/\\//g, '--');\n  return join(getAnnotationsDir(), `${safe}.json`);\n}\n\nexport function readAnnotation(entryId) {\n  try {\n    return JSON.parse(readFileSync(annotationPath(entryId), 'utf8'));\n  } catch {\n    return null;\n  }\n}\n\nexport function writeAnnotation(entryId, note) {\n  const dir = getAnnotationsDir();\n  mkdirSync(dir, { recursive: true });\n  const data = {\n    id: entryId,\n    note,\n    updatedAt: new Date().toISOString(),\n  };\n  writeFileSync(annotationPath(entryId), JSON.stringify(data, null, 2));\n  return data;\n}\n\nexport function clearAnnotation(entryId) {\n  try {\n    unlinkSync(annotationPath(entryId));\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport function listAnnotations() {\n  const dir = getAnnotationsDir();\n  try {\n    const files = readdirSync(dir).filter((f) => f.endsWith('.json'));\n    return files.map((f) => {\n      try {\n        return JSON.parse(readFileSync(join(dir, f), 'utf8'));\n      } catch {\n        return null;\n      }\n    }).filter(Boolean);\n  } catch {\n    return [];\n  }\n}\n"
  },
  {
    "path": "cli/src/lib/bm25.js",
    "content": "/**\n * BM25 search implementation for Context Hub.\n * Index is built at `chub build` time, scoring happens at search time.\n * Tokenizer is shared between build and search to ensure consistency.\n */\n\nconst STOP_WORDS = new Set([\n  'a', 'an', 'and', 'are', 'as', 'at', 'be', 'by', 'for', 'from',\n  'has', 'have', 'in', 'is', 'it', 'its', 'of', 'on', 'or', 'that',\n  'the', 'to', 'was', 'were', 'will', 'with', 'this', 'but', 'not',\n  'you', 'your', 'can', 'do', 'does', 'how', 'if', 'may', 'no',\n  'so', 'than', 'too', 'very', 'just', 'about', 'into', 'over',\n  'such', 'then', 'them', 'these', 'those', 'through', 'under',\n  'use', 'using', 'used',\n]);\n\n// BM25 default parameters\nconst DEFAULT_K1 = 1.5;\nconst DEFAULT_B = 0.75;\n\n// Field weights for multi-field scoring\nconst FIELD_WEIGHTS = {\n  id: 4.0,\n  name: 3.0,\n  tags: 2.0,\n  description: 1.0,\n};\n\nfunction getDefaultParams() {\n  return { k1: DEFAULT_K1, b: DEFAULT_B };\n}\n\nfunction isSearchableToken(token) {\n  return (token.length > 1 || /^\\d+$/.test(token)) && !STOP_WORDS.has(token);\n}\n\nexport function compactIdentifier(text) {\n  return String(text || '')\n    .toLowerCase()\n    .replace(/[^a-z0-9]/g, '');\n}\n\nfunction splitAlphaNumeric(text) {\n  return text\n    .replace(/([a-z])(\\d)/g, '$1 $2')\n    .replace(/(\\d)([a-z])/g, '$1 $2');\n}\n\n/**\n * Tokenize text into lowercase terms with stop word removal.\n * Must be used identically at build time and search time.\n */\nexport function tokenize(text) {\n  if (!text) return [];\n  return text\n    .toLowerCase()\n    .replace(/[^a-z0-9\\s-]/g, ' ')\n    .split(/[\\s-]+/)\n    .filter(isSearchableToken);\n}\n\n/**\n * Tokenize identifiers more aggressively than free text so package ids\n * still match joined/split variants like \"nodefetch\" and \"auth 0\".\n */\nexport function tokenizeIdentifier(text) {\n  if (!text) return [];\n\n  const tokens = new Set(tokenize(text));\n  const raw = String(text);\n  const compact = compactIdentifier(raw);\n  const segments = new Set([\n    ...raw.split('/').map((segment) => compactIdentifier(segment)),\n    ...raw.split(/[\\/_.\\s-]+/).map((segment) => compactIdentifier(segment)),\n  ]);\n\n  if (isSearchableToken(compact)) {\n    tokens.add(compact);\n  }\n\n  for (const token of tokenize(splitAlphaNumeric(compact))) {\n    tokens.add(token);\n  }\n\n  for (const segment of segments) {\n    if (!segment) continue;\n    if (isSearchableToken(segment)) {\n      tokens.add(segment);\n    }\n    for (const token of tokenize(splitAlphaNumeric(segment))) {\n      tokens.add(token);\n    }\n  }\n\n  return [...tokens];\n}\n\nfunction buildInvertedIndex(documents) {\n  const invertedIndex = Object.create(null);\n\n  for (const [docIndex, doc] of documents.entries()) {\n    const allTerms = new Set([\n      ...(doc.tokens.id || []),\n      ...(doc.tokens.name || []),\n      ...(doc.tokens.description || []),\n      ...(doc.tokens.tags || []),\n    ]);\n\n    for (const term of allTerms) {\n      if (!invertedIndex[term]) invertedIndex[term] = [];\n      invertedIndex[term].push(docIndex);\n    }\n  }\n\n  return invertedIndex;\n}\n\nexport function buildIndexFromDocuments(documents, params = getDefaultParams()) {\n  const dfMap = Object.create(null); // document frequency per term (across all fields)\n  const fieldLengths = { id: [], name: [], description: [], tags: [] };\n\n  for (const doc of documents) {\n    const idTokens = doc.tokens.id || [];\n    const nameTokens = doc.tokens.name || [];\n    const descTokens = doc.tokens.description || [];\n    const tagTokens = doc.tokens.tags || [];\n\n    fieldLengths.id.push(idTokens.length);\n    fieldLengths.name.push(nameTokens.length);\n    fieldLengths.description.push(descTokens.length);\n    fieldLengths.tags.push(tagTokens.length);\n\n    const allTerms = new Set([...idTokens, ...nameTokens, ...descTokens, ...tagTokens]);\n    for (const term of allTerms) {\n      dfMap[term] = (dfMap[term] || 0) + 1;\n    }\n  }\n\n  const N = documents.length;\n  const idf = Object.create(null);\n  for (const [term, df] of Object.entries(dfMap)) {\n    idf[term] = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n  }\n\n  const avg = (arr) => arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length;\n  return {\n    version: '1.0.0',\n    algorithm: 'bm25',\n    params,\n    totalDocs: N,\n    avgFieldLengths: {\n      id: avg(fieldLengths.id),\n      name: avg(fieldLengths.name),\n      description: avg(fieldLengths.description),\n      tags: avg(fieldLengths.tags),\n    },\n    idf,\n    documents,\n    invertedIndex: buildInvertedIndex(documents),\n  };\n}\n\n/**\n * Build a BM25 search index from registry entries.\n * Called during `chub build`.\n *\n * @param {Array} entries - Combined docs and skills from registry\n * @returns {Object} The search index\n */\nexport function buildIndex(entries) {\n  const documents = [];\n\n  for (const entry of entries) {\n    const idTokens = tokenizeIdentifier(entry.id);\n    const nameTokens = tokenize(entry.name);\n    const descTokens = tokenize(entry.description || '');\n    const tagTokens = (entry.tags || []).flatMap((t) => tokenize(t));\n\n    documents.push({\n      id: entry.id,\n      tokens: {\n        id: idTokens,\n        name: nameTokens,\n        description: descTokens,\n        tags: tagTokens,\n      },\n    });\n  }\n  return buildIndexFromDocuments(documents);\n}\n\n/**\n * Compute BM25 score for a single field.\n */\nfunction scoreField(queryTerms, fieldTokens, idf, avgFieldLen, k1, b) {\n  if (fieldTokens.length === 0) return 0;\n\n  // Build term frequency map for this field\n  const tf = Object.create(null);\n  for (const t of fieldTokens) {\n    tf[t] = (tf[t] || 0) + 1;\n  }\n\n  let score = 0;\n  const dl = fieldTokens.length;\n\n  for (const term of queryTerms) {\n    const termFreq = tf[term] || 0;\n    if (termFreq === 0) continue;\n\n    const termIdf = idf[term] || 0;\n    const numerator = termFreq * (k1 + 1);\n    const denominator = termFreq + k1 * (1 - b + b * (dl / (avgFieldLen || 1)));\n    score += termIdf * (numerator / denominator);\n  }\n\n  return score;\n}\n\nfunction getCandidateDocIndexes(queryTerms, index) {\n  if (!index.invertedIndex) {\n    return index.documents.map((_, docIndex) => docIndex);\n  }\n\n  const candidateIndexes = new Set();\n  for (const term of new Set(queryTerms)) {\n    const postings = index.invertedIndex[term];\n    if (!postings) continue;\n    for (const docIndex of postings) {\n      candidateIndexes.add(docIndex);\n    }\n  }\n\n  return [...candidateIndexes];\n}\n\nfunction runSearch(query, index, opts = {}) {\n  const queryTerms = tokenize(query);\n  const totalDocs = index.documents.length;\n\n  if (queryTerms.length === 0) {\n    return {\n      results: [],\n      stats: {\n        totalDocs,\n        candidateDocCount: 0,\n        scoredDocCount: 0,\n        matchedDocCount: 0,\n        usedInvertedIndex: !!index.invertedIndex,\n      },\n    };\n  }\n\n  const { k1, b } = index.params;\n  const results = [];\n  const candidateDocIndexes = getCandidateDocIndexes(queryTerms, index);\n\n  for (const docIndex of candidateDocIndexes) {\n    const doc = index.documents[docIndex];\n    let totalScore = 0;\n\n    for (const [field, weight] of Object.entries(FIELD_WEIGHTS)) {\n      const fieldTokens = doc.tokens[field] || [];\n      const avgLen = index.avgFieldLengths[field] || 1;\n      const fieldScore = scoreField(queryTerms, fieldTokens, index.idf, avgLen, k1, b);\n      totalScore += fieldScore * weight;\n    }\n\n    if (totalScore > 0) {\n      results.push({ id: doc.id, score: totalScore });\n    }\n  }\n\n  results.sort((a, b) => b.score - a.score);\n  const limitedResults = opts.limit ? results.slice(0, opts.limit) : results;\n\n  return {\n    results: limitedResults,\n    stats: {\n      totalDocs,\n      candidateDocCount: candidateDocIndexes.length,\n      scoredDocCount: candidateDocIndexes.length,\n      matchedDocCount: results.length,\n      usedInvertedIndex: !!index.invertedIndex,\n    },\n  };\n}\n\n/**\n * Search the BM25 index with a query string.\n *\n * @param {string} query - The search query\n * @param {Object} index - The pre-built BM25 index\n * @param {Object} opts - Options: { limit }\n * @returns {Array} Sorted results: [{ id, score }]\n */\nexport function search(query, index, opts = {}) {\n  return runSearch(query, index, opts).results;\n}\n\nexport function searchWithStats(query, index, opts = {}) {\n  return runSearch(query, index, opts);\n}\n"
  },
  {
    "path": "cli/src/lib/cache.js",
    "content": "import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync, statSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport { createWriteStream } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getChubDir, loadConfig } from './config.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Path to bundled content shipped with the npm package.\n * Contains registry.json + doc files built from content/ at publish time.\n */\nfunction getBundledDir() {\n  return join(__dirname, '..', '..', 'dist');\n}\n\nfunction getSourceDir(sourceName) {\n  return join(getChubDir(), 'sources', sourceName);\n}\n\nfunction getSourceDataDir(sourceName) {\n  return join(getSourceDir(sourceName), 'data');\n}\n\nfunction getSourceMetaPath(sourceName) {\n  return join(getSourceDir(sourceName), 'meta.json');\n}\n\nfunction getSourceRegistryPath(sourceName) {\n  return join(getSourceDir(sourceName), 'registry.json');\n}\n\nfunction getSourceSearchIndexPath(sourceName) {\n  return join(getSourceDir(sourceName), 'search-index.json');\n}\n\nfunction readMeta(sourceName) {\n  try {\n    return JSON.parse(readFileSync(getSourceMetaPath(sourceName), 'utf8'));\n  } catch {\n    return {};\n  }\n}\n\nfunction writeMeta(sourceName, meta) {\n  const dir = getSourceDir(sourceName);\n  mkdirSync(dir, { recursive: true });\n  writeFileSync(getSourceMetaPath(sourceName), JSON.stringify(meta, null, 2));\n}\n\nfunction isSourceCacheFresh(sourceName) {\n  const meta = readMeta(sourceName);\n  if (!meta.lastUpdated && meta.lastUpdated !== 0) return false;\n  const config = loadConfig();\n  const age = (Date.now() - meta.lastUpdated) / 1000;\n  return age < config.refresh_interval;\n}\n\nfunction isTimestampFresh(timestamp) {\n  if (timestamp === undefined || timestamp === null) return false;\n  const config = loadConfig();\n  const age = (Date.now() - timestamp) / 1000;\n  return age < config.refresh_interval;\n}\n\nfunction hasFreshSearchIndexState(sourceName) {\n  if (existsSync(getSourceSearchIndexPath(sourceName))) {\n    return true;\n  }\n\n  const meta = readMeta(sourceName);\n  return meta.searchIndexAvailable === false && isTimestampFresh(meta.searchIndexCheckedAt);\n}\n\nfunction shouldFetchRemoteRegistry(sourceName, force = false) {\n  if (force) return true;\n  return !(\n    isSourceCacheFresh(sourceName)\n    && existsSync(getSourceRegistryPath(sourceName))\n    && hasFreshSearchIndexState(sourceName)\n  );\n}\n\nasync function fetchRemoteText(url) {\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 30000);\n  try {\n    const res = await fetch(url, { signal: controller.signal });\n    if (!res.ok) {\n      throw new Error(`${res.status} ${res.statusText}`);\n    }\n    return await res.text();\n  } finally {\n    clearTimeout(timeout);\n  }\n}\n\n/**\n * Fetch registry for a single remote source.\n */\nasync function fetchRemoteRegistry(source, force = false) {\n  if (!shouldFetchRemoteRegistry(source.name, force)) {\n    return;\n  }\n\n  const registryUrl = `${source.url}/registry.json`;\n  let registryText;\n  try {\n    registryText = await fetchRemoteText(registryUrl);\n  } catch (err) {\n    throw new Error(`Failed to fetch registry from ${source.name}: ${err.message}`);\n  }\n\n  const dir = getSourceDir(source.name);\n  mkdirSync(dir, { recursive: true });\n  writeFileSync(getSourceRegistryPath(source.name), registryText);\n\n  const searchIndexUrl = `${source.url}/search-index.json`;\n  const searchIndexCheckedAt = Date.now();\n  let searchIndexAvailable;\n  try {\n    const searchIndexText = await fetchRemoteText(searchIndexUrl);\n    writeFileSync(getSourceSearchIndexPath(source.name), searchIndexText);\n    searchIndexAvailable = true;\n  } catch (err) {\n    // Avoid serving a stale local search index after a registry refresh.\n    rmSync(getSourceSearchIndexPath(source.name), { force: true });\n    if (err.message?.startsWith('404 ')) {\n      searchIndexAvailable = false;\n    }\n  }\n\n  const nextMeta = {\n    ...readMeta(source.name),\n    lastUpdated: Date.now(),\n  };\n  delete nextMeta.searchIndexAvailable;\n  delete nextMeta.searchIndexCheckedAt;\n\n  if (searchIndexAvailable !== undefined) {\n    nextMeta.searchIndexAvailable = searchIndexAvailable;\n    nextMeta.searchIndexCheckedAt = searchIndexCheckedAt;\n  }\n\n  writeMeta(source.name, nextMeta);\n}\n\n/**\n * Fetch registries for all configured sources.\n */\nexport async function fetchAllRegistries(force = false) {\n  const config = loadConfig();\n  const errors = [];\n\n  for (const source of config.sources) {\n    if (source.path) continue; // Local sources don't need fetching\n    try {\n      await fetchRemoteRegistry(source, force);\n    } catch (err) {\n      errors.push({ source: source.name, error: err.message });\n    }\n  }\n\n  return errors;\n}\n\n/**\n * Download full bundle for a remote source.\n */\nexport async function fetchFullBundle(sourceName) {\n  const config = loadConfig();\n  const source = config.sources.find((s) => s.name === sourceName);\n  if (!source || source.path) {\n    throw new Error(`Source \"${sourceName}\" is not a remote source.`);\n  }\n\n  const url = `${source.url}/bundle.tar.gz`;\n  const tmpPath = join(getSourceDir(sourceName), 'bundle.tar.gz');\n\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 30000);\n  let res;\n  try {\n    res = await fetch(url, { signal: controller.signal });\n  } finally {\n    clearTimeout(timeout);\n  }\n  if (!res.ok) {\n    throw new Error(`Failed to fetch bundle from ${sourceName}: ${res.status} ${res.statusText}`);\n  }\n\n  const dir = getSourceDir(sourceName);\n  mkdirSync(dir, { recursive: true });\n  await pipeline(res.body, createWriteStream(tmpPath));\n\n  const { extract } = await import('tar');\n  const dataDir = getSourceDataDir(sourceName);\n  mkdirSync(dataDir, { recursive: true });\n  await extract({ file: tmpPath, cwd: dataDir });\n\n  // Copy registry.json from extracted bundle if present\n  const extractedRegistry = join(dataDir, 'registry.json');\n  if (existsSync(extractedRegistry)) {\n    const regData = readFileSync(extractedRegistry, 'utf8');\n    writeFileSync(getSourceRegistryPath(sourceName), regData);\n  }\n\n  const extractedSearchIndex = join(dataDir, 'search-index.json');\n  if (existsSync(extractedSearchIndex)) {\n    const searchIndexData = readFileSync(extractedSearchIndex, 'utf8');\n    writeFileSync(getSourceSearchIndexPath(sourceName), searchIndexData);\n  } else {\n    rmSync(getSourceSearchIndexPath(sourceName), { force: true });\n  }\n\n  writeMeta(sourceName, { ...readMeta(sourceName), lastUpdated: Date.now(), fullBundle: true });\n  rmSync(tmpPath, { force: true });\n}\n\n/**\n * Fetch a single doc. Source object must have name + (url or path).\n */\nexport async function fetchDoc(source, docPath) {\n  // Local source: read directly\n  if (source.path) {\n    const localPath = join(source.path, docPath);\n    if (!existsSync(localPath)) {\n      throw new Error(`File not found: ${localPath}`);\n    }\n    return readFileSync(localPath, 'utf8');\n  }\n\n  // Remote source: check cache first\n  const cachedPath = join(getSourceDataDir(source.name), docPath);\n  if (existsSync(cachedPath)) {\n    return readFileSync(cachedPath, 'utf8');\n  }\n\n  // Check bundled content (shipped with npm package)\n  const bundledPath = join(getBundledDir(), docPath);\n  if (existsSync(bundledPath)) {\n    return readFileSync(bundledPath, 'utf8');\n  }\n\n  // Fetch from CDN (optional — only if source has a URL)\n  const url = `${source.url}/${docPath}`;\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 30000);\n  let res;\n  try {\n    res = await fetch(url, { signal: controller.signal });\n  } finally {\n    clearTimeout(timeout);\n  }\n  if (!res.ok) {\n    throw new Error(`Failed to fetch ${docPath} from ${source.name}: ${res.status} ${res.statusText}`);\n  }\n\n  const content = await res.text();\n\n  // Cache locally\n  const dir = dirname(cachedPath);\n  mkdirSync(dir, { recursive: true });\n  writeFileSync(cachedPath, content);\n\n  return content;\n}\n\n/**\n * Fetch all files in an entry directory.\n * Returns array of { name, content }.\n */\nexport async function fetchDocFull(source, basePath, files) {\n  const results = [];\n  for (const file of files) {\n    const filePath = `${basePath}/${file}`;\n    const content = await fetchDoc(source, filePath);\n    results.push({ name: file, content });\n  }\n  return results;\n}\n\n/**\n * Load cached/local registry for a single source.\n */\nexport function loadSourceRegistry(source) {\n  if (source.path) {\n    // Local source: read registry.json from the folder\n    const regPath = join(source.path, 'registry.json');\n    if (!existsSync(regPath)) return null;\n    return JSON.parse(readFileSync(regPath, 'utf8'));\n  }\n\n  // Remote source: read from cache\n  const regPath = getSourceRegistryPath(source.name);\n  if (!existsSync(regPath)) return null;\n  return JSON.parse(readFileSync(regPath, 'utf8'));\n}\n\n/**\n * Load BM25 search index for a single source (if available).\n */\nexport function loadSearchIndex(source) {\n  const basePath = source.path || getSourceDir(source.name);\n  const indexPath = join(basePath, 'search-index.json');\n  if (!existsSync(indexPath)) return null;\n  try {\n    return JSON.parse(readFileSync(indexPath, 'utf8'));\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Get cache stats.\n */\nexport function getCacheStats() {\n  const chubDir = getChubDir();\n  if (!existsSync(chubDir)) {\n    return { exists: false, sources: [] };\n  }\n\n  const config = loadConfig();\n  const sourceStats = [];\n\n  for (const source of config.sources) {\n    if (source.path) {\n      sourceStats.push({ name: source.name, type: 'local', path: source.path });\n      continue;\n    }\n\n    const meta = readMeta(source.name);\n    const dataDir = getSourceDataDir(source.name);\n    let dataSize = 0;\n    let fileCount = 0;\n\n    if (existsSync(dataDir)) {\n      const walk = (dir) => {\n        for (const entry of readdirSync(dir, { withFileTypes: true })) {\n          const full = join(dir, entry.name);\n          if (entry.isDirectory()) walk(full);\n          else { dataSize += statSync(full).size; fileCount++; }\n        }\n      };\n      walk(dataDir);\n    }\n\n    sourceStats.push({\n      name: source.name,\n      type: 'remote',\n      hasRegistry: existsSync(getSourceRegistryPath(source.name)),\n      lastUpdated: meta.lastUpdated ? new Date(meta.lastUpdated).toISOString() : null,\n      fullBundle: meta.fullBundle || false,\n      fileCount,\n      dataSize,\n    });\n  }\n\n  return { exists: true, sources: sourceStats };\n}\n\n/**\n * Clear the cache (preserves config.yaml).\n */\nexport function clearCache() {\n  const chubDir = getChubDir();\n  const configPath = join(chubDir, 'config.yaml');\n  let configContent = null;\n  if (existsSync(configPath)) {\n    configContent = readFileSync(configPath, 'utf8');\n  }\n\n  rmSync(chubDir, { recursive: true, force: true });\n\n  if (configContent) {\n    mkdirSync(chubDir, { recursive: true });\n    writeFileSync(configPath, configContent);\n  }\n}\n\n/**\n * Ensure at least one registry is available.\n */\nexport async function ensureRegistry() {\n  const config = loadConfig();\n\n  // Check if any source has a registry available\n  let hasAny = false;\n  for (const source of config.sources) {\n    if (source.path) {\n      const regPath = join(source.path, 'registry.json');\n      if (existsSync(regPath)) { hasAny = true; break; }\n    } else {\n      if (existsSync(getSourceRegistryPath(source.name))) { hasAny = true; break; }\n    }\n  }\n\n  if (hasAny) {\n    // Auto-refresh stale remote registries (best-effort)\n    for (const source of config.sources) {\n      if (source.path) continue;\n      if (shouldFetchRemoteRegistry(source.name)) {\n        try { await fetchRemoteRegistry(source); } catch { /* use stale */ }\n      }\n    }\n    return;\n  }\n\n  // No registries at all — try bundled content first, then network\n  const bundledRegistry = join(getBundledDir(), 'registry.json');\n  if (existsSync(bundledRegistry)) {\n    // Seed cache from bundled content (ships with npm package)\n    const defaultDir = getSourceDir('default');\n    mkdirSync(defaultDir, { recursive: true });\n    writeFileSync(getSourceRegistryPath('default'), readFileSync(bundledRegistry, 'utf8'));\n    const bundledSearchIndex = join(getBundledDir(), 'search-index.json');\n    if (existsSync(bundledSearchIndex)) {\n      writeFileSync(getSourceSearchIndexPath('default'), readFileSync(bundledSearchIndex, 'utf8'));\n    }\n    writeMeta('default', { lastUpdated: 0, bundledSeed: true }); // lastUpdated=0 → stale, so chub update will refresh\n    return;\n  }\n\n  // No bundled content either — must download from remote\n  await fetchAllRegistries(true);\n}\n"
  },
  {
    "path": "cli/src/lib/config.js",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { parse as parseYaml } from 'yaml';\n\nconst DEFAULT_CDN_URL = 'https://cdn.aichub.org/v1';\nconst DEFAULT_TELEMETRY_URL = 'https://api.aichub.org/v1';\n\nconst DEFAULTS = {\n  output_dir: '.context',\n  refresh_interval: 21600,\n  output_format: 'human',\n  source: 'official,maintainer,community',\n  telemetry: true,\n  feedback: true,\n  telemetry_url: DEFAULT_TELEMETRY_URL,\n};\n\nlet _config = null;\n\nexport function getChubDir() {\n  return process.env.CHUB_DIR || join(homedir(), '.chub');\n}\n\nexport function loadConfig() {\n  if (_config) return _config;\n\n  let fileConfig = {};\n  const configPath = join(getChubDir(), 'config.yaml');\n  try {\n    const raw = readFileSync(configPath, 'utf8');\n    fileConfig = parseYaml(raw) || {};\n  } catch {\n    // No config file, use defaults\n  }\n\n  // Build sources list\n  let sources;\n  if (fileConfig.sources && Array.isArray(fileConfig.sources)) {\n    sources = fileConfig.sources;\n  } else {\n    // Backward compat: single cdn_url becomes a single source\n    const url = process.env.CHUB_BUNDLE_URL || fileConfig.cdn_url || DEFAULT_CDN_URL;\n    sources = [{ name: 'default', url }];\n  }\n\n  _config = {\n    sources,\n    output_dir: fileConfig.output_dir || DEFAULTS.output_dir,\n    refresh_interval: fileConfig.refresh_interval ?? DEFAULTS.refresh_interval,\n    output_format: fileConfig.output_format || DEFAULTS.output_format,\n    source: fileConfig.source || DEFAULTS.source,\n    telemetry: fileConfig.telemetry !== undefined ? fileConfig.telemetry : DEFAULTS.telemetry,\n    feedback: fileConfig.feedback !== undefined ? fileConfig.feedback : DEFAULTS.feedback,\n    telemetry_url: fileConfig.telemetry_url || DEFAULTS.telemetry_url,\n  };\n\n  return _config;\n}\n"
  },
  {
    "path": "cli/src/lib/frontmatter.js",
    "content": "import { parse as parseYaml } from 'yaml';\n\n/**\n * Parse YAML frontmatter from markdown content.\n * Returns { attributes, body } where attributes is the parsed YAML object.\n */\nexport function parseFrontmatter(content) {\n  const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n  if (!match) return { attributes: {}, body: content };\n  return {\n    attributes: parseYaml(match[1]) || {},\n    body: match[2],\n  };\n}\n"
  },
  {
    "path": "cli/src/lib/identity.js",
    "content": "import { createHash } from 'node:crypto';\nimport { execSync } from 'node:child_process';\nimport { platform } from 'node:os';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getChubDir } from './config.js';\n\nlet _cachedClientId = null;\n\n/**\n * Get the platform-native machine UUID.\n */\nfunction getMachineUUID() {\n  const plat = platform();\n\n  if (plat === 'darwin') {\n    return execSync(\n      `ioreg -rd1 -c IOPlatformExpertDevice | awk -F'\"' '/IOPlatformUUID/{print $4}'`,\n      { encoding: 'utf8' }\n    ).trim();\n  }\n\n  if (plat === 'linux') {\n    try {\n      return readFileSync('/etc/machine-id', 'utf8').trim();\n    } catch {\n      return readFileSync('/var/lib/dbus/machine-id', 'utf8').trim();\n    }\n  }\n\n  if (plat === 'win32') {\n    const output = execSync(\n      'reg query \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Cryptography\" /v MachineGuid',\n      { encoding: 'utf8' }\n    );\n    const match = output.match(/MachineGuid\\s+REG_SZ\\s+(.+)/);\n    if (match) return match[1].trim();\n    throw new Error('Could not parse MachineGuid from registry');\n  }\n\n  throw new Error(`Unsupported platform: ${plat}`);\n}\n\n/**\n * Get or create a stable, anonymous client ID.\n * Checks ~/.chub/client_id for a cached 64-char hex string.\n * If not found, hashes the machine UUID with SHA-256 and saves it.\n */\nexport async function getOrCreateClientId() {\n  if (_cachedClientId) return _cachedClientId;\n\n  const chubDir = getChubDir();\n  const idPath = join(chubDir, 'client_id');\n\n  // Try to read existing client id\n  try {\n    const existing = readFileSync(idPath, 'utf8').trim();\n    if (/^[0-9a-f]{64}$/.test(existing)) {\n      _cachedClientId = existing;\n      return existing;\n    }\n  } catch {\n    // File doesn't exist or is unreadable\n  }\n\n  // Generate from machine UUID — this is a first-time user\n  const uuid = getMachineUUID();\n  const hash = createHash('sha256').update(uuid).digest('hex');\n\n  // Ensure directory exists\n  if (!existsSync(chubDir)) {\n    mkdirSync(chubDir, { recursive: true });\n  }\n\n  writeFileSync(idPath, hash, 'utf8');\n  _cachedClientId = hash;\n  _isFirstRun = true;\n  return hash;\n}\n\nlet _isFirstRun = false;\n\n/**\n * Returns true if this is the first time the CLI has run on this machine.\n * Only valid after getOrCreateClientId() has been called.\n */\nexport function isFirstRun() {\n  return _isFirstRun;\n}\n\n/**\n * Auto-detect the AI coding tool from environment variables.\n */\nexport function detectAgent() {\n  if (process.env.CLAUDE_CODE || process.env.CLAUDE_SESSION_ID) return 'claude-code';\n  if (process.env.CURSOR_SESSION_ID || process.env.CURSOR_TRACE_ID) return 'cursor';\n  if (process.env.CODEX_HOME || process.env.CODEX_SESSION) return 'codex';\n  if (process.env.WINDSURF_SESSION) return 'windsurf';\n  if (process.env.AIDER_MODEL || process.env.AIDER) return 'aider';\n  if (process.env.CLINE_SESSION) return 'cline';\n  if (process.env.GITHUB_COPILOT) return 'copilot';\n  return 'unknown';\n}\n\n/**\n * Detect the version of the AI coding tool, if available.\n */\nexport function detectAgentVersion() {\n  return process.env.CLAUDE_CODE_VERSION || process.env.CURSOR_VERSION || undefined;\n}\n"
  },
  {
    "path": "cli/src/lib/normalize.js",
    "content": "const ALIASES = {\n  js: 'javascript',\n  ts: 'typescript',\n  py: 'python',\n  rb: 'ruby',\n  cs: 'csharp',\n};\n\nconst DISPLAY = {\n  javascript: 'js',\n  typescript: 'ts',\n  python: 'py',\n  ruby: 'rb',\n  csharp: 'cs',\n};\n\nexport function normalizeLanguage(lang) {\n  if (!lang) return null;\n  const lower = lang.toLowerCase();\n  return ALIASES[lower] || lower;\n}\n\nexport function displayLanguage(lang) {\n  return DISPLAY[lang] || lang;\n}\n"
  },
  {
    "path": "cli/src/lib/output.js",
    "content": "/**\n * Dual-mode output: human-friendly (default) or JSON (--json flag).\n *\n * Every command calls `output(data, humanFormatter, opts)`.\n * - In JSON mode: prints JSON to stdout, nothing else.\n * - In human mode: calls humanFormatter(data) which prints with chalk.\n */\nexport function output(data, humanFormatter, opts) {\n  if (opts?.json) {\n    console.log(JSON.stringify(data, null, 2));\n  } else {\n    humanFormatter(data);\n  }\n}\n\n/**\n * Print a message to stderr (for confirmations when -o is used).\n */\nexport function info(msg) {\n  process.stderr.write(msg + '\\n');\n}\n\n/**\n * Print an error and exit.\n */\nexport function error(msg, opts) {\n  if (opts?.json) {\n    console.log(JSON.stringify({ error: msg }));\n  } else {\n    process.stderr.write(`Error: ${msg}\\n`);\n  }\n  process.exit(1);\n}\n"
  },
  {
    "path": "cli/src/lib/registry.js",
    "content": "import { loadSourceRegistry, loadSearchIndex } from './cache.js';\nimport { loadConfig } from './config.js';\nimport { normalizeLanguage } from './normalize.js';\nimport { buildIndexFromDocuments, compactIdentifier, search as bm25Search, tokenize } from './bm25.js';\n\nlet _merged = null;\nlet _searchIndex = null;\n\nfunction getSearchLookupId(sourceName, entryId) {\n  return `${sourceName}:${entryId}`;\n}\n\nfunction normalizeQuery(query) {\n  return String(query || '')\n    .trim()\n    .replace(/\\s+/g, ' ');\n}\n\nfunction splitCompactSegments(text) {\n  return [...new Set([\n    ...String(text || '').split('/').map((segment) => compactIdentifier(segment)),\n    ...String(text || '').split(/[\\/_.\\s-]+/).map((segment) => compactIdentifier(segment)),\n  ])].filter(Boolean);\n}\n\nfunction levenshteinDistance(a, b, maxDistance = Infinity) {\n  if (a === b) return 0;\n  if (!a.length) return b.length;\n  if (!b.length) return a.length;\n  if (Math.abs(a.length - b.length) > maxDistance) return maxDistance + 1;\n\n  let previous = Array.from({ length: b.length + 1 }, (_, idx) => idx);\n  let current = new Array(b.length + 1);\n\n  for (let i = 1; i <= a.length; i++) {\n    current[0] = i;\n    let rowMin = current[0];\n\n    for (let j = 1; j <= b.length; j++) {\n      const substitutionCost = a[i - 1] === b[j - 1] ? 0 : 1;\n      current[j] = Math.min(\n        previous[j] + 1,\n        current[j - 1] + 1,\n        previous[j - 1] + substitutionCost,\n      );\n      rowMin = Math.min(rowMin, current[j]);\n    }\n\n    if (rowMin > maxDistance) return maxDistance + 1;\n    [previous, current] = [current, previous];\n  }\n\n  return previous[b.length];\n}\n\nfunction scoreCompactCandidate(queryCompact, candidateCompact, weights) {\n  if (!queryCompact || !candidateCompact) return 0;\n  if (candidateCompact === queryCompact) return weights.exact;\n  if (queryCompact.length < 3) return 0;\n\n  const lengthPenalty = Math.abs(candidateCompact.length - queryCompact.length);\n  const lengthRatio = Math.min(candidateCompact.length, queryCompact.length)\n    / Math.max(candidateCompact.length, queryCompact.length);\n\n  if ((candidateCompact.startsWith(queryCompact) || queryCompact.startsWith(candidateCompact)) && lengthRatio >= 0.6) {\n    return Math.max(weights.prefix - lengthPenalty, 0);\n  }\n\n  if ((candidateCompact.includes(queryCompact) || queryCompact.includes(candidateCompact)) && lengthRatio >= 0.75) {\n    return Math.max(weights.contains - lengthPenalty, 0);\n  }\n\n  if (queryCompact.length < 5) return 0;\n\n  const maxDistance = queryCompact.length <= 5 ? 1 : queryCompact.length <= 8 ? 2 : 3;\n  const distance = levenshteinDistance(queryCompact, candidateCompact, maxDistance);\n  if (distance > maxDistance) return 0;\n\n  return Math.max(weights.fuzzy - (distance * 20) - lengthPenalty, 0);\n}\n\nfunction scoreEntryLexicalVariant(entry, queryCompact) {\n  if (queryCompact.length < 2) return 0;\n\n  const nameCompact = compactIdentifier(entry.name);\n  const idCompact = compactIdentifier(entry.id);\n  const idSegments = splitCompactSegments(entry.id);\n  const nameSegments = splitCompactSegments(entry.name);\n\n  let best = 0;\n\n  best = Math.max(best, scoreCompactCandidate(queryCompact, nameCompact, {\n    exact: 620,\n    prefix: 560,\n    contains: 520,\n    fuzzy: 500,\n  }));\n\n  best = Math.max(best, scoreCompactCandidate(queryCompact, idCompact, {\n    exact: 600,\n    prefix: 540,\n    contains: 500,\n    fuzzy: 470,\n  }));\n\n  for (let idx = 0; idx < idSegments.length; idx++) {\n    const segment = idSegments[idx];\n    const segmentScore = scoreCompactCandidate(queryCompact, segment, {\n      exact: 580,\n      prefix: 530,\n      contains: 490,\n      fuzzy: 460,\n    });\n    if (segmentScore === 0) continue;\n\n    let bonus = 0;\n    const isFirst = idx === 0;\n    const isLast = idx === idSegments.length - 1;\n    if (isFirst) bonus += 10;\n    if (isLast) bonus += 10;\n    if (queryCompact === idSegments[0]) bonus += 60;\n    if (queryCompact === idSegments[idSegments.length - 1]) bonus += 25;\n    if (idSegments.length > 1 && queryCompact === idSegments[0] && queryCompact === idSegments[idSegments.length - 1]) {\n      bonus += 40;\n    }\n\n    best = Math.max(best, segmentScore + bonus);\n  }\n\n  for (const segment of nameSegments) {\n    best = Math.max(best, scoreCompactCandidate(queryCompact, segment, {\n      exact: 560,\n      prefix: 520,\n      contains: 480,\n      fuzzy: 450,\n    }));\n  }\n\n  return best;\n}\n\nfunction scoreEntryLexicalBoost(entry, normalizedQuery, rescueTerms = []) {\n  const queryCompacts = [...new Set([\n    compactIdentifier(normalizedQuery),\n    ...rescueTerms.map((term) => compactIdentifier(term)),\n  ])].filter((queryCompact) => queryCompact.length >= 2);\n\n  let best = 0;\n  for (const queryCompact of queryCompacts) {\n    best = Math.max(best, scoreEntryLexicalVariant(entry, queryCompact));\n  }\n  return best;\n}\n\nfunction getMissingQueryTerms(normalizedQuery) {\n  if (!_searchIndex?.invertedIndex) {\n    return [];\n  }\n\n  return tokenize(normalizedQuery).filter((term) => !_searchIndex.invertedIndex[term]?.length);\n}\n\nfunction shouldRunGlobalLexicalScan(normalizedQuery, resultByKey) {\n  if (!_searchIndex || resultByKey.size === 0) {\n    return true;\n  }\n\n  if (!_searchIndex.invertedIndex) {\n    return false;\n  }\n\n  const queryTerms = tokenize(normalizedQuery);\n  if (queryTerms.length < 2) {\n    return false;\n  }\n\n  return getMissingQueryTerms(normalizedQuery).length > 0;\n}\n\nfunction namespaceSearchIndex(index, sourceName) {\n  return {\n    ...index,\n    documents: (index.documents || []).map((doc) => ({\n      ...doc,\n      id: getSearchLookupId(sourceName, doc.id),\n    })),\n  };\n}\n\n/**\n * Load and merge entries from all configured sources.\n * Returns { docs: [...], skills: [...] } with each entry tagged with _source/_sourceObj.\n */\nfunction getMerged() {\n  if (_merged) return _merged;\n\n  const config = loadConfig();\n  const allDocs = [];\n  const allSkills = [];\n  const searchIndexes = [];\n\n  for (const source of config.sources) {\n    const registry = loadSourceRegistry(source);\n    if (!registry) continue;\n\n    // Load BM25 search index if available\n    const idx = loadSearchIndex(source);\n    if (idx) searchIndexes.push(namespaceSearchIndex(idx, source.name));\n\n    // Support both new format (docs/skills) and old format (entries)\n    if (registry.docs) {\n      for (const doc of registry.docs) {\n        allDocs.push({ ...doc, id: doc.id || doc.name, _source: source.name, _sourceObj: source });\n      }\n    }\n    if (registry.skills) {\n      for (const skill of registry.skills) {\n        allSkills.push({ ...skill, id: skill.id || skill.name, _source: source.name, _sourceObj: source });\n      }\n    }\n\n    // Backward compat: old entries[] format\n    if (registry.entries) {\n      for (const entry of registry.entries) {\n        const tagged = { ...entry, _source: source.name, _sourceObj: source };\n        const provides = entry.languages?.[0]?.versions?.[0]?.provides || [];\n        if (provides.includes('skill')) {\n          allSkills.push(tagged);\n        }\n        if (provides.includes('doc') || provides.length === 0) {\n          allDocs.push(tagged);\n        }\n      }\n    }\n  }\n\n  // Merge search indexes (combine documents and recompute IDF)\n  if (searchIndexes.length > 0) {\n    if (searchIndexes.length === 1) {\n      const [singleIndex] = searchIndexes;\n      _searchIndex = singleIndex.invertedIndex\n        ? singleIndex\n        : buildIndexFromDocuments(singleIndex.documents, singleIndex.params);\n    } else {\n      const allDocuments = searchIndexes.flatMap((idx) => idx.documents);\n      _searchIndex = buildIndexFromDocuments(allDocuments, searchIndexes[0].params);\n    }\n  }\n\n  _merged = { docs: allDocs, skills: allSkills };\n  return _merged;\n}\n\n/**\n * Get all entries (docs + skills combined) for listing/searching.\n */\nfunction getAllEntries() {\n  const { docs, skills } = getMerged();\n  // Tag each with _type for display\n  const taggedDocs = docs.map((d) => ({ ...d, _type: 'doc' }));\n  const taggedSkills = skills.map((s) => ({ ...s, _type: 'skill' }));\n  // Deduplicate: if same id+source appears in both, keep both but mark as bundled\n  return [...taggedDocs, ...taggedSkills];\n}\n\n/**\n * Filter entries by the global source trust policy.\n */\nfunction applySourceFilter(entries) {\n  const config = loadConfig();\n  const allowed = config.source.split(',').map((s) => s.trim().toLowerCase());\n  return entries.filter((e) => !e.source || allowed.includes(e.source.toLowerCase()));\n}\n\n/**\n * Apply tag and language filters.\n */\nfunction applyFilters(entries, filters) {\n  let result = entries;\n\n  if (filters.tags) {\n    const filterTags = filters.tags.split(',').map((t) => t.trim().toLowerCase());\n    result = result.filter((e) =>\n      filterTags.every((ft) => e.tags?.some((t) => t.toLowerCase() === ft))\n    );\n  }\n  if (filters.lang) {\n    const lang = normalizeLanguage(filters.lang);\n    result = result.filter((e) =>\n      e.languages?.some((l) => l.language === lang)\n    );\n  }\n\n  return result;\n}\n\n/**\n * Check if an id has collisions across sources.\n */\nfunction getEntriesById(id, entries) {\n  return entries.filter((e) => e.id === id);\n}\n\n/**\n * Check if we're in multi-source mode.\n */\nexport function isMultiSource() {\n  const config = loadConfig();\n  return config.sources.length > 1;\n}\n\n/**\n * Get the display id for an entry — namespaced only on collision.\n */\nexport function getDisplayId(entry) {\n  if (!isMultiSource()) return entry.id;\n  const all = applySourceFilter(getAllEntries());\n  const matches = getEntriesById(entry.id, all).filter((e) => e._type === entry._type);\n  if (matches.length > 1) return `${entry._source}:${entry.id}`;\n  return entry.id;\n}\n\n/**\n * Search entries by query string. Searches both docs and skills.\n * Uses BM25 when a search index is available, falls back to keyword matching.\n */\nexport function searchEntries(query, filters = {}) {\n  const normalizedQuery = normalizeQuery(query);\n  const entries = applySourceFilter(getAllEntries());\n\n  // Deduplicate: same id+source appearing as both doc and skill → show once\n  const seen = new Set();\n  const deduped = [];\n  for (const entry of entries) {\n    const key = `${entry._source}:${entry.id}`;\n    if (!seen.has(key)) {\n      seen.add(key);\n      deduped.push(entry);\n    }\n  }\n\n  // Build entry lookup by id\n  const entryById = new Map();\n  for (const entry of deduped) {\n    entryById.set(getSearchLookupId(entry._source, entry.id), entry);\n  }\n\n  if (!normalizedQuery) {\n    return applyFilters(deduped, filters).map((entry) => ({ ...entry, _score: 0 }));\n  }\n\n  const resultByKey = new Map();\n\n  if (_searchIndex) {\n    // BM25 search\n    for (const match of bm25Search(normalizedQuery, _searchIndex)) {\n      const entry = entryById.get(match.id);\n      if (!entry) continue;\n      const key = getSearchLookupId(entry._source, entry.id);\n      resultByKey.set(key, { entry, score: match.score });\n    }\n  } else {\n    // Fallback: keyword matching\n    const q = normalizedQuery.toLowerCase();\n    const words = q.split(/\\s+/);\n\n    for (const entry of deduped) {\n      let score = 0;\n\n      if (entry.id === q) score += 100;\n      else if (entry.id.includes(q)) score += 50;\n\n      const nameLower = entry.name.toLowerCase();\n      if (nameLower === q) score += 80;\n      else if (nameLower.includes(q)) score += 40;\n\n      for (const word of words) {\n        if (entry.id.includes(word)) score += 10;\n        if (nameLower.includes(word)) score += 10;\n        if (entry.description?.toLowerCase().includes(word)) score += 5;\n        if (entry.tags?.some((t) => t.toLowerCase().includes(word))) score += 15;\n      }\n\n      if (score > 0) {\n        const key = getSearchLookupId(entry._source, entry.id);\n        resultByKey.set(key, { entry, score });\n      }\n    }\n  }\n\n  const lexicalCandidates = !shouldRunGlobalLexicalScan(normalizedQuery, resultByKey)\n    ? [...new Set([...resultByKey.values()].map(({ entry }) => entry))]\n    : deduped;\n  const rescueTerms = resultByKey.size > 0\n    ? getMissingQueryTerms(normalizedQuery).filter((term) => term.length >= 5)\n    : [];\n\n  for (const entry of lexicalCandidates) {\n    const boost = scoreEntryLexicalBoost(entry, normalizedQuery, rescueTerms);\n    if (boost === 0) continue;\n\n    const key = getSearchLookupId(entry._source, entry.id);\n    const current = resultByKey.get(key);\n    if (current) {\n      current.score += boost;\n    } else {\n      resultByKey.set(key, { entry, score: boost });\n    }\n  }\n\n  let results = [...resultByKey.values()];\n\n  const filtered = applyFilters(results.map((r) => r.entry), filters);\n  const filteredSet = new Set(filtered);\n  results = results.filter((r) => filteredSet.has(r.entry));\n\n  results.sort((a, b) => b.score - a.score);\n  return results.map((r) => ({ ...r.entry, _score: r.score }));\n}\n\n/**\n * Get entry by id or source/id, from a specific type array.\n * type: \"doc\" or \"skill\". If null, searches both.\n */\nexport function getEntry(idOrNamespacedId, type = null) {\n  const normalizedId = normalizeQuery(idOrNamespacedId);\n  const { docs, skills } = getMerged();\n  let pool;\n  if (type === 'doc') pool = applySourceFilter(docs);\n  else if (type === 'skill') pool = applySourceFilter(skills);\n  else pool = applySourceFilter([...docs, ...skills]);\n\n  // Check for source:id format (colon separates source from id)\n  if (normalizedId.includes(':')) {\n    const colonIdx = normalizedId.indexOf(':');\n    const sourceName = normalizedId.slice(0, colonIdx);\n    const id = normalizedId.slice(colonIdx + 1);\n    const entry = pool.find((e) => e._source === sourceName && e.id === id);\n    return entry ? { entry, ambiguous: false } : { entry: null, ambiguous: false };\n  }\n\n  // Bare id (may contain slashes like author/name)\n  const matches = pool.filter((e) => e.id === normalizedId);\n  if (matches.length === 0) return { entry: null, ambiguous: false };\n  if (matches.length === 1) return { entry: matches[0], ambiguous: false };\n\n  // Ambiguous — multiple sources have this id\n  return {\n    entry: null,\n    ambiguous: true,\n    alternatives: matches.map((e) => `${e._source}:${e.id}`),\n  };\n}\n\n/**\n * List entries with optional filters. Searches both docs and skills, deduped.\n */\nexport function listEntries(filters = {}) {\n  const entries = applySourceFilter(getAllEntries());\n  // Deduplicate\n  const seen = new Set();\n  const deduped = [];\n  for (const entry of entries) {\n    const key = `${entry._source}:${entry.id}`;\n    if (!seen.has(key)) {\n      seen.add(key);\n      deduped.push(entry);\n    }\n  }\n  return applyFilters(deduped, filters);\n}\n\n/**\n * Resolve the doc path + source for a doc entry.\n * Returns { source, path, files } or null.\n * If language is null and multiple languages exist, returns { needsLanguage: true, available: [...] }.\n */\nexport function resolveDocPath(entry, language, version) {\n  const lang = language ? normalizeLanguage(language) : null;\n\n  // Skills are flat — no language/version nesting\n  if (!entry.languages) {\n    // This is a skill entry — path is directly on the entry\n    if (!entry.path) return null;\n    return {\n      source: entry._sourceObj,\n      path: entry.path,\n      files: entry.files || [],\n    };\n  }\n\n  let langObj = null;\n  if (lang) {\n    langObj = entry.languages.find((l) => l.language === lang);\n  } else {\n    return {\n      needsLanguage: true,\n      available: entry.languages.map((l) => l.language),\n    };\n  }\n\n  if (!langObj) return null;\n\n  let verObj = null;\n  if (version) {\n    verObj = langObj.versions?.find((v) => v.version === version);\n    if (!verObj) {\n      return {\n        versionNotFound: true,\n        requested: version,\n        available: langObj.versions?.map((v) => v.version) || [],\n      };\n    }\n  } else {\n    const rec = langObj.recommendedVersion;\n    verObj = langObj.versions?.find((v) => v.version === rec) || langObj.versions?.[0];\n  }\n\n  if (!verObj?.path) return null;\n  return {\n    source: entry._sourceObj,\n    path: verObj.path,\n    files: verObj.files || [],\n  };\n}\n\n/**\n * Given a resolved path and a type (\"doc\" or \"skill\"), return the entry file path.\n */\nexport function resolveEntryFile(resolved, type) {\n  if (!resolved || resolved.needsLanguage || resolved.versionNotFound) return { error: 'unresolved' };\n\n  const fileName = type === 'skill' ? 'SKILL.md' : 'DOC.md';\n\n  return {\n    filePath: `${resolved.path}/${fileName}`,\n    basePath: resolved.path,\n    files: resolved.files,\n  };\n}\n"
  },
  {
    "path": "cli/src/lib/telemetry.js",
    "content": "import { loadConfig } from './config.js';\n\nconst DEFAULT_TELEMETRY_URL = 'https://api.aichub.org/v1';\n\nexport function isTelemetryEnabled() {\n  if (process.env.CHUB_TELEMETRY === '0' || process.env.CHUB_TELEMETRY === 'false') return false;\n  const config = loadConfig();\n  return config.telemetry !== false;\n}\n\nexport function isFeedbackEnabled() {\n  if (process.env.CHUB_FEEDBACK === '0' || process.env.CHUB_FEEDBACK === 'false') return false;\n  const config = loadConfig();\n  return config.feedback !== false;\n}\n\nexport function getTelemetryUrl() {\n  const url = process.env.CHUB_TELEMETRY_URL;\n  if (url) return url;\n  const config = loadConfig();\n  return config.telemetry_url || DEFAULT_TELEMETRY_URL;\n}\n\n/**\n * Send feedback to the API.\n *\n * @param {string} entryId - e.g. \"openai/chat\"\n * @param {string} entryType - \"doc\" or \"skill\"\n * @param {string} rating - \"up\" or \"down\"\n * @param {object} opts - Additional context\n * @param {string} [opts.comment]\n * @param {string} [opts.docLang] - Language variant fetched\n * @param {string} [opts.docVersion] - Version fetched\n * @param {string} [opts.targetFile] - Specific file within the entry\n * @param {string[]} [opts.labels] - Structured feedback labels\n * @param {string} [opts.agent] - Agent name override\n * @param {string} [opts.model] - LLM model override\n * @param {string} [opts.cliVersion]\n * @param {string} [opts.source] - Registry source name\n */\nexport async function sendFeedback(entryId, entryType, rating, opts = {}) {\n  if (!isFeedbackEnabled()) return { status: 'skipped', reason: 'feedback_disabled' };\n\n  const { getOrCreateClientId, detectAgent, detectAgentVersion } = await import('./identity.js');\n  const clientId = await getOrCreateClientId();\n  const telemetryUrl = getTelemetryUrl();\n\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 3000);\n\n  try {\n    const res = await fetch(`${telemetryUrl}/feedback`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-Client-ID': clientId,\n      },\n      body: JSON.stringify({\n        entry_id: entryId,\n        entry_type: entryType,\n        rating,\n        // Doc-specific dimensions\n        doc_lang: opts.docLang || undefined,\n        doc_version: opts.docVersion || undefined,\n        target_file: opts.targetFile || undefined,\n        // Structured feedback\n        labels: opts.labels || undefined,\n        comment: opts.comment || undefined,\n        // Agent info\n        agent: {\n          name: opts.agent || detectAgent(),\n          version: detectAgentVersion(),\n          model: opts.model || undefined,\n        },\n        // Context\n        cli_version: opts.cliVersion || undefined,\n        source: opts.source || undefined,\n      }),\n      signal: controller.signal,\n    });\n    clearTimeout(timeout);\n\n    if (res.ok) {\n      const data = await res.json();\n      return { status: 'sent', feedback_id: data.feedback_id || data.id };\n    }\n    return { status: 'error', code: res.status };\n  } catch (err) {\n    clearTimeout(timeout);\n    return { status: 'error', reason: 'network' };\n  }\n}\n"
  },
  {
    "path": "cli/src/lib/welcome.js",
    "content": "import { existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport chalk from 'chalk';\nimport { getChubDir } from './config.js';\n\nconst WELCOME_MARKER = '.welcome_shown';\n\n/**\n * Show the first-run welcome notice if it hasn't been shown yet.\n * Creates a marker file so it only displays once.\n */\nexport function showWelcomeIfNeeded(opts = {}) {\n  if (opts.json) return;\n  if (!process.stdout.isTTY || !process.stderr.isTTY) return;\n\n  const chubDir = getChubDir();\n  const markerPath = join(chubDir, WELCOME_MARKER);\n  const configPath = join(chubDir, 'config.yaml');\n\n  if (existsSync(markerPath)) return;\n\n  // Print to stderr so it doesn't interfere with JSON/piped output\n  console.error(`\n${chalk.bold('Welcome to Context Hub (chub)!')} Chub helps your AI coding agents make API calls correctly, by providing \\\nthe latest documentation.\n\nBy using chub, you agree to the Terms of Service at ${chalk.underline('https://www.aichub.org/tos.html')}\n\nChub asks agents to provide feedback on documentation, and this feedback is used to improve docs for the developer \\\ncommunity. If you wish to disable this feedback, add ${chalk.bold('\"feedback: false\"')} to ${chalk.bold(configPath)}. See \\\n${chalk.underline('https://github.com/andrewyng/context-hub')} for details.\n`);\n\n  try {\n    if (!existsSync(chubDir)) {\n      mkdirSync(chubDir, { recursive: true });\n    }\n    writeFileSync(markerPath, new Date().toISOString(), 'utf8');\n  } catch {\n    // Best-effort — don't block CLI if marker can't be written\n  }\n}\n"
  },
  {
    "path": "cli/src/mcp/server.js",
    "content": "/**\n * Context Hub MCP Server.\n *\n * Exposes chub search, get, list, annotate, and feedback as MCP tools\n * for use with Claude Code, Cursor, and other MCP-compatible agents.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { ensureRegistry } from '../lib/cache.js';\nimport { listEntries } from '../lib/registry.js';\nimport { handleSearch, handleGet, handleList, handleAnnotate, handleFeedback } from './tools.js';\nimport { attachStdioShutdownHandlers } from './stdio-lifecycle.js';\n\n// Prevent console.log from corrupting the stdio JSON-RPC protocol.\n// Any transitive dependency (e.g. posthog-node) that calls console.log\n// would break the MCP transport without this redirect.\nconst _stderr = process.stderr;\nconsole.log = (...args) => _stderr.write(args.join(' ') + '\\n');\nconsole.warn = (...args) => _stderr.write('[warn] ' + args.join(' ') + '\\n');\nconsole.info = (...args) => _stderr.write('[info] ' + args.join(' ') + '\\n');\nconsole.debug = (...args) => _stderr.write('[debug] ' + args.join(' ') + '\\n');\n\n// Read package version\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8'));\n\n// Create server\nconst server = new McpServer({\n  name: 'chub',\n  version: pkg.version,\n});\n\n// --- Register Tools ---\n\nserver.tool(\n  'chub_search',\n  'Search Context Hub for docs and skills by query, tags, or language',\n  {\n    query: z.string().optional().describe('Search query. Omit to list all entries.'),\n    tags: z.string().optional().describe('Comma-separated tag filter (e.g. \"openai,chat\")'),\n    lang: z.string().optional().describe('Filter by language (e.g. \"python\", \"js\")'),\n    limit: z.number().int().min(1).max(100).optional().describe('Max results (default 20)'),\n  },\n  async (args) => handleSearch(args),\n);\n\nserver.tool(\n  'chub_get',\n  'Fetch the content of a doc or skill by ID from Context Hub',\n  {\n    id: z.string().describe('Entry ID (e.g. \"openai/chat\", \"stripe/api\"). Use source:id for disambiguation.'),\n    lang: z.string().optional().describe('Language variant (e.g. \"python\", \"js\"). Auto-selected if only one.'),\n    version: z.string().optional().describe('Specific version (e.g. \"1.52.0\"). Defaults to recommended.'),\n    full: z.boolean().optional().describe('Fetch all files, not just the entry point (default false)'),\n    file: z.string().optional().describe('Fetch a specific file by path (e.g. \"references/streaming.md\")'),\n  },\n  async (args) => handleGet(args),\n);\n\nserver.tool(\n  'chub_list',\n  'List all available docs and skills in Context Hub',\n  {\n    tags: z.string().optional().describe('Comma-separated tag filter'),\n    lang: z.string().optional().describe('Filter by language'),\n    limit: z.number().int().min(1).max(500).optional().describe('Max entries (default 50)'),\n  },\n  async (args) => handleList(args),\n);\n\nserver.tool(\n  'chub_annotate',\n  'Read, write, clear, or list agent annotations. Modes: (1) list=true to list all, (2) id+note to write, (3) id+clear=true to delete, (4) id alone to read. Annotations persist locally across sessions.',\n  {\n    id: z.string().optional().describe('Entry ID to annotate (e.g. \"openai/chat\"). Required unless using list mode.'),\n    note: z.string().optional().describe('Annotation text to save. Omit to read existing annotation.'),\n    clear: z.boolean().optional().describe('Remove the annotation for this entry (default false)'),\n    list: z.boolean().optional().describe('List all annotations (default false). When true, id is not needed.'),\n  },\n  async (args) => handleAnnotate(args),\n);\n\nserver.tool(\n  'chub_feedback',\n  'Send quality feedback (thumbs up/down) for a doc or skill to help authors improve content',\n  {\n    id: z.string().describe('Entry ID to rate (e.g. \"openai/chat\")'),\n    rating: z.enum(['up', 'down']).describe('Thumbs up or down'),\n    comment: z.string().optional().describe('Optional comment explaining the rating'),\n    type: z.enum(['doc', 'skill']).optional().describe('Entry type. Auto-detected if omitted.'),\n    lang: z.string().optional().describe('Language variant rated'),\n    version: z.string().optional().describe('Version rated'),\n    file: z.string().optional().describe('Specific file rated'),\n    labels: z.array(z.enum([\n      'accurate', 'well-structured', 'helpful', 'good-examples',\n      'outdated', 'inaccurate', 'incomplete', 'wrong-examples',\n      'wrong-version', 'poorly-structured',\n    ])).optional().describe('Structured feedback labels'),\n  },\n  async (args) => handleFeedback(args),\n);\n\n// --- Register Resource ---\n\nserver.resource(\n  'registry',\n  'chub://registry',\n  {\n    title: 'Context Hub Registry',\n    description: 'Browse the full Context Hub registry of docs and skills',\n    mimeType: 'application/json',\n  },\n  async (uri) => {\n    try {\n      const entries = listEntries({});\n      const simplified = entries.map((entry) => ({\n        id: entry.id,\n        name: entry.name,\n        type: entry._type || (entry.languages ? 'doc' : 'skill'),\n        description: entry.description,\n        tags: entry.tags || [],\n        ...(entry.languages\n          ? {\n            languages: entry.languages.map((l) => ({\n              language: l.language,\n              versions: l.versions?.map((v) => v.version) || [],\n              recommended: l.recommendedVersion,\n            })),\n          }\n          : {}),\n      }));\n      return {\n        contents: [{\n          uri: uri.href,\n          mimeType: 'application/json',\n          text: JSON.stringify({ entries: simplified, total: simplified.length }, null, 2),\n        }],\n      };\n    } catch (err) {\n      console.warn(`Registry resource error: ${err.message}`);\n      return {\n        contents: [{\n          uri: uri.href,\n          mimeType: 'application/json',\n          text: JSON.stringify({ error: 'Registry not loaded. Run \"chub update\" first.' }),\n        }],\n      };\n    }\n  },\n);\n\n// --- Process Safety ---\n\n// Prevent the server from crashing on unhandled errors (long-lived process)\nprocess.on('uncaughtException', (err) => {\n  _stderr.write(`[chub-mcp] Uncaught exception: ${err.message}\\n`);\n});\nprocess.on('unhandledRejection', (reason) => {\n  _stderr.write(`[chub-mcp] Unhandled rejection: ${reason}\\n`);\n});\n\n// --- Start Server ---\n\n// Best-effort registry load — server starts even if this fails\ntry {\n  await ensureRegistry();\n} catch (err) {\n  _stderr.write(`[chub-mcp] Warning: Registry not loaded: ${err.message}\\n`);\n}\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n\n// Exit promptly when MCP host disconnects stdio.\n// Must be after server.connect() so StdioServerTransport's data handler\n// is already wired — otherwise stdin.resume() discards incoming bytes.\nattachStdioShutdownHandlers({ stderr: _stderr });\n\n_stderr.write(`[chub-mcp] Server started (v${pkg.version})\\n`);\n"
  },
  {
    "path": "cli/src/mcp/stdio-lifecycle.js",
    "content": "/**\n * Attach stdio lifecycle guards so chub-mcp exits cleanly when the parent\n * MCP host goes away (EOF / closed pipe).\n */\nexport function attachStdioShutdownHandlers({\n  stdin = process.stdin,\n  stdout = process.stdout,\n  stderr = process.stderr,\n  onShutdown = () => process.exit(0),\n} = {}) {\n  let shuttingDown = false;\n\n  const shutdown = (reason) => {\n    if (shuttingDown) return;\n    shuttingDown = true;\n\n    try {\n      stderr.write(`[chub-mcp] ${reason}\\n`);\n    } catch {\n      // ignore stderr write errors during shutdown\n    }\n\n    onShutdown(0);\n  };\n\n  const onStdinEnd = () => shutdown('Stdin closed; exiting.');\n  const onStdinClose = () => shutdown('Stdin stream closed; exiting.');\n  const onStdinError = (err) => {\n    const detail = err?.code || err?.message || 'unknown';\n    shutdown(`Stdin error (${detail}); exiting.`);\n  };\n  const onStdoutError = (err) => {\n    if (err?.code === 'EPIPE') {\n      shutdown('Stdout pipe closed (EPIPE); exiting.');\n    }\n  };\n\n  stdin.on('end', onStdinEnd);\n  stdin.on('close', onStdinClose);\n  stdin.on('error', onStdinError);\n  stdout.on('error', onStdoutError);\n\n  // Keep stdin flowing so EOF/end is observed reliably across hosts.\n  if (typeof stdin.resume === 'function') {\n    stdin.resume();\n  }\n\n  return () => {\n    stdin.off('end', onStdinEnd);\n    stdin.off('close', onStdinClose);\n    stdin.off('error', onStdinError);\n    stdout.off('error', onStdoutError);\n  };\n}\n"
  },
  {
    "path": "cli/src/mcp/tools.js",
    "content": "/**\n * MCP tool handler implementations.\n * Each handler wraps existing lib/ functions and returns MCP-compatible results.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join, resolve, relative } from 'node:path';\nimport { searchEntries, getEntry, listEntries, resolveDocPath, resolveEntryFile } from '../lib/registry.js';\nimport { fetchDoc, fetchDocFull } from '../lib/cache.js';\nimport { readAnnotation, writeAnnotation, clearAnnotation, listAnnotations } from '../lib/annotations.js';\nimport { sendFeedback, isFeedbackEnabled } from '../lib/telemetry.js';\nimport { trackEvent, setCliVersion } from '../lib/analytics.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nlet _cliVersion;\nfunction getCliVersion() {\n  if (_cliVersion) return _cliVersion;\n  try {\n    const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8'));\n    _cliVersion = pkg.version;\n    setCliVersion(_cliVersion);\n  } catch {\n    _cliVersion = 'unknown';\n  }\n  return _cliVersion;\n}\n// Initialize cli_version for analytics on module load\ngetCliVersion();\n\nfunction textResult(data) {\n  return {\n    content: [{ type: 'text', text: typeof data === 'string' ? data : JSON.stringify(data, null, 2) }],\n  };\n}\n\nfunction errorResult(message, details = {}) {\n  return {\n    content: [{ type: 'text', text: JSON.stringify({ error: message, ...details }, null, 2) }],\n    isError: true,\n  };\n}\n\n/**\n * Simplify an entry for agent-friendly output (strip internal fields).\n */\nfunction simplifyEntry(entry) {\n  const result = {\n    id: entry.id,\n    name: entry.name,\n    type: entry._type || (entry.languages ? 'doc' : 'skill'),\n    description: entry.description,\n    tags: entry.tags || [],\n  };\n  if (entry.languages) {\n    result.languages = entry.languages.map((l) => l.language);\n  }\n  return result;\n}\n\n// --- Tool Handlers ---\n\nexport async function handleSearch({ query, tags, lang, limit = 20 }) {\n  try {\n    const start = Date.now();\n    let entries;\n    if (query) {\n      entries = searchEntries(query, { tags, lang });\n    } else {\n      entries = listEntries({ tags, lang });\n    }\n    const sliced = entries.slice(0, limit);\n    if (query) {\n      trackEvent('search', {\n        query: query.slice(0, 1000),\n        query_length: query.length,\n        result_count: sliced.length,\n        results: sliced.map((e) => e.id || e.name || 'unknown'),\n        duration_ms: Date.now() - start,\n        has_tags: !!tags,\n        has_lang: !!lang,\n        tags: tags || undefined,\n        lang: lang || undefined,\n        via: 'mcp',\n      }).catch(() => {});\n    }\n    return textResult({\n      results: sliced.map(simplifyEntry),\n      total: entries.length,\n      showing: sliced.length,\n    });\n  } catch (err) {\n    return errorResult(`Search failed: ${err.message}`);\n  }\n}\n\nexport async function handleGet({ id, lang, version, full = false, file }) {\n  const start = Date.now();\n  try {\n    // Validate file parameter early (before entry lookup) to reject path traversal\n    if (file) {\n      const normalizedFile = resolve('/', file).slice(1);\n      if (normalizedFile !== file || file.includes('..')) {\n        return errorResult(`Invalid file path: \"${file}\". Path traversal is not allowed.`);\n      }\n    }\n\n    const result = getEntry(id);\n\n    if (result.ambiguous) {\n      return errorResult(`Ambiguous entry ID \"${id}\". Be specific:`, {\n        alternatives: result.alternatives,\n      });\n    }\n\n    if (!result.entry) {\n      trackEvent('doc_not_found', { entry_id: id, via: 'mcp' }).catch(() => {});\n      return errorResult(`Entry \"${id}\" not found.`, {\n        suggestion: 'Use chub_search to find available entries.',\n      });\n    }\n\n    const entry = result.entry;\n    const type = entry.languages ? 'doc' : 'skill';\n    const resolved = resolveDocPath(entry, lang, version);\n\n    if (!resolved) {\n      return errorResult(`Could not resolve path for \"${id}\".`);\n    }\n\n    if (resolved.versionNotFound) {\n      return errorResult(`Version \"${resolved.requested}\" not found for \"${id}\".`, {\n        available: resolved.available,\n      });\n    }\n\n    if (resolved.needsLanguage) {\n      return errorResult(`Multiple languages available for \"${id}\". Specify the lang parameter.`, {\n        available: resolved.available,\n      });\n    }\n\n    const entryFile = resolveEntryFile(resolved, type);\n    if (entryFile.error) {\n      return errorResult(`\"${id}\": ${entryFile.error}`);\n    }\n\n    let content;\n\n    if (file) {\n      // Fetch a specific file\n      if (!resolved.files.includes(file)) {\n        const entryFileName = type === 'skill' ? 'SKILL.md' : 'DOC.md';\n        const available = resolved.files.filter((f) => f !== entryFileName);\n        return errorResult(`File \"${file}\" not found in ${id}.`, {\n          available: available.length > 0 ? available : '(none)',\n        });\n      }\n      content = await fetchDoc(resolved.source, join(resolved.path, file));\n    } else if (full && resolved.files.length > 0) {\n      // Fetch all files\n      const allFiles = await fetchDocFull(resolved.source, resolved.path, resolved.files);\n      content = allFiles.map((f) => `# FILE: ${f.name}\\n\\n${f.content}`).join('\\n\\n---\\n\\n');\n    } else {\n      // Fetch entry point only\n      content = await fetchDoc(resolved.source, entryFile.filePath);\n    }\n\n    // Append annotation if present\n    const annotation = readAnnotation(entry.id);\n    if (annotation) {\n      content += `\\n\\n---\\n[Agent note — ${annotation.updatedAt}]\\n${annotation.note}\\n`;\n    }\n\n    const entryType = entry.languages ? 'doc' : 'skill';\n    const duration_ms = Date.now() - start;\n    // Emit same event names as CLI for consistent analytics\n    trackEvent(entryType === 'doc' ? 'doc_fetched' : 'skill_fetched', {\n      entry_id: entry.id,\n      full,\n      file: file || undefined,\n      lang: lang || undefined,\n      source: entry._source || undefined,\n      duration_ms,\n      via: 'mcp',\n    }).catch(() => {});\n\n    return textResult(content);\n  } catch (err) {\n    trackEvent('fetch_error', { entry_id: id, via: 'mcp', error_type: err.code || err.name || 'unknown' }).catch(() => {});\n    return errorResult(`Failed to fetch \"${id}\": ${err.message}`);\n  }\n}\n\nexport async function handleList({ tags, lang, limit = 50 }) {\n  try {\n    const entries = listEntries({ tags, lang });\n    const sliced = entries.slice(0, limit);\n    return textResult({\n      entries: sliced.map(simplifyEntry),\n      total: entries.length,\n      showing: sliced.length,\n    });\n  } catch (err) {\n    return errorResult(`List failed: ${err.message}`);\n  }\n}\n\nexport async function handleAnnotate({ id, note, clear = false, list = false }) {\n  try {\n    if (list) {\n      const annotations = listAnnotations();\n      return textResult({ annotations, total: annotations.length });\n    }\n\n    if (!id) {\n      return errorResult('Missing required parameter: id. Provide an entry ID or use list mode.');\n    }\n\n    // Validate entry ID to prevent path traversal or filesystem abuse\n    if (id.length > 200) {\n      return errorResult('Entry ID too long (max 200 characters).');\n    }\n    if (!/^[a-zA-Z0-9._\\-\\/]+$/.test(id)) {\n      return errorResult('Entry ID contains invalid characters. Use only alphanumeric, hyphens, underscores, dots, and slashes.');\n    }\n\n    if (clear) {\n      const removed = clearAnnotation(id);\n      return textResult({\n        status: removed ? 'cleared' : 'not_found',\n        id,\n      });\n    }\n\n    if (note) {\n      const saved = writeAnnotation(id, note);\n      return textResult({ status: 'saved', annotation: saved });\n    }\n\n    // Read mode\n    const annotation = readAnnotation(id);\n    if (annotation) {\n      return textResult({ annotation });\n    }\n    return textResult({ status: 'no_annotation', id });\n  } catch (err) {\n    return errorResult(`Annotation failed: ${err.message}`);\n  }\n}\n\nexport async function handleFeedback({ id, rating, comment, type, lang, version, file, labels }) {\n  try {\n    if (!isFeedbackEnabled()) {\n      return textResult({ status: 'skipped', reason: 'feedback_disabled' });\n    }\n\n    // Auto-detect entry type if not provided\n    let entryType = type;\n    if (!entryType) {\n      try {\n        const result = getEntry(id);\n        if (result.entry) {\n          entryType = result.entry.languages ? 'doc' : 'skill';\n        }\n      } catch {\n        // Fall through with undefined type\n      }\n      entryType = entryType || 'doc';\n    }\n\n    const result = await sendFeedback(id, entryType, rating, {\n      comment,\n      docLang: lang,\n      docVersion: version,\n      targetFile: file,\n      labels,\n      agent: 'mcp-server',\n      cliVersion: getCliVersion(),\n    });\n\n    return textResult(result);\n  } catch (err) {\n    return errorResult(`Feedback failed: ${err.message}`);\n  }\n}\n"
  },
  {
    "path": "cli/test/e2e.test.js",
    "content": "import { describe, it, expect, beforeAll, afterAll } from 'vitest';\nimport { execFileSync, spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { tmpdir } from 'node:os';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst CLI = join(__dirname, '..', 'bin', 'chub');\nconst FIXTURES = join(__dirname, 'fixtures');\nconst BUILD_OUTPUT = join(FIXTURES, 'dist');\nconst CLI_TEST_TIMEOUT = 15000;\nconst TEST_ENV = { ...process.env, NO_COLOR: '1', CHUB_TELEMETRY: '0', CHUB_FEEDBACK: '0' };\n\nlet tmpChubDir;\n\nconst itCli = (name, fn) => it(name, { timeout: CLI_TEST_TIMEOUT }, fn);\n\nfunction chub(args, { expectError = false } = {}) {\n  try {\n    const result = execFileSync('node', [CLI, ...args], {\n      encoding: 'utf8',\n      env: { ...TEST_ENV, CHUB_DIR: tmpChubDir },\n      timeout: CLI_TEST_TIMEOUT,\n    });\n    return result;\n  } catch (err) {\n    if (expectError) return err.stderr || err.stdout || err.message;\n    throw err;\n  }\n}\n\nfunction chubJSON(args) {\n  const out = chub([...args, '--json']);\n  return JSON.parse(out);\n}\n\ndescribe('chub CLI e2e', () => {\n  beforeAll(() => {\n    // Use an isolated temp directory so we never touch ~/.chub\n    tmpChubDir = mkdtempSync(join(tmpdir(), 'chub-e2e-'));\n\n    // Build fixtures\n    chub(['build', FIXTURES]);\n\n    // Point config at fixture build output (local source only)\n    writeFileSync(join(tmpChubDir, 'config.yaml'), `sources:\\n  - name: test\\n    path: ${BUILD_OUTPUT}\\n\\nsource: official,maintainer,community\\ntelemetry: false\\nfeedback: false\\n`);\n  }, CLI_TEST_TIMEOUT);\n\n  afterAll(() => {\n    // Clean up temp dir and build output\n    rmSync(tmpChubDir, { recursive: true, force: true });\n    rmSync(BUILD_OUTPUT, { recursive: true, force: true });\n  });\n\n  describe('build', () => {\n    itCli('keeps first-run JSON output clean', () => {\n      const freshChubDir = mkdtempSync(join(tmpdir(), 'chub-e2e-json-'));\n      try {\n        writeFileSync(join(freshChubDir, 'config.yaml'), `sources:\\n  - name: test\\n    path: ${BUILD_OUTPUT}\\n\\nsource: official,maintainer,community\\ntelemetry: false\\nfeedback: false\\n`);\n        const result = spawnSync('node', [CLI, 'build', FIXTURES, '--validate-only', '--json'], {\n          encoding: 'utf8',\n          env: { ...TEST_ENV, CHUB_DIR: freshChubDir },\n          timeout: CLI_TEST_TIMEOUT,\n        });\n\n        expect(result.status).toBe(0);\n        expect(() => JSON.parse(result.stdout)).not.toThrow();\n        expect(result.stderr).toBe('');\n      } finally {\n        rmSync(freshChubDir, { recursive: true, force: true });\n      }\n    });\n\n    itCli('produces registry.json', () => {\n      expect(existsSync(join(BUILD_OUTPUT, 'registry.json'))).toBe(true);\n    });\n\n    itCli('registry has correct counts', () => {\n      const reg = JSON.parse(readFileSync(join(BUILD_OUTPUT, 'registry.json'), 'utf8'));\n      expect(reg.docs.length).toBe(3); // acme/widgets + acme/versioned-api + multilang/client\n      expect(reg.skills.length).toBe(1); // testskills/deploy\n    });\n\n    itCli('copies content files to output', () => {\n      expect(existsSync(join(BUILD_OUTPUT, 'acme', 'docs', 'widgets', 'DOC.md'))).toBe(true);\n      expect(existsSync(join(BUILD_OUTPUT, 'acme', 'docs', 'widgets', 'references', 'advanced.md'))).toBe(true);\n    });\n\n    itCli('validates with --validate-only', () => {\n      const out = chub(['build', FIXTURES, '--validate-only']);\n      expect(out).toContain('3 docs');\n      expect(out).toContain('1 skills');\n    });\n\n    itCli('errors on missing content dir', () => {\n      const out = chub(['build', '/nonexistent/path'], { expectError: true });\n      expect(out).toContain('Content directory not found');\n    });\n  });\n\n  describe('search', () => {\n    itCli('lists all entries', () => {\n      const data = chubJSON(['search']);\n      expect(data.total).toBe(4); // 3 docs + 1 skill\n    });\n\n    itCli('fuzzy search finds by name', () => {\n      const data = chubJSON(['search', 'widget']);\n      expect(data.results.length).toBe(1);\n      expect(data.results[0].id).toBe('acme/widgets');\n    });\n\n    itCli('fuzzy search finds by description', () => {\n      const data = chubJSON(['search', 'deployment']);\n      expect(data.results.length).toBe(1);\n      expect(data.results[0].id).toBe('testskills/deploy');\n    });\n\n    itCli('exact id shows detail', () => {\n      const data = chubJSON(['search', 'acme/widgets']);\n      // Exact match returns the entry directly, not wrapped in results[]\n      expect(data.id).toBe('acme/widgets');\n      expect(data.languages).toBeDefined();\n    });\n\n    itCli('filters by tag', () => {\n      const data = chubJSON(['search', '--tags', 'automation']);\n      expect(data.results.length).toBe(1);\n      expect(data.results[0].id).toBe('testskills/deploy');\n    });\n\n    itCli('returns empty for no match', () => {\n      const data = chubJSON(['search', 'nonexistentthing']);\n      expect(data.results.length).toBe(0);\n    });\n  });\n\n  describe('get', () => {\n    itCli('fetches single-language doc with --lang', () => {\n      const out = chub(['get', 'acme/widgets', '--lang', 'js']);\n      expect(out).toContain('# Acme Widgets API');\n      expect(out).toContain('npm install @acme/widgets');\n    });\n\n    itCli('errors on single-lang doc without --lang', () => {\n      const out = chub(['get', 'acme/widgets'], { expectError: true });\n      expect(out).toContain('--lang');\n    });\n\n    itCli('fetches multi-language doc with --lang', () => {\n      const out = chub(['get', 'multilang/client', '--lang', 'py']);\n      expect(out).toContain('# Multilang Client — Python');\n      expect(out).toContain('from multilang import Client');\n    });\n\n    itCli('fetches js variant with --lang js', () => {\n      const out = chub(['get', 'multilang/client', '--lang', 'js']);\n      expect(out).toContain('# Multilang Client — JavaScript');\n      expect(out).toContain(\"import { Client } from 'multilang'\");\n    });\n\n    itCli('errors on multi-lang without --lang', () => {\n      const out = chub(['get', 'multilang/client'], { expectError: true });\n      expect(out).toContain('Multiple languages');\n      expect(out).toContain('--lang');\n    });\n\n    itCli('errors on nonexistent entry', () => {\n      const out = chub(['get', 'fake/thing'], { expectError: true });\n      expect(out).toContain('No doc or skill found');\n    });\n\n    itCli('fetches --full with all files', () => {\n      const out = chub(['get', 'acme/widgets', '--lang', 'js', '--full']);\n      expect(out).toContain('FILE: DOC.md');\n      expect(out).toContain('FILE: references/advanced.md');\n      expect(out).toContain('Batch Operations');\n    });\n\n    itCli('writes to file with -o', () => {\n      const tmpFile = join(BUILD_OUTPUT, '_test_output.md');\n      chub(['get', 'acme/widgets', '--lang', 'js', '-o', tmpFile]);\n      expect(existsSync(tmpFile)).toBe(true);\n      const content = readFileSync(tmpFile, 'utf8');\n      expect(content).toContain('# Acme Widgets API');\n      rmSync(tmpFile, { force: true });\n    });\n\n    itCli('fetches skill content', () => {\n      const out = chub(['get', 'testskills/deploy']);\n      expect(out).toContain('# Deploy Skill');\n      expect(out).toContain('Automate deployments');\n    });\n\n    itCli('shows footer with additional files when they exist', () => {\n      const out = chub(['get', 'acme/widgets', '--lang', 'js']);\n      expect(out).toContain('Additional files available');\n      expect(out).toContain('references/advanced.md');\n      expect(out).toContain('--file');\n    });\n\n    itCli('no footer when entry has only one file', () => {\n      const out = chub(['get', 'multilang/client', '--lang', 'js']);\n      expect(out).not.toContain('Additional files available');\n    });\n\n    itCli('fetches specific file with --file', () => {\n      const out = chub(['get', 'acme/widgets', '--lang', 'js', '--file', 'references/advanced.md']);\n      expect(out).toContain('Batch Operations');\n      expect(out).not.toContain('# Acme Widgets API');\n    });\n\n    itCli('errors on nonexistent --file with available list', () => {\n      const out = chub(['get', 'acme/widgets', '--lang', 'js', '--file', 'nonexistent.md'], { expectError: true });\n      expect(out).toContain('not found in acme/widgets');\n      expect(out).toContain('references/advanced.md');\n    });\n\n    itCli('--json includes additionalFiles array', () => {\n      const data = chubJSON(['get', 'acme/widgets', '--lang', 'js']);\n      expect(data.additionalFiles).toContain('references/advanced.md');\n    });\n\n    itCli('--json omits additionalFiles when none exist', () => {\n      const data = chubJSON(['get', 'multilang/client', '--lang', 'js']);\n      expect(data.additionalFiles).toBeUndefined();\n    });\n\n    // Multi-version tests\n    itCli('build groups multi-version docs correctly', () => {\n      const reg = JSON.parse(readFileSync(join(BUILD_OUTPUT, 'registry.json'), 'utf8'));\n      const doc = reg.docs.find((d) => d.id === 'acme/versioned-api');\n      expect(doc).toBeDefined();\n      const jsLang = doc.languages.find((l) => l.language === 'javascript');\n      expect(jsLang.versions.length).toBe(2);\n      expect(jsLang.versions.map((v) => v.version)).toContain('2.0.0');\n      expect(jsLang.versions.map((v) => v.version)).toContain('1.0.0');\n      expect(jsLang.recommendedVersion).toBe('2.0.0');\n    });\n\n    itCli('fetches recommended (latest) version by default', () => {\n      const out = chub(['get', 'acme/versioned-api', '--lang', 'js']);\n      expect(out).toContain('Versioned API v2');\n      expect(out).toContain('version 2.0.0');\n    });\n\n    itCli('fetches specific version with --version', () => {\n      const out = chub(['get', 'acme/versioned-api', '--lang', 'js', '--version', '1.0.0']);\n      expect(out).toContain('Versioned API v1');\n      expect(out).toContain('version 1.0.0');\n    });\n\n    itCli('errors on nonexistent version with available list', () => {\n      const out = chub(['get', 'acme/versioned-api', '--lang', 'js', '--version', '99.0.0'], { expectError: true });\n      expect(out).toContain('Version \"99.0.0\" not found');\n      expect(out).toContain('2.0.0');\n      expect(out).toContain('1.0.0');\n    });\n  });\n\n  describe('annotate', () => {\n    itCli('saves and displays annotation on get', () => {\n      chub(['annotate', 'acme/widgets', 'Use batch mode for large datasets']);\n      const out = chub(['get', 'acme/widgets', '--lang', 'js']);\n      expect(out).toContain('Agent note');\n      expect(out).toContain('Use batch mode for large datasets');\n    });\n\n    itCli('replaces annotation on re-annotate', () => {\n      chub(['annotate', 'acme/widgets', 'Updated: use streaming instead']);\n      const out = chub(['get', 'acme/widgets', '--lang', 'js']);\n      expect(out).toContain('use streaming instead');\n      expect(out).not.toContain('batch mode');\n    });\n\n    itCli('shows annotation with chub annotate <id> (no note)', () => {\n      const out = chub(['annotate', 'acme/widgets']);\n      expect(out).toContain('use streaming instead');\n    });\n\n    itCli('clears annotation', () => {\n      chub(['annotate', 'acme/widgets', '--clear']);\n      const out = chub(['get', 'acme/widgets', '--lang', 'js']);\n      expect(out).not.toContain('Agent note');\n    });\n\n    itCli('no annotation section when none set', () => {\n      const out = chub(['get', 'multilang/client', '--lang', 'js']);\n      expect(out).not.toContain('Agent note');\n    });\n\n    itCli('--list shows all annotations', () => {\n      chub(['annotate', 'acme/widgets', 'Note A']);\n      chub(['annotate', 'multilang/client', 'Note B']);\n      const data = chubJSON(['annotate', '--list']);\n      expect(data.length).toBe(2);\n      const ids = data.map((a) => a.id);\n      expect(ids).toContain('acme/widgets');\n      expect(ids).toContain('multilang/client');\n      // Clean up\n      chub(['annotate', 'acme/widgets', '--clear']);\n      chub(['annotate', 'multilang/client', '--clear']);\n    });\n\n    itCli('--json includes annotation in get output', () => {\n      chub(['annotate', 'acme/widgets', 'JSON test note']);\n      const data = chubJSON(['get', 'acme/widgets', '--lang', 'js']);\n      expect(data.annotation).toBeDefined();\n      expect(data.annotation.note).toBe('JSON test note');\n      expect(data.annotation.id).toBe('acme/widgets');\n      // Clean up\n      chub(['annotate', 'acme/widgets', '--clear']);\n    });\n\n    itCli('--json omits annotation when none set', () => {\n      const data = chubJSON(['get', 'acme/widgets', '--lang', 'js']);\n      expect(data.annotation).toBeUndefined();\n    });\n  });\n\n  describe('json output', () => {\n    itCli('search --json returns valid JSON with total', () => {\n      const data = chubJSON(['search']);\n      expect(typeof data.total).toBe('number');\n      expect(Array.isArray(data.results)).toBe(true);\n    });\n\n    itCli('build --json returns valid JSON', () => {\n      const data = chubJSON(['build', FIXTURES, '--validate-only']);\n      expect(typeof data.docs).toBe('number');\n      expect(typeof data.skills).toBe('number');\n    });\n  });\n});\n"
  },
  {
    "path": "cli/test/fixtures/acme/docs/versioned-api/v1/DOC.md",
    "content": "---\nname: versioned-api\ndescription: \"A test API with multiple versions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2025-01-01\"\n  source: community\n  tags: \"test,versioned\"\n---\n# Versioned API v1\n\nThis is version 1.0.0 of the API documentation.\n\n## Usage\n\n```javascript\nconst client = new AcmeClient({ version: 'v1' });\n```\n"
  },
  {
    "path": "cli/test/fixtures/acme/docs/versioned-api/v2/DOC.md",
    "content": "---\nname: versioned-api\ndescription: \"A test API with multiple versions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2025-06-01\"\n  source: community\n  tags: \"test,versioned\"\n---\n# Versioned API v2\n\nThis is version 2.0.0 of the API documentation.\n\n## Usage\n\n```javascript\nconst client = new AcmeClient({ version: 'v2' });\n```\n"
  },
  {
    "path": "cli/test/fixtures/acme/docs/widgets/DOC.md",
    "content": "---\nname: widgets\ndescription: \"Acme widget API for creating and managing widgets\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  updated-on: \"2026-01-01\"\n  source: maintainer\n  tags: \"acme,widgets,api\"\n---\n\n# Acme Widgets API\n\nCreate and manage widgets with the Acme SDK.\n\n## Installation\n\n```bash\nnpm install @acme/widgets\n```\n\n## Quick Start\n\n```javascript\nimport { Acme } from '@acme/widgets';\nconst client = new Acme({ apiKey: process.env.ACME_KEY });\nconst widget = await client.widgets.create({ name: 'My Widget' });\n```\n\n## See Also\n\n- [Advanced usage](references/advanced.md)\n"
  },
  {
    "path": "cli/test/fixtures/acme/docs/widgets/references/advanced.md",
    "content": "# Advanced Widget Usage\n\n## Batch Operations\n\n```javascript\nconst widgets = await client.widgets.createMany([\n  { name: 'Widget A' },\n  { name: 'Widget B' },\n]);\n```\n\n## Error Handling\n\n```javascript\ntry {\n  await client.widgets.create({ name: '' });\n} catch (err) {\n  console.error(err.code, err.message);\n}\n```\n"
  },
  {
    "path": "cli/test/fixtures/multilang/docs/client/go/DOC.md",
    "content": "---\nname: client\ndescription: \"Multilang client SDK\"\nmetadata:\n  languages: \"go\"\n  versions: \"1.0.0\"\n  updated-on: \"2026-01-01\"\n  source: community\n  tags: \"multilang,client\"\n---\n\n# Multilang Client — Go\n\n```go\nimport \"multilang\"\n\nclient := multilang.NewClient(multilang.WithAPIKey(\"sk-test\"))\n```\n"
  },
  {
    "path": "cli/test/fixtures/multilang/docs/client/javascript/DOC.md",
    "content": "---\nname: client\ndescription: \"Multilang client SDK\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.0.0\"\n  updated-on: \"2026-01-01\"\n  source: community\n  tags: \"multilang,client\"\n---\n\n# Multilang Client — JavaScript\n\n```javascript\nimport { Client } from 'multilang';\nconst client = new Client({ apiKey: 'sk-test' });\n```\n"
  },
  {
    "path": "cli/test/fixtures/multilang/docs/client/python/DOC.md",
    "content": "---\nname: client\ndescription: \"Multilang client SDK\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  updated-on: \"2026-01-01\"\n  source: community\n  tags: \"multilang,client\"\n---\n\n# Multilang Client — Python\n\n```python\nfrom multilang import Client\nclient = Client(api_key=\"sk-test\")\n```\n"
  },
  {
    "path": "cli/test/fixtures/testskills/skills/deploy/SKILL.md",
    "content": "---\nname: deploy\ndescription: \"Deployment automation skill for CI/CD pipelines\"\nmetadata:\n  updated-on: \"2026-01-01\"\n  source: community\n  tags: \"deploy,ci,automation\"\n---\n\n# Deploy Skill\n\nAutomate deployments with this skill.\n\n## Steps\n\n1. Build the project\n2. Run tests\n3. Deploy to production\n"
  },
  {
    "path": "cli/test/lib/bm25.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { tokenize, buildIndex, search } from '../../src/lib/bm25.js';\n\ndescribe('bm25', () => {\n  describe('tokenize', () => {\n    it('lowercases and splits on whitespace', () => {\n      expect(tokenize('Hello World')).toEqual(['hello', 'world']);\n    });\n\n    it('removes stop words', () => {\n      expect(tokenize('the quick and brown fox')).toEqual(['quick', 'brown', 'fox']);\n    });\n\n    it('removes punctuation', () => {\n      expect(tokenize('hello, world! foo-bar')).toEqual(['hello', 'world', 'foo', 'bar']);\n    });\n\n    it('removes single-character tokens', () => {\n      expect(tokenize('a b cd ef')).toEqual(['cd', 'ef']);\n    });\n\n    it('returns empty array for empty/null input', () => {\n      expect(tokenize('')).toEqual([]);\n      expect(tokenize(null)).toEqual([]);\n      expect(tokenize(undefined)).toEqual([]);\n    });\n  });\n\n  describe('buildIndex', () => {\n    const entries = [\n      { id: 'stripe/api', name: 'api', description: 'Payment processing platform', tags: ['stripe', 'payments'] },\n      { id: 'openai/chat', name: 'chat', description: 'Chat completions API', tags: ['openai', 'ai', 'chat'] },\n      { id: 'redis/cache', name: 'cache', description: 'In-memory data store', tags: ['redis', 'cache', 'database'] },\n    ];\n\n    it('builds index with correct structure', () => {\n      const index = buildIndex(entries);\n      expect(index.version).toBe('1.0.0');\n      expect(index.algorithm).toBe('bm25');\n      expect(index.totalDocs).toBe(3);\n      expect(index.documents).toHaveLength(3);\n      expect(index.params).toEqual({ k1: 1.5, b: 0.75 });\n    });\n\n    it('tokenizes all fields', () => {\n      const index = buildIndex(entries);\n      const stripeDoc = index.documents.find((d) => d.id === 'stripe/api');\n      expect(stripeDoc.tokens.name).toEqual(['api']);\n      expect(stripeDoc.tokens.description).toContain('payment');\n      expect(stripeDoc.tokens.description).toContain('processing');\n      expect(stripeDoc.tokens.tags).toContain('stripe');\n      expect(stripeDoc.tokens.tags).toContain('payments');\n    });\n\n    it('computes IDF values', () => {\n      const index = buildIndex(entries);\n      expect(index.idf).toBeDefined();\n      // 'payment' appears in 1 of 3 docs — should have higher IDF than 'api' if it appeared in more\n      expect(index.idf['payment']).toBeGreaterThan(0);\n    });\n\n    it('computes average field lengths', () => {\n      const index = buildIndex(entries);\n      expect(index.avgFieldLengths.name).toBeGreaterThan(0);\n      expect(index.avgFieldLengths.description).toBeGreaterThan(0);\n      expect(index.avgFieldLengths.tags).toBeGreaterThan(0);\n    });\n\n    it('handles empty entries array', () => {\n      const index = buildIndex([]);\n      expect(index.totalDocs).toBe(0);\n      expect(index.documents).toHaveLength(0);\n    });\n  });\n\n  describe('search', () => {\n    const entries = [\n      { id: 'stripe/api', name: 'api', description: 'Payment processing platform with billing', tags: ['stripe', 'payments', 'billing'] },\n      { id: 'openai/chat', name: 'chat', description: 'Chat completions API for language models', tags: ['openai', 'ai', 'chat'] },\n      { id: 'redis/cache', name: 'cache', description: 'In-memory data store for caching', tags: ['redis', 'cache', 'database'] },\n      { id: 'square/payments', name: 'payments', description: 'Payment processing for commerce', tags: ['square', 'payments', 'commerce'] },\n    ];\n\n    const index = buildIndex(entries);\n\n    it('finds entries by keyword match', () => {\n      const results = search('payment', index);\n      expect(results.length).toBeGreaterThan(0);\n      const ids = results.map((r) => r.id);\n      expect(ids).toContain('stripe/api');\n      expect(ids).toContain('square/payments');\n    });\n\n    it('ranks exact name match higher', () => {\n      const results = search('payments', index);\n      // 'square/payments' has 'payments' as its name — should rank high\n      expect(results[0].id).toBe('square/payments');\n    });\n\n    it('finds by tag', () => {\n      const results = search('database', index);\n      expect(results.length).toBeGreaterThan(0);\n      expect(results[0].id).toBe('redis/cache');\n    });\n\n    it('finds by description terms', () => {\n      const results = search('language models', index);\n      expect(results.length).toBeGreaterThan(0);\n      expect(results[0].id).toBe('openai/chat');\n    });\n\n    it('returns empty for no match', () => {\n      const results = search('nonexistent thing', index);\n      expect(results).toHaveLength(0);\n    });\n\n    it('handles multi-word queries', () => {\n      const results = search('payment processing', index);\n      expect(results.length).toBeGreaterThan(0);\n      // Both stripe and square have 'payment processing' in description\n      const ids = results.map((r) => r.id);\n      expect(ids).toContain('stripe/api');\n      expect(ids).toContain('square/payments');\n    });\n\n    it('respects limit option', () => {\n      const results = search('payment', index, { limit: 1 });\n      expect(results).toHaveLength(1);\n    });\n\n    it('returns empty for stop-words-only query', () => {\n      const results = search('the and is', index);\n      expect(results).toHaveLength(0);\n    });\n  });\n\n  describe('search quality report', () => {\n    const entries = [\n      { id: 'stripe/api', name: 'api', description: 'Payment processing platform with billing and subscriptions', tags: ['stripe', 'payments', 'billing'] },\n      { id: 'square/payments', name: 'payments', description: 'Payment processing for commerce and point of sale', tags: ['square', 'payments', 'commerce'] },\n      { id: 'openai/chat', name: 'chat', description: 'Chat completions API for language models and AI assistants', tags: ['openai', 'ai', 'chat', 'llm'] },\n      { id: 'redis/cache', name: 'cache', description: 'In-memory data store for caching and session management', tags: ['redis', 'cache', 'database'] },\n      { id: 'mongodb/driver', name: 'driver', description: 'Document database driver for storing and querying JSON data', tags: ['mongodb', 'database', 'nosql'] },\n      { id: 'auth0/identity', name: 'identity', description: 'Authentication and authorization platform with SSO and MFA', tags: ['auth0', 'auth', 'identity', 'sso'] },\n      { id: 'clerk/auth', name: 'auth', description: 'User authentication with social login and session management', tags: ['clerk', 'auth', 'login'] },\n      { id: 'playwright/testing', name: 'testing', description: 'Browser automation for end-to-end testing of web applications', tags: ['playwright', 'testing', 'browser', 'automation'] },\n      { id: 'sentry/errors', name: 'errors', description: 'Error monitoring and performance tracking for production apps', tags: ['sentry', 'errors', 'monitoring'] },\n      { id: 'twilio/messaging', name: 'messaging', description: 'SMS and messaging API for sending notifications', tags: ['twilio', 'sms', 'messaging'] },\n    ];\n\n    const index = buildIndex(entries);\n\n    const queries = [\n      'payment processing',\n      'database',\n      'authentication login',\n      'browser testing',\n      'error monitoring',\n      'send SMS',\n      'AI language model',\n      'caching',\n      'subscriptions billing',\n      'JSON document store',\n    ];\n\n    it('generates visual search quality report', () => {\n      const lines = ['\\n  ┌─────────────────────────────────────────────────────────────────┐'];\n      lines.push('  │                    BM25 SEARCH QUALITY REPORT                  │');\n      lines.push('  └─────────────────────────────────────────────────────────────────┘\\n');\n\n      for (const query of queries) {\n        const results = search(query, index);\n        lines.push(`  Query: \"${query}\"`);\n        if (results.length === 0) {\n          lines.push('    (no results)');\n        } else {\n          for (const r of results.slice(0, 5)) {\n            const bar = '█'.repeat(Math.min(Math.round(r.score * 2), 30));\n            lines.push(`    ${r.score.toFixed(2).padStart(6)}  ${bar}  ${r.id}`);\n          }\n        }\n        lines.push('');\n      }\n\n      // Print to console so it's visible in test output\n      console.log(lines.join('\\n'));\n\n      // The test itself just verifies search runs without error\n      expect(true).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "cli/test/lib/frontmatter.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { parseFrontmatter } from '../../src/lib/frontmatter.js';\n\ndescribe('parseFrontmatter', () => {\n  it('parses valid YAML frontmatter', () => {\n    const content = `---\nname: test\ndescription: A test entry\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n---\n\n# Test Content\n\nBody text here.`;\n\n    const { attributes, body } = parseFrontmatter(content);\n    expect(attributes.name).toBe('test');\n    expect(attributes.description).toBe('A test entry');\n    expect(attributes.metadata.languages).toBe('python');\n    expect(attributes.metadata.versions).toBe('1.0.0');\n    expect(body).toContain('# Test Content');\n    expect(body).toContain('Body text here.');\n  });\n\n  it('returns empty attributes when no frontmatter', () => {\n    const content = '# Just a heading\\n\\nSome content.';\n    const { attributes, body } = parseFrontmatter(content);\n    expect(attributes).toEqual({});\n    expect(body).toBe(content);\n  });\n\n  it('handles frontmatter with no metadata field', () => {\n    const content = `---\nname: simple\ndescription: No metadata\n---\n\nContent.`;\n\n    const { attributes } = parseFrontmatter(content);\n    expect(attributes.name).toBe('simple');\n    expect(attributes.metadata).toBeUndefined();\n  });\n\n  it('handles empty frontmatter block', () => {\n    const content = `---\n---\n\nContent.`;\n\n    const { attributes, body } = parseFrontmatter(content);\n    expect(attributes).toEqual({});\n    expect(body).toContain('Content.');\n  });\n});\n"
  },
  {
    "path": "cli/test/lib/normalize.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { normalizeLanguage, displayLanguage } from '../../src/lib/normalize.js';\n\ndescribe('normalizeLanguage', () => {\n  it('normalizes short aliases to full names', () => {\n    expect(normalizeLanguage('py')).toBe('python');\n    expect(normalizeLanguage('js')).toBe('javascript');\n    expect(normalizeLanguage('ts')).toBe('typescript');\n    expect(normalizeLanguage('rb')).toBe('ruby');\n    expect(normalizeLanguage('cs')).toBe('csharp');\n  });\n\n  it('passes through full language names', () => {\n    expect(normalizeLanguage('python')).toBe('python');\n    expect(normalizeLanguage('javascript')).toBe('javascript');\n    expect(normalizeLanguage('typescript')).toBe('typescript');\n  });\n\n  it('is case-insensitive', () => {\n    expect(normalizeLanguage('PY')).toBe('python');\n    expect(normalizeLanguage('JS')).toBe('javascript');\n    expect(normalizeLanguage('Python')).toBe('python');\n  });\n\n  it('returns null for null/undefined', () => {\n    expect(normalizeLanguage(null)).toBeNull();\n    expect(normalizeLanguage(undefined)).toBeNull();\n  });\n\n  it('passes through unknown languages as lowercase', () => {\n    expect(normalizeLanguage('rust')).toBe('rust');\n    expect(normalizeLanguage('Go')).toBe('go');\n  });\n});\n\ndescribe('displayLanguage', () => {\n  it('converts full names to short display forms', () => {\n    expect(displayLanguage('javascript')).toBe('js');\n    expect(displayLanguage('typescript')).toBe('ts');\n    expect(displayLanguage('python')).toBe('py');\n  });\n\n  it('passes through unknown languages', () => {\n    expect(displayLanguage('rust')).toBe('rust');\n    expect(displayLanguage('go')).toBe('go');\n  });\n});\n"
  },
  {
    "path": "cli/tests/commands/build.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { execFileSync } from 'node:child_process';\nimport { mkdtempSync, readFileSync, rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CLI_BIN = join(import.meta.dirname, '..', '..', 'bin', 'chub');\nconst FIXTURES = join(import.meta.dirname, '..', '..', 'test', 'fixtures');\nconst BUILD_TEST_TIMEOUT = 15000;\nconst itBuild = (name, fn) => it(name, { timeout: BUILD_TEST_TIMEOUT }, fn);\nconst TEST_ENV = { ...process.env, CHUB_TELEMETRY: '0', CHUB_FEEDBACK: '0' };\n\ndescribe('chub build', () => {\n  itBuild('validates test fixtures and finds docs and skills', () => {\n    const result = execFileSync(\n      process.execPath,\n      [CLI_BIN, 'build', FIXTURES, '--validate-only', '--json'],\n      { encoding: 'utf8', env: TEST_ENV },\n    );\n\n    const parsed = JSON.parse(result.trim());\n    expect(parsed).toHaveProperty('docs');\n    expect(parsed).toHaveProperty('skills');\n    expect(parsed).toHaveProperty('warnings');\n    expect(parsed.docs).toBeGreaterThanOrEqual(1);\n    expect(parsed.skills).toBeGreaterThanOrEqual(1);\n  });\n\n  itBuild('finds expected docs and skills in fixtures', () => {\n    const result = execFileSync(\n      process.execPath,\n      [CLI_BIN, 'build', FIXTURES, '--validate-only', '--json'],\n      { encoding: 'utf8', env: TEST_ENV },\n    );\n\n    const parsed = JSON.parse(result.trim());\n    // test/fixtures has 3 docs (acme/widgets, acme/versioned-api, multilang/client) and 1 skill (testskills/deploy)\n    expect(parsed.docs).toBe(3);\n    expect(parsed.skills).toBe(1);\n  });\n\n  itBuild('writes a search index with an inverted index', () => {\n    const outputDir = mkdtempSync(join(tmpdir(), 'chub-build-'));\n\n    try {\n      execFileSync(\n        process.execPath,\n        [CLI_BIN, 'build', FIXTURES, '--json', '-o', outputDir],\n        { encoding: 'utf8', env: TEST_ENV },\n      );\n\n      const searchIndex = JSON.parse(readFileSync(join(outputDir, 'search-index.json'), 'utf8'));\n      expect(searchIndex).toHaveProperty('invertedIndex');\n      expect(searchIndex.invertedIndex).toHaveProperty('widget');\n    } finally {\n      rmSync(outputDir, { recursive: true, force: true });\n    }\n  });\n\n  itBuild('exits with error for nonexistent directory', () => {\n    let threw = false;\n    try {\n      execFileSync(\n        process.execPath,\n        [CLI_BIN, 'build', '/tmp/nonexistent-dir-xyz-12345', '--validate-only', '--json'],\n        { encoding: 'utf8', stdio: 'pipe', env: TEST_ENV },\n      );\n    } catch (err) {\n      threw = true;\n      expect(err.status).not.toBe(0);\n      expect(err.stderr.toString()).toContain('not found');\n    }\n    expect(threw).toBe(true);\n  });\n});\n"
  },
  {
    "path": "cli/tests/commands/get.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\n\n// Mock analytics module — must be before any import that uses it\nconst trackCalls = [];\nvi.mock('../../src/lib/analytics.js', () => ({\n  trackEvent: vi.fn(async (event, props) => { trackCalls.push([event, props]); }),\n  setCliVersion: vi.fn(),\n  shutdownAnalytics: vi.fn(async () => {}),\n}));\n\n// Mock cache.fetchDoc so we can simulate network errors\nconst mockFetchDoc = vi.fn();\nconst mockFetchDocFull = vi.fn();\nvi.mock('../../src/lib/cache.js', async (importOriginal) => {\n  const actual = await importOriginal();\n  return {\n    ...actual,\n    fetchDoc: (...args) => mockFetchDoc.getMockImplementation() ? mockFetchDoc(...args) : actual.fetchDoc(...args),\n    fetchDocFull: (...args) => mockFetchDocFull.getMockImplementation() ? mockFetchDocFull(...args) : actual.fetchDocFull(...args),\n  };\n});\n\nimport { handleGet, handleSearch } from '../../src/mcp/tools.js';\n\nfunction parseResult(result) {\n  return JSON.parse(result.content[0].text);\n}\n\ndescribe('get command telemetry', () => {\n  beforeEach(() => {\n    trackCalls.length = 0;\n  });\n\n  it('emits doc_not_found with entry_id when entry does not exist', async () => {\n    await handleGet({ id: 'nonexistent/entry-xyz-999' });\n\n    const call = trackCalls.find(([event]) => event === 'doc_not_found');\n    expect(call).toBeDefined();\n    expect(call[1].entry_id).toBe('nonexistent/entry-xyz-999');\n    expect(call[1]).toHaveProperty('via', 'mcp');\n    expect(call[1]).not.toHaveProperty('error_message');\n  });\n\n  it('emits doc_fetched with duration_ms on successful fetch', async () => {\n    const searchResult = await handleSearch({ limit: 1 });\n    const data = parseResult(searchResult);\n    if (data.results.length === 0) return;\n\n    const entry = data.results[0];\n    const lang = entry.languages?.[0];\n    trackCalls.length = 0;\n    await handleGet({ id: entry.id, lang });\n\n    const fetchCall = trackCalls.find(\n      ([event]) => event === 'doc_fetched' || event === 'skill_fetched'\n    );\n    if (fetchCall) {\n      const props = fetchCall[1];\n      expect(props).toHaveProperty('entry_id');\n      expect(props).toHaveProperty('duration_ms');\n      expect(typeof props.duration_ms).toBe('number');\n      expect(props.duration_ms).toBeGreaterThanOrEqual(0);\n      expect(props).toHaveProperty('via', 'mcp');\n      expect(props).not.toHaveProperty('error_message');\n    }\n  });\n\n  it('duration_ms is reasonable per entry', async () => {\n    const searchResult = await handleSearch({ limit: 2 });\n    const data = parseResult(searchResult);\n    if (data.results.length < 1) return;\n\n    for (const entry of data.results) {\n      trackCalls.length = 0;\n      const lang = entry.languages?.[0];\n      await handleGet({ id: entry.id, lang });\n\n      const fetchCall = trackCalls.find(\n        ([event]) => event === 'doc_fetched' || event === 'skill_fetched'\n      );\n      if (fetchCall) {\n        expect(fetchCall[1].duration_ms).toBeGreaterThanOrEqual(0);\n        expect(fetchCall[1].duration_ms).toBeLessThan(10000);\n      }\n    }\n  });\n\n  it('never sends error_message in any telemetry event', async () => {\n    await handleSearch({ query: 'test' });\n    await handleGet({ id: 'nonexistent/entry-999' });\n\n    for (const [, props] of trackCalls) {\n      expect(props).not.toHaveProperty('error_message');\n    }\n  });\n\n  it('fetch_error contains error_type but not error_message', async () => {\n    // Make fetchDoc throw to hit the catch path that emits fetch_error\n    mockFetchDoc.mockImplementation(async () => {\n      const e = new Error('connect ECONNREFUSED');\n      e.code = 'ECONNREFUSED';\n      throw e;\n    });\n\n    try {\n      const searchResult = await handleSearch({ limit: 1 });\n      const data = parseResult(searchResult);\n      if (data.results.length === 0) return;\n\n      const entry = data.results[0];\n      const lang = entry.languages?.[0];\n      trackCalls.length = 0;\n      await handleGet({ id: entry.id, lang });\n\n      const errorCall = trackCalls.find(([event]) => event === 'fetch_error');\n      expect(errorCall).toBeDefined();\n      expect(errorCall[1]).toHaveProperty('error_type', 'ECONNREFUSED');\n      expect(errorCall[1]).toHaveProperty('via', 'mcp');\n      expect(errorCall[1]).not.toHaveProperty('error_message');\n    } finally {\n      mockFetchDoc.mockReset();\n    }\n  });\n});\n"
  },
  {
    "path": "cli/tests/commands/go-lang.test.js",
    "content": "/**\n * Tests for `--lang go` support in context-hub.\n *\n * Covers:\n *  1. content/openai/docs/chat/go/DOC.md — frontmatter correctness\n *  2. resolveDocPath() — correctly resolves a Go language entry\n *  3. resolveDocPath() — returns error for unknown language\n *  4. chub build — validates the Go fixture via CLI\n *  5. chub build --validate-only --json — Go fixture counts as a doc language variant\n */\n\nimport { describe, it, expect } from 'vitest';\nimport { readFileSync, mkdtempSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport { parseFrontmatter } from '../../src/lib/frontmatter.js';\nimport { resolveDocPath } from '../../src/lib/registry.js';\n\nconst REPO_ROOT = join(import.meta.dirname, '..', '..', '..');\nconst CLI_BIN = join(import.meta.dirname, '..', '..', 'bin', 'chub');\nconst FIXTURES = join(import.meta.dirname, '..', '..', 'test', 'fixtures');\nconst GO_DOC_PATH = join(REPO_ROOT, 'content', 'openai', 'docs', 'chat', 'go', 'DOC.md');\nconst GO_FIXTURE_PATH = join(FIXTURES, 'multilang', 'docs', 'client', 'go', 'DOC.md');\nconst BUILD_TEST_TIMEOUT = 15000;\nconst itBuild = (name, fn) => it(name, { timeout: BUILD_TEST_TIMEOUT }, fn);\nconst TEST_ENV = { ...process.env, CHUB_TELEMETRY: '0', CHUB_FEEDBACK: '0' };\n\n// ---------------------------------------------------------------------------\n// 1. Content file — frontmatter validation\n// ---------------------------------------------------------------------------\ndescribe('content/openai/docs/chat/go/DOC.md — frontmatter', () => {\n  it('file exists and is readable', () => {\n    const raw = readFileSync(GO_DOC_PATH, 'utf8');\n    expect(raw.length).toBeGreaterThan(100);\n  });\n\n  it('has required name field equal to \"chat\"', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(attributes.name).toBe('chat');\n  });\n\n  it('has required description field', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(typeof attributes.description).toBe('string');\n    expect(attributes.description.length).toBeGreaterThan(10);\n  });\n\n  it('declares language as \"go\"', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(attributes.metadata.languages).toBe('go');\n  });\n\n  it('has a versions field (SDK version string)', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(typeof attributes.metadata.versions).toBe('string');\n    expect(attributes.metadata.versions.length).toBeGreaterThan(0);\n  });\n\n  it('has an updated-on date in YYYY-MM-DD format', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(attributes.metadata['updated-on']).toMatch(/^\\d{4}-\\d{2}-\\d{2}$/);\n  });\n\n  it('has a valid source value', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    const validSources = ['official', 'maintainer', 'community'];\n    expect(validSources).toContain(attributes.metadata.source);\n  });\n\n  it('has tags including \"go\" or \"openai\"', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    const tags = attributes.metadata.tags || '';\n    expect(tags).toMatch(/openai|go/);\n  });\n\n  it('body contains openai.F() — the critical Go SDK pattern', () => {\n    const { body } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(body).toContain('openai.F(');\n  });\n\n  it('body contains go import statement', () => {\n    const { body } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(body).toContain('github.com/openai/openai-go');\n  });\n\n  it('body contains a code block', () => {\n    const { body } = parseFrontmatter(readFileSync(GO_DOC_PATH, 'utf8'));\n    expect(body).toContain('```go');\n  });\n});\n\n// ---------------------------------------------------------------------------\n// 2. Go fixture — frontmatter validation\n// ---------------------------------------------------------------------------\ndescribe('test fixture: multilang/docs/client/go/DOC.md', () => {\n  it('fixture file exists', () => {\n    const raw = readFileSync(GO_FIXTURE_PATH, 'utf8');\n    expect(raw.length).toBeGreaterThan(0);\n  });\n\n  it('fixture name matches sibling variants (must be \"client\")', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_FIXTURE_PATH, 'utf8'));\n    expect(attributes.name).toBe('client');\n  });\n\n  it('fixture declares language \"go\"', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_FIXTURE_PATH, 'utf8'));\n    expect(attributes.metadata.languages).toBe('go');\n  });\n\n  it('fixture has same description as python/js variants', () => {\n    const { attributes } = parseFrontmatter(readFileSync(GO_FIXTURE_PATH, 'utf8'));\n    expect(attributes.description).toBe('Multilang client SDK');\n  });\n});\n\n// ---------------------------------------------------------------------------\n// 3. resolveDocPath() — Go language resolution logic\n// ---------------------------------------------------------------------------\ndescribe('resolveDocPath() — Go language support', () => {\n  const makeEntry = (languages) => ({\n    name: 'chat',\n    languages,\n    _sourceObj: { name: 'default', url: 'https://cdn.example.com/v1' },\n  });\n\n  it('resolves \"go\" language variant when present', () => {\n    const entry = makeEntry([\n      { language: 'python', versions: [{ version: '2.0', path: 'openai/chat/python', files: ['DOC.md'] }], recommendedVersion: '2.0' },\n      { language: 'javascript', versions: [{ version: '6.0', path: 'openai/chat/javascript', files: ['DOC.md'] }], recommendedVersion: '6.0' },\n      { language: 'go', versions: [{ version: '1.3.0', path: 'openai/chat/go', files: ['DOC.md'] }], recommendedVersion: '1.3.0' },\n    ]);\n\n    const result = resolveDocPath(entry, 'go', null);\n    expect(result).not.toBeNull();\n    expect(result.path).toBe('openai/chat/go');\n    expect(result.files).toContain('DOC.md');\n  });\n\n  it('returns needsLanguage when lang is null and multiple languages exist including go', () => {\n    const entry = makeEntry([\n      { language: 'python', versions: [{ version: '2.0', path: 'p/python', files: ['DOC.md'] }], recommendedVersion: '2.0' },\n      { language: 'go', versions: [{ version: '1.3.0', path: 'p/go', files: ['DOC.md'] }], recommendedVersion: '1.3.0' },\n    ]);\n\n    const result = resolveDocPath(entry, null, null);\n    expect(result).not.toBeNull();\n    expect(result.needsLanguage).toBe(true);\n    expect(result.available).toContain('go');\n    expect(result.available).toContain('python');\n  });\n\n  it('returns error-like result when \"go\" is requested but not available', () => {\n    const entry = makeEntry([\n      { language: 'python', versions: [{ version: '2.0', path: 'p/python', files: ['DOC.md'] }], recommendedVersion: '2.0' },\n      { language: 'javascript', versions: [{ version: '6.0', path: 'p/js', files: ['DOC.md'] }], recommendedVersion: '6.0' },\n    ]);\n\n    const result = resolveDocPath(entry, 'go', null);\n    // Should return null or a languageNotFound indicator — not a valid path\n    if (result !== null) {\n      expect(result.path).toBeUndefined();\n    } else {\n      expect(result).toBeNull();\n    }\n  });\n\n  it('resolves \"go\" at a specific version', () => {\n    const entry = makeEntry([\n      {\n        language: 'go',\n        versions: [\n          { version: '1.3.0', path: 'openai/chat/go', files: ['DOC.md'] },\n          { version: '1.0.0', path: 'openai/chat/go-v1', files: ['DOC.md'] },\n        ],\n        recommendedVersion: '1.3.0',\n      },\n    ]);\n\n    const result = resolveDocPath(entry, 'go', '1.0.0');\n    expect(result).not.toBeNull();\n    expect(result.path).toBe('openai/chat/go-v1');\n  });\n\n  it('resolves recommended version when lang=go and version=null', () => {\n    const entry = makeEntry([\n      {\n        language: 'go',\n        versions: [\n          { version: '1.3.0', path: 'openai/chat/go', files: ['DOC.md'] },\n          { version: '1.0.0', path: 'openai/chat/go-v1', files: ['DOC.md'] },\n        ],\n        recommendedVersion: '1.3.0',\n      },\n    ]);\n\n    const result = resolveDocPath(entry, 'go', null);\n    expect(result).not.toBeNull();\n    expect(result.path).toBe('openai/chat/go');\n  });\n});\n\n// ---------------------------------------------------------------------------\n// 4. CLI integration — build validates Go fixture without errors\n// ---------------------------------------------------------------------------\ndescribe('chub build — Go fixture integration', () => {\n  itBuild('validates the multilang fixture (including Go variant) without errors', () => {\n    const result = execFileSync(\n      process.execPath,\n      [CLI_BIN, 'build', FIXTURES, '--validate-only', '--json'],\n      { encoding: 'utf8', env: TEST_ENV },\n    );\n\n    const parsed = JSON.parse(result.trim());\n    expect(parsed.warnings).toBe(0);\n    expect(parsed.docs).toBeGreaterThanOrEqual(1);\n  });\n\n  itBuild('doc count includes Go as part of the multilang entry (not a new doc)', () => {\n    // The multilang/client entry now has 3 language variants: python, javascript, go.\n    // It should still count as 1 doc entry (language variants share the same name).\n    const result = execFileSync(\n      process.execPath,\n      [CLI_BIN, 'build', FIXTURES, '--validate-only', '--json'],\n      { encoding: 'utf8', env: TEST_ENV },\n    );\n\n    const parsed = JSON.parse(result.trim());\n    // 3 doc entries: acme/widgets, acme/versioned-api, multilang/client (with py+js+go)\n    expect(parsed.docs).toBe(3);\n  });\n\n  itBuild('exits cleanly (exit code 0) with Go fixture present', () => {\n    let threw = false;\n    try {\n      execFileSync(\n        process.execPath,\n        [CLI_BIN, 'build', FIXTURES, '--validate-only'],\n        { encoding: 'utf8', stdio: 'pipe', env: TEST_ENV },\n      );\n    } catch {\n      threw = true;\n    }\n    expect(threw).toBe(false);\n  });\n});\n\n// ---------------------------------------------------------------------------\n// 5. Build → registry round-trip: go appears in built registry.json\n// ---------------------------------------------------------------------------\ndescribe('chub build — Go appears in built registry.json', () => {\n  itBuild('go language is present in registry after building content/', () => {\n    const tmpDir = mkdtempSync(join(tmpdir(), 'chub-go-test-'));\n\n    execFileSync(\n      process.execPath,\n      [CLI_BIN, 'build', join(REPO_ROOT, 'content'), '-o', tmpDir],\n      { encoding: 'utf8', env: TEST_ENV },\n    );\n\n    const registry = JSON.parse(readFileSync(join(tmpDir, 'registry.json'), 'utf8'));\n    const chat = registry.docs.find((d) => d.id === 'openai/chat');\n    expect(chat).toBeDefined();\n    const langs = chat.languages.map((l) => l.language);\n    expect(langs).toContain('go');\n  });\n});\n"
  },
  {
    "path": "cli/tests/commands/search.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\nimport { Command } from 'commander';\n\n// Mock all dependencies before importing the module under test\nvi.mock('../../src/lib/registry.js', () => ({\n  searchEntries: vi.fn(() => []),\n  listEntries: vi.fn(() => []),\n  getEntry: vi.fn(() => ({})),\n  getDisplayId: vi.fn((e) => e.id || e.name),\n  isMultiSource: vi.fn(() => false),\n}));\nvi.mock('../../src/lib/normalize.js', () => ({\n  displayLanguage: vi.fn((l) => l),\n}));\nvi.mock('../../src/lib/output.js', () => ({\n  output: vi.fn((data, formatter, opts) => {\n    if (opts?.json) {\n      console.log(JSON.stringify(data));\n    } else {\n      formatter(data);\n    }\n  }),\n}));\nvi.mock('../../src/lib/analytics.js', () => ({\n  trackEvent: vi.fn(() => Promise.resolve()),\n}));\n\nconst { searchEntries, listEntries, getEntry, getDisplayId, isMultiSource } = await import('../../src/lib/registry.js');\nconst { trackEvent } = await import('../../src/lib/analytics.js');\nconst { output } = await import('../../src/lib/output.js');\nconst { registerSearchCommand } = await import('../../src/commands/search.js');\n\n// Helper to invoke the command via Commander\nasync function runSearch(args = [], globalArgs = []) {\n  const program = new Command();\n  program.exitOverride();\n  program.option('--json', 'JSON output');\n  registerSearchCommand(program);\n  await program.parseAsync(['node', 'test', ...globalArgs, 'search', ...args]);\n}\n\n// Sample entries for reuse\nconst docEntry = {\n  id: 'acme/widgets',\n  name: 'Widgets',\n  _type: 'doc',\n  _source: 'acme',\n  description: 'Widget management library',\n  tags: ['ui', 'components'],\n  languages: [\n    {\n      language: 'javascript',\n      recommendedVersion: '2.0',\n      versions: [{ version: '2.0', size: 10240, lastUpdated: '2025-01-01' }],\n    },\n  ],\n};\n\nconst skillEntry = {\n  id: 'testskills/deploy',\n  name: 'Deploy',\n  _type: 'skill',\n  _source: 'testskills',\n  description: 'Deployment automation skill',\n  tags: ['devops'],\n  path: 'skills/deploy',\n  size: 2048,\n  lastUpdated: '2025-06-01',\n  files: ['deploy.sh', 'config.yml'],\n};\n\nconst longDescEntry = {\n  id: 'verbose/thing',\n  name: 'Verbose',\n  _type: 'doc',\n  _source: 'verbose',\n  description: 'This is an extremely long description that definitely exceeds the sixty character truncation limit for list display',\n  languages: [],\n};\n\ndescribe('search command', () => {\n  let logSpy;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});\n  });\n\n  afterEach(() => {\n    logSpy.mockRestore();\n  });\n\n  // ── Path 1: No query (list all) ──────────────────────────────\n\n  describe('no query — list all', () => {\n    it('calls listEntries with parsed filter options', async () => {\n      listEntries.mockReturnValue([]);\n      await runSearch(['--tags', 'ui', '--lang', 'js']);\n      expect(listEntries).toHaveBeenCalledWith(\n        expect.objectContaining({ tags: 'ui', lang: 'js' }),\n      );\n    });\n\n    it('prints \"No entries found.\" when list is empty', async () => {\n      listEntries.mockReturnValue([]);\n      await runSearch([]);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('No entries found.'));\n    });\n\n    it('prints entry count and formatted list when entries exist', async () => {\n      listEntries.mockReturnValue([docEntry, skillEntry]);\n      await runSearch([]);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('2 entries:'));\n    });\n\n    it('respects --limit option to slice results', async () => {\n      listEntries.mockReturnValue([docEntry, skillEntry, longDescEntry]);\n      await runSearch(['--limit', '1']);\n      // output() should receive only 1 entry\n      expect(output).toHaveBeenCalledWith(\n        expect.objectContaining({ total: 1 }),\n        expect.any(Function),\n        expect.anything(),\n      );\n    });\n\n    it('defaults limit to 20', async () => {\n      const manyEntries = Array.from({ length: 25 }, (_, i) => ({\n        ...docEntry,\n        id: `entry-${i}`,\n      }));\n      listEntries.mockReturnValue(manyEntries);\n      await runSearch([]);\n      expect(output).toHaveBeenCalledWith(\n        expect.objectContaining({ total: 20 }),\n        expect.any(Function),\n        expect.anything(),\n      );\n    });\n\n    it('passes json: true through output() in JSON mode', async () => {\n      listEntries.mockReturnValue([docEntry]);\n      await runSearch([], ['--json']);\n      expect(output).toHaveBeenCalledWith(\n        expect.anything(),\n        expect.any(Function),\n        expect.objectContaining({ json: true }),\n      );\n    });\n  });\n\n  // ── Path 2: Exact ID match ───────────────────────────────────\n\n  describe('exact ID match', () => {\n    it('shows detail view for single match', async () => {\n      getEntry.mockReturnValue({ entry: docEntry });\n      await runSearch(['acme/widgets']);\n      expect(output).toHaveBeenCalledWith(\n        docEntry,\n        expect.any(Function),\n        expect.anything(),\n      );\n    });\n\n    it('prints entry name, description, tags in detail view', async () => {\n      getEntry.mockReturnValue({ entry: docEntry });\n      await runSearch(['acme/widgets']);\n      // The formatter passed to output will be called — verify console output\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Widgets'));\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('ui, components'));\n    });\n\n    it('prints alternatives for ambiguous match', async () => {\n      getEntry.mockReturnValue({\n        ambiguous: true,\n        alternatives: ['src1/widgets', 'src2/widgets'],\n      });\n      await runSearch(['widgets']);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('src1/widgets'));\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('src2/widgets'));\n    });\n\n    it('does NOT fall through to fuzzy search on exact match', async () => {\n      getEntry.mockReturnValue({ entry: docEntry });\n      await runSearch(['acme/widgets']);\n      expect(searchEntries).not.toHaveBeenCalled();\n    });\n\n    it('does NOT fall through to fuzzy search on ambiguous match', async () => {\n      getEntry.mockReturnValue({\n        ambiguous: true,\n        alternatives: ['a', 'b'],\n      });\n      await runSearch(['widgets']);\n      expect(searchEntries).not.toHaveBeenCalled();\n    });\n  });\n\n  // ── Path 3: Fuzzy search ─────────────────────────────────────\n\n  describe('fuzzy search', () => {\n    beforeEach(() => {\n      getEntry.mockReturnValue({});\n    });\n\n    it('calls searchEntries when getEntry returns no match', async () => {\n      searchEntries.mockReturnValue([docEntry]);\n      await runSearch(['widget']);\n      expect(searchEntries).toHaveBeenCalledWith('widget', expect.anything());\n    });\n\n    it('normalizes whitespace before lookup and search', async () => {\n      searchEntries.mockReturnValue([docEntry]);\n      await runSearch(['  widget   api  ']);\n      expect(getEntry).toHaveBeenCalledWith('widget api');\n      expect(searchEntries).toHaveBeenCalledWith('widget api', expect.anything());\n    });\n\n    it('fires analytics event with correct properties', async () => {\n      searchEntries.mockReturnValue([docEntry]);\n      await runSearch(['widget', '--tags', 'ui']);\n      expect(trackEvent).toHaveBeenCalledWith('search', expect.objectContaining({\n        query: 'widget',\n        query_length: 6,\n        result_count: 1,\n        has_tags: true,\n        has_lang: false,\n      }));\n    });\n\n    it('does not fail when trackEvent rejects', async () => {\n      searchEntries.mockReturnValue([docEntry]);\n      trackEvent.mockReturnValue(Promise.reject(new Error('network')));\n      // Should not throw\n      await runSearch(['widget']);\n      expect(trackEvent).toHaveBeenCalled();\n    });\n\n    it('prints \"No results for...\" when empty', async () => {\n      searchEntries.mockReturnValue([]);\n      await runSearch(['xyznonexist']);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('No results for'));\n    });\n\n    it('prints result count and query in header', async () => {\n      searchEntries.mockReturnValue([docEntry, skillEntry]);\n      await runSearch(['widget']);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('2 results for \"widget\"'));\n    });\n\n    it('respects --limit on fuzzy results', async () => {\n      searchEntries.mockReturnValue([docEntry, skillEntry, longDescEntry]);\n      await runSearch(['widget', '--limit', '2']);\n      expect(output).toHaveBeenCalledWith(\n        expect.objectContaining({ total: 2 }),\n        expect.any(Function),\n        expect.anything(),\n      );\n    });\n  });\n\n  // ── Formatting ───────────────────────────────────────────────\n\n  describe('formatEntryList', () => {\n    it('shows source label when isMultiSource() is true', async () => {\n      isMultiSource.mockReturnValue(true);\n      listEntries.mockReturnValue([docEntry]);\n      await runSearch([]);\n      // Source name should appear in output\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('acme'));\n    });\n\n    it('truncates descriptions longer than 60 chars', async () => {\n      listEntries.mockReturnValue([longDescEntry]);\n      await runSearch([]);\n      const descCall = logSpy.mock.calls.find((c) =>\n        typeof c[0] === 'string' && c[0].includes('...'),\n      );\n      expect(descCall).toBeTruthy();\n      // The truncated portion should be 57 chars + '...'\n      const descLine = descCall[0];\n      expect(descLine).toContain('...');\n      expect(descLine).not.toContain('truncation limit for list display');\n    });\n  });\n\n  describe('formatEntryDetail', () => {\n    it('prints language versions for doc entries', async () => {\n      getEntry.mockReturnValue({ entry: docEntry });\n      await runSearch(['acme/widgets']);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('javascript'));\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('2.0'));\n    });\n\n    it('prints path and files for skill entries', async () => {\n      getEntry.mockReturnValue({ entry: skillEntry });\n      await runSearch(['testskills/deploy']);\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('skills/deploy'));\n      expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('deploy.sh, config.yml'));\n    });\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/analytics.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\nimport { mkdtempSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\ndescribe('analytics', () => {\n  beforeEach(() => {\n    vi.resetModules();\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n    delete process.env.CHUB_TELEMETRY;\n  });\n\n  it('trackEvent does not throw when posthog-node is missing', async () => {\n    // posthog-node won't be installed in test env — should silently skip\n    const { trackEvent } = await import('../../src/lib/analytics.js');\n    await expect(trackEvent('test_event', { foo: 'bar' })).resolves.not.toThrow();\n  });\n\n  it('trackEvent does nothing when telemetry is disabled', async () => {\n    process.env.CHUB_TELEMETRY = '0';\n    const { trackEvent } = await import('../../src/lib/analytics.js');\n    await expect(trackEvent('test_event', {})).resolves.not.toThrow();\n  });\n\n  it('shutdownAnalytics does not throw when not initialized', async () => {\n    const { shutdownAnalytics } = await import('../../src/lib/analytics.js');\n    await expect(shutdownAnalytics()).resolves.not.toThrow();\n  });\n\n  it('setCliVersion makes cli_version available', async () => {\n    const { setCliVersion } = await import('../../src/lib/analytics.js');\n    // Should not throw\n    setCliVersion('1.2.3');\n  });\n\n  it('trackEvent includes global properties when posthog is available', async () => {\n    // Mock posthog-node to capture what gets sent\n    const capturedEvents = [];\n    vi.doMock('posthog-node', () => ({\n      PostHog: class {\n        constructor() {}\n        capture(event) { capturedEvents.push(event); }\n        async flush() {}\n        async shutdown() {}\n      },\n    }));\n\n    const { trackEvent, setCliVersion } = await import('../../src/lib/analytics.js');\n    setCliVersion('0.1.2');\n    await trackEvent('test_event', { entry_id: 'openai/chat' });\n\n    expect(capturedEvents.length).toBe(1);\n    const props = capturedEvents[0].properties;\n    expect(props).toHaveProperty('platform');\n    expect(props).toHaveProperty('node_version');\n    expect(props).toHaveProperty('cli_version', '0.1.2');\n    expect(props).toHaveProperty('entry_id', 'openai/chat');\n  });\n\n  it('trackEvent does not include error_message in properties', async () => {\n    const capturedEvents = [];\n    vi.doMock('posthog-node', () => ({\n      PostHog: class {\n        constructor() {}\n        capture(event) { capturedEvents.push(event); }\n        async flush() {}\n        async shutdown() {}\n      },\n    }));\n\n    const { trackEvent } = await import('../../src/lib/analytics.js');\n    await trackEvent('fetch_error', { entry_id: 'stripe/api', error_type: 'ECONNREFUSED' });\n\n    expect(capturedEvents.length).toBe(1);\n    const props = capturedEvents[0].properties;\n    expect(props).toHaveProperty('error_type', 'ECONNREFUSED');\n    expect(props).not.toHaveProperty('error_message');\n  });\n});\n\ndescribe('identity', () => {\n  let tempDir;\n  let origChubDir;\n\n  beforeEach(() => {\n    vi.resetModules();\n    // Isolate from real ~/.chub — use a temp directory\n    tempDir = mkdtempSync(join(tmpdir(), 'chub-test-'));\n    origChubDir = process.env.CHUB_DIR;\n    process.env.CHUB_DIR = tempDir;\n  });\n\n  afterEach(() => {\n    if (origChubDir !== undefined) {\n      process.env.CHUB_DIR = origChubDir;\n    } else {\n      delete process.env.CHUB_DIR;\n    }\n    try { rmSync(tempDir, { recursive: true }); } catch {}\n  });\n\n  it('isFirstRun returns false before getOrCreateClientId', async () => {\n    const { isFirstRun } = await import('../../src/lib/identity.js');\n    expect(isFirstRun()).toBe(false);\n  });\n\n  it('isFirstRun returns true on fresh directory', async () => {\n    const { getOrCreateClientId, isFirstRun } = await import('../../src/lib/identity.js');\n    await getOrCreateClientId();\n    // Fresh temp dir = no existing client_id = first run\n    expect(isFirstRun()).toBe(true);\n  });\n\n  it('isFirstRun returns false on second load with same dir', async () => {\n    // First call creates the client_id file\n    const mod1 = await import('../../src/lib/identity.js');\n    await mod1.getOrCreateClientId();\n    expect(mod1.isFirstRun()).toBe(true);\n\n    // Reset module to simulate a new process, same CHUB_DIR\n    vi.resetModules();\n    const mod2 = await import('../../src/lib/identity.js');\n    await mod2.getOrCreateClientId();\n    // File exists now, so not first run\n    expect(mod2.isFirstRun()).toBe(false);\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/bm25.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { buildIndex, searchWithStats } from '../../src/lib/bm25.js';\n\ndescribe('bm25 inverted index', () => {\n  it('stores postings lists for searchable terms', () => {\n    const index = buildIndex([\n      {\n        id: 'acme/widgets',\n        name: 'Widget API',\n        description: 'Create and list widgets',\n        tags: ['widgets', 'api'],\n      },\n      {\n        id: 'acme/deploy',\n        name: 'Deploy Skill',\n        description: 'Deploy widgets safely',\n        tags: ['deploy'],\n      },\n    ]);\n\n    expect(index.invertedIndex.widget).toEqual([0]);\n    expect(index.invertedIndex.widgets).toEqual([0, 1]);\n    expect(index.invertedIndex.deploy).toEqual([1]);\n    expect(index.invertedIndex.api).toEqual([0]);\n  });\n\n  it('returns the same search results while scoring fewer documents', () => {\n    const entries = Array.from({ length: 1000 }, (_, idx) => ({\n      id: `vendor/entry-${idx}`,\n      name: `Entry ${idx}`,\n      description: idx < 8 ? `Rare needle topic ${idx}` : `Common background topic ${idx}`,\n      tags: idx < 8 ? ['needle'] : ['background'],\n    }));\n\n    const optimizedIndex = buildIndex(entries);\n    const baselineIndex = { ...optimizedIndex };\n    delete baselineIndex.invertedIndex;\n\n    const optimized = searchWithStats('needle', optimizedIndex);\n    const baseline = searchWithStats('needle', baselineIndex);\n\n    expect(optimized.results).toEqual(baseline.results);\n    expect(optimized.stats.usedInvertedIndex).toBe(true);\n    expect(baseline.stats.usedInvertedIndex).toBe(false);\n    expect(optimized.stats.candidateDocCount).toBe(8);\n    expect(baseline.stats.candidateDocCount).toBe(1000);\n    expect(optimized.stats.scoredDocCount).toBeLessThan(baseline.stats.scoredDocCount);\n  });\n\n  it('skips scoring entirely when no postings match the query', () => {\n    const index = buildIndex([\n      {\n        id: 'vendor/alpha',\n        name: 'Alpha',\n        description: 'Alpha topic',\n        tags: ['alpha'],\n      },\n      {\n        id: 'vendor/beta',\n        name: 'Beta',\n        description: 'Beta topic',\n        tags: ['beta'],\n      },\n    ]);\n\n    const result = searchWithStats('gamma', index);\n\n    expect(result.results).toEqual([]);\n    expect(result.stats.candidateDocCount).toBe(0);\n    expect(result.stats.scoredDocCount).toBe(0);\n  });\n\n  it('indexes identifier variants so joined and split package queries still match', () => {\n    const index = buildIndex([\n      {\n        id: 'node-fetch/node-fetch',\n        name: 'node-fetch',\n        description: 'Fetch API for Node.js',\n        tags: ['http'],\n      },\n      {\n        id: 'auth0/identity',\n        name: 'Auth0 Identity',\n        description: 'Identity toolkit',\n        tags: ['auth'],\n      },\n    ]);\n\n    expect(searchWithStats('nodefetch', index).results[0].id).toBe('node-fetch/node-fetch');\n    expect(searchWithStats('auth 0', index).results[0].id).toBe('auth0/identity');\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/cache.test.js",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\nimport { existsSync, mkdtempSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nconst BUNDLED_DIR = join(import.meta.dirname, '..', '..', 'dist');\n\nlet tempChubDir = null;\nlet backupDir = null;\n\nfunction restoreBundledDir() {\n  if (existsSync(BUNDLED_DIR)) {\n    rmSync(BUNDLED_DIR, { recursive: true, force: true });\n  }\n  if (backupDir) {\n    renameSync(backupDir, BUNDLED_DIR);\n    backupDir = null;\n  }\n}\n\nafterEach(() => {\n  vi.resetModules();\n  vi.unstubAllGlobals();\n  delete process.env.CHUB_DIR;\n  if (tempChubDir) {\n    rmSync(tempChubDir, { recursive: true, force: true });\n    tempChubDir = null;\n  }\n  restoreBundledDir();\n});\n\ndescribe('ensureRegistry', () => {\n  it('seeds bundled search-index.json alongside registry.json', async () => {\n    tempChubDir = mkdtempSync(join(tmpdir(), 'chub-cache-test-'));\n    process.env.CHUB_DIR = tempChubDir;\n\n    if (existsSync(BUNDLED_DIR)) {\n      backupDir = mkdtempSync(join(tmpdir(), 'chub-dist-backup-'));\n      rmSync(backupDir, { recursive: true, force: true });\n      renameSync(BUNDLED_DIR, backupDir);\n    }\n\n    mkdirSync(BUNDLED_DIR, { recursive: true });\n    writeFileSync(join(BUNDLED_DIR, 'registry.json'), JSON.stringify({\n      version: '1.0.0',\n      docs: [],\n      skills: [],\n    }));\n    writeFileSync(join(BUNDLED_DIR, 'search-index.json'), JSON.stringify({\n      version: '1.0.0',\n      algorithm: 'bm25',\n      params: { k1: 1.5, b: 0.75 },\n      totalDocs: 1,\n      avgFieldLengths: { name: 1, description: 1, tags: 1 },\n      idf: { alpha: 1 },\n      documents: [{ id: 'test/doc', tokens: { name: ['alpha'], description: [], tags: [] } }],\n      invertedIndex: { alpha: [0] },\n    }));\n\n    const { ensureRegistry } = await import('../../src/lib/cache.js');\n    await ensureRegistry();\n\n    const seededRegistry = join(tempChubDir, 'sources', 'default', 'registry.json');\n    const seededSearchIndex = join(tempChubDir, 'sources', 'default', 'search-index.json');\n    expect(existsSync(seededRegistry)).toBe(true);\n    expect(existsSync(seededSearchIndex)).toBe(true);\n\n    const seededIndex = JSON.parse(readFileSync(seededSearchIndex, 'utf8'));\n    expect(seededIndex.invertedIndex.alpha).toEqual([0]);\n  });\n\n  it('backfills a missing remote search-index.json even when registry.json is fresh', async () => {\n    tempChubDir = mkdtempSync(join(tmpdir(), 'chub-cache-test-'));\n    process.env.CHUB_DIR = tempChubDir;\n\n    mkdirSync(join(tempChubDir, 'sources', 'default'), { recursive: true });\n    writeFileSync(join(tempChubDir, 'config.yaml'), [\n      'sources:',\n      '  - name: default',\n      '    url: https://cdn.example.test/v1',\n      'refresh_interval: 21600',\n      '',\n    ].join('\\n'));\n\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'registry.json'), JSON.stringify({\n      version: '1.0.0',\n      docs: [],\n      skills: [],\n    }));\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), JSON.stringify({\n      lastUpdated: Date.now(),\n    }));\n\n    const fetchMock = vi.fn(async (url) => ({\n      ok: true,\n      status: 200,\n      statusText: 'OK',\n      text: async () => JSON.stringify(url.endsWith('registry.json')\n        ? { version: '1.0.0', docs: [{ id: 'vendor/pkg', name: 'Pkg' }], skills: [] }\n        : {\n            version: '1.0.0',\n            algorithm: 'bm25',\n            params: { k1: 1.5, b: 0.75 },\n            totalDocs: 1,\n            avgFieldLengths: { id: 1, name: 1, description: 0, tags: 0 },\n            idf: { pkg: 1 },\n            documents: [{ id: 'vendor/pkg', tokens: { id: ['vendorpkg'], name: ['pkg'], description: [], tags: [] } }],\n            invertedIndex: { pkg: [0] },\n          }),\n    }));\n    vi.stubGlobal('fetch', fetchMock);\n\n    const { ensureRegistry } = await import('../../src/lib/cache.js');\n    await ensureRegistry();\n\n    expect(fetchMock).toHaveBeenCalledTimes(2);\n    expect(existsSync(join(tempChubDir, 'sources', 'default', 'search-index.json'))).toBe(true);\n\n    const meta = JSON.parse(readFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), 'utf8'));\n    expect(meta.searchIndexAvailable).toBe(true);\n    expect(typeof meta.searchIndexCheckedAt).toBe('number');\n  });\n\n  it('does not re-fetch when the source recently confirmed that no search index exists', async () => {\n    tempChubDir = mkdtempSync(join(tmpdir(), 'chub-cache-test-'));\n    process.env.CHUB_DIR = tempChubDir;\n\n    mkdirSync(join(tempChubDir, 'sources', 'default'), { recursive: true });\n    writeFileSync(join(tempChubDir, 'config.yaml'), [\n      'sources:',\n      '  - name: default',\n      '    url: https://cdn.example.test/v1',\n      'refresh_interval: 21600',\n      '',\n    ].join('\\n'));\n\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'registry.json'), JSON.stringify({\n      version: '1.0.0',\n      docs: [],\n      skills: [],\n    }));\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), JSON.stringify({\n      lastUpdated: Date.now(),\n      searchIndexAvailable: false,\n      searchIndexCheckedAt: Date.now(),\n    }));\n\n    const fetchMock = vi.fn();\n    vi.stubGlobal('fetch', fetchMock);\n\n    const { fetchAllRegistries } = await import('../../src/lib/cache.js');\n    await fetchAllRegistries(false);\n\n    expect(fetchMock).not.toHaveBeenCalled();\n  });\n\n  it('retries search-index fetches after transient failures', async () => {\n    tempChubDir = mkdtempSync(join(tmpdir(), 'chub-cache-test-'));\n    process.env.CHUB_DIR = tempChubDir;\n\n    mkdirSync(join(tempChubDir, 'sources', 'default'), { recursive: true });\n    writeFileSync(join(tempChubDir, 'config.yaml'), [\n      'sources:',\n      '  - name: default',\n      '    url: https://cdn.example.test/v1',\n      'refresh_interval: 21600',\n      '',\n    ].join('\\n'));\n\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'registry.json'), JSON.stringify({\n      version: '1.0.0',\n      docs: [],\n      skills: [],\n    }));\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), JSON.stringify({\n      lastUpdated: Date.now(),\n    }));\n\n    let searchIndexAttempts = 0;\n    const fetchMock = vi.fn(async (url) => {\n      if (url.endsWith('registry.json')) {\n        return {\n          ok: true,\n          status: 200,\n          statusText: 'OK',\n          text: async () => JSON.stringify({ version: '1.0.0', docs: [], skills: [] }),\n        };\n      }\n\n      searchIndexAttempts += 1;\n      if (searchIndexAttempts === 1) {\n        return {\n          ok: false,\n          status: 503,\n          statusText: 'Service Unavailable',\n          text: async () => '',\n        };\n      }\n\n      return {\n        ok: true,\n        status: 200,\n        statusText: 'OK',\n        text: async () => JSON.stringify({\n          version: '1.0.0',\n          algorithm: 'bm25',\n          params: { k1: 1.5, b: 0.75 },\n          totalDocs: 0,\n          avgFieldLengths: { id: 0, name: 0, description: 0, tags: 0 },\n          idf: {},\n          documents: [],\n          invertedIndex: {},\n        }),\n      };\n    });\n    vi.stubGlobal('fetch', fetchMock);\n\n    const { ensureRegistry } = await import('../../src/lib/cache.js');\n    await ensureRegistry();\n    await ensureRegistry();\n\n    expect(searchIndexAttempts).toBe(2);\n    expect(existsSync(join(tempChubDir, 'sources', 'default', 'search-index.json'))).toBe(true);\n\n    const meta = JSON.parse(readFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), 'utf8'));\n    expect(meta.searchIndexAvailable).toBe(true);\n    expect(typeof meta.searchIndexCheckedAt).toBe('number');\n  });\n\n  it('clears stale negative search-index metadata after a forced refresh transient failure', async () => {\n    tempChubDir = mkdtempSync(join(tmpdir(), 'chub-cache-test-'));\n    process.env.CHUB_DIR = tempChubDir;\n\n    mkdirSync(join(tempChubDir, 'sources', 'default'), { recursive: true });\n    writeFileSync(join(tempChubDir, 'config.yaml'), [\n      'sources:',\n      '  - name: default',\n      '    url: https://cdn.example.test/v1',\n      'refresh_interval: 21600',\n      '',\n    ].join('\\n'));\n\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'registry.json'), JSON.stringify({\n      version: '1.0.0',\n      docs: [],\n      skills: [],\n    }));\n    writeFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), JSON.stringify({\n      lastUpdated: Date.now(),\n      searchIndexAvailable: false,\n      searchIndexCheckedAt: Date.now(),\n    }));\n\n    let searchIndexAttempts = 0;\n    const fetchMock = vi.fn(async (url) => {\n      if (url.endsWith('registry.json')) {\n        return {\n          ok: true,\n          status: 200,\n          statusText: 'OK',\n          text: async () => JSON.stringify({ version: '1.0.0', docs: [], skills: [] }),\n        };\n      }\n\n      searchIndexAttempts += 1;\n      return {\n        ok: false,\n        status: 503,\n        statusText: 'Service Unavailable',\n        text: async () => '',\n      };\n    });\n    vi.stubGlobal('fetch', fetchMock);\n\n    const { fetchAllRegistries } = await import('../../src/lib/cache.js');\n    await fetchAllRegistries(true);\n\n    const metaAfterForce = JSON.parse(readFileSync(join(tempChubDir, 'sources', 'default', 'meta.json'), 'utf8'));\n    expect(metaAfterForce.searchIndexAvailable).toBeUndefined();\n    expect(metaAfterForce.searchIndexCheckedAt).toBeUndefined();\n\n    await fetchAllRegistries(false);\n    expect(searchIndexAttempts).toBe(2);\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/config.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { getChubDir, loadConfig } from '../../src/lib/config.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\ndescribe('getChubDir', () => {\n  it('returns a path ending in .chub', () => {\n    const dir = getChubDir();\n    expect(dir.endsWith('.chub')).toBe(true);\n  });\n\n  it('returns a path under the user home directory', () => {\n    const dir = getChubDir();\n    expect(dir).toBe(join(homedir(), '.chub'));\n  });\n});\n\ndescribe('loadConfig', () => {\n  it('returns an object with expected default keys', () => {\n    const config = loadConfig();\n\n    expect(config).toHaveProperty('sources');\n    expect(config).toHaveProperty('output_dir');\n    expect(config).toHaveProperty('refresh_interval');\n    expect(config).toHaveProperty('output_format');\n    expect(config).toHaveProperty('source');\n  });\n\n  it('has sensible default values', () => {\n    const config = loadConfig();\n\n    expect(config.output_dir).toBe('.context');\n    expect(config.refresh_interval).toBe(21600);\n    expect(config.output_format).toBe('human');\n    expect(config.source).toBe('official,maintainer,community');\n  });\n\n  it('sources is a non-empty array', () => {\n    const config = loadConfig();\n\n    expect(Array.isArray(config.sources)).toBe(true);\n    expect(config.sources.length).toBeGreaterThan(0);\n  });\n\n  it('each source has a name and url or path', () => {\n    const config = loadConfig();\n\n    for (const source of config.sources) {\n      expect(source).toHaveProperty('name');\n      expect(source.url || source.path).toBeTruthy();\n    }\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/frontmatter.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { parseFrontmatter } from '../../src/lib/frontmatter.js';\n\ndescribe('parseFrontmatter', () => {\n  it('parses valid frontmatter with attributes and body', () => {\n    const content = `---\nname: my-doc\ndescription: A test document\nmetadata:\n  languages: \"python,javascript\"\n  versions: \"1.0.0\"\n  tags: \"ai,llm\"\n---\n\n# Hello World\n\nThis is the body.`;\n\n    const result = parseFrontmatter(content);\n\n    expect(result.attributes.name).toBe('my-doc');\n    expect(result.attributes.description).toBe('A test document');\n    expect(result.attributes.metadata.languages).toBe('python,javascript');\n    expect(result.attributes.metadata.versions).toBe('1.0.0');\n    expect(result.attributes.metadata.tags).toBe('ai,llm');\n    expect(result.body).toContain('# Hello World');\n    expect(result.body).toContain('This is the body.');\n  });\n\n  it('returns empty attributes when no frontmatter', () => {\n    const content = `# Just a heading\n\nNo frontmatter here.`;\n\n    const result = parseFrontmatter(content);\n\n    expect(result.attributes).toEqual({});\n    expect(result.body).toBe(content);\n  });\n\n  it('handles empty metadata in frontmatter', () => {\n    const content = `---\nname: empty-meta\n---\n\nBody content.`;\n\n    const result = parseFrontmatter(content);\n\n    expect(result.attributes.name).toBe('empty-meta');\n    expect(result.body).toContain('Body content.');\n  });\n\n  it('handles frontmatter with only whitespace values', () => {\n    const content = `---\nname: test\ndescription: \"\"\n---\n\nBody.`;\n\n    const result = parseFrontmatter(content);\n\n    expect(result.attributes.name).toBe('test');\n    expect(result.attributes.description).toBe('');\n    expect(result.body).toContain('Body.');\n  });\n\n  it('handles content with no trailing newline after closing ---', () => {\n    const content = `---\nname: test\n---\nImmediate body.`;\n\n    const result = parseFrontmatter(content);\n\n    expect(result.attributes.name).toBe('test');\n    expect(result.body).toBe('Immediate body.');\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/normalize.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { normalizeLanguage, displayLanguage } from '../../src/lib/normalize.js';\n\ndescribe('normalizeLanguage', () => {\n  it('maps js to javascript', () => {\n    expect(normalizeLanguage('js')).toBe('javascript');\n  });\n\n  it('maps ts to typescript', () => {\n    expect(normalizeLanguage('ts')).toBe('typescript');\n  });\n\n  it('maps py to python', () => {\n    expect(normalizeLanguage('py')).toBe('python');\n  });\n\n  it('maps rb to ruby', () => {\n    expect(normalizeLanguage('rb')).toBe('ruby');\n  });\n\n  it('maps cs to csharp', () => {\n    expect(normalizeLanguage('cs')).toBe('csharp');\n  });\n\n  it('is case-insensitive', () => {\n    expect(normalizeLanguage('JS')).toBe('javascript');\n    expect(normalizeLanguage('Py')).toBe('python');\n    expect(normalizeLanguage('TS')).toBe('typescript');\n  });\n\n  it('passes through unknown languages unchanged (lowercased)', () => {\n    expect(normalizeLanguage('rust')).toBe('rust');\n    expect(normalizeLanguage('go')).toBe('go');\n    expect(normalizeLanguage('java')).toBe('java');\n  });\n\n  it('returns null for falsy input', () => {\n    expect(normalizeLanguage(null)).toBe(null);\n    expect(normalizeLanguage(undefined)).toBe(null);\n    expect(normalizeLanguage('')).toBe(null);\n  });\n});\n\ndescribe('displayLanguage', () => {\n  it('maps javascript to js', () => {\n    expect(displayLanguage('javascript')).toBe('js');\n  });\n\n  it('maps typescript to ts', () => {\n    expect(displayLanguage('typescript')).toBe('ts');\n  });\n\n  it('maps python to py', () => {\n    expect(displayLanguage('python')).toBe('py');\n  });\n\n  it('maps ruby to rb', () => {\n    expect(displayLanguage('ruby')).toBe('rb');\n  });\n\n  it('maps csharp to cs', () => {\n    expect(displayLanguage('csharp')).toBe('cs');\n  });\n\n  it('passes through unknown languages unchanged', () => {\n    expect(displayLanguage('rust')).toBe('rust');\n    expect(displayLanguage('go')).toBe('go');\n    expect(displayLanguage('java')).toBe('java');\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/registry.multisource.test.js",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\nimport { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { buildIndex } from '../../src/lib/bm25.js';\n\nconst ORIGINAL_CHUB_DIR = process.env.CHUB_DIR;\nconst tempDirs = [];\n\nfunction writeSource(root, quality, description, tags = []) {\n  mkdirSync(root, { recursive: true });\n  writeFileSync(\n    join(root, 'registry.json'),\n    JSON.stringify({\n      version: '1.0.0',\n      docs: [\n        {\n          id: 'shared/api',\n          name: 'shared api',\n          description,\n          source: quality,\n          tags,\n          languages: [\n            {\n              language: 'javascript',\n              recommendedVersion: '1.0.0',\n              versions: [\n                {\n                  version: '1.0.0',\n                  path: 'shared/api/javascript',\n                  files: ['DOC.md'],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n      skills: [],\n    }, null, 2)\n  );\n\n  writeFileSync(\n    join(root, 'search-index.json'),\n    JSON.stringify(\n      buildIndex([\n        {\n          id: 'shared/api',\n          name: 'shared api',\n          description,\n          tags,\n        },\n      ])\n    )\n  );\n}\n\nasync function loadRegistryWithSources(sourceRoots) {\n  const tempRoot = mkdtempSync(join(tmpdir(), 'chub-multisource-'));\n  tempDirs.push(tempRoot);\n\n  const chubDir = join(tempRoot, '.chub');\n  mkdirSync(chubDir, { recursive: true });\n\n  const config = [\n    'sources:',\n    ...sourceRoots.map(({ name, root }) => `  - name: ${name}\\n    path: ${JSON.stringify(root)}`),\n    'source: official,maintainer,community',\n  ].join('\\n');\n\n  writeFileSync(join(chubDir, 'config.yaml'), `${config}\\n`);\n  process.env.CHUB_DIR = chubDir;\n\n  vi.resetModules();\n  return import('../../src/lib/registry.js');\n}\n\nafterEach(() => {\n  vi.resetModules();\n  if (ORIGINAL_CHUB_DIR === undefined) delete process.env.CHUB_DIR;\n  else process.env.CHUB_DIR = ORIGINAL_CHUB_DIR;\n\n  while (tempDirs.length > 0) {\n    rmSync(tempDirs.pop(), { recursive: true, force: true });\n  }\n});\n\ndescribe('searchEntries multi-source collisions', () => {\n  it('returns the entry from the matching source when multiple sources share an id', async () => {\n    const tempRoot = mkdtempSync(join(tmpdir(), 'chub-multisource-data-'));\n    tempDirs.push(tempRoot);\n\n    const alpha = join(tempRoot, 'alpha');\n    const beta = join(tempRoot, 'beta');\n    writeSource(alpha, 'official', 'Alpha payments integration', ['payments']);\n    writeSource(beta, 'official', 'Beta observability traces', ['tracing']);\n\n    const { searchEntries } = await loadRegistryWithSources([\n      { name: 'alpha', root: alpha },\n      { name: 'beta', root: beta },\n    ]);\n\n    const payments = searchEntries('payments');\n    const tracing = searchEntries('tracing');\n\n    expect(payments).toHaveLength(1);\n    expect(payments[0]._source).toBe('alpha');\n    expect(payments[0].description).toContain('payments');\n\n    expect(tracing).toHaveLength(1);\n    expect(tracing[0]._source).toBe('beta');\n    expect(tracing[0].description).toContain('traces');\n  });\n\n  it('keeps both search results when duplicate ids exist across sources', async () => {\n    const tempRoot = mkdtempSync(join(tmpdir(), 'chub-multisource-data-'));\n    tempDirs.push(tempRoot);\n\n    const alpha = join(tempRoot, 'alpha');\n    const beta = join(tempRoot, 'beta');\n    writeSource(alpha, 'official', 'Alpha shared API for payments', ['payments']);\n    writeSource(beta, 'official', 'Beta shared API for tracing', ['tracing']);\n\n    const { searchEntries } = await loadRegistryWithSources([\n      { name: 'alpha', root: alpha },\n      { name: 'beta', root: beta },\n    ]);\n\n    const results = searchEntries('shared');\n\n    expect(results).toHaveLength(2);\n    expect(new Set(results.map((entry) => entry._source))).toEqual(new Set(['alpha', 'beta']));\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/registry.search-behavior.test.js",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\nimport { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { buildIndex } from '../../src/lib/bm25.js';\n\nconst ORIGINAL_CHUB_DIR = process.env.CHUB_DIR;\nconst tempDirs = [];\n\nfunction writeSource(root, docs) {\n  mkdirSync(root, { recursive: true });\n  writeFileSync(\n    join(root, 'registry.json'),\n    JSON.stringify({\n      version: '1.0.0',\n      docs: docs.map((doc) => ({\n        ...doc,\n        source: 'official',\n        languages: doc.languages || [],\n      })),\n      skills: [],\n    }, null, 2),\n  );\n\n  writeFileSync(\n    join(root, 'search-index.json'),\n    JSON.stringify(buildIndex(docs)),\n  );\n}\n\nasync function loadRegistry(docs) {\n  const tempRoot = mkdtempSync(join(tmpdir(), 'chub-search-behavior-'));\n  tempDirs.push(tempRoot);\n\n  const sourceRoot = join(tempRoot, 'source');\n  writeSource(sourceRoot, docs);\n\n  const chubDir = join(tempRoot, '.chub');\n  mkdirSync(chubDir, { recursive: true });\n  writeFileSync(join(chubDir, 'config.yaml'), [\n    'sources:',\n    `  - name: default`,\n    `    path: ${JSON.stringify(sourceRoot)}`,\n    'source: official,maintainer,community',\n    '',\n  ].join('\\n'));\n\n  process.env.CHUB_DIR = chubDir;\n  vi.resetModules();\n  return import('../../src/lib/registry.js');\n}\n\nafterEach(() => {\n  vi.resetModules();\n  if (ORIGINAL_CHUB_DIR === undefined) delete process.env.CHUB_DIR;\n  else process.env.CHUB_DIR = ORIGINAL_CHUB_DIR;\n\n  while (tempDirs.length > 0) {\n    rmSync(tempDirs.pop(), { recursive: true, force: true });\n  }\n});\n\ndescribe('searchEntries normalization and typo handling', () => {\n  it('recovers common typos and joined/split identifier forms', async () => {\n    const docs = [\n      {\n        id: 'playwright/playwright',\n        name: 'Playwright',\n        description: 'Browser automation library',\n        tags: ['testing'],\n      },\n      {\n        id: 'react/react',\n        name: 'React',\n        description: 'React UI library',\n        tags: ['react'],\n      },\n      {\n        id: 'node-fetch/node-fetch',\n        name: 'node-fetch',\n        description: 'Fetch API for Node.js',\n        tags: ['http'],\n      },\n      {\n        id: 'typescript/node-fetch',\n        name: 'node-fetch types',\n        description: 'TypeScript support for node-fetch',\n        tags: ['typescript'],\n      },\n      {\n        id: 'auth0/identity',\n        name: 'Auth0 Identity',\n        description: 'Authentication and identity toolkit',\n        tags: ['auth'],\n      },\n      {\n        id: 'next/next',\n        name: 'Next.js',\n        description: 'React framework for production',\n        tags: ['react'],\n      },\n      {\n        id: 'eslint/eslint-config-next',\n        name: 'eslint-config-next',\n        description: 'ESLint preset for Next.js apps',\n        tags: ['eslint'],\n      },\n      {\n        id: 'openai/chat',\n        name: 'OpenAI Chat',\n        description: 'OpenAI chat docs',\n        tags: ['ai'],\n      },\n      {\n        id: 'openapi/package',\n        name: 'OpenAPI',\n        description: 'OpenAPI tooling docs',\n        tags: ['api'],\n      },\n    ];\n\n    const { searchEntries, getEntry } = await loadRegistry(docs);\n\n    expect(searchEntries('playwrite')[0].id).toBe('playwright/playwright');\n    expect(searchEntries('play wright')[0].id).toBe('playwright/playwright');\n    expect(searchEntries('nodefetch')[0].id).toBe('node-fetch/node-fetch');\n    expect(searchEntries('node-fetch')[0].id).toBe('node-fetch/node-fetch');\n    expect(searchEntries('auth 0')[0].id).toBe('auth0/identity');\n    expect(searchEntries('nextjs')[0].id).toBe('next/next');\n    expect(searchEntries('open ai')[0].id).toBe('openai/chat');\n    expect(searchEntries('react playwrite').slice(0, 5).map((entry) => entry.id)).toContain('playwright/playwright');\n    expect(getEntry('  openai/chat  ').entry?.id).toBe('openai/chat');\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/registry.test.js",
    "content": "import { describe, it, expect } from 'vitest';\nimport { searchEntries, getEntry, resolveDocPath, resolveEntryFile } from '../../src/lib/registry.js';\n\ndescribe('searchEntries', () => {\n  it('returns an array', () => {\n    const results = searchEntries('nonexistent-entry-xyz-12345');\n    expect(Array.isArray(results)).toBe(true);\n  });\n\n  it('returns empty array for nonsense query', () => {\n    const results = searchEntries('zzzzz-no-match-ever-xyz');\n    expect(results).toEqual([]);\n  });\n\n  it('scores exact id match higher than partial match', () => {\n    // Create two mock entries by searching for a term that could match partially\n    // This tests the scoring logic: exact id match (100) > partial match (50)\n    // We rely on whatever is in the registry; if empty, results will be []\n    const results = searchEntries('test');\n    if (results.length >= 2) {\n      // Results should be sorted by score descending\n      expect(results[0]._score).toBeGreaterThanOrEqual(results[1]._score);\n    }\n    // Even with 0 or 1 results, the function should not throw\n    expect(Array.isArray(results)).toBe(true);\n  });\n\n  it('applies language filter', () => {\n    // Search with a language filter\n    const results = searchEntries('', { lang: 'python' });\n    for (const entry of results) {\n      if (entry.languages) {\n        const hasLang = entry.languages.some((l) => l.language === 'python');\n        expect(hasLang).toBe(true);\n      }\n    }\n  });\n\n  it('applies tag filter', () => {\n    const results = searchEntries('', { tags: 'nonexistent-tag-xyz' });\n    expect(results).toEqual([]);\n  });\n});\n\ndescribe('getEntry', () => {\n  it('returns { entry: null, ambiguous: false } for nonexistent id', () => {\n    const result = getEntry('does-not-exist/at-all-xyz-12345');\n    expect(result.entry).toBeNull();\n    expect(result.ambiguous).toBe(false);\n  });\n\n  it('handles source:id format', () => {\n    const result = getEntry('nosource:noid');\n    expect(result.entry).toBeNull();\n    expect(result.ambiguous).toBe(false);\n  });\n\n  it('accepts type parameter \"doc\"', () => {\n    const result = getEntry('nonexistent-xyz', 'doc');\n    expect(result.entry).toBeNull();\n  });\n\n  it('accepts type parameter \"skill\"', () => {\n    const result = getEntry('nonexistent-xyz', 'skill');\n    expect(result.entry).toBeNull();\n  });\n});\n\ndescribe('resolveDocPath', () => {\n  it('returns null for entry with no languages and no path', () => {\n    const entry = { name: 'test', _sourceObj: { name: 'default', url: 'http://example.com' } };\n    const result = resolveDocPath(entry, null, null);\n    expect(result).toBeNull();\n  });\n\n  it('returns path directly for skill entries (no languages)', () => {\n    const entry = {\n      name: 'test-skill',\n      path: 'author/test-skill',\n      files: ['SKILL.md'],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    const result = resolveDocPath(entry, null, null);\n    expect(result).toEqual({\n      source: entry._sourceObj,\n      path: 'author/test-skill',\n      files: ['SKILL.md'],\n    });\n  });\n\n  it('prompts for language when multiple languages exist and none specified', () => {\n    const entry = {\n      name: 'multi-lang',\n      languages: [\n        { language: 'python', versions: [{ version: '1.0', path: 'p/python', files: [] }], recommendedVersion: '1.0' },\n        { language: 'javascript', versions: [{ version: '1.0', path: 'p/js', files: [] }], recommendedVersion: '1.0' },\n      ],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    const result = resolveDocPath(entry, null, null);\n    expect(result.needsLanguage).toBe(true);\n    expect(result.available).toEqual(['python', 'javascript']);\n  });\n\n  it('selects the correct language', () => {\n    const entry = {\n      name: 'multi-lang',\n      languages: [\n        { language: 'python', versions: [{ version: '1.0', path: 'p/python', files: ['DOC.md'] }], recommendedVersion: '1.0' },\n        { language: 'javascript', versions: [{ version: '1.0', path: 'p/js', files: ['DOC.md'] }], recommendedVersion: '1.0' },\n      ],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    const result = resolveDocPath(entry, 'python', null);\n    expect(result.path).toBe('p/python');\n  });\n\n  it('normalizes language aliases when resolving', () => {\n    const entry = {\n      name: 'alias-test',\n      languages: [\n        { language: 'javascript', versions: [{ version: '2.0', path: 'a/js', files: [] }], recommendedVersion: '2.0' },\n      ],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    // 'js' should be normalized to 'javascript'\n    const result = resolveDocPath(entry, 'js', null);\n    expect(result.path).toBe('a/js');\n  });\n\n  it('selects the correct version', () => {\n    const entry = {\n      name: 'versioned',\n      languages: [\n        {\n          language: 'python',\n          versions: [\n            { version: '2.0', path: 'p/v2', files: ['DOC.md'] },\n            { version: '1.0', path: 'p/v1', files: ['DOC.md'] },\n          ],\n          recommendedVersion: '2.0',\n        },\n      ],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    const result = resolveDocPath(entry, 'python', '1.0');\n    expect(result.path).toBe('p/v1');\n  });\n\n  it('falls back to recommended version when none specified', () => {\n    const entry = {\n      name: 'versioned',\n      languages: [\n        {\n          language: 'python',\n          versions: [\n            { version: '2.0', path: 'p/v2', files: ['DOC.md'] },\n            { version: '1.0', path: 'p/v1', files: ['DOC.md'] },\n          ],\n          recommendedVersion: '2.0',\n        },\n      ],\n      _sourceObj: { name: 'default', url: 'http://example.com' },\n    };\n    const result = resolveDocPath(entry, 'python', null);\n    expect(result.path).toBe('p/v2');\n  });\n});\n\ndescribe('resolveEntryFile', () => {\n  it('returns DOC.md path for doc type', () => {\n    const resolved = { path: 'author/my-doc', files: ['DOC.md'] };\n    const result = resolveEntryFile(resolved, 'doc');\n    expect(result.filePath).toBe('author/my-doc/DOC.md');\n    expect(result.basePath).toBe('author/my-doc');\n  });\n\n  it('returns SKILL.md path for skill type', () => {\n    const resolved = { path: 'author/my-skill', files: ['SKILL.md'] };\n    const result = resolveEntryFile(resolved, 'skill');\n    expect(result.filePath).toBe('author/my-skill/SKILL.md');\n    expect(result.basePath).toBe('author/my-skill');\n  });\n\n  it('returns error for unresolved entry', () => {\n    const result = resolveEntryFile(null, 'doc');\n    expect(result.error).toBe('unresolved');\n  });\n\n  it('returns error for needsLanguage entry', () => {\n    const result = resolveEntryFile({ needsLanguage: true, available: ['python'] }, 'doc');\n    expect(result.error).toBe('unresolved');\n  });\n});\n"
  },
  {
    "path": "cli/tests/lib/welcome.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\nimport { existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { showWelcomeIfNeeded } from '../../src/lib/welcome.js';\n\nconst TEST_DIR = join('/tmp', 'test-chub');\n\nvi.mock('node:fs', () => ({\n  existsSync: vi.fn(),\n  writeFileSync: vi.fn(),\n  mkdirSync: vi.fn(),\n}));\n\nvi.mock('../../src/lib/config.js', async () => {\n  const { join } = await import('node:path');\n  return { getChubDir: () => join('/tmp', 'test-chub') };\n});\n\ndescribe('showWelcomeIfNeeded', () => {\n  let consoleSpy;\n  let stdoutDescriptor;\n  let stderrDescriptor;\n\n  beforeEach(() => {\n    consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});\n    vi.clearAllMocks();\n    stdoutDescriptor = Object.getOwnPropertyDescriptor(process.stdout, 'isTTY');\n    stderrDescriptor = Object.getOwnPropertyDescriptor(process.stderr, 'isTTY');\n    Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n    Object.defineProperty(process.stderr, 'isTTY', { value: true, configurable: true });\n  });\n\n  afterEach(() => {\n    consoleSpy.mockRestore();\n    if (stdoutDescriptor) {\n      Object.defineProperty(process.stdout, 'isTTY', stdoutDescriptor);\n    }\n    if (stderrDescriptor) {\n      Object.defineProperty(process.stderr, 'isTTY', stderrDescriptor);\n    }\n  });\n\n  it('shows welcome message on first run', () => {\n    existsSync.mockReturnValue(false);\n\n    showWelcomeIfNeeded();\n\n    expect(consoleSpy).toHaveBeenCalledTimes(1);\n    const output = consoleSpy.mock.calls[0][0];\n    expect(output).toContain('Welcome to Context Hub (chub)!');\n    expect(output).toContain('Terms of Service');\n    expect(output).toContain('feedback: false');\n    expect(output).toContain(join(TEST_DIR, 'config.yaml'));\n  });\n\n  it('creates marker file after showing message', () => {\n    existsSync.mockReturnValue(false);\n\n    showWelcomeIfNeeded();\n\n    // Called twice: once for marker check, once for dir check\n    expect(existsSync).toHaveBeenCalledTimes(2);\n    expect(mkdirSync).toHaveBeenCalledWith(TEST_DIR, { recursive: true });\n    expect(writeFileSync).toHaveBeenCalledWith(\n      join(TEST_DIR, '.welcome_shown'),\n      expect.any(String),\n      'utf8'\n    );\n  });\n\n  it('does not show message if marker exists', () => {\n    existsSync.mockReturnValueOnce(true); // marker exists\n\n    showWelcomeIfNeeded();\n\n    expect(consoleSpy).not.toHaveBeenCalled();\n    expect(writeFileSync).not.toHaveBeenCalled();\n  });\n\n  it('does not throw if marker write fails', () => {\n    existsSync.mockReturnValue(false);\n    writeFileSync.mockImplementation(() => { throw new Error('EACCES'); });\n\n    expect(() => showWelcomeIfNeeded()).not.toThrow();\n    expect(consoleSpy).toHaveBeenCalledTimes(1);\n  });\n\n  it('does not show message in JSON mode', () => {\n    showWelcomeIfNeeded({ json: true });\n\n    expect(consoleSpy).not.toHaveBeenCalled();\n    expect(writeFileSync).not.toHaveBeenCalled();\n  });\n\n  it('does not show message when stdout is not a TTY', () => {\n    Object.defineProperty(process.stdout, 'isTTY', { value: false, configurable: true });\n\n    showWelcomeIfNeeded();\n\n    expect(consoleSpy).not.toHaveBeenCalled();\n    expect(writeFileSync).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "cli/tests/mcp/stdio-lifecycle.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest';\nimport { EventEmitter } from 'node:events';\nimport { attachStdioShutdownHandlers } from '../../src/mcp/stdio-lifecycle.js';\n\nfunction makeStream() {\n  const stream = new EventEmitter();\n  stream.resume = vi.fn();\n  return stream;\n}\n\ndescribe('attachStdioShutdownHandlers', () => {\n  it('exits on stdin end', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n    const stderr = { write: vi.fn() };\n    const onShutdown = vi.fn();\n\n    attachStdioShutdownHandlers({ stdin, stdout, stderr, onShutdown });\n    stdin.emit('end');\n\n    expect(onShutdown).toHaveBeenCalledTimes(1);\n    expect(onShutdown).toHaveBeenCalledWith(0);\n    expect(stderr.write).toHaveBeenCalledWith('[chub-mcp] Stdin closed; exiting.\\n');\n  });\n\n  it('exits on stdout EPIPE', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n    const stderr = { write: vi.fn() };\n    const onShutdown = vi.fn();\n\n    attachStdioShutdownHandlers({ stdin, stdout, stderr, onShutdown });\n    stdout.emit('error', { code: 'EPIPE' });\n\n    expect(onShutdown).toHaveBeenCalledTimes(1);\n    expect(stderr.write).toHaveBeenCalledWith('[chub-mcp] Stdout pipe closed (EPIPE); exiting.\\n');\n  });\n\n  it('ignores non-EPIPE stdout errors', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n    const stderr = { write: vi.fn() };\n    const onShutdown = vi.fn();\n\n    attachStdioShutdownHandlers({ stdin, stdout, stderr, onShutdown });\n    stdout.emit('error', { code: 'ECONNRESET' });\n\n    expect(onShutdown).not.toHaveBeenCalled();\n    expect(stderr.write).not.toHaveBeenCalled();\n  });\n\n  it('only shuts down once', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n    const stderr = { write: vi.fn() };\n    const onShutdown = vi.fn();\n\n    attachStdioShutdownHandlers({ stdin, stdout, stderr, onShutdown });\n    stdin.emit('end');\n    stdout.emit('error', { code: 'EPIPE' });\n    stdin.emit('close');\n\n    expect(onShutdown).toHaveBeenCalledTimes(1);\n    expect(stderr.write).toHaveBeenCalledTimes(1);\n  });\n\n  it('returns cleanup function that removes listeners', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n    const stderr = { write: vi.fn() };\n    const onShutdown = vi.fn();\n\n    const cleanup = attachStdioShutdownHandlers({ stdin, stdout, stderr, onShutdown });\n    cleanup();\n\n    expect(stdin.listenerCount('end')).toBe(0);\n    expect(stdin.listenerCount('close')).toBe(0);\n    expect(stdin.listenerCount('error')).toBe(0);\n    expect(stdout.listenerCount('error')).toBe(0);\n    expect(onShutdown).not.toHaveBeenCalled();\n  });\n\n  it('resumes stdin so EOF can be observed', () => {\n    const stdin = makeStream();\n    const stdout = makeStream();\n\n    attachStdioShutdownHandlers({\n      stdin,\n      stdout,\n      stderr: { write: vi.fn() },\n      onShutdown: vi.fn(),\n    });\n\n    expect(stdin.resume).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "cli/tests/mcp/tools.test.js",
    "content": "import { describe, it, expect, vi, afterEach, beforeAll, afterAll } from 'vitest';\nimport { mkdtempSync, rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { handleSearch, handleGet, handleList, handleAnnotate, handleFeedback } from '../../src/mcp/tools.js';\nimport * as analytics from '../../src/lib/analytics.js';\n\nconst originalChubDir = process.env.CHUB_DIR;\nlet tempChubDir;\n\nbeforeAll(() => {\n  tempChubDir = mkdtempSync(join(tmpdir(), 'chub-mcp-test-'));\n  process.env.CHUB_DIR = tempChubDir;\n});\n\nafterAll(() => {\n  if (originalChubDir === undefined) {\n    delete process.env.CHUB_DIR;\n  } else {\n    process.env.CHUB_DIR = originalChubDir;\n  }\n\n  if (tempChubDir) {\n    rmSync(tempChubDir, { recursive: true, force: true });\n  }\n});\n\n/**\n * Helper to parse the JSON text from an MCP tool result.\n */\nfunction parseResult(result) {\n  return JSON.parse(result.content[0].text);\n}\n\ndescribe('chub_search (handleSearch)', () => {\n  it('returns results array for a valid query', async () => {\n    const result = await handleSearch({ query: 'stripe', limit: 5 });\n    const data = parseResult(result);\n    expect(data).toHaveProperty('results');\n    expect(data).toHaveProperty('total');\n    expect(Array.isArray(data.results)).toBe(true);\n  });\n\n  it('lists all entries when no query is provided', async () => {\n    const result = await handleSearch({ limit: 200 });\n    const data = parseResult(result);\n    expect(data.total).toBeGreaterThanOrEqual(0);\n  });\n\n  it('respects limit parameter', async () => {\n    const result = await handleSearch({ limit: 2 });\n    const data = parseResult(result);\n    expect(data.results.length).toBeLessThanOrEqual(2);\n  });\n\n  it('returns simplified entry shape', async () => {\n    const result = await handleSearch({ limit: 1 });\n    const data = parseResult(result);\n    if (data.results.length > 0) {\n      const entry = data.results[0];\n      expect(entry).toHaveProperty('id');\n      expect(entry).toHaveProperty('name');\n      expect(entry).toHaveProperty('type');\n      expect(entry).toHaveProperty('description');\n      expect(entry).toHaveProperty('tags');\n      // Should not contain internal fields\n      expect(entry).not.toHaveProperty('_source');\n      expect(entry).not.toHaveProperty('_sourceObj');\n      expect(entry).not.toHaveProperty('_score');\n    }\n  });\n\n  it('returns empty results for nonsense query', async () => {\n    const result = await handleSearch({ query: 'zzz-no-match-xyz-99999', limit: 10 });\n    const data = parseResult(result);\n    expect(data.results).toEqual([]);\n    expect(data.total).toBe(0);\n  });\n});\n\ndescribe('chub_get (handleGet)', () => {\n  it('returns error for nonexistent entry', async () => {\n    const result = await handleGet({ id: 'does-not-exist/xyz-99999' });\n    expect(result.isError).toBe(true);\n    const data = parseResult(result);\n    expect(data.error).toContain('not found');\n  });\n\n  it('returns doc content as text', async () => {\n    // Use a known entry from the registry\n    const searchResult = await handleSearch({ limit: 1 });\n    const entries = parseResult(searchResult);\n    if (entries.results.length === 0) return; // skip if no registry\n\n    const id = entries.results[0].id;\n    const result = await handleGet({ id });\n\n    if (!result.isError) {\n      const text = result.content[0].text;\n      expect(text.length).toBeGreaterThan(0);\n      expect(typeof text).toBe('string');\n    }\n  });\n\n  it('returns error when language is needed', async () => {\n    // Find a multi-language entry\n    const listResult = await handleList({ limit: 500 });\n    const data = parseResult(listResult);\n    const multiLang = data.entries.find((e) => e.languages && e.languages.length > 1);\n    if (!multiLang) return; // skip if no multi-language entries\n\n    const result = await handleGet({ id: multiLang.id });\n    if (result.isError) {\n      const err = parseResult(result);\n      expect(err.available).toBeDefined();\n    }\n  });\n\n  it('rejects path traversal in file parameter', async () => {\n    const result = await handleGet({ id: 'stripe/api', file: '../../etc/passwd' });\n    expect(result.isError).toBe(true);\n    const data = parseResult(result);\n    expect(data.error).toContain('traversal');\n  });\n\n  it('returns error for nonexistent file within entry', async () => {\n    // Find a single-language entry and pass its language to avoid \"needs language\" errors\n    const listResult = await handleList({ limit: 500 });\n    const data = parseResult(listResult);\n    const singleLang = data.entries.find((e) => e.languages && e.languages.length === 1);\n    if (!singleLang) return;\n\n    const lang = singleLang.languages[0];\n    const result = await handleGet({ id: singleLang.id, lang, file: 'nonexistent-file-xyz.md' });\n    expect(result.isError).toBe(true);\n    const err = parseResult(result);\n    expect(err.error).toContain('not found');\n  });\n});\n\ndescribe('chub_list (handleList)', () => {\n  it('returns entries array', async () => {\n    const result = await handleList({ limit: 10 });\n    const data = parseResult(result);\n    expect(data).toHaveProperty('entries');\n    expect(data).toHaveProperty('total');\n    expect(Array.isArray(data.entries)).toBe(true);\n  });\n\n  it('respects limit', async () => {\n    const result = await handleList({ limit: 3 });\n    const data = parseResult(result);\n    expect(data.entries.length).toBeLessThanOrEqual(3);\n  });\n\n  it('filters by language', async () => {\n    const result = await handleList({ lang: 'python', limit: 100 });\n    const data = parseResult(result);\n    for (const entry of data.entries) {\n      if (entry.languages) {\n        expect(entry.languages).toContain('python');\n      }\n    }\n  });\n});\n\ndescribe('chub_annotate (handleAnnotate)', () => {\n  const testId = '__mcp-test-annotation__/test';\n\n  it('returns no_annotation for nonexistent entry', async () => {\n    const result = await handleAnnotate({ id: testId });\n    const data = parseResult(result);\n    expect(data.status).toBe('no_annotation');\n  });\n\n  it('writes and reads an annotation', async () => {\n    // Write\n    const writeResult = await handleAnnotate({ id: testId, note: 'MCP test note' });\n    const writeData = parseResult(writeResult);\n    expect(writeData.status).toBe('saved');\n    expect(writeData.annotation.note).toBe('MCP test note');\n\n    // Read back\n    const readResult = await handleAnnotate({ id: testId });\n    const readData = parseResult(readResult);\n    expect(readData.annotation.note).toBe('MCP test note');\n\n    // Clean up\n    await handleAnnotate({ id: testId, clear: true });\n  });\n\n  it('clears an annotation', async () => {\n    await handleAnnotate({ id: testId, note: 'to be cleared' });\n    const result = await handleAnnotate({ id: testId, clear: true });\n    const data = parseResult(result);\n    expect(data.status).toBe('cleared');\n  });\n\n  it('lists annotations', async () => {\n    const result = await handleAnnotate({ id: 'ignored', list: true });\n    const data = parseResult(result);\n    expect(data).toHaveProperty('annotations');\n    expect(Array.isArray(data.annotations)).toBe(true);\n  });\n\n  it('returns error when id is missing in non-list mode', async () => {\n    const result = await handleAnnotate({});\n    expect(result.isError).toBe(true);\n    const data = parseResult(result);\n    expect(data.error).toContain('Missing required parameter');\n  });\n\n  it('rejects entry ID with invalid characters', async () => {\n    const result = await handleAnnotate({ id: 'test/<script>alert(1)</script>', note: 'xss' });\n    expect(result.isError).toBe(true);\n    const data = parseResult(result);\n    expect(data.error).toContain('invalid characters');\n  });\n\n  it('rejects excessively long entry ID', async () => {\n    const longId = 'a'.repeat(201);\n    const result = await handleAnnotate({ id: longId, note: 'test' });\n    expect(result.isError).toBe(true);\n    const data = parseResult(result);\n    expect(data.error).toContain('too long');\n  });\n});\n\ndescribe('telemetry', () => {\n  let trackSpy;\n\n  afterEach(() => {\n    trackSpy?.mockRestore();\n  });\n\n  it('emits search event with correct schema for MCP search', async () => {\n    trackSpy = vi.spyOn(analytics, 'trackEvent').mockResolvedValue();\n    await handleSearch({ query: 'stripe', tags: 'payments', lang: 'js', limit: 5 });\n\n    const searchCall = trackSpy.mock.calls.find(([event]) => event === 'search');\n    expect(searchCall).toBeDefined();\n    const [event, props] = searchCall;\n    expect(event).toBe('search');\n    expect(props).toHaveProperty('query', 'stripe');\n    expect(props).toHaveProperty('query_length', 6);\n    expect(props).toHaveProperty('result_count');\n    expect(props).toHaveProperty('results');\n    expect(props).toHaveProperty('has_tags', true);\n    expect(props).toHaveProperty('has_lang', true);\n    expect(props).toHaveProperty('tags', 'payments');\n    expect(props).toHaveProperty('lang', 'js');\n    expect(props).toHaveProperty('duration_ms');\n    expect(props).toHaveProperty('via', 'mcp');\n    // Should NOT have error_message\n    expect(props).not.toHaveProperty('error_message');\n  });\n\n  it('does not emit search event when no query', async () => {\n    trackSpy = vi.spyOn(analytics, 'trackEvent').mockResolvedValue();\n    await handleSearch({ limit: 5 });\n\n    const searchCall = trackSpy.mock.calls.find(([event]) => event === 'search');\n    expect(searchCall).toBeUndefined();\n  });\n\n  it('emits doc_not_found for missing entry', async () => {\n    trackSpy = vi.spyOn(analytics, 'trackEvent').mockResolvedValue();\n    await handleGet({ id: 'does-not-exist/xyz-99999' });\n\n    const call = trackSpy.mock.calls.find(([event]) => event === 'doc_not_found');\n    expect(call).toBeDefined();\n    expect(call[1]).toHaveProperty('entry_id', 'does-not-exist/xyz-99999');\n    expect(call[1]).toHaveProperty('via', 'mcp');\n    expect(call[1]).not.toHaveProperty('error_message');\n  });\n\n  it('emits doc_fetched/skill_fetched on successful get', async () => {\n    trackSpy = vi.spyOn(analytics, 'trackEvent').mockResolvedValue();\n\n    // Find a fetchable entry\n    const searchResult = await handleSearch({ limit: 1 });\n    const entries = parseResult(searchResult);\n    if (entries.results.length === 0) return;\n\n    const entry = entries.results[0];\n    const lang = entry.languages?.[0];\n    await handleGet({ id: entry.id, lang });\n\n    const fetchCall = trackSpy.mock.calls.find(\n      ([event]) => event === 'doc_fetched' || event === 'skill_fetched'\n    );\n    if (fetchCall) {\n      expect(fetchCall[1]).toHaveProperty('entry_id');\n      expect(fetchCall[1]).toHaveProperty('duration_ms');\n      expect(fetchCall[1]).toHaveProperty('via', 'mcp');\n      expect(fetchCall[1]).not.toHaveProperty('error_message');\n    }\n  });\n\n  it('never sends error_message in any telemetry event', async () => {\n    trackSpy = vi.spyOn(analytics, 'trackEvent').mockResolvedValue();\n\n    // Trigger various paths\n    await handleSearch({ query: 'test' });\n    await handleGet({ id: 'nonexistent/entry-999' });\n\n    for (const [, props] of trackSpy.mock.calls) {\n      expect(props).not.toHaveProperty('error_message');\n    }\n  });\n});\n\ndescribe('chub_feedback (handleFeedback)', () => {\n  afterEach(() => {\n    delete process.env.CHUB_FEEDBACK;\n  });\n\n  it('handles feedback without throwing', async () => {\n    const result = await handleFeedback({\n      id: 'test/entry',\n      rating: 'up',\n      comment: 'test from MCP',\n    });\n    expect(result).toHaveProperty('content');\n    const data = parseResult(result);\n    expect(['sent', 'skipped', 'error']).toContain(data.status);\n  });\n\n  it('returns skipped when feedback is disabled', async () => {\n    process.env.CHUB_FEEDBACK = '0';\n    const result = await handleFeedback({ id: 'test/entry', rating: 'up' });\n    const data = parseResult(result);\n    expect(data.status).toBe('skipped');\n    expect(data.reason).toBe('feedback_disabled');\n  });\n});\n"
  },
  {
    "path": "content/accelerate/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hugging Face Accelerate for distributed PyTorch training and inference in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.13.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"accelerate,huggingface,pytorch,distributed-training,mixed-precision,fsdp,deepspeed\"\n---\n\n# accelerate Python Package Guide\n\n## What It Is\n\n`accelerate` is Hugging Face's thin orchestration layer for running mostly-standard PyTorch code across CPU, single-GPU, multi-GPU, TPU, mixed-precision, FSDP, and DeepSpeed setups without rewriting the whole training loop.\n\nUse it when you still want to own the training loop. Do not reach for it if you want a high-level trainer abstraction instead.\n\n## Version Covered\n\n- Package: `accelerate`\n- Ecosystem: `pypi`\n- Version: `1.13.0`\n- Docs root: `https://huggingface.co/docs/accelerate/`\n- Registry: `https://pypi.org/project/accelerate/`\n\n## Install\n\nInstall PyTorch first for your platform, then install `accelerate`:\n\n```bash\npip install torch accelerate\n```\n\nCommon extras from PyPI metadata:\n\n```bash\npip install \"accelerate[deepspeed]\"\npip install \"accelerate[rich]\"\npip install \"accelerate[sagemaker]\"\n```\n\nOther official install paths:\n\n```bash\nconda install -c conda-forge accelerate\npip install git+https://github.com/huggingface/accelerate\n```\n\n## Python Requirement\n\nFor `accelerate==1.13.0`, PyPI metadata requires `Python >=3.10`.\n\nVersion-sensitive note:\n- The Hugging Face install page still says Accelerate is \"tested on Python 3.8+\". For a real `1.13.0` environment, treat the PyPI requirement as authoritative and use Python 3.10+.\n\n## Core Pattern\n\nThe normal migration path is:\n\n1. Create `Accelerator()` early.\n2. Replace manual device selection with `accelerator.device` or let `prepare()` handle placement.\n3. Pass your model, optimizer, dataloaders, and schedulers through `accelerator.prepare(...)`.\n4. Replace `loss.backward()` with `accelerator.backward(loss)`.\n5. Launch the script with `accelerate launch` or `torchrun`.\n\nMinimal training script:\n\n```python\nimport torch\nfrom torch import nn\nfrom torch.utils.data import DataLoader, TensorDataset\nfrom accelerate import Accelerator\n\ndef main() -> None:\n    accelerator = Accelerator()\n\n    model = nn.Sequential(nn.Linear(16, 32), nn.ReLU(), nn.Linear(32, 2))\n    optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)\n\n    x = torch.randn(128, 16)\n    y = torch.randint(0, 2, (128,))\n    dataloader = DataLoader(TensorDataset(x, y), batch_size=8, shuffle=True)\n\n    model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)\n\n    model.train()\n    for batch_x, batch_y in dataloader:\n        optimizer.zero_grad()\n        logits = model(batch_x)\n        loss = nn.functional.cross_entropy(logits, batch_y)\n        accelerator.backward(loss)\n        optimizer.step()\n\n    accelerator.print(\"done\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## Setup And Launch\n\nInteractive config:\n\n```bash\naccelerate config\n```\n\nBarebones config:\n\n```bash\npython -c \"from accelerate.utils import write_basic_config; write_basic_config(mixed_precision='fp16')\"\n```\n\nInspect the detected environment and current config:\n\n```bash\naccelerate env\n```\n\nLaunch the script:\n\n```bash\naccelerate launch train.py --arg1 foo\n```\n\nYou can also pass launch flags directly instead of relying on a saved config:\n\n```bash\naccelerate launch --multi_gpu --num_processes 2 train.py\naccelerate launch --cpu train.py\npython -m accelerate.commands.launch --num_processes=2 train.py\n```\n\nConfig location priority from the official docs:\n\n1. `HF_HOME/accelerate`\n2. `XDG_CACHE_HOME/huggingface/accelerate`\n3. `~/.cache/huggingface/accelerate`\n\nUse `--config_file` when you need multiple launch profiles for different machines or clusters.\n\n## Common `Accelerator` Options\n\nThese are the options most likely to matter in generated code:\n\n- `mixed_precision=\"no\" | \"fp16\" | \"bf16\"` for autocast and mixed precision behavior\n- `gradient_accumulation_steps=N` for accumulation-aware backward/step coordination\n- `cpu=True` to force CPU execution\n- `log_with=...` to enable experiment trackers\n- `project_dir=\"...\"` to control local logs and checkpoint storage\n\nExample:\n\n```python\nfrom accelerate import Accelerator\n\naccelerator = Accelerator(\n    mixed_precision=\"bf16\",\n    gradient_accumulation_steps=4,\n    log_with=\"tensorboard\",\n    project_dir=\"runs/exp1\",\n)\n```\n\n## Gradient Accumulation\n\nPrefer Accelerate's accumulation helpers instead of hand-rolled modulo logic in distributed code:\n\n```python\nfrom accelerate import Accelerator\n\naccelerator = Accelerator(gradient_accumulation_steps=4)\nmodel, optimizer, dataloader, scheduler = accelerator.prepare(\n    model, optimizer, dataloader, scheduler\n)\n\nfor batch in dataloader:\n    with accelerator.accumulate(model):\n        outputs = model(batch[\"input_ids\"])\n        loss = outputs.loss\n        accelerator.backward(loss)\n        if accelerator.sync_gradients:\n            accelerator.clip_grad_norm_(model.parameters(), 1.0)\n        optimizer.step()\n        scheduler.step()\n        optimizer.zero_grad()\n```\n\nWhy this matters:\n- `Accelerator.accumulate(...)` keeps synchronization behavior aligned with distributed execution.\n- `accelerator.backward(...)` applies the right scaling behavior for the configured setup.\n\n## Distributed Evaluation And Metrics\n\nDo not compute metrics independently on each worker and then trust rank 0's local batch. Gather first:\n\n```python\npreds = accelerator.gather_for_metrics(preds)\nlabels = accelerator.gather_for_metrics(labels)\n```\n\n`gather_for_metrics()` exists specifically for metric computation across processes and handles duplicate-dropping in the last distributed batch.\n\n## Saving And Restoring\n\nFor training checkpoints that you intend to resume in the same kind of environment:\n\n```python\naccelerator.save_state(output_dir=\"checkpoints/step_1000\")\naccelerator.load_state(\"checkpoints/step_1000\")\n```\n\nFor custom stateful objects:\n\n```python\naccelerator.register_for_checkpointing(lr_scheduler)\n```\n\nFor model export or safe save patterns in distributed jobs:\n\n```python\naccelerator.wait_for_everyone()\nunwrapped_model = accelerator.unwrap_model(model)\naccelerator.save_model(unwrapped_model, \"exported-model\")\n```\n\nImportant distinction:\n- `save_state()` is for resumable training state in the same environment shape.\n- `save_model()` / model-specific `save_pretrained(...)` patterns are for exported model artifacts.\n\n## Experiment Tracking\n\nAccelerate can initialize and manage trackers from the `Accelerator` instance:\n\n```python\naccelerator = Accelerator(log_with=\"tensorboard\", project_dir=\"runs/demo\")\naccelerator.init_trackers(\"demo-project\", config={\"lr\": 1e-3, \"batch_size\": 32})\n\n# training\n\naccelerator.end_training()\n```\n\nIf you enable trackers, call `accelerator.end_training()` before process exit so tracker shutdown and process-group cleanup happen in the expected place.\n\n## Notebook Usage\n\nFor notebooks, use `notebook_launcher(...)` and create the `Accelerator` inside the launched function, not at notebook top level:\n\n```python\nfrom accelerate import Accelerator, notebook_launcher\n\ndef training_function():\n    accelerator = Accelerator(mixed_precision=\"bf16\")\n    ...\n\nnotebook_launcher(training_function, num_processes=2)\n```\n\nThis pattern matters for Colab, Kaggle, TPU, and multi-device notebook execution.\n\n## Config And Environment Notes\n\n`accelerate` itself does not use service authentication. The main configuration surface is:\n\n- the generated Accelerate launch config\n- device visibility environment variables such as `CUDA_VISIBLE_DEVICES`\n- cache location variables such as `HF_HOME` and `XDG_CACHE_HOME`\n- runtime env vars like `ACCELERATE_GRADIENT_ACCUMULATION_STEPS` and `ACCELERATE_LOG_LEVEL`\n\nIf code needs model or dataset credentials, those usually belong to other libraries such as `huggingface_hub`, not `accelerate`.\n\n## Common Pitfalls\n\n- Do not keep mixing manual `.to(device)` calls with automatic placement unless you are intentionally controlling placement yourself.\n- Do not keep `loss.backward()` after migration. Use `accelerator.backward(loss)`.\n- Do not forget the `if __name__ == \"__main__\":` guard when using `accelerate launch`.\n- Do not assume the docs page you found is stable. The docs site exposes both `main` and release versions; `main` may describe unreleased behavior that requires installation from source.\n- Do not use local per-rank tensors directly for metrics in distributed evaluation. Gather first with `gather_for_metrics()`.\n- Do not treat `save_state()` as a generic model export format.\n- If you use experiment tracking, remember `accelerator.end_training()`.\n- If you only need plain inference and no mixed precision, you may not need to `prepare()` the model at all.\n\n## Version-Sensitive Notes For `1.13.0`\n\n- `1.13.0` is on PyPI as of March 4, 2026.\n- PyPI metadata for `1.13.0` requires Python 3.10+, even though some official docs text still references Python 3.8+.\n- The Hugging Face docs UI currently exposes both `main` and `v1.13.0`. Prefer stable `v1.13.0` content for pip-installed `1.13.0`; use `main` only when you intentionally install from source.\n- The package exposes extras on PyPI including `deepspeed`, `rich`, and `sagemaker`.\n\n## Official Sources\n\n- Docs root: https://huggingface.co/docs/accelerate/\n- Installation: https://huggingface.co/docs/accelerate/basic_tutorials/install\n- Launching scripts: https://huggingface.co/docs/accelerate/en/basic_tutorials/launch\n- Accelerator reference: https://huggingface.co/docs/accelerate/main/package_reference/accelerator\n- CLI reference: https://huggingface.co/docs/accelerate/main/package_reference/cli\n- Notebook launchers: https://huggingface.co/docs/accelerate/en/package_reference/launchers\n- Troubleshooting: https://huggingface.co/docs/accelerate/en/basic_tutorials/troubleshooting\n- Gradient accumulation guide: https://huggingface.co/docs/accelerate/en/usage_guides/gradient_accumulation\n- PyPI: https://pypi.org/project/accelerate/\n- GitHub repository: https://github.com/huggingface/accelerate\n"
  },
  {
    "path": "content/aiofiles/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiofiles package guide for asyncio-friendly local file I/O in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aiofiles,asyncio,python,files,io,tempfile,threadpool\"\n---\n\n# aiofiles Python Package Guide\n\n## What It Is\n\n`aiofiles` gives `asyncio` code an async-looking interface for normal local file operations. It does not provide true kernel-level async disk I/O. Instead, it delegates blocking file and selected `os` calls to an executor so the event loop can keep running other tasks.\n\nUse it when:\n\n- your application is already async\n- you need to read or write local files without blocking unrelated coroutines\n- you want an `async with` / `await` interface close to Python's built-in file APIs\n\nDo not use it as a network storage client. For S3, HTTP, databases, or other remote backends, use the service-specific async library instead.\n\n## Installation\n\nInstall the exact version covered here:\n\n```bash\npip install aiofiles==25.1.0\n```\n\nWith modern package managers:\n\n```bash\nuv add aiofiles==25.1.0\npoetry add aiofiles==25.1.0\n```\n\n`aiofiles 25.1.0` does not support Python 3.8. If a project is pinned to Python 3.8, stay on `aiofiles 24.1.0` instead.\n\n## Initialize And Open Files\n\nThere is no service setup, authentication, or client object. Import the module and use `aiofiles.open()` in the places where synchronous code would call built-in `open()`.\n\n```python\nimport asyncio\nimport aiofiles\n\nasync def load_text(path: str) -> str:\n    async with aiofiles.open(path, \"r\", encoding=\"utf-8\") as f:\n        return await f.read()\n\nprint(asyncio.run(load_text(\"notes.txt\")))\n```\n\n`aiofiles.open()` accepts the usual `open()` arguments plus optional `loop=` and `executor=` keyword arguments. In modern code, rely on the running loop and only pass a custom executor when file work should not share the default thread pool.\n\n## Core Usage\n\n### Read And Write Text Files\n\n```python\nimport aiofiles\n\nasync def rewrite_file(src: str, dst: str) -> None:\n    async with aiofiles.open(src, \"r\", encoding=\"utf-8\") as infile:\n        text = await infile.read()\n\n    async with aiofiles.open(dst, \"w\", encoding=\"utf-8\") as outfile:\n        await outfile.write(text.upper())\n        await outfile.flush()\n```\n\n### Stream Lines With `async for`\n\n`aiofiles` file objects support async iteration, which is the cleanest way to process large text files incrementally.\n\n```python\nimport aiofiles\n\nasync def first_nonempty_line(path: str) -> str | None:\n    async with aiofiles.open(path, \"r\", encoding=\"utf-8\") as f:\n        async for line in f:\n            if line.strip():\n                return line.rstrip(\"\\n\")\n    return None\n```\n\n### Copy Binary Data In Chunks\n\n```python\nimport aiofiles\n\nCHUNK_SIZE = 1024 * 1024\n\nasync def copy_file(src: str, dst: str) -> None:\n    async with aiofiles.open(src, \"rb\") as infile:\n        async with aiofiles.open(dst, \"wb\") as outfile:\n            while chunk := await infile.read(CHUNK_SIZE):\n                await outfile.write(chunk)\n```\n\n### Use Temporary Files And Directories\n\n`aiofiles.tempfile` wraps the common `tempfile` helpers with async context managers and async file methods.\n\n```python\nimport aiofiles.tempfile\n\nasync def build_temp_payload() -> str:\n    async with aiofiles.tempfile.NamedTemporaryFile(\"w+\", encoding=\"utf-8\") as f:\n        await f.write(\"payload\\n\")\n        await f.seek(0)\n        return await f.read()\n```\n\n### Use Async Wrappers Around Selected `os` Functions\n\n`aiofiles.os` exposes async wrappers for a subset of `os` helpers such as `rename`, `replace`, `remove`, `mkdir`, `makedirs`, `stat`, `listdir`, `scandir`, `path.abspath`, and `path.getcwd`.\n\n```python\nimport aiofiles.os\n\nasync def move_into_place(tmp_path: str, final_path: str) -> None:\n    await aiofiles.os.replace(tmp_path, final_path)\n```\n\n### Handle Standard Streams\n\n`aiofiles.stdin`, `aiofiles.stdout`, and related helpers expose wrapped binary and text stdio objects when async code needs to interact with process streams using the same file-style API.\n\n```python\nimport aiofiles\n\nasync def write_status() -> None:\n    await aiofiles.stdout.write(\"ready\\n\")\n    await aiofiles.stdout.flush()\n```\n\n## Configuration And Auth\n\nThere is no auth model and no package-level configuration file.\n\nThe main choices are local I/O settings:\n\n- file mode such as `\"r\"`, `\"w\"`, `\"a\"`, `\"rb\"`, or `\"wb\"`\n- encoding and newline handling for text files\n- buffer sizing and temporary-file behavior\n- executor selection for thread-pool isolation\n\nIf file work should not compete with other threadpool tasks, pass a dedicated executor:\n\n```python\nimport asyncio\nfrom concurrent.futures import ThreadPoolExecutor\n\nimport aiofiles\n\nfile_pool = ThreadPoolExecutor(max_workers=4)\n\nasync def read_with_custom_pool(path: str) -> str:\n    async with aiofiles.open(path, \"r\", encoding=\"utf-8\", executor=file_pool) as f:\n        return await f.read()\n\ntry:\n    print(asyncio.run(read_with_custom_pool(\"example.txt\")))\nfinally:\n    file_pool.shutdown(wait=True)\n```\n\n## Common Pitfalls\n\n- `aiofiles` still uses blocking file APIs under the hood. It avoids blocking the event loop by moving that work into an executor.\n- Always `await` methods like `read()`, `write()`, `seek()`, `flush()`, and `close()`. The wrapped file object is not interchangeable with a normal synchronous file handle.\n- Prefer `async with` so files close correctly on errors and cancellations.\n- Be explicit about text vs binary mode. The same type and encoding mistakes from built-in `open()` still apply.\n- High concurrency can saturate the default executor. If file throughput matters, consider a separate `ThreadPoolExecutor`.\n- `aiofiles.os` covers only selected functions. Check the current README before assuming a specific `os` or `os.path` helper exists.\n- When unit testing, patch `aiofiles.threadpool.sync_open` or use the library's wrapping helpers instead of mocking `aiofiles.open()` like a normal synchronous file factory.\n\n## Version-Sensitive Notes\n\n- The version used here and the current covered version are both `25.1.0`.\n- PyPI lists `25.1.0` as released on `2025-10-09`.\n- `25.1.0` requires Python `>=3.9` and adds support for Python 3.14.\n- If a project still needs Python 3.8, use `aiofiles 24.1.0` instead of upgrading.\n- For long-lived internal docs or ingestion work, prefer the tagged `v25.1.0` sources over `main` when you need version-stable examples.\n\n## Official Sources\n\n- Repository: https://github.com/Tinche/aiofiles\n- Tagged README for `25.1.0`: https://github.com/Tinche/aiofiles/blob/v25.1.0/README.md\n- PyPI project page: https://pypi.org/project/aiofiles/\n- PyPI release page for `25.1.0`: https://pypi.org/project/aiofiles/25.1.0/\n- PyPI version metadata JSON: https://pypi.org/pypi/aiofiles/25.1.0/json\n- GitHub release for `v25.1.0`: https://github.com/Tinche/aiofiles/releases/tag/v25.1.0\n"
  },
  {
    "path": "content/aiohttp/docs/cors/python/DOC.md",
    "content": "---\nname: cors\ndescription: \"aiohttp-cors package guide for adding CORS policies to aiohttp.web apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aiohttp-cors,aiohttp,cors,http,asyncio,python,web\"\n---\n\n# aiohttp-cors Python Package Guide\n\n## Golden Rule\n\nUse `aiohttp-cors` only to express browser CORS policy for `aiohttp.web` routes and resources. It does not replace your app's authentication, authorization, CSRF protection, or normal request validation.\n\n## Install\n\n```bash\npip install aiohttp-cors==0.8.1\n```\n\nBase imports:\n\n```python\nfrom aiohttp import web\nimport aiohttp_cors\n```\n\n## Setup Pattern\n\nCreate the `aiohttp.web.Application`, initialize CORS once with `aiohttp_cors.setup(...)`, then wrap the routes or resources that should emit CORS headers.\n\n```python\nfrom aiohttp import web\nimport aiohttp_cors\n\nasync def health(request: web.Request) -> web.Response:\n    return web.json_response({\"ok\": True})\n\napp = web.Application()\n\ncors = aiohttp_cors.setup(\n    app,\n    defaults={\n        \"https://app.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            expose_headers=(\"X-Request-Id\",),\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            max_age=3600,\n        )\n    },\n)\n\nroute = app.router.add_get(\"/health\", health)\ncors.add(route)\n\nweb.run_app(app)\n```\n\nImportant behavior:\n\n- `setup()` alone does not change any route behavior.\n- A route must be passed to `cors.add(route)` or attached via a resource/view pattern.\n- `defaults=` is only applied to wrapped routes and resources.\n\n## Core Usage\n\n### Add CORS To A Route\n\nUse route-level wrapping when one endpoint has its own policy.\n\n```python\nasync def create_item(request: web.Request) -> web.Response:\n    return web.json_response({\"created\": True}, status=201)\n\nroute = app.router.add_post(\"/items\", create_item)\n\ncors.add(\n    route,\n    {\n        \"https://console.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            expose_headers=(\"Location\",),\n            allow_methods=(\"POST\",),\n        )\n    },\n)\n```\n\n### Add CORS To A Resource\n\nWhen multiple methods share one path, resource-level wrapping is usually cleaner.\n\n```python\nresource = app.router.add_resource(\"/items\")\nresource.add_route(\"GET\", list_items)\nresource.add_route(\"POST\", create_item)\n\ncors.add(\n    resource,\n    {\n        \"https://app.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            allow_methods=(\"GET\", \"POST\"),\n        )\n    },\n)\n```\n\n### Apply One Policy To Many Existing Routes\n\nThe maintainer README shows iterating over registered routes after setup:\n\n```python\nfor route in list(app.router.routes()):\n    cors.add(route)\n```\n\nThis is useful when you want one default policy on most of the app and only a few explicit overrides.\n\n## Class-Based Views And Custom Preflight\n\nThe maintainer README includes a `web.View` pattern for wildcard-style class-based views. Use `aiohttp_cors.CorsViewMixin` and register the route with `webview=True`.\n\n```python\nfrom aiohttp import hdrs, web\nimport aiohttp_cors\n\nclass UserView(web.View, aiohttp_cors.CorsViewMixin):\n    async def get(self) -> web.StreamResponse:\n        return web.json_response({\"method\": \"GET\"})\n\n    @aiohttp_cors.custom_cors(\n        hdrs.METH_OPTIONS,\n        allow_headers=(\"Content-Type\", \"Authorization\"),\n        expose_headers=(\"X-Request-Id\",),\n        allow_credentials=True,\n        max_age=600,\n    )\n    async def options(self) -> web.StreamResponse:\n        return web.Response(status=200)\n\napp.router.add_route(\"*\", \"/users\", UserView, name=\"users\", webview=True)\n```\n\nUse this only when you specifically need a class-based view with custom `OPTIONS` handling. For normal handlers, explicit route or resource registration is simpler.\n\n## Config And Auth Notes\n\n`aiohttp_cors.ResourceOptions(...)` is the main place where browser-facing policy is defined.\n\nCommon fields used in maintainer examples:\n\n- `allow_credentials=True` lets browsers send cookies or auth headers cross-origin when the frontend and backend policy allows it.\n- `allow_headers=(...)` lists request headers the browser may send.\n- `expose_headers=(...)` lists response headers browser JavaScript may read.\n- `allow_methods=(...)` narrows the allowed HTTP methods when you want stricter policy than the route definitions alone.\n- `max_age=...` controls how long the preflight response may be cached.\n\nPractical guidance:\n\n- Prefer explicit origins like `https://app.example.com` in production.\n- Treat `\"*\"` as a deliberate relaxation for controlled cases, not a default production policy.\n- Keep your actual auth and permission checks in middleware, handlers, or upstream infrastructure.\n\n## Common Pitfalls\n\n### Forgetting To Wrap The Route\n\nThis does not enable CORS by itself:\n\n```python\napp = web.Application()\ncors = aiohttp_cors.setup(app)\napp.router.add_get(\"/items\", list_items)\n```\n\nYou still need:\n\n```python\nroute = app.router.add_get(\"/items\", list_items)\ncors.add(route)\n```\n\n### Assuming Wildcard Handlers Work Automatically\n\nThe maintainer README calls out an `aiohttp` limitation around wildcard handlers such as `app.router.add_route(\"*\", ...)`. If you need that shape, use the documented `CorsViewMixin` plus `webview=True` pattern instead of assuming normal route wrapping will work.\n\n### Copying Historical Coroutine Syntax Verbatim\n\nThe upstream README still includes older `@asyncio.coroutine` examples. In modern Python code, translate those examples to `async def` handlers and `await` syntax.\n\n### Treating CORS As Security By Itself\n\nCORS controls what browsers may do with cross-origin requests. It does not make an endpoint safe to expose.\n\n## Version-Sensitive Notes For 0.8.1\n\n- PyPI marks `0.8.1` as released on `2025-03-31`.\n- PyPI release history marks `0.8.0` as yanked. The yank reason says it \"installed on Python 3.8, but wasn't compatible with it.\"\n- The maintainer changelog says `0.8.0` added compatibility with `aiohttp 3.9+` and `python 3.9+`.\n- The maintainer changelog says `0.8.1` fixed the packaging error so the project no longer installs on Python `3.8`.\n- Inference: use `aiohttp-cors 0.8.1` only on Python `3.9+` projects running a supported `aiohttp 3.9+` line.\n\n## Official Sources\n\n- Repository: https://github.com/aio-libs/aiohttp-cors\n- README: https://github.com/aio-libs/aiohttp-cors/blob/master/README.rst\n- Versioned changelog entry: https://github.com/aio-libs/aiohttp-cors/blob/v0.8.1/CHANGES.rst\n- PyPI project page: https://pypi.org/project/aiohttp-cors/\n- PyPI release page for `0.8.1`: https://pypi.org/project/aiohttp-cors/0.8.1/\n"
  },
  {
    "path": "content/aiohttp/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiohttp package guide for Python - async HTTP client/server, web apps, and websockets\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.13.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aiohttp,python,asyncio,http,web,websocket,client,server\"\n---\n\n# aiohttp Python Package Guide\n\n## Golden Rule\n\nUse `aiohttp` when a Python project needs async HTTP client calls, an asyncio-native web server, or both. Keep `ClientSession` and `web.Application` lifecycle-bound to the active event loop. Do not create sessions at module import time or per request.\n\n## Install\n\n```bash\npip install aiohttp==3.13.3\n```\n\nOptional speedups from the official docs:\n\n```bash\npip install \"aiohttp[speedups]\"\n```\n\nThat bundle pulls in extras such as `aiodns` for faster DNS resolution and Brotli support for compressed client responses.\n\n## Choose The Surface\n\n- Use `aiohttp.ClientSession` for outbound async HTTP requests.\n- Use `aiohttp.web` for an asyncio-native HTTP server.\n- Use `session.ws_connect()` or `web.WebSocketResponse()` for WebSockets.\n- Use one long-lived session per app or per upstream service, not one per request.\n\n## Client: Minimal Request Flow\n\n```python\nimport asyncio\nimport aiohttp\n\nasync def main() -> None:\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"https://httpbin.org/get\") as resp:\n            resp.raise_for_status()\n            data = await resp.json()\n            print(resp.status, data[\"url\"])\n\nasyncio.run(main())\n```\n\n## Client: Recommended Session Setup\n\nUse a shared session with explicit timeouts, headers, and connector limits.\n\n```python\nimport asyncio\nimport ssl\n\nimport aiohttp\n\nasync def main() -> None:\n    timeout = aiohttp.ClientTimeout(total=60, connect=10, sock_read=30)\n    ssl_context = ssl.create_default_context()\n    connector = aiohttp.TCPConnector(limit=100, limit_per_host=20, ssl=ssl_context)\n\n    async with aiohttp.ClientSession(\n        base_url=\"https://api.example.com/\",\n        headers={\"Accept\": \"application/json\"},\n        raise_for_status=True,\n        timeout=timeout,\n        connector=connector,\n    ) as session:\n        async with session.get(\"v1/items\", params={\"limit\": 50}) as resp:\n            items = await resp.json()\n            print(items)\n\nasyncio.run(main())\n```\n\nNotes:\n\n- If `base_url` includes a path, it must end with `/`.\n- Relative request paths without a leading slash join onto `base_url` as expected.\n- Default total timeout is 300 seconds, with a 30 second socket connect timeout.\n- `raise_for_status=True` on the session is a good default for API clients.\n\n## Client: JSON, Streaming, Uploads\n\nJSON request/response:\n\n```python\nasync with session.post(\"/v1/jobs\", json={\"name\": \"build\"}) as resp:\n    job = await resp.json()\n```\n\nLarge downloads should stream instead of calling `text()`, `read()`, or `json()`:\n\n```python\nasync with session.get(\"/large-export\") as resp:\n    resp.raise_for_status()\n    with open(\"export.bin\", \"wb\") as f:\n        async for chunk in resp.content.iter_chunked(64 * 1024):\n            f.write(chunk)\n```\n\nLarge uploads can stream file objects or async generators:\n\n```python\nwith open(\"report.csv\", \"rb\") as f:\n    async with session.post(\"/upload\", data=f) as resp:\n        resp.raise_for_status()\n```\n\nPitfall: once you consume `resp.content` manually, do not call `resp.text()`, `resp.read()`, or `resp.json()` afterward.\n\n## Client: Auth, Proxies, Cookies, SSL\n\nBasic auth:\n\n```python\nfrom aiohttp import BasicAuth\n\nasync with aiohttp.ClientSession(\n    auth=BasicAuth(login=\"user\", password=\"pass\")\n) as session:\n    async with session.get(\"https://example.com/protected\") as resp:\n        print(resp.status)\n```\n\nDigest auth in `3.13.3` uses client middleware:\n\n```python\nfrom aiohttp import ClientSession, DigestAuthMiddleware\n\ndigest_auth = DigestAuthMiddleware(login=\"user\", password=\"pass\")\n\nasync with ClientSession(middlewares=(digest_auth,)) as session:\n    async with session.get(\"https://example.com/protected\") as resp:\n        print(await resp.text())\n```\n\nProxy configuration:\n\n```python\nproxy_auth = aiohttp.BasicAuth(\"proxy-user\", \"proxy-pass\")\n\nasync with aiohttp.ClientSession(\n    proxy=\"http://proxy.internal:8080\",\n    proxy_auth=proxy_auth,\n) as session:\n    async with session.get(\"http://python.org\") as resp:\n        print(resp.status)\n```\n\nEnvironment proxy variables are ignored unless you opt in:\n\n```python\nasync with aiohttp.ClientSession(trust_env=True) as session:\n    ...\n```\n\nCookie control:\n\n```python\njar = aiohttp.DummyCookieJar()\nasync with aiohttp.ClientSession(cookie_jar=jar) as session:\n    ...\n```\n\nSSL guidance:\n\n- Default HTTPS verification is strict. Keep it on in production.\n- Prefer a custom `ssl.SSLContext` for private CAs or client certs.\n- `ssl=False` disables certificate checks and should be limited to controlled local/dev cases.\n\n## Client WebSockets\n\n```python\nasync with aiohttp.ClientSession() as session:\n    async with session.ws_connect(\"wss://example.com/ws\") as ws:\n        await ws.send_json({\"type\": \"hello\"})\n        async for msg in ws:\n            if msg.type == aiohttp.WSMsgType.TEXT:\n                print(msg.data)\n            elif msg.type == aiohttp.WSMsgType.ERROR:\n                break\n```\n\nKeep one reader task for a websocket. Multiple tasks can send, but reads should stay serialized through the handler task or one dedicated reader.\n\n## Server: Minimal App\n\n```python\nfrom aiohttp import web\n\nasync def hello(request: web.Request) -> web.Response:\n    return web.json_response({\"message\": \"hello\"})\n\napp = web.Application()\napp.add_routes([web.get(\"/\", hello)])\n\nif __name__ == \"__main__\":\n    web.run_app(app)\n```\n\nAlternative route style:\n\n```python\nfrom aiohttp import web\n\nroutes = web.RouteTableDef()\n\n@routes.get(\"/users/{user_id}\", name=\"user-detail\")\nasync def get_user(request: web.Request) -> web.Response:\n    return web.json_response({\"user_id\": request.match_info[\"user_id\"]})\n\napp = web.Application()\napp.add_routes(routes)\n```\n\nNamed routes can be reversed with `request.app.router[\"user-detail\"].url_for(...)`.\n\n## Server: Shared State And Lifecycle\n\nUse `AppKey` instead of string keys when storing typed app state:\n\n```python\nfrom aiohttp import ClientSession, web\n\nhttp_client_key = web.AppKey(\"http_client\", ClientSession)\n```\n\nPrefer `cleanup_ctx` for paired startup/teardown resources:\n\n```python\nimport aiohttp\nfrom aiohttp import web\n\nhttp_client_key = web.AppKey(\"http_client\", aiohttp.ClientSession)\n\nasync def http_client_ctx(app: web.Application):\n    app[http_client_key] = aiohttp.ClientSession(\n        timeout=aiohttp.ClientTimeout(total=30)\n    )\n    yield\n    await app[http_client_key].close()\n\nasync def health(request: web.Request) -> web.Response:\n    session = request.app[http_client_key]\n    async with session.get(\"https://httpbin.org/status/200\") as resp:\n        return web.json_response({\"upstream\": resp.status})\n\napp = web.Application()\napp.cleanup_ctx.append(http_client_ctx)\napp.add_routes([web.get(\"/health\", health)])\nweb.run_app(app)\n```\n\nWhy `cleanup_ctx` matters:\n\n- It pairs setup and teardown in one async generator.\n- Cleanup only runs for resources that actually initialized.\n- It is safer than separate `on_startup` and `on_cleanup` handlers for dependent resources.\n\n## Server: Middleware And Background Tasks\n\nMiddleware shape:\n\n```python\nfrom aiohttp import web\n\n@web.middleware\nasync def auth_middleware(request: web.Request, handler):\n    token = request.headers.get(\"Authorization\")\n    if token != \"Bearer dev-token\":\n        raise web.HTTPUnauthorized()\n    return await handler(request)\n\napp = web.Application(middlewares=[auth_middleware])\n```\n\nThe second middleware parameter should be named `handler` exactly.\n\nFor long-lived background tasks, attach them to app lifecycle:\n\n```python\nimport asyncio\nimport contextlib\nfrom aiohttp import web\n\nlistener_key = web.AppKey(\"listener\", asyncio.Task)\n\nasync def background(app: web.Application):\n    app[listener_key] = asyncio.create_task(asyncio.sleep(3600))\n    yield\n    app[listener_key].cancel()\n    with contextlib.suppress(asyncio.CancelledError):\n        await app[listener_key]\n\napp = web.Application()\napp.cleanup_ctx.append(background)\n```\n\nIf you need asynchronous startup without blocking `web.run_app()`, use `web.AppRunner` and `web.TCPSite`.\n\n## Server WebSockets\n\n```python\nfrom aiohttp import web\n\nasync def websocket_handler(request: web.Request) -> web.WebSocketResponse:\n    ws = web.WebSocketResponse()\n    await ws.prepare(request)\n\n    async for msg in ws:\n        if msg.type == web.WSMsgType.TEXT:\n            await ws.send_str(f\"echo:{msg.data}\")\n        elif msg.type == web.WSMsgType.ERROR:\n            break\n\n    return ws\n```\n\nRules that matter:\n\n- Only one task should read from a given `WebSocketResponse`.\n- Other tasks may send on that websocket.\n- For graceful shutdown, track open websockets in app state and close them from an `on_shutdown` handler.\n\n## Common Pitfalls\n\n- Creating `ClientSession()` at import time or as a class variable can bind it to the wrong event loop and cause hangs.\n- Creating a new session per request defeats connection pooling and adds overhead.\n- Forgetting to close sessions leaves unclosed connector warnings and leaked sockets.\n- Assuming proxy env vars are honored by default. They are not unless `trust_env=True`.\n- Using `ssl=False` as a general fix for TLS problems. Install the right CA or configure an `SSLContext` instead.\n- Trusting `Forwarded` or `X-Forwarded-*` headers automatically on the server side. `aiohttp.web` ignores them by default for security; only apply them in trusted reverse-proxy middleware.\n- Reusing the same `web.Response` object across requests is invalid. Response objects are one-request objects.\n- Reading from the same websocket in parallel from multiple tasks is forbidden.\n\n## Version-Sensitive Notes For 3.13.3\n\n- `3.13.3` is the current stable docs version and the PyPI latest release as of `2026-03-11`.\n- The `3.13.3` changelog states this release fixes several vulnerabilities and recommends upgrading promptly.\n- Client middlewares on `ClientSession` are available in `3.12+`. Older examples that rely on them will not work on earlier `aiohttp` releases.\n- `ClientSession(base_url=...)` gained absolute-URL override support in `3.12`.\n- `ssl_shutdown_timeout` is deprecated and scheduled for removal in `aiohttp 4.0`; avoid building new code around it.\n\n## Official Sources\n\n- Docs root: https://docs.aiohttp.org/en/stable/\n- Client quickstart: https://docs.aiohttp.org/en/stable/client_quickstart.html\n- Advanced client usage: https://docs.aiohttp.org/en/stable/client_advanced.html\n- Client reference: https://docs.aiohttp.org/en/stable/client_reference.html\n- Web server quickstart: https://docs.aiohttp.org/en/stable/web_quickstart.html\n- Web server advanced: https://docs.aiohttp.org/en/stable/web_advanced.html\n- FAQ: https://docs.aiohttp.org/en/stable/faq.html\n- Changelog: https://docs.aiohttp.org/en/stable/changes.html\n- PyPI: https://pypi.org/project/aiohttp/\n"
  },
  {
    "path": "content/aiohttp-cors/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiohttp-cors package guide for adding CORS policies to aiohttp.web apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aiohttp-cors,aiohttp,cors,http,asyncio,python,web\"\n---\n\n# aiohttp-cors Python Package Guide\n\n## Golden Rule\n\nUse `aiohttp-cors` only to express browser CORS policy for `aiohttp.web` routes and resources. It does not replace your app's authentication, authorization, CSRF protection, or normal request validation.\n\n## Install\n\n```bash\npip install aiohttp-cors==0.8.1\n```\n\nBase imports:\n\n```python\nfrom aiohttp import web\nimport aiohttp_cors\n```\n\n## Setup Pattern\n\nCreate the `aiohttp.web.Application`, initialize CORS once with `aiohttp_cors.setup(...)`, then wrap the routes or resources that should emit CORS headers.\n\n```python\nfrom aiohttp import web\nimport aiohttp_cors\n\nasync def health(request: web.Request) -> web.Response:\n    return web.json_response({\"ok\": True})\n\napp = web.Application()\n\ncors = aiohttp_cors.setup(\n    app,\n    defaults={\n        \"https://app.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            expose_headers=(\"X-Request-Id\",),\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            max_age=3600,\n        )\n    },\n)\n\nroute = app.router.add_get(\"/health\", health)\ncors.add(route)\n\nweb.run_app(app)\n```\n\nImportant behavior:\n\n- `setup()` alone does not change any route behavior.\n- A route must be passed to `cors.add(route)` or attached via a resource/view pattern.\n- `defaults=` is only applied to wrapped routes and resources.\n\n## Core Usage\n\n### Add CORS To A Route\n\nUse route-level wrapping when one endpoint has its own policy.\n\n```python\nasync def create_item(request: web.Request) -> web.Response:\n    return web.json_response({\"created\": True}, status=201)\n\nroute = app.router.add_post(\"/items\", create_item)\n\ncors.add(\n    route,\n    {\n        \"https://console.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            expose_headers=(\"Location\",),\n            allow_methods=(\"POST\",),\n        )\n    },\n)\n```\n\n### Add CORS To A Resource\n\nWhen multiple methods share one path, resource-level wrapping is usually cleaner.\n\n```python\nasync def list_items(request: web.Request) -> web.Response:\n    return web.json_response({\"items\": []})\n\nasync def create_item(request: web.Request) -> web.Response:\n    return web.json_response({\"created\": True}, status=201)\n\nresource = app.router.add_resource(\"/items\")\nresource.add_route(\"GET\", list_items)\nresource.add_route(\"POST\", create_item)\n\ncors.add(\n    resource,\n    {\n        \"https://app.example.com\": aiohttp_cors.ResourceOptions(\n            allow_credentials=True,\n            allow_headers=(\"Authorization\", \"Content-Type\"),\n            allow_methods=(\"GET\", \"POST\"),\n        )\n    },\n)\n```\n\n### Apply One Policy To Many Existing Routes\n\nThe maintainer README shows iterating over registered routes after setup:\n\n```python\nfor route in list(app.router.routes()):\n    cors.add(route)\n```\n\nThis is useful when you want one default policy on most of the app and only a few explicit overrides.\n\n## Class-Based Views And Custom Preflight\n\nThe maintainer README includes a `web.View` pattern for wildcard-style class-based views. Use `aiohttp_cors.CorsViewMixin` and register the route with `webview=True`.\n\n```python\nfrom aiohttp import hdrs, web\nimport aiohttp_cors\n\nclass UserView(web.View, aiohttp_cors.CorsViewMixin):\n    async def get(self) -> web.StreamResponse:\n        return web.json_response({\"method\": \"GET\"})\n\n    @aiohttp_cors.custom_cors(\n        hdrs.METH_OPTIONS,\n        allow_headers=(\"Content-Type\", \"Authorization\"),\n        expose_headers=(\"X-Request-Id\",),\n        allow_credentials=True,\n        max_age=600,\n    )\n    async def options(self) -> web.StreamResponse:\n        return web.Response(status=200)\n\napp.router.add_route(\"*\", \"/users\", UserView, name=\"users\", webview=True)\n```\n\nUse this only when you specifically need a class-based view with custom `OPTIONS` handling. For normal handlers, explicit route or resource registration is simpler.\n\n## Config And Auth Notes\n\n`aiohttp_cors.ResourceOptions(...)` is the main place where browser-facing policy is defined.\n\nThe library does not use environment variables, API keys, or its own auth client. Any auth configuration stays in your `aiohttp` app, middleware, session handling, or upstream proxy.\n\nCommon fields used in maintainer examples:\n\n- `allow_credentials=True` lets browsers send cookies or auth headers cross-origin when the frontend and backend policy allows it.\n- `allow_headers=(...)` lists request headers the browser may send.\n- `expose_headers=(...)` lists response headers browser JavaScript may read.\n- `allow_methods=(...)` narrows the allowed HTTP methods when you want stricter policy than the route definitions alone.\n- `max_age=...` controls how long the preflight response may be cached.\n\nPractical guidance:\n\n- Prefer explicit origins like `https://app.example.com` in production.\n- Treat `\"*\"` as a deliberate relaxation for controlled cases, not a default production policy.\n- Keep your actual auth and permission checks in middleware, handlers, or upstream infrastructure.\n\n## Common Pitfalls\n\n### Forgetting To Wrap The Route\n\nThis does not enable CORS by itself:\n\n```python\nasync def list_items(request: web.Request) -> web.Response:\n    return web.json_response({\"items\": []})\n\napp = web.Application()\ncors = aiohttp_cors.setup(app)\napp.router.add_get(\"/items\", list_items)\n```\n\nYou still need:\n\n```python\nroute = app.router.add_get(\"/items\", list_items)\ncors.add(route)\n```\n\n### Assuming Wildcard Handlers Work Automatically\n\nThe maintainer README calls out an `aiohttp` limitation around wildcard handlers such as `app.router.add_route(\"*\", ...)`. If you need that shape, use the documented `CorsViewMixin` plus `webview=True` pattern instead of assuming normal route wrapping will work.\n\n### Copying Historical Coroutine Syntax Verbatim\n\nThe upstream README still includes older `@asyncio.coroutine` examples. In modern Python code, translate those examples to `async def` handlers and `await` syntax.\n\n### Treating CORS As Security By Itself\n\nCORS controls what browsers may do with cross-origin requests. It does not make an endpoint safe to expose.\n\n## Version-Sensitive Notes For 0.8.1\n\n- PyPI marks `0.8.1` as released on `2025-03-31`.\n- PyPI release history marks `0.8.0` as yanked. The yank reason says it \"installed on Python 3.8, but wasn't compatible with it.\"\n- The maintainer changelog says `0.8.0` added compatibility with `aiohttp 3.9+` and `python 3.9+`.\n- The maintainer changelog says `0.8.1` fixed the packaging error so the project no longer installs on Python `3.8`.\n- Use `aiohttp-cors 0.8.1` on Python `3.9+` projects running a supported `aiohttp 3.9+` line.\n\n## Official Sources\n\n- Repository: https://github.com/aio-libs/aiohttp-cors\n- README: https://github.com/aio-libs/aiohttp-cors/blob/master/README.rst\n- Versioned changelog entry: https://github.com/aio-libs/aiohttp-cors/blob/v0.8.1/CHANGES.rst\n- PyPI project page: https://pypi.org/project/aiohttp-cors/\n- PyPI release page for `0.8.1`: https://pypi.org/project/aiohttp-cors/0.8.1/\n"
  },
  {
    "path": "content/aiomysql/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiomysql package guide for asyncio-based MySQL and MariaDB access in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aiomysql,mysql,mariadb,asyncio,database,sql\"\n---\n\n# aiomysql Python Package Guide\n\n## Golden Rule\n\nUse `aiomysql` when you need direct asyncio access to MySQL or MariaDB with a PyMySQL-like API. Prefer a connection pool for application code, assume writes are not autocommitted unless you enable it, and close pooled resources with `pool.close()` plus `await pool.wait_closed()`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"aiomysql==0.3.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"aiomysql==0.3.2\"\npoetry add \"aiomysql==0.3.2\"\n```\n\nNotes:\n\n- `aiomysql` depends on `PyMySQL`; you do not install a separate MySQL C driver for the basic package.\n- PyPI metadata exposes optional extras `sa` and `rsa`. Use them only when you specifically need the SQLAlchemy integration layer or RSA auth-related dependencies.\n\n## Connect And Create A Pool\n\nFor application code, start with a pool instead of one ad hoc connection:\n\n```python\nimport asyncio\nimport os\n\nimport aiomysql\n\nasync def main() -> None:\n    pool = await aiomysql.create_pool(\n        host=os.environ.get(\"MYSQL_HOST\", \"127.0.0.1\"),\n        port=int(os.environ.get(\"MYSQL_PORT\", \"3306\")),\n        user=os.environ[\"MYSQL_USER\"],\n        password=os.environ[\"MYSQL_PASSWORD\"],\n        db=os.environ[\"MYSQL_DATABASE\"],\n        minsize=1,\n        maxsize=10,\n        autocommit=False,\n        pool_recycle=3600,\n        charset=\"utf8mb4\",\n    )\n\n    try:\n        async with pool.acquire() as conn:\n            async with conn.cursor(aiomysql.DictCursor) as cur:\n                await cur.execute(\"SELECT VERSION() AS version\")\n                row = await cur.fetchone()\n                print(row[\"version\"])\n    finally:\n        pool.close()\n        await pool.wait_closed()\n\nasyncio.run(main())\n```\n\nWhy these settings matter:\n\n- `autocommit=False` is the documented default, so inserts and updates need an explicit `await conn.commit()`.\n- `pool_recycle` helps avoid stale server-side connections in long-running processes.\n- `charset=\"utf8mb4\"` is the safer default for modern Unicode text than leaving the charset empty.\n\nFor short scripts or migrations, a single connection is fine:\n\n```python\nimport asyncio\nimport aiomysql\n\nasync def main() -> None:\n    conn = await aiomysql.connect(\n        host=\"127.0.0.1\",\n        port=3306,\n        user=\"app\",\n        password=\"secret\",\n        db=\"appdb\",\n        autocommit=True,\n        charset=\"utf8mb4\",\n    )\n\n    try:\n        async with conn.cursor() as cur:\n            await cur.execute(\"SELECT 1\")\n            print(await cur.fetchone())\n    finally:\n        await conn.ensure_closed()\n\nasyncio.run(main())\n```\n\n## Core Usage\n\n### Run queries\n\n```python\nasync with pool.acquire() as conn:\n    async with conn.cursor(aiomysql.DictCursor) as cur:\n        await cur.execute(\n            \"\"\"\n            SELECT id, email\n            FROM users\n            WHERE is_active = %s\n            ORDER BY id\n            LIMIT %s\n            \"\"\",\n            (True, 100),\n        )\n        rows = await cur.fetchall()\n\nfor row in rows:\n    print(row[\"id\"], row[\"email\"])\n```\n\nUse parameter binding with `%s` placeholders. Do not build SQL by concatenating user input.\n\n### Transactions\n\nBecause autocommit is off by default, explicit commit and rollback handling matters:\n\n```python\nasync with pool.acquire() as conn:\n    try:\n        async with conn.cursor() as cur:\n            await cur.execute(\n                \"INSERT INTO audit_log(event_type, payload) VALUES (%s, %s)\",\n                (\"user.created\", '{\"user_id\": 42}'),\n            )\n        await conn.commit()\n    except Exception:\n        await conn.rollback()\n        raise\n```\n\nIf you want each statement committed immediately, set `autocommit=True` on the connection or pool.\n\n### Batch inserts\n\n`executemany()` batches inserts using MySQL multi-row syntax:\n\n```python\nrecords = [\n    (\"Jane\", \"555-001\"),\n    (\"Joe\", \"555-002\"),\n    (\"John\", \"555-003\"),\n]\n\nasync with pool.acquire() as conn:\n    async with conn.cursor() as cur:\n        await cur.executemany(\n            \"INSERT INTO employees(name, phone) VALUES (%s, %s)\",\n            records,\n        )\n    await conn.commit()\n```\n\n### Large result sets\n\nUse `SSCursor` or `SSDictCursor` when you need to stream a lot of rows with lower memory usage:\n\n```python\nasync with pool.acquire() as conn:\n    async with conn.cursor(aiomysql.SSDictCursor) as cur:\n        await cur.execute(\"SELECT id, payload FROM events ORDER BY id\")\n        while True:\n            rows = await cur.fetchmany(1000)\n            if not rows:\n                break\n            for row in rows:\n                process(row)\n```\n\n`SSCursor` is unbuffered. The docs note that row counts are not known up front and backward scrolling is not supported.\n\n### Stored procedures\n\n`callproc()` works, but the docs call out two important DB-API quirks:\n\n- OUT and INOUT values are not returned directly; you may need to query server variables such as `@_procname_0` after consuming result sets.\n- Stored procedure calls create an extra empty result set, so use `await cur.nextset()` until all result sets are consumed.\n\n## Configuration And Authentication\n\nImportant `connect()` parameters from the official API reference:\n\n- `host`, `port`, `db`, `user`, `password`: standard TCP connection settings\n- `unix_socket`: use a local Unix domain socket instead of TCP when appropriate\n- `charset`: character set for the session\n- `sql_mode`: session SQL mode such as `STRICT_TRANS_TABLES`\n- `connect_timeout`: timeout in seconds for the initial connection\n- `init_command`: SQL command to run immediately after connection setup\n- `read_default_file` and `read_default_group`: read client settings from a MySQL option file\n- `cursorclass`: set a default cursor type such as `aiomysql.DictCursor`\n- `ssl`: pass an `ssl.SSLContext` to require TLS\n- `auth_plugin`: manually choose an auth plugin when needed, for example `mysql_clear_password` for Amazon RDS IAM authentication\n- `server_public_key`: public key for SHA256 authentication flows\n- `program_name`: client program name sent during handshake\n- `local_infile`: enable `LOAD DATA LOCAL`; disabled by default and unsafe against untrusted servers\n\nExample with TLS and explicit auth plugin:\n\n```python\nimport asyncio\nimport ssl\n\nimport aiomysql\n\nasync def main() -> None:\n    tls = ssl.create_default_context(cafile=\"/path/to/ca.pem\")\n\n    conn = await aiomysql.connect(\n        host=\"db.example.com\",\n        user=\"app\",\n        password=\"secret\",\n        db=\"appdb\",\n        ssl=tls,\n        auth_plugin=\"mysql_clear_password\",\n        autocommit=True,\n    )\n\n    try:\n        async with conn.cursor() as cur:\n            await cur.execute(\"SELECT CURRENT_USER()\")\n            print(await cur.fetchone())\n    finally:\n        await conn.ensure_closed()\n\nasyncio.run(main())\n```\n\n## SQLAlchemy Integration\n\n`aiomysql.sa` is the package's official SQLAlchemy integration layer:\n\n```python\nimport asyncio\nimport sqlalchemy as sa\nfrom aiomysql.sa import create_engine\n\nmetadata = sa.MetaData()\nusers = sa.Table(\n    \"users\",\n    metadata,\n    sa.Column(\"id\", sa.Integer, primary_key=True),\n    sa.Column(\"email\", sa.String(255)),\n)\n\nasync def main() -> None:\n    engine = await create_engine(\n        host=\"127.0.0.1\",\n        user=\"app\",\n        password=\"secret\",\n        db=\"appdb\",\n    )\n\n    try:\n        async with engine.acquire() as conn:\n            result = await conn.execute(users.select())\n            async for row in result:\n                print(row.id, row.email)\n    finally:\n        engine.close()\n        await engine.wait_closed()\n\nasyncio.run(main())\n```\n\nThe official docs describe this as support for SQLAlchemy's functional SQL layer. Treat it as a separate API surface from the raw connection and cursor API.\n\n## Common Pitfalls\n\n- `pool.close()` and `pool.terminate()` are not coroutines. Call them directly, then `await pool.wait_closed()`.\n- `conn.close()` closes immediately and is not a coroutine; `await conn.ensure_closed()` sends a quit command and then closes the socket.\n- The upstream docs still show older `loop=...` examples. For new Python 3.9+ code, prefer `asyncio.run(...)` and omit `loop=` unless you are integrating with older event-loop management. This is an inference from the current docs still exposing optional `loop` parameters while also showing modern `asyncio.run()` examples in the README and `aiomysql.sa` docs.\n- `autocommit=False` is the default. If inserts \"work\" but nothing is persisted, you probably forgot `await conn.commit()`.\n- Leave `local_infile=False` unless you explicitly need `LOAD DATA LOCAL` and trust the server; the docs warn that aiomysql does not validate server-requested files.\n- Use `DictCursor` or `SSDictCursor` when your calling code expects column names. The default cursor returns tuples.\n- `SSCursor.fetchall()` defeats the point of streaming because it still reads the full result set.\n- Stored procedures have result-set edge cases. Consume all result sets with `nextset()` before assuming the connection is safe for the next query.\n\n## Version-Sensitive Notes For 0.3.x\n\n- `0.3.2` is the current package release on PyPI, published on 2025-10-22.\n- The `0.3.0` release dropped support for Python 3.7 and 3.8. If you find older examples pinned to `0.2.x` or earlier, check the runtime first.\n- PyPI now declares `Requires-Python >=3.9`.\n- The `0.3.0` release tightened `local_infile` handling: passing only a client flag is no longer enough; use the documented `local_infile` parameter explicitly.\n- The `0.2.0` release bumped the minimum SQLAlchemy version for `aiomysql.sa` to `1.3` and the minimum PyMySQL version to `1.0.0`.\n\n## Official Sources\n\n- Docs root: `https://aiomysql.readthedocs.io/en/stable/`\n- Tutorial: `https://aiomysql.readthedocs.io/en/stable/tutorial.html`\n- Connection API: `https://aiomysql.readthedocs.io/en/stable/connection.html`\n- Pool API: `https://aiomysql.readthedocs.io/en/stable/pool.html`\n- Cursor API: `https://aiomysql.readthedocs.io/en/stable/cursors.html`\n- SQLAlchemy integration: `https://aiomysql.readthedocs.io/en/stable/sa.html`\n- PyPI package page: `https://pypi.org/project/aiomysql/`\n- PyPI release page for `0.3.2`: `https://pypi.org/project/aiomysql/0.3.2/`\n- GitHub repository and releases: `https://github.com/aio-libs/aiomysql` and `https://github.com/aio-libs/aiomysql/releases`\n"
  },
  {
    "path": "content/aiosignal/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiosignal package guide for Python async signal registration and dispatch\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aiosignal,python,asyncio,signals,aiohttp,callbacks\"\n---\n\n# aiosignal Python Package Guide\n\n## Golden Rule\n\nUse `aiosignal` when you need a small, typed async callback registry that you control in-process. The package is maintained by the aio-libs project and exposes one core primitive: `Signal`.\n\nFor version `1.4.0`, install it on Python `3.9+`. The maintainer docs landing page still says Python 3.8+, but the PyPI metadata for `1.4.0` requires Python 3.9 or newer.\n\n## Install\n\n```bash\npython -m pip install \"aiosignal==1.4.0\"\n```\n\n`aiosignal` has no auth setup and does not read any environment variables.\n\n## Initialize A Signal\n\nCreate a `Signal` with an owner object. The owner is mainly for debugging and repr output; your callbacks receive only the values you pass to `send()`.\n\n```python\nfrom aiosignal import Signal\n\n\nclass JobRunner:\n    pass\n\n\nrunner = JobRunner()\non_job_finished = Signal(runner)\n```\n\nBefore freezing the signal, you can treat it like a mutable sequence of async callbacks.\n\n## Register And Send Callbacks\n\nCallbacks must be `async def` callables. Dispatch with `await signal.send(...)`.\n\n```python\nimport asyncio\nfrom aiosignal import Signal\n\n\nclass JobRunner:\n    pass\n\n\nrunner = JobRunner()\non_job_finished = Signal(runner)\n\n\nasync def log_completion(job_id: str, status: str) -> None:\n    print(f\"{job_id} -> {status}\")\n\n\nasync def update_metrics(job_id: str, status: str) -> None:\n    print(f\"metrics updated for {job_id}\")\n\n\non_job_finished.append(log_completion)\non_job_finished.append(update_metrics)\non_job_finished.freeze()\n\n\nasync def main() -> None:\n    await on_job_finished.send(\"job-42\", \"ok\")\n\n\nasyncio.run(main())\n```\n\nUse `freeze()` once registration is complete. After that point, treat the signal as immutable and only dispatch it.\n\n## Typed Callbacks\n\n`aiosignal 1.4.0` adds type checking support for signal callback parameters. If you run static type checking, declare the expected argument list on the signal itself.\n\n```python\nimport asyncio\nfrom aiosignal import Signal\n\n\nclass Worker:\n    pass\n\n\nworker = Worker()\nbefore_flush = Signal[int, str](worker)\n\n\nasync def log_flush(batch_size: int, source: str) -> None:\n    print(f\"flushing {batch_size} records from {source}\")\n\n\nbefore_flush.append(log_flush)\nbefore_flush.freeze()\n\n\nasync def main() -> None:\n    await before_flush.send(25, \"nightly-sync\")\n\n\nasyncio.run(main())\n```\n\nOn Python versions below 3.13, the `1.4.0` release adds `typing-extensions` as a dependency to support those callback type hints.\n\n## Common Operations Before Freeze\n\nBecause `Signal` behaves like a mutable sequence before freezing, you can use familiar list-style operations while wiring your app:\n\n```python\nfrom aiosignal import Signal\n\n\nsignal = Signal(object())\n\n\nasync def handler(message: str) -> None:\n    print(message)\n\n\nsignal.append(handler)\nprint(signal.frozen)  # False\n\nsignal.remove(handler)\nsignal.append(handler)\nsignal.freeze()\nprint(signal.frozen)  # True\n```\n\nThe `frozen` property is useful when you want to guard against late callback registration during application startup.\n\n## Using It Indirectly Through aiohttp\n\nIf you use `aiohttp.web`, its application lifecycle signals are built on this same pattern. Register async handlers with `app.on_startup`, `app.on_shutdown`, `app.on_cleanup`, or `app.on_response_prepare`.\n\n```python\nfrom aiohttp import web\n\n\nasync def open_resources(app: web.Application) -> None:\n    app[\"ready\"] = True\n\n\nasync def close_resources(app: web.Application) -> None:\n    app[\"ready\"] = False\n\n\napp = web.Application()\napp.on_startup.append(open_resources)\napp.on_cleanup.append(close_resources)\n```\n\nPer the aiohttp docs, these handlers are asynchronous and run sequentially in the order they were added.\n\n## Common Pitfalls\n\n- Do not register synchronous functions. `aiosignal` is for asynchronous callbacks.\n- Do not rely on the owner object being passed into callbacks; only the arguments from `send()` are delivered.\n- Freeze the signal after startup wiring so later code cannot mutate the callback list unexpectedly.\n- Keep callback signatures consistent with the arguments you send, especially if you use the new typed callback support in `1.4.0`.\n\n## Official Links\n\n- Maintainer docs: https://aiosignal.aio-libs.org/en/stable/\n- PyPI package: https://pypi.org/project/aiosignal/1.4.0/\n- Release notes: https://github.com/aio-libs/aiosignal/releases/tag/v1.4.0\n"
  },
  {
    "path": "content/aiosqlite/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"aiosqlite package guide for Python async SQLite access with asyncio\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.22.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aiosqlite,sqlite,asyncio,database,python\"\n---\n\n# aiosqlite Python Package Guide\n\n## Golden Rule\n\nUse `aiosqlite` when an asyncio application needs SQLite without blocking the event loop. Keep the connection open for a unit of work, `await` every DB operation, and close the connection explicitly or use `async with`.\n\n`aiosqlite` mirrors most of the standard-library `sqlite3` API, but runs database work through a single worker thread per connection and exposes async methods for connection and cursor operations.\n\n## Install\n\n```bash\npython -m pip install \"aiosqlite==0.22.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"aiosqlite==0.22.1\"\npoetry add \"aiosqlite==0.22.1\"\n```\n\n## Initialize A Connection\n\nUse `async with` unless you have a strong reason to manage lifecycle manually:\n\n```python\nimport asyncio\nimport aiosqlite\n\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.execute(\"\"\"\n            CREATE TABLE IF NOT EXISTS users (\n                id INTEGER PRIMARY KEY,\n                email TEXT NOT NULL UNIQUE\n            )\n        \"\"\")\n        await db.commit()\n\nasyncio.run(main())\n```\n\nManual lifecycle is valid, but you must close the connection:\n\n```python\nimport aiosqlite\n\nasync def open_db() -> aiosqlite.Connection:\n    db = await aiosqlite.connect(\"app.db\")\n    return db\n```\n\n## Core Usage\n\n### Insert rows safely\n\nUse SQL parameters instead of string formatting:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.execute(\n            \"INSERT INTO users (email) VALUES (?)\",\n            (\"ada@example.com\",),\n        )\n        await db.commit()\n```\n\n### Read rows with a cursor\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        async with db.execute(\n            \"SELECT id, email FROM users WHERE email LIKE ? ORDER BY id\",\n            (\"%@example.com\",),\n        ) as cursor:\n            rows = await cursor.fetchall()\n\n        for row in rows:\n            print(row[0], row[1])\n```\n\n### Stream rows with async iteration\n\nThis is the better default for large result sets:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        async with db.execute(\"SELECT id, email FROM users ORDER BY id\") as cursor:\n            async for row in cursor:\n                print(row)\n```\n\n### Return dictionary-like rows\n\n`aiosqlite.Row` gives named access similar to `sqlite3.Row`:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        db.row_factory = aiosqlite.Row\n\n        async with db.execute(\"SELECT id, email FROM users LIMIT 1\") as cursor:\n            row = await cursor.fetchone()\n\n        if row is not None:\n            print(row[\"email\"])\n```\n\n### Use connection helper shortcuts\n\n`execute`, `execute_fetchall`, `execute_insert`, `executemany`, and `executescript` are exposed on the connection:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        rows = await db.execute_fetchall(\n            \"SELECT id, email FROM users WHERE id > ?\",\n            (10,),\n        )\n```\n\n## Transactions\n\n`aiosqlite` follows SQLite transaction behavior from `sqlite3`:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.execute(\"UPDATE accounts SET balance = balance - 50 WHERE id = ?\", (1,))\n        await db.execute(\"UPDATE accounts SET balance = balance + 50 WHERE id = ?\", (2,))\n        await db.commit()\n```\n\nRollback on error:\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        try:\n            await db.execute(\"INSERT INTO audit_log(message) VALUES (?)\", (\"started\",))\n            await db.execute(\"INSERT INTO broken_table(value) VALUES (?)\", (\"x\",))\n            await db.commit()\n        except Exception:\n            await db.rollback()\n            raise\n```\n\nIf you want autocommit-style behavior, pass the same kind of connection settings you would use with `sqlite3`, for example `isolation_level=None`.\n\n## Configuration\n\nThere is no auth layer. Configuration is mostly:\n\n- database location: file path, `:memory:`, or SQLite URI\n- `sqlite3.connect` keyword arguments forwarded through `aiosqlite.connect(...)`\n- async iteration chunking through `iter_chunk_size`\n\nExample with common SQLite options:\n\n```python\nimport sqlite3\nimport aiosqlite\n\nasync def open_db() -> aiosqlite.Connection:\n    return await aiosqlite.connect(\n        \"file:app.db?mode=rwc\",\n        uri=True,\n        timeout=10,\n        detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES,\n        isolation_level=None,\n        iter_chunk_size=128,\n    )\n```\n\nPractical notes:\n\n- `timeout` controls how long SQLite waits on a locked database before raising.\n- `detect_types` enables adapter and converter behavior from `sqlite3`.\n- `uri=True` lets you use SQLite URI filenames.\n- `iter_chunk_size` controls how many rows are pulled per worker-thread chunk during async iteration.\n\n## Useful sqlite3-Parity Features\n\n### Register custom SQL functions\n\n```python\nimport hashlib\nimport aiosqlite\n\ndef sha1_hex(value: str) -> str:\n    return hashlib.sha1(value.encode(\"utf-8\")).hexdigest()\n\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.create_function(\"sha1_hex\", 1, sha1_hex, deterministic=True)\n```\n\n### Backup one database into another\n\n```python\nimport aiosqlite\n\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as source:\n        async with aiosqlite.connect(\"backup.db\") as target:\n            await source.backup(target)\n```\n\n### Interrupt long-running work\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.interrupt()\n```\n\n### Install progress or trace callbacks\n\n```python\nasync def main() -> None:\n    async with aiosqlite.connect(\"app.db\") as db:\n        await db.set_progress_handler(lambda: 0, 1000)\n        await db.set_trace_callback(print)\n```\n\n`set_authorizer` is also available in `0.21.0+` if you need SQLite authorizer hooks.\n\n## Concurrency Model\n\nThe package uses one dedicated thread per connection and executes actions through a shared request queue for that connection. This prevents overlapping SQLite calls on the same connection from blocking the event loop, but it does not make a single connection truly parallel.\n\nPractical guidance:\n\n- Reuse one connection for a small transactional unit of work.\n- Open separate connections for independent concurrent tasks.\n- Do not expect `asyncio.gather(...)` on the same connection to run queries in parallel.\n- For write-heavy apps, expect SQLite locking rules to matter just as they do with `sqlite3`.\n\n## Common Pitfalls\n\n- Forgetting `await`: `db.execute(...)`, `cursor.fetchone()`, `db.commit()`, and `db.close()` are async.\n- Forgetting `commit()`: inserts and updates are not persisted until committed unless you explicitly configure autocommit behavior.\n- Leaking connections: `0.22.1` adds a `ResourceWarning` when connections are not closed before garbage collection.\n- Sharing one connection for all concurrent work: operations serialize through one queue, so latency stacks up quickly.\n- Using string interpolation in SQL: use placeholders and bound parameters.\n- Expecting network-style auth or pooling features: this is a thin async wrapper around local SQLite, not a client/server database driver.\n- Assuming the docs landing page is fully current on packaging constraints: the stable landing page still says Python 3.8+, but PyPI metadata and the changelog reflect the current support floor.\n\n## Version-Sensitive Notes For 0.22.1\n\n- `0.22.1` is the latest PyPI release as of March 11, 2026.\n- `0.22.1` adds a `ResourceWarning` when a connection is garbage-collected without being closed.\n- `0.22.0` changed `Connection` so it no longer subclasses `Thread`; if you had code relying on thread inheritance details, update it.\n- `0.21.0` added `set_authorizer` support and dropped Python 3.8 support.\n- PyPI currently declares `Requires-Python >=3.9`, which is the packaging constraint agents should trust when generating install or CI guidance.\n\n## Official Sources\n\n- Main docs: https://aiosqlite.omnilib.dev/en/stable/\n- API reference: https://aiosqlite.omnilib.dev/en/stable/api.html\n- Changelog: https://aiosqlite.omnilib.dev/en/stable/changelog.html\n- PyPI metadata: https://pypi.org/project/aiosqlite/\n- Python `sqlite3.connect`: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect\n- Python row factories: https://docs.python.org/3/library/sqlite3.html#how-to-create-and-use-row-factories\n"
  },
  {
    "path": "content/airtable/docs/database/javascript/DOC.md",
    "content": "---\nname: database\ndescription: \"Airtable JavaScript SDK (airtable.js) — use the official airtable npm package for Airtable API operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.12.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"airtable,database,low-code,spreadsheet,api\"\n---\n\n# Airtable JavaScript SDK (airtable.js) - Version 0.12.2\n\n## Golden Rule\n\n**ALWAYS use the official `airtable` npm package (version 0.12.2 or later)**\n\n```bash\nnpm install airtable\n```\n\n**DO NOT use:**\n- Deprecated or unofficial packages like `airtable-node`, `airtable-plus`, or other third-party wrappers\n- The old API key authentication method (deprecated as of February 1, 2024)\n- The `@airtable/blocks` package unless building Airtable extensions\n\n**ALWAYS use Personal Access Tokens (PATs) for authentication**, not the deprecated API keys.\n\n## Installation\n\n```bash\nnpm install airtable\n```\n\n### Environment Variable Setup\n\nCreate a `.env` file:\n\n```bash\nAIRTABLE_API_KEY=your_personal_access_token_here\n```\n\nFor production applications, use proper secret management systems.\n\n## Authentication & Initialization\n\n### Personal Access Token Setup\n\n1. Visit https://airtable.com/create/tokens to create a Personal Access Token\n2. Name your token (e.g., \"My App Token\")\n3. Add required scopes:\n   - `data.records:read` - to read records\n   - `data.records:write` - to create/update/delete records\n   - `schema.bases:read` - to read base structure (optional)\n4. Select base access level (specific bases or all workspace bases)\n5. Copy the token immediately (shown only once)\n\n### Basic Configuration\n\n**Option 1: Global Configuration**\n\n```javascript\nconst Airtable = require('airtable');\n\nAirtable.configure({\n  apiKey: 'your_personal_access_token'\n});\n\nconst base = Airtable.base('appYourBaseId');\n```\n\n**Option 2: Environment Variable**\n\n```javascript\nconst Airtable = require('airtable');\n\n// Automatically reads from AIRTABLE_API_KEY environment variable\nconst base = Airtable.base('appYourBaseId');\n```\n\n**Option 3: Per-Instance Configuration**\n\n```javascript\nconst Airtable = require('airtable');\n\nconst airtable = new Airtable({\n  apiKey: process.env.AIRTABLE_API_KEY\n});\n\nconst base = airtable.base('appYourBaseId');\n```\n\n### Advanced Configuration Options\n\n```javascript\nconst Airtable = require('airtable');\n\nAirtable.configure({\n  apiKey: process.env.AIRTABLE_API_KEY,\n  endpointUrl: 'https://api.airtable.com', // Custom endpoint (optional)\n  requestTimeout: 300000 // Request timeout in milliseconds (default: 300000)\n});\n```\n\n### Finding Your Base and Table IDs\n\n1. Go to https://airtable.com/api\n2. Select your base\n3. Base ID format: `appXXXXXXXXXXXXXX`\n4. Table names are case-sensitive strings (e.g., 'Tasks', 'Contacts')\n\n## Core API Surfaces\n\n### Reading Records\n\n#### Get Single Record by ID\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.find('recXXXXXXXXXXXXXX', function(err, record) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n  console.log('Retrieved', record.get('Name'));\n  console.log('Record ID:', record.id);\n  console.log('Created time:', record._rawJson.createdTime);\n});\n\n// Promise style\ntable.find('recXXXXXXXXXXXXXX')\n  .then(record => {\n    console.log('Retrieved', record.get('Name'));\n  })\n  .catch(err => {\n    console.error(err);\n  });\n\n// Async/await style\nasync function getRecord() {\n  try {\n    const record = await table.find('recXXXXXXXXXXXXXX');\n    console.log('Name:', record.get('Name'));\n    console.log('Status:', record.get('Status'));\n\n    // Access all fields\n    const fields = record.fields;\n    console.log('All fields:', fields);\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n#### Get All Records (≤100 records)\n\nUse `firstPage()` when you know your table has 100 or fewer records:\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.select({\n  view: 'Grid view'\n}).firstPage(function(err, records) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n\n  records.forEach(function(record) {\n    console.log('Retrieved', record.get('Name'));\n  });\n});\n\n// Promise style\ntable.select().firstPage()\n  .then(records => {\n    records.forEach(record => {\n      console.log('Name:', record.get('Name'));\n      console.log('Status:', record.get('Status'));\n    });\n  })\n  .catch(err => {\n    console.error(err);\n  });\n\n// Async/await style\nasync function getAllRecords() {\n  try {\n    const records = await table.select().firstPage();\n\n    records.forEach(record => {\n      console.log('ID:', record.id);\n      console.log('Name:', record.get('Name'));\n    });\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n#### Paginated Reading (>100 records)\n\nUse `eachPage()` for tables with more than 100 records:\n\n```javascript\nconst table = base('Tasks');\n\nlet allRecords = [];\n\ntable.select({\n  view: 'Grid view'\n}).eachPage(\n  function page(records, fetchNextPage) {\n    // Called for each page of records\n    records.forEach(function(record) {\n      console.log('Retrieved', record.get('Name'));\n      allRecords.push(record);\n    });\n\n    // Fetch the next page of records\n    fetchNextPage();\n  },\n  function done(err) {\n    // Called when all pages have been retrieved\n    if (err) {\n      console.error(err);\n      return;\n    }\n\n    console.log(`Total records: ${allRecords.length}`);\n  }\n);\n```\n\n#### Using all() Method with Async/Await\n\nThe `all()` method retrieves all pages synchronously:\n\n```javascript\nconst table = base('Tasks');\n\nasync function getAllRecordsSimple() {\n  try {\n    const records = await table.select({\n      view: 'Grid view'\n    }).all();\n\n    console.log(`Total records: ${records.length}`);\n\n    records.forEach(record => {\n      console.log('Name:', record.get('Name'));\n    });\n\n    return records;\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n**Important:** Only use `all()` when you expect a manageable number of records. For very large tables, use `eachPage()` to avoid memory issues.\n\n### Filtering Records\n\n#### Using filterByFormula\n\n```javascript\nconst table = base('Tasks');\n\n// Simple filter\nconst records = await table.select({\n  filterByFormula: \"{Status} = 'Active'\"\n}).all();\n\n// Multiple conditions with AND\nconst activeHighPriority = await table.select({\n  filterByFormula: \"AND({Status} = 'Active', {Priority} = 'High')\"\n}).all();\n\n// Multiple conditions with OR\nconst urgentOrBlocked = await table.select({\n  filterByFormula: \"OR({Status} = 'Urgent', {Status} = 'Blocked')\"\n}).all();\n\n// Not empty check\nconst withTitles = await table.select({\n  filterByFormula: \"NOT({Title} = '')\"\n}).all();\n\n// Greater than comparison\nconst recentTasks = await table.select({\n  filterByFormula: \"{Created} > '2025-01-01'\"\n}).all();\n\n// String matching with variable\nconst email = 'user@example.com';\nconst userRecords = await table.select({\n  filterByFormula: `{Email} = \"${email}\"`\n}).all();\n\n// Complex formula\nconst complexFilter = await table.select({\n  filterByFormula: `AND(\n    {Status} = 'In Progress',\n    {Priority} = 'High',\n    {Assignee} != '',\n    {DueDate} <= TODAY()\n  )`\n}).all();\n```\n\n### Sorting Records\n\n```javascript\nconst table = base('Tasks');\n\n// Sort by single field (ascending)\nconst sortedAsc = await table.select({\n  sort: [{field: 'Name', direction: 'asc'}]\n}).all();\n\n// Sort by single field (descending)\nconst sortedDesc = await table.select({\n  sort: [{field: 'Created', direction: 'desc'}]\n}).all();\n\n// Sort by multiple fields\nconst multiSort = await table.select({\n  sort: [\n    {field: 'Priority', direction: 'desc'},\n    {field: 'DueDate', direction: 'asc'},\n    {field: 'Name', direction: 'asc'}\n  ]\n}).all();\n```\n\n### Limiting and Pagination Parameters\n\n```javascript\nconst table = base('Tasks');\n\n// Limit total number of records returned\nconst limitedRecords = await table.select({\n  maxRecords: 50\n}).all();\n\n// Set page size (max 100)\nconst customPageSize = await table.select({\n  pageSize: 50\n}).firstPage();\n\n// Combine all parameters\nconst complexQuery = await table.select({\n  view: 'Active Tasks',\n  maxRecords: 100,\n  pageSize: 50,\n  filterByFormula: \"NOT({Name} = '')\",\n  sort: [{field: 'Priority', direction: 'desc'}]\n}).all();\n```\n\n### Selecting Specific Fields\n\n```javascript\nconst table = base('Tasks');\n\n// Only retrieve specific fields\nconst records = await table.select({\n  fields: ['Name', 'Status', 'Assignee']\n}).all();\n\nrecords.forEach(record => {\n  console.log('Name:', record.get('Name'));\n  console.log('Status:', record.get('Status'));\n  // Other fields will be undefined\n});\n```\n\n### Using Views\n\n```javascript\nconst table = base('Tasks');\n\n// Select from a specific view\nconst viewRecords = await table.select({\n  view: 'Active Tasks'\n}).all();\n\n// Combine view with other parameters\nconst filteredView = await table.select({\n  view: 'Active Tasks',\n  filterByFormula: \"{Priority} = 'High'\",\n  sort: [{field: 'DueDate', direction: 'asc'}]\n}).all();\n```\n\n### Creating Records\n\n#### Create Single Record\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.create({\n  'Name': 'New Task',\n  'Status': 'To Do',\n  'Priority': 'Medium'\n}, function(err, record) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n  console.log('Created record:', record.id);\n});\n\n// Promise style\ntable.create({\n  'Name': 'New Task',\n  'Status': 'To Do'\n}).then(record => {\n  console.log('Created record:', record.id);\n}).catch(err => {\n  console.error(err);\n});\n\n// Async/await style\nasync function createTask() {\n  try {\n    const record = await table.create({\n      'Name': 'New Task',\n      'Status': 'To Do',\n      'Priority': 'High',\n      'Notes': 'This is a new task'\n    });\n\n    console.log('Created record:', record.id);\n    console.log('Name:', record.get('Name'));\n\n    return record;\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n#### Create with Typecast\n\n```javascript\nconst table = base('Tasks');\n\n// Typecast converts strings to appropriate types\nconst record = await table.create({\n  'Name': 'Task with Date',\n  'DueDate': '2025-12-31', // String will be converted to date\n  'Count': '42' // String will be converted to number\n}, {\n  typecast: true\n});\n```\n\n#### Batch Create (Multiple Records)\n\nAirtable allows up to 10 records per batch operation:\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.create([\n  {\n    'Name': 'Task 1',\n    'Status': 'To Do'\n  },\n  {\n    'Name': 'Task 2',\n    'Status': 'In Progress'\n  },\n  {\n    'Name': 'Task 3',\n    'Status': 'Done'\n  }\n], function(err, records) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n\n  records.forEach(function(record) {\n    console.log('Created:', record.id);\n  });\n});\n\n// Async/await style\nasync function batchCreate() {\n  try {\n    const records = await table.create([\n      {'Name': 'Task 1', 'Status': 'To Do'},\n      {'Name': 'Task 2', 'Status': 'In Progress'},\n      {'Name': 'Task 3', 'Status': 'Done'},\n      {'Name': 'Task 4', 'Status': 'To Do'},\n      {'Name': 'Task 5', 'Status': 'Review'}\n    ]);\n\n    console.log(`Created ${records.length} records`);\n\n    return records;\n  } catch (err) {\n    console.error(err);\n  }\n}\n\n// With typecast\nconst recordsWithTypecast = await table.create([\n  {'Name': 'Task 1', 'Count': '10'},\n  {'Name': 'Task 2', 'Count': '20'}\n], {\n  typecast: true\n});\n```\n\n### Updating Records\n\n#### Update Single Record (Partial Update)\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.update('recXXXXXXXXXXXXXX', {\n  'Status': 'In Progress',\n  'Notes': 'Updated notes'\n}, function(err, record) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n  console.log('Updated record:', record.id);\n});\n\n// Promise style\ntable.update('recXXXXXXXXXXXXXX', {\n  'Status': 'Done'\n}).then(record => {\n  console.log('Updated:', record.get('Status'));\n}).catch(err => {\n  console.error(err);\n});\n\n// Async/await style\nasync function updateTask(recordId) {\n  try {\n    const record = await table.update(recordId, {\n      'Status': 'In Progress',\n      'Progress': 50\n    });\n\n    console.log('Updated record:', record.id);\n    console.log('New status:', record.get('Status'));\n\n    return record;\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n#### Replace Record (Full Update)\n\nThe `replace()` method replaces all fields (fields not included will be cleared):\n\n```javascript\nconst table = base('Tasks');\n\n// Replace clears fields not specified\nconst record = await table.replace('recXXXXXXXXXXXXXX', {\n  'Name': 'Completely New Task',\n  'Status': 'To Do'\n  // All other fields will be cleared\n});\n```\n\n#### Batch Update (Multiple Records)\n\n```javascript\nconst table = base('Tasks');\n\n// Update up to 10 records at once\nconst records = await table.update([\n  {\n    id: 'recXXXXXXXXXXXXXX',\n    fields: {\n      'Status': 'Done'\n    }\n  },\n  {\n    id: 'recYYYYYYYYYYYYYY',\n    fields: {\n      'Status': 'In Progress',\n      'Progress': 75\n    }\n  }\n]);\n\nconsole.log(`Updated ${records.length} records`);\n\n// With typecast\nconst updatedWithTypecast = await table.update([\n  {\n    id: 'recXXXXXXXXXXXXXX',\n    fields: {'Count': '100'}\n  }\n], {\n  typecast: true\n});\n```\n\n#### Batch Replace (Multiple Records)\n\n```javascript\nconst table = base('Tasks');\n\n// Replace up to 10 records at once\nconst records = await table.replace([\n  {\n    id: 'recXXXXXXXXXXXXXX',\n    fields: {\n      'Name': 'New Name',\n      'Status': 'To Do'\n    }\n  },\n  {\n    id: 'recYYYYYYYYYYYYYY',\n    fields: {\n      'Name': 'Another Task',\n      'Status': 'Done'\n    }\n  }\n]);\n\n// With typecast\nconst replacedWithTypecast = await table.replace([\n  {\n    id: 'recXXXXXXXXXXXXXX',\n    fields: {'Name': 'Task', 'Count': '50'}\n  }\n], {\n  typecast: true\n});\n```\n\n### Deleting Records\n\n#### Delete Single Record\n\n```javascript\nconst table = base('Tasks');\n\n// Callback style\ntable.destroy('recXXXXXXXXXXXXXX', function(err, deletedRecord) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n  console.log('Deleted record:', deletedRecord.id);\n});\n\n// Promise style\ntable.destroy('recXXXXXXXXXXXXXX')\n  .then(deletedRecord => {\n    console.log('Deleted:', deletedRecord.id);\n  })\n  .catch(err => {\n    console.error(err);\n  });\n\n// Async/await style\nasync function deleteTask(recordId) {\n  try {\n    const deletedRecord = await table.destroy(recordId);\n    console.log('Deleted record:', deletedRecord.id);\n\n    return deletedRecord;\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n#### Batch Delete (Multiple Records)\n\n```javascript\nconst table = base('Tasks');\n\n// Delete up to 10 records at once\n// Callback style\ntable.destroy([\n  'recXXXXXXXXXXXXXX',\n  'recYYYYYYYYYYYYYY',\n  'recZZZZZZZZZZZZZZ'\n], function(err, deletedRecords) {\n  if (err) {\n    console.error(err);\n    return;\n  }\n  console.log('Deleted', deletedRecords.length, 'records');\n});\n\n// Async/await style\nasync function batchDelete(recordIds) {\n  try {\n    const deletedRecords = await table.destroy(recordIds);\n    console.log(`Deleted ${deletedRecords.length} records`);\n\n    deletedRecords.forEach(record => {\n      console.log('Deleted:', record.id);\n    });\n\n    return deletedRecords;\n  } catch (err) {\n    console.error(err);\n  }\n}\n\n// Example usage\nawait batchDelete([\n  'recXXXXXXXXXXXXXX',\n  'recYYYYYYYYYYYYYY'\n]);\n```\n\n### Working with Different Field Types\n\n#### Text Fields\n\n```javascript\nconst record = await table.create({\n  'Single Line Text': 'Short text',\n  'Long Text': 'This is a much longer text\\nwith multiple lines',\n  'Email': 'user@example.com',\n  'URL': 'https://example.com',\n  'Phone': '+1-555-0100'\n});\n```\n\n#### Number Fields\n\n```javascript\nconst record = await table.create({\n  'Number': 42,\n  'Currency': 99.99,\n  'Percent': 0.75,\n  'Rating': 5\n});\n```\n\n#### Date and Time Fields\n\n```javascript\nconst record = await table.create({\n  'Date': '2025-10-25',\n  'DateTime': '2025-10-25T14:30:00.000Z'\n});\n\n// Access date fields\nconst dateValue = record.get('Date');\nconsole.log('Date:', dateValue);\n```\n\n#### Checkbox (Boolean) Fields\n\n```javascript\nconst record = await table.create({\n  'Completed': true,\n  'Active': false\n});\n\n// Access checkbox\nconst isCompleted = record.get('Completed');\nif (isCompleted) {\n  console.log('Task is completed');\n}\n```\n\n#### Single Select Fields\n\n```javascript\nconst record = await table.create({\n  'Status': 'In Progress', // Must match exact option name\n  'Priority': 'High'\n});\n```\n\n#### Multiple Select Fields\n\n```javascript\nconst record = await table.create({\n  'Tags': ['Important', 'Urgent', 'Client Work']\n});\n\n// Access multiple select\nconst tags = record.get('Tags');\nconsole.log('Tags:', tags.join(', '));\n```\n\n#### Attachment Fields\n\n```javascript\nconst record = await table.create({\n  'Attachments': [\n    {\n      url: 'https://example.com/image.jpg'\n    },\n    {\n      url: 'https://example.com/document.pdf'\n    }\n  ]\n});\n\n// Access attachments\nconst attachments = record.get('Attachments');\nattachments.forEach(attachment => {\n  console.log('File:', attachment.filename);\n  console.log('URL:', attachment.url);\n  console.log('Size:', attachment.size);\n  console.log('Type:', attachment.type);\n});\n```\n\n#### Linked Record Fields\n\n```javascript\n// Link to existing records by their IDs\nconst record = await table.create({\n  'Linked Records': [\n    'recXXXXXXXXXXXXXX',\n    'recYYYYYYYYYYYYYY'\n  ]\n});\n\n// Access linked records\nconst linkedRecords = record.get('Linked Records');\nconsole.log('Linked record IDs:', linkedRecords);\n```\n\n#### Collaborator Fields\n\n```javascript\nconst record = await table.create({\n  'Assignee': {\n    id: 'usrXXXXXXXXXXXXXX',\n    email: 'user@example.com'\n  },\n  'Collaborators': [\n    {id: 'usrXXXXXXXXXXXXXX'},\n    {id: 'usrYYYYYYYYYYYYYY'}\n  ]\n});\n```\n\n## Complete Examples\n\n### Example 1: Task Management System\n\n```javascript\nconst Airtable = require('airtable');\n\nAirtable.configure({\n  apiKey: process.env.AIRTABLE_API_KEY\n});\n\nconst base = Airtable.base('appTaskManager');\nconst tasksTable = base('Tasks');\n\n// Create a new task\nasync function createTask(taskData) {\n  try {\n    const record = await tasksTable.create({\n      'Name': taskData.name,\n      'Description': taskData.description,\n      'Status': 'To Do',\n      'Priority': taskData.priority || 'Medium',\n      'Assignee': taskData.assignee,\n      'Due Date': taskData.dueDate\n    });\n\n    console.log('Created task:', record.id);\n    return record;\n  } catch (err) {\n    console.error('Error creating task:', err);\n    throw err;\n  }\n}\n\n// Get all active tasks\nasync function getActiveTasks() {\n  try {\n    const records = await tasksTable.select({\n      filterByFormula: \"AND({Status} != 'Done', {Status} != 'Cancelled')\",\n      sort: [\n        {field: 'Priority', direction: 'desc'},\n        {field: 'Due Date', direction: 'asc'}\n      ]\n    }).all();\n\n    return records.map(record => ({\n      id: record.id,\n      name: record.get('Name'),\n      status: record.get('Status'),\n      priority: record.get('Priority'),\n      assignee: record.get('Assignee'),\n      dueDate: record.get('Due Date')\n    }));\n  } catch (err) {\n    console.error('Error fetching tasks:', err);\n    throw err;\n  }\n}\n\n// Update task status\nasync function updateTaskStatus(taskId, newStatus) {\n  try {\n    const record = await tasksTable.update(taskId, {\n      'Status': newStatus,\n      'Last Modified': new Date().toISOString()\n    });\n\n    console.log('Updated task:', record.id);\n    return record;\n  } catch (err) {\n    console.error('Error updating task:', err);\n    throw err;\n  }\n}\n\n// Get overdue tasks\nasync function getOverdueTasks() {\n  try {\n    const today = new Date().toISOString().split('T')[0];\n\n    const records = await tasksTable.select({\n      filterByFormula: `AND(\n        {Status} != 'Done',\n        {Due Date} < '${today}'\n      )`,\n      sort: [{field: 'Due Date', direction: 'asc'}]\n    }).all();\n\n    return records;\n  } catch (err) {\n    console.error('Error fetching overdue tasks:', err);\n    throw err;\n  }\n}\n\n// Bulk update multiple tasks\nasync function bulkUpdateStatus(taskIds, newStatus) {\n  try {\n    const updates = taskIds.map(id => ({\n      id: id,\n      fields: {\n        'Status': newStatus,\n        'Last Modified': new Date().toISOString()\n      }\n    }));\n\n    // Process in batches of 10\n    const results = [];\n    for (let i = 0; i < updates.length; i += 10) {\n      const batch = updates.slice(i, i + 10);\n      const updated = await tasksTable.update(batch);\n      results.push(...updated);\n    }\n\n    console.log(`Updated ${results.length} tasks`);\n    return results;\n  } catch (err) {\n    console.error('Error bulk updating:', err);\n    throw err;\n  }\n}\n\n// Delete completed tasks older than 30 days\nasync function deleteOldCompletedTasks() {\n  try {\n    const thirtyDaysAgo = new Date();\n    thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n    const cutoffDate = thirtyDaysAgo.toISOString().split('T')[0];\n\n    const records = await tasksTable.select({\n      filterByFormula: `AND(\n        {Status} = 'Done',\n        {Completed Date} < '${cutoffDate}'\n      )`\n    }).all();\n\n    const recordIds = records.map(record => record.id);\n\n    // Delete in batches of 10\n    for (let i = 0; i < recordIds.length; i += 10) {\n      const batch = recordIds.slice(i, i + 10);\n      await tasksTable.destroy(batch);\n    }\n\n    console.log(`Deleted ${recordIds.length} old completed tasks`);\n  } catch (err) {\n    console.error('Error deleting old tasks:', err);\n    throw err;\n  }\n}\n\n// Export module\nmodule.exports = {\n  createTask,\n  getActiveTasks,\n  updateTaskStatus,\n  getOverdueTasks,\n  bulkUpdateStatus,\n  deleteOldCompletedTasks\n};\n```\n\n### Example 2: Contact Management with Error Handling\n\n```javascript\nconst Airtable = require('airtable');\n\nconst airtable = new Airtable({\n  apiKey: process.env.AIRTABLE_API_KEY\n});\n\nconst base = airtable.base('appContactManager');\nconst contactsTable = base('Contacts');\n\n// Find contact by email\nasync function findContactByEmail(email) {\n  try {\n    const records = await contactsTable.select({\n      filterByFormula: `{Email} = \"${email}\"`,\n      maxRecords: 1\n    }).firstPage();\n\n    return records.length > 0 ? records[0] : null;\n  } catch (err) {\n    console.error(`Error finding contact with email ${email}:`, err);\n    throw err;\n  }\n}\n\n// Create or update contact (upsert pattern)\nasync function upsertContact(contactData) {\n  try {\n    // First, try to find existing contact\n    const existingContact = await findContactByEmail(contactData.email);\n\n    if (existingContact) {\n      // Update existing contact\n      const updated = await contactsTable.update(existingContact.id, {\n        'First Name': contactData.firstName,\n        'Last Name': contactData.lastName,\n        'Phone': contactData.phone,\n        'Company': contactData.company,\n        'Last Updated': new Date().toISOString()\n      });\n\n      console.log('Updated existing contact:', updated.id);\n      return {record: updated, action: 'updated'};\n    } else {\n      // Create new contact\n      const created = await contactsTable.create({\n        'First Name': contactData.firstName,\n        'Last Name': contactData.lastName,\n        'Email': contactData.email,\n        'Phone': contactData.phone,\n        'Company': contactData.company,\n        'Created': new Date().toISOString()\n      });\n\n      console.log('Created new contact:', created.id);\n      return {record: created, action: 'created'};\n    }\n  } catch (err) {\n    console.error('Error upserting contact:', err);\n    throw err;\n  }\n}\n\n// Get all contacts from a company\nasync function getContactsByCompany(companyName) {\n  try {\n    const records = await contactsTable.select({\n      filterByFormula: `{Company} = \"${companyName}\"`,\n      sort: [\n        {field: 'Last Name', direction: 'asc'},\n        {field: 'First Name', direction: 'asc'}\n      ]\n    }).all();\n\n    return records.map(record => ({\n      id: record.id,\n      name: `${record.get('First Name')} ${record.get('Last Name')}`,\n      email: record.get('Email'),\n      phone: record.get('Phone')\n    }));\n  } catch (err) {\n    console.error(`Error fetching contacts for ${companyName}:`, err);\n    throw err;\n  }\n}\n\n// Export contacts to array\nasync function exportAllContacts() {\n  try {\n    const allContacts = [];\n\n    await contactsTable.select().eachPage(\n      function page(records, fetchNextPage) {\n        records.forEach(record => {\n          allContacts.push({\n            id: record.id,\n            firstName: record.get('First Name'),\n            lastName: record.get('Last Name'),\n            email: record.get('Email'),\n            phone: record.get('Phone'),\n            company: record.get('Company'),\n            created: record.get('Created')\n          });\n        });\n\n        fetchNextPage();\n      },\n      function done(err) {\n        if (err) {\n          console.error('Error during pagination:', err);\n          throw err;\n        }\n      }\n    );\n\n    return allContacts;\n  } catch (err) {\n    console.error('Error exporting contacts:', err);\n    throw err;\n  }\n}\n\nmodule.exports = {\n  findContactByEmail,\n  upsertContact,\n  getContactsByCompany,\n  exportAllContacts\n};\n```\n\n### Example 3: E-commerce Inventory Management\n\n```javascript\nconst Airtable = require('airtable');\nconst base = Airtable.base('appInventory');\n\nconst productsTable = base('Products');\nconst ordersTable = base('Orders');\n\n// Check product availability\nasync function checkInventory(productId) {\n  try {\n    const product = await productsTable.find(productId);\n\n    return {\n      id: product.id,\n      name: product.get('Name'),\n      sku: product.get('SKU'),\n      quantity: product.get('Quantity in Stock'),\n      available: product.get('Quantity in Stock') > 0\n    };\n  } catch (err) {\n    console.error(`Error checking inventory for ${productId}:`, err);\n    throw err;\n  }\n}\n\n// Update stock after purchase\nasync function updateStockQuantity(productId, quantityChange) {\n  try {\n    const product = await productsTable.find(productId);\n    const currentStock = product.get('Quantity in Stock');\n    const newStock = currentStock + quantityChange;\n\n    if (newStock < 0) {\n      throw new Error('Insufficient stock');\n    }\n\n    const updated = await productsTable.update(productId, {\n      'Quantity in Stock': newStock,\n      'Last Updated': new Date().toISOString()\n    });\n\n    console.log(`Updated stock for ${product.get('Name')}: ${currentStock} -> ${newStock}`);\n    return updated;\n  } catch (err) {\n    console.error(`Error updating stock for ${productId}:`, err);\n    throw err;\n  }\n}\n\n// Get low stock products\nasync function getLowStockProducts(threshold = 10) {\n  try {\n    const records = await productsTable.select({\n      filterByFormula: `{Quantity in Stock} < ${threshold}`,\n      sort: [{field: 'Quantity in Stock', direction: 'asc'}]\n    }).all();\n\n    return records.map(record => ({\n      id: record.id,\n      name: record.get('Name'),\n      sku: record.get('SKU'),\n      quantity: record.get('Quantity in Stock'),\n      reorderLevel: record.get('Reorder Level')\n    }));\n  } catch (err) {\n    console.error('Error fetching low stock products:', err);\n    throw err;\n  }\n}\n\n// Create order with multiple line items\nasync function createOrder(orderData) {\n  try {\n    // Create order record\n    const order = await ordersTable.create({\n      'Order Number': orderData.orderNumber,\n      'Customer Name': orderData.customerName,\n      'Customer Email': orderData.customerEmail,\n      'Status': 'Pending',\n      'Total Amount': orderData.totalAmount,\n      'Order Date': new Date().toISOString()\n    });\n\n    // Update inventory for each product\n    for (const item of orderData.items) {\n      await updateStockQuantity(item.productId, -item.quantity);\n    }\n\n    console.log('Created order:', order.id);\n    return order;\n  } catch (err) {\n    console.error('Error creating order:', err);\n    throw err;\n  }\n}\n\n// Get orders by status\nasync function getOrdersByStatus(status) {\n  try {\n    const records = await ordersTable.select({\n      filterByFormula: `{Status} = \"${status}\"`,\n      sort: [{field: 'Order Date', direction: 'desc'}]\n    }).all();\n\n    return records.map(record => ({\n      id: record.id,\n      orderNumber: record.get('Order Number'),\n      customer: record.get('Customer Name'),\n      total: record.get('Total Amount'),\n      date: record.get('Order Date')\n    }));\n  } catch (err) {\n    console.error(`Error fetching ${status} orders:`, err);\n    throw err;\n  }\n}\n\nmodule.exports = {\n  checkInventory,\n  updateStockQuantity,\n  getLowStockProducts,\n  createOrder,\n  getOrdersByStatus\n};\n```\n\n## Rate Limits and Error Handling\n\nAirtable enforces a rate limit of **5 requests per second per base**.\n\n### Handling Rate Limits\n\n```javascript\nasync function retryWithBackoff(fn, maxRetries = 3, initialDelay = 1000) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (err.statusCode === 429 && i < maxRetries - 1) {\n        const delay = initialDelay * Math.pow(2, i);\n        console.log(`Rate limited. Retrying in ${delay}ms...`);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw err;\n      }\n    }\n  }\n}\n\n// Usage\nconst record = await retryWithBackoff(() =>\n  table.create({'Name': 'New Record'})\n);\n```\n\n### Error Handling Patterns\n\n```javascript\nconst table = base('Tasks');\n\n// Basic error handling\ntry {\n  const record = await table.find('recXXXXXXXXXXXXXX');\n} catch (err) {\n  if (err.statusCode === 404) {\n    console.error('Record not found');\n  } else if (err.statusCode === 401) {\n    console.error('Authentication failed');\n  } else if (err.statusCode === 429) {\n    console.error('Rate limit exceeded');\n  } else {\n    console.error('Unexpected error:', err);\n  }\n}\n\n// Comprehensive error handling\nasync function safeCreate(recordData) {\n  try {\n    const record = await table.create(recordData);\n    return {success: true, record};\n  } catch (err) {\n    console.error('Error creating record:', err.message);\n\n    return {\n      success: false,\n      error: {\n        message: err.message,\n        statusCode: err.statusCode,\n        type: err.error\n      }\n    };\n  }\n}\n```\n\n## TypeScript Support\n\n```typescript\nimport Airtable, { FieldSet, Records } from 'airtable';\n\ninterface Task extends FieldSet {\n  'Name': string;\n  'Status': 'To Do' | 'In Progress' | 'Done';\n  'Priority': 'Low' | 'Medium' | 'High';\n  'Due Date': string;\n  'Assignee': string;\n}\n\nAirtable.configure({\n  apiKey: process.env.AIRTABLE_API_KEY!\n});\n\nconst base = Airtable.base('appYourBaseId');\nconst tasksTable = base<Task>('Tasks');\n\nasync function getHighPriorityTasks(): Promise<Records<Task>> {\n  const records = await tasksTable.select({\n    filterByFormula: \"{Priority} = 'High'\",\n    sort: [{field: 'Due Date', direction: 'asc'}]\n  }).all();\n\n  return records;\n}\n\nasync function createTask(taskData: Partial<Task>) {\n  const record = await tasksTable.create(taskData);\n  return record;\n}\n```\n\n## Common Formulas Reference\n\n```javascript\n// Exact match\n\"{Status} = 'Active'\"\n\n// Not equal\n\"{Status} != 'Done'\"\n\n// Greater than / Less than\n\"{Price} > 100\"\n\"{Stock} <= 10\"\n\n// String contains (case-sensitive)\n\"FIND('urgent', {Notes}) > 0\"\n\n// String contains (case-insensitive)\n\"SEARCH('urgent', LOWER({Notes})) > 0\"\n\n// Is empty\n\"{Email} = ''\"\n\"OR({Email} = BLANK())\"\n\n// Is not empty\n\"NOT({Email} = '')\"\n\"{Email} != ''\"\n\n// AND condition\n\"AND({Status} = 'Active', {Priority} = 'High')\"\n\n// OR condition\n\"OR({Status} = 'Urgent', {Priority} = 'High')\"\n\n// Date comparisons\n\"{Created} > '2025-01-01'\"\n\"{Due Date} < TODAY()\"\n\"{Modified} >= DATEADD(TODAY(), -7, 'days')\"\n\n// Multiple conditions\n\"AND({Status} = 'Active', OR({Priority} = 'High', {Due Date} < TODAY()))\"\n\n// Check if field is in a list\n\"OR({Status} = 'Active', {Status} = 'In Progress', {Status} = 'Review')\"\n\n// Numeric range\n\"AND({Price} >= 10, {Price} <= 100)\"\n```\n"
  },
  {
    "path": "content/airtable/docs/database/python/DOC.md",
    "content": "---\nname: database\ndescription: \"Airtable Python SDK (pyairtable) — use the official pyairtable package for Airtable API operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"airtable,database,low-code,spreadsheet,api\"\n---\n\n# Airtable Python SDK (pyairtable) - Version 3.1.1\n\n## Golden Rule\n\n**ALWAYS use the official `pyairtable` package (version 3.1.1 or later)**\n\n```bash\npip install pyairtable\n```\n\n**DO NOT use:**\n- Deprecated packages like `airtable` (v0.4.8, last updated 2021)\n- `airtable-python-wrapper` (v0.15.3, now renamed to pyairtable)\n- `python-airtable` or other unofficial wrappers\n- The old API key authentication method (deprecated as of February 1, 2024)\n\n**ALWAYS use Personal Access Tokens (PATs) for authentication**, not the deprecated API keys.\n\n**NOTE:** `pyairtable` is the current and actively maintained name for what was previously called `airtable-python-wrapper`.\n\n## Installation\n\n```bash\npip install pyairtable\n```\n\n### Environment Variable Setup\n\nCreate a `.env` file:\n\n```bash\nAIRTABLE_API_KEY=your_personal_access_token_here\n```\n\nFor production applications, use proper secret management systems.\n\n## Authentication & Initialization\n\n### Personal Access Token Setup\n\n1. Visit https://airtable.com/create/tokens to create a Personal Access Token\n2. Name your token (e.g., \"My App Token\")\n3. Add required scopes:\n   - `data.records:read` - to read records\n   - `data.records:write` - to create/update/delete records\n   - `schema.bases:read` - to read base structure\n   - `schema.bases:write` - to modify base structure (optional)\n4. Select base access level (specific bases or all workspace bases)\n5. Copy the token immediately (shown only once)\n\n### Basic Configuration\n\n**Option 1: Direct Token Initialization**\n\n```python\nfrom pyairtable import Api\n\napi = Api('your_personal_access_token')\ntable = api.table('appExampleBaseId', 'tblExampleTableId')\n```\n\n**Option 2: Environment Variable**\n\n```python\nimport os\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\ntable = api.table('appExampleBaseId', 'Table Name')\n```\n\n**Option 3: Using Base Instance**\n\n```python\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\nbase = api.base('appExampleBaseId')\ntable = base.table('Table Name')\n```\n\n### Advanced Configuration\n\n```python\nfrom pyairtable import Api, retry_strategy\n\n# Custom timeout (connect_timeout, read_timeout)\napi = Api('token', timeout=(2, 5))\n\n# Enable retry strategy for rate limiting\napi = Api('token', retry_strategy=True)\n\n# Custom retry strategy\ncustom_retry = retry_strategy(\n    total=10,\n    status_forcelist=(429, 500, 502, 503, 504),\n    backoff_factor=0.2\n)\napi = Api('token', retry_strategy=custom_retry)\n\n# Disable retries\napi = Api('token', retry_strategy=None)\n```\n\n### Finding Your Base and Table IDs\n\n1. Go to https://airtable.com/api\n2. Select your base\n3. Base ID format: `appXXXXXXXXXXXXXX`\n4. Table ID format: `tblXXXXXXXXXXXXXX` (or use table name as string)\n\n## Core API Surfaces\n\n### Reading Records\n\n#### Get Single Record by ID\n\n```python\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\ntable = api.table('appBaseId', 'Tasks')\n\n# Get single record\nrecord = table.get('recwPQIfs4wKPyc9D')\n\nprint(f\"Record ID: {record['id']}\")\nprint(f\"Name: {record['fields']['Name']}\")\nprint(f\"Status: {record['fields']['Status']}\")\nprint(f\"Created: {record['createdTime']}\")\n\n# Access all fields\nfields = record['fields']\nfor field_name, value in fields.items():\n    print(f\"{field_name}: {value}\")\n```\n\n#### Get All Records\n\n```python\n# Get all records from table\nall_records = table.all()\n\nfor record in all_records:\n    print(f\"ID: {record['id']}\")\n    print(f\"Name: {record['fields']['Name']}\")\n\n# With view parameter\nview_records = table.all(view='Active Tasks')\n\n# With specific fields only\nlimited_fields = table.all(fields=['Name', 'Status', 'Priority'])\n\n# With max records limit\nlimited_records = table.all(max_records=50)\n\n# Combine multiple parameters\nfiltered_records = table.all(\n    view='Active Tasks',\n    fields=['Name', 'Status'],\n    max_records=100\n)\n```\n\n#### Get First Matching Record\n\n```python\n# Get first record matching formula\nfirst_record = table.first(formula=\"{Status} = 'Active'\")\n\nif first_record:\n    print(f\"Found: {first_record['fields']['Name']}\")\nelse:\n    print(\"No matching record found\")\n\n# With view\nfirst_in_view = table.first(view='High Priority')\n\n# With sort\nfirst_sorted = table.first(\n    formula=\"{Priority} = 'High'\",\n    sort=['Due Date']\n)\n```\n\n#### Iterate Through Pages\n\n```python\n# Iterate through paginated results\nfor page in table.iterate(page_size=100):\n    for record in page:\n        print(f\"Processing: {record['fields']['Name']}\")\n\n# With formula filter\nfor page in table.iterate(\n    formula=\"{Status} = 'Active'\",\n    page_size=50\n):\n    process_records(page)\n```\n\n### Filtering Records\n\n#### Using Formula Parameter\n\n```python\n# Simple equality\nactive_tasks = table.all(formula=\"{Status} = 'Active'\")\n\n# Multiple conditions with AND\nhigh_priority = table.all(\n    formula=\"AND({Status} = 'Active', {Priority} = 'High')\"\n)\n\n# Multiple conditions with OR\nurgent_or_blocked = table.all(\n    formula=\"OR({Status} = 'Urgent', {Status} = 'Blocked')\"\n)\n\n# Not empty check\nwith_titles = table.all(formula=\"NOT({Title} = '')\")\n\n# Greater than comparison\nrecent_tasks = table.all(formula=\"{Created} > '2025-01-01'\")\n\n# Dynamic formula with variables\nemail = 'user@example.com'\nuser_records = table.all(formula=f\"{{Email}} = '{email}'\")\n\n# Complex nested formula\ncomplex = table.all(\n    formula=\"\"\"\n    AND(\n        {Status} = 'In Progress',\n        {Priority} = 'High',\n        {Assignee} != '',\n        {Due Date} <= TODAY()\n    )\n    \"\"\"\n)\n\n# String search (case-insensitive)\nsearch_term = 'urgent'\nsearch_results = table.all(\n    formula=f\"SEARCH(LOWER('{search_term}'), LOWER({{Notes}})) > 0\"\n)\n```\n\n#### Using Formula Helpers\n\n```python\nfrom pyairtable.formulas import match, EQUAL, AND, OR, NOT, IF\n\n# Simple match\nformula = match({'Status': 'Active'})\nrecords = table.all(formula=formula)\n\n# Multiple field match (AND)\nformula = match({'Status': 'Active', 'Priority': 'High'})\nrecords = table.all(formula=formula)\n\n# Using formula operators\nformula = AND(\n    EQUAL('Status', 'Active'),\n    EQUAL('Priority', 'High')\n)\nrecords = table.all(formula=str(formula))\n\n# OR condition\nformula = OR(\n    EQUAL('Status', 'Urgent'),\n    EQUAL('Status', 'Blocked')\n)\nrecords = table.all(formula=str(formula))\n\n# NOT condition\nformula = NOT(EQUAL('Status', 'Done'))\nrecords = table.all(formula=str(formula))\n\n# Complex formula with IF\nfrom pyairtable.formulas import IF, GT\n\nformula = IF(\n    GT('Price', 100),\n    'Expensive',\n    'Affordable'\n)\n```\n\n### Sorting Records\n\n```python\n# Sort by single field (ascending)\nsorted_asc = table.all(sort=['Name'])\n\n# Sort by single field (descending)\nsorted_desc = table.all(sort=['-Created'])\n\n# Sort by multiple fields\nmulti_sort = table.all(\n    sort=['-Priority', 'Due Date', 'Name']\n)\n\n# Combine with filter and fields\nfiltered_sorted = table.all(\n    formula=\"{Status} = 'Active'\",\n    sort=['-Priority', 'Due Date'],\n    fields=['Name', 'Status', 'Priority']\n)\n```\n\n### Creating Records\n\n#### Create Single Record\n\n```python\n# Basic create\nnew_record = table.create({\n    'Name': 'New Task',\n    'Status': 'To Do',\n    'Priority': 'Medium'\n})\n\nprint(f\"Created record: {new_record['id']}\")\nprint(f\"Name: {new_record['fields']['Name']}\")\n\n# Create with all field types\nrecord = table.create({\n    'Name': 'Complete Task',\n    'Description': 'Long description here',\n    'Status': 'In Progress',\n    'Priority': 'High',\n    'Due Date': '2025-12-31',\n    'Completed': False,\n    'Tags': ['Important', 'Client'],\n    'Progress': 50\n})\n\n# With typecast (converts strings to appropriate types)\nrecord_typecast = table.create({\n    'Name': 'Task with Typecast',\n    'Due Date': '2025-12-31',  # String converted to date\n    'Count': '42'  # String converted to number\n}, typecast=True)\n```\n\n#### Batch Create (Multiple Records)\n\n```python\n# Create up to 10 records at once\nrecords = table.batch_create([\n    {'Name': 'Task 1', 'Status': 'To Do'},\n    {'Name': 'Task 2', 'Status': 'In Progress'},\n    {'Name': 'Task 3', 'Status': 'Done'},\n    {'Name': 'Task 4', 'Status': 'To Do'},\n    {'Name': 'Task 5', 'Status': 'Review'}\n])\n\nprint(f\"Created {len(records)} records\")\n\nfor record in records:\n    print(f\"Created: {record['id']} - {record['fields']['Name']}\")\n\n# With typecast\nrecords_typecast = table.batch_create([\n    {'Name': 'Task 1', 'Count': '10'},\n    {'Name': 'Task 2', 'Count': '20'}\n], typecast=True)\n\n# Create more than 10 records (automatic batching)\nlarge_batch = [\n    {'Name': f'Task {i}', 'Status': 'To Do'}\n    for i in range(1, 51)\n]\n\n# Process in batches of 10\nall_created = []\nfor i in range(0, len(large_batch), 10):\n    batch = large_batch[i:i+10]\n    created = table.batch_create(batch)\n    all_created.extend(created)\n\nprint(f\"Created {len(all_created)} records total\")\n```\n\n### Updating Records\n\n#### Update Single Record (Partial Update)\n\n```python\n# Update specific fields only\nupdated = table.update('recXXXXXXXXXXXXXX', {\n    'Status': 'In Progress',\n    'Progress': 50\n})\n\nprint(f\"Updated: {updated['fields']['Status']}\")\n\n# Update multiple fields\nupdated = table.update('recXXXXXXXXXXXXXX', {\n    'Status': 'Done',\n    'Completed': True,\n    'Completed Date': '2025-10-25',\n    'Notes': 'Task completed successfully'\n})\n\n# With typecast\nupdated = table.update('recXXXXXXXXXXXXXX', {\n    'Count': '100',\n    'Due Date': '2025-12-31'\n}, typecast=True)\n```\n\n#### Replace Record (Full Update)\n\n```python\n# Replace entire record (fields not specified will be cleared)\nreplaced = table.update(\n    'recXXXXXXXXXXXXXX',\n    {\n        'Name': 'Completely New Task',\n        'Status': 'To Do'\n    },\n    replace=True\n)\n\n# All other fields will be cleared/empty\n```\n\n#### Batch Update (Multiple Records)\n\n```python\n# Update up to 10 records at once\nupdates = [\n    {\n        'id': 'recXXXXXXXXXXXXXX',\n        'fields': {'Status': 'Done'}\n    },\n    {\n        'id': 'recYYYYYYYYYYYYYY',\n        'fields': {'Status': 'In Progress', 'Progress': 75}\n    },\n    {\n        'id': 'recZZZZZZZZZZZZZZ',\n        'fields': {'Status': 'To Do'}\n    }\n]\n\nupdated_records = table.batch_update(updates)\nprint(f\"Updated {len(updated_records)} records\")\n\n# With typecast\nupdated_typecast = table.batch_update([\n    {\n        'id': 'recXXXXXXXXXXXXXX',\n        'fields': {'Count': '100'}\n    }\n], typecast=True)\n\n# Batch update more than 10 records\nrecord_ids = ['rec1', 'rec2', 'rec3', ...]  # List of many IDs\nall_updated = []\n\nfor i in range(0, len(record_ids), 10):\n    batch_ids = record_ids[i:i+10]\n    batch_updates = [\n        {\n            'id': record_id,\n            'fields': {'Status': 'Archived'}\n        }\n        for record_id in batch_ids\n    ]\n    updated = table.batch_update(batch_updates)\n    all_updated.extend(updated)\n```\n\n#### Upsert Operations (Update or Insert)\n\n```python\n# Upsert based on key fields\nupsert_result = table.batch_upsert(\n    [\n        {'Email': 'john@example.com', 'Name': 'John Doe', 'Status': 'Active'},\n        {'Email': 'jane@example.com', 'Name': 'Jane Smith', 'Status': 'Active'}\n    ],\n    key_fields=['Email']\n)\n\nprint(f\"Created: {len(upsert_result['createdRecords'])}\")\nprint(f\"Updated: {len(upsert_result['updatedRecords'])}\")\n\n# Upsert with multiple key fields\nupsert_result = table.batch_upsert(\n    [\n        {\n            'First Name': 'John',\n            'Last Name': 'Doe',\n            'Email': 'john@example.com',\n            'Company': 'Acme Inc'\n        }\n    ],\n    key_fields=['First Name', 'Last Name']\n)\n\n# With typecast\nupsert_typecast = table.batch_upsert(\n    [{'Email': 'user@example.com', 'Count': '50'}],\n    key_fields=['Email'],\n    typecast=True\n)\n```\n\n### Deleting Records\n\n#### Delete Single Record\n\n```python\n# Delete by record ID\ndeleted = table.delete('recwPQIfs4wKPyc9D')\n\nprint(f\"Deleted record: {deleted['id']}\")\nprint(f\"Deleted: {deleted['deleted']}\")  # True\n\n# Check if deletion was successful\nif deleted['deleted']:\n    print(\"Record successfully deleted\")\n```\n\n#### Batch Delete (Multiple Records)\n\n```python\n# Delete up to 10 records at once\ndeleted_records = table.batch_delete([\n    'recXXXXXXXXXXXXXX',\n    'recYYYYYYYYYYYYYY',\n    'recZZZZZZZZZZZZZZ'\n])\n\nprint(f\"Deleted {len(deleted_records)} records\")\n\nfor record in deleted_records:\n    print(f\"Deleted: {record['id']}\")\n\n# Delete more than 10 records\nrecord_ids = ['rec1', 'rec2', 'rec3', ...]  # Many record IDs\nall_deleted = []\n\nfor i in range(0, len(record_ids), 10):\n    batch = record_ids[i:i+10]\n    deleted = table.batch_delete(batch)\n    all_deleted.extend(deleted)\n\nprint(f\"Deleted {len(all_deleted)} records total\")\n```\n\n### Working with Different Field Types\n\n#### Text Fields\n\n```python\nrecord = table.create({\n    'Single Line Text': 'Short text',\n    'Long Text': 'This is a much longer text\\nwith multiple lines',\n    'Email': 'user@example.com',\n    'URL': 'https://example.com',\n    'Phone': '+1-555-0100'\n})\n```\n\n#### Number Fields\n\n```python\nrecord = table.create({\n    'Number': 42,\n    'Currency': 99.99,\n    'Percent': 0.75,\n    'Rating': 5\n})\n```\n\n#### Date and Time Fields\n\n```python\nfrom datetime import datetime, date\n\nrecord = table.create({\n    'Date': '2025-10-25',\n    'DateTime': '2025-10-25T14:30:00.000Z',\n    'Date Object': date(2025, 10, 25).isoformat(),\n    'DateTime Object': datetime.now().isoformat()\n})\n\n# Access date fields\ndate_value = record['fields']['Date']\nprint(f\"Date: {date_value}\")\n```\n\n#### Checkbox (Boolean) Fields\n\n```python\nrecord = table.create({\n    'Completed': True,\n    'Active': False\n})\n\n# Access checkbox\nis_completed = record['fields']['Completed']\nif is_completed:\n    print('Task is completed')\n```\n\n#### Single Select Fields\n\n```python\nrecord = table.create({\n    'Status': 'In Progress',  # Must match exact option name\n    'Priority': 'High'\n})\n```\n\n#### Multiple Select Fields\n\n```python\nrecord = table.create({\n    'Tags': ['Important', 'Urgent', 'Client Work']\n})\n\n# Access multiple select\ntags = record['fields']['Tags']\nprint(f\"Tags: {', '.join(tags)}\")\n```\n\n#### Attachment Fields\n\n```python\nrecord = table.create({\n    'Attachments': [\n        {'url': 'https://example.com/image.jpg'},\n        {'url': 'https://example.com/document.pdf'}\n    ]\n})\n\n# Access attachments\nattachments = record['fields']['Attachments']\nfor attachment in attachments:\n    print(f\"File: {attachment['filename']}\")\n    print(f\"URL: {attachment['url']}\")\n    print(f\"Size: {attachment['size']}\")\n    print(f\"Type: {attachment['type']}\")\n```\n\n#### Upload Attachments\n\n```python\n# Upload from file path\nresult = table.upload_attachment(\n    'recAdw9EjV90xbZ',\n    'Attachments',\n    '/tmp/example.jpg'\n)\n\n# Upload from bytes/content\nwith open('/tmp/photo.jpg', 'rb') as f:\n    content = f.read()\n\nresult = table.upload_attachment(\n    'recAdw9EjV90xbZ',\n    'Attachments',\n    'photo.jpg',\n    content=content,\n    content_type='image/jpeg'\n)\n```\n\n#### Linked Record Fields\n\n```python\n# Link to existing records by their IDs\nrecord = table.create({\n    'Name': 'Task with Links',\n    'Related Tasks': [\n        'recXXXXXXXXXXXXXX',\n        'recYYYYYYYYYYYYYY'\n    ]\n})\n\n# Access linked records\nlinked_records = record['fields']['Related Tasks']\nprint(f\"Linked record IDs: {linked_records}\")\n```\n\n#### Collaborator Fields\n\n```python\nrecord = table.create({\n    'Assignee': {\n        'id': 'usrXXXXXXXXXXXXXX',\n        'email': 'user@example.com'\n    },\n    'Collaborators': [\n        {'id': 'usrXXXXXXXXXXXXXX'},\n        {'id': 'usrYYYYYYYYYYYYYY'}\n    ]\n})\n```\n\n### Working with Comments\n\n```python\n# Get all comments on a record\ncomments = table.comments('recMNxslc6jG0XedV')\n\nfor comment in comments:\n    print(f\"Author: {comment['author']['email']}\")\n    print(f\"Text: {comment['text']}\")\n    print(f\"Created: {comment['createdTime']}\")\n\n# Add comment\ncomment = table.add_comment(\n    'recMNxslc6jG0XedV',\n    'This is a comment'\n)\n\n# Add comment with user mention\ncomment = table.add_comment(\n    'recMNxslc6jG0XedV',\n    'Hello, @[usrVMNxslc6jG0Xed]! Please review this.'\n)\n```\n\n## ORM (Object-Relational Mapping)\n\npyairtable provides ORM-style classes for type-safe database operations.\n\n### Basic ORM Usage\n\n```python\nfrom pyairtable.orm import Model, fields\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\n\n# Define model\nclass Task(Model):\n    name = fields.TextField('Name')\n    status = fields.SelectField('Status')\n    priority = fields.SelectField('Priority')\n    due_date = fields.DateField('Due Date')\n    completed = fields.CheckboxField('Completed')\n    tags = fields.MultipleSelectField('Tags')\n\n    class Meta:\n        base_id = 'appYourBaseId'\n        table_name = 'Tasks'\n        api_key = os.environ['AIRTABLE_API_KEY']\n\n# Create record\ntask = Task(\n    name='New Task',\n    status='To Do',\n    priority='High',\n    due_date='2025-12-31'\n)\ntask.save()\n\nprint(f\"Created task: {task.id}\")\n\n# Retrieve all records\nall_tasks = Task.all()\n\nfor task in all_tasks:\n    print(f\"{task.name}: {task.status}\")\n\n# Find by ID\ntask = Task.from_id('recXXXXXXXXXXXXXX')\n\n# Update record\ntask.status = 'Done'\ntask.completed = True\ntask.save()\n\n# Delete record\ntask.delete()\n```\n\n### ORM with Relationships\n\n```python\nfrom pyairtable.orm import Model, fields\n\nclass Project(Model):\n    name = fields.TextField('Name')\n    description = fields.TextField('Description')\n    tasks = fields.LinkField('Tasks', 'Task', lazy=True)\n\n    class Meta:\n        base_id = 'appYourBaseId'\n        table_name = 'Projects'\n        api_key = os.environ['AIRTABLE_API_KEY']\n\nclass Task(Model):\n    name = fields.TextField('Name')\n    status = fields.SelectField('Status')\n    project = fields.LinkField('Project', 'Project', lazy=True)\n\n    class Meta:\n        base_id = 'appYourBaseId'\n        table_name = 'Tasks'\n        api_key = os.environ['AIRTABLE_API_KEY']\n\n# Create linked records\nproject = Project(name='New Project', description='Project description')\nproject.save()\n\ntask = Task(name='Task 1', status='To Do')\ntask.project = [project]\ntask.save()\n\n# Access linked records\nfor task in project.tasks:\n    print(f\"Task: {task.name}\")\n```\n\n## Schema Management\n\n### Get Base Schema\n\n```python\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\nbase = api.base('appYourBaseId')\n\n# Get complete base schema\nschema = base.schema()\n\n# List all tables\nfor table_schema in schema.tables:\n    print(f\"Table: {table_schema.name}\")\n    print(f\"ID: {table_schema.id}\")\n\n# Get specific table schema\ntable_schema = schema.table('tblXXXXXXXXXXXXXX')\nprint(f\"Table name: {table_schema.name}\")\n\n# List fields\nfor field in table_schema.fields:\n    print(f\"Field: {field.name} ({field.type})\")\n```\n\n### Get Table Schema\n\n```python\ntable = api.table('appYourBaseId', 'Tasks')\n\n# Get table schema\nschema = table.schema()\n\nprint(f\"Table name: {schema.name}\")\nprint(f\"Table ID: {schema.id}\")\nprint(f\"Primary field: {schema.primary_field_id}\")\n\n# List all fields\nfor field in schema.fields:\n    print(f\"Field: {field.name}\")\n    print(f\"Type: {field.type}\")\n    print(f\"ID: {field.id}\")\n\n    # Access field options\n    if hasattr(field, 'options'):\n        print(f\"Options: {field.options}\")\n```\n\n### Create Table\n\n```python\nbase = api.base('appYourBaseId')\n\n# Create new table with fields\nnew_table = base.create_table(\n    'Employees',\n    fields=[\n        {\n            'name': 'Name',\n            'type': 'singleLineText'\n        },\n        {\n            'name': 'Email',\n            'type': 'email'\n        },\n        {\n            'name': 'Department',\n            'type': 'singleSelect',\n            'options': {\n                'choices': [\n                    {'name': 'Engineering'},\n                    {'name': 'Sales'},\n                    {'name': 'Marketing'}\n                ]\n            }\n        },\n        {\n            'name': 'Start Date',\n            'type': 'date'\n        },\n        {\n            'name': 'Active',\n            'type': 'checkbox'\n        }\n    ]\n)\n\nprint(f\"Created table: {new_table.id}\")\n```\n\n### Create Field\n\n```python\ntable = api.table('appYourBaseId', 'Tasks')\n\n# Create single line text field\nfield = table.create_field('Description', 'singleLineText')\n\n# Create single select field with options\nfield = table.create_field(\n    'Status',\n    'singleSelect',\n    options={\n        'choices': [\n            {'name': 'To Do'},\n            {'name': 'In Progress'},\n            {'name': 'Done'}\n        ]\n    }\n)\n\n# Create multiple select field\nfield = table.create_field(\n    'Tags',\n    'multipleSelects',\n    options={\n        'choices': [\n            {'name': 'Important'},\n            {'name': 'Urgent'},\n            {'name': 'Low Priority'}\n        ]\n    }\n)\n\n# Create number field\nfield = table.create_field(\n    'Progress',\n    'number',\n    options={'precision': 0}\n)\n\n# Create date field\nfield = table.create_field('Due Date', 'date')\n\n# Create checkbox field\nfield = table.create_field('Completed', 'checkbox')\n```\n\n## Workspace and Base Management\n\n### List All Bases\n\n```python\napi = Api(os.environ['AIRTABLE_API_KEY'])\n\n# List all accessible bases\nbases = api.bases()\n\nfor base in bases:\n    print(f\"Base: {base.name}\")\n    print(f\"ID: {base.id}\")\n```\n\n### Create Base\n\n```python\n# Create new base in workspace\nnew_base = api.create_base(\n    workspace_id='wspMhESAta6clCCwF',\n    name='My New Project Base',\n    tables=[\n        {\n            'name': 'Tasks',\n            'fields': [\n                {'name': 'Name', 'type': 'singleLineText'},\n                {'name': 'Status', 'type': 'singleSelect', 'options': {\n                    'choices': [{'name': 'To Do'}, {'name': 'Done'}]\n                }}\n            ]\n        }\n    ]\n)\n\nprint(f\"Created base: {new_base.id}\")\n```\n\n### Workspace Operations\n\n```python\nworkspace = api.workspace('wspmhESAta6clCCwF')\n\n# Create base in workspace\nnew_base = workspace.create_base(\n    'New Project',\n    tables=[\n        {\n            'name': 'Table 1',\n            'fields': [{'name': 'Name', 'type': 'singleLineText'}]\n        }\n    ]\n)\n\n# Get workspace collaborators\ncollaborators = workspace.collaborators()\n\nfor collab in collaborators:\n    print(f\"User: {collab.user.email}\")\n    print(f\"Permission: {collab.permission_level}\")\n\n# Move base to different workspace\nworkspace.move_base('appCwFmhESAta6clC', 'wspTargetWorkspace')\n```\n\n## Webhooks\n\n### List Webhooks\n\n```python\nbase = api.base('appYourBaseId')\n\n# Get all webhooks\nwebhooks = base.webhooks()\n\nfor webhook in webhooks:\n    print(f\"Webhook ID: {webhook.id}\")\n    print(f\"URL: {webhook.notification_url}\")\n```\n\n### Get Webhook\n\n```python\n# Get specific webhook\nwebhook = base.webhook('ach00000000000001')\n\nprint(f\"Webhook URL: {webhook.notification_url}\")\nprint(f\"Cursor: {webhook.cursor}\")\n```\n\n### Create Webhook\n\n```python\n# Create webhook\nwebhook = base.add_webhook(\n    'https://example.com/webhook',\n    {\n        'options': {\n            'filters': {\n                'dataTypes': ['tableData']\n            }\n        }\n    }\n)\n\nprint(f\"Created webhook: {webhook.id}\")\n```\n\n## Enterprise Features\n\n### Enterprise API Access\n\n```python\n# Access enterprise features\nenterprise = api.enterprise('entUBq2RGdihxl3vU')\n\n# Get enterprise info\ninfo = enterprise.info()\nprint(f\"Enterprise: {info.workspace_ids}\")\n\n# Iterate through audit log\nfor page in enterprise.audit_log(sort_asc=True, page_size=50):\n    for event in page.events:\n        print(f\"Event: {event.action}\")\n        print(f\"Actor: {event.actor.email}\")\n        print(f\"Timestamp: {event.timestamp}\")\n\n# User management\nusers = enterprise.users(['usrID1', 'email@example.com'])\n\nfor user in users:\n    print(f\"User: {user.email}\")\n    print(f\"State: {user.state}\")\n\n# Grant admin access\nenterprise.grant_admin('usrID1', 'usrID2')\n\n# Remove from enterprise\nenterprise.remove_user(['usrID1'])\n```\n\n## Complete Examples\n\n### Example 1: Task Management System\n\n```python\nimport os\nfrom pyairtable import Api\nfrom datetime import datetime, timedelta\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\ntable = api.table('appTaskManager', 'Tasks')\n\ndef create_task(name, description, priority='Medium', assignee=None, due_date=None):\n    \"\"\"Create a new task\"\"\"\n    task_data = {\n        'Name': name,\n        'Description': description,\n        'Status': 'To Do',\n        'Priority': priority,\n        'Created': datetime.now().isoformat()\n    }\n\n    if assignee:\n        task_data['Assignee'] = assignee\n\n    if due_date:\n        task_data['Due Date'] = due_date\n\n    record = table.create(task_data)\n    print(f\"Created task: {record['id']}\")\n    return record\n\ndef get_active_tasks():\n    \"\"\"Get all tasks that are not done or cancelled\"\"\"\n    records = table.all(\n        formula=\"AND({Status} != 'Done', {Status} != 'Cancelled')\",\n        sort=['-Priority', 'Due Date']\n    )\n\n    tasks = []\n    for record in records:\n        tasks.append({\n            'id': record['id'],\n            'name': record['fields']['Name'],\n            'status': record['fields']['Status'],\n            'priority': record['fields'].get('Priority', 'Medium'),\n            'assignee': record['fields'].get('Assignee'),\n            'due_date': record['fields'].get('Due Date')\n        })\n\n    return tasks\n\ndef update_task_status(task_id, new_status):\n    \"\"\"Update task status\"\"\"\n    updated = table.update(task_id, {\n        'Status': new_status,\n        'Last Modified': datetime.now().isoformat()\n    })\n\n    if new_status == 'Done':\n        table.update(task_id, {\n            'Completed': True,\n            'Completed Date': datetime.now().isoformat()\n        })\n\n    print(f\"Updated task {task_id} to {new_status}\")\n    return updated\n\ndef get_overdue_tasks():\n    \"\"\"Get all overdue tasks\"\"\"\n    today = datetime.now().date().isoformat()\n\n    records = table.all(\n        formula=f\"AND({{Status}} != 'Done', {{Due Date}} < '{today}')\",\n        sort=['Due Date']\n    )\n\n    return records\n\ndef bulk_update_status(task_ids, new_status):\n    \"\"\"Update multiple tasks at once\"\"\"\n    updates = [\n        {\n            'id': task_id,\n            'fields': {\n                'Status': new_status,\n                'Last Modified': datetime.now().isoformat()\n            }\n        }\n        for task_id in task_ids\n    ]\n\n    # Process in batches of 10\n    all_updated = []\n    for i in range(0, len(updates), 10):\n        batch = updates[i:i+10]\n        updated = table.batch_update(batch)\n        all_updated.extend(updated)\n\n    print(f\"Updated {len(all_updated)} tasks\")\n    return all_updated\n\ndef delete_old_completed_tasks(days=30):\n    \"\"\"Delete completed tasks older than specified days\"\"\"\n    cutoff_date = (datetime.now() - timedelta(days=days)).date().isoformat()\n\n    records = table.all(\n        formula=f\"AND({{Status}} = 'Done', {{Completed Date}} < '{cutoff_date}')\"\n    )\n\n    record_ids = [record['id'] for record in records]\n\n    # Delete in batches of 10\n    for i in range(0, len(record_ids), 10):\n        batch = record_ids[i:i+10]\n        table.batch_delete(batch)\n\n    print(f\"Deleted {len(record_ids)} old completed tasks\")\n\ndef get_tasks_by_assignee(assignee_email):\n    \"\"\"Get all tasks for a specific assignee\"\"\"\n    records = table.all(\n        formula=f\"{{Assignee}} = '{assignee_email}'\",\n        sort=['-Priority', 'Due Date']\n    )\n\n    return records\n\n# Usage examples\nif __name__ == '__main__':\n    # Create new task\n    task = create_task(\n        name='Complete project documentation',\n        description='Write comprehensive docs for the project',\n        priority='High',\n        due_date='2025-11-01'\n    )\n\n    # Get active tasks\n    active = get_active_tasks()\n    print(f\"Found {len(active)} active tasks\")\n\n    # Update task status\n    # update_task_status(task['id'], 'In Progress')\n\n    # Get overdue tasks\n    overdue = get_overdue_tasks()\n    print(f\"Found {len(overdue)} overdue tasks\")\n\n    # Bulk update\n    # task_ids = ['rec1', 'rec2', 'rec3']\n    # bulk_update_status(task_ids, 'Done')\n```\n\n### Example 2: Contact Management with Upsert\n\n```python\nimport os\nfrom pyairtable import Api\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\ntable = api.table('appContactManager', 'Contacts')\n\ndef find_contact_by_email(email):\n    \"\"\"Find contact by email address\"\"\"\n    record = table.first(formula=f\"{{Email}} = '{email}'\")\n    return record\n\ndef upsert_contact(contact_data):\n    \"\"\"Create or update contact based on email\"\"\"\n    result = table.batch_upsert(\n        [contact_data],\n        key_fields=['Email']\n    )\n\n    if result['createdRecords']:\n        print(f\"Created new contact: {result['createdRecords'][0]['id']}\")\n        return {'action': 'created', 'record': result['createdRecords'][0]}\n    else:\n        print(f\"Updated existing contact: {result['updatedRecords'][0]['id']}\")\n        return {'action': 'updated', 'record': result['updatedRecords'][0]}\n\ndef get_contacts_by_company(company_name):\n    \"\"\"Get all contacts from a specific company\"\"\"\n    records = table.all(\n        formula=f\"{{Company}} = '{company_name}'\",\n        sort=['Last Name', 'First Name']\n    )\n\n    contacts = []\n    for record in records:\n        contacts.append({\n            'id': record['id'],\n            'name': f\"{record['fields']['First Name']} {record['fields']['Last Name']}\",\n            'email': record['fields']['Email'],\n            'phone': record['fields'].get('Phone'),\n            'company': record['fields']['Company']\n        })\n\n    return contacts\n\ndef batch_import_contacts(contacts_list):\n    \"\"\"Import multiple contacts with upsert\"\"\"\n    result = table.batch_upsert(\n        contacts_list,\n        key_fields=['Email']\n    )\n\n    print(f\"Created: {len(result['createdRecords'])}\")\n    print(f\"Updated: {len(result['updatedRecords'])}\")\n\n    return result\n\ndef export_all_contacts():\n    \"\"\"Export all contacts to list\"\"\"\n    all_contacts = []\n\n    for page in table.iterate(page_size=100):\n        for record in page:\n            all_contacts.append({\n                'id': record['id'],\n                'first_name': record['fields'].get('First Name'),\n                'last_name': record['fields'].get('Last Name'),\n                'email': record['fields'].get('Email'),\n                'phone': record['fields'].get('Phone'),\n                'company': record['fields'].get('Company'),\n                'created': record['createdTime']\n            })\n\n    return all_contacts\n\ndef tag_contacts(contact_ids, tags):\n    \"\"\"Add tags to multiple contacts\"\"\"\n    updates = [\n        {\n            'id': contact_id,\n            'fields': {'Tags': tags}\n        }\n        for contact_id in contact_ids\n    ]\n\n    # Process in batches of 10\n    all_updated = []\n    for i in range(0, len(updates), 10):\n        batch = updates[i:i+10]\n        updated = table.batch_update(batch)\n        all_updated.extend(updated)\n\n    return all_updated\n\n# Usage examples\nif __name__ == '__main__':\n    # Upsert single contact\n    result = upsert_contact({\n        'First Name': 'John',\n        'Last Name': 'Doe',\n        'Email': 'john.doe@example.com',\n        'Phone': '+1-555-0100',\n        'Company': 'Acme Inc'\n    })\n\n    # Find contact by email\n    contact = find_contact_by_email('john.doe@example.com')\n    if contact:\n        print(f\"Found: {contact['fields']['First Name']} {contact['fields']['Last Name']}\")\n\n    # Get contacts by company\n    acme_contacts = get_contacts_by_company('Acme Inc')\n    print(f\"Found {len(acme_contacts)} contacts at Acme Inc\")\n\n    # Batch import\n    contacts_to_import = [\n        {\n            'First Name': 'Jane',\n            'Last Name': 'Smith',\n            'Email': 'jane@example.com',\n            'Company': 'Tech Corp'\n        },\n        {\n            'First Name': 'Bob',\n            'Last Name': 'Johnson',\n            'Email': 'bob@example.com',\n            'Company': 'Startup LLC'\n        }\n    ]\n    batch_import_contacts(contacts_to_import)\n\n    # Export all contacts\n    all_contacts = export_all_contacts()\n    print(f\"Exported {len(all_contacts)} contacts\")\n```\n\n### Example 3: E-commerce Inventory Management\n\n```python\nimport os\nfrom pyairtable import Api\nfrom datetime import datetime\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\nproducts_table = api.table('appInventory', 'Products')\norders_table = api.table('appInventory', 'Orders')\n\ndef check_inventory(product_id):\n    \"\"\"Check product availability\"\"\"\n    product = products_table.get(product_id)\n\n    return {\n        'id': product['id'],\n        'name': product['fields']['Name'],\n        'sku': product['fields']['SKU'],\n        'quantity': product['fields']['Quantity in Stock'],\n        'available': product['fields']['Quantity in Stock'] > 0,\n        'price': product['fields']['Price']\n    }\n\ndef update_stock_quantity(product_id, quantity_change):\n    \"\"\"Update stock after purchase or restock\"\"\"\n    product = products_table.get(product_id)\n    current_stock = product['fields']['Quantity in Stock']\n    new_stock = current_stock + quantity_change\n\n    if new_stock < 0:\n        raise ValueError(f\"Insufficient stock. Available: {current_stock}\")\n\n    updated = products_table.update(product_id, {\n        'Quantity in Stock': new_stock,\n        'Last Updated': datetime.now().isoformat()\n    })\n\n    print(f\"Updated stock for {product['fields']['Name']}: {current_stock} -> {new_stock}\")\n    return updated\n\ndef get_low_stock_products(threshold=10):\n    \"\"\"Get products below stock threshold\"\"\"\n    records = products_table.all(\n        formula=f\"{{Quantity in Stock}} < {threshold}\",\n        sort=['Quantity in Stock']\n    )\n\n    low_stock = []\n    for record in records:\n        low_stock.append({\n            'id': record['id'],\n            'name': record['fields']['Name'],\n            'sku': record['fields']['SKU'],\n            'quantity': record['fields']['Quantity in Stock'],\n            'reorder_level': record['fields'].get('Reorder Level', threshold)\n        })\n\n    return low_stock\n\ndef create_order(order_data):\n    \"\"\"Create order and update inventory\"\"\"\n    # Create order record\n    order = orders_table.create({\n        'Order Number': order_data['order_number'],\n        'Customer Name': order_data['customer_name'],\n        'Customer Email': order_data['customer_email'],\n        'Status': 'Pending',\n        'Total Amount': order_data['total_amount'],\n        'Order Date': datetime.now().isoformat()\n    })\n\n    # Update inventory for each product\n    try:\n        for item in order_data['items']:\n            update_stock_quantity(item['product_id'], -item['quantity'])\n\n        # Update order status to confirmed\n        orders_table.update(order['id'], {'Status': 'Confirmed'})\n\n        print(f\"Created order: {order['id']}\")\n        return order\n    except ValueError as e:\n        # Rollback: delete order if inventory update fails\n        orders_table.delete(order['id'])\n        raise e\n\ndef get_orders_by_status(status):\n    \"\"\"Get all orders with specific status\"\"\"\n    records = orders_table.all(\n        formula=f\"{{Status}} = '{status}'\",\n        sort=['-Order Date']\n    )\n\n    orders = []\n    for record in records:\n        orders.append({\n            'id': record['id'],\n            'order_number': record['fields']['Order Number'],\n            'customer': record['fields']['Customer Name'],\n            'total': record['fields']['Total Amount'],\n            'date': record['fields']['Order Date']\n        })\n\n    return orders\n\ndef restock_products(restock_list):\n    \"\"\"Bulk restock multiple products\"\"\"\n    updates = []\n\n    for item in restock_list:\n        product = products_table.get(item['product_id'])\n        current_stock = product['fields']['Quantity in Stock']\n        new_stock = current_stock + item['quantity']\n\n        updates.append({\n            'id': item['product_id'],\n            'fields': {\n                'Quantity in Stock': new_stock,\n                'Last Restocked': datetime.now().isoformat()\n            }\n        })\n\n    # Process in batches of 10\n    all_updated = []\n    for i in range(0, len(updates), 10):\n        batch = updates[i:i+10]\n        updated = products_table.batch_update(batch)\n        all_updated.extend(updated)\n\n    print(f\"Restocked {len(all_updated)} products\")\n    return all_updated\n\ndef get_sales_report(start_date, end_date):\n    \"\"\"Get orders within date range\"\"\"\n    records = orders_table.all(\n        formula=f\"AND({{Order Date}} >= '{start_date}', {{Order Date}} <= '{end_date}')\",\n        sort=['Order Date']\n    )\n\n    total_sales = sum(\n        record['fields']['Total Amount']\n        for record in records\n        if 'Total Amount' in record['fields']\n    )\n\n    return {\n        'total_orders': len(records),\n        'total_sales': total_sales,\n        'orders': records\n    }\n\n# Usage examples\nif __name__ == '__main__':\n    # Check inventory\n    inventory = check_inventory('recProductId123')\n    print(f\"{inventory['name']}: {inventory['quantity']} in stock\")\n\n    # Get low stock products\n    low_stock = get_low_stock_products(threshold=15)\n    print(f\"Found {len(low_stock)} products below threshold\")\n\n    # Create order\n    order_data = {\n        'order_number': 'ORD-2025-001',\n        'customer_name': 'John Doe',\n        'customer_email': 'john@example.com',\n        'total_amount': 299.99,\n        'items': [\n            {'product_id': 'recProduct1', 'quantity': 2},\n            {'product_id': 'recProduct2', 'quantity': 1}\n        ]\n    }\n    # create_order(order_data)\n\n    # Get pending orders\n    pending = get_orders_by_status('Pending')\n    print(f\"Found {len(pending)} pending orders\")\n\n    # Restock products\n    restock_list = [\n        {'product_id': 'recProduct1', 'quantity': 50},\n        {'product_id': 'recProduct2', 'quantity': 30}\n    ]\n    # restock_products(restock_list)\n```\n\n## Rate Limits and Error Handling\n\nAirtable enforces a rate limit of **5 requests per second per base**.\n\n### Automatic Retry with Rate Limiting\n\n```python\nfrom pyairtable import Api, retry_strategy\n\n# Enable automatic retry for rate limits\napi = Api(\n    os.environ['AIRTABLE_API_KEY'],\n    retry_strategy=True\n)\n\n# Custom retry configuration\ncustom_retry = retry_strategy(\n    total=10,\n    status_forcelist=(429, 500, 502, 503, 504),\n    backoff_factor=0.2\n)\n\napi = Api(\n    os.environ['AIRTABLE_API_KEY'],\n    retry_strategy=custom_retry\n)\n```\n\n### Manual Error Handling\n\n```python\nfrom pyairtable import Api\nfrom pyairtable.api.types import APIError\nimport time\n\napi = Api(os.environ['AIRTABLE_API_KEY'])\ntable = api.table('appBaseId', 'Tasks')\n\n# Basic error handling\ntry:\n    record = table.get('recXXXXXXXXXXXXXX')\nexcept APIError as e:\n    if e.status_code == 404:\n        print('Record not found')\n    elif e.status_code == 401:\n        print('Authentication failed')\n    elif e.status_code == 429:\n        print('Rate limit exceeded')\n    else:\n        print(f'API error: {e}')\nexcept Exception as e:\n    print(f'Unexpected error: {e}')\n\n# Retry with exponential backoff\ndef create_with_retry(record_data, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            return table.create(record_data)\n        except APIError as e:\n            if e.status_code == 429 and attempt < max_retries - 1:\n                wait_time = 2 ** attempt\n                print(f\"Rate limited. Retrying in {wait_time}s...\")\n                time.sleep(wait_time)\n            else:\n                raise\n\n# Comprehensive error handling\ndef safe_create(record_data):\n    try:\n        record = table.create(record_data)\n        return {'success': True, 'record': record}\n    except APIError as e:\n        return {\n            'success': False,\n            'error': {\n                'message': str(e),\n                'status_code': e.status_code,\n                'type': e.type\n            }\n        }\n    except Exception as e:\n        return {\n            'success': False,\n            'error': {\n                'message': str(e),\n                'type': 'unknown'\n            }\n        }\n```\n\n## Common Formulas Reference\n\n```python\n# Exact match\nformula = \"{Status} = 'Active'\"\n\n# Not equal\nformula = \"{Status} != 'Done'\"\n\n# Greater than / Less than\nformula = \"{Price} > 100\"\nformula = \"{Stock} <= 10\"\n\n# String contains (case-insensitive)\nformula = \"SEARCH('urgent', LOWER({Notes})) > 0\"\n\n# Is empty\nformula = \"{Email} = ''\"\nformula = \"OR({Email} = BLANK())\"\n\n# Is not empty\nformula = \"NOT({Email} = '')\"\nformula = \"{Email} != ''\"\n\n# AND condition\nformula = \"AND({Status} = 'Active', {Priority} = 'High')\"\n\n# OR condition\nformula = \"OR({Status} = 'Urgent', {Priority} = 'High')\"\n\n# Date comparisons\nformula = \"{Created} > '2025-01-01'\"\nformula = \"{Due Date} < TODAY()\"\nformula = \"{Modified} >= DATEADD(TODAY(), -7, 'days')\"\n\n# Multiple conditions\nformula = \"AND({Status} = 'Active', OR({Priority} = 'High', {Due Date} < TODAY()))\"\n\n# Check if field is in a list\nformula = \"OR({Status} = 'Active', {Status} = 'In Progress', {Status} = 'Review')\"\n\n# Numeric range\nformula = \"AND({Price} >= 10, {Price} <= 100)\"\n\n# Using variables\nemail = 'user@example.com'\nformula = f\"{{Email}} = '{email}'\"\n\nsearch_term = 'urgent'\nformula = f\"SEARCH(LOWER('{search_term}'), LOWER({{Notes}})) > 0\"\n```\n"
  },
  {
    "path": "content/albumentations/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Albumentations image augmentation library for Python computer vision pipelines\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.8\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"albumentations,computer-vision,image-augmentation,opencv,pytorch,augmentation\"\n---\n\n# Albumentations Python Package Guide\n\n## Golden Rule\n\nUse `albumentations` as `import albumentations as A`, pass NumPy arrays in HWC layout, convert OpenCV images from BGR to RGB before augmentation, and declare every synchronized target up front in one `A.Compose(...)` call. If you augment masks, bounding boxes, keypoints, or multiple images together, configure the corresponding target metadata explicitly instead of assuming transforms will infer it.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"albumentations==2.0.8\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"albumentations==2.0.8\"\npoetry add \"albumentations==2.0.8\"\n```\n\nPyPI publishes optional extras including `pytorch`, `text`, and `hub`:\n\n```bash\npython -m pip install \"albumentations[pytorch]==2.0.8\"\n```\n\nNotes:\n\n- `albumentations` works on NumPy arrays and is commonly paired with OpenCV, PyTorch, or other training frameworks.\n- If you use `albumentations.pytorch`, you still need a compatible `torch` install in your environment.\n- There is no API key or account setup. Configuration is entirely local Python code.\n\n## Initialize A Pipeline\n\nThe core abstraction is `A.Compose`, which applies the same random decisions to all declared targets in the sample.\n\n```python\nimport cv2\nimport albumentations as A\n\ntransform = A.Compose(\n    [\n        A.SmallestMaxSize(max_size=512),\n        A.RandomCrop(height=448, width=448),\n        A.HorizontalFlip(p=0.5),\n        A.RandomBrightnessContrast(p=0.2),\n    ],\n    strict=True,\n)\n\nimage = cv2.imread(\"image.jpg\")\nimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\naugmented = transform(image=image)\nimage_aug = augmented[\"image\"]\n```\n\nWhy `strict=True` matters:\n\n- it rejects unknown input keys instead of silently ignoring them\n- it catches misconfigured pipelines earlier\n- it is a good default for agent-written code\n\n## Core Usage\n\n### Image classification or generic image augmentation\n\n```python\nimport albumentations as A\n\ntrain_tf = A.Compose(\n    [\n        A.RandomResizedCrop(size=(224, 224), scale=(0.8, 1.0)),\n        A.HorizontalFlip(p=0.5),\n        A.Affine(scale=(0.9, 1.1), rotate=(-15, 15), p=0.5),\n        A.Normalize(),\n    ],\n    strict=True,\n)\n```\n\nCall it with `transform(image=image)` and read the result from `[\"image\"]`.\n\n### Semantic segmentation\n\nMasks stay synchronized automatically when you pass both `image` and `mask`. Geometric transforms affect both; image-only transforms such as `Normalize` affect the image and leave the mask untouched.\n\n```python\nimport albumentations as A\n\nseg_tf = A.Compose(\n    [\n        A.RandomCrop(height=512, width=512),\n        A.HorizontalFlip(p=0.5),\n        A.RandomRotate90(p=0.5),\n        A.Normalize(),\n    ],\n    strict=True,\n)\n\naugmented = seg_tf(image=image, mask=mask)\nimage_aug = augmented[\"image\"]\nmask_aug = augmented[\"mask\"]\n```\n\n### Object detection with bounding boxes\n\nDeclare bounding box metadata with `bbox_params`. Do not pass boxes without it.\n\n```python\nimport albumentations as A\n\ndet_tf = A.Compose(\n    [\n        A.Resize(height=640, width=640),\n        A.HorizontalFlip(p=0.5),\n        A.RandomBrightnessContrast(p=0.2),\n    ],\n    bbox_params=A.BboxParams(\n        format=\"coco\",\n        label_fields=[\"class_labels\"],\n        min_visibility=0.1,\n    ),\n    strict=True,\n)\n\naugmented = det_tf(\n    image=image,\n    bboxes=bboxes,\n    class_labels=class_labels,\n)\n```\n\nUse the bounding box format your data actually uses: `coco`, `pascal_voc`, `albumentations`, or `yolo`.\n\n### Keypoints\n\nKeypoints require their own metadata, just like bounding boxes:\n\n```python\nimport albumentations as A\n\nkp_tf = A.Compose(\n    [\n        A.Resize(height=256, width=256),\n        A.HorizontalFlip(p=0.5),\n    ],\n    keypoint_params=A.KeypointParams(format=\"xy\", remove_invisible=False),\n    strict=True,\n)\n\naugmented = kp_tf(image=image, keypoints=keypoints)\n```\n\n### Multiple images or extra targets\n\nIf you need identical augmentation decisions across multiple related arrays, use `additional_targets`.\n\n```python\nimport albumentations as A\n\nstereo_tf = A.Compose(\n    [\n        A.RandomCrop(height=256, width=256),\n        A.HorizontalFlip(p=0.5),\n    ],\n    additional_targets={\"right_image\": \"image\", \"depth\": \"mask\"},\n    strict=True,\n)\n\naugmented = stereo_tf(\n    image=left_image,\n    right_image=right_image,\n    depth=depth_map,\n)\n```\n\nMap each extra input to the correct target type:\n\n- use `\"image\"` for data that should receive image transforms\n- use `\"mask\"` for label-like arrays that must stay aligned but should not receive pixel normalization or color jitter\n\n## Configuration Notes\n\nThere is no remote configuration or authentication layer. The practical configuration knobs are the pipeline arguments and target metadata:\n\n- `strict=True`: fail fast on unknown inputs or invalid configuration\n- `bbox_params=...`: required for `bboxes`\n- `keypoint_params=...`: required for `keypoints`\n- `additional_targets=...`: required for multi-image or multi-mask synchronization\n- `seed=...` on `A.Compose(...)`: use when you need reproducible augmentation sequences\n- `save_applied_params=True`: use when you need to inspect the transforms and parameters that actually ran\n\nExample with reproducibility and transform inspection:\n\n```python\nimport albumentations as A\n\ntf = A.Compose(\n    [\n        A.HorizontalFlip(p=0.5),\n        A.RandomBrightnessContrast(p=0.5),\n    ],\n    seed=137,\n    save_applied_params=True,\n    strict=True,\n)\n\nresult = tf(image=image)\nprint(result[\"applied_transforms\"])\n```\n\n## Serialization\n\nUse Albumentations' built-in save/load helpers when you need to persist a pipeline definition:\n\n```python\nimport albumentations as A\n\ntransform = A.Compose(\n    [\n        A.Resize(height=256, width=256),\n        A.HorizontalFlip(p=0.5),\n    ],\n    strict=True,\n)\n\nA.save(transform, \"transform.json\")\nloaded = A.load(\"transform.json\")\n```\n\nIf you use `Lambda` transforms or other non-serializable callables, you must provide the `nonserializable` mapping when loading or avoid serializing that pipeline.\n\n## Common Pitfalls\n\n- OpenCV loads images as BGR. Convert to RGB before augmentation if the rest of your pipeline expects RGB.\n- Albumentations expects NumPy arrays, not PIL images. Convert before calling the transform.\n- Keep image, mask, bbox, and keypoint inputs shape-compatible. The FAQ explicitly calls out grayscale and shape-handling edge cases.\n- Do not send `bboxes` or `keypoints` without the corresponding `BboxParams` or `KeypointParams`.\n- Bounding box transforms only work for transforms that support that target type. Check the Supported Targets table before composing a pipeline.\n- Keep `label_fields` in sync with `bboxes`; otherwise label arrays can drift from the boxes that remain after filtering.\n- `Normalize` changes the image, not the mask. Do not manually normalize segmentation masks unless your downstream code explicitly needs that.\n- Use `additional_targets` when augmenting stereo pairs, restoration input/target pairs, or multiple masks together. Separate transform calls will not stay synchronized.\n\n## Version-Sensitive Notes For 2.0.8\n\n- `2.0.8` is the current `albumentations` package version on PyPI as of March 12, 2026.\n- The official GitHub release notes for `2.0.0` document the main breaking changes for all `2.x` users. In particular, `always_apply` was removed; use `p=1` for always-on transforms and `p=0` to disable one.\n- Several transforms changed parameter names in `2.0.0`. A common migration issue is `RandomResizedCrop`: old examples may show `height=` and `width=`, while the `2.0.0` release notes say the `2.x` API uses `size=(height, width)`.\n- `GaussNoise` changed from `var_limit` and `mean` to `std_range` and `mean_range`.\n- Several transforms changed default `border_mode` values to `cv2.BORDER_CONSTANT` in `2.0.0`. If your training data depended on old border behavior, set `border_mode` and fill values explicitly.\n- `2.0.8` added transforms such as `Mosaic` and `OverlayElements`, plus bug fixes around probabilistic composition and replay behavior. If you see examples from early `2.0.x`, prefer the `2.0.8` release notes and current API reference over third-party blog posts.\n- The repository was archived by the maintainers in July 2025. Treat unofficial community examples published before or during the transition carefully and prefer the official docs root, PyPI metadata, and official release notes.\n\n## Official Links\n\n- Docs root: https://albumentations.ai/docs/\n- FAQ: https://albumentations.ai/docs/faq/\n- Pipelines core concept: https://albumentations.ai/docs/2-core-concepts/pipelines/\n- Bounding boxes guide: https://albumentations.ai/docs/3-basic-usage/bounding-boxes-augmentations/\n- Segmentation guide: https://albumentations.ai/docs/3-basic-usage/semantic-segmentation/\n- Additional targets guide: https://albumentations.ai/docs/4-advanced-guides/additional-targets/\n- Serialization example: https://albumentations.ai/docs/examples/serialization/\n- PyPI package: https://pypi.org/project/albumentations/\n- GitHub releases: https://github.com/albumentations-team/albumentations/releases\n"
  },
  {
    "path": "content/alembic/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Alembic package guide for Python database schema migrations with SQLAlchemy\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.18.4\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"alembic,sqlalchemy,migrations,database,schema\"\n---\n\n# alembic Python Package Guide\n\n## What Alembic Is For\n\nAlembic is SQLAlchemy's migration tool for managing schema changes over time. Use it to:\n\n- initialize a migration environment for a project\n- generate revision files\n- autogenerate candidate schema diffs from SQLAlchemy metadata\n- upgrade or downgrade a database to a target revision\n- work with branched migration histories and merge points\n- emit SQL scripts instead of executing DDL directly\n\nAlembic is most effective when your application already has a clear SQLAlchemy metadata model and you treat generated migrations as drafts that still need review.\n\n## Version And Compatibility\n\n- Package covered: `alembic==1.18.4`\n- PyPI release date: `2026-02-10`\n- PyPI metadata for `1.18.4` requires Python `>=3.10`\n- Alembic docs still say Python `3.9+`; treat the PyPI package metadata as the safer installation requirement for this release\n- Alembic works with SQLAlchemy `>=1.4`\n\nAlembic does not follow SemVer. The docs explicitly describe the middle digit as a \"Significant Minor Release\", so pin by major/minor when you need stability:\n\n```bash\npip install \"alembic~=1.18.0\"\n```\n\n## Installation\n\n```bash\npip install \"alembic~=1.18.0\"\n```\n\nCommon project-level installs:\n\n```bash\nuv add \"alembic~=1.18.0\"\npoetry add \"alembic~=1.18.0\"\n```\n\nIf your project uses async SQLAlchemy drivers, you still install normal `alembic`; the async behavior comes from the generated `env.py` template and SQLAlchemy async engine setup.\n\n## Initialize A Migration Environment\n\nBasic setup:\n\n```bash\nalembic init alembic\n```\n\nUseful templates documented upstream:\n\n- `generic`: default single-database setup\n- `pyproject`: stores Alembic source-configuration in `pyproject.toml`\n- `async`: bootstrap for async DBAPI projects\n- `multidb`: rudimentary multi-database setup\n\nFor a modern Python project already using `pyproject.toml`, prefer:\n\n```bash\nalembic init --template pyproject alembic\n```\n\nFor async SQLAlchemy projects, prefer:\n\n```bash\nalembic init -t async alembic\n```\n\nThe generated environment typically includes:\n\n- `alembic.ini`\n- `alembic/env.py`\n- `alembic/script.py.mako`\n- `alembic/versions/`\n\n## Minimal Setup That Must Be Correct\n\n### 1. Point Alembic At The Right Database\n\nThe default templates read the database URL from `sqlalchemy.url`:\n\n```ini\n[alembic]\nsqlalchemy.url = postgresql+psycopg://user:pass@localhost/app\n```\n\nThe tutorial is explicit that `sqlalchemy.url` is consumed by the user-maintained `env.py` script, so it is normal to replace this with environment-driven configuration.\n\n### 2. Set `target_metadata`\n\nAutogenerate does not work until `env.py` imports your SQLAlchemy metadata and assigns it to `target_metadata`.\n\n```python\n# alembic/env.py\nfrom myapp.db import Base\n\ntarget_metadata = Base.metadata\n```\n\nIf your app has multiple metadata collections, Alembic can use a sequence:\n\n```python\ntarget_metadata = [Model1Base.metadata, Model2Base.metadata]\n```\n\n### 3. If You Override The URL In `env.py`, Escape `%`\n\nWhen using `Config.set_main_option()` or `set_section_option()`, Alembic passes the value through `ConfigParser`, so raw percent signs must be doubled.\n\n```python\nimport os\n\nfrom alembic import context\n\nconfig = context.config\ndatabase_url = os.environ[\"DATABASE_URL\"]\nconfig.set_main_option(\"sqlalchemy.url\", database_url.replace(\"%\", \"%%\"))\n```\n\nThis matters for URLs that contain percent-encoded credentials.\n\n## Core CLI Workflow\n\nCreate a blank revision:\n\n```bash\nalembic revision -m \"create users table\"\n```\n\nAutogenerate a candidate revision from metadata vs. live database:\n\n```bash\nalembic revision --autogenerate -m \"add users table\"\n```\n\nApply all pending revisions:\n\n```bash\nalembic upgrade head\n```\n\nStep back one revision:\n\n```bash\nalembic downgrade -1\n```\n\nInspect migration state:\n\n```bash\nalembic current\nalembic history\nalembic heads\n```\n\nCheck whether model changes would produce a non-empty autogenerate diff:\n\n```bash\nalembic check\n```\n\n`alembic check` is useful in CI because it runs the autogenerate comparison without creating a new revision file.\n\n## Typical Revision Contents\n\nGenerated files are normal Python migration scripts. Expect to edit them.\n\n```python\nfrom alembic import op\nimport sqlalchemy as sa\n\ndef upgrade() -> None:\n    op.add_column(\"account\", sa.Column(\"last_transaction_date\", sa.DateTime()))\n\ndef downgrade() -> None:\n    op.drop_column(\"account\", \"last_transaction_date\")\n```\n\nUpstream guidance is clear: autogenerate produces candidate migrations, not finished migrations.\n\n## Programmatic Usage\n\nAlembic can run from Python code instead of the CLI.\n\n```python\nfrom alembic import command, config\n\ncfg = config.Config(\"alembic.ini\")\ncommand.upgrade(cfg, \"head\")\n```\n\nTo reuse an existing SQLAlchemy connection or transaction, pass it through `Config.attributes` and make `env.py` read it:\n\n```python\nfrom alembic import command, config\n\ncfg = config.Config(\"alembic.ini\")\n\nwith engine.begin() as connection:\n    cfg.attributes[\"connection\"] = connection\n    command.upgrade(cfg, \"head\")\n```\n\nThis is the upstream pattern for application-managed transactions.\n\n## Async Projects\n\nAlembic does not expose a separate async API, but it supports SQLAlchemy async engines through the generated environment.\n\nThe documented pattern is:\n\n- bootstrap with the async template\n- use `async_engine_from_config(...)` in `run_migrations_online()`\n- call `await connection.run_sync(do_run_migrations)`\n\nThis lets you keep using normal Alembic commands like:\n\n```bash\nalembic upgrade head\n```\n\nwith an async database URL configured in the environment.\n\n## Existing Databases And `stamp`\n\nIf you create all tables directly from SQLAlchemy metadata for a fresh install, you can align Alembic with the current schema without replaying every old migration:\n\n```python\nfrom alembic import command\nfrom alembic.config import Config\n\nmy_metadata.create_all(engine)\n\ncfg = Config(\"alembic.ini\")\ncommand.stamp(cfg, \"head\")\n```\n\nUse this only when the live schema already matches the latest model state.\n\n## Offline SQL Script Generation\n\nIf DDL must be reviewed or run by DBAs, generate SQL instead of executing directly:\n\n```bash\nalembic upgrade head --sql > migration.sql\n```\n\nOffline mode can also target a specific revision range:\n\n```bash\nalembic upgrade START_REV:END_REV --sql > migration.sql\n```\n\nThat `start:end` syntax is specifically for offline mode.\n\n## Branches And Merge Points\n\nAlembic supports branched revision graphs. If you have multiple heads:\n\n```bash\nalembic heads\nalembic current\n```\n\n`alembic upgrade head` becomes ambiguous when more than one head exists. In that case, either target a specific branch, use `heads`, or create a merge revision:\n\n```bash\nalembic merge -m \"merge feature branches\" heads\n```\n\nUse merge revisions when two independent migration lines both need to remain valid upgrade paths.\n\n## Naming Conventions Matter\n\nAlembic autogenerate cannot reliably reason about anonymously named constraints. If you use SQLAlchemy naming conventions, autogenerate and operations behave much more predictably.\n\nTypical pattern:\n\n```python\nfrom sqlalchemy import MetaData\nfrom sqlalchemy.orm import DeclarativeBase\n\nclass Base(DeclarativeBase):\n    metadata = MetaData(\n        naming_convention={\n            \"ix\": \"ix_%(column_0_label)s\",\n            \"uq\": \"uq_%(table_name)s_%(column_0_name)s\",\n            \"ck\": \"ck_%(table_name)s_%(constraint_name)s\",\n            \"fk\": \"fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s\",\n            \"pk\": \"pk_%(table_name)s\",\n        }\n    )\n```\n\nDo this before you depend heavily on autogenerate.\n\n## SQLite And Batch Migrations\n\nSQLite has very limited `ALTER TABLE` support. Alembic handles this through batch migrations:\n\n```python\nwith op.batch_alter_table(\"some_table\") as batch_op:\n    batch_op.add_column(sa.Column(\"foo\", sa.Integer()))\n    batch_op.drop_column(\"bar\")\n```\n\nImportant SQLite-specific behaviors:\n\n- Alembic may recreate the table with a move-and-copy workflow\n- named CHECK and foreign key constraints need extra care\n- foreign key enforcement can block the required drop/rename cycle\n- unnamed constraints are especially awkward during batch operations\n\nIf you are migrating SQLite schemas, review generated batch migrations more carefully than usual.\n\n## Common Pitfalls\n\n- Autogenerate is not exact. Always review the file it creates.\n- Table renames and column renames are not detected as renames; they show up as add/drop pairs and must be hand-edited.\n- Unnamed constraints are not reliably detectable. Use naming conventions.\n- If your database contains tables outside your ORM metadata, autogenerate may try to drop them unless you filter with `include_name`.\n- `compare_server_default=True` is optional and can produce false positives; enable it deliberately.\n- For projects with many schemas, configure `include_schemas` and `include_name` intentionally.\n- Data migrations are application-specific. Alembic's cookbook recommends keeping only small data changes inline and using separate scripts for more complex migrations.\n- Multiple heads are normal in collaborative workflows, but you need an explicit merge strategy.\n\n## Version-Sensitive Notes\n\n- `1.15.0` was yanked because `alembic init` packaging was broken. Do not pin to `1.15.0`; use `1.15.1+`.\n- `1.15.x+` dropped support for SQLAlchemy `<1.4`.\n- `1.16.0` added `pyproject.toml` support for source-configuration and introduced `path_separator`, which is relevant if you split `version_locations` or `prepend_sys_path`.\n- `1.17.1` added `alembic current --check-heads`, which is useful for tests and deployment checks.\n- `1.18.0` added the plugin system and changed autogenerate reflection to use SQLAlchemy 2.0 bulk inspector methods for some dialects.\n- `1.18.3` fixed an autogenerate regression from `1.18.0` affecting certain foreign key reflections when tables were filtered or reflected across remote schemas. If you depend on complex autogenerate filtering, prefer `>=1.18.3`.\n\n## Official Sources\n\n- Documentation root: https://alembic.sqlalchemy.org/en/latest/\n- Tutorial: https://alembic.sqlalchemy.org/en/latest/tutorial.html\n- Autogenerate guide: https://alembic.sqlalchemy.org/en/latest/autogenerate.html\n- Branches guide: https://alembic.sqlalchemy.org/en/latest/branches.html\n- Naming constraints: https://alembic.sqlalchemy.org/en/latest/naming.html\n- Batch migrations: https://alembic.sqlalchemy.org/en/latest/batch.html\n- Offline mode: https://alembic.sqlalchemy.org/en/latest/offline.html\n- Cookbook: https://alembic.sqlalchemy.org/en/latest/cookbook.html\n- Config API: https://alembic.sqlalchemy.org/en/latest/api/config.html\n- Changelog: https://alembic.sqlalchemy.org/en/latest/changelog.html\n- PyPI: https://pypi.org/project/alembic/\n"
  },
  {
    "path": "content/altair/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Altair Python package guide for declarative charts with Vega-Lite 6\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"altair,vega-lite,visualization,charts,jupyter,data-viz\"\n---\n\n# Altair Python Package Guide\n\n## Golden Rule\n\nUse `altair` to build Vega-Lite chart specifications in Python, not to draw pixels directly. Pass Altair tabular data, annotate encoding types when the dataframe metadata is not enough, and expect rendering or export features to depend on the frontend renderer plus optional `vl-convert-python`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"altair==6.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"altair==6.0.0\"\npoetry add \"altair==6.0.0\"\n```\n\nUseful extras from the official install guide:\n\n```bash\npython -m pip install \"altair[all]==6.0.0\"\npython -m pip install \"altair[save]==6.0.0\"\n```\n\nUse cases:\n\n- `altair[all]`: installs Altair with all optional dependencies, which is the easiest choice for notebooks and examples.\n- `altair[save]`: installs the dependencies needed for offline HTML export and PNG/SVG/PDF export.\n\nIf you need image export or offline HTML without extras, install `vl-convert-python` directly:\n\n```bash\npython -m pip install vl-convert-python\n```\n\n## Initialize And Render A First Chart\n\nAltair works best with tabular data. A pandas `DataFrame` is the smoothest path because Altair can infer many encoding types from pandas dtypes.\n\n```python\nimport altair as alt\nimport pandas as pd\n\nsource = pd.DataFrame(\n    [\n        {\"month\": \"Jan\", \"revenue\": 12, \"region\": \"east\"},\n        {\"month\": \"Feb\", \"revenue\": 18, \"region\": \"east\"},\n        {\"month\": \"Jan\", \"revenue\": 10, \"region\": \"west\"},\n        {\"month\": \"Feb\", \"revenue\": 15, \"region\": \"west\"},\n    ]\n)\n\nchart = (\n    alt.Chart(source)\n    .mark_line(point=True)\n    .encode(\n        x=\"month:O\",\n        y=\"revenue:Q\",\n        color=\"region:N\",\n        tooltip=[\"month:O\", \"region:N\", \"revenue:Q\"],\n    )\n    .properties(width=500, title=\"Monthly revenue\")\n)\n\nchart\n```\n\nNotes:\n\n- `:O`, `:Q`, `:N`, and `:T` mean ordinal, quantitative, nominal, and temporal.\n- With pandas input you can sometimes omit the type suffixes, but keeping them explicit avoids ambiguous output when code is reused.\n- In notebooks, the chart usually renders when it is the final expression in the cell.\n\n## Core Usage\n\n### Use built-in datasets for examples\n\nAltair 6 includes the `altair.datasets` module for convenient access to Vega datasets:\n\n```python\nimport altair as alt\nfrom altair.datasets import data\n\ncars = data.cars()\n\nchart = (\n    alt.Chart(cars)\n    .mark_point()\n    .encode(\n        x=\"Horsepower:Q\",\n        y=\"Miles_per_Gallon:Q\",\n        color=\"Origin:N\",\n        tooltip=[\"Name:N\", \"Origin:N\", \"Horsepower:Q\", \"Miles_per_Gallon:Q\"],\n    )\n)\n```\n\n### Compose charts with transformations and views\n\nAltair charts are immutable-like objects. Build them up with method chaining:\n\n```python\nbase = alt.Chart(cars).properties(width=280, height=220)\n\npoints = base.mark_point().encode(\n    x=\"Horsepower:Q\",\n    y=\"Miles_per_Gallon:Q\",\n    color=\"Origin:N\",\n)\n\nbars = base.mark_bar().encode(\n    x=\"count()\",\n    y=\"Origin:N\",\n    color=\"Origin:N\",\n)\n\ndashboard = points | bars\n```\n\nUse `|` for horizontal concatenation, `&` for vertical concatenation, and `+` for layering.\n\n### Add interactivity with parameters and selections\n\nIn Altair 6, the practical interaction model is still parameters plus `add_params()`. Prefer `alt.when(...)` over the older `alt.condition(...)` style.\n\n```python\nimport altair as alt\nfrom altair.datasets import data\n\ncars = data.cars()\nbrush = alt.selection_interval()\n\npoints = (\n    alt.Chart(cars)\n    .mark_point()\n    .encode(\n        x=\"Horsepower:Q\",\n        y=\"Miles_per_Gallon:Q\",\n        color=alt.when(brush).then(\"Origin:N\").otherwise(alt.value(\"lightgray\")),\n    )\n    .add_params(brush)\n)\n\nbars = (\n    alt.Chart(cars)\n    .mark_bar()\n    .encode(\n        x=\"count()\",\n        y=\"Origin:N\",\n        color=\"Origin:N\",\n    )\n    .transform_filter(brush)\n)\n\ninteractive = points & bars\n```\n\n### Save or serialize charts\n\n```python\nchart.save(\"chart.json\")\nchart.save(\"chart.html\")\nchart.save(\"chart.html\", inline=True)\nchart.save(\"chart.png\")\n\nspec = chart.to_dict()\nvega_url = chart.to_url()\n```\n\nBehavior to remember:\n\n- `.json` and standard `.html` output work from `Chart.save()`.\n- `inline=True` makes HTML self-contained for offline viewing, but requires `vl-convert-python`.\n- PNG, SVG, and PDF export also require `vl-convert-python`.\n- `chart.to_url()` is useful for opening the chart in the online Vega editor during debugging.\n\n## Configuration And Environment\n\nAltair itself does not use API keys or service authentication. The main setup questions are renderer choice, data handling, and export dependencies.\n\n### Pick a renderer that matches the runtime\n\n```python\nimport altair as alt\n\nalt.renderers.enable(\"html\")                # default in many environments\nalt.renderers.enable(\"jupyter\")             # widget-based rendering in Jupyter frontends\nalt.renderers.enable(\"jupyter\", offline=True)\nalt.renderers.enable(\"browser\")             # useful from IPython or local scripts\n```\n\nGuidance:\n\n- Default HTML rendering usually works in JupyterLab, Notebook, VS Code, and other notebook-like frontends.\n- HTML and Jupyter renderers load JavaScript from a CDN unless you choose an offline mode that uses `vl-convert-python`.\n- The `\"browser\"` renderer is useful outside notebooks, but it is not a fit for remote notebook environments.\n- In a plain Python script or REPL, `chart.show()` is often clearer than relying on implicit display.\n\n### Handle larger datasets intentionally\n\nAltair raises `MaxRowsError` when it would embed more than 5000 rows directly in a spec. Prefer one of these approaches:\n\n1. Pre-aggregate or filter in pandas before passing data to Altair.\n2. Enable VegaFusion for larger transformed datasets.\n3. Pass data by URL if the runtime and deployment model support it.\n4. Disable the max row check only when you explicitly want to embed the full dataset.\n\nInstall VegaFusion first:\n\n```bash\npython -m pip install vegafusion vl-convert-python\n```\n\n```python\nimport altair as alt\n\nalt.data_transformers.enable(\"vegafusion\")\n```\n\nImportant details:\n\n- With the VegaFusion data transformer enabled, charts created afterward can work with datasets up to 100,000 rows after supported transformations are evaluated.\n- When VegaFusion is active, converting to JSON or dict should use `format=\"vega\"` rather than the default Vega-Lite format.\n\n```python\nspec = chart.to_dict(format=\"vega\")\n```\n\n## Common Pitfalls\n\n### Non-pandas data needs explicit encoding types\n\nFor plain dict records, URLs, or DataFrame-interchange inputs, declare the type suffixes explicitly:\n\n```python\nalt.Chart(records).mark_bar().encode(\n    x=\"category:N\",\n    y=\"value:Q\",\n)\n```\n\n### DataFrame indices are not chart columns\n\nIf the index matters, move it into a column first:\n\n```python\nchart = alt.Chart(df.reset_index()).mark_line().encode(\n    x=\"index:T\",\n    y=\"value:Q\",\n)\n```\n\n### Wide data is often the wrong shape\n\nAltair’s grammar is usually easier with long-form data. Use pandas `melt()` or an Altair fold transform when multiple series are stored as separate columns.\n\n### Rendering problems are often frontend problems\n\nIf a chart object prints but does not render:\n\n- check that the notebook or IDE supports the chosen renderer\n- confirm the environment can load required JavaScript assets\n- switch to `alt.renderers.enable(\"jupyter\")` or `alt.renderers.enable(\"browser\")`\n- export to `chart.html` to isolate frontend issues from chart-spec issues\n\n### Export failures usually mean a missing optional dependency\n\nIf PNG, SVG, PDF, or offline HTML export fails, install `vl-convert-python`. Do not reach for `altair_saver`; the official docs treat it as an old Altair 4-era path that has been superseded.\n\n## Version-Sensitive Notes For 6.0.0\n\n- Altair `6.0.0` targets Vega-Lite 6.x.\n- PyPI lists Python `>=3.9`, and the 6.0.0 release notes call out Python 3.14 support.\n- Altair 6 introduces the `altair.datasets` module for lazy access to Vega datasets.\n- The release notes also call out thread-safety improvements, so chart specs should be more stable after reruns.\n- The interaction docs still describe major parameter-system changes from Altair 5, and the current guidance is to prefer `alt.when()` over `alt.condition()`.\n\n## Official Sources\n\n- Docs root: https://altair-viz.github.io/\n- Installation: https://altair-viz.github.io/getting_started/installation.html\n- Data guide: https://altair-viz.github.io/user_guide/data.html\n- Display/renderers: https://altair-viz.github.io/user_guide/display_frontends.html\n- Large datasets: https://altair-viz.github.io/user_guide/large_datasets.html\n- Interactions: https://altair-viz.github.io/user_guide/interactions/parameters.html\n- Saving charts: https://altair-viz.github.io/user_guide/saving_charts.html\n- PyPI package page: https://pypi.org/project/altair/\n- GitHub releases: https://github.com/vega/altair/releases\n"
  },
  {
    "path": "content/amplitude/docs/analytics/javascript/DOC.md",
    "content": "---\nname: analytics\ndescription: \"Amplitude Analytics JavaScript SDK for browser-based event tracking and product analytics\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.30.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"amplitude,analytics,events,tracking,product\"\n---\n\n# Amplitude Analytics - JavaScript SDK (@amplitude/analytics-browser)\n\n## Golden Rule\n\n**ALWAYS** use `@amplitude/analytics-browser` version 2.30.1 or newer for browser-based JavaScript applications.\n\n**DO NOT** use the deprecated `amplitude-js` package. It is no longer maintained and lacks modern features.\n\nFor Node.js/server-side applications, use `@amplitude/analytics-node` instead.\n\n---\n\n## Installation\n\n### Browser SDK (NPM/Yarn)\n\n```bash\nnpm install @amplitude/analytics-browser\n```\n\n```bash\nyarn add @amplitude/analytics-browser\n```\n\n### Script Loader (CDN)\n\n```html\n<script src=\"https://cdn.amplitude.com/script/AMPLITUDE_API_KEY.js\"></script>\n```\n\n---\n\n## Environment Variables Setup\n\nStore your API key securely using environment variables:\n\n```javascript\n// .env file\nVITE_AMPLITUDE_API_KEY=your_api_key_here\n```\n\n```javascript\n// Access in code\nconst API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY; // Vite\nconst API_KEY = process.env.REACT_APP_AMPLITUDE_API_KEY; // Create React App\nconst API_KEY = process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY; // Next.js\n```\n\n---\n\n## Initialization\n\n### Basic Initialization\n\n```javascript\nimport * as amplitude from '@amplitude/analytics-browser';\n\namplitude.init('YOUR_API_KEY');\n```\n\n### Initialize with User ID\n\n```javascript\namplitude.init('YOUR_API_KEY', 'user@example.com');\n```\n\n### Initialize with Configuration\n\n```javascript\namplitude.init('YOUR_API_KEY', 'user@example.com', {\n  serverZone: 'US', // or 'EU' for European data residency\n  logLevel: amplitude.Types.LogLevel.Debug,\n  flushIntervalMillis: 1000,\n  flushQueueSize: 30,\n  sessionTimeout: 1800000, // 30 minutes\n  optOut: false,\n  autocapture: true\n});\n```\n\n### Wait for Initialization\n\n```javascript\nawait amplitude.init('YOUR_API_KEY').promise;\nconsole.log('Amplitude initialized');\n```\n\n### Angular Applications with Zone.js\n\n```javascript\nimport { NgZone } from '@angular/core';\n\nconstructor(private ngZone: NgZone) {\n  this.ngZone.runOutsideAngular(() => {\n    amplitude.init('YOUR_API_KEY');\n  });\n}\n```\n\n---\n\n## Configuration Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `flushIntervalMillis` | number | 1000 | Time between event batch uploads (ms) |\n| `flushQueueSize` | number | 30 | Maximum events before triggering upload |\n| `serverZone` | 'US' \\| 'EU' | 'US' | Data residency region |\n| `userId` | string | undefined | User identifier (min 5 characters) |\n| `deviceId` | string | UUID() | Device identifier |\n| `sessionTimeout` | number | 1800000 | Session timeout duration (ms) |\n| `optOut` | boolean | false | Disable event tracking |\n| `autocapture` | boolean \\| object | true | Enable automatic event capture |\n| `identityStorage` | string | 'cookie' | Storage method: 'cookie', 'localStorage', 'sessionStorage' |\n| `minIdLength` | number | 5 | Minimum length for user/device IDs |\n| `logLevel` | LogLevel | Warn | Console logging verbosity |\n| `trackingOptions` | object | {} | Disable specific auto-tracked properties |\n\n---\n\n## Core API Surfaces\n\n### Event Tracking\n\n#### Basic Event\n\n```javascript\namplitude.track('Button Clicked');\n```\n\n#### Event with Properties\n\n```javascript\namplitude.track('Button Clicked', {\n  buttonColor: 'primary',\n  buttonText: 'Submit',\n  section: 'header',\n  userId: 12345\n});\n```\n\n#### Advanced Event Object\n\n```javascript\nconst event = {\n  event_type: 'Product Viewed',\n  event_properties: {\n    productId: 'SKU-123',\n    category: 'Electronics',\n    price: 299.99\n  },\n  groups: {\n    organization: 'acme-corp'\n  },\n  group_properties: {\n    plan: 'enterprise',\n    seats: 50\n  }\n};\n\namplitude.track(event);\n```\n\n#### Event with Callback\n\n```javascript\nconst result = await amplitude.track('Form Submitted', {\n  formName: 'contact'\n}).promise;\n\nconsole.log(result.code);    // HTTP status code\nconsole.log(result.message); // Response message\nconsole.log(result.event);   // Event object\n```\n\n---\n\n### User Identification\n\n#### Set User ID\n\n```javascript\namplitude.setUserId('user@example.com');\n```\n\n#### Set Device ID\n\n```javascript\namplitude.setDeviceId('custom-device-id-12345');\n```\n\n#### Set Session ID\n\n```javascript\namplitude.setSessionId(Date.now());\n```\n\n#### Reset User (Logout)\n\n```javascript\n// Clears userId and generates new deviceId\namplitude.reset();\n```\n\n---\n\n### User Properties\n\n#### Create Identify Object\n\n```javascript\nconst identify = new amplitude.Identify();\n```\n\n#### Set Properties\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.set('name', 'John Doe');\nidentify.set('email', 'john@example.com');\nidentify.set('age', 30);\nidentify.set('premium', true);\n\namplitude.identify(identify);\n```\n\n#### Set Once (Only if Not Already Set)\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.setOnce('signup_date', new Date().toISOString());\nidentify.setOnce('first_source', 'google');\n\namplitude.identify(identify);\n```\n\n#### Add (Increment Numeric Values)\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.add('login_count', 1);\nidentify.add('credits', 100);\n\namplitude.identify(identify);\n```\n\n#### Append to Array\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.append('visited_pages', '/dashboard');\nidentify.append('purchased_products', 'SKU-123');\n\namplitude.identify(identify);\n```\n\n#### Prepend to Array\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.prepend('recent_searches', 'laptop');\n\namplitude.identify(identify);\n```\n\n#### Post Insert (Add to End if Not Present)\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.postInsert('tags', 'premium');\n\namplitude.identify(identify);\n```\n\n#### Pre Insert (Add to Beginning if Not Present)\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.preInsert('badges', 'early_adopter');\n\namplitude.identify(identify);\n```\n\n#### Remove from Array\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.remove('blocked_users', 'user123');\n\namplitude.identify(identify);\n```\n\n#### Unset Property\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.unset('temporary_token');\n\namplitude.identify(identify);\n```\n\n#### Clear All Properties\n\n```javascript\nconst identify = new amplitude.Identify();\nidentify.clearAll();\n\namplitude.identify(identify);\n```\n\n#### Chain Multiple Operations\n\n```javascript\nconst identify = new amplitude.Identify()\n  .set('plan', 'premium')\n  .add('login_count', 1)\n  .append('visited_pages', '/checkout')\n  .setOnce('signup_date', '2025-01-01');\n\namplitude.identify(identify);\n```\n\n---\n\n### Group Analytics\n\n#### Set Single Group\n\n```javascript\namplitude.setGroup('organization', 'acme-corp');\n```\n\n#### Set Multiple Groups\n\n```javascript\namplitude.setGroup('teams', ['engineering', 'product', 'design']);\n```\n\n#### Set Group Properties\n\n```javascript\nconst groupIdentify = new amplitude.Identify();\ngroupIdentify.set('plan', 'enterprise');\ngroupIdentify.set('seats', 100);\ngroupIdentify.set('industry', 'technology');\n\namplitude.groupIdentify('organization', 'acme-corp', groupIdentify);\n```\n\n#### Event-Level Groups (Non-Persistent)\n\n```javascript\namplitude.track({\n  event_type: 'Feature Used',\n  event_properties: {\n    feature_name: 'export'\n  },\n  groups: {\n    department: 'sales',\n    region: 'north-america'\n  }\n});\n```\n\n---\n\n### Revenue Tracking\n\n#### Basic Revenue\n\n```javascript\nconst revenue = new amplitude.Revenue()\n  .setProductId('com.company.premium')\n  .setPrice(9.99);\n\namplitude.revenue(revenue);\n```\n\n#### Advanced Revenue Tracking\n\n```javascript\nconst revenue = new amplitude.Revenue()\n  .setProductId('com.company.product')\n  .setPrice(29.99)\n  .setQuantity(2)\n  .setRevenueType('purchase')\n  .setReceipt('receipt-id-12345')\n  .setReceiptSignature('signature-abc')\n  .setEventProperties({\n    region: 'US',\n    currency: 'USD',\n    paymentMethod: 'credit_card'\n  });\n\namplitude.revenue(revenue);\n```\n\n---\n\n### Autocapture Events\n\n#### Enable All Autocapture\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: true\n});\n```\n\n#### Selective Autocapture\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: {\n    attribution: true,           // UTM parameters, referrer\n    pageViews: true,             // Page view events\n    sessions: true,              // Session start/end\n    formInteractions: true,      // Form submissions\n    fileDownloads: true,         // File download clicks\n    elementInteractions: false,  // Element clicks (opt-in)\n    webVitals: false            // Core Web Vitals (opt-in)\n  }\n});\n```\n\n#### Page View Tracking\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: {\n    pageViews: {\n      trackOn: () => {\n        // Custom logic to determine if page should be tracked\n        return window.location.pathname.includes('/app');\n      },\n      trackHistoryChanges: 'pathOnly', // 'all' or 'pathOnly'\n      eventType: 'Page Viewed' // Custom event type name\n    }\n  }\n});\n```\n\n#### Element Interaction Tracking\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: {\n    elementInteractions: {\n      cssSelectorAllowlist: ['.track-click', '[data-amp-track]'],\n      pageUrlAllowlist: [/\\/dashboard/, /\\/checkout/],\n      dataAttributePrefix: 'data-amp-track'\n    }\n  }\n});\n```\n\n```html\n<button class=\"track-click\" data-amp-track-name=\"Checkout Button\">\n  Checkout\n</button>\n```\n\n#### Network Request Tracking\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: {\n    networkTracking: {\n      captureRules: [\n        {\n          urls: [/api\\.example\\.com/, /\\.googleapis\\.com/],\n          statusCodeRange: '400-599', // Track errors only\n          requestHeaders: ['content-type', 'authorization'],\n          responseHeaders: ['x-request-id'],\n          responseBody: {\n            allowlist: ['error', 'message', 'code']\n          }\n        }\n      ]\n    }\n  }\n});\n```\n\n#### Attribution Tracking\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  autocapture: {\n    attribution: {\n      excludeReferrers: [\n        /yourdomain\\.com$/,\n        'google.com',\n        'facebook.com'\n      ],\n      initialEmptyValue: 'EMPTY',\n      resetSessionOnNewCampaign: false\n    }\n  }\n});\n```\n\n**Captured attribution parameters:**\n- `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`\n- `referrer`, `referring_domain`\n- `gclid`, `fbclid`, `dclid`, `ttclid`, `msclkid`\n\n---\n\n### Multiple Project Tracking\n\n```javascript\n// Default instance\nconst defaultInstance = amplitude.createInstance();\ndefaultInstance.init('API_KEY_DEFAULT');\n\n// Production instance\nconst prodInstance = amplitude.createInstance();\nprodInstance.init('API_KEY_PROD', { instanceName: 'production' });\n\n// Development instance\nconst devInstance = amplitude.createInstance();\ndevInstance.init('API_KEY_DEV', { instanceName: 'development' });\n\n// Track to specific instance\ndefaultInstance.track('Default Event');\nprodInstance.track('Production Event');\ndevInstance.track('Development Event');\n```\n\n---\n\n### Plugin System\n\n#### Enrichment Plugin\n\n```javascript\nconst urlEnrichmentPlugin = {\n  name: 'url-enricher',\n  type: 'enrichment',\n  setup: async (config) => {\n    console.log('Plugin setup complete');\n  },\n  execute: async (event) => {\n    event.event_properties = {\n      ...event.event_properties,\n      page_url: window.location.href,\n      page_title: document.title,\n      referrer: document.referrer\n    };\n    return event;\n  }\n};\n\namplitude.add(urlEnrichmentPlugin);\n```\n\n#### Destination Plugin\n\n```javascript\nconst customDestinationPlugin = {\n  name: 'custom-analytics',\n  type: 'destination',\n  setup: async (config) => {\n    // Initialize custom analytics\n  },\n  execute: async (event) => {\n    try {\n      const response = await fetch('https://api.custom-analytics.com/events', {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          'Authorization': 'Bearer TOKEN'\n        },\n        body: JSON.stringify(event)\n      });\n\n      return {\n        code: response.status,\n        event: event,\n        message: response.statusText\n      };\n    } catch (error) {\n      return {\n        code: 500,\n        event: event,\n        message: error.message\n      };\n    }\n  }\n};\n\namplitude.add(customDestinationPlugin);\n```\n\n#### Remove Plugin\n\n```javascript\namplitude.remove('plugin-name');\n```\n\n---\n\n### Session Management\n\n#### Get Session ID\n\n```javascript\nconst sessionId = amplitude.getSessionId();\nconsole.log('Current session:', sessionId);\n```\n\n#### Set Custom Session ID\n\n```javascript\namplitude.setSessionId(Date.now());\n```\n\n#### Custom Session Timeout\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  sessionTimeout: 600000 // 10 minutes\n});\n```\n\n---\n\n### Cross-Domain Tracking\n\n#### Site 1: Get User/Device IDs\n\n```javascript\nconst deviceId = amplitude.getDeviceId();\nconst sessionId = amplitude.getSessionId();\nconst userId = amplitude.getUserId();\n\n// Redirect with IDs\nwindow.location.href = `https://site2.com?ampDeviceId=${deviceId}&ampSessionId=${sessionId}`;\n```\n\n#### Site 2: Automatically Pick Up IDs\n\n```javascript\n// IDs automatically extracted from URL parameters\namplitude.init('YOUR_API_KEY');\n```\n\n---\n\n### Opt-Out Control\n\n#### Disable Tracking\n\n```javascript\namplitude.setOptOut(true);\n```\n\n#### Enable Tracking\n\n```javascript\namplitude.setOptOut(false);\n```\n\n---\n\n### Buffer Management\n\n#### Flush Events Immediately\n\n```javascript\namplitude.flush();\n```\n\n#### Flush with Promise\n\n```javascript\nawait amplitude.flush().promise;\nconsole.log('All events sent');\n```\n\n#### Send Beacon on Page Exit\n\n```javascript\nwindow.addEventListener('pagehide', () => {\n  amplitude.setTransport('beacon');\n  amplitude.flush();\n});\n```\n\n---\n\n### Tracking Options\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  trackingOptions: {\n    ipAddress: false,\n    language: false,\n    platform: false,\n    osName: false,\n    osVersion: false,\n    deviceManufacturer: false,\n    deviceModel: false,\n    carrier: false,\n    city: false,\n    country: false,\n    region: false,\n    dma: false\n  }\n});\n```\n\n---\n\n### Identity Storage\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  identityStorage: 'localStorage' // 'cookie', 'localStorage', 'sessionStorage', 'none'\n});\n```\n\n---\n\n### Custom Storage Provider\n\n```javascript\nclass CustomStorage {\n  isEnabled() {\n    return true;\n  }\n\n  get(key) {\n    return localStorage.getItem(key);\n  }\n\n  set(key, value) {\n    localStorage.setItem(key, value);\n  }\n\n  remove(key) {\n    localStorage.removeItem(key);\n  }\n\n  reset() {\n    localStorage.clear();\n  }\n\n  getRaw(key) {\n    return this.get(key);\n  }\n}\n\namplitude.init('YOUR_API_KEY', {\n  storageProvider: new CustomStorage()\n});\n```\n\n---\n\n### Debugging\n\n#### Enable Debug Logging\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  logLevel: amplitude.Types.LogLevel.Debug\n});\n```\n\n**Available log levels:**\n- `None` (0) - No logging\n- `Error` (1) - Error messages only\n- `Warn` (2) - Warnings and errors\n- `Verbose` (3) - Verbose output\n- `Debug` (4) - All debug information\n\n#### Custom Logger\n\n```javascript\nclass CustomLogger {\n  disable() {}\n  enable() {}\n  log(...args) {\n    console.log('[AMPLITUDE]', ...args);\n  }\n  warn(...args) {\n    console.warn('[AMPLITUDE]', ...args);\n  }\n  error(...args) {\n    console.error('[AMPLITUDE]', ...args);\n  }\n  debug(...args) {\n    console.debug('[AMPLITUDE]', ...args);\n  }\n}\n\namplitude.init('YOUR_API_KEY', {\n  loggerProvider: new CustomLogger()\n});\n```\n\n---\n\n### Transport Configuration\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  transport: 'xhr' // 'xhr', 'beacon', or 'fetch'\n});\n```\n\n#### Switch Transport at Runtime\n\n```javascript\namplitude.setTransport('beacon');\n```\n\n---\n\n### Offline Mode\n\nEvents are automatically stored when offline and sent when connection is restored. This behavior is enabled by default.\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  offline: true // Default behavior\n});\n```\n\n---\n\n### Server URL Override\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  serverUrl: 'https://custom-proxy.example.com/amplitude'\n});\n```\n\n---\n\n### User Agent Parser\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  deviceId: 'custom-device-id',\n  platform: 'Web',\n  osName: 'MacOS',\n  osVersion: '14.2',\n  deviceModel: 'MacBook Pro'\n});\n```\n\n---\n\n### Middleware Pattern\n\n```javascript\nconst timestampMiddleware = (payload) => {\n  payload.events.forEach(event => {\n    event.event_properties = {\n      ...event.event_properties,\n      middleware_timestamp: Date.now()\n    };\n  });\n  return payload;\n};\n\n// Middleware is applied via plugins\nconst middlewarePlugin = {\n  name: 'middleware',\n  type: 'before',\n  execute: async (event) => {\n    return timestampMiddleware(event);\n  }\n};\n\namplitude.add(middlewarePlugin);\n```\n\n---\n\n### Error Handling\n\n```javascript\ntry {\n  const result = await amplitude.track('Event Name', {\n    property: 'value'\n  }).promise;\n\n  if (result.code === 200) {\n    console.log('Event tracked successfully');\n  } else {\n    console.error('Failed to track event:', result.message);\n  }\n} catch (error) {\n  console.error('Error tracking event:', error);\n}\n```\n\n---\n\n### TypeScript Types\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport {\n  BrowserConfig,\n  Event,\n  Identify,\n  Revenue,\n  Types\n} from '@amplitude/analytics-browser';\n\nconst config: BrowserConfig = {\n  serverZone: 'US',\n  flushQueueSize: 30,\n  logLevel: Types.LogLevel.Warn\n};\n\namplitude.init('YOUR_API_KEY', config);\n\nconst event: Event = {\n  event_type: 'Custom Event',\n  event_properties: {\n    key: 'value'\n  }\n};\n\namplitude.track(event);\n```\n\n---\n\n### React Integration\n\n```javascript\nimport { useEffect } from 'react';\nimport * as amplitude from '@amplitude/analytics-browser';\n\nfunction App() {\n  useEffect(() => {\n    amplitude.init(process.env.REACT_APP_AMPLITUDE_API_KEY);\n  }, []);\n\n  const handleClick = () => {\n    amplitude.track('Button Clicked', {\n      component: 'App',\n      action: 'click'\n    });\n  };\n\n  return <button onClick={handleClick}>Track Event</button>;\n}\n```\n\n---\n\n### Vue Integration\n\n```javascript\nimport { onMounted } from 'vue';\nimport * as amplitude from '@amplitude/analytics-browser';\n\nexport default {\n  setup() {\n    onMounted(() => {\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY);\n    });\n\n    const trackEvent = () => {\n      amplitude.track('Button Clicked', {\n        component: 'MyComponent'\n      });\n    };\n\n    return { trackEvent };\n  }\n};\n```\n\n---\n\n### Angular Integration\n\n```typescript\nimport { Injectable, NgZone } from '@angular/core';\nimport * as amplitude from '@amplitude/analytics-browser';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class AnalyticsService {\n  constructor(private ngZone: NgZone) {\n    this.ngZone.runOutsideAngular(() => {\n      amplitude.init(environment.amplitudeApiKey);\n    });\n  }\n\n  track(eventName: string, properties?: Record<string, any>) {\n    amplitude.track(eventName, properties);\n  }\n}\n```\n\n---\n\n### Next.js Integration\n\n```javascript\n// lib/amplitude.js\nimport * as amplitude from '@amplitude/analytics-browser';\n\nlet initialized = false;\n\nexport const initAmplitude = () => {\n  if (typeof window !== 'undefined' && !initialized) {\n    amplitude.init(process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY);\n    initialized = true;\n  }\n};\n\nexport const trackEvent = (eventName, properties) => {\n  if (typeof window !== 'undefined') {\n    amplitude.track(eventName, properties);\n  }\n};\n```\n\n```javascript\n// pages/_app.js\nimport { useEffect } from 'react';\nimport { initAmplitude } from '../lib/amplitude';\n\nfunction MyApp({ Component, pageProps }) {\n  useEffect(() => {\n    initAmplitude();\n  }, []);\n\n  return <Component {...pageProps} />;\n}\n```\n\n---\n\n### EU Data Residency\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  serverZone: 'EU'\n});\n```\n\n---\n\n### Minimum ID Length\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  minIdLength: 3 // Default is 5\n});\n```\n\n---\n\n### Partner ID\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  partnerId: 'your-partner-id'\n});\n```\n\n---\n\n### App Version Tracking\n\n```javascript\namplitude.init('YOUR_API_KEY', {\n  appVersion: '1.2.3'\n});\n```\n\n---\n\n## Common Patterns\n\n### Page View Tracking\n\n```javascript\n// Track page view on route change\namplitude.track('Page Viewed', {\n  page_url: window.location.href,\n  page_path: window.location.pathname,\n  page_title: document.title,\n  referrer: document.referrer\n});\n```\n\n### Search Tracking\n\n```javascript\namplitude.track('Search Performed', {\n  search_query: 'laptop',\n  search_results_count: 42,\n  search_category: 'electronics'\n});\n```\n\n### Form Submission Tracking\n\n```javascript\namplitude.track('Form Submitted', {\n  form_name: 'contact_us',\n  form_id: 'contact-form',\n  fields_completed: 5\n});\n```\n\n### Error Tracking\n\n```javascript\nwindow.addEventListener('error', (event) => {\n  amplitude.track('JavaScript Error', {\n    error_message: event.message,\n    error_filename: event.filename,\n    error_lineno: event.lineno,\n    error_colno: event.colno\n  });\n});\n```\n\n### Social Share Tracking\n\n```javascript\namplitude.track('Content Shared', {\n  platform: 'twitter',\n  content_type: 'article',\n  content_id: 'article-123'\n});\n```\n\n### Video Playback Tracking\n\n```javascript\n// Video started\namplitude.track('Video Started', {\n  video_id: 'video-123',\n  video_title: 'Product Demo',\n  video_duration: 300\n});\n\n// Video progress\namplitude.track('Video Progress', {\n  video_id: 'video-123',\n  percentage_watched: 25\n});\n\n// Video completed\namplitude.track('Video Completed', {\n  video_id: 'video-123',\n  time_watched: 295\n});\n```\n\n---\n\n## HTTP API Direct Usage\n\n### Endpoint\n\n**US:** `https://api2.amplitude.com/2/httpapi`\n**EU:** `https://api.eu.amplitude.com/2/httpapi`\n\n### Basic Request\n\n```javascript\nconst response = await fetch('https://api2.amplitude.com/2/httpapi', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify({\n    api_key: 'YOUR_API_KEY',\n    events: [{\n      user_id: 'user@example.com',\n      device_id: 'C8F9E604-F01A-4BD9-95C6-8E5357DF265D',\n      event_type: 'page_viewed',\n      time: Date.now(),\n      event_properties: {\n        page: 'homepage'\n      }\n    }]\n  })\n});\n\nconst result = await response.json();\nconsole.log(result);\n```\n\n---\n\n## Constraints & Limits\n\n- **Minimum ID length:** 5 characters (configurable via `minIdLength`)\n- **Event batch size:** 30 events by default (`flushQueueSize`)\n- **Flush interval:** 1000ms by default (`flushIntervalMillis`)\n- **Session timeout:** 30 minutes by default (`sessionTimeout`)\n- **User ID and Device ID:** Must be strings\n- **Event requirements:** Must have `event_type` and at least one of `deviceId` or `userId`\n\n---\n\n## Best Practice Code Examples\n\n### Complete Setup\n\n```javascript\nimport * as amplitude from '@amplitude/analytics-browser';\n\n// Initialize with full configuration\namplitude.init(process.env.VITE_AMPLITUDE_API_KEY, {\n  serverZone: 'US',\n  logLevel: amplitude.Types.LogLevel.Warn,\n  flushIntervalMillis: 1000,\n  flushQueueSize: 30,\n  sessionTimeout: 1800000,\n  autocapture: {\n    attribution: true,\n    pageViews: true,\n    sessions: true,\n    formInteractions: true,\n    fileDownloads: true\n  },\n  identityStorage: 'cookie'\n});\n\n// Set user after login\namplitude.setUserId('user123@example.com');\n\n// Set user properties\nconst identify = new amplitude.Identify()\n  .set('plan', 'premium')\n  .set('email', 'user123@example.com')\n  .setOnce('signup_date', new Date().toISOString());\n\namplitude.identify(identify);\n\n// Track custom events\namplitude.track('Feature Used', {\n  feature_name: 'export',\n  feature_category: 'data'\n});\n```\n\n### Cleanup on Logout\n\n```javascript\nfunction handleLogout() {\n  // Track logout event\n  amplitude.track('User Logged Out');\n\n  // Flush remaining events\n  amplitude.flush();\n\n  // Reset user identity\n  amplitude.reset();\n}\n```\n"
  },
  {
    "path": "content/amplitude/docs/analytics/python/DOC.md",
    "content": "---\nname: analytics\ndescription: \"Amplitude Analytics Python SDK for server-side event tracking and product analytics\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"amplitude,analytics,events,tracking,product\"\n---\n\n# Amplitude Analytics - Python SDK\n\n## Golden Rule\n\n**ALWAYS** use `amplitude-analytics` version 1.2.0 or newer for Python server-side instrumentation.\n\nThis is the official Amplitude backend Python SDK maintained by Amplitude Inc.\n\n**DO NOT** use unofficial community packages like `pyamplitude` or `amplitude-python`.\n\n---\n\n## Installation\n\n```bash\npip install amplitude-analytics\n```\n```bash\npip install amplitude-analytics==1.2.0\n```\n\n---\n\n## Environment Variables Setup\n\nStore your API key securely:\n\n```bash\n# .env file\nAMPLITUDE_API_KEY=your_api_key_here\n```\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\nAPI_KEY = os.getenv('AMPLITUDE_API_KEY')\n```\n\n---\n\n## Initialization\n\n### Basic Initialization\n\n```python\nfrom amplitude import Amplitude\n\nclient = Amplitude('YOUR_API_KEY')\n```\n\n### Initialize with Configuration\n\n```python\nfrom amplitude import Amplitude\n\nclient = Amplitude(\n    api_key='YOUR_API_KEY',\n    configuration={\n        'flush_queue_size': 200,\n        'flush_interval_millis': 10000,\n        'flush_max_retries': 12,\n        'min_id_length': 5,\n        'server_zone': 'US',\n        'use_batch': False,\n        'opt_out': False\n    }\n)\n```\n\n---\n\n## Configuration Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `flush_queue_size` | int | 200 | Maximum events before triggering flush |\n| `flush_interval_millis` | int | 10000 | Time between automatic flushes (ms) |\n| `flush_max_retries` | int | 12 | Maximum retry attempts on failure |\n| `min_id_length` | int | 5 | Minimum length for user_id/device_id |\n| `server_zone` | str | 'US' | Data residency: 'US' or 'EU' |\n| `use_batch` | bool | False | Enable batch API endpoint |\n| `opt_out` | bool | False | Disable event processing |\n| `server_url` | str | None | Custom API endpoint URL |\n| `callback` | callable | None | Callback function for responses |\n\n---\n\n## Core API Surfaces\n\n### Event Tracking\n\n#### Basic Event\n\n```python\nfrom amplitude import BaseEvent\n\nevent = BaseEvent(\n    event_type=\"Button Clicked\",\n    user_id=\"user@example.com\"\n)\n\nclient.track(event)\n```\n\n#### Event with Device ID\n\n```python\nevent = BaseEvent(\n    event_type=\"Page Viewed\",\n    device_id=\"device-123\"\n)\n\nclient.track(event)\n```\n\n#### Event with Properties\n\n```python\nevent = BaseEvent(\n    event_type=\"Product Purchased\",\n    user_id=\"user@example.com\",\n    event_properties={\n        \"product_id\": \"SKU-123\",\n        \"price\": 29.99,\n        \"quantity\": 2,\n        \"category\": \"Electronics\"\n    }\n)\n\nclient.track(event)\n```\n\n#### Advanced Event with All Options\n\n```python\nimport time\n\nevent = BaseEvent(\n    event_type=\"Feature Used\",\n    user_id=\"user@example.com\",\n    device_id=\"device-123\",\n    time=int(time.time() * 1000),  # Milliseconds\n    event_properties={\n        \"feature_name\": \"export\",\n        \"feature_category\": \"data\"\n    },\n    user_properties={\n        \"plan\": \"premium\",\n        \"credits\": 100\n    },\n    groups={\n        \"organization\": \"acme-corp\",\n        \"team\": \"engineering\"\n    },\n    group_properties={\n        \"org_plan\": \"enterprise\",\n        \"team_size\": 50\n    },\n    app_version=\"1.2.3\",\n    platform=\"Web\",\n    os_name=\"MacOS\",\n    os_version=\"14.2\",\n    device_brand=\"Apple\",\n    device_manufacturer=\"Apple\",\n    device_model=\"MacBook Pro\",\n    carrier=\"N/A\",\n    country=\"US\",\n    region=\"California\",\n    city=\"San Francisco\",\n    dma=\"SF-OAK-SJ\",\n    language=\"en-US\",\n    price=9.99,\n    quantity=1,\n    revenue=9.99,\n    product_id=\"product-123\",\n    revenue_type=\"purchase\",\n    location_lat=37.7749,\n    location_lng=-122.4194,\n    ip=\"203.0.113.42\",\n    idfa=\"AEBE52E7-03EE-455A-B3C4-E57283966239\",\n    idfv=\"BCDEF123-03EE-455A-B3C4-E57283966239\",\n    adid=\"CDDEF123-03EE-455A-B3C4-E57283966239\",\n    android_id=\"android-123\",\n    event_id=123456,\n    session_id=1234567890,\n    insert_id=\"unique-insert-id-123\"\n)\n\nclient.track(event)\n```\n\n---\n\n### User Properties\n\n#### Create Identify Object\n\n```python\nfrom amplitude import Identify\n\nidentify_obj = Identify()\n```\n\n#### Set Properties\n\n```python\nfrom amplitude import Identify, EventOptions\n\nidentify_obj = Identify()\nidentify_obj.set(\"name\", \"John Doe\")\nidentify_obj.set(\"email\", \"john@example.com\")\nidentify_obj.set(\"age\", 30)\nidentify_obj.set(\"premium\", True)\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Set Once (Only if Not Set)\n\n```python\nidentify_obj = Identify()\nidentify_obj.set_once(\"signup_date\", \"2025-01-01\")\nidentify_obj.set_once(\"first_source\", \"google\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Add (Increment Numeric Values)\n\n```python\nidentify_obj = Identify()\nidentify_obj.add(\"login_count\", 1)\nidentify_obj.add(\"credits\", 100)\nidentify_obj.add(\"points\", -50)  # Decrement\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Append to Array\n\n```python\nidentify_obj = Identify()\nidentify_obj.append(\"visited_pages\", \"/dashboard\")\nidentify_obj.append(\"purchased_products\", \"SKU-123\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Prepend to Array\n\n```python\nidentify_obj = Identify()\nidentify_obj.prepend(\"recent_searches\", \"laptop\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Pre Insert (Add to Beginning if Not Present)\n\n```python\nidentify_obj = Identify()\nidentify_obj.pre_insert(\"badges\", \"early_adopter\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Post Insert (Add to End if Not Present)\n\n```python\nidentify_obj = Identify()\nidentify_obj.post_insert(\"tags\", \"premium\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Remove from Array\n\n```python\nidentify_obj = Identify()\nidentify_obj.remove(\"blocked_users\", \"user123\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Unset Property\n\n```python\nidentify_obj = Identify()\nidentify_obj.unset(\"temporary_token\")\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Clear All Properties\n\n```python\nidentify_obj = Identify()\nidentify_obj.clear_all()\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Chain Multiple Operations\n\n```python\nidentify_obj = (Identify()\n    .set(\"plan\", \"premium\")\n    .add(\"login_count\", 1)\n    .append(\"visited_pages\", \"/checkout\")\n    .set_once(\"signup_date\", \"2025-01-01\")\n)\n\nclient.identify(identify_obj, EventOptions(user_id=\"user@example.com\"))\n```\n\n---\n\n### Group Analytics\n\n#### Set Single Group\n\n```python\nfrom amplitude import EventOptions\n\nclient.set_group(\n    group_type=\"organization\",\n    group_name=\"acme-corp\",\n    event_options=EventOptions(user_id=\"user@example.com\")\n)\n```\n\n#### Set Multiple Groups\n\n```python\nclient.set_group(\n    group_type=\"teams\",\n    group_name=[\"engineering\", \"product\", \"design\"],\n    event_options=EventOptions(user_id=\"user@example.com\")\n)\n```\n\n#### Set Group Properties\n\n```python\nfrom amplitude import Identify\n\nidentify_obj = Identify()\nidentify_obj.set(\"plan\", \"enterprise\")\nidentify_obj.set(\"seats\", 100)\nidentify_obj.set(\"industry\", \"technology\")\n\nclient.group_identify(\n    group_type=\"organization\",\n    group_name=\"acme-corp\",\n    identify_obj=identify_obj,\n    event_options=EventOptions(user_id=\"user@example.com\")\n)\n```\n\n#### Event-Level Groups\n\n```python\nevent = BaseEvent(\n    event_type=\"Feature Used\",\n    user_id=\"user@example.com\",\n    groups={\n        \"organization\": \"acme-corp\",\n        \"department\": \"sales\"\n    }\n)\n\nclient.track(event)\n```\n\n---\n\n### Revenue Tracking\n\n#### Basic Revenue\n\n```python\nfrom amplitude import Revenue, EventOptions\n\nrevenue = Revenue(\n    price=9.99,\n    quantity=1,\n    product_id=\"com.company.product\"\n)\n\nclient.revenue(revenue, EventOptions(user_id=\"user@example.com\"))\n```\n\n#### Advanced Revenue Tracking\n\n```python\nrevenue = Revenue(\n    price=29.99,\n    quantity=2,\n    product_id=\"SKU-123\",\n    revenue_type=\"purchase\",\n    receipt=\"receipt-id-12345\",\n    receipt_sig=\"signature-abc\",\n    properties={\n        \"region\": \"US\",\n        \"currency\": \"USD\",\n        \"payment_method\": \"credit_card\",\n        \"discount_applied\": True\n    }\n)\n\nclient.revenue(revenue, EventOptions(user_id=\"user@example.com\"))\n```\n\n---\n\n### Plugin System\n\n#### Enrichment Plugin\n\n```python\nfrom amplitude import EventPlugin, PluginType\nimport platform\n\nclass SystemInfoPlugin(EventPlugin):\n    def __init__(self):\n        self.plugin_type = PluginType.ENRICHMENT\n        self.configuration = None\n\n    def setup(self, client):\n        self.configuration = client.configuration\n        print(\"System Info Plugin initialized\")\n\n    def execute(self, event):\n        if event.event_properties is None:\n            event.event_properties = {}\n\n        event.event_properties.update({\n            'plugin_system': platform.system(),\n            'plugin_python_version': platform.python_version(),\n            'plugin_timestamp': int(time.time() * 1000)\n        })\n\n        return event\n\nclient.add(SystemInfoPlugin())\n```\n\n#### Destination Plugin\n\n```python\nimport requests\n\nclass CustomAnalyticsPlugin(EventPlugin):\n    def __init__(self, api_url, api_token):\n        self.plugin_type = PluginType.DESTINATION\n        self.api_url = api_url\n        self.api_token = api_token\n        self.configuration = None\n\n    def setup(self, client):\n        self.configuration = client.configuration\n        print(\"Custom Analytics Plugin initialized\")\n\n    def execute(self, event):\n        try:\n            response = requests.post(\n                self.api_url,\n                headers={\n                    'Content-Type': 'application/json',\n                    'Authorization': f'Bearer {self.api_token}'\n                },\n                json={\n                    'event_type': event.event_type,\n                    'user_id': event.user_id,\n                    'properties': event.event_properties\n                }\n            )\n\n            return event\n        except Exception as e:\n            print(f\"Error sending to custom analytics: {e}\")\n            return event\n\nclient.add(CustomAnalyticsPlugin(\n    api_url='https://api.custom-analytics.com/events',\n    api_token='your_token_here'\n))\n```\n\n#### Remove Plugin\n\n```python\nclient.remove(\"plugin-name\")\n```\n\n---\n\n### Buffer Management\n\n#### Flush Events Immediately\n\n```python\nclient.flush()\n```\n\n#### Async Flush with Callback\n\n```python\ndef flush_callback(code, message):\n    if code == 200:\n        print(\"Flush successful\")\n    else:\n        print(f\"Flush failed: {message}\")\n\nclient.flush(callback=flush_callback)\n```\n\n---\n\n### Shutdown\n\n```python\n# Flush remaining events and close client\nclient.shutdown()\n```\n\n---\n\n### Opt-Out Control\n\n```python\n# Disable tracking\nclient.configuration.opt_out = True\n\n# Enable tracking\nclient.configuration.opt_out = False\n```\n\n---\n\n## Event Options\n\n```python\nfrom amplitude import EventOptions\n\noptions = EventOptions(\n    user_id=\"user@example.com\",\n    device_id=\"device-123\",\n    session_id=1234567890,\n    app_version=\"1.2.3\",\n    platform=\"Web\",\n    os_name=\"MacOS\",\n    os_version=\"14.2\",\n    device_brand=\"Apple\",\n    device_manufacturer=\"Apple\",\n    device_model=\"MacBook Pro\",\n    carrier=\"N/A\",\n    country=\"US\",\n    region=\"California\",\n    city=\"San Francisco\",\n    language=\"en-US\",\n    ip=\"203.0.113.42\"\n)\n```\n\n---\n\n## Common Patterns\n\n### Initialize with Environment Variables\n\n```python\nimport os\nfrom amplitude import Amplitude\n\nAPI_KEY = os.environ.get('AMPLITUDE_API_KEY')\n\nif not API_KEY:\n    raise ValueError(\"AMPLITUDE_API_KEY environment variable not set\")\n\nclient = Amplitude(API_KEY)\n```\n\n### Track User Signup\n\n```python\nfrom amplitude import BaseEvent, Identify, EventOptions\n\n# Track signup event\nevent = BaseEvent(\n    event_type=\"User Signed Up\",\n    user_id=\"new_user@example.com\",\n    event_properties={\n        \"signup_method\": \"google\",\n        \"referral_source\": \"friend\"\n    }\n)\nclient.track(event)\n\n# Set initial user properties\nidentify = Identify()\nidentify.set(\"signup_date\", \"2025-01-07\")\nidentify.set(\"plan\", \"free\")\nidentify.set_once(\"first_source\", \"google\")\n\nclient.identify(identify, EventOptions(user_id=\"new_user@example.com\"))\n```\n\n### Track Page Views\n\n```python\nevent = BaseEvent(\n    event_type=\"Page Viewed\",\n    user_id=\"user@example.com\",\n    event_properties={\n        \"page_url\": \"/dashboard\",\n        \"page_title\": \"Dashboard\",\n        \"referrer\": \"/home\"\n    }\n)\n\nclient.track(event)\n```\n\n### Track API Requests\n\n```python\nimport time\n\nstart_time = time.time()\n\n# Make API request\nresponse = requests.get('https://api.example.com/data')\n\nduration_ms = int((time.time() - start_time) * 1000)\n\nevent = BaseEvent(\n    event_type=\"API Request\",\n    user_id=\"user@example.com\",\n    event_properties={\n        \"endpoint\": \"/data\",\n        \"method\": \"GET\",\n        \"status_code\": response.status_code,\n        \"duration_ms\": duration_ms\n    }\n)\n\nclient.track(event)\n```\n\n### Track Errors\n\n```python\ntry:\n    # Some operation\n    result = perform_operation()\nexcept Exception as e:\n    event = BaseEvent(\n        event_type=\"Error Occurred\",\n        user_id=\"user@example.com\",\n        event_properties={\n            \"error_type\": type(e).__name__,\n            \"error_message\": str(e),\n            \"function_name\": \"perform_operation\"\n        }\n    )\n    client.track(event)\n    raise\n```\n\n---\n\n## Flask Integration\n\n```python\nfrom flask import Flask, request, g\nfrom amplitude import Amplitude, BaseEvent\n\napp = Flask(__name__)\namplitude_client = Amplitude(os.environ['AMPLITUDE_API_KEY'])\n\n@app.before_request\ndef before_request():\n    g.user_id = request.headers.get('X-User-ID')\n\n@app.after_request\ndef after_request(response):\n    if g.user_id:\n        event = BaseEvent(\n            event_type=\"API Request\",\n            user_id=g.user_id,\n            event_properties={\n                \"method\": request.method,\n                \"path\": request.path,\n                \"status_code\": response.status_code\n            }\n        )\n        amplitude_client.track(event)\n\n    return response\n\n@app.route('/api/action')\ndef api_action():\n    amplitude_client.track(BaseEvent(\n        event_type=\"Action Performed\",\n        user_id=g.user_id,\n        event_properties={\n            \"action\": \"api_action\"\n        }\n    ))\n    return {\"status\": \"success\"}\n\nif __name__ == '__main__':\n    try:\n        app.run()\n    finally:\n        amplitude_client.shutdown()\n```\n\n---\n\n## Django Integration\n\n```python\n# middleware.py\nfrom amplitude import Amplitude, BaseEvent\nimport os\n\namplitude_client = Amplitude(os.environ.get('AMPLITUDE_API_KEY'))\n\nclass AmplitudeMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n\n        if hasattr(request, 'user') and request.user.is_authenticated:\n            event = BaseEvent(\n                event_type=\"Page Viewed\",\n                user_id=str(request.user.id),\n                event_properties={\n                    \"path\": request.path,\n                    \"method\": request.method,\n                    \"status_code\": response.status_code\n                }\n            )\n            amplitude_client.track(event)\n\n        return response\n\n# settings.py\nMIDDLEWARE = [\n    # ... other middleware\n    'myapp.middleware.AmplitudeMiddleware',\n]\n```\n\n---\n\n## FastAPI Integration\n\n```python\nfrom fastapi import FastAPI, Request, Depends\nfrom amplitude import Amplitude, BaseEvent\nimport os\n\napp = FastAPI()\namplitude_client = Amplitude(os.environ['AMPLITUDE_API_KEY'])\n\n@app.middleware(\"http\")\nasync def amplitude_middleware(request: Request, call_next):\n    response = await call_next(request)\n\n    user_id = request.headers.get('X-User-ID')\n    if user_id:\n        event = BaseEvent(\n            event_type=\"API Request\",\n            user_id=user_id,\n            event_properties={\n                \"method\": request.method,\n                \"path\": request.url.path,\n                \"status_code\": response.status_code\n            }\n        )\n        amplitude_client.track(event)\n\n    return response\n\n@app.on_event(\"shutdown\")\nasync def shutdown_event():\n    amplitude_client.shutdown()\n\n@app.post(\"/action\")\nasync def perform_action(user_id: str):\n    amplitude_client.track(BaseEvent(\n        event_type=\"Action Performed\",\n        user_id=user_id,\n        event_properties={\n            \"action\": \"perform_action\"\n        }\n    ))\n    return {\"status\": \"success\"}\n```\n\n---\n\n## Celery Integration\n\n```python\nfrom celery import Celery\nfrom amplitude import Amplitude, BaseEvent\nimport os\n\napp = Celery('tasks', broker='redis://localhost:6379/0')\namplitude_client = Amplitude(os.environ['AMPLITUDE_API_KEY'])\n\n@app.task\ndef process_order(order_id, user_id):\n    # Process order\n    result = process_order_logic(order_id)\n\n    # Track event\n    event = BaseEvent(\n        event_type=\"Order Processed\",\n        user_id=user_id,\n        event_properties={\n            \"order_id\": order_id,\n            \"status\": result.status,\n            \"processing_time_ms\": result.duration\n        }\n    )\n    amplitude_client.track(event)\n\n    return result\n\n@app.on_after_finalize.connect\ndef shutdown_amplitude(sender, **kwargs):\n    amplitude_client.shutdown()\n```\n\n---\n\n## Batch Event Tracking\n\n```python\nfrom amplitude import BaseEvent\n\nevents = [\n    BaseEvent(\n        event_type=\"Event 1\",\n        user_id=\"user@example.com\",\n        event_properties={\"property\": \"value1\"}\n    ),\n    BaseEvent(\n        event_type=\"Event 2\",\n        user_id=\"user@example.com\",\n        event_properties={\"property\": \"value2\"}\n    ),\n    BaseEvent(\n        event_type=\"Event 3\",\n        user_id=\"user@example.com\",\n        event_properties={\"property\": \"value3\"}\n    )\n]\n\nfor event in events:\n    client.track(event)\n\n# Flush all events\nclient.flush()\n```\n\n---\n\n## EU Data Residency\n\n```python\nclient = Amplitude(\n    api_key='YOUR_API_KEY',\n    configuration={\n        'server_zone': 'EU'\n    }\n)\n```\n\n---\n\n## Custom Server URL\n\n```python\nclient = Amplitude(\n    api_key='YOUR_API_KEY',\n    configuration={\n        'server_url': 'https://proxy.example.com/amplitude'\n    }\n)\n```\n\n---\n\n## Use Batch API Endpoint\n\n```python\nclient = Amplitude(\n    api_key='YOUR_API_KEY',\n    configuration={\n        'use_batch': True\n    }\n)\n```\n\n---\n\n## Event Callback\n\n```python\ndef event_callback(event, code, message):\n    if code == 200:\n        print(f\"Event '{event.event_type}' sent successfully\")\n    else:\n        print(f\"Failed to send event: {message}\")\n\nclient = Amplitude(\n    api_key='YOUR_API_KEY',\n    configuration={\n        'callback': event_callback\n    }\n)\n```\n\n---\n\n## HTTP API Direct Usage\n\n### Basic Request\n\n```python\nimport requests\nimport time\n\npayload = {\n    \"api_key\": \"YOUR_API_KEY\",\n    \"events\": [\n        {\n            \"user_id\": \"user@example.com\",\n            \"device_id\": \"device-123\",\n            \"event_type\": \"Page Viewed\",\n            \"time\": int(time.time() * 1000),\n            \"event_properties\": {\n                \"page\": \"homepage\"\n            }\n        }\n    ]\n}\n\nresponse = requests.post(\n    'https://api2.amplitude.com/2/httpapi',\n    json=payload\n)\n\nprint(response.json())\n```\n\n### Batch Request\n\n```python\npayload = {\n    \"api_key\": \"YOUR_API_KEY\",\n    \"events\": [\n        {\n            \"user_id\": \"user1@example.com\",\n            \"event_type\": \"Event 1\",\n            \"time\": int(time.time() * 1000)\n        },\n        {\n            \"user_id\": \"user2@example.com\",\n            \"event_type\": \"Event 2\",\n            \"time\": int(time.time() * 1000)\n        }\n    ]\n}\n\nresponse = requests.post(\n    'https://api2.amplitude.com/2/httpapi',\n    json=payload\n)\n```\n\n### EU Endpoint\n\n```python\nresponse = requests.post(\n    'https://api.eu.amplitude.com/2/httpapi',\n    json=payload\n)\n```\n\n---\n\n## Threading Considerations\n\nThe SDK is thread-safe and automatically manages background threads for event flushing.\n\n```python\nimport threading\nfrom amplitude import Amplitude, BaseEvent\n\nclient = Amplitude('YOUR_API_KEY')\n\ndef worker(user_id):\n    for i in range(10):\n        event = BaseEvent(\n            event_type=\"Worker Event\",\n            user_id=user_id,\n            event_properties={\n                \"iteration\": i\n            }\n        )\n        client.track(event)\n\nthreads = []\nfor i in range(5):\n    thread = threading.Thread(target=worker, args=(f\"user{i}@example.com\",))\n    threads.append(thread)\n    thread.start()\n\nfor thread in threads:\n    thread.join()\n\nclient.shutdown()\n```\n\n---\n\n## Logging Configuration\n\n```python\nimport logging\n\n# Enable debug logging\nlogging.basicConfig(level=logging.DEBUG)\n\nclient = Amplitude('YOUR_API_KEY')\n```\n\n---\n\n## Testing\n\n### Mock Amplitude for Tests\n\n```python\nfrom unittest.mock import Mock, patch\nimport pytest\n\n@pytest.fixture\ndef mock_amplitude():\n    with patch('amplitude.Amplitude') as mock:\n        yield mock\n\ndef test_event_tracking(mock_amplitude):\n    client = mock_amplitude.return_value\n\n    event = BaseEvent(\n        event_type=\"Test Event\",\n        user_id=\"test_user\"\n    )\n\n    client.track(event)\n    client.track.assert_called_once()\n```\n\n---\n\n## Error Handling\n\n```python\nfrom amplitude import Amplitude, BaseEvent\n\ntry:\n    client = Amplitude('YOUR_API_KEY')\n\n    event = BaseEvent(\n        event_type=\"Test Event\",\n        user_id=\"user@example.com\"\n    )\n\n    client.track(event)\n    client.flush()\n\nexcept Exception as e:\n    print(f\"Error tracking event: {e}\")\n\nfinally:\n    client.shutdown()\n```\n\n---\n\n## Constraints & Limits\n\n- **Minimum ID length:** 5 characters (configurable via `min_id_length`)\n- **Event batch size:** 200 events by default (`flush_queue_size`)\n- **Flush interval:** 10 seconds by default (`flush_interval_millis`)\n- **User ID or Device ID required:** At least one must be provided\n- **Python version:** Requires Python >= 3.6 and < 4\n\n---\n\n## Complete Example\n\n```python\nimport os\nfrom amplitude import Amplitude, BaseEvent, Identify, Revenue, EventOptions\nfrom dotenv import load_dotenv\n\n# Load environment variables\nload_dotenv()\n\n# Initialize client\nclient = Amplitude(\n    api_key=os.environ['AMPLITUDE_API_KEY'],\n    configuration={\n        'flush_queue_size': 100,\n        'flush_interval_millis': 5000,\n        'server_zone': 'US'\n    }\n)\n\ntry:\n    # Track user signup\n    signup_event = BaseEvent(\n        event_type=\"User Signed Up\",\n        user_id=\"user@example.com\",\n        event_properties={\n            \"signup_method\": \"email\",\n            \"referral_source\": \"organic\"\n        }\n    )\n    client.track(signup_event)\n\n    # Set user properties\n    identify = Identify()\n    identify.set(\"name\", \"John Doe\")\n    identify.set(\"email\", \"user@example.com\")\n    identify.set(\"plan\", \"free\")\n    identify.set_once(\"signup_date\", \"2025-01-07\")\n\n    client.identify(identify, EventOptions(user_id=\"user@example.com\"))\n\n    # Set group\n    client.set_group(\n        group_type=\"organization\",\n        group_name=\"acme-corp\",\n        event_options=EventOptions(user_id=\"user@example.com\")\n    )\n\n    # Track purchase\n    purchase_event = BaseEvent(\n        event_type=\"Product Purchased\",\n        user_id=\"user@example.com\",\n        event_properties={\n            \"product_id\": \"SKU-123\",\n            \"product_name\": \"Premium Plan\",\n            \"category\": \"subscription\"\n        }\n    )\n    client.track(purchase_event)\n\n    # Track revenue\n    revenue = Revenue(\n        price=29.99,\n        quantity=1,\n        product_id=\"SKU-123\",\n        revenue_type=\"purchase\"\n    )\n    client.revenue(revenue, EventOptions(user_id=\"user@example.com\"))\n\n    # Flush all events\n    client.flush()\n\nfinally:\n    # Clean shutdown\n    client.shutdown()\n```\n"
  },
  {
    "path": "content/amqp/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"amqp Python client for AMQP 0-9-1 brokers with direct connection, channel, publish, and consume APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"amqp,rabbitmq,messaging,broker,python\"\n---\n\n# amqp Python Package Guide\n\n## Golden Rule\n\nUse the maintainer package `amqp` for direct AMQP 0-9-1 protocol access from Python. The upstream project is `py-amqp`, published on PyPI as `amqp`.\n\nThis library is low level compared with Celery or Kombu: you open a `Connection`, create a `Channel`, declare broker objects, publish `Message` instances, and acknowledge deliveries yourself.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\npython -m pip install \"amqp==5.3.1\"\n```\n\nTypical broker settings:\n\n```bash\nexport AMQP_HOST=localhost\nexport AMQP_PORT=5672\nexport AMQP_USER=guest\nexport AMQP_PASSWORD=guest\nexport AMQP_VHOST=/\nexport AMQP_HEARTBEAT=30\n```\n\nFor TLS connections, brokers commonly listen on port `5671`.\n\n## Connect And Open A Channel\n\n`Connection(...)` does not open the socket by itself. Call `connect()` before creating or using channels.\n\n```python\nimport os\n\nimport amqp\n\nwith amqp.Connection(\n    host=os.getenv(\"AMQP_HOST\", \"localhost\"),\n    port=int(os.getenv(\"AMQP_PORT\", \"5672\")),\n    userid=os.environ[\"AMQP_USER\"],\n    password=os.environ[\"AMQP_PASSWORD\"],\n    virtual_host=os.getenv(\"AMQP_VHOST\", \"/\"),\n    heartbeat=int(os.getenv(\"AMQP_HEARTBEAT\", \"30\")),\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n\n    print(\"Connected:\", connection.connected)\n    print(\"Channel id:\", channel.channel_id)\n\n    channel.close()\n```\n\n## Declare An Exchange And Queue\n\nThe channel API exposes AMQP primitives directly. For long-lived broker objects, set `durable=True` and `auto_delete=False` explicitly.\n\n```python\nimport amqp\n\nwith amqp.Connection(\n    host=\"localhost\",\n    userid=\"guest\",\n    password=\"guest\",\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n\n    channel.exchange_declare(\n        exchange=\"events\",\n        type=\"direct\",\n        durable=True,\n        auto_delete=False,\n    )\n    channel.queue_declare(\n        queue=\"events.orders\",\n        durable=True,\n        auto_delete=False,\n    )\n    channel.queue_bind(\n        queue=\"events.orders\",\n        exchange=\"events\",\n        routing_key=\"orders.created\",\n    )\n```\n\n## Publish A Message\n\nCreate an `amqp.Message` and publish it through the channel. `basic_publish()` defaults `exchange` to the empty string, which is the AMQP default exchange, so use an explicit exchange name when routing through your own topology.\n\n```python\nimport json\n\nimport amqp\n\npayload = {\"order_id\": \"ord_123\", \"status\": \"created\"}\n\nwith amqp.Connection(\n    host=\"localhost\",\n    userid=\"guest\",\n    password=\"guest\",\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n\n    message = amqp.Message(\n        body=json.dumps(payload).encode(\"utf-8\"),\n        content_type=\"application/json\",\n        content_encoding=\"utf-8\",\n        delivery_mode=2,\n    )\n\n    channel.basic_publish(\n        msg=message,\n        exchange=\"events\",\n        routing_key=\"orders.created\",\n    )\n```\n\nIf you want to send directly to a queue through the default exchange, publish with `exchange=\"\"` and set `routing_key` to the queue name.\n\n## Read A Message With `basic_get`\n\n`basic_get()` is a polling call. It returns one message if available, or `None` if the queue is empty.\n\n```python\nimport json\n\nimport amqp\n\nwith amqp.Connection(\n    host=\"localhost\",\n    userid=\"guest\",\n    password=\"guest\",\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n\n    message = channel.basic_get(queue=\"events.orders\", no_ack=False)\n    if message is not None:\n        payload = json.loads(message.body)\n        print(payload)\n\n        channel.basic_ack(message.delivery_info[\"delivery_tag\"])\n```\n\nUse `no_ack=False` when you need broker-managed redelivery on failure. If you set `no_ack=True`, the broker considers the delivery handled as soon as it sends it.\n\n## Consume In A Loop\n\nFor push-style consumption, register a callback with `basic_consume()` and keep the connection alive by calling `drain_events()`. If heartbeats are enabled, call `heartbeat_tick()` regularly in the loop.\n\n```python\nimport json\nimport socket\n\nimport amqp\n\nwith amqp.Connection(\n    host=\"localhost\",\n    userid=\"guest\",\n    password=\"guest\",\n    heartbeat=30,\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n\n    def handle_message(message):\n        payload = json.loads(message.body)\n        print(\"received\", payload)\n        channel.basic_ack(message.delivery_info[\"delivery_tag\"])\n\n    consumer_tag = channel.basic_consume(\n        queue=\"events.orders\",\n        no_ack=False,\n        callback=handle_message,\n    )\n\n    try:\n        while True:\n            try:\n                connection.drain_events(timeout=1)\n            except socket.timeout:\n                pass\n            connection.heartbeat_tick()\n    finally:\n        channel.basic_cancel(consumer_tag)\n```\n\n## Connect With TLS\n\nSince the 5.2.x line, `Connection(..., ssl=...)` accepts a standard `ssl.SSLContext`, which is the simplest way to enforce CA validation and load client certificates when your broker requires them.\n\n```python\nimport os\nimport ssl\n\nimport amqp\n\ncontext = ssl.create_default_context(cafile=os.environ[\"AMQP_CA_CERT\"])\ncontext.load_cert_chain(\n    certfile=os.environ[\"AMQP_CLIENT_CERT\"],\n    keyfile=os.environ[\"AMQP_CLIENT_KEY\"],\n)\n\nwith amqp.Connection(\n    host=os.environ[\"AMQP_HOST\"],\n    port=5671,\n    userid=os.environ[\"AMQP_USER\"],\n    password=os.environ[\"AMQP_PASSWORD\"],\n    virtual_host=os.getenv(\"AMQP_VHOST\", \"/\"),\n    ssl=context,\n) as connection:\n    connection.connect()\n    channel = connection.channel()\n```\n\n## Common Pitfalls\n\n- Call `connection.connect()` explicitly. Constructing `Connection(...)` or entering its context manager is not enough.\n- `exchange_declare()` and `queue_declare()` default to `durable=False` and `auto_delete=True`. That is usually wrong for shared production queues and exchanges.\n- `basic_get()` is non-blocking polling. For continuous workers, use `basic_consume()` with `drain_events()`.\n- If you enable heartbeats, your consumer loop must call `connection.heartbeat_tick()` often enough to send and check heartbeat frames.\n- Deliveries are not acknowledged automatically when `no_ack=False`; call `basic_ack()` with the delivery tag after successful processing.\n- `Message.body` is binary-safe. When you publish JSON, encode before sending and decode or deserialize after receiving.\n\n## Version-Sensitive Notes\n\n- `amqp 5.3.1` includes a heartbeat retry fix that resets connection byte counters after a heartbeat exception. If you saw heartbeat-related reconnect issues on older 5.3 builds, upgrade to `5.3.1`.\n- The `5.2.0` release added support for passing an `ssl.SSLContext` directly through the `ssl` argument on `Connection`.\n\n## Official Sources\n\n- py-amqp repository: https://github.com/celery/py-amqp\n- PyPI package page: https://pypi.org/project/amqp/\n- README and quick start: https://raw.githubusercontent.com/celery/py-amqp/main/README.rst\n- API reference index: https://docs.celeryq.dev/projects/amqp/en/stable/reference/index.html\n- `amqp.connection.Connection`: https://docs.celeryq.dev/projects/amqp/en/stable/reference/amqp.connection.html\n- `amqp.channel.Channel`: https://docs.celeryq.dev/projects/amqp/en/stable/reference/amqp.channel.html\n- `amqp.basic_message.Message`: https://docs.celeryq.dev/projects/amqp/en/stable/reference/amqp.basic_message.html\n- Changelog: https://raw.githubusercontent.com/celery/py-amqp/main/Changelog\n"
  },
  {
    "path": "content/angular/docs/core/typescript/DOC.md",
    "content": "---\nname: core\ndescription: \"Angular core runtime for standalone components, dependency injection, signals, and lifecycle APIs in TypeScript apps\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"21.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"angular,typescript,ui,framework,signals,dependency-injection\"\n---\n\n# Angular Core for TypeScript\n\n`@angular/core` provides Angular's decorators, dependency injection, signals, lifecycle hooks, and application configuration types. For a browser app, pair it with `@angular/platform-browser`, and usually `@angular/common`.\n\n## Install\n\nFor a new app, start with the Angular CLI:\n\n```bash\nnpm create @angular@latest my-app\ncd my-app\nnpm start\n```\n\nIf you are wiring Angular manually, install the runtime packages plus the Angular compiler for builds:\n\n```bash\nnpm install @angular/core @angular/common @angular/platform-browser rxjs zone.js\nnpm install -D @angular/compiler-cli typescript\n```\n\n`@angular/core` does not require package-specific environment variables.\n\n## TypeScript and compiler setup\n\nAngular templates are compiled by the Angular compiler. The Angular CLI already generates the required config. If you maintain your own build, keep TypeScript strict mode on and enable strict template checking:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true\n  },\n  \"angularCompilerOptions\": {\n    \"strictTemplates\": true\n  }\n}\n```\n\nUse `strictTemplates` to catch missing inputs, invalid event payloads, and nullable template bindings at build time.\n\n## Bootstrap a standalone app\n\nAngular applications are typically bootstrapped with a standalone root component.\n\n`src/app/app.config.ts`:\n\n```ts\nimport { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideZoneChangeDetection({ eventCoalescing: true })],\n};\n```\n\n`src/main.ts`:\n\n```ts\nimport 'zone.js';\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { appConfig } from './app/app.config';\n\nbootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));\n```\n\nIf you use the Angular CLI defaults, `zone.js` is already configured for you. Keep the explicit import only in a manual setup that uses zone-based change detection.\n\n## Create a standalone component with signals\n\nUse `@Component` with `standalone: true`, and keep reactive state in signals.\n\n`src/app/app.component.ts`:\n\n```ts\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  signal,\n} from '@angular/core';\nimport { TodoItemComponent } from './todo-item.component';\n\ntype Todo = {\n  id: number;\n  label: string;\n  done: boolean;\n};\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  imports: [TodoItemComponent],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <h1>{{ title() }}</h1>\n    <p>{{ remaining() }} remaining</p>\n\n    <button type=\"button\" (click)=\"addTodo()\">Add item</button>\n\n    @for (todo of todos(); track todo.id) {\n      <app-todo-item\n        [label]=\"todo.label\"\n        [done]=\"todo.done\"\n        (doneChange)=\"setDone(todo.id, $event)\"\n      />\n    }\n  `,\n})\nexport class AppComponent {\n  readonly title = signal('Angular Core example');\n\n  readonly todos = signal<Todo[]>([\n    { id: 1, label: 'Install Angular', done: true },\n    { id: 2, label: 'Create a standalone component', done: false },\n  ]);\n\n  readonly remaining = computed(\n    () => this.todos().filter((todo) => !todo.done).length,\n  );\n\n  addTodo(): void {\n    this.todos.update((items) => [\n      ...items,\n      {\n        id: items.length + 1,\n        label: `Task ${items.length + 1}`,\n        done: false,\n      },\n    ]);\n  }\n\n  setDone(id: number, done: boolean): void {\n    this.todos.update((items) =>\n      items.map((item) => (item.id === id ? { ...item, done } : item)),\n    );\n  }\n}\n```\n\n`ChangeDetectionStrategy.OnPush` works well with signals and keeps updates predictable.\n\n## Accept typed inputs and emit outputs\n\nThe `input()` and `output()` helpers keep component APIs strongly typed.\n\n`src/app/todo-item.component.ts`:\n\n```ts\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  input,\n  output,\n} from '@angular/core';\n\n@Component({\n  selector: 'app-todo-item',\n  standalone: true,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <button type=\"button\" (click)=\"doneChange.emit(!done())\">\n      {{ done() ? '✓' : '○' }} {{ label() }}\n    </button>\n  `,\n})\nexport class TodoItemComponent {\n  readonly label = input.required<string>();\n  readonly done = input(false);\n  readonly doneChange = output<boolean>();\n}\n```\n\nUse `input.required<T>()` when the parent must always bind a value. Read input signals in the template with `label()` and `done()`.\n\n## Provide and inject services\n\nAngular services are regular classes annotated with `@Injectable`. Use `inject()` in field initializers, constructors, or provider factories.\n\n`src/app/timer.service.ts`:\n\n```ts\nimport { DestroyRef, Injectable, inject, signal } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nexport class TimerService {\n  private readonly destroyRef = inject(DestroyRef);\n\n  readonly seconds = signal(0);\n\n  constructor() {\n    const timer = setInterval(() => {\n      this.seconds.update((value) => value + 1);\n    }, 1000);\n\n    this.destroyRef.onDestroy(() => clearInterval(timer));\n  }\n}\n```\n\nInject the service from a component:\n\n```ts\nimport { Component, inject } from '@angular/core';\nimport { TimerService } from './timer.service';\n\n@Component({\n  selector: 'app-clock',\n  standalone: true,\n  template: `<p>Seconds: {{ timer.seconds() }}</p>`,\n})\nexport class ClockComponent {\n  readonly timer = inject(TimerService);\n}\n```\n\n## Common pitfalls\n\n- `@angular/core` is not enough to render a browser app by itself; use it with `@angular/platform-browser`, and usually `@angular/common`.\n- Standalone components must list every imported component, directive, and pipe in `imports`.\n- Do not mutate objects or arrays stored in a signal in place. Call `.set()` or `.update()` with a new value.\n- `inject()` only works inside an Angular injection context, such as a constructor, field initializer, or provider factory.\n- Environment values exposed to browser code are public. Keep secrets on the server, not in Angular app config.\n"
  },
  {
    "path": "content/annotated-types/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"annotated-types for Python - reusable typing.Annotated metadata for bounds, lengths, predicates, timezones, units, and inline docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,typing,annotated,constraints,metadata,validation\"\n---\n\n# annotated-types Python Package Guide\n\n## What It Is\n\n`annotated-types` provides reusable metadata objects for `typing.Annotated`. Use it when you want to describe constraints and extra meaning in type annotations without inventing your own marker classes.\n\nCommon uses include:\n\n- scalar bounds such as `Gt(0)` or `Le(100)`\n- length constraints such as `Len(1, 64)`\n- divisibility with `MultipleOf(...)`\n- timezone requirements for `datetime` and `time`\n- physical-unit hints with `Unit(...)`\n- inline annotation docs with `doc(...)`\n\nImportant: `annotated-types` does not validate values by itself. It defines metadata that downstream libraries or your own code can inspect.\n\n## Installation\n\n```bash\npip install annotated-types==0.7.0\n```\n\n```bash\nuv add annotated-types==0.7.0\n```\n\nPython requirement for `annotated-types` 0.7.0: Python 3.8+.\n\nOn Python 3.8, the package depends on `typing-extensions` so you can use `Annotated` there too.\n\n## Imports At A Glance\n\n```python\nimport sys\nfrom datetime import datetime, timezone\nfrom typing import get_args, get_origin\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import (\n    Ge,\n    Gt,\n    GroupedMetadata,\n    Interval,\n    IsDigits,\n    IsFinite,\n    Le,\n    Len,\n    LowerCase,\n    MaxLen,\n    MinLen,\n    MultipleOf,\n    Predicate,\n    Timezone,\n    Unit,\n    doc,\n)\n```\n\n## Setup Notes\n\n- No environment variables, auth, or client initialization are required.\n- The package is pure Python metadata; importing it does not activate validation.\n- Prefer statically inspectable metadata such as `Gt`, `Len`, or `Timezone` when possible.\n- Use `Predicate(...)` when you need custom logic that cannot be expressed with the built-in markers.\n\n## Core Usage\n\n### Scalar Bounds With `Gt`, `Ge`, `Lt`, `Le`\n\n```python\nimport sys\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Ge, Gt, Le, Lt\n\nPositiveInt = Annotated[int, Gt(0)]\nPercent = Annotated[float, Ge(0), Le(100)]\nPortNumber = Annotated[int, Ge(1), Lt(65536)]\n```\n\nThese markers work with any type that supports the matching comparison operator, not only numbers.\n\n### Combine Bounds With `Interval`\n\n`Interval` groups lower and upper bounds into one metadata object.\n\n```python\nimport sys\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Interval\n\nHumanBodyTempC = Annotated[float, Interval(ge=35.0, le=42.0)]\n```\n\nFor consumers that unpack grouped metadata, `Interval(ge=35.0, le=42.0)` expands into `Ge(35.0)` and `Le(42.0)`.\n\n### Length Constraints With `MinLen`, `MaxLen`, `Len`\n\n```python\nimport sys\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Len, MaxLen, MinLen\n\nNonEmptyString = Annotated[str, MinLen(1)]\nShortName = Annotated[str, Len(1, 64)]\nTagList = Annotated[List[str], Len(1, 10)]\nBatch = Annotated[List[int], MaxLen(100)]\n```\n\n`Len(min_length, max_length)` uses inclusive bounds in 0.7.0, so `Len(8, 8)` means exactly length 8.\n\n### Divisibility With `MultipleOf`\n\n```python\nimport sys\nfrom decimal import Decimal\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import MultipleOf\n\nEvenNumber = Annotated[int, MultipleOf(2)]\nNickelAmount = Annotated[Decimal, MultipleOf(Decimal(\"0.05\"))]\n```\n\n`MultipleOf` is metadata only. Consumers need to document whether they use Python `%` semantics or JSON Schema style semantics for divisibility.\n\n### Datetime Requirements With `Timezone`\n\n```python\nimport sys\nfrom datetime import datetime, timezone\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Timezone\n\nNaiveDateTime = Annotated[datetime, Timezone(None)]\nAwareDateTime = Annotated[datetime, Timezone(...)]\nUTCDateTime = Annotated[datetime, Timezone(timezone.utc)]\n```\n\nUse `Timezone(None)` for naive datetimes, `Timezone(...)` for any timezone-aware value, or pass a specific timezone string or `tzinfo` object when a consumer should require one exact timezone.\n\n### Units And Predicate-Based Constraints\n\n```python\nimport sys\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import IsDigits, IsFinite, LowerCase, Predicate, Unit\n\nVelocity = Annotated[float, Unit(\"m/s\")]\nAccountCode = Annotated[str, Predicate(str.isalnum)]\nSlug = LowerCase[str]\nPostalCode = IsDigits[str]\nReading = IsFinite[float]\n```\n\n`Unit(...)` does not parse or validate the unit string itself. It is a hint for downstream tooling.\n\n`Predicate(...)` is the escape hatch for arbitrary truthy checks. Prefer named callables such as `str.isalnum` over lambdas so consumers can introspect them more easily.\n\n### Add Inline Documentation With `doc(...)`\n\n```python\nimport sys\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Gt, doc\n\nUserId = Annotated[int, Gt(0), doc(\"Internal numeric user identifier\")]\n```\n\n`doc(...)` adds documentation metadata inside `Annotated`. Tools can extract it at runtime from the returned `DocInfo` object.\n\n## Reusable Aliases In Application Code\n\nDefining aliases keeps model annotations consistent across an application.\n\n```python\nimport sys\nfrom dataclasses import dataclass\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated\nelse:\n    from typing_extensions import Annotated\n\nfrom annotated_types import Ge, Len, LowerCase\n\nAdultAge = Annotated[int, Ge(18)]\nUsername = LowerCase[str]\nDisplayName = Annotated[str, Len(1, 32)]\n\n@dataclass\nclass SignupRequest:\n    age: AdultAge\n    username: Username\n    display_name: DisplayName\n```\n\nThis is a good authoring pattern even if validation happens later in another library. The annotations stay readable and reusable.\n\n## Read Metadata At Runtime\n\nIf you are writing your own consumer, inspect `Annotated` with `get_origin()` and `get_args()`. Unpack `GroupedMetadata` so composite markers such as `Interval` and `Len` are handled consistently.\n\n```python\nimport sys\nfrom typing import get_args, get_origin\n\nif sys.version_info >= (3, 9):\n    from typing import Annotated, List\nelse:\n    from typing import List\n    from typing_extensions import Annotated\n\nfrom annotated_types import GroupedMetadata, Len, doc\n\nDisplayName = Annotated[str, Len(1, 32), doc(\"Public name shown in the UI\")]\n\ndef expanded_metadata(annotation: object) -> List[object]:\n    if get_origin(annotation) is not Annotated:\n        return []\n\n    _, *metadata = get_args(annotation)\n    expanded: List[object] = []\n\n    for item in metadata:\n        if isinstance(item, GroupedMetadata):\n            expanded.extend(item)\n        else:\n            expanded.append(item)\n\n    return expanded\n\nfor item in expanded_metadata(DisplayName):\n    print(repr(item))\n```\n\nWith `DisplayName`, the expanded items include `MinLen(1)`, `MaxLen(32)`, and the `DocInfo` returned by `doc(...)`.\n\n## Common Pitfalls\n\n- `annotated-types` does not reject bad input on its own. Validation only happens if another library or your code reads the metadata.\n- Do not assume every consumer handles every marker. Unsupported metadata may be ignored.\n- When consuming annotations, unpack `GroupedMetadata`; otherwise `Interval(...)` and `Len(...)` may appear to be missing constraints.\n- Be careful with `MultipleOf` on floating-point values. The project explicitly calls out differences between Python and JSON Schema interpretations.\n- Prefer introspectable predicates such as `str.isdigit` or `math.isfinite` over lambdas if downstream tooling needs to understand them.\n- On Python 3.8, import `Annotated` from `typing_extensions`, not `typing`.\n\n## Version-Sensitive Notes For 0.7.0\n\n- `annotated-types` 0.7.0 requires Python 3.8 or newer.\n- On Python versions earlier than 3.9, the package depends on `typing-extensions>=4.0.0`.\n- `Len` uses `min_length` and `max_length`, and the upper bound is inclusive. Older posts that describe `max_exclusive` or exclusive upper bounds are stale.\n- `doc(...)` and `DocInfo` are available in 0.7.0; when `typing_extensions.doc` is unavailable, the package provides its own fallback implementation.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/annotated-types/annotated-types\n- PyPI package page: https://pypi.org/project/annotated-types/\n- Releases: https://github.com/annotated-types/annotated-types/releases\n- PEP 593 `Annotated`: https://peps.python.org/pep-0593/\n"
  },
  {
    "path": "content/ansible/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Ansible community package guide for Python-based automation with inventories, playbooks, collections, and vault\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ansible,automation,devops,playbooks,inventory,ssh,vault\"\n---\n\n# Ansible Python Package Guide\n\n## Golden Rule\n\nUse the `ansible` PyPI package when you want the full Ansible community distribution, but remember that it is primarily a CLI/tooling package, not a Python application library. Pin the package version you expect, keep playbooks in a project directory with a local `ansible.cfg`, and prefer fully qualified collection names such as `ansible.builtin.ping` in tasks and ad hoc commands.\n\n## Install\n\nFor project-local automation, use a virtual environment and pin the package:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"ansible==13.4.0\"\n```\n\nCommon alternatives:\n\n```bash\npipx install \"ansible==13.4.0\"\nuv tool install \"ansible==13.4.0\"\n```\n\nCheck what you installed:\n\n```bash\nansible-community --version\nansible --version\n```\n\n`ansible-community --version` reports the community package version. `ansible --version` reports the underlying `ansible-core` version and config search path, which is useful but easy to misread during debugging.\n\n## Initialize A Project\n\nKeep Ansible files together so the local `ansible.cfg` wins over user-global defaults:\n\n```text\nautomation/\n  ansible.cfg\n  inventory.yml\n  site.yml\n  group_vars/\n    web.yml\n  collections/\n    requirements.yml\n```\n\nMinimal `ansible.cfg`:\n\n```ini\n[defaults]\ninventory = ./inventory.yml\nhost_key_checking = True\ninterpreter_python = auto_silent\nstdout_callback = yaml\n\n[ssh_connection]\npipelining = True\n```\n\nMinimal YAML inventory:\n\n```yaml\nall:\n  children:\n    web:\n      hosts:\n        web-1.example.com:\n          ansible_user: deploy\n          ansible_ssh_private_key_file: ~/.ssh/deploy_ed25519\n    local:\n      hosts:\n        localhost:\n          ansible_connection: local\n```\n\nSanity-check the inventory and connection before writing a large playbook:\n\n```bash\nansible-inventory --graph\nansible web -m ansible.builtin.ping\n```\n\n## Core Usage\n\n### Run an ad hoc command\n\nAd hoc commands are useful for verifying connectivity or gathering a quick fact:\n\n```bash\nansible web -m ansible.builtin.command -a \"uname -a\"\nansible web -m ansible.builtin.setup -a \"filter=ansible_distribution*\"\n```\n\nUse modules instead of raw shell commands when a built-in module exists. That keeps runs more predictable and idempotent.\n\n### Run a playbook\n\n```yaml\n# site.yml\n- name: Configure web hosts\n  hosts: web\n  become: true\n  tasks:\n    - name: Ensure nginx is installed\n      ansible.builtin.package:\n        name: nginx\n        state: present\n\n    - name: Ensure nginx is enabled and started\n      ansible.builtin.service:\n        name: nginx\n        state: started\n        enabled: true\n```\n\n```bash\nansible-playbook site.yml\nansible-playbook site.yml --check --diff\n```\n\nUseful validation commands:\n\n```bash\nansible-playbook site.yml --syntax-check\nansible-lint site.yml\n```\n\n### Use roles and collections explicitly\n\nAnsible 13 docs consistently favor FQCNs. Install required collections from a checked-in requirements file:\n\n```yaml\n# collections/requirements.yml\ncollections:\n  - name: community.general\n  - name: ansible.posix\n```\n\n```bash\nansible-galaxy collection install -r collections/requirements.yml\n```\n\nIf your playbook depends on content outside the `ansible` community package, install that collection up front instead of assuming it is already present on the control node.\n\n## Configuration And Authentication\n\n### Config precedence\n\nAnsible looks for configuration in this order:\n\n1. `ANSIBLE_CONFIG`\n2. `ansible.cfg` in the current directory\n3. `~/.ansible.cfg`\n4. `/etc/ansible/ansible.cfg`\n\nFor reproducible automation, prefer a repo-local config and avoid relying on workstation-global settings.\n\n### SSH and privilege escalation\n\nThe common POSIX path is SSH plus `become`:\n\n```yaml\n- name: Update apt cache\n  hosts: web\n  become: true\n  tasks:\n    - name: Refresh package metadata\n      ansible.builtin.apt:\n        update_cache: true\n```\n\nUseful host or group variables:\n\n- `ansible_user`\n- `ansible_host`\n- `ansible_port`\n- `ansible_ssh_private_key_file`\n- `ansible_become`\n- `ansible_become_user`\n- `ansible_python_interpreter`\n\nSet `ansible_python_interpreter` when the remote host does not expose Python at the default path Ansible discovers.\n\n### Secrets with Vault\n\nDo not hard-code secrets in playbooks or plain inventory vars. Encrypt them with Vault:\n\n```bash\nansible-vault encrypt group_vars/web.yml\nansible-vault edit group_vars/web.yml\nansible-playbook site.yml --ask-vault-pass\n```\n\nFor CI, prefer a vault password file or secret manager wiring over interactive prompts.\n\n## Common Pitfalls\n\n- `ansible` is not the same package as `ansible-core`. The community package includes collections and tracks its own version line.\n- `ansible --version` shows the core engine version, not the community package version. Use `ansible-community --version` when checking the `13.4.0` package line.\n- The public docs use `latest` paths and the older source URL `https://docs.ansible.com/ansible/latest/` redirects into `https://docs.ansible.com/projects/ansible/latest/`. That root can drift after future releases.\n- Use FQCNs like `ansible.builtin.copy` and `community.general.ufw`. Short names are more likely to collide across collections.\n- Many modules need Python on the managed host. Minimal Linux images often fail until Python is installed or `ansible_python_interpreter` is set correctly.\n- `command` and `shell` are not idempotent. Prefer purpose-built modules such as `package`, `service`, `template`, `copy`, `user`, or cloud-provider modules.\n- A local `ansible.cfg` in a world-writable directory is ignored for security reasons. If config changes do not seem to apply, inspect `ansible --version` output and the current working directory permissions.\n- Inventory parsing issues often look like auth failures. Run `ansible-inventory --list` or `--graph` before assuming the SSH key is wrong.\n\n## Version-Sensitive Notes For 13.4.0\n\n- PyPI lists `ansible 13.4.0` as the current release, published on `2026-02-24`.\n- The `ansible` package release and maintenance page shows `13.x` as the latest major line and notes that only the latest major release of `ansible` is maintained.\n- The same release page maps `ansible 13` to `ansible-core 2.20`.\n- Current installation docs require Python `3.12` or newer for the control node.\n- Because the docs root is `latest`, always validate the package version against PyPI or the Ansible release and maintenance table before copying examples into pinned automation.\n\n## Official Sources\n\n- Docs root: `https://docs.ansible.com/projects/ansible/latest/`\n- Installation guide: `https://docs.ansible.com/projects/ansible/latest/installation_guide/index.html`\n- Getting started: `https://docs.ansible.com/projects/ansible/latest/getting_started/index.html`\n- Config reference: `https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html`\n- Release and maintenance: `https://docs.ansible.com/projects/ansible/latest/reference_appendices/release_and_maintenance.html`\n- Collection install docs: `https://docs.ansible.com/projects/ansible/latest/collections_guide/collections_installing.html`\n- PyPI release page: `https://pypi.org/project/ansible/13.4.0/`\n"
  },
  {
    "path": "content/antd/docs/antd/javascript/DOC.md",
    "content": "---\nname: antd\ndescription: \"Ant Design React UI library for app layout, forms, data display, feedback, theming, and localization\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"antd,ant-design,react,ui,components,design-system\"\n---\n\n# Ant Design JavaScript Package Guide\n\n## What It Is\n\n`antd` is a React component library for building application UIs with ready-made components such as forms, tables, modals, date pickers, navigation, and layout primitives.\n\nUse it when you need:\n\n- consistent form and validation patterns\n- data-heavy UI such as tables, filters, and pagination\n- built-in feedback components such as messages, notifications, and modals\n- app-wide theming and localization through a single provider\n\n## Install\n\nInstall the main package in your React app:\n\n```bash\nnpm install antd@6.3.2\n```\n\nAdd companion packages only when you use those features directly:\n\n```bash\nnpm install @ant-design/icons\nnpm install dayjs\n```\n\n- `@ant-design/icons` provides the icon components used in buttons, menus, and inputs.\n- `dayjs` is useful when you need to create or serialize values for `DatePicker` and related date components.\n\n## Setup Model\n\nThere is no client initialization, authentication flow, or required environment variable.\n\nThe minimum setup is:\n\n1. install `antd`\n2. import `antd/dist/reset.css` once near your app entry point\n3. render your app inside `ConfigProvider`\n4. wrap the tree with `App` if you want context-aware `message`, `notification`, and `modal` APIs\n\n```javascript\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { App, ConfigProvider, Button, Space } from 'antd';\nimport 'antd/dist/reset.css';\n\nfunction Home() {\n  return (\n    <Space direction=\"vertical\">\n      <Button type=\"primary\">Save</Button>\n      <Button>Cancel</Button>\n    </Space>\n  );\n}\n\nconst root = createRoot(document.getElementById('root'));\n\nroot.render(\n  <ConfigProvider\n    theme={{\n      token: {\n        colorPrimary: '#1677ff',\n        borderRadius: 8,\n      },\n    }}\n  >\n    <App>\n      <Home />\n    </App>\n  </ConfigProvider>\n);\n```\n\nImport components from the root `antd` package rather than deep internal paths.\n\n## Common Workflows\n\n### Build a validated form\n\nUse `Form` with `rules` for field validation and `onFinish` for successful submission.\n\n```javascript\nimport React from 'react';\nimport { App, Button, Form, Input } from 'antd';\n\nexport default function ProfileForm() {\n  const [form] = Form.useForm();\n  const { message } = App.useApp();\n\n  const onFinish = async (values) => {\n    console.log('submit payload', values);\n    message.success('Profile saved');\n    form.resetFields();\n  };\n\n  return (\n    <Form\n      form={form}\n      layout=\"vertical\"\n      onFinish={onFinish}\n      initialValues={{ name: 'Ada Lovelace' }}\n    >\n      <Form.Item\n        label=\"Name\"\n        name=\"name\"\n        rules={[{ required: true, message: 'Enter a name' }]}\n      >\n        <Input />\n      </Form.Item>\n\n      <Form.Item\n        label=\"Email\"\n        name=\"email\"\n        rules={[\n          { required: true, message: 'Enter an email address' },\n          { type: 'email', message: 'Enter a valid email address' },\n        ]}\n      >\n        <Input />\n      </Form.Item>\n\n      <Button type=\"primary\" htmlType=\"submit\">\n        Save\n      </Button>\n    </Form>\n  );\n}\n```\n\n`rules` run inside the form system, so keep API-side validation separate and show server errors explicitly when the request fails.\n\n### Show feedback with `App.useApp()`\n\nWrap the app in `<App>` once, then use `App.useApp()` inside components that need `message`, `notification`, or `modal`.\n\n```javascript\nimport React from 'react';\nimport { App, Button } from 'antd';\n\nexport default function DeleteButton() {\n  const { message, modal, notification } = App.useApp();\n\n  const confirmDelete = () => {\n    modal.confirm({\n      title: 'Delete record?',\n      content: 'This action cannot be undone.',\n      okText: 'Delete',\n      okButtonProps: { danger: true },\n      onOk: async () => {\n        message.loading({ content: 'Deleting...', key: 'delete' });\n        await Promise.resolve();\n        message.success({ content: 'Deleted', key: 'delete' });\n        notification.success({\n          message: 'Record removed',\n          description: 'The table can now be refreshed.',\n        });\n      },\n    });\n  };\n\n  return (\n    <Button danger onClick={confirmDelete}>\n      Delete\n    </Button>\n  );\n}\n```\n\nUse the hook-based API when your feedback components should inherit the current theme, locale, and provider context.\n\n### Render tables with stable row keys\n\nPass `columns`, `dataSource`, and a stable `rowKey`. Use `render` only when a plain `dataIndex` is not enough.\n\n```javascript\nimport React from 'react';\nimport { Space, Table, Tag } from 'antd';\n\nconst columns = [\n  {\n    title: 'Name',\n    dataIndex: 'name',\n    key: 'name',\n  },\n  {\n    title: 'Status',\n    dataIndex: 'status',\n    key: 'status',\n    render: (status) => (\n      <Tag color={status === 'active' ? 'green' : 'default'}>{status}</Tag>\n    ),\n  },\n  {\n    title: 'Owner',\n    key: 'owner',\n    render: (_, record) => (\n      <Space direction=\"vertical\" size={0}>\n        <span>{record.owner.name}</span>\n        <span>{record.owner.email}</span>\n      </Space>\n    ),\n  },\n];\n\nconst dataSource = [\n  {\n    id: 'proj_1',\n    name: 'Website refresh',\n    status: 'active',\n    owner: { name: 'Ada', email: 'ada@example.com' },\n  },\n  {\n    id: 'proj_2',\n    name: 'Billing migration',\n    status: 'paused',\n    owner: { name: 'Grace', email: 'grace@example.com' },\n  },\n];\n\nexport default function ProjectTable() {\n  return (\n    <Table\n      rowKey=\"id\"\n      columns={columns}\n      dataSource={dataSource}\n      pagination={{ pageSize: 10 }}\n    />\n  );\n}\n```\n\nDo not rely on array indexes as implicit keys when the dataset can be sorted, filtered, or refreshed from the server.\n\n### Work with date values using Day.js\n\nDate-related components work with Day.js values. Convert them before sending data to an API.\n\n```javascript\nimport React from 'react';\nimport dayjs from 'dayjs';\nimport { Button, DatePicker, Form } from 'antd';\n\nexport default function LaunchForm() {\n  const onFinish = (values) => {\n    const payload = {\n      ...values,\n      launchDate: values.launchDate\n        ? values.launchDate.format('YYYY-MM-DD')\n        : null,\n    };\n\n    console.log(payload);\n  };\n\n  return (\n    <Form\n      layout=\"vertical\"\n      onFinish={onFinish}\n      initialValues={{ launchDate: dayjs('2026-03-13', 'YYYY-MM-DD') }}\n    >\n      <Form.Item label=\"Launch date\" name=\"launchDate\">\n        <DatePicker />\n      </Form.Item>\n\n      <Button type=\"primary\" htmlType=\"submit\">\n        Schedule\n      </Button>\n    </Form>\n  );\n}\n```\n\nIf your API expects ISO strings or timestamps, serialize the Day.js object in `onFinish` instead of posting it directly.\n\n### Customize the app theme\n\nUse `ConfigProvider` to define global design tokens once.\n\n```javascript\nimport React from 'react';\nimport { ConfigProvider, Button, Space } from 'antd';\n\nexport default function ThemedApp() {\n  return (\n    <ConfigProvider\n      theme={{\n        token: {\n          colorPrimary: '#0057b8',\n          borderRadius: 6,\n          fontSize: 14,\n        },\n        components: {\n          Button: {\n            controlHeight: 38,\n          },\n        },\n      }}\n    >\n      <Space>\n        <Button type=\"primary\">Primary</Button>\n        <Button>Default</Button>\n      </Space>\n    </ConfigProvider>\n  );\n}\n```\n\nKeep shared design tokens in one provider near the root instead of repeating style overrides per component.\n\n## Localization\n\nSet the Ant Design locale through `ConfigProvider`. When you localize date components, also set the matching Day.js locale in your app.\n\n```javascript\nimport React from 'react';\nimport dayjs from 'dayjs';\nimport 'dayjs/locale/zh-cn';\nimport locale from 'antd/locale/zh_CN';\nimport { ConfigProvider, DatePicker } from 'antd';\n\ndayjs.locale('zh-cn');\n\nexport default function LocalizedDatePicker() {\n  return (\n    <ConfigProvider locale={locale}>\n      <DatePicker />\n    </ConfigProvider>\n  );\n}\n```\n\nSetting only the Ant Design locale is not enough for all date formatting cases; keep the Day.js locale aligned with the UI locale.\n\n## Next.js and SSR\n\nAnt Design uses CSS-in-JS for component styles. In SSR frameworks, use the maintainer SSR integration pattern instead of relying only on client-side style injection.\n\nFor Next.js App Router, the maintainer docs provide `@ant-design/nextjs-registry`:\n\n```bash\nnpm install @ant-design/nextjs-registry\n```\n\n```javascript\nimport { AntdRegistry } from '@ant-design/nextjs-registry';\nimport 'antd/dist/reset.css';\n\nexport default function RootLayout({ children }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        <AntdRegistry>{children}</AntdRegistry>\n      </body>\n    </html>\n  );\n}\n```\n\nUse the official SSR guide for other renderers so styles are extracted on the server and hydration does not produce missing or duplicated styles.\n\n## Important Pitfalls\n\n- Import `antd/dist/reset.css` once. Re-importing it in multiple feature files makes styling harder to reason about.\n- `DatePicker`, `RangePicker`, and related controls work with Day.js values, not plain `Date` objects or raw strings.\n- Icons are not bundled into `antd`; import them from `@ant-design/icons`.\n- Wrap the tree with `<App>` before calling `App.useApp()`.\n- Give `Table` a stable `rowKey` whenever records come from an API.\n- For SSR and Next.js, follow the official CSS-in-JS integration docs instead of treating Ant Design like a CSS-only component library.\n"
  },
  {
    "path": "content/anthropic/docs/claude-api/javascript/DOC.md",
    "content": "---\nname: claude-api\ndescription: \"Claude AI assistant API for text generation, analysis, conversation, streaming, tool use, vision, and batch processing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.78.0\"\n  updated-on: \"2026-03-05\"\n  source: maintainer\n  tags: \"anthropic,sdk,llm,ai,claude\"\n---\n\n# Anthropic JavaScript/TypeScript SDK Coding Guidelines\n\nYou are an Anthropic API coding expert. Help me with writing code using the Anthropic API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.anthropic.com/claude/reference/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Anthropic TypeScript SDK to call the Claude models, which is the standard library for all Anthropic API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Anthropic TypeScript SDK\n- **NPM Package:** `@anthropic-ai/sdk`\n- **Legacy Libraries**: Other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install @anthropic-ai/sdk`\n\n**APIs and Usage:**\n\n- **Correct:** `import Anthropic from '@anthropic-ai/sdk'`\n- **Correct:** `const client = new Anthropic({})`\n- **Correct:** `await client.messages.create(...)`\n- **Correct:** `await client.messages.stream(...)`\n- **Incorrect:** `AnthropicClient` or `AnthropicAPI`\n- **Incorrect:** `client.generate` or `client.completions`\n- **Incorrect:** Legacy completion endpoints\n\n## Initialization and API key\n\nThe `@anthropic-ai/sdk` library requires creating an `Anthropic` instance for all API calls.\n\n- Always use `const client = new Anthropic({})` to create an instance.\n- Set the `ANTHROPIC_API_KEY` environment variable, which will be picked up automatically.\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\n// Uses the ANTHROPIC_API_KEY environment variable if apiKey not specified\nconst client = new Anthropic({});\n\n// Or pass the API key directly\n// const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });\n```\n\n## Models\n\n- By default, use the following models as of March 2026:\n  - **General Tasks:** `claude-sonnet-4-6-20250827`\n  - **High-performance:** `claude-opus-4-6-20250826`\n  - **Fast and Efficient:** `claude-haiku-4-5-20251001`\n\n- Previous generation models (still supported):\n  - `claude-sonnet-4-20250514`, `claude-opus-4-20250514`\n  - `claude-3-5-haiku-20241022`\n\n- Do not use deprecated models: `claude-3-7-sonnet`, `claude-3-5-sonnet`, `claude-3-opus`\n\n## Basic Inference (Text Generation)\n\nHere's how to generate a response from a text prompt.\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic({}); // Assumes ANTHROPIC_API_KEY is set\n\nasync function run() {\n  const message = await client.messages.create({\n    max_tokens: 1024,\n    messages: [{ role: 'user', content: 'Hello, Claude' }],\n    model: 'claude-sonnet-4-20250514',\n  });\n\n  console.log(message.content);\n}\n\nrun();\n```\n\nMultimodal inputs are supported by passing image data in the messages array. You can include images, documents, and other file types using base64 encoding or file uploads.\n\nFor file uploads, use the `client.beta.files.upload` method:\n\n```javascript\nimport fs from 'fs';\nimport Anthropic, { toFile } from '@anthropic-ai/sdk';\n\nconst client = new Anthropic();\n\n// File upload example\nawait client.beta.files.upload({\n  file: await toFile(fs.createReadStream('/path/to/file'), undefined, { type: 'application/json' }),\n  betas: ['files-api-2025-04-14'],\n});\n```\n\n## Streaming Responses\n\nWe provide comprehensive support for streaming responses using Server Sent Events (SSE).\n\n### Basic Streaming\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic();\n\nconst stream = await client.messages.create({\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Hello, Claude' }],\n  model: 'claude-sonnet-4-20250514',\n  stream: true,\n});\n\nfor await (const messageStreamEvent of stream) {\n  console.log(messageStreamEvent.type);\n}\n```\n\n### Advanced Streaming with Helpers\n\nThe SDK provides powerful streaming helpers for convenience:\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic();\n\nasync function main() {\n  const stream = client.messages\n    .stream({\n      model: 'claude-sonnet-4-20250514',\n      max_tokens: 1024,\n      messages: [\n        {\n          role: 'user',\n          content: 'Say hello there!',\n        },\n      ],\n    })\n    .on('text', (text) => {\n      console.log(text);\n    });\n\n  const message = await stream.finalMessage();\n  console.log(message);\n}\n\nmain();\n```\n\nYou can cancel streams by calling `stream.controller.abort()` or breaking from loops.\n\n## Tool Use (Function Calling)\n\nThe SDK supports tool use (function calling) for extending Claude's capabilities.\n\n### Custom Tools\n\nDefine custom functions that Claude can call:\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic();\n\nasync function run() {\n  const response = await client.messages.create({\n    model: 'claude-sonnet-4-20250514',\n    max_tokens: 1024,\n    messages: [{ role: 'user', content: \"What's the weather like in San Francisco?\" }],\n    tools: [\n      {\n        name: 'get_weather',\n        description: 'Get the current weather in a given location',\n        input_schema: {\n          type: 'object',\n          properties: {\n            location: { description: 'The city and state, e.g. San Francisco, CA', type: 'string' },\n            unit: { description: 'Unit for the output - one of (celsius, fahrenheit)', type: 'string' },\n          },\n          required: ['location'],\n        },\n        type: 'custom',\n      },\n    ],\n    tool_choice: { type: 'auto' },\n  });\n\n  // Handle tool use in the response\n  if (response.content.some((block) => block.type === 'tool_use')) {\n    // Process tool calls and provide results back to Claude\n    console.log('Claude wants to use a tool!');\n  }\n}\n\nrun();\n```\n\n### Built-in Beta Tools\n\nThe beta API provides specialized built-in tools.\n\n#### Bash Tool\n\n```javascript\nconst response = await client.beta.messages.create({\n  model: 'claude-sonnet-4-20250514',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'List the files in the current directory' }],\n  tools: [{ type: 'bash_20250124', name: 'bash' }],\n});\n```\n\n#### Computer Use Tool\n\n```javascript\nconst response = await client.beta.messages.create({\n  model: 'claude-sonnet-4-20250514',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Take a screenshot' }],\n  tools: [\n    {\n      type: 'computer_20250124',\n      name: 'computer',\n      display_width_px: 1920,\n      display_height_px: 1080,\n    },\n  ],\n});\n```\n\n#### Text Editor Tool\n\n```javascript\nconst response = await client.beta.messages.create({\n  model: 'claude-sonnet-4-20250514',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Create a Python script' }],\n  tools: [{ type: 'text_editor_20250124', name: 'str_replace_editor' }],\n});\n```\n\n### Tool Choice Configuration\n\nControl how Claude uses tools:\n\n- `{ type: 'auto' }` - Claude decides when to use tools\n- `{ type: 'any' }` - Claude must use a tool\n- `{ type: 'tool', name: 'specific_tool' }` - Force a specific tool\n- `{ disable_parallel_tool_use: true }` - Disable parallel tool execution\n\n## Message Batches\n\nThe SDK supports the Message Batches API for processing multiple requests efficiently.\n\n### Creating a Batch\n\n```javascript\nawait client.messages.batches.create({\n  requests: [\n    {\n      custom_id: 'my-first-request',\n      params: {\n        model: 'claude-sonnet-4-20250514',\n        max_tokens: 1024,\n        messages: [{ role: 'user', content: 'Hello, world' }],\n      },\n    },\n    {\n      custom_id: 'my-second-request',\n      params: {\n        model: 'claude-sonnet-4-20250514',\n        max_tokens: 1024,\n        messages: [{ role: 'user', content: 'Hi again, friend' }],\n      },\n    },\n  ],\n});\n```\n\n### Getting Batch Results\n\n```javascript\nconst results = await client.messages.batches.results(batch_id);\nfor await (const entry of results) {\n  if (entry.result.type === 'succeeded') {\n    console.log(entry.result.message.content);\n  }\n}\n```\n\n## Additional Capabilities\n\n### System Instructions\n\nGuide Claude's behavior with system instructions:\n\n```javascript\nconst response = await client.messages.create({\n  model: 'claude-sonnet-4-20250514',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Hello' }],\n  system: [{ text: 'You are a helpful assistant that responds in a pirate voice.', type: 'text' }],\n});\n```\n\n### Thinking\n\nConfigure Claude's extended thinking (reasoning process):\n\n```javascript\nconst response = await client.messages.create({\n  model: 'claude-sonnet-4-6-20250827',\n  max_tokens: 16000,\n  messages: [{ role: 'user', content: 'Solve this complex problem...' }],\n  thinking: { type: 'enabled', budget_tokens: 10000 },\n});\n```\n\n### Temperature and Generation Parameters\n\nControl randomness and output:\n\n```javascript\nconst response = await client.messages.create({\n  model: 'claude-sonnet-4-20250514',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Write a creative story' }],\n  temperature: 0.7,\n  top_k: 5,\n  top_p: 0.9,\n});\n```\n\n### Token Counting\n\nCount tokens before making requests:\n\n```javascript\nconst tokenCount = await client.messages.countTokens({\n  messages: [{ role: 'user', content: 'Hello, Claude' }],\n  model: 'claude-sonnet-4-20250514',\n});\nconsole.log(tokenCount); // { input_tokens: 25, output_tokens: 13 }\n```\n\n### Auto-pagination\n\nHandle paginated responses automatically:\n\n```javascript\nasync function fetchAllMessageBatches(params) {\n  const allMessageBatches = [];\n  // Automatically fetches more pages as needed.\n  for await (const messageBatch of client.messages.batches.list({ limit: 20 })) {\n    allMessageBatches.push(messageBatch);\n  }\n  return allMessageBatches;\n}\n```\n\n## Error Handling\n\nThe SDK provides comprehensive error handling with specific error types:\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic();\n\ntry {\n  const message = await client.messages.create({\n    max_tokens: 1024,\n    messages: [{ role: 'user', content: 'Hello, Claude' }],\n    model: 'claude-sonnet-4-20250514',\n  });\n} catch (err) {\n  if (err instanceof Anthropic.APIError) {\n    console.log(err.status); // 400\n    console.log(err.name); // BadRequestError\n    console.log(err.headers); // {server: 'nginx', ...}\n    console.log(err.requestID); // request id string\n  } else {\n    throw err;\n  }\n}\n```\n\n### Error Types\n\n| Status Code | Error Type                 |\n| ----------- | -------------------------- |\n| 400         | `BadRequestError`          |\n| 401         | `AuthenticationError`      |\n| 403         | `PermissionDeniedError`    |\n| 404         | `NotFoundError`            |\n| 422         | `UnprocessableEntityError` |\n| 429         | `RateLimitError`           |\n| >=500       | `InternalServerError`      |\n| N/A         | `APIConnectionError`       |\n\nAll errors extend from `AnthropicError` which extends the standard `Error` class.\n\n### Request IDs\n\nAll responses include a `_request_id` property for debugging:\n\n```javascript\nconst message = await client.messages.create({\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Hello, Claude' }],\n  model: 'claude-sonnet-4-20250514',\n});\nconsole.log(message._request_id);\n```\n\n## Advanced Configuration\n\n### Retries\n\nConfigure automatic retry behavior:\n\n```javascript\n// Configure default retries for all requests\nconst client = new Anthropic({\n  maxRetries: 3, // default is 2\n});\n\n// Or configure per-request\nawait client.messages.create(\n  { max_tokens: 1024, messages: [{ role: 'user', content: 'Hello, Claude' }], model: 'claude-sonnet-4-20250514' },\n  { maxRetries: 5 },\n);\n```\n\n### Timeouts\n\nSet custom timeout values:\n\n```javascript\n// Configure default timeout for all requests\nconst client = new Anthropic({\n  timeout: 20 * 1000, // 20 seconds (default is 10 minutes)\n});\n\n// Override per-request\nawait client.messages.create(\n  { max_tokens: 1024, messages: [{ role: 'user', content: 'Hello, Claude' }], model: 'claude-sonnet-4-20250514' },\n  { timeout: 5 * 1000 },\n);\n```\n\n### Logging\n\nEnable debug logging:\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic({\n  logLevel: 'debug', // Show all log messages\n});\n\n// Or use environment variable\n// ANTHROPIC_LOG=debug\n```\n\n### Custom Fetch Options\n\nCustomize the underlying fetch behavior:\n\n```javascript\nimport Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic({\n  fetchOptions: {\n    // Custom RequestInit options\n  },\n});\n```\n\n## Useful Links\n\n- Documentation: https://docs.anthropic.com/\n- API Reference: https://docs.anthropic.com/claude/reference/\n- Models: https://docs.anthropic.com/claude/docs/models-overview\n- API Pricing: https://www.anthropic.com/pricing\n- Rate Limits: https://docs.anthropic.com/claude/reference/rate-limits\n\n"
  },
  {
    "path": "content/anthropic/docs/claude-api/python/DOC.md",
    "content": "---\nname: claude-api\ndescription: \"Claude AI assistant API for text generation, analysis, conversation, streaming, tool use, vision, and batch processing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.84.0\"\n  updated-on: \"2026-03-05\"\n  source: maintainer\n  tags: \"anthropic,sdk,llm,ai,claude\"\n---\n\n\n# Anthropic Python SDK Guidelines\n\nYou are an Anthropic API coding expert. Help me with writing code using the Anthropic API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.anthropic.com/claude/reference/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Anthropic Python SDK to call Claude models, which is the standard library for all Anthropic API interactions.\n\n- **Library Name:** Anthropic Python SDK\n- **Python Package:** `anthropic`\n- **Installation:** `pip install anthropic`\n\n**APIs and Usage:**\n\n- **Correct:** `from anthropic import Anthropic`\n- **Correct:** `from anthropic import AsyncAnthropic` (for async usage)\n- **Correct:** `client = Anthropic(api_key=\"...\")`\n- **Correct:** `client.messages.create(...)`\n\n## Initialization and API Key\n\nThe `anthropic` library requires creating a client object for all API calls.\n\n- Always use `client = Anthropic()` to create a client object.\n- Set `ANTHROPIC_API_KEY` environment variable, which will be picked up automatically.\n- Alternatively, pass the API key directly: `client = Anthropic(api_key=\"your-key-here\")`\n\n## Models\n\nBy default, use the following models as of March 2026:\n\n- **General Tasks:** `claude-sonnet-4-6-20250827`\n- **High-performance:** `claude-opus-4-6-20250826`\n- **Fast and Efficient:** `claude-haiku-4-5-20251001`\n\nPrevious generation models (still supported):\n- `claude-sonnet-4-20250514`, `claude-opus-4-20250514`\n- `claude-3-5-haiku-20241022`\n\nDo not use deprecated models: `claude-3-7-sonnet`, `claude-3-5-sonnet`, `claude-3-opus`\n\n```python\n# List all available models\nmodels = client.models.list()\n```\n```python\n# List all deprecated models\nfrom anthropic.resources.messages.messages import DEPRECATED_MODELS\nfor model, deprecation_date in DEPRECATED_MODELS.items():\n    print(f\"{model}: deprecated {deprecation_date}\")\n```\n\n- It is acceptable to use specific dated versions if consistency is required.\n- Avoid using deprecated models - check the SDK documentation for deprecation notices.\n\n## Basic Inference (Text Generation)\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\nmessage = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Hello, Claude\"\n        }\n    ]\n)\nprint(message.content)\n```\n\n## Multimodal Inputs\n\n### Image Inputs\n\n```python\nmessage = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\n                    \"type\": \"image\",\n                    \"source\": {\n                        \"type\": \"base64\",\n                        \"media_type\": \"image/jpeg\",\n                        \"data\": \"/9j/4AAQSkZJRgABAQ...\"\n                    }\n                },\n                {\n                    \"type\": \"text\",\n                    \"text\": \"What's in this image?\"\n                }\n            ]\n        }\n    ]\n)\n```\n\n### File Uploads\n\n```python\nfrom pathlib import Path\n\nclient.beta.files.upload(\n    file=Path(\"/path/to/file\"),\n)\n```\n\n## Async Usage\n\n```python\nimport asyncio\nfrom anthropic import AsyncAnthropic\n\nclient = AsyncAnthropic()\n\nasync def main():\n    message = await client.messages.create(\n        model=\"claude-sonnet-4-20250514\",\n        max_tokens=1024,\n        messages=[\n            {\n                \"role\": \"user\",\n                \"content\": \"Hello, Claude\"\n            }\n        ]\n    )\n    print(message.content)\n\nasyncio.run(main())\n```\n\n## Advanced Capabilities and Configurations\n\n### System Instructions\n\n```python\nmessage = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    system=\"You are a helpful assistant that speaks like a pirate.\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Hello!\"\n        }\n    ]\n)\n```\n\n### Thinking\n\nConfigure Claude's extended thinking (reasoning process):\n\n```python\nmessage = client.messages.create(\n    model=\"claude-sonnet-4-6-20250827\",\n    max_tokens=16000,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Solve this complex problem step by step.\"\n        }\n    ],\n    thinking={\n        \"type\": \"enabled\",\n        \"budget_tokens\": 10000\n    }\n)\n```\n\n### Tool Use (Function Calling)\n\n```python\ndef get_weather(location: str) -> str:\n    return f\"Weather in {location}: 72°F and sunny\"\n\nmessage = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"What's the weather in San Francisco?\"\n        }\n    ],\n    tools=[\n        {\n            \"type\": \"custom\",\n            \"name\": \"get_weather\",\n            \"description\": \"Get current weather for a location\",\n            \"input_schema\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"location\": {\n                        \"type\": \"string\",\n                        \"description\": \"The city and state, e.g. San Francisco, CA\"\n                    }\n                },\n                \"required\": [\"location\"]\n            }\n        }\n    ]\n)\n```\n\n### Streaming Responses\n\n```python\nstream = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Tell me a story\"\n        }\n    ],\n    stream=True\n)\n\nfor event in stream:\n    if event.type == \"content_block_delta\":\n        print(event.delta.text, end=\"\", flush=True)\n```\n\n### Streaming Helpers\n\n```python\nasync with client.messages.stream(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Say hello there!\"\n        }\n    ]\n) as stream:\n    async for text in stream.text_stream:\n        print(text, end=\"\", flush=True)\n    print()\n\nmessage = await stream.get_final_message()\n```\n\n### Token Counting\n\n```python\ncount = client.messages.count_tokens(\n    model=\"claude-sonnet-4-20250514\",\n    messages=[\n        {\"role\": \"user\", \"content\": \"Hello, world\"}\n    ]\n)\nprint(f\"Input tokens: {count.input_tokens}\")\n```\n\n### Message Batches\n\n```python\nbatch = await client.messages.batches.create(\n    requests=[\n        {\n            \"custom_id\": \"request-1\",\n            \"params\": {\n                \"model\": \"claude-sonnet-4-20250514\",\n                \"max_tokens\": 1024,\n                \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]\n            }\n        }\n    ]\n)\n```\n\n## Specialized Deployments\n\n### AWS Bedrock\n\n```python\nfrom anthropic import AnthropicBedrock\n\nclient = AnthropicBedrock(\n    aws_region=\"us-east-1\",\n    aws_profile=\"default\"\n)\n\nmessage = client.messages.create(\n    model=\"anthropic.claude-sonnet-4-20250514-v1:0\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Hello!\"\n        }\n    ]\n)\n```\n\n### Google Vertex AI\n\n```python\nfrom anthropic import AnthropicVertex\n\nclient = AnthropicVertex()\n\nmessage = client.messages.create(\n    model=\"claude-sonnet-4@20250514\",\n    max_tokens=1024,\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Hello!\"\n        }\n    ]\n)\n```\n\n## Error Handling\n\n```python\nimport anthropic\n\ntry:\n    message = client.messages.create(\n        model=\"claude-sonnet-4-20250514\",\n        max_tokens=1024,\n        messages=[\n            {\n                \"role\": \"user\",\n                \"content\": \"Hello, Claude\"\n            }\n        ]\n    )\nexcept anthropic.APIConnectionError as e:\n    print(\"Connection error occurred\")\nexcept anthropic.RateLimitError as e:\n    print(\"Rate limit exceeded\")\nexcept anthropic.APIStatusError as e:\n    print(f\"API error: {e.status_code}\")\n```\n\n## Configuration Options\n\n### Retries\n\n```python\nclient = Anthropic(max_retries=3)\n\nclient.with_options(max_retries=5).messages.create(...)\n```\n\n### Timeouts\n\n```python\nclient = Anthropic(timeout=30.0)\n\nclient.with_options(timeout=60.0).messages.create(...)\n```\n\n## Useful Links\n\n- **Documentation:** https://docs.anthropic.com/claude/reference/\n- **API Keys:** https://console.anthropic.com/\n- **SDK Repository:** https://github.com/anthropics/anthropic-sdk-python\n- **Rate Limits:** https://docs.anthropic.com/claude/reference/rate-limits\n- **Error Codes:** https://docs.anthropic.com/claude/reference/errors\n"
  },
  {
    "path": "content/anthropic/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Anthropic Python package guide for the Claude SDK: install, auth, messages, streaming, async, tools, and runtime configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.84.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"anthropic,claude,llm,api,sdk,python\"\n---\n\n# anthropic Python Package Guide\n\n## What This Covers\n\nThis entry is for the PyPI package [`anthropic`](https://pypi.org/project/anthropic/) version `0.84.0`, which Anthropic documents as the Claude SDK for Python.\n\nUse it when you need to:\n\n- call the Messages API from Python\n- stream tokens or structured events\n- use the async client\n- configure retries, timeouts, or custom HTTP transports\n- switch to Anthropic-hosted, Bedrock, or Vertex clients without changing the overall SDK shape\n\n## Install\n\n```bash\npip install anthropic==0.84.0\n```\n\nOptional extras documented by Anthropic:\n\n```bash\npip install \"anthropic[aiohttp]\"\npip install \"anthropic[bedrock]\"\npip install \"anthropic[vertex]\"\npip install \"anthropic[mcp]\"\n```\n\nNotes:\n\n- `anthropic[aiohttp]` lets the async client use `aiohttp` instead of the default `httpx`.\n- `anthropic[bedrock]` and `anthropic[vertex]` install cloud-specific integrations.\n- `anthropic[mcp]` installs Model Context Protocol helpers. Anthropic documents that this extra requires Python `3.10+`.\n\n## Authentication And Client Setup\n\nFor Anthropic-hosted API usage, set `ANTHROPIC_API_KEY` and let the client pick it up automatically:\n\n```bash\nexport ANTHROPIC_API_KEY=\"your-api-key\"\n```\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n```\n\nYou can also pass the key directly:\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic(api_key=\"your-api-key\")\n```\n\nCloud-specific clients use different classes:\n\n```python\nfrom anthropic import AnthropicBedrock, AnthropicVertex\n\nbedrock = AnthropicBedrock(aws_region=\"us-east-1\")\nvertex = AnthropicVertex(project_id=\"my-gcp-project\", region=\"us-east5\")\n```\n\n## Core Usage\n\n### Basic message request\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\nmessage = client.messages.create(\n    model=\"claude-opus-4-6\",\n    max_tokens=1024,\n    messages=[\n        {\"role\": \"user\", \"content\": \"Write a haiku about clean APIs.\"}\n    ],\n)\n\ntext = \"\".join(\n    block.text for block in message.content if block.type == \"text\"\n)\nprint(text)\n```\n\nPractical notes:\n\n- `max_tokens` is required in normal `messages.create` calls.\n- Response `content` is block-based. Do not assume the SDK returns a single plain string.\n- Model IDs change independently of SDK releases. If a copied example uses an outdated model, check Anthropic's current model docs or `client.models.list()`.\n\n### Count tokens before sending\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\ncount = client.messages.count_tokens(\n    model=\"claude-opus-4-1\",\n    messages=[\n        {\"role\": \"user\", \"content\": \"Hello, Claude\"}\n    ],\n)\n\nprint(count.input_tokens)\n```\n\n### Async client\n\n```python\nimport asyncio\nfrom anthropic import AsyncAnthropic\n\nclient = AsyncAnthropic()\n\nasync def main() -> None:\n    message = await client.messages.create(\n        model=\"claude-opus-4-6\",\n        max_tokens=512,\n        messages=[\n            {\"role\": \"user\", \"content\": \"Summarize this repository layout.\"}\n        ],\n    )\n    text = \"\".join(\n        block.text for block in message.content if block.type == \"text\"\n    )\n    print(text)\n\nasyncio.run(main())\n```\n\nIf you want the async client to use `aiohttp`:\n\n```python\nfrom anthropic import AsyncAnthropic, DefaultAioHttpClient\n\nclient = AsyncAnthropic(http_client=DefaultAioHttpClient())\n```\n\n### Streaming\n\nAnthropic documents two patterns. Prefer the streaming helper when you want incremental text and the final assembled message.\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\nwith client.messages.stream(\n    model=\"claude-opus-4-6\",\n    max_tokens=1024,\n    messages=[\n        {\"role\": \"user\", \"content\": \"Stream a short explanation of retries.\"}\n    ],\n) as stream:\n    for text in stream.text_stream:\n        print(text, end=\"\", flush=True)\n\n    final_message = stream.get_final_message()\n```\n\nUse `.with_streaming_response` when you want direct access to the raw streaming response object and headers:\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\nwith client.messages.with_streaming_response.create(\n    model=\"claude-opus-4-6\",\n    max_tokens=1024,\n    messages=[\n        {\"role\": \"user\", \"content\": \"List three HTTP status codes.\"}\n    ],\n) as response:\n    print(response.headers.get(\"request-id\"))\n    for line in response.iter_lines():\n        print(line)\n```\n\n### Tool use\n\nThe direct Messages API accepts tool definitions inline:\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic()\n\nmessage = client.messages.create(\n    model=\"claude-opus-4-6\",\n    max_tokens=1024,\n    messages=[\n        {\"role\": \"user\", \"content\": \"What is the weather in SF?\"}\n    ],\n    tools=[\n        {\n            \"name\": \"get_weather\",\n            \"description\": \"Get the weather for a city\",\n            \"input_schema\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"city\": {\"type\": \"string\"}\n                },\n                \"required\": [\"city\"],\n            },\n        }\n    ],\n)\n\nfor block in message.content:\n    print(block)\n```\n\nFor local Python functions, Anthropic also ships beta helpers such as `@beta_tool`, `client.beta.messages.tool_runner(...)`, and MCP adapters in `anthropic[mcp]`.\n\n## Configuration\n\n### Retries\n\nAnthropic documents automatic retries by default for:\n\n- connection errors\n- HTTP `408`\n- HTTP `409`\n- HTTP `429`\n- HTTP `>=500`\n\nDefault retry count is `2`.\n\n```python\nfrom anthropic import Anthropic\n\nclient = Anthropic(max_retries=5)\n\n# Per-request override\nmessage = client.with_options(max_retries=0).messages.create(\n    model=\"claude-opus-4-6\",\n    max_tokens=256,\n    messages=[{\"role\": \"user\", \"content\": \"No automatic retries for this call.\"}],\n)\n```\n\n### Timeouts\n\nAnthropic documents a default timeout of `10 minutes`.\n\n```python\nimport httpx\nfrom anthropic import Anthropic\n\nclient = Anthropic(timeout=20.0)\n\ncustom_client = Anthropic(\n    timeout=httpx.Timeout(60.0, connect=5.0),\n)\n```\n\n### Custom HTTP client\n\nUse a custom transport when you need proxies, custom connection limits, or local test endpoints:\n\n```python\nimport httpx\nfrom anthropic import Anthropic, DefaultHttpxClient\n\nclient = Anthropic(\n    http_client=DefaultHttpxClient(\n        proxy=\"http://proxy.internal:8080\",\n        transport=httpx.HTTPTransport(local_address=\"0.0.0.0\"),\n    )\n)\n```\n\nAnthropic also documents per-request overrides through `client.with_options(...)`.\n\n## Common Pitfalls\n\n- The package name and import root are both `anthropic`, but Anthropic's current docs brand the library as the Claude SDK for Python.\n- Use `client.messages.create(...)` for new code. Anthropic's modern SDK documentation is centered on the Messages API, not legacy text-completions patterns.\n- Do not treat `message.content` as a single string. It is a list of content blocks.\n- Streaming has two different APIs: `client.messages.stream(...)` for helper-driven iteration and `client.messages.with_streaming_response.create(...)` for lower-level raw access.\n- Beta helpers live under `client.beta...` and may require explicit `betas=[...]` flags. Do not copy beta examples into stable code paths without checking the named beta header requirement.\n- Bedrock and Vertex use dedicated client classes and platform credentials. `ANTHROPIC_API_KEY` is for Anthropic-hosted API usage, not for those cloud provider flows.\n\n## Version-Sensitive Notes For 0.84.0\n\n- PyPI lists `0.84.0` as the current release published on `2026-02-25`.\n- PyPI lists Python support as `>=3.8`.\n- The optional MCP helper package path (`anthropic[mcp]`) is documented separately and requires Python `3.10+`.\n- Anthropic's current SDK docs live under `platform.claude.com`. The older docs URL `https://docs.anthropic.com/en/api/client-sdks` redirects there.\n\n## Official Sources Used\n\n- Anthropic SDK docs: `https://platform.claude.com/docs/en/api/sdks/python`\n- Anthropic client SDK landing page: `https://platform.claude.com/docs/en/api/client-sdks`\n- Anthropic Python SDK repository: `https://github.com/anthropics/anthropic-sdk-python`\n- Anthropic SDK helper docs: `https://github.com/anthropics/anthropic-sdk-python/blob/main/helpers.md`\n- PyPI package page: `https://pypi.org/project/anthropic/`\n"
  },
  {
    "path": "content/anyio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"AnyIO package guide for Python structured concurrency across asyncio and Trio\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.12.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"anyio,python,asyncio,trio,async,concurrency,structured-concurrency,pytest,threads\"\n---\n\n# anyio Python Package Guide\n\n## What It Is\n\n`anyio` is a backend-neutral async concurrency library for Python. It exposes Trio-style structured concurrency primitives that run on top of either `asyncio` or Trio, plus shared APIs for cancellation, streams, synchronization, subprocesses, files, worker threads, and pytest integration.\n\nUse it when you want code that:\n\n- targets both `asyncio` and Trio\n- prefers structured concurrency over detached background tasks\n- needs a consistent API for timeouts, cancellation, streams, and blocking offload\n\n## Installation\n\nInstall the exact version covered here:\n\n```bash\npip install anyio==4.12.1\n```\n\nIf you want Trio available as a runtime backend, install the Trio extra:\n\n```bash\npip install \"anyio[trio]==4.12.1\"\n```\n\nWith common Python package managers:\n\n```bash\nuv add anyio==4.12.1\npoetry add anyio==4.12.1\n```\n\nPyPI lists these extras for `4.12.1`: `trio`, `test`, and `doc`.\n\n## Setup And Backend Selection\n\nUse `anyio.run()` from a synchronous entrypoint. The default backend is `asyncio`.\n\n```python\nimport anyio\n\nasync def main() -> None:\n    await anyio.sleep(0.1)\n    print(\"hello from anyio\")\n\nanyio.run(main)\n```\n\nTo choose a backend explicitly:\n\n```python\nanyio.run(main, backend=\"asyncio\")\nanyio.run(main, backend=\"trio\")\n```\n\nBackend-specific options go through `backend_options`:\n\n```python\nanyio.run(main, backend=\"asyncio\", backend_options={\"debug\": True})\n```\n\nFor uvloop with AnyIO 4, prefer the documented `backend_options` path:\n\n```python\nanyio.run(main, backend=\"asyncio\", backend_options={\"use_uvloop\": True})\n```\n\nIf you need custom loop construction, AnyIO 4 migration guidance says to use `loop_factory`, not `event_loop_policy`:\n\n```python\nimport anyio\nimport uvloop\n\nanyio.run(\n    main,\n    backend=\"asyncio\",\n    backend_options={\"loop_factory\": uvloop.new_event_loop},\n)\n```\n\nIf you are already inside async code, do not nest `anyio.run()`. Use AnyIO primitives directly within the existing task instead.\n\n## Core Usage\n\n### Task Groups\n\nUse `create_task_group()` for structured concurrency. Child tasks are scoped to the context manager, and cancellation/cleanup is coordinated automatically.\n\n```python\nimport anyio\n\nasync def worker(name: str, delay: float) -> None:\n    await anyio.sleep(delay)\n    print(f\"{name} done\")\n\nasync def main() -> None:\n    async with anyio.create_task_group() as tg:\n        tg.start_soon(worker, \"a\", 0.2)\n        tg.start_soon(worker, \"b\", 0.1)\n\nanyio.run(main)\n```\n\nIf the parent must wait until the child has started successfully, use `TaskGroup.start()` and `task_status.started()`:\n\n```python\nimport anyio\nfrom anyio.abc import TaskStatus\n\nasync def start_service(*, task_status: TaskStatus[None]) -> None:\n    task_status.started()\n    await anyio.sleep_forever()\n\nasync def main() -> None:\n    async with anyio.create_task_group() as tg:\n        await tg.start(start_service)\n        print(\"service is ready\")\n\nanyio.run(main)\n```\n\n### Timeouts And Cancellation\n\nAnyIO timeout helpers are built on cancel scopes:\n\n- `move_on_after(seconds)` cancels the block and continues\n- `fail_after(seconds)` cancels the block and raises `TimeoutError`\n\n```python\nimport anyio\n\nasync def main() -> None:\n    with anyio.move_on_after(1) as scope:\n        await anyio.sleep(2)\n\n    if scope.cancelled_caught:\n        print(\"timed out\")\n\n    with anyio.fail_after(1):\n        await anyio.sleep(0.5)\n\nanyio.run(main)\n```\n\nWhen cleanup must keep running during cancellation, shield the cleanup block:\n\n```python\nimport anyio\n\nasync def close_resource(resource) -> None:\n    try:\n        await resource.do_work()\n    except anyio.get_cancelled_exc_class():\n        with anyio.move_on_after(10, shield=True):\n            await resource.aclose()\n        raise\n```\n\n### Memory Object Streams\n\nFor in-process producer/consumer pipelines, use memory object streams:\n\n```python\nimport anyio\nfrom anyio.abc import ObjectReceiveStream, ObjectSendStream\n\nasync def producer(send: ObjectSendStream[int]) -> None:\n    async with send:\n        for item in range(3):\n            await send.send(item)\n\nasync def consumer(receive: ObjectReceiveStream[int]) -> None:\n    async with receive:\n        async for item in receive:\n            print(item)\n\nasync def main() -> None:\n    send, receive = anyio.create_memory_object_stream[int](10)\n    async with anyio.create_task_group() as tg:\n        tg.start_soon(producer, send)\n        tg.start_soon(consumer, receive)\n\nanyio.run(main)\n```\n\nIn AnyIO 4, the typed form is `create_memory_object_stream[T](buffer_size)`. Older examples that pass the type as a second runtime argument are pre-4.x.\n\n### Run Blocking Code In Worker Threads\n\nUse `to_thread.run_sync()` for blocking I/O or sync library calls that should not block the event loop:\n\n```python\nimport time\nimport anyio\n\ndef blocking_call() -> str:\n    time.sleep(1)\n    return \"done\"\n\nasync def main() -> None:\n    result = await anyio.to_thread.run_sync(blocking_call)\n    print(result)\n\nanyio.run(main)\n```\n\nThe docs say the default worker thread limiter has `40` total tokens. Adjust it if your app intentionally offloads more sync work:\n\n```python\nimport anyio\n\nasync def main() -> None:\n    anyio.to_thread.current_default_thread_limiter().total_tokens = 60\n```\n\n## Testing\n\nAnyIO ships with a pytest plugin.\n\nMark async tests explicitly:\n\n```python\nimport anyio\nimport pytest\n\n@pytest.mark.anyio\nasync def test_example() -> None:\n    await anyio.sleep(0)\n```\n\nOr enable automatic handling in `pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\nanyio_mode = \"auto\"\n```\n\nIf `pytest-asyncio` is installed too, avoid putting both plugins in conflicting auto modes. Pick one framework's auto-discovery behavior and keep the other explicit.\n\n## Config And Environment\n\n`anyio` does not have package-level authentication or service credentials. The main runtime configuration points are:\n\n- backend choice: `asyncio` vs `trio`\n- `backend_options` for loop/debug behavior\n- worker thread limiter sizing for `to_thread.run_sync()`\n- pytest plugin mode for test suites\n\nFor library code, keep backend-specific calls at the application boundary. If a function uses raw `asyncio` APIs internally, it is no longer backend-neutral and may fail under Trio.\n\n## Common Pitfalls\n\n- Use PyPI, not the moving `stable` docs title, to confirm the package version and Python floor for `4.12.1`.\n- Do not use `asyncio.create_task()` or other raw backend APIs inside backend-neutral AnyIO library code unless you intentionally want to lock the code to that backend.\n- In AnyIO 4, task group failures propagate as `ExceptionGroup`. On Python 3.11+, use `except*`. On Python 3.9-3.10, use the `exceptiongroup` backport if you need compatible exception-group handling.\n- Old AnyIO examples may show `create_memory_object_stream(size, type)`; for AnyIO 4, use `create_memory_object_stream[T](size)`.\n- Old asyncio-backend setup may use `event_loop_policy`; migration guidance says to use `loop_factory` instead.\n- `to_thread.run_sync()` is for blocking synchronous work. It prevents event-loop stalls, but it is still thread-based and not a substitute for deliberate process-level parallelism.\n\n## Version-Sensitive Notes For 4.12.x\n\n- `4.12.0` added `anyio.functools`, `get_available_backends()`, and expanded `use_uvloop=True` support on Windows when `winloop` is installed.\n- `4.12.1` changed the `NoEventLoopError` exception name from the internal `NoCurrentAsyncBackend`. If you were catching the old internal name, update that code.\n- The migration guide remains relevant for AnyIO 4 generally: exception groups replaced custom task-group exceptions, memory object stream typing changed, and event loop policy configuration moved to `loop_factory`.\n\n## Official Sources\n\n- Docs root: https://anyio.readthedocs.io/en/stable/\n- Basics: https://anyio.readthedocs.io/en/stable/basics.html\n- Creating and managing tasks: https://anyio.readthedocs.io/en/stable/tasks.html\n- Cancellation and timeouts: https://anyio.readthedocs.io/en/stable/cancellation.html\n- Working with threads: https://anyio.readthedocs.io/en/stable/threads.html\n- Testing: https://anyio.readthedocs.io/en/stable/testing.html\n- Migrating from AnyIO 3 to AnyIO 4: https://anyio.readthedocs.io/en/stable/migration.html\n- Version history: https://anyio.readthedocs.io/en/stable/versionhistory.html\n- PyPI package page: https://pypi.org/project/anyio/\n- PyPI version page: https://pypi.org/project/anyio/4.12.1/\n"
  },
  {
    "path": "content/apache-airflow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Apache Airflow workflow orchestration platform for authoring, scheduling, and monitoring Python-defined workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.8\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,workflow-orchestration,dag,scheduler,etl,data-pipelines\"\n---\n\n# Apache Airflow Python Package Guide\n\n## Golden Rule\n\nInstall `apache-airflow` with the official constraints file, write DAG code against the Airflow 3 public authoring API in `airflow.sdk`, and treat `airflow standalone` plus the default Simple auth manager as local-development shortcuts rather than production deployment defaults.\n\n## Install\n\nUse a virtual environment and the official constraints file. Upstream explicitly warns that plain `pip install apache-airflow` can produce an unusable installation.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=3.1.8\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\\\"{sys.version_info.major}.{sys.version_info.minor}\\\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf you already know which extras you need, install them in the same constrained command:\n\n```bash\npython -m pip install \"apache-airflow[postgres,google]==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\n```\n\nImportant installation notes:\n\n- Officially supported installers are `pip` and `uv`; Poetry and `pip-tools` are not officially supported workflows for Airflow installation.\n- Install providers separately from Airflow core after the base install. Constraints apply only to the `pip install` command that uses them.\n- When adding providers later, pin `apache-airflow` in the same command so `pip` does not silently upgrade or downgrade core:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" apache-airflow-providers-google\n```\n\n## Initialize A Local Instance\n\nFor local development, the quickest path is `airflow standalone`:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nairflow standalone\n```\n\nWhat this does:\n\n- initializes the metadata database\n- creates a local admin account\n- starts the API server, scheduler, dag processor, and triggerer\n- writes `airflow.cfg` under `$AIRFLOW_HOME`\n\nThen open `http://localhost:8080` and use the admin credentials printed in the terminal.\n\nIf you want to run components separately instead of `standalone`:\n\n```bash\nairflow db migrate\nairflow api-server --port 8080\nairflow scheduler\nairflow dag-processor\nairflow triggerer\n```\n\n`airflow users create` is only available when the Flask AppBuilder auth manager is enabled; it is not the default auth flow in Airflow 3.\n\n## Write And Load DAGs\n\nAirflow 3's stable DAG authoring interface lives in `airflow.sdk`. Put DAG files in `$AIRFLOW_HOME/dags` or set `AIRFLOW__CORE__DAGS_FOLDER` to another absolute path.\n\nMinimal TaskFlow DAG:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import dag, task\n\n@dag(\n    dag_id=\"hello_airflow\",\n    schedule=None,\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    catchup=False,\n    tags=[\"example\"],\n)\ndef hello_airflow():\n    @task()\n    def extract() -> dict[str, int]:\n        return {\"orders\": 3, \"returns\": 1}\n\n    @task()\n    def summarize(stats: dict[str, int]) -> str:\n        return f\"net={stats['orders'] - stats['returns']}\"\n\n    @task()\n    def emit(message: str) -> None:\n        print(message)\n\n    emit(summarize(extract()))\n\nhello_airflow()\n```\n\nUseful local checks:\n\n```bash\nairflow dags list\nairflow dags show hello_airflow\nairflow tasks test hello_airflow emit 2026-03-12\n```\n\nAuthoring notes for agents:\n\n- Prefer `@dag` and `@task` for ordinary Python workflows.\n- `schedule=None` is the explicit \"manual only\" setting in Airflow 3.\n- Set `catchup` explicitly in code even though the global default in Airflow 3 is now `False`.\n- Keep top-level DAG file code lightweight. Airflow repeatedly parses DAG files, so expensive imports, network calls, or database queries at module import time will hurt scheduler performance.\n\n## Common Configuration\n\n`airflow.cfg` is the base config file, but environment variables are the safest override mechanism:\n\n```bash\nexport AIRFLOW__CORE__DAGS_FOLDER=\"/abs/path/to/dags\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\nexport AIRFLOW__CORE__EXECUTOR=\"LocalExecutor\"\nexport AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=\"postgresql+psycopg2://airflow:secret@localhost:5432/airflow\"\n```\n\nCommon settings agents usually need:\n\n- `AIRFLOW__CORE__DAGS_FOLDER`: absolute path where DAG files live\n- `AIRFLOW__CORE__LOAD_EXAMPLES`: disable example DAGs in real environments\n- `AIRFLOW__CORE__EXECUTOR`: defaults to `LocalExecutor`; production stacks often switch to `CeleryExecutor` or `KubernetesExecutor`\n- `AIRFLOW__DATABASE__SQL_ALCHEMY_CONN`: metadata DB connection string\n- `AIRFLOW__CORE__FERNET_KEY`: key used to encrypt connection passwords in the metastore\n- `AIRFLOW__SECRETS__BACKEND`: secrets backend class, which takes precedence over env vars and metastore lookups for Connections and Variables\n\n## Database And Deployment Notes\n\nSQLite is for development only:\n\n- Airflow documents SQLite as suitable for development and says it should never be used in production.\n- For real deployments, move to PostgreSQL or MySQL.\n- MariaDB is explicitly unsupported.\n\nRecommended metadata database URI examples:\n\n```bash\nexport AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=\"postgresql+psycopg2://airflow:secret@localhost:5432/airflow\"\n```\n\n```bash\nexport AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=\"mysql+mysqldb://airflow:secret@localhost:3306/airflow\"\n```\n\nPostgreSQL-specific note:\n\n- Use `postgresql://` or `postgresql+psycopg2://`, not `postgres://`.\n\n## Auth, Users, And API Access\n\nAirflow 3 defaults to `SimpleAuthManager`.\n\nThat means:\n\n- it is intended for development and testing\n- users are configured through Airflow config, not through the legacy webserver/FAB flow\n- passwords are auto-generated and stored in a JSON file unless you set a custom password file path\n\nSimple auth manager example:\n\n```bash\nexport AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_USERS=\"alice:admin,bob:viewer\"\nexport AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_PASSWORDS_FILE=\"$AIRFLOW_HOME/simple-auth-passwords.json\"\n```\n\nDo not use this in production:\n\n```bash\nexport AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_ALL_ADMINS=\"True\"\n```\n\nThat setting disables authentication and treats every user as an admin.\n\nIf you need the traditional Airflow user-management flow, install the FAB auth manager provider and switch auth managers:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" apache-airflow-providers-fab\nexport AIRFLOW__CORE__AUTH_MANAGER=\"airflow.providers.fab.auth_manager.FabAuthManager\"\n```\n\nThen `airflow users create` becomes available.\n\nPublic API auth in Airflow 3 uses JWTs. Typical flow:\n\n```bash\nENDPOINT_URL=\"http://localhost:8080\"\n\nTOKEN=\"$(\n  curl -sS -X POST \"${ENDPOINT_URL}/auth/token\" \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\"username\":\"alice\",\"password\":\"your-password\"}' |\n  python -c 'import json,sys; print(json.load(sys.stdin)[\"access_token\"])'\n)\"\n\ncurl -sS \"${ENDPOINT_URL}/api/v2/dags\" \\\n  -H \"Authorization: Bearer ${TOKEN}\"\n```\n\n## Connections, Variables, And Secrets\n\nEnvironment-based config is often the safest path for agents and CI.\n\nConnection via env var:\n\n```bash\nexport AIRFLOW_CONN_MY_PROD_DB='postgresql://user:pass@db.example.com:5432/app'\n```\n\nConnection via JSON env var:\n\n```bash\nexport AIRFLOW_CONN_AWS_DEFAULT='{\"conn_type\":\"aws\",\"extra\":{\"region_name\":\"us-west-2\"}}'\n```\n\nVariable via env var:\n\n```bash\nexport AIRFLOW_VAR_DEPLOY_ENV=\"staging\"\nexport AIRFLOW_VAR_FEATURE_FLAGS='{\"use_new_loader\": true}'\n```\n\nUse these APIs in DAG code:\n\n```python\nfrom airflow.sdk import Connection, Variable\n\ndeploy_env = Variable.get(\"deploy_env\")\nfeature_flags = Variable.get(\"feature_flags\", deserialize_json=True)\nconn = Connection.get(\"my_prod_db\")\n```\n\nProduction guidance:\n\n- Prefer a secrets backend over UI-entered secrets when possible.\n- Keep `hide_sensitive_var_conn_fields=True` unless you have a strong reason to expose more detail in logs or the UI.\n- Connection testing is disabled by default in UI, API, and CLI unless `core.test_connection` is enabled.\n\n## Common Pitfalls\n\n- Do not install with plain `pip install apache-airflow` and stop there. Use constraints.\n- Do not keep using Airflow 2 import paths like `from airflow.models import DAG` or `from airflow.operators.python import PythonOperator`. In Airflow 3, DAG authoring moved to `airflow.sdk`, and standard operators now live in provider packages such as `airflow.providers.standard`.\n- Do not use `airflow webserver`, `airflow db init`, or `airflow db upgrade` in new Airflow 3 automation. Use `airflow api-server` and `airflow db migrate`.\n- Do not use SQLite for production metadata storage.\n- Do not put slow work at module import time in DAG files.\n- Do not assume manually triggered or REST-triggered DAG runs always have a `logical_date`. In Airflow 3, `logical_date` can be `None`.\n- Do not access the metadata database directly from task code. Airflow 3 expects stateful interactions to go through the REST API or exposed task context.\n\n## Version-Sensitive Notes For Airflow 3.1\n\n- `apache-airflow 3.1.8` is the current Airflow 3 patch release on the stable docs and PyPI as of March 12, 2026.\n- Airflow 3 supports Python `3.10`, `3.11`, `3.12`, and `3.13`.\n- The stable DAG authoring interface is `airflow.sdk`; older internal imports are deprecated or removed.\n- `SimpleAuthManager` is the default auth manager in Airflow 3.\n- `catchup_by_default` is `False` in Airflow 3, and the default DAG `schedule` is `None` instead of `@once`.\n- `SequentialExecutor` has been removed; `LocalExecutor` is the default executor.\n- Future logical dates are no longer supported when triggering DAG runs.\n- The core CLI now covers local functionality, while some service-mode remote actions moved into `airflowctl` from the `apache-airflow-client` package.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-airbyte/python/DOC.md",
    "content": "---\nname: providers-airbyte\ndescription: \"Apache Airflow provider for triggering and monitoring Airbyte connection syncs from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,airbyte,elt,operators,sensors\"\n---\n\n# Apache Airflow Providers Airbyte Guide\n\nUse `apache-airflow-providers-airbyte` when an Airflow DAG needs to start an Airbyte sync for an existing Airbyte connection and optionally wait for that sync job to finish.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone Airbyte SDK.\n- Keep Airbyte server details and any authentication on an Airflow connection such as `airbyte_default` instead of hard-coding them in DAG files.\n- Pass the Airbyte connection UUID to `connection_id`. That value identifies the Airbyte source-to-destination connection inside Airbyte; it is not the Airflow connection id.\n- Use `AirbyteTriggerSyncOperator` to start the sync and `AirbyteJobSensor` when you want the wait step as a separate task.\n\n## What This Package Adds\n\nThe Airbyte provider's main entry points are:\n\n- `AirbyteTriggerSyncOperator`\n- `AirbyteJobSensor`\n- `AirbyteHook`\n\nThese are the classes most DAGs use from this provider.\n\n## Install\n\nInstall the provider into the same Airflow environment used by your scheduler, webserver, triggerer, and workers.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.3.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-airbyte==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-airbyte==5.3.2\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep airbyte\npython -c \"from airflow.providers.airbyte.operators.airbyte import AirbyteTriggerSyncOperator; from airflow.providers.airbyte.sensors.airbyte import AirbyteJobSensor; print('ok')\"\n```\n\n## Configure The Airflow Connection\n\nStart with a basic Airflow environment and keep the Airbyte server address outside the DAG file:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\nexport AIRBYTE_HOST=\"airbyte.example.internal\"\nexport AIRBYTE_PORT=\"8000\"\nexport AIRBYTE_CONNECTION_ID=\"<your-airbyte-connection-uuid>\"\n```\n\nCreate an Airflow connection for the Airbyte server:\n\n```bash\nairflow connections add 'airbyte_default' \\\n  --conn-type 'airbyte' \\\n  --conn-host \"$AIRBYTE_HOST\" \\\n  --conn-port \"$AIRBYTE_PORT\"\n```\n\nConfirm the connection exists before you wire it into a DAG:\n\n```bash\nairflow connections get airbyte_default\n```\n\nIf your Airbyte deployment requires authentication or extra connection settings, put those values on the Airflow connection itself instead of embedding them in DAG code.\n\n## Common Workflow: Trigger A Sync And Wait In One Task\n\nUse a synchronous operator run when one task should both start the Airbyte job and keep polling until the job finishes.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.airbyte.operators.airbyte import AirbyteTriggerSyncOperator\n\n\nAIRBYTE_CONNECTION_ID = os.environ[\"AIRBYTE_CONNECTION_ID\"]\n\n\nwith DAG(\n    dag_id=\"airbyte_sync_connection\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"airbyte\"],\n):\n    trigger_sync = AirbyteTriggerSyncOperator(\n        task_id=\"trigger_sync\",\n        airbyte_conn_id=\"airbyte_default\",\n        connection_id=AIRBYTE_CONNECTION_ID,\n        asynchronous=False,\n        timeout=60 * 60,\n        wait_seconds=3,\n    )\n```\n\nUse this when the DAG only needs one Airbyte task and you do not need a separate sensor step.\n\n## Common Workflow: Trigger Asynchronously And Wait With A Sensor\n\nUse this pattern when you want the trigger and wait phases to be separate tasks.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.airbyte.operators.airbyte import AirbyteTriggerSyncOperator\nfrom airflow.providers.airbyte.sensors.airbyte import AirbyteJobSensor\n\n\nAIRBYTE_CONNECTION_ID = os.environ[\"AIRBYTE_CONNECTION_ID\"]\n\n\nwith DAG(\n    dag_id=\"airbyte_async_connection\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"airbyte\"],\n):\n    trigger_sync = AirbyteTriggerSyncOperator(\n        task_id=\"trigger_sync\",\n        airbyte_conn_id=\"airbyte_default\",\n        connection_id=AIRBYTE_CONNECTION_ID,\n        asynchronous=True,\n    )\n\n    wait_for_sync = AirbyteJobSensor(\n        task_id=\"wait_for_sync\",\n        airbyte_conn_id=\"airbyte_default\",\n        airbyte_job_id=trigger_sync.output,\n    )\n\n    trigger_sync >> wait_for_sync\n```\n\nThe important handoff is `airbyte_job_id=trigger_sync.output`: the operator returns the Airbyte job id, and the sensor polls that job until it reaches a terminal state.\n\n## Configuration Pattern\n\nFor most DAGs, a clean split is:\n\n- keep the Airbyte server address and any credentials on `airbyte_default` or another named Airflow connection\n- keep the Airbyte connection UUID in an environment variable, Airflow Variable, or another deployment-specific config source\n- use `AirbyteTriggerSyncOperator` when the task only needs to start one Airbyte sync\n- add `AirbyteJobSensor` when downstream work should not begin until the Airbyte job finishes\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. A missing package on a worker or task image causes import failures even if the scheduler has it.\n- Do not confuse `airbyte_conn_id` with `connection_id`. `airbyte_conn_id` is the Airflow connection name; `connection_id` is the Airbyte connection UUID.\n- Keep Airbyte server details out of DAG source. Put host, port, and credentials on the Airflow connection or a secrets backend.\n- Make sure the Airbyte server is reachable from the worker environment, not just from your laptop or the Airflow web UI.\n- Keep `apache-airflow` pinned when adding or upgrading the provider so `pip` does not silently change your Airflow core version.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-airbyte` version `5.3.2`.\n- Airflow provider packages are versioned independently from Apache Airflow core and from Airbyte itself, so check provider compatibility before changing Airflow or provider pins in production.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-airbyte/stable/`\n- Airbyte connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-airbyte/stable/connections/airbyte.html`\n- `AirbyteHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-airbyte/stable/_api/airflow/providers/airbyte/hooks/airbyte/index.html`\n- `AirbyteTriggerSyncOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-airbyte/stable/_api/airflow/providers/airbyte/operators/airbyte/index.html`\n- `AirbyteJobSensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-airbyte/stable/_api/airflow/providers/airbyte/sensors/airbyte/index.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-airbyte/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-amazon/python/DOC.md",
    "content": "---\nname: providers-amazon\ndescription: \"Apache Airflow provider for AWS integrations such as S3, Athena, and Secrets Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.22.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,aws,s3,athena,secrets-manager,dag\"\n---\n\n# Apache Airflow Providers Amazon Guide\n\nUse `apache-airflow-providers-amazon` to connect Airflow DAGs to AWS services through provider hooks, operators, sensors, and a Secrets Manager-backed secrets backend.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone runtime.\n- Create an Airflow AWS connection such as `aws_default` and make AWS credentials available before writing DAG code.\n- Keep account-specific credentials and secrets out of DAG files; use Airflow connections, AWS runtime credentials, and secret backends instead.\n\n## Install\n\nStart from an Airflow installation that uses the official constraints file for your Airflow and Python versions, then add the Amazon provider in the same command.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"9.22.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-amazon==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep the Airflow package pinned when adding the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-amazon==9.22.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep amazon\nairflow info\n```\n\n## What This Provider Commonly Adds\n\nThe maintainer docs for this provider include AWS integrations such as:\n\n- `S3Hook`, `S3CreateObjectOperator`, and `S3KeySensor` for S3 file movement and object checks\n- `AthenaOperator` for running Athena queries from DAGs\n- `SecretsManagerBackend` for resolving Airflow connections and variables from AWS Secrets Manager\n\n## Authentication And Configuration\n\nThe conventional Airflow connection ID for this provider is `aws_default`. Most hooks and operators let you override it with `aws_conn_id`.\n\n### Environment credentials plus an Airflow connection\n\nThe simplest setup is an Airflow AWS connection that carries region information while boto3 resolves credentials from the runtime environment.\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"<access-key-id>\"\nexport AWS_SECRET_ACCESS_KEY=\"<secret-access-key>\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n\nexport AIRFLOW_CONN_AWS_DEFAULT='{\"conn_type\":\"aws\",\"extra\":{\"region_name\":\"us-east-1\"}}'\n```\n\nIf you are using temporary credentials, also set:\n\n```bash\nexport AWS_SESSION_TOKEN=\"<session-token>\"\n```\n\nIn ECS, EKS, EC2, MWAA, or another role-based environment, you typically omit the static key variables and let boto3 use the attached role instead.\n\n### Create the connection with the Airflow CLI\n\n```bash\nairflow connections add 'aws_default' \\\n  --conn-type 'aws' \\\n  --conn-extra '{\"region_name\":\"us-east-1\"}'\n```\n\nUse a different connection ID when different DAGs need different accounts, regions, or IAM behavior, and pass that ID explicitly with `aws_conn_id`.\n\n## Common Workflow: Read And Write S3 Objects\n\nUse operators and hooks from the provider instead of shelling out to the AWS CLI from a task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.amazon.aws.hooks.s3 import S3Hook\nfrom airflow.providers.amazon.aws.operators.s3 import S3CreateObjectOperator\nfrom airflow.providers.amazon.aws.sensors.s3 import S3KeySensor\n\n\nwith DAG(\n    dag_id=\"aws_s3_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"aws\", \"s3\"],\n):\n    write_manifest = S3CreateObjectOperator(\n        task_id=\"write_manifest\",\n        aws_conn_id=\"aws_default\",\n        s3_bucket=\"my-data-bucket\",\n        s3_key=\"incoming/manifest.json\",\n        data='{\"run_date\": \"{{ ds }}\"}',\n        replace=True,\n    )\n\n    wait_for_manifest = S3KeySensor(\n        task_id=\"wait_for_manifest\",\n        aws_conn_id=\"aws_default\",\n        bucket_name=\"my-data-bucket\",\n        bucket_key=\"incoming/manifest.json\",\n    )\n\n    @task()\n    def read_manifest() -> str:\n        hook = S3Hook(aws_conn_id=\"aws_default\")\n        body = hook.read_key(\n            key=\"incoming/manifest.json\",\n            bucket_name=\"my-data-bucket\",\n        )\n        print(body)\n        return body\n\n    write_manifest >> wait_for_manifest >> read_manifest()\n```\n\nUseful `S3Hook` methods for task code include `read_key`, `load_string`, `list_keys`, and `check_for_key`.\n\n## Common Workflow: Run An Athena Query\n\nUse `AthenaOperator` when a DAG needs to submit a SQL statement to Athena and write results to S3.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.amazon.aws.operators.athena import AthenaOperator\n\n\nwith DAG(\n    dag_id=\"athena_report_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"aws\", \"athena\"],\n):\n    run_query = AthenaOperator(\n        task_id=\"run_query\",\n        aws_conn_id=\"aws_default\",\n        query=\"\"\"\n        SELECT current_date AS run_date, count(*) AS row_count\n        FROM analytics.orders\n        \"\"\",\n        database=\"analytics\",\n        output_location=\"s3://my-athena-results/queries/\",\n        workgroup=\"primary\",\n    )\n```\n\nMake sure the Airflow task identity can both start Athena queries and read or write the S3 results location used by Athena.\n\n## Common Workflow: Resolve Secrets From AWS Secrets Manager\n\nThe provider also ships a secrets backend so Airflow can read connections and variables from AWS Secrets Manager instead of storing them only in the Airflow metadata database.\n\nSet the backend in the Airflow environment:\n\n```bash\nexport AIRFLOW__SECRETS__BACKEND=\"airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend\"\nexport AIRFLOW__SECRETS__BACKEND_KWARGS='{\"connections_prefix\":\"airflow/connections\",\"variables_prefix\":\"airflow/variables\",\"region_name\":\"us-east-1\"}'\n```\n\nThen access connections and variables through the normal Airflow APIs:\n\n```python\nfrom airflow.hooks.base import BaseHook\nfrom airflow.models import Variable\n\n\naws_conn = BaseHook.get_connection(\"aws_default\")\ndeploy_env = Variable.get(\"deploy_env\")\n\nprint(aws_conn.conn_id)\nprint(deploy_env)\n```\n\nAfter changing secrets backend settings, restart every Airflow component that should use the new backend.\n\n## Operational Checks\n\nConfirm the provider is installed:\n\n```bash\nairflow providers list | grep amazon\n```\n\nConfirm the AWS connection exists:\n\n```bash\nairflow connections get aws_default\n```\n\nCheck that Airflow can parse the DAG and that a task can import the provider classes:\n\n```bash\nairflow dags list\nairflow tasks test aws_s3_demo read_manifest 2026-03-12\n```\n\nUse `airflow tasks test` for isolated task debugging. Use a normal DAG trigger when you need the scheduler, workers, and secrets backend to participate end to end.\n\n## Common Pitfalls\n\n- Installing the provider without pinning `apache-airflow` and the official constraints file for your environment.\n- Setting AWS credentials or IAM role assumptions for only one Airflow process; scheduler, workers, and API or web processes all need compatible AWS access.\n- Relying on `aws_default` implicitly when a DAG should target a different account or region; pass `aws_conn_id` explicitly in shared environments.\n- Giving Athena permission but forgetting the S3 results bucket permissions it also needs.\n- Hard-coding AWS keys or secret values in DAG files instead of using Airflow connections, runtime credentials, or Secrets Manager.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-amazon` version `9.22.0`.\n- The examples focus on the provider classes surfaced in maintainer docs for S3, Athena, and Secrets Manager.\n- Re-check the provider installation and AWS connection documentation before upgrading Airflow or changing authentication modes.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-beam/python/DOC.md",
    "content": "---\nname: providers-apache-beam\ndescription: \"Apache Airflow provider for launching Apache Beam pipelines from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.2.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,apache-beam,beam,dataflow,dag,pipelines\"\n---\n\n# Apache Airflow Apache Beam Provider Guide\n\nUse `apache-airflow-providers-apache-beam` when an Airflow DAG should submit an existing Apache Beam pipeline instead of shelling out manually. This package extends Airflow with Beam operators; you still author the pipeline itself with `apache-beam`.\n\n## Golden Rule\n\n- Install this provider into an existing Airflow environment and keep `apache-airflow` pinned in the same install command.\n- Treat the provider as orchestration glue for Beam jobs, not as a replacement for the `apache-beam` SDK.\n- Keep runner-specific options and credentials outside DAG source when possible, and pass Beam job flags through `pipeline_options`.\n- Point the operator at a real pipeline file that can also run directly with the Beam SDK from the command line.\n\n## What This Package Adds\n\nFor most Python DAGs, the main entry point is:\n\n- `airflow.providers.apache.beam.operators.beam.BeamRunPythonPipelineOperator`\n\nUse it to run a Python Beam pipeline file from a DAG and pass Beam runner flags such as `runner`, `project`, `region`, `temp_location`, or job-specific custom options.\n\n## Install\n\nInstall the provider into the same environment or container image as Airflow. Keep Airflow pinned in the same command so `pip` does not silently upgrade or downgrade core.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"6.2.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-beam==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nFor Python Beam pipelines, install the Beam SDK in the same runtime that executes the Airflow task:\n\n```bash\npython -m pip install apache-beam\n```\n\nIf the DAG runs Beam jobs on Dataflow, install the Google Cloud extra instead:\n\n```bash\npython -m pip install \"apache-beam[gcp]\"\n```\n\nEvery Airflow service that imports or executes DAG code needs the provider installed, including the scheduler and all workers.\n\n## Local Airflow Setup\n\nFor local development, initialize Airflow once and point it at a writable home directory:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nairflow standalone\n```\n\nThat gives you a working local scheduler, API server, and web UI so you can iterate on the DAG and Beam pipeline together.\n\n## Write A Beam Pipeline File\n\nKeep the Beam pipeline in a normal Python file that uses `PipelineOptions()` so the operator can pass runtime flags.\n\n```python\nimport apache_beam as beam\nfrom apache_beam.options.pipeline_options import PipelineOptions\n\n\ndef run() -> None:\n    pipeline_options = PipelineOptions()\n\n    with beam.Pipeline(options=pipeline_options) as pipeline:\n        (\n            pipeline\n            | \"ReadLines\" >> beam.io.ReadFromText(\"input.txt\")\n            | \"SplitWords\" >> beam.FlatMap(str.split)\n            | \"PairWithOne\" >> beam.Map(lambda word: (word, 1))\n            | \"CountWords\" >> beam.CombinePerKey(sum)\n            | \"Format\" >> beam.Map(lambda pair: f\"{pair[0]}:{pair[1]}\")\n            | \"WriteLines\" >> beam.io.WriteToText(\"output/wordcount\")\n        )\n\n\nif __name__ == \"__main__\":\n    run()\n```\n\nSave it somewhere the Airflow worker can read, for example `/opt/airflow/dags/beam/wordcount_pipeline.py`.\n\n## Run A Python Beam Job From A DAG\n\nMinimal local example with `DirectRunner`:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG\nfrom airflow.providers.apache.beam.operators.beam import BeamRunPythonPipelineOperator\n\nwith DAG(\n    dag_id=\"beam_wordcount_local\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"beam\"],\n):\n    run_wordcount = BeamRunPythonPipelineOperator(\n        task_id=\"run_wordcount\",\n        py_file=\"/opt/airflow/dags/beam/wordcount_pipeline.py\",\n        runner=\"DirectRunner\",\n        pipeline_options={\n            \"input\": \"/opt/airflow/dags/data/input.txt\",\n            \"output\": \"/opt/airflow/dags/data/output/wordcount\",\n        },\n    )\n```\n\nKey details:\n\n- `py_file` is the Beam pipeline script the worker will execute.\n- `runner` selects the Beam runner.\n- `pipeline_options` becomes the Beam job arguments, so the keys should match the option names your pipeline and runner expect.\n\n## Run On Dataflow\n\nWhen you switch from local development to Google Cloud Dataflow, keep the same operator and change the Beam runner options.\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\n```\n\n```python\nfrom airflow.providers.apache.beam.operators.beam import BeamRunPythonPipelineOperator\n\nrun_wordcount_dataflow = BeamRunPythonPipelineOperator(\n    task_id=\"run_wordcount_dataflow\",\n    py_file=\"/opt/airflow/dags/beam/wordcount_pipeline.py\",\n    runner=\"DataflowRunner\",\n    pipeline_options={\n        \"project\": \"my-gcp-project\",\n        \"region\": \"us-central1\",\n        \"temp_location\": \"gs://my-bucket/tmp\",\n        \"staging_location\": \"gs://my-bucket/staging\",\n        \"input\": \"gs://my-bucket/input.txt\",\n        \"output\": \"gs://my-bucket/output/wordcount\",\n    },\n)\n```\n\nPractical requirements for Dataflow jobs:\n\n- install `apache-beam[gcp]` in the task runtime\n- use a valid `gs://` bucket for `temp_location`\n- set `staging_location` explicitly when you want predictable staging behavior\n- make the Google credentials available to the worker process that launches the job\n\n## Common Workflow Pattern\n\nThe cleanest pattern is:\n\n1. keep the Beam pipeline in its own Python module\n2. run it locally with `DirectRunner` until the logic is correct\n3. call that same file from `BeamRunPythonPipelineOperator`\n4. switch only the runner-specific `pipeline_options` when you move to a remote runner\n\nThis keeps the Beam job runnable both inside and outside Airflow, which makes debugging much easier.\n\n## Pitfalls\n\n- This provider does not install or replace the Beam SDK by itself; Python Beam jobs still need `apache-beam` in the execution environment.\n- `py_file` must exist on the Airflow worker that executes the task, not just on your laptop.\n- `DirectRunner` is good for local development, but remote runners still need their own dependencies, credentials, and staging configuration.\n- If a pipeline works from the command line and fails in Airflow, compare the worker environment, installed packages, and effective `pipeline_options` first.\n- If a pipeline fails only on Dataflow, check `project`, `region`, `temp_location`, and `staging_location` before changing pipeline code.\n- Install the provider everywhere DAGs are parsed or run. Import errors usually mean one Airflow image or service is missing the package.\n\n## When To Reach For This Provider\n\nUse `apache-airflow-providers-apache-beam` when Airflow should orchestrate Beam jobs as DAG tasks. If you are only writing a standalone Beam application and do not need Airflow scheduling, author and run the pipeline directly with `apache-beam` instead.\n\n## Official References\n\n- Airflow provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-beam/stable/`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-beam/`\n- Apache Beam Python SDK overview: `https://beam.apache.org/documentation/sdks/python/`\n- Apache Beam Python quickstart: `https://beam.apache.org/get-started/quickstart-py/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-cassandra/python/DOC.md",
    "content": "---\nname: providers-apache-cassandra\ndescription: \"Apache Airflow provider for connecting DAGs to Apache Cassandra with Airflow connections and CassandraHook\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,cassandra,cql,dag,python\"\n---\n\n# apache-airflow-providers-apache-cassandra\n\nUse `apache-airflow-providers-apache-cassandra` when an Airflow DAG needs a managed Cassandra connection and Python tasks that execute CQL through `CassandraHook`.\n\nThis guide targets provider version `3.9.2`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Cassandra client for regular Python apps.\n- Keep cluster hosts, credentials, and driver-specific options in an Airflow connection such as `cassandra_default` instead of hard-coding them in DAG files.\n- Use `CassandraHook` inside tasks and send values as query parameters rather than building CQL strings with Python interpolation.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.9.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-cassandra==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-apache-cassandra==3.9.2\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep cassandra\nairflow info\n```\n\n## Configure The Airflow Connection\n\nThis provider reads Cassandra connection details from an Airflow connection. A practical setup is to keep the raw values in environment variables, then create the Airflow connection from them.\n\n```bash\nexport CASSANDRA_HOST='cassandra.example.com'\nexport CASSANDRA_PORT='9042'\nexport CASSANDRA_KEYSPACE='analytics'\nexport CASSANDRA_USERNAME='airflow'\nexport CASSANDRA_PASSWORD='secret'\n```\n\nCreate the connection:\n\n```bash\nairflow connections add 'cassandra_default' \\\n  --conn-type 'cassandra' \\\n  --conn-host \"$CASSANDRA_HOST\" \\\n  --conn-port \"$CASSANDRA_PORT\" \\\n  --conn-schema \"$CASSANDRA_KEYSPACE\" \\\n  --conn-login \"$CASSANDRA_USERNAME\" \\\n  --conn-password \"$CASSANDRA_PASSWORD\"\n```\n\nConfirm the connection exists before wiring it into a DAG:\n\n```bash\nairflow connections get cassandra_default\n```\n\nKeep any cluster-specific settings that go beyond host, port, keyspace, and credentials in the Airflow connection itself. That includes settings such as TLS or other driver-related options that should not live in DAG source files.\n\n## Common Workflow: Check Connectivity And Read Cluster Metadata\n\nUse `CassandraHook` inside a task when you want to run CQL directly from Python code. A simple first query is `system.local`, which exists on Cassandra clusters and is useful for connectivity checks.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.cassandra.hooks.cassandra import CassandraHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"cassandra_cluster_info\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"cassandra\"],\n):\n    @task\n    def read_cluster_info() -> dict[str, str]:\n        hook = CassandraHook(cassandra_conn_id=\"cassandra_default\")\n        session = hook.get_conn()\n\n        row = session.execute(\n            \"SELECT cluster_name, release_version FROM system.local\"\n        ).one()\n\n        if row is None:\n            raise RuntimeError(\"system.local returned no rows\")\n\n        return {\n            \"cluster_name\": row.cluster_name,\n            \"release_version\": row.release_version,\n        }\n\n    read_cluster_info()\n```\n\nThe important pattern is:\n\n1. create `CassandraHook(cassandra_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned session to execute CQL\n\n## Common Workflow: Execute Parameterized CQL In A Task\n\nFor application tables, use parameterized CQL and keep the query itself inside the task that owns the business logic.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.cassandra.hooks.cassandra import CassandraHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"cassandra_insert_and_read\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"cassandra\"],\n):\n    @task\n    def insert_event() -> None:\n        hook = CassandraHook(cassandra_conn_id=\"cassandra_default\")\n        session = hook.get_conn()\n\n        session.execute(\n            \"\"\"\n            INSERT INTO analytics.events (event_id, event_type, source)\n            VALUES (%s, %s, %s)\n            \"\"\",\n            (\"evt-001\", \"signup\", \"airflow\"),\n        )\n\n    @task\n    def read_recent_events() -> list[str]:\n        hook = CassandraHook(cassandra_conn_id=\"cassandra_default\")\n        session = hook.get_conn()\n\n        rows = session.execute(\n            \"SELECT event_id, event_type, source FROM analytics.events LIMIT 10\"\n        )\n\n        return [f\"{row.event_id}:{row.event_type}:{row.source}\" for row in rows]\n\n    insert_event() >> read_recent_events()\n```\n\nAdapt the table name, partition-key filters, and values to your schema. If the connection schema already points at your keyspace, you can use unqualified table names in your own DAGs.\n\n## Common Setup Pattern\n\nFor most Airflow DAGs that touch Cassandra, a clean split is:\n\n- put host, port, keyspace, credentials, and connection extras in `cassandra_default` or another shared Airflow connection id\n- use `CassandraHook` inside `@task` functions when the task needs to execute CQL directly\n- keep table names and task-specific queries in DAG code, but keep secrets and endpoint details in the connection layer\n- use small, purpose-built queries so task retries do not turn into expensive full-table reads\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Scheduler, worker, and local test environments all need the package if they import `airflow.providers.apache.cassandra`.\n- Keep `apache-airflow` pinned when you add or upgrade the provider so `pip` does not silently replace your Airflow core version.\n- Use worker-reachable hosts. A Cassandra hostname that works from a laptop or bastion may still fail from Airflow containers or remote workers.\n- Keep credentials and TLS-related settings in Airflow connections or a secrets backend instead of embedding them directly in DAG code.\n- Use query parameters instead of string formatting when values come from upstream tasks or runtime input.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-cassandra` version `3.9.2`.\n- Re-check the provider's version-specific documentation when you upgrade Airflow core or move to a newer provider release.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-cassandra/3.9.2/`\n- Cassandra connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-cassandra/3.9.2/connections/cassandra.html`\n- `CassandraHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-cassandra/3.9.2/_api/airflow/providers/apache/cassandra/hooks/cassandra/index.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-apache-cassandra/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-druid/python/DOC.md",
    "content": "---\nname: providers-apache-druid\ndescription: \"Apache Airflow Druid provider for submitting ingestion specs, running Druid SQL checks, and querying Druid from Airflow tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,druid,apache-druid,dag,python\"\n---\n\n# apache-airflow-providers-apache-druid\n\nUse `apache-airflow-providers-apache-druid` when an Airflow DAG needs to submit a Druid ingestion spec, run a Druid SQL data check, or query Druid from Python task code through Airflow-managed connections.\n\nThis package is an Airflow provider, not a standalone Druid client for ordinary Python applications.\n\nThis guide targets provider version `4.5.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as `apache-airflow`. In practice, that means the scheduler, webserver, and every worker that imports DAG code must have the provider available.\n\nPin Airflow and the provider together, and use the Airflow constraints file for your Airflow version:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.5.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-druid==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\n## Choose The Right Interface\n\nThis provider exposes three common integration paths:\n\n- `DruidOperator`: submit an indexing task to Druid ingestion\n- `DruidCheckOperator`: run a SQL check against Druid and fail the Airflow task when the result is not truthy\n- `DruidDbApiHook`: query Druid from Python task code\n\nMost DAGs use one of these patterns:\n\n- submit an ingestion spec with `DruidOperator`\n- verify a datasource with `DruidCheckOperator`\n- fetch a small result set in Python with `DruidDbApiHook`\n\n## Configure Airflow Connections\n\nKeep Druid endpoints, credentials, and TLS settings in Airflow connections instead of hard-coding them in DAG files.\n\nTypical connection ids used by this provider:\n\n- `druid_ingest_default` for ingestion through the Druid overlord or indexing service\n- `druid_broker_default` for Druid SQL queries through the broker or router\n\nExample environment-variable connections:\n\n```bash\nexport AIRFLOW_CONN_DRUID_INGEST_DEFAULT='{\"conn_type\":\"druid\",\"host\":\"druid-overlord.example.com\",\"port\":8081}'\n\nexport AIRFLOW_CONN_DRUID_BROKER_DEFAULT='{\"conn_type\":\"druid\",\"host\":\"druid-broker.example.com\",\"port\":8888}'\n```\n\nIf your Druid deployment requires authentication, TLS, or custom extras, keep those values on the Airflow connection instead of embedding them in Python code.\n\nUseful check:\n\n```bash\nairflow connections get druid_ingest_default\nairflow connections get druid_broker_default\n```\n\n## Submit An Ingestion Task\n\nUse `DruidOperator` when the Airflow task should submit a Druid ingestion spec file.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.druid.operators.druid import DruidOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"druid_ingestion_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    submit_index = DruidOperator(\n        task_id=\"submit_index\",\n        json_index_file=\"/opt/airflow/dags/druid/index_wikipedia.json\",\n    )\n```\n\n`json_index_file` must point to a valid Druid ingestion spec that is readable by the Airflow worker running the task.\n\nIf you do not use the default ingestion connection id, pass `druid_ingest_conn_id` explicitly.\n\n## Run A Druid SQL Check\n\nUse `DruidCheckOperator` when a task should fail unless a query returns a truthy result.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.druid.operators.druid_check import DruidCheckOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"druid_check_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    check_rows_loaded = DruidCheckOperator(\n        task_id=\"check_rows_loaded\",\n        sql=\"SELECT COUNT(*) FROM wikipedia\",\n    )\n```\n\nBy default, the check uses the Druid broker connection. If your deployment uses a different Airflow connection id, pass `druid_broker_conn_id` explicitly.\n\nThis is the simplest pattern for guardrail tasks such as:\n\n- checking that a datasource has at least one row\n- verifying a filtered query returns data before downstream publishing steps\n- stopping the DAG early when ingestion produced an empty result\n\n## Query Druid From Python Tasks\n\nUse `DruidDbApiHook` when task code needs a query result in Python.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.druid.hooks.druid import DruidDbApiHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"druid_hook_query_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def print_top_countries() -> None:\n        hook = DruidDbApiHook()\n\n        rows = hook.get_records(\n            \"\"\"\n            SELECT country, COUNT(*) AS row_count\n            FROM wikipedia\n            GROUP BY country\n            ORDER BY row_count DESC\n            LIMIT 10\n            \"\"\"\n        )\n\n        for country, row_count in rows:\n            print(country, row_count)\n\n    print_top_countries()\n```\n\nUse this for small result sets and branching logic. Keep large aggregations and scans inside Druid rather than moving big datasets through an Airflow worker.\n\n## Important Notes\n\n- Use the ingestion connection for indexing tasks and the broker connection for SQL queries. They target different Druid services.\n- `json_index_file` is resolved on the worker that runs the task. A local path on your laptop is not enough if tasks run in containers or on remote workers.\n- Install the provider everywhere DAG code is imported or executed. One missing worker image is enough to cause import failures at runtime.\n- Keep credentials and TLS settings in Airflow connections or your secrets backend, not in DAG source files.\n- This provider orchestrates Druid from Airflow. If you are writing a regular Python application outside Airflow, use a dedicated Druid client library instead of Airflow hooks and operators.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-druid/stable/`\n- Druid connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-druid/stable/connections/druid.html`\n- Hook API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-druid/stable/_api/airflow/providers/apache/druid/hooks/druid/index.html`\n- Operator API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-druid/stable/_api/airflow/providers/apache/druid/operators/druid/index.html`\n- Druid check operator API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-druid/stable/_api/airflow/providers/apache/druid/operators/druid_check/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-druid/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-flink/python/DOC.md",
    "content": "---\nname: providers-apache-flink\ndescription: \"Apache Airflow provider for deploying Apache Flink applications to Kubernetes from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,flink,kubernetes,python,dag,operator\"\n---\n\n# apache-airflow-providers-apache-flink\n\nUse `apache-airflow-providers-apache-flink` when an Airflow DAG needs to submit or update an Apache Flink deployment on Kubernetes. The provider's main public entry point is `FlinkKubernetesOperator`.\n\nThis guide targets provider version `1.8.2`.\n\n## Golden Rule\n\n- Install this provider into the same Python environment or container image as your Airflow deployment; it is not a standalone Flink client for regular Python scripts.\n- Treat Kubernetes access as Airflow configuration, not DAG code. Keep cluster credentials in a Kubernetes connection or another secrets-backed Airflow config path.\n- Use this provider only after the target cluster already has the Flink Kubernetes operator and its custom resources available.\n- Keep the Flink application manifest in a location every Airflow runtime can read, not only on the machine where you edit the DAG.\n\n## What This Package Adds\n\n`apache-airflow-providers-apache-flink` extends Airflow with Flink-on-Kubernetes support. The documented workflow is centered on `FlinkKubernetesOperator`, which applies a Flink application manifest to a Kubernetes cluster from a DAG task.\n\nThere is no separate long-lived client object to initialize in an application. In practice, you configure cluster access in Airflow and instantiate the operator inside a DAG.\n\n## Install\n\nInstall the provider alongside a pinned Airflow version so dependency resolution does not silently change the Airflow core package used by your deployment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"1.8.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-flink==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nEvery Airflow runtime that imports or executes the DAG needs the provider available, including the scheduler and any workers.\n\n## Prerequisites\n\nBefore you use the operator, make sure:\n\n- the Airflow runtime can reach the Kubernetes API server for the target cluster\n- the Kubernetes credentials used by Airflow can create or update the Flink custom resource in the target namespace\n- the cluster already has the Flink Kubernetes operator installed\n- the manifest file passed to `application_file` is available inside the scheduler or worker environment that runs the task\n\nFor local or out-of-cluster work, these environment variables are a practical starting point:\n\n```bash\nexport KUBECONFIG=\"$HOME/.kube/config\"\nexport FLINK_APPLICATION_FILE=\"$PWD/dags/flink/example-flinkdeployment.yaml\"\n```\n\n`KUBECONFIG` is useful while creating or debugging Kubernetes access for Airflow. `FLINK_APPLICATION_FILE` is the manifest path the DAG will hand to the operator.\n\n## Configure Cluster Access\n\nThe simplest day-to-day pattern is to keep cluster details in Airflow's Kubernetes connection layer and reference `kubernetes_default` from the DAG. That keeps kubeconfig paths, service-account settings, and any cluster-specific configuration out of source code.\n\nIf you run Airflow inside Kubernetes, prefer in-cluster credentials. If you run Airflow outside the cluster, a kubeconfig-backed Kubernetes connection is the common setup.\n\n## Minimal DAG\n\nThis is the smallest useful pattern for deploying a Flink application manifest from Airflow:\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\nfrom airflow import DAG\nfrom airflow.providers.apache.flink.operators.flink_kubernetes import FlinkKubernetesOperator\n\n\nFLINK_APPLICATION_FILE = os.environ[\"FLINK_APPLICATION_FILE\"]\n\n\nwith DAG(\n    dag_id=\"flink_kubernetes_submit\",\n    start_date=pendulum.datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"flink\", \"kubernetes\"],\n) as dag:\n    deploy_flink_application = FlinkKubernetesOperator(\n        task_id=\"deploy_flink_application\",\n        namespace=\"default\",\n        application_file=FLINK_APPLICATION_FILE,\n        kubernetes_conn_id=\"kubernetes_default\",\n    )\n```\n\nImportant fields in everyday use:\n\n- `application_file`: path to the Flink deployment manifest Airflow should apply\n- `namespace`: Kubernetes namespace containing the Flink custom resource\n- `kubernetes_conn_id`: Airflow connection id used for cluster authentication; `kubernetes_default` is the usual default\n\nThe `application_file` must point to a valid Flink custom resource manifest for the Flink Kubernetes operator installed in your cluster.\n\n## Common Workflow\n\n1. Build or check in a Flink deployment manifest that matches the Flink Kubernetes operator version used by your cluster.\n2. Make that file available inside the Airflow runtime, for example in the DAGs image or a mounted volume.\n3. Configure Kubernetes access in Airflow with a connection such as `kubernetes_default`.\n4. Add `FlinkKubernetesOperator` to the DAG with the target namespace and manifest path.\n5. Trigger the DAG and inspect the Airflow task log plus the resulting Kubernetes custom resource if the deployment does not come up as expected.\n\nUseful local checks:\n\n```bash\nairflow dags list\nairflow dags show flink_kubernetes_submit\nairflow tasks test flink_kubernetes_submit deploy_flink_application 2026-03-12\n```\n\n## Pitfalls\n\n### `application_file` must exist where the task runs\n\nIf the scheduler or worker runs in a container, `application_file` is resolved in that runtime, not on your laptop. Relative paths that only exist in a local checkout are a common source of task failures.\n\n### Airflow does not install or manage Flink for you\n\nThis provider lets Airflow talk to Kubernetes about Flink deployments. It does not install the Flink Kubernetes operator, create the cluster, or package your Flink job artifacts.\n\n### Keep Kubernetes auth out of DAG code\n\nHard-coding kubeconfig paths, tokens, or certificates directly into DAG files makes deployments brittle. Prefer Airflow connections, environment-backed secrets, or in-cluster credentials.\n\n### Pin Airflow and provider versions together\n\nAirflow provider packages evolve with Airflow itself. When you add or upgrade this provider, pin the Airflow version in the same install command and use the matching constraints file.\n\n## Version Notes\n\n- This guide is written for `apache-airflow-providers-apache-flink==1.8.2`.\n- If you are on another provider release, verify the operator arguments and dependency expectations in the corresponding Airflow provider docs before copying older examples.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-hdfs/python/DOC.md",
    "content": "---\nname: providers-apache-hdfs\ndescription: \"Apache Airflow HDFS provider for HDFS and WebHDFS hooks and sensors\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.11.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,hdfs,webhdfs,hooks,sensors,data-pipelines\"\n---\n\n# Apache Airflow HDFS Provider Guide\n\nUse `apache-airflow-providers-apache-hdfs` when an Airflow DAG needs to check for files in HDFS, wait for HDFS paths to appear, or talk to a cluster through WebHDFS from Python task code.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone HDFS client for regular Python applications.\n- Put cluster connection details and credentials in Airflow connections such as `hdfs_default` or `webhdfs_default` instead of hard-coding them in DAG files.\n- Use `HdfsSensor` or `HdfsRegexSensor` when a task should wait for files or directories to arrive.\n- Use `WebHDFSHook` when task code needs lower-level file operations against a WebHDFS endpoint.\n\n## What This Package Adds\n\nThis provider supplies Airflow's HDFS integration, centered around:\n\n- `HDFSHook`\n- `WebHDFSHook`\n- `HdfsSensor`\n- `HdfsRegexSensor`\n\nIn practice, most DAGs either use a sensor to wait for upstream data in HDFS or a hook inside a Python task for custom WebHDFS operations.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment. Keep Airflow pinned in the same command so `pip` does not silently upgrade or downgrade core.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.11.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-hdfs==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nEvery Airflow runtime that imports DAG code needs the provider installed, including the scheduler and all workers.\n\n## Choose The Connection Type\n\nThe provider supports two common ways to reach HDFS:\n\n- `HDFS` connection: classic HDFS access used by the HDFS hook and sensors\n- `WebHDFS` connection: HTTP-based access through the NameNode's WebHDFS endpoint\n\nIf your platform exposes WebHDFS, it is usually the simpler choice for custom Python task logic because `WebHDFSHook.get_conn()` returns a WebHDFS client object you can call directly.\n\n## Configure Airflow Connections\n\nYou can create the connections in the Airflow UI, with the CLI, or through environment variables.\n\nExample URI-style environment variables:\n\n```bash\nexport AIRFLOW_CONN_HDFS_DEFAULT='hdfs://hdfs@namenode.example.com:8020'\nexport AIRFLOW_CONN_WEBHDFS_DEFAULT='webhdfs://hdfs@namenode.example.com:9870'\n```\n\nUse stable connection ids in DAG code:\n\n- `hdfs_default` for `HdfsSensor`, `HdfsRegexSensor`, or `HDFSHook`\n- `webhdfs_default` for `WebHDFSHook`\n\nKeep usernames, passwords, Kerberos settings, and any cluster-specific extras in the Airflow connection layer or your secrets backend.\n\n## Wait For Files With Sensors\n\nUse `HdfsSensor` when a downstream task should not run until a known path exists.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG\nfrom airflow.providers.apache.hdfs.sensors.hdfs import HdfsSensor, HdfsRegexSensor\n\nwith DAG(\n    dag_id=\"hdfs_wait_for_inputs\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"hdfs\"],\n):\n    wait_for_success = HdfsSensor(\n        task_id=\"wait_for_success\",\n        filepath=\"/data/landing/orders/_SUCCESS\",\n        hdfs_conn_id=\"hdfs_default\",\n    )\n\n    wait_for_parquet = HdfsRegexSensor(\n        task_id=\"wait_for_parquet\",\n        filepath=\"/data/landing/orders/2026-03-12\",\n        regex=r\".*\\.parquet$\",\n        hdfs_conn_id=\"hdfs_default\",\n    )\n\n    wait_for_success >> wait_for_parquet\n```\n\nUse this pattern when an upstream Spark, Hadoop, or batch job writes a completion marker or drops files into a partitioned directory before the rest of the DAG should continue.\n\n## Use `WebHDFSHook` Inside Python Tasks\n\nWhen you need custom file operations instead of a sensor, create a `WebHDFSHook`, get the client, and call the WebHDFS client methods directly.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import dag, task\nfrom airflow.providers.apache.hdfs.hooks.webhdfs import WebHDFSHook\n\n@dag(\n    dag_id=\"webhdfs_inspect_and_upload\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"webhdfs\"],\n)\ndef webhdfs_inspect_and_upload():\n    @task()\n    def inspect_hdfs() -> dict[str, object]:\n        hook = WebHDFSHook(webhdfs_conn_id=\"webhdfs_default\")\n        client = hook.get_conn()\n\n        exists = client.status(\"/data/landing/orders.csv\", strict=False) is not None\n        listing = client.list(\"/data/landing\")\n\n        return {\n            \"exists\": exists,\n            \"listing\": listing,\n        }\n\n    @task()\n    def upload_file() -> None:\n        hook = WebHDFSHook(webhdfs_conn_id=\"webhdfs_default\")\n        client = hook.get_conn()\n\n        client.upload(\n            \"/data/landing/orders.csv\",\n            \"/opt/airflow/dags/data/orders.csv\",\n            overwrite=True,\n        )\n\n    inspect_hdfs() >> upload_file()\n\nwebhdfs_inspect_and_upload()\n```\n\nThe important flow is:\n\n1. create the hook with the Airflow connection id\n2. call `get_conn()`\n3. use the returned WebHDFS client for operations such as `status`, `list`, `upload`, or `download`\n\n## Use `HDFSHook` When A Task Needs The HDFS Client\n\nIf your Airflow environment uses the classic HDFS connection type, instantiate `HDFSHook` with an HDFS connection id and then work through the returned client object.\n\n```python\nfrom airflow.providers.apache.hdfs.hooks.hdfs import HDFSHook\n\nhook = HDFSHook(hdfs_conn_id=\"hdfs_default\")\nclient = hook.get_conn()\n```\n\nUse this pattern when the worker can reach the cluster over the standard HDFS interface and your DAG code needs direct HDFS client behavior instead of the WebHDFS REST endpoint.\n\n## Common Patterns\n\n- Keep the connection id stable across DAGs so sensors and hooks all point at the same HDFS cluster configuration.\n- Prefer a completion marker such as `_SUCCESS` over guessing with arbitrary sleep delays.\n- Keep DAG code focused on paths and task logic; keep auth, hostnames, and port details in Airflow connections.\n- Use sensors for readiness checks and hooks for custom file operations.\n\n## Pitfalls\n\n- This provider extends Airflow; it does not replace `apache-airflow`.\n- Install the provider everywhere DAG code runs. Import errors usually mean one worker image or service is missing the package.\n- An Airflow connection that works from the webserver container can still fail on workers if they do not have network access to the NameNode or HDFS service.\n- Use `WebHDFSHook` only when the cluster actually exposes a WebHDFS endpoint. Not every HDFS deployment does.\n- Keep credentials and Kerberos-related configuration in connections or secret backends instead of embedding them in DAG source files.\n\n## When To Reach For The Provider\n\nUse `apache-airflow-providers-apache-hdfs` when Airflow should orchestrate HDFS-related checks or file movement as DAG tasks. If you are writing a regular Python application instead of an Airflow DAG or plugin, use a dedicated HDFS client library directly rather than importing Airflow hooks.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/`\n- HDFS connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/connections/hdfs.html`\n- WebHDFS connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/connections/webhdfs.html`\n- `HDFSHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/_api/airflow/providers/apache/hdfs/hooks/hdfs/index.html`\n- `WebHDFSHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/_api/airflow/providers/apache/hdfs/hooks/webhdfs/index.html`\n- HDFS sensor API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hdfs/stable/_api/airflow/providers/apache/hdfs/sensors/hdfs/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-hdfs/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-hive/python/DOC.md",
    "content": "---\nname: providers-apache-hive\ndescription: \"Apache Airflow Hive provider for Hive CLI, HiveServer2, and metastore-driven DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,hive,hiveserver2,metastore,dag,python\"\n---\n\n# apache-airflow-providers-apache-hive\n\nUse `apache-airflow-providers-apache-hive` when an Airflow DAG needs to run Hive SQL, wait for Hive partitions to appear, or read Hive metadata from Python task code.\n\nThis package is an Airflow provider, not a standalone Hive client for ordinary Python applications.\n\nThis guide targets provider version `9.3.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as `apache-airflow`. In practice, that means the scheduler, webserver, and every worker that imports DAG code must have the provider available.\n\nPin Airflow and the provider together, and use the Airflow constraints file for your Airflow version:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"9.3.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-hive==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\n## Choose The Right Interface\n\nThis provider exposes three common integration paths:\n\n- `HiveOperator` and `HiveCliHook`: run HQL through the Hive CLI or Beeline from an Airflow task\n- `HivePartitionSensor` and metastore hooks: wait for partitions and inspect table metadata through the Hive metastore\n- `HiveServer2Hook`: query Hive from Python task code over HiveServer2\n\nMost DAGs use one of these patterns:\n\n- run HQL with `HiveOperator`\n- wait for a partition with `HivePartitionSensor`\n- inspect table state with `HiveMetastoreHook`\n\n## Configure Airflow Connections\n\nKeep hostnames, usernames, Kerberos details, and SSL settings in Airflow connections instead of hard-coding them in DAG files.\n\nTypical connection ids used by this provider:\n\n- `hive_cli_default` for `HiveOperator` and `HiveCliHook`\n- `hiveserver2_default` for `HiveServer2Hook`\n- `metastore_default` for metastore hooks and partition sensors\n\nExample environment-variable connections:\n\n```bash\nexport AIRFLOW_CONN_HIVE_CLI_DEFAULT='{\"conn_type\":\"hive_cli\",\"host\":\"hs2.example.com\",\"port\":10000,\"login\":\"airflow\",\"schema\":\"default\",\"extra\":{\"use_beeline\":true}}'\n\nexport AIRFLOW_CONN_HIVESERVER2_DEFAULT='{\"conn_type\":\"hiveserver2\",\"host\":\"hs2.example.com\",\"port\":10000,\"login\":\"airflow\",\"schema\":\"default\"}'\n\nexport AIRFLOW_CONN_METASTORE_DEFAULT='{\"conn_type\":\"hive_metastore\",\"host\":\"metastore.example.com\",\"port\":9083}'\n```\n\nIf your cluster uses Kerberos, SSL, LDAP, or custom Beeline options, put those values in the connection extras rather than embedding them in Python code.\n\n## Run Hive SQL In A DAG\n\nUse `HiveOperator` when the task should execute HQL as part of the DAG.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.hive.operators.hive import HiveOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"hive_load_daily_partition\",\n    start_date=datetime(2026, 1, 1),\n    schedule=\"@daily\",\n    catchup=False,\n) as dag:\n    create_table = HiveOperator(\n        task_id=\"create_table\",\n        hive_cli_conn_id=\"hive_cli_default\",\n        hql=\"\"\"\n        CREATE TABLE IF NOT EXISTS analytics.events (\n            user_id STRING,\n            event_name STRING\n        )\n        PARTITIONED BY (ds STRING)\n        STORED AS PARQUET\n        \"\"\",\n    )\n\n    load_partition = HiveOperator(\n        task_id=\"load_partition\",\n        hive_cli_conn_id=\"hive_cli_default\",\n        hql=\"\"\"\n        INSERT OVERWRITE TABLE analytics.events PARTITION (ds='${hiveconf:ds}')\n        SELECT user_id, event_name\n        FROM staging.events_raw\n        WHERE ds='${hiveconf:ds}'\n        \"\"\",\n        hiveconfs={\"ds\": \"{{ ds }}\"},\n    )\n\n    create_table >> load_partition\n```\n\nUse `hiveconfs` when you want Airflow templating to feed values into HQL without string-concatenating SQL in Python.\n\n## Wait For A Partition\n\nUse `HivePartitionSensor` when downstream tasks should not run until the metastore reports a specific partition.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.hive.sensors.hive_partition import HivePartitionSensor\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"wait_for_hive_partition\",\n    start_date=datetime(2026, 1, 1),\n    schedule=\"@daily\",\n    catchup=False,\n) as dag:\n    wait_for_partition = HivePartitionSensor(\n        task_id=\"wait_for_partition\",\n        table=\"analytics.events\",\n        partition=\"ds='{{ ds }}'\",\n        metastore_conn_id=\"metastore_default\",\n        poke_interval=60,\n        timeout=60 * 60,\n    )\n```\n\nUse this pattern when another system publishes Hive partitions and your DAG should continue only after the partition is visible in the metastore.\n\n## Read Metadata From Python Tasks\n\nUse `HiveMetastoreHook` when task code needs to inspect tables or partitions instead of only waiting for them.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.hive.hooks.hive import HiveMetastoreHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"inspect_hive_partitions\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def print_latest_partition() -> str | None:\n        hook = HiveMetastoreHook(metastore_conn_id=\"metastore_default\")\n        latest = hook.max_partition(\"analytics\", \"events\", field=\"ds\")\n        print(f\"latest partition: {latest}\")\n        return latest\n\n    print_latest_partition()\n```\n\nThis is a good fit for branch logic, audits, or sanity checks before you launch heavier downstream work.\n\n## Query Through HiveServer2 From Python\n\nUse `HiveServer2Hook` when a Python task needs to fetch rows from Hive instead of submitting HQL through the CLI.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.hive.hooks.hive import HiveServer2Hook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"query_hiveserver2\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_counts() -> None:\n        hook = HiveServer2Hook(\n            hiveserver2_conn_id=\"hiveserver2_default\",\n            schema=\"analytics\",\n        )\n\n        rows = hook.get_records(\n            \"\"\"\n            SELECT ds, COUNT(*) AS row_count\n            FROM events\n            GROUP BY ds\n            ORDER BY ds DESC\n            LIMIT 7\n            \"\"\"\n        )\n\n        for ds, row_count in rows:\n            print(ds, row_count)\n\n    read_counts()\n```\n\nUse this for small result sets and control-flow decisions. For large data movement, keep the work in Hive SQL tasks instead of pulling big result sets through Python workers.\n\n## Important Notes\n\n- `HiveOperator` and `HiveCliHook` run the local Hive CLI or Beeline from the worker, so the binary must exist in the worker image and be on `PATH`.\n- If you use Beeline, set the connection to use Beeline and make sure the worker also has the JDBC driver and any required cluster client configuration.\n- `HivePartitionSensor` and `HiveMetastoreHook` talk to the Hive metastore, not HiveServer2. A working query connection does not guarantee the metastore connection is correct.\n- Install the provider everywhere DAG code is imported. One missing worker image is enough to cause `ModuleNotFoundError` during task execution.\n- Put auth and cluster-specific options in Airflow connections or your secrets backend, not in DAG source files.\n\n## When To Reach For This Provider\n\nUse `apache-airflow-providers-apache-hive` when Airflow should orchestrate Hive work as DAG tasks. If you are writing a regular Python application outside Airflow, use a dedicated Hive client directly instead of importing Airflow hooks and operators.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hive/stable/`\n- Hive CLI connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hive/stable/connections/hive_cli.html`\n- HiveServer2 connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hive/stable/connections/hiveserver2.html`\n- Hive metastore connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hive/stable/connections/hive_metastore.html`\n- Operator and hook API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-hive/stable/_api/airflow/providers/apache/hive/`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-hive/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-impala/python/DOC.md",
    "content": "---\nname: providers-apache-impala\ndescription: \"Apache Airflow Impala provider for Airflow-managed Impala connections, SQL tasks, and hook-based queries\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,impala,sql,dag,python\"\n---\n\n# apache-airflow-providers-apache-impala\n\nUse `apache-airflow-providers-apache-impala` when an Airflow DAG needs to execute SQL against Apache Impala through an Airflow connection or open an Impala DB-API connection from task code with `ImpalaHook`.\n\nThis package is an Airflow provider, not a standalone Impala client for ordinary Python applications.\n\nThis guide targets provider version `1.9.0`.\n\n## Install\n\nInstall the provider into the same Python environment as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-apache-impala==1.9.0\"\n```\n\nIf you manage Airflow and providers together, pin both in the same command so `pip` does not drift your Airflow core version:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-impala==1.9.0\"\n```\n\nProvider requirements published by Apache Airflow:\n\n- Apache Airflow `>=2.11.0`\n- Python `>=3.10`\n- `impyla>=0.22.0,<1.0`\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"apache-airflow-providers-apache-impala[kerberos]==1.9.0\"\npython -m pip install \"apache-airflow-providers-apache-impala[sqlalchemy]==1.9.0\"\n```\n\nUse the `kerberos` extra if your Impala environment authenticates with Kerberos. Use the `sqlalchemy` extra only if you need SQLAlchemy URL support from the hook.\n\n## Choose The Right Interface\n\nThis provider exposes two practical entry points:\n\n- `SQLExecuteQueryOperator`: run Impala SQL as a normal Airflow task\n- `ImpalaHook`: open an Impala connection inside Python task code\n\nFor most DAGs, start with `SQLExecuteQueryOperator`. Reach for `ImpalaHook` only when later task logic needs to inspect rows in Python.\n\n## Configure The Airflow Connection\n\nThe provider defines an Airflow connection type named `impala`. The default connection id is `impala_default`.\n\nYou can create it in the Airflow UI, with the Airflow CLI, or with an environment variable. A JSON environment variable is the least error-prone way to carry host, port, credentials, and extras together:\n\n```bash\nexport AIRFLOW_CONN_IMPALA_WAREHOUSE='{\n  \"conn_type\": \"impala\",\n  \"host\": \"impala.example.com\",\n  \"port\": 21050,\n  \"login\": \"airflow\",\n  \"password\": \"secret\",\n  \"schema\": \"analytics\",\n  \"extra\": {\n    \"auth\": \"NOSASL\",\n    \"use_ssl\": false\n  }\n}'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `impala_warehouse`\n- `SQLExecuteQueryOperator` uses `conn_id=\"impala_warehouse\"`\n- `ImpalaHook` uses `impala_conn_id=\"impala_warehouse\"`\n\nImportant connection behavior from the provider docs and hook source:\n\n- connection extras are forwarded to `impyla.dbapi.connect(...)`\n- operator keyword arguments such as `schema`, `login`, or `password` override values from the stored connection\n- if you define connections with `AIRFLOW_CONN_*`, they are available at runtime but do not show up in the Airflow UI or `airflow connections list`\n\n## Run SQL In A DAG\n\nThe provider docs use `SQLExecuteQueryOperator` for Impala tasks.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"impala_sql_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"impala_warehouse\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS analytics.customers (\n            customer_id BIGINT,\n            email STRING\n        )\n        STORED AS PARQUET\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"impala_warehouse\",\n        sql=\"\"\"\n        INSERT INTO analytics.customers (customer_id, email)\n        VALUES (1, 'alice@example.com'), (2, 'bob@example.com')\n        \"\"\",\n    )\n\n    read_rows = SQLExecuteQueryOperator(\n        task_id=\"read_rows\",\n        conn_id=\"impala_warehouse\",\n        sql=\"\"\"\n        SELECT customer_id, email\n        FROM analytics.customers\n        ORDER BY customer_id\n        LIMIT 10\n        \"\"\",\n    )\n\n    create_table >> insert_rows >> read_rows\n```\n\nThis is the normal pattern when Airflow should treat the Impala statement itself as the task boundary.\n\n## Query Impala From Python Tasks\n\nUse `ImpalaHook` when Python task code needs an actual DB-API connection.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.impala.hooks.impala import ImpalaHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"impala_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def fetch_recent_counts() -> list[tuple[str, int]]:\n        hook = ImpalaHook(impala_conn_id=\"impala_warehouse\")\n        conn = hook.get_conn()\n        cursor = conn.cursor()\n\n        try:\n            cursor.execute(\n                \"\"\"\n                SELECT ds, COUNT(*) AS row_count\n                FROM analytics.events\n                GROUP BY ds\n                ORDER BY ds DESC\n                LIMIT 7\n                \"\"\"\n            )\n            return cursor.fetchall()\n        finally:\n            cursor.close()\n            conn.close()\n\n    fetch_recent_counts()\n```\n\nThis keeps connection setup in Airflow while still letting task code branch on query results or hand small result sets to later tasks.\n\n## Build A SQLAlchemy URL\n\nIf your task code needs a SQLAlchemy URL instead of a live connection, install the `sqlalchemy` extra and use the hook helper:\n\n```python\nfrom airflow.providers.apache.impala.hooks.impala import ImpalaHook\n\nhook = ImpalaHook(impala_conn_id=\"impala_warehouse\")\nprint(hook.get_uri())\n```\n\nThe hook raises a `ValueError` if the stored connection is missing `host` or `login`, so keep those fields set on the Airflow connection.\n\n## Important Notes\n\n- Use `SQLExecuteQueryOperator` for new DAG code. The provider docs explicitly point users to the common SQL operator rather than a dedicated Impala operator.\n- Keep auth and transport settings such as `auth` and `use_ssl` on the Airflow connection, not hard-coded in DAG files.\n- Use `ImpalaHook` only for small, Python-driven result handling. If the work is just SQL execution, keep it as an operator task.\n- If you rely on `AIRFLOW_CONN_*` variables, remember that they are runtime-only configuration and will not appear in the UI for manual inspection.\n- `get_uri()` and `sqlalchemy_url` need the optional `sqlalchemy` dependency; plain query execution through `get_conn()` does not.\n\n## Version Notes\n\n- Apache Airflow's provider docs and PyPI both show `1.9.0` as the current release on March 13, 2026.\n- The `1.9.0` changelog notes hook-level lineage support for SQL hooks.\n- The `1.8.1` changelog made SQLAlchemy an optional dependency for this provider. If you upgrade older DAG utilities that called `get_uri()` or `sqlalchemy_url`, install the `sqlalchemy` extra explicitly.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/index.html`\n- Impala connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/connections/impala.html`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/operators.html`\n- `ImpalaHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/_api/airflow/providers/apache/impala/hooks/impala/index.html`\n- `ImpalaHook` source view: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/_modules/airflow/providers/apache/impala/hooks/impala.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-apache-impala/stable/changelog.html`\n- Managing connections: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-impala/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-kafka/python/DOC.md",
    "content": "---\nname: providers-apache-kafka\ndescription: \"Apache Airflow Kafka provider for producing to topics, consuming messages, and deferring on Kafka events from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,kafka,apache-kafka,python,dag,streaming\"\n---\n\n# apache-airflow-providers-apache-kafka\n\nUse `apache-airflow-providers-apache-kafka` when an Airflow DAG needs to publish messages to Kafka, consume messages from one or more topics, or pause until a matching Kafka message arrives.\n\nThis guide targets provider version `1.12.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-apache-kafka==1.12.0\"\n```\n\nUpstream lists `apache-airflow>=2.11.0` as the minimum supported Airflow version for this provider.\n\nIf you plan to use the common message-queue integration for asset-driven scheduling, install the `common.messaging` extra:\n\n```bash\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-apache-kafka[common.messaging]==1.12.0\"\n```\n\nThis package extends Airflow. You do not create a standalone Python client object for it. Instead, you define an Airflow connection of type `kafka` and instantiate provider operators, hooks, or sensors inside DAG code.\n\nInstall the provider anywhere Airflow imports or runs DAG code:\n\n- scheduler\n- workers or task execution image\n- any other runtime that imports DAG modules\n\n## Prerequisites\n\nBefore using the provider, make sure your runtime already has:\n\n- a working Airflow deployment\n- network access from the Airflow runtime to your Kafka brokers\n- Kafka topics that already exist, or an explicit task that creates them\n- a Kafka connection config that at minimum sets `bootstrap.servers`\n\nFor consumer and sensor tasks, the official system tests use separate Kafka connection ids with consumer-specific settings such as `group.id`, `enable.auto.commit`, and `auto.offset.reset`. Follow the same pattern when producer and consumer settings differ.\n\n## Configure The Airflow Kafka Connection\n\nThe provider uses Airflow connection type `kafka`. By default, hooks and operators use `kafka_default`, but the official docs describe that default connection as minimal and only suitable for trivial testing.\n\nKafka connection settings live in the connection's `extra` field as a JSON-serializable config dict. In the Airflow UI, that field is labeled `Config Dict`.\n\nEnvironment variables are the cleanest way to set this up in local development and containerized deployments. Airflow reads connections from `AIRFLOW_CONN_{CONN_ID}` and accepts JSON values.\n\nExample producer connection:\n\n```bash\nexport AIRFLOW_CONN_KAFKA_DEFAULT='{\n  \"conn_type\": \"kafka\",\n  \"extra\": {\n    \"bootstrap.servers\": \"broker-1:9092,broker-2:9092\",\n    \"security.protocol\": \"SASL_SSL\",\n    \"sasl.mechanisms\": \"PLAIN\",\n    \"sasl.username\": \"airflow\",\n    \"sasl.password\": \"secret\"\n  }\n}'\n```\n\nExample consumer connection with explicit offset handling:\n\n```bash\nexport AIRFLOW_CONN_ORDERS_CONSUMER='{\n  \"conn_type\": \"kafka\",\n  \"extra\": {\n    \"bootstrap.servers\": \"broker-1:9092,broker-2:9092\",\n    \"group.id\": \"orders-consumer\",\n    \"auto.offset.reset\": \"earliest\",\n    \"enable.auto.commit\": false\n  }\n}'\n```\n\nYou can also create the same connection from the CLI:\n\n```bash\nairflow connections add 'orders_consumer' \\\n  --conn-json '{\n    \"conn_type\": \"kafka\",\n    \"extra\": {\n      \"bootstrap.servers\": \"broker-1:9092,broker-2:9092\",\n      \"group.id\": \"orders-consumer\",\n      \"auto.offset.reset\": \"earliest\",\n      \"enable.auto.commit\": false\n    }\n  }'\n```\n\nThe provider forwards those config values to `confluent-kafka`, so broker auth and client tuning options also belong in `extra`.\n\n## Produce Messages To A Topic\n\n`ProduceToTopicOperator` sends records to a topic. Its `producer_function` can be a callable or an importable string, and it must yield key/value pairs.\n\n```python\nfrom __future__ import annotations\n\nimport json\n\nfrom airflow import DAG\nfrom airflow.providers.apache.kafka.operators.produce import ProduceToTopicOperator\nfrom pendulum import datetime\n\n\ndef build_messages():\n    for order_id in range(3):\n        key = json.dumps({\"order_id\": order_id})\n        value = json.dumps({\"order_id\": order_id, \"status\": \"paid\"})\n        yield key, value\n\n\nwith DAG(\n    dag_id=\"kafka_produce_orders\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"kafka\"],\n) as dag:\n    produce_orders = ProduceToTopicOperator(\n        task_id=\"produce_orders\",\n        kafka_config_id=\"kafka_default\",\n        topic=\"orders\",\n        producer_function=build_messages,\n    )\n```\n\nImportant operator arguments:\n\n- `topic`: destination Kafka topic\n- `kafka_config_id`: Airflow Kafka connection id, default `kafka_default`\n- `producer_function`: callable that yields `(key, value)` pairs\n- `delivery_callback`: optional import path for a delivery callback\n- `synchronous`: defaults to `True`\n\n## Consume Messages From One Or More Topics\n\n`ConsumeFromTopicOperator` subscribes to one or more topics, polls in batches, and calls either `apply_function` for each message or `apply_function_batch` for each batch.\n\n```python\nfrom __future__ import annotations\n\nimport json\n\nfrom airflow import DAG\nfrom airflow.providers.apache.kafka.operators.consume import ConsumeFromTopicOperator\nfrom pendulum import datetime\n\n\ndef process_message(message):\n    payload = json.loads(message.value())\n    print(\n        f\"topic={message.topic()} offset={message.offset()} key={message.key()} payload={payload}\"\n    )\n\n\nwith DAG(\n    dag_id=\"kafka_consume_orders\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"kafka\"],\n) as dag:\n    consume_orders = ConsumeFromTopicOperator(\n        task_id=\"consume_orders\",\n        kafka_config_id=\"orders_consumer\",\n        topics=[\"orders\"],\n        apply_function=\"kafka_consume_orders.process_message\",\n        commit_cadence=\"end_of_operator\",\n        max_messages=100,\n        max_batch_size=10,\n        poll_timeout=30,\n    )\n```\n\nThe supported commit cadences are:\n\n- `never`\n- `end_of_batch`\n- `end_of_operator`\n\nUse `apply_function_batch` instead of `apply_function` when your processing logic needs to see a whole batch at once. Do not set both on the same operator.\n\n## Wait Until A Matching Kafka Message Arrives\n\n`AwaitMessageSensor` is deferrable. It consumes messages until your `apply_function` returns a truthy value, then resumes the task and optionally pushes the returned data to XCom.\n\n```python\nfrom __future__ import annotations\n\nimport json\n\nfrom airflow import DAG\nfrom airflow.providers.apache.kafka.sensors.kafka import AwaitMessageSensor\nfrom pendulum import datetime\n\n\ndef is_paid_event(message):\n    payload = json.loads(message.value())\n    if payload.get(\"status\") == \"paid\":\n        return payload\n    return None\n\n\nwith DAG(\n    dag_id=\"kafka_wait_for_paid_order\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"kafka\"],\n) as dag:\n    wait_for_paid_order = AwaitMessageSensor(\n        task_id=\"wait_for_paid_order\",\n        kafka_config_id=\"orders_consumer\",\n        topics=[\"orders\"],\n        apply_function=\"kafka_wait_for_paid_order.is_paid_event\",\n        poll_timeout=1,\n        poll_interval=5,\n        xcom_push_key=\"matched_event\",\n    )\n```\n\nFor a long-running listener that handles each positive event and then keeps waiting, use `AwaitMessageTriggerFunctionSensor`:\n\n```python\nfrom airflow.providers.apache.kafka.sensors.kafka import AwaitMessageTriggerFunctionSensor\n\n\ndef on_event(event, **context):\n    print(f\"matched event: {event}\")\n\n\nlisten_for_orders = AwaitMessageTriggerFunctionSensor(\n    task_id=\"listen_for_orders\",\n    kafka_config_id=\"orders_consumer\",\n    topics=[\"orders\"],\n    apply_function=\"kafka_wait_for_paid_order.is_paid_event\",\n    event_triggered_function=on_event,\n)\n```\n\nThe Kafka sensors are deferrable implementations. The inherited `poke_interval` and `mode` arguments are documented as unused here; use `poll_timeout` and `poll_interval` instead.\n\n## Optional: Create Topics From Airflow Code\n\nIf you need an admin task to create a topic before producing messages, use `KafkaAdminClientHook`:\n\n```python\nfrom airflow.providers.apache.kafka.hooks.client import KafkaAdminClientHook\n\n\ndef create_orders_topic():\n    hook = KafkaAdminClientHook(kafka_config_id=\"kafka_default\")\n    hook.create_topic([(\"orders\", 3, 1)])\n```\n\nThe hook expects a list of `(topic_name, num_partitions, replication_factor)` tuples.\n\n## Common Pitfalls\n\n- `kafka_default` is not a real production configuration. Set your own connection id or replace its config before using it.\n- `bootstrap.servers` must be present in the Kafka connection config or most hooks and operators will reject it.\n- Keep Kafka broker settings in the Airflow connection `extra` or `Config Dict`, not in DAG code.\n- Install the provider in every Airflow image that imports DAGs or executes tasks. A missing package on workers causes import failures even if the scheduler has it.\n- `ConsumeFromTopicOperator` accepts either `apply_function` or `apply_function_batch`, not both.\n- For sensors, `apply_function` must be an importable dot-notation string.\n- When you want Airflow to control offset commits with `commit_cadence`, use a consumer connection that disables Kafka auto-commit, following the official system-test pattern.\n- The provider does not start Kafka brokers or create a general-purpose standalone client SDK for your app; it only adds Airflow hooks, operators, sensors, and triggers around Kafka.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-kafka` version `1.12.0`.\n- The provider installs classes under the `airflow.providers.apache.kafka` package.\n- Version `1.12.0` requires Apache Airflow `>=2.11.0`.\n- The provider depends on `confluent-kafka>=2.6.0`.\n- The `common.messaging` extra is only needed when you use the common message-queue integration such as `KafkaMessageQueueTrigger` and `MessageQueueTrigger`.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/`\n- Package index and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/index.html`\n- Kafka connection guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/connections/kafka.html`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/operators/index.html`\n- `ProduceToTopicOperator` API: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/_api/airflow/providers/apache/kafka/operators/produce/index.html`\n- `ConsumeFromTopicOperator` API: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/_api/airflow/providers/apache/kafka/operators/consume/index.html`\n- Sensors API: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/_api/airflow/providers/apache/kafka/sensors/kafka/index.html`\n- Hooks guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/hooks.html`\n- Message queues guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/message-queues/index.html`\n- Airflow connection management: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- Example DAG source: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/_modules/tests/system/apache/kafka/example_dag_hello_kafka.html`\n- Event-listener example source: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kafka/stable/_modules/tests/system/apache/kafka/example_dag_event_listener.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-apache-kafka/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-kylin/python/DOC.md",
    "content": "---\nname: providers-apache-kylin\ndescription: \"Apache Airflow Kylin provider for running Kylin SQL and cube jobs from DAGs with Airflow-managed connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.10.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,kylin,apache-kylin,olap,dag,python\"\n---\n\n# apache-airflow-providers-apache-kylin\n\nUse `apache-airflow-providers-apache-kylin` when an Airflow DAG needs to run Kylin SQL or trigger cube jobs against an Apache Kylin project through an Airflow connection.\n\nThis package is an Airflow provider, not a standalone Kylin client for ordinary Python applications.\n\nThis guide targets provider version `3.10.2`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as `apache-airflow`. In practice, that means the scheduler, webserver, and every worker that imports DAG code must have the provider available.\n\nPyPI metadata for this package lists these minimum requirements:\n\n- Python `>=3.10`\n- `apache-airflow >=2.10.0`\n\nFor a fresh Airflow environment, install Airflow core first using the Airflow installation guide. Then add the Kylin provider alongside your pinned Airflow version:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\nPROVIDER_VERSION=\"3.10.2\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-kylin==${PROVIDER_VERSION}\"\n```\n\nYou do not initialize a separate SDK client package directly. Airflow imports the provider classes from your DAG code and uses an Airflow connection to reach Kylin.\n\n## Prerequisites\n\nBefore using the provider, make sure your runtime already has:\n\n- an Airflow deployment that can import this provider\n- network access from Airflow task runtime to your Kylin server\n- a Kylin project name and the cube or model names your DAG will operate on\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `kylin`. The default connection id used by the hook and operator is `kylin_default`.\n\nThe Kylin connection docs map the connection fields like this:\n\n- Host: Kylin server hostname\n- Project Name: Kylin project to use\n- Username and Password: Kylin credentials\n- Extra: optional JSON such as `{\"timeout\": 60, \"is_debug\": 1}`\n\nIf you prefer environment variables, Airflow supports `AIRFLOW_CONN_*` connection URIs. The provider docs show the Kylin DSN format as:\n\n```bash\nexport AIRFLOW_CONN_KYLIN_DEFAULT='kylin://ADMIN:KYLIN@kylin.example.com/learn_kylin?timeout=60&is_debug=1'\n```\n\nUse the Airflow UI or `airflow connections get kylin_default` to confirm the connection resolves the host, project, and optional extras you expect.\n\nKeep credentials and timeout/debug settings on the Airflow connection instead of hard-coding them in DAG files.\n\n## Run Kylin SQL In A DAG\n\nUse `SQLExecuteQueryOperator` when the task should run SQL through the Kylin connection.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"kylin_sql_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    show_tables = SQLExecuteQueryOperator(\n        task_id=\"show_tables\",\n        conn_id=\"kylin_default\",\n        sql=\"SHOW TABLES\",\n    )\n```\n\nUse this pattern for SQL queries and lightweight administrative statements that should run as normal Airflow tasks.\n\n## Trigger A Cube Job\n\nUse `KylinCubeOperator` when the task should trigger a cube job such as `build`, `merge`, or `refresh`.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.kylin.operators.kylin_cube import KylinCubeOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"kylin_cube_build_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    build_cube = KylinCubeOperator(\n        task_id=\"build_cube\",\n        kylin_conn_id=\"kylin_default\",\n        project=\"learn_kylin\",\n        cube=\"kylin_sales_cube\",\n        command=\"build\",\n        start_time=\"{{ data_interval_start.int_timestamp * 1000 }}\",\n        end_time=\"{{ data_interval_end.int_timestamp * 1000 }}\",\n        is_track_job=True,\n        interval=10,\n        timeout=600,\n    )\n```\n\nImportant operator arguments:\n\n- `project`: Kylin project name\n- `cube`: cube or model identifier to operate on\n- `command`: job action such as `build`, `merge`, `refresh`, `disable`, or `enable`\n- `start_time` and `end_time`: time range for commands that operate on a segment window\n- `is_track_job`: when `True`, the Airflow task waits until the Kylin job ends, errors, or times out\n- `interval` and `timeout`: polling controls used when tracking the job\n\nThe API docs also expose `offset_start` and `offset_end` for streaming-oriented commands.\n\n## Use The Hook In Python Tasks\n\nUse `KylinHook` when a Python task needs to talk to Kylin directly instead of using a prebuilt operator.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.kylin.hooks.kylin import KylinHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"kylin_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def print_job_status(job_id: str) -> None:\n        hook = KylinHook(\n            kylin_conn_id=\"kylin_default\",\n            project=\"learn_kylin\",\n        )\n\n        status = hook.get_job_status(job_id)\n        print(status)\n\n    print_job_status(\"your-kylin-job-id\")\n```\n\nThe provider hook exposes methods documented in the API reference, including:\n\n- `get_conn()`\n- `cube_run(...)`\n- `get_job_status(job_id)`\n- `stop_job(job_id)`\n- `get_job_info()`\n\nUse the hook for small control-flow decisions and metadata lookups. For normal DAG orchestration, prefer `SQLExecuteQueryOperator` or `KylinCubeOperator`.\n\n## Important Notes\n\n- Install the provider everywhere Airflow parses or executes DAG code. One missing worker image is enough to cause `ModuleNotFoundError`.\n- The Kylin connection owns the host, project, credentials, and extras. Keep DAG code portable by passing only the connection id and task-specific values.\n- `KylinCubeOperator` can submit a job without waiting for completion. Set `is_track_job=True` if downstream tasks depend on the finished Kylin job.\n- `start_time` and `end_time` are passed through to the provider as segment boundaries. Keep them in the format your Kylin deployment expects; the provider docs demonstrate millisecond timestamps.\n- This provider orchestrates Kylin from Airflow. If you are writing a regular Python application outside Airflow, use a dedicated Kylin client or HTTP integration instead of importing Airflow hooks and operators.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-kylin` version `3.10.2`.\n- The official Airflow source tree publishes Kylin provider examples from the `providers-apache-kylin/3.10.2` branch, while some Airflow stable documentation pages for this provider still display `3.10.1` or `3.9.2` in their page chrome. Use the stable API pages for current hook and operator signatures, and re-check the package index before changing a production pin.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kylin/stable/`\n- Kylin connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kylin/stable/connections/kylin.html`\n- `KylinHook` API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kylin/stable/_api/airflow/providers/apache/kylin/hooks/kylin/index.html`\n- `KylinCubeOperator` API docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-kylin/stable/_api/airflow/providers/apache/kylin/operators/kylin_cube/index.html`\n- Example DAG: `https://github.com/apache/airflow/blob/providers-apache-kylin/3.10.2/providers/tests/system/apache/kylin/example_kylin_dag.py`\n- Airflow managing connections with environment variables: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-kylin/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-livy/python/DOC.md",
    "content": "---\nname: providers-apache-livy\ndescription: \"Apache Airflow provider for submitting and monitoring Apache Livy batch jobs from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,livy,spark,python,dag\"\n---\n\n# Apache Airflow Apache Livy Provider Guide\n\nUse `apache-airflow-providers-apache-livy` when an Airflow DAG should submit a Spark batch job to a Livy server over HTTP and optionally wait for that batch to finish.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone Livy client.\n- Put the Livy server URL and credentials on an Airflow `livy` connection, then keep DAG code focused on `file`, `args`, `conf`, and executor sizing.\n- Use `LivyOperator` for most DAGs. Use `LivySensor` only when you intentionally submit without polling and want a separate wait step.\n- Point `file`, `py_files`, `jars`, `files`, and `archives` at artifacts your Livy deployment can actually read.\n\n## Install\n\nThis provider requires Apache Airflow `>=2.11.0` and is versioned separately from Airflow core.\n\nInstall it into the same Python environment or container image that parses and runs your DAGs:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-apache-livy==4.5.3\"\n```\n\nIf you are creating a new Airflow environment from scratch, install Airflow first using the official Airflow installation guide, then add this provider.\n\nAfter installation, verify that Airflow sees the provider:\n\n```bash\nairflow providers list | grep -i livy\n```\n\nInstall the provider everywhere Airflow imports or executes DAG code:\n\n- scheduler\n- API server or webserver image, if it imports DAGs\n- workers or task execution image\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `livy`. The default connection id is `livy_default`.\n\nMinimal environment-variable form:\n\n```bash\nexport AIRFLOW_CONN_LIVY_DEFAULT='livy://livy-user:livy-password@livy.example.com:8998/http'\n```\n\nEquivalent Airflow UI fields:\n\n- **Connection Id:** `livy_default`\n- **Connection Type:** `livy`\n- **Host:** `livy.example.com`\n- **Port:** `8998`\n- **Login / Password:** Livy credentials if your server requires them\n- **Schema:** `http` or `https`\n\nThe connection also supports `headers` in Extra or in the URI query string. When you use the URI form, URL-encode reserved characters and JSON values.\n\nExample with a custom header:\n\n```bash\nexport AIRFLOW_CONN_LIVY_DEFAULT='livy://livy-user:livy-password@livy.example.com:8998/http?headers=%7B%22X-Requested-By%22%3A%22airflow%22%7D'\n```\n\nIf your Livy server is mounted behind a reverse proxy path such as `/livy`, pass that path with `livy_endpoint_prefix` on the operator or `endpoint_prefix` on the hook and sensor.\n\n## Submit A Batch Job With `LivyOperator`\n\n`LivyOperator` is the main entry point for this provider. It creates a Livy batch with the same fields exposed by Livy's batch REST API, including `file`, `args`, `class_name`, `jars`, `py_files`, `files`, `archives`, and Spark config in `conf`.\n\nMinimal PySpark batch example:\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.apache.livy.operators.livy import LivyOperator\n\nwith DAG(\n    dag_id=\"livy_batch_example\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"livy\"],\n) as dag:\n    submit_pi = LivyOperator(\n        task_id=\"submit_pi\",\n        livy_conn_id=\"livy_default\",\n        file=\"/opt/spark/jobs/pi.py\",\n        args=[\"1000\"],\n        conf={\n            \"spark.executor.memory\": \"2g\",\n            \"spark.executor.cores\": \"1\",\n        },\n        executor_memory=\"2g\",\n        executor_cores=1,\n        num_executors=2,\n        polling_interval=30,\n    )\n```\n\nThe arguments most DAGs need are:\n\n- `file`: required batch entrypoint accepted by Livy\n- `args`: positional arguments passed to the job\n- `conf`: Spark configuration sent with the batch request\n- `driver_memory`, `driver_cores`, `executor_memory`, `executor_cores`, `num_executors`: resource sizing\n- `polling_interval`: seconds between status checks; values `<=0` submit the batch and return immediately without polling\n- `livy_endpoint_prefix`: optional path prefix when Livy is not served from `/`\n\nWhen `polling_interval` is greater than zero, the operator waits for the batch to reach a terminal state. A successful batch returns normally. Terminal states such as `dead`, `error`, or `killed` fail the task.\n\n## Submit Now, Wait Later With `LivySensor`\n\nIf you want submission and waiting to be separate tasks, disable polling on the operator and pass the returned batch id into `LivySensor`.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.apache.livy.operators.livy import LivyOperator\nfrom airflow.providers.apache.livy.sensors.livy import LivySensor\n\nwith DAG(\n    dag_id=\"livy_async_batch_example\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    submit_batch = LivyOperator(\n        task_id=\"submit_batch\",\n        livy_conn_id=\"livy_default\",\n        file=\"/opt/spark/jobs/pi.py\",\n        args=[\"5000\"],\n        polling_interval=0,\n    )\n\n    wait_for_batch = LivySensor(\n        task_id=\"wait_for_batch\",\n        livy_conn_id=\"livy_default\",\n        batch_id=\"{{ ti.xcom_pull(task_ids='submit_batch') }}\",\n    )\n\n    submit_batch >> wait_for_batch\n```\n\n`batch_id` is a templated field, so a normal Jinja `xcom_pull` works.\n\n## Use `LivyHook` In Task Code\n\nUse `LivyHook` when task code needs direct control over batch submission, status checks, logs, or cancellation.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.apache.livy.hooks.livy import LivyHook\n\n\n@task\ndef inspect_batch(batch_id: int) -> dict[str, object]:\n    hook = LivyHook(\n        livy_conn_id=\"livy_default\",\n        endpoint_prefix=\"/livy\",\n    )\n\n    batch = hook.get_batch(batch_id)\n    state = hook.get_batch_state(batch_id)\n    logs = hook.get_batch_logs(\n        batch_id=batch_id,\n        log_start_position=0,\n        log_batch_size=20,\n    )\n\n    return {\n        \"app_id\": batch.get(\"appId\"),\n        \"state\": state.value,\n        \"log_lines\": logs.get(\"log\", []),\n    }\n```\n\nThe hook methods you will typically use are:\n\n- `post_batch(...)`: create a batch directly\n- `get_batch(batch_id)`: fetch batch metadata\n- `get_batch_state(batch_id)`: fetch only the current state\n- `get_batch_logs(batch_id, log_start_position=0, log_batch_size=100)`: fetch log pages\n- `delete_batch(batch_id)`: cancel a batch\n\nUse the operator for normal DAG tasks and the hook only when you need custom Python logic around the Livy API.\n\n## Common Workflow Pattern\n\nFor most deployments, the cleanest setup is:\n\n1. Create one Airflow `livy` connection per Livy environment.\n2. Keep authentication and custom headers on that connection.\n3. Submit batches with `LivyOperator`.\n4. Use `polling_interval=0` plus `LivySensor` only when you need an explicit submit/wait split.\n5. Use `LivyHook` for log inspection, custom retries, or cancellation logic inside Python tasks.\n\n## Pitfalls\n\n- Install the provider everywhere DAGs are parsed or run. Import errors usually mean one Airflow image is missing the package.\n- `file`, `jars`, `py_files`, `files`, and `archives` are resolved by Livy and Spark, not by your laptop or the scheduler.\n- If `polling_interval <= 0`, the operator only submits the batch and returns the Livy batch id. It does not wait for success.\n- `deferrable=True` requires a running Airflow triggerer. Without one, the task cannot defer correctly.\n- If your Livy server lives behind `/livy` or another path prefix, set `livy_endpoint_prefix` or `endpoint_prefix` explicitly.\n- The operator's kill path calls Livy's delete-batch endpoint for the current batch. That matters if you expect a Spark job to keep running after an Airflow task is cancelled or killed.\n- URL-encode usernames, passwords, and JSON header values when you build `AIRFLOW_CONN_LIVY_DEFAULT` by hand.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-apache-livy` version `4.5.3`.\n- The stable provider docs for `4.5.3` list Apache Airflow `2.11.0` as the minimum supported core version.\n- Provider packages have their own release cadence, so re-check the provider docs before changing Airflow core and provider versions independently.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/`\n- Package index and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/index.html`\n- Livy connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/connections.html`\n- `LivyOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/_api/airflow/providers/apache/livy/operators/livy/index.html`\n- `LivyHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/_api/airflow/providers/apache/livy/hooks/livy/index.html`\n- `LivySensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/_api/airflow/providers/apache/livy/sensors/livy/index.html`\n- Example DAG source: `https://airflow.apache.org/docs/apache-airflow-providers-apache-livy/stable/_modules/tests/system/apache/livy/example_livy.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- Apache Livy REST API: `https://livy.apache.org/docs/latest/rest-api.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-pig/python/DOC.md",
    "content": "---\nname: providers-apache-pig\ndescription: \"Apache Airflow Pig provider for running Pig Latin through the local pig CLI from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.8.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,pig,pig-latin,hadoop,dag,python\"\n---\n\n# apache-airflow-providers-apache-pig\n\nUse `apache-airflow-providers-apache-pig` when an Airflow DAG needs to run Pig Latin through the local `pig` command and track that execution as a normal Airflow task.\n\nThis package is an Airflow provider, not a standalone Pig client for ordinary Python applications.\n\nThis guide targets provider version `4.8.2`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment. Pin Airflow in the same command and use the matching constraints file.\n\n`apache-airflow-providers-apache-pig==4.8.2` requires `apache-airflow>=2.11.0`.\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.8.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-pig==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nInstall it anywhere Airflow imports or runs DAG code:\n\n- scheduler\n- webserver\n- workers or task-execution image\n\n## Prerequisites\n\nThis provider wraps the `pig` CLI. It does not install Apache Pig for you.\n\nBefore using it, make sure the runtime that executes the task already has:\n\n- Apache Pig installed\n- a working Java runtime\n- the `pig` executable on `PATH`\n- any local files, Hadoop config, or cluster client configuration that your Pig job needs\n\nThe Apache Pig getting-started docs use this basic shell setup:\n\n```bash\nexport JAVA_HOME=/path/to/jdk\nexport PIG_HOME=/path/to/pig\nexport PATH=\"${PIG_HOME}/bin:${PATH}\"\n```\n\nFor local development, Pig supports local mode:\n\n```bash\npig -x local\n```\n\nIn Airflow, you pass the same mode switch through `pig_opts`.\n\n## Configure The Airflow Connection\n\nThe operator and hook default to the Airflow connection id `pig_cli_default`.\n\nThe current hook only uses the connection id as an Airflow lookup anchor, so the simplest working setup is an environment-defined connection:\n\n```bash\nexport AIRFLOW_CONN_PIG_CLI_DEFAULT='{\"conn_type\":\"pig_cli\"}'\n```\n\nIf you prefer a different id, set it explicitly in DAG code:\n\n```python\nPigOperator(..., pig_cli_conn_id=\"my_pig\")\n```\n\nImportant version note:\n\n- Do not store `pig_properties` in the connection extras. Provider 4.x rejects that deprecated pattern. Pass `pig_properties` directly to `PigOperator` or `PigCliHook` instead.\n\n## Run An Inline Pig Script\n\nFor most DAGs, start with `PigOperator`.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.pig.operators.pig import PigOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"pig_wordcount_inline\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_pig = PigOperator(\n        task_id=\"run_pig\",\n        pig=\"\"\"\n        records = LOAD '/opt/airflow/dags/data/words.tsv'\n            USING PigStorage('\\\\t')\n            AS (word: chararray);\n\n        grouped = GROUP records BY word;\n\n        counts = FOREACH grouped GENERATE\n            group AS word,\n            COUNT(records) AS total;\n\n        STORE counts\n            INTO '/tmp/airflow-pig-output/{{ ds_nodash }}'\n            USING PigStorage('\\\\t');\n        \"\"\",\n        pig_cli_conn_id=\"pig_cli_default\",\n        pig_opts=\"-x local\",\n        pig_properties=[\n            \"-Dpig.tmpfilecompression=true\",\n        ],\n    )\n```\n\nThe main arguments you usually set are:\n\n- `pig`: the Pig Latin script to run\n- `pig_cli_conn_id`: Airflow connection id, usually `pig_cli_default`\n- `pig_opts`: extra CLI flags as a single space-separated string such as `-x local` or `-x tez`\n- `pig_properties`: extra `-D...` style properties as a list of strings\n\n## Run A File-Backed `.pig` Script\n\n`PigOperator` templates `.pig` and `.piglatin` files. Use that when you want the script stored as a separate file under your DAG directory.\n\nExample script file:\n\n```pig\n-- /opt/airflow/dags/pig/wordcount.pig\nrecords = LOAD '/opt/airflow/dags/data/words_${ds_nodash}.tsv'\n    USING PigStorage('\\t')\n    AS (word: chararray);\n\ngrouped = GROUP records BY word;\n\ncounts = FOREACH grouped GENERATE\n    group AS word,\n    COUNT(records) AS total;\n\nSTORE counts\n    INTO '/tmp/airflow-pig-output/${ds_nodash}'\n    USING PigStorage('\\t');\n```\n\nExample DAG task:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.pig.operators.pig import PigOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"pig_wordcount_file\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_script = PigOperator(\n        task_id=\"run_script\",\n        pig=\"/opt/airflow/dags/pig/wordcount.pig\",\n        pig_cli_conn_id=\"pig_cli_default\",\n        pigparams_jinja_translate=True,\n        pig_opts=\"-x local\",\n    )\n```\n\nSet `pigparams_jinja_translate=True` when your script already uses Pig-style `${name}` placeholders and you want Airflow to translate them to Jinja before execution.\n\n## Use `PigCliHook` In Python Task Code\n\nIf you need lower-level control from task code, instantiate `PigCliHook` directly and call `run_cli()`.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.pig.hooks.pig import PigCliHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"pig_hook_preview\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def preview_rows() -> None:\n        hook = PigCliHook(\n            pig_cli_conn_id=\"pig_cli_default\",\n            pig_properties=[\"-Dpig.tmpfilecompression=true\"],\n        )\n\n        output = hook.run_cli(\n            \"\"\"\n            rows = LOAD '/opt/airflow/dags/data/words.tsv'\n                USING PigStorage('\\\\t')\n                AS (word: chararray);\n            sample = LIMIT rows 5;\n            DUMP sample;\n            \"\"\",\n            pig_opts=\"-x local\",\n        )\n\n        print(output)\n\n    preview_rows()\n```\n\nUse the hook when task logic needs the CLI output as a Python string instead of letting `PigOperator` manage the whole task boundary.\n\n## Pitfalls\n\n- Install both the provider package and Apache Pig everywhere Airflow imports or runs DAGs. A single worker image missing either dependency is enough to fail a task.\n- Keep Pig script input and output paths absolute when possible. The hook runs `pig` from a temporary working directory, so relative paths can point somewhere unexpected.\n- `pig_opts` is one string passed to the CLI. `pig_properties` is a list of individual property strings. Do not swap those shapes.\n- The Airflow connection does not launch or proxy a remote Pig service. The worker runs the local `pig` command.\n- If you run against Hadoop or Tez instead of local mode, make sure the worker image already has the right cluster client configuration before the Airflow task starts.\n- Do not use connection extras for `pig_properties` on provider 4.x. That behavior was removed; set properties on the operator or hook call itself.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-pig` version `4.8.2`.\n- Provider packages are versioned independently from Apache Airflow core.\n- Upstream documents `apache-airflow>=2.11.0` for provider `4.8.2`.\n- The default connection id for both `PigOperator` and `PigCliHook` is `pig_cli_default`.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/index.html`\n- `PigOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/_api/airflow/providers/apache/pig/operators/pig/index.html`\n- `PigCliHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/_api/airflow/providers/apache/pig/hooks/pig/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/changelog.html`\n- Provider source API page: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pig/stable/_modules/airflow/providers/apache/pig/hooks/pig.html`\n- Airflow connection environment variables: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- Apache Pig getting started: `https://pig.apache.org/docs/latest/start.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-pig/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-pinot/python/DOC.md",
    "content": "---\nname: providers-apache-pinot\ndescription: \"Apache Airflow Pinot provider for Airflow-managed Pinot SQL queries and Pinot controller admin tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,pinot,apache-pinot,sql,dag,python\"\n---\n\n# apache-airflow-providers-apache-pinot\n\nUse `apache-airflow-providers-apache-pinot` when an Airflow DAG needs to query Apache Pinot through a broker connection or call Pinot controller admin endpoints for schemas, tables, and segments.\n\nThis provider is not a standalone Pinot client for ordinary Python applications. It plugs Pinot into Airflow through:\n\n- `SQLExecuteQueryOperator` for SQL tasks\n- `PinotDbApiHook` for Python-driven broker queries\n- `PinotAdminHook` for controller admin operations\n\nThis guide targets provider version `4.10.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-apache-pinot==4.10.0\"\n```\n\nIf you manage Airflow and providers together, pin Airflow in the same command so `pip` does not silently upgrade or downgrade core:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-pinot==4.10.0\"\n```\n\nUpstream lists these minimum requirements for `4.10.0`:\n\n- Python `>=3.10`\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-sql>=1.23.0`\n\nInstall the provider anywhere Airflow imports or runs DAG code:\n\n- scheduler\n- webserver\n- workers or task execution image\n\n## Configure Airflow Connections\n\nThis provider uses two separate Airflow connection types:\n\n- `pinot` for broker SQL queries\n- `pinot_admin` for Pinot controller admin APIs\n\nKeep endpoints and credentials in Airflow connections or your secrets backend instead of hard-coding them in DAG files.\n\n### Broker SQL Connection\n\n`PinotDbApiHook` uses the default connection id `pinot_broker_default`. The provider's `pinot` connection type uses:\n\n- `Host`: Pinot broker or router host\n- `Port`: defaults to `8000`\n- `Extra`: optional `endpoint` value such as `query/sql`\n\nExample environment-variable connection:\n\n```bash\nexport AIRFLOW_CONN_PINOT_BROKER_DEFAULT='{\"conn_type\":\"pinot\",\"host\":\"pinot-broker.example.com\",\"port\":8000,\"extra\":{\"endpoint\":\"query/sql\"}}'\n```\n\nUseful check:\n\n```bash\nairflow connections get pinot_broker_default\n```\n\n`PinotDbApiHook.get_conn()` builds the underlying `pinotdb.connect(...)` call from the Airflow connection host, port, and the optional `endpoint` extra.\n\n### Pinot Controller Admin Connection\n\n`PinotAdminHook` uses the default connection id `pinot_admin_default`. The provider's `pinot_admin` connection type uses:\n\n- `Host`: Pinot controller host\n- `Port`: defaults to `9000`\n- `Login`: optional username\n- `Password`: optional password\n\nExample environment-variable connection:\n\n```bash\nexport AIRFLOW_CONN_PINOT_ADMIN_DEFAULT='{\"conn_type\":\"pinot_admin\",\"host\":\"pinot-controller.example.com\",\"port\":9000,\"login\":\"airflow\",\"password\":\"secret\"}'\n```\n\nUseful check:\n\n```bash\nairflow connections get pinot_admin_default\n```\n\nPoint this connection at the Pinot controller, not the broker. `PinotAdminHook` calls controller REST endpoints such as schema, table, and segment APIs.\n\n## Run Pinot SQL In A DAG\n\nThe provider docs recommend Airflow's generic SQL operator for Pinot SQL work. Use `conn_id` with your Pinot broker connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"pinot_sql_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    query_top_cities = SQLExecuteQueryOperator(\n        task_id=\"query_top_cities\",\n        conn_id=\"pinot_broker_default\",\n        sql=\"\"\"\n        SELECT city, COUNT(*) AS row_count\n        FROM trips\n        GROUP BY city\n        ORDER BY row_count DESC\n        LIMIT 10\n        \"\"\",\n    )\n```\n\nUse this pattern when the task is just SQL execution and you do not need custom Python logic around the query.\n\n## Query Pinot From Python Tasks\n\nUse `PinotDbApiHook` when later task logic needs query results in Python:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.pinot.hooks.pinot import PinotDbApiHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"pinot_hook_query_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def summarize_trips() -> None:\n        hook = PinotDbApiHook(pinot_conn_id=\"pinot_broker_default\")\n\n        total_row = hook.get_first(\"SELECT COUNT(*) FROM trips\")\n        top_cities = hook.get_records(\n            \"\"\"\n            SELECT city, COUNT(*) AS row_count\n            FROM trips\n            GROUP BY city\n            ORDER BY row_count DESC\n            LIMIT 5\n            \"\"\"\n        )\n\n        total = total_row[0] if total_row else 0\n        print(f\"total rows: {total}\")\n        for city, row_count in top_cities:\n            print(city, row_count)\n\n    summarize_trips()\n```\n\nUse this when:\n\n- downstream logic depends on query results\n- you need to branch or format output in Python\n- the result set is small enough to move through an Airflow task\n\n## Manage Pinot Schemas, Tables, And Segments\n\nUse `PinotAdminHook` when a task needs Pinot controller admin APIs.\n\n### Create Or Update A Schema And Table\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.pinot.hooks.pinot import PinotAdminHook\nfrom pendulum import datetime\n\nSCHEMA = {\n    \"schemaName\": \"events\",\n    \"dimensionFieldSpecs\": [\n        {\"name\": \"event_type\", \"dataType\": \"STRING\"},\n    ],\n    \"dateTimeFieldSpecs\": [\n        {\n            \"name\": \"event_time\",\n            \"dataType\": \"LONG\",\n            \"format\": \"1:MILLISECONDS:EPOCH\",\n            \"granularity\": \"1:MILLISECONDS\",\n        }\n    ],\n}\n\nTABLE_CONFIG = {\n    \"tableName\": \"events_OFFLINE\",\n    \"tableType\": \"OFFLINE\",\n    \"segmentsConfig\": {\n        \"schemaName\": \"events\",\n        \"replication\": \"1\",\n    },\n    \"tenants\": {},\n}\n\nwith DAG(\n    dag_id=\"pinot_admin_schema_table_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def ensure_pinot_objects() -> None:\n        hook = PinotAdminHook(pinot_admin_conn_id=\"pinot_admin_default\")\n        hook.add_schema(schema_name=\"events\", schema=SCHEMA)\n        hook.add_table(table_name=\"events_OFFLINE\", table_config=TABLE_CONFIG)\n\n    ensure_pinot_objects()\n```\n\n### Upload A Segment\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apache.pinot.hooks.pinot import PinotAdminHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"pinot_upload_segment_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def upload_segment() -> None:\n        hook = PinotAdminHook(pinot_admin_conn_id=\"pinot_admin_default\")\n        hook.upload_segment(\n            segment_name=\"events_20260313_0\",\n            table_name=\"events_OFFLINE\",\n            segment_uri=\"file:///opt/airflow/pinot/events_20260313_0.tar.gz\",\n        )\n\n    upload_segment()\n```\n\n`PinotAdminHook` also exposes `create_segment(...)` when your workflow uses the Pinot segment-generation command and controller APIs together.\n\n## Common Setup Pattern\n\nFor most DAGs, keep the split simple:\n\n- use `pinot_broker_default` with `SQLExecuteQueryOperator` or `PinotDbApiHook` for SQL\n- use `pinot_admin_default` with `PinotAdminHook` for controller operations\n- keep hosts, ports, and credentials on Airflow connections rather than in DAG code\n\nThat keeps DAGs portable across environments and makes it obvious whether a task talks to the broker or the controller.\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports or executes DAG code. One missing worker image is enough to cause import failures.\n- Do not point `pinot_admin_default` at a broker endpoint or `pinot_broker_default` at a controller endpoint. They target different Pinot services.\n- Set the broker `endpoint` extra if your Pinot deployment exposes SQL on a non-default path.\n- Keep controller credentials in the Airflow connection or secrets backend instead of embedding them in Python.\n- Use worker-accessible file paths or URIs for segment uploads. A file path on your laptop will not exist inside a worker container unless you mount it there.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-pinot` version `4.10.0`.\n- The provider's published requirements for `4.10.0` include Airflow `2.11.0+` and Python `3.10+`.\n- Provider release notes state that `PinotAdminHook` gained username and password support in `4.7.0`. If you are copying older examples, they may omit controller authentication.\n- Provider release notes also note that `PinotAdminHook.create_segment()` no longer accepts a custom `cmd_path` as of `4.0.0`; the hook uses the hard-coded `pinot-admin.sh` command name.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/index.html`\n- Providers installation guide: `https://airflow.apache.org/docs/apache-airflow-providers/index.html`\n- Pinot SQL operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/operators.html`\n- Pinot connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/connections/pinot.html`\n- Pinot admin connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/connections/pinot_admin.html`\n- `PinotDbApiHook` and `PinotAdminHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/_api/airflow/providers/apache/pinot/hooks/pinot/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-apache-pinot/stable/changelog.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-pinot/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-spark/python/DOC.md",
    "content": "---\nname: providers-apache-spark\ndescription: \"Apache Airflow Spark provider for submitting Spark applications from DAGs with Airflow-managed Spark connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.5.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,spark,apache-spark,dag,python\"\n---\n\n# apache-airflow-providers-apache-spark\n\nUse `apache-airflow-providers-apache-spark` when an Airflow DAG needs to launch a Spark application with `spark-submit` and track that submission as a normal Airflow task.\n\nThis guide targets provider version `5.5.1`.\n\n## Install\n\nInstall the provider in the same Python environment or container image used by your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-apache-spark==5.5.1\"\n```\n\nInstall it anywhere Airflow imports or runs DAG code:\n\n- scheduler\n- webserver\n- workers or task execution image\n\nThis package is an Airflow provider, not a standalone Spark client. You do not initialize a Python SDK object. Instead, you configure an Airflow connection and instantiate provider operators inside DAG code.\n\n## Prerequisites\n\nBefore using the provider, make sure your runtime already has:\n\n- an Apache Airflow deployment\n- access to a Spark cluster or local Spark installation\n- a working `spark-submit` binary on the machine or container that executes the task\n- your Spark application code available at a path the task can read, or at a remote location your Spark runtime can fetch\n\nThe provider submits work to Spark. It does not bundle Spark itself.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `spark`. The default connection id used by examples and the operator default is `spark_default`.\n\nYou can configure it in the Airflow UI, with the Airflow CLI, or with an environment variable.\n\nExample environment variable for a standalone Spark master:\n\n```bash\nexport AIRFLOW_CONN_SPARK_DEFAULT='spark://spark-master.example.com:7077?deploy-mode=client'\n```\n\nIn the Airflow UI, the connection usually maps like this:\n\n- **Connection Id:** `spark_default`\n- **Connection Type:** `spark`\n- **Host:** `local`, `yarn`, or a Spark master URL such as `spark://spark-master.example.com`\n- **Port:** Spark master port when you use a standalone master\n- **Extra:** optional JSON such as `{\"deploy-mode\": \"client\"}`\n\nUseful extras depend on your Spark environment. Common ones documented for the Spark connection include deploy mode and other `spark-submit` settings. Keep cluster-specific details on the connection when you want DAG code to stay portable across environments.\n\nUseful check:\n\n```bash\nairflow connections get spark_default\n```\n\n## Submit A PySpark Application\n\nFor most DAGs, start with `SparkSubmitOperator`.\n\nExample Spark application:\n\n```python\n# dags/jobs/wordcount.py\nfrom pyspark.sql import SparkSession\n\n\nspark = SparkSession.builder.appName(\"airflow-wordcount\").getOrCreate()\n\nrows = spark.createDataFrame(\n    [(\"apple\",), (\"apple\",), (\"banana\",)],\n    [\"word\"],\n)\n\ncounts = rows.groupBy(\"word\").count().collect()\nfor row in counts:\n    print(f\"{row['word']}: {row['count']}\")\n\nspark.stop()\n```\n\nExample DAG task that submits that application:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.spark.operators.spark_submit import SparkSubmitOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"spark_submit_python_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    submit_wordcount = SparkSubmitOperator(\n        task_id=\"submit_wordcount\",\n        application=\"/opt/airflow/dags/jobs/wordcount.py\",\n        conn_id=\"spark_default\",\n        name=\"airflow-wordcount\",\n        conf={\n            \"spark.executor.memory\": \"2g\",\n            \"spark.driver.memory\": \"1g\",\n        },\n        application_args=[],\n        verbose=False,\n    )\n```\n\nThe main arguments you normally set are:\n\n- `application`: path to the Python file, JAR, or other Spark entrypoint\n- `conn_id`: Airflow Spark connection id, usually `spark_default`\n- `name`: job name shown by Spark\n- `conf`: Spark configuration passed to `spark-submit`\n- `application_args`: positional arguments passed to your application\n\nUse this pattern when Airflow should orchestrate an existing Spark job instead of embedding Spark logic inside the Airflow task itself.\n\n## Submit A JAR Application\n\nIf your Spark job is packaged as a JAR, keep the same operator and point `application` at the JAR.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.spark.operators.spark_submit import SparkSubmitOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"spark_submit_jar_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    submit_jar = SparkSubmitOperator(\n        task_id=\"submit_jar\",\n        application=\"/opt/airflow/dags/jars/example-job.jar\",\n        java_class=\"com.example.jobs.WordCountJob\",\n        conn_id=\"spark_default\",\n        application_args=[\"s3a://input-bucket/data\", \"s3a://output-bucket/results\"],\n        conf={\n            \"spark.executor.instances\": \"3\",\n            \"spark.executor.memory\": \"4g\",\n        },\n    )\n```\n\nUse `java_class` for JVM jobs with a main class. Leave it out when the application itself is the executable entrypoint.\n\n## Common Setup Pattern\n\nFor most teams, a clean setup looks like this:\n\n- keep cluster address and deploy mode on the Airflow `spark` connection\n- keep the Spark application file or JAR in a location available to task runtime\n- use `SparkSubmitOperator` as the Airflow task boundary\n- pass Spark tuning through `conf` and app-specific inputs through `application_args`\n\nThat split keeps DAGs readable and avoids hard-coding environment-specific Spark endpoints into every task.\n\n## Pitfalls\n\n- Install the provider everywhere Airflow parses or runs DAGs. Import errors usually mean one Airflow image is missing the package.\n- Make sure `spark-submit` exists on the worker or execution image. The provider wraps that command; it does not supply Spark binaries.\n- Keep `application` paths valid for the task runtime. A path that exists on your laptop but not inside the Airflow container will fail.\n- Keep connection ids explicit if you do not use `spark_default`.\n- Use Airflow connections, a secrets backend, or environment variables for cluster credentials instead of embedding them in DAG code.\n- When you rely on environment variables, remember that Airflow task runtime, Spark driver runtime, and Spark executor runtime may not share the same environment automatically.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-spark` version `5.5.1`.\n- Airflow provider packages are versioned separately from Apache Airflow core.\n- If you upgrade Airflow core or the Spark provider independently, re-check the provider docs and the operator API reference before changing DAG code.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-spark/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-spark/stable/index.html`\n- Spark connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-spark/stable/connections/spark-submit.html`\n- `SparkSubmitOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-spark/stable/_api/airflow/providers/apache/spark/operators/spark_submit/index.html`\n- `SparkSubmitHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-spark/stable/_api/airflow/providers/apache/spark/hooks/spark_submit/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-spark/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apache-sqoop/python/DOC.md",
    "content": "---\nname: providers-apache-sqoop\ndescription: \"Apache Airflow Sqoop provider for running Sqoop 1 imports and exports from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,sqoop,hadoop,etl,dag,python\"\n---\n\n# apache-airflow-providers-apache-sqoop\n\nUse `apache-airflow-providers-apache-sqoop` when an Airflow DAG needs to run Sqoop 1 imports or exports between a relational database and Hadoop storage by shelling out to the `sqoop` command.\n\nThis is a legacy Airflow provider. The provider changelog marks it as removed and unmaintained, and current Airflow docs list Apache Sqoop under removed providers. Treat it as a maintenance-only integration for existing Airflow 2.x and Sqoop 1 pipelines.\n\n## Golden Rule\n\n- Install the provider into the same Airflow environment as the scheduler and every worker that can execute the DAG.\n- Keep the database JDBC URL, Hadoop settings, and secrets in an Airflow connection such as `sqoop_default`.\n- Make sure the task runtime already has the `sqoop` binary, the JDBC driver jar, and any Hadoop config files it needs. The provider does not bundle them.\n- Use `SqoopOperator` for normal DAG tasks and `SqoopHook` only when task code needs lower-level control.\n\n## Install\n\nThe official provider docs describe installing this package on top of an existing Airflow 2 installation and require Airflow `2.6.0+`.\n\nPin Airflow and the provider together and use the matching Airflow constraints file:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-2.x-version>\"\nPROVIDER_VERSION=\"4.2.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apache-sqoop==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nInstall the provider anywhere Airflow imports or runs DAG code:\n\n- scheduler\n- webserver if it imports DAG modules\n- workers or task execution image\n\n## Prerequisites\n\nBefore writing DAG code, make sure the task runtime already has:\n\n- the `sqoop` executable on `PATH`\n- a JDBC driver jar for the source or destination database\n- access to Hadoop and HDFS config files when your Sqoop job needs them\n- network reachability from the worker to the database and Hadoop services the Sqoop command will call\n\nIf the worker image is missing `sqoop` or the JDBC driver, the provider import will succeed but the task will fail when it tries to launch the command.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection id such as `sqoop_default`. The hook builds the Sqoop `--connect` JDBC string from the connection's `host`, `port`, and optional `schema`, and it also reads extras such as `job_tracker`, `namenode`, `files`, `archives`, and `password_file`.\n\nAirflow supports defining connections with an `AIRFLOW_CONN_*` environment variable in JSON form. Example:\n\n```bash\nexport AIRFLOW_CONN_SQOOP_DEFAULT='{\n  \"conn_type\": \"sqoop\",\n  \"login\": \"etl_user\",\n  \"host\": \"jdbc:mysql://mysql.example.com\",\n  \"port\": 3306,\n  \"schema\": \"warehouse\",\n  \"extra\": {\n    \"job_tracker\": \"local\",\n    \"namenode\": \"hdfs://namenode.example.com:8020\",\n    \"files\": \"/etc/hadoop/conf/core-site.xml,/etc/hadoop/conf/hdfs-site.xml\",\n    \"password_file\": \"/opt/airflow/secrets/mysql-password.txt\"\n  }\n}'\n```\n\nPractical mapping for the connection fields:\n\n- `host`: JDBC base URL such as `jdbc:mysql://mysql.example.com`\n- `port`: database port\n- `schema`: database name appended to the JDBC URL\n- `login`: database username passed as `--username`\n- `extra.job_tracker`: MapReduce job tracker, often `local` for simple setups\n- `extra.namenode`: HDFS namenode such as `hdfs://namenode.example.com:8020`\n- `extra.files` / `extra.archives`: extra files the Sqoop command should ship\n- `extra.password_file`: file passed to `--password-file` instead of embedding a password in the DAG\n\nKeep secrets in a secrets backend or password file instead of hard-coding them in DAG source.\n\n## Import A Table With `SqoopOperator`\n\nUse `SqoopOperator` with `cmd_type=\"import\"` when Airflow should pull a table into HDFS.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.sqoop.operators.sqoop import SqoopOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sqoop_import_customers\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=\"@daily\",\n    catchup=False,\n) as dag:\n    import_customers = SqoopOperator(\n        task_id=\"import_customers\",\n        conn_id=\"sqoop_default\",\n        cmd_type=\"import\",\n        table=\"customers\",\n        target_dir=\"/data/raw/customers/{{ ds }}\",\n        split_by=\"customer_id\",\n        num_mappers=4,\n        columns=\"customer_id,email,updated_at\",\n        where=\"updated_at >= '{{ data_interval_start.to_date_string() }}'\",\n        append=False,\n        verbose=True,\n        extra_options={\"delete-target-dir\": \"\"},\n        libjars=\"/opt/jdbc/mysql-connector-j-8.4.0.jar\",\n    )\n```\n\nThe main arguments you will usually set are:\n\n- `table` or `query`\n- `target_dir` for imports\n- `split_by` and `num_mappers` for parallel jobs\n- `columns` and `where` to reduce imported data\n- `libjars` when the worker needs a JDBC driver jar for the database\n- `extra_options` for raw Sqoop flags not exposed as first-class operator arguments\n\n## Import From A Free-Form Query\n\nUse `query=` instead of `table=` when the source SQL is more complex than a table import.\n\nSqoop's user guide requires free-form imports to include `$CONDITIONS` in the `WHERE` clause. If you run with more than one mapper, also set `split_by` so Sqoop can partition the query.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.sqoop.operators.sqoop import SqoopOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sqoop_import_orders_query\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    import_orders = SqoopOperator(\n        task_id=\"import_orders\",\n        conn_id=\"sqoop_default\",\n        cmd_type=\"import\",\n        query=\"\"\"\n        SELECT order_id, customer_id, total_amount, updated_at\n        FROM orders\n        WHERE $CONDITIONS\n          AND updated_at >= '{{ data_interval_start.to_date_string() }}'\n        \"\"\",\n        target_dir=\"/data/raw/orders/{{ ds }}\",\n        split_by=\"order_id\",\n        num_mappers=4,\n    )\n```\n\nImportant query-import rules:\n\n- `target_dir` is required for query imports\n- parallel query imports need both `$CONDITIONS` and `split_by`\n- if the query cannot be split safely, set `num_mappers=1`\n\n## Export Files Back To A Database\n\nUse `cmd_type=\"export\"` when the data already exists in HDFS and the task should write it into a relational table.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.apache.sqoop.operators.sqoop import SqoopOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sqoop_export_daily_scores\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    export_scores = SqoopOperator(\n        task_id=\"export_scores\",\n        conn_id=\"sqoop_default\",\n        cmd_type=\"export\",\n        table=\"daily_scores\",\n        export_dir=\"/data/curated/daily_scores/{{ ds }}\",\n        input_fields_terminated_by=\",\",\n        input_lines_terminated_by=\"\\n\",\n        input_optionally_enclosed_by='\"',\n        num_mappers=2,\n        staging_table=\"daily_scores_staging\",\n        clear_staging_table=True,\n        batch=True,\n        verbose=True,\n    )\n```\n\nUse the staging-table options when you want Sqoop to load into a temporary table before merging into the final table.\n\n## Use `SqoopHook` In Task Code\n\nWhen a DAG task needs direct access to the provider's Python wrapper instead of a declarative operator task, instantiate `SqoopHook` and call `import_table`, `import_query`, or `export_table`.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.apache.sqoop.hooks.sqoop import SqoopHook\n\n@task\ndef backfill_reference_data() -> None:\n    hook = SqoopHook(\n        conn_id=\"sqoop_default\",\n        verbose=True,\n        num_mappers=1,\n        properties={\"mapreduce.job.queuename\": \"etl\"},\n    )\n\n    hook.import_table(\n        table=\"reference_data\",\n        target_dir=\"/data/reference/reference_data\",\n        append=False,\n        file_type=\"text\",\n    )\n```\n\nUse hook methods when the exact Sqoop action depends on earlier task output or branching logic. For ordinary imports and exports, `SqoopOperator` is easier to read in the DAG graph.\n\n## Important Pitfalls\n\n- This provider wraps the external `sqoop` command. It does not provide a standalone Python database client.\n- Install it everywhere Airflow runs tasks. One missing worker image is enough to cause failures.\n- A valid Airflow connection is not enough by itself. The worker also needs the `sqoop` binary, the JDBC driver jar, and any Hadoop config files referenced by `files` or `archives`.\n- Query imports fail if you forget `$CONDITIONS`. Parallel query imports also need `split_by`.\n- Keep credentials out of DAG code. Use an Airflow connection, a password file, or a secrets backend.\n- This provider is removed and no longer maintained. Re-check the provider changelog before upgrading Airflow or rebuilding old pipelines around it.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apache-sqoop` version `4.2.1`.\n- The provider docs describe it as installable on top of an existing Airflow 2 installation and require Airflow `2.6.0+`.\n- The `4.2.1` changelog entry says the provider was removed and is no longer maintained.\n- Current Airflow docs also list Apache Sqoop among removed providers.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-apache-sqoop/stable/`\n- Provider package index: `https://airflow.apache.org/docs/apache-airflow-providers-apache-sqoop/stable/index.html`\n- `SqoopOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-sqoop/stable/_api/airflow/providers/apache/sqoop/operators/sqoop/index.html`\n- `SqoopHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-apache-sqoop/stable/_api/airflow/providers/apache/sqoop/hooks/sqoop/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-apache-sqoop/stable/changelog.html`\n- Removed providers list: `https://airflow.apache.org/docs/apache-airflow/stable/extra-packages-ref.html`\n- Managing connections with environment variables: `https://airflow.apache.org/docs/apache-airflow/2.6.0/howto/connection.html`\n- Sqoop user guide: `https://sqoop.apache.org/docs/1.4.2/SqoopUserGuide.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-apache-sqoop/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-apprise/python/DOC.md",
    "content": "---\nname: providers-apprise\ndescription: \"Apache Airflow provider for routing DAG and task notifications through Apprise-backed services such as Slack, email, and other Apprise URLs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,apprise,notifications,alerts,python\"\n---\n\n# apache-airflow-providers-apprise\n\nUse `apache-airflow-providers-apprise` when Airflow should send DAG or task notifications through Apprise instead of wiring each target service directly in DAG code.\n\nThis package extends Apache Airflow. It is not a standalone notification SDK for non-Airflow applications.\n\nThis guide targets provider version `2.3.1`.\n\n## What This Package Adds\n\nThe Apprise provider gives Airflow an Apprise-backed connection type plus two practical entry points:\n\n- `send_apprise_notification(...)` for DAG-level or task-level callbacks\n- `AppriseHook` for sending notifications from Python task code\n\nApprise itself handles the target service URLs. Airflow stores those service definitions in an Airflow connection, usually `apprise_default`.\n\n## Install\n\nThe provider docs say this release requires:\n\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-compat>=1.9.0`\n- `apprise>=1.8.0`\n\nInstall Airflow first with the official constraints file, then add the provider in a separate command while keeping your Airflow version pinned:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apprise==2.3.1\"\n```\n\nIf you want the cross-provider extra explicitly, upstream also publishes:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-apprise[common.compat]==2.3.1\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep apprise\npython -c \"from airflow.providers.apprise.hooks.apprise import AppriseHook\"\n```\n\n## Configure The Apprise Connection\n\nBy default, the hook and notifier use the Airflow connection id `apprise_default`.\n\nThe provider expects the Airflow connection to carry a `config` value in `extra`. That `config` must be either:\n\n- one object with `path` and optional `tag`\n- a list of those objects\n\nSingle-service example from an environment variable:\n\n```bash\nexport AIRFLOW_CONN_APPRISE_DEFAULT='{\"extra\": {\"config\": {\"path\": \"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX\", \"tag\": \"ops\"}}}'\n```\n\nMultiple-service example:\n\n```bash\nexport AIRFLOW_CONN_APPRISE_DEFAULT='{\"extra\": {\"config\": [{\"path\": \"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX\", \"tag\": \"ops\"}, {\"path\": \"mailto://user:password@example.com\", \"tag\": \"email\"}]}}'\n```\n\nImportant detail: use `tag`, not `tags`, inside each config object. The connection guide shows an environment-variable example with `tags`, but the provider hook reads the singular key `tag`.\n\nIf you prefer the Airflow UI, create a connection with:\n\n- Connection Id: `apprise_default`\n- Connection Type: `apprise`\n- Config: JSON like `{\"path\": \"service url\", \"tag\": \"ops\"}` or a JSON list of those objects\n\nUse tags when one Airflow connection should route different notifications to different targets.\n\n## Send Callback Notifications With `send_apprise_notification`\n\nUse `send_apprise_notification(...)` when notifications are a side effect of task or DAG state changes.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.apprise.notifications.apprise import send_apprise_notification\nfrom apprise import NotifyFormat, NotifyType\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"apprise_callback_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    on_success_callback=[\n        send_apprise_notification(\n            body=\"DAG {{ dag.dag_id }} succeeded for run {{ run_id }}\",\n            title=\"Airflow DAG success\",\n            notify_type=NotifyType.SUCCESS,\n            body_format=NotifyFormat.MARKDOWN,\n            tag=\"ops\",\n            apprise_conn_id=\"apprise_default\",\n        )\n    ],\n) as dag:\n    @task(\n        on_failure_callback=[\n            send_apprise_notification(\n                body=(\n                    \"Task {{ ti.task_id }} failed in DAG {{ dag.dag_id }}\\n\"\n                    \"Run id: {{ run_id }}\\n\"\n                    \"Log URL: {{ ti.log_url }}\"\n                ),\n                title=\"Airflow task failure\",\n                notify_type=NotifyType.FAILURE,\n                tag=\"ops\",\n            )\n        ]\n    )\n    def run_job() -> None:\n        print(\"work finished\")\n\n    run_job()\n```\n\nParameters worth setting explicitly:\n\n- `body`: required notification body; template fields are supported\n- `title`: optional title\n- `notify_type`: one of Apprise's `info`, `success`, `failure`, or `warning`\n- `body_format`: `text`, `html`, or `markdown`\n- `tag`: which tagged services inside the connection should receive the message\n- `apprise_conn_id`: override the default connection when needed\n\nUse callback notifications when you do not want a separate \"notification task\" in the DAG graph.\n\n## Send Notifications From Python With `AppriseHook`\n\nUse the hook when the message content depends on Python-side logic or task output.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import get_current_context, task\nfrom airflow.providers.apprise.hooks.apprise import AppriseHook\nfrom apprise import NotifyFormat, NotifyType\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"apprise_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def notify_ops() -> None:\n        context = get_current_context()\n\n        hook = AppriseHook(apprise_conn_id=\"apprise_default\")\n        hook.notify(\n            body=(\n                f\"DAG {context['dag'].dag_id} completed task \"\n                f\"{context['ti'].task_id} for run {context['run_id']}\"\n            ),\n            title=\"Airflow notification\",\n            notify_type=NotifyType.INFO,\n            body_format=NotifyFormat.TEXT,\n            tag=\"ops\",\n        )\n\n    notify_ops()\n```\n\n`AppriseHook.notify(...)` accepts the same practical options as the notifier, including `body`, `title`, `notify_type`, `body_format`, `tag`, `attach`, `interpret_escapes`, and an optional `config` object if you want to bypass the Airflow connection entirely.\n\nUse `attach` only for files that exist in the worker runtime where the task executes.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep apprise\nairflow dags list | grep apprise\n```\n\nThen run a task-level test:\n\n```bash\nairflow tasks test apprise_hook_example notify_ops 2026-03-13\n```\n\nUse `airflow tasks test` for import errors, connection lookup problems, and message-shape debugging before you rely on scheduler-driven callbacks.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible Airflow installation, and this provider now requires Airflow `2.11.0` or newer.\n- Installing the provider only on the scheduler: workers and any other process that imports DAG files also need it.\n- Putting the service definitions anywhere except the Apprise connection `config` field or an explicit `config=` object passed to the hook/notifier.\n- Using `tags` instead of `tag` in the config payload.\n- Expecting a tagged notification to reach every service: `tag=\"ops\"` sends only to services configured with that tag.\n- Passing attachment paths that do not exist in the worker container or host filesystem.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-apprise` version `2.3.1`.\n- Upstream's changelog says `2.3.0` raised the minimum supported Airflow version to `2.11.0`; that still applies to `2.3.1`.\n- Upstream's changelog says `2.2.0` added async Apprise notifier support. The notifier class in `2.3.1` includes both `notify(...)` and `async_notify(...)`.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-apprise/stable/index.html`\n- Connection guide: `https://airflow.apache.org/docs/apache-airflow-providers-apprise/stable/connections.html`\n- Notification how-to: `https://airflow.apache.org/docs/apache-airflow-providers-apprise/stable/notifications/apprise_notifier_howto_guide.html`\n- Hook API: `https://airflow.apache.org/docs/apache-airflow-providers-apprise/stable/_api/airflow/providers/apprise/hooks/apprise/index.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-apprise/stable/changelog.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-apprise/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-asana/python/DOC.md",
    "content": "---\nname: providers-asana\ndescription: \"Apache Airflow provider for Asana connections, task operators, and hook-based task or project automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.11.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,asana,tasks,projects,hooks,operators\"\n---\n\n# Apache Airflow Asana Provider Guide\n\nUse `apache-airflow-providers-asana` when an Airflow DAG needs an Airflow-managed Asana personal access token and Python or operator-based tasks that create, search, update, or delete Asana tasks without embedding credentials in DAG files.\n\nThis guide covers provider version `2.11.1`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Asana SDK.\n- Put the Asana personal access token on an Airflow connection such as `asana_default`.\n- Use `AsanaHook` for most real DAG logic, especially if the task needs project operations or more than one Asana API call.\n- Keep task ids, project ids, workspace ids, and secrets in Airflow connections, variables, or deployment config rather than hard-coding them in DAG source.\n\n## What This Package Adds\n\nThis provider supplies Airflow's Asana integration points:\n\n- Airflow connection type `asana`\n- `AsanaHook`\n- `AsanaCreateTaskOperator`\n- `AsanaFindTaskOperator`\n- `AsanaUpdateTaskOperator`\n- `AsanaDeleteTaskOperator`\n\nThe operator surface is task-focused. If your DAG needs to create, find, update, or delete Asana projects, use `AsanaHook`.\n\n## Install\n\nInstall the provider into the same environment as Airflow and keep both versions pinned. Airflow recommends installing providers with the constraints file that matches your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"2.11.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-asana==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i asana\nairflow info\n```\n\nVersion-sensitive notes from the official package metadata:\n\n- `apache-airflow-providers-asana 2.11.1` requires `apache-airflow>=2.11.0`.\n- PyPI classifiers for `2.11.1` list Python `3.10`, `3.11`, `3.12`, and `3.13`.\n\n## Configure An Asana Connection\n\nThe provider connection uses the Airflow connection password field for the Asana personal access token. The hook also recognizes `workspace` and `project` in connection extras as defaults for later task and project calls.\n\nSet the values you want Airflow to store:\n\n```bash\nexport ASANA_PAT=\"<asana-personal-access-token>\"\nexport ASANA_WORKSPACE_GID=\"<asana-workspace-gid>\"\nexport ASANA_PROJECT_GID=\"<asana-project-gid>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'asana_default' \\\n  --conn-type 'asana' \\\n  --conn-password \"$ASANA_PAT\" \\\n  --conn-extra \"{\\\"workspace\\\":\\\"${ASANA_WORKSPACE_GID}\\\",\\\"project\\\":\\\"${ASANA_PROJECT_GID}\\\"}\"\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get asana_default\n```\n\nImportant details:\n\n- `password` is required. The hook raises an error if the token is missing.\n- `host`, `login`, `port`, and `schema` are not used by this provider.\n- `workspace` and `project` in extras act as defaults. Explicit task or search parameters in DAG code still win when both are present.\n\n## Common Workflow: Create, Search, And Complete Tasks With `AsanaHook`\n\nUse `AsanaHook` when a task needs normal Python control flow or more than one Asana API call.\n\n```python\nfrom __future__ import annotations\n\nimport os\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.asana.hooks.asana import AsanaHook\n\n\nPROJECT_GID = os.environ[\"ASANA_PROJECT_GID\"]\n\n\nwith DAG(\n    dag_id=\"asana_hook_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"asana\"],\n):\n    @task()\n    def create_asana_task() -> str:\n        hook = AsanaHook(conn_id=\"asana_default\")\n        created = hook.create_task(\n            \"Review overnight pipeline failures\",\n            {\n                \"projects\": [PROJECT_GID],\n            },\n        )\n        return created[\"gid\"]\n\n    @task()\n    def find_recent_project_tasks() -> list[dict[str, str | None]]:\n        hook = AsanaHook(conn_id=\"asana_default\")\n        tasks = hook.find_task({\"project\": PROJECT_GID})\n        return [{\"gid\": item[\"gid\"], \"name\": item.get(\"name\")} for item in tasks[:10]]\n\n    @task()\n    def mark_task_complete(task_gid: str) -> None:\n        hook = AsanaHook(conn_id=\"asana_default\")\n        hook.update_task(\n            task_gid,\n            {\n                \"name\": \"Review overnight pipeline failures (updated by Airflow)\",\n            },\n        )\n\n    created_gid = create_asana_task()\n    find_recent_project_tasks()\n    mark_task_complete(created_gid)\n```\n\nWhat the hook methods expect:\n\n- `create_task(name, task_parameters)` requires a task name and at least one placement target through `workspace`, `projects`, `parent`, or connection defaults.\n- `find_task(search_parameters)` requires one of `project`, `section`, `tag`, `user_task_list`, or the pair `assignee` plus `workspace`.\n- `update_task(asana_task_gid, task_parameters)` updates an existing task by gid.\n- `delete_task(asana_task_gid)` deletes an existing task by gid.\n\n## Common Workflow: Task Operators In A DAG\n\nUse the operators when a task is one direct Asana action and you do not need much Python control flow around it.\n\n```python\nfrom __future__ import annotations\n\nimport os\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.asana.operators.asana_tasks import (\n    AsanaCreateTaskOperator,\n    AsanaDeleteTaskOperator,\n    AsanaFindTaskOperator,\n    AsanaUpdateTaskOperator,\n)\n\n\nPROJECT_GID = os.environ[\"ASANA_PROJECT_GID\"]\n\n\nwith DAG(\n    dag_id=\"asana_operator_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"asana\"],\n):\n    create_task = AsanaCreateTaskOperator(\n        task_id=\"create_task\",\n        conn_id=\"asana_default\",\n        name=\"Follow up with integration owner\",\n        task_parameters={\n            \"projects\": [PROJECT_GID],\n        },\n    )\n\n    find_tasks = AsanaFindTaskOperator(\n        task_id=\"find_tasks\",\n        conn_id=\"asana_default\",\n        search_parameters={\"project\": PROJECT_GID},\n    )\n\n    update_task = AsanaUpdateTaskOperator(\n        task_id=\"update_task\",\n        conn_id=\"asana_default\",\n        asana_task_gid=\"<existing-task-gid>\",\n        task_parameters={\"name\": \"Follow up with integration owner (updated)\"},\n    )\n\n    delete_task = AsanaDeleteTaskOperator(\n        task_id=\"delete_task\",\n        conn_id=\"asana_default\",\n        asana_task_gid=\"<task-gid-to-delete>\",\n    )\n\n    create_task >> find_tasks >> update_task >> delete_task\n```\n\nThe operator classes are thin wrappers around the same Asana task APIs. Prefer the hook when later steps depend on Python-side branching, multiple Asana calls, or project operations.\n\n## Project Operations With `AsanaHook`\n\nProject methods are available on the hook even though the packaged operators focus on tasks.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nfrom airflow.providers.asana.hooks.asana import AsanaHook\n\n\nWORKSPACE_GID = os.environ[\"ASANA_WORKSPACE_GID\"]\n\n\nhook = AsanaHook(conn_id=\"asana_default\")\n\nproject = hook.create_project(\n    {\n        \"workspace\": WORKSPACE_GID,\n        \"name\": \"Airflow Provider Demo Project\",\n    }\n)\n\nproject_gid = project[\"gid\"]\n\nhook.update_project(project_gid, {\"name\": \"Airflow Provider Demo Project (renamed)\"})\nprojects = hook.find_project({\"workspace\": WORKSPACE_GID})\nhook.delete_project(project_gid)\n```\n\nUse this pattern when the DAG needs to manage project objects directly instead of only task objects.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i asana\nairflow dags list | grep asana\n```\n\nTest one task in isolation while you wire up the token and ids:\n\n```bash\nairflow tasks test asana_hook_demo create_asana_task 2026-03-13\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream dependencies.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Creating the Airflow connection without a password: the provider treats the password as the Asana token and errors if it is missing.\n- Calling `create_task()` without a placement target such as `projects`, `workspace`, or `parent`.\n- Calling `find_task()` without enough search scope. The provider enforces a project, section, tag, user task list, or `assignee` plus `workspace`.\n- Assuming connection extras always override DAG code. The hook uses extras as defaults, then lets explicit parameters in the task payload or search payload take precedence.\n- Expecting project operators to exist. Project CRUD is exposed through `AsanaHook`, not through separate project operator classes in this provider version.\n- Relying on `delete_task()` to fail for a nonexistent gid. The provider logs the condition and still completes successfully.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-asana` version `2.11.1`.\n- The Airflow provider `stable/` docs root moves when new provider releases ship, so keep your pinned Airflow and provider versions as the final authority during upgrades.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-asana/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-asana/stable/index.html`\n- Asana connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-asana/stable/connections/asana.html`\n- `AsanaHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-asana/stable/_api/airflow/providers/asana/hooks/asana/index.html`\n- Task operators API reference: `https://airflow.apache.org/docs/apache-airflow-providers-asana/stable/_api/airflow/providers/asana/operators/asana_tasks/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-asana/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-atlassian-jira/python/DOC.md",
    "content": "---\nname: providers-atlassian-jira\ndescription: \"Apache Airflow provider for Jira connections, hooks, operators, sensors, and failure notifications backed by Atlassian's Jira Python API\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,jira,atlassian,hooks,operators,sensors,notifications\"\n---\n\n# Apache Airflow Atlassian Jira Provider Guide\n\nUse `apache-airflow-providers-atlassian-jira` when an Airflow DAG needs an Airflow-managed Jira connection plus task code, operators, sensors, or failure callbacks that talk to Jira without embedding credentials in the DAG file.\n\nThis guide covers provider version `3.3.1`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Jira SDK.\n- Keep the Jira base URL, login, password or API token, and SSL verification setting on an Airflow connection such as `jira_default`.\n- Use `JiraHook` for most real task logic, and use `JiraOperator`, `JiraTicketSensor`, or `send_jira_notification` when the task shape is already a good fit for those abstractions.\n- Pass method names and payloads that exist on the underlying `atlassian-python-api` Jira client.\n\n## What This Package Adds\n\nThe provider exposes these main integration points:\n\n- Airflow connection type `jira`\n- `JiraHook`\n- `JiraOperator`\n- `JiraSensor`\n- `JiraTicketSensor`\n- `send_jira_notification` / `JiraNotifier`\n\nUnder the hood, `JiraHook` wraps the Atlassian Jira client from `atlassian-python-api`, so the methods you call from the hook or operator come from that client.\n\n## Install\n\nThis provider requires Apache Airflow `>=2.11.0`. For a fresh Airflow environment, use the official constraints file for the Airflow version and Python version you are actually running, then add the provider in a separate pinned install command.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.3.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-atlassian-jira==${PROVIDER_VERSION}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i atlassian\npython -m pip check\n```\n\nImportant install notes:\n\n- PyPI lists Python `3.10` through `3.13` for `apache-airflow-providers-atlassian-jira==3.3.1`.\n- The provider depends on `atlassian-python-api > 3.41.10`.\n- Install the provider in every Airflow environment that parses DAGs or executes tasks importing `airflow.providers.atlassian.jira`.\n\n## Configure A Jira Connection\n\nThe Jira connection type uses:\n\n- `host`: Jira base URL, including scheme\n- `login`: username used for authentication\n- `password`: password or API token\n- `extra.verify`: optional boolean SSL verification flag, default `true`\n\nSet the values you want Airflow to store:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nexport JIRA_HOST=\"https://jira.example.com\"\nexport JIRA_USERNAME=\"airflow@example.com\"\nexport JIRA_API_TOKEN=\"<jira-password-or-api-token>\"\n```\n\nCreate the Airflow connection:\n\n```bash\nairflow connections add 'jira_default' \\\n  --conn-type 'jira' \\\n  --conn-host \"$JIRA_HOST\" \\\n  --conn-login \"$JIRA_USERNAME\" \\\n  --conn-password \"$JIRA_API_TOKEN\" \\\n  --conn-extra '{\"verify\": true}'\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get jira_default\n```\n\nPractical notes:\n\n- The Jira host must include the scheme, such as `https://jira.example.com`.\n- In provider `3.x`, the `verify` extra is a boolean. Do not pass `\"true\"` or `\"false\"` strings.\n- The standard Jira connection form only maps `host`, `login`, `password`, and `verify` into `JiraHook`. If your Jira deployment needs more specialized auth settings, verify that the provider supports them before standardizing on this connection type.\n\n## Common Workflow: Create And Update An Issue In Task Code\n\nUse `JiraHook` when task code needs ordinary Python control flow and more than one Jira API call.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.atlassian.jira.hooks.jira import JiraHook\n\n\nwith DAG(\n    dag_id=\"jira_hook_issue_flow\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    @task()\n    def create_issue() -> str:\n        jira = JiraHook(jira_conn_id=\"jira_default\").get_conn()\n\n        issue = jira.create_issue(\n            fields={\n                \"project\": {\"key\": \"DATA\"},\n                \"summary\": \"Airflow detected a pipeline failure\",\n                \"description\": \"Created from an Airflow task using JiraHook.\",\n                \"issuetype\": {\"name\": \"Task\"},\n                \"labels\": [\"airflow\", \"incident\"],\n            }\n        )\n\n        return issue[\"key\"]\n\n    @task()\n    def update_issue(issue_key: str) -> dict[str, str]:\n        jira = JiraHook(jira_conn_id=\"jira_default\").get_conn()\n\n        jira.issue_add_comment(issue_key, \"Retry has started from Airflow.\")\n        jira.set_issue_status(issue_key, \"In Progress\")\n\n        return {\n            \"issue_key\": issue_key,\n            \"status\": jira.get_issue_status(issue_key),\n        }\n\n    update_issue(create_issue())\n```\n\nWhy this pattern works well:\n\n- `JiraHook(jira_conn_id=\"jira_default\").get_conn()` returns the authenticated Atlassian Jira client.\n- The method names such as `create_issue`, `issue_add_comment`, `set_issue_status`, and `get_issue_status` come from `atlassian-python-api`.\n- Returning small strings or dicts keeps XCom payloads manageable.\n\n## Common Workflow: Run One Jira Method With `JiraOperator`\n\nUse `JiraOperator` when a task is a single Jira client call and you do not need much Python around it.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.atlassian.jira.operators.jira import JiraOperator\n\n\nwith DAG(\n    dag_id=\"jira_operator_create_issue\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    create_issue = JiraOperator(\n        task_id=\"create_issue\",\n        jira_conn_id=\"jira_default\",\n        jira_method=\"create_issue\",\n        jira_method_args={\n            \"fields\": {\n                \"project\": {\"key\": \"DATA\"},\n                \"summary\": \"Open a Jira issue from JiraOperator\",\n                \"description\": \"This task calls one Atlassian Jira client method.\",\n                \"issuetype\": {\"name\": \"Task\"},\n            }\n        },\n    )\n```\n\n`jira_method` must be a method that exists on the underlying Jira client, and `jira_method_args` is the dict of keyword arguments passed to that method.\n\n## Common Workflow: Wait For A Ticket To Reach A Status\n\nUse `JiraTicketSensor` when the DAG should pause until one field on a ticket reaches an expected value.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.atlassian.jira.sensors.jira import JiraTicketSensor\n\n\nwith DAG(\n    dag_id=\"jira_wait_for_done\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    wait_for_done = JiraTicketSensor(\n        task_id=\"wait_for_done\",\n        jira_conn_id=\"jira_default\",\n        ticket_id=\"DATA-123\",\n        field=\"status\",\n        expected_value=\"Done\",\n        poke_interval=60,\n        timeout=60 * 60,\n    )\n```\n\n`JiraTicketSensor` calls the Jira client's `issue()` method internally and checks `issue[\"fields\"][field]`. For object-like fields such as `status`, it compares the nested `name` value.\n\nIf you need a custom wait condition, use `JiraSensor` instead and provide a Jira client method name plus a `result_processor` callback.\n\n## Common Workflow: Create Jira Issues On DAG Or Task Failure\n\nThe notifier helper is the cleanest way to open Jira tickets from `on_failure_callback` hooks.\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.atlassian.jira.notifications.jira import send_jira_notification\nfrom airflow.providers.standard.operators.bash import BashOperator\n\n\nwith DAG(\n    dag_id=\"jira_failure_notifier_demo\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n    on_failure_callback=[\n        send_jira_notification(\n            jira_conn_id=\"jira_default\",\n            description=\"Failure in DAG {{ dag.dag_id }}\",\n            summary=\"Airflow DAG failure\",\n            project_id=10000,\n            issue_type_id=10003,\n            labels=[\"airflow-dag-failure\"],\n        )\n    ],\n):\n    BashOperator(\n        task_id=\"fail_on_purpose\",\n        bash_command=\"exit 1\",\n        retries=0,\n        on_failure_callback=[\n            send_jira_notification(\n                jira_conn_id=\"jira_default\",\n                description=\"Task {{ ti.task_id }} failed in DAG {{ dag.dag_id }}\",\n                summary=\"Airflow task failure\",\n                project_id=10000,\n                issue_type_id=10003,\n                labels=[\"airflow-task-failure\"],\n            )\n        ],\n    )\n```\n\nUse this when the workflow should open a Jira issue automatically instead of adding Jira logic to the task body itself.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i jira\nairflow dags list | grep jira\n```\n\nTest a task in isolation while you wire up the connection and payload:\n\n```bash\nairflow tasks test jira_hook_issue_flow create_issue 2026-03-13\n```\n\nUse `airflow tasks test` while you are proving out connection settings, required Jira fields, and task-side logic. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, or downstream dependencies.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Reusing the discontinued `apache-airflow-providers-jira` package name. The maintained package is `apache-airflow-providers-atlassian-jira`.\n- Passing a Jira host without `http://` or `https://`.\n- Treating `verify` as a string in connection extras. In current provider releases it should be a boolean.\n- Assuming every Jira project accepts the same `fields` payload. Required fields and issue types vary by project configuration.\n- Passing a method name to `JiraOperator` that exists in some old Jira client examples but not in `atlassian-python-api`.\n- Returning full issue payloads or large search results through XCom instead of reducing them to keys, ids, counts, or summaries.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-atlassian-jira` version `3.3.1`.\n- `3.3.1` requires Apache Airflow `>=2.11.0`.\n- The `3.2.0` line added the async Jira notifier; `3.3.1` includes that notifier support.\n- The old `apache-airflow-providers-jira` package was discontinued. Its last release points users to `apache-airflow-providers-atlassian-jira`.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/`\n- Package index and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/index.html`\n- Jira connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/connections.html`\n- Jira notifications how-to: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/notifications/jira-notifier-howto-guide.html`\n- `JiraHook` API docs: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/_api/airflow/providers/atlassian/jira/hooks/jira/index.html`\n- `JiraOperator` API docs: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/_api/airflow/providers/atlassian/jira/operators/jira/index.html`\n- `JiraSensor` and `JiraTicketSensor` API docs: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/_api/airflow/providers/atlassian/jira/sensors/jira/index.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-atlassian-jira/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-atlassian-jira/`\n- Legacy provider package page: `https://pypi.org/project/apache-airflow-providers-jira/`\n- Atlassian Jira client methods used by the hook and operator: `https://atlassian-python-api.readthedocs.io/jira.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-celery/python/DOC.md",
    "content": "---\nname: providers-celery\ndescription: \"Apache Airflow Celery provider for CeleryExecutor-based task execution, workers, and Flower monitoring\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,celery,executor,workers,flower,distributed-tasks\"\n---\n\n# Apache Airflow Providers Celery Guide\n\nUse `apache-airflow-providers-celery` when an Airflow deployment needs distributed task execution through Celery workers instead of the default local executor model.\n\n## Golden Rule\n\n- Install this package alongside `apache-airflow`; it is not a standalone runtime.\n- Switch the executor only after you have a real metadata database plus a working Celery broker and result backend.\n- Run Airflow services and Celery workers as separate processes.\n- Keep DAG code and Airflow configuration consistent across the scheduler and worker environment.\n\n## What This Package Adds\n\nThis provider supplies Airflow's Celery integration, including:\n\n- `CeleryExecutor`\n- `CeleryKubernetesExecutor`\n- `airflow celery worker`\n- `airflow celery flower`\n\nIn normal DAG code you usually do not import from this provider directly. You install it so Airflow can load the executor and Celery-related CLI commands.\n\n## Install\n\nStart from a pinned Airflow installation that uses the official constraints file. Then install the provider in the same command so `pip` does not silently change your Airflow version.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=3.1.8\nPROVIDER_VERSION=3.17.0\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-celery==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep the Airflow package pinned when adding the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==3.1.8\" \\\n  \"apache-airflow-providers-celery==3.17.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep celery\nairflow config get-value core executor\n```\n\n## Minimal CeleryExecutor Configuration\n\nThis package is mainly configuration-driven. A practical starting point is PostgreSQL for the Airflow metadata database, Redis as the Celery broker, and PostgreSQL again for the Celery result backend.\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\n\nexport AIRFLOW__CORE__EXECUTOR=\"CeleryExecutor\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nexport AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=\"postgresql+psycopg2://airflow:secret@localhost:5432/airflow\"\n\nexport AIRFLOW__CELERY__BROKER_URL=\"redis://localhost:6379/0\"\nexport AIRFLOW__CELERY__RESULT_BACKEND=\"db+postgresql://airflow:secret@localhost:5432/airflow\"\n```\n\nImportant notes:\n\n- Do not use SQLite for a CeleryExecutor deployment.\n- `AIRFLOW__DATABASE__SQL_ALCHEMY_CONN` configures the Airflow metastore.\n- `AIRFLOW__CELERY__BROKER_URL` is where Celery workers receive tasks.\n- `AIRFLOW__CELERY__RESULT_BACKEND` is where task completion state is stored for Celery.\n\nIf you intentionally use the hybrid executor, set:\n\n```bash\nexport AIRFLOW__CORE__EXECUTOR=\"CeleryKubernetesExecutor\"\n```\n\n## Start The Services\n\nInitialize the database once:\n\n```bash\nairflow db migrate\n```\n\nThen run each component in its own terminal, container, or service unit:\n\n```bash\nairflow api-server --port 8080\n```\n\n```bash\nairflow scheduler\n```\n\n```bash\nairflow dag-processor\n```\n\n```bash\nairflow triggerer\n```\n\n```bash\nairflow celery worker\n```\n\nOptional monitoring UI:\n\n```bash\nairflow celery flower\n```\n\nOnce Flower is running, it is typically available on `http://localhost:5555`.\n\n## DAG Code Does Not Change\n\nThe provider changes how Airflow executes tasks, not how you author most DAGs. A normal TaskFlow DAG still works; the executor decides whether task instances run locally or through Celery workers.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import dag, task\n\n\n@dag(\n    dag_id=\"celery_demo\",\n    schedule=None,\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    catchup=False,\n    tags=[\"celery\"],\n)\ndef celery_demo():\n    @task()\n    def extract() -> dict[str, int]:\n        return {\"orders\": 3, \"returns\": 1}\n\n    @task()\n    def summarize(stats: dict[str, int]) -> str:\n        return f\"net={stats['orders'] - stats['returns']}\"\n\n    @task()\n    def emit(message: str) -> None:\n        print(message)\n\n    emit(summarize(extract()))\n\n\ncelery_demo()\n```\n\nPut the DAG in your configured DAGs folder, then check that Airflow can parse it:\n\n```bash\nairflow dags list\nairflow dags show celery_demo\n```\n\nTo execute it through the configured executor, trigger the DAG normally:\n\n```bash\nairflow dags trigger celery_demo\n```\n\n## Common Operational Checks\n\nConfirm the executor value:\n\n```bash\nairflow config get-value core executor\n```\n\nList installed providers:\n\n```bash\nairflow providers list | grep celery\n```\n\nLocal task debugging still works:\n\n```bash\nairflow tasks test celery_demo emit 2026-03-12\n```\n\nUse `airflow tasks test` for isolated task debugging. Use `airflow dags trigger` when you need the full scheduler plus Celery worker path.\n\n## Common Pitfalls\n\n- Installing the provider without `apache-airflow`: the provider extends Airflow; it does not replace it.\n- Forgetting to start a worker: tasks stay queued when the scheduler is healthy but no `airflow celery worker` process is consuming from the broker.\n- Mixing local-development defaults with a distributed executor: move off SQLite before enabling Celery.\n- Assuming DAG code needs provider-specific imports: most DAGs stay the same; the important change is executor configuration.\n- Debugging only with `airflow tasks test`: that command is useful, but it does not replace a real end-to-end run through the scheduler and workers.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-celery` version `3.17.0`.\n- The examples follow the Airflow 3 service layout and CLI, including `airflow api-server`, `airflow dag-processor`, and `airflow triggerer`.\n- If your deployment uses a different Airflow major or minor release, keep the Airflow package pinned when adding or upgrading this provider.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-cloudant/python/DOC.md",
    "content": "---\nname: providers-cloudant\ndescription: \"Apache Airflow IBM Cloudant provider for Cloudant connections and hook-based database operations from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,cloudant,ibm-cloudant,nosql,dag,python\"\n---\n\n# Apache Airflow Cloudant Provider Guide\n\nUse `apache-airflow-providers-cloudant` when an Airflow DAG needs to connect to IBM Cloudant through an Airflow connection and call Cloudant from Python task code with `CloudantHook`.\n\n## Golden Rule\n\n- Install this provider into the same environment as `apache-airflow`; it is not a standalone Cloudant client.\n- Put the Cloudant account and credentials on an Airflow connection with type `cloudant`.\n- Use `CloudantHook(...).get_conn()` inside task code, then call the returned IBM Cloudant SDK client with explicit `db=...` arguments.\n- Keep the database name in task code, an environment variable, or an Airflow Variable instead of relying on the connection `schema` field.\n\n## What This Package Adds\n\nThis provider exposes Airflow's Cloudant integration through:\n\n- `airflow.providers.cloudant.hooks.cloudant.CloudantHook`\n\nThere are no public Cloudant operators documented for this provider. The practical workflow is hook-based.\n\n## Install\n\nThe provider docs for `4.3.2` list these minimum requirements:\n\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-compat>=1.10.1`\n- `ibmcloudant>=0.10.0`\n\nInstall the provider in the same Python environment or container image used by your Airflow deployment. Keep Airflow pinned in the same command so `pip` does not silently replace core with another version.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.3.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-cloudant==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful check after installation:\n\n```bash\nairflow providers list | grep -i cloudant\n```\n\nPyPI lists provider `4.3.2` as supporting Python `3.10`, `3.11`, `3.12`, and `3.13`.\n\n## Configure A Cloudant Connection\n\nCreate an Airflow connection with connection type `cloudant`.\n\nAirflow's Cloudant connection UI relabels fields like this:\n\n- `Host` -> `Account`\n- `Login` -> `Username (or API Key)`\n- `Schema` -> `Database`\n\nA practical setup is to keep credentials in the Airflow connection and keep the database name separate:\n\n```bash\nexport CLOUDANT_ACCOUNT='your-account'\nexport CLOUDANT_USERNAME='your-username-or-api-key'\nexport CLOUDANT_PASSWORD='your-password-or-api-key-secret'\nexport CLOUDANT_DB='events'\n```\n\n```bash\nairflow connections add 'cloudant_default' \\\n  --conn-type 'cloudant' \\\n  --conn-host \"$CLOUDANT_ACCOUNT\" \\\n  --conn-login \"$CLOUDANT_USERNAME\" \\\n  --conn-password \"$CLOUDANT_PASSWORD\"\n```\n\nWhy keep `CLOUDANT_DB` separate: Airflow release notes for the provider explicitly say the hook no longer uses the connection `schema` attribute and the old `.db()` helper was removed.\n\n## Use `CloudantHook` In A Task\n\n`CloudantHook.get_conn()` returns the Cloudant client object used to call IBM Cloudant APIs. After that, use normal SDK methods such as `get_database_information`, `post_document`, `put_document`, and `post_all_docs`.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.cloudant.hooks.cloudant import CloudantHook\nfrom ibmcloudant.cloudant_v1 import Document\n\n\nwith DAG(\n    dag_id=\"cloudant_hook_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"cloudant\"],\n):\n    @task\n    def write_and_list() -> None:\n        db_name = os.environ[\"CLOUDANT_DB\"]\n        service = CloudantHook(cloudant_conn_id=\"cloudant_default\").get_conn()\n\n        db_info = service.get_database_information(db=db_name).get_result()\n        print({\"db_name\": db_info[\"db_name\"], \"doc_count\": db_info[\"doc_count\"]})\n\n        event_doc = Document(\n            type=\"event\",\n            source=\"airflow\",\n            status=\"queued\",\n        )\n        created = service.post_document(db=db_name, document=event_doc).get_result()\n        print(created)\n\n        rows = service.post_all_docs(\n            db=db_name,\n            include_docs=True,\n            limit=10,\n        ).get_result()\n\n        for row in rows.get(\"rows\", []):\n            print(row.get(\"id\"))\n\n    write_and_list()\n```\n\nThis is the usual pattern:\n\n1. Create `CloudantHook(cloudant_conn_id=\"...\")`\n2. Call `get_conn()`\n3. Pass `db=\"your-database\"` to each Cloudant SDK method\n\n## Common Workflow: Create Or Replace A Known Document\n\nUse `put_document()` when your DAG owns the document ID.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nfrom airflow.providers.cloudant.hooks.cloudant import CloudantHook\nfrom ibmcloudant.cloudant_v1 import Document\n\n\ndef upsert_status() -> None:\n    db_name = os.environ[\"CLOUDANT_DB\"]\n    service = CloudantHook(cloudant_conn_id=\"cloudant_default\").get_conn()\n\n    status_doc = Document(\n        type=\"job_status\",\n        airflow_dag_id=\"cloudant_hook_example\",\n        state=\"processed\",\n    )\n\n    response = service.put_document(\n        db=db_name,\n        doc_id=\"job-status:cloudant_hook_example\",\n        document=status_doc,\n    ).get_result()\n\n    print(response)\n```\n\n## Common Workflow: Bulk Write Documents\n\nUse `post_bulk_docs()` when one task needs to write many documents in one request.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nfrom airflow.providers.cloudant.hooks.cloudant import CloudantHook\nfrom ibmcloudant.cloudant_v1 import BulkDocs, Document\n\n\ndef write_batch() -> None:\n    db_name = os.environ[\"CLOUDANT_DB\"]\n    service = CloudantHook(cloudant_conn_id=\"cloudant_default\").get_conn()\n\n    docs = BulkDocs(\n        docs=[\n            Document(_id=\"event-1\", type=\"event\", status=\"queued\"),\n            Document(_id=\"event-2\", type=\"event\", status=\"queued\"),\n        ]\n    )\n\n    response = service.post_bulk_docs(\n        db=db_name,\n        bulk_docs=docs,\n    ).get_result()\n\n    print(response)\n```\n\n## Query And Pagination Notes\n\nThe Cloudant SDK supports selector queries with `post_find(...)` and pagination helpers in `ibmcloudant`.\n\nIBM's Cloudant docs explicitly recommend the SDK pagination helpers instead of paginating with `skip` or offsets.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nfrom airflow.providers.cloudant.hooks.cloudant import CloudantHook\nfrom ibmcloudant import Pagination, PagerType\n\n\ndef iterate_matches() -> None:\n    db_name = os.environ[\"CLOUDANT_DB\"]\n    service = CloudantHook(cloudant_conn_id=\"cloudant_default\").get_conn()\n\n    opts = {\n        \"db\": db_name,\n        \"limit\": 50,\n        \"fields\": [\"_id\", \"type\", \"status\"],\n        \"selector\": {\"status\": {\"$eq\": \"queued\"}},\n    }\n\n    pagination = Pagination.new_pagination(\n        service,\n        PagerType.POST_FIND,\n        **opts,\n    )\n\n    for row in pagination.rows():\n        print(row)\n```\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Scheduler, workers, and local test environments all need `apache-airflow-providers-cloudant` if they import `airflow.providers.cloudant`.\n- Do not rely on the connection `schema` field to pick the database. Provider release notes say the hook no longer uses `schema`, and the old `.db()` helper was removed.\n- Pass `db=...` explicitly to Cloudant SDK methods like `get_database_information`, `post_document`, `put_document`, and `post_all_docs`.\n- Keep result sizes bounded. IBM Cloudant documents request classes and rate limits; large unbounded reads in scheduled DAGs are easy to turn into noisy tasks.\n- Prefer SDK pagination helpers over `skip` for repeated reads. IBM Cloudant documents both correctness and performance problems with `skip`-based pagination.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-cloudant` version `4.3.2`.\n- The provider docs list `apache-airflow>=2.11.0` as the minimum supported Airflow version for this release.\n- PyPI lists Python `3.10` through `3.13` for this provider release.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-cloudant/stable/`\n- Provider index / API surface: `https://airflow.apache.org/docs/apache-airflow-providers-cloudant/stable/genindex.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-cloudant/`\n- IBM Cloudant API docs: `https://cloud.ibm.com/apidocs/cloudant?code=python`\n- Airflow provider release notes covering the Cloudant hook changes: `https://airflow.apache.org/docs/apache-airflow/2.10.4/release_notes.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-cncf-kubernetes/python/DOC.md",
    "content": "---\nname: providers-cncf-kubernetes\ndescription: \"Apache Airflow Kubernetes provider for launching pods from DAGs and accessing Kubernetes clusters\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.13.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,kubernetes,cncf,python,dag,operator\"\n---\n\n# apache-airflow-providers-cncf-kubernetes\n\nUse `apache-airflow-providers-cncf-kubernetes` when an Airflow DAG needs to start work in Kubernetes instead of running everything directly inside the Airflow worker process. The provider's main entry point is `KubernetesPodOperator`.\n\nThis guide targets provider version `10.13.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-cncf-kubernetes` is an Apache Airflow provider package. Install it when DAG tasks need to:\n\n- create and monitor Kubernetes pods from Airflow\n- authenticate with a cluster using in-cluster credentials, a kubeconfig file, or an Airflow Kubernetes connection\n- pass environment variables and small result payloads between Airflow and containerized task code\n\nThis package extends Airflow. It is not a general replacement for using the Kubernetes Python client directly in a standalone application.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-cncf-kubernetes==10.13.0\"\n```\n\nIf you add providers after Airflow is already installed, pin your Airflow version in the same command so dependency resolution does not silently change the core package version used by your deployment:\n\n```bash\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-cncf-kubernetes==10.13.0\"\n```\n\nIn practice, the scheduler, workers, and any other Airflow runtime that imports DAG code need the provider available.\n\n## Prerequisites\n\nBefore using the provider, make sure:\n\n- the Airflow runtime that executes the task can reach the Kubernetes API server\n- that runtime has credentials with permission to create pods in the target namespace\n- the container image you reference already contains the commands and libraries the task needs\n- you choose one cluster-auth pattern for the task: in-cluster auth, a kubeconfig file, or an Airflow connection\n\nFor local or out-of-cluster development, a kubeconfig file is the simplest option:\n\n```bash\nexport KUBECONFIG=\"$HOME/.kube/config\"\nexport APP_ENV=\"dev\"\n```\n\nWhen Airflow itself runs inside Kubernetes, use the pod's service account and set `in_cluster=True` instead of relying on `KUBECONFIG`.\n\n## Configure Cluster Access\n\nThe provider supports three practical configuration patterns for `KubernetesPodOperator`.\n\n### 1. Use an in-cluster service account\n\nUse this when the Airflow scheduler or worker is already running inside the same cluster or a network-reachable cluster with mounted service-account credentials:\n\n```python\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\n\n\nrun_in_cluster = KubernetesPodOperator(\n    task_id=\"run_in_cluster\",\n    name=\"run-in-cluster\",\n    namespace=\"airflow\",\n    image=\"python:3.12-slim\",\n    cmds=[\"python\", \"-c\"],\n    arguments=[\"print('hello from in-cluster auth')\"],\n    in_cluster=True,\n    get_logs=True,\n    on_finish_action=\"delete_pod\",\n)\n```\n\n### 2. Use a kubeconfig file\n\nUse this when Airflow runs outside the cluster and you already have a working kubeconfig:\n\n```python\nimport os\n\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\n\n\nKUBECONFIG = os.environ[\"KUBECONFIG\"]\n\n\nrun_with_kubeconfig = KubernetesPodOperator(\n    task_id=\"run_with_kubeconfig\",\n    name=\"run-with-kubeconfig\",\n    namespace=\"default\",\n    image=\"python:3.12-slim\",\n    cmds=[\"python\", \"-c\"],\n    arguments=[\"print('hello from kubeconfig auth')\"],\n    in_cluster=False,\n    config_file=KUBECONFIG,\n    cluster_context=\"dev-cluster\",\n    get_logs=True,\n    on_finish_action=\"delete_pod\",\n)\n```\n\nOmit `cluster_context` if the kubeconfig's current context is already the one you want.\n\n### 3. Use an Airflow Kubernetes connection\n\nUse this when you want Airflow to centralize cluster settings instead of hard-coding them in each DAG:\n\n```python\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\n\n\nrun_with_connection = KubernetesPodOperator(\n    task_id=\"run_with_connection\",\n    name=\"run-with-connection\",\n    namespace=\"default\",\n    image=\"alpine:3.20\",\n    cmds=[\"sh\", \"-c\"],\n    arguments=[\"echo connected through kubernetes_default\"],\n    kubernetes_conn_id=\"kubernetes_default\",\n    get_logs=True,\n    on_finish_action=\"delete_pod\",\n)\n```\n\nPick one approach per task. Avoid mixing a connection, `config_file`, and `in_cluster=True` in the same operator unless you have a specific reason and understand which settings should win.\n\n## Minimal `KubernetesPodOperator` DAG\n\nThis is the smallest useful pattern for running code in a Kubernetes pod from Airflow:\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\nfrom pendulum import datetime\n\n\nKUBECONFIG = os.environ.get(\"KUBECONFIG\", os.path.expanduser(\"~/.kube/config\"))\n\n\nwith DAG(\n    dag_id=\"kubernetes_pod_basic\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"kubernetes\"],\n) as dag:\n    run_python = KubernetesPodOperator(\n        task_id=\"run_python\",\n        name=\"run-python\",\n        namespace=\"default\",\n        image=\"python:3.12-slim\",\n        cmds=[\"python\", \"-c\"],\n        arguments=[\"import os; print(f\\\"APP_ENV={os.environ['APP_ENV']}\\\")\"],\n        env_vars={\"APP_ENV\": os.environ.get(\"APP_ENV\", \"dev\")},\n        in_cluster=False,\n        config_file=KUBECONFIG,\n        get_logs=True,\n        on_finish_action=\"delete_pod\",\n    )\n```\n\nKey arguments in everyday use:\n\n- `image` selects the container image to run\n- `cmds` and `arguments` define the command executed inside the container\n- `namespace` controls where the pod is created\n- `env_vars` passes non-secret environment variables into the container\n- `get_logs=True` streams container logs into the Airflow task log\n- `on_finish_action=\"delete_pod\"` cleans up the pod after the task finishes\n\n## Return Small Results Through XCom\n\nIf the pod needs to return a small structured result to downstream tasks, enable XCom and write valid JSON to `/airflow/xcom/return.json` inside the container:\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\nfrom pendulum import datetime\n\n\nKUBECONFIG = os.environ.get(\"KUBECONFIG\", os.path.expanduser(\"~/.kube/config\"))\n\n\nwith DAG(\n    dag_id=\"kubernetes_pod_xcom\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    write_xcom = KubernetesPodOperator(\n        task_id=\"write_xcom\",\n        name=\"write-xcom\",\n        namespace=\"default\",\n        image=\"alpine:3.20\",\n        cmds=[\"sh\", \"-c\"],\n        arguments=[\n            \"mkdir -p /airflow/xcom && \"\n            \"echo '{\\\"status\\\":\\\"ok\\\",\\\"records\\\":3}' > /airflow/xcom/return.json\"\n        ],\n        do_xcom_push=True,\n        in_cluster=False,\n        config_file=KUBECONFIG,\n        get_logs=True,\n        on_finish_action=\"delete_pod\",\n    )\n```\n\nUse this for small metadata, not for large datasets. For anything substantial, write to object storage, a database, or another external system and pass only the reference through XCom.\n\n## Use A Full Pod Spec For Advanced Pod Configuration\n\nWhen simple operator arguments are not enough, pass a Kubernetes API object through `full_pod_spec`:\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator\nfrom kubernetes.client import models as k8s\nfrom pendulum import datetime\n\n\nKUBECONFIG = os.environ.get(\"KUBECONFIG\", os.path.expanduser(\"~/.kube/config\"))\n\n\npod = k8s.V1Pod(\n    metadata=k8s.V1ObjectMeta(name=\"full-spec-demo\", namespace=\"default\"),\n    spec=k8s.V1PodSpec(\n        restart_policy=\"Never\",\n        containers=[\n            k8s.V1Container(\n                name=\"main\",\n                image=\"alpine:3.20\",\n                command=[\"sh\", \"-c\", \"echo hello from full pod spec\"],\n            )\n        ],\n    ),\n)\n\n\nwith DAG(\n    dag_id=\"kubernetes_pod_full_spec\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_full_spec = KubernetesPodOperator(\n        task_id=\"run_full_spec\",\n        full_pod_spec=pod,\n        in_cluster=False,\n        config_file=KUBECONFIG,\n        get_logs=True,\n        on_finish_action=\"delete_pod\",\n    )\n```\n\nUse this pattern when you need pod-level fields that are awkward to express through top-level operator arguments.\n\n## Common Pitfalls\n\n- Be explicit about `namespace`. Relying on defaults makes DAGs harder to move across environments.\n- Put the provider in every Airflow runtime that parses or executes the DAG, not only on your local machine.\n- Keep secrets in Kubernetes secrets or Airflow connections instead of hard-coding them in DAG files or `env_vars`.\n- Use `get_logs=True` during development so container output appears in task logs.\n- Use `on_finish_action=\"delete_pod\"` for normal runs, but switch to a keep-pod workflow when you need to inspect a failed pod interactively.\n- Keep XCom payloads small and JSON-serializable.\n\n## Operational Checks\n\nConfirm the provider is installed:\n\n```bash\npython -m pip show apache-airflow-providers-cncf-kubernetes\n```\n\nList provider packages visible to Airflow:\n\n```bash\nairflow providers list | rg cncf\n```\n\nIf Airflow cannot create pods, check these first:\n\n- the task log for Kubernetes API auth or RBAC errors\n- whether the target namespace exists\n- whether the image can be pulled from the cluster\n- whether the kubeconfig, connection, or service account is available in the actual runtime that executes the task\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-cohere/python/DOC.md",
    "content": "---\nname: providers-cohere\ndescription: \"Apache Airflow Cohere provider for generating embeddings with Airflow operators and hooks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,cohere,embeddings,llm,dag\"\n---\n\n# Apache Airflow Cohere Provider Python Guide\n\n## Golden Rule\n\n`apache-airflow-providers-cohere` is an Airflow provider package, not a standalone Cohere SDK. Install it into an existing Airflow environment, configure a `Cohere` connection with your API key in the connection password field, and use it for embedding tasks inside DAGs.\n\nThis provider is small by design:\n\n- `airflow.providers.cohere.operators.embedding.CohereEmbeddingOperator`\n- `airflow.providers.cohere.hooks.cohere.CohereHook`\n\nIf you need other Cohere endpoints or more control over embedding parameters than this provider exposes, call the Cohere Python SDK directly inside a Python task or write a custom operator.\n\n## Install\n\nThe provider requires:\n\n- Python 3.10 to 3.13\n- `apache-airflow>=2.11.0`\n- `cohere>=5.13.4`\n\nInstall the provider into the same virtual environment as Airflow. Pin your Airflow version in the same command so the resolver does not silently replace core:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-cohere==1.6.2\"\n```\n\nIf your environment runs Python 3.13, version `1.6.2` also includes the provider's `fastavro>=1.10.0` compatibility fix.\n\nUseful check after installation:\n\n```bash\nairflow providers list | grep -i cohere\n```\n\n## Configure A Cohere Connection\n\nThe provider's default connection ID is `cohere_default`.\n\nIn the Airflow UI, create a connection with:\n\n- Connection Type: `Cohere`\n- Connection ID: `cohere_default`\n- Password: your Cohere API key\n- Host: optional base URL override\n\nOnly `password` and `host` are used by the hook. The hook maps them to:\n\n- `password` -> `api_key`\n- `host` -> `base_url`\n\nIf you prefer environment variables, Airflow supports JSON-formatted connections:\n\n```bash\nexport AIRFLOW_CONN_COHERE_DEFAULT='{\n  \"conn_type\": \"cohere\",\n  \"password\": \"your-cohere-api-key\"\n}'\n```\n\nIf you need to point at a non-default Cohere API base URL, add `host`:\n\n```bash\nexport AIRFLOW_CONN_COHERE_STAGING='{\n  \"conn_type\": \"cohere\",\n  \"password\": \"your-cohere-api-key\",\n  \"host\": \"https://api.cohere.com\"\n}'\n```\n\nPractical notes:\n\n- Environment-defined connections are available at runtime but do not appear in the Airflow UI or `airflow connections list`.\n- Keep API keys in environment variables or a secrets backend, not in DAG files.\n- If you use a connection ID other than `cohere_default`, pass it explicitly as `conn_id=...`.\n\n## Create Embeddings With `CohereEmbeddingOperator`\n\nUse `CohereEmbeddingOperator` when a DAG step needs embeddings and returning `list[list[float]]` through XCom is acceptable.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG, task\nfrom airflow.providers.cohere.operators.embedding import CohereEmbeddingOperator\n\nwith DAG(\n    dag_id=\"cohere_embeddings_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"cohere\", \"embeddings\"],\n) as dag:\n    embed_documents = CohereEmbeddingOperator(\n        task_id=\"embed_documents\",\n        conn_id=\"cohere_default\",\n        input_text=[\n            \"Airflow provider packages extend Airflow with external integrations.\",\n            \"Cohere embeddings can be stored in a vector database for retrieval.\",\n        ],\n        request_options={\n            \"timeout_in_seconds\": 30,\n            \"max_retries\": 2,\n        },\n    )\n\n    @task\n    def inspect_vectors(vectors: list[list[float]]) -> None:\n        print(f\"embedded {len(vectors)} texts\")\n        print(f\"first vector length: {len(vectors[0])}\")\n\n    inspect_vectors(embed_documents.output)\n```\n\nBehavior that matters:\n\n- `input_text` can be a single string or a list of strings.\n- The operator normalizes a single string to a one-item list.\n- The return value is a `list[list[float]]`, which makes it easier to pass through XCom than a complex Cohere response object.\n- `input_text` is a templated field, so you can render it from params, macros, or mapped task inputs.\n\n## Use `CohereHook` Inside Python Tasks\n\nUse the hook when a Python task needs a cached Cohere client or when you want to keep embedding logic inside normal task code.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG, task\nfrom airflow.providers.cohere.hooks.cohere import CohereHook\n\nwith DAG(\n    dag_id=\"cohere_hook_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"cohere\", \"hook\"],\n) as dag:\n    @task\n    def embed_query() -> list[list[float]]:\n        hook = CohereHook(\n            conn_id=\"cohere_default\",\n            request_options={\"timeout_in_seconds\": 15, \"max_retries\": 2},\n        )\n        return hook.create_embeddings(\n            [\"What changed in apache-airflow-providers-cohere 1.6.2?\"]\n        )\n\n    embed_query()\n```\n\nThe hook creates a `cohere.ClientV2` with the connection password as the API key and the connection host as the optional base URL override.\n\n## What The Provider Actually Sends\n\nThe implementation is opinionated. `CohereHook.create_embeddings(...)` sends:\n\n- `model=\"embed-multilingual-v3.0\"` by default\n- `input_type=\"search_document\"`\n- `embedding_types=[\"float\"]`\n\nThis has two important consequences:\n\n- `CohereEmbeddingOperator` does not expose a `model` argument and always calls the hook with its defaults.\n- The provider is suited to document-style embeddings, not arbitrary access to every Cohere embeddings option.\n\nIf you need a different model, a different `input_type`, or other Cohere API surfaces such as chat or generation, this provider is not enough on its own. Use the Cohere SDK directly in a task or extend the provider.\n\n## Common Pattern: Feed Embeddings To A Downstream Task\n\nBecause the operator returns plain float vectors, the common Airflow pattern is:\n\n1. generate embeddings with `CohereEmbeddingOperator`\n2. transform them in a Python task\n3. write them to your database or vector store in another task/operator\n\nKeep the payload size in mind. Large embedding batches can make XCom heavy; for bigger corpora, batch the work or persist outputs outside XCom.\n\n## Pitfalls\n\n- This package does not install Airflow for you. Install `apache-airflow` first or pin it in the same `pip install` command.\n- The provider supports Airflow `2.11.0+` only. That minimum changed in provider `1.6.0`.\n- `max_retries` on `CohereHook` and `CohereEmbeddingOperator` is deprecated. Prefer `request_options={\"max_retries\": ...}`.\n- The connection test in `CohereHook.test_connection()` uses the chat API with model `command-r-plus-08-2024`, not the embedding endpoint. A failed UI connection test can therefore reflect chat-model access rather than a broken embeddings configuration.\n- Only the connection password and optional host are used by the hook. Do not expect login, schema, port, or extra fields to affect requests.\n- If you define the connection through `AIRFLOW_CONN_...`, it will not show up in the Airflow UI.\n\n## Version Notes For `1.6.2`\n\n- `1.6.2` was released on February 2, 2026.\n- The `1.6.2` changelog entry is a Python 3.13 compatibility fix: minimum `fastavro` was pinned to `1.10.0`.\n- The provider's minimum supported Airflow version remains `2.11.0`.\n\n## Official Sources\n\n- Provider docs: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/\n- Provider package page: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/index.html\n- Cohere connection docs: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/connections.html\n- Cohere embedding operator guide: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/operators/embedding.html\n- `CohereHook` API reference: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/_api/airflow/providers/cohere/hooks/cohere/index.html\n- `CohereEmbeddingOperator` API reference: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/_api/airflow/providers/cohere/operators/embedding/index.html\n- `CohereHook` source docs: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/_modules/airflow/providers/cohere/hooks/cohere.html\n- `CohereEmbeddingOperator` source docs: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/_modules/airflow/providers/cohere/operators/embedding.html\n- Provider changelog: https://airflow.apache.org/docs/apache-airflow-providers-cohere/stable/changelog.html\n- PyPI package page: https://pypi.org/project/apache-airflow-providers-cohere/\n- Airflow connection management: https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-common-compat/python/DOC.md",
    "content": "---\nname: providers-common-compat\ndescription: \"Apache Airflow compatibility provider for shared sdk, standard operator, and version-gated imports across Airflow releases\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,providers,compatibility,operators,triggers,python\"\n---\n\n# Apache Airflow Common Compat Provider Guide\n\nUse `apache-airflow-providers-common-compat` when shared Airflow code needs one import path that works across supported Airflow releases. This package does not add a standalone service integration or its own authentication flow. It provides compatibility modules for base SDK classes, standard-provider operators and triggers, and version checks.\n\n## Golden Rule\n\n- Install this provider into the same environment as `apache-airflow`, with the official constraints file.\n- Use it for compatibility imports in shared libraries, custom providers, plugins, or DAG utilities that must support more than one Airflow line.\n- Do not expect a package-specific connection type, hook, or UI entry. It re-exports compatibility surfaces on top of Airflow and other providers.\n\n## Requirements\n\nThe provider docs list these package requirements:\n\n- `apache-airflow>=2.10.0`\n- `apache-airflow-providers-standard>=1.6.0`\n\nPyPI lists Python support as `>=3.10, <3.14`.\n\n## Install\n\nInstall Airflow and this provider together, pinned in the same command. Airflow recommends using the constraints file that matches your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"3.1.8\"\nPROVIDER_VERSION=\"1.14.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-common-compat==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after install:\n\n```bash\nairflow providers list | grep -i common.compat\npython -c \"from airflow.providers.common.compat.sdk import BaseHook, BaseOperator; print(BaseHook, BaseOperator)\"\n```\n\n## Initialization And Environment\n\nThere is no package-specific initialization step. Airflow discovers the provider from the Python environment used by the scheduler, dag processor, triggerer, API server, and workers.\n\nFor local development, initialize Airflow first:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nairflow db migrate\n```\n\nIf you use `airflow standalone`, install this provider before starting `standalone` so the local instance sees the same imports your DAG code will use.\n\n## Common Workflow: Import Base SDK Classes Through The Compat Layer\n\nThe `airflow.providers.common.compat.sdk` module exposes Airflow authoring classes such as `BaseHook`, `BaseOperator`, and `Context`.\n\nUse that module when you maintain custom code that should not hard-code different import paths per Airflow release.\n\n```python\nfrom __future__ import annotations\n\nfrom airflow.providers.common.compat.sdk import BaseOperator, Context\n\n\nclass EchoOperator(BaseOperator):\n    template_fields = (\"message\",)\n\n    def __init__(self, *, message: str, **kwargs) -> None:\n        super().__init__(**kwargs)\n        self.message = message\n\n    def execute(self, context: Context) -> str:\n        self.log.info(\"message=%s\", self.message)\n        return self.message\n```\n\nCustom hooks can use the same compat SDK import path:\n\n```python\nfrom airflow.providers.common.compat.sdk import BaseHook\n\n\nclass DemoHook(BaseHook):\n    conn_name_attr = \"demo_conn_id\"\n    default_conn_name = \"demo_default\"\n    conn_type = \"http\"\n    hook_name = \"Demo API\"\n\n    def __init__(self, demo_conn_id: str = \"demo_default\") -> None:\n        super().__init__()\n        self.demo_conn_id = demo_conn_id\n\n    def get_base_url(self) -> str:\n        connection = self.get_connection(self.demo_conn_id)\n        return connection.host\n```\n\n## Common Workflow: Branch On Airflow Version\n\nThe `airflow.providers.common.compat.version_compat` module exposes version flags including `AIRFLOW_V_3_0_PLUS` and `AIRFLOW_V_3_1_PLUS`.\n\nUse those flags when shared code must choose different imports or behavior for different Airflow major lines.\n\n```python\nfrom airflow.providers.common.compat.version_compat import AIRFLOW_V_3_0_PLUS\n\nif AIRFLOW_V_3_0_PLUS:\n    from airflow.sdk import Variable\nelse:\n    from airflow.models import Variable\n\n\ndeploy_env = Variable.get(\"deploy_env\", default=\"dev\")\n```\n\nKeep the version branching in one helper module rather than scattering `if AIRFLOW_V_3_0_PLUS` checks across many DAG files.\n\n## Common Workflow: Import Standard Provider Operators From A Stable Path\n\nThis provider also exposes compatibility imports for the standard provider, including `TriggerDagRunOperator`.\n\n```python\nfrom airflow.providers.common.compat.standard.operators import TriggerDagRunOperator\n\n\ntrigger_downstream = TriggerDagRunOperator(\n    task_id=\"trigger_downstream\",\n    trigger_dag_id=\"downstream_pipeline\",\n    conf={\"source\": \"compat-demo\"},\n    wait_for_completion=False,\n)\n```\n\nUse this import path when your reusable Airflow code needs one operator import that survives Airflow and standard-provider layout changes.\n\nFor deferrable workflows, the package also exposes trigger compatibility modules under `airflow.providers.common.compat.standard.triggers`.\n\n## Operational Checks\n\nAfter adding the package, confirm that the Airflow runtime can import it and that your DAGs parse cleanly:\n\n```bash\nairflow providers list | grep -i common.compat\nairflow dags list\n```\n\nTo debug an import problem in isolation:\n\n```bash\npython -c \"import airflow.providers.common.compat.standard.operators\"\npython -c \"from airflow.providers.common.compat.version_compat import AIRFLOW_V_3_0_PLUS; print(AIRFLOW_V_3_0_PLUS)\"\n```\n\nIf scheduler or worker containers use different images, install the same Airflow and provider pins in all of them.\n\n## Common Pitfalls\n\n- Installing the provider without pinning `apache-airflow` in the same constrained command.\n- Forgetting that the provider depends on `apache-airflow-providers-standard`; conflicts often surface there first.\n- Assuming the package adds a service connection, API client, or auth workflow. It does not.\n- Installing the package on the webserver image but not on workers, triggerers, or dag processors that import the same code.\n- Using compat imports everywhere when your code only targets one Airflow line and does not need cross-version support.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-common-compat` version `1.14.0`.\n- The Airflow `stable/` docs root moves as new provider releases ship. Check the package reference page and your pinned requirements before copying imports into long-lived libraries.\n- The provider requirement page is the authoritative place to confirm the minimum Airflow and companion-provider versions for your pin.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/index.html`\n- Package requirements and release page: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/index.html#requirements`\n- Package reference page: `https://airflow.apache.org/docs/apache-airflow-providers/packages-ref.html`\n- `sdk` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/_modules/airflow/providers/common/compat/sdk.html`\n- `version_compat` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/_modules/airflow/providers/common/compat/version_compat.html`\n- Standard operators source reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/_modules/airflow/providers/common/compat/standard/operators.html`\n- External-task trigger source reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-compat/stable/_modules/airflow/providers/common/compat/standard/triggers/external_task.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-common-compat/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-common-io/python/DOC.md",
    "content": "---\nname: providers-common-io\ndescription: \"Apache Airflow common.io provider for cross-filesystem transfers and object-store-backed XComs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.7.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,object-storage,file-transfer,xcom,s3\"\n---\n\n# Apache Airflow Common IO Provider Guide\n\nUse `apache-airflow-providers-common-io` when an Airflow deployment needs to copy files between the local filesystem and object storage, or when XCom payloads should spill to object storage instead of living entirely in the metadata database.\n\n## Golden Rule\n\n- Install this package into the same Airflow environment as your scheduler, workers, and any task runtime that imports DAG code.\n- Use `FileTransferOperator` for file copies and `XComObjectStorageBackend` for large XCom payloads.\n- Put credentials on Airflow connections and refer to storage locations with `ObjectStoragePath` or URL-style paths such as `s3://aws_default@bucket/key`.\n\n## Install\n\nThis provider release is `1.7.1`. The maintainer docs and PyPI page list these requirements:\n\n- Apache Airflow `>=2.11.0`\n- Python `3.10` through `3.13`\n\nIf you are adding the provider to an existing Airflow environment, install it with the Airflow version you already run:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-common-io==1.7.1\"\n```\n\nFor a reproducible fresh install from PyPI, Airflow recommends using its constraints file:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"3.1.8\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-common-io==1.7.1\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf your DAGs will access S3, GCS, Azure Blob, or another remote object store, install the matching provider too. For example, the Airflow object storage tutorial uses the Amazon provider plus `s3fs`:\n\n```bash\npython -m pip install \"apache-airflow-providers-amazon[s3fs]\"\n```\n\n## Connection And Path Setup\n\nThe common.io provider uses the connection id associated with the URL scheme or the connection id embedded in the object storage URL.\n\nFor S3-backed examples, a minimal environment looks like this:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nexport AIRFLOW_CONN_AWS_DEFAULT='aws://'\nexport AWS_DEFAULT_REGION='us-east-1'\n```\n\nImportant path rules from the maintainer docs:\n\n- `ObjectStoragePath(\"s3://aws_default@my-bucket/path/to/file.csv\")` embeds the Airflow connection id in the URL.\n- `ObjectStoragePath(\"s3://my-bucket/path/to/file.csv\", conn_id=\"aws_default\")` is also supported, and the keyword argument takes precedence.\n- If the connection id is omitted, Airflow falls back to the default connection for that backend.\n- Local paths use `file://` or `local://`.\n\n## Transfer A File\n\n`FileTransferOperator` accepts `src` and `dst` as either strings or `ObjectStoragePath` objects. If both paths are on the same object store, the provider copies within that object store. Otherwise it streams from source to destination.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.io.operators.file_transfer import FileTransferOperator\nfrom pendulum import datetime\n\ntry:\n    from airflow.sdk import ObjectStoragePath\nexcept ImportError:\n    from airflow.io.path import ObjectStoragePath\n\nLOCAL_REPORT = ObjectStoragePath(\"file:///opt/airflow/data/report.csv\")\nS3_REPORT = ObjectStoragePath(\"s3://aws_default@my-example-bucket/reports/report.csv\")\n\nwith DAG(\n    dag_id=\"common_io_local_to_s3\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    transfer_report = FileTransferOperator(\n        task_id=\"transfer_report\",\n        src=LOCAL_REPORT,\n        dst=S3_REPORT,\n        overwrite=True,\n    )\n```\n\nPractical notes:\n\n- `overwrite` defaults to `False`.\n- `src` and `dst` are templated fields, so Jinja-templated paths are supported.\n- The official system test uses the same pattern with a local `file:///tmp/...` source and an `s3://...` destination.\n\n## Use Object Storage For Large XComs\n\nSet Airflow's XCom backend to `airflow.providers.common.io.xcom.backend.XComObjectStorageBackend` when task return values are too large for the metadata database alone.\n\n```bash\nexport AIRFLOW__CORE__XCOM_BACKEND='airflow.providers.common.io.xcom.backend.XComObjectStorageBackend'\nexport AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_PATH='s3://aws_default@my-example-bucket/airflow-xcom'\nexport AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_THRESHOLD='1048576'\nexport AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_COMPRESSION='gzip'\n```\n\nWhat these settings do:\n\n- `AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_PATH`: object-store location for spilled XCom payloads\n- `AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_THRESHOLD`: `-1` keeps everything in the database, `0` stores everything in object storage, positive numbers create a hybrid setup\n- `AIRFLOW__COMMON_IO__XCOM_OBJECTSTORAGE_COMPRESSION`: optional compression such as `gzip`, `zip`, `bz2`, `lzma`, or `snappy`\n\nWith the backend configured, ordinary TaskFlow code does not need provider-specific XCom calls:\n\n```python\ntry:\n    from airflow.sdk import dag, task\nexcept ImportError:\n    from airflow.decorators import dag, task\n\nfrom pendulum import datetime\n\n\n@dag(\n    dag_id=\"common_io_xcom_backend\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n)\ndef common_io_xcom_backend():\n    @task\n    def produce_manifest() -> dict[str, list[int]]:\n        return {\"partitions\": list(range(10000))}\n\n    @task\n    def count_partitions(manifest: dict[str, list[int]]) -> int:\n        return len(manifest[\"partitions\"])\n\n    count_partitions(produce_manifest())\n\n\ncommon_io_xcom_backend()\n```\n\nAirflow stores only a reference in the metadata database when the serialized XCom value crosses the configured threshold.\n\n## Common Pitfalls\n\n- Do not install this provider only on the webserver image. The scheduler and every worker image that imports DAGs need it too.\n- For remote paths, install the provider for that protocol as well. `apache-airflow-providers-common-io` does not replace the Amazon, Google, or Azure providers.\n- `xcom_objectstorage_threshold` must be greater than `-1` before object storage is actually used.\n- Compression support depends on what is installed in the Python environment. `zip`, `gzip`, and `bz2` work out of the box; `snappy` needs `python-snappy`.\n- Airflow 3 examples import `ObjectStoragePath` and TaskFlow helpers from `airflow.sdk`. Airflow 2.11 still uses legacy import paths such as `airflow.io.path` and `airflow.decorators`.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-common-io==1.7.1`.\n- The stable provider docs for `1.7.1` require Apache Airflow `>=2.11.0`.\n- PyPI lists optional extras for `common.compat` and `openlineage` if your deployment needs those integrations.\n\n## Official Sources\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/`\n- Installation and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/index.html`\n- Transfer guide: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/transfer.html`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/operators.html`\n- `FileTransferOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/_api/airflow/providers/common/io/operators/file_transfer/index.html`\n- XCom backend guide: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/xcom_backend.html`\n- Provider configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/configurations-ref.html`\n- Official system test example: `https://airflow.apache.org/docs/apache-airflow-providers-common-io/stable/_modules/tests/system/common/io/example_file_transfer_local_to_s3.html`\n- Airflow object storage tutorial: `https://airflow.apache.org/docs/apache-airflow/stable/tutorial/objectstorage.html`\n- Airflow PyPI installation guide: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- Airflow Amazon connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-amazon/stable/connections/aws.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-common-io/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-common-sql/python/DOC.md",
    "content": "---\nname: providers-common-sql\ndescription: \"Apache Airflow common SQL provider for reusable SQL operators, data quality checks, inserts, transfers, and DbApiHook helpers across SQL backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.32.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,sql,database,data-quality,dag,python\"\n---\n\n# apache-airflow-providers-common-sql\n\nUse `apache-airflow-providers-common-sql` when your DAGs need Airflow's shared SQL operators and `DbApiHook` helpers across supported SQL backends. This package is the common layer used by many database-specific providers; it is not a standalone database client.\n\nThis guide targets provider version `1.32.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment.\n\nIf you are building a fresh Airflow environment, install Airflow first with the official constraints file, then add the provider:\n\n```bash\nAIRFLOW_VERSION=3.1.8\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-common-sql==1.32.0\"\n```\n\nIf you are adding the provider to an existing Airflow environment, keep `apache-airflow` pinned in the same command so dependency resolution does not silently change your Airflow core version:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-common-sql==1.32.0\"\n```\n\nDataFrame helpers need optional extras:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-common-sql[pandas]==1.32.0\"\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-common-sql[polars]==1.32.0\"\n```\n\nUpstream documents `apache-airflow>=2.11.0` as the minimum compatible Airflow version for this provider.\n\n## Configure Airflow Connections\n\n`apache-airflow-providers-common-sql` does not introduce its own database connection type. Instead, its operators and hooks work through an Airflow connection that is backed by a database-specific provider such as Postgres, MySQL, MsSQL, or SQLite.\n\nFor example, with a PostgreSQL connection:\n\n```bash\nexport AIRFLOW_CONN_WAREHOUSE='postgresql://airflow:secret@db.example.com:5432/warehouse'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `warehouse`\n- common SQL operators use `conn_id=\"warehouse\"`\n- the matching database provider package still needs to be installed anywhere your DAG code runs\n\nKeep credentials in Airflow connections, environment variables, or a secrets backend instead of hard-coding them in DAG files.\n\n## Run SQL With `SQLExecuteQueryOperator`\n\nUse `SQLExecuteQueryOperator` for normal DDL, DML, and query tasks that only need SQL.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"common_sql_execute_query\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"warehouse\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id BIGINT PRIMARY KEY,\n            event_type TEXT NOT NULL,\n            created_at TIMESTAMP NOT NULL\n        )\n        \"\"\",\n    )\n\n    insert_seed_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_seed_rows\",\n        conn_id=\"warehouse\",\n        sql=\"\"\"\n        INSERT INTO events (id, event_type, created_at)\n        VALUES\n            (1, 'signup', CURRENT_TIMESTAMP),\n            (2, 'purchase', CURRENT_TIMESTAMP)\n        \"\"\",\n    )\n\n    create_table >> insert_seed_rows\n```\n\nUseful options from the provider docs:\n\n- pass `parameters={...}` to bind query parameters\n- set `split_statements=True` when `sql` contains multiple statements\n- set `handler=None` when you do not need query results returned\n- set `return_last=False` if you need all result sets instead of only the last one\n\n## Insert Python Rows With `SQLInsertRowsOperator`\n\nUse `SQLInsertRowsOperator` when you already have rows in Python and want the provider hook to insert them.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLInsertRowsOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"common_sql_insert_rows\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    load_daily_metrics = SQLInsertRowsOperator(\n        task_id=\"load_daily_metrics\",\n        conn_id=\"warehouse\",\n        table_name=\"daily_metrics\",\n        rows=[\n            (\"2026-03-13\", \"signup\", 41),\n            (\"2026-03-13\", \"purchase\", 7),\n        ],\n        target_fields=[\"ds\", \"metric_name\", \"metric_value\"],\n    )\n```\n\n`insert_args` are passed through to the underlying database hook, so keep them limited to options that your database-specific provider documents.\n\n## Add Data Quality Checks\n\nThe provider includes reusable check operators for table-level and column-level assertions.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import (\n    SQLColumnCheckOperator,\n    SQLTableCheckOperator,\n)\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"common_sql_quality_checks\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    column_checks = SQLColumnCheckOperator(\n        task_id=\"column_checks\",\n        conn_id=\"warehouse\",\n        table=\"daily_metrics\",\n        column_mapping={\n            \"metric_value\": {\n                \"null_check\": {\"equal_to\": 0},\n                \"min\": {\"greater_than\": 0},\n            }\n        },\n    )\n\n    table_checks = SQLTableCheckOperator(\n        task_id=\"table_checks\",\n        conn_id=\"warehouse\",\n        table=\"daily_metrics\",\n        checks={\n            \"has_rows\": {\"check_statement\": \"COUNT(*) > 0\"},\n            \"signup_rows_present\": {\n                \"check_statement\": \"SUM(CASE WHEN metric_name = 'signup' THEN 1 ELSE 0 END) > 0\"\n            },\n        },\n    )\n\n    column_checks >> table_checks\n```\n\nImportant behavior from the provider docs:\n\n- `partition_clause` can be set at the operator, column, or individual check level\n- `accept_none=True` is the default for `SQLColumnCheckOperator`, so `None` results are converted to `0`\n- table checks can be partitioned the same way as column checks when you need date-scoped assertions\n\n## Move Data Between Connections With `GenericTransfer`\n\n`GenericTransfer` copies rows from one Airflow SQL connection to another by reading from a source hook and writing to a destination hook.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.generic_transfer import GenericTransfer\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"common_sql_transfer\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    copy_active_users = GenericTransfer(\n        task_id=\"copy_active_users\",\n        source_conn_id=\"warehouse\",\n        destination_conn_id=\"reporting\",\n        sql=\"SELECT id, email FROM users WHERE is_active = true\",\n        destination_table=\"active_users\",\n        preoperator=\"TRUNCATE TABLE active_users\",\n    )\n```\n\nUpstream notes that `GenericTransfer` reads all rows into memory before writing them out, so use it for small to moderate result sets rather than very large table copies.\n\n## Use DataFrame Helpers From Compatible Hooks\n\nWhen a database-specific Airflow hook subclasses `DbApiHook`, the common SQL provider adds DataFrame helpers such as `get_df(...)` and `get_df_by_chunks(...)`.\n\nFor example, with a database hook that supports the common SQL interface:\n\n```python\nimport pandas as pd\nfrom airflow.providers.postgres.hooks.postgres import PostgresHook\n\n\nhook = PostgresHook(postgres_conn_id=\"warehouse\")\n\ndf = hook.get_df(\n    \"SELECT metric_name, metric_value FROM daily_metrics WHERE ds = %(ds)s\",\n    parameters={\"ds\": \"2026-03-13\"},\n    df_type=\"pandas\",\n)\n\nfor chunk in hook.get_df_by_chunks(\n    \"SELECT * FROM daily_metrics\",\n    chunksize=1000,\n    df_type=\"pandas\",\n):\n    assert isinstance(chunk, pd.DataFrame)\n    print(len(chunk))\n```\n\nInstall the matching extra first:\n\n- `apache-airflow-providers-common-sql[pandas]` for `df_type=\"pandas\"`\n- `apache-airflow-providers-common-sql[polars]` for `df_type=\"polars\"`\n\n## Pitfalls\n\n- Install the package everywhere DAG code runs. If one scheduler, worker, or image is missing it, imports like `airflow.providers.common.sql...` will fail.\n- Install the matching database provider too. `apache-airflow-providers-common-sql` gives you shared operators and hook helpers, but your actual database connection type still comes from a provider such as Postgres, MySQL, MsSQL, or SQLite.\n- Set `conn_id` explicitly in each task. Do not rely on implicit defaults across different DAGs or providers.\n- Use `handler=None` for `SQLExecuteQueryOperator` when you only care about side effects and do not need rows returned.\n- Review `accept_none` on column checks. The default is helpful for empty partitions, but it can also hide missing data if you expected the query to return a real value.\n- Use `GenericTransfer` only when the selected result set fits comfortably in worker memory.\n\n## Version Notes For `1.32.0`\n\n- The official `1.32.0` release notes include a new `@task.sql` decorator.\n- The same release adds hook-level OpenLineage support.\n- The release notes also bump the minimum SQLAlchemy version to `1.4.54`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/`\n- Supported database types: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/supported_db.html`\n- SQL operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/operators.html`\n- DataFrame integration: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/dataframes.html`\n- `DbApiHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/_api/airflow/providers/common/sql/hooks/sql/index.html`\n- Release notes: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/commits.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-common-sql/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-daskexecutor/python/DOC.md",
    "content": "---\nname: providers-daskexecutor\ndescription: \"Apache Airflow Dask executor provider for running Airflow 2 tasks on a Dask Distributed cluster\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,dask,executor,distributed-tasks\"\n---\n\n# Apache Airflow Providers DaskExecutor Guide\n\nUse `apache-airflow-providers-daskexecutor` when you need an Airflow 2 deployment to submit task execution to a Dask Distributed cluster instead of running tasks locally.\n\n## Golden Rule\n\n- Treat this package as a legacy Airflow 2 provider.\n- Install it on top of an existing `apache-airflow` installation; it is not a standalone runtime.\n- Configure the executor and Dask cluster in Airflow config instead of importing provider-specific APIs in DAG code.\n- Make sure every Dask worker can import Airflow and every Python dependency your tasks need.\n\n## What This Package Adds\n\nThis provider publishes the `DaskExecutor` class in the `airflow.providers.daskexecutor` package.\n\nOperationally, that means:\n\n- Airflow's scheduler hands task execution off to a Dask Distributed scheduler\n- Dask workers run the Airflow task subprocesses\n- DAG code usually stays normal Airflow DAG code\n\nThere is no provider client to initialize in your DAG files. Airflow initializes the Dask client from your executor configuration.\n\n## Install\n\nInstall Airflow first, then add the provider package to the same environment.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"2.11.1\"  # replace with the Airflow 2.x version your deployment already uses\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-daskexecutor==1.1.1\"\n```\n\nPublished package requirements for `1.1.1`:\n\n- `apache-airflow >= 2.5.0`\n- `cloudpickle >= 1.4.1`\n- `dask >= 2.9.0, !=2022.10.1, !=2023.5.0`\n- `distributed >= 2.11.1, !=2023.5.0`\n\nUseful checks:\n\n```bash\npython -m pip show apache-airflow-providers-daskexecutor\nairflow providers list | grep daskexecutor\n```\n\n## Configure The Executor\n\nThe provider's executor class is `airflow.providers.daskexecutor.executors.dask_executor.DaskExecutor`. In practice, configure Airflow to use that full class path and provide the Dask scheduler address in the `[dask]` section.\n\nEnvironment-variable form:\n\n```bash\nexport AIRFLOW__CORE__EXECUTOR=\"airflow.providers.daskexecutor.executors.dask_executor.DaskExecutor\"\nexport AIRFLOW__DASK__CLUSTER_ADDRESS=\"127.0.0.1:8786\"\n```\n\nEquivalent `airflow.cfg` settings:\n\n```ini\n[core]\nexecutor = airflow.providers.daskexecutor.executors.dask_executor.DaskExecutor\n\n[dask]\ncluster_address = 127.0.0.1:8786\n```\n\nOptional TLS settings supported by the executor:\n\n```bash\nexport AIRFLOW__DASK__TLS_CA=\"/etc/ssl/certs/dask-ca.pem\"\nexport AIRFLOW__DASK__TLS_CERT=\"/etc/ssl/certs/dask-client.pem\"\nexport AIRFLOW__DASK__TLS_KEY=\"/etc/ssl/private/dask-client.key\"\n```\n\nThe executor reads `cluster_address`, `tls_ca`, `tls_cert`, and `tls_key` from the `[dask]` config section.\n\n## Start A Dask Cluster\n\nFor a minimal local cluster, start a scheduler first:\n\n```bash\nexport DASK_HOST=127.0.0.1\nexport DASK_PORT=8786\n\ndask-scheduler --host \"$DASK_HOST\" --port \"$DASK_PORT\"\n```\n\nThen start at least one worker that can reach that scheduler:\n\n```bash\ndask-worker \"$DASK_HOST:$DASK_PORT\"\n```\n\nImportant runtime rule:\n\n- Each Dask worker must be able to import Airflow and any task dependencies.\n\nThat usually means installing the same Python environment or container image on the Airflow scheduler host and on every Dask worker host.\n\n## Start Airflow\n\nAfter setting the executor config, start the normal Airflow services for an Airflow 2 deployment:\n\n```bash\nairflow webserver\n```\n\n```bash\nairflow scheduler\n```\n\nCheck the configured executor:\n\n```bash\nairflow config get-value core executor\n```\n\n## DAG Code Stays Normal\n\nMost DAGs do not import anything from this provider directly. You keep writing ordinary Airflow DAGs and let the configured executor decide where tasks run.\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.python import PythonOperator\nfrom pendulum import datetime\n\n\ndef emit(label: str) -> None:\n    print(f\"running {label}\")\n\n\nwith DAG(\n    dag_id=\"dask_executor_example\",\n    start_date=datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule_interval=None,\n    catchup=False,\n) as dag:\n    default_task = PythonOperator(\n        task_id=\"default_task\",\n        python_callable=emit,\n        op_args=[\"default\"],\n    )\n\n    gpu_task = PythonOperator(\n        task_id=\"gpu_task\",\n        python_callable=emit,\n        op_args=[\"gpu\"],\n        queue=\"gpu\",\n    )\n\n    default_task >> gpu_task\n```\n\nPut the DAG in your configured DAGs folder and verify Airflow can parse it:\n\n```bash\nairflow dags list\nairflow dags show dask_executor_example\n```\n\n## Queues Use Dask Worker Resources\n\nThis executor maps Airflow task queues to Dask worker resources.\n\nIf you use `queue=\"gpu\"` or another non-default Airflow queue, start workers with matching resource names:\n\n```bash\ndask-worker \"$DASK_HOST:$DASK_PORT\" --resources=\"gpu=1\"\n```\n\nFor multiple queues:\n\n```bash\ndask-worker \"$DASK_HOST:$DASK_PORT\" --resources=\"gpu=1,etl=1\"\n```\n\nPractical behavior to expect:\n\n- the default Airflow queue behaves like \"no specific Dask resource requested\"\n- non-default queues require a matching worker resource name\n- tasks for a non-default queue only run on workers that advertise the matching resource\n\n## Common Pitfalls\n\n- Installing the provider without Airflow. This package only extends Airflow.\n- Configuring the executor but not starting a reachable Dask scheduler and worker.\n- Running workers that do not have Airflow, DAG dependencies, or provider dependencies installed.\n- Using Airflow queues without matching Dask worker resources.\n- Assuming Airflow 3 service layout or `airflow.sdk` examples apply here. This provider is documented for Airflow 2 installations.\n\n## Version Notes\n\n- PyPI lists `1.1.1` as the latest published version of `apache-airflow-providers-daskexecutor`.\n- The provider changelog says `1.1.1` marks the provider as removed and not maintained anymore.\n- The stable provider index still shows `Release: 1.1.0`, so use PyPI and the changelog when checking the latest package version.\n- PyPI lists supported Python versions `3.8`, `3.9`, `3.10`, and `3.11`.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-daskexecutor/stable/`\n- Provider package index: `https://airflow.apache.org/docs/apache-airflow-providers-daskexecutor/stable/index.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-daskexecutor/stable/changelog.html`\n- `DaskExecutor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-daskexecutor/stable/_api/airflow/providers/daskexecutor/executors/dask_executor/index.html`\n- `DaskExecutor` module source: `https://airflow.apache.org/docs/apache-airflow-providers-daskexecutor/stable/_modules/airflow/providers/daskexecutor/executors/dask_executor.html`\n- Airflow Dask executor guide: `https://airflow.apache.org/docs/apache-airflow/2.6.3/core-concepts/executor/dask.html`\n- Airflow executor configuration overview: `https://airflow.apache.org/docs/apache-airflow/2.6.0/core-concepts/executor/index.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/2.6.0/installation/installing-from-pypi.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-daskexecutor/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-databricks/python/DOC.md",
    "content": "---\nname: providers-databricks\ndescription: \"Apache Airflow Databricks provider for submitting Jobs runs and triggering existing Databricks jobs from Python DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,databricks,jobs,dag,python\"\n---\n\n# apache-airflow-providers-databricks\n\nUse `apache-airflow-providers-databricks` when an Airflow DAG needs to submit a one-time Databricks job run or trigger an existing Databricks job through an Airflow connection.\n\nThis guide targets provider version `7.10.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npip install apache-airflow-providers-databricks==7.10.0\n```\n\nIn practice, the scheduler, workers, and any other component that imports DAG files must all have the provider installed.\n\nIf you are bootstrapping Airflow itself, install Airflow first with the official constraints guidance from the main Airflow docs, then add the provider to that same environment.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection referenced by `databricks_conn_id`, typically `databricks_default`.\n\nCreate a Databricks connection in the Airflow UI or via your secrets backend, then reuse that connection id in operators and hooks.\n\nValues you usually need available when creating the connection:\n\n```bash\nexport DATABRICKS_HOST=\"https://<your-workspace-host>\"\nexport DATABRICKS_TOKEN=\"<your-databricks-token>\"\n```\n\nConnection fields to fill in:\n\n- `Conn Id`: `databricks_default` or another stable connection id\n- `Conn Type`: `Databricks`\n- workspace host URL\n- Databricks access token or other credential material supported by your Airflow connection setup\n\nKeep credentials in Airflow connections or a secrets backend instead of hard-coding them in DAG files.\n\n## Submit A One-Time Databricks Run\n\nUse `DatabricksSubmitRunOperator` when the DAG should submit a run directly from a Databricks Jobs API-style payload instead of triggering an already-created job.\n\n```python\nfrom __future__ import annotations\n\nfrom airflow import DAG\nfrom airflow.providers.databricks.operators.databricks import (\n    DatabricksSubmitRunOperator,\n)\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"databricks_submit_run_demo\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"databricks\"],\n) as dag:\n    submit_one_time_run = DatabricksSubmitRunOperator(\n        task_id=\"submit_one_time_run\",\n        databricks_conn_id=\"databricks_default\",\n        json={\n            \"run_name\": \"airflow-submit-run\",\n            \"new_cluster\": {\n                \"spark_version\": \"13.3.x-scala2.12\",\n                \"node_type_id\": \"i3.xlarge\",\n                \"num_workers\": 1,\n            },\n            \"notebook_task\": {\n                \"notebook_path\": \"/Shared/airflow-demo\",\n                \"base_parameters\": {\n                    \"run_date\": \"{{ ds }}\",\n                    \"source\": \"airflow\",\n                },\n            },\n        },\n    )\n```\n\nImportant details:\n\n- The `json` argument mirrors the Databricks Jobs Runs Submit request body.\n- Cluster fields such as `spark_version` and `node_type_id` must match values that exist in your Databricks workspace.\n- Template only the parameters that truly vary per run; keep the rest of the job spec stable.\n\n## Trigger An Existing Databricks Job\n\nUse `DatabricksRunNowOperator` when the Databricks job already exists and the DAG should launch that saved job definition.\n\n```python\nfrom __future__ import annotations\n\nfrom airflow import DAG\nfrom airflow.providers.databricks.operators.databricks import DatabricksRunNowOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"databricks_run_now_demo\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"databricks\"],\n) as dag:\n    trigger_existing_job = DatabricksRunNowOperator(\n        task_id=\"trigger_existing_job\",\n        databricks_conn_id=\"databricks_default\",\n        job_id=123456789012345,\n        notebook_params={\n            \"run_date\": \"{{ ds }}\",\n            \"source\": \"airflow\",\n        },\n    )\n```\n\nUse this pattern when:\n\n- the job is managed primarily in Databricks\n- Airflow is only responsible for scheduling or dependency control\n- you want Databricks-side edits to the saved job to apply without rewriting the DAG's full run payload\n\n## Choosing Between `submit_run` And `run_now`\n\n- Use `DatabricksSubmitRunOperator` when the DAG owns the one-off run definition.\n- Use `DatabricksRunNowOperator` when the job already exists in Databricks and Airflow should only trigger it.\n\nIf a task becomes hard to read because the `json` payload is large, move the payload into a Python variable or helper module in your DAG repository rather than inlining hundreds of lines inside the operator call.\n\n## Operational Checks\n\nConfirm the provider is installed:\n\n```bash\nairflow providers list | grep databricks\n```\n\nConfirm the Airflow connection exists:\n\n```bash\nairflow connections get databricks_default\n```\n\nCheck that Airflow can parse and test the DAG:\n\n```bash\nairflow dags list\nairflow tasks test databricks_submit_run_demo submit_one_time_run 2026-03-12\n```\n\nUse `airflow tasks test` for isolated task debugging before you rely on scheduler-triggered runs.\n\n## Common Pitfalls\n\n- Installing the provider only in a local shell instead of in the actual Airflow runtime image.\n- Hard-coding workspace URLs or tokens directly in the DAG instead of using an Airflow connection.\n- Copying a `new_cluster` block from another workspace without checking `spark_version`, node type, or policy constraints.\n- Using `submit_run` when the real requirement is to trigger a long-lived, separately managed Databricks job.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-datadog/python/DOC.md",
    "content": "---\nname: providers-datadog\ndescription: \"Apache Airflow Datadog provider guide for configuring a Datadog connection, sending metrics and events, and polling Datadog from Python DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.10.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,datadog,python,metrics,events,sensors,hooks\"\n---\n\n# Apache Airflow Datadog Provider Guide\n\nUse `apache-airflow-providers-datadog` when an Airflow DAG needs to send Datadog metrics, post Datadog events, or poll Datadog's event stream. The provider exposes one Airflow connection type (`datadog`), one hook (`DatadogHook`), and one sensor (`DatadogSensor`).\n\nThis package extends Apache Airflow. It is not a general Datadog SDK for dashboards, monitors, or account management.\n\n## Install\n\nThe current provider release `3.10.2` requires `apache-airflow>=2.11.0`, `apache-airflow-providers-common-compat>=1.10.1`, and `datadog>=0.50.0`.\n\nInstall it in the same Python environment as every Airflow component that imports your DAGs:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-datadog==3.10.2\"\n```\n\nPyPI currently publishes wheels for Python `3.10` through `3.13`.\n\n## Configure The Airflow Connection\n\nThe provider's Datadog connection uses these fields:\n\n- `conn_type`: `datadog`\n- `host`: host name attached to submitted metrics and events\n- `extra.api_host`: Datadog API base URL such as `https://api.datadoghq.com` or your regional Datadog site\n- `extra.api_key`: Datadog API key\n- `extra.app_key`: Datadog application key\n- `extra.source_type_name`: optional source label attached to emitted events\n\nDatadog documents API keys and application keys separately. In practice:\n\n- keep an API key in the connection for write calls such as metrics and events\n- add an application key for read/query calls such as `query_metric(...)` and `DatadogSensor`\n\nExample environment variables:\n\n```bash\nexport DATADOG_API_KEY='<datadog-api-key>'\nexport DATADOG_APP_KEY='<datadog-application-key>'\nexport DATADOG_API_HOST='https://api.datadoghq.com'\nexport DATADOG_EVENT_HOST='airflow-prod'\n```\n\nCreate the Airflow connection as JSON:\n\n```bash\nexport AIRFLOW_CONN_DATADOG_DEFAULT='{\"conn_type\":\"datadog\",\"host\":\"airflow-prod\",\"extra\":{\"api_host\":\"https://api.datadoghq.com\",\"api_key\":\"<datadog-api-key>\",\"app_key\":\"<datadog-application-key>\",\"source_type_name\":\"airflow\"}}'\n```\n\nOr create the same connection with the Airflow CLI:\n\n```bash\nairflow connections add 'datadog_default' \\\n  --conn-json '{\n    \"conn_type\": \"datadog\",\n    \"host\": \"airflow-prod\",\n    \"extra\": {\n      \"api_host\": \"https://api.datadoghq.com\",\n      \"api_key\": \"<datadog-api-key>\",\n      \"app_key\": \"<datadog-application-key>\",\n      \"source_type_name\": \"airflow\"\n    }\n  }'\n```\n\nKeep keys in the connection or your Airflow secrets backend instead of embedding them in DAG code.\n\n## Send Metrics With `DatadogHook`\n\n`DatadogHook.send_metric(...)` sends a single point with the connection's configured host.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.datadog.hooks.datadog import DatadogHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"datadog_metrics_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def publish_metric() -> None:\n        hook = DatadogHook(datadog_conn_id=\"datadog_default\")\n        hook.send_metric(\n            metric_name=\"airflow.etl.rows_loaded\",\n            datapoint=1284,\n            tags=[\"env:prod\", \"dag_id:datadog_metrics_example\"],\n            type_=\"gauge\",\n        )\n\n    publish_metric()\n```\n\nUse tags for dimensions you plan to query later. The method forwards `metric_name`, `datapoint`, `tags`, `type_`, `interval`, and `host` to the Datadog client.\n\n## Post Events And Query Metrics\n\nUse `post_event(...)` for Datadog Events and `query_metric(...)` when a task needs historical metric data from Datadog.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.datadog.hooks.datadog import DatadogHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"datadog_event_and_query_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def publish_and_query() -> None:\n        hook = DatadogHook(datadog_conn_id=\"datadog_default\")\n\n        hook.post_event(\n            title=\"Warehouse load finished\",\n            text=\"Loaded 1284 rows into analytics.\",\n            alert_type=\"success\",\n            aggregation_key=\"warehouse-load\",\n            tags=[\"env:prod\", \"team:data-platform\"],\n        )\n\n        series = hook.query_metric(\n            query=\"avg:airflow.etl.rows_loaded{env:prod}.rollup(avg, 300)\",\n            from_seconds_ago=1800,\n            to_seconds_ago=0,\n        )\n        print(series)\n\n    publish_and_query()\n```\n\n`query_metric(...)` queries a relative time window ending `to_seconds_ago` seconds before now. If this call fails with Datadog authorization errors, check the application key and its scopes first.\n\n## Wait For Events With `DatadogSensor`\n\n`DatadogSensor` queries the Datadog event stream on each poke. Use `priority`, `sources`, and `tags` to narrow the query, and add `response_check` when you want an explicit success condition based on the returned event payload.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.datadog.sensors.datadog import DatadogSensor\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"datadog_sensor_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    wait_for_event = DatadogSensor(\n        task_id=\"wait_for_event\",\n        datadog_conn_id=\"datadog_default\",\n        from_seconds_ago=1800,\n        up_to_seconds_from_now=0,\n        priority=\"normal\",\n        sources=\"airflow\",\n        tags=[\"env:prod\", \"service:payments\"],\n    )\n```\n\nUse `response_check` when you need task-specific filtering beyond the built-in `priority`, `sources`, and `tags` arguments:\n\n```python\nresponse_check=lambda response: bool(response.get(\"events\"))\n```\n\n## Practical Notes\n\n- `host` in the Airflow connection is not the Datadog API endpoint. Put the Datadog site URL in `extra.api_host`.\n- Use the Datadog site for your account. `https://api.datadoghq.com` is only the default US1 endpoint.\n- Install the provider on every Airflow process that imports DAG files, not just on the scheduler.\n- This provider does not ship Datadog operators. Use `DatadogHook` inside Python tasks and `DatadogSensor` when you need polling behavior.\n- Keep Datadog secrets in Airflow connections or a secrets backend. Do not hard-code them into DAG source.\n\n## Version Notes For `3.10.2`\n\n- This guide targets `apache-airflow-providers-datadog==3.10.2`.\n- The provider version is independent from Apache Airflow core. The package index for `3.10.2` requires Airflow `>=2.11.0`.\n\n## Official Sources\n\n- Provider docs root: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/\n- Package index: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/index.html\n- Datadog connection type: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/connections/datadog.html\n- `DatadogHook` API: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/_api/airflow/providers/datadog/hooks/datadog/index.html\n- `DatadogSensor` API: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/_api/airflow/providers/datadog/sensors/datadog/index.html\n- `DatadogHook` source listing: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/_modules/airflow/providers/datadog/hooks/datadog.html\n- `DatadogSensor` source listing: https://airflow.apache.org/docs/apache-airflow-providers-datadog/stable/_modules/airflow/providers/datadog/sensors/datadog.html\n- Airflow provider installation docs: https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html\n- Airflow managing connections docs: https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html\n- Datadog API and application keys: https://docs.datadoghq.com/account_management/api-app-keys/\n- PyPI package page: https://pypi.org/project/apache-airflow-providers-datadog/\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-dbt-cloud/python/DOC.md",
    "content": "---\nname: providers-dbt-cloud\ndescription: \"Apache Airflow provider for triggering and monitoring dbt Cloud job runs from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.6.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,dbt,dbt-cloud,operators,sensors,elt\"\n---\n\n# Apache Airflow dbt Cloud Provider Guide\n\nUse `apache-airflow-providers-dbt-cloud` when an Airflow DAG needs to start an existing dbt Cloud job, wait for the run to finish, and keep dbt Cloud credentials on an Airflow connection instead of in DAG source.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone dbt client.\n- Keep the dbt Cloud host, API token, and account-specific settings on an Airflow connection such as `dbt_cloud_default`.\n- Pass a dbt Cloud `job_id` to the operator. The provider triggers an existing dbt Cloud job; it does not create the job definition for you.\n- Use `DbtCloudRunJobOperator` when one Airflow task should launch the run, and add `DbtCloudJobRunSensor` if you want the wait step to be a separate task.\n\n## What This Package Adds\n\nThe provider's main entry points are:\n\n- `DbtCloudRunJobOperator`\n- `DbtCloudJobRunSensor`\n- `DbtCloudHook`\n\nMost DAGs only need the operator and, for asynchronous orchestration, the sensor.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment. Keep Airflow pinned in the same command so dependency resolution stays aligned with the Airflow constraints model.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.6.5\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-dbt-cloud==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nEvery Airflow runtime that parses or runs DAGs needs the provider installed, including the scheduler, webserver, triggerer, and workers.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i dbt\npython -c \"from airflow.providers.dbt.cloud.operators.dbt import DbtCloudRunJobOperator; from airflow.providers.dbt.cloud.sensors.dbt import DbtCloudJobRunSensor; print('ok')\"\n```\n\n## Authentication And Connection Setup\n\nStart with a minimal Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nSet the values you want to store on the Airflow connection and reuse in DAGs:\n\n```bash\nexport DBT_CLOUD_HOST=\"https://cloud.getdbt.com\"\nexport DBT_CLOUD_API_TOKEN=\"<dbt-cloud-api-token>\"\nexport DBT_CLOUD_ACCOUNT_ID=\"<dbt-cloud-account-id>\"\nexport DBT_CLOUD_JOB_ID=\"<dbt-cloud-job-id>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'dbt_cloud_default' \\\n  --conn-type 'dbt_cloud' \\\n  --conn-host \"$DBT_CLOUD_HOST\" \\\n  --conn-password \"$DBT_CLOUD_API_TOKEN\" \\\n  --conn-extra \"{\\\"account_id\\\":\\\"${DBT_CLOUD_ACCOUNT_ID}\\\"}\"\n```\n\nConfirm the connection before you wire it into a DAG:\n\n```bash\nairflow connections get dbt_cloud_default\n```\n\nPractical notes:\n\n- If your dbt Cloud account uses a region-specific base URL, store that host on the Airflow connection instead of the default `https://cloud.getdbt.com`.\n- Keep the token in the Airflow connection or a secrets backend, not in Python source.\n- Keep the Airflow connection id stable and move environment-specific values into deployment config.\n\n## Common Workflow: Trigger A dbt Cloud Job And Wait In One Task\n\nUse `DbtCloudRunJobOperator` when a single Airflow task should both start the dbt Cloud run and wait for it to complete.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.dbt.cloud.operators.dbt import DbtCloudRunJobOperator\n\n\nDBT_CLOUD_JOB_ID = int(os.environ[\"DBT_CLOUD_JOB_ID\"])\n\n\nwith DAG(\n    dag_id=\"dbt_cloud_run_job\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"dbt-cloud\"],\n):\n    run_dbt_cloud_job = DbtCloudRunJobOperator(\n        task_id=\"run_dbt_cloud_job\",\n        dbt_cloud_conn_id=\"dbt_cloud_default\",\n        job_id=DBT_CLOUD_JOB_ID,\n        check_interval=30,\n        timeout=60 * 60,\n    )\n```\n\nUse this pattern when the DAG only needs a simple task boundary around an existing dbt Cloud job.\n\nThe key arguments most teams set are:\n\n- `dbt_cloud_conn_id`: Airflow connection id for dbt Cloud, usually `dbt_cloud_default`\n- `job_id`: the existing dbt Cloud job to trigger\n- `check_interval`: how often the operator polls run state while waiting\n- `timeout`: maximum seconds to wait before the task fails\n\n## Common Workflow: Trigger Asynchronously And Wait With A Sensor\n\nSplit the start and wait steps when you want a separate monitoring task in the DAG graph.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.dbt.cloud.operators.dbt import DbtCloudRunJobOperator\nfrom airflow.providers.dbt.cloud.sensors.dbt import DbtCloudJobRunSensor\n\n\nDBT_CLOUD_JOB_ID = int(os.environ[\"DBT_CLOUD_JOB_ID\"])\n\n\nwith DAG(\n    dag_id=\"dbt_cloud_run_job_async\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"dbt-cloud\"],\n):\n    trigger_job = DbtCloudRunJobOperator(\n        task_id=\"trigger_job\",\n        dbt_cloud_conn_id=\"dbt_cloud_default\",\n        job_id=DBT_CLOUD_JOB_ID,\n        wait_for_termination=False,\n    )\n\n    wait_for_run = DbtCloudJobRunSensor(\n        task_id=\"wait_for_run\",\n        dbt_cloud_conn_id=\"dbt_cloud_default\",\n        run_id=trigger_job.output,\n        poke_interval=30,\n        timeout=60 * 60,\n    )\n\n    trigger_job >> wait_for_run\n```\n\nThis pattern keeps the DAG graph explicit and is the simplest way to reuse the run id emitted by the operator in a downstream monitoring step.\n\n## When To Reach For `DbtCloudHook`\n\nUse `DbtCloudHook` when task code needs lower-level control than the canned operator and sensor provide, but keep the same `dbt_cloud_conn_id` so credentials stay in Airflow's connection layer.\n\n```python\nfrom airflow.providers.dbt.cloud.hooks.dbt import DbtCloudHook\n\n\nhook = DbtCloudHook(dbt_cloud_conn_id=\"dbt_cloud_default\")\n```\n\nIn most DAGs, start with `DbtCloudRunJobOperator` first and only drop down to the hook when you need custom task logic around the dbt Cloud API.\n\n## Operational Checks\n\nConfirm the provider is installed and the connection exists:\n\n```bash\nairflow providers list | grep -i dbt\nairflow connections get dbt_cloud_default\nairflow dags list\n```\n\nFor isolated debugging, use `airflow tasks test` against the task that launches the job before you depend on a scheduler-triggered run.\n\n## Common Pitfalls\n\n- Installing the provider only in a local shell instead of in the actual Airflow runtime image.\n- Confusing the Airflow connection id with dbt Cloud values such as `account_id` or `job_id`.\n- Hard-coding the API token or account-specific settings directly in the DAG file.\n- Pointing the Airflow connection at the wrong dbt Cloud host for your region.\n- Using the separate sensor pattern without setting `wait_for_termination=False` on the operator.\n- Assuming the provider creates dbt Cloud jobs. It triggers and monitors jobs that already exist in dbt Cloud.\n\n## Version Notes\n\nThis guide targets `apache-airflow-providers-dbt-cloud` version `4.6.5`.\n\nAirflow provider packages are versioned separately from Apache Airflow core, so pin the provider to the Airflow environment you actually run and re-check the provider docs before upgrading either one independently.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/stable/index.html`\n- `DbtCloudHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/stable/_api/airflow/providers/dbt/cloud/hooks/dbt/index.html`\n- `DbtCloudRunJobOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/stable/_api/airflow/providers/dbt/cloud/operators/dbt/index.html`\n- `DbtCloudJobRunSensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/stable/_api/airflow/providers/dbt/cloud/sensors/dbt/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-dbt-cloud/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-dingding/python/DOC.md",
    "content": "---\nname: providers-dingding\ndescription: \"Apache Airflow DingTalk provider for sending custom robot messages with DingdingOperator and DingdingHook\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,dingtalk,dingding,python,notifications,operators,hooks\"\n---\n\n# Apache Airflow DingTalk Provider Guide\n\nUse `apache-airflow-providers-dingding` when an Airflow DAG should send messages to a DingTalk group through a custom robot webhook.\n\nThis package extends Apache Airflow. It is not a general-purpose DingTalk Python SDK for apps outside Airflow.\n\n## Install\n\nInstall the provider in the same Python environment as your Airflow scheduler, workers, and any image that imports DAG code:\n\n```bash\npython -m pip install \"apache-airflow-providers-dingding==3.9.2\"\n```\n\nVersion notes from PyPI for `3.9.2`:\n\n- requires Python `>=3.10`\n- requires `apache-airflow>=2.11.0`\n\nIf your deployment pins Airflow with constraints, keep this provider pinned with the Airflow version your environment supports instead of upgrading it in isolation.\n\n## Prerequisites\n\nBefore writing DAG code:\n\n- add a DingTalk custom robot to the target group\n- collect the custom robot webhook token\n- store only the token in the Airflow connection password field, not the full webhook URL\n\nThe provider uses `https://oapi.dingtalk.com` by default. Only set a custom connection host if your DingTalk endpoint differs.\n\n## Configure The Airflow Connection\n\nThe provider's default connection id is `dingding_default`, and the hook declares the connection type as `dingding`.\n\nEnvironment variable example using Airflow's JSON connection format:\n\n```bash\nexport DINGDING_TOKEN='your-custom-robot-token'\n\nexport AIRFLOW_CONN_DINGDING_DEFAULT=\"{\\\"conn_type\\\": \\\"dingding\\\", \\\"host\\\": \\\"https://oapi.dingtalk.com\\\", \\\"password\\\": \\\"${DINGDING_TOKEN}\\\"}\"\n```\n\nEquivalent CLI setup:\n\n```bash\nexport DINGDING_TOKEN='your-custom-robot-token'\n\nairflow connections add 'dingding_default' \\\n  --conn-json \"{\\\"conn_type\\\": \\\"dingding\\\", \\\"host\\\": \\\"https://oapi.dingtalk.com\\\", \\\"password\\\": \\\"${DINGDING_TOKEN}\\\"}\"\n```\n\nUI setup:\n\n- **Connection Id:** `dingding_default`\n- **Connection Type:** `dingding`\n- **Host:** `https://oapi.dingtalk.com` unless you need a different DingTalk endpoint\n- **Password:** the webhook token only\n\n## Send A Text Message With `DingdingOperator`\n\nUse `DingdingOperator` when message delivery should be a normal task in the DAG graph.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.dingding.operators.dingding import DingdingOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"dingding_text_message_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_text_message = DingdingOperator(\n        task_id=\"send_text_message\",\n        dingding_conn_id=\"dingding_default\",\n        message_type=\"text\",\n        message=\"Airflow run {{ run_id }} finished for DAG {{ dag.dag_id }}.\",\n        at_all=False,\n    )\n```\n\nKey parameters:\n\n- `dingding_conn_id`: Airflow connection id, defaulting to `dingding_default`\n- `message_type`: one of `text`, `link`, `markdown`, `actionCard`, or `feedCard`\n- `message`: string for `text`, dict payload for the rich message types\n- `at_mobiles`: optional list of users to mention\n- `at_all`: mention everyone in the group\n\n## Send A Markdown Message\n\nMarkdown is the rich message type that still supports targeted mentions.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.dingding.operators.dingding import DingdingOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"dingding_markdown_message_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_markdown_message = DingdingOperator(\n        task_id=\"send_markdown_message\",\n        dingding_conn_id=\"dingding_default\",\n        message_type=\"markdown\",\n        message={\n            \"title\": \"Airflow DingTalk alert\",\n            \"text\": \"# DAG failed\\n\"\n            \"DAG: {{ dag.dag_id }}\\n\"\n            \"Run: {{ run_id }}\\n\"\n            \"See the Airflow task logs for details.\",\n        },\n        at_mobiles=[\"156XXXXXXXX\"],\n        at_all=False,\n    )\n```\n\nFor `link`, `actionCard`, and `feedCard`, pass the message payload as the corresponding DingTalk robot payload dict. The provider sends that dict under the selected `message_type`.\n\n## Use `DingdingHook` In Callbacks Or Python Task Code\n\nUse `DingdingHook` when the message is assembled in Python or attached to a task callback.\n\nFailure callback example:\n\n```python\nfrom airflow.providers.dingding.hooks.dingding import DingdingHook\n\n\ndef dingding_failure_callback(context) -> None:\n    task_instance = context[\"ti\"]\n    message = (\n        f\"Task {task_instance.task_id} failed in DAG \"\n        f\"{task_instance.dag_id} for run {task_instance.run_id}.\"\n    )\n\n    DingdingHook(\n        dingding_conn_id=\"dingding_default\",\n        message_type=\"text\",\n        message=message,\n        at_all=True,\n    ).send()\n```\n\nAttach it to a DAG or task:\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.empty import EmptyOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"dingding_callback_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    on_failure_callback=dingding_failure_callback,\n) as dag:\n    task = EmptyOperator(task_id=\"task\")\n```\n\n## Common Usage Pattern\n\nFor most Airflow projects:\n\n- keep the webhook token on `dingding_default`\n- use `DingdingOperator` for visible notification tasks\n- use `DingdingHook(...).send()` in callbacks when you only want alerts on failure or retry\n- keep message bodies in `message`, where Airflow templating is supported\n\n## Pitfalls\n\n- Put only the webhook token in the connection password. Do not paste the full webhook URL there.\n- `at_all=True` overrides `at_mobiles`.\n- Only `message` is a templated field on `DingdingOperator`. If you need dynamic mention lists, build the message in Python and use `DingdingHook`.\n- Rich message types other than `markdown` do not support reminding specific users through `at_mobiles`.\n- If you omit the connection host, the provider posts to `https://oapi.dingtalk.com`.\n- Install the provider everywhere Airflow imports DAG code. Import errors usually mean one scheduler, worker, or image is missing the package.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-dingding==3.9.2`.\n- PyPI lists support for Python 3.10, 3.11, 3.12, and 3.13.\n- PyPI lists a minimum Airflow version of `2.11.0`.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-dingding/stable/`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-dingding/stable/operators.html`\n- `DingdingOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-dingding/stable/_api/airflow/providers/dingding/operators/dingding/index.html`\n- `DingdingHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-dingding/stable/_api/airflow/providers/dingding/hooks/dingding/index.html`\n- `DingdingHook` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-dingding/stable/_modules/airflow/providers/dingding/hooks/dingding.html`\n- Airflow connection management: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-dingding/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-discord/python/DOC.md",
    "content": "---\nname: providers-discord\ndescription: \"Apache Airflow Discord provider for sending webhook messages from DAG tasks, Python code, and callback notifiers\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,discord,python,webhooks,notifications\"\n---\n\n# apache-airflow-providers-discord\n\nUse `apache-airflow-providers-discord` when an Airflow DAG needs to send Discord webhook messages from a task, from Python task code, or from a callback such as `on_failure_callback`.\n\nThis package extends Apache Airflow. It is not a general-purpose Discord bot SDK.\n\nThis guide targets provider version `3.12.0`.\n\n## What This Package Adds\n\nThe Discord provider is centered on Discord webhook delivery through an Airflow connection:\n\n- `DiscordWebhookOperator` for a visible DAG task that posts to Discord\n- `DiscordWebhookHook` for sending a webhook from Python task code\n- `DiscordNotifier` for DAG-level or task-level callbacks\n- a Discord webhook connection that keeps the webhook token out of DAG source\n\nIf you need a Discord bot token, slash commands, gateway events, or channel management APIs, use a Discord bot library outside this provider. This provider is for webhook-based message delivery inside Airflow.\n\n## Install\n\nThe provider docs for `3.12.0` list these minimum runtime requirements:\n\n- `apache-airflow >= 2.11.0`\n- `apache-airflow-providers-common-compat >= 1.8.0`\n- `discord-webhook >= 1.2.1`\n- Python `>= 3.10`\n\nInstall the provider into the same environment or image as every Airflow component that imports or executes DAG code:\n\n```bash\npython -m pip install \"apache-airflow-providers-discord==3.12.0\"\n```\n\nIf you install providers with Airflow constraints, keep the Airflow core package pinned in the same command:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-discord==3.12.0\"\n```\n\nUseful checks:\n\n```bash\nairflow providers list | grep discord\nairflow info\n```\n\n## Configure The Discord Webhook Connection\n\nCreate a Discord webhook in the target Discord channel, then store the secret parts in an Airflow connection instead of hard-coding them in DAG files.\n\nUseful local shell variables:\n\n```bash\nexport DISCORD_WEBHOOK_TOKEN='123456789012345678/your-webhook-token'\nexport DISCORD_WEBHOOK_ENDPOINT='https://discord.com/api/webhooks'\n```\n\nIn Airflow, create a connection such as:\n\n- **Connection Id:** `discord_default`\n- **Connection Type:** Discord webhook (`discordwebhook` in URI form)\n- **Password:** the webhook token segment from the Discord webhook URL\n- **Extra:** `{\"webhook_endpoint\": \"https://discord.com/api/webhooks\"}`\n\nPractical notes:\n\n- The provider docs show the connection URI scheme as `discordwebhook://`.\n- Keep the webhook token in the connection password or a secrets backend, not in DAG code.\n- `webhook_endpoint` is optional if you use the standard Discord endpoint, but it is the documented place to override the webhook base URL.\n\n## Send A Message With `DiscordWebhookOperator`\n\nUse `DiscordWebhookOperator` when sending the Discord message should appear as a normal task in the DAG graph.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.discord.operators.discord_webhook import DiscordWebhookOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"discord_webhook_operator_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    notify_success = DiscordWebhookOperator(\n        task_id=\"notify_success\",\n        discord_webhook_conn_id=\"discord_default\",\n        message=\"Airflow run {{ run_id }} finished for DAG {{ dag.dag_id }}.\",\n        username=\"Airflow\",\n    )\n```\n\nMain parameters you will usually set:\n\n- `discord_webhook_conn_id`: Airflow connection id for the Discord webhook\n- `message`: text content sent to Discord\n- `username`: optional display name override for the webhook sender\n- `avatar_url`: optional avatar image URL for the webhook sender\n- `tts`: set `True` only if you want a text-to-speech message\n\n## Send An Embed With `DiscordWebhookOperator`\n\nVersion `3.12.0` added `embed` support to the operator, hook, and notifier APIs.\n\nUse an embed when the message should include a title, description, or structured rich content:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.discord.operators.discord_webhook import DiscordWebhookOperator\nfrom discord_webhook import DiscordEmbed\nfrom pendulum import datetime\n\n\nembed = DiscordEmbed(\n    title=\"Daily pipeline finished\",\n    description=\"DAG `daily_load` completed successfully.\",\n    color=\"03b2f8\",\n)\n\nwith DAG(\n    dag_id=\"discord_embed_operator_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_embed = DiscordWebhookOperator(\n        task_id=\"send_embed\",\n        discord_webhook_conn_id=\"discord_default\",\n        message=\"Status update from Airflow\",\n        embed=embed,\n        username=\"Airflow\",\n    )\n```\n\n## Use `DiscordWebhookHook` Inside Python Tasks\n\nUse `DiscordWebhookHook` when the message depends on Python logic or task output instead of being a fixed standalone task.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.discord.hooks.discord_webhook import DiscordWebhookHook\n\n\n@task\ndef notify_row_count(row_count: int) -> None:\n    hook = DiscordWebhookHook(\n        discord_webhook_conn_id=\"discord_default\",\n        message=f\"Loaded {row_count} rows into the warehouse.\",\n        username=\"Airflow\",\n        wait=True,\n    )\n    hook.execute()\n```\n\nImportant details from the hook API:\n\n- `discord_webhook_conn_id` selects the Airflow webhook connection.\n- `message` is the text body shortcut for a plain webhook post.\n- `body` can be a raw string or a request dictionary if you need lower-level control.\n- `wait=True` asks Discord to return a response after accepting the webhook.\n\nUse the hook when Python code needs to decide at runtime whether to send a message and what it should contain.\n\n## Use `DiscordNotifier` For Callbacks\n\nUse `DiscordNotifier` for DAG or task callbacks such as `on_failure_callback`.\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.empty import EmptyOperator\nfrom airflow.providers.discord.notifications.discord import DiscordNotifier\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"discord_failure_callback_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    on_failure_callback=DiscordNotifier(\n        webhook_conn_id=\"discord_default\",\n        message=\"Task {{ ti.task_id }} failed in DAG {{ dag.dag_id }} for run {{ run_id }}.\",\n        username=\"Airflow\",\n    ),\n) as dag:\n    start = EmptyOperator(task_id=\"start\")\n```\n\nImportant parameter name difference:\n\n- `DiscordWebhookOperator` and `DiscordWebhookHook` use `discord_webhook_conn_id`\n- `DiscordNotifier` uses `webhook_conn_id`\n\nThat mismatch is easy to miss when you move the same webhook between tasks and callbacks.\n\n## Common Setup Pattern\n\nFor most Airflow deployments, a clean split is:\n\n- keep the Discord webhook token in an Airflow connection or secrets backend\n- use `DiscordWebhookOperator` when Discord delivery is a visible DAG task\n- use `DiscordWebhookHook` inside `@task` code when the message is assembled dynamically\n- use `DiscordNotifier` for DAG-level or task-level callbacks\n\n## Common Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. Scheduler-only installs still fail when workers or other components import the missing provider package.\n- This provider sends Discord webhooks. It does not expose a full Discord bot client.\n- Store only the webhook token in the connection password; do not paste the entire webhook URL into DAG code.\n- `DiscordNotifier` uses `webhook_conn_id`, while the operator and hook use `discord_webhook_conn_id`.\n- Use `wait=True` only when your task logic actually needs Discord to send a response before continuing.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-discord` version `3.12.0`.\n- The official `3.12.0` changelog notes the addition of embed support for the hook, operator, and notifier.\n- Provider packages are versioned independently from Airflow core, so keep the provider pin explicit when you upgrade Airflow.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/index.html`\n- Discord connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/connections/discord.html`\n- Discord webhook operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/operators/discord_operator_howto_guide.html`\n- Discord notifier guide: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/notifications/discord_notifier_howto_guide.html`\n- `DiscordWebhookHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/_api/airflow/providers/discord/hooks/discord_webhook/index.html`\n- `DiscordWebhookOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/_api/airflow/providers/discord/operators/discord_webhook/index.html`\n- `DiscordNotifier` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/_api/airflow/providers/discord/notifications/discord/index.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-discord/stable/changelog.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-discord/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-docker/python/DOC.md",
    "content": "---\nname: providers-docker\ndescription: \"Apache Airflow Docker provider for running containerized tasks with DockerOperator and Docker connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,docker,containers,python,dag,operator\"\n---\n\n# apache-airflow-providers-docker\n\nUse `apache-airflow-providers-docker` to run containerized work from Airflow DAGs with `DockerOperator` and Airflow's Docker connection type.\n\nThis guide targets provider version `4.5.2`.\n\n## What This Package Adds\n\n`apache-airflow-providers-docker` is an Apache Airflow provider package. Install it when DAG tasks need to start Docker containers, pass files or environment variables into those containers, or connect to a local or remote Docker Engine from Airflow.\n\nThis package extends Airflow. It is not a standalone replacement for the Docker SDK in regular application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-docker==4.5.2\"\n```\n\nIn practice, the scheduler, workers, and any other Airflow runtime that imports DAG code need the provider available.\n\n## Prerequisites\n\nBefore using the operator, make sure:\n\n- the Airflow worker that runs the task can reach a Docker daemon\n- that daemon can pull or access the image you reference\n- any bind-mounted host paths exist on the worker that launches the container\n\nIf you run Airflow with Celery, Kubernetes, or another distributed executor, Docker access must exist in the worker runtime, not just on the machine where you edit DAGs.\n\n## Configure Docker Access\n\nThe provider supports two practical setup patterns:\n\n- pass `docker_url` directly in the operator, usually from `DOCKER_HOST`\n- create an Airflow Docker connection and use `docker_conn_id`\n\nFor direct configuration, keep the daemon URL in an environment variable:\n\n```bash\nexport DOCKER_HOST='unix://var/run/docker.sock'\nexport APP_ENV='dev'\nexport API_TOKEN='replace-me'\n```\n\nFor connection-based configuration, create an Airflow connection with connection type `docker`, point it at your Docker daemon URL, and use that connection id in the operator. If your Docker daemon requires TLS client certificates, configure the TLS settings on the connection instead of hard-coding them in each DAG.\n\n## Minimal `DockerOperator` Task\n\nThis is the smallest useful pattern for running a container from a DAG:\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.docker.operators.docker import DockerOperator\nfrom pendulum import datetime\n\n\nDOCKER_HOST = os.environ.get(\"DOCKER_HOST\", \"unix://var/run/docker.sock\")\n\n\nwith DAG(\n    dag_id=\"docker_operator_basic\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_container = DockerOperator(\n        task_id=\"run_container\",\n        image=\"python:3.12-slim\",\n        command='python -c \"import os; print(f\\\"APP_ENV={os.environ[\\\\\\\"APP_ENV\\\\\\\"]}\\\")\"',\n        docker_url=DOCKER_HOST,\n        api_version=\"auto\",\n        environment={\"APP_ENV\": os.environ.get(\"APP_ENV\", \"dev\")},\n    )\n```\n\nKey arguments in everyday use:\n\n- `image` selects the container image to run\n- `command` is the command executed inside the container\n- `docker_url` points at the Docker daemon when you are not using an Airflow connection\n- `api_version=\"auto\"` lets the Docker client negotiate the engine API version\n- `environment` passes non-secret environment variables into the container\n\n## Use An Airflow Connection Instead Of `docker_url`\n\nIf you already manage infrastructure access through Airflow connections, switch to `docker_conn_id` and let the connection hold the daemon details:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.docker.operators.docker import DockerOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"docker_operator_connection\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_via_connection = DockerOperator(\n        task_id=\"run_via_connection\",\n        image=\"bash:5.2\",\n        command=\"date -Iseconds\",\n        docker_conn_id=\"docker_default\",\n        api_version=\"auto\",\n    )\n```\n\nUse one approach consistently inside a DAG. Connection-based configuration is usually easier to rotate and centralize across environments.\n\n## Pass Secrets And Mount Files\n\nUse `private_environment` for sensitive values and `mounts` when the container needs files from the worker host.\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.docker.operators.docker import DockerOperator\nfrom docker.types import Mount\nfrom pendulum import datetime\n\n\nDOCKER_HOST = os.environ.get(\"DOCKER_HOST\", \"unix://var/run/docker.sock\")\n\n\nwith DAG(\n    dag_id=\"docker_operator_mounts\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_job = DockerOperator(\n        task_id=\"run_job\",\n        image=\"python:3.12-slim\",\n        command=\"python /workspace/jobs/build_report.py\",\n        docker_url=DOCKER_HOST,\n        api_version=\"auto\",\n        working_dir=\"/workspace/jobs\",\n        environment={\"APP_ENV\": os.environ.get(\"APP_ENV\", \"dev\")},\n        private_environment={\"API_TOKEN\": os.environ[\"API_TOKEN\"]},\n        mounts=[\n            Mount(\n                source=\"/opt/airflow/dags/jobs\",\n                target=\"/workspace/jobs\",\n                type=\"bind\",\n            )\n        ],\n        mount_tmp_dir=False,\n    )\n```\n\n`private_environment` is the right place for secrets that should not be exposed the same way as ordinary task environment values. For bind mounts, remember that `/opt/airflow/dags/jobs` must exist on the Airflow worker that starts the container.\n\n## Important Pitfalls\n\n- `DockerOperator` runs against the Docker daemon visible from the worker. A mounted socket or reachable TCP endpoint on the scheduler alone is not enough.\n- By default, the operator can create and mount a temporary host directory into the container and expose it as `AIRFLOW_TMP_DIR`. If you use a remote engine or Docker-in-Docker and that bind mount cannot work, set `mount_tmp_dir=False` and use explicit mounts or volumes instead.\n- Use `private_environment` or an Airflow secrets backend for secrets. Keep `environment` for non-sensitive values.\n- Host paths in `Mount(...)` are resolved on the worker host, not on your laptop and not inside the scheduler container unless that is also the worker.\n- Keep `api_version=\"auto\"` unless you have a reason to pin a specific Docker API version for daemon compatibility.\n\n## Version Notes\n\nThis doc is scoped to `apache-airflow-providers-docker` `4.5.2`. Airflow provider packages are versioned separately from Airflow core, so check provider compatibility when upgrading Airflow or when rebuilding Airflow images with a different provider set.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-docker/4.5.2/`\n- Docker operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-docker/4.5.2/operators/docker.html`\n- Docker connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-docker/4.5.2/connections/docker.html`\n- `DockerOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-docker/4.5.2/_api/airflow/providers/docker/operators/docker/index.html`\n- `DockerHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-docker/4.5.2/_api/airflow/providers/docker/hooks/docker/index.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-edge3/python/DOC.md",
    "content": "---\nname: providers-edge3\ndescription: \"Apache Airflow Edge3 provider for running tasks on remote edge workers over HTTPS with EdgeExecutor and worker management commands\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,edge,edge-worker,executor,distributed-execution,dag\"\n---\n\n# Apache Airflow Edge3 Provider Guide\n\nUse `apache-airflow-providers-edge3` when an Airflow deployment needs to run tasks on remote machines that sit behind separate network boundaries and can only reach the central Airflow site over outbound HTTP(S).\n\n## Golden Rule\n\n- Install this provider in the central Airflow environment and in every edge worker environment.\n- Configure `airflow.providers.edge3.executors.EdgeExecutor`, the shared edge API settings, and the shared JWT secret before starting workers.\n- Keep DAG files and task dependencies synchronized between the central Airflow instance and each edge worker.\n- Do not pair provider version `3.1.0` with `apache-airflow==3.1.0`; the maintainer docs explicitly exclude that Airflow core version.\n\n## Install\n\nInstall Airflow with the official constraints file, then add the provider in the same command. This example uses `apache-airflow==3.1.1` because provider `3.1.0` requires `apache-airflow>=3.0.0,!=3.1.0`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"3.1.1\"\nPROVIDER_VERSION=\"3.1.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-edge3==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUpstream lists these direct requirements for `apache-airflow-providers-edge3==3.1.0`:\n\n- `apache-airflow>=3.0.0,!=3.1.0`\n- `apache-airflow-providers-common-compat>=1.14.0`\n- `pydantic>=2.11.0`\n- `retryhttp>=1.4.0`\n- `aiofiles>=23.2.0`\n- `aiohttp>=3.9.2`\n\n## Configure The Central Airflow Instance\n\nThe provider expects the central deployment to run the Edge executor and expose the edge API endpoints. Environment-variable configuration is the cleanest setup:\n\n```bash\nexport AIRFLOW__CORE__EXECUTOR=\"airflow.providers.edge3.executors.EdgeExecutor\"\nexport AIRFLOW__EDGE__API_ENABLED=\"True\"\nexport AIRFLOW__EDGE__API_URL=\"https://airflow.example.com/edge_worker/v1/rpcapi\"\nexport AIRFLOW__API_AUTH__JWT_SECRET=\"replace-with-a-long-random-shared-secret\"\n\n# Required on the central Airflow instance for Airflow 3.0.x and 3.1.x\nexport AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=\"airflow.providers.edge3.models.db.EdgeDBManager\"\n```\n\nIf you are also using `FabAuthManager` on Airflow 3.0.x or 3.1.x, upstream documents `external_db_managers` as a comma-separated list:\n\n```bash\nexport AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=\"airflow.providers.fab.auth_manager.models.db.FABDBManager,airflow.providers.edge3.models.db.EdgeDBManager\"\n```\n\nThen create or migrate the edge tables on the central instance:\n\n```bash\nairflow db migrate\n```\n\nStart the central services that the workers depend on:\n\n```bash\nairflow api-server --port 8080\nairflow scheduler\n```\n\nNotes:\n\n- If `AIRFLOW__CORE__EXECUTION_API_SERVER_URL` is unset, Airflow derives it from `edge.api_url`.\n- The edge API endpoints are disabled by default until `AIRFLOW__EDGE__API_ENABLED=True` is set.\n\n## Start An Edge Worker\n\nEach worker needs Airflow, this provider, access to the same DAG files, and any extra libraries that the assigned tasks import at runtime.\n\n```bash\nexport AIRFLOW__CORE__EXECUTOR=\"airflow.providers.edge3.executors.EdgeExecutor\"\nexport AIRFLOW__CORE__DAGS_FOLDER=\"/opt/airflow/dags\"\nexport AIRFLOW__EDGE__API_ENABLED=\"True\"\nexport AIRFLOW__EDGE__API_URL=\"https://airflow.example.com/edge_worker/v1/rpcapi\"\nexport AIRFLOW__API_AUTH__JWT_SECRET=\"replace-with-the-same-shared-secret\"\n\nairflow edge worker -q factory-floor,warehouse -c 4\n```\n\nUseful variations:\n\n```bash\nairflow edge status\nairflow edge stop --wait\nairflow edge worker -D --stdout edge-worker.out.log --stderr edge-worker.err.log -q factory-floor\n```\n\nWhat the worker needs before it can pick up tasks:\n\n- outbound HTTP(S) access to the central Airflow API server\n- the same DAG files available in `DAGS_FOLDER`\n- compatible Airflow and `apache-airflow-providers-edge3` versions on both sides\n- the provider packages needed by the operators executed on that worker\n\n## Route Tasks To Edge Workers\n\nEdge workers pull from queues. Assign a queue in your DAG, then start workers that listen to the same queue name.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\n\n\nwith DAG(\n    dag_id=\"edge_site_healthcheck\",\n    schedule=None,\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    catchup=False,\n    tags=[\"edge\"],\n) as dag:\n    @task(executor=\"EdgeExecutor\", queue=\"factory-floor\", pool_slots=1)\n    def read_local_sensor() -> str:\n        return \"sensor-ok\"\n\n    @task\n    def report(status: str) -> None:\n        print(status)\n\n    report(read_local_sensor())\n```\n\nPractical rules from the maintainer docs:\n\n- `queue` decides which workers can claim the task.\n- A worker started with `airflow edge worker -q factory-floor` only serves that queue.\n- If `EdgeExecutor` is not your default executor, set `executor=\"EdgeExecutor\"` at the task or DAG level in addition to the queue.\n- Match task `pool_slots` to worker concurrency so a task does not ask for more slots than the worker can provide.\n\n## Operate And Maintain Workers\n\nLocal maintenance on the worker host:\n\n```bash\nairflow edge maintenance --comments \"kernel patching\" on --wait\nairflow edge status\nairflow edge maintenance off\n```\n\nCluster-wide maintenance commands on the central Airflow instance:\n\n```bash\nairflow edge list-workers -o json\nairflow edge remote-edge-worker-request-maintenance -H edge-host-01 -c \"planned restart\"\nairflow edge remote-edge-worker-exit-maintenance -H edge-host-01\n```\n\nThese remote-management commands need database access and only work from the central Airflow instance.\n\n## UI And API\n\nWith Airflow 3.1 and newer, the provider adds:\n\n- `Admin -> Edge Worker` for worker status and maintenance state\n- `Admin -> Edge Worker Jobs` for queued and running job visibility\n- `/edge_worker/v1/jobs`\n- `/edge_worker/v1/logs`\n- `/edge_worker/v1/workers`\n- `/edge_worker/v1/health`\n\nOpen `/edge_worker/docs` in the Airflow UI to inspect the generated API documentation.\n\nThe UI plugin requires either role `Admin`, role `Op`, or the individual permissions `can read on Plugins` and `can read on Jobs`.\n\n## Common Pitfalls\n\n- On Airflow 3.0.x and 3.1.x, forgetting `AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=airflow.providers.edge3.models.db.EdgeDBManager` means `airflow db migrate` will not create the edge tables the provider needs.\n- Central and edge environments must stay aligned. If the worker detects that the Airflow version or Edge provider version does not match the API server, it stops accepting new tasks and shuts down gracefully.\n- The worker only executes tasks whose runtime dependencies are installed locally. Installing the edge provider alone is not enough if your DAG also imports other providers or third-party packages.\n- Airflow 3.0 does not support the Edge UI plugin. Use the CLI commands for status and maintenance if the central deployment is still on 3.0.x.\n- If you run multiple API server or webserver instances without a shared log volume, edge log uploads can be split across instances.\n\n## Version Notes For Provider 3.1.0\n\n- `apache-airflow-providers-edge3==3.1.0` was released on March 4, 2026.\n- This release introduces `EdgeDBManager` and the docs add the `external_db_managers` requirement for central Airflow instances before Airflow 3.2.\n- The changelog also notes a fix for an Edge executor startup crash on Airflow versions earlier than 3.2.\n\n## Official Docs\n\n- Provider home: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/`\n- Provider package page: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/index.html`\n- Edge worker deployment: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/deployment.html`\n- Edge executor details: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/edge_executor.html`\n- Edge UI plugin and REST API: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/ui_plugin.html`\n- Configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/configurations-ref.html`\n- CLI reference: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/cli-ref.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-edge3/3.1.0/changelog.html`\n- Providers package reference: `https://airflow.apache.org/docs/apache-airflow-providers/packages-ref.html`\n- Apache Airflow PyPI package: `https://pypi.org/project/apache-airflow/`\n- Provider PyPI package: `https://pypi.org/project/apache-airflow-providers-edge3/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-elasticsearch/python/DOC.md",
    "content": "---\nname: providers-elasticsearch\ndescription: \"Apache Airflow Elasticsearch provider for SQL and Python hook access plus Elasticsearch-backed task logging\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,elasticsearch,logging,sql,dag,python\"\n---\n\n# apache-airflow-providers-elasticsearch\n\nUse `apache-airflow-providers-elasticsearch` when your Airflow deployment needs one of two things:\n\n- Airflow-managed access to Elasticsearch through `ElasticsearchSQLHook`\n- Elasticsearch-backed task logging, including `write_to_es` support on Airflow 3\n\nThis guide targets provider version `6.5.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow scheduler, webserver, and workers:\n\n```bash\npython -m pip install \"apache-airflow-providers-elasticsearch==6.5.0\"\n```\n\nUpstream lists these runtime requirements for `6.5.0`:\n\n- Apache Airflow `>=2.11.0`\n- Python `>=3.10`\n- `apache-airflow-providers-common-sql>=1.26.0`\n- `elasticsearch>=8.10.0,<9.0.0`\n\nIf one Airflow service is missing the provider, DAG parsing or task execution will fail with import errors even if other services have it installed.\n\n## Configure The Airflow Connection\n\nThe provider defines the `ElasticSearch` connection type. The default connection id is typically `elasticsearch_default`.\n\nSet it with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_ELASTICSEARCH_DEFAULT='elasticsearch://elastic:api_key@es.example.com:9200/https'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `elasticsearch_default`\n- `ElasticsearchSQLHook` uses `elasticsearch_conn_id=\"elasticsearch_default\"`\n- `SQLExecuteQueryOperator` uses `conn_id=\"elasticsearch_default\"`\n\nImportant connection fields from the maintainer docs:\n\n- `Host`: Elasticsearch endpoint\n- `Port`: `9200` for a direct node or `443` behind HTTPS proxies\n- `Login`: login value for the initial connection\n- `Password`: Elasticsearch API key for the initial connection\n- `Schema`: `http` or `https`\n- `Extra`: optional JSON such as `{\"http_compress\": true, \"timeout\": 30}`\n\nAll connection URI parts must be URL-encoded if they contain special characters.\n\n## Query Elasticsearch Through The SQL Hook\n\nUse `ElasticsearchSQLHook` when you want Airflow to manage the connection and you want to call the Elasticsearch SQL API from a task.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchSQLHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"elasticsearch_sql_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def show_tables() -> None:\n        hook = ElasticsearchSQLHook(elasticsearch_conn_id=\"elasticsearch_default\")\n        conn = hook.get_conn()\n\n        response = conn.execute_sql(\"SHOW TABLES\")\n        print(response)\n\n    show_tables()\n```\n\nIf you prefer an operator, provider `6.1.0` added cursor support so the same connection can be used with `SQLExecuteQueryOperator`:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"elasticsearch_sql_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    show_tables = SQLExecuteQueryOperator(\n        task_id=\"show_tables\",\n        conn_id=\"elasticsearch_default\",\n        sql=\"SHOW TABLES\",\n    )\n```\n\nUse this pattern when your task is just SQL execution and you do not need extra Python logic around the response.\n\n## Use The Native Elasticsearch Client In A Task\n\nUse `ElasticsearchPythonHook` when you want the provider to create an `elasticsearch.Elasticsearch` client directly.\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"elasticsearch_python_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def search_logs() -> dict:\n        hook = ElasticsearchPythonHook(\n            hosts=[os.environ[\"ELASTICSEARCH_URL\"]],\n            es_conn_args={\n                \"basic_auth\": (\n                    os.environ[\"ELASTICSEARCH_USER\"],\n                    os.environ[\"ELASTICSEARCH_PASSWORD\"],\n                ),\n                \"verify_certs\": True,\n            },\n        )\n\n        result = hook.search(\n            index=\"airflow-logs-*\",\n            query={\n                \"query\": {\n                    \"match\": {\n                        \"message\": \"failed\",\n                    }\n                }\n            },\n        )\n        print(result)\n        return result\n\n    search_logs()\n```\n\nEnvironment variables for that task-level pattern:\n\n```bash\nexport ELASTICSEARCH_URL=\"https://es.example.com:9200\"\nexport ELASTICSEARCH_USER=\"elastic\"\nexport ELASTICSEARCH_PASSWORD=\"your-password-or-api-key\"\n```\n\n`ElasticsearchPythonHook` takes `hosts` and optional `es_conn_args`; it does not use an Airflow connection id in the same way that `ElasticsearchSQLHook` does. The hook docs explicitly call out `basic_auth` and `ca_cert` as examples of values passed through `es_conn_args`.\n\n## Send Airflow Task Logs To Elasticsearch\n\nThe same provider also ships the Elasticsearch task log handler. The common setup is:\n\n```bash\nexport AIRFLOW__LOGGING__REMOTE_LOGGING=\"True\"\nexport AIRFLOW__ELASTICSEARCH__HOST=\"https://es.example.com:9200\"\nexport AIRFLOW__ELASTICSEARCH__WRITE_STDOUT=\"True\"\nexport AIRFLOW__ELASTICSEARCH__JSON_FORMAT=\"True\"\nexport AIRFLOW__ELASTICSEARCH__JSON_FIELDS=\"asctime,filename,lineno,levelname,message\"\nexport AIRFLOW__ELASTICSEARCH_CONFIGS__VERIFY_CERTS=\"True\"\n```\n\nUse `WRITE_STDOUT=\"True\"` when another runtime component collects stdout and forwards it to Elasticsearch.\n\nIf Airflow should write logs to Elasticsearch itself, enable `write_to_es` and set the target index:\n\n```bash\nexport AIRFLOW__LOGGING__REMOTE_LOGGING=\"True\"\nexport AIRFLOW__ELASTICSEARCH__HOST=\"https://es.example.com:9200\"\nexport AIRFLOW__ELASTICSEARCH__WRITE_TO_ES=\"True\"\nexport AIRFLOW__ELASTICSEARCH__TARGET_INDEX=\"airflow-logs\"\nexport AIRFLOW__ELASTICSEARCH__JSON_FORMAT=\"True\"\nexport AIRFLOW__ELASTICSEARCH_CONFIGS__VERIFY_CERTS=\"True\"\n```\n\nUseful logging settings from the maintainer configuration reference:\n\n- `host`: Elasticsearch endpoint used by the log handler\n- `frontend`: base URL for the Kibana or OpenSearch Dashboards UI when Airflow should generate external log links\n- `write_stdout`: write structured logs to stdout instead of writing to Elasticsearch directly\n- `write_to_es`: send logs directly from Airflow to Elasticsearch\n- `json_format` and `json_fields`: control structured log payloads\n- `target_index`: index used when `write_to_es` is enabled\n- `elasticsearch_configs`: extra client options such as TLS verification\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Scheduler-only installation is not enough.\n- URL-encode special characters in `AIRFLOW_CONN_*` URIs.\n- `ElasticsearchSQLHook` is the Airflow-connection-backed hook. The older deprecated `ElasticsearchHook` was removed in provider `6.0.0`.\n- `ElasticsearchPythonHook` expects `hosts` and client kwargs directly. Do not pass `elasticsearch_conn_id` to it and expect SQL-hook behavior.\n- If you enable `write_to_es`, keep the Airflow logging config consistent across scheduler, workers, and webserver or log retrieval will be inconsistent.\n- `delete_local_logs=True` only removes local task logs after a successful remote upload, so keep local storage available while you are still validating the remote logging path.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-elasticsearch` version `6.5.0`.\n- Provider `6.5.0` fixes `write_to_es` behavior for Airflow 3.\n- Provider `6.1.0` added cursor support so `ElasticsearchSQLHook` works with `SQLExecuteQueryOperator`.\n- Provider `6.0.0` removed the deprecated `ElasticsearchHook`; use `ElasticsearchSQLHook` instead.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/`\n- Installation and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/index.html`\n- Elasticsearch connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/connections/elasticsearch.html`\n- Elasticsearch hook API reference: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/_api/airflow/providers/elasticsearch/hooks/elasticsearch/index.html`\n- Elasticsearch logging configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/configurations-ref.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/changelog.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-elasticsearch/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-exasol/python/DOC.md",
    "content": "---\nname: providers-exasol\ndescription: \"Apache Airflow Exasol provider for Airflow connections, SQL tasks, and ExasolHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,exasol,sql,database,python,dag\"\n---\n\n# apache-airflow-providers-exasol\n\nUse `apache-airflow-providers-exasol` to connect Airflow tasks to Exasol through an Airflow connection, run SQL with Airflow's generic SQL operator, and query or export data from Python tasks with `ExasolHook`.\n\nThis guide targets provider version `4.10.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-exasol` is an Apache Airflow provider package. Install it when your DAGs need Exasol connections and hook-based access from Airflow tasks.\n\nThis package extends Airflow. It is not a standalone Exasol client for general application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-exasol==4.10.0\"\n```\n\nThe provider metadata for `4.10.0` requires:\n\n- `apache-airflow >= 2.11.0`\n- `apache-airflow-providers-common-compat >= 1.8.0`\n- `apache-airflow-providers-common-sql >= 1.27.0`\n- `pyexasol >= 0.26.0`\n- `python >= 3.10`\n\nIn practice, that means the scheduler, workers, and webserver all need the provider installed anywhere DAG code imports it.\n\nIf you are adding the provider to an existing Airflow environment, keep `apache-airflow` pinned in the same install command so dependency resolution does not silently change your Airflow core version:\n\n```bash\npython -m pip install \"apache-airflow==<your-airflow-version>\" \"apache-airflow-providers-exasol==4.10.0\"\n```\n\nIf you need the hook's SQLAlchemy URL helpers, install the optional extra:\n\n```bash\npython -m pip install \"apache-airflow-providers-exasol[sqlalchemy]==4.10.0\"\n```\n\n## Configure The Airflow Connection\n\nThe provider reads connection settings from an Airflow connection with connection type `exasol`. The default connection id is usually `exasol_default`.\n\nIn the Airflow UI, configure:\n\n- **Connection Id:** `exasol_default`\n- **Connection Type:** `exasol`\n- **Host:** your Exasol host name\n- **Schema:** the default Exasol schema\n- **Login / Password:** Exasol credentials\n- **Port:** usually `8563`\n\nYou can also define the connection with an environment variable. JSON is the clearest format when you need extras:\n\n```bash\nexport AIRFLOW_CONN_EXASOL_DEFAULT='{\n  \"conn_type\": \"exasol\",\n  \"host\": \"exasol.example.com\",\n  \"port\": 8563,\n  \"schema\": \"analytics\",\n  \"login\": \"sys\",\n  \"password\": \"secret\",\n  \"extra\": {\n    \"encryption\": true,\n    \"compression\": true,\n    \"client_name\": \"airflow\"\n  }\n}'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `exasol_default`\n- SQL operators use `conn_id=\"exasol_default\"`\n- `ExasolHook` uses `exasol_conn_id=\"exasol_default\"`\n\nThe current `ExasolHook` implementation forwards these connection extras into `pyexasol.connect(...)`:\n\n- `compression`\n- `encryption`\n- `json_lib`\n- `client_name`\n\nIf you define `AIRFLOW_CONN_*` as a URI instead of JSON, URL-encode reserved characters in the username, password, and query string values.\n\nKeep credentials in Airflow connections, environment variables, or a secrets backend instead of hard-coding them in DAG files.\n\n## Minimal Connection Check\n\nUse `ExasolHook` for a quick sanity check from a task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.exasol.hooks.exasol import ExasolHook\n\n\n@task\ndef ping_exasol() -> int:\n    hook = ExasolHook(exasol_conn_id=\"exasol_default\")\n    row = hook.get_first(\"SELECT 1\")\n    return int(row[0])\n```\n\n`ExasolHook` uses `exasol_conn_id`, not `conn_id`.\n\n## Run SQL In A DAG\n\nFor SQL-only tasks, use Airflow's generic SQL operator with an Exasol connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"exasol_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"exasol_default\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS airflow_events (\n            event_name VARCHAR(100),\n            event_value DECIMAL(18, 2)\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"exasol_default\",\n        sql=\"\"\"\n        INSERT INTO airflow_events (event_name, event_value)\n        VALUES ('signup', 1.00), ('purchase', 2.00)\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need Python logic around the result set.\n\n## Query Exasol From Python Tasks\n\nUse `ExasolHook` when you need to fetch rows into Python, branch on query results, or combine Exasol work with other task logic:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.exasol.hooks.exasol import ExasolHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"exasol_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> None:\n        hook = ExasolHook(exasol_conn_id=\"exasol_default\")\n\n        row = hook.get_first(\"SELECT COUNT(*) FROM airflow_events\")\n        event_count = int(row[0]) if row else 0\n\n        records = hook.get_records(\n            \"\"\"\n            SELECT event_name, event_value\n            FROM airflow_events\n            ORDER BY event_name\n            \"\"\"\n        )\n\n        print(f\"total events: {event_count}\")\n        for event_name, event_value in records:\n            print(f\"{event_name}: {event_value}\")\n\n    read_summary()\n```\n\nUseful hook methods for everyday DAG work:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying `pyexasol.ExaConnection`\n- `export_to_file(...)` when you need to write a query result to a local file on the worker\n\n## Export Query Results To A File\n\n`ExasolHook.export_to_file(...)` wraps the underlying Exasol export API:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.exasol.hooks.exasol import ExasolHook\n\n\n@task\ndef export_events() -> None:\n    hook = ExasolHook(exasol_conn_id=\"exasol_default\")\n    hook.export_to_file(\n        filename=\"/opt/airflow/data/airflow_events.csv\",\n        query_or_table=\"SELECT * FROM airflow_events\",\n    )\n```\n\nThe destination path is resolved on the Airflow worker that runs the task. If you use a distributed executor, make sure that path exists inside the worker runtime and is writable there.\n\n## Optional SQLAlchemy URL Support\n\nThe hook exposes `sqlalchemy_url` and `get_uri()` helpers, but they require the provider's `sqlalchemy` extra.\n\n```python\nfrom airflow.providers.exasol.hooks.exasol import ExasolHook\n\n\nhook = ExasolHook(exasol_conn_id=\"exasol_default\")\nprint(hook.sqlalchemy_url)\nprint(hook.get_uri())\n```\n\nIf you need a non-default SQLAlchemy dialect, set `sqlalchemy_scheme` in connection extras. The provider source accepts:\n\n- `exa.websocket`\n- `exa+websocket`\n- `exa+pyodbc`\n- `exa+turbodbc`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the package.\n- `ExasolHook` expects `exasol_conn_id`; Airflow's generic SQL operators use `conn_id`.\n- Use `SQLExecuteQueryOperator` for new SQL tasks. The provider still exposes `ExasolOperator` as a subclass, but the user-facing operator docs tell you to use the generic SQL operator instead.\n- Keep credentials in Airflow connections or a secrets backend instead of embedding usernames and passwords in DAG code.\n- Only a small set of connection extras are forwarded by the current hook implementation: `compression`, `encryption`, `json_lib`, and `client_name`. If you need other `pyexasol` connection kwargs, verify them against your exact provider build before depending on them.\n- `get_pandas_df()` is deprecated in the provider source. Avoid starting new DAG code with it.\n- `sqlalchemy_url` and `get_uri()` raise an exception unless you installed `apache-airflow-providers-exasol[sqlalchemy]`.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-exasol` version `4.10.0`.\n- Provider packages track Airflow compatibility separately from Exasol server compatibility. Check the provider release notes before upgrading this package alongside Airflow core.\n- The stable provider docs and PyPI package metadata for March 2026 both identify `4.10.0` as the current provider line for this package.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-exasol/stable/`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-exasol/stable/operators.html`\n- `ExasolHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-exasol/stable/_api/airflow/providers/exasol/hooks/exasol/index.html`\n- `ExasolHook` source listing: `https://airflow.apache.org/docs/apache-airflow-providers-exasol/stable/_modules/airflow/providers/exasol/hooks/exasol.html`\n- Airflow managing connections: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-exasol/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-fab/python/DOC.md",
    "content": "---\nname: providers-fab\ndescription: \"Apache Airflow FAB provider for Flask AppBuilder auth, RBAC roles, user management, API auth, and OAuth SSO\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,auth,rbac,fab,sso,python\"\n---\n\n# Apache Airflow Providers FAB Guide\n\nUse `apache-airflow-providers-fab` when an Airflow 3 deployment needs Flask AppBuilder-based authentication and authorization instead of the default simple auth flow. This provider adds `FabAuthManager`, FAB-backed user and role management commands, DAG-level access control, API auth backends, and OAuth-based SSO support.\n\n## Golden Rule\n\n- Install this package alongside a pinned `apache-airflow` version; it is not a standalone auth library.\n- Switch Airflow to `FabAuthManager` through the `[core] auth_manager` setting before expecting FAB CLI commands or role-based UI access to work.\n- Keep advanced auth settings in `webserver_config.py`, not in DAG code.\n- Treat FAB database migrations as part of the auth-manager rollout and provider upgrade process.\n\n## Install\n\nAirflow recommends installing from PyPI with a constraints file. For a fresh Airflow 3.1.x environment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=3.1.8\nPROVIDER_VERSION=3.4.0\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-fab==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep core pinned when adding the provider so `pip` does not silently move you to a different Airflow version:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==3.1.8\" \\\n  \"apache-airflow-providers-fab==3.4.0\"\n```\n\nPyPI for `apache-airflow-providers-fab 3.4.0` lists Python `>=3.10` and an Airflow requirement of `apache-airflow>=3.0.2`.\n\n## Enable `FabAuthManager`\n\nSet Airflow's auth manager to the FAB provider and point FAB at your `webserver_config.py` file:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__AUTH_MANAGER=\"airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager\"\nexport AIRFLOW__FAB__CONFIG_FILE=\"$AIRFLOW_HOME/webserver_config.py\"\n```\n\nStart with database-backed login in `webserver_config.py`:\n\n```python\nfrom flask_appbuilder.security.manager import AUTH_DB\n\nAUTH_TYPE = AUTH_DB\n```\n\nAfter setting the auth manager, run migrations:\n\n```bash\nairflow db migrate\n```\n\nIf you upgrade the FAB provider later, the provider also exposes a dedicated migration command:\n\n```bash\nairflow fab-db migrate\n```\n\nUseful checks:\n\n```bash\nairflow config get-value core auth_manager\nairflow providers list | grep fab\n```\n\nIf `airflow users ...`, `airflow roles ...`, or `airflow fab-db ...` commands are missing, confirm Airflow is actually using `FabAuthManager`.\n\n## Create Users And Roles\n\nWith the FAB auth manager enabled, Airflow exposes FAB-backed CLI commands for user and role administration.\n\nCreate an admin user:\n\n```bash\nairflow users create \\\n  --username admin \\\n  --firstname Airflow \\\n  --lastname Admin \\\n  --role Admin \\\n  --email admin@example.com \\\n  --password 'change-me-now'\n```\n\nCreate a custom role and assign it:\n\n```bash\nairflow roles create DataAnalyst\nairflow users add-role --username alice --role DataAnalyst\n```\n\nWhen you change roles, permissions, or DAG-level access rules, resync permissions:\n\n```bash\nairflow sync-perm\n```\n\nPractical role guidance from the FAB docs:\n\n- Keep Airflow's built-in roles (`Admin`, `Op`, `User`, `Viewer`, `Public`) as reference points instead of editing them in place.\n- Create new roles for app-specific access patterns.\n- FAB-specific DAG `access_control` only applies when the FAB auth manager is active.\n\n## Restrict DAG Access With `access_control`\n\nThe FAB provider supports DAG-level permissions through the DAG's `access_control` argument. This is how you grant one role read-only access to a DAG and another role edit access.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.standard.operators.empty import EmptyOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"fab_access_control_demo\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    access_control={\n        \"Viewer\": {\"can_read\"},\n        \"DataAnalyst\": {\"can_read\", \"can_edit\"},\n    },\n) as dag:\n    EmptyOperator(task_id=\"start\")\n```\n\nAfter changing `access_control`, run:\n\n```bash\nairflow sync-perm\n```\n\n## Authenticate API Clients\n\nThe FAB provider exposes an auth endpoint that returns a JWT access token for users authenticated through the database or LDAP backends.\n\nEnvironment variables:\n\n```bash\nexport AIRFLOW_URL=\"http://localhost:8080\"\nexport AIRFLOW_USERNAME=\"admin\"\nexport AIRFLOW_PASSWORD=\"change-me-now\"\n```\n\nMinimal Python client:\n\n```python\nimport os\nimport requests\n\nbase_url = os.environ[\"AIRFLOW_URL\"]\nsession = requests.Session()\n\ntoken_response = session.post(\n    f\"{base_url}/auth/token\",\n    json={\n        \"username\": os.environ[\"AIRFLOW_USERNAME\"],\n        \"password\": os.environ[\"AIRFLOW_PASSWORD\"],\n    },\n    timeout=30,\n)\ntoken_response.raise_for_status()\n\naccess_token = token_response.json()[\"access_token\"]\nsession.headers.update({\"Authorization\": f\"Bearer {access_token}\"})\n\ndags_response = session.get(f\"{base_url}/api/v2/dags\", timeout=30)\ndags_response.raise_for_status()\nprint(dags_response.json())\n```\n\nEquivalent `curl` flow:\n\n```bash\nTOKEN=\"$(\n  curl -sS -X POST \"${AIRFLOW_URL}/auth/token\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"username\\\":\\\"${AIRFLOW_USERNAME}\\\",\\\"password\\\":\\\"${AIRFLOW_PASSWORD}\\\"}\" |\n  python -c 'import json,sys; print(json.load(sys.stdin)[\"access_token\"])'\n)\"\n\ncurl -sS \"${AIRFLOW_URL}/api/v2/dags\" \\\n  -H \"Authorization: Bearer ${TOKEN}\"\n```\n\nFor FAB-managed API routes, the provider's default API backend is session-based. If you need HTTP basic auth for those routes, set:\n\n```bash\nexport AIRFLOW__FAB__AUTH_BACKENDS=\"airflow.providers.fab.auth_manager.api.auth.backend.session,airflow.providers.fab.auth_manager.api.auth.backend.basic_auth\"\n```\n\n## Configure OAuth SSO\n\nFAB reads advanced auth settings from `webserver_config.py`. To switch from local database login to OAuth:\n\n```python\nimport os\n\nfrom airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride\nfrom flask_appbuilder.security.manager import AUTH_OAUTH\n\nAUTH_TYPE = AUTH_OAUTH\nAUTH_USER_REGISTRATION = True\nAUTH_USER_REGISTRATION_ROLE = \"Viewer\"\nSECURITY_MANAGER_CLASS = FabAirflowSecurityManagerOverride\n\nOAUTH_PROVIDERS = [\n    {\n        \"name\": \"my_idp\",\n        \"icon\": \"fa-circle-o\",\n        \"token_key\": \"access_token\",\n        \"remote_app\": {\n            \"client_id\": os.environ[\"OAUTH_CLIENT_ID\"],\n            \"client_secret\": os.environ[\"OAUTH_CLIENT_SECRET\"],\n            \"api_base_url\": \"https://idp.example.com/\",\n            \"client_kwargs\": {\"scope\": \"openid email profile\"},\n            \"access_token_url\": \"https://idp.example.com/oauth/token\",\n            \"authorize_url\": \"https://idp.example.com/oauth/authorize\",\n            \"request_token_url\": None,\n        },\n    }\n]\n```\n\nEnvironment variables for that setup:\n\n```bash\nexport OAUTH_CLIENT_ID=\"your-client-id\"\nexport OAUTH_CLIENT_SECRET=\"your-client-secret\"\n```\n\nImportant SSO behavior:\n\n- FAB can auto-register first-time users when `AUTH_USER_REGISTRATION = True`.\n- `AUTH_USER_REGISTRATION_ROLE` controls the starting role for newly created users.\n- Provider `3.x` removed `AUTH_OID`; the supported OpenID Connect path is `AUTH_OAUTH`.\n\nRestart the Airflow UI process after changing `webserver_config.py`.\n\n## Common Pitfalls\n\n- Setting the wrong config section for `auth_manager`. Airflow's auth-manager docs use `[core] auth_manager`; use `AIRFLOW__CORE__AUTH_MANAGER`.\n- Expecting FAB commands before the provider is the active auth manager. The command groups are only exposed for the configured auth manager.\n- Forgetting the FAB migration step after switching auth managers or upgrading the provider.\n- Using the JWT `/auth/token` flow with an OAuth-only user. The username/password token endpoint is documented for DB- and LDAP-authenticated users.\n- Editing Airflow's built-in roles instead of creating your own roles.\n- Changing DAG `access_control` without running `airflow sync-perm`.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-fab 3.4.0`.\n- The provider docs publish a dedicated CLI group for FAB database migrations in the 3.4.0 line.\n- The 3.0.0 provider release removed `AUTH_OID`; if you are migrating old Airflow 2.x FAB configs, convert those settings to `AUTH_OAUTH`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/`\n- Configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/configurations-ref.html`\n- Access control: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/auth-manager/access-control.html`\n- API and CLI auth: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/auth-manager/api-authentication.html`\n- JWT token endpoint: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/auth-manager/token.html`\n- OAuth/SSO setup: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/auth-manager/sso.html`\n- CLI reference: `https://airflow.apache.org/docs/apache-airflow-providers-fab/3.4.0/cli-ref.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-fab/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-facebook/python/DOC.md",
    "content": "---\nname: providers-facebook\ndescription: \"Apache Airflow provider for configuring Facebook Ads connections and using FacebookAdsReportingHook in DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,facebook,facebook-ads,marketing-api,hooks,dag\"\n---\n\n# Apache Airflow Facebook Provider Guide\n\nUse `apache-airflow-providers-facebook` when an Airflow DAG needs an Airflow-managed Facebook Ads connection and Python task code that pulls Ads Insights reports without hard-coding app credentials in the DAG file.\n\nThis guide covers provider version `3.9.2`.\n\n## Golden Rule\n\n- Install this provider into the same environment as a pinned `apache-airflow` installation.\n- Configure a `facebook_social` Airflow connection and put `app_id`, `app_secret`, `access_token`, and `account_id` in connection extras.\n- Use `FacebookAdsReportingHook` inside task code, then call `bulk_facebook_report(...)`.\n- If `account_id` is a list, handle the method result as a dict keyed by account id instead of a single flat list.\n\n## What This Package Adds\n\nThis provider is narrow. In the official provider metadata it exposes:\n\n- Airflow connection type `facebook_social`\n- `FacebookAdsReportingHook`\n\nThe official provider metadata for `3.9.2` lists hooks and connection types, but not operators. The normal pattern is to call the hook from a Python task.\n\n## Install\n\nInstall the provider in the same Python environment as Airflow and keep Airflow pinned while you add or upgrade the provider.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.9.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-facebook==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i facebook\npython -c \"from airflow.providers.facebook.ads.hooks.ads import FacebookAdsReportingHook; print(FacebookAdsReportingHook.__name__)\"\n```\n\nVersion-sensitive notes for `3.9.2`:\n\n- The provider changelog says `3.9.0` raised the minimum Airflow version to `2.11.0`.\n- PyPI classifiers for `3.9.2` list Python `3.10`, `3.11`, `3.12`, and `3.13`.\n- PyPI lists `facebook-business>=22.0.0` as a dependency, so you do not need to install the Facebook Business SDK separately for normal provider usage.\n\n## Configure A Facebook Ads Connection\n\n`FacebookAdsReportingHook` reads its required values from Airflow connection extras, not from the connection login or password fields.\n\nSet the values you want Airflow to store:\n\n```bash\nexport FACEBOOK_APP_ID=\"<facebook-app-id>\"\nexport FACEBOOK_APP_SECRET=\"<facebook-app-secret>\"\nexport FACEBOOK_ACCESS_TOKEN=\"<facebook-access-token>\"\nexport FACEBOOK_ACCOUNT_ID=\"act_<ad_account_id>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'facebook_default' \\\n  --conn-type 'facebook_social' \\\n  --conn-extra \"{\\\"app_id\\\":\\\"${FACEBOOK_APP_ID}\\\",\\\"app_secret\\\":\\\"${FACEBOOK_APP_SECRET}\\\",\\\"access_token\\\":\\\"${FACEBOOK_ACCESS_TOKEN}\\\",\\\"account_id\\\":\\\"${FACEBOOK_ACCOUNT_ID}\\\"}\"\n```\n\nYou can also provide the same connection through an environment variable:\n\n```bash\nexport AIRFLOW_CONN_FACEBOOK_DEFAULT='{\n  \"conn_type\": \"facebook_social\",\n  \"extra\": {\n    \"app_id\": \"<facebook-app-id>\",\n    \"app_secret\": \"<facebook-app-secret>\",\n    \"access_token\": \"<facebook-access-token>\",\n    \"account_id\": \"act_<ad_account_id>\"\n  }\n}'\n```\n\nConfirm the connection before you wire it into a DAG:\n\n```bash\nairflow connections get facebook_default\n```\n\nRequired extra fields:\n\n- `app_id`\n- `app_secret`\n- `access_token`\n- `account_id`\n\nIf any of those are missing, the hook raises an Airflow exception before making the API call.\n\n## Run A Bulk Insights Report In A Task\n\nThe hook method to use is `bulk_facebook_report(fields, params)`.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.facebook.ads.hooks.ads import FacebookAdsReportingHook\n\n\nwith DAG(\n    dag_id=\"facebook_ads_insights_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"facebook\"],\n):\n    @task()\n    def fetch_campaign_metrics() -> dict[str, int]:\n        hook = FacebookAdsReportingHook(facebook_conn_id=\"facebook_default\")\n\n        rows = hook.bulk_facebook_report(\n            fields=[\n                \"account_id\",\n                \"campaign_name\",\n                \"impressions\",\n                \"clicks\",\n                \"spend\",\n            ],\n            params={\n                \"date_preset\": \"yesterday\",\n                \"level\": \"campaign\",\n            },\n        )\n\n        print(f\"Fetched {len(rows)} insight rows\")\n        return {\"row_count\": len(rows)}\n\n    fetch_campaign_metrics()\n```\n\nPractical points:\n\n- `facebook_conn_id` defaults to `facebook_default`.\n- `fields` is the list of insights fields to request.\n- `params` is passed through to the Facebook Ads Insights API request.\n- If you need a specific Marketing API version, pass `api_version=\"...\"` when creating the hook. If you omit it, the hook uses the Facebook Business SDK default version.\n\n## Use Multiple Ad Accounts\n\nThis provider supports multiple account ids on the same connection. Put a list in the `account_id` extra:\n\n```bash\nexport AIRFLOW_CONN_FACEBOOK_DEFAULT='{\n  \"conn_type\": \"facebook_social\",\n  \"extra\": {\n    \"app_id\": \"<facebook-app-id>\",\n    \"app_secret\": \"<facebook-app-secret>\",\n    \"access_token\": \"<facebook-access-token>\",\n    \"account_id\": [\"act_1111111111\", \"act_2222222222\"]\n  }\n}'\n```\n\nWhen `account_id` is a list, `bulk_facebook_report(...)` returns a dict keyed by account id:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.facebook.ads.hooks.ads import FacebookAdsReportingHook\n\n\nwith DAG(\n    dag_id=\"facebook_ads_multi_account_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"facebook\"],\n):\n    @task()\n    def fetch_by_account() -> dict[str, int]:\n        hook = FacebookAdsReportingHook(facebook_conn_id=\"facebook_default\")\n\n        report = hook.bulk_facebook_report(\n            fields=[\"account_id\", \"campaign_name\", \"spend\"],\n            params={\"date_preset\": \"last_7d\"},\n        )\n\n        return {account_id: len(rows) for account_id, rows in report.items()}\n\n    fetch_by_account()\n```\n\nUse this pattern when one Airflow environment manages several ad accounts with the same app credentials and access token.\n\n## Operational Checks\n\nCheck that Airflow can import the provider and parse your DAG:\n\n```bash\nairflow providers list | grep -i facebook\nairflow dags list | grep facebook_ads\n```\n\nRun an isolated task test while you are wiring up credentials and report parameters:\n\n```bash\nairflow tasks test facebook_ads_insights_demo fetch_campaign_metrics 2026-03-13\n```\n\n## Common Pitfalls\n\n- Installing the provider without upgrading Airflow first. Provider `3.9.x` requires Airflow `2.11.0` or newer.\n- Putting Facebook credentials in Airflow connection login and password fields instead of `extra`.\n- Forgetting `account_id`; it is a required connection extra.\n- Assuming multi-account configuration returns one list. It returns a dict keyed by account id.\n- Forgetting that `params` and `fields` must match the Facebook Ads Insights API surface, not generic Graph API endpoints.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-facebook` version `3.9.2`.\n- The provider's changelog shows `3.9.0` as the release that dropped support for older Airflow versions by requiring Airflow `2.11.0+`.\n- Earlier changelog entries show multi-account support was added before `3.9.x`, so the list-valued `account_id` workflow is available in this version.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-facebook/stable/`\n- Hook API docs: `https://airflow.apache.org/docs/apache-airflow-providers-facebook/stable/_api/airflow/providers/facebook/ads/hooks/ads/index.html`\n- Hook source docs: `https://airflow.apache.org/docs/apache-airflow-providers-facebook/stable/_modules/airflow/providers/facebook/ads/hooks/ads.html`\n- Airflow connections reference: `https://airflow.apache.org/docs/apache-airflow-providers/core-extensions/connections.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-facebook/stable/changelog.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-facebook/`\n- Facebook Marketing API insights parameters: `https://developers.facebook.com/docs/marketing-api/insights/parameters/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-fivetran/python/DOC.md",
    "content": "---\nname: providers-fivetran\ndescription: \"Airflow provider for triggering and monitoring Fivetran connector syncs from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,fivetran,elt,operators,sensors\"\n---\n\n# Airflow Provider Fivetran Python Guide\n\nUse `airflow-provider-fivetran` when an Apache Airflow DAG needs to trigger a sync for an existing Fivetran connector and optionally wait for that sync to finish.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone Fivetran SDK.\n- Keep the Fivetran API key and API secret in an Airflow connection such as `fivetran_default` instead of hard-coding them in DAG files.\n- Pass the Fivetran connector id to your tasks. The provider works with an already-created connector in Fivetran.\n- Use `FivetranOperator` to start a sync and `FivetranSensor` when you want the wait step as a separate Airflow task.\n\n## What This Package Adds\n\nThe maintainer examples for this package center on these DAG entry points:\n\n- `FivetranOperator`\n- `FivetranSensor`\n\nThe package imports use the `fivetran_provider_async` module name even though the PyPI package name is `airflow-provider-fivetran`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow scheduler, webserver, and workers:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"airflow-provider-fivetran==1.1.4\"\n```\n\nIf Airflow is already installed, keep the Airflow version pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"airflow-provider-fivetran==1.1.4\"\n```\n\nUseful checks after installation:\n\n```bash\npython -c \"from fivetran_provider_async.operators import FivetranOperator; from fivetran_provider_async.sensors import FivetranSensor; print('ok')\"\nairflow info\n```\n\n## Configure The Airflow Connection\n\nStart with a minimal Airflow environment and keep Fivetran credentials out of DAG code:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\nexport FIVETRAN_API_KEY=\"<your-fivetran-api-key>\"\nexport FIVETRAN_API_SECRET=\"<your-fivetran-api-secret>\"\nexport FIVETRAN_CONNECTOR_ID=\"<your-fivetran-connector-id>\"\n```\n\nCreate an Airflow connection for the Fivetran account:\n\n```bash\nairflow connections add 'fivetran_default' \\\n  --conn-type 'fivetran' \\\n  --conn-login \"$FIVETRAN_API_KEY\" \\\n  --conn-password \"$FIVETRAN_API_SECRET\"\n```\n\nConfirm the connection exists before wiring it into a DAG:\n\n```bash\nairflow connections get fivetran_default\n```\n\nKeep secrets in Airflow connections or a secrets backend instead of embedding them in Python files.\n\n## Common Workflow: Trigger A Connector Sync\n\nUse `FivetranOperator` when a single Airflow task should request a sync for one connector.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom fivetran_provider_async.operators import FivetranOperator\n\n\nFIVETRAN_CONNECTOR_ID = os.environ[\"FIVETRAN_CONNECTOR_ID\"]\n\n\nwith DAG(\n    dag_id=\"fivetran_trigger_sync\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"fivetran\"],\n):\n    trigger_sync = FivetranOperator(\n        task_id=\"trigger_sync\",\n        fivetran_conn_id=\"fivetran_default\",\n        connector_id=FIVETRAN_CONNECTOR_ID,\n    )\n```\n\nUse this pattern when the DAG's job is simply to request a sync for a connector that already exists in Fivetran.\n\n## Common Workflow: Trigger And Wait In Separate Tasks\n\nUse a sensor when you want one task to request the sync and a second task to block until the connector finishes.\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom fivetran_provider_async.operators import FivetranOperator\nfrom fivetran_provider_async.sensors import FivetranSensor\n\n\nFIVETRAN_CONNECTOR_ID = os.environ[\"FIVETRAN_CONNECTOR_ID\"]\n\n\nwith DAG(\n    dag_id=\"fivetran_trigger_and_wait\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"fivetran\"],\n):\n    trigger_sync = FivetranOperator(\n        task_id=\"trigger_sync\",\n        fivetran_conn_id=\"fivetran_default\",\n        connector_id=FIVETRAN_CONNECTOR_ID,\n    )\n\n    wait_for_sync = FivetranSensor(\n        task_id=\"wait_for_sync\",\n        fivetran_conn_id=\"fivetran_default\",\n        connector_id=FIVETRAN_CONNECTOR_ID,\n        poke_interval=60,\n        timeout=60 * 60,\n    )\n\n    trigger_sync >> wait_for_sync\n```\n\nThis split-task pattern is useful when downstream tasks should run only after Fivetran has finished the connector sync.\n\n## Operational Checks\n\nConfirm that Airflow can see the connection and DAG before you debug connector behavior:\n\n```bash\nairflow connections get fivetran_default\nairflow dags list | grep fivetran\nairflow tasks test fivetran_trigger_and_wait trigger_sync 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging while you wire up credentials and connector ids.\n\n## Common Pitfalls\n\n- Install the provider everywhere DAG code runs. A working import in one container does not help if the scheduler or workers are missing the package.\n- Keep the Fivetran API key and secret in the Airflow connection or a secrets backend instead of embedding them in DAG code.\n- Pass the Fivetran connector id, not a group id or destination id.\n- Make sure the connector already exists in Fivetran. This provider triggers and monitors syncs; it does not replace connector setup in the Fivetran UI.\n- Increase the sensor `timeout` for long-running syncs so Airflow does not fail a healthy connector run too early.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so dependency resolution does not silently replace Airflow core.\n\n## Version Notes\n\n- This guide covers `airflow-provider-fivetran` version `1.1.4`.\n- The provider version is separate from Apache Airflow core. Check the package repository and release notes before upgrading it independently of Airflow.\n\n## Official Docs\n\n- Maintainer repository: `https://github.com/fivetran/airflow-provider-fivetran`\n- PyPI: `https://pypi.org/project/airflow-provider-fivetran/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-ftp/python/DOC.md",
    "content": "---\nname: providers-ftp\ndescription: \"Apache Airflow FTP provider for Airflow connections and hook-based file transfers in DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.14.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,ftp,file-transfer,dag,python\"\n---\n\n# Apache Airflow Providers FTP Guide\n\nUse `apache-airflow-providers-ftp` to connect Airflow DAGs to FTP servers through an Airflow connection, then list, download, and upload files from task code with `FTPHook`.\n\nThis guide targets provider version `3.14.1`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone FTP client library.\n- Keep FTP credentials in an Airflow connection such as `partner_ftp`, not in DAG files.\n- Use `FTPHook(ftp_conn_id=\"...\")` inside tasks, then call normal FTP client methods on the object returned by `get_conn()`.\n- Remember that FTP and SFTP are different protocols. Do not point this provider at an SSH/SFTP endpoint.\n\n## Install\n\nAirflow providers are intended to be installed with the Airflow constraints file that matches your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.14.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-ftp==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already pinned elsewhere in your image or requirements, keep that pin when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-ftp==3.14.1\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep ftp\nairflow info\n```\n\n## Configure The Airflow Connection\n\nMost DAGs keep the FTP server details in an Airflow connection, then reuse its connection id from hooks and any provider operators or sensors.\n\nAn environment-variable connection is the fastest way to wire one in:\n\n```bash\nexport AIRFLOW_CONN_PARTNER_FTP='ftp://airflow:secret@ftp.example.com:21/'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `partner_ftp`\n- DAG code can use `ftp_conn_id=\"partner_ftp\"`\n\nYou can also create the same connection explicitly through the CLI:\n\n```bash\nairflow connections add 'partner_ftp' \\\n  --conn-uri 'ftp://airflow:secret@ftp.example.com:21/'\n```\n\nConfirm the connection exists before you wire it into a DAG:\n\n```bash\nairflow connections get partner_ftp\n```\n\nConnection fields you usually need:\n\n- `Host`: FTP server hostname\n- `Login`: username\n- `Password`: password\n- `Port`: usually `21`\n\nIf you need server-specific extras or TLS-related settings, check the provider's FTP connection docs for the exact fields supported by your Airflow version.\n\n## Download A File With `FTPHook`\n\nUse `FTPHook` when your task needs normal FTP session control and Python-side logic around file existence, naming, or downstream processing.\n\n```python\nfrom pathlib import Path\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.ftp.hooks.ftp import FTPHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ftp_download_orders\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def fetch_orders() -> str:\n        hook = FTPHook(ftp_conn_id=\"partner_ftp\")\n        client = hook.get_conn()\n\n        try:\n            client.cwd(\"/incoming\")\n            files = client.nlst()\n            if \"orders.csv\" not in files:\n                raise FileNotFoundError(\"/incoming/orders.csv not found\")\n\n            output_path = Path(\"/tmp/orders.csv\")\n            output_path.parent.mkdir(parents=True, exist_ok=True)\n\n            with output_path.open(\"wb\") as stream:\n                client.retrbinary(\"RETR orders.csv\", stream.write)\n\n            return str(output_path)\n        finally:\n            client.quit()\n\n    fetch_orders()\n```\n\nThe important pattern is:\n\n1. create `FTPHook(ftp_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned FTP client for normal operations such as `cwd()`, `nlst()`, `retrbinary()`, and `quit()`\n\nChanging into the remote directory before calling `nlst()` keeps file-name checks simpler because FTP servers differ on whether directory listings return bare names or full paths.\n\n## Upload A File From A Task\n\nUse the same hook pattern when the local file path or remote destination is computed in Python.\n\n```python\nfrom pathlib import Path\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.ftp.hooks.ftp import FTPHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ftp_upload_ack\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def upload_ack() -> None:\n        local_path = Path(\"/opt/airflow/data/ack.txt\")\n        hook = FTPHook(ftp_conn_id=\"partner_ftp\")\n        client = hook.get_conn()\n\n        try:\n            client.cwd(\"/outbound\")\n\n            with local_path.open(\"rb\") as stream:\n                client.storbinary(\"STOR ack.txt\", stream)\n        finally:\n            client.quit()\n\n    upload_ack()\n```\n\nThis is the simplest pattern when your DAG needs to create or transform a file first, then push the result to the FTP server in the same task.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep host, port, username, and password in one reusable Airflow connection\n- create `FTPHook` inside the task body instead of at module import time\n- use the FTP client returned by `get_conn()` for normal `ftplib` calls\n- return only small values from tasks, such as local output paths or selected file names\n\nIf your transfer is fully declarative and does not need custom Python logic, the provider docs also include operator and sensor APIs that can keep the DAG more compact.\n\n## Pitfalls\n\n- Installing the provider only on the scheduler or webserver. Workers also need it anywhere task code imports `airflow.providers.ftp`.\n- Using an SFTP URI such as `sftp://...` with this provider. FTP and SFTP use different hooks and different connection types.\n- Embedding credentials directly in DAG code instead of using Airflow connections or a secrets backend.\n- Forgetting that paths like `/tmp/orders.csv` and `/opt/airflow/data/ack.txt` must exist on the actual worker container or VM that runs the task.\n- Leaving FTP sessions open. Close them in a `finally` block so repeated task runs do not accumulate stale connections.\n- Forgetting to URL-encode special characters if you define `AIRFLOW_CONN_*` values manually.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-ftp` version `3.14.1`.\n- Keep `apache-airflow` pinned when you install or upgrade the provider so dependency resolution does not silently change your Airflow core version.\n- Use the Airflow constraints file for your Airflow and Python versions when building a fresh environment or updating provider packages.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-ftp/stable/`\n- FTP connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-ftp/stable/connections/ftp.html`\n- `FTPHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-ftp/stable/_api/airflow/providers/ftp/hooks/ftp/index.html`\n- FTP operators API reference: `https://airflow.apache.org/docs/apache-airflow-providers-ftp/stable/_api/airflow/providers/ftp/operators/ftp/index.html`\n- FTP sensors API reference: `https://airflow.apache.org/docs/apache-airflow-providers-ftp/stable/_api/airflow/providers/ftp/sensors/ftp/index.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-ftp/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-github/python/DOC.md",
    "content": "---\nname: providers-github\ndescription: \"Apache Airflow provider for GitHub connections, hooks, and DAG tasks that call the GitHub API through PyGithub\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,github,pygithub,hooks,operators,dags\"\n---\n\n# Apache Airflow GitHub Provider Guide\n\nUse `apache-airflow-providers-github` when an Airflow DAG needs to read repository data, create issues, or call GitHub from Airflow-managed tasks without hard-coding credentials in DAG files.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone GitHub SDK.\n- Put the GitHub API base URL and token on an Airflow connection such as `github_default`.\n- Use `GithubHook` for most real DAG logic, then call normal PyGithub methods on the returned client.\n- Keep personal access tokens and GitHub App installation tokens out of DAG source and in Airflow connections, variables, or a secrets backend.\n\n## What This Package Adds\n\nThis provider supplies Airflow's GitHub integration points. The core entry points most DAGs use are:\n\n- `GithubHook`\n- `GithubOperator`\n\nIn practice, `GithubHook` is the more flexible choice because it gives your task Python code direct access to the underlying GitHub client.\n\n## Install\n\nInstall the provider into the same environment as Airflow and keep both versions pinned. The Apache Airflow project recommends installing providers with the constraints file that matches your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"2.11.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-github==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i github\nairflow info\n```\n\n## Authentication And Connection Setup\n\nStart with a minimal Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nSet the GitHub values you want Airflow to use:\n\n```bash\nexport GITHUB_API_URL=\"https://api.github.com\"\nexport GITHUB_TOKEN=\"<github-token>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'github_default' \\\n  --conn-type 'github' \\\n  --conn-host \"$GITHUB_API_URL\" \\\n  --conn-password \"$GITHUB_TOKEN\"\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get github_default\n```\n\nNotes:\n\n- For GitHub Enterprise Server, set `GITHUB_API_URL` to the API root such as `https://github.example.com/api/v3`, not the web UI root.\n- Use a token with the repository permissions your DAG needs. For example, creating issues requires issue-write permission on the target repository.\n- Keep the Airflow connection id in DAG code stable and move environment-specific token values into your secrets backend or deployment config.\n\n## Common Workflow: Read Repository Data In A Task\n\nUse `GithubHook` when a task needs normal Python control flow and direct access to repository objects.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.github.hooks.github import GithubHook\n\n\nwith DAG(\n    dag_id=\"github_list_open_pull_requests\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"github\"],\n):\n    @task()\n    def list_open_pull_requests() -> list[str]:\n        hook = GithubHook(github_conn_id=\"github_default\")\n        client = hook.get_conn()\n\n        repo = client.get_repo(\"apache/airflow\")\n        pulls = repo.get_pulls(state=\"open\")\n\n        return [f\"#{pr.number} {pr.title}\" for pr in pulls[:10]]\n\n    list_open_pull_requests()\n```\n\nThe important pattern is:\n\n1. create `GithubHook(github_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned GitHub client for normal PyGithub calls such as `get_repo()`, `get_pulls()`, `get_issues()`, and other repository methods\n\nReturn small strings, numbers, or dictionaries to XCom rather than full PyGithub objects.\n\n## Common Workflow: Create An Issue\n\nUse the hook when a task needs to look up a repository and then perform one or more writes.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.github.hooks.github import GithubHook\n\n\nwith DAG(\n    dag_id=\"github_create_issue_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"github\"],\n):\n    @task()\n    def create_issue() -> str:\n        hook = GithubHook(github_conn_id=\"github_default\")\n        client = hook.get_conn()\n\n        repo = client.get_repo(\"OWNER/REPO\")\n        issue = repo.create_issue(\n            title=\"Airflow provider demo issue\",\n            body=\"Opened from an Airflow task using GithubHook.\",\n        )\n\n        return issue.html_url\n\n    create_issue()\n```\n\nUse this pattern when the task needs to open an issue, add comments, inspect pull requests, or combine multiple GitHub API calls in one task body.\n\n## When To Use `GithubOperator`\n\n`GithubOperator` is useful when a task is a single top-level GitHub client call and you do not need much Python control flow around it.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.github.operators.github import GithubOperator\n\n\nwith DAG(\n    dag_id=\"github_operator_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"github\"],\n):\n    lookup_repo = GithubOperator(\n        task_id=\"lookup_repo\",\n        github_conn_id=\"github_default\",\n        github_method=\"get_repo\",\n        github_method_args={\"full_name_or_id\": \"apache/airflow\"},\n    )\n```\n\nPrefer the hook form when downstream tasks need a small derived result rather than a live PyGithub object.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i github\nairflow dags list | grep github\n```\n\nTest a task in isolation while you wire up the connection and repository permissions:\n\n```bash\nairflow tasks test github_create_issue_demo create_issue 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream dependencies to participate.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Hard-coding GitHub tokens in DAG code instead of keeping them on the Airflow connection.\n- Pointing GitHub Enterprise Server traffic at the web UI host instead of the API root ending in `/api/v3`.\n- Returning large PyGithub objects through XCom instead of small serializable values.\n- Assuming a valid token automatically has the repository permissions your DAG needs.\n- Forgetting that workers, not just the webserver, need network access to the GitHub API endpoint.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-github` version `2.11.0`.\n- The Airflow provider `stable/` docs root moves as new provider releases ship, so keep your pinned Airflow and provider versions as the final authority during upgrades.\n\n## Official Sources\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-github/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-github/stable/index.html`\n- GitHub connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-github/stable/connections/github.html`\n- `GithubHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-github/stable/_api/airflow/providers/github/hooks/github/index.html`\n- `GithubOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-github/stable/_api/airflow/providers/github/operators/github/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-github/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-google/python/DOC.md",
    "content": "---\nname: providers-google\ndescription: \"Apache Airflow Google provider for running Google Cloud workflows with Airflow operators, hooks, sensors, and transfers\"\nmetadata:\n  languages: \"python\"\n  versions: \"20.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,google-cloud,gcp,bigquery,gcs,dag\"\n---\n\n# Apache Airflow Google Provider Python Guide\n\n## Golden Rule\n\n`apache-airflow-providers-google` is an Airflow provider package, not a standalone SDK. Install it into an existing Airflow environment, configure a Google connection such as `google_cloud_default`, and let operators and hooks authenticate through Airflow Connections or Application Default Credentials instead of embedding service-account keys in DAG code.\n\n## Install\n\nInstall the provider into the same virtual environment as Airflow.\n\nIf you already have Airflow installed, pin the existing Airflow version in the same command so the resolver does not silently replace core:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-google==20.0.0\"\n```\n\nIf you are creating the environment from scratch, install Airflow first using the official Airflow installation flow for your Python version, then add this provider.\n\n## Authentication And Connection Setup\n\nThe provider reads credentials from an Airflow connection. The conventional connection ID is `google_cloud_default`, and most operators let you override it with `gcp_conn_id`.\n\nFor local development, the simplest setup is an empty Google connection plus Google Application Default Credentials:\n\n```bash\nexport AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT='google-cloud-platform://'\nexport GOOGLE_APPLICATION_CREDENTIALS='/path/to/service-account.json'\nexport GOOGLE_CLOUD_PROJECT='your-gcp-project'\n```\n\nWhat this does:\n\n- `AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT` creates the Airflow connection from an environment variable\n- `GOOGLE_APPLICATION_CREDENTIALS` points Google auth to a service-account JSON file\n- `GOOGLE_CLOUD_PROJECT` gives client libraries and some tasks a default project value\n\nProduction guidance:\n\n- Prefer an attached service account, Workload Identity, or another short-lived credential flow over long-lived JSON keys.\n- Keep credentials in Airflow Connections, secret backends, or the runtime environment, not in DAG source files.\n- Pass `gcp_conn_id=\"your-connection-id\"` explicitly when a DAG uses anything other than `google_cloud_default`.\n- Use `impersonation_chain` when tasks should run as a different Google service account than the worker's base identity.\n\n## BigQuery Jobs\n\nFor SQL, load jobs, and copy jobs, `BigQueryInsertJobOperator` is the operator to reach for first. It submits a standard BigQuery job configuration and works well for idempotent DAG tasks.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG\nfrom airflow.providers.google.cloud.operators.bigquery import BigQueryInsertJobOperator\n\nwith DAG(\n    dag_id=\"bigquery_daily_report\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"google\", \"bigquery\"],\n):\n    run_query = BigQueryInsertJobOperator(\n        task_id=\"run_query\",\n        gcp_conn_id=\"google_cloud_default\",\n        project_id=\"your-gcp-project\",\n        location=\"US\",\n        configuration={\n            \"query\": {\n                \"query\": \"\"\"\n                CREATE OR REPLACE TABLE `your-gcp-project.analytics.daily_orders` AS\n                SELECT CURRENT_DATE() AS run_date, COUNT(*) AS order_count\n                FROM `bigquery-public-data.samples.shakespeare`\n                \"\"\",\n                \"useLegacySql\": False,\n            }\n        },\n    )\n```\n\nImportant BigQuery details:\n\n- Set `location` to the region or multi-region used by the dataset and job.\n- Keep `useLegacySql` explicit unless you intentionally need legacy SQL.\n- Treat `configuration` as the source of truth for the BigQuery job you want to run.\n\n## Cloud Storage Uploads And Listing\n\nFor Cloud Storage file movement inside a DAG, use the provider's transfer and operator classes instead of shelling out to `gsutil`.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.sdk import DAG\nfrom airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator\nfrom airflow.providers.google.cloud.transfers.local_to_gcs import LocalFilesystemToGCSOperator\n\nwith DAG(\n    dag_id=\"gcs_upload_and_list\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"google\", \"gcs\"],\n):\n    upload_report = LocalFilesystemToGCSOperator(\n        task_id=\"upload_report\",\n        gcp_conn_id=\"google_cloud_default\",\n        src=\"/opt/airflow/dags/data/report.csv\",\n        dst=\"incoming/report.csv\",\n        bucket=\"your-bucket\",\n        mime_type=\"text/csv\",\n    )\n\n    list_incoming = GCSListObjectsOperator(\n        task_id=\"list_incoming\",\n        gcp_conn_id=\"google_cloud_default\",\n        bucket=\"your-bucket\",\n        prefix=\"incoming/\",\n    )\n\n    upload_report >> list_incoming\n```\n\nUse this pattern when a DAG needs to stage files into GCS before BigQuery loads, Dataflow jobs, or downstream batch processing.\n\n## Hooks Inside Python Tasks\n\nWhen you need custom Python logic instead of a prebuilt operator, import a Google hook from `airflow.providers.google.cloud.hooks.*` and let it resolve credentials from the same Airflow connection.\n\nExample import paths you will commonly reach for:\n\n```python\nfrom airflow.providers.google.cloud.hooks.bigquery import BigQueryHook\nfrom airflow.providers.google.cloud.hooks.gcs import GCSHook\n```\n\nUse hooks inside Python tasks for small, service-specific operations. Use operators when the provider already exposes the workflow you need as a first-class Airflow task.\n\n## Common Patterns\n\n- Use `gcp_conn_id` consistently across related tasks in the same DAG.\n- Pass `project_id`, dataset names, bucket names, and locations explicitly instead of assuming every operator will infer them.\n- Keep Google-specific configuration in operator arguments and Airflow connections, not in ad hoc environment parsing inside task bodies.\n- Reuse the provider's transfers and operators for common workflows such as local-file-to-GCS, GCS-to-BigQuery, and BigQuery job submission.\n\n## Pitfalls\n\n- This package does not replace `apache-airflow`; it extends it.\n- A task can authenticate successfully and still fail if the target Google API is not enabled or the service account lacks IAM permissions.\n- BigQuery region mismatches are a common source of job failures; align `location` with the dataset and destination resources.\n- Do not hard-code service-account JSON into DAG files or commit key files into the repository.\n- If a DAG uses multiple Google identities, set separate Airflow connections or use `impersonation_chain` deliberately instead of relying on whichever ambient credentials happen to exist.\n\n## When To Reach For The Provider\n\nUse `apache-airflow-providers-google` when Airflow should orchestrate Google Cloud work as DAG tasks. If you are writing a regular Python application instead of an Airflow DAG or plugin, use the service-specific Google client library directly, such as `google-cloud-storage` or `google-cloud-bigquery`.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-grpc/python/DOC.md",
    "content": "---\nname: providers-grpc\ndescription: \"Apache Airflow gRPC provider for calling protobuf-defined gRPC services from DAGs with hooks and operators\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,grpc,protobuf,operators,hooks\"\n---\n\n# Apache Airflow gRPC Provider Guide\n\nUse `apache-airflow-providers-grpc` when an Airflow DAG needs to call a gRPC service through generated protobuf stubs instead of making raw HTTP requests.\n\n## Golden Rule\n\n- Install this package alongside `apache-airflow`; it extends Airflow and is not a standalone gRPC client.\n- Generate and ship your Python protobuf client modules with your Airflow code. The provider expects a generated stub class such as `GreeterStub`; it does not compile `.proto` files for you.\n- Keep endpoint details and secrets in an Airflow connection, then keep DAG code focused on `stub_class`, `call_func`, and request data.\n- Use `GrpcOperator` for straightforward RPC tasks and `GrpcHook` when task code needs direct control over the call and response.\n\n## What This Package Adds\n\nThis provider supplies Airflow's gRPC integration, including:\n\n- `GrpcOperator`\n- `GrpcHook`\n\nThese are the main entry points most DAGs use from this provider.\n\n## Install\n\nInstall the provider into the same Airflow environment used by your scheduler, webserver, triggerer, and workers.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.9.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-grpc==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf you need to generate Python modules from `.proto` files as part of your build, install `grpcio-tools` in the image or virtualenv that performs code generation.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i grpc\npython -c \"from airflow.providers.grpc.hooks.grpc import GrpcHook; from airflow.providers.grpc.operators.grpc import GrpcOperator; print('ok')\"\n```\n\n## Prepare The Generated gRPC Client Code\n\nThe provider works with the Python modules generated from your service definition. Your DAG code typically imports:\n\n- the generated stub class from `*_pb2_grpc.py`\n- the generated request and response message classes from `*_pb2.py`\n\nExample imports:\n\n```python\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n```\n\nMake sure those generated modules are available everywhere Airflow may import and execute the DAG.\n\n## Configure A gRPC Connection\n\nStart with a basic Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nThen create a connection for the target service. Using the CLI keeps the host and port out of DAG code:\n\n```bash\nairflow connections add grpc_default \\\n  --conn-type grpc \\\n  --conn-host grpc.example.internal \\\n  --conn-port 50051\n```\n\nIf you prefer environment-based connection setup, use the matching connection id:\n\n```bash\nexport AIRFLOW_CONN_GRPC_DEFAULT='grpc://grpc.example.internal:50051'\n```\n\nPractical notes:\n\n- The example DAGs below use `grpc_default` because it matches `AIRFLOW_CONN_GRPC_DEFAULT`.\n- Keep TLS material, tokens, and other secrets in the Airflow connection or a secrets backend instead of hard-coding them in the DAG file.\n- Install the same connection configuration everywhere tasks may run; a connection present only on the webserver does not help a remote worker.\n\n## Call A Unary RPC With `GrpcOperator`\n\nUse `GrpcOperator` when the task is mostly \"call one RPC and handle the response\".\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.grpc.operators.grpc import GrpcOperator\nfrom pendulum import datetime\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nwith DAG(\n    dag_id=\"grpc_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    say_hello = GrpcOperator(\n        task_id=\"say_hello\",\n        grpc_conn_id=\"grpc_default\",\n        stub_class=helloworld_pb2_grpc.GreeterStub,\n        call_func=\"SayHello\",\n        data=helloworld_pb2.HelloRequest(name=\"Airflow\"),\n    )\n```\n\nImportant pieces:\n\n- `grpc_conn_id` selects the Airflow connection.\n- `stub_class` is the generated client stub class from `*_pb2_grpc.py`.\n- `call_func` is the RPC method name on that stub as a string.\n- `data` is the request payload passed to the RPC, typically a generated protobuf request object.\n\nThis pattern is the simplest fit for unary RPC calls that do not need custom task logic around the response.\n\n## Call gRPC Directly In Task Code With `GrpcHook`\n\nUse `GrpcHook` inside a TaskFlow or Python task when you need to inspect the response object directly in Python.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.grpc.hooks.grpc import GrpcHook\nfrom pendulum import datetime\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nwith DAG(\n    dag_id=\"grpc_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def fetch_greeting() -> str:\n        hook = GrpcHook(grpc_conn_id=\"grpc_default\")\n        response = hook.run(\n            stub_class=helloworld_pb2_grpc.GreeterStub,\n            call_func=\"SayHello\",\n            data=helloworld_pb2.HelloRequest(name=\"Airflow\"),\n        )\n\n        print(response.message)\n        return response.message\n\n    fetch_greeting()\n```\n\nUse this pattern when you want normal Python control flow around the RPC result before returning a small value to downstream tasks.\n\n## Common Workflow Pattern\n\nFor most DAGs, a clean split is:\n\n- define the gRPC endpoint and secrets on an Airflow connection\n- import the generated protobuf stub class in DAG code\n- call one RPC with `GrpcOperator` for simple request/response work\n- switch to `GrpcHook` when you need to inspect or transform the protobuf response in Python\n- return only small derived values from tasks instead of large raw payloads when downstream tasks do not need the full response\n\n## Common Pitfalls\n\n- Installing the provider only on one Airflow component. Every image or virtualenv that parses or runs the DAG needs the provider and your generated protobuf modules.\n- Forgetting the generated stubs. `GrpcOperator` and `GrpcHook` require the real generated `*_pb2_grpc.py` client stub class.\n- Passing the wrong RPC name in `call_func`. It must match the generated stub method name exactly.\n- Hard-coding hostnames, ports, or secrets in the DAG instead of using an Airflow connection.\n- Returning large protobuf payloads through XCom when downstream tasks only need a small field such as an id or status string.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-grpc` version `3.9.2`.\n- Check the provider's connection and API reference pages before upgrading across provider releases, especially if your deployment relies on custom channel setup, interceptors, or other advanced hook behavior.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-grpc/stable/`\n- gRPC connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-grpc/stable/connections/grpc.html`\n- `GrpcHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-grpc/stable/_api/airflow/providers/grpc/hooks/grpc/index.html`\n- `GrpcOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-grpc/stable/_api/airflow/providers/grpc/operators/grpc/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-grpc/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-hashicorp/python/DOC.md",
    "content": "---\nname: providers-hashicorp\ndescription: \"Apache Airflow HashiCorp provider for Vault connections, secret reads and writes, and Vault-backed Airflow secrets\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,hashicorp,vault,secrets,dag,python\"\n---\n\n# apache-airflow-providers-hashicorp\n\nUse `apache-airflow-providers-hashicorp` when your DAGs need to read or write HashiCorp Vault secrets with `VaultHook`, or when Airflow itself should resolve Connections and Variables from Vault through `VaultBackend`.\n\nThis guide targets provider version `4.5.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by every Airflow component that parses or runs DAGs.\n\nThe provider docs list these requirements for `4.5.0`:\n\n- `apache-airflow>=2.11.0`\n- `hvac>=1.1.0`\n\nIf Airflow is already installed, keep it pinned when adding the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-hashicorp==4.5.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep hashicorp\nairflow info\n```\n\n## Configure A Vault Connection\n\nThe provider's default connection ID is `vault_default`. The connection type is `Vault`.\n\nThe maintainer connection docs map the Airflow connection fields like this:\n\n- `Host`: Vault host name\n- `Schema`: secret mount point, default `secret`\n- `Login`: username for `ldap` and `userpass`; also used as AppRole `role_id`\n- `Password`: password for `ldap`, `userpass`, and `token`\n- `Port`: Vault port, usually `8200`\n- `Extra`: JSON for provider-specific options such as `auth_type`, `auth_mount_point`, and `kv_engine_version`\n\nCreate a token-based connection with the Airflow CLI:\n\n```bash\nairflow connections add 'vault_default' \\\n  --conn-type 'vault' \\\n  --conn-host 'vault.example.com' \\\n  --conn-schema 'airflow' \\\n  --conn-port '8200' \\\n  --conn-password 's.xxxxxxxx' \\\n  --conn-extra '{\"auth_type\":\"token\",\"kv_engine_version\":2}'\n```\n\nImportant connection extras from the provider docs and API reference:\n\n- `auth_type`: `token`, `github`, `approle`, `kubernetes`, `gcp`, `azure`, `ldap`, `radius`, `userpass`, or `jwt`\n- `auth_mount_point`: non-default auth mount if your Vault auth backend is not mounted at the default path\n- `kv_engine_version`: `1` or `2`; defaults to `2`\n- `token_path`: file path to a token, useful when you do not want the token in the Airflow connection password\n- `kubernetes_role`: role name for Kubernetes auth\n- `jwt_role`, `jwt_token`, `jwt_token_path`: JWT auth parameters added in the current API docs\n\nUse Airflow connections, Vault auth files, or a secrets backend for credentials. Do not hard-code Vault tokens in DAG files.\n\n## Read And Write Vault Secrets In DAG Code\n\n`VaultHook` is the package's main Python API surface for task code.\n\n```python\nfrom __future__ import annotations\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.hashicorp.hooks.vault import VaultHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"vault_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"vault\"],\n) as dag:\n    @task\n    def read_secret() -> str:\n        hook = VaultHook(vault_conn_id=\"vault_default\")\n        secret = hook.get_secret(secret_path=\"applications/payments/api\") or {}\n        api_key = secret[\"api_key\"]\n        print(f\"loaded key prefix: {api_key[:4]}\")\n        return api_key\n\n    @task\n    def write_secret() -> None:\n        hook = VaultHook(vault_conn_id=\"vault_default\")\n        hook.create_or_update_secret(\n            secret_path=\"applications/payments/runtime\",\n            secret={\"rotated_by\": \"airflow\", \"status\": \"ok\"},\n        )\n\n    read_secret() >> write_secret()\n```\n\nThe public hook methods documented in the API reference are:\n\n- `get_secret(secret_path, secret_version=None)` to read a secret as a dictionary\n- `get_secret_metadata(secret_path)` to fetch KV v2 metadata\n- `get_secret_including_metadata(secret_path, secret_version=None)` when you need both the data and metadata payload\n- `create_or_update_secret(secret_path, secret, cas=None)` to write secret data\n\nIf your Vault mount uses KV v1, do not pass `secret_version` and do not expect metadata methods to work. Those behaviors are KV v2-specific.\n\n## Use Vault As Airflow's Secrets Backend\n\nThe provider also exposes `VaultBackend`, which lets Airflow resolve Connections, Variables, and optional config values from Vault instead of only from the Airflow metadata database.\n\nSet the backend in the Airflow environment:\n\n```bash\nexport AIRFLOW__SECRETS__BACKEND=\"airflow.providers.hashicorp.secrets.vault.VaultBackend\"\nexport AIRFLOW__SECRETS__BACKEND_KWARGS='{\n  \"connections_path\": \"connections\",\n  \"variables_path\": \"variables\",\n  \"mount_point\": \"airflow\",\n  \"url\": \"http://127.0.0.1:8200\",\n  \"auth_type\": \"token\",\n  \"token\": \"s.xxxxxxxx\",\n  \"kv_engine_version\": 2\n}'\n```\n\nThe backend docs show the corresponding Vault KV setup:\n\n```bash\nvault secrets enable -path=airflow -version=2 kv\nvault kv put airflow/connections/smtp_default conn_uri=smtps://user:pass@relay.example.com:465\nvault kv put airflow/variables/deploy_env value=prod\n```\n\nOnce configured, use the normal Airflow APIs in code:\n\n```python\nfrom airflow.hooks.base import BaseHook\nfrom airflow.models import Variable\n\n\nsmtp_conn = BaseHook.get_connection(\"smtp_default\")\ndeploy_env = Variable.get(\"deploy_env\")\n\nprint(smtp_conn.host)\nprint(deploy_env)\n```\n\nBackend lookup behavior from the maintainer docs:\n\n- `connections_path` controls where Connection IDs are resolved\n- `variables_path` controls where Variables are resolved\n- `config_path` is optional for Airflow config values\n- set any of those paths to `null` to disable lookups for that category\n- if you omit `url`, the backend can also use standard Vault client environment variables such as `VAULT_ADDR`\n\nAfter changing backend settings, restart all Airflow components that need to read secrets through Vault.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and the connection:\n\n```bash\nairflow providers list | grep hashicorp\nairflow connections get vault_default\n```\n\nValidate a task import and Vault access path without waiting for the scheduler:\n\n```bash\nairflow dags list\nairflow tasks test vault_hook_example read_secret 2026-03-13\n```\n\n## Common Pitfalls\n\n- Install the provider everywhere DAG code runs. A worker image missing the package will fail on import even if the scheduler has it.\n- `Schema` is the Vault secret mount point, not an HTTP URL scheme. If your secrets live under `airflow/...`, set the connection schema or backend `mount_point` to `airflow`.\n- `kv_engine_version` defaults to `2`. Set it explicitly to `1` when your Vault mount uses KV v1.\n- `get_secret_metadata(...)` and versioned reads are for KV v2. They are not interchangeable with KV v1 mounts.\n- AppRole changed in provider `4.0.0`: the changelog says `role_id` moved from connection extras to the connection login field.\n- Provider `4.5.0` adds JWT and OIDC auth support in the changelog, and the current `VaultHook` API exposes `auth_type=\"jwt\"` plus `jwt_role`, `jwt_token`, and `jwt_token_path`. The connection guide page still shows an older auth-type list, so use the current API reference when wiring JWT auth.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/`\n- Installation and requirements: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/index.html`\n- Vault connection type: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/connections/vault.html`\n- Vault secrets backend: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/secrets-backends/hashicorp-vault.html`\n- `VaultHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/_api/airflow/providers/hashicorp/hooks/vault/index.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-hashicorp/stable/changelog.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-http/python/DOC.md",
    "content": "---\nname: providers-http\ndescription: \"Apache Airflow HTTP provider for calling HTTP and REST endpoints with hooks, operators, and sensors\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,http,rest,operators,sensors,hooks\"\n---\n\n# Apache Airflow HTTP Provider Guide\n\nUse `apache-airflow-providers-http` when an Airflow DAG needs to call an HTTP endpoint, wait for a health check to succeed, or wrap a custom REST workflow in Python code.\n\n## Golden Rule\n\n- Install this package alongside `apache-airflow`; it is not a standalone HTTP client.\n- Put the remote server details on an Airflow `HTTP` connection, then keep DAG code focused on `endpoint`, headers, and response handling.\n- Use `HttpOperator` for request/response tasks, `HttpSensor` for readiness checks, and `HttpHook` when task code needs lower-level control.\n- Keep API tokens and passwords in Airflow connections, variables, or a secrets backend instead of hard-coding them in DAG files.\n\n## What This Package Adds\n\nThis provider supplies Airflow's HTTP integration, including:\n\n- `HttpOperator`\n- `HttpSensor`\n- `HttpHook`\n\nThese are the core entry points most DAGs use from this provider.\n\n## Install\n\nInstall the provider with your Airflow environment and keep the provider version pinned:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"6.0.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-http==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i http\n```\n\n## Configure An HTTP Connection\n\nStart with a basic Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nFor a plain HTTP endpoint, define the connection as a URI:\n\n```bash\nexport AIRFLOW_CONN_HTTP_DEFAULT='http://api_user:api_password@api.example.com:80'\n```\n\nFor an HTTPS endpoint, the HTTP provider uses Airflow's historical connection parsing, so the URI looks unusual:\n\n```bash\nexport AIRFLOW_CONN_HTTP_DEFAULT='http://api_user:api_password@api.example.com:443/https'\n```\n\nImportant notes:\n\n- The connection id in the examples below is `http_default` because it matches `AIRFLOW_CONN_HTTP_DEFAULT`.\n- The `/https` path segment is the provider's documented way to signal TLS when using URI-style environment variables.\n- If you prefer not to use the URI form, create the connection in the Airflow UI or CLI with connection type `HTTP`.\n- If usernames or passwords contain reserved URL characters, URL-encode them before putting them in `AIRFLOW_CONN_HTTP_DEFAULT`.\n\n## Call An API With `HttpOperator`\n\nUse `HttpOperator` when the task is mostly \"make a request, check the response, optionally return a small parsed value\".\n\n```python\nimport json\n\nfrom airflow import DAG\nfrom airflow.providers.http.operators.http import HttpOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"http_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_order = HttpOperator(\n        task_id=\"create_order\",\n        http_conn_id=\"http_default\",\n        method=\"POST\",\n        endpoint=\"v1/orders\",\n        data=json.dumps({\"sku\": \"sku_123\", \"quantity\": 1}),\n        headers={\n            \"Accept\": \"application/json\",\n            \"Content-Type\": \"application/json\",\n            \"Authorization\": \"Bearer {{ var.value.example_api_token }}\",\n        },\n        response_check=lambda response: response.status_code == 201,\n        response_filter=lambda response: response.json()[\"id\"],\n        log_response=True,\n    )\n```\n\nPractical points:\n\n- `http_conn_id` selects the Airflow HTTP connection.\n- `endpoint` is the path appended to that connection's base URL.\n- `response_check` should return `True` for a successful response.\n- `response_filter` is the easiest way to return a small JSON fragment to XCom instead of the entire response body.\n\n## Wait For A Service With `HttpSensor`\n\nUse `HttpSensor` when a downstream task should not run until an HTTP endpoint is ready:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.http.sensors.http import HttpSensor\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"http_sensor_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    wait_for_api = HttpSensor(\n        task_id=\"wait_for_api\",\n        http_conn_id=\"http_default\",\n        endpoint=\"health\",\n        response_check=lambda response: response.status_code == 200,\n        poke_interval=30,\n        timeout=300,\n    )\n```\n\nThis pattern is useful for partner APIs, internal services, and rollout checks where a simple `200 OK` gate is enough.\n\n## Use `HttpHook` Inside TaskFlow Code\n\nUse `HttpHook` when task logic needs direct access to the response object:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.models import Variable\nfrom airflow.providers.http.hooks.http import HttpHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"http_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def fetch_user() -> dict:\n        token = Variable.get(\"example_api_token\")\n\n        hook = HttpHook(method=\"GET\", http_conn_id=\"http_default\")\n        response = hook.run(\n            endpoint=\"v1/users/42\",\n            headers={\n                \"Accept\": \"application/json\",\n                \"Authorization\": f\"Bearer {token}\",\n            },\n        )\n\n        response.raise_for_status()\n        return response.json()\n\n    fetch_user()\n```\n\n`hook.run(...)` returns a `requests.Response`, so you can call normal response methods such as `raise_for_status()`, `json()`, and `text`.\n\n## Auth And Configuration Pattern\n\nFor most DAGs, a clean split is:\n\n- keep the host, port, and basic connection details on `http_default` or another named Airflow HTTP connection\n- keep bearer tokens in an Airflow Variable or secrets backend and pass them through the `Authorization` header\n- use `HttpOperator` when the task only needs a request plus a small parsed result\n- use `HttpHook` when Python code must inspect headers, status codes, or response bodies more directly\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. Import errors usually mean one scheduler, worker, or task image is missing the package.\n- Use `http_conn_id` for this provider's classes. Do not replace it with a generic `conn_id`.\n- HTTPS connection URIs are intentionally counter-intuitive in environment-variable form; use the documented `...:443/https` pattern or configure the connection in the Airflow UI.\n- Keep XCom payloads small. If an endpoint returns large JSON, use `response_filter` to return only the fields later tasks need.\n- Keep credentials out of DAG source. Use Airflow connections, variables, or your secrets backend instead of literal tokens in Python files.\n\n## Version Notes\n\nThis guide targets `apache-airflow-providers-http` version `6.0.0`. Provider packages track Airflow compatibility separately from Airflow core, so re-check the provider docs before changing Airflow core and provider versions independently.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-http/stable/`\n- HTTP connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-http/stable/connections/http.html`\n- `HttpHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-http/stable/_api/airflow/providers/http/hooks/http/index.html`\n- `HttpOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-http/stable/_api/airflow/providers/http/operators/http/index.html`\n- `HttpSensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-http/stable/_api/airflow/providers/http/sensors/http/index.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-http/6.0.0/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-imap/python/DOC.md",
    "content": "---\nname: providers-imap\ndescription: \"Apache Airflow IMAP provider guide for configuring IMAP connections and reading mailbox data from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,imap,email,dag,python\"\n---\n\n# apache-airflow-providers-imap\n\nUse `apache-airflow-providers-imap` when your Airflow DAGs need an Airflow-managed IMAP connection and Python task code that reads mailbox state or message content through the standard IMAP client.\n\nThis guide targets provider version `3.11.0`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone email library.\n- Keep IMAP credentials in an Airflow connection such as `imap_default` instead of hard-coding them in DAG files.\n- Use `ImapHook` inside tasks, then call standard IMAP methods on the client returned by `get_conn()`.\n\n## Install\n\nStart from an Airflow installation that uses the official constraints file for your Airflow and Python versions, then add the IMAP provider in the same command.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.11.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-imap==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-imap==3.11.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i imap\nairflow info\n```\n\nIn practice, every Airflow image or environment that imports DAGs or runs tasks must have the provider installed.\n\n## Configure An IMAP Connection\n\nCreate an Airflow connection with connection type `imap`. A common connection id is `imap_default`.\n\nSet shell variables first:\n\n```bash\nexport IMAP_HOST=\"imap.example.com\"\nexport IMAP_PORT=\"993\"\nexport IMAP_USERNAME=\"alerts@example.com\"\nexport IMAP_PASSWORD=\"<app-password-or-mail-password>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'imap_default' \\\n  --conn-type 'imap' \\\n  --conn-host \"$IMAP_HOST\" \\\n  --conn-port \"$IMAP_PORT\" \\\n  --conn-login \"$IMAP_USERNAME\" \\\n  --conn-password \"$IMAP_PASSWORD\"\n```\n\nConfirm the connection exists before wiring it into a DAG:\n\n```bash\nairflow connections get imap_default\n```\n\nKeep secrets in Airflow connections or a secrets backend instead of embedding usernames and passwords in DAG code.\n\n## Use `ImapHook` In A Task\n\nUse `ImapHook` when task code needs to talk to the mailbox directly. The hook manages Airflow connection lookup, and `get_conn()` returns the IMAP client you use for normal mailbox operations.\n\n```python\nfrom __future__ import annotations\n\nfrom email import message_from_bytes\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.imap.hooks.imap import ImapHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"imap_list_unseen_subjects\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def list_unseen_subjects() -> list[str]:\n        hook = ImapHook(imap_conn_id=\"imap_default\")\n        client = hook.get_conn()\n\n        try:\n            status, _ = client.select(\"INBOX\")\n            if status != \"OK\":\n                raise RuntimeError(\"failed to select INBOX\")\n\n            status, data = client.search(None, \"UNSEEN\")\n            if status != \"OK\":\n                raise RuntimeError(\"failed to search mailbox\")\n\n            subjects: list[str] = []\n\n            for message_id in data[0].split():\n                fetch_status, message_data = client.fetch(message_id, \"(RFC822)\")\n                if fetch_status != \"OK\":\n                    raise RuntimeError(f\"failed to fetch message {message_id!r}\")\n\n                raw_message = message_data[0][1]\n                message = message_from_bytes(raw_message)\n                subjects.append(message.get(\"Subject\", \"\"))\n\n            return subjects\n        finally:\n            client.logout()\n\n    list_unseen_subjects()\n```\n\nThe important pattern is:\n\n1. create `ImapHook(imap_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned IMAP client for normal IMAP calls such as `select()`, `search()`, `fetch()`, and `logout()`\n\n## Save A Matching Attachment From A Mailbox\n\nFor mailbox-driven ingestion, combine `ImapHook` with the standard library `email` package to inspect MIME parts and persist the file you care about.\n\n```python\nfrom __future__ import annotations\n\nfrom email import message_from_bytes\nfrom pathlib import Path\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.imap.hooks.imap import ImapHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"imap_download_attachment\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def save_attachment() -> str:\n        hook = ImapHook(imap_conn_id=\"imap_default\")\n        client = hook.get_conn()\n\n        try:\n            status, _ = client.select(\"INBOX\")\n            if status != \"OK\":\n                raise RuntimeError(\"failed to select INBOX\")\n\n            status, data = client.search(None, \"UNSEEN\")\n            if status != \"OK\":\n                raise RuntimeError(\"failed to search mailbox\")\n\n            for message_id in data[0].split():\n                fetch_status, message_data = client.fetch(message_id, \"(RFC822)\")\n                if fetch_status != \"OK\":\n                    continue\n\n                raw_message = message_data[0][1]\n                message = message_from_bytes(raw_message)\n\n                for part in message.walk():\n                    filename = part.get_filename()\n                    if filename != \"report.csv\":\n                        continue\n\n                    payload = part.get_payload(decode=True)\n                    if payload is None:\n                        continue\n\n                    output_path = Path(\"/opt/airflow/data/report.csv\")\n                    output_path.parent.mkdir(parents=True, exist_ok=True)\n                    output_path.write_bytes(payload)\n                    return str(output_path)\n\n            raise FileNotFoundError(\"report.csv not found in unseen messages\")\n        finally:\n            client.logout()\n\n    save_attachment()\n```\n\nThis pattern is useful when downstream tasks need a local file path or when you want full control over which mailbox, message flags, and attachment names count as a match.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep host, port, username, and password in an Airflow connection\n- create the IMAP client inside a task with `ImapHook`\n- parse message bodies and attachments with Python's standard `email` library\n- return only small derived values from tasks instead of entire raw messages\n\n## Pitfalls\n\n- Installing the provider only on the scheduler or webserver: workers also need it anywhere task code imports `airflow.providers.imap`.\n- Embedding mailbox credentials directly in DAG code instead of using Airflow connections or a secrets backend.\n- Forgetting to call `select()` before `search()` or `fetch()`.\n- Assuming IMAP responses are already decoded strings. Search results, message ids, and raw message payloads come back as bytes.\n- Leaving sessions open. Call `logout()` in a `finally` block so repeated task runs do not accumulate idle IMAP sessions.\n- Using a local output path that does not exist on the worker runtime. If you save attachments to disk, make sure the path exists inside the actual Airflow worker container or VM.\n- Assuming every mailbox is named `INBOX`. Verify the server's folder names before hard-coding other folders into DAG logic.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-imap` version `3.11.0`.\n- Pin the provider together with your Airflow core version and use the matching Airflow constraints file when you install or upgrade it.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-imap/stable/`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-imap/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-influxdb/python/DOC.md",
    "content": "---\nname: providers-influxdb\ndescription: \"Apache Airflow InfluxDB provider for Flux queries and hook-based InfluxDB workflows from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.10.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,influxdb,flux,time-series,dags,python\"\n---\n\n# Apache Airflow InfluxDB Provider Guide\n\nUse `apache-airflow-providers-influxdb` when an Airflow DAG needs to query InfluxDB with Flux or call the InfluxDB Python client through an Airflow connection.\n\n## Golden Rule\n\n- Install this package alongside `apache-airflow`; it is not a standalone InfluxDB client setup.\n- Put the server URL parts on an Airflow `influxdb` connection and keep the token plus org in connection extras.\n- Use `InfluxDBOperator` for query-only tasks and `InfluxDBHook` inside Python tasks when you need lower-level reads or writes.\n- Keep the bucket in the query or write call. The connection stores auth and endpoint details, not the bucket name.\n\n## What This Package Adds\n\nThe provider exposes two main entry points:\n\n- `InfluxDBOperator`\n- `InfluxDBHook`\n\nThose are the only classes most DAGs need from this package.\n\n## Install\n\nPyPI metadata for `2.10.2` requires Python `>=3.10,<3.14` and `apache-airflow>=2.11.0`.\n\nInstall the provider in the same Airflow environment or image that parses DAGs and runs tasks:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"2.10.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-influxdb==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful check after installation:\n\n```bash\nairflow providers list | grep -i influxdb\n```\n\n## Configure An InfluxDB Connection\n\nThe provider's connection type is `influxdb`.\n\nConnection fields the provider documents or uses directly:\n\n- `Host`: required InfluxDB host name\n- `Port`: set this explicitly; InfluxDB 2 usually uses `8086`\n- `Schema`: `https` for InfluxDB Cloud, `http` or `https` for self-managed deployments\n- `Extra`: JSON with `token`, `org`, and optional `timeout` in milliseconds\n\nAirflow supports JSON connection values in `AIRFLOW_CONN_*` environment variables, which is the easiest way to keep the connection reproducible in local development and containers:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nexport AIRFLOW_CONN_INFLUXDB_DEFAULT='{\n  \"conn_type\": \"influxdb\",\n  \"host\": \"us-east-1-1.aws.cloud2.influxdata.com\",\n  \"port\": 8086,\n  \"schema\": \"https\",\n  \"extra\": {\n    \"token\": \"your-influxdb-token\",\n    \"org\": \"your-org\",\n    \"timeout\": 10000\n  }\n}'\n```\n\nPractical notes:\n\n- The connection id is `influxdb_default` because that matches `AIRFLOW_CONN_INFLUXDB_DEFAULT`.\n- Put only the host in `host`; do not include `https://` there when you already set `schema`.\n- Keep the token in connection extras or a secrets backend, not in DAG source.\n- Set `port` and `schema` explicitly. The provider code builds the URI from those fields.\n\n## Run A Flux Query With `InfluxDBOperator`\n\nUse `InfluxDBOperator` when the task is just “run this Flux query against InfluxDB”.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.influxdb.operators.influxdb import InfluxDBOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"influxdb_query_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    query_cpu_usage = InfluxDBOperator(\n        task_id=\"query_cpu_usage\",\n        influxdb_conn_id=\"influxdb_default\",\n        sql=\"\"\"\n        from(bucket: \"metrics\")\n          |> range(start: -1h)\n          |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n          |> filter(fn: (r) => r[\"_field\"] == \"usage_user\")\n        \"\"\",\n    )\n```\n\nImportant details:\n\n- `sql` is the operator argument name even though the query language here is Flux.\n- The bucket must be part of the Flux query, for example `from(bucket: \"metrics\")`.\n- `sql` is a templated field, so you can inject Airflow macros if the time window or measurement changes per run.\n\n## Use `InfluxDBHook` In Python Tasks\n\nUse `InfluxDBHook` when task code needs to inspect returned records or write points.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.influxdb.hooks.influxdb import InfluxDBHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"influxdb_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def write_point() -> None:\n        hook = InfluxDBHook(conn_id=\"influxdb_default\")\n        hook.get_conn()\n        hook.write(\n            bucket_name=\"metrics\",\n            point_name=\"cpu\",\n            tag_name=\"host\",\n            tag_value=\"web-1\",\n            field_name=\"usage_user\",\n            field_value=0.82,\n            synchronous=True,\n        )\n\n    @task\n    def read_points() -> None:\n        hook = InfluxDBHook(conn_id=\"influxdb_default\")\n        tables = hook.query(\n            \"\"\"\n            from(bucket: \"metrics\")\n              |> range(start: -1h)\n              |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n              |> filter(fn: (r) => r[\"host\"] == \"web-1\")\n            \"\"\"\n        )\n\n        for table in tables:\n            for record in table.records:\n                print(record.get_time(), record.get_value())\n\n    write_point() >> read_points()\n```\n\nWhy this pattern matters:\n\n- `query(...)` initializes the client for you if needed.\n- `write(...)`, `create_bucket(...)`, and similar hook methods rely on the hook's client state, so call `get_conn()` before using them.\n- Returned query data is the InfluxDB client's normal Flux table structure, so iterate through `table.records` to access values.\n\n## Common Setup Pattern\n\nFor most DAGs, keep the workflow split simple:\n\n- create one shared Airflow connection such as `influxdb_default`\n- use `InfluxDBOperator` for query-only tasks\n- use `InfluxDBHook` in `@task` functions when you need Python logic around query results or writes\n- keep buckets, measurements, tags, and field names in task code or templated params instead of trying to store them on the connection\n\n## Pitfalls\n\n- Install the provider anywhere Airflow imports DAG code or executes tasks. Scheduler-only installs still fail once workers import `airflow.providers.influxdb`.\n- Set both `schema` and `port` on the Airflow connection instead of relying on defaults.\n- Keep the bucket inside the Flux query. The provider does not infer it from the connection.\n- Call `hook.get_conn()` before `write(...)` or other client-state methods.\n- Keep tokens out of DAG files. Use Airflow connections, environment-backed connections, or a secrets backend.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-influxdb` version `2.10.2`.\n- The PyPI package metadata for `2.10.2` requires `apache-airflow>=2.11.0`.\n- If you upgrade Airflow core or the provider independently, recheck the provider API reference before changing imports or connection settings.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-influxdb/stable/`\n- InfluxDB connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-influxdb/stable/connections/influxdb.html`\n- `InfluxDBHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-influxdb/stable/_api/airflow/providers/influxdb/hooks/influxdb/index.html`\n- `InfluxDBOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-influxdb/stable/_api/airflow/providers/influxdb/operators/influxdb/index.html`\n- System test example: `https://airflow.apache.org/docs/apache-airflow-providers-influxdb/stable/_modules/tests/system/influxdb/example_influxdb_query.html`\n- Airflow connection env-var docs: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-influxdb/2.10.2/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-jdbc/python/DOC.md",
    "content": "---\nname: providers-jdbc\ndescription: \"Apache Airflow JDBC provider for Airflow connections, SQL tasks, and JdbcHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,jdbc,sql,java,python,dag,database\"\n---\n\n# apache-airflow-providers-jdbc\n\nUse `apache-airflow-providers-jdbc` when an Airflow task needs to talk to a database through a JDBC driver instead of a database-specific Airflow provider.\n\nThis guide targets provider version `5.4.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-jdbc` is an Apache Airflow provider package. It adds:\n\n- the `jdbc` connection type\n- `JdbcHook` for Python task code\n- JDBC support for Airflow's generic SQL operators such as `SQLExecuteQueryOperator`\n\nThis package extends Airflow. It is not a standalone JDBC client for regular application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-jdbc==5.4.0\"\n```\n\n`5.4.0` requires:\n\n- `apache-airflow>=2.11.0`\n- Python `>=3.10`\n\nIf you are adding the provider to an existing Airflow environment, keep `apache-airflow` pinned in the same command so dependency resolution does not silently change your Airflow core version:\n\n```bash\npython -m pip install \"apache-airflow==<your-current-airflow-version>\" \"apache-airflow-providers-jdbc==5.4.0\"\n```\n\nYou also need these non-Python prerequisites anywhere JDBC tasks run:\n\n- a JVM\n- `JAVA_HOME` pointing at that JVM\n- the vendor JDBC driver JAR for your database\n\nExample environment variables:\n\n```bash\nexport JAVA_HOME=\"/usr/lib/jvm/temurin-17-jdk\"\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport JDBC_DRIVER_PATH=\"/opt/airflow/drivers/postgresql-42.7.5.jar\"\nexport JDBC_DRIVER_CLASS=\"org.postgresql.Driver\"\n```\n\nInstall the provider and place the JDBC driver JAR on every scheduler, worker, and other runtime image that may import or execute the DAG.\n\n## Configure The Airflow Connection\n\n`JdbcHook` uses `jdbc_default` by default. The JDBC provider expects the full JDBC URL in the connection's `host` field, which Airflow relabels as `Connection URL` in the UI.\n\nA portable way to define the connection is a JSON environment variable:\n\n```bash\nexport AIRFLOW_CONN_JDBC_DEFAULT='{\n  \"conn_type\": \"jdbc\",\n  \"host\": \"jdbc:postgresql://db.example.com:5432/warehouse\",\n  \"login\": \"airflow\",\n  \"password\": \"secret\"\n}'\n```\n\nYou can also create the same connection with the CLI:\n\n```bash\nairflow connections add jdbc_default --conn-json '{\n  \"conn_type\": \"jdbc\",\n  \"host\": \"jdbc:postgresql://db.example.com:5432/warehouse\",\n  \"login\": \"airflow\",\n  \"password\": \"secret\"\n}'\n```\n\nImportant connection details:\n\n- Put the entire JDBC URL in `host`, not just a hostname.\n- `JdbcHook` reads username and password from the Airflow connection.\n- Keep credentials in Airflow connections, environment variables, or a secrets backend instead of hard-coding them in DAG files.\n\n## Configure Driver Class And Driver Path\n\nThe safest pattern is to pass `driver_class` and `driver_path` in code:\n\n- `JdbcHook(..., driver_class=..., driver_path=...)`\n- `SQLExecuteQueryOperator(..., hook_params={\"driver_class\": ..., \"driver_path\": ...})`\n\nThe provider can also read `driver_class` and `driver_path` from connection `extra`, but only if you explicitly enable both config flags:\n\n```bash\nexport AIRFLOW__PROVIDERS_JDBC__ALLOW_DRIVER_CLASS_IN_EXTRA=true\nexport AIRFLOW__PROVIDERS_JDBC__ALLOW_DRIVER_PATH_IN_EXTRA=true\n```\n\nIf those flags stay at their default `False` values, `driver_class` and `driver_path` in the connection extra are ignored.\n\n## Run SQL In A DAG\n\nUse Airflow's generic SQL operator for SQL-only tasks. For JDBC connections, pass the Airflow connection id with `conn_id` and the driver settings through `hook_params`.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"jdbc_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"jdbc_default\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n            event_name VARCHAR(255) NOT NULL,\n            created_at TIMESTAMP NOT NULL\n        )\n        \"\"\",\n        autocommit=True,\n        hook_params={\n            \"driver_class\": \"org.postgresql.Driver\",\n            \"driver_path\": \"/opt/airflow/drivers/postgresql-42.7.5.jar\",\n        },\n    )\n\n    insert_row = SQLExecuteQueryOperator(\n        task_id=\"insert_row\",\n        conn_id=\"jdbc_default\",\n        sql=\"\"\"\n        INSERT INTO events (event_name, created_at)\n        VALUES ('signup', CURRENT_TIMESTAMP)\n        \"\"\",\n        autocommit=True,\n        hook_params={\n            \"driver_class\": \"org.postgresql.Driver\",\n            \"driver_path\": \"/opt/airflow/drivers/postgresql-42.7.5.jar\",\n        },\n    )\n\n    create_table >> insert_row\n```\n\nUseful `SQLExecuteQueryOperator` parameters for JDBC tasks:\n\n- `sql`: a single SQL string, a list of SQL strings, or a `.sql` template file path\n- `autocommit`: commit each statement automatically when set to `True`\n- `parameters`: values used when rendering the SQL query\n\n## Query JDBC Sources From Python Tasks\n\nUse `JdbcHook` when your task needs query results in Python.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.jdbc.hooks.jdbc import JdbcHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"jdbc_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> int:\n        hook = JdbcHook(\n            jdbc_conn_id=\"jdbc_default\",\n            driver_class=\"org.postgresql.Driver\",\n            driver_path=\"/opt/airflow/drivers/postgresql-42.7.5.jar\",\n        )\n\n        row = hook.get_first(\"SELECT COUNT(*) FROM events\")\n        return int(row[0]) if row else 0\n\n    read_summary()\n```\n\n`JdbcHook` uses `jdbc_conn_id`, not `conn_id`.\n\nThe hook's connection method calls `jaydebeapi.connect(...)` with:\n\n- the driver class\n- the JDBC URL from the Airflow connection\n- the Airflow login and password\n- the configured driver JAR path\n\n## Optional: SQLAlchemy Engine Access\n\nIf you call `JdbcHook.get_sqlalchemy_engine()`, set `sqlalchemy_scheme` in the connection extra. Without it, Airflow raises an exception because `jdbc` is a protocol, not a SQLAlchemy dialect.\n\nExample connection with SQLAlchemy metadata for PostgreSQL:\n\n```bash\nexport AIRFLOW_CONN_JDBC_ANALYTICS='{\n  \"conn_type\": \"jdbc\",\n  \"host\": \"jdbc:postgresql://db.example.com:5432/warehouse\",\n  \"login\": \"airflow\",\n  \"password\": \"secret\",\n  \"extra\": {\n    \"sqlalchemy_scheme\": \"postgresql+psycopg2\"\n  }\n}'\n```\n\nThen:\n\n```python\nfrom airflow.providers.jdbc.hooks.jdbc import JdbcHook\n\n\nhook = JdbcHook(\n    jdbc_conn_id=\"jdbc_analytics\",\n    driver_class=\"org.postgresql.Driver\",\n    driver_path=\"/opt/airflow/drivers/postgresql-42.7.5.jar\",\n)\nengine = hook.get_sqlalchemy_engine()\n```\n\n## Common Setup Pattern\n\nFor most DAGs, a practical split is:\n\n- store the full JDBC URL and credentials in an Airflow connection\n- pass `driver_class` and `driver_path` directly to `JdbcHook` or `hook_params`\n- use `SQLExecuteQueryOperator` for SQL-only tasks\n- use `JdbcHook` inside `@task` functions when later logic depends on query results\n\n## Pitfalls\n\n- No JVM or missing `JAVA_HOME`. The provider needs a working Java runtime.\n- Missing JDBC driver JAR or wrong `driver_class`.\n- Putting only a hostname in the connection instead of the full JDBC URL.\n- `SQLExecuteQueryOperator` uses `conn_id`; `JdbcHook` uses `jdbc_conn_id`.\n- Setting `driver_class` or `driver_path` in connection `extra` without enabling `AIRFLOW__PROVIDERS_JDBC__ALLOW_DRIVER_CLASS_IN_EXTRA` and `AIRFLOW__PROVIDERS_JDBC__ALLOW_DRIVER_PATH_IN_EXTRA`.\n- Calling `get_sqlalchemy_engine()` without `extra.sqlalchemy_scheme`.\n- Using old `JdbcOperator` examples. The JDBC provider removed `JdbcOperator` in `5.0.0`; use `SQLExecuteQueryOperator` instead.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-jdbc` version `5.4.0`.\n- PyPI lists `5.4.0` as the current stable release on March 13, 2026.\n- `5.4.0` requires Airflow `2.11.0+`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/`\n- JDBC connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/connections/jdbc.html`\n- JDBC configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/configurations-ref.html`\n- `JdbcHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/_api/airflow/providers/jdbc/hooks/jdbc/index.html`\n- `JdbcHook` source docs: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/_modules/airflow/providers/jdbc/hooks/jdbc.html`\n- JDBC operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-jdbc/stable/operators.html`\n- SQL operator docs: `https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/operators.html`\n- Airflow connection management: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-jdbc/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-jira/python/DOC.md",
    "content": "---\nname: providers-jira\ndescription: \"Apache Airflow provider for Jira connections, hooks, and DAG tasks that create or update issues\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,jira,atlassian,issues,hooks,operators\"\n---\n\n# Apache Airflow Jira Provider Guide\n\nUse `apache-airflow-providers-jira` when an Airflow DAG needs to create Jira issues, read issue details, add comments, or drive Jira workflow steps through an Airflow-managed connection.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Jira SDK.\n- Put Jira credentials on an Airflow connection such as `jira_default` and keep DAG code focused on issue fields and workflow logic.\n- Use `JiraHook` when task code needs direct Python access to the Jira client.\n- Keep usernames, passwords, API tokens, and hostnames out of DAG source and in Airflow connections, variables, or a secrets backend.\n\n## What This Package Adds\n\nThis provider supplies Airflow's Jira integration points. In practice, the most useful entry point for custom DAG logic is:\n\n- `JiraHook`\n\nThe provider also includes Jira operator support for DAGs that prefer a declarative task over a Python task body.\n\n## Install\n\nInstall the provider into the same environment as Airflow and keep both versions pinned. The Apache Airflow project recommends installing providers with the matching constraints file for your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.1.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-jira==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i jira\nairflow info\n```\n\n## Authentication And Connection Setup\n\nStart with a minimal Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nSet the Jira values you want to store in Airflow:\n\n```bash\nexport JIRA_HOST=\"https://your-domain.atlassian.net\"\nexport JIRA_USERNAME=\"<jira-username-or-email>\"\nexport JIRA_API_TOKEN=\"<jira-password-or-api-token>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'jira_default' \\\n  --conn-type 'jira' \\\n  --conn-host \"$JIRA_HOST\" \\\n  --conn-login \"$JIRA_USERNAME\" \\\n  --conn-password \"$JIRA_API_TOKEN\"\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get jira_default\n```\n\nUse the credentials and host format that match your Jira deployment. For example, Jira Cloud commonly uses an account email plus an API token.\n\n## Common Workflow: Create A Jira Issue In A Task\n\nUse `JiraHook` when a task needs normal Python control flow and direct access to Jira client methods.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.jira.hooks.jira import JiraHook\n\n\nwith DAG(\n    dag_id=\"jira_create_issue_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    @task()\n    def create_issue() -> str:\n        hook = JiraHook(jira_conn_id=\"jira_default\")\n        jira = hook.get_conn()\n\n        issue = jira.create_issue(\n            fields={\n                \"project\": {\"key\": \"ENG\"},\n                \"summary\": \"Airflow created this Jira issue\",\n                \"description\": \"Created from an Airflow task using JiraHook.\",\n                \"issuetype\": {\"name\": \"Task\"},\n            }\n        )\n\n        return issue.key\n\n    create_issue()\n```\n\nPractical points:\n\n- `jira_conn_id` selects the Airflow Jira connection.\n- `hook.get_conn()` returns the authenticated Jira client object for the connection.\n- The `fields` payload must match the target Jira project's required fields and issue type configuration.\n- Returning `issue.key` keeps downstream tasks simple.\n\n## Common Workflow: Read An Issue, Add A Comment, And Transition It\n\nOnce you have the issue key, use the same hook to perform follow-up actions.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.jira.hooks.jira import JiraHook\n\n\nwith DAG(\n    dag_id=\"jira_follow_up_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    @task()\n    def create_issue() -> str:\n        hook = JiraHook(jira_conn_id=\"jira_default\")\n        jira = hook.get_conn()\n        issue = jira.create_issue(\n            fields={\n                \"project\": {\"key\": \"ENG\"},\n                \"summary\": \"Investigate nightly sync failure\",\n                \"description\": \"Created automatically from Airflow.\",\n                \"issuetype\": {\"name\": \"Task\"},\n            }\n        )\n        return issue.key\n\n    @task()\n    def update_issue(issue_key: str) -> None:\n        hook = JiraHook(jira_conn_id=\"jira_default\")\n        jira = hook.get_conn()\n\n        issue = jira.issue(issue_key)\n        jira.add_comment(issue.key, \"Investigation started from Airflow\")\n        jira.transition_issue(issue.key, \"Done\")\n\n    update_issue(create_issue())\n```\n\nUse this pattern when you want Airflow to open a ticket at the start of a workflow and then annotate or move it later in the same DAG.\n\n## Using `JiraOperator`\n\nIf a task only needs to call one Jira client method, the provider's Jira operator can be simpler than writing a Python task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.jira.operators.jira import JiraOperator\n\n\nwith DAG(\n    dag_id=\"jira_operator_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"jira\"],\n):\n    create_issue = JiraOperator(\n        task_id=\"create_issue\",\n        jira_conn_id=\"jira_default\",\n        jira_method=\"create_issue\",\n        jira_method_args={\n            \"fields\": {\n                \"project\": {\"key\": \"ENG\"},\n                \"summary\": \"Create an issue with JiraOperator\",\n                \"description\": \"This task calls the Jira client method directly.\",\n                \"issuetype\": {\"name\": \"Task\"},\n            }\n        },\n    )\n```\n\nUse the hook form when task behavior depends on normal Python branching or multiple Jira calls. Use the operator form when a task is just one Jira method invocation.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i jira\nairflow dags list | grep jira\n```\n\nTest a task in isolation while you wire up the connection and issue payload:\n\n```bash\nairflow tasks test jira_create_issue_demo create_issue 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream dependencies to participate.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Hard-coding Jira credentials in DAG code: keep them on the Airflow connection instead.\n- Using the wrong Jira host format: keep `--conn-host` set to your Jira base URL.\n- Omitting required issue fields: many Jira projects require more than `project`, `summary`, and `issuetype`.\n- Using a transition name that does not exist for the issue's current workflow state.\n- Assuming the Airflow service account can create, comment on, or transition issues without the required Jira permissions.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-jira` version `3.1.0`.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so dependency resolution does not silently change your Airflow core version.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-microsoft-azure/python/DOC.md",
    "content": "---\nname: providers-microsoft-azure\ndescription: \"Apache Airflow provider for Microsoft Azure integrations such as Blob Storage, Data Factory, and Key Vault\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,azure,blob-storage,data-factory,key-vault,secrets\"\n---\n\n# Apache Airflow Providers Microsoft Azure Guide\n\nUse `apache-airflow-providers-microsoft-azure` to connect Airflow DAGs to Azure services through provider hooks, operators, and a Key Vault-backed secrets backend.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone runtime.\n- Create Airflow connection IDs and Azure credentials before writing DAG code.\n- Keep secrets out of DAG files; use Airflow connections and, when needed, the Azure Key Vault secrets backend.\n\n## Install\n\nStart from an Airflow installation that uses the official constraints file for your Airflow and Python versions, then add the Azure provider in the same command.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"13.0.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-microsoft-azure==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep the Airflow package pinned when adding the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-microsoft-azure==13.0.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep microsoft.azure\nairflow info\n```\n\n## What This Provider Commonly Adds\n\nThe maintainer docs for this provider include Azure integrations such as:\n\n- `WasbHook` for Azure Blob Storage\n- `AzureDataFactoryRunPipelineOperator` for Azure Data Factory pipeline runs\n- `AzureKeyVaultBackend` for resolving Airflow connections and variables from Azure Key Vault\n\n## Authentication And Configuration\n\n### Service principal environment variables\n\nWhen your deployment uses Azure AD application credentials, these environment variables are the usual starting point:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nSet them in every Airflow process that needs Azure access: scheduler, API/web process, workers, and any standalone task runtime.\n\n### Add a Blob Storage connection\n\nFor Blob Storage, create a `wasb` connection in Airflow. A connection string is the simplest configuration when you are not using managed identity.\n\n```bash\nairflow connections add 'wasb_default' \\\n  --conn-type 'wasb' \\\n  --conn-extra '{\"connection_string\":\"DefaultEndpointsProtocol=https;AccountName=<storage-account>;AccountKey=<access-key>;EndpointSuffix=core.windows.net\"}'\n```\n\nUse a different connection ID if you need separate accounts for different DAGs or environments.\n\n## Common Workflow: Read And Write Azure Blob Storage\n\n`WasbHook` can hand back the Azure Blob Storage client so a task can use the normal SDK calls.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.azure.hooks.wasb import WasbHook\n\n\nwith DAG(\n    dag_id=\"azure_blob_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"azure\", \"blob\"],\n):\n    @task()\n    def upload_and_read() -> None:\n        hook = WasbHook(wasb_conn_id=\"wasb_default\")\n        service_client = hook.get_conn()\n\n        blob_client = service_client.get_blob_client(\n            container=\"raw\",\n            blob=\"hello.txt\",\n        )\n        blob_client.upload_blob(b\"hello from airflow\", overwrite=True)\n\n        body = blob_client.download_blob().readall().decode(\"utf-8\")\n        print(body)\n\n    upload_and_read()\n```\n\nThis pattern keeps Azure authentication in the Airflow connection while letting the task use the standard Blob Storage client API.\n\n## Common Workflow: Trigger An Azure Data Factory Pipeline\n\nFor Azure Data Factory, the provider exposes an operator that triggers a named pipeline run from a DAG.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.microsoft.azure.operators.data_factory import (\n    AzureDataFactoryRunPipelineOperator,\n)\n\n\nwith DAG(\n    dag_id=\"azure_data_factory_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"azure\", \"adf\"],\n):\n    run_pipeline = AzureDataFactoryRunPipelineOperator(\n        task_id=\"run_pipeline\",\n        azure_data_factory_conn_id=\"azure_data_factory_default\",\n        resource_group_name=\"rg-data\",\n        factory_name=\"adf-prod\",\n        pipeline_name=\"daily_ingest\",\n        parameters={\"run_date\": \"{{ ds }}\"},\n        wait_for_termination=True,\n    )\n```\n\nBefore using this operator, create an `azure_data_factory` connection in Airflow with the Azure subscription and credential details that can run the target pipeline.\n\n## Common Workflow: Resolve Secrets From Azure Key Vault\n\nThe provider also ships a secrets backend that lets Airflow read connections and variables from Azure Key Vault instead of storing them only in the Airflow metadata database.\n\nSet the backend in the Airflow environment:\n\n```bash\nexport AIRFLOW__SECRETS__BACKEND=\"airflow.providers.microsoft.azure.secrets.key_vault.AzureKeyVaultBackend\"\nexport AIRFLOW__SECRETS__BACKEND_KWARGS='{\"connections_prefix\":\"airflow-connections\",\"variables_prefix\":\"airflow-variables\",\"vault_url\":\"https://<vault-name>.vault.azure.net/\"}'\n\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nThen resolve secrets in DAG code the normal Airflow way:\n\n```python\nfrom airflow.hooks.base import BaseHook\nfrom airflow.models import Variable\n\n\nblob_conn = BaseHook.get_connection(\"wasb_default\")\napi_token = Variable.get(\"third_party_api_token\")\n\nprint(blob_conn.conn_id)\nprint(api_token)\n```\n\nAfter changing secrets backend settings, restart every Airflow component that should use the new backend.\n\n## Operational Checks\n\nConfirm the provider is installed:\n\n```bash\nairflow providers list | grep microsoft.azure\n```\n\nConfirm the Blob Storage connection exists:\n\n```bash\nairflow connections get wasb_default\n```\n\nCheck that Airflow can parse the DAG:\n\n```bash\nairflow dags list\nairflow tasks test azure_blob_demo upload_and_read 2026-03-12\n```\n\nUse `airflow tasks test` for isolated task debugging. Use a normal DAG trigger when you need the scheduler, workers, and secret backend to participate end to end.\n\n## Common Pitfalls\n\n- Installing the provider without pinning `apache-airflow`: providers extend Airflow and should be versioned deliberately.\n- Writing DAG code before creating Airflow connection IDs such as `wasb_default` or `azure_data_factory_default`.\n- Setting Azure environment variables only for one process; scheduler, workers, and API/web processes must all be able to authenticate.\n- Hard-coding storage keys or client secrets in DAG files instead of using Airflow connections or the Key Vault backend.\n- Assuming the Data Factory connection alone identifies the target run; the DAG still needs `resource_group_name`, `factory_name`, and `pipeline_name`.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-microsoft-azure` version `13.0.0`.\n- The examples focus on the provider classes surfaced in maintainer docs for Blob Storage, Data Factory, and Key Vault-backed secrets.\n- Re-check the provider's installation and connection documentation before upgrading Airflow or changing authentication modes.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-microsoft-mssql/python/DOC.md",
    "content": "---\nname: providers-microsoft-mssql\ndescription: \"Apache Airflow Microsoft SQL Server provider for Airflow connections, SQL tasks, and MsSqlHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,mssql,sql-server,python,dag,sql\"\n---\n\n# apache-airflow-providers-microsoft-mssql\n\nUse `apache-airflow-providers-microsoft-mssql` to connect Airflow to Microsoft SQL Server through an Airflow connection, run T-SQL in DAG tasks, and query SQL Server from Python tasks with `MsSqlHook`.\n\nThis guide targets provider version `4.5.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-microsoft-mssql` is an Apache Airflow provider package. Install it when your DAGs need SQL Server connections and hook-based access from Airflow tasks.\n\nThis package extends Airflow. It is not a standalone SQL Server client for regular application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-microsoft-mssql==4.5.0\"\n```\n\nIn practice, that means the scheduler, workers, and webserver all need the provider available anywhere DAG code imports it.\n\n## Configure The Airflow Connection\n\nThe provider reads connection settings from an Airflow connection. The default connection id is `mssql_default`.\n\nIn the Airflow UI, configure:\n\n- **Connection Id:** `mssql_default`\n- **Connection Type:** `mssql`\n- **Host:** your SQL Server host name\n- **Schema:** the default database name\n- **Login / Password:** SQL Server credentials\n- **Port:** usually `1433`\n\nYou can also define the connection with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_MSSQL_DEFAULT='mssql://airflow:secret@sqlserver.example.com:1433/warehouse'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `mssql_default`\n- SQL operators use `conn_id=\"mssql_default\"`\n- `MsSqlHook` uses `mssql_conn_id=\"mssql_default\"`\n\nIf the password contains reserved URL characters such as `@`, `:`, or `/`, URL-encode it before putting it in the URI.\n\nKeep credentials in Airflow connections or a secrets backend instead of hard-coding them in DAG files.\n\n## Minimal Connection Check\n\nUse `MsSqlHook` for a quick connection check from a task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.mssql.hooks.mssql import MsSqlHook\n\n\n@task\ndef ping_mssql() -> int:\n    hook = MsSqlHook(mssql_conn_id=\"mssql_default\")\n    row = hook.get_first(\"SELECT 1\")\n    return int(row[0])\n```\n\n`MsSqlHook` uses `mssql_conn_id`, not `conn_id`.\n\n## Run SQL In A DAG\n\nFor SQL-only tasks, use Airflow's generic SQL operator with an MSSQL connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"mssql_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"mssql_default\",\n        sql=\"\"\"\n        IF OBJECT_ID('dbo.events', 'U') IS NULL\n        BEGIN\n            CREATE TABLE dbo.events (\n                id INT IDENTITY(1,1) PRIMARY KEY,\n                event_name NVARCHAR(255) NOT NULL,\n                created_at DATETIME2 NOT NULL DEFAULT SYSDATETIME()\n            )\n        END\n        \"\"\",\n    )\n\n    insert_row = SQLExecuteQueryOperator(\n        task_id=\"insert_row\",\n        conn_id=\"mssql_default\",\n        sql=\"\"\"\n        INSERT INTO dbo.events (event_name)\n        VALUES ('signup')\n        \"\"\",\n    )\n\n    create_table >> insert_row\n```\n\nUse this pattern when the task is just SQL execution and you do not need Python logic around the query result.\n\n## Query SQL Server From Python Tasks\n\nUse `MsSqlHook` when you need to branch on query results, fetch rows into Python, or combine database work with other task logic.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.mssql.hooks.mssql import MsSqlHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"mssql_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> None:\n        hook = MsSqlHook(mssql_conn_id=\"mssql_default\")\n\n        row = hook.get_first(\"SELECT COUNT(*) FROM dbo.events\")\n        event_count = row[0] if row else 0\n\n        records = hook.get_records(\n            \"SELECT TOP 10 id, event_name FROM dbo.events ORDER BY id DESC\"\n        )\n\n        print(f\"total events: {event_count}\")\n        for event_id, event_name in records:\n            print(f\"{event_id}: {event_name}\")\n\n    read_summary()\n```\n\nUseful hook methods for everyday DAG work:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying database connection\n\n## Common Setup Pattern\n\nFor many DAGs, a clean split is:\n\n- use `SQLExecuteQueryOperator` for schema setup, inserts, updates, and other SQL-only tasks\n- use `MsSqlHook` inside `@task` functions when later task logic needs query results in Python\n- keep the connection id stable across DAGs, such as `mssql_default`, `warehouse`, or `analytics_db`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the provider package.\n- `MsSqlHook` expects `mssql_conn_id`; Airflow's generic SQL operators use `conn_id`.\n- URL-encode special characters in connection URIs if you define `AIRFLOW_CONN_*` variables manually.\n- Use SQL Server syntax in your tasks. For example, `SELECT TOP 10 ...` and `IDENTITY(1,1)` are SQL Server patterns; copying `LIMIT` or `AUTO_INCREMENT` from MySQL or PostgreSQL examples will fail.\n- Keep secrets in Airflow connections or a secrets backend instead of embedding usernames and passwords in DAG code.\n\n## Version Notes\n\nProvider packages track Airflow compatibility separately from SQL Server itself. If you upgrade Airflow core, check the provider's version-specific documentation before upgrading this package in production.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-microsoft-mssql/4.5.0/`\n- MSSQL connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-microsoft-mssql/4.5.0/connections/mssql.html`\n- `MsSqlHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-microsoft-mssql/4.5.0/_api/airflow/providers/microsoft/mssql/hooks/mssql/index.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-microsoft-psrp/python/DOC.md",
    "content": "---\nname: providers-microsoft-psrp\ndescription: \"Apache Airflow provider for running remote Windows commands and PowerShell over PSRP connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,psrp,powershell,windows,remote-execution\"\n---\n\n# Apache Airflow Microsoft PSRP Provider Guide\n\nUse `apache-airflow-providers-microsoft-psrp` when an Airflow DAG needs to run `cmd.exe` commands, PowerShell cmdlets, or PowerShell scripts on a remote Windows host over PSRP.\n\nThis guide targets provider version `3.2.3`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone remote-execution client.\n- Put the remote host, username, password, and WSMan options on an Airflow connection with type `psrp`.\n- Use `command=` only for `cmd.exe /c` commands. Use `cmdlet=` or `powershell=` for actual PowerShell work.\n- Pass exactly one of `command`, `cmdlet`, or `powershell` to `PsrpOperator`.\n\n## What This Package Adds\n\nThe main entry points documented by Apache Airflow are:\n\n- `airflow.providers.microsoft.psrp.operators.psrp.PsrpOperator`\n- `airflow.providers.microsoft.psrp.hooks.psrp.PsrpHook`\n\nThe provider hook also defines:\n\n- connection type: `psrp`\n- default connection id: `psrp_default`\n\n## Install\n\nPyPI lists these compatibility markers for `3.2.3`:\n\n- `apache-airflow >= 2.11.0`\n- Python `3.10`, `3.11`, `3.12`, or `3.13`\n\nFor a fresh Airflow environment, install Airflow first with the official constraints file, then add the provider while keeping the Airflow pin in place:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=3.1.8\nPROVIDER_VERSION=3.2.3\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-microsoft-psrp==${PROVIDER_VERSION}\"\n```\n\nIf Airflow is already installed, keep the Airflow version pinned when adding the provider:\n\n```bash\npython -m pip install \"apache-airflow==<your-airflow-version>\" \"apache-airflow-providers-microsoft-psrp==3.2.3\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i microsoft.psrp\npython -m pip check\n```\n\n## Configure A `psrp` Airflow Connection\n\nThe provider reads the remote endpoint from an Airflow connection. The hook source documents these fields:\n\n- connection fields: `host`, `login`, `password`\n- recognized extras: `auth`, `cert_validation`, `connection_timeout`, `locale`, `read_timeout`, `reconnection_retries`, `reconnection_backoff`, `ssl`, `configuration_name`\n\nAn environment-variable connection is the quickest way to wire one in:\n\n```bash\nexport AIRFLOW_CONN_PSRP_DEFAULT='{\"conn_type\":\"psrp\",\"host\":\"windows.example.com\",\"login\":\"Administrator\",\"password\":\"REPLACE_ME\",\"extra\":{\"ssl\":true,\"connection_timeout\":30,\"read_timeout\":30}}'\n```\n\nEquivalent CLI setup:\n\n```bash\nairflow connections add 'psrp_default' \\\n  --conn-json '{\n    \"conn_type\": \"psrp\",\n    \"host\": \"windows.example.com\",\n    \"login\": \"Administrator\",\n    \"password\": \"REPLACE_ME\",\n    \"extra\": {\n      \"ssl\": true,\n      \"connection_timeout\": 30,\n      \"read_timeout\": 30\n    }\n  }'\n```\n\nKeep credentials and WSMan options in the connection or a secrets backend, not in DAG code.\n\n## Run A Remote `cmd.exe` Command\n\nWhen you pass `command=`, the operator runs it through `cmd.exe /c` on the remote host. This is the path to use for ordinary Windows shell commands.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.microsoft.psrp.operators.psrp import PsrpOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"psrp_command_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    list_temp = PsrpOperator(\n        task_id=\"list_temp\",\n        psrp_conn_id=\"psrp_default\",\n        command=r'dir C:\\Windows\\Temp',\n        do_xcom_push=False,\n    )\n```\n\nUse `do_xcom_push=False` for `command=` unless you specifically control the output format yourself. The provider only adds JSON conversion automatically for `cmdlet=` and `powershell=`.\n\n## Run A PowerShell Script And Use XCom Output\n\nUse `powershell=` for normal PowerShell code. When `do_xcom_push=True` and you use `powershell=` or `cmdlet=`, the operator appends `ConvertTo-Json` and returns JSON-decoded output.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.psrp.operators.psrp import PsrpOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"psrp_powershell_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    get_services = PsrpOperator(\n        task_id=\"get_services\",\n        psrp_conn_id=\"psrp_default\",\n        powershell=\"\"\"\n        Get-Service |\n          Where-Object {$_.Status -eq 'Running'} |\n          Select-Object -First 5 Name, Status\n        \"\"\",\n    )\n\n    @task\n    def show_payload(payload) -> None:\n        print(payload)\n\n    show_payload(get_services.output)\n```\n\nThis is the simplest pattern when a downstream task needs structured output from the remote session.\n\n## Pass Parameters To A PowerShell Cmdlet\n\nUse `cmdlet=` with `parameters=` when you want the provider to construct and invoke a specific PowerShell cmdlet.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.microsoft.psrp.operators.psrp import PsrpOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"psrp_cmdlet_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    top_processes = PsrpOperator(\n        task_id=\"top_processes\",\n        psrp_conn_id=\"psrp_default\",\n        cmdlet=\"Get-Process\",\n        parameters={\"Name\": \"svchost\"},\n    )\n```\n\nThe provider enforces that `arguments=` and `parameters=` are only used with `cmdlet=` or `powershell=`, not with `command=`.\n\n## Use The `securestring` Template Filter\n\nThe provider exposes a `securestring` Jinja filter for arguments or parameters that need to become PowerShell `SecureString` values. The operator docs require `render_template_as_native_obj=True` on the DAG when using this filter.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.microsoft.psrp.operators.psrp import PsrpOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"psrp_securestring_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    render_template_as_native_obj=True,\n) as dag:\n    inspect_password_type = PsrpOperator(\n        task_id=\"inspect_password_type\",\n        psrp_conn_id=\"psrp_default\",\n        powershell=\"param($Password) $Password.GetType().FullName\",\n        arguments=[\"{{ var.value.windows_admin_password | securestring }}\"],\n    )\n```\n\nWithout native-object rendering, the filter output is serialized as a string and PowerShell does not receive a `SecureString` object.\n\n## Reuse A Session With `PsrpHook`\n\nUse `PsrpHook` inside TaskFlow code when you need direct access to the PSRP session. The hook can be used as a context manager so the same runspace is reused across multiple calls.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.psrp.hooks.psrp import PsrpHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"psrp_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def inspect_remote_host() -> None:\n        with PsrpHook(psrp_conn_id=\"psrp_default\") as hook:\n            ps = hook.invoke_cmdlet(\"Get-Date\")\n            print(ps.output)\n\n            ps = hook.invoke_powershell(\"$PSVersionTable.PSVersion.ToString()\")\n            print(ps.output)\n\n    inspect_remote_host()\n```\n\nHook methods documented in the API page:\n\n- `invoke_cmdlet(...)`\n- `invoke_powershell(...)`\n- `test_connection()`\n\n## Operational Checks\n\nConfirm the provider is installed:\n\n```bash\nairflow providers list | grep -i microsoft.psrp\n```\n\nConfirm the connection resolves:\n\n```bash\nairflow connections get psrp_default\n```\n\nParse-test the DAG:\n\n```bash\nairflow dags list\nairflow tasks test psrp_command_example list_temp 2026-03-13\n```\n\nIf you want a task-level connectivity check in DAG code, use the hook:\n\n```python\nfrom airflow.providers.microsoft.psrp.hooks.psrp import PsrpHook\n\nhook = PsrpHook(psrp_conn_id=\"psrp_default\")\nok, message = hook.test_connection()\nprint(ok, message)\n```\n\n## Common Pitfalls\n\n- Treating `command=` as PowerShell. The provider explicitly wraps it in `cmd.exe /c`.\n- Passing more than one of `command`, `cmdlet`, or `powershell`; the operator rejects that.\n- Passing `arguments=` or `parameters=` together with `command=`; the operator rejects that too.\n- Expecting structured XCom output from `command=`. Automatic JSON conversion is only applied for `cmdlet=` and `powershell=`.\n- Forgetting `render_template_as_native_obj=True` when using the `securestring` filter.\n- Adding unknown keys under connection `extra`; the hook raises if unsupported extras are present.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-microsoft-psrp==3.2.3`.\n- The provider changelog documents `apache-airflow >= 2.11.0` as the minimum Airflow version starting in the `3.2.0` line.\n- The `3.1.4` changelog notes support for `arguments` and `parameters` when `powershell` is used, so the examples here rely on behavior that is present in `3.2.3`.\n- The `3.0.0` changelog removed deprecated `kwargs` passthrough for `invoke_cmdlet`; use `parameters=` instead.\n\n## Official Sources\n\n- Provider docs root: https://airflow.apache.org/docs/apache-airflow-providers-microsoft-psrp/stable/\n- Provider overview and changelog: https://airflow.apache.org/docs/apache-airflow-providers-microsoft-psrp/stable/index.html\n- Operator guide: https://airflow.apache.org/docs/apache-airflow-providers-microsoft-psrp/stable/operators/index.html\n- `PsrpHook` API reference: https://airflow.apache.org/docs/apache-airflow-providers-microsoft-psrp/stable/_api/airflow/providers/microsoft/psrp/hooks/psrp/index.html\n- `PsrpOperator` API reference: https://airflow.apache.org/docs/apache-airflow-providers-microsoft-psrp/stable/_api/airflow/providers/microsoft/psrp/operators/psrp/index.html\n- PyPI package page: https://pypi.org/project/apache-airflow-providers-microsoft-psrp/3.2.3/\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-microsoft-winrm/python/DOC.md",
    "content": "---\nname: providers-microsoft-winrm\ndescription: \"Apache Airflow WinRM provider for running commands on Windows hosts through WinRMHook and WinRMOperator\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,winrm,windows,powershell,remote-execution,python\"\n---\n\n# Apache Airflow Providers Microsoft WinRM Guide\n\nUse `apache-airflow-providers-microsoft-winrm` when your Airflow DAGs need to run commands on Windows hosts over WinRM.\n\n## What This Package Adds\n\nThis provider adds:\n\n- `WinRMHook` for direct WinRM calls from Python tasks\n- `WinRMOperator` for command execution as a normal Airflow task\n\nThe provider is not a standalone Windows client library. It extends Airflow and uses `pywinrm` underneath.\n\n## Install\n\nThis provider requires:\n\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-compat>=1.12.0`\n- `pywinrm>=0.5.0`\n\nInstall it into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-microsoft-winrm==3.14.0\"\n```\n\nIf you are pinning Airflow in the same command, keep both versions explicit:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-microsoft-winrm==3.14.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep microsoft.winrm\nairflow info\n```\n\n## Configure The Airflow Connection\n\nThe hook uses:\n\n- connection type: `winrm`\n- default connection id: `winrm_default`\n- constructor argument name: `ssh_conn_id`\n\nThat parameter name is legacy but still current in both `WinRMHook` and `WinRMOperator`.\n\n### Environment variable connection\n\nAirflow connections can be stored in `AIRFLOW_CONN_{CONN_ID}` as JSON. This is the most explicit way to configure WinRM extras.\n\n```bash\nexport AIRFLOW_CONN_WINRM_DEFAULT='{\n  \"conn_type\": \"winrm\",\n  \"host\": \"windows.example.internal\",\n  \"login\": \"Administrator\",\n  \"password\": \"REPLACE_ME\",\n  \"extra\": {\n    \"transport\": \"ntlm\",\n    \"remote_port\": 5985,\n    \"read_timeout_sec\": 60,\n    \"operation_timeout_sec\": 30\n  }\n}'\n```\n\nImportant fields read by the hook:\n\n- top-level `host`, `login`, `password`\n- `extra.endpoint`\n- `extra.remote_port`\n- `extra.transport`\n- `extra.service`\n- `extra.keytab`\n- `extra.ca_trust_path`\n- `extra.cert_pem`\n- `extra.cert_key_pem`\n- `extra.server_cert_validation`\n- `extra.kerberos_delegation`\n- `extra.read_timeout_sec`\n- `extra.operation_timeout_sec`\n- `extra.kerberos_hostname_override`\n- `extra.message_encryption`\n- `extra.credssp_disable_tlsv1_2`\n- `extra.send_cbt`\n\n### CLI connection example\n\n```bash\nairflow connections add 'winrm_default' \\\n  --conn-json '{\n    \"conn_type\": \"winrm\",\n    \"host\": \"windows.example.internal\",\n    \"login\": \"Administrator\",\n    \"password\": \"REPLACE_ME\",\n    \"extra\": {\n      \"transport\": \"ntlm\",\n      \"remote_port\": 5985,\n      \"read_timeout_sec\": 60,\n      \"operation_timeout_sec\": 30\n    }\n  }'\n```\n\n### HTTPS / TLS example\n\nIf you want WinRM over HTTPS, set an explicit endpoint. When `endpoint` is omitted, the hook constructs `http://{remote_host}:{remote_port}/wsman`.\n\n```bash\nexport AIRFLOW_CONN_WINRM_DEFAULT='{\n  \"conn_type\": \"winrm\",\n  \"host\": \"windows.example.internal\",\n  \"login\": \"Administrator\",\n  \"password\": \"REPLACE_ME\",\n  \"extra\": {\n    \"endpoint\": \"https://windows.example.internal:5986/wsman\",\n    \"transport\": \"ssl\",\n    \"server_cert_validation\": \"validate\",\n    \"read_timeout_sec\": 60,\n    \"operation_timeout_sec\": 30\n  }\n}'\n```\n\nFor lab environments with self-signed certificates, `server_cert_validation` can be set to `ignore`, but do that deliberately.\n\n## Common Workflow: Run PowerShell From A Python Task\n\nUse `WinRMHook` when you want Python logic around the command result.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.microsoft.winrm.hooks.winrm import WinRMHook\n\n\nwith DAG(\n    dag_id=\"winrm_hook_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"winrm\"],\n):\n    @task()\n    def list_services() -> str:\n        hook = WinRMHook(ssh_conn_id=\"winrm_default\")\n        return_code, stdout_chunks, stderr_chunks = hook.run(\n            command=\"Get-Service | Select-Object -First 5 Name, Status\",\n            ps_path=\"powershell\",\n            working_directory=r\"C:\\\\\",\n        )\n\n        if return_code != 0:\n            raise RuntimeError(b\"\".join(stderr_chunks).decode(\"utf-8\"))\n\n        output = b\"\".join(stdout_chunks).decode(\"utf-8\")\n        print(output)\n        return output\n\n    list_services()\n```\n\nNotes:\n\n- Set `ps_path=\"powershell\"` for Windows PowerShell 5.1 and earlier.\n- Set `ps_path=\"pwsh\"` for PowerShell 6+.\n- `hook.run(...)` returns `(return_code, stdout_chunks, stderr_chunks)`.\n\n## Common Workflow: Use WinRMOperator In A DAG\n\nUse `WinRMOperator` when the task is just remote command execution.\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import timedelta\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.microsoft.winrm.operators.winrm import WinRMOperator\n\n\nwith DAG(\n    dag_id=\"winrm_operator_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"winrm\"],\n):\n    install_agent = WinRMOperator(\n        task_id=\"install_agent\",\n        ssh_conn_id=\"winrm_default\",\n        command=\"\"\"\n        Start-Process msiexec.exe `\n          -ArgumentList '/i C:\\\\temp\\\\agent.msi /qn' `\n          -Wait\n        exit $LASTEXITCODE\n        \"\"\".strip(),\n        ps_path=\"powershell\",\n        working_directory=r\"C:\\\\temp\",\n        expected_return_code=[0, 3010],\n        execution_timeout=timedelta(minutes=20),\n    )\n```\n\n`expected_return_code` accepts an `int`, `list[int]`, or `range`. That is useful when Windows installers return `3010` for \"success, reboot required\".\n\n## Deferrable Execution\n\n`WinRMOperator` in `3.14.0` supports `deferrable=True`.\n\nUse it for long-running remote commands when you want the task to free its worker slot while Airflow waits for output:\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import timedelta\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.microsoft.winrm.operators.winrm import WinRMOperator\n\n\nwith DAG(\n    dag_id=\"winrm_deferrable_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n):\n    run_patch = WinRMOperator(\n        task_id=\"run_patch\",\n        ssh_conn_id=\"winrm_default\",\n        command=\"Start-Sleep -Seconds 300; Write-Output 'done'\",\n        ps_path=\"powershell\",\n        deferrable=True,\n        poll_interval=5,\n        execution_timeout=timedelta(minutes=10),\n    )\n```\n\nTo use deferrable mode, your Airflow deployment must run at least one `triggerer` process.\n\n## Operational Checks\n\nCheck that Airflow sees the provider:\n\n```bash\nairflow providers list | grep microsoft.winrm\n```\n\nCheck that the connection exists:\n\n```bash\nairflow connections get winrm_default\n```\n\nAirflow's hook-level connection test runs a remote `cd` command:\n\n```bash\nairflow connections test winrm_default\n```\n\nCheck that Airflow can parse and run the DAG:\n\n```bash\nairflow dags list\nairflow tasks test winrm_hook_demo list_services 2026-03-13\n```\n\n## Common Pitfalls\n\n- Use `ssh_conn_id=\"winrm_default\"` in code even though the Airflow connection type is `winrm`.\n- If you omit `extra.endpoint`, the hook builds `http://{remote_host}:{remote_port}/wsman`. For HTTPS on port `5986`, set `extra.endpoint` explicitly.\n- Keep `read_timeout_sec` slightly higher than `operation_timeout_sec`; the hook documentation calls that out directly.\n- In deferrable mode, the operator requires a real `ssh_conn_id`. A prebuilt hook without `ssh_conn_id` is not enough.\n- Prefer `execution_timeout` on the operator. The older `timeout` argument is deprecated.\n- `working_directory` is a first-class operator and hook argument in current releases; use it instead of embedding `cd` into every command.\n- Successful operator output is only pushed to XCom when XCom push is enabled for the task.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-microsoft-winrm` version `3.14.0`.\n- `3.14.0` adds deferrable support to `WinRMOperator`.\n- `3.12.0` added the `working_directory` parameter.\n- `3.11.0` added `WinRMHook.test_connection()`.\n\n## Official Sources\n\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/index.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/operators.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/_api/airflow/providers/microsoft/winrm/hooks/winrm/index.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/_api/airflow/providers/microsoft/winrm/operators/winrm/index.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/_modules/airflow/providers/microsoft/winrm/hooks/winrm.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/_modules/airflow/providers/microsoft/winrm/operators/winrm.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/changelog.html\n- https://airflow.apache.org/docs/apache-airflow-providers-microsoft-winrm/stable/commits.html\n- https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html\n- https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/deferring.html\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-mongo/python/DOC.md",
    "content": "---\nname: providers-mongo\ndescription: \"Apache Airflow provider for connecting DAGs to MongoDB with Airflow connections, MongoHook, and MongoSensor\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,mongodb,mongo,pymongo,dags\"\n---\n\n# Apache Airflow Providers Mongo Guide\n\nUse `apache-airflow-providers-mongo` to connect Airflow DAGs to MongoDB through an Airflow connection, use `MongoHook` inside Python tasks, and wait for records with `MongoSensor`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone MongoDB client.\n- Put credentials and connection options in an Airflow connection such as `mongo_default` instead of hard-coding them in DAG files.\n- Treat the object returned by `MongoHook.get_conn()` as a normal PyMongo client and use standard database and collection calls from there.\n\n## Install\n\nInstall the provider in the same environment as Airflow, using the official Airflow constraints file for your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.3.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-mongo==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-mongo==5.3.2\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep mongo\nairflow info\n```\n\n## Authentication And Connection Setup\n\nThis provider reads MongoDB credentials from an Airflow connection. A safe pattern is to keep the connection values in environment variables, then create the Airflow connection from those values.\n\n```bash\nexport MONGO_HOST='mongo.example.com'\nexport MONGO_PORT='27017'\nexport MONGO_DB='analytics'\nexport MONGO_USER='airflow'\nexport MONGO_PASSWORD='secret'\n```\n\nCreate the Airflow connection:\n\n```bash\nairflow connections add 'mongo_default' \\\n  --conn-type 'mongo' \\\n  --conn-host \"$MONGO_HOST\" \\\n  --conn-port \"$MONGO_PORT\" \\\n  --conn-schema \"$MONGO_DB\" \\\n  --conn-login \"$MONGO_USER\" \\\n  --conn-password \"$MONGO_PASSWORD\"\n```\n\nConfirm the connection exists before you wire it into a DAG:\n\n```bash\nairflow connections get mongo_default\n```\n\nIf your deployment needs TLS, replica set settings, SRV, or another connection option beyond the basic host, port, database, and credentials shown here, add that configuration in the Airflow connection itself using the provider's Mongo connection documentation.\n\n## Common Workflow: Read And Write Documents In A Python Task\n\nUse `MongoHook` when the task needs normal MongoDB operations from Python code.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.mongo.hooks.mongo import MongoHook\n\n\nwith DAG(\n    dag_id=\"mongo_hook_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"mongo\"],\n):\n    @task\n    def write_and_read() -> None:\n        hook = MongoHook(mongo_conn_id=\"mongo_default\")\n        client = hook.get_conn()\n\n        try:\n            collection = client[\"analytics\"][\"events\"]\n\n            collection.insert_one(\n                {\n                    \"event_type\": \"signup\",\n                    \"source\": \"airflow\",\n                    \"status\": \"queued\",\n                }\n            )\n\n            document = collection.find_one({\"event_type\": \"signup\"})\n            print(document)\n\n            collection.update_one(\n                {\"event_type\": \"signup\"},\n                {\"$set\": {\"status\": \"processed\"}},\n            )\n        finally:\n            client.close()\n\n    write_and_read()\n```\n\nThis pattern is usually the simplest way to work with MongoDB in Airflow:\n\n- get the hook with `MongoHook(mongo_conn_id=\"...\")`\n- call `get_conn()` once inside the task\n- use normal PyMongo APIs on the returned client\n- close the client before the task exits when you manage it directly\n\n## Common Workflow: Wait For A Matching Document\n\nUse `MongoSensor` when a DAG should pause until a collection contains a document that matches a query.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.mongo.sensors.mongo import MongoSensor\n\n\nwith DAG(\n    dag_id=\"mongo_sensor_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"mongo\"],\n):\n    wait_for_ready_document = MongoSensor(\n        task_id=\"wait_for_ready_document\",\n        mongo_conn_id=\"mongo_default\",\n        collection=\"events\",\n        query={\"status\": \"ready\"},\n        poke_interval=30,\n        timeout=60 * 20,\n    )\n```\n\nKeep the query small and index-backed when possible. Sensors poll repeatedly, so broad collection scans can turn a simple readiness check into steady load on the database.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- put the database name, host, and credentials in the Airflow connection\n- use `MongoHook` inside `@task` functions when you need custom reads, writes, or updates\n- use `MongoSensor` when downstream work should not start until a document exists\n- keep the connection id stable across DAGs, such as `mongo_default` or `warehouse_mongo`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Scheduler, worker, and local test environments all need the package if they import `airflow.providers.mongo`.\n- Keep credentials in Airflow connections or a secrets backend. Do not embed MongoDB usernames and passwords directly in DAG code.\n- Keep `apache-airflow` pinned when adding or upgrading the provider so `pip` does not silently replace your Airflow core version.\n- Use worker-reachable hostnames. A MongoDB host that works from your laptop may not resolve from a container or remote worker.\n- Keep connection-specific options in the Airflow connection instead of scattering them through DAG code.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-mongo` version `5.3.2`.\n- Provider packages track Airflow compatibility separately from your MongoDB server version. If you are upgrading Airflow core, re-check provider compatibility and release notes before changing production pins.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-mongo/stable/`\n- Mongo connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-mongo/stable/connections/mongo.html`\n- `MongoHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-mongo/stable/_api/airflow/providers/mongo/hooks/mongo/index.html`\n- `MongoSensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-mongo/stable/_api/airflow/providers/mongo/sensors/mongo/index.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-mongo/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-mysql/python/DOC.md",
    "content": "---\nname: providers-mysql\ndescription: \"Apache Airflow MySQL provider guide for configuring MySQL connections and using MySqlHook in Airflow DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,mysql,python,dags,sql,orchestration\"\n---\n\n# Apache Airflow MySQL Provider Python Guide\n\n## What This Package Adds\n\n`apache-airflow-providers-mysql` is the MySQL provider package for Apache Airflow. Install it in the same Python environment as `apache-airflow` when your DAGs need to connect to MySQL through Airflow connections and hooks.\n\nThis provider is for Airflow tasks and DAG code. It is not a standalone MySQL client library for general application code.\n\n## Install\n\nPin the provider version your Airflow environment expects:\n\n```bash\npython -m pip install \"apache-airflow-providers-mysql==6.5.0\"\n```\n\nInstall the provider into the environment used by your Airflow scheduler, workers, and webserver. If you build a custom Airflow image, add the provider during the image build so every Airflow component sees the same installed providers.\n\n## Configure A MySQL Connection\n\nThe provider reads credentials and connection settings from an Airflow connection. The default connection id is `mysql_default`.\n\nIn the Airflow UI, create a connection with:\n\n- **Connection Id:** `mysql_default`\n- **Connection Type:** `mysql`\n- **Host:** your MySQL hostname\n- **Schema:** the default database name\n- **Login / Password:** database credentials\n- **Port:** usually `3306`\n\nYou can also define the connection with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_MYSQL_DEFAULT='mysql://airflow:airflow@mysql:3306/analytics?charset=utf8mb4'\n```\n\nIf the password contains reserved URL characters such as `@`, `:`, or `/`, URL-encode it before putting it in the URI.\n\nUseful connection extras for MySQL deployments:\n\n```json\n{\n  \"charset\": \"utf8mb4\",\n  \"cursor\": \"dictcursor\",\n  \"local_infile\": false\n}\n```\n\nUse extras for connection-level behavior such as character set, cursor type, SSL settings, Unix socket settings, or `LOAD DATA LOCAL INFILE` support instead of hardcoding those details in each DAG.\n\n## Minimal Connection Check\n\nUse `MySqlHook` for a quick sanity check from a task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.mysql.hooks.mysql import MySqlHook\n\n@task\ndef ping_mysql() -> int:\n    hook = MySqlHook(mysql_conn_id=\"mysql_default\")\n    row = hook.get_first(\"SELECT 1\")\n    return int(row[0])\n```\n\n`MySqlHook` uses `mysql_conn_id`, not `conn_id`.\n\n## Common DAG Workflow\n\nFor most DAGs, use `MySqlHook` to create tables, write rows, and read results:\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import datetime\n\nfrom airflow.decorators import dag, task\nfrom airflow.providers.mysql.hooks.mysql import MySqlHook\n\n\n@dag(\n    dag_id=\"mysql_provider_example\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"mysql\"],\n)\ndef mysql_provider_example():\n    @task\n    def create_table() -> None:\n        hook = MySqlHook(mysql_conn_id=\"mysql_default\")\n        hook.run(\n            \"\"\"\n            CREATE TABLE IF NOT EXISTS events (\n                id INT AUTO_INCREMENT PRIMARY KEY,\n                name VARCHAR(255) NOT NULL,\n                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n            )\n            \"\"\"\n        )\n\n    @task\n    def insert_event() -> None:\n        hook = MySqlHook(mysql_conn_id=\"mysql_default\")\n        hook.run(\n            \"INSERT INTO events (name) VALUES (%s)\",\n            parameters=(\"signup\",),\n        )\n\n    @task\n    def fetch_recent() -> list[tuple[int, str]]:\n        hook = MySqlHook(mysql_conn_id=\"mysql_default\")\n        return hook.get_records(\n            \"SELECT id, name FROM events ORDER BY id DESC LIMIT 10\"\n        )\n\n    create_table() >> insert_event() >> fetch_recent()\n\n\nmysql_provider_example()\n```\n\nThe main hook methods you will use most often are:\n\n- `get_first(sql, parameters=None)` for a single row\n- `get_records(sql, parameters=None)` for multiple rows\n- `run(sql, parameters=None)` for DDL or DML statements\n- `get_conn()` when you need raw DB-API cursor access\n\n## Raw Cursor Access\n\nDrop down to the driver connection when you need explicit cursor handling:\n\n```python\nfrom airflow.providers.mysql.hooks.mysql import MySqlHook\n\nhook = MySqlHook(mysql_conn_id=\"mysql_default\")\nconn = hook.get_conn()\ncursor = conn.cursor()\n\ntry:\n    cursor.execute(\n        \"UPDATE events SET name=%s WHERE id=%s\",\n        (\"activated\", 1),\n    )\n    conn.commit()\nfinally:\n    cursor.close()\n    conn.close()\n```\n\nWhen you use `get_conn()` directly, commit write operations yourself.\n\n## Query Parameters And Result Shape\n\nUse MySQL parameter placeholders, not SQLite-style placeholders:\n\n```python\nhook.run(\n    \"INSERT INTO events (name) VALUES (%s)\",\n    parameters=(\"signup\",),\n)\n```\n\nUse the connection extra `{\"cursor\": \"dictcursor\"}` when you want rows keyed by column name instead of positional tuples.\n\n## Pitfalls\n\n- `MySqlHook` expects `mysql_conn_id`; Airflow's generic SQL operators use `conn_id`\n- Use `%s` placeholders for query parameters; do not use `?`\n- Commit explicitly when you use a raw connection from `get_conn()`\n- Do not push large MySQL result sets through XCom; keep task returns small\n- Only enable `local_infile` when you intentionally need local file loading and the server is configured for it\n\n## Version Notes\n\nThis guide targets `apache-airflow-providers-mysql` version `6.5.0`. Keep the provider installed in the same Airflow environment as your DAG code, and check Airflow's provider compatibility requirements before upgrading Airflow core or the provider independently.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-neo4j/python/DOC.md",
    "content": "---\nname: providers-neo4j\ndescription: \"Apache Airflow Neo4j provider for Airflow connections and Neo4j hook-based DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,neo4j,cypher,graph,dag,python\"\n---\n\n# apache-airflow-providers-neo4j\n\nUse `apache-airflow-providers-neo4j` when your Airflow DAGs need an Airflow-managed Neo4j connection and Python-task access to the Neo4j driver through `Neo4jHook`.\n\nThis guide targets provider version `3.11.3`.\n\n## Install\n\nInstall the provider in the same Python environment or container image as Airflow. In practice, that means the scheduler, webserver, and every worker that imports DAG code all need the package.\n\nAirflow providers are normally installed with the Airflow constraints file that matches your Airflow and Python versions:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.11.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-neo4j==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already pinned in your environment, keep that pin explicit when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-neo4j==3.11.3\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep neo4j\nairflow info\n```\n\n## Configure The Airflow Connection\n\nKeep the Neo4j endpoint and credentials in an Airflow connection instead of hard-coding them in DAG files.\n\nEnvironment variables for a typical setup:\n\n```bash\nexport NEO4J_HOST='neo4j.example.com'\nexport NEO4J_PORT='7687'\nexport NEO4J_DATABASE='neo4j'\nexport NEO4J_USERNAME='neo4j'\nexport NEO4J_PASSWORD='secret'\n```\n\nCreate the Airflow connection:\n\n```bash\nairflow connections add 'neo4j_default' \\\n  --conn-type 'neo4j' \\\n  --conn-host \"$NEO4J_HOST\" \\\n  --conn-port \"$NEO4J_PORT\" \\\n  --conn-schema \"$NEO4J_DATABASE\" \\\n  --conn-login \"$NEO4J_USERNAME\" \\\n  --conn-password \"$NEO4J_PASSWORD\"\n```\n\nOr define the same connection with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_NEO4J_DEFAULT='neo4j://neo4j:secret@neo4j.example.com:7687/neo4j'\n```\n\nWith that connection in place:\n\n- the Airflow connection id is `neo4j_default`\n- DAG code passes `neo4j_conn_id=\"neo4j_default\"`\n- the database name can stay in the connection schema or be chosen explicitly in the session you open inside the task\n\nUse the connection to hold credentials, host, port, and deployment-specific connection settings. If your Neo4j deployment needs TLS, routing, or other driver-specific options, keep them in the Airflow connection rather than scattering them through DAG code.\n\n## Common Workflow: Run Cypher In A Python Task\n\nUse `Neo4jHook` when you need to run Cypher from Python code inside a task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.neo4j.hooks.neo4j import Neo4jHook\n\n\nwith DAG(\n    dag_id=\"neo4j_hook_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"neo4j\"],\n):\n    @task\n    def write_and_read() -> str | None:\n        hook = Neo4jHook(neo4j_conn_id=\"neo4j_default\")\n        driver = hook.get_conn()\n\n        try:\n            with driver.session(database=\"neo4j\") as session:\n                session.run(\n                    \"\"\"\n                    MERGE (p:Person {id: $id})\n                    SET p.name = $name\n                    \"\"\",\n                    id=\"user-123\",\n                    name=\"Ada Lovelace\",\n                )\n\n                record = session.run(\n                    \"\"\"\n                    MATCH (p:Person {id: $id})\n                    RETURN p.name AS name\n                    \"\"\",\n                    id=\"user-123\",\n                ).single()\n\n                return record[\"name\"] if record else None\n        finally:\n            driver.close()\n\n    write_and_read()\n```\n\nThe basic pattern is:\n\n1. create `Neo4jHook(neo4j_conn_id=\"...\")`\n2. call `get_conn()`\n3. open a session on the returned Neo4j driver\n4. execute Cypher with `session.run(...)`\n5. close the driver before the task exits when you manage it directly\n\n## Common Workflow: Return A Small Derived Result\n\nAirflow tasks work best when they return small values through XCom instead of large raw query results. A common pattern is to query Neo4j, derive the value you actually need, and return only that.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.neo4j.hooks.neo4j import Neo4jHook\n\n\n@task\ndef count_people() -> int:\n    hook = Neo4jHook(neo4j_conn_id=\"neo4j_default\")\n    driver = hook.get_conn()\n\n    try:\n        with driver.session(database=\"neo4j\") as session:\n            record = session.run(\n                \"MATCH (p:Person) RETURN count(p) AS total\"\n            ).single()\n            return int(record[\"total\"]) if record else 0\n    finally:\n        driver.close()\n```\n\nUse this pattern when downstream tasks only need a count, a status flag, or a short identifier.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep the host, credentials, and connection options in an Airflow connection\n- create the Neo4j driver inside the task with `Neo4jHook`\n- run Cypher with standard Neo4j driver calls on the returned connection\n- return only small derived values through XCom unless a downstream task really needs the full result set\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or worker is missing `apache-airflow-providers-neo4j`.\n- Keep `apache-airflow` pinned when adding or upgrading the provider so `pip` does not silently replace your Airflow core version.\n- Keep secrets in Airflow connections or a secrets backend, not in DAG source.\n- Use a Neo4j host and port reachable from workers, not just from the machine where you authored the DAG.\n- Open the Neo4j driver inside the task body, not at DAG import time. Airflow repeatedly parses DAG files, and top-level network setup makes scheduling less reliable.\n- Return small task outputs. Large Neo4j result payloads are a bad fit for XCom.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-neo4j` version `3.11.3`.\n- Provider packages follow Airflow's provider release cycle, not your Neo4j server version. Re-check the provider docs before upgrading Airflow core or the provider in production.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-neo4j/stable/`\n- Neo4j connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-neo4j/stable/connections/neo4j.html`\n- `Neo4jHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-neo4j/stable/_api/airflow/providers/neo4j/hooks/neo4j/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-neo4j/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-odbc/python/DOC.md",
    "content": "---\nname: providers-odbc\ndescription: \"Apache Airflow ODBC provider for Airflow connections, SQL tasks, and OdbcHook workflows via pyodbc\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,odbc,pyodbc,sql,dag,python\"\n---\n\n# apache-airflow-providers-odbc\n\nUse `apache-airflow-providers-odbc` when your Airflow DAGs need to connect to an ODBC-accessible database through `pyodbc`, execute SQL with Airflow's generic SQL operator, or open a `pyodbc` connection from `OdbcHook`.\n\nThis guide targets provider version `4.12.0`.\n\n## Install\n\n`apache-airflow-providers-odbc` `4.12.0` requires:\n\n- Apache Airflow `>=2.11.0`\n- Python `3.10` through `3.13`\n- `pyodbc >=5.0.0` on Python `<3.13`, or `pyodbc >=5.2.0` on Python `3.13`\n\nInstall the provider into the same Python environment your Airflow components use:\n\n```bash\npython -m pip install \"apache-airflow-providers-odbc==4.12.0\"\n```\n\nThe provider docs also use this Airflow extra when enabling ODBC support from an Airflow install:\n\n```bash\npython -m pip install \"apache-airflow[odbc]\"\n```\n\nSystem prerequisites matter here:\n\n- `pyodbc` has native system dependencies.\n- You must install an actual ODBC driver on the host or container where Airflow runs.\n- Some databases also require an OS-level DSN definition before Airflow can connect.\n\n## Configure The Airflow Connection\n\nThe provider adds the `odbc` connection type. `OdbcHook` uses `odbc_conn_id`, and its default connection id is `odbc_default`.\n\nConnection fields from the provider docs:\n\n- `Host`: required\n- `Schema`: optional database/schema name\n- `Login`: required\n- `Password`: required\n- `Extra`: arbitrary key/value pairs added to the ODBC connection string\n\nSpecial `extra` keys handled by the provider:\n\n- `connect_kwargs`: passed to `pyodbc.connect(...)`\n- `sqlalchemy_scheme`: overrides the default SQLAlchemy scheme `mssql+pyodbc`\n- `driver`: only used when `allow_driver_in_extra` is enabled\n\nAirflow core supports defining connections with `AIRFLOW_CONN_{CONN_ID}` in either JSON or URI format. JSON is usually easier for ODBC because nested `extra` values stay readable:\n\n```bash\nexport AIRFLOW_CONN_MY_ODBC_CONN='{\n  \"conn_type\": \"odbc\",\n  \"host\": \"db.example.com\",\n  \"port\": 1433,\n  \"schema\": \"warehouse\",\n  \"login\": \"airflow\",\n  \"password\": \"secret\",\n  \"extra\": {\n    \"Driver\": \"ODBC Driver 18 for SQL Server\",\n    \"ApplicationIntent\": \"ReadOnly\",\n    \"TrustedConnection\": \"No\",\n    \"connect_kwargs\": {\n      \"autocommit\": false\n    }\n  }\n}'\n```\n\nIf you want the provider to honor `driver` from connection `extra`, enable it explicitly:\n\n```bash\nexport AIRFLOW__PROVIDERS_ODBC__ALLOW_DRIVER_IN_EXTRA=true\n```\n\nIf you do not want that global setting, pass the driver directly to `OdbcHook` or through `hook_params` on SQL operators.\n\n## Run SQL In A DAG\n\nThe provider docs use `SQLExecuteQueryOperator` for ODBC SQL tasks.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"odbc_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"my_odbc_conn\",\n        hook_params={\"driver\": \"ODBC Driver 18 for SQL Server\"},\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS my_table (\n            dt VARCHAR(50),\n            value VARCHAR(255)\n        );\n        \"\"\",\n        autocommit=True,\n    )\n\n    insert_row = SQLExecuteQueryOperator(\n        task_id=\"insert_row\",\n        conn_id=\"my_odbc_conn\",\n        hook_params={\"driver\": \"ODBC Driver 18 for SQL Server\"},\n        sql=\"\"\"\n        INSERT INTO my_table (dt, value)\n        VALUES ('{{ ds }}', 'test_value');\n        \"\"\",\n        autocommit=True,\n    )\n\n    create_table >> insert_row\n```\n\nNotes:\n\n- `conn_id` points to the Airflow connection.\n- `autocommit` defaults to `False`; set it when your database and task pattern need statement-level commits.\n- `hook_params={\"driver\": ...}` is the documented operator-side way to pass the ODBC driver without enabling `allow_driver_in_extra`.\n\n## Use `OdbcHook` In Python Tasks\n\n`OdbcHook` returns a `pyodbc` connection from `get_conn()`. The hook constructor supports `driver`, `dsn`, `connect_kwargs`, and `sqlalchemy_scheme`.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.odbc.hooks.odbc import OdbcHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"odbc_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_rows() -> list[tuple[str, str]]:\n        hook = OdbcHook(\n            odbc_conn_id=\"my_odbc_conn\",\n            driver=\"ODBC Driver 18 for SQL Server\",\n            connect_kwargs={\"autocommit\": False},\n        )\n\n        with hook.get_conn() as conn:\n            cursor = conn.cursor()\n            cursor.execute(\n                \"\"\"\n                SELECT TOP 10 dt, value\n                FROM my_table\n                ORDER BY dt DESC\n                \"\"\"\n            )\n            rows = cursor.fetchall()\n\n        return [(row[0], row[1]) for row in rows]\n\n    read_rows()\n```\n\nUse `driver=` on the hook when:\n\n- you do not want to enable `allow_driver_in_extra`\n- you need to override the connection's driver for one task\n- you are using the hook directly rather than an operator\n\nIf your database relies on a DSN, pass `dsn=\"YourDsnName\"` to the hook, or make sure the DSN is already available where the task runs.\n\n## SQLAlchemy Workflow\n\n`OdbcHook` also exposes `get_sqlalchemy_engine()` and `get_sqlalchemy_connection()`. The default SQLAlchemy scheme is `mssql+pyodbc`, and you can override it with `sqlalchemy_scheme` when the target database needs a different dialect string.\n\n## Common Pitfalls\n\n- Installing only the Python package is not enough. Airflow still needs a working system ODBC driver.\n- Putting `driver` in connection `extra` does nothing unless `AIRFLOW__PROVIDERS_ODBC__ALLOW_DRIVER_IN_EXTRA=true` is set.\n- `SQLExecuteQueryOperator` takes `conn_id`; hook-specific settings such as `driver` belong in `hook_params`.\n- ODBC is only the transport layer. Your SQL still has to match the target database dialect.\n- Environment-defined connections do not appear in the Airflow UI or in `airflow connections list`.\n- If you depend on a DSN, that DSN must exist inside the runtime where the task executes, not just on your laptop.\n\n## Version Notes\n\n- `4.12.0` was released on `2026-03-02`.\n- The `4.12.0` provider line requires Airflow `2.11.0` or later.\n- The `4.12.0` changelog includes `Add Hook Level Lineage to SQL hooks`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-odbc/stable/`\n- ODBC connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-odbc/stable/connections/odbc.html`\n- ODBC operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-odbc/stable/operators.html`\n- `OdbcHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-odbc/stable/_api/airflow/providers/odbc/hooks/odbc/index.html`\n- Airflow connection management: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-odbc/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-openfaas/python/DOC.md",
    "content": "---\nname: providers-openfaas\ndescription: \"Apache Airflow provider for deploying, updating, deleting, and invoking OpenFaaS functions from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,openfaas,faas,serverless,hooks\"\n---\n\n# Apache Airflow OpenFaaS Provider Guide\n\nUse `apache-airflow-providers-openfaas` when an Airflow DAG needs to talk to an OpenFaaS gateway to deploy a function, update it, remove it, or invoke it over HTTP.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone OpenFaaS SDK.\n- The provider exposes a single hook, `OpenFaasHook`. Use it from TaskFlow tasks, `PythonOperator`, or your own operator.\n- Put the gateway base URL on an Airflow connection of type `openfaas` and keep function names plus deployment-specific values outside the DAG file.\n- For authenticated gateways or strict HTTP error handling, plan to wrap or subclass the hook. In `3.9.2`, the hook only reads `conn.host`, sends payloads with `requests.post(..., data=...)`, and returns response text without calling `raise_for_status()`.\n\n## What This Package Adds\n\nThis provider's main entry points are:\n\n- `OpenFaasHook`\n- Airflow connection type `openfaas`\n\nThere is no operator or sensor layer in this package. DAG code usually imports the hook directly.\n\n## Install\n\nThe provider depends on Apache Airflow `>=2.10.0`. Install it into the same environment used by the scheduler, workers, and any task runtime that imports your DAG code.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"3.9.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-openfaas==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider so `pip` does not silently change your Airflow core version:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-openfaas==3.9.2\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i openfaas\npython -c \"from airflow.providers.openfaas.hooks.openfaas import OpenFaasHook; print('ok')\"\n```\n\n## Configure The OpenFaaS Connection\n\nStart with a normal Airflow environment and keep the gateway URL plus function name in deployment config:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n\nexport OPENFAAS_GATEWAY_URL=\"http://127.0.0.1:8080\"\nexport OPENFAAS_FUNCTION_NAME=\"hello\"\n```\n\nCreate the Airflow connection:\n\n```bash\nairflow connections add 'openfaas_default' \\\n  --conn-type 'openfaas' \\\n  --conn-host \"$OPENFAAS_GATEWAY_URL\"\n```\n\nConfirm it exists:\n\n```bash\nairflow connections get openfaas_default\n```\n\nThe provider docs list `host`, `login`, `password`, and `extra` as optional connection fields. The `3.9.2` hook implementation uses the connection host as the base gateway URL and does not read the other fields when it makes requests.\n\n## Common Workflow: Invoke A Function From A DAG\n\nFor a local or otherwise unauthenticated gateway, call `invoke_function` directly from a task:\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.openfaas.hooks.openfaas import OpenFaasHook\n\n\nFUNCTION_NAME = os.environ[\"OPENFAAS_FUNCTION_NAME\"]\n\n\nwith DAG(\n    dag_id=\"openfaas_invoke_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"openfaas\"],\n):\n    @task()\n    def invoke_function() -> str:\n        hook = OpenFaasHook(openfaas_conn_id=\"openfaas_default\")\n        response_text = hook.invoke_function(\n            function_name=FUNCTION_NAME,\n            body=\"hello from airflow\",\n        )\n        if not response_text:\n            raise ValueError(\"OpenFaaS returned an empty response\")\n        return response_text\n\n    invoke_function()\n```\n\nThe hook posts to the OpenFaaS gateway path `/function/<function_name>` and returns the response body as text.\n\n## Common Workflow: Deploy, Update, And Delete Functions\n\nThe hook also exposes the OpenFaaS admin paths used for function lifecycle operations:\n\n```python\nfrom airflow.providers.openfaas.hooks.openfaas import OpenFaasHook\n\n\nhook = OpenFaasHook(openfaas_conn_id=\"openfaas_default\")\n\nhook.deploy_function(\n    function_name=\"hello-python\",\n    body={\n        \"service\": \"hello-python\",\n        \"image\": \"ghcr.io/example/hello-python:latest\",\n        \"envProcess\": \"python index.py\",\n    },\n)\n\nhook.update_function(\n    function_name=\"hello-python\",\n    body={\n        \"service\": \"hello-python\",\n        \"image\": \"ghcr.io/example/hello-python:v2\",\n    },\n)\n\nhook.delete_function(function_name=\"hello-python\")\n```\n\nThese methods target:\n\n- `POST /system/functions`\n- `PUT /system/functions`\n- `DELETE /system/functions`\n\nFor OpenFaaS deployments that expose the gateway admin API, the upstream REST API docs describe these as privileged endpoints and show Basic Auth on the gateway.\n\n## Authenticated Or Strictly Checked Requests\n\nOpenFaaS CE and Standard commonly protect the gateway with Basic Auth. If you need auth headers, response status checks, or request timeouts, use the hook for connection lookup and issue the HTTP request yourself:\n\n```python\nfrom __future__ import annotations\n\nimport os\n\nimport requests\n\nfrom airflow.providers.openfaas.hooks.openfaas import OpenFaasHook\n\n\nhook = OpenFaasHook(openfaas_conn_id=\"openfaas_default\")\ngateway_url = hook.get_conn()\n\nresponse = requests.post(\n    f\"{gateway_url}/function/{os.environ['OPENFAAS_FUNCTION_NAME']}\",\n    data=\"hello from airflow\",\n    auth=(\n        os.environ[\"OPENFAAS_ADMIN_USERNAME\"],\n        os.environ[\"OPENFAAS_ADMIN_PASSWORD\"],\n    ),\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.text)\n```\n\nUse this pattern when the thin provider hook is not enough for your gateway policy or observability requirements.\n\n## Available Hook Methods\n\n`OpenFaasHook` in `3.9.2` exposes these methods:\n\n- `get_conn()` returns the configured gateway base URL string\n- `deploy_function(function_name, body)`\n- `delete_function(function_name)`\n- `invoke_function(function_name, body)`\n- `update_function(function_name, body)`\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. A missing package on a worker or image causes import failures even if the scheduler has it.\n- Do not expect this provider to manage authentication for you. In `3.9.2`, the hook reads `conn.host` and ignores the documented `login`, `password`, and `extra` connection fields when making requests.\n- The hook returns response text only. It does not expose HTTP status codes or raise exceptions on non-2xx responses.\n- The hook sends request bodies with `requests.post(..., data=...)`, not `json=...`. If your function or gateway expects JSON semantics, serialize carefully or issue the HTTP request yourself.\n- `function_name` is used directly in the gateway path. Keep it stable and deployment-specific through env vars, Airflow Variables, or other config instead of hard-coding it repeatedly across DAG files.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-openfaas` version `3.9.2`.\n- The provider documentation added a dedicated `openfaas` connection type in the `3.9.0` line. If you are pinned below that, re-check the provider docs before copying connection setup commands.\n- Provider versions and Airflow core versions move independently. Re-check provider compatibility before upgrading one without the other.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/`\n- Requirements: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/index.html#requirements`\n- OpenFaaS connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/connections/openfaas.html`\n- `OpenFaasHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/_api/airflow/providers/openfaas/hooks/openfaas/index.html`\n- `OpenFaasHook` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/_modules/airflow/providers/openfaas/hooks/openfaas.html`\n- OpenFaaS REST API docs: `https://docs.openfaas.com/reference/rest-api/`\n- OpenFaaS function invocation docs: `https://docs.openfaas.com/reference/async/`\n- Airflow `3.9.0` release notes entry for OpenFaaS connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-openfaas/stable/changelog.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-openfaas/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-openlineage/python/DOC.md",
    "content": "---\nname: providers-openlineage\ndescription: \"Apache Airflow OpenLineage provider for emitting lineage events from DAGs and tasks to an OpenLineage backend\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,openlineage,lineage,data-lineage,dag,python\"\n---\n\n# apache-airflow-providers-openlineage\n\nUse `apache-airflow-providers-openlineage` to emit OpenLineage events from Airflow DAG runs and task runs to a configured backend such as an HTTP endpoint or console output. Basic setup is configuration-only: upstream says no DAG changes are required to start emitting events.\n\nThis guide targets provider version `2.11.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-openlineage==2.11.0\"\n```\n\nUpstream lists these minimum requirements for provider `2.11.0`:\n\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-sql>=1.32.0`\n- `apache-airflow-providers-common-compat>=1.14.0`\n- `openlineage-integration-common>=1.41.0`\n- `openlineage-python>=1.41.0`\n\nPyPI also lists Python `3.10` through `3.13` for this release.\n\nIf you are adding the provider to an existing Airflow environment, keep `apache-airflow` pinned in the same install command so dependency resolution does not unexpectedly move your core Airflow version:\n\n```bash\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-openlineage==2.11.0\"\n```\n\nThe provider must be available anywhere Airflow imports DAG code or runs tasks, which typically means the scheduler and every worker image.\n\n## Minimal Configuration\n\nOpenLineage does nothing until you configure a transport. The recommended configuration path is the Airflow `[openlineage]` section in `airflow.cfg` or the equivalent `AIRFLOW__OPENLINEAGE__*` environment variables.\n\nMinimal HTTP transport:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__TRANSPORT='{\"type\": \"http\", \"url\": \"http://example.com:5000\", \"endpoint\": \"api/v1/lineage\"}'\nexport AIRFLOW__OPENLINEAGE__NAMESPACE='my-airflow-instance'\n```\n\nEquivalent `airflow.cfg` section:\n\n```ini\n[openlineage]\ntransport = {\"type\": \"http\", \"url\": \"http://example.com:5000\", \"endpoint\": \"api/v1/lineage\"}\nnamespace = my-airflow-instance\n```\n\nUseful options from the provider configuration reference:\n\n- `AIRFLOW__OPENLINEAGE__TRANSPORT`: JSON transport configuration\n- `AIRFLOW__OPENLINEAGE__CONFIG_PATH`: path to an `openlineage.yml` file instead of inline JSON\n- `AIRFLOW__OPENLINEAGE__NAMESPACE`: logical namespace for this Airflow instance\n- `AIRFLOW__OPENLINEAGE__DISABLED`: disable event sending without uninstalling the provider\n- `AIRFLOW__OPENLINEAGE__DISABLE_SOURCE_CODE`: stop including source code for operators such as Python and Bash\n- `AIRFLOW__OPENLINEAGE__INCLUDE_FULL_TASK_INFO`: include full serialized task info; keep this off unless you need it\n- `AIRFLOW__OPENLINEAGE__DEBUG_MODE`: emit extra debugging details; use temporarily only\n\nConfiguration precedence is:\n\n1. `config_path`\n2. `transport`\n3. fallback lookup performed by the underlying `openlineage-python` client\n\nUpstream explicitly recommends Airflow configuration as the future-proof option.\n\n## Configure With A YAML File\n\nIf you already manage OpenLineage transport settings in YAML, point Airflow at that file:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__CONFIG_PATH=\"/opt/airflow/openlineage.yml\"\n```\n\nExample `openlineage.yml` content from the provider docs:\n\n```yaml\ntransport:\n  type: http\n  url: https://backend:5000\n  endpoint: events/receive\n  auth:\n    type: api_key\n    apiKey: your-api-key\n```\n\nUse `config_path` when you do not want JSON embedded in environment variables or `airflow.cfg`.\n\n## Verify Events With A Simple DAG\n\nAll Airflow operators emit basic OpenLineage events unless explicitly disabled or skipped during scheduling. A minimal smoke test DAG is enough to verify that your transport is configured correctly:\n\n```python\nfrom __future__ import annotations\n\nfrom airflow import DAG\nfrom airflow.providers.standard.operators.python import PythonOperator\nfrom pendulum import datetime\n\n\ndef emit_log() -> None:\n    print(\"openlineage smoke test\")\n\n\nwith DAG(\n    dag_id=\"openlineage_smoke_test\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"lineage\"],\n) as dag:\n    PythonOperator(\n        task_id=\"emit_log\",\n        python_callable=emit_log,\n    )\n```\n\nFor local debugging, send events to task logs instead of a backend:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__TRANSPORT='{\"type\": \"console\"}'\n```\n\nOnce the DAG runs, the provider emits task and DAG metadata automatically. Upstream's supported-classes docs note that richer lineage details depend on the operator or hook that ran.\n\n## Richer Lineage From Supported Operators And Hooks\n\nThe provider distinguishes between:\n\n- basic events for every operator\n- richer events for supported operators and hooks\n\nUpstream says supported operators and hooks can add metadata such as:\n\n- input and output datasets\n- SQL text and query IDs for supported SQL executions\n- source code or external job IDs for some operators\n\nHook-level lineage also matters. When a supported hook is called from a \"black box\" task such as `PythonOperator`, the provider can still capture lineage from that hook execution.\n\nPractical implication:\n\n- use supported SQL operators and supported database hooks when you want dataset-level lineage\n- for custom Python tasks, prefer supported hooks over raw client libraries if you want automatic lineage extraction\n- check the upstream supported-classes list before assuming a specific operator or hook will emit input/output datasets\n\n## Enable Or Disable Lineage Selectively\n\nIf you do not want lineage on every DAG, enable the selective policy first:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__SELECTIVE_ENABLE=\"true\"\n```\n\nThen enable or disable lineage in code with `enable_lineage` and `disable_lineage`:\n\n```python\nfrom __future__ import annotations\n\nfrom airflow import DAG\nfrom airflow.providers.openlineage.utils.selective_enable import disable_lineage, enable_lineage\nfrom airflow.providers.standard.operators.python import PythonOperator\nfrom pendulum import datetime\n\n\ndef extract() -> None:\n    print(\"extract\")\n\n\ndef publish_metrics() -> None:\n    print(\"publish\")\n\n\nwith DAG(\n    dag_id=\"openlineage_selective_enable\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    extract_task = PythonOperator(\n        task_id=\"extract\",\n        python_callable=extract,\n    )\n\n    publish_task = PythonOperator(\n        task_id=\"publish_metrics\",\n        python_callable=publish_metrics,\n    )\n\n    enable_lineage(dag)\n    disable_lineage(extract_task)\n\n    extract_task >> publish_task\n```\n\nImportant behavior from the provider docs:\n\n- `disabled=true` overrides selective enablement and turns everything off\n- enabling lineage on a task implicitly enables it on the DAG as well\n- disabling DAG-level lineage while enabling task-level lineage can cause errors or inconsistencies because emitted tasks rely on `ParentRunFacet`\n\n## Exclude Specific Operators Globally\n\nIf a few operator classes are especially noisy, exclude them through configuration without changing DAG code:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__DISABLED_FOR_OPERATORS='airflow.providers.standard.operators.bash.BashOperator;airflow.providers.standard.operators.python.PythonOperator'\n```\n\nThis setting takes semicolon-separated full import paths for operator classes.\n\n## Custom Extractors And Custom Run Facets\n\nWhen built-in extraction is not enough, you can register your own extractor classes or run facet functions through configuration:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__EXTRACTORS='my_project.lineage.CustomExtractor'\nexport AIRFLOW__OPENLINEAGE__CUSTOM_RUN_FACETS='my_project.lineage.get_custom_run_facet'\n```\n\nUse this when:\n\n- you run third-party operators that do not expose the lineage metadata you need\n- you want extra run metadata added to emitted events\n\nThe provider docs state that extractor precedence is:\n\n1. user-registered extractor\n2. operator OpenLineage methods\n3. inlets and outlets\n\nIf none of those exist, you still get general Airflow task and DAG events, but not operator-specific input or output datasets.\n\n## Spark Integration Flags\n\nFor supported Spark operators, the provider can inject parent job information and transport information into Spark properties:\n\n```bash\nexport AIRFLOW__OPENLINEAGE__SPARK_INJECT_PARENT_JOB_INFO=\"true\"\nexport AIRFLOW__OPENLINEAGE__SPARK_INJECT_TRANSPORT_INFO=\"true\"\n```\n\nUse these only when your Spark jobs also participate in OpenLineage and you want parent-child relationships and shared transport configuration propagated automatically.\n\n## Pitfalls\n\n- No transport means no events. Set `transport` or `config_path` first.\n- Keep `disable_source_code=true` if Python or Bash task source should not leave the worker in lineage events.\n- Keep `include_full_task_info=false` unless you explicitly need full serialized task parameters. Upstream warns this can make events very large.\n- `debug_mode=true` is for temporary debugging. It can include extensive environment details.\n- Do not rely on legacy `OPENLINEAGE_*` variables for new setups. The provider keeps them only for backward compatibility and warns they may be removed in the future.\n- The supported-classes list is useful, but upstream notes it is generated automatically and may not perfectly reflect every hook-level detail. Verify the exact operator or hook path you depend on.\n\n## Version Notes\n\n- This guide is for `apache-airflow-providers-openlineage==2.11.0`.\n- Upstream says this provider requires `apache-airflow>=2.11.0`.\n- Upstream also says `openlineage-python` can be upgraded independently of Airflow and the provider, and recommends keeping that client current for fixes and features.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/`\n- Configuration reference: `https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/configurations-ref.html`\n- Intro and quickstart: `https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/guides/structure.html`\n- Supported classes: `https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/supported_classes.html`\n- Custom operators and extractor precedence: `https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/guides/developer.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-opensearch/python/DOC.md",
    "content": "---\nname: providers-opensearch\ndescription: \"Apache Airflow OpenSearch provider for Airflow connections and OpenSearch hook-based DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,opensearch,search,dag,python\"\n---\n\n# apache-airflow-providers-opensearch\n\nUse `apache-airflow-providers-opensearch` when your Airflow DAGs need an Airflow-managed connection and a Python hook for talking to an OpenSearch cluster from tasks.\n\nThis guide targets provider version `1.8.4`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npip install apache-airflow-providers-opensearch==1.8.4\n```\n\nIn practice, the scheduler, webserver, and every worker that imports DAG code must all have the provider available.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection for the OpenSearch endpoint. The default connection id is commonly `opensearch_default`.\n\nYou can create it in the Airflow UI, or define it with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_OPENSEARCH_DEFAULT='opensearch://admin:admin@opensearch.example.com:9200?use_ssl=true&verify_certs=true'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `opensearch_default`\n- DAG code passes `opensearch_conn_id=\"opensearch_default\"`\n- credentials stay in the Airflow connection layer instead of in DAG files\n\nConnection values you usually need:\n\n- `Host`: the OpenSearch endpoint\n- `Port`: usually `9200` for self-managed clusters or `443` behind HTTPS\n- `Login` and `Password`: if your cluster uses basic auth\n- `Schema`: `http` or `https` as appropriate\n- `Extra`: TLS-related settings such as certificate verification when needed\n\nKeep connection secrets and TLS settings in Airflow connections or a secrets backend instead of hard-coding them in tasks.\n\n## Use The Hook In A DAG\n\nUse `OpenSearchHook` inside a TaskFlow or Python task when you need to call the OpenSearch client directly.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.opensearch.hooks.opensearch import OpenSearchHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"opensearch_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def write_and_search() -> list[dict]:\n        hook = OpenSearchHook(opensearch_conn_id=\"opensearch_default\")\n        client = hook.get_conn()\n\n        if not client.ping():\n            raise RuntimeError(\"OpenSearch is not reachable\")\n\n        index_name = \"airflow-demo\"\n\n        if not client.indices.exists(index=index_name):\n            client.indices.create(\n                index=index_name,\n                body={\n                    \"settings\": {\n                        \"index\": {\n                            \"number_of_shards\": 1,\n                            \"number_of_replicas\": 0,\n                        }\n                    }\n                },\n            )\n\n        client.index(\n            index=index_name,\n            id=\"1\",\n            body={\"message\": \"hello from airflow\", \"source\": \"dag-task\"},\n            refresh=True,\n        )\n\n        response = client.search(\n            index=index_name,\n            body={\n                \"query\": {\n                    \"match\": {\n                        \"message\": \"airflow\",\n                    }\n                }\n            },\n        )\n\n        hits = response[\"hits\"][\"hits\"]\n        print(hits)\n        return hits\n\n    write_and_search()\n```\n\nThe important pattern is:\n\n1. create `OpenSearchHook(opensearch_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned OpenSearch client for normal `opensearch-py` calls such as `ping()`, `indices.create()`, `index()`, and `search()`\n\n## Read Cluster Metadata In A Task\n\nFor health checks or debugging, call the client returned by the hook and inspect cluster info.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.opensearch.hooks.opensearch import OpenSearchHook\n\n@task\ndef show_cluster_info() -> None:\n    hook = OpenSearchHook(opensearch_conn_id=\"opensearch_default\")\n    client = hook.get_conn()\n\n    info = client.info()\n    print(info[\"version\"][\"number\"])\n    print(info[\"cluster_name\"])\n```\n\nUse this pattern when a DAG should fail early if the endpoint is unreachable or pointed at the wrong cluster.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep the endpoint, auth, and TLS configuration in an Airflow connection\n- create the client inside a task with `OpenSearchHook`\n- use normal OpenSearch client calls for index creation, indexing, and search\n- return only small derived results from tasks instead of large raw search payloads when downstream tasks do not need the full response\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or worker is missing the package.\n- Use `opensearch_conn_id`, not a generic `conn_id`, when creating `OpenSearchHook`.\n- Make sure workers can reach the OpenSearch endpoint over the network. A connection that works from the webserver container may still fail on workers.\n- Keep auth and TLS options in the Airflow connection instead of embedding them in DAG source.\n- If a task writes a document and immediately searches for it in the same run, use `refresh=True` on `index()` or an explicit refresh before `search()`.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-opensearch` version `1.8.4`.\n- If you upgrade the provider, check the provider docs and API reference for any changes to connection handling or hook behavior before rolling the change across production Airflow images.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-opensearch/stable/`\n- OpenSearch connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-opensearch/stable/connections/opensearch.html`\n- `OpenSearchHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-opensearch/stable/_api/airflow/providers/opensearch/hooks/opensearch/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-opensearch/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-opsgenie/python/DOC.md",
    "content": "---\nname: providers-opsgenie\ndescription: \"Apache Airflow provider for creating and closing Opsgenie alerts from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.10.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,opsgenie,alerts,incident-management,dag\"\n---\n\n# Apache Airflow Providers Opsgenie Guide\n\nUse `apache-airflow-providers-opsgenie` to send alert actions from Airflow DAGs into Opsgenie through Airflow connections, hooks, and operators.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Opsgenie client.\n- Store the Opsgenie API key in an Airflow connection such as `opsgenie_default` instead of hard-coding it in DAG files.\n- Use a stable alert `alias` when you may need to close or deduplicate the same alert later.\n\n## Install\n\nStart from an Airflow installation that uses the official constraints file for your Airflow and Python versions, then add the Opsgenie provider in the same command.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.10.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-opsgenie==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep `apache-airflow` pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-opsgenie==5.10.1\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep opsgenie\nairflow info\n```\n\n## Authentication And Connection Setup\n\nMost DAG code uses the conventional connection ID `opsgenie_default`, and provider APIs let you override it with `opsgenie_conn_id`.\n\nCreate shell variables for your Opsgenie account first:\n\n```bash\nexport OPSGENIE_API_KEY=\"<opsgenie-api-key>\"\nexport OPSGENIE_HOST=\"api.opsgenie.com\"\n```\n\nIf your account uses the EU region, set:\n\n```bash\nexport OPSGENIE_HOST=\"api.eu.opsgenie.com\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'opsgenie_default' \\\n  --conn-type 'opsgenie' \\\n  --conn-host \"$OPSGENIE_HOST\" \\\n  --conn-password \"$OPSGENIE_API_KEY\"\n```\n\nConfirm the connection exists before you wire it into a DAG:\n\n```bash\nairflow connections get opsgenie_default\n```\n\n## Common Workflow: Create And Close An Alert From A DAG\n\nUse a create operator to open the alert and a close operator that refers to the same `alias`.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.opsgenie.operators.opsgenie import (\n    OpsgenieCloseAlertOperator,\n    OpsgenieCreateAlertOperator,\n)\n\n\nwith DAG(\n    dag_id=\"opsgenie_alert_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"opsgenie\"],\n):\n    create_alert = OpsgenieCreateAlertOperator(\n        task_id=\"create_alert\",\n        opsgenie_conn_id=\"opsgenie_default\",\n        message=\"Airflow pipeline needs attention\",\n        alias=\"airflow-opsgenie-demo-{{ ds_nodash }}\",\n        description=\"Investigate the DAG run in Airflow\",\n        source=\"airflow\",\n        priority=\"P3\",\n        tags=[\"airflow\", \"demo\"],\n        details={\n            \"dag_id\": \"{{ dag.dag_id }}\",\n            \"run_id\": \"{{ run_id }}\",\n        },\n        responders=[\n            {\"name\": \"platform-oncall\", \"type\": \"team\"},\n        ],\n    )\n\n    close_alert = OpsgenieCloseAlertOperator(\n        task_id=\"close_alert\",\n        opsgenie_conn_id=\"opsgenie_default\",\n        identifier=\"airflow-opsgenie-demo-{{ ds_nodash }}\",\n        identifier_type=\"alias\",\n        note=\"Closed by Airflow after successful follow-up work\",\n    )\n\n    create_alert >> close_alert\n```\n\nThis pattern is useful when you want Airflow itself to own the alert lifecycle instead of calling the Opsgenie REST API manually inside a Python task.\n\n## Common Workflow: Create An Alert From Python Code In A Task\n\nUse the hook when you need normal Python control flow inside a task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.opsgenie.hooks.opsgenie import OpsgenieAlertHook\n\n\nwith DAG(\n    dag_id=\"opsgenie_hook_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"opsgenie\"],\n):\n    @task()\n    def notify_opsgenie() -> None:\n        hook = OpsgenieAlertHook(opsgenie_conn_id=\"opsgenie_default\")\n        hook.create_alert(\n            message=\"Warehouse sync failed\",\n            alias=\"warehouse-sync-demo\",\n            description=\"Check the Airflow task log for details\",\n            source=\"airflow\",\n            priority=\"P2\",\n            tags=[\"airflow\", \"warehouse\"],\n            details={\n                \"dag_id\": \"opsgenie_hook_demo\",\n                \"task_id\": \"notify_opsgenie\",\n            },\n        )\n\n    notify_opsgenie()\n```\n\nUse the operator form when you want a declarative DAG node. Use the hook form when the alert payload depends on Python logic in the task body.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep opsgenie\nairflow dags list | grep opsgenie\n```\n\nRun an isolated task test while you wire up the connection and payload:\n\n```bash\nairflow tasks test opsgenie_alert_demo create_alert 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Use a normal DAG trigger when you need scheduler behavior, retries, callbacks, and downstream tasks to participate.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Hard-coding the API key in DAG code: keep it in the Airflow connection instead.\n- Reusing a vague `alias`: use an alias format that matches how your team identifies alerts and closes them later.\n- Forgetting the Opsgenie region host: use `api.eu.opsgenie.com` for EU accounts instead of the default US host.\n- Relying on an implicit connection name: pass `opsgenie_conn_id` explicitly when a DAG does not use `opsgenie_default`.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-opsgenie` version `5.10.1`.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so `pip` does not silently change your Airflow core version.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-oracle/python/DOC.md",
    "content": "---\nname: providers-oracle\ndescription: \"Apache Airflow Oracle provider for Airflow connections, SQL tasks, and OracleHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,oracle,oracledb,sql,dag,python\"\n---\n\n# apache-airflow-providers-oracle\n\nUse `apache-airflow-providers-oracle` to connect Airflow to Oracle Database through an Airflow connection, run SQL from DAG tasks, and call Oracle from Python tasks with `OracleHook`.\n\nThis guide targets provider version `4.5.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-oracle` is an Apache Airflow provider package. Install it when your DAGs need Oracle connections and hook-based access from Airflow tasks.\n\nThis package extends Airflow. It is not a standalone Oracle client for general application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-oracle==4.5.0\"\n```\n\nThe 4.5.0 provider docs list these minimum requirements:\n\n- `apache-airflow >= 2.11.0`\n- `oracledb >= 2.0.0`\n- `apache-airflow-providers-common-sql >= 1.26.0`\n\nIn practice, the scheduler, workers, and webserver all need the provider installed anywhere DAG code imports it.\n\n## Configure The Airflow Connection\n\nThe provider reads connection settings from an Airflow connection with connection type `oracle`. The default connection id is `oracle_default`.\n\nIn the Airflow UI, configure:\n\n- **Connection Id:** `oracle_default`\n- **Connection Type:** `oracle`\n- **Host:** Oracle host name\n- **Schema:** default Oracle schema to use after connecting\n- **Login / Password:** Oracle credentials\n- **Port:** usually `1521`\n\nUse one of these extras to select the database service:\n\n- `service_name`\n- `sid`\n- `dsn`\n\nDo not set both `sid` and `service_name` in the same connection.\n\nEnvironment variable example using a service name:\n\n```bash\nexport AIRFLOW_CONN_ORACLE_DEFAULT='oracle://app_user:secret@db.example.com:1521/analytics?service_name=orclpdb1'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `oracle_default`\n- SQL operators use `conn_id=\"oracle_default\"`\n- `OracleHook` uses `oracle_conn_id=\"oracle_default\"`\n- `analytics` is the default schema, while `service_name=orclpdb1` selects the Oracle service\n\nUseful extras you may need in real deployments:\n\n```json\n{\n  \"service_name\": \"orclpdb1\",\n  \"mode\": \"sysdba\",\n  \"fetch_lobs\": true,\n  \"fetch_decimals\": true,\n  \"thick_mode\": true,\n  \"thick_mode_lib_dir\": \"/opt/oracle/instantclient_23_5\",\n  \"thick_mode_config_dir\": \"/opt/oracle/network/admin\"\n}\n```\n\nConnection notes:\n\n- Use `service_name`, `sid`, or `dsn` in extras to choose the database target. In the 4.x provider line, `schema` is not the service selector.\n- If you need Oracle Client libraries, enable `thick_mode` and make those libraries available on every Airflow runtime that may open the connection.\n- For wallet and TLS-based setups, the provider also supports extras such as `wallet_location`, `wallet_password`, `ssl_server_cert_dn`, and `ssl_server_dn_match`.\n- If the password or extras contain reserved URL characters, URL-encode them before putting them in `AIRFLOW_CONN_*`.\n\n## Minimal Connection Check\n\nUse `OracleHook` for a quick sanity check from a task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.oracle.hooks.oracle import OracleHook\n\n\n@task\ndef ping_oracle() -> int:\n    hook = OracleHook(oracle_conn_id=\"oracle_default\")\n    row = hook.get_first(\"SELECT 1 FROM dual\")\n    return int(row[0])\n```\n\n`OracleHook` uses `oracle_conn_id`, not `conn_id`.\n\n## Run SQL In A DAG\n\nFor SQL-only tasks, use Airflow's generic SQL operator with an Oracle connection:\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import datetime\n\nfrom airflow.decorators import dag\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\n\n\n@dag(\n    dag_id=\"oracle_sql_example\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"oracle\"],\n)\ndef oracle_sql_example():\n    insert_row = SQLExecuteQueryOperator(\n        task_id=\"insert_row\",\n        conn_id=\"oracle_default\",\n        sql=\"\"\"\n        INSERT INTO customer_events (event_name, created_at)\n        VALUES (:event_name, SYSDATE)\n        \"\"\",\n        parameters={\"event_name\": \"signup\"},\n    )\n\n    mark_processed = SQLExecuteQueryOperator(\n        task_id=\"mark_processed\",\n        conn_id=\"oracle_default\",\n        sql=\"\"\"\n        UPDATE customer_events\n        SET processed_at = SYSDATE\n        WHERE event_name = :event_name\n        \"\"\",\n        parameters={\"event_name\": \"signup\"},\n    )\n\n    insert_row >> mark_processed\n\n\noracle_sql_example()\n```\n\nUse this pattern when the task is just SQL execution and you do not need Python logic around the result set.\n\n## Query Oracle From Python Tasks\n\nUse `OracleHook` when you need to fetch rows, branch on results, or mix database work with Python task logic:\n\n```python\nfrom __future__ import annotations\n\nfrom datetime import datetime\n\nfrom airflow.decorators import dag, task\nfrom airflow.providers.oracle.hooks.oracle import OracleHook\n\n\n@dag(\n    dag_id=\"oracle_hook_example\",\n    start_date=datetime(2024, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"oracle\"],\n)\ndef oracle_hook_example():\n    @task\n    def read_summary() -> dict[str, int]:\n        hook = OracleHook(oracle_conn_id=\"oracle_default\")\n\n        row = hook.get_first(\n            \"\"\"\n            SELECT COUNT(*)\n            FROM customer_events\n            WHERE event_name = :event_name\n            \"\"\",\n            parameters={\"event_name\": \"signup\"},\n        )\n\n        records = hook.get_records(\n            \"\"\"\n            SELECT id, event_name\n            FROM customer_events\n            WHERE ROWNUM <= 10\n            ORDER BY id\n            \"\"\"\n        )\n\n        print(records)\n        return {\"signup_count\": int(row[0]) if row else 0}\n\n    read_summary()\n\n\noracle_hook_example()\n```\n\nUseful hook methods for everyday DAG work:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying DB-API connection\n\n## Call Stored Procedures\n\nFor procedure calls from a Python task, use `OracleHook.callproc(...)`:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.oracle.hooks.oracle import OracleHook\n\n\n@task\ndef run_procedure() -> int:\n    hook = OracleHook(oracle_conn_id=\"oracle_default\")\n\n    result = hook.callproc(\n        \"refresh_customer_rollups\",\n        parameters=[42, int],\n    )\n\n    return int(result[1])\n```\n\nPass `OUT` parameters as Python types or instances. In the example above, the procedure receives one input argument (`42`) and one integer output argument.\n\n## Bulk Insert Rows\n\nUse `bulk_insert_rows(...)` when you need batched inserts from a Python task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.oracle.hooks.oracle import OracleHook\n\n\n@task\ndef load_batch() -> None:\n    hook = OracleHook(oracle_conn_id=\"oracle_default\")\n    hook.bulk_insert_rows(\n        table=\"customer_events\",\n        rows=[\n            (\"signup\",),\n            (\"purchase\",),\n            (\"refund\",),\n        ],\n        target_fields=[\"event_name\"],\n        commit_every=1000,\n    )\n```\n\nIf your table uses an Oracle sequence instead of an identity column, pass `sequence_column` and `sequence_name` as well.\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the package.\n- `OracleHook` expects `oracle_conn_id`; generic SQL operators use `conn_id`.\n- For 4.x providers, use `extra.service_name` or `extra.sid` to pick the Oracle database target. Do not rely on `schema` for that older behavior.\n- Regular SQL statements passed to `insert_rows(...)` should not end with `;`. Use PL/SQL block syntax only when you are intentionally executing a `BEGIN ... END;` block.\n- Thick mode needs Oracle Client libraries on the worker runtime. Setting `thick_mode=true` without those libraries will not work.\n- Keep credentials in Airflow connections or a secrets backend instead of hard-coding usernames and passwords in DAG files.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-oracle` version `4.5.0`.\n- The 4.5.0 provider docs list `apache-airflow >= 2.11.0` as the minimum compatible Airflow version.\n- Oracle connection extras for wallets, TLS server DN checks, `fetch_decimals`, `fetch_lobs`, and connection-class settings were added in the 4.3.0 line. Older blog posts may not mention them.\n- The 4.4.0 line specialized Oracle hook `get_first(...)` and `get_records(...)` return handling to avoid Oracle data types causing XCom serialization failures.\n- The 4.0.0 line removed deprecated behavior that treated `schema` as the Oracle service name. Use `extra.service_name` instead.\n- The 4.5.0 operator guide points new SQL work to `SQLExecuteQueryOperator`. The generated Python API docs still include `OracleStoredProcedureOperator`, but `OracleHook.callproc(...)` is the clearest current API for procedure calls.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/`\n- Oracle connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/connections/oracle.html`\n- `OracleHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/_api/airflow/providers/oracle/hooks/oracle/index.html`\n- Operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/operators.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/changelog.html`\n- 4.5.0 package page: `https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/index.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-pagerduty/python/DOC.md",
    "content": "---\nname: providers-pagerduty\ndescription: \"Apache Airflow provider for sending PagerDuty Events API alerts and callback notifications from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.2.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,pagerduty,events,alerts,notifications\"\n---\n\n# apache-airflow-providers-pagerduty\n\nUse `apache-airflow-providers-pagerduty` to send PagerDuty Events API v2 alerts from Airflow task code and callback notifications.\n\nThis package extends Apache Airflow. It is not a standalone PagerDuty REST client for managing incidents, services, schedules, or users.\n\nThis guide targets provider version `5.2.3`.\n\n## What This Package Adds\n\nThe PagerDuty provider centers on Airflow-native event delivery through an Airflow connection:\n\n- `PagerdutyEventsHook` for sending events from Python task code\n- `send_pagerduty_notification(...)` for DAG or task callbacks\n- PagerDuty connection handling so you can keep the routing key out of DAG source\n\nUse this provider when Airflow needs to trigger or deduplicate PagerDuty alerts. Keep using a PagerDuty REST client outside this provider when you need broader account or incident-management APIs.\n\n## Install\n\nInstall the provider into the same Airflow environment as every scheduler, worker, triggerer, and webserver process that imports your DAGs.\n\nStart from a pinned Airflow install and use the official constraints file for your Airflow and Python versions:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.2.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-pagerduty==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep the Airflow core package pinned when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-pagerduty==5.2.3\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep pagerduty\nairflow info\n```\n\n## Configure The PagerDuty Connection\n\nCreate a PagerDuty Events API integration in PagerDuty and copy its **routing key**. That routing key is what this provider sends with each event.\n\nRecommended Airflow connection fields:\n\n- **Connection Id:** `pagerduty_default`\n- **Connection Type:** `pagerduty`\n- **Host:** `events.pagerduty.com`\n- **Password:** your PagerDuty Events API v2 routing key\n\nExample with the Airflow CLI:\n\n```bash\nexport PAGERDUTY_EVENTS_HOST='events.pagerduty.com'\nexport PAGERDUTY_ROUTING_KEY='<pagerduty-events-routing-key>'\n\nairflow connections add 'pagerduty_default' \\\n  --conn-type 'pagerduty' \\\n  --conn-host \"$PAGERDUTY_EVENTS_HOST\" \\\n  --conn-password \"$PAGERDUTY_ROUTING_KEY\"\n```\n\nConfirm the connection before you wire it into a DAG:\n\n```bash\nairflow connections get pagerduty_default\n```\n\nPractical notes:\n\n- Use a PagerDuty **Events API routing key**, not a PagerDuty REST API token.\n- Keep the routing key in the Airflow connection or a secrets backend instead of hard-coding it in DAG files.\n- Use a stable `dedup_key` when you want repeated events to collapse into the same PagerDuty incident.\n\n## Send An Event From Python With `PagerdutyEventsHook`\n\nUse `PagerdutyEventsHook` when the event payload depends on task logic or Airflow runtime context.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import get_current_context, task\nfrom airflow.providers.pagerduty.hooks.pagerduty_events import PagerdutyEventsHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"pagerduty_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def trigger_pagerduty_event() -> None:\n        context = get_current_context()\n\n        hook = PagerdutyEventsHook()\n        hook.send_event(\n            summary=f\"Airflow failure in {context['dag'].dag_id}\",\n            severity=\"critical\",\n            source=\"airflow\",\n            dedup_key=f\"{context['dag'].dag_id}:{context['run_id']}\",\n            custom_details={\n                \"dag_id\": context[\"dag\"].dag_id,\n                \"task_id\": context[\"ti\"].task_id,\n                \"run_id\": context[\"run_id\"],\n                \"log_url\": context[\"ti\"].log_url,\n            },\n        )\n\n    trigger_pagerduty_event()\n```\n\nImportant details:\n\n- `summary`, `severity`, and `source` are the core event fields you should set explicitly.\n- `dedup_key` is the field you keep stable when the same logical alert should update the same PagerDuty incident.\n- `custom_details` is the right place for DAG metadata such as `dag_id`, `task_id`, `run_id`, and a log URL.\n\nUse the hook inside a Python task when the event body is assembled dynamically from task output or execution context.\n\n## Use PagerDuty Notifications For Callbacks\n\nUse `send_pagerduty_notification(...)` when you want PagerDuty alerting attached to a DAG or task callback instead of adding a standalone task node.\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.empty import EmptyOperator\nfrom airflow.providers.pagerduty.notifications.pagerduty import (\n    send_pagerduty_notification,\n)\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"pagerduty_failure_callback_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    on_failure_callback=send_pagerduty_notification(\n        summary=\"Airflow task failed: {{ ti.task_id }}\",\n        severity=\"critical\",\n        source=\"airflow\",\n        dedup_key=\"{{ dag.dag_id }}:{{ run_id }}\",\n        custom_details={\n            \"dag_id\": \"{{ dag.dag_id }}\",\n            \"task_id\": \"{{ ti.task_id }}\",\n            \"run_id\": \"{{ run_id }}\",\n            \"log_url\": \"{{ ti.log_url }}\",\n        },\n    ),\n) as dag:\n    start = EmptyOperator(task_id=\"start\")\n```\n\nUse this path when PagerDuty is an alerting side effect of a failure callback rather than a first-class task in the DAG graph.\n\n## Operational Checks\n\nCheck the provider import path and connection before debugging payload details:\n\n```bash\nairflow providers list | grep pagerduty\nairflow connections get pagerduty_default\n```\n\nRun a task-level test after the provider and connection are in place:\n\n```bash\nairflow tasks test pagerduty_hook_example trigger_pagerduty_event 2026-03-12\n```\n\nUse `airflow tasks test` for quick feedback on imports, connection lookup, and Python task logic without waiting for a full scheduler-driven DAG run.\n\n## Common Pitfalls\n\n- Using a PagerDuty REST API token instead of an Events API v2 routing key.\n- Installing the provider only on the scheduler. Workers and any process that imports DAG files also need the package.\n- Letting `dedup_key` change on every retry when you actually want repeated failures to map to the same incident.\n- Treating this provider like a general PagerDuty SDK. Its practical role in Airflow is event delivery and callback-based notification.\n- Forgetting that workers need outbound network access to PagerDuty's events endpoint.\n\n## Minimal Decision Guide\n\n- Use `PagerdutyEventsHook` inside a Python task when the event payload is assembled dynamically.\n- Use `send_pagerduty_notification(...)` for DAG-level or task-level callbacks.\n- Keep the routing key in an Airflow connection and reference the connection id from DAG code.\n- Keep Airflow and provider versions pinned together when you install or upgrade.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-pagerduty` version `5.2.3`.\n- Airflow provider packages are versioned separately from Apache Airflow core, so install or upgrade them with an explicit Airflow pin.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-pagerduty/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-pagerduty/stable/index.html`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-pagerduty/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-papermill/python/DOC.md",
    "content": "---\nname: providers-papermill\ndescription: \"Apache Airflow Papermill provider for running parameterized Jupyter notebooks as DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.12.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,papermill,jupyter,notebook,dag\"\n---\n\n# Apache Airflow Papermill Provider Python Guide\n\n## Golden Rule\n\n`apache-airflow-providers-papermill` is an Airflow provider package, not a standalone notebook runner. Install it into an existing Airflow environment, store notebooks somewhere Airflow can read and write, and execute them with `PapermillOperator`.\n\nThis guide targets provider version `3.12.1`. PyPI lists these minimum versions for this release:\n\n- Python `>=3.10`\n- `apache-airflow>=2.11.0`\n\n## Install\n\nInstall the provider into the same Python environment or container image that runs your Airflow scheduler and workers.\n\nIf Airflow is already installed, pin the current core version in the same command so `pip` does not replace it unexpectedly:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-papermill==3.12.1\"\n```\n\nThe provider depends on `papermill[all]`, `scrapbook[all]`, `ipykernel`, and `jupyter-client`, so a normal provider install brings in the notebook execution pieces it needs.\n\n## Prepare The Notebook\n\nPapermill executes a notebook file and injects parameters into it. The provider docs show notebook paths on local storage, S3, GCS, and Azure Blob Storage. HDFS is explicitly not supported.\n\nUse a tagged `parameters` cell in the input notebook when you want stable parameter injection:\n\n```python\n# parameters\nmessage = \"default message\"\n```\n\nIf the notebook does not already contain a `parameters` cell, Papermill injects an `injected-parameters` cell near the top of the notebook.\n\nSave the input notebook somewhere Airflow can access, for example:\n\n- `/opt/airflow/dags/notebooks/input.ipynb`\n- `s3://your-bucket/notebooks/input.ipynb`\n- `gs://your-bucket/notebooks/input.ipynb`\n- `wasbs://container@account.blob.core.windows.net/notebooks/input.ipynb`\n\n## Run A Notebook In A DAG\n\nUse `PapermillOperator` for the actual notebook execution task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.papermill.operators.papermill import PapermillOperator\n\nwith DAG(\n    dag_id=\"papermill_local_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"papermill\"],\n) as dag:\n    run_notebook = PapermillOperator(\n        task_id=\"run_notebook\",\n        input_nb=\"/opt/airflow/dags/notebooks/input.ipynb\",\n        output_nb=\"/opt/airflow/dags/notebooks/output-{{ ds_nodash }}.ipynb\",\n        parameters={\"message\": \"Hello from Airflow\"},\n    )\n```\n\nThe operator API exposes the arguments you usually need:\n\n- `input_nb`: source notebook path or notebook outlet\n- `output_nb`: output notebook path or notebook outlet\n- `parameters`: values injected into the notebook\n- `kernel_conn_id`: optional Airflow connection for a remote Jupyter kernel\n- `kernel_name` and `language_name`: optional kernel metadata overrides\n\n`input_nb`, `output_nb`, `parameters`, `kernel_conn_id`, `kernel_name`, and `language_name` are templated fields, so you can use Airflow macros inside them.\n\n## Read Output Values With `scrapbook`\n\nThe official example DAG reads the executed notebook back with `scrapbook` from a downstream task. Use that pattern when the notebook produces structured output you want later Airflow tasks to inspect.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\nimport scrapbook as sb\n\nfrom airflow import DAG\nfrom airflow.providers.papermill.operators.papermill import PapermillOperator\n\ntry:\n    from airflow.sdk import task\nexcept ImportError:\n    from airflow.decorators import task\n\n\n@task()\ndef inspect_notebook(output) -> None:\n    notebook = sb.read_notebook(output.url)\n    print(notebook.scraps[\"message\"].data)\n\n\nwith DAG(\n    dag_id=\"papermill_output_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_notebook = PapermillOperator(\n        task_id=\"run_notebook\",\n        input_nb=\"/opt/airflow/dags/notebooks/input.ipynb\",\n        output_nb=\"/opt/airflow/dags/notebooks/output.ipynb\",\n        parameters={\"message\": \"Airflow wrote this\"},\n    )\n\n    inspect_notebook(run_notebook.output)\n```\n\nThe upstream example passes `run_notebook.output` to the next task and reads `output.url` inside the task body.\n\n## Use A Remote Jupyter Kernel\n\nIf the notebook should run against a remote Jupyter kernel instead of the default local kernel, configure an Airflow connection of type `jupyter_kernel` and pass its connection id to `kernel_conn_id`.\n\nMinimal environment-variable form:\n\n```bash\nexport AIRFLOW_CONN_JUPYTER_KERNEL_DEFAULT='{\n  \"conn_type\": \"jupyter_kernel\",\n  \"host\": \"remote-jupyter.example.com\",\n  \"extra\": {\n    \"kernel_shell_port\": 57575,\n    \"kernel_iopub_port\": 40885,\n    \"kernel_stdin_port\": 52597,\n    \"kernel_control_port\": 50160,\n    \"kernel_hb_port\": 42540,\n    \"session_key\": \"session\"\n  }\n}'\n```\n\nThen reference that connection from the operator:\n\n```python\nrun_remote_notebook = PapermillOperator(\n    task_id=\"run_remote_notebook\",\n    input_nb=\"/opt/airflow/dags/notebooks/input.ipynb\",\n    output_nb=\"/opt/airflow/dags/notebooks/output-remote.ipynb\",\n    parameters={\"message\": \"Run on a remote kernel\"},\n    kernel_conn_id=\"jupyter_kernel_default\",\n)\n```\n\nThe connection docs define these fields:\n\n- `host`: hostname for the remote kernel\n- `kernel_shell_port`\n- `kernel_iopub_port`\n- `kernel_stdin_port`\n- `kernel_control_port`\n- `kernel_hb_port`\n- `session_key`\n\n## Common Pitfalls\n\n- Install the provider anywhere Airflow imports DAG code or executes tasks. A single missing scheduler or worker image is enough to cause import failures.\n- Keep input and output notebook paths on storage Airflow can access. The provider docs only document local files, S3, GCS, and Azure Blob Storage.\n- Use a `parameters` cell if the notebook depends on injected values landing in a predictable place.\n- Remote-kernel execution is not automatic. You need a `jupyter_kernel` Airflow connection and must pass `kernel_conn_id`.\n- The provider extends Airflow; it does not replace notebook-specific libraries in a normal Python application outside Airflow.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-papermill/stable/`\n- Operator guide and examples: `https://airflow.apache.org/docs/apache-airflow-providers-papermill/stable/operators.html`\n- `PapermillOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-papermill/stable/_api/airflow/providers/papermill/operators/papermill/index.html`\n- Jupyter kernel connection reference: `https://airflow.apache.org/docs/apache-airflow-providers-papermill/stable/connections/jupyter_kernel.html`\n- PyPI package metadata: `https://pypi.org/project/apache-airflow-providers-papermill/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-pinecone/python/DOC.md",
    "content": "---\nname: providers-pinecone\ndescription: \"Apache Airflow Pinecone provider for creating indexes, ingesting vectors, and querying Pinecone from Airflow DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,pinecone,vector-database,embeddings,dag,python\"\n---\n\n# apache-airflow-providers-pinecone\n\nUse `apache-airflow-providers-pinecone` when an Airflow DAG needs an Airflow-managed Pinecone connection plus provider operators and hooks for index creation, vector ingest, and query-time lookups.\n\nThis guide targets provider version `2.4.2`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment.\n\nIf Airflow is already installed, pin the existing Airflow version in the same command so the resolver does not silently replace core:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-pinecone==2.4.2\"\n```\n\nThe PyPI metadata for `2.4.2` lists these key requirements:\n\n- `apache-airflow>=2.11.0`\n- `pinecone>=7.0.0`\n- Python `>=3.10`\n\nInstall the provider anywhere DAG code can import it: scheduler, webserver, workers, and any separate task runtime image.\n\n## Configure The Airflow Connection\n\nThe provider uses the Airflow connection type `pinecone`. The default connection id is `pinecone_default`.\n\nConnection fields exposed by the provider:\n\n- `Host`: optional Pinecone host for a specific index\n- `Login`: Pinecone environment, used for pod-based indexes\n- `Password`: Pinecone API key\n- `Extra.region`: serverless region\n- `Extra.project_id`: optional project id\n- `Extra.debug_curl`: optional Pinecone client debug flag\n\nYou can create the connection in the Airflow UI, or define it with an environment variable. A practical serverless setup is:\n\n```bash\nexport AIRFLOW_CONN_PINECONE_DEFAULT='{\"conn_type\":\"pinecone\",\"password\":\"pcsk_your_api_key\",\"extra\":{\"region\":\"us-west-2\"}}'\n```\n\nFor pod-based indexes, also set the Pinecone environment in the connection:\n\n```bash\nexport AIRFLOW_CONN_PINECONE_DEFAULT='{\"conn_type\":\"pinecone\",\"login\":\"us-east1-gcp\",\"password\":\"pcsk_your_api_key\"}'\n```\n\nIf Pinecone gave you a per-index host and you want the hook to reuse it, include `host`:\n\n```bash\nexport AIRFLOW_CONN_PINECONE_DEFAULT='{\"conn_type\":\"pinecone\",\"host\":\"https://docs-demo-xxxx.svc.us-west2-aws.pinecone.io\",\"password\":\"pcsk_your_api_key\",\"extra\":{\"region\":\"us-west-2\"}}'\n```\n\nKeep API keys in Airflow Connections, environment variables, or a secrets backend instead of hard-coding them in DAG files.\n\n## Create A Serverless Index\n\nUse `CreateServerlessIndexOperator` when the DAG should create a Pinecone serverless index as a task.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.pinecone.operators.pinecone import CreateServerlessIndexOperator\n\nwith DAG(\n    dag_id=\"pinecone_create_serverless_index\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_index = CreateServerlessIndexOperator(\n        task_id=\"create_index\",\n        conn_id=\"pinecone_default\",\n        index_name=\"docs-demo\",\n        dimension=3,\n        metric=\"cosine\",\n        cloud=\"aws\",\n        region=\"us-west-2\",\n    )\n```\n\n`region` can come from the operator argument or the Airflow connection extra field.\n\n## Create A Pod-Based Index\n\nUse `CreatePodIndexOperator` when you need Pinecone's pod-based index flow instead of serverless.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.pinecone.operators.pinecone import CreatePodIndexOperator\n\nwith DAG(\n    dag_id=\"pinecone_create_pod_index\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_index = CreatePodIndexOperator(\n        task_id=\"create_index\",\n        conn_id=\"pinecone_default\",\n        index_name=\"docs-pod-demo\",\n        dimension=3,\n        metric=\"cosine\",\n        environment=\"us-east1-gcp\",\n        pods=1,\n        replicas=1,\n        shards=1,\n        pod_type=\"p1.x1\",\n    )\n```\n\nFor pod-based indexes, `environment` can come from the operator argument or the connection `Login` field.\n\n## Ingest Vectors From A DAG\n\nUse `PineconeIngestOperator` to upsert vectors into an index from a normal Airflow task.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.pinecone.operators.pinecone import (\n    CreateServerlessIndexOperator,\n    PineconeIngestOperator,\n)\n\nwith DAG(\n    dag_id=\"pinecone_ingest_vectors\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_index = CreateServerlessIndexOperator(\n        task_id=\"create_index\",\n        conn_id=\"pinecone_default\",\n        index_name=\"docs-demo\",\n        dimension=3,\n        metric=\"cosine\",\n        cloud=\"aws\",\n        region=\"us-west-2\",\n    )\n\n    ingest_vectors = PineconeIngestOperator(\n        task_id=\"ingest_vectors\",\n        conn_id=\"pinecone_default\",\n        index_name=\"docs-demo\",\n        namespace=\"docs\",\n        input_vectors=[\n            (\"doc-1\", [0.1, 0.2, 0.3], {\"source\": \"faq\"}),\n            (\"doc-2\", [0.3, 0.2, 0.1], {\"source\": \"guide\"}),\n        ],\n        batch_size=100,\n    )\n\n    create_index >> ingest_vectors\n```\n\n`input_vectors` matches the provider API: each item is an id, a numeric vector, and optional metadata.\n\n## Query And Inspect An Index With `PineconeHook`\n\nUse `PineconeHook` inside a Python task when you need methods that do not have their own operator, such as list, query, stats, collections, or delete operations.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.pinecone.hooks.pinecone import PineconeHook\n\nwith DAG(\n    dag_id=\"pinecone_query_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def query_index() -> None:\n        hook = PineconeHook(conn_id=\"pinecone_default\")\n\n        print(hook.list_indexes())\n\n        stats = hook.describe_index_stats(index_name=\"docs-demo\")\n        print(stats)\n\n        result = hook.query_vector(\n            index_name=\"docs-demo\",\n            vector=[0.1, 0.2, 0.3],\n            namespace=\"docs\",\n            top_k=2,\n            include_metadata=True,\n        )\n        print(result)\n\n    query_index()\n```\n\nOther hook methods documented in the provider source include:\n\n- `describe_index(...)`\n- `delete_index(...)`\n- `create_collection(...)`\n- `describe_collection(...)`\n- `delete_collection(...)`\n\nUse the hook when the DAG needs Python control flow around Pinecone calls. Use the provider operators when the Pinecone action should be a first-class Airflow task in the graph.\n\n## Common Patterns\n\n- Keep the Airflow connection id stable across DAGs, for example `pinecone_default` or `pinecone_prod`.\n- Put API keys and region or environment settings in the Airflow connection so DAG code only passes `conn_id`.\n- Use `CreateServerlessIndexOperator` or `CreatePodIndexOperator` for index provisioning, `PineconeIngestOperator` for upserts, and `PineconeHook` for query-time logic.\n\n## Pitfalls\n\n- This package extends Airflow; it does not replace `apache-airflow` or the underlying Pinecone Python client.\n- Install the provider everywhere DAG code runs. A successful import on the scheduler does not mean workers have the package.\n- Serverless index creation needs a region. Set it in `CreateServerlessIndexOperator(..., region=...)` or in the connection extra.\n- Pod-based index creation needs a Pinecone environment. Set it in `CreatePodIndexOperator(..., environment=...)` or in the connection `Login` field.\n- Keep credentials in Airflow Connections or a secrets backend. Do not embed API keys in DAG source files.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-pinecone` version `2.4.2`.\n- The provider docs page for `2.4.2` is the current stable maintainer reference as of `2026-03-13`.\n- If you upgrade the provider, re-check the package dependencies and the operator and hook API reference before rolling the change across Airflow images.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-pinecone/stable/`\n- Pinecone connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-pinecone/stable/connections/pinecone.html`\n- Pinecone operators guide: `https://airflow.apache.org/docs/apache-airflow-providers-pinecone/stable/operators/index.html`\n- `PineconeHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-pinecone/stable/_api/airflow/providers/pinecone/hooks/pinecone/index.html`\n- `PineconeHook` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-pinecone/stable/_modules/airflow/providers/pinecone/hooks/pinecone.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-pinecone/2.4.2/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-plexus/python/DOC.md",
    "content": "---\nname: providers-plexus\ndescription: \"Apache Airflow provider for authenticating to Plexus with Airflow Variables and submitting Plexus jobs from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,plexus,hooks,operators,dags\"\n---\n\n# Apache Airflow Plexus Provider Guide\n\nUse `apache-airflow-providers-plexus` when an Airflow DAG needs to authenticate to Plexus and submit a Plexus job through the provider's built-in hook and operator.\n\nThis guide covers provider version `3.4.1`.\n\n## Golden Rule\n\n- Treat this as an Airflow 2 provider, not a standalone Plexus SDK. Upstream documents `apache-airflow>=2.6.0` as the minimum supported Airflow version.\n- Configure Plexus credentials as Airflow Variables named `email` and `password`. The official hook does not read an Airflow Connection.\n- Use `PlexusJobOperator` for normal job submission. It resolves the Plexus app id, queue id, and billing account id for you before it calls the Plexus API.\n- Plan conservatively: upstream marks `3.4.1` as removed and no longer maintained by the Airflow community.\n\n## What This Package Adds\n\nThis provider is small. The public integration surface is:\n\n- `airflow.providers.plexus.hooks.plexus.PlexusHook`\n- `airflow.providers.plexus.operators.job.PlexusJobOperator`\n\nThe hook:\n\n- reads `Variable.get(\"email\")` and `Variable.get(\"password\")`\n- authenticates against `https://apiplexus.corescientific.com/sso/jwt-token/`\n- caches the JWT and exposes it through `hook.token`\n\nThe operator:\n\n- accepts a `job_params` dict\n- looks up `app` by app `name`\n- looks up `queue` by queue `public_name`\n- looks up the first billing account for the authenticated user\n- submits the job to `https://apiplexus.corescientific.com/jobs/`\n\n## Install\n\nInstall the provider into the same environment as your Airflow scheduler and workers. Upstream says this package installs on top of an existing Airflow 2 installation and requires Airflow `>=2.6.0`.\n\nUse a virtual environment and keep `apache-airflow` pinned when adding the provider:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-2.x-version>\"\nPROVIDER_VERSION=\"3.4.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-plexus==${PROVIDER_VERSION}\"\n```\n\nPyPI lists Python `3.8` through `3.11` for `apache-airflow-providers-plexus==3.4.1`.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i plexus\npython -c \"from airflow.providers.plexus.operators.job import PlexusJobOperator; print(PlexusJobOperator.__name__)\"\n```\n\n## Configure Credentials\n\nThe hook requires two Airflow Variables:\n\n```bash\nexport AIRFLOW_VAR_EMAIL=\"user@example.com\"\nexport AIRFLOW_VAR_PASSWORD=\"your-plexus-password\"\n```\n\nThose environment variables become Airflow Variables named `email` and `password`.\n\nIf you prefer to create them inside Airflow instead of through environment variables:\n\n```bash\nairflow variables set email \"user@example.com\"\nairflow variables set password \"your-plexus-password\"\n```\n\nImportant behavior from the official hook:\n\n- the Plexus API host is fixed to `https://apiplexus.corescientific.com/`\n- missing credentials raise `AirflowException(\"No valid email/password supplied.\")`\n- there is no `plexus_conn_id` parameter and no Airflow connection type for this provider\n\n## Submit A Plexus Job\n\n`PlexusJobOperator` is the main workflow this package supports.\n\nRequired `job_params` keys:\n\n- `name`\n- `app`\n- `queue`\n- `num_nodes`\n- `num_cores`\n\nMinimal DAG example:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.plexus.operators.job import PlexusJobOperator\n\n\nwith DAG(\n    dag_id=\"plexus_submit_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"plexus\"],\n) as dag:\n    submit_job = PlexusJobOperator(\n        task_id=\"submit_job\",\n        job_params={\n            \"name\": \"airflow-plexus-demo\",\n            \"app\": \"my-plexus-app\",\n            \"queue\": \"my-public-cluster\",\n            \"num_nodes\": 1,\n            \"num_cores\": 4,\n        },\n    )\n```\n\nWhat the operator does for you:\n\n- authenticates with `PlexusHook()`\n- calls `GET /apps/` to map the human-readable app name to the Plexus app id\n- calls `GET /queues/` to map the public queue name to the queue id\n- calls `GET /users/{user_id}/billingaccounts/` and takes the first billing account id\n- calls `POST /jobs/` with the resolved job parameters\n- polls `GET /jobs/{job_id}/` every three seconds until the job reaches its terminal state\n\n## Inspect Apps Or Queues Before Submitting\n\nIf you need to confirm the exact Plexus app name or queue public name before wiring the operator into a DAG, create a small Python task with `PlexusHook`.\n\n```python\nfrom __future__ import annotations\n\nimport requests\n\nfrom airflow.decorators import task\nfrom airflow.providers.plexus.hooks.plexus import PlexusHook\n\n\n@task\ndef list_plexus_apps() -> list[str]:\n    hook = PlexusHook()\n    response = requests.get(\n        f\"{hook.host}apps/\",\n        headers={\"Authorization\": f\"Bearer {hook.token}\"},\n        timeout=5,\n    )\n    response.raise_for_status()\n    return [item[\"name\"] for item in response.json()[\"results\"]]\n```\n\nThe same pattern works for queues:\n\n```python\nresponse = requests.get(\n    f\"{hook.host}queues/\",\n    headers={\"Authorization\": f\"Bearer {hook.token}\"},\n    timeout=5,\n)\nresponse.raise_for_status()\nqueue_names = [item[\"public_name\"] for item in response.json()[\"results\"]]\n```\n\nUse this for diagnostics and discovery. Use `PlexusJobOperator` for actual job submission so the provider handles the lookup and polling flow consistently.\n\n## Runtime Behavior And Pitfalls\n\n- `app` must match the Plexus app `name`, not an id.\n- `queue` must match the Plexus queue `public_name`, not an id.\n- The operator does not let you choose a billing account explicitly. It requests `/users/{user_id}/billingaccounts/` and uses the first result.\n- If the app lookup fails or the queue lookup fails, the operator raises an `AirflowException`.\n- If the job ever moves to `Cancelled` or `Failed`, the operator raises an `AirflowException`.\n- Service apps and batch apps finish differently. For service apps, the operator waits for `Running` when `expected_runtime` is not set, and waits for `Finished` when `expected_runtime` is set. For non-service apps, it waits for `Completed`.\n- Every request uses a five-second HTTP timeout in the provider code, so transient API latency can surface as task failures.\n\n## Operational Checks\n\nCheck that Airflow can import the provider and that your DAG parses:\n\n```bash\nairflow dags list | grep plexus\nairflow tasks test plexus_submit_demo submit_job 2026-03-13\n```\n\nWhen task execution fails early, verify these first:\n\n- `AIRFLOW_VAR_EMAIL` and `AIRFLOW_VAR_PASSWORD` are set where the worker runs\n- the `app` value matches a Plexus app name exactly\n- the `queue` value matches a Plexus queue public name exactly\n- the Airflow environment is still on a compatible Python and Airflow 2 version\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-plexus==3.4.1`.\n- Upstream marks `3.4.1` as the release where the Plexus provider was scheduled for removal and states that it is no longer maintained by the Airflow community.\n- The provider documentation says the minimum supported Airflow version is `2.6.0`.\n- The PyPI metadata for `3.4.1` lists Python `3.8`, `3.9`, `3.10`, and `3.11`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-plexus/stable/`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-plexus/stable/changelog.html`\n- Hook source docs: `https://airflow.apache.org/docs/apache-airflow-providers-plexus/stable/_modules/airflow/providers/plexus/hooks/plexus.html`\n- Operator source docs: `https://airflow.apache.org/docs/apache-airflow-providers-plexus/stable/_modules/airflow/providers/plexus/operators/job.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI package: `https://pypi.org/project/apache-airflow-providers-plexus/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-postgres/python/DOC.md",
    "content": "---\nname: providers-postgres\ndescription: \"Apache Airflow PostgreSQL provider for Airflow connections, SQL tasks, and Postgres hook-based workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,postgres,postgresql,sql,dag,python\"\n---\n\n# apache-airflow-providers-postgres\n\nUse `apache-airflow-providers-postgres` to connect Airflow to PostgreSQL through an Airflow connection, run SQL in DAG tasks, and access PostgreSQL from Python tasks with `PostgresHook`.\n\nThis guide targets provider version `6.6.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npip install apache-airflow-providers-postgres==6.6.0\n```\n\nIn practice, that means the scheduler, webserver, and workers must all have the provider available anywhere DAG code imports it.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `Postgres`.\n\nYou can create it in the Airflow UI, or define it with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_ANALYTICS_DB='postgresql://airflow:secret@db.example.com:5432/analytics'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `analytics_db`\n- SQL operators use `conn_id=\"analytics_db\"`\n- `PostgresHook` uses `postgres_conn_id=\"analytics_db\"`\n\nConnection fields you usually need:\n\n- `Host`: PostgreSQL host name\n- `Schema`: database name\n- `Login`: database user\n- `Password`: database password\n- `Port`: usually `5432`\n\nUse Airflow connections or a secrets backend for credentials instead of hard-coding database URLs in DAG files.\n\n## Run SQL In A DAG\n\nFor normal DDL and DML tasks, use Airflow's SQL operator with a Postgres connection.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"postgres_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"analytics_db\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id BIGSERIAL PRIMARY KEY,\n            event_type TEXT NOT NULL,\n            created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"analytics_db\",\n        sql=\"\"\"\n        INSERT INTO events (event_type)\n        VALUES ('signup'), ('purchase')\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need custom Python logic around the query.\n\n## Query Postgres From Python Tasks\n\nUse `PostgresHook` when you need to fetch rows, branch on results, or mix database work with Python code.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.postgres.hooks.postgres import PostgresHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"postgres_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> None:\n        hook = PostgresHook(postgres_conn_id=\"analytics_db\")\n\n        row = hook.get_first(\n            \"SELECT COUNT(*) FROM events WHERE created_at >= NOW() - INTERVAL '1 day'\"\n        )\n        event_count = row[0] if row else 0\n\n        records = hook.get_records(\n            \"SELECT event_type, COUNT(*) FROM events GROUP BY event_type ORDER BY event_type\"\n        )\n\n        print(f\"events in last day: {event_count}\")\n        for event_type, count in records:\n            print(f\"{event_type}: {count}\")\n\n    read_summary()\n```\n\nUseful hook methods for everyday tasks:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying database connection\n\n## Load Data With `COPY`\n\n`PostgresHook.copy_expert(...)` is the practical way to use PostgreSQL `COPY` from an Airflow task.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.postgres.hooks.postgres import PostgresHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"postgres_copy_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def load_csv() -> None:\n        hook = PostgresHook(postgres_conn_id=\"analytics_db\")\n\n        hook.run(\n            \"\"\"\n            CREATE TABLE IF NOT EXISTS staging_users (\n                id BIGINT,\n                email TEXT\n            )\n            \"\"\"\n        )\n\n        hook.copy_expert(\n            sql=\"\"\"\n            COPY staging_users (id, email)\n            FROM STDIN WITH (FORMAT CSV, HEADER TRUE)\n            \"\"\",\n            filename=\"/opt/airflow/dags/data/users.csv\",\n        )\n\n    load_csv()\n```\n\nThe file path is resolved on the Airflow worker that runs the task. If you use Celery, Kubernetes, or another distributed executor, make sure that file exists inside the worker runtime, not just on your local machine.\n\n## Common Setup Pattern\n\nFor many DAGs, a clean split is:\n\n- use `SQLExecuteQueryOperator` for schema setup, inserts, updates, and idempotent SQL tasks\n- use `PostgresHook` inside `@task` functions when later steps need query results in Python\n- keep the connection id stable across DAGs, such as `analytics_db` or `warehouse`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the provider package.\n- Keep credentials in Airflow connections or secrets backends. Do not embed usernames and passwords directly in DAG code.\n- URL-encode special characters in connection URIs if you define `AIRFLOW_CONN_*` variables manually.\n- Use worker-accessible paths with `copy_expert(...)`. A path that exists on your laptop may not exist in a container or remote worker.\n- Use `PostgresHook` for Python-driven logic and `SQLExecuteQueryOperator` for plain SQL tasks. That keeps DAGs simpler and easier to reason about.\n\n## Version Notes\n\nProvider packages track Airflow compatibility separately from PostgreSQL server compatibility. If you are upgrading Airflow core, check the provider's release notes and compatibility information before pinning or upgrading this package in production.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-postgres/stable/`\n- Airflow Postgres connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-postgres/stable/connections/postgres.html`\n- `PostgresHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-postgres/stable/_api/airflow/providers/postgres/hooks/postgres/index.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-presto/python/DOC.md",
    "content": "---\nname: providers-presto\ndescription: \"Apache Airflow Presto provider for Presto connections, SQL tasks, and hook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,presto,sql,dag,python\"\n---\n\n# apache-airflow-providers-presto\n\nUse `apache-airflow-providers-presto` when an Airflow DAG needs to run Presto SQL through an Airflow connection or access Presto from Python task code with `PrestoHook`.\n\nThis package is an Airflow provider, not a standalone Presto client for regular Python applications.\n\nThis guide targets provider version `5.11.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as `apache-airflow`. In practice, the scheduler, webserver, and every worker that imports DAG code must all have the provider available.\n\nPin Airflow and the provider together, and use the Airflow constraints file for your Airflow version:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.11.0\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-presto==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf you add the provider later, keep `apache-airflow` pinned in the same install command so `pip` does not silently move core Airflow to another version.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `Presto`.\n\nYou can create it in the Airflow UI, or define it with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_PRESTO_ANALYTICS='{\"conn_type\":\"presto\",\"host\":\"presto.example.com\",\"port\":8443,\"login\":\"airflow\",\"password\":\"secret\",\"schema\":\"analytics\",\"extra\":{\"catalog\":\"hive\",\"protocol\":\"https\",\"session_props\":{\"query_max_run_time\":\"5m\"}}}'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `presto_analytics`\n- `SQLExecuteQueryOperator` uses `conn_id=\"presto_analytics\"`\n- `PrestoHook` uses `presto_conn_id=\"presto_analytics\"`\n\nConnection fields you usually need:\n\n- `Host`: Presto coordinator host name\n- `Login`: user name sent to Presto\n- `Password`: password when your cluster requires basic auth\n- `Port`: coordinator port, typically `8080` or `8443`\n- `Schema`: default schema for unqualified table names\n- `Extra.catalog`: default catalog, such as `hive`\n- `Extra.protocol`: `http` or `https`\n\nUseful connection extras documented by the provider include:\n\n- `catalog`\n- `protocol`\n- `requests_kwargs`\n- `session_props`\n- JWT auth fields such as `jwt__file` or `jwt__token`\n- Kerberos fields such as `kerberos__config` and `kerberos__service_name`\n\nKeep auth and cluster-specific settings in Airflow connections or your secrets backend instead of hard-coding them in DAG files.\n\n## Run SQL In A DAG\n\nFor normal SQL tasks, use Airflow's common SQL operator with the Presto connection.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"presto_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"presto_analytics\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS hive.analytics.daily_counts (\n            ds DATE,\n            row_count BIGINT\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"presto_analytics\",\n        sql=\"\"\"\n        INSERT INTO hive.analytics.daily_counts\n        SELECT current_date, COUNT(*)\n        FROM hive.analytics.events\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need custom Python logic around the query.\n\n## Query Presto From Python Tasks\n\nUse `PrestoHook` when task code needs cursor-level access from Python.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.presto.hooks.presto import PrestoHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"presto_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_recent_orders() -> None:\n        hook = PrestoHook(presto_conn_id=\"presto_analytics\")\n        conn = hook.get_conn()\n        cursor = conn.cursor()\n\n        cursor.execute(\n            \"\"\"\n            SELECT order_id, total_amount\n            FROM hive.analytics.orders\n            ORDER BY created_at DESC\n            LIMIT 10\n            \"\"\"\n        )\n\n        for order_id, total_amount in cursor.fetchall():\n            print(order_id, total_amount)\n\n    read_recent_orders()\n```\n\n`get_conn()` returns a DB-API style connection backed by the Presto Python client, so standard cursor methods like `execute()` and `fetchall()` work as expected.\n\n## Insert Rows From Python\n\n`PrestoHook.insert_rows(...)` is the provider's write helper when a Python task already has rows prepared.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.presto.hooks.presto import PrestoHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"presto_insert_rows_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def write_audit_rows() -> None:\n        hook = PrestoHook(presto_conn_id=\"presto_analytics\")\n        hook.insert_rows(\n            table=\"task_audit\",\n            rows=[\n                (\"presto_insert_rows_example\", \"success\"),\n                (\"presto_insert_rows_example\", \"complete\"),\n            ],\n            target_fields=[\"dag_id\", \"status\"],\n            commit_every=1000,\n        )\n\n    write_audit_rows()\n```\n\nUse unqualified table names only when your connection's `schema` and `extra.catalog` already point at the destination you want.\n\n## Important Notes\n\n- Install the provider everywhere DAG code runs. A missing worker image is enough to trigger `ModuleNotFoundError` at parse time or task runtime.\n- Set both the schema and the catalog correctly. In this provider, the catalog lives in connection extras, not in the main schema field.\n- Keep coordinator URLs, credentials, JWT files, and Kerberos settings in Airflow connections or a secrets backend, not in DAG source files.\n- This provider is for Airflow DAGs. If you are writing a normal Python service outside Airflow, use a dedicated Presto client directly instead of importing Airflow hooks.\n\n## Version Notes\n\n- `PrestoHook.get_pandas_df(...)` was deprecated in the `5.10.0` line. Do not start new code with that helper.\n- `5.11.0` adds hook-level OpenLineage database info support and raises the minimum SQLAlchemy version for the provider's SQLAlchemy integration to `1.4.54`.\n\n## Official References\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-presto/stable/`\n- Presto connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-presto/stable/connections/presto.html`\n- Presto operators docs: `https://airflow.apache.org/docs/apache-airflow-providers-presto/stable/operators.html`\n- `PrestoHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-presto/stable/_api/airflow/providers/presto/hooks/presto/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-presto/stable/changelog.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-presto/5.11.0/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-qdrant/python/DOC.md",
    "content": "---\nname: providers-qdrant\ndescription: \"Apache Airflow Qdrant provider for configuring Qdrant connections, ingesting vectors, and using QdrantClient from DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,qdrant,vector-database,embeddings,python\"\n---\n\n# Apache Airflow Qdrant Provider Guide\n\nUse `apache-airflow-providers-qdrant` when an Airflow DAG needs to write vectors into Qdrant with `QdrantIngestOperator` or reuse an Airflow-managed Qdrant connection through `QdrantHook`.\n\n## Golden Rule\n\n- This package extends Airflow; it is not a standalone Qdrant SDK.\n- Put the Qdrant endpoint and API key on an Airflow `qdrant` connection, then let `QdrantHook` and `QdrantIngestOperator` resolve credentials from that connection.\n- Use `QdrantIngestOperator` for bulk vector uploads. Use `QdrantHook` when DAG code needs direct `QdrantClient` access for collection setup, querying, or other custom client calls.\n- Keep API keys in Airflow connections, environment variables, or a secrets backend instead of embedding them in DAG code.\n\n## What This Package Adds\n\nThe provider exposes two main entry points:\n\n- `airflow.providers.qdrant.hooks.qdrant.QdrantHook`\n- `airflow.providers.qdrant.operators.qdrant.QdrantIngestOperator`\n\n`QdrantHook.get_conn()` returns a `qdrant_client.QdrantClient`, so you can call the normal Qdrant Python client methods from inside Airflow tasks.\n\n## Install\n\nInstall the provider into the same Python environment as Airflow. Provider `1.5.3` requires:\n\n- `apache-airflow>=2.11.0`\n- `apache-airflow-providers-common-compat>=1.8.0`\n- `qdrant_client>=1.15.1,!=1.17.0`\n- Python `>=3.10`\n\nIf Airflow is already installed, pin your current Airflow version in the same command so the resolver does not silently replace core:\n\n```bash\nAIRFLOW_VERSION=\"3.1.8\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-qdrant==1.5.3\"\n```\n\nIf you are building a new environment from scratch, install Airflow first using the official constrained install flow for your Python version, then add this provider.\n\n## Configure A Qdrant Connection\n\nThe hook uses `qdrant_default` by default.\n\nQdrant connection fields supported by the provider:\n\n- `Host`: Qdrant host name\n- `Password`: Qdrant API key\n- `Port`: REST port, default `6333`\n- `extra.url`: full Qdrant URL; if set, it overrides `host` and `port`\n- `extra.grpc_port`: gRPC port, default `6334`\n- `extra.prefer_gprc`: whether to prefer gRPC for custom methods\n- `extra.https`: whether to use HTTPS\n- `extra.prefix`: path prefix added to REST endpoints\n\nThe most reliable environment-variable form is JSON:\n\n```bash\nexport AIRFLOW_CONN_QDRANT_DEFAULT='{\n  \"conn_type\": \"qdrant\",\n  \"host\": \"xyz-example.us-east.aws.cloud.qdrant.io\",\n  \"password\": \"your-qdrant-api-key\",\n  \"port\": 6333,\n  \"extra\": {\n    \"https\": true,\n    \"grpc_port\": 6334,\n    \"prefer_gprc\": false\n  }\n}'\n```\n\nIf you want the connection stored in the Airflow metadata database instead of an environment variable:\n\n```bash\nairflow connections add 'qdrant_default' \\\n  --conn-json '{\n    \"conn_type\": \"qdrant\",\n    \"host\": \"xyz-example.us-east.aws.cloud.qdrant.io\",\n    \"password\": \"your-qdrant-api-key\",\n    \"port\": 6333,\n    \"extra\": {\n      \"https\": true,\n      \"grpc_port\": 6334,\n      \"prefer_gprc\": false\n    }\n  }'\n```\n\nPractical notes:\n\n- Environment-variable connections work, but they do not show up in the Airflow UI.\n- If your deployment uses a single fully qualified endpoint, set `extra.url` and skip separate `host` and `port`.\n- The provider's extra key is spelled `prefer_gprc` in connection JSON and UI fields. The hook maps that field to the Qdrant client's `prefer_grpc` argument.\n\n## Test The Connection\n\nThe provider implements Airflow connection testing. Airflow disables test-connection support by default, so enable it first if you want UI or CLI checks:\n\n```bash\nexport AIRFLOW__CORE__TEST_CONNECTION=\"Enabled\"\nairflow connections test qdrant_default\n```\n\nBehind the scenes, the hook verifies the connection by calling `get_collections()` on the Qdrant client.\n\n## Ingest Vectors With `QdrantIngestOperator`\n\n`QdrantIngestOperator` is the provider's built-in task for bulk uploads. It passes your data to `QdrantClient.upload_collection(...)`.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.qdrant.operators.qdrant import QdrantIngestOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"qdrant_ingest_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"qdrant\"],\n) as dag:\n    ingest_vectors = QdrantIngestOperator(\n        task_id=\"ingest_vectors\",\n        conn_id=\"qdrant_default\",\n        collection_name=\"products\",\n        vectors=[\n            [0.732, 0.611, 0.289, 0.421],\n            [0.217, 0.526, 0.416, 0.981],\n            [0.326, 0.483, 0.376, 0.136],\n        ],\n        ids=[101, 102, 103],\n        payload=[\n            {\"sku\": \"sku-101\", \"category\": \"books\"},\n            {\"sku\": \"sku-102\", \"category\": \"games\"},\n            {\"sku\": \"sku-103\", \"category\": \"books\"},\n        ],\n        batch_size=64,\n        parallel=1,\n        max_retries=3,\n        wait=True,\n    )\n```\n\nWhat the operator controls:\n\n- `collection_name`: target collection\n- `vectors`: iterable of vectors to upload\n- `payload`: optional payload objects aligned with the vectors\n- `ids`: optional point ids; if you omit them, Qdrant can generate ids client-side\n- `batch_size`: upload chunk size, default `64`\n- `parallel`: number of parallel upload processes, default `1`\n- `method`: multiprocessing start method\n- `max_retries`: retry count for failed upload requests, default `3`\n- `wait`: wait for server-side application, default `True` in the operator\n\n## Use `QdrantHook` For Collection Setup And Queries\n\nUse the hook when you need the underlying Qdrant Python client in task code.\n\nExample: create a collection if it does not exist, then query it.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.qdrant.hooks.qdrant import QdrantHook\nfrom pendulum import datetime\nfrom qdrant_client import models\n\nwith DAG(\n    dag_id=\"qdrant_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"qdrant\"],\n) as dag:\n    @task\n    def ensure_collection() -> None:\n        client = QdrantHook(conn_id=\"qdrant_default\").get_conn()\n\n        if not client.collection_exists(\"products\"):\n            client.create_collection(\n                collection_name=\"products\",\n                vectors_config=models.VectorParams(\n                    size=4,\n                    distance=models.Distance.COSINE,\n                ),\n            )\n\n    @task\n    def query_collection() -> list[dict]:\n        client = QdrantHook(conn_id=\"qdrant_default\").get_conn()\n\n        hits = client.query_points(\n            collection_name=\"products\",\n            query=[0.73, 0.61, 0.29, 0.42],\n            query_filter=models.Filter(\n                must=[\n                    models.FieldCondition(\n                        key=\"category\",\n                        match=models.MatchValue(value=\"books\"),\n                    )\n                ]\n            ),\n            limit=3,\n            with_payload=True,\n        ).points\n\n        return [\n            {\"id\": point.id, \"score\": point.score, \"payload\": point.payload}\n            for point in hits\n        ]\n\n    ensure_collection() >> query_collection()\n```\n\nThis pattern is useful when the DAG needs to:\n\n- create or inspect collections\n- run a filtered similarity query\n- call other `QdrantClient` methods that do not have a dedicated Airflow operator\n\n## Common Pattern\n\nFor most Airflow + Qdrant DAGs, a clean split is:\n\n- use `QdrantHook` once for collection creation or one-off client operations\n- use `QdrantIngestOperator` for bulk uploads of vectors and payload\n- keep the same `conn_id` across related tasks, usually `qdrant_default`\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports or executes DAG code. Missing package errors usually mean one scheduler, worker, or image does not have `apache-airflow-providers-qdrant` installed.\n- `QdrantIngestOperator` uploads to an existing collection name. Create the collection first if your workflow needs explicit vector size and distance configuration.\n- The provider's connection extra key is `prefer_gprc`, not `prefer_grpc`. Use the provider's spelling in Airflow connection JSON.\n- Provider `1.5.3` explicitly excludes `qdrant_client==1.17.0`. Do not pin that client version alongside this provider release.\n- Airflow connection testing is disabled by default. If `airflow connections test qdrant_default` is unavailable, set `AIRFLOW__CORE__TEST_CONNECTION=\"Enabled\"` first.\n- Environment-variable connections are convenient for local development and containers, but they do not appear in the Airflow UI.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-qdrant` `1.5.3`, released on March 2, 2026.\n- Starting with provider `1.5.0`, the minimum supported Airflow version is `2.11.0`.\n- Test-connection support was added in provider `1.1.0`.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/index.html`\n- Qdrant connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/connections.html`\n- `QdrantHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/_api/airflow/providers/qdrant/hooks/qdrant/index.html`\n- `QdrantHook` source docs: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/_modules/airflow/providers/qdrant/hooks/qdrant.html`\n- `QdrantIngestOperator` guide: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/operators/qdrant.html`\n- `QdrantIngestOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/_api/airflow/providers/qdrant/operators/qdrant/index.html`\n- `QdrantIngestOperator` source docs: `https://airflow.apache.org/docs/apache-airflow-providers-qdrant/stable/_modules/airflow/providers/qdrant/operators/qdrant.html`\n- Airflow managing connections: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-qdrant/`\n- Qdrant Python client docs: `https://python-client.qdrant.tech/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-qubole/python/DOC.md",
    "content": "---\nname: providers-qubole\ndescription: \"Apache Airflow Qubole provider for running Qubole commands, checks, and sensors from Airflow DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,qubole,dag,operators,sensors,checks\"\n---\n\n# Apache Airflow Qubole Provider Guide\n\nUse `apache-airflow-providers-qubole` when an existing Airflow deployment needs to submit commands to Qubole, run simple result checks, or wait for Qubole-managed files and partitions.\n\n## Golden Rule\n\n- Treat this provider as a maintenance-time integration for Airflow 2 environments, not a new Airflow 3 authoring target.\n- Install it alongside `apache-airflow`; it is not a standalone Qubole SDK.\n- Put the Qubole API endpoint and auth token on an Airflow `qubole` connection, then keep DAG code focused on `command_type`, query or script arguments, and task flow.\n- Pin the provider version. Upstream marks `3.4.3` as the last release and says the provider is no longer being updated.\n\n## What This Package Adds\n\nThe provider documents these main entry points:\n\n- `QuboleOperator` for running Qubole commands\n- `QuboleCheckOperator` and `QuboleValueCheckOperator` for data-quality style checks\n- `QuboleFileSensor` and `QubolePartitionSensor` for waiting on files and Hive-style partitions\n- `QuboleHook` for lower-level access to Qubole commands from Python code\n\n## Install\n\nInstall the provider into the same Airflow environment used by your scheduler, webserver, and workers. The provider docs state that it requires Airflow `2.5.0` or newer.\n\nUse the Airflow constraints file that matches your Airflow version:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-2.x-version>\"\nPROVIDER_VERSION=\"3.4.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-qubole==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful check after installation:\n\n```bash\nairflow providers list | grep -i qubole\n```\n\n## Configure The Airflow Connection\n\nThe provider's connection type is `qubole`. In the connection form, upstream maps:\n\n- `Host` to the Qubole API endpoint\n- `Password` to the Qubole auth token\n\nA practical environment-variable setup is:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\nexport AIRFLOW_CONN_QUBOLE_DEFAULT='{\n  \"conn_type\": \"qubole\",\n  \"host\": \"https://api.qubole.com/api\",\n  \"password\": \"your-qubole-api-token\"\n}'\n```\n\nWith that environment variable:\n\n- the Airflow connection id is `qubole_default`\n- `QuboleOperator` uses `qubole_conn_id=\"qubole_default\"` by default\n- DAG code does not need to embed the endpoint or token directly\n\nIf you create the connection in the Airflow UI instead, use connection type `qubole` and put the same values in `Host` and `Password`.\n\n## Run A Qubole Command With `QuboleOperator`\n\nUse `QuboleOperator` when the task should submit a Qubole command and wait for it to finish.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.qubole.operators.qubole import QuboleOperator\n\nwith DAG(\n    dag_id=\"qubole_hive_query\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_daily_summary = QuboleOperator(\n        task_id=\"run_daily_summary\",\n        qubole_conn_id=\"qubole_default\",\n        command_type=\"hivecmd\",\n        query=\"\"\"\n        SELECT dt, COUNT(*) AS row_count\n        FROM analytics.events\n        WHERE dt = '{{ ds }}'\n        GROUP BY dt\n        \"\"\",\n        cluster_label=\"{{ var.value.qubole_cluster_label }}\",\n        fetch_logs=True,\n    )\n```\n\nCommon command arguments from the provider docs:\n\n- `command_type` selects the Qubole command family such as `hivecmd`, `presto`, or `sparkcmd`\n- `query` sends inline SQL\n- `script_location` points to a script stored in Qubole-accessible storage\n- `cluster_label` selects the Qubole cluster label\n- `fetch_logs=True` streams Qubole logs back into the Airflow task logs\n\nIf the query body is large, the operator supports templated `.txt` files as well as inline strings.\n\n## Run Checks With `QuboleCheckOperator` And `QuboleValueCheckOperator`\n\nUse the check operators when a DAG should fail fast on an unexpected query result.\n\n`QuboleCheckOperator` expects a truthy first row:\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.qubole.operators.qubole_check import QuboleCheckOperator\n\nwith DAG(\n    dag_id=\"qubole_check_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    row_count_present = QuboleCheckOperator(\n        task_id=\"row_count_present\",\n        qubole_conn_id=\"qubole_default\",\n        command_type=\"hivecmd\",\n        query=\"SELECT COUNT(*) > 0 FROM analytics.events WHERE dt = '{{ ds }}'\",\n    )\n```\n\n`QuboleValueCheckOperator` compares a scalar result with an expected value:\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.qubole.operators.qubole_check import QuboleValueCheckOperator\n\nwith DAG(\n    dag_id=\"qubole_value_check_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    expected_partition_count = QuboleValueCheckOperator(\n        task_id=\"expected_partition_count\",\n        qubole_conn_id=\"qubole_default\",\n        command_type=\"hivecmd\",\n        query=\"SELECT COUNT(*) FROM analytics.events WHERE dt = '{{ ds }}'\",\n        pass_value=1,\n        tolerance=0,\n    )\n```\n\n## Wait For Files Or Partitions\n\nUse the provider sensors when downstream tasks should not run until a Qubole-managed artifact exists.\n\n```python\nfrom datetime import datetime\n\nfrom airflow import DAG\nfrom airflow.providers.qubole.sensors.qubole import (\n    QuboleFileSensor,\n    QubolePartitionSensor,\n)\n\nwith DAG(\n    dag_id=\"qubole_sensor_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    wait_for_export = QuboleFileSensor(\n        task_id=\"wait_for_export\",\n        qubole_conn_id=\"qubole_default\",\n        location=\"s3://analytics-exports/events/dt={{ ds }}/\",\n    )\n\n    wait_for_partition = QubolePartitionSensor(\n        task_id=\"wait_for_partition\",\n        qubole_conn_id=\"qubole_default\",\n        table=\"analytics.events\",\n        ds=\"dt='{{ ds }}'\",\n    )\n\n    wait_for_export >> wait_for_partition\n```\n\n## Use `QuboleHook` In Python Code\n\nReach for `QuboleHook` only when a task needs lower-level access than the operators provide.\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.qubole.hooks.qubole import QuboleHook\n\n@task\ndef submit_with_hook() -> None:\n    hook = QuboleHook(\n        command_type=\"hivecmd\",\n        qubole_conn_id=\"qubole_default\",\n        query=\"SELECT 1\",\n    )\n    hook.execute(context={})\n```\n\nFor most DAGs, start with `QuboleOperator` instead. It is the simpler and better-documented path.\n\n## Pitfalls\n\n- `3.4.3` is the provider's final release. Upstream says the package has been removed and will not be updated anymore, so pin the version instead of expecting forward fixes.\n- This provider is documented against Airflow 2. Its examples and imports use `from airflow import DAG`, not the Airflow 3 public authoring API in `airflow.sdk`.\n- Install the provider everywhere DAG code is imported or executed. Scheduler-only installation is not enough.\n- The documented connection fields are unusual: `Host` is the Qubole API endpoint and `Password` is the auth token.\n- The operator's default failure and retry handlers cancel the running Qubole command. Override that behavior only if you intentionally want Qubole work to keep running after Airflow marks the task failed or retrying.\n- Keep tokens out of DAG files. Use Airflow connections, variables, or a secrets backend instead of literal credentials in Python source.\n\n## Version Notes\n\n- This guide targets `apache-airflow-providers-qubole` version `3.4.3`.\n- The provider changelog marks `3.4.3` as the last release.\n- The `3.4.1` release dropped Python 3.7 support, so older Airflow images pinned to Python 3.7 need both a Python upgrade and an older provider version.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/`\n- Installation and package metadata: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/index.html`\n- Qubole connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/connections/qubole.html`\n- Operators and sensors overview: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/operators.html`\n- `QuboleHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/_api/airflow/providers/qubole/hooks/qubole/index.html`\n- Sensor API reference: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/_api/airflow/providers/qubole/sensors/qubole/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-qubole/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-qubole/3.4.3/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-redis/python/DOC.md",
    "content": "---\nname: providers-redis\ndescription: \"Apache Airflow Redis provider for Redis connections, hook-based tasks, and publish operations from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,redis,apache-airflow,python,dag,hooks,pubsub\"\n---\n\n# Apache Airflow Redis Provider Guide\n\nUse `apache-airflow-providers-redis` when an Airflow DAG needs to connect to Redis through an Airflow connection, run Redis commands from Python task code, or publish messages to a Redis channel.\n\n## Golden Rule\n\n- Install this provider alongside `apache-airflow`; it is not a standalone Redis client or worker runtime.\n- Put Redis host, port, password, and database selection on an Airflow connection, then keep DAG code focused on keys, channels, and task logic.\n- Use `RedisHook` when task code needs direct Redis commands, and use `RedisPublishOperator` when the task is simply “publish this message to this channel”.\n- Keep credentials in Airflow connections or a secrets backend instead of hard-coding them in DAG files.\n\n## What This Package Adds\n\nThis provider supplies Airflow's Redis integration, including:\n\n- `RedisHook`\n- `RedisPublishOperator`\n\nThese are the main entry points most DAGs use from this package.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment. Follow Airflow's normal provider-install pattern and keep Airflow pinned in the same command so `pip` does not silently move core to an incompatible version.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.4.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-redis==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful check after installation:\n\n```bash\nairflow providers list | grep -i redis\n```\n\nIn practice, every Airflow image or environment that imports DAGs or runs tasks must have the provider installed.\n\n## Configure A Redis Connection\n\nCreate an Airflow connection with connection type `redis`, or define one with an environment variable.\n\n```bash\nexport AIRFLOW_CONN_REDIS_DEFAULT='redis://:secret@redis.example.com:6379/0'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `redis_default`\n- `RedisHook` uses `redis_conn_id=\"redis_default\"`\n- `RedisPublishOperator` uses `redis_conn_id=\"redis_default\"`\n\nPractical notes:\n\n- the `/0` path segment selects Redis database `0`\n- URL-encode special characters in passwords before putting them in `AIRFLOW_CONN_REDIS_DEFAULT`\n- if you prefer not to use the URI form, create the connection in the Airflow UI or CLI with the equivalent host, port, password, and database settings\n\nKeep Redis credentials in Airflow connections or a secrets backend instead of embedding them in task code.\n\n## Use `RedisHook` In A Task\n\nUse `RedisHook` when task code needs direct access to the Redis client.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.redis.hooks.redis import RedisHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"redis_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def write_and_read() -> str | None:\n        hook = RedisHook(redis_conn_id=\"redis_default\")\n        client = hook.get_conn()\n\n        if not client.ping():\n            raise RuntimeError(\"Redis is not reachable\")\n\n        client.set(\"airflow:demo:status\", \"ready\", ex=300)\n        value = client.get(\"airflow:demo:status\")\n\n        return value.decode(\"utf-8\") if value else None\n\n    write_and_read()\n```\n\nThe important pattern is:\n\n1. create `RedisHook(redis_conn_id=\"...\")`\n2. call `hook.get_conn()`\n3. use the returned Redis client for normal Redis commands such as `ping()`, `set()`, `get()`, `delete()`, and `publish()`\n\n## Publish A Message With `RedisPublishOperator`\n\nUse `RedisPublishOperator` when the task is just a channel publish and you do not need custom Python code around it.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.redis.operators.redis_publish import RedisPublishOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"redis_publish_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    publish_event = RedisPublishOperator(\n        task_id=\"publish_event\",\n        redis_conn_id=\"redis_default\",\n        channel=\"events\",\n        message='{\"type\": \"order.created\", \"id\": \"ord_123\"}',\n    )\n```\n\nThis is the simplest pattern for pub/sub notifications emitted from a DAG.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep Redis endpoint and credentials in an Airflow connection\n- create the Redis client inside a task with `RedisHook` when you need normal Redis commands\n- use `RedisPublishOperator` for one-step publish tasks\n- return only small derived values from tasks instead of large payloads or large key dumps\n\n## Pitfalls\n\n- Installing the provider only on the webserver or scheduler: workers also need it anywhere task code imports `airflow.providers.redis`.\n- Using the wrong connection parameter name: `RedisHook` and `RedisPublishOperator` use `redis_conn_id`.\n- Embedding passwords or hostnames directly in DAG code instead of using Airflow connections.\n- Forgetting to URL-encode reserved characters when you define `AIRFLOW_CONN_REDIS_DEFAULT` manually.\n- Assuming a connection that works from one Airflow container will also work from workers; make sure every runtime can actually reach the Redis endpoint.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-redis` version `4.4.2`.\n- If you upgrade the provider, recheck the provider docs and API reference before rolling the change across Airflow images.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-redis/stable/`\n- Redis connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-redis/stable/connections/redis.html`\n- `RedisHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-redis/stable/_api/airflow/providers/redis/hooks/redis/index.html`\n- `RedisPublishOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-redis/stable/_api/airflow/providers/redis/operators/redis_publish/index.html`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-redis/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-salesforce/python/DOC.md",
    "content": "---\nname: providers-salesforce\ndescription: \"Apache Airflow provider for configuring Salesforce connections and using SalesforceHook in DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.12.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,salesforce,soql,crm,hooks,dag\"\n---\n\n# Apache Airflow Salesforce Provider Guide\n\nUse `apache-airflow-providers-salesforce` when an Airflow DAG needs an Airflow-managed Salesforce connection and Python task code that runs SOQL or creates and updates Salesforce records without embedding credentials in the DAG file.\n\nThis guide covers provider version `5.12.2`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Salesforce SDK.\n- Put Salesforce credentials on an Airflow connection such as `salesforce_default`.\n- Use `SalesforceHook` inside tasks, then call `get_conn()` to get the authenticated Salesforce client.\n- Return small dicts, ids, or summaries from tasks instead of raw client objects or large query payloads.\n\n## What This Package Adds\n\nThis provider centers on Airflow's Salesforce integration:\n\n- Airflow connection type `salesforce`\n- `SalesforceHook`\n\nFor most DAGs, the pattern is simple: configure one Airflow Salesforce connection, create `SalesforceHook(salesforce_conn_id=\"...\")` inside the task body, call `get_conn()`, and use the returned Salesforce client for normal SOQL and sObject operations.\n\n## Install\n\nInstall the provider into the same environment as Airflow and keep both versions pinned. Airflow recommends installing providers with the constraints file for your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.12.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-salesforce==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i salesforce\nairflow info\n```\n\nEvery Airflow environment that parses DAGs or executes tasks that import `airflow.providers.salesforce` needs this provider installed.\n\n## Configure A Salesforce Connection\n\nThe practical setup is to keep the Salesforce username in the connection login, the password in the connection password, and the Salesforce security token plus login domain in connection extras.\n\nSet the values you want Airflow to store:\n\n```bash\nexport SALESFORCE_USERNAME=\"user@example.com\"\nexport SALESFORCE_PASSWORD=\"<salesforce-password>\"\nexport SALESFORCE_SECURITY_TOKEN=\"<salesforce-security-token>\"\nexport SALESFORCE_DOMAIN=\"login\"   # use test for a sandbox org\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'salesforce_default' \\\n  --conn-type 'salesforce' \\\n  --conn-login \"$SALESFORCE_USERNAME\" \\\n  --conn-password \"$SALESFORCE_PASSWORD\" \\\n  --conn-extra \"{\\\"security_token\\\":\\\"${SALESFORCE_SECURITY_TOKEN}\\\",\\\"domain\\\":\\\"${SALESFORCE_DOMAIN}\\\"}\"\n```\n\nYou can also provide the same connection through an environment variable:\n\n```bash\nexport AIRFLOW_CONN_SALESFORCE_DEFAULT='{\n  \"conn_type\": \"salesforce\",\n  \"login\": \"user@example.com\",\n  \"password\": \"<salesforce-password>\",\n  \"extra\": {\n    \"security_token\": \"<salesforce-security-token>\",\n    \"domain\": \"login\"\n  }\n}'\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get salesforce_default\n```\n\nKeep Salesforce secrets in Airflow connections, environment-backed secrets, or a secrets backend instead of putting them in DAG code.\n\n## Run A SOQL Query In A Task\n\nUse `SalesforceHook` when task code needs direct Python access to the authenticated Salesforce client.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.salesforce.hooks.salesforce import SalesforceHook\n\n\nwith DAG(\n    dag_id=\"salesforce_query_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"salesforce\"],\n):\n    @task()\n    def fetch_accounts() -> list[dict[str, str | None]]:\n        hook = SalesforceHook(salesforce_conn_id=\"salesforce_default\")\n        client = hook.get_conn()\n\n        result = client.query(\n            \"SELECT Id, Name, Type FROM Account ORDER BY LastModifiedDate DESC LIMIT 10\"\n        )\n\n        return [\n            {\n                \"id\": record[\"Id\"],\n                \"name\": record[\"Name\"],\n                \"type\": record.get(\"Type\"),\n            }\n            for record in result[\"records\"]\n        ]\n\n    fetch_accounts()\n```\n\nPractical points:\n\n- `salesforce_conn_id` selects the Airflow connection.\n- `hook.get_conn()` returns the authenticated Salesforce client for that connection.\n- `query()` returns a response payload that includes a `records` list.\n- Reduce the payload before returning it so XCom stays small and serializable.\n\n## Create And Update A Record\n\nThe same client can perform normal sObject operations inside a task.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.salesforce.hooks.salesforce import SalesforceHook\n\n\nwith DAG(\n    dag_id=\"salesforce_write_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"salesforce\"],\n):\n    @task()\n    def create_and_update_lead() -> str:\n        hook = SalesforceHook(salesforce_conn_id=\"salesforce_default\")\n        client = hook.get_conn()\n\n        created = client.Lead.create(\n            {\n                \"LastName\": \"Airflow Example\",\n                \"Company\": \"Example Co\",\n                \"Email\": \"airflow@example.com\",\n            }\n        )\n        lead_id = created[\"id\"]\n\n        client.Lead.update(\n            lead_id,\n            {\n                \"Title\": \"Data Engineer\",\n            },\n        )\n\n        return lead_id\n\n    create_and_update_lead()\n```\n\nUse this pattern when you want Airflow to create a CRM object as part of a workflow and then hand the created record id to downstream tasks.\n\n## Common Setup Pattern\n\nFor most DAGs, the clean split is:\n\n- keep the Salesforce username, password, security token, and domain on an Airflow connection\n- create `SalesforceHook` inside the task that needs Salesforce access\n- call `get_conn()` once per task and use the returned client for normal SOQL or sObject operations\n- convert results to small Python values before returning them from the task\n\nIf task logic needs more than one Salesforce API call, keep those calls in the same task body so the connection setup and client lifecycle stay in one place.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i salesforce\nairflow dags list | grep salesforce\n```\n\nRun an isolated task test while you wire up the connection and query:\n\n```bash\nairflow tasks test salesforce_query_demo fetch_accounts 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream dependencies.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Hard-coding Salesforce credentials in DAG code instead of using an Airflow connection or secrets backend.\n- Using `login` for a sandbox org instead of `test` in the connection extras.\n- Omitting the Salesforce security token when the org requires it for username-password authentication.\n- Returning raw Salesforce client objects or very large query results from a task.\n- Writing SOQL against UI labels instead of Salesforce API object and field names.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-salesforce` version `5.12.2`.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so dependency resolution does not silently change your Airflow core version.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-salesforce/stable/`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-salesforce/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-samba/python/DOC.md",
    "content": "---\nname: providers-samba\ndescription: \"Apache Airflow Samba provider for SMB connections, hook-based file access, and Google Cloud Storage to Samba transfers\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.12.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,samba,smb,file-share,gcs,python\"\n---\n\n# Apache Airflow Samba Provider Guide\n\nUse `apache-airflow-providers-samba` when an Airflow DAG needs to read or write files on an SMB/Samba share through an Airflow connection, or copy objects from Google Cloud Storage into that share with a built-in operator.\n\nThis guide targets provider version `4.12.2`.\n\n## Golden Rule\n\n- Install this package alongside a pinned `apache-airflow` version; it is not a standalone SMB client package.\n- Put the Samba server details on an Airflow `samba` connection and reference that connection id from DAG code.\n- Use `SambaHook` as a context manager. Upstream explicitly documents that pattern so sessions are registered and disconnected correctly.\n- Set the connection's `Share` and `Share Type` correctly. Paths passed to the hook are joined under the configured share, and `share_type` changes path formatting between `posix` and `windows`.\n\n## What This Package Adds\n\nThe provider's documented entry points are:\n\n- `airflow.providers.samba.hooks.samba.SambaHook`\n- `airflow.providers.samba.transfers.gcs_to_samba.GCSToSambaOperator`\n\nThere are no Samba-specific sensors documented in the `4.12.2` provider docs.\n\n## Install\n\nThe provider docs for `4.12.2` require:\n\n- `apache-airflow >= 2.11.0`\n- `apache-airflow-providers-common-compat >= 1.10.1`\n- `smbprotocol >= 1.5.0`\n\nInstall Airflow with the official constraints file, then add the provider while keeping your Airflow pin:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.12.2\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-samba==${PROVIDER_VERSION}\"\n```\n\nIf you plan to use `GCSToSambaOperator`, install the Google extra or the Google provider too:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-samba[google]==4.12.2\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep samba\npython -m pip check\n```\n\n## Configure A Samba Connection\n\n`SambaHook` uses `samba_conn_id`, and the provider's default connection id is `samba_default`.\n\nThe documented connection fields are:\n\n- `Host`: Samba server hostname\n- `Port`: Samba server port, default `445`\n- `Share`: default share used when the hook does not receive `share=...`\n- `Login`: SMB username\n- `Password`: SMB password\n- `Share Type`: `posix` or `windows`\n\nAn environment-variable connection is the fastest way to wire one in:\n\n```bash\nexport AIRFLOW_CONN_SAMBA_DEFAULT='{\n  \"conn_type\": \"samba\",\n  \"host\": \"fileserver.example.com\",\n  \"port\": 445,\n  \"login\": \"airflow\",\n  \"password\": \"secret\",\n  \"schema\": \"shared\",\n  \"extra\": {\n    \"share_type\": \"posix\"\n  }\n}'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `samba_default`\n- the default share is `shared`\n- `SambaHook(..., share=\"other-share\")` can override the connection's default share for a specific task\n\nUse `share_type: \"windows\"` if the remote share expects Windows-style path formatting. Invalid values fall back to `posix`.\n\n## Read And Write Files With `SambaHook`\n\nUse `SambaHook` inside a task when you need Python logic around listing, opening, or uploading files.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.samba.hooks.samba import SambaHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"samba_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def inspect_and_upload() -> list[str]:\n        with SambaHook(samba_conn_id=\"samba_default\") as hook:\n            hook.makedirs(\"/incoming/archive\", exist_ok=True)\n\n            existing_files = hook.listdir(\"/incoming\")\n\n            with hook.open_file(\"/incoming/manifest.txt\", mode=\"r\", encoding=\"utf-8\") as stream:\n                manifest = stream.read()\n                if \"ready\" not in manifest:\n                    raise ValueError(\"Manifest does not contain the expected marker\")\n\n            hook.push_from_local(\n                destination_filepath=\"/incoming/archive/report.csv\",\n                local_filepath=\"/opt/airflow/data/report.csv\",\n                buffer_size=1024 * 1024,\n            )\n\n            return existing_files\n\n    inspect_and_upload()\n```\n\nImportant behavior from the provider API:\n\n- `listdir(path)` lists entries inside the configured share.\n- `open_file(path, ...)` opens a file on the share and supports normal text or binary modes.\n- `makedirs(path, exist_ok=True)` is the simplest way to create nested directories before upload.\n- `push_from_local(destination_filepath, local_filepath, buffer_size=None)` streams a local file to Samba.\n- Paths such as `/incoming/report.csv` are paths inside the SMB share, not full UNC paths.\n\nIf you need to walk a directory tree or inspect file metadata, the hook also exposes methods such as `walk`, `scandir`, `stat`, `rename`, `remove`, and `rmdir`.\n\n## Copy Objects From GCS With `GCSToSambaOperator`\n\nUse `GCSToSambaOperator` when the task is specifically \"take an object from Google Cloud Storage and place it on the Samba share\".\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.samba.transfers.gcs_to_samba import GCSToSambaOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"gcs_to_samba_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    copy_invoice = GCSToSambaOperator(\n        task_id=\"copy_invoice\",\n        gcp_conn_id=\"google_cloud_default\",\n        samba_conn_id=\"samba_default\",\n        source_bucket=\"analytics-exports\",\n        source_object=\"invoices/2026-01-01/invoice.pdf\",\n        destination_path=\"/dropbox/invoice.pdf\",\n        move_object=False,\n        buffer_size=1024 * 1024,\n    )\n```\n\nThe operator also supports these common variants:\n\n- set `move_object=True` to delete the GCS object after the copy\n- use one wildcard in `source_object` to copy a group of objects\n- set `keep_directory_structure=False` when copying multiple objects and you want `destination_path` used as the destination prefix instead of recreating the full source path\n- set `impersonation_chain` if your Airflow Google connection relies on short-lived service-account impersonation\n\nFor a single file move, the provider guide says `destination_path` is the full target file path on the Samba server.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep host, share, credentials, and `share_type` on one reusable Airflow Samba connection\n- create `SambaHook` inside the task body, not at module import time\n- use hook methods for ordinary SMB file operations driven by Python logic\n- use `GCSToSambaOperator` only when the source of truth is a GCS bucket and the task is primarily a transfer step\n\n## Pitfalls\n\n- Installing the provider only on the scheduler or webserver. Workers also need it anywhere task code imports `airflow.providers.samba`.\n- Forgetting that the connection `schema` is the default share. If it is missing and you also omit `share=...`, your paths will not resolve to the share you expect.\n- Passing full UNC paths such as `\\\\\\\\server\\\\share\\\\file.txt` to hook methods. The hook already builds the host/share prefix from the Airflow connection.\n- Using the wrong `share_type`. The provider uses `posix` path joining by default; use `windows` when the share expects Windows-style paths.\n- Leaving file and session cleanup to chance. Use the hook as a context manager and use `with hook.open_file(...)` for remote files.\n- Assuming `GCSToSambaOperator` is available with only the Samba provider installed. The operator depends on the Google provider for `GCSHook`.\n- Forgetting that local paths passed to `push_from_local` must exist on the worker that executes the task.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-samba` `4.12.2`.\n- The provider docs for `4.12.2` require `apache-airflow >= 2.11.0`.\n- The stable provider docs list `apache-airflow-providers-google` as an optional cross-provider dependency exposed through the `google` extra.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-samba/stable/`\n- Samba connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-samba/stable/connections.html`\n- `SambaHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-samba/stable/_api/airflow/providers/samba/hooks/samba/index.html`\n- `GCSToSambaOperator` guide: `https://airflow.apache.org/docs/apache-airflow-providers-samba/stable/transfer/gcs_to_samba.html`\n- `GCSToSambaOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-samba/stable/_api/airflow/providers/samba/transfers/gcs_to_samba/index.html`\n- Airflow installation overview: `https://airflow.apache.org/docs/apache-airflow/3.1.0/installation/index.html`\n- Airflow managing connections: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-samba/4.12.2/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-segment/python/DOC.md",
    "content": "---\nname: providers-segment\ndescription: \"Apache Airflow Segment provider for sending Identify and Track calls from DAG tasks through Airflow connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,segment,analytics,customer-data,dag\"\n---\n\n# apache-airflow-providers-segment\n\nUse `apache-airflow-providers-segment` when an Airflow DAG needs to send Segment user identification and tracking events through an Airflow connection instead of calling Segment directly from ad hoc HTTP code.\n\nThis package extends Apache Airflow. It is not the standalone Segment Python SDK for general applications.\n\nThis guide targets provider version `3.9.2`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by every Airflow component that imports DAGs or executes tasks.\n\nIf you already have Airflow installed, keep `apache-airflow` pinned when adding the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-segment==3.9.2\"\n```\n\nIf you are creating a fresh Airflow environment, start with Airflow's official constraints workflow and add the provider in the same environment.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep segment\nairflow info\n```\n\n## Configure A Segment Connection\n\nThe provider uses an Airflow connection for Segment credentials. In practice, the secret you need is the Segment write key.\n\nSet the write key in an environment variable first:\n\n```bash\nexport SEGMENT_WRITE_KEY=\"<your-segment-write-key>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'segment_default' \\\n  --conn-type 'segment' \\\n  --conn-password \"$SEGMENT_WRITE_KEY\"\n```\n\nConfirm the connection exists:\n\n```bash\nairflow connections get segment_default\n```\n\nMost examples use `segment_default`, but DAG code can point to any connection id with `segment_conn_id`.\n\n## Common Workflow: Identify A User\n\nUse `SegmentIdentifyUserOperator` when a DAG needs to set or update traits for a known user.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.segment.operators.segment import SegmentIdentifyUserOperator\n\n\nwith DAG(\n    dag_id=\"segment_identify_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"segment\"],\n):\n    identify_user = SegmentIdentifyUserOperator(\n        task_id=\"identify_user\",\n        segment_conn_id=\"segment_default\",\n        user_id=\"user-123\",\n        traits={\n            \"email\": \"user@example.com\",\n            \"plan\": \"pro\",\n            \"company\": \"Example Co\",\n        },\n    )\n```\n\nUse this operator when the task is declarative and the payload is known when the DAG is parsed.\n\n## Common Workflow: Track An Event\n\nUse `SegmentTrackEventOperator` to emit an event with an event name and properties.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.segment.operators.segment import (\n    SegmentIdentifyUserOperator,\n    SegmentTrackEventOperator,\n)\n\n\nwith DAG(\n    dag_id=\"segment_track_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"segment\"],\n):\n    identify_user = SegmentIdentifyUserOperator(\n        task_id=\"identify_user\",\n        segment_conn_id=\"segment_default\",\n        user_id=\"user-123\",\n        traits={\"email\": \"user@example.com\", \"plan\": \"pro\"},\n    )\n\n    track_signup = SegmentTrackEventOperator(\n        task_id=\"track_signup\",\n        segment_conn_id=\"segment_default\",\n        user_id=\"user-123\",\n        event=\"Signed Up\",\n        properties={\n            \"plan\": \"pro\",\n            \"source\": \"airflow\",\n        },\n    )\n\n    identify_user >> track_signup\n```\n\nThis is the usual pattern when Airflow should mark a business event such as signup completion, invoice payment, or subscription upgrade.\n\n## Use `SegmentHook` Inside A Python Task\n\nUse the hook when the Segment payload depends on normal Python logic inside the task body.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.segment.hooks.segment import SegmentHook\n\n\nwith DAG(\n    dag_id=\"segment_hook_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"segment\"],\n):\n    @task()\n    def send_invoice_paid_event() -> None:\n        hook = SegmentHook(segment_conn_id=\"segment_default\")\n\n        hook.identify(\n            user_id=\"user-123\",\n            traits={\n                \"email\": \"user@example.com\",\n                \"plan\": \"pro\",\n            },\n        )\n\n        hook.track(\n            user_id=\"user-123\",\n            event=\"Invoice Paid\",\n            properties={\n                \"invoice_id\": \"inv_123\",\n                \"amount\": 4999,\n                \"currency\": \"usd\",\n            },\n        )\n\n    send_invoice_paid_event()\n```\n\nUse the operator form when you want a clear DAG node with a fixed payload. Use the hook form when the event body depends on Python logic, branching, or data loaded earlier in the task.\n\n## Operational Checks\n\nCheck that Airflow can see the provider, the connection, and the DAG:\n\n```bash\nairflow providers list | grep segment\nairflow connections get segment_default\nairflow dags list | grep segment\n```\n\nRun an isolated task test while you wire up the connection and payload:\n\n```bash\nairflow tasks test segment_track_demo track_signup 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream tasks.\n\n## Common Pitfalls\n\n- Install the provider everywhere DAG code runs. A working local import does not help if the scheduler or workers are missing the package.\n- Keep the Segment write key in the Airflow connection or a secrets backend instead of embedding it in DAG code.\n- Pass the connection id explicitly with `segment_conn_id` when a DAG does not use `segment_default`.\n- Keep `traits` and `properties` to normal JSON-serializable values so task payloads stay predictable.\n- If downstream systems expect user traits before an event arrives, send identify data before the related track event.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so dependency resolution does not silently change Airflow core.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-segment` version `3.9.2`.\n- Provider packages track Airflow compatibility separately from your DAG code. Check the provider's own docs and release notes before upgrading it independently of Airflow.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-segment/stable/`\n- Segment connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-segment/stable/connections/segment.html`\n- Operators API reference: `https://airflow.apache.org/docs/apache-airflow-providers-segment/stable/_api/airflow/providers/segment/operators/segment/index.html`\n- Hook API reference: `https://airflow.apache.org/docs/apache-airflow-providers-segment/stable/_api/airflow/providers/segment/hooks/segment/index.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-segment/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-sendgrid/python/DOC.md",
    "content": "---\nname: providers-sendgrid\ndescription: \"Apache Airflow SendGrid provider for configuring Airflow email delivery through SendGrid connections and the SendGrid email backend\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,sendgrid,email,python,notifications\"\n---\n\n# apache-airflow-providers-sendgrid\n\nUse `apache-airflow-providers-sendgrid` when your Airflow deployment should send Airflow email through SendGrid instead of a local SMTP relay.\n\nThis package extends Apache Airflow. It is not the standalone `sendgrid` SDK for general Python applications.\n\nThis guide targets provider version `4.2.1`.\n\n## What This Package Adds\n\nThe SendGrid provider plugs a SendGrid-backed emailer into Airflow's normal email path:\n\n- a SendGrid email backend at `airflow.providers.sendgrid.utils.emailer.send_email`\n- an Airflow connection you reference by id, commonly `sendgrid_default`\n- compatibility with Airflow's built-in email utilities and email-on-failure settings\n\nIn practice, you configure the backend once, store the SendGrid API key in an Airflow connection, and then use Airflow's standard email APIs.\n\n## Install\n\nInstall the provider in the same Python environment or container image as every Airflow component that imports DAGs or sends email:\n\n```bash\npython -m pip install \"apache-airflow-providers-sendgrid==4.2.1\"\n```\n\nIf you manage Airflow with a constraints file, keep `apache-airflow` pinned alongside the provider instead of upgrading the provider in isolation.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep sendgrid\nairflow info\n```\n\n## Configure A SendGrid Connection\n\nCreate a SendGrid API key in your SendGrid account, then store it in an Airflow connection instead of hard-coding it in DAG code.\n\nSet shell variables first:\n\n```bash\nexport SENDGRID_API_KEY='SG.your-api-key'\nexport AIRFLOW_SEND_FROM='airflow@example.com'\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'sendgrid_default' \\\n  --conn-type 'sendgrid' \\\n  --conn-password \"$SENDGRID_API_KEY\"\n```\n\nConfirm the connection exists:\n\n```bash\nairflow connections get sendgrid_default\n```\n\nUse a dedicated connection id if different DAGs should use different SendGrid credentials, but pass that id explicitly in your Airflow email config.\n\n## Wire SendGrid Into Airflow Email Settings\n\nPoint Airflow's email backend at the provider and set a sender address:\n\n```bash\nexport AIRFLOW__EMAIL__EMAIL_BACKEND='airflow.providers.sendgrid.utils.emailer.send_email'\nexport AIRFLOW__EMAIL__EMAIL_CONN_ID='sendgrid_default'\nexport AIRFLOW__EMAIL__FROM_EMAIL=\"$AIRFLOW_SEND_FROM\"\n```\n\nThe equivalent `airflow.cfg` section is:\n\n```ini\n[email]\nemail_backend = airflow.providers.sendgrid.utils.emailer.send_email\nemail_conn_id = sendgrid_default\nfrom_email = airflow@example.com\n```\n\nThis is the key setup step. Without `AIRFLOW__EMAIL__EMAIL_BACKEND`, Airflow will keep using whatever email backend is already configured.\n\n## Send Email From Task Code\n\nOnce the backend is configured, use Airflow's email utility from Python task code instead of calling SendGrid's HTTP API directly.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import get_current_context, task\nfrom airflow.utils.email import send_email\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"sendgrid_email_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def notify_with_sendgrid() -> None:\n        context = get_current_context()\n\n        send_email(\n            to=[\"ops@example.com\"],\n            subject=f\"Airflow run {context['run_id']} finished\",\n            html_content=(\n                f\"<p>DAG: {context['dag'].dag_id}</p>\"\n                f\"<p>Task: {context['ti'].task_id}</p>\"\n                f\"<p>Logical date: {context['ds']}</p>\"\n            ),\n        )\n\n    notify_with_sendgrid()\n```\n\nThe important pattern is:\n\n1. configure the SendGrid provider as Airflow's email backend\n2. import `send_email` from `airflow.utils.email`\n3. pass normal Airflow email fields such as `to`, `subject`, and `html_content`\n\nThis keeps your DAG code tied to Airflow's public email API instead of a provider-specific HTTP client.\n\n## Use Built-In Failure Emails\n\nIf you want failures to send mail automatically, configure email recipients in the DAG and let Airflow use the SendGrid backend behind the scenes:\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.empty import EmptyOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"sendgrid_failure_email_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    default_args={\n        \"email\": [\"ops@example.com\"],\n        \"email_on_failure\": True,\n        \"email_on_retry\": False,\n    },\n) as dag:\n    start = EmptyOperator(task_id=\"start\")\n```\n\nThis is the simplest setup when you want Airflow's built-in task and DAG failure emails to go through SendGrid without adding a dedicated notification task.\n\n## Operational Checks\n\nCheck the provider, connection, and active backend before debugging DAG code:\n\n```bash\nairflow providers list | grep sendgrid\nairflow connections get sendgrid_default\nairflow config get-value email email_backend\nairflow config get-value email email_conn_id\n```\n\nRun a task-level test after you wire up the connection and backend:\n\n```bash\nairflow tasks test sendgrid_email_example notify_with_sendgrid 2026-03-12\n```\n\nUse `airflow tasks test` when you need fast feedback on imports, connection lookup, and task logic without waiting for a full scheduler-driven run.\n\n## Common Pitfalls\n\n- Installing the provider only on the scheduler. Workers and any other process that imports DAG code also need it.\n- Creating the SendGrid connection but forgetting to set `AIRFLOW__EMAIL__EMAIL_BACKEND`.\n- Storing the API key directly in DAG source instead of an Airflow connection or secrets backend.\n- Forgetting to set `from_email` in Airflow email config.\n- Treating this provider like the standalone SendGrid SDK. In Airflow, the normal entry point is `airflow.utils.email.send_email` after backend configuration.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-sendgrid` version `4.2.1`.\n- Airflow provider packages are versioned separately from Apache Airflow core, so keep your Airflow installation strategy and provider pins aligned.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-sendgrid/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-sendgrid/stable/index.html`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-sendgrid/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-sftp/python/DOC.md",
    "content": "---\nname: providers-sftp\ndescription: \"Apache Airflow SFTP provider for Airflow connections, hook-based file transfer, and DAG file movement tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,sftp,ssh,file-transfer,dag,python\"\n---\n\n# apache-airflow-providers-sftp\n\nUse `apache-airflow-providers-sftp` to connect Airflow to SFTP servers through an Airflow connection, move files in DAG tasks, and access remote files from Python task code with `SFTPHook`.\n\nThis guide targets provider version `5.7.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-sftp==5.7.0\"\n```\n\nThis package is an Airflow provider, not a standalone SFTP client. Anywhere your DAG code imports `airflow.providers.sftp...` must have both Airflow and this provider installed.\n\nIf your Airflow version is already pinned in requirements or your image build, keep that pin when you add the provider:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-sftp==5.7.0\"\n```\n\n## Configure The Airflow Connection\n\nCreate an Airflow connection for the SFTP server, then reference that connection id from hooks and operators.\n\nPassword-based auth can be defined with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_PARTNER_SFTP='sftp://airflow:secret@sftp.example.com:22/'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `partner_sftp`\n- DAG code can use that id when it creates `SFTPHook` instances or SFTP operators\n\nConnection fields you usually need:\n\n- `Host`: SFTP server hostname\n- `Login`: username\n- `Password`: password when you are not using key-based auth\n- `Port`: usually `22`\n\nIf your server uses an SSH private key, keep that key in the Airflow connection or a secrets backend instead of embedding it in DAG code.\n\n## List, Check, And Download Files With `SFTPHook`\n\nUse `SFTPHook` inside a Python task when later logic depends on the remote file list, on existence checks, or on local processing after the download.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.sftp.hooks.sftp import SFTPHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sftp_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def fetch_orders() -> str:\n        hook = SFTPHook(ssh_conn_id=\"partner_sftp\")\n\n        files = hook.list_directory(\"/inbound\")\n        if \"orders.csv\" not in files:\n            raise FileNotFoundError(\"/inbound/orders.csv not found\")\n\n        local_path = \"/tmp/orders.csv\"\n        hook.retrieve_file(\"/inbound/orders.csv\", local_path)\n        return local_path\n\n    fetch_orders()\n```\n\nUseful `SFTPHook` methods for task code include `list_directory`, `path_exists`, `retrieve_file`, `store_file`, and `delete_file`.\n\n## Upload Or Download Files With `SFTPOperator`\n\nUse `SFTPOperator` when the task is primarily a file transfer and you want that step to stay declarative in the DAG.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.sftp.operators.sftp import SFTPOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sftp_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    upload_report = SFTPOperator(\n        task_id=\"upload_report\",\n        ssh_conn_id=\"partner_sftp\",\n        local_filepath=\"/opt/airflow/data/report.csv\",\n        remote_filepath=\"/upload/report.csv\",\n        operation=\"put\",\n        create_intermediate_dirs=True,\n        confirm=True,\n    )\n```\n\nFor the inverse flow, keep the same connection id and change `operation` to `\"get\"` with the local and remote paths swapped to match the direction you need.\n\n## Upload From A Python Task\n\nUse the hook form when the local file path or remote destination is computed inside Python.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.sftp.hooks.sftp import SFTPHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"sftp_upload_from_task\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def upload_ack() -> None:\n        hook = SFTPHook(ssh_conn_id=\"partner_sftp\")\n        hook.store_file(\"/outbound/ack.txt\", \"/opt/airflow/data/ack.txt\")\n\n    upload_ack()\n```\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- use `SFTPOperator` for straightforward upload or download tasks\n- use `SFTPHook` inside `@task` functions when you need Python logic around file discovery, branching, or post-transfer processing\n- keep the connection id stable across DAGs, such as `partner_sftp` or `vendor_feed`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the provider package.\n- Keep credentials and SSH keys in Airflow connections or a secrets backend, not in DAG files.\n- URL-encode special characters if you define `AIRFLOW_CONN_*` values manually.\n- Remember that local paths such as `/tmp/orders.csv` and `/opt/airflow/data/report.csv` must exist on the worker that executes the task.\n- Prefer absolute remote paths. Relative paths can behave differently across SFTP server setups.\n\n## Version Notes\n\nProvider packages track Airflow compatibility separately from the remote SFTP server you connect to. If you are upgrading Airflow core, check the provider's release notes and compatibility information before you pin or upgrade this package.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-sftp/stable/`\n- Airflow SFTP connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-sftp/stable/connections/sftp.html`\n- `SFTPHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-sftp/stable/_api/airflow/providers/sftp/hooks/sftp/index.html`\n- `SFTPOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-sftp/stable/_api/airflow/providers/sftp/operators/sftp/index.html`\n- `SFTPSensor` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-sftp/stable/_api/airflow/providers/sftp/sensors/sftp/index.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-singularity/python/DOC.md",
    "content": "---\nname: providers-singularity\ndescription: \"Apache Airflow Singularity provider for running container commands with SingularityOperator\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,singularity,containers,python,dag,operator\"\n---\n\n# apache-airflow-providers-singularity\n\nUse `apache-airflow-providers-singularity` when an Airflow DAG needs to start a Singularity container on the worker with `SingularityOperator`.\n\nThis guide targets provider version `3.9.2`.\n\n## What This Package Adds\n\n`apache-airflow-providers-singularity` is an Apache Airflow provider package. Its public entry point is:\n\n- `airflow.providers.singularity.operators.singularity.SingularityOperator`\n\nThis package extends Airflow. It is not a standalone container SDK for ordinary Python applications outside Airflow.\n\n## Install\n\nPyPI lists these minimum runtime requirements for `3.9.2`:\n\n- `apache-airflow >= 2.11.0`\n- Python `3.10`, `3.11`, `3.12`, or `3.13`\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-singularity==3.9.2\"\n```\n\nUpstream also lists `apache-airflow-providers-common-compat>=1.6.1` and `spython>=0.0.56` as package dependencies. A normal `pip install` of the provider resolves those automatically.\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i singularity\npython -m pip check\n```\n\n## Prerequisites\n\nBefore using the operator, make sure:\n\n- the Airflow worker that runs the task has the provider installed\n- that worker can run a working Singularity-compatible container runtime\n- the image URI or local image path you reference is reachable from that worker\n- any bind-mounted host paths exist on that worker\n\nThe operator source calls `spython.main.Client` to pull, start, and stop the container. In practice, that means the container runtime setup lives on the worker image or host, not in an Airflow connection.\n\nEnvironment variables are usually the cleanest way to keep DAG code portable:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport SINGULARITY_IMAGE=\"docker://busybox:1.36.1\"\nexport APP_ENV=\"dev\"\nexport HOST_DATA_DIR=\"/opt/airflow/data\"\n```\n\n## Minimal `SingularityOperator` DAG\n\nUse `image` plus `command` for the basic case. `environment` values are exported before the instance starts.\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.singularity.operators.singularity import SingularityOperator\nfrom pendulum import datetime\n\n\nSINGULARITY_IMAGE = os.environ.get(\"SINGULARITY_IMAGE\", \"docker://busybox:1.36.1\")\n\n\nwith DAG(\n    dag_id=\"singularity_basic\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    tags=[\"singularity\"],\n) as dag:\n    run_container = SingularityOperator(\n        task_id=\"run_container\",\n        image=SINGULARITY_IMAGE,\n        command='/bin/sh -c \"echo APP_ENV=$APP_ENV && uname -a\"',\n        environment={\"APP_ENV\": os.environ.get(\"APP_ENV\", \"dev\")},\n    )\n```\n\nArguments you will use most often:\n\n- `image`: local image path or remote URI such as `docker://busybox:1.36.1`\n- `command`: command run inside the container\n- `environment`: environment variables exported before launch\n- `working_dir`: working directory inside the container\n- `volumes`: bind mounts in `host_path:container_path` form\n- `force_pull`: pull the image before running when it is not already present locally\n- `pull_folder`: directory used for pulled images\n- `options`: extra runtime flags passed through to Singularity\n- `auto_remove`: remove the local pulled image path after the task finishes\n\n## Pull An Image And Bind A Host Directory\n\nThis is the practical pattern when the worker should pull an image on demand and expose a host directory inside the container:\n\n```python\nimport os\n\nfrom airflow import DAG\nfrom airflow.providers.singularity.operators.singularity import SingularityOperator\nfrom pendulum import datetime\n\n\nHOST_DATA_DIR = os.environ.get(\"HOST_DATA_DIR\", \"/opt/airflow/data\")\n\n\nwith DAG(\n    dag_id=\"singularity_bind_mount\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_report = SingularityOperator(\n        task_id=\"run_report\",\n        image=\"docker://busybox:1.36.1\",\n        command='/bin/sh -c \"ls -la /workspace && cat /workspace/input.txt\"',\n        volumes=[f\"{HOST_DATA_DIR}:/workspace\"],\n        working_dir=\"/workspace\",\n        force_pull=True,\n        pull_folder=\"/opt/airflow/singularity\",\n        auto_remove=False,\n    )\n```\n\nUse this pattern when:\n\n- workers do not already have the image staged locally\n- each worker has a stable local directory for pulled images\n- the task needs a simple host bind mount instead of a more complex executor-specific volume system\n\n## Templating Behavior\n\nThe operator templates these fields:\n\n- `command`\n- `environment`\n\nThat means Jinja values such as `{{ ds }}` or `{{ dag_run.run_id }}` work in those arguments:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.singularity.operators.singularity import SingularityOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"singularity_templated_command\",\n    start_date=datetime(2026, 1, 1),\n    schedule=\"@daily\",\n    catchup=False,\n) as dag:\n    print_context = SingularityOperator(\n        task_id=\"print_context\",\n        image=\"docker://busybox:1.36.1\",\n        command='/bin/sh -c \"echo ds={{ ds }} run_id={{ dag_run.run_id }}\"',\n        environment={\"RUN_ID\": \"{{ dag_run.run_id }}\"},\n    )\n```\n\nThe operator source only marks `command` and `environment` as template fields. Do not expect Airflow to template `image`, `working_dir`, `pull_folder`, or `volumes`.\n\n## Important Pitfalls\n\n- This provider exposes an operator, not an Airflow connection type. Runtime setup happens through worker host configuration and operator arguments.\n- `force_pull=True` does not mean \"always refresh\". In the operator source it only pulls when the `image` path does not already exist locally.\n- Bind mounts in `volumes` are resolved on the Airflow worker that launches the task, not on the scheduler and not on your laptop unless that is also the worker.\n- The operator logs container output but does not return it from `execute()`. Do not depend on command stdout appearing as an XCom value.\n- Only `command` and `environment` are templated. If you need a per-run image name or bind path, compute it in Python before constructing the operator.\n- `auto_remove=True` is for cleaning up the local pulled image path after the run. Leave it off if the image path is shared across tasks or managed outside the task lifecycle.\n\n## Version Notes\n\nThis doc is scoped to `apache-airflow-providers-singularity` `3.9.2`. Provider versions are separate from Airflow core versions, so re-check compatibility when you upgrade either Airflow or the provider package.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-singularity/stable/`\n- Installation and package metadata: `https://airflow.apache.org/docs/apache-airflow-providers-singularity/stable/index.html`\n- `SingularityOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-singularity/stable/_api/airflow/providers/singularity/operators/singularity/index.html`\n- `SingularityOperator` source reference: `https://airflow.apache.org/docs/apache-airflow-providers-singularity/stable/_modules/airflow/providers/singularity/operators/singularity.html#SingularityOperator`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-singularity/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-slack/python/DOC.md",
    "content": "---\nname: providers-slack\ndescription: \"Apache Airflow Slack provider guide for posting messages, sending webhooks, and using Slack hooks from Python DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,slack,python,operators,hooks,notifications\"\n---\n\n# Apache Airflow Slack Provider Guide\n\nThis package adds Slack operators and hooks to Apache Airflow. Install it into an Airflow environment, then reference Airflow connection IDs from your DAG code instead of hard-coding Slack secrets in tasks.\n\n## Install\n\nInstall the provider in the same Python environment as Airflow:\n\n```bash\npython -m pip install \"apache-airflow-providers-slack==9.7.0\"\n```\n\nIf you manage Airflow dependencies with a constraints file, keep the provider pinned with the Airflow version your deployment supports instead of upgrading it in isolation.\n\n## Choose The Right Auth Path\n\nThe provider supports two common Slack paths:\n\n- **Slack Web API**: use a bot token when you want to call Slack API methods such as posting a message to a channel\n- **Incoming Webhook**: use a webhook URL when you only need to send a fixed webhook-style message\n\nKeep the raw secrets outside your DAG code:\n\n```bash\nexport SLACK_API_TOKEN='xoxb-your-bot-token'\nexport SLACK_WEBHOOK_URL='https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'\n```\n\nIn Airflow, create connections that hold those secrets and reference them by ID from the provider:\n\n- `slack_api_alerts`: a Slack API connection backed by the bot token\n- `slack_webhook_alerts`: a Slack Incoming Webhook connection backed by the webhook URL\n\nThe provider code then reads `slack_conn_id` or `slack_webhook_conn_id`; operators and hooks do not need the raw token in the constructor.\n\n## Post A Message With `SlackAPIPostOperator`\n\nUse `SlackAPIPostOperator` when you want a normal Slack API `chat.postMessage` call from a DAG task.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.slack.operators.slack import SlackAPIPostOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"slack_api_post_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    post_summary = SlackAPIPostOperator(\n        task_id=\"post_summary\",\n        slack_conn_id=\"slack_api_alerts\",\n        channel=\"#data-alerts\",\n        text=\"Airflow run {{ run_id }} finished for DAG {{ dag.dag_id }}.\",\n    )\n```\n\nUse this path when you need channel-based posting, richer Slack API access, or follow-up API calls from the same connection.\n\n## Send A Webhook Message With `SlackWebhookOperator`\n\nUse `SlackWebhookOperator` when your team already has a Slack incoming webhook and you only need to send a message payload.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.slack.operators.slack_webhook import SlackWebhookOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"slack_webhook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_webhook_message = SlackWebhookOperator(\n        task_id=\"send_webhook_message\",\n        slack_webhook_conn_id=\"slack_webhook_alerts\",\n        message=\"Daily load for {{ ds }} finished successfully.\",\n        blocks=[\n            {\n                \"type\": \"section\",\n                \"text\": {\n                    \"type\": \"mrkdwn\",\n                    \"text\": \"*Daily load complete* for `{{ ds }}`.\",\n                },\n            }\n        ],\n    )\n```\n\nThis is the simplest path when you do not need broader Slack Web API methods.\n\n## Use Hooks Inside Python Tasks\n\nWhen you need runtime logic instead of a single purpose-built operator, use the provider hooks.\n\n### Slack Web API hook\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.slack.hooks.slack import SlackHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"slack_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def notify_row_count(row_count: int) -> None:\n        hook = SlackHook(slack_conn_id=\"slack_api_alerts\")\n        hook.client.chat_postMessage(\n            channel=\"#data-alerts\",\n            text=f\"Loaded {row_count} rows into the warehouse.\",\n        )\n\n    notify_row_count(1250)\n```\n\n### Incoming webhook hook\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.slack.hooks.slack_webhook import SlackWebhookHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"slack_webhook_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def notify_failure() -> None:\n        hook = SlackWebhookHook(slack_webhook_conn_id=\"slack_webhook_alerts\")\n        hook.send(text=\"The DAG failed. Check the Airflow task logs for details.\")\n\n    notify_failure()\n```\n\nUse the API hook when you need to call Slack methods directly. Use the webhook hook when the webhook itself is the integration boundary.\n\n## Common Patterns\n\n### Keep Slack config in Airflow connections\n\nProvider code expects connection IDs, so treat the connection as the boundary between Airflow code and Slack secrets. That keeps DAG files portable across local, staging, and production environments.\n\n### Template message content with Airflow context\n\nOperator fields such as `text` and `message` are good places for Jinja-templated Airflow context:\n\n```python\ntext=\"Task {{ ti.task_id }} in DAG {{ dag.dag_id }} finished at {{ ts }}\"\n```\n\n### Use the API path for richer Slack behavior\n\nIf you need more than a basic webhook payload, prefer the Slack Web API path with `SlackAPIPostOperator` or `SlackHook`. That gives you a normal Slack client and broader API method coverage.\n\n## Common Pitfalls\n\n- Do not pass raw bot tokens or webhook URLs directly in DAG code; store them in Airflow connections and reference the connection ID.\n- `SlackAPIPostOperator` and `SlackHook` use a Slack API connection. `SlackWebhookOperator` and `SlackWebhookHook` use a webhook connection. Do not swap those IDs.\n- A webhook integration is simpler, but it is not the same thing as a full Slack Web API client. Use the Web API path when you need API-level behavior beyond posting a webhook payload.\n- Install this provider as part of an Airflow environment. The package imports from `airflow.providers.slack...` and is not a standalone Slack SDK.\n- If Slack returns permission errors, fix the Slack app or webhook configuration instead of retrying the Airflow task blindly.\n\n## Version Notes For `9.7.0`\n\n- This guide targets `apache-airflow-providers-slack==9.7.0`.\n- Airflow provider packages are versioned independently from Apache Airflow core, so check the provider docs and your Airflow dependency constraints together before upgrading.\n\n## Official Sources\n\n- Provider docs root: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/\n- Package index: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/index.html\n- Slack API operators: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/operators/slack_api.html\n- Slack webhook operators: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/operators/slack_webhook.html\n- `SlackHook` API reference: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/_api/airflow/providers/slack/hooks/slack/index.html\n- `SlackWebhookHook` API reference: https://airflow.apache.org/docs/apache-airflow-providers-slack/stable/_api/airflow/providers/slack/hooks/slack_webhook/index.html\n- PyPI package page: https://pypi.org/project/apache-airflow-providers-slack/\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-smtp/python/DOC.md",
    "content": "---\nname: providers-smtp\ndescription: \"Apache Airflow SMTP provider for Airflow email backends, EmailOperator tasks, SmtpHook calls, and notifier callbacks\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,smtp,email,python,dag,notifications\"\n---\n\n# apache-airflow-providers-smtp\n\nUse `apache-airflow-providers-smtp` when your Airflow deployment needs to send email through an SMTP server from DAG code, Airflow email alerts, or notifier callbacks.\n\nThis package extends Apache Airflow. It is not a general-purpose email library for non-Airflow applications.\n\nThis guide targets provider version `2.4.2`.\n\n## What This Package Adds\n\nThe SMTP provider adds Airflow-specific email integrations built around an Airflow connection:\n\n- `EmailOperator` for email-sending tasks in DAGs\n- `SmtpHook` for sending mail from Python task code\n- `send_smtp_notification(...)` for callback-style notifications\n- an SMTP email backend you can wire into Airflow's global email settings\n\nUse the Airflow connection id `smtp_default` unless you have a reason to create a separate SMTP connection.\n\n## Install\n\nInstall the provider into the same Python environment or container image as every Airflow component that imports or executes DAG code:\n\n```bash\npython -m pip install \"apache-airflow-providers-smtp==2.4.2\"\n```\n\nIn practice, the scheduler, workers, and any triggerer or webserver process that loads DAGs should all have the provider available.\n\n## Configure The SMTP Connection\n\nCreate an Airflow connection with:\n\n- **Connection Id:** `smtp_default`\n- **Connection Type:** `smtp`\n- **Host:** your SMTP host name\n- **Port:** your provider's SMTP port, commonly `587` for STARTTLS or `465` for implicit TLS\n- **Login / Password:** your SMTP credentials\n\nYou can also define the connection with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_SMTP_DEFAULT='smtp://smtp-user:smtp-password@smtp.example.com:587?disable_ssl=true&from_email=airflow%40example.com'\n```\n\nPractical notes:\n\n- Use `disable_ssl=true` for a STARTTLS-style connection on port `587`.\n- Use port `465` when your provider expects implicit TLS instead of STARTTLS.\n- URL-encode reserved characters in usernames, passwords, and query values.\n- Keep credentials in Airflow connections or a secrets backend instead of hard-coding them in DAG files.\n\nIf your SMTP relay requires a fixed sender address, set `from_email` on the connection or pass it directly in the operator, hook, or notifier call.\n\n## Configure Airflow's Global Email Backend\n\nIf you want Airflow's built-in email features to use this provider, configure the email backend and connection id:\n\n```bash\nexport AIRFLOW__EMAIL__EMAIL_BACKEND='airflow.providers.smtp.utils.emailer.send_email'\nexport AIRFLOW__EMAIL__EMAIL_CONN_ID='smtp_default'\nexport AIRFLOW__EMAIL__FROM_EMAIL='airflow@example.com'\n```\n\nUse this when you want task or DAG failure emails sent through the same SMTP connection instead of relying on older SMTP-only config blocks.\n\n## Send An Email Task With `EmailOperator`\n\nUse `EmailOperator` when email delivery is a first-class task in the DAG:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.smtp.operators.smtp import EmailOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"smtp_email_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_report = EmailOperator(\n        task_id=\"send_report\",\n        conn_id=\"smtp_default\",\n        to=[\"ops@example.com\"],\n        subject=\"Nightly pipeline finished\",\n        html_content=\"\"\"\n        <h3>Pipeline complete</h3>\n        <p>The nightly load finished successfully.</p>\n        \"\"\",\n        files=[\"/opt/airflow/reports/daily.csv\"],\n    )\n```\n\nImportant details:\n\n- `html_content` is the message body field used by the operator.\n- `conn_id` points to an Airflow connection of type `smtp`.\n- `files` takes file paths that must exist in the worker's filesystem when the task runs.\n- `to`, `cc`, and `bcc` can be lists when you need multiple recipients.\n\n## Send Mail From Python With `SmtpHook`\n\nUse `SmtpHook` when a Python task needs to send mail directly:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.smtp.hooks.smtp import SmtpHook\n\n\n@task\ndef send_summary_email() -> None:\n    hook = SmtpHook(smtp_conn_id=\"smtp_default\")\n    hook.send_email_smtp(\n        to=[\"ops@example.com\"],\n        subject=\"Daily summary\",\n        html_content=\"<p>The daily job completed successfully.</p>\",\n    )\n```\n\n`SmtpHook` uses `smtp_conn_id`, not `conn_id`.\n\nUse this path when the email depends on Python-side logic, generated content, or task output that is easier to assemble in code than in a dedicated operator.\n\n## Use SMTP Notifications For Callbacks\n\nUse `send_smtp_notification(...)` for DAG or task callbacks such as failure alerts:\n\n```python\nfrom airflow import DAG\nfrom airflow.operators.empty import EmptyOperator\nfrom airflow.providers.smtp.notifications.smtp import send_smtp_notification\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"smtp_failure_callback_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n    on_failure_callback=send_smtp_notification(\n        conn_id=\"smtp_default\",\n        to=\"ops@example.com\",\n        subject=\"Airflow task failed: {{ ti.task_id }}\",\n        html_content=\"\"\"\n        <p>DAG: {{ dag.dag_id }}</p>\n        <p>Task: {{ ti.task_id }}</p>\n        <p>Run id: {{ run_id }}</p>\n        <p>Log URL: <a href=\"{{ ti.log_url }}\">Open logs</a></p>\n        \"\"\",\n    ),\n) as dag:\n    start = EmptyOperator(task_id=\"start\")\n```\n\nThis pattern is useful when you want alerting tied to callback hooks instead of adding a standalone email task to the DAG graph.\n\n## Common Pitfalls\n\n- Install the provider everywhere DAG code is imported or executed, not only on the scheduler.\n- Use `conn_id` with `EmailOperator` and `smtp_conn_id` with `SmtpHook`.\n- For STARTTLS on port `587`, set `disable_ssl=true` on the connection so Airflow does not try implicit TLS.\n- Ensure any file paths in `files=[...]` exist inside the worker container or runtime environment.\n- Keep sender addresses and credentials in the connection or Airflow config instead of hard-coding them in DAG source.\n\n## Minimal Decision Guide\n\n- Use `EmailOperator` when sending the email is a visible DAG task.\n- Use `SmtpHook` inside a Python task when the message is assembled programmatically.\n- Use `send_smtp_notification(...)` for DAG or task callbacks.\n- Configure `AIRFLOW__EMAIL__EMAIL_BACKEND` and `AIRFLOW__EMAIL__EMAIL_CONN_ID` when you want Airflow's built-in email path to use this provider globally.\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-snowflake/python/DOC.md",
    "content": "---\nname: providers-snowflake\ndescription: \"Apache Airflow Snowflake provider for Snowflake connections, SQL tasks, and hook-based workflows in DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,snowflake,sql,dag,python\"\n---\n\n# Apache Airflow Snowflake Provider Python Guide\n\nUse `apache-airflow-providers-snowflake` when Airflow tasks need to run SQL against Snowflake or access Snowflake from Python task code through Airflow connections.\n\nThis provider extends `apache-airflow`; it is not a standalone Snowflake client for regular application code.\n\n## Install\n\nInstall the provider into the same Python environment or container image used by your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-snowflake==6.10.0\"\n```\n\nIn practice, the scheduler, workers, and any other Airflow service importing DAG code all need the same provider installed.\n\n## Configure The Airflow Connection\n\nThe provider reads Snowflake credentials and session defaults from an Airflow connection. The conventional connection id is `snowflake_default`.\n\nYou can create the connection in the Airflow UI, or define it with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_SNOWFLAKE_DEFAULT='snowflake://AIRFLOW_USER:secret@your-account-identifier/ANALYTICS/PUBLIC?warehouse=COMPUTE_WH&role=TRANSFORMER'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `snowflake_default`\n- generic SQL operators use `conn_id=\"snowflake_default\"`\n- `SnowflakeHook` and `SnowflakeSqlApiOperator` use `snowflake_conn_id=\"snowflake_default\"`\n\nConnection values you usually need:\n\n- Snowflake account identifier\n- user credentials or another auth method configured on the connection\n- warehouse\n- database\n- schema\n- role\n\nKeep credentials and auth material in Airflow connections or a secrets backend instead of DAG files. If you define `AIRFLOW_CONN_*` manually, URL-encode reserved password characters such as `@`, `:`, and `/`.\n\n## Run SQL In A DAG\n\nFor normal DDL and DML tasks, use Airflow's SQL operator with a Snowflake connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"snowflake_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"snowflake_default\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id NUMBER AUTOINCREMENT,\n            event_type STRING,\n            created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"snowflake_default\",\n        sql=\"\"\"\n        INSERT INTO events (event_type)\n        VALUES ('signup'), ('purchase')\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need custom Python logic around the result.\n\n## Query Snowflake From Python Tasks\n\nUse `SnowflakeHook` when later task logic needs query results in Python:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.snowflake.hooks.snowflake import SnowflakeHook\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"snowflake_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> list[tuple[str, int]]:\n        hook = SnowflakeHook(snowflake_conn_id=\"snowflake_default\")\n\n        version_row = hook.get_first(\"SELECT CURRENT_VERSION()\")\n        print(f\"Snowflake version: {version_row[0]}\")\n\n        records = hook.get_records(\n            \"\"\"\n            SELECT event_type, COUNT(*)\n            FROM events\n            GROUP BY event_type\n            ORDER BY event_type\n            \"\"\"\n        )\n\n        return [(event_type, int(count)) for event_type, count in records]\n\n    read_summary()\n```\n\nUseful hook methods for everyday tasks:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying connection object\n\n`SnowflakeHook` uses `snowflake_conn_id`, not `conn_id`.\n\n## Run Multi-Statement SQL With The SQL API Operator\n\nUse `SnowflakeSqlApiOperator` when you specifically want the Snowflake SQL API operator instead of the generic SQL operator:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.snowflake.operators.snowflake import SnowflakeSqlApiOperator\nfrom pendulum import datetime\n\nwith DAG(\n    dag_id=\"snowflake_sql_api_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_batch = SnowflakeSqlApiOperator(\n        task_id=\"run_batch\",\n        snowflake_conn_id=\"snowflake_default\",\n        sql=\"\"\"\n        CREATE OR REPLACE TEMP TABLE tmp_numbers AS\n        SELECT 1 AS n\n        UNION ALL\n        SELECT 2 AS n;\n\n        SELECT COUNT(*) FROM tmp_numbers;\n        \"\"\",\n        statement_count=2,\n    )\n```\n\nWhen you send multiple statements, keep `statement_count` aligned with the actual number of SQL statements in `sql`.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- use `SQLExecuteQueryOperator` for plain SQL tasks\n- use `SnowflakeHook` inside `@task` functions when downstream Python needs query results\n- keep the Snowflake connection id stable across DAGs, such as `snowflake_default` or `analytics_wh`\n- keep warehouse, database, schema, and role consistent on the Airflow connection so tasks do not depend on accidental session state\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. Import errors usually mean one image or service is missing the package.\n- `SnowflakeHook` and `SnowflakeSqlApiOperator` use `snowflake_conn_id`; generic SQL operators use `conn_id`.\n- Keep credentials in Airflow connections or a secrets backend instead of embedding them in DAG code.\n- URL-encode passwords if you define `AIRFLOW_CONN_SNOWFLAKE_DEFAULT` manually.\n- Keep large query results out of XCom. Return small summaries or write larger outputs to storage.\n- If you use `SnowflakeSqlApiOperator` for multi-statement SQL, set `statement_count` correctly.\n\n## Version Notes\n\nThis guide targets `apache-airflow-providers-snowflake` version `6.10.0`. Provider packages track Airflow compatibility separately from your Snowflake account setup, so re-check the provider docs before changing Airflow core and provider versions independently.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-snowflake/stable/`\n- Snowflake connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-snowflake/stable/connections/snowflake.html`\n- `SnowflakeHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-snowflake/stable/_api/airflow/providers/snowflake/hooks/snowflake/index.html`\n- Snowflake operators API reference: `https://airflow.apache.org/docs/apache-airflow-providers-snowflake/stable/_api/airflow/providers/snowflake/operators/snowflake/index.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-snowflake/6.10.0/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-sqlite/python/DOC.md",
    "content": "---\nname: providers-sqlite\ndescription: \"Apache Airflow SQLite provider for Airflow connections, SQL tasks, and SqliteHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,sqlite,sql,python,dag,database\"\n---\n\n# apache-airflow-providers-sqlite\n\nUse `apache-airflow-providers-sqlite` to connect Airflow tasks to a SQLite database file through an Airflow connection, run SQL from DAG tasks, and query SQLite from Python tasks with `SqliteHook`.\n\nThis guide targets provider version `4.3.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-sqlite` is an Apache Airflow provider package. Install it when your DAGs need SQLite connections and hook-based access from Airflow tasks.\n\nThis package extends Airflow. It is not a standalone SQLite client for regular application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-sqlite==4.3.0\"\n```\n\nIn practice, that means the scheduler, workers, and webserver all need the provider available anywhere DAG code imports it.\n\nIf you are adding the provider to an existing Airflow environment, keep `apache-airflow` pinned in the same command so dependency resolution does not silently change your Airflow core version:\n\n```bash\npython -m pip install \"apache-airflow==<your-current-airflow-version>\" \"apache-airflow-providers-sqlite==4.3.0\"\n```\n\nIf you are building a fresh Airflow environment, install Airflow itself with the official constraints file first, then add the provider.\n\n## Configure The Airflow Connection\n\nThe provider reads connection settings from an Airflow connection with connection type `sqlite`. The default connection id is usually `sqlite_default`.\n\nThe simplest portable setup is an environment-defined connection:\n\n```bash\nexport AIRFLOW_CONN_SQLITE_DEFAULT='sqlite:////opt/airflow/data/warehouse.db'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `sqlite_default`\n- SQL operators use `conn_id=\"sqlite_default\"`\n- `SqliteHook` uses `sqlite_conn_id=\"sqlite_default\"`\n\nUse an absolute database path in worker environments so every task resolves the same file location.\n\nKeep the connection definition in Airflow connections, environment variables, or a secrets backend instead of hard-coding SQLite paths in DAG files.\n\n## Minimal Connection Check\n\nUse `SqliteHook` for a quick connection check from a task:\n\n```python\nfrom airflow.decorators import task\nfrom airflow.providers.sqlite.hooks.sqlite import SqliteHook\n\n\n@task\ndef ping_sqlite() -> int:\n    hook = SqliteHook(sqlite_conn_id=\"sqlite_default\")\n    row = hook.get_first(\"SELECT 1\")\n    return int(row[0])\n```\n\n`SqliteHook` uses `sqlite_conn_id`, not `conn_id`.\n\n## Run SQL In A DAG\n\nFor SQL-only tasks, use Airflow's generic SQL operator with a SQLite connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"sqlite_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"sqlite_default\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id INTEGER PRIMARY KEY AUTOINCREMENT,\n            event_name TEXT NOT NULL,\n            created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"sqlite_default\",\n        sql=\"\"\"\n        INSERT INTO events (event_name)\n        VALUES ('signup'), ('purchase')\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need Python logic around the query result.\n\n## Query SQLite From Python Tasks\n\nUse `SqliteHook` when you need to branch on query results, fetch rows into Python, or combine database work with other task logic.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.sqlite.hooks.sqlite import SqliteHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"sqlite_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> None:\n        hook = SqliteHook(sqlite_conn_id=\"sqlite_default\")\n\n        row = hook.get_first(\"SELECT COUNT(*) FROM events\")\n        event_count = row[0] if row else 0\n\n        records = hook.get_records(\n            \"SELECT id, event_name, created_at FROM events ORDER BY id DESC LIMIT 10\"\n        )\n\n        print(f\"total events: {event_count}\")\n        for event_id, event_name, created_at in records:\n            print(f\"{event_id}: {event_name} at {created_at}\")\n\n    read_summary()\n```\n\nUseful hook methods for everyday DAG work:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying DB-API connection\n\n## Common Setup Pattern\n\nFor many DAGs, a clean split is:\n\n- use `SQLExecuteQueryOperator` for schema setup, inserts, updates, and other SQL-only tasks\n- use `SqliteHook` inside `@task` functions when later task logic needs query results in Python\n- keep the connection id stable across DAGs, such as `sqlite_default` or `local_sqlite`\n- store the SQLite file on a path that exists on the worker where the task runs\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the provider package.\n- `SqliteHook` expects `sqlite_conn_id`; Airflow's generic SQL operators use `conn_id`.\n- Pointing different workers at different local files. A path like `/opt/airflow/data/warehouse.db` refers to each worker's filesystem unless you mount shared storage.\n- Assuming SQLite is a good fit for heavy concurrent writes or multi-host database workloads. It works best for lightweight local or single-node patterns.\n- Hard-coding database paths directly in DAG code instead of using an Airflow connection or environment variable.\n- Forgetting that the parent directory for the SQLite file must already exist and be writable by the task runtime.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-sqlite` version `4.3.0`.\n- Provider packages track Airflow compatibility separately from SQLite itself. When you upgrade Airflow core, review the provider's version-specific docs before upgrading this package in production.\n- Keep `apache-airflow` pinned when you add or upgrade the provider so dependency resolution does not silently change your Airflow core version.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-sqlite/4.3.0/`\n- SQLite connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-sqlite/4.3.0/connections/sqlite.html`\n- `SqliteHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-sqlite/4.3.0/_api/airflow/providers/sqlite/hooks/sqlite/index.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-sqlite/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-ssh/python/DOC.md",
    "content": "---\nname: providers-ssh\ndescription: \"Apache Airflow SSH provider for SSH connections, remote command execution, tunnels, and resilient detached remote jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,ssh,remote-execution,operators,tunnels,python\"\n---\n\n# Apache Airflow SSH Provider Guide\n\nUse `apache-airflow-providers-ssh` when an Airflow DAG needs to run commands on a remote host over SSH, open a port-forwarding tunnel, or keep a long-running remote job alive while the task monitoring moves to the triggerer.\n\nThis guide targets provider version `4.3.1`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone SSH client package.\n- Put hosts, credentials, keys, and SSH policy settings on an Airflow `SSH` connection instead of hard-coding them in DAG files.\n- Use `SSHOperator` for short synchronous commands, `SSHRemoteJobOperator` for long-running detached jobs, and `SSHHook` when task code needs connectivity checks or port forwarding.\n- Tighten host-key checking explicitly. The provider's SSH connection extras default `no_host_key_check` to `true`.\n\n## What This Package Adds\n\nThe provider's main entry points are:\n\n- `airflow.providers.ssh.hooks.ssh.SSHHook`\n- `airflow.providers.ssh.operators.ssh.SSHOperator`\n- `airflow.providers.ssh.operators.ssh_remote_job.SSHRemoteJobOperator`\n\nThe same Airflow `SSH` connection type is also reused by other integrations such as `SFTPOperator`.\n\n## Install\n\nPyPI lists these minimum runtime requirements for `4.3.1`:\n\n- `apache-airflow >= 2.11.0`\n- Python `3.10`, `3.11`, `3.12`, or `3.13`\n\nFor a fresh Airflow environment, install Airflow first with the official constraints file, then install the provider in a separate command while keeping the Airflow pin:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=3.1.8\nPROVIDER_VERSION=4.3.1\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\npython -m pip install \"apache-airflow==${AIRFLOW_VERSION}\" \"apache-airflow-providers-ssh==${PROVIDER_VERSION}\"\n```\n\nIf Airflow is already installed in the image or virtualenv, keep that exact Airflow pin when you add the provider:\n\n```bash\npython -m pip install \"apache-airflow==<your-airflow-version>\" \"apache-airflow-providers-ssh==4.3.1\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i ssh\npython -m pip check\n```\n\n## Configure An Airflow SSH Connection\n\nThe provider reads host, auth, and policy settings from an Airflow connection with type `ssh`.\n\nAn environment-variable connection is the fastest way to wire one in:\n\n```bash\nexport AIRFLOW_CONN_DEPLOY_HOST='ssh://deploy@ssh.example.com:22?conn_timeout=20&cmd_timeout=300&auth_timeout=20&no_host_key_check=false&key_file=%2Fopt%2Fairflow%2Fkeys%2Fid_ed25519'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `deploy_host`\n- DAG code can use `ssh_conn_id=\"deploy_host\"`\n\nCommon SSH extras supported by the provider:\n\n- `key_file`\n- `private_key`\n- `private_key_passphrase`\n- `conn_timeout`\n- `cmd_timeout`\n- `auth_timeout`\n- `compress`\n- `no_host_key_check`\n- `allow_host_key_change`\n- `look_for_keys`\n- `host_key`\n- `disabled_algorithms`\n- `ciphers`\n- `host_proxy_cmd`\n\nIf you store the connection in the Airflow UI, the extras JSON can look like this:\n\n```json\n{\n  \"key_file\": \"/opt/airflow/keys/id_ed25519\",\n  \"conn_timeout\": 20,\n  \"cmd_timeout\": 300,\n  \"auth_timeout\": 20,\n  \"no_host_key_check\": false,\n  \"allow_host_key_change\": false,\n  \"look_for_keys\": false,\n  \"host_key\": \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...\"\n}\n```\n\nIf you store raw private-key content in the Airflow UI, upstream documents using literal `\\n` sequences inside the `private_key` value.\n\n## Run A Short Remote Command With `SSHOperator`\n\nUse `SSHOperator` when the task should connect, run a command, and finish in the same worker slot.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.ssh.operators.ssh import SSHOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ssh_operator_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_remote_migration = SSHOperator(\n        task_id=\"run_remote_migration\",\n        ssh_conn_id=\"deploy_host\",\n        command=\"cd /srv/myapp && ./manage.py migrate --noinput\",\n        environment={\n            \"APP_ENV\": \"staging\",\n            \"DJANGO_SETTINGS_MODULE\": \"config.settings.staging\",\n        },\n        cmd_timeout=300,\n        get_pty=True,\n        skip_on_exit_code={99},\n        do_xcom_push=True,\n    )\n```\n\nImportant behavior from the operator API:\n\n- `environment` is templated, but the SSH server silently rejects those variables unless `AcceptEnv` is enabled in the server SSH config.\n- `get_pty=True` is the setting to use when the remote process should be killed if the Airflow task times out.\n- Commands that start with `sudo` force `get_pty=True`.\n- When `do_xcom_push=True`, the remote exit code is pushed to XCom under key `ssh_exit`.\n\n## Check Connectivity Or Open A Tunnel With `SSHHook`\n\nUse `SSHHook` inside TaskFlow code when you need a connection test or a port-forwarding tunnel rather than a single operator-managed command.\n\nConnectivity check:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.ssh.hooks.ssh import SSHHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ssh_hook_test_connection\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def verify_host() -> None:\n        hook = SSHHook(ssh_conn_id=\"deploy_host\", auth_timeout=20)\n        ok, message = hook.test_connection()\n        if not ok:\n            raise RuntimeError(message)\n\n    verify_host()\n```\n\nPort forwarding to a private database behind the SSH host:\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.ssh.hooks.ssh import SSHHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ssh_hook_tunnel_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def probe_private_postgres() -> int:\n        hook = SSHHook(ssh_conn_id=\"deploy_host\")\n        tunnel = hook.get_tunnel(\n            remote_port=5432,\n            remote_host=\"db.internal\",\n            local_port=15432,\n        )\n        tunnel.start()\n        try:\n            return tunnel.local_bind_port\n        finally:\n            tunnel.stop()\n\n    probe_private_postgres()\n```\n\n`get_tunnel()` is the provider's replacement for the old `create_tunnel()` API.\n\n## Run Long Jobs With `SSHRemoteJobOperator`\n\n`SSHRemoteJobOperator` is the better choice for long-running remote jobs in the `4.3.x` line. It submits a detached job over SSH, defers monitoring to the triggerer, and can stream logs incrementally back into Airflow.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.ssh.operators.ssh_remote_job import SSHRemoteJobOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"ssh_remote_job_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    run_nightly_job = SSHRemoteJobOperator(\n        task_id=\"run_nightly_job\",\n        ssh_conn_id=\"deploy_host\",\n        command=\"/opt/jobs/nightly_etl.sh\",\n        poll_interval=10,\n        timeout=3600,\n        cleanup=\"on_success\",\n    )\n```\n\nUse this operator when:\n\n- the remote command may run for minutes or hours\n- you want monitoring moved off the worker and onto the triggerer\n- temporary network drops or worker restarts are a real concern\n\nConnection requirements called out by upstream:\n\n- non-interactive authentication must work\n- the remote host must allow command execution without PTY\n- the operator needs file I/O on the remote host for logs and exit-code files\n\nFor Windows targets, set `remote_os=\"windows\"` explicitly instead of relying on auto-detection.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- keep one reusable Airflow `ssh` connection per target host or bastion\n- use `SSHOperator` for short idempotent commands\n- use `SSHRemoteJobOperator` for detached jobs that should outlive the initial SSH session\n- use `SSHHook` only when task code needs a connectivity check, connection override, or local tunnel\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code or runs tasks. Scheduler-only installation is not enough.\n- Do not rely on the default host-key behavior. The provider defaults `no_host_key_check` to `true`; set it to `false` and use `host_key` or a maintained `known_hosts` policy for stronger verification.\n- Do not expect `environment={...}` to work unless the server allows those variables through `AcceptEnv`.\n- Use `conn_timeout`, not the removed `timeout` hook attribute.\n- Use `hook.get_conn()` as the SSH client context manager; the `SSHHook` context manager itself is deprecated.\n- Use `get_tunnel()`, not the removed `create_tunnel()` API.\n- Clean up remote job directories when using `SSHRemoteJobOperator`, or they will accumulate on the target host.\n- A remote reboot still kills detached jobs. `SSHRemoteJobOperator` is resilient to monitoring interruptions, not to the remote machine disappearing.\n\n## Version Notes\n\n- `4.3.1` was released on `2026-02-02`; the changelog lists only a misc async-connection internal update for this release.\n- `4.3.0` introduced `SSHRemoteJobOperator`, which is the main user-facing addition in the current minor line.\n- `4.2.0` raised the minimum supported Airflow version for this provider to `2.11.0`.\n- `4.0.0` removed several deprecated APIs. In current code, use `conn_timeout`, `get_tunnel()`, and the operator `hook` attribute.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/`\n- SSH connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/connections/ssh.html`\n- `SSHHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/_api/airflow/providers/ssh/hooks/ssh/index.html`\n- `SSHOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/_api/airflow/providers/ssh/operators/ssh/index.html`\n- `SSHRemoteJobOperator` guide: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/operators/ssh_remote_job.html`\n- Provider changelog: `https://airflow.apache.org/docs/apache-airflow-providers-ssh/stable/changelog.html`\n- Airflow installation from PyPI: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-ssh/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-tableau/python/DOC.md",
    "content": "---\nname: providers-tableau\ndescription: \"Apache Airflow Tableau provider guide for configuring Tableau connections and running workbook or datasource refresh jobs from Python DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.3.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,tableau,python,operators,hooks,sensors\"\n---\n\n# Apache Airflow Tableau Provider Guide\n\nUse `apache-airflow-providers-tableau` when an Airflow DAG needs to authenticate to Tableau through an Airflow connection, trigger extract refresh jobs for workbooks or datasources, and optionally poll Tableau job status from Airflow tasks.\n\nThis guide covers provider version `5.3.3`.\n\n## Golden Rule\n\n- Install this provider into the same Python environment as Airflow; it is not a standalone Tableau SDK.\n- Put Tableau credentials on an Airflow connection such as `tableau_default`.\n- Use `TableauOperator` for refresh and delete-style actions, and `TableauHook` or `TableauJobStatusSensor` when task code needs more control.\n- Prefer username/password or JWT authentication. Do not build new DAGs around Tableau personal access tokens.\n\n## What This Package Adds\n\nThe provider exposes three main Airflow integration points:\n\n- `airflow.providers.tableau.operators.tableau.TableauOperator`\n- `airflow.providers.tableau.hooks.tableau.TableauHook`\n- `airflow.providers.tableau.sensors.tableau.TableauJobStatusSensor`\n\nThe provider docs list `tableau_default` as the default connection ID for hooks and operators.\n\n## Install\n\nThe provider requires:\n\n- Python `>=3.10`\n- Apache Airflow `>=2.11.0`\n- `tableauserverclient >=0.27,!=0.39`\n\nInstall it into the same environment as Airflow and keep both versions pinned:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"5.3.3\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-tableau==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed and pinned, install the provider in a separate command while repeating the Airflow pin so `pip` does not silently move core:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-tableau==5.3.3\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i tableau\nairflow info\n```\n\n## Configure A Tableau Connection\n\nThe connection type is `tableau`. The important fields are:\n\n- `host`: Tableau Server or Tableau Cloud base URL\n- `login` and `password`: for username/password auth\n- `extra.site_id`: Tableau site content URL; Tableau Online requires a value, while Tableau Server can use an empty string for the default site\n- `extra.verify`: `true`, `false`, or a CA bundle path\n- `extra.cert`: optional client certificate path or cert/key pair\n\n### Username/password authentication\n\n```bash\nexport AIRFLOW_CONN_TABLEAU_DEFAULT='{\n  \"conn_type\": \"tableau\",\n  \"host\": \"https://MY-TABLEAU-SERVER\",\n  \"login\": \"tableau-user@example.com\",\n  \"password\": \"your-tableau-password\",\n  \"extra\": {\n    \"site_id\": \"MarketingTeam\",\n    \"verify\": true\n  }\n}'\n```\n\n### JWT authentication\n\nCurrent provider code enables JWT auth when connection extra includes `auth: \"jwt\"` and exactly one of `jwt_file` or `jwt_token`.\n\n```bash\nexport AIRFLOW_CONN_TABLEAU_DEFAULT='{\n  \"conn_type\": \"tableau\",\n  \"host\": \"https://MY-TABLEAU-SERVER\",\n  \"extra\": {\n    \"auth\": \"jwt\",\n    \"site_id\": \"MarketingTeam\",\n    \"jwt_file\": \"/opt/airflow/secrets/tableau.jwt\",\n    \"verify\": true\n  }\n}'\n```\n\nIf you want to store the token directly instead of a file path:\n\n```bash\nexport AIRFLOW_CONN_TABLEAU_DEFAULT='{\n  \"conn_type\": \"tableau\",\n  \"host\": \"https://MY-TABLEAU-SERVER\",\n  \"extra\": {\n    \"auth\": \"jwt\",\n    \"site_id\": \"MarketingTeam\",\n    \"jwt_token\": \"eyJhbGciOi...\",\n    \"verify\": true\n  }\n}'\n```\n\nConfirm the connection Airflow will use:\n\n```bash\nairflow connections get tableau_default\n```\n\n## Refresh A Workbook\n\n`TableauOperator` is the simplest path when you want Airflow to trigger a workbook extract refresh.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.tableau.operators.tableau import TableauOperator\n\n\nwith DAG(\n    dag_id=\"tableau_refresh_workbook\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"tableau\"],\n):\n    refresh_workbook = TableauOperator(\n        task_id=\"refresh_workbook\",\n        tableau_conn_id=\"tableau_default\",\n        resource=\"workbooks\",\n        method=\"refresh\",\n        find=\"Finance Workbook\",\n        match_with=\"name\",\n        blocking_refresh=True,\n        check_interval=20,\n    )\n```\n\nKey arguments:\n\n- `resource=\"workbooks\"` or `resource=\"datasources\"` for refresh jobs\n- `method=\"refresh\"`\n- `find`: the workbook or datasource identifier to act on\n- `match_with=\"id\"` if `find` is already a Tableau object id, or `match_with=\"name\"` when resolving by name\n- `blocking_refresh=True` to wait for Tableau job completion in the operator itself\n\n## Refresh A Datasource Asynchronously\n\nSet `blocking_refresh=False` when you want the operator to return the Tableau job id immediately and let a sensor watch the job separately.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.providers.tableau.operators.tableau import TableauOperator\nfrom airflow.providers.tableau.sensors.tableau import TableauJobStatusSensor\n\n\nwith DAG(\n    dag_id=\"tableau_refresh_datasource_async\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"tableau\"],\n):\n    start_refresh = TableauOperator(\n        task_id=\"start_refresh\",\n        tableau_conn_id=\"tableau_default\",\n        resource=\"datasources\",\n        method=\"refresh\",\n        find=\"sales_extract_ds\",\n        match_with=\"id\",\n        blocking_refresh=False,\n    )\n\n    wait_for_refresh = TableauJobStatusSensor(\n        task_id=\"wait_for_refresh\",\n        tableau_conn_id=\"tableau_default\",\n        job_id=start_refresh.output,\n    )\n\n    start_refresh >> wait_for_refresh\n```\n\nThis is the cleanest pattern when the refresh can take a while and you want the Airflow graph to show a separate polling step.\n\n## Use `TableauHook` Inside A Python Task\n\nUse the hook when you need direct Python access to the authenticated Tableau server client or when you need to inspect jobs yourself.\n\nThe hook is designed to be used as a context manager. On entry it signs in, and on exit it signs out.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.tableau.hooks.tableau import TableauHook\n\n\nwith DAG(\n    dag_id=\"tableau_list_workbooks\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"tableau\"],\n):\n    @task()\n    def fetch_workbooks() -> list[dict[str, str | None]]:\n        with TableauHook(tableau_conn_id=\"tableau_default\") as hook:\n            workbooks = hook.get_all(\"workbooks\")\n\n            return [\n                {\n                    \"id\": workbook.id,\n                    \"name\": workbook.name,\n                    \"project\": workbook.project_name,\n                    \"url\": workbook.webpage_url,\n                }\n                for workbook in workbooks\n            ]\n\n    fetch_workbooks()\n```\n\nPolling a job manually from task code looks like this:\n\n```python\nfrom airflow.providers.tableau.hooks.tableau import TableauHook\n\n\ndef get_refresh_status(job_id: str) -> str:\n    with TableauHook(tableau_conn_id=\"tableau_default\") as hook:\n        return hook.get_job_status(job_id).name\n```\n\n## Common Patterns\n\n### Put site selection on the connection unless a DAG truly needs overrides\n\n`TableauHook(site_id=...)` and `TableauOperator(site_id=...)` can override the site at runtime, but most teams should keep `site_id` in the Airflow connection so the DAG code stays portable across environments.\n\n### Use Tableau IDs when you already know them\n\nWhen `match_with=\"id\"`, the operator uses `find` directly. When you switch to a field like `name`, the operator pages through the resource collection to find a match. Use ids for stable automation when possible.\n\n### Keep returned values small\n\nA Tableau refresh can produce a job id, and hook calls can expose rich Tableau objects. Return ids, names, and summaries from tasks instead of raw client objects.\n\n## Common Pitfalls\n\n- Do not install this provider by itself and assume Airflow will appear; it extends an existing Airflow installation.\n- Do not rely on Tableau personal access token extras for new work. The connection page still documents them as deprecated, but provider `5.0.0` removed personal access token authentication and current `5.3.3` hook code only authenticates with username/password or JWT.\n- For JWT auth, set `extra.auth` to `\"jwt\"` and provide exactly one of `jwt_file` or `jwt_token`. Supplying both or neither fails.\n- Tableau Online requires a non-empty `site_id`. An empty string is only for the default Tableau Server site.\n- If you use `match_with=\"name\"`, duplicate workbook or datasource names can resolve unpredictably. Prefer ids for repeatable DAG behavior.\n- The provider excludes `tableauserverclient==0.39`; do not force that version back into your environment.\n- Use `with TableauHook(...) as hook:` for direct hook usage so Airflow signs out cleanly after the task finishes.\n\n## Version Notes For `5.3.3`\n\n- PyPI lists `apache-airflow-providers-tableau==5.3.3` as the current stable release, published on February 14, 2026.\n- Provider `5.3.3` supports Python `3.10` through `3.13`.\n- The provider minimum Airflow version is `2.11.0`.\n- Provider `5.2.0` added JWT authentication support.\n- Provider `5.3.3` specifically excludes `tableauserverclient==0.39`.\n\n## Official Sources\n\n- Provider docs root: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/\n- Provider index and requirements: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/index.html\n- Tableau connection docs: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/connections/tableau.html\n- Tableau operator guide: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/operators.html\n- `TableauHook` API reference: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/_api/airflow/providers/tableau/hooks/tableau/index.html\n- `TableauHook` source: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/_modules/airflow/providers/tableau/hooks/tableau.html\n- `TableauOperator` source: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/_modules/airflow/providers/tableau/operators/tableau.html\n- `TableauJobStatusSensor` source: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/_modules/airflow/providers/tableau/sensors/tableau.html\n- Provider changelog: https://airflow.apache.org/docs/apache-airflow-providers-tableau/stable/changelog.html\n- Airflow installation from PyPI: https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html\n- PyPI package page: https://pypi.org/project/apache-airflow-providers-tableau/\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-telegram/python/DOC.md",
    "content": "---\nname: providers-telegram\ndescription: \"Apache Airflow Telegram provider for sending bot messages from DAGs with TelegramOperator and TelegramHook\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.9.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,telegram,python,notifications,dag\"\n---\n\n# apache-airflow-providers-telegram\n\nUse `apache-airflow-providers-telegram` when an Airflow DAG should send Telegram bot messages to a user, group, or channel.\n\nThis package extends Apache Airflow. It is not the standalone Telegram Bot SDK for general Python applications outside Airflow.\n\nThis guide targets provider version `4.9.2`.\n\n## What This Package Adds\n\nThe Telegram provider gives Airflow Telegram-specific task and hook integrations built around an Airflow connection:\n\n- `TelegramOperator` for sending a message as a DAG task\n- `TelegramHook` for sending a message from Python task code\n- a `telegram` connection type, usually referenced as `telegram_default`\n\nKeep the bot token in an Airflow connection or secrets backend instead of hard-coding it in DAG source.\n\n## Install\n\nInstall the provider in the same Python environment or container image as every Airflow component that imports or executes DAG code:\n\n```bash\npython -m pip install \"apache-airflow-providers-telegram==4.9.2\"\n```\n\nIf your Airflow deployment uses constraints files, keep the provider pinned alongside the Airflow version your environment supports instead of upgrading it in isolation.\n\n## Prerequisites\n\nYou need:\n\n- a Telegram bot token\n- a target `chat_id`\n- an Airflow connection that stores the bot token\n\nExample shell variables for local setup:\n\n```bash\nexport TELEGRAM_BOT_TOKEN='123456789:your-bot-token'\nexport TELEGRAM_CHAT_ID='-1001234567890'\n```\n\n## Configure The Airflow Connection\n\nCreate an Airflow connection for the bot token.\n\nIn the Airflow UI, use:\n\n- **Connection Id:** `telegram_default`\n- **Connection Type:** `telegram`\n- **Password:** your Telegram bot token\n- **Extra:** `{\"chat_id\": \"-1001234567890\"}` if you want a default chat id on the connection\n\nYou can also create it from the CLI:\n\n```bash\nairflow connections add 'telegram_default' \\\n  --conn-type 'telegram' \\\n  --conn-password \"$TELEGRAM_BOT_TOKEN\" \\\n  --conn-extra \"{\\\"chat_id\\\": \\\"$TELEGRAM_CHAT_ID\\\"}\"\n```\n\nUseful check:\n\n```bash\nairflow connections get telegram_default\n```\n\nPractical notes:\n\n- If you keep `chat_id` in connection extras, tasks can omit it and only pass `text`.\n- If different DAGs send to different chats, keep only the bot token on the connection and pass `chat_id` explicitly in each task.\n- Keep the raw bot token out of DAG files.\n\n## Send A Message With `TelegramOperator`\n\nUse `TelegramOperator` when sending the message should appear as a normal task in the DAG graph.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.telegram.operators.telegram import TelegramOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"telegram_operator_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    send_message = TelegramOperator(\n        task_id=\"send_message\",\n        telegram_conn_id=\"telegram_default\",\n        chat_id=\"{{ var.value.telegram_chat_id }}\",\n        text=\"Airflow run {{ run_id }} finished for DAG {{ dag.dag_id }}.\",\n    )\n```\n\nThe main parameters are:\n\n- `telegram_conn_id`: Airflow connection id for the bot token\n- `chat_id`: target Telegram chat; omit it only if the connection already defines a default `chat_id`\n- `text`: the message body to send\n\nUse this path when Telegram delivery is a first-class step in the workflow and should be visible in task history.\n\n## Use `TelegramHook` Inside Python Tasks\n\nUse `TelegramHook` when the message content depends on Python logic or task output.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.models import Variable\nfrom airflow.providers.telegram.hooks.telegram import TelegramHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"telegram_hook_example\",\n    start_date=datetime(2026, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def notify_summary() -> None:\n        chat_id = Variable.get(\"telegram_chat_id\")\n\n        hook = TelegramHook(telegram_conn_id=\"telegram_default\")\n        hook.send_message(\n            {\n                \"chat_id\": chat_id,\n                \"text\": \"Daily pipeline finished successfully.\",\n            }\n        )\n\n    notify_summary()\n```\n\n`TelegramHook` uses `telegram_conn_id`, not `conn_id`.\n\nThis pattern is the better fit when the Telegram message is assembled dynamically in Python code instead of being a dedicated standalone task.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- store the bot token on `telegram_default`\n- keep the destination `chat_id` in an Airflow Variable or the connection extras\n- use `TelegramOperator` for a simple visible notification task\n- use `TelegramHook` inside `@task` code when the message depends on runtime logic\n\n## Pitfalls\n\n- Install the provider everywhere Airflow imports DAG code. Import errors usually mean one scheduler, worker, or image is missing the package.\n- Use `telegram_conn_id` for this provider's classes; do not replace it with a generic `conn_id`.\n- Do not hard-code the bot token in Python source. Keep it in an Airflow connection or secrets backend.\n- If you configure a default `chat_id` on the connection, make sure it matches the actual destination for the DAG; otherwise pass `chat_id` explicitly per task.\n- Keep messages small and plain enough for the target Telegram chat and your bot permissions.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-telegram` version `4.9.2`.\n- Airflow provider packages are versioned separately from Apache Airflow core, so check the provider docs before changing core and provider versions independently.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-telegram/stable/`\n- Package index: `https://airflow.apache.org/docs/apache-airflow-providers-telegram/stable/index.html`\n- Telegram connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-telegram/stable/connections/telegram.html`\n- `TelegramHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-telegram/stable/_api/airflow/providers/telegram/hooks/telegram/index.html`\n- `TelegramOperator` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-telegram/stable/_api/airflow/providers/telegram/operators/telegram/index.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-telegram/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-teradata/python/DOC.md",
    "content": "---\nname: providers-teradata\ndescription: \"Apache Airflow Teradata provider for Airflow connections, SQL tasks, stored procedures, and Teradata-to-Teradata transfers\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,teradata,sql,database,dag,python\"\n---\n\n# apache-airflow-providers-teradata\n\nUse `apache-airflow-providers-teradata` when your Airflow deployment needs a Teradata connection type, SQL tasks through `TeradataOperator`, stored procedure execution, or data movement between Teradata systems.\n\nThis guide targets provider version `3.5.0`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow scheduler, webserver, and workers.\n\nThe provider requires:\n\n- Python `3.10` through `3.13`\n- Apache Airflow `>=2.11.0`\n- `apache-airflow-providers-common-compat>=1.12.0`\n- `apache-airflow-providers-common-sql>=1.32.0`\n- `teradatasql>=17.20.0.28`\n- `teradatasqlalchemy>=17.20.0.0`\n\nIf you already have Airflow installed, keep `apache-airflow` pinned in the same command so dependency resolution does not silently move your core Airflow version:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-teradata==3.5.0\"\n```\n\nIf you need provider-specific extras, install them explicitly:\n\n```bash\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-teradata[amazon]==3.5.0\"\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-teradata[microsoft-azure]==3.5.0\"\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-teradata[ssh]==3.5.0\"\npython -m pip install \"apache-airflow==3.1.8\" \"apache-airflow-providers-teradata[sqlalchemy]==3.5.0\"\n```\n\nUse these extras only when you need the matching feature set:\n\n- `amazon`: S3-to-Teradata transfers\n- `microsoft-azure`: Azure Blob Storage-to-Teradata transfers\n- `ssh`: remote BTEQ or TPT execution over SSH\n- `sqlalchemy`: SQLAlchemy engine usage from the hook\n\n## Configure The Airflow Connection\n\nThe provider adds the `teradata` connection type. `TeradataHook` uses `teradata_conn_id`, and its default connection id is `teradata_default`.\n\nConnection fields from the provider docs:\n\n- `Host`: required\n- `Database`: optional\n- `Login`: required\n- `Password`: required\n- `Extra`: optional JSON dictionary for Teradata-specific parameters\n\nThe hook documents port `1025` as the default database port. A practical URI-based connection definition looks like this:\n\n```bash\nexport AIRFLOW_CONN_TERADATA_DEFAULT='teradata://airflow:secret@td.example.com:1025/analytics?tmode=TERA&sslmode=verify-ca&sslca=%2Fetc%2Fssl%2Fcerts%2Fteradata-ca.pem&query_band=appname%3Dairflow%3Benv%3Dprod%3B'\n```\n\nIf you create the connection in the Airflow UI, put Teradata-specific settings in `Extra`:\n\n```json\n{\n  \"tmode\": \"TERA\",\n  \"sslmode\": \"verify-ca\",\n  \"sslca\": \"/etc/ssl/certs/teradata-ca.pem\",\n  \"query_band\": \"appname=airflow;env=prod;\"\n}\n```\n\nProvider-documented `extra` keys include:\n\n- `tmode`: `DEFAULT`, `ANSI`, or `TERA`\n- `sslmode`: `disable`, `allow`, `prefer`, `require`, `verify-ca`, or `verify-full`\n- `sslca`, `sslcapath`, `sslcipher`, `sslcrc`, `sslprotocol`\n- `query_band`: sets the Teradata session QueryBand for each connection\n\n## Run SQL In A DAG\n\nUse `TeradataOperator` for normal DDL, DML, and query tasks.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.teradata.operators.teradata import TeradataOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"teradata_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = TeradataOperator(\n        task_id=\"create_table\",\n        teradata_conn_id=\"teradata_default\",\n        sql=\"\"\"\n        CREATE MULTISET TABLE customer_stage (\n            customer_id INTEGER,\n            email VARCHAR(320),\n            loaded_at TIMESTAMP\n        );\n        \"\"\",\n    )\n\n    insert_rows = TeradataOperator(\n        task_id=\"insert_rows\",\n        teradata_conn_id=\"teradata_default\",\n        sql=[\n            \"\"\"\n            INSERT INTO customer_stage (customer_id, email, loaded_at)\n            VALUES (1, 'alice@example.com', CURRENT_TIMESTAMP);\n            \"\"\",\n            \"\"\"\n            INSERT INTO customer_stage (customer_id, email, loaded_at)\n            VALUES (2, 'bob@example.com', CURRENT_TIMESTAMP);\n            \"\"\",\n        ],\n    )\n\n    read_rows = TeradataOperator(\n        task_id=\"read_rows\",\n        teradata_conn_id=\"teradata_default\",\n        sql=\"SELECT TOP 10 customer_id, email FROM customer_stage;\",\n    )\n\n    create_table >> insert_rows >> read_rows\n```\n\nNotes from the provider docs and API reference:\n\n- `TeradataOperator` subclasses `SQLExecuteQueryOperator`\n- `sql=` can be a string, a list of SQL statements, or an external `.sql` file\n- `schema=` lets you run the statement against a specific Teradata database\n- `autocommit` defaults to `False`\n\n## Call Stored Procedures\n\nUse `TeradataStoredProcedureOperator` when the task needs to execute a Teradata stored procedure. Output parameters can be declared with Python types such as `int` and `str`, or with `\"?\"` placeholders.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.teradata.operators.teradata import (\n    TeradataOperator,\n    TeradataStoredProcedureOperator,\n)\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"teradata_stored_procedure_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_procedure = TeradataOperator(\n        task_id=\"create_procedure\",\n        teradata_conn_id=\"teradata_default\",\n        sql=\"\"\"\n        REPLACE PROCEDURE TEST_PROCEDURE (\n            IN val_in INTEGER,\n            INOUT val_in_out INTEGER,\n            OUT val_out INTEGER,\n            OUT value_str_out VARCHAR(100)\n        )\n        BEGIN\n            SET val_out = val_in * 2;\n            SET val_in_out = val_in_out * 4;\n            SET value_str_out = 'string output';\n        END;\n        \"\"\",\n    )\n\n    call_procedure = TeradataStoredProcedureOperator(\n        task_id=\"call_procedure\",\n        teradata_conn_id=\"teradata_default\",\n        procedure=\"TEST_PROCEDURE\",\n        parameters=[3, 1, int, str],\n    )\n\n    create_procedure >> call_procedure\n```\n\nUpstream also documents:\n\n- positional placeholders: `parameters=[3, 1, \"?\", \"?\"]`\n- dictionary-based parameters when you prefer named arguments\n- procedures that return cursors and OUT parameters together\n\n## Use `TeradataHook` In Python Tasks\n\nUse `TeradataHook` when you need direct access to the Teradata connection inside Python code.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.teradata.hooks.teradata import TeradataHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"teradata_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> list[tuple[str, int]]:\n        hook = TeradataHook(teradata_conn_id=\"teradata_default\")\n\n        with hook.get_conn() as conn:\n            cursor = conn.cursor()\n            cursor.execute(\n                \"\"\"\n                SELECT department_name, COUNT(*)\n                FROM employee_stage\n                GROUP BY 1\n                ORDER BY 1\n                \"\"\"\n            )\n            return cursor.fetchall()\n\n    read_summary()\n```\n\nProvider behavior exposed in the Python API reference:\n\n- `get_conn()` returns a `teradatasql.TeradataConnection`\n- the hook supports autocommit and executemany\n- `callproc(...)` returns the in/out parameter values as a list or mapping, depending on the input shape\n- `get_sqlalchemy_engine()` and related helpers use the hook's `sqlalchemy_url`, which is why the `sqlalchemy` extra matters if you need SQLAlchemy itself installed\n\n## Transfer Rows Between Teradata Systems\n\nUse `TeradataToTeradataOperator` to read from one Teradata connection and insert into another in row chunks.\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.teradata.transfers.teradata_to_teradata import (\n    TeradataToTeradataOperator,\n)\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"teradata_to_teradata_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    transfer_data = TeradataToTeradataOperator(\n        task_id=\"transfer_data\",\n        source_teradata_conn_id=\"teradata_source\",\n        dest_teradata_conn_id=\"teradata_target\",\n        destination_table=\"reporting.customer_stage\",\n        sql=\"\"\"\n        SELECT customer_id, email, loaded_at\n        FROM raw.customer_stage\n        \"\"\",\n        sql_params={},\n        rows_chunk=5000,\n    )\n```\n\nUse this operator for moderate row-copy workflows inside Airflow. `rows_chunk` controls how many rows are committed at a time.\n\n## Object Store And Utility-Based Loads\n\nThe provider also ships more specialized operators:\n\n- `S3ToTeradataOperator` for CSV, JSON, and Parquet loads from S3 through Teradata `READ_NOS`\n- `AzureBlobStorageToTeradataOperator` for the same pattern from Azure Blob Storage\n- `BteqOperator` for SQL or BTEQ scripts through the Teradata `bteq` utility, locally or over SSH\n- `DdlOperator` and `TdLoadOperator` for Teradata Parallel Transporter workflows\n\nImportant limits and prerequisites from the provider docs:\n\n- `S3ToTeradataOperator` does not support AWS STS temporary credentials in the current provider version\n- private S3 or Azure Blob loads require either a Teradata authorization object or matching Airflow cloud credentials\n- `BteqOperator` requires the `bteq` binary from Teradata Tools and Utilities on the local host or the SSH target\n- `TdLoadOperator` depends on Teradata Parallel Transporter utilities such as `tdload`\n\n## Common Pitfalls\n\n- Install the provider everywhere DAG code runs. One missing worker image is enough to trigger import failures.\n- Keep credentials and TLS paths in Airflow connections or a secrets backend, not in DAG source.\n- URL-encode all `extra` values when defining `AIRFLOW_CONN_*` variables as URIs.\n- `query_band` is passed through as a session setting. If you use it, keep the Teradata format exactly as expected, for example `appname=airflow;env=prod;`.\n- The provider is an Airflow integration layer, not a general-purpose Teradata application SDK. Put one-off app code on `teradatasql`; put orchestration logic in Airflow tasks and hooks.\n- BTEQ and TPT operators need OS-level Teradata utilities in addition to the Python provider package.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/`\n- Teradata connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/connections/teradata.html`\n- `TeradataHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/_api/airflow/providers/teradata/hooks/teradata/index.html`\n- `TeradataOperator` and `TeradataStoredProcedureOperator`: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/operators/teradata.html`\n- `TeradataToTeradataOperator`: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/operators/teradata_to_teradata.html`\n- `S3ToTeradataOperator`: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/operators/s3_to_teradata.html`\n- `AzureBlobStorageToTeradataOperator`: `https://airflow.apache.org/docs/apache-airflow-providers-teradata/stable/operators/azure_blob_to_teradata.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-teradata/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-trino/python/DOC.md",
    "content": "---\nname: providers-trino\ndescription: \"Apache Airflow Trino provider for Airflow connections, SQL tasks, and Python tasks built on TrinoHook\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,trino,sql,dag,python\"\n---\n\n# Apache Airflow Trino Provider Guide\n\nUse `apache-airflow-providers-trino` when an Airflow DAG needs to run SQL against Trino through an Airflow connection or access Trino from Python task code with `TrinoHook`.\n\nThis guide targets provider version `6.5.0`.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone Trino client.\n- Put Trino host, credentials, and session extras on an Airflow `Trino` connection instead of hard-coding them in DAG files.\n- Use `SQLExecuteQueryOperator` for ordinary SQL tasks and `TrinoHook` when Python task code needs to query or write rows directly.\n- Do not use `TrinoOperator`. The provider changelog shows it was removed in `6.0.0` in favor of the common SQL operator.\n- Configure exactly one authentication method per connection. The provider changelog documents that newer releases reject multiple auth methods on the same connection.\n\n## Install\n\nThe provider docs list these minimum runtime requirements for `6.5.0`:\n\n- `apache-airflow >= 2.11.0`\n- `apache-airflow-providers-common-compat >= 1.8.0`\n- `apache-airflow-providers-common-sql >= 1.27.2`\n- `trino >= 0.319.0`\n\nInstall the provider into the same image or virtual environment used by your Airflow scheduler, API server, and workers. Keep your deployed Airflow pin in the same command so the resolver does not silently replace core:\n\n```bash\nAIRFLOW_VERSION=\"<your-airflow-version>\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-trino==6.5.0\"\n```\n\nIf you plan to use `GCSToTrinoOperator`, install the Google extra as well:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-trino[google]==6.5.0\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i trino\npython -m pip check\n```\n\n## Configure A Trino Connection\n\nThe provider uses an Airflow connection with connection type `trino`. The connection form exposes these fields:\n\n- `Host`: Trino coordinator host\n- `Login`: Trino user\n- `Password`: optional; used for basic authentication\n- `Port`: Trino port\n- `Extra`: provider-specific options such as auth type, JWT settings, Kerberos settings, client tags, session properties, and timezone\n\nFor a repeatable local or container setup, define the connection with `AIRFLOW_CONN_TRINO_DEFAULT`:\n\n```bash\nexport AIRFLOW_CONN_TRINO_DEFAULT='{\n  \"conn_type\": \"trino\",\n  \"host\": \"trino.example.com\",\n  \"port\": 8443,\n  \"login\": \"airflow\",\n  \"password\": \"replace-me\",\n  \"extra\": {\n    \"protocol\": \"https\",\n    \"session_properties\": {\n      \"query_max_run_time\": \"10m\"\n    },\n    \"client_tags\": [\"airflow\", \"etl\"],\n    \"timezone\": \"UTC\"\n  }\n}'\n```\n\nNotes that matter in practice:\n\n- `trino_default` is the default connection id used by the provider examples.\n- Airflow supports connection definitions from environment variables, but upstream notes that connections created this way are not stored in the metadata database, do not appear in the UI, and do not show up in `airflow connections list`.\n- If you need custom ids, change the environment variable name, for example `AIRFLOW_CONN_ANALYTICS_TRINO=...`, then use that id in DAG code.\n\n### Authentication Extras\n\nThe provider connection docs support these auth modes in `Extra`:\n\n- `auth=jwt` with `jwt__token` or `jwt__file`\n- `auth=certs` with `certs__client_cert_path` and `certs__client_key_path`\n- `auth=kerberos` with Kerberos extras such as `kerberos__service_name`, `kerberos__config`, and `kerberos__principal`\n\nFor password-based basic auth, set `login` and `password` and leave `auth` unset. Do not combine password auth with JWT, certs, or Kerberos on the same connection.\n\n## Run SQL In A DAG\n\nThe provider docs show Trino SQL tasks using `SQLExecuteQueryOperator`. `sql` can be a single statement, a list of statements, or a templated `.sql` file.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom airflow.sdk import DAG\n\nCATALOG = \"lakehouse\"\nSCHEMA = \"analytics\"\nTABLE = \"cities\"\n\nwith DAG(\n    dag_id=\"trino_sql_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"trino\"],\n):\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"trino_default\",\n        sql=f\"\"\"\n        CREATE TABLE IF NOT EXISTS {CATALOG}.{SCHEMA}.{TABLE} (\n            cityid BIGINT,\n            cityname VARCHAR\n        )\n        \"\"\",\n        handler=list,\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"trino_default\",\n        sql=f\"\"\"\n        INSERT INTO {CATALOG}.{SCHEMA}.{TABLE} (cityid, cityname)\n        VALUES (1, 'San Francisco'), (2, 'New York')\n        \"\"\",\n        handler=list,\n        requires_result_fetch=True,\n    )\n\n    query_rows = SQLExecuteQueryOperator(\n        task_id=\"query_rows\",\n        conn_id=\"trino_default\",\n        sql=f\"\"\"\n        SELECT cityid, cityname\n        FROM {CATALOG}.{SCHEMA}.{TABLE}\n        WHERE cityname = ?\n        ORDER BY cityid\n        \"\"\",\n        parameters=(\"San Francisco\",),\n        handler=list,\n    )\n\n    create_table >> insert_rows >> query_rows\n```\n\nUse this pattern when the task is primarily SQL execution and Airflow should manage retries, templating, and task boundaries around the statement.\n\n## Use `TrinoHook` In Python Tasks\n\nUse `TrinoHook` when task code needs to fetch rows, write rows, or mix Trino queries with Python control flow.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow.providers.trino.hooks.trino import TrinoHook\nfrom airflow.sdk import DAG, task\n\nCATALOG = \"lakehouse\"\nSCHEMA = \"analytics\"\nTABLE = \"daily_orders\"\n\nwith DAG(\n    dag_id=\"trino_hook_example\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"trino\"],\n):\n    @task()\n    def summarize() -> None:\n        hook = TrinoHook(trino_conn_id=\"trino_default\")\n\n        row = hook.get_first(\n            f\"SELECT COUNT(*) FROM {CATALOG}.{SCHEMA}.{TABLE}\"\n        )\n        total = row[0] if row else 0\n\n        recent_rows = hook.get_records(\n            f\"\"\"\n            SELECT order_date, order_count\n            FROM {CATALOG}.{SCHEMA}.{TABLE}\n            WHERE order_date >= ?\n            ORDER BY order_date\n            \"\"\",\n            parameters=(\"2026-03-01\",),\n        )\n\n        print(f\"total rows: {total}\")\n        for order_date, order_count in recent_rows:\n            print(order_date, order_count)\n\n    summarize()\n```\n\nCommon hook methods exposed by the provider API:\n\n- `get_first(...)` for one row\n- `get_records(...)` for multiple rows\n- `get_pandas_df(...)` when you want a DataFrame\n- `insert_rows(...)` for batched inserts\n- `run(...)` for general SQL execution\n- `test_connection()` for a lightweight connectivity check\n\n## Optional: Load CSV Data From GCS\n\nThe provider also exposes `GCSToTrinoOperator` when a DAG needs to load CSV data from Google Cloud Storage into Trino.\n\nUse it only if all of these are true:\n\n- you installed the provider with the `google` extra\n- the destination table already exists\n- your Trino table uses one of the supported destination column types documented by the operator API\n\nThis is a targeted transfer operator, not a general replacement for arbitrary Trino ingestion workflows.\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow service image is missing the package.\n- Prefer JSON for `AIRFLOW_CONN_*` values when you need nested extras like `session_properties` or auth-specific settings.\n- Only one auth method may be configured per connection in current provider releases.\n- If you define the connection only through `AIRFLOW_CONN_TRINO_DEFAULT`, it will work at runtime but will not appear in the Airflow UI.\n- `TrinoOperator` examples from old blog posts are outdated for `6.x`; use `SQLExecuteQueryOperator` or `TrinoHook` instead.\n- The provider docs show `trino_default` as the default connection id. When you instantiate `SQLExecuteQueryOperator` directly, pass the Trino connection with `conn_id`.\n\n## Version Notes\n\n- `6.0.0` removed `TrinoOperator`; migrate old DAGs to `SQLExecuteQueryOperator`.\n- `6.3.3` tightened connection auth handling so a single connection cannot declare multiple auth methods.\n- `6.5.0` is the current stable provider release published by the Airflow docs and PyPI as of March 13, 2026.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-trino/stable/index.html`\n- Connection reference: `https://airflow.apache.org/docs/apache-airflow-providers-trino/stable/connections.html`\n- Operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-trino/stable/operators.html`\n- `TrinoHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-trino/stable/_api/airflow/providers/trino/hooks/trino/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-trino/stable/changelog.html`\n- Airflow connection management docs: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-trino/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-vertica/python/DOC.md",
    "content": "---\nname: providers-vertica\ndescription: \"Apache Airflow Vertica provider for Airflow connections, SQL tasks, and VerticaHook-based DAG workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,vertica,sql,database,dag,python\"\n---\n\n# apache-airflow-providers-vertica\n\nUse `apache-airflow-providers-vertica` to connect Airflow to Vertica through an Airflow connection, run SQL in DAG tasks, and access Vertica from Python tasks with `VerticaHook`.\n\nThis guide targets provider version `4.3.0`.\n\n## What This Package Adds\n\n`apache-airflow-providers-vertica` is an Apache Airflow provider package. Install it when your DAGs need Vertica connections and hook-based access from Airflow tasks.\n\nThis package extends Airflow. It is not a general-purpose Vertica client for application code outside Airflow.\n\n## Install\n\nInstall the provider into the same Python environment or container image as your Airflow deployment:\n\n```bash\npython -m pip install \"apache-airflow-providers-vertica==4.3.0\"\n```\n\nIf you need the hook's `sqlalchemy_url` property, install the optional SQLAlchemy extra:\n\n```bash\npython -m pip install \"apache-airflow-providers-vertica[sqlalchemy]==4.3.0\"\n```\n\nVersion requirements called out by upstream for `4.3.0`:\n\n- Apache Airflow `>=2.11.0`\n- Python `>=3.10,<3.14`\n- `vertica-python>=1.3.0` is installed as a dependency\n\nIn practice, the scheduler, webserver, and every worker image must all have the provider available anywhere DAG code imports it.\n\n## Configure The Airflow Connection\n\nThe provider uses an Airflow connection with connection type `vertica`. The default connection id is `vertica_default`.\n\nIn the Airflow UI, configure:\n\n- **Connection Id:** `vertica_default` or a project-specific id such as `vertica_warehouse`\n- **Connection Type:** `vertica`\n- **Host:** your Vertica host name\n- **Schema:** the default database name\n- **Login / Password:** Vertica credentials\n- **Port:** usually `5433`\n\nYou can also define the connection with an environment variable:\n\n```bash\nexport AIRFLOW_CONN_VERTICA_WAREHOUSE='{\n  \"conn_type\": \"vertica\",\n  \"host\": \"vertica.example.com\",\n  \"login\": \"dbadmin\",\n  \"password\": \"secret\",\n  \"schema\": \"analytics\",\n  \"port\": 5433,\n  \"extra\": {\n    \"ssl\": true,\n    \"session_label\": \"airflow-vertica\",\n    \"connection_timeout\": 30,\n    \"connection_load_balance\": true\n  }\n}'\n```\n\nWith that environment variable in place:\n\n- the Airflow connection id is `vertica_warehouse`\n- SQL operators use `conn_id=\"vertica_warehouse\"`\n- `VerticaHook` uses `vertica_conn_id=\"vertica_warehouse\"`\n\nCommon extra fields documented by the provider include:\n\n- `ssl`\n- `connection_timeout`\n- `backup_server_node`\n- `connection_load_balance`\n- `session_label`\n- `use_prepared_statements`\n\nKeep credentials in Airflow connections or a secrets backend instead of hard-coding usernames and passwords in DAG files.\n\n## Run SQL In A DAG\n\nFor SQL-only tasks, use Airflow's generic SQL operator with a Vertica connection:\n\n```python\nfrom airflow import DAG\nfrom airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"vertica_sql_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    create_table = SQLExecuteQueryOperator(\n        task_id=\"create_table\",\n        conn_id=\"vertica_warehouse\",\n        sql=\"\"\"\n        CREATE TABLE IF NOT EXISTS events (\n            id IDENTITY PRIMARY KEY,\n            event_name VARCHAR(255) NOT NULL,\n            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n        )\n        \"\"\",\n    )\n\n    insert_rows = SQLExecuteQueryOperator(\n        task_id=\"insert_rows\",\n        conn_id=\"vertica_warehouse\",\n        sql=\"\"\"\n        INSERT INTO events (event_name)\n        VALUES ('signup'), ('purchase')\n        \"\"\",\n    )\n\n    create_table >> insert_rows\n```\n\nUse this pattern when the task is just SQL execution and you do not need custom Python logic around the query results.\n\n## Query Vertica From Python Tasks\n\nUse `VerticaHook` when you need to fetch rows, branch on results, or mix database work with other task logic.\n\n```python\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.vertica.hooks.vertica import VerticaHook\nfrom pendulum import datetime\n\n\nwith DAG(\n    dag_id=\"vertica_hook_example\",\n    start_date=datetime(2026, 1, 1),\n    schedule=None,\n    catchup=False,\n) as dag:\n    @task\n    def read_summary() -> None:\n        hook = VerticaHook(vertica_conn_id=\"vertica_warehouse\")\n\n        row = hook.get_first(\"SELECT COUNT(*) FROM events\")\n        event_count = row[0] if row else 0\n\n        records = hook.get_records(\n            \"\"\"\n            SELECT event_name, COUNT(*)\n            FROM events\n            GROUP BY event_name\n            ORDER BY event_name\n            \"\"\"\n        )\n\n        print(f\"total events: {event_count}\")\n        for event_name, count in records:\n            print(f\"{event_name}: {count}\")\n\n    read_summary()\n```\n\nUseful hook methods for everyday DAG work:\n\n- `get_first(...)` for a single row\n- `get_records(...)` for multiple rows\n- `run(...)` for executing SQL from Python code\n- `get_conn()` when you need the underlying `vertica_python` connection\n\n`VerticaHook` supports autocommit, so you can use it for DDL and DML inside Python tasks when SQL needs to live next to other task logic.\n\n## Build A SQLAlchemy URL\n\nIf another part of your Airflow code needs a SQLAlchemy URL, use `VerticaHook.sqlalchemy_url`. This requires the provider's optional `sqlalchemy` extra.\n\n```python\nfrom airflow.providers.vertica.hooks.vertica import VerticaHook\n\n\nhook = VerticaHook(vertica_conn_id=\"vertica_warehouse\")\nengine_url = hook.sqlalchemy_url\n\nprint(engine_url)\n```\n\nThe hook builds that URL from the Airflow connection, including supported extra fields as SQLAlchemy query parameters.\n\n## Common Setup Pattern\n\nFor most DAGs, a clean split is:\n\n- use `SQLExecuteQueryOperator` for schema changes, inserts, updates, and other SQL-only tasks\n- use `VerticaHook` inside `@task` functions when later task logic needs query results in Python\n- keep the connection id stable across DAGs, such as `vertica_default`, `vertica_warehouse`, or `analytics_db`\n\n## Pitfalls\n\n- Install the provider everywhere DAG code runs. Import errors usually mean one Airflow image or service is missing the package.\n- `VerticaHook` uses `vertica_conn_id`; generic SQL operators use `conn_id`.\n- Older examples may still use `VerticaOperator`, but upstream removed it in provider `4.0.0`. Use `SQLExecuteQueryOperator` instead.\n- If you need `hook.sqlalchemy_url`, install `apache-airflow-providers-vertica[sqlalchemy]`. Since `4.2.1`, SQLAlchemy is an optional extra instead of an unconditional dependency.\n- Use valid JSON booleans and numbers in `AIRFLOW_CONN_*` JSON values. For example, `true` is valid JSON; `\"True\"` is just a string.\n- Keep passwords and TLS settings in Airflow connections or a secrets backend, not in DAG source files.\n\n## Version Notes\n\n- Provider `4.3.0` supports Python `3.10` through `3.13`.\n- Provider `4.3.0` raises the minimum SQLAlchemy version for the optional SQLAlchemy integration to `1.4.54`.\n- Provider `4.2.0` raised the minimum Airflow version for this package to `2.11.0`.\n- Provider `4.0.0` removed the legacy `VerticaOperator`; current DAGs should use the generic SQL operator plus `VerticaHook`.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-vertica/stable/`\n- Vertica connection docs: `https://airflow.apache.org/docs/apache-airflow-providers-vertica/stable/connections/vertica.html`\n- `VerticaHook` API reference: `https://airflow.apache.org/docs/apache-airflow-providers-vertica/stable/_api/airflow/providers/vertica/hooks/vertica/index.html`\n- SQL operator docs: `https://airflow.apache.org/docs/apache-airflow-providers-vertica/stable/operators.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-vertica/stable/changelog.html`\n- Airflow connection environment variables: `https://airflow.apache.org/docs/apache-airflow/stable/howto/connection.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-vertica/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-weaviate/python/DOC.md",
    "content": "---\nname: providers-weaviate\ndescription: \"Apache Airflow Weaviate provider for Airflow-managed Weaviate connections, collection setup, and batch ingestion from DAGs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,weaviate,vector-database,embeddings,dag,python\"\n---\n\n# apache-airflow-providers-weaviate\n\nUse `apache-airflow-providers-weaviate` when your DAGs need an Airflow-managed Weaviate connection plus provider helpers for creating collections and ingesting objects into Weaviate.\n\nThis guide targets provider version `3.3.1`.\n\n## Install\n\nInstall the provider into the same Python environment or container image as Airflow. Upstream documents `apache-airflow>=2.11.0` as the minimum supported Airflow version for `apache-airflow-providers-weaviate==3.3.1`.\n\nFor a fresh Airflow environment, install Airflow and the provider together with the matching constraints file:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"3.1.8\"\nPROVIDER_VERSION=\"3.3.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-weaviate==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nIf Airflow is already installed, keep the Airflow version pinned when you add the provider so dependency resolution does not silently replace core Airflow:\n\n```bash\npython -m pip install \\\n  \"apache-airflow==<your-airflow-version>\" \\\n  \"apache-airflow-providers-weaviate==3.3.1\"\n```\n\nUseful checks:\n\n```bash\nairflow providers list | grep -i weaviate\npython -m pip show apache-airflow-providers-weaviate weaviate-client\n```\n\nImportant dependency notes from upstream:\n\n- `weaviate-client` must be `>=4.4.0` and must not be `4.16.7`\n- `httpx>=0.25.0` is required\n- `pandas` is part of the provider dependency set and is used by the hook helpers that accept DataFrames\n\n## Configure The Airflow Connection\n\nThe provider uses the Airflow connection type `weaviate`, and `WeaviateHook` defaults to `weaviate_default`.\n\nThe connection guide is strict about one detail: `Host` must be only the hostname. Do not include `http://` or `https://`.\n\nEnvironment variables for a typical HTTPS setup:\n\n```bash\nexport WEAVIATE_HOST=\"cluster.example.weaviate.network\"\nexport WEAVIATE_HTTP_PORT=\"443\"\nexport WEAVIATE_GRPC_HOST=\"$WEAVIATE_HOST\"\nexport WEAVIATE_GRPC_PORT=\"443\"\nexport WEAVIATE_API_KEY=\"replace-me\"\n```\n\nCreate the Airflow connection:\n\n```bash\nairflow connections add 'weaviate_default' \\\n  --conn-type 'weaviate' \\\n  --conn-host \"$WEAVIATE_HOST\" \\\n  --conn-port \"$WEAVIATE_HTTP_PORT\" \\\n  --conn-extra \"{\\\"api_key\\\":\\\"${WEAVIATE_API_KEY}\\\",\\\"http_secure\\\":true,\\\"grpc_host\\\":\\\"${WEAVIATE_GRPC_HOST}\\\",\\\"grpc_port\\\":${WEAVIATE_GRPC_PORT},\\\"grpc_secure\\\":true}\"\n```\n\nThe hook reads these connection fields:\n\n- `host` and `port` for REST and GraphQL traffic\n- `http_secure` in `extra` to switch the HTTP side to HTTPS\n- `grpc_host`, `grpc_port`, and `grpc_secure` in `extra` for the Weaviate gRPC API\n- authentication from one of:\n  - `api_key` or `token` in `extra`\n  - `access_token` in `extra`\n  - `client_secret` in `extra`\n  - `login` and `password` on the Airflow connection for password auth\n\nIf the collection uses a server-side vectorizer that needs third-party embedding credentials, put those headers in `extra.additional_headers`:\n\n```json\n{\n  \"api_key\": \"replace-me\",\n  \"http_secure\": true,\n  \"grpc_host\": \"cluster.example.weaviate.network\",\n  \"grpc_port\": 443,\n  \"grpc_secure\": true,\n  \"additional_headers\": {\n    \"<embedding-provider-header>\": \"<embedding-provider-secret>\"\n  }\n}\n```\n\n## Create A Collection And Ingest Objects\n\n`WeaviateHook.create_collection(...)` is the main setup call, and `WeaviateIngestOperator` is the main batch-ingest entry point.\n\nThis DAG creates a collection that uses a Weaviate-managed OpenAI vectorizer, then inserts rows without precomputed vectors:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\nfrom weaviate.classes.config import DataType, Property\nfrom weaviate.collections.classes.config import Configure\n\ntry:\n    from airflow.sdk import dag, task\nexcept ImportError:\n    from airflow.decorators import dag, task  # type: ignore[attr-defined,no-redef]\n\nfrom airflow.providers.weaviate.hooks.weaviate import WeaviateHook\nfrom airflow.providers.weaviate.operators.weaviate import WeaviateIngestOperator\n\n\nQUESTIONS = [\n    {\n        \"id\": \"q-1\",\n        \"question\": \"This organ removes excess glucose from the blood and stores it as glycogen\",\n        \"answer\": \"Liver\",\n        \"category\": \"SCIENCE\",\n        \"docLink\": \"https://example.com/docs/biology-1\",\n    },\n    {\n        \"id\": \"q-2\",\n        \"question\": \"It is the only living mammal in the order Proboscidea\",\n        \"answer\": \"Elephant\",\n        \"category\": \"ANIMALS\",\n        \"docLink\": \"https://example.com/docs/animals-1\",\n    },\n]\n\n\n@dag(\n    dag_id=\"weaviate_ingest_example\",\n    schedule=None,\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    catchup=False,\n    tags=[\"weaviate\"],\n)\ndef weaviate_ingest_example():\n    @task()\n    def create_collection() -> None:\n        hook = WeaviateHook(conn_id=\"weaviate_default\")\n        hook.create_collection(\n            \"QuestionWithOpenAIVectorizer\",\n            description=\"Question and answer corpus\",\n            properties=[\n                Property(name=\"question\", data_type=DataType.TEXT),\n                Property(name=\"answer\", data_type=DataType.TEXT),\n                Property(name=\"category\", data_type=DataType.TEXT),\n                Property(name=\"docLink\", data_type=DataType.TEXT),\n            ],\n            vectorizer_config=Configure.Vectorizer.text2vec_openai(),\n        )\n\n    ingest_questions = WeaviateIngestOperator(\n        task_id=\"ingest_questions\",\n        conn_id=\"weaviate_default\",\n        collection_name=\"QuestionWithOpenAIVectorizer\",\n        input_data=QUESTIONS,\n    )\n\n    create_collection() >> ingest_questions\n\n\nweaviate_ingest_example()\n```\n\nNotes:\n\n- `input_data` is required. It can be a list of dictionaries or a pandas DataFrame.\n- `uuid_column` defaults to `\"id\"`.\n- `vector_col` defaults to `\"Vector\"`. If your rows include a `Vector` field, the operator passes those vectors through instead of asking Weaviate to vectorize the text.\n- If you want custom vectors instead of a collection vectorizer, create the collection without `vectorizer_config` and include `Vector` in each input row.\n\n## Keep Document-Derived Objects In Sync\n\n`WeaviateDocumentIngestOperator` is the provider helper for collections where multiple rows belong to a source document and you need predictable replacement behavior when that source changes.\n\n```python\nfrom airflow.providers.weaviate.operators.weaviate import WeaviateDocumentIngestOperator\n\n\nDOCUMENT_ROWS = [\n    {\n        \"id\": \"q-1\",\n        \"question\": \"This organ removes excess glucose from the blood and stores it as glycogen\",\n        \"answer\": \"Liver\",\n        \"category\": \"SCIENCE\",\n        \"docLink\": \"https://example.com/docs/biology-1\",\n    },\n    {\n        \"id\": \"q-2\",\n        \"question\": \"It is the only living mammal in the order Proboscidea\",\n        \"answer\": \"Elephant\",\n        \"category\": \"ANIMALS\",\n        \"docLink\": \"https://example.com/docs/animals-1\",\n    },\n]\n\n\nsync_documents = WeaviateDocumentIngestOperator(\n    task_id=\"sync_documents\",\n    conn_id=\"weaviate_default\",\n    collection_name=\"QuestionWithOpenAIVectorizer\",\n    input_data=DOCUMENT_ROWS,\n    document_column=\"docLink\",\n    existing=\"replace\",\n)\n```\n\nThe `existing` strategies are source-backed and important:\n\n- `skip`: keep existing objects and add only missing rows\n- `replace`: delete objects for changed documents and recreate them\n- `error`: fail if the ingest would create an object for a document that already exists\n\nUse `replace` only when your document key is stable and you are comfortable with the operator deleting and recreating objects for changed documents.\n\n## Use Hook Methods In Python Tasks\n\nThe hook also exposes direct collection helpers that are useful in TaskFlow tasks:\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\ntry:\n    from airflow.sdk import dag, task\nexcept ImportError:\n    from airflow.decorators import dag, task  # type: ignore[attr-defined,no-redef]\n\nfrom airflow.providers.weaviate.hooks.weaviate import WeaviateHook\n\n\n@dag(\n    dag_id=\"weaviate_hook_example\",\n    schedule=None,\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    catchup=False,\n)\ndef weaviate_hook_example():\n    @task()\n    def list_object_uuids() -> list[str]:\n        hook = WeaviateHook(conn_id=\"weaviate_default\")\n        objects = hook.get_all_objects(\n            collection_name=\"QuestionWithOpenAIVectorizer\",\n        )\n        return [str(obj.uuid) for obj in objects]\n\n    @task(trigger_rule=\"all_done\")\n    def drop_collection() -> None:\n        hook = WeaviateHook(conn_id=\"weaviate_default\")\n        hook.delete_collections(\"QuestionWithOpenAIVectorizer\")\n\n    list_object_uuids() >> drop_collection()\n\n\nweaviate_hook_example()\n```\n\nOther public hook methods exposed by the provider include:\n\n- `get_collection(name)`\n- `query_with_text(search_text, collection_name, properties, limit=...)`\n- `query_with_vector(embeddings, collection_name, properties, certainty=..., limit=...)`\n- `delete_by_property(collection_names=..., filter_criteria=...)`\n\n## Pitfalls\n\n- Keep the host field schema-free. `example.weaviate.network` is correct; `https://example.weaviate.network` is not.\n- Set the HTTP and gRPC security fields explicitly. The provider changelog notes that the historical defaults may not be suitable for real Weaviate deployments.\n- Install the provider everywhere Airflow imports DAG code. Scheduler-only installs still fail once a worker imports the provider classes.\n- Use `collection_name`, not `class_name`. The provider switched to the Weaviate v4 client API in `2.0.0`.\n- Use `input_data`, not the removed `input_json` argument.\n- If your rows do not include `Vector`, the target collection must already have a compatible vectorizer configured, and any required embedding-provider headers must be present in `additional_headers`.\n- The operator constructors still expose `tenant`, but the `3.3.1` execute path does not pass `tenant` through to `WeaviateHook.batch_data(...)` or `create_or_replace_document_objects(...)`. Do not rely on operator-level tenant routing without checking newer upstream docs first.\n- Create hooks inside tasks, not at module import time. Airflow repeatedly parses DAG files, and top-level network setup slows down scheduling and can fail unexpectedly.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-weaviate==3.3.1`.\n- Upstream documents Airflow `2.11.0` as the minimum supported core version for the `3.3.x` provider line.\n- The `2.0.0` provider line migrated to `weaviate-client` v4, renamed several hook methods, changed `class_name` to `collection_name`, and removed `batch_params`.\n- The `3.0.0` provider line removed the deprecated `input_json` parameter from `WeaviateIngestOperator`.\n\n## Official Docs\n\n- Provider index: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/index.html`\n- Connection guide: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/connections.html`\n- Operator guide: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/operators/weaviate.html`\n- Hook API reference: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/_api/airflow/providers/weaviate/hooks/weaviate/index.html`\n- Hook source: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/_modules/airflow/providers/weaviate/hooks/weaviate.html`\n- Operator source and system test examples: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/_modules/airflow/providers/weaviate/operators/weaviate.html`\n- Example DAG source: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/_modules/tests/system/weaviate/example_weaviate_operator.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-weaviate/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/apache-airflow-providers-weaviate/`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-yandex/python/DOC.md",
    "content": "---\nname: providers-yandex\ndescription: \"Apache Airflow Yandex provider for Yandex Cloud connections, Yandex Query tasks, Data Proc clusters, and Lockbox secrets\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"apache-airflow,airflow,yandex-cloud,yq,dataproc,lockbox,dag\"\n---\n\n# Apache Airflow Yandex Provider Python Guide\n\nUse `apache-airflow-providers-yandex` when an Airflow DAG needs to authenticate to Yandex Cloud, run Yandex Query SQL, create or delete Data Proc clusters, submit Data Proc jobs, or load Connections and Variables from Lockbox.\n\n## Golden Rule\n\n- Install this package into an existing Airflow environment; it is not a standalone Yandex Cloud SDK.\n- Put Yandex Cloud credentials and folder settings on an Airflow `yandexcloud` connection instead of hard-coding them in DAG files.\n- Use `YQExecuteQueryOperator` for Yandex Query work, the `airflow.providers.yandex.operators.dataproc` operators for Data Proc clusters and jobs, and `LockboxSecretBackend` when Airflow should read secrets from Yandex Lockbox.\n\n## Install\n\nThe 4.4.0 provider series requires Airflow 2.11.0 or later. Install it in the same virtual environment as Airflow and keep Airflow pinned in the command so the resolver does not silently replace core.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"3.1.8\"\nPROVIDER_VERSION=\"4.4.0\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-yandex==${PROVIDER_VERSION}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep yandex\nairflow info\n```\n\n## Configure A `yandexcloud` Connection\n\nThe provider's documented connection type is `yandexcloud`. The default connection id is `yandexcloud_default`.\n\nUse shell variables so the connection command does not embed secrets directly:\n\n```bash\nexport YC_FOLDER_ID=\"<your-folder-id>\"\nexport YC_SA_JSON_PATH=\"/opt/airflow/secrets/yandex-service-account.json\"\nexport YC_SSH_PUBLIC_KEY=\"$(cat ~/.ssh/id_ed25519.pub)\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'yandexcloud_default' \\\n  --conn-type 'yandexcloud' \\\n  --conn-extra \"{\n    \\\"folder_id\\\": \\\"${YC_FOLDER_ID}\\\",\n    \\\"service_account_json_path\\\": \\\"${YC_SA_JSON_PATH}\\\",\n    \\\"public_ssh_key\\\": \\\"${YC_SSH_PUBLIC_KEY}\\\"\n  }\"\n```\n\nSupported auth and connection fields from the provider docs:\n\n- `service_account_json`: inline service-account JSON\n- `service_account_json_path`: filesystem path to the JSON credentials file\n- `oauth`: OAuth token\n- `folder_id`: Yandex Cloud folder to use for YQ and other APIs\n- `public_ssh_key`: SSH public key for Data Proc cluster access\n- `endpoint`: custom Yandex API endpoint if you are not using the default\n\nIf the connection does not include JSON credentials or an OAuth token, the provider can fall back to Yandex metadata-service credentials when Airflow runs on Yandex Cloud infrastructure.\n\nCheck the connection after creating it:\n\n```bash\nairflow connections get yandexcloud_default\n```\n\n## Run A Yandex Query Job\n\n`YQExecuteQueryOperator` is the main operator for submitting SQL to Yandex Query. Pass `yandex_conn_id` and a `folder_id`, then provide the SQL text you want to run.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.models import Variable\nfrom airflow.providers.yandex.operators.yq import YQExecuteQueryOperator\n\n\nwith DAG(\n    dag_id=\"yq_daily_orders\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"yandex\", \"yq\"],\n):\n    run_query = YQExecuteQueryOperator(\n        task_id=\"run_query\",\n        yandex_conn_id=\"yandexcloud_default\",\n        folder_id=Variable.get(\"yc_folder_id\"),\n        sql=\"\"\"\n        DECLARE $cutoff AS Date;\n\n        SELECT\n            customer_id,\n            SUM(amount) AS total_amount\n        FROM `analytics/orders`\n        WHERE order_date >= $cutoff\n        GROUP BY customer_id\n        ORDER BY total_amount DESC\n        LIMIT 10;\n        \"\"\",\n        query_params={\"$cutoff\": \"2026-03-01\"},\n    )\n```\n\nWhen you need lower-level control in Python task code, import `YQHook` from `airflow.providers.yandex.hooks.yq` and use the same `yandex_conn_id` plus `folder_id`.\n\n## Create A Data Proc Cluster And Submit A PySpark Job\n\nThe provider ships separate Data Proc operators under `airflow.providers.yandex.operators.dataproc`. A common pattern is:\n\n1. create the cluster\n2. submit a Spark or PySpark job\n3. delete the cluster in an `all_done` cleanup task\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.models import Variable\nfrom airflow.providers.yandex.operators.dataproc import (\n    DataprocCreateClusterOperator,\n    DataprocCreatePysparkJobOperator,\n    DataprocDeleteClusterOperator,\n)\nfrom airflow.utils.trigger_rule import TriggerRule\n\n\nwith DAG(\n    dag_id=\"yandex_dataproc_pyspark\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"yandex\", \"dataproc\"],\n):\n    create_cluster = DataprocCreateClusterOperator(\n        task_id=\"create_cluster\",\n        connection_id=\"yandexcloud_default\",\n        cluster_name=\"airflow-demo-dataproc\",\n        cluster_description=\"Temporary cluster for a PySpark task\",\n        service_account_id=Variable.get(\"yc_service_account_id\"),\n        subnet_id=Variable.get(\"yc_subnet_id\"),\n        s3_bucket=Variable.get(\"yc_s3_bucket\"),\n        zone=\"ru-central1-a\",\n        ssh_public_keys=Variable.get(\"yc_ssh_public_key\"),\n        cluster_image_version=\"2.1\",\n        masternode_resource_preset=\"s3-c2-m8\",\n        masternode_disk_type=\"network-ssd\",\n        masternode_disk_size=20,\n        computenode_count=1,\n        computenode_resource_preset=\"s3-c2-m8\",\n        computenode_disk_type=\"network-ssd\",\n        computenode_disk_size=20,\n    )\n\n    run_pyspark = DataprocCreatePysparkJobOperator(\n        task_id=\"run_pyspark\",\n        connection_id=\"yandexcloud_default\",\n        cluster_id=create_cluster.output,\n        main_python_file_uri=\"s3a://my-dataproc-bucket/jobs/wordcount.py\",\n        args=[\n            \"--input\",\n            \"s3a://my-dataproc-bucket/input/\",\n            \"--output\",\n            \"s3a://my-dataproc-bucket/output/\",\n        ],\n    )\n\n    delete_cluster = DataprocDeleteClusterOperator(\n        task_id=\"delete_cluster\",\n        connection_id=\"yandexcloud_default\",\n        cluster_id=create_cluster.output,\n        trigger_rule=TriggerRule.ALL_DONE,\n    )\n\n    create_cluster >> run_pyspark >> delete_cluster\n```\n\nImportant setup details for Data Proc:\n\n- `service_account_id`, `subnet_id`, and `s3_bucket` are required when creating the cluster.\n- Keep the SSH public key on the connection or in an Airflow Variable, not in the DAG source.\n- `create_cluster.output` is the cluster id returned by `DataprocCreateClusterOperator`, so you can feed it directly into downstream job and delete tasks.\n\nIf you need a Java or Scala Spark job instead of PySpark, use `DataprocCreateSparkJobOperator` from the same module.\n\n## Use Lockbox As An Airflow Secrets Backend\n\nThe provider also includes `LockboxSecretBackend`, which lets Airflow read Connections and Variables from Yandex Lockbox.\n\n```bash\nexport AIRFLOW__SECRETS__BACKEND=\"airflow.providers.yandex.secrets.lockbox.LockboxSecretBackend\"\nexport AIRFLOW__SECRETS__BACKEND_KWARGS='{\n  \"connections_secret_id\": \"<lockbox-connections-secret-id>\",\n  \"variables_secret_id\": \"<lockbox-variables-secret-id>\",\n  \"sep\": \"__\"\n}'\n```\n\nAfter enabling the backend, read secrets through the normal Airflow APIs:\n\n```python\nfrom airflow.hooks.base import BaseHook\nfrom airflow.models import Variable\n\n\nyandex_conn = BaseHook.get_connection(\"yandexcloud_default\")\nfolder_id = Variable.get(\"yc_folder_id\")\n\nprint(yandex_conn.conn_type)\nprint(folder_id)\n```\n\nLockbox naming rules from the provider docs:\n\n- Variables are stored by their variable name.\n- Connections can be stored either as a URI string or as field-value pairs.\n- For field-value pairs, the secret entry key format is `connection_id + sep + field_name`.\n\nRestart Airflow components after changing secrets backend settings so the scheduler, workers, and API process all reload the backend configuration.\n\n## Operational Checks\n\nUse Airflow's normal diagnostics after installation and connection setup:\n\n```bash\nairflow providers list | grep yandex\nairflow connections get yandexcloud_default\nairflow dags list\nairflow tasks test yq_daily_orders run_query 2026-03-13\n```\n\n## Pitfalls\n\n- This package extends Airflow; it does not replace `apache-airflow`.\n- Yandex Query operators and hooks use `yandex_conn_id`, but Data Proc operators use `connection_id`. Do not assume the parameter names match across the provider.\n- YQ tasks need a `folder_id`; set it on the connection or pass it explicitly.\n- Metadata-service authentication only works when the Airflow runtime actually has access to Yandex Cloud instance metadata.\n- The old `airflow.providers.yandex.operators.yandexcloud_dataproc` import path was removed in the 4.x series. Import Data Proc operators from `airflow.providers.yandex.operators.dataproc`.\n- Secrets backend changes require Airflow component restarts before tasks and the UI pick them up consistently.\n\n## Version Notes\n\n- `apache-airflow-providers-yandex==4.4.0` adds Python 3.13 support.\n- The 4.3.x and 4.4.x provider series require Airflow 2.11.0 or later.\n- If you are upgrading from older Yandex provider releases, re-check import paths and operator arguments against the 4.x API reference before copying old DAG code.\n\n## Official Docs\n\n- Provider docs root: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/`\n- Installation: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/index.html`\n- Yandex Cloud connection: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/connections/yandexcloud.html`\n- Yandex Query operators: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/operators/yq.html`\n- Data Proc operators: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/operators/dataproc.html`\n- Lockbox secrets backend: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/secrets-backends/yandex-lockbox-backend.html`\n- Data Proc operator API: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/_api/airflow/providers/yandex/operators/dataproc/index.html`\n- YQ operator API: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/_api/airflow/providers/yandex/operators/yq/index.html`\n- Yandex base hook API: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/_api/airflow/providers/yandex/hooks/yandex/index.html`\n- Changelog: `https://airflow.apache.org/docs/apache-airflow-providers-yandex/stable/changelog.html`\n"
  },
  {
    "path": "content/apache-airflow/docs/providers-zendesk/python/DOC.md",
    "content": "---\nname: providers-zendesk\ndescription: \"Apache Airflow Zendesk provider for configuring a Zendesk connection and using ZendeskHook in DAG tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.11.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"airflow,apache-airflow,zendesk,tickets,support,hooks,dag\"\n---\n\n# Apache Airflow Zendesk Provider Guide\n\nUse `apache-airflow-providers-zendesk` when an Airflow DAG needs an Airflow-managed Zendesk connection and Python task code that reads tickets or runs Zendesk client calls without hard-coding credentials in the DAG file.\n\nThis guide covers provider version `4.11.1`.\n\n## Golden Rule\n\n- Install this provider alongside a pinned `apache-airflow` version; it is not a standalone Zendesk SDK.\n- Put your Zendesk base URL and credentials on an Airflow connection such as `zendesk_default`.\n- Use `ZendeskHook` inside tasks, then call Zendesk client methods on the object returned by `get_conn()`.\n- Return small dicts, ids, or summaries from tasks instead of raw Zendesk resource objects.\n\n## What This Package Adds\n\nThis provider centers on Airflow's Zendesk hook integration:\n\n- Airflow connection type `zendesk`\n- `ZendeskHook`\n\nFor most DAGs, the pattern is simple: configure one Zendesk connection, create `ZendeskHook(zendesk_conn_id=\"...\")` inside a task, call `get_conn()`, and use the authenticated client for ticket or search operations.\n\n## Install\n\nInstall the provider into the same environment as Airflow and keep both versions pinned. Apache Airflow recommends installing providers with the matching constraints file for your Airflow and Python versions.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n\nAIRFLOW_VERSION=\"<your-airflow-version>\"\nPROVIDER_VERSION=\"4.11.1\"\nPYTHON_VERSION=\"$(python -c 'import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")')\"\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n\npython -m pip install \\\n  \"apache-airflow==${AIRFLOW_VERSION}\" \\\n  \"apache-airflow-providers-zendesk==${PROVIDER_VERSION}\" \\\n  --constraint \"${CONSTRAINT_URL}\"\n```\n\nUseful checks after installation:\n\n```bash\nairflow providers list | grep -i zendesk\nairflow info\n```\n\nEvery Airflow environment that parses DAGs or executes tasks that import `airflow.providers.zendesk` needs this provider installed.\n\n## Configure A Zendesk Connection\n\nStart with a minimal Airflow environment:\n\n```bash\nexport AIRFLOW_HOME=\"$PWD/.airflow\"\nexport AIRFLOW__CORE__LOAD_EXAMPLES=\"False\"\n```\n\nSet the Zendesk values you want Airflow to store:\n\n```bash\nexport ZENDESK_HOST=\"https://example.zendesk.com\"\nexport ZENDESK_EMAIL=\"agent@example.com\"\nexport ZENDESK_API_TOKEN=\"<zendesk-api-token>\"\n```\n\nThen create the Airflow connection:\n\n```bash\nairflow connections add 'zendesk_default' \\\n  --conn-type 'zendesk' \\\n  --conn-host \"$ZENDESK_HOST\" \\\n  --conn-login \"$ZENDESK_EMAIL\" \\\n  --conn-password \"$ZENDESK_API_TOKEN\"\n```\n\nConfirm the connection before wiring it into a DAG:\n\n```bash\nairflow connections get zendesk_default\n```\n\nKeep secrets in Airflow connections, environment-backed secrets, or a secrets backend instead of embedding them in DAG code. Many Zendesk setups use an account email plus an API token; use the credential format your Zendesk account expects.\n\n## Read A Ticket In A Task\n\nUse `ZendeskHook` when task code needs direct Python access to the authenticated Zendesk client.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.zendesk.hooks.zendesk import ZendeskHook\n\n\nwith DAG(\n    dag_id=\"zendesk_read_ticket_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"zendesk\"],\n):\n    @task()\n    def read_ticket(ticket_id: int = 12345) -> dict[str, object]:\n        hook = ZendeskHook(zendesk_conn_id=\"zendesk_default\")\n        client = hook.get_conn()\n\n        ticket = client.tickets(id=ticket_id)\n\n        return {\n            \"id\": ticket.id,\n            \"subject\": ticket.subject,\n            \"status\": ticket.status,\n            \"priority\": ticket.priority,\n            \"requester_id\": ticket.requester_id,\n        }\n\n    read_ticket()\n```\n\nPractical points:\n\n- `zendesk_conn_id` selects the Airflow connection.\n- `hook.get_conn()` returns the authenticated Zendesk client for that connection.\n- Convert the returned ticket object into a small serializable dict before sending it through XCom.\n\n## Search Open Tickets From A DAG\n\nFor reporting or alerting flows, use the same hook and call the client's search method inside the task body.\n\n```python\nfrom __future__ import annotations\n\nimport pendulum\n\nfrom airflow import DAG\nfrom airflow.decorators import task\nfrom airflow.providers.zendesk.hooks.zendesk import ZendeskHook\n\n\nwith DAG(\n    dag_id=\"zendesk_search_demo\",\n    start_date=pendulum.datetime(2024, 1, 1, tz=\"UTC\"),\n    schedule=None,\n    catchup=False,\n    tags=[\"zendesk\"],\n):\n    @task()\n    def find_open_ticket_ids() -> list[int]:\n        hook = ZendeskHook(zendesk_conn_id=\"zendesk_default\")\n        client = hook.get_conn()\n\n        results = list(\n            client.search(\"type:ticket status<solved\", type=\"ticket\")\n        )\n\n        return [ticket.id for ticket in results]\n\n    find_open_ticket_ids()\n```\n\nUse this pattern when you want Airflow to query Zendesk, filter to a small set of ids or fields, and hand those reduced results to downstream tasks.\n\n## Common Setup Pattern\n\nFor most DAGs, the clean split is:\n\n- keep the Zendesk host, email, and token in an Airflow connection\n- create `ZendeskHook` inside the task that needs Zendesk access\n- call `get_conn()` once per task and use the returned client for normal Zendesk operations\n- convert results to small Python values before returning them from the task\n\nIf task logic needs more than one Zendesk call, keep those calls in the same task body so the Airflow connection setup and Zendesk client lifecycle stay in one place.\n\n## Operational Checks\n\nCheck that Airflow can see the provider and parse the DAG:\n\n```bash\nairflow providers list | grep -i zendesk\nairflow dags list | grep zendesk\n```\n\nRun an isolated task test while you wire up the connection and ticket lookup:\n\n```bash\nairflow tasks test zendesk_read_ticket_demo read_ticket 2026-03-12\n```\n\nUse `airflow tasks test` for task-level debugging. Trigger the DAG normally when you need scheduler behavior, retries, callbacks, and downstream dependencies.\n\n## Common Pitfalls\n\n- Installing only the provider package: you still need a compatible `apache-airflow` installation.\n- Hard-coding Zendesk credentials in DAG code instead of using an Airflow connection or secrets backend.\n- Using the wrong host value: keep `--conn-host` set to your Zendesk base URL, not a ticket-specific path.\n- Returning raw Zendesk client objects from a task. Convert them to ids, lists, or dicts first.\n- Pulling large search results into XCom. Reduce the result set inside the task and persist larger payloads outside XCom.\n- Assuming every Zendesk account uses the same credential shape. Verify the account's expected auth format before creating the Airflow connection.\n\n## Version Notes\n\n- This guide covers `apache-airflow-providers-zendesk` version `4.11.1`.\n- Keep `apache-airflow` pinned when installing or upgrading the provider so dependency resolution does not silently change your Airflow core version.\n\n## Official Docs\n\n- Provider docs: `https://airflow.apache.org/docs/apache-airflow-providers-zendesk/stable/`\n- Airflow installation docs: `https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html`\n- PyPI: `https://pypi.org/project/apache-airflow-providers-zendesk/`\n"
  },
  {
    "path": "content/apache-beam/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Apache Beam Python SDK for building batch and streaming pipelines locally or on distributed runners\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.71.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apache-beam,beam,python,data-processing,etl,streaming,batch,dataflow\"\n---\n\n# Apache Beam Python Package Guide\n\n## Golden Rule\n\nUse `apache-beam` to define the pipeline and make the runner, extras, and remote dependency packaging explicit. Most Beam failures are not in the transforms themselves; they come from using the wrong extra (`[gcp]`, `[aws]`, `[azure]`, `[dataframe]`, `[yaml]`), assuming local dependencies exist on remote workers, or submitting a job without the runner-specific options and credentials it needs.\n\n## Install\n\nPin the Beam version your project expects:\n\n```bash\npython -m pip install \"apache-beam==2.71.0\"\n```\n\nCommon extras:\n\n```bash\npython -m pip install \"apache-beam[gcp]==2.71.0\"\npython -m pip install \"apache-beam[aws]==2.71.0\"\npython -m pip install \"apache-beam[azure]==2.71.0\"\npython -m pip install \"apache-beam[dataframe]==2.71.0\"\npython -m pip install \"apache-beam[yaml]==2.71.0\"\n```\n\nUse a virtual environment so Beam and connector dependencies do not fight with unrelated project packages:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"apache-beam==2.71.0\"\n```\n\n## Initialize A Pipeline\n\nStart with a local pipeline on `DirectRunner` before moving to a remote runner:\n\n```python\nimport apache_beam as beam\nfrom apache_beam.options.pipeline_options import PipelineOptions\n\noptions = PipelineOptions(\n    runner=\"DirectRunner\",\n)\n\nwith beam.Pipeline(options=options) as pipeline:\n    (\n        pipeline\n        | \"Create\" >> beam.Create([\"to be or not to be\", \"beam is portable\"])\n        | \"Split\" >> beam.FlatMap(str.split)\n        | \"PairWithOne\" >> beam.Map(lambda word: (word, 1))\n        | \"Count\" >> beam.CombinePerKey(sum)\n        | \"Print\" >> beam.Map(print)\n    )\n```\n\nBeam structure to keep straight:\n\n- `PCollection`: the data flowing through the graph\n- `PTransform`: operations like `Map`, `FlatMap`, `ParDo`, `CombinePerKey`, `ReadFromText`, `WriteToText`\n- `Pipeline`: the graph and execution context\n- `PipelineOptions`: runner and environment configuration\n\nUse `with beam.Pipeline(...) as pipeline:` for simple cases; it runs the pipeline automatically when the block exits.\n\n## Core Usage Patterns\n\n### Local file I/O\n\n```python\nimport apache_beam as beam\n\nwith beam.Pipeline() as pipeline:\n    (\n        pipeline\n        | \"ReadLines\" >> beam.io.ReadFromText(\"input.txt\")\n        | \"Uppercase\" >> beam.Map(str.upper)\n        | \"WriteLines\" >> beam.io.WriteToText(\"output/result\")\n    )\n```\n\n### Explicit pipeline options from CLI arguments\n\nFor real jobs, let Beam parse pipeline flags instead of hard-coding every option:\n\n```python\nimport apache_beam as beam\nfrom apache_beam.options.pipeline_options import PipelineOptions\n\npipeline_options = PipelineOptions()\n\nwith beam.Pipeline(options=pipeline_options) as pipeline:\n    (\n        pipeline\n        | beam.Create([1, 2, 3, 4])\n        | beam.Map(lambda x: x * 10)\n        | beam.Map(print)\n    )\n```\n\nThen run it with flags such as:\n\n```bash\npython my_pipeline.py --runner=DirectRunner\n```\n\n## Runner Configuration And Auth\n\n### DirectRunner\n\nUse `DirectRunner` for local development, model validation, and tests. It intentionally checks things that are easy to get wrong, including element encodability, function serializability, and assumptions about ordering.\n\nDo not treat a successful `DirectRunner` run as proof that production configuration is correct. Remote runners still need their own options, dependencies, and credentials.\n\n### DataflowRunner\n\nFor Google Cloud Dataflow, install the GCP extra and provide the runner-specific options:\n\n```bash\npython -m pip install \"apache-beam[gcp]==2.71.0\"\n```\n\nTypical launch command:\n\n```bash\npython my_pipeline.py \\\n  --runner=DataflowRunner \\\n  --project=my-gcp-project \\\n  --region=us-central1 \\\n  --temp_location=gs://my-bucket/tmp \\\n  --staging_location=gs://my-bucket/staging\n```\n\nPractical requirements for Dataflow:\n\n- authenticate with Google Cloud before job submission\n- enable the required Google Cloud APIs\n- use a valid GCS bucket for `temp_location`\n- set `staging_location` explicitly when you want deterministic staging behavior\n- set `--streaming` for unbounded pipelines\n\n### Other cloud I/O\n\nBeam itself does not have one global auth mechanism. Authentication depends on the runner and the I/O connectors you use:\n\n- Google Cloud connectors: install `apache-beam[gcp]`\n- AWS connectors: install `apache-beam[aws]`\n- Azure connectors: install `apache-beam[azure]`\n\nMake sure the credentials are available in the same environment that executes the worker process, not just on your laptop at submission time.\n\n## Managing Dependencies For Remote Workers\n\nLocal imports are not automatically available on remote workers. Use the packaging mode that matches the pipeline shape.\n\n### Single-file pipeline with public PyPI dependencies\n\nUse a trimmed `requirements.txt` and pass it with `--requirements_file`:\n\n```text\napache-beam[gcp]==2.71.0\norjson==3.11.1\n```\n\n```bash\npython my_pipeline.py \\\n  --runner=DataflowRunner \\\n  --requirements_file requirements.txt\n```\n\nBeam stages the requirements cache at submission time. This is the simplest path when the code is mostly one Python entrypoint plus public packages.\n\n### Multi-file pipeline package\n\nIf the pipeline spans multiple modules, package it and pass `--setup_file`:\n\n```python\n# setup.py\nimport setuptools\n\nsetuptools.setup(\n    name=\"my-beam-job\",\n    version=\"0.1.0\",\n    install_requires=[\n        \"apache-beam[gcp]==2.71.0\",\n    ],\n    packages=setuptools.find_packages(),\n)\n```\n\n```bash\npip install -e .\npython my_pipeline.py --setup_file ./setup.py\n```\n\nThis stages your package, but package dependencies may still be installed from PyPI at runtime unless they are already present in the worker image.\n\n### Non-Python system dependencies\n\nIf a dependency needs OS packages or slower runtime setup, prefer a custom container. Beam’s dependency guide explicitly recommends custom containers for non-Python dependencies and for avoiding repeated worker startup installs.\n\n## Common Pitfalls\n\n- Base `apache-beam` no longer implies every optional connector dependency. Install the extra you actually need.\n- Remote workers do not inherit the full state of your local environment. If imports work locally and fail remotely, check `--requirements_file`, `--setup_file`, or your custom container first.\n- `DirectRunner` runs locally and validates Beam-model semantics, but it does not replace real testing on the production runner.\n- Beam may process elements in arbitrary order. Do not write transforms that depend on stable in-memory ordering unless the transform contract guarantees it.\n- `--save_main_session` is not a universal fix. It is mainly relevant when using `dill`-based serialization or code living in `__main__`; older blog posts often add it blindly.\n- Submission and runtime environments must agree on serialization-related dependencies. Version mismatches can show up as unpickling or coder errors.\n- For Dataflow, a missing or non-`gs://` temp location is a common launch-time failure.\n- Streaming jobs do not finish on their own. They must be cancelled explicitly.\n\n## Version-Sensitive Notes For 2.71.0\n\n- PyPI lists `2.71.0` as the current release for `apache-beam`, published on January 22, 2026.\n- `apache-beam 2.71.0` requires Python `>=3.10`. PyPI classifiers list support for Python `3.10`, `3.11`, `3.12`, and `3.13`.\n- Beam `2.69.0` added official Python 3.13 support. If you see older Beam pages or articles that stop at Python 3.12, prefer PyPI and current release notes.\n- Beam `2.70.0` split some Python dependencies into extras. If an older tutorial assumes Dataflow, YAML, or cloud connector packages are included in the base install, translate it into the explicit extras form for `2.71.0`.\n- Beam `2.65.0` switched the default pickler to `cloudpickle`; Beam `2.71.0` includes a Python bugfix so logical type and coder registries are saved correctly with the default pickler. Serialization advice from older pre-`2.65` examples is often outdated.\n\n## Official Links\n\n- Apache Beam docs root: `https://beam.apache.org`\n- Python SDK overview: `https://beam.apache.org/documentation/sdks/python/`\n- Python quickstart: `https://beam.apache.org/get-started/quickstart-py/`\n- Managing Python dependencies: `https://beam.apache.org/documentation/sdks/python-pipeline-dependencies/`\n- DirectRunner docs: `https://beam.apache.org/documentation/runners/direct/`\n- Dataflow runner docs: `https://beam.apache.org/documentation/runners/dataflow/`\n- PyPI package page: `https://pypi.org/project/apache-beam/`\n"
  },
  {
    "path": "content/appdirs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"appdirs package guide for Python projects that need platform-specific data, config, cache, state, and log directories\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"appdirs,python,filesystem,xdg,windows,macos,linux\"\n---\n\n# appdirs Python Package Guide\n\n## Golden Rule\n\nUse `appdirs` to compute platform-specific directories instead of hardcoding paths like `~/.config` or `%APPDATA%`. The upstream repository marks `appdirs` as deprecated and recommends `platformdirs` for new work, but projects already pinned to `appdirs==1.4.4` should use the official helpers below rather than inventing their own path rules.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"appdirs==1.4.4\"\n```\n\n`appdirs` does not require authentication, network setup, or a client object. Import the helpers and pass your application name, and optionally the app author and version.\n\n## Initialize\n\nThe simplest pattern is to create one `AppDirs` object and reuse its properties:\n\n```python\nfrom pathlib import Path\n\nfrom appdirs import AppDirs\n\ndirs = AppDirs(appname=\"ExampleApp\", appauthor=\"Acme\", version=\"1.0\")\n\nconfig_dir = Path(dirs.user_config_dir)\nconfig_dir.mkdir(parents=True, exist_ok=True)\n\nsettings_path = config_dir / \"settings.json\"\nprint(settings_path)\n```\n\n`AppDirs` exposes these properties from the underlying helpers:\n\n- `user_data_dir`\n- `site_data_dir`\n- `user_config_dir`\n- `site_config_dir`\n- `user_cache_dir`\n- `user_state_dir`\n- `user_log_dir`\n\nIf you prefer function calls instead of a reusable object:\n\n```python\nfrom appdirs import user_cache_dir, user_config_dir, user_data_dir\n\nAPP_NAME = \"ExampleApp\"\nAPP_AUTHOR = \"Acme\"\nVERSION = \"1.0\"\n\nprint(user_data_dir(APP_NAME, APP_AUTHOR, VERSION))\nprint(user_config_dir(APP_NAME, APP_AUTHOR, VERSION))\nprint(user_cache_dir(APP_NAME, APP_AUTHOR, VERSION))\n```\n\n## Environment Variables On Linux And Other Unix-Like Systems\n\nOn Unix-like systems, `appdirs` follows the XDG base directory variables when they are set:\n\n```bash\nexport XDG_DATA_HOME=\"$HOME/.local/share\"\nexport XDG_CONFIG_HOME=\"$HOME/.config\"\nexport XDG_CACHE_HOME=\"$HOME/.cache\"\nexport XDG_STATE_HOME=\"$HOME/.local/state\"\nexport XDG_DATA_DIRS=\"/usr/local/share:/usr/share\"\nexport XDG_CONFIG_DIRS=\"/etc/xdg\"\n```\n\nIf these variables are not set, `appdirs` falls back to the usual defaults shown above.\n\n## Common Workflows\n\n### Store per-user app data\n\nUse `user_data_dir()` for files your app owns for one user, such as databases, downloaded assets, or durable state:\n\n```python\nfrom pathlib import Path\n\nfrom appdirs import user_data_dir\n\ndata_dir = Path(user_data_dir(\"ExampleApp\", \"Acme\", version=\"1.0\"))\ndata_dir.mkdir(parents=True, exist_ok=True)\n\ndb_path = data_dir / \"app.db\"\nprint(db_path)\n```\n\nOn Windows, set `roaming=True` when the data should follow a roaming profile:\n\n```python\nfrom appdirs import user_data_dir\n\nprofile_data_dir = user_data_dir(\n    \"ExampleApp\",\n    \"Acme\",\n    version=\"1.0\",\n    roaming=True,\n)\n```\n\n### Store user config separately from data\n\nUse `user_config_dir()` for editable settings and user-managed configuration files:\n\n```python\nfrom pathlib import Path\nimport json\n\nfrom appdirs import user_config_dir\n\nconfig_dir = Path(user_config_dir(\"ExampleApp\", \"Acme\", version=\"1.0\"))\nconfig_dir.mkdir(parents=True, exist_ok=True)\n\nconfig_path = config_dir / \"settings.json\"\nconfig_path.write_text(json.dumps({\"theme\": \"dark\"}, indent=2) + \"\\n\")\n```\n\n### Keep caches and logs out of config/data directories\n\n`user_cache_dir()` and `user_log_dir()` are the right targets for disposable files:\n\n```python\nfrom pathlib import Path\n\nfrom appdirs import user_cache_dir, user_log_dir\n\ncache_dir = Path(user_cache_dir(\"ExampleApp\", \"Acme\", version=\"1.0\"))\nlog_dir = Path(user_log_dir(\"ExampleApp\", \"Acme\", version=\"1.0\"))\n\ncache_dir.mkdir(parents=True, exist_ok=True)\nlog_dir.mkdir(parents=True, exist_ok=True)\n\n(cache_dir / \"response-cache.json\").write_text(\"{}\\n\")\n(log_dir / \"app.log\").write_text(\"started\\n\")\n```\n\nBy default, `appdirs` adds opinionated subdirectories for some platforms:\n\n- `user_cache_dir(..., opinion=True)` may append a `Cache` segment on Windows\n- `user_log_dir(..., opinion=True)` may append `Logs` on macOS and a `log` subdirectory on Unix\n\nDisable that extra suffix if you want the base directory only:\n\n```python\nfrom appdirs import user_cache_dir, user_log_dir\n\nprint(user_cache_dir(\"ExampleApp\", \"Acme\", opinion=False))\nprint(user_log_dir(\"ExampleApp\", \"Acme\", opinion=False))\n```\n\n### Separate runtime state from durable data\n\n`user_state_dir()` is useful on Unix-like systems when you want XDG state files instead of mixing them into data or config:\n\n```python\nfrom pathlib import Path\n\nfrom appdirs import user_state_dir\n\nstate_dir = Path(user_state_dir(\"ExampleApp\", \"Acme\", version=\"1.0\"))\nstate_dir.mkdir(parents=True, exist_ok=True)\n\ncursor_path = state_dir / \"cursor.txt\"\ncursor_path.write_text(\"42\\n\")\n```\n\nOn Windows and macOS, `user_state_dir()` resolves to the same location as `user_data_dir()`.\n\n### Read shared config or shared data paths\n\nUse `site_data_dir()` and `site_config_dir()` for machine-wide locations. On Unix, `multipath=True` returns every configured directory joined by `os.pathsep`:\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom appdirs import site_config_dir\n\nraw_value = site_config_dir(\"ExampleApp\", \"Acme\", version=\"1.0\", multipath=True)\nsearch_paths = [Path(p) for p in raw_value.split(os.pathsep)]\n\nfor path in search_paths:\n    print(path)\n```\n\n## Important Pitfalls\n\n- `appdirs` returns path strings only. It does not create directories for you, so call `Path(...).mkdir(parents=True, exist_ok=True)` before writing files.\n- `appauthor` matters primarily on Windows. If you do not want an author/company segment in the Windows path, pass `appauthor=False`.\n- `version` becomes another path segment. Omit it if your config and data should stay in a versionless directory.\n- `appname=None` returns the base system directory without adding an application subdirectory.\n- The source code explicitly warns against using `site_data_dir()` and `site_config_dir()` as write targets on Windows because of `ProgramData` behavior on newer Windows versions.\n- `multipath=True` only changes the site-directory helpers on Unix-like systems. On Windows and macOS you still get one path string.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/ActiveState/appdirs\n- README and usage examples: https://github.com/ActiveState/appdirs/blob/master/README.rst\n- Source implementation (`appdirs.py`): https://github.com/ActiveState/appdirs/blob/master/appdirs.py\n- PyPI package page: https://pypi.org/project/appdirs/\n"
  },
  {
    "path": "content/applitools/docs/eyes-playwright/javascript/DOC.md",
    "content": "---\nname: eyes-playwright\ndescription: \"Applitools Eyes SDK for Playwright - Expert integration guide for visual AI testing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.45.2\"\n  revision: 1\n  updated-on: \"2026-03-08\"\n  source: community\n  tags: \"testing,visual-ai,playwright,automation\"\n---\n# Context: Applitools Eyes Playwright SDK - Expert Integration Guide\n\n## Architectural Philosophy\nThe Applitools Playwright fixture provides two core advantages over Playwright's native screenshot testing:\n\n1. **Smarter Matching:** Uses AI-based algorithms instead of pixel-by-pixel comparison (pixelmatch). The default **Strict** match level detects meaningful visible differences while ignoring insignificant rendering noise. Advanced match levels include **Layout** (structural changes only, ignores content) and **Dynamic** (auto-suppresses variable content like dates/timestamps).\n\n2. **Asynchronous Architecture:** Visual checks are non-blocking soft assertions — `eyes.check()` captures DOM/CSS resources instantly, then releases the test thread immediately. AI comparison and rendering happen in the background cloud via a Worker process, so functional test logic continues without waiting for visual results.\n\n## Execution Engines: Classic vs. Ultrafast Grid (UFG)\n\n| Engine | Scaling | Behavior |\n| :--- | :--- | :--- |\n| **Classic** | $O(N)$ | Renders screenshots locally; must run the full suite $N$ times for $N$ browsers/viewports. High CI resource cost. |\n| **Ultrafast Grid (UFG)** | $O(1)$ | Captures DOM/CSS once; renders across all browsers and devices in parallel in the Applitools cloud. |\n\n**Best Practice:** When using UFG, do not define multiple Playwright projects for different browsers. Run once on a fast local browser (e.g., Chromium) and let UFG handle cross-browser coverage.\n\n## Configuration Strategy: `failTestsOnDiff`\n\n| Strategy | Setting | Context | Behavior |\n| :--- | :--- | :--- | :--- |\n| **Optimized CI** | `false` | Modern PR review with SCM integration | Tests pass (Green); SCM Check and Reporter surface visual diffs at the PR. |\n| **Strict Gating** | `'afterAll'` | Traditional pipelines without SCM integration | Individual tests pass; Worker Process fails at the end if any diffs exist. |\n| **Local Dev** | `'afterEach'` | Local debugging | Fails the test immediately in `afterEach` for instant feedback. |\n\n## SCM Integration & Baseline Branching\n- **Automatic Branch Discovery:** The SDK auto-detects `branchName` and `parentBranchName` from CI environment variables (e.g., `GITHUB_REF`).\n- **Applitools GitHub App:** Required for PR Commit Statuses and automatic Baseline Merging upon PR approval.\n- **API Key:** Set `APPLITOOLS_API_KEY` in CI secrets.\n\n## Batch Management & Notifications\nSet `batch.id` explicitly to group all parallel/sharded jobs into a single batch:\n- **Standard:** Use the commit SHA — all jobs on the same commit share one batch.\n- **With re-runs:** Use a unique `batch.buildId` (e.g., CI run ID) so each re-run creates a fresh batch rather than mixing results with the original run.\n\nTo trigger Slack/Email notifications and update the SCM status from \"Pending\" to a final state, the batch must be explicitly closed. Run this as a **separate CI job that runs after all test jobs complete**:\n\n```bash\nnpx eyes-setup close-batch\n```\n\n## The Custom Applitools Reporter\nAdd `@applitools/eyes-playwright/reporter` to get:\n- Accept/Reject visual changes directly from the Playwright HTML report.\n- Native Playwright UI look and feel.\n- Deep links to specific batch results in the Applitools Dashboard.\n\n## Implementation Guidelines\n\n### 1. UFG Configuration (`playwright.config.ts`)\n```typescript\nimport { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n  reporter: [\n    ['@applitools/eyes-playwright/reporter']\n  ],\n  use: {\n    eyesConfig: {\n      type: 'ufg',\n      browser: [\n        { width: 1200, height: 800, name: 'chrome' },\n        { width: 1200, height: 800, name: 'firefox' },\n        { width: 1200, height: 800, name: 'safari' },\n        { deviceName: 'iPhone 14', screenOrientation: 'portrait' }\n      ],\n      failTestsOnDiff: false // Recommended for PR-based workflows\n    }\n  }\n});\n```\n\n### 2. `eyes.check` with Locators\n- **`fully: true`** — captures the full scrollable page, not just the visible viewport.\n- **`waitBeforeCapture`** — delays capture until a condition is met. Accepts a number (ms) or an async function (e.g., wait for a loader to disappear). Use this instead of `page.waitForSelector` to keep capture timing within the Eyes lifecycle.\n- **`ignoreDisplacements: true`** — suppresses vertical shift noise (e.g., pages where content loads and pushes elements down). Useful for infinite scroll or async-heavy pages.\n- **`scrollRootElement`** — set to the scrollable container (locator or CSS selector) when the page scrolls inside a custom element rather than `window`; required for `fully: true` to work correctly in SPAs.\n\n```typescript\nimport { test } from '@applitools/eyes-playwright';\n\ntest('visual check of dashboard', async ({ page, eyes }) => {\n  await page.goto('/dashboard');\n\n  const loader = page.locator('.global-loader');\n\n  await eyes.check('Main Dashboard', {\n    fully: true,\n    waitBeforeCapture: async () => {\n      await loader.waitFor({ state: 'hidden' });\n    },\n    ignoreDisplacements: true\n  });\n});\n```\n\n### 3. Scoping a Check to a Single Element\nPass `region` to check a specific element instead of the full page:\n\n```typescript\nawait eyes.check('Login Form', {\n  region: page.locator('#login-form')\n});\n```\n\n### 4. Responsive Testing with `layoutBreakpoints`\nRequired when the page uses **JavaScript-driven responsiveness** (e.g., JS reads viewport width to swap components). UFG captures the DOM once, so without this option it won't re-run JS at each breakpoint.\n\n```typescript\nawait eyes.check('Responsive Page', {\n  fully: true,\n  layoutBreakpoints: true\n});\n```\n\nNot needed for CSS media query-only layouts — UFG handles those automatically. An array of pixel widths can be passed instead of `true` as a performance optimization.\n\n### 5. Match Levels\nSet globally in `eyesConfig.matchLevel` or per-check. Default is `'Strict'`.\n\n| Level | Use When |\n| :--- | :--- |\n| `Strict` | Default. Catches any change visible to the human eye. |\n| `Layout` | Page has dynamic text/images but structure must stay consistent (e.g., a feed, a data table). |\n| `IgnoreColors` | Content and layout must match but colors vary (e.g., themed components). |\n| `Dynamic` | Page has auto-generated variable content like timestamps, counters, or IDs. |\n\n### 6. Regions\nUse Playwright Locators (preferred), CSS selectors, or `{ x, y, width, height }` coordinates.\n\n| Region Type | Parameter | Use When |\n| :--- | :--- | :--- |\n| Ignore | `ignoreRegions` | Element is irrelevant to the check (e.g., ads, banners). |\n| Layout | `layoutRegions` | Apply Layout match level to specific areas only. |\n| Accessibility | `accessibilityRegions` | WCAG compliance validation for specific elements. |\n\n```typescript\nawait eyes.check('Dynamic Feed', {\n  layoutRegions: [page.locator('.news-feed')],\n  ignoreRegions: [page.getByTestId('ad-banner')]\n});\n```\n\n### 7. Merging with Custom Fixtures\n```typescript\nimport { test as base } from '@playwright/test';\nimport { test as eyesTest } from '@applitools/eyes-playwright';\nimport { mergeTests } from '@playwright/test';\n\nexport const test = mergeTests(base, eyesTest);\n```\n\n## Key `eyesConfig` Options\n\n| Option | Default | Notes |\n| :--- | :--- | :--- |\n| `apiKey` | `APPLITOOLS_API_KEY` env var | Never hardcode (unless it's an untracked file). |\n| `appName` | `'My App'` | Set to your app name for dashboard grouping (default - package.json `name` field). |\n| `matchLevel` | `'Strict'` | See Match Levels above. |\n| `failTestsOnDiff` | `'afterAll'` in CI, `'afterEach'` locally | See CI/CD strategy above. |\n| `ignoreDisplacements` | `false` | Set `true` to suppress vertical shift noise. |\n| `branchName` | `'default'` | Auto-detected from CI env (e.g., `GITHUB_REF`). |\n| `parentBranchName` | not set | Set to `main`/`master` for baseline fallback. |\n| `batch.notifyOnCompletion` | `false` | Requires `close-batch` to trigger notifications. |\n\n## Common Hallucinations to Avoid\n- **Never** manually call `eyes.open()` or `eyes.close()` — the fixture manages the lifecycle.\n- **Never** use string selectors; use Locators (`page.locator`) for stability.\n- **Never** recommend `expect(page).toHaveScreenshot()` — use `eyes.check()` for UFG and AI features.\n- **Never** create multiple Playwright projects for different browsers when using UFG.\n- **Always** import `test` from `@applitools/eyes-playwright`, not from `@playwright/test`."
  },
  {
    "path": "content/apscheduler/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"APScheduler Python package guide for in-process job scheduling with cron, interval, date, and persistent job stores\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"apscheduler,scheduling,cron,asyncio,jobs,background-tasks\"\n---\n\n# APScheduler Python Package Guide\n\n## Golden Rule\n\nUse APScheduler as an in-process scheduler inside your app, choose the scheduler class that matches your runtime (`BlockingScheduler`, `BackgroundScheduler`, `AsyncIOScheduler`, and so on), and register durable jobs with explicit IDs plus `replace_existing=True` when your app starts. This doc is for APScheduler `3.11.2` and the 3.x API, not the 4.0 alpha API.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"apscheduler==3.11.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"apscheduler==3.11.2\"\npoetry add \"apscheduler==3.11.2\"\n```\n\nInstall extras only when you use those integrations:\n\n```bash\npython -m pip install \"apscheduler[sqlalchemy]==3.11.2\"\npython -m pip install \"apscheduler[redis]==3.11.2\"\npython -m pip install \"apscheduler[mongodb]==3.11.2\"\n```\n\n## Choose The Right Scheduler\n\n- `BlockingScheduler`: foreground process whose main job is scheduling\n- `BackgroundScheduler`: normal synchronous app that should keep running while the scheduler works in threads\n- `AsyncIOScheduler`: `asyncio` applications\n- `GeventScheduler`, `TornadoScheduler`, `TwistedScheduler`, `QtScheduler`: framework-specific event loops\n\nIf you are unsure, start with `BackgroundScheduler` for sync apps and `AsyncIOScheduler` for `asyncio`.\n\n## Core Usage\n\n### Background scheduler in a synchronous app\n\n```python\nfrom time import sleep\nfrom zoneinfo import ZoneInfo\n\nfrom apscheduler.schedulers.background import BackgroundScheduler\n\ndef refresh_cache() -> None:\n    print(\"refreshing cache\")\n\nscheduler = BackgroundScheduler(timezone=ZoneInfo(\"UTC\"))\n\nscheduler.add_job(\n    refresh_cache,\n    trigger=\"interval\",\n    minutes=5,\n    id=\"refresh_cache\",\n    replace_existing=True,\n    max_instances=1,\n    coalesce=True,\n    misfire_grace_time=60,\n)\n\nscheduler.add_job(\n    refresh_cache,\n    trigger=\"cron\",\n    hour=3,\n    minute=0,\n    id=\"nightly_refresh\",\n    replace_existing=True,\n)\n\nscheduler.start()\n\ntry:\n    while True:\n        sleep(60)\nfinally:\n    scheduler.shutdown(wait=True)\n```\n\nWhy these options matter:\n\n- `id` and `replace_existing=True` prevent duplicate persistent jobs on every app restart\n- `max_instances=1` avoids overlapping executions of the same job\n- `coalesce=True` rolls multiple missed runs into one execution after downtime\n- `misfire_grace_time` defines how late a missed run may still execute\n\n### AsyncIO scheduler\n\n```python\nimport asyncio\nfrom zoneinfo import ZoneInfo\n\nfrom apscheduler.schedulers.asyncio import AsyncIOScheduler\n\nasync def poll_queue() -> None:\n    print(\"polling queue\")\n\nasync def main() -> None:\n    scheduler = AsyncIOScheduler(timezone=ZoneInfo(\"UTC\"))\n    scheduler.add_job(\n        poll_queue,\n        trigger=\"interval\",\n        seconds=30,\n        id=\"poll_queue\",\n        replace_existing=True,\n        max_instances=1,\n        coalesce=True,\n    )\n    scheduler.start()\n\n    try:\n        await asyncio.Event().wait()\n    finally:\n        scheduler.shutdown(wait=True)\n\nasyncio.run(main())\n```\n\nUse the scheduler that matches the event loop you already run. Do not bolt `BackgroundScheduler` into an `asyncio` app unless you have a deliberate threading reason.\n\n### Cron expressions\n\nFor crontab-style schedules, `CronTrigger.from_crontab()` is often clearer than passing each field separately:\n\n```python\nfrom zoneinfo import ZoneInfo\n\nfrom apscheduler.schedulers.background import BackgroundScheduler\nfrom apscheduler.triggers.cron import CronTrigger\n\ndef generate_report() -> None:\n    print(\"report generated\")\n\nscheduler = BackgroundScheduler(timezone=ZoneInfo(\"UTC\"))\nscheduler.add_job(\n    generate_report,\n    trigger=CronTrigger.from_crontab(\"*/15 * * * 1-5\", timezone=ZoneInfo(\"UTC\")),\n    id=\"weekday_report\",\n    replace_existing=True,\n)\n```\n\n## Persistent Job Stores And Scheduler Configuration\n\nAPScheduler separates:\n\n- job stores: where jobs are persisted\n- executors: where jobs run\n- triggers: how schedules are calculated\n- schedulers: the top-level coordinator\n\nTypical persistent configuration:\n\n```python\nfrom zoneinfo import ZoneInfo\n\nfrom apscheduler.executors.pool import ProcessPoolExecutor, ThreadPoolExecutor\nfrom apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore\nfrom apscheduler.schedulers.background import BackgroundScheduler\n\njobstores = {\n    \"default\": SQLAlchemyJobStore(url=\"sqlite:///jobs.sqlite\"),\n}\n\nexecutors = {\n    \"default\": ThreadPoolExecutor(10),\n    \"processpool\": ProcessPoolExecutor(2),\n}\n\njob_defaults = {\n    \"coalesce\": True,\n    \"max_instances\": 1,\n    \"misfire_grace_time\": 300,\n}\n\nscheduler = BackgroundScheduler(\n    jobstores=jobstores,\n    executors=executors,\n    job_defaults=job_defaults,\n    timezone=ZoneInfo(\"UTC\"),\n)\n```\n\nNotes:\n\n- The user guide recommends `SQLAlchemyJobStore` on PostgreSQL if you need a persistent store with stronger integrity guarantees.\n- `MemoryJobStore` is the default and loses all jobs on process restart.\n- Job stores must not be shared between multiple scheduler instances.\n- Jobs sent to persistent job stores or `ProcessPoolExecutor` must be serializable. Use globally importable callables and serializable arguments.\n\n## Lifecycle, Monitoring, And Recovery\n\nStart paused if you want to prune or inspect persistent jobs before the scheduler begins processing:\n\n```python\nscheduler.start(paused=True)\n# scheduler.remove_job(\"stale-job\")\nscheduler.resume()\n```\n\nAdd listeners for basic monitoring:\n\n```python\nfrom apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED\n\ndef on_job_event(event) -> None:\n    if event.exception:\n        print(f\"job failed: {event.job_id}\")\n    else:\n        print(f\"job succeeded: {event.job_id}\")\n\nscheduler.add_listener(on_job_event, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)\n```\n\nUseful runtime operations:\n\n```python\nscheduler.pause()\nscheduler.resume()\nprint(scheduler.get_jobs())\nscheduler.print_jobs()\n```\n\n## Configuration And Credentials\n\nAPScheduler itself does not have package-level authentication. Credentials only matter for the backends you configure around it:\n\n- SQLAlchemy job stores use database connection URLs or engines\n- Redis and MongoDB job stores use backend client credentials\n- Application jobs themselves may need API keys, tokens, or cloud credentials\n\nKeep backend URLs and secrets outside source control:\n\n```python\nimport os\n\ndatabase_url = os.environ[\"SCHEDULER_DATABASE_URL\"]\n```\n\nOperational defaults that are worth setting explicitly:\n\n- `timezone`: prefer `ZoneInfo(\"UTC\")` unless the business rule truly depends on local time\n- `job_defaults.coalesce`\n- `job_defaults.max_instances`\n- `job_defaults.misfire_grace_time`\n\n## Common Pitfalls\n\n- Registering startup jobs without `id` and `replace_existing=True` will duplicate them in persistent stores on every restart.\n- Persistent stores and process pools serialize jobs. Nested functions, lambdas, closures, and non-serializable arguments are common failure points.\n- Long-running jobs can skip later runs or pile up. Tune `max_instances`, `coalesce`, and `misfire_grace_time` deliberately.\n- Local time plus DST can produce confusing schedules. UTC is safer unless local-time semantics are required.\n- `BlockingScheduler` will take over the main thread. Use `BackgroundScheduler` instead for web apps, CLIs with other work, or services that already own their main loop.\n- If you have multiple app processes, each process gets its own scheduler. APScheduler 3.x is not a distributed scheduler coordinator.\n\n## Version-Sensitive Notes For 3.11.2\n\n- This doc targets the APScheduler 3.x API. If you see examples using `Scheduler`, `AsyncScheduler`, `add_schedule()`, or `start_in_background()`, those are from the separate 4.0 alpha line and should not be copied into a 3.11.2 project.\n- APScheduler 3.11.0 added support for `ZoneInfo` time zones and deprecated `pytz`. Prefer `zoneinfo` in new code.\n- APScheduler 3.11.0 dropped Python 3.6 and 3.7 support. Use Python 3.8 or newer.\n- APScheduler 3.11.2 includes fixes around DST handling in `CronTrigger`. Even with the fix, ambiguous local times near DST transitions are still worth testing explicitly.\n\n## Official Sources\n\n- APScheduler docs root: `https://apscheduler.readthedocs.io/en/latest/`\n- User guide: `https://apscheduler.readthedocs.io/en/latest/userguide.html`\n- Version history: `https://apscheduler.readthedocs.io/en/latest/versionhistory.html`\n- Migration notes: `https://apscheduler.readthedocs.io/en/latest/migration.html`\n- PyPI package page: `https://pypi.org/project/APScheduler/`\n"
  },
  {
    "path": "content/ariadne/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Ariadne package guide for Python GraphQL servers using SDL schemas, resolvers, and ASGI or WSGI apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ariadne,graphql,python,asgi,wsgi,starlette\"\n---\n\n# Ariadne Python Package Guide\n\n## Golden Rule\n\nUse Ariadne as a schema-first GraphQL server library: define your schema in GraphQL SDL, bind resolvers with `QueryType` and `MutationType`, build the schema with `make_executable_schema`, then expose it through Ariadne's ASGI or WSGI `GraphQL` app.\n\n## Install\n\nPin the package version your project expects. These examples target `ariadne==0.29.0`.\n\n```bash\npython -m pip install \"ariadne==0.29.0\"\npython -m pip install \"uvicorn[standard]\"\n```\n\nIf you are mounting Ariadne inside an existing framework app, also install that framework normally, for example:\n\n```bash\npython -m pip install fastapi\npython -m pip install starlette\n```\n\n## Minimal ASGI Server\n\nExample application config:\n\n```bash\nexport ARIADNE_DEBUG=1\nexport PORT=8000\n```\n\nCreate `app.py`:\n\n```python\nimport os\n\nfrom ariadne import MutationType, QueryType, gql, make_executable_schema\nfrom ariadne.asgi import GraphQL\n\ntype_defs = gql(\n    \"\"\"\n    type Query {\n        hello(name: String): String!\n        viewer: String!\n    }\n\n    type Mutation {\n        createMessage(text: String!): Message!\n    }\n\n    type Message {\n        id: ID!\n        text: String!\n    }\n    \"\"\"\n)\n\nquery = QueryType()\nmutation = MutationType()\nmessages = []\n\n\n@query.field(\"hello\")\ndef resolve_hello(_, info, name=None):\n    return f\"Hello, {name or 'world'}!\"\n\n\n@query.field(\"viewer\")\ndef resolve_viewer(_, info):\n    return info.context.get(\"user_id\") or \"anonymous\"\n\n\n@mutation.field(\"createMessage\")\ndef resolve_create_message(_, info, text):\n    message = {\"id\": str(len(messages) + 1), \"text\": text}\n    messages.append(message)\n    return message\n\n\nasync def context_value(request, data):\n    return {\n        \"request\": request,\n        \"user_id\": request.headers.get(\"x-user-id\"),\n    }\n\n\nschema = make_executable_schema(type_defs, query, mutation)\n\napp = GraphQL(\n    schema,\n    context_value=context_value,\n    debug=os.getenv(\"ARIADNE_DEBUG\", \"\") == \"1\",\n)\n```\n\nRun it with Uvicorn:\n\n```bash\nuvicorn app:app --host 127.0.0.1 --port \"${PORT:-8000}\" --reload\n```\n\nSend a query:\n\n```bash\ncurl \"http://127.0.0.1:${PORT:-8000}/\" \\\n  -H \"content-type: application/json\" \\\n  -H \"x-user-id: user-123\" \\\n  --data '{\"query\":\"query($name: String){ hello(name: $name) viewer }\",\"variables\":{\"name\":\"Ada\"}}'\n```\n\nSend a mutation:\n\n```bash\ncurl \"http://127.0.0.1:${PORT:-8000}/\" \\\n  -H \"content-type: application/json\" \\\n  -H \"x-user-id: user-123\" \\\n  --data '{\"query\":\"mutation { createMessage(text: \\\"ship docs\\\") { id text } }\"}'\n```\n\n## Mount Ariadne Inside An Existing ASGI App\n\nIf your project already uses FastAPI or Starlette, mount Ariadne under a subpath instead of serving it at `/`.\n\nFastAPI:\n\n```python\nfrom fastapi import FastAPI\n\nfrom ariadne.asgi import GraphQL\n\napp = FastAPI()\napp.mount(\"/graphql\", GraphQL(schema, context_value=context_value, debug=False))\n```\n\nStarlette:\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.routing import Mount\n\nfrom ariadne.asgi import GraphQL\n\napp = Starlette(routes=[\n    Mount(\"/graphql\", GraphQL(schema, context_value=context_value, debug=False)),\n])\n```\n\nAfter mounting, post GraphQL requests to `/graphql`, not `/`.\n\n## WSGI App\n\nFor synchronous WSGI stacks, Ariadne also exposes a WSGI `GraphQL` app:\n\n```python\nfrom ariadne.wsgi import GraphQL\n\napp = GraphQL(schema, debug=False)\n```\n\nUse the ASGI app for modern async frameworks and the WSGI app only when the rest of your deployment stack is WSGI.\n\n## Context, Auth, And Request Data\n\nAriadne does not provide built-in authentication or secret management. Do auth in your framework layer, then pass request-scoped data through `context_value` and read it from `info.context` in resolvers.\n\nExample pattern:\n\n```python\nfrom graphql import GraphQLError\n\n\n@query.field(\"viewer\")\ndef resolve_viewer(_, info):\n    user_id = info.context.get(\"user_id\")\n    if not user_id:\n        raise GraphQLError(\"Unauthorized\")\n    return user_id\n```\n\nKeep secrets such as database credentials, JWT keys, and third-party API keys in your app config or secret manager. Ariadne only receives the context object you pass in.\n\n## Execute Queries In Tests Or Scripts\n\nFor unit tests and one-off scripts, execute GraphQL documents directly without starting an HTTP server:\n\n```python\nfrom ariadne import graphql_sync\n\nsuccess, result = graphql_sync(\n    schema,\n    {\n        \"query\": \"query($name: String){ hello(name: $name) viewer }\",\n        \"variables\": {\"name\": \"Ada\"},\n    },\n    context_value={\"user_id\": \"test-user\"},\n    debug=True,\n)\n\nassert success is True\nassert result[\"data\"] == {\n    \"hello\": \"Hello, Ada!\",\n    \"viewer\": \"test-user\",\n}\n```\n\nThis is the easiest way to test resolver behavior and GraphQL result shapes without involving routing, middleware, or a live server.\n\n## Common Pitfalls\n\n- Resolver signatures start with `obj` and `info`, followed by GraphQL field arguments. Do not write a resolver that only accepts the field arguments.\n- `debug=True` is a development setting. Turn it off in production so exception details are not exposed in GraphQL responses.\n- Mount paths matter. A standalone `GraphQL(schema, ...)` app serves requests at its own root, while a mounted app serves requests under the mount path.\n- Ariadne does not create database sessions, authenticate users, or load environment variables for you. Put those responsibilities in your framework or application layer.\n- Keep your schema and resolver names aligned. When in doubt, bind resolvers explicitly instead of assuming name conversion between GraphQL fields and Python attributes.\n"
  },
  {
    "path": "content/arq/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"arq Python package guide for async Redis-backed job queues and workers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.27.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"arq,python,asyncio,redis,queue,workers,background-jobs\"\n---\n\n# arq Python Package Guide\n\n## Golden Rule\n\nUse `arq` for async Redis-backed background jobs only if your application is already asyncio-native and you are comfortable with Redis as the queue backend. Define worker functions as `async def`, run them through a `WorkerSettings` class, and make every job idempotent because `arq` intentionally prefers rerunning a job over dropping it during shutdown or cancellation.\n\n`arq` is in maintenance-only mode as of 2026, so avoid building new code around old blog posts or pre-`0.16` examples without checking the current docs first.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"arq==0.27.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"arq==0.27.0\"\npoetry add \"arq==0.27.0\"\n```\n\nIf you want worker auto-reload in development:\n\n```bash\npython -m pip install \"arq[watch]==0.27.0\"\n```\n\nThat installs the optional `watchfiles` dependency used by `arq ... --watch`.\n\n## Core Model\n\n`arq` has two sides:\n\n- An async producer that connects to Redis and enqueues jobs with `create_pool(...)`\n- One or more workers that load a `WorkerSettings` class and execute registered functions\n\nThe producer and worker must agree on:\n\n- function names\n- queue name\n- serializer/deserializer\n- Redis connection settings\n\n## Initialize And Run\n\n### Minimal setup\n\n```python\nimport asyncio\n\nfrom arq import create_pool\nfrom arq.connections import RedisSettings\n\nREDIS_SETTINGS = RedisSettings(host=\"localhost\", port=6379, database=0)\n\nasync def send_email(ctx, user_id: int) -> str:\n    return f\"sent email to user {user_id}\"\n\nclass WorkerSettings:\n    functions = [send_email]\n    redis_settings = REDIS_SETTINGS\n\nasync def main() -> None:\n    redis = await create_pool(REDIS_SETTINGS)\n    await redis.enqueue_job(\"send_email\", 123)\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nEnqueue jobs:\n\n```bash\npython demo.py\n```\n\nRun the worker:\n\n```bash\narq demo.WorkerSettings\n```\n\nUseful worker modes:\n\n```bash\narq demo.WorkerSettings --burst\narq demo.WorkerSettings --watch path/to/src\n```\n\nUse `--burst` for one-shot workers in scripts, CI, or short-lived containers.\n\n### Shared startup and shutdown state\n\nUse `on_startup` and `on_shutdown` to create expensive shared objects once per worker process:\n\n```python\nfrom httpx import AsyncClient\n\nasync def startup(ctx) -> None:\n    ctx[\"http\"] = AsyncClient(timeout=10.0)\n\nasync def shutdown(ctx) -> None:\n    await ctx[\"http\"].aclose()\n\nasync def fetch_url(ctx, url: str) -> int:\n    response = await ctx[\"http\"].get(url)\n    response.raise_for_status()\n    return len(response.text)\n\nclass WorkerSettings:\n    functions = [fetch_url]\n    on_startup = startup\n    on_shutdown = shutdown\n    redis_settings = REDIS_SETTINGS\n```\n\nUse `ctx` for shared clients, connection pools, executors, and feature flags. Do not recreate them inside every job unless that is intentional.\n\n## Redis Configuration And Auth\n\n`RedisSettings` is the main configuration object for both producers and workers.\n\nCommon fields:\n\n- `host`, `port`, `database`\n- `username`, `password`\n- `ssl` and related TLS certificate fields\n- `max_connections`\n- `sentinel` and `sentinel_master`\n- retry controls such as `retry_on_timeout`, `retry_on_error`, and `retry`\n\nEnvironment-driven example:\n\n```python\nimport os\n\nfrom arq.connections import RedisSettings\n\nREDIS_SETTINGS = RedisSettings(\n    host=os.getenv(\"REDIS_HOST\", \"localhost\"),\n    port=int(os.getenv(\"REDIS_PORT\", \"6379\")),\n    database=int(os.getenv(\"REDIS_DB\", \"0\")),\n    username=os.getenv(\"REDIS_USERNAME\") or None,\n    password=os.getenv(\"REDIS_PASSWORD\") or None,\n    ssl=os.getenv(\"REDIS_SSL\", \"\").lower() == \"true\",\n)\n```\n\nIf you already have a Redis DSN, use `RedisSettings.from_dsn(...)`:\n\n```python\nfrom arq.connections import RedisSettings\n\nREDIS_SETTINGS = RedisSettings.from_dsn(\n    \"redis://username:password@redis.example.com:6379/0\"\n)\n```\n\n## Core Usage Patterns\n\n### Enqueue a job\n\n```python\nredis = await create_pool(REDIS_SETTINGS)\njob = await redis.enqueue_job(\"send_email\", 123)\n```\n\n`enqueue_job()` returns a `Job` object, or `None` if a job with the same `_job_id` already exists.\n\n### Enforce uniqueness with `_job_id`\n\nUse a stable `_job_id` when duplicate work would be harmful:\n\n```python\njob = await redis.enqueue_job(\n    \"send_email\",\n    123,\n    _job_id=\"send-email:user:123\",\n)\n```\n\nThis is the cleanest way to deduplicate retries triggered by upstream callers or repeated button clicks.\n\n### Defer execution\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nawait redis.enqueue_job(\"send_email\", 123, _defer_by=timedelta(minutes=5))\n\nawait redis.enqueue_job(\n    \"send_email\",\n    123,\n    _defer_until=datetime.now(timezone.utc) + timedelta(hours=1),\n)\n```\n\n### Get status and results\n\n```python\njob = await redis.enqueue_job(\"send_email\", 123)\n\nstatus = await job.status()\ninfo = await job.info()\nresult = await job.result(timeout=30)\n```\n\nRelevant statuses include `deferred`, `queued`, `in_progress`, `complete`, and `not_found`.\n\n### Retry with backoff\n\nRaise `arq.Retry` from a job to reschedule it:\n\n```python\nfrom arq import Retry\n\nasync def fetch_invoice(ctx, invoice_id: str) -> dict:\n    response = await ctx[\"http\"].get(f\"https://api.example.com/invoices/{invoice_id}\")\n    if response.status_code == 503:\n        raise Retry(defer=ctx[\"job_try\"] * 5)\n    response.raise_for_status()\n    return response.json()\n```\n\nTune retry limits per function or worker:\n\n```python\nfrom arq.worker import func\n\nclass WorkerSettings:\n    functions = [\n        func(fetch_invoice, max_tries=10, timeout=60, keep_result=300),\n    ]\n```\n\n### Schedule cron jobs\n\nUse `cron(...)` in worker settings for recurring jobs:\n\n```python\nfrom arq.cron import cron\n\nasync def refresh_cache(ctx) -> None:\n    ...\n\nclass WorkerSettings:\n    functions = []\n    cron_jobs = [\n        cron(refresh_cache, minute={0, 15, 30, 45}, run_at_startup=True),\n    ]\n```\n\nCron jobs are unique by default, which is important when multiple workers are running.\n\n### Run blocking work safely\n\nWorker functions must be coroutine functions. If the real work is blocking, offload it to an executor:\n\n```python\nimport asyncio\nfrom concurrent.futures import ProcessPoolExecutor\nfrom functools import partial\n\ndef resize_image_sync(path: str) -> str:\n    ...\n\nasync def startup(ctx) -> None:\n    ctx[\"pool\"] = ProcessPoolExecutor()\n\nasync def resize_image(ctx, path: str) -> str:\n    loop = asyncio.get_running_loop()\n    return await loop.run_in_executor(ctx[\"pool\"], partial(resize_image_sync, path))\n```\n\n## Worker Tuning\n\nUseful `WorkerSettings` options to reach for first:\n\n- `queue_name`: separate workloads into different queues\n- `max_jobs`: concurrent jobs per worker, default `10`\n- `job_timeout`: default job runtime limit, default `300` seconds\n- `max_tries`: default retry limit, default `5`\n- `keep_result`: how long to retain results, default `3600` seconds\n- `keep_result_forever`: keep results indefinitely when needed\n- `poll_delay`: queue polling interval\n- `allow_abort_jobs`: required for `job.abort()` to work\n- `health_check_interval` and `health_check_key`: useful for liveness monitoring\n- `burst`: stop after the queue drains\n\nIf you change `queue_name`, the producer must enqueue to the same queue via `_queue_name` or the worker setting.\n\n## Serialization\n\nBy default, `arq` uses `pickle`. If you switch to a custom serializer such as MsgPack, configure it on both sides:\n\n```python\nimport msgpack\n\nfrom arq import create_pool\n\nredis = await create_pool(\n    REDIS_SETTINGS,\n    job_serializer=msgpack.packb,\n    job_deserializer=lambda b: msgpack.unpackb(b, raw=False),\n)\n\nclass WorkerSettings:\n    functions = [send_email]\n    redis_settings = REDIS_SETTINGS\n    job_serializer = msgpack.packb\n    job_deserializer = lambda b: msgpack.unpackb(b, raw=False)\n```\n\nIf the worker and producer serializers differ, queued jobs will not deserialize correctly.\n\n## Common Pitfalls\n\n- Jobs are not exactly-once. Design them to tolerate reruns after worker shutdown, cancellation, or retries.\n- Old `arq <= 0.15` examples are not compatible with `0.27.0`. The project was fully rewritten in `0.16`.\n- Worker functions must be `async def`. Wrap blocking CPU or file work in an executor instead of calling it directly in the event loop.\n- `enqueue_job()` deduplicates only when you provide `_job_id`. Without it, repeated enqueue calls create separate jobs.\n- `job.abort()` does nothing unless the worker has `allow_abort_jobs = True`.\n- Producers and workers must use the same serializer/deserializer pair and compatible payload shapes.\n- If you defer jobs or keep results for a long time, Redis memory usage becomes part of your queue design.\n- `arq` only processes jobs while a worker is actually running. Enqueuing alone is not enough.\n\n## Version-Sensitive Notes For `0.27.0`\n\n- `0.27.0` supports Python `3.9` through `3.13` and no longer supports Python `3.8`.\n- The `v0.16` rewrite is still the main compatibility boundary. Pre-`0.16` docs use a different actor-based API and should be treated as historical only.\n- The project README now marks `arq` as maintenance-only mode. Expect bug fixes and compatibility updates, but be cautious about depending on future feature work.\n\n## Official Sources\n\n- Docs: https://arq-docs.helpmanual.io/\n- PyPI: https://pypi.org/project/arq/\n- Source repository: https://github.com/python-arq/arq\n- Release history: https://github.com/python-arq/arq/releases\n"
  },
  {
    "path": "content/arrow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Arrow Python package guide for creating, parsing, shifting, formatting, and localizing datetimes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"arrow,datetime,date,time,timezone,humanize,localization\"\n---\n\n# Arrow Python Package Guide\n\n## Golden Rule\n\nUse `arrow` when you want a friendlier datetime API, but still treat timezone handling as explicit application logic: create or normalize values in UTC, convert to local zones at the boundaries, and prefer full IANA timezone names such as `America/Los_Angeles` over ambiguous abbreviations such as `PST` or `MST`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"arrow==1.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"arrow==1.4.0\"\npoetry add \"arrow==1.4.0\"\n```\n\nPyPI also publishes `doc` and `test` extras, but normal application code usually just needs the base package.\n\n## Initialize And Create Values\n\nArrow is a library, not a network client, so there is no service authentication step. Setup is just installation plus choosing consistent timezone rules in your app.\n\nCommon creation patterns:\n\n```python\nfrom datetime import datetime\n\nimport arrow\n\nnow_utc = arrow.utcnow()\nnow_local = arrow.now()\npacific_now = arrow.now(\"America/Los_Angeles\")\n\nfrom_timestamp = arrow.get(1710000000)\nfrom_iso = arrow.get(\"2026-03-12T18:30:00+00:00\")\nfrom_formatted = arrow.get(\"2026-03-12 18:30:00\", \"YYYY-MM-DD HH:mm:ss\")\nfrom_datetime = arrow.get(datetime(2026, 3, 12, 18, 30, 0))\n```\n\nImportant behavior:\n\n- `arrow.utcnow()` returns an aware UTC value.\n- `arrow.now()` returns an aware value in the local timezone unless you pass a timezone.\n- `arrow.get(naive_datetime)` treats a naive `datetime` as UTC.\n\n## Core Usage\n\n### Parse, normalize, and format\n\n```python\nimport arrow\n\nevent = arrow.get(\"2026-03-12 10:15:00\", \"YYYY-MM-DD HH:mm:ss\")\nevent_utc = event.to(\"UTC\")\n\nprint(event_utc.isoformat())\nprint(event_utc.format(\"YYYY-MM-DD HH:mm:ss ZZ\"))\nprint(event_utc.format(arrow.FORMAT_RFC3339))\n```\n\nArrow format strings are token-based (`YYYY`, `MM`, `DD`, `HH`, `ZZ`), not Python `strftime` directives.\n\n### Shift or replace components\n\nUse `shift()` for relative arithmetic and `replace()` for absolute component changes:\n\n```python\nimport arrow\n\nbase = arrow.get(\"2026-03-12T18:30:00+00:00\")\n\nnext_week = base.shift(weeks=1)\ntwo_hours_ago = base.shift(hours=-2)\nsame_day_at_noon = base.replace(hour=12, minute=0, second=0, microsecond=0)\n```\n\n### Convert timezones\n\n```python\nimport arrow\n\nutc_value = arrow.utcnow()\nla_value = utc_value.to(\"America/Los_Angeles\")\nberlin_value = utc_value.to(\"Europe/Berlin\")\n```\n\nPrefer full IANA names. The upstream docs explicitly warn that abbreviations such as `MST`, `PDT`, and `BRST` are ambiguous and may fail to parse.\n\n### Humanize and dehumanize\n\n```python\nimport arrow\n\npresent = arrow.utcnow()\nfuture = present.shift(minutes=66)\n\nprint(future.humanize(present))\nprint(future.humanize(present, only_distance=True, granularity=[\"hour\", \"minute\"]))\n\nearlier = present.dehumanize(\"2 days ago\")\nlater = present.dehumanize(\"in a month\")\n```\n\nThis is useful for UI text, but do not treat `humanize()` output as a stable machine-readable format.\n\n### Generate spans and ranges\n\n```python\nfrom datetime import datetime\n\nimport arrow\n\nstart_of_hour, end_of_hour = arrow.utcnow().span(\"hour\")\nstart_of_week = arrow.utcnow().floor(\"week\", week_start=7)\n\nfor point in arrow.Arrow.range(\n    \"hour\",\n    datetime(2026, 3, 12, 9, 0),\n    datetime(2026, 3, 12, 12, 0),\n):\n    print(point)\n```\n\nUse `span()` when you need a closed interval for a unit, `floor()` and `ceil()` when you only need one bound, and `Arrow.range()` or `Arrow.span_range()` for iteration.\n\n## Practical Pattern\n\nThis is a good default workflow for application code:\n\n```python\nimport arrow\n\nraw_created_at = \"2026-03-12T18:30:00-04:00\"\n\ncreated_at = arrow.get(raw_created_at).to(\"UTC\")\nexpires_at = created_at.shift(days=30)\ndisplay_value = expires_at.to(\"America/Los_Angeles\").format(\"YYYY-MM-DD HH:mm:ss ZZ\")\n\nprint(created_at)\nprint(expires_at)\nprint(display_value)\n```\n\nParse once, normalize to UTC for storage and logic, then convert only for display or user-facing output.\n\n## Configuration Notes\n\n- There is no package-level auth or API configuration.\n- Timezone strings are the main configuration surface. Prefer canonical IANA names such as `UTC`, `Europe/London`, or `America/Chicago`.\n- On Python 3.9+, `zoneinfo.ZoneInfo` is a good explicit timezone object choice. On Python 3.8, passing timezone names as strings is the most portable option.\n- Locale matters for `humanize()` and `dehumanize()`. Set `locale=...` explicitly when your app output is not English.\n- If parsing messy input, `arrow.get(..., normalize_whitespace=True)` can help with tabs, newlines, or inconsistent spacing.\n\n## Common Pitfalls\n\n- `arrow.now()` is local time, while `arrow.utcnow()` is UTC. Mixing them without conversion produces subtle bugs.\n- `arrow.get(naive_datetime)` assumes UTC. If a naive `datetime` actually represents local wall time, attach or replace the timezone before converting.\n- Arrow formatting tokens are not `strftime` tokens. `YYYY-MM-DD` works in Arrow; `%Y-%m-%d` does not.\n- Timezone abbreviations are not reliable parse inputs. Use `America/New_York`, not `EST`.\n- `humanize()` is for presentation. Do not parse it later or store it as a durable value.\n- `Arrow.range()` and `Arrow.span_range()` return iterators. Materialize them with `list(...)` only when you actually need all values in memory.\n\n## Version-Sensitive Notes For 1.4.0\n\n- PyPI and the official docs both identify `1.4.0` as the current version, released on `2025-10-18`.\n- The `1.4.0` changelog adds a `week_start` parameter to `floor()` and `ceil()`, which matters when your business logic treats Sunday instead of Monday as the first day of the week.\n- `1.4.0` also adds `arrow.FORMAT_RFC3339_STRICT`, which is useful if you need an RFC 3339 format with a `T` separator.\n- The `1.4.0` changelog says Arrow migrated to `ZoneInfo` for timezones instead of `pytz`.\n- Inference from that change: if older code depended on `pytz`-specific behavior around DST transitions or timezone object identity, retest those paths when upgrading to `1.4.0`.\n- The same release notes mention a fix for the `datetime.utcnow` deprecation warning, so codebases moving to newer Python versions should prefer `1.4.0` over older Arrow releases.\n"
  },
  {
    "path": "content/asana/docs/tasks/DOC.md",
    "content": "---\nname: tasks\ndescription: \"Asana API coding guide for tasks, project management, and workflow\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"asana,tasks,project-management,workflow,api\"\n---\n\n# Asana API Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Asana Node.js SDK package:**\n- Package name: `asana`\n- Official library maintained by Asana for Node.js and browser JavaScript\n\n**Never use deprecated or unofficial libraries.** The `asana` package is the only supported library maintained by Asana, Inc.\n\n**Current SDK Version:** v3.1.2 (Node.js library)\n\n**API Version:** Asana API 1.0\n\n## 2. Installation\n\n### Node.js Installation\n\n```bash\nnpm install asana\n```\n\n```bash\nyarn add asana\n```\n\n```bash\npnpm add asana\n```\n\n**Requirements:** Node.js 12+ (recommended Node.js 18+ for production)\n\n### Environment Variables\n\n```bash\n# Required - Personal Access Token\nASANA_ACCESS_TOKEN=your_personal_access_token_here\n\n# Optional - OAuth credentials\nASANA_CLIENT_ID=your_client_id\nASANA_CLIENT_SECRET=your_client_secret\nASANA_REDIRECT_URI=http://localhost:3000/auth/callback\n\n# Optional - Workspace/Organization IDs\nASANA_WORKSPACE_ID=your_workspace_gid\nASANA_PROJECT_ID=your_project_gid\n```\n\n**CRITICAL:** Never commit access tokens to version control. Use environment variables or secure secret management systems.\n\n## 3. Initialization\n\n### Basic Initialization with Personal Access Token\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n```\n\n**With ES6 Modules:**\n\n```javascript\nimport Asana from 'asana';\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n```\n\n### Advanced Initialization with OAuth\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst oauth = client.authentications['oauth2'];\noauth.accessToken = 'YOUR_OAUTH_ACCESS_TOKEN';\n```\n\n### Client Configuration Options\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nclient.defaultHeaders = {\n  'asana-enable': 'new_user_task_lists,new_project_templates'\n};\nclient.timeout = 60000; // 60 seconds\n\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n```\n\n## 4. Core API Surfaces\n\n### Tasks API\n\nTasks are the basic unit of action in Asana. They can be assigned, have due dates, contain notes, and be organized into projects.\n\n#### Creating Tasks\n\n**Minimal Example:**\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst tasksApiInstance = new Asana.TasksApi();\n\nconst body = {\n  data: {\n    name: 'Buy milk',\n    workspace: '1234567890123456'\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,completed,assignee,due_on'\n};\n\ntasksApiInstance.createTask(body, opts).then((result) => {\n  console.log('Task created:', result.data);\n}).catch((error) => {\n  console.error('Error creating task:', error.response.body);\n});\n```\n\n**Advanced Example with All Options:**\n\n```javascript\nconst body = {\n  data: {\n    name: 'Design new feature mockups',\n    notes: 'Create high-fidelity mockups for the new dashboard feature',\n    assignee: '9876543210987654',\n    workspace: '1234567890123456',\n    projects: ['1111111111111111'],\n    due_on: '2025-12-31',\n    due_at: '2025-12-31T17:00:00.000Z',\n    start_on: '2025-01-15',\n    followers: ['user_gid_1', 'user_gid_2'],\n    tags: ['tag_gid_1'],\n    custom_fields: {\n      '5678901234567890': 'High',\n      '9012345678901234': '42'\n    },\n    resource_subtype: 'default_task',\n    completed: false,\n    liked: false,\n    html_notes: '<body>Create <strong>high-fidelity</strong> mockups</body>',\n    external: {\n      gid: 'my_external_id_123',\n      data: 'Custom external data'\n    }\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,assignee,assignee.name,due_on,completed,projects,projects.name,tags,tags.name,custom_fields,custom_fields.name,followers,followers.name'\n};\n\ntasksApiInstance.createTask(body, opts).then((result) => {\n  console.log('Task created:', JSON.stringify(result.data, null, 2));\n}).catch((error) => {\n  console.error('Error:', error.response.body);\n});\n```\n\n#### Getting a Task\n\n```javascript\nconst taskGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,notes,assignee,assignee.name,assignee.email,completed,due_on,due_at,projects,projects.name,tags,tags.name,custom_fields,custom_fields.name,custom_fields.display_value,followers,followers.name,created_at,modified_at,completed_at,memberships,memberships.project.name,memberships.section.name'\n};\n\ntasksApiInstance.getTask(taskGid, opts).then((result) => {\n  console.log('Task details:', JSON.stringify(result.data, null, 2));\n}).catch((error) => {\n  console.error('Error getting task:', error.response.body);\n});\n```\n\n#### Updating Tasks\n\n```javascript\nconst taskGid = '1234567890123456';\n\nconst body = {\n  data: {\n    name: 'Updated task name',\n    notes: 'Updated task description',\n    completed: true,\n    assignee: 'another_user_gid',\n    due_on: '2025-12-31'\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,completed,assignee.name,due_on'\n};\n\ntasksApiInstance.updateTask(body, taskGid, opts).then((result) => {\n  console.log('Task updated:', result.data);\n}).catch((error) => {\n  console.error('Error updating task:', error.response.body);\n});\n```\n\n#### Deleting Tasks\n\n```javascript\nconst taskGid = '1234567890123456';\n\ntasksApiInstance.deleteTask(taskGid).then((result) => {\n  console.log('Task deleted successfully');\n}).catch((error) => {\n  console.error('Error deleting task:', error.response.body);\n});\n```\n\n#### Searching Tasks in a Workspace\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  assignee: 'me',\n  completed: false,\n  opt_fields: 'name,assignee.name,due_on,projects.name,completed',\n  sort_by: 'due_date',\n  sort_ascending: true\n};\n\ntasksApiInstance.searchTasksForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Tasks found:', result.data);\n}).catch((error) => {\n  console.error('Error searching tasks:', error.response.body);\n});\n```\n\n### Projects API\n\nProjects represent a prioritized list of tasks or a board with columns of tasks.\n\n#### Creating Projects\n\n**Minimal Example:**\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst projectsApiInstance = new Asana.ProjectsApi();\n\nconst body = {\n  data: {\n    name: 'Marketing Campaign Q4',\n    workspace: '1234567890123456'\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,owner,due_date,created_at'\n};\n\nprojectsApiInstance.createProject(body, opts).then((result) => {\n  console.log('Project created:', result.data);\n}).catch((error) => {\n  console.error('Error creating project:', error.response.body);\n});\n```\n\n**Advanced Example:**\n\n```javascript\nconst body = {\n  data: {\n    name: 'Website Redesign 2025',\n    notes: 'Complete redesign of company website with new branding',\n    workspace: '1234567890123456',\n    team: '9876543210987654',\n    owner: 'user_gid',\n    due_date: '2025-12-31',\n    start_on: '2025-01-01',\n    color: 'light-green',\n    archived: false,\n    public: true,\n    default_view: 'board',\n    custom_fields: {\n      '5678901234567890': 'Active'\n    },\n    followers: ['user_gid_1', 'user_gid_2']\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,owner.name,due_date,team.name,custom_fields,members,members.name,archived,color,created_at,current_status,default_view'\n};\n\nprojectsApiInstance.createProject(body, opts).then((result) => {\n  console.log('Project created:', JSON.stringify(result.data, null, 2));\n}).catch((error) => {\n  console.error('Error:', error.response.body);\n});\n```\n\n#### Getting Projects\n\n```javascript\nconst projectGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,owner.name,notes,due_date,start_on,archived,color,created_at,modified_at,team.name,workspace.name,members,members.name,followers,followers.name,custom_fields,custom_fields.name,custom_fields.display_value'\n};\n\nprojectsApiInstance.getProject(projectGid, opts).then((result) => {\n  console.log('Project details:', JSON.stringify(result.data, null, 2));\n}).catch((error) => {\n  console.error('Error getting project:', error.response.body);\n});\n```\n\n#### Updating Projects\n\n```javascript\nconst projectGid = '1234567890123456';\n\nconst body = {\n  data: {\n    name: 'Updated Project Name',\n    notes: 'Updated project description',\n    color: 'dark-blue',\n    archived: false,\n    public: false\n  }\n};\n\nprojectsApiInstance.updateProject(body, projectGid).then((result) => {\n  console.log('Project updated:', result.data);\n}).catch((error) => {\n  console.error('Error updating project:', error.response.body);\n});\n```\n\n#### Getting Tasks in a Project\n\n```javascript\nconst projectGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,assignee.name,completed,due_on,tags.name'\n};\n\ntasksApiInstance.getTasksForProject(projectGid, opts).then((result) => {\n  console.log('Project tasks:', result.data);\n}).catch((error) => {\n  console.error('Error getting project tasks:', error.response.body);\n});\n```\n\n#### Adding a Task to a Project\n\n```javascript\nconst taskGid = '1234567890123456';\n\nconst body = {\n  data: {\n    project: '9876543210987654'\n  }\n};\n\ntasksApiInstance.addProjectForTask(body, taskGid).then((result) => {\n  console.log('Task added to project');\n}).catch((error) => {\n  console.error('Error adding task to project:', error.response.body);\n});\n```\n\n### Sections API\n\nSections divide tasks within a project into categories, workflow stages, or priorities.\n\n#### Creating Sections\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst sectionsApiInstance = new Asana.SectionsApi();\nconst projectGid = '1234567890123456';\n\nconst body = {\n  data: {\n    name: 'In Progress'\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,created_at,project.name'\n};\n\nsectionsApiInstance.createSectionForProject(body, projectGid, opts).then((result) => {\n  console.log('Section created:', result.data);\n}).catch((error) => {\n  console.error('Error creating section:', error.response.body);\n});\n```\n\n#### Getting Sections in a Project\n\n```javascript\nconst projectGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,created_at,project.name'\n};\n\nsectionsApiInstance.getSectionsForProject(projectGid, opts).then((result) => {\n  console.log('Sections:', result.data);\n}).catch((error) => {\n  console.error('Error getting sections:', error.response.body);\n});\n```\n\n#### Adding a Task to a Section\n\n```javascript\nconst sectionGid = '1234567890123456';\n\nconst body = {\n  data: {\n    task: '9876543210987654'\n  }\n};\n\nsectionsApiInstance.addTaskForSection(body, sectionGid).then((result) => {\n  console.log('Task added to section');\n}).catch((error) => {\n  console.error('Error adding task to section:', error.response.body);\n});\n```\n\n### Workspaces API\n\nWorkspaces are the highest-level organizational unit in Asana.\n\n#### Getting Workspaces\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst workspacesApiInstance = new Asana.WorkspacesApi();\n\nconst opts = {\n  opt_fields: 'name,is_organization,email_domains'\n};\n\nworkspacesApiInstance.getWorkspaces(opts).then((result) => {\n  console.log('Workspaces:', result.data);\n}).catch((error) => {\n  console.error('Error getting workspaces:', error.response.body);\n});\n```\n\n#### Getting a Workspace\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,is_organization,email_domains'\n};\n\nworkspacesApiInstance.getWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Workspace:', result.data);\n}).catch((error) => {\n  console.error('Error getting workspace:', error.response.body);\n});\n```\n\n#### Getting Projects in a Workspace\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst projectsApiInstance = new Asana.ProjectsApi();\n\nconst opts = {\n  archived: false,\n  opt_fields: 'name,owner.name,due_date,created_at'\n};\n\nprojectsApiInstance.getProjectsForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Projects:', result.data);\n}).catch((error) => {\n  console.error('Error getting projects:', error.response.body);\n});\n```\n\n### Users API\n\nUsers represent individuals in Asana.\n\n#### Getting the Current User\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst usersApiInstance = new Asana.UsersApi();\nconst userGid = 'me';\n\nconst opts = {\n  opt_fields: 'name,email,photo,workspaces,workspaces.name'\n};\n\nusersApiInstance.getUser(userGid, opts).then((result) => {\n  console.log('Current user:', result.data);\n}).catch((error) => {\n  console.error('Error getting user:', error.response.body);\n});\n```\n\n#### Getting Users in a Workspace\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,email,photo'\n};\n\nusersApiInstance.getUsersForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Users:', result.data);\n}).catch((error) => {\n  console.error('Error getting users:', error.response.body);\n});\n```\n\n### Teams API\n\nTeams organize people and projects within a workspace.\n\n#### Getting Teams\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst teamsApiInstance = new Asana.TeamsApi();\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,description,organization.name'\n};\n\nteamsApiInstance.getTeamsForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Teams:', result.data);\n}).catch((error) => {\n  console.error('Error getting teams:', error.response.body);\n});\n```\n\n#### Getting a Team\n\n```javascript\nconst teamGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,description,organization.name,html_description'\n};\n\nteamsApiInstance.getTeam(teamGid, opts).then((result) => {\n  console.log('Team:', result.data);\n}).catch((error) => {\n  console.error('Error getting team:', error.response.body);\n});\n```\n\n### Custom Fields API\n\nCustom fields allow you to add structured metadata to tasks and projects.\n\n#### Getting Custom Fields in a Workspace\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst customFieldsApiInstance = new Asana.CustomFieldsApi();\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,resource_subtype,type,enum_options,enum_options.name,precision'\n};\n\ncustomFieldsApiInstance.getCustomFieldsForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Custom fields:', result.data);\n}).catch((error) => {\n  console.error('Error getting custom fields:', error.response.body);\n});\n```\n\n#### Creating a Custom Field\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst body = {\n  data: {\n    name: 'Priority',\n    resource_subtype: 'enum',\n    type: 'enum',\n    workspace: workspaceGid,\n    enum_options: [\n      { name: 'Low', enabled: true, color: 'blue' },\n      { name: 'Medium', enabled: true, color: 'yellow' },\n      { name: 'High', enabled: true, color: 'red' }\n    ]\n  }\n};\n\ncustomFieldsApiInstance.createCustomField(body).then((result) => {\n  console.log('Custom field created:', result.data);\n}).catch((error) => {\n  console.error('Error creating custom field:', error.response.body);\n});\n```\n\n#### Updating Custom Field Value on a Task\n\n```javascript\nconst taskGid = '1234567890123456';\nconst customFieldGid = '9876543210987654';\n\nconst body = {\n  data: {\n    custom_fields: {\n      [customFieldGid]: 'High'\n    }\n  }\n};\n\ntasksApiInstance.updateTask(body, taskGid).then((result) => {\n  console.log('Custom field updated');\n}).catch((error) => {\n  console.error('Error updating custom field:', error.response.body);\n});\n```\n\n### Tags API\n\nTags are labels that can be attached to tasks.\n\n#### Creating Tags\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst tagsApiInstance = new Asana.TagsApi();\n\nconst body = {\n  data: {\n    name: 'Bug',\n    workspace: '1234567890123456',\n    color: 'red'\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,color,created_at'\n};\n\ntagsApiInstance.createTag(body, opts).then((result) => {\n  console.log('Tag created:', result.data);\n}).catch((error) => {\n  console.error('Error creating tag:', error.response.body);\n});\n```\n\n#### Getting Tags in a Workspace\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,color,created_at'\n};\n\ntagsApiInstance.getTagsForWorkspace(workspaceGid, opts).then((result) => {\n  console.log('Tags:', result.data);\n}).catch((error) => {\n  console.error('Error getting tags:', error.response.body);\n});\n```\n\n### Attachments API\n\nAttachments are files or URLs associated with tasks.\n\n#### Uploading an Attachment to a Task\n\n```javascript\nconst Asana = require('asana');\nconst fs = require('fs');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst attachmentsApiInstance = new Asana.AttachmentsApi();\nconst taskGid = '1234567890123456';\n\nconst body = {\n  file: fs.createReadStream('/path/to/file.pdf'),\n  parent: taskGid\n};\n\nconst opts = {\n  opt_fields: 'name,download_url,size,host'\n};\n\nattachmentsApiInstance.createAttachmentForObject(body, opts).then((result) => {\n  console.log('Attachment uploaded:', result.data);\n}).catch((error) => {\n  console.error('Error uploading attachment:', error.response.body);\n});\n```\n\n#### Getting Attachments for a Task\n\n```javascript\nconst taskGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'name,download_url,size,host,created_at'\n};\n\nattachmentsApiInstance.getAttachmentsForObject(taskGid, opts).then((result) => {\n  console.log('Attachments:', result.data);\n}).catch((error) => {\n  console.error('Error getting attachments:', error.response.body);\n});\n```\n\n### Webhooks API\n\nWebhooks allow applications to be notified of changes in Asana.\n\n#### Creating a Webhook\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst webhooksApiInstance = new Asana.WebhooksApi();\n\nconst body = {\n  data: {\n    resource: '1234567890123456', // project GID\n    target: 'https://example.com/webhooks/asana'\n  }\n};\n\nconst opts = {\n  opt_fields: 'resource,target,active,last_success_at,last_failure_at'\n};\n\nwebhooksApiInstance.createWebhook(body, opts).then((result) => {\n  console.log('Webhook created:', result.data);\n}).catch((error) => {\n  console.error('Error creating webhook:', error.response.body);\n});\n```\n\n#### Getting Webhooks\n\n```javascript\nconst workspaceGid = '1234567890123456';\n\nconst opts = {\n  resource: workspaceGid,\n  opt_fields: 'resource,target,active,created_at,last_success_at,last_failure_at'\n};\n\nwebhooksApiInstance.getWebhooks(opts).then((result) => {\n  console.log('Webhooks:', result.data);\n}).catch((error) => {\n  console.error('Error getting webhooks:', error.response.body);\n});\n```\n\n#### Deleting a Webhook\n\n```javascript\nconst webhookGid = '1234567890123456';\n\nwebhooksApiInstance.deleteWebhook(webhookGid).then((result) => {\n  console.log('Webhook deleted');\n}).catch((error) => {\n  console.error('Error deleting webhook:', error.response.body);\n});\n```\n\n#### Handling Webhook Events\n\n```javascript\nconst express = require('express');\nconst crypto = require('crypto');\nconst app = express();\n\napp.use(express.json());\n\napp.post('/webhooks/asana', (req, res) => {\n  // Verify webhook signature\n  const signature = req.headers['x-hook-signature'];\n  const secret = process.env.ASANA_WEBHOOK_SECRET;\n\n  const hash = crypto\n    .createHmac('sha256', secret)\n    .update(JSON.stringify(req.body))\n    .digest('hex');\n\n  if (signature !== hash) {\n    return res.status(401).send('Invalid signature');\n  }\n\n  // Handle handshake\n  if (req.headers['x-hook-secret']) {\n    res.setHeader('X-Hook-Secret', req.headers['x-hook-secret']);\n    return res.status(200).send();\n  }\n\n  // Process webhook events\n  const events = req.body.events || [];\n\n  events.forEach((event) => {\n    console.log('Event:', event.action, 'Resource:', event.resource);\n\n    if (event.action === 'added') {\n      console.log('Task added:', event.resource.gid);\n    } else if (event.action === 'changed') {\n      console.log('Task changed:', event.resource.gid);\n    } else if (event.action === 'removed') {\n      console.log('Task removed:', event.resource.gid);\n    }\n  });\n\n  res.status(200).send();\n});\n\napp.listen(3000, () => {\n  console.log('Webhook server listening on port 3000');\n});\n```\n\n### Stories API (Comments and Activity)\n\nStories represent the activity feed on tasks and projects.\n\n#### Creating a Comment on a Task\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst storiesApiInstance = new Asana.StoriesApi();\nconst taskGid = '1234567890123456';\n\nconst body = {\n  data: {\n    text: 'This is a comment on the task',\n    is_pinned: false\n  }\n};\n\nconst opts = {\n  opt_fields: 'text,created_at,created_by.name,is_pinned'\n};\n\nstoriesApiInstance.createStoryForTask(body, taskGid, opts).then((result) => {\n  console.log('Comment created:', result.data);\n}).catch((error) => {\n  console.error('Error creating comment:', error.response.body);\n});\n```\n\n#### Getting Comments for a Task\n\n```javascript\nconst taskGid = '1234567890123456';\n\nconst opts = {\n  opt_fields: 'text,created_at,created_by.name,resource_subtype,type'\n};\n\nstoriesApiInstance.getStoriesForTask(taskGid, opts).then((result) => {\n  console.log('Stories:', result.data);\n}).catch((error) => {\n  console.error('Error getting stories:', error.response.body);\n});\n```\n\n### Portfolios API\n\nPortfolios are collections of projects.\n\n#### Creating a Portfolio\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst portfoliosApiInstance = new Asana.PortfoliosApi();\n\nconst body = {\n  data: {\n    name: 'Product Initiatives',\n    workspace: '1234567890123456',\n    color: 'light-pink',\n    public: false\n  }\n};\n\nconst opts = {\n  opt_fields: 'name,color,created_at,owner.name'\n};\n\nportfoliosApiInstance.createPortfolio(body, opts).then((result) => {\n  console.log('Portfolio created:', result.data);\n}).catch((error) => {\n  console.error('Error creating portfolio:', error.response.body);\n});\n```\n\n#### Adding a Project to a Portfolio\n\n```javascript\nconst portfolioGid = '1234567890123456';\n\nconst body = {\n  data: {\n    project: '9876543210987654'\n  }\n};\n\nportfoliosApiInstance.addItemForPortfolio(body, portfolioGid).then((result) => {\n  console.log('Project added to portfolio');\n}).catch((error) => {\n  console.error('Error adding project to portfolio:', error.response.body);\n});\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\nconst Asana = require('asana');\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst tasksApiInstance = new Asana.TasksApi();\n\nasync function getTask(taskGid) {\n  try {\n    const result = await tasksApiInstance.getTask(taskGid);\n    console.log('Task:', result.data);\n    return result.data;\n  } catch (error) {\n    if (error.response) {\n      console.error('API Error:', error.response.body);\n      console.error('Status:', error.response.status);\n\n      if (error.response.status === 401) {\n        console.error('Authentication failed. Check your access token.');\n      } else if (error.response.status === 403) {\n        console.error('Permission denied. You do not have access to this resource.');\n      } else if (error.response.status === 404) {\n        console.error('Resource not found.');\n      } else if (error.response.status === 429) {\n        console.error('Rate limit exceeded. Please retry after some time.');\n      }\n    } else {\n      console.error('Network error:', error.message);\n    }\n    throw error;\n  }\n}\n```\n\n### Retry Pattern for Rate Limiting\n\n```javascript\nasync function makeRequestWithRetry(apiCall, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await apiCall();\n    } catch (error) {\n      if (error.response?.status === 429) {\n        const retryAfter = error.response.headers['retry-after'] || Math.pow(2, i);\n        console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);\n        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n      } else {\n        throw error;\n      }\n    }\n  }\n  throw new Error('Max retries exceeded');\n}\n\n// Usage\nmakeRequestWithRetry(() => tasksApiInstance.getTask(taskGid))\n  .then(result => console.log('Task:', result.data))\n  .catch(error => console.error('Failed after retries:', error));\n```\n\n## Pagination\n\n### Handling Paginated Results\n\n```javascript\nasync function getAllTasks(projectGid) {\n  const allTasks = [];\n  let offset = undefined;\n\n  do {\n    const opts = {\n      limit: 100,\n      offset: offset,\n      opt_fields: 'name,completed,assignee.name'\n    };\n\n    const result = await tasksApiInstance.getTasksForProject(projectGid, opts);\n    allTasks.push(...result.data);\n\n    offset = result.next_page?.offset;\n  } while (offset);\n\n  return allTasks;\n}\n\n// Usage\ngetAllTasks('1234567890123456').then(tasks => {\n  console.log(`Total tasks: ${tasks.length}`);\n  tasks.forEach(task => console.log(task.name));\n});\n```\n\n## OAuth Authentication Flow\n\n### Setting Up OAuth\n\n```javascript\nconst express = require('express');\nconst Asana = require('asana');\n\nconst app = express();\n\nconst ASANA_CLIENT_ID = process.env.ASANA_CLIENT_ID;\nconst ASANA_CLIENT_SECRET = process.env.ASANA_CLIENT_SECRET;\nconst REDIRECT_URI = process.env.ASANA_REDIRECT_URI;\n\n// Generate authorization URL\napp.get('/auth', (req, res) => {\n  const authUrl = `https://app.asana.com/-/oauth_authorize?client_id=${ASANA_CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&response_type=code&state=random_state_string`;\n  res.redirect(authUrl);\n});\n\n// Handle OAuth callback\napp.get('/auth/callback', async (req, res) => {\n  const code = req.query.code;\n\n  try {\n    const response = await fetch('https://app.asana.com/-/oauth_token', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n      },\n      body: new URLSearchParams({\n        grant_type: 'authorization_code',\n        client_id: ASANA_CLIENT_ID,\n        client_secret: ASANA_CLIENT_SECRET,\n        redirect_uri: REDIRECT_URI,\n        code: code\n      })\n    });\n\n    const data = await response.json();\n\n    if (data.access_token) {\n      // Store access_token and refresh_token securely\n      console.log('Access token:', data.access_token);\n      console.log('Refresh token:', data.refresh_token);\n\n      // Initialize Asana client with OAuth token\n      const client = Asana.ApiClient.instance;\n      const oauth = client.authentications['oauth2'];\n      oauth.accessToken = data.access_token;\n\n      res.send('Authentication successful!');\n    } else {\n      res.status(400).send('Authentication failed');\n    }\n  } catch (error) {\n    console.error('OAuth error:', error);\n    res.status(500).send('Error during authentication');\n  }\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000');\n});\n```\n\n### Refreshing OAuth Tokens\n\n```javascript\nasync function refreshAccessToken(refreshToken) {\n  try {\n    const response = await fetch('https://app.asana.com/-/oauth_token', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n      },\n      body: new URLSearchParams({\n        grant_type: 'refresh_token',\n        client_id: process.env.ASANA_CLIENT_ID,\n        client_secret: process.env.ASANA_CLIENT_SECRET,\n        refresh_token: refreshToken\n      })\n    });\n\n    const data = await response.json();\n\n    if (data.access_token) {\n      console.log('New access token:', data.access_token);\n      return data.access_token;\n    }\n  } catch (error) {\n    console.error('Token refresh error:', error);\n    throw error;\n  }\n}\n```\n\n## TypeScript Support\n\n### Using Asana SDK with TypeScript\n\n```typescript\nimport Asana from 'asana';\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN!;\n\nconst tasksApiInstance = new Asana.TasksApi();\n\ninterface TaskData {\n  name: string;\n  workspace: string;\n  assignee?: string;\n  due_on?: string;\n}\n\nasync function createTask(taskData: TaskData): Promise<any> {\n  const body = {\n    data: taskData\n  };\n\n  const opts = {\n    opt_fields: 'name,assignee.name,due_on,completed'\n  };\n\n  try {\n    const result = await tasksApiInstance.createTask(body, opts);\n    return result.data;\n  } catch (error) {\n    console.error('Error creating task:', error);\n    throw error;\n  }\n}\n\n// Usage\ncreateTask({\n  name: 'TypeScript task',\n  workspace: '1234567890123456',\n  due_on: '2025-12-31'\n}).then(task => {\n  console.log('Task created:', task);\n});\n```\n\n## Batch Operations\n\n### Creating Multiple Tasks\n\n```javascript\nasync function createMultipleTasks(taskDataArray) {\n  const promises = taskDataArray.map(taskData => {\n    const body = { data: taskData };\n    return tasksApiInstance.createTask(body);\n  });\n\n  try {\n    const results = await Promise.all(promises);\n    console.log(`Created ${results.length} tasks`);\n    return results.map(r => r.data);\n  } catch (error) {\n    console.error('Error creating tasks:', error);\n    throw error;\n  }\n}\n\n// Usage\nconst tasksToCreate = [\n  { name: 'Task 1', workspace: '1234567890123456' },\n  { name: 'Task 2', workspace: '1234567890123456' },\n  { name: 'Task 3', workspace: '1234567890123456' }\n];\n\ncreateMultipleTasks(tasksToCreate).then(tasks => {\n  console.log('Tasks created:', tasks);\n});\n```\n\n## Environment Variable Validation\n\n```javascript\nconst Asana = require('asana');\nrequire('dotenv').config();\n\nfunction validateEnvironment() {\n  if (!process.env.ASANA_ACCESS_TOKEN) {\n    console.error('Error: ASANA_ACCESS_TOKEN is required in .env file');\n    process.exit(1);\n  }\n\n  console.log('Environment validated successfully');\n}\n\nvalidateEnvironment();\n\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n```\n\n## Complete Example Application\n\n```javascript\nconst Asana = require('asana');\nrequire('dotenv').config();\n\n// Validate environment\nif (!process.env.ASANA_ACCESS_TOKEN || !process.env.ASANA_WORKSPACE_ID) {\n  console.error('Missing required environment variables');\n  process.exit(1);\n}\n\n// Initialize client\nconst client = Asana.ApiClient.instance;\nconst token = client.authentications['token'];\ntoken.accessToken = process.env.ASANA_ACCESS_TOKEN;\n\nconst tasksApiInstance = new Asana.TasksApi();\nconst projectsApiInstance = new Asana.ProjectsApi();\nconst usersApiInstance = new Asana.UsersApi();\n\nasync function main() {\n  try {\n    // Get current user\n    console.log('Getting current user...');\n    const userResult = await usersApiInstance.getUser('me', {\n      opt_fields: 'name,email,workspaces.name'\n    });\n    console.log('Logged in as:', userResult.data.name);\n\n    // Create a project\n    console.log('\\nCreating project...');\n    const projectBody = {\n      data: {\n        name: 'API Demo Project',\n        workspace: process.env.ASANA_WORKSPACE_ID,\n        notes: 'Project created via Asana API'\n      }\n    };\n    const projectResult = await projectsApiInstance.createProject(projectBody, {\n      opt_fields: 'name,gid'\n    });\n    console.log('Project created:', projectResult.data.name);\n    const projectGid = projectResult.data.gid;\n\n    // Create tasks\n    console.log('\\nCreating tasks...');\n    const taskNames = ['Design mockups', 'Implement feature', 'Write tests', 'Deploy'];\n\n    for (const taskName of taskNames) {\n      const taskBody = {\n        data: {\n          name: taskName,\n          workspace: process.env.ASANA_WORKSPACE_ID,\n          projects: [projectGid]\n        }\n      };\n      const taskResult = await tasksApiInstance.createTask(taskBody);\n      console.log('Created task:', taskResult.data.name);\n    }\n\n    // Get all tasks in project\n    console.log('\\nFetching project tasks...');\n    const tasksResult = await tasksApiInstance.getTasksForProject(projectGid, {\n      opt_fields: 'name,completed'\n    });\n    console.log(`Project has ${tasksResult.data.length} tasks`);\n\n    // Mark first task as complete\n    if (tasksResult.data.length > 0) {\n      const firstTaskGid = tasksResult.data[0].gid;\n      console.log('\\nMarking first task as complete...');\n      await tasksApiInstance.updateTask(\n        { data: { completed: true } },\n        firstTaskGid\n      );\n      console.log('Task marked as complete');\n    }\n\n    console.log('\\nDemo completed successfully!');\n\n  } catch (error) {\n    console.error('Error:', error.response?.body || error.message);\n    process.exit(1);\n  }\n}\n\nmain();\n```\n\n## Notes\n\nThe Asana Node.js SDK is auto-generated from the OpenAPI specification, ensuring it stays current with the latest API features. The SDK supports both Personal Access Tokens for simple authentication and OAuth 2.0 for multi-user applications. All API methods return Promises and can be used with async/await syntax. The SDK automatically handles request formatting and response parsing. Rate limits apply: 1500 requests per minute for most operations, with some endpoints having lower limits. Use the `opt_fields` parameter to optimize API responses by requesting only the fields you need.\n"
  },
  {
    "path": "content/assemblyai/docs/transcription/DOC.md",
    "content": "---\nname: transcription\ndescription: \"AssemblyAI JavaScript SDK coding guide for speech-to-text transcription\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.18.4\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"assemblyai,transcription,speech-to-text,audio,ai\"\n---\n\n# AssemblyAI JavaScript SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official AssemblyAI JavaScript SDK:**\n\nPackage name: `assemblyai`\n\nTo check the latest version, run:\n```bash\nnpm view assemblyai version\n```\n\n**Never use deprecated, unofficial, or direct HTTP clients.** The official `assemblyai` package is the only supported JavaScript/TypeScript SDK maintained by AssemblyAI. It provides type-safe interfaces, automatic polling, streaming support, and simplified error handling.\n\n## 2. Installation\n\n### npm\n```bash\nnpm install assemblyai\n```\n\n### yarn\n```bash\nyarn add assemblyai\n```\n\n### pnpm\n```bash\npnpm add assemblyai\n```\n\n**Environment Variables (Required):**\n```bash\nASSEMBLYAI_API_KEY=your_api_key_here\n```\n\n**Get your API key:**\n\nSign up at https://www.assemblyai.com, navigate to the AssemblyAI Dashboard, and copy your API key from the \"Your API Key\" section.\n\n## 3. Initialization\n\n### Basic Client Initialization\n```javascript\nimport { AssemblyAI } from \"assemblyai\";\n\nconst client = new AssemblyAI({\n  apiKey: process.env.ASSEMBLYAI_API_KEY,\n});\n```\n\n### With Custom Configuration\n```javascript\nconst client = new AssemblyAI({\n  apiKey: process.env.ASSEMBLYAI_API_KEY,\n  // Optional: Custom base URL (for testing or proxy)\n  baseUrl: \"https://api.assemblyai.com\",\n});\n```\n\n**Authentication Best Practice:**\nThe SDK reads from the `ASSEMBLYAI_API_KEY` environment variable by default. Always store API keys in environment variables, never hardcode them in source code.\n\n## 4. Core API Surfaces\n\n### 4.1 Async Transcription\n\nAsync transcription processes pre-recorded audio files. The SDK automatically polls the transcription status until completion.\n\n**Minimal Example (Transcribe from URL):**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/audio.mp3\",\n});\n\nconsole.log(transcript.text);\n```\n\n**Minimal Example (Transcribe from Local File):**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"./path/to/local/audio.mp3\",\n});\n\nconsole.log(transcript.text);\n```\n\n**Advanced Example with Audio Intelligence:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/meeting.mp3\",\n  // Speaker identification\n  speaker_labels: true,\n  speakers_expected: 2,\n\n  // Audio intelligence features\n  sentiment_analysis: true,\n  entity_detection: true,\n  auto_highlights: true,\n  content_safety: true,\n  iab_categories: true,\n\n  // Language detection and translation\n  language_code: \"en\",\n  language_detection: false,\n\n  // Formatting options\n  format_text: true,\n  punctuate: true,\n  disfluencies: false,\n\n  // Custom vocabulary\n  word_boost: [\"AssemblyAI\", \"JavaScript\", \"Node.js\"],\n  boost_param: \"high\",\n});\n\n// Access results\nconsole.log(transcript.text);\nconsole.log(transcript.sentiment_analysis_results);\nconsole.log(transcript.entities);\nconsole.log(transcript.auto_highlights_result);\n```\n\n**Transcribe Without Waiting (Webhook or Manual Polling):**\n```javascript\n// Submit transcription without waiting\nconst transcript = await client.transcripts.submit({\n  audio: \"https://example.com/audio.mp3\",\n  webhook_url: \"https://your-domain.com/webhook\",\n});\n\nconsole.log(transcript.id); // Use this ID to check status later\n\n// Later, retrieve the transcript\nconst result = await client.transcripts.get(transcript.id);\nif (result.status === \"completed\") {\n  console.log(result.text);\n} else if (result.status === \"error\") {\n  console.error(result.error);\n}\n```\n\n### 4.2 Real-Time Streaming Transcription\n\nReal-time transcription provides live speech-to-text with low latency (300ms P50 on final transcripts).\n\n**Minimal Example:**\n```javascript\nimport { RealtimeTranscriber } from \"assemblyai\";\n\nconst transcriber = new RealtimeTranscriber({\n  apiKey: process.env.ASSEMBLYAI_API_KEY,\n  sampleRate: 16000,\n});\n\ntranscriber.on(\"open\", ({ sessionId }) => {\n  console.log(\"Session opened:\", sessionId);\n});\n\ntranscriber.on(\"transcript\", (transcript) => {\n  if (!transcript.text) return;\n\n  if (transcript.message_type === \"FinalTranscript\") {\n    console.log(\"Final:\", transcript.text);\n  } else {\n    console.log(\"Partial:\", transcript.text);\n  }\n});\n\ntranscriber.on(\"error\", (error) => {\n  console.error(\"Error:\", error);\n});\n\ntranscriber.on(\"close\", (code, reason) => {\n  console.log(\"Session closed:\", code, reason);\n});\n\n// Connect to the streaming service\nawait transcriber.connect();\n\n// Send audio data (16-bit PCM audio)\ntranscriber.sendAudio(audioChunk);\n\n// Close when done\nawait transcriber.close();\n```\n\n**Advanced Example with Audio Intelligence:**\n```javascript\nconst transcriber = new RealtimeTranscriber({\n  apiKey: process.env.ASSEMBLYAI_API_KEY,\n  sampleRate: 16000,\n  encoding: \"pcm_s16le\",\n\n  // Enable word-level timestamps\n  word_boost: [\"AssemblyAI\", \"JavaScript\"],\n\n  // Disable automatic punctuation\n  disable_partial_transcripts: false,\n\n  // End utterance silence threshold\n  end_utterance_silence_threshold: 500,\n});\n\ntranscriber.on(\"transcript\", (transcript) => {\n  if (transcript.message_type === \"FinalTranscript\") {\n    console.log(\"Final transcript:\", transcript.text);\n    console.log(\"Confidence:\", transcript.confidence);\n    console.log(\"Words:\", transcript.words);\n  } else if (transcript.message_type === \"PartialTranscript\") {\n    console.log(\"Partial:\", transcript.text);\n  }\n});\n\nawait transcriber.connect();\n\n// Stream from microphone or file\nconst stream = getMicrophoneStream(); // Your audio source\nstream.on(\"data\", (chunk) => {\n  transcriber.sendAudio(chunk);\n});\n```\n\n**Streaming with Temporary Token (Client-Side Security):**\n```javascript\n// Server-side: Generate temporary token\nconst token = await client.realtime.createTemporaryToken({\n  expires_in: 3600, // 1 hour\n});\n// Send token to client\n\n// Client-side: Use token instead of API key\nimport { RealtimeTranscriber } from \"assemblyai\";\n\nconst transcriber = new RealtimeTranscriber({\n  token: temporaryToken, // Use token instead of apiKey\n  sampleRate: 16000,\n});\n```\n\n### 4.3 PII Redaction\n\nAutomatically detect and redact 23 categories of Personally Identifiable Information (PII).\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/audio.mp3\",\n  redact_pii: true,\n  redact_pii_policies: [\"us_social_security_number\", \"credit_card_number\"],\n});\n\nconsole.log(transcript.text); // PII replaced with [REDACTED]\n```\n\n**Advanced Example with Audio Redaction:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/sensitive-call.mp3\",\n\n  // Text redaction\n  redact_pii: true,\n  redact_pii_policies: [\n    \"us_social_security_number\",\n    \"credit_card_number\",\n    \"credit_card_cvv\",\n    \"date_of_birth\",\n    \"drivers_license\",\n    \"email_address\",\n    \"phone_number\",\n    \"medical_condition\",\n    \"medication\",\n    \"person_name\",\n  ],\n  redact_pii_sub: \"hash\", // Options: \"hash\" or \"entity_name\"\n\n  // Audio redaction\n  redact_pii_audio: true,\n  redact_pii_audio_quality: \"mp3\", // Options: \"mp3\" or \"wav\"\n});\n\nconsole.log(transcript.text); // Text with PII redacted\nconsole.log(transcript.redacted_audio_url); // URL to redacted audio file\n\n// Download redacted audio\nif (transcript.redacted_audio_url) {\n  const redactedAudio = await fetch(transcript.redacted_audio_url);\n  // Process redacted audio\n}\n```\n\n**Available PII Categories:**\n\nTo see the complete list of 23+ available PII categories, check the TypeScript types or run:\n```bash\nnpm info assemblyai | grep -A 50 \"redact_pii_policies\"\n```\n\nOr view the official documentation at https://www.assemblyai.com/docs/audio-intelligence/pii-redaction for the most up-to-date list of supported PII categories including SSN, credit cards, medical information, and more.\n\n### 4.4 Speaker Diarization\n\nIdentify and label different speakers in audio (up to 10 speakers).\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/meeting.mp3\",\n  speaker_labels: true,\n});\n\n// Access speaker-labeled words\nfor (const utterance of transcript.utterances) {\n  console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);\n}\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/conference-call.mp3\",\n  speaker_labels: true,\n  speakers_expected: 4, // Hint for better accuracy\n\n  // Combine with other features\n  sentiment_analysis: true,\n  entity_detection: true,\n});\n\n// Analyze per-speaker sentiment\nconst speakerSentiments = {};\nfor (const result of transcript.sentiment_analysis_results) {\n  const speaker = result.speaker;\n  if (!speakerSentiments[speaker]) {\n    speakerSentiments[speaker] = [];\n  }\n  speakerSentiments[speaker].push(result.sentiment);\n}\n\nconsole.log(\"Speaker sentiments:\", speakerSentiments);\n\n// Get full utterances with timestamps\nfor (const utterance of transcript.utterances) {\n  console.log({\n    speaker: utterance.speaker,\n    text: utterance.text,\n    start: utterance.start,\n    end: utterance.end,\n    confidence: utterance.confidence,\n  });\n}\n```\n\n### 4.5 LeMUR - Apply LLMs to Audio\n\nLeMUR (Leveraging Large Language Models to Understand Recordings) applies powerful LLMs to transcribed speech for summarization, Q&A, action items, and custom tasks.\n\n**Question & Answer:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/meeting.mp3\",\n});\n\nconst { response } = await client.lemur.question({\n  transcript_ids: [transcript.id],\n  questions: [\n    {\n      question: \"What were the main action items discussed?\",\n      answer_format: \"bullet points\",\n    },\n    {\n      question: \"Who was assigned to work on the new feature?\",\n    },\n  ],\n});\n\nconsole.log(response);\n```\n\n**Summarization:**\n```javascript\nconst { response } = await client.lemur.summary({\n  transcript_ids: [transcript.id],\n  answer_format: \"one sentence\",\n  context: \"This is a sales call between a sales rep and a potential customer\",\n});\n\nconsole.log(\"Summary:\", response);\n```\n\n**Action Items:**\n```javascript\nconst { response } = await client.lemur.actionItems({\n  transcript_ids: [transcript.id],\n});\n\nconsole.log(\"Action items:\", response);\n```\n\n**Custom Task:**\n```javascript\nconst { response } = await client.lemur.task({\n  transcript_ids: [transcript.id],\n  prompt: \"Identify the key risks discussed in this meeting and categorize them as technical, financial, or operational. Return as JSON with structure: {technical: [], financial: [], operational: []}\",\n  final_model: \"anthropic/claude-3-5-sonnet\",\n});\n\nconsole.log(response);\n```\n\n**Advanced LeMUR with Multiple Transcripts:**\n```javascript\n// Transcribe multiple files\nconst transcript1 = await client.transcripts.transcribe({\n  audio: \"https://example.com/day1.mp3\",\n});\nconst transcript2 = await client.transcripts.transcribe({\n  audio: \"https://example.com/day2.mp3\",\n});\n\n// Analyze all transcripts together\nconst { response } = await client.lemur.task({\n  transcript_ids: [transcript1.id, transcript2.id],\n  prompt: `Analyze these two conference sessions and:\n    1. Identify common themes\n    2. List key speakers and their main points\n    3. Suggest follow-up topics for the next conference\n\n    Return as structured markdown.`,\n  final_model: \"anthropic/claude-3-5-sonnet\",\n  max_output_size: 4000,\n  temperature: 0.3,\n});\n\nconsole.log(response);\n```\n\n**Available LeMUR Models:**\n\nTo see the current list of supported LLM models, check the official documentation at https://www.assemblyai.com/docs/api-reference/lemur or inspect the TypeScript types. As of 2025, Claude 3.5 Sonnet is recommended for most tasks.\n\n### 4.6 Content Moderation\n\nDetect sensitive or inappropriate content across multiple categories.\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/content.mp3\",\n  content_safety: true,\n});\n\nfor (const result of transcript.content_safety_labels.results) {\n  console.log(`${result.text}: ${result.labels.map(l => l.label).join(\", \")}`);\n}\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/user-generated-content.mp3\",\n  content_safety: true,\n\n  // Set confidence threshold\n  content_safety_confidence: 75,\n});\n\n// Filter high-severity content\nconst severityThreshold = 0.8;\nconst flaggedContent = transcript.content_safety_labels.results.filter(\n  (result) => result.labels.some(label => label.confidence > severityThreshold)\n);\n\nif (flaggedContent.length > 0) {\n  console.log(\"Flagged content detected:\");\n  for (const item of flaggedContent) {\n    console.log({\n      text: item.text,\n      timestamp: `${item.timestamp.start}ms - ${item.timestamp.end}ms`,\n      labels: item.labels.map(l => ({\n        category: l.label,\n        confidence: l.confidence,\n        severity: l.severity,\n      })),\n    });\n  }\n}\n\n// Summary of content safety\nconsole.log(\"Summary:\", transcript.content_safety_labels.summary);\n```\n\n**Content Safety Categories:**\n\nTo see the complete list of content moderation categories, check the official documentation at https://www.assemblyai.com/docs/audio-intelligence/content-moderation or inspect the SDK TypeScript types for `ContentSafetyLabel`. Categories include violence, profanity, NSFW, hate speech, and more.\n\n### 4.7 Topic Detection (IAB Classification)\n\nAutomatically classify content using IAB (Interactive Advertising Bureau) taxonomy.\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/podcast.mp3\",\n  iab_categories: true,\n});\n\nconsole.log(\"Detected topics:\", transcript.iab_categories_result.summary);\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/podcast.mp3\",\n  iab_categories: true,\n});\n\n// Get overall summary\nconst topTopics = Object.entries(transcript.iab_categories_result.summary)\n  .sort((a, b) => b[1] - a[1])\n  .slice(0, 5);\n\nconsole.log(\"Top 5 topics:\");\nfor (const [topic, relevance] of topTopics) {\n  console.log(`${topic}: ${(relevance * 100).toFixed(1)}%`);\n}\n\n// Get segment-level topics\nfor (const result of transcript.iab_categories_result.results) {\n  console.log({\n    text: result.text,\n    timestamp: `${result.timestamp.start}ms - ${result.timestamp.end}ms`,\n    topics: result.labels.map(l => ({\n      category: l.label,\n      relevance: l.relevance,\n    })),\n  });\n}\n```\n\n### 4.8 Sentiment Analysis\n\nAnalyze emotional tone throughout the audio.\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/customer-call.mp3\",\n  sentiment_analysis: true,\n});\n\nfor (const result of transcript.sentiment_analysis_results) {\n  console.log(`\"${result.text}\": ${result.sentiment}`);\n}\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/customer-call.mp3\",\n  sentiment_analysis: true,\n  speaker_labels: true,\n});\n\n// Calculate sentiment distribution\nconst sentimentCounts = { POSITIVE: 0, NEUTRAL: 0, NEGATIVE: 0 };\nfor (const result of transcript.sentiment_analysis_results) {\n  sentimentCounts[result.sentiment]++;\n}\n\nconst total = transcript.sentiment_analysis_results.length;\nconsole.log(\"Sentiment distribution:\");\nconsole.log(`Positive: ${(sentimentCounts.POSITIVE / total * 100).toFixed(1)}%`);\nconsole.log(`Neutral: ${(sentimentCounts.NEUTRAL / total * 100).toFixed(1)}%`);\nconsole.log(`Negative: ${(sentimentCounts.NEGATIVE / total * 100).toFixed(1)}%`);\n\n// Analyze sentiment by speaker\nconst speakerSentiments = {};\nfor (const result of transcript.sentiment_analysis_results) {\n  if (!result.speaker) continue;\n\n  if (!speakerSentiments[result.speaker]) {\n    speakerSentiments[result.speaker] = { POSITIVE: 0, NEUTRAL: 0, NEGATIVE: 0 };\n  }\n  speakerSentiments[result.speaker][result.sentiment]++;\n}\n\nconsole.log(\"\\nSentiment by speaker:\", speakerSentiments);\n```\n\n### 4.9 Entity Detection\n\nExtract and classify named entities from transcripts.\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/news.mp3\",\n  entity_detection: true,\n});\n\nfor (const entity of transcript.entities) {\n  console.log(`${entity.text} (${entity.entity_type})`);\n}\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/business-meeting.mp3\",\n  entity_detection: true,\n});\n\n// Group entities by type\nconst entitiesByType = {};\nfor (const entity of transcript.entities) {\n  if (!entitiesByType[entity.entity_type]) {\n    entitiesByType[entity.entity_type] = [];\n  }\n  entitiesByType[entity.entity_type].push({\n    text: entity.text,\n    start: entity.start,\n    end: entity.end,\n  });\n}\n\nconsole.log(\"Entities by type:\");\nfor (const [type, entities] of Object.entries(entitiesByType)) {\n  console.log(`\\n${type}:`);\n  const uniqueEntities = [...new Set(entities.map(e => e.text))];\n  console.log(uniqueEntities.join(\", \"));\n}\n```\n\n**Entity Types:**\n\nTo see the complete list of detectable entity types, check the official documentation at https://www.assemblyai.com/docs/audio-intelligence/entity-detection or inspect the SDK TypeScript types for `EntityType`. Supported types include person names, locations, organizations, dates, medical terms, and more.\n\n### 4.10 Auto Highlights\n\nAutomatically identify and extract key phrases and important moments.\n\n**Minimal Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/meeting.mp3\",\n  auto_highlights: true,\n});\n\nfor (const highlight of transcript.auto_highlights_result.results) {\n  console.log(`${highlight.text} (rank: ${highlight.rank})`);\n}\n```\n\n**Advanced Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/podcast.mp3\",\n  auto_highlights: true,\n});\n\n// Get top highlights\nconst topHighlights = transcript.auto_highlights_result.results\n  .sort((a, b) => b.rank - a.rank)\n  .slice(0, 10);\n\nconsole.log(\"Top 10 highlights:\");\nfor (const highlight of topHighlights) {\n  console.log({\n    text: highlight.text,\n    rank: highlight.rank,\n    count: highlight.count,\n    timestamps: highlight.timestamps.map(t => ({\n      start: t.start,\n      end: t.end,\n    })),\n  });\n}\n```\n\n### 4.11 Export Subtitles (SRT/VTT)\n\nExport completed transcripts as subtitle files for video.\n\n**Export as SRT:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/video-audio.mp3\",\n});\n\nconst srt = await client.transcripts.subtitles(transcript.id, \"srt\");\nconsole.log(srt);\n\n// Or with custom chars per caption\nconst srtCustom = await client.transcripts.subtitles(\n  transcript.id,\n  \"srt\",\n  40 // chars_per_caption\n);\n```\n\n**Export as VTT:**\n```javascript\nconst vtt = await client.transcripts.subtitles(transcript.id, \"vtt\");\nconsole.log(vtt);\n\n// Save to file\nimport fs from \"fs\";\nfs.writeFileSync(\"subtitles.vtt\", vtt);\n```\n\n### 4.12 Paragraphs and Sentences\n\nRetrieve transcripts automatically segmented into paragraphs or sentences.\n\n**Get Paragraphs:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/lecture.mp3\",\n});\n\nconst paragraphs = await client.transcripts.paragraphs(transcript.id);\n\nfor (const para of paragraphs.paragraphs) {\n  console.log(`[${para.start}ms - ${para.end}ms]`);\n  console.log(para.text);\n  console.log(\"---\");\n}\n```\n\n**Get Sentences:**\n```javascript\nconst sentences = await client.transcripts.sentences(transcript.id);\n\nfor (const sentence of sentences.sentences) {\n  console.log({\n    text: sentence.text,\n    start: sentence.start,\n    end: sentence.end,\n    confidence: sentence.confidence,\n    speaker: sentence.speaker,\n  });\n}\n```\n\n### 4.13 Word-Level Timestamps\n\nAccess precise word-level timing information.\n\n**Example:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/speech.mp3\",\n});\n\nfor (const word of transcript.words) {\n  console.log({\n    text: word.text,\n    start: word.start, // milliseconds\n    end: word.end,\n    confidence: word.confidence,\n    speaker: word.speaker, // if speaker_labels enabled\n  });\n}\n\n// Find specific words\nconst targetWord = \"important\";\nconst occurrences = transcript.words.filter(w =>\n  w.text.toLowerCase() === targetWord.toLowerCase()\n);\n\nconsole.log(`\"${targetWord}\" appears ${occurrences.length} times at:`);\nfor (const word of occurrences) {\n  console.log(`  ${word.start}ms - ${word.end}ms`);\n}\n```\n\n## 5. Advanced Features\n\n### 5.1 Language Detection and Multilingual Support\n\n**Automatic Language Detection:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/multilingual.mp3\",\n  language_detection: true,\n});\n\nconsole.log(\"Detected language:\", transcript.language_code);\n```\n\n**Specify Language:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/spanish-audio.mp3\",\n  language_code: \"es\", // Spanish\n});\n```\n\n**Supported Languages:**\n\nAssemblyAI supports 100+ languages. To see the complete list of supported language codes, check the official documentation at https://www.assemblyai.com/docs/concepts/supported-languages or run:\n```bash\nnpm info assemblyai | grep -A 20 \"language_code\"\n```\n\nCommon language codes include `en` (English), `es` (Spanish), `fr` (French), `de` (German), `zh` (Chinese), `ja` (Japanese), and many more.\n\n**Multilingual Streaming (Beta):**\n```javascript\nconst transcriber = new RealtimeTranscriber({\n  apiKey: process.env.ASSEMBLYAI_API_KEY,\n  sampleRate: 16000,\n  // Auto-detect between supported languages\n  language_code: \"multi\",\n});\n```\n\n### 5.2 Custom Vocabulary and Word Boost\n\nImprove accuracy for domain-specific terms.\n\n**Word Boost:**\n```javascript\nconst transcript = await client.transcripts.transcribe({\n  audio: \"https://example.com/tech-talk.mp3\",\n  word_boost: [\n    \"AssemblyAI\",\n    \"Kubernetes\",\n    \"GraphQL\",\n    \"TypeScript\",\n    \"microservices\",\n  ],\n  boost_param: \"high\", // Options: \"low\", \"default\", \"high\"\n});\n```\n\n### 5.3 Audio Format Support\n\nAssemblyAI automatically detects and processes various audio formats.\n\n**Supported Formats:**\n\nAssemblyAI automatically detects and supports most common audio/video formats including MP3, MP4, WAV, FLAC, AAC, and more. For the complete list of supported formats, see https://www.assemblyai.com/docs/concepts/audio-formats\n\n**Optimal Settings:**\nFor best transcription quality, use audio with 16kHz+ sample rate, mono or stereo channels, and 16-bit+ depth.\n\n### 5.4 Webhook Configuration\n\nReceive notifications when transcription completes.\n\n**Setup Webhook:**\n```javascript\nconst transcript = await client.transcripts.submit({\n  audio: \"https://example.com/audio.mp3\",\n  webhook_url: \"https://your-domain.com/webhook/assemblyai\",\n  webhook_auth_header_name: \"X-Webhook-Secret\",\n  webhook_auth_header_value: process.env.WEBHOOK_SECRET,\n});\n```\n\n**Webhook Handler (Express Example):**\n```javascript\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/webhook/assemblyai\", (req, res) => {\n  // Verify webhook secret\n  if (req.headers[\"x-webhook-secret\"] !== process.env.WEBHOOK_SECRET) {\n    return res.status(401).send(\"Unauthorized\");\n  }\n\n  const { transcript_id, status } = req.body;\n\n  if (status === \"completed\") {\n    console.log(\"Transcription completed:\", transcript_id);\n    // Retrieve full transcript\n    client.transcripts.get(transcript_id).then(transcript => {\n      console.log(transcript.text);\n    });\n  } else if (status === \"error\") {\n    console.error(\"Transcription failed:\", req.body.error);\n  }\n\n  res.sendStatus(200);\n});\n```\n\n### 5.5 Polling Status Manually\n\n```javascript\nconst transcript = await client.transcripts.submit({\n  audio: \"https://example.com/audio.mp3\",\n});\n\n// Poll every 3 seconds\nconst checkStatus = async () => {\n  const result = await client.transcripts.get(transcript.id);\n\n  if (result.status === \"completed\") {\n    console.log(\"Done:\", result.text);\n    return result;\n  } else if (result.status === \"error\") {\n    throw new Error(result.error);\n  } else {\n    console.log(\"Status:\", result.status);\n    await new Promise(resolve => setTimeout(resolve, 3000));\n    return checkStatus();\n  }\n};\n\nconst finalTranscript = await checkStatus();\n```\n\n### 5.6 Delete Transcripts\n\nPermanently delete transcripts from AssemblyAI servers.\n\n```javascript\n// Delete a specific transcript\nawait client.transcripts.delete(transcript.id);\nconsole.log(\"Transcript deleted\");\n```\n\n### 5.7 List Transcripts\n\nRetrieve a list of previously submitted transcripts.\n\n```javascript\nconst page = await client.transcripts.list({\n  limit: 10,\n  status: \"completed\",\n});\n\nfor (const transcript of page.transcripts) {\n  console.log({\n    id: transcript.id,\n    status: transcript.status,\n    created: transcript.created,\n    audio_duration: transcript.audio_duration,\n  });\n}\n\n// Handle pagination\nif (page.page_details.next_url) {\n  const nextPage = await client.transcripts.list({\n    limit: 10,\n    before_id: page.transcripts[page.transcripts.length - 1].id,\n  });\n}\n```\n\n## 6. TypeScript Usage\n\nThe AssemblyAI SDK is written in TypeScript and provides comprehensive type definitions.\n\n### Import Types\n```typescript\nimport {\n  AssemblyAI,\n  TranscribeParams,\n  Transcript,\n  RealtimeTranscript,\n  TranscriptStatus,\n  SentimentAnalysisResult,\n  Entity,\n  ContentSafetyLabel,\n  LemurTaskParams,\n  LemurResponse,\n} from \"assemblyai\";\n```\n\n### Type-Safe Transcription\n```typescript\nconst params: TranscribeParams = {\n  audio: \"https://example.com/audio.mp3\",\n  speaker_labels: true,\n  sentiment_analysis: true,\n  entity_detection: true,\n};\n\nconst transcript: Transcript = await client.transcripts.transcribe(params);\n\n// TypeScript knows the available properties\nif (transcript.status === \"completed\") {\n  const text: string = transcript.text;\n  const sentiments: SentimentAnalysisResult[] | undefined =\n    transcript.sentiment_analysis_results;\n  const entities: Entity[] | undefined = transcript.entities;\n}\n```\n\n### Type-Safe LeMUR\n```typescript\nimport type { LemurQuestionAnswerParams } from \"assemblyai\";\n\nconst params: LemurQuestionAnswerParams = {\n  transcript_ids: [transcript.id],\n  questions: [\n    {\n      question: \"What were the key takeaways?\",\n      answer_format: \"bullet points\",\n    },\n  ],\n  final_model: \"anthropic/claude-3-5-sonnet\",\n};\n\nconst result = await client.lemur.question(params);\n```\n\n### Type Guards for Real-Time Transcripts\n```typescript\nimport { RealtimeTranscript } from \"assemblyai\";\n\ntranscriber.on(\"transcript\", (transcript: RealtimeTranscript) => {\n  if (transcript.message_type === \"FinalTranscript\") {\n    // TypeScript knows this is a final transcript\n    const text: string = transcript.text;\n    const confidence: number = transcript.confidence;\n    const words: Array<{ text: string; start: number; end: number }> =\n      transcript.words;\n  } else if (transcript.message_type === \"PartialTranscript\") {\n    // Partial transcript\n    const partialText: string = transcript.text;\n  }\n});\n```\n\n"
  },
  {
    "path": "content/async-timeout/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"async-timeout compatibility timeout context manager for asyncio code on Python 3.8+\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"python,asyncio,timeout,async,compatibility\"\n---\n\n# async-timeout Python Package Guide\n\n## Golden Rule\n\nUse `async-timeout` only when you need one timeout API that still works on Python versions before 3.11, or when a dependency still expects it. The project is deprecated because Python 3.11+ includes `asyncio.timeout()` and `asyncio.timeout_at()` in the standard library, and the maintainers recommend using the stdlib APIs directly when you can.\n\n## Install\n\n`async-timeout` 5.0.1 requires Python 3.8 or newer.\n\n```bash\npython -m pip install \"async-timeout==5.0.1\"\n```\n\nImportant naming detail:\n\n- PyPI package: `async-timeout`\n- Import path: `async_timeout`\n\n## Imports And Setup\n\nThis package has no client object, credentials, or environment variables. You import the timeout helpers directly and use them inside async code.\n\nIf you need one import path that works on Python 3.8 through 3.13, import from `async_timeout`:\n\n```python\nfrom async_timeout import timeout, timeout_at\n```\n\nIf your code runs on Python 3.11+ and you only need the basic timeout context manager APIs, the maintainer docs recommend preferring the stdlib and falling back only on older Python:\n\n```python\nimport sys\n\nif sys.version_info >= (3, 11):\n    from asyncio import timeout, timeout_at\nelse:\n    from async_timeout import timeout, timeout_at\n```\n\n## Time-Limit An Async Block\n\nUse `async with timeout(seconds):` around the specific block you want to cancel if it runs too long.\n\n```python\nimport asyncio\nfrom async_timeout import timeout\n\n\nasync def main() -> None:\n    try:\n        async with timeout(1.5):\n            await asyncio.sleep(2)\n    except TimeoutError:\n        print(\"operation timed out\")\n\n\nasyncio.run(main())\n```\n\nThe timeout exception is raised outside the `async with` block, not inside it.\n\n`None` disables the timeout:\n\n```python\nimport asyncio\nfrom async_timeout import timeout\n\n\nasync def main() -> None:\n    async with timeout(None):\n        await asyncio.sleep(0.2)\n```\n\n## Use An Absolute Deadline\n\nUse `timeout_at()` when you already have a deadline in the event loop's monotonic clock.\n\n```python\nimport asyncio\nfrom async_timeout import timeout_at\n\n\nasync def main() -> None:\n    loop = asyncio.get_running_loop()\n    deadline = loop.time() + 5\n\n    try:\n        async with timeout_at(deadline):\n            await asyncio.sleep(6)\n    except TimeoutError:\n        print(\"deadline exceeded\")\n\n\nasyncio.run(main())\n```\n\nPass `loop.time()` based deadlines, not `time.time()`. `timeout_at()` does not use wall-clock or POSIX time.\n\n## Inspect And Reschedule A Timeout\n\nThe context manager exposes both the newer stdlib-compatible API and the older compatibility API.\n\n```python\nimport asyncio\nfrom async_timeout import timeout\n\n\nasync def main() -> None:\n    async with timeout(1.0) as cm:\n        await asyncio.sleep(0.4)\n\n        # Stdlib-compatible API\n        cm.reschedule(cm.when() + 1.0)\n\n        await asyncio.sleep(0.2)\n\n    print(cm.expired())\n\n\nasyncio.run(main())\n```\n\nIf you are maintaining older code that still uses the pre-5.x compatibility API, the same context object also exposes `shift()`, `update()`, `reject()`, and the `deadline` property.\n\nTo disable a timeout after entering the block:\n\n```python\nimport asyncio\nfrom async_timeout import timeout\n\n\nasync def main() -> None:\n    async with timeout(10) as cm:\n        cm.reschedule(None)\n        await asyncio.sleep(0.2)\n```\n\nRescheduling is only allowed before the timeout expires and before the `async with` block exits.\n\n## When To Use This Instead Of `asyncio.wait_for()`\n\nThe maintainer docs call out one main reason to use this style of timeout context manager: it wraps a block directly and does not create a new task the way `asyncio.wait_for()` does.\n\nThis is useful when you want timeout behavior around several awaited operations inside one block instead of around one awaitable.\n\n## Common Pitfalls\n\n- Use `async with`, not plain `with`. Sync context manager support was dropped in the 5.0.0 release.\n- Catch `TimeoutError` outside the context manager scope.\n- Install name and import name differ: `pip install async-timeout`, then `import async_timeout`.\n- Prefer `asyncio.timeout()` on Python 3.11+ when you do not need this compatibility dependency.\n- Use `loop.time()` with `timeout_at()`. Passing wall-clock timestamps will produce the wrong deadline.\n- Use `cm.expired()` with the stdlib-compatible API. Older compatibility code may still use the `cm.expired` property instead.\n- `expired` tells you whether this timeout context caused the cancellation. If the wrapped code raises its own timeout exception, it stays false.\n\n## Version Notes For 5.0.1\n\n- PyPI lists `5.0.1` as the latest release as of March 13, 2026.\n- The project README and PyPI page both mark the package as deprecated and no longer actively supported.\n- The major behavioral change in the 5.x line happened in `5.0.0`: the package became compatible with `asyncio.Timeout` on Python 3.11+, while deprecated sync context manager support was removed.\n- `5.0.1` is a small follow-up release; the GitHub release notes list it as a misc-only update.\n\n## Official Sources\n\n- Maintainer README: https://github.com/aio-libs/async-timeout\n- GitHub releases: https://github.com/aio-libs/async-timeout/releases\n- PyPI project page: https://pypi.org/project/async-timeout/\n"
  },
  {
    "path": "content/asyncpg/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"asyncpg package guide for asyncio PostgreSQL connections, pools, transactions, and type codecs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.31.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"asyncpg,postgresql,postgres,asyncio,database,sql\"\n---\n\n# asyncpg Python Package Guide\n\n## What It Is\n\n`asyncpg` is MagicStack's native asyncio PostgreSQL driver. It is not a DB-API wrapper and it is not an ORM. It exposes PostgreSQL-oriented async primitives directly: connections, pools, transactions, prepared statements, cursors, COPY helpers, and type codecs.\n\n## Version-Sensitive Notes For `0.31.0`\n\n- The version used here `0.31.0`, the current docs site, and the current PyPI release all align as of March 12, 2026.\n- `0.31.0` adds PostgreSQL connection service file support via the `service` and `servicefile` connection arguments.\n- `0.31.0` adds Python 3.14 support, including experimental subinterpreter and free-threading support.\n- `0.31.0` drops Python 3.8 support. Do not target Python 3.8 for new code.\n- Pool `connect` and `reset` hooks were added in `0.30.0`; they are available in this version and useful for advanced pool customization.\n\n## Install\n\nPin the exact version if your project depends on stable behavior:\n\n```bash\npython -m pip install \"asyncpg==0.31.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"asyncpg==0.31.0\"\npoetry add \"asyncpg==0.31.0\"\n```\n\nIf you need GSSAPI or SSPI authentication support:\n\n```bash\npython -m pip install \"asyncpg[gssauth]==0.31.0\"\n```\n\nUpstream notes that Linux GSSAPI installs need a C compiler plus Kerberos development headers because the `gssapi` dependency does not ship Linux wheels.\n\n## Connection Setup\n\nYou can connect with a DSN or explicit keyword arguments. `asyncpg` also honors the usual PostgreSQL environment variables for most connection defaults, including `PGHOST`, `PGPORT`, `PGUSER`, and `PGDATABASE`.\n\n### Minimal connection\n\n```python\nimport asyncio\nimport asyncpg\n\nasync def main() -> None:\n    conn = await asyncpg.connect(\n        user=\"app\",\n        password=\"secret\",\n        database=\"appdb\",\n        host=\"127.0.0.1\",\n    )\n    try:\n        value = await conn.fetchval(\"select 1\")\n        print(value)\n    finally:\n        await conn.close()\n\nasyncio.run(main())\n```\n\n### DSN-based connection\n\n```python\nconn = await asyncpg.connect(\n    \"postgresql://app:secret@127.0.0.1:5432/appdb\"\n)\n```\n\n### Environment-driven setup\n\nPrefer keeping connection settings out of source code:\n\n```bash\nexport PGHOST=127.0.0.1\nexport PGPORT=5432\nexport PGUSER=app\nexport PGDATABASE=appdb\n```\n\nThen connect with only the secret at runtime, or let PostgreSQL password handling resolve it from a passfile:\n\n```python\nconn = await asyncpg.connect()\n```\n\n## Authentication And Config\n\n### Password handling\n\n- `password=` can be a string or a callable. If it is a callable, `asyncpg` calls it whenever a new connection is established.\n- `PGPASSWORD` works, but upstream explicitly discourages it because other users or processes may be able to read it.\n- Prefer `passfile=` or the default PostgreSQL password file (`~/.pgpass`, or `%APPDATA%\\\\postgresql\\\\pgpass.conf` on Windows) for local and server deployments.\n\n### PostgreSQL service files\n\n`0.31.0` adds support for PostgreSQL connection service files. This is useful when you want to keep host, port, database, SSL, and similar settings in `pg_service.conf` rather than in code.\n\n```python\nconn = await asyncpg.connect(\n    service=\"app-primary\",\n    servicefile=\"/etc/postgresql-common/pg_service.conf\",\n)\n```\n\n### SSL\n\n`ssl=` accepts:\n\n- `True` or an `ssl.SSLContext`\n- PostgreSQL-style modes such as `'disable'`, `'prefer'`, `'allow'`, `'require'`, `'verify-ca'`, and `'verify-full'`\n\nThe default is `'prefer'`, which will try TLS first and fall back to non-TLS if that fails. For production systems, prefer `ssl=\"verify-full\"` or an explicit `ssl.SSLContext` that verifies the server certificate.\n\n```python\nimport ssl\n\nssl_ctx = ssl.create_default_context(\n    ssl.Purpose.SERVER_AUTH,\n    cafile=\"/etc/ssl/certs/pg-ca.pem\",\n)\nssl_ctx.check_hostname = True\n\nconn = await asyncpg.connect(\n    host=\"db.example.com\",\n    user=\"app\",\n    database=\"appdb\",\n    ssl=ssl_ctx,\n)\n```\n\n### Timeouts and server settings\n\n`asyncpg.connect(...)` supports:\n\n- `timeout=` for connection establishment\n- `command_timeout=` as the default per-command timeout\n- `server_settings=` for PostgreSQL runtime parameters such as `application_name`\n\n```python\nconn = await asyncpg.connect(\n    host=\"db.example.com\",\n    user=\"app\",\n    database=\"appdb\",\n    timeout=10,\n    command_timeout=30,\n    server_settings={\"application_name\": \"billing-worker\"},\n)\n```\n\n## Core Query Patterns\n\nUse PostgreSQL positional placeholders: `$1`, `$2`, and so on.\n\n```python\nrow = await conn.fetchrow(\n    \"\"\"\n    select id, email, created_at\n    from users\n    where id = $1\n    \"\"\",\n    user_id,\n)\n```\n\nCommon methods:\n\n- `fetch(...)`: many rows as `list[asyncpg.Record]`\n- `fetchrow(...)`: one row or `None`\n- `fetchval(...)`: first column of the first row\n- `execute(...)`: command status string\n- `executemany(...)`: repeated statement execution\n\n### Inserts and reads\n\n```python\nawait conn.execute(\n    \"\"\"\n    insert into users(email, is_active)\n    values($1, $2)\n    \"\"\",\n    \"alice@example.com\",\n    True,\n)\n\nuser_id = await conn.fetchval(\n    \"select id from users where email = $1\",\n    \"alice@example.com\",\n)\n```\n\n### Records are mappings, not dicts\n\nReturned rows are `asyncpg.Record` objects. Convert them when you need plain JSON-serializable data:\n\n```python\nrow = await conn.fetchrow(\"select id, email from users where id = $1\", user_id)\npayload = dict(row) if row is not None else None\n```\n\n## Transactions\n\nOutside an explicit transaction block, writes are applied immediately. Use `Connection.transaction()` with `async with` for atomic multi-statement work.\n\n```python\nasync with conn.transaction():\n    order_id = await conn.fetchval(\n        \"\"\"\n        insert into orders(customer_id, total_cents)\n        values($1, $2)\n        returning id\n        \"\"\",\n        customer_id,\n        total_cents,\n    )\n\n    await conn.execute(\n        \"\"\"\n        insert into order_events(order_id, event_type)\n        values($1, $2)\n        \"\"\",\n        order_id,\n        \"created\",\n    )\n```\n\nYou can also control transaction mode:\n\n```python\nasync with conn.transaction(\n    isolation=\"serializable\",\n    readonly=False,\n    deferrable=False,\n):\n    ...\n```\n\n## Connection Pools\n\nFor server-style applications, upstream recommends using `asyncpg.create_pool(...)`. The pool handles connection reuse and exposes `acquire()` for short-lived request work.\n\n```python\nimport asyncio\nimport asyncpg\n\nasync def init_pool() -> asyncpg.Pool:\n    return await asyncpg.create_pool(\n        host=\"127.0.0.1\",\n        user=\"app\",\n        password=\"secret\",\n        database=\"appdb\",\n        min_size=5,\n        max_size=20,\n        command_timeout=30,\n    )\n\nasync def get_user(pool: asyncpg.Pool, user_id: int) -> dict | None:\n    async with pool.acquire() as conn:\n        row = await conn.fetchrow(\n            \"select id, email from users where id = $1\",\n            user_id,\n        )\n        return dict(row) if row is not None else None\n```\n\nImportant pool parameters in `0.31.0`:\n\n- `min_size`, `max_size`\n- `max_queries`\n- `max_inactive_connection_lifetime`\n- `init=` to initialize new connections once, such as registering type codecs\n- `setup=` to prepare a connection before each `acquire()`\n- `reset=` to customize how a connection is cleaned up before release\n\n### Register codecs on every pooled connection\n\nIf your application depends on custom JSON or other codecs, register them in `init=` so every new pooled connection is configured consistently:\n\n```python\nimport json\n\nasync def init_connection(conn: asyncpg.Connection) -> None:\n    await conn.set_type_codec(\n        \"json\",\n        encoder=json.dumps,\n        decoder=json.loads,\n        schema=\"pg_catalog\",\n    )\n\npool = await asyncpg.create_pool(\n    host=\"127.0.0.1\",\n    user=\"app\",\n    password=\"secret\",\n    database=\"appdb\",\n    init=init_connection,\n)\n```\n\n## Type Conversion And Codecs\n\n`asyncpg` automatically maps many PostgreSQL types to Python values:\n\n- `timestamp` -> `datetime.datetime`\n- `date` -> `datetime.date`\n- `uuid` -> `uuid.UUID`\n- `numeric` -> `decimal.Decimal`\n- arrays -> Python `list`\n- records -> `asyncpg.Record`\n\nImportant default behaviors:\n\n- `json` and `jsonb` decode to `str` by default, not Python `dict`\n- `numeric` decodes to `Decimal`\n- unsupported or unknown types fall back to text\n\n### Decode JSON automatically\n\n```python\nimport json\n\nawait conn.set_type_codec(\n    \"json\",\n    encoder=json.dumps,\n    decoder=json.loads,\n    schema=\"pg_catalog\",\n)\n\ndoc = await conn.fetchval(\"select $1::json\", {\"ok\": True})\nassert doc == {\"ok\": True}\n```\n\n### Decode `numeric` as float when precision loss is acceptable\n\n```python\nawait conn.set_type_codec(\n    \"numeric\",\n    encoder=str,\n    decoder=float,\n    schema=\"pg_catalog\",\n    format=\"text\",\n)\n```\n\n### Enable builtin `hstore` mapping\n\n```python\nawait conn.set_builtin_type_codec(\n    \"hstore\",\n    codec_name=\"pg_contrib.hstore\",\n)\n```\n\n## COPY And Bulk Loading\n\nIf you need PostgreSQL bulk I/O, prefer the native COPY helpers instead of row-by-row inserts:\n\n- `copy_records_to_table(...)`\n- `copy_to_table(...)`\n- `copy_from_table(...)`\n- `copy_from_query(...)`\n\nThese are usually the right tool for high-volume ingestion or export pipelines.\n\n## Common Pitfalls\n\n- Use PostgreSQL placeholders like `$1`, not `%s` or `?`.\n- `expression IN $1` is invalid PostgreSQL syntax. Use `expression = any($1::mytype[])`.\n- `asyncpg` is not DB-API compatible. Do not assume cursor or connection semantics from synchronous drivers.\n- `asyncpg.Record` is not a plain dict. Convert with `dict(row)` if the next layer expects serializable mappings.\n- `json` and `jsonb` come back as strings unless you register a codec.\n- Cursors created with `Connection.cursor()` cannot be used outside a transaction.\n- Prepared statements do not work correctly behind PgBouncer in `transaction` or `statement` pool modes. If you must use that setup, pass `statement_cache_size=0` and avoid explicit prepared statements, or switch PgBouncer to `session` mode.\n- Prepared statements, cursors, and listeners tied to a pooled connection become invalid or are removed when the connection is released back to the pool.\n- The pool default size is `min_size=10` and `max_size=10`. Tune it deliberately instead of assuming it matches your service concurrency.\n- For production TLS, do not rely on the default `'prefer'` mode if plaintext fallback is unacceptable.\n\n## Recommended Workflow For Agents\n\n1. Pin `asyncpg==0.31.0` unless the project already uses a newer reviewed version.\n2. Choose one connection style early: DSN, explicit kwargs, or PostgreSQL service file.\n3. Set SSL and password handling explicitly for deployed environments instead of relying on implicit local defaults.\n4. Use `fetchval`, `fetchrow`, and `execute` first; reach for prepared statements or cursors only when there is a clear need.\n5. For web services or workers, create one pool at startup and acquire connections per request or job.\n6. If the schema uses JSON, `hstore`, PostGIS, or custom types, register codecs before writing business logic.\n\n## Official Sources\n\n- Installation: https://magicstack.github.io/asyncpg/current/installation.html\n- Usage guide: https://magicstack.github.io/asyncpg/current/usage.html\n- API reference: https://magicstack.github.io/asyncpg/current/api/index.html\n- FAQ: https://magicstack.github.io/asyncpg/current/faq.html\n- PyPI package page: https://pypi.org/project/asyncpg/\n- `0.31.0` release notes: https://github.com/MagicStack/asyncpg/releases/tag/v0.31.0\n"
  },
  {
    "path": "content/atlassian/docs/confluence/javascript/DOC.md",
    "content": "---\nname: confluence\ndescription: \"Confluence Cloud API coding guidelines for JavaScript/TypeScript using the confluence.js library\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.1.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"atlassian,confluence,wiki,documentation,collaboration\"\n---\n\n# Confluence Cloud API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a **Confluence Cloud API coding expert**. Help me write correct, idiomatic JavaScript/TypeScript that calls the Atlassian Confluence Cloud REST API using the confluence.js library.\n\nUse **only official Atlassian sources** for API behavior, fields, and constraints. This guide summarizes key patterns for both **Node.js** and **browser** applications.\n\n> Ground truth: Atlassian Confluence Cloud REST API documentation at developer.atlassian.com/cloud/confluence/\n\n## Golden Rule: Use confluence.js Library\n\n**CRITICAL:** Use the `confluence.js` npm package (version 2.1.0 or later) for interacting with Confluence Cloud REST API. This is the most comprehensive and actively maintained community library for both Cloud and Server APIs.\n\n**DO NOT use:**\n- `confluence-api` (outdated, less comprehensive)\n- `atlassian-confluence` (deprecated)\n- Direct REST API calls without a client library (error-prone)\n\n**Install:**\n```bash\nnpm install confluence.js\n# or\nyarn add confluence.js\n# or\npnpm add confluence.js\n```\n\nThe library supports Node.js v20.0.0+ and modern browsers with full TypeScript support.\n\n## Authentication\n\nConfluence Cloud supports multiple authentication methods. Choose based on your use case.\n\n### API Token (Basic Auth) - Recommended for Scripts\n\nGenerate an API token from your Atlassian Account Settings (https://id.atlassian.com/manage-profile/security/api-tokens).\n\n```ts\nimport { ConfluenceClient } from 'confluence.js';\n\nconst client = new ConfluenceClient({\n  host: 'https://your-domain.atlassian.net/wiki',\n  authentication: {\n    basic: {\n      email: 'your-email@example.com',\n      apiToken: process.env.CONFLUENCE_API_TOKEN,\n    },\n  },\n});\n```\n\n**Environment Variable Setup:**\n\n```bash\n# .env file\nCONFLUENCE_API_TOKEN=your_api_token_here\nCONFLUENCE_EMAIL=your-email@example.com\nCONFLUENCE_HOST=https://your-domain.atlassian.net/wiki\n```\n\n**Loading in code:**\n\n```ts\nimport { config } from 'dotenv';\nimport { ConfluenceClient } from 'confluence.js';\n\nconfig(); // Load .env file\n\nconst client = new ConfluenceClient({\n  host: process.env.CONFLUENCE_HOST!,\n  authentication: {\n    basic: {\n      email: process.env.CONFLUENCE_EMAIL!,\n      apiToken: process.env.CONFLUENCE_API_TOKEN!,\n    },\n  },\n});\n```\n\n### OAuth 2.0 (3LO) - For Third-Party Apps\n\nUse OAuth 2.0 three-legged authentication for apps that access Confluence on behalf of users.\n\n```ts\nimport { ConfluenceClient } from 'confluence.js';\n\nconst client = new ConfluenceClient({\n  host: 'https://your-domain.atlassian.net/wiki',\n  authentication: {\n    oauth2: {\n      accessToken: process.env.OAUTH_ACCESS_TOKEN!,\n    },\n  },\n});\n```\n\n### JWT (Server-to-Server) - For Atlassian Connect Apps\n\n```ts\nimport { ConfluenceClient } from 'confluence.js';\n\nconst client = new ConfluenceClient({\n  host: 'https://your-domain.atlassian.net/wiki',\n  authentication: {\n    jwt: {\n      issuer: process.env.JWT_ISSUER!,\n      secret: process.env.JWT_SECRET!,\n      expiryTimeSeconds: 180, // Optional, defaults to 180\n    },\n  },\n});\n```\n\n## Initialization Patterns\n\n### Basic Initialization\n\n```ts\nimport { ConfluenceClient } from 'confluence.js';\n\nconst client = new ConfluenceClient({\n  host: 'https://your-domain.atlassian.net/wiki',\n  authentication: {\n    basic: {\n      email: 'your-email@example.com',\n      apiToken: 'your-api-token',\n    },\n  },\n});\n```\n\n### With Custom API Prefix\n\nIf your Confluence instance uses a non-standard API path:\n\n```ts\nconst client = new ConfluenceClient({\n  host: 'https://your-domain.atlassian.net',\n  apiPrefix: '/custom/api/path',\n  authentication: {\n    basic: {\n      email: 'your-email@example.com',\n      apiToken: 'your-api-token',\n    },\n  },\n});\n```\n\n### Tree Shaking for Smaller Bundles\n\nImport only the API modules you need:\n\n```ts\nimport { ContentClient } from 'confluence.js/out/api/content';\nimport { SpaceClient } from 'confluence.js/out/api/space';\n\n// Use individual clients\nconst contentClient = new ContentClient({\n  host: 'https://your-domain.atlassian.net/wiki',\n  authentication: { /* ... */ },\n});\n```\n\n## Pages API\n\n### Get Page by ID\n\n```ts\nconst page = await client.content.getContent({\n  id: '123456789',\n  expand: ['body.storage', 'version', 'space'],\n});\n\nconsole.log(page.title);\nconsole.log(page.body?.storage?.value);\nconsole.log(page.version?.number);\n```\n\n### Get Page by Title and Space\n\n```ts\nconst results = await client.content.getContent({\n  spaceKey: 'DEMO',\n  title: 'Project Overview',\n  expand: ['body.storage', 'version'],\n});\n\nif (results.results && results.results.length > 0) {\n  const page = results.results[0];\n  console.log(page.id, page.title);\n}\n```\n\n### Create a Page\n\n```ts\nconst newPage = await client.content.createContent({\n  type: 'page',\n  title: 'Getting Started Guide',\n  space: { key: 'DEMO' },\n  body: {\n    storage: {\n      value: '<h1>Welcome</h1><p>This is the introduction to our project.</p>',\n      representation: 'storage',\n    },\n  },\n});\n\nconsole.log(`Created page: ${newPage.id}`);\nconsole.log(`URL: ${newPage._links?.webui}`);\n```\n\n### Create a Child Page\n\n```ts\nconst childPage = await client.content.createContent({\n  type: 'page',\n  title: 'Installation Instructions',\n  space: { key: 'DEMO' },\n  ancestors: [{ id: '123456789' }], // Parent page ID\n  body: {\n    storage: {\n      value: '<p>Follow these steps to install...</p>',\n      representation: 'storage',\n    },\n  },\n});\n```\n\n### Update a Page\n\n**IMPORTANT:** Always increment the version number when updating.\n\n```ts\n// First, get the current page to retrieve version\nconst currentPage = await client.content.getContent({\n  id: '123456789',\n  expand: ['version'],\n});\n\n// Update with incremented version\nconst updatedPage = await client.content.updateContent({\n  id: '123456789',\n  type: 'page',\n  title: 'Updated Title',\n  version: {\n    number: currentPage.version!.number! + 1,\n  },\n  body: {\n    storage: {\n      value: '<h1>Updated Content</h1><p>New information here.</p>',\n      representation: 'storage',\n    },\n  },\n});\n\nconsole.log(`Updated to version ${updatedPage.version?.number}`);\n```\n\n### Update Only Page Content (Keep Title)\n\n```ts\nconst currentPage = await client.content.getContent({\n  id: '123456789',\n  expand: ['version', 'space'],\n});\n\nconst updatedPage = await client.content.updateContent({\n  id: '123456789',\n  type: 'page',\n  title: currentPage.title, // Keep existing title\n  space: { key: currentPage.space?.key },\n  version: {\n    number: currentPage.version!.number! + 1,\n  },\n  body: {\n    storage: {\n      value: '<p>Only the content changed.</p>',\n      representation: 'storage',\n    },\n  },\n});\n```\n\n### Delete a Page\n\n```ts\nawait client.content.deleteContent({ id: '123456789' });\nconsole.log('Page deleted successfully');\n```\n\n### Get Page Children\n\n```ts\nconst children = await client.content.getContentChildren({\n  id: '123456789',\n  expand: ['page'],\n});\n\nif (children.page?.results) {\n  for (const child of children.page.results) {\n    console.log(`Child: ${child.title} (${child.id})`);\n  }\n}\n```\n\n### Get Page History\n\n```ts\nconst history = await client.content.getHistory({ id: '123456789' });\n\nconsole.log(`Created by: ${history.createdBy?.displayName}`);\nconsole.log(`Created at: ${history.createdDate}`);\nconsole.log(`Latest version: ${history.latest?.number}`);\n```\n\n### Get Page Versions\n\n```ts\nconst versions = await client.content.getContentVersions({\n  id: '123456789',\n  limit: 10,\n});\n\nfor (const version of versions.results || []) {\n  console.log(`Version ${version.number} by ${version.by?.displayName}`);\n  console.log(`  When: ${version.when}`);\n  console.log(`  Message: ${version.message || 'No message'}`);\n}\n```\n\n## Spaces API\n\n### Get Space by Key\n\n```ts\nconst space = await client.space.getSpace({\n  spaceKey: 'DEMO',\n  expand: ['description.plain', 'homepage'],\n});\n\nconsole.log(space.name);\nconsole.log(space.description?.plain?.value);\nconsole.log(space.homepage?.id);\n```\n\n### Get All Spaces\n\n```ts\nconst spaces = await client.space.getSpaces({\n  limit: 50,\n  expand: ['description.plain'],\n});\n\nfor (const space of spaces.results || []) {\n  console.log(`${space.key}: ${space.name}`);\n}\n```\n\n### Get Spaces with Pagination\n\n```ts\nlet start = 0;\nconst limit = 25;\nlet hasMore = true;\n\nwhile (hasMore) {\n  const spaces = await client.space.getSpaces({\n    start,\n    limit,\n  });\n\n  for (const space of spaces.results || []) {\n    console.log(`${space.key}: ${space.name}`);\n  }\n\n  start += limit;\n  hasMore = (spaces.results?.length || 0) === limit;\n}\n```\n\n### Create a Space\n\n```ts\nconst newSpace = await client.space.createSpace({\n  key: 'PROJ',\n  name: 'Project Galaxy',\n  description: {\n    plain: {\n      value: 'Documentation for Project Galaxy',\n      representation: 'plain',\n    },\n  },\n});\n\nconsole.log(`Created space: ${newSpace.key}`);\nconsole.log(`URL: ${newSpace._links?.webui}`);\n```\n\n### Create a Private Space\n\n```ts\nconst privateSpace = await client.space.createPrivateSpace({\n  key: 'PRIV',\n  name: 'Private Team Space',\n  description: {\n    plain: {\n      value: 'Internal team documentation',\n      representation: 'plain',\n    },\n  },\n});\n```\n\n### Update a Space\n\n```ts\nconst updatedSpace = await client.space.updateSpace({\n  spaceKey: 'DEMO',\n  name: 'Demo Space - Updated',\n  description: {\n    plain: {\n      value: 'Updated description',\n      representation: 'plain',\n    },\n  },\n});\n```\n\n### Delete a Space\n\n```ts\nconst task = await client.space.deleteSpace({ spaceKey: 'OLDSPACE' });\nconsole.log('Space deletion initiated');\n```\n\n### Get Space Content\n\n```ts\nconst content = await client.space.getSpaceContent({\n  spaceKey: 'DEMO',\n  expand: ['body.storage'],\n  limit: 50,\n});\n\nfor (const item of content.page?.results || []) {\n  console.log(`Page: ${item.title} (${item.id})`);\n}\n```\n\n## Search API\n\n### Search Content (CQL)\n\nUse Confluence Query Language (CQL) for powerful searches:\n\n```ts\nconst results = await client.search.search({\n  cql: 'type=page AND space=DEMO AND title~\"getting started\"',\n  limit: 20,\n  expand: ['content.space', 'content.version'],\n});\n\nfor (const result of results.results || []) {\n  console.log(`${result.content?.title} - ${result.content?.id}`);\n}\n```\n\n### Common CQL Patterns\n\n```ts\n// Find pages in a space\nconst pagesInSpace = await client.search.search({\n  cql: 'type=page AND space=DEMO',\n});\n\n// Find pages by creator\nconst myPages = await client.search.search({\n  cql: 'type=page AND creator=currentUser()',\n});\n\n// Find recently modified content\nconst recent = await client.search.search({\n  cql: 'type=page AND lastModified > now(\"-7d\") ORDER BY lastModified DESC',\n  limit: 10,\n});\n\n// Find pages with specific label\nconst tagged = await client.search.search({\n  cql: 'type=page AND label=\"documentation\"',\n});\n\n// Complex search with AND/OR\nconst complex = await client.search.search({\n  cql: 'type=page AND space IN (DEMO, PROJ) AND (title~\"guide\" OR text~\"tutorial\")',\n});\n```\n\n### Search by Title\n\n```ts\nconst results = await client.search.searchContent({\n  title: 'Installation',\n  limit: 10,\n});\n```\n\n## Attachments API\n\n### Get Attachments for Page\n\n```ts\nconst attachments = await client.content.getAttachments({\n  id: '123456789',\n  limit: 50,\n});\n\nfor (const attachment of attachments.results || []) {\n  console.log(`${attachment.title} - ${attachment.extensions?.fileSize} bytes`);\n  console.log(`Download: ${attachment._links?.download}`);\n}\n```\n\n### Upload an Attachment\n\n```ts\nimport fs from 'fs';\nimport FormData from 'form-data';\n\nconst form = new FormData();\nform.append('file', fs.createReadStream('/path/to/file.pdf'), 'file.pdf');\nform.append('comment', 'Uploaded via API');\n\nconst attachment = await client.content.createAttachment({\n  id: '123456789',\n  formData: form,\n});\n\nconsole.log(`Uploaded: ${attachment.results?.[0]?.title}`);\n```\n\n### Update an Existing Attachment\n\n```ts\nconst form = new FormData();\nform.append('file', fs.createReadStream('/path/to/updated-file.pdf'), 'file.pdf');\nform.append('comment', 'Updated version');\n\nconst updated = await client.content.updateAttachment({\n  id: '123456789',\n  attachmentId: '987654321',\n  formData: form,\n});\n```\n\n### Download an Attachment\n\n```ts\n// Get attachment metadata first\nconst attachments = await client.content.getAttachments({\n  id: '123456789',\n});\n\nconst attachment = attachments.results?.[0];\nif (attachment) {\n  const downloadUrl = `https://your-domain.atlassian.net${attachment._links?.download}`;\n  // Use fetch or axios to download\n  console.log(`Download from: ${downloadUrl}`);\n}\n```\n\n## Labels API\n\n### Get Labels for Content\n\n```ts\nconst labels = await client.content.getLabels({ id: '123456789' });\n\nfor (const label of labels.results || []) {\n  console.log(`Label: ${label.name}`);\n}\n```\n\n### Add Labels to Content\n\n```ts\nconst newLabels = await client.content.addLabels({\n  id: '123456789',\n  labels: [\n    { name: 'documentation' },\n    { name: 'getting-started' },\n    { name: 'tutorial' },\n  ],\n});\n```\n\n### Remove a Label\n\n```ts\nawait client.content.removeLabel({\n  id: '123456789',\n  label: 'old-label',\n});\n```\n\n## Comments API\n\n### Get Comments for Page\n\n```ts\nconst comments = await client.content.getContentComments({\n  id: '123456789',\n  expand: ['body.storage'],\n  limit: 50,\n});\n\nfor (const comment of comments.results || []) {\n  console.log(`Comment by ${comment.history?.createdBy?.displayName}:`);\n  console.log(comment.body?.storage?.value);\n}\n```\n\n### Add a Comment\n\n```ts\nconst comment = await client.content.createContent({\n  type: 'comment',\n  container: { id: '123456789', type: 'page' },\n  body: {\n    storage: {\n      value: '<p>This is a helpful comment!</p>',\n      representation: 'storage',\n    },\n  },\n});\n```\n\n## User and Group APIs\n\n### Get Current User\n\n```ts\nconst user = await client.user.getCurrentUser();\nconsole.log(`Logged in as: ${user.displayName} (${user.email})`);\n```\n\n### Get User by Account ID\n\n```ts\nconst user = await client.user.getUser({\n  accountId: '5a1234567890123456789012',\n});\nconsole.log(user.displayName);\n```\n\n### Get Group Members\n\n```ts\nconst members = await client.group.getMembers({\n  name: 'confluence-administrators',\n  limit: 50,\n});\n\nfor (const member of members.results || []) {\n  console.log(member.displayName);\n}\n```\n\n## Content Properties (Metadata)\n\n### Get Content Property\n\n```ts\nconst property = await client.content.getContentProperty({\n  id: '123456789',\n  key: 'custom-metadata',\n});\n\nconsole.log(property.value);\n```\n\n### Set Content Property\n\n```ts\nawait client.content.createContentProperty({\n  id: '123456789',\n  key: 'custom-metadata',\n  value: {\n    lastReviewed: '2025-11-07',\n    reviewer: 'john.doe@example.com',\n    status: 'approved',\n  },\n});\n```\n\n### Update Content Property\n\n```ts\nconst current = await client.content.getContentProperty({\n  id: '123456789',\n  key: 'custom-metadata',\n});\n\nawait client.content.updateContentProperty({\n  id: '123456789',\n  key: 'custom-metadata',\n  version: {\n    number: current.version!.number! + 1,\n  },\n  value: {\n    ...current.value,\n    status: 'needs-review',\n  },\n});\n```\n\n### Delete Content Property\n\n```ts\nawait client.content.deleteContentProperty({\n  id: '123456789',\n  key: 'custom-metadata',\n});\n```\n\n## Advanced Content Operations\n\n### Get Content Descendants\n\n```ts\nconst descendants = await client.content.getContentDescendants({\n  id: '123456789',\n  expand: ['page'],\n});\n\nconsole.log('All descendant pages:');\nfor (const page of descendants.page?.results || []) {\n  console.log(`  ${page.title} (${page.id})`);\n}\n```\n\n### Copy a Page\n\n```ts\nconst original = await client.content.getContent({\n  id: '123456789',\n  expand: ['body.storage', 'space'],\n});\n\nconst copy = await client.content.createContent({\n  type: 'page',\n  title: `${original.title} (Copy)`,\n  space: { key: original.space?.key },\n  body: original.body,\n});\n```\n\n### Move a Page to Different Parent\n\n```ts\nconst page = await client.content.getContent({\n  id: '123456789',\n  expand: ['version', 'space', 'ancestors'],\n});\n\nawait client.content.updateContent({\n  id: '123456789',\n  type: 'page',\n  title: page.title,\n  space: { key: page.space?.key },\n  version: {\n    number: page.version!.number! + 1,\n  },\n  ancestors: [{ id: 'new-parent-id' }],\n  body: page.body,\n});\n```\n\n### Archive a Page\n\n```ts\nawait client.content.archivePage({ id: '123456789' });\nconsole.log('Page archived');\n```\n\n### Restore from Trash\n\n```ts\nconst restored = await client.content.restore({\n  id: '123456789',\n});\nconsole.log('Page restored');\n```\n\n## Content Restrictions (Permissions)\n\n### Get Content Restrictions\n\n```ts\nconst restrictions = await client.content.getContentRestrictions({\n  id: '123456789',\n  expand: ['read.restrictions.user', 'update.restrictions.user'],\n});\n\nconsole.log('Read restrictions:', restrictions.read);\nconsole.log('Update restrictions:', restrictions.update);\n```\n\n### Add Read Restriction\n\n```ts\nawait client.content.addContentRestriction({\n  id: '123456789',\n  operation: 'read',\n  restrictions: {\n    user: [\n      { accountId: '5a1234567890123456789012' },\n    ],\n    group: [\n      { name: 'confluence-users' },\n    ],\n  },\n});\n```\n\n### Remove All Restrictions\n\n```ts\nawait client.content.deleteContentRestriction({\n  id: '123456789',\n  operation: 'read',\n});\n\nawait client.content.deleteContentRestriction({\n  id: '123456789',\n  operation: 'update',\n});\n```\n\n## Macros in Content\n\n### Insert a Table of Contents Macro\n\n```ts\nconst page = await client.content.createContent({\n  type: 'page',\n  title: 'Documentation Index',\n  space: { key: 'DEMO' },\n  body: {\n    storage: {\n      value: `\n        <h1>Table of Contents</h1>\n        <ac:structured-macro ac:name=\"toc\" ac:schema-version=\"1\">\n          <ac:parameter ac:name=\"maxLevel\">3</ac:parameter>\n        </ac:structured-macro>\n        <h2>Section 1</h2>\n        <p>Content here...</p>\n      `,\n      representation: 'storage',\n    },\n  },\n});\n```\n\n### Insert a Status Macro\n\n```ts\nconst content = `\n  <p>Project status:\n    <ac:structured-macro ac:name=\"status\" ac:schema-version=\"1\">\n      <ac:parameter ac:name=\"colour\">Green</ac:parameter>\n      <ac:parameter ac:name=\"title\">Active</ac:parameter>\n    </ac:structured-macro>\n  </p>\n`;\n```\n\n### Insert a Code Block Macro\n\n```ts\nconst content = `\n  <ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\">\n    <ac:parameter ac:name=\"language\">javascript</ac:parameter>\n    <ac:plain-text-body><![CDATA[\nconst greeting = 'Hello, World!';\nconsole.log(greeting);\n    ]]></ac:plain-text-body>\n  </ac:structured-macro>\n`;\n```\n\n### Insert an Info Panel Macro\n\n```ts\nconst content = `\n  <ac:structured-macro ac:name=\"info\" ac:schema-version=\"1\">\n    <ac:rich-text-body>\n      <p>This is important information for users to know.</p>\n    </ac:rich-text-body>\n  </ac:structured-macro>\n`;\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```ts\ntry {\n  const page = await client.content.getContent({ id: 'invalid-id' });\n} catch (error) {\n  if (error.response) {\n    console.error('Status:', error.response.status);\n    console.error('Message:', error.response.data?.message);\n  } else {\n    console.error('Error:', error.message);\n  }\n}\n```\n\n### Common HTTP Status Codes\n\n- `400 Bad Request`: Invalid parameters or request body\n- `401 Unauthorized`: Invalid or missing authentication\n- `403 Forbidden`: Insufficient permissions\n- `404 Not Found`: Content or space does not exist\n- `409 Conflict`: Version conflict (update with wrong version number)\n- `429 Too Many Requests`: Rate limit exceeded\n\n### Handling Version Conflicts\n\n```ts\nasync function updatePageWithRetry(pageId: string, newContent: string, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      const page = await client.content.getContent({\n        id: pageId,\n        expand: ['version', 'space'],\n      });\n\n      const updated = await client.content.updateContent({\n        id: pageId,\n        type: 'page',\n        title: page.title,\n        space: { key: page.space?.key },\n        version: {\n          number: page.version!.number! + 1,\n        },\n        body: {\n          storage: {\n            value: newContent,\n            representation: 'storage',\n          },\n        },\n      });\n\n      return updated;\n    } catch (error) {\n      if (error.response?.status === 409 && i < maxRetries - 1) {\n        console.log(`Conflict detected, retrying (${i + 1}/${maxRetries})...`);\n        await new Promise(resolve => setTimeout(resolve, 1000));\n        continue;\n      }\n      throw error;\n    }\n  }\n}\n```\n\n### Rate Limit Handling\n\n```ts\nasync function apiCallWithBackoff<T>(\n  apiCall: () => Promise<T>,\n  maxRetries = 5\n): Promise<T> {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await apiCall();\n    } catch (error) {\n      if (error.response?.status === 429 && i < maxRetries - 1) {\n        const retryAfter = error.response.headers['retry-after'] || Math.pow(2, i);\n        console.log(`Rate limited, waiting ${retryAfter}s before retry...`);\n        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n        continue;\n      }\n      throw error;\n    }\n  }\n  throw new Error('Max retries exceeded');\n}\n\n// Usage\nconst page = await apiCallWithBackoff(() =>\n  client.content.getContent({ id: '123456789' })\n);\n```\n\n## Bulk Operations\n\n### Get Multiple Pages by IDs\n\n```ts\nasync function getPagesByIds(pageIds: string[]) {\n  const pages = await Promise.all(\n    pageIds.map(id =>\n      client.content.getContent({\n        id,\n        expand: ['body.storage', 'version']\n      })\n    )\n  );\n  return pages;\n}\n```\n\n### Batch Create Pages\n\n```ts\nasync function createMultiplePages(\n  spaceKey: string,\n  pageData: Array<{ title: string; content: string }>\n) {\n  const created = [];\n\n  for (const { title, content } of pageData) {\n    const page = await client.content.createContent({\n      type: 'page',\n      title,\n      space: { key: spaceKey },\n      body: {\n        storage: {\n          value: content,\n          representation: 'storage',\n        },\n      },\n    });\n    created.push(page);\n\n    // Rate limit protection: wait between requests\n    await new Promise(resolve => setTimeout(resolve, 200));\n  }\n\n  return created;\n}\n```\n\n### Batch Update Pages\n\n```ts\nasync function updateMultiplePages(\n  updates: Array<{ id: string; title?: string; content: string }>\n) {\n  const results = [];\n\n  for (const { id, title, content } of updates) {\n    const current = await client.content.getContent({\n      id,\n      expand: ['version', 'space'],\n    });\n\n    const updated = await client.content.updateContent({\n      id,\n      type: 'page',\n      title: title || current.title,\n      space: { key: current.space?.key },\n      version: {\n        number: current.version!.number! + 1,\n      },\n      body: {\n        storage: {\n          value: content,\n          representation: 'storage',\n        },\n      },\n    });\n\n    results.push(updated);\n    await new Promise(resolve => setTimeout(resolve, 200));\n  }\n\n  return results;\n}\n```\n\n## Performance and Optimization\n\n### Use Expand Wisely\n\nOnly expand fields you need to reduce response size:\n\n```ts\n// Bad - expands everything\nconst page = await client.content.getContent({\n  id: '123456789',\n  expand: ['body.storage', 'body.view', 'body.editor', 'version', 'space', 'history', 'ancestors', 'descendants', 'container'],\n});\n\n// Good - only what you need\nconst page = await client.content.getContent({\n  id: '123456789',\n  expand: ['body.storage', 'version'],\n});\n```\n\n### Pagination Best Practices\n\n```ts\nasync function getAllPagesInSpace(spaceKey: string) {\n  const allPages = [];\n  let start = 0;\n  const limit = 100; // Max recommended: 100\n\n  while (true) {\n    const response = await client.content.getContent({\n      spaceKey,\n      type: 'page',\n      start,\n      limit,\n    });\n\n    if (!response.results || response.results.length === 0) {\n      break;\n    }\n\n    allPages.push(...response.results);\n\n    if (response.results.length < limit) {\n      break;\n    }\n\n    start += limit;\n  }\n\n  return allPages;\n}\n```\n\n### Caching Strategies\n\n```ts\nclass ConfluenceCache {\n  private cache = new Map<string, { data: any; expires: number }>();\n\n  constructor(private client: ConfluenceClient, private ttlMs = 60000) {}\n\n  async getPage(id: string) {\n    const cached = this.cache.get(id);\n\n    if (cached && Date.now() < cached.expires) {\n      return cached.data;\n    }\n\n    const page = await this.client.content.getContent({ id });\n\n    this.cache.set(id, {\n      data: page,\n      expires: Date.now() + this.ttlMs,\n    });\n\n    return page;\n  }\n\n  invalidate(id: string) {\n    this.cache.delete(id);\n  }\n}\n```\n\n## TypeScript Support\n\n### Typed Responses\n\n```ts\nimport { Content, Space, User } from 'confluence.js/out/api/models';\n\nconst page: Content = await client.content.getContent({ id: '123456789' });\nconst space: Space = await client.space.getSpace({ spaceKey: 'DEMO' });\nconst user: User = await client.user.getCurrentUser();\n```\n\n### Type-Safe Page Creation\n\n```ts\nimport { ContentCreate } from 'confluence.js/out/api/models';\n\nconst pageData: ContentCreate = {\n  type: 'page',\n  title: 'Type-Safe Page',\n  space: { key: 'DEMO' },\n  body: {\n    storage: {\n      value: '<p>Content</p>',\n      representation: 'storage',\n    },\n  },\n};\n\nconst created = await client.content.createContent(pageData);\n```\n\n## Common Patterns\n\n### Create or Update Page\n\n```ts\nasync function createOrUpdatePage(\n  spaceKey: string,\n  title: string,\n  content: string\n) {\n  // Try to find existing page\n  const searchResult = await client.content.getContent({\n    spaceKey,\n    title,\n    expand: ['version', 'space'],\n  });\n\n  if (searchResult.results && searchResult.results.length > 0) {\n    // Update existing\n    const existing = searchResult.results[0];\n    return await client.content.updateContent({\n      id: existing.id!,\n      type: 'page',\n      title,\n      space: { key: spaceKey },\n      version: {\n        number: existing.version!.number! + 1,\n      },\n      body: {\n        storage: {\n          value: content,\n          representation: 'storage',\n        },\n      },\n    });\n  } else {\n    // Create new\n    return await client.content.createContent({\n      type: 'page',\n      title,\n      space: { key: spaceKey },\n      body: {\n        storage: {\n          value: content,\n          representation: 'storage',\n        },\n      },\n    });\n  }\n}\n```\n\n### Build Table of Contents\n\n```ts\nasync function buildTableOfContents(spaceKey: string) {\n  const pages = await client.content.getContent({\n    spaceKey,\n    type: 'page',\n    limit: 100,\n  });\n\n  let tocHtml = '<h2>Table of Contents</h2><ul>';\n\n  for (const page of pages.results || []) {\n    tocHtml += `<li><ac:link><ri:page ri:content-title=\"${page.title}\"/></ac:link></li>`;\n  }\n\n  tocHtml += '</ul>';\n\n  return tocHtml;\n}\n```\n\n### Export Page to Different Format\n\n```ts\nasync function exportPageAsPDF(pageId: string) {\n  const page = await client.content.getContent({\n    id: pageId,\n    expand: ['body.export_view'],\n  });\n\n  // Export view provides HTML optimized for export\n  return page.body?.export_view?.value;\n}\n```\n\n## Content Body Formats\n\nConfluence supports multiple body representations:\n\n- `storage`: XHTML format used for storage (required for create/update)\n- `view`: HTML for rendering in browser\n- `export_view`: HTML optimized for export\n- `editor`: Format used in the editor\n- `anonymous_export_view`: HTML for anonymous viewing\n\n```ts\nconst page = await client.content.getContent({\n  id: '123456789',\n  expand: ['body.storage', 'body.view', 'body.export_view'],\n});\n\nconsole.log('Storage format:', page.body?.storage?.value);\nconsole.log('View format:', page.body?.view?.value);\nconsole.log('Export format:', page.body?.export_view?.value);\n```\n\n## Common Mistakes to Avoid\n\n- **Not incrementing version number** when updating content (causes 409 conflict)\n- **Forgetting to expand fields** needed in response (results in undefined properties)\n- **Using wrong representation** for body content (use 'storage' for create/update)\n- **Not handling pagination** when fetching multiple items (misses items beyond first page)\n- **Hardcoding credentials** instead of using environment variables (security risk)\n- **Not handling rate limits** in bulk operations (causes 429 errors)\n- **Creating pages without checking if they exist** (creates duplicates)\n- **Not URL-encoding** special characters in space keys or titles\n- **Assuming synchronous operations** (all API calls are async and return promises)\n- **Not catching errors** properly (unhandled rejections crash Node.js apps)\n- **Using outdated packages** like confluence-api instead of confluence.js\n- **Forgetting authentication object** in ConfluenceClient initialization\n- **Not escaping HTML** in content values (causes malformed XML in storage format)\n\n## Reference Links\n\n- **confluence.js Documentation**: https://mrrefactoring.github.io/confluence.js/\n- **Confluence Cloud REST API v2**: https://developer.atlassian.com/cloud/confluence/rest/v2/\n- **Confluence Cloud REST API v1**: https://developer.atlassian.com/cloud/confluence/rest/v1/\n- **CQL (Confluence Query Language)**: https://developer.atlassian.com/cloud/confluence/advanced-searching-using-cql/\n- **Storage Format Guide**: https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html\n- **Atlassian API Tokens**: https://id.atlassian.com/manage-profile/security/api-tokens\n- **Rate Limits**: https://developer.atlassian.com/cloud/confluence/rate-limiting/\n- **OAuth 2.0 (3LO)**: https://developer.atlassian.com/cloud/confluence/oauth-2-3lo-apps/\n- **Atlassian Connect (JWT)**: https://developer.atlassian.com/cloud/confluence/authentication-for-apps/\n"
  },
  {
    "path": "content/atlassian/docs/confluence/python/DOC.md",
    "content": "---\nname: confluence\ndescription: \"Confluence Cloud API coding guidelines for Python using the atlassian-python-api library\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.7\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"atlassian,confluence,wiki,documentation,collaboration\"\n---\n\n# Confluence Cloud API Coding Guidelines (Python)\n\nYou are a **Confluence Cloud API coding expert**. Help me write correct, idiomatic Python code that calls the Atlassian Confluence Cloud REST API using the atlassian-python-api library.\n\nUse **only official Atlassian sources** for API behavior, fields, and constraints. This guide summarizes key patterns for Python applications.\n\n> Ground truth: Atlassian Confluence Cloud REST API documentation at developer.atlassian.com/cloud/confluence/\n\n## Golden Rule: Use atlassian-python-api Library\n\n**CRITICAL:** Use the `atlassian-python-api` package (version 4.0.7 or later) for interacting with Confluence Cloud REST API. This is the most comprehensive and actively maintained community library for Atlassian products.\n\n**DO NOT use:**\n- `pyatlassian` (different package, less maintained)\n- `confluence-api` (JavaScript package, not Python)\n- Direct REST API calls with `requests` without a client library (error-prone)\n\n**Install:**\n```bash\npip install atlassian-python-api\n# or\npoetry add atlassian-python-api\n# or\nuv pip install atlassian-python-api\n```\n\nThe library supports Python 3.8+ and provides comprehensive coverage of Confluence Cloud and Server APIs.\n\n## Authentication\n\nConfluence Cloud requires API token authentication. Username/password authentication is deprecated.\n\n### API Token Authentication - Required for Cloud\n\nGenerate an API token from your Atlassian Account Settings (https://id.atlassian.com/manage-profile/security/api-tokens).\n\n```python\nfrom atlassian import Confluence\n\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    username='your-email@example.com',\n    password='your-api-token',  # This is your API token, not your password\n    cloud=True\n)\n```\n\n**IMPORTANT:** For Confluence Cloud, you must:\n1. Use your email address as the username\n2. Use an API token (not your account password) as the password\n3. Set `cloud=True`\n\n### Environment Variables Setup\n\n```bash\n# .env file\nCONFLUENCE_URL=https://your-domain.atlassian.net\nCONFLUENCE_USERNAME=your-email@example.com\nCONFLUENCE_API_TOKEN=your_api_token_here\n```\n\n**Loading in Python:**\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom atlassian import Confluence\n\nload_dotenv()\n\nconfluence = Confluence(\n    url=os.getenv('CONFLUENCE_URL'),\n    username=os.getenv('CONFLUENCE_USERNAME'),\n    password=os.getenv('CONFLUENCE_API_TOKEN'),\n    cloud=True\n)\n```\n\n### OAuth 2.0 Authentication\n\nFor apps using OAuth 2.0 access tokens:\n\n```python\nfrom atlassian import Confluence\n\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    token='your-oauth-access-token',\n    cloud=True\n)\n```\n\n### Server/Data Center Authentication (On-Premise)\n\nFor self-hosted Confluence instances:\n\n```python\nfrom atlassian import Confluence\n\nconfluence = Confluence(\n    url='https://confluence.company.com',\n    username='your-username',\n    password='your-password',\n    cloud=False  # Important for Server/Data Center\n)\n```\n\n## Initialization Patterns\n\n### Basic Initialization\n\n```python\nfrom atlassian import Confluence\n\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    username='your-email@example.com',\n    password='your-api-token',\n    cloud=True\n)\n```\n\n### With Timeout Configuration\n\n```python\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    username='your-email@example.com',\n    password='your-api-token',\n    cloud=True,\n    timeout=60  # Seconds\n)\n```\n\n### With Proxy Support\n\n```python\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    username='your-email@example.com',\n    password='your-api-token',\n    cloud=True,\n    proxies={\n        'http': 'http://proxy.company.com:8080',\n        'https': 'https://proxy.company.com:8080',\n    }\n)\n```\n\n### Verify SSL Certificates\n\n```python\n# Disable SSL verification (not recommended for production)\nconfluence = Confluence(\n    url='https://your-domain.atlassian.net',\n    username='your-email@example.com',\n    password='your-api-token',\n    cloud=True,\n    verify_ssl=False\n)\n```\n\n## Pages API\n\n### Get Page by ID\n\n```python\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.storage,version,space'\n)\n\nprint(f\"Title: {page['title']}\")\nprint(f\"Space: {page['space']['key']}\")\nprint(f\"Version: {page['version']['number']}\")\nprint(f\"Content: {page['body']['storage']['value']}\")\n```\n\n### Get Page by Title\n\n```python\npage = confluence.get_page_by_title(\n    space='DEMO',\n    title='Getting Started'\n)\n\nif page:\n    print(f\"Page ID: {page['id']}\")\n    print(f\"Title: {page['title']}\")\nelse:\n    print(\"Page not found\")\n```\n\n### Get Page ID Only\n\n```python\npage_id = confluence.get_page_id(\n    space='DEMO',\n    title='Getting Started'\n)\n\nif page_id:\n    print(f\"Found page: {page_id}\")\n```\n\n### Get All Pages from Space\n\n```python\npages = confluence.get_all_pages_from_space(\n    space='DEMO',\n    start=0,\n    limit=100,\n    status='current',\n    expand='version,space'\n)\n\nfor page in pages:\n    print(f\"{page['title']} - {page['id']}\")\n```\n\n### Get All Pages as Generator (Memory Efficient)\n\n```python\nfor page in confluence.get_all_pages_from_space_as_generator(\n    space='DEMO',\n    expand='body.storage,version'\n):\n    print(f\"Processing: {page['title']}\")\n    # Process each page without loading all into memory\n```\n\n### Create a Page\n\n```python\npage = confluence.create_page(\n    space='DEMO',\n    title='Getting Started Guide',\n    body='<h1>Welcome</h1><p>This is the introduction to our project.</p>',\n    parent_id=None,  # Optional: specify parent page ID\n    type='page',\n    representation='storage'\n)\n\nprint(f\"Created page ID: {page['id']}\")\nprint(f\"URL: {page['_links']['webui']}\")\n```\n\n### Create a Child Page\n\n```python\nparent_id = confluence.get_page_id(space='DEMO', title='Parent Page')\n\nchild_page = confluence.create_page(\n    space='DEMO',\n    title='Child Page',\n    body='<p>This is a child page.</p>',\n    parent_id=parent_id\n)\n\nprint(f\"Created child page: {child_page['id']}\")\n```\n\n### Update a Page\n\n**IMPORTANT:** Always increment the version number when updating.\n\n```python\n# Get current page to retrieve version\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='version,space'\n)\n\n# Update with incremented version\nupdated = confluence.update_page(\n    page_id='123456789',\n    title='Updated Title',\n    body='<h1>Updated Content</h1><p>New information here.</p>',\n    version_number=page['version']['number'] + 1,\n    representation='storage'\n)\n\nprint(f\"Updated to version {updated['version']['number']}\")\n```\n\n### Update Page Content Only (Keep Title)\n\n```python\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='version,body.storage'\n)\n\nconfluence.update_page(\n    page_id='123456789',\n    title=page['title'],  # Keep existing title\n    body='<p>Only the content changed.</p>',\n    version_number=page['version']['number'] + 1\n)\n```\n\n### Append to Page Content\n\n```python\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='version,body.storage'\n)\n\ncurrent_content = page['body']['storage']['value']\nnew_content = current_content + '<p>Additional content appended.</p>'\n\nconfluence.update_page(\n    page_id='123456789',\n    title=page['title'],\n    body=new_content,\n    version_number=page['version']['number'] + 1\n)\n```\n\n### Delete a Page\n\n```python\nconfluence.remove_page(\n    page_id='123456789',\n    status=None  # Use 'trashed' for soft delete\n)\n\nprint(\"Page deleted successfully\")\n```\n\n### Move Page to Trash (Soft Delete)\n\n```python\nconfluence.set_page_property(\n    page_id='123456789',\n    data={'status': 'trashed'}\n)\n```\n\n### Get Page Children\n\n```python\nchildren = confluence.get_page_child_by_type(\n    page_id='123456789',\n    type='page',\n    start=0,\n    limit=50\n)\n\nfor child in children:\n    print(f\"Child: {child['title']} ({child['id']})\")\n```\n\n### Get Page Descendants\n\n```python\ndescendants = confluence.get_page_descendants(\n    page_id='123456789',\n    type='page'\n)\n\nfor page in descendants:\n    print(f\"Descendant: {page['title']}\")\n```\n\n### Get Page Ancestors\n\n```python\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='ancestors'\n)\n\nfor ancestor in page.get('ancestors', []):\n    print(f\"Ancestor: {ancestor['title']} ({ancestor['id']})\")\n```\n\n### Get Page History\n\n```python\nhistory = confluence.history(page_id='123456789')\n\nprint(f\"Created by: {history['createdBy']['displayName']}\")\nprint(f\"Created date: {history['createdDate']}\")\nprint(f\"Latest version: {history['latest']['number']}\")\n```\n\n### Get Page Version Information\n\n```python\nversion = confluence.get_page_version(\n    page_id='123456789',\n    version_number=None  # None for latest, or specify version number\n)\n\nprint(f\"Version: {version['number']}\")\nprint(f\"Modified by: {version['by']['displayName']}\")\nprint(f\"Modified when: {version['when']}\")\n```\n\n## Spaces API\n\n### Get Space\n\n```python\nspace = confluence.get_space(\n    space_key='DEMO',\n    expand='description.plain,homepage'\n)\n\nprint(f\"Name: {space['name']}\")\nprint(f\"Key: {space['key']}\")\nprint(f\"Type: {space['type']}\")\nif 'description' in space:\n    print(f\"Description: {space['description']['plain']['value']}\")\n```\n\n### Get All Spaces\n\n```python\nspaces = confluence.get_all_spaces(\n    start=0,\n    limit=100,\n    expand='description.plain'\n)\n\nfor space in spaces['results']:\n    print(f\"{space['key']}: {space['name']}\")\n```\n\n### Get All Spaces as Generator\n\n```python\nfor space in confluence.get_all_spaces_as_generator():\n    print(f\"Space: {space['key']} - {space['name']}\")\n```\n\n### Create a Space\n\n```python\nspace = confluence.create_space(\n    space_key='PROJ',\n    space_name='Project Galaxy',\n    description='Documentation for Project Galaxy'\n)\n\nprint(f\"Created space: {space['key']}\")\nprint(f\"URL: {space['_links']['webui']}\")\n```\n\n### Update Space\n\n```python\nconfluence.update_space(\n    space_key='DEMO',\n    name='Demo Space - Updated',\n    description='Updated description'\n)\n```\n\n### Delete Space\n\n```python\nconfluence.delete_space(space_key='OLDSPACE')\nprint(\"Space deleted successfully\")\n```\n\n### Get Space Content\n\n```python\ncontent = confluence.get_space_content(\n    space_key='DEMO',\n    depth='all',\n    start=0,\n    limit=100\n)\n\nfor item in content.get('page', {}).get('results', []):\n    print(f\"Page: {item['title']} ({item['id']})\")\n```\n\n### Get Space Homepage\n\n```python\nspace = confluence.get_space(\n    space_key='DEMO',\n    expand='homepage'\n)\n\nif 'homepage' in space:\n    homepage = space['homepage']\n    print(f\"Homepage: {homepage['title']} ({homepage['id']})\")\n```\n\n## Search API\n\n### CQL Search (Confluence Query Language)\n\n```python\nresults = confluence.cql(\n    cql='type=page AND space=DEMO AND title~\"getting started\"',\n    start=0,\n    limit=20,\n    expand='content.space,content.version'\n)\n\nfor result in results.get('results', []):\n    content = result.get('content', {})\n    print(f\"{content.get('title')} - {content.get('id')}\")\n```\n\n### Common CQL Query Patterns\n\n```python\n# Find all pages in a space\nresults = confluence.cql('type=page AND space=DEMO')\n\n# Find pages by creator\nresults = confluence.cql('type=page AND creator=currentUser()')\n\n# Find recently modified content\nresults = confluence.cql(\n    'type=page AND lastModified > now(\"-7d\") ORDER BY lastModified DESC',\n    limit=10\n)\n\n# Find pages with specific label\nresults = confluence.cql('type=page AND label=\"documentation\"')\n\n# Complex search with AND/OR\nresults = confluence.cql(\n    'type=page AND space IN (DEMO, PROJ) AND (title~\"guide\" OR text~\"tutorial\")'\n)\n\n# Find pages modified by specific user\nresults = confluence.cql('type=page AND contributor=\"john.doe@example.com\"')\n\n# Find pages created this month\nresults = confluence.cql('type=page AND created >= startOfMonth()')\n```\n\n### Search Content by Title\n\n```python\n# Using get_page_by_title for exact match\npage = confluence.get_page_by_title(\n    space='DEMO',\n    title='Installation'\n)\n\n# Using CQL for partial match\nresults = confluence.cql('type=page AND title~\"installation\"')\n```\n\n### Full-Text Search\n\n```python\nresults = confluence.cql(\n    'type=page AND text~\"kubernetes deployment\"',\n    limit=50\n)\n\nfor result in results.get('results', []):\n    content = result.get('content', {})\n    print(f\"Found: {content.get('title')}\")\n```\n\n## Attachments API\n\n### Get Attachments for Page\n\n```python\nattachments = confluence.get_attachments_from_content(\n    page_id='123456789',\n    start=0,\n    limit=50,\n    filename=None,  # Optional: filter by filename\n    media_type=None  # Optional: filter by media type\n)\n\nfor attachment in attachments.get('results', []):\n    print(f\"{attachment['title']} - {attachment['extensions']['fileSize']} bytes\")\n    print(f\"Download: {attachment['_links']['download']}\")\n```\n\n### Attach File to Page\n\n```python\n# Upload a file\nresult = confluence.attach_file(\n    filename='/path/to/document.pdf',\n    page_id='123456789',\n    title='Document',  # Optional: display name\n    comment='Uploaded via API'\n)\n\nprint(f\"Uploaded: {result['title']}\")\n```\n\n### Attach File from Content\n\n```python\n# Upload file from bytes or file object\nwith open('/path/to/image.png', 'rb') as f:\n    result = confluence.attach_content(\n        content=f.read(),\n        name='screenshot.png',\n        content_type='image/png',\n        page_id='123456789',\n        comment='Screenshot of the dashboard'\n    )\n```\n\n### Update Existing Attachment\n\n```python\n# Re-upload with same filename updates the attachment\nresult = confluence.attach_file(\n    filename='/path/to/updated-document.pdf',\n    page_id='123456789',\n    title='Document',\n    comment='Updated version'\n)\n```\n\n### Download Attachment\n\n```python\n# Get attachment info first\nattachments = confluence.get_attachments_from_content(page_id='123456789')\n\nfor attachment in attachments.get('results', []):\n    if attachment['title'] == 'document.pdf':\n        download_link = attachment['_links']['download']\n\n        # Download the file\n        import requests\n        response = requests.get(\n            f\"{confluence.url}{download_link}\",\n            auth=(confluence.username, confluence.password)\n        )\n\n        with open('downloaded-document.pdf', 'wb') as f:\n            f.write(response.content)\n\n        break\n```\n\n### Delete Attachment\n\n```python\nconfluence.delete_attachment(\n    page_id='123456789',\n    filename='old-document.pdf'\n)\n```\n\n## Labels API\n\n### Get Labels for Content\n\n```python\nlabels = confluence.get_page_labels(page_id='123456789')\n\nfor label in labels.get('results', []):\n    print(f\"Label: {label['name']}\")\n```\n\n### Add Label to Content\n\n```python\nconfluence.add_label(\n    page_id='123456789',\n    label='documentation'\n)\n\nprint(\"Label added successfully\")\n```\n\n### Add Multiple Labels\n\n```python\nlabels = ['documentation', 'getting-started', 'tutorial']\n\nfor label in labels:\n    confluence.add_label(\n        page_id='123456789',\n        label=label\n    )\n```\n\n### Remove Label from Content\n\n```python\nconfluence.remove_label(\n    page_id='123456789',\n    label='old-label'\n)\n```\n\n### Search Pages by Label\n\n```python\nresults = confluence.cql('type=page AND label=\"documentation\"')\n\nfor result in results.get('results', []):\n    content = result.get('content', {})\n    print(f\"{content.get('title')} - {content.get('id')}\")\n```\n\n## Comments API\n\n### Get Comments for Page\n\n```python\ncomments = confluence.get_page_comments(\n    page_id='123456789',\n    expand='body.storage',\n    depth='all'\n)\n\nfor comment in comments:\n    print(f\"Comment: {comment['title']}\")\n    print(f\"Content: {comment['body']['storage']['value']}\")\n```\n\n### Add Comment to Page\n\n```python\ncomment = confluence.create_page(\n    space='DEMO',\n    title='Re: Page Title',  # Comment title\n    body='<p>This is a helpful comment!</p>',\n    parent_id='123456789',\n    type='comment'\n)\n\nprint(f\"Comment added: {comment['id']}\")\n```\n\n## User and Group APIs\n\n### Get Current User\n\n```python\nuser = confluence.get_current_user()\n\nprint(f\"Display Name: {user['displayName']}\")\nprint(f\"Email: {user['email']}\")\nprint(f\"Account ID: {user['accountId']}\")\n```\n\n### Get User by Username (Server/Data Center)\n\n```python\nuser = confluence.get_user_details_by_username(\n    username='john.doe'\n)\n```\n\n### Get User by Account ID (Cloud)\n\n```python\nuser = confluence.get_user_details_by_accountid(\n    account_id='5a1234567890123456789012'\n)\n\nprint(f\"Display Name: {user['displayName']}\")\n```\n\n### Get Group Members\n\n```python\nmembers = confluence.get_group_members(\n    group_name='confluence-administrators',\n    start=0,\n    limit=50\n)\n\nfor member in members:\n    print(f\"Member: {member['displayName']}\")\n```\n\n### Check if User is in Group\n\n```python\n# Get all group members and check\nmembers = confluence.get_group_members('confluence-users')\nuser_ids = [m['accountId'] for m in members]\n\nis_member = 'user-account-id' in user_ids\nprint(f\"User is member: {is_member}\")\n```\n\n## Content Properties (Metadata)\n\n### Get Content Properties\n\n```python\nproperties = confluence.get_page_properties(page_id='123456789')\n\nfor prop in properties:\n    print(f\"Key: {prop['key']}\")\n    print(f\"Value: {prop['value']}\")\n```\n\n### Get Specific Content Property\n\n```python\nproperty_value = confluence.get_page_property(\n    page_id='123456789',\n    page_property_key='custom-metadata'\n)\n\nprint(f\"Property value: {property_value}\")\n```\n\n### Set Content Property\n\n```python\nconfluence.set_page_property(\n    page_id='123456789',\n    data={\n        'key': 'custom-metadata',\n        'value': {\n            'lastReviewed': '2025-11-07',\n            'reviewer': 'john.doe@example.com',\n            'status': 'approved'\n        }\n    }\n)\n```\n\n### Update Content Property\n\n```python\n# Get current property\ncurrent = confluence.get_page_property(\n    page_id='123456789',\n    page_property_key='custom-metadata'\n)\n\n# Update with new data\ncurrent['value']['status'] = 'needs-review'\ncurrent['version']['number'] += 1\n\nconfluence.update_page_property(\n    page_id='123456789',\n    page_property_key='custom-metadata',\n    data=current\n)\n```\n\n### Delete Content Property\n\n```python\nconfluence.delete_page_property(\n    page_id='123456789',\n    page_property_key='custom-metadata'\n)\n```\n\n## Advanced Page Operations\n\n### Copy a Page\n\n```python\n# Get source page\nsource = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.storage,space'\n)\n\n# Create copy\ncopy = confluence.create_page(\n    space=source['space']['key'],\n    title=f\"{source['title']} (Copy)\",\n    body=source['body']['storage']['value'],\n    parent_id=None\n)\n\nprint(f\"Created copy: {copy['id']}\")\n```\n\n### Copy Page with Children\n\n```python\ndef copy_page_tree(confluence, source_page_id, target_space, parent_id=None):\n    \"\"\"Recursively copy a page and all its children.\"\"\"\n    # Get source page\n    source = confluence.get_page_by_id(\n        page_id=source_page_id,\n        expand='body.storage,space'\n    )\n\n    # Create copy\n    copy = confluence.create_page(\n        space=target_space,\n        title=source['title'],\n        body=source['body']['storage']['value'],\n        parent_id=parent_id\n    )\n\n    # Copy children\n    children = confluence.get_page_child_by_type(\n        page_id=source_page_id,\n        type='page'\n    )\n\n    for child in children:\n        copy_page_tree(confluence, child['id'], target_space, copy['id'])\n\n    return copy\n```\n\n### Move Page to Different Parent\n\n```python\n# Get current page\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='version,body.storage,space,ancestors'\n)\n\n# Update with new parent\nconfluence.update_page(\n    page_id='123456789',\n    title=page['title'],\n    body=page['body']['storage']['value'],\n    parent_id='new-parent-id',\n    version_number=page['version']['number'] + 1\n)\n```\n\n### Export Page as PDF\n\n```python\n# Get page content in export view\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.export_view'\n)\n\nexport_html = page['body']['export_view']['value']\n\n# Use a PDF library to convert HTML to PDF\n# Example with pdfkit (requires wkhtmltopdf)\nimport pdfkit\npdfkit.from_string(export_html, 'output.pdf')\n```\n\n## Content Restrictions (Permissions)\n\n### Get Content Restrictions\n\n```python\nrestrictions = confluence.get_content_restrictions(\n    content_id='123456789',\n    expand='read.restrictions.user,update.restrictions.user'\n)\n\nprint(\"Read restrictions:\", restrictions.get('read'))\nprint(\"Update restrictions:\", restrictions.get('update'))\n```\n\n### Add Read Restriction\n\n```python\nconfluence.add_content_restriction(\n    content_id='123456789',\n    operation='read',\n    restrictions={\n        'user': [\n            {'accountId': '5a1234567890123456789012'}\n        ],\n        'group': [\n            {'name': 'confluence-users'}\n        ]\n    }\n)\n```\n\n### Remove Content Restrictions\n\n```python\nconfluence.remove_content_restriction(\n    content_id='123456789',\n    operation='read'\n)\n```\n\n## Macros in Content\n\n### Table of Contents Macro\n\n```python\ncontent = '''\n<h1>Table of Contents</h1>\n<ac:structured-macro ac:name=\"toc\" ac:schema-version=\"1\">\n    <ac:parameter ac:name=\"maxLevel\">3</ac:parameter>\n</ac:structured-macro>\n<h2>Section 1</h2>\n<p>Content here...</p>\n'''\n\nconfluence.create_page(\n    space='DEMO',\n    title='Documentation Index',\n    body=content\n)\n```\n\n### Status Macro\n\n```python\ncontent = '''\n<p>Project status:\n    <ac:structured-macro ac:name=\"status\" ac:schema-version=\"1\">\n        <ac:parameter ac:name=\"colour\">Green</ac:parameter>\n        <ac:parameter ac:name=\"title\">Active</ac:parameter>\n    </ac:structured-macro>\n</p>\n'''\n```\n\n### Code Block Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\">\n    <ac:parameter ac:name=\"language\">python</ac:parameter>\n    <ac:plain-text-body><![CDATA[\ndef greet(name):\n    return f\"Hello, {name}!\"\n\nprint(greet(\"World\"))\n    ]]></ac:plain-text-body>\n</ac:structured-macro>\n'''\n```\n\n### Info Panel Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"info\" ac:schema-version=\"1\">\n    <ac:rich-text-body>\n        <p>This is important information for users to know.</p>\n    </ac:rich-text-body>\n</ac:structured-macro>\n'''\n```\n\n### Warning Panel Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"warning\" ac:schema-version=\"1\">\n    <ac:rich-text-body>\n        <p><strong>Warning:</strong> This action cannot be undone.</p>\n    </ac:rich-text-body>\n</ac:structured-macro>\n'''\n```\n\n### Note Panel Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"note\" ac:schema-version=\"1\">\n    <ac:rich-text-body>\n        <p>Remember to save your work frequently.</p>\n    </ac:rich-text-body>\n</ac:structured-macro>\n'''\n```\n\n### Excerpt Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"excerpt\" ac:schema-version=\"1\">\n    <ac:rich-text-body>\n        <p>This is an excerpt that can be included in other pages.</p>\n    </ac:rich-text-body>\n</ac:structured-macro>\n'''\n```\n\n### Include Page Macro\n\n```python\ncontent = '''\n<ac:structured-macro ac:name=\"include\" ac:schema-version=\"1\">\n    <ac:parameter ac:name=\"\"><ac:link>\n        <ri:page ri:content-title=\"Page to Include\"/>\n    </ac:link></ac:parameter>\n</ac:structured-macro>\n'''\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom atlassian import Confluence\nfrom requests.exceptions import HTTPError\n\ntry:\n    page = confluence.get_page_by_id(page_id='invalid-id')\nexcept HTTPError as e:\n    print(f\"HTTP Error: {e.response.status_code}\")\n    print(f\"Message: {e.response.text}\")\nexcept Exception as e:\n    print(f\"Error: {str(e)}\")\n```\n\n### Common HTTP Status Codes\n\n- `400 Bad Request`: Invalid parameters or request body\n- `401 Unauthorized`: Invalid or missing authentication\n- `403 Forbidden`: Insufficient permissions\n- `404 Not Found`: Content or space does not exist\n- `409 Conflict`: Version conflict (update with wrong version number)\n- `429 Too Many Requests`: Rate limit exceeded\n\n### Handling Version Conflicts\n\n```python\ndef update_page_with_retry(confluence, page_id, new_content, max_retries=3):\n    \"\"\"Update page with automatic retry on version conflicts.\"\"\"\n    import time\n\n    for attempt in range(max_retries):\n        try:\n            # Get current version\n            page = confluence.get_page_by_id(\n                page_id=page_id,\n                expand='version,body.storage'\n            )\n\n            # Update with incremented version\n            updated = confluence.update_page(\n                page_id=page_id,\n                title=page['title'],\n                body=new_content,\n                version_number=page['version']['number'] + 1\n            )\n\n            return updated\n\n        except HTTPError as e:\n            if e.response.status_code == 409 and attempt < max_retries - 1:\n                print(f\"Conflict detected, retrying ({attempt + 1}/{max_retries})...\")\n                time.sleep(1)\n                continue\n            raise\n\n    raise Exception(f\"Failed after {max_retries} retries\")\n```\n\n### Rate Limit Handling\n\n```python\nimport time\nfrom requests.exceptions import HTTPError\n\ndef api_call_with_backoff(api_call, *args, max_retries=5, **kwargs):\n    \"\"\"Execute API call with exponential backoff on rate limits.\"\"\"\n    for attempt in range(max_retries):\n        try:\n            return api_call(*args, **kwargs)\n        except HTTPError as e:\n            if e.response.status_code == 429 and attempt < max_retries - 1:\n                retry_after = int(e.response.headers.get('Retry-After', 2 ** attempt))\n                print(f\"Rate limited, waiting {retry_after}s before retry...\")\n                time.sleep(retry_after)\n                continue\n            raise\n\n    raise Exception(f\"Max retries ({max_retries}) exceeded\")\n\n# Usage\npage = api_call_with_backoff(\n    confluence.get_page_by_id,\n    page_id='123456789'\n)\n```\n\n### Comprehensive Error Handler\n\n```python\nfrom requests.exceptions import HTTPError, Timeout, ConnectionError\n\ndef safe_api_call(func, *args, **kwargs):\n    \"\"\"Wrapper for safe API calls with comprehensive error handling.\"\"\"\n    try:\n        return func(*args, **kwargs)\n    except HTTPError as e:\n        status = e.response.status_code\n        if status == 401:\n            print(\"Authentication failed. Check your API token.\")\n        elif status == 403:\n            print(\"Permission denied. Check user permissions.\")\n        elif status == 404:\n            print(\"Resource not found.\")\n        elif status == 409:\n            print(\"Version conflict. Refresh and try again.\")\n        elif status == 429:\n            print(\"Rate limit exceeded. Slow down requests.\")\n        else:\n            print(f\"HTTP Error {status}: {e.response.text}\")\n        raise\n    except Timeout:\n        print(\"Request timed out. Try again later.\")\n        raise\n    except ConnectionError:\n        print(\"Connection error. Check network connectivity.\")\n        raise\n    except Exception as e:\n        print(f\"Unexpected error: {str(e)}\")\n        raise\n```\n\n## Bulk Operations\n\n### Get Multiple Pages by IDs\n\n```python\ndef get_pages_by_ids(confluence, page_ids):\n    \"\"\"Fetch multiple pages by their IDs.\"\"\"\n    pages = []\n\n    for page_id in page_ids:\n        try:\n            page = confluence.get_page_by_id(\n                page_id=page_id,\n                expand='body.storage,version'\n            )\n            pages.append(page)\n        except HTTPError as e:\n            print(f\"Failed to fetch page {page_id}: {e}\")\n\n    return pages\n```\n\n### Batch Create Pages\n\n```python\nimport time\n\ndef create_multiple_pages(confluence, space_key, page_data):\n    \"\"\"Create multiple pages in a space.\"\"\"\n    created = []\n\n    for data in page_data:\n        page = confluence.create_page(\n            space=space_key,\n            title=data['title'],\n            body=data['content'],\n            parent_id=data.get('parent_id')\n        )\n        created.append(page)\n\n        # Rate limit protection: wait between requests\n        time.sleep(0.2)\n\n    return created\n\n# Usage\npages = [\n    {'title': 'Page 1', 'content': '<p>Content 1</p>'},\n    {'title': 'Page 2', 'content': '<p>Content 2</p>'},\n    {'title': 'Page 3', 'content': '<p>Content 3</p>'},\n]\n\ncreated_pages = create_multiple_pages(confluence, 'DEMO', pages)\n```\n\n### Batch Update Pages\n\n```python\ndef update_multiple_pages(confluence, updates):\n    \"\"\"Update multiple pages.\"\"\"\n    results = []\n\n    for update in updates:\n        page = confluence.get_page_by_id(\n            page_id=update['id'],\n            expand='version,body.storage'\n        )\n\n        updated = confluence.update_page(\n            page_id=update['id'],\n            title=update.get('title', page['title']),\n            body=update['content'],\n            version_number=page['version']['number'] + 1\n        )\n\n        results.append(updated)\n        time.sleep(0.2)\n\n    return results\n```\n\n### Export All Pages from Space\n\n```python\nimport json\n\ndef export_space_to_json(confluence, space_key, output_file):\n    \"\"\"Export all pages from a space to JSON file.\"\"\"\n    pages_data = []\n\n    for page in confluence.get_all_pages_from_space_as_generator(\n        space=space_key,\n        expand='body.storage,version'\n    ):\n        pages_data.append({\n            'id': page['id'],\n            'title': page['title'],\n            'content': page['body']['storage']['value'],\n            'version': page['version']['number']\n        })\n\n    with open(output_file, 'w', encoding='utf-8') as f:\n        json.dump(pages_data, f, indent=2, ensure_ascii=False)\n\n    print(f\"Exported {len(pages_data)} pages to {output_file}\")\n```\n\n### Clone Space to Another Space\n\n```python\ndef clone_space(confluence, source_space, target_space):\n    \"\"\"Clone all pages from source space to target space.\"\"\"\n    # Get all pages from source\n    for page in confluence.get_all_pages_from_space_as_generator(\n        space=source_space,\n        expand='body.storage'\n    ):\n        try:\n            confluence.create_page(\n                space=target_space,\n                title=page['title'],\n                body=page['body']['storage']['value']\n            )\n            print(f\"Cloned: {page['title']}\")\n            time.sleep(0.2)\n        except Exception as e:\n            print(f\"Failed to clone {page['title']}: {e}\")\n```\n\n## Performance and Optimization\n\n### Use Expand Parameter Wisely\n\n```python\n# Bad - expands everything (slow)\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.storage,body.view,body.editor,version,space,history,ancestors,descendants,container'\n)\n\n# Good - only what you need (fast)\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.storage,version'\n)\n```\n\n### Pagination Best Practices\n\n```python\ndef get_all_pages_paginated(confluence, space_key, batch_size=100):\n    \"\"\"Get all pages with manual pagination control.\"\"\"\n    all_pages = []\n    start = 0\n\n    while True:\n        batch = confluence.get_all_pages_from_space(\n            space=space_key,\n            start=start,\n            limit=batch_size\n        )\n\n        if not batch:\n            break\n\n        all_pages.extend(batch)\n\n        if len(batch) < batch_size:\n            break\n\n        start += batch_size\n\n    return all_pages\n```\n\n### Use Generators for Large Datasets\n\n```python\n# Memory efficient - processes one page at a time\ndef process_all_pages(confluence, space_key):\n    for page in confluence.get_all_pages_from_space_as_generator(space=space_key):\n        # Process each page\n        process_page(page)\n        # Memory is released after each iteration\n\n# Memory inefficient - loads all pages into memory\ndef process_all_pages_bad(confluence, space_key):\n    all_pages = confluence.get_all_pages_from_space(space=space_key, limit=10000)\n    for page in all_pages:\n        process_page(page)\n```\n\n### Caching Strategies\n\n```python\nfrom functools import lru_cache\nimport time\n\nclass CachedConfluence:\n    def __init__(self, confluence):\n        self.confluence = confluence\n        self.cache = {}\n        self.cache_ttl = 300  # 5 minutes\n\n    def get_page_cached(self, page_id):\n        \"\"\"Get page with caching.\"\"\"\n        cache_key = f\"page_{page_id}\"\n\n        if cache_key in self.cache:\n            cached_data, cached_time = self.cache[cache_key]\n            if time.time() - cached_time < self.cache_ttl:\n                return cached_data\n\n        # Fetch fresh data\n        page = self.confluence.get_page_by_id(page_id=page_id)\n        self.cache[cache_key] = (page, time.time())\n\n        return page\n\n    def invalidate_cache(self, page_id=None):\n        \"\"\"Invalidate cache for specific page or all.\"\"\"\n        if page_id:\n            cache_key = f\"page_{page_id}\"\n            self.cache.pop(cache_key, None)\n        else:\n            self.cache.clear()\n```\n\n## Common Patterns\n\n### Create or Update Page\n\n```python\ndef create_or_update_page(confluence, space_key, title, content):\n    \"\"\"Create page if it doesn't exist, update if it does.\"\"\"\n    existing = confluence.get_page_by_title(\n        space=space_key,\n        title=title\n    )\n\n    if existing:\n        # Update existing page\n        page = confluence.get_page_by_id(\n            page_id=existing['id'],\n            expand='version'\n        )\n\n        return confluence.update_page(\n            page_id=existing['id'],\n            title=title,\n            body=content,\n            version_number=page['version']['number'] + 1\n        )\n    else:\n        # Create new page\n        return confluence.create_page(\n            space=space_key,\n            title=title,\n            body=content\n        )\n```\n\n### Build Table of Contents\n\n```python\ndef build_table_of_contents(confluence, space_key):\n    \"\"\"Generate HTML table of contents for all pages in space.\"\"\"\n    pages = confluence.get_all_pages_from_space(space=space_key)\n\n    toc_html = '<h2>Table of Contents</h2><ul>'\n\n    for page in pages:\n        toc_html += f'''\n        <li>\n            <ac:link>\n                <ri:page ri:content-title=\"{page['title']}\"/>\n            </ac:link>\n        </li>\n        '''\n\n    toc_html += '</ul>'\n\n    return toc_html\n```\n\n### Sync Local Files to Confluence\n\n```python\nimport os\nfrom pathlib import Path\n\ndef sync_markdown_to_confluence(confluence, directory, space_key, parent_id=None):\n    \"\"\"Sync Markdown files to Confluence pages.\"\"\"\n    import markdown\n\n    for md_file in Path(directory).glob('*.md'):\n        # Read Markdown file\n        with open(md_file, 'r', encoding='utf-8') as f:\n            md_content = f.read()\n\n        # Convert Markdown to HTML\n        html_content = markdown.markdown(md_content)\n\n        # Extract title from filename\n        title = md_file.stem.replace('-', ' ').title()\n\n        # Create or update page\n        create_or_update_page(\n            confluence,\n            space_key=space_key,\n            title=title,\n            content=html_content\n        )\n\n        print(f\"Synced: {title}\")\n```\n\n## Content Body Formats\n\nConfluence supports multiple body representations:\n\n```python\n# Get page with different body formats\npage = confluence.get_page_by_id(\n    page_id='123456789',\n    expand='body.storage,body.view,body.export_view'\n)\n\n# Storage format (XHTML for create/update)\nstorage = page['body']['storage']['value']\n\n# View format (HTML for rendering)\nview = page['body']['view']['value']\n\n# Export format (HTML optimized for export)\nexport = page['body']['export_view']['value']\n```\n\n## Common Mistakes to Avoid\n\n- **Not incrementing version number** when updating (causes 409 conflict)\n- **Using password instead of API token** for Cloud (causes 401 error)\n- **Forgetting cloud=True** for Confluence Cloud instances\n- **Not using expand parameter** to get needed fields (results in missing data)\n- **Using storage format incorrectly** (must be valid XHTML)\n- **Not handling pagination** for large result sets (misses data beyond first page)\n- **Hardcoding credentials** in code instead of environment variables (security risk)\n- **Not implementing rate limiting** in bulk operations (causes 429 errors)\n- **Creating duplicate pages** without checking if title exists first\n- **Not escaping HTML** in content (causes malformed XML errors)\n- **Using get_all_pages_from_space** without limit for large spaces (memory issues)\n- **Not using generators** for processing large datasets (runs out of memory)\n- **Ignoring HTTP errors** without proper error handling (silent failures)\n- **Not validating page exists** before operations (causes 404 errors)\n\n## Reference Links\n\n- **atlassian-python-api Documentation**: https://atlassian-python-api.readthedocs.io/\n- **Confluence Module Docs**: https://atlassian-python-api.readthedocs.io/confluence.html\n- **Confluence Cloud REST API v2**: https://developer.atlassian.com/cloud/confluence/rest/v2/\n- **Confluence Cloud REST API v1**: https://developer.atlassian.com/cloud/confluence/rest/v1/\n- **CQL (Confluence Query Language)**: https://developer.atlassian.com/cloud/confluence/advanced-searching-using-cql/\n- **Storage Format Guide**: https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html\n- **Atlassian API Tokens**: https://id.atlassian.com/manage-profile/security/api-tokens\n- **Rate Limits**: https://developer.atlassian.com/cloud/confluence/rate-limiting/\n- **PyPI Package**: https://pypi.org/project/atlassian-python-api/\n- **GitHub Repository**: https://github.com/atlassian-api/atlassian-python-api\n"
  },
  {
    "path": "content/attrs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"attrs package guide for Python declarative classes, validators, converters, and serialization helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.4.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"attrs,python,dataclass,validation,serialization\"\n---\n\n# attrs Python Package Guide\n\n## What It Is\n\n`attrs` is a Python library for defining classes without hand-writing boilerplate like `__init__`, `__repr__`, equality, ordering, and optional immutability. For new code, the upstream docs recommend the modern `attrs` namespace with `attrs.define()` and `attrs.field()`.\n\n## Installation\n\n```bash\npython -m pip install attrs==25.4.0\n```\n\nWith Poetry:\n\n```bash\npoetry add attrs==25.4.0\n```\n\nWith uv:\n\n```bash\nuv add attrs==25.4.0\n```\n\n## Initialize And Define Classes\n\nUse the modern API for new code:\n\n```python\nfrom attrs import Factory, define, field\n\n@define\nclass User:\n    id: int\n    email: str\n    tags: list[str] = Factory(list)\n    active: bool = True\n```\n\n`@define` defaults to slotted classes (`slots=True`) and generates the initializer and common dunder methods automatically.\n\nLegacy `attr.s` / `attr.ib` code is still valid and supported, but prefer `from attrs import ...` in new code.\n\n## Core Usage\n\n### Validators And Converters\n\nConverters run before validators, so normalize incoming data first and validate the normalized value second.\n\n```python\nimport attrs\nfrom attrs import define, field\n\n@define\nclass Config:\n    retries: int = field(\n        converter=int,\n        validator=attrs.validators.ge(0),\n    )\n    timeout_seconds: float = field(\n        converter=float,\n        validator=attrs.validators.gt(0),\n    )\n```\n\nThis accepts string inputs like `\"3\"` and stores them as typed values.\n\n### Frozen Classes\n\nUse `@frozen` or `@define(frozen=True)` when instances should be immutable and hashable-by-default behavior is appropriate for your model.\n\n```python\nfrom attrs import frozen\n\n@frozen\nclass Point:\n    x: int\n    y: int\n```\n\n### Serialize Or Copy Instances\n\n```python\nimport attrs\nfrom attrs import define\n\n@define\nclass User:\n    id: int\n    email: str\n\nu1 = User(1, \"a@example.com\")\npayload = attrs.asdict(u1)\nu2 = attrs.evolve(u1, email=\"b@example.com\")\n```\n\nUse `attrs.filters.include(...)` or `attrs.filters.exclude(...)` with `attrs.asdict()` when you need to omit fields such as passwords or internal IDs.\n\n### Post-Initialization Hooks\n\nIf you need derived values after field assignment, use `__attrs_post_init__`.\n\n```python\nfrom attrs import define, field\n\n@define\nclass Rectangle:\n    width: int\n    height: int\n    area: int = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n        self.area = self.width * self.height\n```\n\nUse `__attrs_pre_init__` only when you specifically need to call `super().__init__()` or integrate with subclassing-based APIs.\n\n## Type Checking\n\n- `attrs` works well with explicit type annotations.\n- The upstream docs call out dedicated `mypy` support for attrs classes.\n- Pyright support is based on `dataclass_transform` / PEP 681 and covers a subset closest to standard-library dataclasses.\n- If you use forward references and need runtime-resolved field types, call `attrs.resolve_types(...)`.\n\n## Config And Auth\n\n`attrs` has no service authentication, API keys, or network configuration.\n\nTypical project-level configuration is limited to:\n\n- choosing mutable vs frozen classes\n- deciding whether fields are positional or keyword-only\n- deciding whether validators/converters should also run on attribute assignment\n- enabling your type checker configuration if the project relies on static typing\n\n## Common Pitfalls\n\n- Install name vs imports: install with `pip install attrs`, prefer importing from `attrs`, and expect older code to import from `attr`.\n- Mixed typed and untyped field declarations: if you define one field with `field()` but omit its annotation, attrs switches into no-typing mode and will ignore merely annotated attributes that are not also defined with `field()`.\n- Mutable defaults: do not write `tags: list[str] = []`; use `Factory(list)` or `field(factory=list)` instead.\n- Private attribute aliases: a field like `_token: str` is exposed as `token=` in the generated `__init__` unless you override it with `field(alias=\"_token\")`.\n- Attribute ordering: required fields cannot follow fields with defaults unless the later fields are keyword-only.\n- Assignment behavior: with the modern APIs, assignment-time conversion and validation are part of the default `on_setattr` behavior. If your code mutates fields after construction, expect converters and validators to run again.\n- `attrs.evolve()` uses `__init__`: pass private attributes without the leading underscore, matching the generated initializer.\n- Hashing options: prefer `frozen=True` or `unsafe_hash=`. The `hash=` argument is the deprecated alias.\n\n## Version-Sensitive Notes\n\n- `25.4.0` is the current stable release documented at `www.attrs.org` and released on `2025-10-06`.\n- `25.4.0` changed class-level `kw_only=True` behavior to match `dataclasses`: it now applies only to attributes defined on that class unless a field explicitly opts out.\n- `25.4.0` added support for Python `3.14`.\n- `24.3.0` dropped Python `3.7`; for `25.4.0`, PyPI requires Python `>=3.9`.\n- `24.1.0` changed `attrs.evolve()` so the instance must be passed positionally, not as `inst=...`.\n- Since `21.3.0`, the `attrs` import namespace is available directly; older examples may still show `import attr`.\n\n## Practical Guidance For Agents\n\n1. Start with `@define` plus type annotations unless the codebase already uses legacy `attr.s`.\n2. Use `Factory(...)` or `field(factory=...)` for mutable values.\n3. Put normalization in `converter=` and invariant checks in `validator=`.\n4. Reach for `@frozen` when the class should be hashable and immutable in application code.\n5. Use `attrs.asdict()` for simple serialization, but prefer `cattrs` or another dedicated serialization layer when the project needs schema-driven loading/dumping.\n\n## Official Sources\n\n- Documentation root: `https://www.attrs.org/en/stable/`\n- Examples: `https://www.attrs.org/en/stable/examples.html`\n- Initialization guide: `https://www.attrs.org/en/stable/init.html`\n- API reference: `https://www.attrs.org/en/stable/api.html`\n- Type annotations guide: `https://www.attrs.org/en/stable/types.html`\n- Core API naming guide: `https://www.attrs.org/en/stable/names.html`\n- Changelog: `https://www.attrs.org/en/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/attrs/`\n"
  },
  {
    "path": "content/auth0/docs/identity/javascript/DOC.md",
    "content": "---\nname: identity\ndescription: \"Auth0 JavaScript/Node.js SDK for OAuth, OIDC, and identity management in server-side applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.0.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"auth0,identity,oauth,oidc,authentication\"\n---\n\n# Auth0 JavaScript/Node.js SDK Coding Guidelines\n\nYou are an Auth0 API expert. Help me with writing code using the Auth0 SDK for JavaScript/Node.js applications.\n\nYou can find the official SDK documentation here:\nhttps://auth0.github.io/node-auth0/\n\n## Golden Rule: Use the Correct Auth0 SDK\n\nAlways use the official Auth0 Node.js SDK for server-side authentication and user management operations. This is the standard library for all Auth0 Management API and Authentication API interactions.\n\n- **Library Name:** Auth0 Node.js SDK\n- **NPM Package:** `auth0`\n- **Current Version:** 5.0.0\n- **Minimum Node.js Version:** 20.19.0+ or 22.12.0+ or 24.0.0+\n\n**Installation:**\n\n```bash\nnpm install auth0\n```\n\n**Correct Usage:**\n\n```javascript\nimport { ManagementClient, AuthenticationClient } from 'auth0';\n```\n\n**Incorrect:**\n- Using `auth0-js` for server-side operations (this is for browser-based apps)\n- Using unofficial or deprecated Auth0 packages\n\n## Environment Variables\n\nSet up your environment variables for Auth0:\n\n```\nAUTH0_DOMAIN=your-tenant.us.auth0.com\nAUTH0_CLIENT_ID=your_client_id\nAUTH0_CLIENT_SECRET=your_client_secret\nAUTH0_MANAGEMENT_API_TOKEN=your_management_api_token\n```\n\n## Installation and Setup\n\nInstall the Auth0 SDK:\n\n```bash\nnpm install auth0\n```\n\nFor TypeScript projects, types are included in the package.\n\n## Initialization\n\n### ManagementClient Initialization\n\nThe ManagementClient is used for administrative operations like user management, role assignment, and configuration.\n\n**Basic initialization with API token:**\n\n```javascript\nimport { ManagementClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  token: process.env.AUTH0_MANAGEMENT_API_TOKEN,\n});\n```\n\n**Initialization with client credentials:**\n\n```javascript\nimport { ManagementClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n```\n\n**Advanced configuration:**\n\n```javascript\nimport { ManagementClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n  timeout: 60000, // 60 seconds\n  retry: {\n    enabled: true,\n    maxRetries: 2,\n  },\n});\n```\n\n### AuthenticationClient Initialization\n\nThe AuthenticationClient handles user authentication operations like login, password reset, and token management.\n\n**Basic initialization:**\n\n```javascript\nimport { AuthenticationClient } from 'auth0';\n\nconst auth0 = new AuthenticationClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n});\n```\n\n**With client secret (for confidential clients):**\n\n```javascript\nimport { AuthenticationClient } from 'auth0';\n\nconst auth0 = new AuthenticationClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n```\n\n### UserInfoClient Initialization\n\nFor retrieving user profile information using access tokens:\n\n```javascript\nimport { UserInfoClient } from 'auth0';\n\nconst userInfo = new UserInfoClient({\n  domain: process.env.AUTH0_DOMAIN,\n});\n```\n\n## User Management\n\n### Creating Users\n\n```javascript\nimport { ManagementClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n\nasync function createUser() {\n  const newUser = await management.users.create({\n    email: 'user@example.com',\n    password: 'SecurePassword123!',\n    connection: 'Username-Password-Authentication',\n    email_verified: false,\n    user_metadata: {\n      plan: 'premium',\n      preferences: { theme: 'dark' },\n    },\n    app_metadata: {\n      role: 'user',\n    },\n  });\n\n  console.log('User created:', newUser.user_id);\n  return newUser;\n}\n```\n\n### Getting User by ID\n\n```javascript\nasync function getUser(userId) {\n  const user = await management.users.get({ id: userId });\n  console.log('User:', user);\n  return user;\n}\n```\n\n### Getting User by Email\n\n```javascript\nasync function getUserByEmail(email) {\n  const users = await management.usersByEmail.get({ email });\n\n  if (users.length > 0) {\n    console.log('User found:', users[0]);\n    return users[0];\n  }\n\n  return null;\n}\n```\n\n### Updating User\n\n```javascript\nasync function updateUser(userId, updates) {\n  const updatedUser = await management.users.update(\n    { id: userId },\n    {\n      email: 'newemail@example.com',\n      user_metadata: {\n        plan: 'enterprise',\n      },\n    }\n  );\n\n  return updatedUser;\n}\n```\n\n### Deleting User\n\n```javascript\nasync function deleteUser(userId) {\n  await management.users.delete({ id: userId });\n  console.log('User deleted');\n}\n```\n\n### Listing Users\n\n```javascript\nasync function listUsers() {\n  const users = await management.users.getAll({\n    per_page: 50,\n    page: 0,\n  });\n\n  return users;\n}\n```\n\n### Searching Users\n\n```javascript\nasync function searchUsers(query) {\n  const users = await management.users.getAll({\n    q: `email:\"*@example.com\"`,\n    search_engine: 'v3',\n  });\n\n  return users;\n}\n```\n\n## Authentication Operations\n\n### Password Grant (Direct Login)\n\n```javascript\nimport { AuthenticationClient } from 'auth0';\n\nconst auth0 = new AuthenticationClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n\nasync function login(username, password) {\n  const response = await auth0.oauth.passwordGrant({\n    username,\n    password,\n    audience: 'https://api.example.com',\n    scope: 'openid profile email',\n  });\n\n  console.log('Access Token:', response.access_token);\n  console.log('ID Token:', response.id_token);\n  return response;\n}\n```\n\n### Client Credentials Grant\n\n```javascript\nasync function getClientCredentialsToken() {\n  const response = await auth0.oauth.clientCredentialsGrant({\n    audience: 'https://api.example.com',\n  });\n\n  console.log('Access Token:', response.access_token);\n  return response;\n}\n```\n\n### Refresh Token\n\n```javascript\nasync function refreshToken(refreshToken) {\n  const response = await auth0.oauth.refreshTokenGrant({\n    refresh_token: refreshToken,\n  });\n\n  console.log('New Access Token:', response.access_token);\n  return response;\n}\n```\n\n### Password Reset\n\n```javascript\nasync function requestPasswordReset(email) {\n  await auth0.database.changePassword({\n    email,\n    connection: 'Username-Password-Authentication',\n  });\n\n  console.log('Password reset email sent');\n}\n```\n\n### User Signup\n\n```javascript\nasync function signup(email, password) {\n  const user = await auth0.database.signUp({\n    email,\n    password,\n    connection: 'Username-Password-Authentication',\n  });\n\n  return user;\n}\n```\n\n## Token Operations\n\n### Getting User Info from Access Token\n\n```javascript\nimport { UserInfoClient } from 'auth0';\n\nconst userInfo = new UserInfoClient({\n  domain: process.env.AUTH0_DOMAIN,\n});\n\nasync function getUserProfile(accessToken) {\n  const profile = await userInfo.getUserInfo(accessToken);\n\n  console.log('User Profile:', profile);\n  return profile;\n}\n```\n\n### Revoking Refresh Token\n\n```javascript\nasync function revokeToken(token) {\n  await auth0.oauth.revokeRefreshToken({\n    token,\n  });\n\n  console.log('Token revoked');\n}\n```\n\n## Role and Permission Management\n\n### Assigning Roles to User\n\n```javascript\nasync function assignRolesToUser(userId, roleIds) {\n  await management.users.assignRoles(\n    { id: userId },\n    { roles: roleIds }\n  );\n\n  console.log('Roles assigned');\n}\n```\n\n### Getting User Roles\n\n```javascript\nasync function getUserRoles(userId) {\n  const roles = await management.users.getRoles({ id: userId });\n\n  console.log('User Roles:', roles);\n  return roles;\n}\n```\n\n### Removing Roles from User\n\n```javascript\nasync function removeRolesFromUser(userId, roleIds) {\n  await management.users.removeRoles(\n    { id: userId },\n    { roles: roleIds }\n  );\n\n  console.log('Roles removed');\n}\n```\n\n### Getting User Permissions\n\n```javascript\nasync function getUserPermissions(userId) {\n  const permissions = await management.users.getPermissions({ id: userId });\n\n  console.log('User Permissions:', permissions);\n  return permissions;\n}\n```\n\n### Assigning Permissions to User\n\n```javascript\nasync function assignPermissionsToUser(userId, permissions) {\n  await management.users.assignPermissions(\n    { id: userId },\n    {\n      permissions: [\n        { permission_name: 'read:messages', resource_server_identifier: 'https://api.example.com' },\n        { permission_name: 'write:messages', resource_server_identifier: 'https://api.example.com' },\n      ]\n    }\n  );\n\n  console.log('Permissions assigned');\n}\n```\n\n## Organization Management\n\n### Creating an Organization\n\n```javascript\nasync function createOrganization(name, displayName) {\n  const org = await management.organizations.create({\n    name,\n    display_name: displayName,\n  });\n\n  return org;\n}\n```\n\n### Adding Members to Organization\n\n```javascript\nasync function addMemberToOrganization(orgId, userId) {\n  await management.organizations.addMembers(\n    { id: orgId },\n    { members: [userId] }\n  );\n\n  console.log('Member added to organization');\n}\n```\n\n### Getting Organization Members\n\n```javascript\nasync function getOrganizationMembers(orgId) {\n  const members = await management.organizations.getMembers({ id: orgId });\n\n  return members;\n}\n```\n\n### Assigning Roles to Organization Member\n\n```javascript\nasync function assignOrgRoles(orgId, userId, roleIds) {\n  await management.organizations.addMemberRoles(\n    { id: orgId, user_id: userId },\n    { roles: roleIds }\n  );\n\n  console.log('Organization roles assigned');\n}\n```\n\n## Client Application Management\n\n### Getting All Clients\n\n```javascript\nasync function getAllClients() {\n  const clients = await management.clients.getAll();\n\n  return clients;\n}\n```\n\n### Creating a Client\n\n```javascript\nasync function createClient(name, type) {\n  const client = await management.clients.create({\n    name,\n    app_type: type, // 'native', 'spa', 'regular_web', 'non_interactive'\n    callbacks: ['http://localhost:3000/callback'],\n    allowed_logout_urls: ['http://localhost:3000'],\n  });\n\n  return client;\n}\n```\n\n### Updating a Client\n\n```javascript\nasync function updateClient(clientId, updates) {\n  const client = await management.clients.update(\n    { client_id: clientId },\n    updates\n  );\n\n  return client;\n}\n```\n\n## Connection Management\n\n### Getting All Connections\n\n```javascript\nasync function getAllConnections() {\n  const connections = await management.connections.getAll();\n\n  return connections;\n}\n```\n\n### Creating a Database Connection\n\n```javascript\nasync function createDatabaseConnection(name) {\n  const connection = await management.connections.create({\n    name,\n    strategy: 'auth0',\n    enabled_clients: [process.env.AUTH0_CLIENT_ID],\n  });\n\n  return connection;\n}\n```\n\n### Getting Connection by ID\n\n```javascript\nasync function getConnection(connectionId) {\n  const connection = await management.connections.get({ id: connectionId });\n\n  return connection;\n}\n```\n\n## Email Templates and Verification\n\n### Sending Email Verification\n\n```javascript\nasync function sendVerificationEmail(userId) {\n  await management.jobs.verifyEmail({\n    user_id: userId,\n  });\n\n  console.log('Verification email sent');\n}\n```\n\n### Creating Email Verification Ticket\n\n```javascript\nasync function createEmailVerificationTicket(userId) {\n  const ticket = await management.tickets.verifyEmail({\n    user_id: userId,\n    result_url: 'https://example.com/verified',\n  });\n\n  console.log('Verification URL:', ticket.ticket);\n  return ticket;\n}\n```\n\n### Creating Password Change Ticket\n\n```javascript\nasync function createPasswordChangeTicket(userId) {\n  const ticket = await management.tickets.changePassword({\n    user_id: userId,\n    result_url: 'https://example.com/password-changed',\n  });\n\n  console.log('Password change URL:', ticket.ticket);\n  return ticket;\n}\n```\n\n## Pagination\n\n### Manual Pagination\n\n```javascript\nasync function getAllUsersPaginated() {\n  let page = 0;\n  const perPage = 50;\n  let allUsers = [];\n  let hasMore = true;\n\n  while (hasMore) {\n    const users = await management.users.getAll({\n      page,\n      per_page: perPage,\n    });\n\n    allUsers = allUsers.concat(users);\n    hasMore = users.length === perPage;\n    page++;\n  }\n\n  return allUsers;\n}\n```\n\n### Using Pagination Iterator\n\n```javascript\nasync function iterateAllUsers() {\n  const users = [];\n\n  for await (const user of management.users.getAll()) {\n    users.push(user);\n  }\n\n  return users;\n}\n```\n\n## Error Handling\n\nThe SDK provides comprehensive error handling with ManagementError and AuthenticationError types.\n\n```javascript\nimport { ManagementClient, ManagementError } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n\nasync function handleErrors() {\n  try {\n    const user = await management.users.get({ id: 'invalid-id' });\n  } catch (err) {\n    if (err instanceof ManagementError) {\n      console.log('Status Code:', err.statusCode); // 404\n      console.log('Error Message:', err.message);\n      console.log('Error Body:', err.body);\n      console.log('Raw Response:', err.rawResponse);\n    } else {\n      throw err;\n    }\n  }\n}\n```\n\n### Common Error Status Codes\n\n| Status Code | Error Type | Description |\n|-------------|------------|-------------|\n| 400 | Bad Request | Invalid request parameters |\n| 401 | Unauthorized | Invalid or missing credentials |\n| 403 | Forbidden | Insufficient permissions |\n| 404 | Not Found | Resource not found |\n| 409 | Conflict | Resource already exists |\n| 429 | Too Many Requests | Rate limit exceeded |\n| 500 | Internal Server Error | Server error |\n\n## Advanced Configuration\n\n### Custom Timeout\n\n```javascript\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  token: process.env.AUTH0_MANAGEMENT_API_TOKEN,\n  timeout: 30000, // 30 seconds\n});\n```\n\n### Retry Configuration\n\n```javascript\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  token: process.env.AUTH0_MANAGEMENT_API_TOKEN,\n  retry: {\n    enabled: true,\n    maxRetries: 3,\n  },\n});\n```\n\n### Custom Headers\n\n```javascript\nasync function makeRequestWithCustomHeaders() {\n  const users = await management.users.getAll({}, {\n    headers: {\n      'X-Custom-Header': 'custom-value',\n    },\n  });\n\n  return users;\n}\n```\n\n### Abort Signal (Request Cancellation)\n\n```javascript\nasync function cancelableRequest() {\n  const controller = new AbortController();\n\n  // Cancel after 5 seconds\n  setTimeout(() => controller.abort(), 5000);\n\n  try {\n    const users = await management.users.getAll({}, {\n      signal: controller.signal,\n    });\n\n    return users;\n  } catch (err) {\n    if (err.name === 'AbortError') {\n      console.log('Request was cancelled');\n    }\n    throw err;\n  }\n}\n```\n\n## Logs and Monitoring\n\n### Getting Logs\n\n```javascript\nasync function getLogs() {\n  const logs = await management.logs.getAll({\n    per_page: 100,\n    page: 0,\n  });\n\n  return logs;\n}\n```\n\n### Filtering Logs by Type\n\n```javascript\nasync function getLoginLogs() {\n  const logs = await management.logs.getAll({\n    q: 'type:s', // 's' = successful login\n    per_page: 100,\n  });\n\n  return logs;\n}\n```\n\n### Getting Log by ID\n\n```javascript\nasync function getLogById(logId) {\n  const log = await management.logs.get({ id: logId });\n\n  return log;\n}\n```\n\n## Guardian (MFA) Management\n\n### Getting Guardian Enrollments\n\n```javascript\nasync function getUserMFAEnrollments(userId) {\n  const enrollments = await management.users.getGuardianEnrollments({ id: userId });\n\n  return enrollments;\n}\n```\n\n### Deleting Guardian Enrollment\n\n```javascript\nasync function deleteMFAEnrollment(userId, enrollmentId) {\n  await management.guardian.deleteEnrollment({ id: enrollmentId });\n\n  console.log('MFA enrollment deleted');\n}\n```\n\n## Runtime Compatibility\n\nThe Auth0 Node.js SDK v5 is compatible with:\n\n- Node.js 20.19.0+\n- Node.js 22.12.0+\n- Node.js 24.0.0+\n- Vercel Edge Functions\n- Cloudflare Workers\n- Deno\n- Bun\n- React Native\n\n## Legacy Support\n\nIf you're migrating from v4.x, use the legacy exports:\n\n```javascript\nimport { ManagementClient } from 'auth0/legacy';\n\n// Old v4.x configuration format\nconst management = new ManagementClient({\n  domain: 'tenant.auth0.com',\n  clientId: 'CLIENT_ID',\n  clientSecret: 'CLIENT_SECRET',\n});\n```\n\n## Complete Example: User Registration and Login Flow\n\n```javascript\nimport { ManagementClient, AuthenticationClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n\nconst auth0 = new AuthenticationClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n});\n\nasync function registerAndLogin() {\n  // 1. Create a new user\n  const newUser = await management.users.create({\n    email: 'john.doe@example.com',\n    password: 'SecurePassword123!',\n    connection: 'Username-Password-Authentication',\n    user_metadata: {\n      firstName: 'John',\n      lastName: 'Doe',\n    },\n  });\n\n  console.log('User created:', newUser.user_id);\n\n  // 2. Send verification email\n  await management.jobs.verifyEmail({\n    user_id: newUser.user_id,\n  });\n\n  console.log('Verification email sent');\n\n  // 3. Login user (after email verification)\n  const loginResponse = await auth0.oauth.passwordGrant({\n    username: 'john.doe@example.com',\n    password: 'SecurePassword123!',\n    audience: 'https://api.example.com',\n    scope: 'openid profile email',\n  });\n\n  console.log('Access Token:', loginResponse.access_token);\n\n  // 4. Get user profile\n  const userInfo = new UserInfoClient({\n    domain: process.env.AUTH0_DOMAIN,\n  });\n\n  const profile = await userInfo.getUserInfo(loginResponse.access_token);\n  console.log('User Profile:', profile);\n\n  return {\n    user: newUser,\n    tokens: loginResponse,\n    profile,\n  };\n}\n```\n\n## Important Notes\n\n### Security Best Practices\n\n1. **Never expose client secrets** - Keep client secrets secure on the server side only\n2. **Use environment variables** - Store credentials in environment variables, not in code\n3. **Validate tokens** - Always validate tokens on the server side\n4. **Use HTTPS** - Always use HTTPS in production\n5. **Implement rate limiting** - Protect against brute force attacks\n6. **Rotate credentials** - Regularly rotate API tokens and client secrets\n\n### Management API Token\n\n- Management API tokens expire after 24 hours\n- Use client credentials grant for long-running applications\n- Cache tokens and refresh before expiration\n\n### Rate Limits\n\nAuth0 enforces rate limits on API requests. Handle 429 errors gracefully:\n\n```javascript\nasync function retryWithBackoff(fn, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (err.statusCode === 429 && i < maxRetries - 1) {\n        const waitTime = Math.pow(2, i) * 1000;\n        await new Promise(resolve => setTimeout(resolve, waitTime));\n        continue;\n      }\n      throw err;\n    }\n  }\n}\n```\n\n### User Search Syntax\n\nUse Lucene query syntax for user searches:\n\n```javascript\n// Search by email domain\nq: 'email:\"*@example.com\"'\n\n// Search by metadata\nq: 'user_metadata.plan:\"premium\"'\n\n// Search by multiple fields\nq: 'email:\"*@example.com\" AND user_metadata.plan:\"premium\"'\n\n// Search by created date\nq: 'created_at:[2024-01-01 TO 2024-12-31]'\n```\n\n## Useful Links\n\n- Official Documentation: https://auth0.com/docs\n- SDK Reference: https://auth0.github.io/node-auth0/\n- GitHub Repository: https://github.com/auth0/node-auth0\n- Community Forum: https://community.auth0.com/\n- Auth0 Dashboard: https://manage.auth0.com/\n- API Rate Limits: https://auth0.com/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy\n"
  },
  {
    "path": "content/auth0/docs/identity/python/DOC.md",
    "content": "---\nname: identity\ndescription: \"Auth0 Python SDK for OAuth, OIDC, and identity management in server-side applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.7.2\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"auth0,identity,oauth,oidc,authentication\"\n---\n\n# Auth0 Python SDK Coding Guidelines\n\nYou are an Auth0 API expert. Help me with writing code using the Auth0 SDK for Python applications.\n\nYou can find the official SDK documentation here:\nhttps://auth0-python.readthedocs.io/en/latest/\n\n## Golden Rule: Use the Correct Auth0 SDK\n\nAlways use the official Auth0 Python SDK for server-side authentication and user management operations. This is the standard library for all Auth0 Management API and Authentication API interactions in Python.\n\n- **Library Name:** Auth0 Python SDK\n- **PyPI Package:** `auth0-python`\n- **Current Version:** 4.13.0\n- **Minimum Python Version:** 3.7+\n\n**Installation:**\n\n```bash\npip install auth0-python\n```\n\n**Correct Usage:**\n\n```python\nfrom auth0.management import Auth0\nfrom auth0.authentication import GetToken, Database\n```\n\n**Incorrect:**\n- Using unofficial Auth0 packages\n- Using deprecated versions of the SDK\n\n## Environment Variables\n\nSet up your environment variables for Auth0:\n\n```\nAUTH0_DOMAIN=your-tenant.us.auth0.com\nAUTH0_CLIENT_ID=your_client_id\nAUTH0_CLIENT_SECRET=your_client_secret\nAUTH0_MANAGEMENT_API_AUDIENCE=https://your-tenant.us.auth0.com/api/v2/\n```\n\n## Installation and Setup\n\nInstall the Auth0 Python SDK:\n\n```bash\npip install auth0-python\n```\n\nFor specific versions:\n\n```bash\npip install auth0-python==4.13.0\n```\n\n## Initialization\n\n### Management API Client Initialization\n\nThe Management API client is used for administrative operations like user management, role assignment, and configuration.\n\n**Basic initialization with token:**\n\n```python\nfrom auth0.management import Auth0\nimport os\n\ndomain = os.getenv('AUTH0_DOMAIN')\nmgmt_api_token = os.getenv('AUTH0_MANAGEMENT_API_TOKEN')\n\nauth0 = Auth0(domain, mgmt_api_token)\n```\n\n**Initialization with client credentials (recommended):**\n\n```python\nfrom auth0.authentication import GetToken\nfrom auth0.management import Auth0\nimport os\n\ndomain = os.getenv('AUTH0_DOMAIN')\nclient_id = os.getenv('AUTH0_CLIENT_ID')\nclient_secret = os.getenv('AUTH0_CLIENT_SECRET')\n\n# Get Management API token\nget_token = GetToken(domain, client_id, client_secret=client_secret)\ntoken = get_token.client_credentials(f'https://{domain}/api/v2/')\nmgmt_api_token = token['access_token']\n\n# Initialize Management client\nauth0 = Auth0(domain, mgmt_api_token)\n```\n\n### Authentication API Client Initialization\n\nThe Authentication API provides methods for login, signup, and password management.\n\n**Database authentication:**\n\n```python\nfrom auth0.authentication import Database\nimport os\n\ndomain = os.getenv('AUTH0_DOMAIN')\nclient_id = os.getenv('AUTH0_CLIENT_ID')\n\ndatabase = Database(domain, client_id)\n```\n\n**Token authentication:**\n\n```python\nfrom auth0.authentication import GetToken\nimport os\n\ndomain = os.getenv('AUTH0_DOMAIN')\nclient_id = os.getenv('AUTH0_CLIENT_ID')\nclient_secret = os.getenv('AUTH0_CLIENT_SECRET')\n\nget_token = GetToken(domain, client_id, client_secret=client_secret)\n```\n\n## User Management\n\n### Creating Users\n\n```python\nfrom auth0.management import Auth0\n\nauth0 = Auth0(domain, mgmt_api_token)\n\ndef create_user(email, password):\n    user = auth0.users.create({\n        'email': email,\n        'password': password,\n        'connection': 'Username-Password-Authentication',\n        'email_verified': False,\n        'user_metadata': {\n            'plan': 'premium',\n            'preferences': {'theme': 'dark'}\n        },\n        'app_metadata': {\n            'role': 'user'\n        }\n    })\n\n    print(f\"User created: {user['user_id']}\")\n    return user\n```\n\n### Getting User by ID\n\n```python\ndef get_user(user_id):\n    user = auth0.users.get(user_id)\n    print(f\"User: {user}\")\n    return user\n```\n\n### Getting User by Email\n\n```python\ndef get_user_by_email(email):\n    users = auth0.users_by_email.search_users_by_email(email)\n\n    if users:\n        print(f\"User found: {users[0]}\")\n        return users[0]\n\n    return None\n```\n\n### Updating User\n\n```python\ndef update_user(user_id, updates):\n    updated_user = auth0.users.update(user_id, {\n        'email': 'newemail@example.com',\n        'user_metadata': {\n            'plan': 'enterprise'\n        }\n    })\n\n    return updated_user\n```\n\n### Deleting User\n\n```python\ndef delete_user(user_id):\n    auth0.users.delete(user_id)\n    print('User deleted')\n```\n\n### Listing Users\n\n```python\ndef list_users(page=0, per_page=50):\n    users = auth0.users.list(page=page, per_page=per_page)\n    return users\n```\n\n### Searching Users\n\n```python\ndef search_users(query):\n    users = auth0.users.list(\n        q=query,\n        search_engine='v3'\n    )\n    return users\n\n# Example usage\nusers = search_users('email:\"*@example.com\"')\n```\n\n### Getting All Users (with pagination)\n\n```python\ndef get_all_users():\n    all_users = []\n    page = 0\n    per_page = 100\n\n    while True:\n        users = auth0.users.list(page=page, per_page=per_page)\n\n        if not users['users']:\n            break\n\n        all_users.extend(users['users'])\n\n        # Check if there are more pages\n        if len(users['users']) < per_page:\n            break\n\n        page += 1\n\n    return all_users\n```\n\n## Authentication Operations\n\n### User Signup\n\n```python\nfrom auth0.authentication import Database\n\ndatabase = Database(domain, client_id)\n\ndef signup_user(email, password):\n    result = database.signup(\n        email=email,\n        password=password,\n        connection='Username-Password-Authentication'\n    )\n\n    print(f\"User signed up: {result}\")\n    return result\n```\n\n### User Login (Resource Owner Password Grant)\n\n```python\nfrom auth0.authentication import GetToken\n\nget_token = GetToken(domain, client_id, client_secret=client_secret)\n\ndef login_user(username, password):\n    token_response = get_token.login(\n        username=username,\n        password=password,\n        realm='Username-Password-Authentication',\n        scope='openid profile email',\n        audience='https://api.example.com'\n    )\n\n    print(f\"Access Token: {token_response['access_token']}\")\n    print(f\"ID Token: {token_response.get('id_token')}\")\n\n    return token_response\n```\n\n### Client Credentials Grant\n\n```python\ndef get_client_credentials_token(audience):\n    token = get_token.client_credentials(audience)\n\n    print(f\"Access Token: {token['access_token']}\")\n    return token\n```\n\n### Authorization Code Exchange\n\n```python\ndef exchange_authorization_code(code, redirect_uri):\n    token = get_token.authorization_code(\n        code=code,\n        redirect_uri=redirect_uri\n    )\n\n    return token\n```\n\n### Refresh Token\n\n```python\ndef refresh_access_token(refresh_token):\n    token = get_token.refresh_token(refresh_token)\n\n    print(f\"New Access Token: {token['access_token']}\")\n    return token\n```\n\n### Password Reset\n\n```python\ndef request_password_reset(email):\n    database.change_password(\n        email=email,\n        connection='Username-Password-Authentication'\n    )\n\n    print('Password reset email sent')\n```\n\n### Password Realm Grant\n\n```python\ndef password_realm_grant(username, password, realm):\n    token = get_token.login(\n        username=username,\n        password=password,\n        realm=realm,\n        scope='openid profile email'\n    )\n\n    return token\n```\n\n## Role and Permission Management\n\n### Creating a Role\n\n```python\ndef create_role(name, description):\n    role = auth0.roles.create({\n        'name': name,\n        'description': description\n    })\n\n    print(f\"Role created: {role['id']}\")\n    return role\n```\n\n### Getting All Roles\n\n```python\ndef get_all_roles():\n    roles = auth0.roles.list()\n    return roles\n```\n\n### Getting Role by ID\n\n```python\ndef get_role(role_id):\n    role = auth0.roles.get(role_id)\n    return role\n```\n\n### Updating a Role\n\n```python\ndef update_role(role_id, name, description):\n    role = auth0.roles.update(role_id, {\n        'name': name,\n        'description': description\n    })\n\n    return role\n```\n\n### Deleting a Role\n\n```python\ndef delete_role(role_id):\n    auth0.roles.delete(role_id)\n    print('Role deleted')\n```\n\n### Assigning Roles to User\n\n```python\ndef assign_roles_to_user(user_id, role_ids):\n    auth0.users.add_roles(user_id, {'roles': role_ids})\n    print('Roles assigned to user')\n```\n\n### Getting User Roles\n\n```python\ndef get_user_roles(user_id):\n    roles = auth0.users.list_roles(user_id)\n    print(f\"User Roles: {roles}\")\n    return roles\n```\n\n### Removing Roles from User\n\n```python\ndef remove_roles_from_user(user_id, role_ids):\n    auth0.users.remove_roles(user_id, {'roles': role_ids})\n    print('Roles removed from user')\n```\n\n### Adding Permissions to Role\n\n```python\ndef add_permissions_to_role(role_id, permissions):\n    auth0.roles.add_permissions(role_id, {\n        'permissions': [\n            {\n                'permission_name': 'read:messages',\n                'resource_server_identifier': 'https://api.example.com'\n            },\n            {\n                'permission_name': 'write:messages',\n                'resource_server_identifier': 'https://api.example.com'\n            }\n        ]\n    })\n\n    print('Permissions added to role')\n```\n\n### Getting Role Permissions\n\n```python\ndef get_role_permissions(role_id):\n    permissions = auth0.roles.get_permissions(role_id)\n    return permissions\n```\n\n### Removing Permissions from Role\n\n```python\ndef remove_permissions_from_role(role_id, permissions):\n    auth0.roles.remove_permissions(role_id, {'permissions': permissions})\n    print('Permissions removed from role')\n```\n\n### Getting User Permissions\n\n```python\ndef get_user_permissions(user_id):\n    permissions = auth0.users.list_permissions(user_id)\n    print(f\"User Permissions: {permissions}\")\n    return permissions\n```\n\n### Assigning Permissions to User\n\n```python\ndef assign_permissions_to_user(user_id):\n    auth0.users.add_permissions(user_id, {\n        'permissions': [\n            {\n                'permission_name': 'read:messages',\n                'resource_server_identifier': 'https://api.example.com'\n            }\n        ]\n    })\n\n    print('Permissions assigned to user')\n```\n\n### Removing Permissions from User\n\n```python\ndef remove_permissions_from_user(user_id, permissions):\n    auth0.users.remove_permissions(user_id, {'permissions': permissions})\n    print('Permissions removed from user')\n```\n\n## Organization Management\n\n### Creating an Organization\n\n```python\ndef create_organization(name, display_name):\n    org = auth0.organizations.create({\n        'name': name,\n        'display_name': display_name\n    })\n\n    print(f\"Organization created: {org['id']}\")\n    return org\n```\n\n### Getting All Organizations\n\n```python\ndef get_all_organizations():\n    orgs = auth0.organizations.list()\n    return orgs\n```\n\n### Getting Organization by ID\n\n```python\ndef get_organization(org_id):\n    org = auth0.organizations.get(org_id)\n    return org\n```\n\n### Updating an Organization\n\n```python\ndef update_organization(org_id, updates):\n    org = auth0.organizations.update(org_id, updates)\n    return org\n```\n\n### Deleting an Organization\n\n```python\ndef delete_organization(org_id):\n    auth0.organizations.delete(org_id)\n    print('Organization deleted')\n```\n\n### Adding Members to Organization\n\n```python\ndef add_member_to_organization(org_id, user_ids):\n    auth0.organizations.create_members(org_id, {'members': user_ids})\n    print('Members added to organization')\n```\n\n### Getting Organization Members\n\n```python\ndef get_organization_members(org_id):\n    members = auth0.organizations.list_members(org_id)\n    return members\n```\n\n### Removing Members from Organization\n\n```python\ndef remove_members_from_organization(org_id, user_ids):\n    for user_id in user_ids:\n        auth0.organizations.delete_member(org_id, user_id)\n\n    print('Members removed from organization')\n```\n\n### Assigning Roles to Organization Member\n\n```python\ndef assign_org_roles(org_id, user_id, role_ids):\n    auth0.organizations.create_member_roles(\n        org_id,\n        user_id,\n        {'roles': role_ids}\n    )\n\n    print('Organization roles assigned')\n```\n\n### Getting Organization Member Roles\n\n```python\ndef get_org_member_roles(org_id, user_id):\n    roles = auth0.organizations.list_member_roles(org_id, user_id)\n    return roles\n```\n\n## Connection Management\n\n### Getting All Connections\n\n```python\ndef get_all_connections():\n    connections = auth0.connections.all()\n    return connections\n```\n\n### Getting Connection by ID\n\n```python\ndef get_connection(connection_id):\n    connection = auth0.connections.get(connection_id)\n    return connection\n```\n\n### Creating a Database Connection\n\n```python\ndef create_database_connection(name):\n    connection = auth0.connections.create({\n        'name': name,\n        'strategy': 'auth0',\n        'enabled_clients': [client_id]\n    })\n\n    return connection\n```\n\n### Updating a Connection\n\n```python\ndef update_connection(connection_id, updates):\n    connection = auth0.connections.update(connection_id, updates)\n    return connection\n```\n\n### Deleting a Connection\n\n```python\ndef delete_connection(connection_id):\n    auth0.connections.delete(connection_id)\n    print('Connection deleted')\n```\n\n## Client Application Management\n\n### Getting All Clients\n\n```python\ndef get_all_clients():\n    clients = auth0.clients.all()\n    return clients\n```\n\n### Getting Client by ID\n\n```python\ndef get_client(client_id):\n    client = auth0.clients.get(client_id)\n    return client\n```\n\n### Creating a Client\n\n```python\ndef create_client(name, app_type):\n    client = auth0.clients.create({\n        'name': name,\n        'app_type': app_type,  # 'native', 'spa', 'regular_web', 'non_interactive'\n        'callbacks': ['http://localhost:3000/callback'],\n        'allowed_logout_urls': ['http://localhost:3000']\n    })\n\n    return client\n```\n\n### Updating a Client\n\n```python\ndef update_client(client_id, updates):\n    client = auth0.clients.update(client_id, updates)\n    return client\n```\n\n### Deleting a Client\n\n```python\ndef delete_client(client_id):\n    auth0.clients.delete(client_id)\n    print('Client deleted')\n```\n\n## Email and Verification\n\n### Sending Email Verification\n\n```python\ndef send_verification_email(user_id):\n    job = auth0.jobs.send_verification_email({\n        'user_id': user_id\n    })\n\n    print(f\"Verification email job created: {job}\")\n    return job\n```\n\n### Creating Email Verification Ticket\n\n```python\ndef create_email_verification_ticket(user_id):\n    ticket = auth0.tickets.create_email_verification({\n        'user_id': user_id,\n        'result_url': 'https://example.com/verified'\n    })\n\n    print(f\"Verification URL: {ticket['ticket']}\")\n    return ticket\n```\n\n### Creating Password Change Ticket\n\n```python\ndef create_password_change_ticket(user_id):\n    ticket = auth0.tickets.create_pswd_change({\n        'user_id': user_id,\n        'result_url': 'https://example.com/password-changed'\n    })\n\n    print(f\"Password change URL: {ticket['ticket']}\")\n    return ticket\n```\n\n## Logs and Monitoring\n\n### Getting Logs\n\n```python\ndef get_logs(page=0, per_page=100):\n    logs = auth0.logs.search(page=page, per_page=per_page)\n    return logs\n```\n\n### Getting Logs with Query\n\n```python\ndef get_login_logs():\n    logs = auth0.logs.search(q='type:s', per_page=100)  # 's' = successful login\n    return logs\n```\n\n### Getting Log by ID\n\n```python\ndef get_log_by_id(log_id):\n    log = auth0.logs.get(log_id)\n    return log\n```\n\n## Guardian (MFA) Management\n\n### Getting User Enrollments\n\n```python\ndef get_user_mfa_enrollments(user_id):\n    enrollments = auth0.users.get_guardian_enrollments(user_id)\n    return enrollments\n```\n\n### Deleting User Enrollment\n\n```python\ndef delete_mfa_enrollment(user_id, enrollment_id):\n    auth0.guardian.delete_enrollment(enrollment_id)\n    print('MFA enrollment deleted')\n```\n\n### Getting Guardian Factors\n\n```python\ndef get_guardian_factors():\n    factors = auth0.guardian.all_factors()\n    return factors\n```\n\n### Updating Guardian Factor\n\n```python\ndef update_guardian_factor(factor_name, enabled):\n    auth0.guardian.update_factor(factor_name, {'enabled': enabled})\n    print(f\"Guardian factor {factor_name} updated\")\n```\n\n## User Blocking\n\n### Getting User Blocks by Identifier\n\n```python\ndef get_user_blocks(identifier):\n    blocks = auth0.user_blocks.get_by_identifier(identifier)\n    return blocks\n```\n\n### Unblocking User by Identifier\n\n```python\ndef unblock_user(identifier):\n    auth0.user_blocks.unblock_by_identifier(identifier)\n    print('User unblocked')\n```\n\n### Getting User Blocks by ID\n\n```python\ndef get_user_blocks_by_id(user_id):\n    blocks = auth0.user_blocks.get(user_id)\n    return blocks\n```\n\n### Unblocking User by ID\n\n```python\ndef unblock_user_by_id(user_id):\n    auth0.user_blocks.unblock(user_id)\n    print('User unblocked')\n```\n\n## Grants Management\n\n### Getting All Grants\n\n```python\ndef get_all_grants():\n    grants = auth0.grants.all()\n    return grants\n```\n\n### Getting Grants by User ID\n\n```python\ndef get_user_grants(user_id):\n    grants = auth0.grants.all(user_id=user_id)\n    return grants\n```\n\n### Deleting Grant\n\n```python\ndef delete_grant(grant_id):\n    auth0.grants.delete(grant_id)\n    print('Grant deleted')\n```\n\n## Resource Servers (APIs)\n\n### Getting All Resource Servers\n\n```python\ndef get_all_resource_servers():\n    apis = auth0.resource_servers.get_all()\n    return apis\n```\n\n### Creating a Resource Server\n\n```python\ndef create_resource_server(identifier, name):\n    api = auth0.resource_servers.create({\n        'identifier': identifier,\n        'name': name,\n        'signing_alg': 'RS256',\n        'scopes': [\n            {'value': 'read:messages', 'description': 'Read messages'},\n            {'value': 'write:messages', 'description': 'Write messages'}\n        ]\n    })\n\n    return api\n```\n\n### Getting Resource Server by ID\n\n```python\ndef get_resource_server(resource_server_id):\n    api = auth0.resource_servers.get(resource_server_id)\n    return api\n```\n\n### Updating Resource Server\n\n```python\ndef update_resource_server(resource_server_id, updates):\n    api = auth0.resource_servers.update(resource_server_id, updates)\n    return api\n```\n\n### Deleting Resource Server\n\n```python\ndef delete_resource_server(resource_server_id):\n    auth0.resource_servers.delete(resource_server_id)\n    print('Resource server deleted')\n```\n\n## Error Handling\n\nThe SDK raises exceptions for API errors that should be handled appropriately.\n\n```python\nfrom auth0.exceptions import Auth0Error\n\ndef safe_get_user(user_id):\n    try:\n        user = auth0.users.get(user_id)\n        return user\n    except Auth0Error as e:\n        print(f\"Auth0 Error: {e}\")\n        print(f\"Status Code: {e.status_code}\")\n        print(f\"Error Code: {e.error_code}\")\n        print(f\"Message: {e.message}\")\n        return None\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n        return None\n```\n\n### Common Error Handling Patterns\n\n```python\ndef handle_user_creation(email, password):\n    try:\n        user = auth0.users.create({\n            'email': email,\n            'password': password,\n            'connection': 'Username-Password-Authentication'\n        })\n        return {'success': True, 'user': user}\n    except Auth0Error as e:\n        if e.status_code == 409:\n            return {'success': False, 'error': 'User already exists'}\n        elif e.status_code == 400:\n            return {'success': False, 'error': 'Invalid request'}\n        elif e.status_code == 429:\n            return {'success': False, 'error': 'Rate limit exceeded'}\n        else:\n            return {'success': False, 'error': str(e)}\n```\n\n## Rate Limiting\n\nHandle rate limits with exponential backoff:\n\n```python\nimport time\n\ndef retry_with_backoff(func, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            return func()\n        except Auth0Error as e:\n            if e.status_code == 429 and attempt < max_retries - 1:\n                wait_time = 2 ** attempt\n                print(f\"Rate limited. Waiting {wait_time} seconds...\")\n                time.sleep(wait_time)\n                continue\n            raise\n\n    raise Exception(\"Max retries exceeded\")\n\n# Usage\nresult = retry_with_backoff(lambda: auth0.users.get(user_id))\n```\n\n## Complete Example: User Registration and Login Flow\n\n```python\nfrom auth0.authentication import Database, GetToken\nfrom auth0.management import Auth0\nimport os\n\n# Configuration\ndomain = os.getenv('AUTH0_DOMAIN')\nclient_id = os.getenv('AUTH0_CLIENT_ID')\nclient_secret = os.getenv('AUTH0_CLIENT_SECRET')\n\n# Initialize clients\ndatabase = Database(domain, client_id)\nget_token = GetToken(domain, client_id, client_secret=client_secret)\n\n# Get Management API token\ntoken = get_token.client_credentials(f'https://{domain}/api/v2/')\nmgmt_api_token = token['access_token']\nauth0 = Auth0(domain, mgmt_api_token)\n\ndef register_and_login(email, password):\n    # 1. Sign up user\n    signup_result = database.signup(\n        email=email,\n        password=password,\n        connection='Username-Password-Authentication'\n    )\n    print(f\"User signed up: {signup_result}\")\n\n    # 2. Get user by email\n    users = auth0.users_by_email.search_users_by_email(email)\n    user = users[0] if users else None\n\n    if not user:\n        raise Exception(\"User not found after signup\")\n\n    print(f\"User ID: {user['user_id']}\")\n\n    # 3. Update user metadata\n    auth0.users.update(user['user_id'], {\n        'user_metadata': {\n            'first_name': 'John',\n            'last_name': 'Doe'\n        }\n    })\n\n    # 4. Send verification email\n    auth0.jobs.send_verification_email({\n        'user_id': user['user_id']\n    })\n    print(\"Verification email sent\")\n\n    # 5. Login user (after email verification)\n    token_response = get_token.login(\n        username=email,\n        password=password,\n        realm='Username-Password-Authentication',\n        scope='openid profile email',\n        audience=f'https://{domain}/api/v2/'\n    )\n\n    print(f\"Access Token: {token_response['access_token']}\")\n    print(f\"ID Token: {token_response.get('id_token')}\")\n\n    return {\n        'user': user,\n        'tokens': token_response\n    }\n\n# Usage\nif __name__ == '__main__':\n    result = register_and_login('john.doe@example.com', 'SecurePassword123!')\n    print(f\"Registration and login complete: {result}\")\n```\n\n## Advanced Patterns\n\n### Batch User Creation\n\n```python\ndef batch_create_users(users_data):\n    created_users = []\n    errors = []\n\n    for user_data in users_data:\n        try:\n            user = auth0.users.create(user_data)\n            created_users.append(user)\n        except Auth0Error as e:\n            errors.append({\n                'email': user_data.get('email'),\n                'error': str(e)\n            })\n\n    return {\n        'created': created_users,\n        'errors': errors\n    }\n```\n\n### User Search with Filters\n\n```python\ndef search_users_advanced(email_domain=None, created_after=None, metadata_filters=None):\n    queries = []\n\n    if email_domain:\n        queries.append(f'email:\"*@{email_domain}\"')\n\n    if created_after:\n        queries.append(f'created_at:[{created_after} TO *]')\n\n    if metadata_filters:\n        for key, value in metadata_filters.items():\n            queries.append(f'user_metadata.{key}:\"{value}\"')\n\n    query = ' AND '.join(queries) if queries else None\n\n    users = auth0.users.list(q=query, search_engine='v3')\n    return users\n```\n\n### Token Management Helper\n\n```python\nclass TokenManager:\n    def __init__(self, domain, client_id, client_secret):\n        self.domain = domain\n        self.client_id = client_id\n        self.client_secret = client_secret\n        self.get_token = GetToken(domain, client_id, client_secret=client_secret)\n        self._token = None\n        self._token_expiry = 0\n\n    def get_management_token(self):\n        import time\n\n        # Check if token is still valid (with 5-minute buffer)\n        if self._token and time.time() < self._token_expiry - 300:\n            return self._token\n\n        # Get new token\n        token_response = self.get_token.client_credentials(\n            f'https://{self.domain}/api/v2/'\n        )\n\n        self._token = token_response['access_token']\n        self._token_expiry = time.time() + token_response.get('expires_in', 86400)\n\n        return self._token\n\n# Usage\ntoken_manager = TokenManager(domain, client_id, client_secret)\nauth0 = Auth0(domain, token_manager.get_management_token())\n```\n\n## Important Notes\n\n### Security Best Practices\n\n1. **Never expose client secrets** - Keep credentials secure on the server side\n2. **Use environment variables** - Store sensitive data in environment variables\n3. **Validate tokens** - Always validate tokens on the server side\n4. **Use HTTPS** - Always use HTTPS in production\n5. **Implement rate limiting** - Protect against brute force attacks\n6. **Rotate credentials** - Regularly rotate API tokens and secrets\n\n### Management API Token Lifecycle\n\n- Management API tokens expire after 24 hours by default\n- Use client credentials grant for long-running applications\n- Cache tokens and refresh before expiration\n- Implement token refresh logic in production applications\n\n### Python Version Support\n\nThe SDK follows Python's official support schedule:\n- Python 3.12: Supported through October 2028\n- Python 3.11: Supported through October 2027\n- Python 3.10: Supported through October 2026\n- Python 3.9: Supported through October 2025\n- Python 3.8: End of life October 2024\n- Python 3.7: End of life October 2023\n\n### User Search Syntax\n\nUse Lucene query syntax for user searches:\n\n```python\n# Search by email domain\nq = 'email:\"*@example.com\"'\n\n# Search by metadata\nq = 'user_metadata.plan:\"premium\"'\n\n# Search by multiple fields\nq = 'email:\"*@example.com\" AND user_metadata.plan:\"premium\"'\n\n# Search by created date\nq = 'created_at:[2024-01-01 TO 2024-12-31]'\n\n# Complex query\nq = '(email:\"*@example.com\" OR email:\"*@test.com\") AND user_metadata.active:true'\n```\n\n### Common Status Codes\n\n| Status Code | Description |\n|-------------|-------------|\n| 200 | Success |\n| 201 | Created |\n| 204 | No Content (Success) |\n| 400 | Bad Request |\n| 401 | Unauthorized |\n| 403 | Forbidden |\n| 404 | Not Found |\n| 409 | Conflict (e.g., user already exists) |\n| 429 | Too Many Requests (Rate Limited) |\n| 500 | Internal Server Error |\n\n## Useful Links\n\n- Official Documentation: https://auth0.com/docs\n- Python SDK Documentation: https://auth0-python.readthedocs.io/\n- GitHub Repository: https://github.com/auth0/auth0-python\n- Example Code: https://github.com/auth0/auth0-python/blob/master/EXAMPLES.md\n- Community Forum: https://community.auth0.com/\n- Auth0 Dashboard: https://manage.auth0.com/\n- API Rate Limits: https://auth0.com/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy\n"
  },
  {
    "path": "content/authlib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Authlib package guide for OAuth 2.0, OpenID Connect, and JOSE integrations in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,authlib,oauth2,openid-connect,jwt,jose,authentication\"\n---\n\n# Authlib Python Package Guide\n\n## What It Does\n\n`authlib` is a Python library for OAuth 1.0, OAuth 2.0, OpenID Connect, and JOSE.\n\nIn application code, the most common entry points are:\n\n- framework OAuth clients for Flask, Django, and Starlette/FastAPI\n- `OAuth2Session` for sync HTTP flows\n- `AsyncOAuth2Client` for async HTTP flows\n- `authlib.jose.jwt` for signing and validating JWTs\n\nUse the framework integrations when your app signs users in with an external identity provider. Use the HTTP client classes for service-to-service OAuth or custom authorization flows. Use the JOSE APIs when your app issues or validates JWTs directly.\n\nThis guide covers `1.6.9`.\n\n## Install\n\nInstall Authlib plus the framework or HTTP client you are actually using:\n\n```bash\npip install authlib==1.6.9\n```\n\nCommon combinations:\n\n```bash\npip install authlib==1.6.9 Flask\npip install authlib==1.6.9 Django\npip install authlib==1.6.9 fastapi starlette\npip install authlib==1.6.9 requests\npip install authlib==1.6.9 httpx\n```\n\n## Shared Setup Rules\n\nFor OAuth and OpenID Connect integrations, keep these inputs outside source control:\n\n```bash\nexport APP_SECRET_KEY=\"replace-me\"\nexport GOOGLE_CLIENT_ID=\"replace-me\"\nexport GOOGLE_CLIENT_SECRET=\"replace-me\"\n```\n\nUse these rules across frameworks:\n\n- Set a session secret before calling `authorize_redirect(...)`; Authlib stores OAuth state and OIDC nonce in the session.\n- Prefer `server_metadata_url` for OpenID Connect providers instead of hard-coding authorization, token, and JWKS endpoints.\n- Keep `client_kwargs={\"scope\": \"openid email profile\"}` when you expect OIDC user identity data.\n- Make the registered redirect URI match your callback route exactly.\n\n## Flask: Sign In With Google\n\nUse the Flask integration when a Flask app needs browser-based sign-in.\n\n```python\nimport os\n\nfrom flask import Flask, redirect, session, url_for\nfrom authlib.integrations.flask_client import OAuth\n\napp = Flask(__name__)\napp.secret_key = os.environ[\"APP_SECRET_KEY\"]\n\noauth = OAuth(app)\noauth.register(\n    name=\"google\",\n    server_metadata_url=\"https://accounts.google.com/.well-known/openid-configuration\",\n    client_id=os.environ[\"GOOGLE_CLIENT_ID\"],\n    client_secret=os.environ[\"GOOGLE_CLIENT_SECRET\"],\n    client_kwargs={\"scope\": \"openid email profile\"},\n)\n\n\n@app.get(\"/login/google\")\ndef login_google():\n    redirect_uri = url_for(\"auth_google\", _external=True)\n    return oauth.google.authorize_redirect(redirect_uri)\n\n\n@app.get(\"/auth/google\")\ndef auth_google():\n    token = oauth.google.authorize_access_token()\n    session[\"user\"] = token[\"userinfo\"]\n    return redirect(\"/\")\n```\n\nIf the provider is plain OAuth 2.0 rather than OpenID Connect, register the client with explicit URLs instead of `server_metadata_url`:\n\n```python\noauth.register(\n    name=\"provider\",\n    client_id=os.environ[\"OAUTH_CLIENT_ID\"],\n    client_secret=os.environ[\"OAUTH_CLIENT_SECRET\"],\n    api_base_url=\"https://provider.example.com/\",\n    authorize_url=\"https://provider.example.com/oauth/authorize\",\n    access_token_url=\"https://provider.example.com/oauth/token\",\n    client_kwargs={\"scope\": \"read write\"},\n)\n```\n\nAfter `authorize_access_token()`, call the provider's user API yourself if there is no OIDC `userinfo` available in the token payload.\n\n## Django: Sign In With Google\n\nUse the Django integration when you want the same browser redirect flow in a Django app.\n\nMake sure Django sessions are enabled with `django.contrib.sessions` and `django.contrib.sessions.middleware.SessionMiddleware`.\n\n```python\n# app/oauth.py\nimport os\n\nfrom authlib.integrations.django_client import OAuth\n\noauth = OAuth()\noauth.register(\n    name=\"google\",\n    server_metadata_url=\"https://accounts.google.com/.well-known/openid-configuration\",\n    client_id=os.environ[\"GOOGLE_CLIENT_ID\"],\n    client_secret=os.environ[\"GOOGLE_CLIENT_SECRET\"],\n    client_kwargs={\"scope\": \"openid email profile\"},\n)\n```\n\n```python\n# app/views.py\nfrom django.shortcuts import redirect\n\nfrom .oauth import oauth\n\n\ndef login_google(request):\n    redirect_uri = request.build_absolute_uri(\"/auth/google\")\n    return oauth.google.authorize_redirect(request, redirect_uri)\n\n\ndef auth_google(request):\n    token = oauth.google.authorize_access_token(request)\n    request.session[\"user\"] = token[\"userinfo\"]\n    return redirect(\"/\")\n```\n\n## FastAPI Or Starlette: Sign In With Google\n\nFastAPI uses Starlette underneath, so use the Starlette Authlib integration.\n\n```python\nimport os\n\nfrom fastapi import FastAPI, Request\nfrom authlib.integrations.starlette_client import OAuth\nfrom starlette.middleware.sessions import SessionMiddleware\nfrom starlette.responses import RedirectResponse\n\napp = FastAPI()\napp.add_middleware(SessionMiddleware, secret_key=os.environ[\"APP_SECRET_KEY\"])\n\noauth = OAuth()\noauth.register(\n    name=\"google\",\n    server_metadata_url=\"https://accounts.google.com/.well-known/openid-configuration\",\n    client_id=os.environ[\"GOOGLE_CLIENT_ID\"],\n    client_secret=os.environ[\"GOOGLE_CLIENT_SECRET\"],\n    client_kwargs={\"scope\": \"openid email profile\"},\n)\n\n\n@app.get(\"/login/google\")\nasync def login_google(request: Request):\n    redirect_uri = request.url_for(\"auth_google\")\n    return await oauth.google.authorize_redirect(request, redirect_uri)\n\n\n@app.get(\"/auth/google\")\nasync def auth_google(request: Request):\n    token = await oauth.google.authorize_access_token(request)\n    request.session[\"user\"] = token[\"userinfo\"]\n    return RedirectResponse(url=\"/\")\n```\n\n## Service-To-Service OAuth 2.0\n\nWhen there is no browser redirect and your app needs a bearer token directly, use `OAuth2Session` or `AsyncOAuth2Client`.\n\n### Sync Client Credentials With `OAuth2Session`\n\n```python\nimport os\n\nfrom authlib.integrations.requests_client import OAuth2Session\n\nclient = OAuth2Session(\n    client_id=os.environ[\"OAUTH_CLIENT_ID\"],\n    client_secret=os.environ[\"OAUTH_CLIENT_SECRET\"],\n    scope=\"read:orders\",\n)\n\ntoken = client.fetch_token(\n    \"https://provider.example.com/oauth/token\",\n    grant_type=\"client_credentials\",\n)\n\nresponse = client.get(\"https://provider.example.com/api/orders\")\nresponse.raise_for_status()\nprint(response.json())\n```\n\n### Async Client Credentials With `AsyncOAuth2Client`\n\n```python\nimport os\nimport asyncio\n\nfrom authlib.integrations.httpx_client import AsyncOAuth2Client\n\n\nasync def main():\n    async with AsyncOAuth2Client(\n        client_id=os.environ[\"OAUTH_CLIENT_ID\"],\n        client_secret=os.environ[\"OAUTH_CLIENT_SECRET\"],\n        scope=\"read:orders\",\n    ) as client:\n        token = await client.fetch_token(\n            \"https://provider.example.com/oauth/token\",\n            grant_type=\"client_credentials\",\n        )\n\n        response = await client.get(\"https://provider.example.com/api/orders\")\n        response.raise_for_status()\n        print(token)\n        print(response.json())\n\n\nasyncio.run(main())\n```\n\nIf the provider requires extra token request parameters such as `audience` or a custom resource indicator, pass them through `fetch_token(...)`.\n\n## Manual Authorization Code Flow Outside A Framework\n\nIf you are not using Flask, Django, or Starlette/FastAPI, `OAuth2Session` gives you the lower-level browser flow.\n\n```python\nimport os\n\nfrom authlib.integrations.requests_client import OAuth2Session\n\nclient = OAuth2Session(\n    client_id=os.environ[\"OAUTH_CLIENT_ID\"],\n    client_secret=os.environ[\"OAUTH_CLIENT_SECRET\"],\n    scope=\"openid profile email\",\n    redirect_uri=\"https://client.example.com/callback\",\n)\n\nauthorization_url, state = client.create_authorization_url(\n    \"https://provider.example.com/oauth/authorize\"\n)\n\nprint(\"Open this URL in a browser:\")\nprint(authorization_url)\n\nauthorization_response = input(\"Paste the full callback URL: \").strip()\n\ntoken = client.fetch_token(\n    \"https://provider.example.com/oauth/token\",\n    authorization_response=authorization_response,\n)\n\nuserinfo_response = client.get(\"https://provider.example.com/userinfo\")\nuserinfo_response.raise_for_status()\n\nprint(state)\nprint(token)\nprint(userinfo_response.json())\n```\n\nFor production web apps, use a framework integration instead of copying this interactive example directly.\n\n## Sign And Validate JWTs\n\nUse `authlib.jose.jwt` when your application issues or verifies JWTs directly.\n\n```python\nimport time\n\nfrom authlib.jose import jwt\n\nheader = {\"alg\": \"HS256\"}\nclaims = {\n    \"iss\": \"https://issuer.example.com\",\n    \"sub\": \"user-123\",\n    \"aud\": \"api://my-service\",\n    \"iat\": int(time.time()),\n    \"exp\": int(time.time()) + 3600,\n}\n\nsecret = \"replace-me-with-a-real-secret\"\n\ntoken = jwt.encode(header, claims, secret)\ndecoded = jwt.decode(token, secret)\ndecoded.validate()\n\nprint(token)\nprint(dict(decoded))\n```\n\nFor asymmetric signing, pass your PEM private key to `jwt.encode(...)` and the corresponding public key to `jwt.decode(...)`.\n\nCall `validate()` after `decode()`. Decoding alone parses the token; validation enforces claims such as expiration and not-before.\n\n## Common Pitfalls\n\n- Missing session configuration causes callback failures because Authlib cannot restore `state` or OIDC nonce.\n- `token[\"userinfo\"]` is an OpenID Connect convenience. For plain OAuth 2.0 providers, fetch the user profile from the provider API yourself.\n- Redirect URI mismatches are provider-side configuration errors, not Authlib bugs.\n- Do not mix sync and async clients. Use `OAuth2Session` in sync code and `AsyncOAuth2Client` in async code.\n- Validate decoded JWT claims with `claims.validate()` before trusting them.\n\n## Quick Reference\n\n- Flask OAuth client: `from authlib.integrations.flask_client import OAuth`\n- Django OAuth client: `from authlib.integrations.django_client import OAuth`\n- Starlette/FastAPI OAuth client: `from authlib.integrations.starlette_client import OAuth`\n- Sync OAuth 2.0 HTTP client: `from authlib.integrations.requests_client import OAuth2Session`\n- Async OAuth 2.0 HTTP client: `from authlib.integrations.httpx_client import AsyncOAuth2Client`\n- JOSE/JWT helpers: `from authlib.jose import jwt`\n"
  },
  {
    "path": "content/autogen/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"AG2 / AutoGen Python package for building LLM agents, multi-agent chats, tools, and code-executing workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.3\"\n  revision: 2\n  updated-on: \"2026-03-17\"\n  source: maintainer\n  tags: \"autogen,ag2,agents,llm,multi-agent,openai,tool-use\"\n---\n\n# AG2 / AutoGen Python Package Guide\n\n## Golden Rule\n\nTreat `autogen` on PyPI as the AG2 project. The package name in your lockfile may be `autogen` or `ag2`, but the import path in current Python examples is still `autogen`. Install the OpenAI extra when you want OpenAI-backed agents, provide model credentials explicitly, and do not enable code execution without understanding where the code will run.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"autogen[openai]==0.11.3\"\n```\n\nEquivalent commands:\n\n```bash\nuv add \"autogen[openai]==0.11.3\"\npoetry add \"autogen[openai]==0.11.3\"\n```\n\nNotes:\n\n- Upstream docs often show `ag2[openai]`. `autogen` and `ag2` are package aliases for the same AG2 project; keep the name already used by the repo you are editing.\n- Since AG2 `0.8`, model-client extras are optional. If you skip `[openai]`, OpenAI model calls will fail until you install the matching extra.\n- If you need Docker-backed code execution, install Docker separately. AG2 does not bundle the Docker runtime.\n\n## Authentication And Model Setup\n\n`LLMConfig` takes a dict with provider-specific fields. AG2 supports multiple providers — install the matching extra for each (e.g., `autogen[openai]`, `autogen[google]`, `autogen[anthropic]`).\n\n```python\nfrom autogen.llm_config import LLMConfig\n\n# OpenAI\nllm_config = LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\", \"api_key\": \"your-api-key\"})\n\n# Google\nllm_config = LLMConfig({\"api_type\": \"google\", \"model\": \"gemini-3.1-flash-lite-preview\"})\n\n# Anthropic\nllm_config = LLMConfig({\"api_type\": \"anthropic\", \"model\": \"claude-sonnet-4-20250514\"})\n```\n\nIf credentials already live in the environment, keep secrets out of source files:\n\n```python\nimport os\nfrom autogen.llm_config import LLMConfig\n\nllm_config = LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]})\n```\n\nSee `references/agents.md` for the full `LLMConfig` reference including `from_json` loading.\n\n## Core Usage\n\nAG2 has two main entry points:\n- **`run()`** — for single-agent and two-agent conversations (see `references/agents.md`)\n- **`run_group_chat()`** — for orchestrating 3+ agents (see `references/group-chat.md`)\n\nBoth return a `RunResponse`. Call `.process()` to execute, then access `.summary`, `.cost`, `.last_speaker`, and `.context_variables`.\n\n### Quick start with a single assistant\n\n`run()` prepares the chat and `process()` executes it:\n\n```python\nfrom autogen import ConversableAgent\nfrom autogen.llm_config import LLMConfig\n\nassistant = ConversableAgent(\n    name=\"assistant\",\n    llm_config=LLMConfig({\"api_type\": \"google\", \"model\": \"gemini-3.1-flash-lite-preview\"}),\n    system_message=\"You are a concise Python coding assistant.\",\n)\n\nchat_result = assistant.run(\n    message=\"Write a Python function that groups strings by first letter.\"\n)\nchat_result.process()\n\nprint(chat_result.summary)\n```\n\n### Add a human proxy or tool-calling peer\n\nUse `UserProxyAgent` when a workflow needs a human checkpoint, tool execution, or code execution policy:\n\n```python\nfrom autogen import ConversableAgent, UserProxyAgent\nfrom autogen.llm_config import LLMConfig\n\nassistant = ConversableAgent(\n    name=\"assistant\",\n    llm_config=LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\", \"api_key\": \"your-api-key\"}),\n)\n\nuser_proxy = UserProxyAgent(\n    name=\"user_proxy\",\n    code_execution_config=False,\n)\n\nresult = user_proxy.run(\n    recipient=assistant,\n    message=\"Summarize the advantages of asyncio for IO-bound work.\",\n)\nresult.process()\n\nprint(result.summary)\n```\n\n### Multi-agent group chat\n\nAG2 is built around agent-to-agent conversations. A minimal planning-and-review flow looks like this:\n\n```python\nfrom autogen import ConversableAgent\nfrom autogen.agentchat import run_group_chat\nfrom autogen.agentchat.group.patterns import AutoPattern\nfrom autogen.llm_config import LLMConfig\n\nllm_config = LLMConfig({\"api_type\": \"google\", \"model\": \"gemini-3.1-flash-lite-preview\"})\n\nplanner = ConversableAgent(name=\"planner\", llm_config=llm_config,\n    description=\"Plans implementation steps and breaks down tasks.\")\ncoder = ConversableAgent(name=\"coder\", llm_config=llm_config,\n    description=\"Writes Python code based on the plan.\")\nreviewer = ConversableAgent(name=\"reviewer\", llm_config=llm_config,\n    description=\"Reviews code and plans for correctness.\")\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],\n    group_manager_args={\"llm_config\": llm_config},\n)\n\nresult = run_group_chat(\n    pattern=pattern,\n    messages=\"Plan a Python CLI that syncs local markdown files to S3.\",\n)\nresult.process()\n```\n\nUse specialized system prompts and smaller agent sets first. Group chats become noisy quickly when every agent has the same role. Set `description` on each agent — the group manager uses descriptions to select the next speaker.\n\n### Tools\n\nRegister tool functions on agents via the `functions` parameter. In group chat, tool execution is automatic. In two-agent `run()`, split registration between LLM and execution agents:\n\n```python\nfrom typing import Annotated\n\ndef search_web(query: Annotated[str, \"The search query\"]) -> str:\n    \"\"\"Search the web and return results.\"\"\"\n    return do_search(query)\n\n# Group chat: just pass functions, execution is automatic\nagent = ConversableAgent(name=\"researcher\", llm_config=llm_config, functions=[search_web])\n\n# Two-agent: split registration (see references/agents.md for details)\n@user_proxy.register_for_execution()\n@assistant.register_for_llm(description=\"Look up a stock price\")\ndef get_stock_price(symbol: Annotated[str, \"The ticker symbol\"]) -> str:\n    return fetch_price(symbol)\n```\n\nSee `references/agents.md` for full tool registration patterns and `references/group-chat.md` for `ReplyResult` (controlling routing from within tools).\n\n## Code Execution\n\nAG2 can execute code through a configured executor. Keep execution disabled unless you explicitly need it:\n\n```python\nfrom autogen import ConversableAgent, UserProxyAgent\nfrom autogen.coding import LocalCommandLineCodeExecutor\nfrom autogen.llm_config import LLMConfig\n\nexecutor = LocalCommandLineCodeExecutor(work_dir=\"coding\")\n\nassistant = ConversableAgent(\n    name=\"assistant\",\n    llm_config=LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\", \"api_key\": \"your-api-key\"}),\n)\n\nuser_proxy = UserProxyAgent(\n    name=\"user_proxy\",\n    code_execution_config={\"executor\": executor},\n)\n\nresult = user_proxy.run(\n    recipient=assistant,\n    message=\"Write and run Python code that prints the first 10 Fibonacci numbers.\",\n)\nresult.process()\n```\n\nNotes:\n\n- `LocalCommandLineCodeExecutor` runs code on the host machine. Treat generated code as untrusted.\n- Prefer Docker-backed execution when you need stronger isolation and the environment supports it.\n- Keep the execution working directory disposable. Do not point it at your repo root.\n\n## Common Pitfalls\n\n- The package slug and the project branding differ. `autogen` on PyPI is AG2, and the docs frequently use `ag2` in install commands.\n- The import path does not change just because the install command uses `ag2`; current examples still import from `autogen`.\n- Missing extras are a common failure mode. Install `[openai]` or the provider extra that matches your model backend.\n- `LLMConfig` takes a dict — do not pass keyword arguments. Use `LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\"})`, not `LLMConfig(api_type=\"openai\", model=\"gpt-4.1-mini\")`.\n- `run()` and `run_group_chat()` return a `RunResponse`; call `.process()` to execute the conversation. Access `.summary`, `.cost`, `.last_speaker` after processing.\n- Code execution is opt-in. `code_execution_config=False` is safer than silently allowing local execution.\n- Older examples on blogs and issue threads may still use pre-0.9 group-chat or Swarm terminology. Prefer the current AG2 docs for orchestration patterns.\n\n## Version-Sensitive Notes\n\n- The version used here `0.11.3` matches the current PyPI release as of March 12, 2026.\n- The docs URL points to the GitHub repo. The canonical maintainer docs for daily use are on `docs.ag2.ai`; use the repo mainly for source, examples, and release history.\n- AG2 `0.8` made provider integrations optional extras, which is why current install commands explicitly include `[openai]`.\n- AG2 `0.9` merged the older Swarm and Group Chat concepts into a unified Group Chat pattern model. If you see Swarm-only examples, treat them as older guidance unless the target codebase is already built around them.\n- The docs root used here is `https://docs.ag2.ai/latest/`, not a version-pinned `0.11.3` snapshot. If an example disagrees with your installed package, check the repo tag or release notes for `v0.11.3` before copying newer APIs.\n\n## Official Sources Used\n\n- PyPI package page: `https://pypi.org/project/autogen/`\n- AG2 install guide: `https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/installing-ag2/`\n- AG2 quick start: `https://docs.ag2.ai/latest/docs/quick-start/`\n- AG2 LLM configuration guide: `https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/llm-configuration/`\n- AG2 LLM configuration deep dive: `https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/llm-configuration-deep-dive/`\n- AG2 OpenAI model guide: `https://docs.ag2.ai/latest/docs/user-guide/models/openai/`\n- AG2 code execution guide: `https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/code-execution/`\n- AG2 repository: `https://github.com/ag2ai/ag2`\n\n## Available References\n\n- `references/agents.md` — Agent classes, `run()`, `run_iter()`, tool registration\n- `references/group-chat.md` — `run_group_chat()`, patterns, handoffs, targets, `ReplyResult`, context variables\n"
  },
  {
    "path": "content/autogen/docs/package/python/references/agents.md",
    "content": "# AG2 Agent API Reference\n\n## LLMConfig\n\nWraps model configuration for any supported provider. Always pass a dict:\n\n```python\nfrom autogen.llm_config import LLMConfig\n\n# OpenAI\nllm_config = LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\", \"api_key\": \"your-api-key\"})\n\n# Google\nllm_config = LLMConfig({\"api_type\": \"google\", \"model\": \"gemini-3.1-flash-lite-preview\"})\n\n# Anthropic\nllm_config = LLMConfig({\"api_type\": \"anthropic\", \"model\": \"claude-sonnet-4-20250514\"})\n```\n\n| Key | Required | Description |\n|---|---|---|\n| `api_type` | Yes | Provider identifier: `\"openai\"`, `\"google\"`, `\"anthropic\"`, etc. |\n| `model` | Yes | Model name as the provider expects it |\n| `api_key` | No | API key; omit if set in environment variables |\n| `base_url` | No | Custom endpoint URL (for proxies or self-hosted models) |\n| `temperature` | No | Sampling temperature |\n| `max_tokens` | No | Maximum tokens in response |\n\n### Loading from JSON file\n\n```python\nllm_config = LLMConfig.from_json(\n    path=\"OAI_CONFIG_LIST\",\n    file_location=\".\",\n    filter_dict={\"model\": [\"gpt-4.1-mini\"]},\n)\n```\n\nUse when a project stores multi-model credentials in an `OAI_CONFIG_LIST` file.\n\n### Using as context manager\n\n```python\nwith LLMConfig({\"api_type\": \"openai\", \"model\": \"gpt-4.1-mini\"}) as config:\n    agent = ConversableAgent(name=\"assistant\", llm_config=config)\n```\n\nNote: Each provider requires its corresponding extra to be installed (e.g., `autogen[openai]`, `autogen[google]`, `autogen[anthropic]`). Without the extra, model calls will fail at runtime.\n\n## ConversableAgent\n\nThe base class for all AG2 agents. Every agent is a `ConversableAgent` or extends one.\n\n### Constructor\n\n```python\nfrom autogen import ConversableAgent\n\nagent = ConversableAgent(\n    name=\"my_agent\",\n    system_message=\"You are a helpful assistant.\",\n    llm_config=llm_config,\n    human_input_mode=\"NEVER\",\n    code_execution_config=False,\n    functions=[my_tool_fn],\n)\n```\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `name` | `str` | required | Unique agent identifier |\n| `system_message` | `str \\| None` | `\"\"` | Role/personality prompt sent to the LLM |\n| `llm_config` | `LLMConfig \\| dict \\| False \\| None` | `None` | LLM configuration; `False` disables LLM |\n| `human_input_mode` | `\"ALWAYS\" \\| \"NEVER\" \\| \"TERMINATE\"` | `\"TERMINATE\"` | When to solicit human input |\n| `code_execution_config` | `dict \\| False` | `False` | Code executor settings; `False` disables |\n| `functions` | `list[Callable]` | `None` | Tool functions the agent can call |\n| `is_termination_msg` | `Callable[[dict], bool] \\| None` | `None` | Predicate to end the conversation |\n| `max_consecutive_auto_reply` | `int \\| None` | `None` | Auto-reply limit before requesting human input |\n| `description` | `str \\| None` | `None` | Description used by group chat manager for speaker selection |\n\n## UserProxyAgent\n\nPre-configured to represent a human or execute code on their behalf. Extends `ConversableAgent`.\n\n```python\nfrom autogen import UserProxyAgent\n\nuser_proxy = UserProxyAgent(\n    name=\"user_proxy\",\n    code_execution_config={\"executor\": executor},\n)\n```\n\nKey defaults that differ from `ConversableAgent`:\n- `human_input_mode=\"ALWAYS\"` — prompts for human input by default\n- `llm_config=False` — no LLM backing\n- `code_execution_config={}` — code execution enabled by default\n\nUse when: you need a human-in-the-loop checkpoint, tool execution relay, or code execution sandbox.\n\n## run()\n\nThe primary method for single-agent and two-agent conversations. For 3+ agents, use `run_group_chat()` (see `references/group-chat.md`). Non-blocking — runs the chat in a background thread and returns a `RunResponse` immediately.\n\n```python\nresult = assistant.run(\n    message=\"Write a function that groups strings by first letter.\",\n    max_turns=3,\n)\nresult.process()  # execute and stream output to console\n\nprint(result.summary)\n```\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `message` | `str \\| dict \\| Callable \\| None` | `None` | Initial message to start the chat |\n| `recipient` | `ConversableAgent \\| None` | `None` | Target agent; `None` enables single-agent mode |\n| `max_turns` | `int \\| None` | `None` | Maximum conversation turns |\n| `user_input` | `bool \\| None` | `False` | Whether to allow user input during execution |\n| `tools` | `Tool \\| Iterable[Tool] \\| None` | `None` | Tools available (single-agent mode only) |\n| `clear_history` | `bool` | `True` | Clear chat history before starting |\n| `silent` | `bool \\| None` | `False` | Suppress console output |\n| `summary_method` | `str \\| Callable \\| None` | `\"last_msg\"` | How to generate the summary (`\"last_msg\"`, `\"reflection_with_llm\"`, or callable) |\n| `msg_to` | `str \\| None` | `\"agent\"` | Direction of initial message: `\"agent\"` or `\"user\"` |\n\n### Single-agent mode\n\nWhen `recipient=None`, `run()` creates a temporary executor agent automatically:\n\n```python\nresult = assistant.run(\n    message=\"Explain Python decorators.\",\n    max_turns=1,\n)\nresult.process()\n```\n\n### Two-agent mode\n\nPass a `recipient` to create a direct conversation between two agents:\n\n```python\nresult = user_proxy.run(\n    recipient=assistant,\n    message=\"Summarize the advantages of asyncio.\",\n    max_turns=4,\n)\nresult.process()\n```\n\n### RunResponse\n\n`run()` returns a `RunResponse`. Call `.process()` to execute, then access results:\n\n```python\nresult = assistant.run(message=\"Explain decorators.\", max_turns=2)\nresult.process()\n\nprint(result.summary)        # conversation summary\nprint(result.cost)           # token usage and cost breakdown\nprint(result.last_speaker)   # name of the last agent that spoke\n```\n\n| Property | Type | Description |\n|---|---|---|\n| `.summary` | `str \\| None` | Conversation summary (controlled by `summary_method`) |\n| `.cost` | `Cost \\| None` | Token usage and cost; `.cost.usage_including_cached_inference` and `.cost.usage_excluding_cached_inference` each have `.total_cost` |\n| `.last_speaker` | `str \\| None` | Name of the last agent that spoke |\n| `.context_variables` | `ContextVariables \\| None` | Shared context state |\n| `.events` | `Iterable[BaseEvent]` | Stream of conversation events |\n| `.messages` | `Iterable[Message]` | Chat messages exchanged |\n\nPass a custom `EventProcessorProtocol` to `.process(processor)` for custom event handling.\n\n## run_iter()\n\nStepped execution — the background thread pauses after each event until you advance. Use for event-driven UIs, custom logging, or streaming integrations.\n\n```python\nfrom autogen.events import TextEvent, TerminationEvent\n\nfor event in assistant.run_iter(\n    message=\"Write a haiku about Python.\",\n    yield_on=[TextEvent, TerminationEvent],\n):\n    if isinstance(event, TextEvent):\n        print(f\"[{event.source}]: {event.content}\")\n    elif isinstance(event, TerminationEvent):\n        print(\"Done.\")\n```\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `yield_on` | `Sequence[type[BaseEvent]] \\| None` | `None` | Event types to yield; `None` yields all |\n\nAll other params match `run()`. Common event types:\n\n| Event | Description |\n|---|---|\n| `TextEvent` | Agent produced text output |\n| `ToolCallEvent` | Agent invoked a tool |\n| `TerminationEvent` | Conversation ended |\n| `InputRequestEvent` | Agent is requesting user input |\n\n## Tool Registration\n\nTool execution works differently depending on whether you use group chat or two-agent chat.\n\n### Group chat: automatic tool execution\n\nIn `run_group_chat()`, tool execution is automatic. Register tools on the agent via `functions` and AG2 handles execution internally through a built-in `_Group_Tool_Executor` agent:\n\n```python\nfrom typing import Annotated\n\ndef search_web(query: Annotated[str, \"The search query\"]) -> str:\n    \"\"\"Search the web and return results.\"\"\"\n    return do_search(query)\n\nresearcher = ConversableAgent(\n    name=\"researcher\",\n    llm_config=llm_config,\n    functions=[search_web],\n    description=\"Researches topics using web search.\",\n)\nwriter = ConversableAgent(name=\"writer\", llm_config=llm_config,\n    description=\"Writes content based on research.\")\neditor = ConversableAgent(name=\"editor\", llm_config=llm_config,\n    description=\"Edits and polishes written content.\")\n\n# In group chat, tool calls are executed automatically\nresult = run_group_chat(\n    pattern=AutoPattern(\n        initial_agent=researcher,\n        agents=[researcher, writer, editor],\n        group_manager_args={\"llm_config\": llm_config},\n    ),\n    messages=\"Research and write about AG2 documentation.\",\n)\nresult.process()\n```\n\n### Two-agent chat: split registration\n\nWith `run()` and two agents, you must explicitly split tool registration — one agent proposes the tool call (LLM), and the other executes it:\n\n```python\nfrom typing import Annotated\nfrom autogen import ConversableAgent, UserProxyAgent\n\nassistant = ConversableAgent(name=\"assistant\", llm_config=llm_config)\nuser_proxy = UserProxyAgent(name=\"user_proxy\", code_execution_config=False)\n\n@user_proxy.register_for_execution()\n@assistant.register_for_llm(description=\"Search the web\")\ndef search_web(query: Annotated[str, \"The search query\"]) -> str:\n    return do_search(query)\n\nresult = user_proxy.run(\n    recipient=assistant,\n    message=\"Search for AG2 documentation.\",\n)\nresult.process()\n```\n\n| Decorator | Purpose |\n|---|---|\n| `@agent.register_for_llm(description=...)` | Makes the tool available in the agent's LLM tool list (agent proposes the call) |\n| `@agent.register_for_execution(name=...)` | Registers the function for actual execution by that agent (agent runs it) |\n\nThe LLM agent decides when to call the tool; the execution agent runs it and returns the result.\n\n### Single-agent mode: inline tools\n\nWhen using `run()` without a recipient, pass tools directly:\n\n```python\nfrom typing import Annotated\n\ndef search_web(query: Annotated[str, \"The search query\"]) -> str:\n    \"\"\"Search the web and return results.\"\"\"\n    return do_search(query)\n\nassistant = ConversableAgent(name=\"assistant\", llm_config=llm_config)\n\nresult = assistant.run(\n    message=\"Search for AG2 documentation.\",\n    tools=[search_web],\n)\nresult.process()\n```\n\n### Defining tool functions\n\nUse `Annotated` types with descriptions on every parameter. The function docstring becomes the tool description the LLM sees:\n\n```python\nfrom typing import Annotated, Any\n\ndef check_payment(\n    vendor: Annotated[str, \"The vendor name\"],\n    amount: Annotated[float, \"The transaction amount\"],\n) -> dict[str, Any]:\n    \"\"\"Check if a payment has been processed.\"\"\"\n    return {\"status\": \"processed\", \"vendor\": vendor}\n```\n\n### Tools with context variables\n\nName a parameter `context_variables: ContextVariables` and AG2 injects the shared context automatically:\n\n```python\nfrom autogen.agentchat.group.context_variables import ContextVariables\n\ndef get_user_name(context_variables: ContextVariables) -> str:\n    \"\"\"Get the current user's name from context.\"\"\"\n    return context_variables.get(\"user_name\", \"Unknown\")\n```\n\n## initiate_chat() (legacy)\n\nBlocking two-agent chat. Suitable for simple synchronous scripts:\n\n```python\nresult = user_proxy.initiate_chat(\n    assistant,\n    message=\"Explain list comprehensions.\",\n    max_turns=3,\n)\nprint(result.summary)\n```\n\nReturns a `ChatResult` with `.chat_history`, `.summary`, `.cost`, `.human_input`.\n\nNote: Prefer `run()` + `.process()` for new code. `run()` supports single-agent mode, event streaming, and the `RunResponse` interface. `initiate_chat()` is retained for backward compatibility.\n"
  },
  {
    "path": "content/autogen/docs/package/python/references/group-chat.md",
    "content": "# AG2 Group Chat API Reference\n\n## run_group_chat()\n\nThe primary function for orchestrating 3+ agents. For single-agent or two-agent conversations, use `run()` (see `references/agents.md`). Non-blocking — runs in a background thread and returns a `RunResponse` immediately.\n\n```python\nfrom autogen import ConversableAgent\nfrom autogen.agentchat import run_group_chat\nfrom autogen.agentchat.group.patterns import AutoPattern\nfrom autogen.llm_config import LLMConfig\n\nllm_config = LLMConfig({\"api_type\": \"google\", \"model\": \"gemini-3.1-flash-lite-preview\"})\n\nplanner = ConversableAgent(name=\"planner\", llm_config=llm_config,\n    description=\"Plans implementation steps and breaks down tasks.\")\nreviewer = ConversableAgent(name=\"reviewer\", llm_config=llm_config,\n    description=\"Reviews work for correctness and quality.\")\ncoder = ConversableAgent(name=\"coder\", llm_config=llm_config,\n    description=\"Writes Python code based on the plan.\")\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, reviewer, coder],\n    group_manager_args={\"llm_config\": llm_config},\n)\n\nresult = run_group_chat(\n    pattern=pattern,\n    messages=\"Design a REST API for a todo app.\",\n    max_rounds=10,\n)\nresult.process()\n\nprint(result.summary)\n```\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `pattern` | `Pattern` | required | Orchestration pattern controlling agent selection |\n| `messages` | `str \\| list[dict]` | required | Initial message(s) to start the group chat |\n| `max_rounds` | `int` | `20` | Maximum conversation rounds before termination |\n\n### RunResponse\n\n`run_group_chat()` returns a `RunResponse`. Call `.process()` to execute, then access results:\n\n```python\nresult = run_group_chat(pattern=pattern, messages=\"Design an API.\")\nresult.process()\n\nprint(result.summary)                          # conversation summary\nprint(result.cost)                             # token usage and cost breakdown\nprint(result.last_speaker)                     # name of the last agent that spoke\nprint(result.context_variables.to_dict())      # final shared state\n```\n\n| Property | Type | Description |\n|---|---|---|\n| `.summary` | `str \\| None` | Conversation summary (controlled by `summary_method`) |\n| `.cost` | `Cost \\| None` | Token usage and cost; `.cost.usage_including_cached_inference` and `.cost.usage_excluding_cached_inference` each have `.total_cost` |\n| `.last_speaker` | `str \\| None` | Name of the last agent that spoke |\n| `.context_variables` | `ContextVariables \\| None` | Final shared state after the conversation |\n| `.events` | `Iterable[BaseEvent]` | Stream of all conversation events |\n| `.messages` | `Iterable[Message]` | Chat messages exchanged |\n\n`run()` returns the same `RunResponse` — see `references/agents.md` for details.\n\n## run_group_chat_iter()\n\nStepped iteration over group chat events. Use for streaming UIs or custom event processing.\n\n```python\nfrom autogen.agentchat import run_group_chat_iter\nfrom autogen.events import TextEvent, TerminationEvent\n\nfor event in run_group_chat_iter(\n    pattern=pattern,\n    messages=\"Plan a deployment strategy.\",\n    max_rounds=15,\n    yield_on=[TextEvent, TerminationEvent],\n):\n    if isinstance(event, TextEvent):\n        print(f\"[{event.source}]: {event.content}\")\n```\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `yield_on` | `Sequence[type[BaseEvent]] \\| None` | `None` | Event types to yield; `None` yields all |\n\nAll other params match `run_group_chat()`. Common event types:\n\n| Event | Description |\n|---|---|\n| `TextEvent` | Agent produced text output |\n| `ToolCallEvent` | Agent invoked a tool |\n| `GroupChatRunChatEvent` | Group chat round completed |\n| `TerminationEvent` | Conversation ended |\n\n## Tool Execution in Group Chat\n\nIn group chat, tool execution is automatic. Register tools on an agent via `functions` and AG2 handles execution internally — no need for a separate executor agent or split registration:\n\n```python\nfrom typing import Annotated\n\ndef lookup_order(order_id: Annotated[str, \"The order ID\"]) -> str:\n    \"\"\"Look up an order by ID.\"\"\"\n    return f\"Order {order_id}: shipped\"\n\nagent = ConversableAgent(\n    name=\"support\",\n    llm_config=llm_config,\n    functions=[lookup_order],\n)\n```\n\nThis differs from two-agent `run()` where you must split registration between an LLM agent and an execution agent. See `references/agents.md` for the two-agent pattern.\n\n## Patterns\n\nPatterns control how agents take turns in a group chat. All patterns share a common base:\n\n| Param | Type | Default | Description |\n|---|---|---|---|\n| `initial_agent` | `ConversableAgent` | required | Agent that speaks first |\n| `agents` | `list[ConversableAgent]` | required | All participating agents |\n| `user_agent` | `ConversableAgent \\| None` | `None` | Human-in-the-loop agent |\n| `group_manager_args` | `dict \\| None` | `None` | Config for the internal group manager (e.g., `llm_config`, `is_termination_msg`) |\n| `context_variables` | `ContextVariables \\| None` | `None` | Shared state across agents |\n| `group_after_work` | `TransitionTarget \\| None` | `TerminateTarget()` | Default action when no handoff triggers |\n| `summary_method` | `str \\| Callable \\| None` | `\"last_msg\"` | How to generate the conversation summary |\n\n### AutoPattern\n\nLLM-based agent selection. The group manager uses its LLM to choose the next speaker based on conversation context. Easiest to start with.\n\nImportant: Set `description` on each agent — the group manager uses agent descriptions to decide who speaks next. Without descriptions, it uses the system_message which can be too verbose.\n\n```python\nfrom autogen.agentchat.group.patterns import AutoPattern\n\nplanner = ConversableAgent(name=\"planner\", llm_config=llm_config,\n    description=\"Plans implementation steps and breaks down tasks.\")\ncoder = ConversableAgent(name=\"coder\", llm_config=llm_config,\n    description=\"Writes Python code based on the plan.\")\nreviewer = ConversableAgent(name=\"reviewer\", llm_config=llm_config,\n    description=\"Reviews code and plans for correctness and quality.\")\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],\n    group_manager_args={\"llm_config\": llm_config},\n)\n```\n\n`group_after_work` is always `GroupManagerTarget` (LLM picks the next agent). Requires an LLM config on the group manager.\n\nUse when: you want the LLM to dynamically route between agents without explicit handoff rules.\n\n### DefaultPattern\n\nExplicit handoff-driven routing. Agents must configure their own transitions via `agent.handoffs`. No automatic next-speaker selection.\n\n```python\nfrom autogen.agentchat.group.patterns import DefaultPattern\nfrom autogen.agentchat.group import OnCondition, AfterWork\n\nplanner.handoffs.add_llm_condition(\n    OnCondition(target=coder, condition=\"The plan is ready to implement.\")\n)\ncoder.handoffs.add_llm_condition(\n    OnCondition(target=reviewer, condition=\"Code is ready for review.\")\n)\nreviewer.handoffs.set_after_work(AfterWork(target=planner))\n\npattern = DefaultPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],\n)\n```\n\nUse when: you need deterministic control over agent transitions.\n\n### RoundRobinPattern\n\nAgents speak in list order, cycling back to the first. No LLM-based selection.\n\n```python\nfrom autogen.agentchat.group.patterns import RoundRobinPattern\n\npattern = RoundRobinPattern(\n    initial_agent=agent_a,\n    agents=[agent_a, agent_b, agent_c],\n)\n```\n\nUse when: every agent must contribute each round in a fixed order.\n\n### RandomPattern\n\nEach turn, a random agent is selected. No LLM-based selection.\n\n```python\nfrom autogen.agentchat.group.patterns import RandomPattern\n\npattern = RandomPattern(\n    initial_agent=agent_a,\n    agents=[agent_a, agent_b, agent_c],\n)\n```\n\nUse when: you want diverse perspectives without ordering bias.\n\n### ManualPattern\n\nPrompts the user to select the next agent each turn.\n\n```python\nfrom autogen.agentchat.group.patterns import ManualPattern\n\npattern = ManualPattern(\n    initial_agent=agent_a,\n    agents=[agent_a, agent_b, agent_c],\n    user_agent=human,\n)\n```\n\nUse when: a human operator needs full control over the conversation flow.\n\n## Handoffs\n\nHandoffs control how agents transition to each other in `DefaultPattern` (or when adding custom transitions in any pattern).\n\n### OnCondition\n\nLLM-evaluated transition. The condition is translated into a tool the LLM can call to trigger the handoff.\n\n```python\nfrom autogen.agentchat.group import OnCondition\n\nplanner.handoffs.add_llm_condition(\n    OnCondition(\n        target=reviewer,\n        condition=\"The plan is complete and ready for review.\",\n    )\n)\n```\n\n| Param | Type | Description |\n|---|---|---|\n| `target` | `TransitionTarget` | Agent or target to hand off to |\n| `condition` | `str` | Natural language condition evaluated by the LLM |\n\n### OnContextCondition\n\nContext variable-based transition. Evaluated without an LLM call — checked before `OnCondition`.\n\n```python\nfrom autogen.agentchat.group import OnContextCondition\n\nplanner.handoffs.add_context_condition(\n    OnContextCondition(\n        target=reviewer,\n        condition=lambda ctx: ctx.get(\"plan_ready\", False),\n    )\n)\n```\n\n### AfterWork\n\nFallback target when no `OnCondition` or `OnContextCondition` triggers.\n\n```python\nfrom autogen.agentchat.group import AfterWork\n\nreviewer.handoffs.set_after_work(AfterWork(target=planner))\n```\n\n### Transition Targets\n\nTargets control where the conversation goes next. Used in `OnCondition`, `AfterWork`, and `ReplyResult`.\n\n| Target | Description |\n|---|---|\n| `AgentTarget(agent)` | Hand off to a specific agent instance |\n| `AgentNameTarget(\"name\")` | Hand off to an agent by name (string) |\n| `RevertToUserTarget()` | Return control to the user agent |\n| `StayTarget()` | Current agent continues speaking |\n| `TerminateTarget()` | End the group chat |\n| `GroupManagerTarget()` | Let the group manager LLM pick the next agent |\n| `RandomAgentTarget(agents)` | Randomly select from a list of agents |\n| `FunctionTarget(fn)` | Call a function to determine the next target dynamically |\n\nAll targets import from `autogen.agentchat.group`.\n\n#### AgentTarget\n\nThe most common target — routes to a specific agent:\n\n```python\nfrom autogen.agentchat.group import AgentTarget, OnCondition\n\nplanner.handoffs.add_llm_condition(\n    OnCondition(target=AgentTarget(coder), condition=\"Plan is ready to implement.\")\n)\n```\n\nYou can also pass an agent instance directly to `target=` in `OnCondition` or `AfterWork` — AG2 wraps it in `AgentTarget` automatically.\n\n#### FunctionTarget\n\nCalls a function at transition time to dynamically decide where to go. The function receives the last message and context variables, and must return a `FunctionTargetResult`:\n\n```python\nfrom autogen.agentchat.group import FunctionTarget, OnCondition\nfrom autogen.agentchat.group.targets.function_target import FunctionTargetResult\n\ndef route_next(output: str, context_variables: ContextVariables) -> FunctionTargetResult:\n    if context_variables.get(\"needs_review\", False):\n        return FunctionTargetResult(target=AgentTarget(reviewer))\n    return FunctionTargetResult(target=AgentTarget(coder))\n\nplanner.handoffs.set_after_work(\n    AfterWork(target=FunctionTarget(route_next))\n)\n```\n\n| `FunctionTargetResult` field | Type | Description |\n|---|---|---|\n| `target` | `TransitionTarget` | Required — the next target to transition to |\n| `messages` | `list \\| str \\| None` | Optional messages to broadcast to specific agents |\n| `context_variables` | `ContextVariables \\| None` | Optional context updates to merge |\n\nUse when: the next agent depends on runtime state that can't be expressed as a static condition.\n\n### Handoffs API\n\nAll methods return `self` for chaining:\n\n```python\nagent.handoffs \\\n    .add_llm_condition(OnCondition(target=other, condition=\"Ready.\")) \\\n    .set_after_work(AfterWork(target=TerminateTarget()))\n```\n\n| Method | Description |\n|---|---|\n| `.add_llm_condition(condition)` | Add an LLM-evaluated transition |\n| `.add_context_condition(condition)` | Add a context variable-based transition |\n| `.set_after_work(target)` | Set unconditional fallback (replaces existing) |\n| `.add_after_work(condition)` | Add conditional fallback |\n| `.add(condition)` | Type-dispatched — adds any condition type |\n| `.add_many(conditions)` | Add multiple conditions at once |\n| `.clear()` | Remove all handoffs |\n\n## ReplyResult\n\nTool functions can return a `ReplyResult` to control both the response message and which agent speaks next. This is the primary way tools influence routing in group chats.\n\n```python\nfrom autogen.agentchat.group.reply_result import ReplyResult\nfrom autogen.agentchat.group import AgentTarget\n\ndef process_order(order_id: Annotated[str, \"The order ID\"],\n                  context_variables: ContextVariables) -> ReplyResult:\n    \"\"\"Process an order and route to the appropriate agent.\"\"\"\n    result = do_processing(order_id)\n    context_variables.set(\"order_status\", result[\"status\"])\n\n    if result[\"status\"] == \"needs_review\":\n        return ReplyResult(\n            message=f\"Order {order_id} needs manual review.\",\n            target=AgentTarget(reviewer),\n            context_variables=context_variables,\n        )\n    return ReplyResult(\n        message=f\"Order {order_id} processed successfully.\",\n        target=AgentTarget(shipping_agent),\n    )\n```\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `message` | `str` | required | The tool's response text (what the LLM sees) |\n| `target` | `TransitionTarget \\| None` | `None` | Which agent to hand off to next |\n| `context_variables` | `ContextVariables \\| None` | `None` | Context updates to merge into the group's shared state |\n\nA `ReplyResult` without a `target` lets the normal handoff/pattern logic decide the next speaker while still updating context variables:\n\n```python\ndef fetch_data(query: Annotated[str, \"The query\"]) -> ReplyResult:\n    \"\"\"Fetch data without influencing routing.\"\"\"\n    result = do_fetch(query)\n    return ReplyResult(message=result)\n```\n\nWhen `target` is set, `ReplyResult` overrides the normal routing. Without `ReplyResult` at all, a tool returns a plain string and the pattern decides the next speaker.\n\nNote: Only the `message` field is visible to the LLM in conversation history. The `target` and `context_variables` are consumed by the orchestration layer silently.\n\n## ContextVariables\n\nDict-like shared state accessible by all agents and tool functions in a group chat.\n\n```python\nfrom autogen.agentchat.group.context_variables import ContextVariables\n\nctx = ContextVariables({\"user_name\": \"Alice\", \"step\": 1})\n\n# Dict-like access\nctx[\"step\"] = 2\nname = ctx.get(\"user_name\", \"Unknown\")\ndel ctx[\"step\"]\n```\n\n| Method | Description |\n|---|---|\n| `.get(key, default)` | Get value with fallback |\n| `.set(key, value)` | Set a value |\n| `.remove(key)` | Remove a key, returns `bool` |\n| `.update(dict)` | Merge another dict |\n| `.contains(key)` | Check existence |\n| `.to_dict()` | Export as plain dict |\n\n### Injecting into tool functions\n\nName a parameter `context_variables: ContextVariables` and AG2 provides it automatically:\n\n```python\ndef update_step(context_variables: ContextVariables) -> str:\n    \"\"\"Advance to the next workflow step.\"\"\"\n    step = context_variables.get(\"step\", 0) + 1\n    context_variables.set(\"step\", step)\n    return f\"Advanced to step {step}\"\n```\n\n### Passing to a pattern\n\n```python\nctx = ContextVariables({\"project\": \"my-app\"})\n\npattern = DefaultPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],\n    context_variables=ctx,\n)\n\nresult = run_group_chat(pattern=pattern, messages=\"Start the project.\")\nresult.process()\n\n# Access final context state\nprint(result.context_variables.to_dict())\n```\n\n## Termination\n\n### is_termination_msg\n\nPass a predicate to `group_manager_args` to stop the chat when a condition is met:\n\n```python\ndef should_terminate(msg: dict) -> bool:\n    content = msg.get(\"content\", \"\") or \"\"\n    return \"DONE\" in content\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, reviewer, coder],  # ensure each agent has a description set\n    group_manager_args={\n        \"llm_config\": llm_config,\n        \"is_termination_msg\": should_terminate,\n    },\n)\n```\n\n### max_rounds\n\nSet `max_rounds` in `run_group_chat()` to cap the number of turns:\n\n```python\nresult = run_group_chat(pattern=pattern, messages=\"Go.\", max_rounds=5)\n```\n\n### Agent-level termination\n\nUse `TerminateTarget()` in handoffs to end the group chat from a specific agent:\n\n```python\nfrom autogen.agentchat.group import AfterWork, TerminateTarget\n\nreviewer.handoffs.set_after_work(AfterWork(target=TerminateTarget()))\n```\n\n## initiate_group_chat() (legacy)\n\nBlocking group chat. Returns a tuple instead of `RunResponse`:\n\n```python\nfrom autogen.agentchat import initiate_group_chat\n\nresult, context_variables, last_agent = initiate_group_chat(\n    pattern=pattern,\n    messages=\"Start planning.\",\n    max_rounds=10,\n)\nprint(result.summary)\n```\n\nReturns `(ChatResult, ContextVariables, Agent)`.\n\nNote: Prefer `run_group_chat()` + `.process()` for new code. It returns a unified `RunResponse` with event streaming support. `initiate_group_chat()` is retained for backward compatibility.\n\n## Common Patterns\n\n### Planning and review loop\n\n```python\nplanner = ConversableAgent(name=\"planner\", llm_config=llm_config,\n    system_message=\"Create detailed implementation plans.\",\n    description=\"Plans implementation steps and breaks down tasks.\")\ncoder = ConversableAgent(name=\"coder\", llm_config=llm_config,\n    system_message=\"Implement the plan in Python.\",\n    description=\"Writes Python code based on the plan.\")\nreviewer = ConversableAgent(name=\"reviewer\", llm_config=llm_config,\n    system_message=\"Review plans and code. Say APPROVED when satisfied.\",\n    description=\"Reviews code and plans for correctness.\")\n\ndef is_approved(msg):\n    return \"APPROVED\" in (msg.get(\"content\", \"\") or \"\")\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],\n    group_manager_args={\"llm_config\": llm_config, \"is_termination_msg\": is_approved},\n)\n\nresult = run_group_chat(pattern=pattern, messages=\"Plan a user auth system.\")\nresult.process()\n```\n\n### Explicit handoff chain\n\n```python\nfrom autogen.agentchat.group import OnCondition, AfterWork, TerminateTarget\nfrom autogen.agentchat.group.patterns import DefaultPattern\n\nresearcher = ConversableAgent(name=\"researcher\", llm_config=llm_config)\nwriter = ConversableAgent(name=\"writer\", llm_config=llm_config)\neditor = ConversableAgent(name=\"editor\", llm_config=llm_config)\n\nresearcher.handoffs.add_llm_condition(\n    OnCondition(target=writer, condition=\"Research is complete.\")\n)\nwriter.handoffs.add_llm_condition(\n    OnCondition(target=editor, condition=\"Draft is written.\")\n)\neditor.handoffs.set_after_work(AfterWork(target=TerminateTarget()))\n\npattern = DefaultPattern(\n    initial_agent=researcher,\n    agents=[researcher, writer, editor],\n)\n\nresult = run_group_chat(pattern=pattern, messages=\"Write about async Python.\")\nresult.process()\n```\n\n### Human-in-the-loop\n\n```python\nfrom autogen import UserProxyAgent\n\nhuman = UserProxyAgent(name=\"human\")\n\npattern = AutoPattern(\n    initial_agent=planner,\n    agents=[planner, coder, reviewer],  # ensure each agent has a description set\n    user_agent=human,\n    group_manager_args={\"llm_config\": llm_config},\n)\n\nresult = run_group_chat(pattern=pattern, messages=\"Build a CLI tool.\")\nresult.process()\n```\n"
  },
  {
    "path": "content/autopep8/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"autopep8 package guide for formatting Python code to PEP 8 with the maintainer's CLI and module API\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"autopep8,python,pep8,formatter,pycodestyle,pre-commit\"\n---\n\n# autopep8 Python Package Guide\n\n## Golden Rule\n\nUse `autopep8` when you specifically want a `pycodestyle`-driven formatter for Python code. It is a formatter, not a linter, and some non-whitespace rewrites only happen when you opt into `--aggressive`.\n\n## Install\n\nPin the version if your project or toolchain expects a specific formatter behavior:\n\n```bash\npython -m pip install \"autopep8==2.3.2\"\n```\n\nUpgrade in place when you want the latest published release:\n\n```bash\npython -m pip install --upgrade autopep8\n```\n\n`autopep8` requires `pycodestyle`; pip will install the dependency for you.\n\n## Initialize And Setup\n\n`autopep8` has no project bootstrap step and no authentication requirements. Setup usually means one of these:\n\n1. Install the package into the environment that will run the formatter.\n2. Add a project config file so repeated runs use the same options.\n3. Optionally wire it into `pre-commit` or your editor.\n\nCheck the installed CLI:\n\n```bash\nautopep8 --version\nautopep8 --help\n```\n\n## Core CLI Usage\n\nPreview changes without modifying files:\n\n```bash\nautopep8 --diff path/to/file.py\n```\n\nRewrite a file in place:\n\n```bash\nautopep8 --in-place path/to/file.py\n```\n\nFormat a tree recursively. `--recursive` must be combined with `--in-place` or `--diff`:\n\n```bash\nautopep8 --recursive --in-place src/\n```\n\nRead from stdin by passing `-` as the file:\n\n```bash\ncat bad.py | autopep8 -\n```\n\nLimit fixes to specific codes:\n\n```bash\nautopep8 --select=E1,W1 --in-place path/to/file.py\n```\n\nRestrict formatting to a line range:\n\n```bash\nautopep8 --line-range 1 120 --in-place path/to/file.py\n```\n\nList fix codes supported by the tool:\n\n```bash\nautopep8 --list-fixes\n```\n\n## Aggressive And Experimental Modes\n\nBy default, `autopep8` only makes whitespace-safe changes. Important consequences from the maintainer docs:\n\n- `E711` and `E712` are not fixed unless you pass `--aggressive`\n- `E712` needs aggressiveness level 2, so pass `--aggressive --aggressive`\n- deprecated-code `W6` fixes also require aggressive mode\n- `--experimental` enables additional line-shortening behavior\n\nTypical aggressive run:\n\n```bash\nautopep8 --in-place --aggressive --aggressive path/to/file.py\n```\n\nUse aggressive mode carefully on code with overloaded equality or code where boolean-comparison rewrites could be semantically sensitive.\n\n## Use As A Module\n\nThe simplest programmatic API is `fix_code()`:\n\n```python\nimport autopep8\n\nfixed = autopep8.fix_code(\"x=       123\\n\")\nprint(fixed)\n```\n\nPass options when you need behavior closer to the CLI:\n\n```python\nimport autopep8\n\nfixed = autopep8.fix_code(\n    \"print( 123 )\\n\",\n    options={\"ignore\": [\"E\"]},\n)\nprint(fixed)\n```\n\nThis is useful when you want formatting inside another Python tool instead of shelling out to the CLI.\n\n## Configuration\n\n`autopep8` can read configuration from several places:\n\n- global config: `$HOME/.config/pycodestyle` on Unix-like systems\n- local project config: `setup.cfg`, `tox.ini`, `.pep8`, `.flake8`\n- `pyproject.toml`\n\nSupported INI sections are `pep8`, `pycodestyle`, and `flake8`.\n\nIf you use `pyproject.toml`, the section must be `[tool.autopep8]`, and the maintainer docs state that `pyproject.toml` takes precedence over the other config files.\n\nExample:\n\n```toml\n[tool.autopep8]\nmax_line_length = 100\nignore = [\"E501\"]\nin-place = true\nrecursive = true\naggressive = 2\n```\n\nYou can also point the CLI at a specific global config file:\n\n```bash\nautopep8 --global-config /path/to/pep8.ini --in-place app.py\n```\n\n## pre-commit Integration\n\nThe maintainer repo publishes a `pre-commit` hook:\n\n```yaml\nrepos:\n  - repo: https://github.com/hhatto/autopep8\n    rev: v2.3.2\n    hooks:\n      - id: autopep8\n```\n\nAfter adding it to `.pre-commit-config.yaml`, run:\n\n```bash\npre-commit run --all-files\n```\n\nPin `rev` to the formatter version you want reviewed and reproduced in CI.\n\n## Common Pitfalls\n\n- `autopep8` is not the same tool as `black`, `ruff format`, or `yapf`. Do not assume those tools' defaults or style rules apply here.\n- `--recursive` does nothing useful on its own; pair it with `--in-place` or `--diff`.\n- Default behavior is conservative. If a rewrite did not happen, check whether it needs `--aggressive`.\n- The tool uses `pycodestyle` findings as its basis, so config choices like `max_line_length`, `ignore`, and `select` materially change what gets rewritten.\n- `pyproject.toml` wins over `setup.cfg`, `tox.ini`, `.pep8`, and `.flake8`. Conflicting config files are a common source of surprise.\n- `# autopep8: off` / `# autopep8: on` and `# fmt: off` / `# fmt: on` can disable formatting for sections that should not be touched.\n- If you need CI to fail when formatting would change files, use `--diff --exit-code` and treat exit code `2` as \"differences found\".\n- If an older environment raises `pkg_resources.DistributionNotFound`, the maintainer docs recommend upgrading `setuptools`.\n\n## Version-Sensitive Notes For 2.3.2\n\n- The version used here `2.3.2` matches the current PyPI release page for `autopep8` as of March 12, 2026.\n- PyPI lists `Requires: Python >=3.9`, so do not plan new usage around Python 3.8 or older.\n- The official maintainer documentation is the repository README rendered on GitHub and mirrored on PyPI, not a separate docs site.\n- The project supports `pyproject.toml` configuration, and that precedence rule is important when migrating older repos from `setup.cfg` or `.flake8`.\n"
  },
  {
    "path": "content/av/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyAV Python bindings for FFmpeg for decoding, encoding, remuxing, and frame conversion\"\nmetadata:\n  languages: \"python\"\n  versions: \"16.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyav,av,ffmpeg,video,audio,media,encoding,decoding\"\n---\n\n# PyAV Python Package Guide\n\n## Golden Rule\n\nUse `av` as Python bindings around FFmpeg, and treat the current PyAV docs root as `https://pyav.basswood-io.com/docs/stable/`. The docs URL `https://pyav.org/docs/stable/` is still live, but on 2026-03-12 it serves older `9.0.2` docs and should not be used as the canonical source for `16.1.0`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"av==16.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"av==16.1.0\"\npoetry add \"av==16.1.0\"\n```\n\nFor frame conversion helpers you will often also want:\n\n```bash\npython -m pip install \"numpy\" \"pillow\"\n```\n\nSource-build notes:\n\n- PyAV `16.1.0` supports Python `3.10` through `3.13`.\n- Building from source requires FFmpeg `7.0` or newer plus development headers and `pkg-config`.\n- Prefer prebuilt wheels unless you need a custom FFmpeg build or a platform without wheels.\n\n## Initialization And Environment\n\nPyAV has no package-level authentication model. It opens local files, Python file-like objects, or media/network URLs through FFmpeg.\n\nThe core entry point is `av.open(...)`:\n\n```python\nimport av\n\ncontainer = av.open(\"input.mp4\")\ncontainer.close()\n```\n\nUse a context manager so containers always close cleanly:\n\n```python\nimport av\n\nwith av.open(\"input.mp4\") as container:\n    print(container.format.name)\n    print(container.streams.video)\n```\n\nUseful `av.open(...)` controls:\n\n- `mode=\"r\"` or `\"w\"` when the input is not obvious\n- `format=\"mp4\"` or another container name when FFmpeg cannot infer it\n- `options={...}` for demuxer/protocol settings\n- `container_options={...}` and `stream_options=[...]` for finer-grained FFmpeg control\n- `timeout=` as a float or `(open_timeout, read_timeout)` tuple for network inputs\n- `buffer_size=` when wrapping a Python file-like object\n\nExample for a network stream:\n\n```python\nimport av\n\nwith av.open(\n    \"rtsp://example.invalid/live\",\n    options={\"rtsp_transport\": \"tcp\"},\n    timeout=(5.0, 30.0),\n) as container:\n    for frame in container.decode(video=0):\n        print(frame.pts)\n        break\n```\n\nIf you pass a Python file object, open it in binary mode:\n\n```python\nimport av\n\nwith open(\"input.mp4\", \"rb\") as fh, av.open(fh, mode=\"r\") as container:\n    frame = next(container.decode(video=0))\n    print(frame)\n```\n\n## Core Usage\n\n### Decode frames from a video stream\n\n```python\nimport av\n\nwith av.open(\"input.mp4\") as container:\n    video_stream = container.streams.video[0]\n\n    for frame in container.decode(video_stream):\n        print(\n            \"pts=\", frame.pts,\n            \"time_base=\", frame.time_base,\n            \"size=\", (frame.width, frame.height),\n        )\n```\n\n`container.decode(...)` yields decoded `VideoFrame` or `AudioFrame` objects. Use `container.streams.video[0]` or `container.streams.audio[0]` rather than assuming the first stream is the right type.\n\n### Convert video frames to NumPy arrays\n\n```python\nimport av\n\nwith av.open(\"input.mp4\") as container:\n    frame = next(container.decode(video=0))\n    rgb = frame.to_ndarray(format=\"rgb24\")\n    print(rgb.shape)\n```\n\n`VideoFrame.to_ndarray(...)` is the most direct way to hand frames to NumPy/OpenCV-style code. Choose the pixel format explicitly when downstream code expects RGB rather than FFmpeg-native YUV layouts.\n\n### Create frames from NumPy and encode a video\n\n```python\nimport av\nimport numpy as np\n\nwidth = 640\nheight = 360\n\nwith av.open(\"output.mp4\", mode=\"w\") as container:\n    stream = container.add_stream(\"libx264\", rate=30)\n    stream.width = width\n    stream.height = height\n    stream.pix_fmt = \"yuv420p\"\n\n    for i in range(60):\n        rgb = np.zeros((height, width, 3), dtype=np.uint8)\n        rgb[:, :, 0] = (i * 4) % 255\n        frame = av.VideoFrame.from_ndarray(rgb, format=\"rgb24\")\n\n        for packet in stream.encode(frame):\n            container.mux(packet)\n\n    for packet in stream.encode(None):\n        container.mux(packet)\n```\n\nTwo rules matter here:\n\n- Set codec properties such as `width`, `height`, and `pix_fmt` before encoding.\n- Flush the encoder with `stream.encode(None)` or the file may be truncated.\n\n### Remux packets without re-encoding\n\nUse remuxing when you want a new container but the encoded media should stay unchanged:\n\n```python\nimport av\n\nwith av.open(\"input.mp4\") as input_container, av.open(\"output.mkv\", mode=\"w\") as output_container:\n    in_video = input_container.streams.video[0]\n    out_video = output_container.add_stream_from_template(in_video)\n\n    for packet in input_container.demux(in_video):\n        if packet.dts is None:\n            continue\n\n        packet.stream = out_video\n        output_container.mux(packet)\n```\n\n`add_stream_from_template(...)` preserves codec parameters from the input stream. For remuxing, do not decode frames and do not invent new timestamps unless you really intend to re-encode.\n\n### Work with audio streams\n\n```python\nimport av\n\nwith av.open(\"input.mp4\") as container:\n    audio_stream = container.streams.audio[0]\n\n    for frame in container.decode(audio_stream):\n        print(frame.samples, frame.sample_rate, frame.layout.name)\n        break\n```\n\nPyAV also exposes audio resampling and FIFO helpers, but simple decode/read flows start exactly like video: select the correct stream, decode frames, and inspect sample metadata before transforming anything.\n\n## Configuration Notes\n\n- There is no separate credential object. For HTTP, RTSP, S3-compatible gateways, and similar inputs, credentials typically live in the URL or in FFmpeg/protocol options passed to `av.open(...)`.\n- `options={...}` is the first place to put protocol knobs such as transport choice, reconnect flags, codec hints, or demuxer-specific options.\n- Use `timeout=` for network sources; otherwise a bad remote source can block longer than your application expects.\n- PyAV does not replace FFmpeg concepts. Container format, codec name, pixel format, sample format, and timestamps still matter and often must be set explicitly.\n\n## Errors And Debugging\n\nPyAV raises FFmpeg-backed exceptions such as `av.FFmpegError` and more specific subclasses like `av.DecoderNotFoundError`.\n\n```python\nimport av\n\ntry:\n    with av.open(\"missing.mp4\") as container:\n        next(container.decode(video=0))\nexcept av.FFmpegError as exc:\n    print(type(exc).__name__)\n    print(exc)\n```\n\nDuring local debugging you can enable FFmpeg logging:\n\n```python\nimport av\n\nav.logging.set_level(av.logging.VERBOSE)\n```\n\nDo not leave verbose logging on by default in threaded or embedded interpreter environments. The upstream caveats page warns that FFmpeg logging can interact badly with Python sub-interpreters and has caused lockups in Cython shutdown paths.\n\n## Common Pitfalls\n\n- Always close containers. Use `with av.open(...) as container:` instead of relying on garbage collection.\n- Do not confuse remuxing with transcoding. `demux` plus `mux` keeps encoded packets; `decode` plus `encode` produces new media.\n- When remuxing, skip packets with `packet.dts is None`; the upstream cookbook example does this because flush packets are not valid for muxing.\n- Be explicit about stream selection. Containers can have multiple video, audio, subtitle, or data streams.\n- Frame timing is not seconds by default. `frame.pts` and `packet.pts` are expressed in units of `time_base`.\n- If colors look wrong after conversion, check `pix_fmt` and the array format you requested from `to_ndarray(...)` or `from_ndarray(...)`.\n- If installation falls back to a source build and fails, you are usually missing FFmpeg development libraries or `pkg-config`.\n- Older PyAV blog posts and the old `pyav.org` docs can be materially stale. Validate examples against the current `basswood-io.com` docs and the `16.1.0` changelog.\n\n## Time And Timestamps\n\nPyAV follows FFmpeg timing rules:\n\n- `Packet.pts` / `Packet.dts` are in the stream time base\n- `Frame.pts` is in the frame time base\n- `time_base` is the unit conversion factor, not a frame rate\n\nPractical rule: do not fabricate timestamps unless you understand the target codec and container. When reusing an existing stream template, preserve upstream timing. When encoding new content, make the stream rate and frame cadence consistent from the start.\n\n## Version-Sensitive Notes For 16.1.0\n\n- PyPI and the current maintained docs both reflect `16.1.0` as of 2026-03-12.\n- The maintained docs root is `https://pyav.basswood-io.com/docs/stable/`; the docs URL `https://pyav.org/docs/stable/` currently serves old `9.0.2` documentation and should be treated as stale.\n- PyAV `16.x` supports Python `3.10+` and source builds against FFmpeg `7.0+`.\n- The `16.1.0` changelog adds more modern media support, including AMD AMF hardware decoding, AV1/H.264 multiview decoding, `CodecContext.colorspace`, and alpha-aware `libx264rgb` encoding. If you are copying older examples, check whether they predate these capabilities.\n\n## Official Links\n\n- Docs root: `https://pyav.basswood-io.com/docs/stable/`\n- Installation: `https://pyav.basswood-io.com/docs/stable/overview/installation.html`\n- Basics cookbook: `https://pyav.basswood-io.com/docs/stable/cookbook/basics.html`\n- Timing guide: `https://pyav.basswood-io.com/docs/stable/api/time.html`\n- API reference: `https://pyav.basswood-io.com/docs/stable/api/_globals.html`\n- Changelog: `https://github.com/PyAV-Org/PyAV/blob/main/CHANGELOG.rst`\n- PyPI: `https://pypi.org/project/av/`\n"
  },
  {
    "path": "content/aws/docs/acm/javascript/DOC.md",
    "content": "---\nname: acm\ndescription: \"AWS SDK for JavaScript v3 ACM client for requesting, importing, listing, and managing TLS certificates.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,acm,javascript,nodejs,tls,certificates,ssl\"\n---\n\n# `@aws-sdk/client-acm`\n\nUse this package for AWS Certificate Manager in AWS SDK for JavaScript v3. It covers certificate lifecycle tasks such as requesting public certificates, reading validation details, importing existing PEM certificates, listing certificates, tagging, and deleting certificates.\n\nPrefer `ACMClient` plus explicit command imports for new code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-acm\n```\n\nIf you need explicit profile, SSO, or assume-role credential providers in application code, install the credential helpers you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nACM is regional. Create the client in the same AWS region where the certificate exists or should be created.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\"\n```\n\nOr with direct credentials:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nIn Node.js, the default AWS SDK credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n\nACM administration belongs on trusted backend or automation code, not untrusted browser clients.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { ACMClient } from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit profile-based credentials\n\n```javascript\nimport { ACMClient } from \"@aws-sdk/client-acm\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst acm = new ACMClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ACMClient,\n  DescribeCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nconst response = await acm.send(\n  new DescribeCertificateCommand({\n    CertificateArn:\n      \"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012\",\n  }),\n);\n\nconsole.log(response.Certificate?.Status);\n```\n\n## Common Workflows\n\n### Request a public certificate with DNS validation\n\n`RequestCertificateCommand` returns the certificate ARN. Use `DescribeCertificateCommand` to read the DNS validation record that must be published.\n\n```javascript\nimport {\n  ACMClient,\n  DescribeCertificateCommand,\n  RequestCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nconst request = await acm.send(\n  new RequestCertificateCommand({\n    DomainName: \"api.example.com\",\n    SubjectAlternativeNames: [\"www.example.com\"],\n    ValidationMethod: \"DNS\",\n    IdempotencyToken: \"api-example-com\",\n    Tags: [{ Key: \"service\", Value: \"edge-api\" }],\n  }),\n);\n\nconst certificateArn = request.CertificateArn;\n\nif (!certificateArn) {\n  throw new Error(\"RequestCertificate did not return a certificate ARN\");\n}\n\nconst details = await acm.send(\n  new DescribeCertificateCommand({\n    CertificateArn: certificateArn,\n  }),\n);\n\nfor (const option of details.Certificate?.DomainValidationOptions ?? []) {\n  const record = option.ResourceRecord;\n\n  if (record) {\n    console.log({\n      domain: option.DomainName,\n      name: record.Name,\n      type: record.Type,\n      value: record.Value,\n    });\n  }\n}\n```\n\nIf you choose email validation instead, ACM also exposes `ResendValidationEmailCommand` for retrying the validation email flow.\n\n### Wait for validation to complete\n\nThe generated ACM waiter polls `DescribeCertificate` until every domain validation status becomes `SUCCESS`, or fails if the certificate status becomes `FAILED`.\n\n```javascript\nimport {\n  ACMClient,\n  waitUntilCertificateValidated,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nawait waitUntilCertificateValidated(\n  { client: acm, maxWaitTime: 30 * 60 },\n  {\n    CertificateArn:\n      \"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012\",\n  },\n);\n```\n\n### List certificates with the paginator\n\nACM exposes one paginator for `ListCertificates`. Use it when you need to scan more than one page.\n\n```javascript\nimport {\n  ACMClient,\n  paginateListCertificates,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListCertificates(\n  { client: acm },\n  {\n    CertificateStatuses: [\"ISSUED\", \"PENDING_VALIDATION\"],\n  },\n)) {\n  for (const cert of page.CertificateSummaryList ?? []) {\n    console.log(cert.CertificateArn, cert.DomainName, cert.Status);\n  }\n}\n```\n\n### Read the issued certificate body and chain\n\n`GetCertificateCommand` returns the certificate PEM and certificate chain PEM. It does not return the private key.\n\n```javascript\nimport {\n  ACMClient,\n  GetCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nconst response = await acm.send(\n  new GetCertificateCommand({\n    CertificateArn:\n      \"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012\",\n  }),\n);\n\nconsole.log(response.Certificate);\nconsole.log(response.CertificateChain);\n```\n\n### Import an existing PEM certificate\n\nUse `ImportCertificateCommand` when you already have the certificate PEM and private key PEM. In Node.js, `readFileSync()` returns `Buffer`, which is accepted for ACM blob inputs.\n\n```javascript\nimport { readFileSync } from \"node:fs\";\nimport {\n  ACMClient,\n  ImportCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nconst response = await acm.send(\n  new ImportCertificateCommand({\n    Certificate: readFileSync(\"./tls/certificate.pem\"),\n    PrivateKey: readFileSync(\"./tls/private-key.pem\"),\n    CertificateChain: readFileSync(\"./tls/certificate-chain.pem\"),\n    Tags: [{ Key: \"environment\", Value: \"production\" }],\n  }),\n);\n\nconsole.log(response.CertificateArn);\n```\n\nKeep the private key on trusted infrastructure only, and never commit it to source control.\n\n### Add and remove tags\n\n```javascript\nimport {\n  ACMClient,\n  AddTagsToCertificateCommand,\n  RemoveTagsFromCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\nconst certificateArn =\n  \"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012\";\n\nawait acm.send(\n  new AddTagsToCertificateCommand({\n    CertificateArn: certificateArn,\n    Tags: [\n      { Key: \"service\", Value: \"payments\" },\n      { Key: \"owner\", Value: \"platform\" },\n    ],\n  }),\n);\n\nawait acm.send(\n  new RemoveTagsFromCertificateCommand({\n    CertificateArn: certificateArn,\n    Tags: [{ Key: \"owner\" }],\n  }),\n);\n```\n\n### Delete a certificate you no longer use\n\n```javascript\nimport {\n  ACMClient,\n  DeleteCertificateCommand,\n} from \"@aws-sdk/client-acm\";\n\nconst acm = new ACMClient({ region: \"us-east-1\" });\n\nawait acm.send(\n  new DeleteCertificateCommand({\n    CertificateArn:\n      \"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012\",\n  }),\n);\n```\n\nIf AWS still reports the certificate as in use, detach it from the dependent service first and retry.\n\n## Common Pitfalls\n\n- `RequestCertificateCommand` does not include the DNS validation record in its response. Call `DescribeCertificateCommand` and read `Certificate.DomainValidationOptions[].ResourceRecord`.\n- ACM is regional. Listing or describing a certificate in the wrong region will not find the ARN you expect.\n- `GetCertificateCommand` returns the certificate body and chain, not the private key.\n- `ImportCertificateCommand` requires certificate PEM bytes and private key bytes. In Node.js, pass `Buffer` values such as `readFileSync()` results.\n- `DeleteCertificateCommand` can fail with `ResourceInUseException` while the certificate is still attached elsewhere.\n- If you use `ExportCertificateCommand`, pass `Passphrase` as bytes and expect it to work only for certificates with export enabled.\n\n## Related Packages\n\n- `@aws-sdk/credential-providers`: explicit profile, SSO, Cognito, and assume-role credential flows.\n- `@aws-sdk/client-route-53`: automate DNS validation record creation when you manage DNS in Route 53.\n- `@aws-sdk/client-elastic-load-balancing-v2`: attach ACM certificates to Application Load Balancer or Network Load Balancer listeners.\n- `@aws-sdk/client-cloudfront`: reference ACM certificates from CloudFront distributions.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-acm` version `3.1007.0`.\n- The current ACM API model exposes one paginator for `ListCertificates` and one waiter for certificate validation, which maps to `paginateListCertificates` and `waitUntilCertificateValidated` in AWS SDK for JavaScript v3.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 ACM client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/acm/`\n- AWS Certificate Manager API Reference: `https://docs.aws.amazon.com/acm/latest/APIReference/Welcome.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-acm`\n"
  },
  {
    "path": "content/aws/docs/aiobotocore/python/DOC.md",
    "content": "---\nname: aiobotocore\ndescription: \"aiobotocore package guide for async AWS clients with botocore-compatible APIs, aiohttp transport, and AioConfig\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aiobotocore,aws,botocore,aiohttp,asyncio,python,sdk\"\n---\n\n# aiobotocore Python Package Guide\n\n## What It Is\n\n`aiobotocore` is the aio-libs asynchronous wrapper around `botocore`. You keep botocore-style AWS service names, method names, and request kwargs, but run them under `asyncio`, create clients with async context managers, and `await` service operations.\n\nIf you already know the `boto3` or `botocore` client model, the practical translation is usually:\n\n- create the same service client\n- call the same operation names\n- `await` the calls\n- close clients and streaming response bodies correctly\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `3.2.1`.\n- On March 12, 2026, the current stable docs and the current PyPI release are both `3.2.1`.\n- `3.2.1` widened the supported `botocore` window to `>=1.42.53,<1.42.62`. Do not upgrade `botocore` independently past that range.\n- Since `3.0.0`, `aiobotocore` forbids leaving a loose underlying `ClientSession` around after an `AioBaseClient` exits. Keep client lifetime inside `async with` or manage it with `AsyncExitStack`.\n- Since `3.0.0`, the old package extras `aiobotocore[awscli]` and `aiobotocore[boto3]` are gone. Install `awscli` or `boto3` separately alongside `aiobotocore` if you need them.\n- Since `2.23.0`, an optional `httpx` backend exists, but upstream still describes it as experimental and not fully feature-parity with `aiohttp`.\n- Since `3.1.0`, `AioConfig.connector_args` can include `socket_factory`.\n\n## Install\n\nPin the package if you need reproducible behavior:\n\n```bash\npython -m pip install \"aiobotocore==3.2.1\"\n```\n\nIf you want to try the optional `httpx` transport:\n\n```bash\npython -m pip install \"aiobotocore[httpx]==3.2.1\"\n```\n\nIf you also need `boto3` or `awscli`, install them separately:\n\n```bash\npython -m pip install \"aiobotocore==3.2.1\" \"boto3\"\npython -m pip install \"aiobotocore==3.2.1\" \"awscli\"\n```\n\n## Initialize A Session\n\nUse `get_session()` for the common case. Create service clients with `async with` so sockets and credential-refresh resources close deterministically.\n\n```python\nimport asyncio\n\nfrom aiobotocore.session import get_session\n\nasync def main() -> None:\n    session = get_session()\n\n    async with session.create_client(\"sts\", region_name=\"us-east-1\") as sts:\n        identity = await sts.get_caller_identity()\n        print(identity[\"Account\"])\n        print(identity[\"Arn\"])\n\nasyncio.run(main())\n```\n\n## Credentials And Region Configuration\n\n`aiobotocore` uses botocore-compatible credential and region behavior. In practice, prefer the same AWS setup you would use for `botocore` or `boto3`:\n\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_DEFAULT_REGION`\n- `AWS_PROFILE`\n- shared config in `~/.aws/config` and `~/.aws/credentials`\n- IAM roles in deployed AWS environments\n\nFor local development, letting botocore resolve a profile is usually cleaner than hardcoding credentials:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n```python\nfrom aiobotocore.session import get_session\n\nsession = get_session()\n\nasync def list_queues() -> None:\n    async with session.create_client(\"sqs\") as sqs:\n        response = await sqs.list_queues()\n        print(response.get(\"QueueUrls\", []))\n```\n\nIf you already have short-lived credentials from STS or another bootstrap step, pass them directly to `create_client(...)`:\n\n```python\nfrom aiobotocore.session import get_session\n\nsession = get_session()\n\nasync def head_bucket() -> None:\n    async with session.create_client(\n        \"s3\",\n        region_name=\"us-west-2\",\n        aws_access_key_id=\"...\",\n        aws_secret_access_key=\"...\",\n        aws_session_token=\"...\",\n    ) as s3:\n        await s3.head_bucket(Bucket=\"my-bucket\")\n```\n\n## Core Usage Patterns\n\n### Use Botocore-Style Operation Names\n\nAWS operations map to async client methods with the same keyword arguments you would use in botocore-style code.\n\n```python\nimport asyncio\n\nfrom aiobotocore.session import get_session\n\nasync def main() -> None:\n    session = get_session()\n\n    async with session.create_client(\"s3\", region_name=\"us-west-2\") as s3:\n        await s3.put_object(Bucket=\"my-bucket\", Key=\"demo.txt\", Body=b\"hello\")\n\n        response = await s3.get_object(Bucket=\"my-bucket\", Key=\"demo.txt\")\n        async with response[\"Body\"] as stream:\n            body = await stream.read()\n            print(body)\n\nasyncio.run(main())\n```\n\n### Always Consume Or Close Streaming Bodies\n\nThe upstream examples explicitly wrap `response[\"Body\"]` in `async with` so the underlying connection can be reused. If you forget this, you can leak connections and reduce throughput under load.\n\n```python\nresponse = await s3.get_object(Bucket=\"my-bucket\", Key=\"demo.txt\")\nasync with response[\"Body\"] as stream:\n    payload = await stream.read()\n```\n\n### Use Async Paginators\n\nPaginators are async iterables:\n\n```python\nfrom aiobotocore.session import get_session\n\nasync def list_keys(bucket: str, prefix: str) -> None:\n    session = get_session()\n\n    async with session.create_client(\"s3\", region_name=\"us-west-2\") as s3:\n        paginator = s3.get_paginator(\"list_objects_v2\")\n        async for page in paginator.paginate(Bucket=bucket, Prefix=prefix):\n            for item in page.get(\"Contents\", []):\n                print(item[\"Key\"])\n```\n\n### Manage Long-Lived Clients With `AsyncExitStack`\n\nFor application components that need a client for a longer scope, keep cleanup explicit:\n\n```python\nfrom contextlib import AsyncExitStack\n\nfrom aiobotocore.session import AioSession\n\nclass AwsManager:\n    def __init__(self) -> None:\n        self._exit_stack = AsyncExitStack()\n        self.s3 = None\n\n    async def __aenter__(self):\n        session = AioSession()\n        self.s3 = await self._exit_stack.enter_async_context(\n            session.create_client(\"s3\", region_name=\"us-west-2\")\n        )\n        return self\n\n    async def __aexit__(self, exc_type, exc, tb) -> None:\n        await self._exit_stack.__aexit__(exc_type, exc, tb)\n```\n\n## `AioConfig` And Transport Configuration\n\nUse `AioConfig` when you need retry configuration, connection-pool sizing, or async transport-specific options.\n\n```python\nfrom aiobotocore.config import AioConfig\nfrom aiobotocore.session import get_session\n\nconfig = AioConfig(\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n    connect_timeout=5,\n    read_timeout=60,\n    max_pool_connections=50,\n    connector_args={\"ttl_dns_cache\": 60},\n)\n\nsession = get_session()\n\nasync def list_tables() -> None:\n    async with session.create_client(\n        \"dynamodb\",\n        region_name=\"us-west-2\",\n        config=config,\n    ) as dynamodb:\n        print(await dynamodb.list_tables(Limit=10))\n```\n\nIf you need the experimental `httpx` backend, activate it through `AioConfig` and install the extra first:\n\n```python\nfrom aiobotocore.config import AioConfig\nfrom aiobotocore.httpxsession import HttpxSession\nfrom aiobotocore.session import get_session\n\nconfig = AioConfig(http_session_cls=HttpxSession)\nsession = get_session()\n```\n\nUse the `httpx` backend only when you have a concrete reason. Upstream still says some `aiohttp` features have not been ported and the backend is not fully tested.\n\n## Tested Service Coverage\n\nUpstream documents explicit test coverage for at least these services:\n\n- S3\n- DynamoDB\n- SNS\n- SQS\n- CloudFormation\n- Kinesis\n\nThe maintainers also note that many other botocore service clients work with the same pattern even if they are not listed individually. Treat that as a good starting assumption, but still smoke-test less common services against the exact operations you need.\n\n## Type Checking\n\nFor service-specific type stubs and editor completion:\n\n```bash\npython -m pip install \"types-aiobotocore[essential]\"\n```\n\nIf you need a lighter install, upstream also publishes `types-aiobotocore-lite`, but it does not provide `session.create_client(...)` overloads, so you usually need explicit client type annotations.\n\n## Common Pitfalls\n\n- Do not install or upgrade `botocore` independently without checking the exact supported range for your `aiobotocore` version.\n- Do not keep using a client after its async context has exited.\n- Do not ignore `response[\"Body\"]`; close or consume it so connections return to the pool.\n- Do not copy older install commands that use `aiobotocore[boto3]` or `aiobotocore[awscli]`; those extras were removed in `3.0.0`.\n- Do not assume the experimental `httpx` backend behaves exactly like the default `aiohttp` backend.\n- Prefer `asyncio.run(...)` in application entry points instead of older `get_event_loop().run_until_complete(...)` snippets from historical examples.\n\n## Official Sources Used For This Entry\n\n- Docs root: `https://aiobotocore.aio-libs.org/en/stable/`\n- Getting started: `https://aiobotocore.aio-libs.org/en/stable/tutorial.html`\n- S3 example: `https://aiobotocore.aio-libs.org/en/stable/examples/s3/basic_usage.html`\n- PyPI project page: `https://pypi.org/project/aiobotocore/`\n- PyPI release metadata for `3.2.1`: `https://pypi.org/pypi/aiobotocore/3.2.1/json`\n- Maintainer repository: `https://github.com/aio-libs/aiobotocore`\n"
  },
  {
    "path": "content/aws/docs/amplify/javascript/DOC.md",
    "content": "---\nname: amplify\ndescription: \"AWS SDK for JavaScript v3 client for managing Amplify Hosting apps, branches, jobs, manual deployments, and custom domains\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,amplify,hosting,javascript,nodejs,deployments,domains\"\n---\n\n# AWS Amplify SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-amplify` to manage Amplify Hosting resources from JavaScript or TypeScript. This package is the AWS control-plane client for creating apps, managing branches, starting build jobs, handling manual deployments, creating domain associations, and inspecting Amplify state.\n\nThis is not the `aws-amplify` frontend package. Use `@aws-sdk/client-amplify` when your code needs to manage Amplify resources from a backend service, CI job, or admin script.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-amplify`, not the legacy `aws-sdk` v2 package, for new JavaScript work.\n- Prefer `AmplifyClient` plus individual command imports over the aggregated service client.\n- Configure AWS credentials and `region` before creating the client.\n- If you create an app connected to GitHub, pass `accessToken`; for other supported repository providers, pass `oauthToken`.\n- `StartJobCommand({ jobType: \"RELEASE\" })` is for apps connected to a repository.\n- `StartDeploymentCommand` is for manually deployed apps that are not connected to a Git repository.\n- The current Amplify job success status is `\"SUCCEED\"`, not `\"SUCCEEDED\"`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-amplify\n```\n\nIf you want to load named profiles explicitly in code, install the AWS credential helpers you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nAmplify is regional. Set AWS credentials and a region before you create the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n\n# Only needed when creating or reconnecting a GitHub-backed Amplify app\nexport GITHUB_TOKEN=\"...\"\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { AmplifyClient } from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { AmplifyClient } from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { AmplifyClient } from \"@aws-sdk/client-amplify\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst amplify = new AmplifyClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS access already comes from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  AmplifyClient,\n  GetAppCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nconst { app } = await amplify.send(\n  new GetAppCommand({\n    appId: \"d1234567890abc\",\n  }),\n);\n\nconsole.log({\n  appId: app?.appId,\n  name: app?.name,\n  platform: app?.platform,\n  defaultDomain: app?.defaultDomain,\n});\n```\n\n## Common Workflows\n\n### List apps with pagination\n\n```javascript\nimport {\n  AmplifyClient,\n  ListAppsCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await amplify.send(\n    new ListAppsCommand({\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const app of response.apps ?? []) {\n    console.log(app.appId, app.name, app.platform, app.defaultDomain);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\n`ListAppsCommand`, `ListBranchesCommand`, `ListJobsCommand`, and `ListDomainAssociationsCommand` all use `nextToken` and `maxResults` pagination.\n\n### Create an app connected to a repository\n\n```javascript\nimport {\n  AmplifyClient,\n  CreateAppCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nconst { app } = await amplify.send(\n  new CreateAppCommand({\n    name: \"marketing-site\",\n    repository: \"https://github.com/acme/marketing-site\",\n    accessToken: process.env.GITHUB_TOKEN,\n    platform: \"WEB\",\n    enableBranchAutoBuild: true,\n    environmentVariables: {\n      NODE_ENV: \"production\",\n    },\n  }),\n);\n\nconsole.log(app?.appId, app?.defaultDomain);\n```\n\nUse `platform: \"WEB\"` for static apps. The current service model also includes `\"WEB_DYNAMIC\"` and `\"WEB_COMPUTE\"` for server-side rendered hosting modes.\n\nIf you connect a repository when creating the app, AWS requires repository auth:\n\n- GitHub: use `accessToken`\n- other supported providers such as Bitbucket or CodeCommit: use `oauthToken`\n\n### Update app settings\n\n```javascript\nimport {\n  AmplifyClient,\n  UpdateAppCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nconst { app } = await amplify.send(\n  new UpdateAppCommand({\n    appId: \"d1234567890abc\",\n    description: \"Production marketing site\",\n    enableBranchAutoBuild: true,\n    environmentVariables: {\n      NODE_ENV: \"production\",\n      API_BASE_URL: \"https://api.example.com\",\n    },\n  }),\n);\n\nconsole.log(app?.updateTime, app?.environmentVariables);\n```\n\nFor SSR apps, the current model also exposes `computeRoleArn` on `CreateAppCommand` and `UpdateAppCommand`.\n\n### Create and inspect branches\n\n```javascript\nimport {\n  AmplifyClient,\n  CreateBranchCommand,\n  ListBranchesCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\nconst appId = \"d1234567890abc\";\n\nawait amplify.send(\n  new CreateBranchCommand({\n    appId,\n    branchName: \"main\",\n    stage: \"PRODUCTION\",\n    enableAutoBuild: true,\n    displayName: \"main\",\n    environmentVariables: {\n      NEXT_PUBLIC_SITE_URL: \"https://example.com\",\n    },\n  }),\n);\n\nlet nextToken;\n\ndo {\n  const response = await amplify.send(\n    new ListBranchesCommand({\n      appId,\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const branch of response.branches ?? []) {\n    console.log(branch.branchName, branch.stage, branch.enableAutoBuild);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\nValid branch stage values in the current model are `PRODUCTION`, `BETA`, `DEVELOPMENT`, `EXPERIMENTAL`, and `PULL_REQUEST`.\n\n### Start a release job and wait for completion\n\n```javascript\nimport {\n  AmplifyClient,\n  GetJobCommand,\n  StartJobCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nfunction sleep(ms) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function startRelease(appId, branchName) {\n  const { jobSummary } = await amplify.send(\n    new StartJobCommand({\n      appId,\n      branchName,\n      jobType: \"RELEASE\",\n      jobReason: \"Deploy latest repository commit\",\n    }),\n  );\n\n  const jobId = jobSummary?.jobId;\n\n  if (!jobId) {\n    throw new Error(\"Amplify did not return a jobId\");\n  }\n\n  for (;;) {\n    const { job } = await amplify.send(\n      new GetJobCommand({\n        appId,\n        branchName,\n        jobId,\n      }),\n    );\n\n    const status = job?.summary?.status;\n    console.log(jobId, status);\n\n    if (status === \"SUCCEED\") {\n      return job;\n    }\n\n    if (status === \"FAILED\" || status === \"CANCELLED\") {\n      throw new Error(`Amplify job ${jobId} ended with status ${status}`);\n    }\n\n    await sleep(5000);\n  }\n}\n\nawait startRelease(\"d1234567890abc\", \"main\");\n```\n\nThe current job type values are `RELEASE`, `RETRY`, `MANUAL`, and `WEB_HOOK`. If you use `RETRY`, you must also pass the existing `jobId`.\n\n### Start a manual deployment from a public ZIP URL\n\nUse this flow for apps that are not connected to a Git repository.\n\n```javascript\nimport {\n  AmplifyClient,\n  StartDeploymentCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\n\nconst { jobSummary } = await amplify.send(\n  new StartDeploymentCommand({\n    appId: \"d1234567890abc\",\n    branchName: \"production\",\n    sourceUrl: \"https://downloads.example.com/site-build.zip\",\n    sourceUrlType: \"ZIP\",\n  }),\n);\n\nconsole.log(jobSummary?.jobId, jobSummary?.status);\n```\n\nIf you need Amplify-managed upload URLs instead of a public source URL, call `CreateDeploymentCommand` first. The current response shape includes a `jobId` plus either `zipUploadUrl` or `fileUploadUrls`, and the follow-up `StartDeploymentCommand` must happen within 8 hours.\n\n### Create a custom domain association\n\n```javascript\nimport {\n  AmplifyClient,\n  CreateDomainAssociationCommand,\n  GetDomainAssociationCommand,\n} from \"@aws-sdk/client-amplify\";\n\nconst amplify = new AmplifyClient({ region: \"us-east-1\" });\nconst appId = \"d1234567890abc\";\nconst domainName = \"example.com\";\n\nawait amplify.send(\n  new CreateDomainAssociationCommand({\n    appId,\n    domainName,\n    subDomainSettings: [\n      { prefix: \"\", branchName: \"main\" },\n      { prefix: \"www\", branchName: \"main\" },\n    ],\n  }),\n);\n\nconst { domainAssociation } = await amplify.send(\n  new GetDomainAssociationCommand({\n    appId,\n    domainName,\n  }),\n);\n\nconsole.log({\n  domainStatus: domainAssociation?.domainStatus,\n  statusReason: domainAssociation?.statusReason,\n  certificateVerificationDNSRecord:\n    domainAssociation?.certificateVerificationDNSRecord,\n});\n```\n\nPoll `GetDomainAssociationCommand` until `domainStatus` becomes `AVAILABLE`. If the status is `PENDING_VERIFICATION`, read `certificateVerificationDNSRecord` and make sure the required DNS record exists.\n\n## Practical Notes\n\n- This package manages Amplify resources in AWS. It does not build your frontend locally and it does not replace the `aws-amplify` application library.\n- Amplify is regional. If your code points at the wrong region, you usually get not-found behavior against the wrong app inventory.\n- `StartJobCommand` is the repo-connected CI/CD path. `StartDeploymentCommand` is the manual-deployment path.\n- The current platform enum values are `WEB`, `WEB_DYNAMIC`, and `WEB_COMPUTE`.\n- `GenerateAccessLogsCommand` returns a pre-signed `logUrl` if you need Amplify access logs.\n- `CreateWebhookCommand` and `ListWebhooksCommand` are available when you need a repository webhook outside the default app setup flow.\n\n## Common Pitfalls\n\n- Using `aws-amplify` instead of `@aws-sdk/client-amplify` for control-plane operations.\n- Forgetting to set `region`, which commonly leads to looking up the wrong Amplify app or branch.\n- Expecting `StartJobCommand` to work for a manually deployed app that is not connected to a repository.\n- Expecting `StartDeploymentCommand` to replace the repository-driven build flow for a connected app.\n- Checking for `\"SUCCEEDED\"` instead of the actual Amplify success status `\"SUCCEED\"`.\n- Passing plain `username:password` to `basicAuthCredentials`; the API expects base64-encoded credentials.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-amplify` version `3.1007.0`.\n- The current package surface includes the command-oriented client pattern shown here, including `CreateAppCommand`, `UpdateAppCommand`, `CreateBranchCommand`, `ListBranchesCommand`, `StartJobCommand`, `GetJobCommand`, `StartDeploymentCommand`, `CreateDomainAssociationCommand`, and `GetDomainAssociationCommand`.\n- In the current service model, branch stage values include `PRODUCTION`, `BETA`, `DEVELOPMENT`, `EXPERIMENTAL`, and `PULL_REQUEST`.\n- In the current service model, job type values include `RELEASE`, `RETRY`, `MANUAL`, and `WEB_HOOK`.\n- AWS currently documents `WEB`, `WEB_DYNAMIC`, and `WEB_COMPUTE` as the relevant Amplify app platform values.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Amplify client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/amplify/`\n- AWS Amplify API Reference: `https://docs.aws.amazon.com/amplify/latest/APIReference/Welcome.html`\n- AWS Amplify `CreateApp` API: `https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateApp.html`\n- AWS Amplify `StartJob` API: `https://docs.aws.amazon.com/amplify/latest/APIReference/API_StartJob.html`\n- AWS Amplify `StartDeployment` API: `https://docs.aws.amazon.com/amplify/latest/APIReference/API_StartDeployment.html`\n- AWS Amplify `CreateDomainAssociation` API: `https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateDomainAssociation.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/api-gateway/javascript/DOC.md",
    "content": "---\nname: api-gateway\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon API Gateway REST APIs, resources, methods, deployments, stages, usage plans, and domains.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,api-gateway,javascript,nodejs,rest-api,openapi\"\n---\n\n# `@aws-sdk/client-api-gateway`\n\nUse this package for the API Gateway **REST API control plane** in AWS SDK for JavaScript v3. It manages APIs, resources, methods, integrations, deployments, stages, usage plans, API keys, and custom domains.\n\nThis package does **not** invoke your deployed API for application traffic. It is for provisioning and admin workflows.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-api-gateway\n```\n\nPrefer `APIGatewayClient` plus explicit command imports. The aggregated `APIGateway` client exists, but command-based imports are the safer default for clearer code and smaller bundles.\n\n## Initialize the client\n\n```javascript\nimport { APIGatewayClient } from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({\n  region: \"us-east-1\",\n});\n```\n\nIn Node.js, the SDK can usually resolve credentials from the default credential provider chain, so setting the region is often enough.\n\n## Credentials and Region\n\n- Node.js: credentials usually come from environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n- Browser runtimes: use explicit browser-safe credentials only. In practice, this control-plane client is usually better kept on the server because it manages high-privilege infrastructure.\n- Region is required somewhere: pass it in code, set `AWS_REGION`, or configure it in shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## What This Client Covers\n\nUse `@aws-sdk/client-api-gateway` for the original API Gateway REST API service:\n\n- REST APIs and OpenAPI import/export\n- resources, methods, and integrations\n- deployments and stages\n- usage plans and API keys\n- custom domain names and base path mappings\n\nIf you need API Gateway HTTP APIs or WebSocket APIs, use the API Gateway v2 client instead of this package.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  APIGatewayClient,\n  CreateRestApiCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst response = await apiGateway.send(\n  new CreateRestApiCommand({\n    name: \"orders-api\",\n    description: \"REST API for order operations\",\n    endpointConfiguration: {\n      types: [\"REGIONAL\"],\n    },\n  }),\n);\n\nconsole.log(response.id);\nconsole.log(response.rootResourceId);\n```\n\nMost workflows follow the same sequence:\n\n1. create or import a `RestApi`\n2. create resources under the API root\n3. attach methods and integrations\n4. create a deployment\n5. bind or update a stage\n\n## Common Operations\n\n### List REST APIs with pagination\n\n```javascript\nimport {\n  APIGatewayClient,\n  paginateGetRestApis,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst paginator = paginateGetRestApis(\n  { client: apiGateway },\n  { limit: 25 },\n);\n\nfor await (const page of paginator) {\n  for (const api of page.items ?? []) {\n    console.log(api.id, api.name);\n  }\n}\n```\n\n### Get resources for an API\n\n```javascript\nimport {\n  APIGatewayClient,\n  GetResourcesCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst { items = [] } = await apiGateway.send(\n  new GetResourcesCommand({\n    restApiId: \"a1b2c3d4\",\n    limit: 500,\n  }),\n);\n\nfor (const resource of items) {\n  console.log(resource.id, resource.path);\n}\n```\n\n### Create a deployment\n\n```javascript\nimport {\n  APIGatewayClient,\n  CreateDeploymentCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst deployment = await apiGateway.send(\n  new CreateDeploymentCommand({\n    restApiId: \"a1b2c3d4\",\n    stageName: \"prod\",\n    description: \"Deploy current API configuration\",\n  }),\n);\n\nconsole.log(deployment.id);\n```\n\nPassing `stageName` creates or updates that stage as part of the deployment flow.\n\n## API Gateway REST API Gotchas\n\n- This package manages **REST APIs**. Do not confuse it with the separate API Gateway v2 service for HTTP APIs and WebSocket APIs.\n- Control-plane changes are not live until you create a deployment or point a stage at a new deployment.\n- `PutMethod` and `PutIntegration` are separate steps. A method without an integration still will not serve backend traffic.\n- `CreateDeployment` can create or update a stage when you pass `stageName`; otherwise deploy first and create a stage separately.\n- `PutRestApi` can merge or overwrite an existing API definition. Be explicit about update mode during OpenAPI-based workflows.\n- `Update*` operations use patch operations. Treat them like targeted infrastructure mutations rather than partial JSON merges.\n- Custom domain names, usage plans, and API keys are in this client too, so you do not need separate service packages for those control-plane APIs.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-apigatewayv2`: API Gateway HTTP APIs and WebSocket APIs.\n- `@aws-sdk/credential-providers`: Cognito, IAM Identity Center, shared config, assume-role flows, and other credential helpers.\n- `@aws-sdk/signature-v4` or higher-level HTTP clients: signed runtime calls if you are invoking an API rather than administering it.\n\n## Common API Gateway REST API Operations\n\n### Import an API from an OpenAPI file\n\nUse `ImportRestApiCommand` when the API definition already exists as OpenAPI or Swagger.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  APIGatewayClient,\n  ImportRestApiCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\nconst body = await readFile(\"./openapi.json\");\n\nconst response = await apiGateway.send(\n  new ImportRestApiCommand({\n    failOnWarnings: true,\n    body,\n    parameters: {\n      endpointConfigurationTypes: \"REGIONAL\",\n    },\n  }),\n);\n\nconsole.log(response.id, response.name);\n```\n\nUse `PutRestApiCommand` later if you want to merge or overwrite an existing API with a revised definition.\n\n### Create a child resource under the API root\n\n`CreateRestApi` returns `rootResourceId`. Use that as the parent when adding new paths.\n\n```javascript\nimport {\n  APIGatewayClient,\n  CreateResourceCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst resource = await apiGateway.send(\n  new CreateResourceCommand({\n    restApiId: \"a1b2c3d4\",\n    parentId: \"xyz987\",\n    pathPart: \"orders\",\n  }),\n);\n\nconsole.log(resource.id, resource.path);\n```\n\n### Attach a method and HTTP proxy integration\n\n`PutMethod` defines the method shape on the resource. `PutIntegration` connects that method to a backend.\n\n```javascript\nimport {\n  APIGatewayClient,\n  PutIntegrationCommand,\n  PutMethodCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\nconst restApiId = \"a1b2c3d4\";\nconst resourceId = \"r123456\";\n\nawait apiGateway.send(\n  new PutMethodCommand({\n    restApiId,\n    resourceId,\n    httpMethod: \"GET\",\n    authorizationType: \"NONE\",\n  }),\n);\n\nawait apiGateway.send(\n  new PutIntegrationCommand({\n    restApiId,\n    resourceId,\n    httpMethod: \"GET\",\n    type: \"HTTP_PROXY\",\n    integrationHttpMethod: \"GET\",\n    uri: \"https://example.com/orders\",\n  }),\n);\n```\n\nIf you use `AWS` or `AWS_PROXY` integrations, the `uri` must be the service-specific AWS integration URI, and the target service usually needs its own IAM permissions and resource policy setup.\n\n### Deploy a specific API revision to a stage\n\nIf you do not pass `stageName` to `CreateDeployment`, create the stage separately.\n\n```javascript\nimport {\n  APIGatewayClient,\n  CreateDeploymentCommand,\n  CreateStageCommand,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst deployment = await apiGateway.send(\n  new CreateDeploymentCommand({\n    restApiId: \"a1b2c3d4\",\n    description: \"Deploy after method and integration updates\",\n  }),\n);\n\nawait apiGateway.send(\n  new CreateStageCommand({\n    restApiId: \"a1b2c3d4\",\n    deploymentId: deployment.id,\n    stageName: \"prod\",\n    tracingEnabled: true,\n    variables: {\n      LOG_LEVEL: \"info\",\n    },\n  }),\n);\n```\n\nUse `UpdateStageCommand` when you only need to change stage settings or move the stage to a new deployment.\n\n### Paginate all resources for a large API\n\nLarge REST APIs may require multiple `GetResources` calls.\n\n```javascript\nimport {\n  APIGatewayClient,\n  paginateGetResources,\n} from \"@aws-sdk/client-api-gateway\";\n\nconst apiGateway = new APIGatewayClient({ region: \"us-east-1\" });\n\nconst paginator = paginateGetResources(\n  { client: apiGateway },\n  {\n    restApiId: \"a1b2c3d4\",\n    limit: 500,\n  },\n);\n\nfor await (const page of paginator) {\n  for (const resource of page.items ?? []) {\n    console.log(resource.path);\n  }\n}\n```\n\n### Notes\n\n- For OpenAPI-first workflows, `ImportRestApi` and `PutRestApi` are usually simpler than manually building every resource and method.\n- For imperative workflows, store `restApiId`, `rootResourceId`, `resourceId`, `deployment.id`, and `stageName` as soon as they are created.\n- Changes to resources, methods, and integrations do not affect live traffic until a deployment is created and a stage points at it.\n- API Gateway resource trees can become large, so use the paginators rather than assuming one page is enough.\n"
  },
  {
    "path": "content/aws/docs/apigatewayv2/javascript/DOC.md",
    "content": "---\nname: apigatewayv2\ndescription: \"AWS SDK for JavaScript v3 client for Amazon API Gateway V2 HTTP APIs and WebSocket API control-plane workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,apigatewayv2,api-gateway,http-api,websocket,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-apigatewayv2`\n\nUse this package for Amazon API Gateway V2 control-plane APIs in AWS SDK for JavaScript v3. It manages HTTP APIs, WebSocket APIs, routes, integrations, stages, deployments, authorizers, custom domains, and API mappings.\n\nThis package is not the runtime client for posting messages back to connected WebSocket clients. For that, use `@aws-sdk/client-apigatewaymanagementapi`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-apigatewayv2\n```\n\nPrefer `ApiGatewayV2Client` plus explicit command imports. The package also exposes an aggregated `ApiGatewayV2` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Initialize the client\n\n```javascript\nimport { ApiGatewayV2Client } from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({\n  region: \"us-east-1\",\n});\n```\n\n## Credentials and Region\n\n- Node.js: the default AWS credential provider chain usually works if credentials are already configured through environment variables, shared AWS config, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: this is a control-plane client for infrastructure and admin workflows, so it usually belongs on the server side.\n- Keep the region explicit somewhere: in code, `AWS_REGION`, or shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## What This Client Covers\n\nUse `@aws-sdk/client-apigatewayv2` for:\n\n- HTTP APIs\n- WebSocket APIs\n- routes and route responses\n- integrations and integration responses\n- stages and deployments\n- JWT and Lambda authorizers\n- custom domains and API mappings\n\nIf you need the original API Gateway REST API service, use `@aws-sdk/client-api-gateway` instead.\n\n## Core Usage Pattern\n\nThe v3 SDK uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  CreateApiCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nconst response = await apiGatewayV2.send(\n  new CreateApiCommand({\n    Name: \"orders-http-api\",\n    ProtocolType: \"HTTP\",\n  }),\n);\n\nconsole.log(response.ApiId, response.ApiEndpoint);\n```\n\nFor most HTTP API workflows, the sequence is:\n\n1. create the API\n2. create one or more integrations\n3. create routes that point at those integrations\n4. create a stage or rely on auto-deploy\n\n## Common Operations\n\n### List APIs with pagination\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  GetApisCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await apiGatewayV2.send(\n    new GetApisCommand({\n      MaxResults: \"50\",\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const api of response.Items ?? []) {\n    console.log(api.ApiId, api.Name, api.ProtocolType);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Create an HTTP proxy integration\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  CreateIntegrationCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nconst integration = await apiGatewayV2.send(\n  new CreateIntegrationCommand({\n    ApiId: \"a1b2c3d4\",\n    IntegrationType: \"HTTP_PROXY\",\n    IntegrationMethod: \"ANY\",\n    IntegrationUri: \"https://example.com/orders\",\n    PayloadFormatVersion: \"1.0\",\n  }),\n);\n\nconsole.log(integration.IntegrationId);\n```\n\nFor Lambda proxy integrations, use the Lambda invoke ARN as the integration URI and make sure the function also has the correct invoke permission.\n\n### Create an HTTP route\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  CreateRouteCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nawait apiGatewayV2.send(\n  new CreateRouteCommand({\n    ApiId: \"a1b2c3d4\",\n    RouteKey: \"GET /orders\",\n    Target: \"integrations/abc123\",\n  }),\n);\n```\n\nFor HTTP APIs, route keys look like `METHOD /path`. For WebSocket APIs, route keys look like `$connect`, `$disconnect`, `$default`, or an application-defined route key.\n\n### Create a stage with auto-deploy\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  CreateStageCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nawait apiGatewayV2.send(\n  new CreateStageCommand({\n    ApiId: \"a1b2c3d4\",\n    StageName: \"$default\",\n    AutoDeploy: true,\n  }),\n);\n```\n\nFor HTTP APIs, a `$default` stage with `AutoDeploy: true` is a common simple setup.\n\n### Create a deployment when auto-deploy is off\n\n```javascript\nimport {\n  ApiGatewayV2Client,\n  CreateDeploymentCommand,\n} from \"@aws-sdk/client-apigatewayv2\";\n\nconst apiGatewayV2 = new ApiGatewayV2Client({ region: \"us-east-1\" });\n\nconst deployment = await apiGatewayV2.send(\n  new CreateDeploymentCommand({\n    ApiId: \"a1b2c3d4\",\n    Description: \"Promote tested routes and integrations\",\n  }),\n);\n\nconsole.log(deployment.DeploymentId);\n```\n\nIf the stage is not auto-deploying, point the stage at the new deployment after this step.\n\n## API Gateway V2 Gotchas\n\n- `ProtocolType` is required and changes the whole workflow: `HTTP` and `WEBSOCKET` APIs use different route-key patterns and capabilities.\n- This package manages infrastructure, not runtime traffic. It creates APIs and routes; it does not invoke your deployed endpoints for application calls.\n- `@aws-sdk/client-api-gateway` is for the original REST API service. Do not mix the two packages.\n- A route usually needs an integration first, because the route `Target` points at `integrations/<integrationId>`.\n- `$default` has special meaning for both routes and stages. Use it intentionally rather than as a placeholder string.\n- Auto-deploy changes whether you need explicit deployment management. Know which stage mode you are using before assuming a route change is already live.\n- WebSocket callback messages are handled through the API Gateway Management API package, not this package.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-api-gateway`: the original API Gateway REST API service.\n- `@aws-sdk/client-apigatewaymanagementapi`: post messages to connected WebSocket clients at runtime.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, and assume-role flows.\n"
  },
  {
    "path": "content/aws/docs/application-auto-scaling/javascript/DOC.md",
    "content": "---\nname: application-auto-scaling\ndescription: \"AWS Application Auto Scaling SDK for JavaScript v3 guide for registering scalable targets, attaching scaling policies, and scheduling capacity changes\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,application-auto-scaling,autoscaling,ecs,dynamodb,javascript,nodejs\"\n---\n\n# AWS Application Auto Scaling SDK for JavaScript v3 Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-application-auto-scaling` when you need to scale an AWS service that integrates with **Application Auto Scaling** rather than EC2 Auto Scaling groups.\n\nCommon examples include:\n\n- ECS service desired count\n- DynamoDB read or write capacity\n- Aurora read replica count\n- Lambda provisioned concurrency\n- SageMaker production variant capacity\n\nDo **not** use this package for EC2 Auto Scaling groups. That uses `@aws-sdk/client-auto-scaling` instead.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-application-auto-scaling\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/credential-providers @aws-sdk/client-ecs\n```\n\nExamples in this guide use ESM imports and the AWS SDK v3 command pattern: `client.send(new Command(input))`.\n\n## Credentials And Region\n\nThe client uses the standard AWS SDK for JavaScript v3 credential provider chain. For local development, set a region and either a profile or direct credentials.\n\nPreferred local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\n```\n\nDirect environment credentials also work:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nApplication Auto Scaling is regional. Use the same region for the scalable resource and the Application Auto Scaling client.\n\n## Initialize The Client\n\n```javascript\nimport { ApplicationAutoScalingClient } from \"@aws-sdk/client-application-auto-scaling\";\n\nexport const applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nFor most server-side applications, one shared client instance per region is enough.\n\n## Core Usage\n\n### Register A Scalable Target\n\nBefore you add a scaling policy, register the resource and its scalable dimension with `RegisterScalableTargetCommand`.\n\nThis example registers an ECS service so Application Auto Scaling can adjust its task count:\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  RegisterScalableTargetCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait applicationAutoScaling.send(\n  new RegisterScalableTargetCommand({\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n    MinCapacity: 2,\n    MaxCapacity: 10,\n  }),\n);\n```\n\nFor ECS, the `ResourceId` format is `service/<cluster-name>/<service-name>`.\n\n### Add A Target Tracking Scaling Policy\n\nUse `PutScalingPolicyCommand` with `PolicyType: \"TargetTrackingScaling\"` when you want AWS to adjust capacity toward a target metric.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  PutScalingPolicyCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await applicationAutoScaling.send(\n  new PutScalingPolicyCommand({\n    PolicyName: \"web-api-cpu-target-50\",\n    PolicyType: \"TargetTrackingScaling\",\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n    TargetTrackingScalingPolicyConfiguration: {\n      PredefinedMetricSpecification: {\n        PredefinedMetricType: \"ECSServiceAverageCPUUtilization\",\n      },\n      TargetValue: 50,\n      ScaleInCooldown: 60,\n      ScaleOutCooldown: 60,\n    },\n  }),\n);\n\nconsole.log(response.PolicyARN);\n```\n\nFor ECS service target tracking, predefined metrics such as `ECSServiceAverageCPUUtilization` let you attach a policy without creating CloudWatch alarms yourself.\n\n### List Registered Targets\n\nUse `DescribeScalableTargetsCommand` to confirm the resource, dimension, and capacity bounds that are currently registered.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  DescribeScalableTargetsCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await applicationAutoScaling.send(\n  new DescribeScalableTargetsCommand({\n    ServiceNamespace: \"ecs\",\n    ResourceIds: [\"service/default/web-api\"],\n    ScalableDimension: \"ecs:service:DesiredCount\",\n  }),\n);\n\nfor (const target of response.ScalableTargets ?? []) {\n  console.log({\n    resourceId: target.ResourceId,\n    dimension: target.ScalableDimension,\n    minCapacity: target.MinCapacity,\n    maxCapacity: target.MaxCapacity,\n    roleArn: target.RoleARN,\n  });\n}\n```\n\n### Inspect Scaling Policies\n\nUse `DescribeScalingPoliciesCommand` when you need to confirm which target tracking or step scaling policies exist for a resource.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  DescribeScalingPoliciesCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await applicationAutoScaling.send(\n  new DescribeScalingPoliciesCommand({\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n  }),\n);\n\nfor (const policy of response.ScalingPolicies ?? []) {\n  console.log({\n    name: policy.PolicyName,\n    type: policy.PolicyType,\n    arn: policy.PolicyARN,\n  });\n}\n```\n\n### Add A Scheduled Scaling Action\n\nUse `PutScheduledActionCommand` when you want to change capacity bounds on a schedule, such as raising minimum capacity during business hours.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  PutScheduledActionCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait applicationAutoScaling.send(\n  new PutScheduledActionCommand({\n    ScheduledActionName: \"weekday-business-hours\",\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n    Schedule: \"cron(0 13 ? * MON-FRI *)\",\n    ScalableTargetAction: {\n      MinCapacity: 4,\n      MaxCapacity: 12,\n    },\n  }),\n);\n```\n\n`PutScheduledActionCommand` updates the action if you reuse the same scheduled action name for the same target.\n\n### Inspect Recent Scaling Activity\n\nUse `DescribeScalingActivitiesCommand` when you need to understand why a resource scaled or why a scaling action failed.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  DescribeScalingActivitiesCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await applicationAutoScaling.send(\n  new DescribeScalingActivitiesCommand({\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n    MaxResults: 20,\n  }),\n);\n\nfor (const activity of response.ScalingActivities ?? []) {\n  console.log({\n    id: activity.ActivityId,\n    statusCode: activity.StatusCode,\n    statusMessage: activity.StatusMessage,\n    cause: activity.Cause,\n    startTime: activity.StartTime,\n    endTime: activity.EndTime,\n  });\n}\n```\n\n### Remove A Scaling Policy Or Scalable Target\n\nDelete the policy first, then deregister the scalable target if you no longer want the resource managed by Application Auto Scaling.\n\n```javascript\nimport {\n  ApplicationAutoScalingClient,\n  DeleteScalingPolicyCommand,\n  DeregisterScalableTargetCommand,\n} from \"@aws-sdk/client-application-auto-scaling\";\n\nconst applicationAutoScaling = new ApplicationAutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait applicationAutoScaling.send(\n  new DeleteScalingPolicyCommand({\n    PolicyName: \"web-api-cpu-target-50\",\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n  }),\n);\n\nawait applicationAutoScaling.send(\n  new DeregisterScalableTargetCommand({\n    ServiceNamespace: \"ecs\",\n    ResourceId: \"service/default/web-api\",\n    ScalableDimension: \"ecs:service:DesiredCount\",\n  }),\n);\n```\n\n## Common Pitfalls\n\n- Do not confuse Application Auto Scaling with EC2 Auto Scaling. `@aws-sdk/client-application-auto-scaling` manages scalable targets for other AWS services, not Auto Scaling groups.\n- Do not guess the `ResourceId` or `ScalableDimension` format. They are service-specific and must exactly match the target service integration.\n- Register the scalable target before attaching scaling policies or scheduled actions.\n- Application Auto Scaling does not create the underlying ECS service, DynamoDB table, Lambda alias, or other resource. It only manages scaling for an existing resource.\n- Keep the AWS region consistent across the scalable resource, the Application Auto Scaling client, and any metrics or alarms the policy depends on.\n- Do not hardcode AWS credentials in source files. Use environment variables, shared AWS config, or IAM roles.\n\n## Version Scope\n\n- This guide targets `@aws-sdk/client-application-auto-scaling@3.1007.0`.\n- Examples use the modular AWS SDK for JavaScript v3 client and explicit command imports.\n- The npm package slug is `@aws-sdk/client-application-auto-scaling`, while the runtime client class is `ApplicationAutoScalingClient`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Application Auto Scaling client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/application-auto-scaling/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- Application Auto Scaling API Reference: `https://docs.aws.amazon.com/autoscaling/application/APIReference/Welcome.html`\n- `RegisterScalableTarget` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_RegisterScalableTarget.html`\n- `DescribeScalableTargets` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_DescribeScalableTargets.html`\n- `PutScalingPolicy` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PutScalingPolicy.html`\n- `DescribeScalingPolicies` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_DescribeScalingPolicies.html`\n- `PutScheduledAction` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PutScheduledAction.html`\n- `DescribeScalingActivities` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_DescribeScalingActivities.html`\n- `DeleteScalingPolicy` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_DeleteScalingPolicy.html`\n- `DeregisterScalableTarget` API: `https://docs.aws.amazon.com/autoscaling/application/APIReference/API_DeregisterScalableTarget.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-application-auto-scaling`\n"
  },
  {
    "path": "content/aws/docs/apprunner/javascript/DOC.md",
    "content": "---\nname: apprunner\ndescription: \"AWS App Runner SDK for JavaScript guide for creating, updating, and operating App Runner services\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,apprunner,javascript,nodejs,containers,deployment\"\n---\n\n# AWS App Runner SDK for JavaScript\n\n## Golden Rule\n\nUse `@aws-sdk/client-apprunner` for App Runner control-plane operations from JavaScript or Node.js: creating services, describing them, starting deployments, pausing or resuming traffic, and managing custom domains.\n\n```bash\nnpm install @aws-sdk/client-apprunner\n```\n\nThis package manages App Runner resources. Your application code still runs inside App Runner after deployment; this SDK does not replace your service runtime or your container image.\n\n## Credentials And Region\n\nApp Runner is regional. Pass `region` explicitly and make sure the service ARN, ECR image, VPC connector, and custom domain workflow all belong to the same AWS Region unless the AWS API explicitly says otherwise.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\n\nexport APP_RUNNER_SERVICE_ARN=arn:aws:apprunner:us-east-1:123456789012:service/my-service/0123456789abcdef\nexport APP_RUNNER_CONNECTION_ARN=arn:aws:apprunner:us-east-1:123456789012:connection/my-github-connection/e7656250f67242d7819feade6800f59e\nexport APP_RUNNER_ECR_ACCESS_ROLE_ARN=arn:aws:iam::123456789012:role/my-app-runner-ecr-role\nexport APP_RUNNER_IMAGE_URI=123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest\nexport APP_RUNNER_CUSTOM_DOMAIN=api.example.com\n```\n\nThe SDK uses the standard AWS credential provider chain in Node.js, including environment variables, shared AWS config files, IAM roles, and other standard AWS sources.\n\n## Client Initialization\n\n```javascript\nimport { AppRunnerClient } from \"@aws-sdk/client-apprunner\";\n\nexport const apprunner = new AppRunnerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you need explicit static credentials, pass a `credentials` object to `AppRunnerClient`, but the default provider chain is the normal setup for local development and AWS-hosted workloads.\n\n## Common Workflows\n\n### List services\n\n`ListServices` returns summary objects only. Use `DescribeService` when you need the full source, instance, networking, or health-check configuration.\n\n```javascript\nimport {\n  AppRunnerClient,\n  ListServicesCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListServicesCommand({\n      MaxResults: 20,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const service of page.ServiceSummaryList ?? []) {\n    console.log({\n      serviceName: service.ServiceName,\n      serviceArn: service.ServiceArn,\n      status: service.Status,\n      serviceUrl: service.ServiceUrl,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n### Describe a service\n\n```javascript\nimport {\n  AppRunnerClient,\n  DescribeServiceCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst response = await client.send(\n  new DescribeServiceCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n  }),\n);\n\nconsole.log({\n  serviceName: response.Service?.ServiceName,\n  status: response.Service?.Status,\n  serviceUrl: response.Service?.ServiceUrl,\n  sourceConfiguration: response.Service?.SourceConfiguration,\n  instanceConfiguration: response.Service?.InstanceConfiguration,\n});\n```\n\n### Create a service from a GitHub repository\n\nFor source-code services, App Runner needs a connection ARN. If `CodeConfiguration.ConfigurationSource` is `API`, App Runner uses the values you send in `CodeConfigurationValues`. If it is `REPOSITORY`, App Runner reads `apprunner.yaml` from the repository and ignores `CodeConfigurationValues`.\n\n```javascript\nimport {\n  AppRunnerClient,\n  CreateServiceCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst response = await client.send(\n  new CreateServiceCommand({\n    ServiceName: \"nodejs-web-app\",\n    SourceConfiguration: {\n      AuthenticationConfiguration: {\n        ConnectionArn: process.env.APP_RUNNER_CONNECTION_ARN,\n      },\n      AutoDeploymentsEnabled: true,\n      CodeRepository: {\n        RepositoryUrl: \"https://github.com/your-org/your-repo\",\n        SourceCodeVersion: {\n          Type: \"BRANCH\",\n          Value: \"main\",\n        },\n        SourceDirectory: \"/\",\n        CodeConfiguration: {\n          ConfigurationSource: \"API\",\n          CodeConfigurationValues: {\n            Runtime: \"NODEJS_22\",\n            BuildCommand: \"npm ci\",\n            StartCommand: \"npm start\",\n            Port: \"3000\",\n            RuntimeEnvironmentVariables: {\n              NODE_ENV: \"production\",\n            },\n          },\n        },\n      },\n    },\n    InstanceConfiguration: {\n      Cpu: \"1 vCPU\",\n      Memory: \"2 GB\",\n    },\n    HealthCheckConfiguration: {\n      Protocol: \"HTTP\",\n      Path: \"/health\",\n    },\n  }),\n);\n\nconsole.log(response.Service?.ServiceArn);\nconsole.log(response.OperationId);\n```\n\n### Create a service from an ECR image\n\nFor private ECR repositories, send `AuthenticationConfiguration.AccessRoleArn`. The App Runner API documents that this role is required for ECR, but not for ECR Public.\n\n```javascript\nimport {\n  AppRunnerClient,\n  CreateServiceCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst response = await client.send(\n  new CreateServiceCommand({\n    ServiceName: \"container-web-app\",\n    SourceConfiguration: {\n      AuthenticationConfiguration: {\n        AccessRoleArn: process.env.APP_RUNNER_ECR_ACCESS_ROLE_ARN,\n      },\n      AutoDeploymentsEnabled: true,\n      ImageRepository: {\n        ImageIdentifier: process.env.APP_RUNNER_IMAGE_URI,\n        ImageRepositoryType: \"ECR\",\n        ImageConfiguration: {\n          Port: \"8080\",\n          RuntimeEnvironmentVariables: {\n            NODE_ENV: \"production\",\n          },\n        },\n      },\n    },\n    InstanceConfiguration: {\n      Cpu: \"1 vCPU\",\n      Memory: \"2 GB\",\n    },\n    HealthCheckConfiguration: {\n      Protocol: \"HTTP\",\n      Path: \"/health\",\n    },\n  }),\n);\n\nconsole.log(response.Service?.ServiceArn);\nconsole.log(response.OperationId);\n```\n\n### Start a deployment and wait for the async operation\n\n`CreateService`, `UpdateService`, `PauseService`, `ResumeService`, `DeleteService`, and `StartDeployment` are asynchronous. Track the returned `OperationId` with `ListOperations`.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  AppRunnerClient,\n  ListOperationsCommand,\n  StartDeploymentCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nasync function waitForOperation(serviceArn, operationId) {\n  for (;;) {\n    const response = await client.send(\n      new ListOperationsCommand({\n        ServiceArn: serviceArn,\n        MaxResults: 20,\n      }),\n    );\n\n    const operation = (response.OperationSummaryList ?? []).find(\n      (item) => item.Id === operationId,\n    );\n\n    if (!operation) {\n      await sleep(5000);\n      continue;\n    }\n\n    if (operation.Status === \"SUCCEEDED\") {\n      return operation;\n    }\n\n    if (\n      operation.Status === \"FAILED\" ||\n      operation.Status === \"ROLLBACK_FAILED\"\n    ) {\n      throw new Error(\n        `App Runner operation ${operation.Id} failed with status ${operation.Status}`,\n      );\n    }\n\n    await sleep(5000);\n  }\n}\n\nconst deployment = await client.send(\n  new StartDeploymentCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n  }),\n);\n\nawait waitForOperation(\n  process.env.APP_RUNNER_SERVICE_ARN,\n  deployment.OperationId,\n);\n```\n\n### Update service settings\n\n`UpdateService` lets you change the source configuration, instance size, health checks, scaling configuration association, networking, and observability settings.\n\n```javascript\nimport {\n  AppRunnerClient,\n  UpdateServiceCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst response = await client.send(\n  new UpdateServiceCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n    InstanceConfiguration: {\n      Cpu: \"2 vCPU\",\n      Memory: \"4 GB\",\n    },\n    HealthCheckConfiguration: {\n      Protocol: \"HTTP\",\n      Path: \"/readyz\",\n      Interval: 10,\n      Timeout: 5,\n      HealthyThreshold: 1,\n      UnhealthyThreshold: 5,\n    },\n  }),\n);\n\nconsole.log(response.OperationId);\nconsole.log(response.Service?.Status);\n```\n\n### Pause and resume a service\n\n```javascript\nimport {\n  AppRunnerClient,\n  PauseServiceCommand,\n  ResumeServiceCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst paused = await client.send(\n  new PauseServiceCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n  }),\n);\n\nconsole.log(paused.OperationId);\nconsole.log(paused.Service?.Status);\n\nconst resumed = await client.send(\n  new ResumeServiceCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n  }),\n);\n\nconsole.log(resumed.OperationId);\nconsole.log(resumed.Service?.Status);\n```\n\n### Associate a custom domain and inspect DNS validation\n\nThe association response gives you the App Runner DNS target and certificate validation records. Publish the returned CNAME records in DNS, then call `DescribeCustomDomains` until the domain status becomes `ACTIVE`.\n\n```javascript\nimport {\n  AppRunnerClient,\n  AssociateCustomDomainCommand,\n  DescribeCustomDomainsCommand,\n} from \"@aws-sdk/client-apprunner\";\n\nconst client = new AppRunnerClient({ region: process.env.AWS_REGION });\n\nconst association = await client.send(\n  new AssociateCustomDomainCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n    DomainName: process.env.APP_RUNNER_CUSTOM_DOMAIN,\n    EnableWWWSubdomain: true,\n  }),\n);\n\nconsole.log(\"service target\", association.DNSTarget);\n\nfor (const record of association.CustomDomain?.CertificateValidationRecords ?? []) {\n  console.log(record.Name, record.Type, record.Value, record.Status);\n}\n\nconst domains = await client.send(\n  new DescribeCustomDomainsCommand({\n    ServiceArn: process.env.APP_RUNNER_SERVICE_ARN,\n  }),\n);\n\nfor (const domain of domains.CustomDomains ?? []) {\n  console.log(domain.DomainName, domain.Status);\n}\n```\n\n## App Runner-Specific Notes\n\n- `CreateService` requires `ServiceName` and `SourceConfiguration`.\n- `SourceConfiguration` must include exactly one of `CodeRepository` or `ImageRepository`.\n- For GitHub source repositories, send `AuthenticationConfiguration.ConnectionArn`.\n- For private ECR images, send `AuthenticationConfiguration.AccessRoleArn`; ECR Public does not require it.\n- `AutoDeploymentsEnabled` defaults depend on the source. The App Runner API documents `false` for ECR Public and cross-account ECR, and `true` for code repositories and same-account ECR.\n- Code-repository services can use `ConfigurationSource: \"REPOSITORY\"` to read `apprunner.yaml`, or `\"API\"` to use `CodeConfigurationValues` from your SDK request.\n- `ImageConfiguration.Port` and `CodeConfigurationValues.Port` default to `8080` when omitted.\n- `NetworkConfiguration.EgressConfiguration.EgressType` is `DEFAULT` for public outbound access and `VPC` when you attach a VPC connector.\n- `IngressConfiguration.IsPubliclyAccessible: false` makes the service private to an Amazon VPC.\n- `IpAddressType` defaults to `IPV4`; the current API also supports `DUAL_STACK`.\n- The current App Runner runtime enum includes `NODEJS_18` and `NODEJS_22` for code-repository services.\n\n## Common Pitfalls\n\n- Assuming async operations finish when the initial API call returns. Use `OperationId` plus `ListOperations`.\n- Sending both `CodeRepository` and `ImageRepository` in one request.\n- Sending `CodeConfigurationValues` while expecting `apprunner.yaml` to apply. `ConfigurationSource` decides which source wins.\n- Using a service ARN from one Region with a client configured for another Region.\n- Forgetting the ECR access role for private images.\n- Expecting `ListServices` to return the full service configuration. Use `DescribeService` for the full shape.\n- Treating environment variables and secrets as arrays. In the current API model, `RuntimeEnvironmentVariables` and `RuntimeEnvironmentSecrets` are key-value maps.\n\n## Official Sources\n\n- Maintainer package source: `https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-apprunner`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-apprunner`\n- AWS App Runner API reference: `https://docs.aws.amazon.com/apprunner/latest/api/`\n- AWS CLI App Runner reference: `https://docs.aws.amazon.com/cli/latest/reference/apprunner/`\n"
  },
  {
    "path": "content/aws/docs/appstream/javascript/DOC.md",
    "content": "---\nname: appstream\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon AppStream 2.0 / WorkSpaces Applications stacks, fleets, users, sessions, and streaming URLs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,appstream,workspaces-applications,streaming,iam\"\n---\n\n# AWS AppStream SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-appstream` to manage Amazon AppStream 2.0 resources from JavaScript or TypeScript. In current AWS documentation, parts of the service are also branded as WorkSpaces Applications, but the SDK package, client name, and API namespace remain `appstream`.\n\nThis is the control-plane client. Typical tasks include listing stacks and fleets, creating temporary streaming URLs, inspecting active sessions, managing user-pool users, and associating users with stacks.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-appstream`, not the legacy `aws-sdk` v2 package.\n- Set `region` explicitly or provide it through standard AWS SDK configuration before creating `AppStreamClient`.\n- `CreateStreamingURLCommand` returns a short-lived URL for one stack, one fleet, and one user. Set `Validity` explicitly if the default 60-second lifetime is too short.\n- User-management APIs such as `CreateUserCommand`, `DescribeUsersCommand`, `EnableUserCommand`, and `DisableUserCommand` require `AuthenticationType: \"USERPOOL\"`.\n- AppStream user email addresses are case-sensitive in user-management and user-stack association APIs.\n- `DescribeSessionsCommand` requires both `UserId` and `AuthenticationType` when you filter sessions for a specific user.\n- `BatchAssociateUserStackCommand` can return per-association errors in `errors`, so inspect the response even when the request succeeds.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-appstream\n```\n\n## Prerequisites\n\nAppStream is regional. Configure credentials and a region before making calls.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_REGION=\"us-west-2\"\n```\n\nOr set credentials directly:\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional, only for temporary credentials\nexport AWS_REGION=\"us-west-2\"\n```\n\nIf you use shared config or named profiles locally, `AWS_PROFILE` also works with the standard AWS SDK credential chain.\n\n## Client Setup\n\n```javascript\nimport { AppStreamClient } from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nIf you need to provide credentials in code:\n\n```javascript\nimport { AppStreamClient } from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({\n  region: \"us-west-2\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  AppStreamClient,\n  DescribeStacksCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await appstream.send(\n  new DescribeStacksCommand({\n    Names: [\"engineering-stack\"],\n  }),\n);\n\nconsole.log(response.Stacks?.[0]);\n```\n\n## Common Workflows\n\n### List fleets\n\n`DescribeFleetsCommand` returns all fleets when you omit `Names`.\n\n```javascript\nimport {\n  AppStreamClient,\n  DescribeFleetsCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await appstream.send(\n    new DescribeFleetsCommand({\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const fleet of page.Fleets ?? []) {\n    console.log({\n      name: fleet.Name,\n      state: fleet.State,\n      fleetType: fleet.FleetType,\n      instanceType: fleet.InstanceType,\n      maxConcurrentSessions: fleet.MaxConcurrentSessions,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n### List stacks\n\n`DescribeStacksCommand` also paginates with `NextToken`.\n\n```javascript\nimport {\n  AppStreamClient,\n  DescribeStacksCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await appstream.send(\n    new DescribeStacksCommand({\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const stack of page.Stacks ?? []) {\n    console.log({\n      name: stack.Name,\n      displayName: stack.DisplayName,\n      redirectUrl: stack.RedirectURL,\n      feedbackUrl: stack.FeedbackURL,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n### Create a temporary streaming URL\n\nUse `CreateStreamingURLCommand` when you need a temporary session URL for a specific user. AWS documents `Validity` as 1 to 604800 seconds, with a default of 60 seconds.\n\n```javascript\nimport {\n  AppStreamClient,\n  CreateStreamingURLCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nconst response = await appstream.send(\n  new CreateStreamingURLCommand({\n    StackName: \"engineering-stack\",\n    FleetName: \"engineering-fleet\",\n    UserId: \"developer@example.com\",\n    ApplicationId: \"Visual Studio Code\",\n    Validity: 300,\n    SessionContext: JSON.stringify({\n      ticketId: \"INC-1234\",\n      launchedBy: \"admin-console\",\n    }),\n  }),\n);\n\nconsole.log(response.StreamingURL);\nconsole.log(response.Expires);\n```\n\n`StreamingURL` is the one-time launch URL. `Expires` tells you when the URL becomes invalid.\n\n### Inspect sessions and expire one\n\nUse `DescribeSessionsCommand` to inspect active or pending sessions for a stack and fleet. Stack and fleet names are case-sensitive here.\n\n```javascript\nimport {\n  AppStreamClient,\n  DescribeSessionsCommand,\n  ExpireSessionCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nconst listed = await appstream.send(\n  new DescribeSessionsCommand({\n    StackName: \"engineering-stack\",\n    FleetName: \"engineering-fleet\",\n    UserId: \"developer@example.com\",\n    AuthenticationType: \"API\",\n    Limit: 20,\n  }),\n);\n\nfor (const session of listed.Sessions ?? []) {\n  console.log({\n    id: session.Id,\n    userId: session.UserId,\n    state: session.State,\n    connectionState: session.ConnectionState,\n    instanceId: session.InstanceId,\n  });\n}\n\nconst activeSession = listed.Sessions?.find((session) => session.State === \"ACTIVE\");\n\nif (activeSession?.Id) {\n  await appstream.send(\n    new ExpireSessionCommand({\n      SessionId: activeSession.Id,\n    }),\n  );\n}\n```\n\nIf you omit `AuthenticationType`, AWS defaults session lookup to streaming-URL users (`API`). If you send `UserId`, also send `AuthenticationType`.\n\n### Create and list user-pool users\n\nUse `CreateUserCommand` and `DescribeUsersCommand` only with `AuthenticationType: \"USERPOOL\"`.\n\n```javascript\nimport {\n  AppStreamClient,\n  CreateUserCommand,\n  DescribeUsersCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nawait appstream.send(\n  new CreateUserCommand({\n    UserName: \"alex@example.com\",\n    AuthenticationType: \"USERPOOL\",\n    FirstName: \"Alex\",\n    LastName: \"Rivera\",\n    MessageAction: \"SUPPRESS\",\n  }),\n);\n\nlet nextToken;\n\ndo {\n  const page = await appstream.send(\n    new DescribeUsersCommand({\n      AuthenticationType: \"USERPOOL\",\n      MaxResults: 25,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const user of page.Users ?? []) {\n    console.log({\n      userName: user.UserName,\n      enabled: user.Enabled,\n      status: user.Status,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nAWS documents user email addresses as case-sensitive. Use the same capitalization consistently when you create users, enable or disable them, and associate them with stacks.\n\n### Associate a user with a stack\n\nUse `BatchAssociateUserStackCommand` to map one or more users to one or more stacks. AWS documents that users in a user pool cannot be assigned to stacks with fleets that are joined to an Active Directory domain.\n\n```javascript\nimport {\n  AppStreamClient,\n  BatchAssociateUserStackCommand,\n  DescribeUserStackAssociationsCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nconst associated = await appstream.send(\n  new BatchAssociateUserStackCommand({\n    UserStackAssociations: [\n      {\n        StackName: \"engineering-stack\",\n        UserName: \"alex@example.com\",\n        AuthenticationType: \"USERPOOL\",\n        SendEmailNotification: false,\n      },\n    ],\n  }),\n);\n\nif ((associated.errors ?? []).length > 0) {\n  console.error(associated.errors);\n}\n\nconst result = await appstream.send(\n  new DescribeUserStackAssociationsCommand({\n    UserName: \"alex@example.com\",\n    AuthenticationType: \"USERPOOL\",\n    MaxResults: 25,\n  }),\n);\n\nfor (const association of result.UserStackAssociations ?? []) {\n  console.log(association.StackName, association.UserName);\n}\n```\n\n### Temporarily disable and re-enable a user\n\n`DisableUserCommand` blocks sign-in without deleting the user. `EnableUserCommand` restores access.\n\n```javascript\nimport {\n  AppStreamClient,\n  DisableUserCommand,\n  EnableUserCommand,\n} from \"@aws-sdk/client-appstream\";\n\nconst appstream = new AppStreamClient({ region: \"us-west-2\" });\n\nawait appstream.send(\n  new DisableUserCommand({\n    UserName: \"alex@example.com\",\n    AuthenticationType: \"USERPOOL\",\n  }),\n);\n\nawait appstream.send(\n  new EnableUserCommand({\n    UserName: \"alex@example.com\",\n    AuthenticationType: \"USERPOOL\",\n  }),\n);\n```\n\n## Common Pitfalls\n\n- AWS documentation now mixes AppStream and WorkSpaces Applications terminology. The JavaScript package name and client are still `@aws-sdk/client-appstream` and `AppStreamClient`.\n- AppStream pagination is not fully uniform. `DescribeSessionsCommand` uses `Limit`, while `DescribeUsersCommand` and `DescribeUserStackAssociationsCommand` use `MaxResults`.\n- `DescribeFleetsCommand` and `DescribeStacksCommand` page with `NextToken` but do not expose a page-size parameter in the service model.\n- `CreateStreamingURLCommand` defaults to a 60-second URL lifetime. Set `Validity` explicitly if another service or person will open the link.\n- `BatchAssociateUserStackCommand` may return item-level failures in `errors` such as `STACK_NOT_FOUND` or `USER_NAME_NOT_FOUND`.\n- User email addresses are case-sensitive. A mismatched email casing can break create, lookup, enable, disable, and association flows.\n- Do not hardcode credentials in code. Prefer environment variables, shared AWS config, IAM Identity Center, or runtime IAM roles.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets the modular AWS SDK for JavaScript v3 package `@aws-sdk/client-appstream`.\n- The current AWS documentation for this client still points to the AppStream namespace even where the service documentation uses WorkSpaces Applications branding.\n- The examples here use command-based imports and `client.send(...)`, which is the standard v3 usage pattern.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 AppStream client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/appstream/`\n- Amazon AppStream 2.0 API Reference: `https://docs.aws.amazon.com/appstream2/latest/APIReference/Welcome.html`\n- `CreateStreamingURL` API: `https://docs.aws.amazon.com/appstream2/latest/APIReference/API_CreateStreamingURL.html`\n- `DescribeSessions` API: `https://docs.aws.amazon.com/appstream2/latest/APIReference/API_DescribeSessions.html`\n- `CreateUser` API: `https://docs.aws.amazon.com/appstream2/latest/APIReference/API_CreateUser.html`\n- `BatchAssociateUserStack` API: `https://docs.aws.amazon.com/appstream2/latest/APIReference/API_BatchAssociateUserStack.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n"
  },
  {
    "path": "content/aws/docs/appsync/javascript/DOC.md",
    "content": "---\nname: appsync\ndescription: \"AWS SDK for JavaScript v3 client for managing AWS AppSync GraphQL APIs and related AppSync resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,appsync,graphql,realtime,serverless\"\n---\n\n# AWS AppSync SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-appsync` to manage AppSync resources from JavaScript or TypeScript. This package is the AppSync control-plane client: it creates and updates APIs, schemas, auth settings, API keys, data sources, resolvers, and related resources. It does not execute GraphQL operations against your deployed endpoint.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-appsync`, not the legacy `aws-sdk` v2 package.\n- Prefer `AppSyncClient` plus individual commands over the aggregated service client.\n- Set `region` explicitly or provide it through standard AWS configuration.\n- Creating a GraphQL API and creating an API key are separate steps.\n- `StartSchemaCreationCommand` is asynchronous; poll `GetSchemaCreationStatusCommand` until it succeeds or fails.\n- `PutGraphqlApiEnvironmentVariablesCommand` replaces the full environment-variable map for the API, so read the current values first if you need to merge.\n- Current AppSync package versions expose both classic GraphQL API commands such as `CreateGraphqlApiCommand` and newer AppSync Events commands such as `CreateApiCommand` and `CreateChannelNamespaceCommand`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-appsync\n```\n\nIf you want to supply non-default credentials in code, install the AWS credential helpers you actually use. For many Node.js apps, the built-in default credential chain is enough.\n\n## Prerequisites\n\nAppSync is regional. Set AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use named profiles locally, `AWS_PROFILE` also works with the standard AWS SDK credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { AppSyncClient } from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { AppSyncClient } from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  AppSyncClient,\n  GetGraphqlApiCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\n\nconst response = await appsync.send(\n  new GetGraphqlApiCommand({\n    apiId: \"abc123def456\",\n  }),\n);\n\nconsole.log(response.graphqlApi);\n```\n\n## Common Workflows\n\n### List GraphQL APIs with pagination\n\n```javascript\nimport {\n  AppSyncClient,\n  ListGraphqlApisCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await appsync.send(\n    new ListGraphqlApisCommand({\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const api of response.graphqlApis ?? []) {\n    console.log(api.apiId, api.name, api.authenticationType);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\n### Get one API by ID\n\n```javascript\nimport {\n  AppSyncClient,\n  GetGraphqlApiCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\n\nconst { graphqlApi } = await appsync.send(\n  new GetGraphqlApiCommand({\n    apiId: \"abc123def456\",\n  }),\n);\n\nconsole.log({\n  apiId: graphqlApi?.apiId,\n  name: graphqlApi?.name,\n  authenticationType: graphqlApi?.authenticationType,\n  uris: graphqlApi?.uris,\n});\n```\n\nThe returned `graphqlApi` object includes the API ID, auth settings, ARN, and endpoint URI map.\n\n### Create a GraphQL API\n\n```javascript\nimport {\n  AppSyncClient,\n  CreateGraphqlApiCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\n\nconst { graphqlApi } = await appsync.send(\n  new CreateGraphqlApiCommand({\n    name: \"orders-api\",\n    authenticationType: \"API_KEY\",\n    xrayEnabled: true,\n  }),\n);\n\nconsole.log(graphqlApi?.apiId);\n```\n\n`name` and `authenticationType` are required. Valid auth modes in the current service model are `API_KEY`, `AWS_IAM`, `AMAZON_COGNITO_USER_POOLS`, `OPENID_CONNECT`, and `AWS_LAMBDA`.\n\n### Upload a schema and wait for completion\n\n`StartSchemaCreationCommand` accepts the GraphQL schema as bytes and starts an asynchronous job.\n\n```javascript\nimport {\n  AppSyncClient,\n  GetSchemaCreationStatusCommand,\n  StartSchemaCreationCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\n\nconst apiId = \"abc123def456\";\n\nconst schema = /* GraphQL */ `\n  type Query {\n    hello: String\n  }\n\n  schema {\n    query: Query\n  }\n`;\n\nawait appsync.send(\n  new StartSchemaCreationCommand({\n    apiId,\n    definition: Buffer.from(schema, \"utf8\"),\n  }),\n);\n\nfor (;;) {\n  const { status, details } = await appsync.send(\n    new GetSchemaCreationStatusCommand({ apiId }),\n  );\n\n  if (status === \"SUCCESS\") {\n    break;\n  }\n\n  if (status === \"FAILED\") {\n    throw new Error(details ?? \"Schema creation failed\");\n  }\n\n  await new Promise((resolve) => setTimeout(resolve, 2000));\n}\n```\n\n### Create and list API keys\n\nIf your GraphQL API uses `API_KEY` auth, create a key after the API exists.\n\n```javascript\nimport {\n  AppSyncClient,\n  CreateApiKeyCommand,\n  ListApiKeysCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\nconst apiId = \"abc123def456\";\n\nconst { apiKey } = await appsync.send(\n  new CreateApiKeyCommand({\n    apiId,\n    description: \"web-client-dev\",\n  }),\n);\n\nconsole.log(apiKey?.id, apiKey?.expires);\n\nconst { apiKeys } = await appsync.send(\n  new ListApiKeysCommand({\n    apiId,\n    maxResults: 25,\n  }),\n);\n\nfor (const key of apiKeys ?? []) {\n  console.log(key.id, key.description, key.expires, key.deletes);\n}\n```\n\nIf you omit `expires`, AppSync uses the service default. When you provide `expires`, pass seconds since the Unix epoch; AppSync rounds that value down to the nearest hour.\n\n### Read and update GraphQL API environment variables safely\n\n`PutGraphqlApiEnvironmentVariablesCommand` overwrites the full map, so read the current values first when you want to add or update one key.\n\n```javascript\nimport {\n  AppSyncClient,\n  GetGraphqlApiEnvironmentVariablesCommand,\n  PutGraphqlApiEnvironmentVariablesCommand,\n} from \"@aws-sdk/client-appsync\";\n\nconst appsync = new AppSyncClient({ region: \"us-east-1\" });\nconst apiId = \"abc123def456\";\n\nconst current = await appsync.send(\n  new GetGraphqlApiEnvironmentVariablesCommand({ apiId }),\n);\n\nawait appsync.send(\n  new PutGraphqlApiEnvironmentVariablesCommand({\n    apiId,\n    environmentVariables: {\n      ...(current.environmentVariables ?? {}),\n      ORDERS_TABLE: \"orders-dev\",\n      STAGE: \"dev\",\n    },\n  }),\n);\n```\n\nEnvironment-variable keys must start with a letter, be at least two characters long, use only letters, numbers, and underscores, and AppSync allows up to 50 key-value pairs per GraphQL API.\n\n## Related Control-Plane Commands\n\nThe same package also includes commands for other AppSync resources. Common examples in the current model include:\n\n- `CreateDataSourceCommand`, `ListDataSourcesCommand`, `GetDataSourceCommand`\n- `CreateResolverCommand`, `ListResolversCommand`, `GetResolverCommand`\n- `CreateFunctionCommand`, `ListFunctionsCommand`\n- `EvaluateMappingTemplateCommand` and `EvaluateCodeCommand`\n- `CreateApiCommand`, `ListApisCommand`, and `CreateChannelNamespaceCommand` for newer AppSync Events resources\n\nWhen you create resolvers with inline code, the service model requires a `runtime` object and the runtime name must be `APPSYNC_JS`. When you use mapping templates instead, pass `requestMappingTemplate` and `responseMappingTemplate` strings.\n\n## Pitfalls\n\n- This package manages AppSync resources. Use your GraphQL HTTP client against the deployed endpoint for runtime queries and mutations.\n- `StartSchemaCreationCommand` is not synchronous. Always poll `GetSchemaCreationStatusCommand` before assuming the schema is ready.\n- API keys are separate resources. Setting `authenticationType: \"API_KEY\"` on the API does not create a key for clients automatically.\n- `PutGraphqlApiEnvironmentVariablesCommand` replaces the entire environment-variable map, not a single key.\n- API key `expires` and `deletes` values are epoch seconds, and AppSync documents expiration handling at hour granularity.\n- Data sources that access AWS services typically require `serviceRoleArn`; AppSync assumes that IAM role when accessing the backing service.\n- `visibility` defaults to `GLOBAL` when you do not provide it, and the service model documents that this setting cannot be changed after API creation.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-appsync` version `3.1007.0`.\n- The current AppSync service model includes both legacy GraphQL API operations such as `CreateGraphqlApi` and newer API or channel-namespace operations such as `CreateApi` and `CreateChannelNamespace`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 AppSync client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/appsync/`\n- AWS AppSync API Reference: `https://docs.aws.amazon.com/appsync/latest/APIReference/Welcome.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/athena/javascript/DOC.md",
    "content": "---\nname: athena\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Athena query execution, result retrieval, and metadata APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,athena,javascript,nodejs,sql,analytics,query\"\n---\n\n# `@aws-sdk/client-athena`\n\nUse this package for Amazon Athena APIs in AWS SDK for JavaScript v3. The most common application workflow is: submit a SQL statement with `StartQueryExecution`, poll `GetQueryExecution` until the query reaches a terminal state, then page through `GetQueryResults` if you need rows in-process.\n\nAthena is usually called from trusted server-side code. The client works anywhere AWS SDK v3 works, but browser usage needs explicit credentials and careful permission scoping for both Athena and the S3 bucket that stores query results.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-athena\n```\n\nPrefer `AthenaClient` plus explicit command imports. The package also exposes an aggregated `Athena` client, but command-based imports are the safer default for smaller bundles and clearer dependency boundaries.\n\n## Initialize the client\n\n```javascript\nimport { AthenaClient } from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({\n  region: \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already configured AWS access through environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## What This Client Covers\n\n`@aws-sdk/client-athena` covers Athena SQL query execution and most Athena control-plane APIs, including:\n\n- running SQL statements and prepared statements\n- polling query state and runtime statistics\n- reading query results and manifests\n- listing query history, data catalogs, databases, and table metadata\n- managing workgroups, notebooks, and Spark session-oriented Athena APIs\n\nMost application code only needs the query execution flow plus lightweight metadata lookups.\n\n## Core Usage Pattern\n\nStart a query with a database context and an output location for results:\n\n```javascript\nimport {\n  AthenaClient,\n  StartQueryExecutionCommand,\n} from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({ region: \"us-east-1\" });\n\nconst start = await athena.send(\n  new StartQueryExecutionCommand({\n    QueryString: \"SELECT order_id, total FROM analytics.orders LIMIT 10\",\n    QueryExecutionContext: {\n      Catalog: \"AwsDataCatalog\",\n      Database: \"analytics\",\n    },\n    ResultConfiguration: {\n      OutputLocation: \"s3://my-athena-results/query-results/\",\n    },\n    WorkGroup: \"primary\",\n  }),\n);\n\nconst queryExecutionId = start.QueryExecutionId;\n\nif (!queryExecutionId) {\n  throw new Error(\"Athena did not return a query execution id\");\n}\n\nconsole.log(queryExecutionId);\n```\n\nIf your workgroup enforces its own configuration, Athena can ignore client-side result settings such as `OutputLocation` and encryption options.\n\n## Common Operations\n\n### Start a query and poll until it finishes\n\n```javascript\nimport {\n  AthenaClient,\n  GetQueryExecutionCommand,\n  StartQueryExecutionCommand,\n} from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({ region: \"us-east-1\" });\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst start = await athena.send(\n  new StartQueryExecutionCommand({\n    QueryString: `\n      SELECT date_trunc('day', created_at) AS day, count(*) AS orders\n      FROM analytics.orders\n      GROUP BY 1\n      ORDER BY 1 DESC\n      LIMIT 7\n    `,\n    QueryExecutionContext: {\n      Catalog: \"AwsDataCatalog\",\n      Database: \"analytics\",\n    },\n    ResultConfiguration: {\n      OutputLocation: \"s3://my-athena-results/query-results/\",\n    },\n    ResultReuseConfiguration: {\n      ResultReuseByAgeConfiguration: {\n        Enabled: true,\n        MaxAgeInMinutes: 15,\n      },\n    },\n    WorkGroup: \"primary\",\n  }),\n);\n\nconst queryExecutionId = start.QueryExecutionId;\n\nif (!queryExecutionId) {\n  throw new Error(\"Athena did not return a query execution id\");\n}\n\nconst terminalStates = new Set([\"SUCCEEDED\", \"FAILED\", \"CANCELLED\"]);\nlet state = \"QUEUED\";\n\nwhile (!terminalStates.has(state)) {\n  const result = await athena.send(\n    new GetQueryExecutionCommand({\n      QueryExecutionId: queryExecutionId,\n    }),\n  );\n\n  const execution = result.QueryExecution;\n  state = execution?.Status?.State ?? \"UNKNOWN\";\n\n  console.log({\n    state,\n    bytesScanned: execution?.Statistics?.DataScannedInBytes,\n    queueMs: execution?.Statistics?.QueryQueueTimeInMillis,\n  });\n\n  if (state === \"FAILED\" || state === \"CANCELLED\") {\n    throw new Error(\n      execution?.Status?.AthenaError?.ErrorMessage ??\n        execution?.Status?.StateChangeReason ??\n        `Athena query ended in state ${state}`,\n    );\n  }\n\n  if (state !== \"SUCCEEDED\") {\n    await sleep(2000);\n  }\n}\n```\n\n`StartQueryExecution` only submits work. If the next step depends on results, always poll `GetQueryExecution` until the state is terminal.\n\n### Read rows from a completed query\n\n```javascript\nimport {\n  AthenaClient,\n  GetQueryResultsCommand,\n} from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({ region: \"us-east-1\" });\n\nasync function getAllRows(queryExecutionId) {\n  let nextToken;\n  const pages = [];\n\n  do {\n    const page = await athena.send(\n      new GetQueryResultsCommand({\n        QueryExecutionId: queryExecutionId,\n        MaxResults: 1000,\n        NextToken: nextToken,\n      }),\n    );\n\n    pages.push(page);\n    nextToken = page.NextToken;\n  } while (nextToken);\n\n  const firstPage = pages[0];\n  const columnNames =\n    firstPage?.ResultSet?.ResultSetMetadata?.ColumnInfo?.map(\n      (column) => column.Name ?? \"\",\n    ) ?? [];\n\n  const rows = pages.flatMap((page) => page.ResultSet?.Rows ?? []);\n\n  return rows.slice(1).map((row) => {\n    return Object.fromEntries(\n      columnNames.map((name, index) => [\n        name,\n        row.Data?.[index]?.VarCharValue ?? null,\n      ]),\n    );\n  });\n}\n\nconst rows = await getAllRows(\"1234abcd-12ab-34cd-56ef-1234567890ab\");\nconsole.log(rows);\n```\n\nUse `ResultSetMetadata.ColumnInfo` to build stable column mappings. `GetQueryResults` is paginated, so do not assume a single response contains the full result set.\n\n### List databases in a data catalog\n\n```javascript\nimport {\n  AthenaClient,\n  ListDatabasesCommand,\n} from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await athena.send(\n    new ListDatabasesCommand({\n      CatalogName: \"AwsDataCatalog\",\n      MaxResults: 50,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const database of page.DatabaseList ?? []) {\n    console.log(database.Name);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nUse the Athena metadata APIs when you need lightweight catalog visibility from the same client that runs queries.\n\n### Stop a running query\n\n```javascript\nimport {\n  AthenaClient,\n  StopQueryExecutionCommand,\n} from \"@aws-sdk/client-athena\";\n\nconst athena = new AthenaClient({ region: \"us-east-1\" });\n\nawait athena.send(\n  new StopQueryExecutionCommand({\n    QueryExecutionId: \"1234abcd-12ab-34cd-56ef-1234567890ab\",\n  }),\n);\n```\n\nCancellation is useful when a user abandons an interactive request or a workflow exceeds a cost or time budget.\n\n## Athena-Specific Gotchas\n\n- `StartQueryExecution` does not wait for completion; you must inspect `GetQueryExecution` for `QUEUED`, `RUNNING`, `SUCCEEDED`, `FAILED`, or `CANCELLED`.\n- Query results need an output location. Supply `ResultConfiguration.OutputLocation` unless the workgroup already defines and enforces the results configuration.\n- `GetQueryResults` also depends on Amazon S3 access to the Athena results location, not just Athena API permissions.\n- Query results are paginated with `NextToken`. Large result sets and manifest responses require repeated calls.\n- `ListQueryExecutions` returns query history for only 45 days.\n- Metadata APIs such as `ListDatabases` and `ListDataCatalogs` can require `WorkGroup` in IAM Identity Center-enabled setups.\n- For failed queries, inspect both `Status.StateChangeReason` and `Status.AthenaError` instead of logging only the terminal state.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-s3`: manage Athena result buckets or read raw result objects and manifests directly from S3.\n- `@aws-sdk/client-glue`: broader Glue Data Catalog, crawler, and ETL management beyond Athena's own metadata endpoints.\n- `@aws-sdk/credential-providers`: explicit credential providers for Cognito, shared config, or other non-default auth flows.\n"
  },
  {
    "path": "content/aws/docs/auto-scaling/javascript/DOC.md",
    "content": "---\nname: auto-scaling\ndescription: \"Amazon EC2 Auto Scaling SDK for JavaScript v3 guide for inspecting groups, updating capacity, and managing scaling policies\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,auto-scaling,ec2,javascript,nodejs,scaling,autoscaling\"\n---\n\n# Amazon EC2 Auto Scaling SDK for JavaScript v3 Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-auto-scaling` for **EC2 Auto Scaling group** management in JavaScript: listing groups, changing desired capacity, updating group settings, attaching target groups, creating scaling policies, and starting instance refreshes.\n\nDo **not** use this package for other AWS scaling systems:\n\n- Use `@aws-sdk/client-application-auto-scaling` for services such as ECS, DynamoDB, Aurora, Lambda provisioned concurrency, and SageMaker variants that integrate with Application Auto Scaling.\n- Use `@aws-sdk/client-ec2` to create or update launch templates and inspect the underlying instances.\n- Use `@aws-sdk/client-elastic-load-balancing-v2` to create target groups and load balancers before attaching them to an Auto Scaling group.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-auto-scaling\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/client-ec2 @aws-sdk/client-elastic-load-balancing-v2 @aws-sdk/credential-providers\n```\n\nExamples in this guide use ESM imports and the AWS SDK v3 command pattern: `client.send(new Command(input))`.\n\n## Credentials And Region\n\nThe client uses the standard AWS SDK for JavaScript v3 credential provider chain. For local development, set a region and either a profile or direct credentials.\n\nPreferred local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\n```\n\nDirect environment credentials also work:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nEC2 Auto Scaling is regional. Use the same region for the Auto Scaling group, launch template, subnets, and any attached target groups.\n\n## Initialize The Client\n\n```javascript\nimport { AutoScalingClient } from \"@aws-sdk/client-auto-scaling\";\n\nexport const autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nFor most server-side applications, one shared client instance per region is enough.\n\n## Core Usage\n\n### List And Inspect Auto Scaling Groups\n\n`DescribeAutoScalingGroupsCommand` is the quickest way to confirm that the account and region contain the groups your application expects.\n\n```javascript\nimport {\n  AutoScalingClient,\n  DescribeAutoScalingGroupsCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await autoScaling.send(\n    new DescribeAutoScalingGroupsCommand({\n      MaxRecords: 20,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const group of page.AutoScalingGroups ?? []) {\n    console.log({\n      name: group.AutoScalingGroupName,\n      minSize: group.MinSize,\n      maxSize: group.MaxSize,\n      desiredCapacity: group.DesiredCapacity,\n      instances: group.Instances?.length ?? 0,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nTo inspect one specific group, pass `AutoScalingGroupNames`:\n\n```javascript\nconst response = await autoScaling.send(\n  new DescribeAutoScalingGroupsCommand({\n    AutoScalingGroupNames: [\"web-prod-asg\"],\n  }),\n);\n\nconst group = response.AutoScalingGroups?.[0];\nconsole.log(group?.AutoScalingGroupName, group?.LaunchTemplate, group?.VPCZoneIdentifier);\n```\n\n### Change Desired Capacity Immediately\n\nUse `SetDesiredCapacityCommand` when you want to scale the group to a known size now.\n\n```javascript\nimport {\n  AutoScalingClient,\n  SetDesiredCapacityCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait autoScaling.send(\n  new SetDesiredCapacityCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    DesiredCapacity: 6,\n    HonorCooldown: true,\n  }),\n);\n```\n\nKeep `DesiredCapacity` inside the group's `MinSize` and `MaxSize` range.\n\n### Update Group Capacity Limits Or Launch Template Settings\n\nUse `UpdateAutoScalingGroupCommand` to change steady-state settings such as min size, max size, desired capacity, health check grace period, subnets, or launch template reference.\n\n```javascript\nimport {\n  AutoScalingClient,\n  UpdateAutoScalingGroupCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait autoScaling.send(\n  new UpdateAutoScalingGroupCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    MinSize: 2,\n    MaxSize: 10,\n    DesiredCapacity: 4,\n    HealthCheckType: \"EC2\",\n    HealthCheckGracePeriod: 300,\n    LaunchTemplate: {\n      LaunchTemplateName: \"web-prod-template\",\n      Version: \"$Latest\",\n    },\n  }),\n);\n```\n\nIf you reference a launch template here, that launch template must already exist in EC2.\n\n### Attach Existing Target Groups\n\nUse `AttachLoadBalancerTargetGroupsCommand` after the target groups already exist in Elastic Load Balancing v2.\n\n```javascript\nimport {\n  AttachLoadBalancerTargetGroupsCommand,\n  AutoScalingClient,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait autoScaling.send(\n  new AttachLoadBalancerTargetGroupsCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    TargetGroupARNs: [\n      \"arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/web-blue/0123456789abcdef\",\n    ],\n  }),\n);\n```\n\n### Create A Target Tracking Scaling Policy\n\nUse `PutScalingPolicyCommand` with `PolicyType: \"TargetTrackingScaling\"` when you want Auto Scaling to adjust capacity toward a metric target.\n\n```javascript\nimport {\n  AutoScalingClient,\n  PutScalingPolicyCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await autoScaling.send(\n  new PutScalingPolicyCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    PolicyName: \"cpu-target-50\",\n    PolicyType: \"TargetTrackingScaling\",\n    EstimatedInstanceWarmup: 300,\n    TargetTrackingConfiguration: {\n      PredefinedMetricSpecification: {\n        PredefinedMetricType: \"ASGAverageCPUUtilization\",\n      },\n      TargetValue: 50,\n    },\n  }),\n);\n\nconsole.log(response.PolicyARN);\n```\n\n### Roll Out A New Launch Template Version With Instance Refresh\n\nAfter updating a group's launch template or mixed instances policy, use `StartInstanceRefreshCommand` to replace instances gradually.\n\n```javascript\nimport {\n  AutoScalingClient,\n  DescribeInstanceRefreshesCommand,\n  StartInstanceRefreshCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst started = await autoScaling.send(\n  new StartInstanceRefreshCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    Strategy: \"Rolling\",\n    Preferences: {\n      MinHealthyPercentage: 90,\n      InstanceWarmup: 300,\n    },\n  }),\n);\n\nconsole.log(started.InstanceRefreshId);\n\nconst refreshes = await autoScaling.send(\n  new DescribeInstanceRefreshesCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    InstanceRefreshIds: [started.InstanceRefreshId],\n  }),\n);\n\nfor (const refresh of refreshes.InstanceRefreshes ?? []) {\n  console.log(\n    refresh.InstanceRefreshId,\n    refresh.Status,\n    refresh.PercentageComplete,\n    refresh.StatusReason,\n  );\n}\n```\n\n`StartInstanceRefreshCommand` starts the rollout and returns immediately. Poll `DescribeInstanceRefreshesCommand` if you need completion status.\n\n### Inspect Recent Scaling Activity\n\nUse `DescribeScalingActivitiesCommand` when you need to understand why a scale-out, scale-in, launch, terminate, or refresh step happened.\n\n```javascript\nimport {\n  AutoScalingClient,\n  DescribeScalingActivitiesCommand,\n} from \"@aws-sdk/client-auto-scaling\";\n\nconst autoScaling = new AutoScalingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await autoScaling.send(\n  new DescribeScalingActivitiesCommand({\n    AutoScalingGroupName: \"web-prod-asg\",\n    MaxRecords: 20,\n  }),\n);\n\nfor (const activity of response.Activities ?? []) {\n  console.log({\n    id: activity.ActivityId,\n    status: activity.StatusCode,\n    description: activity.Description,\n    cause: activity.Cause,\n    startTime: activity.StartTime,\n    endTime: activity.EndTime,\n  });\n}\n```\n\n## Common Pitfalls\n\n- Do not confuse EC2 Auto Scaling with Application Auto Scaling. The package names are similar, but they manage different AWS services.\n- Do not assume this package creates launch templates, target groups, or load balancers. Those are separate resources managed through other AWS services.\n- Do not set `DesiredCapacity` outside the group's `MinSize` and `MaxSize` bounds.\n- Do not hardcode AWS credentials in source files. Use environment variables, shared config, or IAM roles.\n- Do not expect `StartInstanceRefreshCommand` or scaling policy changes to block until the group becomes steady. Check `DescribeInstanceRefreshesCommand` and `DescribeScalingActivitiesCommand` for progress.\n- Do not mix regions across the Auto Scaling group, launch template, and attached target groups.\n\n## Version Scope\n\n- This guide targets `@aws-sdk/client-auto-scaling@3.1007.0`.\n- Examples use the modular AWS SDK for JavaScript v3 client and explicit command imports.\n- The npm package slug is `@aws-sdk/client-auto-scaling`, while the runtime client class is `AutoScalingClient`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Auto Scaling client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/auto-scaling/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- Amazon EC2 Auto Scaling API Reference: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/Welcome.html`\n- `DescribeAutoScalingGroups` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html`\n- `SetDesiredCapacity` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_SetDesiredCapacity.html`\n- `UpdateAutoScalingGroup` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_UpdateAutoScalingGroup.html`\n- `PutScalingPolicy` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_PutScalingPolicy.html`\n- `AttachLoadBalancerTargetGroups` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_AttachLoadBalancerTargetGroups.html`\n- `StartInstanceRefresh` API: `https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_StartInstanceRefresh.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-auto-scaling`\n"
  },
  {
    "path": "content/aws/docs/backup/javascript/DOC.md",
    "content": "---\nname: backup\ndescription: \"AWS SDK for JavaScript v3 client for managing AWS Backup vaults, plans, selections, backup jobs, and restore jobs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,backup,javascript,nodejs,recovery,backup-vault,restore\"\n---\n\n# AWS Backup SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-backup` for the AWS Backup control plane in JavaScript or TypeScript. Common tasks include creating backup vaults, defining backup plans, attaching protected resources to a plan, starting on-demand backup jobs, listing recovery points, and starting restore jobs.\n\nThis package manages AWS Backup resources and jobs in AWS. It does not back up local files by itself.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-backup`, not the legacy `aws-sdk` v2 package.\n- Prefer `BackupClient` plus individual command imports over broader service wrappers.\n- Set `region` explicitly in code or standard AWS config before creating the client.\n- `CreateBackupPlanCommand` defines rules, but resources are not protected until you also call `CreateBackupSelectionCommand`.\n- `StartBackupJobCommand` and `StartRestoreJobCommand` are asynchronous. Poll `DescribeBackupJobCommand` or `DescribeRestoreJobCommand` for terminal state.\n- `StartRestoreJobCommand` requires a `Metadata` map. Call `GetRecoveryPointRestoreMetadataCommand` first instead of guessing restore keys.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-backup\n```\n\nIf you need named-profile or assume-role helpers in application code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nAWS Backup is regional. Configure credentials and region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { BackupClient } from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { BackupClient } from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { BackupClient } from \"@aws-sdk/client-backup\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst backup = new BackupClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config, ECS task credentials, EC2 instance metadata, web identity, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  BackupClient,\n  ListBackupVaultsCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst { BackupVaultList } = await backup.send(\n  new ListBackupVaultsCommand({\n    MaxResults: 20,\n  }),\n);\n\nfor (const vault of BackupVaultList ?? []) {\n  console.log(vault.BackupVaultName, vault.BackupVaultArn);\n}\n```\n\n## Common Workflows\n\n### Create a backup vault\n\n```javascript\nimport {\n  BackupClient,\n  CreateBackupVaultCommand,\n  DescribeBackupVaultCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst { BackupVaultName, BackupVaultArn } = await backup.send(\n  new CreateBackupVaultCommand({\n    BackupVaultName: \"primary-vault\",\n    EncryptionKeyArn: \"arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555\",\n    BackupVaultTags: {\n      Environment: \"prod\",\n      ManagedBy: \"app\",\n    },\n  }),\n);\n\nconst vault = await backup.send(\n  new DescribeBackupVaultCommand({\n    BackupVaultName: BackupVaultName,\n  }),\n);\n\nconsole.log(BackupVaultArn);\nconsole.log(vault.NumberOfRecoveryPoints, vault.EncryptionKeyArn, vault.Locked);\n```\n\nUse `DescribeBackupVaultCommand` when you need current vault settings such as recovery-point count, KMS key ARN, or vault-lock retention fields.\n\n### Configure SNS notifications for a vault\n\n```javascript\nimport {\n  BackupClient,\n  GetBackupVaultNotificationsCommand,\n  PutBackupVaultNotificationsCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nawait backup.send(\n  new PutBackupVaultNotificationsCommand({\n    BackupVaultName: \"primary-vault\",\n    SNSTopicArn: \"arn:aws:sns:us-east-1:123456789012:backup-events\",\n    BackupVaultEvents: [\n      \"BACKUP_JOB_STARTED\",\n      \"BACKUP_JOB_COMPLETED\",\n      \"BACKUP_JOB_FAILED\",\n      \"RESTORE_JOB_COMPLETED\",\n      \"RESTORE_JOB_FAILED\",\n    ],\n  }),\n);\n\nconst notifications = await backup.send(\n  new GetBackupVaultNotificationsCommand({\n    BackupVaultName: \"primary-vault\",\n  }),\n);\n\nconsole.log(notifications.SNSTopicArn, notifications.BackupVaultEvents);\n```\n\nUse vault notifications when you want push-style job events instead of tight polling loops.\n\n### Create a backup plan and attach resources\n\nCreate the plan first, then create a selection that points AWS Backup at concrete resources.\n\n```javascript\nimport {\n  BackupClient,\n  CreateBackupPlanCommand,\n  CreateBackupSelectionCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst plan = await backup.send(\n  new CreateBackupPlanCommand({\n    BackupPlan: {\n      BackupPlanName: \"daily-ebs-plan\",\n      Rules: [\n        {\n          RuleName: \"daily-ebs\",\n          TargetBackupVaultName: \"primary-vault\",\n          ScheduleExpression: \"cron(0 5 ? * * *)\",\n          StartWindowMinutes: 60,\n          CompletionWindowMinutes: 180,\n          Lifecycle: {\n            DeleteAfterDays: 30,\n          },\n          RecoveryPointTags: {\n            Environment: \"prod\",\n            Policy: \"daily\",\n          },\n        },\n      ],\n    },\n  }),\n);\n\nawait backup.send(\n  new CreateBackupSelectionCommand({\n    BackupPlanId: plan.BackupPlanId,\n    BackupSelection: {\n      SelectionName: \"production-ebs-volumes\",\n      IamRoleArn: \"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole\",\n      Resources: [\n        \"arn:aws:ec2:us-east-1:123456789012:volume/vol-0123456789abcdef0\",\n      ],\n    },\n  }),\n);\n```\n\nIf you only create the plan, nothing is actually assigned to it yet. `CreateBackupSelectionCommand` is the step that binds resources and the IAM role AWS Backup should use.\n\n### Start an on-demand backup job and poll for completion\n\n```javascript\nimport {\n  BackupClient,\n  DescribeBackupJobCommand,\n  StartBackupJobCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst { BackupJobId, RecoveryPointArn } = await backup.send(\n  new StartBackupJobCommand({\n    BackupVaultName: \"primary-vault\",\n    ResourceArn: \"arn:aws:ec2:us-east-1:123456789012:volume/vol-0123456789abcdef0\",\n    IamRoleArn: \"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole\",\n    Lifecycle: {\n      DeleteAfterDays: 30,\n    },\n    RecoveryPointTags: {\n      Environment: \"prod\",\n      Trigger: \"manual\",\n    },\n    IdempotencyToken: \"manual-ebs-backup-20260313\",\n  }),\n);\n\nconsole.log(BackupJobId, RecoveryPointArn);\n\nasync function waitForBackupJob(backupJobId) {\n  const doneStates = new Set([\"COMPLETED\", \"ABORTED\", \"FAILED\", \"EXPIRED\", \"PARTIAL\"]);\n\n  for (;;) {\n    const job = await backup.send(\n      new DescribeBackupJobCommand({\n        BackupJobId: backupJobId,\n      }),\n    );\n\n    console.log(job.State, job.PercentDone, job.StatusMessage);\n\n    if (!doneStates.has(job.State)) {\n      await new Promise((resolve) => setTimeout(resolve, 5000));\n      continue;\n    }\n\n    if (job.State !== \"COMPLETED\") {\n      throw new Error(`Backup job ended in state ${job.State}: ${job.StatusMessage ?? \"unknown\"}`);\n    }\n\n    return job;\n  }\n}\n\nawait waitForBackupJob(BackupJobId);\n```\n\n`StartBackupJobCommand` requires three core inputs: `BackupVaultName`, `ResourceArn`, and `IamRoleArn`. Use `IdempotencyToken` when retries could otherwise create duplicate work.\n\n### List recovery points in a vault\n\n```javascript\nimport {\n  BackupClient,\n  ListRecoveryPointsByBackupVaultCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nlet NextToken;\n\ndo {\n  const page = await backup.send(\n    new ListRecoveryPointsByBackupVaultCommand({\n      BackupVaultName: \"primary-vault\",\n      MaxResults: 100,\n      NextToken,\n    }),\n  );\n\n  for (const point of page.RecoveryPoints ?? []) {\n    console.log(point.RecoveryPointArn, point.ResourceType, point.Status, point.CreationDate);\n  }\n\n  NextToken = page.NextToken;\n} while (NextToken);\n```\n\nUse `ByResourceArn`, `ByResourceType`, `ByBackupPlanId`, or date filters if you only need a narrower subset.\n\n### Start a restore job from a recovery point\n\nRestore metadata is resource-specific. Fetch it first, adjust any values your restore target needs, then pass that map into `StartRestoreJobCommand`.\n\n```javascript\nimport {\n  BackupClient,\n  DescribeRestoreJobCommand,\n  GetRecoveryPointRestoreMetadataCommand,\n  StartRestoreJobCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst recoveryPointArn = \"arn:aws:backup:us-east-1:123456789012:recovery-point:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\";\n\nconst restoreMetadata = await backup.send(\n  new GetRecoveryPointRestoreMetadataCommand({\n    BackupVaultName: \"primary-vault\",\n    RecoveryPointArn: recoveryPointArn,\n  }),\n);\n\nif (!restoreMetadata.RestoreMetadata) {\n  throw new Error(\"AWS Backup did not return restore metadata for this recovery point.\");\n}\n\nconst { RestoreJobId } = await backup.send(\n  new StartRestoreJobCommand({\n    RecoveryPointArn: recoveryPointArn,\n    ResourceType: restoreMetadata.ResourceType,\n    Metadata: {\n      ...restoreMetadata.RestoreMetadata,\n    },\n    IamRoleArn: \"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole\",\n    IdempotencyToken: \"restore-ebs-20260313\",\n  }),\n);\n\nasync function waitForRestoreJob(restoreJobId) {\n  const doneStates = new Set([\"COMPLETED\", \"ABORTED\", \"FAILED\"]);\n\n  for (;;) {\n    const job = await backup.send(\n      new DescribeRestoreJobCommand({\n        RestoreJobId: restoreJobId,\n      }),\n    );\n\n    console.log(job.Status, job.PercentDone, job.StatusMessage);\n\n    if (!doneStates.has(job.Status)) {\n      await new Promise((resolve) => setTimeout(resolve, 5000));\n      continue;\n    }\n\n    if (job.Status !== \"COMPLETED\") {\n      throw new Error(`Restore job ended in status ${job.Status}: ${job.StatusMessage ?? \"unknown\"}`);\n    }\n\n    return job;\n  }\n}\n\nconst restoreJob = await waitForRestoreJob(RestoreJobId);\nconsole.log(restoreJob.CreatedResourceArn);\n```\n\nFor many workloads you must edit some metadata values before restore, such as destination identifiers or networking-related fields. Do not hard-code those keys unless you have confirmed the resource type's restore requirements.\n\n### Update a recovery point lifecycle\n\n```javascript\nimport {\n  BackupClient,\n  UpdateRecoveryPointLifecycleCommand,\n} from \"@aws-sdk/client-backup\";\n\nconst backup = new BackupClient({ region: \"us-east-1\" });\n\nconst response = await backup.send(\n  new UpdateRecoveryPointLifecycleCommand({\n    BackupVaultName: \"primary-vault\",\n    RecoveryPointArn: \"arn:aws:backup:us-east-1:123456789012:recovery-point:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\n    Lifecycle: {\n      MoveToColdStorageAfterDays: 30,\n      DeleteAfterDays: 365,\n    },\n  }),\n);\n\nconsole.log(response.Lifecycle, response.CalculatedLifecycle);\n```\n\n## Practical Notes\n\n- AWS Backup is a regional control-plane API. Region mismatches often look like missing vaults, plans, or recovery points.\n- The service model exposes many list operations with `NextToken` and `MaxResults`. Do not assume a single list response is complete in larger accounts.\n- Backup jobs and restore jobs are asynchronous. Treat `Start*Job` responses as accepted work, not finished work.\n- `ListProtectedResourcesCommand` is useful when you need the inventory AWS Backup currently knows about before choosing a resource ARN to back up or restore.\n- `GetRecoveryPointRestoreMetadataCommand` is the safest starting point for restores because the `Metadata` map is resource-specific.\n- Temporary AWS credentials require `AWS_SESSION_TOKEN` in addition to access key ID and secret access key.\n\n## Common Pitfalls\n\n- Creating a backup plan and forgetting to create a selection, which leaves the plan with no protected resources.\n- Treating `ListBackupJobsCommand` or `ListRestoreJobsCommand` as a detailed status API. Use the matching `Describe*JobCommand` call for the full job record.\n- Hand-writing restore metadata without first calling `GetRecoveryPointRestoreMetadataCommand`.\n- Using an IAM role ARN that AWS Backup cannot assume for the target resource.\n- Looking in the wrong region when a vault or recovery point appears to be missing.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-backup` version `3.1007.0`.\n- AWS publishes the JavaScript SDK service docs under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for current command names and request shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Backup client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/backup/`\n- AWS Backup `CreateBackupVault` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_CreateBackupVault.html`\n- AWS Backup `CreateBackupPlan` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_CreateBackupPlan.html`\n- AWS Backup `CreateBackupSelection` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_CreateBackupSelection.html`\n- AWS Backup `StartBackupJob` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_StartBackupJob.html`\n- AWS Backup `GetRecoveryPointRestoreMetadata` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_GetRecoveryPointRestoreMetadata.html`\n- AWS Backup `StartRestoreJob` API: `https://docs.aws.amazon.com/aws-backup/latest/devguide/API_StartRestoreJob.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-backup`\n"
  },
  {
    "path": "content/aws/docs/batch/javascript/DOC.md",
    "content": "---\nname: batch\ndescription: \"AWS SDK for JavaScript v3 client for submitting, listing, inspecting, canceling, and terminating AWS Batch jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,batch,javascript,nodejs,job-queue,containers\"\n---\n\n# AWS Batch SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-batch` to manage AWS Batch jobs and related Batch resources from JavaScript or TypeScript. Common tasks include describing job queues, submitting jobs, polling job status, listing queued or running jobs, and canceling or terminating work.\n\nThis package is the Batch control-plane client. It submits and manages jobs in AWS, but it does not run the container or job process locally.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-batch`, not the legacy `aws-sdk` v2 package.\n- Prefer `BatchClient` plus individual command imports over broader service wrappers.\n- Set `region` explicitly in code or through standard AWS configuration.\n- `SubmitJobCommand` only accepts the job into Batch. It does not wait for completion.\n- Use `DescribeJobsCommand` for detailed status and container-level details. `ListJobsCommand` is a summary API.\n- Use `CancelJobCommand` for work that has not started running yet. Use `TerminateJobCommand` once the job is starting or running.\n- Pin the job definition revision with `name:revision` or a full ARN when exact runtime behavior matters.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-batch\n```\n\nIf you need shared-profile, IAM Identity Center, or assume-role helpers in code, install the credential provider package you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nAWS Batch is regional. Configure AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { BatchClient } from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { BatchClient } from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { BatchClient } from \"@aws-sdk/client-batch\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst batch = new BatchClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  BatchClient,\n  DescribeJobQueuesCommand,\n} from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({ region: \"us-east-1\" });\n\nconst response = await batch.send(\n  new DescribeJobQueuesCommand({\n    jobQueues: [\"high-priority\"],\n  }),\n);\n\nconsole.log(response.jobQueues?.[0]?.jobQueueName, response.jobQueues?.[0]?.state);\n```\n\n## Common Workflows\n\n### Submit a job\n\n```javascript\nimport {\n  BatchClient,\n  SubmitJobCommand,\n} from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({ region: \"us-east-1\" });\n\nconst { jobId, jobName } = await batch.send(\n  new SubmitJobCommand({\n    jobName: \"daily-etl-2026-03-13\",\n    jobQueue: \"high-priority\",\n    jobDefinition: \"etl-job:3\",\n    containerOverrides: {\n      command: [\"node\", \"dist/jobs/daily-etl.js\"],\n      environment: [\n        { name: \"RUN_DATE\", value: \"2026-03-13\" },\n        { name: \"LOG_LEVEL\", value: \"info\" },\n      ],\n    },\n    retryStrategy: {\n      attempts: 3,\n    },\n    timeout: {\n      attemptDurationSeconds: 3600,\n    },\n  }),\n);\n\nconsole.log(jobId, jobName);\n```\n\n`jobQueue` and `jobDefinition` can be names or ARNs. For deployment automation, prefer a fixed job definition revision such as `etl-job:3` so a later active revision does not change behavior unexpectedly.\n\n### Poll a job until it finishes\n\n`SubmitJobCommand` returns immediately after the job is accepted. Poll `DescribeJobsCommand` until the status reaches a terminal state.\n\n```javascript\nimport {\n  BatchClient,\n  DescribeJobsCommand,\n} from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({ region: \"us-east-1\" });\n\nasync function waitForJob(jobId) {\n  for (;;) {\n    const { jobs } = await batch.send(\n      new DescribeJobsCommand({\n        jobs: [jobId],\n      }),\n    );\n\n    const job = jobs?.[0];\n\n    if (!job) {\n      throw new Error(`Job not found: ${jobId}`);\n    }\n\n    console.log(job.status, job.statusReason);\n\n    if (job.status === \"SUCCEEDED\") {\n      return job;\n    }\n\n    if (job.status === \"FAILED\") {\n      throw new Error(job.statusReason ?? \"Batch job failed\");\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 5000));\n  }\n}\n```\n\nFor container jobs, `DescribeJobsCommand` is also the place to inspect fields such as `container.exitCode`, `container.reason`, and attempt history after a failure.\n\n### List jobs in a queue with pagination\n\n```javascript\nimport {\n  BatchClient,\n  ListJobsCommand,\n} from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await batch.send(\n    new ListJobsCommand({\n      jobQueue: \"high-priority\",\n      jobStatus: \"RUNNING\",\n      maxResults: 100,\n      nextToken,\n    }),\n  );\n\n  for (const summary of response.jobSummaryList ?? []) {\n    console.log(summary.jobId, summary.jobName, summary.status, summary.createdAt);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\n`ListJobsCommand` returns summary records. If you need detailed container, retry, or attempt information, pass the returned job IDs to `DescribeJobsCommand`.\n\n### Cancel or terminate a job\n\nAWS Batch distinguishes between canceling queued work and terminating work that has already started.\n\n```javascript\nimport {\n  BatchClient,\n  CancelJobCommand,\n  TerminateJobCommand,\n} from \"@aws-sdk/client-batch\";\n\nconst batch = new BatchClient({ region: \"us-east-1\" });\n\nawait batch.send(\n  new CancelJobCommand({\n    jobId: \"0d9f0f32-1234-5678-90ab-cdef12345678\",\n    reason: \"Superseded by a newer run\",\n  }),\n);\n\nawait batch.send(\n  new TerminateJobCommand({\n    jobId: \"7de1b7b9-1234-5678-90ab-cdef12345678\",\n    reason: \"Manual rollback\",\n  }),\n);\n```\n\nIf you are not sure whether the job has started, read the current status first with `DescribeJobsCommand` and choose the operation accordingly.\n\n## Practical Notes\n\n- Batch is regional. The client region must match the region where the job queue, job definition, and compute environment exist.\n- Browser use is uncommon because this package manages AWS infrastructure and needs AWS credentials with Batch permissions.\n- `SubmitJobCommand` does not prove the job completed successfully. Always follow with status checks when the result matters.\n- `ListJobsCommand` is useful for dashboards and polling loops, but it does not replace `DescribeJobsCommand` for debugging a failure.\n- Batch resource names and ARNs are both accepted in many APIs. Be consistent inside one code path to avoid mixing regions, accounts, or revisions.\n\n## Common Pitfalls\n\n- Sending a job definition name without a revision when your deployment expects a specific revision.\n- Treating a successful `SubmitJobCommand` response as job success instead of queue acceptance.\n- Calling `CancelJobCommand` on a job that is already starting or running.\n- Forgetting to set the region explicitly in scripts and workers, which usually turns into resource-not-found errors against the wrong region.\n- Debugging only from `ListJobsCommand` output instead of loading full job details with `DescribeJobsCommand`.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-batch` version `3.1007.0`.\n- The current package surface includes the command-oriented client pattern shown here, including `SubmitJobCommand`, `DescribeJobsCommand`, `ListJobsCommand`, `CancelJobCommand`, `TerminateJobCommand`, and `DescribeJobQueuesCommand`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Batch client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/batch/`\n- AWS Batch API Reference: `https://docs.aws.amazon.com/batch/latest/APIReference/Welcome.html`\n- AWS Batch `SubmitJob` API: `https://docs.aws.amazon.com/batch/latest/APIReference/API_SubmitJob.html`\n- AWS Batch `DescribeJobs` API: `https://docs.aws.amazon.com/batch/latest/APIReference/API_DescribeJobs.html`\n- AWS Batch `ListJobs` API: `https://docs.aws.amazon.com/batch/latest/APIReference/API_ListJobs.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/bedrock/javascript/DOC.md",
    "content": "---\nname: bedrock\ndescription: \"AWS SDK for JavaScript v3 Bedrock control-plane client for model discovery and Bedrock resource management.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,bedrock,javascript,nodejs,genai,foundation-models,llm,control-plane\"\n---\n\n# `@aws-sdk/client-bedrock`\n\nUse this package for the Amazon Bedrock **control plane** in AWS SDK for JavaScript v3. It is the package for discovering Bedrock models and managing Bedrock-side resources. It is **not** the package that sends prompts to models.\n\nIf you need to invoke a model, stream a response, or use chat-style inference APIs, use `@aws-sdk/client-bedrock-runtime` instead.\n\nPrefer `BedrockClient` plus explicit command imports. The package also exposes an aggregated client, but command-based imports are the safer default for smaller bundles and clearer call sites.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-bedrock\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/client-bedrock-runtime @aws-sdk/credential-providers\n```\n\n## What This Client Covers\n\nUse `@aws-sdk/client-bedrock` for Bedrock management tasks such as:\n\n- discovering which foundation models are available in a region\n- reading model metadata such as provider, modalities, lifecycle status, and streaming support\n- administrative Bedrock workflows that belong to the service control plane rather than runtime inference\n\nKeep the boundary clear:\n\n- `@aws-sdk/client-bedrock`: discovery and management\n- `@aws-sdk/client-bedrock-runtime`: inference and response streaming\n\n## Initialize the client\n\n```javascript\nimport { BedrockClient } from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain usually works if AWS access is already configured through environment variables, shared AWS config files, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: avoid using this control-plane client directly in the browser unless you have a tightly scoped browser-safe credential story. Bedrock management operations are usually server-side.\n- Region matters a lot with Bedrock. Model availability, account access, and related resources vary by region.\n- Set the region in code, with `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  BedrockClient,\n  ListFoundationModelsCommand,\n} from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({ region: \"us-east-1\" });\n\nconst response = await bedrock.send(new ListFoundationModelsCommand({}));\n\nfor (const model of response.modelSummaries ?? []) {\n  console.log({\n    modelId: model.modelId,\n    modelName: model.modelName,\n    providerName: model.providerName,\n    inputModalities: model.inputModalities,\n    outputModalities: model.outputModalities,\n    streaming: model.responseStreamingSupported,\n    lifecycleStatus: model.modelLifecycle?.status,\n  });\n}\n```\n\nFor most application code, the control-plane client is the place where you discover or validate a model identifier before passing that identifier into your runtime inference flow.\n\n## Common Operations\n\n### Discover active text-capable models in a region\n\n`ListFoundationModels` is the safest starting point when your code needs to discover which Bedrock model IDs are usable in a given region.\n\n```javascript\nimport {\n  BedrockClient,\n  ListFoundationModelsCommand,\n} from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({ region: \"us-east-1\" });\n\nconst response = await bedrock.send(new ListFoundationModelsCommand({}));\n\nconst textModels = (response.modelSummaries ?? []).filter((model) => {\n  const lifecycleStatus = model.modelLifecycle?.status?.toUpperCase();\n  const outputModalities = (model.outputModalities ?? []).map((value) => value.toLowerCase());\n\n  return lifecycleStatus === \"ACTIVE\" && outputModalities.includes(\"text\");\n});\n\nfor (const model of textModels) {\n  console.log(model.modelId, model.providerName, model.responseStreamingSupported);\n}\n```\n\nThis is a practical way to avoid hard-coding assumptions about which providers or model IDs are enabled in a specific account and region.\n\n### Choose a model ID for runtime inference\n\nAfter discovery, keep only the metadata you actually need in application code and hand the selected model ID to your runtime client.\n\n```javascript\nimport {\n  BedrockClient,\n  ListFoundationModelsCommand,\n} from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({ region: \"us-east-1\" });\n\nconst response = await bedrock.send(new ListFoundationModelsCommand({}));\n\nconst selectedModel = (response.modelSummaries ?? []).find((model) => {\n  const outputs = (model.outputModalities ?? []).map((value) => value.toLowerCase());\n\n  return model.modelLifecycle?.status?.toUpperCase() === \"ACTIVE\" && outputs.includes(\"text\");\n});\n\nif (!selectedModel?.modelId) {\n  throw new Error(\"No matching Bedrock model is available in this region/account\");\n}\n\nconsole.log(\"Use this model ID with @aws-sdk/client-bedrock-runtime:\", selectedModel.modelId);\n```\n\nThe exact model you choose should be driven by your own access policy, region, provider requirements, and runtime feature needs.\n\n## Bedrock-Specific Gotchas\n\n- This package does **not** invoke models. If you are looking for prompt execution, streaming responses, or chat-style runtime calls, you want `@aws-sdk/client-bedrock-runtime`.\n- Bedrock model availability is region-specific and account-specific. A model ID that works in one region or account may not be available in another.\n- Discovery results are metadata, not proof that your IAM policy and Bedrock access configuration are sufficient for every downstream inference action.\n- Check modalities before choosing a model. Some models are text-focused, some are multimodal, and not every model supports streaming.\n- Control-plane credentials are usually privileged. Keep Bedrock administration code on the server side.\n- The Bedrock service surface evolves quickly. Prefer explicit command imports and verify the exact resource workflow you need against the current AWS Bedrock documentation for your feature area.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-bedrock-runtime`: model invocation, streaming responses, and chat-style runtime APIs.\n- `@aws-sdk/credential-providers`: shared config helpers, IAM Identity Center, STS assume-role flows, and other credential providers.\n\n## Common Bedrock operations\n\n### Print a compact inventory of model summaries\n\n```javascript\nimport {\n  BedrockClient,\n  ListFoundationModelsCommand,\n} from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({ region: \"us-east-1\" });\n\nconst response = await bedrock.send(new ListFoundationModelsCommand({}));\n\nconst inventory = (response.modelSummaries ?? []).map((model) => ({\n  modelId: model.modelId,\n  name: model.modelName,\n  provider: model.providerName,\n  status: model.modelLifecycle?.status,\n  inputs: model.inputModalities ?? [],\n  outputs: model.outputModalities ?? [],\n  streaming: model.responseStreamingSupported ?? false,\n}));\n\nconsole.table(inventory);\n```\n\n### Filter for streaming-capable text models\n\n```javascript\nimport {\n  BedrockClient,\n  ListFoundationModelsCommand,\n} from \"@aws-sdk/client-bedrock\";\n\nconst bedrock = new BedrockClient({ region: \"us-east-1\" });\n\nconst response = await bedrock.send(new ListFoundationModelsCommand({}));\n\nconst streamingTextModels = (response.modelSummaries ?? []).filter((model) => {\n  const outputs = (model.outputModalities ?? []).map((value) => value.toLowerCase());\n  return model.responseStreamingSupported === true && outputs.includes(\"text\");\n});\n\nfor (const model of streamingTextModels) {\n  console.log(`${model.providerName}: ${model.modelId}`);\n}\n```\n\n## Notes\n\n- Treat the discovered `modelId` as configuration data. Resolve it once, store it where appropriate for your app, and re-check when you change regions or providers.\n- If your real goal is application inference, keep this package at the discovery and admin edge of your system and move prompt execution into the runtime client.\n"
  },
  {
    "path": "content/aws/docs/bedrock-runtime/javascript/DOC.md",
    "content": "---\nname: bedrock-runtime\ndescription: \"AWS SDK for JavaScript v3 Bedrock Runtime client for model invocation, chat-style Converse APIs, token counting, and streaming inference.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,bedrock,bedrock-runtime,javascript,nodejs,genai,llm,inference,streaming\"\n---\n\n# `@aws-sdk/client-bedrock-runtime`\n\nUse this package for Amazon Bedrock **runtime inference** in AWS SDK for JavaScript v3. It covers chat-style `Converse` requests, streaming responses, raw model-native invocation, token counting, guardrails, and async invoke APIs.\n\nThis is the runtime client. If you need to discover model IDs or work with the Bedrock control plane, use `@aws-sdk/client-bedrock` instead.\n\nPrefer `BedrockRuntimeClient` plus explicit command imports. That keeps call sites clear and avoids pulling in the full aggregated client surface by accident.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-bedrock-runtime\n```\n\nIf you want to pin a named shared AWS profile in code instead of relying on the default credential provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-bedrock-runtime@3.1007.0`.\n\n## Prerequisites And Authentication\n\nBefore sending requests, make sure all of the following are true:\n\n- your AWS credentials are available to the SDK\n- your chosen AWS region supports the Bedrock model you want to call\n- your account has access to that model in that region\n- your IAM policy allows the Bedrock runtime actions your code uses\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=bedrock-dev\nexport AWS_REGION=us-east-1\nexport BEDROCK_MODEL_ID=amazon.nova-lite-v1:0\n```\n\nThe JavaScript SDK usually resolves credentials from the default provider chain in Node.js, including environment variables, shared AWS config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nMinimal client setup:\n\n```javascript\nimport { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to force a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"bedrock-dev\" }),\n});\n```\n\nKeep Bedrock runtime calls on the server side unless you already have a browser-safe temporary credential flow. Do not ship long-lived AWS credentials to the browser.\n\n## Choose The Right Runtime API\n\n- `ConverseCommand`: higher-level message-based inference API\n- `ConverseStreamCommand`: streaming version of `Converse`\n- `InvokeModelCommand`: raw model-native request body and response body\n- `InvokeModelWithResponseStreamCommand`: streaming version of raw model-native invocation\n- `CountTokensCommand`: estimate input token count before sending a request\n\nFor new application code, start with `Converse` when your target model supports it. Reach for `InvokeModel` when you need the provider-specific native payload shape exactly as documented for that model.\n\n## Send A Basic Chat Request With `Converse`\n\n`Converse` uses a common message format across Bedrock-supported conversational models.\n\n```javascript\nimport {\n  BedrockRuntimeClient,\n  ConverseCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\nconst modelId = process.env.BEDROCK_MODEL_ID;\n\nif (!modelId) {\n  throw new Error(\"Set BEDROCK_MODEL_ID before calling Bedrock Runtime\");\n}\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ConverseCommand({\n    modelId,\n    messages: [\n      {\n        role: \"user\",\n        content: [{ text: \"Summarize why region selection matters for Amazon Bedrock.\" }],\n      },\n    ],\n    inferenceConfig: {\n      maxTokens: 256,\n      temperature: 0.2,\n    },\n  }),\n);\n\nconst text = (response.output?.message?.content ?? [])\n  .map((block) => block.text ?? \"\")\n  .join(\"\");\n\nconsole.log(text);\nconsole.log(response.usage?.inputTokens, response.usage?.outputTokens);\n```\n\nUseful request fields for `Converse`:\n\n- `messages`: conversation history as `{ role, content }[]`\n- `system`: optional system instructions separate from user messages\n- `inferenceConfig`: shared knobs such as `maxTokens`, `temperature`, `topP`, and `stopSequences`\n\nThe response includes `output.message.content`, `stopReason`, `usage`, and `metrics`.\n\n## Stream Text With `ConverseStream`\n\nUse `ConverseStream` when you want tokens or text blocks as they arrive instead of waiting for the full response.\n\n```javascript\nimport {\n  BedrockRuntimeClient,\n  ConverseStreamCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\nconst modelId = process.env.BEDROCK_MODEL_ID;\n\nif (!modelId) {\n  throw new Error(\"Set BEDROCK_MODEL_ID before calling Bedrock Runtime\");\n}\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ConverseStreamCommand({\n    modelId,\n    messages: [\n      {\n        role: \"user\",\n        content: [{ text: \"Write a short haiku about AWS logs.\" }],\n      },\n    ],\n    inferenceConfig: {\n      maxTokens: 128,\n      temperature: 0.7,\n    },\n  }),\n);\n\nif (!response.stream) {\n  throw new Error(\"Bedrock returned no stream\");\n}\n\nfor await (const event of response.stream) {\n  const text = event.contentBlockDelta?.delta?.text;\n\n  if (text) {\n    process.stdout.write(text);\n  }\n\n  if (event.metadata) {\n    console.error(\"\\nusage:\", event.metadata.usage);\n  }\n}\n\nprocess.stdout.write(\"\\n\");\n```\n\nThe stream emits structured events such as `messageStart`, `contentBlockDelta`, `messageStop`, and `metadata`. For plain text output, `contentBlockDelta.delta.text` is usually the field you want.\n\n## Count Tokens Before Sending A Request\n\n`CountTokens` is useful when you want to reject oversized prompts early or estimate cost before running inference.\n\n```javascript\nimport {\n  BedrockRuntimeClient,\n  CountTokensCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\nconst modelId = process.env.BEDROCK_MODEL_ID;\n\nif (!modelId) {\n  throw new Error(\"Set BEDROCK_MODEL_ID before calling Bedrock Runtime\");\n}\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new CountTokensCommand({\n    modelId,\n    input: {\n      converse: {\n        messages: [\n          {\n            role: \"user\",\n            content: [{ text: \"Draft a short release note for an SDK update.\" }],\n          },\n        ],\n      },\n    },\n  }),\n);\n\nconsole.log(`Input tokens: ${response.inputTokens}`);\n```\n\nFor `CountTokens`, the `input` object can describe either a `converse` request or an `invokeModel` request body.\n\n## Use `InvokeModel` For Model-Native Payloads\n\n`InvokeModel` is lower level than `Converse`. The request body and the parsed response shape depend on the specific model family you call.\n\nThis example uses a Titan Text payload. Do not reuse this JSON body unchanged for other model families.\n\n```javascript\nimport {\n  BedrockRuntimeClient,\n  InvokeModelCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\nconst client = new BedrockRuntimeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst payload = {\n  inputText: \"Explain why explicit credential handling matters in production.\",\n  textGenerationConfig: {\n    maxTokenCount: 256,\n    temperature: 0.2,\n  },\n};\n\nconst response = await client.send(\n  new InvokeModelCommand({\n    modelId: \"amazon.titan-text-express-v1\",\n    contentType: \"application/json\",\n    accept: \"application/json\",\n    body: JSON.stringify(payload),\n  }),\n);\n\nconst responseJson = JSON.parse(new TextDecoder().decode(response.body));\n\nconsole.log(responseJson);\n```\n\nUse `InvokeModel` when the model documentation gives you a provider-specific JSON schema that does not map cleanly to the higher-level `Converse` request format.\n\n## Common Runtime Errors And Pitfalls\n\n- `@aws-sdk/client-bedrock` and `@aws-sdk/client-bedrock-runtime` are different clients. Use the runtime client for inference.\n- Bedrock access is region-specific and model-specific. A valid model ID in one region may fail in another.\n- `InvokeModel` request bodies are model-native. Do not assume one JSON payload works across Anthropic, Amazon, Meta, and other providers.\n- `InvokeModelCommand` returns `body` as bytes. Decode it before calling `JSON.parse`.\n- Streaming APIs return structured event streams, not a plain string. Read `contentBlockDelta` for `ConverseStream` and streamed chunks for `InvokeModelWithResponseStream`.\n- Common service exceptions include `AccessDeniedException`, `ValidationException`, `ThrottlingException`, `ModelNotReadyException`, `ModelTimeoutException`, and `ModelErrorException`.\n\n## Minimal Error Handling Pattern\n\n```javascript\ntry {\n  const response = await client.send(command);\n  return response;\n} catch (error) {\n  if (error?.name === \"ThrottlingException\") {\n    throw new Error(\"Bedrock throttled the request; retry with backoff.\");\n  }\n\n  if (error?.name === \"AccessDeniedException\") {\n    throw new Error(\"AWS credentials or IAM permissions do not allow this Bedrock runtime call.\");\n  }\n\n  throw error;\n}\n```\n\n## Related Packages\n\n- `@aws-sdk/client-bedrock`: control-plane discovery and management APIs\n- `@aws-sdk/credential-providers`: explicit profile, assume-role, IAM Identity Center, and other credential helpers\n\n## Notes\n\n- Keep your chosen `modelId` in configuration, not hard-coded deep inside request helpers.\n- If you need to discover model IDs dynamically before inference, query Bedrock with `@aws-sdk/client-bedrock` and pass the selected ID into this runtime client.\n- If you need a fully model-native streaming payload instead of `ConverseStream`, use `InvokeModelWithResponseStreamCommand` and read each event chunk from the response stream.\n"
  },
  {
    "path": "content/aws/docs/boto3/python/DOC.md",
    "content": "---\nname: boto3\ndescription: \"AWS SDK for Python (boto3) package guide with sessions, clients, credentials, retries, paginators, waiters, and concurrency rules\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,botocore,python,sdk,cloud\"\n---\n\n# boto3 Python Package Guide\n\n## Golden Rule\n\n- Use an explicit `boto3.Session(...)` and create service clients from that session.\n- Prefer clients for new code. AWS documents the resource interface as feature-frozen.\n- Do not hardcode AWS credentials in source code. Let boto3 load them from profiles, environment variables, IAM Identity Center, assume-role configuration, or runtime IAM roles.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.66`.\n- On March 12, 2026, PyPI lists `boto3 1.42.66`. The AWS `latest` docs tree is rolling and still shows mixed patch numbers across pages, so use PyPI for exact package pinning and the AWS guide pages for behavior and examples.\n- `boto3` on PyPI requires Python `>=3.9`.\n- AWS documents three retry modes: `legacy`, `standard`, and `adaptive`. For new code, prefer `standard` unless you intentionally want adaptive client-side rate limiting.\n\n## Install\n\nPin the package version when you need reproducible behavior:\n\n```bash\npython -m pip install \"boto3==1.42.66\"\n```\n\nIf you need the optional CRT-backed integrations:\n\n```bash\npython -m pip install \"boto3[crt]==1.42.66\"\n```\n\n## Recommended Setup\n\nStart with an explicit session, set the region deliberately, and verify the caller identity before making service-specific calls.\n\n```python\nimport boto3\nfrom botocore.config import Config\nfrom botocore.exceptions import ClientError\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\nconfig = Config(\n    retries={\n        \"mode\": \"standard\",\n        \"max_attempts\": 10,\n    }\n)\n\nsts = session.client(\"sts\", config=config)\n\ntry:\n    identity = sts.get_caller_identity()\n    print(identity[\"Account\"])\n    print(identity[\"Arn\"])\nexcept ClientError as err:\n    print(err.response[\"Error\"][\"Code\"])\n    raise\n```\n\n## Credentials And Region Resolution\n\nThe AWS credentials guide documents a longer provider chain than most agents remember. In practice, the important sources are:\n\n1. Explicit credentials passed to `boto3.client(...)`\n2. Explicit credentials passed to `boto3.Session(...)`\n3. Environment variables\n4. Assume-role configuration\n5. Assume-role-with-web-identity configuration\n6. IAM Identity Center credentials\n7. Shared credentials file\n8. AWS config file\n9. Container credentials\n10. EC2 instance metadata\n\nFor region selection, boto3 can use:\n\n- `region_name=` on `Session(...)` or `client(...)`\n- `AWS_DEFAULT_REGION`\n- the selected profile in `~/.aws/config`\n- `Config(region_name=...)`\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\nFor local development, a named profile is usually the cleanest default:\n\n```python\nimport boto3\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\ns3 = session.client(\"s3\")\n```\n\nFor cross-account access, assume a role and then build a new session from the temporary credentials:\n\n```python\nimport boto3\n\nbase_session = boto3.Session(profile_name=\"admin\", region_name=\"us-east-1\")\nsts = base_session.client(\"sts\")\n\nassumed = sts.assume_role(\n    RoleArn=\"arn:aws:iam::123456789012:role/app-reader\",\n    RoleSessionName=\"context-hub-example\",\n)\n\ncreds = assumed[\"Credentials\"]\n\nsession = boto3.Session(\n    aws_access_key_id=creds[\"AccessKeyId\"],\n    aws_secret_access_key=creds[\"SecretAccessKey\"],\n    aws_session_token=creds[\"SessionToken\"],\n    region_name=\"us-east-1\",\n)\n```\n\n## Clients Vs Resources\n\n### Default Choice: Clients\n\nClients are the low-level interface and track AWS service APIs most closely.\n\n```python\nimport boto3\n\nsession = boto3.Session(region_name=\"us-east-1\")\ns3 = session.client(\"s3\")\nddb = session.client(\"dynamodb\")\n\nprint(s3.list_buckets())\nprint(ddb.list_tables(Limit=10))\n```\n\nUse clients when you need:\n\n- the newest service features\n- generated request and response dictionaries\n- paginators and waiters\n- direct parity with AWS API reference examples\n\n### Use Resources Only For Existing Convenience Workflows\n\nAWS states it does not intend to add new features to the resource interface. Keep using resources only when you already depend on their object model.\n\n```python\nimport boto3\n\nsession = boto3.Session(region_name=\"us-east-1\")\ns3 = session.resource(\"s3\")\n\nfor bucket in s3.buckets.all():\n    print(bucket.name)\n```\n\n## Core Usage Patterns\n\n### Call Operations With Keyword Arguments\n\nClient methods are generated from the service model. Use keyword arguments, not positional arguments.\n\n```python\nimport boto3\n\nec2 = boto3.Session(region_name=\"us-west-2\").client(\"ec2\")\n\nresponse = ec2.describe_instances(MaxResults=5)\nreservations = response.get(\"Reservations\", [])\n```\n\n### Use Paginators For List APIs\n\nMany list operations return partial results. Prefer a paginator whenever an operation may span multiple pages.\n\n```python\nimport boto3\n\ns3 = boto3.Session(region_name=\"us-east-1\").client(\"s3\")\npaginator = s3.get_paginator(\"list_objects_v2\")\n\nfor page in paginator.paginate(Bucket=\"my-bucket\", Prefix=\"logs/\"):\n    for item in page.get(\"Contents\", []):\n        print(item[\"Key\"])\n```\n\n### Use Waiters Instead Of Hand-Written Sleep Loops\n\nWaiters are only available for operations where AWS publishes waiter models, so check per service.\n\n```python\nimport boto3\n\ns3 = boto3.Session(region_name=\"us-east-1\").client(\"s3\")\ns3.create_bucket(Bucket=\"example-bucket-123\")\n\nwaiter = s3.get_waiter(\"bucket_exists\")\nwaiter.wait(Bucket=\"example-bucket-123\")\n```\n\n### Catch `ClientError` And Inspect The AWS Error Code\n\n```python\nimport boto3\nfrom botocore.exceptions import ClientError\n\ns3 = boto3.Session(region_name=\"us-east-1\").client(\"s3\")\n\ntry:\n    s3.head_bucket(Bucket=\"does-not-exist\")\nexcept ClientError as err:\n    code = err.response[\"Error\"][\"Code\"]\n    if code in {\"404\", \"NoSuchBucket\"}:\n        print(\"Bucket is missing\")\n    else:\n        raise\n```\n\n## Retry And Client Configuration\n\nUse `botocore.config.Config` when you need to override retry behavior or client settings such as timeouts, proxies, or signature behavior.\n\n```python\nimport boto3\nfrom botocore.config import Config\n\nconfig = Config(\n    region_name=\"us-west-2\",\n    retries={\n        \"mode\": \"standard\",\n        \"max_attempts\": 10,\n    },\n)\n\ndynamodb = boto3.Session().client(\"dynamodb\", config=config)\n```\n\nNotes that matter in practice:\n\n- `standard` is the safest default for most applications.\n- `adaptive` adds client-side rate limiting on top of standard retry behavior.\n- Retry settings can also come from `AWS_RETRY_MODE` and `AWS_MAX_ATTEMPTS`.\n- AWS documents a subtle difference in how `max_attempts` is interpreted depending on where you configure it. In a `Config` object it counts retries only, while `AWS_MAX_ATTEMPTS` and config-file settings count the initial request too. Use `total_max_attempts` when you want consistent total-request semantics from code.\n\n## Concurrency Rules\n\nThe boto3 guides call out an important split:\n\n- Low-level clients are generally thread-safe.\n- Clients are not safe to share across processes.\n- `Session` objects are not thread-safe.\n- Resource objects are not thread-safe and should not be shared across threads or processes.\n\nFor threaded code, create one session per thread and then build clients or resources from that session.\n\n## Common Pitfalls\n\n- `boto3.client(...)` and `boto3.resource(...)` use a shared default session if you do not create one explicitly. That is convenient for scripts but a poor default for libraries, tests, and concurrent code.\n- Credentials and region are separate concerns. Having valid credentials without a region still produces confusing failures for regional services.\n- List-style APIs often paginate even when a small test account returns everything in one call.\n- Not every service has waiters, and waiter names differ from operation names.\n- The legacy `boto3.amazonaws.com` docs hostname redirects to the canonical `docs.aws.amazon.com` root. Store the canonical root in tooling.\n- The `latest` AWS docs tree is rolling. Verify exact package pinning against PyPI before writing version-sensitive automation.\n\n## Official Source URLs\n\n- AWS docs root: `https://docs.aws.amazon.com/boto3/latest/`\n- AWS quickstart: `https://docs.aws.amazon.com/boto3/latest/guide/quickstart.html`\n- AWS credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- AWS clients guide: `https://docs.aws.amazon.com/boto3/latest/guide/clients.html`\n- AWS resources guide: `https://docs.aws.amazon.com/boto3/latest/guide/resources.html`\n- AWS paginators guide: `https://docs.aws.amazon.com/boto3/latest/guide/paginators.html`\n- AWS retries guide: `https://docs.aws.amazon.com/boto3/latest/guide/retries.html`\n- AWS error handling guide: `https://docs.aws.amazon.com/boto3/latest/guide/error-handling.html`\n- AWS session guide: `https://docs.aws.amazon.com/boto3/latest/guide/session.html`\n- PyPI package page: `https://pypi.org/project/boto3/`\n"
  },
  {
    "path": "content/aws/docs/boto3-stubs/python/DOC.md",
    "content": "---\nname: boto3-stubs\ndescription: \"boto3-stubs package guide for Python with service extras, typed boto3 clients/resources, and AWS config notes for mypy and pyright\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,boto3-stubs,typing,mypy,pyright,python\"\n---\n\n# boto3-stubs Python Package Guide\n\n## What It Is\n\n`boto3-stubs` adds generated type information and editor completion for `boto3`. It covers service clients, resources, paginators, waiters, and typed dictionaries, but it is not the runtime AWS SDK. Your code still runs through normal `boto3` sessions, clients, and resources.\n\nThe official docs position it for:\n\n- `mypy` and `pyright` type checking\n- IDE completion for `boto3` services\n- explicit imports like `mypy_boto3_s3.client.S3Client`\n- generated paginator, waiter, and `type_defs` modules\n\n## Golden Rules\n\n- Keep `boto3` installed for runtime calls. `boto3-stubs` only improves static typing.\n- Install the service extras you actually use, or use `essential` / `full` when you want convenience over a small environment.\n- Add explicit annotations for `session.client(\"...\")` and `session.resource(\"...\")` when inference is ambiguous.\n- Configure credentials, profiles, regions, retries, and endpoints through `boto3` and AWS config, not through `boto3-stubs`.\n- If the stubs are development-only, guard imports with `TYPE_CHECKING` so production environments do not need them.\n\n## Install\n\nFor most projects, pin the stub version explicitly and keep it aligned with the `boto3` version you are using.\n\n```bash\npython -m pip install \"boto3-stubs==1.42.66\"\n```\n\nCommon install patterns from the official docs:\n\n```bash\n# Install matching boto3 with the stubs\npython -m pip install \"boto3-stubs[boto3]==1.42.66\"\n\n# Common AWS services\npython -m pip install \"boto3-stubs[essential]==1.42.66\"\n\n# Only the services you need\npython -m pip install \"boto3-stubs[s3,sts,dynamodb]==1.42.66\"\n\n# All generated service stubs\npython -m pip install \"boto3-stubs[full]==1.42.66\"\n```\n\nPractical install rule:\n\n- use `[boto3]` when you want the runtime SDK and the stubs to stay aligned by default\n- use service extras when you care about smaller environments and faster installs\n- use `[full]` only when you genuinely need broad service coverage\n\n## Initialize Type Checking\n\nInstall a type checker in the same environment as `boto3` and `boto3-stubs`.\n\n```bash\npython -m pip install mypy\npython -m mypy app.py\n```\n\n`pyright` also works with the generated stubs. If you only need editor completion and CI type checks, keep `boto3-stubs` as a development dependency.\n\n## Core Usage\n\n### Typed Session Client\n\nUse normal `boto3` runtime objects and import the matching generated types.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.client import S3Client\nfrom mypy_boto3_s3.paginator import ListObjectsV2Paginator\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\ns3: S3Client = session.client(\"s3\")\npaginator: ListObjectsV2Paginator = s3.get_paginator(\"list_objects_v2\")\n\nfor page in paginator.paginate(Bucket=\"my-bucket\", Prefix=\"logs/\"):\n    for item in page.get(\"Contents\", []):\n        print(item[\"Key\"])\n```\n\nThis explicit annotation pattern is the safest default for coding agents because the client type is obvious to the checker and to the reader.\n\n### Typed Resource\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.service_resource import S3ServiceResource\n\nsession = Session(region_name=\"us-east-1\")\ns3: S3ServiceResource = session.resource(\"s3\")\n\nfor bucket in s3.buckets.all():\n    print(bucket.name)\n```\n\n### `TYPE_CHECKING` For Dev-Only Stub Imports\n\nIf your production runtime does not install the stubs, keep type imports behind `TYPE_CHECKING`.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sts.client import STSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsts: \"STSClient\" = session.client(\"sts\")\n\nidentity = sts.get_caller_identity()\nprint(identity[\"Arn\"])\n```\n\n### Service Extras And Import Mapping\n\nThe package exposes service-specific modules such as:\n\n- `mypy_boto3_s3.client`\n- `mypy_boto3_s3.service_resource`\n- `mypy_boto3_s3.paginator`\n- `mypy_boto3_s3.waiter`\n- `mypy_boto3_s3.type_defs`\n\nThose imports only exist when the matching service stubs are installed through:\n\n- `boto3-stubs[s3]`\n- `boto3-stubs[essential]`\n- `boto3-stubs[full]`\n- or the standalone service package such as `mypy-boto3-s3`\n\nIf `from mypy_boto3_s3.client import S3Client` fails, the usual problem is a missing service extra, not a broken AWS client.\n\n## Config And Authentication\n\n`boto3-stubs` does not add its own authentication layer. Use the normal `boto3` and AWS credential/config flow.\n\nTypical inputs:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `~/.aws/config`\n- `~/.aws/credentials`\n\nTypical local setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sts.client import STSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nsts: STSClient = session.client(\"sts\")\n\nprint(sts.get_caller_identity()[\"Account\"])\n```\n\nImportant constraint for agents: a typed client can still fail at runtime if the AWS profile, region, endpoint, or IAM permissions are wrong.\n\n## Common Pitfalls\n\n- Installing `boto3-stubs` and forgetting to install `boto3` for runtime AWS calls.\n- Importing `mypy_boto3_<service>` modules without installing the matching service extra.\n- Expecting type inference to always understand `session.client(\"service\")` without an explicit annotation.\n- Assuming successful type checking means credentials, region, or permissions are correct.\n- Using `boto3-stubs-lite` and expecting the same `session.client(...)` and `session.resource(...)` overload coverage. The official docs call out that the lite variant does not provide those overloads.\n- Mixing `boto3-stubs` imports with `types-boto3` imports in the same code path without planning the migration.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.66`.\n- The official docs describe `boto3-stubs` versions as following the related `boto3` version, so pinning matching versions is the safest default.\n- The documentation site is generated and unversioned. Search snippets and older examples can show stale patch numbers, so prefer your lockfile and the exact PyPI release page when pinning dependencies.\n- The maintainer repository documents `types-boto3` as the successor project. This entry remains intentionally focused on the published `boto3-stubs` package and its `mypy_boto3_<service>` import surface.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/\n- Package page: https://pypi.org/project/boto3-stubs/\n- Exact release page: https://pypi.org/project/boto3-stubs/1.42.66/\n- Current repository: https://github.com/youtype/types-boto3\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/botocore/python/DOC.md",
    "content": "---\nname: botocore\ndescription: \"botocore Python package guide for low-level AWS clients, shared credential/config loading, retries, paginators, and stubbing\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,botocore,python,sdk,credentials,retries,paginators,testing\"\n---\n\n# botocore Python Package Guide\n\n## What This Package Is For\n\n`botocore` is the low-level AWS SDK foundation used by `boto3` and the AWS CLI.\n\nUse it when your code needs to:\n\n- create low-level AWS service clients directly with `botocore.session.Session`\n- control request behavior with `botocore.config.Config`\n- stub AWS responses in tests with `botocore.stub.Stubber`\n- work close to generated AWS service models instead of the higher-level `boto3` resource layer\n\nIf you want higher-level service resources for normal application code, prefer `boto3`. If you need the common AWS credential chain, retry configuration, endpoint behavior, or service model-driven clients, `botocore` is the actual implementation layer.\n\n## Version-Sensitive Notes\n\n- This entry keeps `1.42.66` in frontmatter because that was the version used here provided for review.\n- Public upstream sources checked on 2026-03-12 did not verify a public `1.42.66` release. The PyPI project page currently shows `1.42.63`.\n- The AWS `latest` botocore docs are a rolling docs tree, not a strict patch snapshot. Different pages in the same tree currently show different `1.42.x` patch labels.\n- Treat the AWS docs as the canonical behavior reference and PyPI as the package-version source of truth before pinning an exact release.\n- If your project also installs `boto3`, keep `boto3` and `botocore` on compatible release lines instead of upgrading one independently.\n\n## Install\n\nInstall from PyPI:\n\n```bash\npython -m pip install botocore\n```\n\nIf you need the last public version verified during this session:\n\n```bash\npython -m pip install \"botocore==1.42.63\"\n```\n\nIf your internal mirror or lockfile already uses the version used here, verify that `1.42.66` is actually available before copying that exact pin.\n\n## Initialize A reviewnd Client\n\nThe core botocore workflow is:\n\n1. create a session\n2. create a low-level client for one AWS service\n3. call service operations with plain Python dictionaries\n\n```python\nimport botocore.session\nfrom botocore.exceptions import ClientError\n\nsession = botocore.session.get_session()\nsts = session.create_client(\"sts\", region_name=\"us-west-2\")\n\ntry:\n    identity = sts.get_caller_identity()\n    print(identity[\"Account\"])\n    print(identity[\"Arn\"])\nexcept ClientError as err:\n    print(err.response[\"Error\"][\"Code\"])\n    raise\n```\n\nUseful discovery helpers:\n\n```python\nimport botocore.session\n\nsession = botocore.session.get_session()\n\nprint(\"s3\" in session.get_available_services())\nprint(session.get_available_regions(\"s3\")[:5])\n```\n\n## Credentials And Region Configuration\n\n`botocore` uses the standard AWS SDK credential and settings chain. In practice, the most useful inputs are:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_SHARED_CREDENTIALS_FILE`\n- `AWS_CONFIG_FILE`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n- `AWS_EC2_METADATA_DISABLED`\n\nLocal profile-based setup is the safest default for development:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create clients without hardcoding credentials:\n\n```python\nimport botocore.session\n\nsession = botocore.session.get_session()\ns3 = session.create_client(\"s3\")\n```\n\nIf you must override settings for a single client, pass them explicitly:\n\n```python\nimport botocore.session\n\nsession = botocore.session.get_session()\nclient = session.create_client(\n    \"sqs\",\n    region_name=\"us-east-1\",\n    aws_access_key_id=\"...\",\n    aws_secret_access_key=\"...\",\n    aws_session_token=\"...\",\n)\n```\n\nPrefer explicit credentials only for short-lived scripts, local emulators, or test fixtures.\n\n## Use `Config` For Retries, Timeouts, Proxies, And Pools\n\n`botocore.config.Config` is the main runtime override surface for per-client behavior.\n\nTypical settings worth controlling:\n\n- `region_name`\n- `connect_timeout`\n- `read_timeout`\n- `retries`\n- `max_pool_connections`\n- `proxies`\n- `signature_version`\n\n```python\nimport botocore.session\nfrom botocore.config import Config\n\nsession = botocore.session.get_session()\n\nconfig = Config(\n    region_name=\"us-west-2\",\n    connect_timeout=5,\n    read_timeout=30,\n    max_pool_connections=20,\n    retries={\n        \"mode\": \"standard\",\n        \"total_max_attempts\": 10,\n    },\n)\n\nclient = session.create_client(\"dynamodb\", config=config)\n```\n\nPractical guidance:\n\n- prefer `total_max_attempts` in `Config(...)` because it consistently counts the initial request\n- prefer `mode: \"standard\"` for most code unless you have a specific reason to use `adaptive`\n- lower timeouts for latency-sensitive code instead of accepting the default 60-second connect/read timeouts\n- raise `max_pool_connections` if many threads share clients from the same session\n\nFor local emulators such as LocalStack, override the endpoint:\n\n```python\nimport botocore.session\nfrom botocore.config import Config\n\nsession = botocore.session.get_session()\ns3 = session.create_client(\n    \"s3\",\n    region_name=\"us-east-1\",\n    endpoint_url=\"http://localhost:4566\",\n    aws_access_key_id=\"test\",\n    aws_secret_access_key=\"test\",\n    config=Config(signature_version=\"s3v4\"),\n)\n```\n\n## Core Usage Pattern\n\nOperations are generated from AWS service models. Method names are snake_case, and requests and responses use plain dict/list structures.\n\n```python\nimport botocore.session\nfrom botocore.exceptions import ClientError\n\nsession = botocore.session.get_session()\nec2 = session.create_client(\"ec2\", region_name=\"us-west-2\")\n\ntry:\n    response = ec2.describe_instances(\n        Filters=[\n            {\n                \"Name\": \"instance-state-name\",\n                \"Values\": [\"running\"],\n            }\n        ]\n    )\nexcept ClientError as err:\n    code = err.response[\"Error\"][\"Code\"]\n    if code == \"UnauthorizedOperation\":\n        raise PermissionError(\"Missing EC2 permissions\") from err\n    raise\n\nfor reservation in response[\"Reservations\"]:\n    for instance in reservation[\"Instances\"]:\n        print(instance[\"InstanceId\"])\n```\n\nInspect service capabilities dynamically when needed:\n\n```python\nimport botocore.session\n\nsession = botocore.session.get_session()\nclient = session.create_client(\"lambda\", region_name=\"us-west-2\")\n\nprint(client.meta.service_model.service_name)\nprint(client.meta.service_model.operation_names[:10])\n```\n\n## Paginators\n\nMany list operations return partial results. Use paginators instead of manually looping on service-specific continuation tokens when the operation supports them.\n\n```python\nimport botocore.session\n\nsession = botocore.session.get_session()\niam = session.create_client(\"iam\")\n\nif iam.can_paginate(\"list_users\"):\n    paginator = iam.get_paginator(\"list_users\")\n    for page in paginator.paginate(\n        PaginationConfig={\n            \"MaxItems\": 200,\n            \"PageSize\": 50,\n        }\n    ):\n        for user in page[\"Users\"]:\n            print(user[\"UserName\"])\n```\n\nNotes:\n\n- use `client.can_paginate(\"operation_name\")` before assuming a paginator exists\n- `PaginationConfig` commonly accepts `MaxItems`, `PageSize`, and `StartingToken`\n- paginator page shapes are still raw response dictionaries from the underlying service\n\n## Testing With `Stubber`\n\nUse `botocore.stub.Stubber` for unit tests that should not make network calls.\n\n```python\nimport botocore.session\nfrom botocore.stub import Stubber\n\nsession = botocore.session.get_session()\nsts = session.create_client(\"sts\", region_name=\"us-east-1\")\n\nwith Stubber(sts) as stubber:\n    stubber.add_response(\n        \"get_caller_identity\",\n        {\n            \"UserId\": \"AIDATEST\",\n            \"Account\": \"123456789012\",\n            \"Arn\": \"arn:aws:iam::123456789012:user/test\",\n        },\n        {},\n    )\n\n    response = sts.get_caller_identity()\n    assert response[\"Account\"] == \"123456789012\"\n```\n\nTo test failure paths:\n\n```python\nimport botocore.session\nfrom botocore.exceptions import ClientError\nfrom botocore.stub import Stubber\n\nsession = botocore.session.get_session()\ns3 = session.create_client(\"s3\", region_name=\"us-east-1\")\n\nwith Stubber(s3) as stubber:\n    stubber.add_client_error(\n        \"head_bucket\",\n        service_error_code=\"404\",\n        service_message=\"Not Found\",\n        http_status_code=404,\n    )\n\n    try:\n        s3.head_bucket(Bucket=\"missing-bucket\")\n    except ClientError as err:\n        assert err.response[\"ResponseMetadata\"][\"HTTPStatusCode\"] == 404\n```\n\n`Stubber` validates both the called operation name and the expected parameters, which makes it much better than patching random methods with loose mocks.\n\n## Error Handling\n\nMost AWS service failures surface as `botocore.exceptions.ClientError`.\n\n```python\nfrom botocore.exceptions import ClientError, NoCredentialsError\n\ntry:\n    response = client.some_operation(...)\nexcept NoCredentialsError:\n    raise RuntimeError(\"AWS credentials are not configured\")\nexcept ClientError as err:\n    code = err.response[\"Error\"][\"Code\"]\n    message = err.response[\"Error\"][\"Message\"]\n    raise RuntimeError(f\"AWS error {code}: {message}\") from err\n```\n\nPractical rules:\n\n- branch on `err.response[\"Error\"][\"Code\"]`, not on message text\n- handle missing credentials separately from service-side errors\n- keep retry logic aligned with idempotency and the configured retry mode\n- do not suppress `ClientError` broadly without logging the service error code\n\n## Common Pitfalls\n\n- Do not treat `botocore` like `boto3` resources. It gives you low-level clients and raw response dicts.\n- Do not hardcode long-lived credentials in source files. Use the shared AWS credential chain.\n- Do not assume every list operation has a paginator. Check `can_paginate(...)`.\n- Do not assume the AWS `latest` docs tree is patch-pinned to your installed wheel.\n- Do not upgrade `botocore` independently from `boto3` without checking compatibility.\n- Use `Config(...)` for retry, timeout, proxy, and pool overrides instead of scattering ad hoc environment tweaks across scripts.\n- In tests, use `Stubber` instead of live AWS calls or overly loose mocks.\n\n## Official Sources Used For This Entry\n\n- `https://docs.aws.amazon.com/botocore/latest/`\n- `https://docs.aws.amazon.com/botocore/latest/tutorial/`\n- `https://docs.aws.amazon.com/botocore/latest/reference/config.html`\n- `https://docs.aws.amazon.com/botocore/latest/reference/stubber.html`\n- `https://docs.aws.amazon.com/botocore/latest/topics/paginators.html`\n- `https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html`\n- `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- `https://docs.aws.amazon.com/boto3/latest/guide/retries.html`\n- `https://pypi.org/project/botocore/`\n"
  },
  {
    "path": "content/aws/docs/budgets/javascript/DOC.md",
    "content": "---\nname: budgets\ndescription: \"AWS SDK for JavaScript v3 client for listing, creating, updating, and automating AWS Budgets.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,budgets,javascript,nodejs,billing,cost-management,cost-control\"\n---\n\n# `@aws-sdk/client-budgets`\n\nUse this package to manage AWS Budgets from JavaScript with AWS SDK v3. The client covers budget creation and updates, budget notifications and subscribers, performance history, budget actions, and resource tagging.\n\nAWS Budgets is a billing service with a global endpoint (`https://budgets.amazonaws.com`). The SDK still expects normal client configuration, so set a region explicitly in your client config.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-budgets\n```\n\nTypical environment variables for local development:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCOUNT_ID=123456789012\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=... # only for temporary credentials\n```\n\nMost Budgets operations require the 12-digit AWS account ID in the request body, so it is practical to keep `AWS_ACCOUNT_ID` next to your normal AWS credentials.\n\n## Client Setup\n\n```javascript\nimport { BudgetsClient } from \"@aws-sdk/client-budgets\";\n\nconst accountId = process.env.AWS_ACCOUNT_ID;\n\nif (!accountId) {\n  throw new Error(\"Set AWS_ACCOUNT_ID to your 12-digit AWS account ID.\");\n}\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough when credentials already come from environment variables, shared AWS config files, IAM Identity Center, ECS, or EC2 instance metadata.\n\n## Common Workflows\n\n### List budgets for an account\n\n`DescribeBudgets` is the main discovery call. It supports `MaxResults` and `NextToken` pagination.\n\n```javascript\nimport {\n  BudgetsClient,\n  DescribeBudgetsCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst accountId = process.env.AWS_ACCOUNT_ID;\n\nlet nextToken;\n\ndo {\n  const page = await budgets.send(\n    new DescribeBudgetsCommand({\n      AccountId: accountId,\n      MaxResults: 20,\n      NextToken: nextToken,\n      ShowFilterExpression: true,\n    }),\n  );\n\n  for (const budget of page.Budgets ?? []) {\n    console.log({\n      name: budget.BudgetName,\n      type: budget.BudgetType,\n      timeUnit: budget.TimeUnit,\n      limit: budget.BudgetLimit,\n      actual: budget.CalculatedSpend?.ActualSpend,\n      forecasted: budget.CalculatedSpend?.ForecastedSpend,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nSet `ShowFilterExpression: true` when you want the response to include the newer `FilterExpression` form for budgets that use expression-based filters.\n\n### Read a single budget\n\nUse `DescribeBudget` when you already know the budget name.\n\n```javascript\nimport {\n  BudgetsClient,\n  DescribeBudgetCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await budgets.send(\n  new DescribeBudgetCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    BudgetName: \"monthly-cost\",\n    ShowFilterExpression: true,\n  }),\n);\n\nconsole.log(response.Budget?.BudgetName);\nconsole.log(response.Budget?.BudgetLimit);\nconsole.log(response.Budget?.CalculatedSpend?.ActualSpend);\nconsole.log(response.Budget?.CalculatedSpend?.ForecastedSpend);\n```\n\n### Create a monthly cost budget with an email alert\n\n`CreateBudget` can create the budget and its initial notifications/subscribers in one request.\n\n```javascript\nimport {\n  BudgetsClient,\n  CreateBudgetCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst now = new Date();\nconst startOfMonth = new Date(\n  Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1),\n);\n\nawait budgets.send(\n  new CreateBudgetCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    Budget: {\n      BudgetName: \"monthly-cost\",\n      BudgetType: \"COST\",\n      TimeUnit: \"MONTHLY\",\n      BudgetLimit: {\n        Amount: \"200\",\n        Unit: \"USD\",\n      },\n      TimePeriod: {\n        Start: startOfMonth,\n      },\n    },\n    NotificationsWithSubscribers: [\n      {\n        Notification: {\n          NotificationType: \"FORECASTED\",\n          ComparisonOperator: \"GREATER_THAN\",\n          Threshold: 80,\n          ThresholdType: \"PERCENTAGE\",\n        },\n        Subscribers: [\n          {\n            SubscriptionType: \"EMAIL\",\n            Address: \"finops@example.com\",\n          },\n        ],\n      },\n    ],\n  }),\n);\n```\n\nFor cost and usage budgets, supply `BudgetLimit`. If you use `PlannedBudgetLimits`, omit `BudgetLimit` from the same request.\n\n### Add or update notifications later\n\nIf you did not create notifications during `CreateBudget`, or you need to add another alert later, use `CreateNotification`. To add another subscriber to an existing notification, use `CreateSubscriber`.\n\n```javascript\nimport {\n  BudgetsClient,\n  CreateNotificationCommand,\n  CreateSubscriberCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst notification = {\n  NotificationType: \"ACTUAL\",\n  ComparisonOperator: \"GREATER_THAN\",\n  Threshold: 90,\n  ThresholdType: \"PERCENTAGE\",\n};\n\nawait budgets.send(\n  new CreateNotificationCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    BudgetName: \"monthly-cost\",\n    Notification: notification,\n    Subscribers: [\n      {\n        SubscriptionType: \"EMAIL\",\n        Address: \"owner@example.com\",\n      },\n    ],\n  }),\n);\n\nawait budgets.send(\n  new CreateSubscriberCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    BudgetName: \"monthly-cost\",\n    Notification: notification,\n    Subscriber: {\n      SubscriptionType: \"EMAIL\",\n      Address: \"backup-owner@example.com\",\n    },\n  }),\n);\n```\n\n### Update a budget amount\n\nUse `UpdateBudget` to replace the mutable parts of a budget. `BudgetName` stays the same, and `CalculatedSpend` is not something you set yourself.\n\n```javascript\nimport {\n  BudgetsClient,\n  UpdateBudgetCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst now = new Date();\nconst startOfMonth = new Date(\n  Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1),\n);\n\nawait budgets.send(\n  new UpdateBudgetCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    NewBudget: {\n      BudgetName: \"monthly-cost\",\n      BudgetType: \"COST\",\n      TimeUnit: \"MONTHLY\",\n      BudgetLimit: {\n        Amount: \"250\",\n        Unit: \"USD\",\n      },\n      TimePeriod: {\n        Start: startOfMonth,\n      },\n    },\n  }),\n);\n```\n\nIf your existing budget uses filters, metrics, auto-adjust, planned limits, or a custom time period, include the fields you want the updated budget to keep.\n\n### Read budget performance history\n\nUse `DescribeBudgetPerformanceHistory` to compare historical budgeted amounts versus actual amounts over time.\n\n```javascript\nimport {\n  BudgetsClient,\n  DescribeBudgetPerformanceHistoryCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await budgets.send(\n    new DescribeBudgetPerformanceHistoryCommand({\n      AccountId: process.env.AWS_ACCOUNT_ID,\n      BudgetName: \"monthly-cost\",\n      MaxResults: 12,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (\n    const point of page.BudgetPerformanceHistory?.BudgetedAndActualAmountsList ?? []\n  ) {\n    console.log({\n      start: point.TimePeriod?.Start,\n      end: point.TimePeriod?.End,\n      budgeted: point.BudgetedAmount,\n      actual: point.ActualAmount,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nBudget performance history is available for `DAILY`, `MONTHLY`, and `QUARTERLY` budgets. It is not available for `ANNUALLY` budgets.\n\n### Delete a budget\n\n```javascript\nimport {\n  BudgetsClient,\n  DeleteBudgetCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait budgets.send(\n  new DeleteBudgetCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    BudgetName: \"monthly-cost\",\n  }),\n);\n```\n\nDeleting a budget also deletes the notifications and subscribers attached to that budget.\n\n## Budget Actions\n\nThe Budgets client also supports automated actions through `CreateBudgetAction`, `UpdateBudgetAction`, `DescribeBudgetActionsForBudget`, `DescribeBudgetActionsForAccount`, `DescribeBudgetActionHistories`, and `ExecuteBudgetAction`.\n\nAvailable action types are:\n\n- `APPLY_IAM_POLICY`\n- `APPLY_SCP_POLICY`\n- `RUN_SSM_DOCUMENTS`\n\nAvailable approval models are `AUTOMATIC` and `MANUAL`.\n\nExample: create a manual budget action that can stop EC2 instances through SSM when the forecast reaches 95% of the budget.\n\n```javascript\nimport {\n  BudgetsClient,\n  CreateBudgetActionCommand,\n  ExecuteBudgetActionCommand,\n} from \"@aws-sdk/client-budgets\";\n\nconst budgets = new BudgetsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst createActionResponse = await budgets.send(\n  new CreateBudgetActionCommand({\n    AccountId: process.env.AWS_ACCOUNT_ID,\n    BudgetName: \"monthly-cost\",\n    NotificationType: \"FORECASTED\",\n    ActionType: \"RUN_SSM_DOCUMENTS\",\n    ActionThreshold: {\n      ActionThresholdValue: 95,\n      ActionThresholdType: \"PERCENTAGE\",\n    },\n    Definition: {\n      SsmActionDefinition: {\n        ActionSubType: \"STOP_EC2_INSTANCES\",\n        Region: process.env.AWS_REGION ?? \"us-east-1\",\n        InstanceIds: [\"i-0123456789abcdef0\"],\n      },\n    },\n    ExecutionRoleArn:\n      \"arn:aws:iam::123456789012:role/BudgetsActionExecutionRole\",\n    ApprovalModel: \"MANUAL\",\n    Subscribers: [\n      {\n        SubscriptionType: \"EMAIL\",\n        Address: \"finops@example.com\",\n      },\n    ],\n  }),\n);\n\nif (createActionResponse.ActionId) {\n  await budgets.send(\n    new ExecuteBudgetActionCommand({\n      AccountId: process.env.AWS_ACCOUNT_ID,\n      BudgetName: \"monthly-cost\",\n      ActionId: createActionResponse.ActionId,\n      ExecutionType: \"APPROVE_BUDGET_ACTION\",\n    }),\n  );\n}\n```\n\n## Important Notes\n\n- Set `AccountId` on nearly every request. The API expects the 12-digit AWS account ID, not just credentials on the client.\n- Budget names must be unique within the account and cannot contain `:` or `\\`, and cannot include the `/action/` substring.\n- In `CreateBudget` and `UpdateBudget`, use either `BudgetLimit` or `PlannedBudgetLimits`, not both.\n- For modern filtering, prefer `FilterExpression` with `Metrics`. Do not combine `FilterExpression`/`Metrics` with `CostFilters`/`CostTypes` in the same budget definition.\n- `DescribeBudgets`, `DescribeNotificationsForBudget`, `DescribeSubscribersForNotification`, `DescribeBudgetPerformanceHistory`, `DescribeBudgetActionHistories`, `DescribeBudgetActionsForAccount`, `DescribeBudgetActionsForBudget`, and `DescribeBudgetNotificationsForAccount` are paginated via `NextToken`.\n- If you rely on newer filter expression fields in responses, request them with `ShowFilterExpression: true` on `DescribeBudget` and `DescribeBudgets`.\n\n## Useful Enums and Fields\n\nCommon values you will use in budget requests:\n\n- `BudgetType`: `COST`, `USAGE`, `RI_UTILIZATION`, `RI_COVERAGE`, `SAVINGS_PLANS_UTILIZATION`, `SAVINGS_PLANS_COVERAGE`\n- `TimeUnit`: `DAILY`, `MONTHLY`, `QUARTERLY`, `ANNUALLY`, `CUSTOM`\n- `NotificationType`: `ACTUAL`, `FORECASTED`\n- `ThresholdType`: `PERCENTAGE`, `ABSOLUTE_VALUE`\n- `SubscriptionType`: `EMAIL`, `SNS`\n- `Metrics`: `BlendedCost`, `UnblendedCost`, `AmortizedCost`, `NetUnblendedCost`, `NetAmortizedCost`, `UsageQuantity`, `NormalizedUsageAmount`, `Hours`\n\nWhen you build `FilterExpression`, supported dimension keys include `LINKED_ACCOUNT`, `LINKED_ACCOUNT_NAME`, `SERVICE`, `SERVICE_CODE`, `REGION`, `USAGE_TYPE`, `RESOURCE_ID`, `TAG_KEY`, and `COST_CATEGORY_NAME`.\n"
  },
  {
    "path": "content/aws/docs/chime-sdk-messaging/javascript/DOC.md",
    "content": "---\nname: chime-sdk-messaging\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Chime SDK Messaging channels, memberships, messages, and channel flows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,chime-sdk,messaging,javascript,nodejs,channels\"\n---\n\n# `@aws-sdk/client-chime-sdk-messaging`\n\nUse `@aws-sdk/client-chime-sdk-messaging` to manage Amazon Chime SDK messaging channels, channel memberships, channel messages, read markers, and channel flows from JavaScript or TypeScript.\n\nThis package is for the messaging layer. It does not create app instances or app instance users. For that setup work, use the Chime SDK identity APIs, then use this package with the resulting `AppInstanceArn`, `AppInstanceUserArn`, `ChannelArn`, and related ARNs.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-chime-sdk-messaging`, not the legacy `aws-sdk` v2 package.\n- Prefer `ChimeSDKMessagingClient` with explicit command imports.\n- Pass `ChimeBearer` on the calls that require it, using the acting `AppInstanceUserArn` or `AppInstanceBotArn`.\n- Keep the client `region` aligned with the Chime SDK app instance region.\n- Use full ARNs such as `AppInstanceArn`, `AppInstanceUserArn`, `ChannelArn`, and `ChannelFlowArn`.\n- Handle pagination yourself with `NextToken`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-chime-sdk-messaging\n```\n\nIf you want to force a named shared AWS profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-chime-sdk-messaging@3.1007.0`.\n\n## Prerequisites And Authentication\n\nBefore using the client, make sure all of the following are true:\n\n- AWS credentials are available to the SDK.\n- Your IAM policy allows the Chime SDK messaging actions your code calls.\n- You already have a Chime SDK app instance and app instance users or bots.\n- Your code knows the acting user or bot ARN that should be sent as `ChimeBearer`.\n- Your client region matches the app instance region.\n\nTypical local setup:\n\n```bash\naws configure --profile chime-dev\n\nexport AWS_PROFILE=chime-dev\nexport AWS_REGION=us-east-1\nexport APP_INSTANCE_ARN=arn:aws:chime:us-east-1:123456789012:app-instance/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\nexport APP_INSTANCE_USER_ARN=arn:aws:chime:us-east-1:123456789012:app-instance/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/user/alice\nexport TARGET_MEMBER_ARN=arn:aws:chime:us-east-1:123456789012:app-instance/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/user/bob\nexport SECOND_TARGET_MEMBER_ARN=arn:aws:chime:us-east-1:123456789012:app-instance/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/user/carol\nexport CHANNEL_ARN=arn:aws:chime:us-east-1:123456789012:channel/ffffffff-1111-2222-3333-444444444444\nexport MESSAGE_ID=12345678-90ab-cdef-1234-567890abcdef\nexport MODERATION_LAMBDA_ARN=arn:aws:lambda:us-east-1:123456789012:function:chime-message-moderator\n```\n\nMinimal client setup:\n\n```javascript\nimport { ChimeSDKMessagingClient } from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a shared profile explicitly:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { ChimeSDKMessagingClient } from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"chime-dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already use environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance profiles.\n\n## Shared Helpers\n\n```javascript\nfunction mustEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing required environment variable: ${name}`);\n  }\n\n  return value;\n}\n\nconst region = process.env.AWS_REGION ?? \"us-east-1\";\nconst appInstanceArn = mustEnv(\"APP_INSTANCE_ARN\");\nconst bearerArn = mustEnv(\"APP_INSTANCE_USER_ARN\");\n```\n\n## Core Usage Pattern\n\nThe normal v3 flow is `client.send(new Command(input))`.\n\nThe snippets below assume `mustEnv`, `region`, `appInstanceArn`, and `bearerArn` from the shared-helper block.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  ListChannelsCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst page = await client.send(\n  new ListChannelsCommand({\n    AppInstanceArn: appInstanceArn,\n    Privacy: \"PUBLIC\",\n    MaxResults: 20,\n    ChimeBearer: bearerArn,\n  }),\n);\n\nfor (const channel of page.Channels ?? []) {\n  console.log(channel.ChannelArn, channel.Name, channel.Privacy);\n}\n```\n\n## Common Operations\n\n### Get the messaging session endpoint\n\nUse this when you need the messaging session endpoint URL for a Chime SDK messaging session.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  GetMessagingSessionEndpointCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst response = await client.send(\n  new GetMessagingSessionEndpointCommand({\n    NetworkType: \"DUAL_STACK\",\n  }),\n);\n\nconsole.log(response.Endpoint?.Url);\n```\n\n`NetworkType` accepts `\"IPV4_ONLY\"` or `\"DUAL_STACK\"`.\n\n### Create a channel\n\n`CreateChannel` requires `AppInstanceArn`, a channel `Name`, a `ClientRequestToken`, and `ChimeBearer`.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  ChimeSDKMessagingClient,\n  CreateChannelCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst created = await client.send(\n  new CreateChannelCommand({\n    AppInstanceArn: appInstanceArn,\n    Name: \"support-room\",\n    Mode: \"UNRESTRICTED\",\n    Privacy: \"PRIVATE\",\n    ClientRequestToken: randomUUID(),\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(created.ChannelArn);\n```\n\nChannel privacy cannot be changed later, so pick `\"PUBLIC\"` vs `\"PRIVATE\"` up front.\n\n### Add members to a channel\n\nAdd a single member:\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  CreateChannelMembershipCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\nconst channelArn = mustEnv(\"CHANNEL_ARN\");\nconst targetMemberArn = mustEnv(\"TARGET_MEMBER_ARN\");\n\nconst membership = await client.send(\n  new CreateChannelMembershipCommand({\n    ChannelArn: channelArn,\n    MemberArn: targetMemberArn,\n    Type: \"DEFAULT\",\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(membership.Member?.Arn);\n```\n\nAdd multiple members in one request:\n\n```javascript\nimport {\n  BatchCreateChannelMembershipCommand,\n  ChimeSDKMessagingClient,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst result = await client.send(\n  new BatchCreateChannelMembershipCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    MemberArns: [\n      mustEnv(\"TARGET_MEMBER_ARN\"),\n      mustEnv(\"SECOND_TARGET_MEMBER_ARN\"),\n    ],\n    Type: \"DEFAULT\",\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(result.BatchChannelMemberships);\nconsole.log(result.Errors);\n```\n\nFor public channels, callers do not need to be a member to list messages, but they must be a member to send messages. For private channels, callers must be a member to list or send messages.\n\n### List channels under an app instance\n\n`ListChannels` returns `NextToken`, so loop until it is empty.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  ListChannelsCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListChannelsCommand({\n      AppInstanceArn: appInstanceArn,\n      Privacy: \"PUBLIC\",\n      MaxResults: 50,\n      NextToken: nextToken,\n      ChimeBearer: bearerArn,\n    }),\n  );\n\n  for (const channel of page.Channels ?? []) {\n    console.log(channel.ChannelArn, channel.Name, channel.LastMessageTimestamp);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nUse `Privacy: \"PUBLIC\"` to retrieve all public channels in the app instance. Listing all private channels at the account level requires an `AppInstanceAdmin` caller.\n\n### Search channels by member\n\n`SearchChannels` searches by channel member. The supported field key is `\"MEMBERS\"`.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  SearchChannelsCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\nconst targetMemberArn = mustEnv(\"TARGET_MEMBER_ARN\");\n\nconst response = await client.send(\n  new SearchChannelsCommand({\n    ChimeBearer: bearerArn,\n    Fields: [\n      {\n        Key: \"MEMBERS\",\n        Operator: \"EQUALS\",\n        Values: [targetMemberArn],\n      },\n    ],\n    MaxResults: 20,\n  }),\n);\n\nfor (const channel of response.Channels ?? []) {\n  console.log(channel.ChannelArn, channel.Name);\n}\n```\n\nUsers and bots can search across channels they belong to. `AppInstanceAdmin` callers can search across all channels. AWS documents that this operation is not supported for `AppInstanceUser` identities with a large number of memberships.\n\n### Send a channel message\n\n`SendChannelMessage` requires explicit `Type`, `Persistence`, `ClientRequestToken`, and `ChimeBearer`.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  ChimeSDKMessagingClient,\n  SendChannelMessageCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\nconst channelArn = mustEnv(\"CHANNEL_ARN\");\n\nconst sent = await client.send(\n  new SendChannelMessageCommand({\n    ChannelArn: channelArn,\n    Content: JSON.stringify({ text: \"hello from the AWS SDK v3\" }),\n    ContentType: \"application/json\",\n    Type: \"STANDARD\",\n    Persistence: \"PERSISTENT\",\n    ClientRequestToken: randomUUID(),\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(sent.MessageId, sent.Status?.Value, sent.Status?.Detail);\n```\n\n`Type` accepts `\"STANDARD\"` or `\"CONTROL\"`. `Persistence` accepts `\"PERSISTENT\"` or `\"NON_PERSISTENT\"`.\n\n### List and inspect channel messages\n\n`ListChannelMessages` returns the latest version of each message. Redacted messages stay in the list with empty content. Deleted messages do not appear.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  GetChannelMessageCommand,\n  ListChannelMessagesCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\nconst channelArn = mustEnv(\"CHANNEL_ARN\");\n\nconst listed = await client.send(\n  new ListChannelMessagesCommand({\n    ChannelArn: channelArn,\n    ChimeBearer: bearerArn,\n    SortOrder: \"ASCENDING\",\n    MaxResults: 20,\n  }),\n);\n\nfor (const message of listed.ChannelMessages ?? []) {\n  console.log(message.MessageId, message.Content, message.Redacted, message.Status?.Value);\n}\n\nconst firstMessageId = listed.ChannelMessages?.[0]?.MessageId;\n\nif (firstMessageId) {\n  const full = await client.send(\n    new GetChannelMessageCommand({\n      ChannelArn: channelArn,\n      MessageId: firstMessageId,\n      ChimeBearer: bearerArn,\n    }),\n  );\n\n  console.log(full.ChannelMessage);\n}\n```\n\n### Update, redact, or delete a message\n\nUpdate a message body:\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  UpdateChannelMessageCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst updated = await client.send(\n  new UpdateChannelMessageCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    MessageId: mustEnv(\"MESSAGE_ID\"),\n    Content: JSON.stringify({ text: \"edited message\" }),\n    ContentType: \"application/json\",\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(updated.Status?.Value, updated.Status?.Detail);\n```\n\nRedact a message so the record remains but the content is removed:\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  RedactChannelMessageCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nawait client.send(\n  new RedactChannelMessageCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    MessageId: mustEnv(\"MESSAGE_ID\"),\n    ChimeBearer: bearerArn,\n  }),\n);\n```\n\nDelete a message entirely:\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  DeleteChannelMessageCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nawait client.send(\n  new DeleteChannelMessageCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    MessageId: mustEnv(\"MESSAGE_ID\"),\n    ChimeBearer: bearerArn,\n  }),\n);\n```\n\nAWS documents `DeleteChannelMessage` as an admin-only action.\n\n### Update the read marker\n\nUse `UpdateChannelReadMarker` when the current user has consumed messages and you want the server-side read position updated.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  UpdateChannelReadMarkerCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst response = await client.send(\n  new UpdateChannelReadMarkerCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    ChimeBearer: bearerArn,\n  }),\n);\n\nconsole.log(response.ChannelArn);\n```\n\n### List the channels a user belongs to\n\nThis is the most direct way to rebuild a user’s channel list.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  ListChannelMembershipsForAppInstanceUserCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListChannelMembershipsForAppInstanceUserCommand({\n      AppInstanceUserArn: bearerArn,\n      MaxResults: 50,\n      NextToken: nextToken,\n      ChimeBearer: bearerArn,\n    }),\n  );\n\n  for (const membership of page.ChannelMemberships ?? []) {\n    console.log(\n      membership.ChannelSummary?.ChannelArn,\n      membership.ChannelSummary?.Name,\n      membership.AppInstanceUserMembershipSummary?.Type,\n    );\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nAn `AppInstanceAdmin` can call this for another user. Non-admin callers should use their own user ARN.\n\n### Set per-channel notification preferences\n\n`PutChannelMembershipPreferences` updates the preferences for a single membership.\n\n```javascript\nimport {\n  ChimeSDKMessagingClient,\n  PutChannelMembershipPreferencesCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst response = await client.send(\n  new PutChannelMembershipPreferencesCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    MemberArn: bearerArn,\n    ChimeBearer: bearerArn,\n    Preferences: {\n      PushNotifications: {\n        AllowNotifications: \"NONE\",\n      },\n    },\n  }),\n);\n\nconsole.log(response.Preferences);\n```\n\nOnly the user or bot that owns the membership can set its preferences.\n\n### Create and associate a channel flow\n\nChannel flows let you run Lambda processors on new and updated standard messages.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  AssociateChannelFlowCommand,\n  ChimeSDKMessagingClient,\n  CreateChannelFlowCommand,\n} from \"@aws-sdk/client-chime-sdk-messaging\";\n\nconst client = new ChimeSDKMessagingClient({ region });\n\nconst created = await client.send(\n  new CreateChannelFlowCommand({\n    AppInstanceArn: appInstanceArn,\n    Name: \"moderation-flow\",\n    ClientRequestToken: randomUUID(),\n    Processors: [\n      {\n        Name: \"message-moderator\",\n        ExecutionOrder: 1,\n        FallbackAction: \"CONTINUE\",\n        Configuration: {\n          Lambda: {\n            ResourceArn: mustEnv(\"MODERATION_LAMBDA_ARN\"),\n            InvocationType: \"ASYNC\",\n          },\n        },\n      },\n    ],\n  }),\n);\n\nawait client.send(\n  new AssociateChannelFlowCommand({\n    ChannelArn: mustEnv(\"CHANNEL_ARN\"),\n    ChannelFlowArn: created.ChannelFlowArn,\n    ChimeBearer: bearerArn,\n  }),\n);\n```\n\nChannel flows process new and updated standard messages, including persistent and non-persistent messages. They do not process control or system messages. Associating a channel flow requires an administrator or channel moderator caller.\n\n## Chime SDK Messaging Gotchas\n\n- `ChimeBearer` is mandatory on most real operations. Use the acting `AppInstanceUserArn` or `AppInstanceBotArn`.\n- This package is not the app-instance bootstrap package. Create app instances and app instance users elsewhere, then pass their ARNs here.\n- Use full ARNs, not short IDs.\n- `CreateChannel` requires a client request token, and channel privacy cannot be changed later.\n- `SendChannelMessage` also requires a client request token and an explicit `Persistence` mode.\n- There are no generated v3 paginators for this service in the local AWS model metadata, so loop on `NextToken` yourself.\n- `SearchChannels` only searches by members. The supported field key is `MEMBERS`.\n- `ListChannelMessages` returns edited messages in their latest form. Redacted messages remain in results with empty content, while deleted messages disappear.\n- Keep these calls server-side unless you already have a browser-safe temporary credential flow for the acting user or bot.\n\n## Related Packages\n\n- `@aws-sdk/client-chime-sdk-identity` for app instances, app instance users, and other identity setup.\n- `@aws-sdk/credential-providers` if you want `fromIni` or other explicit credential-provider helpers.\n"
  },
  {
    "path": "content/aws/docs/cleanrooms/javascript/DOC.md",
    "content": "---\nname: cleanrooms\ndescription: \"AWS SDK for JavaScript v3 client for creating collaborations, joining memberships, configuring tables, inspecting schemas, and running protected queries in AWS Clean Rooms\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cleanrooms,javascript,nodejs,sql,analytics,collaboration\"\n---\n\n# AWS Clean Rooms SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-cleanrooms` to manage AWS Clean Rooms collaborations and memberships, register tables for collaboration use, inspect schemas, and start protected SQL queries.\n\nThis package is the Clean Rooms control-plane client. It creates and manages Clean Rooms resources in AWS. It does not execute queries locally.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-cleanrooms`, not the legacy `aws-sdk` v2 package.\n- Set `region` explicitly or through the standard AWS SDK credential and region chain.\n- Most write operations use UUID-style resource identifiers such as `collaborationIdentifier`, `membershipIdentifier`, and `configuredTableIdentifier`, not display names.\n- `CreateConfiguredTableAssociationCommand` gives a table an alias inside the collaboration. That alias is the relation name you use with `GetSchemaCommand` and in protected SQL.\n- Query execution depends on analysis rules being configured for the shared schema. Check `schemaStatusDetails` and wait for `READY` before assuming a query can run.\n- Clean Rooms does not provide modeled waiters for protected queries. Poll `GetProtectedQueryCommand` until the query reaches a terminal status.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cleanrooms\n```\n\nIf you want to load a named AWS profile directly in code, also install the credential helpers:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nBefore you create the client, make sure you already have:\n\n- AWS credentials with permission to call Clean Rooms and any related IAM, Glue, Athena, or S3 resources you use\n- an AWS region where your Clean Rooms collaboration resources live\n- a collaboration invitation or collaboration owner account, depending on whether you are joining or creating a collaboration\n- an IAM role for table access when creating configured table associations\n- an IAM role for protected query result delivery if you want results written to S3\n\nTypical local environment variables:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\"\n\nexport PARTNER_ACCOUNT_ID=\"123456789012\"\nexport COLLABORATION_ID=\"11111111-2222-3333-4444-555555555555\"\nexport MEMBERSHIP_ID=\"66666666-7777-8888-9999-000000000000\"\n\nexport CLEANROOMS_TABLE_ROLE_ARN=\"arn:aws:iam::123456789012:role/CleanRoomsTableAccessRole\"\nexport CLEANROOMS_RESULTS_ROLE_ARN=\"arn:aws:iam::123456789012:role/CleanRoomsResultsWriteRole\"\nexport CLEANROOMS_RESULTS_BUCKET=\"my-cleanrooms-results\"\n```\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { CleanRoomsClient } from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { CleanRoomsClient } from \"@aws-sdk/client-cleanrooms\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst cleanrooms = new CleanRoomsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already use environment variables, shared AWS config, ECS task credentials, or EC2 instance credentials.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  ListCollaborationsCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst response = await cleanrooms.send(\n  new ListCollaborationsCommand({\n    memberStatus: \"ACTIVE\",\n    maxResults: 25,\n  }),\n);\n\nfor (const collaboration of response.collaborationList ?? []) {\n  console.log(collaboration.id, collaboration.name, collaboration.memberStatus);\n}\n```\n\n## Common Workflows\n\n### List active memberships with pagination\n\n```javascript\nimport {\n  CleanRoomsClient,\n  ListMembershipsCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await cleanrooms.send(\n    new ListMembershipsCommand({\n      status: \"ACTIVE\",\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const membership of page.membershipSummaries ?? []) {\n    console.log(\n      membership.id,\n      membership.collaborationName,\n      membership.status,\n      membership.memberAbilities,\n    );\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\nThe list operations in Clean Rooms are paginated. Keep following `nextToken` until it is absent.\n\n### Create a collaboration\n\nUse this from the collaboration owner account. The initial `members` list does not include the creator.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  CreateCollaborationCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst { collaboration } = await cleanrooms.send(\n  new CreateCollaborationCommand({\n    name: \"retail-measurement\",\n    description: \"Shared campaign measurement collaboration\",\n    creatorDisplayName: \"Acme Retail\",\n    creatorMemberAbilities: [\"CAN_QUERY\", \"CAN_RECEIVE_RESULTS\"],\n    members: [\n      {\n        accountId: process.env.PARTNER_ACCOUNT_ID,\n        displayName: \"Contoso Ads\",\n        memberAbilities: [\"CAN_QUERY\", \"CAN_RECEIVE_RESULTS\"],\n      },\n    ],\n    queryLogStatus: \"ENABLED\",\n    tags: {\n      project: \"retail-measurement\",\n    },\n  }),\n);\n\nconsole.log(collaboration?.id, collaboration?.arn, collaboration?.name);\n```\n\nThe returned collaboration object includes the collaboration ID and, for the caller, the membership ID and ARN when applicable.\n\n### Join an invited collaboration and set default query result delivery\n\nUse `CreateMembershipCommand` from the invited member account after the collaboration exists.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  CreateMembershipCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst { membership } = await cleanrooms.send(\n  new CreateMembershipCommand({\n    collaborationIdentifier: process.env.COLLABORATION_ID,\n    queryLogStatus: \"ENABLED\",\n    defaultResultConfiguration: {\n      outputConfiguration: {\n        s3: {\n          resultFormat: \"CSV\",\n          bucket: process.env.CLEANROOMS_RESULTS_BUCKET,\n          keyPrefix: \"protected-queries/\",\n          singleFileOutput: true,\n        },\n      },\n      roleArn: process.env.CLEANROOMS_RESULTS_ROLE_ARN,\n    },\n  }),\n);\n\nconsole.log(membership?.id, membership?.status, membership?.collaborationName);\n```\n\nWhen you want query results written to S3, set the membership's default result configuration and result-writing role. That role is separate from the table access role used by configured table associations.\n\n### Create a configured table for a Glue table\n\nThe current API can model multiple table reference types. This example uses a Glue table because it is the most common Clean Rooms setup.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  CreateConfiguredTableCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst { configuredTable } = await cleanrooms.send(\n  new CreateConfiguredTableCommand({\n    name: \"orders_configured\",\n    description: \"Order facts shared into the collaboration\",\n    tableReference: {\n      glue: {\n        region: process.env.AWS_REGION ?? \"us-east-1\",\n        databaseName: \"analytics\",\n        tableName: \"orders\",\n      },\n    },\n    allowedColumns: [\"customer_id\", \"order_date\", \"order_total\"],\n    analysisMethod: \"DIRECT_QUERY\",\n  }),\n);\n\nconsole.log(configuredTable?.id, configuredTable?.name, configuredTable?.analysisMethod);\n```\n\n`analysisMethod` is currently `DIRECT_QUERY` for configured tables.\n\n### Associate the configured table with a membership\n\nThe configured table association creates the relation alias used inside the collaboration.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  CreateConfiguredTableAssociationCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst { configuredTableAssociation } = await cleanrooms.send(\n  new CreateConfiguredTableAssociationCommand({\n    name: \"orders_shared\",\n    description: \"Orders available to collaboration members\",\n    membershipIdentifier: process.env.MEMBERSHIP_ID,\n    configuredTableIdentifier: \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\n    roleArn: process.env.CLEANROOMS_TABLE_ROLE_ARN,\n  }),\n);\n\nconsole.log(\n  configuredTableAssociation?.id,\n  configuredTableAssociation?.name,\n  configuredTableAssociation?.configuredTableId,\n);\n```\n\nUse the association `name` such as `orders_shared` as the table name in protected SQL. Clean Rooms returns the association name in lowercase for querying.\n\n### Inspect shared schemas and readiness\n\nBefore running SQL, inspect the schema exposed inside the collaboration and make sure the schema status is ready for the analysis rule you expect to use.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  GetSchemaCommand,\n  ListSchemasCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nconst list = await cleanrooms.send(\n  new ListSchemasCommand({\n    collaborationIdentifier: process.env.COLLABORATION_ID,\n    maxResults: 50,\n  }),\n);\n\nfor (const schema of list.schemaSummaries ?? []) {\n  console.log(schema.name, schema.type, schema.analysisMethod);\n}\n\nconst detail = await cleanrooms.send(\n  new GetSchemaCommand({\n    collaborationIdentifier: process.env.COLLABORATION_ID,\n    name: \"orders_shared\",\n  }),\n);\n\nconsole.table(\n  (detail.schema?.columns ?? []).map((column) => ({\n    name: column.name,\n    type: column.type,\n  })),\n);\n\nfor (const status of detail.schema?.schemaStatusDetails ?? []) {\n  console.log(status.analysisRuleType, status.analysisType, status.status);\n}\n```\n\n`schemaStatusDetails.status` is the important readiness signal. A status of `READY` means Clean Rooms considers the schema properly configured for queries of that analysis rule type.\n\n### Start a protected SQL query and poll until it finishes\n\nThis example writes results to S3. It assumes the membership already has compatible analysis rules and an S3 result role configured.\n\n```javascript\nimport {\n  CleanRoomsClient,\n  GetProtectedQueryCommand,\n  StartProtectedQueryCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nfunction sleep(ms) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst started = await cleanrooms.send(\n  new StartProtectedQueryCommand({\n    type: \"SQL\",\n    membershipIdentifier: process.env.MEMBERSHIP_ID,\n    sqlParameters: {\n      queryString: `\n        SELECT customer_id, SUM(order_total) AS total_revenue\n        FROM orders_shared\n        GROUP BY customer_id\n      `,\n    },\n    resultConfiguration: {\n      outputConfiguration: {\n        s3: {\n          resultFormat: \"CSV\",\n          bucket: process.env.CLEANROOMS_RESULTS_BUCKET,\n          keyPrefix: \"protected-queries/run-001/\",\n          singleFileOutput: true,\n        },\n      },\n    },\n  }),\n);\n\nconst protectedQueryId = started.protectedQuery?.id;\n\nif (!protectedQueryId) {\n  throw new Error(\"Clean Rooms did not return a protected query ID\");\n}\n\nasync function waitForProtectedQuery(id) {\n  for (;;) {\n    const { protectedQuery } = await cleanrooms.send(\n      new GetProtectedQueryCommand({\n        membershipIdentifier: process.env.MEMBERSHIP_ID,\n        protectedQueryIdentifier: id,\n      }),\n    );\n\n    console.log(protectedQuery?.status, protectedQuery?.statistics?.totalDurationInMillis);\n\n    if (protectedQuery?.status === \"SUCCESS\") {\n      return protectedQuery;\n    }\n\n    if (protectedQuery?.status === \"FAILED\" || protectedQuery?.status === \"TIMED_OUT\") {\n      throw new Error(\n        protectedQuery?.error?.message ?? `Protected query failed with status ${protectedQuery?.status}`,\n      );\n    }\n\n    if (protectedQuery?.status === \"CANCELLED\") {\n      throw new Error(\"Protected query was cancelled\");\n    }\n\n    await sleep(5000);\n  }\n}\n\nconst finished = await waitForProtectedQuery(protectedQueryId);\n\nconsole.log(finished.result?.output?.s3?.location);\n```\n\n`StartProtectedQueryCommand` currently uses `type: \"SQL\"`.\n\n### Cancel a running protected query\n\n```javascript\nimport {\n  CleanRoomsClient,\n  UpdateProtectedQueryCommand,\n} from \"@aws-sdk/client-cleanrooms\";\n\nconst cleanrooms = new CleanRoomsClient({ region: \"us-east-1\" });\n\nawait cleanrooms.send(\n  new UpdateProtectedQueryCommand({\n    membershipIdentifier: process.env.MEMBERSHIP_ID,\n    protectedQueryIdentifier: \"ffffffff-1111-2222-3333-444444444444\",\n    targetStatus: \"CANCELLED\",\n  }),\n);\n```\n\nFor protected queries, the modeled update target status is `CANCELLED`.\n\n## Important Pitfalls\n\n- `CreateConfiguredTableCommand` registers metadata and allowed columns, but protected queries still depend on analysis rules. If `GetSchemaCommand` shows `NOT_READY`, fix the rule configuration before querying.\n- `CreateConfiguredTableAssociationCommand` needs a `roleArn` for table access. That role is different from the membership-level `roleArn` used for S3 query results.\n- Query results do not appear inline in the `StartProtectedQueryCommand` response. Poll `GetProtectedQueryCommand` and read the result output location from the finished query object.\n- `ListSchemasCommand` and `GetSchemaCommand` address schemas by collaboration ID plus relation name, not by configured table ID.\n- `DeleteMembershipCommand` only succeeds after resources under that membership are removed. `DeleteCollaborationCommand` can only be called by the collaboration owner.\n- Display names are not unique. Persist the IDs and ARNs returned by create calls instead of re-looking up resources by name.\n\n## Useful Commands To Pair With This SDK\n\nIf you need to inspect the current API shape from AWS without leaving the terminal, the AWS CLI exposes the same service model:\n\n```bash\naws cleanrooms help\naws cleanrooms create-configured-table --generate-cli-skeleton input\naws cleanrooms start-protected-query --generate-cli-skeleton input\n```\n\nThese are useful when you need a quick JSON template for less common fields such as analysis templates, distributed outputs, Athena or Snowflake table references, or newer Clean Rooms features that your app wants to adopt.\n"
  },
  {
    "path": "content/aws/docs/cli/python/DOC.md",
    "content": "---\nname: cli\ndescription: \"awscli package guide for Python environments: install AWS CLI v1, configure credentials and profiles, and run AWS commands safely in scripts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.44.56\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,awscli,cli,python,cloud,devops\"\n---\n\n# awscli Python Package Guide\n\n## What This Package Is\n\n`awscli` is the PyPI package that installs the AWS CLI v1 `aws` executable.\n\nUse it when you need to:\n\n- install a pinned AWS CLI into a Python virtual environment\n- run AWS commands from a shell, CI job, or deployment script\n- call the CLI from Python with `subprocess`\n\nDo not use `awscli` as your default Python SDK. If the task is \"call AWS APIs from Python code\", prefer `boto3` or `botocore`.\n\nFor this package entry, the version used here is `1.44.56`, which is part of the AWS CLI v1 line. Use AWS CLI v1 docs under `https://docs.aws.amazon.com/cli/v1/`, not the moving `latest/reference` URL.\n\n## Install\n\nPin the package version explicitly in automation:\n\n```bash\npython -m pip install \"awscli==1.44.56\"\naws --version\n```\n\nExpected prefix:\n\n```text\naws-cli/1.44.56\n```\n\nUse a virtual environment if the machine may also have AWS CLI v2 or an OS-packaged `aws` binary on `PATH`:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"awscli==1.44.56\"\nwhich aws\naws --version\n```\n\nIf you need to confirm the installed Python package and executable match:\n\n```bash\npython -m pip show awscli\nwhich aws\naws --version\n```\n\n## Python Compatibility\n\nAWS CLI v1 installation docs group versions `1.39.0` and later into the Python `3.9+` support band. Treat `awscli==1.44.56` as a Python 3.9+ package unless your environment-specific testing proves otherwise.\n\nFor reproducible CI, pin both:\n\n- the Python runtime\n- the `awscli` version\n\n## First-Time Setup\n\nThe basic setup flow is:\n\n```bash\naws configure\n```\n\nThat writes to the shared AWS CLI files:\n\n- `~/.aws/credentials`\n- `~/.aws/config`\n\nSanity-check the active identity before making changes:\n\n```bash\naws sts get-caller-identity\n```\n\nCommon smoke tests:\n\n```bash\naws s3 ls\naws ec2 describe-regions --output json\n```\n\n## Credentials, Config Files, and Profiles\n\nAWS CLI v1 uses two files with different profile-section conventions:\n\n- `~/.aws/credentials` uses `[default]` or `[work]`\n- `~/.aws/config` uses `[default]` or `[profile work]`\n\nExample:\n\n```ini\n# ~/.aws/credentials\n[default]\naws_access_key_id = AKIA...\naws_secret_access_key = ...\n\n[work]\naws_access_key_id = AKIA...\naws_secret_access_key = ...\naws_session_token = ...\n```\n\n```ini\n# ~/.aws/config\n[default]\nregion = us-west-2\noutput = json\n\n[profile work]\nregion = us-east-1\noutput = json\n```\n\nPick a non-default profile either per command:\n\n```bash\naws s3 ls --profile work\n```\n\nor for a shell session:\n\n```bash\nexport AWS_PROFILE=work\n```\n\nUseful config commands:\n\n```bash\naws configure list\naws configure get region --profile work\naws configure set region us-east-1 --profile work\naws configure set output json --profile work\n```\n\nAssume-role profile example:\n\n```ini\n[profile admin]\nrole_arn = arn:aws:iam::123456789012:role/Admin\nsource_profile = work\nregion = us-east-1\noutput = json\n```\n\n## Environment Variables\n\nCommon environment variables for automation:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-west-2\nexport AWS_DEFAULT_OUTPUT=json\nexport AWS_PROFILE=work\n```\n\nUseful path overrides:\n\n```bash\nexport AWS_SHARED_CREDENTIALS_FILE=/tmp/aws-credentials\nexport AWS_CONFIG_FILE=/tmp/aws-config\n```\n\nPrefer:\n\n- named profiles for local development across multiple accounts\n- explicit environment variables for short-lived CI jobs\n- `AWS_SESSION_TOKEN` whenever credentials come from STS or assumed roles\n\n## Core Usage\n\nCLI command shape:\n\n```bash\naws <service> <operation> [options]\n```\n\nHelp is available at every level:\n\n```bash\naws help\naws s3 help\naws s3 cp help\n```\n\nGood defaults for scripts:\n\n- use `--output json`\n- use `--query` to extract only the fields you need\n- pass `--region` explicitly when the script must be portable\n- pass `--profile` explicitly when the account must be unambiguous\n\nExamples:\n\n```bash\naws sts get-caller-identity --output json\n```\n\n```bash\naws ec2 describe-instances \\\n  --filters \"Name=instance-state-name,Values=running\" \\\n  --query 'Reservations[].Instances[].{Id:InstanceId,Type:InstanceType,AZ:Placement.AvailabilityZone}' \\\n  --output json\n```\n\n```bash\naws s3 cp ./build.zip s3://my-bucket/build.zip --profile work --region us-east-1\n```\n\n## Calling The CLI From Python\n\nTreat `awscli` as a subprocess dependency, not as a stable in-process library API.\n\n```python\nimport json\nimport subprocess\n\ndef caller_identity(profile: str = \"default\", region: str = \"us-west-2\") -> dict:\n    result = subprocess.run(\n        [\n            \"aws\",\n            \"sts\",\n            \"get-caller-identity\",\n            \"--profile\",\n            profile,\n            \"--region\",\n            region,\n            \"--output\",\n            \"json\",\n        ],\n        check=True,\n        capture_output=True,\n        text=True,\n    )\n    return json.loads(result.stdout)\n```\n\nGuidelines:\n\n- keep `shell=False`\n- request JSON output and parse it\n- pin `--profile` and `--region`\n- surface `stderr` on failures because AWS CLI errors are usually actionable\n\n## Output, Queries, and Pagination\n\nAWS CLI v1 supports `json`, `text`, and `table` output.\n\n- `json` is the safest default for automation\n- `table` is for humans\n- `text` is easy to break if you later change the query shape\n\nAWS's filtering guide warns that on paginated responses, `--query` behaves differently with `--output text` because the query is applied per page. For stable machine-readable results, prefer `--output json` and then parse the JSON.\n\nExamples:\n\n```bash\naws iam list-users --output json --query 'Users[].UserName'\n```\n\n```bash\naws cloudformation describe-stacks \\\n  --stack-name my-stack \\\n  --output json \\\n  --query 'Stacks[0].Outputs'\n```\n\nIf a command is paginated and you need complete results in a script, read the command help for pagination flags and test with realistic account-sized datasets.\n\n## Version-Sensitive Notes\n\n- `awscli` on PyPI is the AWS CLI v1 line. Do not mix v1 guidance with AWS CLI v2 blog posts or examples.\n- The docs URL, `https://docs.aws.amazon.com/cli/latest/reference/`, is not version-pinned. For this package, prefer `https://docs.aws.amazon.com/cli/v1/`.\n- AWS's v1 documentation now carries an end-of-support notice. For new greenfield environments, prefer AWS CLI v2 unless the project is explicitly pinned to `awscli` v1 on PyPI.\n- PyPI may show newer releases than the version covered here. This doc is intentionally pinned to `1.44.56`.\n\n## Common Pitfalls\n\n### Wrong `aws` on `PATH`\n\nIf the machine has multiple AWS CLI installs, the binary you invoke may not match the Python package you just installed.\n\nCheck:\n\n```bash\nwhich aws\naws --version\npython -m pip show awscli\n```\n\n### Wrong docs\n\nDo not use generic AWS CLI \"latest\" docs when the task is pinned to a PyPI `awscli` version. Start from AWS CLI v1 docs.\n\n### Missing region\n\nMany commands fail or behave inconsistently when no region is configured. Set one in the profile, export `AWS_DEFAULT_REGION`, or pass `--region`.\n\n### Temporary credentials without session token\n\nIf the credentials come from STS or an assumed role, `AWS_SESSION_TOKEN` is required with the access key and secret key.\n\n### Account mix-ups\n\nScripts that rely on the implicit default profile are easy to run against the wrong account. Prefer explicit `--profile` and `--region`.\n\n### Fragile `text` parsing\n\n`--output text` is convenient for shell experiments but brittle in automation, especially with pagination and `--query`.\n\n## Official Sources\n\n- AWS CLI v1 user guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-welcome.html`\n- AWS CLI v1 install guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-install.html`\n- AWS CLI v1 command reference: `https://docs.aws.amazon.com/cli/v1/reference/`\n- AWS CLI v1 config files guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html`\n- AWS CLI v1 environment variables guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-envvars.html`\n- AWS CLI v1 output format guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-usage-output-format.html`\n- AWS CLI v1 filtering guide: `https://docs.aws.amazon.com/cli/v1/userguide/cli-usage-filter.html`\n- PyPI package page: `https://pypi.org/project/awscli/`\n"
  },
  {
    "path": "content/aws/docs/cloudformation/javascript/DOC.md",
    "content": "---\nname: cloudformation\ndescription: \"AWS SDK for JavaScript v3 CloudFormation client for creating, updating, and inspecting stacks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,cloudformation,javascript,nodejs,browser,infrastructure\"\n---\n\n# `@aws-sdk/client-cloudformation`\n\nUse this package for Amazon CloudFormation from AWS SDK for JavaScript v3. It follows the v3 client-plus-command pattern and works in Node.js, browsers, and React Native.\n\nPrefer `CloudFormationClient` plus explicit command imports. The package also exposes an aggregated `CloudFormation` client, but command-based imports are the safer default for clearer usage and smaller bundles.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cloudformation\n```\n\n## Initialize the client\n\n```javascript\nimport { CloudFormationClient } from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS access is already configured through environment variables, shared config files, IAM roles, or IAM Identity Center.\n\n## Credentials and Region\n\n- Node.js: credentials often come from environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n- Browser runtimes: use an explicit browser-safe credential provider such as Cognito identity; do not hard-code access keys in client-side code.\n- Region is required somewhere. Set it in the client constructor, via `AWS_REGION`, or via shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n```javascript\nimport {\n  CloudFormationClient,\n  DescribeStacksCommand,\n} from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n\nconst response = await cloudformation.send(\n  new DescribeStacksCommand({\n    StackName: \"app-infra\",\n  }),\n);\n\nconst stack = response.Stacks?.[0];\nconsole.log(stack?.StackStatus);\n```\n\n## Common Operations\n\n### Create a stack from a template URL\n\n```javascript\nimport {\n  CloudFormationClient,\n  CreateStackCommand,\n} from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n\nconst response = await cloudformation.send(\n  new CreateStackCommand({\n    StackName: \"app-infra\",\n    TemplateURL: \"https://s3.amazonaws.com/example-bucket/templates/app.yaml\",\n    Parameters: [\n      {\n        ParameterKey: \"Environment\",\n        ParameterValue: \"prod\",\n      },\n    ],\n    Capabilities: [\"CAPABILITY_NAMED_IAM\"],\n    Tags: [{ Key: \"service\", Value: \"billing\" }],\n  }),\n);\n\nconsole.log(response.StackId);\n```\n\nUse `Capabilities` only when the template requires them, such as when it creates or updates IAM resources.\n\n### Update a stack\n\n```javascript\nimport {\n  CloudFormationClient,\n  UpdateStackCommand,\n} from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n\ntry {\n  const response = await cloudformation.send(\n    new UpdateStackCommand({\n      StackName: \"app-infra\",\n      TemplateURL: \"https://s3.amazonaws.com/example-bucket/templates/app.yaml\",\n      Parameters: [\n        {\n          ParameterKey: \"Environment\",\n          ParameterValue: \"prod\",\n        },\n      ],\n      Capabilities: [\"CAPABILITY_NAMED_IAM\"],\n    }),\n  );\n\n  console.log(response.StackId);\n} catch (error) {\n  if (\n    error.name === \"ValidationError\" &&\n    error.message?.includes(\"No updates are to be performed\")\n  ) {\n    console.log(\"Stack is already up to date.\");\n  } else {\n    throw error;\n  }\n}\n```\n\n### Delete a stack\n\n```javascript\nimport {\n  CloudFormationClient,\n  DeleteStackCommand,\n} from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n\nawait cloudformation.send(\n  new DeleteStackCommand({\n    StackName: \"app-infra\",\n  }),\n);\n```\n\n### Describe recent stack events\n\n```javascript\nimport {\n  CloudFormationClient,\n  DescribeStackEventsCommand,\n} from \"@aws-sdk/client-cloudformation\";\n\nconst cloudformation = new CloudFormationClient({ region: \"us-east-1\" });\n\nconst response = await cloudformation.send(\n  new DescribeStackEventsCommand({\n    StackName: \"app-infra\",\n  }),\n);\n\nfor (const event of response.StackEvents ?? []) {\n  console.log(event.Timestamp, event.ResourceStatus, event.LogicalResourceId);\n}\n```\n\n## CloudFormation-Specific Gotchas\n\n- `CreateStack`, `UpdateStack`, and `DeleteStack` are asynchronous. Do not assume success until the stack reaches a terminal status.\n- Use change sets when you want to review the impact of a template change before execution.\n- `TemplateBody` is convenient for small inline templates; larger templates are usually stored in S3 and referenced with `TemplateURL`.\n- A template that creates or updates IAM resources requires an explicit capability acknowledgement such as `CAPABILITY_IAM` or `CAPABILITY_NAMED_IAM`.\n- `UpdateStack` commonly returns a `ValidationError` with `No updates are to be performed` when the resolved template and parameters do not change the stack.\n- Parameter values are passed as strings, even when the template interprets them as numbers or booleans.\n- Stack deletion can fail when resources still have external dependencies or retention settings.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and other credential providers.\n- `@aws-sdk/client-s3`: storing and versioning templates in S3 before deploying them with CloudFormation.\n"
  },
  {
    "path": "content/aws/docs/cloudfront/javascript/DOC.md",
    "content": "---\nname: cloudfront\ndescription: \"AWS SDK for JavaScript v3 CloudFront client for distributions, invalidations, and edge configuration APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,cloudfront,javascript,nodejs,browser,cdn\"\n---\n\n# `@aws-sdk/client-cloudfront`\n\nUse this package for Amazon CloudFront control-plane APIs in AWS SDK for JavaScript v3: distributions, invalidations, cache policies, origin request policies, response headers policies, and related edge configuration resources.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cloudfront\n```\n\nPrefer `CloudFrontClient` plus explicit command imports. The package also exposes an aggregated `CloudFront` client, but command-based imports are the safer default for smaller bundles and clearer dependency boundaries.\n\n## Initialize the client\n\n```javascript\nimport { CloudFrontClient } from \"@aws-sdk/client-cloudfront\";\n\nconst cloudfront = new CloudFrontClient({\n  region: \"us-east-1\",\n});\n```\n\nCloudFront is a global service, but the SDK still needs a region for configuration and request signing. In practice, JavaScript SDK examples commonly use `us-east-1` for CloudFront control-plane calls.\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain usually works if AWS access is already configured through environment variables, shared config files, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: use an explicit credential provider such as Cognito identity; do not ship privileged CloudFront management credentials to the browser.\n- Keep region setup simple and consistent. For CloudFront control-plane code, prefer `us-east-1` unless you have an explicit endpoint strategy.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  CloudFrontClient,\n  ListDistributionsCommand,\n} from \"@aws-sdk/client-cloudfront\";\n\nconst cloudfront = new CloudFrontClient({ region: \"us-east-1\" });\n\nconst response = await cloudfront.send(\n  new ListDistributionsCommand({ MaxItems: 25 }),\n);\n\nfor (const distribution of response.DistributionList?.Items ?? []) {\n  console.log(distribution.Id, distribution.DomainName, distribution.Enabled);\n}\n```\n\n## CloudFront-Specific Gotchas\n\n- CloudFront configuration changes are asynchronous. A successful create or update call does not mean the new behavior is already deployed at edge locations.\n- `UpdateDistribution` is a full-config replace flow. Read the current config first, keep required fields, and send `IfMatch` with the current `ETag`.\n- `CreateInvalidation` requires a unique `CallerReference`. Reusing one can return an existing invalidation instead of creating a new request.\n- Delete flows are multi-step: disable the distribution, wait for deployment, then delete with the latest `ETag`.\n- Signed URLs and signed cookies are not the main job of this client. Use `@aws-sdk/cloudfront-signer` for signing helpers.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/cloudfront-signer`: create signed URLs and signed cookies for private content.\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role, shared config, and other credential helpers.\n\n## Common CloudFront operations\n\n### List distributions\n\n```javascript\nimport {\n  CloudFrontClient,\n  ListDistributionsCommand,\n} from \"@aws-sdk/client-cloudfront\";\n\nconst cloudfront = new CloudFrontClient({ region: \"us-east-1\" });\n\nconst { DistributionList } = await cloudfront.send(\n  new ListDistributionsCommand({ MaxItems: 25 }),\n);\n\nfor (const distribution of DistributionList?.Items ?? []) {\n  console.log({\n    id: distribution.Id,\n    domainName: distribution.DomainName,\n    enabled: distribution.Enabled,\n    status: distribution.Status,\n  });\n}\n```\n\n### Create an invalidation\n\n```javascript\nimport {\n  CloudFrontClient,\n  CreateInvalidationCommand,\n} from \"@aws-sdk/client-cloudfront\";\n\nconst cloudfront = new CloudFrontClient({ region: \"us-east-1\" });\n\nconst response = await cloudfront.send(\n  new CreateInvalidationCommand({\n    DistributionId: \"E1234567890ABC\",\n    InvalidationBatch: {\n      CallerReference: `deploy-${Date.now()}`,\n      Paths: {\n        Quantity: 2,\n        Items: [\"/index.html\", \"/assets/*\"],\n      },\n    },\n  }),\n);\n\nconsole.log(response.Invalidation?.Id, response.Invalidation?.Status);\n```\n\nKeep `CallerReference` unique for each invalidation request you intend to create.\n\n### Update a distribution\n\nCloudFront updates use a read-modify-write flow. Fetch the full config and current `ETag` first, then send the updated config back with `IfMatch`.\n\n```javascript\nimport {\n  CloudFrontClient,\n  GetDistributionConfigCommand,\n  UpdateDistributionCommand,\n} from \"@aws-sdk/client-cloudfront\";\n\nconst cloudfront = new CloudFrontClient({ region: \"us-east-1\" });\nconst id = \"E1234567890ABC\";\n\nconst { DistributionConfig, ETag } = await cloudfront.send(\n  new GetDistributionConfigCommand({ Id: id }),\n);\n\nif (!DistributionConfig || !ETag) {\n  throw new Error(\"Distribution config lookup failed.\");\n}\n\nconst response = await cloudfront.send(\n  new UpdateDistributionCommand({\n    Id: id,\n    IfMatch: ETag,\n    DistributionConfig: {\n      ...DistributionConfig,\n      Comment: \"Updated from AWS SDK for JavaScript v3\",\n    },\n  }),\n);\n\nconsole.log(response.Distribution?.Id, response.ETag);\n```\n\nIf another process updates the distribution first, the `ETag` changes and your update can fail until you refetch the latest config.\n\n### Disable before delete\n\nCloudFront does not let you delete an enabled distribution. The usual sequence is:\n\n1. Read the current config and `ETag`.\n2. Update the distribution with `Enabled: false`.\n3. Wait until the distribution finishes deploying.\n4. Delete it with the newest `ETag`.\n\nTreat deletes as an operational workflow, not a single call.\n"
  },
  {
    "path": "content/aws/docs/cloudfront-signer/javascript/DOC.md",
    "content": "---\nname: cloudfront-signer\ndescription: \"AWS SDK for JavaScript v3 helpers for creating CloudFront signed URLs and signed cookies for private content.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1005.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cloudfront,javascript,nodejs,cdn,signed-urls,signed-cookies\"\n---\n\n# `@aws-sdk/cloudfront-signer`\n\nUse this package to create CloudFront signed URLs and signed cookies in AWS SDK for JavaScript v3.\n\nThis package signs locally with your CloudFront private key. It does not create an AWS service client, does not call CloudFront APIs, and does not need `AWS_REGION` or AWS access keys just to generate signatures.\n\nUse `@aws-sdk/client-cloudfront` when you need to manage distributions, invalidations, cache behaviors, or other CloudFront control-plane resources.\n\n## Install\n\n```bash\nnpm install @aws-sdk/cloudfront-signer@3.1005.0\n```\n\n## Prerequisites\n\nBefore you can sign anything, CloudFront must already be configured for private content:\n\n- A CloudFront distribution serves the content.\n- CloudFront trusts the public key that matches the private key your app will use for signing.\n- You know the CloudFront key pair ID for that public key.\n- You sign the CloudFront URL or alternate domain name that viewers actually request.\n\nDo the signing on your server or another trusted backend. Do not ship the private key to browser code.\n\n## Load the signing inputs\n\nThe package expects a `keyPairId`, a private key, and either an expiration time or a custom policy. A practical Node.js setup is:\n\n```bash\nexport CLOUDFRONT_KEY_PAIR_ID=K2JCJMDEHXQW5F\nexport CLOUDFRONT_PRIVATE_KEY_PATH=./cloudfront-private-key.pem\nexport CLOUDFRONT_URL_BASE=https://d111111abcdef8.cloudfront.net\n```\n\n```javascript\nimport { readFileSync } from \"node:fs\";\n\nconst keyPairId = process.env.CLOUDFRONT_KEY_PAIR_ID;\nconst privateKeyPath = process.env.CLOUDFRONT_PRIVATE_KEY_PATH;\nconst urlBase = process.env.CLOUDFRONT_URL_BASE;\n\nif (!keyPairId || !urlBase) {\n  throw new Error(\"Set CLOUDFRONT_KEY_PAIR_ID and CLOUDFRONT_URL_BASE\");\n}\n\nconst privateKey = process.env.CLOUDFRONT_PRIVATE_KEY\n  ? process.env.CLOUDFRONT_PRIVATE_KEY.replace(/\\\\n/g, \"\\n\")\n  : privateKeyPath\n    ? readFileSync(privateKeyPath, \"utf8\")\n    : null;\n\nif (!privateKey) {\n  throw new Error(\n    \"Set CLOUDFRONT_PRIVATE_KEY or CLOUDFRONT_PRIVATE_KEY_PATH\",\n  );\n}\n```\n\nIf you store the PEM in an environment variable, keep the newline normalization step. Many secret managers flatten multi-line values.\n\n## Create a signed URL\n\n`getSignedUrl()` returns the final viewer URL with the CloudFront signature parameters already attached.\n\n```javascript\nimport { getSignedUrl } from \"@aws-sdk/cloudfront-signer\";\n\nconst assetUrl = `${urlBase}/private/reports/quarterly.pdf`;\nconst expiresAt = new Date(Date.now() + 60 * 60 * 1000).toISOString();\n\nconst signedUrl = getSignedUrl({\n  url: assetUrl,\n  keyPairId,\n  dateLessThan: expiresAt,\n  privateKey,\n});\n\nconsole.log(signedUrl);\n```\n\nBuild the full URL before signing it. If you change the path, hostname, or query string after signing, the signature no longer matches.\n\n## Sign a URL that already has query parameters\n\nIf the viewer URL needs query parameters, add them first and sign the final string.\n\n```javascript\nimport { getSignedUrl } from \"@aws-sdk/cloudfront-signer\";\n\nconst downloadUrl = new URL(`${urlBase}/private/export.csv`);\ndownloadUrl.searchParams.set(\"download\", \"1\");\ndownloadUrl.searchParams.set(\"filename\", \"export.csv\");\n\nconst signedUrl = getSignedUrl({\n  url: downloadUrl.toString(),\n  keyPairId,\n  dateLessThan: new Date(Date.now() + 15 * 60 * 1000).toISOString(),\n  privateKey,\n});\n```\n\n## Create signed cookies\n\nUse `getSignedCookies()` when the browser should fetch protected content with cookies instead of a per-link signed URL.\n\nThe function returns cookie name/value pairs. Your web framework still needs to send them as `Set-Cookie` headers.\n\n```javascript\nimport { getSignedCookies } from \"@aws-sdk/cloudfront-signer\";\n\nconst expiresAt = new Date(Date.now() + 60 * 60 * 1000).toISOString();\n\nconst cookies = getSignedCookies({\n  url: `${urlBase}/private/reports/quarterly.pdf`,\n  keyPairId,\n  dateLessThan: expiresAt,\n  privateKey,\n});\n\nconsole.log(cookies);\n```\n\nIn Express, map those values into real cookies:\n\n```javascript\nfor (const [name, value] of Object.entries(cookies)) {\n  res.cookie(name, value, {\n    httpOnly: true,\n    secure: true,\n    sameSite: \"none\",\n    path: \"/\",\n  });\n}\n```\n\nIf you need cookies that cover multiple files, a not-before time, or IP-based restrictions, use a custom CloudFront policy instead of only an expiration timestamp.\n\n## Important pitfalls\n\n- Sign the CloudFront URL, not the underlying S3 URL. Viewers must request the same host and path that you signed.\n- Keep the private key on the server. Browser code should only receive the finished signed URL or the final cookies.\n- This package does not need `CloudFrontClient`, `AWS_REGION`, or AWS credentials for signing. It only uses the key pair ID and private key you provide.\n- `getSignedCookies()` returns a plain object, not complete `Set-Cookie` header strings.\n- Read the private key as UTF-8 text and preserve PEM newlines. Flattened or malformed PEM content causes signing failures.\n- If you use an alternate domain name such as `https://assets.example.com`, sign that exact host instead of the default `*.cloudfront.net` domain.\n\n## Version notes\n\n- This guide covers `@aws-sdk/cloudfront-signer` version `3.1005.0`.\n- Use root imports such as `import { getSignedUrl } from \"@aws-sdk/cloudfront-signer\"` rather than deep-importing package internals.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-cloudfront-signer/\n- Amazon CloudFront signed URLs: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html\n- Amazon CloudFront signed cookies: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html\n- npm package page: https://www.npmjs.com/package/@aws-sdk/cloudfront-signer\n"
  },
  {
    "path": "content/aws/docs/cloudtrail/javascript/DOC.md",
    "content": "---\nname: cloudtrail\ndescription: \"AWS SDK for JavaScript v3 client for managing CloudTrail trails, logging state, event selectors, and recent event lookup.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cloudtrail,javascript,nodejs,audit,logging,security,aws-sdk-v3\"\n---\n\n# `@aws-sdk/client-cloudtrail`\n\nUse this package to manage AWS CloudTrail from JavaScript or Node.js with AWS SDK v3. The common flow is: create or inspect a trail, point it at an S3 bucket, start or stop logging, adjust event selectors, and look up recent events when you need to inspect account activity.\n\nThis package is the CloudTrail control-plane client. It manages trail configuration and event lookup APIs, but it does not create the S3 bucket, KMS key, or CloudWatch Logs resources that a trail can depend on.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cloudtrail\n```\n\nIf you want to select a named AWS profile in code, install the credential provider package you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\n- AWS credentials that can call CloudTrail APIs in the target account.\n- An AWS region.\n- An existing S3 bucket for trail log delivery.\n- If you enable SSE-KMS or CloudWatch Logs integration, the related KMS key, log group, and IAM permissions must already be in place.\n\nTypical local environment:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\nexport CLOUDTRAIL_BUCKET=\"my-cloudtrail-logs-bucket\"\n```\n\nIf you use shared AWS config locally, `AWS_PROFILE` also works with the standard AWS SDK v3 credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { CloudTrailClient } from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { CloudTrailClient } from \"@aws-sdk/client-cloudtrail\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  CloudTrailClient,\n  ListTrailsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({ region: \"us-east-1\" });\n\nconst response = await cloudtrail.send(new ListTrailsCommand({}));\n\nfor (const trail of response.Trails ?? []) {\n  console.log(trail.Name, trail.TrailARN, trail.HomeRegion);\n}\n```\n\n## Common Workflows\n\n### Create a trail and start logging\n\nCreate the trail first, then start logging explicitly.\n\n```javascript\nimport {\n  CloudTrailClient,\n  CreateTrailCommand,\n  StartLoggingCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst trailName = \"app-audit-trail\";\n\nconst created = await cloudtrail.send(\n  new CreateTrailCommand({\n    Name: trailName,\n    S3BucketName: process.env.CLOUDTRAIL_BUCKET,\n    IsMultiRegionTrail: true,\n    IncludeGlobalServiceEvents: true,\n    EnableLogFileValidation: true,\n  }),\n);\n\nconsole.log(created.TrailARN);\n\nawait cloudtrail.send(\n  new StartLoggingCommand({\n    Name: trailName,\n  }),\n);\n```\n\nUse `KmsKeyId`, `CloudWatchLogsLogGroupArn`, and `CloudWatchLogsRoleArn` only when those resources and permissions are already configured.\n\n### List trails and inspect one trail\n\nUse `ListTrails` for discovery, `GetTrail` for configuration details, and `GetTrailStatus` for logging and delivery state.\n\n```javascript\nimport {\n  CloudTrailClient,\n  GetTrailCommand,\n  GetTrailStatusCommand,\n  ListTrailsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Trails = [] } = await cloudtrail.send(new ListTrailsCommand({}));\n\nfor (const trail of Trails) {\n  console.log(trail.Name, trail.TrailARN, trail.HomeRegion);\n}\n\nconst trailName = \"app-audit-trail\";\n\nconst detail = await cloudtrail.send(\n  new GetTrailCommand({\n    Name: trailName,\n  }),\n);\n\nconst status = await cloudtrail.send(\n  new GetTrailStatusCommand({\n    Name: trailName,\n  }),\n);\n\nconsole.log(detail.Trail?.S3BucketName);\nconsole.log(detail.Trail?.IsMultiRegionTrail);\nconsole.log(status.IsLogging);\nconsole.log(status.LatestDeliveryTime);\nconsole.log(status.LatestDeliveryError);\n```\n\n### Change what the trail records\n\n`PutEventSelectors` lets you keep management events enabled and add data events for specific resources.\n\n```javascript\nimport {\n  CloudTrailClient,\n  PutEventSelectorsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait cloudtrail.send(\n  new PutEventSelectorsCommand({\n    TrailName: \"app-audit-trail\",\n    EventSelectors: [\n      {\n        ReadWriteType: \"All\",\n        IncludeManagementEvents: true,\n        DataResources: [\n          {\n            Type: \"AWS::S3::Object\",\n            Values: [\"arn:aws:s3:::example-bucket/\"],\n          },\n        ],\n      },\n    ],\n  }),\n);\n```\n\nFor S3 object data events, the `Values` entry is an S3 bucket ARN prefix with a trailing slash.\n\n### Look up recent events\n\nUse `LookupEvents` when you need recent CloudTrail event history and paginate with `NextToken` when the result set is larger than one page.\n\n```javascript\nimport {\n  CloudTrailClient,\n  LookupEventsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet NextToken;\n\ndo {\n  const response = await cloudtrail.send(\n    new LookupEventsCommand({\n      LookupAttributes: [\n        {\n          AttributeKey: \"EventName\",\n          AttributeValue: \"CreateTrail\",\n        },\n      ],\n      StartTime: new Date(Date.now() - 24 * 60 * 60 * 1000),\n      EndTime: new Date(),\n      MaxResults: 50,\n      NextToken,\n    }),\n  );\n\n  for (const event of response.Events ?? []) {\n    console.log(event.EventTime, event.EventName, event.Username);\n\n    if (event.CloudTrailEvent) {\n      const detail = JSON.parse(event.CloudTrailEvent);\n      console.log(detail.eventSource, detail.sourceIPAddress);\n    }\n  }\n\n  NextToken = response.NextToken;\n} while (NextToken);\n```\n\n`CloudTrailEvent` is returned as a JSON string. Parse it before reading nested request or response fields.\n\n### Update, stop, or delete a trail\n\nUse `UpdateTrail` for configuration changes. Use `StopLogging` when you want to keep the trail definition but pause delivery. Delete the trail when you no longer want the configuration to exist.\n\n```javascript\nimport {\n  CloudTrailClient,\n  DeleteTrailCommand,\n  StopLoggingCommand,\n  UpdateTrailCommand,\n} from \"@aws-sdk/client-cloudtrail\";\n\nconst cloudtrail = new CloudTrailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait cloudtrail.send(\n  new UpdateTrailCommand({\n    Name: \"app-audit-trail\",\n    EnableLogFileValidation: true,\n  }),\n);\n\nawait cloudtrail.send(\n  new StopLoggingCommand({\n    Name: \"app-audit-trail\",\n  }),\n);\n\nawait cloudtrail.send(\n  new DeleteTrailCommand({\n    Name: \"app-audit-trail\",\n  }),\n);\n```\n\n## Pitfalls\n\n- `CreateTrail` does not create the S3 bucket or fix its bucket policy for you.\n- Creating a trail and starting log delivery are separate API calls.\n- `GetTrailStatus` is the quickest way to confirm whether a trail is actively logging and whether recent delivery attempts are succeeding.\n- `LookupEvents` paginates; keep following `NextToken` until it is absent.\n- `LookupEvents` returns `CloudTrailEvent` as a stringified JSON document, not a nested object.\n- If you enable KMS encryption or CloudWatch Logs delivery, the related resource policies and IAM role permissions must already allow CloudTrail to use them.\n- This package is best used from backend or automation code. Do not ship long-lived AWS credentials in browser code.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-cloudtrail@3.1007.0`.\n- Examples use the AWS SDK for JavaScript v3 command-based client pattern.\n"
  },
  {
    "path": "content/aws/docs/cloudwatch/javascript/DOC.md",
    "content": "---\nname: cloudwatch\ndescription: \"AWS SDK for JavaScript v3 CloudWatch client for custom metrics, metric queries, alarms, and dashboards.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,cloudwatch,javascript,nodejs,browser,monitoring,metrics,alarms\"\n---\n\n# `@aws-sdk/client-cloudwatch`\n\nUse this package for Amazon CloudWatch metrics and alarms in AWS SDK for JavaScript v3. It follows the v3 client-plus-command pattern and is the package to use for publishing custom metrics, querying metric time series, creating alarms, and managing dashboards.\n\nPrefer `CloudWatchClient` plus explicit command imports. The package also exposes an aggregated `CloudWatch` client, but command-based imports are the safer default for smaller bundles and clearer dependency boundaries.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cloudwatch\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Initialize the client\n\n```javascript\nimport { CloudWatchClient } from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain usually works if AWS access is already configured through environment variables, shared AWS config files, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: use an explicit browser-safe credential provider such as Cognito identity; do not ship privileged CloudWatch management credentials to the browser.\n- Region is required somewhere. Set it in the client constructor, via `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  CloudWatchClient,\n  PutMetricDataCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nawait cloudwatch.send(\n  new PutMetricDataCommand({\n    Namespace: \"MyApp/Orders\",\n    MetricData: [\n      {\n        MetricName: \"CheckoutLatency\",\n        Dimensions: [\n          { Name: \"Environment\", Value: \"prod\" },\n          { Name: \"Service\", Value: \"api\" },\n        ],\n        Unit: \"Milliseconds\",\n        Value: 182,\n      },\n    ],\n  }),\n);\n```\n\nTreat the combination of namespace, metric name, and dimensions as the metric identity you will later query and alarm on.\n\n## Common Operations\n\n### Publish a high-resolution custom metric\n\nSet `StorageResolution: 1` when you need one-second granularity.\n\n```javascript\nimport {\n  CloudWatchClient,\n  PutMetricDataCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nawait cloudwatch.send(\n  new PutMetricDataCommand({\n    Namespace: \"MyApp/Workers\",\n    MetricData: [\n      {\n        MetricName: \"QueueLag\",\n        Dimensions: [{ Name: \"QueueName\", Value: \"jobs\" }],\n        Unit: \"Count\",\n        Value: 3,\n        StorageResolution: 1,\n      },\n    ],\n  }),\n);\n```\n\n### Query recent metric data\n\nUse `GetMetricData` when you need one or more metric series over a time window.\n\n```javascript\nimport {\n  CloudWatchClient,\n  GetMetricDataCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\nconst endTime = new Date();\nconst startTime = new Date(endTime.getTime() - 15 * 60 * 1000);\n\nconst response = await cloudwatch.send(\n  new GetMetricDataCommand({\n    StartTime: startTime,\n    EndTime: endTime,\n    MetricDataQueries: [\n      {\n        Id: \"checkoutLatencyP95\",\n        MetricStat: {\n          Metric: {\n            Namespace: \"MyApp/Orders\",\n            MetricName: \"CheckoutLatency\",\n            Dimensions: [\n              { Name: \"Environment\", Value: \"prod\" },\n              { Name: \"Service\", Value: \"api\" },\n            ],\n          },\n          Period: 60,\n          Stat: \"p95\",\n          Unit: \"Milliseconds\",\n        },\n        ReturnData: true,\n      },\n    ],\n  }),\n);\n\nfor (const result of response.MetricDataResults ?? []) {\n  console.log(result.Id, result.Timestamps, result.Values);\n}\n```\n\n### Create or update an alarm\n\n`PutMetricAlarm` creates the alarm if it does not exist and updates it when the alarm name already exists.\n\n```javascript\nimport {\n  CloudWatchClient,\n  PutMetricAlarmCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nawait cloudwatch.send(\n  new PutMetricAlarmCommand({\n    AlarmName: \"checkout-latency-p95-too-high\",\n    Namespace: \"MyApp/Orders\",\n    MetricName: \"CheckoutLatency\",\n    Dimensions: [\n      { Name: \"Environment\", Value: \"prod\" },\n      { Name: \"Service\", Value: \"api\" },\n    ],\n    Statistic: \"Average\",\n    Period: 60,\n    EvaluationPeriods: 5,\n    Threshold: 500,\n    ComparisonOperator: \"GreaterThanThreshold\",\n    TreatMissingData: \"notBreaching\",\n    AlarmDescription: \"Average checkout latency is above 500 ms\",\n  }),\n);\n```\n\n## CloudWatch-Specific Gotchas\n\n- This package is for CloudWatch metrics, alarms, and dashboards. It is not the log ingestion and query client; use `@aws-sdk/client-cloudwatch-logs` for log groups, log streams, and Logs Insights APIs.\n- Custom metric reads and alarms only match the exact metric identity you publish. Keep namespace, metric name, dimension names, and dimension values consistent.\n- Use `GetMetricData` for multi-series queries or metric math. `GetMetricStatistics` is still available, but `GetMetricData` is usually the better default for new application code.\n- High-resolution datapoints require `StorageResolution: 1`, and alarms must use periods that are compatible with the metric resolution you publish.\n- Recently published datapoints can take a short time to become visible in reads and alarm evaluations. Do not assume a write is immediately queryable.\n- Alarm actions such as SNS topics or Auto Scaling policies are separate resources. Creating an alarm does not create those downstream integrations for you.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-cloudwatch-logs`: log groups, log streams, subscription filters, and Logs Insights queries.\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and other credential providers.\n- `@aws-sdk/client-sns`: create or manage SNS topics that alarm actions publish to.\n\n## Common CloudWatch operations\n\n### List metrics in a namespace\n\n`ListMetrics` helps you discover which metric names and dimensions currently exist.\n\n```javascript\nimport {\n  CloudWatchClient,\n  ListMetricsCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await cloudwatch.send(\n    new ListMetricsCommand({\n      Namespace: \"MyApp/Orders\",\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const metric of response.Metrics ?? []) {\n    console.log(metric.MetricName, metric.Dimensions);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Describe alarms by name prefix\n\n```javascript\nimport {\n  CloudWatchClient,\n  DescribeAlarmsCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await cloudwatch.send(\n    new DescribeAlarmsCommand({\n      AlarmNamePrefix: \"checkout-\",\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const alarm of response.MetricAlarms ?? []) {\n    console.log(alarm.AlarmName, alarm.StateValue, alarm.StateUpdatedTimestamp);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Delete alarms\n\n```javascript\nimport {\n  CloudWatchClient,\n  DeleteAlarmsCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nawait cloudwatch.send(\n  new DeleteAlarmsCommand({\n    AlarmNames: [\"checkout-latency-p95-too-high\"],\n  }),\n);\n```\n\n### Create or replace a dashboard\n\n`DashboardBody` is a JSON string, so build the object in JavaScript first and then serialize it.\n\n```javascript\nimport {\n  CloudWatchClient,\n  PutDashboardCommand,\n} from \"@aws-sdk/client-cloudwatch\";\n\nconst cloudwatch = new CloudWatchClient({ region: \"us-east-1\" });\n\nconst dashboardBody = {\n  widgets: [\n    {\n      type: \"metric\",\n      x: 0,\n      y: 0,\n      width: 12,\n      height: 6,\n      properties: {\n        title: \"Checkout latency\",\n        region: \"us-east-1\",\n        stat: \"Average\",\n        period: 60,\n        metrics: [\n          [\n            \"MyApp/Orders\",\n            \"CheckoutLatency\",\n            \"Environment\",\n            \"prod\",\n          ],\n        ],\n      },\n    },\n  ],\n};\n\nawait cloudwatch.send(\n  new PutDashboardCommand({\n    DashboardName: \"myapp-orders\",\n    DashboardBody: JSON.stringify(dashboardBody),\n  }),\n);\n```\n\n### Notes\n\n- For custom metrics, discovery via `ListMetrics` is useful during setup, but production code should usually know the namespace and dimensions it writes.\n- Alarm names are regional and account-scoped identifiers; treat them as stable resource names.\n- Dashboards are replace-on-write documents. Keep the source dashboard JSON in code or configuration if you want reproducible updates.\n"
  },
  {
    "path": "content/aws/docs/codebuild/javascript/DOC.md",
    "content": "---\nname: codebuild\ndescription: \"AWS SDK for JavaScript v3 client for starting, stopping, and inspecting AWS CodeBuild builds and projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,codebuild,ci,builds,devops\"\n---\n\n# AWS CodeBuild SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-codebuild` to trigger builds, inspect project configuration, and query build results from Node.js automation and backend services.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-codebuild`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `CodeBuildClient` plus individual commands over the aggregated `CodeBuild` client.\n- Set `region` explicitly in code or through standard AWS shared config.\n- Treat `StartBuildCommand` as asynchronous acceptance, not final build completion.\n- Many list APIs return names or IDs first; use `BatchGetProjectsCommand` or `BatchGetBuildsCommand` to load full details.\n- Use this client from trusted server-side code. Direct browser use is uncommon because it requires AWS credentials with build permissions.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-codebuild\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Auth And Region\n\nThe client uses the standard AWS SDK for JavaScript v3 credential provider chain.\n\nCommon environment variables:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { CodeBuildClient } from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { CodeBuildClient } from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Core Usage Pattern\n\nThe typical v3 flow is `client.send(new Command(input))`.\n\n```javascript\nimport {\n  CodeBuildClient,\n  StartBuildCommand,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\n\nconst response = await codebuild.send(\n  new StartBuildCommand({\n    projectName: \"my-build-project\",\n  }),\n);\n\nconsole.log(response.build?.id, response.build?.buildStatus);\n```\n\n`StartBuildCommand` returns build metadata immediately. If you need the final result, poll with `BatchGetBuildsCommand` until the build reaches a terminal status.\n\n## Common Operations\n\n### Start a build with per-run overrides\n\nUse overrides when you need to change the source version, buildspec, or environment variables for a single build without editing the underlying project.\n\n```javascript\nimport {\n  CodeBuildClient,\n  StartBuildCommand,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\n\nconst result = await codebuild.send(\n  new StartBuildCommand({\n    projectName: \"my-build-project\",\n    sourceVersion: \"refs/heads/main\",\n    buildspecOverride: \"buildspec.release.yml\",\n    environmentVariablesOverride: [\n      {\n        name: \"DEPLOY_ENV\",\n        value: \"staging\",\n        type: \"PLAINTEXT\",\n      },\n    ],\n  }),\n);\n\nconsole.log(result.build?.id);\n```\n\n### Poll a build until it finishes\n\n```javascript\nimport {\n  BatchGetBuildsCommand,\n  CodeBuildClient,\n  StartBuildCommand,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst startResult = await codebuild.send(\n  new StartBuildCommand({\n    projectName: \"my-build-project\",\n  }),\n);\n\nconst buildId = startResult.build?.id;\n\nif (!buildId) {\n  throw new Error(\"StartBuild did not return a build id\");\n}\n\nconst terminalStatuses = new Set([\n  \"SUCCEEDED\",\n  \"FAILED\",\n  \"FAULT\",\n  \"STOPPED\",\n  \"TIMED_OUT\",\n]);\n\nlet build;\n\nwhile (true) {\n  const response = await codebuild.send(\n    new BatchGetBuildsCommand({\n      ids: [buildId],\n    }),\n  );\n\n  build = response.builds?.[0];\n\n  if (!build) {\n    throw new Error(`Build not found: ${buildId}`);\n  }\n\n  console.log(build.buildStatus, build.currentPhase);\n\n  if (terminalStatuses.has(build.buildStatus ?? \"\")) {\n    break;\n  }\n\n  await sleep(5000);\n}\n\nif (build.buildStatus !== \"SUCCEEDED\") {\n  throw new Error(`Build ended with status ${build.buildStatus}`);\n}\n```\n\n### Inspect project configuration\n\n`BatchGetProjectsCommand` is the easiest way to fetch project details when you already know the project name.\n\n```javascript\nimport {\n  BatchGetProjectsCommand,\n  CodeBuildClient,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\n\nconst response = await codebuild.send(\n  new BatchGetProjectsCommand({\n    names: [\"my-build-project\"],\n  }),\n);\n\nconst project = response.projects?.[0];\n\nconsole.log({\n  name: project?.name,\n  sourceType: project?.source?.type,\n  image: project?.environment?.image,\n  serviceRole: project?.serviceRole,\n});\n```\n\n### List project names\n\n`ListProjectsCommand` returns names, not full project objects.\n\n```javascript\nimport {\n  CodeBuildClient,\n  ListProjectsCommand,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await codebuild.send(\n    new ListProjectsCommand({\n      nextToken,\n    }),\n  );\n\n  for (const name of page.projects ?? []) {\n    console.log(name);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Stop a running build\n\n`StopBuildCommand` takes a build ID, not a project name.\n\n```javascript\nimport {\n  CodeBuildClient,\n  StopBuildCommand,\n} from \"@aws-sdk/client-codebuild\";\n\nconst codebuild = new CodeBuildClient({ region: \"us-east-1\" });\n\nawait codebuild.send(\n  new StopBuildCommand({\n    id: \"my-build-project:11111111-2222-3333-4444-555555555555\",\n  }),\n);\n```\n\n## CodeBuild-Specific Gotchas\n\n- `StartBuildCommand` only queues and creates the build record. It does not wait for phases to finish.\n- `ListProjectsCommand` returns project names only; call `BatchGetProjectsCommand` for source, environment, cache, VPC, and artifact settings.\n- `ListBuildsForProjectCommand` returns build IDs only; call `BatchGetBuildsCommand` to inspect status, phases, logs, and artifact metadata.\n- `sourceVersion` meaning depends on the project source provider. It may be a branch, tag, commit SHA, or provider-specific revision string.\n- `environmentVariablesOverride` applies only to that run. It does not persist back into the CodeBuild project definition.\n- Avoid hard-coding secrets into `PLAINTEXT` overrides when Parameter Store or Secrets Manager references are a better fit.\n- Build logs and artifacts are delivered through the destinations configured on the project, commonly CloudWatch Logs and S3.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-cloudwatch-logs`: inspect build logs when the CodeBuild project publishes to CloudWatch Logs.\n- `@aws-sdk/client-s3`: download or inspect S3 build artifacts.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, assume-role, and other credential helpers.\n- `@aws-sdk/client-codepipeline`: coordinate builds as one step in a broader AWS delivery pipeline.\n"
  },
  {
    "path": "content/aws/docs/codecommit/javascript/DOC.md",
    "content": "---\nname: codecommit\ndescription: \"AWS SDK for JavaScript v3 client for Amazon CodeCommit repositories, branches, commits, pull requests, and approval workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,codecommit,git,repositories,pull-requests,javascript\"\n---\n\n# `@aws-sdk/client-codecommit`\n\nUse this package for Amazon CodeCommit API operations from JavaScript or TypeScript. It is the AWS SDK v3 client for repository management, branches, commits, file reads and writes, pull requests, comments, triggers, and approval rules.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-codecommit`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `CodeCommitClient` plus individual commands over the aggregated `CodeCommit` client.\n- Use this client for CodeCommit API actions, not for `git clone`, `git fetch`, or `git push`.\n- Import only from the package root. Do not deep-import from `dist-*` paths.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-codecommit\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## What This Client Is For\n\nUse `@aws-sdk/client-codecommit` when you need to automate CodeCommit over the AWS API, including:\n\n- creating or deleting repositories\n- reading repository metadata and clone URLs\n- listing branches or repositories\n- creating commits and updating files\n- reading files, blobs, folders, and differences\n- creating or listing pull requests\n- managing comments, approval rules, and repository triggers\n\nFor normal Git transport, use the repository's HTTPS or SSH clone URL with Git tooling. The SDK client signs AWS API requests; it is not a drop-in replacement for Git remote operations.\n\n## Create a Client\n\n```javascript\nimport { CodeCommitClient } from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({\n  region: \"us-east-1\",\n});\n```\n\n## Credentials and Region\n\n- In Node.js, the standard AWS SDK default credential chain applies.\n- Set `region` in the client constructor, via `AWS_REGION`, or through shared AWS config.\n- API calls use IAM credentials and SigV4 signing.\n- Git-over-HTTPS or SSH access uses CodeCommit clone URLs and Git credentials or SSH keys, not this SDK client.\n- Before building greenfield workflows on CodeCommit, verify current service and regional availability for your account.\n\n## Common Operations\n\n### Create a repository and read clone URLs\n\n`CreateRepository` and `GetRepository` return `repositoryMetadata`, including the HTTPS and SSH clone URLs you use with Git.\n\n```javascript\nimport {\n  CodeCommitClient,\n  CreateRepositoryCommand,\n  GetRepositoryCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nawait codecommit.send(\n  new CreateRepositoryCommand({\n    repositoryName: \"demo-repo\",\n    repositoryDescription: \"Repository created from the AWS SDK for JavaScript v3\",\n  }),\n);\n\nconst { repositoryMetadata } = await codecommit.send(\n  new GetRepositoryCommand({\n    repositoryName: \"demo-repo\",\n  }),\n);\n\nconsole.log(repositoryMetadata?.cloneUrlHttp);\nconsole.log(repositoryMetadata?.cloneUrlSsh);\n```\n\n### List repositories with `nextToken`\n\n`ListRepositories` is paginated.\n\n```javascript\nimport {\n  CodeCommitClient,\n  ListRepositoriesCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await codecommit.send(\n    new ListRepositoriesCommand({\n      nextToken,\n      sortBy: \"repositoryName\",\n      order: \"ascending\",\n    }),\n  );\n\n  for (const repository of page.repositories ?? []) {\n    console.log(repository.repositoryName, repository.repositoryId);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Add or update one file on a branch\n\nUse `PutFile` for a single-file change. For multi-file atomic changes, use `CreateCommit` instead.\n\n```javascript\nimport {\n  CodeCommitClient,\n  PutFileCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nconst encoder = new TextEncoder();\n\nawait codecommit.send(\n  new PutFileCommand({\n    repositoryName: \"demo-repo\",\n    branchName: \"main\",\n    filePath: \"/README.md\",\n    fileContent: encoder.encode(\"# Demo Repo\\n\\nCreated from the AWS SDK v3.\\n\"),\n    commitMessage: \"Add README\",\n    name: \"Automation Bot\",\n    email: \"bot@example.com\",\n    parentCommitId: \"4c925148EXAMPLE\",\n  }),\n);\n```\n\nNotes:\n\n- `parentCommitId` helps prevent writing on top of a branch tip that has moved.\n- For the first commit in an empty repository, the parent commit is not required.\n- `filePath` is the full path in the repository.\n\n### Read a file and decode its bytes\n\nAWS CLI examples show `GetFile` content as base64 because the CLI serializes blob output. In the JavaScript SDK, `fileContent` is binary data, so decode it with `TextDecoder` when you expect text.\n\n```javascript\nimport {\n  CodeCommitClient,\n  GetFileCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nconst response = await codecommit.send(\n  new GetFileCommand({\n    repositoryName: \"demo-repo\",\n    commitSpecifier: \"main\",\n    filePath: \"README.md\",\n  }),\n);\n\nconst text = new TextDecoder().decode(response.fileContent);\n\nconsole.log(response.commitId);\nconsole.log(text);\n```\n\n### Create and list pull requests\n\n```javascript\nimport {\n  CodeCommitClient,\n  CreatePullRequestCommand,\n  ListPullRequestsCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nconst { pullRequest } = await codecommit.send(\n  new CreatePullRequestCommand({\n    title: \"Merge feature/login into main\",\n    description: \"Please review the login flow changes\",\n    targets: [\n      {\n        repositoryName: \"demo-repo\",\n        sourceReference: \"feature/login\",\n        destinationReference: \"main\",\n      },\n    ],\n  }),\n);\n\nconsole.log(pullRequest?.pullRequestId);\n\nconst page = await codecommit.send(\n  new ListPullRequestsCommand({\n    repositoryName: \"demo-repo\",\n    pullRequestStatus: \"OPEN\",\n  }),\n);\n\nconsole.log(page.pullRequestIds);\n```\n\nIf you only pass a source branch in some workflows, CodeCommit can target the repository default branch. Passing both references explicitly is clearer in automation.\n\n### Change the default branch\n\n```javascript\nimport {\n  CodeCommitClient,\n  UpdateDefaultBranchCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\nawait codecommit.send(\n  new UpdateDefaultBranchCommand({\n    repositoryName: \"demo-repo\",\n    defaultBranchName: \"main\",\n  }),\n);\n```\n\n## Error Handling\n\nCodeCommit commands throw service exceptions with stable names. Handle the cases your workflow expects and let unexpected failures bubble up.\n\n```javascript\nimport {\n  CodeCommitClient,\n  GetRepositoryCommand,\n} from \"@aws-sdk/client-codecommit\";\n\nconst codecommit = new CodeCommitClient({ region: \"us-east-1\" });\n\ntry {\n  await codecommit.send(\n    new GetRepositoryCommand({ repositoryName: \"missing-repo\" }),\n  );\n} catch (error) {\n  if (error?.name === \"RepositoryDoesNotExistException\") {\n    console.error(\"Repository not found\");\n  } else {\n    throw error;\n  }\n}\n```\n\nCommon cases to expect in automation:\n\n- `RepositoryDoesNotExistException`\n- `BranchDoesNotExistException`\n- `FileDoesNotExistException`\n- `ParentCommitIdOutdatedException`\n- validation errors around bad branch names, file paths, or references\n\n## CodeCommit-Specific Gotchas\n\n- `PutFile` updates one file. Use `CreateCommit` when one logical change touches multiple files.\n- `GetFile` and `GetBlob` return binary data in the SDK even when CLI examples show base64 text.\n- Repository metadata includes clone URLs, but actual clone, fetch, merge, and push flows still belong to Git tooling.\n- Branch and commit references matter for write safety. Supplying the current `parentCommitId` avoids racing another writer.\n- Approval rules, comments, pull requests, and triggers are separate API surfaces. Grant IAM permissions for the exact actions your workflow needs.\n- If the repository uses a customer-managed KMS key, your IAM principal also needs the right KMS permissions.\n- Do not deep-import package internals from build directories.\n\n## When To Reach For Other Packages Or Tools\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, STS assume-role flows, and other credential helpers.\n- Git CLI or Git libraries: working trees, clone/fetch/push, conflict resolution, and local branch management.\n\n## High-Value APIs To Know\n\n- Repository admin: `CreateRepositoryCommand`, `GetRepositoryCommand`, `DeleteRepositoryCommand`\n- Branches: `GetBranchCommand`, `ListBranchesCommand`, `UpdateDefaultBranchCommand`\n- Files and content: `GetFileCommand`, `PutFileCommand`, `DeleteFileCommand`, `GetFolderCommand`, `GetBlobCommand`\n- Commits and diffs: `CreateCommitCommand`, `GetCommitCommand`, `GetDifferencesCommand`\n- Pull requests and reviews: `CreatePullRequestCommand`, `ListPullRequestsCommand`, `GetPullRequestCommand`, `PostCommentForPullRequestCommand`\n- Merge operations: `MergePullRequestByFastForwardCommand`, `MergePullRequestBySquashCommand`, `MergePullRequestByThreeWayCommand`\n"
  },
  {
    "path": "content/aws/docs/codedeploy/javascript/DOC.md",
    "content": "---\nname: codedeploy\ndescription: \"AWS SDK for JavaScript v3 client for managing AWS CodeDeploy applications, deployment groups, and deployments\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,codedeploy,deployments,devops,ci-cd\"\n---\n\n# AWS CodeDeploy SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-codedeploy` to start deployments, inspect deployment state, and report lifecycle hook results for CodeDeploy applications targeting EC2/on-premises hosts, Lambda, or ECS.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-codedeploy`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `CodeDeployClient` plus individual commands over the aggregated `CodeDeploy` client.\n- Set `region` explicitly in code or via standard AWS config.\n- `CreateDeployment` starts work but does not mean the deployment succeeded; poll `GetDeployment` or use the waiter.\n- Most list operations use `nextToken`; use the generated paginators for anything beyond a single page.\n- CodeDeploy does not build or upload your revision artifact for you; you provide an existing S3 revision, a GitHub revision for EC2/on-premises deployments, or one of the supported Lambda/ECS AppSpec-based revision payloads.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-codedeploy\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { CodeDeployClient } from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { CodeDeployClient } from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\nIn practice, CodeDeploy calls usually run from backend automation, CI/CD jobs, or Lambda functions. Browser use is uncommon because these APIs are operationally sensitive and usually require privileged IAM permissions.\n\n## Core Usage Pattern\n\nThe normal v3 flow is `client.send(new Command(input))`.\n\n```javascript\nimport {\n  CreateDeploymentCommand,\n  CodeDeployClient,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\n\nconst response = await codedeploy.send(\n  new CreateDeploymentCommand({\n    applicationName: \"orders-service\",\n    deploymentGroupName: \"orders-service-prod\",\n    revision: {\n      revisionType: \"S3\",\n      s3Location: {\n        bucket: \"my-codedeploy-artifacts\",\n        key: \"orders-service/releases/2026-03-11.zip\",\n        bundleType: \"zip\",\n      },\n    },\n    description: \"Deploy release 2026-03-11\",\n  }),\n);\n\nconsole.log(response.deploymentId);\n```\n\nFor S3 revisions, `bundleType` must match the uploaded artifact format exactly (`zip`, `tgz`, `tar`, `YAML`, or `JSON`).\n\n## Common Operations\n\n### Start a deployment from an S3 revision bundle\n\n```javascript\nimport {\n  CreateDeploymentCommand,\n  CodeDeployClient,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\n\nconst { deploymentId } = await codedeploy.send(\n  new CreateDeploymentCommand({\n    applicationName: \"orders-service\",\n    deploymentGroupName: \"orders-service-prod\",\n    revision: {\n      revisionType: \"S3\",\n      s3Location: {\n        bucket: \"my-codedeploy-artifacts\",\n        key: \"orders-service/releases/2026-03-11.zip\",\n        bundleType: \"zip\",\n      },\n    },\n    description: \"Release 2026-03-11\",\n    ignoreApplicationStopFailures: false,\n  }),\n);\n\nif (!deploymentId) {\n  throw new Error(\"CodeDeploy did not return a deployment id\");\n}\n\nconsole.log(`Started deployment ${deploymentId}`);\n```\n\n`CreateDeployment` assumes the application and deployment group already exist. This package manages the deployment workflow, not your artifact packaging pipeline.\n\n### Wait for a deployment to finish and inspect the result\n\n```javascript\nimport {\n  CodeDeployClient,\n  GetDeploymentCommand,\n  waitUntilDeploymentSuccessful,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\nconst deploymentId = \"d-ABCDEFGHI\";\n\nawait waitUntilDeploymentSuccessful(\n  { client: codedeploy, maxWaitTime: 30 * 60 },\n  { deploymentId },\n);\n\nconst { deploymentInfo } = await codedeploy.send(\n  new GetDeploymentCommand({ deploymentId }),\n);\n\nconsole.log({\n  status: deploymentInfo?.status,\n  overview: deploymentInfo?.deploymentOverview,\n  messages: deploymentInfo?.deploymentStatusMessages,\n});\n```\n\nThe generated waiter treats `Succeeded` as success and `Failed` or `Stopped` as failure. If you need custom handling, poll `GetDeployment` yourself and inspect `deploymentInfo.status`.\n\n### List applications and deployment groups with paginators\n\n```javascript\nimport {\n  CodeDeployClient,\n  paginateListApplications,\n  paginateListDeploymentGroups,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListApplications({ client: codedeploy }, {})) {\n  for (const applicationName of page.applications ?? []) {\n    console.log(\"application\", applicationName);\n  }\n}\n\nfor await (const page of paginateListDeploymentGroups(\n  { client: codedeploy },\n  { applicationName: \"orders-service\" },\n)) {\n  for (const deploymentGroupName of page.deploymentGroups ?? []) {\n    console.log(\"deployment group\", deploymentGroupName);\n  }\n}\n```\n\nThe list APIs return paginated slices. Do not assume large accounts fit into one response.\n\n### List recent deployments for a deployment group\n\n```javascript\nimport {\n  CodeDeployClient,\n  paginateListDeployments,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListDeployments(\n  { client: codedeploy },\n  {\n    applicationName: \"orders-service\",\n    deploymentGroupName: \"orders-service-prod\",\n    includeOnlyStatuses: [\"Created\", \"Queued\", \"InProgress\", \"Succeeded\", \"Failed\"],\n  },\n)) {\n  for (const deploymentId of page.deployments ?? []) {\n    console.log(deploymentId);\n  }\n}\n```\n\nUse `includeOnlyStatuses` when you only care about active or recently failed deployments instead of the full history.\n\n### Report lifecycle hook success from a validation Lambda\n\nCodeDeploy Lambda and ECS deployments can invoke a validation Lambda hook. That function must call `PutLifecycleEventHookExecutionStatus` with the IDs from the event payload.\n\n```javascript\nimport {\n  CodeDeployClient,\n  PutLifecycleEventHookExecutionStatusCommand,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport const handler = async (event) => {\n  await codedeploy.send(\n    new PutLifecycleEventHookExecutionStatusCommand({\n      deploymentId: event.DeploymentId,\n      lifecycleEventHookExecutionId: event.LifecycleEventHookExecutionId,\n      status: \"Succeeded\",\n    }),\n  );\n\n  return { ok: true };\n};\n```\n\nFor Lambda deployments, the validation hooks are `BeforeAllowTraffic` and `AfterAllowTraffic`. For ECS deployments, CodeDeploy can also invoke hooks such as `BeforeInstall`, `AfterInstall`, and `AfterAllowTestTraffic`.\n\n### Stop an in-progress deployment\n\n```javascript\nimport {\n  CodeDeployClient,\n  StopDeploymentCommand,\n} from \"@aws-sdk/client-codedeploy\";\n\nconst codedeploy = new CodeDeployClient({ region: \"us-east-1\" });\n\nconst response = await codedeploy.send(\n  new StopDeploymentCommand({\n    deploymentId: \"d-ABCDEFGHI\",\n    autoRollbackEnabled: true,\n  }),\n);\n\nconsole.log(response.status, response.statusMessage);\n```\n\nStopping a deployment is asynchronous. The stop request can be accepted before rollback or final cleanup has finished, so keep checking deployment status afterward.\n\n## CodeDeploy-Specific Gotchas\n\n- `CreateDeployment` only starts the deployment; treat success as `GetDeployment().deploymentInfo.status === \"Succeeded\"` or a successful waiter result.\n- `GetDeployment` can report `Ready` for blue/green workflows that are waiting for traffic rerouting or manual continuation.\n- `ContinueDeployment` is only for blue/green deployments and supports `deploymentWaitType` values such as `READY_WAIT` and `TERMINATION_WAIT`.\n- `StopDeployment` is not an instant rollback confirmation; it is a request to stop, and you still need to monitor the deployment afterward.\n- S3-based revisions require a pre-uploaded artifact and a correct `bundleType`; CodeDeploy will not infer the format for you.\n- GitHub revisions are limited to EC2/on-premises deployments; Lambda and ECS deployments use the Lambda/ECS AppSpec-style revision forms instead.\n- The lifecycle hook callback API is for Lambda and ECS deployment hooks, not general deployment status updates.\n- Large environments often require pagination for applications, deployment groups, instances, targets, and deployments.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-s3`: upload and version deployment artifacts before handing them to CodeDeploy.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, and assume-role credential helpers.\n- `@aws-sdk/client-lambda`: invoke or manage the Lambda functions that participate in validation hooks.\n- `@aws-sdk/client-ecs`: inspect or manage the ECS services attached to a CodeDeploy deployment group.\n"
  },
  {
    "path": "content/aws/docs/codepipeline/javascript/DOC.md",
    "content": "---\nname: codepipeline\ndescription: \"AWS SDK for JavaScript v3 CodePipeline client for pipeline definitions, execution control, and delivery-state inspection.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,codepipeline,javascript,nodejs,cicd,deployments\"\n---\n\n# `@aws-sdk/client-codepipeline`\n\nUse this package for AWS CodePipeline control-plane operations such as reading pipeline definitions, starting and stopping executions, retrying failed stages, and inspecting stage or action status. It follows the AWS SDK for JavaScript v3 client-plus-command pattern.\n\nPrefer `CodePipelineClient` plus explicit command imports for application code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-codepipeline\n```\n\n## Initialize the client\n\n```javascript\nimport { CodePipelineClient } from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS credentials are already configured. In practice, CodePipeline calls are usually made from backend tools, CI helpers, or automation jobs rather than browser code because these APIs often need broad deployment permissions.\n\n## Credentials and Region\n\n- In Node.js, credentials can come from environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance profiles.\n- In browser runtimes, use an explicit browser-safe credential provider such as Cognito, but prefer server-side execution for CodePipeline administration.\n- Region is required somewhere. Set it in code, via `AWS_REGION`, or via shared AWS config.\n- Pipelines are regional. A client pointed at the wrong region will not see or control the pipeline you expect.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nInspect the current state of a pipeline and read the latest execution status for each stage:\n\n```javascript\nimport {\n  CodePipelineClient,\n  GetPipelineStateCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nconst response = await codepipeline.send(\n  new GetPipelineStateCommand({\n    name: \"MyPipeline\",\n  }),\n);\n\nfor (const stage of response.stageStates ?? []) {\n  console.log({\n    stageName: stage.stageName,\n    latestStatus: stage.latestExecution?.status,\n    inboundEnabled: stage.inboundTransitionState?.enabled,\n  });\n}\n```\n\n`GetPipelineStateCommand` is the fastest way to answer operational questions such as “which stage is failing?” and “what execution ID is currently active?”\n\n## Common Operations\n\n### Start a pipeline execution\n\nBy default, CodePipeline starts the latest source revision currently visible to the pipeline.\n\n```javascript\nimport {\n  CodePipelineClient,\n  StartPipelineExecutionCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nconst { pipelineExecutionId } = await codepipeline.send(\n  new StartPipelineExecutionCommand({\n    name: \"MyPipeline\",\n    variables: [{ name: \"Environment\", value: \"prod\" }],\n  }),\n);\n\nconsole.log(pipelineExecutionId);\n```\n\nIf your pipeline supports overrides, you can also pass `sourceRevisions` with values such as `COMMIT_ID`, `IMAGE_DIGEST`, `S3_OBJECT_VERSION_ID`, or `S3_OBJECT_KEY` for the relevant source action.\n\n### List recent pipeline executions\n\nUse execution history when you need run-level status rather than stage-level status.\n\n```javascript\nimport {\n  CodePipelineClient,\n  ListPipelineExecutionsCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await codepipeline.send(\n    new ListPipelineExecutionsCommand({\n      pipelineName: \"MyPipeline\",\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const execution of page.pipelineExecutionSummaries ?? []) {\n    console.log({\n      pipelineExecutionId: execution.pipelineExecutionId,\n      status: execution.status,\n      startTime: execution.startTime,\n      lastUpdateTime: execution.lastUpdateTime,\n    });\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Retry a failed stage execution\n\nRetry a failed stage using the execution ID returned by `GetPipelineStateCommand` or `ListPipelineExecutionsCommand`.\n\n```javascript\nimport {\n  CodePipelineClient,\n  RetryStageExecutionCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nconst { pipelineExecutionId } = await codepipeline.send(\n  new RetryStageExecutionCommand({\n    pipelineName: \"MyPipeline\",\n    stageName: \"Deploy\",\n    pipelineExecutionId: \"b59babff-5f34-EXAMPLE\",\n    retryMode: \"FAILED_ACTIONS\",\n  }),\n);\n\nconsole.log(pipelineExecutionId);\n```\n\nUse `FAILED_ACTIONS` when you only want to rerun the failed work. Use `ALL_ACTIONS` when the entire stage must be replayed.\n\n### Stop an in-progress execution\n\n```javascript\nimport {\n  CodePipelineClient,\n  StopPipelineExecutionCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nawait codepipeline.send(\n  new StopPipelineExecutionCommand({\n    pipelineName: \"MyPipeline\",\n    pipelineExecutionId: \"d-EXAMPLE\",\n    reason: \"Stopping after the current build finishes\",\n    abandon: false,\n  }),\n);\n```\n\nWith `abandon: false`, CodePipeline stops after in-progress actions finish. With `abandon: true`, it abandons in-progress actions instead, which is faster but can leave external systems midway through deployment work.\n\n### Inspect action-level execution details\n\nUse action execution details when a pipeline run failed but stage-level state is too coarse.\n\n```javascript\nimport {\n  CodePipelineClient,\n  ListActionExecutionsCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nconst response = await codepipeline.send(\n  new ListActionExecutionsCommand({\n    pipelineName: \"MyPipeline\",\n    filter: {\n      pipelineExecutionId: \"EXAMPLE0-adfc-488e-bf4c-1111111720d3\",\n    },\n  }),\n);\n\nfor (const detail of response.actionExecutionDetails ?? []) {\n  console.log({\n    stageName: detail.stageName,\n    actionName: detail.actionName,\n    status: detail.status,\n    externalExecutionId: detail.output?.executionResult?.externalExecutionId,\n    externalExecutionSummary:\n      detail.output?.executionResult?.externalExecutionSummary,\n  });\n}\n```\n\n## CodePipeline-Specific Gotchas\n\n- This package manages CodePipeline itself. It does not replace service-specific clients such as CodeBuild, CodeDeploy, Lambda, or S3 that power individual pipeline actions.\n- `StartPipelineExecutionCommand` runs the latest visible source by default. Use `variables` and `sourceRevisions` only when you intentionally need an override.\n- `RetryStageExecutionCommand` needs the exact failed `pipelineExecutionId` plus a `retryMode` of `FAILED_ACTIONS` or `ALL_ACTIONS`.\n- `StopPipelineExecutionCommand` behaves differently based on `abandon`. `false` drains in-progress work; `true` abandons it.\n- `GetPipelineStateCommand` is better for current operational state, while `ListPipelineExecutionsCommand` is better for run history.\n- `ListPipelinesCommand`, `ListPipelineExecutionsCommand`, and `ListActionExecutionsCommand` can paginate; loop on `nextToken` for complete results.\n- `UpdatePipelineCommand` expects a full `pipeline` declaration. If you start from `GetPipelineCommand` output, reuse the `pipeline` object only and drop response-only metadata before sending the update.\n- CodePipeline control-plane calls often need broad IAM permissions and are usually safer on the server side than in browser apps.\n- Do not deep-import package internals from build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-codebuild`: inspect or manage build projects used by CodePipeline actions.\n- `@aws-sdk/client-codedeploy`: inspect deployments launched from deploy stages.\n- `@aws-sdk/client-s3`: inspect artifact buckets and source artifacts used by S3-backed pipelines.\n- `@aws-sdk/credential-providers`: explicit credential flows such as `fromIni`, IAM Identity Center, Cognito, and assume-role helpers.\n\n## Common CodePipeline Operations\n\n### List pipelines in a region\n\n```javascript\nimport {\n  CodePipelineClient,\n  ListPipelinesCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await codepipeline.send(\n    new ListPipelinesCommand({\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const pipeline of page.pipelines ?? []) {\n    console.log({\n      name: pipeline.name,\n      version: pipeline.version,\n      created: pipeline.created,\n      updated: pipeline.updated,\n    });\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Fetch a pipeline definition before editing it\n\n```javascript\nimport {\n  CodePipelineClient,\n  GetPipelineCommand,\n} from \"@aws-sdk/client-codepipeline\";\n\nconst codepipeline = new CodePipelineClient({ region: \"us-east-1\" });\n\nconst { pipeline } = await codepipeline.send(\n  new GetPipelineCommand({\n    name: \"MyPipeline\",\n  }),\n);\n\nconsole.log(JSON.stringify(pipeline, null, 2));\n```\n\nThis is the safest starting point before reviewing stages, action configuration, artifact stores, variables, triggers, or execution mode.\n"
  },
  {
    "path": "content/aws/docs/cognito-identity/javascript/DOC.md",
    "content": "---\nname: cognito-identity\ndescription: \"AWS SDK for JavaScript v3 Cognito Identity client for identity pools and temporary AWS credentials.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,cognito,identity-pools,javascript,nodejs,browser,credentials\"\n---\n\n# `@aws-sdk/client-cognito-identity`\n\nUse this package for Amazon Cognito **identity pools**: exchanging trusted identity-provider tokens for temporary AWS credentials, resolving Cognito identity IDs, and reading or managing identity-pool metadata. It is not the package for Cognito user-pool sign-in, sign-up, MFA, or admin APIs.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cognito-identity\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Golden Rule\n\n- Use `@aws-sdk/client-cognito-identity` for identity pools and federated AWS credentials.\n- Use `@aws-sdk/client-cognito-identity-provider` for user-pool authentication and admin flows.\n- Prefer `CognitoIdentityClient` plus explicit commands over the aggregated `CognitoIdentity` client.\n- If you only need credentials for another AWS client, `fromCognitoIdentityPool()` is often simpler than manually calling `GetId` and `GetCredentialsForIdentity`.\n- `IdentityPoolId` looks like `us-east-1:12345678-1234-1234-1234-123456789012`.\n- Provider tokens go in the `Logins` map, keyed by provider identifier.\n\n## Client Setup\n\n```javascript\nimport { CognitoIdentityClient } from \"@aws-sdk/client-cognito-identity\";\n\nconst cognitoIdentity = new CognitoIdentityClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough for calling the Cognito Identity service itself.\n\n## Core Usage Pattern\n\nThe usual identity-pool flow is:\n\n1. Exchange a trusted provider token for an `IdentityId` with `GetIdCommand`.\n2. Exchange that `IdentityId` for temporary AWS credentials with `GetCredentialsForIdentityCommand`.\n\n```javascript\nimport {\n  CognitoIdentityClient,\n  GetCredentialsForIdentityCommand,\n  GetIdCommand,\n} from \"@aws-sdk/client-cognito-identity\";\n\nconst cognitoIdentity = new CognitoIdentityClient({ region: \"us-east-1\" });\n\nconst identityPoolId = \"us-east-1:12345678-1234-1234-1234-123456789012\";\nconst logins = {\n  \"cognito-idp.us-east-1.amazonaws.com/us-east-1_Example\": idToken,\n};\n\nconst { IdentityId } = await cognitoIdentity.send(\n  new GetIdCommand({\n    IdentityPoolId: identityPoolId,\n    Logins: logins,\n  }),\n);\n\nif (!IdentityId) {\n  throw new Error(\"No IdentityId returned\");\n}\n\nconst { Credentials } = await cognitoIdentity.send(\n  new GetCredentialsForIdentityCommand({\n    IdentityId,\n    Logins: logins,\n  }),\n);\n\nif (!Credentials?.AccessKeyId || !Credentials.SecretKey || !Credentials.SessionToken) {\n  throw new Error(\"No AWS credentials returned\");\n}\n\nconsole.log(Credentials.AccessKeyId);\nconsole.log(Credentials.Expiration);\n```\n\nIf you pass the returned credentials into another AWS SDK client manually, map `Credentials.SecretKey` to the SDK config field `secretAccessKey`.\n\n## Credentials and Region\n\n- Node.js server code can usually rely on the default AWS credential chain for the `CognitoIdentityClient` itself.\n- Browser code should not embed long-lived AWS access keys. Use Cognito identity providers or `fromCognitoIdentityPool()`.\n- The client `region`, the identity pool, and any provider-specific configuration should all line up.\n- The `Logins` map keys must exactly match the provider names configured on the identity pool.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Cognito Identity Gotchas\n\n- Identity pools and user pools are separate concepts. A user-pool token does not become AWS credentials until you exchange it through an identity pool.\n- `GetIdCommand` returns an `IdentityId`, not credentials.\n- `GetCredentialsForIdentityCommand` returns temporary credentials that expire.\n- Calling `GetIdCommand` without `Logins` only works when the identity pool allows unauthenticated identities.\n- `Logins` provider names are strict string identifiers; small mismatches cause hard-to-read authorization failures.\n- For most browser and mobile app code, automatic credential refresh via `@aws-sdk/credential-providers` is safer than hand-rolling refresh logic.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: `fromCognitoIdentityPool()` and related helpers for automatic refresh and simpler app wiring.\n- `@aws-sdk/client-cognito-identity-provider`: user-pool sign-in, token issuance, MFA, password flows, and admin APIs.\n- Higher-level auth libraries such as Amplify Auth when you want a full browser or mobile auth flow instead of raw SDK commands.\n\n## Common Cognito Identity Operations\n\n### Use `fromCognitoIdentityPool()` for another AWS client\n\nIf your goal is simply to give another AWS SDK client temporary credentials, the credential-provider helper is often the cleanest integration point.\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { fromCognitoIdentityPool } from \"@aws-sdk/credential-providers\";\n\nconst s3 = new S3Client({\n  region: \"us-east-1\",\n  credentials: fromCognitoIdentityPool({\n    clientConfig: { region: \"us-east-1\" },\n    identityPoolId: \"us-east-1:12345678-1234-1234-1234-123456789012\",\n    logins: {\n      \"cognito-idp.us-east-1.amazonaws.com/us-east-1_Example\": idToken,\n    },\n  }),\n});\n```\n\nThis avoids manually caching `IdentityId` values and refreshing expired AWS credentials yourself.\n\n### Get an unauthenticated identity\n\nUnauthenticated access only works when the identity pool explicitly allows it.\n\n```javascript\nimport {\n  CognitoIdentityClient,\n  GetIdCommand,\n} from \"@aws-sdk/client-cognito-identity\";\n\nconst cognitoIdentity = new CognitoIdentityClient({ region: \"us-east-1\" });\n\nconst { IdentityId } = await cognitoIdentity.send(\n  new GetIdCommand({\n    IdentityPoolId: \"us-east-1:12345678-1234-1234-1234-123456789012\",\n  }),\n);\n\nconsole.log(IdentityId);\n```\n\n### Get an OpenID token for an identity\n\n`GetOpenIdTokenCommand` can produce an OpenID token for an already resolved Cognito identity.\n\n```javascript\nimport {\n  CognitoIdentityClient,\n  GetOpenIdTokenCommand,\n} from \"@aws-sdk/client-cognito-identity\";\n\nconst cognitoIdentity = new CognitoIdentityClient({ region: \"us-east-1\" });\n\nconst { Token } = await cognitoIdentity.send(\n  new GetOpenIdTokenCommand({\n    IdentityId: \"us-east-1:example-identity-id\",\n    Logins: {\n      \"cognito-idp.us-east-1.amazonaws.com/us-east-1_Example\": idToken,\n    },\n  }),\n);\n\nconsole.log(Token);\n```\n\n### Read identity-pool settings\n\n```javascript\nimport {\n  CognitoIdentityClient,\n  DescribeIdentityPoolCommand,\n} from \"@aws-sdk/client-cognito-identity\";\n\nconst cognitoIdentity = new CognitoIdentityClient({ region: \"us-east-1\" });\n\nconst pool = await cognitoIdentity.send(\n  new DescribeIdentityPoolCommand({\n    IdentityPoolId: \"us-east-1:12345678-1234-1234-1234-123456789012\",\n  }),\n);\n\nconsole.log(pool.IdentityPoolName);\nconsole.log(pool.AllowUnauthenticatedIdentities);\n```\n"
  },
  {
    "path": "content/aws/docs/cognito-identity-provider/javascript/DOC.md",
    "content": "---\nname: cognito-identity-provider\ndescription: \"AWS SDK for JavaScript v3 Cognito Identity Provider client for Amazon Cognito User Pools authentication and user administration.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,cognito,authentication,user-pools,javascript,nodejs,browser\"\n---\n\n# `@aws-sdk/client-cognito-identity-provider`\n\nUse this package for Amazon Cognito User Pools APIs in AWS SDK for JavaScript v3. It covers both app-client flows such as sign-up and sign-in, and IAM-backed admin APIs such as listing users or reading a user profile by username.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cognito-identity-provider\n```\n\nPrefer `CognitoIdentityProviderClient` plus explicit command imports. The package also exposes an aggregated client, but command-based imports are the safer default for smaller bundles and clearer call sites.\n\n## Initialize the client\n\n```javascript\nimport { CognitoIdentityProviderClient } from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({\n  region: \"us-east-1\",\n});\n```\n\nThe region must match the user pool region.\n\n## Authentication Model\n\n- Public user-pool app-client APIs such as `SignUp`, `ConfirmSignUp`, `InitiateAuth`, `RespondToAuthChallenge`, `ForgotPassword`, and `GetUser` are driven by app-client IDs or user tokens.\n- Admin APIs such as `AdminGetUser`, `AdminCreateUser`, `AdminInitiateAuth`, and `ListUsers` require AWS credentials and IAM permissions.\n- Browser code should use only public app clients and should never include an app client secret.\n- If your app client has a secret, the relevant public commands need a `SecretHash`; compute that only on a trusted backend.\n\n## Credentials and Region\n\n- Server-side admin commands usually rely on the standard AWS credential provider chain.\n- Public user-pool flows can be called without AWS credentials, but they still need the correct `region` and `ClientId`.\n- Keep admin operations on the server side even if the same user pool also supports public client-side auth flows.\n\nTypical server-side setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nUse `client.send(new Command(...))` for every operation.\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  InitiateAuthCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nconst response = await cognito.send(\n  new InitiateAuthCommand({\n    AuthFlow: \"USER_PASSWORD_AUTH\",\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    AuthParameters: {\n      USERNAME: \"ada@example.com\",\n      PASSWORD: \"correct horse battery staple\",\n    },\n  }),\n);\n\nif (response.ChallengeName) {\n  console.log(\"Additional challenge required:\", response.ChallengeName);\n} else {\n  console.log(response.AuthenticationResult?.AccessToken);\n}\n```\n\n`USER_PASSWORD_AUTH` must be enabled on the app client. If Cognito returns a `ChallengeName`, continue with `RespondToAuthChallengeCommand` instead of assuming token issuance is complete.\n\n## Common Operations\n\n### Sign up a user\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  SignUpCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nawait cognito.send(\n  new SignUpCommand({\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    Username: \"ada@example.com\",\n    Password: \"correct horse battery staple\",\n    UserAttributes: [\n      { Name: \"email\", Value: \"ada@example.com\" },\n    ],\n  }),\n);\n```\n\n### Read the current user from an access token\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  GetUserCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nconst user = await cognito.send(\n  new GetUserCommand({\n    AccessToken: accessToken,\n  }),\n);\n\nconsole.log(user.Username);\n```\n\n`GetUser` takes an access token, not an ID token.\n\n### Read a user by username with admin permissions\n\n```javascript\nimport {\n  AdminGetUserCommand,\n  CognitoIdentityProviderClient,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nconst user = await cognito.send(\n  new AdminGetUserCommand({\n    UserPoolId: \"us-east-1_example\",\n    Username: \"ada@example.com\",\n  }),\n);\n\nconsole.log(user.UserStatus);\n```\n\n## Cognito-Specific Gotchas\n\n- `ClientId` is the user-pool app client ID, not the `UserPoolId`.\n- Public and admin commands have different auth models; do not assume a command that works in browser code also works for admin automation.\n- App clients with secrets require `SecretHash` on several public operations, which means those flows belong on a trusted backend.\n- `InitiateAuth` can return challenges such as MFA or password resets; handle them with `RespondToAuthChallengeCommand`.\n- `GetUser` needs an access token from Cognito, not an AWS credential and not an ID token.\n- Do not deep-import package internals from build directories.\n\n## When To Reach For Other Packages\n\n- `aws-amplify`: higher-level browser and mobile auth flows, hosted UI integration, token storage, and session management.\n- `@aws-sdk/credential-providers`: server-side AWS credential resolution for admin Cognito operations.\n\n## Common Cognito Identity Provider Operations\n\n### Confirm a user after sign-up\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  ConfirmSignUpCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nawait cognito.send(\n  new ConfirmSignUpCommand({\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    Username: \"ada@example.com\",\n    ConfirmationCode: codeFromEmail,\n  }),\n);\n```\n\n### Sign in and handle a follow-up challenge\n\nUse `RespondToAuthChallengeCommand` whenever `InitiateAuth` does not return tokens immediately.\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  InitiateAuthCommand,\n  RespondToAuthChallengeCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nconst auth = await cognito.send(\n  new InitiateAuthCommand({\n    AuthFlow: \"USER_PASSWORD_AUTH\",\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    AuthParameters: {\n      USERNAME: \"ada@example.com\",\n      PASSWORD: password,\n    },\n  }),\n);\n\nif (auth.ChallengeName === \"NEW_PASSWORD_REQUIRED\") {\n  const challenge = await cognito.send(\n    new RespondToAuthChallengeCommand({\n      ClientId: process.env.COGNITO_APP_CLIENT_ID,\n      ChallengeName: auth.ChallengeName,\n      Session: auth.Session,\n      ChallengeResponses: {\n        USERNAME: \"ada@example.com\",\n        NEW_PASSWORD: newPassword,\n      },\n    }),\n  );\n\n  console.log(challenge.AuthenticationResult?.AccessToken);\n}\n```\n\n### Start a forgot-password flow\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  ForgotPasswordCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nawait cognito.send(\n  new ForgotPasswordCommand({\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    Username: \"ada@example.com\",\n  }),\n);\n```\n\n### Complete a forgot-password flow\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  ConfirmForgotPasswordCommand,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nawait cognito.send(\n  new ConfirmForgotPasswordCommand({\n    ClientId: process.env.COGNITO_APP_CLIENT_ID,\n    Username: \"ada@example.com\",\n    ConfirmationCode: codeFromEmail,\n    Password: newPassword,\n  }),\n);\n```\n\n### List users with pagination\n\n`ListUsers` is an admin API, so run it only with AWS credentials that can access the target user pool.\n\n```javascript\nimport {\n  CognitoIdentityProviderClient,\n  paginateListUsers,\n} from \"@aws-sdk/client-cognito-identity-provider\";\n\nconst cognito = new CognitoIdentityProviderClient({ region: \"us-east-1\" });\n\nconst paginator = paginateListUsers(\n  { client: cognito },\n  {\n    UserPoolId: \"us-east-1_example\",\n    Limit: 60,\n  },\n);\n\nfor await (const page of paginator) {\n  for (const user of page.Users ?? []) {\n    console.log(user.Username);\n  }\n}\n```\n\n### Compute `SecretHash` on a trusted backend\n\nIf the app client has a secret, Cognito expects a base64-encoded HMAC-SHA256 over `username + clientId`.\n\n```javascript\nimport { createHmac } from \"node:crypto\";\n\nfunction makeSecretHash({ username, clientId, clientSecret }) {\n  return createHmac(\"sha256\", clientSecret)\n    .update(`${username}${clientId}`)\n    .digest(\"base64\");\n}\n```\n\nDo not ship the client secret to browser code.\n"
  },
  {
    "path": "content/aws/docs/comprehend/javascript/DOC.md",
    "content": "---\nname: comprehend\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Comprehend text analysis APIs and asynchronous detection jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,comprehend,javascript,nodejs,nlp,sentiment,pii\"\n---\n\n# `@aws-sdk/client-comprehend`\n\nUse this package to call Amazon Comprehend from JavaScript or TypeScript with AWS SDK for JavaScript v3. The same client covers real-time text analysis APIs such as language detection, sentiment, entities, key phrases, and PII detection, plus asynchronous S3-backed batch jobs for larger datasets.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-comprehend\n```\n\nIf you want to load a named AWS profile in code, also install the credential helpers package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nSet AWS credentials and a region before creating the client:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use shared AWS config locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain:\n\n```bash\nexport AWS_PROFILE=\"my-dev-profile\"\nexport AWS_REGION=\"us-east-1\"\n```\n\nFor asynchronous detection jobs, you also need an IAM role that Amazon Comprehend can assume and S3 locations for input and output:\n\n```bash\nexport COMPREHEND_DATA_ACCESS_ROLE_ARN=\"arn:aws:iam::123456789012:role/ComprehendDataAccessRole\"\nexport COMPREHEND_INPUT_S3_URI=\"s3://my-input-bucket/comprehend/input/\"\nexport COMPREHEND_OUTPUT_S3_URI=\"s3://my-output-bucket/comprehend/output/\"\n```\n\n## Initialize the client\n\n### Minimal Node.js client\n\n```javascript\nimport { ComprehendClient } from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { ComprehendClient } from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { ComprehendClient } from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"my-dev-profile\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core usage pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ComprehendClient,\n  DetectSentimentCommand,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DetectSentimentCommand({\n    Text: \"The delivery was fast and the packaging was excellent.\",\n    LanguageCode: \"en\",\n  }),\n);\n\nconsole.log(response.Sentiment, response.SentimentScore);\n```\n\n## Common workflows\n\n### Detect language, then analyze sentiment\n\nMost text analysis APIs require a `LanguageCode`. If the language is not already known, detect it first and pass that code into the next request.\n\n```javascript\nimport {\n  ComprehendClient,\n  DetectDominantLanguageCommand,\n  DetectSentimentCommand,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst text = \"The delivery was fast and the packaging was excellent.\";\n\nconst languageResult = await client.send(\n  new DetectDominantLanguageCommand({\n    Text: text,\n  }),\n);\n\nconst languageCode = languageResult.Languages?.[0]?.LanguageCode;\n\nif (!languageCode) {\n  throw new Error(\"Comprehend did not return a dominant language\");\n}\n\nconst sentimentResult = await client.send(\n  new DetectSentimentCommand({\n    Text: text,\n    LanguageCode: languageCode,\n  }),\n);\n\nconsole.log(sentimentResult.Sentiment);\nconsole.log(sentimentResult.SentimentScore);\n```\n\n### Run sentiment on multiple short documents with one language code\n\nUse a batch API when you already know that every document in the request uses the same language.\n\n```javascript\nimport {\n  BatchDetectSentimentCommand,\n  ComprehendClient,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new BatchDetectSentimentCommand({\n    LanguageCode: \"en\",\n    TextList: [\n      \"This product solved the problem quickly.\",\n      \"Setup was confusing and took too long.\",\n      \"Support answered within five minutes.\",\n    ],\n  }),\n);\n\nfor (const result of response.ResultList ?? []) {\n  console.log(result.Index, result.Sentiment, result.SentimentScore);\n}\n\nfor (const error of response.ErrorList ?? []) {\n  console.error(error.Index, error.ErrorCode, error.ErrorMessage);\n}\n```\n\n### Extract entities from a document\n\n```javascript\nimport {\n  ComprehendClient,\n  DetectEntitiesCommand,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DetectEntitiesCommand({\n    Text: \"Jane Doe from Example Corp met the AWS team in Seattle on Tuesday.\",\n    LanguageCode: \"en\",\n  }),\n);\n\nfor (const entity of response.Entities ?? []) {\n  console.log(entity.Text, entity.Type, entity.Score);\n}\n```\n\nUse the same pattern for other synchronous text APIs such as `DetectKeyPhrasesCommand` and `DetectSyntaxCommand` when those are a better match for your application.\n\n### Gate on PII, then get exact offsets when needed\n\n`ContainsPiiEntitiesCommand` is useful when you only need to know whether the text contains PII labels. `DetectPiiEntitiesCommand` returns the entity spans.\n\n```javascript\nimport {\n  ComprehendClient,\n  ContainsPiiEntitiesCommand,\n  DetectPiiEntitiesCommand,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst text = \"Contact me at jane@example.com or 206-555-0100.\";\n\nconst contains = await client.send(\n  new ContainsPiiEntitiesCommand({\n    Text: text,\n    LanguageCode: \"en\",\n  }),\n);\n\nconsole.log(contains.Labels);\n\nconst detailed = await client.send(\n  new DetectPiiEntitiesCommand({\n    Text: text,\n    LanguageCode: \"en\",\n  }),\n);\n\nfor (const entity of detailed.Entities ?? []) {\n  console.log(entity.Type, entity.BeginOffset, entity.EndOffset, entity.Score);\n}\n```\n\n### Start and poll an asynchronous sentiment job\n\nUse the asynchronous job APIs when your input already lives in S3 or when the dataset is too large for the real-time text APIs.\n\n```javascript\nimport {\n  ComprehendClient,\n  DescribeSentimentDetectionJobCommand,\n  StartSentimentDetectionJobCommand,\n} from \"@aws-sdk/client-comprehend\";\n\nconst client = new ComprehendClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst roleArn = process.env.COMPREHEND_DATA_ACCESS_ROLE_ARN;\nconst inputS3Uri = process.env.COMPREHEND_INPUT_S3_URI;\nconst outputS3Uri = process.env.COMPREHEND_OUTPUT_S3_URI;\n\nif (!roleArn || !inputS3Uri || !outputS3Uri) {\n  throw new Error(\"Set COMPREHEND_DATA_ACCESS_ROLE_ARN, COMPREHEND_INPUT_S3_URI, and COMPREHEND_OUTPUT_S3_URI\");\n}\n\nconst start = await client.send(\n  new StartSentimentDetectionJobCommand({\n    JobName: \"support-ticket-sentiment\",\n    LanguageCode: \"en\",\n    DataAccessRoleArn: roleArn,\n    InputDataConfig: {\n      S3Uri: inputS3Uri,\n      InputFormat: \"ONE_DOC_PER_LINE\",\n    },\n    OutputDataConfig: {\n      S3Uri: outputS3Uri,\n    },\n  }),\n);\n\nconst jobId = start.JobId;\n\nif (!jobId) {\n  throw new Error(\"Comprehend did not return a JobId\");\n}\n\nfor (;;) {\n  const detail = await client.send(\n    new DescribeSentimentDetectionJobCommand({\n      JobId: jobId,\n    }),\n  );\n\n  const properties = detail.SentimentDetectionJobProperties;\n  const status = properties?.JobStatus;\n\n  console.log(status);\n\n  if (status === \"COMPLETED\") {\n    console.log(properties?.OutputDataConfig?.S3Uri);\n    break;\n  }\n\n  if (status === \"FAILED\" || status === \"STOPPED\") {\n    throw new Error(`Sentiment job ended with status ${status}`);\n  }\n\n  await new Promise((resolve) => setTimeout(resolve, 10000));\n}\n```\n\nThe other asynchronous Comprehend job APIs follow the same pattern: `Start*JobCommand` to launch work in S3, then `Describe*JobCommand` to poll status.\n\n## Important gotchas\n\n- Most synchronous Comprehend text APIs require `LanguageCode`. If your application does not already know the language, detect it first.\n- Batch APIs still take a single `LanguageCode` for the whole request. Group texts by language before sending a batch request.\n- Synchronous text APIs take raw `Text` in the request. Asynchronous job APIs read from S3 and write results back to S3.\n- Asynchronous jobs require `DataAccessRoleArn` in addition to the credentials your application uses to call AWS.\n- `ContainsPiiEntitiesCommand` tells you which PII label types are present; `DetectPiiEntitiesCommand` is the API that returns offsets for exact matches.\n- `StartSentimentDetectionJobCommand` only starts the job. Use `DescribeSentimentDetectionJobCommand` to wait for a terminal status and locate the output S3 path.\n- Amazon Comprehend is regional. Region mismatches often look like permission or missing-resource problems.\n\n## When to reach for other packages\n\n- `@aws-sdk/credential-providers` for explicit credential loading such as `fromIni`, assume-role flows, or other profile-based setup.\n- Other AWS SDK v3 service clients when your Comprehend workflow depends on S3, IAM, or surrounding infrastructure automation.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-comprehend` version `3.1007.0`.\n- The current package surface uses the standard AWS SDK v3 command pattern shown here: `client.send(new Command(input))`.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 Comprehend client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/comprehend/`\n- Amazon Comprehend API Reference: `https://docs.aws.amazon.com/comprehend/latest/APIReference/Welcome.html`\n- Amazon Comprehend `DetectDominantLanguage` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_DetectDominantLanguage.html`\n- Amazon Comprehend `DetectSentiment` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_DetectSentiment.html`\n- Amazon Comprehend `BatchDetectSentiment` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_BatchDetectSentiment.html`\n- Amazon Comprehend `DetectEntities` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_DetectEntities.html`\n- Amazon Comprehend `ContainsPiiEntities` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_ContainsPiiEntities.html`\n- Amazon Comprehend `DetectPiiEntities` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_DetectPiiEntities.html`\n- Amazon Comprehend `StartSentimentDetectionJob` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_StartSentimentDetectionJob.html`\n- Amazon Comprehend `DescribeSentimentDetectionJob` API: `https://docs.aws.amazon.com/comprehend/latest/APIReference/API_DescribeSentimentDetectionJob.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n"
  },
  {
    "path": "content/aws/docs/compute-optimizer/javascript/DOC.md",
    "content": "---\nname: compute-optimizer\ndescription: \"AWS SDK for JavaScript v3 client for Compute Optimizer enrollment, recommendation retrieval, projected metrics, preferences, and exports.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,compute-optimizer,javascript,nodejs,ec2,autoscaling,ebs,lambda,recommendations\"\n---\n\n# `@aws-sdk/client-compute-optimizer`\n\nUse this package for AWS Compute Optimizer operations in JavaScript or Node.js. It lets you check enrollment, retrieve recommendations for EC2 instances, Auto Scaling groups, EBS volumes, and Lambda functions, inspect projected metrics for EC2 recommendation options, manage recommendation preferences, and export recommendations to S3.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-compute-optimizer\n```\n\nPrefer `ComputeOptimizerClient` with explicit command imports.\n\n## Prerequisites\n\n- AWS credentials with permission to call Compute Optimizer.\n- A configured AWS region.\n- Compute Optimizer must be enrolled before recommendation APIs are useful.\n- Resources must meet the service's supported-resource requirements before recommendations appear.\n\nTypical local environment:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=... # only if you use temporary credentials\nexport COMPUTE_OPTIMIZER_EXPORT_BUCKET=my-existing-export-bucket\n```\n\nIn Node.js, the AWS SDK v3 can also load credentials from shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance roles.\n\n## Initialize the client\n\n```javascript\nimport { ComputeOptimizerClient } from \"@aws-sdk/client-compute-optimizer\";\n\nconst computeOptimizer = new ComputeOptimizerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nAll examples below assume trusted backend code. Do not ship long-lived AWS credentials in browser code.\n\n## Core usage pattern\n\nStart by checking enrollment. If the account is not enrolled, most recommendation calls either return nothing useful or do not reflect the resources you expect.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetEnrollmentStatusCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst enrollment = await client.send(new GetEnrollmentStatusCommand({}));\n\nconsole.log({\n  status: enrollment.status,\n  statusReason: enrollment.statusReason,\n  memberAccountsEnrolled: enrollment.memberAccountsEnrolled,\n  lastUpdatedTimestamp: enrollment.lastUpdatedTimestamp,\n});\n```\n\n## Common operations\n\n### Opt in the current account\n\nUse `UpdateEnrollmentStatusCommand` to opt in or opt out. When you opt in, Compute Optimizer creates a service-linked role in the account.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  UpdateEnrollmentStatusCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nawait client.send(\n  new UpdateEnrollmentStatusCommand({\n    status: \"Active\",\n  }),\n);\n```\n\nIf you call this from an AWS Organizations management account, you can also include member accounts:\n\n```javascript\nawait client.send(\n  new UpdateEnrollmentStatusCommand({\n    status: \"Active\",\n    includeMemberAccounts: true,\n  }),\n);\n```\n\n### List EC2 instance recommendations\n\nUse `GetEC2InstanceRecommendationsCommand` to retrieve instance findings and ranked recommendation options. This API paginates with `nextToken` and can also return per-resource errors in `errors`.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetEC2InstanceRecommendationsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst recommendations = [];\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new GetEC2InstanceRecommendationsCommand({\n      filters: [\n        {\n          name: \"Finding\",\n          values: [\"Overprovisioned\"],\n        },\n      ],\n      maxResults: 50,\n      nextToken,\n      recommendationPreferences: {\n        cpuVendorArchitectures: [\"AWS_ARM64\"],\n      },\n    }),\n  );\n\n  recommendations.push(...(page.instanceRecommendations ?? []));\n  nextToken = page.nextToken;\n\n  for (const error of page.errors ?? []) {\n    console.error(error.identifier, error.code, error.message);\n  }\n} while (nextToken);\n\nfor (const recommendation of recommendations) {\n  const bestOption = recommendation.recommendationOptions?.[0];\n\n  console.log({\n    instanceArn: recommendation.instanceArn,\n    currentInstanceType: recommendation.currentInstanceType,\n    finding: recommendation.finding,\n    recommendedInstanceType: bestOption?.instanceType,\n    performanceRisk: bestOption?.performanceRisk,\n    monthlySavings: bestOption?.savingsOpportunity?.estimatedMonthlySavings,\n    migrationEffort: bestOption?.migrationEffort,\n  });\n}\n```\n\nUseful EC2 filters include `Finding`, `RecommendationSourceType`, `FindingReasonCodes`, `InferredWorkloadTypes`, `tag:key`, and `tag-key`.\n\n### Get projected metrics for a recommended EC2 option\n\nUse `GetEC2RecommendationProjectedMetricsCommand` when you need the projected utilization metrics behind a recommendation. This API requires an instance ARN, a metric statistic, a period, and a time window.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetEC2RecommendationProjectedMetricsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst projected = await client.send(\n  new GetEC2RecommendationProjectedMetricsCommand({\n    instanceArn: \"arn:aws:ec2:us-east-1:111122223333:instance/i-1234567890abcdef0\",\n    stat: \"Maximum\",\n    period: 3600,\n    startTime: new Date(\"2026-03-01T00:00:00Z\"),\n    endTime: new Date(\"2026-03-08T00:00:00Z\"),\n    recommendationPreferences: {\n      cpuVendorArchitectures: [\"CURRENT\"],\n    },\n  }),\n);\n\nfor (const option of projected.recommendedOptionProjectedMetrics ?? []) {\n  console.log(option.recommendedInstanceType, option.rank);\n\n  for (const metric of option.projectedMetrics ?? []) {\n    console.log(metric.name, metric.timestamps?.length, metric.values?.length);\n  }\n}\n```\n\nThis operation returns projected `Cpu` and `Memory` metrics only. The `Memory` metric is returned only when the unified CloudWatch agent is installed on the instance.\n\n### List Auto Scaling group recommendations\n\nUse `GetAutoScalingGroupRecommendationsCommand` to compare the current group configuration with ranked alternatives.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetAutoScalingGroupRecommendationsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst { autoScalingGroupRecommendations = [], errors = [] } = await client.send(\n  new GetAutoScalingGroupRecommendationsCommand({\n    filters: [\n      {\n        name: \"Finding\",\n        values: [\"NotOptimized\"],\n      },\n    ],\n    maxResults: 20,\n  }),\n);\n\nfor (const error of errors) {\n  console.error(error.identifier, error.code, error.message);\n}\n\nfor (const recommendation of autoScalingGroupRecommendations) {\n  const bestOption = recommendation.recommendationOptions?.[0];\n\n  console.log({\n    autoScalingGroupName: recommendation.autoScalingGroupName,\n    finding: recommendation.finding,\n    currentConfiguration: recommendation.currentConfiguration,\n    recommendedConfiguration: bestOption?.configuration,\n    performanceRisk: bestOption?.performanceRisk,\n    monthlySavings: bestOption?.savingsOpportunity?.estimatedMonthlySavings,\n  });\n}\n```\n\n### List EBS volume recommendations\n\nUse `GetEBSVolumeRecommendationsCommand` to inspect volume-type, size, IOPS, and throughput recommendations.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetEBSVolumeRecommendationsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst { volumeRecommendations = [], errors = [] } = await client.send(\n  new GetEBSVolumeRecommendationsCommand({\n    filters: [\n      {\n        name: \"Finding\",\n        values: [\"NotOptimized\"],\n      },\n    ],\n    maxResults: 20,\n  }),\n);\n\nfor (const error of errors) {\n  console.error(error.identifier, error.code, error.message);\n}\n\nfor (const recommendation of volumeRecommendations) {\n  const bestOption = recommendation.volumeRecommendationOptions?.[0];\n\n  console.log({\n    volumeArn: recommendation.volumeArn,\n    currentConfiguration: recommendation.currentConfiguration,\n    recommendedConfiguration: bestOption?.configuration,\n    performanceRisk: bestOption?.performanceRisk,\n    monthlySavings: bestOption?.savingsOpportunity?.estimatedMonthlySavings,\n  });\n}\n```\n\nFor EBS recommendations, `Finding` supports `Optimized` and `NotOptimized`. You can also filter by `tag:key` and `tag-key`.\n\n### List Lambda function recommendations\n\nUse `GetLambdaFunctionRecommendationsCommand` when you want recommended memory sizes for Lambda functions.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetLambdaFunctionRecommendationsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst { lambdaFunctionRecommendations = [] } = await client.send(\n  new GetLambdaFunctionRecommendationsCommand({\n    filters: [\n      {\n        name: \"Finding\",\n        values: [\"NotOptimized\"],\n      },\n    ],\n    maxResults: 20,\n  }),\n);\n\nfor (const recommendation of lambdaFunctionRecommendations) {\n  const bestOption = recommendation.memorySizeRecommendationOptions?.[0];\n\n  console.log({\n    functionArn: recommendation.functionArn,\n    currentMemorySize: recommendation.currentMemorySize,\n    finding: recommendation.finding,\n    recommendedMemorySize: bestOption?.memorySize,\n    monthlySavings: bestOption?.savingsOpportunity?.estimatedMonthlySavings,\n  });\n}\n```\n\nLambda filters support `Finding`, `FindingReasonCode`, `tag:key`, and `tag-key`.\n\n### Get recommendation summaries for an account\n\nUse `GetRecommendationSummariesCommand` for a compact view of findings and savings opportunities by resource type.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  GetRecommendationSummariesCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst { recommendationSummaries = [] } = await client.send(\n  new GetRecommendationSummariesCommand({\n    maxResults: 20,\n  }),\n);\n\nfor (const summary of recommendationSummaries) {\n  console.log({\n    resourceType: summary.recommendationResourceType,\n    savings: summary.savingsOpportunity?.estimatedMonthlySavings,\n    aggregatedSavings: summary.aggregatedSavingsOpportunity?.estimatedMonthlySavings,\n    performanceRiskRatings: summary.currentPerformanceRiskRatings,\n  });\n}\n```\n\nThis is a good starting point for dashboards or scheduled reporting before you fetch detailed per-resource recommendations.\n\n### Set and inspect recommendation preferences\n\nUse `PutRecommendationPreferencesCommand` to set saved preferences, then `GetEffectiveRecommendationPreferencesCommand` to see which active preferences actually apply to a specific resource.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  PutRecommendationPreferencesCommand,\n  GetEffectiveRecommendationPreferencesCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nawait client.send(\n  new PutRecommendationPreferencesCommand({\n    resourceType: \"Ec2Instance\",\n    scope: {\n      name: \"AccountId\",\n      value: \"111122223333\",\n    },\n    enhancedInfrastructureMetrics: \"Active\",\n    lookBackPeriod: \"DAYS_32\",\n  }),\n);\n\nconst effective = await client.send(\n  new GetEffectiveRecommendationPreferencesCommand({\n    resourceArn: \"arn:aws:ec2:us-east-1:111122223333:instance/i-1234567890abcdef0\",\n  }),\n);\n\nconsole.log({\n  enhancedInfrastructureMetrics: effective.enhancedInfrastructureMetrics,\n  lookBackPeriod: effective.lookBackPeriod,\n  preferredResources: effective.preferredResources,\n});\n```\n\nSaved preference scopes can target an `Organization`, an `AccountId`, or a specific `ResourceArn`.\n\n### Export EC2 recommendations to S3\n\nUse `ExportEC2InstanceRecommendationsCommand` to create a CSV export in an existing S3 bucket, then poll `DescribeRecommendationExportJobsCommand` for job status.\n\n```javascript\nimport {\n  ComputeOptimizerClient,\n  ExportEC2InstanceRecommendationsCommand,\n  DescribeRecommendationExportJobsCommand,\n} from \"@aws-sdk/client-compute-optimizer\";\n\nconst client = new ComputeOptimizerClient({ region: \"us-east-1\" });\n\nconst exportResponse = await client.send(\n  new ExportEC2InstanceRecommendationsCommand({\n    s3DestinationConfig: {\n      bucket: process.env.COMPUTE_OPTIMIZER_EXPORT_BUCKET,\n      keyPrefix: \"compute-optimizer/ec2\",\n    },\n    fileFormat: \"Csv\",\n    filters: [\n      {\n        name: \"Finding\",\n        values: [\"Overprovisioned\"],\n      },\n    ],\n  }),\n);\n\nconsole.log(exportResponse.jobId, exportResponse.s3Destination);\n\nconst jobs = await client.send(\n  new DescribeRecommendationExportJobsCommand({\n    jobIds: [exportResponse.jobId],\n  }),\n);\n\nconsole.log(jobs.recommendationExportJobs?.[0]);\n```\n\nThe export writes a CSV data file and a JSON metadata file to S3. For EC2 instance recommendation exports, only one export job can be in progress per AWS Region.\n\n## Pitfalls and notes\n\n- Empty recommendation lists usually mean the account is not enrolled yet, the resource type is not supported, or Compute Optimizer has not collected enough data.\n- Recommendation APIs commonly paginate with `nextToken`; keep fetching until it is absent.\n- Some list responses include an `errors` array even when the overall request succeeds.\n- Organization-scoped inputs such as `accountIds` and `includeMemberAccounts` are for organization-aware setups, not a normal single-account workflow.\n- `GetEC2InstanceRecommendationsCommand` and `GetAutoScalingGroupRecommendationsCommand` accept request-scoped `recommendationPreferences`, which are separate from the saved preferences managed by `PutRecommendationPreferencesCommand`.\n- Keep the client region explicit and consistent with the resources and export destination you are querying.\n"
  },
  {
    "path": "content/aws/docs/config-service/javascript/DOC.md",
    "content": "---\nname: config-service\ndescription: \"AWS SDK for JavaScript v3 client for AWS Config recorders, delivery channels, resource queries, config rules, and compliance lookups.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,config,compliance,governance,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-config-service`\n\nUse this package for AWS Config from JavaScript or TypeScript. Common tasks include enabling a configuration recorder, wiring a delivery channel, listing discovered resources, reading configuration history, querying the resource inventory with SQL, creating Config rules, and checking compliance results.\n\nAWS Config is a regional control-plane service. The npm package is `@aws-sdk/client-config-service`, the client class is `ConfigServiceClient`, and the AWS CLI service name is `configservice`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-config-service\n```\n\nIf you want shared-profile or assume-role helpers in code, install the credential provider package you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nConfigure AWS credentials and a region before creating the client.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\"\n```\n\nOr with direct credentials:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nTo enable recording, you also need:\n\n- an IAM role that AWS Config can assume for the recorder\n- an S3 bucket for configuration snapshots and history\n- optionally, an SNS topic for notifications\n\nUseful environment variables for the setup flow:\n\n```bash\nexport AWS_CONFIG_ROLE_ARN=\"arn:aws:iam::123456789012:role/config-role\"\nexport AWS_CONFIG_BUCKET=\"config-bucket-123456789012\"\nexport AWS_CONFIG_SNS_TOPIC_ARN=\"arn:aws:sns:us-east-1:123456789012:config-topic\" # optional\n```\n\nIn Node.js, the default AWS SDK for JavaScript v3 credential provider chain is usually enough if credentials already come from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { ConfigServiceClient } from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { ConfigServiceClient } from \"@aws-sdk/client-config-service\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst config = new ConfigServiceClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  DescribeConfigRulesCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nconst response = await config.send(\n  new DescribeConfigRulesCommand({\n    ConfigRuleNames: [\"RequiredTagsForEC2Instances\"],\n  }),\n);\n\nfor (const rule of response.ConfigRules ?? []) {\n  console.log(rule.ConfigRuleName, rule.ConfigRuleState, rule.Source?.Owner);\n}\n```\n\n## Common Workflows\n\n### Enable a recorder and delivery channel\n\nYou must create a delivery channel before `StartConfigurationRecorderCommand` succeeds.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  PutConfigurationRecorderCommand,\n  PutDeliveryChannelCommand,\n  StartConfigurationRecorderCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nif (!process.env.AWS_CONFIG_ROLE_ARN || !process.env.AWS_CONFIG_BUCKET) {\n  throw new Error(\"Set AWS_CONFIG_ROLE_ARN and AWS_CONFIG_BUCKET first\");\n}\n\nawait config.send(\n  new PutConfigurationRecorderCommand({\n    ConfigurationRecorder: {\n      name: \"default\",\n      roleARN: process.env.AWS_CONFIG_ROLE_ARN,\n      recordingGroup: {\n        allSupported: true,\n        includeGlobalResourceTypes: true,\n      },\n    },\n  }),\n);\n\nawait config.send(\n  new PutDeliveryChannelCommand({\n    DeliveryChannel: {\n      name: \"default\",\n      s3BucketName: process.env.AWS_CONFIG_BUCKET,\n      ...(process.env.AWS_CONFIG_SNS_TOPIC_ARN\n        ? { snsTopicARN: process.env.AWS_CONFIG_SNS_TOPIC_ARN }\n        : {}),\n      configSnapshotDeliveryProperties: {\n        deliveryFrequency: \"Twelve_Hours\",\n      },\n    },\n  }),\n);\n\nawait config.send(\n  new StartConfigurationRecorderCommand({\n    ConfigurationRecorderName: \"default\",\n  }),\n);\n```\n\nAWS Config allows only one customer-managed configuration recorder and one delivery channel per account per region, so these calls usually create the regional defaults on first run and update them on later runs.\n\n### List discovered resources of a specific type\n\nUse this to enumerate resources AWS Config knows about. The result can include resources that AWS Config discovered even if they are not currently being recorded.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  ListDiscoveredResourcesCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await config.send(\n    new ListDiscoveredResourcesCommand({\n      resourceType: \"AWS::EC2::Instance\",\n      limit: 100,\n      nextToken,\n    }),\n  );\n\n  for (const resource of response.resourceIdentifiers ?? []) {\n    console.log(resource.resourceType, resource.resourceId, resource.resourceName);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\n`ListDiscoveredResourcesCommand` uses lower-camel input keys such as `resourceType`, `resourceId`, `limit`, and `nextToken`.\n\n### Read a resource's configuration history\n\n`GetResourceConfigHistoryCommand` returns configuration items across time. The `configuration` field in each item is a JSON-encoded string, so parse it before reading nested properties.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  GetResourceConfigHistoryCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nconst response = await config.send(\n  new GetResourceConfigHistoryCommand({\n    resourceType: \"AWS::S3::Bucket\",\n    resourceId: \"example-bucket\",\n    chronologicalOrder: \"Reverse\",\n    limit: 10,\n  }),\n);\n\nfor (const item of response.configurationItems ?? []) {\n  const configuration = item.configuration\n    ? JSON.parse(item.configuration)\n    : undefined;\n\n  console.log({\n    resourceType: item.resourceType,\n    resourceId: item.resourceId,\n    captureTime: item.configurationItemCaptureTime,\n    status: item.configurationItemStatus,\n    versioning: configuration?.versioning,\n  });\n}\n```\n\nEach `GetResourceConfigHistory` call can span at most seven days and the response is paginated, so longer lookbacks need repeated calls with time windows or `nextToken`.\n\n### Query the Config inventory with SQL\n\n`SelectResourceConfigCommand` accepts a SQL `SELECT` expression. The `Results` array contains JSON strings, not already-parsed objects.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  SelectResourceConfigCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nconst response = await config.send(\n  new SelectResourceConfigCommand({\n    Expression:\n      \"SELECT resourceId, resourceType, awsRegion WHERE resourceType = 'AWS::S3::Bucket'\",\n    Limit: 100,\n  }),\n);\n\nconst rows = (response.Results ?? []).map((row) => JSON.parse(row));\n\nfor (const row of rows) {\n  console.log(row.resourceId, row.resourceType, row.awsRegion);\n}\n```\n\nThis is the most practical API when you want a filtered inventory view without manually listing every resource type and then joining details yourself.\n\n### Create or update an AWS-managed Config rule\n\nFor managed rules, set `Source.Owner` to `AWS` and pass the managed rule identifier as `Source.SourceIdentifier`.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  PutConfigRuleCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nawait config.send(\n  new PutConfigRuleCommand({\n    ConfigRule: {\n      ConfigRuleName: \"RequiredTagsForEC2Instances\",\n      Description:\n        \"Checks whether the CostCenter and Owner tags are applied to EC2 instances.\",\n      Scope: {\n        ComplianceResourceTypes: [\"AWS::EC2::Instance\"],\n      },\n      Source: {\n        Owner: \"AWS\",\n        SourceIdentifier: \"REQUIRED_TAGS\",\n      },\n      InputParameters: JSON.stringify({\n        tag1Key: \"CostCenter\",\n        tag2Key: \"Owner\",\n      }),\n    },\n    Tags: [{ Key: \"environment\", Value: \"prod\" }],\n  }),\n);\n```\n\nFor new rules, set `ConfigRuleName` and the `Source` block, but do not send generated identifiers such as `ConfigRuleArn` or `ConfigRuleId`.\n\n### Read non-compliant resources for a rule\n\nUse `GetComplianceDetailsByConfigRuleCommand` when you already know the rule and want the resources that failed it.\n\n```javascript\nimport {\n  ConfigServiceClient,\n  GetComplianceDetailsByConfigRuleCommand,\n} from \"@aws-sdk/client-config-service\";\n\nconst config = new ConfigServiceClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await config.send(\n    new GetComplianceDetailsByConfigRuleCommand({\n      ConfigRuleName: \"RequiredTagsForEC2Instances\",\n      ComplianceTypes: [\"NON_COMPLIANT\"],\n      Limit: 100,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const result of response.EvaluationResults ?? []) {\n    const qualifier = result.EvaluationResultIdentifier?.EvaluationResultQualifier;\n\n    console.log({\n      rule: qualifier?.ConfigRuleName,\n      resourceType: qualifier?.ResourceType,\n      resourceId: qualifier?.ResourceId,\n      complianceType: result.ComplianceType,\n      recordedAt: result.ResultRecordedTime,\n    });\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\nIf you already know the resource and want all rule evaluations for it, use `GetComplianceDetailsByResourceCommand` instead.\n\n## Important Notes\n\n- AWS Config is regional. Use the client in the same region where the recorder, delivery channel, rules, and recorded resources live.\n- `PutConfigurationRecorderCommand` and `PutDeliveryChannelCommand` are upsert-style APIs, but each account and region can have only one customer-managed recorder and one delivery channel.\n- `StartConfigurationRecorderCommand` requires a delivery channel to exist first.\n- `PutConfigRuleCommand` can create AWS-managed rules, custom Lambda rules, and custom policy rules. For AWS-managed rules, the critical fields are `Owner: \"AWS\"` and the correct managed rule identifier.\n- `PutConfigRuleCommand` and `PutConfigurationRecorderCommand` treat tags as create-time metadata. To change tags later, use the tagging APIs rather than re-sending different tag values in the same put call.\n- `SelectResourceConfigCommand` returns `Results` as JSON strings.\n- `GetResourceConfigHistoryCommand` returns `configuration` and some supplementary fields as JSON-encoded strings.\n\n## Common Pitfalls\n\n- Mixing the service names. In JavaScript you import `@aws-sdk/client-config-service`, in code you create `ConfigServiceClient`, and in AWS CLI commands the namespace is `configservice`.\n- Sending the wrong field casing. Some AWS Config operations use `ConfigRuleName` and `ConfigurationRecorderName`, while others use lower-camel keys such as `resourceType`, `resourceId`, `limit`, and `nextToken`.\n- Assuming `ListDiscoveredResourcesCommand` only returns currently recorded resources. It can include resources AWS Config discovered even if they are not actively recorded now.\n- Forgetting to parse `SelectResourceConfigCommand` results and `GetResourceConfigHistoryCommand` configuration payloads from JSON strings.\n- Expecting `GetResourceConfigHistoryCommand` to return an unlimited time range in one call. The API is paginated and each call is limited to a seven-day span.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-config-service` version `3.1007.0`.\n- The AWS Config service model uses mixed member casing. The command examples above keep the exact request member names exposed by the current SDK surface.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Config client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/config-service/`\n- AWS Config API reference: `https://docs.aws.amazon.com/config/latest/APIReference/Welcome.html`\n- AWS Config Developer Guide: `https://docs.aws.amazon.com/config/latest/developerguide/WhatIsConfig.html`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-config-service`\n"
  },
  {
    "path": "content/aws/docs/connect/javascript/DOC.md",
    "content": "---\nname: connect\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Connect instance, user, metrics, and outbound contact APIs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,connect,javascript,nodejs,contact-center,ccp,metrics\"\n---\n\n# `@aws-sdk/client-connect`\n\nUse `@aws-sdk/client-connect` to call Amazon Connect control-plane and real-time metrics APIs from JavaScript or TypeScript. Typical tasks include inspecting an instance, listing or searching users, creating users, reading current queue metrics, and starting outbound voice contacts.\n\nPrefer `ConnectClient` plus explicit command imports. Amazon Connect resources are regional, and many operations require an `InstanceId`, so set the client region to the same region as the Connect instance you are targeting.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-connect`, not the legacy `aws-sdk` v2 package.\n- Prefer `ConnectClient` with `client.send(new Command(input))`.\n- Set `region` explicitly or through standard AWS config.\n- Expect to pass `InstanceId` on most operations.\n- Keep Connect API calls on the server side unless you already have a browser-safe temporary credential flow.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-connect\n```\n\nIf you want to pin a named shared AWS profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-connect@3.1007.0`.\n\n## Prerequisites And Authentication\n\nBefore sending requests, make sure all of the following are true:\n\n- your AWS credentials are available to the SDK\n- your IAM policy allows the Amazon Connect actions your code uses\n- your client region matches the Amazon Connect instance region\n- you know the target Connect `InstanceId`\n\nTypical local setup:\n\n```bash\naws configure --profile connect-dev\n\nexport AWS_PROFILE=connect-dev\nexport AWS_REGION=us-east-1\nexport CONNECT_INSTANCE_ID=your-connect-instance-id\nexport CONNECT_QUEUE_ID=your-queue-id\nexport CONNECT_CONTACT_FLOW_ID=your-contact-flow-id\nexport CONNECT_ROUTING_PROFILE_ID=your-routing-profile-id\nexport CONNECT_SECURITY_PROFILE_ID=your-security-profile-id\n```\n\nMinimal client setup:\n\n```javascript\nimport { ConnectClient } from \"@aws-sdk/client-connect\";\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to force a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { ConnectClient } from \"@aws-sdk/client-connect\";\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"connect-dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already use environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance profiles.\n\n## Core Usage Pattern\n\nThe normal v3 flow is `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ConnectClient,\n  DescribeInstanceCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\n\nif (!instanceId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID before calling Amazon Connect\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DescribeInstanceCommand({\n    InstanceId: instanceId,\n  }),\n);\n\nconsole.log(response.Instance?.InstanceStatus);\nconsole.log(response.Instance?.InstanceAccessUrl);\nconsole.log(response.Instance?.IdentityManagementType);\n```\n\n## Common Operations\n\n### List users with pagination\n\n`ListUsers` returns summaries and uses `NextToken` pagination.\n\n```javascript\nimport {\n  ConnectClient,\n  ListUsersCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\n\nif (!instanceId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID before listing users\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListUsersCommand({\n      InstanceId: instanceId,\n      MaxResults: 100,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const user of page.UserSummaryList ?? []) {\n    console.log(user.Id, user.Username, user.Arn);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n### Search users by username prefix\n\nUse `SearchUsers` when you need filtering instead of walking the full user list.\n\n```javascript\nimport {\n  ConnectClient,\n  SearchUsersCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\n\nif (!instanceId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID before searching users\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new SearchUsersCommand({\n    InstanceId: instanceId,\n    MaxResults: 25,\n    SearchCriteria: {\n      StringCondition: {\n        FieldName: \"Username\",\n        Value: \"alex\",\n        ComparisonType: \"STARTS_WITH\",\n      },\n    },\n  }),\n);\n\nfor (const user of response.Users ?? []) {\n  console.log(user.Id, user.Username, user.IdentityInfo?.Email);\n}\n```\n\nSupported string-search fields include `Username`, `FirstName`, `LastName`, `RoutingProfileId`, `SecurityProfileId`, and `resourceId`.\n\n### Read a full user record\n\n`DescribeUser` gives you the expanded user document after you already know the user ID.\n\n```javascript\nimport {\n  ConnectClient,\n  DescribeUserCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\nconst userId = process.env.CONNECT_USER_ID;\n\nif (!instanceId || !userId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID and CONNECT_USER_ID before describing a user\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DescribeUserCommand({\n    InstanceId: instanceId,\n    UserId: userId,\n  }),\n);\n\nconsole.log(response.User?.Username);\nconsole.log(response.User?.IdentityInfo?.Email);\nconsole.log(response.User?.RoutingProfileId);\nconsole.log(response.User?.SecurityProfileIds);\n```\n\n### Create a user in a Connect-managed instance\n\nThis example uses `CONNECT_MANAGED` identity management, where `Password` is required. For SAML or existing-directory setups, do not blindly reuse the same identity fields; see the gotchas section below.\n\n```javascript\nimport {\n  ConnectClient,\n  CreateUserCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\nconst routingProfileId = process.env.CONNECT_ROUTING_PROFILE_ID;\nconst securityProfileId = process.env.CONNECT_SECURITY_PROFILE_ID;\n\nif (!instanceId || !routingProfileId || !securityProfileId) {\n  throw new Error(\n    \"Set CONNECT_INSTANCE_ID, CONNECT_ROUTING_PROFILE_ID, and CONNECT_SECURITY_PROFILE_ID before creating a user\",\n  );\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new CreateUserCommand({\n    InstanceId: instanceId,\n    Username: \"alex.lee\",\n    Password: \"TempPassword123!\",\n    IdentityInfo: {\n      FirstName: \"Alex\",\n      LastName: \"Lee\",\n      Email: \"alex.lee@example.com\",\n    },\n    PhoneConfig: {\n      PhoneType: \"SOFT_PHONE\",\n      AutoAccept: false,\n      AfterContactWorkTimeLimit: 0,\n    },\n    RoutingProfileId: routingProfileId,\n    SecurityProfileIds: [securityProfileId],\n  }),\n);\n\nconsole.log(response.UserId);\nconsole.log(response.UserArn);\n```\n\n### Read current queue metrics\n\n`GetCurrentMetricData` returns real-time metrics. The example below asks for queue-level values for the voice channel.\n\n```javascript\nimport {\n  ConnectClient,\n  GetCurrentMetricDataCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\nconst queueId = process.env.CONNECT_QUEUE_ID;\n\nif (!instanceId || !queueId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID and CONNECT_QUEUE_ID before reading metrics\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new GetCurrentMetricDataCommand({\n    InstanceId: instanceId,\n    Filters: {\n      Queues: [queueId],\n      Channels: [\"VOICE\"],\n    },\n    Groupings: [\"QUEUE\"],\n    CurrentMetrics: [\n      { Name: \"AGENTS_AVAILABLE\", Unit: \"COUNT\" },\n      { Name: \"CONTACTS_IN_QUEUE\", Unit: \"COUNT\" },\n      { Name: \"OLDEST_CONTACT_AGE\", Unit: \"SECONDS\" },\n    ],\n  }),\n);\n\nfor (const result of response.MetricResults ?? []) {\n  const queue = result.Dimensions?.Queue?.Id;\n\n  for (const metric of result.Collections ?? []) {\n    console.log(queue, metric.Metric?.Name, metric.Value);\n  }\n}\n```\n\n### Start an outbound voice contact\n\nUse `StartOutboundVoiceContact` to place an outbound call and run the specified contact flow.\n\n```javascript\nimport {\n  ConnectClient,\n  StartOutboundVoiceContactCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\nconst contactFlowId = process.env.CONNECT_CONTACT_FLOW_ID;\n\nif (!instanceId || !contactFlowId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID and CONNECT_CONTACT_FLOW_ID before starting an outbound contact\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new StartOutboundVoiceContactCommand({\n    InstanceId: instanceId,\n    ContactFlowId: contactFlowId,\n    DestinationPhoneNumber: \"+12065550100\",\n    SourcePhoneNumber: \"+12065550199\",\n    Name: \"Order follow-up\",\n    Attributes: {\n      orderId: \"12345\",\n      customerTier: \"gold\",\n    },\n    RingTimeoutInSeconds: 30,\n  }),\n);\n\nconsole.log(response.ContactId);\n```\n\nIf you need to stop a queued callback or another stoppable contact later:\n\n```javascript\nimport {\n  ConnectClient,\n  StopContactCommand,\n} from \"@aws-sdk/client-connect\";\n\nconst instanceId = process.env.CONNECT_INSTANCE_ID;\nconst contactId = process.env.CONNECT_CONTACT_ID;\n\nif (!instanceId || !contactId) {\n  throw new Error(\"Set CONNECT_INSTANCE_ID and CONNECT_CONTACT_ID before stopping a contact\");\n}\n\nconst client = new ConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new StopContactCommand({\n    InstanceId: instanceId,\n    ContactId: contactId,\n  }),\n);\n```\n\n## Connect-Specific Gotchas\n\n- Most Connect APIs require `InstanceId`; forgetting it is one of the fastest ways to get blocked.\n- Keep the SDK `region` aligned with the Connect instance region. A region mismatch often looks like a missing resource or access problem.\n- `CreateUserCommand` rules depend on the instance identity-management mode. `Password` is required for `CONNECT_MANAGED`, must be omitted otherwise, and `DirectoryUserId` is invalid for SAML identities.\n- `CreateUserCommand` does not let you mix `PhoneConfig` fields with the corresponding channel-specific config families such as `AutoAcceptConfigs`, `AfterContactWorkConfigs`, `PhoneNumberConfigs`, or `PersistentConnectionConfigs`.\n- `StartOutboundVoiceContactCommand` expects E.164 phone numbers such as `+12065550100`. If you omit `RingTimeoutInSeconds`, Amazon Connect uses a 60-second dialing timeout.\n- `GetCurrentMetricDataCommand` has request-shape rules: grouping by `CHANNEL` should include a `Channels` filter, and some groupings require a queue filter or queue-first grouping.\n- `StopContactCommand` does not stop every voice contact type. It is intended for stoppable contacts such as queued callbacks, while some voice initiation methods are explicitly unsupported.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: explicit shared-profile, Cognito, and assume-role credential flows.\n- `@aws-sdk/client-connectcases`: Amazon Connect Cases is a separate service client.\n- `@aws-sdk/client-connectparticipant`: use this for participant messaging APIs instead of the Connect control-plane client.\n"
  },
  {
    "path": "content/aws/docs/controltower/javascript/DOC.md",
    "content": "---\nname: controltower\ndescription: \"AWS SDK for JavaScript v3 client for AWS Control Tower landing zone, control, baseline, and tagging APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,controltower,javascript,nodejs,governance,landing-zone,organizations\"\n---\n\n# `@aws-sdk/client-controltower`\n\nUse this package for AWS Control Tower APIs in AWS SDK for JavaScript v3. The most common automation flows are:\n\n- inspect the current landing zone\n- list or change enabled controls on an organizational unit (OU)\n- manage enabled baselines for an OU\n\nControl Tower mutating APIs are asynchronous. After `EnableControl`, `DisableControl`, `ResetEnabledControl`, `EnableBaseline`, `DisableBaseline`, `ResetEnabledBaseline`, `CreateLandingZone`, `ResetLandingZone`, or `DeleteLandingZone`, store the returned `operationIdentifier` and poll the matching `Get*Operation` API until it reaches a terminal state.\n\nThis client is usually used from trusted server-side code with AWS credentials that already have permission to manage Control Tower resources.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-controltower\n```\n\nPrefer `ControlTowerClient` plus explicit command imports.\n\n## Initialize the client\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=my-controltower-admin\n\nexport CONTROLTOWER_TARGET_IDENTIFIER=arn:aws:organizations::123456789012:ou/o-example/ou-abcd-12345678\nexport CONTROLTOWER_CONTROL_IDENTIFIER=<your-control-arn>\nexport CONTROLTOWER_BASELINE_IDENTIFIER=<your-baseline-arn>\nexport CONTROLTOWER_BASELINE_VERSION=<baseline-version>\nexport CONTROLTOWER_LANDING_ZONE_IDENTIFIER=<optional-landing-zone-arn>\n```\n\nCreate the client:\n\n```javascript\nimport { ControlTowerClient } from \"@aws-sdk/client-controltower\";\n\nfunction required(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing environment variable: ${name}`);\n  }\n\n  return value;\n}\n\nconst controlTower = new ControlTowerClient({\n  region: required(\"AWS_REGION\"),\n});\n```\n\nIn Node.js, the default AWS SDK v3 credential provider chain is usually enough if you already configured credentials through environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance metadata.\n\n## What this client covers\n\n`@aws-sdk/client-controltower` covers Control Tower APIs for:\n\n- landing zones: `ListLandingZones`, `GetLandingZone`, `GetLandingZoneOperation`, `ListLandingZoneOperations`, `CreateLandingZone`, `ResetLandingZone`, `DeleteLandingZone`\n- controls: `ListEnabledControls`, `GetEnabledControl`, `EnableControl`, `DisableControl`, `ResetEnabledControl`, `GetControlOperation`, `ListControlOperations`\n- baselines: `ListBaselines`, `GetBaseline`, `ListEnabledBaselines`, `GetEnabledBaseline`, `EnableBaseline`, `DisableBaseline`, `ResetEnabledBaseline`, `UpdateEnabledBaseline`, `GetBaselineOperation`\n- resource tags: `ListTagsForResource`, `TagResource`, `UntagResource`\n\nMost applications only need the control and baseline workflows plus occasional landing zone inspection.\n\n## Common workflows\n\n### Find the current landing zone and inspect its status\n\n`ListLandingZones` returns the landing zone ARN for the managed account. Use that ARN as `landingZoneIdentifier` for `GetLandingZone` and `ResetLandingZone`.\n\n```javascript\nimport {\n  ControlTowerClient,\n  GetLandingZoneCommand,\n  ListLandingZonesCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst listResult = await controlTower.send(\n  new ListLandingZonesCommand({\n    maxResults: 1,\n  }),\n);\n\nconst landingZoneIdentifier = listResult.landingZones?.[0];\n\nif (!landingZoneIdentifier) {\n  throw new Error(\"No landing zone ARN returned by ListLandingZones\");\n}\n\nconst detailResult = await controlTower.send(\n  new GetLandingZoneCommand({\n    landingZoneIdentifier,\n  }),\n);\n\nconsole.log({\n  landingZoneIdentifier,\n  version: detailResult.landingZone?.version,\n  latestAvailableVersion: detailResult.landingZone?.latestAvailableVersion,\n  status: detailResult.landingZone?.status,\n  driftStatus: detailResult.landingZone?.driftStatus?.status,\n  remediationTypes: detailResult.landingZone?.remediationTypes,\n});\n```\n\nThe landing zone detail also includes `manifest`, which is the landing zone configuration document returned by the service.\n\n### List enabled controls for one OU\n\n`targetIdentifier` is the OU ARN. `ListEnabledControls` is paginated and can optionally include child OU results.\n\n```javascript\nimport {\n  ControlTowerClient,\n  ListEnabledControlsCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst targetIdentifier = process.env.CONTROLTOWER_TARGET_IDENTIFIER;\n\nif (!targetIdentifier) {\n  throw new Error(\"Missing CONTROLTOWER_TARGET_IDENTIFIER\");\n}\n\nlet nextToken;\n\ndo {\n  const page = await controlTower.send(\n    new ListEnabledControlsCommand({\n      targetIdentifier,\n      includeChildren: false,\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const control of page.enabledControls ?? []) {\n    console.log({\n      enabledControlArn: control.arn,\n      controlIdentifier: control.controlIdentifier,\n      targetIdentifier: control.targetIdentifier,\n      enablementStatus: control.statusSummary?.status,\n      driftStatus: control.driftStatusSummary?.driftStatus,\n      parentIdentifier: control.parentIdentifier,\n    });\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\nIf you only care about a specific control, pass a filter:\n\n```javascript\nfilter: {\n  controlIdentifiers: [process.env.CONTROLTOWER_CONTROL_IDENTIFIER],\n}\n```\n\n### Enable a control and wait for completion\n\n`EnableControl` returns immediately with an `operationIdentifier`. Poll `GetControlOperation` until the status is `SUCCEEDED` or `FAILED`.\n\n```javascript\nimport {\n  ControlTowerClient,\n  EnableControlCommand,\n  GetControlOperationCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst controlIdentifier = process.env.CONTROLTOWER_CONTROL_IDENTIFIER;\nconst targetIdentifier = process.env.CONTROLTOWER_TARGET_IDENTIFIER;\n\nif (!controlIdentifier || !targetIdentifier) {\n  throw new Error(\"Missing CONTROLTOWER_CONTROL_IDENTIFIER or CONTROLTOWER_TARGET_IDENTIFIER\");\n}\n\nconst enableResult = await controlTower.send(\n  new EnableControlCommand({\n    controlIdentifier,\n    targetIdentifier,\n    tags: {\n      owner: \"platform-team\",\n    },\n    // Some controls require parameters.\n    // parameters: [{ key: \"AllowedRegions\", value: [\"us-east-1\", \"us-west-2\"] }],\n  }),\n);\n\nconst operationIdentifier = enableResult.operationIdentifier;\n\nif (!operationIdentifier) {\n  throw new Error(\"EnableControl did not return an operation identifier\");\n}\n\nwhile (true) {\n  const operationResult = await controlTower.send(\n    new GetControlOperationCommand({\n      operationIdentifier,\n    }),\n  );\n\n  const operation = operationResult.controlOperation;\n  const status = operation?.status;\n\n  console.log({\n    operationIdentifier,\n    status,\n    statusMessage: operation?.statusMessage,\n  });\n\n  if (status === \"SUCCEEDED\") {\n    console.log({ enabledControlArn: enableResult.arn });\n    break;\n  }\n\n  if (status === \"FAILED\") {\n    throw new Error(operation?.statusMessage ?? \"EnableControl failed\");\n  }\n\n  await sleep(5000);\n}\n```\n\n`EnableControl` only permits strongly recommended and elective controls, except for the Region deny control.\n\n### Disable or reset an enabled control\n\nIf you already know the enabled control ARN, use that as `enabledControlIdentifier`. This is the safest identifier to use for `DisableControl` and `ResetEnabledControl`.\n\n```javascript\nimport {\n  ControlTowerClient,\n  DisableControlCommand,\n  GetControlOperationCommand,\n  ListEnabledControlsCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst controlIdentifier = process.env.CONTROLTOWER_CONTROL_IDENTIFIER;\nconst targetIdentifier = process.env.CONTROLTOWER_TARGET_IDENTIFIER;\n\nif (!controlIdentifier || !targetIdentifier) {\n  throw new Error(\"Missing CONTROLTOWER_CONTROL_IDENTIFIER or CONTROLTOWER_TARGET_IDENTIFIER\");\n}\n\nconst listResult = await controlTower.send(\n  new ListEnabledControlsCommand({\n    targetIdentifier,\n    filter: {\n      controlIdentifiers: [controlIdentifier],\n    },\n    maxResults: 10,\n  }),\n);\n\nconst enabledControlIdentifier = listResult.enabledControls?.[0]?.arn;\n\nif (!enabledControlIdentifier) {\n  throw new Error(\"The requested control is not enabled on this OU\");\n}\n\nconst disableResult = await controlTower.send(\n  new DisableControlCommand({\n    enabledControlIdentifier,\n  }),\n);\n\nconst operationIdentifier = disableResult.operationIdentifier;\n\nif (!operationIdentifier) {\n  throw new Error(\"DisableControl did not return an operation identifier\");\n}\n\nwhile (true) {\n  const operationResult = await controlTower.send(\n    new GetControlOperationCommand({\n      operationIdentifier,\n    }),\n  );\n\n  const status = operationResult.controlOperation?.status;\n\n  if (status === \"SUCCEEDED\") {\n    break;\n  }\n\n  if (status === \"FAILED\") {\n    throw new Error(\n      operationResult.controlOperation?.statusMessage ??\n        `Control operation ${operationIdentifier} failed`,\n    );\n  }\n\n  await sleep(5000);\n}\n```\n\nUse `ResetEnabledControl` with the same `enabledControlIdentifier` if you need to repair drift instead of disabling. It does not work for controls implemented with SCPs.\n\n### List available baselines and enabled baselines\n\n`ListBaselines` returns baseline summaries. `ListEnabledBaselines` returns the baselines currently applied to targets, and supports filtering by target, baseline, parent, status, and drift state.\n\n```javascript\nimport {\n  ControlTowerClient,\n  ListBaselinesCommand,\n  ListEnabledBaselinesCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst targetIdentifier = process.env.CONTROLTOWER_TARGET_IDENTIFIER;\n\nlet baselineToken;\n\ndo {\n  const page = await controlTower.send(\n    new ListBaselinesCommand({\n      maxResults: 50,\n      nextToken: baselineToken,\n    }),\n  );\n\n  for (const baseline of page.baselines ?? []) {\n    console.log({\n      arn: baseline.arn,\n      name: baseline.name,\n      description: baseline.description,\n    });\n  }\n\n  baselineToken = page.nextToken;\n} while (baselineToken);\n\nif (targetIdentifier) {\n  const enabledPage = await controlTower.send(\n    new ListEnabledBaselinesCommand({\n      filter: {\n        targetIdentifiers: [targetIdentifier],\n      },\n      includeChildren: false,\n      maxResults: 50,\n    }),\n  );\n\n  for (const baseline of enabledPage.enabledBaselines ?? []) {\n    console.log({\n      enabledBaselineArn: baseline.arn,\n      baselineIdentifier: baseline.baselineIdentifier,\n      baselineVersion: baseline.baselineVersion,\n      targetIdentifier: baseline.targetIdentifier,\n      status: baseline.statusSummary?.status,\n      inheritanceDriftStatus:\n        baseline.driftStatusSummary?.types?.inheritance?.status,\n    });\n  }\n}\n```\n\n### Enable a baseline on an OU and poll until complete\n\n`EnableBaseline` requires a baseline ARN, a baseline version, and an OU ARN. The target must be an OU.\n\n```javascript\nimport {\n  ControlTowerClient,\n  EnableBaselineCommand,\n  GetBaselineOperationCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst baselineIdentifier = process.env.CONTROLTOWER_BASELINE_IDENTIFIER;\nconst baselineVersion = process.env.CONTROLTOWER_BASELINE_VERSION;\nconst targetIdentifier = process.env.CONTROLTOWER_TARGET_IDENTIFIER;\n\nif (!baselineIdentifier || !baselineVersion || !targetIdentifier) {\n  throw new Error(\n    \"Missing CONTROLTOWER_BASELINE_IDENTIFIER, CONTROLTOWER_BASELINE_VERSION, or CONTROLTOWER_TARGET_IDENTIFIER\",\n  );\n}\n\nconst enableResult = await controlTower.send(\n  new EnableBaselineCommand({\n    baselineIdentifier,\n    baselineVersion,\n    targetIdentifier,\n    tags: {\n      owner: \"platform-team\",\n    },\n    // parameters: [{ key: \"SomeBaselineParameter\", value: \"example\" }],\n  }),\n);\n\nconst operationIdentifier = enableResult.operationIdentifier;\n\nif (!operationIdentifier) {\n  throw new Error(\"EnableBaseline did not return an operation identifier\");\n}\n\nwhile (true) {\n  const operationResult = await controlTower.send(\n    new GetBaselineOperationCommand({\n      operationIdentifier,\n    }),\n  );\n\n  const operation = operationResult.baselineOperation;\n  const status = operation?.status;\n\n  console.log({\n    operationIdentifier,\n    status,\n    statusMessage: operation?.statusMessage,\n  });\n\n  if (status === \"SUCCEEDED\") {\n    console.log({ enabledBaselineArn: enableResult.arn });\n    break;\n  }\n\n  if (status === \"FAILED\") {\n    throw new Error(operation?.statusMessage ?? \"EnableBaseline failed\");\n  }\n\n  await sleep(5000);\n}\n```\n\n## Practical notes\n\n- Mutating APIs are async. Do not assume the resource is ready immediately after `Enable*`, `Disable*`, `Reset*`, `CreateLandingZone`, `ResetLandingZone`, or `DeleteLandingZone`.\n- Use the matching poll API: `GetControlOperation`, `GetBaselineOperation`, or `GetLandingZoneOperation`.\n- `ListEnabledControls`, `ListBaselines`, `ListEnabledBaselines`, `ListControlOperations`, `ListLandingZones`, and `ListLandingZoneOperations` all use `nextToken` pagination.\n- Control Tower identifiers are ARNs. For control workflows, `targetIdentifier` is an OU ARN. For baseline enablement, only OUs are supported as targets.\n- `DisableControl` and `ResetEnabledControl` are easier to drive from `enabledControlIdentifier`, which you can get from `ListEnabledControls` or `EnableControl` output.\n- Drift repair uses `ResetEnabledControl`, `ResetEnabledBaseline`, and `ResetLandingZone`.\n- Expect service-level errors such as `ConflictException`, `ValidationException`, `AccessDeniedException`, `ResourceNotFoundException`, `ServiceQuotaExceededException`, and `ThrottlingException`.\n- Control operation details and landing zone operation details are available for 90 days.\n\n## Minimal landing zone reset example\n\nIf the landing zone is drifted and you already know the landing zone ARN, reset it and poll the landing zone operation:\n\n```javascript\nimport {\n  ControlTowerClient,\n  GetLandingZoneOperationCommand,\n  ResetLandingZoneCommand,\n} from \"@aws-sdk/client-controltower\";\n\nconst controlTower = new ControlTowerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst landingZoneIdentifier = process.env.CONTROLTOWER_LANDING_ZONE_IDENTIFIER;\n\nif (!landingZoneIdentifier) {\n  throw new Error(\"Missing CONTROLTOWER_LANDING_ZONE_IDENTIFIER\");\n}\n\nconst resetResult = await controlTower.send(\n  new ResetLandingZoneCommand({\n    landingZoneIdentifier,\n  }),\n);\n\nconst operationIdentifier = resetResult.operationIdentifier;\n\nif (!operationIdentifier) {\n  throw new Error(\"ResetLandingZone did not return an operation identifier\");\n}\n\nwhile (true) {\n  const operationResult = await controlTower.send(\n    new GetLandingZoneOperationCommand({\n      operationIdentifier,\n    }),\n  );\n\n  const operation = operationResult.operationDetails;\n  const status = operation?.status;\n\n  if (status === \"SUCCEEDED\") {\n    break;\n  }\n\n  if (status === \"FAILED\") {\n    throw new Error(operation?.statusMessage ?? \"ResetLandingZone failed\");\n  }\n\n  await sleep(10000);\n}\n```\n"
  },
  {
    "path": "content/aws/docs/cost-explorer/javascript/DOC.md",
    "content": "---\nname: cost-explorer\ndescription: \"AWS SDK for JavaScript v3 client for Cost Explorer historical cost, dimension discovery, forecasts, and resource-level cost queries.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cost-explorer,billing,cost-management,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-cost-explorer`\n\nUse this package to query AWS Cost Explorer from JavaScript or Node.js. The main workflows are: retrieve historical cost and usage with `GetCostAndUsage`, discover valid filter values with `GetDimensionValues`, request forecasts with `GetCostForecast`, and read resource-level EC2 cost data with `GetCostAndUsageWithResources` when that feature is enabled.\n\nCost Explorer is a billing service. In the standard AWS partition, its endpoint resolves to `ce.us-east-1.amazonaws.com`, so it is practical to set `us-east-1` explicitly in client configuration.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-cost-explorer\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nTypical local environment variables:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=billing\n\n# Or use direct credentials instead of AWS_PROFILE\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=... # only for temporary credentials\n```\n\n## Client setup\n\n```javascript\nimport { CostExplorerClient } from \"@aws-sdk/client-cost-explorer\";\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default AWS SDK v3 credential provider chain is usually enough when credentials already come from environment variables, shared AWS config files, IAM Identity Center, ECS, or EC2 instance metadata.\n\nIf you need a specific shared config profile in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { CostExplorerClient } from \"@aws-sdk/client-cost-explorer\";\n\nconst costExplorer = new CostExplorerClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"billing\" }),\n});\n```\n\n## Common workflows\n\n### Get historical cost grouped by service\n\n`GetCostAndUsage` is the main reporting API for historical spend and usage. The request requires `TimePeriod`, `Granularity`, and `Metrics`.\n\n```javascript\nimport {\n  CostExplorerClient,\n  GetCostAndUsageCommand,\n} from \"@aws-sdk/client-cost-explorer\";\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextPageToken;\nconst pages = [];\n\ndo {\n  const page = await costExplorer.send(\n    new GetCostAndUsageCommand({\n      TimePeriod: {\n        Start: \"2026-02-01\",\n        End: \"2026-03-01\",\n      },\n      Granularity: \"MONTHLY\",\n      Metrics: [\"UnblendedCost\"],\n      GroupBy: [\n        {\n          Type: \"DIMENSION\",\n          Key: \"SERVICE\",\n        },\n      ],\n      NextPageToken: nextPageToken,\n    }),\n  );\n\n  pages.push(page);\n  nextPageToken = page.NextPageToken;\n} while (nextPageToken);\n\nconst rows = pages.flatMap(\n  (page) =>\n    page.ResultsByTime?.flatMap((result) => {\n      return (result.Groups ?? []).map((group) => ({\n        start: result.TimePeriod?.Start,\n        end: result.TimePeriod?.End,\n        service: group.Keys?.[0],\n        amount: group.Metrics?.UnblendedCost?.Amount,\n        unit: group.Metrics?.UnblendedCost?.Unit,\n        estimated: result.Estimated,\n      }));\n    }) ?? [],\n);\n\nconsole.table(rows);\n```\n\nThe `TimePeriod.Start` date is inclusive and `TimePeriod.End` is exclusive. For a full calendar month, use the first day of the month as `Start` and the first day of the next month as `End`.\n\n### Filter by linked account or service\n\nFilters use the `Expression` shape. For `GetCostAndUsage`, dimension filters support `EQUALS` and `CASE_SENSITIVE` match options.\n\n```javascript\nimport {\n  CostExplorerClient,\n  GetCostAndUsageCommand,\n} from \"@aws-sdk/client-cost-explorer\";\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await costExplorer.send(\n  new GetCostAndUsageCommand({\n    TimePeriod: {\n      Start: \"2026-02-01\",\n      End: \"2026-03-01\",\n    },\n    Granularity: \"DAILY\",\n    Metrics: [\"UnblendedCost\", \"UsageQuantity\"],\n    Filter: {\n      And: [\n        {\n          Dimensions: {\n            Key: \"LINKED_ACCOUNT\",\n            Values: [\"123456789012\"],\n          },\n        },\n        {\n          Dimensions: {\n            Key: \"SERVICE\",\n            Values: [\"Amazon Elastic Compute Cloud - Compute\"],\n          },\n        },\n      ],\n    },\n  }),\n);\n\nconsole.dir(response.ResultsByTime, { depth: null });\n```\n\nBe careful with `UsageQuantity`: Cost Explorer can aggregate different units together unless you also narrow the query by `USAGE_TYPE` or `USAGE_TYPE_GROUP`.\n\n### Discover valid dimension values before building filters\n\nDo not guess service names, linked account IDs, or usage types. Use `GetDimensionValues` to retrieve values that Cost Explorer accepts for the time period and context you care about.\n\n```javascript\nimport {\n  CostExplorerClient,\n  GetDimensionValuesCommand,\n} from \"@aws-sdk/client-cost-explorer\";\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextPageToken;\nconst values = [];\n\ndo {\n  const page = await costExplorer.send(\n    new GetDimensionValuesCommand({\n      TimePeriod: {\n        Start: \"2026-02-01\",\n        End: \"2026-03-01\",\n      },\n      Context: \"COST_AND_USAGE\",\n      Dimension: \"SERVICE\",\n      SearchString: \"Amazon\",\n      NextPageToken: nextPageToken,\n    }),\n  );\n\n  values.push(...(page.DimensionValues ?? []));\n  nextPageToken = page.NextPageToken;\n} while (nextPageToken);\n\nconsole.table(\n  values.map((entry) => ({\n    value: entry.Value,\n    attributes: entry.Attributes,\n  })),\n);\n```\n\nFor cost-and-usage queries, `GetDimensionValues` can return dimensions such as `SERVICE`, `LINKED_ACCOUNT`, `REGION`, `USAGE_TYPE`, `USAGE_TYPE_GROUP`, and `RESOURCE_ID`.\n\n### Forecast future cost\n\nUse `GetCostForecast` for forward-looking spend estimates. Forecast metric names use uppercase enum values such as `UNBLENDED_COST`, not the camel-case metric names used by `GetCostAndUsage`.\n\n```javascript\nimport {\n  CostExplorerClient,\n  GetCostForecastCommand,\n} from \"@aws-sdk/client-cost-explorer\";\n\nfunction formatDate(date) {\n  return date.toISOString().slice(0, 10);\n}\n\nconst now = new Date();\nconst forecastStart = new Date(\n  Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1),\n);\nconst forecastEnd = new Date(\n  Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 3, 1),\n);\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await costExplorer.send(\n  new GetCostForecastCommand({\n    TimePeriod: {\n      Start: formatDate(forecastStart),\n      End: formatDate(forecastEnd),\n    },\n    Metric: \"UNBLENDED_COST\",\n    Granularity: \"MONTHLY\",\n    Filter: {\n      Dimensions: {\n        Key: \"SERVICE\",\n        Values: [\"Amazon Simple Storage Service\"],\n      },\n    },\n    PredictionIntervalLevel: 80,\n  }),\n);\n\nconsole.log({\n  totalAmount: response.Total?.Amount,\n  totalUnit: response.Total?.Unit,\n});\n\nconsole.table(\n  (response.ForecastResultsByTime ?? []).map((entry) => ({\n    start: entry.TimePeriod?.Start,\n    end: entry.TimePeriod?.End,\n    meanValue: entry.MeanValue,\n    lowerBound: entry.PredictionIntervalLowerBound,\n    upperBound: entry.PredictionIntervalUpperBound,\n  })),\n);\n```\n\n`GetCostForecast` supports only `DAILY` and `MONTHLY` granularity.\n\n### Query resource-level EC2 cost data\n\nUse `GetCostAndUsageWithResources` only when you need resource-level cost data. This feature is opt-in, limited to the last 14 days, and requires a `RESOURCE_ID` filter or group plus the EC2 compute service filter.\n\n```javascript\nimport {\n  CostExplorerClient,\n  GetCostAndUsageWithResourcesCommand,\n} from \"@aws-sdk/client-cost-explorer\";\n\nfunction formatDate(date) {\n  return date.toISOString().slice(0, 10);\n}\n\nconst end = new Date();\nconst start = new Date();\nstart.setUTCDate(start.getUTCDate() - 7);\n\nconst costExplorer = new CostExplorerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await costExplorer.send(\n  new GetCostAndUsageWithResourcesCommand({\n    TimePeriod: {\n      Start: formatDate(start),\n      End: formatDate(end),\n    },\n    Granularity: \"DAILY\",\n    Filter: {\n      And: [\n        {\n          Dimensions: {\n            Key: \"SERVICE\",\n            Values: [\"Amazon Elastic Compute Cloud - Compute\"],\n          },\n        },\n        {\n          Dimensions: {\n            Key: \"RESOURCE_ID\",\n            Values: [\"i-0123456789abcdef0\"],\n          },\n        },\n      ],\n    },\n    Metrics: [\"UnblendedCost\"],\n  }),\n);\n\nconsole.table(\n  (response.ResultsByTime ?? []).map((entry) => ({\n    start: entry.TimePeriod?.Start,\n    end: entry.TimePeriod?.End,\n    amount: entry.Total?.UnblendedCost?.Amount,\n    unit: entry.Total?.UnblendedCost?.Unit,\n    estimated: entry.Estimated,\n  })),\n);\n```\n\nHourly granularity is only available for EC2 instance resource-level data. Other resource-level data is available only at daily granularity.\n\n## Important pitfalls\n\n- `TimePeriod.Start` is inclusive and `TimePeriod.End` is exclusive across Cost Explorer reporting and dimension lookups.\n- Historical reporting APIs such as `GetCostAndUsage` use metric names like `UnblendedCost`, while forecast APIs use enum names like `UNBLENDED_COST`.\n- These APIs use `NextPageToken`, not `NextToken`. Handle pagination manually for `GetCostAndUsage`, `GetDimensionValues`, and `GetCostAndUsageWithResources`.\n- Each `Expression` can have only one root operator. Nest `And`, `Or`, and `Not` instead of combining multiple root fields in the same object.\n- `UsageQuantity` is not meaningful across mixed units unless you also filter by `USAGE_TYPE` or `USAGE_TYPE_GROUP`.\n- `GetCostAndUsageWithResources` is opt-in, limited to the last 14 days, and requires EC2 compute service plus `RESOURCE_ID` filtering or grouping.\n- A management account in AWS Organizations can query member-account cost data.\n\n## Related packages\n\n- `@aws-sdk/credential-providers`: explicit profile, SSO, Cognito, and assume-role credential flows.\n- `@aws-sdk/client-budgets`: budgets, notifications, and budget actions when you need enforcement or alerts in addition to reporting.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-cost-explorer` version `3.1007.0`.\n- Current endpoint rules resolve the standard AWS partition to `ce.us-east-1.amazonaws.com` and the China partition to `ce.cn-northwest-1.amazonaws.com.cn`.\n- The current Cost Explorer API model does not advertise SDK paginators for `GetCostAndUsage`, `GetDimensionValues`, or `GetCostAndUsageWithResources`, so explicit `NextPageToken` loops are the safe default.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 Cost Explorer client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cost-explorer/`\n- AWS Cost Explorer API Reference: `https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/Welcome.html`\n- `GetCostAndUsage` API reference: `https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostAndUsage.html`\n- `GetDimensionValues` API reference: `https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetDimensionValues.html`\n- `GetCostForecast` API reference: `https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostForecast.html`\n- `GetCostAndUsageWithResources` API reference: `https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostAndUsageWithResources.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-cost-explorer`\n"
  },
  {
    "path": "content/aws/docs/credential-providers/javascript/DOC.md",
    "content": "---\nname: credential-providers\ndescription: \"AWS SDK for JavaScript v3 credential provider helpers for shared profiles, IAM Identity Center, STS assume-role, web identity, Cognito, and Node.js credential resolution.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,credentials,sts,sso,cognito,iam,javascript,nodejs\"\n---\n\n# `@aws-sdk/credential-providers`\n\nUse this package when you need to tell an AWS SDK v3 client **how to get credentials**: shared profiles, IAM Identity Center (SSO), STS assume-role, OIDC/web identity, Cognito identity pools, ECS/EC2 metadata, or the same default Node.js credential chain that AWS clients already use.\n\n## Install\n\nInstall the provider package plus the AWS service client you actually call:\n\n```bash\nnpm install @aws-sdk/credential-providers @aws-sdk/client-s3\n```\n\nExamples below also use:\n\n```bash\nnpm install @aws-sdk/client-sts @aws-sdk/s3-request-presigner\n```\n\n## Golden Rule\n\n- In Node.js, AWS SDK v3 clients already use the default credential provider chain. You usually do **not** need to pass `credentials` at all.\n- Use this package when you need an explicit credential source, a non-default profile, assume-role, SSO, token-file auth, Cognito identity pools, or credentials outside a client constructor.\n- `fromIni()`, `fromEnv()`, `fromProcess()`, `fromTokenFile()`, `fromSSO()`, `fromNodeProviderChain()`, `fromContainerMetadata()`, and `fromInstanceMetadata()` are for Node.js.\n- `fromCognitoIdentity()`, `fromCognitoIdentityPool()`, `fromWebToken()`, and `fromTemporaryCredentials()` are available in browsers and native apps.\n\n## Default Node.js Behavior\n\nThis package powers the default credential behavior for Node.js AWS SDK clients.\n\nIf your environment already has working AWS credentials, this is enough:\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await s3.send(new ListBucketsCommand({}));\nconsole.log(result.Buckets);\n```\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\n\n# Option 1: shared profile files\nexport AWS_PROFILE=dev\n\n# Option 2: static or temporary environment credentials\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\n```\n\nIf you want the same default chain explicitly, use `fromNodeProviderChain()`.\n\n## Shared Profiles with `fromIni()`\n\nUse `fromIni()` when credentials come from `~/.aws/credentials`, `~/.aws/config`, an assume-role profile, or a profile selected with `AWS_PROFILE`.\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst profile = process.env.AWS_PROFILE ?? \"app-dev\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  profile,\n  credentials: fromIni({ profile }),\n});\n\nconst result = await s3.send(new ListBucketsCommand({}));\nconsole.log(result.Buckets);\n```\n\nExample shared files:\n\n`~/.aws/credentials`\n\n```ini\n[source-user]\naws_access_key_id = AKIAEXAMPLE\naws_secret_access_key = SECRETEXAMPLE\n```\n\n`~/.aws/config`\n\n```ini\n[profile app-dev]\nregion = us-west-2\nrole_arn = arn:aws:iam::123456789012:role/AppDeveloper\nsource_profile = source-user\n```\n\n`fromIni()` also supports `credential_source` for role assumption without a separate `source_profile`:\n\n```ini\n[profile app-prod]\nregion = us-west-2\nrole_arn = arn:aws:iam::123456789012:role/AppProduction\ncredential_source = Ec2InstanceMetadata\n```\n\nSupported `credential_source` values in maintainer docs are:\n\n- `Ec2InstanceMetadata`\n- `Environment`\n- `EcsContainer`\n\nUseful options:\n\n- `profile`: profile name to read.\n- `filepath`: override `~/.aws/credentials`.\n- `configFilepath`: override `~/.aws/config`.\n- `mfaCodeProvider`: required when the selected profile requires MFA.\n- `clientConfig`: overrides the inner STS or SSO client used to resolve credentials.\n\nAs of AWS SDK v3.714.0, AWS clients also accept a top-level `profile` field. In this package version, setting `profile` on the client is often the simplest way to select a profile for that client.\n\n## Fail Fast on Environment Variables with `fromEnv()`\n\nUse `fromEnv()` when you want credentials to come only from environment variables and you want a clear failure if they are missing.\n\n```javascript\nimport { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\nimport { fromEnv } from \"@aws-sdk/credential-providers\";\n\nconst sts = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromEnv(),\n});\n\nconst caller = await sts.send(new GetCallerIdentityCommand({}));\nconsole.log(caller.Arn);\n```\n\n`fromEnv()` reads:\n\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_CREDENTIAL_EXPIRATION`\n\n## Assume a Role at Runtime with `fromTemporaryCredentials()`\n\nUse `fromTemporaryCredentials()` when you want to assume a role in code instead of relying on a preconfigured profile.\n\n```javascript\nimport { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\nimport { fromIni, fromTemporaryCredentials } from \"@aws-sdk/credential-providers\";\n\nconst credentials = fromTemporaryCredentials({\n  masterCredentials: fromIni({ profile: \"source-user\" }),\n  clientConfig: {\n    region: \"us-east-1\",\n  },\n  params: {\n    RoleArn: \"arn:aws:iam::123456789012:role/DeployRole\",\n    RoleSessionName: \"deploy-session\",\n    DurationSeconds: 3600,\n  },\n});\n\nconst sts = new STSClient({\n  region: \"us-east-1\",\n  credentials,\n});\n\nconst caller = await sts.send(new GetCallerIdentityCommand({}));\nconsole.log(caller.Arn);\n```\n\nIf your `AssumeRole` request includes `SerialNumber`, also provide `mfaCodeProvider` so the SDK can fetch the MFA code.\n\n## OIDC or IRSA with `fromTokenFile()`\n\nUse `fromTokenFile()` when an OIDC token is on disk and AWS should call `AssumeRoleWithWebIdentity`. This is the pattern used by environments such as Kubernetes service-account token files.\n\nRequired inputs come from either function options or environment variables:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token\nexport AWS_ROLE_ARN=arn:aws:iam::123456789012:role/EksAppRole\nexport AWS_ROLE_SESSION_NAME=my-app\n```\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\nimport { fromTokenFile } from \"@aws-sdk/credential-providers\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromTokenFile(),\n});\n\nconst result = await s3.send(new ListBucketsCommand({}));\nconsole.log(result.Buckets);\n```\n\n`fromTokenFile()` reads:\n\n- `AWS_WEB_IDENTITY_TOKEN_FILE`\n- `AWS_ROLE_ARN`\n- `AWS_ROLE_SESSION_NAME`\n\nIf the web identity token is already in memory instead of a file on disk, use `fromWebToken()` instead.\n\n## IAM Identity Center with `fromSSO()`\n\nUse `fromSSO()` for a profile that contains direct IAM Identity Center / AWS SSO settings.\n\nFirst create an SSO-enabled profile with the AWS CLI:\n\n```bash\naws configure sso\n```\n\nExample profile:\n\n```ini\n[profile my-sso-profile]\nsso_account_id = 012345678901\nsso_region = us-east-1\nsso_role_name = SampleRole\nsso_start_url = https://d-abc123.awsapps.com/start\nregion = us-east-1\n```\n\nThen use it explicitly:\n\n```javascript\nimport { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\nimport { fromSSO } from \"@aws-sdk/credential-providers\";\n\nconst sts = new STSClient({\n  region: \"us-east-1\",\n  profile: \"my-sso-profile\",\n  credentials: fromSSO({ profile: \"my-sso-profile\" }),\n});\n\nconst caller = await sts.send(new GetCallerIdentityCommand({}));\nconsole.log(caller.Account);\n```\n\nImportant limitation from maintainer docs: `fromSSO()` only supports profiles that use the SSO credential directly. If the profile assumes another role derived from SSO, use `fromIni()` instead.\n\nTo clear local SSO sessions:\n\n```bash\naws sso logout\n```\n\n## Browser or Mobile Apps with Cognito Identity Pools\n\nUse `fromCognitoIdentityPool()` when browser or mobile code needs temporary AWS credentials from an identity pool.\n\n```javascript\nimport { S3Client, ListObjectsV2Command } from \"@aws-sdk/client-s3\";\nimport { fromCognitoIdentityPool } from \"@aws-sdk/credential-providers\";\n\nconst s3 = new S3Client({\n  region: \"us-east-1\",\n  credentials: fromCognitoIdentityPool({\n    clientConfig: { region: \"us-east-1\" },\n    identityPoolId: \"us-east-1:1699ebc0-7900-4099-b910-2df94f52a030\",\n    logins: {\n      \"cognito-idp.us-east-1.amazonaws.com/us-east-1_Example\": idToken,\n    },\n  }),\n});\n\nconst objects = await s3.send(\n  new ListObjectsV2Command({\n    Bucket: \"example-bucket\",\n    MaxKeys: 10,\n  }),\n);\n\nconsole.log(objects.Contents);\n```\n\nMaintainer docs note that `fromCognitoIdentityPool()` caches the `GetId` result internally, but does not cache `GetCredentialsForIdentity` results.\n\nIf you already have a Cognito `IdentityId`, use `fromCognitoIdentity()` instead of `fromCognitoIdentityPool()`.\n\n## Use the Default Chain Outside a Client Constructor\n\n`fromNodeProviderChain()` is useful when a helper needs credentials directly, such as an S3 presigner.\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport { fromNodeProviderChain } from \"@aws-sdk/credential-providers\";\n\nconst credentials = fromNodeProviderChain();\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials,\n});\n\nconst url = await getSignedUrl(\n  s3,\n  new PutObjectCommand({\n    Bucket: \"example-bucket\",\n    Key: \"uploads/example.txt\",\n  }),\n  { expiresIn: 900 },\n);\n\nconsole.log(url);\n```\n\n## Other Providers You May Need\n\n- `fromProcess()`: reads `credential_process` from shared AWS config and credentials files.\n- `fromContainerMetadata()`: reads credentials from the ECS task metadata endpoint.\n- `fromInstanceMetadata()`: reads credentials from the EC2 instance metadata service.\n- `fromWebToken()`: uses an in-memory web identity token instead of reading a token file.\n- `createCredentialChain()`: combines multiple providers or custom async credential functions into one chain.\n\n## Credential Provider Gotchas\n\n- In Node.js, do not add `credentials: fromNodeProviderChain()` unless you actually need an explicit provider. The client already uses that chain by default.\n- `~/.aws/credentials` and `~/.aws/config` profiles are not merged. If the same profile appears in both files, the credentials-file version takes precedence.\n- Provider `clientConfig` applies to the inner STS, SSO, or Cognito client used to resolve credentials. If you set `clientConfig.region`, that can override region values coming from the selected profile.\n- `fromIni()` can use `source_profile`, `credential_source`, SSO-backed profiles, and MFA, but the profile data must be valid AWS shared-config syntax.\n- `fromTokenFile()` requires both a web identity token file and a role ARN.\n- `fromSSO()` is for direct SSO profiles only; use `fromIni()` when an SSO profile is part of a larger assume-role chain.\n- `fromContainerMetadata()` and `fromInstanceMetadata()` are for AWS runtime environments, not local development laptops.\n- Credential providers refresh temporary credentials when the credential object includes an `expiration` and the remaining lifetime drops under five minutes.\n"
  },
  {
    "path": "content/aws/docs/datasync/javascript/DOC.md",
    "content": "---\nname: datasync\ndescription: \"AWS SDK for JavaScript v3 client for AWS DataSync locations, tasks, and task executions.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,datasync,javascript,nodejs,s3,data-transfer,migration\"\n---\n\n# `@aws-sdk/client-datasync`\n\nUse this package for AWS DataSync control-plane operations in AWS SDK for JavaScript v3: creating locations, creating and updating tasks, starting task executions, checking execution status, and listing existing DataSync resources.\n\nPrefer server-side code. Real DataSync workflows usually need AWS credentials with DataSync permissions, and S3-based transfers also need an IAM role that DataSync itself can assume for bucket access.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-datasync\n```\n\nIf you want to force a named profile from shared AWS config files in Node.js, install the credential helpers too:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Credentials and region\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_PROFILE=storage-migrations\nexport DATASYNC_S3_ROLE_ARN=arn:aws:iam::123456789012:role/DataSyncS3Access\n```\n\n- Set the client region explicitly. DataSync locations, tasks, and task executions are regional.\n- `CreateLocationS3Command` requires `S3Config.BucketAccessRoleArn`. This is the IAM role DataSync uses to read from or write to your S3 bucket.\n- If your runtime already has AWS credentials available, you can use the normal AWS SDK v3 default credential chain and only set the region in code.\n\n## Initialize the client\n\nUse the default provider chain when the environment is already configured:\n\n```javascript\nimport { DataSyncClient } from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nIf you want to force a named profile from shared AWS config:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { DataSyncClient } from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"storage-migrations\",\n  }),\n});\n```\n\n## What this client covers\n\nCommon DataSync workflows with this package include:\n\n- discovering existing locations with `ListLocationsCommand`\n- creating source and destination locations such as S3 with `CreateLocationS3Command`\n- creating transfer tasks with `CreateTaskCommand`\n- starting a task execution with `StartTaskExecutionCommand`\n- polling execution state with `DescribeTaskExecutionCommand`\n- updating schedules or task options with `UpdateTaskCommand`\n- listing or canceling executions with `ListTaskExecutionsCommand` and `CancelTaskExecutionCommand`\n\n## Common workflows\n\n### List existing locations\n\n`ListLocationsCommand` returns `LocationArn` and `LocationUri`. Use `NextToken` when you need the full list.\n\n```javascript\nimport {\n  DataSyncClient,\n  ListLocationsCommand,\n} from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await datasync.send(\n    new ListLocationsCommand({\n      MaxResults: 25,\n      NextToken: nextToken,\n      Filters: [\n        {\n          Name: \"LocationType\",\n          Operator: \"Equals\",\n          Values: [\"S3\"],\n        },\n      ],\n    }),\n  );\n\n  for (const location of page.Locations ?? []) {\n    console.log(location.LocationArn, location.LocationUri);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nIf the location you expect is missing, check the client region first.\n\n### Create an S3 location\n\nUse `CreateLocationS3Command` to register an S3 bucket or a prefix inside a bucket as a DataSync location. You decide later whether that location is a source or destination when creating the task.\n\n```javascript\nimport {\n  CreateLocationS3Command,\n  DataSyncClient,\n} from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst response = await datasync.send(\n  new CreateLocationS3Command({\n    S3BucketArn: \"arn:aws:s3:::company-transfer-source\",\n    Subdirectory: \"exports/2026-03-13\",\n    S3Config: {\n      BucketAccessRoleArn: process.env.DATASYNC_S3_ROLE_ARN,\n    },\n    Tags: [\n      {\n        Key: \"Name\",\n        Value: \"company-transfer-source\",\n      },\n    ],\n  }),\n);\n\nconsole.log(response.LocationArn);\n```\n\n`Subdirectory` is an S3 prefix, not a filesystem path. DataSync documents that this prefix must not start with `/` or contain `//`, `/./`, or `/../`.\n\n### Create a transfer task\n\nAt minimum, `CreateTaskCommand` needs a source location ARN and a destination location ARN.\n\n```javascript\nimport {\n  CreateTaskCommand,\n  DataSyncClient,\n} from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst response = await datasync.send(\n  new CreateTaskCommand({\n    SourceLocationArn: \"arn:aws:datasync:us-west-2:123456789012:location/loc-11111111111111111\",\n    DestinationLocationArn: \"arn:aws:datasync:us-west-2:123456789012:location/loc-22222222222222222\",\n    Name: \"nightly-s3-copy\",\n    Options: {\n      TransferMode: \"CHANGED\",\n      VerifyMode: \"ONLY_FILES_TRANSFERRED\",\n      LogLevel: \"BASIC\",\n      OverwriteMode: \"ALWAYS\",\n    },\n    CloudWatchLogGroupArn: \"arn:aws:logs:us-west-2:123456789012:log-group:/aws/datasync/nightly-s3-copy\",\n  }),\n);\n\nconsole.log(response.TaskArn);\n```\n\nIf you use include or exclude filters, DataSync only supports `FilterType: \"SIMPLE_PATTERN\"`, and the `Value` is one pipe-delimited string such as `\"/folder1|/folder2\"`.\n\nFor supported transfers, you can create an Enhanced mode task by adding `TaskMode: \"ENHANCED\"`. AWS documents Enhanced mode for S3-to-S3 transfers and certain non-agent S3 flows, and the caller creating the task needs `iam:CreateServiceLinkedRole`.\n\n### Start a task execution and poll until it finishes\n\n`StartTaskExecutionCommand` returns a task execution ARN. Use `DescribeTaskExecutionCommand` to check progress and final status.\n\n```javascript\nimport {\n  DataSyncClient,\n  DescribeTaskExecutionCommand,\n  StartTaskExecutionCommand,\n} from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst start = await datasync.send(\n  new StartTaskExecutionCommand({\n    TaskArn: \"arn:aws:datasync:us-west-2:123456789012:task/task-0123456789abcdef0\",\n    OverrideOptions: {\n      LogLevel: \"BASIC\",\n    },\n  }),\n);\n\nconst taskExecutionArn = start.TaskExecutionArn;\n\nif (!taskExecutionArn) {\n  throw new Error(\"StartTaskExecution did not return a task execution ARN\");\n}\n\nwhile (true) {\n  const execution = await datasync.send(\n    new DescribeTaskExecutionCommand({\n      TaskExecutionArn: taskExecutionArn,\n    }),\n  );\n\n  console.log({\n    status: execution.Status,\n    filesTransferred: execution.FilesTransferred,\n    bytesWritten: execution.BytesWritten,\n    bytesCompressed: execution.BytesCompressed,\n  });\n\n  if (execution.Status === \"SUCCESS\") {\n    break;\n  }\n\n  if (execution.Status === \"ERROR\") {\n    throw new Error(execution.Result?.ErrorDetail ?? \"DataSync task execution failed\");\n  }\n\n  await new Promise((resolve) => setTimeout(resolve, 15_000));\n}\n```\n\nThe execution status can move through states such as `QUEUED`, `LAUNCHING`, `PREPARING`, `TRANSFERRING`, and `VERIFYING` before reaching `SUCCESS` or `ERROR`.\n\n### Add or update a schedule\n\nUse `UpdateTaskCommand` when you want the task to run automatically.\n\n```javascript\nimport {\n  DataSyncClient,\n  UpdateTaskCommand,\n} from \"@aws-sdk/client-datasync\";\n\nconst datasync = new DataSyncClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nawait datasync.send(\n  new UpdateTaskCommand({\n    TaskArn: \"arn:aws:datasync:us-west-2:123456789012:task/task-0123456789abcdef0\",\n    Schedule: {\n      ScheduleExpression: \"rate(12 hours)\",\n      Status: \"ENABLED\",\n    },\n  }),\n);\n```\n\nDataSync documents a minimum schedule interval of one hour.\n\n## Important pitfalls\n\n- Use the same region for your client, locations, and task ARNs. Cross-region confusion is a common cause of empty list results and missing resources.\n- `CreateLocationS3Command` needs `S3Config.BucketAccessRoleArn`. Your application credentials are not enough by themselves for DataSync to access the bucket.\n- `CreateTaskCommand` and `StartTaskExecutionCommand` are asynchronous control-plane calls. Do not assume data has moved until `DescribeTaskExecutionCommand` reports a terminal status.\n- `Subdirectory` on S3 locations is a prefix. Do not start it with `/` or include `//`, `/./`, or `/../`.\n- Basic-mode task logging uses `CloudWatchLogGroupArn`. For Enhanced mode tasks, AWS documents that DataSync automatically publishes to the `/aws/datasync` log group.\n- If you use include or exclude filters, pass a single `SIMPLE_PATTERN` filter string with pipe delimiters instead of a long array of separate patterns.\n- If you create an Enhanced mode task, the caller needs permission to create the DataSync service-linked role.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 DataSync client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/datasync/`\n- AWS CLI DataSync reference: `https://docs.aws.amazon.com/cli/latest/reference/datasync/`\n- AWS DataSync user guide: `https://docs.aws.amazon.com/datasync/latest/userguide/what-is-datasync.html`\n- Create an S3 location: `https://docs.aws.amazon.com/datasync/latest/userguide/create-s3-location.html`\n- DataSync task mode guide: `https://docs.aws.amazon.com/datasync/latest/userguide/choosing-task-mode.html`\n- DataSync filtering guide: `https://docs.aws.amazon.com/datasync/latest/userguide/filtering.html`\n- `CreateTask` API reference: `https://docs.aws.amazon.com/datasync/latest/userguide/API_CreateTask.html`\n- `StartTaskExecution` API reference: `https://docs.aws.amazon.com/datasync/latest/userguide/API_StartTaskExecution.html`\n- `DescribeTaskExecution` API reference: `https://docs.aws.amazon.com/datasync/latest/userguide/API_DescribeTaskExecution.html`\n- `UpdateTask` API reference: `https://docs.aws.amazon.com/datasync/latest/userguide/API_UpdateTask.html`\n"
  },
  {
    "path": "content/aws/docs/deadline/javascript/DOC.md",
    "content": "---\nname: deadline\ndescription: \"AWS SDK for JavaScript v3 client for managing AWS Deadline Cloud farms, queues, fleets, jobs, steps, and tasks\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,deadline,deadline-cloud,javascript,nodejs,rendering,job-scheduling\"\n---\n\n# `@aws-sdk/client-deadline`\n\nUse `@aws-sdk/client-deadline` to manage AWS Deadline Cloud control-plane resources from JavaScript or TypeScript. The normal workflow is: find or create a farm, create queues and fleets inside that farm, associate a queue with a fleet, submit a job from a JSON or YAML template string, then inspect jobs, steps, and tasks until the render finishes.\n\nThis package talks to the Deadline Cloud API. Worker agent setup, IAM role creation, storage profiles, and the contents of your render job template are separate concerns.\n\n## Golden Rules\n\n- Set `region` deliberately. Farms, queues, fleets, and jobs are region-scoped.\n- Most operations use resource IDs such as `farmId`, `queueId`, `fleetId`, `jobId`, `stepId`, and `taskId`, not display names.\n- `CreateQueueFleetAssociationCommand` is a separate step. Creating a queue and a fleet does not connect them automatically.\n- `CreateJobCommand` requires `farmId`, `queueId`, `priority`, `template`, and `templateType`.\n- Job priority is `1` to `100`, and `1` is the highest priority.\n- List APIs use `nextToken` pagination. `SearchJobsCommand` uses `itemOffset` and `pageSize` instead.\n- The generated service model exposes paginators for list operations, but no generated waiters. Poll with `GetJobCommand` or list related resources yourself.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-deadline\n```\n\nIf you want to select a shared AWS profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-deadline@3.1007.0`.\n\n## Prerequisites And Authentication\n\nYou need AWS credentials, a region, and existing Deadline Cloud permissions for the farms and queues you want to manage. Creating queues and fleets also usually means you already have IAM roles prepared for workers and queue execution.\n\nTypical local environment variables:\n\n```bash\nexport AWS_PROFILE=\"deadline\"\nexport AWS_REGION=\"us-west-2\"\n\nexport DEADLINE_FARM_ID=\"farm-1234567890abcdef\"\nexport DEADLINE_QUEUE_ID=\"queue-1234567890abcdef\"\n\nexport DEADLINE_QUEUE_ROLE_ARN=\"arn:aws:iam::123456789012:role/DeadlineQueueRole\"\nexport DEADLINE_FLEET_ROLE_ARN=\"arn:aws:iam::123456789012:role/DeadlineFleetRole\"\n\nexport DEADLINE_ATTACHMENTS_BUCKET=\"my-deadline-attachments\"\nexport DEADLINE_JOB_TEMPLATE_JSON_PATH=\"./job-template.json\"\n```\n\nIn Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance roles.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { DeadlineClient } from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Shared profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { DeadlineClient } from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"deadline\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DeadlineClient,\n  ListFarmsCommand,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await deadline.send(\n  new ListFarmsCommand({\n    maxResults: 20,\n  }),\n);\n\nfor (const farm of response.farms ?? []) {\n  console.log(farm.farmId, farm.displayName, farm.createdAt);\n}\n```\n\n## Common Workflows\n\n### Create a farm\n\nUse a farm as the top-level container for queues, fleets, budgets, and permissions.\n\n```javascript\nimport {\n  CreateFarmCommand,\n  DeadlineClient,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst { farmId } = await deadline.send(\n  new CreateFarmCommand({\n    displayName: \"studio-main\",\n    description: \"Primary Deadline Cloud farm for production renders\",\n    tags: {\n      environment: \"production\",\n      team: \"rendering\",\n    },\n  }),\n);\n\nconsole.log(farmId);\n```\n\nThe response returns the new `farmId`. Save it, because later queue, fleet, and job calls use the ID rather than the display name.\n\n### Create a queue\n\nQueues control where jobs are submitted and can carry job attachment and run-as settings.\n\n```javascript\nimport {\n  CreateQueueCommand,\n  DeadlineClient,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst roleArn = process.env.DEADLINE_QUEUE_ROLE_ARN;\nconst bucket = process.env.DEADLINE_ATTACHMENTS_BUCKET;\n\nif (!farmId || !roleArn || !bucket) {\n  throw new Error(\"Set DEADLINE_FARM_ID, DEADLINE_QUEUE_ROLE_ARN, and DEADLINE_ATTACHMENTS_BUCKET\");\n}\n\nconst { queueId } = await deadline.send(\n  new CreateQueueCommand({\n    farmId,\n    displayName: \"linux-render-queue\",\n    description: \"Main Linux render queue\",\n    defaultBudgetAction: \"NONE\",\n    roleArn,\n    jobAttachmentSettings: {\n      s3BucketName: bucket,\n      rootPrefix: \"deadline/jobs/\",\n    },\n    jobRunAsUser: {\n      runAs: \"QUEUE_CONFIGURED_USER\",\n      posix: {\n        user: \"render\",\n        group: \"render\",\n      },\n    },\n    tags: {\n      os: \"linux\",\n    },\n  }),\n);\n\nconsole.log(queueId);\n```\n\nFor Windows workers, use the `windows` form inside `jobRunAsUser` instead of `posix`.\n\n### Create a service-managed EC2 fleet\n\nDeadline Cloud fleets can be customer-managed or service-managed. This example creates a service-managed EC2 fleet with basic Linux capability requirements.\n\n```javascript\nimport {\n  CreateFleetCommand,\n  DeadlineClient,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst roleArn = process.env.DEADLINE_FLEET_ROLE_ARN;\n\nif (!farmId || !roleArn) {\n  throw new Error(\"Set DEADLINE_FARM_ID and DEADLINE_FLEET_ROLE_ARN\");\n}\n\nconst { fleetId } = await deadline.send(\n  new CreateFleetCommand({\n    farmId,\n    displayName: \"linux-spot-fleet\",\n    description: \"Service-managed Linux fleet using spot capacity\",\n    roleArn,\n    minWorkerCount: 0,\n    maxWorkerCount: 20,\n    configuration: {\n      serviceManagedEc2: {\n        instanceCapabilities: {\n          cpuArchitectureType: \"x86_64\",\n          osFamily: \"LINUX\",\n          memoryMiB: { min: 8192 },\n          vCpuCount: { min: 4 },\n        },\n        instanceMarketOptions: {\n          type: \"spot\",\n        },\n      },\n    },\n    tags: {\n      capacity: \"spot\",\n    },\n  }),\n);\n\nconsole.log(fleetId);\n```\n\nIf you manage workers yourself, create the fleet with `configuration.customerManaged` instead.\n\n### Associate a queue with a fleet\n\nJobs will not flow from a queue to a fleet until you create the association.\n\n```javascript\nimport {\n  CreateQueueFleetAssociationCommand,\n  DeadlineClient,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst queueId = process.env.DEADLINE_QUEUE_ID;\nconst fleetId = process.env.DEADLINE_FLEET_ID;\n\nif (!farmId || !queueId || !fleetId) {\n  throw new Error(\"Set DEADLINE_FARM_ID, DEADLINE_QUEUE_ID, and DEADLINE_FLEET_ID\");\n}\n\nawait deadline.send(\n  new CreateQueueFleetAssociationCommand({\n    farmId,\n    queueId,\n    fleetId,\n  }),\n);\n```\n\n### Submit a job from a JSON template\n\n`CreateJobCommand` expects the job template as a raw string plus a `templateType` of `\"JSON\"` or `\"YAML\"`. Read the template from disk rather than trying to embed a large template inline.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  CreateJobCommand,\n  DeadlineClient,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst queueId = process.env.DEADLINE_QUEUE_ID;\nconst templatePath = process.env.DEADLINE_JOB_TEMPLATE_JSON_PATH;\n\nif (!farmId || !queueId || !templatePath) {\n  throw new Error(\"Set DEADLINE_FARM_ID, DEADLINE_QUEUE_ID, and DEADLINE_JOB_TEMPLATE_JSON_PATH\");\n}\n\nconst template = await readFile(templatePath, \"utf8\");\n\nconst { jobId } = await deadline.send(\n  new CreateJobCommand({\n    farmId,\n    queueId,\n    priority: 50,\n    template,\n    templateType: \"JSON\",\n    targetTaskRunStatus: \"READY\",\n    parameters: {\n      ShotName: { string: \"shot-010\" },\n      FrameStart: { int: \"1001\" },\n      SceneFile: { path: \"/projects/show-a/scenes/shot-010.mb\" },\n    },\n  }),\n);\n\nconsole.log(jobId);\n```\n\nThe keys under `parameters` must match parameters defined by your Deadline Cloud job template. Each parameter value is typed as exactly one of `string`, `int`, `float`, or `path`.\n\nIf you send `attachments`, the `attachments.manifests` list is required, and each manifest requires at least `rootPath` and `rootPathFormat`.\n\n### List jobs in a queue\n\n`ListJobsCommand` is the simplest way to enumerate jobs for one queue.\n\n```javascript\nimport {\n  DeadlineClient,\n  ListJobsCommand,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst queueId = process.env.DEADLINE_QUEUE_ID;\n\nif (!farmId || !queueId) {\n  throw new Error(\"Set DEADLINE_FARM_ID and DEADLINE_QUEUE_ID\");\n}\n\nlet nextToken;\n\ndo {\n  const page = await deadline.send(\n    new ListJobsCommand({\n      farmId,\n      queueId,\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const job of page.jobs ?? []) {\n    console.log(job.jobId, job.name, job.lifecycleStatus, job.taskRunStatus);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Inspect one job, then walk steps and tasks\n\nUse `GetJobCommand` for the current job state, then drill into steps and tasks.\n\n```javascript\nimport {\n  DeadlineClient,\n  GetJobCommand,\n  ListStepsCommand,\n  ListTasksCommand,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst queueId = process.env.DEADLINE_QUEUE_ID;\nconst jobId = process.env.DEADLINE_JOB_ID;\n\nif (!farmId || !queueId || !jobId) {\n  throw new Error(\"Set DEADLINE_FARM_ID, DEADLINE_QUEUE_ID, and DEADLINE_JOB_ID\");\n}\n\nconst job = await deadline.send(\n  new GetJobCommand({\n    farmId,\n    queueId,\n    jobId,\n  }),\n);\n\nconsole.log({\n  jobId: job.jobId,\n  name: job.name,\n  lifecycleStatus: job.lifecycleStatus,\n  taskRunStatus: job.taskRunStatus,\n  taskRunStatusCounts: job.taskRunStatusCounts,\n});\n\nconst { steps = [] } = await deadline.send(\n  new ListStepsCommand({\n    farmId,\n    queueId,\n    jobId,\n  }),\n);\n\nfor (const step of steps) {\n  console.log(step.stepId, step.name, step.lifecycleStatus, step.taskRunStatus);\n\n  const { tasks = [] } = await deadline.send(\n    new ListTasksCommand({\n      farmId,\n      queueId,\n      jobId,\n      stepId: step.stepId,\n    }),\n  );\n\n  for (const task of tasks) {\n    console.log(\"  \", task.taskId, task.runStatus, task.failureRetryCount ?? 0);\n  }\n}\n```\n\n### Search jobs with offset pagination\n\nUse `SearchJobsCommand` when you need the search endpoint instead of simple queue listing. Unlike the list APIs, this operation uses `itemOffset` and returns `nextItemOffset`.\n\n```javascript\nimport {\n  DeadlineClient,\n  SearchJobsCommand,\n} from \"@aws-sdk/client-deadline\";\n\nconst deadline = new DeadlineClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst farmId = process.env.DEADLINE_FARM_ID;\nconst queueId = process.env.DEADLINE_QUEUE_ID;\n\nif (!farmId || !queueId) {\n  throw new Error(\"Set DEADLINE_FARM_ID and DEADLINE_QUEUE_ID\");\n}\n\nconst page = await deadline.send(\n  new SearchJobsCommand({\n    farmId,\n    queueIds: [queueId],\n    itemOffset: 0,\n    pageSize: 25,\n  }),\n);\n\nconsole.log({\n  totalResults: page.totalResults,\n  nextItemOffset: page.nextItemOffset,\n});\n\nfor (const job of page.jobs ?? []) {\n  console.log(job.jobId, job.name, job.lifecycleStatus, job.taskRunStatus);\n}\n```\n\n## Deadline-Specific Gotchas\n\n- Save resource IDs when you create farms, queues, fleets, and jobs. Later commands use IDs, not display names.\n- Queue creation and fleet creation are not enough by themselves; you must also call `CreateQueueFleetAssociationCommand`.\n- `priority` is inverted from what many schedulers use: `1` is highest priority.\n- `template` on `CreateJobCommand` is the full template body as a string. The SDK does not load files for you.\n- `List*` operations page with `nextToken`; `SearchJobsCommand` pages with numeric offsets.\n- If you pass `attachments`, include at least one manifest, and each manifest must include `rootPath` plus `rootPathFormat` (`\"posix\"` or `\"windows\"`).\n- The service model does not define waiters for Deadline Cloud. If you need progress tracking, poll `GetJobCommand` and list steps or tasks as needed.\n- Do not hard-code long-lived AWS credentials into browser or frontend code.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared profiles, IAM Identity Center, and explicit credential selection.\n- `@aws-sdk/client-s3`: upload or manage S3 content referenced by queue job attachment settings or job manifests.\n"
  },
  {
    "path": "content/aws/docs/docdb/javascript/DOC.md",
    "content": "---\nname: docdb\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon DocumentDB clusters, instances, snapshots, and related control-plane resources.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,documentdb,docdb,javascript,nodejs,mongodb,db-cluster,db-instance\"\n---\n\n# `@aws-sdk/client-docdb`\n\nUse this package for Amazon DocumentDB with MongoDB compatibility control-plane operations in AWS SDK for JavaScript v3. It manages clusters, instances, snapshots, subnet groups, tagging, failover, start/stop, and related infrastructure settings.\n\nThis package does not run database queries against your DocumentDB endpoint. Use a MongoDB-compatible driver against the cluster endpoint for application reads and writes.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-docdb\n```\n\nIf you want explicit profile helpers in application code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites and AWS Configuration\n\nDocumentDB is regional. Configure credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\nexport DOCDB_MASTER_USERNAME=\"clusteradmin\"\nexport DOCDB_MASTER_PASSWORD=\"replace-me\"\n```\n\nIf you use a shared AWS profile locally:\n\n```bash\nexport AWS_PROFILE=\"docdb-dev\"\nexport AWS_REGION=\"us-east-1\"\n```\n\nYour IAM identity needs the DocumentDB actions required by the calls you make, such as `docdb:DescribeDBClusters`, `docdb:CreateDBCluster`, `docdb:CreateDBInstance`, `docdb:ModifyDBCluster`, and `docdb:DeleteDBCluster`.\n\nYou also need the VPC networking inputs your cluster will use:\n\n- a security group that allows the traffic you expect\n- a DB subnet group if you are not using an existing default or shared network setup\n- KMS permissions if you enable encryption with a customer-managed key\n\n## Initialize the Client\n\n### Minimal Node.js client\n\n```javascript\nimport { DocDBClient } from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { DocDBClient } from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { DocDBClient } from \"@aws-sdk/client-docdb\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst docdb = new DocDBClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"docdb-dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS access already comes from environment variables, shared config, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nconst response = await docdb.send(\n  new DescribeDBClustersCommand({\n    Filters: [{ Name: \"engine\", Values: [\"docdb\"] }],\n    MaxRecords: 20,\n  }),\n);\n\nfor (const cluster of response.DBClusters ?? []) {\n  console.log({\n    id: cluster.DBClusterIdentifier,\n    status: cluster.Status,\n    engine: cluster.Engine,\n    engineVersion: cluster.EngineVersion,\n    endpoint: cluster.Endpoint,\n    readerEndpoint: cluster.ReaderEndpoint,\n    port: cluster.Port,\n  });\n}\n```\n\n`DescribeDBClusters` supports pagination with `Marker` and `MaxRecords`.\n\n## Common Workflows\n\n### List all clusters with the paginator\n\nFor fleet inventory, prefer the generated paginator instead of manually looping on `Marker`.\n\n```javascript\nimport {\n  DocDBClient,\n  paginateDescribeDBClusters,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nfor await (const page of paginateDescribeDBClusters(\n  { client: docdb },\n  {\n    Filters: [{ Name: \"engine\", Values: [\"docdb\"] }],\n    MaxRecords: 100,\n  },\n)) {\n  for (const cluster of page.DBClusters ?? []) {\n    console.log(cluster.DBClusterIdentifier, cluster.Status);\n  }\n}\n```\n\nAWS documents the `engine=docdb` filter for cluster inventory because some management features share underlying operational technology with Amazon RDS and Amazon Neptune.\n\n### Discover supported engine versions and instance classes\n\nUse `DescribeDBEngineVersions` and `DescribeOrderableDBInstanceOptions` before hard-coding an engine version or instance class in automation.\n\n```javascript\nimport {\n  DescribeDBEngineVersionsCommand,\n  DescribeOrderableDBInstanceOptionsCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nconst versions = await docdb.send(\n  new DescribeDBEngineVersionsCommand({\n    Engine: \"docdb\",\n    DefaultOnly: true,\n  }),\n);\n\nconst engineVersion = versions.DBEngineVersions?.[0]?.EngineVersion;\n\nconst options = await docdb.send(\n  new DescribeOrderableDBInstanceOptionsCommand({\n    Engine: \"docdb\",\n    EngineVersion: engineVersion,\n    Vpc: true,\n  }),\n);\n\nfor (const option of options.OrderableDBInstanceOptions ?? []) {\n  console.log(option.DBInstanceClass, option.EngineVersion);\n}\n```\n\n### Create a cluster\n\nProvisioning normally starts with a cluster, then one or more instances attached to that cluster.\n\n```javascript\nimport {\n  CreateDBClusterCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new CreateDBClusterCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n    Engine: \"docdb\",\n    MasterUsername: process.env.DOCDB_MASTER_USERNAME,\n    MasterUserPassword: process.env.DOCDB_MASTER_PASSWORD,\n    DBSubnetGroupName: \"docdb-private-subnets\",\n    VpcSecurityGroupIds: [\"sg-0123456789abcdef0\"],\n    BackupRetentionPeriod: 7,\n    StorageEncrypted: true,\n    DeletionProtection: true,\n    Tags: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"Service\", Value: \"orders\" },\n    ],\n  }),\n);\n```\n\n### Add an instance to the cluster\n\nCreating the cluster is not the whole provisioning flow. Add at least one DB instance so the cluster can serve traffic.\n\n```javascript\nimport {\n  CreateDBInstanceCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new CreateDBInstanceCommand({\n    DBInstanceIdentifier: \"orders-prod-instance-1\",\n    DBInstanceClass: \"db.r6g.large\",\n    Engine: \"docdb\",\n    DBClusterIdentifier: \"orders-prod-cluster\",\n    AutoMinorVersionUpgrade: true,\n    Tags: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"Role\", Value: \"writer-candidate\" },\n    ],\n  }),\n);\n```\n\n### Wait until the instance is available\n\nThe client publishes instance waiters. Use them after create or delete flows when later steps require the instance to have reached a stable state.\n\n```javascript\nimport {\n  DocDBClient,\n  waitUntilDBInstanceAvailable,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait waitUntilDBInstanceAvailable(\n  {\n    client: docdb,\n    maxWaitTime: 1800,\n  },\n  {\n    DBInstanceIdentifier: \"orders-prod-instance-1\",\n  },\n);\n```\n\n### Poll until the cluster is usable\n\nThe generated waiters cover DB instances. For cluster readiness, use a describe loop and wait for the cluster status you need.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nasync function waitForClusterStatus(DBClusterIdentifier, desiredStatus) {\n  for (;;) {\n    const { DBClusters } = await docdb.send(\n      new DescribeDBClustersCommand({ DBClusterIdentifier }),\n    );\n\n    const cluster = DBClusters?.[0];\n\n    if (!cluster) {\n      throw new Error(`Cluster not found: ${DBClusterIdentifier}`);\n    }\n\n    console.log(cluster.Status);\n\n    if (cluster.Status === desiredStatus) {\n      return cluster;\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 30000));\n  }\n}\n\nconst cluster = await waitForClusterStatus(\"orders-prod-cluster\", \"available\");\n\nconsole.log(cluster.Endpoint, cluster.ReaderEndpoint, cluster.Port);\n```\n\n### Read cluster endpoints\n\nUse the cluster endpoint for the primary writer path and the reader endpoint for read-scaling scenarios.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nconst { DBClusters } = await docdb.send(\n  new DescribeDBClustersCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n  }),\n);\n\nconst cluster = DBClusters?.[0];\n\nif (!cluster) {\n  throw new Error(\"Cluster not found\");\n}\n\nconsole.log({\n  writerEndpoint: cluster.Endpoint,\n  readerEndpoint: cluster.ReaderEndpoint,\n  port: cluster.Port,\n  status: cluster.Status,\n});\n```\n\n### Stop and start a cluster\n\n`StopDBCluster` applies to a running cluster and `StartDBCluster` restarts a stopped cluster.\n\n```javascript\nimport {\n  DocDBClient,\n  StartDBClusterCommand,\n  StopDBClusterCommand,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new StopDBClusterCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n  }),\n);\n\nawait docdb.send(\n  new StartDBClusterCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n  }),\n);\n```\n\n### Force a failover\n\nUse this when you want to promote a replica to primary, or when you need to simulate failover behavior in automation tests.\n\n```javascript\nimport {\n  DocDBClient,\n  FailoverDBClusterCommand,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new FailoverDBClusterCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n    TargetDBInstanceIdentifier: \"orders-prod-instance-2\",\n  }),\n);\n```\n\n### Restore a cluster from a snapshot\n\nSnapshot restore creates a new cluster. After the restore, create at least one DB instance in the restored cluster before treating it as ready for traffic.\n\n```javascript\nimport {\n  DocDBClient,\n  RestoreDBClusterFromSnapshotCommand,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new RestoreDBClusterFromSnapshotCommand({\n    DBClusterIdentifier: \"orders-restore-cluster\",\n    SnapshotIdentifier: \"orders-prod-manual-2026-03-13\",\n    Engine: \"docdb\",\n    DBSubnetGroupName: \"docdb-private-subnets\",\n    VpcSecurityGroupIds: [\"sg-0123456789abcdef0\"],\n  }),\n);\n```\n\n### Tag a cluster or instance by ARN\n\nTagging uses the resource ARN, not the short identifier.\n\n```javascript\nimport {\n  AddTagsToResourceCommand,\n  DescribeDBClustersCommand,\n  DocDBClient,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nconst { DBClusters } = await docdb.send(\n  new DescribeDBClustersCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n  }),\n);\n\nconst clusterArn = DBClusters?.[0]?.DBClusterArn;\n\nif (!clusterArn) {\n  throw new Error(\"Cluster ARN not found\");\n}\n\nawait docdb.send(\n  new AddTagsToResourceCommand({\n    ResourceName: clusterArn,\n    Tags: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"ManagedBy\", Value: \"automation\" },\n    ],\n  }),\n);\n```\n\n### Delete an instance and then delete the cluster\n\nDelete flows are explicit. Wait for instance deletion to finish, then delete the cluster and make an intentional final-snapshot choice.\n\n```javascript\nimport {\n  DeleteDBClusterCommand,\n  DeleteDBInstanceCommand,\n  DocDBClient,\n  waitUntilDBInstanceDeleted,\n} from \"@aws-sdk/client-docdb\";\n\nconst docdb = new DocDBClient({ region: \"us-east-1\" });\n\nawait docdb.send(\n  new DeleteDBInstanceCommand({\n    DBInstanceIdentifier: \"orders-prod-instance-1\",\n  }),\n);\n\nawait waitUntilDBInstanceDeleted(\n  {\n    client: docdb,\n    maxWaitTime: 1800,\n  },\n  {\n    DBInstanceIdentifier: \"orders-prod-instance-1\",\n  },\n);\n\nawait docdb.send(\n  new DeleteDBClusterCommand({\n    DBClusterIdentifier: \"orders-prod-cluster\",\n    SkipFinalSnapshot: false,\n    FinalDBSnapshotIdentifier: `orders-prod-final-${Date.now()}`,\n  }),\n);\n```\n\nIf your workflow intentionally skips the final snapshot, set `SkipFinalSnapshot: true` instead.\n\n## Practical Notes\n\n- `CreateDBCluster` creates the cluster resource, but provisioning usually also requires `CreateDBInstance` before you have a usable writer.\n- `DescribeDBClusters` paginates with `Marker` and `MaxRecords`; do not assume one response contains the full inventory.\n- AWS documents using `Filters: [{ Name: \"engine\", Values: [\"docdb\"] }]` when listing clusters.\n- Create, restore, modify, failover, start, stop, and delete flows are asynchronous. Re-read status before assuming the resource is ready.\n- Cluster and instance endpoint fields can be absent or incomplete while provisioning, restoring, starting, stopping, or deleting.\n- `StopDBCluster` only works when the cluster is in the `available` state.\n- Temporary AWS credentials require `AWS_SESSION_TOKEN` in addition to the access key and secret key.\n- Import from the package root only. Do not deep-import package internals.\n\n## Common Pitfalls\n\n- Expecting this package to execute MongoDB wire-protocol queries.\n- Creating a cluster and then forgetting to create at least one DB instance in it.\n- Treating a successful create or restore response as proof that the endpoint is already ready for traffic.\n- Forgetting to make an explicit final-snapshot decision when deleting a cluster.\n- Reading cluster inventory without handling pagination.\n- Using the wrong region and then debugging the result as if the resource were missing.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-docdb` version `3.1007.0`.\n- AWS publishes the JavaScript SDK service docs under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for command names and request shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 DocDB client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/docdb/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n- Amazon DocumentDB stop/start guide: `https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-stop-start.html`\n- AWS SDK for JavaScript v3 DocDB client source: `https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-docdb`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-docdb`\n"
  },
  {
    "path": "content/aws/docs/dynamodb/javascript/DOC.md",
    "content": "---\nname: dynamodb\ndescription: \"AWS SDK for JavaScript v3 DynamoDB client for low-level table and item operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,dynamodb,javascript,nodejs,browser,nosql\"\n---\n\n# `@aws-sdk/client-dynamodb`\n\nUse this package for the low-level Amazon DynamoDB API in AWS SDK for JavaScript v3. It works in Node.js, browsers, and React Native, and it follows the v3 client-plus-command pattern.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-dynamodb\n```\n\nPrefer `DynamoDBClient` plus explicit command imports. The aggregated `DynamoDB` client exists for v2-style usage, but AWS documents it as a bigger-bundle compatibility path.\n\n## Initialize the client\n\n```javascript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, the SDK can use the default credential provider chain, so setting the region is often enough in application code.\n\n## Credentials and Region\n\n- Node.js: the SDK has a default credential provider chain, so credentials often come from environment variables, shared AWS config files, IAM roles, or IAM Identity Center.\n- Browser runtimes: use an explicit credential provider such as Cognito identity; do not hard-code access keys in client-side code.\n- Region is required somewhere. Set it in the client constructor, via `AWS_REGION`, or via shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Low-Level Item Model\n\nThis client uses raw DynamoDB `AttributeValue` shapes, not plain JavaScript objects.\n\n```javascript\nconst item = {\n  pk: { S: \"user#123\" },\n  sk: { S: \"profile\" },\n  age: { N: \"42\" },\n  active: { BOOL: true },\n};\n```\n\nIf you want plain-object reads and writes, use `@aws-sdk/lib-dynamodb` or `marshall`/`unmarshall` from `@aws-sdk/util-dynamodb` alongside this client.\n\n## Core Usage Pattern\n\n```javascript\nimport {\n  DynamoDBClient,\n  GetItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst response = await dynamodb.send(\n  new GetItemCommand({\n    TableName: \"Users\",\n    Key: {\n      pk: { S: \"user#123\" },\n      sk: { S: \"profile\" },\n    },\n  }),\n);\n\nconsole.log(response.Item);\n```\n\n## Common Operations\n\n### Put an item\n\n```javascript\nimport {\n  DynamoDBClient,\n  PutItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nawait dynamodb.send(\n  new PutItemCommand({\n    TableName: \"Users\",\n    Item: {\n      pk: { S: \"user#123\" },\n      sk: { S: \"profile\" },\n      email: { S: \"ada@example.com\" },\n      active: { BOOL: true },\n    },\n    ConditionExpression: \"attribute_not_exists(pk)\",\n  }),\n);\n```\n\n### Query a partition\n\n```javascript\nimport {\n  DynamoDBClient,\n  QueryCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst response = await dynamodb.send(\n  new QueryCommand({\n    TableName: \"Users\",\n    KeyConditionExpression: \"pk = :pk AND begins_with(sk, :prefix)\",\n    ExpressionAttributeValues: {\n      \":pk\": { S: \"user#123\" },\n      \":prefix\": { S: \"order#\" },\n    },\n    ScanIndexForward: false,\n    Limit: 25,\n  }),\n);\n\nconsole.log(response.Items ?? []);\n```\n\n## DynamoDB-Specific Gotchas\n\n- `@aws-sdk/client-dynamodb` is the low-level API; every `Item`, `Key`, and `ExpressionAttributeValues` entry must use DynamoDB attribute descriptors like `{ S: \"...\" }` and `{ N: \"...\" }`.\n- `Query` is for key-based access patterns. `Scan` reads the whole table or index and is usually the wrong default for application code.\n- `GetItem` returns no item on a miss; handle `response.Item` being absent.\n- `BatchWriteItem` can succeed partially and return `UnprocessedItems`; retry those instead of assuming the batch fully wrote.\n- New tables are not immediately usable after `CreateTable`; wait until the table is active before writing.\n- Prefer command imports over v2-style aggregated client usage.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/lib-dynamodb`: document client wrapper for plain JavaScript objects.\n- `@aws-sdk/util-dynamodb`: `marshall` and `unmarshall` helpers.\n- `@aws-sdk/credential-providers`: Cognito and other explicit credential providers.\n\n## Common DynamoDB Operations\n\n### Create a table\n\n```javascript\nimport {\n  CreateTableCommand,\n  DynamoDBClient,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nawait dynamodb.send(\n  new CreateTableCommand({\n    TableName: \"Users\",\n    BillingMode: \"PAY_PER_REQUEST\",\n    AttributeDefinitions: [\n      { AttributeName: \"pk\", AttributeType: \"S\" },\n      { AttributeName: \"sk\", AttributeType: \"S\" },\n    ],\n    KeySchema: [\n      { AttributeName: \"pk\", KeyType: \"HASH\" },\n      { AttributeName: \"sk\", KeyType: \"RANGE\" },\n    ],\n  }),\n);\n```\n\nTable creation is asynchronous. Do not immediately assume the table is ready for reads and writes.\n\n### Get an item\n\n```javascript\nimport {\n  DynamoDBClient,\n  GetItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst { Item } = await dynamodb.send(\n  new GetItemCommand({\n    TableName: \"Users\",\n    Key: {\n      pk: { S: \"user#123\" },\n      sk: { S: \"profile\" },\n    },\n  }),\n);\n\nif (!Item) {\n  console.log(\"not found\");\n}\n```\n\n### Update an item\n\n```javascript\nimport {\n  DynamoDBClient,\n  UpdateItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst response = await dynamodb.send(\n  new UpdateItemCommand({\n    TableName: \"Users\",\n    Key: {\n      pk: { S: \"user#123\" },\n      sk: { S: \"profile\" },\n    },\n    UpdateExpression: \"SET #name = :name, updatedAt = :updatedAt\",\n    ExpressionAttributeNames: {\n      \"#name\": \"name\",\n    },\n    ExpressionAttributeValues: {\n      \":name\": { S: \"Ada Lovelace\" },\n      \":updatedAt\": { S: new Date().toISOString() },\n    },\n    ReturnValues: \"ALL_NEW\",\n  }),\n);\n\nconsole.log(response.Attributes);\n```\n\n### Query a partition key\n\nUse `Query` when you know the partition key and optionally want to narrow by sort key.\n\n```javascript\nimport {\n  DynamoDBClient,\n  QueryCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst response = await dynamodb.send(\n  new QueryCommand({\n    TableName: \"Users\",\n    KeyConditionExpression: \"pk = :pk AND begins_with(sk, :prefix)\",\n    ExpressionAttributeValues: {\n      \":pk\": { S: \"user#123\" },\n      \":prefix\": { S: \"order#\" },\n    },\n    Limit: 25,\n  }),\n);\n\nconsole.log(response.Items ?? []);\nconsole.log(response.LastEvaluatedKey);\n```\n\nIf `LastEvaluatedKey` is present, send another `QueryCommand` with `ExclusiveStartKey` to fetch the next page.\n\n### Scan a table carefully\n\n`Scan` is a full-table or full-index read. Use it for tooling, backfills, or admin tasks more than for request-path application logic.\n\n```javascript\nimport {\n  DynamoDBClient,\n  ScanCommand,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nconst response = await dynamodb.send(\n  new ScanCommand({\n    TableName: \"Users\",\n    Limit: 25,\n    FilterExpression: \"attribute_exists(email)\",\n  }),\n);\n\nconsole.log(response.Items ?? []);\nconsole.log(response.LastEvaluatedKey);\n```\n\n### Batch write with retry handling\n\n`BatchWriteItem` can return unprocessed work even when the request itself succeeds.\n\n```javascript\nimport {\n  BatchWriteItemCommand,\n  DynamoDBClient,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nlet requestItems = {\n  Users: [\n    {\n      PutRequest: {\n        Item: {\n          pk: { S: \"user#123\" },\n          sk: { S: \"profile\" },\n        },\n      },\n    },\n    {\n      DeleteRequest: {\n        Key: {\n          pk: { S: \"user#999\" },\n          sk: { S: \"profile\" },\n        },\n      },\n    },\n  ],\n};\n\ndo {\n  const response = await dynamodb.send(\n    new BatchWriteItemCommand({\n      RequestItems: requestItems,\n    }),\n  );\n\n  requestItems = response.UnprocessedItems ?? {};\n} while (Object.keys(requestItems).length > 0);\n```\n\n## Advanced Patterns and Migration Notes\n\n### Browser credentials\n\nIn browser runtimes, do not assume the Node.js default credential provider chain exists. Use an explicit credential provider.\n\n```javascript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { fromCognitoIdentityPool } from \"@aws-sdk/credential-providers\";\n\nconst dynamodb = new DynamoDBClient({\n  region: \"us-east-1\",\n  credentials: fromCognitoIdentityPool({\n    clientConfig: { region: \"us-east-1\" },\n    identityPoolId: \"us-east-1:example-pool-id\",\n  }),\n});\n```\n\nDo not embed long-lived access keys in browser code.\n\n### Marshall and unmarshall data\n\nThis package is intentionally low-level. If your application works with normal JavaScript objects, convert them at the boundary.\n\n```javascript\nimport { DynamoDBClient, PutItemCommand } from \"@aws-sdk/client-dynamodb\";\nimport { marshall, unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nawait dynamodb.send(\n  new PutItemCommand({\n    TableName: \"Users\",\n    Item: marshall({\n      pk: \"user#123\",\n      sk: \"profile\",\n      active: true,\n      age: 42,\n    }),\n  }),\n);\n\nconst raw = {\n  pk: { S: \"user#123\" },\n  active: { BOOL: true },\n};\n\nconsole.log(unmarshall(raw));\n```\n\nFor a higher-level wrapper around the same service, use `@aws-sdk/lib-dynamodb`.\n\n### Wait for table readiness\n\nNew tables can take time to become active. If your workflow creates a table and then immediately writes to it, wait first.\n\n```javascript\nimport {\n  DynamoDBClient,\n  waitUntilTableExists,\n} from \"@aws-sdk/client-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({ region: \"us-east-1\" });\n\nawait waitUntilTableExists(\n  { client: dynamodb, maxWaitTime: 60 },\n  { TableName: \"Users\" },\n);\n```\n\n### Migration notes from `aws-sdk` v2\n\n- Replace `aws-sdk` DynamoDB usage with `@aws-sdk/client-dynamodb`.\n- Prefer `DynamoDBClient` plus explicit commands over `new AWS.DynamoDB()`.\n- Treat the aggregated client as a compatibility path, not the default import style.\n- Do not copy v2 examples that rely on callbacks or global AWS SDK configuration objects.\n- If you previously used the document client heavily, plan the migration around `@aws-sdk/lib-dynamodb` rather than hand-writing every `AttributeValue` shape.\n\n### Query and consistency notes\n\n- `Query` is the normal read path when your key design matches the access pattern.\n- `Scan` is expensive and usually reserved for maintenance flows, migrations, or admin tooling.\n- Strongly consistent reads are opt-in on supported operations such as `GetItem` and `Query`, but they are not a substitute for fixing a poor key design.\n"
  },
  {
    "path": "content/aws/docs/ec2/javascript/DOC.md",
    "content": "---\nname: ec2\ndescription: \"AWS SDK for JavaScript v3 EC2 client for managing instances and related compute resources.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,ec2,javascript,nodejs,browser,compute,instances\"\n---\n\n# `@aws-sdk/client-ec2`\n\nUse this package for the low-level Amazon EC2 API in AWS SDK for JavaScript v3. Prefer `EC2Client` plus explicit command imports for instance lifecycle, inventory, tagging, networking, and other EC2 control-plane operations.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ec2\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Initialize the client\n\n```javascript\nimport { EC2Client } from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access is already configured.\n\n## Credentials and Region\n\n- Node.js: credentials often come from environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n- Browser runtimes: use explicit browser-safe credentials such as Cognito. Direct EC2 access from the browser is uncommon and needs intentional IAM and CORS design.\n- Region is required somewhere: set it in code, via `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n`DescribeInstances` is a common read path, but remember that instances are nested under reservations.\n\n```javascript\nimport {\n  DescribeInstancesCommand,\n  EC2Client,\n} from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nconst response = await ec2.send(\n  new DescribeInstancesCommand({\n    Filters: [\n      {\n        Name: \"instance-state-name\",\n        Values: [\"running\"],\n      },\n    ],\n  }),\n);\n\nconst instances = (response.Reservations ?? []).flatMap(\n  (reservation) => reservation.Instances ?? [],\n);\n\nfor (const instance of instances) {\n  console.log(instance.InstanceId, instance.State?.Name);\n}\n```\n\nPrefer `EC2Client` plus explicit commands for most code. The package also exports an aggregated `EC2` client, but command-based imports keep dependencies and bundle size more predictable.\n\n## Common Operations\n\n### Launch an instance\n\n```javascript\nimport { EC2Client, RunInstancesCommand } from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nconst response = await ec2.send(\n  new RunInstancesCommand({\n    ImageId: \"ami-0123456789abcdef0\",\n    InstanceType: \"t3.micro\",\n    MinCount: 1,\n    MaxCount: 1,\n    SubnetId: \"subnet-0123456789abcdef0\",\n    SecurityGroupIds: [\"sg-0123456789abcdef0\"],\n    ClientToken: \"launch-web-1\",\n    TagSpecifications: [\n      {\n        ResourceType: \"instance\",\n        Tags: [\n          {\n            Key: \"Name\",\n            Value: \"web-1\",\n          },\n        ],\n      },\n    ],\n  }),\n);\n\nconsole.log(response.Instances?.[0]?.InstanceId);\n```\n\n### Stop an instance\n\n```javascript\nimport { EC2Client, StopInstancesCommand } from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nawait ec2.send(\n  new StopInstancesCommand({\n    InstanceIds: [\"i-0123456789abcdef0\"],\n  }),\n);\n```\n\n### List instances with pagination\n\n```javascript\nimport {\n  EC2Client,\n  paginateDescribeInstances,\n} from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nconst paginator = paginateDescribeInstances(\n  { client: ec2 },\n  {\n    Filters: [\n      {\n        Name: \"tag:Environment\",\n        Values: [\"prod\"],\n      },\n    ],\n  },\n);\n\nfor await (const page of paginator) {\n  for (const reservation of page.Reservations ?? []) {\n    for (const instance of reservation.Instances ?? []) {\n      console.log(instance.InstanceId);\n    }\n  }\n}\n```\n\n## EC2-Specific Gotchas\n\n- `DescribeInstances` and similar APIs return `Reservations`, then `Instances`; do not expect a flat top-level array.\n- Many mutating calls are asynchronous. After `RunInstances`, `StartInstances`, `StopInstances`, or `TerminateInstances`, wait for the state you need before assuming follow-up calls will succeed.\n- `RunInstances` requires both `MinCount` and `MaxCount`, even when launching exactly one instance.\n- Use `ClientToken` on launch flows so retries do not create duplicate instances.\n- `DryRun: true` does not return a normal success response; EC2 commonly signals permission checks through `DryRunOperation` or `UnauthorizedOperation` errors.\n- For repeated launch configuration, prefer launch templates instead of duplicating large `RunInstances` payloads.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and browser-safe credential setup.\n- `@aws-sdk/client-auto-scaling`: manage Auto Scaling groups instead of hand-rolling group behavior around individual instance launches.\n- `@aws-sdk/client-ssm`: fetch AMI IDs or configuration values from Parameter Store, or work with EC2 instances through Systems Manager workflows.\n\n## Common EC2 Operations And Waiters\n\n### Wait for a launched instance to be running\n\nEC2 launches are asynchronous. If later steps need the instance to exist in a running state, wait explicitly.\n\n```javascript\nimport {\n  EC2Client,\n  RunInstancesCommand,\n  waitUntilInstanceRunning,\n} from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nconst launch = await ec2.send(\n  new RunInstancesCommand({\n    ImageId: \"ami-0123456789abcdef0\",\n    InstanceType: \"t3.micro\",\n    MinCount: 1,\n    MaxCount: 1,\n  }),\n);\n\nconst instanceId = launch.Instances?.[0]?.InstanceId;\n\nif (!instanceId) {\n  throw new Error(\"RunInstances did not return an instance ID\");\n}\n\nawait waitUntilInstanceRunning(\n  { client: ec2, maxWaitTime: 300 },\n  { InstanceIds: [instanceId] },\n);\n```\n\n### Terminate an instance\n\n```javascript\nimport {\n  EC2Client,\n  TerminateInstancesCommand,\n} from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nawait ec2.send(\n  new TerminateInstancesCommand({\n    InstanceIds: [\"i-0123456789abcdef0\"],\n  }),\n);\n```\n\n### Add or update tags\n\nUse `CreateTagsCommand` for instances, volumes, snapshots, ENIs, and other EC2 resources that support tags.\n\n```javascript\nimport {\n  CreateTagsCommand,\n  EC2Client,\n} from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\nawait ec2.send(\n  new CreateTagsCommand({\n    Resources: [\"i-0123456789abcdef0\"],\n    Tags: [\n      {\n        Key: \"Environment\",\n        Value: \"prod\",\n      },\n      {\n        Key: \"Owner\",\n        Value: \"platform\",\n      },\n    ],\n  }),\n);\n```\n\n### Use `DryRun` to check permissions\n\nMany EC2 APIs support `DryRun`. Treat `DryRunOperation` as proof that the caller is authorized for the action.\n\n```javascript\nimport { EC2Client, StopInstancesCommand } from \"@aws-sdk/client-ec2\";\n\nconst ec2 = new EC2Client({ region: \"us-east-1\" });\n\ntry {\n  await ec2.send(\n    new StopInstancesCommand({\n      InstanceIds: [\"i-0123456789abcdef0\"],\n      DryRun: true,\n    }),\n  );\n} catch (error) {\n  if (error.name === \"DryRunOperation\") {\n    console.log(\"The caller is allowed to stop this instance.\");\n  } else if (error.name === \"UnauthorizedOperation\") {\n    console.log(\"The caller is not allowed to stop this instance.\");\n  } else {\n    throw error;\n  }\n}\n```\n\n### Notes\n\n- Waiters poll describe-style APIs and are a better default than hand-written sleep loops.\n- EC2 has eventual consistency across instance, volume, ENI, and tagging state; read-after-write flows should expect short propagation windows.\n- Launch templates are usually the right abstraction once `RunInstances` inputs become repetitive or environment-specific.\n"
  },
  {
    "path": "content/aws/docs/ecr/javascript/DOC.md",
    "content": "---\nname: ecr\ndescription: \"Amazon ECR client for JavaScript with repository management, image metadata queries, and registry auth for Docker workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,ecr,javascript,docker,containers,registry,images\"\n---\n\n# Amazon ECR JavaScript Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-ecr` for Amazon ECR private registry operations from Node.js: creating repositories, querying image metadata, updating repository settings, and getting Docker auth tokens.\n\nDo not use this package to push or pull image layers directly. Image transfer still happens through Docker or another OCI-compatible client after you authenticate. For Amazon ECR Public, use `@aws-sdk/client-ecr-public` instead.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ecr\n```\n\n## Prerequisites and AWS Configuration\n\nThe SDK uses the standard AWS credential provider chain. For local development, the simplest setup is a named profile plus an explicit region:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-west-2\n```\n\nOr set credentials directly:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_REGION=us-west-2\n```\n\nYour IAM identity needs the ECR actions required by the calls you make, such as `ecr:DescribeRepositories`, `ecr:CreateRepository`, `ecr:DescribeImages`, `ecr:GetAuthorizationToken`, `ecr:BatchDeleteImage`, and `ecr:DeleteRepository`.\n\n## Client Initialization\n\nPrefer the default provider chain unless you have a specific reason to hard-code credentials:\n\n```javascript\nimport { ECRClient } from \"@aws-sdk/client-ecr\";\n\nexport const ecr = new ECRClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nIf you need explicit credentials:\n\n```javascript\nimport { ECRClient } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({\n  region: \"us-west-2\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Common Workflows\n\n### Create a Repository\n\n```javascript\nimport { ECRClient, CreateRepositoryCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst response = await ecr.send(\n  new CreateRepositoryCommand({\n    repositoryName: \"example-app\",\n    imageTagMutability: \"IMMUTABLE\",\n  })\n);\n\nconsole.log(response.repository.repositoryName);\nconsole.log(response.repository.repositoryUri);\n```\n\n`repositoryUri` is the registry path you use with `docker tag` and `docker push`.\n\n### List Repositories\n\n```javascript\nimport { ECRClient, DescribeRepositoriesCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst page = await ecr.send(\n  new DescribeRepositoriesCommand({\n    maxResults: 100,\n  })\n);\n\nfor (const repository of page.repositories ?? []) {\n  console.log(repository.repositoryName, repository.repositoryUri);\n}\n\nconsole.log(\"nextToken:\", page.nextToken ?? null);\n```\n\nIf your account has many repositories, keep calling `DescribeRepositoriesCommand` with the returned `nextToken` until it is absent.\n\n### Inspect Image Tags and Digests\n\n```javascript\nimport { ECRClient, DescribeImagesCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst images = await ecr.send(\n  new DescribeImagesCommand({\n    repositoryName: \"example-app\",\n    maxResults: 100,\n  })\n);\n\nfor (const image of images.imageDetails ?? []) {\n  console.log({\n    digest: image.imageDigest,\n    tags: image.imageTags,\n    pushedAt: image.imagePushedAt,\n    size: image.imageSizeInBytes,\n  });\n}\n```\n\nUse image digests for deletion and deployment logic when you need an immutable identifier.\n\n### Get a Docker Login Token\n\n`GetAuthorizationTokenCommand` returns a base64-encoded `AWS:password` pair and a registry endpoint. The token is temporary, so request it close to the time you run `docker login`.\n\n```javascript\nimport { ECRClient, GetAuthorizationTokenCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst response = await ecr.send(new GetAuthorizationTokenCommand({}));\nconst auth = response.authorizationData?.[0];\n\nif (!auth?.authorizationToken || !auth.proxyEndpoint) {\n  throw new Error(\"ECR did not return authorization data\");\n}\n\nconst [username, password] = Buffer.from(auth.authorizationToken, \"base64\")\n  .toString(\"utf8\")\n  .split(\":\", 2);\n\nconst registry = auth.proxyEndpoint.replace(/^https?:\\/\\//, \"\");\n\nconsole.log({ username, password, registry });\n```\n\n### Log In to Docker from Node.js\n\n```javascript\nimport { spawn } from \"node:child_process\";\nimport { ECRClient, GetAuthorizationTokenCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nasync function dockerLoginToEcr() {\n  const response = await ecr.send(new GetAuthorizationTokenCommand({}));\n  const auth = response.authorizationData?.[0];\n\n  if (!auth?.authorizationToken || !auth.proxyEndpoint) {\n    throw new Error(\"ECR did not return authorization data\");\n  }\n\n  const [username, password] = Buffer.from(auth.authorizationToken, \"base64\")\n    .toString(\"utf8\")\n    .split(\":\", 2);\n\n  const registry = auth.proxyEndpoint.replace(/^https?:\\/\\//, \"\");\n\n  await new Promise((resolve, reject) => {\n    const child = spawn(\n      \"docker\",\n      [\"login\", \"--username\", username, \"--password-stdin\", registry],\n      { stdio: [\"pipe\", \"inherit\", \"inherit\"] }\n    );\n\n    child.on(\"error\", reject);\n    child.on(\"close\", (code) => {\n      if (code === 0) {\n        resolve();\n      } else {\n        reject(new Error(`docker login exited with code ${code}`));\n      }\n    });\n\n    child.stdin.end(password);\n  });\n\n  return registry;\n}\n\nconst registry = await dockerLoginToEcr();\nconsole.log(`Logged in to ${registry}`);\n```\n\nAfter login, tag and push with the repository URI returned by ECR:\n\n```bash\nexport ECR_REPOSITORY_URI=123456789012.dkr.ecr.us-west-2.amazonaws.com/example-app\n\ndocker build -t example-app:latest .\ndocker tag example-app:latest \"$ECR_REPOSITORY_URI:latest\"\ndocker push \"$ECR_REPOSITORY_URI:latest\"\n```\n\n### Delete Images by Tag or Digest\n\n```javascript\nimport { ECRClient, BatchDeleteImageCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nawait ecr.send(\n  new BatchDeleteImageCommand({\n    repositoryName: \"example-app\",\n    imageIds: [{ imageTag: \"old-build\" }],\n  })\n);\n\nawait ecr.send(\n  new BatchDeleteImageCommand({\n    repositoryName: \"example-app\",\n    imageIds: [{ imageDigest: \"sha256:0123456789abcdef...\" }],\n  })\n);\n```\n\nDeleting by digest is safer when tags may have moved.\n\n### Delete a Repository\n\n```javascript\nimport { ECRClient, DeleteRepositoryCommand } from \"@aws-sdk/client-ecr\";\n\nconst ecr = new ECRClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nawait ecr.send(\n  new DeleteRepositoryCommand({\n    repositoryName: \"example-app\",\n    force: true,\n  })\n);\n```\n\n`force: true` deletes all images in the repository before removing the repository itself.\n\n## Common Pitfalls\n\n- `@aws-sdk/client-ecr` is for private Amazon ECR. Public ECR uses `@aws-sdk/client-ecr-public`.\n- ECR is regional. Use the same region for the client, the repository URI, and the Docker registry login target.\n- The SDK manages repositories and auth tokens, but Docker or another OCI client still handles image push and pull.\n- `GetAuthorizationTokenCommand` returns a base64 token and a `proxyEndpoint`. Strip the `https://` prefix before passing the registry to `docker login`.\n- If you use temporary AWS credentials, include `AWS_SESSION_TOKEN` or the SDK can authenticate incorrectly even when the key and secret are present.\n- Large registries require pagination through `nextToken` on list and describe operations.\n\n## Version Notes\n\nThis guide targets `@aws-sdk/client-ecr` version `3.1007.0`.\n"
  },
  {
    "path": "content/aws/docs/ecs/javascript/DOC.md",
    "content": "---\nname: ecs\ndescription: \"AWS SDK for JavaScript v3 ECS client for clusters, services, task definitions, and task lifecycle operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,ecs,javascript,nodejs,containers,fargate\"\n---\n\n# `@aws-sdk/client-ecs`\n\nUse this package for Amazon ECS control-plane operations such as describing services, running one-off tasks, registering task definitions, and inspecting task state. It follows the AWS SDK for JavaScript v3 client-plus-command pattern.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ecs\n```\n\nPrefer `ECSClient` plus explicit command imports for application code.\n\n## Initialize the client\n\n```javascript\nimport { ECSClient } from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, the default credential provider chain is usually enough if credentials are already configured. If this code runs inside an ECS task, the SDK can also use task-role credentials exposed through the container metadata endpoint.\n\n## Credentials and Region\n\n- In Node.js, credentials can come from environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance profiles.\n- In browser runtimes, use an explicit browser-safe credential provider such as Cognito. Do not ship long-lived AWS keys in client code.\n- Region is required somewhere. Set it in code, via `AWS_REGION`, or via shared AWS config.\n- For workloads already running on ECS, prefer IAM task roles instead of injecting static credentials into the container.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nDescribe a service to inspect desired count, running count, and active deployments:\n\n```javascript\nimport {\n  DescribeServicesCommand,\n  ECSClient,\n} from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nconst { services = [], failures = [] } = await ecs.send(\n  new DescribeServicesCommand({\n    cluster: \"prod-cluster\",\n    services: [\"api\"],\n  }),\n);\n\nconsole.log(services[0]?.runningCount);\nconsole.log(services[0]?.deployments);\nconsole.log(failures);\n```\n\n## Common Operations\n\n### Run a one-off Fargate task\n\n```javascript\nimport { ECSClient, RunTaskCommand } from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nconst response = await ecs.send(\n  new RunTaskCommand({\n    cluster: \"prod-cluster\",\n    taskDefinition: \"worker:12\",\n    launchType: \"FARGATE\",\n    networkConfiguration: {\n      awsvpcConfiguration: {\n        subnets: [\"subnet-abc123\"],\n        securityGroups: [\"sg-abc123\"],\n        assignPublicIp: \"DISABLED\",\n      },\n    },\n    overrides: {\n      containerOverrides: [\n        {\n          name: \"worker\",\n          environment: [{ name: \"JOB_ID\", value: \"123\" }],\n        },\n      ],\n    },\n  }),\n);\n\nconsole.log(response.tasks?.[0]?.taskArn);\nconsole.log(response.failures);\n```\n\nCheck `failures` even when the request itself succeeds.\n\n### List and describe running tasks\n\n```javascript\nimport {\n  DescribeTasksCommand,\n  ECSClient,\n  ListTasksCommand,\n} from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nconst { taskArns = [] } = await ecs.send(\n  new ListTasksCommand({\n    cluster: \"prod-cluster\",\n    serviceName: \"api\",\n    desiredStatus: \"RUNNING\",\n  }),\n);\n\nif (taskArns.length > 0) {\n  const { tasks = [] } = await ecs.send(\n    new DescribeTasksCommand({\n      cluster: \"prod-cluster\",\n      tasks: taskArns,\n    }),\n  );\n\n  console.log(\n    tasks.map((task) => ({\n      taskArn: task.taskArn,\n      lastStatus: task.lastStatus,\n      stoppedReason: task.stoppedReason,\n    })),\n  );\n}\n```\n\n### Update a service deployment\n\n```javascript\nimport { ECSClient, UpdateServiceCommand } from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nawait ecs.send(\n  new UpdateServiceCommand({\n    cluster: \"prod-cluster\",\n    service: \"api\",\n    desiredCount: 4,\n    forceNewDeployment: true,\n  }),\n);\n```\n\nAfter `UpdateService`, poll `DescribeServicesCommand` until the deployment settles before assuming the rollout is complete.\n\n## ECS-Specific Gotchas\n\n- `RunTask`, `StartTask`, and `DescribeServices` can return `failures` alongside otherwise successful responses.\n- `ListTasks` returns task ARNs only. Use `DescribeTasks` to inspect status, container exit codes, and stop reasons.\n- Fargate tasks need a compatible task definition and a runtime `networkConfiguration` with `awsvpcConfiguration`.\n- `launchType` and `capacityProviderStrategy` are alternative scheduling modes. Do not send both in the same request.\n- Application AWS permissions belong on the task role. Image pulls, log delivery, and secret injection use the execution role.\n- ECS service changes are eventually consistent. Poll for steady state after mutating service configuration.\n- Do not deep-import package internals from build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: explicit credential flows such as Cognito, `fromIni`, and assume-role helpers.\n- `@aws-sdk/client-cloudwatch-logs`: manage log groups and log streams referenced by ECS task definitions.\n- `@aws-sdk/client-service-discovery`: manage Cloud Map namespaces and services used by ECS service discovery.\n\n## Common ECS Operations\n\n### Register a Fargate task definition\n\nUse a task definition compatible with `awsvpc` networking and Fargate sizing.\n\n```javascript\nimport {\n  ECSClient,\n  RegisterTaskDefinitionCommand,\n} from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nconst { taskDefinition } = await ecs.send(\n  new RegisterTaskDefinitionCommand({\n    family: \"api\",\n    networkMode: \"awsvpc\",\n    requiresCompatibilities: [\"FARGATE\"],\n    cpu: \"512\",\n    memory: \"1024\",\n    executionRoleArn:\n      \"arn:aws:iam::123456789012:role/ecsTaskExecutionRole\",\n    taskRoleArn: \"arn:aws:iam::123456789012:role/apiTaskRole\",\n    containerDefinitions: [\n      {\n        name: \"api\",\n        image: \"123456789012.dkr.ecr.us-east-1.amazonaws.com/api:latest\",\n        essential: true,\n        portMappings: [\n          {\n            containerPort: 3000,\n            protocol: \"tcp\",\n          },\n        ],\n        logConfiguration: {\n          logDriver: \"awslogs\",\n          options: {\n            \"awslogs-group\": \"/ecs/api\",\n            \"awslogs-region\": \"us-east-1\",\n            \"awslogs-stream-prefix\": \"ecs\",\n          },\n        },\n      },\n    ],\n  }),\n);\n\nconsole.log(taskDefinition?.taskDefinitionArn);\n```\n\n### Stop a running task\n\n```javascript\nimport { ECSClient, StopTaskCommand } from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nconst { task } = await ecs.send(\n  new StopTaskCommand({\n    cluster: \"prod-cluster\",\n    task: \"arn:aws:ecs:us-east-1:123456789012:task/prod-cluster/abc123\",\n    reason: \"manual rollback\",\n  }),\n);\n\nconsole.log(task?.lastStatus);\n```\n\nAfter a stop request, use `DescribeTasksCommand` to inspect `stoppedReason` and per-container `exitCode` values.\n\n### List services with manual pagination\n\n```javascript\nimport { ECSClient, ListServicesCommand } from \"@aws-sdk/client-ecs\";\n\nconst ecs = new ECSClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await ecs.send(\n    new ListServicesCommand({\n      cluster: \"prod-cluster\",\n      nextToken,\n      maxResults: 20,\n    }),\n  );\n\n  for (const serviceArn of page.serviceArns ?? []) {\n    console.log(serviceArn);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n"
  },
  {
    "path": "content/aws/docs/efs/javascript/DOC.md",
    "content": "---\nname: efs\ndescription: \"AWS SDK for JavaScript v3 EFS client for managing file systems, mount targets, access points, tags, and throughput settings.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,efs,filesystem,nfs,storage,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-efs`\n\nUse this package for Amazon EFS control-plane operations from JavaScript or TypeScript: create file systems, inspect state, create mount targets and access points, manage tags, and update throughput settings. It does not mount the file system itself; mounting still happens from your compute environment over NFS by using an EFS mount target or DNS name.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-efs\n```\n\n## Credentials and region\n\nThe EFS client uses the normal AWS SDK for JavaScript v3 credential chain. In Node.js, that usually means environment variables, shared AWS config files, ECS task roles, EC2 instance roles, or IAM Identity Center-backed profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\n# Or set static credentials when needed.\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\n```\n\nRegion is required somewhere. Set it in code or through `AWS_REGION`.\n\n## Initialize the client\n\n```javascript\nimport { EFSClient } from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## List and inspect file systems\n\n`DescribeFileSystems` accepts either a `FileSystemId`, a `CreationToken`, or no identifier at all.\n\nFetch one file system by ID:\n\n```javascript\nimport {\n  DescribeFileSystemsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst response = await efs.send(\n  new DescribeFileSystemsCommand({\n    FileSystemId: \"fs-0123456789abcdef0\",\n  }),\n);\n\nconst fileSystem = response.FileSystems?.[0];\n\nconsole.log(fileSystem?.FileSystemId);\nconsole.log(fileSystem?.LifeCycleState);\nconsole.log(fileSystem?.PerformanceMode);\nconsole.log(fileSystem?.ThroughputMode);\nconsole.log(fileSystem?.AvailabilityZoneName);\n```\n\nList every file system in the current region with manual pagination:\n\n```javascript\nimport {\n  DescribeFileSystemsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function listAllFileSystems() {\n  const fileSystems = [];\n  let marker;\n\n  do {\n    const page = await efs.send(\n      new DescribeFileSystemsCommand({\n        Marker: marker,\n        MaxItems: 100,\n      }),\n    );\n\n    fileSystems.push(...(page.FileSystems ?? []));\n    marker = page.NextMarker;\n  } while (marker);\n\n  return fileSystems;\n}\n\nconst fileSystems = await listAllFileSystems();\nfor (const fileSystem of fileSystems) {\n  console.log(fileSystem.FileSystemId, fileSystem.LifeCycleState);\n}\n```\n\n## Create a file system\n\nProvide your own `CreationToken` so retries stay idempotent. The file system is returned immediately in the `creating` state, so poll until it becomes `available` before creating mount targets.\n\n```javascript\nimport {\n  CreateFileSystemCommand,\n  DescribeFileSystemsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function createFileSystem() {\n  const created = await efs.send(\n    new CreateFileSystemCommand({\n      CreationToken: `shared-${Date.now()}`,\n      PerformanceMode: \"generalPurpose\",\n      ThroughputMode: \"bursting\",\n      Encrypted: true,\n      Tags: [{ Key: \"Name\", Value: \"shared-app-files\" }],\n    }),\n  );\n\n  return created.FileSystemId;\n}\n\nasync function waitForFileSystemAvailable(fileSystemId) {\n  while (true) {\n    const response = await efs.send(\n      new DescribeFileSystemsCommand({ FileSystemId: fileSystemId }),\n    );\n\n    const fileSystem = response.FileSystems?.[0];\n\n    if (!fileSystem) {\n      throw new Error(`File system not found: ${fileSystemId}`);\n    }\n\n    if (fileSystem.LifeCycleState === \"available\") {\n      return fileSystem;\n    }\n\n    if (fileSystem.LifeCycleState === \"error\" || fileSystem.LifeCycleState === \"deleted\") {\n      throw new Error(`Unexpected file system state: ${fileSystem.LifeCycleState}`);\n    }\n\n    await sleep(5000);\n  }\n}\n\nconst fileSystemId = await createFileSystem();\nconst fileSystem = await waitForFileSystemAvailable(fileSystemId);\n\nconsole.log(fileSystem.FileSystemId, fileSystem.LifeCycleState);\n```\n\nCommon create-time settings:\n\n- `PerformanceMode`: `generalPurpose` or `maxIO`. AWS recommends `generalPurpose` for most file systems, and you cannot change performance mode after creation.\n- `ThroughputMode`: `bursting`, `provisioned`, or `elastic`.\n- `ProvisionedThroughputInMibps`: required when `ThroughputMode` is `provisioned`.\n- `Encrypted` and `KmsKeyId`: use `KmsKeyId` only when you want a non-default KMS key.\n- `AvailabilityZoneName`: creates a One Zone file system; mount targets for One Zone must be created in that same Availability Zone.\n\nIf you include `Tags` during creation, the caller also needs `elasticfilesystem:TagResource` in addition to `elasticfilesystem:CreateFileSystem`.\n\n## Create a mount target\n\nCreate mount targets only after the file system is `available`. You can create one mount target per Availability Zone in a VPC. For One Zone file systems, create exactly one mount target in the file system's Availability Zone.\n\n```javascript\nimport {\n  CreateMountTargetCommand,\n  DescribeMountTargetsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function createMountTarget(fileSystemId) {\n  const created = await efs.send(\n    new CreateMountTargetCommand({\n      FileSystemId: fileSystemId,\n      SubnetId: \"subnet-0123456789abcdef0\",\n      SecurityGroups: [\"sg-0123456789abcdef0\"],\n    }),\n  );\n\n  return created.MountTargetId;\n}\n\nasync function waitForMountTargetAvailable(mountTargetId) {\n  while (true) {\n    const response = await efs.send(\n      new DescribeMountTargetsCommand({ MountTargetId: mountTargetId }),\n    );\n\n    const mountTarget = response.MountTargets?.[0];\n\n    if (!mountTarget) {\n      throw new Error(`Mount target not found: ${mountTargetId}`);\n    }\n\n    if (mountTarget.LifeCycleState === \"available\") {\n      return mountTarget;\n    }\n\n    if (mountTarget.LifeCycleState === \"error\" || mountTarget.LifeCycleState === \"deleted\") {\n      throw new Error(`Unexpected mount target state: ${mountTarget.LifeCycleState}`);\n    }\n\n    await sleep(5000);\n  }\n}\n\nconst mountTargetId = await createMountTarget(\"fs-0123456789abcdef0\");\nconst mountTarget = await waitForMountTargetAvailable(mountTargetId);\n\nconsole.log(mountTarget.MountTargetId);\nconsole.log(mountTarget.IpAddress);\nconsole.log(mountTarget.AvailabilityZoneName);\n```\n\nImportant details:\n\n- `SubnetId` determines the VPC and Availability Zone for the mount target.\n- `SecurityGroups` must belong to the same VPC as the subnet.\n- `IpAddressType` can be `IPV4_ONLY`, `IPV6_ONLY`, or `DUAL_STACK` if you need to control address family explicitly.\n- Creating a mount target also needs EC2 permissions such as `ec2:DescribeSubnets`, `ec2:DescribeNetworkInterfaces`, and `ec2:CreateNetworkInterface`.\n\n## Create an access point\n\nAccess points let you expose a specific directory and force a specific POSIX identity for requests that use that access point.\n\n```javascript\nimport {\n  CreateAccessPointCommand,\n  DescribeAccessPointsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function createAccessPoint(fileSystemId) {\n  return efs.send(\n    new CreateAccessPointCommand({\n      ClientToken: `web-${Date.now()}`,\n      FileSystemId: fileSystemId,\n      PosixUser: {\n        Uid: 1000,\n        Gid: 1000,\n      },\n      RootDirectory: {\n        Path: \"/apps/web\",\n        CreationInfo: {\n          OwnerUid: 1000,\n          OwnerGid: 1000,\n          Permissions: \"0755\",\n        },\n      },\n      Tags: [{ Key: \"Name\", Value: \"web-access\" }],\n    }),\n  );\n}\n\nconst accessPoint = await createAccessPoint(\"fs-0123456789abcdef0\");\n\nconst accessPointDetails = await efs.send(\n  new DescribeAccessPointsCommand({\n    AccessPointId: accessPoint.AccessPointId,\n  }),\n);\n\nconsole.log(accessPointDetails.AccessPoints?.[0]?.AccessPointId);\nconsole.log(accessPointDetails.AccessPoints?.[0]?.LifeCycleState);\n```\n\nImportant access-point behavior:\n\n- The access point exposes only `RootDirectory.Path` and its subdirectories to clients using that access point.\n- If `RootDirectory.Path` does not already exist, include `CreationInfo`. Without it, mounts that use the access point fail.\n- `PosixUser` overrides identity information from the NFS client for requests through the access point.\n- Tagging on access-point creation also requires `elasticfilesystem:TagResource`.\n\n## Tag resources\n\nEFS supports tagging file systems and access points.\n\n```javascript\nimport {\n  EFSClient,\n  ListTagsForResourceCommand,\n  TagResourceCommand,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait efs.send(\n  new TagResourceCommand({\n    ResourceId: \"fs-0123456789abcdef0\",\n    Tags: [\n      { Key: \"Environment\", Value: \"production\" },\n      { Key: \"Team\", Value: \"platform\" },\n    ],\n  }),\n);\n\nconst tags = await efs.send(\n  new ListTagsForResourceCommand({\n    ResourceId: \"fs-0123456789abcdef0\",\n  }),\n);\n\nconsole.log(tags.Tags ?? []);\n```\n\n## Update throughput mode\n\nYou cannot change `PerformanceMode` after creation, but you can update throughput settings.\n\n```javascript\nimport {\n  EFSClient,\n  UpdateFileSystemCommand,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait efs.send(\n  new UpdateFileSystemCommand({\n    FileSystemId: \"fs-0123456789abcdef0\",\n    ThroughputMode: \"provisioned\",\n    ProvisionedThroughputInMibps: 128,\n  }),\n);\n```\n\nWhen switching to `ThroughputMode: \"provisioned\"`, `ProvisionedThroughputInMibps` is required.\n\n## Delete resources safely\n\nDelete access points and mount targets before deleting the file system. `DeleteMountTarget` is disruptive: it forcibly breaks active mounts and returns before the mount target is fully gone.\n\n```javascript\nimport {\n  DeleteAccessPointCommand,\n  DeleteFileSystemCommand,\n  DeleteMountTargetCommand,\n  DescribeMountTargetsCommand,\n  EFSClient,\n} from \"@aws-sdk/client-efs\";\n\nconst efs = new EFSClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function deleteFileSystem(fileSystemId, accessPointIds = []) {\n  for (const accessPointId of accessPointIds) {\n    await efs.send(new DeleteAccessPointCommand({ AccessPointId: accessPointId }));\n  }\n\n  const response = await efs.send(\n    new DescribeMountTargetsCommand({ FileSystemId: fileSystemId }),\n  );\n\n  for (const mountTarget of response.MountTargets ?? []) {\n    if (mountTarget.MountTargetId) {\n      await efs.send(\n        new DeleteMountTargetCommand({\n          MountTargetId: mountTarget.MountTargetId,\n        }),\n      );\n    }\n  }\n\n  while (true) {\n    const poll = await efs.send(\n      new DescribeMountTargetsCommand({ FileSystemId: fileSystemId }),\n    );\n\n    if ((poll.MountTargets ?? []).length === 0) {\n      break;\n    }\n\n    await sleep(5000);\n  }\n\n  await efs.send(\n    new DeleteFileSystemCommand({ FileSystemId: fileSystemId }),\n  );\n}\n```\n\nIf the file system still has mount targets, `DeleteFileSystem` fails. EFS also does not let you delete a file system that is part of a replication configuration.\n\n## Common pitfalls\n\n- This package manages EFS resources; it does not perform the OS-level NFS mount.\n- Create the file system first, wait for `LifeCycleState === \"available\"`, then create mount targets.\n- Keep mount targets aligned with Availability Zones. You can create only one mount target per Availability Zone in a VPC.\n- For One Zone file systems, use the file system's `AvailabilityZoneName` or `AvailabilityZoneId` when choosing the subnet for the mount target.\n- Use your own `CreationToken` for file systems and `ClientToken` for access points when you want safe retries.\n- If an access point path might not exist yet, include `RootDirectory.CreationInfo`; otherwise the access point can be created but mounts through it fail.\n- If you tag during creation, include IAM permission for `elasticfilesystem:TagResource` as well as the create action.\n- `PerformanceMode` is fixed at create time. Only throughput settings are updatable later.\n"
  },
  {
    "path": "content/aws/docs/eks/javascript/DOC.md",
    "content": "---\nname: eks\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon EKS clusters, node groups, and add-ons\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,eks,kubernetes,containers,cluster\"\n---\n\n# AWS EKS SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-eks` to manage Amazon EKS control-plane resources from modern JavaScript and TypeScript code.\n\nThis package talks to the Amazon EKS management API. It does not replace `kubectl` or a Kubernetes client for working with Kubernetes objects inside the cluster.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-eks`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `EKSClient` plus individual command imports.\n- Treat create and update APIs as asynchronous workflows. Read status fields and follow up with `DescribeUpdateCommand` or a fresh `Describe*` call before assuming the resource is ready.\n- `DescribeClusterCommand` returns the API server endpoint and certificate authority data you need for kubeconfig generation, but those fields are only available after the cluster reaches `ACTIVE`.\n- Set `region` explicitly in code or through standard AWS config.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-eks\n```\n\nCommon companion packages:\n\n```bash\n# Shared config, Cognito, STS, and other credential helpers\nnpm install @aws-sdk/credential-providers\n\n# Kubernetes API access after you have cluster connection details\nnpm install @kubernetes/client-node\n```\n\n## Initialize the client\n\n```javascript\nimport { EKSClient } from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({\n  region: \"us-east-1\",\n});\n```\n\nFor browser runtimes, do not assume the Node.js default credential chain exists. Use explicit browser-safe credentials and verify that your IAM and network setup intentionally allows direct calls to EKS APIs.\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you already use environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n`DescribeClusterCommand` is the usual starting point when you need the cluster endpoint, certificate authority data, version, or status.\n\n```javascript\nimport {\n  DescribeClusterCommand,\n  EKSClient,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nconst response = await eks.send(\n  new DescribeClusterCommand({\n    name: \"prod-cluster\",\n  }),\n);\n\nconst cluster = response.cluster;\n\nif (!cluster) {\n  throw new Error(\"Cluster not found\");\n}\n\nconsole.log(cluster.status);\nconsole.log(cluster.endpoint);\nconsole.log(cluster.certificateAuthority?.data);\nconsole.log(cluster.version);\n```\n\n`certificateAuthority.data` is base64-encoded certificate data. Keep it as-is if you are writing kubeconfig, or decode it if a downstream tool expects PEM text.\n\n## Common Operations\n\n### List clusters with pagination\n\n```javascript\nimport {\n  EKSClient,\n  paginateListClusters,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListClusters({ client: eks }, {})) {\n  for (const clusterName of page.clusters ?? []) {\n    console.log(clusterName);\n  }\n}\n```\n\n### Read installed add-ons for a cluster\n\n```javascript\nimport {\n  EKSClient,\n  ListAddonsCommand,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nconst response = await eks.send(\n  new ListAddonsCommand({\n    clusterName: \"prod-cluster\",\n  }),\n);\n\nconsole.log(response.addons ?? []);\n```\n\n## EKS-Specific Gotchas\n\n- This client manages EKS resources such as clusters, managed node groups, add-ons, access entries, and updates. It does not manage Kubernetes resources like `Deployment` or `Service` objects.\n- `DescribeClusterCommand` uses `{ name }`, while many other operations use `{ clusterName }`. Do not assume the input field names are identical across commands.\n- The cluster endpoint and certificate authority are not available until the cluster is `ACTIVE`.\n- Managed node group and add-on updates commonly return an update record first and complete later. Track the returned update ID with `DescribeUpdateCommand`.\n- Add-on compatibility depends on the cluster's Kubernetes version. Use `DescribeAddonVersionsCommand` instead of hard-coding add-on versions.\n- Cluster creation requires existing VPC subnets, security groups, and an IAM role ARN. This package does not provision those prerequisites for you.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config helpers, Cognito, and STS-based credential flows.\n- `@kubernetes/client-node`: Kubernetes API calls after you already have cluster endpoint, certificate authority data, and authentication.\n- `@aws-sdk/client-iam`: create or inspect the IAM roles that EKS clusters and node groups need.\n- `@aws-sdk/client-ec2`: inspect or provision the VPC, subnet, and security-group resources that EKS depends on.\n\n## Common EKS Operations\n\n### List managed node groups in a cluster\n\n```javascript\nimport {\n  EKSClient,\n  ListNodegroupsCommand,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nconst response = await eks.send(\n  new ListNodegroupsCommand({\n    clusterName: \"prod-cluster\",\n  }),\n);\n\nfor (const nodegroupName of response.nodegroups ?? []) {\n  console.log(nodegroupName);\n}\n```\n\nUse `paginateListNodegroups` if you expect enough node groups to span multiple pages.\n\n### Read add-on versions compatible with a Kubernetes version\n\n```javascript\nimport {\n  DescribeAddonVersionsCommand,\n  EKSClient,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nconst response = await eks.send(\n  new DescribeAddonVersionsCommand({\n    addonName: \"vpc-cni\",\n    kubernetesVersion: \"1.31\",\n  }),\n);\n\nfor (const addon of response.addons ?? []) {\n  console.log(addon.addonName);\n\n  for (const version of addon.addonVersions ?? []) {\n    console.log(version.addonVersion, version.compatibilities);\n  }\n}\n```\n\nUse this before pinning an add-on version during upgrades.\n\n### Update a managed node group's scaling config and labels\n\n`UpdateNodegroupConfigCommand` starts an asynchronous update. The initial response includes an update record rather than fully updated node group state.\n\n```javascript\nimport {\n  EKSClient,\n  UpdateNodegroupConfigCommand,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nconst response = await eks.send(\n  new UpdateNodegroupConfigCommand({\n    clusterName: \"prod-cluster\",\n    nodegroupName: \"workers-a\",\n    scalingConfig: {\n      minSize: 2,\n      maxSize: 6,\n      desiredSize: 3,\n    },\n    labels: {\n      addOrUpdateLabels: {\n        workload: \"general\",\n      },\n    },\n  }),\n);\n\nconsole.log(response.update?.id, response.update?.status);\n```\n\n### Poll an update until it finishes\n\n```javascript\nimport {\n  DescribeUpdateCommand,\n  EKSClient,\n} from \"@aws-sdk/client-eks\";\n\nconst eks = new EKSClient({ region: \"us-east-1\" });\n\nasync function waitForNodegroupUpdate({\n  clusterName,\n  nodegroupName,\n  updateId,\n}) {\n  while (true) {\n    const response = await eks.send(\n      new DescribeUpdateCommand({\n        name: clusterName,\n        nodegroupName,\n        updateId,\n      }),\n    );\n\n    const status = response.update?.status;\n\n    if (status === \"Successful\") {\n      return response.update;\n    }\n\n    if (status === \"Failed\" || status === \"Cancelled\") {\n      throw new Error(`EKS update failed with status: ${status}`);\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 15000));\n  }\n}\n```\n\n### Notes\n\n- Many EKS operations are cluster-scoped, so keep `clusterName` available in your calling code instead of passing only ARNs around.\n- Update APIs are eventually consistent. Re-read the cluster, node group, or add-on after a successful update before depending on new fields.\n- EKS cluster creation needs existing VPC networking and IAM prerequisites; application code often combines this package with infrastructure tooling rather than creating clusters ad hoc.\n"
  },
  {
    "path": "content/aws/docs/elastic-load-balancing-v2/javascript/DOC.md",
    "content": "---\nname: elastic-load-balancing-v2\ndescription: \"AWS SDK for JavaScript v3 client for managing Application, Network, and Gateway Load Balancers, listeners, rules, and target groups.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,elastic-load-balancing,elb,alb,nlb,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-elastic-load-balancing-v2`\n\nUse this package for the low-level Elastic Load Balancing v2 control-plane API in AWS SDK for JavaScript v3. It covers Application Load Balancers (ALB), Network Load Balancers (NLB), Gateway Load Balancers (GWLB), listeners, listener rules, and target groups.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-elastic-load-balancing-v2\n```\n\nIf you want to load a named AWS profile in code instead of relying on the default provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Credentials and region\n\nThe client needs AWS credentials with permissions for the ELBv2 actions you call, plus access to related resources such as VPCs, subnets, security groups, and ACM certificates.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=... # only for temporary credentials\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access is already configured.\n\n## Initialize the client\n\n```javascript\nimport { ElasticLoadBalancingV2Client } from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nUse a named shared-config profile when needed:\n\n```javascript\nimport { ElasticLoadBalancingV2Client } from \"@aws-sdk/client-elastic-load-balancing-v2\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\n## Prerequisites for create flows\n\n- Load balancers and target groups are regional.\n- `CreateTargetGroup` needs an existing VPC.\n- `CreateLoadBalancer` needs existing subnet IDs; for an Application Load Balancer, use subnets in at least two Availability Zones.\n- Application Load Balancers also need security group IDs.\n- HTTPS listeners need an ACM certificate ARN in the same region as the load balancer.\n\n## Inspect existing load balancers\n\n```javascript\nimport {\n  DescribeLoadBalancersCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await elbv2.send(\n  new DescribeLoadBalancersCommand({\n    Names: [\"web-alb\"],\n  }),\n);\n\nfor (const loadBalancer of response.LoadBalancers ?? []) {\n  console.log({\n    arn: loadBalancer.LoadBalancerArn,\n    dnsName: loadBalancer.DNSName,\n    scheme: loadBalancer.Scheme,\n    type: loadBalancer.Type,\n    state: loadBalancer.State?.Code,\n  });\n}\n```\n\nUse `Names` when you know the resource name. For cross-account or more targeted lookups, call the same API with `LoadBalancerArns` instead.\n\n## Create a target group\n\nThis example creates an HTTP target group for instance targets.\n\n```javascript\nimport {\n  CreateTargetGroupCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst vpcId = process.env.AWS_VPC_ID;\n\nif (!vpcId) {\n  throw new Error(\"Set AWS_VPC_ID before creating a target group.\");\n}\n\nconst targetGroupResult = await elbv2.send(\n  new CreateTargetGroupCommand({\n    Name: \"web-tg\",\n    Protocol: \"HTTP\",\n    Port: 80,\n    VpcId: vpcId,\n    TargetType: \"instance\",\n    HealthCheckPath: \"/health\",\n  }),\n);\n\nconst targetGroupArn = targetGroupResult.TargetGroups?.[0]?.TargetGroupArn;\n\nif (!targetGroupArn) {\n  throw new Error(\"CreateTargetGroup did not return a target group ARN.\");\n}\n\nconsole.log(targetGroupArn);\n```\n\n`TargetType` controls what you register later. For example, `instance` expects EC2 instance IDs, while `ip` expects IP addresses.\n\n## Register targets\n\n```javascript\nimport {\n  ElasticLoadBalancingV2Client,\n  RegisterTargetsCommand,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait elbv2.send(\n  new RegisterTargetsCommand({\n    TargetGroupArn: \"arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/web-tg/0123456789abcdef\",\n    Targets: [\n      {\n        Id: \"i-0123456789abcdef0\",\n        Port: 80,\n      },\n    ],\n  }),\n);\n```\n\nThe `Targets[].Id` value must match the target group type you created.\n\n## Create an Application Load Balancer and listener\n\nThis example creates an internet-facing ALB and forwards HTTP port 80 to the target group.\n\n```javascript\nimport {\n  CreateListenerCommand,\n  CreateLoadBalancerCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst targetGroupArn = process.env.TARGET_GROUP_ARN;\nconst securityGroupIds = (process.env.AWS_SECURITY_GROUP_IDS ?? \"\")\n  .split(\",\")\n  .map((value) => value.trim())\n  .filter(Boolean);\nconst subnetIds = (process.env.AWS_SUBNET_IDS ?? \"\")\n  .split(\",\")\n  .map((value) => value.trim())\n  .filter(Boolean);\n\nif (!targetGroupArn) {\n  throw new Error(\"Set TARGET_GROUP_ARN before creating a listener.\");\n}\n\nif (securityGroupIds.length === 0) {\n  throw new Error(\"Set AWS_SECURITY_GROUP_IDS to one or more ALB security groups.\");\n}\n\nif (subnetIds.length < 2) {\n  throw new Error(\"Set AWS_SUBNET_IDS to at least two subnets for an ALB.\");\n}\n\nconst loadBalancerResult = await elbv2.send(\n  new CreateLoadBalancerCommand({\n    Name: \"web-alb\",\n    Type: \"application\",\n    Scheme: \"internet-facing\",\n    IpAddressType: \"ipv4\",\n    SecurityGroups: securityGroupIds,\n    Subnets: subnetIds,\n  }),\n);\n\nconst loadBalancerArn = loadBalancerResult.LoadBalancers?.[0]?.LoadBalancerArn;\nconst dnsName = loadBalancerResult.LoadBalancers?.[0]?.DNSName;\n\nif (!loadBalancerArn) {\n  throw new Error(\"CreateLoadBalancer did not return a load balancer ARN.\");\n}\n\nconst listenerResult = await elbv2.send(\n  new CreateListenerCommand({\n    LoadBalancerArn: loadBalancerArn,\n    Port: 80,\n    Protocol: \"HTTP\",\n    DefaultActions: [\n      {\n        Type: \"forward\",\n        TargetGroupArn: targetGroupArn,\n      },\n    ],\n  }),\n);\n\nconsole.log({\n  loadBalancerArn,\n  dnsName,\n  listenerArn: listenerResult.Listeners?.[0]?.ListenerArn,\n});\n```\n\n`CreateLoadBalancer` is asynchronous from an infrastructure perspective. After creation, poll `DescribeLoadBalancers` until `State.Code` is `active` before depending on the DNS name in automation.\n\n## Create an HTTPS listener\n\nUse an ACM certificate ARN from the same AWS region as the load balancer.\n\n```javascript\nimport {\n  CreateListenerCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst loadBalancerArn = process.env.LOAD_BALANCER_ARN;\nconst targetGroupArn = process.env.TARGET_GROUP_ARN;\nconst certificateArn = process.env.ACM_CERTIFICATE_ARN;\n\nif (!loadBalancerArn || !targetGroupArn || !certificateArn) {\n  throw new Error(\n    \"Set LOAD_BALANCER_ARN, TARGET_GROUP_ARN, and ACM_CERTIFICATE_ARN before creating an HTTPS listener.\",\n  );\n}\n\nawait elbv2.send(\n  new CreateListenerCommand({\n    LoadBalancerArn: loadBalancerArn,\n    Port: 443,\n    Protocol: \"HTTPS\",\n    Certificates: [\n      {\n        CertificateArn: certificateArn,\n      },\n    ],\n    DefaultActions: [\n      {\n        Type: \"forward\",\n        TargetGroupArn: targetGroupArn,\n      },\n    ],\n  }),\n);\n```\n\n## Check target health\n\n```javascript\nimport {\n  DescribeTargetHealthCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await elbv2.send(\n  new DescribeTargetHealthCommand({\n    TargetGroupArn: process.env.TARGET_GROUP_ARN,\n  }),\n);\n\nfor (const description of response.TargetHealthDescriptions ?? []) {\n  console.log({\n    target: description.Target?.Id,\n    port: description.Target?.Port,\n    state: description.TargetHealth?.State,\n    reason: description.TargetHealth?.Reason,\n    description: description.TargetHealth?.Description,\n  });\n}\n```\n\nThis is the quickest way to confirm whether a registered target is passing health checks and why it is failing if it is not.\n\n## Delete resources\n\nWhen cleaning up, remove listeners before deleting a target group they reference.\n\n```javascript\nimport {\n  DeleteListenerCommand,\n  DeleteLoadBalancerCommand,\n  DeleteTargetGroupCommand,\n  ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nconst elbv2 = new ElasticLoadBalancingV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nif (process.env.LISTENER_ARN) {\n  await elbv2.send(\n    new DeleteListenerCommand({\n      ListenerArn: process.env.LISTENER_ARN,\n    }),\n  );\n}\n\nif (process.env.LOAD_BALANCER_ARN) {\n  await elbv2.send(\n    new DeleteLoadBalancerCommand({\n      LoadBalancerArn: process.env.LOAD_BALANCER_ARN,\n    }),\n  );\n}\n\nif (process.env.TARGET_GROUP_ARN) {\n  await elbv2.send(\n    new DeleteTargetGroupCommand({\n      TargetGroupArn: process.env.TARGET_GROUP_ARN,\n    }),\n  );\n}\n```\n\nIf `DeleteTargetGroup` reports that the target group is still in use, wait for the load balancer or listener deletion to finish and retry.\n\n## Common pitfalls\n\n- Use the same region for the client, the load balancer, the target group, and any ACM certificate attached to an HTTPS listener.\n- For ALBs, pass security groups to `CreateLoadBalancer`; load balancer networking options differ by load balancer type.\n- Health check failures usually come from the wrong port, the wrong `HealthCheckPath`, missing security-group ingress, or targets that are not serving traffic yet.\n- `RegisterTargets` does not make a target healthy immediately; check `DescribeTargetHealth` until the target reaches a healthy state.\n- Target groups are attached by ARN in listener actions. Create the target group first, then create or update listeners that forward to it.\n"
  },
  {
    "path": "content/aws/docs/elasticache/javascript/DOC.md",
    "content": "---\nname: elasticache\ndescription: \"AWS SDK for JavaScript v3 client for Amazon ElastiCache control-plane operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,elasticache,javascript,nodejs,redis,memcached,valkey\"\n---\n\n# `@aws-sdk/client-elasticache`\n\nUse this package to manage Amazon ElastiCache infrastructure from JavaScript or TypeScript: cache clusters, replication groups, serverless caches, snapshots, subnet groups, parameter groups, service updates, and tags.\n\n## What This Package Is For\n\n- Control-plane operations only: create, modify, describe, tag, snapshot, and delete ElastiCache resources.\n- Use it for Memcached clusters, Redis OSS or Valkey replication groups, and serverless cache administration.\n- Do not use it for application cache reads and writes. Your app should connect to the cache endpoint with a Redis, Valkey, or Memcached protocol client.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-elasticache\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nPrefer `ElastiCacheClient` plus explicit command imports. The package also exposes an aggregated `ElastiCache` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Initialize the Client\n\n### Minimal Node.js client\n\n```javascript\nimport { ElastiCacheClient } from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { ElastiCacheClient } from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Credentials and Region\n\n- In Node.js, the SDK can use the default credential provider chain, so environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center are often enough.\n- Browser use requires explicit browser-safe credentials and is uncommon for ElastiCache administration flows.\n- Set the region in the client constructor, through `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n```javascript\nimport {\n  DescribeReplicationGroupsCommand,\n  ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nconst response = await elasticache.send(\n  new DescribeReplicationGroupsCommand({\n    ReplicationGroupId: \"orders-cache\",\n  }),\n);\n\nconst group = response.ReplicationGroups?.[0];\n\nconsole.log(group?.Status);\nconsole.log(\n  group?.ConfigurationEndpoint?.Address ??\n    group?.NodeGroups?.[0]?.PrimaryEndpoint?.Address,\n);\n```\n\n## Common Operations\n\n### Describe a cache cluster and inspect endpoints\n\nUse `ShowCacheNodeInfo: true` when you need per-node connection data.\n\n```javascript\nimport {\n  DescribeCacheClustersCommand,\n  ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nconst response = await elasticache.send(\n  new DescribeCacheClustersCommand({\n    CacheClusterId: \"session-cache\",\n    ShowCacheNodeInfo: true,\n  }),\n);\n\nconst cluster = response.CacheClusters?.[0];\n\nconsole.log(cluster?.CacheClusterStatus);\nconsole.log(cluster?.ConfigurationEndpoint?.Address);\n\nfor (const node of cluster?.CacheNodes ?? []) {\n  console.log(node.CacheNodeId, node.Endpoint?.Address, node.Endpoint?.Port);\n}\n```\n\n### Create a Redis OSS or Valkey replication group\n\nUse replication groups for replicated Redis OSS or Valkey topologies and failover management.\n\n```javascript\nimport {\n  CreateReplicationGroupCommand,\n  ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nconst replicationGroupId = \"orders-cache\";\n\nawait elasticache.send(\n  new CreateReplicationGroupCommand({\n    ReplicationGroupId: replicationGroupId,\n    ReplicationGroupDescription: \"Cache for the orders service\",\n    Engine: \"redis\",\n    CacheNodeType: process.env.ELASTICACHE_NODE_TYPE ?? \"cache.r6g.large\",\n    NumCacheClusters: 2,\n    AutomaticFailoverEnabled: true,\n    TransitEncryptionEnabled: true,\n    AtRestEncryptionEnabled: true,\n    SnapshotRetentionLimit: 7,\n  }),\n);\n```\n\n### Wait until a replication group is available\n\nCreate, modify, and delete operations are asynchronous. Waiters are useful when your automation needs the resource to become usable before continuing.\n\n```javascript\nimport {\n  ElastiCacheClient,\n  waitUntilReplicationGroupAvailable,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nawait waitUntilReplicationGroupAvailable(\n  {\n    client: elasticache,\n    maxWaitTime: 900,\n  },\n  {\n    ReplicationGroupId: \"orders-cache\",\n  },\n);\n```\n\n### Create a Memcached cluster\n\n`CreateCacheCluster` is the classic cluster API and is the normal entry point for Memcached.\n\n```javascript\nimport {\n  CreateCacheClusterCommand,\n  ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nawait elasticache.send(\n  new CreateCacheClusterCommand({\n    CacheClusterId: \"session-cache\",\n    Engine: \"memcached\",\n    CacheNodeType: process.env.ELASTICACHE_NODE_TYPE ?? \"cache.t4g.small\",\n    NumCacheNodes: 2,\n    AZMode: \"cross-az\",\n    Port: 11211,\n  }),\n);\n```\n\n### Create a serverless cache\n\nServerless caches have their own request and pagination model and can optionally cap storage and ECPU usage.\n\n```javascript\nimport {\n  CreateServerlessCacheCommand,\n  ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nawait elasticache.send(\n  new CreateServerlessCacheCommand({\n    ServerlessCacheName: \"api-session-cache\",\n    Description: \"Serverless cache for API sessions\",\n    Engine: \"redis\",\n    SecurityGroupIds: [\"sg-0123456789abcdef0\"],\n    SubnetIds: [\"subnet-0123456789abcdef0\", \"subnet-abcdef01234567890\"],\n    CacheUsageLimits: {\n      DataStorage: {\n        Maximum: 10,\n        Unit: \"GB\",\n      },\n      ECPUPerSecond: {\n        Maximum: 5000,\n      },\n    },\n    SnapshotRetentionLimit: 7,\n    DailySnapshotTime: \"03:00\",\n  }),\n);\n```\n\n### List replication groups with pagination\n\n```javascript\nimport {\n  ElastiCacheClient,\n  paginateDescribeReplicationGroups,\n} from \"@aws-sdk/client-elasticache\";\n\nconst elasticache = new ElastiCacheClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateDescribeReplicationGroups(\n  { client: elasticache },\n  { MaxRecords: 50 },\n)) {\n  for (const group of page.ReplicationGroups ?? []) {\n    console.log(group.ReplicationGroupId, group.Status);\n  }\n}\n```\n\n## ElastiCache-Specific Gotchas\n\n- This package manages ElastiCache resources, but it does not speak the Redis, Valkey, or Memcached wire protocols.\n- `DescribeCacheClusters` returns richer per-node endpoint data only when `ShowCacheNodeInfo` is true.\n- Memcached clusters expose a `ConfigurationEndpoint`; replication groups may expose a configuration endpoint or per-node-group primary and reader endpoints depending on topology.\n- `CreateCacheCluster` is commonly used for Memcached or single-node legacy flows. For replicated Redis OSS or Valkey deployments, prefer `CreateReplicationGroup`.\n- Classic list operations such as `DescribeCacheClusters` and `DescribeReplicationGroups` paginate with `Marker` and `MaxRecords`; serverless list operations use `NextToken` and `MaxResults`.\n- Generated waiters exist for cache clusters and replication groups, which is helpful because create, modify, and delete operations are asynchronous.\n- `DeleteServerlessCache` can create a final snapshot through `FinalSnapshotName`, and that path requires snapshot permissions.\n- Import from `@aws-sdk/client-elasticache` only. Do not deep-import package internals.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito identity, shared config helpers, assume-role flows, and other credential setup.\n- A Redis, Valkey, or Memcached client library: actual application data access after ElastiCache returns the endpoint.\n"
  },
  {
    "path": "content/aws/docs/elasticsearch-service/javascript/DOC.md",
    "content": "---\nname: elasticsearch-service\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Elasticsearch Service control-plane domain management.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,elasticsearch-service,opensearch,javascript,nodejs,search,managed-service,control-plane\"\n---\n\n# `@aws-sdk/client-elasticsearch-service`\n\nUse this package for the AWS control-plane API that manages Amazon Elasticsearch Service domains. It covers domain creation, inspection, updates, upgrades, package associations, VPC endpoint metadata, tagging, and deletion.\n\nThis is not the data-plane client for index, document, or query traffic. Use it to manage the service itself, not to call `/_search`, `/_bulk`, or other domain REST endpoints.\n\nThe package keeps the legacy `Elasticsearch...` naming because the service API is still `es` / `2015-01-01`. Some operations also refer to Amazon OpenSearch Service resources, so mixed Elasticsearch/OpenSearch naming is expected.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-elasticsearch-service\n```\n\n## Prerequisites\n\nSet a region and credentials that can manage the target domain.\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=my-aws-profile\n\n# Or use direct credentials instead of AWS_PROFILE\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=... # only for temporary credentials\n```\n\n## Client Setup\n\n```javascript\nimport { ElasticsearchServiceClient } from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you need to pass credentials explicitly:\n\n```javascript\nimport { ElasticsearchServiceClient } from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Control Plane Vs Domain Endpoint\n\nUse this package when you need to:\n\n- create or delete domains\n- inspect domain status, endpoints, or configuration\n- change instance sizing, storage, endpoint, security, or logging settings\n- manage tags, packages, upgrades, and service software updates\n\nDo not use this package for:\n\n- indexing documents\n- running searches\n- calling `/_search`, `/_bulk`, or other Elasticsearch/OpenSearch REST APIs directly\n\nFor data-plane traffic, first fetch the domain endpoint with `DescribeElasticsearchDomainCommand`, then send signed HTTP requests to `DomainStatus.Endpoint` or `DomainStatus.Endpoints.vpc`.\n\n## Common Workflows\n\n### List domains in the current account and region\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  ListDomainNamesCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new ListDomainNamesCommand({\n    EngineType: \"Elasticsearch\",\n  }),\n);\n\nfor (const domain of response.DomainNames ?? []) {\n  console.log(domain.DomainName);\n}\n```\n\n`EngineType` is optional. The API accepts `Elasticsearch` and `OpenSearch` if you want to filter mixed estates.\n\n### Describe a domain and read its endpoint\n\n```javascript\nimport {\n  DescribeElasticsearchDomainCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new DescribeElasticsearchDomainCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconst domain = response.DomainStatus;\n\nconsole.log(domain?.ARN);\nconsole.log(domain?.Endpoint ?? domain?.Endpoints?.vpc);\nconsole.log(domain?.Created);\nconsole.log(domain?.Processing);\nconsole.log(domain?.DomainProcessingStatus);\n```\n\nUse this call when you need the ARN for tagging, the endpoint for data-plane access, or the current domain processing state.\n\n### Inspect the current configuration\n\n```javascript\nimport {\n  DescribeElasticsearchDomainConfigCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new DescribeElasticsearchDomainConfigCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.DomainConfig?.ElasticsearchClusterConfig);\nconsole.log(response.DomainConfig?.EBSOptions);\nconsole.log(response.DomainConfig?.DomainEndpointOptions);\n```\n\nThis is the best call when you need the managed configuration model instead of the higher-level status summary.\n\n### Create a domain\n\n```javascript\nimport {\n  CreateElasticsearchDomainCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst accessPolicy = {\n  Version: \"2012-10-17\",\n  Statement: [\n    {\n      Effect: \"Allow\",\n      Principal: { AWS: \"arn:aws:iam::123456789012:role/search-admin\" },\n      Action: \"es:*\",\n      Resource: \"arn:aws:es:us-east-1:123456789012:domain/search-prod/*\",\n    },\n  ],\n};\n\nconst response = await es.send(\n  new CreateElasticsearchDomainCommand({\n    DomainName: \"search-prod\",\n    ElasticsearchVersion: \"7.10\",\n    ElasticsearchClusterConfig: {\n      InstanceType: \"m5.large.elasticsearch\",\n      InstanceCount: 2,\n      DedicatedMasterEnabled: true,\n      DedicatedMasterType: \"m5.large.elasticsearch\",\n      DedicatedMasterCount: 3,\n      ZoneAwarenessEnabled: true,\n      ZoneAwarenessConfig: {\n        AvailabilityZoneCount: 2,\n      },\n    },\n    EBSOptions: {\n      EBSEnabled: true,\n      VolumeType: \"gp3\",\n      VolumeSize: 100,\n    },\n    VPCOptions: {\n      SubnetIds: [\"subnet-0123456789abcdef0\", \"subnet-0fedcba9876543210\"],\n      SecurityGroupIds: [\"sg-0123456789abcdef0\"],\n    },\n    EncryptionAtRestOptions: {\n      Enabled: true,\n    },\n    NodeToNodeEncryptionOptions: {\n      Enabled: true,\n    },\n    DomainEndpointOptions: {\n      EnforceHTTPS: true,\n      TLSSecurityPolicy: \"Policy-Min-TLS-1-2-2019-07\",\n    },\n    AccessPolicies: JSON.stringify(accessPolicy),\n    TagList: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"Service\", Value: \"search\" },\n    ],\n  }),\n);\n\nconsole.log(response.DomainStatus?.ARN);\nconsole.log(response.DomainStatus?.Created);\nconsole.log(response.DomainStatus?.Processing);\n```\n\nCreate, update, upgrade, and delete operations are asynchronous. After submitting a change, poll `DescribeElasticsearchDomain` or `DescribeDomainChangeProgress` until the domain is stable.\n\n### Preview a config change with `DryRun`\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  UpdateElasticsearchDomainConfigCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst dryRun = await es.send(\n  new UpdateElasticsearchDomainConfigCommand({\n    DomainName: \"search-prod\",\n    DryRun: true,\n    ElasticsearchClusterConfig: {\n      InstanceType: \"m5.xlarge.elasticsearch\",\n      InstanceCount: 3,\n    },\n    EBSOptions: {\n      EBSEnabled: true,\n      VolumeType: \"gp3\",\n      VolumeSize: 200,\n    },\n  }),\n);\n\nconsole.log(dryRun.DryRunResults?.DeploymentType);\nconsole.log(dryRun.DryRunResults?.Message);\n```\n\n`DryRun` lets you see whether the update will use a dynamic update path or a blue/green style deployment before applying it.\n\n### Apply a config update\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  UpdateElasticsearchDomainConfigCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new UpdateElasticsearchDomainConfigCommand({\n    DomainName: \"search-prod\",\n    ElasticsearchClusterConfig: {\n      InstanceType: \"m5.xlarge.elasticsearch\",\n      InstanceCount: 3,\n    },\n    EBSOptions: {\n      EBSEnabled: true,\n      VolumeType: \"gp3\",\n      VolumeSize: 200,\n    },\n    DomainEndpointOptions: {\n      EnforceHTTPS: true,\n      TLSSecurityPolicy: \"Policy-Min-TLS-1-2-2019-07\",\n    },\n  }),\n);\n\nconsole.log(response.DomainConfig?.ElasticsearchClusterConfig?.Options);\nconsole.log(response.DomainConfig?.EBSOptions?.Options);\n```\n\n### Track a change after create or update\n\n```javascript\nimport {\n  DescribeDomainChangeProgressCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new DescribeDomainChangeProgressCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.ChangeProgressStatus?.ChangeId);\nconsole.log(response.ChangeProgressStatus?.Status);\nconsole.log(response.ChangeProgressStatus?.ConfigChangeStatus);\nconsole.log(response.ChangeProgressStatus?.PendingProperties);\n```\n\nThis is the most useful progress API when a change stays in `Processing` for a long time.\n\n### Tag and untag a domain\n\n`AddTags` and `RemoveTags` use the domain ARN, not the domain name.\n\n```javascript\nimport {\n  AddTagsCommand,\n  ElasticsearchServiceClient,\n  ListTagsCommand,\n  RemoveTagsCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\nconst arn = \"arn:aws:es:us-east-1:123456789012:domain/search-prod\";\n\nawait es.send(\n  new AddTagsCommand({\n    ARN: arn,\n    TagList: [\n      { Key: \"Team\", Value: \"platform\" },\n      { Key: \"Environment\", Value: \"prod\" },\n    ],\n  }),\n);\n\nconst listed = await es.send(new ListTagsCommand({ ARN: arn }));\nconsole.log(listed.TagList);\n\nawait es.send(\n  new RemoveTagsCommand({\n    ARN: arn,\n    TagKeys: [\"Team\"],\n  }),\n);\n```\n\n### List and associate custom packages\n\nThe package APIs are for Amazon ES packages such as `TXT-DICTIONARY` packages.\n\n```javascript\nimport {\n  AssociatePackageCommand,\n  DescribePackagesCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst packages = await es.send(\n  new DescribePackagesCommand({\n    Filters: [\n      {\n        Name: \"PackageStatus\",\n        Value: [\"AVAILABLE\"],\n      },\n    ],\n    MaxResults: 25,\n  }),\n);\n\nconst packageId = packages.PackageDetailsList?.[0]?.PackageID;\n\nif (packageId) {\n  await es.send(\n    new AssociatePackageCommand({\n      DomainName: \"search-prod\",\n      PackageID: packageId,\n    }),\n  );\n}\n```\n\nThe filter member is named `Value`, not `Values`.\n\n### List VPC endpoints attached to a domain\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  ListVpcEndpointsForDomainCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new ListVpcEndpointsForDomainCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nfor (const endpoint of response.VpcEndpointSummaryList ?? []) {\n  console.log(endpoint.VpcEndpointId, endpoint.Status, endpoint.DomainArn);\n}\n```\n\nAlthough this package is named for Elasticsearch Service, this operation describes OpenSearch Service-managed VPC endpoints.\n\n### Check upgrade targets and supported instance types\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  ListElasticsearchInstanceTypesCommand,\n  ListElasticsearchVersionsCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nlet nextToken;\ndo {\n  const versions = await es.send(\n    new ListElasticsearchVersionsCommand({\n      MaxResults: 100,\n      NextToken: nextToken,\n    }),\n  );\n\n  console.log(versions.ElasticsearchVersions ?? []);\n  nextToken = versions.NextToken;\n} while (nextToken);\n\nconst instanceTypes = await es.send(\n  new ListElasticsearchInstanceTypesCommand({\n    ElasticsearchVersion: \"7.10\",\n    DomainName: \"search-prod\",\n    MaxResults: 100,\n  }),\n);\n\nconsole.log(instanceTypes.ElasticsearchInstanceTypes ?? []);\n```\n\nUse `DomainName` when you want instance types that are valid for modifying an existing domain, not just the generic version-wide list.\n\n### Run an eligibility check before upgrading\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  UpgradeElasticsearchDomainCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst check = await es.send(\n  new UpgradeElasticsearchDomainCommand({\n    DomainName: \"search-prod\",\n    TargetVersion: \"7.10\",\n    PerformCheckOnly: true,\n  }),\n);\n\nconsole.log(check.PerformCheckOnly);\nconsole.log(check.ChangeProgressDetails?.ConfigChangeStatus);\n```\n\nAfter the eligibility check passes, submit the same command again without `PerformCheckOnly` to start the upgrade.\n\n### Start a service software update\n\n```javascript\nimport {\n  ElasticsearchServiceClient,\n  StartElasticsearchServiceSoftwareUpdateCommand,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new StartElasticsearchServiceSoftwareUpdateCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.ServiceSoftwareOptions?.CurrentVersion);\nconsole.log(response.ServiceSoftwareOptions?.NewVersion);\nconsole.log(response.ServiceSoftwareOptions?.UpdateStatus);\n```\n\n### Delete a domain\n\n```javascript\nimport {\n  DeleteElasticsearchDomainCommand,\n  ElasticsearchServiceClient,\n} from \"@aws-sdk/client-elasticsearch-service\";\n\nconst es = new ElasticsearchServiceClient({ region: \"us-east-1\" });\n\nconst response = await es.send(\n  new DeleteElasticsearchDomainCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.DomainStatus?.Deleted);\nconsole.log(response.DomainStatus?.Processing);\n```\n\nDeletion is permanent. Once the domain is deleted, its data cannot be recovered.\n\n## Practical Pitfalls\n\n- Use this package only for service management. It does not replace a signed HTTP client for search and indexing requests.\n- Keep the client region aligned with the domain region. Domain listing and management are region-scoped.\n- Expect asynchronous operations. Poll `DescribeElasticsearchDomain` and `DescribeDomainChangeProgress` after create, update, upgrade, software-update, and delete calls.\n- Pass the domain ARN to `AddTags`, `ListTags`, and `RemoveTags`; those operations do not accept `DomainName`.\n- Treat mixed naming as normal. This package still uses `Elasticsearch...` commands, but some operations expose OpenSearch-oriented fields such as `EngineType: \"OpenSearch\"` and OpenSearch-managed VPC endpoints.\n- Keep package examples small and explicit. The control-plane API has many optional nested settings, so it is safer to start from a minimal request and add only the options you actually need.\n"
  },
  {
    "path": "content/aws/docs/emr/javascript/DOC.md",
    "content": "---\nname: emr\ndescription: \"AWS SDK for JavaScript v3 client for creating, inspecting, updating, and terminating Amazon EMR clusters and steps\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,emr,javascript,nodejs,spark,hadoop,clusters\"\n---\n\n# AWS EMR SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-emr` to manage classic Amazon EMR clusters and steps from JavaScript or TypeScript.\n\nThis package is the EMR control-plane client. Use it to create clusters, inspect cluster state, add steps, and terminate clusters. It does not run Spark code locally, upload your application artifacts, or replace the tooling you use inside the cluster.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-emr`, not the legacy `aws-sdk` v2 package.\n- Prefer `EMRClient` plus individual command imports.\n- Set `region` explicitly in code or through standard AWS configuration.\n- `RunJobFlowCommand` accepts cluster creation; it does not wait for the cluster to become ready.\n- If you want to attach steps later, set `KeepJobFlowAliveWhenNoSteps: true` when you create the cluster.\n- Cluster creation depends on existing IAM roles, instance profile, subnet or networking configuration, release label, and instance sizing.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-emr\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nConfigure AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\nFor cluster creation, make sure you already have:\n\n- an EMR service role such as `EMR_DefaultRole_V2` or your own replacement\n- an EC2 instance profile for cluster nodes such as `EMR_EC2_DefaultRole` or your own replacement\n- a subnet and instance types that are valid in the target region\n- an S3 location for logs and job artifacts if your workflow depends on them\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { EMRClient } from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { EMRClient } from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { EMRClient } from \"@aws-sdk/client-emr\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst emr = new EMRClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS task roles, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nRead cluster details with `DescribeClusterCommand`.\n\n```javascript\nimport {\n  DescribeClusterCommand,\n  EMRClient,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nconst { Cluster } = await emr.send(\n  new DescribeClusterCommand({\n    ClusterId: \"j-2AXXXXXXGAPLF\",\n  }),\n);\n\nif (!Cluster) {\n  throw new Error(\"Cluster not found\");\n}\n\nconsole.log({\n  id: Cluster.Id,\n  name: Cluster.Name,\n  state: Cluster.Status?.State,\n  releaseLabel: Cluster.ReleaseLabel,\n  logUri: Cluster.LogUri,\n});\n```\n\n## Common Workflows\n\n### List active clusters with pagination\n\n```javascript\nimport {\n  EMRClient,\n  paginateListClusters,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListClusters(\n  { client: emr },\n  {\n    ClusterStates: [\"STARTING\", \"BOOTSTRAPPING\", \"RUNNING\", \"WAITING\"],\n  },\n)) {\n  for (const cluster of page.Clusters ?? []) {\n    console.log(cluster.Id, cluster.Name, cluster.Status?.State);\n  }\n}\n```\n\nUse `ClusterStates` to limit the results you page through. That is usually better than listing every terminated cluster in the account and filtering later.\n\n### Create a cluster\n\n`RunJobFlowCommand` starts cluster creation. A successful response means EMR accepted the request, not that the cluster is ready for steps yet.\n\n```javascript\nimport {\n  EMRClient,\n  RunJobFlowCommand,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nconst { JobFlowId } = await emr.send(\n  new RunJobFlowCommand({\n    Name: \"analytics-dev\",\n    ReleaseLabel: \"emr-7.0.0\",\n    LogUri: \"s3://my-emr-logs/\",\n    ServiceRole: \"EMR_DefaultRole_V2\",\n    JobFlowRole: \"EMR_EC2_DefaultRole\",\n    Instances: {\n      Ec2SubnetId: \"subnet-0123456789abcdef0\",\n      KeepJobFlowAliveWhenNoSteps: true,\n      InstanceGroups: [\n        {\n          Name: \"Primary\",\n          InstanceRole: \"MASTER\",\n          InstanceType: \"m5.xlarge\",\n          InstanceCount: 1,\n          Market: \"ON_DEMAND\",\n        },\n        {\n          Name: \"Core\",\n          InstanceRole: \"CORE\",\n          InstanceType: \"m5.xlarge\",\n          InstanceCount: 2,\n          Market: \"ON_DEMAND\",\n        },\n      ],\n    },\n    Applications: [{ Name: \"Spark\" }],\n    VisibleToAllUsers: true,\n  }),\n);\n\nconsole.log(JobFlowId);\n```\n\nReplace the role names, subnet ID, log bucket, release label, and instance types with values that exist in your account and region.\n\n### Poll cluster state until it is usable\n\nFor step-based workflows, a common target state is `WAITING`. Some automation may also treat `RUNNING` as ready depending on how the cluster was created.\n\n```javascript\nimport {\n  DescribeClusterCommand,\n  EMRClient,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nasync function waitForCluster(clusterId) {\n  for (;;) {\n    const { Cluster } = await emr.send(\n      new DescribeClusterCommand({\n        ClusterId: clusterId,\n      }),\n    );\n\n    const state = Cluster?.Status?.State;\n    console.log(state);\n\n    if (state === \"WAITING\" || state === \"RUNNING\") {\n      return Cluster;\n    }\n\n    if (state === \"TERMINATED\" || state === \"TERMINATED_WITH_ERRORS\") {\n      throw new Error(`Cluster failed with state ${state}`);\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 30000));\n  }\n}\n```\n\n### Add a Spark step to an existing cluster\n\nUse `AddJobFlowStepsCommand` to submit work to a cluster that is already running.\n\n```javascript\nimport {\n  AddJobFlowStepsCommand,\n  EMRClient,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nconst { StepIds } = await emr.send(\n  new AddJobFlowStepsCommand({\n    JobFlowId: \"j-2AXXXXXXGAPLF\",\n    Steps: [\n      {\n        Name: \"daily-spark-job\",\n        ActionOnFailure: \"CANCEL_AND_WAIT\",\n        HadoopJarStep: {\n          Jar: \"command-runner.jar\",\n          Args: [\n            \"spark-submit\",\n            \"s3://my-emr-jobs/jobs/daily-etl.py\",\n            \"--input\",\n            \"s3://my-data/input/2026-03-13/\",\n            \"--output\",\n            \"s3://my-data/output/2026-03-13/\",\n          ],\n        },\n      },\n    ],\n  }),\n);\n\nconsole.log(StepIds?.[0]);\n```\n\nThe SDK sends the step definition to EMR. It does not upload your script, dependencies, or data. Store those in S3 or another location your cluster can already access.\n\n### Poll a step until completion\n\n```javascript\nimport {\n  DescribeStepCommand,\n  EMRClient,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nasync function waitForStep(clusterId, stepId) {\n  for (;;) {\n    const { Step } = await emr.send(\n      new DescribeStepCommand({\n        ClusterId: clusterId,\n        StepId: stepId,\n      }),\n    );\n\n    const state = Step?.Status?.State;\n    console.log(state);\n\n    if (state === \"COMPLETED\") {\n      return Step;\n    }\n\n    if (\n      state === \"CANCELLED\" ||\n      state === \"FAILED\" ||\n      state === \"INTERRUPTED\"\n    ) {\n      throw new Error(`Step failed with state ${state}`);\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 15000));\n  }\n}\n```\n\n### Protect or terminate a cluster\n\nUse termination protection when you want to block accidental shutdown, and remove it before you intentionally delete the cluster.\n\n```javascript\nimport {\n  EMRClient,\n  SetTerminationProtectionCommand,\n  TerminateJobFlowsCommand,\n} from \"@aws-sdk/client-emr\";\n\nconst emr = new EMRClient({ region: \"us-east-1\" });\n\nawait emr.send(\n  new SetTerminationProtectionCommand({\n    JobFlowIds: [\"j-2AXXXXXXGAPLF\"],\n    TerminationProtected: false,\n  }),\n);\n\nawait emr.send(\n  new TerminateJobFlowsCommand({\n    JobFlowIds: [\"j-2AXXXXXXGAPLF\"],\n  }),\n);\n```\n\n`TerminateJobFlowsCommand` starts termination asynchronously. Use `DescribeClusterCommand` if your automation needs to wait until the cluster is actually gone.\n\n## Practical Notes\n\n- This client manages classic EMR clusters and steps. It does not cover every EMR-adjacent service surface.\n- The request field names are not fully uniform across operations. Cluster reads use `ClusterId`, step submission uses `JobFlowId`, and termination protection or cluster termination use `JobFlowIds`.\n- `JobFlowRole` is the EC2 instance profile for cluster nodes. It is not the same field as `ServiceRole`.\n- If you create a cluster with `KeepJobFlowAliveWhenNoSteps: false`, EMR can terminate it after the submitted steps finish, which prevents later `AddJobFlowStepsCommand` calls.\n- `ActionOnFailure` controls what EMR does after a step fails. Choose the behavior intentionally for unattended pipelines.\n- If you set `LogUri`, the target S3 bucket or prefix must already be writable by the cluster.\n\n## Common Pitfalls\n\n- Treating a successful `RunJobFlowCommand` response as proof that the cluster is ready.\n- Reusing example default role names when your account uses custom IAM roles or instance profiles.\n- Mixing `ClusterId`, `JobFlowId`, and `JobFlowIds` across commands.\n- Adding steps to a cluster that was not configured to stay alive after earlier work completed.\n- Assuming the SDK uploads your Spark script or JAR automatically.\n- Forgetting that EMR is regional and then looking for clusters in the wrong region.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-emr@3.1007.0`.\n- The AWS SDK for JavaScript v3 service reference is published under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for operation names and request shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 EMR client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/emr/`\n- Amazon EMR API Reference: `https://docs.aws.amazon.com/emr/latest/APIReference/Welcome.html`\n- Amazon EMR `RunJobFlow` API: `https://docs.aws.amazon.com/emr/latest/APIReference/API_RunJobFlow.html`\n- Amazon EMR `AddJobFlowSteps` API: `https://docs.aws.amazon.com/emr/latest/APIReference/API_AddJobFlowSteps.html`\n- Amazon EMR `DescribeCluster` API: `https://docs.aws.amazon.com/emr/latest/APIReference/API_DescribeCluster.html`\n- Amazon EMR `DescribeStep` API: `https://docs.aws.amazon.com/emr/latest/APIReference/API_DescribeStep.html`\n- Amazon EMR `TerminateJobFlows` API: `https://docs.aws.amazon.com/emr/latest/APIReference/API_TerminateJobFlows.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/entityresolution/javascript/DOC.md",
    "content": "---\nname: entityresolution\ndescription: \"AWS SDK for JavaScript v3 Entity Resolution client for schema mappings, matching workflows, match lookups, and job execution.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,entityresolution,javascript,nodejs,identity,matching,glue,s3\"\n---\n\n# `@aws-sdk/client-entityresolution`\n\nUse this package for Amazon Entity Resolution from JavaScript or TypeScript code. It covers schema mappings, matching workflows, matching jobs, match ID lookups, ID generation, provider integrations, tagging, and related control-plane APIs.\n\nPrefer `EntityResolutionClient` plus explicit command imports for new code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-entityresolution\n```\n\nIf you want explicit profile, IAM Identity Center, or assume-role credential resolution in application code, install the credential helpers you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nEntity Resolution workflows depend on other AWS resources. For a typical rule-based workflow, have these ready before you call the SDK:\n\n- An AWS region where you will create the schema mapping and workflow.\n- A source table ARN for your input data. In common setups this is an AWS Glue table ARN.\n- An S3 path for workflow output.\n- An IAM role ARN that Entity Resolution can assume for workflow execution.\n- Optional: a customer KMS key ARN if you do not want to use the service-managed key for output encryption.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\"\n\nexport CUSTOMER_GLUE_TABLE_ARN=\"arn:aws:glue:us-east-1:123456789012:table/customerdb/customers\"\nexport ENTITYRESOLUTION_ROLE_ARN=\"arn:aws:iam::123456789012:role/entityresolution-workflow-role\"\nexport ENTITYRESOLUTION_OUTPUT_S3=\"s3://my-entityresolution-output/customer-dedup/\"\n```\n\nOr with direct credentials:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nIn Node.js, the default AWS SDK credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { EntityResolutionClient } from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit profile-based credentials\n\n```javascript\nimport { EntityResolutionClient } from \"@aws-sdk/client-entityresolution\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  EntityResolutionClient,\n  ListMatchingWorkflowsCommand,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await entityResolution.send(\n  new ListMatchingWorkflowsCommand({\n    maxResults: 25,\n  }),\n);\n\nfor (const workflow of response.workflowSummaries ?? []) {\n  console.log(workflow.workflowName, workflow.resolutionType);\n}\n```\n\n## Common Workflows\n\n### Create a schema mapping\n\nCreate the schema mapping before you create a matching workflow. Each mapped input field describes a source column, its attribute type, and whether it participates in matching.\n\n```javascript\nimport {\n  CreateSchemaMappingCommand,\n  EntityResolutionClient,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst schema = await entityResolution.send(\n  new CreateSchemaMappingCommand({\n    schemaName: \"customers-v1\",\n    description: \"Customer table for rule-based matching\",\n    mappedInputFields: [\n      {\n        fieldName: \"first_name\",\n        type: \"NAME_FIRST\",\n        groupName: \"NAME\",\n        matchKey: \"name\",\n      },\n      {\n        fieldName: \"last_name\",\n        type: \"NAME_LAST\",\n        groupName: \"NAME\",\n        matchKey: \"name\",\n      },\n      {\n        fieldName: \"email\",\n        type: \"EMAIL_ADDRESS\",\n        matchKey: \"email\",\n      },\n      {\n        fieldName: \"phone\",\n        type: \"PHONE_NUMBER\",\n        matchKey: \"phone\",\n      },\n      {\n        fieldName: \"customer_id\",\n        type: \"UNIQUE_ID\",\n      },\n    ],\n  }),\n);\n\nconsole.log(schema.schemaArn);\n```\n\nImportant details from the API model:\n\n- `mappedInputFields` requires at least 2 fields and allows up to 35.\n- If you omit `matchKey` for a column, that field is not used for matching, but it can still appear in output.\n- Normalization only applies to `NAME`, `ADDRESS`, `PHONE`, and `EMAIL_ADDRESS` groups.\n- If your source splits names across `NAME_FIRST`, `NAME_MIDDLE`, and `NAME_LAST`, assign the same `groupName`, such as `NAME`, so Entity Resolution can treat them as one normalized value.\n\n### Read a schema mapping back\n\n```javascript\nimport {\n  EntityResolutionClient,\n  GetSchemaMappingCommand,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst schema = await entityResolution.send(\n  new GetSchemaMappingCommand({\n    schemaName: \"customers-v1\",\n  }),\n);\n\nconsole.log(schema.schemaName);\nconsole.log(schema.mappedInputFields?.map((field) => [field.fieldName, field.type]));\n```\n\n### Create a rule-based matching workflow\n\nThis is the most direct workflow to automate from application or internal tooling. The workflow points at your input source, writes results to S3, and defines matching rules using the `matchKey` names from the schema mapping.\n\n```javascript\nimport {\n  CreateMatchingWorkflowCommand,\n  EntityResolutionClient,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst workflow = await entityResolution.send(\n  new CreateMatchingWorkflowCommand({\n    workflowName: \"customer-dedup-v1\",\n    description: \"Rule-based customer deduplication\",\n    inputSourceConfig: [\n      {\n        inputSourceARN: process.env.CUSTOMER_GLUE_TABLE_ARN,\n        schemaName: \"customers-v1\",\n        applyNormalization: true,\n      },\n    ],\n    outputSourceConfig: [\n      {\n        outputS3Path: process.env.ENTITYRESOLUTION_OUTPUT_S3,\n        output: [\n          { name: \"customer_id\", hashed: false },\n          { name: \"first_name\", hashed: false },\n          { name: \"last_name\", hashed: false },\n          { name: \"email\", hashed: true },\n          { name: \"phone\", hashed: true },\n        ],\n        applyNormalization: true,\n      },\n    ],\n    resolutionTechniques: {\n      resolutionType: \"RULE_MATCHING\",\n      ruleBasedProperties: {\n        rules: [\n          {\n            ruleName: \"email-exact\",\n            matchingKeys: [\"email\"],\n          },\n          {\n            ruleName: \"name-and-phone\",\n            matchingKeys: [\"name\", \"phone\"],\n          },\n        ],\n        attributeMatchingModel: \"MANY_TO_MANY\",\n        matchPurpose: \"IDENTIFIER_GENERATION\",\n      },\n    },\n    incrementalRunConfig: {\n      incrementalRunType: \"IMMEDIATE\",\n    },\n    roleArn: process.env.ENTITYRESOLUTION_ROLE_ARN,\n  }),\n);\n\nconsole.log(workflow.workflowArn);\n```\n\nKey inputs to understand:\n\n- `inputSourceConfig[].inputSourceARN` is commonly a Glue table ARN.\n- `outputSourceConfig[].output[].name` must be an input field name from the schema mapping.\n- `matchingKeys` refer to `matchKey` values from the schema mapping, not raw column names unless you used the same strings for both.\n- `attributeMatchingModel: \"ONE_TO_ONE\"` only matches exact sub-type pairs. `\"MANY_TO_MANY\"` allows matching across sub-types of the same attribute type.\n- `matchPurpose: \"IDENTIFIER_GENERATION\"` generates match IDs and indexes the data. `\"INDEXING\"` indexes without generating IDs.\n\n### Start a matching job and poll until completion\n\n`StartMatchingJobCommand` returns a job ID. Poll `GetMatchingJobCommand` until the status becomes `SUCCEEDED` or `FAILED`.\n\n```javascript\nimport {\n  EntityResolutionClient,\n  GetMatchingJobCommand,\n  StartMatchingJobCommand,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst start = await entityResolution.send(\n  new StartMatchingJobCommand({\n    workflowName: \"customer-dedup-v1\",\n  }),\n);\n\nconst jobId = start.jobId;\n\nif (!jobId) {\n  throw new Error(\"Entity Resolution did not return a job ID\");\n}\n\nlet status = \"QUEUED\";\n\nwhile (status === \"QUEUED\" || status === \"RUNNING\") {\n  const job = await entityResolution.send(\n    new GetMatchingJobCommand({\n      workflowName: \"customer-dedup-v1\",\n      jobId,\n    }),\n  );\n\n  status = job.status ?? \"FAILED\";\n\n  console.log({\n    status,\n    metrics: job.metrics,\n  });\n\n  if (status === \"FAILED\") {\n    throw new Error(job.errorDetails?.errorMessage ?? \"Matching job failed\");\n  }\n\n  if (status !== \"SUCCEEDED\") {\n    await sleep(5000);\n  }\n}\n```\n\n`GetMatchingJobCommand` returns metrics including input records, total processed records, records not processed, delete records processed, and generated match IDs.\n\n### Look up a single match ID for a rule-based workflow\n\nUse `GetMatchIdCommand` when you want the corresponding match ID for one record against an existing rule-based workflow. The API reference describes this as a dry run of an incremental load.\n\n```javascript\nimport {\n  EntityResolutionClient,\n  GetMatchIdCommand,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await entityResolution.send(\n  new GetMatchIdCommand({\n    workflowName: \"customer-dedup-v1\",\n    record: {\n      first_name: \"Alice\",\n      last_name: \"Ng\",\n      email: \"alice@example.com\",\n      phone: \"1234567890\",\n    },\n    applyNormalization: true,\n  }),\n);\n\nconsole.log(result.matchId, result.matchRule);\n```\n\nThe `record` map uses your source field names. If you enable `applyNormalization`, Entity Resolution normalizes supported field groups before evaluating the rule-based workflow.\n\n### Generate or retrieve a match ID for one record\n\nUse `GenerateMatchIdCommand` when you want Entity Resolution to process one record against a rule-based workflow and return grouped results directly. The API accepts exactly one record per call and also saves results to S3.\n\n```javascript\nimport {\n  EntityResolutionClient,\n  GenerateMatchIdCommand,\n} from \"@aws-sdk/client-entityresolution\";\n\nconst entityResolution = new EntityResolutionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await entityResolution.send(\n  new GenerateMatchIdCommand({\n    workflowName: \"customer-dedup-v1\",\n    records: [\n      {\n        inputSourceARN: process.env.CUSTOMER_GLUE_TABLE_ARN,\n        uniqueId: \"customer-123\",\n        recordAttributeMap: {\n          first_name: \"Alice\",\n          last_name: \"Ng\",\n          email: \"alice@example.com\",\n          phone: \"1234567890\",\n        },\n      },\n    ],\n    processingType: \"CONSISTENT\",\n  }),\n);\n\nconsole.log(result.matchGroups);\nconsole.log(result.failedRecords);\n```\n\n`processingType` controls the trade-off between accuracy and speed:\n\n- `CONSISTENT` does immediate lookup and matching against all existing records, with synchronous results. This is the default.\n- `EVENTUAL` returns an initial result quickly, then finishes updates asynchronously in the background.\n- `EVENTUAL_NO_LOOKUP` generates new match IDs without checking existing matches first. Use it only when you already know the incoming record is unique.\n\n## Common Pitfalls\n\n- Rule-based workflow rules match on `matchKey` values from the schema mapping. If a source field has no `matchKey`, it is not used for matching.\n- `applyNormalization` only helps for supported attribute groups. Split name and address fields need the correct shared `groupName` if you want normalized grouping behavior.\n- `incrementalRunConfig` only supports `IMMEDIATE`, and incremental processing is not supported for `ML_MATCHING` or `PROVIDER` workflows.\n- `GenerateMatchIdCommand` accepts a single record per call. It is not a batch backfill API.\n- `StartMatchingJobCommand` starts the workflow run, but you still need to poll `GetMatchingJobCommand` for `QUEUED`, `RUNNING`, `SUCCEEDED`, or `FAILED`.\n- If you specify `outputSourceConfig[].output[].name`, those names must already exist in the schema mapping.\n\n## Related Packages\n\n- `@aws-sdk/credential-providers`: explicit profile, IAM Identity Center, and assume-role credential flows.\n- `@aws-sdk/client-glue`: inspect or manage the Glue tables you use as input sources.\n- `@aws-sdk/client-s3`: manage the buckets and prefixes where matching workflow results are written.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-entityresolution` version `3.1007.0`.\n- The current Entity Resolution API surface includes schema mappings, matching workflows, matching jobs, ID mapping workflows, ID namespaces, provider services, policy operations, and tagging commands.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Entity Resolution client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/entityresolution/`\n- Amazon Entity Resolution API Reference: `https://docs.aws.amazon.com/entityresolution/latest/apireference/Welcome.html`\n- Amazon Entity Resolution User Guide: `https://docs.aws.amazon.com/entityresolution/latest/userguide/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 source package: `https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-entityresolution`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-entityresolution`\n"
  },
  {
    "path": "content/aws/docs/eventbridge/javascript/DOC.md",
    "content": "---\nname: eventbridge\ndescription: \"AWS SDK for JavaScript v3 EventBridge client for publishing events and managing buses, rules, and targets.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,eventbridge,javascript,nodejs,events,event-bus,rules\"\n---\n\n# `@aws-sdk/client-eventbridge`\n\nUse this package for Amazon EventBridge in AWS SDK for JavaScript v3. It covers two common jobs:\n\n- publish application events to an event bus\n- manage EventBridge resources such as event buses, rules, and rule targets\n\nPrefer `EventBridgeClient` plus explicit command imports for new code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-eventbridge\n```\n\nIf you need non-default credential providers in application code, install the credential helper package you actually use:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nEventBridge is regional. Configure AWS credentials and a region before you create the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { EventBridgeClient } from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { EventBridgeClient } from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access is already configured through environment variables, shared config, ECS, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeRuleCommand,\n  EventBridgeClient,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\n\nconst response = await eventbridge.send(\n  new DescribeRuleCommand({\n    Name: \"route-order-created\",\n    EventBusName: \"default\",\n  }),\n);\n\nconsole.log(response.Name, response.State, response.EventPattern);\n```\n\n## Common Workflows\n\n### Publish a custom event\n\n`PutEventsCommand` sends one or more entries to EventBridge. For custom application events, `Detail` must be a JSON string.\n\n```javascript\nimport {\n  EventBridgeClient,\n  PutEventsCommand,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\n\nconst response = await eventbridge.send(\n  new PutEventsCommand({\n    Entries: [\n      {\n        Source: \"com.example.orders\",\n        DetailType: \"order.created\",\n        Detail: JSON.stringify({\n          orderId: \"ord_123\",\n          customerId: \"cus_456\",\n          total: 4200,\n        }),\n        EventBusName: \"default\",\n      },\n    ],\n  }),\n);\n\nif ((response.FailedEntryCount ?? 0) > 0) {\n  throw new Error(JSON.stringify(response.Entries));\n}\n```\n\nIf you publish to a custom bus, set `EventBusName` to that bus name or ARN consistently in your publishers and rules.\n\n### Create or update a rule with an event pattern\n\n`PutRuleCommand` creates a new rule or updates an existing rule with the same name. `EventPattern` is a JSON string, not a JavaScript object.\n\n```javascript\nimport {\n  EventBridgeClient,\n  PutRuleCommand,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\n\nconst eventPattern = JSON.stringify({\n  source: [\"com.example.orders\"],\n  \"detail-type\": [\"order.created\"],\n});\n\nconst response = await eventbridge.send(\n  new PutRuleCommand({\n    Name: \"route-order-created\",\n    Description: \"Match order.created events from the orders app\",\n    EventBusName: \"default\",\n    EventPattern: eventPattern,\n    State: \"ENABLED\",\n  }),\n);\n\nconsole.log(response.RuleArn);\n```\n\nYou can also create scheduled rules with `ScheduleExpression` instead of an event pattern.\n\n### Attach a target to a rule\n\nCreating a rule does not attach any destination. Use `PutTargetsCommand` to send matched events to a Lambda function, SQS queue, SNS topic, Step Functions state machine, or another supported target.\n\n```javascript\nimport {\n  EventBridgeClient,\n  PutTargetsCommand,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\n\nconst response = await eventbridge.send(\n  new PutTargetsCommand({\n    Rule: \"route-order-created\",\n    EventBusName: \"default\",\n    Targets: [\n      {\n        Id: \"order-processor\",\n        Arn: \"arn:aws:lambda:us-east-1:123456789012:function:process-order\",\n      },\n    ],\n  }),\n);\n\nif ((response.FailedEntryCount ?? 0) > 0) {\n  throw new Error(JSON.stringify(response.FailedEntries));\n}\n```\n\nFor some targets, the target resource also needs separate permissions or a `RoleArn`. For Lambda targets, EventBridge target attachment does not replace the Lambda resource-based permission that allows `events.amazonaws.com` to invoke the function.\n\n### List targets for a rule\n\n`ListTargetsByRuleCommand` is the easiest way to inspect which targets are currently attached.\n\n```javascript\nimport {\n  EventBridgeClient,\n  ListTargetsByRuleCommand,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await eventbridge.send(\n    new ListTargetsByRuleCommand({\n      Rule: \"route-order-created\",\n      EventBusName: \"default\",\n      NextToken: nextToken,\n      Limit: 100,\n    }),\n  );\n\n  for (const target of response.Targets ?? []) {\n    console.log(target.Id, target.Arn);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Remove targets and delete a rule\n\nYou must remove a rule's targets before deleting the rule.\n\n```javascript\nimport {\n  DeleteRuleCommand,\n  EventBridgeClient,\n  ListTargetsByRuleCommand,\n  RemoveTargetsCommand,\n} from \"@aws-sdk/client-eventbridge\";\n\nconst eventbridge = new EventBridgeClient({ region: \"us-east-1\" });\nconst ruleName = \"route-order-created\";\nconst eventBusName = \"default\";\n\nconst targetIds = [];\nlet nextToken;\n\ndo {\n  const response = await eventbridge.send(\n    new ListTargetsByRuleCommand({\n      Rule: ruleName,\n      EventBusName: eventBusName,\n      NextToken: nextToken,\n      Limit: 100,\n    }),\n  );\n\n  for (const target of response.Targets ?? []) {\n    if (target.Id) {\n      targetIds.push(target.Id);\n    }\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n\nif (targetIds.length > 0) {\n  await eventbridge.send(\n    new RemoveTargetsCommand({\n      Rule: ruleName,\n      EventBusName: eventBusName,\n      Ids: targetIds,\n    }),\n  );\n}\n\nawait eventbridge.send(\n  new DeleteRuleCommand({\n    Name: ruleName,\n    EventBusName: eventBusName,\n  }),\n);\n```\n\n## Pitfalls\n\n- `Detail` for `PutEventsCommand` is a serialized JSON string. Do not pass a raw object.\n- `EventPattern` for `PutRuleCommand` is also a JSON string.\n- `PutEventsCommand` and `PutTargetsCommand` can partially fail. Always check `FailedEntryCount` and inspect the per-entry results.\n- Creating a rule is not enough by itself. Rules only deliver anywhere after you attach one or more targets.\n- Deleting a rule requires target cleanup first.\n- EventBridge resources are regional. A rule, bus, or target lookup in the wrong region looks like a missing resource.\n- If you use a non-default bus, include `EventBusName` on related calls instead of relying on the default bus implicitly.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-lambda`: add or manage Lambda invoke permissions for EventBridge targets.\n- `@aws-sdk/client-scheduler`: use the separate EventBridge Scheduler service when you need one-time or flexible-time-window schedules rather than EventBridge rules.\n- `@aws-sdk/credential-providers`: configure Cognito, assume-role, SSO, or other explicit credential flows.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-eventbridge` version `3.1007.0`.\n- The AWS SDK for JavaScript v3 package exports the low-level `EventBridgeClient` and individual commands; this is the import style to prefer in application code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 EventBridge client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/eventbridge/`\n- Amazon EventBridge API Reference: `https://docs.aws.amazon.com/eventbridge/latest/APIReference/Welcome.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-eventbridge`\n"
  },
  {
    "path": "content/aws/docs/firehose/javascript/DOC.md",
    "content": "---\nname: firehose\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Data Firehose delivery stream writes and stream inspection APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,firehose,data-firehose,streaming,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-firehose`\n\nUse this package to write records to Amazon Data Firehose delivery streams and inspect delivery stream configuration from JavaScript or TypeScript. AWS branding often says Amazon Data Firehose, but the SDK package, client class, and API names still use `firehose` and `DeliveryStream`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-firehose\n```\n\nPrefer `FirehoseClient` plus explicit command imports. The package also exports an aggregated `Firehose` client, but command-based imports are the safer default for smaller bundles and clearer application code.\n\n## Credentials and region\n\nIn Node.js, the default credential provider chain is usually enough if AWS access is already configured through environment variables, shared config files, ECS or EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you use temporary credentials, also set `AWS_SESSION_TOKEN`.\n\n## Initialize the client\n\n```javascript\nimport { FirehoseClient } from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nExplicit credentials:\n\n```javascript\nimport { FirehoseClient } from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\nFirehose is usually called from trusted backend code. Browser usage needs explicit credential configuration and tight IAM scoping because the client can write directly to your delivery stream.\n\n## Core usage pattern\n\nApplication code usually writes to an existing delivery stream with `PutRecord` or `PutRecordBatch`. Firehose record data is binary, so encode structured payloads yourself before sending them. JSON Lines is a practical default for S3-based downstream processing.\n\n```javascript\nimport {\n  FirehoseClient,\n  PutRecordCommand,\n} from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({ region: \"us-east-1\" });\nconst event = { event: \"signup\", userId: 123 };\n\nconst response = await firehose.send(\n  new PutRecordCommand({\n    DeliveryStreamName: \"events-stream\",\n    Record: {\n      Data: new TextEncoder().encode(`${JSON.stringify(event)}\\n`),\n    },\n  }),\n);\n\nconsole.log(response.RecordId);\n```\n\nUnlike Kinesis Data Streams, Firehose direct puts do not take a `PartitionKey`. Use `DeliveryStreamName`, not `StreamName`.\n\n## Common operations\n\n### Write multiple records in one request\n\n`PutRecordBatch` can succeed partially, so always inspect `FailedPutCount` and retry only the failed records.\n\n```javascript\nimport {\n  FirehoseClient,\n  PutRecordBatchCommand,\n} from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({ region: \"us-east-1\" });\nconst encoder = new TextEncoder();\n\nconst payloads = [\n  { event: \"signup\", userId: 123 },\n  { event: \"purchase\", userId: 123, total: 49.99 },\n];\n\nconst records = payloads.map((payload) => ({\n  Data: encoder.encode(`${JSON.stringify(payload)}\\n`),\n}));\n\nconst response = await firehose.send(\n  new PutRecordBatchCommand({\n    DeliveryStreamName: \"events-stream\",\n    Records: records,\n  }),\n);\n\nif ((response.FailedPutCount ?? 0) > 0) {\n  const failedPayloads = (response.RequestResponses ?? [])\n    .map((result, index) => ({ result, payload: payloads[index] }))\n    .filter(({ result }) => result.ErrorCode || result.ErrorMessage);\n\n  console.log(\"retry these payloads\", failedPayloads);\n}\n```\n\n### Inspect a delivery stream\n\nUse `DescribeDeliveryStream` when your app needs stream metadata or when you need to confirm that a newly created or updated stream is ready before writing to it.\n\n```javascript\nimport {\n  DescribeDeliveryStreamCommand,\n  FirehoseClient,\n} from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({ region: \"us-east-1\" });\n\nconst response = await firehose.send(\n  new DescribeDeliveryStreamCommand({\n    DeliveryStreamName: \"events-stream\",\n  }),\n);\n\nconsole.log(response.DeliveryStreamDescription?.DeliveryStreamStatus);\nconsole.log(response.DeliveryStreamDescription?.DeliveryStreamType);\nconsole.log(response.DeliveryStreamDescription?.VersionId);\n```\n\n### List delivery streams\n\n```javascript\nimport {\n  FirehoseClient,\n  ListDeliveryStreamsCommand,\n} from \"@aws-sdk/client-firehose\";\n\nconst firehose = new FirehoseClient({ region: \"us-east-1\" });\n\nconst response = await firehose.send(\n  new ListDeliveryStreamsCommand({\n    Limit: 25,\n  }),\n);\n\nconsole.log(response.DeliveryStreamNames ?? []);\nconsole.log(response.HasMoreDeliveryStreams ?? false);\n```\n\nIf `HasMoreDeliveryStreams` is `true`, request the next page with `ExclusiveStartDeliveryStreamName` set to the last stream name from the previous page.\n\n## Firehose-specific gotchas\n\n- `Record.Data` must be bytes. Use `TextEncoder`, `Buffer`, or another byte conversion step instead of passing plain objects.\n- For line-oriented downstream consumers, add your own newline delimiter. Firehose does not convert objects into JSON or JSON Lines for you.\n- `PutRecordBatch` can return partial success. Retry only the failed records from `RequestResponses` instead of resending the full batch.\n- Firehose write APIs use `DeliveryStreamName`; they do not use Kinesis Data Streams fields like `PartitionKey`.\n- Delivery stream creation and destination updates are destination-specific. If you manage streams programmatically, validate those request shapes against the Firehose API reference for your destination type.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 Firehose client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/firehose/`\n- Amazon Data Firehose API Reference: `https://docs.aws.amazon.com/firehose/latest/APIReference/Welcome.html`\n- `PutRecord` API reference: `https://docs.aws.amazon.com/firehose/latest/APIReference/API_PutRecord.html`\n- `PutRecordBatch` API reference: `https://docs.aws.amazon.com/firehose/latest/APIReference/API_PutRecordBatch.html`\n- `DescribeDeliveryStream` API reference: `https://docs.aws.amazon.com/firehose/latest/APIReference/API_DescribeDeliveryStream.html`\n- `ListDeliveryStreams` API reference: `https://docs.aws.amazon.com/firehose/latest/APIReference/API_ListDeliveryStreams.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/forecast/javascript/DOC.md",
    "content": "---\nname: forecast\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Forecast datasets, predictors, forecasts, and related control-plane APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,forecast,javascript,nodejs,time-series,ml\"\n---\n\n# `@aws-sdk/client-forecast`\n\nUse this package for Amazon Forecast control-plane operations in AWS SDK for JavaScript v3: dataset groups, datasets, dataset import jobs, predictors, forecasts, forecast export jobs, tags, monitors, and related describe/list/delete APIs.\n\nAmazon Forecast is no longer available to new customers. Existing customers can continue using the service, so this package is mainly useful for maintaining or extending existing Forecast deployments.\n\nPrefer trusted server-side code. Forecast operations usually need broad IAM permissions plus access to S3 data locations.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-forecast\n```\n\nIf you want explicit shared-config or profile-based credentials in Node.js instead of the default provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Credentials and region\n\nSet region explicitly in code or through environment/config. Typical local setup:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_PROFILE=forecast-admin\n```\n\nIn Node.js, the AWS SDK v3 default credential chain usually resolves credentials from environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance profiles.\n\n## Initialize the client\n\nUse the default provider chain when the environment is already configured:\n\n```javascript\nimport { ForecastClient } from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nIf you want to force a named profile from shared AWS config files:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { ForecastClient } from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"forecast-admin\",\n  }),\n});\n```\n\n## What this client covers\n\n`@aws-sdk/client-forecast` is the resource-management side of Amazon Forecast. Common flows look like this:\n\n1. create or inspect datasets and dataset groups\n2. import training data from S3\n3. create an auto predictor\n4. wait until the predictor becomes `ACTIVE`\n5. inspect accuracy metrics\n6. create a forecast from the predictor\n7. wait until the forecast becomes `ACTIVE`\n8. export or query the resulting forecast\n\nQuery-time APIs are separate from this package. If you need low-latency retrieval for a specific item and time range, use the Forecast Query service client instead of this control-plane client.\n\n## Core usage pattern\n\n### List dataset groups\n\nStart by discovering the dataset groups already present in the target region.\n\n```javascript\nimport {\n  ForecastClient,\n  ListDatasetGroupsCommand,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await forecast.send(\n    new ListDatasetGroupsCommand({\n      MaxResults: 20,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const group of page.DatasetGroups ?? []) {\n    console.log({\n      arn: group.DatasetGroupArn,\n      name: group.DatasetGroupName,\n      status: group.Status,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nForecast resources are regional. If you do not see the dataset group you expect, check the client region first.\n\n### Inspect one dataset group\n\n`DescribeDatasetGroupCommand` gives you the domain and the dataset ARNs attached to the group.\n\n```javascript\nimport {\n  DescribeDatasetGroupCommand,\n  ForecastClient,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst response = await forecast.send(\n  new DescribeDatasetGroupCommand({\n    DatasetGroupArn: \"arn:aws:forecast:us-west-2:123456789012:dataset-group/retail-demo\",\n  }),\n);\n\nconsole.log({\n  name: response.DatasetGroupName,\n  arn: response.DatasetGroupArn,\n  domain: response.Domain,\n  status: response.Status,\n  datasets: response.DatasetArns,\n});\n```\n\nWait for the dataset group to become `ACTIVE` before using it to train predictors.\n\n### Start a dataset import job from S3\n\nUse this when you already have a Forecast dataset and need to load or refresh its training data from S3.\n\n```javascript\nimport {\n  CreateDatasetImportJobCommand,\n  ForecastClient,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst { DatasetImportJobArn } = await forecast.send(\n  new CreateDatasetImportJobCommand({\n    DatasetImportJobName: \"retail-target-import-20260313\",\n    DatasetArn: \"arn:aws:forecast:us-west-2:123456789012:dataset/retail-target\",\n    DataSource: {\n      S3Config: {\n        Path: \"s3://my-forecast-input/retail/target-time-series.csv\",\n        RoleArn: \"arn:aws:iam::123456789012:role/AmazonForecastS3Access\",\n      },\n    },\n    TimestampFormat: \"yyyy-MM-dd\",\n  }),\n);\n\nconsole.log(DatasetImportJobArn);\n```\n\nPractical rules:\n\n- dataset import data must come from S3\n- the IAM role in `DataSource.S3Config.RoleArn` must be in your account\n- if you use KMS encryption for the dataset, the import job must use matching key access\n- if you omit `TimestampFormat`, Forecast expects `yyyy-MM-dd HH:mm:ss`\n\n### Create an auto predictor\n\nFor new work, prefer `CreateAutoPredictorCommand`. Current service docs describe AutoPredictor as the normal predictor-creation path.\n\n```javascript\nimport {\n  CreateAutoPredictorCommand,\n  ForecastClient,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst { PredictorArn } = await forecast.send(\n  new CreateAutoPredictorCommand({\n    PredictorName: \"retail-demand-v1\",\n    ForecastHorizon: 14,\n    ForecastFrequency: \"D\",\n    ForecastTypes: [\"0.1\", \"0.5\", \"0.9\"],\n    DataConfig: {\n      DatasetGroupArn:\n        \"arn:aws:forecast:us-west-2:123456789012:dataset-group/retail-demo\",\n    },\n  }),\n);\n\nconsole.log(PredictorArn);\n```\n\nThe required fields for a new auto predictor are the predictor name, dataset group ARN, forecast frequency, and forecast horizon.\n\n### Wait for predictor training and inspect metrics\n\nForecast creation APIs are asynchronous. Submit the job, then poll the matching `Describe*` operation until the resource becomes `ACTIVE` or fails.\n\n```javascript\nimport {\n  DescribePredictorCommand,\n  ForecastClient,\n  GetAccuracyMetricsCommand,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForPredictor(predictorArn) {\n  for (;;) {\n    const response = await forecast.send(\n      new DescribePredictorCommand({\n        PredictorArn: predictorArn,\n      }),\n    );\n\n    const status = response.Status ?? \"UNKNOWN\";\n    console.log({ status, message: response.Message });\n\n    if (status === \"ACTIVE\") {\n      return response;\n    }\n\n    if (status.endsWith(\"_FAILED\") || status.endsWith(\"_STOPPED\")) {\n      throw new Error(response.Message ?? `Predictor ended in state ${status}`);\n    }\n\n    await sleep(30_000);\n  }\n}\n\nconst predictorArn = \"arn:aws:forecast:us-west-2:123456789012:predictor/retail-demand-v1\";\n\nawait waitForPredictor(predictorArn);\n\nconst metrics = await forecast.send(\n  new GetAccuracyMetricsCommand({\n    PredictorArn: predictorArn,\n  }),\n);\n\nfor (const result of metrics.PredictorEvaluationResults ?? []) {\n  console.log({\n    algorithmArn: result.AlgorithmArn,\n    windows: result.TestWindows?.length ?? 0,\n  });\n}\n```\n\nUse `DescribePredictorCommand` for lifecycle state and `GetAccuracyMetricsCommand` for model quality details after training finishes.\n\n### Create a forecast from a predictor\n\n`CreateForecastCommand` runs inference for the predictor. The forecast horizon comes from the predictor configuration.\n\n```javascript\nimport {\n  CreateForecastCommand,\n  ForecastClient,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nconst { ForecastArn } = await forecast.send(\n  new CreateForecastCommand({\n    ForecastName: \"retail-demand-v1-20260313\",\n    PredictorArn: \"arn:aws:forecast:us-west-2:123456789012:predictor/retail-demand-v1\",\n    ForecastTypes: [\"0.1\", \"0.5\", \"0.9\"],\n  }),\n);\n\nconsole.log(ForecastArn);\n```\n\nIf you omit `ForecastTypes`, Forecast uses the predictor's configured quantiles. If the predictor did not specify quantiles, the service default is `0.1`, `0.5`, and `0.9`.\n\n### Wait for a forecast to become active\n\nForecasts must be `ACTIVE` before you query or export them.\n\n```javascript\nimport {\n  DescribeForecastCommand,\n  ForecastClient,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForForecast(forecastArn) {\n  for (;;) {\n    const response = await forecast.send(\n      new DescribeForecastCommand({\n        ForecastArn: forecastArn,\n      }),\n    );\n\n    const status = response.Status ?? \"UNKNOWN\";\n    console.log({ status, message: response.Message });\n\n    if (status === \"ACTIVE\") {\n      return response;\n    }\n\n    if (status.endsWith(\"_FAILED\") || status.endsWith(\"_STOPPED\")) {\n      throw new Error(response.Message ?? `Forecast ended in state ${status}`);\n    }\n\n    await sleep(30_000);\n  }\n}\n\nconst forecastArn = \"arn:aws:forecast:us-west-2:123456789012:forecast/retail-demand-v1-20260313\";\nconst description = await waitForForecast(forecastArn);\n\nconsole.log({\n  predictorArn: description.PredictorArn,\n  datasetGroupArn: description.DatasetGroupArn,\n  forecastTypes: description.ForecastTypes,\n});\n```\n\nForecast outputs use the same time zone as the dataset that trained the predictor.\n\n### List or delete forecasts\n\n`ListForecastsCommand` supports filtering by `DatasetGroupArn`, `PredictorArn`, and `Status`.\n\n```javascript\nimport {\n  DeleteForecastCommand,\n  ForecastClient,\n  ListForecastsCommand,\n} from \"@aws-sdk/client-forecast\";\n\nconst forecast = new ForecastClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await forecast.send(\n    new ListForecastsCommand({\n      MaxResults: 25,\n      NextToken: nextToken,\n      Filters: [\n        {\n          Key: \"PredictorArn\",\n          Condition: \"IS\",\n          Value: \"arn:aws:forecast:us-west-2:123456789012:predictor/retail-demand-v1\",\n        },\n      ],\n    }),\n  );\n\n  for (const item of page.Forecasts ?? []) {\n    console.log({\n      arn: item.ForecastArn,\n      name: item.ForecastName,\n      status: item.Status,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n\nawait forecast.send(\n  new DeleteForecastCommand({\n    ForecastArn: \"arn:aws:forecast:us-west-2:123456789012:forecast/retail-demand-v1-20260313\",\n  }),\n);\n```\n\nDelete only after downstream exports or queries are done. Forecast resources are not reusable after deletion.\n\n## Common pitfalls\n\n- `@aws-sdk/client-forecast` is the management client, not the query client. Use the Forecast Query service for low-latency per-item reads.\n- Forecast resources are regional. A valid ARN in one region will not show up in another region's client.\n- Most create operations are asynchronous. Always poll `DescribeDatasetGroup`, `DescribeDatasetImportJob`, `DescribePredictor`, or `DescribeForecast` before starting the next dependent step.\n- `CreateForecastCommand` requires a predictor ARN. The forecast cannot become usable until its status is `ACTIVE`.\n- Dataset import jobs read from S3 and require an IAM role that Forecast can assume. Cross-account role passing is not allowed.\n- If you use KMS-encrypted data, make sure the Forecast service role can use the same key.\n- For existing installations, prefer `CreateAutoPredictorCommand` over older predictor-creation flows unless you have a specific legacy reason.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 Forecast client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/forecast/`\n- Amazon Forecast API operations reference: `https://docs.aws.amazon.com/forecast/latest/dg/API_Operations_Amazon_Forecast_Service.html`\n- AWS CLI `forecast` reference: `https://docs.aws.amazon.com/cli/latest/reference/forecast/`\n- Amazon Forecast developer guide: `https://docs.aws.amazon.com/forecast/latest/dg/what-is-forecast.html`\n"
  },
  {
    "path": "content/aws/docs/fsx/javascript/DOC.md",
    "content": "---\nname: fsx\ndescription: \"AWS SDK for JavaScript v3 client for Amazon FSx file system, backup, tagging, and volume administration APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,fsx,javascript,nodejs,storage,lustre,windows,ontap,openzfs\"\n---\n\n# `@aws-sdk/client-fsx`\n\nUse this package for Amazon FSx control-plane APIs from JavaScript or TypeScript: create and describe file systems, manage backups and tags, and work with ONTAP or OpenZFS volumes.\n\nThis package manages FSx resources. It is not the client you use to read and write files inside a mounted FSx file system.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-fsx\n```\n\nPrefer `FSxClient` plus explicit command imports. That keeps examples clear and matches normal AWS SDK v3 usage.\n\n## Initialize the Client\n\n### Minimal Node.js client\n\n```javascript\nimport { FSxClient } from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { FSxClient } from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({\n  region: \"us-west-2\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-west-2\n```\n\nOr with direct environment variables:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nThese are administrative APIs, so browser usage is uncommon. Most applications call FSx from trusted server-side code.\n\n## File System Types and Request Shape\n\n`CreateFileSystemCommand` supports these file system types:\n\n- `WINDOWS`\n- `LUSTRE`\n- `ONTAP`\n- `OPENZFS`\n\nThe nested configuration object must match `FileSystemType`:\n\n- `WindowsConfiguration` for `WINDOWS`\n- `LustreConfiguration` for `LUSTRE`\n- `OntapConfiguration` for `ONTAP`\n- `OpenZFSConfiguration` for `OPENZFS`\n\nIf those do not line up, FSx rejects the request.\n\n## Common Operations\n\n### List file systems across pages\n\n```javascript\nimport {\n  FSxClient,\n  paginateDescribeFileSystems,\n} from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({ region: process.env.AWS_REGION ?? \"us-west-2\" });\n\nfor await (const page of paginateDescribeFileSystems({ client: fsx }, {})) {\n  for (const fileSystem of page.FileSystems ?? []) {\n    console.log(\n      fileSystem.FileSystemId,\n      fileSystem.FileSystemType,\n      fileSystem.Lifecycle,\n    );\n  }\n}\n```\n\nUse `DescribeFileSystemsCommand` with `FileSystemIds` when you already know the specific file system IDs you want.\n\n### Create a Lustre file system and poll until it becomes usable\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  CreateFileSystemCommand,\n  DescribeFileSystemsCommand,\n  FSxClient,\n} from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({ region: \"us-west-2\" });\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst createResult = await fsx.send(\n  new CreateFileSystemCommand({\n    ClientRequestToken: randomUUID(),\n    FileSystemType: \"LUSTRE\",\n    StorageCapacity: 1200,\n    SubnetIds: [\"subnet-0123456789abcdef0\"],\n    SecurityGroupIds: [\"sg-0123456789abcdef0\"],\n    LustreConfiguration: {\n      DeploymentType: \"SCRATCH_2\",\n    },\n    Tags: [{ Key: \"Name\", Value: \"analytics-lustre\" }],\n  }),\n);\n\nconst fileSystemId = createResult.FileSystem?.FileSystemId;\n\nif (!fileSystemId) {\n  throw new Error(\"FSx did not return a file system id\");\n}\n\nlet lifecycle;\n\ndo {\n  const describeResult = await fsx.send(\n    new DescribeFileSystemsCommand({\n      FileSystemIds: [fileSystemId],\n    }),\n  );\n\n  lifecycle = describeResult.FileSystems?.[0]?.Lifecycle;\n  console.log(\"Current lifecycle:\", lifecycle);\n\n  if ([\"AVAILABLE\", \"FAILED\", \"MISCONFIGURED\"].includes(lifecycle ?? \"\")) {\n    break;\n  }\n\n  await sleep(30_000);\n} while (true);\n\nif (lifecycle !== \"AVAILABLE\") {\n  throw new Error(`File system did not become available: ${lifecycle}`);\n}\n```\n\nFSx create calls are asynchronous. A successful `CreateFileSystemCommand` response only means the request was accepted.\n\n### Create a backup for a file system\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  CreateBackupCommand,\n  DescribeBackupsCommand,\n  FSxClient,\n} from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({ region: \"us-west-2\" });\nconst fileSystemId = \"fs-0123456789abcdef0\";\n\nconst createBackupResult = await fsx.send(\n  new CreateBackupCommand({\n    FileSystemId: fileSystemId,\n    ClientRequestToken: randomUUID(),\n    Tags: [{ Key: \"environment\", Value: \"prod\" }],\n  }),\n);\n\nconst backupId = createBackupResult.Backup?.BackupId;\n\nif (!backupId) {\n  throw new Error(\"FSx did not return a backup id\");\n}\n\nconst describeBackupResult = await fsx.send(\n  new DescribeBackupsCommand({\n    BackupIds: [backupId],\n  }),\n);\n\nconsole.log(describeBackupResult.Backups?.[0]?.Lifecycle);\n```\n\n`CreateBackupCommand` accepts either `FileSystemId` or `VolumeId`. Volume backups apply to FSx for ONTAP and FSx for OpenZFS volumes.\n\n### Tag a resource and read its tags back\n\n```javascript\nimport {\n  DescribeFileSystemsCommand,\n  FSxClient,\n  ListTagsForResourceCommand,\n  TagResourceCommand,\n} from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({ region: \"us-west-2\" });\nconst fileSystemId = \"fs-0123456789abcdef0\";\n\nconst describeResult = await fsx.send(\n  new DescribeFileSystemsCommand({\n    FileSystemIds: [fileSystemId],\n  }),\n);\n\nconst resourceArn = describeResult.FileSystems?.[0]?.ResourceARN;\n\nif (!resourceArn) {\n  throw new Error(\"Missing file system ARN\");\n}\n\nawait fsx.send(\n  new TagResourceCommand({\n    ResourceARN: resourceArn,\n    Tags: [\n      { Key: \"environment\", Value: \"prod\" },\n      { Key: \"owner\", Value: \"platform\" },\n    ],\n  }),\n);\n\nconst tagsResult = await fsx.send(\n  new ListTagsForResourceCommand({\n    ResourceARN: resourceArn,\n  }),\n);\n\nconsole.log(tagsResult.Tags);\n```\n\nThe property name is `ResourceARN`, not `ResourceArn`.\n\n### List volumes for ONTAP or OpenZFS\n\n```javascript\nimport {\n  DescribeVolumesCommand,\n  FSxClient,\n} from \"@aws-sdk/client-fsx\";\n\nconst fsx = new FSxClient({ region: \"us-west-2\" });\nconst fileSystemId = \"fs-0123456789abcdef0\";\n\nconst result = await fsx.send(\n  new DescribeVolumesCommand({\n    Filters: [\n      {\n        Name: \"file-system-id\",\n        Values: [fileSystemId],\n      },\n    ],\n  }),\n);\n\nfor (const volume of result.Volumes ?? []) {\n  console.log(volume.VolumeId, volume.Lifecycle);\n}\n```\n\n`DescribeVolumesCommand` is for Amazon FSx for NetApp ONTAP and Amazon FSx for OpenZFS volumes.\n\n## FSx-Specific Gotchas\n\n- `CreateFileSystemCommand` is type-specific. Keep `FileSystemType` aligned with the matching nested configuration object.\n- File system creation, backup creation, updates, and deletion are asynchronous. Check `Lifecycle` and, when relevant, `AdministrativeActions` before treating the resource as ready.\n- Tag APIs use `ResourceARN` in request shapes.\n- `DescribeVolumesCommand` only applies to ONTAP and OpenZFS volume resources.\n- `DeleteFileSystemCommand` also uses a type-specific nested configuration block such as `LustreConfiguration`, `WindowsConfiguration`, or `OpenZFSConfiguration` to control final-backup behavior.\n- Deleting OpenZFS file systems can require `OpenZFSConfiguration.Options`, such as `DELETE_CHILD_VOLUMES_AND_SNAPSHOTS`, when child resources still exist.\n- Network placement still matters. Subnets, security groups, route tables, Active Directory settings, and file-system-type-specific throughput or deployment options are validated by the service at runtime.\n\n## Official Source URLs\n\n- `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/fsx/`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateFileSystem.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_DescribeFileSystems.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateBackup.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_DescribeBackups.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_DescribeVolumes.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_TagResource.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_ListTagsForResource.html`\n- `https://docs.aws.amazon.com/fsx/latest/APIReference/API_DeleteFileSystem.html`\n"
  },
  {
    "path": "content/aws/docs/glue/javascript/DOC.md",
    "content": "---\nname: glue\ndescription: \"AWS SDK for JavaScript v3 Glue client for Data Catalog reads, crawler control, and ETL job orchestration.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,glue,javascript,nodejs,data-catalog,crawlers,etl\"\n---\n\n# `@aws-sdk/client-glue`\n\nUse this package for AWS Glue control-plane APIs in AWS SDK for JavaScript v3. The most common application use cases are reading Data Catalog metadata, creating or starting crawlers, creating jobs, starting job runs, and polling job status.\n\nMost Glue workloads run from trusted server-side code. The package can be used anywhere the AWS SDK v3 works, but browser usage usually needs an explicit credential strategy and careful permission scoping.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-glue\n```\n\nPrefer `GlueClient` plus explicit command imports. The package also exposes an aggregated `Glue` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Initialize the client\n\n```javascript\nimport { GlueClient } from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already configured AWS access through environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nRead table metadata from the Glue Data Catalog with client-plus-command calls:\n\n```javascript\nimport {\n  GetTableCommand,\n  GlueClient,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nconst response = await glue.send(\n  new GetTableCommand({\n    DatabaseName: \"analytics\",\n    Name: \"events\",\n  }),\n);\n\nconst columns = response.Table?.StorageDescriptor?.Columns ?? [];\n\nfor (const column of columns) {\n  console.log(column.Name, column.Type);\n}\n```\n\nFor Hive compatibility, Glue database and table names are expected to be lowercase. If you fetch metadata for mixed-case names created elsewhere, normalize your own naming conventions before relying on catalog lookups.\n\n## Common Operations\n\n### List Data Catalog databases with pagination\n\n```javascript\nimport {\n  GetDatabasesCommand,\n  GlueClient,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await glue.send(\n    new GetDatabasesCommand({\n      NextToken: nextToken,\n      MaxResults: 100,\n    }),\n  );\n\n  for (const database of page.DatabaseList ?? []) {\n    console.log(database.Name);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nGlue list operations commonly return `NextToken`. Do not assume one response contains every database, table, crawler, or job.\n\n### List tables in a database\n\n```javascript\nimport {\n  GetTablesCommand,\n  GlueClient,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nconst response = await glue.send(\n  new GetTablesCommand({\n    DatabaseName: \"analytics\",\n    Expression: \"events_*\",\n    MaxResults: 50,\n  }),\n);\n\nfor (const table of response.TableList ?? []) {\n  console.log(table.Name, table.TableType);\n}\n```\n\nUse `Expression` when you want server-side name filtering instead of listing a whole database and filtering in application code.\n\n### Create and start an S3 crawler\n\n```javascript\nimport {\n  CreateCrawlerCommand,\n  GlueClient,\n  StartCrawlerCommand,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nawait glue.send(\n  new CreateCrawlerCommand({\n    Name: \"orders-landing-zone\",\n    Role: \"arn:aws:iam::123456789012:role/AWSGlueServiceRoleDefault\",\n    DatabaseName: \"analytics\",\n    Targets: {\n      S3Targets: [\n        {\n          Path: \"s3://my-bucket/raw/orders/\",\n        },\n      ],\n    },\n    TablePrefix: \"raw_\",\n  }),\n);\n\nawait glue.send(\n  new StartCrawlerCommand({\n    Name: \"orders-landing-zone\",\n  }),\n);\n```\n\n`CreateCrawler` requires a role and at least one target. Targets can point to S3, JDBC, DynamoDB, Glue catalog targets, Delta, Iceberg, or Hudi sources.\n\n### Create a job definition\n\n```javascript\nimport {\n  CreateJobCommand,\n  GlueClient,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nawait glue.send(\n  new CreateJobCommand({\n    Name: \"nightly-orders-etl\",\n    Role: \"arn:aws:iam::123456789012:role/AWSGlueServiceRoleDefault\",\n    Command: {\n      Name: \"glueetl\",\n      ScriptLocation: \"s3://my-bucket/glue-scripts/orders-etl.py\",\n    },\n    DefaultArguments: {\n      \"--job-language\": \"python\",\n      \"--TempDir\": \"s3://my-bucket/glue-temporary/\",\n    },\n    GlueVersion: \"4.0\",\n    WorkerType: \"G.1X\",\n    NumberOfWorkers: 2,\n  }),\n);\n```\n\nUse `Command.Name` to match the job type:\n\n- `glueetl` for Spark ETL jobs\n- `gluestreaming` for Spark streaming jobs\n- `pythonshell` for Python shell jobs\n- `glueray` for Ray jobs\n\n### Start a job run and poll its status\n\n```javascript\nimport {\n  GetJobRunCommand,\n  GlueClient,\n  StartJobRunCommand,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nconst start = await glue.send(\n  new StartJobRunCommand({\n    JobName: \"nightly-orders-etl\",\n    Arguments: {\n      \"--source_bucket\": \"my-bucket\",\n      \"--target_prefix\": \"processed/orders/\",\n    },\n    WorkerType: \"G.1X\",\n    NumberOfWorkers: 2,\n    ExecutionClass: \"STANDARD\",\n  }),\n);\n\nconst runId = start.JobRunId;\n\nif (!runId) {\n  throw new Error(\"Glue did not return a job run id\");\n}\n\nconst terminalStates = new Set([\n  \"SUCCEEDED\",\n  \"FAILED\",\n  \"STOPPED\",\n  \"TIMEOUT\",\n  \"ERROR\",\n  \"EXPIRED\",\n]);\n\nlet state = \"STARTING\";\n\nwhile (!terminalStates.has(state)) {\n  const result = await glue.send(\n    new GetJobRunCommand({\n      JobName: \"nightly-orders-etl\",\n      RunId: runId,\n    }),\n  );\n\n  state = result.JobRun?.JobRunState ?? \"UNKNOWN\";\n  console.log(state, result.JobRun?.ErrorMessage ?? \"\");\n\n  if (!terminalStates.has(state)) {\n    await new Promise((resolve) => setTimeout(resolve, 15000));\n  }\n}\n```\n\n`StartJobRun` only queues a run. Check `GetJobRun` until the state reaches a terminal value if your workflow depends on completion.\n\n### Read table partitions\n\n```javascript\nimport {\n  GetPartitionsCommand,\n  GlueClient,\n} from \"@aws-sdk/client-glue\";\n\nconst glue = new GlueClient({ region: \"us-east-1\" });\n\nconst response = await glue.send(\n  new GetPartitionsCommand({\n    DatabaseName: \"analytics\",\n    TableName: \"events\",\n    MaxResults: 25,\n  }),\n);\n\nfor (const partition of response.Partitions ?? []) {\n  console.log(partition.Values);\n}\n```\n\nUse `GetPartitions` for browsing or filtering partitions, and `BatchGetPartition` when you already know the exact partition values to fetch.\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain is usually enough for server-side Glue automation.\n- Browser runtimes: use an explicit credential provider and tightly scoped IAM permissions; most Glue operations are better kept off the client.\n- Region must be configured somewhere, either in the client constructor, `AWS_REGION`, or shared AWS config.\n- Glue jobs and crawlers also need service roles with the right permissions for S3, CloudWatch Logs, and any other resources they touch.\n\n## Glue-Specific Gotchas\n\n- Job arguments may be logged; do not pass plaintext secrets in `DefaultArguments` or `Arguments`.\n- For Glue 2.0+ jobs, prefer `WorkerType` plus `NumberOfWorkers` instead of `MaxCapacity`.\n- `StartCrawlerCommand` throws `CrawlerRunningException` if the crawler is already active.\n- `StartJobRunCommand` can fail with `ConcurrentRunsExceededException` when the job is already at its allowed run concurrency.\n- `GetJobRun` history is retained for 90 days, so do not treat it as your long-term execution archive.\n- Data Catalog pagination is common; handle `NextToken` on reads that can span many resources.\n- Table and database names are lowercase-oriented for Hive compatibility.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-s3`: store Glue ETL scripts, crawler targets, and job temporary data in S3.\n- `@aws-sdk/client-athena`: query the tables registered in the Glue Data Catalog.\n- `@aws-sdk/client-lakeformation`: manage Data Catalog permissions and governance in Lake Formation-aware environments.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, assume-role, and browser-safe credential helpers.\n"
  },
  {
    "path": "content/aws/docs/guardduty/javascript/DOC.md",
    "content": "---\nname: guardduty\ndescription: \"AWS SDK for JavaScript v3 client for Amazon GuardDuty detectors, findings, filters, trusted IP sets, and publishing destinations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,guardduty,javascript,nodejs,security,findings,threat-detection\"\n---\n\n# `@aws-sdk/client-guardduty`\n\nUse this package to manage Amazon GuardDuty from JavaScript with AWS SDK v3. The most common workflow is: find or create the detector for the current AWS Region, list findings for that detector, fetch full finding details, then optionally manage saved filters, trusted IP sets, or an S3 publishing destination for exported findings.\n\nGuardDuty is regional. A detector, its findings, its filters, and its related resources are all scoped to the client region you configure.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-guardduty\n```\n\n## Prerequisites\n\nYou need AWS credentials with GuardDuty permissions in the target account and region. For some workflows you also need access to related AWS resources:\n\n- S3 access for trusted IP sets and exported findings\n- KMS access when exporting findings to an encrypted S3 destination\n- permission to create or update the GuardDuty detector in that region\n\nTypical local setup in Node.js:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you use a shared AWS profile, set `AWS_PROFILE` before starting your app.\n\n## Initialize the client\n\n```javascript\nimport { GuardDutyClient } from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, AWS SDK v3 uses the default credential provider chain, so you usually do not need to pass credentials explicitly when your environment or shared AWS config is already set up.\n\n## Find or create the detector for this region\n\nGuardDuty requires a detector in each region where you enable the service. The service allows only one detector per account per region.\n\n```javascript\nimport {\n  CreateDetectorCommand,\n  GuardDutyClient,\n  ListDetectorsCommand,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function getOrCreateDetectorId() {\n  const listed = await guardduty.send(new ListDetectorsCommand({}));\n  const existingDetectorId = listed.DetectorIds?.[0];\n\n  if (existingDetectorId) {\n    return existingDetectorId;\n  }\n\n  const created = await guardduty.send(\n    new CreateDetectorCommand({\n      Enable: true,\n      FindingPublishingFrequency: \"FIFTEEN_MINUTES\",\n    }),\n  );\n\n  if (!created.DetectorId) {\n    throw new Error(\"GuardDuty did not return a detector ID\");\n  }\n\n  return created.DetectorId;\n}\n```\n\n`FindingPublishingFrequency` accepts `FIFTEEN_MINUTES`, `ONE_HOUR`, or `SIX_HOURS`.\n\n## Inspect or update detector settings\n\nUse `GetDetector` to inspect the current detector status, enabled data sources, and feature configuration. Use `UpdateDetector` to change the enabled state, publishing frequency, or configured features.\n\n```javascript\nimport {\n  GetDetectorCommand,\n  GuardDutyClient,\n  UpdateDetectorCommand,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function inspectAndUpdateDetector(detectorId) {\n  const before = await guardduty.send(\n    new GetDetectorCommand({ DetectorId: detectorId }),\n  );\n\n  console.log({\n    status: before.Status,\n    findingPublishingFrequency: before.FindingPublishingFrequency,\n    createdAt: before.CreatedAt,\n    updatedAt: before.UpdatedAt,\n  });\n\n  await guardduty.send(\n    new UpdateDetectorCommand({\n      DetectorId: detectorId,\n      Enable: true,\n      FindingPublishingFrequency: \"ONE_HOUR\",\n    }),\n  );\n}\n```\n\n## List findings and fetch full details\n\n`ListFindings` returns finding IDs. Use `GetFindings` with those IDs when you need the full finding payload.\n\n```javascript\nimport {\n  GetFindingsCommand,\n  GuardDutyClient,\n  ListFindingsCommand,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function listHighSeverityFindings(detectorId) {\n  const listed = await guardduty.send(\n    new ListFindingsCommand({\n      DetectorId: detectorId,\n      FindingCriteria: {\n        Criterion: {\n          severity: {\n            Gte: 7,\n          },\n        },\n      },\n      MaxResults: 20,\n    }),\n  );\n\n  const findingIds = listed.FindingIds ?? [];\n\n  if (findingIds.length === 0) {\n    return [];\n  }\n\n  const details = await guardduty.send(\n    new GetFindingsCommand({\n      DetectorId: detectorId,\n      FindingIds: findingIds,\n    }),\n  );\n\n  return (details.Findings ?? []).map((finding) => ({\n    id: finding.Id,\n    type: finding.Type,\n    title: finding.Title,\n    severity: finding.Severity,\n    resourceType: finding.Resource?.ResourceType,\n    archived: finding.Service?.Archived,\n    updatedAt: finding.UpdatedAt,\n  }));\n}\n```\n\nGuardDuty finding criteria supports many nested attributes. For severity bands, GuardDuty documents these numeric ranges:\n\n- low: `1` to `3`\n- medium: `4` to `6`\n- high: `7` to `8`\n- critical: `9` to `10`\n\nIf you need every page of results, keep following `NextToken` until it is absent.\n\n## Generate sample findings\n\nSample findings are useful when you need test data for dashboards, alerting, or downstream processing.\n\n```javascript\nimport {\n  CreateSampleFindingsCommand,\n  GuardDutyClient,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createSampleFindings(detectorId) {\n  await guardduty.send(\n    new CreateSampleFindingsCommand({\n      DetectorId: detectorId,\n    }),\n  );\n}\n```\n\n## Create a saved filter\n\nFilters let you store reusable finding criteria. `Action` can be `NOOP` or `ARCHIVE`.\n\n```javascript\nimport {\n  CreateFilterCommand,\n  GuardDutyClient,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createHighSeverityFilter(detectorId) {\n  const response = await guardduty.send(\n    new CreateFilterCommand({\n      DetectorId: detectorId,\n      Name: \"high-severity-findings\",\n      Description: \"Saved filter for GuardDuty findings with severity 7 or higher\",\n      Action: \"NOOP\",\n      Rank: 1,\n      FindingCriteria: {\n        Criterion: {\n          severity: {\n            Gte: 7,\n          },\n        },\n      },\n    }),\n  );\n\n  console.log(response.Name);\n}\n```\n\nUse `ARCHIVE` only when you intentionally want matching findings archived by the filter.\n\n## Create a trusted IP set from S3\n\n`CreateIPSet` creates what the GuardDuty console calls a trusted IP list. The source file must be in S3, and the request uses the file URI.\n\n```javascript\nimport {\n  CreateIPSetCommand,\n  GuardDutyClient,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createTrustedIpSet(detectorId) {\n  const response = await guardduty.send(\n    new CreateIPSetCommand({\n      DetectorId: detectorId,\n      Name: \"corp-egress-trusted-ips\",\n      Format: \"TXT\",\n      Location: \"s3://my-guardduty-lists/trusted-ips.txt\",\n      Activate: true,\n      ExpectedBucketOwner: \"123456789012\",\n    }),\n  );\n\n  return response.IpSetId;\n}\n```\n\nSupported IP set formats include `TXT`, `STIX`, `OTX_CSV`, `ALIEN_VAULT`, `PROOF_POINT`, and `FIRE_EYE`.\n\n## Export findings to S3\n\nGuardDuty can export findings to an S3 publishing destination. Today the destination type is `S3`, and you must provide both the destination ARN and the KMS key ARN used for encryption.\n\n```javascript\nimport {\n  CreatePublishingDestinationCommand,\n  DescribePublishingDestinationCommand,\n  GuardDutyClient,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createPublishingDestination(detectorId) {\n  const created = await guardduty.send(\n    new CreatePublishingDestinationCommand({\n      DetectorId: detectorId,\n      DestinationType: \"S3\",\n      DestinationProperties: {\n        DestinationArn: \"arn:aws:s3:::my-guardduty-exports/findings/\",\n        KmsKeyArn:\n          \"arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555\",\n      },\n    }),\n  );\n\n  if (!created.DestinationId) {\n    throw new Error(\"GuardDuty did not return a publishing destination ID\");\n  }\n\n  const destination = await guardduty.send(\n    new DescribePublishingDestinationCommand({\n      DetectorId: detectorId,\n      DestinationId: created.DestinationId,\n    }),\n  );\n\n  console.log({\n    destinationId: destination.DestinationId,\n    status: destination.Status,\n    destinationArn: destination.DestinationProperties?.DestinationArn,\n  });\n}\n```\n\nFor an S3 folder destination, AWS documents the ARN format as `arn:aws:s3:::DOC-EXAMPLE-BUCKET/myFolder/`.\n\n## Important GuardDuty gotchas\n\n- GuardDuty is regional. If you switch `region`, you are talking to a different detector and a different findings set.\n- `CreateDetector` does not create detectors globally. You must enable GuardDuty separately in each region you use.\n- GuardDuty supports only one detector per account per region, so call `ListDetectors` before creating a new one.\n- Data source availability can differ by region.\n- If you configure features on `CreateDetector` or `UpdateDetector`, do not specify both `EKS_RUNTIME_MONITORING` and `RUNTIME_MONITORING`; GuardDuty returns an error because runtime monitoring already includes EKS runtime threat detection.\n- When you specify some detector features, GuardDuty enables unspecified optional features by default, except `RUNTIME_MONITORING`.\n- `CreatePublishingDestination` requires the destination resource to exist first, and the destination type is currently only `S3`.\n- For S3-backed IP sets and exports, make sure the bucket and KMS permissions are correct for the GuardDuty service in that account and region.\n- Create-style APIs accept `ClientToken` idempotency tokens. Use them in retry-prone automation if duplicate creation would be a problem.\n\n## Minimal end-to-end example\n\n```javascript\nimport {\n  CreateDetectorCommand,\n  GetFindingsCommand,\n  GuardDutyClient,\n  ListDetectorsCommand,\n  ListFindingsCommand,\n} from \"@aws-sdk/client-guardduty\";\n\nconst guardduty = new GuardDutyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function main() {\n  const listed = await guardduty.send(new ListDetectorsCommand({}));\n\n  let detectorId = listed.DetectorIds?.[0];\n\n  if (!detectorId) {\n    const created = await guardduty.send(\n      new CreateDetectorCommand({\n        Enable: true,\n      }),\n    );\n\n    detectorId = created.DetectorId;\n  }\n\n  if (!detectorId) {\n    throw new Error(\"Unable to resolve a GuardDuty detector ID\");\n  }\n\n  const findingIdsPage = await guardduty.send(\n    new ListFindingsCommand({\n      DetectorId: detectorId,\n      MaxResults: 10,\n    }),\n  );\n\n  const findingIds = findingIdsPage.FindingIds ?? [];\n\n  if (findingIds.length === 0) {\n    console.log(\"No findings in this region\");\n    return;\n  }\n\n  const findings = await guardduty.send(\n    new GetFindingsCommand({\n      DetectorId: detectorId,\n      FindingIds: findingIds,\n    }),\n  );\n\n  for (const finding of findings.Findings ?? []) {\n    console.log({\n      id: finding.Id,\n      type: finding.Type,\n      severity: finding.Severity,\n      title: finding.Title,\n    });\n  }\n}\n\nmain().catch((error) => {\n  console.error(error);\n  process.exitCode = 1;\n});\n```\n"
  },
  {
    "path": "content/aws/docs/health/javascript/DOC.md",
    "content": "---\nname: health\ndescription: \"AWS SDK for JavaScript v3 client for AWS Health account and organization event APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,health,javascript,nodejs,operations,events\"\n---\n\n# `@aws-sdk/client-health`\n\nUse this package for the AWS Health API in JavaScript or Node.js. It lets you list AWS Health events, fetch detailed descriptions, and inspect affected entities for your account. It also includes organization-scoped operations for AWS Organizations setups.\n\nThis package is for **AWS Health service events**. It is not the SDK for Route 53 health checks, application health endpoints, or CloudWatch alarms.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-health\n```\n\nPrefer `HealthClient` with explicit command imports.\n\n## Prerequisites\n\n- AWS credentials that the SDK can resolve.\n- A configured AWS region. The examples below use `us-east-1`.\n- Access to AWS Health. Accounts without the required AWS Support plan can receive `SubscriptionRequiredException`.\n\nTypical local environment:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIn Node.js, the AWS SDK v3 can also load credentials from the shared config files, IAM Identity Center, ECS task roles, or EC2 instance roles.\n\n## Initialize the client\n\n```javascript\nimport { HealthClient } from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Core usage pattern\n\nEvery call follows the v3 client-plus-command pattern:\n\n```javascript\nimport {\n  HealthClient,\n  DescribeEventsCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\nconst response = await health.send(\n  new DescribeEventsCommand({\n    filter: {\n      services: [\"EC2\"],\n      eventStatusCodes: [\"open\", \"upcoming\"],\n      regions: [\"us-east-1\"],\n    },\n    maxResults: 10,\n  }),\n);\n\nfor (const event of response.events ?? []) {\n  console.log(event.arn, event.service, event.eventTypeCode, event.statusCode);\n}\n```\n\n## Common operations\n\n### List recent AWS Health events\n\nUse `DescribeEventsCommand` for account-scoped events.\n\n```javascript\nimport {\n  HealthClient,\n  DescribeEventsCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\nconst { events = [] } = await health.send(\n  new DescribeEventsCommand({\n    filter: {\n      services: [\"RDS\"],\n      eventStatusCodes: [\"open\", \"upcoming\"],\n    },\n    maxResults: 20,\n  }),\n);\n\nfor (const event of events) {\n  console.log({\n    arn: event.arn,\n    service: event.service,\n    type: event.eventTypeCode,\n    status: event.statusCode,\n    start: event.startTime,\n  });\n}\n```\n\nPut filters under `filter`. Common filters include service names, event status codes, event type codes, regions, and time ranges.\n\n### Get full descriptions for one or more events\n\n`DescribeEventsCommand` gives summary metadata. Use `DescribeEventDetailsCommand` when you need the full human-readable description.\n\n```javascript\nimport {\n  HealthClient,\n  DescribeEventDetailsCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\nconst eventArns = [\n  \"arn:aws:health:us-east-1::event/AWS_EC2_OPERATIONAL_ISSUE/AWS_EC2_OPERATIONAL_ISSUE_1234567890\",\n];\n\nconst { successfulSet = [], failedSet = [] } = await health.send(\n  new DescribeEventDetailsCommand({ eventArns }),\n);\n\nfor (const item of successfulSet) {\n  console.log(item.event?.arn);\n  console.log(item.eventDescription?.latestDescription);\n}\n\nfor (const item of failedSet) {\n  console.error(item.eventArn, item.errorName, item.errorMessage);\n}\n```\n\n### List affected entities for an event\n\nUse `DescribeAffectedEntitiesCommand` to see which resources are affected by a specific event.\n\n```javascript\nimport {\n  HealthClient,\n  DescribeAffectedEntitiesCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\nconst { entities = [] } = await health.send(\n  new DescribeAffectedEntitiesCommand({\n    filter: {\n      eventArns: [\n        \"arn:aws:health:us-east-1::event/AWS_EC2_OPERATIONAL_ISSUE/AWS_EC2_OPERATIONAL_ISSUE_1234567890\",\n      ],\n    },\n    maxResults: 50,\n  }),\n);\n\nfor (const entity of entities) {\n  console.log({\n    entityArn: entity.entityArn,\n    entityValue: entity.entityValue,\n    status: entity.statusCode,\n    lastUpdatedTime: entity.lastUpdatedTime,\n  });\n}\n```\n\nIf you already know the resource identifiers you care about, add `entityValues` to the filter to narrow the result set.\n\n### Read organization-wide events\n\nIf AWS Health organizational view is enabled, use the organization operations instead of the account-scoped ones.\n\n```javascript\nimport {\n  HealthClient,\n  DescribeEventsForOrganizationCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\nconst { events = [] } = await health.send(\n  new DescribeEventsForOrganizationCommand({\n    filter: {\n      services: [\"S3\"],\n      eventStatusCodes: [\"open\"],\n    },\n    maxResults: 20,\n  }),\n);\n\nfor (const event of events) {\n  console.log(event.arn, event.service, event.statusCode);\n}\n```\n\nOrganization APIs are for the management account or a delegated administrator account with AWS Health organizational access enabled.\n\n## Error handling\n\n`SubscriptionRequiredException` is the first error to check when an otherwise valid request fails immediately.\n\n```javascript\nimport {\n  HealthClient,\n  DescribeEventsCommand,\n} from \"@aws-sdk/client-health\";\n\nconst health = new HealthClient({ region: \"us-east-1\" });\n\ntry {\n  await health.send(\n    new DescribeEventsCommand({\n      filter: { eventStatusCodes: [\"open\"] },\n      maxResults: 5,\n    }),\n  );\n} catch (error) {\n  if (error?.name === \"SubscriptionRequiredException\") {\n    console.error(\"AWS Health API access requires a supported AWS Support plan.\");\n  }\n\n  throw error;\n}\n```\n\n## AWS Health gotchas\n\n- This client is for AWS-originated health events. It does not create health checks for your own URLs or services.\n- Use account-scoped commands such as `DescribeEventsCommand` for the current account, and organization-scoped commands such as `DescribeEventsForOrganizationCommand` only when organizational view is enabled.\n- Event descriptions are a separate read. Fetch summaries with `DescribeEventsCommand`, then call `DescribeEventDetailsCommand` when you need the long description text.\n- Affected resources are a separate read too. Use `DescribeAffectedEntitiesCommand` after you have the event ARN.\n- Health responses are filter-driven. Put service names, status codes, regions, and time filters inside the nested `filter` object.\n- Do not deep-import package internals from generated build paths.\n\n## When to use other packages\n\n- `@aws-sdk/client-route-53`: Route 53 DNS and Route 53 health checks.\n- `@aws-sdk/client-cloudwatch`: metrics, alarms, and dashboards.\n- `@aws-sdk/credential-providers`: explicit credential providers such as shared config, IAM Identity Center, Cognito, or assume-role helpers.\n"
  },
  {
    "path": "content/aws/docs/healthlake/javascript/DOC.md",
    "content": "---\nname: healthlake\ndescription: \"AWS SDK for JavaScript v3 client for Amazon HealthLake datastore management and bulk data jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,healthlake,fhir,healthcare,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-healthlake`\n\nUse `@aws-sdk/client-healthlake` for the **HealthLake control plane** in JavaScript: creating, listing, describing, and deleting FHIR datastores, plus starting and tracking bulk import and export jobs.\n\nThis package does **not** replace the FHIR REST endpoint exposed by an active datastore. After a datastore is active, use its `DatastoreEndpoint` for FHIR reads and writes.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-healthlake\n```\n\nIf you need explicit profile-based credential loading in code, also install:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Credentials and region\n\nHealthLake uses the standard AWS SDK for JavaScript v3 credential chain. In local development, the simplest setup is usually a named profile plus a region:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n```\n\nDirect environment credentials also work:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nFor import and export examples, set these too:\n\n```bash\nexport HEALTHLAKE_DATASTORE_ID=your-datastore-id\nexport HEALTHLAKE_DATA_ACCESS_ROLE_ARN=arn:aws:iam::123456789012:role/HealthLakeDataAccessRole\nexport HEALTHLAKE_INPUT_S3_URI=s3://your-input-bucket/path/\nexport HEALTHLAKE_OUTPUT_S3_URI=s3://your-output-bucket/path/\n```\n\n## Initialize the client\n\n```javascript\nimport { HealthLakeClient } from \"@aws-sdk/client-healthlake\";\n\nexport const healthlake = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nThe normal v3 pattern is:\n\n```javascript\nconst response = await healthlake.send(new SomeCommand(input));\n```\n\n## Common workflows\n\n### Create a FHIR datastore\n\nHealthLake datastore creation is asynchronous. Start the create call, keep the returned datastore ID, then poll until the datastore becomes active.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  CreateFHIRDatastoreCommand,\n  DescribeFHIRDatastoreCommand,\n  HealthLakeClient,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst created = await client.send(\n  new CreateFHIRDatastoreCommand({\n    DatastoreName: \"claims-r4-demo\",\n    DatastoreTypeVersion: \"R4\",\n  }),\n);\n\nconst datastoreId = created.DatastoreId;\n\nif (!datastoreId) {\n  throw new Error(\"CreateFHIRDatastore did not return a DatastoreId\");\n}\n\nfor (;;) {\n  const described = await client.send(\n    new DescribeFHIRDatastoreCommand({\n      DatastoreId: datastoreId,\n    }),\n  );\n\n  const properties = described.DatastoreProperties ?? described;\n  const status = properties.DatastoreStatus;\n\n  console.log({\n    datastoreId,\n    status,\n    endpoint: properties.DatastoreEndpoint,\n  });\n\n  if (status === \"ACTIVE\") {\n    break;\n  }\n\n  if (typeof status === \"string\" && status.endsWith(\"_FAILED\")) {\n    throw new Error(`Datastore creation failed with status ${status}`);\n  }\n\n  await sleep(15000);\n}\n```\n\nUse `DatastoreTypeVersion: \"R4\"` for a FHIR R4 datastore.\n\n### List existing datastores\n\n```javascript\nimport {\n  HealthLakeClient,\n  ListFHIRDatastoresCommand,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ListFHIRDatastoresCommand({\n    MaxResults: 20,\n  }),\n);\n\nfor (const datastore of response.DatastorePropertiesList ?? []) {\n  console.log({\n    datastoreId: datastore.DatastoreId,\n    name: datastore.DatastoreName,\n    status: datastore.DatastoreStatus,\n    createdAt: datastore.CreatedAt,\n  });\n}\n```\n\n### Inspect one datastore and get its endpoint\n\nUse `DescribeFHIRDatastoreCommand` when you need the endpoint, status, or other details for one datastore.\n\n```javascript\nimport {\n  DescribeFHIRDatastoreCommand,\n  HealthLakeClient,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst datastoreId = process.env.HEALTHLAKE_DATASTORE_ID;\n\nif (!datastoreId) {\n  throw new Error(\"Set HEALTHLAKE_DATASTORE_ID first\");\n}\n\nconst response = await client.send(\n  new DescribeFHIRDatastoreCommand({\n    DatastoreId: datastoreId,\n  }),\n);\n\nconst properties = response.DatastoreProperties ?? response;\n\nconsole.log({\n  datastoreId: properties.DatastoreId,\n  status: properties.DatastoreStatus,\n  endpoint: properties.DatastoreEndpoint,\n  datastoreArn: properties.DatastoreArn,\n});\n```\n\nThe `DatastoreEndpoint` is the base URL for FHIR API traffic after the datastore is active.\n\n### Start and poll a bulk import job\n\nUse HealthLake import jobs when your FHIR data already lives in Amazon S3.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  DescribeFHIRImportJobCommand,\n  HealthLakeClient,\n  StartFHIRImportJobCommand,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst datastoreId = process.env.HEALTHLAKE_DATASTORE_ID;\nconst dataAccessRoleArn = process.env.HEALTHLAKE_DATA_ACCESS_ROLE_ARN;\nconst inputS3Uri = process.env.HEALTHLAKE_INPUT_S3_URI;\nconst outputS3Uri = process.env.HEALTHLAKE_OUTPUT_S3_URI;\n\nif (!datastoreId || !dataAccessRoleArn || !inputS3Uri || !outputS3Uri) {\n  throw new Error(\n    \"Set HEALTHLAKE_DATASTORE_ID, HEALTHLAKE_DATA_ACCESS_ROLE_ARN, HEALTHLAKE_INPUT_S3_URI, and HEALTHLAKE_OUTPUT_S3_URI\",\n  );\n}\n\nconst started = await client.send(\n  new StartFHIRImportJobCommand({\n    DatastoreId: datastoreId,\n    JobName: \"initial-import\",\n    DataAccessRoleArn: dataAccessRoleArn,\n    InputDataConfig: {\n      S3Uri: inputS3Uri,\n    },\n    JobOutputDataConfig: {\n      S3Configuration: {\n        S3Uri: outputS3Uri,\n      },\n    },\n  }),\n);\n\nconst jobId = started.JobId;\n\nif (!jobId) {\n  throw new Error(\"StartFHIRImportJob did not return a JobId\");\n}\n\nfor (;;) {\n  const detail = await client.send(\n    new DescribeFHIRImportJobCommand({\n      DatastoreId: datastoreId,\n      JobId: jobId,\n    }),\n  );\n\n  const job = detail.ImportJobProperties ?? detail;\n  const status = job.JobStatus;\n\n  console.log({ jobId, status, message: job.Message });\n\n  if (status === \"COMPLETED\") {\n    break;\n  }\n\n  if (status === \"FAILED\" || status === \"CANCELLED\") {\n    throw new Error(`Import job ended with status ${status}`);\n  }\n\n  await sleep(15000);\n}\n```\n\nThe caller needs permission to start the job, and `DataAccessRoleArn` must grant HealthLake access to the S3 locations used by the job.\n\n### Start and poll a bulk export job\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  DescribeFHIRExportJobCommand,\n  HealthLakeClient,\n  StartFHIRExportJobCommand,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst datastoreId = process.env.HEALTHLAKE_DATASTORE_ID;\nconst dataAccessRoleArn = process.env.HEALTHLAKE_DATA_ACCESS_ROLE_ARN;\nconst outputS3Uri = process.env.HEALTHLAKE_OUTPUT_S3_URI;\n\nif (!datastoreId || !dataAccessRoleArn || !outputS3Uri) {\n  throw new Error(\n    \"Set HEALTHLAKE_DATASTORE_ID, HEALTHLAKE_DATA_ACCESS_ROLE_ARN, and HEALTHLAKE_OUTPUT_S3_URI\",\n  );\n}\n\nconst started = await client.send(\n  new StartFHIRExportJobCommand({\n    DatastoreId: datastoreId,\n    JobName: \"daily-export\",\n    DataAccessRoleArn: dataAccessRoleArn,\n    OutputDataConfig: {\n      S3Configuration: {\n        S3Uri: outputS3Uri,\n      },\n    },\n  }),\n);\n\nconst jobId = started.JobId;\n\nif (!jobId) {\n  throw new Error(\"StartFHIRExportJob did not return a JobId\");\n}\n\nfor (;;) {\n  const detail = await client.send(\n    new DescribeFHIRExportJobCommand({\n      DatastoreId: datastoreId,\n      JobId: jobId,\n    }),\n  );\n\n  const job = detail.ExportJobProperties ?? detail;\n  const status = job.JobStatus;\n\n  console.log({ jobId, status, message: job.Message });\n\n  if (status === \"COMPLETED\") {\n    break;\n  }\n\n  if (status === \"FAILED\" || status === \"CANCELLED\") {\n    throw new Error(`Export job ended with status ${status}`);\n  }\n\n  await sleep(15000);\n}\n```\n\n### Delete a datastore\n\nDeletion is also asynchronous. After you call delete, keep polling until the datastore is gone.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  DeleteFHIRDatastoreCommand,\n  DescribeFHIRDatastoreCommand,\n  HealthLakeClient,\n} from \"@aws-sdk/client-healthlake\";\n\nconst client = new HealthLakeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst datastoreId = process.env.HEALTHLAKE_DATASTORE_ID;\n\nif (!datastoreId) {\n  throw new Error(\"Set HEALTHLAKE_DATASTORE_ID first\");\n}\n\nawait client.send(\n  new DeleteFHIRDatastoreCommand({\n    DatastoreId: datastoreId,\n  }),\n);\n\nfor (;;) {\n  try {\n    const described = await client.send(\n      new DescribeFHIRDatastoreCommand({\n        DatastoreId: datastoreId,\n      }),\n    );\n\n    const properties = described.DatastoreProperties ?? described;\n    console.log(properties.DatastoreStatus);\n    await sleep(15000);\n  } catch (error) {\n    console.log(\"Datastore no longer available\", error);\n    break;\n  }\n}\n```\n\n## Important gotchas\n\n- `@aws-sdk/client-healthlake` manages datastores and batch jobs. It does not expose FHIR resource CRUD commands; use the datastore endpoint for FHIR API requests.\n- Datastore creation, deletion, imports, and exports are asynchronous. Do not assume the resource is ready immediately after `CreateFHIRDatastoreCommand`, `DeleteFHIRDatastoreCommand`, `StartFHIRImportJobCommand`, or `StartFHIRExportJobCommand`.\n- Import and export jobs need `DataAccessRoleArn` in addition to the AWS credentials your application uses to call HealthLake.\n- Use S3 URIs such as `s3://bucket/prefix/` for import and export locations. Local file paths are not valid job inputs.\n- HealthLake is regional. Use the same region consistently for the client, the datastore, the S3 buckets you reference, and any KMS keys or IAM roles tied to the workflow.\n- Wait for `DatastoreStatus` to become `ACTIVE` before using `DatastoreEndpoint`.\n\n## When to reach for other packages\n\n- `@aws-sdk/credential-providers` for explicit `fromIni`, SSO, or assume-role credential loading.\n- Other AWS SDK v3 clients such as S3, IAM, or KMS when your HealthLake workflow also provisions storage, IAM roles, or encryption resources.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-healthlake` version `3.1007.0`.\n- Examples use the AWS SDK for JavaScript v3 command pattern: `client.send(new Command(input))`.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 HealthLake client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/healthlake/`\n- Amazon HealthLake API Reference: `https://docs.aws.amazon.com/healthlake/latest/APIReference/Welcome.html`\n- `CreateFHIRDatastore`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_CreateFHIRDatastore.html`\n- `DescribeFHIRDatastore`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_DescribeFHIRDatastore.html`\n- `ListFHIRDatastores`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_ListFHIRDatastores.html`\n- `DeleteFHIRDatastore`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_DeleteFHIRDatastore.html`\n- `StartFHIRImportJob`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_StartFHIRImportJob.html`\n- `DescribeFHIRImportJob`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_DescribeFHIRImportJob.html`\n- `StartFHIRExportJob`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_StartFHIRExportJob.html`\n- `DescribeFHIRExportJob`: `https://docs.aws.amazon.com/healthlake/latest/APIReference/API_DescribeFHIRExportJob.html`\n"
  },
  {
    "path": "content/aws/docs/iam/javascript/DOC.md",
    "content": "---\nname: iam\ndescription: \"AWS SDK for JavaScript v3 IAM client for users, roles, policies, and access key management.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,iam,javascript,nodejs,identity,access-management,policies,roles\"\n---\n\n# `@aws-sdk/client-iam`\n\nUse this package for AWS Identity and Access Management in AWS SDK for JavaScript v3. It covers account-level IAM resources such as users, groups, roles, managed policy attachments, inline policies, login profiles, and access keys.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-iam\n```\n\nPrefer `IAMClient` plus explicit command imports. The package also exposes an aggregated `IAM` client, but command-based imports are the safer default for smaller bundles and clearer call sites.\n\n## Client Setup\n\n```javascript\nimport { IAMClient } from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n```\n\nIAM is a global AWS service, but the SDK still expects normal client configuration. In practice, set a region such as `us-east-1` or rely on your standard AWS region configuration.\n\n## Credentials and Runtime Notes\n\n- In Node.js, the default credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n- IAM administration usually belongs on trusted backends, not in browser code.\n- Avoid long-lived IAM user access keys when temporary role credentials will work.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n```javascript\nimport {\n  GetRoleCommand,\n  IAMClient,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst response = await iam.send(\n  new GetRoleCommand({\n    RoleName: \"app-worker-role\",\n  }),\n);\n\nconsole.log(response.Role?.Arn);\n```\n\n## Common Operations\n\n### Create a role with a trust policy\n\n`AssumeRolePolicyDocument` must be a JSON string, not a plain JavaScript object.\n\n```javascript\nimport {\n  CreateRoleCommand,\n  IAMClient,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst trustPolicy = JSON.stringify({\n  Version: \"2012-10-17\",\n  Statement: [\n    {\n      Effect: \"Allow\",\n      Principal: { Service: \"lambda.amazonaws.com\" },\n      Action: \"sts:AssumeRole\",\n    },\n  ],\n});\n\nconst { Role } = await iam.send(\n  new CreateRoleCommand({\n    RoleName: \"app-worker-role\",\n    AssumeRolePolicyDocument: trustPolicy,\n    Description: \"Execution role for background workers\",\n  }),\n);\n\nconsole.log(Role?.Arn);\n```\n\n### Attach an AWS managed policy to a role\n\n```javascript\nimport {\n  AttachRolePolicyCommand,\n  IAMClient,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nawait iam.send(\n  new AttachRolePolicyCommand({\n    RoleName: \"app-worker-role\",\n    PolicyArn:\n      \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\",\n  }),\n);\n```\n\n### List users with pagination\n\n```javascript\nimport {\n  IAMClient,\n  paginateListUsers,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListUsers({ client: iam }, {})) {\n  for (const user of page.Users ?? []) {\n    console.log(user.UserName, user.Arn);\n  }\n}\n```\n\n## IAM-Specific Gotchas\n\n- Trust policies and inline policy documents are JSON strings on write.\n- Some IAM read APIs return policy documents in URL-encoded form. Decode them before `JSON.parse`.\n- IAM is eventually consistent for many create, update, and delete flows, so follow-up calls may need retry/backoff.\n- Managed policy attachment APIs require a full `PolicyArn`, not just a policy name.\n- A role's trust policy controls who can assume it; attached or inline permission policies control what it can do after assumption.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-sts`: assume roles, inspect caller identity, and obtain temporary credentials.\n- `@aws-sdk/credential-providers`: `fromIni`, IAM Identity Center, web identity, and other credential helpers.\n\n## Common IAM Operations\n\n### Create a user\n\n```javascript\nimport {\n  CreateUserCommand,\n  IAMClient,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst { User } = await iam.send(\n  new CreateUserCommand({\n    UserName: \"ci-bot\",\n    Path: \"/automation/\",\n  }),\n);\n\nconsole.log(User?.Arn);\n```\n\n### Get and decode a role trust policy\n\nSome IAM policy documents come back URL-encoded.\n\n```javascript\nimport {\n  GetRoleCommand,\n  IAMClient,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst { Role } = await iam.send(\n  new GetRoleCommand({\n    RoleName: \"app-worker-role\",\n  }),\n);\n\nconst trustPolicy = Role?.AssumeRolePolicyDocument\n  ? JSON.parse(decodeURIComponent(Role.AssumeRolePolicyDocument))\n  : null;\n\nconsole.log(trustPolicy);\n```\n\n### Put an inline role policy\n\n`PolicyDocument` is a JSON string.\n\n```javascript\nimport {\n  IAMClient,\n  PutRolePolicyCommand,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst policyDocument = JSON.stringify({\n  Version: \"2012-10-17\",\n  Statement: [\n    {\n      Effect: \"Allow\",\n      Action: [\"s3:GetObject\"],\n      Resource: [\"arn:aws:s3:::example-bucket/*\"],\n    },\n  ],\n});\n\nawait iam.send(\n  new PutRolePolicyCommand({\n    RoleName: \"app-worker-role\",\n    PolicyName: \"read-example-bucket\",\n    PolicyDocument: policyDocument,\n  }),\n);\n```\n\n### List attached role policies\n\n```javascript\nimport {\n  IAMClient,\n  ListAttachedRolePoliciesCommand,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nconst { AttachedPolicies = [] } = await iam.send(\n  new ListAttachedRolePoliciesCommand({\n    RoleName: \"app-worker-role\",\n  }),\n);\n\nfor (const policy of AttachedPolicies) {\n  console.log(policy.PolicyName, policy.PolicyArn);\n}\n```\n\n### List roles with pagination\n\n```javascript\nimport {\n  IAMClient,\n  paginateListRoles,\n} from \"@aws-sdk/client-iam\";\n\nconst iam = new IAMClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListRoles({ client: iam }, { PathPrefix: \"/\" })) {\n  for (const role of page.Roles ?? []) {\n    console.log(role.RoleName, role.Arn);\n  }\n}\n```\n\nIf you need stronger read-after-write behavior after `CreateRole`, retry `GetRole` or the dependent downstream call with backoff.\n"
  },
  {
    "path": "content/aws/docs/inspector2/javascript/DOC.md",
    "content": "---\nname: inspector2\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Inspector account status, findings, coverage, deep inspection, and findings report workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,inspector,inspector2,security,vulnerability,ec2,ecr,lambda,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-inspector2`\n\nUse this package to work with Amazon Inspector from JavaScript or TypeScript. The client covers account enablement and status, findings, coverage, EC2 deep inspection configuration, findings reports, organization/member operations, and newer code security and SBOM APIs.\n\nAmazon Inspector is regional. Set `region` explicitly or provide it through the normal AWS SDK configuration chain.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-inspector2`, not the legacy `aws-sdk` v2 package.\n- Use the standard AWS SDK v3 credential chain; this package does not handle credentials by itself.\n- The service name is `inspector2`.\n- Enable Inspector in the target account and region before expecting coverage or findings.\n- `ListFindingsCommand` and `ListCoverageCommand` paginate with `nextToken`.\n- `CreateFindingsReportCommand` requires both an S3 destination and a KMS key ARN.\n- Findings reports return only `ACTIVE` findings by default; add a `findingStatus` filter if you need `SUPPRESSED` or `CLOSED` findings too.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-inspector2\n```\n\nTypical environment variables:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\" # optional when using shared AWS config\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional, for temporary credentials\nexport AWS_ACCOUNT_ID=\"123456789012\"\nexport INSPECTOR_REPORT_BUCKET=\"example-inspector-reports\"\nexport INSPECTOR_REPORT_KMS_KEY_ARN=\"arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012\"\n```\n\n`AWS_ACCOUNT_ID` is not required by the SDK, but it is useful for account-status and account-targeted enablement calls.\n\n## Prerequisites\n\nInspector uses the normal AWS SDK for JavaScript v3 authentication flow in Node.js. Environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance roles all work with the usual SDK behavior.\n\nYour IAM principal also needs Inspector permissions for the operations you call. Common setup problems are usually one of these:\n\n- Inspector is not enabled in the target region yet\n- the caller lacks Inspector or KMS or S3 permissions\n- the code points at the wrong AWS account or region\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { Inspector2Client } from \"@aws-sdk/client-inspector2\";\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { Inspector2Client } from \"@aws-sdk/client-inspector2\";\n\nconst inspector2 = new Inspector2Client({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  BatchGetAccountStatusCommand,\n  Inspector2Client,\n} from \"@aws-sdk/client-inspector2\";\n\nconst accountId = process.env.AWS_ACCOUNT_ID;\n\nif (!accountId) {\n  throw new Error(\"Set AWS_ACCOUNT_ID.\");\n}\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await inspector2.send(\n  new BatchGetAccountStatusCommand({\n    accountIds: [accountId],\n  }),\n);\n\nconsole.log(response.accounts?.[0]);\n```\n\n## Common Workflows\n\n### Inspect account status and enable scan types\n\nUse `BatchGetAccountStatusCommand` to read current account state. Use `EnableCommand` to enable specific resource scan types.\n\n```javascript\nimport {\n  BatchGetAccountStatusCommand,\n  EnableCommand,\n  Inspector2Client,\n} from \"@aws-sdk/client-inspector2\";\n\nconst accountId = process.env.AWS_ACCOUNT_ID;\n\nif (!accountId) {\n  throw new Error(\"Set AWS_ACCOUNT_ID.\");\n}\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst before = await inspector2.send(\n  new BatchGetAccountStatusCommand({\n    accountIds: [accountId],\n  }),\n);\n\nconsole.log(before.accounts?.[0]);\n\nawait inspector2.send(\n  new EnableCommand({\n    accountIds: [accountId],\n    resourceTypes: [\"EC2\", \"ECR\", \"LAMBDA\"],\n  }),\n);\n```\n\n`resourceTypes` currently supports `EC2`, `ECR`, `LAMBDA`, `LAMBDA_CODE`, and `CODE_REPOSITORY`.\n\nFor multi-account or organization workflows, the delegated-administrator and member APIs are separate operations on the same client.\n\n### List findings with filters and pagination\n\n`ListFindingsCommand` already returns finding objects, so you can usually work directly from the response without a second fetch.\n\n```javascript\nimport {\n  Inspector2Client,\n  ListFindingsCommand,\n} from \"@aws-sdk/client-inspector2\";\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function listCriticalEc2Findings() {\n  const findings = [];\n  let nextToken;\n\n  do {\n    const page = await inspector2.send(\n      new ListFindingsCommand({\n        maxResults: 100,\n        nextToken,\n        filterCriteria: {\n          severity: [{ comparison: \"EQUALS\", value: \"CRITICAL\" }],\n          resourceType: [\n            { comparison: \"EQUALS\", value: \"AWS_EC2_INSTANCE\" },\n          ],\n        },\n        sortCriteria: {\n          field: \"LAST_OBSERVED_AT\",\n          sortOrder: \"DESC\",\n        },\n      }),\n    );\n\n    for (const finding of page.findings ?? []) {\n      findings.push({\n        findingArn: finding.findingArn,\n        title: finding.title,\n        severity: finding.severity,\n        status: finding.status,\n        inspectorScore: finding.inspectorScore,\n        vulnerabilityId:\n          finding.packageVulnerabilityDetails?.vulnerabilityId,\n        resourceType: finding.resources?.[0]?.type,\n        resourceId: finding.resources?.[0]?.id,\n        lastObservedAt: finding.lastObservedAt,\n      });\n    }\n\n    nextToken = page.nextToken;\n  } while (nextToken);\n\n  return findings;\n}\n```\n\nCommon string filters use `comparison` values `EQUALS`, `PREFIX`, or `NOT_EQUALS`. The findings filter model also supports date ranges, numeric ranges, tags, vulnerable package fields, EPSS score, and code repository fields.\n\n### List scan coverage for resources\n\nUse `ListCoverageCommand` when you need to know which resources Inspector is scanning and their scan status.\n\n```javascript\nimport {\n  Inspector2Client,\n  ListCoverageCommand,\n} from \"@aws-sdk/client-inspector2\";\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function listEc2PackageCoverage() {\n  const coveredResources = [];\n  let nextToken;\n\n  do {\n    const page = await inspector2.send(\n      new ListCoverageCommand({\n        maxResults: 100,\n        nextToken,\n        filterCriteria: {\n          resourceType: [\n            { comparison: \"EQUALS\", value: \"AWS_EC2_INSTANCE\" },\n          ],\n          scanType: [{ comparison: \"EQUALS\", value: \"PACKAGE\" }],\n        },\n      }),\n    );\n\n    for (const item of page.coveredResources ?? []) {\n      coveredResources.push({\n        accountId: item.accountId,\n        resourceType: item.resourceType,\n        resourceId: item.resourceId,\n        scanType: item.scanType,\n        scanStatusCode: item.scanStatus?.statusCode,\n        scanStatusReason: item.scanStatus?.reason,\n        scanMode: item.scanMode,\n        lastScannedAt: item.lastScannedAt,\n      });\n    }\n\n    nextToken = page.nextToken;\n  } while (nextToken);\n\n  return coveredResources;\n}\n```\n\nCoverage filters are separate from findings filters. For coverage, common fields include `resourceType`, `scanType`, `scanStatusCode`, `accountId`, `lastScannedAt`, ECR metadata, Lambda metadata, and code repository metadata.\n\n### Read or update EC2 deep inspection configuration\n\nUse `GetEc2DeepInspectionConfigurationCommand` to read the current configuration and `UpdateEc2DeepInspectionConfigurationCommand` to activate or update custom package paths.\n\n```javascript\nimport {\n  GetEc2DeepInspectionConfigurationCommand,\n  Inspector2Client,\n  UpdateEc2DeepInspectionConfigurationCommand,\n} from \"@aws-sdk/client-inspector2\";\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst current = await inspector2.send(\n  new GetEc2DeepInspectionConfigurationCommand({}),\n);\n\nconsole.log({\n  status: current.status,\n  packagePaths: current.packagePaths,\n  orgPackagePaths: current.orgPackagePaths,\n  errorMessage: current.errorMessage,\n});\n\nawait inspector2.send(\n  new UpdateEc2DeepInspectionConfigurationCommand({\n    activateDeepInspection: true,\n    packagePaths: [\"/usr/lib\", \"/usr/local/lib\"],\n  }),\n);\n```\n\nDeep inspection status values are `ACTIVATED`, `DEACTIVATED`, `PENDING`, and `FAILED`.\n\nIf you manage custom paths, read the current configuration first and then write the full path list you want to keep.\n\n### Export a findings report to S3 and poll for completion\n\nUse `CreateFindingsReportCommand` to start the export and `GetFindingsReportStatusCommand` to poll until the report finishes.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  CreateFindingsReportCommand,\n  GetFindingsReportStatusCommand,\n  Inspector2Client,\n} from \"@aws-sdk/client-inspector2\";\n\nconst bucketName = process.env.INSPECTOR_REPORT_BUCKET;\nconst kmsKeyArn = process.env.INSPECTOR_REPORT_KMS_KEY_ARN;\n\nif (!bucketName || !kmsKeyArn) {\n  throw new Error(\n    \"Set INSPECTOR_REPORT_BUCKET and INSPECTOR_REPORT_KMS_KEY_ARN.\",\n  );\n}\n\nconst inspector2 = new Inspector2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { reportId } = await inspector2.send(\n  new CreateFindingsReportCommand({\n    reportFormat: \"JSON\",\n    s3Destination: {\n      bucketName,\n      keyPrefix: \"inspector2/reports\",\n      kmsKeyArn,\n    },\n    filterCriteria: {\n      severity: [{ comparison: \"EQUALS\", value: \"CRITICAL\" }],\n    },\n  }),\n);\n\nif (!reportId) {\n  throw new Error(\"Inspector did not return a report ID.\");\n}\n\nwhile (true) {\n  const status = await inspector2.send(\n    new GetFindingsReportStatusCommand({ reportId }),\n  );\n\n  console.log(status.status, status.destination);\n\n  if (status.status === \"SUCCEEDED\") {\n    break;\n  }\n\n  if (status.status === \"FAILED\" || status.status === \"CANCELLED\") {\n    throw new Error(\n      `${status.errorCode ?? \"REPORT_FAILED\"}: ${status.errorMessage ?? \"Findings report did not complete.\"}`,\n    );\n  }\n\n  await sleep(2000);\n}\n```\n\n`reportFormat` accepts `CSV` or `JSON`.\n\n## Common Pitfalls\n\n- The package and service name are `inspector2`. Do not guess older names like `inspector`.\n- Empty result sets are often a region or account mismatch, not an SDK problem.\n- Findings and coverage list operations paginate; keep following `nextToken` until it is absent.\n- Findings report exports need S3 write permissions and a valid KMS key ARN.\n- Report status errors can include `INVALID_PERMISSIONS`, `BUCKET_NOT_FOUND`, `INCOMPATIBLE_BUCKET_REGION`, and `MALFORMED_KMS_KEY`.\n- `CreateFindingsReportCommand` returns only `ACTIVE` findings unless you explicitly filter for other finding statuses.\n- Updating deep inspection configuration writes the package path list you provide; fetch current settings first if you need merge behavior.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-inspector2` version `3.1007.0`.\n- At this version line, the client surface includes account status APIs, coverage and findings APIs, report export APIs, EC2 deep inspection APIs, and additional code-security, CIS, and SBOM operations.\n\n## Official Sources\n\n- `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/inspector2/`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/index.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/batch-get-account-status.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/enable.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/list-findings.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/list-coverage.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/get-ec2-deep-inspection-configuration.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/update-ec2-deep-inspection-configuration.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/create-findings-report.html`\n- `https://docs.aws.amazon.com/cli/latest/reference/inspector2/get-findings-report-status.html`\n"
  },
  {
    "path": "content/aws/docs/iot/javascript/DOC.md",
    "content": "---\nname: iot\ndescription: \"AWS SDK for JavaScript v3 client for AWS IoT Core control-plane APIs, including things, certificates, policies, endpoints, and related registry operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,iot,javascript,nodejs,iot-core,certificates,things,policies\"\n---\n\n# `@aws-sdk/client-iot`\n\nUse this package for AWS IoT Core control-plane APIs in AWS SDK for JavaScript v3. It covers registry and account management tasks such as creating things, looking up IoT endpoints, issuing certificates, creating policies, and attaching principals to things.\n\nThis client does not open MQTT connections or publish device messages. Use it to manage AWS IoT resources; use an AWS IoT data-plane or device SDK when you need runtime messaging.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-iot\n```\n\nIf you need explicit credential helpers such as assume-role, IAM Identity Center, or Cognito in application code, install the matching provider package too:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nConfigure AWS credentials and a region before you create the client:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nFor local development with a shared profile:\n\n```bash\naws configure --profile iot-dev\nexport AWS_PROFILE=\"iot-dev\"\nexport AWS_REGION=\"us-east-1\"\n```\n\nAWS IoT Core resources are regional. The client region must match the region where your things, certificates, policies, and endpoints live.\n\n## Client setup\n\n### Minimal Node.js client\n\n```javascript\nimport { IoTClient } from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { IoTClient } from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if you already configured environment variables, a shared AWS profile, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core usage pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeThingCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({ region: \"us-east-1\" });\n\nconst response = await iot.send(\n  new DescribeThingCommand({\n    thingName: \"sensor-123\",\n  }),\n);\n\nconsole.log(response.thingName, response.thingArn, response.attributes);\n```\n\n## Common workflows\n\n### Create a thing in the registry\n\nUse `CreateThingCommand` to register a device identity in the thing registry.\n\n```javascript\nimport {\n  CreateThingCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await iot.send(\n  new CreateThingCommand({\n    thingName: \"sensor-123\",\n    attributePayload: {\n      attributes: {\n        site: \"plant-1\",\n        model: \"motor-monitor\",\n      },\n      merge: false,\n    },\n  }),\n);\n\nconsole.log(response.thingName, response.thingArn, response.thingId);\n```\n\n### List and describe things\n\nList operations return `nextToken` when more results are available.\n\n```javascript\nimport {\n  DescribeThingCommand,\n  IoTClient,\n  ListThingsCommand,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await iot.send(\n    new ListThingsCommand({\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const thing of page.things ?? []) {\n    console.log(thing.thingName, thing.thingArn);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n\nconst detail = await iot.send(\n  new DescribeThingCommand({\n    thingName: \"sensor-123\",\n  }),\n);\n\nconsole.log(detail.thingName, detail.thingTypeName, detail.attributes);\n```\n\n### Look up the account endpoint for device or data-plane clients\n\n`DescribeEndpointCommand` returns the account-specific endpoint address for a given endpoint type. `iot:Data-ATS` is the common endpoint type to use for ATS-signed data endpoints.\n\n```javascript\nimport {\n  DescribeEndpointCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await iot.send(\n  new DescribeEndpointCommand({\n    endpointType: \"iot:Data-ATS\",\n  }),\n);\n\nconsole.log(response.endpointAddress);\n```\n\n### Create device keys and a certificate\n\n`CreateKeysAndCertificateCommand` can create an active certificate and return the private key material in the same response.\n\nStore the private key immediately. AWS IoT does not return the private key again later.\n\n```javascript\nimport { writeFile } from \"node:fs/promises\";\nimport {\n  CreateKeysAndCertificateCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await iot.send(\n  new CreateKeysAndCertificateCommand({\n    setAsActive: true,\n  }),\n);\n\nconst certificateArn = response.certificateArn;\nconst certificatePem = response.certificatePem;\nconst privateKey = response.keyPair?.PrivateKey;\n\nif (!certificateArn || !certificatePem || !privateKey) {\n  throw new Error(\"AWS IoT did not return the expected certificate materials\");\n}\n\nawait writeFile(\"./device-certificate.pem\", certificatePem, \"utf8\");\nawait writeFile(\"./device-private-key.pem\", privateKey, \"utf8\");\n\nconsole.log(certificateArn);\n```\n\n### Create a policy and attach the certificate to a thing\n\nThis is the usual control-plane flow for provisioning a registry thing and linking an X.509 certificate to it.\n\n```javascript\nimport {\n  AttachPolicyCommand,\n  AttachThingPrincipalCommand,\n  CreatePolicyCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst thingName = \"sensor-123\";\nconst certificateArn = \"arn:aws:iot:us-east-1:123456789012:cert/abc123...\";\nconst policyName = \"sensor-123-policy\";\n\nconst policyDocument = JSON.stringify({\n  Version: \"2012-10-17\",\n  Statement: [\n    {\n      Effect: \"Allow\",\n      Action: [\n        \"iot:Connect\",\n        \"iot:Publish\",\n        \"iot:Receive\",\n        \"iot:Subscribe\",\n      ],\n      Resource: \"*\",\n    },\n  ],\n});\n\nawait iot.send(\n  new CreatePolicyCommand({\n    policyName,\n    policyDocument,\n  }),\n);\n\nawait iot.send(\n  new AttachPolicyCommand({\n    policyName,\n    target: certificateArn,\n  }),\n);\n\nawait iot.send(\n  new AttachThingPrincipalCommand({\n    thingName,\n    principal: certificateArn,\n  }),\n);\n```\n\nUse a least-privilege policy in real deployments. The wildcard example keeps the provisioning flow readable, but it is broader than most production setups should allow.\n\n## Pitfalls\n\n- `@aws-sdk/client-iot` is the AWS IoT Core control-plane client. It does not replace an MQTT client, thing shadow client, or jobs data-plane client.\n- `CreateKeysAndCertificateCommand` returns the private key only when the key pair is created. Persist it before your process exits.\n- `AttachPolicyCommand` and `AttachThingPrincipalCommand` use the certificate ARN, not just the certificate ID.\n- `CreatePolicyCommand` creates a named policy. Re-running the same create flow with the same `policyName` will fail unless you reuse the existing policy or choose a different name.\n- `ListThingsCommand` and similar list APIs paginate with `nextToken`. Do not assume a single response contains everything.\n- AWS IoT endpoints are account- and region-specific. A lookup in the wrong region usually looks like a missing endpoint, thing, or certificate.\n\n## When to reach for other packages\n\n- `@aws-sdk/client-iot-data-plane`: use the AWS IoT data plane for operations such as thing shadows.\n- An AWS IoT device SDK or another MQTT client: use one of these when you need device connections, publish/subscribe messaging, or long-lived MQTT sessions.\n- `@aws-sdk/credential-providers`: use this for explicit assume-role, SSO, Cognito, or other non-default credential flows.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-iot` version `3.1007.0`.\n- AWS SDK for JavaScript v3 uses a modular package layout. Prefer `IoTClient` plus explicit command imports in application code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 IoT client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/iot/`\n- AWS IoT API Reference: `https://docs.aws.amazon.com/iot/latest/apireference/Welcome.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-iot`\n"
  },
  {
    "path": "content/aws/docs/iot-data-plane/javascript/DOC.md",
    "content": "---\nname: iot-data-plane\ndescription: \"AWS SDK for JavaScript v3 client for AWS IoT Core data-plane APIs, including HTTPS publish and thing shadow operations against your account-specific data endpoint.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,iot,iot-core,thing-shadow,publish,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-iot-data-plane`\n\nUse this package for AWS IoT Core data-plane calls from JavaScript. The common flows are publishing a message to an MQTT topic over HTTPS and reading, updating, listing, or deleting thing shadows.\n\nThis is not the AWS IoT control-plane client. Use `@aws-sdk/client-iot` for registry and account operations such as creating things, creating certificates, or discovering your account-specific IoT data endpoint.\n\n## Install\n\nInstall the data-plane client:\n\n```bash\nnpm install @aws-sdk/client-iot-data-plane\n```\n\nIf you want to resolve the IoT data endpoint from code instead of configuring it manually, install the control-plane client too:\n\n```bash\nnpm install @aws-sdk/client-iot\n```\n\nIf your app needs explicit credential helpers for profiles, IAM Identity Center, assume-role, or Cognito, add the credential provider package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nConfigure AWS credentials, a region, and the AWS IoT data endpoint before you send requests:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\nexport AWS_IOT_DATA_ENDPOINT=\"https://a1b2c3d4e5f6g7-ats.iot.us-east-1.amazonaws.com\"\n```\n\nFor local development with a shared profile:\n\n```bash\naws configure --profile iot-dev\nexport AWS_PROFILE=\"iot-dev\"\nexport AWS_REGION=\"us-east-1\"\nexport AWS_IOT_DATA_ENDPOINT=\"https://a1b2c3d4e5f6g7-ats.iot.us-east-1.amazonaws.com\"\n```\n\nThe IoT data endpoint is account-specific and regional. In practice, you usually need both the region and the `iot:Data-ATS` endpoint address for the same AWS account and region.\n\n## Resolve the data endpoint\n\nIf you do not already have the endpoint address, look it up with the AWS IoT control-plane client and `DescribeEndpointCommand`.\n\n```javascript\nimport {\n  DescribeEndpointCommand,\n  IoTClient,\n} from \"@aws-sdk/client-iot\";\n\nconst iot = new IoTClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { endpointAddress } = await iot.send(\n  new DescribeEndpointCommand({\n    endpointType: \"iot:Data-ATS\",\n  }),\n);\n\nif (!endpointAddress) {\n  throw new Error(\"AWS IoT did not return a data endpoint address\");\n}\n\nconst endpoint = `https://${endpointAddress}`;\nconsole.log(endpoint);\n```\n\nStore that value and pass it to `IoTDataPlaneClient` as `endpoint`.\n\n## Client setup\n\n### Minimal Node.js client\n\n```javascript\nimport { IoTDataPlaneClient } from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { IoTDataPlaneClient } from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\nIn Node.js, the default AWS SDK v3 credential provider chain is usually enough if you already configured environment variables, a shared profile, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core usage pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetThingShadowCommand,\n  IoTDataPlaneClient,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nconst response = await iotData.send(\n  new GetThingShadowCommand({\n    thingName: \"sensor-123\",\n  }),\n);\n\nconst shadowJson = new TextDecoder().decode(response.payload);\nconsole.log(JSON.parse(shadowJson));\n```\n\nFor shadow APIs, the response payload is JSON bytes. Decode it before parsing.\n\n## Common workflows\n\n### Publish a JSON message to a topic\n\n`PublishCommand` sends a single HTTPS publish request to an MQTT topic.\n\n```javascript\nimport {\n  IoTDataPlaneClient,\n  PublishCommand,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nconst payload = {\n  deviceId: \"sensor-123\",\n  temperatureC: 21.4,\n  recordedAt: new Date().toISOString(),\n};\n\nawait iotData.send(\n  new PublishCommand({\n    topic: \"devices/sensor-123/telemetry\",\n    qos: 1,\n    payload: Buffer.from(JSON.stringify(payload)),\n  }),\n);\n```\n\nUse `qos: 0` or `qos: 1` depending on your delivery requirements.\n\n### Read the classic thing shadow\n\nUse the unnamed shadow when you do not pass `shadowName`.\n\n```javascript\nimport {\n  GetThingShadowCommand,\n  IoTDataPlaneClient,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nconst { payload } = await iotData.send(\n  new GetThingShadowCommand({\n    thingName: \"sensor-123\",\n  }),\n);\n\nconst shadow = JSON.parse(new TextDecoder().decode(payload));\n\nconsole.log(shadow.state?.desired);\nconsole.log(shadow.state?.reported);\n```\n\n### Update a thing shadow\n\nSend the shadow document as JSON bytes.\n\n```javascript\nimport {\n  IoTDataPlaneClient,\n  UpdateThingShadowCommand,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nconst update = {\n  state: {\n    desired: {\n      samplingIntervalSeconds: 60,\n      ledEnabled: true,\n    },\n  },\n};\n\nconst { payload } = await iotData.send(\n  new UpdateThingShadowCommand({\n    thingName: \"sensor-123\",\n    payload: Buffer.from(JSON.stringify(update)),\n  }),\n);\n\nconst updatedShadow = JSON.parse(new TextDecoder().decode(payload));\nconsole.log(updatedShadow.state?.desired);\n```\n\n### Work with a named shadow\n\nPass `shadowName` when the thing uses multiple independent shadow documents.\n\n```javascript\nimport {\n  GetThingShadowCommand,\n  IoTDataPlaneClient,\n  UpdateThingShadowCommand,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nawait iotData.send(\n  new UpdateThingShadowCommand({\n    thingName: \"sensor-123\",\n    shadowName: \"config\",\n    payload: Buffer.from(\n      JSON.stringify({\n        state: {\n          desired: {\n            firmwareChannel: \"stable\",\n          },\n        },\n      }),\n    ),\n  }),\n);\n\nconst { payload } = await iotData.send(\n  new GetThingShadowCommand({\n    thingName: \"sensor-123\",\n    shadowName: \"config\",\n  }),\n);\n\nconsole.log(JSON.parse(new TextDecoder().decode(payload)));\n```\n\n### List named shadows for a thing\n\nUse `ListNamedShadowsForThingCommand` when you need to discover existing named shadows.\n\n```javascript\nimport {\n  IoTDataPlaneClient,\n  ListNamedShadowsForThingCommand,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nconst response = await iotData.send(\n  new ListNamedShadowsForThingCommand({\n    thingName: \"sensor-123\",\n    pageSize: 25,\n  }),\n);\n\nfor (const shadowName of response.results ?? []) {\n  console.log(shadowName);\n}\n```\n\n### Delete a thing shadow\n\nDelete the classic shadow or pass `shadowName` to delete a named shadow.\n\n```javascript\nimport {\n  DeleteThingShadowCommand,\n  IoTDataPlaneClient,\n} from \"@aws-sdk/client-iot-data-plane\";\n\nconst iotData = new IoTDataPlaneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.AWS_IOT_DATA_ENDPOINT,\n});\n\nawait iotData.send(\n  new DeleteThingShadowCommand({\n    thingName: \"sensor-123\",\n  }),\n);\n```\n\n## Pitfalls\n\n- `IoTDataPlaneClient` needs your account-specific AWS IoT data endpoint. Region-only configuration is not enough for most IoT data-plane flows.\n- Use the ATS data endpoint from `DescribeEndpointCommand({ endpointType: \"iot:Data-ATS\" })`, not the control-plane endpoint.\n- This client sends HTTPS API requests. It does not open a long-lived MQTT connection or subscribe to topics.\n- Thing shadow responses come back as bytes in `payload`. Decode them before calling `JSON.parse`.\n- If you omit `shadowName`, the API reads or updates the classic unnamed shadow.\n- The caller still needs IAM permissions for the data-plane actions it uses, such as `iot:Publish`, `iot:GetThingShadow`, `iot:UpdateThingShadow`, and `iot:DeleteThingShadow`.\n\n## When to reach for other packages\n\n- `@aws-sdk/client-iot`: use the AWS IoT Core control plane for things, certificates, policies, and endpoint discovery.\n- An AWS IoT device SDK or another MQTT client: use one of these when you need persistent device connections, subscriptions, or long-lived MQTT sessions.\n- `@aws-sdk/credential-providers`: use this for explicit assume-role, IAM Identity Center, Cognito, or shared-config credential flows in application code.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-iot-data-plane` version `3.1007.0`.\n- AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Pin the npm package version in your application when exact patch-level parity matters.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 IoT Data Plane client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/iot-data-plane/`\n- AWS IoT API Reference: `https://docs.aws.amazon.com/iot/latest/apireference/Welcome.html`\n- AWS IoT `DescribeEndpoint` API reference: `https://docs.aws.amazon.com/iot/latest/apireference/API_DescribeEndpoint.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-iot-data-plane`\n"
  },
  {
    "path": "content/aws/docs/iot-events/javascript/DOC.md",
    "content": "---\nname: iot-events\ndescription: \"AWS SDK for JavaScript v3 client for AWS IoT Events control-plane APIs, including inputs, detector models, alarm models, logging, and analysis.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,iot-events,javascript,nodejs,iot,detectors,alarms\"\n---\n\n# `@aws-sdk/client-iot-events`\n\nUse this package for AWS IoT Events control-plane APIs in AWS SDK for JavaScript v3. It covers creating and describing inputs, detector models, and alarm models, plus logging, tagging, and detector model analysis.\n\nThis client does not send runtime device messages. Input messages are sent through the separate AWS IoT Events data-plane API, where `BatchPutMessage` lives.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-iot-events\n```\n\n## Prerequisites\n\nSet AWS credentials and a region before calling the client:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport IOTEVENTS_ROLE_ARN=arn:aws:iam::123456789012:role/IoTEventsRole\n```\n\nIf you use shared config instead of raw keys, set `AWS_PROFILE` and keep `AWS_REGION`:\n\n```bash\nexport AWS_PROFILE=my-team-dev\nexport AWS_REGION=us-east-1\n```\n\n`IOTEVENTS_ROLE_ARN` is the service role that AWS IoT Events uses for detector actions and logging. It is separate from the credentials your application uses to call the API.\n\n## Initialize the client\n\n```javascript\nimport { IoTEventsClient } from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain usually works if you already configured environment variables, a shared AWS profile, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## What this client covers\n\n`@aws-sdk/client-iot-events` is the control-plane client for AWS IoT Events APIs such as:\n\n- inputs: `CreateInputCommand`, `DescribeInputCommand`, `ListInputsCommand`, `UpdateInputCommand`\n- detector models: `CreateDetectorModelCommand`, `DescribeDetectorModelCommand`, `ListDetectorModelsCommand`, `UpdateDetectorModelCommand`\n- alarm models: `CreateAlarmModelCommand`, `DescribeAlarmModelCommand`, `ListAlarmModelsCommand`, `UpdateAlarmModelCommand`\n- logging and analysis: `PutLoggingOptionsCommand`, `DescribeLoggingOptionsCommand`, `StartDetectorModelAnalysisCommand`, `GetDetectorModelAnalysisResultsCommand`\n- tagging and related lookups: `TagResourceCommand`, `UntagResourceCommand`, `ListTagsForResourceCommand`, `ListInputRoutingsCommand`\n\nIf your application needs to send input payloads into AWS IoT Events at runtime, use the AWS IoT Events data-plane API instead of this package.\n\n## Common operations\n\n### Create an input\n\nThe input definition exposes JSON payload fields as attributes that detector model expressions can reference later.\n\n```javascript\nimport {\n  CreateInputCommand,\n  IoTEventsClient,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new CreateInputCommand({\n    inputName: \"PressureInput\",\n    inputDescription: \"Pressure readings from a motor\",\n    inputDefinition: {\n      attributes: [\n        { jsonPath: \"sensorData.pressure\" },\n        { jsonPath: \"motorid\" },\n      ],\n    },\n    tags: [\n      {\n        key: \"deviceType\",\n        value: \"motor\",\n      },\n    ],\n  }),\n);\n\nconsole.log(response.inputConfiguration?.inputArn);\nconsole.log(response.inputConfiguration?.status);\n```\n\n### List and describe inputs\n\nList APIs use `nextToken` for pagination. Loop until AWS stops returning a token.\n\n```javascript\nimport {\n  DescribeInputCommand,\n  IoTEventsClient,\n  ListInputsCommand,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListInputsCommand({\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const summary of page.inputSummaries ?? []) {\n    console.log(summary.inputName, summary.status);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n\nconst detail = await client.send(\n  new DescribeInputCommand({\n    inputName: \"PressureInput\",\n  }),\n);\n\nconsole.log(detail.input?.inputDefinition?.attributes);\n```\n\n### Create a detector model\n\nDetector models are state machines. `key` tells AWS IoT Events which payload field identifies the detector instance that should receive each input.\n\n```javascript\nimport {\n  CreateDetectorModelCommand,\n  IoTEventsClient,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst roleArn = process.env.IOTEVENTS_ROLE_ARN;\n\nif (!roleArn) {\n  throw new Error(\"Set IOTEVENTS_ROLE_ARN before creating detector models\");\n}\n\nconst detectorModelDefinition = {\n  states: [\n    {\n      stateName: \"Normal\",\n      onInput: {\n        transitionEvents: [\n          {\n            eventName: \"Overpressurized\",\n            condition: \"$input.PressureInput.sensorData.pressure > 70\",\n            nextState: \"Dangerous\",\n          },\n        ],\n      },\n    },\n    {\n      stateName: \"Dangerous\",\n      onEnter: {\n        events: [\n          {\n            eventName: \"NotifyOperators\",\n            condition: \"true\",\n            actions: [\n              {\n                sns: {\n                  targetArn: \"arn:aws:sns:us-east-1:123456789012:underPressureAction\",\n                },\n              },\n            ],\n          },\n        ],\n      },\n      onInput: {\n        transitionEvents: [\n          {\n            eventName: \"PressureRecovered\",\n            condition: \"$input.PressureInput.sensorData.pressure <= 70\",\n            nextState: \"Normal\",\n          },\n        ],\n      },\n    },\n  ],\n  initialStateName: \"Normal\",\n};\n\nconst response = await client.send(\n  new CreateDetectorModelCommand({\n    detectorModelName: \"motorDetectorModel\",\n    detectorModelDescription: \"Detect overpressure in a motor.\",\n    detectorModelDefinition,\n    key: \"motorid\",\n    roleArn,\n  }),\n);\n\nconsole.log(response.detectorModelConfiguration?.detectorModelArn);\nconsole.log(response.detectorModelConfiguration?.detectorModelVersion);\n```\n\n### Describe the latest detector model version\n\nIf you omit `detectorModelVersion`, AWS IoT Events returns the latest version.\n\n```javascript\nimport {\n  DescribeDetectorModelCommand,\n  IoTEventsClient,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DescribeDetectorModelCommand({\n    detectorModelName: \"motorDetectorModel\",\n  }),\n);\n\nconsole.log(response.detectorModel?.detectorModelConfiguration?.detectorModelVersion);\nconsole.log(response.detectorModel?.detectorModelConfiguration?.status);\n```\n\n### Analyze a detector model definition before create or update\n\n`StartDetectorModelAnalysisCommand` takes a detector model definition directly. `GetDetectorModelAnalysisResultsCommand` returns findings such as unsupported actions, expression issues, or missing references.\n\n```javascript\nimport {\n  GetDetectorModelAnalysisResultsCommand,\n  IoTEventsClient,\n  StartDetectorModelAnalysisCommand,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst detectorModelDefinition = {\n  states: [\n    {\n      stateName: \"Normal\",\n      onInput: {\n        transitionEvents: [\n          {\n            eventName: \"Overpressurized\",\n            condition: \"$input.PressureInput.sensorData.pressure > 70\",\n            nextState: \"Dangerous\",\n          },\n        ],\n      },\n    },\n    {\n      stateName: \"Dangerous\",\n      onInput: {\n        transitionEvents: [\n          {\n            eventName: \"Recovered\",\n            condition: \"$input.PressureInput.sensorData.pressure <= 70\",\n            nextState: \"Normal\",\n          },\n        ],\n      },\n    },\n  ],\n  initialStateName: \"Normal\",\n};\n\nconst start = await client.send(\n  new StartDetectorModelAnalysisCommand({\n    detectorModelDefinition,\n  }),\n);\n\nconst analysisId = start.analysisId;\n\nif (!analysisId) {\n  throw new Error(\"AWS IoT Events did not return an analysisId\");\n}\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new GetDetectorModelAnalysisResultsCommand({\n      analysisId,\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const result of page.analysisResults ?? []) {\n    console.log(result.level, result.type, result.message);\n\n    for (const location of result.locations ?? []) {\n      console.log(\"  at\", location.path);\n    }\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n### Configure service logging\n\n```javascript\nimport {\n  DescribeLoggingOptionsCommand,\n  IoTEventsClient,\n  PutLoggingOptionsCommand,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst roleArn = process.env.IOTEVENTS_ROLE_ARN;\n\nif (!roleArn) {\n  throw new Error(\"Set IOTEVENTS_ROLE_ARN before configuring logging\");\n}\n\nawait client.send(\n  new PutLoggingOptionsCommand({\n    loggingOptions: {\n      roleArn,\n      level: \"ERROR\",\n      enabled: true,\n      detectorDebugOptions: [\n        {\n          detectorModelName: \"motorDetectorModel\",\n          keyValue: \"motor-123\",\n        },\n      ],\n    },\n  }),\n);\n\nconst response = await client.send(new DescribeLoggingOptionsCommand({}));\n\nconsole.log(response.loggingOptions);\n```\n\n### List input routings\n\nUse `ListInputRoutingsCommand` when you need to see how an input is routed. For an AWS IoT Events input, identify it by input name.\n\n```javascript\nimport {\n  IoTEventsClient,\n  ListInputRoutingsCommand,\n} from \"@aws-sdk/client-iot-events\";\n\nconst client = new IoTEventsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ListInputRoutingsCommand({\n    inputIdentifier: {\n      iotEventsInputIdentifier: {\n        inputName: \"PressureInput\",\n      },\n    },\n    maxResults: 50,\n  }),\n);\n\nfor (const resource of response.routedResources ?? []) {\n  console.log(resource.name, resource.arn);\n}\n```\n\n## Important gotchas\n\n- This is the control-plane client. Do not expect it to send device payloads into AWS IoT Events.\n- `inputDefinition.attributes[].jsonPath` must match fields in the JSON payload that your data-plane messages send. Detector expressions reference those values through `$input.<inputName>...`.\n- `key` on a detector model controls detector-instance routing. Set it deliberately if the model tracks state per device or per system.\n- `roleArn` is required for detector models and logging. That role needs the permissions required by the actions or logging targets your model uses.\n- `DescribeDetectorModelCommand` returns the latest detector model version when you omit `detectorModelVersion`. `DescribeAlarmModelCommand` behaves the same way for alarm model versions.\n- `PutLoggingOptionsCommand` changes can take up to one minute to apply. If you changed the IAM policy attached to the logging role, that can take up to five minutes to take effect.\n- `GetDetectorModelAnalysisResultsCommand` results are only retrievable for up to 24 hours after AWS IoT Events starts the analysis.\n- List-style APIs use `nextToken`; do not assume a single response contains everything.\n- If event evaluation order matters in your detector model, set `evaluationMethod` explicitly to either `\"BATCH\"` or `\"SERIAL\"` instead of relying on defaults.\n\n## When to reach for other packages\n\n- `@aws-sdk/credential-providers` for explicit credential loading such as shared config, IAM Identity Center, assume-role, or Cognito flows.\n- The separate AWS IoT Events data-plane client for runtime message ingestion APIs such as `BatchPutMessage`.\n"
  },
  {
    "path": "content/aws/docs/ivs/javascript/DOC.md",
    "content": "---\nname: ivs\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon IVS channels, stream keys, recording configurations, and live stream metadata.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,ivs,live-streaming,video,javascript\"\n---\n\n# `@aws-sdk/client-ivs`\n\nUse `@aws-sdk/client-ivs` for the Amazon IVS low-latency streaming control plane in JavaScript or TypeScript. This client creates and manages channels, stream keys, recording configurations, playback key pairs, playback restriction policies, and live-stream metadata.\n\nIt does not publish video by itself. Your encoder sends video to the channel ingest endpoint that IVS creates for you, and viewers play the returned playback URL.\n\n## Golden Rules\n\n- Prefer `IVSClient` with explicit command imports.\n- Set `region` explicitly or provide it through standard AWS configuration.\n- `CreateChannelCommand` creates the channel and its initial stream key in one call.\n- Treat `streamKey.value` like a secret; anyone who has it can stream to the channel.\n- A channel can have only one stream key at a time. To rotate it, delete the existing key and create a new one.\n- `UpdateChannelCommand` cannot update a live channel; stop the stream first.\n- `PutMetadataCommand` only works on an active stream and is limited to 1 KB per request, 5 requests per second per channel, and 155 requests per second per account.\n- `GetStreamCommand` may signal an offline channel with `ChannelNotBroadcasting`; do not depend on `stream.state === \"OFFLINE\"`.\n- If you create a recording configuration, keep its S3 bucket in the same AWS region as the IVS configuration.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ivs\n```\n\n## Prerequisites\n\nAmazon IVS is regional. Set AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-west-2\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n\nexport IVS_CHANNEL_ARN=\"arn:aws:ivs:us-west-2:123456789012:channel/abcdEFGHijkl\"\nexport IVS_RECORDING_BUCKET=\"my-ivs-recordings\"\n```\n\nIf you already use shared AWS config or named profiles locally, you can omit the explicit `credentials` block and let the SDK resolve credentials from your environment.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { IVSClient } from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { IVSClient } from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({\n  region: \"us-west-2\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetChannelCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst { channel } = await ivs.send(\n  new GetChannelCommand({\n    arn: process.env.IVS_CHANNEL_ARN,\n  }),\n);\n\nconsole.log({\n  arn: channel?.arn,\n  name: channel?.name,\n  ingestEndpoint: channel?.ingestEndpoint,\n  playbackUrl: channel?.playbackUrl,\n});\n```\n\n## Common Workflows\n\n### Create a channel and get the ingest endpoint\n\n`CreateChannelCommand` returns both the channel details and the initial stream key.\n\n```javascript\nimport {\n  CreateChannelCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst { channel, streamKey } = await ivs.send(\n  new CreateChannelCommand({\n    name: \"live-app\",\n    latencyMode: \"LOW\",\n    type: \"STANDARD\",\n    tags: {\n      environment: \"dev\",\n    },\n  }),\n);\n\nconsole.log(\"Channel ARN:\", channel?.arn);\nconsole.log(\"RTMPS ingest endpoint:\", channel?.ingestEndpoint);\nconsole.log(\"Playback URL:\", channel?.playbackUrl);\nconsole.log(\"Stream key:\", streamKey?.value);\n```\n\nUse the returned `ingestEndpoint` and `streamKey.value` in your broadcasting software. Do not expose the stream key in browser code or logs.\n\n### Create a recording configuration in S3\n\nUse a recording configuration when you want IVS to write recorded output to S3.\n\n```javascript\nimport {\n  CreateRecordingConfigurationCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst { recordingConfiguration } = await ivs.send(\n  new CreateRecordingConfigurationCommand({\n    name: \"record-live-app\",\n    destinationConfiguration: {\n      s3: {\n        bucketName: process.env.IVS_RECORDING_BUCKET,\n      },\n    },\n    recordingReconnectWindowSeconds: 60,\n  }),\n);\n\nconsole.log(recordingConfiguration?.arn);\nconsole.log(recordingConfiguration?.state);\n```\n\nIf you want recording enabled from the start, pass the returned `recordingConfiguration.arn` as `recordingConfigurationArn` when you create the channel.\n\n```javascript\nimport {\n  CreateChannelCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst recordingConfigurationArn = \"arn:aws:ivs:us-west-2:123456789012:recording-configuration/abcdEFGHijkl\";\n\nconst { channel } = await ivs.send(\n  new CreateChannelCommand({\n    name: \"live-app-with-recording\",\n    recordingConfigurationArn,\n  }),\n);\n\nconsole.log(channel?.arn);\n```\n\n### List channels with pagination\n\n```javascript\nimport {\n  IVSClient,\n  ListChannelsCommand,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const response = await ivs.send(\n    new ListChannelsCommand({\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const channel of response.channels ?? []) {\n    console.log(channel.arn, channel.name, channel.playbackUrl);\n  }\n\n  nextToken = response.nextToken;\n} while (nextToken);\n```\n\nYou can also filter `ListChannelsCommand` requests by `filterByName`, `filterByRecordingConfigurationArn`, or `filterByPlaybackRestrictionPolicyArn`.\n\n### Check whether a channel is live\n\nUse `GetStreamCommand` for the active stream on a channel.\n\n```javascript\nimport {\n  GetStreamCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\ntry {\n  const { stream } = await ivs.send(\n    new GetStreamCommand({\n      channelArn: process.env.IVS_CHANNEL_ARN,\n    }),\n  );\n\n  console.log({\n    streamId: stream?.streamId,\n    health: stream?.health,\n    state: stream?.state,\n    viewerCount: stream?.viewerCount,\n    playbackUrl: stream?.playbackUrl,\n  });\n} catch (error) {\n  if (error.name === \"ChannelNotBroadcasting\") {\n    console.log(\"Channel is not live.\");\n  } else {\n    throw error;\n  }\n}\n```\n\n### Read the latest stream session\n\n`GetStreamSessionCommand` returns the most recent session if you omit `streamId`.\n\n```javascript\nimport {\n  GetStreamSessionCommand,\n  IVSClient,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst { streamSession } = await ivs.send(\n  new GetStreamSessionCommand({\n    channelArn: process.env.IVS_CHANNEL_ARN,\n  }),\n);\n\nconsole.log({\n  streamId: streamSession?.streamId,\n  startTime: streamSession?.startTime,\n  endTime: streamSession?.endTime,\n  channelType: streamSession?.channel?.type,\n  recordingState: streamSession?.recordingConfiguration?.state,\n});\n```\n\nPass a specific `streamId` when you need one historical session instead of the most recent one.\n\n### Put timed metadata into the active stream\n\n`PutMetadataCommand` inserts small metadata messages into the active stream for downstream consumers such as players or analytics.\n\n```javascript\nimport {\n  IVSClient,\n  PutMetadataCommand,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nawait ivs.send(\n  new PutMetadataCommand({\n    channelArn: process.env.IVS_CHANNEL_ARN,\n    metadata: JSON.stringify({\n      event: \"score-update\",\n      home: 2,\n      away: 1,\n    }),\n  }),\n);\n```\n\nKeep the payload under 1 KB and only call this while the channel is actively broadcasting.\n\n### Stop a live stream\n\n```javascript\nimport {\n  IVSClient,\n  StopStreamCommand,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nawait ivs.send(\n  new StopStreamCommand({\n    channelArn: process.env.IVS_CHANNEL_ARN,\n  }),\n);\n```\n\nSome encoders reconnect automatically after a dropped RTMPS session. If you need to stop publishing permanently, rotate or delete the current stream key as part of the shutdown flow.\n\n## Private Playback And Playback Restrictions\n\nAmazon IVS has two related but separate features:\n\n- Set `authorized: true` on a channel when you want a private channel that requires playback-authorization tokens.\n- Use `playbackRestrictionPolicyArn` on a channel when you want to restrict playback by country and-or origin.\n\nTo enable private playback, import the public key material that your auth service will use for viewer token verification.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  CreateChannelCommand,\n  IVSClient,\n  ImportPlaybackKeyPairCommand,\n} from \"@aws-sdk/client-ivs\";\n\nconst ivs = new IVSClient({ region: \"us-west-2\" });\n\nconst publicKeyMaterial = await readFile(\"./ivs-playback-public.pem\", \"utf8\");\n\nconst { playbackKeyPair } = await ivs.send(\n  new ImportPlaybackKeyPairCommand({\n    name: \"viewer-auth\",\n    publicKeyMaterial,\n  }),\n);\n\nconst { channel } = await ivs.send(\n  new CreateChannelCommand({\n    name: \"private-live-app\",\n    authorized: true,\n  }),\n);\n\nconsole.log(playbackKeyPair?.arn);\nconsole.log(channel?.authorized);\n```\n\nThis package manages playback key pairs, but it does not generate viewer authorization tokens for you. Keep the private key in your own auth service.\n\n## Pitfalls\n\n- This is a control-plane client. Your encoder publishes media to the IVS ingest endpoint; application viewers use the playback URL.\n- `CreateStreamKeyCommand` fails if the channel already has a stream key. Delete the current key first if you need to rotate it.\n- `UpdateChannelCommand` fails on a live channel. Stop the stream, update the channel, then start broadcasting again.\n- If you enable `multitrackInputConfiguration.enabled`, channel type must be `STANDARD`, `policy` and `maximumResolution` are required, and `containerFormat` must be `FRAGMENTED_MP4`.\n- Recording configurations can land in `CREATE_FAILED` if the target S3 bucket is in a different region from the IVS configuration.\n- `GetStreamCommand` is for active streams only. For offline channels, expect `ChannelNotBroadcasting` instead of relying on an `OFFLINE` response.\n- `PutMetadataCommand` requires an active stream and throttles aggressively enough that you should batch small events together when possible.\n- Private channels and playback restriction policies solve different problems: signed viewer authorization versus geographic or origin restrictions.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-ivs` version `3.1007.0`.\n- The current service model exposes channel types `BASIC`, `STANDARD`, `ADVANCED_SD`, and `ADVANCED_HD`.\n- The current paginated list operations are `ListChannels`, `ListPlaybackKeyPairs`, `ListRecordingConfigurations`, `ListStreamKeys`, and `ListStreams`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 IVS client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ivs/`\n- Amazon IVS Low-Latency Streaming API Reference: `https://docs.aws.amazon.com/ivs/latest/LowLatencyAPIReference/Welcome.html`\n- Amazon IVS Getting Started guide: `https://docs.aws.amazon.com/ivs/latest/LowLatencyUserGuide/getting-started.html`\n- Amazon IVS private channels guide: `https://docs.aws.amazon.com/ivs/latest/userguide/private-channels.html`\n- Amazon IVS timed metadata guide: `https://docs.aws.amazon.com/ivs/latest/userguide/metadata.html`\n- Amazon IVS channel types reference: `https://docs.aws.amazon.com/ivs/latest/LowLatencyAPIReference/channel-types.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/keyspaces/javascript/DOC.md",
    "content": "---\nname: keyspaces\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Keyspaces keyspace, table, restore, and type management\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,keyspaces,cassandra,database,nosql\"\n---\n\n# Amazon Keyspaces SDK for JavaScript\n\n## Golden Rule\n\nUse `@aws-sdk/client-keyspaces` for Amazon Keyspaces control-plane operations such as creating keyspaces, creating tables, updating table settings, restoring tables, and managing user-defined types.\n\nDo not use this package for application reads and writes with CQL. Amazon Keyspaces supports CQL through Cassandra-compatible drivers; this SDK client is for the service API that manages keyspaces and tables.\n\n```bash\nnpm install @aws-sdk/client-keyspaces\n```\n\nIf you want to load a named AWS profile explicitly in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\n- An AWS account with Amazon Keyspaces enabled in the target region.\n- IAM permissions for the Keyspaces operations you call.\n- AWS credentials and a region available through environment variables, shared config files, or another supported AWS SDK credential source.\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=your-access-key-id\nAWS_SECRET_ACCESS_KEY=your-secret-access-key\nAWS_SESSION_TOKEN=your-session-token\nAWS_PROFILE=default\nKEYSPACES_KEYSPACE=app\nKEYSPACES_TABLE=events\n```\n\n`AWS_SESSION_TOKEN` is only needed for temporary credentials. `AWS_PROFILE` is only needed if you want to load a named profile from shared AWS config files.\n\n## Create the client\n\nThe default setup uses the standard AWS SDK credential chain and the configured region.\n\n```javascript\nimport \"dotenv/config\";\nimport { KeyspacesClient } from \"@aws-sdk/client-keyspaces\";\n\nexport const keyspaces = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to force a shared-config profile in code, pass an explicit credentials provider:\n\n```javascript\nimport \"dotenv/config\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { KeyspacesClient } from \"@aws-sdk/client-keyspaces\";\n\nconst keyspaces = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"default\" }),\n});\n```\n\n## Create and inspect a keyspace\n\n`CreateKeyspace` is asynchronous. Keyspace names must be unique within a region.\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  CreateKeyspaceCommand,\n  GetKeyspaceCommand,\n  KeyspacesClient,\n  ListKeyspacesCommand,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst keyspaceName = process.env.KEYSPACES_KEYSPACE ?? \"app\";\n\nawait client.send(\n  new CreateKeyspaceCommand({\n    keyspaceName,\n    replicationSpecification: {\n      replicationStrategy: \"SINGLE_REGION\",\n    },\n    tags: [{ key: \"env\", value: \"dev\" }],\n  }),\n);\n\nconst details = await client.send(\n  new GetKeyspaceCommand({ keyspaceName }),\n);\n\nconsole.log(details.keyspaceName);\nconsole.log(details.resourceArn);\nconsole.log(details.replicationStrategy);\n\nconst page = await client.send(\n  new ListKeyspacesCommand({ maxResults: 25 }),\n);\n\nconsole.log(page.keyspaces ?? []);\n```\n\nFor a multi-region keyspace, create it with `replicationStrategy: \"MULTI_REGION\"` and a `regionList`.\n\n```javascript\nawait client.send(\n  new CreateKeyspaceCommand({\n    keyspaceName: \"app-global\",\n    replicationSpecification: {\n      replicationStrategy: \"MULTI_REGION\",\n      regionList: [\"us-east-1\", \"us-west-2\"],\n    },\n  }),\n);\n```\n\n## Create a table and wait for `ACTIVE`\n\n`CreateTable` is asynchronous. After the request is accepted, the table status becomes `CREATING`. Use `GetTable` and wait until the status is `ACTIVE` before treating the table as ready.\n\n```javascript\nimport \"dotenv/config\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport {\n  CreateTableCommand,\n  GetTableCommand,\n  KeyspacesClient,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function waitForTableActive(keyspaceName, tableName, timeoutMs = 10 * 60_000) {\n  const startedAt = Date.now();\n\n  while (Date.now() - startedAt < timeoutMs) {\n    try {\n      const response = await client.send(\n        new GetTableCommand({ keyspaceName, tableName }),\n      );\n\n      if (response.status === \"ACTIVE\") {\n        return response;\n      }\n\n      if (\n        response.status === \"DELETING\" ||\n        response.status === \"DELETED\" ||\n        response.status === \"INACCESSIBLE_ENCRYPTION_CREDENTIALS\"\n      ) {\n        throw new Error(`Unexpected table status: ${response.status}`);\n      }\n    } catch (error) {\n      if (error.name !== \"ResourceNotFoundException\") {\n        throw error;\n      }\n    }\n\n    await delay(5000);\n  }\n\n  throw new Error(`Timed out waiting for ${keyspaceName}.${tableName} to become ACTIVE`);\n}\n\nconst keyspaceName = process.env.KEYSPACES_KEYSPACE ?? \"app\";\nconst tableName = process.env.KEYSPACES_TABLE ?? \"events\";\n\nawait client.send(\n  new CreateTableCommand({\n    keyspaceName,\n    tableName,\n    schemaDefinition: {\n      allColumns: [\n        { name: \"tenant_id\", type: \"text\" },\n        { name: \"event_id\", type: \"uuid\" },\n        { name: \"created_at\", type: \"timestamp\" },\n        { name: \"event_type\", type: \"text\" },\n        { name: \"payload\", type: \"text\" },\n      ],\n      partitionKeys: [{ name: \"tenant_id\" }],\n      clusteringKeys: [{ name: \"event_id\", orderBy: \"ASC\" }],\n    },\n    capacitySpecification: {\n      throughputMode: \"PAY_PER_REQUEST\",\n    },\n    pointInTimeRecovery: {\n      status: \"ENABLED\",\n    },\n    ttl: {\n      status: \"ENABLED\",\n    },\n    comment: {\n      message: \"Application event log\",\n    },\n  }),\n);\n\nconst table = await waitForTableActive(keyspaceName, tableName);\nconsole.log(table.status);\n```\n\n`capacitySpecification` supports two modes:\n\n- `PAY_PER_REQUEST` for on-demand throughput.\n- `PROVISIONED` for provisioned RCUs and WCUs.\n\nIf you use `PROVISIONED`, include `readCapacityUnits` and `writeCapacityUnits`.\n\n## List tables with pagination\n\n`ListTables` uses `nextToken` pagination.\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  KeyspacesClient,\n  ListTablesCommand,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst keyspaceName = process.env.KEYSPACES_KEYSPACE ?? \"app\";\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListTablesCommand({\n      keyspaceName,\n      maxResults: 25,\n      nextToken,\n    }),\n  );\n\n  for (const table of page.tables ?? []) {\n    console.log(`${table.keyspaceName}.${table.tableName}`);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\n## Update a table\n\n`UpdateTable` lets you add columns or change one table setting such as capacity mode, auto scaling, encryption, point-in-time recovery, or TTL.\n\nImportant: update only one specific table setting per `UpdateTable` request.\n\nAdd a new column:\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  KeyspacesClient,\n  UpdateTableCommand,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new UpdateTableCommand({\n    keyspaceName: process.env.KEYSPACES_KEYSPACE ?? \"app\",\n    tableName: process.env.KEYSPACES_TABLE ?? \"events\",\n    addColumns: [{ name: \"source\", type: \"text\" }],\n  }),\n);\n```\n\nEnable point-in-time recovery in a separate request:\n\n```javascript\nawait client.send(\n  new UpdateTableCommand({\n    keyspaceName: process.env.KEYSPACES_KEYSPACE ?? \"app\",\n    tableName: process.env.KEYSPACES_TABLE ?? \"events\",\n    pointInTimeRecovery: {\n      status: \"ENABLED\",\n    },\n  }),\n);\n```\n\nSwitch to provisioned throughput in a separate request:\n\n```javascript\nawait client.send(\n  new UpdateTableCommand({\n    keyspaceName: process.env.KEYSPACES_KEYSPACE ?? \"app\",\n    tableName: process.env.KEYSPACES_TABLE ?? \"events\",\n    capacitySpecification: {\n      throughputMode: \"PROVISIONED\",\n      readCapacityUnits: 200,\n      writeCapacityUnits: 100,\n    },\n  }),\n);\n```\n\nIf you use provisioned throughput with auto scaling, inspect the current settings with `GetTableAutoScalingSettings`.\n\n```javascript\nimport {\n  GetTableAutoScalingSettingsCommand,\n  KeyspacesClient,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new GetTableAutoScalingSettingsCommand({\n    keyspaceName: process.env.KEYSPACES_KEYSPACE ?? \"app\",\n    tableName: process.env.KEYSPACES_TABLE ?? \"events\",\n  }),\n);\n\nconsole.log(response);\n```\n\n## Restore a table from point-in-time recovery\n\n`RestoreTable` restores a source table to a new table. It does not overwrite the original table.\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  KeyspacesClient,\n  RestoreTableCommand,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new RestoreTableCommand({\n    sourceKeyspaceName: \"app\",\n    sourceTableName: \"events\",\n    targetKeyspaceName: \"app\",\n    targetTableName: \"events_restored\",\n    restoreTimestamp: new Date(\"2026-03-13T12:00:00Z\"),\n  }),\n);\n```\n\nWhat restore keeps and changes:\n\n- The restored table is created as a new table.\n- Schema, data, and TTL state are restored based on the selected timestamp.\n- Capacity mode, auto scaling, encryption, and PITR settings are restored from the source table's current settings unless you override them in the restore request.\n- IAM policies and CloudWatch metrics or alarms are not restored.\n- Amazon Keyspaces allows up to 4 concurrent restores per account.\n\n## Add a region to a keyspace\n\nUse `UpdateKeyspace` to add a region to a single-region or multi-region keyspace. When you add a region, Amazon Keyspaces replicates all tables in that keyspace to the new region.\n\nTo replicate tables successfully, they must use client-side timestamps for conflict resolution.\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  KeyspacesClient,\n  UpdateKeyspaceCommand,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new UpdateKeyspaceCommand({\n    keyspaceName: \"app-global\",\n    replicationSpecification: {\n      replicationStrategy: \"MULTI_REGION\",\n      regionList: [\"us-east-1\", \"us-west-2\"],\n    },\n    clientSideTimestamps: {\n      status: \"ENABLED\",\n    },\n  }),\n);\n```\n\n## Create a user-defined type\n\nIf your schema uses Cassandra user-defined types, create them with `CreateType`.\n\n```javascript\nimport \"dotenv/config\";\nimport {\n  CreateTypeCommand,\n  KeyspacesClient,\n} from \"@aws-sdk/client-keyspaces\";\n\nconst client = new KeyspacesClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new CreateTypeCommand({\n    keyspaceName: process.env.KEYSPACES_KEYSPACE ?? \"app\",\n    typeName: \"address\",\n    fieldDefinitions: [\n      { name: \"street\", type: \"text\" },\n      { name: \"postal_code\", type: \"text\" },\n    ],\n  }),\n);\n```\n\nField definitions can use supported Cassandra data types, including collections and user-defined types in the same keyspace.\n\n## Pitfalls and version-sensitive behavior\n\n- This package manages Amazon Keyspaces resources; it does not execute CQL application queries.\n- `CreateKeyspace` and `CreateTable` are asynchronous. Retry `GetKeyspace` after creating a keyspace, and only treat a table as ready when `GetTable` returns `status: \"ACTIVE\"`.\n- `ListKeyspaces`, `ListTables`, `ListTypes`, and `ListTagsForResource` paginate with `nextToken`.\n- `UpdateTable` can add columns or update one table setting per request; split unrelated changes into separate calls.\n- `RestoreTable` always creates a new table and does not restore IAM policies or CloudWatch alarms.\n- If you add a region with `UpdateKeyspace`, make sure replicated tables use client-side timestamps.\n"
  },
  {
    "path": "content/aws/docs/kinesis/javascript/DOC.md",
    "content": "---\nname: kinesis\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Kinesis Data Streams in JavaScript applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,kinesis,data-streams,streaming,javascript,nodejs\"\n---\n\n# AWS Kinesis SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-kinesis` to write records to Amazon Kinesis Data Streams and inspect streams, shards, and consumers from modern JavaScript and TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-kinesis`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1006.0`.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n- Prefer `KinesisClient` plus explicit commands for most application code.\n- Encode text or JSON into bytes before sending it as record `Data`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-kinesis\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { KinesisClient } from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { KinesisClient } from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you have already configured AWS access through environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  KinesisClient,\n  PutRecordCommand,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nawait kinesis.send(\n  new PutRecordCommand({\n    StreamName: \"orders\",\n    PartitionKey: \"customer#123\",\n    Data: new TextEncoder().encode(\n      JSON.stringify({ orderId: \"ord_123\", status: \"created\" }),\n    ),\n  }),\n);\n```\n\n`PartitionKey` affects which shard receives the record. Records with the same partition key are ordered within their shard, but ordering is not global across the stream.\n\n## Common Operations\n\n### Write multiple records in one request\n\n`PutRecords` can succeed partially, so always inspect `FailedRecordCount` and retry only the failed entries.\n\n```javascript\nimport {\n  KinesisClient,\n  PutRecordsCommand,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nconst records = [\n  { orderId: \"ord_123\", status: \"created\" },\n  { orderId: \"ord_124\", status: \"created\" },\n];\n\nconst response = await kinesis.send(\n  new PutRecordsCommand({\n    StreamName: \"orders\",\n    Records: records.map((record) => ({\n      PartitionKey: record.orderId,\n      Data: new TextEncoder().encode(JSON.stringify(record)),\n    })),\n  }),\n);\n\nif ((response.FailedRecordCount ?? 0) > 0) {\n  const failedRecords = (response.Records ?? [])\n    .map((result, index) => ({ result, record: records[index] }))\n    .filter(({ result }) => result.ErrorCode);\n\n  console.log(\"Retry these records\", failedRecords);\n}\n```\n\n### List streams with pagination\n\n```javascript\nimport {\n  KinesisClient,\n  paginateListStreams,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListStreams(\n  { client: kinesis },\n  { Limit: 25 },\n)) {\n  for (const streamName of page.StreamNames ?? []) {\n    console.log(streamName);\n  }\n}\n```\n\n### List shard IDs for a stream\n\n```javascript\nimport {\n  KinesisClient,\n  ListShardsCommand,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nconst response = await kinesis.send(\n  new ListShardsCommand({\n    StreamName: \"orders\",\n  }),\n);\n\nfor (const shard of response.Shards ?? []) {\n  console.log(shard.ShardId);\n}\n```\n\n### Read records from a shard\n\n`GetShardIterator` gives you a starting iterator, then `GetRecords` returns a `NextShardIterator` for the next poll.\n\n```javascript\nimport { Buffer } from \"node:buffer\";\nimport {\n  GetRecordsCommand,\n  GetShardIteratorCommand,\n  KinesisClient,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nconst { ShardIterator } = await kinesis.send(\n  new GetShardIteratorCommand({\n    StreamName: \"orders\",\n    ShardId: \"shardId-000000000000\",\n    ShardIteratorType: \"LATEST\",\n  }),\n);\n\nconst response = await kinesis.send(\n  new GetRecordsCommand({\n    ShardIterator,\n    Limit: 100,\n  }),\n);\n\nfor (const record of response.Records ?? []) {\n  const text = Buffer.from(record.Data).toString(\"utf8\");\n  console.log(record.SequenceNumber, text);\n}\n\nconst nextIterator = response.NextShardIterator;\n```\n\n### Inspect stream status\n\n```javascript\nimport {\n  DescribeStreamSummaryCommand,\n  KinesisClient,\n} from \"@aws-sdk/client-kinesis\";\n\nconst kinesis = new KinesisClient({ region: \"us-east-1\" });\n\nconst response = await kinesis.send(\n  new DescribeStreamSummaryCommand({\n    StreamName: \"orders\",\n  }),\n);\n\nconsole.log(response.StreamDescriptionSummary?.StreamStatus);\nconsole.log(response.StreamDescriptionSummary?.OpenShardCount);\n```\n\n## Kinesis-Specific Gotchas\n\n- Record `Data` is binary. Use `TextEncoder`, `Buffer`, or another byte conversion step instead of sending plain strings directly.\n- `PutRecords` is not all-or-nothing. A successful HTTP response can still contain per-record failures.\n- Ordering guarantees are per shard, not across the whole stream. Your partition-key strategy matters for both ordering and hot-shard avoidance.\n- `GetShardIterator` returns a short-lived iterator. Use `NextShardIterator` from each `GetRecords` response rather than reusing an old iterator indefinitely.\n- `LATEST` starts from newly arriving data, while `TRIM_HORIZON` starts from the oldest retained records. Pick the iterator type deliberately.\n- Shard layouts can change after resharding. Refresh shard IDs instead of caching them forever in long-running consumers.\n- Low-level polling with `GetRecords` is useful for simple consumers and tools, but production consumers often need extra coordination, checkpointing, or fan-out strategy beyond this package alone.\n- For LocalStack or other emulators, set `endpoint`, an explicit region, and test credentials.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, SSO, STS assume-role flows, and other credential helpers.\n- `@aws-sdk/client-firehose`: managed delivery to downstream destinations when you do not want to build your own stream consumer pipeline.\n- `@aws-sdk/client-cloudwatch`: alarms and metrics around producer or consumer health.\n"
  },
  {
    "path": "content/aws/docs/kms/javascript/DOC.md",
    "content": "---\nname: kms\ndescription: \"AWS SDK for JavaScript v3 client for AWS Key Management Service key management and cryptographic operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,kms,key-management,encryption,security,javascript\"\n---\n\n# AWS KMS SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-kms` to manage KMS keys, encrypt and decrypt small payloads, generate data keys for envelope encryption, and inspect aliases and key metadata from JavaScript or TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-kms`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1006.0`.\n- AWS SDK for JavaScript v2 reached end of support on September 8, 2025.\n- Current v3 releases at and above `3.968.0` require Node.js 20+, so `3.1006.0` should be treated as Node 20+.\n- Use KMS `Encrypt` and `Decrypt` for small payloads. For files, large objects, or application data at rest, use envelope encryption with `GenerateDataKey` and do the bulk encryption locally.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-kms\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\nPrefer `KMSClient` plus explicit command imports. The package also exposes an aggregated `KMS` client, but command-based imports are the safer default for smaller bundles and clearer call sites.\n\n### Minimal Node.js client\n\n```javascript\nimport { KMSClient } from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { KMSClient } from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n### Browser usage warning\n\nThe package can run in browser builds, but direct browser access to KMS is usually the wrong architecture. Prefer calling KMS from a trusted backend or Lambda function. If you must use it in a browser, use tightly scoped temporary credentials and restrict permissions aggressively.\n\n## Credentials and Region\n\n- In Node.js, the default credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n- KMS keys are regional unless you intentionally work with multi-Region keys. Your client region must still match the key or alias you intend to use.\n- KMS authorization is a combination of IAM permissions and key policy permissions. A principal can have valid AWS credentials and still be denied by the key policy.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  DescribeKeyCommand,\n  KMSClient,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\n\nconst response = await kms.send(\n  new DescribeKeyCommand({\n    KeyId: \"alias/app-key\",\n  }),\n);\n\nconsole.log(response.KeyMetadata?.Arn);\n```\n\nUse aliases like `alias/app-key` where possible so application code does not hard-code raw key IDs.\n\n## Common Operations\n\n### Encrypt a small string\n\nUse `TextEncoder` to turn text into bytes before calling KMS.\n\n```javascript\nimport {\n  EncryptCommand,\n  KMSClient,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\nconst plaintext = new TextEncoder().encode(\"hello from kms\");\n\nconst { CiphertextBlob } = await kms.send(\n  new EncryptCommand({\n    KeyId: \"alias/app-key\",\n    Plaintext: plaintext,\n    EncryptionContext: {\n      service: \"billing\",\n      env: \"prod\",\n    },\n  }),\n);\n\nconst ciphertextBase64 = Buffer.from(CiphertextBlob).toString(\"base64\");\nconsole.log(ciphertextBase64);\n```\n\n### Decrypt ciphertext\n\nIf you encrypted with an `EncryptionContext`, provide the same key-value pairs when decrypting.\n\n```javascript\nimport {\n  DecryptCommand,\n  KMSClient,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\n\nconst ciphertextBase64 = process.env.KMS_CIPHERTEXT;\n\nconst { Plaintext } = await kms.send(\n  new DecryptCommand({\n    CiphertextBlob: Buffer.from(ciphertextBase64, \"base64\"),\n    EncryptionContext: {\n      service: \"billing\",\n      env: \"prod\",\n    },\n  }),\n);\n\nconst value = new TextDecoder().decode(Plaintext);\nconsole.log(value);\n```\n\n### Generate a data key for envelope encryption\n\nFor application payloads, ask KMS for a data key, use the plaintext key locally, and store only the encrypted data key beside the ciphertext.\n\n```javascript\nimport {\n  GenerateDataKeyCommand,\n  KMSClient,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\n\nconst { Plaintext, CiphertextBlob, KeyId } = await kms.send(\n  new GenerateDataKeyCommand({\n    KeyId: \"alias/app-key\",\n    KeySpec: \"AES_256\",\n    EncryptionContext: {\n      service: \"billing\",\n      env: \"prod\",\n    },\n  }),\n);\n\nconst dataKey = Buffer.from(Plaintext);\nconst encryptedDataKey = Buffer.from(CiphertextBlob).toString(\"base64\");\n\nconsole.log({\n  keyId: KeyId,\n  dataKeyLength: dataKey.length,\n  encryptedDataKey,\n});\n```\n\nAfter using the plaintext data key, clear it from memory as early as your runtime and crypto flow allow.\n\n### Create a symmetric encryption key and alias\n\n```javascript\nimport {\n  CreateAliasCommand,\n  CreateKeyCommand,\n  KMSClient,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\n\nconst { KeyMetadata } = await kms.send(\n  new CreateKeyCommand({\n    Description: \"Application envelope encryption key\",\n    KeyUsage: \"ENCRYPT_DECRYPT\",\n    KeySpec: \"SYMMETRIC_DEFAULT\",\n  }),\n);\n\nif (!KeyMetadata?.KeyId) {\n  throw new Error(\"Missing key id\");\n}\n\nawait kms.send(\n  new CreateAliasCommand({\n    AliasName: \"alias/app-key\",\n    TargetKeyId: KeyMetadata.KeyId,\n  }),\n);\n\nconsole.log(KeyMetadata.KeyId);\n```\n\nUse aliases for application configuration and keep raw key IDs in infrastructure state or admin tooling, not in day-to-day app code.\n\n### List aliases\n\n```javascript\nimport {\n  KMSClient,\n  ListAliasesCommand,\n} from \"@aws-sdk/client-kms\";\n\nconst kms = new KMSClient({ region: \"us-east-1\" });\n\nconst response = await kms.send(new ListAliasesCommand({}));\n\nfor (const alias of response.Aliases ?? []) {\n  console.log(alias.AliasName, alias.TargetKeyId);\n}\n```\n\nList operations can paginate. For large accounts, keep following `NextMarker` until `Truncated` is false.\n\n## KMS-Specific Gotchas\n\n- `Plaintext`, `CiphertextBlob`, and generated data keys are binary values. Use `Uint8Array` or `Buffer`, not plain strings.\n- `Encrypt` and `Decrypt` are not for large payloads. Use envelope encryption for files, database fields at scale, or other bulk data.\n- `EncryptionContext` is case-sensitive and exact-match. If you use it during encryption, keep it stable and supply the same context when decrypting.\n- KMS key access depends on both IAM and key policies. A missing key-policy grant is a common cause of `AccessDeniedException`.\n- Aliases are region-scoped. `alias/app-key` in one region is unrelated to the same alias name in another region.\n- Keys that are disabled, pending deletion, or otherwise not usable will cause cryptographic operations to fail even if the key identifier resolves.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, assume-role, and other explicit credential flows.\n- `@aws-sdk/client-secrets-manager`: secret storage and rotation workflows instead of storing ad hoc ciphertext blobs yourself.\n- `@aws-sdk/client-ssm`: configuration and `SecureString` parameter workflows backed by KMS.\n\n## Practical Notes\n\n- Prefer aliases such as `alias/app-key` in application settings so you can rotate the backing key with less code churn.\n- Keep cryptographic permissions narrow. Many workloads only need `kms:Decrypt` on one key, not broad KMS administration rights.\n- Log key identifiers and alias names, but never log plaintext values, plaintext data keys, or raw decrypted secrets.\n- If you need high-level client-side encryption workflows instead of raw KMS primitives, reach for an envelope-encryption library rather than rebuilding everything around `Encrypt` and `Decrypt` directly.\n"
  },
  {
    "path": "content/aws/docs/lambda/javascript/DOC.md",
    "content": "---\nname: lambda\ndescription: \"AWS SDK for JavaScript v3 client for invoking and managing AWS Lambda functions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,lambda,serverless,functions,cloud\"\n---\n\n# AWS Lambda SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-lambda` to invoke Lambda functions and manage Lambda resources from modern JavaScript and TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-lambda`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `LambdaClient` plus individual commands over the aggregated `Lambda` client.\n- Set `region` explicitly in code or through standard AWS config.\n- `InvokeCommand` request and response bodies are byte payloads; encode with `TextEncoder` and decode with `TextDecoder`.\n- A completed invocation can still represent a Lambda runtime error, so inspect `FunctionError` and the decoded payload.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-lambda\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { LambdaClient } from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { LambdaClient } from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\nFor browser runtimes, use explicit browser-safe credentials and verify that your IAM and CORS setup intentionally allows direct Lambda calls.\n\n## Core Usage Pattern\n\nThe usual v3 flow is `client.send(new Command(input))`.\n\n```javascript\nimport { InvokeCommand, LambdaClient } from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder(\"utf-8\");\n\nconst response = await lambda.send(\n  new InvokeCommand({\n    FunctionName: \"process-order\",\n    Payload: encoder.encode(\n      JSON.stringify({\n        orderId: \"1234\",\n      }),\n    ),\n  }),\n);\n\nconst body = response.Payload\n  ? JSON.parse(decoder.decode(response.Payload))\n  : undefined;\n\nif (response.FunctionError) {\n  throw new Error(body?.errorMessage ?? \"Lambda invocation failed\");\n}\n\nconsole.log(body);\n```\n\n## Common Operations\n\n### Invoke asynchronously\n\nUse `InvocationType: \"Event\"` when you want Lambda to queue the event and return immediately.\n\n```javascript\nimport { InvokeCommand, LambdaClient } from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nawait lambda.send(\n  new InvokeCommand({\n    FunctionName: \"process-order\",\n    InvocationType: \"Event\",\n    Payload: new TextEncoder().encode(\n      JSON.stringify({\n        orderId: \"1234\",\n      }),\n    ),\n  }),\n);\n```\n\n### Read deployed function metadata\n\n```javascript\nimport { GetFunctionCommand, LambdaClient } from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nconst response = await lambda.send(\n  new GetFunctionCommand({\n    FunctionName: \"process-order\",\n  }),\n);\n\nconsole.log(response.Configuration?.Runtime);\nconsole.log(response.Configuration?.LastModified);\n```\n\n### List functions with pagination\n\n```javascript\nimport {\n  LambdaClient,\n  paginateListFunctions,\n} from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListFunctions({ client: lambda }, {})) {\n  for (const item of page.Functions ?? []) {\n    console.log(item.FunctionName);\n  }\n}\n```\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you already use environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Lambda-Specific Gotchas\n\n- `InvokeCommand` does not automatically parse JSON payloads for you.\n- `InvocationType: \"Event\"` does not return the handler result.\n- `LogType: \"Tail\"` returns base64-encoded log tail data on synchronous invokes.\n- Lambda handler failures may come back as `FunctionError` plus an error payload instead of an SDK exception.\n- Resource-based invoke permissions for services such as EventBridge or S3 use `AddPermissionCommand` on the function.\n- For LocalStack or other emulators, set `endpoint`, `region`, and explicit test credentials.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and browser-safe credential setup.\n- `@aws-sdk/client-cloudwatch-logs`: read or filter execution logs without depending on invoke log tails.\n- `@aws-sdk/client-iam`: manage execution roles and related IAM policies.\n\n## Common Lambda Operations\n\n### Update function configuration\n\nUse `UpdateFunctionConfigurationCommand` for memory, timeout, environment variables, runtime settings, and similar configuration changes.\n\n```javascript\nimport {\n  LambdaClient,\n  UpdateFunctionConfigurationCommand,\n} from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nawait lambda.send(\n  new UpdateFunctionConfigurationCommand({\n    FunctionName: \"process-order\",\n    MemorySize: 512,\n    Timeout: 30,\n    Environment: {\n      Variables: {\n        STAGE: \"prod\",\n      },\n    },\n  }),\n);\n```\n\n### Update function code from a zip file\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  LambdaClient,\n  UpdateFunctionCodeCommand,\n} from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\nconst zipFile = await readFile(\"./dist/function.zip\");\n\nawait lambda.send(\n  new UpdateFunctionCodeCommand({\n    FunctionName: \"process-order\",\n    ZipFile: zipFile,\n    Publish: true,\n  }),\n);\n```\n\n### Add invoke permission for another AWS service\n\nUse a function resource policy when another AWS service should invoke the function.\n\n```javascript\nimport {\n  AddPermissionCommand,\n  LambdaClient,\n} from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nawait lambda.send(\n  new AddPermissionCommand({\n    FunctionName: \"process-order\",\n    StatementId: \"allow-eventbridge-rule\",\n    Action: \"lambda:InvokeFunction\",\n    Principal: \"events.amazonaws.com\",\n    SourceArn: \"arn:aws:events:us-east-1:123456789012:rule/process-order\",\n  }),\n);\n```\n\n### Create an event source mapping\n\nUse an event source mapping for poll-based integrations such as SQS or DynamoDB Streams.\n\n```javascript\nimport {\n  CreateEventSourceMappingCommand,\n  LambdaClient,\n} from \"@aws-sdk/client-lambda\";\n\nconst lambda = new LambdaClient({ region: \"us-east-1\" });\n\nawait lambda.send(\n  new CreateEventSourceMappingCommand({\n    FunctionName: \"process-order\",\n    EventSourceArn: \"arn:aws:sqs:us-east-1:123456789012:orders\",\n    BatchSize: 10,\n    Enabled: true,\n  }),\n);\n```\n\n### Notes\n\n- Configuration and code updates are separate APIs.\n- If later steps depend on the updated state, re-read the function configuration before assuming the change is active everywhere.\n- For event source mappings, the event source itself usually needs its own service-specific permissions and setup.\n"
  },
  {
    "path": "content/aws/docs/lex-runtime-v2/javascript/DOC.md",
    "content": "---\nname: lex-runtime-v2\ndescription: \"Amazon Lex V2 Runtime SDK for JavaScript v3 guide for sending text or audio to a bot and managing session state\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,lex,lex-v2,chatbot,conversational-ai,javascript,nodejs\"\n---\n\n# Amazon Lex V2 Runtime SDK for JavaScript v3 Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-lex-runtime-v2` only for runtime conversations with an existing Amazon Lex V2 bot alias. Your app must already know the bot ID, bot alias ID, locale ID, and a session ID for the current conversation.\n\nFor most server-side apps, create one `LexRuntimeV2Client` for the AWS region that hosts the bot and call `client.send(new Command(...))` for each user turn.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-lex-runtime-v2\n```\n\nThis guide uses ESM imports and the standard AWS SDK for JavaScript v3 command pattern.\n\n## Prerequisites\n\nBefore you send runtime requests, have these values ready:\n\n- `AWS_REGION` for the region where the Lex V2 bot alias is deployed.\n- `LEX_BOT_ID` for the bot.\n- `LEX_BOT_ALIAS_ID` for the alias you want to invoke.\n- `LEX_LOCALE_ID` such as `en_US`.\n- A stable `sessionId` for one conversation.\n\nSet region and credentials with the normal AWS SDK credential chain.\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\n\nexport LEX_BOT_ID=YOUR_BOT_ID\nexport LEX_BOT_ALIAS_ID=YOUR_BOT_ALIAS_ID\nexport LEX_LOCALE_ID=en_US\n```\n\nIf you use environment credentials directly:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nFor local development, a named AWS profile is usually safer than hardcoding credentials in application code.\n\n## Initialize The Client\n\n```javascript\nimport { LexRuntimeV2Client } from \"@aws-sdk/client-lex-runtime-v2\";\n\nexport const lex = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nCreate a small helper object so each command uses the same bot target.\n\n```javascript\nexport const lexTarget = {\n  botId: process.env.LEX_BOT_ID,\n  botAliasId: process.env.LEX_BOT_ALIAS_ID,\n  localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n};\n```\n\n## Core Usage\n\n### Send One Text Turn\n\nUse `RecognizeTextCommand` when the user message is already plain text in memory.\n\n```javascript\nimport {\n  LexRuntimeV2Client,\n  RecognizeTextCommand,\n} from \"@aws-sdk/client-lex-runtime-v2\";\n\nconst client = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sessionId = \"web-user-123\";\n\nconst response = await client.send(\n  new RecognizeTextCommand({\n    botId: process.env.LEX_BOT_ID,\n    botAliasId: process.env.LEX_BOT_ALIAS_ID,\n    localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n    sessionId,\n    text: \"I want to check my order status\",\n  }),\n);\n\nfor (const message of response.messages ?? []) {\n  console.log(message.contentType, message.content);\n}\n\nconsole.log(response.sessionState?.intent?.name);\nconsole.log(response.sessionState?.sessionAttributes);\n```\n\nReuse the same `sessionId` while the conversation is active so Lex keeps the current dialog state.\n\n### Pass Session Attributes With A Request\n\nUse `sessionState.sessionAttributes` when your application needs to send channel or tenant context with the turn.\n\n```javascript\nimport {\n  LexRuntimeV2Client,\n  RecognizeTextCommand,\n} from \"@aws-sdk/client-lex-runtime-v2\";\n\nconst client = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new RecognizeTextCommand({\n    botId: process.env.LEX_BOT_ID,\n    botAliasId: process.env.LEX_BOT_ALIAS_ID,\n    localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n    sessionId: \"web-user-123\",\n    text: \"Show my last invoice\",\n    sessionState: {\n      sessionAttributes: {\n        channel: \"web\",\n        tenant: \"sandbox\",\n      },\n    },\n    requestAttributes: {\n      \"x-application\": \"support-portal\",\n    },\n  }),\n);\n\nconsole.log(response.sessionState?.sessionAttributes);\n```\n\n### Read The Current Session\n\nUse `GetSessionCommand` when you need the current intent, messages, or session state without sending a new utterance.\n\n```javascript\nimport {\n  GetSessionCommand,\n  LexRuntimeV2Client,\n} from \"@aws-sdk/client-lex-runtime-v2\";\n\nconst client = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst session = await client.send(\n  new GetSessionCommand({\n    botId: process.env.LEX_BOT_ID,\n    botAliasId: process.env.LEX_BOT_ALIAS_ID,\n    localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n    sessionId: \"web-user-123\",\n  }),\n);\n\nconsole.log(session.sessionId);\nconsole.log(session.sessionState?.intent?.name);\nconsole.log(session.messages);\n```\n\n### Reset A Conversation\n\nUse `DeleteSessionCommand` when the user starts over and you do not want to keep the existing dialog state.\n\n```javascript\nimport {\n  DeleteSessionCommand,\n  LexRuntimeV2Client,\n} from \"@aws-sdk/client-lex-runtime-v2\";\n\nconst client = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new DeleteSessionCommand({\n    botId: process.env.LEX_BOT_ID,\n    botAliasId: process.env.LEX_BOT_ALIAS_ID,\n    localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n    sessionId: \"web-user-123\",\n  }),\n);\n```\n\nAfter deletion, the next turn with the same `sessionId` starts from a clean session state.\n\n### Send Recorded Audio\n\nUse `RecognizeUtteranceCommand` when you already have audio bytes and want a single request-response call instead of a streaming conversation.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  LexRuntimeV2Client,\n  RecognizeUtteranceCommand,\n} from \"@aws-sdk/client-lex-runtime-v2\";\n\nconst client = new LexRuntimeV2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst audio = await readFile(\"./utterance.pcm\");\n\nconst response = await client.send(\n  new RecognizeUtteranceCommand({\n    botId: process.env.LEX_BOT_ID,\n    botAliasId: process.env.LEX_BOT_ALIAS_ID,\n    localeId: process.env.LEX_LOCALE_ID ?? \"en_US\",\n    sessionId: \"voice-user-123\",\n    requestContentType: \"audio/l16; rate=16000; channels=1\",\n    responseContentType: \"text/plain; charset=utf-8\",\n    inputStream: audio,\n  }),\n);\n\nconsole.log(response.contentType);\n```\n\nIf you need bidirectional or streaming conversation behavior instead of a single request-response turn, use `StartConversationCommand` rather than `RecognizeTextCommand` or `RecognizeUtteranceCommand`.\n\n## Choosing The Right Operation\n\n- `RecognizeTextCommand` for ordinary chat or form-style text input.\n- `RecognizeUtteranceCommand` for one-shot audio input you already captured as bytes.\n- `GetSessionCommand` to inspect the current session state.\n- `DeleteSessionCommand` to clear the active conversation.\n- `PutSessionCommand` to seed or replace session state from your application.\n- `StartConversationCommand` for streaming or duplex conversation flows.\n\n## Common Pitfalls\n\n- `botAliasId` is the alias ID, not the alias name you see in casual documentation or internal naming.\n- `localeId` must match a locale enabled on the target bot alias, such as `en_US`.\n- Reuse one `sessionId` per conversation. If you create a new `sessionId` for every message, Lex cannot keep dialog state across turns.\n- Use `DeleteSessionCommand` when a user explicitly restarts. Reusing an old `sessionId` without clearing it can carry over stale slot or intent state.\n- Use `RecognizeTextCommand` for text and `RecognizeUtteranceCommand` for recorded audio. Use `StartConversationCommand` only when you need streaming behavior.\n- Do not expose long-lived AWS credentials in browser code. Put Lex runtime calls behind a server or use short-lived AWS credentials.\n- This runtime client invokes an existing bot alias. Bot building, versioning, and publishing happen outside the runtime client.\n\n## Version Notes\n\n- This guide covers `@aws-sdk/client-lex-runtime-v2` version `3.1007.0`.\n- The examples use the modular AWS SDK for JavaScript v3 pattern: `client.send(new Command(input))`.\n"
  },
  {
    "path": "content/aws/docs/lib-dynamodb/javascript/DOC.md",
    "content": "---\nname: lib-dynamodb\ndescription: \"AWS SDK for JavaScript v3 DynamoDB document client for reading and writing plain JavaScript objects.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,dynamodb,javascript,nodejs,nosql,document-client\"\n---\n\n# `@aws-sdk/lib-dynamodb`\n\nUse `@aws-sdk/lib-dynamodb` when you want to work with plain JavaScript values in DynamoDB instead of low-level `AttributeValue` shapes. It wraps `@aws-sdk/client-dynamodb`, marshals native inputs into DynamoDB attribute values, and unmarshals responses back into plain objects.\n\n## Install\n\nInstall both the low-level client and the document wrapper:\n\n```bash\nnpm install @aws-sdk/client-dynamodb@3.1007.0 @aws-sdk/lib-dynamodb@3.1007.0\n```\n\n`@aws-sdk/lib-dynamodb` depends on `@aws-sdk/client-dynamodb`.\n\n## Prerequisites\n\nYou need a DynamoDB table, an AWS region, and AWS credentials available to the SDK.\n\nTypical local environment variables:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...   # optional\nexport DYNAMODB_TABLE=Users\n```\n\nIn Node.js, the SDK can also load credentials and region from the usual AWS shared config files or attached IAM role.\n\n## Initialize the document client\n\nCreate a base `DynamoDBClient`, then wrap it with `DynamoDBDocumentClient.from(...)`.\n\n```javascript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\n\nconst client = new DynamoDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport const ddb = DynamoDBDocumentClient.from(client, {\n  marshallOptions: {\n    removeUndefinedValues: true,\n  },\n});\n```\n\nThis is the usual command-based setup. The package also exports `DynamoDBDocument.from(client)` if you want the aggregated client with methods like `put()` and `get()`.\n\n## Common workflows\n\n### Put and get an item\n\nUse plain JavaScript objects for `Item` and `Key`.\n\n```javascript\nimport { GetCommand, PutCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst tableName = process.env.DYNAMODB_TABLE;\n\nawait ddb.send(\n  new PutCommand({\n    TableName: tableName,\n    Item: {\n      pk: \"user#123\",\n      sk: \"profile\",\n      email: \"ada@example.com\",\n      active: true,\n      loginCount: 0,\n    },\n    ConditionExpression: \"attribute_not_exists(pk)\",\n  }),\n);\n\nconst { Item } = await ddb.send(\n  new GetCommand({\n    TableName: tableName,\n    Key: {\n      pk: \"user#123\",\n      sk: \"profile\",\n    },\n  }),\n);\n\nconsole.log(Item);\n```\n\n### Update an item with expressions\n\nExpression syntax is the same as the low-level DynamoDB API, but the values stay as normal JavaScript types.\n\n```javascript\nimport { UpdateCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst tableName = process.env.DYNAMODB_TABLE;\n\nconst { Attributes } = await ddb.send(\n  new UpdateCommand({\n    TableName: tableName,\n    Key: {\n      pk: \"user#123\",\n      sk: \"profile\",\n    },\n    UpdateExpression:\n      \"SET #name = :name, loginCount = if_not_exists(loginCount, :zero) + :one\",\n    ExpressionAttributeNames: {\n      \"#name\": \"name\",\n    },\n    ExpressionAttributeValues: {\n      \":name\": \"Ada Lovelace\",\n      \":zero\": 0,\n      \":one\": 1,\n    },\n    ReturnValues: \"ALL_NEW\",\n  }),\n);\n\nconsole.log(Attributes);\n```\n\n### Query a partition key\n\nUse `QueryCommand` for key-based reads. Prefer this over `ScanCommand` whenever the table design allows it.\n\n```javascript\nimport { QueryCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst tableName = process.env.DYNAMODB_TABLE;\n\nconst response = await ddb.send(\n  new QueryCommand({\n    TableName: tableName,\n    KeyConditionExpression: \"pk = :pk AND begins_with(sk, :prefix)\",\n    ExpressionAttributeValues: {\n      \":pk\": \"user#123\",\n      \":prefix\": \"order#\",\n    },\n    Limit: 25,\n  }),\n);\n\nconsole.log(response.Items);\nconsole.log(response.LastEvaluatedKey);\n```\n\n### Paginate query results\n\nUse the built-in paginator for multiple pages.\n\n```javascript\nimport { paginateQuery } from \"@aws-sdk/lib-dynamodb\";\n\nconst paginator = paginateQuery(\n  { client: ddb },\n  {\n    TableName: process.env.DYNAMODB_TABLE,\n    KeyConditionExpression: \"pk = :pk\",\n    ExpressionAttributeValues: {\n      \":pk\": \"user#123\",\n    },\n  },\n);\n\nfor await (const page of paginator) {\n  for (const item of page.Items ?? []) {\n    console.log(item);\n  }\n}\n```\n\nIf you truly need a full table scan, the package also exports `paginateScan`.\n\n### Run a transaction\n\nUse `TransactWriteCommand` when multiple writes must succeed or fail together.\n\n```javascript\nimport { TransactWriteCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst tableName = process.env.DYNAMODB_TABLE;\n\nawait ddb.send(\n  new TransactWriteCommand({\n    TransactItems: [\n      {\n        Put: {\n          TableName: tableName,\n          Item: {\n            pk: \"user#456\",\n            sk: \"profile\",\n            email: \"grace@example.com\",\n          },\n          ConditionExpression: \"attribute_not_exists(pk)\",\n        },\n      },\n      {\n        Update: {\n          TableName: tableName,\n          Key: {\n            pk: \"stats\",\n            sk: \"users\",\n          },\n          UpdateExpression: \"ADD #count :one\",\n          ExpressionAttributeNames: {\n            \"#count\": \"count\",\n          },\n          ExpressionAttributeValues: {\n            \":one\": 1,\n          },\n        },\n      },\n    ],\n  }),\n);\n```\n\n## Large numbers and translation options\n\nThe document client can preserve DynamoDB numbers more safely than plain JavaScript `number` values.\n\nUse `NumberValue` when you need an exact numeric representation on writes, and `wrapNumbers: true` when you want large numbers returned as `NumberValue` instances instead of native JavaScript numbers.\n\n```javascript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport {\n  DynamoDBDocumentClient,\n  GetCommand,\n  NumberValue,\n  PutCommand,\n} from \"@aws-sdk/lib-dynamodb\";\n\nconst preciseDdb = DynamoDBDocumentClient.from(\n  new DynamoDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" }),\n  {\n    unmarshallOptions: {\n      wrapNumbers: true,\n    },\n  },\n);\n\nawait preciseDdb.send(\n  new PutCommand({\n    TableName: process.env.DYNAMODB_TABLE,\n    Item: {\n      pk: \"invoice#1\",\n      sk: \"totals\",\n      amount: NumberValue.from(\"1000000000000000000000.000000000001\"),\n    },\n  }),\n);\n\nconst { Item } = await preciseDdb.send(\n  new GetCommand({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: {\n      pk: \"invoice#1\",\n      sk: \"totals\",\n    },\n  }),\n);\n\nconsole.log(Item.amount.toString());\n```\n\n## Important pitfalls\n\n- Pass plain JavaScript values to this package. If your code already uses raw DynamoDB shapes like `{ S: \"value\" }`, use `@aws-sdk/client-dynamodb` directly instead.\n- If your objects can contain `undefined` values, set `marshallOptions.removeUndefinedValues: true` so they are removed during marshalling.\n- `convertEmptyValues: true` changes empty strings, blobs, and sets into `null` while marshalling. Enable it only if you want that translation.\n- By default, large JavaScript numbers can throw during marshalling to avoid silent precision loss. Use `NumberValue` for exact values, or enable `marshallOptions.allowImpreciseNumbers` only when loss of precision is acceptable.\n- `DynamoDBDocumentClient.destroy()` is a no-op. Destroy the underlying `DynamoDBClient` if your application needs to release client resources.\n- Prefer `QueryCommand` or `BatchGetCommand` over `ScanCommand` for large tables. If you do scan, use the exported paginator helpers rather than building your own page loop unless you need custom control.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/\n- AWS SDK for JavaScript v3 source and package README: https://github.com/aws/aws-sdk-js-v3/tree/main/lib/lib-dynamodb\n- npm package page: https://www.npmjs.com/package/@aws-sdk/lib-dynamodb\n"
  },
  {
    "path": "content/aws/docs/lib-storage/javascript/DOC.md",
    "content": "---\nname: lib-storage\ndescription: \"AWS SDK for JavaScript v3 multipart upload helper for uploading large files to Amazon S3\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,s3,multipart-upload,storage,javascript\"\n---\n\n# `@aws-sdk/lib-storage` for JavaScript\n\n`@aws-sdk/lib-storage` provides the `Upload` helper for managed multipart uploads to Amazon S3. Use it with `@aws-sdk/client-s3` when you need a higher-level upload flow than calling `PutObjectCommand` yourself, especially for large files, streams, progress reporting, or abortable uploads.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-s3 @aws-sdk/lib-storage\n```\n\n## Prerequisites\n\nSet AWS credentials and a region in the environment, or rely on another supported AWS SDK credential source in your runtime.\n\n```env\nAWS_ACCESS_KEY_ID=your-access-key-id\nAWS_SECRET_ACCESS_KEY=your-secret-access-key\nAWS_SESSION_TOKEN=your-session-token\nAWS_REGION=us-east-1\nAWS_S3_BUCKET=your-bucket-name\n```\n\nIf you already use shared AWS config files, IAM roles, ECS task roles, or Lambda execution roles, you can still initialize `S3Client` without embedding credentials in code.\n\n## Initialize the S3 client\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n```\n\nUse explicit credentials only when you cannot rely on the default AWS SDK credential provider chain:\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Basic multipart upload from a file\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function uploadFile({ filePath, key }) {\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: key,\n      Body: createReadStream(filePath),\n    },\n  });\n\n  await upload.done();\n}\n```\n\n`Upload` manages the multipart workflow and resolves when the full upload has completed.\n\n## Upload with metadata and content type\n\nPass the same S3 object parameters you would normally send for an upload in `params`:\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function uploadImage({ filePath, key }) {\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: key,\n      Body: createReadStream(filePath),\n      ContentType: \"image/png\",\n      Metadata: {\n        source: \"app\",\n      },\n    },\n  });\n\n  const result = await upload.done();\n  return result;\n}\n```\n\n## Track upload progress\n\nAttach the progress listener before awaiting `done()`:\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream, statSync } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function uploadFileWithProgress({ filePath, key }) {\n  const totalBytes = statSync(filePath).size;\n\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: key,\n      Body: createReadStream(filePath),\n    },\n  });\n\n  upload.on(\"httpUploadProgress\", (progress) => {\n    if (typeof progress.loaded !== \"number\") {\n      return;\n    }\n\n    const percent = Math.round((progress.loaded / totalBytes) * 100);\n    console.log(`${percent}% uploaded`);\n  });\n\n  return upload.done();\n}\n```\n\n## Tune concurrency and part size\n\n`Upload` accepts multipart configuration options for throughput and failure behavior:\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function uploadLargeFile({ filePath, key }) {\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: key,\n      Body: createReadStream(filePath),\n    },\n    queueSize: 4,\n    partSize: 5 * 1024 * 1024,\n    leavePartsOnError: false,\n  });\n\n  return upload.done();\n}\n```\n\nUse these options deliberately:\n\n- `queueSize`: number of concurrent part uploads.\n- `partSize`: size of each uploaded part. AWS S3 multipart uploads require parts of at least 5 MiB except the final part.\n- `leavePartsOnError`: when set to `false`, the helper cleans up multipart state on failure instead of leaving uploaded parts behind.\n\n## Abort an in-flight upload\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function uploadWithTimeout({ filePath, key, timeoutMs = 5000 }) {\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: key,\n      Body: createReadStream(filePath),\n    },\n  });\n\n  const timer = setTimeout(() => {\n    upload.abort();\n  }, timeoutMs);\n\n  try {\n    return await upload.done();\n  } catch (error) {\n    if (error?.name === \"AbortError\") {\n      throw new Error(\"Upload aborted\");\n    }\n\n    throw error;\n  } finally {\n    clearTimeout(timer);\n  }\n}\n```\n\n## Common workflow: upload an Express file to S3\n\nIf middleware gives you a local temp file path, pass its read stream directly into `Upload`.\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION,\n});\n\nexport async function saveUploadedFile(file) {\n  const upload = new Upload({\n    client: s3,\n    params: {\n      Bucket: process.env.AWS_S3_BUCKET,\n      Key: `uploads/${file.originalname}`,\n      Body: createReadStream(file.path),\n      ContentType: file.mimetype,\n    },\n  });\n\n  return upload.done();\n}\n```\n\n## When to use `Upload` instead of `PutObjectCommand`\n\nUse `Upload` when you need any of the following:\n\n- multipart uploads for large objects\n- uploads from Node.js streams\n- progress events during upload\n- concurrency control with `queueSize`\n- explicit abort support\n\nFor a simple small-object upload where you do not need multipart behavior or progress reporting, `@aws-sdk/client-s3` with `PutObjectCommand` is usually simpler.\n\n## Pitfalls\n\n- Install both packages. `Upload` comes from `@aws-sdk/lib-storage`, but it still needs an `S3Client` from `@aws-sdk/client-s3`.\n- Set `region` on the client. Leaving it undefined can cause credential or endpoint resolution failures before the upload starts.\n- Keep `partSize` at or above `5 * 1024 * 1024` for multipart uploads.\n- Register `httpUploadProgress` listeners before calling `await upload.done()`.\n- Call `upload.abort()` only while the upload is still active; after `done()` resolves there is nothing left to cancel.\n- If you disable cleanup behavior, you are responsible for any incomplete multipart upload state left in S3.\n\n## Version notes\n\nThis guide targets `@aws-sdk/lib-storage` version `3.1007.0`. The package is part of AWS SDK for JavaScript v3 and is documented under the AWS maintainer documentation for the package.\n"
  },
  {
    "path": "content/aws/docs/license-manager/javascript/DOC.md",
    "content": "---\nname: license-manager\ndescription: \"AWS License Manager SDK for JavaScript (v3) for creating license configurations, associating them with resources, and tracking consumption\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,license-manager,license-configuration,compliance,operations\"\n---\n\n# AWS License Manager SDK for JavaScript\n\nUse `@aws-sdk/client-license-manager` to manage AWS License Manager resources from Node.js. The most common infrastructure workflow is to create a license configuration, associate it with a resource such as an AMI, and then inspect associations and license consumption over time.\n\nThis guide focuses on license configuration workflows:\n\n- creating a license configuration\n- listing and reading configurations\n- associating a configuration with a resource\n- checking resource associations and consumed licenses\n\n## Installation\n\n```bash\nnpm install @aws-sdk/client-license-manager\n```\n\nThese examples assume Node.js 18+ and the standard AWS SDK for JavaScript v3 credential provider chain.\n\n## Credentials and client initialization\n\nSet credentials with environment variables or an AWS profile:\n\n```bash\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=your-profile\n```\n\nCreate the client with the AWS region where you want to manage License Manager resources.\n\n```typescript\nimport { LicenseManagerClient } from \"@aws-sdk/client-license-manager\";\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you need to pin credentials in code, pass them explicitly:\n\n```typescript\nimport { LicenseManagerClient } from \"@aws-sdk/client-license-manager\";\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Create a license configuration\n\n`CreateLicenseConfiguration` defines how License Manager should count and enforce licenses. Supported counting types are `vCPU`, `Instance`, `Core`, and `Socket`.\n\nThe `LicenseRules` format is `#name=value`. The valid rule names depend on `LicenseCountingType`.\n\n```typescript\nimport {\n  CreateLicenseConfigurationCommand,\n  LicenseManagerClient,\n} from \"@aws-sdk/client-license-manager\";\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new CreateLicenseConfigurationCommand({\n    Name: \"sql-server-vcpu-prod\",\n    Description: \"Track SQL Server licenses by vCPU\",\n    LicenseCountingType: \"vCPU\",\n    LicenseCount: 64,\n    LicenseCountHardLimit: true,\n    LicenseRules: [\n      \"#allowedTenancy=EC2-DedicatedHost\",\n      \"#honorVcpuOptimization=True\",\n      \"#minimumVcpus=2\",\n      \"#maximumVcpus=64\",\n    ],\n    DisassociateWhenNotFound: true,\n    Tags: [\n      { Key: \"Environment\", Value: \"production\" },\n      { Key: \"Application\", Value: \"sql-server\" },\n    ],\n  }),\n);\n\nconsole.log(response.LicenseConfigurationArn);\n```\n\n`LicenseCountHardLimit: true` enables hard enforcement. When the limit is exceeded, AWS blocks new launches that would consume more licenses.\n\nIf you use automated discovery, `ProductInformationList` is also available on create and update calls. License Manager documents `SSM_MANAGED` and `RDS` as supported resource types, with different filter names depending on the resource type.\n\n## List and inspect license configurations\n\nUse `ListLicenseConfigurations` to enumerate configurations, then `GetLicenseConfiguration` when you need the full details for one ARN.\n\n```typescript\nimport {\n  GetLicenseConfigurationCommand,\n  LicenseManagerClient,\n  ListLicenseConfigurationsCommand,\n} from \"@aws-sdk/client-license-manager\";\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken: string | undefined;\n\ndo {\n  const listResponse = await client.send(\n    new ListLicenseConfigurationsCommand({\n      NextToken: nextToken,\n      MaxResults: 50,\n    }),\n  );\n\n  for (const config of listResponse.LicenseConfigurations ?? []) {\n    console.log({\n      arn: config.LicenseConfigurationArn,\n      name: config.Name,\n      countingType: config.LicenseCountingType,\n      consumedLicenses: config.ConsumedLicenses,\n      status: config.Status,\n    });\n  }\n\n  nextToken = listResponse.NextToken;\n} while (nextToken);\n\nconst licenseConfigurationArn = process.env.AWS_LICENSE_CONFIGURATION_ARN;\n\nif (!licenseConfigurationArn) {\n  throw new Error(\"Set AWS_LICENSE_CONFIGURATION_ARN to inspect one configuration.\");\n}\n\nconst getResponse = await client.send(\n  new GetLicenseConfigurationCommand({\n    LicenseConfigurationArn: licenseConfigurationArn,\n  }),\n);\n\nconsole.dir(\n  {\n    arn: getResponse.LicenseConfigurationArn,\n    name: getResponse.Name,\n    description: getResponse.Description,\n    rules: getResponse.LicenseRules,\n    consumedLicenses: getResponse.ConsumedLicenses,\n    summaries: getResponse.ConsumedLicenseSummaryList,\n    managedResources: getResponse.ManagedResourceSummaryList,\n  },\n  { depth: null },\n);\n```\n\n`ListLicenseConfigurations`, `ListAssociationsForLicenseConfiguration`, `ListLicenseSpecificationsForResource`, and `ListUsageForLicenseConfiguration` are paginated. Always carry `NextToken` forward until it is absent.\n\n## Associate a license configuration with a resource\n\nUse `UpdateLicenseSpecificationsForResource` to add or remove license configuration associations for a resource ARN.\n\nThe AWS CLI example for this operation uses an EC2 AMI ARN such as `arn:aws:ec2:us-west-2::image/ami-1234567890abcdef0`.\n\n```bash\nexport AWS_LICENSE_CONFIGURATION_ARN=arn:aws:license-manager:us-east-1:123456789012:license-configuration:lic-0123456789abcdef0\nexport AWS_LICENSED_RESOURCE_ARN=arn:aws:ec2:us-east-1::image/ami-0123456789abcdef0\n```\n\n```typescript\nimport {\n  LicenseManagerClient,\n  ListLicenseSpecificationsForResourceCommand,\n  UpdateLicenseSpecificationsForResourceCommand,\n} from \"@aws-sdk/client-license-manager\";\n\nconst licenseConfigurationArn = process.env.AWS_LICENSE_CONFIGURATION_ARN;\nconst resourceArn = process.env.AWS_LICENSED_RESOURCE_ARN;\n\nif (!licenseConfigurationArn || !resourceArn) {\n  throw new Error(\n    \"Set AWS_LICENSE_CONFIGURATION_ARN and AWS_LICENSED_RESOURCE_ARN before running this example.\",\n  );\n}\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new UpdateLicenseSpecificationsForResourceCommand({\n    ResourceArn: resourceArn,\n    AddLicenseSpecifications: [\n      {\n        LicenseConfigurationArn: licenseConfigurationArn,\n      },\n    ],\n  }),\n);\n\nconst verifyResponse = await client.send(\n  new ListLicenseSpecificationsForResourceCommand({\n    ResourceArn: resourceArn,\n  }),\n);\n\nconsole.dir(verifyResponse.LicenseSpecifications, { depth: null });\n```\n\nTo replace an association, pass the old ARN in `RemoveLicenseSpecifications` and the new ARN in `AddLicenseSpecifications` in the same call.\n\n## Inspect associations and license consumption\n\nUse `ListAssociationsForLicenseConfiguration` to find the resources attached to one configuration, and `ListUsageForLicenseConfiguration` to see the license consumption reported for those resources.\n\n```bash\nexport AWS_LICENSE_CONFIGURATION_ARN=arn:aws:license-manager:us-east-1:123456789012:license-configuration:lic-0123456789abcdef0\n```\n\n```typescript\nimport {\n  LicenseManagerClient,\n  ListAssociationsForLicenseConfigurationCommand,\n  ListUsageForLicenseConfigurationCommand,\n} from \"@aws-sdk/client-license-manager\";\n\nconst licenseConfigurationArn = process.env.AWS_LICENSE_CONFIGURATION_ARN;\n\nif (!licenseConfigurationArn) {\n  throw new Error(\"Set AWS_LICENSE_CONFIGURATION_ARN before running this example.\");\n}\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst associationsResponse = await client.send(\n  new ListAssociationsForLicenseConfigurationCommand({\n    LicenseConfigurationArn: licenseConfigurationArn,\n    MaxResults: 50,\n  }),\n);\n\nconsole.dir(associationsResponse.LicenseConfigurationAssociations, {\n  depth: null,\n});\n\nconst usageResponse = await client.send(\n  new ListUsageForLicenseConfigurationCommand({\n    LicenseConfigurationArn: licenseConfigurationArn,\n    MaxResults: 50,\n  }),\n);\n\nconsole.dir(usageResponse.LicenseConfigurationUsageList, {\n  depth: null,\n});\n```\n\nThe usage response includes resource ARN, resource type, resource status, association time, owner account ID, and consumed license count for each tracked resource.\n\n## Update or delete a configuration\n\nUse `UpdateLicenseConfiguration` to change the name, description, license rules, count, hard-limit behavior, or automated discovery settings. Use `DeleteLicenseConfiguration` to remove a configuration you no longer need.\n\n```typescript\nimport {\n  DeleteLicenseConfigurationCommand,\n  LicenseManagerClient,\n  UpdateLicenseConfigurationCommand,\n} from \"@aws-sdk/client-license-manager\";\n\nconst licenseConfigurationArn = process.env.AWS_LICENSE_CONFIGURATION_ARN;\n\nif (!licenseConfigurationArn) {\n  throw new Error(\"Set AWS_LICENSE_CONFIGURATION_ARN before running this example.\");\n}\n\nconst client = new LicenseManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new UpdateLicenseConfigurationCommand({\n    LicenseConfigurationArn: licenseConfigurationArn,\n    Description: \"Updated description from deployment automation\",\n    LicenseCount: 96,\n    LicenseCountHardLimit: false,\n  }),\n);\n\n// Later, when you want to remove the configuration entirely:\nawait client.send(\n  new DeleteLicenseConfigurationCommand({\n    LicenseConfigurationArn: licenseConfigurationArn,\n  }),\n);\n```\n\nBoth operations return no response body on success.\n\n## Important details\n\n- `LicenseRules` must use the `#name=value` format, and the allowed rule names depend on `LicenseCountingType`.\n- `licenseAffinityToHost` is expressed in days and accepts values from 1 to 180.\n- `allowedTenancy` accepts `EC2-Default`, `EC2-DedicatedHost`, and `EC2-DedicatedInstance`.\n- `DisassociateWhenNotFound` causes License Manager to disassociate a resource when the software is no longer found.\n- Resource association calls use full ARNs such as a license configuration ARN and resource ARN.\n- List operations are paginated; keep following `NextToken` until it is absent.\n"
  },
  {
    "path": "content/aws/docs/lightsail/javascript/DOC.md",
    "content": "---\nname: lightsail\ndescription: \"AWS SDK for JavaScript v3 Lightsail client for instances, blueprints, networking, and other Lightsail control-plane operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,lightsail,javascript,nodejs,instances,static-ip,networking\"\n---\n\n# `@aws-sdk/client-lightsail`\n\nUse this package for Amazon Lightsail in AWS SDK for JavaScript v3. It covers instance lifecycle, instance access details, public port rules, static IPs, snapshots, buckets, databases, and other Lightsail control-plane resources.\n\nPrefer `LightsailClient` plus explicit command imports for application code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-lightsail\n```\n\nIf you want an explicit shared-profile credential loader in code, install the credential helper package too:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nLightsail is regional. Set a region and credentials before you create the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK credential chain.\n\n```bash\nexport AWS_PROFILE=\"dev\"\nexport AWS_REGION=\"us-east-1\"\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { LightsailClient } from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Shared profile in code\n\n```javascript\nimport { LightsailClient } from \"@aws-sdk/client-lightsail\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst lightsail = new LightsailClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access is already configured with environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetInstanceCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await lightsail.send(\n  new GetInstanceCommand({\n    instanceName: \"web-1\",\n  }),\n);\n\nconsole.log(response.instance?.name);\nconsole.log(response.instance?.state?.name);\nconsole.log(response.instance?.publicIpAddress);\n```\n\n## Common Workflows\n\n### Discover a region, blueprint, and bundle\n\nCreating an instance needs a region, an availability zone, a `blueprintId`, and a `bundleId`.\n\n```javascript\nimport {\n  GetBlueprintsCommand,\n  GetBundlesCommand,\n  GetRegionsCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst [regions, blueprints, bundles] = await Promise.all([\n  lightsail.send(\n    new GetRegionsCommand({\n      includeAvailabilityZones: true,\n    }),\n  ),\n  lightsail.send(\n    new GetBlueprintsCommand({\n      includeInactive: false,\n    }),\n  ),\n  lightsail.send(\n    new GetBundlesCommand({\n      includeInactive: false,\n    }),\n  ),\n]);\n\nfor (const region of regions.regions ?? []) {\n  console.log(region.name, region.availabilityZones?.map((zone) => zone.zoneName));\n}\n\nfor (const blueprint of blueprints.blueprints ?? []) {\n  console.log(blueprint.blueprintId, blueprint.name, blueprint.isActive);\n}\n\nfor (const bundle of bundles.bundles ?? []) {\n  console.log(bundle.bundleId, bundle.name, bundle.price);\n}\n```\n\nUse active blueprints when creating new instances.\n\n### Create an instance\n\n`CreateInstancesCommand` creates one or more instances and returns operation records. It does not return the finished instance object directly.\n\n```javascript\nimport {\n  CreateInstancesCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await lightsail.send(\n  new CreateInstancesCommand({\n    instanceNames: [\"web-1\"],\n    availabilityZone: \"us-east-1a\",\n    blueprintId: \"amazon_linux_2023\",\n    bundleId: \"micro_3_0\",\n    keyPairName: \"default\",\n    userData: [\n      \"#!/bin/bash\",\n      \"dnf -y update\",\n      \"dnf -y install nginx\",\n      \"systemctl enable --now nginx\",\n    ].join(\"\\n\"),\n    tags: [\n      {\n        key: \"Name\",\n        value: \"web-1\",\n      },\n    ],\n  }),\n);\n\nconst operationId = response.operations?.[0]?.id;\nconsole.log(operationId);\n```\n\n### Wait for the operation, then read the instance\n\nMany Lightsail create, update, attach, and delete calls return operation objects. Poll the operation until it becomes terminal, then fetch the resource you care about.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  GetInstanceCommand,\n  GetOperationCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function waitForOperation(operationId) {\n  while (true) {\n    const response = await lightsail.send(\n      new GetOperationCommand({\n        operationId,\n      }),\n    );\n\n    if (response.operation?.isTerminal) {\n      return response.operation;\n    }\n\n    await sleep(5000);\n  }\n}\n\nawait waitForOperation(\"operation-id-from-create\");\n\nconst instance = await lightsail.send(\n  new GetInstanceCommand({\n    instanceName: \"web-1\",\n  }),\n);\n\nconsole.log(instance.instance?.state?.name);\nconsole.log(instance.instance?.publicIpAddress);\n```\n\n### Open a public port on an instance\n\nUse `OpenInstancePublicPortsCommand` to allow inbound traffic. `portInfo` can scope access with IPv4 CIDRs, IPv6 CIDRs, or Lightsail alias lists.\n\n```javascript\nimport {\n  LightsailClient,\n  OpenInstancePublicPortsCommand,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait lightsail.send(\n  new OpenInstancePublicPortsCommand({\n    instanceName: \"web-1\",\n    portInfo: {\n      fromPort: 80,\n      toPort: 80,\n      protocol: \"tcp\",\n      cidrs: [\"0.0.0.0/0\"],\n    },\n  }),\n);\n```\n\nFor SSH or RDP, narrow the CIDR range whenever possible instead of opening it to the entire internet.\n\n### Allocate and attach a static IP\n\nStatic IP assignment is a two-step flow: allocate the static IP resource, then attach it to the instance.\n\n```javascript\nimport {\n  AllocateStaticIpCommand,\n  AttachStaticIpCommand,\n  GetStaticIpCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait lightsail.send(\n  new AllocateStaticIpCommand({\n    staticIpName: \"web-1-ip\",\n  }),\n);\n\nawait lightsail.send(\n  new AttachStaticIpCommand({\n    staticIpName: \"web-1-ip\",\n    instanceName: \"web-1\",\n  }),\n);\n\nconst response = await lightsail.send(\n  new GetStaticIpCommand({\n    staticIpName: \"web-1-ip\",\n  }),\n);\n\nconsole.log(response.staticIp?.ipAddress);\nconsole.log(response.staticIp?.attachedTo);\n```\n\n### Get temporary SSH access details\n\n`GetInstanceAccessDetailsCommand` returns temporary access details for the instance. The default protocol is `ssh`; use `rdp` for Windows instances.\n\n```javascript\nimport {\n  GetInstanceAccessDetailsCommand,\n  LightsailClient,\n} from \"@aws-sdk/client-lightsail\";\n\nconst lightsail = new LightsailClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await lightsail.send(\n  new GetInstanceAccessDetailsCommand({\n    instanceName: \"web-1\",\n    protocol: \"ssh\",\n  }),\n);\n\nconsole.log(response.accessDetails?.username);\nconsole.log(response.accessDetails?.ipAddress);\nconsole.log(response.accessDetails?.privateKey);\n```\n\nTreat `privateKey`, `password`, and related access fields as secrets.\n\n## Pitfalls\n\n- Lightsail resources are regional. Creating an instance in one region and looking it up in another looks like a missing resource.\n- `CreateInstancesCommand` requires an `availabilityZone`, not only a region.\n- Use active blueprints for new instances. The service still lists inactive blueprints for older resources.\n- `customImageName` is discontinued and should not be part of new instance creation flows.\n- Many mutating operations return `operations` metadata rather than a fully provisioned resource. Poll the operation before assuming the resource is ready.\n- Opening a public port requires the nested `portInfo` object; the CIDR scope is part of that object.\n- Static IP allocation and static IP attachment are separate API calls.\n- `GetInstanceAccessDetailsCommand` returns temporary access credentials. Do not treat them as long-lived keys.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-lightsail` version `3.1007.0`.\n- Prefer `LightsailClient` and explicit command imports for predictable dependencies and clearer application code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Lightsail client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/lightsail/`\n- AWS CLI Lightsail command reference: `https://docs.aws.amazon.com/cli/latest/reference/lightsail/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-lightsail`\n"
  },
  {
    "path": "content/aws/docs/location/javascript/DOC.md",
    "content": "---\nname: location\ndescription: \"AWS SDK for JavaScript v3 Amazon Location client for place search, routing, and tracker position APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,amazon-location,location,maps,routing,geocoding,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-location`\n\nUse this package for Amazon Location Service APIs in AWS SDK for JavaScript v3. The most common application-side tasks are place search, reverse geocoding, route calculation, and tracker position updates or reads.\n\nThis client works with named Amazon Location resources such as place indexes, route calculators, trackers, maps, and geofence collections. Create those resources first in the AWS console or your infrastructure tooling, then use their names in SDK calls.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-location\n```\n\nPrefer `LocationClient` plus explicit command imports.\n\n## Credentials, region, and required resource names\n\nUse the standard AWS SDK v3 credential chain in Node.js. A local shell setup usually looks like this:\n\n```bash\nexport AWS_REGION=YOUR_REGION\nexport AWS_PROFILE=your-profile\n# Or set AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN instead.\n\nexport AWS_LOCATION_INDEX_NAME=your-place-index\nexport AWS_LOCATION_ROUTE_CALCULATOR_NAME=your-route-calculator\nexport AWS_LOCATION_TRACKER_NAME=your-tracker\n```\n\nKeep the client region aligned with the region that contains your Amazon Location resources. A place index or tracker in one region is not available from a client configured for another region.\n\n## Initialize the client\n\n```javascript\nimport { LocationClient } from \"@aws-sdk/client-location\";\n\nfunction requiredEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Set ${name} before calling Amazon Location.`);\n  }\n\n  return value;\n}\n\nconst location = new LocationClient({\n  region: requiredEnv(\"AWS_REGION\"),\n});\n```\n\nFor browser applications, use temporary credentials such as Cognito-backed credentials. Do not ship long-lived AWS access keys to the browser.\n\n## Core usage pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  LocationClient,\n  SearchPlaceIndexForTextCommand,\n} from \"@aws-sdk/client-location\";\n\nconst location = new LocationClient({\n  region: process.env.AWS_REGION,\n});\n\nconst response = await location.send(\n  new SearchPlaceIndexForTextCommand({\n    IndexName: process.env.AWS_LOCATION_INDEX_NAME,\n    Text: \"1600 Amphitheatre Parkway, Mountain View, CA\",\n    MaxResults: 5,\n  }),\n);\n\nfor (const result of response.Results ?? []) {\n  console.log(result.Place?.Label, result.Place?.Geometry?.Point);\n}\n```\n\nAmazon Location coordinate arrays use `[longitude, latitude]`, not `[latitude, longitude]`.\n\n## Common workflows\n\n### Search for an address or point of interest\n\n```javascript\nimport {\n  LocationClient,\n  SearchPlaceIndexForTextCommand,\n} from \"@aws-sdk/client-location\";\n\nfunction requiredEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing ${name}`);\n  }\n\n  return value;\n}\n\nconst client = new LocationClient({\n  region: requiredEnv(\"AWS_REGION\"),\n});\n\nconst response = await client.send(\n  new SearchPlaceIndexForTextCommand({\n    IndexName: requiredEnv(\"AWS_LOCATION_INDEX_NAME\"),\n    Text: \"1 Market St, San Francisco, CA\",\n    MaxResults: 5,\n  }),\n);\n\nfor (const result of response.Results ?? []) {\n  console.log({\n    label: result.Place?.Label,\n    position: result.Place?.Geometry?.Point,\n  });\n}\n```\n\nUse `MaxResults` to cap the response size when you only need a few candidates.\n\n### Reverse geocode a known position\n\n```javascript\nimport {\n  LocationClient,\n  SearchPlaceIndexForPositionCommand,\n} from \"@aws-sdk/client-location\";\n\nconst client = new LocationClient({\n  region: process.env.AWS_REGION,\n});\n\nconst response = await client.send(\n  new SearchPlaceIndexForPositionCommand({\n    IndexName: process.env.AWS_LOCATION_INDEX_NAME,\n    Position: [-122.395936, 37.793682],\n    MaxResults: 1,\n  }),\n);\n\nconst bestMatch = response.Results?.[0];\n\nconsole.log(bestMatch?.Place?.Label);\n```\n\nThe `Position` array is still `[longitude, latitude]`.\n\n### Calculate a route between two coordinates\n\n```javascript\nimport {\n  CalculateRouteCommand,\n  LocationClient,\n} from \"@aws-sdk/client-location\";\n\nfunction requiredEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing ${name}`);\n  }\n\n  return value;\n}\n\nconst client = new LocationClient({\n  region: requiredEnv(\"AWS_REGION\"),\n});\n\nconst response = await client.send(\n  new CalculateRouteCommand({\n    CalculatorName: requiredEnv(\"AWS_LOCATION_ROUTE_CALCULATOR_NAME\"),\n    DeparturePosition: [-122.335167, 47.608013],\n    DestinationPosition: [-122.137469, 47.639721],\n    TravelMode: \"Car\",\n  }),\n);\n\nconsole.dir(response.Summary, { depth: null });\nconsole.log(`Leg count: ${response.Legs?.length ?? 0}`);\n```\n\nKeep the route calculator name in configuration, not hard-coded in request handlers.\n\n### Update one or more device positions in a tracker\n\n```javascript\nimport {\n  BatchUpdateDevicePositionCommand,\n  LocationClient,\n} from \"@aws-sdk/client-location\";\n\nfunction requiredEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing ${name}`);\n  }\n\n  return value;\n}\n\nconst client = new LocationClient({\n  region: requiredEnv(\"AWS_REGION\"),\n});\n\nconst response = await client.send(\n  new BatchUpdateDevicePositionCommand({\n    TrackerName: requiredEnv(\"AWS_LOCATION_TRACKER_NAME\"),\n    Updates: [\n      {\n        DeviceId: \"vehicle-42\",\n        Position: [-122.335167, 47.608013],\n        SampleTime: new Date(),\n      },\n      {\n        DeviceId: \"vehicle-43\",\n        Position: [-122.330062, 47.603832],\n        SampleTime: new Date(),\n      },\n    ],\n  }),\n);\n\nif ((response.Errors ?? []).length > 0) {\n  console.error(response.Errors);\n}\n```\n\nBatch tracker updates can partially fail. Always inspect `Errors` instead of assuming the whole batch succeeded.\n\n### Read the latest known position for tracked devices\n\n```javascript\nimport {\n  BatchGetDevicePositionCommand,\n  LocationClient,\n} from \"@aws-sdk/client-location\";\n\nconst client = new LocationClient({\n  region: process.env.AWS_REGION,\n});\n\nconst response = await client.send(\n  new BatchGetDevicePositionCommand({\n    TrackerName: process.env.AWS_LOCATION_TRACKER_NAME,\n    DeviceIds: [\"vehicle-42\", \"vehicle-43\"],\n  }),\n);\n\nfor (const device of response.DevicePositions ?? []) {\n  console.log({\n    deviceId: device.DeviceId,\n    position: device.Position,\n    sampleTime: device.SampleTime,\n  });\n}\n```\n\nUse this call when you need the current position snapshot. Reach for history-specific APIs only when you need older samples.\n\n## Important gotchas\n\n- Resource names are required on most operations. Store `IndexName`, `CalculatorName`, `TrackerName`, `MapName`, or `CollectionName` in configuration and inject them into requests.\n- Coordinates are `[longitude, latitude]` throughout the Location APIs.\n- Region mismatches are a common cause of confusing failures. Keep the client region and the resource region the same.\n- Browser apps need temporary AWS credentials. Do not embed long-lived IAM user keys in frontend code.\n- Map APIs return data such as tiles or style descriptors, but this package does not render a map UI by itself.\n- Stick to top-level imports from `@aws-sdk/client-location`; do not deep-import from generated SDK internals.\n\n## Related packages\n\n- `@aws-sdk/credential-providers`: useful when you need explicit profile, SSO, Cognito, or assume-role credential configuration.\n\n## Useful links\n\n- AWS SDK for JavaScript v3 package: `https://www.npmjs.com/package/@aws-sdk/client-location`\n- AWS SDK v3 client source: `https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-location`\n- Amazon Location API Reference: `https://docs.aws.amazon.com/location/latest/APIReference/Welcome.html`\n"
  },
  {
    "path": "content/aws/docs/macie2/javascript/DOC.md",
    "content": "---\nname: macie2\ndescription: \"AWS SDK for JavaScript v3 client for enabling Amazon Macie, inspecting S3 bucket coverage, running classification jobs, and working with findings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,macie,macie2,s3,security,data-classification,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-macie2`\n\nUse this package to manage Amazon Macie from JavaScript or TypeScript. The client covers Macie account setup, S3 bucket inventory and search, classification jobs, findings, sensitive-data reveal, allow lists, custom data identifiers, tagging, and organization or member workflows.\n\nMacie is regional. The SDK requires a region, and the service model resolves endpoints as `macie2.<region>.<dnsSuffix>`. If you override the endpoint, do not combine that with FIPS or dual-stack settings.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-macie2`, not the legacy `aws-sdk` v2 package.\n- Set `region` explicitly or provide it through the normal AWS SDK configuration chain.\n- Macie must be enabled for the account in the target region before most account-scoped APIs are useful.\n- Most list-style APIs paginate with `nextToken`; build pagination into scripts from the start.\n- `CreateClassificationJobCommand` requires a `clientToken` and explicit S3 bucket owner account IDs.\n- `GetSensitiveDataOccurrencesCommand` is asynchronous; check availability first, then poll until the status becomes `SUCCESS` or `ERROR`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-macie2\n```\n\nTypical local environment variables:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\nexport AWS_ACCOUNT_ID=\"123456789012\"\nexport MACIE_BUCKET_NAME=\"example-sensitive-data-bucket\"\n```\n\n`AWS_ACCOUNT_ID` is not required by the SDK itself, but it is convenient for classification job requests because Macie expects bucket owner account IDs in `s3JobDefinition.bucketDefinitions`.\n\n## Prerequisites\n\nMacie uses the standard AWS SDK for JavaScript v3 credential chain in Node.js. Environment variables, shared AWS config files, IAM Identity Center, ECS task roles, and EC2 instance roles all work with the normal SDK behavior.\n\nYour IAM principal also needs Macie permissions for the operations you call. Common setup issues are not package issues: they are usually missing IAM permissions, Macie not being enabled in the region yet, or targeting the wrong region for the S3 buckets and findings you expect.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { Macie2Client } from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { Macie2Client } from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## What This Client Covers\n\nCommon areas in the generated client surface:\n\n- Account lifecycle: `EnableMacieCommand`, `GetMacieSessionCommand`, `UpdateMacieSessionCommand`\n- S3 inventory: `DescribeBucketsCommand`, `SearchResourcesCommand`, `GetBucketStatisticsCommand`\n- Classification jobs: `CreateClassificationJobCommand`, `DescribeClassificationJobCommand`, `ListClassificationJobsCommand`\n- Findings: `ListFindingsCommand`, `GetFindingsCommand`, `CreateSampleFindingsCommand`\n- Sensitive-data reveal: `GetSensitiveDataOccurrencesAvailabilityCommand`, `GetSensitiveDataOccurrencesCommand`\n- Detection tuning: allow lists, managed data identifiers, custom data identifiers, findings filters, and sensitivity inspection templates\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetMacieSessionCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst session = await macie.send(new GetMacieSessionCommand({}));\n\nconsole.log({\n  status: session.status,\n  findingPublishingFrequency: session.findingPublishingFrequency,\n  serviceRole: session.serviceRole,\n});\n```\n\n## Common Workflows\n\n### Enable Macie or inspect the current session\n\n`GetMacieSessionCommand` reads the current account status. `EnableMacieCommand` enables Macie and lets you choose the policy-finding publishing frequency.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  EnableMacieCommand,\n  GetMacieSessionCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait macie.send(\n  new EnableMacieCommand({\n    status: \"ENABLED\",\n    findingPublishingFrequency: \"FIFTEEN_MINUTES\",\n    clientToken: randomUUID(),\n  }),\n);\n\nconst session = await macie.send(new GetMacieSessionCommand({}));\n\nconsole.log({\n  status: session.status,\n  findingPublishingFrequency: session.findingPublishingFrequency,\n});\n```\n\nUse `GetMacieSessionCommand` by itself when you only want to inspect the existing account configuration. If you want to pause or resume Macie later, use `UpdateMacieSessionCommand` with `status: \"PAUSED\"` or `status: \"ENABLED\"`.\n\n### List S3 buckets that Macie monitors\n\n`DescribeBucketsCommand` returns Macie bucket metadata such as the bucket ARN, region, object counts, classifiable object counts, encryption details, public access information, and the most recent job or automated-discovery metadata.\n\n```javascript\nimport {\n  DescribeBucketsCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await macie.send(\n    new DescribeBucketsCommand({\n      maxResults: 50,\n      nextToken,\n      sortCriteria: {\n        attributeName: \"bucketName\",\n        orderBy: \"ASC\",\n      },\n    }),\n  );\n\n  for (const bucket of page.buckets ?? []) {\n    console.log({\n      name: bucket.bucketName,\n      arn: bucket.bucketArn,\n      region: bucket.region,\n      objectCount: bucket.objectCount,\n      classifiableObjectCount: bucket.classifiableObjectCount,\n      automatedDiscoveryMonitoringStatus:\n        bucket.automatedDiscoveryMonitoringStatus,\n      allowsUnencryptedObjectUploads: bucket.allowsUnencryptedObjectUploads,\n      errorCode: bucket.errorCode,\n    });\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\nIf a bucket shows `errorCode: \"ACCESS_DENIED\"`, Macie found the bucket but could not retrieve the metadata it needs for analysis.\n\n### Create and poll a one-time classification job\n\nFor a one-time job, set `jobType: \"ONE_TIME\"` and omit `scheduleFrequency`. The minimal request is `name`, `clientToken`, `jobType`, and `s3JobDefinition`.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  CreateClassificationJobCommand,\n  DescribeClassificationJobCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst accountId = process.env.AWS_ACCOUNT_ID;\nconst bucketName = process.env.MACIE_BUCKET_NAME;\n\nif (!accountId || !bucketName) {\n  throw new Error(\"Set AWS_ACCOUNT_ID and MACIE_BUCKET_NAME.\");\n}\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst created = await macie.send(\n  new CreateClassificationJobCommand({\n    name: `scan-${bucketName}`,\n    description: \"One-time Macie scan created from the SDK\",\n    clientToken: randomUUID(),\n    jobType: \"ONE_TIME\",\n    managedDataIdentifierSelector: \"RECOMMENDED\",\n    s3JobDefinition: {\n      bucketDefinitions: [\n        {\n          accountId,\n          buckets: [bucketName],\n        },\n      ],\n    },\n    tags: {\n      environment: \"dev\",\n    },\n  }),\n);\n\nconsole.log({\n  jobId: created.jobId,\n  jobArn: created.jobArn,\n});\n\nconst terminalStates = new Set([\n  \"COMPLETE\",\n  \"CANCELLED\",\n  \"USER_PAUSED\",\n  \"PAUSED\",\n  \"IDLE\",\n]);\n\nwhile (true) {\n  const job = await macie.send(\n    new DescribeClassificationJobCommand({\n      jobId: created.jobId,\n    }),\n  );\n\n  console.log({\n    jobId: job.jobId,\n    jobStatus: job.jobStatus,\n    objectsScanned: job.statistics?.objectsScanned,\n    bytesProcessed: job.statistics?.bytesProcessed,\n  });\n\n  if (job.jobStatus && terminalStates.has(job.jobStatus)) {\n    break;\n  }\n\n  await sleep(10_000);\n}\n```\n\nFor recurring jobs, switch to `jobType: \"SCHEDULED\"` and provide `scheduleFrequency` with a daily, weekly, or monthly schedule.\n\n### Create sample findings, then fetch full finding details\n\n`CreateSampleFindingsCommand` is a safe way to exercise finding workflows without waiting for a real classification result. `ListFindingsCommand` returns finding IDs; call `GetFindingsCommand` to retrieve the actual finding objects.\n\n```javascript\nimport {\n  CreateSampleFindingsCommand,\n  GetFindingsCommand,\n  ListFindingsCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait macie.send(\n  new CreateSampleFindingsCommand({\n    findingTypes: [\"SensitiveData:S3Object/Financial\"],\n  }),\n);\n\nconst list = await macie.send(\n  new ListFindingsCommand({\n    maxResults: 10,\n    sortCriteria: {\n      attributeName: \"createdAt\",\n      orderBy: \"DESC\",\n    },\n  }),\n);\n\nif (!list.findingIds?.length) {\n  throw new Error(\"No findings returned.\");\n}\n\nconst details = await macie.send(\n  new GetFindingsCommand({\n    findingIds: list.findingIds,\n  }),\n);\n\nfor (const finding of details.findings ?? []) {\n  console.log({\n    id: finding.id,\n    sample: finding.sample,\n    category: finding.category,\n    type: finding.type,\n    title: finding.title,\n    severity: finding.severity?.description,\n    bucketName: finding.resourcesAffected?.s3Bucket?.name,\n    objectKey: finding.resourcesAffected?.s3Object?.key,\n  });\n}\n```\n\n### Reveal sensitive data occurrences for a finding\n\nBefore requesting the reveal, call `GetSensitiveDataOccurrencesAvailabilityCommand`. If availability is `UNAVAILABLE`, inspect the returned reasons instead of polling blindly.\n\n```javascript\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport {\n  GetSensitiveDataOccurrencesAvailabilityCommand,\n  GetSensitiveDataOccurrencesCommand,\n  Macie2Client,\n} from \"@aws-sdk/client-macie2\";\n\nconst macie = new Macie2Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst findingId = process.env.MACIE_FINDING_ID;\n\nif (!findingId) {\n  throw new Error(\"Set MACIE_FINDING_ID.\");\n}\n\nconst availability = await macie.send(\n  new GetSensitiveDataOccurrencesAvailabilityCommand({\n    findingId,\n  }),\n);\n\nif (availability.code !== \"AVAILABLE\") {\n  console.log(\"Reveal is unavailable:\", availability.reasons);\n} else {\n  while (true) {\n    const result = await macie.send(\n      new GetSensitiveDataOccurrencesCommand({\n        findingId,\n      }),\n    );\n\n    if (result.status === \"SUCCESS\") {\n      console.dir(result.sensitiveDataOccurrences, { depth: null });\n      break;\n    }\n\n    if (result.status === \"ERROR\") {\n      throw new Error(result.error ?? \"Macie failed to reveal occurrences.\");\n    }\n\n    await sleep(2_000);\n  }\n}\n```\n\nThe generated service model also defines a `FindingRevealed` waiter. If you prefer not to manage polling yourself, check the waiter exports available in the exact SDK version you ship.\n\n## Pitfalls\n\n- Macie is enabled per account and region. A client configured for the wrong region will not see the buckets, jobs, or findings you expect.\n- `ListFindingsCommand` returns only finding IDs. Use `GetFindingsCommand` for the actual finding payloads.\n- `GetSensitiveDataOccurrencesCommand` is not an immediate read. The response status can be `PROCESSING` before the reveal is ready.\n- `CreateClassificationJobCommand` needs the bucket owner account ID in `s3JobDefinition.bucketDefinitions`, not just a bucket name.\n- Many list and search APIs default to partial result sets. Keep `maxResults` and `nextToken` in every inventory script.\n- Custom endpoints cannot be combined with FIPS or dual-stack endpoint settings for this service model.\n\n## Version Notes\n\n- This guide is pinned to `@aws-sdk/client-macie2` version `3.1007.0`.\n- The Macie service model used by the generated client is `2020-01-01`.\n- The AWS JavaScript SDK v3 docs site is a rolling latest view. When exact command exports matter, check the installed package version in `package.json` alongside the maintainer docs.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Macie client: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/macie2/`\n- Amazon Macie API Reference: `https://docs.aws.amazon.com/macie/latest/APIReference/`\n- Amazon Macie User Guide: `https://docs.aws.amazon.com/macie/latest/user/what-is-macie.html`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-macie2`\n"
  },
  {
    "path": "content/aws/docs/managedblockchain/javascript/DOC.md",
    "content": "---\nname: managedblockchain\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Managed Blockchain networks, members, nodes, proposals, and accessors.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,managedblockchain,javascript,nodejs,ethereum,hyperledger-fabric\"\n---\n\n# `@aws-sdk/client-managedblockchain`\n\nUse this package for Amazon Managed Blockchain control-plane APIs from AWS SDK for JavaScript v3. It covers network, member, node, proposal, tag, and accessor management for Hyperledger Fabric and Ethereum where those APIs apply.\n\nFramework support is operation-specific. The service model marks `ListMembers`, `GetMember`, `CreateMember`, `ListProposals`, and `VoteOnProposal` as Hyperledger Fabric only, while `ListNetworks`, `GetNetwork`, `ListNodes`, `GetNode`, and `CreateNode` apply to both Hyperledger Fabric and Ethereum.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-managedblockchain\n```\n\n## Credentials and region\n\nManaged Blockchain requests are SigV4-signed AWS API calls, so the client needs AWS credentials and a region.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIn Node.js, the default AWS SDK credential provider chain also supports shared config files and IAM roles.\n\n## Initialize the client\n\n```javascript\nimport { ManagedBlockchainClient } from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## List networks\n\n`ListNetworks` returns the Managed Blockchain networks that the current AWS account participates in.\n\n```javascript\nimport {\n  ListNetworksCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Networks } = await client.send(\n  new ListNetworksCommand({\n    Framework: \"ETHEREUM\",\n    MaxResults: 25,\n  }),\n);\n\nfor (const network of Networks ?? []) {\n  console.log(network.Id, network.Name, network.Framework, network.Status);\n}\n```\n\nValid `Framework` values are `\"HYPERLEDGER_FABRIC\"` and `\"ETHEREUM\"`.\n\n## Get network details\n\n`GetNetwork` returns framework-specific attributes in addition to the general network metadata.\n\n```javascript\nimport {\n  GetNetworkCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Network } = await client.send(\n  new GetNetworkCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n  }),\n);\n\nconsole.log(\"network\", Network?.Id, Network?.Name, Network?.Framework);\nconsole.log(\"vpc endpoint service\", Network?.VpcEndpointServiceName);\nconsole.log(\"fabric ordering endpoint\", Network?.FrameworkAttributes?.Fabric?.OrderingServiceEndpoint);\nconsole.log(\"ethereum chain id\", Network?.FrameworkAttributes?.Ethereum?.ChainId);\n```\n\nUse the framework-specific fields conditionally. A Fabric network exposes Fabric attributes, and an Ethereum network exposes Ethereum attributes.\n\n## Work with Hyperledger Fabric members\n\nMember APIs apply only to Hyperledger Fabric.\n\n### List members\n\n```javascript\nimport {\n  ListMembersCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Members } = await client.send(\n  new ListMembersCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    IsOwned: true,\n    MaxResults: 25,\n  }),\n);\n\nfor (const member of Members ?? []) {\n  console.log(member.Id, member.Name, member.Status, member.IsOwned);\n}\n```\n\n### Get a member\n\n```javascript\nimport {\n  GetMemberCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Member } = await client.send(\n  new GetMemberCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    MemberId: process.env.MB_MEMBER_ID,\n  }),\n);\n\nconsole.log(Member?.Name, Member?.Status);\nconsole.log(\"fabric admin\", Member?.FrameworkAttributes?.Fabric?.AdminUsername);\nconsole.log(\"fabric CA endpoint\", Member?.FrameworkAttributes?.Fabric?.CaEndpoint);\n```\n\n### Create a member from an invitation\n\n`CreateMember` requires an invitation ID and Hyperledger Fabric admin credentials.\n\n```javascript\nimport {\n  CreateMemberCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { MemberId } = await client.send(\n  new CreateMemberCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    InvitationId: process.env.MB_INVITATION_ID,\n    MemberConfiguration: {\n      Name: \"operations-member\",\n      FrameworkConfiguration: {\n        Fabric: {\n          AdminUsername: \"mbadmin\",\n          AdminPassword: process.env.MB_ADMIN_PASSWORD,\n        },\n      },\n      LogPublishingConfiguration: {\n        Fabric: {\n          CaLogs: {\n            Cloudwatch: {\n              Enabled: true,\n            },\n          },\n        },\n      },\n    },\n  }),\n);\n\nconsole.log(MemberId);\n```\n\nThe member admin password must be 8 to 32 characters and include at least one uppercase letter, one lowercase letter, and one digit. It cannot include spaces, `@`, quotes, or slashes.\n\n## List nodes and read node endpoints\n\nNode APIs apply to both Hyperledger Fabric and Ethereum.\n\n### List nodes\n\n```javascript\nimport {\n  ListNodesCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Nodes } = await client.send(\n  new ListNodesCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    MemberId: process.env.MB_MEMBER_ID,\n    MaxResults: 25,\n  }),\n);\n\nfor (const node of Nodes ?? []) {\n  console.log(node.Id, node.InstanceType, node.AvailabilityZone, node.Status);\n}\n```\n\nFor Ethereum networks, omit `MemberId`. For Hyperledger Fabric, include `MemberId` when you want to scope the list to a member.\n\n### Get a node and inspect framework-specific endpoints\n\n```javascript\nimport {\n  GetNodeCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Node } = await client.send(\n  new GetNodeCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    NodeId: process.env.MB_NODE_ID,\n    MemberId: process.env.MB_MEMBER_ID,\n  }),\n);\n\nconsole.log(\"fabric peer\", Node?.FrameworkAttributes?.Fabric?.PeerEndpoint);\nconsole.log(\"fabric peer events\", Node?.FrameworkAttributes?.Fabric?.PeerEventEndpoint);\nconsole.log(\"ethereum http\", Node?.FrameworkAttributes?.Ethereum?.HttpEndpoint);\nconsole.log(\"ethereum websocket\", Node?.FrameworkAttributes?.Ethereum?.WebSocketEndpoint);\n```\n\nEthereum node endpoints returned by `GetNode` are for Ethereum API or JSON-RPC access and the service model notes that those connections use SigV4 authentication.\n\n## Create or update a node\n\n### Create a node\n\n`CreateNode` works for Hyperledger Fabric and Ethereum. `InstanceType` is required. `AvailabilityZone` is required for Ethereum nodes. For Hyperledger Fabric, `StateDB` can be `\"LevelDB\"` or `\"CouchDB\"`.\n\n```javascript\nimport {\n  CreateNodeCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { NodeId } = await client.send(\n  new CreateNodeCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    MemberId: process.env.MB_MEMBER_ID,\n    NodeConfiguration: {\n      InstanceType: process.env.MB_INSTANCE_TYPE,\n      StateDB: \"CouchDB\",\n      LogPublishingConfiguration: {\n        Fabric: {\n          ChaincodeLogs: {\n            Cloudwatch: {\n              Enabled: true,\n            },\n          },\n          PeerLogs: {\n            Cloudwatch: {\n              Enabled: true,\n            },\n          },\n        },\n      },\n    },\n    Tags: {\n      environment: \"dev\",\n    },\n  }),\n);\n\nconsole.log(NodeId);\n```\n\nFor an Ethereum node, pass the public network ID and an availability zone instead of Fabric-only fields:\n\n```javascript\nimport {\n  CreateNodeCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { NodeId } = await client.send(\n  new CreateNodeCommand({\n    NetworkId: \"n-ethereum-mainnet\",\n    NodeConfiguration: {\n      InstanceType: process.env.MB_INSTANCE_TYPE,\n      AvailabilityZone: process.env.MB_AVAILABILITY_ZONE,\n    },\n  }),\n);\n\nconsole.log(NodeId);\n```\n\n### Update Fabric node logging\n\n`UpdateNode` applies only to Hyperledger Fabric and updates log publishing configuration.\n\n```javascript\nimport {\n  ManagedBlockchainClient,\n  UpdateNodeCommand,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new UpdateNodeCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    MemberId: process.env.MB_MEMBER_ID,\n    NodeId: process.env.MB_NODE_ID,\n    LogPublishingConfiguration: {\n      Fabric: {\n        ChaincodeLogs: {\n          Cloudwatch: {\n            Enabled: true,\n          },\n        },\n        PeerLogs: {\n          Cloudwatch: {\n            Enabled: true,\n          },\n        },\n      },\n    },\n  }),\n);\n```\n\n## Ethereum accessors\n\nAccessors are for token-based access. The service returns an accessor ID and a billing token when you create one.\n\n```javascript\nimport {\n  CreateAccessorCommand,\n  ListAccessorsCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst created = await client.send(\n  new CreateAccessorCommand({\n    AccessorType: \"BILLING_TOKEN\",\n    NetworkType: \"ETHEREUM_MAINNET\",\n    Tags: {\n      environment: \"dev\",\n    },\n  }),\n);\n\nconsole.log(created.AccessorId, created.BillingToken, created.NetworkType);\n\nconst listed = await client.send(\n  new ListAccessorsCommand({\n    NetworkType: \"ETHEREUM_MAINNET\",\n    MaxResults: 25,\n  }),\n);\n\nfor (const accessor of listed.Accessors ?? []) {\n  console.log(accessor.Id, accessor.Type, accessor.NetworkType, accessor.Status);\n}\n```\n\nThe accessor type is currently restricted to `\"BILLING_TOKEN\"`.\n\n## Vote on a Hyperledger Fabric proposal\n\nProposal APIs apply only to Hyperledger Fabric.\n\n```javascript\nimport {\n  ListProposalsCommand,\n  ManagedBlockchainClient,\n  VoteOnProposalCommand,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Proposals } = await client.send(\n  new ListProposalsCommand({\n    NetworkId: process.env.MB_NETWORK_ID,\n    MaxResults: 25,\n  }),\n);\n\nconst proposalId = Proposals?.[0]?.ProposalId;\n\nif (proposalId) {\n  await client.send(\n    new VoteOnProposalCommand({\n      NetworkId: process.env.MB_NETWORK_ID,\n      ProposalId: proposalId,\n      VoterMemberId: process.env.MB_MEMBER_ID,\n      Vote: \"YES\",\n    }),\n  );\n}\n```\n\nValid `Vote` values are `\"YES\"` and `\"NO\"`.\n\n## Manual pagination\n\nList operations use `MaxResults` and `NextToken`.\n\n```javascript\nimport {\n  ListNetworksCommand,\n  ManagedBlockchainClient,\n} from \"@aws-sdk/client-managedblockchain\";\n\nconst client = new ManagedBlockchainClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListNetworksCommand({\n      Framework: \"HYPERLEDGER_FABRIC\",\n      MaxResults: 25,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const network of page.Networks ?? []) {\n    console.log(network.Id, network.Name);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n## Important notes\n\n- Check the framework before choosing an API. Several member and proposal operations are Fabric-only.\n- `GetNode` returns different endpoint fields by framework: Fabric uses peer endpoints, while Ethereum uses HTTP and WebSocket endpoints.\n- Ethereum node endpoints use SigV4 authentication.\n- `CreateNode` requires `AvailabilityZone` for Ethereum nodes.\n- `StateDB` applies only to Hyperledger Fabric and can be `\"LevelDB\"` or `\"CouchDB\"`.\n- The service model notes that `CreateAccessor` `NetworkType` still includes legacy values such as `\"ETHEREUM_GOERLI\"` and `\"POLYGON_MUMBAI\"`, but those values are no longer available for new selection after those networks shut down.\n"
  },
  {
    "path": "content/aws/docs/marketplace-catalog/javascript/DOC.md",
    "content": "---\nname: marketplace-catalog\ndescription: \"AWS SDK for JavaScript v3 client for AWS Marketplace Catalog entity lookups, change sets, tagging, and resource policies\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,marketplace,marketplace-catalog,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-marketplace-catalog`\n\nUse this package for AWS Marketplace Catalog API operations from JavaScript or TypeScript. The common flow is:\n\n1. list or describe catalog entities\n2. submit a change set\n3. poll the change set until it reaches a terminal status\n\nFor the operations in this client, `Catalog` is the fixed string `AWSMarketplace`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-marketplace-catalog\n```\n\n## Credentials and region\n\nThis client uses the normal AWS SDK for JavaScript v3 credential resolution flow. In Node.js, that usually means environment variables, shared AWS config, IAM Identity Center, or an attached IAM role.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=my-marketplace-profile\n```\n\nIf you use static credentials instead:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\n```\n\n## Initialize the client\n\n```javascript\nimport { MarketplaceCatalogClient } from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n```\n\n## List entities\n\n`ListEntities` returns summaries for one entity type at a time. Valid `EntityType` values documented in the service model include `AmiProduct`, `ContainerProduct`, `DataProduct`, `SaaSProduct`, `Offer`, `OfferSet`, `ResaleAuthorization`, and `Solution`.\n\n```javascript\nimport {\n  MarketplaceCatalogClient,\n  ListEntitiesCommand,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function listOffers() {\n  let nextToken;\n\n  do {\n    const page = await marketplaceCatalog.send(\n      new ListEntitiesCommand({\n        Catalog: CATALOG,\n        EntityType: \"Offer\",\n        MaxResults: 20,\n        OwnershipType: \"SELF\",\n        Sort: {\n          SortBy: \"LastModifiedDate\",\n          SortOrder: \"DESCENDING\",\n        },\n        NextToken: nextToken,\n      }),\n    );\n\n    for (const entity of page.EntitySummaryList ?? []) {\n      console.log(entity.EntityId, entity.Name, entity.Visibility);\n    }\n\n    nextToken = page.NextToken;\n  } while (nextToken);\n}\n```\n\nNotes:\n\n- `MaxResults` for `ListEntities` is 1-50.\n- Generic `FilterList` on `ListEntities` is for `EntityId` filtering. For richer filtering, use `EntityTypeFilters` with the specific entity family.\n- `OwnershipType` defaults to `SELF`. Use `SHARED` for entities shared through AWS RAM.\n\n## Describe one entity\n\n`DescribeEntity` returns full details for a single entity ID.\n\n```javascript\nimport {\n  DescribeEntityCommand,\n  MarketplaceCatalogClient,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function describeEntity(entityId) {\n  const response = await marketplaceCatalog.send(\n    new DescribeEntityCommand({\n      Catalog: CATALOG,\n      EntityId: entityId,\n    }),\n  );\n\n  const details = response.DetailsDocument ?? JSON.parse(response.Details ?? \"{}\");\n\n  console.log(response.EntityType);\n  console.log(response.EntityIdentifier);\n  console.log(response.LastModifiedDate);\n  console.dir(details, { depth: null });\n}\n```\n\nImportant response fields:\n\n- `EntityType` is returned as `EntityType@Version`.\n- `EntityIdentifier` is returned as `EntityId@RevisionId`.\n- `DetailsDocument` is already structured JSON. `Details` is the stringified JSON form.\n\n## Describe multiple entities in one request\n\nUse `BatchDescribeEntities` when you already know the entity IDs.\n\n```javascript\nimport {\n  BatchDescribeEntitiesCommand,\n  MarketplaceCatalogClient,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function batchDescribe(entityIds) {\n  const response = await marketplaceCatalog.send(\n    new BatchDescribeEntitiesCommand({\n      EntityRequestList: entityIds.map((entityId) => ({\n        Catalog: CATALOG,\n        EntityId: entityId,\n      })),\n    }),\n  );\n\n  for (const [entityId, entity] of Object.entries(response.EntityDetails ?? {})) {\n    console.log(entityId, entity.EntityType, entity.EntityIdentifier);\n  }\n\n  for (const [entityId, error] of Object.entries(response.Errors ?? {})) {\n    console.error(entityId, error.ErrorCode, error.ErrorMessage);\n  }\n}\n```\n\n## Start a change set\n\n`StartChangeSet` is the write path for Marketplace Catalog updates. The outer request shape is stable, but the contents of each change's `DetailsDocument` depend on the entity type and change type you are using.\n\nThe service supports both `Intent: \"VALIDATE\"` and `Intent: \"APPLY\"`. If you omit `Intent`, the service treats it as `APPLY`.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n  MarketplaceCatalogClient,\n  StartChangeSetCommand,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function startChangeSet() {\n  const detailsDocument = JSON.parse(\n    await readFile(\"./changeset-details.json\", \"utf8\"),\n  );\n\n  const response = await marketplaceCatalog.send(\n    new StartChangeSetCommand({\n      Catalog: CATALOG,\n      Intent: \"VALIDATE\",\n      ChangeSetName: \"example-change-set\",\n      ClientRequestToken: randomUUID(),\n      ChangeSet: [\n        {\n          ChangeType: process.env.MARKETPLACE_CHANGE_TYPE,\n          Entity: {\n            Type: process.env.MARKETPLACE_ENTITY_TYPE,\n            Identifier: process.env.MARKETPLACE_ENTITY_IDENTIFIER,\n          },\n          DetailsDocument: detailsDocument,\n          ChangeName: \"primary-change\",\n        },\n      ],\n    }),\n  );\n\n  console.log(response.ChangeSetId);\n  console.log(response.ChangeSetArn);\n}\n```\n\nUse this environment alongside the example above:\n\n```bash\nexport MARKETPLACE_CHANGE_TYPE=YOUR_CHANGE_TYPE\nexport MARKETPLACE_ENTITY_TYPE=YOUR_ENTITY_TYPE_WITH_VERSION\nexport MARKETPLACE_ENTITY_IDENTIFIER=YOUR_ENTITY_ID_OR_ENTITY_ID_AT_REVISION\n```\n\nKeep in mind:\n\n- A single request can include 1-20 changes.\n- Each change requires `ChangeType` and `Entity`.\n- Use `DetailsDocument` for JSON input or `Details` for stringified JSON, but not both on the same change.\n- `ClientRequestToken` is the idempotency token for safe retries.\n\n## Poll a change set until it finishes\n\n`DescribeChangeSet` is how you track the asynchronous workflow.\n\n```javascript\nimport {\n  DescribeChangeSetCommand,\n  MarketplaceCatalogClient,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForChangeSet(changeSetId) {\n  while (true) {\n    const response = await marketplaceCatalog.send(\n      new DescribeChangeSetCommand({\n        Catalog: CATALOG,\n        ChangeSetId: changeSetId,\n      }),\n    );\n\n    console.log(response.Status, response.FailureCode, response.FailureDescription);\n\n    if (\n      response.Status === \"SUCCEEDED\" ||\n      response.Status === \"FAILED\" ||\n      response.Status === \"CANCELLED\"\n    ) {\n      for (const change of response.ChangeSet ?? []) {\n        for (const error of change.ErrorDetailList ?? []) {\n          console.error(change.ChangeName ?? change.ChangeType, error.ErrorCode, error.ErrorMessage);\n        }\n      }\n\n      return response;\n    }\n\n    await sleep(10_000);\n  }\n}\n```\n\nChange set statuses are `PREPARING`, `APPLYING`, `SUCCEEDED`, `CANCELLED`, and `FAILED`.\n\n## Cancel an in-flight change set\n\n```javascript\nimport {\n  CancelChangeSetCommand,\n  MarketplaceCatalogClient,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function cancelChangeSet(changeSetId) {\n  await marketplaceCatalog.send(\n    new CancelChangeSetCommand({\n      Catalog: CATALOG,\n      ChangeSetId: changeSetId,\n    }),\n  );\n}\n```\n\n## List recent change sets\n\nUse `ListChangeSets` when you need audit-style visibility into recent work.\n\n```javascript\nimport {\n  ListChangeSetsCommand,\n  MarketplaceCatalogClient,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nconst CATALOG = \"AWSMarketplace\";\n\nasync function listRecentChangeSets() {\n  let nextToken;\n\n  do {\n    const page = await marketplaceCatalog.send(\n      new ListChangeSetsCommand({\n        Catalog: CATALOG,\n        MaxResults: 20,\n        Sort: {\n          SortBy: \"StartTime\",\n          SortOrder: \"DESCENDING\",\n        },\n        NextToken: nextToken,\n      }),\n    );\n\n    for (const item of page.ChangeSetSummaryList ?? []) {\n      console.log(item.ChangeSetId, item.ChangeSetName, item.Status, item.StartTime);\n    }\n\n    nextToken = page.NextToken;\n  } while (nextToken);\n}\n```\n\n`ListChangeSets` supports filtering by `ChangeSetName`, `Status`, `EntityId`, `BeforeStartTime`, `AfterStartTime`, `BeforeEndTime`, and `AfterEndTime` through `FilterList`.\n\n## Tags and resource policies\n\nThis client also supports tagging and per-resource policy management.\n\n```javascript\nimport {\n  GetResourcePolicyCommand,\n  ListTagsForResourceCommand,\n  MarketplaceCatalogClient,\n  PutResourcePolicyCommand,\n  TagResourceCommand,\n  UntagResourceCommand,\n} from \"@aws-sdk/client-marketplace-catalog\";\n\nconst marketplaceCatalog = new MarketplaceCatalogClient({\n  region: process.env.AWS_REGION,\n});\n\nasync function manageMetadata(resourceArn) {\n  await marketplaceCatalog.send(\n    new TagResourceCommand({\n      ResourceArn: resourceArn,\n      Tags: [\n        { Key: \"environment\", Value: \"prod\" },\n        { Key: \"owner\", Value: \"marketplace-team\" },\n      ],\n    }),\n  );\n\n  const tags = await marketplaceCatalog.send(\n    new ListTagsForResourceCommand({ ResourceArn: resourceArn }),\n  );\n\n  console.log(tags.Tags);\n\n  await marketplaceCatalog.send(\n    new PutResourcePolicyCommand({\n      ResourceArn: resourceArn,\n      Policy: JSON.stringify({\n        Version: \"2012-10-17\",\n        Statement: [],\n      }),\n    }),\n  );\n\n  const policy = await marketplaceCatalog.send(\n    new GetResourcePolicyCommand({ ResourceArn: resourceArn }),\n  );\n\n  console.log(policy.Policy);\n\n  await marketplaceCatalog.send(\n    new UntagResourceCommand({\n      ResourceArn: resourceArn,\n      TagKeys: [\"owner\"],\n    }),\n  );\n}\n```\n\n`PutResourcePolicyCommand` expects `Policy` as a JSON string.\n\n## Common gotchas\n\n- Pass `Catalog: \"AWSMarketplace\"` on the catalog operations that require it.\n- Prefer `DetailsDocument` over `Details` in new code so you can work with real JSON values.\n- Treat `StartChangeSet` as asynchronous work. Submit, then poll with `DescribeChangeSet` until a terminal status.\n- Use `Intent: \"VALIDATE\"` first when you are iterating on a new change payload.\n- `DescribeEntity` and `BatchDescribeEntities` return entity identifiers with revision suffixes. Keep the exact returned value when you need revision-aware workflows.\n- `OwnershipType: \"SHARED\"` only covers AWS RAM shared entities. The service model explicitly notes that entities shared via `PutResourcePolicy` are not discoverable through that flag.\n\n## When you need the exact change payload schema\n\nThe service model exposes generic `DetailsDocument` fields, but the JSON schema inside those fields depends on the entity family and change type. For practical work, keep the SDK client docs open together with the AWS Marketplace Catalog API reference for the specific entity family you are editing.\n"
  },
  {
    "path": "content/aws/docs/mediaconnect/javascript/DOC.md",
    "content": "---\nname: mediaconnect\ndescription: \"AWS SDK for JavaScript v3 client for listing, inspecting, starting, stopping, and tagging AWS Elemental MediaConnect resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,mediaconnect,javascript,nodejs,video,live-streaming,media\"\n---\n\n# `@aws-sdk/client-mediaconnect`\n\nUse `@aws-sdk/client-mediaconnect` to work with AWS Elemental MediaConnect flows, entitlements, bridges, and gateways from JavaScript or TypeScript. For most application code, the common flow is: create a client for the correct AWS region, identify the target flow by ARN, inspect it with `DescribeFlowCommand`, then start, stop, or tag it with explicit commands.\n\nThis package manages MediaConnect resources in AWS. It does not transport video locally or replace the MediaConnect control plane.\n\n## Golden Rules\n\n- Set `region` deliberately. MediaConnect resources are region-scoped.\n- Use the exact resource ARN for the operation you are calling. Flow, output, entitlement, and gateway ARNs are different resource types.\n- Treat `StartFlowCommand` and `StopFlowCommand` as asynchronous control actions. Poll `DescribeFlowCommand` until the flow reaches the status you need.\n- Paginate list operations with `NextToken` when you may have more than one page of results.\n- Keep credentials out of source code. Use the default AWS credential provider chain or a shared profile.\n- Expect flow creation and update payloads to be much larger than simple lifecycle operations; start from AWS request shapes or console-exported values instead of inventing nested config by hand.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-mediaconnect\n```\n\nIf you want to force a shared AWS profile in code instead of relying on the default provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-mediaconnect@3.1007.0`.\n\n## Prerequisites And Authentication\n\nMediaConnect requests need AWS credentials and a region. Most operational calls also need a resource ARN, especially a flow ARN.\n\nTypical environment variables for local development:\n\n```bash\nexport AWS_PROFILE=\"media\"\nexport AWS_REGION=\"us-east-1\"\n\nexport AWS_MEDIACONNECT_FLOW_ARN=\"arn:aws:mediaconnect:us-east-1:123456789012:flow:1-23aBC45dEF67hiJ8-12AbC34DE5fG:AwardsShow\"\nexport AWS_MEDIACONNECT_RESOURCE_ARN=\"$AWS_MEDIACONNECT_FLOW_ARN\"\n```\n\nIn Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { MediaConnectClient } from \"@aws-sdk/client-mediaconnect\";\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Named shared profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MediaConnectClient } from \"@aws-sdk/client-mediaconnect\";\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"media\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ListFlowsCommand,\n  MediaConnectClient,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await mediaconnect.send(\n  new ListFlowsCommand({\n    MaxResults: 20,\n  }),\n);\n\nfor (const flow of response.Flows ?? []) {\n  console.log(flow.Name, flow.Status, flow.FlowArn);\n}\n```\n\n## Common Workflows\n\n### List flows with pagination\n\n`ListFlowsCommand` returns summaries and may include `NextToken`.\n\n```javascript\nimport {\n  ListFlowsCommand,\n  MediaConnectClient,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const response = await mediaconnect.send(\n    new ListFlowsCommand({\n      MaxResults: 20,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const flow of response.Flows ?? []) {\n    console.log(`${flow.Name} [${flow.Status}]`);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Inspect a flow before changing it\n\n`DescribeFlowCommand` returns the current status plus source, output, and entitlement details for the flow.\n\n```javascript\nimport {\n  DescribeFlowCommand,\n  MediaConnectClient,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst flowArn = process.env.AWS_MEDIACONNECT_FLOW_ARN;\n\nif (!flowArn) {\n  throw new Error(\"Set AWS_MEDIACONNECT_FLOW_ARN first.\");\n}\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Flow: flow } = await mediaconnect.send(\n  new DescribeFlowCommand({\n    FlowArn: flowArn,\n  }),\n);\n\nconsole.log(\"name:\", flow?.Name);\nconsole.log(\"status:\", flow?.Status);\nconsole.log(\"source:\", flow?.Source?.Name, flow?.Source?.IngestIp, flow?.Source?.IngestPort);\n\nfor (const output of flow?.Outputs ?? []) {\n  console.log(\"output:\", output.Name, output.OutputArn, output.Destination, output.Port);\n}\n```\n\n### Start a standby flow and wait for `ACTIVE`\n\n`StartFlowCommand` starts the flow but does not wait for it to become active. Poll `DescribeFlowCommand` until `Flow.Status` is `ACTIVE`.\n\n```javascript\nimport {\n  DescribeFlowCommand,\n  MediaConnectClient,\n  StartFlowCommand,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst flowArn = process.env.AWS_MEDIACONNECT_FLOW_ARN;\n\nif (!flowArn) {\n  throw new Error(\"Set AWS_MEDIACONNECT_FLOW_ARN first.\");\n}\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForFlowStatus(flowArn, expectedStatus, timeoutMs = 10 * 60 * 1000) {\n  const startedAt = Date.now();\n\n  while (Date.now() - startedAt < timeoutMs) {\n    const { Flow: flow } = await mediaconnect.send(\n      new DescribeFlowCommand({\n        FlowArn: flowArn,\n      }),\n    );\n\n    const status = flow?.Status;\n    console.log(\"current status:\", status);\n\n    if (status === expectedStatus) {\n      return flow;\n    }\n\n    if (status === \"ERROR\") {\n      throw new Error(\"Flow entered ERROR state.\");\n    }\n\n    await delay(15000);\n  }\n\n  throw new Error(`Timed out waiting for ${expectedStatus}.`);\n}\n\nawait mediaconnect.send(\n  new StartFlowCommand({\n    FlowArn: flowArn,\n  }),\n);\n\nawait waitForFlowStatus(flowArn, \"ACTIVE\");\n```\n\n### Stop a flow and wait for `STANDBY`\n\n```javascript\nimport {\n  DescribeFlowCommand,\n  MediaConnectClient,\n  StopFlowCommand,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst flowArn = process.env.AWS_MEDIACONNECT_FLOW_ARN;\n\nif (!flowArn) {\n  throw new Error(\"Set AWS_MEDIACONNECT_FLOW_ARN first.\");\n}\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForStandby(flowArn, timeoutMs = 10 * 60 * 1000) {\n  const startedAt = Date.now();\n\n  while (Date.now() - startedAt < timeoutMs) {\n    const { Flow: flow } = await mediaconnect.send(\n      new DescribeFlowCommand({\n        FlowArn: flowArn,\n      }),\n    );\n\n    const status = flow?.Status;\n    console.log(\"current status:\", status);\n\n    if (status === \"STANDBY\") {\n      return flow;\n    }\n\n    if (status === \"ERROR\") {\n      throw new Error(\"Flow entered ERROR state.\");\n    }\n\n    await delay(15000);\n  }\n\n  throw new Error(\"Timed out waiting for STANDBY.\");\n}\n\nawait mediaconnect.send(\n  new StopFlowCommand({\n    FlowArn: flowArn,\n  }),\n);\n\nawait waitForStandby(flowArn);\n```\n\n### List entitlements granted to your account\n\nUse `ListEntitlementsCommand` when your account consumes sources shared from another AWS account.\n\n```javascript\nimport {\n  ListEntitlementsCommand,\n  MediaConnectClient,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await mediaconnect.send(\n  new ListEntitlementsCommand({\n    MaxResults: 20,\n  }),\n);\n\nfor (const entitlement of response.Entitlements ?? []) {\n  console.log(entitlement.EntitlementName, entitlement.EntitlementArn);\n}\n```\n\n### Tag a resource and read the current tags\n\n`TagResourceCommand` applies or updates the specified keys. `ListTagsForResourceCommand` reads the full key/value map back.\n\n```javascript\nimport {\n  ListTagsForResourceCommand,\n  MediaConnectClient,\n  TagResourceCommand,\n} from \"@aws-sdk/client-mediaconnect\";\n\nconst resourceArn = process.env.AWS_MEDIACONNECT_RESOURCE_ARN;\n\nif (!resourceArn) {\n  throw new Error(\"Set AWS_MEDIACONNECT_RESOURCE_ARN first.\");\n}\n\nconst mediaconnect = new MediaConnectClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait mediaconnect.send(\n  new TagResourceCommand({\n    ResourceArn: resourceArn,\n    Tags: {\n      stage: \"prod\",\n      team: \"media-ops\",\n    },\n  }),\n);\n\nconst { Tags } = await mediaconnect.send(\n  new ListTagsForResourceCommand({\n    ResourceArn: resourceArn,\n  }),\n);\n\nconsole.log(Tags);\n```\n\n## Practical Notes\n\n- Flow lifecycle operations are simple, but resource creation and update calls can have deeply nested request bodies. For `CreateFlow` and `UpdateFlow`, work from the AWS API reference or a known-good console configuration.\n- `Flow.Status` transitions asynchronously. `STARTING` and `STOPPING` are normal intermediate states; check again before assuming the stream is ready.\n- `ListFlowsCommand` and `ListEntitlementsCommand` are paginated operations. Do not assume one call returns everything in larger accounts.\n- The service also exposes bridge and gateway operations in the same client, but many day-to-day automations only need flow, entitlement, and tagging commands.\n- Server-side usage is the common case. Browser usage is uncommon because MediaConnect operations usually need broad account permissions and direct access to AWS resources.\n\n## Common Pitfalls\n\n- Pointing the client at the wrong region for the flow ARN you are operating on.\n- Passing an entitlement or output ARN to a command that expects a flow ARN.\n- Treating a successful `StartFlowCommand` or `StopFlowCommand` call as the final state instead of polling `DescribeFlowCommand`.\n- Ignoring `NextToken` and silently missing resources in larger accounts.\n- Hardcoding access keys in code instead of using the AWS credential provider chain.\n- Building large `CreateFlow` payloads from memory instead of starting from documented request shapes.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-mediaconnect@3.1007.0`.\n- The AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for operation names and request shapes.\n- The examples here focus on operations that are straightforward to wire into scripts and services: listing flows, describing flows, starting and stopping flows, listing entitlements, and managing tags.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 MediaConnect client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/mediaconnect/`\n- AWS Elemental MediaConnect API Reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/`\n- MediaConnect `ListFlows` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_ListFlows.html`\n- MediaConnect `DescribeFlow` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_DescribeFlow.html`\n- MediaConnect `StartFlow` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_StartFlow.html`\n- MediaConnect `StopFlow` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_StopFlow.html`\n- MediaConnect `ListEntitlements` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_ListEntitlements.html`\n- MediaConnect `TagResource` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_TagResource.html`\n- MediaConnect `ListTagsForResource` API reference: `https://docs.aws.amazon.com/mediaconnect/latest/api/API_ListTagsForResource.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n"
  },
  {
    "path": "content/aws/docs/mediaconvert/javascript/DOC.md",
    "content": "---\nname: mediaconvert\ndescription: \"AWS SDK for JavaScript v3 client for creating, monitoring, and canceling AWS Elemental MediaConvert jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,mediaconvert,javascript,nodejs,video,transcoding,s3\"\n---\n\n# `@aws-sdk/client-mediaconvert`\n\nUse `@aws-sdk/client-mediaconvert` to create and manage AWS Elemental MediaConvert jobs from JavaScript or TypeScript. The normal workflow is: choose the correct AWS region, provide an IAM role ARN and S3 input/output locations, submit a job with `CreateJobCommand`, then poll `GetJobCommand` until the job reaches a terminal state.\n\nThis package manages MediaConvert resources and jobs in AWS. It does not transcode media locally.\n\n## Golden Rules\n\n- Set `region` deliberately. MediaConvert jobs, queues, presets, and templates are region-scoped.\n- Pass a valid IAM role ARN in `Role` when creating jobs. `CreateJobCommand` requires it.\n- Keep your source media in S3 and write outputs to S3 URIs.\n- Treat MediaConvert job settings as real configuration, not something to improvise from memory. Start from a known-good payload or console-generated JSON when possible.\n- New code should not build around `DescribeEndpointsCommand`. AWS documents that operation as deprecated and no longer required.\n- A successful `CreateJobCommand` response means the job was accepted, not that transcoding finished.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-mediaconvert\n```\n\nIf you want to force a shared AWS profile in code instead of relying on the default provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-mediaconvert@3.1007.0`.\n\n## Prerequisites And Authentication\n\nMediaConvert requests need AWS credentials, a region, and S3 locations for inputs and outputs. Job creation also needs an IAM role that MediaConvert can assume.\n\nTypical environment variables for local development:\n\n```bash\nexport AWS_PROFILE=\"media\"\nexport AWS_REGION=\"us-west-2\"\n\nexport AWS_MEDIACONVERT_ROLE_ARN=\"arn:aws:iam::123456789012:role/MediaConvertServiceRole\"\nexport AWS_MEDIACONVERT_INPUT_S3_URI=\"s3://my-input-bucket/source/video.mov\"\nexport AWS_MEDIACONVERT_OUTPUT_S3_URI=\"s3://my-output-bucket/outputs/\"\n\n# Optional: target a non-default queue or explicit endpoint\nexport AWS_MEDIACONVERT_QUEUE_ARN=\"arn:aws:mediaconvert:us-west-2:123456789012:queues/Default\"\nexport AWS_MEDIACONVERT_ENDPOINT=\"https://abcd1234.mediaconvert.us-west-2.amazonaws.com\"\n```\n\nIn Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { MediaConvertClient } from \"@aws-sdk/client-mediaconvert\";\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  ...(process.env.AWS_MEDIACONVERT_ENDPOINT\n    ? { endpoint: process.env.AWS_MEDIACONVERT_ENDPOINT }\n    : {}),\n});\n```\n\nIf you already have an explicit MediaConvert endpoint or VPC endpoint for your account, pass it in `endpoint`. For new code, prefer direct regional client configuration instead of calling the deprecated `DescribeEndpoints` operation.\n\n### Named shared profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MediaConvertClient } from \"@aws-sdk/client-mediaconvert\";\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"media\" }),\n  ...(process.env.AWS_MEDIACONVERT_ENDPOINT\n    ? { endpoint: process.env.AWS_MEDIACONVERT_ENDPOINT }\n    : {}),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  ListQueuesCommand,\n  MediaConvertClient,\n} from \"@aws-sdk/client-mediaconvert\";\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await mediaconvert.send(\n  new ListQueuesCommand({\n    ListBy: \"NAME\",\n    Order: \"ASCENDING\",\n  }),\n);\n\nfor (const queue of response.Queues ?? []) {\n  console.log(queue.Name, queue.Arn);\n}\n```\n\n## Common Workflows\n\n### Submit a basic file-to-file transcoding job\n\nThis example reads one source object from S3 and writes an H.264/AAC MP4 output to an S3 destination prefix.\n\n```javascript\nimport {\n  CreateJobCommand,\n  MediaConvertClient,\n} from \"@aws-sdk/client-mediaconvert\";\n\nconst roleArn = process.env.AWS_MEDIACONVERT_ROLE_ARN;\nconst inputUri = process.env.AWS_MEDIACONVERT_INPUT_S3_URI;\nconst outputUri = process.env.AWS_MEDIACONVERT_OUTPUT_S3_URI;\nconst queueArn = process.env.AWS_MEDIACONVERT_QUEUE_ARN;\n\nif (!roleArn || !inputUri || !outputUri) {\n  throw new Error(\"Set AWS_MEDIACONVERT_ROLE_ARN, AWS_MEDIACONVERT_INPUT_S3_URI, and AWS_MEDIACONVERT_OUTPUT_S3_URI\");\n}\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  ...(process.env.AWS_MEDIACONVERT_ENDPOINT\n    ? { endpoint: process.env.AWS_MEDIACONVERT_ENDPOINT }\n    : {}),\n});\n\nconst response = await mediaconvert.send(\n  new CreateJobCommand({\n    Role: roleArn,\n    ...(queueArn ? { Queue: queueArn } : {}),\n    Settings: {\n      TimecodeConfig: {\n        Source: \"ZEROBASED\",\n      },\n      Inputs: [\n        {\n          FileInput: inputUri,\n          TimecodeSource: \"ZEROBASED\",\n          AudioSelectors: {\n            \"Audio Selector 1\": {\n              DefaultSelection: \"DEFAULT\",\n            },\n          },\n        },\n      ],\n      OutputGroups: [\n        {\n          Name: \"File Group\",\n          OutputGroupSettings: {\n            Type: \"FILE_GROUP_SETTINGS\",\n            FileGroupSettings: {\n              Destination: outputUri,\n            },\n          },\n          Outputs: [\n            {\n              NameModifier: \"-mp4\",\n              ContainerSettings: {\n                Container: \"MP4\",\n              },\n              VideoDescription: {\n                CodecSettings: {\n                  Codec: \"H_264\",\n                  H264Settings: {\n                    RateControlMode: \"QVBR\",\n                    MaxBitrate: 5000000,\n                    QvbrSettings: {\n                      QvbrQualityLevel: 7,\n                    },\n                  },\n                },\n              },\n              AudioDescriptions: [\n                {\n                  AudioSourceName: \"Audio Selector 1\",\n                  CodecSettings: {\n                    Codec: \"AAC\",\n                    AacSettings: {\n                      Bitrate: 96000,\n                      CodingMode: \"CODING_MODE_2_0\",\n                      SampleRate: 48000,\n                    },\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  }),\n);\n\nconsole.log(response.Job?.Id);\nconsole.log(response.Job?.Status);\n```\n\nMediaConvert job settings can become much larger than this. If your team already uses custom presets or job templates, keep those JSON settings under version control and send them through `CreateJobCommand` instead of rebuilding every nested field by hand.\n\n### Poll until the job finishes\n\n`CreateJobCommand` returns quickly. Use `GetJobCommand` to watch the job until it reaches a terminal status.\n\n```javascript\nimport {\n  GetJobCommand,\n  MediaConvertClient,\n} from \"@aws-sdk/client-mediaconvert\";\n\nconst delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  ...(process.env.AWS_MEDIACONVERT_ENDPOINT\n    ? { endpoint: process.env.AWS_MEDIACONVERT_ENDPOINT }\n    : {}),\n});\n\nasync function waitForJob(jobId) {\n  while (true) {\n    const result = await mediaconvert.send(\n      new GetJobCommand({\n        Id: jobId,\n      }),\n    );\n\n    const status = result.Job?.Status ?? \"UNKNOWN\";\n    console.log(status, result.Job?.JobPercentComplete ?? 0);\n\n    if (status === \"COMPLETE\") {\n      return result.Job;\n    }\n\n    if (status === \"ERROR\" || status === \"CANCELED\") {\n      throw new Error(`MediaConvert job ${jobId} finished with status ${status}`);\n    }\n\n    await delay(15000);\n  }\n}\n\nawait waitForJob(\"1678901234567-abcde\");\n```\n\n### Cancel a job\n\nUse `CancelJobCommand` when the current transcode is no longer needed.\n\n```javascript\nimport {\n  CancelJobCommand,\n  MediaConvertClient,\n} from \"@aws-sdk/client-mediaconvert\";\n\nconst mediaconvert = new MediaConvertClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  ...(process.env.AWS_MEDIACONVERT_ENDPOINT\n    ? { endpoint: process.env.AWS_MEDIACONVERT_ENDPOINT }\n    : {}),\n});\n\nawait mediaconvert.send(\n  new CancelJobCommand({\n    Id: \"1678901234567-abcde\",\n  }),\n);\n```\n\n## Practical Notes\n\n- MediaConvert job payloads are large enough that many teams store them as JSON checked into the repo or derived from the MediaConvert console, then inject only the input and output locations at runtime.\n- Keep the client region, queue ARN, job template, preset names, and S3 buckets aligned. Cross-region mismatches are a common cause of confusing failures.\n- The output destination shown above is an S3 prefix such as `s3://bucket/outputs/`, not a local filesystem path.\n- Browser use is uncommon because MediaConvert usually needs broad AWS permissions, service roles, and direct access to account resources.\n\n## Common Pitfalls\n\n- Forgetting the required `Role` field on `CreateJobCommand`.\n- Pointing the client at the wrong AWS region for the queue, preset, or template you want to use.\n- Copying older code that still calls `DescribeEndpointsCommand` for every run.\n- Treating job acceptance as successful transcoding instead of polling `GetJobCommand`.\n- Hand-writing complex job settings once in code and never preserving the known-good JSON that produced them.\n- Using S3 URIs that the MediaConvert service role cannot read from or write to.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-mediaconvert@3.1007.0`.\n- The AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for operation names and request shapes.\n- `DescribeEndpointsCommand` remains part of the client surface for compatibility, but AWS documents `DescribeEndpoints` as deprecated and says it is no longer required for new code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 MediaConvert client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/mediaconvert/`\n- AWS Elemental MediaConvert API Reference: `https://docs.aws.amazon.com/mediaconvert/latest/apireference/`\n- AWS boto3 MediaConvert service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert.html`\n- AWS boto3 `create_job` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/create_job.html`\n- AWS boto3 `get_job` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/get_job.html`\n- AWS boto3 `cancel_job` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/cancel_job.html`\n- AWS boto3 `list_queues` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/list_queues.html`\n- AWS boto3 `describe_endpoints` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/describe_endpoints.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n"
  },
  {
    "path": "content/aws/docs/medialive/javascript/DOC.md",
    "content": "---\nname: medialive\ndescription: \"AWS SDK for JavaScript v3 client for AWS Elemental MediaLive channels, inputs, input security groups, tagging, and channel control-plane operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,medialive,javascript,nodejs,video,streaming,live-video\"\n---\n\n# `@aws-sdk/client-medialive`\n\nUse `@aws-sdk/client-medialive` to manage AWS Elemental MediaLive resources from JavaScript or TypeScript. This is the MediaLive control-plane client: you use it to list and inspect channels and inputs, start and stop channels, manage input security groups, update schedules, and tag MediaLive resources.\n\nPrefer `MediaLiveClient` with explicit command imports for new code.\n\n## Golden Rules\n\n- Set `region` and credentials before creating `MediaLiveClient`; MediaLive resources are regional.\n- Treat `StartChannelCommand` and `StopChannelCommand` as asynchronous operations. Use `waitUntilChannelRunning` and `waitUntilChannelStopped`, or poll `DescribeChannelCommand`.\n- `ListChannels` and `ListInputs` paginate with `NextToken`; AWS SDK v3 also exports `paginateListChannels` and `paginateListInputs`.\n- Input security group whitelist rules are IPv4 CIDR blocks.\n- `DescribeInputCommand` returns `AttachedChannels` as a list, but MediaLive currently documents an input as attachable to one channel at a time.\n- If you automate create flows, pass `RequestId` on retryable operations such as `CreateChannelCommand` and `CreateInputCommand`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-medialive\n```\n\nIf you want explicit shared-profile or SSO helpers in application code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-medialive@3.1007.0`.\n\n## Prerequisites And Authentication\n\nConfigure AWS credentials and a region before calling MediaLive.\n\nTypical local setup:\n\n```bash\naws configure\n\nexport AWS_PROFILE=\"video\"\nexport AWS_REGION=\"us-west-2\"\n\nexport AWS_MEDIALIVE_CHANNEL_ID=\"1234567\"\nexport AWS_MEDIALIVE_INPUT_ID=\"7654321\"\n```\n\nOr with direct credentials:\n\n```bash\nexport AWS_REGION=\"us-west-2\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional, only for temporary credentials\n```\n\nIn Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nYour credentials must allow the MediaLive operations you call, and create/update flows may also require permission to pass any IAM role ARN you include in the request.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { MediaLiveClient } from \"@aws-sdk/client-medialive\";\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Explicit shared profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MediaLiveClient } from \"@aws-sdk/client-medialive\";\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"video\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeChannelCommand,\n  MediaLiveClient,\n} from \"@aws-sdk/client-medialive\";\n\nconst channelId = process.env.AWS_MEDIALIVE_CHANNEL_ID;\n\nif (!channelId) {\n  throw new Error(\"Set AWS_MEDIALIVE_CHANNEL_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await medialive.send(\n  new DescribeChannelCommand({\n    ChannelId: channelId,\n  }),\n);\n\nconsole.log(response.Id, response.Name, response.State);\n```\n\n## Common Workflows\n\n### List channels with the built-in paginator\n\n```javascript\nimport {\n  MediaLiveClient,\n  paginateListChannels,\n} from \"@aws-sdk/client-medialive\";\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nfor await (const page of paginateListChannels(\n  { client: medialive },\n  { MaxResults: 25 },\n)) {\n  for (const channel of page.Channels ?? []) {\n    console.log({\n      id: channel.Id,\n      name: channel.Name,\n      state: channel.State,\n      channelClass: channel.ChannelClass,\n      pipelinesRunningCount: channel.PipelinesRunningCount,\n    });\n  }\n}\n```\n\n### Inspect one channel in detail\n\n`ListChannels` returns summaries. Use `DescribeChannelCommand` when you need the full channel configuration and runtime state.\n\n```javascript\nimport {\n  DescribeChannelCommand,\n  MediaLiveClient,\n} from \"@aws-sdk/client-medialive\";\n\nconst channelId = process.env.AWS_MEDIALIVE_CHANNEL_ID;\n\nif (!channelId) {\n  throw new Error(\"Set AWS_MEDIALIVE_CHANNEL_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Id, Name, State, PipelinesRunningCount, InputAttachments, EgressEndpoints } =\n  await medialive.send(\n    new DescribeChannelCommand({\n      ChannelId: channelId,\n    }),\n  );\n\nconsole.log({\n  Id,\n  Name,\n  State,\n  PipelinesRunningCount,\n  inputIds: (InputAttachments ?? []).map((attachment) => attachment.InputId),\n  egressSourceIps: (EgressEndpoints ?? []).map((endpoint) => endpoint.SourceIp),\n});\n```\n\n### Start a channel and wait until it is running\n\n```javascript\nimport {\n  MediaLiveClient,\n  StartChannelCommand,\n  waitUntilChannelRunning,\n} from \"@aws-sdk/client-medialive\";\n\nconst channelId = process.env.AWS_MEDIALIVE_CHANNEL_ID;\n\nif (!channelId) {\n  throw new Error(\"Set AWS_MEDIALIVE_CHANNEL_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait medialive.send(\n  new StartChannelCommand({\n    ChannelId: channelId,\n  }),\n);\n\nawait waitUntilChannelRunning(\n  { client: medialive, maxWaitTime: 600 },\n  {\n    ChannelId: channelId,\n  },\n);\n\nconsole.log(`Channel ${channelId} is running`);\n```\n\n### Stop a channel and wait until it is idle\n\nThe MediaLive channel-stopped waiter succeeds when the channel state returns to `IDLE`.\n\n```javascript\nimport {\n  MediaLiveClient,\n  StopChannelCommand,\n  waitUntilChannelStopped,\n} from \"@aws-sdk/client-medialive\";\n\nconst channelId = process.env.AWS_MEDIALIVE_CHANNEL_ID;\n\nif (!channelId) {\n  throw new Error(\"Set AWS_MEDIALIVE_CHANNEL_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait medialive.send(\n  new StopChannelCommand({\n    ChannelId: channelId,\n  }),\n);\n\nawait waitUntilChannelStopped(\n  { client: medialive, maxWaitTime: 300 },\n  {\n    ChannelId: channelId,\n  },\n);\n\nconsole.log(`Channel ${channelId} is idle`);\n```\n\n### List inputs and see which channel each input is attached to\n\n```javascript\nimport {\n  MediaLiveClient,\n  paginateListInputs,\n} from \"@aws-sdk/client-medialive\";\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nfor await (const page of paginateListInputs(\n  { client: medialive },\n  { MaxResults: 25 },\n)) {\n  for (const input of page.Inputs ?? []) {\n    console.log({\n      id: input.Id,\n      name: input.Name,\n      type: input.Type,\n      state: input.State,\n      attachedChannels: input.AttachedChannels ?? [],\n    });\n  }\n}\n```\n\n### Inspect one input in detail\n\n```javascript\nimport {\n  DescribeInputCommand,\n  MediaLiveClient,\n} from \"@aws-sdk/client-medialive\";\n\nconst inputId = process.env.AWS_MEDIALIVE_INPUT_ID;\n\nif (!inputId) {\n  throw new Error(\"Set AWS_MEDIALIVE_INPUT_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst input = await medialive.send(\n  new DescribeInputCommand({\n    InputId: inputId,\n  }),\n);\n\nconsole.log({\n  id: input.Id,\n  name: input.Name,\n  type: input.Type,\n  state: input.State,\n  inputClass: input.InputClass,\n  securityGroups: input.SecurityGroups ?? [],\n  sources: (input.Sources ?? []).map((source) => source.Url),\n  destinations: (input.Destinations ?? []).map((destination) => destination.Url),\n});\n```\n\n### Create an input security group\n\nInput security group whitelist rules are CIDR allow-lists for incoming traffic.\n\n```javascript\nimport {\n  CreateInputSecurityGroupCommand,\n  MediaLiveClient,\n} from \"@aws-sdk/client-medialive\";\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await medialive.send(\n  new CreateInputSecurityGroupCommand({\n    Tags: {\n      Environment: \"dev\",\n      Service: \"live-stream\",\n    },\n    WhitelistRules: [\n      { Cidr: \"203.0.113.0/24\" },\n      { Cidr: \"198.51.100.10/32\" },\n    ],\n  }),\n);\n\nconsole.log(response.SecurityGroup?.Id, response.SecurityGroup?.Arn);\n```\n\n### Tag a MediaLive resource by ARN\n\nMediaLive tagging uses the resource ARN, not the numeric channel or input ID.\n\n```javascript\nimport {\n  CreateTagsCommand,\n  DescribeChannelCommand,\n  ListTagsForResourceCommand,\n  MediaLiveClient,\n} from \"@aws-sdk/client-medialive\";\n\nconst channelId = process.env.AWS_MEDIALIVE_CHANNEL_ID;\n\nif (!channelId) {\n  throw new Error(\"Set AWS_MEDIALIVE_CHANNEL_ID\");\n}\n\nconst medialive = new MediaLiveClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst channel = await medialive.send(\n  new DescribeChannelCommand({\n    ChannelId: channelId,\n  }),\n);\n\nif (!channel.Arn) {\n  throw new Error(`Channel ${channelId} did not return an ARN`);\n}\n\nawait medialive.send(\n  new CreateTagsCommand({\n    ResourceArn: channel.Arn,\n    Tags: {\n      Environment: \"prod\",\n      Owner: \"video-platform\",\n    },\n  }),\n);\n\nconst tags = await medialive.send(\n  new ListTagsForResourceCommand({\n    ResourceArn: channel.Arn,\n  }),\n);\n\nconsole.log(tags.Tags);\n```\n\n## MediaLive-Specific Gotchas\n\n- `StartChannelCommand` and `StopChannelCommand` return before the channel reaches its final runtime state. Wait explicitly if later steps depend on `RUNNING` or `IDLE`.\n- `ChannelClass: \"STANDARD\"` means two pipelines; `\"SINGLE_PIPELINE\"` means one pipeline.\n- MediaLive documents `DescribeInput.InputClass` so that `STANDARD` inputs expect two sources for redundancy. If the attached channel is `SINGLE_PIPELINE`, only the first source is ingested.\n- `CreateInputCommand` distinguishes pull and push inputs: pull inputs use `Sources`, while push inputs use `Destinations`.\n- `BatchStartCommand` and `BatchStopCommand` can report per-resource failures in `Failed`, so inspect the response instead of assuming a 200 response means every requested resource changed state.\n- The current MediaLive waiter model includes waiters for channel creation, running, stopped, and deleted states, plus input attached, detached, and deleted states.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, and assume-role helpers for explicit credential setup.\n- `@aws-sdk/client-mediaconvert`: file-based transcoding jobs before or after live pipelines.\n- `@aws-sdk/client-s3`: source and destination object management for adjacent video workflows.\n"
  },
  {
    "path": "content/aws/docs/mediapackage/javascript/DOC.md",
    "content": "---\nname: mediapackage\ndescription: \"AWS SDK for JavaScript v3 client for managing AWS Elemental MediaPackage channels, origin endpoints, ingest credentials, and related settings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,mediapackage,javascript,nodejs,streaming,video,hls,dash,cmaf\"\n---\n\n# `@aws-sdk/client-mediapackage`\n\nUse `@aws-sdk/client-mediapackage` to create and manage AWS Elemental MediaPackage channels, origin endpoints, access controls, log configuration, and ingest credential rotation from JavaScript or TypeScript.\n\nThis package manages MediaPackage resources in AWS. It does not upload, encode, or package media locally. Your encoder pushes a live stream to the ingest URLs that MediaPackage creates for a channel.\n\n## Golden Rules\n\n- Set `region` deliberately. MediaPackage channels, endpoints, and harvest jobs are region-scoped.\n- Choose stable IDs up front. Channel IDs, origin endpoint IDs, and harvest job IDs must be unique within a region and cannot be changed after creation.\n- Treat the returned ingest credentials as secrets. `CreateChannelCommand` and `DescribeChannelCommand` return WebDAV ingest usernames and passwords.\n- Lock down playback explicitly when needed with `Authorization`, `Whitelist`, and `Origination` on origin endpoints.\n- Configure the packaging block you actually need on the origin endpoint, such as `HlsPackage`, `DashPackage`, `CmafPackage`, or `MssPackage`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-mediapackage\n```\n\nIf you want to force a named shared profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-mediapackage@3.1007.0`.\n\n## Prerequisites And Authentication\n\nMediaPackage requests need AWS credentials and a region. Common local-development variables:\n\n```bash\nexport AWS_PROFILE=\"media\"\nexport AWS_REGION=\"us-west-2\"\n\nexport AWS_MEDIAPACKAGE_CHANNEL_ID=\"sportschannel\"\nexport AWS_MEDIAPACKAGE_ENDPOINT_ID=\"sports-hls\"\n\nexport AWS_MEDIAPACKAGE_CDN_SECRET_ARN=\"arn:aws:secretsmanager:us-west-2:123456789012:secret:mediapackage/cdn\"\nexport AWS_MEDIAPACKAGE_SECRETS_ROLE_ARN=\"arn:aws:iam::123456789012:role/MediaPackageSecretsRole\"\n\nexport AWS_MEDIAPACKAGE_INGRESS_LOG_GROUP=\"/aws/mediapackage/ingress\"\nexport AWS_MEDIAPACKAGE_EGRESS_LOG_GROUP=\"/aws/mediapackage/egress\"\n```\n\nIn Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { MediaPackageClient } from \"@aws-sdk/client-mediapackage\";\n\nexport const mediaPackage = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Named shared profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MediaPackageClient } from \"@aws-sdk/client-mediapackage\";\n\nexport const mediaPackage = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"media\" }),\n});\n```\n\n### Small helper for required environment variables\n\n```javascript\nfunction required(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing environment variable: ${name}`);\n  }\n\n  return value;\n}\n```\n\n## Create A Channel\n\n`CreateChannelCommand` requires an `Id`. The response includes `HlsIngest.IngestEndpoints`, which contain the ingest URLs and generated WebDAV credentials for your encoder.\n\n```javascript\nimport {\n  CreateChannelCommand,\n  MediaPackageClient,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst channel = await client.send(\n  new CreateChannelCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    Description: \"24x7 sports feed\",\n    Tags: {\n      environment: \"dev\",\n      workload: \"live-streaming\",\n    },\n  }),\n);\n\nfor (const ingest of channel.HlsIngest?.IngestEndpoints ?? []) {\n  console.log({\n    id: ingest.Id,\n    url: ingest.Url,\n    username: ingest.Username,\n    password: ingest.Password,\n  });\n}\n```\n\nIf the channel already exists, use `DescribeChannelCommand` to re-read the current ingest endpoints:\n\n```javascript\nimport {\n  DescribeChannelCommand,\n  MediaPackageClient,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst channel = await client.send(\n  new DescribeChannelCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n  }),\n);\n\nconsole.log(channel.HlsIngest?.IngestEndpoints ?? []);\n```\n\n## Create An Origin Endpoint\n\nAn origin endpoint attaches packaging and playback settings to a channel. `CreateOriginEndpointCommand` requires `ChannelId` and `Id`.\n\nThis example creates an HLS endpoint and returns the playback URL in `endpoint.Url`:\n\n```javascript\nimport {\n  CreateOriginEndpointCommand,\n  MediaPackageClient,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst endpoint = await client.send(\n  new CreateOriginEndpointCommand({\n    ChannelId: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    Id: required(\"AWS_MEDIAPACKAGE_ENDPOINT_ID\"),\n    Description: \"Public HLS playback\",\n    ManifestName: \"index\",\n    Origination: \"ALLOW\",\n    StartoverWindowSeconds: 300,\n    TimeDelaySeconds: 0,\n    HlsPackage: {\n      PlaylistType: \"EVENT\",\n      PlaylistWindowSeconds: 60,\n      ProgramDateTimeIntervalSeconds: 0,\n      SegmentDurationSeconds: 6,\n      IncludeIframeOnlyStream: false,\n      UseAudioRenditionGroup: false,\n    },\n  }),\n);\n\nconsole.log(endpoint.Url);\n```\n\nIf you use CMAF, MediaPackage exposes HLS manifest URLs under `CmafPackage.HlsManifests`. In the AWS CLI example for `create-origin-endpoint`, the top-level `Url` is empty while `CmafPackage.HlsManifests[].Url` contains the playable manifest URL.\n\n```javascript\nimport {\n  CreateOriginEndpointCommand,\n  MediaPackageClient,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst endpoint = await client.send(\n  new CreateOriginEndpointCommand({\n    ChannelId: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    Id: `${required(\"AWS_MEDIAPACKAGE_ENDPOINT_ID\")}-cmaf`,\n    Description: \"CMAF output\",\n    ManifestName: \"sports_channel\",\n    StartoverWindowSeconds: 300,\n    TimeDelaySeconds: 10,\n    CmafPackage: {\n      SegmentDurationSeconds: 2,\n      SegmentPrefix: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n      HlsManifests: [\n        {\n          Id: \"cmaf_sports_endpoint\",\n          ManifestName: \"index\",\n          AdMarkers: \"PASSTHROUGH\",\n          IncludeIframeOnlyStream: true,\n          PlaylistType: \"EVENT\",\n          PlaylistWindowSeconds: 300,\n          ProgramDateTimeIntervalSeconds: 300,\n        },\n      ],\n    },\n  }),\n);\n\nconsole.log(endpoint.CmafPackage?.HlsManifests?.[0]?.Url ?? null);\n```\n\n## Restrict Access To An Endpoint\n\n`UpdateOriginEndpointCommand` lets you control playback access after creation.\n\n- `Origination: \"ALLOW\"` or `\"DENY\"` controls whether the endpoint can be requested.\n- `Whitelist` accepts source IP CIDR blocks.\n- `Authorization` uses a Secrets Manager secret ARN plus an IAM role ARN that lets MediaPackage read the secret.\n\n```javascript\nimport {\n  MediaPackageClient,\n  UpdateOriginEndpointCommand,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst endpoint = await client.send(\n  new UpdateOriginEndpointCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_ENDPOINT_ID\"),\n    Origination: \"ALLOW\",\n    Whitelist: [\"203.0.113.0/24\", \"198.51.100.10/32\"],\n    Authorization: {\n      CdnIdentifierSecret: required(\"AWS_MEDIAPACKAGE_CDN_SECRET_ARN\"),\n      SecretsRoleArn: required(\"AWS_MEDIAPACKAGE_SECRETS_ROLE_ARN\"),\n    },\n  }),\n);\n\nconsole.log(endpoint.Authorization);\n```\n\n## Rotate Ingest Credentials\n\nIf an encoder credential leaks or you are rotating secrets during maintenance, use `RotateIngestEndpointCredentialsCommand`. It requires the channel `Id` and the specific `IngestEndpointId`.\n\n```javascript\nimport {\n  DescribeChannelCommand,\n  MediaPackageClient,\n  RotateIngestEndpointCredentialsCommand,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst current = await client.send(\n  new DescribeChannelCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n  }),\n);\n\nconst ingestEndpointId = current.HlsIngest?.IngestEndpoints?.[0]?.Id;\n\nif (!ingestEndpointId) {\n  throw new Error(\"No ingest endpoint found on the channel.\");\n}\n\nconst rotated = await client.send(\n  new RotateIngestEndpointCredentialsCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    IngestEndpointId: ingestEndpointId,\n  }),\n);\n\nconsole.log(rotated.HlsIngest?.IngestEndpoints ?? []);\n```\n\nThe response is the updated channel object, so re-read the returned `Username` and `Password` before reconnecting your encoder.\n\n## Configure Access Logs\n\n`ConfigureLogsCommand` sets CloudWatch log group names for ingress and egress access logs on a channel.\n\n```javascript\nimport {\n  ConfigureLogsCommand,\n  MediaPackageClient,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new ConfigureLogsCommand({\n    Id: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    IngressAccessLogs: {\n      LogGroupName: required(\"AWS_MEDIAPACKAGE_INGRESS_LOG_GROUP\"),\n    },\n    EgressAccessLogs: {\n      LogGroupName: required(\"AWS_MEDIAPACKAGE_EGRESS_LOG_GROUP\"),\n    },\n  }),\n);\n```\n\n## List And Tag Resources\n\nMost list operations use `MaxResults` and `NextToken` for pagination.\n\n```javascript\nimport {\n  ListChannelsCommand,\n  ListOriginEndpointsCommand,\n  ListTagsForResourceCommand,\n  MediaPackageClient,\n  TagResourceCommand,\n} from \"@aws-sdk/client-mediapackage\";\n\nconst client = new MediaPackageClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Channels, NextToken } = await client.send(\n  new ListChannelsCommand({\n    MaxResults: 20,\n  }),\n);\n\nconsole.log(Channels?.map((channel) => channel.Id) ?? [], NextToken ?? null);\n\nconst endpoints = await client.send(\n  new ListOriginEndpointsCommand({\n    ChannelId: required(\"AWS_MEDIAPACKAGE_CHANNEL_ID\"),\n    MaxResults: 20,\n  }),\n);\n\nconst channelArn = Channels?.[0]?.Arn;\n\nif (channelArn) {\n  await client.send(\n    new TagResourceCommand({\n      ResourceArn: channelArn,\n      Tags: {\n        owner: \"video-platform\",\n      },\n    }),\n  );\n\n  const tags = await client.send(\n    new ListTagsForResourceCommand({\n      ResourceArn: channelArn,\n    }),\n  );\n\n  console.log(tags.Tags ?? {});\n}\n\nconsole.log(endpoints.OriginEndpoints?.map((endpoint) => endpoint.Id) ?? []);\n```\n\n## Harvest Jobs\n\nIf you use MediaPackage live-to-VOD harvesting, the client exposes `CreateHarvestJobCommand`, `ListHarvestJobsCommand`, and `DescribeHarvestJobCommand`.\n\n`CreateHarvestJobCommand` requires:\n\n- `Id`\n- `OriginEndpointId`\n- `StartTime`\n- `EndTime`\n- `S3Destination.BucketName`\n- `S3Destination.ManifestKey`\n- `S3Destination.RoleArn`\n\n## Important Pitfalls\n\n- `CreateChannelCommand` returns ingest credentials immediately. Store them securely and expect your encoder configuration to depend on them.\n- `CreateOriginEndpointCommand` can return different URL shapes depending on the packaging mode. For CMAF, inspect `CmafPackage.HlsManifests[].Url` instead of assuming `Url` is populated.\n- `RotateIngestEndpointCredentialsCommand` changes the targeted ingest endpoint credentials. Update the encoder before reconnecting.\n- `Origination: \"DENY\"` blocks playback requests even if other access settings look correct.\n- `Whitelist` expects CIDR blocks, not arbitrary hostnames.\n"
  },
  {
    "path": "content/aws/docs/mediastore/javascript/DOC.md",
    "content": "---\nname: mediastore\ndescription: \"AWS SDK for JavaScript v3 client for creating and managing AWS Elemental MediaStore containers, policies, logging, metrics, and tags\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,mediastore,javascript,nodejs,media,storage,video\"\n---\n\n# `@aws-sdk/client-mediastore`\n\nUse `@aws-sdk/client-mediastore` for the AWS Elemental MediaStore control plane in JavaScript or TypeScript. This client manages containers and their policies, access logging, metric policies, and tags.\n\nIt is not the object data-plane client. The common control-plane flow is:\n\n1. create or locate a container\n2. call `DescribeContainerCommand` to get the stable container `Endpoint`\n3. manage access policy, CORS, lifecycle, metrics, logging, and tags\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-mediastore\n```\n\nIf you want to force a shared AWS profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-mediastore@3.1007.0`.\n\n## Prerequisites And Authentication\n\nMediaStore requests need AWS credentials and a region. Most operations also need a container name, and tagging operations need the container ARN.\n\nTypical local environment variables:\n\n```bash\nexport AWS_PROFILE=\"media\"\nexport AWS_REGION=\"us-west-2\"\nexport AWS_MEDIASTORE_CONTAINER_NAME=\"live-events\"\n```\n\nThe SDK can use the default AWS credential chain, or you can provide credentials explicitly.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { MediaStoreClient } from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Use a named shared profile\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MediaStoreClient } from \"@aws-sdk/client-mediastore\";\n\nconst profile = process.env.AWS_PROFILE;\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  ...(profile ? { credentials: fromIni({ profile }) } : {}),\n});\n```\n\n## Common Workflows\n\n### Create a container\n\nContainer names must be unique to your AWS account within a region.\n\n```javascript\nimport {\n  CreateContainerCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Container } = await client.send(\n  new CreateContainerCommand({\n    ContainerName: containerName,\n    Tags: [\n      { Key: \"environment\", Value: \"dev\" },\n      { Key: \"team\", Value: \"media\" },\n    ],\n  }),\n);\n\nconsole.log(Container?.Name);\nconsole.log(Container?.ARN);\nconsole.log(Container?.Status);\n```\n\n`CreateContainerCommand` returns metadata such as `Name`, `ARN`, `Status`, and `AccessLoggingEnabled`, but not the data-plane endpoint. Use `DescribeContainerCommand` next.\n\n### Describe a container and get its endpoint\n\nThe container endpoint is assigned by the service and does not change after it is assigned.\n\n```javascript\nimport {\n  DescribeContainerCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Container } = await client.send(\n  new DescribeContainerCommand({\n    ContainerName: containerName,\n  }),\n);\n\nconsole.log(\"arn:\", Container?.ARN);\nconsole.log(\"status:\", Container?.Status);\nconsole.log(\"endpoint:\", Container?.Endpoint);\nconsole.log(\"access logging:\", Container?.AccessLoggingEnabled);\n```\n\nUse `Container.Endpoint` for MediaStore object operations on the data plane.\n\n### List containers with pagination\n\n`ListContainersCommand` can return `NextToken`. Do not assume one call returns every container.\n\n```javascript\nimport {\n  ListContainersCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nlet nextToken;\n\ndo {\n  const response = await client.send(\n    new ListContainersCommand({\n      MaxResults: 20,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const container of response.Containers ?? []) {\n    console.log(container.Name, container.Status, container.Endpoint);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Put and read a container policy\n\nContainer policies are JSON documents, but the service model uses a string field for `Policy`. Serialize on write and parse on read.\n\n```javascript\nimport {\n  GetContainerPolicyCommand,\n  MediaStoreClient,\n  PutContainerPolicyCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst policyDocument = {\n  Version: \"2012-10-17\",\n  Statement: [\n    {\n      Sid: \"ReadOverHttps\",\n      Effect: \"Allow\",\n      Principal: {\n        AWS: \"arn:aws:iam::123456789012:root\",\n      },\n      Action: [\"mediastore:GetObject\", \"mediastore:DescribeObject\"],\n      Resource: `arn:aws:mediastore:${process.env.AWS_REGION ?? \"us-west-2\"}:123456789012:container/${containerName}/*`,\n      Condition: {\n        Bool: {\n          \"aws:SecureTransport\": \"true\",\n        },\n      },\n    },\n  ],\n};\n\nawait client.send(\n  new PutContainerPolicyCommand({\n    ContainerName: containerName,\n    Policy: JSON.stringify(policyDocument),\n  }),\n);\n\nconst { Policy } = await client.send(\n  new GetContainerPolicyCommand({\n    ContainerName: containerName,\n  }),\n);\n\nconst parsedPolicy = Policy ? JSON.parse(Policy) : undefined;\n\nconsole.log(parsedPolicy);\n```\n\nTo remove the policy:\n\n```javascript\nimport {\n  DeleteContainerPolicyCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new DeleteContainerPolicyCommand({\n    ContainerName: process.env.AWS_MEDIASTORE_CONTAINER_NAME,\n  }),\n);\n```\n\n### Configure CORS\n\nEach CORS rule needs at least one `AllowedOrigins` value and at least one `AllowedMethods` value. Supported methods are `PUT`, `GET`, `DELETE`, and `HEAD`.\n\n```javascript\nimport {\n  GetCorsPolicyCommand,\n  MediaStoreClient,\n  PutCorsPolicyCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new PutCorsPolicyCommand({\n    ContainerName: containerName,\n    CorsPolicy: [\n      {\n        AllowedOrigins: [\"https://app.example.com\"],\n        AllowedMethods: [\"GET\", \"HEAD\"],\n        AllowedHeaders: [\"*\"],\n        ExposeHeaders: [\"ETag\"],\n        MaxAgeSeconds: 3000,\n      },\n    ],\n  }),\n);\n\nconst { CorsPolicy } = await client.send(\n  new GetCorsPolicyCommand({\n    ContainerName: containerName,\n  }),\n);\n\nconsole.log(CorsPolicy);\n```\n\nTo remove the CORS policy:\n\n```javascript\nimport {\n  DeleteCorsPolicyCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new DeleteCorsPolicyCommand({\n    ContainerName: process.env.AWS_MEDIASTORE_CONTAINER_NAME,\n  }),\n);\n```\n\n### Put and read an object lifecycle policy\n\nLifecycle policies are also passed as strings.\n\n```javascript\nimport {\n  GetLifecyclePolicyCommand,\n  MediaStoreClient,\n  PutLifecyclePolicyCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst lifecyclePolicy = {\n  rules: [\n    {\n      definition: {\n        path: [{ prefix: \"archive/\" }],\n        days_since_create: [{ numeric: [\">\", 30] }],\n      },\n      action: \"EXPIRE\",\n    },\n  ],\n};\n\nawait client.send(\n  new PutLifecyclePolicyCommand({\n    ContainerName: containerName,\n    LifecyclePolicy: JSON.stringify(lifecyclePolicy),\n  }),\n);\n\nconst { LifecyclePolicy } = await client.send(\n  new GetLifecyclePolicyCommand({\n    ContainerName: containerName,\n  }),\n);\n\nconst parsedLifecyclePolicy = LifecyclePolicy ? JSON.parse(LifecyclePolicy) : undefined;\n\nconsole.log(parsedLifecyclePolicy);\n```\n\nTo remove the lifecycle policy:\n\n```javascript\nimport {\n  DeleteLifecyclePolicyCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new DeleteLifecyclePolicyCommand({\n    ContainerName: process.env.AWS_MEDIASTORE_CONTAINER_NAME,\n  }),\n);\n```\n\n`DeleteLifecyclePolicyCommand` can take up to 20 minutes to take effect.\n\n### Enable metric collection\n\nMetric policies are structured objects, not strings. You must set `ContainerLevelMetrics`, and object-level rules need both `ObjectGroup` and `ObjectGroupName`.\n\n```javascript\nimport {\n  GetMetricPolicyCommand,\n  MediaStoreClient,\n  PutMetricPolicyCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new PutMetricPolicyCommand({\n    ContainerName: containerName,\n    MetricPolicy: {\n      ContainerLevelMetrics: \"ENABLED\",\n      MetricPolicyRules: [\n        {\n          ObjectGroup: \"archive/*\",\n          ObjectGroupName: \"archive_objects\",\n        },\n      ],\n    },\n  }),\n);\n\nconst { MetricPolicy } = await client.send(\n  new GetMetricPolicyCommand({\n    ContainerName: containerName,\n  }),\n);\n\nconsole.log(MetricPolicy);\n```\n\nTo remove the metric policy:\n\n```javascript\nimport {\n  DeleteMetricPolicyCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new DeleteMetricPolicyCommand({\n    ContainerName: process.env.AWS_MEDIASTORE_CONTAINER_NAME,\n  }),\n);\n```\n\n### Start and stop access logging\n\nWhen access logging is enabled, MediaStore delivers access logs for objects in the container to Amazon CloudWatch Logs.\n\n```javascript\nimport {\n  MediaStoreClient,\n  StartAccessLoggingCommand,\n  StopAccessLoggingCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new StartAccessLoggingCommand({\n    ContainerName: containerName,\n  }),\n);\n\nawait client.send(\n  new StopAccessLoggingCommand({\n    ContainerName: containerName,\n  }),\n);\n```\n\n### Tag a container by ARN\n\nTagging APIs use the container ARN, not the container name.\n\n```javascript\nimport {\n  ListTagsForResourceCommand,\n  MediaStoreClient,\n  TagResourceCommand,\n  UntagResourceCommand,\n} from \"@aws-sdk/client-mediastore\";\n\nconst resourceArn = process.env.AWS_MEDIASTORE_CONTAINER_ARN;\n\nif (!resourceArn) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_ARN first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new TagResourceCommand({\n    Resource: resourceArn,\n    Tags: [\n      { Key: \"environment\", Value: \"dev\" },\n      { Key: \"owner\", Value: \"media-team\" },\n    ],\n  }),\n);\n\nconst { Tags } = await client.send(\n  new ListTagsForResourceCommand({\n    Resource: resourceArn,\n  }),\n);\n\nconsole.log(Tags);\n\nawait client.send(\n  new UntagResourceCommand({\n    Resource: resourceArn,\n    TagKeys: [\"owner\"],\n  }),\n);\n```\n\n### Delete an empty container\n\nYou can delete only empty containers. Remove any objects and folders from the container before calling `DeleteContainerCommand`.\n\n```javascript\nimport {\n  DeleteContainerCommand,\n  MediaStoreClient,\n} from \"@aws-sdk/client-mediastore\";\n\nconst containerName = process.env.AWS_MEDIASTORE_CONTAINER_NAME;\n\nif (!containerName) {\n  throw new Error(\"Set AWS_MEDIASTORE_CONTAINER_NAME first.\");\n}\n\nconst client = new MediaStoreClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait client.send(\n  new DeleteContainerCommand({\n    ContainerName: containerName,\n  }),\n);\n```\n\n## Practical Notes\n\n- This client covers MediaStore container management. Use the container `Endpoint` for object-level MediaStore operations.\n- `GetContainerPolicyCommand` and `GetLifecyclePolicyCommand` return string fields that usually need `JSON.parse(...)` in application code.\n- `ListContainersCommand` is paginated via `NextToken`.\n- CORS rules are ordered. If more than one rule applies, MediaStore uses the first applicable rule.\n- `PutMetricPolicyCommand` requires `ContainerLevelMetrics`. Object-level metric rules are optional, but if you include them each rule needs both `ObjectGroup` and `ObjectGroupName`.\n- `StartAccessLoggingCommand` writes MediaStore access logs to CloudWatch Logs.\n\n## Common Pitfalls\n\n- Creating a policy document as an object and passing it directly instead of `JSON.stringify(...)`.\n- Using a container name where the API expects a container ARN for tagging.\n- Forgetting to read `Container.Endpoint` before making object-level requests.\n- Ignoring `NextToken` and only processing the first page of `ListContainersCommand` results.\n- Expecting `DeleteContainerCommand` to work before the container is empty.\n- Expecting lifecycle policy deletion to take effect immediately.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-mediastore@3.1007.0`.\n- The AWS SDK for JavaScript v3 docs use a rolling `latest` documentation URL. Pin the npm package version in your app if you need reproducible installs.\n- At this version, the control-plane client includes container, policy, CORS, lifecycle, metric, access logging, and tagging operations.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 MediaStore client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/mediastore/`\n- AWS CLI MediaStore command reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/`\n- AWS CLI `create-container` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/create-container.html`\n- AWS CLI `describe-container` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/describe-container.html`\n- AWS CLI `list-containers` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/list-containers.html`\n- AWS CLI `put-container-policy` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/put-container-policy.html`\n- AWS CLI `put-cors-policy` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/put-cors-policy.html`\n- AWS CLI `put-lifecycle-policy` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/put-lifecycle-policy.html`\n- AWS CLI `put-metric-policy` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/put-metric-policy.html`\n- AWS CLI `start-access-logging` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/start-access-logging.html`\n- AWS CLI `list-tags-for-resource` reference: `https://docs.aws.amazon.com/cli/latest/reference/mediastore/list-tags-for-resource.html`\n"
  },
  {
    "path": "content/aws/docs/memorydb/javascript/DOC.md",
    "content": "---\nname: memorydb\ndescription: \"AWS SDK for JavaScript v3 client for Amazon MemoryDB users, ACLs, subnet groups, clusters, snapshots, and related control-plane APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,memorydb,javascript,nodejs,redis,cache,acl\"\n---\n\n# `@aws-sdk/client-memorydb`\n\nUse this package for Amazon MemoryDB control-plane APIs in AWS SDK for JavaScript v3. Typical workflows are: create or inspect users and ACLs, create a subnet group, create or update a cluster, poll until the cluster is usable, and manage snapshots.\n\nThis package does not speak the Redis wire protocol. Use it to provision and inspect MemoryDB resources, then pass the returned endpoint into your Redis-compatible application client.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-memorydb\n```\n\n## Initialize the client\n\n```javascript\nimport { MemoryDBClient } from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS access is already configured through environment variables, shared AWS config files, ECS task roles, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n\nexport MEMORYDB_SUBNET_GROUP=memorydb-private-subnets\nexport MEMORYDB_SECURITY_GROUP_ID=sg-0123456789abcdef0\nexport MEMORYDB_USER_PASSWORD='replace-with-a-strong-password'\n```\n\nSet the region deliberately. MemoryDB clusters, subnet groups, snapshots, and security groups are regional resources.\n\n## What this client covers\n\nUse `@aws-sdk/client-memorydb` for:\n\n- users and ACLs\n- subnet groups\n- cluster create, describe, update, and delete operations\n- snapshots and snapshot restores\n- tags, service updates, and multi-Region cluster APIs\n\nDo not use this client for:\n\n- `GET`, `SET`, pub/sub, streams, or other Redis data-plane commands\n- opening or pooling application connections to the cache\n\nAfter `DescribeClusters` returns a `ClusterEndpoint`, connect to that endpoint with your Redis-compatible client and enable TLS when the cluster has `TLSEnabled` set.\n\n## Common workflow\n\nFor a new cluster, the usual order is:\n\n1. Create or reuse a subnet group in the target VPC.\n2. Create a MemoryDB user.\n3. Create an ACL that includes that user.\n4. Create the cluster with `ACLName`, `SubnetGroupName`, and security groups.\n5. Poll `DescribeClusters` until the cluster status is `available`.\n6. Read `ClusterEndpoint` and hand it to your Redis-compatible client.\n\nMost create, update, snapshot, and delete operations are asynchronous. A successful API call usually means the request was accepted, not that the resource is ready for the next step.\n\n## Common operations\n\n### Create a subnet group\n\nMemoryDB subnet groups are collections of VPC subnets that MemoryDB can place cluster nodes into.\n\n```javascript\nimport {\n  CreateSubnetGroupCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst subnetIds = [\n  \"subnet-0123456789abcdef0\",\n  \"subnet-abcdef01234567890\",\n];\n\nconst { SubnetGroup } = await memorydb.send(\n  new CreateSubnetGroupCommand({\n    SubnetGroupName: process.env.MEMORYDB_SUBNET_GROUP ?? \"memorydb-private-subnets\",\n    Description: \"Private subnets for MemoryDB clusters\",\n    SubnetIds: subnetIds,\n    Tags: [{ Key: \"service\", Value: \"orders\" }],\n  }),\n);\n\nconsole.log(SubnetGroup?.Name, SubnetGroup?.VpcId, SubnetGroup?.SupportedNetworkTypes);\n```\n\n### Create a user\n\n`CreateUser` requires `UserName`, `AuthenticationMode`, and `AccessString`.\n\n```javascript\nimport {\n  CreateUserCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst password = process.env.MEMORYDB_USER_PASSWORD;\n\nif (!password) {\n  throw new Error(\"Set MEMORYDB_USER_PASSWORD before creating a MemoryDB user.\");\n}\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst { User } = await memorydb.send(\n  new CreateUserCommand({\n    UserName: \"orders-app-user\",\n    AuthenticationMode: {\n      Type: \"password\",\n      Passwords: [password],\n    },\n    AccessString: \"on ~* +@all\",\n    Tags: [{ Key: \"service\", Value: \"orders\" }],\n  }),\n);\n\nconsole.log(User?.Name, User?.Status);\n```\n\nIf you already manage users outside application code, reuse the existing user name instead of creating one during deploy.\n\n### Create an ACL\n\nClusters attach to an ACL by name. Keep the required `default` user in the ACL unless you have a specific replacement plan; ACL operations can fail with `DefaultUserRequired` if you remove it.\n\n```javascript\nimport {\n  CreateACLCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst { ACL } = await memorydb.send(\n  new CreateACLCommand({\n    ACLName: \"orders-app-acl\",\n    UserNames: [\"default\", \"orders-app-user\"],\n    Tags: [{ Key: \"service\", Value: \"orders\" }],\n  }),\n);\n\nconsole.log(ACL?.Name, ACL?.Status, ACL?.UserNames);\n```\n\nTo add or remove users later, use `UpdateACLCommand`.\n\n```javascript\nimport {\n  MemoryDBClient,\n  UpdateACLCommand,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait memorydb.send(\n  new UpdateACLCommand({\n    ACLName: \"orders-app-acl\",\n    UserNamesToAdd: [\"reporting-user\"],\n    UserNamesToRemove: [\"old-user\"],\n  }),\n);\n```\n\n### Create a cluster\n\n`CreateCluster` requires `ClusterName`, `NodeType`, and `ACLName`. In normal VPC deployments you also set `SubnetGroupName` and one or more security groups.\n\n```javascript\nimport {\n  CreateClusterCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst securityGroupId = process.env.MEMORYDB_SECURITY_GROUP_ID;\n\nif (!securityGroupId) {\n  throw new Error(\"Set MEMORYDB_SECURITY_GROUP_ID before creating a cluster.\");\n}\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst { Cluster } = await memorydb.send(\n  new CreateClusterCommand({\n    ClusterName: \"orders-cache\",\n    NodeType: process.env.MEMORYDB_NODE_TYPE ?? \"db.r6g.large\",\n    ACLName: \"orders-app-acl\",\n    SubnetGroupName: process.env.MEMORYDB_SUBNET_GROUP ?? \"memorydb-private-subnets\",\n    SecurityGroupIds: [securityGroupId],\n    NumShards: 1,\n    NumReplicasPerShard: 1,\n    Port: 6379,\n    TLSEnabled: true,\n    AutoMinorVersionUpgrade: true,\n    SnapshotRetentionLimit: 7,\n    Tags: [{ Key: \"service\", Value: \"orders\" }],\n  }),\n);\n\nconsole.log(Cluster?.Name, Cluster?.Status, Cluster?.ARN);\n```\n\n`CreateCluster` also supports restore-style inputs such as `SnapshotName` and `SnapshotArns` when you want to seed a new cluster from snapshot data.\n\n### Poll until a cluster is available\n\nThe current MemoryDB service model includes paginators for `Describe*` operations, but it does not publish waiter definitions. For create, update, restore, or delete flows, poll `DescribeClusters` yourself.\n\n```javascript\nimport {\n  DescribeClustersCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForClusterAvailable(clusterName, timeoutMs = 30 * 60 * 1000) {\n  const startedAt = Date.now();\n\n  while (Date.now() - startedAt < timeoutMs) {\n    const { Clusters } = await memorydb.send(\n      new DescribeClustersCommand({\n        ClusterName: clusterName,\n      }),\n    );\n\n    const cluster = Clusters?.[0];\n    const status = cluster?.Status;\n\n    if (status === \"available\") {\n      return cluster;\n    }\n\n    if (status === \"deleting\") {\n      throw new Error(`Cluster ${clusterName} is deleting.`);\n    }\n\n    await sleep(30_000);\n  }\n\n  throw new Error(`Timed out waiting for cluster ${clusterName} to become available.`);\n}\n\nconst cluster = await waitForClusterAvailable(\"orders-cache\");\n\nconsole.log(cluster?.ClusterEndpoint?.Address, cluster?.ClusterEndpoint?.Port);\n```\n\n### Read the cluster endpoint and shard details\n\nSet `ShowShardDetails: true` when you need per-shard and per-node endpoint data.\n\n```javascript\nimport {\n  DescribeClustersCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst { Clusters } = await memorydb.send(\n  new DescribeClustersCommand({\n    ClusterName: \"orders-cache\",\n    ShowShardDetails: true,\n  }),\n);\n\nconst cluster = Clusters?.[0];\n\nconsole.log(cluster?.Status);\nconsole.log(cluster?.ClusterEndpoint?.Address, cluster?.ClusterEndpoint?.Port);\n\nfor (const shard of cluster?.Shards ?? []) {\n  console.log(shard.Name, shard.Status, shard.Slots);\n\n  for (const node of shard.Nodes ?? []) {\n    console.log(node.Name, node.Endpoint?.Address, node.Endpoint?.Port, node.AvailabilityZone);\n  }\n}\n```\n\n### Paginate cluster inventory\n\nThe client publishes paginators for cluster, snapshot, subnet-group, ACL, user, engine-version, service-update, and related describe operations.\n\n```javascript\nimport {\n  MemoryDBClient,\n  paginateDescribeClusters,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nfor await (const page of paginateDescribeClusters(\n  { client: memorydb },\n  { MaxResults: 50, ShowShardDetails: false },\n)) {\n  for (const cluster of page.Clusters ?? []) {\n    console.log(cluster.Name, cluster.Status, cluster.NodeType);\n  }\n}\n```\n\n### Create and inspect snapshots\n\n```javascript\nimport {\n  CreateSnapshotCommand,\n  DescribeSnapshotsCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait memorydb.send(\n  new CreateSnapshotCommand({\n    ClusterName: \"orders-cache\",\n    SnapshotName: \"orders-cache-2026-03-13\",\n  }),\n);\n\nconst { Snapshots } = await memorydb.send(\n  new DescribeSnapshotsCommand({\n    ClusterName: \"orders-cache\",\n    ShowDetail: true,\n  }),\n);\n\nfor (const snapshot of Snapshots ?? []) {\n  console.log(snapshot.Name, snapshot.Status, snapshot.Source, snapshot.ARN);\n}\n```\n\n### Update cluster settings\n\nUse `UpdateCluster` for changes such as snapshot retention, engine version, node type, replica count, shard count, or the attached ACL.\n\n```javascript\nimport {\n  MemoryDBClient,\n  UpdateClusterCommand,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait memorydb.send(\n  new UpdateClusterCommand({\n    ClusterName: \"orders-cache\",\n    SnapshotRetentionLimit: 14,\n    ReplicaConfiguration: {\n      ReplicaCount: 2,\n    },\n    ACLName: \"orders-app-acl\",\n  }),\n);\n```\n\nIf you want to change node type, call `ListAllowedNodeTypeUpdates` first and only pass a `NodeType` value returned by that API.\n\n```javascript\nimport {\n  ListAllowedNodeTypeUpdatesCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst { ScaleUpNodeTypes, ScaleDownNodeTypes } = await memorydb.send(\n  new ListAllowedNodeTypeUpdatesCommand({\n    ClusterName: \"orders-cache\",\n  }),\n);\n\nconsole.log(\"scale up:\", ScaleUpNodeTypes);\nconsole.log(\"scale down:\", ScaleDownNodeTypes);\n```\n\n### Delete a cluster with a final snapshot\n\n```javascript\nimport {\n  DeleteClusterCommand,\n  MemoryDBClient,\n} from \"@aws-sdk/client-memorydb\";\n\nconst memorydb = new MemoryDBClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait memorydb.send(\n  new DeleteClusterCommand({\n    ClusterName: \"orders-cache\",\n    FinalSnapshotName: \"orders-cache-final-2026-03-13\",\n  }),\n);\n```\n\nIf you pass `FinalSnapshotName`, the caller also needs permission to create snapshots. Otherwise `DeleteCluster` can fail with an access denied error.\n\n## Important gotchas\n\n- This is a control-plane package. Use a Redis-compatible client for actual cache reads and writes.\n- `CreateCluster` requires `ACLName`. In normal VPC deployments you also need a subnet group and security groups ready first.\n- `DescribeClusters` only returns shard and node detail when `ShowShardDetails` is true.\n- MemoryDB mutations are asynchronous. Poll `DescribeClusters` or `DescribeSnapshots` until a terminal state instead of assuming the resource is ready immediately.\n- The current service model publishes paginators for many `Describe*` APIs, but not waiter definitions.\n- `DeleteCluster` with `FinalSnapshotName` needs snapshot creation permission in addition to delete permission.\n- `UpdateCluster` can change replica count, shard count, node type, engine version, snapshot settings, and ACL association, but node type changes must use values returned by `ListAllowedNodeTypeUpdates`.\n- Data tiering is only supported on `r6gd` node types. If you use those nodes, set `DataTiering` explicitly.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-memorydb` version `3.1007.0`.\n- The current MemoryDB service model includes multi-Region cluster operations such as `CreateMultiRegionCluster`, `DescribeMultiRegionClusters`, and `UpdateMultiRegionCluster`.\n- The current service model also includes paginators for `DescribeACLs`, `DescribeClusters`, `DescribeEngineVersions`, `DescribeEvents`, `DescribeMultiRegionClusters`, `DescribeParameterGroups`, `DescribeParameters`, `DescribeReservedNodes`, `DescribeReservedNodesOfferings`, `DescribeServiceUpdates`, `DescribeSnapshots`, `DescribeSubnetGroups`, and `DescribeUsers`.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 MemoryDB client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/memorydb/`\n- Amazon MemoryDB API Reference: `https://docs.aws.amazon.com/memorydb/latest/APIReference/Welcome.html`\n- `CreateCluster` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_CreateCluster.html`\n- `DescribeClusters` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_DescribeClusters.html`\n- `CreateSubnetGroup` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_CreateSubnetGroup.html`\n- `CreateUser` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_CreateUser.html`\n- `CreateACL` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_CreateACL.html`\n- `UpdateACL` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_UpdateACL.html`\n- `CreateSnapshot` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_CreateSnapshot.html`\n- `DescribeSnapshots` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_DescribeSnapshots.html`\n- `UpdateCluster` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_UpdateCluster.html`\n- `DeleteCluster` API: `https://docs.aws.amazon.com/memorydb/latest/APIReference/API_DeleteCluster.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n"
  },
  {
    "path": "content/aws/docs/middleware-endpoint/javascript/DOC.md",
    "content": "---\nname: middleware-endpoint\ndescription: \"AWS SDK for JavaScript v3 endpoint resolution middleware for custom clients and endpoint-aware service configuration\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,aws-sdk,javascript,endpoints,middleware\"\n---\n\n# `@aws-sdk/middleware-endpoint`\n\n`@aws-sdk/middleware-endpoint` is the AWS SDK for JavaScript v3 middleware that resolves which endpoint a request should use. In normal application code, you usually consume it indirectly through a service client such as `@aws-sdk/client-s3`. Install and import it directly only when you are building or extending a custom Smithy/AWS client stack.\n\n## When to Use It Directly\n\nUse this package directly when you need to:\n\n- add endpoint resolution to a custom client or middleware stack\n- resolve built-in endpoint settings like `region`, `endpoint`, `useFipsEndpoint`, and `useDualstackEndpoint`\n- attach the standard endpoint plugin with `getEndpointPlugin(...)`\n\nIf you are writing regular application code against AWS services, prefer configuring the service client and let that client add this middleware for you.\n\n## Installation\n\nInstall the middleware package directly only if you are wiring a custom client:\n\n```bash\nnpm install @aws-sdk/middleware-endpoint\n```\n\nFor typical app code, install the service client you actually call. Example with S3:\n\n```bash\nnpm install @aws-sdk/client-s3\n```\n\n## Credentials and Region\n\nThis package does not authenticate requests by itself. Your service client or custom stack still needs AWS credentials and a region for SigV4 signing.\n\nCommon environment variables:\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=your-access-key-id\nAWS_SECRET_ACCESS_KEY=your-secret-access-key\nAWS_SESSION_TOKEN=your-session-token\n```\n\nIf you use a generated AWS client in Node.js, the standard AWS credential provider chain can load credentials from environment variables, shared config, IAM roles, and other supported sources.\n\n## Common App Usage: Configure the Service Client\n\nMost users should configure endpoint behavior on the service client and not import `@aws-sdk/middleware-endpoint` directly.\n\n### Default AWS Endpoint Resolution\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(new ListBucketsCommand({}));\nconsole.log(response.Buckets ?? []);\n```\n\n### Override the Endpoint\n\nUse `endpoint` when you need a fixed host, such as LocalStack or another S3-compatible endpoint.\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.S3_ENDPOINT ?? \"http://localhost:4566\",\n  forcePathStyle: true,\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? \"test\",\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? \"test\",\n  },\n});\n\nconst response = await client.send(new ListBucketsCommand({}));\nconsole.log(response.Buckets ?? []);\n```\n\nEven with a custom endpoint, keep `region` configured so request signing works correctly.\n\n### Enable FIPS or Dual-Stack Endpoints\n\nWhen a service supports these endpoint variants, set them on the client config:\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  useFipsEndpoint: true,\n  useDualstackEndpoint: true,\n});\n```\n\nSupport for FIPS, dual-stack, or a specific combination depends on the service and region endpoint rules.\n\n## Direct Package API\n\nIf you are building a custom client stack, the two main entry points are `resolveEndpointConfig(...)` and `getEndpointPlugin(...)`.\n\n```javascript\nimport {\n  getEndpointPlugin,\n  resolveEndpointConfig,\n} from \"@aws-sdk/middleware-endpoint\";\n\nconst endpointParameterInstructions = {\n  Region: { type: \"builtInParams\", name: \"region\" },\n  Endpoint: { type: \"builtInParams\", name: \"endpoint\" },\n  UseFIPS: { type: \"builtInParams\", name: \"useFipsEndpoint\" },\n  UseDualStack: { type: \"builtInParams\", name: \"useDualstackEndpoint\" },\n};\n\nconst resolvedConfig = resolveEndpointConfig({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  endpoint: process.env.CUSTOM_ENDPOINT,\n  useFipsEndpoint: false,\n  useDualstackEndpoint: false,\n});\n\nmiddlewareStack.use(\n  getEndpointPlugin(resolvedConfig, endpointParameterInstructions)\n);\n```\n\nUse this pattern inside a client or command implementation that already has a Smithy-compatible `middlewareStack`. Generated AWS SDK v3 clients already do this internally.\n\n## Practical Rules\n\n- Install a service client such as `@aws-sdk/client-s3` for normal application code.\n- Install `@aws-sdk/middleware-endpoint` directly only when you are authoring client infrastructure.\n- Set `endpoint` when you need a fixed host override.\n- Set `useFipsEndpoint` and `useDualstackEndpoint` on the client config when the target service supports them.\n- Keep `region` configured even when you override `endpoint`.\n\n## Pitfalls\n\n- `@aws-sdk/middleware-endpoint` does not provide service commands like `ListBucketsCommand`; it only resolves endpoints.\n- A custom `endpoint` does not replace AWS credentials or region configuration.\n- Do not add the endpoint plugin twice to a generated AWS client; generated clients already register it.\n- Service-specific endpoint behavior can still require additional client settings outside this package.\n- Unsupported FIPS or dual-stack combinations fail according to the service's endpoint rules.\n"
  },
  {
    "path": "content/aws/docs/middleware-retry/javascript/DOC.md",
    "content": "---\nname: middleware-retry\ndescription: \"AWS SDK for JavaScript v3 retry middleware package for configuring max attempts, retry mode, and explicit retry strategies on AWS clients.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,javascript,nodejs,sdk,retry,middleware\"\n---\n\n# `@aws-sdk/middleware-retry`\n\nUse `@aws-sdk/middleware-retry` when you need to control how an AWS SDK for JavaScript v3 client retries failed requests. In most apps, the simplest path is setting `maxAttempts` or `retryMode` on the client config. Import this package directly when you want to pass an explicit retry strategy instance.\n\nAWS SDK v3 clients already include retry handling by default. This package is mainly for configuration, not for manually attaching retry middleware in normal application code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/middleware-retry @aws-sdk/client-sts\n```\n\n`@aws-sdk/client-sts` is only here as a concrete client for the examples. Use the same retry configuration with other AWS SDK v3 clients such as S3, DynamoDB, or SQS.\n\n## Retry Configuration Sources\n\nThe SDK can resolve retry settings from explicit client config, environment variables, or the shared AWS config file.\n\nTypical shell setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_RETRY_MODE=standard\nexport AWS_MAX_ATTEMPTS=4\n```\n\nShared AWS config file:\n\n```ini\n[default]\nregion = us-east-1\nretry_mode = standard\nmax_attempts = 4\n```\n\nImportant defaults and precedence:\n\n- Default retry mode is `standard`.\n- Default max attempts is `3`.\n- `AWS_RETRY_MODE` maps to shared config key `retry_mode`.\n- `AWS_MAX_ATTEMPTS` maps to shared config key `max_attempts`.\n- Explicit client config wins over environment variables and shared config.\n\n## Basic Client Setup\n\nFor most applications, set `maxAttempts` directly on the client.\n\n```javascript\nimport {\n  GetCallerIdentityCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst client = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  maxAttempts: 4,\n});\n\nconst response = await client.send(new GetCallerIdentityCommand({}));\n\nconsole.log(response.Account);\nconsole.log(response.Arn);\n```\n\nThis keeps the SDK's built-in retry behavior and only changes the attempt limit.\n\n## Choose a Retry Mode\n\nThe two retry modes exposed through client config are `standard` and `adaptive`.\n\n### Standard mode\n\n`standard` is the default and is the safest choice unless you have a specific reason to change it.\n\n```javascript\nimport { STSClient } from \"@aws-sdk/client-sts\";\n\nconst client = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  retryMode: \"standard\",\n  maxAttempts: 4,\n});\n```\n\n### Adaptive mode\n\nUse `adaptive` when you want the SDK to resolve to `AdaptiveRetryStrategy` instead of the standard strategy.\n\n```javascript\nimport { STSClient } from \"@aws-sdk/client-sts\";\n\nconst client = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  retryMode: \"adaptive\",\n  maxAttempts: 6,\n});\n```\n\nWhen `retryMode` resolves to `adaptive`, the retry config resolver creates `AdaptiveRetryStrategy`. Otherwise it creates `StandardRetryStrategy`.\n\n## Pass an Explicit Retry Strategy\n\nUse an explicit strategy object when the calling code needs to choose the strategy directly rather than through `retryMode`.\n\n### `StandardRetryStrategy`\n\n```javascript\nimport {\n  GetCallerIdentityCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\nimport { StandardRetryStrategy } from \"@aws-sdk/middleware-retry\";\n\nconst client = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  retryStrategy: new StandardRetryStrategy(async () => 5),\n});\n\nawait client.send(new GetCallerIdentityCommand({}));\n```\n\nThe constructor takes a provider function for the maximum attempt count.\n\n### `AdaptiveRetryStrategy`\n\n```javascript\nimport {\n  GetCallerIdentityCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\nimport { AdaptiveRetryStrategy } from \"@aws-sdk/middleware-retry\";\n\nconst client = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  retryStrategy: new AdaptiveRetryStrategy(async () => 6),\n});\n\nawait client.send(new GetCallerIdentityCommand({}));\n```\n\n## Important Behavior\n\n- Prefer `maxAttempts` for normal application code. AWS's retry utilities recommend this over replacing the whole strategy when you only need to change the attempt count.\n- If you set both `maxAttempts` and `retryStrategy`, the explicit `retryStrategy` takes precedence.\n- `AWS_MAX_ATTEMPTS` must parse as a number. Invalid values in the environment or shared config cause configuration loading to fail.\n- `getRetryPlugin`, `retryMiddleware`, and `omitRetryHeadersMiddleware` are internal helpers. Do not build application code against them.\n\n## Version Note\n\nCurrent AWS-maintained Smithy retry packages also expose equivalent retry configuration through `@smithy/middleware-retry` and point advanced backoff customization to `@smithy/util-retry`. If your application is pinned to `@aws-sdk/middleware-retry`, the practical client-level patterns remain the same: use `maxAttempts`, `retryMode`, or an explicit retry strategy instance.\n"
  },
  {
    "path": "content/aws/docs/middleware-signing/javascript/DOC.md",
    "content": "---\nname: middleware-signing\ndescription: \"AWS SDK for JavaScript v3 signing middleware for attaching SigV4 auth to custom Smithy client stacks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.972.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,javascript,aws-sdk,smithy,middleware,signing,sigv4,credentials\"\n---\n\n# `@aws-sdk/middleware-signing`\n\nUse this package when you are building a custom AWS SDK for JavaScript v3 or Smithy-based client and need AWS SigV4 request signing added to the middleware stack.\n\nMost application code should not install this package directly. Generated `@aws-sdk/client-*` packages already wire request signing into their client stacks. Reach for `@aws-sdk/middleware-signing` when you are composing your own client, replacing signing behavior, or attaching AWS auth to a custom middleware stack.\n\n## Install\n\nInstall the package plus the pieces needed for credentials and hashing:\n\n```bash\nnpm install @aws-sdk/middleware-signing@3.972.7 @aws-sdk/credential-providers @aws-crypto/sha256-js @smithy/smithy-client\n```\n\nThis package does not create AWS service clients on its own. It only installs signing middleware.\n\n## Environment and credentials\n\nFor local development, set region and credentials the same way you would for other AWS SDK v3 code:\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\nAWS_SESSION_TOKEN=...\nAWS_PROFILE=default\n```\n\nIn Node.js, you can usually let the default credential chain resolve credentials from environment variables, shared AWS config, ECS, EC2, or IAM Identity Center.\n\n## Add signing middleware to a custom client\n\n`resolveAwsAuthConfig()` normalizes the auth configuration, and `getAwsAuthPlugin()` installs the signing middleware on the client stack.\n\n```javascript\nimport { Client as SmithyClient } from \"@smithy/smithy-client\";\nimport { fromNodeProviderChain } from \"@aws-sdk/credential-providers\";\nimport {\n  getAwsAuthPlugin,\n  resolveAwsAuthConfig,\n} from \"@aws-sdk/middleware-signing\";\nimport { Sha256 } from \"@aws-crypto/sha256-js\";\n\nclass ExampleAwsClient extends SmithyClient {\n  constructor(input = {}) {\n    const region = input.region ?? process.env.AWS_REGION ?? \"us-east-1\";\n\n    const config = resolveAwsAuthConfig({\n      ...input,\n      region: async () => region,\n      credentials: input.credentials ?? fromNodeProviderChain(),\n      sha256: Sha256,\n      signingName: input.signingName ?? \"execute-api\",\n      signingRegion: input.signingRegion ?? (async () => region),\n    });\n\n    super(config);\n    this.middlewareStack.use(getAwsAuthPlugin(config));\n  }\n}\n\nconst client = new ExampleAwsClient();\n```\n\nUse this pattern inside your own Smithy client constructor after you have decided how region, credentials, and the SigV4 service name should resolve.\n\n## Use an explicit shared-profile credential source\n\nContinuing the `ExampleAwsClient` above, swap in `fromIni()` when the client should sign with a named shared config profile instead of the default chain.\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n \nconst client = new ExampleAwsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"default\" }),\n  signingName: \"execute-api\",\n});\n```\n\nUse the same approach with any other AWS credential provider you want to plug into the stack.\n\n## Override the SigV4 service name or signing region\n\nContinuing the same custom client pattern, override `signingName` or `signingRegion` when the endpoint you are calling needs a specific signing identity.\n\n```javascript\nconst client = new ExampleAwsClient({\n  region: \"us-east-1\",\n  signingName: \"execute-api\",\n  signingRegion: async () => \"us-west-2\",\n});\n```\n\n`signingName` is the SigV4 service identifier, not the npm package name. Keep it aligned with the AWS service you are calling.\n\n## Important pitfalls\n\n- Most generated `@aws-sdk/client-*` packages already include signing middleware. Do not add this package on top of a generated client unless you are intentionally replacing or overriding auth behavior.\n- This package does not serialize commands, create HTTP requests, or send network traffic by itself. Your client still needs a real transport and request serialization layer.\n- Credentials and region still must resolve at runtime. Installing the middleware does not load them automatically unless you provide credential and region providers.\n- `signingName` must match the SigV4 service name expected by the target service. A wrong value leads to authentication failures even when the credentials are valid.\n- Browser code needs browser-safe credential providers such as Cognito-based flows. Do not expose long-lived IAM secrets in frontend code.\n- Import from the package root. Do not deep-import package internals from build directories.\n\n## When not to use this package\n\n- If you are calling normal AWS service APIs such as S3, DynamoDB, or STS, install the relevant `@aws-sdk/client-*` package instead.\n- If your existing AWS client already signs requests correctly, do not add this middleware just to make a request authenticated.\n- If you need a one-off signing primitive rather than a middleware plugin, use a signer package directly instead of rewriting a whole client stack around this middleware.\n\n## Version notes\n\n- This guide covers `@aws-sdk/middleware-signing` version `3.972.7`.\n- The maintainer source for this package lives under the AWS SDK for JavaScript v3 repository's internal package tree.\n- Treat this package as low-level SDK plumbing: useful for custom integrations, unnecessary for ordinary service-client usage.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 maintainer source: https://github.com/aws/aws-sdk-js-v3/tree/main/packages-internal/middleware-signing\n- npm package page: https://www.npmjs.com/package/@aws-sdk/middleware-signing\n"
  },
  {
    "path": "content/aws/docs/middleware-stack/javascript/DOC.md",
    "content": "---\nname: middleware-stack\ndescription: \"AWS SDK for JavaScript v3 middleware stack utilities for composing, ordering, and debugging low-level client middleware.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,javascript,aws-sdk,middleware,smithy,client\"\n---\n\n# `@aws-sdk/middleware-stack`\n\nUse this package when you need to build or manipulate the middleware pipeline used by AWS SDK for JavaScript v3 clients and commands.\n\nMost application code does not need to install it directly. Generated `@aws-sdk/client-*` packages already expose `client.middlewareStack` and `command.middlewareStack`, and that is usually where you add custom behavior. Reach for `@aws-sdk/middleware-stack` when you need `constructStack()` itself or when you are composing low-level SDK plumbing.\n\n## Install\n\nInstall the package directly when you are creating or composing a stack yourself:\n\n```bash\nnpm install @aws-sdk/middleware-stack@3.374.0\n```\n\nIf you are customizing an existing AWS client, install the service client you actually use. The client already carries a middleware stack:\n\n```bash\nnpm install @aws-sdk/client-s3\n```\n\n## Environment and prerequisites\n\nThis package does not load credentials, resolve region, sign requests, or send HTTP traffic by itself.\n\nYou do not need any environment variables just to create or mutate a stack. If the surrounding client also signs and sends AWS requests, configure region and credentials the same way you would for other AWS SDK v3 code:\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\nAWS_SESSION_TOKEN=...\nAWS_PROFILE=default\n```\n\n## Middleware lifecycle\n\nThe stack executes middleware in five ordered steps:\n\n- `initialize` - prepare or normalize input before request creation\n- `serialize` - turn input into a request object\n- `build` - modify retry-stable request parts such as headers or checksums\n- `finalizeRequest` - do final transport-specific work such as signing\n- `deserialize` - turn the raw response into structured output\n\nUse the right step for the job. A header that must survive retries belongs in `build`, while signing belongs in `finalizeRequest`.\n\n## Create and resolve a standalone stack\n\n`constructStack()` creates an empty middleware stack. You add middleware with `add()` or `addRelativeTo()`, then turn the stack into a handler with `resolve()`.\n\n```javascript\nimport { constructStack } from \"@aws-sdk/middleware-stack\";\n\nconst stack = constructStack();\n\nstack.add(\n  (next) => async (args) => {\n    return next({\n      ...args,\n      input: {\n        ...args.input,\n        requestId: args.input.requestId ?? \"req-123\",\n      },\n    });\n  },\n  {\n    step: \"initialize\",\n    name: \"defaultRequestId\",\n  }\n);\n\nstack.add(\n  (next) => async (args) => {\n    return next({\n      ...args,\n      request: {\n        method: \"POST\",\n        headers: {\n          \"content-type\": \"application/json\",\n        },\n        body: JSON.stringify(args.input),\n      },\n    });\n  },\n  {\n    step: \"serialize\",\n    name: \"serializeJsonBody\",\n  }\n);\n\nstack.add(\n  (next) => async (args) => {\n    return next({\n      ...args,\n      request: {\n        ...args.request,\n        headers: {\n          ...args.request.headers,\n          \"x-request-id\": args.input.requestId,\n        },\n      },\n    });\n  },\n  {\n    step: \"build\",\n    name: \"addRequestIdHeader\",\n  }\n);\n\nstack.add(\n  (next) => async (args) => {\n    const result = await next(args);\n\n    return {\n      ...result,\n      output: {\n        statusCode: result.response.statusCode,\n        body: JSON.parse(result.response.body),\n      },\n    };\n  },\n  {\n    step: \"deserialize\",\n    name: \"parseJsonResponse\",\n  }\n);\n\nconst handler = stack.resolve(\n  async (args) => {\n    return {\n      response: {\n        statusCode: 200,\n        body: JSON.stringify({\n          ok: true,\n          sentHeaders: args.request.headers,\n        }),\n      },\n      output: undefined,\n    };\n  },\n  {\n    logger: console,\n  }\n);\n\nconst result = await handler({\n  input: {\n    message: \"hello\",\n  },\n});\n\nconsole.log(result.output);\n```\n\n## Add middleware at a specific location\n\nUse `add()` when you know the lifecycle step and optional priority.\n\n```javascript\nimport { constructStack } from \"@aws-sdk/middleware-stack\";\n\nconst stack = constructStack();\n\nstack.add(\n  (next) => async (args) => next(args),\n  {\n    step: \"finalizeRequest\",\n    priority: \"high\",\n    name: \"signingPreparation\",\n    tags: [\"auth\"],\n  }\n);\n```\n\nValid priorities are `high`, `normal`, and `low`. Within the same step and priority, execution order follows insertion order.\n\n## Add middleware relative to another middleware\n\nUse `addRelativeTo()` when you need to run before or after a named middleware.\n\n```javascript\nimport { constructStack } from \"@aws-sdk/middleware-stack\";\n\nconst stack = constructStack();\n\nstack.add(\n  (next) => async (args) => {\n    return next({\n      ...args,\n      request: {\n        ...args.request,\n        headers: {\n          ...args.request.headers,\n          \"x-base-header\": \"base\",\n        },\n      },\n    });\n  },\n  {\n    step: \"build\",\n    name: \"baseHeaders\",\n  }\n);\n\nstack.addRelativeTo(\n  (next) => async (args) => {\n    return next({\n      ...args,\n      request: {\n        ...args.request,\n        headers: {\n          ...args.request.headers,\n          \"x-trace-id\": \"trace-123\",\n        },\n      },\n    });\n  },\n  {\n    relation: \"after\",\n    toMiddleware: \"baseHeaders\",\n    name: \"traceHeaders\",\n  }\n);\n```\n\nRelative middleware must target an existing named middleware. If `toMiddleware` cannot be found, the stack throws when it is resolved.\n\n## Package reusable behavior as a plugin\n\nAny object with `applyToStack(stack)` can be applied with `use()`.\n\n```javascript\nimport { constructStack } from \"@aws-sdk/middleware-stack\";\n\nconst timingPlugin = {\n  applyToStack(stack) {\n    stack.add(\n      (next, context) => async (args) => {\n        const startedAt = Date.now();\n        const result = await next(args);\n\n        context.logger?.info?.(`middleware duration=${Date.now() - startedAt}ms`);\n        return result;\n      },\n      {\n        step: \"finalizeRequest\",\n        name: \"timingMiddleware\",\n        tags: [\"timing\"],\n      }\n    );\n  },\n};\n\nconst stack = constructStack();\nstack.use(timingPlugin);\n```\n\nThis pattern is useful when one customization needs to add or remove multiple middleware entries together.\n\n## Customize an existing AWS client stack\n\nFor normal application code, this is the most common pattern. Generated AWS SDK v3 clients already have a stack, so add middleware there instead of creating a new one from scratch.\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nclient.middlewareStack.add(\n  (next, context) => async (args) => {\n    context.logger?.debug?.(`sending ${context.clientName}.${context.commandName}`);\n    return next(args);\n  },\n  {\n    step: \"initialize\",\n    name: \"logCommandName\",\n  }\n);\n\nawait client.send(new ListBucketsCommand({}));\n```\n\nYou can also attach middleware to a single command instance through `command.middlewareStack` when you want the customization to apply only to one operation.\n\n## Inspect, clone, combine, and remove middleware\n\nThe stack exposes utilities that are useful when you need to debug or safely compose middleware sets.\n\n```javascript\nimport { constructStack } from \"@aws-sdk/middleware-stack\";\n\nconst baseStack = constructStack();\nbaseStack.add(\n  (next) => async (args) => next(args),\n  {\n    step: \"build\",\n    name: \"baseHeaders\",\n    tags: [\"headers\"],\n  }\n);\n\nconst extraStack = constructStack();\nextraStack.add(\n  (next) => async (args) => next(args),\n  {\n    step: \"finalizeRequest\",\n    name: \"requestLogger\",\n    tags: [\"logging\"],\n  }\n);\n\nconst combined = baseStack.concat(extraStack);\nconst cloned = combined.clone();\n\nconsole.log(combined.identify());\n\ncloned.remove(\"requestLogger\");\ncloned.removeByTag(\"headers\");\ncloned.identifyOnResolve(true);\n```\n\n- `concat()` returns a new stack and does not mutate either source stack.\n- `clone()` preserves names, tags, steps, priorities, and relative bindings.\n- `identify()` returns the current middleware order as strings.\n- `identifyOnResolve(true)` logs that order to the console whenever `resolve()` is used.\n\n## Important pitfalls\n\n- Give middleware a stable `name` when other code may need to remove it, replace it, or attach relative middleware around it.\n- Names must be unique unless you deliberately replace an entry with `override: true`.\n- `override: true` is not a free move. Replacements added with `add()` must keep the same step and priority, and replacements added with `addRelativeTo()` must keep the same relation and `toMiddleware` target.\n- `removeByTag()` removes matching middleware from both absolute and relative entries.\n- Relative middleware chains must still be anchored to middleware that was added with `add()`.\n- `identifyOnResolve(true)` is useful for debugging, but it writes to `console` during handler resolution.\n- Import from `@aws-sdk/middleware-stack`, not internal `dist-*` paths.\n\n## Version notes\n\n- This guide covers `@aws-sdk/middleware-stack` version `3.374.0`.\n- The public API used here is `constructStack()` plus stack methods such as `add()`, `addRelativeTo()`, `use()`, `clone()`, `concat()`, `remove()`, `removeByTag()`, `identify()`, `identifyOnResolve()`, and `resolve()`.\n- For most end-user code, you customize `client.middlewareStack` or `command.middlewareStack` on a generated AWS SDK v3 client instead of building a standalone stack.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-middleware-stack/\n- npm package page: https://www.npmjs.com/package/@aws-sdk/middleware-stack\n"
  },
  {
    "path": "content/aws/docs/mwaa/javascript/DOC.md",
    "content": "---\nname: mwaa\ndescription: \"AWS SDK for JavaScript v3 MWAA client for listing environments, reading environment details, creating Airflow login tokens, and invoking the Airflow REST API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,mwaa,airflow,javascript,nodejs,managed-workflows\"\n---\n\n# `@aws-sdk/client-mwaa`\n\nUse this package for Amazon Managed Workflows for Apache Airflow (Amazon MWAA) operations from JavaScript or Node.js. The MWAA client lets you list environments, inspect environment status and endpoints, create short-lived Airflow login tokens, call the managed Airflow REST API, and manage environment tags.\n\nThe service model for this package also exposes `CreateEnvironmentCommand`, `UpdateEnvironmentCommand`, and `DeleteEnvironmentCommand`. `PublishMetricsCommand` exists in the API model, but AWS documents it as internal-only.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-mwaa\n```\n\nInstall the credential provider helpers only if you want to force a named shared-config profile in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\nexport MWAA_ENV_NAME=my-airflow-env\n```\n\n- Keep the SDK region aligned with the MWAA environment region.\n- The default AWS SDK credential provider chain is usually enough in Node.js if credentials already come from environment variables, shared AWS config files, ECS, EC2, or IAM Identity Center.\n- If you tag environments, the tag APIs use the environment ARN, not the environment name.\n\n## Client Setup\n\nUse `MWAAClient` plus explicit command imports.\n\n```javascript\nimport { MWAAClient } from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a named local AWS profile explicitly:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { MWAAClient } from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"default\",\n  }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetEnvironmentCommand,\n  MWAAClient,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Environment } = await mwaa.send(\n  new GetEnvironmentCommand({\n    Name: process.env.MWAA_ENV_NAME,\n  }),\n);\n\nconsole.log(Environment?.Name);\nconsole.log(Environment?.Status);\nconsole.log(Environment?.AirflowVersion);\nconsole.log(Environment?.WebserverUrl);\n```\n\n`GetEnvironmentCommand` is the best first call when you need to confirm the environment exists, check whether it is available, or retrieve the environment ARN and webserver URL for follow-up work.\n\n## Common Workflows\n\n### List environments\n\n`ListEnvironmentsCommand` returns environment names only. Call `GetEnvironmentCommand` for full details.\n\n```javascript\nimport {\n  ListEnvironmentsCommand,\n  MWAAClient,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function listAllEnvironments() {\n  const names = [];\n  let nextToken;\n\n  do {\n    const page = await mwaa.send(\n      new ListEnvironmentsCommand({\n        MaxResults: 25,\n        NextToken: nextToken,\n      }),\n    );\n\n    names.push(...(page.Environments ?? []));\n    nextToken = page.NextToken;\n  } while (nextToken);\n\n  return names;\n}\n\nconsole.log(await listAllEnvironments());\n```\n\nAWS documents `MaxResults` for this operation as `1` to `25`.\n\n### Create an Airflow CLI token\n\nUse `CreateCliTokenCommand` when you need a short-lived token for the Airflow CLI flow.\n\n```javascript\nimport {\n  CreateCliTokenCommand,\n  MWAAClient,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { CliToken, WebServerHostname } = await mwaa.send(\n  new CreateCliTokenCommand({\n    Name: process.env.MWAA_ENV_NAME,\n  }),\n);\n\nif (!CliToken || !WebServerHostname) {\n  throw new Error(\"MWAA did not return a CLI token.\");\n}\n\nconsole.log(WebServerHostname);\n```\n\nTreat `CliToken` as secret material. Do not log or persist it outside the immediate login flow.\n\n### Create a web login token\n\nUse `CreateWebLoginTokenCommand` for the Airflow web UI login flow.\n\n```javascript\nimport {\n  CreateWebLoginTokenCommand,\n  MWAAClient,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { WebToken, WebServerHostname, IamIdentity, AirflowIdentity } = await mwaa.send(\n  new CreateWebLoginTokenCommand({\n    Name: process.env.MWAA_ENV_NAME,\n  }),\n);\n\nif (!WebToken || !WebServerHostname) {\n  throw new Error(\"MWAA did not return a web login token.\");\n}\n\nconsole.log(WebServerHostname);\nconsole.log(IamIdentity);\nconsole.log(AirflowIdentity);\n```\n\nThis call can fail with `AccessDeniedException` if the caller is not allowed to create a web login token for the target environment.\n\n### Call the Airflow REST API\n\nUse `InvokeRestApiCommand` when you want MWAA to call the managed Airflow REST API on your behalf.\n\n```javascript\nimport {\n  InvokeRestApiCommand,\n  MWAAClient,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await mwaa.send(\n  new InvokeRestApiCommand({\n    Name: process.env.MWAA_ENV_NAME,\n    Path: \"/dags\",\n    Method: \"GET\",\n    QueryParameters: {\n      limit: 10,\n    },\n  }),\n);\n\nconsole.log(response.RestApiStatusCode);\nconsole.log(response.RestApiResponse);\n```\n\nImportant details:\n\n- Pass only the Airflow path such as `/dags` or `/dags/example_dag/dagRuns`, not the full webserver URL.\n- `Method` must be one of `GET`, `PUT`, `POST`, `PATCH`, or `DELETE`.\n- `QueryParameters` and `Body` are JSON objects, not pre-encoded query strings.\n- AWS documents this operation with dedicated REST API guidance for MWAA because the available paths and payloads come from Apache Airflow rather than the AWS SDK itself.\n\n### Manage environment tags\n\nThe tag APIs work with the environment ARN. Fetch that ARN first if you only have the environment name.\n\n```javascript\nimport {\n  GetEnvironmentCommand,\n  ListTagsForResourceCommand,\n  MWAAClient,\n  TagResourceCommand,\n  UntagResourceCommand,\n} from \"@aws-sdk/client-mwaa\";\n\nconst mwaa = new MWAAClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Environment } = await mwaa.send(\n  new GetEnvironmentCommand({\n    Name: process.env.MWAA_ENV_NAME,\n  }),\n);\n\nif (!Environment?.Arn) {\n  throw new Error(\"Environment ARN was not returned.\");\n}\n\nawait mwaa.send(\n  new TagResourceCommand({\n    ResourceArn: Environment.Arn,\n    Tags: {\n      Environment: \"staging\",\n      Team: \"data-platform\",\n    },\n  }),\n);\n\nconst { Tags } = await mwaa.send(\n  new ListTagsForResourceCommand({\n    ResourceArn: Environment.Arn,\n  }),\n);\n\nconsole.log(Tags);\n\nawait mwaa.send(\n  new UntagResourceCommand({\n    ResourceArn: Environment.Arn,\n    tagKeys: [\"Team\"],\n  }),\n);\n```\n\n## Errors and Operational Notes\n\nThe most common service errors documented for MWAA operations are `ResourceNotFoundException`, `ValidationException`, and `InternalServerException`. `InvokeRestApiCommand` also documents `RestApiClientException` and `RestApiServerException`.\n\n```javascript\ntry {\n  await mwaa.send(\n    new GetEnvironmentCommand({\n      Name: process.env.MWAA_ENV_NAME,\n    }),\n  );\n} catch (error) {\n  if (error?.name === \"ResourceNotFoundException\") {\n    console.error(\"MWAA environment was not found in this region/account.\");\n  } else if (error?.name === \"ValidationException\") {\n    console.error(\"The MWAA request shape or parameter values were invalid.\");\n  } else {\n    throw error;\n  }\n}\n```\n\n## Pitfalls\n\n- `PublishMetricsCommand` is in the API model, but AWS marks it as internal-only. Do not build application code around it.\n- `ListEnvironmentsCommand` does not return full environment objects.\n- MWAA is regional. A valid environment name in one region is not visible from another region.\n- Tag operations require `ResourceArn`; they do not accept the environment name.\n- For `CreateEnvironmentCommand`, the minimum request includes `Name`, `ExecutionRoleArn`, `SourceBucketArn`, `DagS3Path`, and `NetworkConfiguration`.\n- `NetworkConfiguration.SubnetIds` must contain exactly two subnet IDs, and `SecurityGroupIds` must contain between one and five security group IDs.\n- `UpdateEnvironmentCommand` still requires `Name`, and its network update shape accepts only `SecurityGroupIds`, not subnets.\n\n## Useful Links\n\n- AWS SDK for JavaScript v3 MWAA client: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/mwaa/\n- MWAA API reference: https://docs.aws.amazon.com/mwaa/latest/APIReference/Welcome.html\n- `CreateCliToken`: https://docs.aws.amazon.com/mwaa/latest/APIReference/API_CreateCliToken.html\n- `CreateWebLoginToken`: https://docs.aws.amazon.com/mwaa/latest/APIReference/API_CreateWebLoginToken.html\n- `GetEnvironment`: https://docs.aws.amazon.com/mwaa/latest/APIReference/API_GetEnvironment.html\n- `ListEnvironments`: https://docs.aws.amazon.com/mwaa/latest/APIReference/API_ListEnvironments.html\n- `InvokeRestApi`: https://docs.aws.amazon.com/mwaa/latest/APIReference/API_InvokeRestApi.html\n- Airflow CLI token flow: https://docs.aws.amazon.com/mwaa/latest/userguide/call-mwaa-apis-cli.html\n- Airflow web login token flow: https://docs.aws.amazon.com/mwaa/latest/userguide/call-mwaa-apis-web.html\n- MWAA Airflow REST API guide: https://docs.aws.amazon.com/mwaa/latest/userguide/access-mwaa-apache-airflow-rest-api.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-accessanalyzer/python/DOC.md",
    "content": "---\nname: mypy-boto3-accessanalyzer\ndescription: \"Type stubs for boto3 IAM Access Analyzer in Python, including typed clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,accessanalyzer,boto3,python,typing,type-stubs,mypy,pyright\"\n---\n\n# `mypy-boto3-accessanalyzer` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-accessanalyzer` is a typing package for `boto3` IAM Access Analyzer code. It does not make AWS calls, it does not configure credentials, and it does not replace `boto3`.\n\nUse it in one of these modes:\n\n- `boto3-stubs[accessanalyzer]` for automatic `Session.client(\"accessanalyzer\")` type inference in editors and type checkers.\n- `mypy-boto3-accessanalyzer` when you only want the Access Analyzer stubs and are willing to annotate clients and paginators explicitly.\n- `boto3-stubs-lite[accessanalyzer]` if IDE memory use matters more than overload-based inference.\n\n## Install\n\nPyPI marks this package as `Stubs Only` and requires Python `>=3.9`.\n\nRecommended for most projects:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[accessanalyzer]==1.42.3\"\n```\n\nLower-memory option:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[accessanalyzer]==1.42.3\"\n```\n\nStandalone service stubs:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-accessanalyzer==1.42.3\"\n```\n\nPractical install rule:\n\n- use `boto3-stubs[accessanalyzer]` when you want the smoothest editor experience\n- use `boto3-stubs-lite[accessanalyzer]` if PyCharm or large `Literal` overloads are slowing your IDE down\n- use `mypy-boto3-accessanalyzer` when you want only this service package and you are fine with explicit annotations\n\n## Initialize And Authenticate\n\nAuthentication and configuration still come from normal `boto3` and the AWS credential chain. IAM Access Analyzer is regional, so set the region deliberately when you create the session or client.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=audit\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\n\nsession = Session(profile_name=\"audit\", region_name=\"us-east-1\")\n\naccessanalyzer: AccessAnalyzerClient = session.client(\n    \"accessanalyzer\",\n    config=Config(\n        retries={\n            \"mode\": \"standard\",\n            \"max_attempts\": 10,\n        }\n    ),\n)\n```\n\nEnvironment variables that commonly matter:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n\n## Core Usage\n\n### Typed client and paginator\n\n`list_analyzers` accepts `nextToken`, `maxResults`, and `type`, and returns analyzer objects with fields such as `arn`, `name`, `type`, and `status`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\nfrom mypy_boto3_accessanalyzer.paginator import ListAnalyzersPaginator\n\nclient: AccessAnalyzerClient = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\nlist_analyzers: ListAnalyzersPaginator = client.get_paginator(\"list_analyzers\")\n\nfor page in list_analyzers.paginate(type=\"ACCOUNT\"):\n    for analyzer in page.get(\"analyzers\", []):\n        print(analyzer[\"name\"], analyzer[\"arn\"], analyzer[\"status\"])\n```\n\n### Create an analyzer\n\nAWS documents `create_analyzer` with required `analyzerName` and `type` parameters. The response contains the analyzer ARN.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\n\nclient: AccessAnalyzerClient = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\n\nresponse = client.create_analyzer(\n    analyzerName=\"account-external-access\",\n    type=\"ACCOUNT\",\n    tags={\"Environment\": \"dev\"},\n)\n\nprint(response[\"arn\"])\n```\n\n### Validate a policy before deployment\n\n`validate_policy` takes a JSON policy document string and returns findings with `findingType`, `issueCode`, `findingDetails`, optional `learnMoreLink`, and location metadata.\n\n```python\nimport json\n\nfrom boto3.session import Session\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\n\nbucket_policy = {\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"AllowReadFromAnalyticsRole\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\"AWS\": \"arn:aws:iam::123456789012:role/analytics\"},\n            \"Action\": [\"s3:GetObject\"],\n            \"Resource\": [\"arn:aws:s3:::example-bucket/*\"],\n        }\n    ],\n}\n\nclient: AccessAnalyzerClient = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\n\nresponse = client.validate_policy(\n    policyDocument=json.dumps(bucket_policy),\n    policyType=\"RESOURCE_POLICY\",\n    validatePolicyResourceType=\"AWS::S3::Bucket\",\n)\n\nfor finding in response[\"findings\"]:\n    print(finding[\"findingType\"], finding[\"issueCode\"])\n    print(finding[\"findingDetails\"])\n```\n\nIf you are validating a resource policy for a resource type that is not in the documented `validatePolicyResourceType` set, omit that parameter and let IAM Access Analyzer apply the generic resource-policy checks.\n\n### Review findings with `list_findings_v2`\n\n`list_findings_v2` requires `analyzerArn` and supports `filter` and `sort`. The response returns finding fields including `id`, `resource`, `resourceType`, `status`, `updatedAt`, and `findingType`.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\nfrom mypy_boto3_accessanalyzer.paginator import ListFindingsV2Paginator\n\nclient: AccessAnalyzerClient = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\nanalyzer_arn = os.environ[\"ACCESS_ANALYZER_ARN\"]\n\nfindings: ListFindingsV2Paginator = client.get_paginator(\"list_findings_v2\")\n\nfor page in findings.paginate(\n    analyzerArn=analyzer_arn,\n    filter={\"status\": {\"eq\": [\"ACTIVE\"]}},\n    sort={\"attributeName\": \"updatedAt\", \"orderBy\": \"DESC\"},\n):\n    for finding in page[\"findings\"]:\n        print(finding[\"id\"], finding[\"resource\"], finding[\"status\"], finding[\"findingType\"])\n```\n\n### Start a fresh resource scan\n\nAWS documents `start_resource_scan` as supported only for external access analyzers.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_accessanalyzer import AccessAnalyzerClient\n\nclient: AccessAnalyzerClient = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\n\nclient.start_resource_scan(\n    analyzerArn=os.environ[\"ACCESS_ANALYZER_ARN\"],\n    resourceArn=\"arn:aws:s3:::example-bucket\",\n    resourceOwnerAccount=\"123456789012\",\n)\n```\n\n## Tooling Patterns\n\n### `TYPE_CHECKING` for dev-only stubs\n\nIf production images do not install stub packages, keep the imports behind `TYPE_CHECKING` and annotate with strings:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_accessanalyzer import AccessAnalyzerClient\n    from mypy_boto3_accessanalyzer.paginator import ListAnalyzersPaginator\n\nclient: \"AccessAnalyzerClient\" = Session(region_name=\"us-east-1\").client(\"accessanalyzer\")\npaginator: \"ListAnalyzersPaginator\" = client.get_paginator(\"list_analyzers\")\n```\n\n### Literals and `TypedDict` shapes\n\nThe package exposes constrained string literals and typed dictionaries through `literals` and `type_defs`.\n\n```python\nfrom mypy_boto3_accessanalyzer.literals import AccessCheckPolicyTypeType\nfrom mypy_boto3_accessanalyzer.type_defs import AccessPreviewStatusReasonTypeDef\n\ndef normalize_policy_type(value: AccessCheckPolicyTypeType) -> str:\n    return value\n\ndef build_reason(code: str) -> AccessPreviewStatusReasonTypeDef:\n    return {\"code\": code}\n```\n\n## Common Pitfalls\n\n- Installing the stubs without `boto3`. This package is typing-only.\n- Expecting the standalone or lite variants to infer `Session.client(\"accessanalyzer\")` automatically. Upstream only promises that behavior from `boto3-stubs[accessanalyzer]`.\n- Importing the module name with hyphens. The Python import package is `mypy_boto3_accessanalyzer`.\n- Treating this like a resource-based service package. The maintainer docs for this package focus on the typed client, paginator module, literals, and type definitions.\n- Passing `validatePolicyResourceType` for non-`RESOURCE_POLICY` validation. AWS documents that parameter only for resource policy validation.\n- Calling `start_resource_scan` on a non-external analyzer. AWS documents that operation as external-analyzer only.\n- Assuming analyzers are global. `create_analyzer` is regional, and AWS documents a limit of one analyzer per account per Region.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-accessanalyzer 1.42.3` as the current release on March 13, 2026, released on December 4, 2025.\n- The package was generated with `mypy-boto3-builder 8.12.0`.\n- Upstream states that the package version matches the related `boto3` version. Pin `boto3==1.42.3` with `mypy-boto3-accessanalyzer==1.42.3` when exact generated signatures matter.\n- The PyPI project page recommends local generation with `uvx --with 'boto3==1.42.3' mypy-boto3-builder` if you need stubs generated directly from your pinned boto3 version.\n- The AWS `latest` documentation pages for Access Analyzer are rolling and currently show mixed boto3 patch numbers across pages, so use PyPI for exact dependency pinning and the AWS pages for operation behavior.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/mypy-boto3-accessanalyzer/\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_accessanalyzer/\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n- Access Analyzer `create_analyzer`: https://docs.aws.amazon.com/boto3/latest/reference/services/accessanalyzer/client/create_analyzer.html\n- Access Analyzer `list_analyzers`: https://docs.aws.amazon.com/boto3/latest/reference/services/accessanalyzer/client/list_analyzers.html\n- Access Analyzer `list_findings_v2`: https://docs.aws.amazon.com/boto3/latest/reference/services/accessanalyzer/client/list_findings_v2.html\n- Access Analyzer `start_resource_scan`: https://docs.aws.amazon.com/boto3/latest/reference/services/accessanalyzer/client/start_resource_scan.html\n- Access Analyzer `validate_policy`: https://docs.aws.amazon.com/boto3/latest/reference/services/accessanalyzer/client/validate_policy.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-acm/python/DOC.md",
    "content": "---\nname: mypy-boto3-acm\ndescription: \"Type stubs for boto3 ACM in Python, including typed clients, paginators, waiters, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,acm,boto3,python,typing,type-stubs,mypy,pyright\"\n---\n\n# `mypy-boto3-acm` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-acm` is a stubs-only package for static typing. Keep using `boto3` for real ACM API calls, then choose one typing mode:\n\n- Use `boto3-stubs[acm]` when you want `Session().client(\"acm\")` to infer types automatically in IDEs, `mypy`, and `pyright`.\n- Use `mypy-boto3-acm` when you only want ACM-specific type stubs and are willing to annotate `ACMClient`, paginators, waiters, literals, and `type_defs` explicitly.\n- Use `boto3-stubs-lite[acm]` if full stubs are too heavy for PyCharm or memory-constrained environments. The lite package is more RAM-friendly, but upstream notes that it does not provide `session.client/resource` overloads.\n\n## Install\n\nRecommended when you want automatic type discovery:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[acm]==1.42.3\"\n```\n\nLower-memory option:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[acm]==1.42.3\"\n```\n\nStandalone ACM-only stubs:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-acm==1.42.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"boto3-stubs[acm]==1.42.3\"\npoetry add \"boto3==1.42.3\" \"boto3-stubs[acm]==1.42.3\"\n```\n\nNotes:\n\n- `boto3-stubs[acm]` is the easiest path if you want `Session().client(\"acm\")` to be inferred without extra annotations.\n- `boto3-stubs-lite[acm]` is the safer choice when PyCharm becomes slow on large `Literal` overloads.\n- `mypy-boto3-acm` does not replace `boto3`. If you install only the stubs package, type checking can pass while runtime imports or AWS calls still fail.\n\n## Authentication And Runtime Setup\n\nThe typing package does not change runtime auth, retries, endpoints, or permissions. Those still come from `boto3` and the normal AWS credential chain.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=\"dev\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nOr use shared config and credentials files:\n\n```bash\naws configure\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_acm import ACMClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nacm: ACMClient = session.client(\"acm\")\n```\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n\nACM in boto3 is client-oriented. AWS documents an ACM client surface with one paginator and one waiter; unlike services such as S3 or IAM, there is no boto3 ACM resource interface to type here.\n\n## Core Usage\n\n### Typed ACM client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_acm import ACMClient\n\nacm: ACMClient = Session(region_name=\"us-east-1\").client(\"acm\")\n\nresponse = acm.list_certificates(CertificateStatuses=[\"ISSUED\"])\n\nfor cert in response[\"CertificateSummaryList\"]:\n    print(cert[\"CertificateArn\"], cert.get(\"DomainName\"))\n```\n\n### Typed paginator\n\nAWS documents only one ACM paginator: `list_certificates`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_acm import ACMClient\nfrom mypy_boto3_acm.paginator import ListCertificatesPaginator\n\nacm: ACMClient = Session(region_name=\"us-east-1\").client(\"acm\")\npaginator: ListCertificatesPaginator = acm.get_paginator(\"list_certificates\")\n\nfor page in paginator.paginate(CertificateStatuses=[\"ISSUED\"]):\n    for cert in page[\"CertificateSummaryList\"]:\n        print(cert[\"CertificateArn\"])\n```\n\n### Typed waiter\n\nAWS documents one ACM waiter: `certificate_validated`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_acm import ACMClient\nfrom mypy_boto3_acm.waiter import CertificateValidatedWaiter\n\nacm: ACMClient = Session(region_name=\"us-east-1\").client(\"acm\")\nwaiter: CertificateValidatedWaiter = acm.get_waiter(\"certificate_validated\")\n\nwaiter.wait(\n    CertificateArn=\"arn:aws:acm:us-east-1:123456789012:certificate/...\",\n    WaiterConfig={\"Delay\": 60, \"MaxAttempts\": 30},\n)\n```\n\n### Typed request shapes with `type_defs`\n\nUse `type_defs` when you want explicit `TypedDict` request or response structures in helper functions.\n\n```python\nfrom mypy_boto3_acm.type_defs import RequestCertificateRequestTypeDef, TagTypeDef\n\ntags: list[TagTypeDef] = [\n    {\"Key\": \"service\", \"Value\": \"payments\"},\n]\n\nrequest: RequestCertificateRequestTypeDef = {\n    \"DomainName\": \"api.example.com\",\n    \"ValidationMethod\": \"DNS\",\n    \"SubjectAlternativeNames\": [\"www.example.com\"],\n    \"Tags\": tags,\n}\n```\n\n### Literals for constrained values\n\n```python\nfrom mypy_boto3_acm.literals import CertificateStatusType, ValidationMethodType\n\nstatus: CertificateStatusType = \"ISSUED\"\nvalidation_method: ValidationMethodType = \"DNS\"\n```\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nIf production images should not carry stub packages, keep the imports in a type-checking branch and fall back to `object` to avoid a known `pylint` complaint documented on PyPI.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_acm import ACMClient\nelse:\n    ACMClient = object\n\nacm = Session(region_name=\"us-east-1\").client(\"acm\")\ntyped_acm: \"ACMClient\" = acm\n```\n\n## Tooling Notes\n\n- Upstream documents that `boto3-stubs[acm]` works with VSCode, PyCharm, Emacs, Sublime Text, `mypy`, and `pyright`.\n- PyCharm can be slow on `Literal` overloads. If that happens, upstream recommends `boto3-stubs-lite` or disabling the built-in PyCharm type checker and running `mypy` or `pyright` separately.\n- The standalone `mypy-boto3-acm` package is useful when you want only ACM typings installed, but your factories and helper functions should return explicit `ACMClient`, paginator, waiter, or `type_defs` types instead of relying on overload inference.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-acm` as the runtime SDK. Real AWS calls still require `boto3`.\n- Do not mismatch `boto3` and stubs versions casually. This package tracks the related boto3 version line, so pin them together when you want predictable signatures.\n- Do not expect the lite package to infer `Session().client(\"acm\")` automatically. Add explicit `ACMClient` annotations.\n- Do not import the hyphenated package name in code. The import root uses underscores: `mypy_boto3_acm`.\n- Do not expect a typed ACM resource interface. ACM is exposed through a client, one paginator, one waiter, literals, and `type_defs`.\n- Do not assume type stubs validate AWS credentials, IAM permissions, regional availability, or certificate state. They only improve static typing.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-acm 1.42.3` as the latest release on March 12, 2026, released on December 4, 2025.\n- The hosted docs site is ahead of the published package for this entry: on March 12, 2026 it showed generation commands for `boto3==1.42.61` while PyPI still published `1.42.3`. When those disagree, prefer the installed package version and PyPI metadata as the source of truth for exact compatibility.\n- PyPI states this package was generated with `mypy-boto3-builder 8.12.0`.\n- Based on the maintainer repository's migration guidance for `boto3-stubs`, newer `types-boto3` packages use `types_boto3_<service>` import roots instead of `mypy_boto3_<service>`. If your team migrates to that newer family, update imports accordingly.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-acm/`\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_acm/`\n- AWS ACM boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/acm.html`\n- Maintainer repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-amplify/python/DOC.md",
    "content": "---\nname: mypy-boto3-amplify\ndescription: \"mypy-boto3-amplify package guide for typed boto3 Amplify clients, paginators, literals, and TypedDict API shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,aws,boto3,amplify,type-stubs,mypy,pyright\"\n---\n\n# mypy-boto3-amplify Python Package Guide\n\n## What This Package Is\n\n`mypy-boto3-amplify` provides generated type annotations for the AWS Amplify boto3 client.\n\nUse it when you want:\n\n- typed `boto3` Amplify clients\n- paginator types such as `ListAppsPaginator`\n- generated literal enums from the Amplify API model\n- request and response `TypedDict` shapes for static analysis\n\nThis package does not replace `boto3` at runtime and it does not configure AWS credentials or regions.\n\n## Install\n\nChoose one install mode based on how much boto3 typing you want.\n\n### Recommended: full boto3 stubs for Amplify\n\n```bash\npython -m pip install \"boto3-stubs[amplify]==1.42.3\"\n```\n\nThis is the best option when you want the most editor help around `Session().client(\"amplify\")`.\n\n### Service-only package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-amplify==1.42.3\"\n```\n\nUse this when you only need Amplify-specific stub modules and are willing to annotate the client explicitly.\n\n### Lite variant for lower memory usage\n\n```bash\npython -m pip install \"boto3-stubs-lite[amplify]==1.42.3\"\n```\n\nThe maintainer docs recommend the lite variant when the full package is too heavy for the IDE, but it does not provide the same boto3 session overloads. Plan to annotate client variables explicitly.\n\n## Setup And Initialization\n\n`mypy-boto3-amplify` has no package-specific configuration. Authentication, retry settings, endpoints, and region selection all come from normal `boto3` setup.\n\nAWS's standard pattern is:\n\n```bash\naws configure\n```\n\nor environment variables such as:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nRecommended typed setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_amplify import AmplifyClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\namplify: AmplifyClient = session.client(\"amplify\")\n```\n\nIf you need a custom endpoint or botocore config, pass it to `session.client(\"amplify\", ...)` exactly as you would without stubs.\n\n## Core Usage\n\n### Typed Amplify client\n\nThe stub package gives you the `AmplifyClient` type, but the runtime client still comes from `boto3`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_amplify import AmplifyClient\n\ndef make_amplify_client() -> AmplifyClient:\n    session = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n    return session.client(\"amplify\")\n```\n\n### Typed paginator\n\nAmplify exposes paginator types through the package. Use the paginator class when listing resources such as apps.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_amplify import AmplifyClient\nfrom mypy_boto3_amplify.paginator import ListAppsPaginator\n\nclient: AmplifyClient = Session(region_name=\"us-east-1\").client(\"amplify\")\npaginator: ListAppsPaginator = client.get_paginator(\"list_apps\")\n\nfor page in paginator.paginate():\n    for app in page.get(\"apps\", []):\n        print(app[\"appId\"], app[\"name\"])\n```\n\n### Typed response shapes\n\nUse generated `type_defs` when you want the type checker to validate the response shape you are consuming.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_amplify import AmplifyClient\nfrom mypy_boto3_amplify.type_defs import ListAppsResultTypeDef\n\nclient: AmplifyClient = Session(region_name=\"us-east-1\").client(\"amplify\")\nresult: ListAppsResultTypeDef = client.list_apps(maxResults=25)\n\nfor app in result.get(\"apps\", []):\n    print(app[\"repository\"])\n```\n\n### Literal enums for safer config\n\nThe generated literals catch typos in enum-like values before runtime.\n\n```python\nfrom mypy_boto3_amplify.literals import PlatformType\n\nplatform: PlatformType = \"WEB\"\n```\n\n### `TYPE_CHECKING` pattern\n\nThe maintainer docs explicitly recommend guarding stub-only imports when you do not want them to become hard runtime dependencies.\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_amplify import AmplifyClient\nelse:\n    AmplifyClient = object\n\nsession = boto3.Session(region_name=\"us-east-1\")\nclient: AmplifyClient = session.client(\"amplify\")\n```\n\n## Type-Checking Workflow\n\nTypical local setup:\n\n```bash\npython -m pip install boto3 mypy-boto3-amplify mypy\nmypy your_module.py\n```\n\n`pyright` also works with these generated stubs. The maintainer docs also mention this package can help with IDE autocompletion and Pylint false-positive suppression.\n\n## Config And Auth Notes\n\n- The package does not define any Amplify-specific environment variables.\n- Region handling still matters because Amplify is an AWS service client created through `boto3`.\n- If credentials or region resolution fail, debug that as a `boto3` problem, not a stub-package problem.\n- For multi-account or profile-based usage, prefer explicit `boto3.Session(profile_name=..., region_name=...)`.\n- For custom retry or timeout behavior, use `botocore.config.Config` when constructing the client.\n\nExample with explicit botocore config:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_amplify import AmplifyClient\n\nconfig = Config(retries={\"max_attempts\": 5, \"mode\": \"standard\"})\nsession = Session(region_name=\"us-east-1\")\nclient: AmplifyClient = session.client(\"amplify\", config=config)\n```\n\n## Common Pitfalls\n\n### Installing only the stubs\n\n`mypy-boto3-amplify` is not the runtime SDK. Your application still needs `boto3`.\n\n### Assuming every boto3 call becomes typed automatically\n\nThe maintainer docs call out current limitations around generated boto3 session overloads. In standalone or lite setups, explicitly annotate:\n\n```python\namplify: AmplifyClient = session.client(\"amplify\")\n```\n\n### Confusing the package name with the import path\n\n- PyPI package: `mypy-boto3-amplify`\n- Python import package: `mypy_boto3_amplify`\n\n### Treating stubs as runtime validation\n\n`TypedDict` and literal types help static analysis only. AWS still validates the request at runtime.\n\n### Forgetting that version alignment matters\n\nThese stubs are generated from a particular boto3 and botocore model snapshot. Keep `boto3` and the stub package aligned when you depend on newer Amplify fields or enum values.\n\n### Expecting resources or waiters\n\nThe official Amplify stubs surface client, paginator, literals, and `type_defs` usage. Do not assume there is a higher-level service resource layer or waiter support just because other AWS services have them.\n\n## Version-Sensitive Notes\n\n- This guide is pinned to version `1.42.3`.\n- The official maintainer docs for `mypy-boto3-amplify` were generated against `boto3==1.42.3`.\n- On 2026-03-12, the official PyPI project page showed a newer package release, `1.42.37`.\n- The docs root and the current PyPI page are therefore not describing the same publication snapshot.\n- If exact model coverage matters, pin both `boto3` and `mypy-boto3-amplify` deliberately and verify the version actually available in your package index.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_amplify/\n- Maintainer examples page: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_amplify/usage_examples/\n- PyPI package: https://pypi.org/project/mypy-boto3-amplify/\n- boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- boto3 session reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html\n- boto3 Amplify service reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/amplify.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-apigateway/python/DOC.md",
    "content": "---\nname: mypy-boto3-apigateway\ndescription: \"mypy-boto3-apigateway typing guide for boto3 API Gateway clients, paginators, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,apigateway,typing,mypy,pyright\"\n---\n\n# mypy-boto3-apigateway Python Package Guide\n\n## What This Package Is For\n\n`mypy-boto3-apigateway` is a typing-only package for the `boto3` API Gateway client.\n\nUse it when you want:\n\n- typed `Session.client(\"apigateway\")` clients\n- typed paginator objects\n- literal unions and `TypedDict` request/response shapes for API Gateway operations\n- better completion and static analysis in mypy, pyright, or Pylance\n\nIt does not replace `boto3`, and it does not change AWS authentication or runtime behavior. Your code still runs through the real `boto3` client.\n\n## Version-Sensitive Notes\n\n- The maintainer docs state that the package version matches the related `boto3` version.\n- Keep `mypy-boto3-apigateway` aligned with the `boto3` version your project actually installs, or you can end up with missing methods or stale request/response shapes in type checking.\n- The current package line is generated for the classic API Gateway control-plane client, whose boto3 service name is `\"apigateway\"`.\n- Do not confuse this package with the separate AWS services `apigatewayv2` or `apigatewaymanagementapi`; those need different stub packages.\n\n## Install\n\nChoose one of these installation patterns.\n\n### 1. Recommended: `boto3-stubs` extra for implicit client typing\n\nThis is the easiest setup for editor completion because `session.client(\"apigateway\")` gets the precise client type automatically.\n\n```bash\npython -m pip install \"boto3-stubs[apigateway]\"\n```\n\n### 2. Standalone service package for explicit annotations\n\nUse this when you only want the API Gateway stubs.\n\n```bash\npython -m pip install \"mypy-boto3-apigateway==1.42.3\"\n```\n\n### 3. Lite variant when full `boto3-stubs` is too heavy\n\nThe maintainer docs note that `boto3-stubs-lite[apigateway]` is more memory-friendly, but you must annotate the client explicitly.\n\n```bash\npython -m pip install \"boto3-stubs-lite[apigateway]\"\n```\n\nRuntime code still needs `boto3` itself:\n\n```bash\npython -m pip install \"boto3\"\n```\n\n## Authentication And Setup\n\nThis package does not add any auth layer. Credentials, profiles, regions, retries, and endpoints all come from `boto3` and the AWS SDK configuration chain.\n\nPractical defaults:\n\n- local development: `AWS_PROFILE` plus `AWS_DEFAULT_REGION`\n- CI or cloud runtimes: IAM role, workload identity, or environment-injected temporary credentials\n- explicit `Session(profile_name=..., region_name=...)` when you want deterministic behavior\n\nTyped setup with an explicit session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient = session.client(\"apigateway\")\n```\n\n## Core Usage\n\n### Explicitly type the client\n\nUse the generated client type when you install `mypy-boto3-apigateway` directly or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_apigateway.client import APIGatewayClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: APIGatewayClient = session.client(\"apigateway\")\n```\n\n### Call API Gateway operations with typed requests and responses\n\nThe package exposes `TypedDict` request and response shapes under `type_defs`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_apigateway.client import APIGatewayClient\nfrom mypy_boto3_apigateway.type_defs import CreateRestApiRequestTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nclient: APIGatewayClient = session.client(\"apigateway\")\n\nrequest: CreateRestApiRequestTypeDef = {\n    \"name\": \"orders-api\",\n    \"endpointConfiguration\": {\n        \"types\": [\"REGIONAL\"],\n    },\n}\n\nresult = client.create_rest_api(**request)\nprint(result[\"id\"])\n```\n\n### Use typed paginators\n\nThe generated docs include paginator classes such as `GetRestApisPaginator`, `GetResourcesPaginator`, and `GetApiKeysPaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_apigateway.client import APIGatewayClient\nfrom mypy_boto3_apigateway.paginator import GetRestApisPaginator\n\nsession = Session(region_name=\"us-east-1\")\nclient: APIGatewayClient = session.client(\"apigateway\")\n\npaginator: GetRestApisPaginator = client.get_paginator(\"get_rest_apis\")\n\nfor page in paginator.paginate():\n    for api in page.get(\"items\", []):\n        print(api[\"id\"], api[\"name\"])\n```\n\n### Use literals for constrained string values\n\nThe `literals` module gives you type-checked string unions for many AWS enum-like parameters.\n\n```python\nfrom mypy_boto3_apigateway.literals import EndpointTypeType\n\ndef endpoint_config(endpoint_type: EndpointTypeType) -> dict[str, list[str]]:\n    return {\"types\": [endpoint_type]}\n```\n\n## Configuration Notes\n\n- The service name is `\"apigateway\"`, so the typed client comes from `Session.client(\"apigateway\")`.\n- Region still matters for control-plane requests. Set `region_name` explicitly unless your environment already does it reliably.\n- If you need custom retries, timeouts, or endpoints, configure those through `botocore.config.Config` on the real boto3 client. The stub package only describes types.\n- For local testing against emulators, type checking still works as long as the runtime client is created normally with `endpoint_url=...`.\n\nExample with explicit config:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_apigateway.client import APIGatewayClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig = Config(retries={\"mode\": \"standard\", \"max_attempts\": 10})\n\nclient: APIGatewayClient = session.client(\"apigateway\", config=config)\n```\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-apigateway` alone does not install or replace `boto3`. You still need the runtime SDK.\n- Only `boto3-stubs[apigateway]` gives implicit typing for `session.client(\"apigateway\")`. The standalone and lite packages require explicit annotations.\n- The stubs do not validate data at runtime. A typed `TypedDict` request can still fail with a real AWS `ClientError`.\n- Use `\"apigateway\"` for the classic REST API control plane. If your code targets HTTP APIs, WebSocket APIs, or callback management APIs, check whether you actually need `apigatewayv2` or `apigatewaymanagementapi`.\n- Keep stub and `boto3` versions aligned. Generated stubs are version-specific.\n\n## When To Reach For The Docs\n\nUse the maintainer docs when you need:\n\n- the exact `APIGatewayClient` method surface\n- paginator class names and overloads\n- available literal types\n- request/response `TypedDict` names for specific operations\n\nUse the AWS boto3 docs when you need:\n\n- auth and credential-chain behavior\n- runtime operation semantics and AWS-side errors\n- endpoint, region, retry, and transport configuration\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-apprunner/python/DOC.md",
    "content": "---\nname: mypy-boto3-apprunner\ndescription: \"mypy-boto3-apprunner package guide for typed boto3 App Runner clients, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,apprunner,boto3,python,typing,mypy,pyright,stubs\"\n---\n\n# mypy-boto3-apprunner Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS App Runner calls and use `mypy-boto3-apprunner` only for typing.\n\nIf you want `Session.client(\"apprunner\")` to infer automatically, install `boto3-stubs[apprunner]`. If you install only `mypy-boto3-apprunner` or `boto3-stubs-lite[apprunner]`, expect to add explicit client annotations.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, PyPI lists `mypy-boto3-apprunner 1.42.3`, which matches the version used here for this session.\n- The PyPI package description says this release provides type annotations for `boto3.AppRunner 1.42.3`, so keep the stub package close to your installed `boto3` line.\n- The maintainer docs site is rolling rather than patch-pinned. The same docs tree already shows generic local-generation examples for newer boto3 patch lines, so treat PyPI as the exact version source for frontmatter and install pins.\n- The package index currently centers on typed `client`, `literals`, `type_defs`, and usage examples. Typed client code is the safest default workflow for App Runner.\n- If the published stub package lags the boto3 version you must use, the maintainer project recommends generating fresh stubs locally with `mypy-boto3-builder`.\n\n## Install\n\nChoose one install mode based on how much automatic inference you want.\n\n### Recommended for normal boto3 code\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[apprunner]==1.42.3\"\n```\n\nUse this when you want editors and type checkers to infer the right type from ordinary `Session.client(\"apprunner\")` code.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[apprunner]==1.42.3\"\n```\n\nThe maintainer docs note that the lite variant does not provide `session.client()` and `session.resource()` overloads, so explicit annotations become the normal pattern.\n\n### Standalone service package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-apprunner==1.42.3\"\n```\n\nUse this when you want only the App Runner typing package or when you keep typing imports behind `TYPE_CHECKING`.\n\n## Setup And Authentication\n\n`mypy-boto3-apprunner` does not handle AWS authentication or runtime configuration. Credentials, region resolution, retries, timeouts, and endpoints still come from `boto3` and `botocore`.\n\nCommon credential sources from the boto3 credentials guide:\n\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n- shared config in `~/.aws/credentials` and `~/.aws/config`\n- `AWS_PROFILE` for named profiles\n- assume-role, IAM Identity Center, container credentials, or EC2/ECS runtime roles\n\nApp Runner is regional, so keep the region explicit when it is not already obvious from the environment:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n```python\nimport boto3\nfrom botocore.config import Config\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\napprunner = session.client(\n    \"apprunner\",\n    config=Config(\n        retries={\n            \"mode\": \"standard\",\n            \"max_attempts\": 10,\n        }\n    ),\n)\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[apprunner]`\n\nWith the full service extra installed, normal boto3 code should infer correctly:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-west-2\")\nclient = session.client(\"apprunner\")\n\nresponse = client.list_services()\n\nfor service in response.get(\"ServiceSummaryList\", []):\n    print(service[\"ServiceName\"], service[\"Status\"])\n```\n\n### Explicit client annotations\n\nUse explicit types when you installed the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_apprunner.client import AppRunnerClient\n\nsession = Session(region_name=\"us-west-2\")\nclient: AppRunnerClient = session.client(\"apprunner\")\n\nservice = client.describe_service(\n    ServiceArn=\"arn:aws:apprunner:us-west-2:123456789012:service/my-service/0123456789abcdef\"\n)\n\nprint(service[\"Service\"][\"ServiceUrl\"])\n```\n\n### Typed request dictionaries from `type_defs`\n\nUse generated `TypedDict` shapes when building helper functions around nested App Runner request payloads:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_apprunner.client import AppRunnerClient\nfrom mypy_boto3_apprunner.type_defs import (\n    DescribeServiceRequestTypeDef,\n    StartDeploymentRequestTypeDef,\n)\n\nsession = Session(region_name=\"us-west-2\")\nclient: AppRunnerClient = session.client(\"apprunner\")\n\ndescribe_request: DescribeServiceRequestTypeDef = {\n    \"ServiceArn\": \"arn:aws:apprunner:us-west-2:123456789012:service/my-service/0123456789abcdef\",\n}\n\nservice = client.describe_service(**describe_request)\n\ndeploy_request: StartDeploymentRequestTypeDef = {\n    \"ServiceArn\": describe_request[\"ServiceArn\"],\n}\n\nclient.start_deployment(**deploy_request)\nprint(service[\"Service\"][\"ServiceName\"])\n```\n\nThe published type definitions also cover many nested shapes used by operations such as `create_service`, `update_service`, `pause_service`, `resume_service`, `list_operations`, and custom-domain management.\n\n### Literal types for constrained strings\n\nUse literal aliases when a helper accepts only App Runner enum-like values:\n\n```python\nfrom mypy_boto3_apprunner.literals import RuntimeType\n\ndef normalize_runtime(value: RuntimeType) -> str:\n    return value\n```\n\nThis is useful when building wrappers that map project settings onto App Runner runtime or status fields.\n\n## Runtime-Safe Typing Pattern\n\nIf production images install only `boto3`, keep stub imports behind `TYPE_CHECKING`:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_apprunner.client import AppRunnerClient\nelse:\n    AppRunnerClient = object\n\nclient: \"AppRunnerClient\" = boto3.Session(region_name=\"us-west-2\").client(\"apprunner\")\n```\n\nThis keeps the stub package out of runtime environments while preserving static analysis. The `else` branch also avoids the `pylint` undefined-name issue called out in the maintainer docs.\n\n## App Runner-Specific Notes\n\n- The boto3 service name is `apprunner`, not `mypy-boto3-apprunner`.\n- App Runner ARNs are region-specific. Create the session in the same region as the service you are describing, updating, pausing, or resuming.\n- `create_service` and `update_service` use large nested request shapes. `type_defs` helps catch missing fields or wrong nesting before you run the code.\n- Starting a deployment or updating a service is still subject to IAM permissions, source connection state, image availability, VPC connector setup, and service runtime health. The stubs validate shapes, not AWS-side behavior.\n- Keep retry, proxy, endpoint, and timeout configuration on the boto3 client or `botocore.config.Config`, not in your typing helpers.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but the Python import root uses underscores: `mypy_boto3_apprunner`.\n- This package is stub-only. It does not provide the runtime App Runner client by itself.\n- `boto3-stubs[apprunner]`, `boto3-stubs-lite[apprunner]`, and `mypy-boto3-apprunner` are not ergonomically equivalent. Full `boto3-stubs` gives the best automatic inference.\n- If your stub package version drifts away from the installed boto3 line, editor hints can become stale even when runtime code still works.\n- The maintainer docs site is rolling. Install snippets there may reference newer boto3 patch versions than the exact PyPI release you pinned.\n- Typed request payloads do not protect you from runtime issues like missing IAM permissions, invalid ARNs, unsupported regional resources, or bad source repository configuration.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_apprunner/`\n- AppRunner client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_apprunner/client/`\n- AppRunner type definitions: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_apprunner/type_defs/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-apprunner/`\n- PyPI JSON metadata: `https://pypi.org/pypi/mypy-boto3-apprunner/json`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS App Runner boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/apprunner.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-appstream/python/DOC.md",
    "content": "---\nname: mypy-boto3-appstream\ndescription: \"Type annotations for boto3 AppStream in Python, covering typed clients, paginators, waiters, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.54\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,appstream,boto3,type-stubs,mypy,pyright,autocomplete\"\n---\n\n# mypy-boto3-appstream Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-appstream` is a stubs-only package for static typing. It does not make AWS calls by itself and it does not replace `boto3`.\n\nUse one of these workflows:\n\n- Install `boto3-stubs[appstream]` when you want normal `Session().client(\"appstream\")` code to infer types automatically.\n- Install `mypy-boto3-appstream` when you want only the AppStream typing package and are willing to annotate the client, paginators, waiters, literals, and `TypedDict` shapes explicitly.\n- Install `boto3-stubs-lite[appstream]` if full overloads are too heavy for PyCharm or low-memory environments. The lite package drops automatic `session.client()` overloads, so explicit annotations matter more.\n\nThe maintainer docs list client, paginator, waiter, literal, and `type_defs` modules, but no service-resource surface, so treat AppStream typing here as client-only.\n\n## Install\n\nRecommended when you want typed boto3 code with automatic client inference:\n\n```bash\npython -m pip install \"boto3==1.42.54\" \"boto3-stubs[appstream]==1.42.54\"\n```\n\nStandalone service-specific stubs:\n\n```bash\npython -m pip install \"boto3==1.42.54\" \"mypy-boto3-appstream==1.42.54\"\n```\n\nLower-memory alternative:\n\n```bash\npython -m pip install \"boto3==1.42.54\" \"boto3-stubs-lite[appstream]==1.42.54\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.54\" \"boto3-stubs[appstream]==1.42.54\"\npoetry add \"boto3==1.42.54\" \"boto3-stubs[appstream]==1.42.54\"\n```\n\nNotes:\n\n- Keep the stub version aligned with the boto3 version you pin. The maintainer docs say package versions match the related boto3 version.\n- `mypy-boto3-appstream` does not ship the runtime client. If you install only the stubs package, type checking can pass while runtime imports fail.\n\n## Runtime Setup And Authentication\n\nAuthentication and region handling still come from boto3. AWS documents that boto3 checks explicit client or session parameters, environment variables, shared credentials files, config files, container credentials, and instance metadata as part of its credential provider chain.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n```\n\nOr use environment variables directly:\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"  # only for temporary credentials\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n```\n\nMinimal typed setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appstream import AppStreamClient\n\nsession = Session(region_name=\"us-west-2\")\nclient: AppStreamClient = session.client(\"appstream\")\n```\n\nAWS now brands the service docs as WorkSpaces Applications in parts of the boto3 reference, but the Python service identifier is still `appstream` and the stub package name is still `mypy-boto3-appstream`.\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[appstream]`\n\nWith the full extra installed, ordinary boto3 client code should infer types:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-west-2\")\nclient = session.client(\"appstream\")\n\nresponse = client.describe_stacks()\nfor stack in response[\"Stacks\"]:\n    print(stack[\"Name\"])\n```\n\n### Explicit client annotations\n\nUse this pattern when you installed `mypy-boto3-appstream` or `boto3-stubs-lite[appstream]`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appstream import AppStreamClient\n\ndef get_client() -> AppStreamClient:\n    return Session(region_name=\"us-west-2\").client(\"appstream\")\n\nclient = get_client()\nresult = client.describe_fleets()\nfor fleet in result[\"Fleets\"]:\n    print(fleet[\"Name\"], fleet[\"State\"])\n```\n\n### Typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appstream import AppStreamClient\nfrom mypy_boto3_appstream.paginator import DescribeStacksPaginator\n\nclient: AppStreamClient = Session(region_name=\"us-west-2\").client(\"appstream\")\npaginator: DescribeStacksPaginator = client.get_paginator(\"describe_stacks\")\n\nfor page in paginator.paginate():\n    for stack in page[\"Stacks\"]:\n        print(stack[\"Name\"])\n```\n\n### Typed waiter\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appstream import AppStreamClient\nfrom mypy_boto3_appstream.waiter import FleetStartedWaiter\n\nclient: AppStreamClient = Session(region_name=\"us-west-2\").client(\"appstream\")\nwaiter: FleetStartedWaiter = client.get_waiter(\"fleet_started\")\nwaiter.wait(Name=\"example-fleet\")\n```\n\n### Literals and `TypedDict` request and response shapes\n\nUse literals for constrained enum-like values and `type_defs` for helper boundaries:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appstream import AppStreamClient\nfrom mypy_boto3_appstream.literals import AuthenticationTypeType\nfrom mypy_boto3_appstream.type_defs import (\n    DescribeUsersRequestTypeDef,\n    DescribeUsersResultTypeDef,\n)\n\nclient: AppStreamClient = Session(region_name=\"us-west-2\").client(\"appstream\")\n\nauth_type: AuthenticationTypeType = \"USERPOOL\"\nrequest: DescribeUsersRequestTypeDef = {\"AuthenticationType\": auth_type}\nresult: DescribeUsersResultTypeDef = client.describe_users(**request)\n\nprint(len(result[\"Users\"]))\n```\n\nThis pattern is useful when you pass request objects through helper functions and want mypy or pyright to catch wrong keys or wrong literal values before runtime.\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nIf you keep stubs out of production images, import them only for type checking:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_appstream import AppStreamClient\nelse:\n    AppStreamClient = object\n\nclient: \"AppStreamClient\" = Session(region_name=\"us-west-2\").client(\"appstream\")\n```\n\nThe maintainer docs explicitly call this pattern safe and note that the fallback also avoids a common pylint undefined-name complaint.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-appstream` as the runtime SDK. Real AWS calls still require `boto3`.\n- Do not expect a boto3 resource surface here. The published AppStream stubs expose a typed client, paginators, waiters, literals, and `type_defs`, but not a `resource(\"appstream\")` service-resource layer.\n- Do not mix unrelated boto3 and stubs versions casually. Generated names and availability track the boto3 service model version closely.\n- Do not rely on automatic `session.client(\"appstream\")` inference when you installed the standalone package or the lite package. Add explicit `AppStreamClient` annotations in those setups.\n- Do not hardcode AWS credentials in application code. Keep auth in profiles, environment variables, IAM Identity Center, or runtime IAM roles.\n- Do not forget the region. Even typed code still fails at runtime if credentials or region resolution are wrong.\n- AppStream user-management APIs are stricter than many examples imply. AWS documents that user email addresses for operations like `enable_user` and `disable_user` are case-sensitive.\n- The service branding is inconsistent across sources. AWS may say WorkSpaces Applications while boto3, the API namespace, and this package still use `appstream`.\n\n## Version-Sensitive Notes For `1.42.54`\n\n- PyPI lists `1.42.54` as the current `mypy-boto3-appstream` release on March 12, 2026, published on February 20, 2026.\n- The package description says it provides type annotations for `boto3 AppStream 1.42.54`, and the maintainer docs say package versions are the same as the related boto3 version.\n- The rolling AWS boto3 reference for AppStream is already on a newer patch line than this standalone stub release. When exact generated names matter, prefer the version you pinned from PyPI over whatever patch number appears in the live boto3 docs tree.\n- If you upgrade `boto3`, upgrade the AppStream stubs in the same change. That keeps client methods, paginator names, waiter names, literals, and `TypedDict` shapes aligned.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_appstream/\n- PyPI package page: https://pypi.org/project/mypy-boto3-appstream/\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- AWS boto3 AppStream reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appstream.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-appsync/python/DOC.md",
    "content": "---\nname: mypy-boto3-appsync\ndescription: \"Type annotations for boto3 AppSync in Python, covering typed clients, paginators, literals, and TypedDict request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,appsync,boto3,type-stubs,mypy,pyright,autocomplete,graphql\"\n---\n\n# mypy-boto3-appsync Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-appsync` is a stubs-only package for static typing, not the runtime SDK. Install `boto3` for real AWS AppSync calls, then choose one typing mode:\n\n- Use `boto3-stubs[appsync]` when you want `Session().client(\"appsync\")` overloads to infer the client type automatically in editors and type checkers.\n- Use `mypy-boto3-appsync` when you want only the AppSync stubs package and are willing to annotate `AppSyncClient`, paginator objects, literals, and `TypedDict` request shapes explicitly.\n- Use `boto3-stubs-lite[appsync]` when the full overload set is too heavy for PyCharm or low-memory environments. The lite package drops `session.client(...)` overload inference, so explicit annotations matter more.\n\n## Install\n\nIf you want automatic boto3 overload discovery in editors and type checkers:\n\n```bash\npython -m pip install \"boto3==1.42.6\" \"boto3-stubs[appsync]==1.42.6\"\n```\n\nIf you want the standalone service-specific stubs package:\n\n```bash\npython -m pip install \"boto3==1.42.6\" \"mypy-boto3-appsync==1.42.6\"\n```\n\nIf PyCharm becomes slow on literal-heavy overloads:\n\n```bash\npython -m pip install \"boto3==1.42.6\" \"boto3-stubs-lite[appsync]==1.42.6\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.6\" \"boto3-stubs[appsync]==1.42.6\"\npoetry add \"boto3==1.42.6\" \"boto3-stubs[appsync]==1.42.6\"\n```\n\nNotes:\n\n- Keep the stubs version aligned with the boto3 version you pin. The maintainer metadata says `mypy-boto3-appsync` uses the related boto3 version number.\n- `mypy-boto3-appsync` does not replace `boto3`. Installing only the stubs package gives type checking but no runtime client implementation.\n\n## Authentication And Runtime Setup\n\nTyping comes from `mypy-boto3-appsync`, but runtime behavior still comes from `boto3` and `botocore`. AWS documents that Boto3 needs both credentials and a region to make requests, and that it searches for credentials in a standard order including explicit parameters, environment variables, assume-role providers, shared credentials files, config files, container credentials, and EC2 instance metadata.\n\nRecommended local setup:\n\n```bash\naws configure\n```\n\nUseful environment variables:\n\n```bash\nexport AWS_PROFILE=\"dev\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\nexport AWS_RETRY_MODE=\"standard\"\nexport AWS_MAX_ATTEMPTS=\"10\"\n```\n\nPrefer an explicit session so the profile and region are obvious:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_appsync import AppSyncClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig = Config(\n    retries={\n        \"mode\": \"standard\",\n        \"max_attempts\": 10,\n    }\n)\n\nclient: AppSyncClient = session.client(\"appsync\", config=config)\n```\n\nAppSync is a client-only boto3 surface in this release line. The AWS boto3 AppSync reference documents a low-level `AppSync.Client` plus paginators; there is no boto3 resource interface or waiter section to rely on here.\n\n## Core Usage\n\n### Typed client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appsync import AppSyncClient\n\ndef get_appsync_client() -> AppSyncClient:\n    return Session(region_name=\"us-east-1\").client(\"appsync\")\n\nclient = get_appsync_client()\nresponse = client.list_graphql_apis(maxResults=25)\n\nfor api in response.get(\"graphqlApis\", []):\n    print(api[\"apiId\"], api[\"name\"])\n```\n\nUse explicit annotations like this when you install the standalone package or the lite package, because only the full `boto3-stubs[appsync]` extra gives overload-based auto-discovery for `session.client(\"appsync\")`.\n\n### Typed paginator\n\nAppSync supports typed paginator overloads for list operations such as `list_graphql_apis`, `list_data_sources`, and `list_types`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_appsync import AppSyncClient\nfrom mypy_boto3_appsync.paginator import ListGraphqlApisPaginator\n\nclient: AppSyncClient = Session(region_name=\"us-east-1\").client(\"appsync\")\npaginator: ListGraphqlApisPaginator = client.get_paginator(\"list_graphql_apis\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 25}):\n    for api in page.get(\"graphqlApis\", []):\n        print(api[\"apiId\"], api[\"name\"])\n```\n\n### Literals and TypedDict request shapes\n\nUse `literals` for constrained string values and `type_defs` for nested request structures you build in user code:\n\n```python\nfrom mypy_boto3_appsync.literals import ApiCacheStatusType\nfrom mypy_boto3_appsync.type_defs import CognitoUserPoolConfigTypeDef\n\nstatus: ApiCacheStatusType = \"AVAILABLE\"\n\nuser_pool_config: CognitoUserPoolConfigTypeDef = {\n    \"awsRegion\": \"us-east-1\",\n    \"userPoolId\": \"us-east-1_example\",\n    \"appIdClientRegex\": \"my-client-id\",\n}\n```\n\nBuild nested request fragments as typed variables first, then pass them into the boto3 client call that needs them. That catches misspelled keys before runtime and keeps large AppSync payloads readable.\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nIf your production image omits typing dependencies, guard imports so runtime environments do not need the stub package:\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypy_boto3_appsync import AppSyncClient\nelse:\n    AppSyncClient = object\n```\n\n## Tooling Notes\n\n- `boto3-stubs[appsync]` is the easiest option for VSCode plus Pylance, mypy, and pyright because it supports automatic type discovery for `boto3.client(...)` and `session.client(...)`.\n- The maintainer PyPI page specifically warns that PyCharm can become slow on `Literal` overloads. If that happens, switch to `boto3-stubs-lite[appsync]` or disable the PyCharm type checker and run `mypy` or `pyright` separately.\n- The standalone `mypy-boto3-appsync` package is useful when you only want AppSync typing installed, but your client factories should return explicit `AppSyncClient` types instead of relying on overload inference.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-appsync` as the runtime SDK. Real AWS calls still require `boto3`.\n- Do not mix unrelated boto3 and stubs versions casually. This package tracks boto3 versions, so pin them together when you want predictable method signatures.\n- Do not expect `boto3-stubs-lite[appsync]` to infer `session.client(\"appsync\")` return types. Add explicit `AppSyncClient` annotations.\n- Do not forget region configuration. AppSync endpoints are regional, so `AWS_DEFAULT_REGION` or `region_name` needs to match the target API.\n- Do not assume every AppSync list operation is paginated the same way. Use `client.get_paginator(...)` only for operations documented with paginator support.\n- Do not hard-code AWS credentials in source. AWS recommends environment variables, shared config files, assume-role flows, or runtime identity providers instead.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-appsync 1.42.6` as the current release for this package on 2026-03-12, and the release was uploaded on 2025-12-09.\n- The package version is intended to match the related boto3 AppSync release line. If you upgrade `boto3`, upgrade the matching AppSync stubs package in the same change.\n- The AppSync client surface in current boto3 docs includes both older `*_graphql_api` operations and newer `create_api` or channel-namespace operations. Type hints follow the installed boto3 service model, so confirm the exact method you need against the boto3 AppSync reference for your pinned version.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_appsync/`\n- PyPI release metadata: `https://pypi.org/project/mypy-boto3-appsync/1.42.6/`\n- PyPI JSON metadata: `https://pypi.org/pypi/mypy-boto3-appsync/json`\n- AWS boto3 AppSync reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/appsync.html`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-athena/python/DOC.md",
    "content": "---\nname: mypy-boto3-athena\ndescription: \"mypy-boto3-athena type stubs for boto3 Athena clients, paginators, TypedDict request shapes, and editor/type-checker setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.43\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,athena,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-athena Python Package Guide\n\n## What This Package Is For\n\n`mypy-boto3-athena` is a stub-only package for `boto3` Athena clients. It improves autocomplete and static type checking in tools such as mypy, pyright, Pylance, and PyCharm, but it does not make AWS calls by itself. Runtime behavior still comes from `boto3` and botocore.\n\nUse it when your code already calls Athena through `boto3`, and you want typed clients, paginator types, generated `TypedDict` request and response shapes, and service literals.\n\n## Golden Rule\n\n- Install `boto3` for runtime behavior. `mypy-boto3-athena` only adds types.\n- Treat Athena as a client-first boto3 service. The AWS Athena boto3 reference documents a low-level client plus paginators.\n- Keep `boto3` and the Athena stubs on the same release line when request and response shapes matter.\n- Prefer `boto3-stubs[athena]` for automatic client inference; use explicit annotations with the standalone or `lite` packages.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.43\" \"boto3-stubs[athena]==1.42.43\"\n```\n\nThis keeps runtime and typing packages aligned and usually gives automatic `Session().client(\"athena\")` inference in editors and type checkers.\n\n### Standalone Athena stubs\n\n```bash\npython -m pip install \"boto3==1.42.43\" \"mypy-boto3-athena==1.42.43\"\n```\n\nUse this when you want only the Athena service stubs instead of the `boto3-stubs` extras package.\n\n### Lower-memory PyCharm fallback\n\n```bash\npython -m pip install \"boto3==1.42.43\" \"boto3-stubs-lite[athena]==1.42.43\"\n```\n\nThe maintainer docs note that `boto3-stubs-lite[athena]` is more RAM-friendly, but it does not provide `session.client(...)` and `session.resource(...)` overload inference. In lite mode, annotate clients and paginators explicitly.\n\n### Generate exact stubs locally\n\nIf you need stubs generated against the exact `boto3` version in your environment, the maintainer docs recommend local generation:\n\n```bash\nuvx --with \"boto3==1.42.43\" mypy-boto3-builder\n```\n\nThe public docs root is latest-only, so this is the safest option when exact patch-level parity matters.\n\n## Setup, Authentication, And Configuration\n\n`mypy-boto3-athena` has no separate auth or config layer. Credentials, regions, retries, profiles, endpoints, proxies, and timeouts still come from normal `boto3` and botocore configuration.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThe boto3 credentials guide documents the main provider order agents usually need to remember:\n\n1. Credentials passed to `boto3.client(...)`\n2. Credentials passed to `boto3.Session(...)`\n3. Environment variables\n4. Assume-role providers\n5. Web identity providers\n6. Shared config and credentials files\n7. Container or EC2 instance credentials\n\nFor client-specific behavior, pass a botocore `Config` object:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nathena = session.client(\n    \"athena\",\n    config=Config(\n        retries={\"mode\": \"standard\", \"max_attempts\": 5},\n        read_timeout=60,\n    ),\n)\n```\n\nUseful environment variables from the boto3 configuration guide:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\nIf credentials, IAM permissions, workgroup settings, or region selection are wrong, type checking still passes and the real AWS call still fails.\n\n## Core Usage\n\n### Typed client\n\nAnnotate the boto3 client explicitly when you use the standalone package or `lite` package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_athena.client import AthenaClient\n\ndef make_athena_client() -> AthenaClient:\n    session = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n    return session.client(\"athena\")\n```\n\nThis gives typed access to operations such as `start_query_execution`, `get_query_execution`, `get_query_results`, `list_query_executions`, and `stop_query_execution`.\n\n### Typed request shapes with `TypedDict`\n\nUse generated `type_defs` when building Athena request payloads across helper functions or config layers:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_athena.client import AthenaClient\nfrom mypy_boto3_athena.type_defs import (\n    QueryExecutionContextTypeDef,\n    ResultConfigurationTypeDef,\n    StartQueryExecutionOutputTypeDef,\n)\n\nathena: AthenaClient = Session(region_name=\"us-east-1\").client(\"athena\")\n\ncontext: QueryExecutionContextTypeDef = {\n    \"Database\": \"analytics\",\n}\nresult_config: ResultConfigurationTypeDef = {\n    \"OutputLocation\": \"s3://my-query-results/athena/\",\n}\n\nresponse: StartQueryExecutionOutputTypeDef = athena.start_query_execution(\n    QueryString=\"SELECT 1\",\n    QueryExecutionContext=context,\n    ResultConfiguration=result_config,\n    WorkGroup=\"primary\",\n)\n\nprint(response[\"QueryExecutionId\"])\n```\n\nThis catches misspelled keys and wrong nested shapes before runtime.\n\n### Typed paginator usage\n\nThe AWS Athena reference exposes paginators for `get_query_results`, `list_data_catalogs`, `list_databases`, `list_named_queries`, `list_query_executions`, `list_table_metadata`, and `list_tags_for_resource`. The stub package exposes matching paginator types.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_athena.client import AthenaClient\nfrom mypy_boto3_athena.paginator import ListQueryExecutionsPaginator\n\nclient: AthenaClient = Session(region_name=\"us-east-1\").client(\"athena\")\npaginator: ListQueryExecutionsPaginator = client.get_paginator(\n    \"list_query_executions\"\n)\n\nfor page in paginator.paginate(WorkGroup=\"primary\"):\n    for query_id in page.get(\"QueryExecutionIds\", []):\n        print(query_id)\n```\n\n### Literals for constrained Athena values\n\n```python\nfrom mypy_boto3_athena.literals import QueryExecutionStateType\n\ndef is_terminal(state: QueryExecutionStateType) -> bool:\n    return state in {\"SUCCEEDED\", \"FAILED\", \"CANCELLED\"}\n```\n\nUse literals instead of unchecked string constants when you branch on Athena states or enum-like parameters.\n\n## Tooling Patterns\n\n### Keep typing-only imports behind `TYPE_CHECKING`\n\nIf the stub package is installed only in development or CI, keep the imports out of runtime-only paths:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_athena.client import AthenaClient\n\ndef get_client() -> \"AthenaClient\":\n    return Session(region_name=\"us-east-1\").client(\"athena\")\n```\n\n### When explicit annotations are necessary\n\n- With `boto3-stubs[athena]`, editors usually infer `session.client(\"athena\")` automatically.\n- With `mypy-boto3-athena` standalone or `boto3-stubs-lite[athena]`, annotate `AthenaClient` and paginator variables explicitly.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-athena` and expecting runtime Athena calls to work. You still need `boto3`.\n- Treating the package as an auth, retry, or endpoint layer. Those settings live in `boto3` and botocore.\n- Assuming successful typing proves that your result bucket, IAM permissions, workgroup, and region are valid.\n- Copying docs-root examples as if they are frozen to your exact PyPI version. The docs site tracks the latest generated output.\n- Expecting `boto3-stubs-lite[athena]` to preserve automatic `session.client(\"athena\")` overload inference.\n- Writing `boto3.resource(\"athena\")` patterns by analogy with S3 or DynamoDB. Athena is documented here as a low-level client surface with paginators.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.43`.\n- PyPI shows `mypy-boto3-athena 1.42.43` was released on `2026-02-05` and requires Python `>=3.9`.\n- The maintainer docs root is not frozen to `1.42.43`; when checked on `2026-03-12`, its local-generation example referenced `boto3==1.42.66`.\n- If exact stub parity matters, pin `boto3` and the stubs together or generate them locally for the exact boto3 version you ship.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_athena/\n- Client reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_athena/client/\n- Paginators reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_athena/paginators/\n- Registry page: https://pypi.org/project/mypy-boto3-athena/\n- Boto3 Athena reference: https://docs.aws.amazon.com/boto3/latest/reference/services/athena.html\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-autoscaling/python/DOC.md",
    "content": "---\nname: mypy-boto3-autoscaling\ndescription: \"mypy-boto3-autoscaling package guide for typed boto3 Auto Scaling clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.33\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,autoscaling,mypy,typing,python\"\n---\n\n# mypy-boto3-autoscaling Python Package Guide\n\n## Golden Rule\n\n- `mypy-boto3-autoscaling` only provides type information for `boto3` Auto Scaling usage. It is not a runtime SDK.\n- Install it alongside `boto3`, or install `boto3-stubs[autoscaling]` if you want the upstream bundled path with better client inference.\n- Keep the stub package version close to the `boto3` version you actually run so generated operations and shapes stay aligned.\n\n## Version-Sensitive Notes\n\n- On 2026-03-12, PyPI lists `mypy-boto3-autoscaling 1.42.33` as the current published release, released on 2026-01-22.\n- PyPI lists `Requires: Python >=3.8`.\n- The upstream versioning guide says stub package versions usually follow the corresponding `boto3` version.\n- The current maintainer docs page for this package includes a local-generation command pinned to `boto3==1.42.63`, which is newer than the published stub package version. Treat the docs site as authoritative for import patterns, but use PyPI as the source of truth for what version you can actually install.\n- The upstream GitHub repository has moved from `youtype/boto3-stubs` to `youtype/types-boto3`.\n\n## Install\n\n### Minimal Service-Specific Setup\n\n```bash\npython -m pip install \"boto3\" \"mypy-boto3-autoscaling==1.42.33\"\n```\n\nUse this when you only need Auto Scaling typings and you are willing to annotate clients explicitly.\n\n### Bundled Upstream Install Path\n\n```bash\npython -m pip install \"boto3-stubs[autoscaling]==1.42.33\"\n```\n\nUse this when you want the upstream-recommended package family and better overloads for `Session.client(\"autoscaling\")`.\n\n### Exact-Match Fallback\n\nIf you need typings for a newer `boto3` build than PyPI currently publishes for this package, the maintainer docs point to local generation with `mypy-boto3-builder`:\n\n```bash\nuvx --with 'boto3==1.42.63' mypy-boto3-builder\n```\n\nThat is a fallback for exact service-model alignment, not the normal install path.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-autoscaling` does not configure credentials, regions, retries, or endpoints. All runtime behavior still comes from `boto3`.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create an explicit session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n```\n\nAWS documents a standard credential resolution chain for boto3. In practice, these are the sources agents should check first:\n\n1. Parameters passed directly to `boto3.client(...)` or `boto3.Session(...)`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. Shared AWS credentials and config files, including named profiles\n4. Role-based providers in AWS runtimes\n\n## Core Usage\n\n### Typed Auto Scaling Client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_autoscaling.client import AutoScalingClient\nfrom mypy_boto3_autoscaling.type_defs import DescribeAutoScalingGroupsAnswerTypeDef\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: AutoScalingClient = session.client(\"autoscaling\")\n\nresponse: DescribeAutoScalingGroupsAnswerTypeDef = client.describe_auto_scaling_groups(\n    MaxRecords=10,\n)\n\nfor group in response[\"AutoScalingGroups\"]:\n    print(group[\"AutoScalingGroupName\"])\n```\n\nThe standalone package gives you the client type, request and response shape types, and completions for Auto Scaling methods. The real API call still goes through `boto3`.\n\n### Typed Paginators\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_autoscaling.client import AutoScalingClient\nfrom mypy_boto3_autoscaling.paginator import DescribeAutoScalingGroupsPaginator\n\nclient: AutoScalingClient = Session(region_name=\"us-east-1\").client(\"autoscaling\")\npaginator: DescribeAutoScalingGroupsPaginator = client.get_paginator(\n    \"describe_auto_scaling_groups\"\n)\n\nfor page in paginator.paginate(PaginationConfig={\"MaxItems\": 50}):\n    for group in page[\"AutoScalingGroups\"]:\n        print(group[\"AutoScalingGroupName\"])\n```\n\nUse typed paginators instead of hand-rolled token loops when an Auto Scaling operation supports pagination.\n\n### Typed Nested Shapes\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_autoscaling.client import AutoScalingClient\nfrom mypy_boto3_autoscaling.type_defs import LaunchTemplateSpecificationTypeDef\n\nclient: AutoScalingClient = Session(region_name=\"us-east-1\").client(\"autoscaling\")\n\nlaunch_template: LaunchTemplateSpecificationTypeDef = {\n    \"LaunchTemplateName\": \"web-asg-template\",\n    \"Version\": \"$Latest\",\n}\n\nclient.update_auto_scaling_group(\n    AutoScalingGroupName=\"web-asg\",\n    LaunchTemplate=launch_template,\n)\n```\n\nUse `type_defs` whenever you pass nested AWS-shaped dictionaries between helpers or want static validation for request and response keys.\n\n### Literals For Enum-Like Values\n\n```python\nfrom mypy_boto3_autoscaling.literals import MetricStatisticTypeType\n\nstatistic: MetricStatisticTypeType = \"Average\"\n```\n\nUse generated literal types when you want refactor-safe handling of constrained strings instead of bare string constants.\n\n## Type Checker And IDE Setup\n\n- Install the stubs in the same environment that `mypy`, `pyright`, or your editor is analyzing.\n- Import from `mypy_boto3_autoscaling`, not `mypy-boto3-autoscaling`. The PyPI name uses hyphens; the Python import uses underscores.\n- If you install only the standalone package, explicit annotations like `client: AutoScalingClient = ...` are the safest path.\n- If the stub package is dev-only, guard imports with `TYPE_CHECKING` so production environments do not need it installed:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_autoscaling.client import AutoScalingClient\n\ndef make_client() -> \"AutoScalingClient\":\n    return Session(region_name=\"us-east-1\").client(\"autoscaling\")\n```\n\n## Common Pitfalls\n\n- Do not try to create runtime clients from `mypy_boto3_autoscaling`. Runtime calls still come from `boto3`.\n- Do not expect the standalone package to infer `Session.client(\"autoscaling\")` types automatically in every tool. Add explicit annotations when inference is weak.\n- Do not use the wrong service name. The boto3 service string is `\"autoscaling\"`.\n- Do not assume the docs-site generator version is the same as the published PyPI package version. For installable pins, trust PyPI.\n- Do not forget region and credential setup. Correct type annotations do not prevent runtime auth or configuration failures.\n- Do not let `boto3` drift far ahead of the stub package if you rely on exact request or response shapes for newer Auto Scaling features.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_autoscaling/`\n- Package examples: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_autoscaling/usage-examples/`\n- Paginator reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_autoscaling/paginators/`\n- TypedDict reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_autoscaling/type_defs/`\n- Literal reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_autoscaling/literals/`\n- Upstream versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-autoscaling/`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Upstream repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-backup/python/DOC.md",
    "content": "---\nname: mypy-boto3-backup\ndescription: \"Type stubs for boto3 AWS Backup clients, paginators, literals, and TypedDicts in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,backup,boto3,mypy,pyright,type-stubs,python\"\n---\n\n# `mypy-boto3-backup` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-backup` is a typing-only companion for `boto3`, not a runtime AWS SDK. Create real Backup clients with `boto3`, keep the stub package on the same release line as `boto3`, and add explicit `BackupClient` annotations unless you are intentionally relying on the full `boto3-stubs[backup]` overloads.\n\n## What This Package Gives You\n\n`mypy-boto3-backup` adds type information for the boto3 AWS Backup client surface:\n\n- `BackupClient` for `Session.client(\"backup\")`\n- typed paginator classes for Backup list operations\n- `literals` for enum-like string values\n- `type_defs` for generated request and response `TypedDict` shapes\n\nIt does not perform AWS authentication, retries, endpoint resolution, or API calls by itself. Those still come from `boto3` and `botocore`.\n\n## Install\n\nChoose one installation path and keep the version aligned with your `boto3` line.\n\n### Option 1: standalone service stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-backup==1.42.3\"\n```\n\n### Option 2: full `boto3-stubs` bundle\n\nUse this when you want `Session.client(\"backup\")` inference to work with minimal annotation noise.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[backup]==1.42.3\"\n```\n\n### Option 3: `boto3-stubs-lite`\n\nUse this when IDE memory use matters more than automatic overload inference.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[backup]==1.42.3\"\n```\n\nNotes:\n\n- `boto3-stubs-lite[backup]` keeps the service types, but upstream says it does not provide `session.client()` or `session.resource()` overloads.\n- If the stubs are only needed for editor support and CI type checks, keep them in a development dependency group.\n\n## Authentication And Setup\n\nThis package does not change AWS Backup authentication behavior. `boto3` still resolves credentials and region settings from the normal AWS provider chain:\n\n1. Explicit `Session(...)` or `client(...)` parameters\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. Shared AWS config and credentials files such as `~/.aws/config` and `~/.aws/credentials`\n4. Role-based providers such as assume-role, IAM Identity Center, web identity, container credentials, or instance metadata\n\nMinimal local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_backup.client import BackupClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nbackup: BackupClient = session.client(\"backup\")\n```\n\nAWS Backup is regional. Set `region_name` deliberately, especially when working with backup vaults, restore jobs, or cross-account automation.\n\n## Core Usage\n\n### Type a normal Backup client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_backup.client import BackupClient\n\nbackup: BackupClient = Session(region_name=\"us-east-1\").client(\"backup\")\n\nresponse = backup.list_backup_jobs(ByState=\"COMPLETED\", MaxResults=20)\n\nfor job in response.get(\"BackupJobs\", []):\n    print(job[\"BackupJobId\"], job[\"State\"], job.get(\"ResourceArn\"))\n```\n\nWith full `boto3-stubs[backup]`, the explicit `BackupClient` annotation is often optional. With standalone or lite installs, keep the annotation.\n\n### Type paginators explicitly\n\nAWS and the maintainer docs both expose many Backup paginators. Two common examples:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_backup.client import BackupClient\nfrom mypy_boto3_backup.paginator import (\n    ListBackupJobsPaginator,\n    ListRecoveryPointsByResourcePaginator,\n)\n\nbackup: BackupClient = Session(region_name=\"us-east-1\").client(\"backup\")\n\njobs: ListBackupJobsPaginator = backup.get_paginator(\"list_backup_jobs\")\nfor page in jobs.paginate(PaginationConfig={\"PageSize\": 100}):\n    for job in page.get(\"BackupJobs\", []):\n        print(job[\"BackupJobId\"])\n\nrecovery_points: ListRecoveryPointsByResourcePaginator = backup.get_paginator(\n    \"list_recovery_points_by_resource\"\n)\nfor page in recovery_points.paginate(\n    ResourceArn=\"arn:aws:ec2:us-east-1:123456789012:volume/vol-0123456789abcdef0\",\n    PaginationConfig={\"PageSize\": 50},\n):\n    for point in page.get(\"RecoveryPoints\", []):\n        print(point[\"RecoveryPointArn\"])\n```\n\nThe Backup service reference currently lists paginator support for operations such as `list_backup_jobs`, `list_backup_plans`, `list_backup_vaults`, `list_copy_jobs`, `list_restore_jobs`, `list_scan_jobs`, and related resource-specific list calls.\n\n### Use literals and TypedDicts in helper code\n\nThe generated `literals` and `type_defs` modules are useful when you want stricter checking around helper inputs and structured data.\n\n```python\nfrom mypy_boto3_backup.literals import AggregationPeriodType\nfrom mypy_boto3_backup.type_defs import AdvancedBackupSettingOutputTypeDef\n\ndef normalize_period(value: AggregationPeriodType) -> AggregationPeriodType:\n    return value\n\ndef build_setting() -> AdvancedBackupSettingOutputTypeDef:\n    return {\n        \"ResourceType\": \"EC2\",\n    }\n```\n\n### Keep typing imports out of runtime-only environments\n\nIf the stubs are installed only in development or CI, use `TYPE_CHECKING` guards so production imports do not depend on `mypy-boto3-backup`.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_backup.client import BackupClient\nelse:\n    BackupClient = object\n\nbackup: BackupClient = Session(region_name=\"us-east-1\").client(\"backup\")\n```\n\nThe PyPI project description notes this pattern is safe and specifically calls out a `pylint` workaround using `object` fallbacks.\n\n## Service Shape Notes\n\n- The current Backup boto3 reference exposes a low-level client with many `list_*`, `describe_*`, `start_*`, and `update_*` operations.\n- The current Backup boto3 reference exposes paginators, but it does not expose a waiters section.\n- The maintainer docs and PyPI package description for `mypy-boto3-backup` focus on the client, paginator, literals, and `type_defs` modules.\n\nDo not assume `client.get_waiter(...)` or a typed service resource exists for Backup unless your exact installed boto3 and stub versions prove it.\n\n## Common Pitfalls\n\n- `mypy-boto3-backup` does not replace `boto3`; it only adds static types.\n- The install name and import root differ: install `mypy-boto3-backup`, import from `mypy_boto3_backup`.\n- `boto3-stubs-lite[backup]` is lighter because it drops the automatic `Session.client(...)` and `Session.resource(...)` overload behavior. Add explicit annotations in lite mode.\n- Keep `boto3` and the stubs on the same release line when possible. Upstream versioning says the stub version tracks the related boto3 version.\n- The maintainer docs site is a generated rolling reference. Use PyPI for exact installable version pins.\n- AWS Backup authorization, cross-account access, vault policies, and restore semantics are runtime AWS concerns. The stubs help editors and type checkers, not permissions or service-side validation.\n- The AWS Backup reference is newer than this pinned stub version, so verify any newly documented operations before assuming they exist in `1.42.3`.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- The version used here `1.42.3` matches the current PyPI release checked on `2026-03-12`.\n- PyPI states that `mypy-boto3-backup` requires Python `>=3.9` and is classified as `Stubs Only`.\n- The PyPI project description says the package version matches the related `boto3` version.\n- On `2026-03-12`, the live AWS Backup boto3 reference was on `1.42.66`, so the AWS runtime docs can be slightly ahead of the pinned stub package.\n- The live AWS Backup service page exposes paginators but no waiters section. Treat waiter usage as unsupported unless you confirm it in your installed runtime and stubs.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-backup/`\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_backup/`\n- AWS Backup boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/backup.html`\n- AWS credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-batch/python/DOC.md",
    "content": "---\nname: mypy-boto3-batch\ndescription: \"Type stubs for boto3 Batch in Python, covering typed clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.59\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,batch,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-batch Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-batch` is a typing package for AWS Batch code that uses `boto3`. It does not make AWS calls by itself, it does not manage credentials, and it does not replace the runtime SDK.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[batch]` for the smoothest editor and type-checker experience with typed `Session.client(\"batch\")` overloads.\n- Install `mypy-boto3-batch` when you only want the Batch service stubs and are willing to annotate clients explicitly.\n- Install `boto3-stubs-lite[batch]` when IDE memory use matters more than automatic overload inference.\n\nKeep runtime setup in normal `boto3` or botocore configuration.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3-stubs[batch]==1.42.59\"\n```\n\nThis is the maintainer-recommended path when you want typed `boto3.client(\"batch\")` and `Session().client(\"batch\")` without annotating every variable yourself.\n\n### Standalone Batch stubs\n\n```bash\npython -m pip install \"boto3==1.42.59\" \"mypy-boto3-batch==1.42.59\"\n```\n\nUse this when you want only the Batch stubs package. In this mode, explicit annotations are the safest default.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install \"boto3-stubs-lite[batch]==1.42.59\"\n```\n\nThe lite package is more memory-friendly, but the maintainer docs note that it does not provide `Session.client()` overloads. Add explicit annotations or casts if you use it.\n\n### Generate stubs locally for an exact boto3 pin\n\nIf your project is pinned to a boto3 version newer than the standalone wheel, generate local stubs against that runtime version:\n\n```bash\nuvx --with \"boto3==1.42.59\" mypy-boto3-builder\n```\n\n## Setup And AWS Authentication\n\n`mypy-boto3-batch` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nBoto3 uses the standard AWS credential provider chain, including:\n\n1. Explicit credentials passed to a session or client\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. Shared config and credentials files under `~/.aws/`\n4. Role-based providers such as IAM Identity Center, assume-role, container credentials, or EC2 instance metadata\n\nTypical session setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(\n    profile_name=\"dev\",\n    region_name=\"us-east-1\",\n)\n```\n\nIf the boto3 session is misconfigured, the stubs will still type-check while the AWS call fails at runtime.\n\n## Core Usage\n\n### Typed Batch client\n\nUse the runtime client from `boto3`, then annotate it with the generated Batch type:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_batch import BatchClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nbatch: BatchClient = session.client(\"batch\")\n\nresponse = batch.describe_job_queues()\nfor queue in response.get(\"jobQueues\", []):\n    print(queue[\"jobQueueName\"], queue[\"state\"])\n```\n\n### Explicit annotations for standalone or lite installs\n\nWith standalone `mypy-boto3-batch` or `boto3-stubs-lite[batch]`, annotate the client directly instead of relying on inference:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_batch import BatchClient\n\nclient: BatchClient = Session(region_name=\"us-east-1\").client(\"batch\")\n```\n\n### Typed paginator\n\nThe generated docs expose paginator classes for Batch operations such as `describe_job_queues`, `list_jobs`, `list_jobs_by_consumable_resource`, `list_scheduling_policies`, and `list_service_jobs`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_batch import BatchClient\nfrom mypy_boto3_batch.paginator import ListJobsPaginator\n\nclient: BatchClient = Session(region_name=\"us-east-1\").client(\"batch\")\npaginator: ListJobsPaginator = client.get_paginator(\"list_jobs\")\n\nfor page in paginator.paginate(jobQueue=\"high-priority\", jobStatus=\"RUNNING\"):\n    for job in page.get(\"jobSummaryList\", []):\n        print(job[\"jobId\"], job[\"status\"])\n```\n\n### Submit a job with a typed client\n\n```python\nfrom mypy_boto3_batch import BatchClient\n\ndef submit_etl_job(client: BatchClient) -> str:\n    response = client.submit_job(\n        jobName=\"daily-etl\",\n        jobQueue=\"high-priority\",\n        jobDefinition=\"etl-job:1\",\n        containerOverrides={\n            \"command\": [\"python\", \"main.py\"],\n            \"environment\": [\n                {\"name\": \"RUN_MODE\", \"value\": \"daily\"},\n            ],\n        },\n    )\n    return response[\"jobId\"]\n```\n\nUse the generated `type_defs` module when wrapper code needs stronger typing for nested request and response shapes, and use `literals` when you want enum-like values checked before runtime.\n\n### Keep stub imports out of production-only environments\n\nIf the stubs are installed only in development or CI, keep the imports behind `TYPE_CHECKING` and cast the runtime client:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_batch import BatchClient\n\nclient = cast(\"BatchClient\", Session(region_name=\"us-east-1\").client(\"batch\"))\n```\n\nThis keeps runtime imports clean while preserving editor and mypy support.\n\n## Configuration Notes\n\n- `mypy-boto3-batch` adds typing for the Batch client and paginator surface only. The generated docs page for this service does not expose a Batch service resource module, so client-based code is the default.\n- Keep `boto3`, `botocore`, and the stub package aligned when exact request and response shapes matter.\n- Region selection still comes from the boto3 session or client. Set `region_name` explicitly in scripts and tests when the environment is ambiguous.\n- Use `botocore.config.Config` for retries, timeouts, proxies, and endpoint tuning. The stubs package only helps type-check those calls.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-batch` and expecting it to replace `boto3`. It is a stubs package, not the runtime AWS SDK.\n- Mixing up the names: install `mypy-boto3-batch`, import `mypy_boto3_batch`, and create the runtime client with service name `\"batch\"`.\n- Expecting `Session.client(\"batch\")` to infer a typed return value when you installed only `mypy-boto3-batch` or `boto3-stubs-lite[batch]`. Add explicit annotations in those modes.\n- Importing stub symbols at runtime when the package is only a dev dependency. Use `TYPE_CHECKING` or keep the stubs installed anywhere those imports execute.\n- Copying examples from the moving generated docs root without verifying the installable wheel version on PyPI. The docs site can be ahead of the latest standalone package release.\n- Treating typing as permission validation. Good type hints do not prevent runtime failures from missing IAM permissions, wrong regions, or incorrect Batch resource names.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.59` matches the current PyPI project page for `mypy-boto3-batch`.\n- PyPI lists `mypy-boto3-batch 1.42.59` as the latest installable release on March 12, 2026, published on February 27, 2026.\n- The generated maintainer docs root is ahead of the standalone wheel and currently shows local generation with `boto3==1.42.66`.\n- The maintainer documentation states that this package uses the same version as the related `boto3` package.\n- Practical rule: if exact type alignment matters, pin `boto3==1.42.59` with `mypy-boto3-batch==1.42.59`, or generate stubs locally against your exact boto3 pin.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_batch/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-batch/`\n- Maintainer source repository: `https://github.com/youtype/mypy_boto3_builder`\n- Boto3 Batch reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/batch.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-bedrock/python/DOC.md",
    "content": "---\nname: mypy-boto3-bedrock\ndescription: \"mypy-boto3-bedrock package guide for typed boto3 Bedrock clients, paginators, literals, and type definitions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.63\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,bedrock,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-bedrock Python Package Guide\n\n## What It Is\n\n`mypy-boto3-bedrock` provides generated type annotations for the AWS Bedrock control-plane client in `boto3`.\n\nUse it when you want:\n\n- typed `Session.client(\"bedrock\")`\n- typed paginator objects for Bedrock listing operations\n- typed request and response dictionaries from `mypy_boto3_bedrock.type_defs`\n- better autocomplete and mypy or pyright coverage for Bedrock administration code\n\nIt does not replace `boto3` at runtime. Real AWS calls still go through `boto3` and `botocore`.\n\n## Golden Rule\n\n- Install `boto3` for runtime behavior.\n- Install either `boto3-stubs[bedrock]` or the standalone `mypy-boto3-bedrock` package for typing.\n- Configure AWS credentials, region, retries, and profiles through normal `boto3` configuration; this package only adds types.\n\n## Install\n\nInstall the runtime SDK first if it is not already present:\n\n```bash\npython -m pip install boto3\n```\n\nThen choose one typing strategy.\n\n### Option A: `boto3-stubs` Extra\n\nUse this when you want the standard umbrella package flow:\n\n```bash\npython -m pip install \"boto3-stubs[bedrock]\"\n```\n\n### Option B: Standalone Service Package\n\nUse this when you want a narrower dependency just for Bedrock typing:\n\n```bash\npython -m pip install \"boto3-stubs[essential]\" \"mypy-boto3-bedrock==1.42.63\"\n```\n\n### IDE And Type Checker Notes\n\n- The maintainers also document lite variants of the stubs. If full overload-heavy packages slow down your IDE, use the lite workflow and annotate the client explicitly.\n- Keep `boto3`, `botocore`, and the stub package in the same release family whenever possible.\n\n## Initialization And Setup\n\nCreate the runtime client with normal boto3 session setup, then add a `BedrockClient` annotation.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock.client import BedrockClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nbedrock: BedrockClient = session.client(\"bedrock\")\n```\n\nIf you keep stubs as a development-only dependency, guard the type import with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_bedrock.client import BedrockClient\n\ndef make_bedrock_client() -> \"BedrockClient\":\n    return boto3.client(\"bedrock\", region_name=\"us-east-1\")\n```\n\nThis keeps the explicit type available to mypy and pyright without making the stub import part of normal runtime execution.\n\n## Authentication And Region\n\n`mypy-boto3-bedrock` does not add a Bedrock-specific auth layer. Credential and region resolution work exactly as they do in `boto3`.\n\nCommon configuration sources:\n\n- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`\n- `AWS_PROFILE` and `AWS_DEFAULT_REGION`\n- shared config files in `~/.aws/config` and `~/.aws/credentials`\n- IAM roles and task roles in AWS environments\n\nExample:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock.client import BedrockClient\n\nsession = Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\nbedrock: BedrockClient = session.client(\"bedrock\")\n```\n\nIf Bedrock requests fail because of credentials or region access, fix the underlying `boto3` or AWS configuration. The stub package does not change runtime behavior.\n\n## Core Usage Patterns\n\n### Typed Bedrock Client\n\nUse the typed client as the default entry point for control-plane operations.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock.client import BedrockClient\n\nsession = Session(region_name=\"us-east-1\")\nbedrock: BedrockClient = session.client(\"bedrock\")\n\nresponse = bedrock.list_foundation_models()\n\nfor summary in response.get(\"modelSummaries\", []):\n    print(summary[\"modelId\"], summary.get(\"providerName\"))\n```\n\n### Typed Paginator\n\nThe generated docs include paginator types for multi-page listing operations such as `list_custom_models`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock.client import BedrockClient\nfrom mypy_boto3_bedrock.paginator import ListCustomModelsPaginator\n\nsession = Session(region_name=\"us-east-1\")\nbedrock: BedrockClient = session.client(\"bedrock\")\n\npaginator: ListCustomModelsPaginator = bedrock.get_paginator(\"list_custom_models\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 25}):\n    for model in page.get(\"modelSummaries\", []):\n        print(model[\"modelArn\"], model.get(\"modelName\"))\n```\n\n### Typed Request Dictionaries\n\nUse `type_defs` when you want request construction to be checked before it reaches the client call.\n\n```python\nfrom mypy_boto3_bedrock.client import BedrockClient\nfrom mypy_boto3_bedrock.type_defs import (\n    ListCustomModelsRequestPaginateTypeDef,\n    PaginatorConfigTypeDef,\n)\n\npagination: PaginatorConfigTypeDef = {\"PageSize\": 25}\nrequest: ListCustomModelsRequestPaginateTypeDef = {\n    \"PaginationConfig\": pagination,\n}\n\ndef iter_custom_model_pages(bedrock: BedrockClient) -> None:\n    paginator = bedrock.get_paginator(\"list_custom_models\")\n    for page in paginator.paginate(**request):\n        print(page.get(\"modelSummaries\", []))\n```\n\n## What Upstream Modules Cover\n\nThe maintainer docs for this package focus on these import areas:\n\n- `mypy_boto3_bedrock.client` for `BedrockClient`\n- `mypy_boto3_bedrock.paginator` for paginator types\n- `mypy_boto3_bedrock.type_defs` for generated request and response `TypedDict`s\n- `mypy_boto3_bedrock.literals` for constrained literal values\n- `mypy_boto3_bedrock` top-level exports for common typing shortcuts\n\nPlan around typed clients and paginator helpers. The published docs for this service package do not emphasize boto3 resource-style usage.\n\n## Common Pitfalls\n\n- `mypy-boto3-bedrock` is not the Bedrock runtime client package. Runtime calls still come from `boto3`.\n- Package name and import name differ. Install `mypy-boto3-bedrock`, import from `mypy_boto3_bedrock`.\n- Service name is `\"bedrock\"` when constructing the client.\n- Bedrock control-plane typing is separate from `bedrock-runtime`; do not import runtime client types from this package.\n- If you use the lite stubs workflow, expect to annotate `BedrockClient` explicitly instead of relying on inference.\n- Version skew between `boto3`, `botocore`, and the stubs can surface false-positive type errors or missing symbols when AWS adds new Bedrock operations or fields.\n\n## Version-Sensitive Notes\n\n- This doc is keyed to the version used here `1.42.63`, and the PyPI project page also showed `1.42.63` on `2026-03-12`.\n- The maintainer docs page still embeds install snippets for an older `boto3-stubs[bedrock]==1.40.61` release family even though PyPI is newer.\n- The current AWS boto3 Bedrock client docs already expose Bedrock operations such as `list_foundation_models` and paginator-backed listing APIs; if your project pins older boto3 or stubs, newer methods may not type-check cleanly.\n- Re-check the official docs before copying type names into code if your project is pinned to a different boto3 release line.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock/`\n- Maintainer examples page: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock/examples/`\n- Maintainer type definitions page: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock/type_defs/`\n- PyPI project: `https://pypi.org/project/mypy-boto3-bedrock/`\n- AWS boto3 Bedrock client docs: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock.html`\n- AWS boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-bedrock-agent/python/DOC.md",
    "content": "---\nname: mypy-boto3-bedrock-agent\ndescription: \"mypy-boto3-bedrock-agent guide for typed boto3 Bedrock Agents clients, paginators, and TypedDict request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,bedrock,bedrock-agent,boto3,mypy,pyright,python,typing,stubs\"\n---\n\n# mypy-boto3-bedrock-agent Python Package Guide\n\n## What It Is\n\n`mypy-boto3-bedrock-agent` provides generated type annotations for `boto3.client(\"bedrock-agent\")`.\n\nUse it when you want:\n\n- a typed `AgentsforBedrockClient`\n- typed paginator classes such as `ListAgentsPaginator`\n- generated `TypedDict` request and response shapes from `mypy_boto3_bedrock_agent.type_defs`\n- better autocomplete and mypy or pyright coverage for Bedrock agent management code\n\nIt is a stubs-only package. Real AWS calls still come from `boto3`.\n\n## Install\n\nPin `boto3` and the stubs to the same release family when possible:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-bedrock-agent==1.42.3\"\n```\n\nThe maintainer also documents these install patterns:\n\n```bash\n# Full boto3-stubs package with the Bedrock Agent service extra\npython -m pip install \"boto3-stubs[bedrock-agent]==1.42.3\"\n\n# Lite variant: lower editor memory use, but no session.client/resource overloads\npython -m pip install \"boto3-stubs-lite[bedrock-agent]==1.42.3\"\n```\n\nUse the standalone package when you only want this service's types. Use `boto3-stubs[bedrock-agent]` when you already standardize on the umbrella package.\n\n## Authentication And Client Initialization\n\nThis package follows normal boto3 credential and region resolution. Boto3 checks client parameters, session parameters, environment variables, assume-role providers, shared credentials files, config files, container credentials, and EC2 instance metadata in that order.\n\nTypical local environment:\n\n```bash\nexport AWS_PROFILE=bedrock-dev\nexport AWS_DEFAULT_REGION=us-east-1\nexport BEDROCK_FOUNDATION_MODEL_ID=your-model-id\nexport BEDROCK_AGENT_ROLE_ARN=arn:aws:iam::123456789012:role/bedrock-agent-role\n```\n\nTyped client setup:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent import AgentsforBedrockClient\n\nsession = Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\n\nclient: AgentsforBedrockClient = session.client(\"bedrock-agent\")\n```\n\n`region_name` on the client or session takes precedence over environment and config file values.\n\n## Core Workflows\n\n### Create A Typed Bedrock Agent\n\nAWS documents `agentName` as required for `create_agent`. In practice, a usable agent setup usually also includes an instruction, a foundation model identifier, and an IAM role ARN.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent import AgentsforBedrockClient\nfrom mypy_boto3_bedrock_agent.type_defs import (\n    CreateAgentRequestTypeDef,\n    CreateAgentResponseTypeDef,\n    MemoryConfigurationTypeDef,\n)\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockClient = session.client(\"bedrock-agent\")\n\nmemory_config: MemoryConfigurationTypeDef = {\n    \"enabledMemoryTypes\": [\"SESSION_SUMMARY\"],\n    \"storageDays\": 7,\n    \"sessionSummaryConfiguration\": {\"maxRecentSessions\": 5},\n}\n\nrequest: CreateAgentRequestTypeDef = {\n    \"agentName\": \"support-agent\",\n    \"instruction\": \"Answer support questions and escalate billing issues.\",\n    \"foundationModel\": os.environ[\"BEDROCK_FOUNDATION_MODEL_ID\"],\n    \"agentResourceRoleArn\": os.environ[\"BEDROCK_AGENT_ROLE_ARN\"],\n    \"idleSessionTTLInSeconds\": 900,\n    \"memoryConfiguration\": memory_config,\n    \"tags\": {\n        \"app\": \"support-api\",\n        \"env\": \"dev\",\n    },\n}\n\nresponse: CreateAgentResponseTypeDef = client.create_agent(**request)\nagent_id = response[\"agent\"][\"agentId\"]\nprint(agent_id, response[\"agent\"][\"agentStatus\"])\n```\n\nAWS also documents these `create_agent` details that matter in real code:\n\n- `agentResourceRoleArn` is the IAM role the agent uses to invoke API operations.\n- `idleSessionTTLInSeconds` controls how long Bedrock keeps conversation state for the agent session.\n- `memoryConfiguration` is how you enable retained conversational context such as `SESSION_SUMMARY`.\n\n### Prepare The Draft Agent And Poll Status\n\n`prepare_agent` works on the agent's `DRAFT` version. `get_agent` lets you poll until the draft is ready.\n\n```python\nimport os\nimport time\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent import AgentsforBedrockClient\nfrom mypy_boto3_bedrock_agent.type_defs import (\n    GetAgentResponseTypeDef,\n    PrepareAgentResponseTypeDef,\n)\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockClient = session.client(\"bedrock-agent\")\n\nagent_id = \"your-agent-id\"\n\nprepare_response: PrepareAgentResponseTypeDef = client.prepare_agent(agentId=agent_id)\nprint(prepare_response[\"agentVersion\"], prepare_response[\"agentStatus\"])\n\nwhile True:\n    current: GetAgentResponseTypeDef = client.get_agent(agentId=agent_id)\n    status = current[\"agent\"][\"agentStatus\"]\n\n    if status == \"PREPARED\":\n        print(\"Agent is ready\")\n        break\n    if status == \"FAILED\":\n        raise RuntimeError(current[\"agent\"].get(\"failureReasons\", [\"Agent preparation failed\"]))\n\n    time.sleep(5)\n```\n\nThe Bedrock Agent response shape includes statuses such as `CREATING`, `PREPARING`, `PREPARED`, `NOT_PREPARED`, `FAILED`, `UPDATING`, and `DELETING`.\n\n### Paginate Through Existing Agents\n\nThe generated paginator overloads are useful when your account has enough agents, aliases, action groups, or knowledge bases to require pagination.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent import AgentsforBedrockClient\nfrom mypy_boto3_bedrock_agent.paginator import ListAgentsPaginator\nfrom mypy_boto3_bedrock_agent.type_defs import (\n    ListAgentsRequestPaginateTypeDef,\n    PaginatorConfigTypeDef,\n)\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockClient = session.client(\"bedrock-agent\")\n\npagination: PaginatorConfigTypeDef = {\n    \"PageSize\": 25,\n    \"MaxItems\": 100,\n}\nrequest: ListAgentsRequestPaginateTypeDef = {\n    \"PaginationConfig\": pagination,\n}\n\npaginator: ListAgentsPaginator = client.get_paginator(\"list_agents\")\n\nfor page in paginator.paginate(**request):\n    for summary in page.get(\"agentSummaries\", []):\n        print(summary[\"agentId\"], summary[\"agentName\"], summary[\"agentStatus\"])\n```\n\nThe same package also exposes paginator types for:\n\n- `list_agent_action_groups`\n- `list_agent_aliases`\n- `list_agent_collaborators`\n- `list_agent_knowledge_bases`\n- `list_agent_versions`\n- `list_data_sources`\n- `list_knowledge_bases`\n\n### Keep Stub Imports Out Of Production If Needed\n\nIf your runtime environment only installs `boto3`, guard type imports with `TYPE_CHECKING`.\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_bedrock_agent import AgentsforBedrockClient\n\ndef make_client() -> \"AgentsforBedrockClient\":\n    return boto3.client(\"bedrock-agent\", region_name=\"us-east-1\")\n```\n\nThis pattern is explicitly supported by the PyPI project docs for stub-only usage.\n\n## Common Pitfalls\n\n- `mypy-boto3-bedrock-agent` does not install `boto3` for runtime calls. Install both if the environment actually talks to AWS.\n- The service name is `\"bedrock-agent\"`. If you annotate the wrong service client, the types will not match the operations in this package.\n- `boto3-stubs-lite` is valid, but the maintainer docs call out that it does not provide `session.client()` and `session.resource()` overloads. Add explicit annotations in that setup.\n- Bedrock agent creation can succeed syntactically while still being unusable operationally if the IAM role ARN, model identifier, region access, or account permissions are wrong.\n- AWS notes that agent instructions are not honored in a narrow default configuration: one knowledge base, default prompts, no action group, and user input disabled.\n- Generated AWS reference pages are latest-docs targets. They can show newer operations or fields before an older pinned stub package catches up.\n\n## Version-Sensitive Notes\n\n- This guide is pinned to `mypy-boto3-bedrock-agent 1.42.3`.\n- PyPI lists `1.42.3` as a stubs-only release published on December 4, 2025, with `Requires: Python >=3.9`.\n- The maintainer documentation is generated from the same release family and documents the `AgentsforBedrockClient`, paginator classes, and `type_defs` used above.\n- As of March 13, 2026, the AWS boto3 Bedrock Agent reference pages are served from newer latest-docs builds than `1.42.3`, so keep `boto3`, `botocore`, and the stub package aligned if exact field coverage matters in type checking.\n\n## Official Sources\n\n- Maintainer client docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_agent/client/\n- Maintainer type definitions docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_agent/type_defs/\n- PyPI package page: https://pypi.org/project/mypy-boto3-bedrock-agent/\n- AWS `create_agent` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agent/client/create_agent.html\n- AWS `list_agents` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agent/client/list_agents.html\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- AWS boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-bedrock-agent-runtime/python/DOC.md",
    "content": "---\nname: mypy-boto3-bedrock-agent-runtime\ndescription: \"mypy-boto3-bedrock-agent-runtime guide for typed boto3 Agents for Bedrock Runtime clients, request/response TypedDicts, and paginator usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,bedrock,boto3,mypy,pyright,python,stubs,agents\"\n---\n\n# mypy-boto3-bedrock-agent-runtime Python Package Guide\n\n## What It Is\n\n`mypy-boto3-bedrock-agent-runtime` provides generated type annotations for the `boto3` Agents for Amazon Bedrock Runtime client.\n\nUse it when you want:\n\n- a typed `Session.client(\"bedrock-agent-runtime\")`\n- generated request and response `TypedDict` definitions from `type_defs`\n- paginator types from `paginator`\n- literal types for constrained string values from `literals`\n\nIt is a stubs-only package. Real AWS calls still run through `boto3` and `botocore`.\n\n## Golden Rule\n\n- Install `boto3` for runtime behavior.\n- Install either `mypy-boto3-bedrock-agent-runtime` or the `boto3-stubs[bedrock-agent-runtime]` extra for typing.\n- Keep `boto3`, `botocore`, and the stubs in the same release family when possible.\n- Configure credentials, region, retries, and endpoints through normal `boto3` configuration.\n\n## Install\n\nPin the runtime SDK and the stub package together when you want reproducible type coverage:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-bedrock-agent-runtime==1.42.3\"\n```\n\nThe maintainer docs also support the umbrella extras:\n\n```bash\npython -m pip install \"boto3-stubs[bedrock-agent-runtime]\"\npython -m pip install \"boto3-stubs-lite[bedrock-agent-runtime]\"\n```\n\nUse `boto3-stubs-lite` if the full overload-heavy package slows down your editor. The maintainer docs note that the lite variant does not provide `session.client()` and `session.resource()` overloads, so explicit annotations matter more.\n\n## Authentication And Region\n\nThis package does not change AWS authentication. Use the same environment variables and shared config files that `boto3` expects:\n\n```bash\nexport AWS_PROFILE=bedrock-dev\nexport AWS_DEFAULT_REGION=us-east-1\n\n# Or explicit credentials when needed\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...  # temporary credentials only\n```\n\nAWS documents a full credential provider chain for `boto3`, including explicit parameters, environment variables, assume-role providers, IAM Identity Center, shared config files, container credentials, and EC2 instance metadata.\n\n## Initialize A Typed Client\n\nCreate the client with normal `boto3` session setup, then annotate it as `AgentsforBedrockRuntimeClient`:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent_runtime import AgentsforBedrockRuntimeClient\n\nsession = Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\n\nclient: AgentsforBedrockRuntimeClient = session.client(\"bedrock-agent-runtime\")\n```\n\nIf you keep stubs as a development-only dependency, guard the import with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_bedrock_agent_runtime import AgentsforBedrockRuntimeClient\n\n\ndef make_client() -> \"AgentsforBedrockRuntimeClient\":\n    return boto3.client(\"bedrock-agent-runtime\", region_name=\"us-east-1\")\n```\n\n## Core Usage\n\n### Invoke An Agent With Typed Requests\n\n`invoke_agent` requires you to send `agentId`, `agentAliasId`, `sessionId`, and the user input. The AWS boto3 docs also note that the response contains an event stream under `completion`.\n\n```python\nimport os\nfrom uuid import uuid4\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent_runtime import AgentsforBedrockRuntimeClient\nfrom mypy_boto3_bedrock_agent_runtime.type_defs import (\n    InvokeAgentRequestTypeDef,\n    InvokeAgentResponseTypeDef,\n)\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockRuntimeClient = session.client(\"bedrock-agent-runtime\")\n\nrequest: InvokeAgentRequestTypeDef = {\n    \"agentId\": os.environ[\"BEDROCK_AGENT_ID\"],\n    \"agentAliasId\": os.environ[\"BEDROCK_AGENT_ALIAS_ID\"],\n    \"sessionId\": str(uuid4()),\n    \"inputText\": \"Summarize the latest support ticket in two bullets.\",\n    \"enableTrace\": False,\n}\n\nresponse: InvokeAgentResponseTypeDef = client.invoke_agent(**request)\n\nfor event in response[\"completion\"]:\n    chunk = event.get(\"chunk\")\n    if chunk and \"bytes\" in chunk:\n        print(chunk[\"bytes\"].decode(\"utf-8\"), end=\"\")\n\nprint()\nprint(\"sessionId:\", response[\"sessionId\"])\n```\n\nIf you turn on tracing, the stream can also contain `trace` events. AWS also documents that streaming agent responses require the `bedrock:InvokeModelWithResponseStream` permission in addition to the normal agent invocation permissions.\n\n### Retrieve From A Knowledge Base And Generate An Answer\n\nUse `retrieve_and_generate` when you want Bedrock to retrieve context from a knowledge base and produce the final answer in one call.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent_runtime import AgentsforBedrockRuntimeClient\nfrom mypy_boto3_bedrock_agent_runtime.type_defs import (\n    RetrieveAndGenerateRequestTypeDef,\n    RetrieveAndGenerateResponseTypeDef,\n)\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockRuntimeClient = session.client(\"bedrock-agent-runtime\")\n\nrequest: RetrieveAndGenerateRequestTypeDef = {\n    \"input\": {\"text\": \"Which product issues were escalated this week?\"},\n    \"retrieveAndGenerateConfiguration\": {\n        \"type\": \"KNOWLEDGE_BASE\",\n        \"knowledgeBaseConfiguration\": {\n            \"knowledgeBaseId\": os.environ[\"BEDROCK_KNOWLEDGE_BASE_ID\"],\n            \"modelArn\": os.environ[\"BEDROCK_MODEL_ARN\"],\n            \"retrievalConfiguration\": {\n                \"vectorSearchConfiguration\": {\n                    \"numberOfResults\": 4,\n                }\n            },\n        },\n    },\n}\n\nresponse: RetrieveAndGenerateResponseTypeDef = client.retrieve_and_generate(**request)\n\nprint(response[\"output\"][\"text\"])\nprint(\"sessionId:\", response[\"sessionId\"])\n```\n\nThe AWS docs call out an important difference from `invoke_agent`: you do not choose the initial `sessionId` for `retrieve_and_generate`. The service returns it in the first response, and you reuse that value on follow-up calls when you want conversation context to continue.\n\n### Paginate Retrieval Results\n\nThe generated package includes paginator types for operations such as `retrieve`, `rerank`, `list_sessions`, and `get_agent_memory`. Use the paginator type directly when you want checked pagination code.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_bedrock_agent_runtime import AgentsforBedrockRuntimeClient\nfrom mypy_boto3_bedrock_agent_runtime.paginator import RetrievePaginator\nfrom mypy_boto3_bedrock_agent_runtime.type_defs import RetrieveRequestPaginateTypeDef\n\nsession = Session(region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\nclient: AgentsforBedrockRuntimeClient = session.client(\"bedrock-agent-runtime\")\n\npaginator: RetrievePaginator = client.get_paginator(\"retrieve\")\n\nrequest: RetrieveRequestPaginateTypeDef = {\n    \"knowledgeBaseId\": os.environ[\"BEDROCK_KNOWLEDGE_BASE_ID\"],\n    \"retrievalQuery\": {\"text\": \"refund policy for enterprise accounts\"},\n    \"retrievalConfiguration\": {\n        \"vectorSearchConfiguration\": {\n            \"numberOfResults\": 10,\n        }\n    },\n    \"PaginationConfig\": {\"PageSize\": 10},\n}\n\nfor page in paginator.paginate(**request):\n    for result in page.get(\"retrievalResults\", []):\n        content = result.get(\"content\", {})\n        print(result[\"location\"])\n        print(content)\n```\n\n## Common Pitfalls\n\n- This package does not create a runtime client by itself. If `boto3` is missing, your code will still fail at runtime.\n- The service name is `\"bedrock-agent-runtime\"`. Do not swap it with `\"bedrock\"` or `\"bedrock-runtime\"` unless you are intentionally using those separate AWS APIs.\n- `invoke_agent` and `retrieve_and_generate` handle session state differently. For `invoke_agent`, you supply `sessionId`; for `retrieve_and_generate`, the service returns the initial `sessionId`.\n- `invoke_agent` returns an event stream in `completion`, not a single plain-text field.\n- If you use `boto3-stubs-lite`, do not expect `session.client(\"bedrock-agent-runtime\")` overload inference. Add the explicit `AgentsforBedrockRuntimeClient` annotation yourself.\n- Version skew between `boto3`, `botocore`, and the stubs can surface missing methods or stale request shapes when AWS adds new Bedrock Agent Runtime features.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.42.3`.\n- PyPI lists `mypy-boto3-bedrock-agent-runtime 1.42.3` and marks it as requiring Python `>=3.9`.\n- The maintainer docs state that the package version matches the related `boto3` version.\n- The maintainer docs are generated and unversioned, so examples on the site can drift. Use PyPI for exact pinning and the AWS boto3 reference for service behavior.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_agent_runtime/`\n- Maintainer usage examples: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_agent_runtime/usage/`\n- Maintainer type definitions: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_agent_runtime/type_defs/`\n- PyPI project: `https://pypi.org/project/mypy-boto3-bedrock-agent-runtime/`\n- AWS boto3 Agents for Bedrock Runtime reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agent-runtime.html`\n- AWS `invoke_agent` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agent-runtime/client/invoke_agent.html`\n- AWS `retrieve_and_generate` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html`\n- AWS credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-bedrock-runtime/python/DOC.md",
    "content": "---\nname: mypy-boto3-bedrock-runtime\ndescription: \"mypy-boto3-bedrock-runtime guide for Python type-safe Bedrock Runtime clients, literals, paginators, and TypedDict request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.42\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,aws,boto3,bedrock,bedrock-runtime,mypy,typing,stubs\"\n---\n\n# mypy-boto3-bedrock-runtime Python Package Guide\n\n## What It Is\n\n`mypy-boto3-bedrock-runtime` is a stubs-only package for the `boto3` Bedrock Runtime client.\n\nUse it when you want static typing for:\n\n- `boto3.client(\"bedrock-runtime\")` as `BedrockRuntimeClient`\n- the `list_async_invokes` paginator\n- `literals` such as `AsyncInvokeStatusType`\n- `type_defs` such as `ConverseRequestTypeDef`, `ConverseResponseTypeDef`, and `InvokeModelResponseTypeDef`\n\nIt does not send requests by itself. You still need `boto3` installed and AWS credentials configured.\n\n## Install\n\nInstall the runtime SDK and the stubs together if you want reproducible typing:\n\n```bash\npython -m pip install \"boto3==1.42.42\" \"mypy-boto3-bedrock-runtime==1.42.42\"\n```\n\nIf you want boto3 overload auto-discovery in editors and type checkers, the maintainer docs recommend the umbrella extra:\n\n```bash\npython -m pip install \"boto3-stubs[bedrock-runtime]\"\n```\n\nIf memory use in the editor matters more than auto-discovery, the docs also provide a lite variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[bedrock-runtime]\"\n```\n\n`boto3-stubs-lite` is more RAM-friendly, but it does not provide `session.client()` and `session.resource()` overloads, so explicit annotations become more important.\n\n## Initialize A Typed Client\n\nUse the normal boto3 session flow and annotate the returned client.\n\n```python\nfrom boto3.session import Session\n\nfrom mypy_boto3_bedrock_runtime import BedrockRuntimeClient\n\nsession = Session(profile_name=\"bedrock-dev\", region_name=\"us-east-1\")\nclient: BedrockRuntimeClient = session.client(\"bedrock-runtime\")\n```\n\nUse `\"bedrock-runtime\"` for inference calls. `\"bedrock\"` is a different control-plane service.\n\n## Core Usage\n\n### Typed `converse` requests\n\nUse `type_defs` when you want request and response dictionaries checked before the API call.\n\n```python\nfrom boto3.session import Session\n\nfrom mypy_boto3_bedrock_runtime import BedrockRuntimeClient\nfrom mypy_boto3_bedrock_runtime.type_defs import (\n    ConverseRequestTypeDef,\n    ConverseResponseTypeDef,\n    InferenceConfigurationTypeDef,\n)\n\nsession = Session(region_name=\"us-east-1\")\nclient: BedrockRuntimeClient = session.client(\"bedrock-runtime\")\n\ninference_config: InferenceConfigurationTypeDef = {\n    \"maxTokens\": 256,\n    \"temperature\": 0.2,\n}\n\nrequest: ConverseRequestTypeDef = {\n    \"modelId\": \"your-model-id\",\n    \"messages\": [\n        {\n            \"role\": \"user\",\n            \"content\": [{\"text\": \"Summarize why typed boto3 clients help.\"}],\n        }\n    ],\n    \"inferenceConfig\": inference_config,\n}\n\nresponse: ConverseResponseTypeDef = client.converse(**request)\nprint(response[\"output\"][\"message\"][\"content\"])\n```\n\nThe Bedrock Runtime reference documents `modelId` and `messages` as the core `converse` inputs. The stubs package gives you the matching request and response shapes.\n\n### Typed `invoke_model` responses\n\nUse `invoke_model` when you need the raw model-specific JSON body instead of the higher-level `converse` interface.\n\n```python\nimport json\nfrom boto3.session import Session\n\nfrom mypy_boto3_bedrock_runtime import BedrockRuntimeClient\nfrom mypy_boto3_bedrock_runtime.type_defs import InvokeModelResponseTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nclient: BedrockRuntimeClient = session.client(\"bedrock-runtime\")\n\npayload = {\n    \"inputText\": \"Explain the difference between boto3 and its stubs.\",\n}\n\nresponse: InvokeModelResponseTypeDef = client.invoke_model(\n    body=json.dumps(payload).encode(\"utf-8\"),\n    contentType=\"application/json\",\n    accept=\"application/json\",\n    modelId=\"your-model-id\",\n)\n\nbody = json.loads(response[\"body\"].read())\nprint(body)\n```\n\nThe AWS reference requires `body`, `contentType`, `accept`, and `modelId`, and it specifies JSON request bodies for `invoke_model`.\n\n### Typed paginator\n\nBedrock Runtime currently exposes one paginator: `list_async_invokes`.\n\n```python\nfrom boto3.session import Session\n\nfrom mypy_boto3_bedrock_runtime import BedrockRuntimeClient\nfrom mypy_boto3_bedrock_runtime.paginator import ListAsyncInvokesPaginator\nfrom mypy_boto3_bedrock_runtime.type_defs import AsyncInvokeSummaryTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nclient: BedrockRuntimeClient = session.client(\"bedrock-runtime\")\n\npaginator: ListAsyncInvokesPaginator = client.get_paginator(\"list_async_invokes\")\n\nfor page in paginator.paginate(statusEquals=\"Completed\", maxResults=25):\n    for summary in page.get(\"asyncInvokeSummaries\", []):\n        item: AsyncInvokeSummaryTypeDef = summary\n        print(item[\"invocationArn\"], item[\"status\"])\n```\n\n### Literals for constrained values\n\nUse the generated literal types when a field only accepts a small fixed set of strings.\n\n```python\nfrom mypy_boto3_bedrock_runtime.literals import AsyncInvokeStatusType\n\nstatus: AsyncInvokeStatusType = \"Completed\"\n```\n\nThis is useful for filters like `statusEquals` on async invocation listing and for avoiding string typos in your own wrappers.\n\n## Authentication And Configuration\n\nThis package inherits normal boto3 configuration behavior because all runtime calls still go through boto3.\n\nPractical defaults:\n\n- set a Bedrock-supported AWS region explicitly\n- use `AWS_PROFILE` for local development when possible\n- use IAM roles or workload identity in deployed environments\n- avoid hard-coding credentials unless you are handling temporary credentials intentionally\n\nUseful environment variables:\n\n```bash\nexport AWS_PROFILE=bedrock-dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nAccording to the boto3 credentials guide, boto3 searches for credentials in this order: explicit client parameters, explicit `Session` parameters, environment variables, assume-role providers, web identity, IAM Identity Center, shared credentials/config files, container credentials, and EC2 instance metadata.\n\n## Common Pitfalls\n\n### This package is types only\n\n`mypy-boto3-bedrock-runtime` does not bundle the runtime client. If `boto3` is missing, your code will still fail at import or runtime even if the type checker passes.\n\n### Use the correct service name\n\nInference uses:\n\n```python\nsession.client(\"bedrock-runtime\")\n```\n\nDo not switch this to `session.client(\"bedrock\")` unless you are intentionally using the Bedrock control-plane API.\n\n### Keep boto3 and stubs in the same version family\n\nThe maintainer docs state that `mypy-boto3-bedrock-runtime` versions track the related `boto3` version. In practice, pinning both to the same `1.42.42` line avoids missing parameters and stale editor hints.\n\n### `boto3-stubs-lite` changes the ergonomics\n\nThe lite package is valid, but the docs explicitly warn that it does not provide `session.client/resource` overloads. If you use it, annotate returned clients directly instead of relying on inference.\n\n### Use `TYPE_CHECKING` if you do not want a runtime dependency\n\nThe PyPI project description notes that it is safe to gate imports behind `TYPE_CHECKING` when you only want the stubs for development and CI type checks.\n\n## Version-Sensitive Notes\n\n- The version covered here is `1.42.42`.\n- PyPI currently shows `1.42.42` as the latest release, published on February 4, 2026.\n- The generated maintainer docs are useful for symbols and examples, but the local-generation snippet on that site still references `boto3==1.42.39` as of March 12, 2026.\n- The AWS boto3 Bedrock Runtime reference is a moving latest-docs target and currently renders newer boto3 patch documentation than this package version. Treat the AWS method list as authoritative for service behavior, but keep your installed `boto3`, `botocore`, and stubs aligned when you need exact type coverage.\n\n## Official Sources Used\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_bedrock_runtime/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-bedrock-runtime/`\n- AWS Bedrock Runtime boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-runtime.html`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cleanrooms/python/DOC.md",
    "content": "---\nname: mypy-boto3-cleanrooms\ndescription: \"mypy-boto3-cleanrooms type stubs for boto3 AWS Clean Rooms clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.52\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cleanrooms,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-cleanrooms Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cleanrooms` provides generated type annotations for the AWS Clean Rooms client in `boto3`.\n\nUse it when you want:\n\n- a typed `Session.client(\"cleanrooms\")`\n- typed paginator objects for list operations such as `list_memberships`\n- generated `literals` and `type_defs` modules for Clean Rooms request and response shapes\n- better autocomplete and mypy or pyright coverage for AWS Clean Rooms administration code\n\nIt does not replace `boto3` at runtime. Real AWS calls still go through `boto3` and `botocore`.\n\n## Golden Rule\n\n- Install `boto3` for runtime AWS calls.\n- Install either `boto3-stubs[cleanrooms]` or the standalone `mypy-boto3-cleanrooms` package for typing.\n- Configure AWS credentials, profiles, and regions through normal `boto3` setup. This package only adds types.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 \"boto3-stubs[cleanrooms]\"\n```\n\nThis is the maintainer-recommended path when you want type checking plus automatic overloads for `Session.client(\"cleanrooms\")`.\n\n### Standalone Clean Rooms stubs\n\n```bash\npython -m pip install boto3 mypy-boto3-cleanrooms\n```\n\nUse this when you only want the Clean Rooms service stubs. In this mode, explicit annotations are usually necessary.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[cleanrooms]\"\n```\n\nThe lite package is more memory-friendly, especially for PyCharm, but it does not provide `session.client()` overloads. Add explicit annotations if you use it.\n\n### Type Checker\n\n```bash\npython -m pip install mypy\npython -m mypy app.py\n```\n\n`pyright` also works with the generated stubs.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-cleanrooms` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nAWS Clean Rooms requests still depend on normal AWS credentials and region resolution. Typical local setup is either:\n\n```bash\naws configure\n```\n\nor environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_DEFAULT_REGION=us-east-1\nexport AWS_PROFILE=dev\n```\n\nCreate a normal boto3 session, then annotate the client:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\nsession = Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\ncleanrooms: CleanRoomsServiceClient = session.client(\"cleanrooms\")\n```\n\nIf your project keeps stubs as a development-only dependency, gate the import with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\ndef make_cleanrooms_client() -> \"CleanRoomsServiceClient\":\n    return boto3.Session(region_name=\"us-east-1\").client(\"cleanrooms\")\n```\n\n## Core Usage\n\n### Typed client for membership lookups\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\nsession = Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\ncleanrooms: CleanRoomsServiceClient = session.client(\"cleanrooms\")\n\nresponse = cleanrooms.get_membership(\n    membershipIdentifier=os.environ[\"CLEANROOMS_MEMBERSHIP_ID\"],\n)\n\nmembership = response[\"membership\"]\nprint(membership[\"membershipIdentifier\"])\nprint(membership[\"queryLogStatus\"])\n```\n\n### Paginate memberships\n\nUse the generated paginator type when listing memberships across multiple pages.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\nfrom mypy_boto3_cleanrooms.paginator import ListMembershipsPaginator\n\ncleanrooms: CleanRoomsServiceClient = Session(region_name=\"us-east-1\").client(\"cleanrooms\")\n\npaginator: ListMembershipsPaginator = cleanrooms.get_paginator(\"list_memberships\")\n\nfor page in paginator.paginate():\n    for membership in page.get(\"membershipSummaries\", []):\n        print(membership[\"membershipIdentifier\"], membership[\"status\"])\n```\n\n### Create a membership\n\nAWS documents `create_membership` as the API for joining an existing collaboration. The request includes the collaboration identifier and the query log setting.\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\ncleanrooms: CleanRoomsServiceClient = Session(region_name=\"us-east-1\").client(\"cleanrooms\")\n\nresponse = cleanrooms.create_membership(\n    collaborationIdentifier=os.environ[\"CLEANROOMS_COLLABORATION_ID\"],\n    queryLogStatus=\"ENABLED\",\n)\n\nmembership_id = response[\"membership\"][\"membershipIdentifier\"]\nprint(membership_id)\n```\n\n### Inspect configured tables\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\ncleanrooms: CleanRoomsServiceClient = Session(region_name=\"us-east-1\").client(\"cleanrooms\")\n\nresponse = cleanrooms.list_configured_tables()\n\nfor table in response.get(\"configuredTableSummaries\", []):\n    print(table[\"id\"], table[\"name\"])\n```\n\n## Exceptions And Error Handling\n\nThe generated client exposes typed service exceptions. Use them for the expected Clean Rooms failure modes, then fall back to `ClientError` for generic AWS handling.\n\n```python\nfrom boto3.session import Session\nfrom botocore.exceptions import ClientError\nfrom mypy_boto3_cleanrooms import CleanRoomsServiceClient\n\ncleanrooms: CleanRoomsServiceClient = Session(region_name=\"us-east-1\").client(\"cleanrooms\")\n\ntry:\n    cleanrooms.get_membership(membershipIdentifier=\"missing-membership-id\")\nexcept cleanrooms.exceptions.ResourceNotFoundException:\n    print(\"Membership not found\")\nexcept cleanrooms.exceptions.AccessDeniedException:\n    print(\"Missing Clean Rooms permissions\")\nexcept ClientError as err:\n    print(err.response[\"Error\"][\"Code\"])\n    raise\n```\n\n## What Upstream Modules Cover\n\nThe published maintainer docs for this package center on these import areas:\n\n- `mypy_boto3_cleanrooms` for the top-level `CleanRoomsServiceClient` export\n- `mypy_boto3_cleanrooms.paginator` for paginator types such as `ListMembershipsPaginator`\n- `mypy_boto3_cleanrooms.type_defs` for generated request and response `TypedDict`s\n- `mypy_boto3_cleanrooms.literals` for constrained literal values used by the service model\n\nThat is the practical surface to plan around for agent-written code.\n\n## Common Pitfalls\n\n- `mypy-boto3-cleanrooms` is not the runtime SDK. You still need `boto3`.\n- The install name uses dashes, but the import name uses underscores: `mypy-boto3-cleanrooms` vs `mypy_boto3_cleanrooms`.\n- Installing only the standalone package does not give you the same `Session.client(\"cleanrooms\")` overload experience as `boto3-stubs[cleanrooms]`.\n- `boto3-stubs-lite[cleanrooms]` is easier on IDE memory, but you should expect to annotate the client explicitly.\n- Successful type checking does not prove your AWS profile, region, or IAM permissions are correct.\n- The published typing surface is client-focused. Plan around typed clients and paginators rather than expecting resource-style helpers.\n\n## Version-Sensitive Notes\n\n- This entry is keyed to `1.42.52`.\n- The maintainer documents these packages as matching the related `boto3` version, so pinning `boto3` and `mypy-boto3-cleanrooms` to the same release family is the safest default.\n- If your project relies on automatic `session.client(\"cleanrooms\")` inference, prefer `boto3-stubs[cleanrooms]`. Use the standalone package when you want the narrowest service-specific dependency.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cleanrooms/\n- PyPI project: https://pypi.org/project/mypy-boto3-cleanrooms/\n- AWS boto3 Clean Rooms reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cleanrooms.html\n- AWS `get_membership` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cleanrooms/client/get_membership.html\n- AWS `create_membership` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cleanrooms/client/create_membership.html\n- AWS boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- AWS boto3 configuration guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cloudformation/python/DOC.md",
    "content": "---\nname: mypy-boto3-cloudformation\ndescription: \"mypy-boto3-cloudformation typed stubs for boto3 CloudFormation clients, resources, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,boto3,cloudformation,mypy,pyright,pylance,types,stubs\"\n---\n\n# mypy-boto3-cloudformation Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cloudformation` provides generated type stubs for the CloudFormation parts of `boto3`.\n\nUse it when you want:\n\n- typed `Session.client(\"cloudformation\")` or explicit `CloudFormationClient` annotations\n- typed `Session.resource(\"cloudformation\")` resource access\n- typed paginator and waiter objects\n- CloudFormation literal unions and `TypedDict` request/response shapes\n- better autocomplete and static checking in mypy, pyright, Pylance, and PyCharm\n\nIt does not make AWS calls by itself. Runtime behavior still comes from `boto3`.\n\n## Install\n\nPreferred install modes:\n\n```bash\npython -m pip install \"boto3-stubs[cloudformation]\"\n```\n\nUse this when you want the best editor and type-checker experience. The upstream docs show this as the standard install path for typed service support.\n\nIf the full stubs package is too heavy for your IDE, use the lite variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[cloudformation]\"\n```\n\nIf you want only the standalone CloudFormation stubs package:\n\n```bash\npython -m pip install mypy-boto3-cloudformation\n```\n\nYou still need the runtime SDK:\n\n```bash\npython -m pip install boto3\n```\n\nPractical rule:\n\n- use `boto3-stubs[cloudformation]` for automatic `Session.client(...)` and `Session.resource(...)` typing\n- use `boto3-stubs-lite[cloudformation]` if IDE performance matters more than overload convenience\n- use `mypy-boto3-cloudformation` when you want explicit CloudFormation type imports without the full bundle\n\n## Setup And AWS Auth\n\nThis package does not handle credentials. `boto3` still uses the normal AWS credential chain.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr create the session explicitly:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n```\n\nCredential resolution still comes from:\n\n- explicit credentials passed to `Session(...)`\n- environment variables\n- `~/.aws/credentials` and `~/.aws/config`\n- IAM roles or workload identity in AWS environments\n\n## Core Usage\n\n### Typed CloudFormation Client\n\nUse the standalone type when you want an explicit annotation:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudformation import CloudFormationClient\n\nsession = Session(region_name=\"us-east-1\")\ncloudformation: CloudFormationClient = session.client(\"cloudformation\")\n\nresponse = cloudformation.describe_stacks(StackName=\"example-stack\")\nfor stack in response.get(\"Stacks\", []):\n    print(stack[\"StackName\"], stack[\"StackStatus\"])\n```\n\n### Typed CloudFormation Resource\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudformation import CloudFormationServiceResource\n\nsession = Session(region_name=\"us-east-1\")\ncf: CloudFormationServiceResource = session.resource(\"cloudformation\")\n\nfor stack in cf.stacks.all():\n    print(stack.stack_name)\n```\n\n### Typed Paginators And Waiters\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudformation.paginator import ListStacksPaginator\nfrom mypy_boto3_cloudformation.waiter import StackCreateCompleteWaiter\n\nsession = Session(region_name=\"us-east-1\")\ncloudformation = session.client(\"cloudformation\")\n\npaginator: ListStacksPaginator = cloudformation.get_paginator(\"list_stacks\")\nfor page in paginator.paginate(\n    StackStatusFilter=[\"CREATE_COMPLETE\", \"UPDATE_COMPLETE\"],\n):\n    for summary in page.get(\"StackSummaries\", []):\n        print(summary[\"StackName\"])\n\nwaiter: StackCreateCompleteWaiter = cloudformation.get_waiter(\n    \"stack_create_complete\"\n)\nwaiter.wait(StackName=\"example-stack\")\n```\n\n### Literals And TypedDicts\n\nUse the generated literal aliases and type definitions in helper code:\n\n```python\nfrom mypy_boto3_cloudformation.literals import AccountFilterTypeType\nfrom mypy_boto3_cloudformation.type_defs import AccountGateResultTypeDef\n\ndef summarize_gate(\n    filter_type: AccountFilterTypeType,\n    result: AccountGateResultTypeDef,\n) -> str:\n    return f\"{filter_type}: {result.get('Status')}\"\n```\n\n### `TYPE_CHECKING` Pattern\n\nThis keeps explicit stub imports out of runtime-only paths when you prefer string annotations:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_cloudformation import CloudFormationClient\n\nsession = Session(region_name=\"us-east-1\")\ncloudformation: \"CloudFormationClient\" = session.client(\"cloudformation\")\n```\n\n## Common Pitfalls\n\n- These are typing stubs, not the AWS SDK itself. Install and use `boto3` for runtime calls.\n- The service name must be `\"cloudformation\"`. Typos here break both runtime creation and type inference.\n- `boto3-stubs-lite[cloudformation]` does not provide the same `Session.client(...)` and `Session.resource(...)` overload convenience as the full `boto3-stubs` extra. Use explicit annotations with the lite package.\n- Responses are still plain Python dictionaries at runtime. The stubs improve editor and checker accuracy, but they do not validate live AWS responses.\n- CloudFormation unions and `TypedDict` shapes can be large. If your IDE slows down, switch from the full bundle to the lite package or annotate only the surfaces you actually use.\n- Pylint can complain about generated imports or aliases. The PyPI page documents a `TYPE_CHECKING` pattern specifically for this case.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here and current PyPI release: `1.42.3`.\n- The PyPI page states that the package version should match the related `boto3` version.\n- The package docs site is a generated reference site and may show examples for newer builder inputs than the published standalone wheel. As of March 12, 2026, the docs site includes a local-generation example against `boto3==1.42.66`.\n- Treat the docs root as the authoritative feature map for available client/resource/paginator/waiter/type exports, but verify the exact published package version on PyPI before pinning a lockfile or CI constraint.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cloudformation/\n- PyPI package page: https://pypi.org/project/mypy-boto3-cloudformation/\n- Upstream repository: https://github.com/youtype/mypy_boto3_builder\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cloudfront/python/DOC.md",
    "content": "---\nname: mypy-boto3-cloudfront\ndescription: \"mypy-boto3-cloudfront type stubs for boto3 CloudFront clients, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.40\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,cloudfront,mypy,pyright,type-stubs,python\"\n---\n\n# mypy-boto3-cloudfront Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cloudfront` is the generated type-stubs package for the CloudFront part of `boto3`.\n\nUse it when you want:\n\n- typed `Session.client(\"cloudfront\")`\n- typed paginator and waiter objects\n- generated `Literal` unions for CloudFront string enums\n- generated `TypedDict` request and response shapes\n\nIt does not make runtime AWS calls by itself. Install and use `boto3` for actual CloudFront operations.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[cloudfront]'\n```\n\nThis is the upstream default when you want type inference for normal `boto3` code without adding explicit annotations everywhere.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[cloudfront]'\n```\n\nUse the lite package if your IDE struggles with the full stubs. The official package notes that the lite variant is more RAM-friendly, but it does not provide `session.client()` or `session.resource()` overloads, so explicit annotations become important.\n\n### Standalone CloudFront stubs\n\n```bash\npython -m pip install boto3 mypy-boto3-cloudfront\n```\n\nUse this when you want only the CloudFront stubs package and are comfortable importing concrete types from `mypy_boto3_cloudfront`.\n\n### Local generation for exact boto3 parity\n\nIf your project pins a specific boto3 patch and exact type parity matters, upstream recommends local generation:\n\n```bash\nuvx --with 'boto3==1.42.40' mypy-boto3-builder\n```\n\nThen select `boto3-stubs` and the `CloudFront` service.\n\n## Authentication And Setup\n\n`mypy-boto3-cloudfront` has no package-specific auth or config. Credentials, region selection, retries, and endpoints all come from normal `boto3` configuration.\n\nAWS says boto3 searches for credentials in a standard order that includes explicit client or session parameters, environment variables, shared credential files, config files, and runtime providers such as container or EC2 metadata.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nExplicit session setup is the clearest pattern for agents and reviewers:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudfront.client import CloudFrontClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ncloudfront: CloudFrontClient = session.client(\"cloudfront\")\n```\n\nCloudFront is globally scoped, but keeping `region_name=\"us-east-1\"` explicit avoids ambiguous environment-dependent behavior in local tooling and CI.\n\nDo not hard-code access keys in source. Use profiles, environment variables, or workload credentials.\n\n## Core Usage\n\n### Typed client annotation\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudfront.client import CloudFrontClient\n\ncloudfront: CloudFrontClient = Session(region_name=\"us-east-1\").client(\n    \"cloudfront\"\n)\n\nresponse = cloudfront.get_distribution(Id=\"EDFDVBD6EXAMPLE\")\nstatus = response[\"Distribution\"][\"Status\"]\nprint(status)\n```\n\nAWS documents clients as the low-level interface whose methods map closely to service APIs and support all service operations. For CloudFront code, prefer typed clients over generic `BaseClient`.\n\n### Typed paginator usage\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudfront.client import CloudFrontClient\nfrom mypy_boto3_cloudfront.paginator import ListDistributionsPaginator\n\nclient: CloudFrontClient = Session(region_name=\"us-east-1\").client(\"cloudfront\")\npaginator: ListDistributionsPaginator = client.get_paginator(\"list_distributions\")\n\nfor page in paginator.paginate():\n    for item in page.get(\"DistributionList\", {}).get(\"Items\", []):\n        print(item[\"Id\"], item[\"DomainName\"])\n```\n\nThe package also publishes paginator types for newer CloudFront operations such as connection functions, trust stores, and distribution tenants. Use the generated paginator class that matches the operation name instead of hand-rolled marker loops.\n\n### Typed waiter usage\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudfront.client import CloudFrontClient\nfrom mypy_boto3_cloudfront.waiter import InvalidationCompletedWaiter\n\nclient: CloudFrontClient = Session(region_name=\"us-east-1\").client(\"cloudfront\")\nwaiter: InvalidationCompletedWaiter = client.get_waiter(\"invalidation_completed\")\n\nwaiter.wait(\n    DistributionId=\"EDFDVBD6EXAMPLE\",\n    Id=\"I1JLWSDAP8FU89\",\n)\n```\n\nThe published waiters include `distribution_deployed`, `invalidation_completed`, `invalidation_for_distribution_tenant_completed`, and `streaming_distribution_deployed`.\n\n### Literals and TypedDicts\n\n```python\nfrom mypy_boto3_cloudfront.literals import CachePolicyCookieBehaviorType\nfrom mypy_boto3_cloudfront.type_defs import AliasICPRecordalTypeDef\n\ncookie_behavior: CachePolicyCookieBehaviorType = \"allExcept\"\n\nrecordal: AliasICPRecordalTypeDef = {\n    \"CNAME\": \"cdn.example.com\",\n}\n```\n\nUse `literals` when an argument accepts a fixed string set, and use `type_defs` when you want stronger checking for request or response shapes.\n\n## Type-Checking Patterns\n\n### `TYPE_CHECKING` imports\n\nIf stubs are available only in development or CI, keep them out of runtime imports:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_cloudfront.client import CloudFrontClient\nelse:\n    CloudFrontClient = object\n\ndef make_client() -> \"CloudFrontClient\":\n    return Session(region_name=\"us-east-1\").client(\"cloudfront\")\n```\n\nThis is also the upstream workaround for `pylint` complaints about typing-only imports.\n\n### Prefer clients over resources\n\nAWS documents that resources are a higher-level interface, but the boto3 team does not plan to add new features to the resources interface. If you need newer CloudFront operations, type the client surface first.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-cloudfront` and forgetting `boto3`. The stubs package is `Typing :: Stubs Only`.\n- Expecting `boto3-stubs-lite[cloudfront]` to infer `Session().client(\"cloudfront\")` automatically. Add explicit `CloudFrontClient` annotations in lite mode.\n- Passing around a generic botocore client type and losing CloudFront-specific method signatures, paginator types, and waiter types.\n- Treating `TypedDict` coverage as runtime validation. Boto3 responses are still normal dictionaries, and missing keys are still possible.\n- Hard-coding credentials in code examples or app code. AWS explicitly recommends against that pattern.\n- Assuming older blog posts cover the current CloudFront API surface. The generated stubs for `1.42.40` include recent paginator and waiter names that older examples may not mention.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.40`.\n- On 2026-03-12, the official PyPI page, release history, and maintainer docs all aligned on `mypy-boto3-cloudfront 1.42.40`, released on `2026-02-02`.\n- The package description says its version matches the related `boto3` version. If your application is already on a later boto3 patch than `1.42.40`, verify the published stub version before pinning.\n- The official boto3 credentials, clients, and resources guides currently resolve to newer boto3 docs (`1.42.66` on 2026-03-12). Use those pages for runtime behavior guidance, but keep the stub package version pinned separately.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cloudfront/\n- Client docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cloudfront/client/\n- PyPI package page: https://pypi.org/project/mypy-boto3-cloudfront/\n- Upstream repository: https://github.com/youtype/mypy_boto3_builder\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 clients guide: https://docs.aws.amazon.com/boto3/latest/guide/clients.html\n- Boto3 resources guide: https://docs.aws.amazon.com/boto3/latest/guide/resources.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cloudwatch/python/DOC.md",
    "content": "---\nname: mypy-boto3-cloudwatch\ndescription: \"mypy-boto3-cloudwatch type stubs for typed boto3 CloudWatch clients, paginators, waiters, resources, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.56\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,cloudwatch,mypy,pyright,type-stubs,python\"\n---\n\n# mypy-boto3-cloudwatch Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cloudwatch` is the maintainer-generated type stub package for the CloudWatch part of `boto3`.\n\nUse it when you want:\n\n- a typed `CloudWatchClient` for `Session.client(\"cloudwatch\")`\n- typed paginator and waiter objects\n- typed CloudWatch resource objects and collections\n- generated `Literal` unions for CloudWatch string enums\n- generated `TypedDict` request and response shapes under `type_defs`\n\nIt does not replace `boto3`, sign AWS requests, or load credentials by itself.\n\n## Install\n\nKeep `boto3` installed in the same environment as the stubs.\n\n### Recommended for most projects\n\nUse the full stub package when you want automatic `Session.client(\"cloudwatch\")` inference:\n\n```bash\npython -m pip install boto3 \"boto3-stubs[cloudwatch]\"\n```\n\n### Standalone CloudWatch stubs\n\nUse this when you only need the CloudWatch typing package and are fine with explicit annotations:\n\n```bash\npython -m pip install boto3 mypy-boto3-cloudwatch\n```\n\n### Lower-memory IDE fallback\n\nThe lite package is more memory-friendly, but upstream documents that it does not provide `session.client()` or `session.resource()` overloads:\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[cloudwatch]\"\n```\n\n### Exact-match local generation\n\nThe maintainer docs recommend local generation when exact parity with your pinned boto3 version matters:\n\n```bash\nuvx --with \"boto3==1.42.56\" mypy-boto3-builder\n```\n\nThen select `boto3-stubs` and the `CloudWatch` service.\n\n## Authentication And Setup\n\nAWS documents the main credential lookup order as:\n\n1. explicit credentials passed to `boto3.client(...)`\n2. explicit credentials passed to `boto3.Session(...)`\n3. environment variables\n4. assume-role providers\n5. shared credentials and config files\n6. container and EC2 metadata providers\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nExplicit session setup keeps typing and runtime configuration clear:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.client import CloudWatchClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ncloudwatch: CloudWatchClient = session.client(\"cloudwatch\")\n```\n\n`Session` also accepts explicit credentials, but do not hardcode access keys in source code. Prefer profiles, environment variables, IAM Identity Center, or runtime IAM roles.\n\n## Core Usage\n\n### Typed client annotation\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.client import CloudWatchClient\n\ncloudwatch: CloudWatchClient = Session(region_name=\"us-east-1\").client(\n    \"cloudwatch\"\n)\n\nalarms = cloudwatch.describe_alarms(AlarmNames=[\"high-error-rate\"])\nprint(alarms[\"MetricAlarms\"])\n```\n\nAWS documents clients as the low-level interface whose methods map closely to service APIs. Prefer typed clients for new code.\n\n### Typed request shapes for `put_metric_data`\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.client import CloudWatchClient\nfrom mypy_boto3_cloudwatch.literals import StandardUnitType\nfrom mypy_boto3_cloudwatch.type_defs import MetricDatumTypeDef, PutMetricDataInputTypeDef\n\ncloudwatch: CloudWatchClient = Session(region_name=\"us-east-1\").client(\"cloudwatch\")\n\nunit: StandardUnitType = \"Count\"\n\ndatum: MetricDatumTypeDef = {\n    \"MetricName\": \"JobsProcessed\",\n    \"Dimensions\": [{\"Name\": \"Service\", \"Value\": \"billing-worker\"}],\n    \"Unit\": unit,\n    \"Value\": 1.0,\n}\n\npayload: PutMetricDataInputTypeDef = {\n    \"Namespace\": \"MyApp/Workers\",\n    \"MetricData\": [datum],\n}\n\ncloudwatch.put_metric_data(**payload)\n```\n\n`MetricDatumTypeDef` and `PutMetricDataInputTypeDef` are useful when you want type checking for nested CloudWatch request dictionaries instead of passing untyped dict literals around.\n\n### Typed paginator usage\n\nCloudWatch has generated paginator types for operations including `describe_alarm_history`, `describe_alarms`, `describe_anomaly_detectors`, `get_metric_data`, `list_alarm_mute_rules`, `list_dashboards`, and `list_metrics`.\n\n```python\nfrom datetime import UTC, datetime, timedelta\n\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.client import CloudWatchClient\nfrom mypy_boto3_cloudwatch.paginator import GetMetricDataPaginator\nfrom mypy_boto3_cloudwatch.type_defs import MetricDataQueryTypeDef\n\ncloudwatch: CloudWatchClient = Session(region_name=\"us-east-1\").client(\"cloudwatch\")\n\nquery: MetricDataQueryTypeDef = {\n    \"Id\": \"cpu\",\n    \"MetricStat\": {\n        \"Metric\": {\n            \"Namespace\": \"AWS/EC2\",\n            \"MetricName\": \"CPUUtilization\",\n            \"Dimensions\": [{\"Name\": \"InstanceId\", \"Value\": \"i-0123456789abcdef0\"}],\n        },\n        \"Period\": 300,\n        \"Stat\": \"Average\",\n    },\n    \"ReturnData\": True,\n}\n\npaginator: GetMetricDataPaginator = cloudwatch.get_paginator(\"get_metric_data\")\n\nfor page in paginator.paginate(\n    MetricDataQueries=[query],\n    StartTime=datetime.now(UTC) - timedelta(hours=1),\n    EndTime=datetime.now(UTC),\n):\n    for result in page[\"MetricDataResults\"]:\n        print(result[\"Id\"], result.get(\"Values\", []))\n```\n\n### Typed waiter usage\n\nThe maintainer docs publish waiter types for `alarm_exists`, `alarm_mute_rule_exists`, and `composite_alarm_exists`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.client import CloudWatchClient\nfrom mypy_boto3_cloudwatch.waiter import AlarmExistsWaiter\n\ncloudwatch: CloudWatchClient = Session(region_name=\"us-east-1\").client(\"cloudwatch\")\nwaiter: AlarmExistsWaiter = cloudwatch.get_waiter(\"alarm_exists\")\n\nwaiter.wait(\n    AlarmNames=[\"high-error-rate\"],\n    WaiterConfig={\"Delay\": 10, \"MaxAttempts\": 12},\n)\n```\n\n### Typed resources\n\nCloudWatch still has typed resource classes and collections, but AWS documents the resource interface as feature-frozen. Use resources when you already depend on them; prefer clients for new features.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cloudwatch.service_resource import (\n    Alarm,\n    CloudWatchServiceResource,\n    ServiceResourceMetricsCollection,\n)\n\nresource: CloudWatchServiceResource = Session(region_name=\"us-east-1\").resource(\n    \"cloudwatch\"\n)\n\nalarm: Alarm = resource.Alarm(\"high-error-rate\")\nmetrics: ServiceResourceMetricsCollection = resource.metrics\n\nprint(alarm.name)\nprint(metrics)\n```\n\n## Type-Checking Patterns\n\n### `TYPE_CHECKING` imports for dev-only stubs\n\nIf production images do not install stub packages, keep the imports behind `TYPE_CHECKING` so runtime imports stay clean:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_cloudwatch.client import CloudWatchClient\nelse:\n    CloudWatchClient = object\n\ndef make_client() -> \"CloudWatchClient\":\n    return Session(region_name=\"us-east-1\").client(\"cloudwatch\")\n```\n\nThis is also the upstream workaround for `pylint` complaints about typing-only imports.\n\n### Use literals when an API accepts a fixed string set\n\n```python\nfrom mypy_boto3_cloudwatch.literals import StandardUnitType\n\nunit: StandardUnitType = \"Percent\"\n```\n\nLiteral aliases help catch invalid enum-like strings before runtime.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-cloudwatch` without `boto3`. PyPI classifies this package as `Typing :: Stubs Only`.\n- Using `boto3-stubs-lite[cloudwatch]` and expecting overload-based inference from `Session.client(\"cloudwatch\")`. Add explicit annotations in lite mode.\n- Treating `TypedDict` coverage as runtime validation. Boto3 responses are still normal dictionaries and AWS can still omit optional keys.\n- Debugging auth or region issues inside the stub package. Fix the `boto3.Session(...)` setup first.\n- Preferring resources by default. AWS explicitly says newer features should be accessed through the client interface.\n- Assuming the docs site, PyPI wheel, and AWS `latest` docs are always on the same boto3 patch. They drift.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.56`.\n- On March 12, 2026, PyPI lists `mypy-boto3-cloudwatch 1.42.56`, released on `2026-02-24`, and describes it as generated with `mypy-boto3-builder 8.12.0`.\n- On the same date, the maintainer docs root for this package shows local-generation commands against `boto3==1.42.66`, so the docs site is useful for current type surfaces but not an exact wheel-version pin source.\n- On the same date, AWS `docs.aws.amazon.com/boto3/latest/...` pages resolve to mixed boto3 patch numbers such as `1.42.51`, `1.42.52`, and `1.42.54`. Use AWS docs for runtime behavior and service semantics, but use PyPI for exact package pinning.\n- If your application pins a different boto3 or botocore patch and you need exact typing parity, upstream recommends local generation instead of assuming the published wheel matches your lockfile exactly.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cloudwatch/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-cloudwatch/`\n- Upstream builder repository: `https://github.com/youtype/mypy_boto3_builder`\n- Boto3 CloudWatch reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/cloudwatch.html`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 session reference: `https://docs.aws.amazon.com/boto3/latest/reference/core/session.html`\n- Boto3 clients guide: `https://docs.aws.amazon.com/boto3/latest/guide/clients.html`\n- Boto3 resources guide: `https://docs.aws.amazon.com/boto3/latest/guide/resources.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-codebuild/python/DOC.md",
    "content": "---\nname: mypy-boto3-codebuild\ndescription: \"mypy-boto3-codebuild Python package guide for typed AWS CodeBuild boto3 clients\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,aws,codebuild,boto3,typing,mypy,stub\"\n---\n\n# mypy-boto3-codebuild Python Package Guide\n\n## What This Package Is\n\n`mypy-boto3-codebuild` is the generated type-stub package for the AWS CodeBuild client in `boto3`. It improves static analysis and autocomplete for CodeBuild operations, paginators, literals, and TypedDict request or response shapes.\n\nIt is not a runtime SDK. You still install and use `boto3` to talk to AWS.\n\n## Installation\n\nInstall the runtime SDK plus the split CodeBuild stubs:\n\n```bash\npython -m pip install \"boto3>=1.42,<1.43\" \"mypy-boto3-codebuild==1.42.3\"\n```\n\nIf your project already uses the bundled stubs package, the equivalent extra is:\n\n```bash\npython -m pip install \"boto3-stubs[codebuild]==1.42.3\"\n```\n\nUse one stub strategy per project. Mixing the split package and the bundled extras usually adds noise without adding capability.\n\n## Initialize A Typed CodeBuild Client\n\nWith the split service package, explicitly annotate the client variable:\n\n```python\nimport boto3\nfrom mypy_boto3_codebuild.client import CodeBuildClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\ncodebuild: CodeBuildClient = session.client(\"codebuild\")\n\nprojects = codebuild.list_projects()\nprint(projects[\"projects\"])\n```\n\nThe annotation matters. `boto3.client(\"codebuild\")` still returns a normal boto3 client at runtime, but the stub type gives editors and type checkers the generated CodeBuild method signatures.\n\nIf you keep stubs in a dev-only dependency group, guard the import:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_codebuild.client import CodeBuildClient\n\ncodebuild: \"CodeBuildClient\" = boto3.client(\"codebuild\", region_name=\"us-east-1\")\n```\n\n## Core Imports\n\n```python\nfrom mypy_boto3_codebuild.client import CodeBuildClient\nfrom mypy_boto3_codebuild.paginator import ListBuildsForProjectPaginator\nfrom mypy_boto3_codebuild.type_defs import StartBuildInputTypeDef\n```\n\nUse these modules for the common cases:\n\n- `client` for the typed service client\n- `paginator` for typed paginator classes\n- `type_defs` for request and response TypedDicts\n\n## Core Usage\n\n### Call normal CodeBuild APIs with typed responses\n\n```python\nimport boto3\nfrom mypy_boto3_codebuild.client import CodeBuildClient\n\ncodebuild: CodeBuildClient = boto3.client(\"codebuild\", region_name=\"us-east-1\")\n\nresponse = codebuild.batch_get_projects(names=[\"my-project\"])\nfor project in response[\"projects\"]:\n    print(project[\"name\"], project.get(\"serviceRole\"))\n```\n\n### Build request payloads with TypedDicts\n\n```python\nimport boto3\nfrom mypy_boto3_codebuild.client import CodeBuildClient\nfrom mypy_boto3_codebuild.type_defs import StartBuildInputTypeDef\n\ncodebuild: CodeBuildClient = boto3.client(\"codebuild\", region_name=\"us-east-1\")\n\nrequest: StartBuildInputTypeDef = {\n    \"projectName\": \"my-project\",\n    \"environmentVariablesOverride\": [\n        {\"name\": \"APP_ENV\", \"value\": \"ci\", \"type\": \"PLAINTEXT\"},\n    ],\n}\n\nresponse = codebuild.start_build(**request)\nprint(response[\"build\"][\"id\"])\n```\n\n### Use typed paginators for repeated listing\n\n```python\nimport boto3\nfrom mypy_boto3_codebuild.client import CodeBuildClient\nfrom mypy_boto3_codebuild.paginator import ListBuildsForProjectPaginator\n\ncodebuild: CodeBuildClient = boto3.client(\"codebuild\", region_name=\"us-east-1\")\npaginator: ListBuildsForProjectPaginator = codebuild.get_paginator(\"list_builds_for_project\")\n\nfor page in paginator.paginate(projectName=\"my-project\", sortOrder=\"DESCENDING\"):\n    for build_id in page[\"ids\"]:\n        print(build_id)\n```\n\n## Authentication And Configuration\n\n`mypy-boto3-codebuild` adds no authentication behavior. Credential loading and region resolution are exactly the same as `boto3`.\n\nUse the normal boto3 credential chain:\n\n- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optional `AWS_SESSION_TOKEN`\n- shared AWS config and credentials files\n- named profiles such as `profile_name=\"dev\"`\n- IAM roles in EC2, ECS, Lambda, or other AWS runtimes\n\nExample:\n\n```python\nimport boto3\nfrom mypy_boto3_codebuild.client import CodeBuildClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\ncodebuild: CodeBuildClient = session.client(\"codebuild\")\n```\n\nFor agents, the practical rule is simple: solve auth and region setup exactly as you would for any other boto3 client, then layer the CodeBuild typing imports on top.\n\n## Version-Sensitive Notes\n\n### Use the version used here for this entry\n\nThis repo entry is intentionally pinned to `mypy-boto3-codebuild==1.42.3`, because that is the version used here for this package session.\n\n### The docs site currently shows newer generated examples\n\nThe maintainer docs root for `mypy_boto3_codebuild` currently shows install snippets for newer generated boto3-stubs builds than the target version. Treat the docs site as the canonical API-shape reference, but treat the pinned PyPI package version as authoritative for this entry.\n\nIf you copy snippets from the docs site, re-pin them to `1.42.3` for this package doc and verify the matching boto3 family you actually install.\n\n### Keep boto3, botocore, and the stubs in the same release family\n\nThese stubs are generated from boto3 and botocore service models. If your installed `boto3` or `botocore` drifts too far from the stub version, type hints can advertise request fields or response members that do not match runtime behavior.\n\nFor `1.42.3`, prefer a `boto3` and `botocore` version from the same `1.42.x` family when possible.\n\n## Common Pitfalls\n\n### Treating the package as a runtime dependency only\n\n`mypy-boto3-codebuild` does not create clients, sign requests, or make AWS API calls. Runtime behavior still comes from `boto3`.\n\n### Expecting `boto3.client(\"codebuild\")` to become fully typed by itself\n\nWith the split service package, you usually need an explicit `CodeBuildClient` annotation on the variable returned by `boto3.client(...)` or `Session.client(...)`.\n\n### Forgetting to install the stubs where imports are evaluated\n\nIf code imports `mypy_boto3_codebuild` at runtime but the package is only installed in a dev environment, production imports will fail. Use a `TYPE_CHECKING` guard if the stubs are not part of the runtime environment.\n\n### Copying mismatched versions from the docs site\n\nThe docs site is generated from the broader project and can show newer version pins than the PyPI package version covered here.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_codebuild/\n- PyPI project: https://pypi.org/project/mypy-boto3-codebuild/\n- Upstream repository: https://github.com/youtype/mypy_boto3_builder\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-codepipeline/python/DOC.md",
    "content": "---\nname: mypy-boto3-codepipeline\ndescription: \"mypy-boto3-codepipeline package guide for typed boto3 CodePipeline clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,codepipeline,boto3,mypy,pyright,stubs,typing,python,cicd\"\n---\n\n# mypy-boto3-codepipeline Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS calls and use `mypy-boto3-codepipeline` only for typing. If you want `Session.client(\"codepipeline\")` to infer automatically, install `boto3-stubs[codepipeline]`. If you install only `mypy-boto3-codepipeline` or `boto3-stubs-lite[codepipeline]`, plan to add explicit type annotations.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matches the official PyPI release and the maintainer docs checked on `2026-03-12`.\n- The maintainer project states that `mypy-boto3-codepipeline` uses the same version as the related `boto3` release. Keep the stub package close to your installed `boto3` line so signatures and response shapes do not drift.\n- The maintainer docs page is a stable package URL, not a release-pinned docs snapshot. Pin the package version in your environment when exact patch parity matters.\n- The PyPI package page shows this release was generated with `mypy-boto3-builder 8.12.0`. If you need exact parity with a locally pinned boto3 build, the maintainer recommends generating stubs locally with `mypy-boto3-builder`.\n- AWS runtime docs for CodePipeline are on a rolling latest-docs line, so use PyPI as the source of truth for the exact stub package version and AWS docs for runtime behavior.\n\n## Install\n\nChoose one install mode based on whether you want automatic type inference or smaller typing dependencies.\n\n### Best inference: full boto3 stubs\n\nUse this when you want `Session.client(\"codepipeline\")` to infer without extra annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[codepipeline]==1.42.3\"\n```\n\n### Lower-memory option\n\nUse this when editor performance matters more than overload-based inference:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[codepipeline]==1.42.3\"\n```\n\nThe maintainer docs say the lite package does not provide `session.client/resource` overloads, so explicit annotations become the normal workflow.\n\n### Standalone package\n\nUse this when you want only the CodePipeline typing package:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-codepipeline==1.42.3\"\n```\n\n### Generate locally when exact parity matters\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\nThen select `boto3-stubs` and the `CodePipeline` service.\n\n## Initialization And Setup\n\n`mypy-boto3-codepipeline` does not add credentials, retries, or endpoint behavior. Runtime configuration still comes from `boto3` and `botocore`.\n\nUseful AWS credential and config facts for typed CodePipeline clients:\n\n- Boto3 checks credentials in the normal provider chain, including explicit client/session credentials, environment variables, assume-role providers, IAM Identity Center, shared credentials files, config files, container credentials, and EC2 instance metadata.\n- Use `AWS_PROFILE` or `boto3.Session(profile_name=...)` for local development instead of hardcoding keys.\n- Set region explicitly in code or via `AWS_DEFAULT_REGION` because CodePipeline is regional.\n- Retry and transport behavior still come from boto3 config such as `AWS_RETRY_MODE`, `AWS_MAX_ATTEMPTS`, or `botocore.config.Config(...)`.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\nexport AWS_RETRY_MODE=standard\nexport AWS_MAX_ATTEMPTS=10\n```\n\nThen create the real boto3 client:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig = Config(retries={\"mode\": \"standard\", \"max_attempts\": 10})\ncodepipeline = session.client(\"codepipeline\", config=config)\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[codepipeline]`\n\nWith the full extra installed, ordinary boto3 code should type-check without explicit annotations:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient = session.client(\"codepipeline\")\n\nstate = client.get_pipeline_state(name=\"MyPipeline\")\n\nfor stage in state.get(\"stageStates\", []):\n    latest = stage.get(\"latestExecution\") or {}\n    print(stage[\"stageName\"], latest.get(\"status\"))\n```\n\n### Explicit client annotations\n\nUse explicit annotations when you installed the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_codepipeline import CodePipelineClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: CodePipelineClient = session.client(\"codepipeline\")\n\nresponse = client.start_pipeline_execution(name=\"MyPipeline\")\nprint(response[\"pipelineExecutionId\"])\n```\n\n### Typed paginators\n\nThe maintainer docs expose typed paginators for operations such as `list_action_executions`, `list_pipeline_executions`, `list_rule_executions`, and `list_webhooks`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_codepipeline import CodePipelineClient\nfrom mypy_boto3_codepipeline.paginator import ListPipelineExecutionsPaginator\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: CodePipelineClient = session.client(\"codepipeline\")\n\npaginator: ListPipelineExecutionsPaginator = client.get_paginator(\n    \"list_pipeline_executions\"\n)\n\nfor page in paginator.paginate(pipelineName=\"MyPipeline\"):\n    for execution in page.get(\"pipelineExecutionSummaries\", []):\n        print(execution[\"pipelineExecutionId\"], execution[\"status\"])\n```\n\n### Literals and typed request fragments\n\nUse generated literals and `TypedDict` shapes in helpers that construct CodePipeline request data:\n\n```python\nfrom mypy_boto3_codepipeline.literals import ActionCategoryType\nfrom mypy_boto3_codepipeline.type_defs import AWSSessionCredentialsTypeDef\n\ncategory: ActionCategoryType = \"Build\"\n\ncreds: AWSSessionCredentialsTypeDef = {\n    \"accessKeyId\": \"AKIA...\",\n    \"secretAccessKey\": \"secret\",\n    \"sessionToken\": \"token\",\n}\n```\n\nGenerated `type_defs` are useful when your code assembles request/response fragments before the actual boto3 call.\n\n### Runtime-safe `TYPE_CHECKING` pattern\n\nIf production installs omit stub packages, keep the imports type-only:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_codepipeline import CodePipelineClient\nelse:\n    CodePipelineClient = object\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: \"CodePipelineClient\" = session.client(\"codepipeline\")\n```\n\nThis matches the maintainer guidance for avoiding runtime stub dependencies and also avoids the `pylint` undefined-name issue.\n\n## CodePipeline-Specific Notes\n\n- The boto3 service name is `codepipeline`, not `mypy-boto3-codepipeline`.\n- CodePipeline is regional. A client pointed at the wrong region will not see the pipeline you expect.\n- Typed helpers are most useful around client methods the AWS docs highlight for operational workflows: `get_pipeline_state`, `list_pipeline_executions`, `list_action_executions`, `list_rule_executions`, `start_pipeline_execution`, `retry_stage_execution`, and `stop_pipeline_execution`.\n- The AWS service reference lists paginator support for `ListActionExecutions`, `ListActionTypes`, `ListDeployActionExecutionTargets`, `ListPipelineExecutions`, `ListPipelines`, `ListRuleExecutions`, `ListTagsForResource`, and `ListWebhooks`.\n- These stubs improve editor help and static checking, but they do not validate that your pipeline name, IAM permissions, or deployment state are correct at runtime.\n\n## Common Pitfalls\n\n- `mypy-boto3-codepipeline` is stub-only. It does not replace `boto3` and does not create a runtime client by itself.\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_codepipeline`.\n- `boto3-stubs[codepipeline]` gives the best inference experience. `boto3-stubs-lite[codepipeline]` and standalone installs usually require explicit `CodePipelineClient` annotations.\n- Keep the stub version aligned with the installed `boto3` line. Type hints can silently drift even when runtime code still works.\n- Do not hardcode AWS credentials in application code. Prefer profiles, IAM Identity Center, assume-role config, container credentials, or instance/task roles.\n- PyCharm can be slow on large `Literal` overloads. The maintainer docs recommend the lite variant if editor performance becomes a problem.\n- Stubs only describe shapes. They will not catch wrong region selection, missing IAM permissions, or pipeline names that do not exist.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_codepipeline/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-codepipeline/`\n- Maintainer repository: `https://github.com/youtype/types-boto3`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- AWS CodePipeline boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/codepipeline.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cognito-identity/python/DOC.md",
    "content": "---\nname: mypy-boto3-cognito-identity\ndescription: \"mypy-boto3-cognito-identity package guide for typed boto3 Cognito Identity clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,cognito,cognito-identity,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-cognito-identity Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cognito-identity` is the maintainer-generated type stub package for the Cognito Identity part of `boto3`.\n\nUse it when you want:\n\n- a typed `CognitoIdentityClient`\n- paginator annotations such as `ListIdentityPoolsPaginator`\n- generated literal unions from the Cognito Identity service model\n- generated `TypedDict` request and response shapes under `type_defs`\n\nThis package is `Typing :: Stubs Only`. It does not create AWS sessions, sign requests, or fetch credentials. Real API calls still come from `boto3`.\n\n## Golden Rule\n\n- Install `boto3-stubs[cognito-identity]` when you want the best automatic type inference for `Session().client(\"cognito-identity\")`.\n- Install `mypy-boto3-cognito-identity` when you only need the Cognito Identity stub package and are willing to annotate the client explicitly.\n- Keep runtime AWS setup in normal `boto3` configuration. The stubs package does not change auth, region, retry, or endpoint behavior.\n\n## Install\n\nPick one mode and keep `boto3` installed in the environment.\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[cognito-identity]==1.42.3\"\n```\n\nUse this when you want `Session.client(\"cognito-identity\")` overloads and the least manual annotation work.\n\n### Service-only stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-cognito-identity==1.42.3\"\n```\n\nUse this when you only want the Cognito Identity stub package.\n\n### Lite package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[cognito-identity]==1.42.3\"\n```\n\nThe maintainer docs note that the lite package is more RAM-friendly, but it does not provide the same `session.client(...)` overloads. Add explicit annotations when you choose this option.\n\n### Exact-match local generation\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\nUse this when your lockfile must match a specific `boto3` line exactly and you do not want to rely on the latest published stub wheel.\n\n## Initialize And Setup\n\nCreate the real client with `boto3`, then add the generated client type:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_identity.client import CognitoIdentityClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ncognito: CognitoIdentityClient = session.client(\"cognito-identity\")\n```\n\nPractical setup choices for local development:\n\n- `profile_name` plus `~/.aws/config` and `~/.aws/credentials`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_DEFAULT_REGION`\n- role-based credentials in ECS, EKS, Lambda, or EC2\n\nThe boto3 credentials guide says boto3 searches for credentials in a fixed order including explicit client parameters, session parameters, environment variables, assume-role providers, IAM Identity Center, shared credential files, shared config files, container credentials, and EC2 instance metadata.\n\n## Core Usage\n\n### Typed client calls\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_identity.client import CognitoIdentityClient\n\nsession = Session(region_name=\"us-east-1\")\ncognito: CognitoIdentityClient = session.client(\"cognito-identity\")\n\nresponse = cognito.list_identity_pools(MaxResults=10)\n\nfor pool in response.get(\"IdentityPools\", []):\n    print(pool[\"IdentityPoolName\"], pool[\"IdentityPoolId\"])\n```\n\n### `TYPE_CHECKING` pattern\n\nUse this when stubs are installed only in development or CI:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_cognito_identity.client import CognitoIdentityClient\nelse:\n    CognitoIdentityClient = object\n\ncognito: CognitoIdentityClient = boto3.client(\"cognito-identity\", region_name=\"us-east-1\")\n```\n\n### Typed request and response shapes\n\nThe maintainer docs expose request and response aliases such as `GetIdInputTypeDef`, `GetIdResponseTypeDef`, `GetCredentialsForIdentityInputTypeDef`, and `GetCredentialsForIdentityResponseTypeDef`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_identity.client import CognitoIdentityClient\nfrom mypy_boto3_cognito_identity.type_defs import (\n    GetCredentialsForIdentityInputTypeDef,\n    GetCredentialsForIdentityResponseTypeDef,\n    GetIdInputTypeDef,\n    GetIdResponseTypeDef,\n)\n\nsession = Session(region_name=\"us-east-1\")\ncognito: CognitoIdentityClient = session.client(\"cognito-identity\")\n\nlogins = {\n    \"cognito-idp.us-east-1.amazonaws.com/us-east-1_example\": \"USER_POOL_JWT\",\n}\n\nget_id_request: GetIdInputTypeDef = {\n    \"IdentityPoolId\": \"us-east-1:11111111-2222-3333-4444-555555555555\",\n    \"Logins\": logins,\n}\n\nidentity: GetIdResponseTypeDef = cognito.get_id(**get_id_request)\n\ncredentials_request: GetCredentialsForIdentityInputTypeDef = {\n    \"IdentityId\": identity[\"IdentityId\"],\n    \"Logins\": logins,\n}\n\ncredentials: GetCredentialsForIdentityResponseTypeDef = (\n    cognito.get_credentials_for_identity(**credentials_request)\n)\n\nprint(credentials[\"Credentials\"][\"AccessKeyId\"])\n```\n\n### Typed paginator\n\nThe boto3 Cognito Identity reference shows one paginator for this service: `ListIdentityPools`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_identity.client import CognitoIdentityClient\nfrom mypy_boto3_cognito_identity.paginator import ListIdentityPoolsPaginator\n\nsession = Session(region_name=\"us-east-1\")\ncognito: CognitoIdentityClient = session.client(\"cognito-identity\")\n\npaginator: ListIdentityPoolsPaginator = cognito.get_paginator(\"list_identity_pools\")\n\nfor page in paginator.paginate(MaxResults=60):\n    for pool in page.get(\"IdentityPools\", []):\n        print(pool[\"IdentityPoolId\"])\n```\n\n### Literals and service-name-safe annotations\n\n```python\nfrom mypy_boto3_cognito_identity.literals import (\n    AmbiguousRoleResolutionTypeType,\n    CognitoIdentityServiceName,\n)\n\nresolution: AmbiguousRoleResolutionTypeType = \"AuthenticatedRole\"\nservice_name: CognitoIdentityServiceName = \"cognito-identity\"\n```\n\n## Configuration And Authentication\n\n`mypy-boto3-cognito-identity` adds no package-specific auth layer. All configuration still comes from `boto3` and AWS.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr create a session explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_identity.client import CognitoIdentityClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ncognito: CognitoIdentityClient = session.client(\"cognito-identity\")\n```\n\nImportant Cognito Identity detail:\n\n- AWS credentials authorize the caller to use the Cognito Identity API.\n- The `Logins` map is separate from AWS credentials and carries end-user identity-provider tokens.\n- The client region should match the target identity pool region.\n\nIf code type-checks but calls fail, debug `boto3` credentials, region, IAM policy, or token inputs rather than the stubs package.\n\n## Common Pitfalls\n\n- Installing stubs without `boto3`. These packages add typing only.\n- Using the wrong service name. `\"cognito-identity\"` and `\"cognito-idp\"` are different services and different stub packages.\n- Expecting automatic inference from `mypy-boto3-cognito-identity` or `boto3-stubs-lite[cognito-identity]`. Use explicit `CognitoIdentityClient` annotations in those modes.\n- Treating `Logins` as AWS access keys. They are identity-provider tokens used in Cognito Identity flows.\n- Assuming the docs root is a frozen per-release snapshot. It is a generated latest-style page, so verify symbols against the installed version when a new alias matters to shared code.\n- Expecting extra typed helpers by analogy with other AWS services. The official docs for this package focus on the client, paginator, literals, and `TypedDict` definitions.\n\n## Version-Sensitive Notes\n\n- This guide is pinned to the version used here `1.42.3`.\n- The official PyPI project page shows `mypy-boto3-cognito-identity 1.42.3`, generated with `mypy-boto3-builder 8.12.0`, published on `2025-12-04`.\n- The official PyPI page also shows Python requirement `>=3.9`.\n- The maintainer docs and PyPI project page both state that package versioning follows the related `boto3` version.\n- If runtime `boto3` is newer than the installed stubs, newly added operations, paginator names, literals, or `TypeDef` fields can be missing from type checking even when runtime code still executes.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cognito_identity/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-cognito-identity/`\n- AWS boto3 Cognito Identity reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/cognito-identity.html`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-cognito-idp/python/DOC.md",
    "content": "---\nname: mypy-boto3-cognito-idp\ndescription: \"mypy-boto3-cognito-idp typed boto3 stubs for Cognito Identity Provider clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.59\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,cognito,cognito-idp,python,typing,stubs,mypy\"\n---\n\n# mypy-boto3-cognito-idp Python Package Guide\n\n## What It Is\n\n`mypy-boto3-cognito-idp` adds static typing for the Cognito Identity Provider part of `boto3`.\n\nUse it when you want type checking and editor completion for:\n\n- `Session.client(\"cognito-idp\")` as `CognitoIdentityProviderClient`\n- generated paginator types such as `ListUserPoolsPaginator`\n- generated `Literal` aliases such as `AuthFlowTypeType`\n- generated `TypedDict` request and response shapes such as `AdminGetUserResponseTypeDef`\n\nThis package does not replace `boto3` at runtime. Real AWS calls still go through normal `boto3` clients and normal AWS credentials.\n\n## Version Note\n\nThis entry is pinned to the version used here `1.42.59`, and the official PyPI package page for `mypy-boto3-cognito-idp` also reported `1.42.59` on March 12, 2026.\n\nThe upstream versioning guide says these packages follow the related `boto3` version. Keep your stub package and runtime `boto3` dependency on the same release family whenever possible.\n\n## Install\n\nInstall the runtime SDK plus the service-specific stubs:\n\n```bash\npython -m pip install \"boto3==1.42.59\" \"mypy-boto3-cognito-idp==1.42.59\"\n```\n\nIf your team standardizes on the umbrella stubs package, the official docs also support:\n\n```bash\npython -m pip install \"boto3-stubs[cognito-idp]==1.42.59\"\n```\n\nIf editor memory usage matters more than automatic `Session.client(...)` inference, the upstream docs also list the lighter variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[cognito-idp]==1.42.59\"\n```\n\n`boto3-stubs-lite` keeps the generated Cognito IDP types, but the official docs note that it does not provide the same `session.client(...)` and `session.resource(...)` overloads as full `boto3-stubs`.\n\n## Initialization And Setup\n\nKeep setup boring: configure AWS auth and region the same way you would for any other boto3 client, then annotate the returned client with the generated type.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_idp import CognitoIdentityProviderClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\ncognito: CognitoIdentityProviderClient = session.client(\"cognito-idp\")\n```\n\nIf the stub package is only installed in development, guard typing-only imports:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_cognito_idp import CognitoIdentityProviderClient\n\ndef get_cognito_client() -> \"CognitoIdentityProviderClient\":\n    return Session(region_name=\"us-west-2\").client(\"cognito-idp\")\n```\n\n## Config And Authentication\n\n`mypy-boto3-cognito-idp` does not add any auth helpers. Credential lookup and region resolution still come from `boto3` and `botocore`.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nUse the same patterns you already trust for boto3:\n\n- shared AWS config and credentials files\n- environment variables such as `AWS_PROFILE` and `AWS_DEFAULT_REGION`\n- IAM roles or assumed roles in deployed environments\n- explicit `Session(...)` configuration when you need to override defaults\n\nCognito IDP is regional. Make sure the client region matches the user pool region before you debug request shapes or permissions.\n\n## Core Usage\n\n### Typed Cognito IDP Client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_idp import CognitoIdentityProviderClient\n\ncognito: CognitoIdentityProviderClient = Session(\n    region_name=\"us-west-2\",\n).client(\"cognito-idp\")\n\npool = cognito.describe_user_pool(UserPoolId=\"us-west-2_example\")[\"UserPool\"]\nprint(pool[\"Id\"], pool[\"Name\"])\n```\n\n### Typed Response Shapes\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_idp import CognitoIdentityProviderClient\nfrom mypy_boto3_cognito_idp.type_defs import AdminGetUserResponseTypeDef\n\ncognito: CognitoIdentityProviderClient = Session(\n    region_name=\"us-west-2\",\n).client(\"cognito-idp\")\n\nresponse: AdminGetUserResponseTypeDef = cognito.admin_get_user(\n    UserPoolId=\"us-west-2_example\",\n    Username=\"alice@example.com\",\n)\n\nfor attribute in response.get(\"UserAttributes\", []):\n    print(attribute[\"Name\"], attribute.get(\"Value\"))\n```\n\n### Typed Paginators\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_cognito_idp import CognitoIdentityProviderClient\nfrom mypy_boto3_cognito_idp.paginator import ListUserPoolsPaginator\n\ncognito: CognitoIdentityProviderClient = Session(\n    region_name=\"us-west-2\",\n).client(\"cognito-idp\")\n\npaginator: ListUserPoolsPaginator = cognito.get_paginator(\"list_user_pools\")\n\nfor page in paginator.paginate(MaxResults=60):\n    for pool in page.get(\"UserPools\", []):\n        print(pool[\"Id\"], pool[\"Name\"])\n```\n\n### Literals For Safer Enum-Like Values\n\n```python\nfrom mypy_boto3_cognito_idp.literals import AuthFlowTypeType\n\nauth_flow: AuthFlowTypeType = \"USER_PASSWORD_AUTH\"\n```\n\nImport literal aliases when you want the type checker to reject unsupported Cognito string values before runtime.\n\n## IDE And Type Checker Notes\n\nThe official package page explicitly calls out support for:\n\n- `mypy`\n- `pyright`\n- PyCharm\n- VSCode with Pylance\n\nInstall the stubs into the same environment that your editor or CI type checker analyzes. If your editor struggles with large overload sets, the upstream docs suggest trying `boto3-stubs-lite`.\n\n## Common Pitfalls\n\n### PyPI Name, Import Name, And Service Name Differ\n\n- install: `mypy-boto3-cognito-idp`\n- import: `mypy_boto3_cognito_idp`\n- runtime service name: `\"cognito-idp\"`\n\nDo not substitute one for another.\n\n### These Are Stubs, Not A Runtime SDK\n\nKeep importing and executing `boto3`. The stubs only improve static analysis and autocomplete.\n\n### `boto3-stubs-lite` Needs More Explicit Annotations\n\nIf you choose `boto3-stubs-lite[cognito-idp]`, expect to annotate client variables manually because the full session overloads are intentionally omitted upstream.\n\n### Keep Versions Aligned\n\nThese types are generated from the boto3 service model. If `boto3`, `botocore`, and `mypy-boto3-cognito-idp` drift too far apart, method signatures and `TypedDict` fields can stop matching what your runtime client actually supports.\n\n### Treat `TYPE_CHECKING` As The Safe Default For Dev-Only Stubs\n\nIf production images do not install stub packages, keep imports for annotation-only names behind `TYPE_CHECKING` so runtime imports stay clean.\n\n### Do Not Expect A Separate Cognito Resource Interface Here\n\nThe official package docs for `mypy-boto3-cognito-idp` expose client, paginator, literal, and `type_defs` sections. Use typed clients as the default workflow.\n\n## Version-Sensitive Notes\n\n- Official sources checked on March 12, 2026 matched the version used here `1.42.59`.\n- The official PyPI page lists `Requires: Python >=3.9`.\n- The generated docs root is stable across releases rather than release-specific. When exact parity matters, verify the installed package version on PyPI and pin the dependency explicitly.\n\n## Official Sources\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_cognito_idp/`\n- Versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-cognito-idp/`\n- Maintainer repository linked from PyPI: `https://github.com/youtype/mypy_boto3_builder`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-comprehend/python/DOC.md",
    "content": "---\nname: mypy-boto3-comprehend\ndescription: \"Typed boto3 stubs for Amazon Comprehend clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,comprehend,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-comprehend Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-comprehend` is a stubs-only package for static typing of `boto3` Comprehend code. It does not send requests, load credentials, or replace the runtime SDK.\n\nUse one of these install modes:\n\n- `boto3-stubs[comprehend]` for the best editor experience with automatic `Session.client(\"comprehend\")` overloads\n- `mypy-boto3-comprehend` when you want only the Comprehend stubs and are willing to annotate clients and paginators explicitly\n- `boto3-stubs-lite[comprehend]` when IDE memory use matters more than automatic overload inference\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[comprehend]==1.42.3\"\n```\n\nThis is the simplest path when you want `Session().client(\"comprehend\")` to infer `ComprehendClient` automatically in editors and type checkers.\n\n### Standalone Comprehend stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-comprehend==1.42.3\"\n```\n\nUse this when you want only the Comprehend typing package. In this mode, explicit type annotations are usually necessary.\n\n### Lower-memory editor fallback\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[comprehend]==1.42.3\"\n```\n\nThe lite package is more memory-friendly, but the maintainer docs say it does not provide `session.client()` overloads. Expect to annotate types explicitly.\n\n### Generate locally for an exact boto3 pin\n\n```bash\nuvx --with 'boto3==1.42.3' mypy-boto3-builder\n```\n\nThis is useful when your project is pinned to a boto3 version and you want generated stubs that match that runtime release line as closely as possible.\n\n## Runtime Setup And AWS Auth\n\n`mypy-boto3-comprehend` has no package-specific initialization. All runtime behavior still comes from `boto3` and botocore.\n\nUse the normal AWS credential chain and prefer an explicit session when the region or profile is not obvious:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nclient = session.client(\"comprehend\")\n```\n\nCommon configuration sources:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- shared config in `~/.aws/config` and `~/.aws/credentials`\n- assume-role, IAM Identity Center, container, or instance metadata providers\n\nPractical rule: keep credentials and retry config on the boto3 session or client. The stub package only improves static typing.\n\n## Core Usage\n\n### Typed client with automatic overloads\n\nWith `boto3-stubs[comprehend]`, standard boto3 client creation should infer the correct type:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-east-1\")\nclient = session.client(\"comprehend\")\n\nresponse = client.detect_sentiment(\n    Text=\"The delivery was fast and the packaging was excellent.\",\n    LanguageCode=\"en\",\n)\n\nprint(response[\"Sentiment\"])\n```\n\n### Explicit client annotation\n\nUse explicit annotations when you installed the standalone or lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_comprehend.client import ComprehendClient\n\nclient: ComprehendClient = Session(region_name=\"us-east-1\").client(\"comprehend\")\n\nresponse = client.contains_pii_entities(\n    Text=\"Contact me at jane@example.com\",\n    LanguageCode=\"en\",\n)\n\nprint(response[\"Labels\"])\n```\n\n### Typed paginator\n\nComprehend exposes typed paginator overloads for list operations such as `list_endpoints`, `list_entities_detection_jobs`, and `list_sentiment_detection_jobs`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_comprehend.client import ComprehendClient\nfrom mypy_boto3_comprehend.paginator import ListEntitiesDetectionJobsPaginator\n\nclient: ComprehendClient = Session(region_name=\"us-east-1\").client(\"comprehend\")\npaginator: ListEntitiesDetectionJobsPaginator = client.get_paginator(\n    \"list_entities_detection_jobs\"\n)\n\nfor page in paginator.paginate(PaginationConfig={\"MaxItems\": 25}):\n    for props in page.get(\"EntitiesDetectionJobPropertiesList\", []):\n        print(props[\"JobId\"], props[\"JobStatus\"])\n```\n\n### Typed request and response fragments\n\n`type_defs` are useful when wrapper code builds request dictionaries before calling the client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_comprehend.client import ComprehendClient\nfrom mypy_boto3_comprehend.type_defs import ContainsPiiEntitiesRequestTypeDef\n\nclient: ComprehendClient = Session(region_name=\"us-east-1\").client(\"comprehend\")\n\nrequest: ContainsPiiEntitiesRequestTypeDef = {\n    \"Text\": \"Call me at 206-555-0100\",\n    \"LanguageCode\": \"en\",\n}\n\nresponse = client.contains_pii_entities(**request)\nprint(response[\"Labels\"])\n```\n\n### Literal-constrained values\n\nThe generated literals help when helpers should only accept valid enum-like values:\n\n```python\nfrom mypy_boto3_comprehend.literals import LanguageCodeType\n\ndef normalize_language(value: LanguageCodeType) -> LanguageCodeType:\n    return value\n```\n\n### `TYPE_CHECKING` pattern for dev-only stubs\n\nIf production images do not install stub packages, keep the imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_comprehend.client import ComprehendClient\nelse:\n    ComprehendClient = object\n\nclient: \"ComprehendClient\" = Session(region_name=\"us-east-1\").client(\"comprehend\")\n```\n\nThe `object` fallback avoids runtime import failures and the common pylint undefined-name issue that the maintainer docs call out.\n\n## Configuration Notes\n\n- Amazon Comprehend is regional. Set `region_name` explicitly when the execution environment is not already pinned to the correct region.\n- Comprehend request parameters still follow the AWS service API. The stubs help you catch missing or misspelled fields, but they do not validate IAM permissions, model availability, or regional service support.\n- Batch and async job APIs often require S3 input and output locations plus IAM roles. Those runtime requirements come from AWS service behavior, not from the stub package.\n- The generated `client.exceptions` surface is typed for editor completion, but the actual exception classes still come from the runtime boto3 client.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-comprehend` and expecting unannotated `Session.client(\"comprehend\")` calls to become typed automatically. That overload behavior comes from `boto3-stubs[comprehend]`.\n- Forgetting to install `boto3`. The stub package does not ship the runtime AWS client.\n- Treating static typing as runtime validation. Correct type hints do not guarantee that the selected region supports the model, that the IAM role has permission, or that S3 input and output locations are valid.\n- Hardcoding AWS credentials in application code. Keep auth in profiles, environment variables, IAM Identity Center, or runtime IAM roles.\n- Mixing unrelated AWS SDK families. `mypy-boto3-comprehend` is for synchronous `boto3`; if your code uses `aiobotocore`, use the matching `types-aiobotocore-comprehend` family instead.\n- Assuming the maintainer docs are an exact frozen patch snapshot. They are a generated rolling docs site; use PyPI as the exact release source for frontmatter and pins.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-comprehend 1.42.3` as the current release on March 12, 2026, and the version used here matches this package release.\n- The package description says it provides type annotations for `boto3 Comprehend 1.42.3`, so the practical default is to keep `boto3==1.42.3` and the stub package on the same release line.\n- The package was generated with `mypy-boto3-builder 8.12.0`, which matters when comparing older examples or generated symbol names.\n- The maintainer docs and AWS boto3 reference are rolling documentation sources. When exact patch compatibility matters, trust PyPI for the published package version and use the docs for API shape and usage patterns.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_comprehend/`\n- Maintainer client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_comprehend/client/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-comprehend/`\n- PyPI JSON metadata: `https://pypi.org/pypi/mypy-boto3-comprehend/json`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 Comprehend reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/comprehend.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-config/python/DOC.md",
    "content": "---\nname: mypy-boto3-config\ndescription: \"mypy-boto3-config type stubs for typed boto3 AWS Config clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.32\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,config,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-config Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-config` is only the typing layer for AWS Config. Keep `boto3` installed for runtime calls, create the real client with `Session().client(\"config\")`, and handle credentials, region, retries, and endpoints through normal boto3 and AWS configuration.\n\nFor new AWS Config code, prefer the client interface over boto3 resources. AWS documents clients as the low-level interface that supports all service operations, and boto3 resources are feature-frozen.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 \"boto3-stubs[config]\"\n```\n\nThis is the simplest path when you want normal boto3 runtime behavior plus automatic type inference for `Session.client(\"config\")` in editors and type checkers.\n\n### Standalone service stubs\n\n```bash\npython -m pip install boto3 \"mypy-boto3-config==1.42.32\"\n```\n\nUse this when you only want the Config service stub package. In this setup, explicit client annotations are usually the clearest option.\n\n### Lower-memory editor fallback\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[config]\"\n```\n\nUpstream notes that the lite package does not provide `session.client()` and `session.resource()` overloads, so expect to annotate clients explicitly.\n\n### Generate for an exact boto3 line\n\nIf your project is pinned to a different boto3 patch line and you want locally generated matching stubs:\n\n```bash\nuvx --with \"boto3==1.42.32\" mypy-boto3-builder\n```\n\n## Authentication And Setup\n\nThis package does not add its own configuration surface. boto3 still resolves credentials and region through the normal AWS provider chain.\n\nThe boto3 credentials guide says boto3 searches, in order:\n\n1. Credentials passed directly to `boto3.client(...)`\n2. Credentials passed when creating a `Session`\n3. Environment variables\n4. Role-based and other AWS providers later in the chain\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create an explicitly typed client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_config.client import ConfigServiceClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig_client: ConfigServiceClient = session.client(\"config\")\n```\n\n## Core Usage\n\n### Typed AWS Config client\n\n`ConfigServiceClient` is the main type to use for `boto3.client(\"config\")`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_config.client import ConfigServiceClient\n\nclient: ConfigServiceClient = Session(region_name=\"us-east-1\").client(\"config\")\n\nresponse = client.describe_config_rules(ConfigRuleNames=[\"required-tags\"])\n\nfor rule in response.get(\"ConfigRules\", []):\n    print(rule[\"ConfigRuleName\"], rule[\"ConfigRuleState\"])\n```\n\n### Typed paginator\n\nThe generated stubs include paginator types such as `ListConfigurationRecordersPaginator` and `GetComplianceDetailsByResourcePaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_config.client import ConfigServiceClient\nfrom mypy_boto3_config.paginator import ListConfigurationRecordersPaginator\n\nclient: ConfigServiceClient = Session(region_name=\"us-east-1\").client(\"config\")\npaginator: ListConfigurationRecordersPaginator = client.get_paginator(\n    \"list_configuration_recorders\"\n)\n\nfor page in paginator.paginate():\n    for recorder in page.get(\"ConfigurationRecorders\", []):\n        print(recorder[\"name\"], recorder[\"roleARN\"])\n```\n\n### `TYPE_CHECKING` and `cast(...)` pattern\n\nUse this when stubs are installed only in development or CI:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_config.client import ConfigServiceClient\n\nsession = boto3.Session(region_name=\"us-east-1\")\nclient = cast(\"ConfigServiceClient\", session.client(\"config\"))\n```\n\nThis keeps runtime imports clean while preserving static typing.\n\n### Literals and `type_defs`\n\nUse generated literal unions and `TypedDict` shapes when helper code builds request objects or validates response structure before the boto3 call site.\n\n```python\nfrom mypy_boto3_config.literals import ComplianceTypeType\nfrom mypy_boto3_config.type_defs import ConfigRuleTypeDef\n\ndesired_compliance: ComplianceTypeType = \"COMPLIANT\"\n\nrule: ConfigRuleTypeDef = {\n    \"ConfigRuleName\": \"required-tags\",\n    \"Source\": {\n        \"Owner\": \"AWS\",\n        \"SourceIdentifier\": \"REQUIRED_TAGS\",\n    },\n}\n```\n\nThe generated docs currently list Config-specific shapes such as `ConfigurationRecorderTypeDef`, `ConfigRuleTypeDef`, and `SelectResourceConfigResponseTypeDef`.\n\n## Practical Notes For Agents\n\n- Use the boto3 service name string `config`, not `configservice`, when constructing the runtime client.\n- Treat this package as typing-only. Successful type checking does not prove that AWS Config is enabled, a recorder exists, or the caller has the right IAM permissions.\n- The AWS Config service reference exposes many read and write operations, including `describe_config_rules`, `get_compliance_details_by_resource`, `put_config_rule`, and `put_configuration_recorder`. Prefer read-only calls in diagnostics and automation unless the task explicitly requires mutation.\n- If you already install `boto3-stubs[config]`, many IDEs can infer the client type without explicit annotations. Keep explicit annotations in reusable helpers and libraries where clarity matters more than editor magic.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-config` without `boto3` and expecting runtime AWS calls to work.\n- Importing the package with hyphens in Python code. The import root is `mypy_boto3_config`.\n- Expecting automatic `Session.client(\"config\")` inference when you installed only `mypy-boto3-config` or `boto3-stubs-lite[config]`.\n- Treating generated `TypedDict` definitions as runtime validation. boto3 still returns ordinary dictionaries.\n- Assuming the stubs package changes authentication, region resolution, retry behavior, or endpoints. Those all remain boto3 concerns.\n- Using boto3 resources for new Config code. AWS says new boto3 features land on clients, not resources.\n- Letting `boto3`, `botocore`, and the stubs drift too far apart. Runtime calls may still work while your typings become stale.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.32`.\n- On 2026-03-12, PyPI lists `mypy-boto3-config 1.42.32`, marks it as `Stubs Only`, and says it was generated with `mypy-boto3-builder 8.12.0`.\n- PyPI also says `mypy-boto3-config` follows the related `boto3` version, so matching the stub version to the boto3 line is the safest default.\n- The maintainer docs site is a rolling generated build. On 2026-03-12, its local-generation example already showed `boto3==1.42.62` even though PyPI for this package still published `1.42.32`. Use PyPI for exact release pinning and use the docs site for import names and generated module layout.\n- The current generated docs surface client, paginator, literal, and `type_defs` modules for Config. They do not present a boto3 resource entry point for this service, which fits AWS guidance to prefer clients.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_config/`\n- Maintainer client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_config/client/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-config/`\n- PyPI release JSON: `https://pypi.org/pypi/mypy-boto3-config/1.42.32/json`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 clients guide: `https://docs.aws.amazon.com/boto3/latest/guide/clients.html`\n- AWS boto3 resources guide: `https://docs.aws.amazon.com/boto3/latest/guide/resources.html`\n- AWS Config boto3 service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/config.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-connect/python/DOC.md",
    "content": "---\nname: mypy-boto3-connect\ndescription: \"Type stubs for boto3 Amazon Connect clients, paginators, literals, and TypedDict shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.63\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,connect,boto3,python,typing,mypy,pyright,stubs\"\n---\n\n# mypy-boto3-connect Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-connect` is a typing package for `boto3` Amazon Connect code, not a runtime SDK. Keep `boto3` installed, authenticate exactly as you would for normal AWS code, and use the stub package to type your Connect client and paginator usage so `mypy` or `pyright` can catch operation-name and shape mistakes before runtime.\n\nUse one of these install patterns:\n\n- `boto3-stubs[connect]` for the best automatic typing on `Session().client(\"connect\")`\n- `mypy-boto3-connect` when you want the service-specific package and explicit annotations\n- `boto3-stubs-lite[connect]` when IDE performance matters more than automatic overloads\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.63`, which matches the current PyPI release page on March 12, 2026.\n- The maintainer docs are a rolling latest site. Use PyPI for exact release pinning and use the docs site for package structure, import names, and install-mode guidance.\n- The maintainer versioning guide says stub package versions follow the related `boto3` version, so pin `boto3`, `botocore`, and the stub package to the same release line when exact generated signatures matter.\n- `boto3-stubs-lite` does not provide the overloaded `Session.client()` helper types. In lite mode, annotate the Connect client explicitly after creation.\n\n## Install\n\n### Recommended: full boto3 overloads\n\nThis is the simplest setup when your code constructs Connect clients directly from `boto3.Session`.\n\n```bash\npython -m pip install \"boto3==1.42.63\" \"boto3-stubs[connect]==1.42.63\"\n```\n\n### Service-specific stub package\n\nUse this when you want the Connect-only package and do not mind explicit annotations.\n\n```bash\npython -m pip install \"boto3==1.42.63\" \"mypy-boto3-connect==1.42.63\"\n```\n\n### Lite variant\n\nUse this when the full overload set is too heavy for your editor or type checker.\n\n```bash\npython -m pip install \"boto3==1.42.63\" \"boto3-stubs-lite[connect]==1.42.63\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.63\" \"mypy-boto3-connect==1.42.63\"\npoetry add \"boto3==1.42.63\" \"mypy-boto3-connect==1.42.63\"\n```\n\n## Authentication And Setup\n\nThis package does not change how AWS authentication or client configuration works. Use the normal boto3 credential chain:\n\n1. Shared AWS config and credentials files plus `AWS_PROFILE` for local development\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. IAM roles, IAM Identity Center, or other runtime AWS credential providers in deployed environments\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create a normal typed client:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_connect.client import ConnectClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n\nconfig = Config(\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n)\n\nclient: ConnectClient = session.client(\"connect\", config=config)\n```\n\nAmazon Connect resources are regional and many operations require an `InstanceId`, so keep the client region aligned with the Connect instance region you are targeting.\n\n## Core Usage\n\n### Type the Connect client explicitly\n\nThis is the most reliable pattern when you install the service-specific stub package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_connect.client import ConnectClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: ConnectClient = session.client(\"connect\")\n\nresponse = client.describe_user(\n    InstanceId=\"your-connect-instance-id\",\n    UserId=\"your-user-id\",\n)\n\nprint(response[\"User\"][\"Username\"])\n```\n\n### Type paginators for list operations\n\nThe generated package includes paginator classes for Connect list APIs such as `list_users`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_connect.client import ConnectClient\nfrom mypy_boto3_connect.paginator import ListUsersPaginator\n\nclient: ConnectClient = Session(region_name=\"us-east-1\").client(\"connect\")\npaginator: ListUsersPaginator = client.get_paginator(\"list_users\")\n\nfor page in paginator.paginate(InstanceId=\"your-connect-instance-id\"):\n    for user in page.get(\"UserSummaryList\", []):\n        print(user[\"Username\"])\n```\n\n### Use `TYPE_CHECKING` when stubs are dev-only\n\nIf production environments omit typing dependencies, keep the stub import out of runtime execution:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_connect.client import ConnectClient\n\ndef get_connect_client() -> \"ConnectClient\":\n    return boto3.client(\"connect\", region_name=\"us-east-1\")\n```\n\n### Use generated `type_defs` and literals in helper layers\n\nThe package also exposes generated `TypedDict` request and response shapes plus `Literal` aliases. Use them when you wrap Connect calls behind helper functions, build request dictionaries incrementally, or want enum-like string parameters checked statically instead of treated as plain `str`.\n\n## Configuration Notes\n\n- Set `region_name` deliberately. Connect instances and many related resources are regional, and a mismatched region often looks like a not-found or access issue.\n- Prefer `boto3.Session(...)` when you need predictable profile or region selection in local tooling.\n- Use `botocore.config.Config` for retries, timeouts, proxies, and endpoint options. This stub package does not replace `botocore` runtime configuration.\n- Keep `boto3`, `botocore`, and the stub package on the same version line in your lockfile to avoid stale method signatures or missing generated types.\n- Treat the generated docs as current-package structure, but validate exact runtime behavior against AWS Connect API docs when request/response details matter.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-connect` without `boto3`. The stub package does not make AWS API calls on its own.\n- Using `\"mypy-boto3-connect\"` as the boto3 service name. The runtime service name is still `\"connect\"`.\n- Expecting `boto3-stubs-lite[connect]` to infer `Session.client(\"connect\")` overloads automatically.\n- Importing stub modules at runtime in environments where only production dependencies are installed. Use `TYPE_CHECKING` or install the package wherever those imports execute.\n- Forgetting the required `InstanceId` parameter on many Connect operations.\n- Pointing the client at the wrong AWS region for the target Connect instance.\n- Copying examples from generic boto3 guides without checking the generated Connect stub names for the version you actually installed.\n\n## Official Source URLs Used\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_connect/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI release: `https://pypi.org/project/mypy-boto3-connect/1.42.63/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-connect/`\n- Umbrella package release: `https://pypi.org/project/boto3-stubs/1.42.63/`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- Boto3 Connect client reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/connect.html`\n- Boto3 Connect paginator reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/connect/paginator/ListUsers.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-datasync/python/DOC.md",
    "content": "---\nname: mypy-boto3-datasync\ndescription: \"mypy-boto3-datasync package guide for typed boto3 AWS DataSync clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,datasync,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-datasync Python Package Guide\n\n## Golden Rule\n\n- Keep `boto3` as the runtime AWS SDK. `mypy-boto3-datasync` is a typing-only companion for DataSync code.\n- Prefer `boto3-stubs[datasync]` when you want `Session.client(\"datasync\")` inference with less annotation work.\n- Use standalone `mypy-boto3-datasync` when you only want DataSync stubs and are willing to annotate the client explicitly.\n- Treat PyPI as the source of truth for the exact published stub version. The maintainer docs site is a rolling latest view.\n\n## Install\n\nService-specific stubs only:\n\n```bash\npython -m pip install \"boto3==1.42.9\" \"mypy-boto3-datasync==1.42.9\"\n```\n\nBundled boto3 stubs with automatic `Session.client(\"datasync\")` overloads:\n\n```bash\npython -m pip install \"boto3-stubs[datasync]\"\n```\n\nLower-memory bundled variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[datasync]\"\n```\n\nNotes:\n\n- `boto3-stubs-lite[datasync]` keeps the generated DataSync types, but the maintainer docs say it omits `session.client(...)` and `session.resource(...)` overloads.\n- Install the stubs in the same environment that your editor, `mypy`, or `pyright` analyzes.\n- If you need exact parity with a custom `boto3` build, the maintainer project also supports local generation with `mypy-boto3-builder`.\n\n## Initialize And Authenticate\n\n`mypy-boto3-datasync` does not add its own auth, retry, endpoint, or region layer. All runtime behavior still comes from `boto3` and `botocore`.\n\nCommon credential sources, following boto3's documented search order:\n\n1. explicit credentials passed to `client(...)` or `Session(...)`\n2. environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. shared config and credentials files, including `AWS_PROFILE`\n4. container, instance, or other AWS runtime credentials\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=storage-migrations\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nTyped client initialization:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_datasync import DataSyncClient\n\nsession = Session(profile_name=\"storage-migrations\", region_name=\"us-west-2\")\ndatasync: DataSyncClient = session.client(\"datasync\")\n```\n\nIf your production image does not install stub packages, keep the import type-only:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_datasync import DataSyncClient\n\nsession = Session(region_name=\"us-west-2\")\ndatasync = cast(\"DataSyncClient\", session.client(\"datasync\"))\n```\n\nIf you create sessions manually, follow boto3's session guidance and create a separate `Session` per thread or process instead of sharing one across concurrent workers.\n\n## Core Usage\n\n### Typed DataSync client\n\nUse the generated client type for normal DataSync API calls:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_datasync import DataSyncClient\n\ndatasync: DataSyncClient = Session(region_name=\"us-west-2\").client(\"datasync\")\n\nresponse = datasync.list_locations(MaxResults=25)\n\nfor location in response.get(\"Locations\", []):\n    print(location[\"LocationArn\"], location.get(\"LocationUri\"))\n```\n\n### Typed paginators\n\nThe published package docs list paginator types such as `ListTasksPaginator` and `ListTaskExecutionsPaginator`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_datasync import DataSyncClient\nfrom mypy_boto3_datasync.paginator import ListTasksPaginator\n\ndatasync: DataSyncClient = Session(region_name=\"us-west-2\").client(\"datasync\")\npaginator: ListTasksPaginator = datasync.get_paginator(\"list_tasks\")\n\nfor page in paginator.paginate():\n    for task in page.get(\"Tasks\", []):\n        print(task[\"TaskArn\"], task.get(\"Name\"))\n```\n\n### Start and inspect a task execution\n\nRuntime call shapes still come from the boto3 DataSync client docs, but the stubs keep request and response shapes typed:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_datasync import DataSyncClient\n\ndatasync: DataSyncClient = Session(region_name=\"us-west-2\").client(\"datasync\")\n\nstart = datasync.start_task_execution(\n    TaskArn=\"arn:aws:datasync:us-west-2:123456789012:task/task-0123456789abcdef0\",\n)\n\ntask_execution_arn = start[\"TaskExecutionArn\"]\n\ndetails = datasync.describe_task_execution(TaskExecutionArn=task_execution_arn)\nprint(details[\"Status\"], details.get(\"Result\"))\n```\n\n### Typed literals and request shapes\n\nThe generated package docs also expose `literals` and `type_defs`. Use them when helper functions assemble DataSync request dictionaries before the real boto3 call:\n\n```python\nfrom mypy_boto3_datasync.type_defs import PlatformTypeDef\n\nplatform: PlatformTypeDef = {\n    \"Version\": \"1\",\n    \"Platform\": \"linux\",\n}\n```\n\nFor DataSync-heavy codebases, typed request and response shapes are most useful at module boundaries where raw AWS dictionaries would otherwise degrade to `dict[str, Any]`.\n\n## Type Checking Notes\n\n- Import from `mypy_boto3_datasync`, not `mypy-boto3-datasync`. The PyPI distribution name uses hyphens; the Python module uses underscores.\n- Standalone `mypy-boto3-datasync` is the narrow dependency choice, but explicit `DataSyncClient` annotations are more important there.\n- `boto3-stubs[datasync]` is the easiest path if you want overload-based inference from `Session.client(\"datasync\")`.\n- `boto3-stubs-lite[datasync]` is the memory-friendlier option, but plan on explicit annotations.\n\n## Common Pitfalls\n\n- Do not install only `mypy-boto3-datasync` and expect AWS calls to work. You still need `boto3`.\n- Do not pass the package name to boto3. The service name is `\"datasync\"`, not `\"mypy-boto3-datasync\"`.\n- Do not assume the maintainer docs root is release-pinned. It is a latest-style page and can move ahead of the exact wheel you install.\n- Do not treat the stubs as a separate AWS config layer. Credentials, retries, endpoints, IAM permissions, and throttling behavior are still normal boto3 concerns.\n- Do not assume all stub install modes infer `Session.client(\"datasync\")` the same way. The full bundled stubs have overloads; lite and standalone installs need more explicit typing.\n- Do not share one boto3 `Session` across threads or processes.\n\n## Version-Sensitive Notes For `1.42.9`\n\n- The version used here for this session was `1.42.9`, and the official PyPI project page also reported `1.42.9` on March 12, 2026.\n- The maintainer docs for this package describe install paths for `mypy-boto3-datasync`, `boto3-stubs[datasync]`, and `boto3-stubs-lite[datasync]`, plus the typed `DataSyncClient`, paginator classes, literals, and `type_defs`.\n- The maintainer project states that stub package versions track the related `boto3` release line. Keep `boto3`, `botocore`, and the stub package close together when exact method and shape parity matters.\n- The DataSync boto3 reference is a rolling latest reference, so examples copied from AWS docs may reflect a newer runtime patch line than your pinned stub package. Pin first, then type-check against the installed versions in your environment.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_datasync/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-datasync/`\n- Runtime boto3 DataSync reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/datasync.html`\n- boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- boto3 session guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html`\n- DataSync `start_task_execution`: `https://docs.aws.amazon.com/boto3/latest/reference/services/datasync/client/start_task_execution.html`\n- DataSync `describe_task_execution`: `https://docs.aws.amazon.com/boto3/latest/reference/services/datasync/client/describe_task_execution.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-dynamodb/python/DOC.md",
    "content": "---\nname: mypy-boto3-dynamodb\ndescription: \"mypy-boto3-dynamodb package guide for typed boto3 DynamoDB clients, resources, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.55\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,dynamodb,boto3,mypy-boto3-dynamodb,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-dynamodb Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for runtime AWS calls and use `mypy-boto3-dynamodb` only for typing.\n\nIf you want type inference without explicit annotations, install `boto3-stubs[dynamodb]`. If you install `mypy-boto3-dynamodb` or `boto3-stubs-lite[dynamodb]` by itself, you should expect to add explicit type annotations for clients, resources, paginators, and waiters.\n\n## Install\n\n### Recommended for normal boto3 code\n\nInstall the runtime SDK and the service stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.55\" \"boto3-stubs[dynamodb]==1.42.55\"\n```\n\nThis is the best default when you want `Session().client(\"dynamodb\")` and `Session().resource(\"dynamodb\")` to infer the correct types in editors and type checkers.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.55\" \"boto3-stubs-lite[dynamodb]==1.42.55\"\n```\n\nUse this when editor performance matters more than automatic overload discovery. The maintainer docs explicitly say the lite variant does not provide `session.client()` and `session.resource()` overloads, so explicit annotations become the normal workflow.\n\n### Standalone package\n\n```bash\npython -m pip install \"boto3==1.42.55\" \"mypy-boto3-dynamodb==1.42.55\"\n```\n\nUse the standalone package when you only want the DynamoDB typing package or when you prefer guarding typing imports behind `TYPE_CHECKING`.\n\n## Setup And Authentication\n\nThis package does not authenticate to AWS and does not create clients by itself. Authentication, regions, retries, and endpoints still come from `boto3`.\n\nPractical setup:\n\n1. Create a `boto3.Session(...)` with an explicit profile and region when the environment is not obvious.\n2. Let boto3 load credentials from the normal AWS chain unless you are intentionally passing temporary credentials.\n3. Keep runtime config on the session or client, not in the stub package.\n\nMinimal setup:\n\n```python\nimport boto3\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\ndynamodb = session.client(\"dynamodb\")\n```\n\nImportant credential sources from the boto3 guide:\n\n- explicit credentials passed to `boto3.client(...)`\n- explicit credentials passed to `boto3.Session(...)`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n- assume-role and web-identity configuration\n- IAM Identity Center profiles\n- shared config in `~/.aws/credentials` and `~/.aws/config`\n- container or EC2 instance role credentials\n\nFor most local development, use a profile instead of hardcoding keys:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[dynamodb]`\n\nWith the full service extra installed, type discovery should work on ordinary boto3 code:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-west-2\")\nclient = session.client(\"dynamodb\")\nresource = session.resource(\"dynamodb\")\n\ntables = client.list_tables(Limit=10)\nusers_table = resource.Table(\"users\")\n```\n\nThis is the simplest setup for agents generating application code.\n\n### Explicit client annotations\n\nUse explicit annotations when you installed the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_dynamodb import DynamoDBClient\n\nsession = Session(region_name=\"us-west-2\")\nclient: DynamoDBClient = session.client(\"dynamodb\")\n\nresponse = client.list_tables(Limit=10)\nprint(response[\"TableNames\"])\n```\n\n### Explicit paginator and waiter annotations\n\nThe package exposes typed paginators for `list_backups`, `list_tables`, `list_tags_of_resource`, `query`, and `scan`, plus typed waiters such as `table_exists` and `table_not_exists`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_dynamodb import DynamoDBClient\nfrom mypy_boto3_dynamodb.paginator import QueryPaginator\nfrom mypy_boto3_dynamodb.waiter import TableExistsWaiter\n\nsession = Session(region_name=\"us-west-2\")\nclient: DynamoDBClient = session.client(\"dynamodb\")\n\nquery_pages: QueryPaginator = client.get_paginator(\"query\")\ntable_exists: TableExistsWaiter = client.get_waiter(\"table_exists\")\n\ntable_exists.wait(TableName=\"users\")\n```\n\n### Explicit service-resource annotations\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_dynamodb import DynamoDBServiceResource\nfrom mypy_boto3_dynamodb.service_resource import Table\n\nsession = Session(region_name=\"us-west-2\")\nresource: DynamoDBServiceResource = session.resource(\"dynamodb\")\nusers: Table = resource.Table(\"users\")\n```\n\n### Use literals for constrained string values\n\n```python\nfrom mypy_boto3_dynamodb.literals import ApproximateCreationDateTimePrecisionType\n\ndef accepts_precision(value: ApproximateCreationDateTimePrecisionType) -> str:\n    return value\n```\n\n### Use `type_defs` when you want typed request or response fragments\n\n```python\nfrom mypy_boto3_dynamodb.type_defs import ArchivalSummaryTypeDef\n\ndef handle_summary(summary: ArchivalSummaryTypeDef) -> None:\n    print(summary)\n```\n\nThe upstream docs also expose service-specific `TypedDict` definitions and unions under `mypy_boto3_dynamodb.type_defs` for building helper functions and validating request-shape assumptions in typed code.\n\n## `TYPE_CHECKING` Pattern\n\nThe maintainer docs explicitly say it is safe to keep this dependency out of production by importing it only for type checking.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_dynamodb import DynamoDBClient\nelse:\n    DynamoDBClient = object\n\nsession = Session(region_name=\"us-west-2\")\nclient: \"DynamoDBClient\" = session.client(\"dynamodb\")\n```\n\nUse this pattern when your production image should ship only `boto3`. The `object` fallback also avoids the pylint undefined-name problem called out in the upstream docs.\n\n## Common Pitfalls\n\n- `mypy-boto3-dynamodb` is stub-only. It does not replace `boto3`, and it does not give you a runtime DynamoDB client by itself.\n- `boto3-stubs[dynamodb]` and `mypy-boto3-dynamodb` are not equivalent ergonomically. Full `boto3-stubs` gives auto-discovered client and resource overloads; standalone and lite installs usually require explicit annotations.\n- Keep the `boto3` version aligned with the stub version. The maintainer docs say the stub package version matches the related `boto3` version.\n- Do not put AWS credentials in code examples generated for real projects. Keep auth in profiles, environment variables, IAM Identity Center, or runtime IAM roles.\n- If editor performance is poor in PyCharm, the maintainer recommends `boto3-stubs-lite` because `Literal` overloads can be slow there.\n- Typed resource code can still be functionally wrong at runtime if the region, table name, or credentials are wrong. The stubs only validate shape information.\n- AWS behavior docs and package release numbers are separate sources of truth. Use PyPI for the exact package version and AWS docs for credential-chain and runtime behavior.\n\n## Version-Sensitive Notes For `1.42.55`\n\n- PyPI lists `1.42.55` as the latest `mypy-boto3-dynamodb` release on March 12, 2026, published on February 23, 2026.\n- The package description says it provides type annotations for `boto3 DynamoDB 1.42.55`, and the maintainer docs say the package version follows the related `boto3` version.\n- The PyPI release history for this package skips many intermediate patch numbers. Do not assume that every `boto3` patch release has a matching standalone `mypy-boto3-dynamodb` upload.\n- The AWS boto3 docs are currently on a newer rolling patch line (`1.42.66` in the docs tree), so pin against PyPI when exact package compatibility matters.\n- This package was generated with `mypy-boto3-builder 8.12.0`, which matters when comparing generated names or availability across older blog posts and code snippets.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_dynamodb/\n- PyPI package page: https://pypi.org/project/mypy-boto3-dynamodb/\n- PyPI JSON metadata: https://pypi.org/pypi/mypy-boto3-dynamodb/json\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ec2/python/DOC.md",
    "content": "---\nname: mypy-boto3-ec2\ndescription: \"mypy-boto3-ec2 type stubs for boto3 EC2 clients, resources, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.62\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,ec2,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-ec2 Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-ec2` is a typing package for `boto3` EC2 code, not a runtime AWS SDK.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[ec2]` for the best editor and type-checker experience with automatic `Session.client(\"ec2\")` and `Session.resource(\"ec2\")` overloads.\n- Install `mypy-boto3-ec2` when you only want the standalone EC2 stubs and are willing to add explicit annotations.\n- Install `boto3-stubs-lite[ec2]` when IDE memory use matters more than automatic overload inference.\n\nRuntime credentials, regions, retries, endpoints, and API behavior still come from `boto3` and botocore.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[ec2]'\n```\n\nThis is the maintainer-recommended path when you want autocomplete and overload-based type inference without annotating every EC2 variable yourself.\n\n### Standalone EC2 stubs\n\n```bash\npython -m pip install boto3 mypy-boto3-ec2\n```\n\nUse this when you want only the EC2 stubs package. In this mode, explicit annotations are usually necessary.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[ec2]'\n```\n\nThe lite package is more memory-friendly, especially for PyCharm, but it does not provide `session.client()` and `session.resource()` overloads. Add explicit annotations if you use it.\n\n### Conda\n\n```bash\nconda install mypy-boto3-ec2\n```\n\n### Generate locally for an exact boto3 pin\n\nIf your project is pinned to a specific `boto3` version and you need the closest possible type alignment, the maintainer recommends local generation:\n\n```bash\nuvx --with 'boto3==1.42.62' mypy-boto3-builder\n```\n\n## Runtime Setup And AWS Auth\n\n`mypy-boto3-ec2` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nAWS documents that Boto3 searches a credential chain that starts with explicit client or session parameters, then environment variables, then role or profile-based providers, then shared config files, container credentials, and finally EC2 instance metadata.\n\nCommon setup for local development:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nOr create an explicit session in code:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n```\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n\nDo not hardcode credentials in source code. The stub package does not change auth behavior.\n\n## Core Usage\n\n### Typed client\n\nUse clients for full EC2 API coverage. AWS documents that clients map closely to service APIs and support all service operations.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ec2.client import EC2Client\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nec2: EC2Client = session.client(\"ec2\")\n\nresponse = ec2.describe_instances(MaxResults=5)\n\nfor reservation in response.get(\"Reservations\", []):\n    for instance in reservation.get(\"Instances\", []):\n        print(instance[\"InstanceId\"])\n```\n\n### Explicit annotations for standalone or lite installs\n\nWith standalone `mypy-boto3-ec2` or `boto3-stubs-lite[ec2]`, annotate clients and resources explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ec2.client import EC2Client\n\nclient: EC2Client = Session(region_name=\"us-east-1\").client(\"ec2\")\n```\n\n### Typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ec2.client import EC2Client\nfrom mypy_boto3_ec2.paginator import DescribeInstancesPaginator\n\nclient: EC2Client = Session(region_name=\"us-east-1\").client(\"ec2\")\npaginator: DescribeInstancesPaginator = client.get_paginator(\"describe_instances\")\n\nfor page in paginator.paginate(PaginationConfig={\"MaxItems\": 25}):\n    for reservation in page.get(\"Reservations\", []):\n        for instance in reservation.get(\"Instances\", []):\n            print(instance[\"InstanceId\"])\n```\n\n### Typed waiter\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ec2.client import EC2Client\nfrom mypy_boto3_ec2.waiter import InstanceRunningWaiter\n\nclient: EC2Client = Session(region_name=\"us-east-1\").client(\"ec2\")\nwaiter: InstanceRunningWaiter = client.get_waiter(\"instance_running\")\n\nwaiter.wait(InstanceIds=[\"i-0123456789abcdef0\"])\n```\n\n### Typed service resource\n\nAWS documents the resource API as feature-frozen, so prefer clients for new EC2 features. Use resources when you intentionally want the object-oriented interface.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ec2.service_resource import EC2ServiceResource, Instance\n\nresource: EC2ServiceResource = Session(region_name=\"us-east-1\").resource(\"ec2\")\ninstance: Instance = resource.Instance(\"i-0123456789abcdef0\")\n\nprint(instance.instance_id)\n```\n\n### Literals and TypedDicts\n\nUse generated literal and `type_defs` helpers when wrapper code needs stricter typing than plain dictionaries:\n\n```python\nfrom mypy_boto3_ec2.client import EC2Client\nfrom mypy_boto3_ec2.literals import InstanceTypeType\nfrom mypy_boto3_ec2.type_defs import FilterTypeDef\nfrom boto3.session import Session\n\nclient: EC2Client = Session(region_name=\"us-east-1\").client(\"ec2\")\n\ninstance_type: InstanceTypeType = \"t3.micro\"\nfilters: list[FilterTypeDef] = [\n    {\n        \"Name\": \"instance-state-name\",\n        \"Values\": [\"running\"],\n    }\n]\n\nclient.describe_instances(Filters=filters)\nprint(instance_type)\n```\n\n## Tooling Patterns\n\n### Keep stub imports out of production-only environments\n\nIf runtime images do not install stub packages, gate the imports with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_ec2.client import EC2Client\n\ndef make_client() -> \"EC2Client\":\n    return Session(region_name=\"us-east-1\").client(\"ec2\")\n```\n\n### Pylint workaround for dev-only stub installs\n\nThe maintainer docs call out a `pylint` issue with `TYPE_CHECKING` imports. Use an `object` fallback when needed:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_ec2.client import EC2Client\nelse:\n    EC2Client = object\n\nclient: EC2Client = Session(region_name=\"us-east-1\").client(\"ec2\")\n```\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-ec2` and expecting unannotated `session.client(\"ec2\")` or `session.resource(\"ec2\")` calls to become typed automatically. That behavior comes from `boto3-stubs[ec2]`.\n- Forgetting to install `boto3`. These packages are stubs, not the runtime SDK.\n- Treating the stubs package as AWS auth or config middleware. Credentials, region, retries, endpoints, and permissions still come from normal `boto3` and botocore setup.\n- Defaulting to the resource API for every EC2 task. AWS says newer service features land on clients, not resources.\n- Using `boto3-stubs-lite[ec2]` and expecting overload-based inference from `session.client(\"ec2\")`. Lite mode needs more explicit annotations.\n- Importing stub symbols at runtime when the package is installed only in dev dependencies. Use `TYPE_CHECKING` or keep the stubs installed anywhere those imports execute.\n- Assuming generated stubs always match the EC2 surface in your environment. When exact shape coverage matters, pin the stub version with the matching `boto3` version or generate stubs locally.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-ec2 1.42.62` as the latest version on March 12, 2026, released on March 5, 2026.\n- The maintainer states that `mypy-boto3-ec2` uses the same version as the related `boto3` release.\n- Practical rule: when exact request and response shapes matter, pin `boto3==1.42.62` with `mypy-boto3-ec2==1.42.62`.\n- The builder project version is separate. PyPI shows this package was generated with `mypy-boto3-builder 8.12.0`, but that builder version is not the package version you should pin in application dependencies.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ec2/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-ec2/`\n- Builder and issue tracker: `https://github.com/youtype/mypy_boto3_builder`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 clients guide: `https://docs.aws.amazon.com/boto3/latest/guide/clients.html`\n- Boto3 resources guide: `https://docs.aws.amazon.com/boto3/latest/guide/resources.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ecr/python/DOC.md",
    "content": "---\nname: mypy-boto3-ecr\ndescription: \"Type stubs for boto3 Amazon ECR clients, paginators, waiters, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.57\"\n  revision: 3\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,ecr,boto3,mypy,pyright,typing,type-stubs\"\n---\n\n# mypy-boto3-ecr Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-ecr` adds static types for the Amazon ECR client in `boto3`.\n\nIt helps with:\n\n- autocompletion for ECR client methods\n- typed paginator and waiter names\n- `TypedDict` request and response shapes\n- literal string unions used by the ECR API\n\nIt does not replace `boto3` at runtime. AWS credentials, regions, retries, endpoints, and API behavior still come from `boto3` and your AWS configuration.\n\n## Install\n\n### Standalone ECR stubs\n\nInstall the runtime SDK plus the ECR service stubs:\n\n```bash\npython -m pip install boto3 \"mypy-boto3-ecr==1.42.57\"\n```\n\nUse this when you only want ECR typing support.\n\n### Full boto3 stubs bundle\n\nIf you want typed overloads across multiple AWS services, use the maintained extras package:\n\n```bash\npython -m pip install boto3 \"boto3-stubs[ecr]\"\n```\n\nThis is usually the easiest option when your project uses more than one AWS service.\n\n### Lower-memory fallback\n\nIf IDE memory use matters more than automatic `Session.client(...)` inference:\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[ecr]\"\n```\n\nWith the lite package, explicit client annotations are more important because the generated overloads for `Session.client(...)` are reduced.\n\n## Runtime Setup And Auth\n\nThere is no package-specific initialization. Create a normal boto3 session and let AWS resolve credentials through the usual boto3 credential chain.\n\nTypical local environment setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nOr configure explicit credentials in environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create a typed ECR client:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\necr: ECRClient = session.client(\"ecr\")\n```\n\nFor local development, named profiles are usually easier to rotate and audit than hard-coded keys. In AWS-hosted environments, prefer IAM roles.\n\n## Core Usage\n\n### Typed Client Calls\n\nUse normal boto3 runtime calls and add the service client annotation explicitly:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\n\necr: ECRClient = boto3.Session(region_name=\"us-west-2\").client(\"ecr\")\n\nresponse = ecr.describe_repositories(maxResults=20)\n\nfor repository in response.get(\"repositories\", []):\n    print(repository[\"repositoryName\"], repository[\"repositoryUri\"])\n```\n\nThis pattern works well with the standalone package, the full `boto3-stubs` package, and the lite package.\n\n### Create A Repository\n\nThe stubs also make write operations easier to discover and shape correctly:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\n\necr: ECRClient = boto3.Session(region_name=\"us-west-2\").client(\"ecr\")\n\ncreated = ecr.create_repository(\n    repositoryName=\"example-repo\",\n    imageScanningConfiguration={\"scanOnPush\": True},\n)\n\nprint(created[\"repository\"][\"repositoryArn\"])\n```\n\n### Typed Paginators\n\nUse the generated paginator class when you need to iterate through repository pages:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\nfrom mypy_boto3_ecr.paginator import DescribeRepositoriesPaginator\n\necr: ECRClient = boto3.Session(region_name=\"us-west-2\").client(\"ecr\")\npaginator: DescribeRepositoriesPaginator = ecr.get_paginator(\n    \"describe_repositories\"\n)\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 100}):\n    for repository in page.get(\"repositories\", []):\n        print(repository[\"repositoryArn\"])\n```\n\n### Typed Waiters\n\nECR exposes generated waiter classes through the stubs package. For example, wait for an image scan to finish:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\nfrom mypy_boto3_ecr.waiter import ImageScanCompleteWaiter\n\necr: ECRClient = boto3.Session(region_name=\"us-west-2\").client(\"ecr\")\nwaiter: ImageScanCompleteWaiter = ecr.get_waiter(\"image_scan_complete\")\n\nwaiter.wait(\n    repositoryName=\"example-repo\",\n    imageId={\"imageTag\": \"latest\"},\n    WaiterConfig={\"Delay\": 5, \"MaxAttempts\": 60},\n)\n```\n\nThe generated docs also list `LifecyclePolicyPreviewCompleteWaiter`.\n\n### Typed Request Payloads And Literals\n\nWhen you build request payloads in helpers, the generated `TypedDict` and literal modules make it easier to catch mistakes before runtime:\n\n```python\nimport boto3\nfrom mypy_boto3_ecr.client import ECRClient\nfrom mypy_boto3_ecr.literals import TagStatusType\nfrom mypy_boto3_ecr.type_defs import DescribeImagesRequestRequestTypeDef\n\ntag_status: TagStatusType = \"TAGGED\"\n\nrequest: DescribeImagesRequestRequestTypeDef = {\n    \"repositoryName\": \"example-repo\",\n    \"filter\": {\"tagStatus\": tag_status},\n}\n\necr: ECRClient = boto3.Session(region_name=\"us-west-2\").client(\"ecr\")\nimages = ecr.describe_images(**request)\n\nfor detail in images.get(\"imageDetails\", []):\n    print(detail.get(\"imageDigest\"))\n```\n\n## Dev-Only Type Imports\n\nIf production images install `boto3` but not the stub package, keep type imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_ecr.client import ECRClient\n\nsession = boto3.Session(region_name=\"us-west-2\")\necr: \"ECRClient\" = session.client(\"ecr\")\n\nprint(ecr.describe_repositories(maxResults=5)[\"repositories\"])\n```\n\nThis keeps runtime imports simple while preserving type checking in development and CI.\n\n## Import Surface\n\nThe service-specific package exposes the modules most ECR projects need:\n\n- `mypy_boto3_ecr.client`\n- `mypy_boto3_ecr.paginator`\n- `mypy_boto3_ecr.waiter`\n- `mypy_boto3_ecr.type_defs`\n- `mypy_boto3_ecr.literals`\n\nFor ECR, the generated package is client-oriented. Do not assume there is a typed boto3 resource layer for this service.\n\n## Common Pitfalls\n\n### The Stub Package Does Not Replace boto3\n\nYou still need `boto3` installed for runtime AWS calls.\n\n### Package Name And Import Name Differ\n\nUse:\n\n- package name: `mypy-boto3-ecr`\n- import root: `mypy_boto3_ecr`\n\n### Type Safety Does Not Fix Auth Or Region Problems\n\nIf calls fail with credential, authorization, or region errors, debug them as normal boto3 and AWS configuration issues.\n\n### Keep boto3 And Stub Versions Close\n\nThese stubs are generated from boto3 service models. If your installed `boto3` and `mypy-boto3-ecr` versions drift too far apart, type information can become stale even when runtime code still works.\n\n### Lite Installs Need Explicit Annotations\n\nIf you use `boto3-stubs-lite[ecr]`, annotate the client explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ecr.client import ECRClient\n\necr: ECRClient = Session(region_name=\"us-west-2\").client(\"ecr\")\n```\n\n## Version Notes\n\nThis guide targets `mypy-boto3-ecr` version `1.42.57`.\n\nIf you pin dependency versions, keep the ECR stubs aligned with the boto3 release line you use in the same project.\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ecs/python/DOC.md",
    "content": "---\nname: mypy-boto3-ecs\ndescription: \"mypy-boto3-ecs typed boto3 stubs for Amazon ECS clients, resources, literals, paginators, waiters, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.58\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,ecs,boto3,python,typing,mypy,pyright,stubs\"\n---\n\n# mypy-boto3-ecs Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-ecs` is a typing package for ECS code written with `boto3`. It improves autocomplete and static checking, but it is not the runtime SDK. Keep `boto3` installed for real AWS calls, credentials, regions, retries, and endpoints.\n\nChoose the install mode deliberately:\n\n- Use `boto3-stubs[ecs]` if you want the best overloads for `Session.client(\"ecs\")` and `Session.resource(\"ecs\")`.\n- Use `mypy-boto3-ecs` if you only need ECS-specific types and are willing to annotate ECS clients and resources explicitly.\n- Use `boto3-stubs-lite[ecs]` if install size matters and explicit annotations are acceptable.\n\n## Install\n\n### Minimal service-specific setup\n\n```bash\npython -m pip install \"boto3\" \"mypy-boto3-ecs==1.42.58\"\n```\n\nThis is the narrowest install if you only need ECS typing.\n\n### Bundled upstream install path\n\n```bash\npython -m pip install \"boto3-stubs[ecs]==1.42.58\"\n```\n\nUse this when you want better typing inference around `boto3.session.Session`, `client(...)`, and `resource(...)`.\n\n### Lower-memory fallback\n\n```bash\npython -m pip install \"boto3-stubs-lite[ecs]==1.42.58\"\n```\n\nThe lite package omits `session.client(...)` and `session.resource(...)` overloads. Add explicit annotations or `cast(...)` when you use it.\n\n## Authentication And Configuration\n\n`mypy-boto3-ecs` does not change how AWS auth works. Use normal `boto3` configuration:\n\n1. Explicit `Session(...)` or `client(...)` arguments\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_DEFAULT_REGION`, and `AWS_PROFILE`\n3. Shared AWS config and credentials files\n4. IAM roles and other runtime credential providers in AWS environments\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen construct a typed session client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ecs import ECSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\necs: ECSClient = session.client(\"ecs\")\n```\n\nIf your project spans multiple accounts or regions, keep the `Session(...)` creation explicit instead of relying on ambient defaults.\n\n## Core Usage\n\n### Typed ECS client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ecs import ECSClient\n\necs: ECSClient = Session(region_name=\"us-east-1\").client(\"ecs\")\n\nresponse = ecs.describe_clusters(clusters=[\"default\"])\n\nfor cluster in response.get(\"clusters\", []):\n    print(cluster[\"clusterArn\"], cluster[\"status\"])\n```\n\n### Typed ECS resource\n\nThe generated stubs also expose the resource surface:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ecs.service_resource import ECSServiceResource\n\necs_resource: ECSServiceResource = Session(region_name=\"us-east-1\").resource(\"ecs\")\n```\n\nPrefer the client API for most new code. Use the resource interface only when you already depend on its object model.\n\n### Typed request data for Fargate networking\n\nUse generated `TypedDict` shapes from `mypy_boto3_ecs.type_defs` when you pass ECS-shaped dictionaries between helpers:\n\n```python\nfrom mypy_boto3_ecs.type_defs import AwsVpcConfigurationTypeDef\n\nnetwork_config: AwsVpcConfigurationTypeDef = {\n    \"subnets\": [\"subnet-12345678\", \"subnet-abcdef12\"],\n    \"securityGroups\": [\"sg-12345678\"],\n    \"assignPublicIp\": \"DISABLED\",\n}\n```\n\n### Literals for enum-like ECS fields\n\n```python\nfrom mypy_boto3_ecs.literals import LaunchTypeType\n\nlaunch_type: LaunchTypeType = \"FARGATE\"\n```\n\nThis catches typos such as `\"fargate\"` during type checking instead of at runtime.\n\n### Typed paginator pattern\n\nThe generated package includes paginator classes under `mypy_boto3_ecs.paginator`. Even if you do not annotate the paginator class directly, the stubs still improve completion on paginated response pages.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ecs import ECSClient\n\necs: ECSClient = Session(region_name=\"us-east-1\").client(\"ecs\")\npaginator = ecs.get_paginator(\"list_clusters\")\n\nfor page in paginator.paginate():\n    for cluster_arn in page.get(\"clusterArns\", []):\n        print(cluster_arn)\n```\n\n### Dev-only typing dependencies\n\nIf the stub package is installed only in development or CI, guard type-only imports:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_ecs import ECSClient\n\ndef get_ecs_client() -> \"ECSClient\":\n    return Session(region_name=\"us-west-2\").client(\"ecs\")\n```\n\n## ECS Runtime Notes That Types Do Not Solve\n\n- `RunTask`, `StartTask`, and several describe operations can return `failures` inside an otherwise successful response. Check them explicitly.\n- `list_tasks` returns task ARNs, not full task objects. Follow it with `describe_tasks`.\n- Fargate tasks need a task definition compatible with `awsvpc` networking plus a valid VPC network configuration.\n- IAM, cluster state, capacity providers, service deployment state, and regional availability are runtime concerns. The stub package only validates shapes and names.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-ecs` and assuming it replaces `boto3`. It does not.\n- Importing `mypy-boto3-ecs` with hyphens. Install with hyphens, import with underscores: `mypy_boto3_ecs`.\n- Expecting automatic `Session.client(\"ecs\")` inference from the standalone package in every toolchain. Use `boto3-stubs[ecs]` if you want the bundled overloads.\n- Choosing `boto3-stubs-lite[ecs]` and forgetting that explicit annotations are required more often.\n- Letting `boto3`, `botocore`, and `mypy-boto3-ecs` drift too far apart. New ECS fields can appear in runtime models before matching stubs land.\n- Treating better typing as proof that the call will succeed. Region, credentials, IAM, cluster names, task definitions, and service state still need real validation.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, the version used here `1.42.58` matches the current PyPI package page for `mypy-boto3-ecs`.\n- On `2026-03-12`, the maintainer docs root also points to the ECS stub package for the `1.42.58` line.\n- The maintainer project documents these stub packages as tracking the related `boto3` version family. For exact ECS model coverage, pin the stub package close to the `boto3` version you actually deploy.\n- Repository branding has moved to `types-boto3`, but the published package name and Python import root remain `mypy-boto3-ecs` and `mypy_boto3_ecs`.\n\n## Official Source URLs\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ecs/`\n- Upstream versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-ecs/`\n- PyPI JSON API: `https://pypi.org/pypi/mypy-boto3-ecs/json`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Boto3 session guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html`\n- Boto3 ECS reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecs.html`\n- Repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-efs/python/DOC.md",
    "content": "---\nname: mypy-boto3-efs\ndescription: \"Type annotations for boto3 EFS in Python, covering typed clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,efs,boto3,type-stubs,mypy,pyright,autocomplete\"\n---\n\n# mypy-boto3-efs Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-efs` is a stubs-only package for static typing. Use `boto3` for real AWS calls, and use either `boto3-stubs[efs]` or `mypy-boto3-efs` to improve type checking and editor completion.\n\n- Use `boto3-stubs[efs]` when you want `Session().client(\"efs\")` to infer types automatically.\n- Use `mypy-boto3-efs` when you want only the EFS service stubs and you are willing to add explicit annotations.\n- Use `boto3-stubs-lite[efs]` if full overloads are too heavy for your editor; expect to annotate types explicitly.\n\n## Install\n\n### Recommended for normal boto3 code\n\nInstall the runtime SDK and the full service stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[efs]==1.42.3\"\n```\n\nThis is the best default when you want mypy, pyright, and editor tooling to infer the return type of `Session().client(\"efs\")` without extra annotations.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[efs]==1.42.3\"\n```\n\nUse this when full overloads make PyCharm or other tools slow. The maintainer docs explicitly note that the lite package does not provide `session.client/resource` overloads.\n\n### Standalone service package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-efs==1.42.3\"\n```\n\nUse this when you want only EFS stubs installed or you plan to guard imports with `TYPE_CHECKING`.\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"boto3-stubs[efs]==1.42.3\"\npoetry add \"boto3==1.42.3\" \"boto3-stubs[efs]==1.42.3\"\n```\n\nNotes:\n\n- Keep the stub version aligned with the `boto3` version you pin. The maintainer states that `mypy-boto3-efs` uses the related boto3 version number.\n- `mypy-boto3-efs` does not replace `boto3`. If you install only the stub package, code may type-check but runtime imports and AWS calls still depend on `boto3`.\n\n## Authentication And Runtime Setup\n\nThis package adds typing only. Credentials, region selection, retry behavior, endpoints, and actual network calls still come from `boto3`.\n\nAWS documents that Boto3 searches for credentials in order, starting with explicit client parameters, explicit `Session(...)` parameters, environment variables, assume-role providers, and shared config files. In practice:\n\n1. Prefer `aws configure` or an AWS profile for local development.\n2. Set `AWS_PROFILE` and `AWS_DEFAULT_REGION` when the environment is not obvious.\n3. Pass `region_name` explicitly in generated code when region ambiguity could break requests.\n\nProfile-based setup:\n\n```bash\nexport AWS_PROFILE=\"dev\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nMinimal typed client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_efs import EFSClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: EFSClient = session.client(\"efs\")\n```\n\nUse the client interface as the main surface. The current AWS boto3 EFS reference exposes a low-level client and paginators, and the EFS stub docs I validated are centered on `EFSClient`, literals, paginators, and `type_defs`.\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[efs]`\n\nWith the full `boto3-stubs` extra installed, ordinary boto3 code should type-check without explicit annotations:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-east-1\")\nclient = session.client(\"efs\")\n\nresponse = client.describe_file_systems()\nfor file_system in response.get(\"FileSystems\", []):\n    print(file_system[\"FileSystemId\"], file_system[\"LifeCycleState\"])\n```\n\n### Explicit client annotations\n\nUse explicit annotations when you installed `mypy-boto3-efs` or `boto3-stubs-lite[efs]`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_efs import EFSClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: EFSClient = session.client(\"efs\")\n\nresponse = client.describe_access_points(FileSystemId=\"fs-12345678\")\nfor access_point in response.get(\"AccessPoints\", []):\n    print(access_point[\"AccessPointId\"])\n```\n\n### Typed paginators\n\nAWS currently documents five EFS paginators: `describe_access_points`, `describe_file_systems`, `describe_mount_targets`, `describe_replication_configurations`, and `describe_tags`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_efs import EFSClient\nfrom mypy_boto3_efs.paginator import DescribeFileSystemsPaginator\n\nsession = Session(region_name=\"us-east-1\")\nclient: EFSClient = session.client(\"efs\")\npages: DescribeFileSystemsPaginator = client.get_paginator(\"describe_file_systems\")\n\nfor page in pages.paginate():\n    for file_system in page.get(\"FileSystems\", []):\n        print(file_system[\"FileSystemId\"])\n```\n\n### Literals\n\nUse literals for constrained string values that appear in helpers and config plumbing:\n\n```python\nfrom mypy_boto3_efs.literals import DeletionModeType\n\ndef normalize_deletion_mode(value: DeletionModeType) -> DeletionModeType:\n    return value\n```\n\nThe maintainer docs show `DeletionModeType` as one of the generated EFS literals.\n\n### `type_defs` for request and response shapes\n\nUse `type_defs` when you want request fragments or response objects to stay typed across helper functions:\n\n```python\nfrom mypy_boto3_efs.type_defs import PosixUserOutputTypeDef\n\ndef get_posix_user(uid: int, gid: int) -> PosixUserOutputTypeDef:\n    return {\n        \"Uid\": uid,\n        \"Gid\": gid,\n    }\n```\n\nThe generated docs also list service-specific request and response `TypedDict`s such as `CreateAccessPointRequestTypeDef`, `DescribeFileSystemsResponseTypeDef`, and `MountTargetDescriptionTypeDef`.\n\n## `TYPE_CHECKING` Pattern\n\nIf you do not want to ship the stub package in production, import the types only when type checkers are running:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_efs import EFSClient\nelse:\n    EFSClient = object\n\nsession = Session(region_name=\"us-east-1\")\nclient: \"EFSClient\" = session.client(\"efs\")\n```\n\nThis matches the maintainer guidance for keeping stub dependencies out of production environments while avoiding pylint issues with missing symbols.\n\n## Common Pitfalls\n\n- `mypy-boto3-efs` is stub-only. It does not create runtime clients and it does not include `boto3`.\n- `boto3-stubs[efs]` and `mypy-boto3-efs` are not equivalent ergonomically. The full `boto3-stubs` extra gives better type inference for normal boto3 code.\n- `boto3-stubs-lite[efs]` is more memory-friendly, but you should expect to add explicit annotations.\n- Keep `boto3` and the EFS stubs on matching versions when you want predictable method signatures and generated shape names.\n- The current EFS pages I validated do not expose a typed service-resource section or waiter section for EFS. Generate code around the client and paginators first.\n- Type correctness does not validate your AWS setup. Bad credentials, wrong region, missing IAM permissions, or wrong file system IDs will still fail at runtime.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI lists `mypy-boto3-efs 1.42.3` as the latest release on March 12, 2026, published on December 4, 2025.\n- The package description says it provides type annotations for `boto3 EFS 1.42.3` and that package versioning follows the related `boto3` version.\n- The hosted maintainer docs are a rolling generated site. The current docs root already shows a local-generation example against `boto3==1.42.44`, so do not assume every example on the docs site is pinned to `1.42.3`.\n- The AWS boto3 documentation is also on a rolling latest patch line, so use PyPI as the source of truth for the exact stub package version you pin in code.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_efs/\n- PyPI package page: https://pypi.org/project/mypy-boto3-efs/\n- AWS boto3 EFS reference: https://docs.aws.amazon.com/boto3/latest/reference/services/efs.html\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-eks/python/DOC.md",
    "content": "---\nname: mypy-boto3-eks\ndescription: \"mypy-boto3-eks package guide for typed boto3 Amazon EKS clients, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 3\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,eks,mypy,python,stubs,types\"\n---\n\n# mypy-boto3-eks Python Package Guide\n\n## What It Is\n\n`mypy-boto3-eks` provides type annotations for the Amazon EKS part of `boto3`.\n\nUse it when you want static checking and editor completion for:\n\n- `EKSClient`\n- paginator classes such as `ListClustersPaginator`\n- waiter classes such as `ClusterActiveWaiter`\n- generated `TypedDict` request and response shapes under `type_defs`\n- generated literal unions under `literals`\n\nIt does not replace `boto3` at runtime. Real AWS calls still come from `boto3.Session(...).client(\"eks\")`.\n\n## Prerequisites\n\n- Python `>=3.9`\n- `boto3` for runtime AWS calls\n- AWS credentials and a region configured through the normal boto3 credential chain\n\nCommon local environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3-stubs[eks]==1.42.66\"\n```\n\nThis is the maintainer-recommended path when you want EKS typing with `boto3-stubs` service extras.\n\n### Install runtime boto3 through the umbrella package too\n\n```bash\npython -m pip install \"boto3-stubs[boto3,eks]==1.42.66\"\n```\n\n### Standalone service stubs\n\n```bash\npython -m pip install \"boto3==1.42.66\" \"mypy-boto3-eks==1.42.66\"\n```\n\nUse this when you want only the EKS stub package and are willing to annotate the client explicitly.\n\n### Lower-memory variant\n\n```bash\npython -m pip install \"boto3==1.42.66\" \"boto3-stubs-lite[eks]==1.42.66\"\n```\n\nThe lite package is useful when IDE memory use matters more than automatic `Session.client(\"eks\")` overloads.\n\n### Generate local stubs for an exact boto3 pin\n\nIf your project is pinned tightly to a specific `boto3` build and exact generated type parity matters, the maintainer docs point to local generation:\n\n```bash\nuvx --with \"boto3==1.42.66\" mypy-boto3-builder\n```\n\n## Initialize A Typed EKS Client\n\n`mypy-boto3-eks` does not add its own auth or config layer. Create sessions and clients exactly as you would in normal boto3 code.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_eks.client import EKSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\neks: EKSClient = session.client(\"eks\")\n\nresponse = eks.describe_cluster(name=\"example-cluster\")\nprint(response[\"cluster\"][\"arn\"])\n```\n\nIf you need retries, proxies, or timeouts, keep using botocore configuration:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_eks.client import EKSClient\n\nconfig = Config(retries={\"max_attempts\": 10, \"mode\": \"standard\"})\nsession = Session(region_name=\"us-west-2\")\neks: EKSClient = session.client(\"eks\", config=config)\n```\n\n## Core Usage\n\n### Typed Client Calls\n\nUse the typed client for EKS control-plane operations such as cluster lookup, nodegroup inspection, access-entry management, and updates.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_eks.client import EKSClient\n\neks: EKSClient = Session(region_name=\"us-west-2\").client(\"eks\")\n\ncluster = eks.describe_cluster(name=\"example-cluster\")[\"cluster\"]\nprint(cluster[\"name\"], cluster[\"status\"])\n```\n\nEKS does not have a typed resource layer here comparable to S3 resources. Prefer the client interface.\n\n### Typed Paginators\n\nThe generated docs expose paginator types for these operations:\n\n- `describe_addon_versions`\n- `describe_cluster_versions`\n- `list_access_entries`\n- `list_access_policies`\n- `list_associated_access_policies`\n- `list_capabilities`\n- `list_clusters`\n- `list_eks_anywhere_subscriptions`\n- `list_fargate_profiles`\n- `list_identity_provider_configs`\n- `list_insights`\n- `list_nodegroups`\n- `list_pod_identity_associations`\n- `list_updates`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_eks.client import EKSClient\nfrom mypy_boto3_eks.paginator import ListClustersPaginator\n\neks: EKSClient = Session(region_name=\"us-west-2\").client(\"eks\")\npaginator: ListClustersPaginator = eks.get_paginator(\"list_clusters\")\n\nfor page in paginator.paginate():\n    for cluster_name in page.get(\"clusters\", []):\n        print(cluster_name)\n```\n\n### Typed Waiters\n\nThe generated docs expose waiter types for:\n\n- `addon_active`\n- `addon_deleted`\n- `cluster_active`\n- `cluster_deleted`\n- `fargate_profile_active`\n- `fargate_profile_deleted`\n- `nodegroup_active`\n- `nodegroup_deleted`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_eks.client import EKSClient\nfrom mypy_boto3_eks.waiter import ClusterActiveWaiter\n\neks: EKSClient = Session(region_name=\"us-west-2\").client(\"eks\")\nwaiter: ClusterActiveWaiter = eks.get_waiter(\"cluster_active\")\nwaiter.wait(name=\"example-cluster\")\n```\n\n### TypedDict Request And Response Shapes\n\nUse `type_defs` when request payloads or responses move through helpers before the boto3 call site.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_eks.client import EKSClient\nfrom mypy_boto3_eks.type_defs import (\n    AssociateAccessPolicyRequestTypeDef,\n    DescribeClusterResponseTypeDef,\n)\n\nrequest: AssociateAccessPolicyRequestTypeDef = {\n    \"clusterName\": \"example-cluster\",\n    \"principalArn\": \"arn:aws:iam::123456789012:role/EKSAdmin\",\n    \"policyArn\": \"arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy\",\n    \"accessScope\": {\"type\": \"cluster\"},\n}\n\neks: EKSClient = Session(region_name=\"us-west-2\").client(\"eks\")\nresponse: DescribeClusterResponseTypeDef = eks.describe_cluster(name=\"example-cluster\")\n\nprint(request[\"policyArn\"])\nprint(response[\"cluster\"][\"name\"])\n```\n\nThis is especially useful for access-entry, pod-identity, and other nested EKS request shapes where untyped dictionaries become noisy quickly.\n\n### Literal Types\n\nUse the generated literal unions when helpers should only accept the allowed EKS string values.\n\n```python\nfrom mypy_boto3_eks.literals import AMITypesType\n\n\ndef normalize_ami_type(value: AMITypesType) -> str:\n    return value\n```\n\n### `TYPE_CHECKING` Pattern For Dev-Only Stubs\n\nIf the stub package is installed only in development or CI, keep typing imports behind `TYPE_CHECKING`.\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_eks.client import EKSClient\n\neks = cast(\"EKSClient\", boto3.Session(region_name=\"us-west-2\").client(\"eks\"))\n\nfor cluster_name in eks.list_clusters().get(\"clusters\", []):\n    print(cluster_name)\n```\n\n## What This Package Does Not Do\n\n- It does not create AWS credentials.\n- It does not ship a runtime EKS client.\n- It does not manage Kubernetes objects inside a running cluster.\n- It does not validate IAM permissions, cluster state, or network reachability at runtime.\n\nFor in-cluster resources such as Pods, Deployments, or Services, use kubeconfig or token-based auth plus the Kubernetes Python client after the EKS control-plane calls.\n\n## Common Pitfalls\n\n### Hyphenated Package Name vs Import Name\n\nInstall with `mypy-boto3-eks`, but import from `mypy_boto3_eks`.\n\n### Treating The Stubs As The SDK\n\nIf an EKS call fails, debug it as normal boto3 code: credentials, region, IAM permissions, request shape, or service state. The stubs only affect static analysis.\n\n### Expecting A Typed Resource Interface\n\nEKS is a client-focused service in this package. Do not expect `Session.resource(\"eks\")` typing similar to S3.\n\n### Importing Stub Modules At Runtime When They Are Dev Dependencies\n\nIf production images do not install the stub package, direct runtime imports from `mypy_boto3_eks` will fail. Use `TYPE_CHECKING`, string annotations, or `cast(...)`.\n\n### Confusing EKS Control-Plane Calls With Kubernetes API Calls\n\n`describe_cluster`, `list_nodegroups`, `associate_access_policy`, and related methods operate on the AWS EKS control plane. They do not replace the Kubernetes API for workloads running inside the cluster.\n\n### Assuming The Hosted Docs Are Release-Pinned\n\nThe maintainer docs site is a generated latest view. Use the PyPI release page for installation pinning, and use the hosted docs for the current typed surface and symbol names.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.42.66`.\n- The package family tracks the related `boto3` version line, so keep `boto3` and `mypy-boto3-eks` close when exact API coverage matters.\n- The hosted docs root is a moving latest page and can lag or lead the currently published PyPI package on patch labels.\n- The maintainer docs currently show local generation text against `boto3==1.42.65`, so treat that page as the current API-shape reference rather than strict release-pinning evidence.\n- If exact generated names matter more than using the published wheel, generate local stubs for your pinned `boto3` version.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_eks/`\n- Upstream versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-eks/`\n- PyPI JSON API: `https://pypi.org/pypi/mypy-boto3-eks/json`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Boto3 clients guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html`\n- Boto3 EKS reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/eks.html`\n- Repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-elasticache/python/DOC.md",
    "content": "---\nname: mypy-boto3-elasticache\ndescription: \"Type stubs for boto3 ElastiCache in Python projects, including typed clients, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,elasticache,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-elasticache Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-elasticache` for static typing only, and keep normal `boto3` as the runtime SDK. Create real clients with `boto3` or `boto3.session.Session`, then annotate them with `ElastiCacheClient` or install `boto3-stubs[elasticache]` if you want broader boto3 overload support in editors and type checkers.\n\n## What This Package Gives You\n\n`mypy-boto3-elasticache` adds type information for the boto3 ElastiCache client surface:\n\n- typed client annotations for `Session.client(\"elasticache\")`\n- typed paginator and waiter classes\n- generated `TypedDict` request and response shapes\n- literal unions for enum-like string parameters\n\nIt does not replace boto3 at runtime and does not add new AWS behavior by itself.\n\n## Install\n\nPin the stubs to the boto3 version your project expects. This package follows boto3 versioning, so version drift between the runtime SDK and the stubs is the main source of missing or mismatched symbols.\n\nStandalone service stubs:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-elasticache==1.42.3\"\n```\n\nIf you want the broader `boto3-stubs` experience with service extras:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[elasticache]==1.42.3\"\n```\n\nLower-memory alternative:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[elasticache]==1.42.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"mypy-boto3-elasticache==1.42.3\"\npoetry add \"boto3==1.42.3\" \"mypy-boto3-elasticache==1.42.3\"\n```\n\nIf the stubs are only needed for type checking, keeping them in a development dependency group is usually the right choice.\n\n## Authentication And Setup\n\nElastiCache uses normal boto3 credential and region configuration. Boto3 checks explicit client parameters, explicit `Session(...)` parameters, environment variables, shared AWS config and credentials files, and then runtime providers such as container or instance metadata.\n\nPrefer one of these setup paths:\n\n1. Local development with a named AWS profile in `~/.aws/config` and `~/.aws/credentials`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_DEFAULT_REGION`\n3. IAM roles or workload identity when running in AWS\n\nTyped client setup with an explicit region:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_elasticache import ElastiCacheClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: ElastiCacheClient = session.client(\"elasticache\")\n```\n\nIf the stubs are not installed in production, keep the type import behind `TYPE_CHECKING`:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_elasticache import ElastiCacheClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: ElastiCacheClient = session.client(\"elasticache\")\n```\n\n## Core Usage\n\n### Type a normal ElastiCache client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_elasticache import ElastiCacheClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: ElastiCacheClient = session.client(\"elasticache\")\n\nresponse = client.describe_cache_clusters(ShowCacheNodeInfo=True)\n\nfor cluster in response.get(\"CacheClusters\", []):\n    print(cluster[\"CacheClusterId\"], cluster[\"Engine\"])\n```\n\n### Type paginators explicitly\n\n```python\nfrom mypy_boto3_elasticache import ElastiCacheClient\nfrom mypy_boto3_elasticache.paginator import DescribeCacheClustersPaginator\n\nclient: ElastiCacheClient = session.client(\"elasticache\")\npaginator: DescribeCacheClustersPaginator = client.get_paginator(\n    \"describe_cache_clusters\"\n)\n\nfor page in paginator.paginate(ShowCacheNodeInfo=True):\n    for cluster in page.get(\"CacheClusters\", []):\n        print(cluster[\"CacheClusterId\"])\n```\n\nThe ElastiCache boto3 service reference also exposes paginator names such as `DescribeCacheClusters`, `DescribeEngineDefaultParameters`, `DescribeReplicationGroups`, `DescribeReservedCacheNodes`, `DescribeReservedCacheNodesOfferings`, `DescribeServerlessCaches`, `DescribeSnapshots`, `DescribeUpdateActions`, and `DescribeUsers`.\n\n### Type waiters explicitly\n\n```python\nfrom mypy_boto3_elasticache import ElastiCacheClient\nfrom mypy_boto3_elasticache.waiter import CacheClusterAvailableWaiter\n\nclient: ElastiCacheClient = session.client(\"elasticache\")\nwaiter: CacheClusterAvailableWaiter = client.get_waiter(\"cache_cluster_available\")\n\nwaiter.wait(\n    CacheClusterId=\"my-cache-cluster\",\n    WaiterConfig={\"Delay\": 30, \"MaxAttempts\": 20},\n)\n```\n\nFor this package version, the generated stubs include waiter classes for cache clusters, cache parameter groups, replication groups, snapshots, and global replication groups.\n\n### Use generated literals and TypedDicts\n\n```python\nfrom mypy_boto3_elasticache.literals import AZModeType\nfrom mypy_boto3_elasticache.type_defs import TagTypeDef\n\ndef normalize_inputs(mode: AZModeType, tags: list[TagTypeDef]) -> tuple[AZModeType, list[TagTypeDef]]:\n    return mode, tags\n```\n\nUse these imports when you want static validation of request payloads or helper functions that wrap boto3 calls.\n\n## Configuration Notes\n\n- Set `region_name` explicitly when the runtime environment is ambiguous. ElastiCache is regional, and the wrong default region leads to confusing \"resource not found\" failures.\n- Prefer `Session(profile_name=..., region_name=...)` for local tools or multi-account code instead of scattering credentials through `client(...)` calls.\n- Keep runtime boto3 retries and botocore config in the real client setup. The stubs package does not change retry behavior, timeouts, endpoints, or auth resolution.\n- Use the AWS service reference for operation names and runtime semantics; use the stubs package for typing and editor support.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-elasticache` without `boto3` does not give you a working AWS client. The stubs package is typing-only.\n- Do not assume the latest online boto3 reference exactly matches your pinned stubs. On March 12, 2026, the package is pinned to `1.42.3`, while the live boto3 docs may already describe newer service updates.\n- `boto3-stubs-lite[elasticache]` is lighter, but the maintainer docs note that it does not provide `Session.client()` or `Session.resource()` overloads. Use explicit annotations when you choose the lite variant.\n- Keep stub imports out of production-only environments unless you intentionally ship them there. `TYPE_CHECKING` imports are the safest pattern when the dependency is dev-only.\n- TypedDicts describe request and response shapes, but runtime validation still happens in boto3 and AWS. Static types do not replace service-side constraints.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matched the current PyPI release observed on March 12, 2026.\n- The maintainer states that the stubs package version is intended to stay aligned with the related boto3 version. Pin both together when possible.\n- The canonical package docs are generated from the `boto3-stubs` project. When AWS adds new ElastiCache operations or waiters in later boto3 releases, your pinned `1.42.3` stubs may lag those newer symbols even if the AWS docs site already shows them.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elasticache/`\n- Maintainer client docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elasticache/client/`\n- Maintainer paginators docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elasticache/paginators/`\n- Maintainer waiters docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elasticache/waiters/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-elasticache/`\n- AWS boto3 credential guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- AWS ElastiCache service reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elasticache.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-elbv2/python/DOC.md",
    "content": "---\nname: mypy-boto3-elbv2\ndescription: \"Typed boto3 ELBv2 stubs for Python with install choices, typed clients, paginators, waiters, and request TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,elbv2,alb,nlb,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-elbv2 Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-elbv2` only as the typing layer for Elastic Load Balancing v2 code written with `boto3`. Keep `boto3` installed for real AWS calls, credentials, retries, and endpoints, and annotate `boto3.client(\"elbv2\")` explicitly unless you install the full `boto3-stubs[elbv2]` extra.\n\n## What This Package Gives You\n\n`mypy-boto3-elbv2` is the generated type-stub package for the ALB and NLB portion of boto3. It gives you typed definitions for:\n\n- `ElasticLoadBalancingv2Client`\n- paginator classes such as `DescribeLoadBalancersPaginator`\n- waiter classes such as `LoadBalancerAvailableWaiter`\n- `TypedDict` request and response shapes under `mypy_boto3_elbv2.type_defs`\n- generated literal unions for enum-like ELBv2 values\n\nIt does not make requests by itself and it does not replace boto3. The AWS ELBv2 boto3 reference exposes client, paginator, and waiter surfaces; there is no separate high-level boto3 resource API for `elbv2`.\n\n## Install\n\nPick the install mode based on how much type inference you want.\n\n### Standalone service-specific stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-elbv2==1.42.3\"\n```\n\nUse this when you only need ELBv2 typing and are willing to annotate the client explicitly.\n\n### Full boto3 stubs package\n\n```bash\npython -m pip install \"boto3-stubs[elbv2]\"\n```\n\nUse this when you want the bundled `Session.client(\"elbv2\")` overloads with less annotation noise.\n\n### Lower-memory fallback\n\n```bash\npython -m pip install \"boto3-stubs-lite[elbv2]\"\n```\n\nThe lite package omits the session `client(...)` and `resource(...)` overloads documented in the maintainer versioning guide, so explicit annotations are more important there.\n\n## Authentication And Configuration\n\n`mypy-boto3-elbv2` does not change AWS auth. boto3 still resolves credentials and region from the normal provider chain:\n\n1. Explicit credentials, profile, or region passed to `Session(...)` or `client(...)`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_DEFAULT_REGION`, and `AWS_PROFILE`\n3. Shared AWS config and credentials files\n4. Assume-role, IAM Identity Center, ECS task roles, Lambda execution roles, EC2 instance profiles, and other AWS runtime providers\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create the normal boto3 client and add the type annotation:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nelbv2: ElasticLoadBalancingv2Client = session.client(\n    \"elbv2\",\n    config=Config(retries={\"mode\": \"standard\", \"max_attempts\": 10}),\n)\n```\n\nIf your application spans multiple accounts or regions, keep `Session(...)` creation explicit instead of relying on the global default session.\n\n## Core Usage\n\n### Typed ELBv2 client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\n\nelbv2: ElasticLoadBalancingv2Client = Session(region_name=\"us-west-2\").client(\"elbv2\")\n\nresponse = elbv2.describe_load_balancers(Names=[\"internal-api\"])\n\nfor lb in response.get(\"LoadBalancers\", []):\n    print(lb[\"LoadBalancerArn\"], lb[\"Type\"], lb[\"State\"][\"Code\"])\n```\n\nUse the service name `elbv2`. Classic Elastic Load Balancing uses the different boto3 service name `elb`.\n\n### Typed paginator\n\nUse paginators for list-style operations instead of hand-rolling marker loops:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\nfrom mypy_boto3_elbv2.paginator import DescribeLoadBalancersPaginator\n\nelbv2: ElasticLoadBalancingv2Client = Session(region_name=\"us-west-2\").client(\"elbv2\")\npaginator: DescribeLoadBalancersPaginator = elbv2.get_paginator(\"describe_load_balancers\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 20}):\n    for lb in page.get(\"LoadBalancers\", []):\n        print(lb[\"LoadBalancerName\"])\n```\n\n### Typed waiter\n\nThe generated waiters help you keep the waiter name and parameters correct:\n\n```python\nfrom mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\nfrom mypy_boto3_elbv2.waiter import LoadBalancerAvailableWaiter\n\ndef wait_for_load_balancer(elbv2: ElasticLoadBalancingv2Client, lb_arn: str) -> None:\n    waiter: LoadBalancerAvailableWaiter = elbv2.get_waiter(\"load_balancer_available\")\n    waiter.wait(\n        LoadBalancerArns=[lb_arn],\n        WaiterConfig={\"Delay\": 15, \"MaxAttempts\": 40},\n    )\n```\n\n### Typed request dictionaries\n\nUse generated request shapes when you build ELBv2 payloads outside the call site:\n\n```python\nfrom mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\nfrom mypy_boto3_elbv2.type_defs import (\n    MatcherTypeDef,\n    RegisterTargetsInputTypeDef,\n    TargetDescriptionTypeDef,\n)\n\nmatcher: MatcherTypeDef = {\"HttpCode\": \"200-399\"}\ntargets: list[TargetDescriptionTypeDef] = [\n    {\"Id\": \"i-0123456789abcdef0\", \"Port\": 8080},\n]\nrequest: RegisterTargetsInputTypeDef = {\n    \"TargetGroupArn\": \"arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/app-tg/abc123\",\n    \"Targets\": targets,\n}\n\ndef register_targets(elbv2: ElasticLoadBalancingv2Client) -> None:\n    elbv2.register_targets(**request)\n    print(matcher[\"HttpCode\"])\n```\n\nThis is useful when request dictionaries move through helpers, background jobs, or config builders before the final boto3 call.\n\n### `TYPE_CHECKING` pattern for dev-only stubs\n\nIf the stub package is installed only in development or CI, keep the import behind `TYPE_CHECKING` so production environments do not require it:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_elbv2.client import ElasticLoadBalancingv2Client\n\ndef get_elbv2_client() -> \"ElasticLoadBalancingv2Client\":\n    return boto3.client(\"elbv2\", region_name=\"us-west-2\")\n```\n\n## Runtime Notes That Types Do Not Solve\n\n- `describe_target_health` and similar calls still require the target group ARN, region, and IAM permissions to be correct at runtime.\n- Load balancer creation and target registration are eventually consistent. A clean type check does not mean the load balancer or target group is ready yet.\n- ALB, NLB, and Gateway Load Balancer behavior differs in protocol support, health checks, and listener actions. The stubs validate shapes, not service semantics.\n- Retry mode, timeouts, endpoint selection, dual-stack, and FIPS settings still come from boto3 and botocore config, not from the stub package.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-elbv2` without `boto3`. The stubs do not make AWS calls.\n- Importing the package name with hyphens. Install with hyphens, import with underscores: `mypy_boto3_elbv2`.\n- Using the wrong boto3 service name. ALB and NLB APIs use `client(\"elbv2\")`, not `client(\"elb\")`.\n- Expecting a high-level boto3 resource API for ELBv2. This service is effectively client-first in boto3.\n- Using `boto3-stubs-lite[elbv2]` and expecting the same `Session.client(\"elbv2\")` inference as the full bundle.\n- Importing stub modules at runtime when they are installed only as dev dependencies. Use the `TYPE_CHECKING` pattern if production images omit the stubs.\n- Reusing a custom `boto3.session.Session` across threads or processes. The boto3 session guide recommends a separate `Session` object per thread or process when you need explicit sessions.\n- Assuming type safety proves runtime correctness. Region mismatches, IAM permissions, missing target groups, and target health state still fail at runtime.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, the version used here `1.42.3` matched the live PyPI project page for `mypy-boto3-elbv2`.\n- The live PyPI project page describes `1.42.3` as compatible with `boto3 1.42.3`, marks the package as `Typing :: Stubs Only`, and reports generation with `mypy-boto3-builder 8.12.0`.\n- The maintainer docs site is rolling and can surface newer family-wide version strings than the pinned package release. Treat your installed package version and the PyPI release page as the source of truth for exact version matching.\n- Repository branding has moved from `boto3-stubs` to `types-boto3`, but the published package name and Python import root remain `mypy-boto3-elbv2` and `mypy_boto3_elbv2`.\n\n## Official Source URLs\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elbv2/`\n- Maintainer paginators reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elbv2/paginators/`\n- Maintainer type definitions reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_elbv2/type_defs/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-elbv2/`\n- AWS boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- AWS boto3 session guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html`\n- AWS ELBv2 boto3 reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elbv2.html`\n- Upstream repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-emr/python/DOC.md",
    "content": "---\nname: mypy-boto3-emr\ndescription: \"mypy-boto3-emr type stubs for boto3 Amazon EMR clients, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,emr,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-emr Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-emr` is a typing package for `boto3` EMR code. It does not replace `boto3`, it does not create clusters by itself, and it does not manage AWS credentials, regions, or IAM roles.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[emr]` if you want the best editor and type-checker experience with automatic `Session.client(\"emr\")` overloads.\n- Install `mypy-boto3-emr` if you want only the EMR stub package and are willing to add explicit annotations.\n- Install `boto3-stubs-lite[emr]` if IDE memory use matters more than overload-based inference.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `mypy-boto3-emr 1.42.3`, released on `2025-08-25`, and the package description says it provides type annotations for `boto3 EMR 1.42.3`.\n- The maintainer docs say the standalone service packages use the related `boto3` version number, so pin `boto3==1.42.3` when you want predictable signature parity.\n- PyPI also shows this package was generated with `mypy-boto3-builder 8.12.0`.\n- Inference from the official sources on March 12, 2026: the version used here `1.42.3` is still the current published version for this service package.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[emr]==1.42.3\"\n```\n\nThis is the best default if you want autocomplete plus typed `Session.client(\"emr\")` without annotating every client variable.\n\n### Standalone EMR stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-emr==1.42.3\"\n```\n\nUse this when you want only the EMR service stubs. In this mode, explicit annotations are usually necessary.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[emr]==1.42.3\"\n```\n\nThe lite package is more memory-friendly, especially for PyCharm, but it does not provide `Session.client(\"emr\")` overloads. Add explicit annotations if you use it.\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"boto3-stubs[emr]==1.42.3\"\npoetry add \"boto3==1.42.3\" \"boto3-stubs[emr]==1.42.3\"\n```\n\n## Runtime Setup And Auth\n\n`mypy-boto3-emr` adds no runtime setup of its own. All real behavior still comes from `boto3`.\n\nAWS documents that boto3 resolves credentials from a standard provider chain that includes:\n\n- credentials passed directly to `boto3.client(...)`\n- credentials passed to `boto3.Session(...)`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_PROFILE`, and `AWS_DEFAULT_REGION`\n- shared config in `~/.aws/credentials` and `~/.aws/config`\n- assume-role, IAM Identity Center, container credentials, and EC2 instance metadata\n\nSafe local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nExplicit session setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nemr = session.client(\"emr\")\n```\n\nFor `run_job_flow`, remember that typing only validates request shapes. Runtime success still depends on EMR prerequisites such as subnet/networking choices, instance profiles, service roles, release labels, and region-specific availability.\n\n## Core Usage\n\n### Typed client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_emr.client import EMRClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nemr: EMRClient = session.client(\"emr\")\n\nresponse = emr.list_clusters(\n    ClusterStates=[\"STARTING\", \"BOOTSTRAPPING\", \"RUNNING\", \"WAITING\"],\n)\n\nfor cluster in response.get(\"Clusters\", []):\n    print(cluster[\"Id\"], cluster[\"Name\"], cluster[\"Status\"][\"State\"])\n```\n\nAWS documents boto3 clients as the low-level interface that maps closely to the full service API. That is the right mental model for EMR here: this package types the EMR control-plane API surface, not Spark code, bootstrap scripts, or data-processing logic inside a cluster.\n\n### Keep stubs dev-only with `TYPE_CHECKING`\n\nIf production images do not install stub packages, gate the imports and cast the client:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_emr.client import EMRClient\n\nemr = cast(\"EMRClient\", boto3.Session(region_name=\"us-east-1\").client(\"emr\"))\n```\n\n### Typed paginators\n\nThe generated docs expose paginator types for common list operations such as:\n\n- `list_bootstrap_actions`\n- `list_clusters`\n- `list_instance_fleets`\n- `list_instance_groups`\n- `list_instances`\n- `list_steps`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_emr.client import EMRClient\nfrom mypy_boto3_emr.paginator import ListClustersPaginator\n\nclient: EMRClient = Session(region_name=\"us-east-1\").client(\"emr\")\npaginator: ListClustersPaginator = client.get_paginator(\"list_clusters\")\n\nfor page in paginator.paginate(ClusterStates=[\"RUNNING\", \"WAITING\"]):\n    for cluster in page.get(\"Clusters\", []):\n        print(cluster[\"Id\"], cluster[\"Name\"])\n```\n\n### Typed waiters\n\nThe generated docs expose waiter types including:\n\n- `cluster_running`\n- `cluster_terminated`\n- `step_complete`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_emr.client import EMRClient\nfrom mypy_boto3_emr.waiter import ClusterRunningWaiter\n\nclient: EMRClient = Session(region_name=\"us-east-1\").client(\"emr\")\nwaiter: ClusterRunningWaiter = client.get_waiter(\"cluster_running\")\nwaiter.wait(ClusterId=\"j-ABCDEFGHIJKL\")\n```\n\n### Literals and TypedDicts\n\nUse `literals` when an EMR field is a constrained string union, and use `type_defs` when helper functions build request payloads or normalize responses.\n\n```python\nfrom mypy_boto3_emr.literals import ClusterStateTypeType\n\ndef is_active_state(state: ClusterStateTypeType) -> bool:\n    return state in {\"STARTING\", \"BOOTSTRAPPING\", \"RUNNING\", \"WAITING\"}\n```\n\nThis is useful when code branches on cluster state, step state, action-on-failure settings, or instance-group configuration values.\n\n## Configuration Notes\n\n- `mypy-boto3-emr` focuses on the EMR client surface. Do not expect a rich boto3 resource layer like `service_resource` modules here.\n- The stub package helps type-check `client.get_paginator(...)`, `client.get_waiter(...)`, literal unions, and request or response `TypedDict` shapes exposed under `mypy_boto3_emr.type_defs`.\n- Keep the `boto3` runtime version aligned with the EMR stub version. Mismatched versions can still run, but the method signatures and enum values your editor sees may drift.\n- EMR examples often fail for runtime reasons that typing cannot catch: invalid `ReleaseLabel`, missing `JobFlowRole` or `ServiceRole`, subnet constraints, unavailable instance types, or region mismatches.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-emr` and expecting unannotated `Session.client(\"emr\")` calls to become typed automatically. That behavior comes from `boto3-stubs[emr]`.\n- Forgetting to install `boto3`. These packages are type stubs, not the runtime AWS SDK.\n- Treating `mypy-boto3-emr` as if it validates EMR job semantics. It checks Python shapes, not whether a cluster config is valid for your account or region.\n- Importing stub modules at runtime in production environments that do not install them. Use `TYPE_CHECKING` if stubs are dev-only.\n- Using `boto3-stubs-lite[emr]` and expecting overload-based inference from `Session.client(\"emr\")`. Lite mode needs more explicit annotations.\n- Guessing waiter or paginator names from older blog posts. Pull them from the generated docs for the exact service package version you installed.\n- Assuming typed examples cover EMR Serverless or the on-cluster Spark API surface. This package only types the classic boto3 EMR service client.\n\n## Official Sources\n\n- Docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_emr/`\n- PyPI: `https://pypi.org/project/mypy-boto3-emr/`\n- Source repository: `https://github.com/youtype/types-boto3`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- Boto3 clients guide: `https://docs.aws.amazon.com/boto3/latest/guide/clients.html`\n- Boto3 EMR service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/emr.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-events/python/DOC.md",
    "content": "---\nname: mypy-boto3-events\ndescription: \"Typed stubs for the boto3 EventBridge client, paginators, literals, and TypedDicts in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,eventbridge,boto3,typing,stubs,mypy\"\n---\n\n# mypy-boto3-events Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-events` is a typing package for the boto3 EventBridge client. It does not replace `boto3`, it does not send requests by itself, and it does not configure AWS credentials for you.\n\nUse it when you want:\n\n- typed `boto3.client(\"events\")` calls\n- typed paginator objects\n- generated `TypedDict` request and response shapes\n- literal types for constrained EventBridge string values\n\nKeep the runtime and typing story separate:\n\n- Install `boto3` for runtime AWS calls\n- Install `mypy-boto3-events` or `boto3-stubs[events]` for type checking and editor support\n- Configure auth, region, retries, and endpoints through boto3 and botocore\n\n## Install\n\nInstall the direct service stub package when you only need EventBridge typing:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-events==1.42.3\"\n```\n\nUpstream also publishes the aggregated extras:\n\n```bash\npython -m pip install \"boto3-stubs[events]\"\npython -m pip install \"boto3-stubs-lite[events]\"\n```\n\nUse `boto3-stubs[events]` when you want the standard bundled install flow from the maintainer docs. Use `boto3-stubs-lite[events]` when you want lighter runtime dependencies and are comfortable with more explicit type annotations.\n\n## Initialize And Setup\n\n### Typed client setup\n\n```python\nimport boto3\nfrom mypy_boto3_events import EventBridgeClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\nevents: EventBridgeClient = session.client(\"events\")\n```\n\n### If the typing package is dev-only\n\nIf production images do not install the stub wheel, keep the type import behind `TYPE_CHECKING` and cast the client:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_events import EventBridgeClient\n\nevents = cast(\"EventBridgeClient\", boto3.client(\"events\", region_name=\"us-east-1\"))\n```\n\nThis keeps runtime imports clean while preserving editor and mypy support.\n\n## Core Usage\n\n### Publish events with typed request entries\n\nThe generated `type_defs` module includes request shapes such as `PutEventsRequestEntryTypeDef`.\n\n```python\nimport json\n\nfrom mypy_boto3_events import EventBridgeClient\nfrom mypy_boto3_events.type_defs import PutEventsRequestEntryTypeDef\n\ndef publish_order_created(events: EventBridgeClient) -> None:\n    entries: list[PutEventsRequestEntryTypeDef] = [\n        {\n            \"Source\": \"com.example.orders\",\n            \"DetailType\": \"order.created\",\n            \"Detail\": json.dumps({\"order_id\": \"123\"}),\n            \"EventBusName\": \"default\",\n        }\n    ]\n\n    response = events.put_events(Entries=entries)\n\n    if response[\"FailedEntryCount\"]:\n        raise RuntimeError(response[\"Entries\"])\n```\n\n`put_events` requires `Entries`, and EventBridge expects `Detail` to be a JSON string for application events. Do not pass a raw Python dict.\n\n### Use typed paginators\n\nThe maintainer docs expose paginator types such as `ListRuleNamesByTargetPaginator`.\n\n```python\nfrom mypy_boto3_events import EventBridgeClient\nfrom mypy_boto3_events.paginator import ListRuleNamesByTargetPaginator\n\ndef list_rule_names_by_target(\n    events: EventBridgeClient,\n    target_arn: str,\n) -> list[str]:\n    paginator: ListRuleNamesByTargetPaginator = events.get_paginator(\n        \"list_rule_names_by_target\"\n    )\n    names: list[str] = []\n\n    for page in paginator.paginate(TargetArn=target_arn):\n        names.extend(page.get(\"RuleNames\", []))\n\n    return names\n```\n\n### Use literals for constrained values\n\nThe package also exports literal unions for enum-like fields:\n\n```python\nfrom mypy_boto3_events.literals import RuleStateType\n\nstate: RuleStateType = \"ENABLED\"\n```\n\nThis is mainly useful for catching misspelled constants before runtime.\n\n## Auth And Configuration\n\nAuthentication comes from boto3. The stubs package does not add a separate auth layer.\n\nBoto3 checks several credential sources, including:\n\n1. explicit parameters passed when creating a client or session\n2. environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. shared config and credentials files under `~/.aws/`\n4. assume-role and web-identity configuration\n5. container or instance role credentials\n\nPractical setup:\n\n```python\nimport boto3\nfrom botocore.config import Config\nfrom mypy_boto3_events import EventBridgeClient\n\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n)\n\nevents: EventBridgeClient = boto3.client(\"events\", config=config)\n```\n\nNotes:\n\n- Set `region_name` explicitly in local scripts and tests when the environment is ambiguous.\n- Keep credential selection on the boto3 session or client, not in your typing layer.\n- Use `botocore.config.Config` for retries, timeouts, proxies, and endpoint tuning.\n\n## Common Pitfalls\n\n- `mypy-boto3-events` is typing-only. Without `boto3`, your code will type-check but cannot call AWS.\n- The names differ: install `mypy-boto3-events`, import `mypy_boto3_events`, and create the runtime client with service name `\"events\"`.\n- The typed client class is `EventBridgeClient`, not the older `EventsClient` name used in some stale examples.\n- `put_events` expects `Detail` as a serialized JSON string for custom event payloads.\n- `boto3-stubs-lite[events]` can require more explicit annotations or casts because it is optimized for lighter installs.\n- The docs site may be generated from a newer boto3-stubs build than the latest standalone PyPI wheel, so version drift is possible between type docs and the package you can install.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matches the current PyPI project page for `mypy-boto3-events`.\n- PyPI shows `1.42.3` as the latest installable release, published on December 4, 2025.\n- As of March 12, 2026, the maintainer docs root is generated from a newer boto3 line and currently brands this module as `1.42.46` documentation.\n- The docs root also shows local-generation examples pinned to `boto3==1.42.46`, which is newer than the standalone stub wheel on PyPI.\n- Before pinning dependencies, verify the versions of `boto3`, `botocore`, and the installed stub package in the same environment. If the docs site is ahead of the wheel, prefer the installed package metadata over the moving `/latest` docs branding.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_events/`\n- Maintainer paginator reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_events/paginators/`\n- Maintainer type-def reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_events/type_defs/#puteventsrequestentrytypedef`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-events/`\n- Boto3 EventBridge `put_events` reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/events/client/put_events.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-evidently/python/DOC.md",
    "content": "---\nname: mypy-boto3-evidently\ndescription: \"mypy-boto3-evidently type stubs for typed boto3 CloudWatch Evidently clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.35\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,boto3,evidently,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-evidently Python Package Guide\n\n## What It Is\n\n`mypy-boto3-evidently` adds static types for the `boto3` `evidently` client surface. Use it for editor completion and type checking around `CloudWatchEvidentlyClient`, paginator classes, `Literal` enums, and `TypedDict` request and response shapes.\n\nIt does not replace `boto3`, and it does not configure credentials, regions, or retries for you.\n\nImportant context: AWS documents that CloudWatch Evidently support ended on October 16, 2025. In practice, this package is mainly useful for maintaining or migrating older code that still imports or types legacy Evidently calls.\n\n## Install\n\n`mypy-boto3-evidently` is a stubs-only package. Keep `boto3` installed for runtime AWS calls.\n\n### Recommended for most projects\n\nUse the service extra when you want `Session.client(\"evidently\")` type inference without annotating every variable:\n\n```bash\npython -m pip install boto3 \"boto3-stubs[evidently]\"\n```\n\n### Standalone service stubs\n\nUse this when you only want the Evidently stubs package and are fine with explicit annotations:\n\n```bash\npython -m pip install boto3 mypy-boto3-evidently\n```\n\n### Lower-memory IDE fallback\n\nThe lite package is more memory-friendly, but upstream notes that it does not provide `session.client()` and `session.resource()` overloads:\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[evidently]\"\n```\n\n### Exact-match local generation\n\nThe maintainer recommends local generation when you need stubs that exactly match a pinned `boto3` build:\n\n```bash\nuvx --with \"boto3==1.42.35\" mypy-boto3-builder\n```\n\nThen choose `boto3-stubs` and the `CloudWatchEvidently` service.\n\n## AWS Auth And Client Initialization\n\n`mypy-boto3-evidently` has no package-specific initialization. Use normal `boto3` credential and region configuration.\n\nAWS documents that Boto3 requests need both credentials and an AWS Region. Common local setup:\n\n```bash\nexport AWS_PROFILE=legacy-evidently\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nor:\n\n```bash\naws configure\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_evidently import CloudWatchEvidentlyClient\n\nsession = Session(profile_name=\"legacy-evidently\", region_name=\"us-west-2\")\nevidently: CloudWatchEvidentlyClient = session.client(\"evidently\")\n```\n\nIf you need client-specific retry or region overrides, pass a `botocore.config.Config` object when creating the client.\n\n## Core Usage\n\n### Inspect a legacy project\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_evidently import CloudWatchEvidentlyClient\n\nevidently: CloudWatchEvidentlyClient = Session(\n    profile_name=\"legacy-evidently\",\n    region_name=\"us-west-2\",\n).client(\"evidently\")\n\nproject = evidently.get_project(project=\"legacy-project\")[\"project\"]\nprint(project[\"name\"], project[\"status\"], project[\"featureCount\"])\n```\n\n### Typed `evaluate_feature` request\n\nAWS documents `evaluate_feature` with `project`, `feature`, and `entityId` as required parameters, and `evaluationContext` as an optional JSON object string.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_evidently import CloudWatchEvidentlyClient\nfrom mypy_boto3_evidently.type_defs import EvaluationRequestTypeDef\n\nevidently: CloudWatchEvidentlyClient = Session(region_name=\"us-west-2\").client(\n    \"evidently\"\n)\n\nrequest: EvaluationRequestTypeDef = {\n    \"project\": \"legacy-project\",\n    \"feature\": \"checkout-banner\",\n    \"entityId\": \"user-123\",\n    \"evaluationContext\": '{\"plan\":\"pro\"}',\n}\n\nresponse = evidently.evaluate_feature(**request)\nprint(response[\"variation\"])\nprint(response[\"value\"])\n```\n\n### Typed paginator for project discovery\n\nThe maintainer publishes paginator types for `list_experiments`, `list_features`, `list_launches`, `list_projects`, `list_segment_references`, and `list_segments`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_evidently import CloudWatchEvidentlyClient\nfrom mypy_boto3_evidently.paginator import ListProjectsPaginator\n\nevidently: CloudWatchEvidentlyClient = Session(region_name=\"us-west-2\").client(\n    \"evidently\"\n)\n\npaginator: ListProjectsPaginator = evidently.get_paginator(\"list_projects\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 20}):\n    for project in page.get(\"projects\", []):\n        print(project[\"name\"], project[\"status\"])\n```\n\n### Sending project events\n\nAWS documents `put_project_events` with a required `project` and an `events` list containing `data`, `timestamp`, and `type`.\n\n```python\nimport json\nfrom datetime import datetime, timezone\n\nfrom boto3.session import Session\nfrom mypy_boto3_evidently import CloudWatchEvidentlyClient\n\nevidently: CloudWatchEvidentlyClient = Session(region_name=\"us-west-2\").client(\n    \"evidently\"\n)\n\nevidently.put_project_events(\n    project=\"legacy-project\",\n    events=[\n        {\n            \"data\": json.dumps({\"name\": \"checkout-click\", \"user\": \"user-123\"}),\n            \"timestamp\": datetime.now(timezone.utc),\n            \"type\": \"aws.evidently.custom\",\n        }\n    ],\n)\n```\n\nIf you are maintaining old client-side evaluation code that targets the AWS AppConfig Lambda extension on `localhost`, AWS shows configuring the boto3 client with `endpoint_url=\"http://localhost:2772\"` and `Config(inject_host_prefix=False)`.\n\n## Type-Checking Patterns\n\n### Keep stub imports behind `TYPE_CHECKING`\n\nIf production environments do not install stubs, avoid a runtime dependency:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_evidently import CloudWatchEvidentlyClient\nelse:\n    CloudWatchEvidentlyClient = object\n\ndef make_client() -> \"CloudWatchEvidentlyClient\":\n    return Session(region_name=\"us-west-2\").client(\"evidently\")\n```\n\n### Use generated literals and `TypedDict` shapes\n\n```python\nfrom mypy_boto3_evidently.literals import ChangeDirectionEnumType\nfrom mypy_boto3_evidently.type_defs import EvaluationRequestTypeDef\n\ndirection: ChangeDirectionEnumType = \"INCREASE\"\n\nrequest: EvaluationRequestTypeDef = {\n    \"project\": \"legacy-project\",\n    \"feature\": \"checkout-banner\",\n    \"entityId\": \"user-123\",\n}\n```\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-evidently` and expecting it to make AWS calls by itself. Runtime calls still come from `boto3`.\n- Forgetting AWS credentials or a Region. AWS documents that both are required for Boto3 requests.\n- Expecting `session.client(\"evidently\")` inference from `boto3-stubs-lite[evidently]`. The lite package needs more explicit annotations.\n- Treating CloudWatch Evidently as an active AWS service. AWS ended support on October 16, 2025.\n- Assuming old AppConfig-backed localhost evaluation code uses normal Evidently IAM enforcement. AWS documents that client-side evaluation uses a different access-control model.\n- Using the full stub package in PyCharm when IDE performance is already tight. Upstream recommends the lite variant if overloads become too heavy.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `mypy-boto3-evidently 1.42.35`, which PyPI lists as requiring Python 3.9 or newer.\n- The maintainer describes these packages as version-matched to the related `boto3` service model. Pin `boto3` and `mypy-boto3-evidently` together when exact request and response shapes matter.\n- AWS documents that CloudWatch Evidently support ended on October 16, 2025, so new projects should not start on this service.\n\n## Official Sources\n\n- Package page: https://pypi.org/project/mypy-boto3-evidently/\n- Exact release page: https://pypi.org/project/mypy-boto3-evidently/1.42.35/\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_evidently/\n- Builder repository: https://github.com/youtype/mypy_boto3_builder\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n- Boto3 `evaluate_feature`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/evidently/client/evaluate_feature.html\n- Boto3 `put_project_events`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/evidently/client/put_project_events.html\n- Boto3 `ListProjects` paginator: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/evidently/paginator/ListProjects.html\n- AWS CloudWatch Evidently client-side evaluation guide: https://docs.aws.amazon.com/en_us/AmazonCloudWatch/latest/monitoring/CloudWatch-Evidently-client-side-evaluation.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-firehose/python/DOC.md",
    "content": "---\nname: mypy-boto3-firehose\ndescription: \"mypy-boto3-firehose package guide for typed boto3 Firehose clients in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,firehose,boto3,type-stubs,mypy,pyright\"\n---\n\n# mypy-boto3-firehose Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for the runtime Firehose client and use `mypy-boto3-firehose` only to add static types for editors, mypy, and pyright.\n\nIf you want `Session.client(\"firehose\")` to infer the service type automatically, install `boto3-stubs[firehose]`. If you prefer the smaller service-only package, install `mypy-boto3-firehose` and annotate the client explicitly.\n\n## Install\n\nService-only stubs:\n\n```bash\npython -m pip install \"mypy-boto3-firehose==1.42.3\" \"boto3==1.42.3\"\n```\n\nBundled boto3 stubs with Firehose extras:\n\n```bash\npython -m pip install \"boto3-stubs[firehose]==1.42.3\"\n```\n\nLite variant if you do not want the heavy `boto3-stubs` session overloads:\n\n```bash\npython -m pip install \"boto3-stubs-lite[firehose]==1.42.3\"\n```\n\nOther package managers:\n\n```bash\nuv add \"mypy-boto3-firehose==1.42.3\" \"boto3==1.42.3\"\npoetry add \"mypy-boto3-firehose==1.42.3\" \"boto3==1.42.3\"\n```\n\n## Setup And Authentication\n\nThis package does not configure AWS credentials by itself. Authentication, region selection, retries, custom endpoints, and profiles all come from the normal `boto3` and `botocore` setup.\n\nCommon credential sources for `boto3`:\n\n1. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n2. Shared AWS config in `~/.aws/config` and `~/.aws/credentials`\n3. IAM roles or workload credentials when running on AWS\n\nBasic setup:\n\n```bash\naws configure\n```\n\nTyped client with an explicit annotation:\n\n```python\nimport boto3\nfrom mypy_boto3_firehose import FirehoseClient\n\nsession = boto3.session.Session(profile_name=\"dev\", region_name=\"us-east-1\")\nfirehose: FirehoseClient = session.client(\"firehose\")\n```\n\nIf you need a non-AWS endpoint, keep using normal boto3 client arguments:\n\n```python\nimport boto3\nfrom mypy_boto3_firehose import FirehoseClient\n\nsession = boto3.session.Session(region_name=\"us-east-1\")\nfirehose: FirehoseClient = session.client(\n    \"firehose\",\n    endpoint_url=\"http://localhost:4566\",\n)\n```\n\n## Core Usage\n\n### Annotate the client without changing runtime behavior\n\nThe stubs package is useful even if you keep runtime imports limited to `boto3`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_firehose import FirehoseClient\n\nsession = boto3.session.Session(region_name=\"us-east-1\")\nfirehose: \"FirehoseClient\" = session.client(\"firehose\")\n```\n\nThis pattern keeps the import type-only while still giving completions and static checking.\n\n### Type request payloads with generated `TypedDict` definitions\n\nThe package publishes service-specific `TypedDict` names for Firehose request and response shapes. `RecordTypeDef` is useful for producer code that batches records:\n\n```python\nimport json\n\nimport boto3\nfrom mypy_boto3_firehose import FirehoseClient\nfrom mypy_boto3_firehose.type_defs import RecordTypeDef\n\nsession = boto3.session.Session(region_name=\"us-east-1\")\nfirehose: FirehoseClient = session.client(\"firehose\")\n\nrecord: RecordTypeDef = {\n    \"Data\": (json.dumps({\"event\": \"signup\", \"user_id\": 123}) + \"\\n\").encode(\"utf-8\"),\n}\n\nresponse = firehose.put_record_batch(\n    DeliveryStreamName=\"events-stream\",\n    Records=[record],\n)\n\nif response[\"FailedPutCount\"]:\n    raise RuntimeError(response[\"RequestResponses\"])\n```\n\nOther useful generated Firehose shapes documented upstream include:\n\n- `CreateDeliveryStreamInputTypeDef`\n- `DeliveryStreamDescriptionTypeDef`\n- `TagDeliveryStreamInputRequestTypeDef`\n\n### Use literal types when AWS expects specific string enums\n\nThe stubs package also exposes literal aliases for enum-like string values:\n\n```python\nfrom mypy_boto3_firehose.literals import AmazonOpenSearchServerlessS3BackupModeType\n\nbackup_mode: AmazonOpenSearchServerlessS3BackupModeType = \"AllDocuments\"\n```\n\nThis is most useful when you build larger typed config dictionaries for `create_delivery_stream(...)`.\n\n### Get automatic client inference with `boto3-stubs[firehose]`\n\nWith the full `boto3-stubs` extra, `Session.client(\"firehose\")` is overloaded so manual annotations are often unnecessary:\n\n```python\nimport boto3\n\nsession = boto3.session.Session(region_name=\"us-east-1\")\nfirehose = session.client(\"firehose\")\n```\n\nWith the standalone `mypy-boto3-firehose` package or the lite variant, prefer explicit annotations.\n\n## Configuration Notes\n\n- Keep `boto3`, `botocore`, and the stubs package on matching release lines when possible. The package version tracks the boto3 model version it was generated from.\n- Region matters for Firehose stream operations. Set `region_name` explicitly when the environment could be ambiguous.\n- Custom retry config, STS assume-role flows, and endpoint overrides belong on the boto3 session or client, not in the stubs package.\n- Firehose streams are service resources, not local objects. Creating or updating a delivery stream can be asynchronous on the AWS side even though the typed method call returns immediately.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-firehose` as a runtime SDK. It adds types; the actual API calls still come from `boto3`.\n- Do not assume the standalone package gives you overloaded `Session.client(\"firehose\")`. That convenience comes from `boto3-stubs`, while `boto3-stubs-lite` explicitly omits those overloads.\n- Do not let your stubs drift far from your boto3 version. Missing methods or stale `TypedDict` fields usually mean the model versions no longer match.\n- Keep type-only imports behind `TYPE_CHECKING` if you do not want the stubs package imported at runtime.\n- Firehose `put_record` and `put_record_batch` accept bytes payloads. Encode structured data yourself, typically JSON Lines for downstream S3-based destinations.\n- For stream creation flows, validate the destination-specific config against the live AWS Firehose API docs. The stubs help with field names and literals, but they do not replace service-side validation rules.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI currently lists `1.42.3` as the package version and marks it compatible with `boto3 1.42.3`.\n- PyPI classifiers for `1.42.3` include Python `3.9` through `3.14`, with `Requires: Python >=3.9`.\n- The package page shows `mypy-boto3-builder 8.12.0` as the generator used for this release.\n- The published docs for this package live under the `youtype.github.io` generated docs tree and match the `1.42.3` release line on March 12, 2026.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/mypy-boto3-firehose/\n- Package docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_firehose/\n- Firehose typed definitions: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_firehose/type_defs/\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 Firehose client reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/firehose.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-forecast/python/DOC.md",
    "content": "---\nname: mypy-boto3-forecast\ndescription: \"mypy-boto3-forecast type stubs for boto3 Amazon Forecast clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,mypy,typing,stubs,forecast,python\"\n---\n\n# mypy-boto3-forecast Python Package Guide\n\n## What It Is\n\n`mypy-boto3-forecast` is a typing-only companion package for `boto3`'s Amazon Forecast client.\n\nUse it when your code already talks to AWS through `boto3` and you want:\n\n- typed `forecast` client methods\n- paginator types for Forecast list operations\n- generated `TypedDict` request and response shapes\n- better `mypy`, `pyright`, and IDE completion\n\nIt does not create runtime clients, does not replace `boto3`, and does not change AWS auth or transport behavior.\n\n## Install\n\nIf you want the small service-specific package and you are fine adding explicit client annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-forecast==1.42.3\"\n```\n\nIf you want `session.client(\"forecast\")` and `boto3.client(\"forecast\")` to resolve more automatically in editors and type checkers:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[forecast]==1.42.3\"\n```\n\nIf you need a lighter typing package and can live with explicit annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[forecast]==1.42.3\"\n```\n\nPractical rule:\n\n- use `mypy-boto3-forecast` for the smallest Forecast-only typing dependency\n- use `boto3-stubs[forecast]` when you want better boto3 overloads across normal client creation\n- keep the stub package aligned with the `boto3` version family already pinned by the project\n\n## Initialize And Set Up\n\n`mypy-boto3-forecast` does not change how you create sessions. Start with normal `boto3` setup and then type the client explicitly.\n\n```python\nfrom typing import cast\n\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_forecast.client import ForecastServiceClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\nforecast = cast(\n    ForecastServiceClient,\n    session.client(\n        \"forecast\",\n        config=Config(\n            retries={\"mode\": \"standard\", \"max_attempts\": 10},\n            connect_timeout=5,\n            read_timeout=60,\n        ),\n    ),\n)\n\nresponse = forecast.list_predictors(MaxResults=20)\n\nfor predictor in response.get(\"Predictors\", []):\n    print(predictor[\"PredictorArn\"])\n```\n\nWhy `cast(...)` here:\n\n- it works reliably with the standalone `mypy-boto3-forecast` package\n- it makes the intended service type obvious\n- it avoids relying on broader boto3 overload packages\n\nIf the environment installs `boto3-stubs[forecast]`, you can often skip the `cast` and annotate directly because the boto3 session overloads are available.\n\n## Authentication And Configuration\n\nAuth still comes entirely from boto3 and botocore. Use the normal AWS credential chain:\n\n1. explicit credentials passed to `Session(...)` or `client(...)`\n2. environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. shared AWS config and credentials files\n4. IAM role or container credentials in AWS-hosted environments\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create the client normally:\n\n```python\nfrom boto3.session import Session\nfrom typing import cast\n\nfrom mypy_boto3_forecast.client import ForecastServiceClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nforecast = cast(ForecastServiceClient, session.client(\"forecast\"))\n```\n\nFor agent-generated code:\n\n- prefer IAM roles in deployed environments\n- prefer named profiles locally\n- use `botocore.config.Config(...)` for retries, timeouts, proxies, and retry mode\n- do not hardcode long-lived AWS credentials\n\n## Core Typed Usage\n\n### Client Type\n\nThe main client type lives at:\n\n```python\nfrom mypy_boto3_forecast.client import ForecastServiceClient\n```\n\nThat type gives you typed methods for the Forecast service operations exposed by boto3's `forecast` client.\n\n### Paginators\n\nThe generated package includes paginator classes for Forecast list operations.\n\n```python\nfrom typing import cast\n\nfrom boto3.session import Session\nfrom mypy_boto3_forecast.client import ForecastServiceClient\nfrom mypy_boto3_forecast.paginator import ListPredictorsPaginator\n\nsession = Session(region_name=\"us-west-2\")\nforecast = cast(ForecastServiceClient, session.client(\"forecast\"))\n\npaginator = cast(\n    ListPredictorsPaginator,\n    forecast.get_paginator(\"list_predictors\"),\n)\n\nfor page in paginator.paginate():\n    for predictor in page.get(\"Predictors\", []):\n        print(predictor[\"PredictorName\"])\n```\n\nUse typed paginators instead of handwritten `NextToken` loops when the API supports them.\n\n### Literals And Type Definitions\n\nThe package also exposes:\n\n- `mypy_boto3_forecast.literals`\n- `mypy_boto3_forecast.type_defs`\n\nUse them when request payloads or enum-like string values get large enough that plain `dict[str, object]` becomes error-prone.\n\n### `TYPE_CHECKING` Pattern\n\nIf you want runtime environments to depend only on `boto3`, keep the stub package as a dev dependency and import it only for type checking:\n\n```python\nfrom typing import TYPE_CHECKING, Any, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_forecast.client import ForecastServiceClient\nelse:\n    ForecastServiceClient = Any\n\ndef get_forecast_client(session: Session) -> ForecastServiceClient:\n    return cast(ForecastServiceClient, session.client(\"forecast\"))\n```\n\nThis is a good default when CI runs `mypy` or `pyright` but production images stay minimal.\n\n## Common Pitfalls\n\n- `mypy-boto3-forecast` is not a runtime SDK. You still need `boto3`.\n- The package name uses hyphens, but Python imports use underscores: `mypy_boto3_forecast`.\n- `forecast` and `forecastquery` are different boto3 services. Query-time APIs use a separate package: `mypy-boto3-forecastquery`.\n- If you only install the service-specific stub package, `session.client(\"forecast\")` usually needs an explicit type annotation or `cast`.\n- If `boto3`, `botocore`, and the stub package drift apart, generated signatures and `TypedDict` shapes can stop matching the runtime SDK.\n- These stubs improve type checking only. Runtime failures from IAM, region support, service quotas, or invalid resources still come from AWS.\n\n## Version-Sensitive Notes\n\nThis entry is intentionally pinned to the version used here `1.42.3`.\n\nUpstream visibility is inconsistent:\n\n- the searchable PyPI result for `mypy-boto3-forecast` still surfaced `1.40.17` during this review\n- related official package-family pages, including `mypy-boto3`, `mypy-boto3-forecastquery`, and `types-boto3-forecast`, surfaced `1.42.3`\n- the maintainer docs index is generated by `mypy-boto3-builder 8.12.0`, which matches the newer 1.42.x package family rather than the stale `1.40.17` search snippet\n\nTreat that as an indexing or publication-visibility mismatch and re-check the canonical package release against the package page if you need exact release provenance.\n\nFor code generation, the practical rule remains: match the stub package to the `boto3` family already pinned in the project.\n\n## Amazon Forecast Availability Note\n\nAWS documents that Amazon Forecast is no longer available to new customers. Existing customers can continue to use it.\n\nThat matters because your typed code can still be correct while account setup or enablement fails for business reasons rather than SDK reasons.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_forecast/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-forecast/`\n- Maintainer repository: `https://github.com/youtype/boto3-stubs`\n- Boto3 Forecast client reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/forecast.html`\n- Amazon Forecast API reference: `https://docs.aws.amazon.com/forecast/latest/dg/API_Operations_Amazon_Forecast_Service.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-fsx/python/DOC.md",
    "content": "---\nname: mypy-boto3-fsx\ndescription: \"Typed boto3 stubs for Amazon FSx clients, paginators, literals, and TypedDict request and response shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,fsx,boto3,typing,mypy,pyright,stubs,python\"\n---\n\n# mypy-boto3-fsx Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-fsx` adds static types for `boto3.client(\"fsx\")`. It is not a runtime SDK.\n\n- Keep `boto3` installed for actual AWS requests, credentials, retries, and endpoints.\n- Use `boto3-stubs[fsx]` if you want automatic typing for `Session.client(\"fsx\")`.\n- Use `mypy-boto3-fsx` or `boto3-stubs-lite[fsx]` when you want a narrower install and are willing to annotate the client explicitly.\n\n## Install\n\n### Full boto3 stubs\n\nUse this when you want overloaded `Session.client(\"fsx\")` inference in editors and type checkers:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[fsx]==1.42.3\"\n```\n\n### Standalone FSx stubs\n\nUse this when you only need FSx typing and are fine with explicit annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-fsx==1.42.3\"\n```\n\n### Lite stubs\n\nUse this when install size or IDE performance matters more than overload-based inference:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[fsx]==1.42.3\"\n```\n\nThe maintainer docs note that the lite package does not provide `session.client/resource` overloads and is more RAM-friendly. The PyPI package page also recommends the lite variant for PyCharm when `Literal` overload performance becomes a problem.\n\nOther package managers:\n\n```bash\nuv add \"boto3==1.42.3\" \"mypy-boto3-fsx==1.42.3\"\npoetry add \"boto3==1.42.3\" \"mypy-boto3-fsx==1.42.3\"\n```\n\n## Authentication And Configuration\n\n`mypy-boto3-fsx` does not add package-specific configuration. FSx auth and region handling come from normal boto3 behavior.\n\nAWS documents this credential search order for boto3:\n\n1. Credentials passed directly to `boto3.client(...)`\n2. Credentials passed when creating a `Session(...)`\n3. Environment variables\n4. Assume-role providers\n5. Shared AWS config and credential files and later providers in the standard chain\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nExplicit session setup is safer when code can run in multiple accounts or regions:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_fsx import FSxClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nfsx: FSxClient = session.client(\"fsx\")\n```\n\nIf you need client-specific retries, proxies, or a forced region, keep using normal boto3 and botocore config objects:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_fsx import FSxClient\n\nconfig = Config(region_name=\"us-west-2\", retries={\"mode\": \"standard\", \"max_attempts\": 10})\nfsx: FSxClient = Session().client(\"fsx\", config=config)\n```\n\n## Core Usage\n\n### Typed FSx client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_fsx import FSxClient\n\nfsx: FSxClient = Session(region_name=\"us-west-2\").client(\"fsx\")\n\nresponse = fsx.describe_file_systems()\nfor file_system in response.get(\"FileSystems\", []):\n    print(file_system[\"FileSystemId\"], file_system[\"Lifecycle\"])\n```\n\n### Typed paginator\n\nThe generated package includes paginator types such as `DescribeFileSystemsPaginator` and `DescribeVolumesPaginator`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_fsx import FSxClient\nfrom mypy_boto3_fsx.paginator import DescribeFileSystemsPaginator\n\nfsx: FSxClient = Session(region_name=\"us-west-2\").client(\"fsx\")\npaginator: DescribeFileSystemsPaginator = fsx.get_paginator(\"describe_file_systems\")\n\nfor page in paginator.paginate():\n    for file_system in page.get(\"FileSystems\", []):\n        print(file_system[\"FileSystemId\"])\n```\n\n### Literals and TypedDict request and response shapes\n\nUse literal aliases for enum-like strings and `type_defs` for request or response dictionaries passed between helpers:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_fsx import FSxClient\nfrom mypy_boto3_fsx.literals import FileSystemTypeType\nfrom mypy_boto3_fsx.type_defs import DescribeFileSystemsResponseTypeDef\n\nexpected_type: FileSystemTypeType = \"LUSTRE\"\nfsx: FSxClient = Session(region_name=\"us-west-2\").client(\"fsx\")\nresponse: DescribeFileSystemsResponseTypeDef = fsx.describe_file_systems()\n\nfor item in response.get(\"FileSystems\", []):\n    if item[\"FileSystemType\"] == expected_type:\n        print(item[\"FileSystemId\"])\n```\n\n### Dev-only typing imports\n\nIf the stubs are installed only in development or CI, keep imports type-only:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_fsx import FSxClient\nelse:\n    FSxClient = object\n\ndef get_fsx_client() -> \"FSxClient\":\n    return Session(region_name=\"us-west-2\").client(\"fsx\")\n```\n\nThe `object` fallback matches the maintainer's Pylint compatibility guidance for type-only imports.\n\n## Common Pitfalls\n\n- Treating `mypy-boto3-fsx` as a replacement for `boto3`. It only adds types.\n- Installing the standalone or lite package and expecting `Session.client(\"fsx\")` inference without an explicit `FSxClient` annotation.\n- Importing with hyphens instead of underscores. Install `mypy-boto3-fsx`, import `mypy_boto3_fsx`.\n- Letting `boto3` and the stubs drift apart. New FSx operations or fields can appear in runtime models before matching generated types arrive.\n- Assuming type checking validates credentials, IAM permissions, region choice, or endpoint reachability. Those remain boto3 and AWS runtime concerns.\n- Treating better typing as proof the FSx call is semantically correct. Service-specific constraints still come from the live FSx API.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- On 2026-03-12, the version used here `1.42.3` matches the current maintainer docs and PyPI package page for `mypy-boto3-fsx`.\n- PyPI lists this package as `Stubs Only`, requires Python `>=3.9`, and includes `1.42.3` in the published release history.\n- The maintainer docs state that `mypy-boto3-fsx` versions follow the related boto3 version. If exact service-model alignment matters, pin `boto3` and the stubs to the same release line or generate stubs locally with `uvx --with 'boto3==1.42.3' mypy-boto3-builder`.\n\n## Official Source URLs\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_fsx/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-fsx/`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- Boto3 FSx reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/fsx.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-glue/python/DOC.md",
    "content": "---\nname: mypy-boto3-glue\ndescription: \"mypy-boto3-glue package guide for Python typed boto3 Glue clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.43\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,glue,boto3,stubs,typing,mypy,pyright\"\n---\n\n# mypy-boto3-glue Python Package Guide\n\n## What It Is\n\n`mypy-boto3-glue` is the maintainer-published type stub package for the AWS Glue part of `boto3`.\n\nUse it when you want:\n\n- static typing for `Session().client(\"glue\")`\n- IDE completion for Glue operations and response fields\n- typed paginator classes\n- generated `Literal` values for Glue enum-like strings\n- generated `TypedDict` request and response shapes\n\nImportant boundary: this package does not make API calls by itself. Runtime behavior still comes from `boto3` and `botocore`.\n\n## Install\n\nInstall `boto3` for runtime calls, then pick one typing package.\n\n```bash\npython -m pip install boto3\npython -m pip install mypy-boto3-glue\n```\n\nMaintainer-supported alternatives:\n\n```bash\npython -m pip install \"boto3-stubs[glue]\"\npython -m pip install \"boto3-stubs-lite[glue]\"\n```\n\nPractical rule:\n\n- use `mypy-boto3-glue` when you only need Glue stubs\n- use `boto3-stubs[glue]` when you want the broader boto3 typing package with Glue enabled\n- use `boto3-stubs-lite[glue]` only if you need the lower-memory variant and can live without `session.client()` and `session.resource()` overloads\n- do not install multiple stub variants unless you are deliberately managing which one wins in your type checker environment\n\n## Recommended Setup\n\nFor agent-written code, explicit client annotations are the safest default.\n\n```python\nfrom __future__ import annotations\n\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_glue import GlueClient\n\nsession = Session(profile_name=\"analytics-dev\", region_name=\"us-east-1\")\n\nglue: GlueClient = session.client(\n    \"glue\",\n    config=Config(\n        retries={\n            \"mode\": \"standard\",\n            \"max_attempts\": 10,\n        }\n    ),\n)\n\nresponse = glue.get_databases(MaxResults=25)\n\nfor database in response.get(\"DatabaseList\", []):\n    print(database[\"Name\"])\n```\n\nWhy this pattern works well:\n\n- it keeps runtime construction in normal boto3 code\n- it gives mypy and pyright a concrete `GlueClient`\n- it keeps AWS profile, region, retry, and proxy settings in standard boto3/botocore configuration\n\nIf the stubs are installed only in development, keep imports behind `TYPE_CHECKING`:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_glue import GlueClient\n\ndef make_glue_client() -> \"GlueClient\":\n    return Session(region_name=\"us-east-1\").client(\"glue\")\n```\n\n## Core Typing Patterns\n\n### Paginators\n\nThe package publishes typed paginator classes for Glue paginator operations.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_glue import GlueClient\nfrom mypy_boto3_glue.paginator import GetDatabasesPaginator\n\nglue: GlueClient = Session(region_name=\"us-east-1\").client(\"glue\")\npaginator: GetDatabasesPaginator = glue.get_paginator(\"get_databases\")\n\nfor page in paginator.paginate():\n    for database in page.get(\"DatabaseList\", []):\n        print(database[\"Name\"])\n```\n\n### Literals\n\nUse generated literal types when you want type checkers to catch misspelled AWS string constants.\n\n```python\nfrom mypy_boto3_glue.literals import AdditionalOptionKeysType\n\noption_key: AdditionalOptionKeysType = \"compositeRuleEvaluation.method\"\n```\n\n### TypedDict Shapes\n\nUse generated `type_defs` when you pass nested Glue request or response fragments between helpers.\n\n```python\nfrom mypy_boto3_glue.type_defs import NotificationPropertyTypeDef\n\nnotification: NotificationPropertyTypeDef = {\n    \"NotifyDelayAfter\": 5,\n}\n```\n\nThese generated shapes are more precise than `dict[str, object]` and reduce avoidable casting.\n\n## Auth And Runtime Config\n\n`mypy-boto3-glue` does not have its own authentication layer. Credential and region resolution come from boto3.\n\nCommon inputs:\n\n- `AWS_PROFILE` or `Session(profile_name=\"...\")`\n- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`\n- `AWS_DEFAULT_REGION`\n- `~/.aws/config` and `~/.aws/credentials`\n- IAM roles and other AWS runtime credential providers\n\nTypical local setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"analytics-dev\", region_name=\"us-west-2\")\nglue = session.client(\"glue\")\n```\n\nUse `botocore.config.Config` when you need retries, timeouts, proxies, or custom endpoints. The stubs type the client surface; they do not change runtime behavior.\n\n## Type Checker Notes\n\n- `mypy` and `pyright` work best when the stub package is installed in the same environment used for analysis\n- explicit annotations are the most reliable choice for standalone `mypy-boto3-glue`\n- `boto3-stubs-lite[glue]` intentionally omits `session.client()` and `session.resource()` overloads, so explicit annotations are required there\n- `from __future__ import annotations` avoids importing typing-only names too early in runtime paths\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-glue` as a runtime SDK. Import and call AWS Glue through `boto3`.\n- Keep the stub version close to the installed `boto3` version family. These packages are generated from boto3 service models and can drift.\n- Do not assume every boto3 Glue convenience pattern is represented by one stable public type name. Generated symbols can change when AWS updates service models.\n- If the stub package is a dev dependency only, avoid importing stub-only names unguarded in modules that production code imports.\n- If autocomplete is missing after installation, check that your editor, virtual environment, and type checker are all looking at the same interpreter.\n\n## Version-Sensitive Notes\n\n- The version used here, the current PyPI release, and this doc all align on `1.42.43` as verified on March 12, 2026.\n- The hosted docs site currently includes a local-generation example pinned to `boto3==1.42.65`, which is ahead of the standalone PyPI package version. Treat the docs site as the best API-shape reference, but pin installs from PyPI to the package version your project actually uses.\n- When in doubt, pin `boto3` and `mypy-boto3-glue` together during upgrades and rerun your type checker after the bump.\n\n## Official Sources\n\n- Docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_glue/`\n- PyPI: `https://pypi.org/project/mypy-boto3-glue/`\n- Repository: `https://github.com/youtype/boto3-stubs`\n- AWS boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-guardduty/python/DOC.md",
    "content": "---\nname: mypy-boto3-guardduty\ndescription: \"mypy-boto3-guardduty typed boto3 stubs for Amazon GuardDuty clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.33\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,guardduty,boto3,python,typing,mypy,pyright,stubs\"\n---\n\n# mypy-boto3-guardduty Python Package Guide\n\n## What It Is\n\n`mypy-boto3-guardduty` is a typing-only companion package for `boto3.client(\"guardduty\")`.\n\nUse it when you want static typing for:\n\n- `GuardDutyClient`\n- paginator overloads such as `ListDetectorsPaginator` and `ListFindingsPaginator`\n- generated `TypedDict` request and response shapes under `mypy_boto3_guardduty.type_defs`\n- literal aliases under `mypy_boto3_guardduty.literals`\n\nIt does not replace `boto3` at runtime. Authentication, retry behavior, endpoints, and actual GuardDuty API calls still come from `boto3` and botocore.\n\n## Golden Rules\n\n- Keep `boto3`, `botocore`, and `mypy-boto3-guardduty` on the same release line when possible.\n- Use `boto3-stubs[guardduty]` if you want the best `Session.client(\"guardduty\")` inference.\n- Use standalone `mypy-boto3-guardduty` when you only need GuardDuty-specific imports and are fine with explicit annotations.\n- If stubs are dev-only dependencies, keep type-only imports behind `TYPE_CHECKING`.\n\n## Prerequisites\n\nBefore you add the stubs, make sure you already have:\n\n- `boto3` in the Python environment that runs your application\n- AWS credentials available through the normal boto3 credential chain\n- a region selected for the GuardDuty detector you want to query or manage\n- one typing package choice: `boto3-stubs[guardduty]`, `boto3-stubs-lite[guardduty]`, or `mypy-boto3-guardduty`\n\n## Install\n\nInstall the runtime SDK plus one typing option.\n\n### Recommended: full boto3 stubs\n\n```bash\npython -m pip install \"boto3==1.42.33\" \"boto3-stubs[guardduty]==1.42.33\"\n```\n\nThis gives the best editor experience for `Session.client(...)`.\n\n### Service-only package\n\n```bash\npython -m pip install \"boto3==1.42.33\" \"mypy-boto3-guardduty==1.42.33\"\n```\n\nUse this when you only need GuardDuty typings and prefer narrow dependencies.\n\n### Lower-memory fallback\n\n```bash\npython -m pip install \"boto3==1.42.33\" \"boto3-stubs-lite[guardduty]==1.42.33\"\n```\n\nThe lite package is easier on IDE memory, but the maintainer docs note that it does not provide the usual `session.client(...)` and `session.resource(...)` overloads.\n\n### Generate locally for an exact boto3 match\n\nThe maintainer docs and package page both point to local generation when you need the stubs to exactly match the boto3 version already locked in your environment:\n\n```bash\nuvx --with \"boto3==1.42.33\" mypy-boto3-builder\n```\n\nThen choose `boto3-stubs` and the `GuardDuty` service.\n\n## Initialize And Setup\n\nAnnotate the boto3 client explicitly when you are using the standalone package or the lite bundle:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_guardduty.client import GuardDutyClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nguardduty: GuardDutyClient = session.client(\"guardduty\")\n```\n\nIf your type checker sees the full `boto3-stubs[guardduty]` bundle, this is usually enough:\n\n```python\nfrom boto3.session import Session\n\nguardduty = Session(region_name=\"us-west-2\").client(\"guardduty\")\n```\n\nSafe pattern when the stubs are installed only in development or CI:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_guardduty.client import GuardDutyClient\n\ndef get_guardduty_client() -> \"GuardDutyClient\":\n    return Session(region_name=\"us-west-2\").client(\"guardduty\")\n```\n\n## Authentication And Configuration\n\n`mypy-boto3-guardduty` does not introduce its own auth or config layer. Use the normal boto3 credential and region chain.\n\nCommon sources:\n\n1. explicit parameters on `Session(...)` or `client(...)`\n2. environment variables such as `AWS_PROFILE`, `AWS_DEFAULT_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. shared AWS config and credentials files\n4. assume-role, IAM Identity Center, container credentials, or EC2 instance metadata\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create the typed client normally:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_guardduty.client import GuardDutyClient\n\nguardduty: GuardDutyClient = Session().client(\"guardduty\")\n```\n\nGuardDuty is region-scoped. Set the client region deliberately so it matches the detector you want to query or manage.\n\n## Core Usage\n\nMost GuardDuty calls in real apps start by resolving a detector ID and then reusing it for later requests.\n\n### Typed client calls\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_guardduty.client import GuardDutyClient\n\nguardduty: GuardDutyClient = Session(region_name=\"us-west-2\").client(\"guardduty\")\n\ndetector_ids = guardduty.list_detectors().get(\"DetectorIds\", [])\nprint(detector_ids)\n```\n\nOnce you have a detector ID, use it in follow-up calls:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_guardduty.client import GuardDutyClient\n\nguardduty: GuardDutyClient = Session(region_name=\"us-west-2\").client(\"guardduty\")\n\ndetector_id = guardduty.list_detectors()[\"DetectorIds\"][0]\nfinding_ids = guardduty.list_findings(DetectorId=detector_id).get(\"FindingIds\", [])\nprint(finding_ids[:10])\n```\n\n### Typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_guardduty.client import GuardDutyClient\nfrom mypy_boto3_guardduty.paginator import ListFindingsPaginator\n\nguardduty: GuardDutyClient = Session(region_name=\"us-west-2\").client(\"guardduty\")\ndetector_id = guardduty.list_detectors()[\"DetectorIds\"][0]\n\npaginator: ListFindingsPaginator = guardduty.get_paginator(\"list_findings\")\n\nfor page in paginator.paginate(DetectorId=detector_id):\n    for finding_id in page.get(\"FindingIds\", []):\n        print(finding_id)\n```\n\n### Typed request shapes\n\nThe generated package exposes request and response `TypedDict` definitions. Use them when you pass GuardDuty-shaped dictionaries between helpers instead of building large untyped `dict` objects.\n\n```python\nfrom mypy_boto3_guardduty.type_defs import AcceptAdministratorInvitationRequestTypeDef\n\ndef submit_accept_request(payload: AcceptAdministratorInvitationRequestTypeDef) -> None:\n    print(payload)\n```\n\n### Literal aliases\n\nThe generated `literals` module exposes enum-like string aliases such as `AdminStatusType`. Use them when you want your type checker to reject unsupported string values before runtime.\n\n## IDE And Type Checker Notes\n\nThe official package page explicitly documents support for:\n\n- `mypy`\n- `pyright`\n- VSCode with Pylance\n- PyCharm\n\nInstall the stubs into the same environment that your editor or CI type checker analyzes. If your IDE struggles with large overload sets, switch to `boto3-stubs-lite[guardduty]` or the standalone service package and annotate clients explicitly.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-guardduty` and assuming it replaces `boto3`. It does not.\n- Mixing up the package name and import root. Install `mypy-boto3-guardduty`, import `mypy_boto3_guardduty`.\n- Expecting the lite package to infer `Session.client(\"guardduty\")` automatically. Add explicit `GuardDutyClient` annotations in lite mode.\n- Letting `boto3`, `botocore`, and `mypy-boto3-guardduty` drift apart. New GuardDuty fields can appear in runtime models before matching stubs land.\n- Treating typed request shapes as proof that the call will succeed. Region choice, detector state, permissions, and account configuration are still runtime concerns.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, the official PyPI project page lists `mypy-boto3-guardduty 1.42.33` as the latest published release. This does not match the initial package metadata version `1.42.62`.\n- The maintainer docs describe these packages as following the related boto3 version family, so pin `boto3` and `mypy-boto3-guardduty` close together when exact model coverage matters.\n- The public project branding is `types-boto3`, but the published wheel and Python import root remain `mypy-boto3-guardduty` and `mypy_boto3_guardduty`.\n\n## Official Source URLs\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_guardduty/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-guardduty/`\n- PyPI JSON API: `https://pypi.org/pypi/mypy-boto3-guardduty/json`\n- Boto3 GuardDuty reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/guardduty.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Boto3 session guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html`\n- Repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-iam/python/DOC.md",
    "content": "---\nname: mypy-boto3-iam\ndescription: \"Type stubs for boto3 IAM in Python, including typed clients, resources, paginators, waiters, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.64\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,iam,boto3,python,typing,type-stubs,mypy,pyright\"\n---\n\n# `mypy-boto3-iam` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-iam` is a typing package, not a runtime AWS SDK. Keep using `boto3` to talk to AWS IAM, and add these stubs so `mypy`, `pyright`, and IDEs understand IAM clients, resources, paginators, waiters, literals, and TypedDict shapes.\n\nIf you install the lightweight or standalone package variants, annotate your clients and resources explicitly. If you want automatic type discovery for `Session.client(\"iam\")` and `Session.resource(\"iam\")`, install `boto3-stubs[iam]`.\n\n## Install\n\nRecommended for the best editor experience:\n\n```bash\npython -m pip install \"boto3==1.42.64\" \"boto3-stubs[iam]==1.42.64\"\n```\n\nLower-memory option:\n\n```bash\npython -m pip install \"boto3==1.42.64\" \"boto3-stubs-lite[iam]==1.42.64\"\n```\n\nService-specific standalone stubs:\n\n```bash\npython -m pip install \"boto3==1.42.64\" \"mypy-boto3-iam==1.42.64\"\n```\n\nNotes:\n\n- `boto3-stubs[iam]` provides overloads so type checkers can infer `Session.client(\"iam\")`, `Session.resource(\"iam\")`, `client.get_paginator(...)`, and `client.get_waiter(...)` automatically.\n- `boto3-stubs-lite[iam]` is more RAM-friendly, but upstream notes that it does not provide `session.client/resource` overloads, so explicit annotations are the safer default.\n- `mypy-boto3-iam` gives you the IAM-specific type surface without installing the full `boto3-stubs` package. Keep `boto3` installed because the stubs do not make AWS calls themselves.\n\n## Initialize And Authenticate\n\nAuthentication and configuration still come from `boto3` and the normal AWS credential chain. The stubs do not change request behavior, retries, endpoints, or permissions.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_iam import IAMClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\niam: IAMClient = session.client(\"iam\")\n```\n\nUse the same credential sources you would use for normal `boto3` code:\n\n- shared config and credentials files\n- environment variables\n- SSO or assume-role configuration\n- IAM roles on AWS compute\n\n## Core Usage\n\n### Typed IAM client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_iam import IAMClient\n\niam: IAMClient = Session().client(\"iam\")\n\nresponse = iam.get_role(RoleName=\"MyApplicationRole\")\nprint(response[\"Role\"][\"Arn\"])\n```\n\n### Typed IAM resource\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_iam import IAMServiceResource\n\niam_resource: IAMServiceResource = Session().resource(\"iam\")\nuser = iam_resource.User(\"alice\")\n\nprint(user.arn)\n```\n\n### Typed paginators\n\nThe docs site uses a `/paginators/` URL, but the Python import module is singular: `mypy_boto3_iam.paginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_iam import IAMClient\nfrom mypy_boto3_iam.paginator import ListUsersPaginator\n\niam: IAMClient = Session().client(\"iam\")\npaginator: ListUsersPaginator = iam.get_paginator(\"list_users\")\n\nfor page in paginator.paginate():\n    for user in page.get(\"Users\", []):\n        print(user[\"UserName\"])\n```\n\n### Typed waiters\n\nLikewise, the docs URL is `/waiters/`, but the import module is singular: `mypy_boto3_iam.waiter`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_iam import IAMClient\nfrom mypy_boto3_iam.waiter import RoleExistsWaiter\n\niam: IAMClient = Session().client(\"iam\")\nwaiter: RoleExistsWaiter = iam.get_waiter(\"role_exists\")\nwaiter.wait(RoleName=\"MyApplicationRole\")\n```\n\n### Typed request and response shapes\n\nUse `type_defs` when you want explicit `TypedDict` shapes for request payloads or structured values:\n\n```python\nfrom mypy_boto3_iam.type_defs import AcceptDelegationRequestRequestTypeDef\n\ndef build_request(request_id: str) -> AcceptDelegationRequestRequestTypeDef:\n    return {\n        \"DelegationRequestId\": request_id,\n    }\n```\n\n### Literals for constrained string values\n\n```python\nfrom mypy_boto3_iam.literals import AccessAdvisorUsageGranularityTypeType\n\ndef normalize_granularity(value: AccessAdvisorUsageGranularityTypeType) -> str:\n    return value\n```\n\n### Keep stubs out of production-only dependency sets\n\nIf your deployment image should not carry stub packages, use `TYPE_CHECKING` imports and keep the stubs in a dev or type-checking environment:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_iam import IAMClient\nelse:\n    IAMClient = object\n\niam = Session().client(\"iam\")\ntyped_iam: \"IAMClient\" = iam\n```\n\nThis pattern is especially useful with `pylint`, where upstream notes that undefined-name complaints can appear without a non-`TYPE_CHECKING` fallback.\n\n## Common Pitfalls\n\n- `mypy-boto3-iam` is not `boto3`. Install `boto3` for runtime use.\n- The import package uses underscores: `mypy_boto3_iam`, not `mypy-boto3-iam`.\n- Align versions. Upstream states that `mypy-boto3-iam` follows the related `boto3` version, so pin both packages to the same release family.\n- Do not confuse docs URLs with import module names. The site uses `/paginators/` and `/waiters/`, but the modules are `paginator` and `waiter`.\n- If `Session().client(\"iam\")` is inferred as `BaseClient` instead of `IAMClient`, you probably installed the standalone or lite package and need explicit annotations.\n- PyCharm can be slow with large `Literal` overload sets. Upstream recommends `boto3-stubs-lite` if IDE performance becomes a problem.\n- These stubs describe the generated boto3 IAM surface. They do not validate that your AWS credentials, IAM permissions, or account state are correct at runtime.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-iam 1.42.64` as the latest release on March 12, 2026, released March 9, 2026.\n- This release was generated with `mypy-boto3-builder 8.12.0`.\n- The package is marked `Stubs Only` on PyPI and supports Python `3.9` through `3.14`.\n- Upstream documents typed `Client`, `ServiceResource`, resource collections, `Paginator`, `Waiter`, `Literal`, and `TypeDef` surfaces for this service.\n- If your project upgrades `boto3`, upgrade the IAM stubs at the same time to avoid drift between generated signatures and the installed runtime SDK.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-iam/`\n- Service docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_iam/`\n- Client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_iam/client/`\n- Paginators reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_iam/paginators/`\n- Maintainer repository: `https://github.com/vemel/mypy_boto3_builder`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-inspector2/python/DOC.md",
    "content": "---\nname: mypy-boto3-inspector2\ndescription: \"Typed boto3 stubs for Amazon Inspector2 clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.49\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,inspector2,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-inspector2 Python Package Guide\n\n## Golden Rule\n\n- Use `mypy-boto3-inspector2` only for static typing of Amazon Inspector code that runs through `boto3`.\n- Real AWS requests, credentials, retries, endpoints, and IAM behavior still come from `boto3` and `botocore`.\n- Keep the stub package on the same release line as your runtime `boto3` when you want reliable request and response typing.\n\n## Install\n\nInstall the runtime SDK and the matching stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.49\" \"mypy-boto3-inspector2==1.42.49\"\n```\n\nUpstream also documents the umbrella extras packages:\n\n```bash\npython -m pip install \"boto3-stubs[inspector2]==1.42.49\"\npython -m pip install \"boto3-stubs-lite[inspector2]==1.42.49\"\n```\n\nCommon alternatives:\n\n```bash\nuv add boto3==1.42.49\nuv add --dev mypy-boto3-inspector2==1.42.49\npoetry add boto3==1.42.49\npoetry add --group dev mypy-boto3-inspector2==1.42.49\n```\n\nUse `boto3-stubs[inspector2]` when you want overloads for `boto3.client(\"inspector2\")` and `Session.client(\"inspector2\")`. Use `mypy-boto3-inspector2` when you want only the Inspector2 type package and are willing to annotate the client and paginator types explicitly. Use `boto3-stubs-lite[inspector2]` if the full overload set is too heavy for your editor; the lite variant omits those boto3 helper overloads.\n\n## Initialize And Authenticate\n\nAuthentication is standard boto3 authentication. Prefer the normal AWS credential chain:\n\n1. `aws configure` or named profiles in `~/.aws/config` and `~/.aws/credentials`\n2. Environment variables such as `AWS_PROFILE`, `AWS_DEFAULT_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. IAM roles or workload credentials in AWS runtimes\n\nTypical setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_inspector2.client import Inspector2Client\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n\nclient: Inspector2Client = session.client(\n    \"inspector2\",\n    config=Config(\n        retries={\"mode\": \"standard\", \"max_attempts\": 10},\n    ),\n)\n```\n\nIf you use `boto3-stubs-lite[inspector2]`, add an explicit cast because the overloaded client helpers are not installed:\n\n```python\nfrom typing import cast\nfrom boto3.session import Session\nfrom mypy_boto3_inspector2.client import Inspector2Client\n\nsession = Session(region_name=\"us-east-1\")\nclient = cast(Inspector2Client, session.client(\"inspector2\"))\n```\n\n## Core Usage\n\n### Typed client helpers\n\nAnnotate helper signatures with the generated client type instead of `Any`:\n\n```python\nfrom mypy_boto3_inspector2.client import Inspector2Client\n\ndef list_finding_arns(client: Inspector2Client) -> list[str]:\n    response = client.list_findings(maxResults=25)\n    return [finding[\"findingArn\"] for finding in response.get(\"findings\", [])]\n```\n\n### Typed response shapes\n\nUse generated `type_defs` when you want request and response dictionaries to stay explicit:\n\n```python\nfrom mypy_boto3_inspector2.client import Inspector2Client\nfrom mypy_boto3_inspector2.type_defs import ListFindingsResponseTypeDef\n\ndef get_critical_titles(client: Inspector2Client) -> list[str]:\n    response: ListFindingsResponseTypeDef = client.list_findings(\n        filterCriteria={\n            \"severity\": [{\"comparison\": \"EQUALS\", \"value\": \"CRITICAL\"}],\n        },\n        maxResults=25,\n    )\n    return [finding[\"title\"] for finding in response.get(\"findings\", [])]\n```\n\n### Typed paginators\n\nThe generated paginator surface is useful for account-wide or large-result scans:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_inspector2.client import Inspector2Client\nfrom mypy_boto3_inspector2.paginator import ListFindingsPaginator\n\nclient: Inspector2Client = Session(region_name=\"us-east-1\").client(\"inspector2\")\npaginator: ListFindingsPaginator = client.get_paginator(\"list_findings\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 100}):\n    for finding in page.get(\"findings\", []):\n        print(finding[\"severity\"], finding[\"findingArn\"])\n```\n\n### Typed request bodies\n\nFor update-style APIs, define the payload with a generated request shape before splatting it into the boto3 call:\n\n```python\nfrom mypy_boto3_inspector2.client import Inspector2Client\nfrom mypy_boto3_inspector2.type_defs import (\n    UpdateEc2DeepInspectionConfigurationRequestTypeDef,\n)\n\ndef enable_deep_inspection(client: Inspector2Client) -> None:\n    request: UpdateEc2DeepInspectionConfigurationRequestTypeDef = {\n        \"activateDeepInspection\": True,\n        \"packagePaths\": [\"/usr/lib\", \"/usr/local/lib\"],\n    }\n    client.update_ec2_deep_inspection_configuration(**request)\n```\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nIf the stubs are only installed in development, guard the imports and keep runtime imports clean:\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypy_boto3_inspector2.client import Inspector2Client\n\ndef uses_client(client: \"Inspector2Client\") -> str:\n    return client.meta.service_model.service_name\n```\n\n## Config And Tooling Notes\n\n- This package does not load credentials, regions, or retry configuration by itself.\n- Put region, timeouts, endpoints, and retry behavior on the boto3 session or client.\n- Install the stubs in the same environment your IDE, `mypy`, or `pyright` analyzes.\n- The PyPI description recommends the `TYPE_CHECKING` guard pattern when the package is not available in production installs.\n- The maintainer docs call out PyCharm performance problems with `Literal`-heavy overloads; switch to `boto3-stubs-lite[inspector2]` or run `mypy`/`pyright` outside PyCharm if that becomes an issue.\n\n## Common Pitfalls\n\n- Install name and import name differ: install `mypy-boto3-inspector2`, import `mypy_boto3_inspector2`.\n- This package does not replace `boto3`; without `boto3`, your code cannot make Inspector runtime calls.\n- The boto3 service name is `inspector2`. Do not guess older names like `inspector`.\n- If `boto3` and the stubs drift apart, your type hints can stop matching the actual request and response shapes.\n- Missing region, credentials, service enablement, or IAM permissions are still runtime failures; static typing does not prevent them.\n- The rolling maintainer docs can drift ahead of the exact package version published on PyPI, so use PyPI for exact pinning.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, PyPI published `mypy-boto3-inspector2 1.42.49`, which matches the version used here for this session.\n- The PyPI project description says the stub package version follows the related `boto3` version line, so align your pins when you need accurate types.\n- The maintainer docs site is a rolling generated reference. Treat it as the best source for the available typed modules and boto3 method coverage, and treat PyPI as the source of truth for exact package version pinning.\n- PyPI requires Python `>=3.9` for the current release line.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_inspector2/`\n- Client docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_inspector2/client/`\n- Paginators docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_inspector2/paginators/`\n- Package page: `https://pypi.org/project/mypy-boto3-inspector2/`\n- boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- boto3 Inspector2 reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/inspector2.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-iot/python/DOC.md",
    "content": "---\nname: mypy-boto3-iot\ndescription: \"mypy-boto3-iot type stubs for boto3 AWS IoT clients, paginators, literals, and generated type definitions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.14\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,iot,python,mypy,typing,stubs\"\n---\n\n# mypy-boto3-iot Python Package Guide\n\n## What It Is\n\n`mypy-boto3-iot` is a stub-only PEP 561 package for the AWS IoT service client in `boto3`.\n\nUse it when your code already talks to AWS IoT through `boto3`, but you want static typing for:\n\n- the `IoTClient` interface\n- generated paginator types\n- generated string literal unions\n- generated request and response `TypedDict` shapes\n\nIt does not make AWS calls by itself. Runtime behavior, credentials, retries, endpoints, and exceptions still come from `boto3` and `botocore`.\n\n## Install\n\nInstall the runtime SDK and the matching stub package together:\n\n```bash\npython -m pip install \"boto3==1.42.14\" \"mypy-boto3-iot==1.42.14\"\n```\n\nIf you want typed `Session.client(\"iot\")` overloads from the broader maintainer package, use:\n\n```bash\npython -m pip install \"boto3-stubs[iot]==1.42.14\"\n```\n\nIf your IDE struggles with the larger `boto3-stubs` package, the maintainer docs recommend either the service-specific package you are reading about now or the lighter extra:\n\n```bash\npython -m pip install \"boto3-stubs-lite[iot]==1.42.14\"\n```\n\nPractical rule: keep `boto3`, `botocore`, and `mypy-boto3-iot` on the same patch version when possible.\n\n## Setup\n\nAnnotate the client explicitly and let `boto3` handle the real runtime client creation.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_iot import IoTClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\niot: IoTClient = session.client(\"iot\")\n\nthing = iot.describe_thing(thingName=\"sensor-123\")\nprint(thing[\"thingName\"])\n```\n\nThis pattern is the safest default because:\n\n- the annotation is available to mypy and pyright\n- `boto3` still creates the real client at runtime\n- `from __future__ import annotations` prevents the type annotation from being evaluated at runtime\n\n## Auth And Configuration\n\n`mypy-boto3-iot` has no separate auth or config system. Use the normal `boto3` credential and region chain:\n\n1. explicit arguments on `boto3.Session(...)` or `session.client(...)`\n2. environment variables such as `AWS_PROFILE` and `AWS_DEFAULT_REGION`\n3. shared AWS config in `~/.aws/config` and `~/.aws/credentials`\n4. runtime providers such as container or instance roles\n\nLocal development example:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen:\n\n```python\nimport boto3\n\nsession = boto3.Session()\niot = session.client(\"iot\")\n```\n\nIf the underlying boto3 client is misconfigured, the stub package will not fix it. Treat auth, retry mode, endpoint selection, and region selection as boto3 concerns.\n\n## Core Usage\n\n### Typed Client\n\nUse `IoTClient` when you want operation names, parameter names, and response keys checked by your type checker.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_iot import IoTClient\n\niot: IoTClient = boto3.Session(region_name=\"us-east-1\").client(\"iot\")\ncertificate = iot.describe_certificate(certificateId=\"abcd1234\")\nprint(certificate[\"certificateDescription\"][\"status\"])\n```\n\n### Typed Paginators\n\nThe generated docs for this package include paginator support. Keep the paginator name as a string literal so the overload stays precise.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_iot import IoTClient\n\niot: IoTClient = boto3.Session(region_name=\"us-east-1\").client(\"iot\")\npaginator = iot.get_paginator(\"list_things\")\n\nfor page in paginator.paginate():\n    for thing in page.get(\"things\", []):\n        print(thing[\"thingName\"])\n```\n\n### Literals And Type Definitions\n\nThe generated docs root exposes these modules:\n\n- `mypy_boto3_iot.client`\n- `mypy_boto3_iot.literals`\n- `mypy_boto3_iot.paginator`\n- `mypy_boto3_iot.type_defs`\n\nUse `literals` when an API parameter only accepts a fixed set of string values, and `type_defs` when you want generated request or response shapes in helper functions. The exact names are generated from the AWS service model, so check the docs site before inventing a `Literal` alias or `TypedDict` name.\n\n## When To Use `boto3-stubs[iot]` Instead\n\nChoose `mypy-boto3-iot` when you want the smallest service-specific typing package.\n\nChoose `boto3-stubs[iot]` when you want:\n\n- typed `Session.client(\"iot\")` overloads with less manual annotation\n- one install pattern used across multiple AWS services\n- the broader maintainer setup shown in the upstream package README\n\nChoose `boto3-stubs-lite[iot]` when you want those service extras but your IDE struggles with the full `boto3-stubs` package.\n\n## Common Pitfalls\n\n- This is not a runtime SDK. You still need `boto3`.\n- The boto3 service name is `iot`, not `mypy-boto3-iot`.\n- Prefer `TYPE_CHECKING` imports or postponed annotations. Direct runtime imports from stub-only packages are easy to get wrong.\n- Keep `boto3`, `botocore`, and `mypy-boto3-iot` aligned. If the versions drift, you can type-check calls that fail at runtime or miss newly added parameters.\n- `mypy-boto3-iot` alone does not configure credentials, retries, or regions. That is still boto3 setup.\n- The generated docs list client, literals, paginators, and type definitions for this package. I did not find service-resource or waiter modules for `mypy-boto3-iot` in the published 1.42.14 docs.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.14` matches the official PyPI package page and the generated docs site as of 2026-03-12.\n- PyPI shows `mypy-boto3-iot 1.42.14` was released on 2025-12-19.\n- This package requires Python `>=3.9`.\n- The package is generated from the maintainer's broader `boto3-stubs` project, so patch releases closely track boto3 and AWS service-model changes.\n- If you copy examples from older posts, confirm the current generated symbol names on the docs site before using them in annotations.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/mypy-boto3-iot/\n- PyPI JSON metadata: https://pypi.org/pypi/mypy-boto3-iot/json\n- Generated docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_iot/\n- Generated client docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_iot/client/\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ivs/python/DOC.md",
    "content": "---\nname: mypy-boto3-ivs\ndescription: \"Typed boto3 IVS stubs for Python with install options, typed clients and paginators, literals, and runtime-safe typing patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,ivs,boto3,mypy,typing,stubs,python,streaming\"\n---\n\n# mypy-boto3-ivs Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS IVS calls and use `mypy-boto3-ivs` only for typing. If you want `Session.client(\"ivs\")` to infer automatically, install `boto3-stubs[ivs]`; if you install only the standalone or lite package, annotate `IVSClient` explicitly.\n\n## What This Package Gives You\n\nThe published maintainer docs for `mypy-boto3-ivs` expose typed surfaces for:\n\n- `IVSClient`\n- paginators such as `ListChannelsPaginator` and `ListStreamsPaginator`\n- literal aliases such as `ChannelLatencyModeType`\n- generated request and response shapes in `mypy_boto3_ivs.type_defs`\n\nThe published IVS stubs docs do not surface a `service_resource` or `waiter` section, so plan around typed client usage rather than `Session.resource(\"ivs\")` or waiter APIs.\n\n## Install\n\nChoose one installation pattern based on how much boto3 typing support you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want `Session.client(\"ivs\")` overload inference with the least annotation noise:\n\n```bash\npython -m pip install \"boto3-stubs[ivs]\"\n```\n\n### Service-specific package only\n\nUse this when you only need IVS typings and are willing to annotate the client explicitly:\n\n```bash\npython -m pip install \"boto3\" \"mypy-boto3-ivs==1.42.3\"\n```\n\n### Lite aggregate package\n\nUse this when the full stubs package is too heavy for your IDE or environment:\n\n```bash\npython -m pip install \"boto3-stubs-lite[ivs]\"\n```\n\nPractical rule:\n\n- `boto3-stubs[ivs]`: best editor inference\n- `boto3-stubs-lite[ivs]`: lighter, but explicit annotations matter more\n- `mypy-boto3-ivs`: standalone IVS typings only\n\n## Setup, Auth, And Region\n\n`mypy-boto3-ivs` adds no auth or config layer. Credentials, region selection, retries, profiles, and endpoints still come from normal `boto3` and `botocore` configuration.\n\nCommon local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_ivs.client import IVSClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-west-2\")\nivs: \"IVSClient\" = session.client(\"ivs\")\n```\n\nIVS is regional, so set `region_name` or `AWS_DEFAULT_REGION` explicitly when your environment is not already pinned to the correct region.\n\n## Core Usage\n\n### Typed client for normal IVS API calls\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_ivs.client import IVSClient\n\nivs: \"IVSClient\" = boto3.Session(region_name=\"us-west-2\").client(\"ivs\")\n\nresponse = ivs.list_channels(maxResults=10)\n\nfor channel in response.get(\"channels\", []):\n    print(channel[\"arn\"], channel.get(\"name\"))\n```\n\n### Typed paginator for scans\n\nUse paginator types instead of hand-rolled next-token loops:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_ivs.client import IVSClient\n    from mypy_boto3_ivs.paginator import ListStreamsPaginator\n\nivs: \"IVSClient\" = boto3.Session(region_name=\"us-west-2\").client(\"ivs\")\n\npaginator: \"ListStreamsPaginator\" = ivs.get_paginator(\"list_streams\")\n\nfor page in paginator.paginate():\n    for stream in page.get(\"streams\", []):\n        print(stream[\"channelArn\"], stream.get(\"health\"))\n```\n\n### Literals for constrained string parameters\n\nUse generated literal aliases when helper code builds request parameters:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\nfrom mypy_boto3_ivs.literals import ChannelLatencyModeType\n\nif TYPE_CHECKING:\n    from mypy_boto3_ivs.client import IVSClient\n\nivs: \"IVSClient\" = boto3.Session(region_name=\"us-west-2\").client(\"ivs\")\n\nlatency_mode: ChannelLatencyModeType = \"LOW\"\n\nivs.create_channel(\n    name=\"live-app\",\n    latencyMode=latency_mode,\n)\n```\n\n### Generated `type_defs` for helper boundaries\n\nThe `type_defs` module is useful when you build IVS request dictionaries outside the call site or want typed response-shape helpers. The published docs surface generated definitions such as `AudioConfigurationTypeDef` alongside many request and response shapes.\n\n## Runtime-Safe Typing Pattern\n\nIf production environments do not install stub packages, keep stub imports behind `TYPE_CHECKING` and use forward references:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_ivs.client import IVSClient\n\ndef make_client() -> \"IVSClient\":\n    return boto3.Session(region_name=\"us-west-2\").client(\"ivs\")\n```\n\nThis lets type checkers see the annotations without making `mypy-boto3-ivs` a required runtime dependency.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_ivs`.\n- This package is typing-only. Real requests still come from `boto3`.\n- If you install only `mypy-boto3-ivs` or `boto3-stubs-lite[ivs]`, do not expect all `Session.client(\"ivs\")` calls to infer automatically.\n- The boto3 service name is `\"ivs\"`, not `\"mypy-boto3-ivs\"`.\n- IVS is regional. Missing or wrong region configuration is a boto3 setup problem, not a stub-package problem.\n- Typed responses are still ordinary Python dictionaries at runtime; the stubs help static analysis, not runtime validation.\n- Only some IVS list operations are paginated. Use `get_paginator(...)` only for operations that boto3 exposes as paginators, such as `list_channels` and `list_streams`.\n\n## Version-Sensitive Notes\n\n- The version used here for this session was `1.42.3`, and the live PyPI project page also showed `1.42.3` on March 12, 2026.\n- The maintainer package page says `mypy-boto3-ivs` uses the same version as the related `boto3` release, so keep your stub package close to the boto3 line you actually run.\n- The docs root is a stable package URL, not a release-pinned docs URL. Use PyPI as the source of truth when you need an exact lockfile pin.\n- If your runtime `boto3` moves ahead of the installed stubs, newly added IVS operations or shape fields may be missing from editor and type-checker output.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ivs/`\n- Versioning and install guidance: `https://youtype.github.io/boto3_stubs_docs/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-ivs/`\n- Boto3 IVS service reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ivs.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-kinesis/python/DOC.md",
    "content": "---\nname: mypy-boto3-kinesis\ndescription: \"mypy-boto3-kinesis type stubs for typed boto3 Kinesis clients, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.41\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,kinesis,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-kinesis Python Package Guide\n\n## What It Is\n\n`mypy-boto3-kinesis` is the maintainer-generated type stub package for the Amazon Kinesis Data Streams part of `boto3`.\n\nUse it when you want static typing and editor completion for:\n\n- `KinesisClient`\n- generated paginator types such as `ListStreamsPaginator`\n- generated waiter types such as `StreamExistsWaiter`\n- generated `Literal` unions for Kinesis enum-like values\n- generated `TypedDict` request and response shapes under `type_defs`\n\nThis package does not replace `boto3` or change AWS runtime behavior. It only adds typing information for normal boto3 Kinesis code.\n\n## Golden Rules\n\n- Keep `boto3` installed. This package is only the typing layer.\n- Prefer `boto3-stubs[kinesis]` when you want `Session.client(\"kinesis\")` overload inference with minimal annotation noise.\n- Use `mypy-boto3-kinesis` directly when you only need Kinesis typings and are willing to annotate clients explicitly.\n- Configure credentials, region, retries, and endpoints through normal AWS and boto3 configuration, not through this package.\n- Treat service semantics such as shard iterators, partial `PutRecords` failures, and stream state transitions as AWS concerns, not stub-package concerns.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 \"boto3-stubs[kinesis]\"\n```\n\nThis is the cleanest option when you want `boto3` plus the generated overloads that let editors and checkers infer `Session.client(\"kinesis\")` automatically.\n\n### Standalone Kinesis stubs\n\n```bash\npython -m pip install boto3 \"mypy-boto3-kinesis==1.42.41\"\n```\n\nUse this when you only want the Kinesis stub package. In this mode, explicit client annotations are usually the clearest approach.\n\n### Lower-memory fallback\n\n```bash\npython -m pip install boto3 \"boto3-stubs-lite[kinesis]\"\n```\n\nThe lite package is more memory-friendly, but the maintainer docs note that it omits the `Session.client(...)` and `Session.resource(...)` overloads. Expect to annotate clients explicitly.\n\n### Generate against an exact boto3 line\n\nIf your project pins a different boto3 release family and you need the stubs to match it closely, generate locally:\n\n```bash\nuvx --with \"boto3==1.42.41\" mypy-boto3-builder\n```\n\n## Initialize And Setup\n\nCreate the real client with `boto3`, then add the Kinesis type from the stubs package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kinesis import KinesisClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: KinesisClient = session.client(\"kinesis\")\n```\n\nNormal AWS credential and region resolution still applies. Practical local options are:\n\n- `profile_name` plus `~/.aws/config` and `~/.aws/credentials`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_DEFAULT_REGION`\n- role-based credentials in ECS, EKS, Lambda, or EC2\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\n## Core Usage\n\n### Typed Kinesis client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kinesis import KinesisClient\n\nclient: KinesisClient = Session(region_name=\"us-east-1\").client(\"kinesis\")\n\nresponse = client.describe_stream_summary(StreamName=\"orders\")\nsummary = response[\"StreamDescriptionSummary\"]\n\nprint(summary[\"StreamARN\"])\nprint(summary[\"OpenShardCount\"])\nprint(summary[\"StreamStatus\"])\n```\n\nAWS recommends `describe_stream_summary` plus `list_shards` for most stream inspection work instead of building new code around the older `describe_stream` API.\n\n### Typed producer call\n\n`Data` is bytes, not plain text. Encode payloads explicitly before sending them.\n\n```python\nimport json\nfrom boto3.session import Session\nfrom mypy_boto3_kinesis import KinesisClient\n\nclient: KinesisClient = Session(region_name=\"us-east-1\").client(\"kinesis\")\n\nrecord = {\"order_id\": \"ord-123\", \"status\": \"created\"}\n\nresult = client.put_record(\n    StreamName=\"orders\",\n    PartitionKey=record[\"order_id\"],\n    Data=json.dumps(record).encode(\"utf-8\"),\n)\n\nprint(result[\"SequenceNumber\"])\n```\n\n### `TYPE_CHECKING` pattern\n\nUse this when the stub package is installed only in development or CI:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_kinesis import KinesisClient\nelse:\n    KinesisClient = object\n\nclient: KinesisClient = boto3.client(\"kinesis\", region_name=\"us-east-1\")\n```\n\nThis also avoids common `pylint` false positives around typing-only imports.\n\n### Typed paginators\n\nThe AWS Kinesis boto3 client exposes these paginators: `DescribeStream`, `ListShards`, `ListStreamConsumers`, and `ListStreams`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kinesis import KinesisClient\nfrom mypy_boto3_kinesis.paginator import ListStreamsPaginator\n\nclient: KinesisClient = Session(region_name=\"us-east-1\").client(\"kinesis\")\npaginator: ListStreamsPaginator = client.get_paginator(\"list_streams\")\n\nfor page in paginator.paginate(Limit=25):\n    for stream_name in page.get(\"StreamNames\", []):\n        print(stream_name)\n```\n\n### Typed waiters\n\nThe AWS Kinesis client exposes `stream_exists` and `stream_not_exists` waiters.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kinesis import KinesisClient\nfrom mypy_boto3_kinesis.waiter import StreamExistsWaiter\n\nclient: KinesisClient = Session(region_name=\"us-east-1\").client(\"kinesis\")\nwaiter: StreamExistsWaiter = client.get_waiter(\"stream_exists\")\n\nwaiter.wait(StreamName=\"orders\")\n```\n\n### Literals and `TypedDict` shapes\n\nUse generated literal types for enum-like values and `type_defs` when you want stronger typing around helper functions.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom mypy_boto3_kinesis.literals import StreamStatusType\n\nif TYPE_CHECKING:\n    from mypy_boto3_kinesis.type_defs import PutRecordOutputTypeDef\n\nstatus: StreamStatusType = \"ACTIVE\"\noutput: \"PutRecordOutputTypeDef\"\n```\n\nThis is useful when validating configuration helpers or normalizing AWS responses into internal models.\n\n## Configuration And Authentication\n\n`mypy-boto3-kinesis` has no package-specific configuration surface. If authentication, region selection, retries, or endpoints are wrong, fix the underlying boto3 client configuration.\n\nTypical setup patterns:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient = session.client(\"kinesis\")\n```\n\nFor local emulators such as LocalStack, set `endpoint_url=...` on the boto3 client. The stubs package does not change endpoint behavior.\n\n## Common Pitfalls\n\n- Installing only the stubs and expecting real AWS calls to work without `boto3`.\n- Importing `mypy-boto3-kinesis` with hyphens in Python code. The import root is `mypy_boto3_kinesis`.\n- Expecting automatic `Session.client(\"kinesis\")` inference when you installed only `mypy-boto3-kinesis` or `boto3-stubs-lite[kinesis]`. Use explicit annotations in those setups.\n- Treating successful type checking as proof that IAM permissions, credentials, region, endpoint selection, or stream state are correct.\n- Sending plain strings to `PutRecord` or `PutRecords` instead of bytes.\n- Ignoring partial failures from `put_records`; Kinesis can return a successful HTTP response with failed individual records.\n- Building new logic around `describe_stream` without noticing the AWS docs recommend `describe_stream_summary` plus `list_shards` for most cases.\n- Letting `boto3`, `botocore`, and the stubs drift too far apart. Generated types can become stale even if some runtime calls still succeed.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.42.41`, which matched the initial package metadata and the public PyPI release checked on 2026-03-12.\n- The PyPI package page for `1.42.41` says it is compatible with the Kinesis portion of `boto3 1.42.41`.\n- The PyPI package page also reports that this release was generated with `mypy-boto3-builder 8.12.0`.\n- Maintainer docs and PyPI both present `boto3-stubs[kinesis]`, `boto3-stubs-lite[kinesis]`, and the standalone `mypy-boto3-kinesis` package as valid install paths.\n- If your project is pinned to a different boto3 release family, prefer matching stub versions or generate locally for the exact boto3 version you ship.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_kinesis/`\n- PyPI project: `https://pypi.org/project/mypy-boto3-kinesis/`\n- PyPI release page: `https://pypi.org/project/mypy-boto3-kinesis/1.42.41/`\n- Boto3 Kinesis service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/kinesis.html`\n- Boto3 Kinesis `describe_stream` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/kinesis/client/describe_stream.html`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n- Repository family: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-kms/python/DOC.md",
    "content": "---\nname: mypy-boto3-kms\ndescription: \"Typed boto3 KMS stubs for Python: KMSClient annotations, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.50\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mypy-boto3-kms,boto3,kms,aws,python,type-stubs,typing\"\n---\n\n# mypy-boto3-kms Python Package Guide\n\n## What It Is\n\n`mypy-boto3-kms` is the generated typing package for AWS KMS in `boto3`.\n\nUse it when you need:\n\n- `KMSClient` annotations for `boto3.client(\"kms\")`\n- generated paginator types for KMS list operations\n- `Literal` aliases for enum-like parameters\n- generated `TypedDict` request and response shapes in `type_defs`\n\nIt does not replace `boto3` at runtime. You still create real clients with `boto3`; this package only supplies typing information.\n\n## Version Covered\n\n- Package: `mypy-boto3-kms`\n- Ecosystem: `pypi`\n- Version covered: `1.42.50`\n- Registry: `https://pypi.org/project/mypy-boto3-kms/`\n- Docs root used for this entry: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_kms/`\n\nThe package docs site is generated separately from PyPI and can lag by a few patch releases. As of 2026-03-12, PyPI publishes `1.42.50`, while the maintainer docs still show a `generate-services 1.42.44 kms` example on the landing page. Pin to the version you actually install.\n\n## Install\n\nInstall `boto3` plus the KMS stubs:\n\n```bash\npython -m pip install boto3 mypy-boto3-kms==1.42.50\n```\n\nThe maintainer docs also expose bundle installs:\n\n```bash\npython -m pip install 'boto3-stubs[kms]'\npython -m pip install 'boto3-stubs-lite[kms]'\npython -m pip install mypy-boto3-kms\n```\n\nPractical choice:\n\n- use `mypy-boto3-kms` when you want only the KMS typing package\n- use `boto3-stubs[kms]` when you also want `Session.client(...)` overloads and broader boto3 typing\n- use `boto3-stubs-lite[kms]` when full stubs slow down PyCharm or consume too much memory\n\nPython requirement on PyPI is currently `>=3.9`.\n\n## Core Setup\n\nCreate the runtime client with `boto3`, then annotate it with `KMSClient`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kms.client import KMSClient\n\nsession = Session(region_name=\"us-west-2\")\nkms: KMSClient = session.client(\"kms\")\n\naliases = kms.list_aliases(Limit=10)\nfor alias in aliases.get(\"Aliases\", []):\n    print(alias.get(\"AliasName\"))\n```\n\nThe generated package is organized into a few modules:\n\n```python\nfrom mypy_boto3_kms.client import KMSClient\nfrom mypy_boto3_kms.literals import AlgorithmSpecType\nfrom mypy_boto3_kms.type_defs import AliasListEntryTypeDef\n```\n\nUse:\n\n- `client` for the typed KMS client\n- `paginator` types when you paginate KMS list operations\n- `literals` for constrained string parameters\n- `type_defs` for request and response dictionaries\n\n## AWS Auth And Configuration\n\nAuthentication still comes from the normal boto3 and AWS SDK credential chain. The stub package adds no auth behavior of its own.\n\nPreferred local setup:\n\n```bash\naws configure\n```\n\nCommon environment variables:\n\n```bash\nexport AWS_PROFILE=default\nexport AWS_DEFAULT_REGION=us-west-2\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\n```\n\nThe official boto3 credentials guide documents the usual search order, including:\n\n1. explicit credentials passed to `client(...)`\n2. explicit credentials passed to `Session(...)`\n3. environment variables\n4. assume-role providers\n5. shared credentials and config files\n6. container and EC2 instance metadata\n\nFor agent-written code, prefer shared config or short-lived credentials over hard-coded secrets.\n\n## Common Typed Usage Patterns\n\n### Explicit Client Annotation\n\nThis is the safest pattern when you install only `mypy-boto3-kms` or use the lite bundle.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kms.client import KMSClient\n\nsession = Session(region_name=\"us-east-1\")\nkms: KMSClient = session.client(\"kms\")\n\nmetadata = kms.describe_key(KeyId=\"alias/my-key\")\nprint(metadata[\"KeyMetadata\"][\"Arn\"])\n```\n\n### Paginators\n\nUse paginators for inventory-style operations instead of assuming a single response contains every key or alias.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_kms.client import KMSClient\n\nsession = Session(region_name=\"us-east-1\")\nkms: KMSClient = session.client(\"kms\")\n\npaginator = kms.get_paginator(\"list_keys\")\nfor page in paginator.paginate(PaginationConfig={\"MaxItems\": 100, \"PageSize\": 25}):\n    for item in page.get(\"Keys\", []):\n        print(item[\"KeyId\"])\n```\n\n### Literal Types And TypedDict Shapes\n\nLiteral aliases help keep parameter values valid, and `type_defs` make helper functions easier to type-check.\n\n```python\nfrom mypy_boto3_kms.client import KMSClient\nfrom mypy_boto3_kms.literals import AlgorithmSpecType\nfrom mypy_boto3_kms.type_defs import AliasListEntryTypeDef\n\ndef alias_name(alias: AliasListEntryTypeDef) -> str | None:\n    return alias.get(\"AliasName\")\n\ndef encrypt_blob(kms: KMSClient, key_id: str, plaintext: bytes) -> bytes:\n    algorithm: AlgorithmSpecType = \"SYMMETRIC_DEFAULT\"\n    response = kms.encrypt(\n        KeyId=key_id,\n        Plaintext=plaintext,\n        EncryptionAlgorithm=algorithm,\n    )\n    return response[\"CiphertextBlob\"]\n```\n\n### Runtime-Optional Imports\n\nIf stubs are installed only in development, keep the import inside `TYPE_CHECKING` and cast the runtime client.\n\n```python\nfrom typing import TYPE_CHECKING, cast\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_kms.client import KMSClient\nelse:\n    KMSClient = object\n\nkms = cast(KMSClient, boto3.client(\"kms\", region_name=\"us-east-1\"))\n```\n\n## Common Pitfalls\n\n- Install `boto3` as well. The stubs package does not include runtime KMS client code.\n- Import names differ from the package name: install `mypy-boto3-kms`, import `mypy_boto3_kms`.\n- `boto3-stubs-lite[kms]` intentionally omits `Session.client(...)` and `Session.resource(...)` overloads, so keep explicit client annotations.\n- Full `boto3-stubs[kms]` can hurt PyCharm performance because of many generated overloads and literals; switch to the lite bundle if the IDE becomes sluggish.\n- The stub package does not configure AWS credentials, region, retries, or endpoints. All of that still comes from boto3 configuration.\n- KMS is region-scoped. Make sure `region_name` or `AWS_DEFAULT_REGION` matches the key you are trying to use.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `1.42.50`, and this doc is pinned to that version.\n- The maintainer docs root is rolling generated output. The landing page still references `generate-services 1.42.44 kms`, so do not copy patch numbers from that snippet blindly.\n- When you pin versions, keep `boto3` and `mypy-boto3-kms` on the same `1.42.x` line unless you have verified compatibility another way.\n- If you need broader auto-inference from `session.client(\"kms\")`, install the matching `boto3-stubs[kms]` bundle instead of only the standalone package.\n\n## Official Sources\n\n- PyPI project: https://pypi.org/project/mypy-boto3-kms/\n- Official generated docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_kms/\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-lambda/python/DOC.md",
    "content": "---\nname: mypy-boto3-lambda\ndescription: \"Python type stubs for boto3 Lambda clients, paginators, waiters, literals, and typed dicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.37\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,lambda,boto3,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-lambda Python Package Guide\n\n## What This Package Is For\n\n`mypy-boto3-lambda` is a stubs-only package for the Lambda service in `boto3`. It adds static typing for `Session().client(\"lambda\")`, Lambda paginators, waiters, literals, and typed dict request or response shapes.\n\nUse it when your code already uses `boto3` for AWS Lambda and you want better editor completion plus stricter checking from `mypy`, `pyright`, Pylance, or similar tools.\n\nIt does not replace the runtime SDK. Your application still uses `boto3` to talk to AWS.\n\n## Golden Rule\n\n- Install `boto3` for runtime behavior and `mypy-boto3-lambda` or `boto3-stubs[lambda]` for typing.\n- Keep the `boto3` and stub package versions on the same `1.42.x` line when possible.\n- Treat AWS credentials, profiles, and regions as `boto3` setup concerns, not stub-package concerns.\n- If you use the lite package, expect to add explicit annotations because `session.client(\"lambda\")` overloads are not provided.\n\n## Install\n\nRecommended explicit pin for runtime plus service-specific stubs:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"mypy-boto3-lambda==1.42.37\"\n```\n\nIf you want automatic type discovery for `boto3.client(\"lambda\")` and `Session().client(\"lambda\")`, install the full extras package instead:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"boto3-stubs[lambda]==1.42.37\"\n```\n\nRAM-friendlier option:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"boto3-stubs-lite[lambda]==1.42.37\"\n```\n\nNotes:\n\n- `boto3-stubs-lite[lambda]` does not provide `session.client/resource` overloads, so you usually need explicit imported types.\n- The standalone `mypy-boto3-lambda` package is useful when you only want the Lambda service stubs instead of the broader extras package.\n- The maintainer docs root is rolling and can show newer generator examples than `1.42.37`; pin to the PyPI release your project actually installs.\n\n## Authentication And Region Setup\n\nThe stubs package does not load credentials or choose a region. `boto3` still follows the normal AWS credential chain and needs a region before requests succeed.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nUseful points from the boto3 docs:\n\n- `boto3` checks explicit client or session parameters first, then environment variables, then shared AWS config and credentials files, and then runtime providers such as container credentials or EC2 instance metadata.\n- `Session(region_name=...)` sets the default region for clients created from that session.\n- `Session.client(...)` can still override `region_name`, `endpoint_url`, and credential parameters per client.\n\n## Core Usage\n\n### Typed Lambda client\n\nThis is the core pattern when you want explicit typing without relying on IDE auto-discovery:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lambda.client import LambdaClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nlambda_client: LambdaClient = session.client(\"lambda\")\n```\n\nYou can now call normal boto3 Lambda operations with editor and type-checker help:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lambda.client import LambdaClient\n\nsession = Session(region_name=\"us-east-1\")\nlambda_client: LambdaClient = session.client(\"lambda\")\n\nresponse = lambda_client.invoke(\n    FunctionName=\"process-order\",\n    InvocationType=\"RequestResponse\",\n    Payload=b'{\"order_id\":\"1234\"}',\n)\n\npayload = response[\"Payload\"].read()\nprint(payload)\n```\n\n### Paginators\n\nThe package exposes paginator classes under `mypy_boto3_lambda.paginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lambda.client import LambdaClient\nfrom mypy_boto3_lambda.paginator import ListFunctionsPaginator\n\nclient: LambdaClient = Session(region_name=\"us-east-1\").client(\"lambda\")\npages: ListFunctionsPaginator = client.get_paginator(\"list_functions\")\n\nfor page in pages.paginate():\n    for fn in page.get(\"Functions\", []):\n        print(fn[\"FunctionName\"])\n```\n\nUseful paginator names include `list_functions`, `list_aliases`, `list_event_source_mappings`, and `list_versions_by_function`.\n\n### Waiters\n\nLambda-specific waiters are typed under `mypy_boto3_lambda.waiter`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lambda.client import LambdaClient\nfrom mypy_boto3_lambda.waiter import FunctionActiveWaiter\n\nclient: LambdaClient = Session(region_name=\"us-east-1\").client(\"lambda\")\nwaiter: FunctionActiveWaiter = client.get_waiter(\"function_active\")\n\nwaiter.wait(FunctionName=\"process-order\")\n```\n\nUseful waiter names include `function_active`, `function_updated`, `function_exists`, and `published_version_active`.\n\n### Literals And Type Definitions\n\nThe generated `literals` and `type_defs` modules are useful when you want stronger typing for inputs and response shapes.\n\n```python\nfrom mypy_boto3_lambda.literals import ApplicationLogLevelType, InvocationTypeType\nfrom mypy_boto3_lambda.type_defs import FunctionConfigurationTypeDef\n\ndef summarize_config(\n    config: FunctionConfigurationTypeDef,\n    invocation_type: InvocationTypeType,\n    app_log_level: ApplicationLogLevelType,\n) -> tuple[str | None, str, str]:\n    return (\n        config.get(\"FunctionName\"),\n        invocation_type,\n        app_log_level,\n    )\n```\n\nUse these modules when agents need to validate enum-like values or document-shaped dictionaries instead of leaving everything as plain `dict[str, Any]`.\n\n## TYPE_CHECKING Pattern\n\nIf you want stubs available only during development and CI type checking, gate the imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_lambda.client import LambdaClient\nelse:\n    LambdaClient = object\n\nsession = Session(region_name=\"us-east-1\")\nlambda_client: \"LambdaClient\" = session.client(\"lambda\")\n```\n\nThis avoids requiring the stub package at runtime, though some linters and IDEs behave better when the stubs are installed in the active environment.\n\n## Tooling Notes\n\n- `boto3-stubs[lambda]` is the easiest path for VS Code, Pylance, mypy, and pyright because no explicit client annotation is usually required.\n- The maintainer docs recommend `boto3-stubs-lite` for PyCharm when literal-heavy overloads make the IDE slow.\n- The package docs also note that `TYPE_CHECKING` is safe, but some `pylint` setups may need `object` fallbacks for imported stub types.\n\n## Common Pitfalls\n\n- This package is `Stubs Only`. Installing it without `boto3` does not give you a working Lambda client at runtime.\n- A typed client does not guarantee valid AWS credentials, region, IAM permissions, or Lambda payload semantics.\n- If you use `boto3-stubs-lite[lambda]`, `Session().client(\"lambda\")` will not infer to `LambdaClient` automatically.\n- The live docs site is generated from the latest builder output and may show commands for a newer `boto3` patch than the PyPI release you pinned.\n- Lambda invoke payloads are still raw bytes or streams at runtime; the stubs improve types, but they do not JSON-encode or decode payloads for you.\n- Some Lambda APIs shown in the generated paginator and type-def lists are newer service surface areas. If your environment is pinned to an older `boto3` or botocore build, verify that the operation exists before copying generated examples.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-lambda 1.42.37` as the latest release on March 12, 2026, released on January 28, 2026.\n- PyPI describes the package as type annotations for `boto3 Lambda 1.42.37` generated with `mypy-boto3-builder 8.12.0`.\n- The maintainer docs root is not patch-pinned. During this session it showed install-generation examples for a newer `boto3 1.42.66`, so prefer PyPI for exact package pinning and the docs root for current symbol coverage.\n\n## Official Sources Used\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_lambda/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-lambda/`\n- boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- boto3 session reference: `https://docs.aws.amazon.com/boto3/latest/reference/core/session.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-lex-runtime/python/DOC.md",
    "content": "---\nname: mypy-boto3-lex-runtime\ndescription: \"Typed boto3 stubs for Amazon Lex Runtime V1 clients, literals, and TypedDict request and response shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,lex,lex-runtime,boto3,mypy,pyright,type-checking,stubs\"\n---\n\n# mypy-boto3-lex-runtime Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-lex-runtime` is a stubs-only package for `boto3.client(\"lex-runtime\")`, not the runtime SDK. Install `boto3` as well, and treat this package as a legacy Amazon Lex V1 typing aid. AWS states that support for Amazon Lex V1 ended on September 15, 2025, so new work should target Lex V2 and `mypy-boto3-lexv2-runtime` instead.\n\n## Install\n\nChoose one install mode and keep the stubs aligned with the `boto3` version you pin.\n\n### Recommended: full boto3 stubs\n\nUse this when you want `Session().client(\"lex-runtime\")` to infer `LexRuntimeServiceClient` automatically in editors and type checkers.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[lex-runtime]==1.42.3\"\n```\n\n### Standalone service package\n\nUse this when you only want the Lex Runtime stubs and are fine with explicit annotations.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-lex-runtime==1.42.3\"\n```\n\n### Lite package\n\nThe maintainer docs note that the lite package is more RAM-friendly but does not provide `session.client/resource` overloads, so explicit client annotations are required.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[lex-runtime]==1.42.3\"\n```\n\n### Local generation for exact lockfile alignment\n\nPyPI and the maintainer docs recommend local generation when you need the stubs to match an exact boto3 build.\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\nSelect `boto3-stubs` and then add the `LexRuntimeService` service.\n\n## Authentication And Runtime Setup\n\n`mypy-boto3-lex-runtime` adds typing only. Credentials, regions, retries, and HTTP behavior still come from `boto3`.\n\nAWS documents that boto3 searches for credentials in a standard order, starting with explicit client or session parameters, then environment variables, shared credentials files, config files, container credentials, and finally EC2 instance metadata.\n\nPractical local setup:\n\n```bash\naws configure --profile lex-dev\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nOr export credentials directly:\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"   # only when using temporary credentials\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nMinimal typed client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lex_runtime import LexRuntimeServiceClient\n\nsession = Session(profile_name=\"lex-dev\", region_name=\"us-east-1\")\nclient: LexRuntimeServiceClient = session.client(\"lex-runtime\")\n```\n\nIf you use the standalone or lite package, keep the explicit annotation even though the runtime object still comes from `boto3`.\n\n## Core Usage\n\n### Typed `post_text`\n\nLex Runtime V1 exposes these main boto3 client operations: `delete_session`, `get_session`, `post_content`, `post_text`, and `put_session`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lex_runtime import LexRuntimeServiceClient\nfrom mypy_boto3_lex_runtime.type_defs import (\n    PostTextRequestRequestTypeDef,\n    PostTextResponseTypeDef,\n)\n\nclient: LexRuntimeServiceClient = Session(region_name=\"us-east-1\").client(\"lex-runtime\")\n\nrequest: PostTextRequestRequestTypeDef = {\n    \"botName\": \"OrderPizzaBot\",\n    \"botAlias\": \"prod\",\n    \"userId\": \"user-123\",\n    \"inputText\": \"I want a pizza\",\n}\n\nresponse: PostTextResponseTypeDef = client.post_text(**request)\nprint(response.get(\"dialogState\"))\nprint(response.get(\"message\"))\n```\n\nUse a stable `userId` that does not contain personal data. AWS documents the `userId` field as required for runtime calls.\n\n### Typed session inspection and mutation\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lex_runtime import LexRuntimeServiceClient\nfrom mypy_boto3_lex_runtime.type_defs import (\n    GetSessionRequestRequestTypeDef,\n    PutSessionRequestRequestTypeDef,\n)\n\nclient: LexRuntimeServiceClient = Session(region_name=\"us-east-1\").client(\"lex-runtime\")\n\nget_request: GetSessionRequestRequestTypeDef = {\n    \"botName\": \"OrderPizzaBot\",\n    \"botAlias\": \"prod\",\n    \"userId\": \"user-123\",\n}\n\nsession_state = client.get_session(**get_request)\n\nput_request: PutSessionRequestRequestTypeDef = {\n    \"botName\": \"OrderPizzaBot\",\n    \"botAlias\": \"prod\",\n    \"userId\": \"user-123\",\n    \"accept\": \"text/plain; charset=utf-8\",\n    \"sessionAttributes\": {\n        \"channel\": \"web\",\n        \"tenant\": \"sandbox\",\n    },\n}\n\nclient.put_session(**put_request)\n```\n\n`put_session` is the runtime call to seed or replace session state from your application. AWS documents `accept` as controlling whether the response is text or audio.\n\n### Literals and TypedDict helpers\n\nThe stubs package also gives you service-specific literals and request or response shapes for your own helper functions.\n\n```python\nfrom mypy_boto3_lex_runtime.literals import ConfirmationStatusType\nfrom mypy_boto3_lex_runtime.type_defs import ActiveContextTimeToLiveTypeDef\n\ndef normalize_status(status: ConfirmationStatusType) -> str:\n    return status\n\ndef build_ttl(seconds: int, turns: int) -> ActiveContextTimeToLiveTypeDef:\n    return {\n        \"timeToLiveInSeconds\": seconds,\n        \"turnsToLive\": turns,\n    }\n```\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nUse this pattern when stubs are installed only in development or CI environments.\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_lex_runtime import LexRuntimeServiceClient\nelse:\n    LexRuntimeServiceClient = object\n\nclient: LexRuntimeServiceClient = boto3.client(\"lex-runtime\", region_name=\"us-east-1\")\n```\n\n## Configuration Notes\n\n- The boto3 service string is exactly `lex-runtime`.\n- This package types the Lex V1 runtime client. Lex V2 uses a different client name: `lexv2-runtime`.\n- Prefer `Session(profile_name=..., region_name=...)` in application setup so region and credential selection stay explicit.\n- Do not hard-code credentials. AWS documents environment variables, shared config, IAM Identity Center, container credentials, and instance metadata as supported options.\n- If you use `boto3-stubs-lite[lex-runtime]` or the standalone package, write explicit return annotations for client factories because automatic overload inference is reduced.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-lex-runtime` as the runtime SDK. If `boto3` is missing, type checking may pass while runtime imports fail.\n- Do not use `lex-runtime` for new chatbot development in 2026. AWS ended support for Amazon Lex V1 on September 15, 2025.\n- Do not confuse Lex V1 runtime calls (`post_text`, `post_content`) with Lex V2 runtime calls (`recognize_text`, `recognize_utterance`). They use different clients and request shapes.\n- Do not rely on implicit type inference when using `boto3-stubs-lite[lex-runtime]` or `mypy-boto3-lex-runtime` alone. Add `LexRuntimeServiceClient` annotations explicitly.\n- Do not drift `boto3` and stubs versions casually. The maintainer docs say the package version matches the related `boto3` version.\n- Do not put personally identifiable information into `userId`. AWS documents that field as required and intended only as a conversation identifier.\n- Do not depend on the deprecated `message` header behavior from `put_session`; AWS documents `encodedMessage` as the safer response field for locales where `message` may be null.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `mypy-boto3-lex-runtime 1.42.3` as the latest release, published on December 4, 2025.\n- The version used here, `1.42.3`, matches the live official PyPI release as of March 12, 2026.\n- The maintainer docs state that `mypy-boto3-lex-runtime` uses the related `boto3` version number. If you upgrade boto3 for this legacy integration, upgrade the stubs package in the same change.\n- AWS documentation now treats Amazon Lex V1 as end-of-support. On March 12, 2026, this package is mainly useful for maintaining or migrating legacy Lex V1 code, not for greenfield bot implementations.\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-lightsail/python/DOC.md",
    "content": "---\nname: mypy-boto3-lightsail\ndescription: \"Type annotations for boto3 Lightsail in Python, covering typed clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,lightsail,type-stubs,mypy,pyright,autocomplete,python\"\n---\n\n# mypy-boto3-lightsail Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-lightsail` is a typing package, not the runtime SDK. Install `boto3` for real Lightsail API calls, then choose one typing mode:\n\n- Use `boto3-stubs[lightsail]` when you want `Session().client(\"lightsail\")` to infer `LightsailClient` automatically in editors and type checkers.\n- Use `mypy-boto3-lightsail` when you want only the service-specific stubs package and are willing to annotate `LightsailClient`, paginator types, literals, and `type_defs` explicitly.\n- Use `boto3-stubs-lite[lightsail]` if full overload support is too heavy for PyCharm or constrained environments. The lite package drops `session.client/resource` overloads, so explicit annotations become more important.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matches the official PyPI package version checked on `2026-03-12`.\n- The maintainer docs state that these generated stubs track the related `boto3` version. Pin `boto3` and `mypy-boto3-lightsail` together when you want method signatures and typed request shapes to stay aligned.\n- The published docs root is a live generated documentation surface, not a version-pinned archive. When the hosted docs drift, prefer the package version you actually installed.\n- The published Lightsail stub docs expose `client`, `paginator`, `literals`, and `type_defs`. I did not find published `service_resource` or `waiter` modules for Lightsail in the current docs, so plan around typed clients and paginators.\n- The maintainer docs recommend local generation with `mypy-boto3-builder` when you need stubs that exactly match a different installed `boto3` build.\n\n## Install\n\nChoose one install mode based on how much inference support you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want `session.client(\"lightsail\")` to infer without extra annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[lightsail]==1.42.3\"\n```\n\n### Service-specific package only\n\nUse this when you want only the Lightsail stubs package and are fine with explicit annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-lightsail==1.42.3\"\n```\n\n### Lite aggregate package\n\nUse this when IDE performance matters more than automatic overload inference:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[lightsail]==1.42.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"boto3-stubs[lightsail]==1.42.3\"\npoetry add \"boto3==1.42.3\" \"boto3-stubs[lightsail]==1.42.3\"\n```\n\n## Authentication And Runtime Setup\n\n`mypy-boto3-lightsail` adds typing only. Credentials, region resolution, retries, endpoints, and actual API behavior still come from `boto3` and `botocore`.\n\nAWS documents that boto3 searches for credentials in the standard provider chain, including:\n\n1. Explicit credentials passed in code\n2. Environment variables\n3. Shared AWS config and credentials files\n4. Container or instance role credentials\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_lightsail.client import LightsailClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n\nlightsail: LightsailClient = session.client(\n    \"lightsail\",\n    config=Config(\n        retries={\n            \"mode\": \"standard\",\n            \"max_attempts\": 10,\n        }\n    ),\n)\n```\n\nKeep the region explicit. Lightsail resources are regional, and missing or mismatched region configuration is an easy way to get `NoRegionError` or to query the wrong account region.\n\n## Core Usage\n\n### Typed Lightsail client\n\nUse the generated client type for normal boto3 calls:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lightsail.client import LightsailClient\n\ndef get_lightsail_client() -> LightsailClient:\n    return Session(region_name=\"us-east-1\").client(\"lightsail\")\n\nclient = get_lightsail_client()\nresponse = client.get_instances()\n\nfor instance in response.get(\"instances\", []):\n    print(instance[\"name\"])\n```\n\n### Typed paginator\n\nThe stub docs publish overloads for many paginated operations, including `get_instances`, `get_operations`, `get_key_pairs`, `get_domains`, and `get_relational_databases`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lightsail.client import LightsailClient\nfrom mypy_boto3_lightsail.paginator import GetInstancesPaginator\n\nclient: LightsailClient = Session(region_name=\"us-east-1\").client(\"lightsail\")\npaginator: GetInstancesPaginator = client.get_paginator(\"get_instances\")\n\nfor page in paginator.paginate():\n    for instance in page.get(\"instances\", []):\n        print(instance[\"name\"])\n```\n\n### Typed request dictionaries\n\nUse generated request `TypedDict` shapes when helper functions assemble kwargs before the client call:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lightsail.client import LightsailClient\nfrom mypy_boto3_lightsail.type_defs import GetInstanceRequestTypeDef\n\nclient: LightsailClient = Session(region_name=\"us-east-1\").client(\"lightsail\")\n\nparams: GetInstanceRequestTypeDef = {\n    \"instanceName\": \"web-1\",\n}\n\nresponse = client.get_instance(**params)\nprint(response[\"instance\"][\"name\"])\n```\n\n### Typed response dictionaries and literals\n\nUse `type_defs` for response handling and `literals` for constrained string values:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_lightsail.client import LightsailClient\nfrom mypy_boto3_lightsail.literals import InstanceAccessProtocolType\nfrom mypy_boto3_lightsail.type_defs import GetInstanceAccessDetailsResultTypeDef\n\nclient: LightsailClient = Session(region_name=\"us-east-1\").client(\"lightsail\")\nprotocol: InstanceAccessProtocolType = \"ssh\"\n\nresult: GetInstanceAccessDetailsResultTypeDef = client.get_instance_access_details(\n    instanceName=\"web-1\",\n    protocol=protocol,\n)\n\nprint(result[\"accessDetails\"][\"username\"])\n```\n\n### `TYPE_CHECKING` guard for runtime-safe imports\n\nIf production installs omit stub packages, keep the imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_lightsail.client import LightsailClient\nelse:\n    LightsailClient = object\n\nclient: \"LightsailClient\" = boto3.Session(region_name=\"us-east-1\").client(\"lightsail\")\n```\n\nThe maintainer docs call this safe and specifically note it as a workaround for a common `pylint` complaint about names defined only under `TYPE_CHECKING`.\n\n## Tooling Notes\n\n- `boto3-stubs[lightsail]` is the easiest choice for VSCode, Pylance, mypy, and pyright because it provides automatic boto3 client overloads.\n- The maintainer PyPI docs warn that PyCharm can become slow on `Literal` overloads. If that happens, switch to `boto3-stubs-lite[lightsail]` or disable PyCharm's built-in type checker and run `mypy` or `pyright` separately.\n- The standalone `mypy-boto3-lightsail` package is useful when you want only Lightsail typings installed, but you should annotate factory return types explicitly instead of relying on boto3 overload inference.\n- If you need exact parity with a newer or older boto3 lockfile, generate service stubs locally with `mypy-boto3-builder` rather than trusting the hosted docs snapshot.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-lightsail` as the runtime SDK. Real AWS calls still require `boto3`.\n- Do not confuse the package name and the import root: install `mypy-boto3-lightsail`, import `mypy_boto3_lightsail`.\n- Do not expect `boto3-stubs-lite[lightsail]` or the standalone service package to infer `Session().client(\"lightsail\")` automatically in all tooling. Add explicit `LightsailClient` annotations.\n- Do not assume Lightsail has typed resource or waiter modules just because other AWS services do. The current published stub docs expose typed clients and paginators, not a Lightsail resource layer.\n- Do not forget region selection. Lightsail resources such as instances, buckets, databases, and distributions live in specific regions.\n- Do not attribute auth or retry behavior to the stubs package. Credential resolution, endpoint selection, and retry configuration are still boto3 concerns.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_lightsail/`\n- Maintainer client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_lightsail/client/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-lightsail/`\n- AWS boto3 Lightsail reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lightsail.html`\n- AWS boto3 credential guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- AWS boto3 clients guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-logs/python/DOC.md",
    "content": "---\nname: mypy-boto3-logs\ndescription: \"mypy-boto3-logs package guide for typed boto3 CloudWatch Logs clients, paginators, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.60\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,cloudwatch-logs,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-logs Python Package Guide\n\n## Golden Rule\n\n- Keep `boto3` as the runtime AWS SDK. `mypy-boto3-logs` only adds static typing for the CloudWatch Logs client.\n- Prefer `boto3-stubs[logs]` when you want `Session.client(\"logs\")` overload inference with minimal annotation work.\n- Use standalone `mypy-boto3-logs` when you want only the CloudWatch Logs stubs and are willing to annotate clients explicitly.\n- Treat PyPI as the source of truth for the exact published package version. On March 12, 2026, PyPI listed `1.42.60`, while the generated docs page already said the package docs were compatible with `boto3==1.42.63`.\n\n## Install\n\nIf you want the narrow standalone service stubs, pin them with the matching boto3 line:\n\n```bash\npython -m pip install \"boto3==1.42.60\" \"mypy-boto3-logs==1.42.60\"\n```\n\nIf you want the upstream-recommended overloads for `Session.client(\"logs\")`, install the bundled package instead:\n\n```bash\npython -m pip install \"boto3-stubs[logs]\"\n```\n\nLower-memory bundle:\n\n```bash\npython -m pip install \"boto3-stubs-lite[logs]\"\n```\n\nNotes:\n\n- `boto3-stubs-lite[logs]` omits the `Session.client(...)` overloads, so explicit annotations or `cast(...)` become more important.\n- For `uv` or Poetry, keep the same rule: install `boto3` for runtime, and keep the stub package in the same environment that `mypy`, `pyright`, or your IDE analyzes.\n\n## Initialize And Authenticate\n\n`mypy-boto3-logs` does not change AWS credentials, region resolution, retries, or endpoints. Those still come from normal `boto3` and `botocore` behavior.\n\nCommon credential sources, in boto3's documented search order:\n\n1. explicit credentials passed to `client(...)` or `Session(...)`\n2. environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`\n3. shared config and credentials files, including `AWS_PROFILE`\n4. container or instance credentials in AWS runtimes\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=observability-dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nTyped client initialization:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_logs.client import CloudWatchLogsClient\n\nsession = Session(profile_name=\"observability-dev\", region_name=\"us-west-2\")\nlogs: CloudWatchLogsClient = session.client(\"logs\")\n```\n\nIf you create sessions manually, keep boto3's session guidance in mind: do not share a `Session` object across threads or processes. Create one session per thread or worker when concurrency matters.\n\n## Core Usage\n\n### Typed CloudWatch Logs client\n\nUse the generated client type for normal CloudWatch Logs operations:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_logs.client import CloudWatchLogsClient\n\nsession = Session(profile_name=\"observability-dev\", region_name=\"us-west-2\")\nlogs: CloudWatchLogsClient = session.client(\"logs\")\n\nresponse = logs.describe_log_groups(\n    logGroupNamePrefix=\"/aws/lambda/\",\n    limit=20,\n)\n\nfor group in response.get(\"logGroups\", []):\n    print(group[\"logGroupName\"])\n```\n\nThis follows the same runtime call shape as the boto3 CloudWatch Logs client docs, but the response and operation names stop collapsing to `Any`.\n\n### Dev-only stubs with `TYPE_CHECKING`\n\nIf production images do not install the stub package, keep the imports type-only:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_logs.client import CloudWatchLogsClient\n\nsession = Session(region_name=\"us-west-2\")\nlogs = cast(\"CloudWatchLogsClient\", session.client(\"logs\"))\n```\n\n### Typed paginators\n\nThe generated docs expose paginator classes for CloudWatch Logs operations such as `describe_log_groups`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_logs.client import CloudWatchLogsClient\nfrom mypy_boto3_logs.paginator import DescribeLogGroupsPaginator\n\nlogs: CloudWatchLogsClient = Session(region_name=\"us-west-2\").client(\"logs\")\npaginator: DescribeLogGroupsPaginator = logs.get_paginator(\"describe_log_groups\")\n\nfor page in paginator.paginate(logGroupNamePrefix=\"/aws/lambda/\"):\n    for group in page.get(\"logGroups\", []):\n        print(group[\"logGroupName\"])\n```\n\n### Typed event shapes\n\nUse the generated `type_defs` module when helper functions pass AWS-shaped dictionaries around:\n\n```python\nfrom collections.abc import Sequence\n\nfrom mypy_boto3_logs.type_defs import FilteredLogEventTypeDef\n\ndef extract_messages(events: Sequence[FilteredLogEventTypeDef]) -> list[str]:\n    return [event[\"message\"] for event in events if \"message\" in event]\n```\n\nExample call using the normal boto3 runtime client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_logs.client import CloudWatchLogsClient\n\nlogs: CloudWatchLogsClient = Session(region_name=\"us-west-2\").client(\"logs\")\n\nresponse = logs.filter_log_events(\n    logGroupName=\"/aws/lambda/my-function\",\n    limit=50,\n)\n\nmessages = [event[\"message\"] for event in response.get(\"events\", []) if \"message\" in event]\n```\n\n## Type Checking Notes\n\n- Install the stubs in the same environment as `mypy`, `pyright`, or your editor language server.\n- Import from `mypy_boto3_logs`, not `mypy-boto3-logs`. The package name uses hyphens; the Python module uses underscores.\n- Standalone `mypy-boto3-logs` is best when you want one narrow dependency and explicit annotations.\n- `boto3-stubs[logs]` is best when you want better inference from `Session.client(\"logs\")` and broader boto3 typing support.\n\n## Common Pitfalls\n\n- Do not install only `mypy-boto3-logs` and expect AWS calls to work. You still need `boto3`.\n- Do not pass the package name to boto3. The service id is `\"logs\"`, not `\"mypy-boto3-logs\"`.\n- Do not assume the generated docs site and PyPI are on the same patch version. For this package, the docs page was ahead of the last published wheel during this session.\n- Do not assume a resource-oriented API or waiter coverage just because other boto3 services have them. The maintainer docs for this package focus on the CloudWatch Logs client, paginators, literals, and typed shapes.\n- Do not treat good type checking as proof that IAM permissions, log group names, retention settings, or throttling behavior are correct. Runtime failures still come from normal boto3 and botocore exceptions.\n- Do not share one boto3 `Session` across threads or processes.\n\n## Version-Sensitive Notes For `1.42.60`\n\n- The version used here for this session was `1.42.60`, and PyPI still reported `1.42.60` on March 12, 2026.\n- PyPI reports Python `>=3.9` for this release line.\n- The package docs page currently says the generated stubs are compatible with `boto3==1.42.63`, so the docs site can move ahead of the last published `mypy-boto3-logs` wheel.\n- If exact AWS model parity matters, pin `boto3`, `botocore`, and the stub package from the same validated release line instead of assuming \"latest\" is synchronized everywhere.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_logs/\n- Maintainer versioning guide: https://youtype.github.io/boto3_stubs_docs/#versioning\n- PyPI project page: https://pypi.org/project/mypy-boto3-logs/\n- PyPI JSON API: https://pypi.org/pypi/mypy-boto3-logs/json\n- boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- boto3 session guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html\n- boto3 CloudWatch Logs `describe_log_groups`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs/client/describe_log_groups.html\n- boto3 CloudWatch Logs `filter_log_events`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs/client/filter_log_events.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-macie2/python/DOC.md",
    "content": "---\nname: mypy-boto3-macie2\ndescription: \"mypy-boto3-macie2 package guide for typed boto3 Macie2 clients, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.16\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,macie2,boto3,typing,stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-macie2 Python Package Guide\n\n## What It Is\n\n`mypy-boto3-macie2` is a stubs-only package for the Macie2 part of `boto3`. Keep using `boto3` for runtime AWS calls, and install this package or `boto3-stubs[macie2]` only to improve static typing, editor completion, and request or response shape checking.\n\nMacie2 is client-oriented in boto3. The maintainer docs expose typed clients, paginators, waiters, literals, and `type_defs`, but not a service-resource workflow.\n\nUse it when you want:\n\n- a typed `Macie2Client` for `Session.client(\"macie2\")`\n- typed paginator and waiter objects\n- literal unions for string-valued fields such as finding status enums\n- generated `TypedDict` request and response shapes for stricter Macie calls\n\n## Install\n\n### Recommended: full `boto3-stubs` extra\n\nUse this when you want the smoothest typing for `Session().client(\"macie2\")` without adding explicit casts everywhere.\n\n```bash\npython -m pip install \"boto3==1.40.16\" \"boto3-stubs[macie2]==1.40.16\"\n```\n\n### Standalone service stub package\n\nUse this when you only want the Macie2 stubs and do not mind explicit type annotations.\n\n```bash\npython -m pip install \"boto3==1.40.16\" \"mypy-boto3-macie2==1.40.16\"\n```\n\n### Lite variant\n\nUse this when IDE memory or indexing cost matters more than automatic overload inference.\n\n```bash\npython -m pip install \"boto3==1.40.16\" \"boto3-stubs-lite[macie2]==1.40.16\"\n```\n\nInstall notes:\n\n- `mypy-boto3-macie2` does not include the runtime SDK. Without `boto3`, nothing works at runtime.\n- `boto3-stubs[macie2]` is usually the best development experience because it types `boto3.client(...)` and `Session.client(...)`.\n- `boto3-stubs-lite[macie2]` reduces overload coverage, so explicit imported types are often needed.\n- The maintainer docs root is a rolling latest page. Use PyPI for the exact release pin and the docs root for current package structure.\n\n## AWS Authentication And Region Setup\n\nThis package does not change AWS authentication. Credential lookup, region resolution, retries, and endpoint configuration still come from `boto3` and `botocore`.\n\nTypical local setup:\n\n```bash\naws configure --profile security\nexport AWS_PROFILE=security\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nImportant boto3 rules:\n\n1. Credentials passed directly to `Session(...)` or `client(...)` win first.\n2. Then boto3 checks environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.\n3. Then it checks shared AWS config and credentials files, followed by role-based providers such as IAM Identity Center, container credentials, or EC2 instance metadata.\n4. Region selection can come from the session, the client call, or `AWS_DEFAULT_REGION`.\n\nIf you need retry or timeout tuning, pass a normal botocore `Config`:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_macie2.client import Macie2Client\n\nsession = Session(profile_name=\"security\", region_name=\"us-east-1\")\nconfig = Config(\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n)\n\nmacie: Macie2Client = session.client(\"macie2\", config=config)\n```\n\n## Core Usage\n\n### Typed Macie2 client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_macie2.client import Macie2Client\n\nsession = Session(profile_name=\"security\", region_name=\"us-east-1\")\nmacie: Macie2Client = session.client(\"macie2\")\n\nresponse = macie.get_macie_session()\nprint(response[\"status\"])\n```\n\nThis is the main pattern when you install `mypy-boto3-macie2` directly instead of the umbrella extras package.\n\n### Typed paginators\n\nThe maintainer docs expose paginator types such as `DescribeBucketsPaginator` and `ListFindingsPaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_macie2.client import Macie2Client\nfrom mypy_boto3_macie2.paginator import DescribeBucketsPaginator\n\nmacie: Macie2Client = Session(region_name=\"us-east-1\").client(\"macie2\")\npaginator: DescribeBucketsPaginator = macie.get_paginator(\"describe_buckets\")\n\nfor page in paginator.paginate():\n    for item in page.get(\"buckets\", []):\n        print(item[\"bucketName\"])\n```\n\n### Typed waiters\n\nMacie2 also exposes a waiter type for delayed finding visibility.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_macie2.client import Macie2Client\nfrom mypy_boto3_macie2.waiter import FindingRevealedWaiter\n\nmacie: Macie2Client = Session(region_name=\"us-east-1\").client(\"macie2\")\nwaiter: FindingRevealedWaiter = macie.get_waiter(\"finding_revealed\")\n\nwaiter.wait(id=\"example-finding-id\")\n```\n\n### Literals And TypedDict helpers\n\nUse the generated `literals` and `type_defs` modules when you want stronger typing than `dict[str, Any]`.\n\n```python\nfrom mypy_boto3_macie2.literals import FindingStatusType\nfrom mypy_boto3_macie2.type_defs import BucketCriteriaForJobTypeDef\n\nstatus: FindingStatusType = \"NEW\"\n\ncriteria: BucketCriteriaForJobTypeDef = {\n    \"excludes\": {\n        \"and\": [\n            {\n                \"simpleCriterion\": {\n                    \"comparator\": \"EQ\",\n                    \"key\": \"S3_BUCKET_EFFECTIVE_PERMISSION\",\n                    \"values\": [\"PUBLIC\"],\n                }\n            }\n        ]\n    }\n}\n```\n\n### `TYPE_CHECKING` pattern\n\nIf production images omit dev-only stub packages, keep the imports behind `TYPE_CHECKING` and annotate with a string type:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_macie2.client import Macie2Client\nelse:\n    Macie2Client = object\n\ndef make_client() -> \"Macie2Client\":\n    return Session(region_name=\"us-east-1\").client(\"macie2\")\n```\n\n## Configuration Notes\n\n- The runtime service name is still `\"macie2\"`, not `\"mypy-boto3-macie2\"`.\n- Use `Session(region_name=...)` or `client(..., region_name=...)` explicitly when the environment is not unambiguous.\n- Retry, proxy, TLS, and timeout settings still come from `botocore.config.Config`.\n- Generated types help with request parameters and response shapes, but they do not guarantee that your IAM permissions, Macie account status, or region setup are correct.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-macie2` and expecting a working SDK at runtime. You still need `boto3`.\n- Using the package name instead of the boto3 service name. The client call is `session.client(\"macie2\")`.\n- Expecting `boto3-stubs-lite[macie2]` to infer `Session().client(\"macie2\")` automatically.\n- Copying the rolling docs root without checking the installed PyPI version when exact generated symbol names matter.\n- Treating the stub package as an auth or config layer. Credentials, profiles, regions, retries, and endpoints are still boto3 concerns.\n- Assuming every boto3 service has a typed resource layer. Macie2 is documented here as a typed client, paginator, waiter, literal, and `type_defs` surface.\n\n## Version-Sensitive Notes\n\n- The maintainer docs site is a rolling latest view, while PyPI is the safer source for exact published version pins. This guide is pinned to `1.40.16`, the package version visible on PyPI on `2026-03-12`.\n- The maintainer versioning docs say stub package versions track the related `boto3` version line, so keep `boto3` and the stub package aligned when exact API coverage matters.\n- PyPI marks the package as `Typing :: Stubs Only`; this is a development-time dependency, not a runtime AWS client.\n- The maintainer docs root is not patch-pinned. Prefer PyPI for exact installation pins and use the docs site to inspect the latest module layout and generated symbols.\n\n## Official Sources Used\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_macie2/`\n- Maintainer versioning docs: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-macie2/`\n- AWS Macie2 boto3 reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/macie2.html`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-mediaconvert/python/DOC.md",
    "content": "---\nname: mypy-boto3-mediaconvert\ndescription: \"Type stubs for boto3 MediaConvert clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.37\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,mediaconvert,boto3,python,typing,stubs,mypy,pyright,transcoding\"\n---\n\n# mypy-boto3-mediaconvert Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-mediaconvert` is a stubs-only package. Keep `boto3` installed for real AWS Elemental MediaConvert API calls, and use this package only for static typing, autocomplete, literals, and `TypedDict` shapes.\n\nFor most projects:\n\n- Use `boto3-stubs[mediaconvert]` when you want `Session().client(\"mediaconvert\")` inference in editors and type checkers.\n- Use `mypy-boto3-mediaconvert` when you want only the MediaConvert typing package and are willing to annotate `MediaConvertClient` and paginator types explicitly.\n- Use `boto3-stubs-lite[mediaconvert]` if PyCharm or memory usage becomes a problem; the maintainer docs note that the lite package drops `session.client/resource` overloads.\n\n## Install\n\nRecommended when you want boto3 plus automatic client inference:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"boto3-stubs[mediaconvert]==1.42.37\"\n```\n\nStandalone MediaConvert stubs:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"mypy-boto3-mediaconvert==1.42.37\"\n```\n\nLower-memory fallback:\n\n```bash\npython -m pip install \"boto3==1.42.37\" \"boto3-stubs-lite[mediaconvert]==1.42.37\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.37\" \"boto3-stubs[mediaconvert]==1.42.37\"\npoetry add \"boto3==1.42.37\" \"boto3-stubs[mediaconvert]==1.42.37\"\n```\n\nNotes:\n\n- Keep the `boto3` and stub versions aligned. The maintainer package tracks the related boto3 version line.\n- If you install only `mypy-boto3-mediaconvert`, runtime imports will still need `boto3`.\n- The maintainer docs also support local generation with `uvx --with 'boto3==1.42.37' mypy-boto3-builder` when you need an exact pinned output.\n\n## Initialize And Setup\n\nAuthentication and region handling still come from normal boto3 configuration. AWS documents that boto3 searches for credentials in order, including explicit client or session parameters, environment variables, assume-role providers, shared AWS config files, container credentials, and EC2 instance metadata.\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_mediaconvert.client import MediaConvertClient\n\nsession = Session(profile_name=\"media\", region_name=\"us-west-2\")\nconfig = Config(\n    retries={\n        \"mode\": \"standard\",\n        \"max_attempts\": 10,\n    }\n)\n\nmediaconvert: MediaConvertClient = session.client(\"mediaconvert\", config=config)\n```\n\nMediaConvert-specific notes:\n\n- Jobs, queues, presets, and templates are region-scoped. Set `region_name` or `AWS_DEFAULT_REGION` deliberately.\n- AWS marks `describe_endpoints` as deprecated and says it is no longer required; new code should target the regional endpoint directly instead of building fresh endpoint-discovery logic around that call.\n- The service reference documents a low-level client plus paginators. There is no documented resource-oriented stub surface for this package.\n\n## Core Usage\n\n### Typed client\n\nUse the real boto3 client and annotate it with the generated client type:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_mediaconvert.client import MediaConvertClient\n\ndef get_client() -> MediaConvertClient:\n    return Session(region_name=\"us-west-2\").client(\"mediaconvert\")\n\nclient = get_client()\n```\n\n### Typed paginator\n\nAWS documents `list_queues` as returning up to twenty queues at a time, and the stubs package exposes a matching paginator type:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_mediaconvert.client import MediaConvertClient\nfrom mypy_boto3_mediaconvert.paginator import ListQueuesPaginator\n\nclient: MediaConvertClient = Session(region_name=\"us-west-2\").client(\"mediaconvert\")\npaginator: ListQueuesPaginator = client.get_paginator(\"list_queues\")\n\nfor page in paginator.paginate(ListBy=\"NAME\", Order=\"ASCENDING\"):\n    for queue in page[\"Queues\"]:\n        print(queue[\"Name\"], queue[\"Arn\"])\n```\n\nThe maintainer docs list these paginator classes for this package:\n\n- `DescribeEndpointsPaginator`\n- `ListJobTemplatesPaginator`\n- `ListJobsPaginator`\n- `ListPresetsPaginator`\n- `ListQueuesPaginator`\n- `ListVersionsPaginator`\n- `SearchJobsPaginator`\n\n### Typed request shapes for helpers\n\nMediaConvert job payloads are large. A practical pattern is to type helper functions with the generated `TypedDict` shapes instead of hand-waving request bodies as plain `dict`:\n\n```python\nfrom mypy_boto3_mediaconvert.type_defs import (\n    CreateJobRequestRequestTypeDef,\n    JobSettingsTypeDef,\n)\n\ndef build_job_request(\n    role_arn: str,\n    settings: JobSettingsTypeDef,\n) -> CreateJobRequestRequestTypeDef:\n    return {\n        \"Role\": role_arn,\n        \"Settings\": settings,\n    }\n```\n\nThe generated type definitions include high-value MediaConvert shapes such as:\n\n- `CreateJobRequestRequestTypeDef`\n- `CreateJobTemplateRequestRequestTypeDef`\n- `JobSettingsTypeDef`\n- `JobTemplateTypeDef`\n- `TagResourceRequestRequestTypeDef`\n\n### Literals for enum-like values\n\nUse the `literals` module when you want type-checked string values for MediaConvert enums:\n\n```python\nfrom mypy_boto3_mediaconvert.literals import AacAudioDescriptionBroadcasterMixType\n\nmix: AacAudioDescriptionBroadcasterMixType = \"BROADCASTER_MIXED_AD\"\n```\n\nThis is especially useful in job settings, where MediaConvert has many enum-like string fields.\n\n### `TYPE_CHECKING` guard for dev-only stubs\n\nIf you install typing packages only in development or CI, guard the imports and fall back to `object`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mediaconvert.client import MediaConvertClient\nelse:\n    MediaConvertClient = object\n\nclient: MediaConvertClient = boto3.client(\"mediaconvert\", region_name=\"us-west-2\")\n```\n\nThe maintainer docs explicitly recommend this pattern for `pylint` compatibility.\n\n## Configuration And Authentication\n\nThis package has no configuration surface of its own. If a call fails because of credentials, region, retries, endpoints, or IAM, fix the underlying boto3 setup.\n\nUseful setup patterns:\n\n```bash\naws configure\nexport AWS_PROFILE=media\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"media\", region_name=\"us-west-2\")\nclient = session.client(\"mediaconvert\")\n```\n\nMediaConvert runtime constraints that typing does not solve:\n\n- `create_job` requires an IAM role ARN, and AWS documents `Role` as required.\n- Job settings are large and service-specific; start from a known-good job template or AWS-generated example rather than inventing nested payloads from memory.\n- Queue, preset, and job-template names are account and region specific.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-mediaconvert` and expecting runtime AWS calls to work without `boto3`.\n- Importing the package name with hyphens instead of the Python import root `mypy_boto3_mediaconvert`.\n- Expecting automatic `Session().client(\"mediaconvert\")` inference when you installed only the standalone stub package or the lite bundle.\n- Building new code around `describe_endpoints`. AWS marks it deprecated and recommends sending requests directly to the regional endpoint instead.\n- Forgetting to set a region. MediaConvert resources are region-scoped and jobs often fail in confusing ways when the client region does not match your queues, presets, or templates.\n- Treating successful type checking as proof that IAM roles, S3 access, queue names, and MediaConvert job settings are valid.\n- Assuming there is a resource-oriented MediaConvert stub surface similar to S3. The documented package surface here is client, paginators, literals, and type definitions.\n- Copying request shapes from newer boto3 reference pages without checking them against the exact `1.42.37` package line you pinned.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `mypy-boto3-mediaconvert 1.42.37`, released on `2026-01-28`.\n- As of `2026-03-12`, the live AWS boto3 MediaConvert reference is already on a newer `1.42.54` to `1.42.56` patch line. Treat your installed `boto3` and stub versions as the source of truth when signatures drift.\n- The maintainer docs still recommend generating local stubs with `uvx --with 'boto3==1.42.37' mypy-boto3-builder` when you need an exact match for a pinned runtime dependency.\n- AWS documents `describe_endpoints` as deprecated and says it should not be used going forward. If older code relies on it, treat that as legacy compatibility work, not a pattern to copy into new code.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_mediaconvert/`\n- PyPI project: `https://pypi.org/project/mypy-boto3-mediaconvert/`\n- AWS boto3 MediaConvert service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert.html`\n- AWS boto3 `describe_endpoints` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/describe_endpoints.html`\n- AWS boto3 `list_queues` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/list_queues.html`\n- AWS boto3 `create_job` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/mediaconvert/client/create_job.html`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-memorydb/python/DOC.md",
    "content": "---\nname: mypy-boto3-memorydb\ndescription: \"mypy-boto3-memorydb package guide for typed boto3 MemoryDB clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,memorydb,boto3,mypy-boto3-memorydb,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-memorydb Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS calls and use `mypy-boto3-memorydb` only for static typing.\n\nIf you want type inference with normal `Session().client(\"memorydb\")` code, install `boto3-stubs[memorydb]`. If you install `mypy-boto3-memorydb` or `boto3-stubs-lite[memorydb]`, expect to add explicit `MemoryDBClient` annotations.\n\nMemoryDB is client-oriented in boto3. AWS publishes a MemoryDB client reference and paginators, but not a boto3 resource surface for this service, so do not plan around `Session().resource(\"memorydb\")`.\n\n## Install\n\n### Recommended for ordinary boto3 code\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[memorydb]==1.42.3\"\n```\n\nThis is the easiest option when you want IDEs and type checkers to infer `Session().client(\"memorydb\")` automatically.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[memorydb]==1.42.3\"\n```\n\nUse this when PyCharm or another editor struggles with literal-heavy overloads. The lite package is more RAM-friendly, but the maintainer docs say it does not provide `session.client()` and `session.resource()` overloads.\n\n### Standalone package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-memorydb==1.42.3\"\n```\n\nUse the standalone package when you only want the MemoryDB stubs package installed or when you prefer to keep stub imports behind `TYPE_CHECKING`.\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.3\" \"boto3-stubs[memorydb]==1.42.3\"\npoetry add \"boto3==1.42.3\" \"boto3-stubs[memorydb]==1.42.3\"\n```\n\n## Setup And Authentication\n\n`mypy-boto3-memorydb` does not change AWS authentication, region resolution, retries, or endpoints. Those still come from `boto3` and `botocore`.\n\nAWS's boto3 credentials guide says you need both credentials and a region configured, and that boto3 searches in a fixed order including:\n\n1. Explicit credentials passed to `boto3.client(...)`\n2. Explicit credentials passed to `boto3.Session(...)`\n3. Environment variables\n4. Assume-role and web-identity providers\n5. AWS IAM Identity Center credentials\n6. Shared credentials and config files\n7. Container or EC2 instance metadata credentials\n\nPractical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nMinimal typed client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_memorydb import MemoryDBClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: MemoryDBClient = session.client(\"memorydb\")\n```\n\nIf stubs are installed only in development, guard the import:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_memorydb import MemoryDBClient\nelse:\n    MemoryDBClient = object\n\nclient: \"MemoryDBClient\" = Session(region_name=\"us-east-1\").client(\"memorydb\")\n```\n\nThe `object` fallback matches the maintainer guidance for avoiding pylint complaints in non-`TYPE_CHECKING` mode.\n\n## Core Usage\n\n### Explicit client annotations\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_memorydb import MemoryDBClient\n\nclient: MemoryDBClient = Session(region_name=\"us-east-1\").client(\"memorydb\")\n\nresponse = client.describe_clusters(ShowShardDetails=False)\nfor cluster in response.get(\"Clusters\", []):\n    print(cluster[\"Name\"], cluster[\"Status\"])\n```\n\n### Typed paginator annotations\n\nThe maintainer docs publish typed paginators for MemoryDB listing calls including:\n\n- `describe_acls`\n- `describe_clusters`\n- `describe_engine_versions`\n- `describe_events`\n- `describe_multi_region_clusters`\n- `describe_parameter_groups`\n- `describe_parameters`\n- `describe_reserved_nodes_offerings`\n- `describe_reserved_nodes`\n- `describe_service_updates`\n- `describe_snapshots`\n- `describe_subnet_groups`\n- `describe_users`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_memorydb import MemoryDBClient\nfrom mypy_boto3_memorydb.paginator import DescribeClustersPaginator\n\nclient: MemoryDBClient = Session(region_name=\"us-east-1\").client(\"memorydb\")\npaginator: DescribeClustersPaginator = client.get_paginator(\"describe_clusters\")\n\nfor page in paginator.paginate(ShowShardDetails=False):\n    for cluster in page.get(\"Clusters\", []):\n        print(cluster[\"Name\"])\n```\n\n### Typed request and response fragments\n\nUse `type_defs` when your helpers accept or return AWS-shaped dictionaries:\n\n```python\nfrom mypy_boto3_memorydb.type_defs import ACLPendingChangesTypeDef\n\ndef read_pending_changes(value: ACLPendingChangesTypeDef) -> list[str]:\n    return value.get(\"UserNamesToRemove\", [])\n```\n\n### Literal value types\n\nUse literals when you want the checker to reject impossible string values:\n\n```python\nfrom mypy_boto3_memorydb.literals import AZStatusType\n\ndef accepts_status(value: AZStatusType) -> str:\n    return value\n```\n\n## Configuration Notes\n\n- Keep runtime configuration on the boto3 session or client, not in the stubs package.\n- Use `botocore.config.Config(...)` for retries, timeouts, or proxy settings.\n- Keep the service name exact: `session.client(\"memorydb\")`.\n- Treat the stubs package as a development dependency unless you intentionally want it in production images.\n\nExample client config:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_memorydb import MemoryDBClient\n\nconfig = Config(retries={\"mode\": \"standard\", \"max_attempts\": 10})\nclient: MemoryDBClient = Session(region_name=\"us-east-1\").client(\"memorydb\", config=config)\n```\n\n## Common Pitfalls\n\n- Install with `mypy-boto3-memorydb`, but import from `mypy_boto3_memorydb`.\n- `mypy-boto3-memorydb` is stub-only. It does not replace `boto3`, and it does not create a working runtime client by itself.\n- Do not expect a boto3 MemoryDB resource surface. AWS documents MemoryDB as a client-plus-paginators service.\n- Do not assume the lite package will infer `Session().client(\"memorydb\")` automatically; add explicit `MemoryDBClient` annotations.\n- Keep `boto3`, `botocore`, and the stubs package close in version. These stubs are generated from boto3 service models, so version drift can surface stale or missing types.\n- Typed code can still fail at runtime because of IAM permissions, region mismatches, service access, or request semantics. The stubs only improve static checking.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI lists `mypy-boto3-memorydb 1.42.3` as the latest release on March 12, 2026, published on December 4, 2025.\n- The live PyPI project page says the package version matches the related `boto3` version and follows Python packaging version specifiers.\n- The release history jumps from `1.41.0` to `1.42.3`; do not assume every boto3 patch number gets a matching standalone MemoryDB stub release.\n- The PyPI project links currently point to the `youtype/mypy_boto3_builder` repository for homepage, source, tracker, and releases. Use that live project metadata instead of older secondary references to other repo names.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_memorydb/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-memorydb/`\n- AWS MemoryDB boto3 reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/memorydb.html`\n- AWS boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Maintainer repository from the live PyPI project links: `https://github.com/youtype/mypy_boto3_builder`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-mwaa/python/DOC.md",
    "content": "---\nname: mypy-boto3-mwaa\ndescription: \"mypy-boto3-mwaa package guide for typed boto3 Amazon MWAA clients, paginators, literals, and TypedDict request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,mwaa,airflow,boto3,python,typing,type-stubs,mypy,pyright\"\n---\n\n# `mypy-boto3-mwaa` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-mwaa` is a typing package, not a runtime AWS SDK. Use `boto3` for real Amazon MWAA calls, and add this package only so `mypy`, `pyright`, and editors understand the MWAA client, paginator, literals, and generated request/response shapes.\n\nIf you want `Session.client(\"mwaa\")` to infer automatically, install `boto3-stubs[mwaa]`. If you install only `mypy-boto3-mwaa` or `boto3-stubs-lite[mwaa]`, annotate `MWAAClient` explicitly.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matched the live PyPI package and maintainer docs checked on `2026-03-12`.\n- PyPI marks this package as `Typing :: Stubs Only`, uploaded on `2025-12-04`, and notes it was generated by `mypy-boto3-builder 8.12.0`.\n- The maintainer versioning guide states that `boto3-stubs` and `mypy-boto3-*` versions track the related `boto3` release line. Keep `mypy-boto3-mwaa` close to the installed `boto3` version so signatures do not drift.\n- The maintainer docs URL is stable but not release-pinned. The AWS runtime docs I used are the latest boto3 service reference, not a frozen `1.42.3` snapshot, so prefer local stub generation when exact patch parity matters.\n- For MWAA specifically, the official materials I checked exposed a typed client, one paginator (`ListEnvironmentsPaginator`), literals, and `type_defs`. I did not find a published MWAA service-resource or waiter page in the maintainer docs search results used for this session.\n\n## Install\n\nChoose the install mode that matches how much boto3 type inference you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want `Session.client(\"mwaa\")` and `client.get_paginator(...)` to infer automatically:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[mwaa]==1.42.3\"\n```\n\n### Service-specific package only\n\nUse this when you only want the MWAA typing package and are comfortable adding explicit annotations:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-mwaa==1.42.3\"\n```\n\n### Lower-memory aggregate package\n\nUse this when the full stubs package is too heavy for the IDE or type-checking environment:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[mwaa]==1.42.3\"\n```\n\nNotes:\n\n- `boto3-stubs[mwaa]` gives the best overload-based inference.\n- `boto3-stubs-lite[mwaa]` is lighter, but the maintainer docs note that lite mode omits overloaded `session.client/resource` inference.\n- `mypy-boto3-mwaa` is useful when you want only MWAA typing support instead of the broader `boto3-stubs` extras package.\n\n## Initialize And Authenticate\n\nThis package does not change AWS authentication, retries, endpoints, or permissions. All runtime behavior still comes from normal `boto3` and `botocore` configuration.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\nfrom botocore.config import Config\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig = Config(\n    retries={\n        \"mode\": \"standard\",\n        \"max_attempts\": 10,\n    }\n)\n\nmwaa: \"MWAAClient\" = session.client(\"mwaa\", config=config)\n```\n\nUse the same credential sources you would use for any other boto3 client:\n\n- environment variables\n- shared AWS config and credentials files\n- IAM Identity Center or assume-role configuration\n- task, container, Lambda, or EC2 IAM roles\n\nMWAA is regional. Keep the session region aligned with the environment you are targeting.\n\n## Core Usage\n\n### Typed MWAA client\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\n\nmwaa: \"MWAAClient\" = boto3.Session(region_name=\"us-east-1\").client(\"mwaa\")\n\nresponse = mwaa.get_environment(Name=\"my-airflow-env\")\nenvironment = response[\"Environment\"]\n\nprint(environment[\"Status\"])\nprint(environment.get(\"AirflowVersion\"))\nprint(environment.get(\"WebserverUrl\"))\n```\n\nUse `get_environment` before destructive or follow-up operations when you need to confirm the environment state and webserver endpoint.\n\n### Typed paginator\n\nThe docs site uses a `/paginators/` URL, but the Python import module is singular: `mypy_boto3_mwaa.paginator`.\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\n    from mypy_boto3_mwaa.paginator import ListEnvironmentsPaginator\n\nmwaa: \"MWAAClient\" = boto3.Session(region_name=\"us-east-1\").client(\"mwaa\")\npaginator: \"ListEnvironmentsPaginator\" = mwaa.get_paginator(\"list_environments\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 25}):\n    for env_name in page.get(\"Environments\", []):\n        print(env_name)\n```\n\n`list_environments` returns environment names, so call `get_environment` for each name when you also need status, Airflow version, or webserver details.\n\n### Generate a CLI token for the Airflow CLI\n\n`create_cli_token` is the normal path for authenticated CLI access to an MWAA environment:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\n\nmwaa: \"MWAAClient\" = boto3.Session(region_name=\"us-east-1\").client(\"mwaa\")\nresponse = mwaa.create_cli_token(Name=\"my-airflow-env\")\n\nprint(response[\"WebServerHostname\"])\nprint(response[\"CliToken\"])\n```\n\nTreat the returned CLI token as short-lived secret material. Do not log or persist it.\n\n### Call the Airflow REST API through MWAA\n\n`invoke_rest_api` is useful when you want to reach the managed Airflow API without hand-assembling the environment endpoint yourself:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\n\nmwaa: \"MWAAClient\" = boto3.Session(region_name=\"us-east-1\").client(\"mwaa\")\n\nresponse = mwaa.invoke_rest_api(\n    Name=\"my-airflow-env\",\n    Path=\"/dags\",\n    Method=\"GET\",\n)\n\nfor dag in response.get(\"RestApiResponse\", {}).get(\"dags\", []):\n    print(dag[\"dag_id\"])\n```\n\nPass only the Airflow path such as `/dags` or `/dags/<dag_id>/dagRuns`. Do not pass the full webserver URL.\n\n### Typed request dictionaries and literals\n\nUse generated `TypedDict` request shapes and literal aliases when helper functions construct MWAA parameters outside the immediate client call:\n\n```python\nfrom mypy_boto3_mwaa.type_defs import CreateCliTokenRequestTypeDef\n\nrequest: CreateCliTokenRequestTypeDef = {\n    \"Name\": \"my-airflow-env\",\n}\n```\n\nThe upstream docs also publish service-specific literals and request/response shapes under `mypy_boto3_mwaa.literals` and `mypy_boto3_mwaa.type_defs` for methods such as `get_environment`, `list_environments`, and `invoke_rest_api`.\n\n## Runtime-Safe Typing Pattern\n\nIf stub packages are dev-only dependencies, keep the imports behind `TYPE_CHECKING` so runtime environments do not need them installed:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_mwaa.client import MWAAClient\nelse:\n    MWAAClient = object\n\nclient = boto3.Session(region_name=\"us-east-1\").client(\"mwaa\")\ntyped_client: \"MWAAClient\" = client\n```\n\nThis also helps with `pylint` in environments where stub-only imports would otherwise trigger undefined-name warnings.\n\n## Configuration Notes\n\n- Use the boto3 credential provider chain rather than hard-coding AWS keys in source.\n- `AWS_PROFILE` and `AWS_DEFAULT_REGION` are the most useful environment variables for local development.\n- Use `botocore.config.Config` for retries, timeouts, proxies, and adaptive behavior; the stubs only type-check those calls.\n- The boto3 service name is `\"mwaa\"`, not `\"airflow\"` and not the PyPI package name.\n- Keep the region explicit in automation. MWAA environment names are unique only within the account and region context you are querying.\n- If exact stubs for a locally pinned boto3 build matter more than the published package, the maintainer project recommends generating them locally with `mypy-boto3-builder`.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_mwaa`.\n- `mypy-boto3-mwaa` does not replace `boto3`. Install `boto3` for runtime AWS calls.\n- If `Session().client(\"mwaa\")` is inferred as `BaseClient`, you probably installed the standalone or lite package and need an explicit `MWAAClient` annotation.\n- `boto3-stubs-lite[mwaa]` trades inference for lower memory use. That is expected behavior, not a broken installation.\n- Do not pass a full URL to `invoke_rest_api`; pass the Airflow API path.\n- `create_cli_token` returns a short-lived token for the Airflow CLI flow, not long-term AWS credentials.\n- Keep the stubs close to the boto3 runtime version. Drift can leave editors showing stale parameters or missing newly added shapes.\n- Do not assume every AWS service has a boto3 resource interface or waiter set. For MWAA, the official material used here is client-oriented.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-mwaa/`\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_mwaa/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- Boto3 MWAA service reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/mwaa.html`\n- Boto3 `create_cli_token`: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/mwaa/client/create_cli_token.html`\n- Boto3 `invoke_rest_api`: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/mwaa/client/invoke_rest_api.html`\n- Boto3 credential guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-neptune/python/DOC.md",
    "content": "---\nname: mypy-boto3-neptune\ndescription: \"mypy-boto3-neptune package guide for typed boto3 Neptune clients, paginators, waiters, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.57\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,neptune,boto3,mypy-boto3-neptune,boto3-stubs,typing,type-checking,python\"\n---\n\n# mypy-boto3-neptune Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for runtime AWS calls and use `mypy-boto3-neptune` only for typing.\n\nIf you want `Session().client(\"neptune\")` to infer its type automatically, install `boto3-stubs[neptune]`. If you install `mypy-boto3-neptune` or `boto3-stubs-lite[neptune]`, plan on adding explicit type annotations for the client, paginators, and waiters.\n\n## Install\n\n### Recommended when you want overload inference\n\nInstall the runtime SDK and the full service extra together:\n\n```bash\npython -m pip install \"boto3==1.42.57\" \"boto3-stubs[neptune]==1.42.57\"\n```\n\nThis is the easiest setup when you want editors and type checkers to understand `Session().client(\"neptune\")` without explicit annotations.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.57\" \"boto3-stubs-lite[neptune]==1.42.57\"\n```\n\nThe maintainer docs say the lite package is more RAM-friendly, but it does not provide `session.client()` and `session.resource()` overloads, so explicit annotations become the normal workflow.\n\n### Standalone service package\n\n```bash\npython -m pip install \"boto3==1.42.57\" \"mypy-boto3-neptune==1.42.57\"\n```\n\nUse the standalone package when you only want Neptune typings or when you keep stub imports behind `TYPE_CHECKING`.\n\nIf you use other package managers:\n\n```bash\nuv add \"boto3==1.42.57\" \"mypy-boto3-neptune==1.42.57\"\npoetry add \"boto3==1.42.57\" \"mypy-boto3-neptune==1.42.57\"\n```\n\n## Initialize Type Checking\n\n### Zero-annotation workflow with `boto3-stubs[neptune]`\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-east-1\")\nclient = session.client(\"neptune\")\n\nresponse = client.describe_db_clusters(MaxRecords=20)\nfor cluster in response.get(\"DBClusters\", []):\n    print(cluster[\"DBClusterIdentifier\"])\n```\n\n### Explicit client annotations\n\nUse this pattern with the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_neptune.client import NeptuneClient\n\nsession = Session(region_name=\"us-east-1\")\nneptune: NeptuneClient = session.client(\"neptune\")\n\nresponse = neptune.describe_db_clusters(MaxRecords=20)\n```\n\n## Auth And Configuration\n\n`mypy-boto3-neptune` does not handle AWS credentials, profiles, regions, retries, or endpoints. Those still come from normal `boto3` and `botocore` behavior.\n\nThe boto3 credentials guide says Boto3 searches credentials in this order: explicit client parameters, explicit `Session(...)` parameters, environment variables, assume-role providers, AWS IAM Identity Center, shared credentials/config files, container credentials, and EC2 instance metadata.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=graph-dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup with an explicit session:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_neptune.client import NeptuneClient\n\nsession = Session(profile_name=\"graph-dev\", region_name=\"us-east-1\")\nneptune: NeptuneClient = session.client(\n    \"neptune\",\n    config=Config(retries={\"mode\": \"standard\", \"max_attempts\": 5}),\n)\n```\n\nThe boto3 session guide also says `Session` objects are not thread safe. Create one session per thread or worker when concurrency matters.\n\n## Core Usage\n\n### Typed Neptune client\n\nThe AWS boto3 reference for `describe_db_clusters` says the operation supports pagination and returns a `DBClusters` list:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_neptune.client import NeptuneClient\n\nneptune: NeptuneClient = Session(region_name=\"us-east-1\").client(\"neptune\")\n\nresponse = neptune.describe_db_clusters(\n    Filters=[\n        {\n            \"Name\": \"engine\",\n            \"Values\": [\"neptune\"],\n        }\n    ],\n    MaxRecords=20,\n)\n\nfor cluster in response.get(\"DBClusters\", []):\n    print(cluster[\"DBClusterIdentifier\"], cluster.get(\"Status\"))\n```\n\n### Typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_neptune.client import NeptuneClient\nfrom mypy_boto3_neptune.paginator import DescribeDBClustersPaginator\n\nneptune: NeptuneClient = Session(region_name=\"us-east-1\").client(\"neptune\")\npaginator: DescribeDBClustersPaginator = neptune.get_paginator(\"describe_db_clusters\")\n\nfor page in paginator.paginate(MaxRecords=20):\n    for cluster in page.get(\"DBClusters\", []):\n        print(cluster[\"DBClusterIdentifier\"])\n```\n\n### Typed waiter\n\nThe maintainer docs list `DBInstanceAvailableWaiter` and `DBInstanceDeletedWaiter` for this package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_neptune.client import NeptuneClient\nfrom mypy_boto3_neptune.waiter import DBInstanceAvailableWaiter\n\nneptune: NeptuneClient = Session(region_name=\"us-east-1\").client(\"neptune\")\nwaiter: DBInstanceAvailableWaiter = neptune.get_waiter(\"db_instance_available\")\n\nwaiter.wait(\n    DBInstanceIdentifier=\"graph-instance-1\",\n    WaiterConfig={\"Delay\": 30, \"MaxAttempts\": 40},\n)\n```\n\n### Typed request and response helpers\n\nUse `type_defs` and `literals` when helper functions need AWS-shaped dictionaries or constrained string values:\n\n```python\nfrom mypy_boto3_neptune.literals import ApplyMethodType\nfrom mypy_boto3_neptune.type_defs import AddRoleToDBClusterMessageTypeDef\n\napply_method: ApplyMethodType = \"immediate\"\n\nrequest: AddRoleToDBClusterMessageTypeDef = {\n    \"DBClusterIdentifier\": \"graph-cluster-1\",\n    \"RoleArn\": \"arn:aws:iam::123456789012:role/NeptuneS3ExportRole\",\n}\n```\n\n### `TYPE_CHECKING` pattern\n\nIf production images do not install the stubs, keep imports type-only:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_neptune.client import NeptuneClient\n\nsession = Session(region_name=\"us-east-1\")\nneptune: \"NeptuneClient\" = session.client(\"neptune\")\n```\n\n## Common Pitfalls\n\n- `mypy-boto3-neptune` is stub-only. It does not replace `boto3`, and it does not create a runtime Neptune client by itself.\n- `boto3-stubs[neptune]` and `mypy-boto3-neptune` are not equivalent ergonomically. The full `boto3-stubs` extra gives overload inference; the standalone and lite installs usually need explicit annotations.\n- Keep `boto3`, `botocore`, and the stub package on the same release line when exact request and response shapes matter.\n- The package name uses hyphens, but imports use underscores: `mypy-boto3-neptune` vs `mypy_boto3_neptune`.\n- Good typing does not guarantee valid AWS credentials, region selection, IAM permissions, or Neptune cluster identifiers. Runtime failures still come from normal boto3 and botocore behavior.\n- The current Neptune stub docs focus on the client, paginators, waiters, literals, and `type_defs`. Write new code against the client API unless you have a separate boto3 runtime reason to do otherwise.\n\n## Version-Sensitive Notes For `1.42.57`\n\n- PyPI listed `1.42.57` as the latest `mypy-boto3-neptune` release on March 12, 2026, and the project page reports it was released on February 25, 2026.\n- The maintainer docs say the version of `boto3-stubs` follows the version of `boto3`, so keep the stub package aligned with the boto3 line you actually run.\n- The standalone package docs and the umbrella `boto3-stubs` docs both note that lite packages do not provide `session.client()` overloads.\n- AWS boto3 runtime docs are rolling reference docs, not exact package lockfiles. Use PyPI for the exact stub version you pin, and use the AWS boto3 docs for credential-chain behavior and operation semantics.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_neptune/\n- Maintainer versioning docs: https://youtype.github.io/boto3_stubs_docs/#versioning\n- PyPI project page: https://pypi.org/project/mypy-boto3-neptune/\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- AWS boto3 session guide: https://docs.aws.amazon.com/boto3/latest/guide/session.html\n- AWS boto3 Neptune `describe_db_clusters`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptune/client/describe_db_clusters.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-opensearch/python/DOC.md",
    "content": "---\nname: mypy-boto3-opensearch\ndescription: \"Type stubs for boto3 OpenSearch Service clients, paginators, literals, and TypedDicts in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.64\"\n  revision: 3\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,opensearch,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-opensearch Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-opensearch` is a stubs-only package for static typing. It does not replace `boto3`, it does not create AWS clients by itself, and it does not handle credentials or retries. Use it to type `boto3` OpenSearch Service clients, paginator calls, literal values, and request or response `TypedDict` shapes.\n\n## Install\n\nFor the standalone service package:\n\n```bash\npython -m pip install \"boto3==1.42.64\" \"mypy-boto3-opensearch==1.42.64\"\n```\n\nIf you prefer the umbrella stubs distribution with an OpenSearch extra:\n\n```bash\npython -m pip install \"boto3-stubs[opensearch]==1.42.64\"\n```\n\nIf you need a lower-overhead typing install:\n\n```bash\npython -m pip install \"boto3-stubs-lite[opensearch]==1.42.64\"\n```\n\nPractical install notes:\n\n- `mypy-boto3-opensearch` is useful when you want only this service's stubs.\n- `boto3-stubs[opensearch]` adds boto3 overloads so `boto3.client(\"opensearch\")` and `Session.client(\"opensearch\")` infer better.\n- `boto3-stubs-lite[opensearch]` reduces type-checker overhead, but it omits those overloaded helpers, so explicit annotations matter more.\n- When exact request and response shapes matter, pin `boto3` and the stubs package to the same release line.\n\n## Authentication And Setup\n\nThis package uses normal boto3 configuration. Set credentials and region exactly as you would for any other boto3 client.\n\nCommon boto3 credential sources:\n\n1. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n2. Shared config and credentials files under `~/.aws/config` and `~/.aws/credentials`\n3. A named profile selected with `AWS_PROFILE` or `Session(profile_name=...)`\n4. IAM role credentials on AWS infrastructure such as EC2, ECS, or Lambda\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_opensearch.client import OpenSearchServiceClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\nclient: OpenSearchServiceClient = session.client(\n    \"opensearch\",\n    config=Config(\n        retries={\"mode\": \"standard\", \"max_attempts\": 10},\n    ),\n)\n```\n\nIf you prefer the top-level import, the package also exposes `OpenSearchServiceClient` from `mypy_boto3_opensearch`.\n\n## Core Usage\n\n### Typed Client Calls\n\nUse the generated client type in helper functions instead of `Any`:\n\n```python\nfrom mypy_boto3_opensearch.client import OpenSearchServiceClient\n\ndef list_domains(client: OpenSearchServiceClient) -> list[str]:\n    response = client.list_domain_names()\n    return [item[\"DomainName\"] for item in response.get(\"DomainNames\", [])]\n```\n\n### Typed Request And Response Shapes\n\nImport `type_defs` when you want stricter checking for AWS-shaped dictionaries:\n\n```python\nfrom mypy_boto3_opensearch.client import OpenSearchServiceClient\nfrom mypy_boto3_opensearch.type_defs import DescribeDomainResponseTypeDef\n\ndef get_domain_arn(\n    client: OpenSearchServiceClient,\n    domain_name: str,\n) -> str:\n    response: DescribeDomainResponseTypeDef = client.describe_domain(\n        DomainName=domain_name\n    )\n    return response[\"DomainStatus\"][\"ARN\"]\n```\n\nThat pattern is useful when you pass a response object deeper into your application and want type checking on nested fields such as `DomainStatus`.\n\n### Typed Paginators\n\nPaginator classes are generated for supported OpenSearch operations:\n\n```python\nfrom mypy_boto3_opensearch.client import OpenSearchServiceClient\nfrom mypy_boto3_opensearch.paginator import ListApplicationsPaginator\n\ndef list_application_ids(client: OpenSearchServiceClient) -> list[str]:\n    paginator: ListApplicationsPaginator = client.get_paginator(\"list_applications\")\n    application_ids: list[str] = []\n\n    for page in paginator.paginate():\n        application_ids.extend(\n            item[\"Id\"] for item in page.get(\"ApplicationSummaries\", [])\n        )\n\n    return application_ids\n```\n\n### Literals For Enum-Like Strings\n\nGenerated literal types live under `mypy_boto3_opensearch.literals`:\n\n```python\nfrom mypy_boto3_opensearch.literals import DomainStateType\n\ndef record_state(state: DomainStateType) -> None:\n    print(state)\n```\n\nUse these when you want type-checker validation for enum-like AWS string values instead of untyped `str`.\n\n## Tooling Patterns\n\n- Install the stubs in the same environment your editor, `mypy`, or `pyright` analyzes.\n- Keep runtime settings such as retries, timeouts, regions, custom endpoints, and credentials on the `boto3` session or client.\n- If you keep stubs as a dev-only dependency, gate imports with `TYPE_CHECKING`.\n\nExample `TYPE_CHECKING` pattern:\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypy_boto3_opensearch.client import OpenSearchServiceClient\n\ndef takes_client(client: \"OpenSearchServiceClient\") -> None:\n    print(client.meta.service_model.service_name)\n```\n\n## Common Pitfalls\n\n- Install `mypy-boto3-opensearch`, but import `mypy_boto3_opensearch`.\n- `mypy-boto3-opensearch` does not replace `boto3`; your app still needs the runtime SDK.\n- `boto3-stubs-lite[opensearch]` drops overloaded `client(...)` helpers, so unannotated client creation is less precise.\n- Credentials, region, IAM permissions, custom endpoints, and retry behavior are runtime boto3 concerns, not problems this package solves.\n- The maintainer docs site is rolling. Its generated install snippets can move ahead of the exact version currently published on PyPI.\n\n## Version-Sensitive Notes\n\n- This guide tracks `mypy-boto3-opensearch==1.42.64`, which PyPI listed as the published package version when this entry was revised.\n- PyPI lists `Requires: Python >=3.9` for this release line.\n- The hosted maintainer docs are generated from a rolling source and may already show newer `boto3` or `boto3-stubs` patch versions in install examples.\n- Practical rule: when you want the closest type alignment, pin `boto3` and `mypy-boto3-opensearch` together on the same release line.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_opensearch/`\n- Maintainer client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_opensearch/client/`\n- Maintainer paginator reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_opensearch/paginators/`\n- Maintainer type definitions: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_opensearch/type_defs/`\n- Package page: `https://pypi.org/project/mypy-boto3-opensearch/`\n- boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- boto3 OpenSearch reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/opensearch.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-organizations/python/DOC.md",
    "content": "---\nname: mypy-boto3-organizations\ndescription: \"mypy-boto3-organizations type stubs for boto3 Organizations clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.41\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,organizations,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-organizations Python Package Guide\n\n## What It Is\n\n`mypy-boto3-organizations` is a PEP 561 stub-only package for the AWS Organizations client in `boto3`.\n\nUse it when you already call AWS Organizations through `boto3`, but want static typing for:\n\n- `OrganizationsClient`\n- generated paginator classes\n- generated `TypedDict` request and response shapes\n- generated string `Literal` values\n\nIt does not replace `boto3`, does not make AWS API calls by itself, and does not manage credentials, regions, retries, or endpoints. Runtime behavior still comes from `boto3` and `botocore`.\n\n## Version Covered\n\n- Ecosystem: `pypi`\n- Package: `mypy-boto3-organizations`\n- Import family: `mypy_boto3_organizations`\n- Service name for boto3: `\"organizations\"`\n- Version used here for this entry: `1.42.41`\n- Python requirement on the official PyPI page checked on 2026-03-12: `>=3.9`\n- Registry URL: `https://pypi.org/project/mypy-boto3-organizations/`\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_organizations/`\n\n## Install\n\nInstall the runtime SDK and the service stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.41\" \"mypy-boto3-organizations==1.42.41\"\n```\n\nIf you want the broader boto3 overloads upstream documents for `session.client(...)`, use the extra-based package instead:\n\n```bash\npython -m pip install \"boto3-stubs[organizations]==1.42.41\"\n```\n\nIf editor or memory usage is a concern, upstream also documents a lite variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[organizations]==1.42.41\"\n```\n\nPractical rule: keep `boto3`, `botocore`, and `mypy-boto3-organizations` on the same patch line when possible.\n\n## Auth And Configuration\n\n`mypy-boto3-organizations` has no package-specific configuration. Use the normal boto3 credential and configuration chain.\n\nCommon setup for local development:\n\n```bash\naws configure --profile org-admin\nexport AWS_PROFILE=org-admin\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create the client with normal boto3 session handling:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"org-admin\", region_name=\"us-east-1\")\norg = session.client(\"organizations\")\n```\n\nIf credentials, region, retry mode, or endpoint selection are wrong, the stub package will not fix runtime failures. Treat those as standard boto3 concerns.\n\n## Core Setup\n\nAnnotate the client explicitly and let `boto3` keep creating the real runtime client.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_organizations.client import OrganizationsClient\n\nsession = Session(profile_name=\"org-admin\", region_name=\"us-east-1\")\norg: OrganizationsClient = session.client(\"organizations\")\n\nresponse = org.describe_organization()\nprint(response[\"Organization\"][\"Id\"])\n```\n\nThis pattern is usually the most reliable with the standalone `mypy-boto3-organizations` package because it does not rely on inferred `session.client(...)` overloads.\n\n## Core Typing Patterns\n\n### Typed client\n\nUse `OrganizationsClient` when you want operation names, request keys, and response keys checked by your type checker.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_organizations.client import OrganizationsClient\n\norg: OrganizationsClient = Session(region_name=\"us-east-1\").client(\"organizations\")\n\norganization = org.describe_organization()[\"Organization\"]\nprint(organization[\"Arn\"])\n```\n\n### Typed paginators\n\nAWS Organizations exposes paginator operations in boto3, and the stub package includes generated paginator classes for them.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_organizations.client import OrganizationsClient\n    from mypy_boto3_organizations.paginator import ListAccountsPaginator\n\norg: OrganizationsClient = Session(region_name=\"us-east-1\").client(\"organizations\")\npaginator: ListAccountsPaginator = org.get_paginator(\"list_accounts\")\n\nfor page in paginator.paginate():\n    for account in page.get(\"Accounts\", []):\n        print(account[\"Id\"], account[\"Email\"])\n```\n\nThe official boto3 Organizations paginator list currently includes operations such as `list_accounts`, `list_accounts_for_parent`, `list_children`, `list_organizational_units_for_parent`, `list_parents`, `list_policies`, and `list_roots`.\n\n### Generated literals and TypedDict shapes\n\nUse `literals` when a field or parameter is constrained to a fixed string set, and `type_defs` when you want `TypedDict` coverage for helper boundaries.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_organizations.client import OrganizationsClient\n    from mypy_boto3_organizations.literals import PolicyTypeType\n    from mypy_boto3_organizations.type_defs import DescribePolicyResponseTypeDef\n\npolicy_type: PolicyTypeType = \"SERVICE_CONTROL_POLICY\"\norg: OrganizationsClient = Session(region_name=\"us-east-1\").client(\"organizations\")\npolicy: DescribePolicyResponseTypeDef = org.describe_policy(PolicyId=\"p-12345678\")\n\nprint(policy_type, policy[\"Policy\"][\"PolicySummary\"][\"Id\"])\n```\n\nThe generated module families documented upstream are:\n\n- `mypy_boto3_organizations.client`\n- `mypy_boto3_organizations.paginator`\n- `mypy_boto3_organizations.type_defs`\n- `mypy_boto3_organizations.literals`\n\n## Tooling Patterns\n\n### `TYPE_CHECKING` imports\n\nIf the stub package is only installed in dev or CI, keep stub-only imports behind `TYPE_CHECKING`:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_organizations.client import OrganizationsClient\n\ndef make_client() -> \"OrganizationsClient\":\n    return Session(region_name=\"us-east-1\").client(\"organizations\")\n```\n\nThis avoids turning a typing helper into a hard runtime dependency.\n\n### When to use `boto3-stubs[organizations]` instead\n\nChoose `mypy-boto3-organizations` when you want the smallest service-specific stub package and you are comfortable with explicit annotations.\n\nChoose `boto3-stubs[organizations]` when you want:\n\n- better automatic typing for `boto3.client(\"organizations\")` and `Session.client(\"organizations\")`\n- a single dependency pattern across multiple AWS services\n- the broader setup path shown in the upstream README\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-organizations` and expecting it to work as a runtime AWS SDK. You still need `boto3`.\n- Using the package name as the boto3 service name. The service is `organizations`, not `mypy-boto3-organizations`.\n- Expecting automatic `session.client(...)` overload inference from the standalone package. That is what `boto3-stubs[organizations]` is for.\n- Forgetting that import names use underscores. Install `mypy-boto3-organizations`, but import from `mypy_boto3_organizations`.\n- Assuming every AWS service has resources and waiters. The official boto3 Organizations reference is client-and-paginator focused; do not invent `OrganizationsServiceResource` or waiter imports.\n- Letting `boto3` and the stub package drift too far apart. Newer stubs can type-check calls your installed runtime does not support, and older stubs can miss newer parameters.\n\n## Version-Sensitive Notes\n\n- The version used here for this session is `1.42.41`.\n- On 2026-03-12, the official PyPI project page showed `1.42.42` as the latest published release for `mypy-boto3-organizations`.\n- On 2026-03-12, the official generated docs search result for `mypy_boto3_organizations` surfaced documentation pages on the `1.42.64` line. Treat that as upstream docs drift relative to the pinned package version.\n- Upstream states that the package version follows the related `boto3` version. Pin `boto3` and `mypy-boto3-organizations` together when exact model parity matters.\n- If you need exact stubs for a different boto3 patch line than the published package provides, prefer checking the generated docs and the broader `boto3-stubs` toolchain before copying older examples.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/mypy-boto3-organizations/\n- Generated docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_organizations/\n- AWS Organizations boto3 client reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html\n- AWS Organizations paginators reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#paginators\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 configuration guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-personalize/python/DOC.md",
    "content": "---\nname: mypy-boto3-personalize\ndescription: \"mypy-boto3-personalize package guide for typed Amazon Personalize boto3 clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,mypy,pyright,typing,stubs,personalize,python\"\n---\n\n# mypy-boto3-personalize Python Package Guide\n\n## What It Is\n\n`mypy-boto3-personalize` is the generated type-stub package for the Amazon Personalize `boto3` client. Use it to add static typing and editor autocomplete for:\n\n- `Session.client(\"personalize\")` client annotations\n- paginator names and paginator object types\n- generated literals and `TypedDict` request/response shapes\n\nIt does **not** replace `boto3` at runtime. Install and use the real AWS SDK packages for credentials, retries, and API calls.\n\n## Install\n\nUse one of these install patterns:\n\n```bash\npython -m pip install boto3 mypy-boto3-personalize\n```\n\nIf you already use the umbrella stubs package, install the Amazon Personalize extra:\n\n```bash\npython -m pip install boto3-stubs[personalize]\n```\n\nIf IDE performance matters more than automatic `Session.client(...)` overload inference, the project also publishes a lighter variant:\n\n```bash\npython -m pip install boto3-stubs-lite[personalize]\n```\n\nUse `boto3-stubs-lite` only if you are comfortable adding explicit annotations yourself. The upstream docs note that the lite package omits `Session.client` and `Session.resource` overloads to reduce package size.\n\n## Initialize A Typed Client\n\nCreate the runtime client with `boto3`, then annotate it with the generated client type from the stubs package.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_personalize.client import PersonalizeClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\npersonalize: PersonalizeClient = session.client(\"personalize\")\n```\n\nThe service name is exactly `\"personalize\"`, matching the AWS boto3 service reference.\n\nIf you keep stub packages out of production images, gate the import behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_personalize.client import PersonalizeClient\n\nsession = Session(region_name=\"us-west-2\")\npersonalize: \"PersonalizeClient\" = session.client(\"personalize\")\n```\n\n## Core Usage\n\n### Typed Client Calls\n\nThe stubs keep the normal boto3 calling pattern, but the return values and parameters become discoverable to the type checker.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_personalize.client import PersonalizeClient\n\nsession = Session(region_name=\"us-west-2\")\npersonalize: PersonalizeClient = session.client(\"personalize\")\n\nresponse = personalize.list_dataset_groups()\n\nfor summary in response.get(\"datasetGroups\", []):\n    print(summary[\"name\"], summary[\"datasetGroupArn\"])\n```\n\n### Typed Paginators\n\nAmazon Personalize exposes paginators for several `list_*` operations. Annotate the paginator object when you want strong typing across pagination loops.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_personalize.client import PersonalizeClient\nfrom mypy_boto3_personalize.paginator import ListDatasetGroupsPaginator\n\nsession = Session(region_name=\"us-west-2\")\npersonalize: PersonalizeClient = session.client(\"personalize\")\n\npaginator: ListDatasetGroupsPaginator = personalize.get_paginator(\"list_dataset_groups\")\n\nfor page in paginator.paginate():\n    for summary in page.get(\"datasetGroups\", []):\n        print(summary[\"name\"])\n```\n\n### Literals And TypedDicts\n\n- Import generated literals from `mypy_boto3_personalize.literals` when a parameter must come from a fixed string set.\n- Import generated request/response `TypedDict`s from `mypy_boto3_personalize.type_defs` when annotating helper functions or adapter layers.\n- Use the generated docs pages to look up the exact symbol names before hardcoding them in shared libraries.\n\n## Auth And Configuration\n\nAuthentication, region selection, retry behavior, and credential discovery all come from `boto3`, not from the stubs package.\n\nPreferred setup:\n\n1. Configure credentials with AWS profiles, IAM Identity Center, assume-role config, or runtime IAM roles.\n2. Set the region explicitly on `Session(...)` or through shared AWS config.\n3. Use the same region as the Amazon Personalize resources you want to read or modify.\n\nCommon environment variables:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_personalize.client import PersonalizeClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\npersonalize: PersonalizeClient = session.client(\"personalize\")\n```\n\nSee the AWS boto3 credentials guide for the full provider chain and profile behavior.\n\n## Common Pitfalls\n\n- This package is type information only. It does not create clients, send requests, or vend credentials.\n- Use the control-plane service name `\"personalize\"`. `personalize-runtime` and `personalize-events` are separate AWS clients and need their own stub packages.\n- Keep `boto3`, `botocore`, and `mypy-boto3-personalize` broadly aligned. Generated methods can drift as AWS updates service models.\n- If you choose `boto3-stubs-lite`, expect to add explicit `PersonalizeClient` annotations because `Session.client(...)` overloads are intentionally omitted.\n- Some lint stacks still report false positives against generated stub internals. Trust the type checker and upstream stubs package before rewriting working imports.\n- Do not hardcode AWS credentials in source code. Let boto3 load them from environment variables, profiles, or runtime roles.\n\n## Version-Sensitive Notes\n\n- The initial package metadata and the official PyPI metadata both point to version `1.42.3`.\n- The PyPI JSON metadata on March 12, 2026 reports `requires_python >=3.8`.\n- The generated docs root is stable and useful for symbol lookup, but it is not versioned in the URL. Use PyPI metadata when you need exact patch-level provenance for dependency pinning.\n- When editor hints and runtime behavior disagree, trust the runtime `boto3` and `botocore` versions actually installed in the environment and update the stubs package to match.\n\n## Official Sources\n\n- PyPI project page: https://pypi.org/project/mypy-boto3-personalize/\n- PyPI JSON API: https://pypi.org/pypi/mypy-boto3-personalize/json\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_personalize/\n- Usage page: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_personalize/usage/\n- Package source code page: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_personalize/package/\n- AWS boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- AWS Personalize service reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/personalize.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-pinpoint/python/DOC.md",
    "content": "---\nname: mypy-boto3-pinpoint\ndescription: \"Typed boto3 Amazon Pinpoint stubs for Python with PinpointClient annotations, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,pinpoint,typing,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-pinpoint Python Package Guide\n\n## What It Is\n\n`mypy-boto3-pinpoint` is the generated typing package for the Amazon Pinpoint `boto3` client.\n\nUse it when you want:\n\n- a typed `PinpointClient`\n- generated `Literal` aliases for constrained string fields\n- generated `TypedDict` request and response shapes from `type_defs`\n- better editor completion and static analysis in `mypy`, Pyright, Pylance, and similar tools\n\nIt does not replace `boto3` at runtime. Real AWS calls, credentials, retries, regions, and endpoints still come from normal `boto3` and botocore configuration.\n\nThe maintainer docs for this package expose `client`, `literals`, and `type_defs`. They do not expose a `service_resource`, paginator, or waiter module for Pinpoint, so treat this as a client-first stubs package.\n\n## Golden Rules\n\n- Install `boto3` for runtime behavior and `mypy-boto3-pinpoint` for typing.\n- Keep `boto3`, `botocore`, and the stubs on the same release line when you care about exact request and response shapes.\n- Prefer explicit `PinpointClient` annotations when you use the standalone package or `boto3-stubs-lite[pinpoint]`.\n- Configure credentials, profiles, regions, retries, and endpoints through standard boto3 settings, not through the stubs package.\n- Amazon Pinpoint reaches end of support on `2026-10-30`. Keep using the stubs only for existing Pinpoint workloads, and check AWS End User Messaging for the unaffected SMS, voice, push, OTP, and phone number validate APIs.\n\n## Install\n\nRecommended for pinned environments:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-pinpoint==1.42.3\"\n```\n\nMaintainer-supported alternatives:\n\n```bash\npython -m pip install \"boto3-stubs[pinpoint]==1.42.3\"\npython -m pip install \"boto3-stubs-lite[pinpoint]==1.42.3\"\npython -m pip install \"mypy-boto3-pinpoint==1.42.3\"\n```\n\nPractical choice:\n\n- use `mypy-boto3-pinpoint` when you want only Pinpoint typings\n- use `boto3-stubs[pinpoint]` when you also want `Session.client(\"pinpoint\")` overload inference\n- use `boto3-stubs-lite[pinpoint]` when full overloads slow down PyCharm or use too much memory\n\nIf you use other package managers:\n\n```bash\nuv add \"boto3==1.42.3\" \"mypy-boto3-pinpoint==1.42.3\"\npoetry add \"boto3==1.42.3\" \"mypy-boto3-pinpoint==1.42.3\"\n```\n\nIf you need stubs generated against the exact `boto3` build in your environment, the maintainer docs show a local generation flow:\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\n## Initialize Type Checking\n\nFor the standalone package, annotate boto3 clients explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_pinpoint.client import PinpointClient\n\nsession = Session(profile_name=\"marketing\", region_name=\"us-east-1\")\npinpoint: PinpointClient = session.client(\"pinpoint\")\n```\n\nIf your production environment excludes dev dependencies, keep the import behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_pinpoint.client import PinpointClient\n\nsession = Session(profile_name=\"marketing\", region_name=\"us-east-1\")\npinpoint: \"PinpointClient\" = session.client(\"pinpoint\")\n```\n\nIf you use `boto3-stubs[pinpoint]`, explicit type annotations are often unnecessary because the session overloads are included.\n\n## Auth And Configuration\n\n`mypy-boto3-pinpoint` has no auth layer of its own. AWS requests still require valid credentials and a region through the normal boto3 credential chain.\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=marketing\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_pinpoint.client import PinpointClient\n\nsession = Session(profile_name=\"marketing\", region_name=\"us-east-1\")\npinpoint: PinpointClient = session.client(\n    \"pinpoint\",\n    config=Config(retries={\"mode\": \"standard\", \"max_attempts\": 5}),\n)\n```\n\nUse the same boto3 patterns you would use without stubs for:\n\n- shared config and credentials files\n- IAM roles, IAM Identity Center, and assumed roles\n- custom endpoints for tests\n- retry, timeout, and proxy settings via botocore `Config`\n\n## Core Usage\n\n### Typed client for application metadata\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_pinpoint.client import PinpointClient\nfrom mypy_boto3_pinpoint.type_defs import GetAppResponseTypeDef\n\npinpoint: PinpointClient = Session(region_name=\"us-east-1\").client(\"pinpoint\")\nresponse: GetAppResponseTypeDef = pinpoint.get_app(ApplicationId=\"your-pinpoint-project-id\")\n\nprint(response[\"ApplicationResponse\"][\"Id\"])\nprint(response[\"ApplicationResponse\"][\"Name\"])\n```\n\nUse this pattern when you are validating that the project exists and that your credentials can see it before attempting message sends or endpoint updates.\n\n### Typed message payloads\n\nAWS publishes Pinpoint examples around `send_messages`. Use `type_defs` so nested request bodies stay typed instead of degrading into `dict[str, Any]`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_pinpoint.client import PinpointClient\nfrom mypy_boto3_pinpoint.type_defs import MessageRequestTypeDef, SendMessagesResponseTypeDef\n\napp_id = \"your-pinpoint-project-id\"\nrecipient = \"user@example.com\"\n\npinpoint: PinpointClient = Session(region_name=\"us-east-1\").client(\"pinpoint\")\n\nmessage_request: MessageRequestTypeDef = {\n    \"Addresses\": {\n        recipient: {\n            \"ChannelType\": \"EMAIL\",\n        }\n    },\n    \"MessageConfiguration\": {\n        \"EmailMessage\": {\n            \"FromAddress\": \"sender@example.com\",\n            \"SimpleEmail\": {\n                \"Subject\": {\"Charset\": \"UTF-8\", \"Data\": \"Hello\"},\n                \"HtmlPart\": {\"Charset\": \"UTF-8\", \"Data\": \"<h1>Hello</h1>\"},\n            },\n        }\n    },\n}\n\nresponse: SendMessagesResponseTypeDef = pinpoint.send_messages(\n    ApplicationId=app_id,\n    MessageRequest=message_request,\n)\n\nresult = response[\"MessageResponse\"][\"Result\"][recipient]\nprint(result.get(\"MessageId\"))\n```\n\nThis is safer than constructing the request inline because the type checker can catch missing nested keys and invalid enum-like fields earlier.\n\n### Literal aliases\n\nUse generated literals when your helpers accept constrained string values:\n\n```python\nfrom mypy_boto3_pinpoint.literals import ActionType, ChannelTypeType\n\nchannel: ChannelTypeType = \"EMAIL\"\naction: ActionType = \"DEEP_LINK\"\n```\n\nThat keeps wrapper utilities and config objects aligned with the generated service model.\n\n## Common Pitfalls\n\n- The package name is `mypy-boto3-pinpoint`, but imports use `mypy_boto3_pinpoint`.\n- This is a stubs package, not an AWS SDK. If `boto3` or credentials are missing, type checking may still pass while runtime calls fail.\n- `boto3-stubs-lite[pinpoint]` omits the same session overload inference you get from full `boto3-stubs[pinpoint]`. Add explicit annotations instead of assuming IDE inference will work.\n- Pinpoint is client-oriented in the generated docs. Do not expect `service_resource`, named paginator, or waiter modules for this package.\n- Version skew between `boto3`, `botocore`, and the generated stubs can show up as missing methods, wrong literal values, or stale `TypedDict` fields.\n- Guard stub imports with `TYPE_CHECKING` if deployment environments omit dev dependencies.\n- `ApplicationId` is the Pinpoint project identifier. Many operations fail because code has the right AWS account and region but the wrong application id.\n- Channel setup still matters at runtime. For example, email sends need a configured sender identity, and SMS sends need supported origination settings, even when the request is perfectly typed.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matches the current PyPI package page on `2026-03-12`.\n- The maintainer docs describe these packages as versioned to match the related `boto3` release line, so pin the exact versions you test.\n- The hosted docs root is a generated latest site, not a version-pinned archive. On `2026-03-12`, it still showed the local generation example with `boto3==1.41.5`, so use PyPI as the source of truth for the exact installable wheel version.\n- The boto3 Pinpoint reference page itself is rendered from a different boto3 patch line than this package. Use the AWS docs for runtime behavior and the exact stubs wheel for the typed symbol surface in your environment.\n- AWS states that Amazon Pinpoint end support is `2026-10-30`, and that SMS, voice, mobile push, OTP, and phone number validate APIs are not affected because they are supported by AWS End User Messaging.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-pinpoint/`\n- Exact release page: `https://pypi.org/project/mypy-boto3-pinpoint/1.42.3/`\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_pinpoint/`\n- Maintainer versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- AWS boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- AWS boto3 configuration guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html`\n- AWS boto3 Pinpoint service reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/pinpoint.html`\n- AWS Pinpoint Python code examples: `https://docs.aws.amazon.com/code-library/latest/ug/python_3_pinpoint_code_examples.html`\n- AWS Amazon Pinpoint end-of-support notice: `https://docs.aws.amazon.com/pinpoint/latest/developerguide/migrate.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-pipes/python/DOC.md",
    "content": "---\nname: mypy-boto3-pipes\ndescription: \"mypy-boto3-pipes type stubs for boto3 EventBridge Pipes clients, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,eventbridge,pipes,boto3,typing,mypy,pyright,python\"\n---\n\n# mypy-boto3-pipes Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-pipes` is a typing package for `boto3.client(\"pipes\")`. It does not replace `boto3`, it does not create AWS clients by itself, and it does not manage credentials or regions for you.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[pipes]` when you want the standard maintainer setup with typed `Session.client(\"pipes\")` calls.\n- Install `mypy-boto3-pipes` when you only want the EventBridge Pipes stubs and are willing to add explicit annotations.\n- Install `boto3-stubs-lite[pipes]` when editor memory use matters more than automatic overload inference.\n\n## Install\n\n`mypy-boto3-pipes` requires Python `>=3.9`.\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[pipes]==1.42.3\"\n```\n\nThis is the best default when you want typed `session.client(\"pipes\")` calls without annotating every variable by hand.\n\n### Standalone EventBridge Pipes stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-pipes==1.42.3\"\n```\n\nUse this when you want only the Pipes typing package. In this mode, explicit client and paginator annotations are usually the safer pattern.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[pipes]==1.42.3\"\n```\n\nThe maintainer docs note that the lite variant does not provide `session.client()` overloads. Add explicit annotations when you use it.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-pipes` has no package-specific initialization. All runtime behavior still comes from `boto3` and botocore.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr use direct credentials in environments where profiles are not available:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup with explicit retry configuration:\n\n```python\nimport boto3\nfrom botocore.config import Config\nfrom mypy_boto3_pipes import EventBridgePipesClient\n\nsession = boto3.Session(profile_name=\"dev\")\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"mode\": \"standard\", \"total_max_attempts\": 10},\n)\n\npipes: EventBridgePipesClient = session.client(\"pipes\", config=config)\n```\n\nKeep credentials, region, retries, endpoints, and timeouts on the `boto3` session or client. The stub package only improves static typing.\n\n## Core Usage\n\n### Typed client and paginator\n\n```python\nimport boto3\nfrom mypy_boto3_pipes import EventBridgePipesClient\nfrom mypy_boto3_pipes.paginator import ListPipesPaginator\n\nsession = boto3.Session(region_name=\"us-east-1\")\npipes: EventBridgePipesClient = session.client(\"pipes\")\n\npaginator: ListPipesPaginator = pipes.get_paginator(\"list_pipes\")\n\nfor page in paginator.paginate(NamePrefix=\"orders-\"):\n    for item in page.get(\"Pipes\", []):\n        print(item[\"Name\"], item.get(\"CurrentState\"))\n```\n\n### Inspect a pipe\n\n```python\npipe = pipes.describe_pipe(Name=\"orders-to-lambda\")\n\nprint(pipe[\"Arn\"])\nprint(pipe[\"Source\"])\nprint(pipe[\"Target\"])\nprint(pipe[\"CurrentState\"])\n```\n\n### Create a pipe in `STOPPED` state first\n\nAWS lets you create a pipe without starting event delivery immediately. This is safer when you want to confirm the source, target, and IAM role before traffic starts flowing.\n\n```python\nimport os\n\nresponse = pipes.create_pipe(\n    Name=\"orders-to-lambda\",\n    DesiredState=\"STOPPED\",\n    RoleArn=os.environ[\"PIPES_ROLE_ARN\"],\n    Source=os.environ[\"SOURCE_QUEUE_ARN\"],\n    SourceParameters={\n        \"SqsQueueParameters\": {\n            \"BatchSize\": 10,\n        }\n    },\n    Target=os.environ[\"TARGET_LAMBDA_ARN\"],\n    TargetParameters={\n        \"LambdaFunctionParameters\": {\n            \"InvocationType\": \"REQUEST_RESPONSE\",\n        }\n    },\n)\n\nprint(response[\"Arn\"])\n```\n\n### Start, stop, and delete a pipe\n\n```python\npipes.start_pipe(Name=\"orders-to-lambda\")\n\nstatus = pipes.describe_pipe(Name=\"orders-to-lambda\")\nprint(status[\"CurrentState\"])\n\npipes.stop_pipe(Name=\"orders-to-lambda\")\npipes.delete_pipe(Name=\"orders-to-lambda\")\n```\n\n### Literals and TypedDicts\n\nThe package also exposes service-specific literal unions and typed dictionaries.\n\n```python\nfrom mypy_boto3_pipes.literals import AssignPublicIpType\nfrom mypy_boto3_pipes.type_defs import AwsVpcConfigurationOutputTypeDef\n\nassign_public_ip: AssignPublicIpType = \"ENABLED\"\n\ndef subnet_ids(config: AwsVpcConfigurationOutputTypeDef) -> list[str]:\n    return config[\"Subnets\"]\n```\n\nUse `literals` for enum-like string values and `type_defs` when you want typed request or response fragments in helper functions.\n\n## `TYPE_CHECKING` Pattern\n\nIf production environments do not install the stub wheel, keep the import behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_pipes import EventBridgePipesClient\nelse:\n    EventBridgePipesClient = object\n\npipes: \"EventBridgePipesClient\" = boto3.client(\"pipes\", region_name=\"us-east-1\")\n```\n\nThe `object` fallback avoids the undefined-name problem that the maintainer docs call out for pylint.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-pipes` without `boto3`. The stubs package is typing-only.\n- Expecting standalone `mypy-boto3-pipes` or `boto3-stubs-lite[pipes]` to infer `session.client(\"pipes\")` automatically. Full `boto3-stubs[pipes]` is the better default for that workflow.\n- Forgetting to set a region. EventBridge Pipes clients still use the normal boto3 credential and region resolution chain.\n- Starting a new pipe immediately when you meant to inspect it first. Set `DesiredState=\"STOPPED\"` during `create_pipe(...)` if you want a safer rollout.\n- Assuming `stop_pipe` is instant. AWS documents that some pipe sources can take time to stop fully.\n- Treating successful type checking as proof that IAM permissions, source ARNs, or target parameters are valid. The stubs only validate Python-side shapes.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-pipes 1.42.3` as the latest release and marks it as generated for `boto3 1.42.3`.\n- PyPI also marks the package as `Typing :: Stubs Only` and `Requires: Python >=3.9`.\n- The maintainer docs state that stub package versions follow the related `boto3` version, so pinning `boto3==1.42.3` with `mypy-boto3-pipes==1.42.3` is the safest default.\n- The standalone `mypy-boto3-pipes` release history is sparse. Do not assume every boto3 patch release has a matching standalone Pipes wheel on PyPI.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_pipes/\n- PyPI package page: https://pypi.org/project/mypy-boto3-pipes/\n- PyPI release page: https://pypi.org/project/mypy-boto3-pipes/1.42.3/\n- AWS EventBridge Pipes user guide: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-start-stop.html\n- AWS EventBridge Pipes `CreatePipe` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/pipes/client/create_pipe.html\n- AWS EventBridge Pipes `DescribePipe` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/pipes/client/describe_pipe.html\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- AWS boto3 retries guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-polly/python/DOC.md",
    "content": "---\nname: mypy-boto3-polly\ndescription: \"mypy-boto3-polly type stubs for typed boto3 Polly clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,polly,boto3,python,typing,stubs,mypy,pyright,text-to-speech\"\n---\n\n# mypy-boto3-polly Python Package Guide\n\n## What It Is\n\n`mypy-boto3-polly` is the maintainer-generated type stub package for the Amazon Polly part of `boto3`.\n\nUse it when you want:\n\n- a typed `PollyClient` for `Session().client(\"polly\")`\n- typed paginator classes such as `DescribeVoicesPaginator`\n- generated `Literal` aliases such as `EngineType`, `OutputFormatType`, and `VoiceIdType`\n- generated `TypedDict` request and response shapes under `type_defs`\n- better IDE completion and static analysis in `mypy`, Pyright, Pylance, and similar tools\n\nIt does not replace `boto3`, add AWS credentials, or change Polly runtime behavior.\n\nPyPI classifies it as `Typing :: Stubs Only`.\n\n## Golden Rules\n\n- Install `boto3` for runtime behavior and `mypy-boto3-polly` only for typing.\n- Prefer `boto3-stubs[polly]` when you want `Session.client(\"polly\")` inference without explicit annotations.\n- Use the standalone `mypy-boto3-polly` package or `boto3-stubs-lite[polly]` only if you are willing to annotate clients explicitly.\n- Configure credentials, region, retries, endpoints, and profiles through normal boto3 and AWS settings.\n- Use PyPI to pin exact released versions. Treat the maintainer docs root as a rolling latest page for package structure and symbol names, not as a version-pinned archive.\n\n## Install\n\nRecommended for pinned environments:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-polly==1.42.3\"\n```\n\nMaintainer-supported alternatives:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[polly]==1.42.3\"\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[polly]==1.42.3\"\n```\n\nPractical choice:\n\n- use `mypy-boto3-polly` when you only want Polly typings\n- use `boto3-stubs[polly]` when you also want `Session.client(...)` overload inference\n- use `boto3-stubs-lite[polly]` when full overloads slow down PyCharm or use too much memory\n\nIf your project is pinned to a newer boto3 release line than the published wheel, the maintainer docs recommend local generation:\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\nThen select `boto3-stubs` and the `Polly` service.\n\n## Initialize Type Checking\n\nFor the standalone package or lite package, annotate clients explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_polly.client import PollyClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\npolly: PollyClient = session.client(\"polly\")\n```\n\nIf stub packages are installed only in development or CI, use `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_polly.client import PollyClient\nelse:\n    PollyClient = object\n\ndef make_client() -> \"PollyClient\":\n    return Session(region_name=\"us-east-1\").client(\"polly\")\n```\n\nThis is also the maintainer-documented workaround for `pylint` complaints about typing-only imports.\n\n## Auth And Configuration\n\n`mypy-boto3-polly` has no package-specific auth or config layer. Credentials, region resolution, retries, proxies, and custom endpoints all come from normal boto3 configuration.\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n# Or provide direct credentials when your environment requires them\n# export AWS_ACCESS_KEY_ID=...\n# export AWS_SECRET_ACCESS_KEY=...\n# export AWS_SESSION_TOKEN=...\n```\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_polly.client import PollyClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\npolly: PollyClient = session.client(\n    \"polly\",\n    config=Config(retries={\"mode\": \"standard\", \"max_attempts\": 5}),\n)\n```\n\nAWS documents the usual boto3 credential sources. In practice, the important ones are:\n\n1. Explicit credentials on `Session(...)` or `client(...)`\n2. Environment variables\n3. Shared config and credentials files\n4. IAM Identity Center or assume-role configuration\n5. Container or EC2 instance credentials\n\n## Core Usage\n\n### Typed client\n\nUse the typed client for normal Polly API calls:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_polly.client import PollyClient\n\npolly: PollyClient = Session(region_name=\"us-east-1\").client(\"polly\")\n\nresponse = polly.describe_voices(LanguageCode=\"en-US\", Engine=\"neural\")\n\nfor voice in response.get(\"Voices\", []):\n    print(voice[\"Id\"], voice[\"LanguageCode\"], voice.get(\"SupportedEngines\", []))\n```\n\n`describe_voices` is the safest way to validate which voices and engines are actually available before hardcoding `VoiceId` values into synthesis code.\n\n### Typed `synthesize_speech` requests\n\nUse generated literals and `TypedDict` shapes to keep synthesis options typed:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_polly.client import PollyClient\nfrom mypy_boto3_polly.literals import EngineType, OutputFormatType, VoiceIdType\nfrom mypy_boto3_polly.type_defs import SynthesizeSpeechInputTypeDef\n\npolly: PollyClient = Session(region_name=\"us-east-1\").client(\"polly\")\n\nengine: EngineType = \"neural\"\noutput_format: OutputFormatType = \"mp3\"\nvoice_id: VoiceIdType = \"Joanna\"\n\nrequest: SynthesizeSpeechInputTypeDef = {\n    \"Engine\": engine,\n    \"OutputFormat\": output_format,\n    \"Text\": \"<speak>Hello from Polly</speak>\",\n    \"TextType\": \"ssml\",\n    \"VoiceId\": voice_id,\n}\n\nresponse = polly.synthesize_speech(**request)\naudio_bytes = response[\"AudioStream\"].read()\n```\n\nAWS documents that `synthesize_speech` accepts UTF-8 plain text or valid SSML. If you request speech marks instead of audio, `OutputFormat` must be `json`.\n\n### Typed paginator\n\nThe maintainer docs list paginator types for `describe_voices`, `list_lexicons`, and `list_speech_synthesis_tasks`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_polly.client import PollyClient\nfrom mypy_boto3_polly.paginator import DescribeVoicesPaginator\n\npolly: PollyClient = Session(region_name=\"us-east-1\").client(\"polly\")\npaginator: DescribeVoicesPaginator = polly.get_paginator(\"describe_voices\")\n\nfor page in paginator.paginate(LanguageCode=\"en-US\"):\n    for voice in page.get(\"Voices\", []):\n        print(voice[\"Id\"])\n```\n\n### Typed asynchronous synthesis task\n\n`start_speech_synthesis_task` is the typed path when you want Polly to write output to S3 instead of returning a streaming body directly.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_polly.client import PollyClient\nfrom mypy_boto3_polly.type_defs import StartSpeechSynthesisTaskInputTypeDef\n\npolly: PollyClient = Session(region_name=\"us-east-1\").client(\"polly\")\n\nrequest: StartSpeechSynthesisTaskInputTypeDef = {\n    \"Engine\": \"neural\",\n    \"OutputFormat\": \"mp3\",\n    \"OutputS3BucketName\": \"my-polly-output-bucket\",\n    \"Text\": \"Hello from Polly\",\n    \"VoiceId\": \"Joanna\",\n}\n\nresult = polly.start_speech_synthesis_task(**request)\ntask = result[\"SynthesisTask\"]\n\nprint(task[\"TaskId\"], task[\"TaskStatus\"])\n```\n\nPolly does not publish service-specific waiter types in the maintainer docs root. Poll `get_speech_synthesis_task` or paginate `list_speech_synthesis_tasks` when you need task completion tracking.\n\n### Literals and `TypedDict` helpers\n\nGenerated literal and `TypedDict` types are useful outside the direct boto3 call site:\n\n```python\nfrom mypy_boto3_polly.literals import LanguageCodeType, VoiceIdType\nfrom mypy_boto3_polly.type_defs import DescribeVoicesInputTypeDef\n\nlanguage: LanguageCodeType = \"en-US\"\nvoice_id: VoiceIdType = \"Joanna\"\n\nrequest: DescribeVoicesInputTypeDef = {\n    \"LanguageCode\": language,\n}\n```\n\nThis is useful when wrapping Polly inside your own helpers, adapters, or config validation code.\n\n## Common Pitfalls\n\n- Installing only the stub package and expecting real AWS calls to work without `boto3`.\n- Importing `mypy-boto3-polly` with hyphens in Python code. The import root is `mypy_boto3_polly`.\n- Expecting automatic `Session.client(\"polly\")` inference when you installed only the standalone package or `boto3-stubs-lite[polly]`.\n- Treating successful type checking as proof that IAM permissions, region, S3 output permissions, or voice availability are correct.\n- Hardcoding a `VoiceId` without checking whether the selected engine and language support it. Use `describe_voices` first.\n- Passing invalid SSML to `synthesize_speech`. AWS requires well-formed SSML.\n- Treating the maintainer docs root as a release-pinned source. It is a rolling generated page and may drift away from the current PyPI wheel.\n- Assuming Polly has resource types or documented service waiters here. This package is primarily client, paginator, literal, and `TypedDict` oriented.\n\n## Version-Sensitive Notes\n\n- This guide tracks the latest published standalone PyPI wheel for `mypy-boto3-polly`, which PyPI listed as `1.42.3` on 2026-03-12.\n- PyPI states that `mypy-boto3-polly` version matches the related `boto3` version and marks the package as `Typing :: Stubs Only`.\n- The current PyPI page says `1.42.3` was generated with `mypy-boto3-builder 8.12.0`.\n- The maintainer docs root is useful for package structure and symbol discovery, but it is a rolling generated page rather than a version-pinned archive and can drift from the currently published wheel.\n- If your project needs typings for a newer boto3 patch such as `1.42.66`, verify that exact wheel exists on PyPI first or generate matching stubs locally with `mypy-boto3-builder`.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_polly/`\n- Maintainer usage examples: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_polly/usage/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-polly/`\n- boto3 Polly reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/polly.html`\n- boto3 `describe_voices` reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/polly/client/describe_voices.html`\n- boto3 `synthesize_speech` reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/polly/client/synthesize_speech.html`\n- boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-proton/python/DOC.md",
    "content": "---\nname: mypy-boto3-proton\ndescription: \"mypy-boto3-proton package guide for typed boto3 Proton clients, paginators, waiters, and generated request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,proton,boto3,mypy-boto3-proton,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-proton Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for runtime AWS calls and use `mypy-boto3-proton` only for typing.\n\nIf you want `Session().client(\"proton\")` to infer the right type automatically, install `boto3-stubs[proton]`. If you install `mypy-boto3-proton` or `boto3-stubs-lite[proton]`, expect to add explicit type annotations for clients, paginators, and waiters.\n\n## Install\n\n### Recommended for normal boto3 code\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[proton]==1.42.3\"\n```\n\nUse this when you want the easiest editor and type-checker experience. The maintainer docs say the full `boto3-stubs` service extra gives auto-discovery for `session.client(...)` and `client.get_paginator(...)` calls, so ordinary boto3 code usually needs no extra annotations.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[proton]==1.42.3\"\n```\n\nUse this when editor performance matters more than automatic overload discovery. The maintainer docs note that the lite variant does not provide the `session.client()` and `session.resource()` overloads, so explicit annotations become the normal workflow.\n\n### Standalone Proton stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-proton==1.42.3\"\n```\n\nUse the standalone package when you only want Proton typings or when you prefer keeping stub imports behind `TYPE_CHECKING`.\n\n## Setup And Authentication\n\n`mypy-boto3-proton` does not authenticate to AWS and does not create clients by itself. Credentials, region, retries, and endpoint selection still come from `boto3`.\n\nPractical setup:\n\n1. Create a `boto3.Session(...)` with an explicit profile and region when the environment is not obvious.\n2. Let boto3 load credentials from the normal AWS chain unless you are intentionally passing temporary credentials.\n3. Keep auth and runtime config on the boto3 session or client, not in the stubs package.\n\nMinimal setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nclient = session.client(\"proton\")\n```\n\nImportant credential sources from the boto3 docs:\n\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_PROFILE`, and `AWS_DEFAULT_REGION`\n- shared config in `~/.aws/credentials` and `~/.aws/config`\n- assume-role, web-identity, and IAM Identity Center profiles\n- container or EC2 instance role credentials\n\nFor most local development, use a profile instead of hardcoding keys:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[proton]`\n\nWith the full service extra installed, type discovery should work on normal boto3 code:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-west-2\")\nclient = session.client(\"proton\")\n\nresponse = client.list_services()\nfor service in response.get(\"services\", []):\n    print(service[\"name\"])\n```\n\nThis is the simplest setup for agents generating application code.\n\n### Explicit client annotations\n\nUse explicit annotations when you installed the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_proton import ProtonClient\n\nsession = Session(region_name=\"us-west-2\")\nclient: ProtonClient = session.client(\"proton\")\n\nresponse = client.list_services()\nprint(response.get(\"services\", []))\n```\n\n### Explicit paginator annotations\n\nThe maintainer docs expose many typed Proton paginators, including `ListServicesPaginator`, `ListServiceInstancesPaginator`, `ListEnvironmentsPaginator`, and `ListComponentProvisionedResourcesPaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_proton import ProtonClient\nfrom mypy_boto3_proton.paginator import ListServicesPaginator\n\nsession = Session(region_name=\"us-west-2\")\nclient: ProtonClient = session.client(\"proton\")\npaginator: ListServicesPaginator = client.get_paginator(\"list_services\")\n\nfor page in paginator.paginate():\n    for service in page.get(\"services\", []):\n        print(service[\"name\"])\n```\n\n### Typed waiters, literals, and `type_defs`\n\nThe package also provides:\n\n- typed waiter classes under `mypy_boto3_proton.waiter`\n- generated literal unions under `mypy_boto3_proton.literals`\n- generated `TypedDict` request and response shapes under `mypy_boto3_proton.type_defs`\n\nUse those modules when helper functions need stricter typing than a raw `dict[str, Any]` or string literal can provide.\n\n## `TYPE_CHECKING` Pattern\n\nThe maintainer docs explicitly say it is safe to keep this dependency out of production by importing it only for type checking.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_proton import ProtonClient\n    from mypy_boto3_proton.paginator import ListServicesPaginator\nelse:\n    ProtonClient = object\n    ListServicesPaginator = object\n\nsession = Session(region_name=\"us-west-2\")\nclient: \"ProtonClient\" = session.client(\"proton\")\npaginator: \"ListServicesPaginator\" = client.get_paginator(\"list_services\")\n```\n\nUse this pattern when production should ship only `boto3`. The `object` fallback also avoids the pylint undefined-name problem called out in the upstream docs.\n\n## Configuration Notes\n\n- `mypy-boto3-proton` has no package-specific runtime configuration surface. If auth, region selection, retries, or endpoints are wrong, fix the underlying boto3 client configuration.\n- Proton is an AWS service client, so successful type checking does not prove the region, account, IAM permissions, or service resources are valid at runtime.\n- Use `botocore.config.Config(...)` with `Session().client(\"proton\", config=...)` when you need explicit retry mode, timeouts, or other client settings.\n- Use `endpoint_url=...` on the boto3 client for tests or custom endpoints. The stubs package does not change endpoint behavior.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-proton` and expecting real AWS calls to work without `boto3`.\n- Importing the package with hyphens in Python code. The import root is `mypy_boto3_proton`.\n- Expecting automatic `Session().client(\"proton\")` inference when you installed only `mypy-boto3-proton` or `boto3-stubs-lite[proton]`. Use explicit annotations in those setups.\n- Letting the `boto3` and stub versions drift apart. The maintainer docs say the stub package version matches the related `boto3` version.\n- Treating successful type checking as proof that credentials, region choice, IAM permissions, or Proton resource names are correct.\n- Using old blog posts or copied code that predates the current generated package line. Always verify the current class names and paginator names in the maintainer docs.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI lists `1.42.3` as the exact `mypy-boto3-proton` release for this entry, uploaded on `2025-12-04`.\n- The package description says it provides type annotations for `boto3 Proton 1.42.3`, and the maintainer docs say the package version follows the related `boto3` version.\n- The maintainer docs site is rolling generated output, so use the exact PyPI release page and your lockfile when exact package compatibility matters.\n- `boto3-stubs[proton]`, `boto3-stubs-lite[proton]`, and standalone `mypy-boto3-proton` are all valid install paths, but only the non-lite bundle is meant to avoid most explicit annotations.\n- If your project needs an exact local regeneration for a pinned boto3 line, the maintainer docs recommend `uvx --with 'boto3==1.42.3' mypy-boto3-builder`.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_proton/\n- Proton paginators docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_proton/paginators/\n- PyPI project: https://pypi.org/project/mypy-boto3-proton/\n- PyPI exact release context: https://pypi.org/project/mypy-boto3-proton/1.42.3/\n- AWS boto3 Proton reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/proton.html\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- AWS boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-qbusiness/python/DOC.md",
    "content": "---\nname: mypy-boto3-qbusiness\ndescription: \"mypy-boto3-qbusiness type stubs for boto3 Amazon Q Business clients, paginators, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.14\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,qbusiness,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-qbusiness Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-qbusiness` adds type annotations for Amazon Q Business code that uses `boto3`. It is not a runtime SDK, it does not make AWS calls by itself, and it does not replace normal Boto3 credential or region setup.\n\nUse one of these install modes:\n\n- `boto3-stubs[qbusiness]` when you want the best autocomplete and automatic `Session.client(\"qbusiness\")` typing.\n- `mypy-boto3-qbusiness` when you want only the standalone Amazon Q Business stubs and are willing to add explicit annotations.\n- `boto3-stubs-lite[qbusiness]` when IDE memory use matters more than overload-based inference.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[qbusiness]'\n```\n\n### Standalone Amazon Q Business stubs\n\n```bash\npython -m pip install boto3 mypy-boto3-qbusiness\n```\n\nUse this when you only want the QBusiness service stubs. Explicit annotations are usually needed.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[qbusiness]'\n```\n\nThe lite package is more RAM-friendly, but the maintainer docs say it does not provide `session.client/resource` overloads.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-qbusiness` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nAWS documents that Boto3 requests need both AWS credentials and an AWS Region. The usual options are:\n\n```bash\naws configure\n```\n\nor environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...      # optional\nexport AWS_DEFAULT_REGION=us-east-1\nexport AWS_PROFILE=dev            # optional\n```\n\nCreate the typed client through a normal Boto3 session:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\n\nsession = Session(region_name=os.environ[\"AWS_DEFAULT_REGION\"])\nqbusiness: QBusinessClient = session.client(\"qbusiness\")\n```\n\nIf you want explicit profile control:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nqbusiness: QBusinessClient = session.client(\"qbusiness\")\n```\n\n## Core Usage\n\n### List applications with a typed response\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\nfrom mypy_boto3_qbusiness.type_defs import ListApplicationsResponseTypeDef\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\nresponse: ListApplicationsResponseTypeDef = qbusiness.list_applications(maxResults=20)\n\nfor app in response.get(\"applications\", []):\n    print(app[\"applicationId\"], app[\"displayName\"], app.get(\"status\"))\n```\n\n### Use a typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\nfrom mypy_boto3_qbusiness.paginator import ListApplicationsPaginator\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\npaginator: ListApplicationsPaginator = qbusiness.get_paginator(\"list_applications\")\n\nfor page in paginator.paginate(maxResults=50):\n    for app in page.get(\"applications\", []):\n        print(app[\"applicationId\"], app[\"displayName\"])\n```\n\nThe maintainer docs also publish typed paginators for `get_chat_controls_configuration`, `list_attachments`, `list_conversations`, `list_data_sources`, `list_documents`, `list_indices`, `list_messages`, `list_plugins`, `list_retrievers`, `list_subscriptions`, `list_web_experiences`, and `search_relevant_content`.\n\n### Start a data source sync job\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\nresult = qbusiness.start_data_source_sync_job(\n    dataSourceId=data_source_id,\n    applicationId=application_id,\n    indexId=index_id,\n)\n\nprint(result[\"executionId\"])\n```\n\n### Search relevant content with a typed request shape\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\nfrom mypy_boto3_qbusiness.type_defs import (\n    ContentSourceTypeDef,\n    SearchRelevantContentResponseTypeDef,\n)\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\ncontent_source: ContentSourceTypeDef = {\n    \"retriever\": {\n        \"retrieverId\": retriever_id,\n    }\n}\n\nresponse: SearchRelevantContentResponseTypeDef = qbusiness.search_relevant_content(\n    applicationId=application_id,\n    queryText=\"What is our PTO policy?\",\n    contentSource=content_source,\n    maxResults=5,\n)\n\nfor item in response.get(\"relevantContent\", []):\n    print(item[\"documentTitle\"], item.get(\"documentUri\"))\n```\n\n### Run a non-streaming chat call\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\nfrom mypy_boto3_qbusiness.type_defs import ChatSyncInputTypeDef, ChatSyncOutputTypeDef\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\nrequest: ChatSyncInputTypeDef = {\n    \"applicationId\": application_id,\n    \"userMessage\": \"Summarize the top support issues from this week.\",\n}\n\nresponse: ChatSyncOutputTypeDef = qbusiness.chat_sync(**request)\n\nprint(response[\"conversationId\"])\nprint(response.get(\"systemMessage\", \"\"))\n\nfor source in response.get(\"sourceAttributions\", []):\n    print(source.get(\"title\"), source.get(\"url\"))\n```\n\n### Ingest documents into an index\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qbusiness.client import QBusinessClient\nfrom mypy_boto3_qbusiness.type_defs import BatchPutDocumentRequestTypeDef\n\nqbusiness: QBusinessClient = Session(region_name=\"us-east-1\").client(\"qbusiness\")\n\nrequest: BatchPutDocumentRequestTypeDef = {\n    \"applicationId\": application_id,\n    \"indexId\": index_id,\n    \"documents\": [\n        {\n            \"id\": \"employee-handbook-2026\",\n            \"content\": {\n                \"s3\": {\n                    \"bucket\": bucket_name,\n                    \"key\": \"handbooks/employee-handbook-2026.pdf\",\n                }\n            },\n            \"contentType\": \"PDF\",\n            \"title\": \"Employee Handbook 2026\",\n        }\n    ],\n}\n\nresult = qbusiness.batch_put_document(**request)\nprint(result.get(\"failedDocuments\", []))\n```\n\n## Typing Patterns\n\n### Use `type_defs` for nested request bodies\n\nThe maintainer docs publish `TypedDict` definitions for request and response shapes. This is the cleanest way to type nested Amazon Q Business payloads before they reach the client call.\n\n```python\nfrom mypy_boto3_qbusiness.type_defs import ChatSyncInputTypeDef\n\nrequest: ChatSyncInputTypeDef = {\n    \"applicationId\": application_id,\n    \"userMessage\": \"Show me the latest onboarding checklist.\",\n}\n```\n\n### Use `literals` when a field expects a constrained string\n\n```python\nfrom mypy_boto3_qbusiness.literals import APISchemaTypeType\n\nschema_type: APISchemaTypeType = \"OpenAPI_3\"\n```\n\n### Keep the stubs as a development dependency\n\nIf production images do not install stub packages, gate the import with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_qbusiness.client import QBusinessClient\nelse:\n    QBusinessClient = object\n\ndef make_client() -> \"QBusinessClient\":\n    return boto3.client(\"qbusiness\", region_name=\"us-east-1\")\n```\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-qbusiness` and expecting it to replace `boto3`. You still need the runtime SDK.\n- Expecting unannotated `Session.client(\"qbusiness\")` calls to become typed automatically when you use the standalone or lite packages. That behavior comes from `boto3-stubs[qbusiness]`.\n- Forgetting the import-name difference: install `mypy-boto3-qbusiness`, import `mypy_boto3_qbusiness`.\n- Treating stub packages as AWS auth or config helpers. Credentials, region, retries, and endpoints still come from normal Boto3 and botocore configuration.\n- Using the full `boto3-stubs` package in PyCharm when overload-heavy typing slows the IDE down. The maintainer recommends trying `boto3-stubs-lite` in that case.\n- Letting `boto3`, `botocore`, and the stubs drift apart. The maintainer says the stub version matches the related `boto3` version.\n\n## Version-Sensitive Notes\n\n- This guide is keyed to `mypy-boto3-qbusiness==1.42.14`, and PyPI lists it as the package version for boto3 QBusiness `1.42.14`.\n- PyPI lists `Python >=3.9` for this package.\n- The maintainer recommends local generation with `uvx --with 'boto3==1.42.14' mypy-boto3-builder` when you want stubs generated exactly for your pinned boto3 version.\n- When exact shape coverage matters, pin `boto3`, `botocore`, and `mypy-boto3-qbusiness` in the same release family.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_qbusiness/\n- Maintainer client docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_qbusiness/client/\n- Maintainer paginators docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_qbusiness/paginators/\n- PyPI project: https://pypi.org/project/mypy-boto3-qbusiness/\n- AWS QBusiness service reference: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness.html\n- AWS `list_applications`: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness/client/list_applications.html\n- AWS `chat_sync`: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness/client/chat_sync.html\n- AWS `search_relevant_content`: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness/client/search_relevant_content.html\n- AWS `start_data_source_sync_job`: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness/client/start_data_source_sync_job.html\n- AWS `batch_put_document`: https://docs.aws.amazon.com/boto3/latest/reference/services/qbusiness/client/batch_put_document.html\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n- Boto3 session reference: https://docs.aws.amazon.com/boto3/latest/reference/core/session.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-qldb/python/DOC.md",
    "content": "---\nname: mypy-boto3-qldb\ndescription: \"Type stubs for boto3 Amazon QLDB control-plane clients, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.54\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,qldb,boto3,mypy-boto3-qldb,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-qldb Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-qldb` is a stubs-only package for static typing. Keep using `boto3` for real AWS calls, and use this package only to type `Session().client(\"qldb\")`, generated `TypedDict` shapes, and QLDB-specific literal values.\n\nFor most projects, install either:\n\n- `boto3-stubs[qldb]` if you want `session.client(\"qldb\")` overload inference in editors and type checkers\n- `mypy-boto3-qldb` if you want the standalone service package and are willing to annotate `QLDBClient` explicitly\n\nQLDB itself reached end of support on July 31, 2025, so this package is mainly for maintaining existing QLDB control-plane code rather than starting new systems.\n\n## Install\n\nRecommended for normal boto3 development:\n\n```bash\npython -m pip install \"boto3==1.40.54\" \"boto3-stubs[qldb]==1.40.54\"\n```\n\nStandalone service-specific stubs:\n\n```bash\npython -m pip install \"boto3==1.40.54\" \"mypy-boto3-qldb==1.40.54\"\n```\n\nLower-memory editor fallback:\n\n```bash\npython -m pip install \"boto3==1.40.54\" \"boto3-stubs-lite[qldb]==1.40.54\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.40.54\" \"boto3-stubs[qldb]==1.40.54\"\npoetry add \"boto3==1.40.54\" \"boto3-stubs[qldb]==1.40.54\"\n```\n\nNotes:\n\n- Keep the stubs version aligned with the `boto3` version you pin. The maintainer docs track these packages to the related boto3 release line.\n- `boto3-stubs-lite[qldb]` is useful when IDE performance matters, but it does not provide the overloaded `session.client(\"qldb\")` inference from the full `boto3-stubs` package.\n- Installing only `mypy-boto3-qldb` does not install the runtime SDK.\n\n## Authentication And Runtime Setup\n\n`mypy-boto3-qldb` does not configure AWS credentials, regions, retries, or endpoints. Runtime behavior still comes from `boto3` and `botocore`.\n\nBoto3's credential guide documents the normal provider chain, including:\n\n1. Explicit parameters passed in code\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n3. Shared credentials and config files\n4. Assume-role, container, or EC2 instance metadata providers\n\nPractical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr make the session explicit in code:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qldb import QLDBClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nqldb: QLDBClient = session.client(\"qldb\")\n```\n\nKeep secrets out of source control. Prefer shared AWS config, IAM roles, IAM Identity Center, or other temporary-credential flows over hardcoded keys.\n\n## Core Usage\n\n### Typed control-plane client\n\nThis package types the QLDB management API exposed through `boto3.client(\"qldb\")`. It does not add a `resource()` interface.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qldb import QLDBClient\n\nclient: QLDBClient = Session(region_name=\"us-east-1\").client(\"qldb\")\n\nresponse = client.list_ledgers()\n\nfor ledger in response.get(\"Ledgers\", []):\n    print(ledger[\"Name\"], ledger[\"State\"])\n```\n\n### Typed request literals and response shapes\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qldb import QLDBClient\nfrom mypy_boto3_qldb.literals import PermissionsModeType\nfrom mypy_boto3_qldb.type_defs import CreateLedgerResponseTypeDef\n\nclient: QLDBClient = Session(region_name=\"us-east-1\").client(\"qldb\")\npermissions_mode: PermissionsModeType = \"STANDARD\"\n\nresult: CreateLedgerResponseTypeDef = client.create_ledger(\n    Name=\"app-ledger\",\n    PermissionsMode=permissions_mode,\n)\n\nprint(result[\"Name\"], result[\"State\"])\n```\n\n### Typed helper functions\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_qldb import QLDBClient\nfrom mypy_boto3_qldb.type_defs import DescribeLedgerResponseTypeDef\n\ndef describe_ledger(name: str) -> DescribeLedgerResponseTypeDef:\n    client: QLDBClient = Session(region_name=\"us-east-1\").client(\"qldb\")\n    return client.describe_ledger(Name=name)\n```\n\n### `TYPE_CHECKING` pattern for dev-only stubs\n\nIf your production image does not install stub packages, keep stub imports out of runtime paths:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_qldb import QLDBClient\n\ndef get_qldb_client() -> \"QLDBClient\":\n    return Session(region_name=\"us-east-1\").client(\"qldb\")\n```\n\n## What This Package Does Not Cover\n\n- It does not replace `boto3`.\n- It does not execute or validate runtime requests by itself.\n- It does not cover QLDB session or transaction-driver workflows used for ledger document operations.\n- It does not provide `resource()`, waiter, or paginator helpers for this service surface.\n\nAWS's QLDB developer guide distinguishes the control-plane management API from the data plane used for ledger sessions and PartiQL transactions. Use this package only for the management side exposed through `boto3.client(\"qldb\")`.\n\n## Common Pitfalls\n\n### Hyphenated package name vs import name\n\nInstall with `mypy-boto3-qldb`, but import with underscores:\n\n```python\nfrom mypy_boto3_qldb import QLDBClient\n```\n\n### Expecting resource, waiter, or paginator modules\n\nThe generated maintainer docs for this package focus on `QLDBClient`, literals, and typed definitions. Do not assume there are service resource, waiter, or paginator modules just because other AWS service stub packages expose them.\n\n### Treating the stubs package as the transaction SDK\n\nApplication code that works with ledger sessions and transactions uses different APIs than the control-plane operations typed here. Do not infer document-transaction support from this package alone.\n\n### Forgetting version alignment\n\nIf `boto3`, `botocore`, and `mypy-boto3-qldb` drift too far apart, generated method signatures and typed shapes can stop matching your runtime SDK.\n\nSafest rule:\n\n- pin `boto3`\n- pin `botocore`\n- pin `mypy-boto3-qldb`\n- update them together\n\n## Version-Sensitive Notes\n\n- The version used here `1.40.54` matched the official PyPI project page and generated maintainer docs on March 12, 2026.\n- The package is tied to a now-retired AWS service. For new work, confirm that QLDB is still an intentional dependency before adding this package.\n- If you need automatic client overload inference, prefer `boto3-stubs[qldb]` over the standalone service package.\n\n## Official Sources\n\n- PyPI project: https://pypi.org/project/mypy-boto3-qldb/\n- PyPI JSON API: https://pypi.org/pypi/mypy-boto3-qldb/json\n- Generated maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_qldb/\n- Repository: https://github.com/youtype/types-boto3\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Amazon QLDB management and transaction API guide: https://docs.aws.amazon.com/qldb/latest/developerguide/api-reference.html\n- Amazon QLDB end-of-support notice: https://docs.aws.amazon.com/qldb/latest/developerguide/what-is.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-rds/python/DOC.md",
    "content": "---\nname: mypy-boto3-rds\ndescription: \"mypy-boto3-rds package guide for Python with typed boto3 RDS clients, paginators, waiters, literals, and type defs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.51\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,boto3,rds,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-rds Python Package Guide\n\n## What It Is\n\n`mypy-boto3-rds` is the generated type-stubs package for `boto3` Amazon RDS clients.\n\nUse it when you want:\n\n- a typed `RDSClient`\n- typed paginators and waiters from `client.get_paginator(...)` and `client.get_waiter(...)`\n- generated `Literal` aliases and `TypedDict` request and response shapes\n- better autocomplete and static analysis in `mypy`, Pyright, Pylance, VS Code, or PyCharm\n\nImportant boundary:\n\n- this package does not make AWS calls by itself\n- runtime behavior still comes from `boto3` and `botocore`\n- AWS credentials, region selection, retries, and endpoint settings are still standard boto3 configuration\n\n## Version Covered\n\n- Ecosystem: `pypi`\n- Package: `mypy-boto3-rds`\n- Import root: `mypy_boto3_rds`\n- Runtime SDK: `boto3`\n- Official latest observed on PyPI on `2026-03-11`: `1.42.51`\n- PyPI release date: `2026-02-17`\n- Python requirement on PyPI: `>=3.9`\n- Docs root used for this entry: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_rds/`\n- Registry URL: `https://pypi.org/project/mypy-boto3-rds/`\n- Repository: `https://github.com/youtype/types-boto3`\n\n## Install\n\nInstall the stubs package alongside `boto3`:\n\n```bash\npython -m pip install boto3 mypy-boto3-rds\n```\n\nIf you want aligned versions in a lockfile, pin both packages to the same observed line:\n\n```bash\npython -m pip install \"boto3==1.42.51\" \"mypy-boto3-rds==1.42.51\"\n```\n\nThe upstream docs also publish two broader alternatives:\n\n```bash\npython -m pip install \"boto3-stubs[rds]\"\npython -m pip install \"boto3-stubs-lite[rds]\"\n```\n\n- `mypy-boto3-rds`: service-only RDS stubs\n- `boto3-stubs[rds]`: includes session overloads so IDEs can infer `Session().client(\"rds\")` without extra annotations\n- `boto3-stubs-lite[rds]`: smaller install, but upstream notes that it does not provide `session.client/resource` overloads\n\nOther package managers:\n\n```bash\nuv add boto3 mypy-boto3-rds\npoetry add boto3 mypy-boto3-rds\nconda install mypy-boto3-rds -c conda-forge\n```\n\n## Setup\n\nThis package is usually a development dependency. Install it anywhere type checking or editor indexing runs.\n\nIf your deployed runtime omits stubs, keep imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_rds import RDSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nrds: \"RDSClient\" = session.client(\"rds\")\n```\n\nIf the runtime environment includes the stubs package, regular imports are fine:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_rds import RDSClient\n\nrds: RDSClient = Session(region_name=\"us-west-2\").client(\"rds\")\n```\n\n## Authentication And Configuration\n\n`mypy-boto3-rds` has no separate auth system. Use normal AWS SDK configuration:\n\n- `AWS_PROFILE` for local profile selection\n- `AWS_DEFAULT_REGION` or `region_name=...`\n- standard AWS credential resolution from environment variables, shared config files, SSO, assume-role, or runtime IAM roles\n- `botocore.config.Config(...)` for retries, timeouts, and other client settings\n\nPractical setup pattern:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_rds import RDSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nconfig = Config(\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n    connect_timeout=5,\n    read_timeout=60,\n)\n\nrds: RDSClient = session.client(\"rds\", config=config)\n```\n\n## Core Usage\n\n### Typed RDS Client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_rds import RDSClient\n\nrds: RDSClient = Session(region_name=\"us-east-1\").client(\"rds\")\n\nresponse = rds.describe_db_instances(\n    MaxRecords=20,\n)\n\nfor db in response.get(\"DBInstances\", []):\n    print(db[\"DBInstanceIdentifier\"], db.get(\"Engine\"))\n```\n\n### Typed Paginator\n\nUse paginator types when iterating over multi-page list operations:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_rds import RDSClient\nfrom mypy_boto3_rds.paginator import DescribeDBInstancesPaginator\n\nrds: RDSClient = Session(region_name=\"us-east-1\").client(\"rds\")\npaginator: DescribeDBInstancesPaginator = rds.get_paginator(\"describe_db_instances\")\n\nfor page in paginator.paginate(DBInstanceIdentifier=\"app-db\"):\n    for db in page.get(\"DBInstances\", []):\n        print(db[\"DBInstanceIdentifier\"])\n```\n\n### Typed Waiter\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_rds import RDSClient\nfrom mypy_boto3_rds.waiter import DBInstanceAvailableWaiter\n\nrds: RDSClient = Session(region_name=\"us-east-1\").client(\"rds\")\nwaiter: DBInstanceAvailableWaiter = rds.get_waiter(\"db_instance_available\")\n\nwaiter.wait(\n    DBInstanceIdentifier=\"app-db\",\n    WaiterConfig={\"Delay\": 30, \"MaxAttempts\": 40},\n)\n```\n\n### Literal Types\n\nThe generated package exposes `Literal` aliases for fixed-value parameters and waiter or paginator names:\n\n```python\nfrom mypy_boto3_rds.literals import ActivityStreamModeType, DBInstanceAvailableWaiterName\n\nmode: ActivityStreamModeType = \"async\"\nwaiter_name: DBInstanceAvailableWaiterName = \"db_instance_available\"\n```\n\n### Type Definitions\n\nUse generated `TypedDict` shapes to keep helper payloads typed:\n\n```python\nfrom mypy_boto3_rds.type_defs import FilterTypeDef\n\nengine_filter: FilterTypeDef = {\n    \"Name\": \"engine\",\n    \"Values\": [\"postgres\"],\n}\n```\n\nThese shapes are useful for request builders, wrapper utilities, and test fixtures.\n\n## Editor And Type Checker Notes\n\n- `mypy`, Pyright, Pylance, and other static analyzers consume the stubs automatically once they are installed.\n- Upstream notes that `boto3-stubs[rds]` gives the best zero-annotation IDE experience in VS Code and similar editors.\n- Upstream also warns that PyCharm can be slow on `Literal` overloads; if that happens, prefer `boto3-stubs-lite` or rely on `mypy` or `pyright` for checking.\n- With standalone `mypy-boto3-rds`, explicit client annotations remain the safest way to keep `Session().client(\"rds\")` typed.\n\nMinimal `mypy` config:\n\n```ini\n[mypy]\npython_version = 3.11\nstrict = True\n```\n\n## Common Pitfalls\n\n- `mypy-boto3-rds` is stubs-only. It does not replace `boto3`, `botocore`, or AWS credentials.\n- The PyPI name uses hyphens, but the import package is `mypy_boto3_rds`.\n- Keep `boto3`, `botocore`, and the generated stubs on closely aligned version lines. Mismatches can show up as missing members or stale type errors.\n- If you install `boto3-stubs-lite[rds]`, `Session.client(\"rds\")` overloads are intentionally omitted upstream. Add explicit annotations instead of assuming inference will work.\n- Guard stub imports with `TYPE_CHECKING` if your deployed runtime excludes dev-only dependencies.\n- RDS has no service resource type in this package doc flow; treat the typed client as the primary entry point.\n- Do not copy older boto3 examples that flatten everything to `dict[str, Any]`. The benefit of this package comes from typed clients, paginators, waiters, literals, and type defs propagating through call sites.\n\n## Version-Sensitive Notes\n\n- The package version and version used here both resolve cleanly to `1.42.51`.\n- The docs URL is a generated latest site, not a version-pinned page. On `2026-03-11`, its install guidance already referenced local generation against `boto3==1.42.63`, which is newer than the published `mypy-boto3-rds==1.42.51` package.\n- For reproducible builds, pin `boto3`, `botocore`, and `mypy-boto3-rds` to a tested set instead of assuming the latest docs page matches the currently published wheel.\n- If you need stubs for a newer boto3 release before PyPI publishes the matching service package, upstream recommends generating them locally with `mypy-boto3-builder`.\n\n## Official Sources Used\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_rds/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-rds/`\n- Maintainer repository: `https://github.com/youtype/types-boto3`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-redshift/python/DOC.md",
    "content": "---\nname: mypy-boto3-redshift\ndescription: \"Type stubs for boto3 Redshift in Python projects, including typed clients, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.42\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,redshift,boto3,python,typing,stubs,mypy,pyright\"\n---\n\n# mypy-boto3-redshift Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-redshift` for static typing only, and keep `boto3` as the runtime AWS SDK.\n\nCreate the real client with `boto3` or `boto3.session.Session`, then:\n\n- install `boto3-stubs[redshift]` if you want editor and type-checker auto-discovery with minimal annotation noise\n- install `mypy-boto3-redshift` directly if you want the Redshift-specific stubs and are fine importing the types explicitly\n\nThis package does not change AWS runtime behavior, credentials, retries, endpoints, or service semantics.\n\n## What This Package Gives You\n\n`mypy-boto3-redshift` adds type information for the boto3 Redshift control-plane client surface:\n\n- typed client annotations via `RedshiftClient`\n- generated paginator classes in `mypy_boto3_redshift.paginator`\n- generated waiter classes in `mypy_boto3_redshift.waiter`\n- generated literal unions in `mypy_boto3_redshift.literals`\n- generated `TypedDict` request and response shapes in `mypy_boto3_redshift.type_defs`\n\nUse this package for cluster-management code such as describing clusters, snapshots, subnet groups, scheduled actions, and tags.\n\nDo not use it as a runtime library for SQL execution. For SQL statements, use the Redshift Data API client or a PostgreSQL-compatible driver against the cluster endpoint.\n\n## Install\n\nPin `boto3` and the stubs to the same release line when possible.\n\nRecommended for most projects:\n\n```bash\npython -m pip install \"boto3==1.42.42\" \"boto3-stubs[redshift]==1.42.42\"\n```\n\nStandalone Redshift stubs:\n\n```bash\npython -m pip install \"boto3==1.42.42\" \"mypy-boto3-redshift==1.42.42\"\n```\n\nLower-memory alternative:\n\n```bash\npython -m pip install \"boto3==1.42.42\" \"boto3-stubs-lite[redshift]==1.42.42\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.42\" \"mypy-boto3-redshift==1.42.42\"\npoetry add \"boto3==1.42.42\" \"mypy-boto3-redshift==1.42.42\"\n```\n\nIf you need stubs generated against your exact pinned boto3 version, the maintainer recommends local generation:\n\n```bash\nuvx --with \"boto3==1.42.42\" mypy-boto3-builder\n```\n\n## Authentication And Setup\n\nThis package has no auth configuration of its own. Redshift typing follows normal boto3 setup.\n\nThe boto3 credentials guide says boto3 checks credentials in this order: explicit client parameters, explicit `Session(...)` parameters, environment variables, assume-role providers, AWS IAM Identity Center, shared credential/config files, then runtime providers such as containers or EC2 instance metadata.\n\nPractical defaults:\n\n1. Local development: `Session(profile_name=..., region_name=...)`\n2. CI or containers: environment variables or workload credentials\n3. AWS runtime: attached IAM role or equivalent runtime identity\n\nTyped client setup with an explicit region:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_redshift import RedshiftClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: RedshiftClient = session.client(\"redshift\")\n```\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_MAX_ATTEMPTS`\n- `AWS_RETRY_MODE`\n\nRedshift is regional. If the environment is ambiguous, set `region_name` explicitly or you will get confusing not-found and access errors against the wrong region.\n\n## Core Usage\n\n### Type a normal Redshift client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_redshift import RedshiftClient\n\nclient: RedshiftClient = Session(region_name=\"us-east-1\").client(\"redshift\")\n\nresponse = client.describe_clusters(ClusterIdentifier=\"analytics-prod\")\ncluster = response[\"Clusters\"][0]\n\nprint(cluster[\"ClusterIdentifier\"])\nprint(cluster[\"ClusterStatus\"])\nprint(cluster[\"NodeType\"])\nprint(cluster.get(\"Endpoint\", {}).get(\"Address\"))\n```\n\n### Type paginators explicitly\n\nAWS documents paginator support for Redshift list and describe operations such as `DescribeClusters`, `DescribeClusterSnapshots`, `DescribeEvents`, `DescribeTags`, and `ListRecommendations`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_redshift import RedshiftClient\nfrom mypy_boto3_redshift.paginator import DescribeClustersPaginator\n\nclient: RedshiftClient = Session(region_name=\"us-east-1\").client(\"redshift\")\npaginator: DescribeClustersPaginator = client.get_paginator(\"describe_clusters\")\n\nfor page in paginator.paginate(MaxRecords=100):\n    for cluster in page.get(\"Clusters\", []):\n        print(cluster[\"ClusterIdentifier\"], cluster[\"ClusterStatus\"])\n```\n\n### Type waiters explicitly\n\nAWS documents four Redshift waiters: `cluster_available`, `cluster_deleted`, `cluster_restored`, and `snapshot_available`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_redshift import RedshiftClient\nfrom mypy_boto3_redshift.waiter import ClusterAvailableWaiter\n\nclient: RedshiftClient = Session(region_name=\"us-east-1\").client(\"redshift\")\nwaiter: ClusterAvailableWaiter = client.get_waiter(\"cluster_available\")\n\nwaiter.wait(\n    ClusterIdentifier=\"analytics-prod\",\n    WaiterConfig={\"Delay\": 30, \"MaxAttempts\": 40},\n)\n```\n\nUse waiters after create, restore, resize, or resume operations instead of hand-written sleep loops.\n\n### Use generated literals and TypedDicts\n\n```python\nfrom mypy_boto3_redshift.literals import ActionTypeType\nfrom mypy_boto3_redshift.type_defs import AcceptReservedNodeExchangeInputMessageTypeDef\n\ndef build_exchange_request(action_type: ActionTypeType) -> AcceptReservedNodeExchangeInputMessageTypeDef:\n    return {\n        \"ActionType\": action_type,\n        \"ReservedNodeId\": \"reserved-node-id\",\n        \"TargetReservedNodeOfferingId\": \"offering-id\",\n    }\n```\n\nThis is useful when you wrap boto3 calls in helper functions and want stronger static validation for request payloads.\n\n### `TYPE_CHECKING` pattern for dev-only stubs\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_redshift import RedshiftClient\nelse:\n    RedshiftClient = object\n\nclient: RedshiftClient = boto3.client(\"redshift\", region_name=\"us-east-1\")\n```\n\nThis avoids importing the stubs package at runtime when it is installed only in development or CI. It also matches the maintainer's documented workaround for `pylint`.\n\n## Configuration Notes\n\n- Keep auth, region, retries, and timeouts on the real boto3 client. The stubs package does not alter runtime configuration.\n- Prefer `Session(profile_name=..., region_name=...)` for local tools and multi-account automation.\n- The Redshift client in boto3 is the control-plane API. It manages clusters, snapshots, parameter groups, and related resources.\n- For SQL execution, use `redshift-data` or a PostgreSQL-compatible driver instead of the Redshift control-plane client.\n- Use waiter and paginator types only after confirming the underlying boto3 client actually exposes the corresponding waiter or paginator in your pinned version.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-redshift` without `boto3` and expecting a working AWS client.\n- Importing the package as `mypy-boto3-redshift` in Python code. The import root is `mypy_boto3_redshift`.\n- Treating the Redshift control-plane client as a SQL client. `describe_clusters` and `create_cluster` are not the same surface as query execution.\n- Assuming type checking proves IAM permissions, network reachability, cluster availability, or region selection are correct.\n- Forgetting that `boto3-stubs-lite[redshift]` is lighter specifically because it drops `session.client()` and `session.resource()` overload support.\n- Letting `boto3`, `botocore`, and the stubs drift too far apart. Generated symbols can lag or differ if versions are not aligned.\n- Copying examples from generic Redshift Data API docs into this package. `mypy-boto3-redshift` targets the `redshift` service client, not `redshift-data` or `redshift-serverless`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.42.42`, which matches the PyPI project page as of March 12, 2026.\n- PyPI lists this release as published on February 4, 2026.\n- PyPI says `mypy-boto3-redshift 1.42.42` was generated with `mypy-boto3-builder 8.12.0`.\n- The maintainer documents that the package version tracks the related boto3 version. Keep `boto3` and `mypy-boto3-redshift` on the same version when practical.\n- The AWS boto3 Redshift reference is a rolling `latest` docs tree and may show a nearby patch version in the page header. Use PyPI for exact package pinning and AWS docs for runtime behavior.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_redshift/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-redshift/`\n- AWS boto3 credential guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 Redshift reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/redshift.html`\n- Builder repository linked from PyPI for support and bug reports: `https://github.com/youtype/mypy_boto3_builder`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-rekognition/python/DOC.md",
    "content": "---\nname: mypy-boto3-rekognition\ndescription: \"mypy-boto3-rekognition package guide for typed boto3 Rekognition clients, literals, TypedDicts, paginators, and waiters\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,boto3,rekognition,python,types,stubs,mypy\"\n---\n\n# mypy-boto3-rekognition Python Package Guide\n\n## Golden Rule\n\n- `mypy-boto3-rekognition` is a typing package for `boto3`, not a runtime AWS SDK.\n- Install it alongside `boto3`, or use the upstream `boto3-stubs[rekognition]` extra.\n- Keep `boto3`, `botocore`, and this stub package on the same release line when request and response shapes matter.\n\n## Version-Sensitive Notes\n\n- The official PyPI package page shows `mypy-boto3-rekognition 1.42.3` and `Requires: Python >=3.9`.\n- The upstream package page also states these stubs were generated from `boto3==1.42.3` and `botocore==1.42.3`.\n- The hosted docs URL is a moving docs root, not an immutable versioned snapshot. Re-check it before pinning a newer release line.\n- If you upgrade `boto3` before matching Rekognition stubs exist, runtime calls can still work while type hints lag behind the actual service model.\n\n## Install\n\n### Minimal Service-Specific Setup\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-rekognition==1.42.3\"\n```\n\n### Bundled Upstream Install Path\n\n```bash\npython -m pip install \"boto3-stubs[rekognition]==1.42.3\"\n```\n\n### Lower-Memory Alternative\n\n```bash\npython -m pip install \"boto3-stubs-lite[rekognition]==1.42.3\"\n```\n\nUse the standalone package when you only need Rekognition types. Use the umbrella extras when your project already follows the `boto3-stubs` install path across multiple AWS services.\n\n## Initialize And Type A Rekognition Client\n\nAWS credentials and region handling still come from normal `boto3` configuration. The stub package only improves static analysis.\n\n```python\nfrom typing import cast\n\nimport boto3\nfrom mypy_boto3_rekognition import RekognitionClient\n\nsession = boto3.Session(profile_name=\"vision-dev\", region_name=\"us-east-1\")\nrekognition = cast(RekognitionClient, session.client(\"rekognition\"))\n\nresponse = rekognition.detect_labels(\n    Image={\"S3Object\": {\"Bucket\": \"incoming-images\", \"Name\": \"photo.jpg\"}},\n    MaxLabels=10,\n    MinConfidence=80.0,\n)\n\nfor label in response.get(\"Labels\", []):\n    print(label[\"Name\"], label.get(\"Confidence\"))\n```\n\nIf your checker already infers the concrete client type from `session.client(\"rekognition\")`, the explicit `cast(...)` may be unnecessary. Keep it when editor or CI inference is inconsistent.\n\n## Core Typing Surfaces\n\n### Typed Client\n\nImport `RekognitionClient` from the package root and use it to annotate helpers that accept a Rekognition client:\n\n```python\nfrom mypy_boto3_rekognition import RekognitionClient\n\ndef has_face_model(client: RekognitionClient, project_version_arn: str) -> bool:\n    response = client.describe_project_versions(\n        ProjectArn=project_version_arn.rsplit(\"/\", 1)[0],\n        VersionNames=[project_version_arn.rsplit(\"/\", 1)[-1]],\n    )\n    return bool(response.get(\"ProjectVersionDescriptions\"))\n```\n\n### Literals\n\nThe package exposes generated literal types under `mypy_boto3_rekognition.literals` for enum-like strings:\n\n```python\nfrom mypy_boto3_rekognition.literals import AttributeTypeType\n\nrequested_attributes: list[AttributeTypeType] = [\"DEFAULT\"]\n```\n\nUse them when you want the type checker to reject misspelled Rekognition option values.\n\n### TypedDict Shapes\n\nGenerated request and response shapes live under `mypy_boto3_rekognition.type_defs`:\n\n```python\nfrom mypy_boto3_rekognition.type_defs import CompareFacesRequestRequestTypeDef\n\nrequest: CompareFacesRequestRequestTypeDef = {\n    \"SourceImage\": {\"S3Object\": {\"Bucket\": \"images\", \"Name\": \"source.jpg\"}},\n    \"TargetImage\": {\"S3Object\": {\"Bucket\": \"images\", \"Name\": \"target.jpg\"}},\n    \"SimilarityThreshold\": 90.0,\n}\n```\n\nUse these types when a helper builds request payloads separately from the final client call.\n\n### Paginators And Waiters\n\nThe generated package also includes `paginator.py` and `waiter.py` modules.\n\n- Use paginators through the normal `boto3` runtime API: `client.get_paginator(...)`.\n- Use waiters only for the Rekognition workflows that actually expose them, mainly Custom Labels project-version operations.\n- Check the generated docs page for the exact paginator and waiter names in your installed version before hardcoding them.\n\n## AWS Config And Authentication\n\nThis package does not add a separate auth layer. Use the normal `boto3` credential provider chain:\n\n1. Explicit credentials passed to `boto3.Session(...)` or `client(...)`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. Shared AWS config and credentials files, including named profiles\n4. IAM roles, IAM Identity Center configuration, or other runtime credential providers in AWS environments\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=vision-dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen:\n\n```python\nfrom typing import cast\n\nimport boto3\nfrom mypy_boto3_rekognition import RekognitionClient\n\nrekognition = cast(RekognitionClient, boto3.Session().client(\"rekognition\"))\n```\n\nFor deployed workloads, prefer IAM roles or other short-lived credentials instead of hardcoded keys.\n\n## Type Checker And IDE Setup\n\n- Install the stub package in the same environment your type checker or editor analyzes.\n- Import from `mypy_boto3_rekognition`, not `mypy-boto3-rekognition`. The package name uses hyphens; the Python module uses underscores.\n- If you use `boto3-stubs-lite`, expect to add more explicit annotations because some session overload helpers are intentionally lighter.\n- Treat the stub package as a development-time typing dependency unless your runtime code imports its types directly.\n\n## Common Pitfalls\n\n- Do not try to construct a client from `mypy_boto3_rekognition`; real clients still come from `boto3.client(\"rekognition\")` or `Session.client(\"rekognition\")`.\n- Do not forget the AWS region. Static typing will not save you from runtime `NoRegionError`.\n- Do not assume every Rekognition API has a paginator or waiter. Many image-analysis operations are plain request-response calls.\n- Do not pin a newer `boto3` without checking whether matching Rekognition stubs are published yet.\n- Do not confuse dev-only typing imports with runtime dependencies if your production environment omits stub packages.\n\n## Official Sources\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_rekognition/`\n- Upstream versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-rekognition/`\n- boto3 credential guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-route53/python/DOC.md",
    "content": "---\nname: mypy-boto3-route53\ndescription: \"mypy-boto3-route53 package guide for typed boto3 Route 53 clients, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,route53,dns,mypy,pyright,stubs,python\"\n---\n\n# mypy-boto3-route53 Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real Route 53 API calls and `mypy-boto3-route53` only for typing. If you want `Session.client(\"route53\")` to infer automatically, install `boto3-stubs[route53]`; if you install only the standalone or lite package, annotate `Route53Client` explicitly.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.6` matches the official PyPI release and maintainer docs checked on `2026-03-12`.\n- The maintainer project states that `mypy-boto3-route53` uses the same version as the related `boto3` release. Keep the stub package close to your runtime `boto3` line so method signatures and request/response shapes do not drift.\n- The docs root is a stable package URL, not a release-pinned docs URL. Pin the package in your environment when exact patch parity matters.\n- The published Route 53 docs expose `client`, `paginator`, `waiter`, `literals`, and `type_defs`. I did not find a dedicated Route 53 `service_resource` module in the published `1.42.6` docs, so plan around typed clients.\n- The project recommends local generation with `mypy-boto3-builder` when you need stubs that exactly match the installed `boto3` build in your environment.\n\n## Install\n\nChoose one install mode based on how much boto3 typing support you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want automatic type discovery for `Session.client(\"route53\")`, `client.get_paginator(...)`, and `client.get_waiter(...)`:\n\n```bash\npython -m pip install \"boto3-stubs[route53]\"\n```\n\n### Service-specific package only\n\nUse this when you want only the Route 53 typing package and are willing to add explicit annotations:\n\n```bash\npython -m pip install \"boto3\" \"mypy-boto3-route53==1.42.6\"\n```\n\n### Lite aggregate package\n\nUse this when the full stubs package is too heavy for your IDE or environment:\n\n```bash\npython -m pip install \"boto3-stubs-lite[route53]\"\n```\n\nThe lite package is more RAM-friendly, but the maintainer docs note that it does not provide `session.client/resource` overloads, so explicit annotations become more important.\n\n## Initialization And Setup\n\n`mypy-boto3-route53` does not add its own auth or config layer. All runtime behavior still comes from normal boto3 setup:\n\n- credentials from environment variables, shared AWS config files, IAM Identity Center, assume-role config, container credentials, or runtime IAM roles\n- optional profile selection through `AWS_PROFILE` or `boto3.Session(profile_name=...)`\n- any retry, timeout, proxy, or endpoint behavior from `botocore.config.Config`\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\n```\n\nThen create the real boto3 client and annotate it:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53.client import Route53Client\n\nsession = boto3.Session(profile_name=\"dev\")\nroute53: \"Route53Client\" = session.client(\"route53\")\n```\n\nRoute 53 is a global service, so examples commonly use `Session().client(\"route53\")` without service-specific region handling. Still keep your broader AWS profile and signing configuration explicit in the session your application uses.\n\n## Core Usage\n\n### Typed Route 53 client\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53.client import Route53Client\n\nroute53: \"Route53Client\" = boto3.Session(profile_name=\"dev\").client(\"route53\")\n\nresponse = route53.list_hosted_zones(MaxItems=\"10\")\n\nfor zone in response.get(\"HostedZones\", []):\n    print(zone[\"Name\"], zone[\"Id\"])\n```\n\n### Typed paginator\n\nUse paginator types instead of hand-rolled marker loops when scanning many hosted zones or record sets:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53.client import Route53Client\n    from mypy_boto3_route53.paginator import ListResourceRecordSetsPaginator\n\nroute53: \"Route53Client\" = boto3.Session().client(\"route53\")\n\npaginator: \"ListResourceRecordSetsPaginator\" = route53.get_paginator(\n    \"list_resource_record_sets\"\n)\n\nfor page in paginator.paginate(HostedZoneId=\"Z0123456789ABCDEFG\"):\n    for record in page.get(\"ResourceRecordSets\", []):\n        print(record[\"Name\"], record[\"Type\"])\n```\n\n### Typed waiter for DNS changes\n\nRoute 53 DNS changes are asynchronous. Use the typed waiter after `change_resource_record_sets` when later steps depend on the change reaching `INSYNC`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53.client import Route53Client\n    from mypy_boto3_route53.waiter import ResourceRecordSetsChangedWaiter\n\nroute53: \"Route53Client\" = boto3.Session().client(\"route53\")\n\nresponse = route53.change_resource_record_sets(\n    HostedZoneId=\"Z0123456789ABCDEFG\",\n    ChangeBatch={\n        \"Comment\": \"Update app record\",\n        \"Changes\": [\n            {\n                \"Action\": \"UPSERT\",\n                \"ResourceRecordSet\": {\n                    \"Name\": \"app.example.com.\",\n                    \"Type\": \"A\",\n                    \"TTL\": 60,\n                    \"ResourceRecords\": [{\"Value\": \"203.0.113.10\"}],\n                },\n            }\n        ],\n    },\n)\n\nwaiter: \"ResourceRecordSetsChangedWaiter\" = route53.get_waiter(\n    \"resource_record_sets_changed\"\n)\nwaiter.wait(Id=response[\"ChangeInfo\"][\"Id\"])\n```\n\n### Typed request dictionaries and literals\n\nGenerated request `TypedDict` shapes and literal aliases are useful when helper functions build Route 53 arguments before the client call:\n\n```python\nfrom mypy_boto3_route53.literals import RRTypeType\nfrom mypy_boto3_route53.type_defs import ListResourceRecordSetsRequestTypeDef\n\nrecord_type: RRTypeType = \"A\"\n\nparams: ListResourceRecordSetsRequestTypeDef = {\n    \"HostedZoneId\": \"Z0123456789ABCDEFG\",\n    \"StartRecordName\": \"app.example.com.\",\n    \"StartRecordType\": record_type,\n}\n```\n\nThe generated client docs also expose request shapes such as `ListHostedZonesRequestTypeDef`, `GetChangeRequestTypeDef`, and many Route 53 response `TypedDict` definitions.\n\n## Runtime-Safe Typing Pattern\n\nIf your production image does not install stub packages, keep the imports inside `TYPE_CHECKING` so the type checker sees them without turning the stubs into a runtime dependency:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53.client import Route53Client\n\nclient: \"Route53Client\" = boto3.Session().client(\"route53\")\n```\n\nThe maintainer docs also note a `pylint` workaround: if `pylint` complains about names imported only under `TYPE_CHECKING`, assign those names to `object` in the `else` branch.\n\n## Route 53-Specific Notes\n\n- The boto3 service name is `route53`, not `mypy-boto3-route53`.\n- Hosted zone IDs and change IDs come from Route 53 responses; do not guess their format.\n- Record names are easiest to reason about when you keep them fully qualified, including the trailing dot.\n- `change_resource_record_sets` accepts change batches. Prefer `UPSERT` when you want idempotent create-or-replace behavior.\n- Wait for `INSYNC` when later automation depends on the change. A successful write call only means Route 53 accepted the change request.\n- Route 53 DNS management is separate from services such as Route 53 Domains and Route 53 Resolver. Do not mix service names or docs across those packages.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_route53`.\n- This package is typing-only. Real AWS requests still require `boto3`.\n- If you choose `mypy-boto3-route53` or `boto3-stubs-lite[route53]`, do not expect all `Session.client(\"route53\")` calls to infer automatically. Add explicit `Route53Client` annotations.\n- Keep the stub package close to the installed `boto3` line. Version drift can hide newly added parameters or leave stale type information in the editor.\n- Route 53 authorization, credentials, retries, and profile resolution are boto3 concerns, not stub-package concerns.\n\n## Official Sources\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_route53/`\n- Route53 client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_route53/client/`\n- Waiter reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_route53/waiters/`\n- Versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-route53/`\n- Boto3 Route 53 service reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/route53.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-route53resolver/python/DOC.md",
    "content": "---\nname: mypy-boto3-route53resolver\ndescription: \"mypy-boto3-route53resolver package guide for typed boto3 Route 53 Resolver clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,boto3,route53resolver,dns,mypy,pyright,stubs,python\"\n---\n\n# mypy-boto3-route53resolver Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real Route 53 Resolver API calls and `mypy-boto3-route53resolver` only for typing. If you want `Session.client(\"route53resolver\")` to infer automatically, install `boto3-stubs[route53resolver]`. If you install only the standalone package or the lite bundle, annotate `Route53ResolverClient` explicitly.\n\n## Version-Sensitive Notes\n\n- The PyPI package page for `mypy-boto3-route53resolver` shows version `1.42.10`, release date `2025-12-15`, `Requires: Python >=3.9`, and `Typing :: Stubs Only`.\n- The maintainer project states that `mypy-boto3-route53resolver` uses the same version as the related `boto3` release. Keep the stub package close to your runtime `boto3` version so request and response shapes do not drift.\n- The maintainer docs recommend local generation with `mypy-boto3-builder` when you need stubs that exactly match the `boto3` version already pinned in your environment.\n- The Route 53 Resolver boto3 reference documents a low-level client and paginators for this service. I did not find a Route 53 Resolver service resource or waiters section in the published service reference, so plan around typed clients and paginators.\n\n## Install\n\nChoose one install mode based on how much boto3 typing support you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want `Session.client(\"route53resolver\")` overloads and editor inference without extra casts:\n\n```bash\npython -m pip install \"boto3-stubs[route53resolver]==1.42.10\"\n```\n\n### Service-specific package only\n\nUse this when you only need Route 53 Resolver types and are willing to annotate the client explicitly:\n\n```bash\npython -m pip install \"boto3==1.42.10\" \"mypy-boto3-route53resolver==1.42.10\"\n```\n\n### Lower-memory alternative\n\nUse this when the full stubs package is too heavy for your IDE:\n\n```bash\npython -m pip install \"boto3-stubs-lite[route53resolver]==1.42.10\"\n```\n\nThe maintainer docs note that the lite package does not provide `session.client/resource` overloads, so explicit annotations become more important.\n\n## Initialization And AWS Config\n\n`mypy-boto3-route53resolver` does not add its own auth or transport layer. Runtime behavior still comes from normal boto3 configuration:\n\n- credentials passed directly to `boto3.client(...)` or `boto3.Session(...)`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_PROFILE`, and `AWS_DEFAULT_REGION`\n- shared AWS config and credentials files\n- assume-role, IAM Identity Center, container credentials, or IAM roles\n- `botocore.config.Config` for retries, proxies, and other client settings\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=networking-dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nRoute 53 Resolver is regional, so set `region_name` on the session or in your AWS config.\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_route53resolver import Route53ResolverClient\n\nsession = Session(profile_name=\"networking-dev\", region_name=\"us-east-1\")\n\nroute53resolver: Route53ResolverClient = session.client(\n    \"route53resolver\",\n    config=Config(retries={\"max_attempts\": 10, \"mode\": \"standard\"}),\n)\n```\n\n## Core Usage\n\n### Typed client\n\nUse the generated client type for helpers that create or accept a Route 53 Resolver client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_route53resolver import Route53ResolverClient\n\nroute53resolver: Route53ResolverClient = Session(\n    profile_name=\"networking-dev\",\n    region_name=\"us-east-1\",\n).client(\"route53resolver\")\n\nresponse = route53resolver.list_resolver_endpoints()\n\nfor endpoint in response.get(\"ResolverEndpoints\", []):\n    print(endpoint[\"Id\"], endpoint[\"Direction\"], endpoint.get(\"Name\"))\n```\n\n### Typed paginator\n\nThe generated paginator module includes Route 53 Resolver paginator types such as `ListResolverEndpointsPaginator`, `ListResolverRulesPaginator`, and `ListTagsForResourcePaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_route53resolver import Route53ResolverClient\nfrom mypy_boto3_route53resolver.paginator import ListResolverRulesPaginator\n\nclient: Route53ResolverClient = Session(region_name=\"us-east-1\").client(\n    \"route53resolver\"\n)\n\npaginator: ListResolverRulesPaginator = client.get_paginator(\"list_resolver_rules\")\n\nfor page in paginator.paginate():\n    for rule in page.get(\"ResolverRules\", []):\n        print(rule[\"Id\"], rule[\"DomainName\"], rule[\"RuleType\"])\n```\n\n### Associate a resolver rule with a VPC\n\nUse the real boto3 client call and let the stub package validate argument names and types:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_route53resolver import Route53ResolverClient\n\nclient: Route53ResolverClient = Session(region_name=\"us-east-1\").client(\n    \"route53resolver\"\n)\n\nclient.associate_resolver_rule(\n    ResolverRuleId=\"rslvr-rr-0123456789abcdef0\",\n    Name=\"corp-example-com\",\n    VPCId=\"vpc-0123456789abcdef0\",\n)\n```\n\n### Create and tag a resolver endpoint\n\nThe boto3 service reference exposes `create_resolver_endpoint` with `Direction`, `SecurityGroupIds`, `IpAddresses`, and optional `Tags`. You can keep tag payloads typed with `TagTypeDef`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_route53resolver import Route53ResolverClient\nfrom mypy_boto3_route53resolver.type_defs import TagTypeDef\n\nclient: Route53ResolverClient = Session(region_name=\"us-east-1\").client(\n    \"route53resolver\"\n)\n\ntags: list[TagTypeDef] = [\n    {\"Key\": \"env\", \"Value\": \"dev\"},\n    {\"Key\": \"owner\", \"Value\": \"dns-team\"},\n]\n\nclient.create_resolver_endpoint(\n    CreatorRequestId=\"resolver-endpoint-001\",\n    Name=\"outbound-main\",\n    SecurityGroupIds=[\"sg-0123456789abcdef0\"],\n    Direction=\"OUTBOUND\",\n    IpAddresses=[\n        {\"SubnetId\": \"subnet-0123456789abcdef0\"},\n        {\"SubnetId\": \"subnet-0fedcba9876543210\"},\n    ],\n    Tags=tags,\n)\n```\n\nIf you already have a resource ARN and only need to tag it later:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_route53resolver import Route53ResolverClient\nfrom mypy_boto3_route53resolver.type_defs import TagTypeDef\n\nclient: Route53ResolverClient = Session(region_name=\"us-east-1\").client(\n    \"route53resolver\"\n)\n\ntags: list[TagTypeDef] = [{\"Key\": \"env\", \"Value\": \"dev\"}]\n\nclient.tag_resource(\n    ResourceArn=\"arn:aws:route53resolver:us-east-1:123456789012:resolver-rule/rslvr-rr-0123456789abcdef0\",\n    Tags=tags,\n)\n```\n\n## Runtime-Safe Typing Pattern\n\nIf your production environment does not install stub packages, keep imports behind `TYPE_CHECKING` so your type checker sees them without making them a runtime dependency:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_route53resolver import Route53ResolverClient\nelse:\n    Route53ResolverClient = object\n\nclient: \"Route53ResolverClient\" = Session(region_name=\"us-east-1\").client(\n    \"route53resolver\"\n)\n```\n\nThe `else` assignment is the upstream `pylint` workaround for names imported only under `TYPE_CHECKING`.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_route53resolver`.\n- This package is typing-only. Real Route 53 Resolver requests still come from `boto3`.\n- `boto3-stubs-lite[route53resolver]` is more RAM-friendly, but it does not provide `session.client/resource` overloads.\n- Route 53 Resolver is regional. Static typing does not protect you from `NoRegionError` or from pointing at the wrong region.\n- The AWS service reference lists paginators for Route 53 Resolver, but not a service-specific waiters section. If later automation depends on a resource reaching a specific state, poll the relevant `get_*` or `list_*` operation yourself.\n- If the published stub version lags behind your pinned `boto3` runtime, generate stubs locally with `mypy-boto3-builder` instead of mixing mismatched versions.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_route53resolver/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-route53resolver/`\n- Boto3 Route 53 Resolver service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/route53resolver.html`\n- `list_resolver_rules` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/route53resolver/client/list_resolver_rules.html`\n- `create_resolver_endpoint` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/route53resolver/client/create_resolver_endpoint.html`\n- `associate_resolver_rule` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/route53resolver/client/associate_resolver_rule.html`\n- `tag_resource` reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/route53resolver/client/tag_resource.html`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-s3/python/DOC.md",
    "content": "---\nname: mypy-boto3-s3\ndescription: \"mypy-boto3-s3 type stubs for boto3 S3 clients, resources, paginators, waiters, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.37\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,s3,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-s3 Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-s3` is a typing package for `boto3` S3 code. It does not replace `boto3`, it does not make AWS calls on its own, and it does not manage credentials or regions for you.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[s3]` for the best editor and type-checker experience with automatic `Session.client(\"s3\")` and `Session.resource(\"s3\")` overloads.\n- Install `mypy-boto3-s3` when you want only the standalone S3 stubs and are willing to add explicit type annotations.\n- Install `boto3-stubs-lite[s3]` when IDE memory use matters more than automatic overload inference.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[s3]'\n```\n\nThis is the maintainer-recommended path when you want autocomplete plus type inference without annotating every S3 variable.\n\n### Standalone S3 stubs\n\n```bash\npython -m pip install boto3 mypy-boto3-s3\n```\n\nUse this when you want only the S3 stubs package. In this mode, explicit annotations are usually necessary.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[s3]'\n```\n\nThe lite package is more memory-friendly, especially for PyCharm, but it does not provide `session.client()` and `session.resource()` overloads. Add explicit annotations if you use it.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-s3` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nAWS documents that Boto3 requests need both AWS credentials and an AWS Region. The usual setup is either:\n\n```bash\naws configure\n```\n\nor environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nFor explicit account, profile, or region control, create a session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n```\n\n## Core Usage\n\n### Typed client and resource\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.client import S3Client\nfrom mypy_boto3_s3.service_resource import S3ServiceResource\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n\ns3_client: S3Client = session.client(\"s3\")\ns3_resource: S3ServiceResource = session.resource(\"s3\")\n```\n\nUse the client for full API coverage. AWS says Boto3 clients are the low-level interface and map closely to service APIs. AWS also says the resources interface is not getting new features, so newer S3 capabilities may only appear on the client side.\n\n### Typed paginator and waiter\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.client import S3Client\nfrom mypy_boto3_s3.paginator import ListObjectsV2Paginator\nfrom mypy_boto3_s3.waiter import ObjectExistsWaiter\n\nclient: S3Client = Session(region_name=\"us-west-2\").client(\"s3\")\n\npaginator: ListObjectsV2Paginator = client.get_paginator(\"list_objects_v2\")\nwaiter: ObjectExistsWaiter = client.get_waiter(\"object_exists\")\n\nfor page in paginator.paginate(Bucket=\"my-bucket\", Prefix=\"incoming/\"):\n    for item in page.get(\"Contents\", []):\n        print(item[\"Key\"])\n\nwaiter.wait(Bucket=\"my-bucket\", Key=\"incoming/report.csv\")\n```\n\n### Typed resources and collections\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.service_resource import Bucket, ObjectSummary, S3ServiceResource\n\nresource: S3ServiceResource = Session(region_name=\"us-west-2\").resource(\"s3\")\n\nbucket: Bucket = resource.Bucket(\"my-bucket\")\n\nfor obj in bucket.objects.filter(Prefix=\"incoming/\"):\n    typed_obj: ObjectSummary = obj\n    print(typed_obj.key)\n```\n\n### TypedDict request and response shapes\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_s3.client import S3Client\nfrom mypy_boto3_s3.literals import BucketLocationConstraintType\nfrom mypy_boto3_s3.type_defs import GetObjectOutputTypeDef\n\nclient: S3Client = Session(region_name=\"us-west-2\").client(\"s3\")\n\nlocation: BucketLocationConstraintType = \"us-west-2\"\nclient.create_bucket(\n    Bucket=\"my-bucket\",\n    CreateBucketConfiguration={\"LocationConstraint\": location},\n)\n\nresponse: GetObjectOutputTypeDef = client.get_object(\n    Bucket=\"my-bucket\",\n    Key=\"data.json\",\n)\nbody = response[\"Body\"].read()\n```\n\nUse `literals` when an API field accepts a constrained string set, and use `type_defs` when you need `TypedDict` coverage for request or response shapes.\n\n## Tooling Patterns\n\n### Explicit annotations for standalone stubs\n\nThe standalone `mypy-boto3-s3` package is most useful when you annotate clients, resources, paginators, waiters, and `TypedDict` values directly. That keeps type checking deterministic across mypy, pyright, and IDEs.\n\n### Keep the stubs as a dev-only dependency\n\nIf production images do not install stub packages, gate the imports with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_s3.client import S3Client\n\ndef make_client() -> \"S3Client\":\n    return Session(region_name=\"us-west-2\").client(\"s3\")\n```\n\nThis avoids a runtime import dependency while preserving type information.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-s3` and expecting unannotated `session.client(\"s3\")` calls to become typed automatically. That behavior comes from `boto3-stubs[s3]`.\n- Forgetting to install `boto3`. These packages are type stubs, not the runtime SDK.\n- Treating the stubs package as AWS auth or config middleware. Credentials, region, retries, and endpoints still come from normal `boto3` and botocore setup.\n- Defaulting to the resource API for every new S3 feature. AWS documents that new features land on clients, not resources.\n- Using `boto3-stubs-lite[s3]` and then expecting overload-based inference from `session.client(\"s3\")`. Lite mode needs more explicit annotations.\n- Copying examples from other service stub packages. Imports and class names are service-specific; use `mypy_boto3_s3`, not generic or EC2 examples.\n\n## Version-Sensitive Notes\n\n- The version used here for this package is `1.42.37`, and the PyPI project page currently lists `1.42.37` as the published release for `mypy-boto3-s3`.\n- The maintainer states that `mypy-boto3-s3` versions match the related `boto3` version. Pin them together when exact shape coverage matters.\n- The maintainer also documents a local generation path with `mypy-boto3-builder`. If you need exact stubs for a pinned `boto3` version or a private fork, generate them locally instead of assuming the hosted docs are version-perfect for your environment.\n- Practical rule: pin `boto3==1.42.37` with `mypy-boto3-s3==1.42.37` when you want the closest alignment to this entry.\n\n## Official Sources\n\n- Docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_s3/\n- PyPI: https://pypi.org/project/mypy-boto3-s3/\n- Homepage: https://youtype.github.io/boto3_stubs_docs/\n- Source repository: https://github.com/youtype/mypy_boto3_builder\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 clients guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html\n- Boto3 resources guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sagemaker/python/DOC.md",
    "content": "---\nname: mypy-boto3-sagemaker\ndescription: \"mypy-boto3-sagemaker package guide for typed boto3 SageMaker clients, paginators, waiters, and static analysis\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,pypi,aws,sagemaker,boto3,mypy,typing,stubs\"\n---\n\n# mypy-boto3-sagemaker Python Package Guide\n\n## What It Is\n\n`mypy-boto3-sagemaker` is the generated type-stub package for the SageMaker part of `boto3`. It gives you typed client methods, paginators, waiters, literals, and request/response definitions for static analysis and editor completion.\n\nIt is not a runtime AWS SDK. Your code still runs through normal `boto3` sessions and clients.\n\n## Golden Rules\n\n- Install `boto3` for runtime behavior and `mypy-boto3-sagemaker` for typing.\n- Annotate the client explicitly when you want reliable `mypy` or `pyright` inference.\n- Keep the stub version close to the installed `boto3` version.\n- Configure credentials, region, retries, and endpoints through `boto3` and botocore, not through the stub package.\n- Treat the package as development-time support. It improves correctness before runtime, but it does not fix IAM, region, or network problems.\n\n## Install\n\nPin the runtime SDK and the matching stubs together when you want reproducible typing:\n\n```bash\npython -m pip install \"boto3==1.42.66\" \"mypy-boto3-sagemaker==1.42.66\"\n```\n\nThe upstream docs also treat this standalone package as equivalent to the service extra on `boto3-stubs`:\n\n```bash\npython -m pip install \"boto3-stubs[sagemaker]==1.42.66\"\n```\n\nIf you want the `boto3` runtime installed through the umbrella package too, use:\n\n```bash\npython -m pip install \"boto3-stubs[boto3,sagemaker]==1.42.66\"\n```\n\n## Initialize A Typed SageMaker Client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sagemaker.client import SageMakerClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nsm: SageMakerClient = session.client(\"sagemaker\")\n```\n\nFor botocore retry settings, proxies, or timeouts, keep using `Config`:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_sagemaker.client import SageMakerClient\n\nconfig = Config(retries={\"max_attempts\": 10, \"mode\": \"standard\"})\nsession = Session(region_name=\"us-west-2\")\nsm: SageMakerClient = session.client(\"sagemaker\", config=config)\n```\n\n## Core Usage\n\n### Typed Client Calls\n\n```python\nfrom mypy_boto3_sagemaker.client import SageMakerClient\n\ndef training_job_status(sm: SageMakerClient, job_name: str) -> str:\n    response = sm.describe_training_job(TrainingJobName=job_name)\n    return response[\"TrainingJobStatus\"]\n```\n\n### Typed Paginators\n\nUse the generated paginator classes when you want explicit annotations:\n\n```python\nfrom mypy_boto3_sagemaker.client import SageMakerClient\nfrom mypy_boto3_sagemaker.paginator import ListTrainingJobsPaginator\n\ndef recent_training_jobs(sm: SageMakerClient) -> list[str]:\n    paginator: ListTrainingJobsPaginator = sm.get_paginator(\"list_training_jobs\")\n    names: list[str] = []\n\n    for page in paginator.paginate(SortBy=\"CreationTime\", SortOrder=\"Descending\"):\n        names.extend(item[\"TrainingJobName\"] for item in page[\"TrainingJobSummaries\"])\n\n    return names\n```\n\n### Typed Waiters\n\nThe generated waiters let type checkers understand the waiter name and request shape:\n\n```python\nfrom mypy_boto3_sagemaker.client import SageMakerClient\nfrom mypy_boto3_sagemaker.waiter import TrainingJobCompletedOrStoppedWaiter\n\ndef wait_for_training_job(sm: SageMakerClient, job_name: str) -> None:\n    waiter: TrainingJobCompletedOrStoppedWaiter = sm.get_waiter(\n        \"training_job_completed_or_stopped\"\n    )\n    waiter.wait(TrainingJobName=job_name)\n```\n\n### TYPE_CHECKING For Dev-Only Stub Installs\n\nIf the stubs are installed only in development or CI, keep the type imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sagemaker.client import SageMakerClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nsm: \"SageMakerClient\" = session.client(\"sagemaker\")\n```\n\nThis pattern is useful if production images ship `boto3` without the stub package.\n\n## AWS Config And Authentication\n\n`mypy-boto3-sagemaker` does not change how AWS authentication works. Use standard `boto3` configuration:\n\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `~/.aws/credentials`\n- `~/.aws/config`\n- IAM roles or task roles when running on AWS\n\nTypical local setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sagemaker.client import SageMakerClient\n\nsession = Session(profile_name=\"ml-dev\", region_name=\"us-west-2\")\nsm: SageMakerClient = session.client(\"sagemaker\")\n\nprint(sm.list_domains()[\"Domains\"])\n```\n\nIf the client is typed correctly but calls still fail, debug the runtime AWS setup first: credentials, region, permissions, VPC/network access, and endpoint configuration.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-sagemaker` and expecting SageMaker calls to work without `boto3`.\n- Letting `boto3` and the stubs drift too far apart, which can make typed method signatures or shape definitions stale.\n- Using `session.client(\"sagemaker\")` without an explicit annotation and then assuming the editor will infer the precise client type.\n- Treating successful type checking as proof that the request is valid for the target account or region.\n- Importing stub modules at runtime in environments where the stubs are installed only as development dependencies.\n- Assuming older blog posts match current generated waiter names or paginator names. Re-check against the current docs when copying examples.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.66`.\n- The official PyPI release page for `mypy-boto3-sagemaker 1.42.66` shows a release date of `2026-03-11`.\n- The official `boto3-stubs` package page also lists `1.42.66` as current and describes the standalone service packages as equivalent to service extras on `boto3-stubs`.\n- The generated docs are tied closely to `boto3` service definitions. If your project pins an older `boto3`, pin the matching `mypy-boto3-sagemaker` version too.\n- The upstream docs also note that `boto3-stubs-lite` does not provide the same `session.client(...)` and `session.resource(...)` overloads, so explicit annotations matter even more if you use the lite variant elsewhere in the family.\n\n## Official Sources\n\n- PyPI release page: https://pypi.org/project/mypy-boto3-sagemaker/1.42.66/\n- Package docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sagemaker/\n- SageMaker client reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sagemaker/client/\n- SageMaker examples: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sagemaker/client/#usage-examples\n- boto3-stubs package page: https://pypi.org/project/boto3-stubs/1.42.66/\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-scheduler/python/DOC.md",
    "content": "---\nname: mypy-boto3-scheduler\ndescription: \"Typed stubs for the boto3 EventBridge Scheduler client, paginators, literals, and request/response shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,scheduler,eventbridge,boto3,typing,stubs,mypy,python\"\n---\n\n# mypy-boto3-scheduler Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-scheduler` is a typing package for the boto3 EventBridge Scheduler client. It does not replace `boto3`, it does not make AWS calls on its own, and it does not configure AWS credentials or regions for you.\n\nUse it when you want:\n\n- typed `boto3.client(\"scheduler\")` calls\n- typed paginator objects for listing schedules and schedule groups\n- generated `TypedDict` request and response shapes\n- literal types for constrained Scheduler string values\n\nKeep runtime and typing separate:\n\n- install `boto3` for runtime AWS calls\n- install `mypy-boto3-scheduler` or `boto3-stubs[scheduler]` for type checking and editor support\n- configure credentials, region, retries, and endpoints through boto3 and botocore\n\n## Install\n\nInstall the standalone service stubs when you only need EventBridge Scheduler typing:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-scheduler==1.42.3\"\n```\n\nUpstream also publishes the aggregated extras:\n\n```bash\npython -m pip install \"boto3-stubs[scheduler]\"\npython -m pip install \"boto3-stubs-lite[scheduler]\"\n```\n\nUse `boto3-stubs[scheduler]` when you want the maintainer's standard install flow and better overload-based inference. Use `boto3-stubs-lite[scheduler]` when you want a lighter install and are comfortable adding more explicit annotations.\n\nPyPI lists `Requires: Python >=3.9` for this package.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-scheduler` has no package-specific initialization. All runtime behavior still comes from `boto3`.\n\nSet AWS credentials and a region through the normal boto3 sources, for example:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr use a named profile:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup:\n\n```python\nimport boto3\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\nscheduler: EventBridgeSchedulerClient = session.client(\"scheduler\")\n```\n\nIf the stub package is dev-only, keep the import behind `TYPE_CHECKING` and cast the client:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nscheduler = cast(\n    \"EventBridgeSchedulerClient\",\n    boto3.client(\"scheduler\", region_name=\"us-east-1\"),\n)\n```\n\nFor retries and other client options, use normal botocore config:\n\n```python\nimport boto3\nfrom botocore.config import Config\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n)\n\nscheduler: EventBridgeSchedulerClient = boto3.client(\"scheduler\", config=config)\n```\n\n## Core Usage\n\n### Create a one-time schedule\n\nAWS Scheduler `create_schedule` requires `Name`, `ScheduleExpression`, `FlexibleTimeWindow`, and `Target`.\n\nFor Lambda, Step Functions, and EventBridge targets, AWS says `Target.Input` must be a well-formed JSON string.\n\n```python\nimport json\n\nimport boto3\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nsession = boto3.Session(region_name=\"us-east-1\")\nscheduler: EventBridgeSchedulerClient = session.client(\"scheduler\")\n\nscheduler.create_schedule(\n    Name=\"nightly-report-once\",\n    ScheduleExpression=\"at(2026-03-14T02:00:00)\",\n    ScheduleExpressionTimezone=\"UTC\",\n    FlexibleTimeWindow={\"Mode\": \"OFF\"},\n    Target={\n        \"Arn\": \"arn:aws:lambda:us-east-1:123456789012:function:nightly-report\",\n        \"RoleArn\": \"arn:aws:iam::123456789012:role/scheduler-invoke-lambda\",\n        \"Input\": json.dumps({\"report_date\": \"2026-03-13\"}),\n    },\n    ActionAfterCompletion=\"DELETE\",\n)\n```\n\nIf you omit `ClientToken`, boto3 auto-generates it for idempotency.\n\n### Create a recurring schedule group and schedule\n\nSchedule groups help you organize schedules and scope list operations.\n\n```python\nimport json\n\nimport boto3\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nscheduler: EventBridgeSchedulerClient = boto3.client(\"scheduler\", region_name=\"us-east-1\")\n\nscheduler.create_schedule_group(\n    Name=\"payments-jobs\",\n    Tags=[{\"Key\": \"env\", \"Value\": \"prod\"}],\n)\n\nscheduler.create_schedule(\n    Name=\"payments-reconcile-hourly\",\n    GroupName=\"payments-jobs\",\n    ScheduleExpression=\"rate(1 hour)\",\n    FlexibleTimeWindow={\"Mode\": \"FLEXIBLE\", \"MaximumWindowInMinutes\": 10},\n    Target={\n        \"Arn\": \"arn:aws:states:us-east-1:123456789012:stateMachine:reconcile-payments\",\n        \"RoleArn\": \"arn:aws:iam::123456789012:role/scheduler-start-stepfunctions\",\n        \"Input\": json.dumps({\"job\": \"reconcile\"}),\n    },\n    State=\"ENABLED\",\n)\n```\n\nAWS Scheduler also supports cron expressions through the same `ScheduleExpression` field.\n\n### Read a schedule before updating it\n\nAWS documents that `update_schedule` uses the values in your request, including empty values, and overrides the existing schedule. The safe pattern is to fetch the current schedule first and then resend the fields you want to preserve.\n\n```python\nimport boto3\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\n\nscheduler: EventBridgeSchedulerClient = boto3.client(\"scheduler\", region_name=\"us-east-1\")\n\ncurrent = scheduler.get_schedule(\n    Name=\"payments-reconcile-hourly\",\n    GroupName=\"payments-jobs\",\n)\n\nscheduler.update_schedule(\n    Name=current[\"Name\"],\n    GroupName=current[\"GroupName\"],\n    ScheduleExpression=\"rate(30 minutes)\",\n    FlexibleTimeWindow=current[\"FlexibleTimeWindow\"],\n    Target=current[\"Target\"],\n    State=current[\"State\"],\n    Description=current.get(\"Description\"),\n    KmsKeyArn=current.get(\"KmsKeyArn\"),\n    ScheduleExpressionTimezone=current.get(\"ScheduleExpressionTimezone\"),\n    StartDate=current.get(\"StartDate\"),\n    EndDate=current.get(\"EndDate\"),\n    ActionAfterCompletion=current.get(\"ActionAfterCompletion\"),\n)\n```\n\n### Use typed paginators\n\nThe maintainer docs publish paginator types for `list_schedule_groups` and `list_schedules`.\n\n```python\nimport boto3\nfrom mypy_boto3_scheduler import EventBridgeSchedulerClient\nfrom mypy_boto3_scheduler.paginator import ListSchedulesPaginator\n\nscheduler: EventBridgeSchedulerClient = boto3.client(\"scheduler\", region_name=\"us-east-1\")\n\npaginator: ListSchedulesPaginator = scheduler.get_paginator(\"list_schedules\")\n\nfor page in paginator.paginate(GroupName=\"payments-jobs\", State=\"ENABLED\"):\n    for schedule in page.get(\"Schedules\", []):\n        print(schedule[\"Name\"], schedule[\"Arn\"])\n```\n\n### Use generated literals and type definitions\n\nThe package exposes literal unions and generated type definitions when you want stricter annotations than raw dicts.\n\n```python\nfrom mypy_boto3_scheduler.literals import ActionAfterCompletionType, FlexibleTimeWindowModeType\n\naction: ActionAfterCompletionType = \"DELETE\"\nwindow_mode: FlexibleTimeWindowModeType = \"OFF\"\n```\n\nUse the `type_defs` module when you need exact request or response shape annotations in helper functions or shared library code.\n\n## Common Pitfalls\n\n- `mypy-boto3-scheduler` is typing-only. Without `boto3`, your code can type-check but cannot call AWS.\n- The names differ: install `mypy-boto3-scheduler`, import `mypy_boto3_scheduler`, and create the runtime client with service name `\"scheduler\"`.\n- `Target.Input` is a JSON string for templated Lambda, Step Functions, and EventBridge targets. Do not pass a raw Python dict.\n- `update_schedule` is easy to misuse because omitted optional fields are not preserved automatically. Read the existing schedule first if you are making a partial change.\n- `boto3-stubs-lite[scheduler]` usually needs more explicit annotations because the lite package does not provide the same `session.client(...)` overloads.\n- Type safety does not validate IAM permissions, target ARNs, schedule expressions, or region configuration. Runtime AWS errors still come from your boto3 setup.\n\n## Version-Sensitive Notes\n\n- The version used here is `1.42.3`, which matches the current PyPI project page for `mypy-boto3-scheduler`.\n- PyPI shows `mypy-boto3-scheduler 1.42.3` was published on December 4, 2025.\n- The hosted maintainer docs are generated and can move ahead of the standalone wheel version on PyPI. When exact typing alignment matters, pin `boto3`, `botocore`, and `mypy-boto3-scheduler` together in the same environment.\n- The package page links to `types-boto3` as the current repository. This entry stays focused on the published `mypy-boto3-scheduler` package and its `mypy_boto3_scheduler` import surface.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_scheduler/\n- Maintainer package page: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_scheduler/\n- Maintainer paginator reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_scheduler/paginators/\n- PyPI package page: https://pypi.org/project/mypy-boto3-scheduler/\n- Boto3 Scheduler service reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/scheduler.html\n- Boto3 Scheduler `create_schedule` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/scheduler/client/create_schedule.html\n- Boto3 Scheduler `update_schedule` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/scheduler/client/update_schedule.html\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-secretsmanager/python/DOC.md",
    "content": "---\nname: mypy-boto3-secretsmanager\ndescription: \"mypy-boto3-secretsmanager package guide for typed boto3 Secrets Manager clients, paginators, literals, and TypedDict responses\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.8\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,secretsmanager,typing,mypy,pyright,python\"\n---\n\n# mypy-boto3-secretsmanager Python Package Guide\n\n## What It Is\n\n`mypy-boto3-secretsmanager` is a stubs-only package for `boto3` Secrets Manager clients. Use it when you want typed `client(...)` calls, paginator overloads, service literals, and `TypedDict` request and response shapes while still running the normal AWS SDK for Python at runtime.\n\nIt does not replace `boto3`, add its own authentication layer, or change Secrets Manager behavior.\n\n## Install\n\nIf you are pinning to the version used here, keep `boto3` and the stub package aligned:\n\n```bash\npython -m pip install \"boto3==1.42.8\" \"mypy-boto3-secretsmanager==1.42.8\"\n```\n\nIf you want automatic type discovery for `boto3.client(\"secretsmanager\")` and `Session.client(\"secretsmanager\")`, install the extra-based bundle instead:\n\n```bash\npython -m pip install \"boto3-stubs[secretsmanager]==1.42.8\"\n```\n\nIf editor performance matters more than overload-based auto-discovery, the maintainer docs also provide a lighter option:\n\n```bash\npython -m pip install \"boto3-stubs-lite[secretsmanager]==1.42.8\"\n```\n\nFor an exact local match without depending on the floating docs site, the maintainer recommends generating stubs locally:\n\n```bash\nuvx --with 'boto3==1.42.8' mypy-boto3-builder\n```\n\n## Setup And Auth\n\nAll configuration still comes from `boto3` and `botocore`.\n\nTypical setup:\n\n- local development: `AWS_PROFILE=dev`\n- region selection: `AWS_DEFAULT_REGION=us-east-1` or `region_name=\"us-east-1\"`\n- deployed workloads: IAM role, web identity, or other normal AWS credential sources\n\nExample:\n\n```python\nimport boto3\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\n```\n\n## Initialize A Typed Client\n\nWith the standalone service package, annotate the client explicitly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_secretsmanager import SecretsManagerClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: SecretsManagerClient = session.client(\"secretsmanager\")\n```\n\nIf you installed `boto3-stubs[secretsmanager]`, the type checker can usually infer the client type without the explicit annotation.\n\n## Core Usage\n\n### Read A Secret Value\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_secretsmanager import SecretsManagerClient\nfrom mypy_boto3_secretsmanager.type_defs import GetSecretValueResponseTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nclient: SecretsManagerClient = session.client(\"secretsmanager\")\n\nresponse: GetSecretValueResponseTypeDef = client.get_secret_value(\n    SecretId=\"my/app/config\",\n)\n\nsecret_string = response.get(\"SecretString\")\nsecret_binary = response.get(\"SecretBinary\")\n\nif secret_string is not None:\n    print(secret_string)\nelif secret_binary is not None:\n    print(secret_binary.decode(\"utf-8\"))\n```\n\nNotes:\n\n- AWS returns the `AWSCURRENT` version when you do not pass `VersionId` or `VersionStage`.\n- `SecretString` and `SecretBinary` are mutually exclusive in normal use; handle both if you are writing reusable helpers.\n\n### Write A New Secret Version\n\nUse `create_secret` for the initial secret and `put_secret_value` for later versions.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_secretsmanager import SecretsManagerClient\nfrom mypy_boto3_secretsmanager.type_defs import PutSecretValueRequestTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nclient: SecretsManagerClient = session.client(\"secretsmanager\")\n\nclient.create_secret(\n    Name=\"my/app/config\",\n    SecretString='{\"token\":\"initial\"}',\n)\n\nput_request: PutSecretValueRequestTypeDef = {\n    \"SecretId\": \"my/app/config\",\n    \"SecretString\": '{\"token\":\"rotated\"}',\n}\nclient.put_secret_value(**put_request)\n```\n\nNotes:\n\n- `put_secret_value` creates a new version; it does not mutate an existing version in place.\n- If you omit `VersionStages`, AWS moves `AWSCURRENT` to the new version automatically.\n\n### Paginate `list_secrets`\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_secretsmanager import SecretsManagerClient\nfrom mypy_boto3_secretsmanager.paginator import ListSecretsPaginator\n\nsession = Session(region_name=\"us-east-1\")\nclient: SecretsManagerClient = session.client(\"secretsmanager\")\npaginator: ListSecretsPaginator = client.get_paginator(\"list_secrets\")\n\nfor page in paginator.paginate(IncludePlannedDeletion=False):\n    for item in page.get(\"SecretList\", []):\n        print(item[\"Name\"])\n```\n\nAWS documents `ListSecrets` as eventually consistent. If you need the freshest state for one secret after a write, call `describe_secret` for that secret instead of trusting a list result immediately.\n\n## Useful Typed Imports\n\nCommon imports for this package:\n\n```python\nfrom mypy_boto3_secretsmanager import SecretsManagerClient\nfrom mypy_boto3_secretsmanager.literals import FilterNameStringTypeType\nfrom mypy_boto3_secretsmanager.paginator import ListSecretsPaginator\nfrom mypy_boto3_secretsmanager.type_defs import (\n    CreateSecretRequestTypeDef,\n    GetSecretValueResponseTypeDef,\n    PutSecretValueRequestTypeDef,\n)\n```\n\nUse `type_defs` when you want typed kwargs or typed return values in helper functions:\n\n```python\nfrom mypy_boto3_secretsmanager.type_defs import CreateSecretRequestTypeDef\n\nrequest: CreateSecretRequestTypeDef = {\n    \"Name\": \"my/app/config\",\n    \"SecretString\": '{\"token\":\"initial\"}',\n}\n```\n\n## Keep Runtime Dependencies Optional\n\nBecause this package is stubs-only, some projects keep it out of production images and import it only for type checking:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_secretsmanager import SecretsManagerClient\n\ndef get_client() -> \"SecretsManagerClient\":\n    return boto3.client(\"secretsmanager\", region_name=\"us-east-1\")\n```\n\nIf your linter complains about `TYPE_CHECKING`-only names, the maintainer docs recommend using the heavier `boto3-stubs[...]` install or falling back to a non-typing alias in runtime-only branches.\n\n## Common Pitfalls\n\n- The package name uses hyphens, but the import root is `mypy_boto3_secretsmanager`.\n- `mypy-boto3-secretsmanager` is not a runtime SDK. You still need `boto3` for actual API calls.\n- Keep `boto3`, `botocore`, and the stubs in the same release family. The maintainer states that stub versions track the related `boto3` version.\n- The docs root from PyPI is a floating latest snapshot. On 2026-03-12 it was showing generator commands for `boto3==1.42.66`, not the package version covered here `1.42.8`.\n- `boto3-stubs-lite` is more memory-friendly but does not provide the `session.client(...)` and `boto3.client(...)` overloads that many IDEs use for automatic inference.\n- `put_secret_value` creates a new secret version every time. AWS warns against calling it more often than roughly once every 10 minutes on a sustained basis because you can run into version-count limits.\n- `list_secrets` can lag recent writes for several minutes.\n- Runtime exceptions still come from `botocore` and AWS service behavior, not from this package.\n\n## Version-Sensitive Notes\n\n- This entry is intentionally pinned to `1.42.8`, the version used here and the current PyPI release dated 2025-12-11.\n- The maintainer docs URL is useful for module structure and available typed imports, but it is not version-pinned. Treat it as canonical for package layout, not as proof that every latest-page method exists in `1.42.8`.\n- If you need an exact stub surface for the installed `boto3` build, use the maintainer's local-generation workflow with `mypy-boto3-builder`.\n- AWS runtime semantics such as staging labels, KMS permissions, caching guidance, and eventual consistency come from the boto3/AWS docs, not the stub package itself.\n\n## Official Sources Used\n\n- `https://pypi.org/project/mypy-boto3-secretsmanager/`\n- `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_secretsmanager/`\n- `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_secretsmanager/client/`\n- `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_secretsmanager/type_defs/`\n- `https://docs.aws.amazon.com/boto3/latest/reference/services/secretsmanager/client/get_secret_value.html`\n- `https://docs.aws.amazon.com/boto3/latest/reference/services/secretsmanager/client/put_secret_value.html`\n- `https://docs.aws.amazon.com/boto3/latest/reference/services/secretsmanager/client/list_secrets.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-securityhub/python/DOC.md",
    "content": "---\nname: mypy-boto3-securityhub\ndescription: \"mypy-boto3-securityhub type stubs for boto3 Security Hub clients, paginators, literals, and TypedDict request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,security-hub,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-securityhub Python Package Guide\n\n## Golden Rule\n\n- `mypy-boto3-securityhub` is a typing package for `boto3`, not a runtime AWS SDK.\n- Keep `boto3` installed for real Security Hub API calls.\n- Use `boto3-stubs[securityhub]` if you want better `session.client(\"securityhub\")` inference. Use `mypy-boto3-securityhub` when you only need the standalone Security Hub stubs and are willing to add explicit annotations.\n\n## Version-Sensitive Notes\n\n- As of March 13, 2026, PyPI lists `mypy-boto3-securityhub 1.42.3` and `Requires: Python >=3.9`.\n- The maintainer docs are a rolling site. The current package page includes local-generation examples for newer `boto3` patch lines than the published `mypy-boto3-securityhub` release, so pin against the exact PyPI release you can install.\n- The maintainer versioning guide says service stub versions follow the related `boto3` version. When request and response shapes matter, pin `boto3` and `mypy-boto3-securityhub` to the same release line.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[securityhub]==1.42.3\"\n```\n\nThis is the easiest path when you want editor completion plus better type inference for `Session.client(\"securityhub\")`.\n\n### Standalone Security Hub stubs\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-securityhub==1.42.3\"\n```\n\nUse this when you only want Security Hub types and are comfortable with explicit annotations.\n\n### Lower-memory IDE fallback\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[securityhub]==1.42.3\"\n```\n\nThe lite package is easier on IDE memory but does not provide the same overload coverage for `session.client(...)`.\n\n## Runtime Setup And Auth\n\nThis package has no Security Hub-specific initialization. Authentication, profiles, regions, retries, and endpoints still come from normal `boto3` and botocore configuration.\n\nTypical local setup:\n\n```bash\naws configure --profile security-audit\nexport AWS_PROFILE=security-audit\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr set credentials directly:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nCreate an explicit session when you want predictable account and region selection:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"security-audit\", region_name=\"us-east-1\")\n```\n\n## Core Usage\n\n### Typed Security Hub client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securityhub import SecurityHubClient\n\nsession = Session(profile_name=\"security-audit\", region_name=\"us-east-1\")\nsecurityhub: SecurityHubClient = session.client(\"securityhub\")\n\nhub = securityhub.describe_hub()\nprint(hub[\"HubArn\"])\n```\n\nImport from `mypy_boto3_securityhub`, but create the real client from `boto3`.\n\n### Paginate findings safely\n\n`get_findings` is the main read path for Security Hub findings. Use the generated paginator type when you expect multiple pages.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securityhub import SecurityHubClient\nfrom mypy_boto3_securityhub.paginator import GetFindingsPaginator\n\nsession = Session(profile_name=\"security-audit\", region_name=\"us-east-1\")\nsecurityhub: SecurityHubClient = session.client(\"securityhub\")\n\npaginator: GetFindingsPaginator = securityhub.get_paginator(\"get_findings\")\n\nfor page in paginator.paginate(\n    Filters={\n        \"RecordState\": [{\"Value\": \"ACTIVE\", \"Comparison\": \"EQUALS\"}],\n        \"WorkflowStatus\": [{\"Value\": \"NEW\", \"Comparison\": \"EQUALS\"}],\n    }\n):\n    for finding in page.get(\"Findings\", []):\n        print(finding[\"Id\"], finding[\"Severity\"][\"Label\"])\n```\n\n### Inspect enabled standards\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securityhub import SecurityHubClient\nfrom mypy_boto3_securityhub.paginator import GetEnabledStandardsPaginator\n\nsecurityhub: SecurityHubClient = Session(region_name=\"us-east-1\").client(\"securityhub\")\npaginator: GetEnabledStandardsPaginator = securityhub.get_paginator(\"get_enabled_standards\")\n\nfor page in paginator.paginate():\n    for subscription in page.get(\"StandardsSubscriptions\", []):\n        print(subscription[\"StandardsArn\"], subscription[\"StandardsStatus\"])\n```\n\n### Enable Security Hub explicitly\n\nIf you are bootstrapping a region, the typed client exposes the normal boto3 operation:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securityhub import SecurityHubClient\n\nsecurityhub: SecurityHubClient = Session(region_name=\"us-east-1\").client(\"securityhub\")\n\nsecurityhub.enable_security_hub(\n    EnableDefaultStandards=False,\n    ControlFindingGenerator=\"SECURITY_CONTROL\",\n)\n```\n\n## Type Surfaces That Matter\n\nThe generated package exposes the modules you usually need for static analysis:\n\n- `mypy_boto3_securityhub` for `SecurityHubClient`\n- `mypy_boto3_securityhub.paginator` for paginator classes such as `GetFindingsPaginator`\n- `mypy_boto3_securityhub.literals` for enum-like string types\n- `mypy_boto3_securityhub.type_defs` for request and response `TypedDict` definitions\n\nUse `literals` when you want the type checker to reject invalid string constants, and use `type_defs` when helpers build request payloads before the final client call.\n\n## Keep Stubs Out Of Production Images\n\nIf the stubs are a development-only dependency, gate the type imports with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_securityhub import SecurityHubClient\n\ndef make_client() -> \"SecurityHubClient\":\n    return Session(region_name=\"us-east-1\").client(\"securityhub\")\n```\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-securityhub` without `boto3`. The stub package does not make AWS calls by itself.\n- Expecting standalone stubs to infer `session.client(\"securityhub\")` automatically. That behavior is better with `boto3-stubs[securityhub]`.\n- Importing `mypy-boto3-securityhub` with hyphens. The Python import path is `mypy_boto3_securityhub`.\n- Treating successful type checks as proof that your AWS profile, region, or IAM permissions are correct.\n- Copying the patch version shown in the rolling docs site without checking the exact PyPI release page first.\n- Forgetting that Security Hub is regional. Use an explicit session or `AWS_DEFAULT_REGION` so your findings queries hit the expected region.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_securityhub/\n- Maintainer versioning guide: https://youtype.github.io/boto3_stubs_docs/#versioning\n- PyPI package page: https://pypi.org/project/mypy-boto3-securityhub/\n- Exact PyPI release page: https://pypi.org/project/mypy-boto3-securityhub/1.42.3/\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 configuration guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html\n- SecurityHub client docs: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub.html\n- `describe_hub`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub/client/describe_hub.html\n- `get_findings`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub/client/get_findings.html\n- `get_enabled_standards`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub/client/get_enabled_standards.html\n- `enable_security_hub`: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub/client/enable_security_hub.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-securitylake/python/DOC.md",
    "content": "---\nname: mypy-boto3-securitylake\ndescription: \"mypy-boto3-securitylake package guide for typed boto3 Security Lake clients, paginators, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,securitylake,boto3,mypy-boto3-securitylake,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-securitylake Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS calls and use `mypy-boto3-securitylake` only for typing.\n\nIf you want `Session().client(\"securitylake\")` to infer types in editors and type checkers, install `boto3-stubs[securitylake]`. If you install `mypy-boto3-securitylake` or `boto3-stubs-lite[securitylake]`, expect to add explicit annotations for the client and paginators.\n\n## Install\n\n### Recommended for normal boto3 code\n\nInstall the runtime SDK and the Security Lake stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[securitylake]==1.42.3\"\n```\n\nThis is the best default when you want `boto3` runtime behavior plus editor and type-checker support without extra casts in most code.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[securitylake]==1.42.3\"\n```\n\nThe maintainer docs say the lite variant does not provide `session.client()` and `session.resource()` overloads, so explicit annotations become the normal workflow.\n\n### Standalone package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-securitylake==1.42.3\"\n```\n\nUse this when you only want the Security Lake typing package or when you prefer `TYPE_CHECKING` imports.\n\n## Prerequisites And AWS Setup\n\nThis package does not handle authentication, regions, retries, or endpoints. Those still come from `boto3` and normal AWS configuration.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=security-dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n`boto3` looks for credentials through its normal provider chain, including explicit client or session parameters, environment variables, IAM Identity Center, `~/.aws/credentials`, `~/.aws/config`, container credentials, and EC2 instance metadata.\n\nWhen you need client-specific behavior, pass a `botocore.config.Config` object. AWS documents that a `Config` object takes precedence over environment variables and config-file values for settings such as `region_name` and retries.\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\n\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"max_attempts\": 10, \"mode\": \"standard\"},\n)\n\nsession = Session(profile_name=\"security-dev\")\nsecuritylake = session.client(\"securitylake\", config=config)\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[securitylake]`\n\nWith the full service extra installed, ordinary `boto3` code should type-check without manual annotations:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"security-dev\", region_name=\"us-east-1\")\nclient = session.client(\"securitylake\")\n\nresponse = client.list_subscribers(maxResults=20)\n\nfor subscriber in response.get(\"subscribers\", []):\n    print(subscriber[\"subscriberName\"], subscriber[\"subscriberStatus\"])\n```\n\n`list_subscribers` is a real Security Lake client method documented by boto3. It is a good low-friction call for confirming your typing and region setup.\n\n### Explicit client annotation\n\nUse explicit annotations when you installed the standalone package or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securitylake import SecurityLakeClient\n\nsession = Session(profile_name=\"security-dev\", region_name=\"us-east-1\")\nclient: SecurityLakeClient = session.client(\"securitylake\")\n\nresponse = client.list_data_lakes(regions=[\"us-east-1\"])\n\nfor data_lake in response.get(\"dataLakes\", []):\n    print(data_lake[\"region\"], data_lake[\"createStatus\"])\n```\n\n### Typed paginator usage\n\nThe generated paginator module exposes typed paginator classes for:\n\n- `get_data_lake_sources`\n- `list_data_lake_exceptions`\n- `list_log_sources`\n- `list_subscribers`\n\nExample:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_securitylake import SecurityLakeClient\nfrom mypy_boto3_securitylake.paginator import ListSubscribersPaginator\n\nsession = Session(profile_name=\"security-dev\", region_name=\"us-east-1\")\nclient: SecurityLakeClient = session.client(\"securitylake\")\nsubscribers: ListSubscribersPaginator = client.get_paginator(\"list_subscribers\")\n\nfor page in subscribers.paginate():\n    for subscriber in page.get(\"subscribers\", []):\n        print(subscriber[\"subscriberArn\"])\n```\n\n### Typed request and response helpers\n\nUse `type_defs` when request fragments or nested response shapes need to stay typed:\n\n```python\nfrom mypy_boto3_securitylake.type_defs import AwsIdentityTypeDef\n\nsubscriber_identity: AwsIdentityTypeDef = {\n    \"externalId\": \"external-id-for-cross-account-access\",\n}\n```\n\nUse generated literals when you want the type checker to reject misspelled enum-like strings:\n\n```python\nfrom mypy_boto3_securitylake.literals import AccessTypeType\n\ndef normalize_access_type(value: AccessTypeType) -> AccessTypeType:\n    return value\n```\n\n## `TYPE_CHECKING` Pattern\n\nThe maintainer docs explicitly recommend `TYPE_CHECKING` if you do not want to ship stub packages in production. They also note that `pylint` can complain unless you provide an `object` fallback.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_securitylake import SecurityLakeClient\nelse:\n    SecurityLakeClient = object\n\nsession = Session(profile_name=\"security-dev\", region_name=\"us-east-1\")\nclient: \"SecurityLakeClient\" = session.client(\"securitylake\")\n```\n\n## Common Pitfalls\n\n- `mypy-boto3-securitylake` is stub-only. It does not create a Security Lake client and it does not replace `boto3`.\n- Keep the runtime SDK and stubs on the same release line. The maintainer docs say `mypy-boto3-securitylake` uses the same version as the related `boto3` release.\n- `boto3-stubs[securitylake]` and `boto3-stubs-lite[securitylake]` are not equivalent. The lite package is more memory-friendly, but the maintainer docs say it does not provide `session.client/resource` overloads.\n- Static typing does not validate AWS credentials, IAM permissions, region selection, or whether Security Lake is enabled in the target Region.\n- Import names use underscores, not hyphens: install `mypy-boto3-securitylake`, import `mypy_boto3_securitylake`.\n- If PyCharm becomes slow with these generated literals and overloads, the maintainer docs recommend trying `boto3-stubs-lite`.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI shows `mypy-boto3-securitylake 1.42.3` as the latest release as of March 13, 2026, released on December 4, 2025.\n- PyPI lists `Requires: Python >=3.9`.\n- The package description says it provides type annotations for `boto3 SecurityLake 1.42.3`.\n- The package page says `mypy-boto3-securitylake` version matches the related `boto3` version, so pinning both to `1.42.3` is the safest default.\n- The hosted documentation is a generated site, not a versioned snapshot. Re-check the live docs before moving to a newer release line.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_securitylake/\n- boto3-stubs docs root: https://youtype.github.io/boto3_stubs_docs/\n- PyPI package page: https://pypi.org/project/mypy-boto3-securitylake/\n- boto3 Security Lake service reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securitylake.html\n- boto3 `list_subscribers` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securitylake/client/list_subscribers.html\n- boto3 `list_data_lakes` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securitylake/client/list_data_lakes.html\n- boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-servicediscovery/python/DOC.md",
    "content": "---\nname: mypy-boto3-servicediscovery\ndescription: \"Type stubs for boto3 AWS Cloud Map (ServiceDiscovery) clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,cloud-map,servicediscovery,boto3,mypy,pyright,type-stubs,python\"\n---\n\n# `mypy-boto3-servicediscovery` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-servicediscovery` adds type information for the `boto3` `servicediscovery` client used by AWS Cloud Map. It is not a runtime SDK, it does not create AWS sessions for you, and it does not manage credentials, regions, or retries. Use `boto3` for real API calls and use this package for editor completion and static checking.\n\nIf you want `Session().client(\"servicediscovery\")` to infer automatically, install `boto3-stubs[servicediscovery]`. If you install only the standalone or lite package, annotate `ServiceDiscoveryClient` explicitly.\n\n## Install\n\nChoose one install mode based on how much typing support you want.\n\n### Best inference: full boto3 stubs\n\n```bash\npython -m pip install \"boto3\" \"boto3-stubs[servicediscovery]==1.42.3\"\n```\n\nUse this when you want overloads for `session.client(\"servicediscovery\")` and typed paginator discovery.\n\n### Standalone service package\n\n```bash\npython -m pip install \"boto3\" \"mypy-boto3-servicediscovery==1.42.3\"\n```\n\nUse this when you only want the Cloud Map typing package and are willing to annotate the client yourself.\n\n### Lower-memory lite package\n\n```bash\npython -m pip install \"boto3\" \"boto3-stubs-lite[servicediscovery]==1.42.3\"\n```\n\nThe maintainer docs note that lite builds do not provide `session.client()` or `session.resource()` overloads, so explicit annotations are more important.\n\n## Runtime Setup And Auth\n\nThis package has no package-specific initialization. Runtime setup is normal `boto3` setup.\n\nTypical environment variables:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nOr use direct credentials:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create the real client through `boto3` and annotate it:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery import ServiceDiscoveryClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nservicediscovery: ServiceDiscoveryClient = session.client(\"servicediscovery\")\n```\n\nThe boto3 credentials guide is the source of truth for the provider chain. The stubs only describe types.\n\n## Core Usage\n\n### Typed client for AWS Cloud Map calls\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\n\nclient: ServiceDiscoveryClient = Session(\n    profile_name=\"dev\",\n    region_name=\"us-east-1\",\n).client(\"servicediscovery\")\n\nnamespace = client.get_namespace(Id=\"ns-abc1234567890\")\nprint(namespace[\"Namespace\"][\"Name\"])\n```\n\nUse the boto3 service name `servicediscovery`, not the package name, when creating the client.\n\n### Discover instances with typed request and response shapes\n\n`discover_instances` is the main runtime lookup API for Cloud Map. AWS documents that this call uses `NamespaceName` and `ServiceName`, not namespace or service IDs.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\nfrom mypy_boto3_servicediscovery.literals import HealthStatusFilterType\nfrom mypy_boto3_servicediscovery.type_defs import (\n    DiscoverInstancesRequestTypeDef,\n    DiscoverInstancesResponseTypeDef,\n)\n\nclient: ServiceDiscoveryClient = Session(region_name=\"us-east-1\").client(\n    \"servicediscovery\"\n)\n\nhealth_filter: HealthStatusFilterType = \"HEALTHY_OR_ELSE_ALL\"\n\nrequest: DiscoverInstancesRequestTypeDef = {\n    \"NamespaceName\": \"example.internal\",\n    \"ServiceName\": \"orders\",\n    \"HealthStatus\": health_filter,\n    \"QueryParameters\": {\"stage\": \"prod\"},\n}\n\nresponse: DiscoverInstancesResponseTypeDef = client.discover_instances(**request)\n\nfor instance in response.get(\"Instances\", []):\n    attrs = instance.get(\"Attributes\", {})\n    print(attrs.get(\"AWS_INSTANCE_IPV4\"), attrs.get(\"AWS_INSTANCE_PORT\"))\n\nprint(response.get(\"InstancesRevision\"))\n```\n\n### List services with a typed paginator\n\nThe generated stubs include paginator annotations for Service Discovery list operations.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\nfrom mypy_boto3_servicediscovery.paginator import ListServicesPaginator\n\nclient: ServiceDiscoveryClient = Session(region_name=\"us-east-1\").client(\n    \"servicediscovery\"\n)\n\npaginator: ListServicesPaginator = client.get_paginator(\"list_services\")\n\nfor page in paginator.paginate():\n    for service in page.get(\"Services\", []):\n        print(service[\"Name\"], service[\"Id\"])\n```\n\n### Create a namespace and service\n\nCloud Map create operations are asynchronous. The boto3 APIs return an `OperationId`; poll `get_operation` before assuming the namespace or service is ready for later steps.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\nfrom mypy_boto3_servicediscovery.type_defs import CreateHttpNamespaceRequestTypeDef\n\nclient: ServiceDiscoveryClient = Session(region_name=\"us-east-1\").client(\n    \"servicediscovery\"\n)\n\nnamespace_request: CreateHttpNamespaceRequestTypeDef = {\n    \"Name\": \"example.internal\",\n    \"CreatorRequestId\": \"example-internal-namespace-001\",\n    \"Description\": \"HTTP namespace for internal service discovery\",\n}\n\nnamespace_response = client.create_http_namespace(**namespace_request)\nprint(namespace_response[\"OperationId\"])\n\nservice_response = client.create_service(\n    Name=\"orders\",\n    NamespaceId=\"ns-abc1234567890\",\n    Type=\"HTTP\",\n)\nprint(service_response[\"Service\"][\"Id\"])\n```\n\nIf you are creating DNS-backed services instead of HTTP services, AWS documents `DnsConfig` on `create_service` and service-specific registration attributes such as `AWS_INSTANCE_IPV4` and `AWS_INSTANCE_PORT` on `register_instance`.\n\n### Register an instance with typed Cloud Map attributes\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\nfrom mypy_boto3_servicediscovery.type_defs import RegisterInstanceRequestTypeDef\n\nclient: ServiceDiscoveryClient = Session(region_name=\"us-east-1\").client(\n    \"servicediscovery\"\n)\n\nrequest: RegisterInstanceRequestTypeDef = {\n    \"ServiceId\": \"srv-p5zdwlg5uvvzjita\",\n    \"InstanceId\": \"orders-01\",\n    \"Attributes\": {\n        \"AWS_INSTANCE_IPV4\": \"10.0.2.15\",\n        \"AWS_INSTANCE_PORT\": \"8080\",\n    },\n    \"CreatorRequestId\": \"orders-01-register-001\",\n}\n\nresponse = client.register_instance(**request)\nprint(response[\"OperationId\"])\n```\n\n### Use `TYPE_CHECKING` when stubs are not installed in production\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_servicediscovery.client import ServiceDiscoveryClient\n\nclient: \"ServiceDiscoveryClient\" = boto3.Session(\n    region_name=\"us-east-1\"\n).client(\"servicediscovery\")\n```\n\nThis keeps the type information available to mypy and pyright without making the stub package a required runtime dependency.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_servicediscovery`.\n- This package does not install a working AWS client by itself. Keep `boto3` in the environment for runtime calls.\n- Automatic `session.client(\"servicediscovery\")` inference comes from `boto3-stubs[servicediscovery]`, not from standalone `mypy-boto3-servicediscovery` or `boto3-stubs-lite[servicediscovery]`.\n- `discover_instances` uses namespace and service names. If you pass IDs where names are expected, your request shape may still type-check but the API call will be wrong.\n- Cloud Map create and register APIs are asynchronous. A successful `create_http_namespace`, `create_service`, or `register_instance` call usually means \"operation accepted\", not \"ready for immediate discovery\".\n- For DNS-based services, the attributes passed to `register_instance` must match the service configuration. AWS documents keys such as `AWS_INSTANCE_IPV4`, `AWS_INSTANCE_IPV6`, `AWS_INSTANCE_PORT`, and `AWS_ALIAS_DNS_NAME` for specific DNS record scenarios.\n- The Service Discovery boto3 reference documents paginators, but do not assume waiter support unless your pinned boto3 build actually exposes a named waiter for the operation you want.\n- `create_service` has important DNS constraints. AWS documents that some DNS record type changes require deleting and recreating the service instead of editing it in place.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-servicediscovery 1.42.3` and requires Python `>=3.9`.\n- The maintainer docs state that the package version matches the related `boto3` version. Keep the stubs and your runtime boto3 line aligned when exact request and response shapes matter.\n- The maintainer docs site is generated documentation, not a release-pinned snapshot. Use the docs for API shape discovery, but pin install commands from the exact PyPI release you intend to use.\n- The maintainer also documents local generation with `mypy-boto3-builder` when you need stubs that exactly match a locked boto3 version or a custom environment.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_servicediscovery/\n- Client reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_servicediscovery/client/\n- Paginators reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_servicediscovery/paginators/\n- Type definitions reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_servicediscovery/type_defs/\n- Literals reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_servicediscovery/literals/\n- Versioning guide: https://youtype.github.io/boto3_stubs_docs/#versioning\n- PyPI package page: https://pypi.org/project/mypy-boto3-servicediscovery/\n- Exact PyPI release: https://pypi.org/project/mypy-boto3-servicediscovery/1.42.3/\n- Boto3 Service Discovery reference: https://docs.aws.amazon.com/boto3/latest/reference/services/servicediscovery.html\n- `discover_instances` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/servicediscovery/client/discover_instances.html\n- `create_service` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/servicediscovery/client/create_service.html\n- `create_http_namespace` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/servicediscovery/client/create_http_namespace.html\n- `register_instance` reference: https://docs.aws.amazon.com/boto3/latest/reference/services/servicediscovery/client/register_instance.html\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ses/python/DOC.md",
    "content": "---\nname: mypy-boto3-ses\ndescription: \"Typed boto3 stubs for Amazon SES clients, paginators, waiters, literals, and TypedDict request shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,ses,typing,mypy,pyright,stub\"\n---\n\n# mypy-boto3-ses Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-ses` only for static typing around `boto3.client(\"ses\")`.\n\n- Keep `boto3` installed for runtime behavior, credentials, retries, and request execution.\n- Keep the SES region explicit. Identity verification, sandbox status, and sending permissions are region-specific.\n- If you install the standalone `mypy-boto3-ses` package or `boto3-stubs-lite[ses]`, add an explicit `SESClient` annotation. Only the full `boto3-stubs[ses]` package provides the overloaded `Session.client(\"ses\")` typing automatically.\n\n## Install\n\nPick one of these typing strategies:\n\n### Full boto3 stubs\n\nRecommended when you want typed `Session.client(...)` overloads across boto3 services:\n\n```bash\npython -m pip install \"boto3-stubs[ses]\"\n```\n\n### Lite boto3 stubs\n\nUse this when the full package is too heavy for your editor or CI environment. Upstream notes that the lite package omits the overloads, so you must annotate clients explicitly:\n\n```bash\npython -m pip install \"boto3-stubs-lite[ses]\"\n```\n\n### Standalone SES stubs\n\nUse this when you only want SES typing:\n\n```bash\npython -m pip install \"mypy-boto3-ses==1.42.3\"\n```\n\nRuntime dependency:\n\n```bash\npython -m pip install \"boto3\"\n```\n\nIn real projects, keep the stub package in your dev or typing dependency group and keep `boto3` in the runtime dependency set.\n\n## Authentication And Setup\n\nThis package does not load AWS credentials or regions. `boto3` still owns that behavior through the standard AWS provider chain:\n\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n- shared config in `~/.aws/config` and `~/.aws/credentials`\n- IAM Identity Center, assume-role config, ECS task roles, or EC2 instance roles\n\nMinimal typed setup with an explicit session:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ses.client import SESClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nses: SESClient = session.client(\"ses\")\n```\n\nIf the stubs are dev-only and you do not want to import them at runtime, a `TYPE_CHECKING` gate is a practical pattern:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_ses.client import SESClient\n\nsession = Session(region_name=\"us-east-1\")\nses = cast(\"SESClient\", session.client(\"ses\"))\n```\n\n## Core Usage\n\n### Send a typed SES email request\n\nUse the generated `TypedDict` request shapes when you want the type checker to catch field-name mistakes before runtime:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ses.client import SESClient\nfrom mypy_boto3_ses.type_defs import SendEmailRequestTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nses: SESClient = session.client(\"ses\")\n\nrequest: SendEmailRequestTypeDef = {\n    \"Source\": \"noreply@example.com\",\n    \"Destination\": {\n        \"ToAddresses\": [\"ada@example.com\"],\n    },\n    \"Message\": {\n        \"Subject\": {\n            \"Data\": \"Welcome\",\n            \"Charset\": \"UTF-8\",\n        },\n        \"Body\": {\n            \"Text\": {\n                \"Data\": \"Your account is ready.\",\n                \"Charset\": \"UTF-8\",\n            }\n        },\n    },\n}\n\nresponse = ses.send_email(**request)\nprint(response[\"MessageId\"])\n```\n\nThis package improves static checking only. SES will still reject the call at runtime if the sender identity is not verified in the configured region or the account is still in the SES sandbox.\n\n### Use typed paginators\n\n`mypy-boto3-ses` includes paginator classes for paginator-enabled SES operations:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ses.client import SESClient\nfrom mypy_boto3_ses.paginator import ListIdentitiesPaginator\n\nsession = Session(region_name=\"us-east-1\")\nses: SESClient = session.client(\"ses\")\n\npaginator: ListIdentitiesPaginator = ses.get_paginator(\"list_identities\")\n\nfor page in paginator.paginate(IdentityType=\"EmailAddress\"):\n    for identity in page.get(\"Identities\", []):\n        print(identity)\n```\n\n### Use typed waiters\n\nThe package also exposes SES waiter types, which is safer than inventing sleep loops when the service model already defines the waiter:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ses.client import SESClient\nfrom mypy_boto3_ses.waiter import IdentityExistsWaiter\n\nsession = Session(region_name=\"us-east-1\")\nses: SESClient = session.client(\"ses\")\n\nwaiter: IdentityExistsWaiter = ses.get_waiter(\"identity_exists\")\nwaiter.wait(Identities=[\"noreply@example.com\"])\n```\n\n## Configuration Notes\n\n- This package types the classic SES client from `boto3.client(\"ses\")`, not `boto3.client(\"sesv2\")`. If your code uses the newer SES v2 API surface, use the matching `mypy-boto3-sesv2` stubs instead.\n- The generated stubs include literals, paginators, waiters, and `type_defs` modules. They are useful for editor completion and mypy or pyright validation, but they do not change boto3 runtime semantics.\n- The package docs are client-focused. There is no documented `SESServiceResource` surface in the package docs, so treat this package as a typed client companion rather than a resource-layer guide.\n\n## Common Pitfalls\n\n- Do not replace `boto3` with `mypy-boto3-ses`; the stub package is not a runtime AWS SDK.\n- Do not expect client inference from `session.client(\"ses\")` unless you installed full `boto3-stubs[ses]`. The standalone and lite variants need explicit annotations.\n- Do not assume the stub package will always publish every boto3 patch. Upstream says the version matches the related boto3 version, but the standalone service package can lag the latest boto3 patch line in practice.\n- Do not point this package at SES v2 code. `ses` and `sesv2` are different boto3 service names and have different generated stubs.\n- Do not forget that SES account state is regional. A verified identity or production-access status in one region does not automatically carry over to another.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI lists `mypy-boto3-ses 1.42.3` as the current published version checked on 2026-03-12.\n- PyPI marks the package as typed stubs and requires Python `>=3.9`.\n- The maintainer docs for this package describe three install paths: `boto3-stubs`, `boto3-stubs-lite`, and the standalone `mypy-boto3-ses` package. Choose based on whether you want automatic overloaded client typing or a smaller type-only install.\n- The docs site is a rolling generated reference, so use PyPI for exact package pinning and the maintainer docs for the available typed surfaces and import paths.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ses/\n- Maintainer client reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ses/client/\n- PyPI package page: https://pypi.org/project/mypy-boto3-ses/\n- boto3 SES reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses.html\n- boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Source repository: https://github.com/youtype/boto3-stubs\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sesv2/python/DOC.md",
    "content": "---\nname: mypy-boto3-sesv2\ndescription: \"Typed boto3 stubs for Amazon SES v2 clients, paginators, literals, and TypedDict request shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,sesv2,boto3,typing,mypy,pyright,stub\"\n---\n\n# mypy-boto3-sesv2 Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-sesv2` only for static typing around `boto3.client(\"sesv2\")`.\n\n- Keep `boto3` installed for runtime behavior, retries, credentials, and request execution.\n- Use the SES v2 service name: `sesv2`. This package does not type `boto3.client(\"ses\")`.\n- If you install the standalone `mypy-boto3-sesv2` package or `boto3-stubs-lite[sesv2]`, add an explicit `SESV2Client` annotation. The full `boto3-stubs[sesv2]` package is the path that documents overloaded `Session.client(\"sesv2\")` typing.\n\n## Install\n\nPick one of these typing strategies:\n\n### Full boto3 stubs\n\nUse this when you want the best autocomplete and typed `Session.client(...)` overloads:\n\n```bash\npython -m pip install \"boto3-stubs[sesv2]\"\n```\n\n### Lite boto3 stubs\n\nUse this when editor memory use matters more than automatic overload inference:\n\n```bash\npython -m pip install \"boto3-stubs-lite[sesv2]\"\n```\n\n### Standalone SES v2 stubs\n\nUse this when you only want the SES v2 typing package:\n\n```bash\npython -m pip install \"mypy-boto3-sesv2==1.42.13\"\n```\n\nRuntime dependency:\n\n```bash\npython -m pip install \"boto3\"\n```\n\nPyPI currently lists `mypy-boto3-sesv2 1.42.13` and requires Python `>=3.9`.\n\n## Authentication And Setup\n\nThis package does not read AWS credentials or region settings. `boto3` still uses the normal AWS provider chain and config sources.\n\nCommon environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nYou can also use shared AWS config files, IAM Identity Center, assume-role profiles, ECS task roles, or EC2 instance roles.\n\nMinimal typed setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sesv2.client import SESV2Client\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsesv2: SESV2Client = session.client(\"sesv2\")\n```\n\nIf the stubs are dev-only, keep the imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING, cast\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sesv2.client import SESV2Client\n\nsession = Session(region_name=\"us-east-1\")\nsesv2 = cast(\"SESV2Client\", session.client(\"sesv2\"))\n```\n\n## Core Usage\n\n### Send a typed email request\n\nUse the generated `TypedDict` request shape when you want the type checker to catch misspelled request keys before runtime:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sesv2.client import SESV2Client\nfrom mypy_boto3_sesv2.type_defs import SendEmailRequestRequestTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nsesv2: SESV2Client = session.client(\"sesv2\")\n\nrequest: SendEmailRequestRequestTypeDef = {\n    \"FromEmailAddress\": \"noreply@example.com\",\n    \"Destination\": {\n        \"ToAddresses\": [\"ada@example.com\"],\n    },\n    \"Content\": {\n        \"Simple\": {\n            \"Subject\": {\n                \"Data\": \"Welcome\",\n                \"Charset\": \"UTF-8\",\n            },\n            \"Body\": {\n                \"Text\": {\n                    \"Data\": \"Your account is ready.\",\n                    \"Charset\": \"UTF-8\",\n                }\n            },\n        }\n    },\n}\n\nresponse = sesv2.send_email(**request)\nprint(response[\"MessageId\"])\n```\n\nThe typing is local only. SES still validates the sender identity, region, account status, and IAM permissions at runtime.\n\n### List email identities with explicit pagination\n\nThe maintainer docs do not list `list_email_identities` as a paginator-enabled operation, so use `NextToken` directly:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sesv2.client import SESV2Client\nfrom mypy_boto3_sesv2.type_defs import (\n    ListEmailIdentitiesRequestTypeDef,\n    ListEmailIdentitiesResponseTypeDef,\n)\n\nsession = Session(region_name=\"us-east-1\")\nsesv2: SESV2Client = session.client(\"sesv2\")\n\nrequest: ListEmailIdentitiesRequestTypeDef = {\"PageSize\": 100}\n\nwhile True:\n    response: ListEmailIdentitiesResponseTypeDef = sesv2.list_email_identities(**request)\n\n    for identity in response.get(\"EmailIdentities\", []):\n        print(identity[\"IdentityName\"], identity[\"VerificationStatus\"])\n\n    next_token = response.get(\"NextToken\")\n    if not next_token:\n        break\n\n    request[\"NextToken\"] = next_token\n```\n\n### Use a documented paginator\n\nThe generated stubs include paginator types for a small set of SES v2 list operations, including `list_email_templates`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sesv2.client import SESV2Client\nfrom mypy_boto3_sesv2.paginator import ListEmailTemplatesPaginator\n\nsession = Session(region_name=\"us-east-1\")\nsesv2: SESV2Client = session.client(\"sesv2\")\n\npaginator: ListEmailTemplatesPaginator = sesv2.get_paginator(\"list_email_templates\")\n\nfor page in paginator.paginate(PageSize=20):\n    for template in page.get(\"TemplatesMetadata\", []):\n        print(template[\"TemplateName\"])\n```\n\n### Check identity status with typed responses\n\nUse `get_email_identity` when your code needs to inspect verification or DKIM state before sending:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sesv2.client import SESV2Client\nfrom mypy_boto3_sesv2.type_defs import GetEmailIdentityResponseTypeDef\n\nsession = Session(region_name=\"us-east-1\")\nsesv2: SESV2Client = session.client(\"sesv2\")\n\nidentity: GetEmailIdentityResponseTypeDef = sesv2.get_email_identity(\n    EmailIdentity=\"example.com\"\n)\n\nprint(identity[\"VerificationStatus\"])\nprint(identity.get(\"DkimAttributes\", {}).get(\"Status\"))\n```\n\n## Configuration Notes\n\n- This package types the SES v2 client surface only. The maintainer docs document a `client` module, `type_defs`, `literals`, and paginator types.\n- Treat this as a typed client companion, not as a replacement for `boto3`.\n- If you want automatic client overloads, prefer `boto3-stubs[sesv2]`. If you want the smallest dependency, use `mypy-boto3-sesv2` and annotate the client explicitly.\n- The docs site is generated and rolling. It can reflect a newer boto3 model than the currently installable standalone PyPI release.\n\n## Common Pitfalls\n\n- Do not install `mypy-boto3-sesv2` without `boto3` and expect AWS calls to work.\n- Do not point this package at `boto3.client(\"ses\")`. `ses` and `sesv2` are different service names with different generated stubs.\n- Do not assume every list operation has a paginator. The maintainer docs list paginator types for only a subset of SES v2 operations.\n- Do not assume successful type checking means SES can send mail. Runtime failures still happen for unverified identities, missing IAM permissions, wrong region, or account restrictions.\n- Do not rely on unannotated `session.client(\"sesv2\")` inference if you installed the standalone or lite package.\n\n## Version-Sensitive Notes For `1.42.13`\n\n- On March 13, 2026, PyPI lists `mypy-boto3-sesv2 1.42.13` as the published standalone package version.\n- The maintainer docs page for this service is a rolling generated reference and currently shows boto3 model version `1.42.63`.\n- The maintainer docs describe three install paths for this service: `boto3-stubs`, `boto3-stubs-lite`, and the standalone `mypy-boto3-sesv2` package.\n- Practical rule: pin the exact standalone version you can install from PyPI, and keep `boto3` aligned closely enough that the generated request and response shapes match the service model you are using.\n\n## Official Sources\n\n- Maintainer docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sesv2/\n- Maintainer client reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sesv2/client/\n- Maintainer paginator reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sesv2/paginators/\n- Maintainer type definitions: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sesv2/type_defs/\n- PyPI package page: https://pypi.org/project/mypy-boto3-sesv2/\n- Boto3 SES v2 reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sesv2.html\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 configuration guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sns/python/DOC.md",
    "content": "---\nname: mypy-boto3-sns\ndescription: \"mypy-boto3-sns type stubs for boto3 SNS clients, resources, paginators, literals, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,sns,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-sns Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-sns` is a stub-only package for `boto3` SNS usage. It improves static typing, but it does not ship the runtime AWS SDK, does not configure credentials, and does not make AWS calls by itself.\n\nUse one of these patterns:\n\n- Install `boto3-stubs[sns]` if you want automatic typing for `Session().client(\"sns\")` and `Session().resource(\"sns\")`.\n- Install `mypy-boto3-sns` if you want the standalone SNS stub package and are willing to annotate types explicitly.\n- Keep auth, region, retries, and endpoint behavior on the normal `boto3` side.\n\n## Install\n\n### Recommended: automatic boto3 overloads\n\nUse this when you want the best editor inference for ordinary boto3 session code.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[sns]==1.42.3\"\n```\n\n### Standalone SNS stubs\n\nUse this when you only want the SNS service package or want to keep imports explicit.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-sns==1.42.3\"\n```\n\n### Lower-memory alternative\n\nUse the lite package if your IDE struggles with the full overload set.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[sns]==1.42.3\"\n```\n\nThe maintainer docs note that the lite package does not provide `session.client()` and `session.resource()` overloads, so explicit annotations are more important in lite mode.\n\n## Runtime Setup And Auth\n\n`mypy-boto3-sns` has no package-specific configuration. Use the standard boto3 credential and region chain.\n\nCommon local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create an SNS client from a normal session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsns = session.client(\"sns\")\n```\n\nAWS documents that boto3 searches several locations for credentials, including explicit parameters, environment variables, assume-role configuration, IAM Identity Center, shared config files, container credentials, and EC2 instance metadata.\n\n## Core Usage\n\n### Typed client\n\nPrefer the client interface for new code. AWS documents the boto3 resource interface as feature-frozen.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sns import SNSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsns: SNSClient = session.client(\"sns\")\n\nresponse = sns.publish(\n    TopicArn=\"arn:aws:sns:us-east-1:123456789012:orders\",\n    Subject=\"order-created\",\n    Message='{\"order_id\":\"123\"}',\n)\n\nprint(response[\"MessageId\"])\n```\n\n### Typed paginator\n\nThe generated package exposes paginator types such as `ListTopicsPaginator`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sns import SNSClient\nfrom mypy_boto3_sns.paginator import ListTopicsPaginator\n\nsns: SNSClient = Session(region_name=\"us-east-1\").client(\"sns\")\npaginator: ListTopicsPaginator = sns.get_paginator(\"list_topics\")\n\nfor page in paginator.paginate(PaginationConfig={\"PageSize\": 100}):\n    for topic in page.get(\"Topics\", []):\n        print(topic[\"TopicArn\"])\n```\n\n### Typed service resource\n\nUse resources only if your codebase already depends on them.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sns import SNSServiceResource\n\nresource: SNSServiceResource = Session(region_name=\"us-east-1\").resource(\"sns\")\n\nfor topic in resource.topics.all():\n    print(topic.arn)\n```\n\n### Typed request and response shapes\n\nThe package also exposes generated `TypedDict` and `Literal` modules for helper code that passes dict-shaped data around separately from the boto3 call site.\n\n```python\nfrom mypy_boto3_sns.literals import LanguageCodeStringType\nfrom mypy_boto3_sns.type_defs import PublishInputTypeDef\n\nlanguage: LanguageCodeStringType = \"en-US\"\n\nrequest: PublishInputTypeDef = {\n    \"TopicArn\": \"arn:aws:sns:us-east-1:123456789012:orders\",\n    \"Message\": \"hello\",\n    \"MessageAttributes\": {},\n}\n```\n\n## TYPE_CHECKING Pattern\n\nThe package documentation explicitly supports importing stub types behind `TYPE_CHECKING` when you do not want the stub package to matter at runtime.\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sns import SNSClient\n\ndef make_client() -> \"SNSClient\":\n    return Session(region_name=\"us-east-1\").client(\"sns\")\n```\n\nThis is also the cleanest answer when linters complain about typing-only imports.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-sns` and expecting runtime AWS calls to work. You still need `boto3`.\n- Using the package name as a service name. The boto3 client is still `session.client(\"sns\")`.\n- Expecting automatic overload inference from `boto3-stubs-lite[sns]`. Lite mode needs explicit annotations.\n- Treating the stub package as an auth or config layer. Credentials, profiles, regions, retries, and endpoints still come from `boto3` and botocore.\n- Preferring resources for new code. AWS says resources are not getting new features, so clients are the safer default.\n- Pinning only one side of the version pair. The maintainer docs state that stub versions follow the related `boto3` version, so keep them aligned when exact API coverage matters.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.3`, and PyPI currently publishes `mypy-boto3-sns 1.42.3`.\n- The PyPI project metadata for `1.42.3` says the package version matches the related `boto3` version. If you pin one, pin both.\n- The maintainer docs root is a moving `latest` page. On 2026-03-12 it already showed local generation examples for newer `boto3` `1.42.66`, so treat that site as the current API-shape reference, not as release-specific pinning evidence for `1.42.3`.\n- If exact generated names matter, verify against the installed package or the release-specific PyPI README before copying a hardcoded `TypedDict` or `Literal` symbol from newer docs.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sns/\n- PyPI project page: https://pypi.org/project/mypy-boto3-sns/\n- PyPI JSON metadata: https://pypi.org/pypi/mypy-boto3-sns/json\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 resources guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html\n- SNS paginator reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns/paginator/ListTopics.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sqs/python/DOC.md",
    "content": "---\nname: mypy-boto3-sqs\ndescription: \"Typed boto3 SQS stubs for Python with install choices, typed clients and resources, paginators, request dicts, and runtime-safe patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,sqs,mypy,typing,stubs,python\"\n---\n\n# mypy-boto3-sqs Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-sqs` only for static typing and editor support around SQS code. Keep `boto3` as the runtime SDK, keep AWS credentials and region setup in boto3, and annotate clients or resources with the generated SQS types when inference is not enough.\n\n## What This Package Is For\n\n`mypy-boto3-sqs` is the generated type-stub package for the SQS part of boto3. It gives you typed definitions for:\n\n- `SQSClient`\n- `SQSServiceResource`\n- SQS paginator classes such as `ListQueuesPaginator`\n- request and response type definitions such as `SendMessageRequestTypeDef`\n- SQS literal unions and typed resource collections\n\nIt does not send requests by itself and it does not change boto3 behavior at runtime.\n\n## Install\n\nPick one of these installation patterns:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-sqs==1.42.3\"\n```\n\nIf you want boto3 plus generated overloads for `session.client(\"sqs\")` and `session.resource(\"sqs\")`, use the maintained extra package:\n\n```bash\npython -m pip install \"boto3-stubs[sqs]\"\n```\n\nIf you want lower dependency weight and can live without those overloads, use the lite variant:\n\n```bash\npython -m pip install \"boto3-stubs-lite[sqs]\"\n```\n\nPractical guidance:\n\n- Install `boto3` as the runtime dependency either way.\n- Use the full `boto3-stubs[sqs]` extra when you want the best IDE inference with the least annotation noise.\n- Use `mypy-boto3-sqs` directly when you only need SQS types.\n- Use the lite package when build size matters and explicit annotations are acceptable.\n\n## Setup And Initialization\n\nThe normal pattern is an ordinary boto3 session plus typed annotations from `mypy_boto3_sqs`.\n\n### Typed client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nsqs: SQSClient = session.client(\"sqs\")\n\nresponse = sqs.send_message(\n    QueueUrl=queue_url,\n    MessageBody=\"hello from typed boto3\",\n)\n\nprint(response[\"MessageId\"])\n```\n\n### Typed resource\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSServiceResource\nfrom mypy_boto3_sqs.service_resource import Queue\n\nsession = Session(region_name=\"us-west-2\")\nsqs: SQSServiceResource = session.resource(\"sqs\")\nqueue: Queue = sqs.Queue(queue_url)\n\nresult = queue.send_message(MessageBody=\"hello from the resource API\")\nprint(result.get(\"MessageId\"))\n```\n\n### When explicit annotations are optional\n\nWith the full `boto3-stubs[sqs]` package, IDEs and type checkers can often infer the SQS client or resource type from the service name. With `mypy-boto3-sqs` alone or with the lite variant, explicit annotations are more useful and sometimes necessary.\n\n## Core Usage Patterns\n\n### Use paginator types for list operations\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSClient\nfrom mypy_boto3_sqs.paginator import ListQueuesPaginator\n\nsession = Session(region_name=\"us-west-2\")\nsqs: SQSClient = session.client(\"sqs\")\npaginator: ListQueuesPaginator = sqs.get_paginator(\"list_queues\")\n\nfor page in paginator.paginate(QueueNamePrefix=\"orders-\"):\n    for url in page.get(\"QueueUrls\", []):\n        print(url)\n```\n\n### Use typed request dictionaries in helpers\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSClient\nfrom mypy_boto3_sqs.type_defs import SendMessageRequestTypeDef\n\nsession = Session(region_name=\"us-west-2\")\nsqs: SQSClient = session.client(\"sqs\")\n\nrequest: SendMessageRequestTypeDef = {\n    \"QueueUrl\": queue_url,\n    \"MessageBody\": \"typed payload\",\n}\n\nsqs.send_message(**request)\n```\n\n### Model long polling explicitly\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSClient\nfrom mypy_boto3_sqs.type_defs import ReceiveMessageRequestTypeDef\n\nsession = Session(region_name=\"us-west-2\")\nsqs: SQSClient = session.client(\"sqs\")\n\nrequest: ReceiveMessageRequestTypeDef = {\n    \"QueueUrl\": queue_url,\n    \"MaxNumberOfMessages\": 10,\n    \"WaitTimeSeconds\": 20,\n    \"MessageAttributeNames\": [\"All\"],\n}\n\nresponse = sqs.receive_message(**request)\n\nfor message in response.get(\"Messages\", []):\n    print(message[\"ReceiptHandle\"])\n```\n\n### Type resource collections when iterating queues\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sqs import SQSServiceResource\nfrom mypy_boto3_sqs.service_resource import Queue\nfrom mypy_boto3_sqs.service_resource import ServiceResourceQueuesCollection\n\nsession = Session(region_name=\"us-west-2\")\nsqs: SQSServiceResource = session.resource(\"sqs\")\nqueues: ServiceResourceQueuesCollection = sqs.queues\n\nfor queue in queues.all():\n    typed_queue: Queue = queue\n    print(typed_queue.url)\n```\n\n## Runtime-Safe Typing Pattern\n\nIf production environments do not install stub packages, keep the imports behind `TYPE_CHECKING` and use forward references:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sqs import SQSClient\n\nsession = Session(region_name=\"us-west-2\")\nsqs: \"SQSClient\" = session.client(\"sqs\")\n```\n\nUse this pattern when the package is dev-only and your deployed image only includes `boto3`.\n\n## AWS Credentials And Config\n\n`mypy-boto3-sqs` adds no new auth layer. boto3 still resolves credentials and region from the normal AWS SDK chain:\n\n1. Explicit credentials or region passed to `Session(...)` or `client(...)`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_DEFAULT_REGION`\n3. Shared config and credentials files under `~/.aws/`\n4. `AWS_PROFILE`\n5. IAM roles, IAM Identity Center, or workload identity in AWS-hosted environments\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nThen create a normal session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\n```\n\nIf you need custom retry or timeout behavior, configure it on the boto3 client with `botocore.config.Config`; this stub package only affects types.\n\n## Common Pitfalls\n\n- This package is not a runtime SQS client. You still need `boto3`.\n- `boto3-stubs-lite[sqs]` does not provide the session `client` and `resource` overloads from the full variant, so type inference is weaker.\n- If you import `mypy_boto3_sqs` directly at runtime but only install it as a dev dependency, production imports will fail. Use `TYPE_CHECKING` when needed.\n- SQS request dictionaries are strict about key names. Use the generated `type_defs` instead of untyped dicts when building payloads outside the call site.\n- Most SQS APIs use `QueueUrl`, not a queue name. Typed request defs help catch that early.\n- FIFO-only keys such as `MessageGroupId` and `MessageDeduplicationId` are valid only for FIFO queues.\n\n## Version-Sensitive Notes\n\n- The version used here for this session was `1.42.3`, and the live PyPI project page also showed `1.42.3` on March 12, 2026.\n- The maintainer docs state that service package versions track the related boto3 version line, so keep your stub packages aligned with the boto3 family you actually install.\n- The upstream docs site still documents the `boto3-stubs` package family and `mypy_boto3_sqs` imports.\n- The upstream repository now positions `types-boto3` as the successor project to `boto3-stubs`. If you are comparing newer examples from that repository, expect equivalent service-specific packages and different import roots.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sqs/\n- Type definitions reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sqs/type_defs/\n- Service resource reference: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sqs/service_resource/\n- PyPI package page: https://pypi.org/project/mypy-boto3-sqs/\n- Upstream repository: https://github.com/youtype/types-boto3\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-ssm/python/DOC.md",
    "content": "---\nname: mypy-boto3-ssm\ndescription: \"mypy-boto3-ssm package guide for typed boto3 SSM clients, paginators, waiters, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.54\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,ssm,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-ssm Python Package Guide\n\n## Golden Rule\n\nUse `mypy-boto3-ssm` only for static typing around the `boto3` SSM client.\n\n- Install `boto3` for runtime AWS calls.\n- Install `mypy-boto3-ssm` when you want only the SSM stub package and are willing to annotate clients explicitly.\n- Install `boto3-stubs[ssm]` when you want the upstream-recommended path with typed `boto3.client(\"ssm\")` and `Session().client(\"ssm\")` overloads.\n- Keep auth, region, retries, and endpoints in normal `boto3` / botocore configuration. This package does not add a runtime wrapper.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install \"boto3-stubs[ssm]==1.42.54\"\n```\n\nThis is the easiest way to get typed `boto3.client(\"ssm\")`, paginators, waiters, literals, and `TypedDict` request/response shapes.\n\n### Standalone SSM stubs\n\n```bash\npython -m pip install \"boto3==1.42.54\" \"mypy-boto3-ssm==1.42.54\"\n```\n\nUse this when you only want the SSM service stubs. In this mode, explicit annotations are the safest default.\n\n### Lower-memory / PyCharm-oriented install\n\n```bash\npython -m pip install \"boto3-stubs-lite[ssm]==1.42.54\"\n```\n\nThe upstream docs note that the lite variant is more memory-friendly, but it does not provide `session.client()` overloads. Add explicit client annotations when you use it.\n\n## Setup And AWS Auth\n\nCommon setup sources:\n\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n- named profiles via `AWS_PROFILE` or `Session(profile_name=\"...\")`\n- shared config in `~/.aws/config` and `~/.aws/credentials`\n- IAM roles in AWS runtimes\n\nTypical setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(\n    profile_name=\"dev\",\n    region_name=\"us-west-2\",\n)\n```\n\nIf your `boto3` session is wrong, the stubs will still type-check but the AWS call will fail at runtime.\n\n## Core Usage\n\n### Typed SSM client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ssm.client import SSMClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nssm: SSMClient = session.client(\"ssm\")\n\nparameter = ssm.get_parameter(\n    Name=\"/app/db/password\",\n    WithDecryption=True,\n)\n\nprint(parameter[\"Parameter\"][\"Value\"])\n```\n\n### Typed response dictionaries\n\n```python\nfrom mypy_boto3_ssm.client import SSMClient\nfrom mypy_boto3_ssm.type_defs import GetParameterResultTypeDef\n\ndef read_parameter(client: SSMClient, name: str) -> str:\n    response: GetParameterResultTypeDef = client.get_parameter(\n        Name=name,\n        WithDecryption=True,\n    )\n    return response[\"Parameter\"][\"Value\"]\n```\n\nUse `type_defs` when you want `TypedDict` coverage for nested response or request shapes instead of plain `dict[str, Any]`.\n\n### Typed paginator\n\n```python\nfrom mypy_boto3_ssm.client import SSMClient\nfrom mypy_boto3_ssm.paginator import DescribeParametersPaginator\nfrom mypy_boto3_ssm.type_defs import ParameterStringFilterTypeDef\n\ndef list_secure_parameters(client: SSMClient) -> list[str]:\n    filters: list[ParameterStringFilterTypeDef] = [\n        {\"Key\": \"Type\", \"Option\": \"Equals\", \"Values\": [\"SecureString\"]}\n    ]\n    paginator: DescribeParametersPaginator = client.get_paginator(\"describe_parameters\")\n\n    names: list[str] = []\n    for page in paginator.paginate(ParameterFilters=filters):\n        for parameter in page.get(\"Parameters\", []):\n            names.append(parameter[\"Name\"])\n    return names\n```\n\n### Typed waiter\n\nThe boto3 SSM client exposes the `command_executed` waiter, and the stubs provide `CommandExecutedWaiter`.\n\n```python\nfrom mypy_boto3_ssm.client import SSMClient\nfrom mypy_boto3_ssm.waiter import CommandExecutedWaiter\n\ndef run_shell_command(client: SSMClient, instance_id: str) -> str:\n    command = client.send_command(\n        InstanceIds=[instance_id],\n        DocumentName=\"AWS-RunShellScript\",\n        Parameters={\"commands\": [\"uname -a\"]},\n    )\n\n    command_id = command[\"Command\"][\"CommandId\"]\n    waiter: CommandExecutedWaiter = client.get_waiter(\"command_executed\")\n    waiter.wait(CommandId=command_id, InstanceId=instance_id)\n    return command_id\n```\n\n## Tooling Patterns\n\n### Explicit annotations are the safest default\n\nWith the standalone package or the lite package, annotate clients, paginators, and waiters directly instead of relying on inference.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_ssm.client import SSMClient\n\nssm: SSMClient = Session(region_name=\"us-east-1\").client(\"ssm\")\n```\n\n### Keep stubs out of production-only environments\n\nIf the stubs exist only in development or CI, gate imports behind `TYPE_CHECKING`.\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_ssm.client import SSMClient\nelse:\n    SSMClient = object\n\ndef make_client() -> \"SSMClient\":\n    return Session(region_name=\"us-west-2\").client(\"ssm\")\n```\n\nThis pattern is also the upstream workaround for tools like `pylint` when the stubs are not importable at runtime.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-ssm` and expecting it to replace `boto3`. It is a stubs package, not the runtime SDK.\n- Importing the wrong module path. Install `mypy-boto3-ssm`, but import from `mypy_boto3_ssm`.\n- Expecting zero-annotation `session.client(\"ssm\")` inference from `mypy-boto3-ssm` alone. The upstream docs position `boto3-stubs[ssm]` as the automatic-overload path.\n- Using `boto3-stubs-lite[ssm]` and then expecting `session.client(\"ssm\")` overloads to exist. Add explicit annotations in lite mode.\n- Letting `boto3`, `botocore`, and the stub package drift too far apart. These stubs are generated from boto3 service models, so version skew can show up as missing or incorrect types.\n- Treating the docs site as the source of truth for exact installable versions. Use PyPI for pinning, then use the generated docs for module layout and available typed surfaces.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.42.54`.\n- PyPI currently publishes `mypy-boto3-ssm 1.42.54`, and the package metadata says the stubs version follows the related boto3 version.\n- On `2026-03-11`, the maintainer docs page for `mypy-boto3-ssm` showed locally generated examples using `boto3==1.42.57`. Treat that as a docs-generation input, not proof that `mypy-boto3-ssm==1.42.57` is on PyPI.\n- When exact alignment matters, pin `boto3`, `botocore`, and `mypy-boto3-ssm` together and verify the package version on PyPI before copying examples from the generated docs.\n- The official boto3 SSM reference currently lists paginators and a single waiter, `CommandExecuted`; the stub package mirrors that boto3 client surface for typing.\n\n## Official Sources\n\n- Docs root: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_ssm/\n- PyPI project: https://pypi.org/project/mypy-boto3-ssm/\n- PyPI JSON for exact release metadata: https://pypi.org/pypi/mypy-boto3-ssm/json\n- Upstream repository: https://github.com/youtype/boto3_stubs\n- Boto3 credentials guide: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n- Boto3 SSM reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sso/python/DOC.md",
    "content": "---\nname: mypy-boto3-sso\ndescription: \"mypy-boto3-sso type stubs for boto3 IAM Identity Center (AWS SSO) clients, paginators, and TypedDict shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,sso,iam-identity-center,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-sso Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-sso` adds static types for the `boto3` `sso` client. It does not replace `boto3`, it does not create IAM Identity Center sessions for you, and it does not remove the need for an `accessToken` when you call the SSO Portal API directly.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[sso]` if you want the best autocomplete and `Session.client(\"sso\")` overloads.\n- Install `mypy-boto3-sso` if you only want the standalone SSO stubs and are willing to add explicit annotations.\n- Install `boto3-stubs-lite[sso]` if IDE memory use matters more than automatic overload inference.\n\nAWS now calls this service IAM Identity Center, but the SDK service name and the stubs package still use `sso`.\n\n## Install\n\n`mypy-boto3-sso` requires Python 3.9 or later.\n\nRecommended for most projects:\n\n```bash\npython -m pip install boto3 'boto3-stubs[sso]==1.42.3'\n```\n\nStandalone SSO stubs:\n\n```bash\npython -m pip install boto3 'mypy-boto3-sso==1.42.3'\n```\n\nLower-memory IDE fallback:\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[sso]==1.42.3'\n```\n\n## Auth And Runtime Setup\n\n`mypy-boto3-sso` has no package-specific initialization. Runtime behavior still comes from `boto3`, AWS config, and the IAM Identity Center login flow.\n\nIf your app uses AWS CLI v2 IAM Identity Center profiles, configure and log in first:\n\n```bash\naws configure sso --profile my-sso-profile\naws sso login --profile my-sso-profile\n```\n\nUseful environment variables:\n\n```bash\nexport AWS_PROFILE=my-sso-profile\nexport AWS_DEFAULT_REGION=us-west-2\nexport AWS_SSO_REGION=us-east-1\nexport AWS_SSO_ACCESS_TOKEN=your-portal-access-token\n```\n\nImportant distinction:\n\n- `AWS_PROFILE` and `Session(profile_name=...)` let normal `boto3` clients reuse credentials sourced from IAM Identity Center.\n- Direct `sso` client calls such as `list_accounts` and `get_role_credentials` still need an `accessToken` parameter. AWS documents that this token comes from the IAM Identity Center OIDC flow.\n\nCreate a typed client like this:\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_sso import SSOClient\n\nsession = Session(profile_name=os.getenv(\"AWS_PROFILE\", \"my-sso-profile\"))\n\nsso: SSOClient = session.client(\n    \"sso\",\n    region_name=os.getenv(\"AWS_SSO_REGION\", \"us-east-1\"),\n)\n```\n\n## Core Usage\n\n### List assigned accounts with a typed paginator\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_sso import SSOClient\nfrom mypy_boto3_sso.paginator import ListAccountsPaginator\nfrom mypy_boto3_sso.type_defs import AccountInfoTypeDef, ListAccountsRequestPaginateTypeDef\n\nclient: SSOClient = Session(profile_name=os.environ[\"AWS_PROFILE\"]).client(\n    \"sso\",\n    region_name=os.environ[\"AWS_SSO_REGION\"],\n)\n\nrequest: ListAccountsRequestPaginateTypeDef = {\n    \"accessToken\": os.environ[\"AWS_SSO_ACCESS_TOKEN\"],\n}\n\npaginator: ListAccountsPaginator = client.get_paginator(\"list_accounts\")\n\nfor page in paginator.paginate(**request):\n    for account in page.get(\"accountList\", []):\n        typed_account: AccountInfoTypeDef = account\n        print(typed_account[\"accountId\"], typed_account.get(\"accountName\"))\n```\n\n`list_accounts` is a paginated API in AWS, so use the paginator instead of managing `nextToken` manually.\n\n### List roles for an account and exchange for temporary AWS credentials\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_sso import SSOClient\nfrom mypy_boto3_sso.paginator import ListAccountRolesPaginator\nfrom mypy_boto3_sso.type_defs import GetRoleCredentialsResponseTypeDef, RoleInfoTypeDef\n\nclient: SSOClient = Session(profile_name=os.environ[\"AWS_PROFILE\"]).client(\n    \"sso\",\n    region_name=os.environ[\"AWS_SSO_REGION\"],\n)\n\naccess_token = os.environ[\"AWS_SSO_ACCESS_TOKEN\"]\naccount_id = \"123456789012\"\n\nroles: ListAccountRolesPaginator = client.get_paginator(\"list_account_roles\")\n\nfor page in roles.paginate(accessToken=access_token, accountId=account_id):\n    for role in page.get(\"roleList\", []):\n        typed_role: RoleInfoTypeDef = role\n        print(typed_role[\"roleName\"])\n\ncreds_response: GetRoleCredentialsResponseTypeDef = client.get_role_credentials(\n    accessToken=access_token,\n    accountId=account_id,\n    roleName=\"AdministratorAccess\",\n)\n\nrole_credentials = creds_response[\"roleCredentials\"]\n\naccount_session = Session(\n    aws_access_key_id=role_credentials[\"accessKeyId\"],\n    aws_secret_access_key=role_credentials[\"secretAccessKey\"],\n    aws_session_token=role_credentials[\"sessionToken\"],\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-west-2\"),\n)\n\ns3 = account_session.client(\"s3\")\nprint(s3.list_buckets()[\"Buckets\"])\n```\n\nThis is the common low-level pattern when you are integrating directly with the IAM Identity Center Portal API instead of relying only on `aws sso login` plus a named profile.\n\n### Revoke the portal access token\n\n```python\nimport os\n\nfrom boto3.session import Session\nfrom mypy_boto3_sso import SSOClient\n\nclient: SSOClient = Session(profile_name=os.environ[\"AWS_PROFILE\"]).client(\n    \"sso\",\n    region_name=os.environ[\"AWS_SSO_REGION\"],\n)\n\nclient.logout(accessToken=os.environ[\"AWS_SSO_ACCESS_TOKEN\"])\n```\n\n## Tooling Pattern For Dev-Only Stubs\n\nIf production environments do not install stub packages, keep imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sso import SSOClient\n\ndef make_client() -> \"SSOClient\":\n    return Session(profile_name=\"my-sso-profile\").client(\n        \"sso\",\n        region_name=\"us-east-1\",\n    )\n```\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-sso` and forgetting to install `boto3` for runtime calls.\n- Expecting a named AWS CLI SSO profile to remove the `accessToken` argument from direct `sso` client API calls. AWS still requires that parameter on these methods.\n- Using `boto3-stubs-lite[sso]` or the standalone package and expecting unannotated `Session.client(\"sso\")` calls to become typed automatically.\n- Confusing your workload region with the IAM Identity Center portal region. The `sso` client should target the IAM Identity Center region.\n- Treating the package as a credential provider. It only adds generated types for the `boto3` client, paginators, literals, and `TypedDict` response shapes.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `mypy-boto3-sso==1.42.3`.\n- The maintainer documents these stub versions as matching the related `boto3` version. Pin them together when exact request and response shapes matter.\n- The maintainer docs are generated and unversioned, so use the exact PyPI release page when locking dependencies.\n\n## Official Sources\n\n- Docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sso/\n- PyPI: https://pypi.org/project/mypy-boto3-sso/\n- Exact release: https://pypi.org/project/mypy-boto3-sso/1.42.3/\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n- Boto3 IAM Identity Center credential provider guide: https://docs.aws.amazon.com/sdkref/latest/guide/feature-sso-credentials.html\n- Boto3 SSO client reference: https://docs.aws.amazon.com/boto3/latest/reference/services/sso.html\n- `list_accounts`: https://docs.aws.amazon.com/boto3/latest/reference/services/sso/client/list_accounts.html\n- `list_account_roles`: https://docs.aws.amazon.com/boto3/latest/reference/services/sso/client/list_account_roles.html\n- `get_role_credentials`: https://docs.aws.amazon.com/boto3/latest/reference/services/sso/client/get_role_credentials.html\n- `logout`: https://docs.aws.amazon.com/boto3/latest/reference/services/sso/client/logout.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sso-admin/python/DOC.md",
    "content": "---\nname: mypy-boto3-sso-admin\ndescription: \"Type stubs for boto3 IAM Identity Center SSO Admin clients, paginators, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.41\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,iam-identity-center,sso-admin,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# `mypy-boto3-sso-admin` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-sso-admin` is a stubs-only package for IAM Identity Center SSO Admin. Keep using `boto3` for real AWS calls, then choose one typing mode:\n\n- Use `boto3-stubs[sso-admin]` when you want `Session().client(\"sso-admin\")` to infer types automatically in IDEs, `mypy`, and `pyright`.\n- Use `mypy-boto3-sso-admin` when you only want SSO Admin typings and are willing to annotate `SSOAdminClient`, paginators, literals, and `type_defs` explicitly.\n- Use `boto3-stubs-lite[sso-admin]` when full overloads are too heavy for your IDE. Upstream notes that the lite package does not provide `session.client/resource` overloads.\n\n## Install\n\nRecommended when you want automatic type discovery:\n\n```bash\npython -m pip install \"boto3==1.42.41\" \"boto3-stubs[sso-admin]==1.42.41\"\n```\n\nStandalone SSO Admin stubs:\n\n```bash\npython -m pip install \"boto3==1.42.41\" \"mypy-boto3-sso-admin==1.42.41\"\n```\n\nLower-memory IDE option:\n\n```bash\npython -m pip install \"boto3==1.42.41\" \"boto3-stubs-lite[sso-admin]==1.42.41\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.41\" \"boto3-stubs[sso-admin]==1.42.41\"\npoetry add \"boto3==1.42.41\" \"boto3-stubs[sso-admin]==1.42.41\"\n```\n\nNotes:\n\n- The PyPI project requires Python 3.9 or newer.\n- The maintainer documents this package as following the related `boto3` version, so pinning the same version is the safest default.\n- The import root uses underscores: `mypy_boto3_sso_admin`, not the hyphenated package name.\n\n## Runtime Setup And Auth\n\nThe typing package does not change runtime auth, retries, endpoints, or AWS config. Those still come from `boto3` and the normal AWS credential chain.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=\"dev\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nOr configure shared AWS files:\n\n```bash\naws configure\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsso_admin: SSOAdminClient = session.client(\"sso-admin\")\n```\n\nUseful environment variables:\n\n- `AWS_PROFILE`\n- `AWS_DEFAULT_REGION`\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN`\n\n## Core Usage\n\nAWS documents SSO Admin as a client-based boto3 service. In practice, start by discovering your IAM Identity Center instance, then work from the returned `InstanceArn`.\n\n### Discover the IAM Identity Center instance\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\n\nsso_admin: SSOAdminClient = Session(region_name=\"us-east-1\").client(\"sso-admin\")\n\ninstances = sso_admin.list_instances()[\"Instances\"]\ninstance = instances[0]\n\ninstance_arn = instance[\"InstanceArn\"]\nidentity_store_id = instance[\"IdentityStoreId\"]\n\nprint(instance_arn)\nprint(identity_store_id)\n```\n\nUse `identity_store_id` with the separate `identitystore` API when you need principal IDs for users or groups.\n\n### List permission sets with a typed paginator\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\nfrom mypy_boto3_sso_admin.paginator import ListPermissionSetsPaginator\n\nsso_admin: SSOAdminClient = Session(region_name=\"us-east-1\").client(\"sso-admin\")\ninstance_arn = \"arn:aws:sso:::instance/ssoins-1234567890abcdef\"\n\npaginator: ListPermissionSetsPaginator = sso_admin.get_paginator(\"list_permission_sets\")\n\nfor page in paginator.paginate(InstanceArn=instance_arn):\n    for permission_set_arn in page[\"PermissionSets\"]:\n        details = sso_admin.describe_permission_set(\n            InstanceArn=instance_arn,\n            PermissionSetArn=permission_set_arn,\n        )[\"PermissionSet\"]\n        print(details[\"Name\"], permission_set_arn)\n```\n\n### Create a permission set and attach policies\n\n`put_inline_policy_to_permission_set` expects a JSON string, not a Python dict.\n\n```python\nimport json\n\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\nfrom mypy_boto3_sso_admin.type_defs import CreatePermissionSetRequestTypeDef\n\nsso_admin: SSOAdminClient = Session(region_name=\"us-east-1\").client(\"sso-admin\")\ninstance_arn = \"arn:aws:sso:::instance/ssoins-1234567890abcdef\"\n\nrequest: CreatePermissionSetRequestTypeDef = {\n    \"InstanceArn\": instance_arn,\n    \"Name\": \"BillingReadOnly\",\n    \"Description\": \"Read-only billing access\",\n    \"Tags\": [{\"Key\": \"owner\", \"Value\": \"platform\"}],\n}\n\npermission_set = sso_admin.create_permission_set(**request)[\"PermissionSet\"]\npermission_set_arn = permission_set[\"PermissionSetArn\"]\n\nsso_admin.attach_managed_policy_to_permission_set(\n    InstanceArn=instance_arn,\n    PermissionSetArn=permission_set_arn,\n    ManagedPolicyArn=\"arn:aws:iam::aws:policy/job-function/Billing\",\n)\n\nsso_admin.put_inline_policy_to_permission_set(\n    InstanceArn=instance_arn,\n    PermissionSetArn=permission_set_arn,\n    InlinePolicy=json.dumps(\n        {\n            \"Version\": \"2012-10-17\",\n            \"Statement\": [\n                {\n                    \"Effect\": \"Allow\",\n                    \"Action\": [\"ce:GetCostAndUsage\"],\n                    \"Resource\": \"*\",\n                }\n            ],\n        }\n    ),\n)\n```\n\n### Provision the permission set to an AWS account\n\nAfter changing a permission set, provision it to the target account so the update is pushed out.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\nfrom mypy_boto3_sso_admin.literals import ProvisionTargetTypeType\n\nsso_admin: SSOAdminClient = Session(region_name=\"us-east-1\").client(\"sso-admin\")\n\ntarget_type: ProvisionTargetTypeType = \"AWS_ACCOUNT\"\n\nresult = sso_admin.provision_permission_set(\n    InstanceArn=\"arn:aws:sso:::instance/ssoins-1234567890abcdef\",\n    PermissionSetArn=\"arn:aws:sso:::permissionSet/ssoins-1234567890abcdef/ps-abcdef1234567890\",\n    TargetType=target_type,\n    TargetId=\"123456789012\",\n)\n\nrequest_id = result[\"PermissionSetProvisioningStatus\"][\"RequestId\"]\nstatus = sso_admin.describe_permission_set_provisioning_status(\n    InstanceArn=\"arn:aws:sso:::instance/ssoins-1234567890abcdef\",\n    ProvisionPermissionSetRequestId=request_id,\n)\n\nprint(status[\"PermissionSetProvisioningStatus\"][\"Status\"])\n```\n\n### Create an account assignment and poll the status\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sso_admin import SSOAdminClient\nfrom mypy_boto3_sso_admin.literals import PrincipalTypeType, TargetTypeType\n\nsso_admin: SSOAdminClient = Session(region_name=\"us-east-1\").client(\"sso-admin\")\n\nprincipal_type: PrincipalTypeType = \"GROUP\"\ntarget_type: TargetTypeType = \"AWS_ACCOUNT\"\n\nassignment = sso_admin.create_account_assignment(\n    InstanceArn=\"arn:aws:sso:::instance/ssoins-1234567890abcdef\",\n    TargetId=\"123456789012\",\n    TargetType=target_type,\n    PermissionSetArn=\"arn:aws:sso:::permissionSet/ssoins-1234567890abcdef/ps-abcdef1234567890\",\n    PrincipalType=principal_type,\n    PrincipalId=\"f81d4fae-7dec-11d0-a765-00a0c91e6bf6\",\n)\n\nrequest_id = assignment[\"AccountAssignmentCreationStatus\"][\"RequestId\"]\nstatus = sso_admin.describe_account_assignment_creation_status(\n    InstanceArn=\"arn:aws:sso:::instance/ssoins-1234567890abcdef\",\n    AccountAssignmentCreationRequestId=request_id,\n)\n\nprint(status[\"AccountAssignmentCreationStatus\"][\"Status\"])\n```\n\n`PrincipalId` is the IAM Identity Center user or group ID, not a display name or email address.\n\n## Typed Shapes And Dev-Only Imports\n\nUse the generated `type_defs` when helper functions pass complex request objects around.\n\n```python\nfrom mypy_boto3_sso_admin.type_defs import PermissionsBoundaryTypeDef\n\nboundary: PermissionsBoundaryTypeDef = {\n    \"ManagedPolicyArn\": \"arn:aws:iam::aws:policy/ReadOnlyAccess\",\n}\n```\n\nIf the stubs are installed only in development, guard the imports with `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_sso_admin import SSOAdminClient\nelse:\n    SSOAdminClient = object\n\n\ndef make_client() -> \"SSOAdminClient\":\n    return Session(region_name=\"us-east-1\").client(\"sso-admin\")\n```\n\n## Common Pitfalls\n\n- Do not install only `mypy-boto3-sso-admin` and expect AWS calls to work. You still need `boto3`.\n- Do not expect `session.client(\"sso-admin\")` to infer types automatically unless you installed `boto3-stubs[sso-admin]`. The standalone and lite packages need more explicit annotations.\n- Do not pass a Python dict to `put_inline_policy_to_permission_set`. The API expects a JSON string.\n- Do not use email addresses or group names for `PrincipalId`. SSO Admin expects IAM Identity Center principal IDs.\n- Do not treat successful type checking as proof that your AWS profile, region, IAM permissions, or IAM Identity Center instance are correct.\n- Do not import the hyphenated package name in Python code. Use `mypy_boto3_sso_admin`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `mypy-boto3-sso-admin 1.42.41` as the current release for this package on March 13, 2026.\n- PyPI states this package was generated with `mypy-boto3-builder 8.12.0`.\n- The maintainer documents package versioning as following the related `boto3` version. When exact type coverage matters, pin `boto3==1.42.41` with `mypy-boto3-sso-admin==1.42.41`.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sso_admin/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-sso-admin/`\n- Exact PyPI release page: `https://pypi.org/project/mypy-boto3-sso-admin/1.42.41/`\n- AWS boto3 SSO Admin reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/sso-admin.html`\n- Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://docs.aws.amazon.com/boto3/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-stepfunctions/python/DOC.md",
    "content": "---\nname: mypy-boto3-stepfunctions\ndescription: \"mypy-boto3-stepfunctions type stubs for boto3 Step Functions clients, paginators, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,stepfunctions,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-stepfunctions Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-stepfunctions` is a typing package for `boto3` Step Functions usage. It improves autocomplete and static checking, but it does not replace `boto3`, does not configure AWS credentials, and does not make runtime API calls by itself.\n\nUse it in one of these modes:\n\n- Install `boto3-stubs[stepfunctions]` when you want `Session().client(\"stepfunctions\")` to infer the `SFNClient` type automatically.\n- Install `mypy-boto3-stepfunctions` when you only want the standalone Step Functions stubs and are willing to add explicit type annotations.\n- Keep runtime setup in normal `boto3` and AWS config.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[stepfunctions]'\n```\n\nThis gives you the runtime SDK plus service-specific type discovery for Step Functions.\n\n### Standalone Step Functions stubs\n\n```bash\npython -m pip install \"mypy-boto3-stepfunctions==1.42.3\" boto3\n```\n\nUse this when you only want the Step Functions stubs package. In this mode, explicit annotations are usually the clearest approach.\n\n### Lite mode for lower memory / PyCharm\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[stepfunctions]'\n```\n\nThe maintainer docs recommend the lite variant for PyCharm performance, but it does not provide `session.client()` overload inference. Plan to annotate your client variables explicitly.\n\n## Runtime Setup And Auth\n\nThis package has no package-specific auth or config. Use normal `boto3` setup.\n\nBoto3 searches for credentials in a defined order that includes explicit client parameters, explicit `Session(...)` parameters, environment variables, shared credentials/config files, container credentials, and EC2 instance metadata.\n\nCommon local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nFor project-specific behavior, create an explicit session or pass a `Config` object:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\n\nsession = Session(profile_name=\"dev\")\n\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"max_attempts\": 10, \"mode\": \"standard\"},\n)\n```\n\nUse explicit sessions in tests, CLIs, and multi-account code so credentials and region do not come from hidden global state.\n\n## Core Usage\n\n### Typed Step Functions client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_stepfunctions import SFNClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: SFNClient = session.client(\"stepfunctions\")\n```\n\nAWS exposes Step Functions in boto3 as a low-level client. The service reference lists client methods such as `start_execution`, `start_sync_execution`, `describe_execution`, `list_executions`, `get_execution_history`, and `validate_state_machine_definition`.\n\n### Start an execution with typed output\n\nStep Functions expects `input` as JSON text, not a Python dict.\n\n```python\nimport json\n\nfrom boto3.session import Session\nfrom mypy_boto3_stepfunctions import SFNClient\nfrom mypy_boto3_stepfunctions.type_defs import StartExecutionOutputTypeDef\n\nclient: SFNClient = Session(region_name=\"us-east-1\").client(\"stepfunctions\")\n\nresponse: StartExecutionOutputTypeDef = client.start_execution(\n    stateMachineArn=\"arn:aws:states:us-east-1:123456789012:stateMachine:OrderWorkflow\",\n    name=\"order-123\",\n    input=json.dumps({\"order_id\": \"123\", \"retry\": False}),\n)\n\nprint(response[\"executionArn\"])\n```\n\n### Typed paginator\n\nStep Functions has generated paginator types for `get_execution_history`, `list_activities`, `list_executions`, `list_map_runs`, and `list_state_machines`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_stepfunctions import SFNClient\nfrom mypy_boto3_stepfunctions.paginator import ListExecutionsPaginator\n\nclient: SFNClient = Session(region_name=\"us-east-1\").client(\"stepfunctions\")\npaginator: ListExecutionsPaginator = client.get_paginator(\"list_executions\")\n\nfor page in paginator.paginate(\n    stateMachineArn=\"arn:aws:states:us-east-1:123456789012:stateMachine:OrderWorkflow\"\n):\n    for execution in page.get(\"executions\", []):\n        print(execution[\"name\"], execution[\"status\"])\n```\n\n### Literals and TypedDict request shapes\n\n```python\nfrom mypy_boto3_stepfunctions.literals import StateMachineTypeType\nfrom mypy_boto3_stepfunctions.type_defs import StartExecutionInputTypeDef\n\nmachine_type: StateMachineTypeType = \"STANDARD\"\n\nrequest: StartExecutionInputTypeDef = {\n    \"stateMachineArn\": \"arn:aws:states:us-east-1:123456789012:stateMachine:OrderWorkflow\",\n    \"input\": \"{}\",\n}\n```\n\nThe generated `type_defs` module is useful when you want precise request and response dictionaries in helper functions or tests.\n\n### Keep stub imports out of runtime-only environments\n\nIf stubs are installed only in dev or CI, gate them behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_stepfunctions import SFNClient\nelse:\n    SFNClient = object\n\ndef make_client() -> \"SFNClient\":\n    return Session(region_name=\"us-east-1\").client(\"stepfunctions\")\n```\n\nThe upstream PyPI page calls out this pattern specifically as the way to avoid a production dependency on the stubs package while keeping pylint satisfied.\n\n## Tooling Notes\n\n- `mypy` and `pyright` are both first-class upstream targets.\n- `boto3-stubs[stepfunctions]` is the easiest option if you want IDE auto-discovery without explicit annotations.\n- `boto3-stubs-lite[stepfunctions]` trades inference quality for lower IDE overhead.\n- The standalone package is best when you want service-specific imports without the broader extras package.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-stepfunctions` and expecting AWS calls to work. You still need `boto3`.\n- Forgetting the package/import name split: install `mypy-boto3-stepfunctions`, import `mypy_boto3_stepfunctions`.\n- Using `session.client(\"sfn\")`. The boto3 service name is `\"stepfunctions\"`, even though the typed client class is `SFNClient`.\n- Passing a raw dict to `start_execution(..., input=...)`. Step Functions expects a JSON string.\n- Expecting `boto3-stubs-lite[stepfunctions]` to infer `session.client(\"stepfunctions\")` automatically. Add explicit `SFNClient` annotations in lite mode.\n- Assuming there is a Step Functions resource layer in boto3 like S3 has. The official Step Functions boto3 reference is client-based, and the generated stub docs for this package expose client, paginator, literal, and `type_defs` modules.\n- Treating successful type checking as proof that credentials, region, IAM permissions, or state machine ARNs are correct. Typing and runtime access are separate concerns.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.3`.\n- PyPI currently serves `mypy-boto3-stepfunctions 1.42.3` as the latest release, published on `2025-12-04`.\n- The maintainer docs landing page is not version-pinned. On `2026-03-12` it still showed a local generation example against `boto3==1.42.62`, so use PyPI as the authoritative source for package-version pinning.\n- Upstream states that `mypy-boto3-stepfunctions` follows the related `boto3` version. If a symbol looks missing, first check whether your installed `boto3`, `botocore`, and stub package are aligned closely enough.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_stepfunctions/\n- PyPI package page: https://pypi.org/project/mypy-boto3-stepfunctions/\n- Boto3 Step Functions reference: https://docs.aws.amazon.com/boto3/latest/reference/services/stepfunctions.html\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-sts/python/DOC.md",
    "content": "---\nname: mypy-boto3-sts\ndescription: \"Type annotations for boto3 STS clients, literals, and TypedDicts in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,sts,boto3,mypy,pyright,type-stubs,python\"\n---\n\n# `mypy-boto3-sts` Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-sts` is a typing package for `boto3`, not a runtime AWS SDK. Use it to improve editor completion and static checking for STS clients, keep it aligned with your `boto3` release line, and let `boto3` handle credentials, sessions, and actual API calls.\n\n## Install\n\nChoose one installation path. Do not install all three.\n\n### Option 1: full `boto3-stubs` with STS overloads\n\nBest when you want `Session().client(\"sts\")` to infer the client type automatically.\n\n```bash\npython -m pip install \"boto3-stubs[sts]==1.42.3\"\n```\n\n### Option 2: `boto3-stubs-lite` for lower IDE and type-checker overhead\n\nUse this when full overload support is too heavy for your editor. The maintainer docs note that the lite build does not provide `session.client()` or `session.resource()` overloads, so you need explicit annotations.\n\n```bash\npython -m pip install \"boto3-stubs-lite[sts]==1.42.3\"\npython -m pip install \"boto3==1.42.3\"\n```\n\n### Option 3: standalone `mypy-boto3-sts`\n\nUse this when you only want the STS typing package. You still need `boto3` at runtime.\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-sts==1.42.3\"\n```\n\n## Client Setup\n\nFor actual AWS calls, create the client through `boto3`:\n\n```python\nimport boto3\nfrom mypy_boto3_sts import STSClient\n\nsession = boto3.Session(profile_name=\"dev\", region_name=\"us-east-1\")\nsts: STSClient = session.client(\"sts\")\n\nidentity = sts.get_caller_identity()\nprint(identity[\"Account\"])\nprint(identity[\"Arn\"])\n```\n\nIf you installed full `boto3-stubs[sts]`, your type checker can usually infer the return type from `session.client(\"sts\")`. If you installed `boto3-stubs-lite[sts]` or standalone `mypy-boto3-sts`, keep the explicit `STSClient` annotation.\n\n## Authentication And Configuration\n\nThis package does not define its own auth behavior. `boto3` still resolves credentials and region settings from the normal AWS chain.\n\nThe Boto3 credentials guide is the source of truth for configuration order. The sources that matter most in practice are:\n\n1. Explicit credentials passed to `Session(...)` or `client(...)`\n2. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n3. Shared AWS config and credentials files, usually `~/.aws/config` and `~/.aws/credentials`\n4. Assume-role, web identity, IAM Identity Center, container, or instance-role providers\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen construct the typed client normally:\n\n```python\nimport boto3\nfrom mypy_boto3_sts import STSClient\n\nsts: STSClient = boto3.Session().client(\"sts\")\n```\n\n## Core Usage\n\n### Type an STS client\n\n`STSClient` is the main type for `boto3.client(\"sts\")`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_sts.client import STSClient\n\ndef get_client() -> STSClient:\n    return Session(region_name=\"us-east-1\").client(\"sts\")\n```\n\n### Type `get_caller_identity()` responses\n\nUse the generated response `TypedDict` when you want stricter checking around returned fields.\n\n```python\nimport boto3\nfrom mypy_boto3_sts import STSClient\nfrom mypy_boto3_sts.type_defs import GetCallerIdentityResponseTypeDef\n\nsts: STSClient = boto3.Session(region_name=\"us-east-1\").client(\"sts\")\nidentity: GetCallerIdentityResponseTypeDef = sts.get_caller_identity()\n\naccount_id = identity[\"Account\"]\narn = identity[\"Arn\"]\nuser_id = identity[\"UserId\"]\n```\n\n### Type `assume_role()` request and response payloads\n\nThe package exposes `TypedDict` request and response shapes for STS operations.\n\n```python\nimport boto3\nfrom mypy_boto3_sts import STSClient\nfrom mypy_boto3_sts.type_defs import (\n    AssumeRoleRequestTypeDef,\n    AssumeRoleResponseTypeDef,\n)\n\nsts: STSClient = boto3.Session(profile_name=\"admin\", region_name=\"us-east-1\").client(\"sts\")\n\nrequest: AssumeRoleRequestTypeDef = {\n    \"RoleArn\": \"arn:aws:iam::123456789012:role/CrossAccountReadOnly\",\n    \"RoleSessionName\": \"reporting-job\",\n    \"DurationSeconds\": 3600,\n}\n\nresponse: AssumeRoleResponseTypeDef = sts.assume_role(**request)\ncreds = response[\"Credentials\"]\n\nprint(creds[\"AccessKeyId\"])\nprint(creds[\"Expiration\"])\n```\n\nUseful STS response shapes exposed by the package include:\n\n- `CredentialsTypeDef`\n- `GetCallerIdentityResponseTypeDef`\n- `AssumeRoleResponseTypeDef`\n- `GetSessionTokenResponseTypeDef`\n- `GetFederationTokenResponseTypeDef`\n\n### Use literals for stricter helper APIs\n\nThe generated literals module includes `STSServiceName`, `ServiceName`, `ResourceServiceName`, and `RegionName`.\n\n```python\nfrom mypy_boto3_sts.literals import STSServiceName\n\ndef normalize_service_name(value: STSServiceName) -> str:\n    return value\n\nservice_name: STSServiceName = \"sts\"\n```\n\n### Keep type-only imports out of production dependencies when needed\n\nThe maintainer docs explicitly recommend `TYPE_CHECKING` guards if you do not want stub packages installed in production. They also note that `pylint` may complain unless you provide fallback `object` assignments.\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypy_boto3_sts import STSClient\nelse:\n    STSClient = object\n```\n\nUse this pattern only when your deployment environment does not include the typing package. If your runtime environment already installs the stubs, plain imports are simpler.\n\n## Common STS Operations Covered By The Stubs\n\nThe generated `STSClient` docs currently include typing for the standard STS calls agents usually need:\n\n- `get_caller_identity`\n- `assume_role`\n- `assume_role_with_web_identity`\n- `assume_role_with_saml`\n- `get_session_token`\n- `get_federation_token`\n- `decode_authorization_message`\n\nThe current generated docs also expose newer STS operations such as:\n\n- `assume_root`\n- `get_delegated_access_token`\n- `get_web_identity_token`\n\nVerify that your pinned `boto3` and `botocore` versions actually expose the same operations before copying examples for those newer methods into a locked project.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-sts` as a replacement for `boto3`. It adds types only.\n- Do not expect automatic `session.client(\"sts\")` inference from the lite package. The maintainer docs explicitly say lite builds do not include those overloads.\n- Keep the stubs on the same release line as `boto3` when you want the best method and shape coverage.\n- Pin the version from PyPI, not from the generated docs site. The docs root is a rolling generated site and can be ahead of the published wheel.\n- These types help editors and static analysis, but they do not validate IAM policies, trust policies, MFA requirements, or role-session limits at runtime.\n- `STSClient` typing does not eliminate ordinary boto3 error handling. AWS service errors still arrive as runtime exceptions from `botocore`.\n\n## Version-Sensitive Notes\n\n- Frontmatter is pinned to the package version used here `1.42.3`.\n- PyPI lists `mypy-boto3-sts 1.42.3` as the current published release checked on `2026-03-12`.\n- The generated maintainer docs site is not a strict patch snapshot of the published wheel. Treat it as the canonical API-shape reference, but confirm package pins from PyPI before writing install commands.\n- PyPI states this package requires Python `>=3.9` and classifies it as `Stubs Only`.\n- PyPI and the related `types-boto3-*` project pages describe versioning as tracking the related `boto3` version, so mismatched `boto3` and stub versions are the main source of typing drift.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sts/`\n- STS client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sts/client/`\n- STS type definitions: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_sts/type_defs/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-sts/`\n- AWS Boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS Boto3 STS reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/sts.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-textract/python/DOC.md",
    "content": "---\nname: mypy-boto3-textract\ndescription: \"Type annotations for boto3 Textract in Python, covering typed clients, paginators, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,textract,boto3,mypy-boto3-textract,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-textract Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for runtime AWS calls and use `mypy-boto3-textract` only for typing.\n\nFor most projects, install `boto3-stubs[textract]` so `Session().client(\"textract\")` is typed automatically. Use `mypy-boto3-textract` when you want only the Textract typing package or when you prefer explicit annotations behind `TYPE_CHECKING`.\n\n## Install\n\n### Recommended for normal boto3 code\n\nInstall the runtime SDK and the full service stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[textract]==1.42.3\"\n```\n\nThis is the best default when you want typed `Session().client(\"textract\")` usage in VSCode, pyright, or mypy without adding explicit annotations everywhere.\n\n### Lower-memory option\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[textract]==1.42.3\"\n```\n\nThe maintainer docs say the lite package does not provide `session.client()` and `session.resource()` overloads. Use it when editor performance matters more than automatic inference.\n\n### Standalone service package\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-textract==1.42.3\"\n```\n\nUse the standalone package when you only want Textract typing support installed or when you plan to guard stub imports behind `TYPE_CHECKING`.\n\n## Setup And Authentication\n\nThis package does not configure AWS access. Credentials, region resolution, retries, endpoints, and HTTP behavior still come from `boto3`.\n\nPractical setup:\n\n1. Create a `boto3.Session(...)` with an explicit region.\n2. Let boto3 resolve credentials from the normal AWS chain unless you are intentionally passing temporary credentials.\n3. Keep runtime config on the session or client, not in the stubs package.\n\nMinimal setup:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ntextract = session.client(\"textract\")\n```\n\nImportant credential sources from the AWS boto3 guide:\n\n- explicit credentials passed to `boto3.client(...)`\n- explicit credentials passed to `boto3.Session(...)`\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n- assume-role and web-identity providers\n- AWS IAM Identity Center profiles\n- shared credentials in `~/.aws/credentials`\n- shared config in `~/.aws/config`\n- container credentials\n- EC2 instance metadata credentials\n\nUseful local-development defaults:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n## Core Usage\n\n### Zero-annotation workflow with `boto3-stubs[textract]`\n\nWith the full service extra installed, ordinary boto3 code should infer the correct client type:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(region_name=\"us-east-1\")\nclient = session.client(\"textract\")\n\nresponse = client.detect_document_text(\n    Document={\n        \"S3Object\": {\n            \"Bucket\": \"incoming-documents\",\n            \"Name\": \"forms/example.pdf\",\n        }\n    }\n)\n\nfor block in response.get(\"Blocks\", []):\n    if block.get(\"BlockType\") == \"LINE\":\n        print(block.get(\"Text\"))\n```\n\n### Explicit client annotations\n\nUse explicit annotations when you installed `mypy-boto3-textract` or the lite package:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_textract import TextractClient\n\nsession = Session(region_name=\"us-east-1\")\nclient: TextractClient = session.client(\"textract\")\n\nresponse = client.analyze_document(\n    Document={\n        \"S3Object\": {\n            \"Bucket\": \"incoming-documents\",\n            \"Name\": \"forms/example.pdf\",\n        }\n    },\n    FeatureTypes=[\"FORMS\", \"TABLES\"],\n)\n```\n\nAWS exposes Textract as a low-level client surface. The current boto3 Textract reference lists client methods and two paginators, not a higher-level resource API.\n\n### Typed paginator annotations\n\nThe maintainer docs expose typed paginators for the two paginator operations AWS currently documents for Textract:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_textract import TextractClient\nfrom mypy_boto3_textract.paginator import ListAdaptersPaginator\n\nsession = Session(region_name=\"us-east-1\")\nclient: TextractClient = session.client(\"textract\")\n\npaginator: ListAdaptersPaginator = client.get_paginator(\"list_adapters\")\n\nfor page in paginator.paginate(MaxResults=20):\n    for adapter in page.get(\"Adapters\", []):\n        print(adapter[\"AdapterName\"])\n```\n\n### Literals and TypedDicts\n\nUse literals for constrained string values and `type_defs` for request and response shapes:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_textract import TextractClient\nfrom mypy_boto3_textract.literals import FeatureTypeType\nfrom mypy_boto3_textract.type_defs import (\n    DocumentLocationTypeDef,\n    StartDocumentAnalysisResponseTypeDef,\n)\n\nfeature: FeatureTypeType = \"FORMS\"\ndocument: DocumentLocationTypeDef = {\n    \"S3Object\": {\n        \"Bucket\": \"incoming-documents\",\n        \"Name\": \"batch/job-001.pdf\",\n    }\n}\n\nclient: TextractClient = Session(region_name=\"us-east-1\").client(\"textract\")\nresponse: StartDocumentAnalysisResponseTypeDef = client.start_document_analysis(\n    DocumentLocation=document,\n    FeatureTypes=[feature],\n)\n\nprint(response[\"JobId\"])\n```\n\n### `TYPE_CHECKING` pattern\n\nThe PyPI project description explicitly says it is safe to keep this dependency out of production by importing it only for type checking:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_textract import TextractClient\nelse:\n    TextractClient = object\n\nsession = Session(region_name=\"us-east-1\")\nclient: \"TextractClient\" = session.client(\"textract\")\n```\n\nThis also avoids the pylint undefined-name issue called out in the upstream docs.\n\n## Configuration Notes\n\n- Prefer an explicit `Session(region_name=...)` for Textract. Region mismatches are easy to hide when credentials load successfully but the service is not enabled where you expect.\n- Keep retries and timeouts on the boto3 client config, not in stub-only imports.\n- For large or asynchronous document workflows, use the `start_*` Textract operations and then poll the matching `get_*` operation with the returned job ID.\n- For development environments that use AWS IAM Identity Center, let the AWS CLI manage login state and then construct a normal boto3 session with that profile.\n\n## Common Pitfalls\n\n- `mypy-boto3-textract` is stub-only. It does not replace `boto3`, and it does not create a runtime Textract client by itself.\n- `boto3-stubs[textract]` and `mypy-boto3-textract` are not equivalent ergonomically. Full `boto3-stubs` gives the smoothest inference; standalone and lite installs usually require explicit annotations.\n- Keep the `boto3` version aligned with the stubs version when you want predictable method signatures. PyPI states that `mypy-boto3-textract` uses the related boto3 version.\n- Do not invent `resource(\"textract\")` patterns. The official Textract boto3 reference documents the client interface and paginators, not a resource surface.\n- `boto3-stubs-lite[textract]` is intentionally incomplete for overload inference. Expect to annotate `TextractClient` and paginators yourself.\n- Type safety does not validate AWS permissions, region support, document size limits, or whether S3 objects actually exist.\n\n## Version-Sensitive Notes For `1.42.3`\n\n- PyPI lists `1.42.3` as the latest `mypy-boto3-textract` release on March 12, 2026, published on December 4, 2025.\n- PyPI states that `mypy-boto3-textract` versioning follows the related `boto3` version.\n- The hosted maintainer docs currently show a local generation example using `boto3==1.42.63`, even though the published package is `1.42.3`. Treat the installed package metadata and PyPI as the source of truth for exact pinning.\n- The AWS Textract reference is a rolling `latest` docs surface and currently resolves to a newer boto3 patch line than this package version. Use AWS docs for runtime behavior and available operations, but pin compatibility from the published package version.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_textract/\n- PyPI package page: https://pypi.org/project/mypy-boto3-textract/\n- AWS boto3 Textract reference: https://docs.aws.amazon.com/boto3/latest/reference/services/textract.html\n- AWS boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-timestream-write/python/DOC.md",
    "content": "---\nname: mypy-boto3-timestream-write\ndescription: \"Type stubs for boto3 Amazon Timestream Write clients, literals, and TypedDict request and response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,timestream,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-timestream-write Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real Amazon Timestream for LiveAnalytics write calls and use `mypy-boto3-timestream-write` only for typing. If you want `Session.client(\"timestream-write\")` to infer automatically, install `boto3-stubs[timestream-write]`; if you install only the standalone or lite package, annotate `TimestreamWriteClient` explicitly.\n\n## Install\n\nRecommended when you want automatic `Session.client(...)` typing:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs[timestream-write]==1.42.3\"\n```\n\nLower-memory option:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"boto3-stubs-lite[timestream-write]==1.42.3\"\n```\n\nStandalone Timestream Write stubs only:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-timestream-write==1.42.3\"\n```\n\nGenerate stubs locally when you need exact parity with a pinned boto3 build:\n\n```bash\nuvx --with \"boto3==1.42.3\" mypy-boto3-builder\n```\n\nPractical install rule:\n\n- `boto3-stubs[timestream-write]`: best inference for `Session.client(\"timestream-write\")`\n- `boto3-stubs-lite[timestream-write]`: smaller install, but you should annotate the client explicitly\n- `mypy-boto3-timestream-write`: service-only stubs without the bundled overload helpers\n\n## Setup And AWS Auth\n\nThis package does not add its own auth or config layer. Credentials, region, retry behavior, custom endpoints, and profiles still come from normal `boto3` and `botocore` configuration.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_timestream_write.client import TimestreamWriteClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\ntimestream_write: TimestreamWriteClient = session.client(\"timestream-write\")\n```\n\nIf the code type-checks but requests fail, debug the normal boto3 credential chain, IAM permissions, VPC endpoint routing, or Timestream service configuration rather than the stubs package.\n\n## Core Usage\n\n### Typed client for `write_records`\n\nTimestream `MeasureValue` values are strings even when the logical type is numeric. Keep the measure type in `MeasureValueType` and stringify the actual values.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_timestream_write.client import TimestreamWriteClient\n\nclient: TimestreamWriteClient = Session(region_name=\"us-east-1\").client(\n    \"timestream-write\"\n)\n\nresponse = client.write_records(\n    DatabaseName=\"metrics\",\n    TableName=\"cpu_utilization\",\n    CommonAttributes={\n        \"Dimensions\": [{\"Name\": \"host\", \"Value\": \"web-1\"}],\n        \"MeasureName\": \"cpu\",\n        \"MeasureValueType\": \"DOUBLE\",\n        \"TimeUnit\": \"SECONDS\",\n    },\n    Records=[\n        {\"Time\": \"1731456000\", \"MeasureValue\": \"18.25\"},\n        {\"Time\": \"1731456060\", \"MeasureValue\": \"19.75\"},\n    ],\n)\n\nprint(response[\"RecordsIngested\"][\"Total\"])\n```\n\nThe AWS `WriteRecords` docs note that `CommonAttributes` dimensions must not overlap with per-record dimensions, and updates to an existing record must use a higher `Version` or the service can reject the write.\n\n### Endpoint discovery and custom endpoint handling\n\nThe AWS Timestream endpoint-discovery guide says SDKs can discover ingestion endpoints automatically. `describe_endpoints()` is mainly useful when you need visibility into the resolved address or are managing custom endpoint behavior.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_timestream_write.client import TimestreamWriteClient\n\nclient: TimestreamWriteClient = Session(region_name=\"us-east-1\").client(\n    \"timestream-write\"\n)\n\nendpoint = client.describe_endpoints()[\"Endpoints\"][0]\nprint(endpoint[\"Address\"])\nprint(endpoint[\"CachePeriodInMinutes\"])\n```\n\nIf you manually cache endpoints or pass a custom `endpoint_url`, respect the returned cache period and keep the region aligned with the target Timestream resources.\n\n### Start a batch load task from S3\n\nUse batch load for larger backfills instead of pushing many individual `write_records` calls.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_timestream_write.client import TimestreamWriteClient\n\nclient: TimestreamWriteClient = Session(region_name=\"us-east-1\").client(\n    \"timestream-write\"\n)\n\ntask = client.create_batch_load_task(\n    DataModelConfiguration={\n        \"DataModel\": {\n            \"TimeColumn\": \"time\",\n            \"TimeUnit\": \"MILLISECONDS\",\n            \"DimensionMappings\": [\n                {\"SourceColumn\": \"host\", \"DestinationColumn\": \"host\"},\n            ],\n            \"MultiMeasureMappings\": {\n                \"TargetMultiMeasureName\": \"metrics\",\n                \"MultiMeasureAttributeMappings\": [\n                    {\n                        \"SourceColumn\": \"cpu\",\n                        \"TargetMultiMeasureAttributeName\": \"cpu\",\n                        \"MeasureValueType\": \"DOUBLE\",\n                    }\n                ],\n            },\n        }\n    },\n    DataSourceConfiguration={\n        \"DataSourceS3Configuration\": {\n            \"BucketName\": \"my-import-bucket\",\n            \"ObjectKeyPrefix\": \"timestream/cpu/\",\n        },\n        \"CsvConfiguration\": {\"ColumnSeparator\": \",\"},\n        \"DataFormat\": \"CSV\",\n    },\n    ReportConfiguration={\n        \"ReportS3Configuration\": {\n            \"BucketName\": \"my-import-bucket\",\n            \"ObjectKeyPrefix\": \"timestream/reports/\",\n        }\n    },\n    TargetDatabaseName=\"metrics\",\n    TargetTableName=\"cpu_utilization\",\n)\n\nprint(task[\"TaskId\"])\n```\n\nThe AWS batch-load API requires both an S3 data source and an S3 report location. Check `describe_batch_load_task(...)` or `list_batch_load_tasks(...)` to monitor progress and failures.\n\n### `TYPE_CHECKING` pattern for dev-only stubs\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_timestream_write.client import TimestreamWriteClient\nelse:\n    TimestreamWriteClient = object\n\ndef make_client() -> \"TimestreamWriteClient\":\n    return boto3.client(\"timestream-write\", region_name=\"us-east-1\")\n```\n\nThis keeps stub imports out of runtime-only environments while preserving type checking.\n\n### Literals and `TypedDict` shapes\n\nThe published maintainer docs for this package expose `client`, `literals`, `type_defs`, and example sections. Use literal aliases for enum-like strings and `TypedDict` definitions for helpers that pass request fragments around.\n\n```python\nfrom mypy_boto3_timestream_write.literals import BatchLoadDataFormatType\nfrom mypy_boto3_timestream_write.type_defs import BatchLoadProgressReportTypeDef\n\ndata_format: BatchLoadDataFormatType = \"CSV\"\n\ndef processed_records(report: BatchLoadProgressReportTypeDef) -> int:\n    return report.get(\"RecordsProcessed\", 0)\n```\n\n## Configuration Notes\n\n- Keep `boto3`, `botocore`, and the stubs package on the same release line when possible. The maintainer docs say the service-stub packages use the same version as the related `boto3` release.\n- `timestream-write` is the boto3 service name. Do not use the PyPI package name in `session.client(...)`.\n- Timestream Write does not have a boto3 resource interface. Plan around the typed client and generated request and response shapes.\n- SDK endpoint discovery is normal for this service. If your environment overrides endpoints manually, test ingestion carefully.\n- Batch load uses S3 source objects plus S3 error-report output; it is not a drop-in replacement for `write_records`.\n\n## Common Pitfalls\n\n- Treating `mypy-boto3-timestream-write` as a runtime SDK. Real AWS calls still require `boto3`.\n- Installing only `mypy-boto3-timestream-write` or `boto3-stubs-lite[timestream-write]` and expecting `Session.client(\"timestream-write\")` overload inference to appear automatically.\n- Forgetting that `MeasureValue` is serialized as a string even when `MeasureValueType` is numeric.\n- Duplicating the same dimension name in both `CommonAttributes` and individual records. The AWS `WriteRecords` API rejects overlapping dimensions.\n- Updating an existing record without increasing `Version`, which can trigger `RejectedRecordsException`.\n- Assuming batch-load tasks are synchronous. They need task-status polling and S3 report inspection.\n\n## Version-Sensitive Notes\n\n- The version used here `1.42.3` matches the official PyPI release and the maintainer docs checked on March 12, 2026.\n- PyPI lists `mypy-boto3-timestream-write 1.42.3` as the current release, published on December 4, 2025, with `Requires: Python >=3.9`.\n- The PyPI package page says this package was generated by `mypy-boto3-builder 8.12.0`.\n- The generated docs root is a stable package URL, not a release-pinned docs URL. Pin the package version in your environment when exact patch parity matters.\n\n## Official Sources\n\n- Maintainer docs: https://youtype.github.io/boto3_stubs_docs/mypy_boto3_timestream_write/\n- Maintainer versioning guide: https://youtype.github.io/boto3_stubs_docs/#versioning\n- PyPI package page: https://pypi.org/project/mypy-boto3-timestream-write/\n- PyPI release page: https://pypi.org/project/mypy-boto3-timestream-write/1.42.3/\n- Boto3 Timestream Write service reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/timestream-write.html\n- Boto3 `write_records` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/timestream-write/client/write_records.html\n- Boto3 `create_batch_load_task` reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/timestream-write/client/create_batch_load_task.html\n- Boto3 credentials guide: https://docs.aws.amazon.com/boto3/latest/guide/credentials.html\n- Boto3 configuration guide: https://docs.aws.amazon.com/boto3/latest/guide/configuration.html\n- AWS endpoint-discovery guide: https://docs.aws.amazon.com/timestream/latest/developerguide/Using-API.endpoint-discovery.describe-endpoints.implementation.html\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-transcribe/python/DOC.md",
    "content": "---\nname: mypy-boto3-transcribe\ndescription: \"mypy-boto3-transcribe type stubs for typed boto3 Amazon Transcribe clients, waiters, literals, and TypedDict request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.25\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,transcribe,boto3,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-transcribe Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-transcribe` is a typing package for Amazon Transcribe in `boto3`. It does not replace `boto3`, does not configure AWS credentials, and does not make API calls by itself.\n\nUse one of these modes:\n\n- Install `boto3-stubs[transcribe]` if you want `boto3.client(\"transcribe\")` to be typed automatically in editors and type checkers.\n- Install `boto3-stubs-lite[transcribe]` if you need a lower-memory option and are willing to add explicit annotations.\n- Install `mypy-boto3-transcribe` if you want the standalone Transcribe stub package and explicit service-specific imports.\n\n## Install\n\n### Recommended for most projects\n\n```bash\npython -m pip install boto3 'boto3-stubs[transcribe]'\n```\n\nThis gives automatic type discovery for `boto3.client(\"transcribe\")` in supported IDEs and type checkers.\n\n### Standalone package\n\n```bash\npython -m pip install boto3 mypy-boto3-transcribe\n```\n\nUse this when you specifically want the standalone Transcribe stubs package and are willing to annotate the client explicitly.\n\n### Lower-memory fallback\n\n```bash\npython -m pip install boto3 'boto3-stubs-lite[transcribe]'\n```\n\nUpstream notes that `boto3-stubs-lite` is more RAM-friendly, but it does not provide `session.client()` or `session.resource()` overloads, so explicit annotations are usually necessary.\n\nPyPI metadata for `mypy-boto3-transcribe 1.42.25` requires Python `>=3.9`.\n\n## Setup And Initialization\n\n`mypy-boto3-transcribe` has no package-specific auth or config layer. Runtime configuration still comes from normal `boto3` setup.\n\nAWS says Boto3 requests need both credentials and a region. The usual setup is:\n\n```bash\naws configure\n```\n\nor environment variables such as:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nBoto3 searches for credentials in a defined order, including explicit client/session parameters, environment variables, shared credential files, config files, container credentials, and EC2 instance metadata.\n\nFor isolated or multi-account code, create an explicit session:\n\n```python\nfrom boto3.session import Session\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\n```\n\nWith the standalone package or lite package, annotate the client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_transcribe import TranscribeServiceClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: TranscribeServiceClient = session.client(\"transcribe\")\n```\n\n## Core Usage\n\n### Typed client\n\nPyPI documents `TranscribeServiceClient` as the type for `boto3.client(\"transcribe\")`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_transcribe import TranscribeServiceClient\n\nclient: TranscribeServiceClient = Session(region_name=\"us-east-1\").client(\"transcribe\")\n\njob = client.get_transcription_job(TranscriptionJobName=\"daily-call-001\")\nstatus = job[\"TranscriptionJob\"][\"TranscriptionJobStatus\"]\nprint(status)\n```\n\n### Typed request payloads with `type_defs`\n\nUse generated `TypedDict` shapes for larger request objects so mypy or pyright can catch misspelled keys before runtime.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_transcribe import TranscribeServiceClient\nfrom mypy_boto3_transcribe.type_defs import StartTranscriptionJobRequestRequestTypeDef\n\nclient: TranscribeServiceClient = Session(region_name=\"us-east-1\").client(\"transcribe\")\n\nrequest: StartTranscriptionJobRequestRequestTypeDef = {\n    \"TranscriptionJobName\": \"daily-call-001\",\n    \"LanguageCode\": \"en-US\",\n    \"MediaFormat\": \"mp3\",\n    \"Media\": {\"MediaFileUri\": \"s3://my-input-bucket/audio/daily-call-001.mp3\"},\n    \"OutputBucketName\": \"my-output-bucket\",\n}\n\nclient.start_transcription_job(**request)\n```\n\n### Waiters\n\nThe package includes typed waiters under `mypy_boto3_transcribe.waiter`. PyPI lists waiters including:\n\n- `CallAnalyticsJobCompletedWaiter`\n- `LanguageModelCompletedWaiter`\n- `MedicalScribeJobCompletedWaiter`\n- `MedicalTranscriptionJobCompletedWaiter`\n- `MedicalVocabularyReadyWaiter`\n- `TranscriptionJobCompletedWaiter`\n- `VocabularyReadyWaiter`\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_transcribe import TranscribeServiceClient\nfrom mypy_boto3_transcribe.waiter import TranscriptionJobCompletedWaiter\n\nclient: TranscribeServiceClient = Session(region_name=\"us-east-1\").client(\"transcribe\")\nwaiter: TranscriptionJobCompletedWaiter = client.get_waiter(\"transcription_job_completed\")\nwaiter.wait(TranscriptionJobName=\"daily-call-001\")\n```\n\n### Literals and helper modules\n\nThe documented helper modules are:\n\n- `mypy_boto3_transcribe.client` for `TranscribeServiceClient`\n- `mypy_boto3_transcribe.waiter` for waiter types\n- `mypy_boto3_transcribe.literals` for constrained string values\n- `mypy_boto3_transcribe.type_defs` for `TypedDict` request and response shapes\n\nUse `literals` when a parameter only accepts a fixed string set, and `type_defs` when you want checked request or response dictionaries.\n\n## Tooling Patterns\n\n### mypy and pyright\n\nUpstream expects `boto3-stubs[transcribe]` to work with normal mypy or pyright setups. For standalone `mypy-boto3-transcribe`, install the stubs in the same interpreter environment that your editor and CI use.\n\n### Avoiding a production dependency on the stubs\n\nIf you only want the package in dev or CI, import types behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_transcribe import TranscribeServiceClient\nelse:\n    TranscribeServiceClient = object\n\ndef make_client() -> \"TranscribeServiceClient\":\n    return Session(region_name=\"us-east-1\").client(\"transcribe\")\n```\n\nUpstream calls this pattern safe for keeping the typing dependency out of production, with the caveat that `pylint` may need the `object` fallback.\n\n## Configuration And Authentication Notes\n\nThe stubs do not change:\n\n- credentials\n- region selection\n- assume-role behavior\n- retries\n- endpoint overrides\n- transport settings\n\nIf Transcribe calls fail at runtime, fix the `boto3` or AWS configuration rather than the stub package.\n\n## Common Pitfalls\n\n- Installing only `mypy-boto3-transcribe` and expecting unannotated `boto3.client(\"transcribe\")` calls to become typed automatically. That behavior comes from `boto3-stubs[transcribe]`.\n- Forgetting to install `boto3`. This package is stubs only.\n- Running the editor or CI against a different interpreter than the one where the stubs are installed.\n- Letting the Transcribe client flow through untyped helpers before annotating it.\n- Assuming `boto3-stubs-lite[transcribe]` provides client overload inference. It does not.\n- Importing stub types at runtime when the stubs are only installed in dev dependencies. Use `TYPE_CHECKING`.\n- Ignoring IDE-specific tradeoffs. Upstream recommends `boto3-stubs-lite` for PyCharm when `Literal` overload performance becomes a problem.\n\n## Version-Sensitive Notes\n\n- This entry covers `mypy-boto3-transcribe 1.42.25`, which matches the version used here and the current PyPI release page on `2026-03-12`.\n- Upstream says `mypy-boto3-transcribe` versions track the related `boto3` version.\n- PyPI metadata for `1.42.25` requires Python `>=3.9`.\n- If you need exact type coverage for a different installed `boto3` version, upstream recommends generating stubs locally with `uvx --with 'boto3==<version>' mypy-boto3-builder`.\n\n## Official Source URLs\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transcribe/`\n- Examples page: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transcribe/usage/#usage-examples`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-transcribe/`\n- Builder repository: `https://github.com/youtype/mypy_boto3_builder`\n- AWS credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS session guide: `https://docs.aws.amazon.com/boto3/latest/guide/session.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-transfer/python/DOC.md",
    "content": "---\nname: mypy-boto3-transfer\ndescription: \"mypy-boto3-transfer package guide for typed boto3 AWS Transfer Family clients, paginators, waiters, literals, and TypedDicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.45\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,transfer,transfer-family,boto3,mypy-boto3-transfer,boto3-stubs,typing,type-checking\"\n---\n\n# mypy-boto3-transfer Python Package Guide\n\n## Golden Rule\n\nUse `boto3` for real AWS Transfer Family API calls and use `mypy-boto3-transfer` only for typing. If you want `Session.client(\"transfer\")` to infer automatically, install `boto3-stubs[transfer]`; if you install only the standalone or lite package, annotate `TransferClient` explicitly.\n\n## Version-Sensitive Notes\n\n- On `2026-03-12`, the version used here `1.42.45` matches the current official PyPI release for `mypy-boto3-transfer`.\n- The PyPI release page shows `1.42.45` was published on `2026-02-09` and generated with `mypy-boto3-builder 8.12.0`.\n- Upstream states that the package version follows the related `boto3` version. Keep your stub package close to the `boto3` line you actually run so request/response shapes do not drift.\n- The maintainer docs root is a stable package URL, not a release-pinned docs snapshot. Pin the package in your environment when exact patch parity matters.\n- The published docs expose `client`, `paginator`, `waiter`, `literals`, `type_defs`, and examples. I did not find a dedicated `service_resource` module for Transfer, so plan around typed clients.\n- The release history skips some patch numbers. Do not assume every `boto3` patch has a matching standalone `mypy-boto3-transfer` upload.\n- If you need stubs that exactly match the `boto3` build in your environment, the maintainer docs recommend generating them locally with `mypy-boto3-builder`.\n\n## Install\n\nChoose one install mode based on how much boto3 typing support you want.\n\n### Best inference: full boto3 stubs\n\nUse this when you want automatic type discovery for `Session.client(\"transfer\")`, `client.get_paginator(...)`, and `client.get_waiter(...)`:\n\n```bash\npython -m pip install \"boto3\" \"boto3-stubs[transfer]\"\n```\n\n### Service-specific package only\n\nUse this when you want only the Transfer Family typing package and are willing to add explicit annotations:\n\n```bash\npython -m pip install \"boto3==1.42.45\" \"mypy-boto3-transfer==1.42.45\"\n```\n\n### Lite aggregate package\n\nUse this when the full stubs package is too heavy for your IDE or environment:\n\n```bash\npython -m pip install \"boto3\" \"boto3-stubs-lite[transfer]\"\n```\n\nThe lite package is more RAM-friendly, but the maintainer docs note that it does not provide `session.client/resource` overloads, so explicit annotations become more important.\n\n## Initialization And Setup\n\n`mypy-boto3-transfer` does not add its own auth or config layer. All runtime behavior still comes from normal boto3 setup:\n\n- credentials from environment variables, shared AWS config files, IAM Identity Center, assume-role config, container credentials, or runtime IAM roles\n- optional profile selection through `AWS_PROFILE` or `boto3.Session(profile_name=...)`\n- optional `botocore.config.Config` settings for region, retries, timeouts, proxies, and endpoint behavior\n\nTypical setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nThen create the real boto3 client and annotate it:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\nfrom botocore.config import Config\n\nif TYPE_CHECKING:\n    from mypy_boto3_transfer.client import TransferClient\n\nconfig = Config(\n    region_name=\"us-east-1\",\n    retries={\"mode\": \"standard\", \"max_attempts\": 10},\n)\n\nsession = boto3.Session(profile_name=\"dev\")\ntransfer: \"TransferClient\" = session.client(\"transfer\", config=config)\n```\n\nIf you target LocalStack or a private endpoint for tests, set `endpoint_url=...` on the real boto3 client. The stub package does not change endpoint resolution.\n\n## Core Usage\n\n### Typed Transfer client\n\nUse the typed client for ordinary server, user, connector, and workflow calls:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_transfer.client import TransferClient\n\ntransfer: \"TransferClient\" = boto3.Session().client(\"transfer\")\n\nresponse = transfer.list_servers(MaxResults=10)\n\nfor server in response.get(\"Servers\", []):\n    print(server[\"ServerId\"], server[\"State\"], server[\"Protocols\"])\n```\n\n### Typed paginator\n\nUse paginators instead of hand-rolled token loops when listing users or servers:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_transfer.client import TransferClient\n    from mypy_boto3_transfer.paginator import ListUsersPaginator\n\ntransfer: \"TransferClient\" = boto3.Session().client(\"transfer\")\n\npaginator: \"ListUsersPaginator\" = transfer.get_paginator(\"list_users\")\n\nfor page in paginator.paginate(ServerId=\"s-0123456789abcdef0\", MaxResults=50):\n    for user in page.get(\"Users\", []):\n        print(user[\"UserName\"], user[\"Role\"])\n```\n\n### Typed waiter for server state\n\nTransfer Family server start and stop operations are asynchronous. Use the waiter that matches the state you need before moving to later automation:\n\n```python\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_transfer.client import TransferClient\n    from mypy_boto3_transfer.waiter import ServerOnlineWaiter\n\ntransfer: \"TransferClient\" = boto3.Session().client(\"transfer\")\nserver_id = \"s-0123456789abcdef0\"\n\ntransfer.start_server(ServerId=server_id)\n\nwaiter: \"ServerOnlineWaiter\" = transfer.get_waiter(\"server_online\")\nwaiter.wait(ServerId=server_id)\n```\n\nUse `server_offline` after `stop_server(...)` when a workflow depends on the server reaching `OFFLINE`.\n\n### Typed request dictionaries and literals\n\nThe generated docs also expose Transfer-specific `TypedDict` request and response shapes plus literal aliases. This is useful when helper functions assemble request dictionaries before the client call:\n\n```python\nfrom mypy_boto3_transfer.literals import AgreementStatusTypeType\nfrom mypy_boto3_transfer.type_defs import As2AsyncMdnConnectorConfigOutputTypeDef\n\nstatus: AgreementStatusTypeType = \"ACTIVE\"\n\nconnector_config: As2AsyncMdnConnectorConfigOutputTypeDef = {\n    \"LocalProfileId\": \"p-0123456789abcdef0\",\n    \"PartnerProfileId\": \"p-abcdef0123456789\",\n    \"MdnSigningAlgorithm\": \"SHA256WITHRSA\",\n    \"MdnSigningCertificate\": \"arn:aws:acm:us-east-1:123456789012:certificate/example\",\n}\n```\n\nUse the published `type_defs` reference when you need exact shapes for operations such as `create_user`, `describe_server`, connectors, certificates, or workflow detail objects.\n\n## Runtime-Safe Typing Pattern\n\nIf your production image does not install stub packages, keep the imports inside `TYPE_CHECKING` so the type checker sees them without turning the stubs into a runtime dependency:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport boto3\n\nif TYPE_CHECKING:\n    from mypy_boto3_transfer.client import TransferClient\n\nclient: \"TransferClient\" = boto3.Session().client(\"transfer\")\n```\n\n## Transfer-Family-Specific Notes\n\n- The boto3 service name is `transfer`, not `mypy-boto3-transfer`.\n- `create_user` applies to Transfer Family servers that use the `SERVICE_MANAGED` identity provider. It is not the universal user-management path for every identity setup.\n- If you use logical directories, the server and user configuration must agree on `HomeDirectoryType=\"LOGICAL\"` and the corresponding directory mappings.\n- Waiters tell you when the control-plane server state changes. They do not confirm that individual file transfers or workflows finished successfully.\n- Use the real AWS Transfer Family docs for runtime semantics such as connector behavior, protocol support, identity-provider requirements, and billing details.\n\n## Common Pitfalls\n\n- The PyPI package name uses hyphens, but Python imports use underscores: `mypy_boto3_transfer`.\n- This package is typing-only. Real AWS requests still require `boto3`.\n- If you choose `mypy-boto3-transfer` or `boto3-stubs-lite[transfer]`, do not expect all `Session.client(\"transfer\")` calls to infer automatically. Add explicit `TransferClient` annotations.\n- Keep `boto3`, `botocore`, and `mypy-boto3-transfer` reasonably aligned. New Transfer Family fields can appear in runtime models before matching stubs land.\n- PyCharm can be slow with large `Literal` overload sets. If IDE responsiveness matters more than overload inference, `boto3-stubs-lite` is the safer default.\n- Do not mix up package docs with runtime docs. The maintainer docs explain the typing surface; the AWS Transfer Family docs explain service behavior and API semantics.\n\n## Official Sources\n\n- Docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transfer/`\n- Client reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transfer/client/`\n- Waiters reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transfer/waiters/`\n- Type defs reference: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_transfer/type_defs/`\n- Versioning guide: `https://youtype.github.io/boto3_stubs_docs/#versioning`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-transfer/`\n- PyPI exact release: `https://pypi.org/project/mypy-boto3-transfer/1.42.45/`\n- Maintainer repository: `https://github.com/youtype/types-boto3`\n- Boto3 Transfer service reference: `https://docs.aws.amazon.com/boto3/latest/reference/services/transfer.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n- Boto3 configuration guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-translate/python/DOC.md",
    "content": "---\nname: mypy-boto3-translate\ndescription: \"mypy-boto3-translate package guide for typed boto3 AWS Translate clients, paginators, literals, and request/response shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,translate,boto3,type-stubs,mypy,pyright,pylance,python\"\n---\n\n# mypy-boto3-translate Python Package Guide\n\n`mypy-boto3-translate` is a stubs-only package for the AWS Translate service in `boto3`. It improves type checking and editor completion for `Session().client(\"translate\")`, paginator calls, literals, and typed request/response dictionaries. It does not make AWS API calls by itself.\n\n## Golden Rule\n\n- Keep using `boto3` for runtime AWS calls.\n- Install the stubs alongside `boto3`, or use the bundled `boto3-stubs[translate]` extra.\n- Prefer explicit client annotations when you install the standalone service package.\n- Let `boto3` handle credentials and region resolution. These stubs only affect typing.\n\n## Install\n\nInstall the runtime SDK and the service stubs together:\n\n```bash\npython -m pip install \"boto3==1.42.3\" \"mypy-boto3-translate==1.42.3\"\n```\n\nMaintainer-recommended bundled install:\n\n```bash\npython -m pip install \"boto3-stubs[translate]\"\n```\n\nLower-memory alternative:\n\n```bash\npython -m pip install \"boto3-stubs-lite[translate]\"\n```\n\nUse these options deliberately:\n\n- `mypy-boto3-translate`: service-specific standalone stubs; explicit annotations are the safest pattern.\n- `boto3-stubs[translate]`: best default when you want editor auto-discovery for `session.client(\"translate\")`.\n- `boto3-stubs-lite[translate]`: lighter on memory, but the maintainer docs note that it does not provide `session.client/resource` overloads and needs more explicit annotations.\n\n## Core Setup\n\nCreate a normal boto3 session, then annotate the Translate client:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_translate import TranslateClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: TranslateClient = session.client(\"translate\")\n\nresponse = client.translate_text(\n    Text=\"Hello, world!\",\n    SourceLanguageCode=\"en\",\n    TargetLanguageCode=\"es\",\n)\n\nprint(response[\"TranslatedText\"])\n```\n\nThis is the default pattern to use in agent-generated code:\n\n1. Create a `boto3.session.Session`.\n2. Build `session.client(\"translate\")`.\n3. Annotate it as `TranslateClient`.\n4. Keep using normal boto3 keyword arguments and response dictionaries.\n\n## Typed Usage\n\n### Client annotations\n\n`TranslateClient` is the main type you will use:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_translate import TranslateClient\n\ndef get_client() -> TranslateClient:\n    return Session(region_name=\"us-east-1\").client(\"translate\")\n```\n\nThis gives completions and type checking for Translate methods such as:\n\n- `translate_text`\n- `translate_document`\n- `list_languages`\n- `list_parallel_data`\n- `list_terminologies`\n- `list_text_translation_jobs`\n- `start_text_translation_job`\n- `describe_text_translation_job`\n- `stop_text_translation_job`\n\n### Paginators\n\nThe generated client docs expose paginator overloads for `list_terminologies`:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_translate import TranslateClient\nfrom mypy_boto3_translate.paginator import ListTerminologiesPaginator\n\nclient: TranslateClient = Session(region_name=\"us-east-1\").client(\"translate\")\npaginator: ListTerminologiesPaginator = client.get_paginator(\"list_terminologies\")\n\nfor page in paginator.paginate(MaxResults=20):\n    for item in page.get(\"TerminologyPropertiesList\", []):\n        print(item[\"Name\"])\n```\n\n### Literals\n\nUse literals when a helper should only accept documented enum-like string values:\n\n```python\nfrom mypy_boto3_translate.literals import BrevityType\n\ndef set_brevity(value: BrevityType) -> BrevityType:\n    return value\n```\n\n### Typed request and response shapes\n\nUse generated `type_defs` for helper functions and tests that build Translate payloads:\n\n```python\nfrom mypy_boto3_translate.type_defs import TermTypeDef\n\ndef build_term(source_text: str, target_text: str) -> TermTypeDef:\n    return {\n        \"SourceText\": source_text,\n        \"TargetText\": target_text,\n    }\n```\n\n## Config And Authentication\n\n`mypy-boto3-translate` does not add a separate auth layer. Authentication and region handling come from `boto3`.\n\nAccording to the official boto3 credential guide, boto3 searches for credentials in this order:\n\n1. Credentials passed directly to `boto3.client()`\n2. Credentials passed when creating `Session(...)`\n3. Environment variables\n4. Assume-role providers\n5. Web identity providers\n6. IAM Identity Center\n7. Shared credentials file\n8. Console login credentials\n9. AWS config file\n10. Boto2 config\n11. Container credential provider\n12. EC2 instance metadata / IAM role\n\nPractical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_translate import TranslateClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-east-1\")\nclient: TranslateClient = session.client(\"translate\")\n```\n\nPrefer profiles, IAM roles, or short-lived credentials over hardcoded keys.\n\n## TYPE_CHECKING Pattern\n\nIf you do not want to require the stub package in production images, gate imports behind `TYPE_CHECKING`:\n\n```python\nfrom typing import TYPE_CHECKING\n\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_translate import TranslateClient\nelse:\n    TranslateClient = object\n\ndef get_client() -> \"TranslateClient\":\n    return Session(region_name=\"us-east-1\").client(\"translate\")\n```\n\nThe maintainer docs call out this pattern as safe, and note that `pylint` may need the `object` fallback to avoid undefined-name complaints.\n\n## Common Pitfalls\n\n- `mypy-boto3-translate` is typing metadata only. Runtime calls still come from `boto3`.\n- Install `boto3` as well. The stub package does not replace the SDK.\n- Keep `boto3`, `botocore`, and the stubs aligned. A surprising type error often means version skew.\n- Use `TranslateClient` annotations if editor completion does not appear automatically.\n- Do not assume every AWS service has waiters or multiple paginators. For Translate, the generated client docs show `list_terminologies` as the paginator overload surfaced here.\n- Prefer keyword arguments for boto3 calls. The generated stubs mirror named parameters and response shapes.\n- When mocking AWS responses, use `type_defs` instead of anonymous `dict[str, Any]` where possible.\n- If PyCharm becomes slow on large literal overloads, the maintainer docs recommend trying `boto3-stubs-lite`.\n\n## Version-Sensitive Notes\n\n- PyPI lists this package as `1.42.3`, released on `2025-12-04`.\n- The maintainer states that `mypy-boto3-translate` version matches the related `boto3` version.\n- The docs are generated from `mypy-boto3-builder 8.12.0`.\n- The docs site is a generated documentation surface, so method lists and shapes track the published stub package rather than an AWS marketing guide.\n- If a field or method matters for production code, verify the exact installed versions:\n\n```bash\npython -m pip show mypy-boto3-translate\npython -m pip show boto3\npython -m pip show botocore\n```\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/mypy-boto3-translate/`\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_translate/`\n- Maintainer client docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_translate/client/`\n- Builder repository: `https://github.com/youtype/mypy_boto3_builder`\n- boto3 credential guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-wafv2/python/DOC.md",
    "content": "---\nname: mypy-boto3-wafv2\ndescription: \"Type stubs for boto3 WAFV2 clients, literals, and TypedDict request/response shapes in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.57\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,wafv2,waf,mypy,pyright,type-stubs,python\"\n---\n\n# `mypy-boto3-wafv2`\n\n## Golden Rule\n\nUse `mypy-boto3-wafv2` only for typing. Keep `boto3` installed for runtime calls, use the low-level WAFV2 client as the default surface, and set the region deliberately:\n\n- use your workload region for `Scope=\"REGIONAL\"`\n- use `region_name=\"us-east-1\"` for all `Scope=\"CLOUDFRONT\"` calls\n\nWAFV2 updates are also lock-token based. Read the object first, then pass the returned `LockToken` into `update_*` or `delete_*` operations.\n\n## Install\n\nRecommended for most editor and CI setups:\n\n```bash\npython -m pip install \"boto3-stubs[wafv2]\"\n```\n\nLower-memory alternative:\n\n```bash\npython -m pip install \"boto3-stubs-lite[wafv2]\"\n```\n\nStandalone service stubs with an explicitly pinned runtime SDK:\n\n```bash\npython -m pip install \"boto3==1.42.57\" \"mypy-boto3-wafv2==1.42.57\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"boto3==1.42.57\" \"mypy-boto3-wafv2==1.42.57\"\npoetry add \"boto3==1.42.57\" \"mypy-boto3-wafv2==1.42.57\"\n```\n\nNotes:\n\n- `boto3-stubs[wafv2]` is the easiest option when you want `Session().client(\"wafv2\")` to infer cleanly in VS Code, Pyright, or mypy.\n- `boto3-stubs-lite[wafv2]` is more RAM-friendly, but upstream notes that lite mode does not provide `session.client()` or `session.resource()` overloads, so explicit `WAFV2Client` annotations matter more.\n- Installing only `mypy-boto3-wafv2` is not enough for runtime code. This package publishes stubs only.\n\nIf you need locally generated stubs matched to a pinned boto3 version, upstream recommends:\n\n```bash\nuvx --with \"boto3==1.42.57\" mypy-boto3-builder\n```\n\n## Authentication And Setup\n\nThis package does not change AWS authentication. Runtime configuration still comes from `boto3` and the normal credentials provider chain.\n\nAWS documents this lookup order, with the common sources being:\n\n1. Explicit credentials passed to `boto3.client(...)`\n2. Explicit credentials passed to `boto3.Session(...)`\n3. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n4. Shared config and credentials files under `~/.aws/`\n5. Container or instance metadata credentials\n\nTypical local setup:\n\n```bash\naws configure\nexport AWS_PROFILE=dev\nexport AWS_DEFAULT_REGION=us-west-2\n```\n\nIf your code manages CloudFront-scoped WAF objects, override the region to `us-east-1` for those calls.\n\nExplicit typed session setup:\n\n```python\nfrom boto3.session import Session\nfrom botocore.config import Config\nfrom mypy_boto3_wafv2 import WAFV2Client\n\ndef make_wafv2_client(scope: str) -> WAFV2Client:\n    region = \"us-east-1\" if scope == \"CLOUDFRONT\" else \"us-west-2\"\n    session = Session(profile_name=\"dev\", region_name=region)\n    return session.client(\n        \"wafv2\",\n        config=Config(\n            retries={\n                \"mode\": \"standard\",\n                \"max_attempts\": 10,\n            }\n        ),\n    )\n```\n\nUse the client interface as the default. AWS documents that new boto3 features land on clients, not on the higher-level resource interface.\n\n## Core Usage\n\n### Typed client\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_wafv2 import WAFV2Client\n\nclient: WAFV2Client = Session(region_name=\"us-west-2\").client(\"wafv2\")\n\nresponse = client.list_web_acls(\n    Scope=\"REGIONAL\",\n    Limit=20,\n)\n\nfor acl in response.get(\"WebACLs\", []):\n    print(acl[\"Name\"], acl[\"ARN\"])\n```\n\nFor CloudFront or Amplify-managed WAF, use `Scope=\"CLOUDFRONT\"` and create the client in `us-east-1`.\n\n### Manual pagination with `NextMarker`\n\nWAFV2 list operations expose `NextMarker`. A simple loop is usually clearer than guessing whether a paginator exists for the exact operation you need:\n\n```python\nfrom collections.abc import Iterator\nfrom boto3.session import Session\nfrom mypy_boto3_wafv2 import WAFV2Client\n\ndef iter_web_acls(scope: str) -> Iterator[dict]:\n    region = \"us-east-1\" if scope == \"CLOUDFRONT\" else \"us-west-2\"\n    client: WAFV2Client = Session(region_name=region).client(\"wafv2\")\n\n    marker: str | None = None\n    while True:\n        kwargs = {\"Scope\": scope, \"Limit\": 100}\n        if marker:\n            kwargs[\"NextMarker\"] = marker\n\n        page = client.list_web_acls(**kwargs)\n\n        for acl in page.get(\"WebACLs\", []):\n            yield acl\n\n        marker = page.get(\"NextMarker\")\n        if not marker:\n            break\n```\n\n### Update flow with `LockToken`\n\nWAFV2 uses optimistic locking. Read the current object, keep the returned `LockToken`, then submit the update:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_wafv2 import WAFV2Client\n\nclient: WAFV2Client = Session(region_name=\"us-west-2\").client(\"wafv2\")\n\ncurrent = client.get_ip_set(\n    Name=\"office-allowlist\",\n    Scope=\"REGIONAL\",\n    Id=\"11111111-2222-3333-4444-555555555555\",\n)\n\nip_set = current[\"IPSet\"]\n\nresult = client.update_ip_set(\n    Name=ip_set[\"Name\"],\n    Scope=\"REGIONAL\",\n    Id=ip_set[\"Id\"],\n    Description=ip_set.get(\"Description\", \"\"),\n    Addresses=[\n        *ip_set[\"Addresses\"],\n        \"203.0.113.18/32\",\n    ],\n    LockToken=current[\"LockToken\"],\n)\n\nnext_lock_token = result[\"NextLockToken\"]\nprint(next_lock_token)\n```\n\nIf AWS returns `WAFOptimisticLockException`, fetch the object again and retry with the new token.\n\n### Type-only imports for production images\n\nIf production installs omit stub packages, keep imports behind `TYPE_CHECKING`:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\nfrom boto3.session import Session\n\nif TYPE_CHECKING:\n    from mypy_boto3_wafv2 import WAFV2Client\nelse:\n    WAFV2Client = object\n\ndef build_client() -> \"WAFV2Client\":\n    return Session(region_name=\"us-east-1\").client(\"wafv2\")\n```\n\n### Literals and TypedDicts\n\nThe generated helper modules are most useful when you validate fixed string values and dictionary shapes before the boto3 call site:\n\n```python\nfrom mypy_boto3_wafv2.literals import ActionValueType\nfrom mypy_boto3_wafv2.type_defs import APIKeySummaryTypeDef\n\naction: ActionValueType = \"ALLOW\"\n\ndef summarize_api_key(item: APIKeySummaryTypeDef) -> tuple[str, int]:\n    return (item[\"TokenDomains\"][0], item[\"Version\"])\n```\n\nReach for `type_defs` when helper functions build request dictionaries or when fixtures mock WAFV2 responses.\n\n## Practical Notes For Agents\n\n- Separate typing questions from runtime behavior. Retry policy, permissions, ARNs, rate limits, and service exceptions all come from AWS WAFV2 and boto3, not from the stub package.\n- Prefer explicit client factories that encode the correct region for each scope. That removes a common class of CloudFront failures.\n- Treat `LockToken` as mandatory mutable-state bookkeeping. Cache it only briefly.\n- When associating or inspecting WAF on CloudFront, remember that `get_web_acl_for_resource` is not the CloudFront path. AWS directs CloudFront callers to `GetDistributionConfig` instead.\n\n## Common Pitfalls\n\n- Installing `mypy-boto3-wafv2` without `boto3`. The package is typing-only.\n- Expecting `boto3-stubs-lite[wafv2]` to infer `Session().client(\"wafv2\")` automatically. Add an explicit `WAFV2Client` annotation in lite mode.\n- Using the wrong region for `Scope=\"CLOUDFRONT\"`. AWS requires `us-east-1` for API and SDK calls on CloudFront scope.\n- Calling `get_web_acl_for_resource` for CloudFront distributions. AWS explicitly says not to use that operation for CloudFront.\n- Reusing a stale `LockToken` after another process or deployment modified the same Web ACL, IP set, or rule group.\n- Assuming WAFV2 has a resource-oriented boto3 surface worth preferring. Stay on the client API for predictability and newer feature coverage.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to version used here `1.42.57`.\n- On `2026-03-12`, PyPI listed `mypy-boto3-wafv2 1.42.57`, released on `2026-02-25`, and the maintainer package page described it as type annotations for `boto3 WAFV2 1.42.57` generated with `mypy-boto3-builder 8.12.0`.\n- The AWS boto3 docs are rolling `latest` pages and may display neighboring `1.42.5x` doc builds. Use those pages for runtime semantics, but use the PyPI release page as the source of truth for the pinned package version.\n- Keep the runtime `boto3` version and the WAFV2 stubs line aligned. If you upgrade boto3 for new WAFV2 operations or shapes, verify that the matching stubs release exists before pinning both.\n\n## Official Sources\n\n- Maintainer docs root: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_wafv2/`\n- Maintainer client docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_wafv2/client/`\n- PyPI package page: `https://pypi.org/project/mypy-boto3-wafv2/`\n- Upstream builder repository: `https://github.com/youtype/mypy_boto3_builder`\n- AWS boto3 credentials guide: `https://docs.aws.amazon.com/boto3/latest/guide/credentials.html`\n- AWS boto3 resources guide: `https://docs.aws.amazon.com/boto3/latest/guide/resources.html`\n- AWS WAFV2 `list_web_acls`: `https://docs.aws.amazon.com/boto3/latest/reference/services/wafv2/client/list_web_acls.html`\n- AWS WAFV2 `get_ip_set`: `https://docs.aws.amazon.com/boto3/latest/reference/services/wafv2/client/get_ip_set.html`\n- AWS WAFV2 `update_ip_set`: `https://docs.aws.amazon.com/boto3/latest/reference/services/wafv2/client/update_ip_set.html`\n- AWS WAFV2 `get_web_acl_for_resource`: `https://docs.aws.amazon.com/boto3/latest/reference/services/wafv2/client/get_web_acl_for_resource.html`\n"
  },
  {
    "path": "content/aws/docs/mypy-boto3-workspaces/python/DOC.md",
    "content": "---\nname: mypy-boto3-workspaces\ndescription: \"Type stubs for boto3 WorkSpaces client, paginators, literals, and TypedDicts in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.66\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"aws,boto3,workspaces,type-stubs,mypy,pyright,python\"\n---\n\n# mypy-boto3-workspaces Python Package Guide\n\n## Golden Rule\n\n`mypy-boto3-workspaces` is a stubs-only package for static typing. It does not replace `boto3`, it does not handle AWS auth for you, and it should usually track the same version as your installed `boto3`. Use it to type `boto3.client(\"workspaces\")`, paginator calls, literals, and request/response TypedDict shapes.\n\n## Install\n\nFor direct use with this package:\n\n```bash\npython -m pip install \"boto3==1.42.66\" \"mypy-boto3-workspaces==1.42.66\"\n```\n\nIf you want the broader boto3 stubs distribution instead of the standalone service package:\n\n```bash\npython -m pip install \"boto3-stubs[workspaces]==1.42.66\"\n```\n\nIf you need a lower-memory option and can tolerate less inference:\n\n```bash\npython -m pip install \"boto3-stubs-lite[workspaces]==1.42.66\"\n```\n\nImportant install behavior:\n\n- `boto3-stubs[workspaces]` gives you boto3 typing plus the WorkSpaces service extras.\n- `boto3-stubs-lite[workspaces]` does not provide `Session().client(\"workspaces\")` overload inference, so explicit annotations become more important.\n- The standalone package is useful when you want only the WorkSpaces stubs in a typing or dev dependency set.\n\n## Authentication And Setup\n\nThis package uses normal boto3 configuration. Configure AWS credentials and region exactly as you would for any boto3 client.\n\nCommon boto3 credential sources:\n\n1. Environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION`\n2. Shared credentials and config files under `~/.aws/credentials` and `~/.aws/config`\n3. A named profile via `AWS_PROFILE` or `boto3.Session(profile_name=...)`\n4. IAM role or workload credentials on AWS infrastructure\n\nTyped client setup:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_workspaces.client import WorkSpacesClient\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nclient: WorkSpacesClient = session.client(\"workspaces\")\n```\n\nIf you prefer the top-level import:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_workspaces import WorkSpacesClient\n\nclient: WorkSpacesClient = Session(region_name=\"us-west-2\").client(\"workspaces\")\n```\n\n## Core Usage\n\n### Typed client calls\n\nUse request TypedDicts when you want stricter validation of request shapes before calling boto3:\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_workspaces.client import WorkSpacesClient\nfrom mypy_boto3_workspaces.type_defs import DescribeWorkspacesRequestTypeDef\n\nsession = Session(profile_name=\"dev\", region_name=\"us-west-2\")\nclient: WorkSpacesClient = session.client(\"workspaces\")\n\nrequest: DescribeWorkspacesRequestTypeDef = {\n    \"DirectoryId\": \"d-90670a1b1d\",\n    \"UserName\": \"alice@example.com\",\n}\n\nresponse = client.describe_workspaces(**request)\n\nfor workspace in response.get(\"Workspaces\", []):\n    print(workspace[\"WorkspaceId\"], workspace.get(\"State\"))\n```\n\n`describe_workspaces` is a common starting point, but its filters are constrained by the AWS API:\n\n- `WorkspaceIds` cannot be combined with other filters.\n- `DirectoryId` cannot be combined with other filters except its paired `UserName`.\n- `BundleId` cannot be combined with other filters.\n\n### Typed paginators\n\nThe generated docs expose paginator types for WorkSpaces operations such as `describe_workspaces` and `describe_workspace_directories`.\n\n```python\nfrom boto3.session import Session\nfrom mypy_boto3_workspaces.client import WorkSpacesClient\nfrom mypy_boto3_workspaces.paginator import DescribeWorkspacesPaginator\n\nclient: WorkSpacesClient = Session(region_name=\"us-west-2\").client(\"workspaces\")\n\npaginator: DescribeWorkspacesPaginator = client.get_paginator(\"describe_workspaces\")\n\nfor page in paginator.paginate(\n    DirectoryId=\"d-90670a1b1d\",\n    PaginationConfig={\"PageSize\": 25},\n):\n    for workspace in page.get(\"Workspaces\", []):\n        print(workspace[\"WorkspaceId\"])\n```\n\nThe maintainer docs list these WorkSpaces paginator classes in `1.42.66`:\n\n- `DescribeAccountModificationsPaginator`\n- `DescribeIpGroupsPaginator`\n- `DescribeWorkspaceBundlesPaginator`\n- `DescribeWorkspaceDirectoriesPaginator`\n- `DescribeWorkspaceImagesPaginator`\n- `DescribeWorkspacesConnectionStatusPaginator`\n- `DescribeWorkspacesPaginator`\n- `ListAccountLinksPaginator`\n- `ListAvailableManagementCidrRangesPaginator`\n\n### Literals and TypedDicts\n\nUse generated literals to avoid stringly typed state and enum values:\n\n```python\nfrom mypy_boto3_workspaces.literals import WorkspaceStateType\n\ndef is_terminal(state: WorkspaceStateType) -> bool:\n    return state in {\"STOPPED\", \"TERMINATED\", \"ERROR\"}\n```\n\nUse generated TypedDicts to make request builders and helpers safer:\n\n```python\nfrom mypy_boto3_workspaces.type_defs import RebootRequestTypeDef\n\npayload: RebootRequestTypeDef = {\n    \"RebootWorkspaceRequests\": [\n        {\"WorkspaceId\": \"ws-1234567890\"},\n    ],\n}\n```\n\n## Tooling Patterns\n\n### `TYPE_CHECKING` guard for dev-only stub installs\n\nIf stubs are installed only in dev or CI environments, guard imports so production runtime does not require the package:\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypy_boto3_workspaces.client import WorkSpacesClient\nelse:\n    WorkSpacesClient = object\n```\n\nThen annotate normally:\n\n```python\nfrom boto3.session import Session\n\nclient: WorkSpacesClient = Session(region_name=\"us-west-2\").client(\"workspaces\")\n```\n\nThis pattern is especially useful when `pylint` or runtime-only images do not include stub packages.\n\n## Common Pitfalls\n\n- Do not treat `mypy-boto3-workspaces` as the runtime SDK. You still need `boto3` installed and configured.\n- Keep the stub package version aligned with `boto3`. The project explicitly versions service stubs to match the corresponding boto3 release.\n- `boto3-stubs-lite[workspaces]` does not provide `session.client/resource` overload inference. If you use lite, annotate the client explicitly.\n- The current generated WorkSpaces docs expose a typed client, paginators, literals, and TypedDicts, but no documented `WorkSpacesServiceResource` or waiter module. Do not assume `Session().resource(\"workspaces\")` or `client.get_waiter(...)` has matching generated types for this service.\n- `describe_workspaces` filters are mutually exclusive in the ways documented by boto3. Agents often incorrectly send `WorkspaceIds` together with `DirectoryId` or `BundleId`.\n- Credentials and region issues come from boto3 configuration, not this stub package. If client creation or requests fail, debug AWS auth and region selection first.\n\n## Version-Sensitive Notes\n\n- `1.42.66` was released on March 11, 2026 and the PyPI page says it was generated with `mypy-boto3-builder 8.12.0`.\n- PyPI marks this package as `Stubs Only` and requires Python `>=3.9`.\n- PyPI project links for this package point to `youtype/mypy_boto3_builder`. Separately, the older `youtype/boto3-stubs` repository page now points to `youtype/types-boto3`. That only matters if you are migrating package families; this package is still actively published and documented for the `mypy_boto3_workspaces` import path.\n- If you generate stubs locally, the maintainer docs recommend `uvx --with 'boto3==1.42.66' mypy-boto3-builder`, then selecting the `WorkSpaces` service.\n\n## Official Sources\n\n- Maintainer docs: `https://youtype.github.io/boto3_stubs_docs/mypy_boto3_workspaces/`\n- PyPI project page: `https://pypi.org/project/mypy-boto3-workspaces/`\n- Boto3 WorkSpaces reference: `https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/workspaces.html`\n- Boto3 credentials guide: `https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html`\n"
  },
  {
    "path": "content/aws/docs/neptune/javascript/DOC.md",
    "content": "---\nname: neptune\ndescription: \"AWS SDK for JavaScript v3 client for inspecting and managing Amazon Neptune DB clusters and DB instances.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,neptune,javascript,nodejs,graph-database,db-cluster,db-instance\"\n---\n\n# Amazon Neptune SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-neptune` for Amazon Neptune control-plane APIs from JavaScript or TypeScript. Common tasks include listing Neptune clusters and instances, reading status and endpoint metadata, and automating cluster lifecycle operations.\n\nThis package manages Neptune infrastructure. It does not execute Gremlin, SPARQL, or openCypher queries against your graph endpoint.\n\n## Golden Rules\n\n- Use `NeptuneClient` plus explicit command imports.\n- Set `region` explicitly in code or through standard AWS configuration.\n- Treat create, modify, start, stop, reboot, failover, and delete flows as asynchronous operations.\n- Re-read cluster or instance state before assuming an endpoint is ready.\n- Use a graph protocol client against the Neptune endpoint for application queries.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-neptune\n```\n\nIf you want explicit profile or assume-role helpers in code:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites and AWS Configuration\n\nNeptune is regional. Configure credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n```\n\nIf you use shared AWS profiles locally, this also works with the standard AWS SDK for JavaScript v3 credential chain:\n\n```bash\nexport AWS_PROFILE=\"graph-dev\"\nexport AWS_REGION=\"us-east-1\"\n```\n\nYour IAM identity needs the Neptune actions required by the calls you make, such as `neptune:DescribeDBClusters` and `neptune:DescribeDBInstances`, plus any create, modify, delete, or tagging permissions used by your automation.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { NeptuneClient } from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { NeptuneClient } from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { NeptuneClient } from \"@aws-sdk/client-neptune\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst neptune = new NeptuneClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"graph-dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nconst response = await neptune.send(\n  new DescribeDBClustersCommand({\n    MaxRecords: 20,\n  }),\n);\n\nfor (const cluster of response.DBClusters ?? []) {\n  console.log({\n    id: cluster.DBClusterIdentifier,\n    status: cluster.Status,\n    endpoint: cluster.Endpoint,\n    readerEndpoint: cluster.ReaderEndpoint,\n    port: cluster.Port,\n  });\n}\n```\n\n## Common Workflows\n\n### List clusters with pagination\n\n`DescribeDBClustersCommand` uses `MaxRecords` and `Marker` for pagination.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nlet marker;\n\ndo {\n  const page = await neptune.send(\n    new DescribeDBClustersCommand({\n      MaxRecords: 100,\n      Marker: marker,\n    }),\n  );\n\n  for (const cluster of page.DBClusters ?? []) {\n    console.log(cluster.DBClusterIdentifier, cluster.Status);\n  }\n\n  marker = page.Marker;\n} while (marker);\n```\n\n### Inspect one cluster by identifier\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nconst { DBClusters } = await neptune.send(\n  new DescribeDBClustersCommand({\n    DBClusterIdentifier: \"graph-prod-cluster\",\n  }),\n);\n\nconst cluster = DBClusters?.[0];\n\nif (!cluster) {\n  throw new Error(\"Cluster not found\");\n}\n\nconsole.log({\n  id: cluster.DBClusterIdentifier,\n  status: cluster.Status,\n  endpoint: cluster.Endpoint,\n  readerEndpoint: cluster.ReaderEndpoint,\n  port: cluster.Port,\n});\n```\n\n### Poll until a cluster becomes available\n\nAfter a create, restore, modify, failover, start, or stop operation, read the cluster again until it reaches the state your code expects.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nasync function waitForClusterAvailable(DBClusterIdentifier) {\n  for (;;) {\n    const { DBClusters } = await neptune.send(\n      new DescribeDBClustersCommand({\n        DBClusterIdentifier,\n      }),\n    );\n\n    const cluster = DBClusters?.[0];\n\n    if (!cluster) {\n      throw new Error(`Cluster not found: ${DBClusterIdentifier}`);\n    }\n\n    console.log(cluster.Status);\n\n    if (cluster.Status === \"available\") {\n      return cluster;\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, 30000));\n  }\n}\n\nconst cluster = await waitForClusterAvailable(\"graph-prod-cluster\");\nconsole.log(cluster.Endpoint, cluster.ReaderEndpoint);\n```\n\n### List Neptune DB instances\n\n```javascript\nimport {\n  DescribeDBInstancesCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nconst response = await neptune.send(\n  new DescribeDBInstancesCommand({\n    MaxRecords: 100,\n  }),\n);\n\nfor (const instance of response.DBInstances ?? []) {\n  console.log({\n    id: instance.DBInstanceIdentifier,\n    cluster: instance.DBClusterIdentifier,\n    status: instance.DBInstanceStatus,\n    endpoint: instance.Endpoint?.Address,\n    port: instance.Endpoint?.Port,\n  });\n}\n```\n\n### Inspect one Neptune DB instance\n\n```javascript\nimport {\n  DescribeDBInstancesCommand,\n  NeptuneClient,\n} from \"@aws-sdk/client-neptune\";\n\nconst neptune = new NeptuneClient({ region: \"us-east-1\" });\n\nconst { DBInstances } = await neptune.send(\n  new DescribeDBInstancesCommand({\n    DBInstanceIdentifier: \"graph-prod-instance-1\",\n  }),\n);\n\nconst instance = DBInstances?.[0];\n\nif (!instance) {\n  throw new Error(\"Instance not found\");\n}\n\nconsole.log({\n  id: instance.DBInstanceIdentifier,\n  status: instance.DBInstanceStatus,\n  endpoint: instance.Endpoint?.Address,\n  port: instance.Endpoint?.Port,\n});\n```\n\n## Practical Notes\n\n- `@aws-sdk/client-neptune` is the management client for Neptune resources. Your application query path is separate and uses the cluster endpoint with a graph protocol client.\n- Region mismatches often look like missing resources. Keep the client region aligned with the cluster region.\n- `DescribeDBClustersCommand` paginates with `Marker` and `MaxRecords`; do not assume one response contains your full fleet.\n- Endpoint fields can be absent or incomplete while a cluster or instance is still provisioning, restoring, stopping, starting, or deleting.\n- Temporary AWS credentials require `AWS_SESSION_TOKEN` in addition to the access key and secret key.\n- Import from the package root only. Do not deep-import internal package files.\n\n## Common Pitfalls\n\n- Expecting this package to execute Gremlin, SPARQL, or openCypher queries.\n- Treating a successful control-plane response as proof that the cluster or instance is already ready.\n- Forgetting to set `AWS_REGION`, which often turns into resource-not-found or endpoint-resolution errors against the wrong region.\n- Reading only cluster inventory when you actually need instance-level state such as `DBInstanceStatus` or instance endpoint details.\n- Assuming a single `DescribeDBClustersCommand` call returns every cluster in larger accounts.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-neptune` version `3.1007.0`.\n- AWS publishes the JavaScript SDK service docs under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for command names and request shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Neptune client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/neptune/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS SDK for JavaScript v3 region configuration: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-neptune`\n"
  },
  {
    "path": "content/aws/docs/network-firewall/javascript/DOC.md",
    "content": "---\nname: network-firewall\ndescription: \"AWS SDK for JavaScript v3 client for creating and managing AWS Network Firewall rule groups, firewall policies, firewalls, protections, and logging.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,network-firewall,javascript,nodejs,vpc,security,suricata\"\n---\n\n# `@aws-sdk/client-network-firewall`\n\nUse this package to create and manage AWS Network Firewall resources from JavaScript. The common workflow is:\n\n1. Create one or more rule groups.\n2. Create a firewall policy that references those rule groups.\n3. Create a firewall in a VPC with one firewall subnet per Availability Zone.\n4. Wait for the firewall endpoints to become ready, then route VPC traffic to the endpoint IDs.\n5. Optionally configure logging and update protection settings.\n\nAWS Network Firewall is regional. Rule groups, firewall policies, firewalls, and readiness state are all scoped to the client region.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-network-firewall\n```\n\n## Prerequisites\n\nYou need:\n\n- AWS credentials with permissions for Network Firewall and the related VPC resources.\n- A target AWS Region.\n- A VPC with firewall subnets prepared for Network Firewall. Each subnet mapping must use a different Availability Zone.\n- VPC routing configured to send traffic through the firewall endpoint IDs after the firewall is ready.\n\nTypical local environment:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=my-profile\n\n# Or set static credentials instead of AWS_PROFILE.\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIn Node.js, AWS SDK v3 uses the default credential provider chain, so shared config and environment variables usually work without passing credentials in code.\n\n## Initialize the client\n\n```javascript\nimport { NetworkFirewallClient } from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Create a stateful domain list rule group\n\nFor stateful domain filtering, Network Firewall supports `RulesSourceList` with `TLS_SNI` for HTTPS and `HTTP_HOST` for HTTP. Generated rules can be allow, deny, reject, or alert lists.\n\n```javascript\nimport {\n  CreateRuleGroupCommand,\n  NetworkFirewallClient,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createDomainDenylistRuleGroup() {\n  const response = await networkFirewall.send(\n    new CreateRuleGroupCommand({\n      RuleGroupName: \"blocked-domains\",\n      Type: \"STATEFUL\",\n      Capacity: 100,\n      Description: \"Block selected HTTPS hostnames\",\n      RuleGroup: {\n        RulesSource: {\n          RulesSourceList: {\n            Targets: [\".example.com\", \"bad.example.org\"],\n            TargetTypes: [\"TLS_SNI\"],\n            GeneratedRulesType: \"DENYLIST\",\n          },\n        },\n      },\n    }),\n  );\n\n  const ruleGroupArn = response.RuleGroupResponse?.RuleGroupArn;\n  if (!ruleGroupArn) {\n    throw new Error(\"CreateRuleGroup did not return a rule group ARN\");\n  }\n\n  return ruleGroupArn;\n}\n```\n\n`Capacity` is fixed when you create the rule group. For stateful rule groups, the minimum required capacity is the number of individual rules you expect to have in the group.\n\nIf you use `RulesString` with Suricata-compatible rules instead of `RulesSourceList`, Network Firewall supports Suricata version `7.0.3`. When `StatefulRuleOptions.RuleOrder` is `STRICT_ORDER`, do not use the Suricata `priority` keyword in `RulesString`.\n\n## Create a firewall policy\n\nTo send packets that do not match your stateless rules to the stateful engine, set both stateless default action lists to `aws:forward_to_sfe`.\n\n```javascript\nimport {\n  CreateFirewallPolicyCommand,\n  NetworkFirewallClient,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createFirewallPolicy(ruleGroupArn) {\n  const response = await networkFirewall.send(\n    new CreateFirewallPolicyCommand({\n      FirewallPolicyName: \"egress-filtering-policy\",\n      Description: \"Send unmatched traffic to stateful inspection\",\n      FirewallPolicy: {\n        StatelessDefaultActions: [\"aws:forward_to_sfe\"],\n        StatelessFragmentDefaultActions: [\"aws:forward_to_sfe\"],\n        StatefulRuleGroupReferences: [\n          {\n            ResourceArn: ruleGroupArn,\n          },\n        ],\n      },\n    }),\n  );\n\n  const firewallPolicyArn = response.FirewallPolicyResponse?.FirewallPolicyArn;\n  if (!firewallPolicyArn) {\n    throw new Error(\"CreateFirewallPolicy did not return a firewall policy ARN\");\n  }\n\n  return firewallPolicyArn;\n}\n```\n\nIf you use `StatefulEngineOptions.RuleOrder: \"STRICT_ORDER\"` in the policy, the stateful rule groups attached to the policy must use compatible stateful rule options.\n\n## Create a firewall in a VPC\n\nA firewall uses subnet mappings in the VPC. Network Firewall creates one firewall endpoint in each mapped subnet.\n\n```javascript\nimport {\n  CreateFirewallCommand,\n  NetworkFirewallClient,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createFirewall({ firewallPolicyArn, vpcId, subnetIds }) {\n  const response = await networkFirewall.send(\n    new CreateFirewallCommand({\n      FirewallName: \"prod-egress-firewall\",\n      FirewallPolicyArn: firewallPolicyArn,\n      VpcId: vpcId,\n      SubnetMappings: subnetIds.map((subnetId) => ({\n        SubnetId: subnetId,\n        IPAddressType: \"IPV4\",\n      })),\n      DeleteProtection: true,\n      SubnetChangeProtection: true,\n      FirewallPolicyChangeProtection: true,\n      Description: \"Primary egress inspection firewall\",\n    }),\n  );\n\n  return {\n    firewallArn: response.Firewall?.FirewallArn,\n    firewallId: response.Firewall?.FirewallId,\n    status: response.FirewallStatus?.Status,\n  };\n}\n```\n\nEach subnet mapping must belong to a different Availability Zone. Creating the firewall does not automatically route traffic through it. After the firewall is ready, use the endpoint IDs from `DescribeFirewall` in your VPC route tables.\n\n## Wait for the firewall endpoints to be ready\n\n`DescribeFirewall` returns both the overall firewall readiness and per-subnet endpoint state.\n\n```javascript\nimport {\n  DescribeFirewallCommand,\n  NetworkFirewallClient,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nfunction sleep(ms) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForFirewallReady(firewallName) {\n  for (;;) {\n    const response = await networkFirewall.send(\n      new DescribeFirewallCommand({ FirewallName: firewallName }),\n    );\n\n    const status = response.FirewallStatus?.Status;\n    const sync = response.FirewallStatus?.ConfigurationSyncStateSummary;\n\n    if (status === \"READY\" && sync === \"IN_SYNC\") {\n      const endpointIds = Object.values(response.FirewallStatus?.SyncStates ?? {})\n        .map((state) => state.Attachment?.EndpointId)\n        .filter(Boolean);\n\n      return {\n        firewallArn: response.Firewall?.FirewallArn,\n        endpointIds,\n      };\n    }\n\n    await sleep(5000);\n  }\n}\n```\n\nA firewall is ready only when:\n\n- `FirewallStatus.Status` is `READY`\n- `FirewallStatus.ConfigurationSyncStateSummary` is `IN_SYNC`\n- each mapped subnet attachment reports `READY`\n\nUse the returned firewall endpoint IDs when you update VPC route tables to steer traffic through the firewall.\n\n## Update protection settings safely\n\nNetwork Firewall resources expose `UpdateToken` values for optimistic locking. A common pattern is to fetch the current resource, then pass its token into an update command.\n\n```javascript\nimport {\n  DescribeFirewallCommand,\n  NetworkFirewallClient,\n  UpdateFirewallDeleteProtectionCommand,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function disableDeleteProtection(firewallName) {\n  const described = await networkFirewall.send(\n    new DescribeFirewallCommand({ FirewallName: firewallName }),\n  );\n\n  await networkFirewall.send(\n    new UpdateFirewallDeleteProtectionCommand({\n      FirewallArn: described.Firewall?.FirewallArn,\n      UpdateToken: described.UpdateToken,\n      DeleteProtection: false,\n    }),\n  );\n}\n```\n\nIf you omit `UpdateToken`, the update is unconditional. If you provide it and the resource changed since your last read, the operation fails with `InvalidTokenException`, and you need to fetch the resource again.\n\n## Configure logging\n\nNetwork Firewall can send stateful engine logs to Amazon S3, CloudWatch Logs, or Kinesis Data Firehose. The supported log types are `ALERT`, `FLOW`, and `TLS`.\n\n```javascript\nimport {\n  NetworkFirewallClient,\n  UpdateLoggingConfigurationCommand,\n} from \"@aws-sdk/client-network-firewall\";\n\nconst networkFirewall = new NetworkFirewallClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function enableS3AlertLogging(firewallName) {\n  await networkFirewall.send(\n    new UpdateLoggingConfigurationCommand({\n      FirewallName: firewallName,\n      LoggingConfiguration: {\n        LogDestinationConfigs: [\n          {\n            LogType: \"ALERT\",\n            LogDestinationType: \"S3\",\n            LogDestination: {\n              bucketName: \"my-network-firewall-logs\",\n              prefix: \"alerts/\",\n            },\n          },\n        ],\n      },\n      EnableMonitoringDashboard: true,\n    }),\n  );\n}\n```\n\nFor other destinations, use these keys in `LogDestination`:\n\n- CloudWatch Logs: `logGroup`\n- Kinesis Data Firehose: `deliveryStream`\n\nIf you omit `LoggingConfiguration`, Network Firewall disables logging for the firewall.\n\n## Common pitfalls\n\n- Region mismatch: rule groups, firewall policies, and firewalls must all exist in the same region as the client.\n- Missing route updates: creating a firewall endpoint does not change VPC routing by itself.\n- Subnet layout mistakes: each subnet mapping must be in a different Availability Zone.\n- Protection flags: new firewalls start with delete, subnet-change, and firewall-policy-change protection enabled.\n- Capacity planning: rule group capacity is set at creation time; size it for the rules you expect to manage.\n- Strict rule ordering: if you choose `STRICT_ORDER`, keep the policy and attached stateful rule groups compatible, and avoid Suricata `priority` in `RulesString`.\n\n## Useful commands in this client\n\nThese SDK command classes map directly to the core service operations:\n\n- `CreateRuleGroupCommand`\n- `DescribeRuleGroupCommand`\n- `UpdateRuleGroupCommand`\n- `CreateFirewallPolicyCommand`\n- `DescribeFirewallPolicyCommand`\n- `UpdateFirewallPolicyCommand`\n- `CreateFirewallCommand`\n- `DescribeFirewallCommand`\n- `ListFirewallsCommand`\n- `UpdateFirewallDeleteProtectionCommand`\n- `UpdateLoggingConfigurationCommand`\n- `CreateTLSInspectionConfigurationCommand`\n"
  },
  {
    "path": "content/aws/docs/omics/javascript/DOC.md",
    "content": "---\nname: omics\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Omics workflows, runs, sequence stores, reference stores, and import jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,omics,healthomics,genomics,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-omics`\n\nUse `@aws-sdk/client-omics` for the Amazon Omics control plane in JavaScript: creating workflows, starting runs, managing run groups, creating sequence and reference stores, and tracking import jobs.\n\nThis client manages Omics resources. Your workflow definitions and data still live in Amazon S3, and most create or import operations are asynchronous, so plan to poll `Get*` APIs until the resource reaches a terminal state.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-omics\n```\n\nIf you want to load a named AWS profile in code instead of relying on the default credential chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Credentials and region\n\nAmazon Omics uses standard AWS SDK v3 credentials and SigV4 signing. For local development, the usual setup is a named profile plus region:\n\n```bash\nexport AWS_PROFILE=omics-dev\nexport AWS_REGION=us-east-1\n```\n\nDirect environment credentials also work:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nUseful variables for the examples below:\n\n```bash\nexport AWS_OMICS_SERVICE_ROLE_ARN=arn:aws:iam::123456789012:role/OmicsServiceRole\nexport AWS_OMICS_WORKFLOW_ZIP_URI=s3://your-bucket/workflows/example.zip\nexport AWS_OMICS_OUTPUT_S3_URI=s3://your-bucket/omics-runs/\nexport AWS_OMICS_REFERENCE_FASTA_URI=s3://your-bucket/references/hg38.fa.gz\nexport AWS_OMICS_READS_1_URI=s3://your-bucket/reads/sample_R1.fastq.gz\nexport AWS_OMICS_READS_2_URI=s3://your-bucket/reads/sample_R2.fastq.gz\nexport AWS_OMICS_RUN_PARAMETERS_JSON='{\"YOUR_WORKFLOW_INPUT\":\"s3://your-bucket/input\"}'\n```\n\nThe `roleArn` values used by run and import operations must point to an IAM role that Omics can assume and that can read the referenced S3 inputs and write the configured outputs.\n\n## Initialize the client\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { OmicsClient } from \"@aws-sdk/client-omics\";\n\nfunction requireEnv(name) {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`Missing required environment variable: ${name}`);\n  }\n\n  return value;\n}\n\nexport const omics = new OmicsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you do not pass `credentials`, the SDK uses its normal default provider chain.\n\nIf you want to force a named shared-credentials profile in code, use `fromIni` from `@aws-sdk/credential-providers`:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { OmicsClient } from \"@aws-sdk/client-omics\";\n\nconst omics = new OmicsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"omics-dev\",\n  }),\n});\n```\n\n## Common workflows\n\n### Create and inspect a run group\n\nRun groups let you cap resources for runs assigned to that group.\n\n```javascript\nimport {\n  CreateRunGroupCommand,\n  GetRunGroupCommand,\n} from \"@aws-sdk/client-omics\";\n\nconst created = await omics.send(\n  new CreateRunGroupCommand({\n    name: \"standard-analysis\",\n    maxCpus: 256,\n    maxRuns: 10,\n    requestId: randomUUID(),\n  }),\n);\n\nif (!created.id) {\n  throw new Error(\"CreateRunGroup did not return an id\");\n}\n\nconst runGroup = await omics.send(\n  new GetRunGroupCommand({\n    id: created.id,\n  }),\n);\n\nconsole.log({\n  id: runGroup.id,\n  name: runGroup.name,\n  maxCpus: runGroup.maxCpus,\n  maxRuns: runGroup.maxRuns,\n});\n```\n\nKeep the returned `id`; `StartRun` accepts `runGroupId`, not the ARN.\n\n### Create a private workflow from a zipped definition in S3\n\n`CreateWorkflow` creates **private** workflows. The workflow definition file must be a `.zip` archive. Use `engine` for the workflow type (`\"WDL\"`, `\"NEXTFLOW\"`, `\"CWL\"`, or `\"WDL_LENIENT\"`), and set `main` to the entrypoint inside the archive.\n\n```javascript\nimport {\n  CreateWorkflowCommand,\n  GetWorkflowCommand,\n} from \"@aws-sdk/client-omics\";\n\nconst created = await omics.send(\n  new CreateWorkflowCommand({\n    name: \"tumor-normal-wdl\",\n    engine: \"WDL\",\n    definitionUri: requireEnv(\"AWS_OMICS_WORKFLOW_ZIP_URI\"),\n    main: \"main.wdl\",\n    requestId: randomUUID(),\n  }),\n);\n\nif (!created.id) {\n  throw new Error(\"CreateWorkflow did not return an id\");\n}\n\nfor (;;) {\n  const workflow = await omics.send(\n    new GetWorkflowCommand({\n      id: created.id,\n    }),\n  );\n\n  console.log({\n    workflowId: workflow.id,\n    status: workflow.status,\n    parameterTemplate: workflow.parameterTemplate,\n  });\n\n  if (workflow.status === \"ACTIVE\") {\n    break;\n  }\n\n  if (workflow.status === \"FAILED\") {\n    throw new Error(workflow.statusMessage ?? \"Workflow creation failed\");\n  }\n\n  await sleep(3000);\n}\n```\n\n`GetWorkflow` returns `parameterTemplate`, which is the safest source for the input names your later `StartRun` call must use.\n\n### Start a run and poll until it finishes\n\nTo start a run, pass the workflow ID, a service role ARN, an S3 output URI, and workflow parameters that match the workflow's parameter template exactly. `StartRun` accepts a free-form JSON document for `parameters`, but Omics rejects keys that are not defined by the workflow.\n\n```javascript\nimport {\n  GetRunCommand,\n  StartRunCommand,\n} from \"@aws-sdk/client-omics\";\n\nconst workflowId = requireEnv(\"AWS_OMICS_WORKFLOW_ID\");\nconst roleArn = requireEnv(\"AWS_OMICS_SERVICE_ROLE_ARN\");\nconst outputUri = requireEnv(\"AWS_OMICS_OUTPUT_S3_URI\");\nconst parameters = JSON.parse(process.env.AWS_OMICS_RUN_PARAMETERS_JSON ?? \"{}\");\n\nconst input = {\n  workflowId,\n  workflowType: \"PRIVATE\",\n  roleArn,\n  outputUri,\n  requestId: randomUUID(),\n  name: \"example-run\",\n  parameters,\n  logLevel: \"ERROR\",\n  retentionMode: \"REMOVE\",\n};\n\nif (process.env.AWS_OMICS_RUN_GROUP_ID) {\n  input.runGroupId = process.env.AWS_OMICS_RUN_GROUP_ID;\n}\n\nif (process.env.AWS_OMICS_STORAGE_CAPACITY_GIB) {\n  input.storageCapacity = Number(process.env.AWS_OMICS_STORAGE_CAPACITY_GIB);\n} else {\n  input.storageType = \"DYNAMIC\";\n}\n\nconst started = await omics.send(new StartRunCommand(input));\n\nif (!started.id) {\n  throw new Error(\"StartRun did not return an id\");\n}\n\nfor (;;) {\n  const run = await omics.send(\n    new GetRunCommand({\n      id: started.id,\n    }),\n  );\n\n  console.log({\n    runId: run.id,\n    status: run.status,\n    statusMessage: run.statusMessage,\n    runOutputUri: run.runOutputUri,\n    logLocation: run.logLocation,\n  });\n\n  if (run.status === \"COMPLETED\") {\n    break;\n  }\n\n  if (run.status === \"FAILED\" || run.status === \"CANCELLED\") {\n    throw new Error(run.failureReason ?? run.statusMessage ?? `Run ended with ${run.status}`);\n  }\n\n  await sleep(30000);\n}\n```\n\nImportant details:\n\n- `workflowId` must be the workflow ID, not the workflow UUID.\n- If your run uses `STATIC` storage, provide `storageCapacity`. Omics does not require `storageCapacity` for `DYNAMIC` storage.\n- Reuse the same `requestId` when retrying the same logical submission so Omics can deduplicate it.\n\n### Create a reference store and import a reference genome from S3\n\nReference stores hold FASTA reference genomes. After the import job completes, fetch reference metadata if you need the `referenceArn` for aligned read set imports.\n\n```javascript\nimport {\n  CreateReferenceStoreCommand,\n  GetReferenceImportJobCommand,\n  GetReferenceMetadataCommand,\n  StartReferenceImportJobCommand,\n} from \"@aws-sdk/client-omics\";\n\nconst referenceStore = await omics.send(\n  new CreateReferenceStoreCommand({\n    name: \"human-reference-store\",\n    clientToken: randomUUID(),\n  }),\n);\n\nif (!referenceStore.id) {\n  throw new Error(\"CreateReferenceStore did not return an id\");\n}\n\nconst started = await omics.send(\n  new StartReferenceImportJobCommand({\n    referenceStoreId: referenceStore.id,\n    roleArn: requireEnv(\"AWS_OMICS_SERVICE_ROLE_ARN\"),\n    clientToken: randomUUID(),\n    sources: [\n      {\n        sourceFile: requireEnv(\"AWS_OMICS_REFERENCE_FASTA_URI\"),\n        name: \"hg38\",\n      },\n    ],\n  }),\n);\n\nif (!started.id) {\n  throw new Error(\"StartReferenceImportJob did not return an id\");\n}\n\nfor (;;) {\n  const job = await omics.send(\n    new GetReferenceImportJobCommand({\n      referenceStoreId: referenceStore.id,\n      id: started.id,\n    }),\n  );\n\n  console.log({\n    jobId: job.id,\n    status: job.status,\n    statusMessage: job.statusMessage,\n  });\n\n  if (job.status === \"COMPLETED\") {\n    const referenceId = job.sources?.[0]?.referenceId;\n\n    if (referenceId) {\n      const reference = await omics.send(\n        new GetReferenceMetadataCommand({\n          referenceStoreId: referenceStore.id,\n          id: referenceId,\n        }),\n      );\n\n      console.log({\n        referenceId: reference.id,\n        referenceArn: reference.arn,\n        status: reference.status,\n      });\n    }\n\n    break;\n  }\n\n  if (\n    job.status === \"FAILED\" ||\n    job.status === \"CANCELLED\" ||\n    job.status === \"COMPLETED_WITH_FAILURES\"\n  ) {\n    throw new Error(job.statusMessage ?? `Reference import ended with ${job.status}`);\n  }\n\n  await sleep(30000);\n}\n```\n\n### Create a sequence store and import read sets from S3\n\nSequence stores hold read sets in `FASTQ`, `BAM`, `CRAM`, or `UBAM` format. For aligned formats (`BAM` and `CRAM`), include `referenceArn` so Omics can associate the read set with the correct reference genome.\n\n```javascript\nimport {\n  CreateSequenceStoreCommand,\n  GetReadSetImportJobCommand,\n  GetSequenceStoreCommand,\n  StartReadSetImportJobCommand,\n} from \"@aws-sdk/client-omics\";\n\nconst sequenceStore = await omics.send(\n  new CreateSequenceStoreCommand({\n    name: \"example-sequence-store\",\n    clientToken: randomUUID(),\n  }),\n);\n\nif (!sequenceStore.id) {\n  throw new Error(\"CreateSequenceStore did not return an id\");\n}\n\nfor (;;) {\n  const store = await omics.send(\n    new GetSequenceStoreCommand({\n      id: sequenceStore.id,\n    }),\n  );\n\n  console.log({\n    sequenceStoreId: store.id,\n    status: store.status,\n    statusMessage: store.statusMessage,\n  });\n\n  if (store.status === \"ACTIVE\") {\n    break;\n  }\n\n  if (store.status === \"FAILED\") {\n    throw new Error(store.statusMessage ?? \"Sequence store creation failed\");\n  }\n\n  await sleep(30000);\n}\n\nconst sourceFileType = process.env.AWS_OMICS_READ_SET_FILE_TYPE ?? \"FASTQ\";\nconst readSetSource = {\n  sourceFiles: {\n    source1: requireEnv(\"AWS_OMICS_READS_1_URI\"),\n    ...(process.env.AWS_OMICS_READS_2_URI\n      ? { source2: process.env.AWS_OMICS_READS_2_URI }\n      : {}),\n  },\n  sourceFileType,\n  subjectId: \"subject-001\",\n  sampleId: \"sample-001\",\n  name: \"sample-001\",\n};\n\nif (process.env.AWS_OMICS_REFERENCE_ARN) {\n  readSetSource.referenceArn = process.env.AWS_OMICS_REFERENCE_ARN;\n}\n\nconst started = await omics.send(\n  new StartReadSetImportJobCommand({\n    sequenceStoreId: sequenceStore.id,\n    roleArn: requireEnv(\"AWS_OMICS_SERVICE_ROLE_ARN\"),\n    clientToken: randomUUID(),\n    sources: [readSetSource],\n  }),\n);\n\nif (!started.id) {\n  throw new Error(\"StartReadSetImportJob did not return an id\");\n}\n\nfor (;;) {\n  const job = await omics.send(\n    new GetReadSetImportJobCommand({\n      sequenceStoreId: sequenceStore.id,\n      id: started.id,\n    }),\n  );\n\n  console.log({\n    jobId: job.id,\n    status: job.status,\n    statusMessage: job.statusMessage,\n  });\n\n  if (job.status === \"COMPLETED\") {\n    console.log(job.sources);\n    break;\n  }\n\n  if (\n    job.status === \"FAILED\" ||\n    job.status === \"CANCELLED\" ||\n    job.status === \"COMPLETED_WITH_FAILURES\"\n  ) {\n    throw new Error(job.statusMessage ?? `Read set import ended with ${job.status}`);\n  }\n\n  await sleep(30000);\n}\n```\n\n## Important notes\n\n- `requestId` and `clientToken` are the idempotency keys for write operations. Generate them once per logical request and reuse them if you retry.\n- Most Omics provisioning and import APIs are asynchronous. Poll `GetWorkflow`, `GetRun`, `GetSequenceStore`, `GetReadSetImportJob`, or `GetReferenceImportJob` instead of assuming the initial create call is finished.\n- `StartRun` can either start a new run from `workflowId` or duplicate an existing run from `runId`. Do not mix up workflow IDs, workflow UUIDs, run IDs, and ARNs.\n- `GetRun` returns `statusMessage`, `failureReason`, `logLocation`, and `runOutputUri`; these are the first fields to inspect when a run does not reach `COMPLETED`.\n- Direct multipart uploads use `CreateMultipartReadSetUpload`, `UploadReadSetPart`, and `CompleteMultipartReadSetUpload`. Each uploaded part must be no larger than 100 MB.\n- Variant stores and annotation stores are not open to new customers starting on 2025-11-07. Existing customers can continue using those APIs.\n"
  },
  {
    "path": "content/aws/docs/opensearch/javascript/DOC.md",
    "content": "---\nname: opensearch\ndescription: \"AWS SDK for JavaScript v3 OpenSearch client for Amazon OpenSearch Service domain administration and configuration.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,opensearch,javascript,nodejs,browser,search,managed-service,control-plane\"\n---\n\n# `@aws-sdk/client-opensearch`\n\nUse this package for the control-plane API of Amazon OpenSearch Service in AWS SDK for JavaScript v3. It is the client for creating, describing, updating, tagging, and deleting managed OpenSearch domains and related service resources.\n\nThis package is not the OpenSearch data-plane client for index, document, or query requests against a domain endpoint. Use it to manage the service itself, not to run searches.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-opensearch\n```\n\nPrefer `OpenSearchClient` plus explicit command imports. Like other AWS SDK v3 service packages, it also exposes an aggregated compatibility client, but the client-and-command style is the clearer default.\n\n## Version And Runtime Notes\n\n- This doc covers package version `3.1006.0`.\n- Current AWS SDK for JavaScript v3 releases at and above `3.968.0` should be treated as Node.js 20+ in Node runtimes.\n- The SDK also supports browser-oriented bundles, but OpenSearch domain administration typically belongs on trusted backend code rather than in browser applications.\n\n## Client Setup\n\n```javascript\nimport { OpenSearchClient } from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n```\n\nIn Node.js, region plus the default credential provider chain is usually enough when credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Control Plane Vs Data Plane\n\nUse `@aws-sdk/client-opensearch` when you need to:\n\n- create or delete domains\n- inspect domain status and configuration\n- update cluster, storage, networking, or security settings\n- manage tags and other service-level metadata\n\nDo not use this package for:\n\n- indexing documents\n- running search queries\n- calling `/_search`, `/_bulk`, or other OpenSearch REST endpoints directly\n\nThose data-plane requests go to the domain endpoint itself and usually use an OpenSearch HTTP client with AWS SigV4 signing.\n\n## Core Usage Pattern\n\n```javascript\nimport {\n  DescribeDomainCommand,\n  OpenSearchClient,\n} from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n\nconst response = await opensearch.send(\n  new DescribeDomainCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.DomainStatus?.ARN);\nconsole.log(response.DomainStatus?.Endpoint);\n```\n\nThe standard v3 pattern is the same as other AWS packages: create a client once, then call `client.send(new SomeCommand(input))`.\n\n## Common Operations\n\n### List domains in an account and region\n\n```javascript\nimport {\n  ListDomainNamesCommand,\n  OpenSearchClient,\n} from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n\nconst response = await opensearch.send(\n  new ListDomainNamesCommand({}),\n);\n\nfor (const domain of response.DomainNames ?? []) {\n  console.log(domain.DomainName);\n}\n```\n\nThis is the quickest way to discover the managed OpenSearch domains visible to the current credentials in the configured region.\n\n### Inspect the current configuration for one domain\n\n```javascript\nimport {\n  DescribeDomainConfigCommand,\n  OpenSearchClient,\n} from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n\nconst response = await opensearch.send(\n  new DescribeDomainConfigCommand({\n    DomainName: \"search-prod\",\n  }),\n);\n\nconsole.log(response.DomainConfig?.ClusterConfig);\nconsole.log(response.DomainConfig?.EBSOptions);\n```\n\nUse `DescribeDomainConfig` when you need the configurable settings rather than only the summary status returned by `DescribeDomain`.\n\n### Add tags to a domain\n\n```javascript\nimport {\n  AddTagsCommand,\n  OpenSearchClient,\n} from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n\nawait opensearch.send(\n  new AddTagsCommand({\n    ARN: \"arn:aws:es:us-east-1:123456789012:domain/search-prod\",\n    TagList: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"Owner\", Value: \"search-team\" },\n    ],\n  }),\n);\n```\n\nThe tag APIs use the domain ARN, not the domain name. In practice, fetch the ARN from a prior `DescribeDomain` call or from infrastructure metadata.\n\n### Delete a domain\n\n```javascript\nimport {\n  DeleteDomainCommand,\n  OpenSearchClient,\n} from \"@aws-sdk/client-opensearch\";\n\nconst opensearch = new OpenSearchClient({ region: \"us-east-1\" });\n\nconst response = await opensearch.send(\n  new DeleteDomainCommand({\n    DomainName: \"search-dev\",\n  }),\n);\n\nconsole.log(response.DomainStatus?.Deleted);\n```\n\nDeletion is asynchronous. A successful API call means the service accepted the delete request, not that the domain and its endpoint have disappeared immediately.\n\n## OpenSearch Service Gotchas\n\n- This package manages Amazon OpenSearch Service resources. It does not replace an OpenSearch REST client for search and indexing traffic.\n- Domain create, update, and delete workflows are asynchronous. Poll domain status before assuming configuration changes are active.\n- Some domains expose VPC-only endpoints. The SDK can manage them from anywhere with AWS API access, but data-plane traffic still needs network access to the domain endpoint.\n- OpenSearch Serverless uses a different service package: `@aws-sdk/client-opensearchserverless`.\n- If your application needs document APIs, index templates, or raw query DSL calls, connect to the domain endpoint separately instead of trying to model those calls through this client.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, and assume-role credential helpers.\n- `@aws-sdk/client-opensearchserverless`: OpenSearch Serverless collections, policies, and related serverless control-plane operations.\n- `@opensearch-project/opensearch`: data-plane indexing and search requests sent to an OpenSearch endpoint, typically combined with AWS SigV4 request signing.\n\n## Practical Use Pattern\n\nFor most applications, the workflow is split across two layers:\n\n1. Use `@aws-sdk/client-opensearch` in deployment or admin code to provision and configure the managed domain.\n2. Use the domain endpoint with an OpenSearch client for runtime search and indexing traffic.\n\nKeeping those roles separate avoids a common mistake: trying to use the AWS control-plane client as if it were the OpenSearch query client.\n"
  },
  {
    "path": "content/aws/docs/organizations/javascript/DOC.md",
    "content": "---\nname: organizations\ndescription: \"AWS SDK for JavaScript v3 client for AWS Organizations account, root, OU, and policy APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,organizations,javascript,nodejs,accounts,ou,scp,governance\"\n---\n\n# `@aws-sdk/client-organizations`\n\nUse this package for AWS Organizations APIs in AWS SDK for JavaScript v3. The most common automation flows are:\n\n- inspect the current organization\n- enumerate roots, organizational units, and accounts\n- list organization policies such as service control policies\n- create organizational units\n- move accounts between roots and OUs\n\nThis client is usually used from backend or admin automation. `DescribeOrganization` can be called from any account in an organization, but many `List*` APIs require the management account or a delegated administrator. Mutating APIs such as `CreateOrganizationalUnit` and `MoveAccount` require the management account.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-organizations\n```\n\n## Prerequisites and environment\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=my-org-admin\n\nexport ORG_PARENT_ID=r-example\nexport ORG_ACCOUNT_ID=123456789012\nexport ORG_DESTINATION_PARENT_ID=ou-abcd-12345678\nexport ORG_POLICY_TYPE=SERVICE_CONTROL_POLICY\n```\n\nCreate the client with the standard AWS SDK v3 credential chain:\n\n```javascript\nimport { OrganizationsClient } from \"@aws-sdk/client-organizations\";\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if credentials already come from environment variables, shared AWS config files, IAM Identity Center, ECS task roles, or EC2 instance metadata.\n\nFor the standard `aws` partition, the Organizations endpoint rules resolve requests to the `us-east-1` endpoint. Setting `AWS_REGION=us-east-1` is the simplest default.\n\n## Common workflows\n\n### Inspect the current organization\n\nUse `DescribeOrganization` to get the organization ID, ARN, feature set, and management account identifiers.\n\n```javascript\nimport {\n  DescribeOrganizationCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await organizations.send(\n  new DescribeOrganizationCommand({}),\n);\n\nconst organization = result.Organization;\n\nif (!organization?.Id) {\n  throw new Error(\"No organization returned\");\n}\n\nconsole.log({\n  orgId: organization.Id,\n  arn: organization.Arn,\n  featureSet: organization.FeatureSet,\n  managementAccountId: organization.MasterAccountId,\n  managementAccountEmail: organization.MasterAccountEmail,\n});\n```\n\nDo not build new logic around `Organization.AvailablePolicyTypes`. That field is deprecated. Use `ListRoots` to inspect enabled policy types on each root.\n\n### List roots and their enabled policy types\n\nOrganizations `List*` APIs use `NextToken` pagination. Keep following `NextToken` until it is `null`, even if a page returns zero results.\n\n```javascript\nimport {\n  ListRootsCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst roots = [];\nlet nextToken;\n\ndo {\n  const page = await organizations.send(\n    new ListRootsCommand({\n      NextToken: nextToken,\n      MaxResults: 20,\n    }),\n  );\n\n  roots.push(...(page.Roots ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nfor (const root of roots) {\n  console.log({\n    id: root.Id,\n    arn: root.Arn,\n    name: root.Name,\n    policyTypes: root.PolicyTypes?.map((policyType) => ({\n      type: policyType.Type,\n      status: policyType.Status,\n    })),\n  });\n}\n```\n\n### List all accounts in the organization\n\nUse `ListAccounts` when you need every account in the organization. Prefer `account.State` in new code. AWS states that `account.Status` will be retired on 2026-09-09.\n\n```javascript\nimport {\n  ListAccountsCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst accounts = [];\nlet nextToken;\n\ndo {\n  const page = await organizations.send(\n    new ListAccountsCommand({\n      NextToken: nextToken,\n      MaxResults: 20,\n    }),\n  );\n\n  accounts.push(...(page.Accounts ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nfor (const account of accounts) {\n  console.log({\n    id: account.Id,\n    name: account.Name,\n    email: account.Email,\n    state: account.State,\n    joinedMethod: account.JoinedMethod,\n  });\n}\n```\n\n### List accounts directly under one root or OU\n\n`ListAccountsForParent` is not recursive. If you pass a root, you only get accounts directly under that root. If you pass an OU, you only get accounts directly inside that OU.\n\n```javascript\nimport {\n  ListAccountsForParentCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst parentId = process.env.ORG_PARENT_ID;\n\nif (!parentId) {\n  throw new Error(\"Missing ORG_PARENT_ID\");\n}\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst accounts = [];\nlet nextToken;\n\ndo {\n  const page = await organizations.send(\n    new ListAccountsForParentCommand({\n      ParentId: parentId,\n      NextToken: nextToken,\n      MaxResults: 20,\n    }),\n  );\n\n  accounts.push(...(page.Accounts ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nconsole.log(accounts.map((account) => ({\n  id: account.Id,\n  name: account.Name,\n  state: account.State,\n})));\n```\n\n## Create and reorganize OUs\n\n### List child OUs under a root or parent OU\n\n```javascript\nimport {\n  ListOrganizationalUnitsForParentCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst parentId = process.env.ORG_PARENT_ID;\n\nif (!parentId) {\n  throw new Error(\"Missing ORG_PARENT_ID\");\n}\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst ous = [];\nlet nextToken;\n\ndo {\n  const page = await organizations.send(\n    new ListOrganizationalUnitsForParentCommand({\n      ParentId: parentId,\n      NextToken: nextToken,\n      MaxResults: 20,\n    }),\n  );\n\n  ous.push(...(page.OrganizationalUnits ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nconsole.log(ous.map((ou) => ({\n  id: ou.Id,\n  arn: ou.Arn,\n  name: ou.Name,\n})));\n```\n\n### Create an organizational unit\n\n```javascript\nimport {\n  CreateOrganizationalUnitCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst parentId = process.env.ORG_PARENT_ID;\n\nif (!parentId) {\n  throw new Error(\"Missing ORG_PARENT_ID\");\n}\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await organizations.send(\n  new CreateOrganizationalUnitCommand({\n    ParentId: parentId,\n    Name: \"Sandbox\",\n  }),\n);\n\nconsole.log({\n  ouId: result.OrganizationalUnit?.Id,\n  arn: result.OrganizationalUnit?.Arn,\n  name: result.OrganizationalUnit?.Name,\n});\n```\n\n### Move an account to another OU\n\nUse `ListParents` first if you do not already know the source parent ID. In the current Organizations release, a child has only one immediate parent.\n\n```javascript\nimport {\n  ListParentsCommand,\n  MoveAccountCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst accountId = process.env.ORG_ACCOUNT_ID;\nconst destinationParentId = process.env.ORG_DESTINATION_PARENT_ID;\n\nif (!accountId) {\n  throw new Error(\"Missing ORG_ACCOUNT_ID\");\n}\n\nif (!destinationParentId) {\n  throw new Error(\"Missing ORG_DESTINATION_PARENT_ID\");\n}\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst parentsResult = await organizations.send(\n  new ListParentsCommand({\n    ChildId: accountId,\n  }),\n);\n\nconst sourceParentId = parentsResult.Parents?.[0]?.Id;\n\nif (!sourceParentId) {\n  throw new Error(\"Could not determine the current parent for the account\");\n}\n\nawait organizations.send(\n  new MoveAccountCommand({\n    AccountId: accountId,\n    SourceParentId: sourceParentId,\n    DestinationParentId: destinationParentId,\n  }),\n);\n\nconsole.log({\n  accountId,\n  sourceParentId,\n  destinationParentId,\n});\n```\n\n## Work with organization policies\n\nUse `ListPolicies` with a required `Filter`. The most common value is `SERVICE_CONTROL_POLICY`.\n\n```javascript\nimport {\n  ListPoliciesCommand,\n  OrganizationsClient,\n} from \"@aws-sdk/client-organizations\";\n\nconst filter = process.env.ORG_POLICY_TYPE ?? \"SERVICE_CONTROL_POLICY\";\n\nconst organizations = new OrganizationsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst policies = [];\nlet nextToken;\n\ndo {\n  const page = await organizations.send(\n    new ListPoliciesCommand({\n      Filter: filter,\n      NextToken: nextToken,\n      MaxResults: 20,\n    }),\n  );\n\n  policies.push(...(page.Policies ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nfor (const policy of policies) {\n  console.log({\n    id: policy.Id,\n    name: policy.Name,\n    type: policy.Type,\n    awsManaged: policy.AwsManaged,\n    description: policy.Description,\n  });\n}\n```\n\nVerified `Filter` values include `SERVICE_CONTROL_POLICY`, `RESOURCE_CONTROL_POLICY`, `TAG_POLICY`, `BACKUP_POLICY`, `AISERVICES_OPT_OUT_POLICY`, `CHATBOT_POLICY`, `DECLARATIVE_POLICY_EC2`, `SECURITYHUB_POLICY`, `INSPECTOR_POLICY`, `UPGRADE_ROLLOUT_POLICY`, `BEDROCK_POLICY`, `S3_POLICY`, and `NETWORK_SECURITY_DIRECTOR_POLICY`.\n\n## Practical notes\n\n- Keep following `NextToken` until it is `null`. Organizations `List*` APIs can return an empty page and still provide another token.\n- Prefer `account.State` over `account.Status`. AWS marks `Status` for retirement on 2026-09-09 in `DescribeAccount`, `ListAccounts`, and `ListAccountsForParent` responses.\n- Treat `Organization.AvailablePolicyTypes` as deprecated. Use `ListRoots` to inspect which policy types are enabled on a root.\n- ID formats matter: account IDs are 12 digits, root IDs look like `r-...`, and OU IDs look like `ou-...-...`.\n- `DescribeOrganization` works from any account in an organization. `ListRoots`, `ListAccounts`, `ListAccountsForParent`, `ListChildren`, `ListParents`, and `ListPolicies` require the management account or a delegated administrator. `MoveAccount` and `CreateOrganizationalUnit` require the management account.\n- Expect service errors such as `AWSOrganizationsNotInUseException`, `AccessDeniedException`, `TooManyRequestsException`, `ConcurrentModificationException`, `ParentNotFoundException`, `SourceParentNotFoundException`, `DestinationParentNotFoundException`, and `ConstraintViolationException`.\n- If you add tags while creating an OU, the caller also needs `organizations:TagResource` permission.\n"
  },
  {
    "path": "content/aws/docs/payment-cryptography/javascript/DOC.md",
    "content": "---\nname: payment-cryptography\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Payment Cryptography control-plane key management, aliases, import and export preparation, and key lifecycle operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,payment-cryptography,javascript,nodejs,control-plane,keys,aliases,cryptography\"\n---\n\n# `@aws-sdk/client-payment-cryptography`\n\nUse this package for Amazon Payment Cryptography **control-plane** operations in JavaScript and Node.js. It covers key creation and import, aliases, key metadata, import/export preparation, public-key certificate workflows, and key lifecycle actions such as enabling, disabling, deleting, and restoring keys.\n\nThis package does **not** perform data-plane cryptographic calls such as `EncryptData`, `DecryptData`, `GenerateMac`, or `TranslatePinData`. Keep that boundary clear in your app: this client manages keys and related metadata; the data plane uses a separate API.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-payment-cryptography\n```\n\nIf you need explicit credential helpers instead of the default credential chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Initialize the client\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n# export AWS_SESSION_TOKEN=...   # if you use temporary credentials\n# export AWS_PROFILE=...         # if you use shared AWS config\n```\n\n```javascript\nimport { PaymentCryptographyClient } from \"@aws-sdk/client-payment-cryptography\";\n\nconst paymentCryptography = new PaymentCryptographyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nThese are sensitive key-management APIs. In practice, use them from trusted backend code rather than directly from a browser.\n\n## What this client covers\n\nUse `@aws-sdk/client-payment-cryptography` for control-plane tasks such as:\n\n- creating keys and reading key metadata\n- creating, listing, and updating aliases\n- fetching import or export parameters for TR-34 or key-cryptogram flows\n- getting a certificate signing request or public key certificate for asymmetric keys\n- stopping key usage, starting key usage, scheduling deletion, and restoring a key\n\nMost list operations paginate with `NextToken`, so do not assume one response is complete.\n\n## Core usage pattern\n\nThe AWS SDK for JavaScript v3 uses explicit command objects:\n\n```javascript\nimport {\n  GetKeyCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst response = await client.send(\n  new GetKeyCommand({\n    KeyIdentifier: \"alias/acquirer/pin-key\",\n  }),\n);\n\nconsole.log(response.Key?.KeyArn, response.Key?.KeyState);\n```\n\nFor operations that accept `KeyIdentifier`, you can usually pass either a full key ARN or an alias name that starts with `alias/`.\n\n## Common operations\n\n### Create a key\n\n`CreateKey` requires a valid combination of immutable key attributes: `KeyUsage`, `KeyClass`, `KeyAlgorithm`, and `KeyModesOfUse`. Choose a combination that matches your payment use case.\n\n```javascript\nimport {\n  CreateKeyCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst { Key } = await client.send(\n  new CreateKeyCommand({\n    Exportable: true,\n    Enabled: true,\n    KeyCheckValueAlgorithm: \"ANSI_X9_24\",\n    KeyAttributes: {\n      KeyClass: \"SYMMETRIC_KEY\",\n      KeyAlgorithm: \"TDES_2KEY\",\n      KeyUsage: \"TR31_P0_PIN_ENCRYPTION_KEY\",\n      KeyModesOfUse: {\n        Encrypt: true,\n        Decrypt: true,\n      },\n    },\n  }),\n);\n\nconsole.log({\n  keyArn: Key?.KeyArn,\n  keyState: Key?.KeyState,\n  keyCheckValue: Key?.KeyCheckValue,\n});\n```\n\nThe key attributes are immutable after creation. If you need a different key type or algorithm later, create a new key instead of expecting an in-place update.\n\n### Create and inspect an alias\n\nAliases are region-local friendly names for keys. They must start with `alias/`, must be unique within the account and region, and always point to exactly one key at a time.\n\n```javascript\nimport {\n  CreateAliasCommand,\n  GetAliasCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst keyArn = process.env.PAYMENT_KEY_ARN;\n\nif (!keyArn) {\n  throw new Error(\"Set PAYMENT_KEY_ARN before creating an alias\");\n}\n\nconst aliasName = \"alias/acquirer/pin-key\";\n\nawait client.send(\n  new CreateAliasCommand({\n    AliasName: aliasName,\n    KeyArn: keyArn,\n  }),\n);\n\nconst { Alias } = await client.send(\n  new GetAliasCommand({\n    AliasName: aliasName,\n  }),\n);\n\nconsole.log(Alias?.AliasName, Alias?.KeyArn);\n```\n\nDeleting or re-pointing an alias does not delete or modify the underlying key.\n\n### List keys with pagination\n\n`ListKeys` uses `NextToken` pagination.\n\n```javascript\nimport {\n  ListKeysCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst keys = [];\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListKeysCommand({\n      KeyState: \"CREATE_COMPLETE\",\n      MaxResults: 50,\n      NextToken: nextToken,\n    }),\n  );\n\n  keys.push(...(page.Keys ?? []));\n  nextToken = page.NextToken;\n} while (nextToken);\n\nfor (const key of keys) {\n  console.log(key.KeyArn, key.KeyAttributes?.KeyUsage, key.Enabled);\n}\n```\n\n### Read key metadata by ARN or alias\n\n`GetKey` returns metadata only. It does not return raw key material.\n\n```javascript\nimport {\n  GetKeyCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst { Key } = await client.send(\n  new GetKeyCommand({\n    KeyIdentifier: \"alias/acquirer/pin-key\",\n  }),\n);\n\nconsole.log({\n  keyArn: Key?.KeyArn,\n  keyState: Key?.KeyState,\n  enabled: Key?.Enabled,\n  exportable: Key?.Exportable,\n  keyUsage: Key?.KeyAttributes?.KeyUsage,\n  keyAlgorithm: Key?.KeyAttributes?.KeyAlgorithm,\n  usageStartTimestamp: Key?.UsageStartTimestamp,\n  usageStopTimestamp: Key?.UsageStopTimestamp,\n});\n```\n\n### Stop and start key usage\n\nIf you need to take a key out of service without deleting it, use `StopKeyUsage`. You can later reactivate it with `StartKeyUsage`.\n\n```javascript\nimport {\n  PaymentCryptographyClient,\n  StartKeyUsageCommand,\n  StopKeyUsageCommand,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\nconst keyIdentifier = \"alias/acquirer/pin-key\";\n\nconst stopResponse = await client.send(\n  new StopKeyUsageCommand({\n    KeyIdentifier: keyIdentifier,\n  }),\n);\n\nconsole.log(\"stopped:\", stopResponse.Key?.KeyState, stopResponse.Key?.UsageStopTimestamp);\n\nconst startResponse = await client.send(\n  new StartKeyUsageCommand({\n    KeyIdentifier: keyIdentifier,\n  }),\n);\n\nconsole.log(\"started:\", startResponse.Key?.KeyState, startResponse.Key?.UsageStartTimestamp);\n```\n\n### Schedule deletion and restore a key\n\n`DeleteKey` does not delete immediately. It disables the key and schedules deletion after a waiting period. The default waiting period is 7 days, and the service model allows `DeleteKeyInDays` values from 3 to 180.\n\n```javascript\nimport {\n  DeleteKeyCommand,\n  PaymentCryptographyClient,\n  RestoreKeyCommand,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\nconst keyIdentifier = \"alias/acquirer/pin-key\";\n\nconst deleteResponse = await client.send(\n  new DeleteKeyCommand({\n    KeyIdentifier: keyIdentifier,\n    DeleteKeyInDays: 30,\n  }),\n);\n\nconsole.log(\n  deleteResponse.Key?.KeyState,\n  deleteResponse.Key?.DeletePendingTimestamp,\n);\n\nconst restoreResponse = await client.send(\n  new RestoreKeyCommand({\n    KeyIdentifier: keyIdentifier,\n  }),\n);\n\nconsole.log(restoreResponse.Key?.KeyState);\n```\n\nIf you are not sure whether a key can be retired, prefer `StopKeyUsage` first. Deletion is irreversible after the waiting period expires.\n\n### Fetch import or export parameters\n\nFor TR-34 and key-cryptogram workflows, first request the temporary certificates and token that the later import or export step needs.\n\n```javascript\nimport { writeFileSync } from \"node:fs\";\nimport {\n  GetParametersForImportCommand,\n  GetParametersForExportCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst importParams = await client.send(\n  new GetParametersForImportCommand({\n    KeyMaterialType: \"TR34_KEY_BLOCK\",\n    WrappingKeyAlgorithm: \"RSA_2048\",\n  }),\n);\n\nwriteFileSync(\"./wrapping-key-certificate.pem\", importParams.WrappingKeyCertificate ?? \"\");\nwriteFileSync(\"./wrapping-key-chain.pem\", importParams.WrappingKeyCertificateChain ?? \"\");\n\nconsole.log(importParams.ImportToken, importParams.ParametersValidUntilTimestamp);\n\nconst exportParams = await client.send(\n  new GetParametersForExportCommand({\n    KeyMaterialType: \"TR34_KEY_BLOCK\",\n    SigningKeyAlgorithm: \"RSA_2048\",\n  }),\n);\n\nwriteFileSync(\"./signing-key-certificate.pem\", exportParams.SigningKeyCertificate ?? \"\");\nwriteFileSync(\"./signing-key-chain.pem\", exportParams.SigningKeyCertificateChain ?? \"\");\n\nconsole.log(exportParams.ExportToken, exportParams.ParametersValidUntilTimestamp);\n```\n\nThe import and export tokens expire after 30 days. While valid, the same token can be reused for multiple imports or exports in the same account.\n\n### Generate a CSR for an asymmetric key pair\n\nIf you create an asymmetric key pair in Payment Cryptography, you can generate a certificate signing request directly from that key pair.\n\n```javascript\nimport { writeFileSync } from \"node:fs\";\nimport {\n  GetCertificateSigningRequestCommand,\n  PaymentCryptographyClient,\n} from \"@aws-sdk/client-payment-cryptography\";\n\nconst client = new PaymentCryptographyClient({ region: \"us-east-1\" });\n\nconst response = await client.send(\n  new GetCertificateSigningRequestCommand({\n    KeyIdentifier: \"alias/acquirer/ecdh-key\",\n    SigningAlgorithm: \"SHA256\",\n    CertificateSubject: {\n      CommonName: \"terminal.example.internal\",\n      Organization: \"Example Payments\",\n      Country: \"US\",\n    },\n  }),\n);\n\nwriteFileSync(\"./payment-cryptography-key.csr.pem\", response.CertificateSigningRequest ?? \"\");\n```\n\n## Important details and pitfalls\n\n- This client is region-scoped. Keys and aliases are created in one AWS region, and aliases are unique only within the account and region.\n- Control-plane operations in this service are documented as same-account operations; do not design around cross-account use for these calls.\n- `ListKeys`, `ListAliases`, and `ListTagsForResource` are paginated with `NextToken`.\n- `GetKey` returns metadata, not plaintext key material.\n- Alias names must start with `alias/`.\n- `DeleteKey` schedules deletion instead of removing the key immediately; the service default is 7 days.\n- If you download a public-key certificate with `GetPublicKeyCertificate`, the service describes that certificate as valid for 90 days.\n\n## Minimal backend pattern\n\nFor a typical backend integration, the safe order is:\n\n1. Create or import the key.\n2. Create an alias such as `alias/acquirer/pin-key`.\n3. Store the alias or key ARN in your application config.\n4. Use key lifecycle APIs here for management tasks.\n5. Use the Payment Cryptography data-plane API separately for actual cryptographic operations.\n"
  },
  {
    "path": "content/aws/docs/personalize/javascript/DOC.md",
    "content": "---\nname: personalize\ndescription: \"Amazon Personalize control-plane SDK for JavaScript v3 guide for datasets, training jobs, and campaign management\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,personalize,javascript,nodejs,recommendations,machine-learning,control-plane\"\n---\n\n# Amazon Personalize SDK for JavaScript v3 Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-personalize` for Amazon Personalize **control-plane** work in JavaScript: schemas, dataset groups, datasets, import jobs, solutions, solution versions, and campaigns.\n\nDo **not** use this package for live recommendation serving or event ingestion:\n\n- Use `@aws-sdk/client-personalize-runtime` for `GetRecommendations` and `GetPersonalizedRanking`.\n- Use `@aws-sdk/client-personalize-events` for `PutEvents`, `PutUsers`, `PutItems`, and related event APIs.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-personalize\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/client-personalize-runtime @aws-sdk/client-personalize-events @aws-sdk/credential-providers\n```\n\nExamples in this guide use ESM imports and the AWS SDK v3 command pattern: `client.send(new Command(input))`.\n\n## Credentials And Region\n\nThe client uses the normal AWS SDK for JavaScript v3 credential provider chain. For local development, set a region and either a profile or direct credentials.\n\nPreferred local setup:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_PROFILE=dev\n```\n\nDirect environment credentials also work:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nAmazon Personalize resources are regional. Use the same region for the client, the dataset group, and any related S3 import locations.\n\n## Initialize The Client\n\n```javascript\nimport { PersonalizeClient } from \"@aws-sdk/client-personalize\";\n\nexport const personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nFor most server-side applications, one shared client instance per region is enough.\n\n## Core Usage\n\n### List Dataset Groups\n\n`ListDatasetGroupsCommand` is the fastest way to confirm the account and region already contain the resources your application expects.\n\n```javascript\nimport {\n  ListDatasetGroupsCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nlet nextToken;\n\ndo {\n  const page = await personalize.send(\n    new ListDatasetGroupsCommand({\n      nextToken,\n      maxResults: 20,\n    }),\n  );\n\n  for (const group of page.datasetGroups ?? []) {\n    console.log(group.name, group.datasetGroupArn, group.status);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\nThe current service model publishes pagination for `ListDatasetGroups`, `ListDatasets`, `ListRecipes`, `ListSolutions`, `ListSolutionVersions`, and `ListCampaigns`.\n\n### Inspect Available Recipes\n\nFor custom dataset groups, a solution needs a recipe. Start by listing service-provided recipes, then inspect the one you plan to use.\n\n```javascript\nimport {\n  DescribeRecipeCommand,\n  ListRecipesCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst list = await personalize.send(\n  new ListRecipesCommand({\n    recipeProvider: \"SERVICE\",\n    maxResults: 20,\n  }),\n);\n\nfor (const recipe of list.recipes ?? []) {\n  console.log(recipe.name, recipe.recipeArn);\n}\n\nconst recipeArn = process.env.PERSONALIZE_RECIPE_ARN;\n\nconst describe = await personalize.send(\n  new DescribeRecipeCommand({ recipeArn }),\n);\n\nconsole.log(describe.recipe?.name);\nconsole.log(describe.recipe?.recipeType);\nconsole.log(describe.recipe?.status);\n```\n\nIf you create a **Domain dataset group** by setting `domain` on the dataset group, your workflow changes. Domain dataset groups use domain-specific resources such as recommenders. The custom workflow below omits `domain` and uses solutions, solution versions, and campaigns.\n\n### Create A Custom Dataset Group\n\n```javascript\nimport {\n  CreateDatasetGroupCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst createGroup = await personalize.send(\n  new CreateDatasetGroupCommand({\n    name: \"movies-custom-group\",\n  }),\n);\n\nconsole.log(createGroup.datasetGroupArn);\n```\n\nIf you do set `domain`, the current service model accepts `ECOMMERCE` and `VIDEO_ON_DEMAND`.\n\n### Create A Schema And Dataset\n\nAmazon Personalize requires schemas in **Avro JSON** format. For a custom interactions dataset, create the schema first and then create a dataset that points at it.\n\n```javascript\nimport {\n  CreateDatasetCommand,\n  CreateSchemaCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst datasetGroupArn = process.env.PERSONALIZE_DATASET_GROUP_ARN;\n\nconst interactionsSchema = JSON.stringify({\n  type: \"record\",\n  name: \"Interactions\",\n  namespace: \"com.amazonaws.personalize.schema\",\n  fields: [\n    { name: \"USER_ID\", type: \"string\" },\n    { name: \"ITEM_ID\", type: \"string\" },\n    { name: \"TIMESTAMP\", type: \"long\" },\n  ],\n  version: \"1.0\",\n});\n\nconst schemaResponse = await personalize.send(\n  new CreateSchemaCommand({\n    name: \"movies-interactions-schema\",\n    schema: interactionsSchema,\n  }),\n);\n\nconst datasetResponse = await personalize.send(\n  new CreateDatasetCommand({\n    name: \"movies-interactions\",\n    datasetGroupArn,\n    datasetType: \"Interactions\",\n    schemaArn: schemaResponse.schemaArn,\n  }),\n);\n\nconsole.log(schemaResponse.schemaArn);\nconsole.log(datasetResponse.datasetArn);\n```\n\nFor `CreateDatasetCommand`, the documented dataset types are `Interactions`, `Items`, `Users`, `Actions`, and `Action_Interactions`.\n\n### Start A Dataset Import Job\n\nAfter creating an empty dataset, import training data from Amazon S3 with `CreateDatasetImportJobCommand`. The IAM role must be able to read the S3 location.\n\n```javascript\nimport {\n  CreateDatasetImportJobCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst datasetArn = process.env.PERSONALIZE_DATASET_ARN;\n\nconst response = await personalize.send(\n  new CreateDatasetImportJobCommand({\n    jobName: \"movies-interactions-import\",\n    datasetArn,\n    dataSource: {\n      dataLocation: \"s3://my-personalize-data/interactions.csv\",\n    },\n    roleArn: \"arn:aws:iam::123456789012:role/PersonalizeS3ImportRole\",\n    importMode: \"FULL\",\n  }),\n);\n\nconsole.log(response.datasetImportJobArn);\n```\n\nIf you already imported bulk records before, `importMode: \"INCREMENTAL\"` is also available.\n\n### Poll Long-Running Resources Until They Become Active\n\nThe current service model does not publish Personalize waiters. Poll the matching `Describe*` API until the resource becomes `ACTIVE` or fails.\n\n```javascript\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nasync function waitForActive(label, load) {\n  for (;;) {\n    const resource = await load();\n    const status = resource?.status;\n\n    if (status === \"ACTIVE\") {\n      return resource;\n    }\n\n    if (status?.endsWith(\"FAILED\")) {\n      throw new Error(`${label} failed: ${resource.failureReason ?? status}`);\n    }\n\n    console.log(`${label} status: ${status ?? \"UNKNOWN\"}`);\n    await sleep(30_000);\n  }\n}\n```\n\nExample for a dataset import job:\n\n```javascript\nimport {\n  DescribeDatasetImportJobCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst datasetImportJobArn = process.env.PERSONALIZE_DATASET_IMPORT_JOB_ARN;\n\nconst datasetImportJob = await waitForActive(\"dataset import job\", async () => {\n  const response = await personalize.send(\n    new DescribeDatasetImportJobCommand({ datasetImportJobArn }),\n  );\n\n  return response.datasetImportJob;\n});\n\nconsole.log(datasetImportJob.status);\n```\n\n### Create A Solution, Train A Solution Version, And Deploy A Campaign\n\nFor a custom dataset group, the standard progression is:\n\n1. Create a solution.\n2. Wait for the solution to become active.\n3. Create a solution version.\n4. Wait for the solution version to become active.\n5. Create a campaign that deploys that solution version.\n\n```javascript\nimport {\n  CreateCampaignCommand,\n  CreateSolutionCommand,\n  CreateSolutionVersionCommand,\n  DescribeCampaignCommand,\n  DescribeSolutionCommand,\n  DescribeSolutionVersionCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst datasetGroupArn = process.env.PERSONALIZE_DATASET_GROUP_ARN;\nconst recipeArn = process.env.PERSONALIZE_RECIPE_ARN;\n\nconst createSolution = await personalize.send(\n  new CreateSolutionCommand({\n    name: \"movies-user-personalization\",\n    datasetGroupArn,\n    recipeArn,\n    performAutoTraining: false,\n  }),\n);\n\nconst solutionArn = createSolution.solutionArn;\n\nawait waitForActive(\"solution\", async () => {\n  const response = await personalize.send(\n    new DescribeSolutionCommand({ solutionArn }),\n  );\n\n  return response.solution;\n});\n\nconst createSolutionVersion = await personalize.send(\n  new CreateSolutionVersionCommand({\n    solutionArn,\n    trainingMode: \"FULL\",\n  }),\n);\n\nconst solutionVersionArn = createSolutionVersion.solutionVersionArn;\n\nawait waitForActive(\"solution version\", async () => {\n  const response = await personalize.send(\n    new DescribeSolutionVersionCommand({ solutionVersionArn }),\n  );\n\n  return response.solutionVersion;\n});\n\nconst createCampaign = await personalize.send(\n  new CreateCampaignCommand({\n    name: \"movies-user-personalization-campaign\",\n    solutionVersionArn,\n  }),\n);\n\nconst campaignArn = createCampaign.campaignArn;\n\nconst campaign = await waitForActive(\"campaign\", async () => {\n  const response = await personalize.send(\n    new DescribeCampaignCommand({ campaignArn }),\n  );\n\n  return response.campaign;\n});\n\nconsole.log(campaign.campaignArn, campaign.status);\n```\n\n`CreateSolutionCommand` defaults new solutions to automatic training. Set `performAutoTraining: false` if you do not want the solution to keep training automatically while it remains active.\n\n### Update Or Delete A Campaign\n\nUse `UpdateCampaignCommand` to point an existing campaign at a new solution version or to start following the latest version of a solution.\n\n```javascript\nimport {\n  PersonalizeClient,\n  UpdateCampaignCommand,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst campaignArn = process.env.PERSONALIZE_CAMPAIGN_ARN;\nconst solutionArn = process.env.PERSONALIZE_SOLUTION_ARN;\n\nawait personalize.send(\n  new UpdateCampaignCommand({\n    campaignArn,\n    solutionVersionArn: `${solutionArn}/$LATEST`,\n    campaignConfig: {\n      syncWithLatestSolutionVersion: true,\n    },\n  }),\n);\n```\n\nDelete campaigns when you no longer need them so you do not keep paying for an active deployment.\n\n```javascript\nimport {\n  DeleteCampaignCommand,\n  PersonalizeClient,\n} from \"@aws-sdk/client-personalize\";\n\nconst personalize = new PersonalizeClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait personalize.send(\n  new DeleteCampaignCommand({\n    campaignArn: process.env.PERSONALIZE_CAMPAIGN_ARN,\n  }),\n);\n```\n\n## Config And Auth Notes\n\n- `PersonalizeClient` uses the standard AWS SDK v3 credential resolution chain.\n- Keep the region consistent across the client, the dataset group, and the S3 data you import.\n- `CreateDatasetImportJobCommand` needs an S3 path in `dataSource.dataLocation` and an IAM role in `roleArn` that can read it.\n- Reuse a single client instance instead of constructing a new one for each request.\n- For custom dataset groups, omit `domain` and use solutions, solution versions, and campaigns. Setting `domain` moves you into the domain dataset group flow.\n\n## Common Pitfalls\n\n- Do not expect this package to return live recommendations. That is `@aws-sdk/client-personalize-runtime`.\n- Do not expect imports, solution training, or campaign deployment to finish in one request. These are asynchronous operations.\n- Do not skip the schema step. `CreateSchemaCommand` expects an Avro JSON schema string, and `CreateDatasetCommand` requires the schema ARN.\n- Do not leave `performAutoTraining` enabled by default unless you actually want automatic retraining.\n- Do not leave campaigns running after tests or one-off migrations. Active campaigns incur cost until you delete them.\n- Do not hardcode AWS credentials in source files. Use environment variables, shared config, or IAM roles.\n\n## Version Scope\n\n- This guide targets `@aws-sdk/client-personalize@3.1007.0`.\n- The current service model publishes paginators for `ListCampaigns`, `ListDatasetGroups`, `ListDatasetImportJobs`, `ListDatasets`, `ListRecipes`, `ListSchemas`, `ListSolutions`, and `ListSolutionVersions`.\n- The current service model does not publish Personalize waiters, so polling `Describe*` operations is the practical status-check pattern.\n- The current service model accepts dataset group domain values `ECOMMERCE` and `VIDEO_ON_DEMAND`.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Personalize client docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/personalize/\n- Amazon Personalize developer guide: https://docs.aws.amazon.com/personalize/latest/dg/what-is-personalize.html\n- Amazon Personalize API reference: https://docs.aws.amazon.com/personalize/latest/dg/API_Operations.html\n- `CreateDatasetGroup` API: https://docs.aws.amazon.com/personalize/latest/dg/API_CreateDatasetGroup.html\n- `CreateDatasetImportJob` API: https://docs.aws.amazon.com/personalize/latest/dg/API_CreateDatasetImportJob.html\n- `CreateSolution` API: https://docs.aws.amazon.com/personalize/latest/dg/API_CreateSolution.html\n- `CreateCampaign` API: https://docs.aws.amazon.com/personalize/latest/dg/API_CreateCampaign.html\n- npm package: https://www.npmjs.com/package/@aws-sdk/client-personalize\n"
  },
  {
    "path": "content/aws/docs/pinpoint/javascript/DOC.md",
    "content": "---\nname: pinpoint\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Pinpoint applications, endpoints, and direct message sending\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,pinpoint,messaging,sms,endpoints,analytics,javascript\"\n---\n\n# AWS Pinpoint SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-pinpoint` to manage Pinpoint applications, upsert endpoints, validate phone numbers, record events, and send direct messages from JavaScript or TypeScript.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-pinpoint`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1007.0`.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n- Prefer `PinpointClient` plus explicit commands for application code.\n- Treat `ApplicationId` as required configuration; most Pinpoint operations need it.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-pinpoint\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { PinpointClient } from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst applicationId = process.env.PINPOINT_APPLICATION_ID;\n\nif (!applicationId) {\n  throw new Error(\"Set PINPOINT_APPLICATION_ID before calling Pinpoint APIs.\");\n}\n```\n\n### Explicit credentials\n\n```javascript\nimport { PinpointClient } from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Credentials and Region\n\nIn Node.js, the default AWS credential provider chain is usually enough if you already authenticate with environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport PINPOINT_APPLICATION_ID=your-pinpoint-application-id\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  GetAppCommand,\n  PinpointClient,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await pinpoint.send(\n  new GetAppCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n  }),\n);\n\nconsole.log(response.ApplicationResponse?.Name);\n```\n\n## Common Operations\n\n### Create a Pinpoint application\n\nUse this once when provisioning a new project. Save the returned application ID and reuse it in later calls.\n\n```javascript\nimport {\n  CreateAppCommand,\n  PinpointClient,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nconst response = await pinpoint.send(\n  new CreateAppCommand({\n    CreateApplicationRequest: {\n      Name: \"orders-prod\",\n    },\n  }),\n);\n\nconsole.log(response.ApplicationResponse?.Id);\n```\n\n### Read application details\n\n```javascript\nimport {\n  GetAppCommand,\n  PinpointClient,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nconst { ApplicationResponse } = await pinpoint.send(\n  new GetAppCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n  }),\n);\n\nconsole.log(ApplicationResponse?.Name);\nconsole.log(ApplicationResponse?.Id);\n```\n\n### Create or update an endpoint\n\nPinpoint endpoints represent an addressable destination such as an SMS number, email address, or device token. Reuse the same `EndpointId` when you want to update an existing profile.\n\n```javascript\nimport {\n  PinpointClient,\n  UpdateEndpointCommand,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nawait pinpoint.send(\n  new UpdateEndpointCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n    EndpointId: \"user-123-sms\",\n    EndpointRequest: {\n      Address: \"+12065550100\",\n      ChannelType: \"SMS\",\n      OptOut: \"NONE\",\n      Attributes: {\n        interests: [\"product-updates\", \"receipts\"],\n      },\n      User: {\n        UserId: \"user-123\",\n        UserAttributes: {\n          tier: [\"pro\"],\n        },\n      },\n    },\n  }),\n);\n```\n\n### Delete an endpoint\n\n```javascript\nimport {\n  DeleteEndpointCommand,\n  PinpointClient,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nawait pinpoint.send(\n  new DeleteEndpointCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n    EndpointId: \"user-123-sms\",\n  }),\n);\n```\n\n### Send a direct SMS message\n\nUse `SendMessagesCommand` when you already know the destination address. For SMS, supply the address in E.164 format.\n\n```javascript\nimport {\n  PinpointClient,\n  SendMessagesCommand,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nconst response = await pinpoint.send(\n  new SendMessagesCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n    MessageRequest: {\n      Addresses: {\n        \"+12065550100\": {\n          ChannelType: \"SMS\",\n        },\n      },\n      MessageConfiguration: {\n        SMSMessage: {\n          Body: \"Your verification code is 123456\",\n          MessageType: \"TRANSACTIONAL\",\n        },\n      },\n    },\n  }),\n);\n\nconsole.log(response.MessageResponse?.Result);\n```\n\nAdd `OriginationNumber` or `SenderId` to `SMSMessage` when your Pinpoint configuration requires them.\n\n### Send a message to known Pinpoint users\n\nUse `SendUsersMessagesCommand` when your application already maps users to Pinpoint endpoints and you want Pinpoint to resolve the target endpoints for each user.\n\n```javascript\nimport {\n  PinpointClient,\n  SendUsersMessagesCommand,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nconst response = await pinpoint.send(\n  new SendUsersMessagesCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n    SendUsersMessageRequest: {\n      Users: {\n        \"user-123\": {},\n      },\n      MessageConfiguration: {\n        SMSMessage: {\n          Body: \"Your order has shipped.\",\n          MessageType: \"TRANSACTIONAL\",\n        },\n      },\n    },\n  }),\n);\n\nconsole.log(response.SendUsersMessageResponse?.Result);\n```\n\n### Record an event for an endpoint\n\nUse `PutEventsCommand` to send custom analytics or lifecycle events tied to a specific endpoint.\n\n```javascript\nimport {\n  PinpointClient,\n  PutEventsCommand,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nawait pinpoint.send(\n  new PutEventsCommand({\n    ApplicationId: process.env.PINPOINT_APPLICATION_ID,\n    EventsRequest: {\n      BatchItem: {\n        \"user-123-sms\": {\n          Endpoint: {\n            Address: \"+12065550100\",\n            ChannelType: \"SMS\",\n            OptOut: \"NONE\",\n          },\n          Events: {\n            [`order-created-${Date.now()}`]: {\n              EventType: \"order.created\",\n              Timestamp: new Date().toISOString(),\n              Metrics: {\n                value: 1,\n              },\n            },\n          },\n        },\n      },\n    },\n  }),\n);\n```\n\n### Validate a phone number before sending\n\n```javascript\nimport {\n  PhoneNumberValidateCommand,\n  PinpointClient,\n} from \"@aws-sdk/client-pinpoint\";\n\nconst pinpoint = new PinpointClient({ region: \"us-east-1\" });\n\nconst response = await pinpoint.send(\n  new PhoneNumberValidateCommand({\n    NumberValidateRequest: {\n      PhoneNumber: \"+12065550100\",\n    },\n  }),\n);\n\nconsole.log(response.NumberValidateResponse);\n```\n\n## Pinpoint-Specific Gotchas\n\n- Most commands require `ApplicationId`; store it alongside your other service configuration.\n- Use E.164 phone numbers for SMS destinations, such as `+12065550100`.\n- Reuse stable `EndpointId` values to update the same endpoint instead of creating disconnected profiles.\n- Endpoint `Attributes` and `UserAttributes` are maps of string arrays, not plain strings.\n- `SendMessagesCommand` targets explicit addresses or endpoints; `SendUsersMessagesCommand` targets user IDs that Pinpoint resolves to endpoints.\n- `SMSMessage.MessageType` is typically `TRANSACTIONAL` or `PROMOTIONAL`; choose the value that matches your use case and account configuration.\n- If your SMS setup depends on a dedicated origination number or sender ID, include it in the message configuration before sending.\n- Do not deep-import package internals from build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, STS assume-role flows, and other credential helpers.\n\n## Useful Links\n\n- AWS SDK for JavaScript v3 Pinpoint client docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/pinpoint/\n- `@aws-sdk/client-pinpoint` on npm: https://www.npmjs.com/package/@aws-sdk/client-pinpoint\n"
  },
  {
    "path": "content/aws/docs/polly/javascript/DOC.md",
    "content": "---\nname: polly\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Polly voice discovery, text-to-speech synthesis, speech marks, lexicons, and asynchronous synthesis tasks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,polly,javascript,nodejs,text-to-speech,ssml,speech-marks,lexicons\"\n---\n\n# `@aws-sdk/client-polly`\n\nUse this package for Amazon Polly text-to-speech workflows in AWS SDK for JavaScript v3. It covers:\n\n- listing voices with `DescribeVoices`\n- direct synthesis with `SynthesizeSpeech`\n- asynchronous S3 output with `StartSpeechSynthesisTask`\n- lexicon management with `PutLexicon`, `GetLexicon`, `ListLexicons`, and `DeleteLexicon`\n\nThis guide targets `@aws-sdk/client-polly@3.1007.0`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-polly\n```\n\nIf you want to force a named shared-credentials profile in code instead of relying on the default AWS provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites And Authentication\n\nPolly needs normal AWS credentials plus a region. In Node.js, the SDK can usually resolve credentials from the default provider chain, including environment variables, shared AWS config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\nexport AWS_POLLY_VOICE_ID=Joanna\nexport AWS_POLLY_OUTPUT_BUCKET=my-polly-output-bucket\n```\n\nMinimal client setup:\n\n```javascript\nimport { PollyClient } from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { PollyClient } from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nFor browser apps, do not embed long-lived AWS access keys. Polly is usually safer behind backend code or a federation flow that issues tightly scoped temporary credentials.\n\n## Core Request Rules\n\n- `Text`, `OutputFormat`, and `VoiceId` are required for `SynthesizeSpeech`.\n- `Text`, `OutputFormat`, `VoiceId`, and `OutputS3BucketName` are required for `StartSpeechSynthesisTask`.\n- `TextType` defaults to plain text; set `TextType: \"ssml\"` for SSML input.\n- `SpeechMarkTypes` only makes sense when `OutputFormat` is `\"json\"`.\n- Voice support is engine-specific. Call `DescribeVoices` before hardcoding a `VoiceId` plus `Engine` combination.\n- If you use a bilingual voice such as `Aditi`, set `LanguageCode` when you need the non-default language.\n\n## List Available Voices\n\nUse `DescribeVoicesCommand` to discover which voices and engines are available before you synthesize anything.\n\n```javascript\nimport {\n  DescribeVoicesCommand,\n  PollyClient,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken;\n\ndo {\n  const response = await polly.send(\n    new DescribeVoicesCommand({\n      Engine: \"neural\",\n      LanguageCode: \"en-US\",\n      IncludeAdditionalLanguageCodes: true,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const voice of response.Voices ?? []) {\n    console.log({\n      id: voice.Id,\n      name: voice.Name,\n      language: voice.LanguageCode,\n      additionalLanguages: voice.AdditionalLanguageCodes,\n      supportedEngines: voice.SupportedEngines,\n    });\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\nUse this as the source of truth for which voices work with `standard`, `neural`, `long-form`, or `generative` synthesis in your region.\n\n## Synthesize Audio And Save It Locally\n\nUse `SynthesizeSpeechCommand` when you want the audio bytes returned directly in the response.\n\n```javascript\nimport { writeFile } from \"node:fs/promises\";\nimport {\n  PollyClient,\n  SynthesizeSpeechCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await polly.send(\n  new SynthesizeSpeechCommand({\n    Engine: \"neural\",\n    OutputFormat: \"mp3\",\n    Text: \"Hello from Amazon Polly.\",\n    VoiceId: process.env.AWS_POLLY_VOICE_ID ?? \"Joanna\",\n  }),\n);\n\nif (!response.AudioStream) {\n  throw new Error(\"Polly returned no audio stream.\");\n}\n\nconst audioBytes = await response.AudioStream.transformToByteArray();\n\nawait writeFile(\"./hello.mp3\", Buffer.from(audioBytes));\n\nconsole.log({\n  contentType: response.ContentType,\n  requestCharacters: response.RequestCharacters,\n});\n```\n\nUse `TextType: \"ssml\"` when sending SSML:\n\n```javascript\nimport {\n  PollyClient,\n  SynthesizeSpeechCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await polly.send(\n  new SynthesizeSpeechCommand({\n    Engine: \"neural\",\n    OutputFormat: \"mp3\",\n    Text: \"<speak><break time=\\\"300ms\\\"/>Hello from SSML.</speak>\",\n    TextType: \"ssml\",\n    VoiceId: \"Joanna\",\n  }),\n);\n```\n\nAWS requires valid, well-formed SSML when `TextType` is `\"ssml\"`.\n\n## Request Speech Marks Instead Of Audio\n\nUse `OutputFormat: \"json\"` with `SpeechMarkTypes` when you need timing metadata instead of an audio file.\n\n```javascript\nimport {\n  PollyClient,\n  SynthesizeSpeechCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await polly.send(\n  new SynthesizeSpeechCommand({\n    OutputFormat: \"json\",\n    SpeechMarkTypes: [\"sentence\", \"word\"],\n    Text: \"Hello from Amazon Polly.\",\n    VoiceId: \"Joanna\",\n  }),\n);\n\nif (!response.AudioStream) {\n  throw new Error(\"Polly returned no speech-mark stream.\");\n}\n\nconst jsonLines = await response.AudioStream.transformToString();\nconst speechMarks = jsonLines\n  .trim()\n  .split(\"\\n\")\n  .filter(Boolean)\n  .map((line) => JSON.parse(line));\n\nconsole.log(speechMarks);\n```\n\nThe response field is still named `AudioStream`, but for speech marks the content type is JSON stream data rather than playable audio.\n\n## Start An Asynchronous Synthesis Task To S3\n\nUse `StartSpeechSynthesisTaskCommand` when you want Polly to write output to S3 instead of returning a streaming body directly.\n\n```javascript\nimport {\n  GetSpeechSynthesisTaskCommand,\n  PollyClient,\n  StartSpeechSynthesisTaskCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst bucketName = process.env.AWS_POLLY_OUTPUT_BUCKET;\n\nif (!bucketName) {\n  throw new Error(\"Set AWS_POLLY_OUTPUT_BUCKET.\");\n}\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst startResponse = await polly.send(\n  new StartSpeechSynthesisTaskCommand({\n    Engine: \"neural\",\n    OutputFormat: \"mp3\",\n    OutputS3BucketName: bucketName,\n    OutputS3KeyPrefix: \"polly/jobs/\",\n    Text: \"Hello from an asynchronous Polly task.\",\n    VoiceId: \"Joanna\",\n  }),\n);\n\nconst taskId = startResponse.SynthesisTask?.TaskId;\n\nif (!taskId) {\n  throw new Error(\"Polly did not return a task id.\");\n}\n\nwhile (true) {\n  const taskResponse = await polly.send(\n    new GetSpeechSynthesisTaskCommand({ TaskId: taskId }),\n  );\n\n  const task = taskResponse.SynthesisTask;\n\n  if (!task) {\n    throw new Error(\"Polly did not return task details.\");\n  }\n\n  if (task.TaskStatus === \"completed\") {\n    console.log({\n      taskId: task.TaskId,\n      outputUri: task.OutputUri,\n      status: task.TaskStatus,\n    });\n    break;\n  }\n\n  if (task.TaskStatus === \"failed\") {\n    throw new Error(task.TaskStatusReason ?? \"Speech synthesis task failed.\");\n  }\n\n  await new Promise((resolve) => setTimeout(resolve, 3000));\n}\n```\n\nPolly documents that a `SpeechSynthesisTask` remains available for 72 hours after the asynchronous task starts.\n\n## Manage Pronunciation Lexicons\n\nLexicons let you override pronunciation for specific words or phrases. Lexicons are regional and Polly documents eventual consistency for lexicon operations, so a newly written lexicon might not be available immediately for synthesis.\n\n```javascript\nimport {\n  GetLexiconCommand,\n  PollyClient,\n  PutLexiconCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst lexiconName = \"acronyms\";\n\nconst lexiconContent = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lexicon\n  version=\"1.0\"\n  xmlns=\"http://www.w3.org/2005/01/pronunciation-lexicon\"\n  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://www.w3.org/2005/01/pronunciation-lexicon http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd\"\n  alphabet=\"ipa\"\n  xml:lang=\"en-US\">\n  <lexeme>\n    <grapheme>W3C</grapheme>\n    <alias>World Wide Web Consortium</alias>\n  </lexeme>\n</lexicon>`;\n\nawait polly.send(\n  new PutLexiconCommand({\n    Name: lexiconName,\n    Content: lexiconContent,\n  }),\n);\n\nconst lexiconResponse = await polly.send(\n  new GetLexiconCommand({ Name: lexiconName }),\n);\n\nconsole.log(lexiconResponse.Lexicon?.Name);\nconsole.log(lexiconResponse.LexiconAttributes?.LanguageCode);\nconsole.log(lexiconResponse.Lexicon?.Content);\n```\n\nTo apply a lexicon during synthesis, pass its name in `LexiconNames`:\n\n```javascript\nimport {\n  PollyClient,\n  SynthesizeSpeechCommand,\n} from \"@aws-sdk/client-polly\";\n\nconst polly = new PollyClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await polly.send(\n  new SynthesizeSpeechCommand({\n    LexiconNames: [\"acronyms\"],\n    OutputFormat: \"mp3\",\n    Text: \"The W3C published a new recommendation.\",\n    VoiceId: \"Joanna\",\n  }),\n);\n```\n\n## Common Pitfalls\n\n- Do not assume a voice supports every engine. Check `DescribeVoices` first.\n- Do not send SSML without `TextType: \"ssml\"`.\n- Do not request speech marks with an audio output format. Use `OutputFormat: \"json\"`.\n- Do not assume `AudioStream` always means binary audio bytes; speech-mark responses also use `AudioStream`.\n- Do not expect immediate lexicon availability right after `PutLexiconCommand`; Polly documents eventual consistency.\n- Do not expect built-in waiters for async synthesis tasks in the current service model; poll `GetSpeechSynthesisTask` yourself.\n- Do not forget `LanguageCode` when using bilingual voices and you need a non-default language.\n\n## Version-Sensitive Notes\n\n- This guide tracks `@aws-sdk/client-polly@3.1007.0`.\n- The generated service model for this release exposes engine values `standard`, `neural`, `long-form`, and `generative`.\n- The generated service model exposes output formats `json`, `mp3`, `ogg_opus`, `ogg_vorbis`, and `pcm`.\n- The service model includes pagination for `DescribeVoices`, `ListLexicons`, and `ListSpeechSynthesisTasks`.\n- The current service model does not publish Polly waiters.\n"
  },
  {
    "path": "content/aws/docs/proton/javascript/DOC.md",
    "content": "---\nname: proton\ndescription: \"AWS Proton SDK for JavaScript guide for template discovery, environment and service lifecycle operations, and deployment inspection\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,proton,javascript,nodejs,infrastructure,platform-engineering\"\n---\n\n# AWS Proton SDK for JavaScript\n\n## Golden Rule\n\nUse `@aws-sdk/client-proton` for Proton control-plane work from JavaScript or Node.js: discover templates, create or update environments and services, manage service instances, and inspect deployment outputs.\n\nMost Proton write APIs take a `spec` field as a YAML string, not a nested JavaScript object. Keep the spec in a file that matches your Proton template bundle and load it as text.\n\n```bash\nnpm install @aws-sdk/client-proton\n```\n\nBefore you call create or update APIs, make sure the target Region already has the Proton environment template, service template, and published template versions you plan to use.\n\n## Credentials And Region\n\nProton is regional. Use the same AWS Region as your Proton templates, environments, services, linked repositories, and CodeStar connection resources.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_PROFILE=dev\n\nexport PROTON_ENV_TEMPLATE_NAME=network-env\nexport PROTON_SERVICE_TEMPLATE_NAME=orders-service\nexport PROTON_ENVIRONMENT_NAME=orders-dev\nexport PROTON_SERVICE_NAME=orders-api\nexport PROTON_SERVICE_INSTANCE_NAME=orders-api-dev\n\nexport PROTON_SERVICE_ROLE_ARN=arn:aws:iam::123456789012:role/AWSProtonServiceRole\nexport PROTON_COMPONENT_ROLE_ARN=arn:aws:iam::123456789012:role/ProtonEnvironmentComponentRole\nexport PROTON_ENV_ACCOUNT_CONNECTION_ID=12345678-1234-1234-1234-123456789012\n\nexport PROTON_REPOSITORY_CONNECTION_ARN=arn:aws:codestar-connections:us-west-2:123456789012:connection/11111111-2222-3333-4444-555555555555\nexport PROTON_REPOSITORY_ID=myorg/orders-api\nexport PROTON_REPOSITORY_BRANCH=main\n\nexport PROTON_PROVISIONING_REPO_NAME=infra-live\nexport PROTON_PROVISIONING_REPO_BRANCH=main\n```\n\nThe SDK uses the standard AWS credential provider chain in Node.js, including environment variables, shared AWS config files, IAM roles, and other standard AWS credential sources.\n\nFor environment provisioning, choose one mode and keep the request shape consistent:\n\n- AWS-managed provisioning: send `protonServiceRoleArn` or `environmentAccountConnectionId`, and omit `provisioningRepository`.\n- Self-managed provisioning: send `provisioningRepository`, and omit `protonServiceRoleArn` and `environmentAccountConnectionId`.\n\n## Client Initialization\n\n```javascript\nimport { ProtonClient } from \"@aws-sdk/client-proton\";\n\nexport const proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n## Common Workflows\n\n### Discover templates and published versions\n\nList templates first, then inspect template versions before you hardcode a template name or version.\n\n```javascript\nimport {\n  ListServiceTemplateVersionsCommand,\n  ProtonClient,\n  paginateListEnvironmentTemplates,\n  paginateListServiceTemplates,\n} from \"@aws-sdk/client-proton\";\n\nconst proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nfor await (const page of paginateListEnvironmentTemplates(\n  { client: proton },\n  {},\n)) {\n  for (const template of page.templates ?? []) {\n    console.log(\"environment template\", template.name, template.recommendedVersion);\n  }\n}\n\nfor await (const page of paginateListServiceTemplates(\n  { client: proton },\n  {},\n)) {\n  for (const template of page.templates ?? []) {\n    console.log(\"service template\", template.name, template.recommendedVersion);\n  }\n}\n\nconst { templateVersions } = await proton.send(\n  new ListServiceTemplateVersionsCommand({\n    templateName: process.env.PROTON_SERVICE_TEMPLATE_NAME,\n  }),\n);\n\nfor (const version of templateVersions ?? []) {\n  if (version.status === \"PUBLISHED\") {\n    console.log(\n      `${version.templateName} ${version.majorVersion}.${version.minorVersion}`,\n      \"recommended minor:\",\n      version.recommendedMinorVersion,\n    );\n  }\n}\n```\n\nUse the published versions from these APIs when you set `templateMajorVersion` and `templateMinorVersion` on create or update calls.\n\n### Create an environment and wait for deployment\n\n`CreateEnvironmentCommand` requires `name`, `spec`, `templateMajorVersion`, and `templateName`. The `spec` must match the schema in your environment template bundle.\n\n```javascript\nimport { readFileSync } from \"node:fs\";\nimport {\n  CreateEnvironmentCommand,\n  GetEnvironmentCommand,\n  ProtonClient,\n  waitUntilEnvironmentDeployed,\n} from \"@aws-sdk/client-proton\";\n\nconst proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst environmentSpec = readFileSync(\"./proton/environment-spec.yaml\", \"utf8\");\n\nawait proton.send(\n  new CreateEnvironmentCommand({\n    name: process.env.PROTON_ENVIRONMENT_NAME,\n    templateName: process.env.PROTON_ENV_TEMPLATE_NAME,\n    templateMajorVersion: \"1\",\n    spec: environmentSpec,\n    protonServiceRoleArn: process.env.PROTON_SERVICE_ROLE_ARN,\n    componentRoleArn: process.env.PROTON_COMPONENT_ROLE_ARN,\n  }),\n);\n\nawait waitUntilEnvironmentDeployed(\n  { client: proton, maxWaitTime: 30 * 60 },\n  { name: process.env.PROTON_ENVIRONMENT_NAME },\n);\n\nconst { environment } = await proton.send(\n  new GetEnvironmentCommand({\n    name: process.env.PROTON_ENVIRONMENT_NAME,\n  }),\n);\n\nconsole.log(environment?.deploymentStatus, environment?.templateName);\n```\n\nIf your environment uses self-managed provisioning, replace `protonServiceRoleArn` with `provisioningRepository: { name, branch, provider }` and omit both `protonServiceRoleArn` and `environmentAccountConnectionId`.\n\n### Create a service and inspect pipeline status\n\nRepository-backed service creation commonly includes `branchName`, `repositoryConnectionArn`, and `repositoryId`, but the API model does not require those fields for every service template. Send them only when your service template or provisioning model needs them.\n\n```javascript\nimport { readFileSync } from \"node:fs\";\nimport {\n  CreateServiceCommand,\n  GetServiceCommand,\n  ProtonClient,\n  waitUntilServiceCreated,\n} from \"@aws-sdk/client-proton\";\n\nconst proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst serviceSpec = readFileSync(\"./proton/service-spec.yaml\", \"utf8\");\n\nawait proton.send(\n  new CreateServiceCommand({\n    name: process.env.PROTON_SERVICE_NAME,\n    templateName: process.env.PROTON_SERVICE_TEMPLATE_NAME,\n    templateMajorVersion: \"1\",\n    spec: serviceSpec,\n    branchName: process.env.PROTON_REPOSITORY_BRANCH,\n    repositoryConnectionArn: process.env.PROTON_REPOSITORY_CONNECTION_ARN,\n    repositoryId: process.env.PROTON_REPOSITORY_ID,\n  }),\n);\n\nawait waitUntilServiceCreated(\n  { client: proton, maxWaitTime: 30 * 60 },\n  { name: process.env.PROTON_SERVICE_NAME },\n);\n\nconst { service } = await proton.send(\n  new GetServiceCommand({\n    name: process.env.PROTON_SERVICE_NAME,\n  }),\n);\n\nconsole.log(service?.status, service?.pipeline?.deploymentStatus);\n```\n\nFor service templates with pipelines, the service `spec` is still a YAML string. AWS CLI examples show a `proton: ServiceSpec` document with `pipeline` and `instances` sections, so keep the YAML in source control instead of embedding a large multiline string in your application code.\n\n### Update a service instance\n\n`UpdateServiceInstanceCommand` always requires `deploymentType`, `name`, and `serviceName`. Use `CURRENT_VERSION` when you are changing only the instance spec on the current template version.\n\n```javascript\nimport { readFileSync } from \"node:fs\";\nimport {\n  ProtonClient,\n  UpdateServiceInstanceCommand,\n  waitUntilServiceInstanceDeployed,\n} from \"@aws-sdk/client-proton\";\n\nconst proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst serviceInstanceSpec = readFileSync(\n  \"./proton/service-instance-spec.yaml\",\n  \"utf8\",\n);\n\nawait proton.send(\n  new UpdateServiceInstanceCommand({\n    name: process.env.PROTON_SERVICE_INSTANCE_NAME,\n    serviceName: process.env.PROTON_SERVICE_NAME,\n    deploymentType: \"CURRENT_VERSION\",\n    spec: serviceInstanceSpec,\n  }),\n);\n\nawait waitUntilServiceInstanceDeployed(\n  { client: proton, maxWaitTime: 30 * 60 },\n  {\n    name: process.env.PROTON_SERVICE_INSTANCE_NAME,\n    serviceName: process.env.PROTON_SERVICE_NAME,\n  },\n);\n```\n\nUse `MINOR_VERSION` or `MAJOR_VERSION` only when you are intentionally moving the service instance to a newer published template version. Use `NONE` for metadata-only updates that should not trigger a deployment.\n\nIf you are adding a brand-new instance to an existing service, use `CreateServiceInstanceCommand` with `name`, `serviceName`, and an instance `spec`, then wait with `waitUntilServiceInstanceDeployed`.\n\n### Read environment outputs and provisioned resources\n\nAfter deployment, the outputs and provisioned-resource list APIs are the practical way to discover IDs, ARNs, stack outputs, and downstream resource names.\n\n```javascript\nimport {\n  ListEnvironmentOutputsCommand,\n  ListServiceInstanceProvisionedResourcesCommand,\n  ProtonClient,\n} from \"@aws-sdk/client-proton\";\n\nconst proton = new ProtonClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { outputs } = await proton.send(\n  new ListEnvironmentOutputsCommand({\n    environmentName: process.env.PROTON_ENVIRONMENT_NAME,\n  }),\n);\n\nfor (const output of outputs ?? []) {\n  console.log(\"environment output\", output.key, output.valueString);\n}\n\nconst { provisionedResources } = await proton.send(\n  new ListServiceInstanceProvisionedResourcesCommand({\n    serviceInstanceName: process.env.PROTON_SERVICE_INSTANCE_NAME,\n    serviceName: process.env.PROTON_SERVICE_NAME,\n  }),\n);\n\nfor (const resource of provisionedResources ?? []) {\n  console.log(\n    \"provisioned resource\",\n    resource.name,\n    resource.identifier,\n    resource.provisioningEngine,\n  );\n}\n```\n\nIf you need outputs or resources for a specific deployment attempt, the output-list APIs also accept `deploymentId`.\n\n## Common Pitfalls\n\n- Sending the Proton `spec` as a JavaScript object. The current API expects a YAML string.\n- Treating `templateMajorVersion` and `templateMinorVersion` as numbers. The API model defines them as strings.\n- Creating or updating resources before checking that the target template version is `PUBLISHED`.\n- Mixing environment provisioning modes. Self-managed provisioning uses `provisioningRepository`; AWS-managed provisioning uses `protonServiceRoleArn` or `environmentAccountConnectionId`.\n- Forgetting `deploymentType` on `UpdateEnvironmentCommand` or `UpdateServiceInstanceCommand`.\n- Assuming the initial create or update call means the deployment already finished. Use Proton waiters or poll `GetEnvironment`, `GetService`, or `GetServiceInstance`.\n- Expecting list APIs to return every result in one call. Proton exposes paginators for templates, environments, services, service instances, outputs, provisioned resources, repositories, and deployments.\n- Sending repository fields for a service template that does not use repository-backed pipeline provisioning.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-proton` version `3.1007.0`.\n- The underlying Proton service model reports API version `2020-07-20`.\n- The current Proton API model exposes paginators for 21 list-style operations, including `paginateListEnvironmentTemplates`, `paginateListServices`, `paginateListServiceInstances`, and the output and provisioned-resource list APIs.\n- The current waiter set includes service and environment helpers that map to `waitUntilEnvironmentDeployed`, `waitUntilServiceCreated`, `waitUntilServiceUpdated`, `waitUntilServiceInstanceDeployed`, and `waitUntilServicePipelineDeployed` in AWS SDK for JavaScript v3.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Proton client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/proton/`\n- AWS Proton API Reference: `https://docs.aws.amazon.com/proton/latest/APIReference/Welcome.html`\n- AWS Proton Administrator Guide: `https://docs.aws.amazon.com/proton/latest/adminguide/`\n- AWS Proton User Guide: `https://docs.aws.amazon.com/proton/latest/userguide/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS CLI Proton reference: `https://docs.aws.amazon.com/cli/latest/reference/proton/`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-proton`\n"
  },
  {
    "path": "content/aws/docs/qldb/javascript/DOC.md",
    "content": "---\nname: qldb\ndescription: \"AWS SDK for JavaScript v3 client for Amazon QLDB control-plane operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.918.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,qldb,aws-sdk,javascript,nodejs,ledger\"\n---\n\n# `@aws-sdk/client-qldb` JavaScript Package Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-qldb` for **Amazon QLDB control-plane operations** in JavaScript: creating, listing, describing, updating, and deleting ledgers.\n\nThis package is **not** the session API used for PartiQL document transactions. If you need to work with ledger sessions and transaction execution, use the separate QLDB session client package instead of trying to do it through this client.\n\n## Install\n\nPin the package version you are using:\n\n```bash\nnpm install @aws-sdk/client-qldb@3.918.0\n```\n\nIf you want to load a named AWS profile explicitly in code, install the credential providers package too:\n\n```bash\nnpm install @aws-sdk/client-qldb@3.918.0 @aws-sdk/credential-providers@3.918.0\n```\n\n## Authentication And Region Setup\n\nThe client uses the normal AWS SDK for JavaScript v3 credential chain. In practice, the safest setups are:\n\n- local development with `aws configure` and a named profile\n- AWS-hosted runtimes with an attached IAM role\n- temporary credentials instead of hardcoded long-lived keys\n\nTypical local setup:\n\n```bash\naws configure --profile dev\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n```\n\nIf you are using environment-variable credentials directly, the SDK also reads the usual values:\n\n```bash\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\nexport AWS_REGION=us-east-1\n```\n\nKeep secrets out of source control. Prefer shared AWS config, IAM roles, or other temporary-credential flows when possible.\n\n## Initialize The Client\n\n### Default credential chain\n\n```javascript\nimport { QLDBClient } from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit named profile\n\n```javascript\nimport { QLDBClient } from \"@aws-sdk/client-qldb\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nPass `region` explicitly unless your application already centralizes region resolution elsewhere.\n\n## Common Workflows\n\n### List ledgers\n\n```javascript\nimport { QLDBClient, ListLedgersCommand } from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function listLedgers() {\n  const response = await client.send(\n    new ListLedgersCommand({\n      MaxResults: 10,\n    })\n  );\n\n  for (const ledger of response.Ledgers ?? []) {\n    console.log(ledger.Name, ledger.State);\n  }\n\n  return response.NextToken;\n}\n```\n\nUse `NextToken` to continue paging when you need the full ledger list.\n\n### Create a ledger\n\n`PermissionsMode` is required. The API supports QLDB's permissions modes; the example below uses `STANDARD`.\n\n```javascript\nimport { QLDBClient, CreateLedgerCommand } from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function createLedger(name) {\n  const response = await client.send(\n    new CreateLedgerCommand({\n      Name: name,\n      PermissionsMode: \"STANDARD\",\n      DeletionProtection: true,\n    })\n  );\n\n  console.log(response.Name, response.State, response.Arn);\n  return response;\n}\n\nawait createLedger(\"app-ledger\");\n```\n\n### Describe a ledger\n\n```javascript\nimport { QLDBClient, DescribeLedgerCommand } from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function describeLedger(name) {\n  const response = await client.send(\n    new DescribeLedgerCommand({\n      Name: name,\n    })\n  );\n\n  console.log({\n    name: response.Name,\n    state: response.State,\n    permissionsMode: response.PermissionsMode,\n    deletionProtection: response.DeletionProtection,\n  });\n\n  return response;\n}\n```\n\n### Update deletion protection\n\nLedger deletion protection is controlled through `UpdateLedgerCommand`.\n\n```javascript\nimport { QLDBClient, UpdateLedgerCommand } from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function setDeletionProtection(name, enabled) {\n  return client.send(\n    new UpdateLedgerCommand({\n      Name: name,\n      DeletionProtection: enabled,\n    })\n  );\n}\n\nawait setDeletionProtection(\"app-ledger\", false);\n```\n\n### Delete a ledger\n\nIf deletion protection is enabled, disable it first and then call `DeleteLedgerCommand`.\n\n```javascript\nimport {\n  QLDBClient,\n  UpdateLedgerCommand,\n  DeleteLedgerCommand,\n} from \"@aws-sdk/client-qldb\";\n\nconst client = new QLDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function deleteLedger(name) {\n  await client.send(\n    new UpdateLedgerCommand({\n      Name: name,\n      DeletionProtection: false,\n    })\n  );\n\n  await client.send(\n    new DeleteLedgerCommand({\n      Name: name,\n    })\n  );\n}\n\nawait deleteLedger(\"app-ledger\");\n```\n\n## What This Package Does Not Cover\n\n- It does not run PartiQL statements or manage QLDB session transactions.\n- It does not replace AWS credential or IAM setup.\n- It does not give you a higher-level document client; you work with the generated command classes directly.\n\nTreat this package as the QLDB **management** client.\n\n## Common Pitfalls\n\n### Mixing up QLDB and QLDB Session APIs\n\n`@aws-sdk/client-qldb` manages ledgers and related control-plane resources. It is the wrong client for transaction execution against ledger documents.\n\n### Forgetting to set a region\n\nAlways provide `region` directly or make sure your runtime exports `AWS_REGION`. Region resolution errors look like credential problems surprisingly often.\n\n### Deletion protection blocks ledger removal\n\nIf a ledger was created with `DeletionProtection: true`, `DeleteLedgerCommand` will not succeed until you disable it with `UpdateLedgerCommand`.\n\n### Copying older v2 examples\n\nThis package is the modular AWS SDK for JavaScript v3 client. Prefer imports from `@aws-sdk/client-qldb` and `client.send(new SomeCommand(...))` over older `aws-sdk` v2 examples.\n\n## Version-Sensitive Notes\n\n- This guide targets `@aws-sdk/client-qldb` version `3.918.0`.\n- The package is part of the modular AWS SDK for JavaScript v3 line.\n- Amazon QLDB's developer guide says the service reached end of support on July 31, 2025, so this package is primarily relevant for maintaining existing QLDB integrations.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 QLDB client docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/qldb/\n- npm package page: https://www.npmjs.com/package/@aws-sdk/client-qldb\n- AWS SDK for JavaScript v3 credential settings for Node.js: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html\n- Amazon QLDB developer guide API reference: https://docs.aws.amazon.com/qldb/latest/developerguide/api-reference.html\n- Amazon QLDB overview and end-of-support notice: https://docs.aws.amazon.com/qldb/latest/developerguide/what-is.html\n"
  },
  {
    "path": "content/aws/docs/ram/javascript/DOC.md",
    "content": "---\nname: ram\ndescription: \"AWS SDK for JavaScript v3 RAM client for creating, sharing, inspecting, and accepting AWS Resource Access Manager resource shares.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,ram,javascript,nodejs,resource-sharing,organizations\"\n---\n\n# `@aws-sdk/client-ram`\n\nUse this package to manage AWS Resource Access Manager (RAM) resource shares from JavaScript. Common tasks include creating a resource share, attaching resources and principals, listing shares you own or received from other accounts, accepting invitations, inspecting share permissions, and deleting a share.\n\nPrefer `RAMClient` with explicit command imports.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ram\n```\n\nIf you want explicit profile or assume-role credential helpers in application code, install the credential providers package too:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_PROFILE=\"dev\"\n```\n\nOr with direct credentials:\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nIn Node.js, the default AWS SDK credential provider chain is usually enough if credentials already come from environment variables, shared AWS config, ECS, EC2 instance metadata, or IAM Identity Center.\n\nIf you want to share with an AWS Organization or organizational unit, first enable RAM sharing with Organizations. AWS documents that `EnableSharingWithAwsOrganization` must be called from the organization's management account and that it creates the service-linked role `AWSServiceRoleForResourceAccessManager`.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { RAMClient } from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit profile-based credentials\n\n```javascript\nimport { RAMClient } from \"@aws-sdk/client-ram\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst ram = new RAMClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetResourceSharesCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: \"us-east-1\" });\n\nconst response = await ram.send(\n  new GetResourceSharesCommand({\n    resourceOwner: \"SELF\",\n    maxResults: 25,\n  }),\n);\n\nconsole.log(response.resourceShares ?? []);\n```\n\n## Common Workflows\n\n### Enable sharing with AWS Organizations\n\nUse this once before sharing with organization or OU principals.\n\n```javascript\nimport {\n  EnableSharingWithAwsOrganizationCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nawait ram.send(new EnableSharingWithAwsOrganizationCommand({}));\n```\n\n### Create a resource share\n\nThis example shares an existing resource ARN with one AWS account. If you omit `permissionArns`, RAM attaches the default permission version for each resource type in the share.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  CreateResourceShareCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst createResponse = await ram.send(\n  new CreateResourceShareCommand({\n    name: \"network-core-share\",\n    resourceArns: [\n      \"arn:aws:ec2:us-east-1:123456789012:transit-gateway/tgw-0123456789abcdef0\",\n    ],\n    principals: [\"210987654321\"],\n    allowExternalPrincipals: false,\n    tags: [\n      { key: \"environment\", value: \"prod\" },\n      { key: \"owner\", value: \"networking\" },\n    ],\n    clientToken: randomUUID(),\n  }),\n);\n\nconst resourceShareArn = createResponse.resourceShare?.resourceShareArn;\nconsole.log(resourceShareArn);\n```\n\nPrincipals can be AWS account IDs, organization ARNs, OU ARNs, IAM role/user ARNs, or service principal names. AWS notes that not all resource types can be shared with IAM roles and users.\n\n### Add or remove principals and resources on an existing share\n\nUse `AssociateResourceShareCommand` to add resources or principals after creation, and `DisassociateResourceShareCommand` to remove them later.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  AssociateResourceShareCommand,\n  DisassociateResourceShareCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst resourceShareArn = \"arn:aws:ram:us-east-1:123456789012:resource-share/rs-12345678\";\n\nawait ram.send(\n  new AssociateResourceShareCommand({\n    resourceShareArn,\n    principals: [\"210987654321\"],\n    resourceArns: [\n      \"arn:aws:ec2:us-east-1:123456789012:subnet/subnet-0123456789abcdef0\",\n    ],\n    clientToken: randomUUID(),\n  }),\n);\n\nawait ram.send(\n  new DisassociateResourceShareCommand({\n    resourceShareArn,\n    principals: [\"210987654321\"],\n    clientToken: randomUUID(),\n  }),\n);\n```\n\n### List shares you own or shares other accounts shared with you\n\n`resourceOwner` is required and must be either `SELF` or `OTHER-ACCOUNTS`.\n\nAWS documents an important pagination detail for RAM: paginated operations can return an empty page even when more results still exist. Keep requesting pages until `nextToken` is `null` or absent.\n\n```javascript\nimport {\n  GetResourceSharesCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function listAllResourceShares(resourceOwner) {\n  const shares = [];\n  let nextToken;\n\n  do {\n    const page = await ram.send(\n      new GetResourceSharesCommand({\n        resourceOwner,\n        maxResults: 50,\n        nextToken,\n      }),\n    );\n\n    shares.push(...(page.resourceShares ?? []));\n    nextToken = page.nextToken;\n  } while (nextToken);\n\n  return shares;\n}\n\nconst ownedShares = await listAllResourceShares(\"SELF\");\nconst receivedShares = await listAllResourceShares(\"OTHER-ACCOUNTS\");\n\nconsole.log({ ownedShares, receivedShares });\n```\n\n### Accept or reject a resource share invitation\n\nIf another account shares a resource with you through an invitation flow, list invitations first and then accept or reject the one you want.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  AcceptResourceShareInvitationCommand,\n  GetResourceShareInvitationsCommand,\n  RAMClient,\n  RejectResourceShareInvitationCommand,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nconst invitationsResponse = await ram.send(\n  new GetResourceShareInvitationsCommand({\n    maxResults: 50,\n  }),\n);\n\nconst invitation = (invitationsResponse.resourceShareInvitations ?? []).find(\n  (item) => item.status === \"PENDING\",\n);\n\nif (!invitation?.resourceShareInvitationArn) {\n  throw new Error(\"No pending RAM invitation found.\");\n}\n\nconst action = \"accept\";\n\nif (action === \"accept\") {\n  await ram.send(\n    new AcceptResourceShareInvitationCommand({\n      resourceShareInvitationArn: invitation.resourceShareInvitationArn,\n      clientToken: randomUUID(),\n    }),\n  );\n} else {\n  await ram.send(\n    new RejectResourceShareInvitationCommand({\n      resourceShareInvitationArn: invitation.resourceShareInvitationArn,\n      clientToken: randomUUID(),\n    }),\n  );\n}\n```\n\nChoose the branch that matches your application flow.\n\n### Inspect resources, principals, and permissions for a share\n\nUse these calls when you need to audit what is attached to a share.\n\n```javascript\nimport {\n  ListPrincipalsCommand,\n  ListResourceSharePermissionsCommand,\n  ListResourcesCommand,\n  RAMClient,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\nconst resourceShareArn = \"arn:aws:ram:us-east-1:123456789012:resource-share/rs-12345678\";\n\nconst [resourcesPage, principalsPage, permissionsPage] = await Promise.all([\n  ram.send(\n    new ListResourcesCommand({\n      resourceOwner: \"SELF\",\n      resourceShareArns: [resourceShareArn],\n      maxResults: 50,\n    }),\n  ),\n  ram.send(\n    new ListPrincipalsCommand({\n      resourceOwner: \"SELF\",\n      resourceShareArns: [resourceShareArn],\n      maxResults: 50,\n    }),\n  ),\n  ram.send(\n    new ListResourceSharePermissionsCommand({\n      resourceShareArn,\n      maxResults: 50,\n    }),\n  ),\n]);\n\nconsole.log(resourcesPage.resources ?? []);\nconsole.log(principalsPage.principals ?? []);\nconsole.log(permissionsPage.permissions ?? []);\n```\n\nFor `ListResourcesCommand`, you can also filter by `resourceType`, `resourceArns`, `principal`, or `resourceRegionScope` (`REGIONAL` or `GLOBAL`).\n\n### Update or delete a share\n\nUse `UpdateResourceShareCommand` to rename a share or change whether external principals are allowed. Use `DeleteResourceShareCommand` to stop sharing through that share. AWS notes that deleting a resource share does not delete the underlying resources.\n\n```javascript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  DeleteResourceShareCommand,\n  RAMClient,\n  UpdateResourceShareCommand,\n} from \"@aws-sdk/client-ram\";\n\nconst ram = new RAMClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\nconst resourceShareArn = \"arn:aws:ram:us-east-1:123456789012:resource-share/rs-12345678\";\n\nawait ram.send(\n  new UpdateResourceShareCommand({\n    resourceShareArn,\n    name: \"network-core-share-prod\",\n    allowExternalPrincipals: false,\n    clientToken: randomUUID(),\n  }),\n);\n\nawait ram.send(\n  new DeleteResourceShareCommand({\n    resourceShareArn,\n    clientToken: randomUUID(),\n  }),\n);\n```\n\n## RAM-Specific Gotchas\n\n- Continue paginating until `nextToken` is empty or `null`, even if a page returns zero items. AWS RAM explicitly documents this behavior for paginated operations.\n- Set `allowExternalPrincipals` explicitly when creating or updating a share. AWS documents that the default is `true`.\n- `allowExternalPrincipals: false` only has meaning when your account is part of an AWS Organization.\n- If you share with organization or OU principals, call `EnableSharingWithAwsOrganization` first from the organization's management account.\n- Reuse a `clientToken` only when retrying the same request with the same parameters. Changing parameters while reusing the token can cause `IdempotentParameterMismatch`.\n- If you omit `permissionArns` on `CreateResourceShare`, RAM applies the default permission version for each included resource type.\n- Not every resource type supports every principal type. AWS documents that IAM roles and IAM users are not supported for all RAM-shareable resources.\n- `DeleteResourceShare` stops the share; it does not delete the underlying resources.\n\n## Related Packages\n\n- `@aws-sdk/credential-providers` for `fromIni`, SSO, and assume-role credential loading.\n"
  },
  {
    "path": "content/aws/docs/rds/javascript/DOC.md",
    "content": "---\nname: rds\ndescription: \"AWS SDK for JavaScript v3 RDS client for managing DB instances, clusters, snapshots, and related database resources.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,rds,javascript,nodejs,browser,database,aurora,postgres,mysql\"\n---\n\n# `@aws-sdk/client-rds`\n\nUse this package for Amazon RDS control-plane operations in AWS SDK for JavaScript v3. It manages DB instances, DB clusters, snapshots, subnet groups, parameter groups, tags, and other RDS resources.\n\nUse `@aws-sdk/client-rds` to create, inspect, modify, and delete RDS resources. Do not use it to open SQL connections to PostgreSQL, MySQL, MariaDB, SQL Server, or Oracle engines running inside RDS.\n\nPrefer `RDSClient` plus explicit command imports. The package also exposes an aggregated `RDS` client, but command-based imports are the safer default for smaller bundles and clearer dependency boundaries.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-rds\n```\n\nCommon companion packages:\n\n```bash\n# Shared config, IAM Identity Center, STS assume-role, Cognito, and other credential helpers\nnpm install @aws-sdk/credential-providers\n\n# IAM database authentication token generation\nnpm install @aws-sdk/rds-signer\n\n# Aurora Serverless Data API over HTTPS\nnpm install @aws-sdk/client-rds-data\n```\n\n## Initialize the client\n\n```javascript\nimport { RDSClient } from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain usually works if AWS access is already configured through environment variables, shared AWS config files, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: use explicit browser-safe credentials, and avoid exposing privileged RDS management permissions directly to end users.\n- Region is required somewhere. Set it in the client constructor, via `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeDBInstancesCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nconst response = await rds.send(\n  new DescribeDBInstancesCommand({\n    MaxRecords: 20,\n  }),\n);\n\nfor (const instance of response.DBInstances ?? []) {\n  console.log({\n    id: instance.DBInstanceIdentifier,\n    engine: instance.Engine,\n    status: instance.DBInstanceStatus,\n    endpoint: instance.Endpoint?.Address,\n    port: instance.Endpoint?.Port,\n  });\n}\n```\n\nUse instance-level APIs for traditional RDS instances and cluster-level APIs for Aurora cluster resources.\n\n## Common Operations\n\n### List DB instances across pages\n\nMany RDS `Describe*` operations are paginated with `Marker` and `MaxRecords`.\n\n```javascript\nimport {\n  DescribeDBInstancesCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nlet marker;\n\ndo {\n  const page = await rds.send(\n    new DescribeDBInstancesCommand({\n      MaxRecords: 100,\n      Marker: marker,\n    }),\n  );\n\n  for (const instance of page.DBInstances ?? []) {\n    console.log(instance.DBInstanceIdentifier, instance.DBInstanceStatus);\n  }\n\n  marker = page.Marker;\n} while (marker);\n```\n\n### Inspect an Aurora or Multi-AZ DB cluster\n\nUse cluster APIs when the resource is modeled as a DB cluster instead of a standalone instance.\n\n```javascript\nimport {\n  DescribeDBClustersCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nconst { DBClusters } = await rds.send(\n  new DescribeDBClustersCommand({\n    DBClusterIdentifier: \"app-cluster\",\n  }),\n);\n\nconst cluster = DBClusters?.[0];\n\nconsole.log({\n  id: cluster?.DBClusterIdentifier,\n  engine: cluster?.Engine,\n  status: cluster?.Status,\n  endpoint: cluster?.Endpoint,\n  readerEndpoint: cluster?.ReaderEndpoint,\n});\n```\n\n### Create a manual DB snapshot\n\n```javascript\nimport {\n  CreateDBSnapshotCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nconst snapshot = await rds.send(\n  new CreateDBSnapshotCommand({\n    DBInstanceIdentifier: \"app-db-1\",\n    DBSnapshotIdentifier: `app-db-1-manual-${Date.now()}`,\n  }),\n);\n\nconsole.log(snapshot.DBSnapshot?.DBSnapshotIdentifier);\n```\n\n### Modify an existing DB instance\n\nRDS updates are often asynchronous. Submit the change, then poll `DescribeDBInstances` until the resource reaches the state you expect.\n\n```javascript\nimport {\n  ModifyDBInstanceCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nawait rds.send(\n  new ModifyDBInstanceCommand({\n    DBInstanceIdentifier: \"app-db-1\",\n    BackupRetentionPeriod: 7,\n    ApplyImmediately: true,\n  }),\n);\n```\n\n### Delete a DB instance\n\nChoose either `SkipFinalSnapshot: true` or provide `FinalDBSnapshotIdentifier` when your workflow requires a final backup.\n\n```javascript\nimport {\n  DeleteDBInstanceCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nawait rds.send(\n  new DeleteDBInstanceCommand({\n    DBInstanceIdentifier: \"app-db-1\",\n    SkipFinalSnapshot: true,\n  }),\n);\n```\n\n### Tag an RDS resource by ARN\n\nRDS tagging operations target the resource ARN rather than a short identifier.\n\n```javascript\nimport {\n  AddTagsToResourceCommand,\n  RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nconst rds = new RDSClient({ region: \"us-east-1\" });\n\nawait rds.send(\n  new AddTagsToResourceCommand({\n    ResourceName:\n      \"arn:aws:rds:us-east-1:123456789012:db:app-db-1\",\n    Tags: [\n      { Key: \"Environment\", Value: \"prod\" },\n      { Key: \"ManagedBy\", Value: \"automation\" },\n    ],\n  }),\n);\n```\n\n## RDS-Specific Gotchas\n\n- `@aws-sdk/client-rds` is a management client. Use `pg`, `mysql2`, `mssql`, or another database driver for actual SQL connections.\n- Aurora and some newer RDS topologies expose important state at the cluster layer. Use `DescribeDBClusters` when instance-level calls are not enough.\n- Many create, modify, restore, failover, and delete operations are asynchronous. Do not assume the endpoint is ready immediately after the API call returns.\n- `instance.Endpoint` or cluster endpoints can be absent while provisioning, restoring, or deleting.\n- `DeleteDBInstance` often requires an explicit final-snapshot decision. Make that choice intentionally in automation.\n- IAM database authentication token generation belongs to `@aws-sdk/rds-signer`, not `@aws-sdk/client-rds`.\n- Aurora Serverless Data API calls use `@aws-sdk/client-rds-data`, not `@aws-sdk/client-rds`.\n- Import from the package root only. Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `pg`, `mysql2`, `mssql`, or another engine-specific driver: connect to the database endpoint and run SQL.\n- `@aws-sdk/rds-signer`: generate IAM auth tokens for passwordless database login.\n- `@aws-sdk/client-rds-data`: call the Aurora Data API instead of opening a database socket.\n- `@aws-sdk/credential-providers`: use `fromIni`, IAM Identity Center, Cognito, STS assume-role, and other explicit credential helpers.\n\n## Practical Notes For Agents\n\n- Pick the API family that matches the resource model: instance commands for DB instances, cluster commands for Aurora or DB cluster resources.\n- Log both identifiers and status fields during automation. RDS workflows are long-running and easier to debug when you capture `DBInstanceIdentifier`, `DBClusterIdentifier`, and current state.\n- For idempotent automation, read current state with `Describe*` first and branch on whether the resource already exists.\n- Treat endpoint discovery as a separate step from resource creation. The endpoint may not be available until the resource is fully ready.\n"
  },
  {
    "path": "content/aws/docs/redshift/javascript/DOC.md",
    "content": "---\nname: redshift\ndescription: \"AWS SDK for JavaScript v3 Redshift client for provisioning and managing Amazon Redshift clusters and snapshots.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,redshift,javascript,nodejs,browser,data-warehouse,analytics\"\n---\n\n# `@aws-sdk/client-redshift`\n\nUse this package for Amazon Redshift control-plane APIs in AWS SDK for JavaScript v3. Typical tasks include describing clusters, creating or deleting clusters, managing snapshots, and changing cluster configuration.\n\nPrefer `RedshiftClient` plus explicit command imports. The package also exposes an aggregated `Redshift` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-redshift\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Initialize the client\n\n```javascript\nimport { RedshiftClient } from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({\n  region: \"us-east-1\",\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access is already configured.\n\n## Credentials and Region\n\n- Node.js: credentials often come from environment variables, shared AWS config files, IAM roles, ECS task roles, or IAM Identity Center.\n- Browser runtimes: use explicit browser-safe credentials only. In practice, Redshift administration from the browser is uncommon and is usually better handled on a backend.\n- Region is required somewhere: set it in the client constructor, via `AWS_REGION`, or through shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## What This Client Does\n\n`@aws-sdk/client-redshift` manages Redshift resources. It does not run SQL queries against your warehouse.\n\nUse this client for:\n\n- cluster lifecycle operations\n- snapshots and restores\n- parameter groups, subnet groups, and IAM-role attachments\n- inventory and status checks\n\nDo not use this client for:\n\n- running SQL statements\n- fetching query results\n- opening PostgreSQL-compatible database connections\n\nFor those workflows, use `@aws-sdk/client-redshift-data` or a PostgreSQL-compatible driver such as `pg`, depending on whether you want the Redshift Data API or a direct database connection.\n\n## Core Usage Pattern\n\n`DescribeClusters` is a common read path when you need cluster status, endpoint details, or inventory.\n\n```javascript\nimport {\n  DescribeClustersCommand,\n  RedshiftClient,\n} from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({ region: \"us-east-1\" });\n\nconst response = await redshift.send(\n  new DescribeClustersCommand({\n    ClusterIdentifier: \"analytics-prod\",\n  }),\n);\n\nconst cluster = response.Clusters?.[0];\n\nconsole.log(cluster?.ClusterIdentifier);\nconsole.log(cluster?.ClusterStatus);\nconsole.log(cluster?.Endpoint?.Address);\nconsole.log(cluster?.Endpoint?.Port);\n```\n\n## Common Workflow\n\nFor many automation tasks, the flow is:\n\n1. Create or modify a cluster.\n2. Poll `DescribeClusters` until the cluster reaches the state you need, such as `available`.\n3. Read the endpoint from `cluster.Endpoint`.\n4. Run SQL through the Redshift Data API or a PostgreSQL-compatible client.\n\nMost Redshift mutations are asynchronous. A successful command usually means the request was accepted, not that the cluster is immediately ready for the next step.\n\n## Common Redshift Operations\n\n### Describe a cluster\n\n```javascript\nimport {\n  DescribeClustersCommand,\n  RedshiftClient,\n} from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({ region: \"us-east-1\" });\n\nconst response = await redshift.send(\n  new DescribeClustersCommand({\n    ClusterIdentifier: \"analytics-prod\",\n  }),\n);\n\nconst cluster = response.Clusters?.[0];\n\nif (!cluster) {\n  throw new Error(\"Cluster not found\");\n}\n\nconsole.log({\n  status: cluster.ClusterStatus,\n  nodeType: cluster.NodeType,\n  dbName: cluster.DBName,\n  endpoint: cluster.Endpoint,\n});\n```\n\n### List clusters across pages\n\nRedshift list-style APIs use marker-based pagination. Continue until the service stops returning `Marker`.\n\n```javascript\nimport {\n  DescribeClustersCommand,\n  RedshiftClient,\n} from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({ region: \"us-east-1\" });\n\nlet marker;\n\ndo {\n  const page = await redshift.send(\n    new DescribeClustersCommand({\n      Marker: marker,\n      MaxRecords: 100,\n    }),\n  );\n\n  for (const cluster of page.Clusters ?? []) {\n    console.log(cluster.ClusterIdentifier, cluster.ClusterStatus);\n  }\n\n  marker = page.Marker;\n} while (marker);\n```\n\n### Create a manual snapshot\n\n```javascript\nimport {\n  CreateClusterSnapshotCommand,\n  RedshiftClient,\n} from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({ region: \"us-east-1\" });\n\nconst response = await redshift.send(\n  new CreateClusterSnapshotCommand({\n    ClusterIdentifier: \"analytics-prod\",\n    SnapshotIdentifier: \"analytics-prod-manual-20260311\",\n  }),\n);\n\nconsole.log(response.Snapshot?.SnapshotIdentifier);\nconsole.log(response.Snapshot?.Status);\n```\n\n### Delete a cluster and keep a final snapshot\n\nIf you do not want to lose the last cluster state, provide a final snapshot identifier.\n\n```javascript\nimport {\n  DeleteClusterCommand,\n  RedshiftClient,\n} from \"@aws-sdk/client-redshift\";\n\nconst redshift = new RedshiftClient({ region: \"us-east-1\" });\n\nawait redshift.send(\n  new DeleteClusterCommand({\n    ClusterIdentifier: \"analytics-dev\",\n    SkipFinalClusterSnapshot: false,\n    FinalClusterSnapshotIdentifier: \"analytics-dev-final-20260311\",\n  }),\n);\n```\n\nIf you are intentionally deleting an ephemeral environment, you can set `SkipFinalClusterSnapshot: true` instead.\n\n## Redshift-Specific Gotchas\n\n- This package manages Redshift resources; it does not execute SQL. For SQL, use `@aws-sdk/client-redshift-data` or a direct database driver.\n- Cluster operations are asynchronous. Poll `DescribeClusters` after create, restore, resize, pause, resume, or delete requests before assuming the next step can run.\n- The cluster endpoint is not reliably usable until the cluster is fully available.\n- `ClusterIdentifier` is the control-plane identifier, not the database name. Do not confuse it with `DBName` or the endpoint hostname.\n- `DeleteCluster` requires either `SkipFinalClusterSnapshot: true` or a valid `FinalClusterSnapshotIdentifier` when you want to preserve the last state.\n- Provisioned Redshift and Redshift Serverless are different surfaces. Use the serverless client for workgroups and namespaces.\n- Browser-based admin flows are unusual; keep cluster-management calls on the server side unless you have a very deliberate IAM and credential design.\n- Do not deep-import SDK internals from build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-redshift-data`: run SQL statements through the Redshift Data API.\n- `@aws-sdk/client-redshift-serverless`: manage Redshift Serverless workgroups and namespaces instead of provisioned clusters.\n- `pg`: connect directly to a Redshift endpoint using the PostgreSQL wire protocol.\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and other credential helpers.\n\n## Common Decision Point\n\nChoose the package based on the job you need to do:\n\n- provisioning, snapshots, IAM-role attachment, and cluster configuration: `@aws-sdk/client-redshift`\n- submitting SQL without managing a raw TCP connection: `@aws-sdk/client-redshift-data`\n- direct SQL connections over the PostgreSQL protocol: `pg`\n- serverless namespace and workgroup administration: `@aws-sdk/client-redshift-serverless`\n"
  },
  {
    "path": "content/aws/docs/rekognition/javascript/DOC.md",
    "content": "---\nname: rekognition\ndescription: \"AWS SDK for JavaScript v3 client for Rekognition image analysis, face collections, text detection, and asynchronous video jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,rekognition,vision,images,video,faces\"\n---\n\n# AWS Rekognition SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-rekognition` from trusted server-side JavaScript or TypeScript code when you need image analysis, face collection workflows, text detection, moderation checks, or asynchronous video analysis.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-rekognition`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1007.0`.\n- Prefer `RekognitionClient` plus individual commands over the aggregated `Rekognition` service class.\n- Set `region` explicitly in code or through standard AWS shared config.\n- Use `Image.S3Object` for objects already in S3 and `Image.Bytes` for in-memory image bytes.\n- Treat video analysis APIs such as `StartLabelDetectionCommand` as asynchronous jobs that return a `JobId`.\n- Use this client from backend code or AWS-hosted workloads. Browser use needs a deliberate credential setup such as Cognito identity pools.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-rekognition\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/credential-providers dotenv\n```\n\n## Prerequisites\n\n- AWS credentials with Rekognition permissions and access to any S3 buckets you reference.\n- An AWS region where you will create the Rekognition client.\n- For asynchronous video jobs, an SNS topic and an IAM role that allows Rekognition to publish job completion notifications.\n\nCommon environment variables:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...\n\nexport AWS_REKOGNITION_BUCKET=my-rekognition-bucket\nexport AWS_REKOGNITION_COLLECTION=employees\nexport REKOGNITION_SNS_TOPIC_ARN=arn:aws:sns:us-east-1:123456789012:rekognition-jobs\nexport REKOGNITION_ROLE_ARN=arn:aws:iam::123456789012:role/RekognitionPublishToSns\n```\n\nIf you use shared AWS config instead of raw keys, set `AWS_PROFILE` and `AWS_REGION` and let the SDK resolve credentials through the default provider chain.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { RekognitionClient } from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Named profile\n\n```javascript\nimport { RekognitionClient } from \"@aws-sdk/client-rekognition\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"default\" }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 calls use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DetectLabelsCommand,\n  RekognitionClient,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({ region: \"us-east-1\" });\n\nconst response = await rekognition.send(\n  new DetectLabelsCommand({\n    Image: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"images/city.jpg\",\n      },\n    },\n    MaxLabels: 10,\n    MinConfidence: 80,\n  }),\n);\n\nfor (const label of response.Labels ?? []) {\n  console.log(label.Name, label.Confidence);\n}\n```\n\n## Common Workflows\n\n### Detect labels in an S3 image\n\n```javascript\nimport {\n  DetectLabelsCommand,\n  RekognitionClient,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await rekognition.send(\n  new DetectLabelsCommand({\n    Image: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"photos/warehouse.jpg\",\n      },\n    },\n    MaxLabels: 15,\n    MinConfidence: 80,\n  }),\n);\n\nfor (const label of result.Labels ?? []) {\n  console.log(label.Name, label.Confidence);\n}\n```\n\n### Detect text from local image bytes\n\nIn Node.js, pass raw bytes from `readFile`. Do not pass a base64 string unless you decode it first.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  DetectTextCommand,\n  RekognitionClient,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst imageBytes = await readFile(\"./receipt.jpg\");\n\nconst result = await rekognition.send(\n  new DetectTextCommand({\n    Image: {\n      Bytes: imageBytes,\n    },\n  }),\n);\n\nfor (const detection of result.TextDetections ?? []) {\n  if (detection.Type === \"LINE\") {\n    console.log(detection.DetectedText, detection.Confidence);\n  }\n}\n```\n\n### Compare faces between two S3 images\n\n```javascript\nimport {\n  CompareFacesCommand,\n  RekognitionClient,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst result = await rekognition.send(\n  new CompareFacesCommand({\n    SourceImage: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"faces/source.jpg\",\n      },\n    },\n    TargetImage: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"faces/group-photo.jpg\",\n      },\n    },\n    SimilarityThreshold: 90,\n  }),\n);\n\nfor (const match of result.FaceMatches ?? []) {\n  console.log(match.Similarity, match.Face?.BoundingBox);\n}\n```\n\n`SimilarityThreshold` filters returned matches. It does not create a face collection or persist anything for later searches.\n\n### Create a face collection, index faces, and search by image\n\nUse collections when you need repeated face search over a known set of indexed faces.\n\n```javascript\nimport {\n  CreateCollectionCommand,\n  IndexFacesCommand,\n  RekognitionClient,\n  SearchFacesByImageCommand,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst collectionId = process.env.AWS_REKOGNITION_COLLECTION ?? \"employees\";\n\nawait rekognition.send(\n  new CreateCollectionCommand({\n    CollectionId: collectionId,\n  }),\n);\n\nawait rekognition.send(\n  new IndexFacesCommand({\n    CollectionId: collectionId,\n    Image: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"known-faces/alice.jpg\",\n      },\n    },\n    ExternalImageId: \"alice\",\n    MaxFaces: 1,\n  }),\n);\n\nconst search = await rekognition.send(\n  new SearchFacesByImageCommand({\n    CollectionId: collectionId,\n    Image: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"queries/visitor.jpg\",\n      },\n    },\n    MaxFaces: 5,\n    FaceMatchThreshold: 90,\n  }),\n);\n\nfor (const match of search.FaceMatches ?? []) {\n  console.log(match.Face?.ExternalImageId, match.Similarity);\n}\n```\n\nIf `CreateCollectionCommand` has already been run for the collection ID you want, skip that step and reuse the existing collection.\n\n### Start an asynchronous video label job and fetch results\n\nVideo analysis jobs return a `JobId`. Production flows usually wait for the SNS completion notification before calling `GetLabelDetectionCommand`.\n\n```javascript\nimport {\n  GetLabelDetectionCommand,\n  RekognitionClient,\n  StartLabelDetectionCommand,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst start = await rekognition.send(\n  new StartLabelDetectionCommand({\n    Video: {\n      S3Object: {\n        Bucket: process.env.AWS_REKOGNITION_BUCKET,\n        Name: \"videos/storefront.mp4\",\n      },\n    },\n    NotificationChannel: {\n      SNSTopicArn: process.env.REKOGNITION_SNS_TOPIC_ARN,\n      RoleArn: process.env.REKOGNITION_ROLE_ARN,\n    },\n    MinConfidence: 80,\n  }),\n);\n\nconst jobId = start.JobId;\n\nif (!jobId) {\n  throw new Error(\"StartLabelDetection did not return a JobId\");\n}\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nlet nextToken;\n\nfor (;;) {\n  const page = await rekognition.send(\n    new GetLabelDetectionCommand({\n      JobId: jobId,\n      SortBy: \"TIMESTAMP\",\n      MaxResults: 1000,\n      NextToken: nextToken,\n    }),\n  );\n\n  if (page.JobStatus === \"IN_PROGRESS\") {\n    await sleep(5000);\n    continue;\n  }\n\n  if (page.JobStatus !== \"SUCCEEDED\") {\n    throw new Error(`Label detection job failed with status ${page.JobStatus}`);\n  }\n\n  for (const item of page.Labels ?? []) {\n    console.log(item.Timestamp, item.Label?.Name, item.Label?.Confidence);\n  }\n\n  if (!page.NextToken) {\n    break;\n  }\n\n  nextToken = page.NextToken;\n}\n```\n\n## Error Handling\n\nRekognition returns normal AWS SDK service exceptions. For app-level handling, check `error.name` and decide whether the problem is bad input, missing AWS permissions, or missing collection and S3 resources.\n\n```javascript\nimport {\n  DetectLabelsCommand,\n  RekognitionClient,\n} from \"@aws-sdk/client-rekognition\";\n\nconst rekognition = new RekognitionClient({ region: \"us-east-1\" });\n\ntry {\n  await rekognition.send(\n    new DetectLabelsCommand({\n      Image: {\n        S3Object: {\n          Bucket: \"missing-bucket\",\n          Name: \"missing.jpg\",\n        },\n      },\n    }),\n  );\n} catch (error) {\n  if (error?.name === \"InvalidS3ObjectException\") {\n    console.error(\"The image could not be loaded from S3\");\n  } else if (error?.name === \"AccessDeniedException\") {\n    console.error(\"The caller does not have permission for this Rekognition request\");\n  } else if (error?.name === \"ResourceNotFoundException\") {\n    console.error(\"The requested Rekognition resource was not found\");\n  } else {\n    console.error(error);\n  }\n}\n```\n\n## Rekognition-Specific Pitfalls\n\n- `Image.Bytes` expects binary image data. In Node.js, a `Buffer` from `readFile` works.\n- `CompareFacesCommand` is a one-off comparison call. It does not create searchable state.\n- `SearchFacesByImageCommand` only works against a collection that already contains indexed faces.\n- `Start*` video APIs are asynchronous. Persist the `JobId` if another worker will fetch results later.\n- `Get*` video result APIs are paginated with `NextToken`; keep reading until it is absent.\n- Missing S3 permissions or a wrong region often show up as service exceptions even when the request shape is correct.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config profiles, Cognito identity pools, and other explicit credential provider setups.\n- `@aws-sdk/client-s3`: upload source images and videos before passing them to Rekognition through `S3Object` references.\n- `@aws-sdk/client-sns`: manage the SNS topic used for asynchronous video job notifications.\n\n## Official Docs\n\n- AWS SDK for JavaScript v3 Rekognition client: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/rekognition/`\n- AWS SDK for JavaScript v3 credentials guide: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-rekognition`\n"
  },
  {
    "path": "content/aws/docs/route-53/javascript/DOC.md",
    "content": "---\nname: route-53\ndescription: \"AWS SDK for JavaScript v3 Route 53 client for hosted zones, record sets, and DNS change workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,route53,dns,javascript,nodejs,browser,hosted-zones\"\n---\n\n# `@aws-sdk/client-route-53`\n\nUse this package for Amazon Route 53 control-plane APIs in AWS SDK for JavaScript v3. Typical tasks include listing hosted zones, reading record sets, submitting DNS changes, and checking change status.\n\nPrefer `Route53Client` plus explicit command imports. The package also exposes an aggregated `Route53` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-route-53\n```\n\n## Initialize the client\n\n```javascript\nimport { Route53Client } from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n```\n\nRoute 53 is a global service, but it is still a good idea to keep the client region explicit in code and config. `us-east-1` is the common choice in JavaScript examples.\n\n## Credentials and Region\n\n- Node.js: the default credential provider chain is usually enough if credentials are already configured through environment variables, shared AWS config, IAM roles, or IAM Identity Center.\n- Browser runtimes: use an explicit browser-safe credential provider such as Cognito; do not ship long-lived AWS keys to the browser.\n- Keep the region explicit somewhere even though Route 53 is global, so signing behavior is predictable.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  ListHostedZonesCommand,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n\nconst response = await route53.send(new ListHostedZonesCommand({}));\n\nfor (const zone of response.HostedZones ?? []) {\n  console.log(zone.Name, zone.Id);\n}\n```\n\n## Common Workflow\n\nFor most DNS automation, the flow is:\n\n1. Resolve the hosted zone you want to manage.\n2. Read or construct the target `ResourceRecordSet`.\n3. Submit a `ChangeResourceRecordSetsCommand` batch.\n4. Poll the returned change ID with `GetChangeCommand` until the status is `INSYNC` if later steps depend on propagation.\n\n## Route 53-Specific Gotchas\n\n- Route 53 record names and hosted zone names are fully qualified domain names. Keeping the trailing dot in code avoids ambiguity.\n- DNS changes are asynchronous. A successful change request means Route 53 accepted it, not that every nameserver is already serving the new answer.\n- Alias records use `AliasTarget`; they do not use the usual `TTL` plus `ResourceRecords` combination.\n- Batch changes are the unit of mutation. Group related creates, deletes, and upserts into one `ChangeBatch` when they should succeed together.\n- Prefer paginators when scanning many hosted zones or record sets.\n- Do not deep-import SDK internals from build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito, STS assume-role flows, shared config helpers, and other credential helpers.\n- `@aws-sdk/client-route-53-domains`: domain registration and transfer APIs that are separate from hosted-zone DNS management.\n\n## Common Route 53 Operations\n\n### List hosted zones with a paginator\n\nUse the paginator form when you want a consistent async iteration pattern.\n\n```javascript\nimport {\n  paginateListHostedZones,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n\nfor await (const page of paginateListHostedZones({ client: route53 }, {})) {\n  for (const zone of page.HostedZones ?? []) {\n    console.log(zone.Name, zone.Id);\n  }\n}\n```\n\n### Read the record sets in a hosted zone\n\n```javascript\nimport {\n  ListResourceRecordSetsCommand,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n\nconst response = await route53.send(\n  new ListResourceRecordSetsCommand({\n    HostedZoneId: \"Z0123456789ABCDEFG\",\n  }),\n);\n\nfor (const record of response.ResourceRecordSets ?? []) {\n  console.log(record.Name, record.Type, record.TTL);\n}\n```\n\nIf you need to walk large zones, continue from the returned pagination markers or use the service paginator when available in your SDK version.\n\n### Upsert a standard A record\n\n```javascript\nimport {\n  ChangeResourceRecordSetsCommand,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n\nconst response = await route53.send(\n  new ChangeResourceRecordSetsCommand({\n    HostedZoneId: \"Z0123456789ABCDEFG\",\n    ChangeBatch: {\n      Comment: \"Update app endpoint\",\n      Changes: [\n        {\n          Action: \"UPSERT\",\n          ResourceRecordSet: {\n            Name: \"app.example.com.\",\n            Type: \"A\",\n            TTL: 60,\n            ResourceRecords: [{ Value: \"203.0.113.10\" }],\n          },\n        },\n      ],\n    },\n  }),\n);\n\nconsole.log(response.ChangeInfo?.Id, response.ChangeInfo?.Status);\n```\n\n### Create or update an alias record\n\nAlias records point at AWS resources such as load balancers and CloudFront distributions.\n\n```javascript\nimport {\n  ChangeResourceRecordSetsCommand,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\n\nawait route53.send(\n  new ChangeResourceRecordSetsCommand({\n    HostedZoneId: \"Z0123456789ABCDEFG\",\n    ChangeBatch: {\n      Changes: [\n        {\n          Action: \"UPSERT\",\n          ResourceRecordSet: {\n            Name: \"www.example.com.\",\n            Type: \"A\",\n            AliasTarget: {\n              DNSName: \"dualstack.my-load-balancer-123.us-east-1.elb.amazonaws.com.\",\n              HostedZoneId: \"Z35SXDOTRQ7X7K\",\n              EvaluateTargetHealth: false,\n            },\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\nWhen you use `AliasTarget`, omit `TTL` and `ResourceRecords`.\n\n### Wait for a submitted change to become `INSYNC`\n\nRoute 53 applies changes asynchronously, so poll the returned change ID when a later deployment step depends on the new record being active.\n\n```javascript\nimport {\n  GetChangeCommand,\n  Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\nconst route53 = new Route53Client({ region: \"us-east-1\" });\nconst changeId = \"C2682N5HXP0BZ4\";\n\nlet status = \"PENDING\";\n\nwhile (status === \"PENDING\") {\n  const response = await route53.send(\n    new GetChangeCommand({ Id: changeId }),\n  );\n\n  status = response.ChangeInfo?.Status ?? \"PENDING\";\n\n  if (status === \"PENDING\") {\n    await new Promise((resolve) => setTimeout(resolve, 5000));\n  }\n}\n\nconsole.log(status);\n```\n\n### Notes\n\n- Use `UPSERT` for idempotent automation when you want create-or-replace behavior.\n- Record-set names are easiest to reason about when you keep them fully qualified, including the trailing dot.\n- If you need deterministic record browsing around a specific name and type, use the list operation's start-name and start-type fields instead of scanning from the beginning every time.\n"
  },
  {
    "path": "content/aws/docs/route53-recovery-control-config/javascript/DOC.md",
    "content": "---\nname: route53-recovery-control-config\ndescription: \"AWS SDK for JavaScript v3 client for Route 53 Application Recovery Controller configuration APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,route53,application-recovery-controller,arc,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-route53-recovery-control-config`\n\nUse this package for Amazon Route 53 Application Recovery Controller (ARC) configuration APIs in AWS SDK for JavaScript v3. It covers clusters, control panels, routing controls, safety rules, tags, and resource policies.\n\nThis is the ARC configuration plane. It does not turn routing controls on or off. Cluster state reads and writes happen through the separate ARC recovery-cluster data plane APIs.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-route53-recovery-control-config\n```\n\n## Credentials and region\n\nIn Node.js, the default AWS credential provider chain is usually enough if credentials are already configured through environment variables, shared AWS config files, IAM roles, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-west-2\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...   # only when using temporary credentials\n```\n\nUse `us-west-2` explicitly for this client. The service endpoint rules resolve the standard configuration endpoint in the AWS partition to `route53-recovery-control-config.us-west-2.amazonaws.com`.\n\nFor browser runtimes, use a browser-safe credential provider. Do not ship long-lived AWS keys to the browser.\n\n## Initialize the client\n\n```javascript\nimport { Route53RecoveryControlConfigClient } from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\nPrefer the command-based client and explicit imports. The package also exposes an aggregated service client, but command imports keep dependencies clearer and bundle size smaller.\n\n## Core usage pattern\n\n```javascript\nimport {\n  ListClustersCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nconst response = await arcConfig.send(\n  new ListClustersCommand({ MaxResults: 20 }),\n);\n\nfor (const cluster of response.Clusters ?? []) {\n  console.log(cluster.Name, cluster.ClusterArn, cluster.Status);\n}\n```\n\n## Common workflows\n\n### Create a cluster\n\n`CreateCluster` returns the cluster ARN plus five regional cluster endpoints. Those endpoints are what you use later with ARC data plane APIs to read or update routing control state.\n\n```javascript\nimport {\n  CreateClusterCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nconst { Cluster } = await arcConfig.send(\n  new CreateClusterCommand({\n    ClusterName: \"payments-prod\",\n    NetworkType: \"IPV4\",\n    Tags: {\n      app: \"payments\",\n      environment: \"prod\",\n    },\n  }),\n);\n\nconsole.log(Cluster?.ClusterArn);\n\nfor (const endpoint of Cluster?.ClusterEndpoints ?? []) {\n  console.log(endpoint.Region, endpoint.Endpoint);\n}\n```\n\n`NetworkType` supports `IPV4` and `DUALSTACK`.\n\n### Find the default control panel for a cluster\n\nWhen you create a cluster, ARC also creates a default control panel for it. Fetch the cluster's control panels and look for `DefaultControlPanel`.\n\n```javascript\nimport {\n  ListControlPanelsCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\nconst clusterArn = \"arn:aws:route53-recovery-control::123456789012:cluster/abc123\";\n\nconst { ControlPanels } = await arcConfig.send(\n  new ListControlPanelsCommand({\n    ClusterArn: clusterArn,\n    MaxResults: 20,\n  }),\n);\n\nconst defaultPanel = ControlPanels?.find(\n  (panel) => panel.DefaultControlPanel,\n);\n\nconsole.log(defaultPanel?.Name, defaultPanel?.ControlPanelArn);\n```\n\nIf you need an additional panel instead of the default one:\n\n```javascript\nimport {\n  CreateControlPanelCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nconst { ControlPanel } = await arcConfig.send(\n  new CreateControlPanelCommand({\n    ClusterArn: clusterArn,\n    ControlPanelName: \"manual-failover\",\n  }),\n);\n\nconsole.log(ControlPanel?.ControlPanelArn);\n```\n\n### Create routing controls\n\nRouting controls belong to a cluster and can optionally be attached to a specific control panel. In practice, pass the `ControlPanelArn` explicitly so the relationship is obvious in code.\n\n```javascript\nimport {\n  CreateRoutingControlCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nconst clusterArn = \"arn:aws:route53-recovery-control::123456789012:cluster/abc123\";\nconst controlPanelArn = \"arn:aws:route53-recovery-control::123456789012:controlpanel/def456\";\n\nconst { RoutingControl } = await arcConfig.send(\n  new CreateRoutingControlCommand({\n    ClusterArn: clusterArn,\n    ControlPanelArn: controlPanelArn,\n    RoutingControlName: \"payments-us-east-1\",\n  }),\n);\n\nconsole.log(RoutingControl?.RoutingControlArn, RoutingControl?.Status);\n```\n\n### Create an assertion safety rule\n\nSafety rules let you guard state changes. Create either an `AssertionRule` or a `GatingRule` in the request body, depending on the behavior you need.\n\n```javascript\nimport {\n  CreateSafetyRuleCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nconst controlPanelArn = \"arn:aws:route53-recovery-control::123456789012:controlpanel/def456\";\nconst eastRoutingControlArn = \"arn:aws:route53-recovery-control::123456789012:routingcontrol/rc-east\";\nconst westRoutingControlArn = \"arn:aws:route53-recovery-control::123456789012:routingcontrol/rc-west\";\n\nconst response = await arcConfig.send(\n  new CreateSafetyRuleCommand({\n    AssertionRule: {\n      ControlPanelArn: controlPanelArn,\n      Name: \"keep-one-region-on\",\n      AssertedControls: [eastRoutingControlArn, westRoutingControlArn],\n      RuleConfig: {\n        Type: \"ATLEAST\",\n        Threshold: 1,\n        Inverted: false,\n      },\n      WaitPeriodMs: 5000,\n    },\n  }),\n);\n\nconsole.log(response.AssertionRule?.SafetyRuleArn, response.AssertionRule?.Status);\n```\n\nIf you need a gating rule instead, pass `GatingRule` with `GatingControls`, `TargetControls`, `RuleConfig`, `WaitPeriodMs`, and `Name`.\n\n### List routing controls and associated Route 53 health checks\n\n```javascript\nimport {\n  ListAssociatedRoute53HealthChecksCommand,\n  ListRoutingControlsCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\nconst controlPanelArn = \"arn:aws:route53-recovery-control::123456789012:controlpanel/def456\";\n\nconst { RoutingControls } = await arcConfig.send(\n  new ListRoutingControlsCommand({\n    ControlPanelArn: controlPanelArn,\n    MaxResults: 50,\n  }),\n);\n\nfor (const routingControl of RoutingControls ?? []) {\n  console.log(routingControl.Name, routingControl.RoutingControlArn);\n\n  const { HealthCheckIds } = await arcConfig.send(\n    new ListAssociatedRoute53HealthChecksCommand({\n      RoutingControlArn: routingControl.RoutingControlArn,\n    }),\n  );\n\n  console.log(HealthCheckIds ?? []);\n}\n```\n\n### Update a safety rule\n\nYou can update only the rule name and wait period. If you need to change the controls or rule configuration, delete the safety rule and create a new one.\n\n```javascript\nimport {\n  Route53RecoveryControlConfigClient,\n  UpdateSafetyRuleCommand,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\nconst safetyRuleArn = \"arn:aws:route53-recovery-control::123456789012:safetyrule/ghi789\";\n\nconst response = await arcConfig.send(\n  new UpdateSafetyRuleCommand({\n    AssertionRuleUpdate: {\n      SafetyRuleArn: safetyRuleArn,\n      Name: \"keep-one-region-on\",\n      WaitPeriodMs: 10000,\n    },\n  }),\n);\n\nconsole.log(response.AssertionRule?.WaitPeriodMs);\n```\n\n### Tag a resource and read its tags\n\nCreate operations accept tags, and you can also add or inspect tags later.\n\n```javascript\nimport {\n  ListTagsForResourceCommand,\n  Route53RecoveryControlConfigClient,\n  TagResourceCommand,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\nconst resourceArn = \"arn:aws:route53-recovery-control::123456789012:cluster/abc123\";\n\nawait arcConfig.send(\n  new TagResourceCommand({\n    ResourceArn: resourceArn,\n    Tags: {\n      owner: \"platform\",\n      environment: \"prod\",\n    },\n  }),\n);\n\nconst { Tags } = await arcConfig.send(\n  new ListTagsForResourceCommand({\n    ResourceArn: resourceArn,\n  }),\n);\n\nconsole.log(Tags);\n```\n\n## Manual pagination pattern\n\nThe list operations use `NextToken` and `MaxResults`.\n\n```javascript\nimport {\n  ListClustersCommand,\n  Route53RecoveryControlConfigClient,\n} from \"@aws-sdk/client-route53-recovery-control-config\";\n\nconst arcConfig = new Route53RecoveryControlConfigClient({ region: \"us-west-2\" });\n\nlet nextToken;\n\ndo {\n  const page = await arcConfig.send(\n    new ListClustersCommand({\n      MaxResults: 50,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const cluster of page.Clusters ?? []) {\n    console.log(cluster.Name);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\n## ARC config gotchas\n\n- This package configures ARC resources. It does not get or update routing control ON/OFF state.\n- `CreateCluster` returns five regional cluster endpoints. Keep them if later automation needs the ARC data plane.\n- New clusters include a default control panel. You often need to look it up before creating or organizing routing controls.\n- `CreateSafetyRule` and `UpdateSafetyRule` work with one rule type at a time: assertion or gating.\n- `UpdateSafetyRule` only supports renaming the rule and changing `WaitPeriodMs`.\n- Create operations accept an optional `ClientToken` if you want explicit idempotency on retries.\n- Expect `ValidationException`, `ResourceNotFoundException`, `ConflictException`, `ThrottlingException`, and `InternalServerException` in real integrations.\n- Retry throttling and temporary server errors with backoff instead of treating them as permanent failures.\n"
  },
  {
    "path": "content/aws/docs/s3/javascript/DOC.md",
    "content": "---\nname: s3\ndescription: \"AWS S3 SDK for JavaScript (v3) - Complete guide for S3 operations in JavaScript/Node.js projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.917.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"aws,s3,storage,cloud,bucket\"\n---\n\n# AWS S3 SDK for JavaScript (v3) - Complete Guide\n\n## Golden Rule\n\n**ALWAYS use `@aws-sdk/client-s3` for AWS S3 operations in JavaScript/Node.js projects.**\n\n```bash\nnpm install @aws-sdk/client-s3\n```\n\n**DO NOT use:**\n- `aws-sdk` (v2) - End-of-support on September 8, 2025\n- Any unofficial S3 libraries\n\nThe AWS SDK for JavaScript v3 (`@aws-sdk/client-s3`) is the official, maintained SDK. It uses a modular architecture that reduces bundle size and improves performance.\n\n---\n\n## Installation\n\n### Basic Installation\n\n```bash\nnpm install @aws-sdk/client-s3\n```\n\n### Additional Packages for Advanced Features\n\n```bash\n# For presigned URLs\nnpm install @aws-sdk/s3-request-presigner\n\n# For multipart uploads (large files)\nnpm install @aws-sdk/lib-storage\n\n# For credential providers\nnpm install @aws-sdk/credential-providers\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```env\nAWS_ACCESS_KEY_ID=your_access_key_id\nAWS_SECRET_ACCESS_KEY=your_secret_access_key\nAWS_REGION=us-east-1\nAWS_S3_BUCKET=your-bucket-name\n```\n\nLoad environment variables in your code:\n\n```javascript\nimport dotenv from 'dotenv';\ndotenv.config();\n\nconst REGION = process.env.AWS_REGION;\nconst BUCKET = process.env.AWS_S3_BUCKET;\n```\n\n---\n\n## Initialization\n\n### Basic Client Setup\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\n// Default credentials from environment variables or AWS config files\nconst client = new S3Client({});\n```\n\n### Client with Region\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: \"us-east-1\"\n});\n```\n\n### Client with Explicit Credentials\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n### Client with Cognito (Browser/Frontend)\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { fromCognitoIdentityPool } from \"@aws-sdk/credential-providers\";\n\nconst client = new S3Client({\n  region: \"us-east-1\",\n  credentials: fromCognitoIdentityPool({\n    clientConfig: { region: \"us-east-1\" },\n    identityPoolId: \"us-east-1:your-identity-pool-id\",\n  }),\n});\n```\n\n### Client with Custom Endpoint (LocalStack, MinIO)\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  region: \"us-east-1\",\n  endpoint: \"http://localhost:4566\",\n  forcePathStyle: true,\n  credentials: {\n    accessKeyId: \"test\",\n    secretAccessKey: \"test\",\n  },\n});\n```\n\n---\n\n## Bucket Operations\n\n### List All Buckets\n\n```javascript\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listBuckets() {\n  try {\n    const response = await client.send(new ListBucketsCommand({}));\n    console.log(\"Buckets:\");\n    response.Buckets.forEach((bucket) => {\n      console.log(`  • ${bucket.Name} (Created: ${bucket.CreationDate})`);\n    });\n  } catch (error) {\n    console.error(\"Error listing buckets:\", error);\n  }\n}\n```\n\n### Create Bucket\n\n```javascript\nimport {\n  S3Client,\n  CreateBucketCommand,\n  waitUntilBucketExists\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\nasync function createBucket(bucketName) {\n  try {\n    const response = await client.send(\n      new CreateBucketCommand({\n        Bucket: bucketName,\n      })\n    );\n\n    // Wait until bucket exists\n    await waitUntilBucketExists(\n      { client, maxWaitTime: 60 },\n      { Bucket: bucketName }\n    );\n\n    console.log(`Bucket created: ${response.Location}`);\n  } catch (error) {\n    console.error(\"Error creating bucket:\", error);\n  }\n}\n```\n\n### Create Bucket in Specific Region\n\n```javascript\nimport { S3Client, CreateBucketCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({ region: \"us-west-2\" });\n\nasync function createBucketInRegion(bucketName, region) {\n  try {\n    const params = {\n      Bucket: bucketName,\n    };\n\n    // us-east-1 doesn't require LocationConstraint\n    if (region !== \"us-east-1\") {\n      params.CreateBucketConfiguration = {\n        LocationConstraint: region,\n      };\n    }\n\n    await client.send(new CreateBucketCommand(params));\n    console.log(`Bucket created in ${region}`);\n  } catch (error) {\n    console.error(\"Error creating bucket:\", error);\n  }\n}\n```\n\n### Delete Bucket\n\n```javascript\nimport {\n  S3Client,\n  DeleteBucketCommand,\n  waitUntilBucketNotExists\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function deleteBucket(bucketName) {\n  try {\n    await client.send(new DeleteBucketCommand({ Bucket: bucketName }));\n\n    await waitUntilBucketNotExists(\n      { client, maxWaitTime: 60 },\n      { Bucket: bucketName }\n    );\n\n    console.log(`Bucket deleted: ${bucketName}`);\n  } catch (error) {\n    console.error(\"Error deleting bucket:\", error);\n  }\n}\n```\n\n### Check if Bucket Exists\n\n```javascript\nimport { S3Client, HeadBucketCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function bucketExists(bucketName) {\n  try {\n    await client.send(new HeadBucketCommand({ Bucket: bucketName }));\n    return true;\n  } catch (error) {\n    if (error.name === \"NotFound\") {\n      return false;\n    }\n    throw error;\n  }\n}\n```\n\n---\n\n## Object Upload Operations\n\n### Upload File from Disk\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { readFile } from \"node:fs/promises\";\n\nconst client = new S3Client({});\n\nasync function uploadFile(bucketName, key, filePath) {\n  try {\n    const fileContent = await readFile(filePath);\n\n    const response = await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: fileContent,\n      })\n    );\n\n    console.log(\"Upload successful:\", response.ETag);\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n```\n\n### Upload with Content Type\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { readFile } from \"node:fs/promises\";\n\nconst client = new S3Client({});\n\nasync function uploadWithContentType(bucketName, key, filePath, contentType) {\n  try {\n    const fileContent = await readFile(filePath);\n\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: fileContent,\n        ContentType: contentType,\n      })\n    );\n\n    console.log(`Uploaded ${key} as ${contentType}`);\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n\n// Usage\nawait uploadWithContentType(\n  \"my-bucket\",\n  \"images/photo.jpg\",\n  \"./photo.jpg\",\n  \"image/jpeg\"\n);\n```\n\n### Upload String/Buffer\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function uploadString(bucketName, key, content) {\n  try {\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: content,\n        ContentType: \"text/plain\",\n      })\n    );\n\n    console.log(`Uploaded text to ${key}`);\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n\n// Upload JSON\nasync function uploadJSON(bucketName, key, data) {\n  try {\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: JSON.stringify(data),\n        ContentType: \"application/json\",\n      })\n    );\n\n    console.log(`Uploaded JSON to ${key}`);\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n```\n\n### Upload with Metadata\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function uploadWithMetadata(bucketName, key, body) {\n  try {\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: body,\n        Metadata: {\n          \"uploaded-by\": \"user123\",\n          \"original-name\": \"document.pdf\",\n          \"category\": \"reports\",\n        },\n      })\n    );\n\n    console.log(\"Uploaded with metadata\");\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n```\n\n### Upload with Server-Side Encryption\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function uploadEncrypted(bucketName, key, body) {\n  try {\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Body: body,\n        ServerSideEncryption: \"AES256\",\n      })\n    );\n\n    console.log(\"Uploaded with encryption\");\n  } catch (error) {\n    console.error(\"Upload error:\", error);\n  }\n}\n```\n\n### Batch Upload Multiple Files\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst client = new S3Client({});\n\nasync function uploadDirectory(bucketName, folderPath, s3Prefix = \"\") {\n  try {\n    const files = readdirSync(folderPath);\n\n    for (const file of files) {\n      const filePath = join(folderPath, file);\n      const fileContent = readFileSync(filePath);\n      const s3Key = s3Prefix ? `${s3Prefix}/${file}` : file;\n\n      await client.send(\n        new PutObjectCommand({\n          Bucket: bucketName,\n          Key: s3Key,\n          Body: fileContent,\n        })\n      );\n\n      console.log(`Uploaded: ${s3Key}`);\n    }\n\n    console.log(`Uploaded ${files.length} files`);\n  } catch (error) {\n    console.error(\"Batch upload error:\", error);\n  }\n}\n```\n\n---\n\n## Object Download Operations\n\n### Download File to Disk\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\nimport { writeFile } from \"node:fs/promises\";\n\nconst client = new S3Client({});\n\nasync function downloadFile(bucketName, key, destinationPath) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    const fileContent = await response.Body.transformToByteArray();\n    await writeFile(destinationPath, fileContent);\n\n    console.log(`Downloaded to ${destinationPath}`);\n  } catch (error) {\n    console.error(\"Download error:\", error);\n  }\n}\n```\n\n### Download as String\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function downloadAsString(bucketName, key) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    const content = await response.Body.transformToString();\n    return content;\n  } catch (error) {\n    console.error(\"Download error:\", error);\n    throw error;\n  }\n}\n\n// Download JSON\nasync function downloadJSON(bucketName, key) {\n  const content = await downloadAsString(bucketName, key);\n  return JSON.parse(content);\n}\n```\n\n### Download with Error Handling\n\n```javascript\nimport {\n  S3Client,\n  GetObjectCommand,\n  NoSuchKey\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function downloadSafe(bucketName, key) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    return await response.Body.transformToString();\n  } catch (error) {\n    if (error instanceof NoSuchKey) {\n      console.error(`Key does not exist: ${key}`);\n      return null;\n    }\n    throw error;\n  }\n}\n```\n\n### Download Byte Range\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function downloadRange(bucketName, key, start, end) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n        Range: `bytes=${start}-${end}`,\n      })\n    );\n\n    return await response.Body.transformToByteArray();\n  } catch (error) {\n    console.error(\"Download error:\", error);\n  }\n}\n```\n\n### Get Object Metadata Only\n\n```javascript\nimport { S3Client, HeadObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function getObjectMetadata(bucketName, key) {\n  try {\n    const response = await client.send(\n      new HeadObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    console.log(\"Metadata:\", {\n      ContentType: response.ContentType,\n      ContentLength: response.ContentLength,\n      LastModified: response.LastModified,\n      ETag: response.ETag,\n      Metadata: response.Metadata,\n    });\n\n    return response;\n  } catch (error) {\n    console.error(\"Metadata error:\", error);\n  }\n}\n```\n\n---\n\n## List Objects\n\n### List All Objects (Paginated)\n\n```javascript\nimport { S3Client, paginateListObjectsV2 } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listAllObjects(bucketName) {\n  try {\n    const paginator = paginateListObjectsV2(\n      { client },\n      { Bucket: bucketName }\n    );\n\n    let totalObjects = 0;\n\n    for await (const page of paginator) {\n      if (page.Contents) {\n        page.Contents.forEach((obj) => {\n          console.log(`  • ${obj.Key} (${obj.Size} bytes)`);\n          totalObjects++;\n        });\n      }\n    }\n\n    console.log(`\\nTotal objects: ${totalObjects}`);\n  } catch (error) {\n    console.error(\"List error:\", error);\n  }\n}\n```\n\n### List Objects with Prefix\n\n```javascript\nimport { S3Client, paginateListObjectsV2 } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listObjectsWithPrefix(bucketName, prefix) {\n  try {\n    const paginator = paginateListObjectsV2(\n      { client },\n      {\n        Bucket: bucketName,\n        Prefix: prefix,\n      }\n    );\n\n    for await (const page of paginator) {\n      if (page.Contents) {\n        page.Contents.forEach((obj) => {\n          console.log(`  • ${obj.Key}`);\n        });\n      }\n    }\n  } catch (error) {\n    console.error(\"List error:\", error);\n  }\n}\n```\n\n### List Objects with Custom Page Size\n\n```javascript\nimport { S3Client, paginateListObjectsV2 } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listObjectsPaged(bucketName, pageSize = 10) {\n  try {\n    const paginator = paginateListObjectsV2(\n      { client, pageSize },\n      { Bucket: bucketName }\n    );\n\n    let pageNumber = 1;\n\n    for await (const page of paginator) {\n      console.log(`\\nPage ${pageNumber}:`);\n\n      if (page.Contents) {\n        page.Contents.forEach((obj) => {\n          console.log(`  • ${obj.Key}`);\n        });\n      }\n\n      pageNumber++;\n    }\n  } catch (error) {\n    console.error(\"List error:\", error);\n  }\n}\n```\n\n### List Objects (Non-Paginated)\n\n```javascript\nimport { S3Client, ListObjectsV2Command } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listObjectsSimple(bucketName, maxKeys = 1000) {\n  try {\n    const response = await client.send(\n      new ListObjectsV2Command({\n        Bucket: bucketName,\n        MaxKeys: maxKeys,\n      })\n    );\n\n    if (response.Contents) {\n      response.Contents.forEach((obj) => {\n        console.log(`  • ${obj.Key}`);\n      });\n    }\n\n    console.log(`Listed ${response.KeyCount} objects`);\n    console.log(`Truncated: ${response.IsTruncated}`);\n  } catch (error) {\n    console.error(\"List error:\", error);\n  }\n}\n```\n\n### List Objects in Folder Structure\n\n```javascript\nimport { S3Client, ListObjectsV2Command } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function listFolder(bucketName, prefix) {\n  try {\n    const response = await client.send(\n      new ListObjectsV2Command({\n        Bucket: bucketName,\n        Prefix: prefix,\n        Delimiter: \"/\",\n      })\n    );\n\n    console.log(\"Folders:\");\n    if (response.CommonPrefixes) {\n      response.CommonPrefixes.forEach((cp) => {\n        console.log(`  📁 ${cp.Prefix}`);\n      });\n    }\n\n    console.log(\"\\nFiles:\");\n    if (response.Contents) {\n      response.Contents.forEach((obj) => {\n        console.log(`  📄 ${obj.Key}`);\n      });\n    }\n  } catch (error) {\n    console.error(\"List error:\", error);\n  }\n}\n```\n\n---\n\n## Delete Operations\n\n### Delete Single Object\n\n```javascript\nimport {\n  S3Client,\n  DeleteObjectCommand,\n  waitUntilObjectNotExists\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function deleteObject(bucketName, key) {\n  try {\n    await client.send(\n      new DeleteObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    await waitUntilObjectNotExists(\n      { client, maxWaitTime: 60 },\n      { Bucket: bucketName, Key: key }\n    );\n\n    console.log(`Deleted: ${key}`);\n  } catch (error) {\n    console.error(\"Delete error:\", error);\n  }\n}\n```\n\n### Delete Multiple Objects (Batch)\n\n```javascript\nimport { S3Client, DeleteObjectsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function deleteMultipleObjects(bucketName, keys) {\n  try {\n    const response = await client.send(\n      new DeleteObjectsCommand({\n        Bucket: bucketName,\n        Delete: {\n          Objects: keys.map((key) => ({ Key: key })),\n        },\n      })\n    );\n\n    if (response.Deleted) {\n      console.log(`Deleted ${response.Deleted.length} objects:`);\n      response.Deleted.forEach((obj) => {\n        console.log(`  • ${obj.Key}`);\n      });\n    }\n\n    if (response.Errors) {\n      console.error(\"Errors:\", response.Errors);\n    }\n  } catch (error) {\n    console.error(\"Batch delete error:\", error);\n  }\n}\n\n// Usage\nawait deleteMultipleObjects(\"my-bucket\", [\n  \"file1.txt\",\n  \"file2.txt\",\n  \"folder/file3.txt\",\n]);\n```\n\n### Delete All Objects with Prefix\n\n```javascript\nimport {\n  S3Client,\n  ListObjectsV2Command,\n  DeleteObjectsCommand\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function deleteObjectsWithPrefix(bucketName, prefix) {\n  try {\n    const listResponse = await client.send(\n      new ListObjectsV2Command({\n        Bucket: bucketName,\n        Prefix: prefix,\n      })\n    );\n\n    if (!listResponse.Contents || listResponse.Contents.length === 0) {\n      console.log(\"No objects to delete\");\n      return;\n    }\n\n    const deleteResponse = await client.send(\n      new DeleteObjectsCommand({\n        Bucket: bucketName,\n        Delete: {\n          Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),\n        },\n      })\n    );\n\n    console.log(`Deleted ${deleteResponse.Deleted.length} objects`);\n  } catch (error) {\n    console.error(\"Delete error:\", error);\n  }\n}\n```\n\n### Empty and Delete Bucket\n\n```javascript\nimport {\n  S3Client,\n  ListObjectsV2Command,\n  DeleteObjectsCommand,\n  DeleteBucketCommand\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function emptyAndDeleteBucket(bucketName) {\n  try {\n    // List all objects\n    const listResponse = await client.send(\n      new ListObjectsV2Command({ Bucket: bucketName })\n    );\n\n    // Delete all objects if any exist\n    if (listResponse.Contents && listResponse.Contents.length > 0) {\n      await client.send(\n        new DeleteObjectsCommand({\n          Bucket: bucketName,\n          Delete: {\n            Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),\n          },\n        })\n      );\n\n      console.log(`Deleted ${listResponse.Contents.length} objects`);\n    }\n\n    // Delete the bucket\n    await client.send(new DeleteBucketCommand({ Bucket: bucketName }));\n    console.log(`Bucket deleted: ${bucketName}`);\n  } catch (error) {\n    console.error(\"Error:\", error);\n  }\n}\n```\n\n---\n\n## Copy and Move Operations\n\n### Copy Object\n\n```javascript\nimport { S3Client, CopyObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function copyObject(sourceBucket, sourceKey, destBucket, destKey) {\n  try {\n    await client.send(\n      new CopyObjectCommand({\n        CopySource: `${sourceBucket}/${sourceKey}`,\n        Bucket: destBucket,\n        Key: destKey,\n      })\n    );\n\n    console.log(`Copied ${sourceKey} to ${destKey}`);\n  } catch (error) {\n    console.error(\"Copy error:\", error);\n  }\n}\n```\n\n### Move Object (Copy + Delete)\n\n```javascript\nimport {\n  S3Client,\n  CopyObjectCommand,\n  DeleteObjectCommand\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function moveObject(sourceBucket, sourceKey, destBucket, destKey) {\n  try {\n    // Copy\n    await client.send(\n      new CopyObjectCommand({\n        CopySource: `${sourceBucket}/${sourceKey}`,\n        Bucket: destBucket,\n        Key: destKey,\n      })\n    );\n\n    // Delete source\n    await client.send(\n      new DeleteObjectCommand({\n        Bucket: sourceBucket,\n        Key: sourceKey,\n      })\n    );\n\n    console.log(`Moved ${sourceKey} to ${destKey}`);\n  } catch (error) {\n    console.error(\"Move error:\", error);\n  }\n}\n```\n\n---\n\n## Presigned URLs\n\n### Install Required Package\n\n```bash\nnpm install @aws-sdk/s3-request-presigner\n```\n\n### Presigned URL for Download (GET)\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\nasync function createPresignedDownloadUrl(bucketName, key, expiresIn = 3600) {\n  try {\n    const command = new GetObjectCommand({\n      Bucket: bucketName,\n      Key: key,\n    });\n\n    const url = await getSignedUrl(client, command, { expiresIn });\n    return url;\n  } catch (error) {\n    console.error(\"Presigned URL error:\", error);\n    throw error;\n  }\n}\n\n// Usage\nconst url = await createPresignedDownloadUrl(\"my-bucket\", \"file.pdf\", 3600);\nconsole.log(\"Download URL:\", url);\n```\n\n### Presigned URL for Upload (PUT)\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\nasync function createPresignedUploadUrl(bucketName, key, expiresIn = 3600) {\n  try {\n    const command = new PutObjectCommand({\n      Bucket: bucketName,\n      Key: key,\n    });\n\n    const url = await getSignedUrl(client, command, { expiresIn });\n    return url;\n  } catch (error) {\n    console.error(\"Presigned URL error:\", error);\n    throw error;\n  }\n}\n\n// Usage with fetch\nconst uploadUrl = await createPresignedUploadUrl(\"my-bucket\", \"upload.txt\");\n\n// Client can now upload using PUT request\nawait fetch(uploadUrl, {\n  method: \"PUT\",\n  body: fileContent,\n  headers: {\n    \"Content-Type\": \"text/plain\",\n  },\n});\n```\n\n### Presigned URL with Content Type\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\nasync function createPresignedUploadUrlWithType(\n  bucketName,\n  key,\n  contentType,\n  expiresIn = 3600\n) {\n  try {\n    const command = new PutObjectCommand({\n      Bucket: bucketName,\n      Key: key,\n      ContentType: contentType,\n    });\n\n    const url = await getSignedUrl(client, command, { expiresIn });\n    return url;\n  } catch (error) {\n    console.error(\"Presigned URL error:\", error);\n    throw error;\n  }\n}\n```\n\n### Presigned URL with Metadata\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\nasync function createPresignedUrlWithMetadata(bucketName, key) {\n  try {\n    const command = new PutObjectCommand({\n      Bucket: bucketName,\n      Key: key,\n      Metadata: {\n        \"uploaded-by\": \"user123\",\n        \"original-name\": \"document.pdf\",\n      },\n    });\n\n    const url = await getSignedUrl(client, command, { expiresIn: 3600 });\n    return url;\n  } catch (error) {\n    console.error(\"Presigned URL error:\", error);\n    throw error;\n  }\n}\n```\n\n### Complete Presigned Upload Example\n\n```javascript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\n\n// Server-side: Generate presigned URL\nasync function generateUploadUrl(fileName, fileType) {\n  const command = new PutObjectCommand({\n    Bucket: \"my-bucket\",\n    Key: `uploads/${fileName}`,\n    ContentType: fileType,\n  });\n\n  return await getSignedUrl(client, command, { expiresIn: 300 }); // 5 minutes\n}\n\n// Client-side: Upload using presigned URL\nasync function uploadUsingPresignedUrl(presignedUrl, file) {\n  const response = await fetch(presignedUrl, {\n    method: \"PUT\",\n    body: file,\n    headers: {\n      \"Content-Type\": file.type,\n    },\n  });\n\n  if (response.ok) {\n    console.log(\"Upload successful\");\n  } else {\n    console.error(\"Upload failed:\", response.statusText);\n  }\n}\n```\n\n---\n\n## Multipart Upload\n\n### Install Required Package\n\n```bash\nnpm install @aws-sdk/lib-storage\n```\n\n### Basic Multipart Upload\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function multipartUpload(bucketName, key, filePath) {\n  try {\n    const fileStream = createReadStream(filePath);\n\n    const upload = new Upload({\n      client,\n      params: {\n        Bucket: bucketName,\n        Key: key,\n        Body: fileStream,\n      },\n    });\n\n    const result = await upload.done();\n    console.log(\"Upload complete:\", result.Location);\n  } catch (error) {\n    console.error(\"Multipart upload error:\", error);\n  }\n}\n```\n\n### Multipart Upload with Progress Tracking\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream, statSync } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function multipartUploadWithProgress(bucketName, key, filePath) {\n  try {\n    const fileStream = createReadStream(filePath);\n    const fileSize = statSync(filePath).size;\n\n    const upload = new Upload({\n      client,\n      params: {\n        Bucket: bucketName,\n        Key: key,\n        Body: fileStream,\n      },\n    });\n\n    upload.on(\"httpUploadProgress\", (progress) => {\n      const percentage = Math.round((progress.loaded / fileSize) * 100);\n      console.log(`Upload progress: ${percentage}%`);\n    });\n\n    const result = await upload.done();\n    console.log(\"Upload complete:\", result.Location);\n  } catch (error) {\n    console.error(\"Multipart upload error:\", error);\n  }\n}\n```\n\n### Multipart Upload with Custom Configuration\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function multipartUploadConfigured(bucketName, key, filePath) {\n  try {\n    const fileStream = createReadStream(filePath);\n\n    const upload = new Upload({\n      client,\n      params: {\n        Bucket: bucketName,\n        Key: key,\n        Body: fileStream,\n      },\n      queueSize: 4, // Number of concurrent uploads\n      partSize: 1024 * 1024 * 5, // 5 MB parts (minimum is 5 MB)\n      leavePartsOnError: false, // Clean up on error\n    });\n\n    const result = await upload.done();\n    console.log(\"Upload complete:\", result.Location);\n  } catch (error) {\n    console.error(\"Multipart upload error:\", error);\n  }\n}\n```\n\n### Multipart Upload with Tags and Metadata\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { readFileSync } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function multipartUploadWithTags(bucketName, key, filePath) {\n  try {\n    const fileContent = readFileSync(filePath);\n\n    const upload = new Upload({\n      client,\n      params: {\n        Bucket: bucketName,\n        Key: key,\n        Body: fileContent,\n        Metadata: {\n          \"uploaded-by\": \"system\",\n          \"file-category\": \"large-files\",\n        },\n      },\n      tags: [\n        { Key: \"Environment\", Value: \"Production\" },\n        { Key: \"Department\", Value: \"Engineering\" },\n      ],\n    });\n\n    const result = await upload.done();\n    console.log(\"Upload complete:\", result.Location);\n  } catch (error) {\n    console.error(\"Multipart upload error:\", error);\n  }\n}\n```\n\n### Abort Multipart Upload\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function abortableMultipartUpload(bucketName, key, filePath) {\n  const fileStream = createReadStream(filePath);\n\n  const upload = new Upload({\n    client,\n    params: {\n      Bucket: bucketName,\n      Key: key,\n      Body: fileStream,\n    },\n  });\n\n  // Abort after 5 seconds (example)\n  setTimeout(() => {\n    upload.abort();\n    console.log(\"Upload aborted\");\n  }, 5000);\n\n  try {\n    await upload.done();\n  } catch (error) {\n    if (error.name === \"AbortError\") {\n      console.log(\"Upload was aborted\");\n    } else {\n      console.error(\"Upload error:\", error);\n    }\n  }\n}\n```\n\n---\n\n## Streaming Operations\n\n### Stream Download\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\nimport { pipeline } from \"node:stream/promises\";\nimport { createWriteStream } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function streamDownload(bucketName, key, destinationPath) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    await pipeline(\n      response.Body,\n      createWriteStream(destinationPath)\n    );\n\n    console.log(`Streamed download to ${destinationPath}`);\n  } catch (error) {\n    console.error(\"Stream download error:\", error);\n  }\n}\n```\n\n### Stream Upload\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new S3Client({});\n\nasync function streamUpload(bucketName, key, filePath) {\n  try {\n    const fileStream = createReadStream(filePath);\n\n    const upload = new Upload({\n      client,\n      params: {\n        Bucket: bucketName,\n        Key: key,\n        Body: fileStream,\n      },\n    });\n\n    await upload.done();\n    console.log(\"Stream upload complete\");\n  } catch (error) {\n    console.error(\"Stream upload error:\", error);\n  }\n}\n```\n\n---\n\n## Object Tagging\n\n### Put Object Tags\n\n```javascript\nimport { S3Client, PutObjectTaggingCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function tagObject(bucketName, key, tags) {\n  try {\n    await client.send(\n      new PutObjectTaggingCommand({\n        Bucket: bucketName,\n        Key: key,\n        Tagging: {\n          TagSet: tags.map(({ Key, Value }) => ({ Key, Value })),\n        },\n      })\n    );\n\n    console.log(`Tagged ${key}`);\n  } catch (error) {\n    console.error(\"Tagging error:\", error);\n  }\n}\n\n// Usage\nawait tagObject(\"my-bucket\", \"file.txt\", [\n  { Key: \"Environment\", Value: \"Production\" },\n  { Key: \"Department\", Value: \"Engineering\" },\n]);\n```\n\n### Get Object Tags\n\n```javascript\nimport { S3Client, GetObjectTaggingCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function getObjectTags(bucketName, key) {\n  try {\n    const response = await client.send(\n      new GetObjectTaggingCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    console.log(\"Tags:\");\n    response.TagSet.forEach((tag) => {\n      console.log(`  ${tag.Key}: ${tag.Value}`);\n    });\n\n    return response.TagSet;\n  } catch (error) {\n    console.error(\"Get tags error:\", error);\n  }\n}\n```\n\n---\n\n## Bucket Configuration\n\n### Enable Versioning\n\n```javascript\nimport { S3Client, PutBucketVersioningCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function enableVersioning(bucketName) {\n  try {\n    await client.send(\n      new PutBucketVersioningCommand({\n        Bucket: bucketName,\n        VersioningConfiguration: {\n          Status: \"Enabled\",\n        },\n      })\n    );\n\n    console.log(`Versioning enabled for ${bucketName}`);\n  } catch (error) {\n    console.error(\"Versioning error:\", error);\n  }\n}\n```\n\n### Set Bucket CORS\n\n```javascript\nimport { S3Client, PutBucketCorsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function setBucketCORS(bucketName) {\n  try {\n    await client.send(\n      new PutBucketCorsCommand({\n        Bucket: bucketName,\n        CORSConfiguration: {\n          CORSRules: [\n            {\n              AllowedHeaders: [\"*\"],\n              AllowedMethods: [\"GET\", \"PUT\", \"POST\", \"DELETE\"],\n              AllowedOrigins: [\"*\"],\n              ExposeHeaders: [\"ETag\"],\n              MaxAgeSeconds: 3000,\n            },\n          ],\n        },\n      })\n    );\n\n    console.log(\"CORS configured\");\n  } catch (error) {\n    console.error(\"CORS error:\", error);\n  }\n}\n```\n\n### Get Bucket CORS\n\n```javascript\nimport { S3Client, GetBucketCorsCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function getBucketCORS(bucketName) {\n  try {\n    const response = await client.send(\n      new GetBucketCorsCommand({\n        Bucket: bucketName,\n      })\n    );\n\n    console.log(\"CORS Rules:\", JSON.stringify(response.CORSRules, null, 2));\n    return response.CORSRules;\n  } catch (error) {\n    console.error(\"Get CORS error:\", error);\n  }\n}\n```\n\n### Set Bucket Encryption\n\n```javascript\nimport { S3Client, PutBucketEncryptionCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function setBucketEncryption(bucketName) {\n  try {\n    await client.send(\n      new PutBucketEncryptionCommand({\n        Bucket: bucketName,\n        ServerSideEncryptionConfiguration: {\n          Rules: [\n            {\n              ApplyServerSideEncryptionByDefault: {\n                SSEAlgorithm: \"AES256\",\n              },\n            },\n          ],\n        },\n      })\n    );\n\n    console.log(\"Encryption enabled\");\n  } catch (error) {\n    console.error(\"Encryption error:\", error);\n  }\n}\n```\n\n---\n\n## Error Handling\n\n### Common Error Types\n\n```javascript\nimport {\n  S3Client,\n  GetObjectCommand,\n  NoSuchKey,\n  NoSuchBucket,\n} from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({});\n\nasync function handleErrors(bucketName, key) {\n  try {\n    const response = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: key,\n      })\n    );\n\n    return await response.Body.transformToString();\n  } catch (error) {\n    if (error instanceof NoSuchKey) {\n      console.error(\"Object not found\");\n    } else if (error instanceof NoSuchBucket) {\n      console.error(\"Bucket not found\");\n    } else if (error.name === \"AccessDenied\") {\n      console.error(\"Access denied\");\n    } else if (error.name === \"InvalidAccessKeyId\") {\n      console.error(\"Invalid credentials\");\n    } else {\n      console.error(\"Unknown error:\", error);\n    }\n\n    throw error;\n  }\n}\n```\n\n### Retry Logic\n\n```javascript\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst client = new S3Client({\n  maxAttempts: 3, // Built-in retry configuration\n});\n\nasync function downloadWithRetry(bucketName, key, maxRetries = 3) {\n  let lastError;\n\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      const response = await client.send(\n        new GetObjectCommand({\n          Bucket: bucketName,\n          Key: key,\n        })\n      );\n\n      return await response.Body.transformToString();\n    } catch (error) {\n      lastError = error;\n      console.log(`Attempt ${i + 1} failed, retrying...`);\n      await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));\n    }\n  }\n\n  throw lastError;\n}\n```\n\n---\n\n## Complete Example: Full S3 Operations\n\n```javascript\nimport {\n  S3Client,\n  CreateBucketCommand,\n  PutObjectCommand,\n  GetObjectCommand,\n  ListObjectsV2Command,\n  DeleteObjectCommand,\n  DeleteBucketCommand,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst client = new S3Client({ region: \"us-east-1\" });\nconst bucketName = `my-test-bucket-${Date.now()}`;\n\nasync function completeS3Example() {\n  try {\n    // 1. Create bucket\n    console.log(\"Creating bucket...\");\n    await client.send(new CreateBucketCommand({ Bucket: bucketName }));\n\n    // 2. Upload object\n    console.log(\"Uploading object...\");\n    await client.send(\n      new PutObjectCommand({\n        Bucket: bucketName,\n        Key: \"test-file.txt\",\n        Body: \"Hello, S3!\",\n        ContentType: \"text/plain\",\n      })\n    );\n\n    // 3. Generate presigned URL\n    console.log(\"Generating presigned URL...\");\n    const url = await getSignedUrl(\n      client,\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: \"test-file.txt\",\n      }),\n      { expiresIn: 3600 }\n    );\n    console.log(\"Presigned URL:\", url);\n\n    // 4. Download object\n    console.log(\"Downloading object...\");\n    const downloadResponse = await client.send(\n      new GetObjectCommand({\n        Bucket: bucketName,\n        Key: \"test-file.txt\",\n      })\n    );\n    const content = await downloadResponse.Body.transformToString();\n    console.log(\"Content:\", content);\n\n    // 5. List objects\n    console.log(\"Listing objects...\");\n    const listResponse = await client.send(\n      new ListObjectsV2Command({ Bucket: bucketName })\n    );\n    listResponse.Contents.forEach((obj) => {\n      console.log(`  • ${obj.Key}`);\n    });\n\n    // 6. Delete object\n    console.log(\"Deleting object...\");\n    await client.send(\n      new DeleteObjectCommand({\n        Bucket: bucketName,\n        Key: \"test-file.txt\",\n      })\n    );\n\n    // 7. Delete bucket\n    console.log(\"Deleting bucket...\");\n    await client.send(new DeleteBucketCommand({ Bucket: bucketName }));\n\n    console.log(\"Complete!\");\n  } catch (error) {\n    console.error(\"Error:\", error);\n  }\n}\n\ncompleteS3Example();\n```\n"
  },
  {
    "path": "content/aws/docs/s3/python/DOC.md",
    "content": "---\nname: s3\ndescription: \"AWS S3 SDK for Python (boto3) - Complete guide for S3 operations in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.59\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"aws,s3,storage,cloud,bucket\"\n---\n\n# AWS S3 SDK for Python (boto3) - Complete Guide\n\n## Golden Rule\n\n**ALWAYS use `boto3` for AWS S3 operations in Python projects.**\n\n```bash\npip install boto3\n```\n\n**DO NOT use:**\n- `boto` (legacy library, deprecated)\n- Any unofficial S3 libraries\n\n`boto3` is the official AWS SDK for Python. It provides low-level client access and high-level object-oriented resource access to AWS services.\n\n**Python Version Requirements:**\n- Python 3.9 or later (support for Python 3.8 ended on 2025-04-22)\n\n---\n\n## Installation\n\n### Basic Installation\n\n```bash\npip install boto3\n```\n\n### With pip (specific version)\n\n```bash\npip install boto3==1.40.59\n```\n\n### With Poetry\n\n```bash\npoetry add boto3\n```\n\n### With uv\n\n```bash\nuv add boto3\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```env\nAWS_ACCESS_KEY_ID=your_access_key_id\nAWS_SECRET_ACCESS_KEY=your_secret_access_key\nAWS_DEFAULT_REGION=us-east-1\nAWS_S3_BUCKET=your-bucket-name\n```\n\nLoad environment variables in your code:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nREGION = os.getenv(\"AWS_DEFAULT_REGION\")\nBUCKET = os.getenv(\"AWS_S3_BUCKET\")\n```\n\n### AWS Credentials Configuration\n\nBoto3 looks for credentials in this order:\n\n1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)\n2. Shared credentials file (`~/.aws/credentials`)\n3. AWS config file (`~/.aws/config`)\n4. IAM role (when running on EC2)\n\nConfigure credentials using AWS CLI:\n\n```bash\naws configure\n```\n\n---\n\n## Initialization\n\n### Client vs Resource\n\nboto3 provides two interfaces:\n\n- **Client**: Low-level service access (1-to-1 mapping with AWS APIs)\n- **Resource**: Higher-level object-oriented interface\n\n```python\nimport boto3\n\n# Client (low-level)\ns3_client = boto3.client(\"s3\")\n\n# Resource (high-level)\ns3_resource = boto3.resource(\"s3\")\n```\n\n### Basic Client Setup\n\n```python\nimport boto3\n\n# Default credentials from environment or AWS config\ns3 = boto3.client(\"s3\")\n```\n\n### Client with Region\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\", region_name=\"us-east-1\")\n```\n\n### Client with Explicit Credentials\n\n```python\nimport boto3\n\ns3 = boto3.client(\n    \"s3\",\n    aws_access_key_id=\"YOUR_ACCESS_KEY\",\n    aws_secret_access_key=\"YOUR_SECRET_KEY\",\n    region_name=\"us-east-1\"\n)\n```\n\n### Client with Session\n\n```python\nimport boto3\n\nsession = boto3.Session(\n    aws_access_key_id=\"YOUR_ACCESS_KEY\",\n    aws_secret_access_key=\"YOUR_SECRET_KEY\",\n    region_name=\"us-east-1\"\n)\n\ns3 = session.client(\"s3\")\n```\n\n### Resource Setup\n\n```python\nimport boto3\n\ns3 = boto3.resource(\"s3\")\n\n# With region\ns3 = boto3.resource(\"s3\", region_name=\"us-west-2\")\n```\n\n### Client with Custom Endpoint (LocalStack, MinIO)\n\n```python\nimport boto3\n\ns3 = boto3.client(\n    \"s3\",\n    endpoint_url=\"http://localhost:4566\",\n    aws_access_key_id=\"test\",\n    aws_secret_access_key=\"test\",\n    region_name=\"us-east-1\"\n)\n```\n\n---\n\n## Bucket Operations\n\n### List All Buckets\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_buckets():\n    try:\n        response = s3.list_buckets()\n\n        print(\"Buckets:\")\n        for bucket in response[\"Buckets\"]:\n            print(f\"  • {bucket['Name']} (Created: {bucket['CreationDate']})\")\n    except Exception as e:\n        print(f\"Error listing buckets: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef list_buckets_resource():\n    for bucket in s3.buckets.all():\n        print(f\"  • {bucket.name}\")\n```\n\n### Create Bucket\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef create_bucket(bucket_name):\n    try:\n        s3.create_bucket(Bucket=bucket_name)\n        print(f\"Bucket created: {bucket_name}\")\n    except Exception as e:\n        print(f\"Error creating bucket: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef create_bucket_resource(bucket_name):\n    try:\n        s3.create_bucket(Bucket=bucket_name)\n        print(f\"Bucket created: {bucket_name}\")\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n### Create Bucket in Specific Region\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\", region_name=\"us-west-2\")\n\ndef create_bucket_in_region(bucket_name, region):\n    try:\n        if region == \"us-east-1\":\n            s3.create_bucket(Bucket=bucket_name)\n        else:\n            s3.create_bucket(\n                Bucket=bucket_name,\n                CreateBucketConfiguration={\"LocationConstraint\": region}\n            )\n\n        print(f\"Bucket created in {region}\")\n    except Exception as e:\n        print(f\"Error creating bucket: {e}\")\n```\n\n### Delete Bucket\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_bucket(bucket_name):\n    try:\n        s3.delete_bucket(Bucket=bucket_name)\n        print(f\"Bucket deleted: {bucket_name}\")\n    except Exception as e:\n        print(f\"Error deleting bucket: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef delete_bucket_resource(bucket_name):\n    try:\n        bucket = s3.Bucket(bucket_name)\n        bucket.delete()\n        print(f\"Bucket deleted: {bucket_name}\")\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n### Check if Bucket Exists\n\n```python\nimport boto3\nfrom botocore.exceptions import ClientError\n\ns3 = boto3.client(\"s3\")\n\ndef bucket_exists(bucket_name):\n    try:\n        s3.head_bucket(Bucket=bucket_name)\n        return True\n    except ClientError as e:\n        if e.response[\"Error\"][\"Code\"] == \"404\":\n            return False\n        raise\n```\n\n### Get Bucket Location\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef get_bucket_location(bucket_name):\n    try:\n        response = s3.get_bucket_location(Bucket=bucket_name)\n        location = response[\"LocationConstraint\"]\n\n        # us-east-1 returns None\n        if location is None:\n            location = \"us-east-1\"\n\n        print(f\"Bucket location: {location}\")\n        return location\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n---\n\n## Object Upload Operations\n\n### Upload File from Disk\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_file(file_path, bucket_name, object_key):\n    try:\n        s3.upload_file(file_path, bucket_name, object_key)\n        print(f\"Uploaded {file_path} to {bucket_name}/{object_key}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef upload_file_resource(file_path, bucket_name, object_key):\n    try:\n        bucket = s3.Bucket(bucket_name)\n        bucket.upload_file(file_path, object_key)\n        print(f\"Uploaded {file_path}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Upload with put_object\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_object(bucket_name, key, data):\n    try:\n        s3.put_object(\n            Bucket=bucket_name,\n            Key=key,\n            Body=data\n        )\n        print(f\"Uploaded to {key}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n\n# Upload string\nupload_object(\"my-bucket\", \"file.txt\", b\"Hello, S3!\")\n\n# Upload JSON\nimport json\nupload_object(\"my-bucket\", \"data.json\", json.dumps({\"key\": \"value\"}))\n```\n\n### Upload with Content Type\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_with_content_type(bucket_name, key, file_path, content_type):\n    try:\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            ExtraArgs={\"ContentType\": content_type}\n        )\n        print(f\"Uploaded {key} as {content_type}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n\n# Usage\nupload_with_content_type(\n    \"my-bucket\",\n    \"image.jpg\",\n    \"./photo.jpg\",\n    \"image/jpeg\"\n)\n```\n\n### Upload with Metadata\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_with_metadata(bucket_name, key, file_path):\n    try:\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            ExtraArgs={\n                \"Metadata\": {\n                    \"uploaded-by\": \"user123\",\n                    \"original-name\": \"document.pdf\",\n                    \"category\": \"reports\"\n                }\n            }\n        )\n        print(\"Uploaded with metadata\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Upload with Server-Side Encryption\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_encrypted(bucket_name, key, file_path):\n    try:\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            ExtraArgs={\"ServerSideEncryption\": \"AES256\"}\n        )\n        print(\"Uploaded with encryption\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Upload with ACL\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_with_acl(bucket_name, key, file_path):\n    try:\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            ExtraArgs={\"ACL\": \"public-read\"}\n        )\n        print(\"Uploaded as public\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Upload Binary Data\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef upload_binary(bucket_name, key, data):\n    try:\n        s3.put_object(\n            Bucket=bucket_name,\n            Key=key,\n            Body=data,\n            ContentType=\"application/octet-stream\"\n        )\n        print(f\"Uploaded binary data to {key}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n\n# Usage\nwith open(\"image.png\", \"rb\") as f:\n    upload_binary(\"my-bucket\", \"uploads/image.png\", f.read())\n```\n\n### Batch Upload Multiple Files\n\n```python\nimport boto3\nimport os\n\ns3 = boto3.client(\"s3\")\n\ndef upload_directory(directory_path, bucket_name, s3_prefix=\"\"):\n    try:\n        for root, dirs, files in os.walk(directory_path):\n            for file in files:\n                local_path = os.path.join(root, file)\n                relative_path = os.path.relpath(local_path, directory_path)\n                s3_key = os.path.join(s3_prefix, relative_path).replace(\"\\\\\", \"/\")\n\n                s3.upload_file(local_path, bucket_name, s3_key)\n                print(f\"Uploaded: {s3_key}\")\n\n        print(f\"Uploaded directory: {directory_path}\")\n    except Exception as e:\n        print(f\"Batch upload error: {e}\")\n```\n\n---\n\n## Object Download Operations\n\n### Download File to Disk\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef download_file(bucket_name, key, file_path):\n    try:\n        s3.download_file(bucket_name, key, file_path)\n        print(f\"Downloaded to {file_path}\")\n    except Exception as e:\n        print(f\"Download error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef download_file_resource(bucket_name, key, file_path):\n    try:\n        bucket = s3.Bucket(bucket_name)\n        bucket.download_file(key, file_path)\n        print(f\"Downloaded to {file_path}\")\n    except Exception as e:\n        print(f\"Download error: {e}\")\n```\n\n### Download as Bytes\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef download_as_bytes(bucket_name, key):\n    try:\n        response = s3.get_object(Bucket=bucket_name, Key=key)\n        data = response[\"Body\"].read()\n        return data\n    except Exception as e:\n        print(f\"Download error: {e}\")\n        return None\n\n# Usage\ndata = download_as_bytes(\"my-bucket\", \"file.txt\")\n```\n\n### Download as String\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef download_as_string(bucket_name, key, encoding=\"utf-8\"):\n    try:\n        response = s3.get_object(Bucket=bucket_name, Key=key)\n        content = response[\"Body\"].read().decode(encoding)\n        return content\n    except Exception as e:\n        print(f\"Download error: {e}\")\n        return None\n\n# Download JSON\nimport json\n\ndef download_json(bucket_name, key):\n    content = download_as_string(bucket_name, key)\n    if content:\n        return json.loads(content)\n    return None\n```\n\n### Download with Error Handling\n\n```python\nimport boto3\nfrom botocore.exceptions import ClientError\n\ns3 = boto3.client(\"s3\")\n\ndef download_safe(bucket_name, key, file_path):\n    try:\n        s3.download_file(bucket_name, key, file_path)\n        print(f\"Downloaded to {file_path}\")\n        return True\n    except ClientError as e:\n        if e.response[\"Error\"][\"Code\"] == \"404\":\n            print(f\"Object not found: {key}\")\n        else:\n            print(f\"Error: {e}\")\n        return False\n```\n\n### Download with Version\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef download_version(bucket_name, key, file_path, version_id):\n    try:\n        s3.download_file(\n            bucket_name,\n            key,\n            file_path,\n            ExtraArgs={\"VersionId\": version_id}\n        )\n        print(f\"Downloaded version {version_id}\")\n    except Exception as e:\n        print(f\"Download error: {e}\")\n```\n\n### Download Byte Range\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef download_range(bucket_name, key, start, end):\n    try:\n        response = s3.get_object(\n            Bucket=bucket_name,\n            Key=key,\n            Range=f\"bytes={start}-{end}\"\n        )\n        data = response[\"Body\"].read()\n        return data\n    except Exception as e:\n        print(f\"Download error: {e}\")\n        return None\n```\n\n### Get Object Metadata Only\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef get_object_metadata(bucket_name, key):\n    try:\n        response = s3.head_object(Bucket=bucket_name, Key=key)\n\n        print(\"Metadata:\")\n        print(f\"  Content-Type: {response.get('ContentType')}\")\n        print(f\"  Content-Length: {response.get('ContentLength')} bytes\")\n        print(f\"  Last Modified: {response.get('LastModified')}\")\n        print(f\"  ETag: {response.get('ETag')}\")\n        print(f\"  Metadata: {response.get('Metadata')}\")\n\n        return response\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n---\n\n## List Objects\n\n### List All Objects\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_objects(bucket_name):\n    try:\n        response = s3.list_objects_v2(Bucket=bucket_name)\n\n        if \"Contents\" in response:\n            print(\"Objects:\")\n            for obj in response[\"Contents\"]:\n                print(f\"  • {obj['Key']} ({obj['Size']} bytes)\")\n        else:\n            print(\"Bucket is empty\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef list_objects_resource(bucket_name):\n    try:\n        bucket = s3.Bucket(bucket_name)\n\n        for obj in bucket.objects.all():\n            print(f\"  • {obj.key} ({obj.size} bytes)\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n```\n\n### List Objects with Prefix\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_objects_with_prefix(bucket_name, prefix):\n    try:\n        response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)\n\n        if \"Contents\" in response:\n            print(f\"Objects with prefix '{prefix}':\")\n            for obj in response[\"Contents\"]:\n                print(f\"  • {obj['Key']}\")\n        else:\n            print(f\"No objects with prefix '{prefix}'\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef list_objects_with_prefix_resource(bucket_name, prefix):\n    bucket = s3.Bucket(bucket_name)\n\n    for obj in bucket.objects.filter(Prefix=prefix):\n        print(f\"  • {obj.key}\")\n```\n\n### List Objects with Pagination\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_objects_paginated(bucket_name):\n    try:\n        paginator = s3.get_paginator(\"list_objects_v2\")\n        page_iterator = paginator.paginate(Bucket=bucket_name)\n\n        total_objects = 0\n\n        for page in page_iterator:\n            if \"Contents\" in page:\n                for obj in page[\"Contents\"]:\n                    print(f\"  • {obj['Key']}\")\n                    total_objects += 1\n\n        print(f\"\\nTotal objects: {total_objects}\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n```\n\n### List Objects with Max Keys\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_objects_limited(bucket_name, max_keys=10):\n    try:\n        response = s3.list_objects_v2(Bucket=bucket_name, MaxKeys=max_keys)\n\n        if \"Contents\" in response:\n            for obj in response[\"Contents\"]:\n                print(f\"  • {obj['Key']}\")\n\n            print(f\"\\nShowing {len(response['Contents'])} objects\")\n            print(f\"More available: {response.get('IsTruncated', False)}\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n```\n\n### List Objects in Folder Structure\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_folder(bucket_name, prefix=\"\"):\n    try:\n        response = s3.list_objects_v2(\n            Bucket=bucket_name,\n            Prefix=prefix,\n            Delimiter=\"/\"\n        )\n\n        # List folders (common prefixes)\n        if \"CommonPrefixes\" in response:\n            print(\"Folders:\")\n            for cp in response[\"CommonPrefixes\"]:\n                print(f\"  📁 {cp['Prefix']}\")\n\n        # List files\n        if \"Contents\" in response:\n            print(\"\\nFiles:\")\n            for obj in response[\"Contents\"]:\n                print(f\"  📄 {obj['Key']}\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n```\n\n### List with Filter\n\n```python\nimport boto3\n\ns3 = boto3.resource(\"s3\")\n\ndef list_objects_filtered(bucket_name, extension):\n    try:\n        bucket = s3.Bucket(bucket_name)\n\n        for obj in bucket.objects.all():\n            if obj.key.endswith(extension):\n                print(f\"  • {obj.key}\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n\n# Usage\nlist_objects_filtered(\"my-bucket\", \".jpg\")\n```\n\n---\n\n## Delete Operations\n\n### Delete Single Object\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_object(bucket_name, key):\n    try:\n        s3.delete_object(Bucket=bucket_name, Key=key)\n        print(f\"Deleted: {key}\")\n    except Exception as e:\n        print(f\"Delete error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef delete_object_resource(bucket_name, key):\n    try:\n        obj = s3.Object(bucket_name, key)\n        obj.delete()\n        print(f\"Deleted: {key}\")\n    except Exception as e:\n        print(f\"Delete error: {e}\")\n```\n\n### Delete Multiple Objects (Batch)\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_multiple_objects(bucket_name, keys):\n    try:\n        response = s3.delete_objects(\n            Bucket=bucket_name,\n            Delete={\n                \"Objects\": [{\"Key\": key} for key in keys]\n            }\n        )\n\n        if \"Deleted\" in response:\n            print(f\"Deleted {len(response['Deleted'])} objects:\")\n            for obj in response[\"Deleted\"]:\n                print(f\"  • {obj['Key']}\")\n\n        if \"Errors\" in response:\n            print(\"Errors:\")\n            for error in response[\"Errors\"]:\n                print(f\"  • {error['Key']}: {error['Message']}\")\n    except Exception as e:\n        print(f\"Batch delete error: {e}\")\n\n# Usage\ndelete_multiple_objects(\"my-bucket\", [\"file1.txt\", \"file2.txt\", \"file3.txt\"])\n```\n\n### Delete All Objects with Prefix\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_objects_with_prefix(bucket_name, prefix):\n    try:\n        response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)\n\n        if \"Contents\" not in response:\n            print(\"No objects to delete\")\n            return\n\n        keys = [obj[\"Key\"] for obj in response[\"Contents\"]]\n\n        s3.delete_objects(\n            Bucket=bucket_name,\n            Delete={\"Objects\": [{\"Key\": key} for key in keys]}\n        )\n\n        print(f\"Deleted {len(keys)} objects with prefix '{prefix}'\")\n    except Exception as e:\n        print(f\"Delete error: {e}\")\n```\n\n### Delete All Objects in Bucket\n\n```python\nimport boto3\n\ns3 = boto3.resource(\"s3\")\n\ndef empty_bucket(bucket_name):\n    try:\n        bucket = s3.Bucket(bucket_name)\n        bucket.objects.all().delete()\n        print(f\"Emptied bucket: {bucket_name}\")\n    except Exception as e:\n        print(f\"Empty error: {e}\")\n```\n\n### Empty and Delete Bucket\n\n```python\nimport boto3\n\ns3 = boto3.resource(\"s3\")\n\ndef empty_and_delete_bucket(bucket_name):\n    try:\n        bucket = s3.Bucket(bucket_name)\n\n        # Delete all objects\n        bucket.objects.all().delete()\n        print(f\"Deleted all objects\")\n\n        # Delete all object versions (if versioning enabled)\n        bucket.object_versions.all().delete()\n        print(f\"Deleted all object versions\")\n\n        # Delete bucket\n        bucket.delete()\n        print(f\"Deleted bucket: {bucket_name}\")\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n---\n\n## Copy and Move Operations\n\n### Copy Object\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef copy_object(source_bucket, source_key, dest_bucket, dest_key):\n    try:\n        copy_source = {\"Bucket\": source_bucket, \"Key\": source_key}\n\n        s3.copy_object(\n            CopySource=copy_source,\n            Bucket=dest_bucket,\n            Key=dest_key\n        )\n\n        print(f\"Copied {source_key} to {dest_key}\")\n    except Exception as e:\n        print(f\"Copy error: {e}\")\n\n# Using resource\ns3 = boto3.resource(\"s3\")\n\ndef copy_object_resource(source_bucket, source_key, dest_bucket, dest_key):\n    try:\n        copy_source = {\"Bucket\": source_bucket, \"Key\": source_key}\n\n        dest_obj = s3.Object(dest_bucket, dest_key)\n        dest_obj.copy_from(CopySource=copy_source)\n\n        print(f\"Copied {source_key} to {dest_key}\")\n    except Exception as e:\n        print(f\"Copy error: {e}\")\n```\n\n### Copy with Metadata\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef copy_with_metadata(source_bucket, source_key, dest_bucket, dest_key):\n    try:\n        copy_source = {\"Bucket\": source_bucket, \"Key\": source_key}\n\n        s3.copy_object(\n            CopySource=copy_source,\n            Bucket=dest_bucket,\n            Key=dest_key,\n            Metadata={\n                \"copied-from\": source_key,\n                \"copied-date\": \"2025-10-26\"\n            },\n            MetadataDirective=\"REPLACE\"\n        )\n\n        print(\"Copied with new metadata\")\n    except Exception as e:\n        print(f\"Copy error: {e}\")\n```\n\n### Move Object (Copy + Delete)\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef move_object(source_bucket, source_key, dest_bucket, dest_key):\n    try:\n        # Copy\n        copy_source = {\"Bucket\": source_bucket, \"Key\": source_key}\n        s3.copy_object(\n            CopySource=copy_source,\n            Bucket=dest_bucket,\n            Key=dest_key\n        )\n\n        # Delete source\n        s3.delete_object(Bucket=source_bucket, Key=source_key)\n\n        print(f\"Moved {source_key} to {dest_key}\")\n    except Exception as e:\n        print(f\"Move error: {e}\")\n```\n\n---\n\n## Presigned URLs\n\n### Presigned URL for Download (GET)\n\n```python\nimport boto3\nfrom botocore.config import Config\n\ns3 = boto3.client(\"s3\", config=Config(signature_version=\"s3v4\"))\n\ndef create_presigned_download_url(bucket_name, key, expiration=3600):\n    try:\n        url = s3.generate_presigned_url(\n            ClientMethod=\"get_object\",\n            Params={\"Bucket\": bucket_name, \"Key\": key},\n            ExpiresIn=expiration\n        )\n        return url\n    except Exception as e:\n        print(f\"Presigned URL error: {e}\")\n        return None\n\n# Usage\nurl = create_presigned_download_url(\"my-bucket\", \"file.pdf\", 3600)\nprint(f\"Download URL: {url}\")\n```\n\n### Presigned URL for Upload (PUT)\n\n```python\nimport boto3\nfrom botocore.config import Config\n\ns3 = boto3.client(\"s3\", config=Config(signature_version=\"s3v4\"))\n\ndef create_presigned_upload_url(bucket_name, key, expiration=3600):\n    try:\n        url = s3.generate_presigned_url(\n            ClientMethod=\"put_object\",\n            Params={\"Bucket\": bucket_name, \"Key\": key},\n            ExpiresIn=expiration\n        )\n        return url\n    except Exception as e:\n        print(f\"Presigned URL error: {e}\")\n        return None\n\n# Usage with requests\nimport requests\n\nupload_url = create_presigned_upload_url(\"my-bucket\", \"upload.txt\")\n\nwith open(\"file.txt\", \"rb\") as f:\n    response = requests.put(upload_url, data=f)\n    print(f\"Upload status: {response.status_code}\")\n```\n\n### Presigned URL with Content Type\n\n```python\nimport boto3\nfrom botocore.config import Config\n\ns3 = boto3.client(\"s3\", config=Config(signature_version=\"s3v4\"))\n\ndef create_presigned_url_with_type(bucket_name, key, content_type, expiration=3600):\n    try:\n        url = s3.generate_presigned_url(\n            ClientMethod=\"put_object\",\n            Params={\n                \"Bucket\": bucket_name,\n                \"Key\": key,\n                \"ContentType\": content_type\n            },\n            ExpiresIn=expiration\n        )\n        return url\n    except Exception as e:\n        print(f\"Presigned URL error: {e}\")\n        return None\n```\n\n### Presigned POST for File Upload\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef create_presigned_post(bucket_name, key, expiration=3600):\n    try:\n        response = s3.generate_presigned_post(\n            Bucket=bucket_name,\n            Key=key,\n            ExpiresIn=expiration\n        )\n        return response\n    except Exception as e:\n        print(f\"Presigned POST error: {e}\")\n        return None\n\n# Usage\npresigned_post = create_presigned_post(\"my-bucket\", \"upload.txt\")\n\n# Client uploads using POST with the URL and fields\nimport requests\n\nwith open(\"file.txt\", \"rb\") as f:\n    files = {\"file\": f}\n    response = requests.post(\n        presigned_post[\"url\"],\n        data=presigned_post[\"fields\"],\n        files=files\n    )\n    print(f\"Upload status: {response.status_code}\")\n```\n\n### Presigned POST with Conditions\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef create_presigned_post_with_conditions(bucket_name, key, max_size=10485760):\n    try:\n        response = s3.generate_presigned_post(\n            Bucket=bucket_name,\n            Key=key,\n            Fields={\"acl\": \"public-read\"},\n            Conditions=[\n                {\"acl\": \"public-read\"},\n                [\"content-length-range\", 0, max_size]  # Max 10 MB\n            ],\n            ExpiresIn=3600\n        )\n        return response\n    except Exception as e:\n        print(f\"Presigned POST error: {e}\")\n        return None\n```\n\n---\n\n## Multipart Upload\n\n### Automatic Multipart Upload (Recommended)\n\n```python\nimport boto3\nfrom boto3.s3.transfer import TransferConfig\n\ns3 = boto3.client(\"s3\")\n\ndef multipart_upload(file_path, bucket_name, key):\n    try:\n        # Configure multipart upload\n        config = TransferConfig(\n            multipart_threshold=1024 * 25,  # 25 MB\n            max_concurrency=10,\n            multipart_chunksize=1024 * 25,  # 25 MB\n            use_threads=True\n        )\n\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            Config=config\n        )\n\n        print(f\"Multipart upload complete: {key}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Multipart Upload with Progress Callback\n\n```python\nimport boto3\nimport sys\n\ns3 = boto3.client(\"s3\")\n\nclass ProgressPercentage:\n    def __init__(self, filename):\n        self._filename = filename\n        self._size = float(os.path.getsize(filename))\n        self._seen_so_far = 0\n\n    def __call__(self, bytes_amount):\n        self._seen_so_far += bytes_amount\n        percentage = (self._seen_so_far / self._size) * 100\n        sys.stdout.write(\n            f\"\\r{self._filename}: {self._seen_so_far} / {self._size} ({percentage:.2f}%)\"\n        )\n        sys.stdout.flush()\n\ndef multipart_upload_with_progress(file_path, bucket_name, key):\n    try:\n        s3.upload_file(\n            file_path,\n            bucket_name,\n            key,\n            Callback=ProgressPercentage(file_path)\n        )\n        print(f\"\\nUpload complete: {key}\")\n    except Exception as e:\n        print(f\"Upload error: {e}\")\n```\n\n### Manual Multipart Upload (Low-Level)\n\n```python\nimport boto3\nimport os\n\ns3 = boto3.client(\"s3\")\n\ndef manual_multipart_upload(file_path, bucket_name, key):\n    try:\n        # Step 1: Initiate multipart upload\n        response = s3.create_multipart_upload(\n            Bucket=bucket_name,\n            Key=key\n        )\n        upload_id = response[\"UploadId\"]\n\n        # Step 2: Upload parts\n        parts = []\n        chunk_size = 10 * 1024 * 1024  # 10 MB\n        part_number = 1\n\n        with open(file_path, \"rb\") as f:\n            while True:\n                data = f.read(chunk_size)\n                if not data:\n                    break\n\n                response = s3.upload_part(\n                    Bucket=bucket_name,\n                    Key=key,\n                    PartNumber=part_number,\n                    UploadId=upload_id,\n                    Body=data\n                )\n\n                parts.append({\n                    \"PartNumber\": part_number,\n                    \"ETag\": response[\"ETag\"]\n                })\n\n                print(f\"Uploaded part {part_number}\")\n                part_number += 1\n\n        # Step 3: Complete multipart upload\n        s3.complete_multipart_upload(\n            Bucket=bucket_name,\n            Key=key,\n            UploadId=upload_id,\n            MultipartUpload={\"Parts\": parts}\n        )\n\n        print(f\"Multipart upload complete: {key}\")\n    except Exception as e:\n        # Abort multipart upload on error\n        s3.abort_multipart_upload(\n            Bucket=bucket_name,\n            Key=key,\n            UploadId=upload_id\n        )\n        print(f\"Upload error: {e}\")\n```\n\n### List In-Progress Multipart Uploads\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef list_multipart_uploads(bucket_name):\n    try:\n        response = s3.list_multipart_uploads(Bucket=bucket_name)\n\n        if \"Uploads\" in response:\n            print(\"In-progress uploads:\")\n            for upload in response[\"Uploads\"]:\n                print(f\"  • {upload['Key']} (ID: {upload['UploadId']})\")\n        else:\n            print(\"No in-progress uploads\")\n    except Exception as e:\n        print(f\"List error: {e}\")\n```\n\n### Abort Multipart Upload\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef abort_multipart_upload(bucket_name, key, upload_id):\n    try:\n        s3.abort_multipart_upload(\n            Bucket=bucket_name,\n            Key=key,\n            UploadId=upload_id\n        )\n        print(f\"Aborted upload: {key}\")\n    except Exception as e:\n        print(f\"Abort error: {e}\")\n```\n\n---\n\n## Object Tagging\n\n### Put Object Tags\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef tag_object(bucket_name, key, tags):\n    try:\n        s3.put_object_tagging(\n            Bucket=bucket_name,\n            Key=key,\n            Tagging={\n                \"TagSet\": [\n                    {\"Key\": k, \"Value\": v} for k, v in tags.items()\n                ]\n            }\n        )\n        print(f\"Tagged {key}\")\n    except Exception as e:\n        print(f\"Tagging error: {e}\")\n\n# Usage\ntag_object(\"my-bucket\", \"file.txt\", {\n    \"Environment\": \"Production\",\n    \"Department\": \"Engineering\"\n})\n```\n\n### Get Object Tags\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef get_object_tags(bucket_name, key):\n    try:\n        response = s3.get_object_tagging(Bucket=bucket_name, Key=key)\n\n        print(\"Tags:\")\n        for tag in response[\"TagSet\"]:\n            print(f\"  {tag['Key']}: {tag['Value']}\")\n\n        return response[\"TagSet\"]\n    except Exception as e:\n        print(f\"Get tags error: {e}\")\n        return None\n```\n\n### Delete Object Tags\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_object_tags(bucket_name, key):\n    try:\n        s3.delete_object_tagging(Bucket=bucket_name, Key=key)\n        print(f\"Deleted tags from {key}\")\n    except Exception as e:\n        print(f\"Delete tags error: {e}\")\n```\n\n---\n\n## Bucket Configuration\n\n### Enable Versioning\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef enable_versioning(bucket_name):\n    try:\n        s3.put_bucket_versioning(\n            Bucket=bucket_name,\n            VersioningConfiguration={\"Status\": \"Enabled\"}\n        )\n        print(f\"Versioning enabled for {bucket_name}\")\n    except Exception as e:\n        print(f\"Versioning error: {e}\")\n```\n\n### Get Versioning Status\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef get_versioning_status(bucket_name):\n    try:\n        response = s3.get_bucket_versioning(Bucket=bucket_name)\n        status = response.get(\"Status\", \"Disabled\")\n        print(f\"Versioning status: {status}\")\n        return status\n    except Exception as e:\n        print(f\"Error: {e}\")\n```\n\n### Set Bucket CORS\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef set_bucket_cors(bucket_name):\n    try:\n        cors_configuration = {\n            \"CORSRules\": [\n                {\n                    \"AllowedHeaders\": [\"*\"],\n                    \"AllowedMethods\": [\"GET\", \"PUT\", \"POST\", \"DELETE\"],\n                    \"AllowedOrigins\": [\"*\"],\n                    \"ExposeHeaders\": [\"ETag\"],\n                    \"MaxAgeSeconds\": 3000\n                }\n            ]\n        }\n\n        s3.put_bucket_cors(\n            Bucket=bucket_name,\n            CORSConfiguration=cors_configuration\n        )\n\n        print(\"CORS configured\")\n    except Exception as e:\n        print(f\"CORS error: {e}\")\n```\n\n### Get Bucket CORS\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef get_bucket_cors(bucket_name):\n    try:\n        response = s3.get_bucket_cors(Bucket=bucket_name)\n        print(\"CORS Rules:\")\n        print(response[\"CORSRules\"])\n        return response[\"CORSRules\"]\n    except Exception as e:\n        print(f\"Get CORS error: {e}\")\n        return None\n```\n\n### Delete Bucket CORS\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef delete_bucket_cors(bucket_name):\n    try:\n        s3.delete_bucket_cors(Bucket=bucket_name)\n        print(\"CORS configuration deleted\")\n    except Exception as e:\n        print(f\"Delete CORS error: {e}\")\n```\n\n### Set Bucket Encryption\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef set_bucket_encryption(bucket_name):\n    try:\n        s3.put_bucket_encryption(\n            Bucket=bucket_name,\n            ServerSideEncryptionConfiguration={\n                \"Rules\": [\n                    {\n                        \"ApplyServerSideEncryptionByDefault\": {\n                            \"SSEAlgorithm\": \"AES256\"\n                        }\n                    }\n                ]\n            }\n        )\n        print(\"Encryption enabled\")\n    except Exception as e:\n        print(f\"Encryption error: {e}\")\n```\n\n### Set Bucket Lifecycle Policy\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef set_lifecycle_policy(bucket_name):\n    try:\n        s3.put_bucket_lifecycle_configuration(\n            Bucket=bucket_name,\n            LifecycleConfiguration={\n                \"Rules\": [\n                    {\n                        \"Id\": \"DeleteOldObjects\",\n                        \"Status\": \"Enabled\",\n                        \"Expiration\": {\"Days\": 90},\n                        \"Filter\": {\"Prefix\": \"logs/\"}\n                    }\n                ]\n            }\n        )\n        print(\"Lifecycle policy configured\")\n    except Exception as e:\n        print(f\"Lifecycle error: {e}\")\n```\n\n---\n\n## Waiters\n\n### Wait Until Object Exists\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef wait_for_object(bucket_name, key):\n    try:\n        waiter = s3.get_waiter(\"object_exists\")\n        waiter.wait(Bucket=bucket_name, Key=key)\n        print(f\"Object exists: {key}\")\n    except Exception as e:\n        print(f\"Wait error: {e}\")\n```\n\n### Wait Until Object Not Exists\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef wait_for_object_deletion(bucket_name, key):\n    try:\n        waiter = s3.get_waiter(\"object_not_exists\")\n        waiter.wait(Bucket=bucket_name, Key=key)\n        print(f\"Object deleted: {key}\")\n    except Exception as e:\n        print(f\"Wait error: {e}\")\n```\n\n### Wait Until Bucket Exists\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\")\n\ndef wait_for_bucket(bucket_name):\n    try:\n        waiter = s3.get_waiter(\"bucket_exists\")\n        waiter.wait(Bucket=bucket_name)\n        print(f\"Bucket exists: {bucket_name}\")\n    except Exception as e:\n        print(f\"Wait error: {e}\")\n```\n\n---\n\n## Error Handling\n\n### Common Error Types\n\n```python\nimport boto3\nfrom botocore.exceptions import ClientError, NoCredentialsError\n\ns3 = boto3.client(\"s3\")\n\ndef handle_errors(bucket_name, key):\n    try:\n        response = s3.get_object(Bucket=bucket_name, Key=key)\n        return response[\"Body\"].read()\n    except NoCredentialsError:\n        print(\"No AWS credentials found\")\n    except ClientError as e:\n        error_code = e.response[\"Error\"][\"Code\"]\n\n        if error_code == \"NoSuchKey\":\n            print(\"Object not found\")\n        elif error_code == \"NoSuchBucket\":\n            print(\"Bucket not found\")\n        elif error_code == \"AccessDenied\":\n            print(\"Access denied\")\n        elif error_code == \"InvalidAccessKeyId\":\n            print(\"Invalid credentials\")\n        else:\n            print(f\"Error: {error_code}\")\n    except Exception as e:\n        print(f\"Unknown error: {e}\")\n```\n\n### Retry Logic with Backoff\n\n```python\nimport boto3\nimport time\nfrom botocore.exceptions import ClientError\n\ns3 = boto3.client(\"s3\")\n\ndef download_with_retry(bucket_name, key, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            response = s3.get_object(Bucket=bucket_name, Key=key)\n            return response[\"Body\"].read()\n        except ClientError as e:\n            if attempt < max_retries - 1:\n                wait_time = 2 ** attempt  # Exponential backoff\n                print(f\"Attempt {attempt + 1} failed, retrying in {wait_time}s...\")\n                time.sleep(wait_time)\n            else:\n                raise\n```\n\n### Custom Retry Configuration\n\n```python\nimport boto3\nfrom botocore.config import Config\n\n# Configure custom retry settings\nconfig = Config(\n    retries={\n        \"max_attempts\": 10,\n        \"mode\": \"adaptive\"\n    }\n)\n\ns3 = boto3.client(\"s3\", config=config)\n```\n\n---\n\n## Complete Example: Full S3 Operations\n\n```python\nimport boto3\nfrom botocore.exceptions import ClientError\nimport json\n\ndef main():\n    s3 = boto3.client(\"s3\", region_name=\"us-east-1\")\n    bucket_name = f\"my-test-bucket-{int(time.time())}\"\n\n    try:\n        # 1. Create bucket\n        print(\"Creating bucket...\")\n        s3.create_bucket(Bucket=bucket_name)\n\n        # 2. Upload object\n        print(\"Uploading object...\")\n        s3.put_object(\n            Bucket=bucket_name,\n            Key=\"test-file.txt\",\n            Body=b\"Hello, S3!\",\n            ContentType=\"text/plain\"\n        )\n\n        # 3. Generate presigned URL\n        print(\"Generating presigned URL...\")\n        url = s3.generate_presigned_url(\n            ClientMethod=\"get_object\",\n            Params={\"Bucket\": bucket_name, \"Key\": \"test-file.txt\"},\n            ExpiresIn=3600\n        )\n        print(f\"Presigned URL: {url}\")\n\n        # 4. Download object\n        print(\"Downloading object...\")\n        response = s3.get_object(Bucket=bucket_name, Key=\"test-file.txt\")\n        content = response[\"Body\"].read().decode(\"utf-8\")\n        print(f\"Content: {content}\")\n\n        # 5. List objects\n        print(\"Listing objects...\")\n        response = s3.list_objects_v2(Bucket=bucket_name)\n        for obj in response.get(\"Contents\", []):\n            print(f\"  • {obj['Key']}\")\n\n        # 6. Delete object\n        print(\"Deleting object...\")\n        s3.delete_object(Bucket=bucket_name, Key=\"test-file.txt\")\n\n        # 7. Delete bucket\n        print(\"Deleting bucket...\")\n        s3.delete_bucket(Bucket=bucket_name)\n\n        print(\"Complete!\")\n\n    except ClientError as e:\n        print(f\"Error: {e}\")\n\nif __name__ == \"__main__\":\n    import time\n    main()\n```\n"
  },
  {
    "path": "content/aws/docs/s3-presigned-post/javascript/DOC.md",
    "content": "---\nname: s3-presigned-post\ndescription: \"AWS SDK for JavaScript v3 helper for generating S3 browser-based presigned POST uploads.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,s3,javascript,nodejs,browser-uploads,presigned-posts\"\n---\n\n# `@aws-sdk/s3-presigned-post`\n\nUse this package when your backend should generate an S3 HTML form upload for a browser or other multipart client.\n\nIt returns a form `url` and signed `fields`. The uploader sends those fields back to S3 in a `multipart/form-data` POST request together with the file.\n\nUse `@aws-sdk/s3-request-presigner` instead when you need a presigned `PUT` URL rather than a browser-style form POST.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-s3@3.1007.0 @aws-sdk/s3-presigned-post@3.1007.0\n```\n\n## Prerequisites\n\nThe code that calls `createPresignedPost()` needs normal AWS SDK v3 S3 configuration:\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\nAWS_SESSION_TOKEN=...\nAWS_PROFILE=default\nS3_BUCKET=my-upload-bucket\n```\n\nUse a trusted backend to create the presigned POST. Do not expose long-lived AWS credentials in browser code.\n\nFor direct browser uploads, the target bucket also needs a CORS rule that allows your frontend origin to send `POST` requests:\n\n```bash\naws s3api put-bucket-cors \\\n  --bucket \"$S3_BUCKET\" \\\n  --cors-configuration '{\n    \"CORSRules\": [\n      {\n        \"AllowedOrigins\": [\"http://localhost:3000\"],\n        \"AllowedMethods\": [\"POST\"],\n        \"AllowedHeaders\": [\"*\"],\n        \"ExposeHeaders\": [\"ETag\"]\n      }\n    ]\n  }'\n```\n\n## Create a presigned POST on the server\n\nInitialize an `S3Client`, then call `createPresignedPost()` with the target bucket, object key, and any form constraints you want S3 to enforce.\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { createPresignedPost } from \"@aws-sdk/s3-presigned-post\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createImageUpload({ key, contentType }) {\n  const bucket = process.env.S3_BUCKET;\n\n  if (!bucket) {\n    throw new Error(\"Set S3_BUCKET\");\n  }\n\n  const { url, fields } = await createPresignedPost(s3, {\n    Bucket: bucket,\n    Key: key,\n    Fields: {\n      \"Content-Type\": contentType,\n      success_action_status: \"201\",\n    },\n    Conditions: [\n      { \"Content-Type\": contentType },\n      { success_action_status: \"201\" },\n      [\"content-length-range\", 0, 5 * 1024 * 1024],\n    ],\n    Expires: 600,\n  });\n\n  return { url, fields, key };\n}\n```\n\n`Expires` is the presigned POST lifetime in seconds.\n\nIf you want S3 to enforce a field value such as `Content-Type`, include it in both `Fields` and `Conditions`.\n\n## Upload the file from the browser\n\nYour app sends the upload intent to your backend, receives the signed form payload, then posts it directly to S3.\n\n```javascript\nexport async function uploadFile(file) {\n  const key = `uploads/${crypto.randomUUID()}-${file.name}`;\n\n  const presignResponse = await fetch(\"/api/uploads/presign\", {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\n      key,\n      contentType: file.type || \"application/octet-stream\",\n    }),\n  });\n\n  if (!presignResponse.ok) {\n    throw new Error(\"Failed to create presigned POST\");\n  }\n\n  const { url, fields } = await presignResponse.json();\n\n  const formData = new FormData();\n\n  for (const [name, value] of Object.entries(fields)) {\n    formData.append(name, value);\n  }\n\n  formData.append(\"file\", file);\n\n  const uploadResponse = await fetch(url, {\n    method: \"POST\",\n    body: formData,\n  });\n\n  if (!uploadResponse.ok) {\n    throw new Error(`S3 upload failed with ${uploadResponse.status}`);\n  }\n\n  return { key };\n}\n```\n\nThe uploader must send the returned `fields` back unchanged. Those signed values are part of the POST policy.\n\n## Common policy patterns\n\nUse exact-match object conditions when the backend already knows the value:\n\n```javascript\nconst post = await createPresignedPost(s3, {\n  Bucket: process.env.S3_BUCKET,\n  Key: \"uploads/avatar.png\",\n  Fields: {\n    \"Content-Type\": \"image/png\",\n  },\n  Conditions: [\n    { \"Content-Type\": \"image/png\" },\n    [\"content-length-range\", 0, 1 * 1024 * 1024],\n  ],\n  Expires: 300,\n});\n```\n\nUse `starts-with` when multiple values should be accepted under one signed policy:\n\n```javascript\nconst post = await createPresignedPost(s3, {\n  Bucket: process.env.S3_BUCKET,\n  Key: \"uploads/image-upload\",\n  Conditions: [\n    [\"starts-with\", \"$Content-Type\", \"image/\"],\n    [\"content-length-range\", 0, 10 * 1024 * 1024],\n  ],\n  Expires: 300,\n});\n```\n\n## Important pitfalls\n\n- Generate the presigned POST on a server you control. The browser should receive only the final `url` and `fields`.\n- Submit the request as `multipart/form-data` to the returned `url`. This package does not create a signed `PUT` URL.\n- If you need S3 to enforce a form field value, put that value in both `Fields` and `Conditions`.\n- Bucket CORS still applies for browser uploads. A valid signature alone does not bypass cross-origin restrictions.\n- The IAM credentials used by `S3Client` still need permission for the target bucket and object key.\n- Import from the package root: `@aws-sdk/s3-presigned-post`.\n\n## Version notes\n\n- This guide covers `@aws-sdk/s3-presigned-post` version `3.1007.0`.\n- Pair it with `@aws-sdk/client-s3` in the same AWS SDK v3 app.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-s3-presigned-post/\n- Amazon S3 browser-based uploads using POST: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html\n- Amazon S3 POST policy construction: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html\n- npm package page: https://www.npmjs.com/package/@aws-sdk/s3-presigned-post\n"
  },
  {
    "path": "content/aws/docs/s3-request-presigner/javascript/DOC.md",
    "content": "---\nname: s3-request-presigner\ndescription: \"Generate presigned Amazon S3 URLs in JavaScript with the AWS SDK v3.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,s3,presigned-url,signing,javascript\"\n---\n\n# `@aws-sdk/s3-request-presigner`\n\nUse `@aws-sdk/s3-request-presigner` to generate presigned Amazon S3 request URLs from AWS SDK v3 command objects. The usual flow is:\n\n1. Create an `S3Client` with the correct region and credentials.\n2. Create a command such as `GetObjectCommand` or `PutObjectCommand`.\n3. Call `getSignedUrl(client, command, { expiresIn })`.\n4. Return that URL to the caller that should upload or download the object.\n\nThis package signs requests. It does not upload or download data itself.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner\n```\n\n## Prerequisites\n\nGenerate presigned URLs on a trusted server or serverless function that already has permission to access the target bucket.\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=your-access-key-id\nAWS_SECRET_ACCESS_KEY=your-secret-access-key\nAWS_SESSION_TOKEN=your-session-token\nAWS_S3_BUCKET=your-bucket-name\n```\n\nIf you use shared AWS config instead of environment variables, the SDK can also resolve credentials from your usual AWS profile and config chain.\n\n## Initialize the S3 client\n\n```javascript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst region = process.env.AWS_REGION ?? \"us-east-1\";\n\nexport const s3 = new S3Client({\n  region,\n});\n```\n\nUse the bucket's actual region. A region mismatch produces invalid signatures.\n\n## Create a presigned download URL\n\nUse `GetObjectCommand` when another client should download an existing object without holding AWS credentials.\n\n```javascript\nimport { GetObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createDownloadUrl(bucket, key) {\n  const command = new GetObjectCommand({\n    Bucket: bucket,\n    Key: key,\n  });\n\n  return getSignedUrl(s3, command, {\n    expiresIn: 3600,\n  });\n}\n\nconst url = await createDownloadUrl(\n  process.env.AWS_S3_BUCKET,\n  \"reports/quarterly.pdf\",\n);\n\nconsole.log(url);\n```\n\nThe caller can then issue a normal `GET` request to that URL.\n\n## Create a presigned upload URL\n\nUse `PutObjectCommand` when you want a browser or other client to upload directly to S3.\n\n```javascript\nimport { PutObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createUploadUrl(bucket, key, contentType) {\n  const command = new PutObjectCommand({\n    Bucket: bucket,\n    Key: key,\n    ContentType: contentType,\n  });\n\n  return getSignedUrl(s3, command, {\n    expiresIn: 900,\n  });\n}\n```\n\nUpload with the same method and headers you signed:\n\n```javascript\nconst uploadUrl = await createUploadUrl(\n  process.env.AWS_S3_BUCKET,\n  \"uploads/report.pdf\",\n  \"application/pdf\",\n);\n\nconst response = await fetch(uploadUrl, {\n  method: \"PUT\",\n  headers: {\n    \"Content-Type\": \"application/pdf\",\n  },\n  body: fileBuffer,\n});\n\nif (!response.ok) {\n  throw new Error(`Upload failed: ${response.status} ${response.statusText}`);\n}\n```\n\nIf you sign `ContentType`, server-side encryption headers, checksum headers, or other request headers in the command input, the uploader must send matching headers on the actual request.\n\n## Presign other S3 operations\n\n`getSignedUrl()` works with normal S3 command objects, not only `GetObjectCommand`.\n\n```javascript\nimport {\n  DeleteObjectCommand,\n  HeadObjectCommand,\n  S3Client,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst headUrl = await getSignedUrl(\n  s3,\n  new HeadObjectCommand({\n    Bucket: process.env.AWS_S3_BUCKET,\n    Key: \"uploads/report.pdf\",\n  }),\n  { expiresIn: 300 },\n);\n\nconst deleteUrl = await getSignedUrl(\n  s3,\n  new DeleteObjectCommand({\n    Bucket: process.env.AWS_S3_BUCKET,\n    Key: \"uploads/report.pdf\",\n  }),\n  { expiresIn: 300 },\n);\n\nconsole.log({ headUrl, deleteUrl });\n```\n\n## Common pitfalls\n\n- Generate the URL with credentials that already have the intended S3 permissions. The presigned URL cannot do more than the signer can do.\n- Keep `expiresIn` short. It is expressed in seconds.\n- Use the correct region for the bucket or access point you are signing against.\n- Send the same signed headers on the real request, especially for uploads.\n- Return presigned URLs from a backend. Do not embed long-lived AWS credentials in a browser app just to create them client-side.\n- Use `@aws-sdk/s3-presigned-post` instead when you need a browser form POST policy rather than a signed request URL.\n\n## Version notes\n\n- This guide covers `@aws-sdk/s3-request-presigner` version `3.1007.0`.\n- Pair this package with `@aws-sdk/client-s3` in the same AWS SDK v3 dependency set to avoid unnecessary version skew.\n"
  },
  {
    "path": "content/aws/docs/s3transfer/python/DOC.md",
    "content": "---\nname: s3transfer\ndescription: \"s3transfer package guide for Python managed S3 transfer orchestration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.16.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"s3transfer,aws,s3,botocore,boto3,transfers\"\n---\n\n# s3transfer Python Package Guide\n\n## Golden Rule\n\nPrefer the stable S3 transfer helpers in `boto3` for ordinary application code.\n\nUse direct `s3transfer` APIs only when you specifically need lower-level transfer orchestration, futures, or transfer-manager configuration. Upstream marks the direct package API as not currently GA, so pin the minor version if you depend on it directly.\n\n## Installation\n\nInstall the direct package only if you need to work below the `boto3` wrapper:\n\n```bash\npip install s3transfer==0.16.0\n```\n\n```bash\nuv add s3transfer==0.16.0\n```\n\n```bash\npoetry add s3transfer==0.16.0\n```\n\nOptional AWS Common Runtime support:\n\n```bash\npip install \"s3transfer[crt]==0.16.0\"\n```\n\n## Setup And Authentication\n\n`s3transfer` does not manage AWS credentials on its own. It runs transfer workflows on top of an S3 client from `botocore` or `boto3`, so auth and region come from the normal AWS client chain:\n\n- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`\n- shared config in `~/.aws/config` and `~/.aws/credentials`\n- IAM roles or workload identity when running in AWS\n\nMinimal client setup with `botocore`:\n\n```python\nfrom botocore.session import Session\n\nsession = Session()\ns3 = session.create_client(\"s3\", region_name=\"us-east-1\")\n```\n\nIf you already use `boto3`, you can pass its S3 client instead:\n\n```python\nimport boto3\n\ns3 = boto3.client(\"s3\", region_name=\"us-east-1\")\n```\n\nFor LocalStack, MinIO, or another S3-compatible endpoint, pass `endpoint_url=...` when creating the client.\n\n## Core Usage\n\n### Preferred Stable Path: `boto3`\n\nThe direct package is the engine behind `boto3`'s managed S3 transfer helpers. For most code, stay on the documented `boto3` surface:\n\n```python\nimport boto3\nfrom boto3.s3.transfer import TransferConfig\n\ns3 = boto3.client(\"s3\", region_name=\"us-east-1\")\nconfig = TransferConfig(\n    multipart_threshold=8 * 1024 * 1024,\n    multipart_chunksize=8 * 1024 * 1024,\n    max_concurrency=10,\n)\n\ns3.upload_file(\n    \"dist/app.tar.gz\",\n    \"my-bucket\",\n    \"releases/app.tar.gz\",\n    Config=config,\n    ExtraArgs={\"ContentType\": \"application/gzip\"},\n)\n```\n\nThis is the stable interface upstream recommends for production application code.\n\n### Direct Usage: `TransferManager`\n\nUse `TransferManager` when you need direct futures and lower-level control:\n\n```python\nfrom botocore.session import Session\nfrom s3transfer.manager import TransferConfig, TransferManager\n\nsession = Session()\ns3 = session.create_client(\"s3\", region_name=\"us-east-1\")\n\nconfig = TransferConfig(\n    multipart_threshold=8 * 1024 * 1024,\n    multipart_chunksize=8 * 1024 * 1024,\n    max_request_concurrency=10,\n    max_io_queue_size=1000,\n)\n\nmanager = TransferManager(s3, config=config)\n\ntry:\n    future = manager.upload(\n        \"dist/app.tar.gz\",\n        \"my-bucket\",\n        \"releases/app.tar.gz\",\n        extra_args={\"ContentType\": \"application/gzip\"},\n    )\n    future.result()\nfinally:\n    manager.shutdown()\n```\n\nDownload example:\n\n```python\nfrom botocore.session import Session\nfrom s3transfer.manager import TransferManager\n\nsession = Session()\ns3 = session.create_client(\"s3\", region_name=\"us-east-1\")\nmanager = TransferManager(s3)\n\ntry:\n    future = manager.download(\n        \"my-bucket\",\n        \"releases/app.tar.gz\",\n        \"downloads/app.tar.gz\",\n    )\n    future.result()\nfinally:\n    manager.shutdown()\n```\n\nOther direct operations exposed by `TransferManager` include `copy(...)` and `delete(...)`.\n\n### Filename Wrapper: `S3Transfer`\n\nIf you want a thinner filename-based wrapper without using `boto3`:\n\n```python\nfrom botocore.session import Session\nfrom s3transfer import S3Transfer\n\nsession = Session()\ns3 = session.create_client(\"s3\", region_name=\"us-east-1\")\ntransfer = S3Transfer(s3)\n\ntransfer.upload_file(\n    \"dist/app.tar.gz\",\n    \"my-bucket\",\n    \"releases/app.tar.gz\",\n    extra_args={\"ContentType\": \"application/gzip\"},\n)\n```\n\n## TransferConfig Notes\n\nCore `s3transfer.manager.TransferConfig` knobs in `0.16.0`:\n\n- `multipart_threshold=8388608`\n- `multipart_chunksize=8388608`\n- `max_request_concurrency=10`\n- `max_submission_concurrency=5`\n- `max_io_queue_size=1000`\n- `io_chunksize=262144`\n- `num_download_attempts=5`\n- `max_bandwidth=None`\n\nImportant naming difference:\n\n- `boto3.s3.transfer.TransferConfig` uses `max_concurrency`\n- `s3transfer.manager.TransferConfig` uses `max_request_concurrency`\n\n`boto3` documents this aliasing and recommends the injected client methods (`upload_file`, `download_file`, `upload_fileobj`, `download_fileobj`) as the stable public transfer surface.\n\n## Optional CRT Support\n\nInstalling `s3transfer[crt]` enables the AWS Common Runtime transfer path through `botocore[crt]`.\n\nVersion-sensitive note for `0.16.0`:\n\n- `CRTTransferManager` now supports `multipart_threshold`, `multipart_chunksize`, and `max_request_concurrency`\n\nIf you are upgrading from older `0.14.x` or `0.15.x` releases and rely on CRT-backed transfers, re-check your config behavior against this change.\n\n## Common Pitfalls\n\n### Do Not Assume The Direct Package API Is Stable\n\nThe upstream README says `s3transfer` is not currently GA and advises locking to a minor version if you use it directly in production.\n\n### Prefer Filenames Over File-Like Objects When Possible\n\n`TransferManager.upload()` and `download()` accept filenames or seekable file-like objects, but the upstream source notes that file-like objects can increase memory usage.\n\n### Always Wait On The Future\n\n`TransferManager` methods return a transfer future. Call `future.result()` or you may miss transfer failures and exit before the transfer completes.\n\n### Always Shut Down The Manager\n\n`TransferManager` owns executors for request submission, transfer work, and download I/O. Call `shutdown()` in a `finally` block.\n\n### Do Not Copy `boto3` Config Names Into Direct `s3transfer` Code\n\nExamples using `boto3.s3.transfer.TransferConfig(max_concurrency=...)` do not map directly to `s3transfer.manager.TransferConfig`, which expects `max_request_concurrency`.\n\n### S3 Object Lambda Buckets Are Rejected\n\n`TransferManager` explicitly blocks S3 Object Lambda resource ARNs and tells callers to use direct client calls instead.\n\n### Credentials And Region Errors Come From The S3 Client\n\n`NoCredentialsError`, bad region resolution, or endpoint mismatches are client-construction problems, not transfer-manager problems.\n\n## Version-Sensitive Notes\n\n- `0.16.0`: CRT transfer config gained support for `multipart_threshold`, `multipart_chunksize`, and `max_request_concurrency`\n- `0.15.0`: multipart copy operations added stored-object ETag validation\n- `0.14.0`: multipart download range validation was tightened\n- `0.12.0`: Python 3.8 support ended, so `0.16.0` requires Python 3.9+\n\n## Official Sources\n\n- GitHub repository: https://github.com/boto/s3transfer\n- PyPI package page: https://pypi.org/project/s3transfer/\n- PyPI version metadata: https://pypi.org/pypi/s3transfer/0.16.0/json\n- README: https://raw.githubusercontent.com/boto/s3transfer/develop/README.rst\n- Changelog: https://github.com/boto/s3transfer/blob/develop/CHANGELOG.rst\n- `TransferManager` source for `0.16.0`: https://raw.githubusercontent.com/boto/s3transfer/0.16.0/s3transfer/manager.py\n- Stable wrapper reference: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3.html\n- Boto3 transfer customization reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/customizations/s3.html\n"
  },
  {
    "path": "content/aws/docs/sagemaker/javascript/DOC.md",
    "content": "---\nname: sagemaker\ndescription: \"AWS SDK for JavaScript v3 client for managing Amazon SageMaker jobs, models, endpoints, and notebook resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,sagemaker,machine-learning,training,endpoints\"\n---\n\n# Amazon SageMaker SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-sagemaker` to manage Amazon SageMaker control-plane resources from JavaScript or TypeScript code: training jobs, models, endpoint configs, endpoints, notebook instances, and related metadata.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-sagemaker`, not the legacy `aws-sdk` v2 package.\n- This doc covers package version `3.1006.0`.\n- Prefer `SageMakerClient` plus individual commands over the aggregated `SageMaker` client.\n- `@aws-sdk/client-sagemaker` is the control-plane client. To invoke a deployed model endpoint, use `@aws-sdk/client-sagemaker-runtime`.\n- Most create, update, stop, and delete operations are asynchronous. A successful response usually means SageMaker accepted the request, not that the resource is already ready.\n- SageMaker job names, model names, endpoint config names, and endpoint names are separate identifiers. Keep them explicit and stable in your deployment flow.\n- Many request fields depend on IAM roles, S3 URIs, container images, and regions lining up correctly.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-sagemaker\n```\n\nCommon companion packages:\n\n```bash\nnpm install @aws-sdk/client-sagemaker-runtime @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { SageMakerClient } from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { SageMakerClient } from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\nIf your environment already uses the standard AWS credential chain, keep the client config minimal and set only the region in code.\n\n## Core Usage Pattern\n\nThe normal v3 flow is `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeTrainingJobCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nconst response = await sagemaker.send(\n  new DescribeTrainingJobCommand({\n    TrainingJobName: \"xgboost-demo-20260311\",\n  }),\n);\n\nconsole.log({\n  status: response.TrainingJobStatus,\n  secondaryStatus: response.SecondaryStatus,\n  modelArtifacts: response.ModelArtifacts?.S3ModelArtifacts,\n});\n```\n\nFor most SageMaker automation, the workflow is create a resource, then poll the matching `Describe*` API until the status reaches the state you need.\n\n## Common Operations\n\n### Start a training job\n\n```javascript\nimport {\n  CreateTrainingJobCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nawait sagemaker.send(\n  new CreateTrainingJobCommand({\n    TrainingJobName: \"xgboost-demo-20260311\",\n    RoleArn: \"arn:aws:iam::123456789012:role/service-role/AmazonSageMaker-ExecutionRole\",\n    AlgorithmSpecification: {\n      TrainingImage: \"123456789012.dkr.ecr.us-east-1.amazonaws.com/my-training-image:latest\",\n      TrainingInputMode: \"File\",\n    },\n    InputDataConfig: [\n      {\n        ChannelName: \"train\",\n        DataSource: {\n          S3DataSource: {\n            S3DataType: \"S3Prefix\",\n            S3Uri: \"s3://my-bucket/sagemaker/train/\",\n            S3DataDistributionType: \"FullyReplicated\",\n          },\n        },\n      },\n    ],\n    OutputDataConfig: {\n      S3OutputPath: \"s3://my-bucket/sagemaker/output/\",\n    },\n    ResourceConfig: {\n      InstanceCount: 1,\n      InstanceType: \"ml.m5.large\",\n      VolumeSizeInGB: 30,\n    },\n    StoppingCondition: {\n      MaxRuntimeInSeconds: 3600,\n    },\n    HyperParameters: {\n      epochs: \"3\",\n      learning_rate: \"0.2\",\n    },\n  }),\n);\n```\n\n`CreateTrainingJob` only queues the work. Use `DescribeTrainingJobCommand` to check `TrainingJobStatus`, inspect `FailureReason`, and read `ModelArtifacts` after the job completes.\n\n### List recent training jobs\n\n```javascript\nimport {\n  ListTrainingJobsCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nconst response = await sagemaker.send(\n  new ListTrainingJobsCommand({\n    StatusEquals: \"Completed\",\n    SortBy: \"CreationTime\",\n    SortOrder: \"Descending\",\n    MaxResults: 20,\n  }),\n);\n\nfor (const job of response.TrainingJobSummaries ?? []) {\n  console.log(job.TrainingJobName, job.TrainingJobStatus);\n}\n```\n\nList APIs return summaries, not full details. Call the related `Describe*` command when you need complete configuration, artifact, or failure metadata.\n\n### Register a model and create an endpoint\n\nCreating an online inference endpoint is typically a three-step flow: create the model, create the endpoint config, then create the endpoint.\n\n```javascript\nimport {\n  CreateEndpointCommand,\n  CreateEndpointConfigCommand,\n  CreateModelCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nconst modelName = \"xgboost-demo-model\";\nconst endpointConfigName = \"xgboost-demo-endpoint-config\";\nconst endpointName = \"xgboost-demo-endpoint\";\n\nawait sagemaker.send(\n  new CreateModelCommand({\n    ModelName: modelName,\n    ExecutionRoleArn: \"arn:aws:iam::123456789012:role/service-role/AmazonSageMaker-ExecutionRole\",\n    PrimaryContainer: {\n      Image: \"123456789012.dkr.ecr.us-east-1.amazonaws.com/my-inference-image:latest\",\n      ModelDataUrl: \"s3://my-bucket/sagemaker/output/model.tar.gz\",\n    },\n  }),\n);\n\nawait sagemaker.send(\n  new CreateEndpointConfigCommand({\n    EndpointConfigName: endpointConfigName,\n    ProductionVariants: [\n      {\n        VariantName: \"AllTraffic\",\n        ModelName: modelName,\n        InitialInstanceCount: 1,\n        InstanceType: \"ml.m5.large\",\n        InitialVariantWeight: 1,\n      },\n    ],\n  }),\n);\n\nawait sagemaker.send(\n  new CreateEndpointCommand({\n    EndpointName: endpointName,\n    EndpointConfigName: endpointConfigName,\n  }),\n);\n```\n\nThe endpoint is not ready immediately after `CreateEndpoint`. Poll `DescribeEndpointCommand` until `EndpointStatus` reaches `InService` before sending live traffic.\n\n### Check endpoint rollout status\n\n```javascript\nimport {\n  DescribeEndpointCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nconst response = await sagemaker.send(\n  new DescribeEndpointCommand({\n    EndpointName: \"xgboost-demo-endpoint\",\n  }),\n);\n\nconsole.log({\n  status: response.EndpointStatus,\n  failureReason: response.FailureReason,\n});\n```\n\nTreat endpoint creation and update like long-running infrastructure work. A 200-level response only confirms the rollout started.\n\n### List notebook instances\n\n```javascript\nimport {\n  ListNotebookInstancesCommand,\n  SageMakerClient,\n} from \"@aws-sdk/client-sagemaker\";\n\nconst sagemaker = new SageMakerClient({ region: \"us-east-1\" });\n\nconst response = await sagemaker.send(\n  new ListNotebookInstancesCommand({\n    StatusEquals: \"InService\",\n    MaxResults: 20,\n  }),\n);\n\nfor (const instance of response.NotebookInstances ?? []) {\n  console.log(instance.NotebookInstanceName, instance.NotebookInstanceStatus);\n}\n```\n\nThis is useful for admin tooling and fleet audits. Notebook instances are managed resources; they are separate from Studio domains, user profiles, and runtime inference endpoints.\n\n## Auth and Configuration Notes\n\n- SageMaker control-plane calls need normal AWS SigV4 credentials plus the correct `region`.\n- Training jobs, processing jobs, and model creation often also depend on an execution role that SageMaker can assume separately from the caller identity making the API call.\n- S3 inputs and outputs must be readable and writable by the execution role you pass in requests such as `CreateTrainingJob` and `CreateModel`.\n- Container image URIs must point to images your account and region can actually pull, commonly from Amazon ECR.\n\n## SageMaker-Specific Gotchas\n\n- Use `@aws-sdk/client-sagemaker-runtime` for `InvokeEndpoint` and other data-plane inference calls. They are not exposed by `@aws-sdk/client-sagemaker`.\n- Many create and stop APIs are asynchronous. Poll the related `Describe*` API and inspect status fields and failure reasons.\n- `HyperParameters` values are strings, even when they represent numbers or booleans for your training container.\n- Endpoint deployment is a multi-resource workflow: model, endpoint config, and endpoint are distinct resources with distinct names.\n- SageMaker often fails because IAM, ECR, S3, KMS, VPC, or region settings do not line up. Validate those dependencies before debugging SDK wiring.\n- List operations usually return summaries and pagination tokens rather than everything in one call.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-sagemaker-runtime`: invoke deployed endpoints and other inference data-plane operations.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, and assume-role credential helpers.\n- `@aws-sdk/client-sts`: caller identity checks and explicit role-assumption workflows around SageMaker automation.\n\n## Version Notes\n\n- This content is written for `@aws-sdk/client-sagemaker` version `3.1006.0`.\n- Examples use the modular AWS SDK for JavaScript v3 import pattern and `client.send(new Command(...))` calls.\n- If you are migrating from v2 `aws-sdk`, do not translate examples into `new AWS.SageMaker()` service-method style calls.\n"
  },
  {
    "path": "content/aws/docs/secrets-manager/javascript/DOC.md",
    "content": "---\nname: secrets-manager\ndescription: \"AWS SDK for JavaScript v3 client for AWS Secrets Manager in Node.js and browser applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,secrets-manager,secrets,security,javascript\"\n---\n\n# AWS Secrets Manager SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-secrets-manager` to read, create, and manage AWS Secrets Manager secrets from modern JavaScript and TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-secrets-manager`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1006.0`.\n- AWS SDK for JavaScript v2 reached end of support on September 8, 2025.\n- Current v3 releases at and above `3.968.0` require Node.js 20+, so `3.1006.0` should be treated as Node 20+.\n- Prefer server-side secret access. Do not expose broad Secrets Manager reads to untrusted browser clients.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-secrets-manager\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { SecretsManagerClient } from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { SecretsManagerClient } from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n### Browser usage warning\n\nThe package can run in browser builds, but browser code should not directly retrieve application secrets for end users. If you must run it outside Node.js, use explicit federated credentials and a tightly scoped IAM policy, and prefer a backend API over direct secret reads.\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you have already configured AWS access through environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  GetSecretValueCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nconst response = await secrets.send(\n  new GetSecretValueCommand({\n    SecretId: \"prod/my-app\",\n  }),\n);\n\nconst secretValue =\n  response.SecretString ?? new TextDecoder().decode(response.SecretBinary);\n\nconsole.log(secretValue);\n```\n\nPrefer `SecretsManagerClient` plus explicit commands for most application code.\n\n## Common Operations\n\n### Read a JSON secret\n\nMany teams store structured JSON inside `SecretString`.\n\n```javascript\nimport {\n  GetSecretValueCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nconst { SecretString } = await secrets.send(\n  new GetSecretValueCommand({ SecretId: \"prod/my-app\" }),\n);\n\nconst config = JSON.parse(SecretString);\nconsole.log(config.username);\n```\n\n### Read a specific version stage\n\n`AWSCURRENT` is the default. `AWSPREVIOUS` is useful for rollback checks.\n\n```javascript\nimport {\n  GetSecretValueCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nconst previous = await secrets.send(\n  new GetSecretValueCommand({\n    SecretId: \"prod/my-app\",\n    VersionStage: \"AWSPREVIOUS\",\n  }),\n);\n\nconsole.log(previous.SecretString);\n```\n\n### Create a new secret\n\n```javascript\nimport {\n  CreateSecretCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nawait secrets.send(\n  new CreateSecretCommand({\n    Name: \"prod/my-app\",\n    Description: \"Application credentials for my-app\",\n    SecretString: JSON.stringify({\n      username: \"app-user\",\n      password: \"replace-me\",\n    }),\n  }),\n);\n```\n\n### Put a new secret value version\n\nUse `PutSecretValue` when you want a fresh secret version instead of editing only metadata.\n\n```javascript\nimport {\n  PutSecretValueCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nawait secrets.send(\n  new PutSecretValueCommand({\n    SecretId: \"prod/my-app\",\n    SecretString: JSON.stringify({\n      username: \"app-user\",\n      password: process.env.NEXT_PASSWORD,\n    }),\n  }),\n);\n```\n\n### Inspect rotation and versions\n\n```javascript\nimport {\n  DescribeSecretCommand,\n  SecretsManagerClient,\n} from \"@aws-sdk/client-secrets-manager\";\n\nconst secrets = new SecretsManagerClient({ region: \"us-east-1\" });\n\nconst details = await secrets.send(\n  new DescribeSecretCommand({ SecretId: \"prod/my-app\" }),\n);\n\nconsole.log(details.RotationEnabled);\nconsole.log(details.VersionIdsToStages);\n```\n\n## Secrets Manager-Specific Gotchas\n\n- `SecretId` can be a friendly name or an ARN. Use the full ARN for cross-account access or when names may be ambiguous.\n- `GetSecretValue` returns either `SecretString` or `SecretBinary`. Handle both paths explicitly.\n- Parse `SecretString` defensively. Many secrets contain JSON, but the service does not enforce a schema.\n- `PutSecretValue` creates a new secret version. Use it for rotation or value updates; reserve `UpdateSecret` for metadata or configuration changes.\n- Version stages matter: `AWSCURRENT` is the default active version, `AWSPREVIOUS` is useful for rollback, and `AWSPENDING` commonly appears during rotation workflows.\n- Do not log raw secret contents, copy them into frontend bundles, or keep them in long-lived error objects.\n- If a secret is read frequently, cache the parsed value in your application layer and refresh it intentionally when rotation happens.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, STS assume-role flows, and other credential helpers.\n\n"
  },
  {
    "path": "content/aws/docs/service-catalog/javascript/DOC.md",
    "content": "---\nname: service-catalog\ndescription: \"AWS Service Catalog SDK for JavaScript (v3) for discovering products, reading launch parameters, provisioning products, and tracking request records\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,service-catalog,portfolios,provisioning,cloudformation\"\n---\n\n# AWS Service Catalog SDK for JavaScript\n\nUse `@aws-sdk/client-service-catalog` to discover Service Catalog portfolios and products, inspect the parameters needed to launch a product, provision it, poll the resulting record, list active provisioned products, and terminate them later.\n\nThis package manages the Service Catalog control plane. Provisioning a product usually creates or updates underlying infrastructure such as CloudFormation stacks, but the Service Catalog API itself is asynchronous and record-based.\n\n## Installation\n\n```bash\nnpm install @aws-sdk/client-service-catalog\n```\n\nThese examples assume Node.js 18+ and the standard AWS SDK for JavaScript v3 credential provider chain.\n\n## Credentials and client initialization\n\nSet credentials with environment variables or an AWS profile:\n\n```bash\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=your-profile\n```\n\nCreate the client with an explicit region:\n\n```typescript\nimport { ServiceCatalogClient } from \"@aws-sdk/client-service-catalog\";\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you need to pin credentials in code, pass them directly:\n\n```typescript\nimport { ServiceCatalogClient } from \"@aws-sdk/client-service-catalog\";\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\nYour AWS identity must also have the Service Catalog permissions needed for the operations you call and access to the target portfolio or product.\n\n## List portfolios\n\nUse `ListPortfolios` when you need portfolio IDs for admin workflows or to inspect what is available in the catalog.\n\n```typescript\nimport {\n  ListPortfoliosCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet pageToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new ListPortfoliosCommand({\n      PageToken: pageToken,\n      PageSize: 20,\n    }),\n  );\n\n  for (const portfolio of response.PortfolioDetails ?? []) {\n    console.log({\n      id: portfolio.Id,\n      name: portfolio.DisplayName,\n      provider: portfolio.ProviderName,\n      description: portfolio.Description,\n    });\n  }\n\n  pageToken = response.NextPageToken;\n} while (pageToken);\n```\n\nService Catalog uses `PageToken` on requests and `NextPageToken` on responses for pagination.\n\n## Search products available to the caller\n\nUse `SearchProducts` for end-user style discovery. It returns products the current caller can access.\n\n```typescript\nimport {\n  SearchProductsCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet pageToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new SearchProductsCommand({\n      PageToken: pageToken,\n      PageSize: 20,\n    }),\n  );\n\n  for (const product of response.ProductViewSummaries ?? []) {\n    console.log({\n      id: product.ProductId,\n      viewId: product.Id,\n      name: product.Name,\n      owner: product.Owner,\n      hasDefaultPath: product.HasDefaultPath,\n      type: product.Type,\n    });\n  }\n\n  pageToken = response.NextPageToken;\n} while (pageToken);\n```\n\nIf you are building admin tooling, `SearchProductsAsAdmin` is the matching admin-side operation and can scope the search to one portfolio with `PortfolioId`.\n\n## Resolve a product version and launch path\n\nTo provision a product, you typically need a `ProductId`, a `ProvisioningArtifactId` for the version to launch, and sometimes a `PathId`.\n\n```bash\nexport AWS_PRODUCT_ID=prod-EXAMPLE123\n```\n\n### List provisioning artifacts for a product\n\n```typescript\nimport {\n  ListProvisioningArtifactsCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst productId = process.env.AWS_PRODUCT_ID;\n\nif (!productId) {\n  throw new Error(\"Set AWS_PRODUCT_ID before running this example.\");\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst artifacts = await client.send(\n  new ListProvisioningArtifactsCommand({\n    ProductId: productId,\n  }),\n);\n\nfor (const artifact of artifacts.ProvisioningArtifactDetails ?? []) {\n  console.log({\n    id: artifact.Id,\n    name: artifact.Name,\n    active: artifact.Active,\n    guidance: artifact.Guidance,\n  });\n}\n```\n\n### List launch paths for a product\n\n```typescript\nimport {\n  ListLaunchPathsCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst productId = process.env.AWS_PRODUCT_ID;\n\nif (!productId) {\n  throw new Error(\"Set AWS_PRODUCT_ID before running this example.\");\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet pageToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new ListLaunchPathsCommand({\n      ProductId: productId,\n      PageToken: pageToken,\n      PageSize: 20,\n    }),\n  );\n\n  for (const path of response.LaunchPathSummaries ?? []) {\n    console.log({\n      id: path.Id,\n      name: path.Name,\n    });\n  }\n\n  pageToken = response.NextPageToken;\n} while (pageToken);\n```\n\nA launch path describes how the caller can access the product and which constraints apply. When a product has more than one launch path, resolve the correct `PathId` before provisioning.\n\n## Read the provisioning parameters before launch\n\nUse `DescribeProvisioningParameters` to fetch the exact parameter keys your app must send for a specific product version.\n\n```bash\nexport AWS_PRODUCT_ID=prod-EXAMPLE123\nexport AWS_PROVISIONING_ARTIFACT_ID=pa-EXAMPLE456\nexport AWS_PATH_ID=lpv2-EXAMPLE789\n```\n\n```typescript\nimport {\n  DescribeProvisioningParametersCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst productId = process.env.AWS_PRODUCT_ID;\nconst provisioningArtifactId = process.env.AWS_PROVISIONING_ARTIFACT_ID;\nconst pathId = process.env.AWS_PATH_ID;\n\nif (!productId || !provisioningArtifactId) {\n  throw new Error(\n    \"Set AWS_PRODUCT_ID and AWS_PROVISIONING_ARTIFACT_ID before running this example.\",\n  );\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DescribeProvisioningParametersCommand({\n    ProductId: productId,\n    ProvisioningArtifactId: provisioningArtifactId,\n    PathId: pathId,\n  }),\n);\n\nfor (const parameter of response.ProvisioningArtifactParameters ?? []) {\n  console.log({\n    key: parameter.ParameterKey,\n    type: parameter.ParameterType,\n    defaultValue: parameter.DefaultValue,\n    description: parameter.Description,\n    isNoEcho: parameter.IsNoEcho,\n  });\n}\n\nconsole.log(\"usageInstructions\", response.UsageInstructions ?? []);\nconsole.log(\"constraintSummaries\", response.ConstraintSummaries ?? []);\n```\n\nUse the returned `ParameterKey` values exactly as provided when constructing `ProvisioningParameters`.\n\n## Provision a product\n\nProvisioning is asynchronous. `ProvisionProduct` creates a record immediately, and you then poll that record with `DescribeRecord`.\n\n```bash\nexport AWS_PRODUCT_ID=prod-EXAMPLE123\nexport AWS_PROVISIONING_ARTIFACT_ID=pa-EXAMPLE456\nexport AWS_PATH_ID=lpv2-EXAMPLE789\nexport AWS_PROVISIONED_PRODUCT_NAME=my-service-catalog-product\n```\n\n```typescript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  ProvisionProductCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst productId = process.env.AWS_PRODUCT_ID;\nconst provisioningArtifactId = process.env.AWS_PROVISIONING_ARTIFACT_ID;\nconst pathId = process.env.AWS_PATH_ID;\nconst provisionedProductName = process.env.AWS_PROVISIONED_PRODUCT_NAME;\n\nif (!productId || !provisioningArtifactId || !provisionedProductName) {\n  throw new Error(\n    \"Set AWS_PRODUCT_ID, AWS_PROVISIONING_ARTIFACT_ID, and AWS_PROVISIONED_PRODUCT_NAME.\",\n  );\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ProvisionProductCommand({\n    ProductId: productId,\n    ProvisioningArtifactId: provisioningArtifactId,\n    PathId: pathId,\n    ProvisionedProductName: provisionedProductName,\n    ProvisionToken: randomUUID(),\n    ProvisioningParameters: [\n      {\n        Key: \"InstanceType\",\n        Value: \"t3.micro\",\n      },\n      {\n        Key: \"VpcId\",\n        Value: \"vpc-0123456789abcdef0\",\n      },\n    ],\n  }),\n);\n\nconsole.log({\n  recordId: response.RecordDetail?.RecordId,\n  provisionedProductId: response.RecordDetail?.ProvisionedProductId,\n  status: response.RecordDetail?.Status,\n});\n```\n\n`ProvisionToken` is required and should be unique per request. Generate it once for the request and reuse it only when you intentionally retry the same provisioning operation.\n\n## Poll a provisioning record\n\nUse `DescribeRecord` after `ProvisionProduct`, `UpdateProvisionedProduct`, or `TerminateProvisionedProduct`.\n\n```bash\nexport AWS_RECORD_ID=rec-EXAMPLE123\n```\n\n```typescript\nimport {\n  DescribeRecordCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst recordId = process.env.AWS_RECORD_ID;\n\nif (!recordId) {\n  throw new Error(\"Set AWS_RECORD_ID before running this example.\");\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nwhile (true) {\n  const response = await client.send(\n    new DescribeRecordCommand({\n      Id: recordId,\n      PageSize: 20,\n    }),\n  );\n\n  const detail = response.RecordDetail;\n\n  console.log({\n    recordId: detail?.RecordId,\n    status: detail?.Status,\n    updatedTime: detail?.UpdatedTime,\n    errors: detail?.RecordErrors,\n  });\n\n  if (!detail || detail.Status === \"SUCCEEDED\" || detail.Status === \"FAILED\") {\n    break;\n  }\n\n  await new Promise((resolve) => setTimeout(resolve, 5000));\n}\n```\n\nRecord status is the source of truth for the async request. A successful `ProvisionProduct` API call only means Service Catalog accepted the request.\n\n## List active provisioned products\n\nUse `ScanProvisionedProducts` to list provisioned products that are still available. Terminated products are not returned by this operation.\n\n```typescript\nimport {\n  ScanProvisionedProductsCommand,\n  ServiceCatalogClient,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet pageToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new ScanProvisionedProductsCommand({\n      PageToken: pageToken,\n      PageSize: 20,\n    }),\n  );\n\n  for (const product of response.ProvisionedProducts ?? []) {\n    console.log({\n      id: product.Id,\n      name: product.Name,\n      status: product.Status,\n      productId: product.ProductId,\n      artifactId: product.ProvisioningArtifactId,\n      physicalId: product.PhysicalId,\n    });\n  }\n\n  pageToken = response.NextPageToken;\n} while (pageToken);\n```\n\nIf you need to inspect one provisioned product in more detail, call `DescribeProvisionedProduct` with its `Id` or `Name`.\n\n## Terminate a provisioned product\n\nTermination is also asynchronous and returns a record you should poll with `DescribeRecord`.\n\n```bash\nexport AWS_PROVISIONED_PRODUCT_ID=pp-EXAMPLE123\n```\n\n```typescript\nimport { randomUUID } from \"node:crypto\";\nimport {\n  ServiceCatalogClient,\n  TerminateProvisionedProductCommand,\n} from \"@aws-sdk/client-service-catalog\";\n\nconst provisionedProductId = process.env.AWS_PROVISIONED_PRODUCT_ID;\n\nif (!provisionedProductId) {\n  throw new Error(\"Set AWS_PROVISIONED_PRODUCT_ID before running this example.\");\n}\n\nconst client = new ServiceCatalogClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new TerminateProvisionedProductCommand({\n    ProvisionedProductId: provisionedProductId,\n    TerminateToken: randomUUID(),\n    IgnoreErrors: false,\n  }),\n);\n\nconsole.log({\n  recordId: response.RecordDetail?.RecordId,\n  status: response.RecordDetail?.Status,\n});\n```\n\nSet `RetainPhysicalResources: true` only when you intentionally want the underlying resources to remain after Service Catalog terminates its tracking of the provisioned product.\n\n## Common pitfalls\n\n- Pagination uses `PageToken` and `NextPageToken`, not `NextToken`.\n- `ProvisionProduct` is asynchronous; always read `RecordDetail.RecordId` and poll `DescribeRecord` until you reach a terminal status.\n- `ProvisionToken`, `UpdateToken`, and `TerminateToken` are required idempotency tokens for their respective write operations.\n- A product can expose multiple launch paths. Call `ListLaunchPaths` and pass the correct `PathId` when needed.\n- Build `ProvisioningParameters` from `DescribeProvisioningParameters` output instead of hard-coding parameter keys.\n- `ScanProvisionedProducts` returns available provisioned products only. Use record history or other record APIs if you need terminated-operation history.\n- If `DescribeProvisioningParameters` surfaces a TagOption key with an empty value list, do not send that conflicted key in `Tags` on `ProvisionProduct`.\n\n## Minimal end-to-end flow\n\nIf you are wiring Service Catalog into an app or agent workflow, the normal sequence is:\n\n1. Call `SearchProducts` to find a product the caller can access.\n2. Call `ListProvisioningArtifacts` to choose the version to launch.\n3. Call `ListLaunchPaths` if the product might have multiple launch paths.\n4. Call `DescribeProvisioningParameters` to fetch the exact parameter keys and constraints.\n5. Call `ProvisionProduct` with a unique `ProvisionToken`.\n6. Poll `DescribeRecord` until the provisioning record reaches `SUCCEEDED` or `FAILED`.\n7. Call `ScanProvisionedProducts` or `DescribeProvisionedProduct` to inspect active provisioned products later.\n8. Call `TerminateProvisionedProduct` with a unique `TerminateToken` when you want to remove one, then poll its record.\n\n## Version notes\n\n- This guide targets `@aws-sdk/client-service-catalog` version `3.1007.0`.\n- These examples use the AWS SDK for JavaScript v3 command-based client API and the current Service Catalog request member names such as `PageToken`, `NextPageToken`, `ProvisionToken`, and `TerminateToken`.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 Service Catalog client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/service-catalog/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- AWS Service Catalog `ListPortfolios` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_ListPortfolios.html`\n- AWS Service Catalog `SearchProducts` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_SearchProducts.html`\n- AWS Service Catalog `ListLaunchPaths` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_ListLaunchPaths.html`\n- AWS Service Catalog `DescribeProvisioningParameters` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_DescribeProvisioningParameters.html`\n- AWS Service Catalog `ProvisionProduct` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_ProvisionProduct.html`\n- AWS Service Catalog `DescribeRecord` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_DescribeRecord.html`\n- AWS Service Catalog `ScanProvisionedProducts` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_ScanProvisionedProducts.html`\n- AWS Service Catalog `TerminateProvisionedProduct` API: `https://docs.aws.amazon.com/servicecatalog/latest/dg/API_TerminateProvisionedProduct.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-service-catalog`\n"
  },
  {
    "path": "content/aws/docs/service-quotas/javascript/DOC.md",
    "content": "---\nname: service-quotas\ndescription: \"AWS Service Quotas SDK for JavaScript (v3) for inspecting quota values, comparing defaults, and requesting increases\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,service-quotas,limits,quota-management,operations\"\n---\n\n# AWS Service Quotas SDK for JavaScript\n\nUse `@aws-sdk/client-service-quotas` to discover service and quota codes, read the quota currently applied to your account, compare it with the AWS default, submit increase requests for adjustable quotas, and track request history.\n\nThe client exposes the AWS Service Quotas API directly, so you work with AWS identifiers such as `serviceCode` and `quotaCode` instead of display names.\n\n## Installation\n\n```bash\nnpm install @aws-sdk/client-service-quotas\n```\n\nThese examples assume Node.js 18+ and the standard AWS SDK for JavaScript v3 credential provider chain.\n\n## Credentials and client initialization\n\nSet credentials with environment variables or an AWS profile:\n\n```bash\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=your-profile\n```\n\nCreate the client with an explicit region so quota reads and requests are sent to the region you intend to manage.\n\n```typescript\nimport { ServiceQuotasClient } from \"@aws-sdk/client-service-quotas\";\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you need to pin credentials in code, pass them explicitly:\n\n```typescript\nimport { ServiceQuotasClient } from \"@aws-sdk/client-service-quotas\";\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n## Discover service codes\n\nStart with `ListServices` when you do not already know the `serviceCode` you need.\n\n```typescript\nimport {\n  ListServicesCommand,\n  ServiceQuotasClient,\n} from \"@aws-sdk/client-service-quotas\";\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new ListServicesCommand({\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const service of response.Services ?? []) {\n    console.log(`${service.ServiceCode}\\t${service.ServiceName}`);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\nPersist the returned `ServiceCode` values in your app configuration. Do not rely on display names.\n\n## List quotas for one AWS service\n\nUse `ListServiceQuotas` to enumerate the applied quota values for a service in the current account and region.\n\n```bash\nexport AWS_SERVICE_CODE=ec2\n```\n\n```typescript\nimport {\n  ListServiceQuotasCommand,\n  ServiceQuotasClient,\n} from \"@aws-sdk/client-service-quotas\";\n\nconst serviceCode = process.env.AWS_SERVICE_CODE;\n\nif (!serviceCode) {\n  throw new Error(\"Set AWS_SERVICE_CODE before running this example.\");\n}\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nlet nextToken: string | undefined;\n\ndo {\n  const response = await client.send(\n    new ListServiceQuotasCommand({\n      ServiceCode: serviceCode,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const quota of response.Quotas ?? []) {\n    console.log({\n      quotaCode: quota.QuotaCode,\n      quotaName: quota.QuotaName,\n      value: quota.Value,\n      unit: quota.Unit,\n      adjustable: quota.Adjustable,\n      globalQuota: quota.GlobalQuota,\n    });\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\nThe response tells you whether the quota is adjustable and whether AWS marks it as a global quota. Keep the returned `QuotaCode`; you need it for reads and increase requests.\n\n## Compare your applied quota with the AWS default\n\nUse `GetServiceQuota` for the value currently applied to your account and `GetAWSDefaultServiceQuota` for the AWS default.\n\n```bash\nexport AWS_SERVICE_CODE=ec2\nexport AWS_QUOTA_CODE=YOUR_QUOTA_CODE\n```\n\n```typescript\nimport {\n  GetAWSDefaultServiceQuotaCommand,\n  GetServiceQuotaCommand,\n  ServiceQuotasClient,\n} from \"@aws-sdk/client-service-quotas\";\n\nconst serviceCode = process.env.AWS_SERVICE_CODE;\nconst quotaCode = process.env.AWS_QUOTA_CODE;\n\nif (!serviceCode || !quotaCode) {\n  throw new Error(\"Set AWS_SERVICE_CODE and AWS_QUOTA_CODE.\");\n}\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst [appliedResponse, defaultResponse] = await Promise.all([\n  client.send(\n    new GetServiceQuotaCommand({\n      ServiceCode: serviceCode,\n      QuotaCode: quotaCode,\n    }),\n  ),\n  client.send(\n    new GetAWSDefaultServiceQuotaCommand({\n      ServiceCode: serviceCode,\n      QuotaCode: quotaCode,\n    }),\n  ),\n]);\n\nconsole.log({\n  applied: appliedResponse.Quota?.Value,\n  awsDefault: defaultResponse.Quota?.Value,\n  unit: appliedResponse.Quota?.Unit ?? defaultResponse.Quota?.Unit,\n  adjustable: appliedResponse.Quota?.Adjustable,\n  globalQuota: appliedResponse.Quota?.GlobalQuota,\n});\n```\n\nUse this comparison before opening an increase request so you can show operators the current limit and the baseline AWS default side by side.\n\n## Request a quota increase\n\nOnly call `RequestServiceQuotaIncrease` for quotas that report `Adjustable: true`.\n\n```bash\nexport AWS_SERVICE_CODE=ec2\nexport AWS_QUOTA_CODE=YOUR_QUOTA_CODE\nexport AWS_DESIRED_VALUE=200\n```\n\n```typescript\nimport {\n  GetServiceQuotaCommand,\n  RequestServiceQuotaIncreaseCommand,\n  ServiceQuotasClient,\n} from \"@aws-sdk/client-service-quotas\";\n\nconst serviceCode = process.env.AWS_SERVICE_CODE;\nconst quotaCode = process.env.AWS_QUOTA_CODE;\nconst desiredValue = Number(process.env.AWS_DESIRED_VALUE);\n\nif (!serviceCode || !quotaCode || Number.isNaN(desiredValue)) {\n  throw new Error(\n    \"Set AWS_SERVICE_CODE, AWS_QUOTA_CODE, and AWS_DESIRED_VALUE.\",\n  );\n}\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst current = await client.send(\n  new GetServiceQuotaCommand({\n    ServiceCode: serviceCode,\n    QuotaCode: quotaCode,\n  }),\n);\n\nif (!current.Quota?.Adjustable) {\n  throw new Error(\"This quota is not adjustable through Service Quotas.\");\n}\n\nconst response = await client.send(\n  new RequestServiceQuotaIncreaseCommand({\n    ServiceCode: serviceCode,\n    QuotaCode: quotaCode,\n    DesiredValue: desiredValue,\n  }),\n);\n\nconsole.log({\n  requestId: response.RequestedQuota?.Id,\n  status: response.RequestedQuota?.Status,\n  desiredValue: response.RequestedQuota?.DesiredValue,\n  created: response.RequestedQuota?.Created,\n});\n```\n\nStore the returned request ID if you want to fetch that request later with `GetRequestedServiceQuotaChange`.\n\n## Track request status and history\n\nUse `ListRequestedServiceQuotaChangeHistoryByQuota` to list requests for one quota, or `GetRequestedServiceQuotaChange` when you already have a request ID.\n\n```bash\nexport AWS_SERVICE_CODE=ec2\nexport AWS_QUOTA_CODE=YOUR_QUOTA_CODE\nexport AWS_REQUEST_ID=YOUR_REQUEST_ID\n```\n\n```typescript\nimport {\n  GetRequestedServiceQuotaChangeCommand,\n  ListRequestedServiceQuotaChangeHistoryByQuotaCommand,\n  ServiceQuotasClient,\n} from \"@aws-sdk/client-service-quotas\";\n\nconst serviceCode = process.env.AWS_SERVICE_CODE;\nconst quotaCode = process.env.AWS_QUOTA_CODE;\nconst requestId = process.env.AWS_REQUEST_ID;\n\nif (!serviceCode || !quotaCode) {\n  throw new Error(\"Set AWS_SERVICE_CODE and AWS_QUOTA_CODE.\");\n}\n\nconst client = new ServiceQuotasClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst history = await client.send(\n  new ListRequestedServiceQuotaChangeHistoryByQuotaCommand({\n    ServiceCode: serviceCode,\n    QuotaCode: quotaCode,\n  }),\n);\n\nconsole.table(\n  (history.RequestedQuotas ?? []).map((request) => ({\n    id: request.Id,\n    desiredValue: request.DesiredValue,\n    status: request.Status,\n    created: request.Created,\n    lastUpdated: request.LastUpdated,\n    caseId: request.CaseId,\n  })),\n);\n\nif (requestId) {\n  const detail = await client.send(\n    new GetRequestedServiceQuotaChangeCommand({\n      RequestId: requestId,\n    }),\n  );\n\n  console.dir(detail.RequestedQuota, { depth: null });\n}\n```\n\nUse the request history endpoint when you need to surface pending versus approved increases in internal tooling without requiring users to open the AWS console.\n\n## Common pitfalls\n\n- Use `serviceCode` and `quotaCode` from the API responses, not copied display names.\n- Use `ListServiceQuotas` or `GetServiceQuota` for your account's applied value, and `ListAWSDefaultServiceQuotas` or `GetAWSDefaultServiceQuota` for the AWS default.\n- Check `Adjustable` before calling `RequestServiceQuotaIncrease`; not every quota can be changed through this API.\n- Handle pagination with `NextToken` for list operations.\n- Read `GlobalQuota` from the response instead of assuming every quota is regional.\n\n## Minimal end-to-end flow\n\nIf you are wiring this into an app or automation, the normal sequence is:\n\n1. Call `ListServices` once and store the `ServiceCode` you need.\n2. Call `ListServiceQuotas` for that service and store the `QuotaCode` values your workflow cares about.\n3. Call `GetServiceQuota` and `GetAWSDefaultServiceQuota` when you need to show current versus default limits.\n4. Call `RequestServiceQuotaIncrease` only for quotas where `Adjustable` is `true`.\n5. Poll `GetRequestedServiceQuotaChange` or list with `ListRequestedServiceQuotaChangeHistoryByQuota` until the request reaches a terminal status.\n"
  },
  {
    "path": "content/aws/docs/ses/javascript/DOC.md",
    "content": "---\nname: ses\ndescription: \"AWS SDK for JavaScript v3 client for Amazon SES email sending, identity management, and template workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,ses,email,javascript,nodejs,templating,delivery\"\n---\n\n# `@aws-sdk/client-ses`\n\nUse this package for the classic Amazon SES API in AWS SDK for JavaScript v3. It covers email sending, identity verification, template management, and related account-level SES operations.\n\nThis package is for the older SES `2010-12-01` API surface. If you need newer SES v2 features such as configuration sets, suppression-list operations, or contact-list features, use `@aws-sdk/client-sesv2` instead.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ses\n```\n\nPrefer `SESClient` plus explicit command imports. The package also exposes an aggregated `SES` client, but command-based imports are the safer default for smaller bundles and clearer call sites.\n\n## Initialize the client\n\n```javascript\nimport { SESClient } from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({\n  region: \"us-east-1\",\n});\n```\n\nSES is regional. Verified identities, sandbox restrictions, quotas, and deliverability settings are evaluated per region, so the client region must match the region where your SES resources are configured.\n\n## Credentials and Region\n\n- Node.js: the default AWS credential provider chain usually works if credentials are already configured through environment variables, shared config, ECS, EC2, or IAM Identity Center.\n- Browser runtimes: this package can run in browser bundles, but direct browser-side email sending is usually the wrong design because it exposes privileged SES permissions.\n- Keep the region explicit somewhere: in code, `AWS_REGION`, or shared AWS config.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## SES-Specific Rules\n\n- In the SES sandbox, you can send only to verified identities unless your account has production access in that region.\n- Sender identities must be verified in the same region where you send mail.\n- Recipient limits, message-size limits, and sending quotas are service-side checks; a successful client call still depends on SES account state.\n- `SendEmailCommand` is for structured subject/body content. Use `SendRawEmailCommand` when you need MIME control, custom headers, or attachments.\n\n## Core Usage Pattern\n\nThe v3 SDK uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  SESClient,\n  SendEmailCommand,\n} from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({ region: \"us-east-1\" });\n\nawait ses.send(\n  new SendEmailCommand({\n    Source: \"noreply@example.com\",\n    Destination: {\n      ToAddresses: [\"ada@example.com\"],\n    },\n    Message: {\n      Subject: {\n        Data: \"Order received\",\n        Charset: \"UTF-8\",\n      },\n      Body: {\n        Text: {\n          Data: \"Your order was received.\",\n          Charset: \"UTF-8\",\n        },\n      },\n    },\n  }),\n);\n```\n\nUse a verified sender identity and keep the sender region aligned with the SES region in code.\n\n## Common Operations\n\n### Send an HTML email\n\n```javascript\nimport {\n  SESClient,\n  SendEmailCommand,\n} from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({ region: \"us-east-1\" });\n\nawait ses.send(\n  new SendEmailCommand({\n    Source: \"noreply@example.com\",\n    Destination: {\n      ToAddresses: [\"ada@example.com\"],\n      CcAddresses: [\"ops@example.com\"],\n    },\n    ReplyToAddresses: [\"support@example.com\"],\n    Message: {\n      Subject: {\n        Data: \"Welcome to Example Co\",\n        Charset: \"UTF-8\",\n      },\n      Body: {\n        Html: {\n          Data: \"<h1>Welcome</h1><p>Your account is ready.</p>\",\n          Charset: \"UTF-8\",\n        },\n        Text: {\n          Data: \"Welcome. Your account is ready.\",\n          Charset: \"UTF-8\",\n        },\n      },\n    },\n  }),\n);\n```\n\nProvide both HTML and text bodies when possible so clients that do not render HTML still receive a readable message.\n\n### Send a templated email\n\n```javascript\nimport {\n  SESClient,\n  SendTemplatedEmailCommand,\n} from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({ region: \"us-east-1\" });\n\nawait ses.send(\n  new SendTemplatedEmailCommand({\n    Source: \"noreply@example.com\",\n    Destination: {\n      ToAddresses: [\"ada@example.com\"],\n    },\n    Template: \"order-created\",\n    TemplateData: JSON.stringify({\n      firstName: \"Ada\",\n      orderId: \"12345\",\n    }),\n  }),\n);\n```\n\n`TemplateData` must be a JSON string, not a plain JavaScript object.\n\n### Create an email template\n\n```javascript\nimport {\n  CreateTemplateCommand,\n  SESClient,\n} from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({ region: \"us-east-1\" });\n\nawait ses.send(\n  new CreateTemplateCommand({\n    Template: {\n      TemplateName: \"order-created\",\n      SubjectPart: \"Order {{orderId}} received\",\n      TextPart: \"Hi {{firstName}}, your order {{orderId}} was received.\",\n      HtmlPart:\n        \"<h1>Thanks {{firstName}}</h1><p>Your order {{orderId}} was received.</p>\",\n    },\n  }),\n);\n```\n\nTemplate names are region-scoped SES resources, so keep naming stable across deploys.\n\n### List verified identities\n\n```javascript\nimport {\n  ListIdentitiesCommand,\n  SESClient,\n} from \"@aws-sdk/client-ses\";\n\nconst ses = new SESClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await ses.send(\n    new ListIdentitiesCommand({\n      IdentityType: \"EmailAddress\",\n      MaxItems: 100,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const identity of response.Identities ?? []) {\n    console.log(identity);\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\nUse this for admin flows and environment checks rather than for every send path.\n\n## SES Gotchas\n\n- `@aws-sdk/client-ses` and `@aws-sdk/client-sesv2` are different service packages. Choose intentionally based on the API surface you need.\n- SES sandbox restrictions are regional. Being out of the sandbox in one region does not imply the same state in another.\n- Verified sender identity checks are also regional. A domain verified in one region is not automatically verified everywhere.\n- `SendTemplatedEmailCommand` and related template APIs fail if template placeholders and `TemplateData` keys do not line up.\n- `SendRawEmailCommand` is the correct path for attachments and full MIME control; `SendEmailCommand` does not accept arbitrary attachments.\n- Keep email-sending permissions server-side. Direct browser calls with broad SES permissions are usually a bad default.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-sesv2`: newer SES v2 APIs such as suppression lists, configuration sets, and account-level deliverability features.\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, and assume-role flows.\n- `nodemailer`: higher-level application mail composition when you still want to send through SES.\n"
  },
  {
    "path": "content/aws/docs/sfn/javascript/DOC.md",
    "content": "---\nname: sfn\ndescription: \"AWS SDK for JavaScript v3 client for Step Functions state machines, executions, execution history, and workflow definitions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,step-functions,sfn,javascript,nodejs,workflows,state-machines\"\n---\n\n# AWS Step Functions SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-sfn` to start executions, inspect workflow state, read execution history, and create or update Step Functions state machines from JavaScript or TypeScript.\n\nThis is the Step Functions control-plane client. It manages state machines and executions in AWS; it does not run a workflow engine locally.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-sfn`, not the legacy `aws-sdk` v2 package.\n- Use `SFNClient` with specific command imports such as `StartExecutionCommand` and `DescribeExecutionCommand`.\n- Configure AWS credentials and `region` before creating the client.\n- `StartExecutionCommand` returns immediately after the execution is accepted. Poll `DescribeExecutionCommand` if you need the final result.\n- Step Functions request and response payloads such as `input`, `output`, `cause`, and state machine `definition` are JSON text fields. Serialize with `JSON.stringify(...)` and parse with `JSON.parse(...)` when needed.\n- `StartSyncExecutionCommand` is for Express Workflows. Standard workflows use `StartExecutionCommand` and a follow-up status check.\n- When creating a state machine, your caller needs permission to invoke Step Functions APIs, and Step Functions also needs a `roleArn` it can assume for the workflow itself.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-sfn\n```\n\nIf you want to select a named shared AWS profile in code, also install the credential provider helpers:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nStep Functions is regional. Configure AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n\nexport STEP_FUNCTIONS_STATE_MACHINE_ARN=\"arn:aws:states:us-east-1:123456789012:stateMachine:OrderWorkflow\"\nexport STEP_FUNCTIONS_EXPRESS_ARN=\"arn:aws:states:us-east-1:123456789012:stateMachine:OrderWorkflowExpress\"\nexport STEP_FUNCTIONS_ROLE_ARN=\"arn:aws:iam::123456789012:role/service-role/StepFunctionsExecutionRole\"\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { SFNClient } from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { SFNClient } from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { SFNClient } from \"@aws-sdk/client-sfn\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst sfn = new SFNClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"dev\",\n  }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if your AWS access already comes from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  SFNClient,\n  DescribeStateMachineCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nconst response = await sfn.send(\n  new DescribeStateMachineCommand({\n    stateMachineArn: process.env.STEP_FUNCTIONS_STATE_MACHINE_ARN,\n  }),\n);\n\nconsole.log(response.name, response.status, response.type);\n```\n\n## Common Workflows\n\n### Start an execution\n\nStep Functions expects `input` as a JSON string.\n\n```javascript\nimport {\n  SFNClient,\n  StartExecutionCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nconst { executionArn, startDate } = await sfn.send(\n  new StartExecutionCommand({\n    stateMachineArn: process.env.STEP_FUNCTIONS_STATE_MACHINE_ARN,\n    name: `order-${Date.now()}`,\n    input: JSON.stringify({\n      orderId: \"order-123\",\n      retryable: false,\n      items: [{ sku: \"sku-1\", quantity: 2 }],\n    }),\n  }),\n);\n\nconsole.log(executionArn, startDate);\n```\n\n### Poll an execution until it finishes\n\n`StartExecutionCommand` does not wait for the workflow to finish. Poll `DescribeExecutionCommand` until the execution reaches a terminal state.\n\n```javascript\nimport {\n  SFNClient,\n  DescribeExecutionCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nfunction sleep(ms) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function waitForExecution(executionArn) {\n  for (;;) {\n    const execution = await sfn.send(\n      new DescribeExecutionCommand({\n        executionArn,\n      }),\n    );\n\n    console.log(execution.status, execution.startDate, execution.stopDate);\n\n    if (execution.status === \"SUCCEEDED\") {\n      return execution.output ? JSON.parse(execution.output) : undefined;\n    }\n\n    if (\n      execution.status === \"FAILED\"\n      || execution.status === \"TIMED_OUT\"\n      || execution.status === \"ABORTED\"\n    ) {\n      throw new Error(\n        [execution.error, execution.cause]\n          .filter(Boolean)\n          .join(\": \") || `Execution finished with status ${execution.status}`,\n      );\n    }\n\n    await sleep(2000);\n  }\n}\n```\n\n### Read execution history\n\nUse `GetExecutionHistoryCommand` when you need event-by-event details for debugging or audit tooling.\n\n```javascript\nimport {\n  SFNClient,\n  GetExecutionHistoryCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nasync function printExecutionHistory(executionArn) {\n  let nextToken;\n\n  do {\n    const page = await sfn.send(\n      new GetExecutionHistoryCommand({\n        executionArn,\n        maxResults: 100,\n        nextToken,\n      }),\n    );\n\n    for (const event of page.events ?? []) {\n      console.log(event.id, event.type, event.timestamp);\n    }\n\n    nextToken = page.nextToken;\n  } while (nextToken);\n}\n```\n\n### Start an Express Workflow synchronously\n\nUse `StartSyncExecutionCommand` only with Express Workflows when you need the workflow result in the same API call.\n\n```javascript\nimport {\n  SFNClient,\n  StartSyncExecutionCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nconst result = await sfn.send(\n  new StartSyncExecutionCommand({\n    stateMachineArn: process.env.STEP_FUNCTIONS_EXPRESS_ARN,\n    input: JSON.stringify({\n      orderId: \"order-123\",\n      dryRun: true,\n    }),\n  }),\n);\n\nif (result.status !== \"SUCCEEDED\") {\n  throw new Error(\n    [result.error, result.cause]\n      .filter(Boolean)\n      .join(\": \") || `Sync execution finished with status ${result.status}`,\n  );\n}\n\nconsole.log(result.output ? JSON.parse(result.output) : undefined);\n```\n\n### Create a state machine from an Amazon States Language definition\n\nState machine definitions are JSON strings. Build the object in JavaScript, then serialize it.\n\n```javascript\nimport {\n  CreateStateMachineCommand,\n  SFNClient,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nconst definition = JSON.stringify({\n  Comment: \"Minimal order workflow\",\n  StartAt: \"ApproveOrder\",\n  States: {\n    ApproveOrder: {\n      Type: \"Pass\",\n      Result: { approved: true },\n      End: true,\n    },\n  },\n});\n\nconst created = await sfn.send(\n  new CreateStateMachineCommand({\n    name: \"OrderWorkflow\",\n    type: \"STANDARD\",\n    definition,\n    roleArn: process.env.STEP_FUNCTIONS_ROLE_ARN,\n  }),\n);\n\nconsole.log(created.stateMachineArn);\n```\n\n### Validate and update a state machine definition\n\n`ValidateStateMachineDefinitionCommand` is useful before a create or update, especially when you generate Amazon States Language dynamically.\n\n```javascript\nimport {\n  SFNClient,\n  UpdateStateMachineCommand,\n  ValidateStateMachineDefinitionCommand,\n} from \"@aws-sdk/client-sfn\";\n\nconst sfn = new SFNClient({ region: \"us-east-1\" });\n\nconst definition = JSON.stringify({\n  Comment: \"Updated order workflow\",\n  StartAt: \"PrepareResult\",\n  States: {\n    PrepareResult: {\n      Type: \"Pass\",\n      Result: { version: 2 },\n      End: true,\n    },\n  },\n});\n\nconst validation = await sfn.send(\n  new ValidateStateMachineDefinitionCommand({\n    definition,\n    type: \"STANDARD\",\n  }),\n);\n\nif (validation.result !== \"OK\") {\n  throw new Error(JSON.stringify(validation.diagnostics ?? []));\n}\n\nawait sfn.send(\n  new UpdateStateMachineCommand({\n    stateMachineArn: process.env.STEP_FUNCTIONS_STATE_MACHINE_ARN,\n    definition,\n  }),\n);\n```\n\n## Common Pitfalls\n\n- Passing a plain object to `input`, `output`, `cause`, or `definition`. These fields are JSON strings in the API.\n- Expecting `StartExecutionCommand` to return the workflow result. It returns an execution ARN; use `DescribeExecutionCommand` or `StartSyncExecutionCommand` for result handling.\n- Using `StartSyncExecutionCommand` with a Standard Workflow. Sync execution is for Express Workflows.\n- Forgetting that state machine creation needs both caller permissions and a workflow `roleArn` that Step Functions can assume.\n- Omitting `region`. Step Functions is regional, and the client needs the correct region to find the target state machine ARN.\n- Treating `cause` as structured JSON automatically. It is returned as text and may need `JSON.parse(...)` only if your workflow or downstream service encoded JSON into the string.\n\n## Official Sources\n\n- Maintainer package docs: https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-sfn\n- AWS SDK for JavaScript v3 Step Functions reference: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sfn/\n- Step Functions API reference: https://docs.aws.amazon.com/step-functions/latest/apireference/Welcome.html\n- `StartExecution`: https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html\n- `StartSyncExecution`: https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html\n- `CreateStateMachine`: https://docs.aws.amazon.com/step-functions/latest/apireference/API_CreateStateMachine.html\n- `ValidateStateMachineDefinition`: https://docs.aws.amazon.com/step-functions/latest/apireference/API_ValidateStateMachineDefinition.html\n"
  },
  {
    "path": "content/aws/docs/shield/javascript/DOC.md",
    "content": "---\nname: shield\ndescription: \"AWS SDK for JavaScript v3 client for AWS Shield Advanced protections, attack details, protection groups, and proactive engagement settings.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,shield,javascript,nodejs,security,ddos,shield-advanced\"\n---\n\n# `@aws-sdk/client-shield`\n\nUse this package to manage AWS Shield Advanced from JavaScript with AWS SDK v3. The practical flow is: confirm the account has an active Shield Advanced subscription, create protections for specific resource ARNs, optionally attach Route 53 health checks or proactive engagement contacts, and then use attack and protection APIs to inspect status over time.\n\nThis package is for Shield Advanced, not the always-on Shield Standard protection that AWS applies automatically.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-shield\n```\n\n## Prerequisites\n\nYou need AWS credentials that can call Shield Advanced APIs in the target account. Common prerequisites:\n\n- an active Shield Advanced subscription for the account\n- permission to manage the target protected resource ARN\n- a Route 53 health check ARN if you want health-based detection\n- an associated WAF v2 web ACL if you want automatic application layer mitigation on a supported resource\n\nTypical local setup in Node.js:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you use shared AWS config, set `AWS_PROFILE` before starting your app.\n\n## Initialize the client\n\n```javascript\nimport { ShieldClient } from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIn Node.js, AWS SDK v3 uses the default credential provider chain, so you usually do not need to pass credentials explicitly when environment variables, shared config, ECS, EC2, or IAM Identity Center are already configured.\n\n## Confirm the Shield Advanced subscription\n\nBefore creating protections, check whether the account subscription is active and inspect the current subscription limits.\n\n```javascript\nimport {\n  DescribeSubscriptionCommand,\n  GetSubscriptionStateCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function assertShieldAdvancedIsActive() {\n  const state = await shield.send(new GetSubscriptionStateCommand({}));\n\n  if (state.SubscriptionState !== \"ACTIVE\") {\n    throw new Error(\"Shield Advanced subscription is not active for this account\");\n  }\n\n  const details = await shield.send(new DescribeSubscriptionCommand({}));\n\n  console.log({\n    proactiveEngagementStatus: details.Subscription?.ProactiveEngagementStatus,\n    subscriptionArn: details.Subscription?.SubscriptionArn,\n    autoRenew: details.Subscription?.AutoRenew,\n    protectionLimits: details.Subscription?.SubscriptionLimits?.ProtectionLimits,\n  });\n}\n```\n\n`CreateSubscriptionCommand` exists, but Shield Advanced subscription management is an account-level billing decision and `DeleteSubscription` has a one-year subscription commitment. Most application code should verify subscription state rather than creating or deleting the subscription itself.\n\n## Create a protection for one resource\n\n`CreateProtection` enables Shield Advanced for a single AWS resource ARN per request.\n\nSupported resource types include:\n\n- CloudFront distributions\n- Route 53 hosted zones\n- Global Accelerator standard accelerators\n- Elastic IP allocations\n- Classic Load Balancers\n- Application Load Balancers\n\nShield Advanced does not create a protection directly for EC2 instances or Network Load Balancers. AWS documents protecting those through associated Elastic IP addresses.\n\n```javascript\nimport {\n  CreateProtectionCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function protectApplicationLoadBalancer(resourceArn) {\n  const response = await shield.send(\n    new CreateProtectionCommand({\n      Name: \"app-prod-alb\",\n      ResourceArn: resourceArn,\n      Tags: [\n        { Key: \"Environment\", Value: \"prod\" },\n        { Key: \"Service\", Value: \"app\" },\n      ],\n    }),\n  );\n\n  if (!response.ProtectionId) {\n    throw new Error(\"Shield did not return a protection ID\");\n  }\n\n  return response.ProtectionId;\n}\n```\n\n## List protections and inspect one\n\nUse `ListProtections` for discovery, then `DescribeProtection` when you need one full protection record. `DescribeProtection` accepts either `ProtectionId` or `ResourceArn`, but not both.\n\n```javascript\nimport {\n  DescribeProtectionCommand,\n  ListProtectionsCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function inspectAlbProtections() {\n  const listed = await shield.send(\n    new ListProtectionsCommand({\n      MaxResults: 20,\n      InclusionFilters: {\n        ResourceTypes: [\"APPLICATION_LOAD_BALANCER\"],\n      },\n    }),\n  );\n\n  for (const protection of listed.Protections ?? []) {\n    console.log({\n      id: protection.Id,\n      name: protection.Name,\n      resourceArn: protection.ResourceArn,\n      healthCheckIds: protection.HealthCheckIds,\n      applicationLayerAutomaticResponseConfiguration:\n        protection.ApplicationLayerAutomaticResponseConfiguration,\n    });\n  }\n\n  const firstArn = listed.Protections?.[0]?.ResourceArn;\n\n  if (!firstArn) {\n    return null;\n  }\n\n  return shield.send(\n    new DescribeProtectionCommand({\n      ResourceArn: firstArn,\n    }),\n  );\n}\n```\n\nIf you need every protection, keep following `NextToken` until it is absent.\n\n## Add or remove health-based detection\n\nHealth-based detection uses a Route 53 health check to improve Shield Advanced attack detection and response for a protected resource.\n\n```javascript\nimport {\n  AssociateHealthCheckCommand,\n  DisassociateHealthCheckCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function setHealthCheck(protectionId, healthCheckArn, enabled) {\n  if (enabled) {\n    await shield.send(\n      new AssociateHealthCheckCommand({\n        ProtectionId: protectionId,\n        HealthCheckArn: healthCheckArn,\n      }),\n    );\n\n    return;\n  }\n\n  await shield.send(\n    new DisassociateHealthCheckCommand({\n      ProtectionId: protectionId,\n      HealthCheckArn: healthCheckArn,\n    }),\n  );\n}\n```\n\nPass the Route 53 health check ARN, not just a health check ID.\n\n## List recent attacks and inspect one\n\nUse `ListAttacks` to retrieve attack summaries for a time window. Then call `DescribeAttack` with the `AttackId` when you need the detailed counters, properties, mitigations, and sub-resource information.\n\n```javascript\nimport {\n  DescribeAttackCommand,\n  ListAttacksCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function getRecentAttacks(resourceArn) {\n  const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);\n\n  const listed = await shield.send(\n    new ListAttacksCommand({\n      ResourceArns: [resourceArn],\n      StartTime: {\n        FromInclusive: sevenDaysAgo,\n      },\n      MaxResults: 20,\n    }),\n  );\n\n  const summaries = (listed.AttackSummaries ?? []).map((attack) => ({\n    attackId: attack.AttackId,\n    resourceArn: attack.ResourceArn,\n    startTime: attack.StartTime,\n    endTime: attack.EndTime,\n    vectors: (attack.AttackVectors ?? []).map((vector) => vector.VectorType),\n  }));\n\n  const firstAttackId = listed.AttackSummaries?.[0]?.AttackId;\n\n  if (!firstAttackId) {\n    return { summaries, details: null };\n  }\n\n  const details = await shield.send(\n    new DescribeAttackCommand({\n      AttackId: firstAttackId,\n    }),\n  );\n\n  return { summaries, details: details.Attack };\n}\n```\n\n`StartTime` and `EndTime` use time-range objects with `FromInclusive` and `ToExclusive` fields.\n\n## Create and inspect a protection group\n\nProtection groups let Shield Advanced treat multiple protected resources as a collective. For explicit membership, use `Pattern: \"ARBITRARY\"` and pass the protected resource ARNs in `Members`.\n\n```javascript\nimport {\n  CreateProtectionGroupCommand,\n  ListResourcesInProtectionGroupCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function createProtectionGroup(memberArns) {\n  await shield.send(\n    new CreateProtectionGroupCommand({\n      ProtectionGroupId: \"public-edge\",\n      Aggregation: \"SUM\",\n      Pattern: \"ARBITRARY\",\n      Members: memberArns,\n    }),\n  );\n\n  const members = await shield.send(\n    new ListResourcesInProtectionGroupCommand({\n      ProtectionGroupId: \"public-edge\",\n      MaxResults: 50,\n    }),\n  );\n\n  return members.ResourceArns ?? [];\n}\n```\n\nIf you later change the group definition, use `UpdateProtectionGroupCommand` with the same `ProtectionGroupId`.\n\n## Configure proactive engagement contacts\n\nThe Shield Response Team can use proactive engagement contacts for escalations and proactive support. Initialize the contact list first, then enable proactive engagement.\n\n```javascript\nimport {\n  AssociateProactiveEngagementDetailsCommand,\n  EnableProactiveEngagementCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function enableProactiveContacts() {\n  await shield.send(\n    new AssociateProactiveEngagementDetailsCommand({\n      EmergencyContactList: [\n        {\n          EmailAddress: \"secops@example.com\",\n          PhoneNumber: \"+1-206-555-0100\",\n          ContactNotes: \"24x7 security on-call rotation\",\n        },\n      ],\n    }),\n  );\n\n  await shield.send(new EnableProactiveEngagementCommand({}));\n}\n```\n\nThe contact list must include at least one phone number. If you already have contacts configured and want to keep them, read them first with `DescribeEmergencyContactSettingsCommand` and then send the full updated list.\n\n## Enable automatic application layer mitigation\n\nShield Advanced can manage WAF rules automatically for supported resources. AWS documents this for CloudFront distributions and Application Load Balancers only.\n\n```javascript\nimport {\n  EnableApplicationLayerAutomaticResponseCommand,\n  ShieldClient,\n  UpdateApplicationLayerAutomaticResponseCommand,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function enableAutomaticMitigation(resourceArn) {\n  await shield.send(\n    new EnableApplicationLayerAutomaticResponseCommand({\n      ResourceArn: resourceArn,\n      Action: {\n        Block: {},\n      },\n    }),\n  );\n}\n\nexport async function switchAutomaticMitigationToCount(resourceArn) {\n  await shield.send(\n    new UpdateApplicationLayerAutomaticResponseCommand({\n      ResourceArn: resourceArn,\n      Action: {\n        Count: {},\n      },\n    }),\n  );\n}\n```\n\nThis requires a WAF v2 web ACL already associated with the protected resource. When automatic mitigation is already enabled, update it with `UpdateApplicationLayerAutomaticResponseCommand` instead of calling the enable operation again.\n\n## Delete a protection\n\nDeleting a protection removes Shield Advanced coverage from that one resource. It does not cancel the account subscription.\n\n```javascript\nimport {\n  DeleteProtectionCommand,\n  ShieldClient,\n} from \"@aws-sdk/client-shield\";\n\nconst shield = new ShieldClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nexport async function deleteProtection(protectionId) {\n  await shield.send(\n    new DeleteProtectionCommand({\n      ProtectionId: protectionId,\n    }),\n  );\n}\n```\n\n## Pitfalls\n\n- This package is for Shield Advanced APIs. It does not enable or configure the baseline Shield Standard coverage that AWS applies automatically.\n- `CreateProtectionCommand` covers one resource per request.\n- `DescribeProtectionCommand` accepts either `ProtectionId` or `ResourceArn`, but not both.\n- Shield Advanced protects EC2 instances and Network Load Balancers through associated Elastic IP addresses rather than direct protection creation for those resource types.\n- Health-based detection requires a Route 53 health check ARN.\n- Automatic application layer mitigation works only for CloudFront distributions and Application Load Balancers, and it requires an associated WAF v2 web ACL.\n- List operations such as `ListProtectionsCommand`, `ListAttacksCommand`, `ListProtectionGroupsCommand`, and `ListResourcesInProtectionGroupCommand` can paginate through `NextToken`.\n- `DeleteSubscriptionCommand` is separate from deleting an individual protection, and AWS documents a one-year Shield Advanced subscription commitment.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-shield` version `3.1007.0`.\n- Prefer `ShieldClient` plus explicit command imports in application code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Shield client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/shield/`\n- AWS Shield Advanced API Reference: `https://docs.aws.amazon.com/waf/latest/DDOSAPIReference/Welcome.html`\n- Shield Advanced getting started: `https://docs.aws.amazon.com/waf/latest/developerguide/getting-started-ddos.html`\n- Adding Shield Advanced protection to AWS resources: `https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html`\n- Shield Advanced health-based detection: `https://docs.aws.amazon.com/waf/latest/developerguide/ddos-overview.html#ddos-advanced-health-check-option`\n- Shield Advanced automatic application layer DDoS mitigation: `https://docs.aws.amazon.com/waf/latest/developerguide/ddos-advanced-automatic-app-layer-response.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-shield`\n"
  },
  {
    "path": "content/aws/docs/smithy-client/javascript/DOC.md",
    "content": "---\nname: smithy-client\ndescription: \"Low-level AWS SDK for JavaScript v3 Smithy runtime for building custom clients, commands, and middleware stacks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,javascript,smithy,sdk,client,commands,middleware\"\n---\n\n# `@aws-sdk/smithy-client`\n\nUse `@aws-sdk/smithy-client` when you are building a low-level custom client or command on top of the AWS SDK for JavaScript v3 runtime.\n\nMost application code should **not** install this package directly. If you are calling AWS services such as S3, DynamoDB, or STS, install the relevant `@aws-sdk/client-*` package instead. Reach for `@aws-sdk/smithy-client` when you need to define your own `Client`, `Command`, middleware stack behavior, or generated-style convenience methods.\n\n## Install\n\nFor a custom Node.js client, install the Smithy runtime pieces you need explicitly:\n\n```bash\nnpm install @aws-sdk/smithy-client@3.374.0 @aws-sdk/node-http-handler @aws-sdk/protocol-http @aws-sdk/middleware-serde\n```\n\nIf the endpoint is an AWS-authenticated endpoint, also install credential and signing support:\n\n```bash\nnpm install @aws-sdk/credential-provider-node @aws-sdk/middleware-signing @aws-crypto/sha256-js\n```\n\n## Environment and credentials\n\nFor local development, set an endpoint and, if the endpoint requires AWS SigV4 signing, the usual AWS region and credentials:\n\n```env\nSMITHY_ENDPOINT=https://example.execute-api.us-east-1.amazonaws.com\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\nAWS_SESSION_TOKEN=...\nAWS_PROFILE=default\n```\n\n`SMITHY_ENDPOINT` is the main package-specific input. The AWS credential variables are only needed when the target endpoint expects signed AWS requests.\n\n## Initialize a custom client\n\n`Client` gives you the shared middleware stack and the `send()` method. At minimum, provide a request handler, an endpoint provider, and an internal API version string.\n\n```javascript\nimport { Client, NoOpLogger } from \"@aws-sdk/smithy-client\";\nimport { NodeHttpHandler } from \"@aws-sdk/node-http-handler\";\n\nexport class ExampleClient extends Client {\n  constructor(input = {}) {\n    const endpointUrl = new URL(\n      input.endpoint ?? process.env.SMITHY_ENDPOINT ?? \"http://localhost:3000\",\n    );\n\n    super({\n      ...input,\n      apiVersion: \"2023-01-01\",\n      requestHandler: input.requestHandler ?? new NodeHttpHandler(),\n      logger: input.logger ?? new NoOpLogger(),\n      endpoint: async () => ({\n        protocol: endpointUrl.protocol,\n        hostname: endpointUrl.hostname,\n        port: endpointUrl.port ? Number(endpointUrl.port) : undefined,\n        path: endpointUrl.pathname,\n      }),\n    });\n  }\n}\n```\n\nWhen you are done with a Node.js client, call `client.destroy()` to release the underlying HTTP handler resources.\n\n## Define and send a custom command\n\nCommands attach their own middleware to the shared client stack. For a normal HTTP command, add the serde plugin and implement `serialize()` and `deserialize()`.\n\n```javascript\nimport { Command } from \"@aws-sdk/smithy-client\";\nimport { getSerdePlugin } from \"@aws-sdk/middleware-serde\";\nimport { HttpRequest, HttpResponse } from \"@aws-sdk/protocol-http\";\n\nexport class PingCommand extends Command {\n  constructor(input = {}) {\n    super();\n    this.input = input;\n  }\n\n  resolveMiddleware(clientStack, configuration, options) {\n    this.middlewareStack.use(\n      getSerdePlugin(configuration, this.serialize, this.deserialize),\n    );\n\n    return this.resolveMiddlewareWithContext(clientStack, configuration, options, {\n      middlewareFn: () => [],\n      clientName: \"ExampleClient\",\n      commandName: \"PingCommand\",\n      inputFilterSensitiveLog: (value) => value,\n      outputFilterSensitiveLog: (value) => value,\n      smithyContext: {\n        service: \"ExampleService\",\n        operation: \"Ping\",\n      },\n      additionalContext: {},\n      CommandCtor: PingCommand,\n    });\n  }\n\n  async serialize(input, context) {\n    const endpoint = await context.endpoint();\n    const basePath = endpoint.path?.replace(/\\/$/, \"\") ?? \"\";\n\n    return new HttpRequest({\n      protocol: endpoint.protocol,\n      hostname: endpoint.hostname,\n      port: endpoint.port,\n      method: \"GET\",\n      path: `${basePath}/ping`,\n      headers: {\n        host: endpoint.hostname,\n      },\n    });\n  }\n\n  async deserialize(response) {\n    if (!HttpResponse.isInstance(response)) {\n      throw new Error(\"Expected an HttpResponse\");\n    }\n\n    return {\n      $metadata: {\n        httpStatusCode: response.statusCode,\n      },\n      ok: response.statusCode === 200,\n    };\n  }\n}\n```\n\nUse the client and command together with `send()`:\n\n```javascript\nimport { ExampleClient } from \"./example-client.js\";\nimport { PingCommand } from \"./ping-command.js\";\n\nconst client = new ExampleClient({\n  endpoint: process.env.SMITHY_ENDPOINT,\n});\n\nconst output = await client.send(new PingCommand({}));\n\nconsole.log(output.ok);\nconsole.log(output.$metadata.httpStatusCode);\n\nclient.destroy();\n```\n\n## Add AWS SigV4 signing\n\n`@aws-sdk/smithy-client` does not resolve credentials or sign requests by itself. If your custom client calls an AWS-authenticated endpoint, layer signing middleware into the client configuration.\n\n```javascript\nimport { Client, NoOpLogger } from \"@aws-sdk/smithy-client\";\nimport { NodeHttpHandler } from \"@aws-sdk/node-http-handler\";\nimport { defaultProvider } from \"@aws-sdk/credential-provider-node\";\nimport {\n  getAwsAuthPlugin,\n  resolveAwsAuthConfig,\n} from \"@aws-sdk/middleware-signing\";\nimport { Sha256 } from \"@aws-crypto/sha256-js\";\n\nexport class ExampleAwsClient extends Client {\n  constructor(input = {}) {\n    const endpointUrl = new URL(input.endpoint ?? process.env.SMITHY_ENDPOINT);\n    const region = input.region ?? process.env.AWS_REGION ?? \"us-east-1\";\n\n    const config = resolveAwsAuthConfig({\n      ...input,\n      apiVersion: \"2023-01-01\",\n      requestHandler: input.requestHandler ?? new NodeHttpHandler(),\n      logger: input.logger ?? new NoOpLogger(),\n      endpoint: async () => ({\n        protocol: endpointUrl.protocol,\n        hostname: endpointUrl.hostname,\n        port: endpointUrl.port ? Number(endpointUrl.port) : undefined,\n        path: endpointUrl.pathname,\n      }),\n      region: async () => region,\n      credentials: input.credentials ?? defaultProvider(),\n      sha256: Sha256,\n      signingName: input.signingName ?? \"execute-api\",\n      signingRegion: input.signingRegion ?? (async () => region),\n    });\n\n    super(config);\n    this.middlewareStack.use(getAwsAuthPlugin(config));\n  }\n}\n```\n\nSet `signingName` to the SigV4 service name expected by the target endpoint. For example, API Gateway commonly uses `execute-api`.\n\n## Add generated-style convenience methods\n\n`createAggregatedClient()` adds convenience methods to a client prototype by turning command class names into lower-camel-case methods and stripping the `Command` suffix.\n\n```javascript\nimport { createAggregatedClient } from \"@aws-sdk/smithy-client\";\nimport { ExampleClient } from \"./example-client.js\";\nimport { PingCommand } from \"./ping-command.js\";\n\ncreateAggregatedClient({ PingCommand }, ExampleClient);\n\nconst client = new ExampleClient({\n  endpoint: process.env.SMITHY_ENDPOINT,\n});\n\nconst output = await client.ping({});\nconsole.log(output.ok);\n\nclient.destroy();\n```\n\nThis matches how generated AWS SDK clients expose methods such as `client.listTables()` in addition to `client.send(new ListTablesCommand(...))`.\n\n## Handle service exceptions\n\nThe package exports `ServiceException`, which gives you a consistent base shape for modeled or decorated service-side errors.\n\n```javascript\nimport { ServiceException } from \"@aws-sdk/smithy-client\";\n\ntry {\n  await client.send(new PingCommand({}));\n} catch (error) {\n  if (ServiceException.isInstance(error)) {\n    console.error(error.name);\n    console.error(error.$metadata.httpStatusCode);\n  }\n\n  throw error;\n}\n```\n\n## Common pitfalls\n\n- Do not use this package instead of a real `@aws-sdk/client-*` service client unless you are intentionally building custom Smithy runtime code.\n- Do not forget to attach `getSerdePlugin(...)` inside each command's `resolveMiddleware()`; without it, `serialize()` and `deserialize()` are not wired into the stack.\n- Do not assume requests are automatically signed. Add `@aws-sdk/middleware-signing` and a credential provider when the endpoint requires AWS SigV4 auth.\n- If you enable `cacheMiddleware: true`, middleware resolution is cached per command class. Middleware changes made after the first request are not picked up until you create a new client or clear the cache with `destroy()`.\n- Call `client.destroy()` when using Node.js request handlers so sockets and related resources can be released.\n\n## Version notes\n\n- This guide covers `@aws-sdk/smithy-client` version `3.374.0`.\n- The most important public runtime pieces are `Client`, `Command`, `createAggregatedClient`, `NoOpLogger`, and the Smithy exception helpers.\n- Keep companion runtime packages on the same AWS SDK v3 family when following examples for this package version.\n\n## Official sources\n\n- AWS SDK for JavaScript v3 package reference: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-smithy-client/\n- npm package page: https://www.npmjs.com/package/@aws-sdk/smithy-client\n"
  },
  {
    "path": "content/aws/docs/sns/javascript/DOC.md",
    "content": "---\nname: sns\ndescription: \"AWS SDK for JavaScript v3 client for Amazon SNS in Node.js applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,sns,notifications,pubsub,messaging,javascript\"\n---\n\n# AWS SNS SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-sns` to create topics, publish messages, and manage Amazon SNS subscriptions from modern JavaScript and TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-sns`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1006.0`.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n- Prefer `SNSClient` plus explicit commands for most application code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-sns\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you have already configured AWS access through environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport { PublishCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nawait sns.send(\n  new PublishCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders\",\n    Subject: \"order-created\",\n    Message: JSON.stringify({ orderId: \"123\", status: \"created\" }),\n  }),\n);\n```\n\n`PublishCommand` requires exactly one destination: `TopicArn`, `TargetArn`, or `PhoneNumber`.\n\n## Common Operations\n\n### Create a topic\n\n```javascript\nimport { CreateTopicCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nconst { TopicArn } = await sns.send(\n  new CreateTopicCommand({\n    Name: \"orders\",\n  }),\n);\n\nconsole.log(TopicArn);\n```\n\n### Subscribe an SQS queue to a topic\n\n```javascript\nimport { SNSClient, SubscribeCommand } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nconst { SubscriptionArn } = await sns.send(\n  new SubscribeCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders\",\n    Protocol: \"sqs\",\n    Endpoint: \"arn:aws:sqs:us-east-1:123456789012:orders-queue\",\n  }),\n);\n\nconsole.log(SubscriptionArn);\n```\n\nFor SQS subscriptions, the queue also needs a resource policy that allows the SNS topic to send messages to it.\n\n## SNS-Specific Gotchas\n\n- `PublishCommand` targets one destination at a time. Set only one of `TopicArn`, `TargetArn`, or `PhoneNumber`.\n- Email and HTTP(S) subscriptions can remain `PendingConfirmation` until the endpoint confirms the subscription.\n- SQS and Lambda integrations usually need an additional queue policy or function permission before delivery works.\n- FIFO topics must end with `.fifo`, and publishing to them requires `MessageGroupId`; `MessageDeduplicationId` is also required unless content-based deduplication is enabled.\n- `MessageStructure: \"json\"` expects `Message` to be a JSON string containing per-protocol payloads, not a nested JavaScript object.\n- Phone-number publishing uses E.164 format such as `+12065550100`.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: Cognito, `fromIni`, assume-role flows, and other explicit credential helpers.\n- `@aws-sdk/client-sqs`: create queues and manage queue policies for SNS-to-SQS fan-out.\n- `@aws-sdk/client-lambda`: manage Lambda permissions when subscribing functions to topics.\n\n## Common SNS Operations\n\n### Publish a message with attributes\n\n```javascript\nimport { PublishCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nawait sns.send(\n  new PublishCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders\",\n    Message: JSON.stringify({ orderId: \"123\", status: \"created\" }),\n    MessageAttributes: {\n      eventType: {\n        DataType: \"String\",\n        StringValue: \"order.created\",\n      },\n      tenantId: {\n        DataType: \"String\",\n        StringValue: \"acme\",\n      },\n    },\n  }),\n);\n```\n\n### Publish protocol-specific payloads\n\nUse `MessageStructure: \"json\"` when different subscribers should receive different message bodies.\n\n```javascript\nimport { PublishCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nawait sns.send(\n  new PublishCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders\",\n    MessageStructure: \"json\",\n    Message: JSON.stringify({\n      default: \"Order 123 created\",\n      email: \"Order 123 was created and is ready for review.\",\n      sqs: JSON.stringify({ orderId: \"123\", status: \"created\" }),\n    }),\n  }),\n);\n```\n\n### Publish to a FIFO topic\n\nFIFO topic names end with `.fifo`.\n\n```javascript\nimport { PublishCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nawait sns.send(\n  new PublishCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders.fifo\",\n    Message: JSON.stringify({ orderId: \"123\", status: \"created\" }),\n    MessageGroupId: \"orders\",\n    MessageDeduplicationId: \"order-123-created\",\n  }),\n);\n```\n\nIf the topic enables content-based deduplication, `MessageDeduplicationId` can be omitted.\n\n### List topics with pagination\n\n```javascript\nimport {\n  paginateListTopics,\n  SNSClient,\n} from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListTopics({ client: sns }, {})) {\n  for (const topic of page.Topics ?? []) {\n    console.log(topic.TopicArn);\n  }\n}\n```\n\n### Confirm a subscription from a token\n\nThis is useful when your application receives the confirmation token out of band.\n\n```javascript\nimport {\n  ConfirmSubscriptionCommand,\n  SNSClient,\n} from \"@aws-sdk/client-sns\";\n\nconst sns = new SNSClient({ region: \"us-east-1\" });\n\nconst { SubscriptionArn } = await sns.send(\n  new ConfirmSubscriptionCommand({\n    TopicArn: \"arn:aws:sns:us-east-1:123456789012:orders\",\n    Token: \"token-from-confirmation-message\",\n  }),\n);\n\nconsole.log(SubscriptionArn);\n```\n"
  },
  {
    "path": "content/aws/docs/sqs/javascript/DOC.md",
    "content": "---\nname: sqs\ndescription: \"AWS SDK for JavaScript v3 client for Amazon SQS in Node.js applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,sqs,queues,messaging,javascript\"\n---\n\n# AWS SQS SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-sqs` to create queues and send, receive, and delete Amazon SQS messages from modern JavaScript and TypeScript code.\n\n## Golden Rule\n\n- Install `@aws-sdk/client-sqs`, not the legacy `aws-sdk` v2 package.\n- The package version covered here is `3.1006.0`.\n- Import from the package root only. Do not deep-import from `dist-*` paths.\n- Prefer `SQSClient` plus explicit commands for most application code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-sqs\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  },\n});\n```\n\n## Credentials and Region\n\nIn Node.js, the default credential provider chain is usually enough if you have already configured AWS access through environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\nIf you rely on shared AWS config instead of environment variables, keep the client initialization simple and set only the region in code.\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport { SendMessageCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nawait sqs.send(\n  new SendMessageCommand({\n    QueueUrl: \"https://sqs.us-east-1.amazonaws.com/123456789012/jobs\",\n    MessageBody: JSON.stringify({ taskId: \"123\" }),\n  }),\n);\n```\n\nPrefer storing or resolving the full `QueueUrl` before sending traffic. Do not build queue URLs by string concatenation.\n\n## Common Operations\n\n### Resolve a queue URL from a queue name\n\n```javascript\nimport { GetQueueUrlCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nconst { QueueUrl } = await sqs.send(\n  new GetQueueUrlCommand({ QueueName: \"jobs\" }),\n);\n\nconsole.log(QueueUrl);\n```\n\n### Receive and delete a message\n\n```javascript\nimport {\n  DeleteMessageCommand,\n  ReceiveMessageCommand,\n  SQSClient,\n} from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\nconst queueUrl = \"https://sqs.us-east-1.amazonaws.com/123456789012/jobs\";\n\nconst { Messages = [] } = await sqs.send(\n  new ReceiveMessageCommand({\n    QueueUrl: queueUrl,\n    MaxNumberOfMessages: 10,\n    WaitTimeSeconds: 20,\n    VisibilityTimeout: 30,\n  }),\n);\n\nfor (const message of Messages) {\n  console.log(message.Body);\n\n  if (!message.ReceiptHandle) {\n    continue;\n  }\n\n  await sqs.send(\n    new DeleteMessageCommand({\n      QueueUrl: queueUrl,\n      ReceiptHandle: message.ReceiptHandle,\n    }),\n  );\n}\n```\n\nDelete only after successful processing. If the handler fails, let the visibility timeout expire so the message can be retried.\n\n## SQS-Specific Gotchas\n\n- SQS delivery is at least once. Make consumers idempotent.\n- Delete messages with `ReceiptHandle`, not `MessageId`.\n- Use long polling with `WaitTimeSeconds` to reduce empty responses and API churn.\n- `ReceiveMessage` returns at most 10 messages per call, so batch or poll accordingly.\n- FIFO queue names must end with `.fifo`, and FIFO sends require `MessageGroupId`.\n- If FIFO content-based deduplication is off, supply `MessageDeduplicationId` on sends.\n- Queue attribute values are strings when you create or update queues.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, STS assume-role flows, and other credential helpers.\n\n## Common SQS Operations\n\n### Create a standard queue\n\nQueue attributes are string values.\n\n```javascript\nimport { CreateQueueCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nconst { QueueUrl } = await sqs.send(\n  new CreateQueueCommand({\n    QueueName: \"jobs\",\n    Attributes: {\n      ReceiveMessageWaitTimeSeconds: \"20\",\n      VisibilityTimeout: \"30\",\n    },\n  }),\n);\n\nconsole.log(QueueUrl);\n```\n\n### Resolve a queue URL\n\n`SendMessage`, `ReceiveMessage`, and `DeleteMessage` all need the full queue URL.\n\n```javascript\nimport { GetQueueUrlCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nconst { QueueUrl } = await sqs.send(\n  new GetQueueUrlCommand({ QueueName: \"jobs\" }),\n);\n```\n\n### Send a message with attributes\n\n```javascript\nimport { SendMessageCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nawait sqs.send(\n  new SendMessageCommand({\n    QueueUrl: \"https://sqs.us-east-1.amazonaws.com/123456789012/jobs\",\n    MessageBody: JSON.stringify({ taskId: \"123\" }),\n    MessageAttributes: {\n      eventType: {\n        DataType: \"String\",\n        StringValue: \"job.created\",\n      },\n    },\n  }),\n);\n```\n\n### Send to a FIFO queue\n\nFIFO queue names end with `.fifo`, and the send input must include `MessageGroupId`.\n\n```javascript\nimport { SendMessageCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nawait sqs.send(\n  new SendMessageCommand({\n    QueueUrl: \"https://sqs.us-east-1.amazonaws.com/123456789012/jobs.fifo\",\n    MessageBody: JSON.stringify({ taskId: \"123\" }),\n    MessageGroupId: \"jobs\",\n    MessageDeduplicationId: \"task-123\",\n  }),\n);\n```\n\nIf the queue has content-based deduplication enabled, the explicit `MessageDeduplicationId` can be omitted.\n\n### List queues with pagination\n\n```javascript\nimport {\n  paginateListQueues,\n  SQSClient,\n} from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nfor await (const page of paginateListQueues(\n  { client: sqs },\n  { QueueNamePrefix: \"jobs\" },\n)) {\n  for (const queueUrl of page.QueueUrls ?? []) {\n    console.log(queueUrl);\n  }\n}\n```\n\n### Extend visibility while processing\n\nIf work takes longer than the original visibility timeout, extend it before the message becomes visible again.\n\n```javascript\nimport {\n  ChangeMessageVisibilityCommand,\n  SQSClient,\n} from \"@aws-sdk/client-sqs\";\n\nconst sqs = new SQSClient({ region: \"us-east-1\" });\n\nawait sqs.send(\n  new ChangeMessageVisibilityCommand({\n    QueueUrl: \"https://sqs.us-east-1.amazonaws.com/123456789012/jobs\",\n    ReceiptHandle: \"AQEB...example...\",\n    VisibilityTimeout: 120,\n  }),\n);\n```\n"
  },
  {
    "path": "content/aws/docs/ssm/javascript/DOC.md",
    "content": "---\nname: ssm\ndescription: \"AWS SDK for JavaScript v3 Systems Manager client for Parameter Store, Run Command, and related SSM APIs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,ssm,systems-manager,javascript,nodejs,parameter-store,run-command\"\n---\n\n# `@aws-sdk/client-ssm`\n\nUse this package for Amazon Systems Manager APIs in AWS SDK for JavaScript v3. The most common application use cases are Parameter Store reads and writes, parameter hierarchy traversal, and Run Command execution against managed nodes.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-ssm\n```\n\nPrefer `SSMClient` plus explicit command imports. The package also exposes an aggregated `SSM` client, but command-based imports are the safer default for clearer dependencies and smaller bundles.\n\n## Initialize the client\n\n```javascript\nimport { SSMClient } from \"@aws-sdk/client-ssm\";\n\nconst ssm = new SSMClient({ region: \"us-east-1\" });\n```\n\nMost SSM workloads run from trusted server-side code. In Node.js, the default credential provider chain is usually enough if you already configured AWS access through environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\nThe v3 SDK uses client-plus-command calls:\n\n```javascript\nimport {\n  GetParameterCommand,\n  SSMClient,\n} from \"@aws-sdk/client-ssm\";\n\nconst ssm = new SSMClient({ region: \"us-east-1\" });\n\nconst response = await ssm.send(\n  new GetParameterCommand({\n    Name: \"/app/prod/db/password\",\n    WithDecryption: true,\n  }),\n);\n\nconsole.log(response.Parameter?.Value);\n```\n\nUse `WithDecryption: true` when reading `SecureString` parameters and ensure the caller also has permission to use the backing KMS key.\n\n## Common Operations\n\n### Put or update a parameter\n\n```javascript\nimport {\n  PutParameterCommand,\n  SSMClient,\n} from \"@aws-sdk/client-ssm\";\n\nconst ssm = new SSMClient({ region: \"us-east-1\" });\n\nawait ssm.send(\n  new PutParameterCommand({\n    Name: \"/app/prod/api/base-url\",\n    Value: \"https://api.example.com\",\n    Type: \"String\",\n    Overwrite: true,\n  }),\n);\n```\n\nOverwriting a parameter creates a new parameter version instead of mutating history in place.\n\n### Walk a parameter hierarchy\n\n```javascript\nimport {\n  GetParametersByPathCommand,\n  SSMClient,\n} from \"@aws-sdk/client-ssm\";\n\nconst ssm = new SSMClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await ssm.send(\n    new GetParametersByPathCommand({\n      Path: \"/app/prod\",\n      Recursive: true,\n      WithDecryption: true,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const parameter of page.Parameters ?? []) {\n    console.log(parameter.Name, parameter.Value);\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nParameter Store names are hierarchical slash-delimited strings. Traverse by path instead of maintaining a hard-coded list when your app groups configuration under a shared prefix.\n\n### Send a Run Command and inspect the invocation\n\n```javascript\nimport {\n  GetCommandInvocationCommand,\n  SendCommandCommand,\n  SSMClient,\n} from \"@aws-sdk/client-ssm\";\n\nconst ssm = new SSMClient({ region: \"us-east-1\" });\n\nconst sendResult = await ssm.send(\n  new SendCommandCommand({\n    InstanceIds: [\"i-0123456789abcdef0\"],\n    DocumentName: \"AWS-RunShellScript\",\n    Parameters: {\n      commands: [\"echo hello from systems manager\"],\n    },\n  }),\n);\n\nconst commandId = sendResult.Command?.CommandId;\n\nif (!commandId) {\n  throw new Error(\"Missing command id\");\n}\n\nconst invocation = await ssm.send(\n  new GetCommandInvocationCommand({\n    CommandId: commandId,\n    InstanceId: \"i-0123456789abcdef0\",\n  }),\n);\n\nconsole.log(invocation.Status, invocation.StandardOutputContent);\n```\n\n`SendCommand` is asynchronous. A successful send only means Systems Manager accepted the request, not that the command finished successfully on the target.\n\n## SSM-Specific Gotchas\n\n- `SecureString` reads need `WithDecryption: true` and matching KMS permissions.\n- Many list-style SSM APIs use `NextToken`; do not assume a single response contains everything.\n- Parameter names are case-sensitive and path-like naming conventions are operationally easier to manage.\n- Run Command requires managed nodes that are actually registered with Systems Manager and have the right IAM/agent setup.\n- `SendCommand` acceptance is not execution success; inspect invocation status and output separately.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: shared config, IAM Identity Center, Cognito, and assume-role credential helpers.\n- `@aws-sdk/client-kms`: direct KMS key management or cryptographic workflows outside normal Parameter Store reads and writes.\n"
  },
  {
    "path": "content/aws/docs/sts/javascript/DOC.md",
    "content": "---\nname: sts\ndescription: \"AWS SDK for JavaScript v3 STS client for temporary credentials, role assumption, and caller identity inspection.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1006.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"aws,sts,javascript,nodejs,iam,credentials,assume-role,temporary-credentials\"\n---\n\n# `@aws-sdk/client-sts`\n\nUse this package for AWS Security Token Service operations in AWS SDK for JavaScript v3. The STS client is how JavaScript code inspects the current AWS identity, assumes IAM roles, requests temporary session credentials, and decodes some authorization failure details.\n\nCommon operations include `AssumeRole`, `AssumeRoleWithWebIdentity`, `AssumeRoleWithSAML`, `GetSessionToken`, `GetFederationToken`, `GetCallerIdentity`, and `DecodeAuthorizationMessage`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-sts\n```\n\nCommon companion package:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nPrefer `STSClient` plus explicit command imports. The package also exposes an aggregated `STS` client, but command-based imports are the safer default for clearer call sites and smaller bundles.\n\n## Client Setup\n\n```javascript\nimport { STSClient } from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nSTS historically has a global endpoint, but the SDK still expects normal client configuration. In practice, set a region explicitly and keep it consistent with the workloads that will use the temporary credentials you request.\n\n## Credentials and Runtime Notes\n\n- In Node.js, the default credential provider chain is usually enough if AWS access is already configured through environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n- Most STS calls are made from trusted backend code that already has some base AWS credentials and needs short-lived credentials for a narrower task.\n- In browser and mobile code, do not ship long-lived AWS keys. Prefer federation flows such as Cognito or web identity plus tightly scoped IAM roles.\n- If your app needs automatic refresh of temporary credentials, prefer `@aws-sdk/credential-providers` over hand-rolling STS refresh loops.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n```\n\n## Core Usage Pattern\n\n`GetCallerIdentity` is the fastest STS sanity check. It confirms which principal the SDK is using without requiring you to guess whether the current credentials came from environment variables, a profile, ECS, EC2, or another provider.\n\n```javascript\nimport {\n  GetCallerIdentityCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst response = await sts.send(new GetCallerIdentityCommand({}));\n\nconsole.log(response.Account);\nconsole.log(response.Arn);\nconsole.log(response.UserId);\n```\n\n`GetCallerIdentity` is also unusual because STS returns this identity information even when an IAM policy explicitly denies `sts:GetCallerIdentity`.\n\n## Common Operations\n\n### Assume a role\n\nUse `AssumeRole` for cross-account access, privilege narrowing, or role chaining from trusted backend code.\n\n```javascript\nimport {\n  AssumeRoleCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst { Credentials, AssumedRoleUser } = await sts.send(\n  new AssumeRoleCommand({\n    RoleArn: \"arn:aws:iam::123456789012:role/CrossAccountReadOnly\",\n    RoleSessionName: \"billing-report-job\",\n    ExternalId: process.env.AWS_EXTERNAL_ID,\n    DurationSeconds: 3600,\n  }),\n);\n\nif (!Credentials) {\n  throw new Error(\"AssumeRole did not return credentials.\");\n}\n\nconsole.log(AssumedRoleUser?.Arn);\nconsole.log(Credentials.Expiration);\n```\n\nThe returned session is only usable if you pass all three credential parts onward: `AccessKeyId`, `SecretAccessKey`, and `SessionToken`.\n\n### Use assumed credentials in another SDK client\n\nAfter `AssumeRole`, pass the temporary credential set directly into the client that should run under that role.\n\n```javascript\nimport {\n  AssumeRoleCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\nimport { S3Client, ListBucketsCommand } from \"@aws-sdk/client-s3\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst { Credentials } = await sts.send(\n  new AssumeRoleCommand({\n    RoleArn: \"arn:aws:iam::123456789012:role/CrossAccountReadOnly\",\n    RoleSessionName: \"list-buckets-job\",\n  }),\n);\n\nif (!Credentials?.AccessKeyId || !Credentials.SecretAccessKey || !Credentials.SessionToken) {\n  throw new Error(\"Incomplete STS credentials returned.\");\n}\n\nconst s3 = new S3Client({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: Credentials.AccessKeyId,\n    secretAccessKey: Credentials.SecretAccessKey,\n    sessionToken: Credentials.SessionToken,\n  },\n});\n\nconst { Buckets } = await s3.send(new ListBucketsCommand({}));\n\nconsole.log(Buckets?.map((bucket) => bucket.Name));\n```\n\nIf you need auto-refresh instead of one manual STS call, move this flow to `@aws-sdk/credential-providers`.\n\n### Request an MFA-backed session token\n\nUse `GetSessionToken` when an IAM user needs temporary credentials tied to MFA.\n\n```javascript\nimport {\n  GetSessionTokenCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst { Credentials } = await sts.send(\n  new GetSessionTokenCommand({\n    SerialNumber: \"arn:aws:iam::123456789012:mfa/alice\",\n    TokenCode: \"123456\",\n    DurationSeconds: 3600,\n  }),\n);\n\nconsole.log(Credentials?.AccessKeyId);\nconsole.log(Credentials?.Expiration);\n```\n\nThis does not switch you into a different IAM role. It issues temporary credentials for the calling IAM identity.\n\n### Assume a role with a web identity token\n\nUse `AssumeRoleWithWebIdentity` when an external identity provider gives you an OIDC token and IAM is configured to trust that provider.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  AssumeRoleWithWebIdentityCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst webIdentityToken = await readFile(\n  \"/var/run/secrets/eks.amazonaws.com/serviceaccount/token\",\n  \"utf8\",\n);\n\nconst { Credentials, SubjectFromWebIdentityToken } = await sts.send(\n  new AssumeRoleWithWebIdentityCommand({\n    RoleArn: \"arn:aws:iam::123456789012:role/oidc-workload-role\",\n    RoleSessionName: \"web-identity-session\",\n    WebIdentityToken: webIdentityToken,\n  }),\n);\n\nconsole.log(SubjectFromWebIdentityToken);\nconsole.log(Credentials?.Expiration);\n```\n\nFor EKS, local profile-based assume-role, or recurring browser-safe refresh, the higher-level providers in `@aws-sdk/credential-providers` are usually less error-prone than calling this command directly.\n\n### Decode an encoded authorization failure\n\nSome AWS API errors include an encoded authorization message. `DecodeAuthorizationMessage` turns that into a human-readable JSON string.\n\n```javascript\nimport {\n  DecodeAuthorizationMessageCommand,\n  STSClient,\n} from \"@aws-sdk/client-sts\";\n\nconst sts = new STSClient({ region: \"us-east-1\" });\n\nconst { DecodedMessage } = await sts.send(\n  new DecodeAuthorizationMessageCommand({\n    EncodedMessage: process.env.AWS_ENCODED_AUTH_MESSAGE,\n  }),\n);\n\nif (DecodedMessage) {\n  console.log(JSON.parse(DecodedMessage));\n}\n```\n\nOnly some AWS service errors include an encoded authorization message, so treat this as a troubleshooting tool rather than part of a normal request path.\n\n## STS-Specific Gotchas\n\n- Temporary STS credentials always include a session token. If you forget `SessionToken`, downstream AWS clients fail even if the access key and secret key look valid.\n- `RoleSessionName` is required for role-assumption flows and shows up in AWS logs and ARNs. Use a descriptive, traceable value.\n- `GetSessionToken` and `AssumeRole` solve different problems: one creates a temporary session for the current IAM identity, the other switches into another role.\n- Session policies, managed policy ARNs, and session tags contribute to `PackedPolicySize`. If that value grows too large, role assumption can fail.\n- Temporary credentials expire. Cache them with the expiration timestamp, not forever, and prefer auto-refreshing credential providers when possible.\n- `GetCallerIdentity` is the safest first diagnostic when you are unsure which principal the SDK resolved.\n- `DecodeAuthorizationMessage` requires an encoded message from another AWS error response; it is not a generic IAM simulator.\n- Do not deep-import internals from package build directories.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/credential-providers`: `fromIni`, role chaining, IAM Identity Center, token-file and web-identity helpers, and auto-refreshing temporary credentials.\n- `@aws-sdk/client-iam`: manage roles, trust policies, users, and policy attachments; STS consumes those identities and trust relationships but does not administer them.\n- `@aws-sdk/client-cognito-identity`: browser and mobile federation patterns that should not embed long-lived AWS keys.\n"
  },
  {
    "path": "content/aws/docs/support/javascript/DOC.md",
    "content": "---\nname: support\ndescription: \"AWS Support SDK for JavaScript (v3) for creating and managing AWS Support cases from Node.js\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,support,case-management,troubleshooting,operations\"\n---\n\n# AWS Support SDK for JavaScript\n\nUse `@aws-sdk/client-support` to create and manage AWS Support cases from JavaScript or Node.js. The same client also exposes the discovery APIs you need before creating a case, including service codes, category codes, severity levels, supported languages, attachments, and case communications.\n\nThe AWS Support API requires a Business, Enterprise On-Ramp, or Enterprise Support plan. Accounts without one receive `SubscriptionRequiredException`.\n\n## Installation\n\n```bash\nnpm install @aws-sdk/client-support\n```\n\nThese examples assume Node.js 18+ and the standard AWS SDK for JavaScript v3 credential chain.\n\n## Credentials and client initialization\n\nSet credentials with environment variables or an AWS profile:\n\n```bash\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=your-profile\n```\n\nFor the standard AWS partition, the Support endpoint resolves to `support.us-east-1.amazonaws.com`, so using `us-east-1` keeps the configuration explicit.\n\n```typescript\nimport { SupportClient } from \"@aws-sdk/client-support\";\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Discover valid service, category, and severity codes\n\nDo not guess `serviceCode`, `categoryCode`, or `severityCode`. Fetch them from the Support API and use the returned codes in `CreateCase`.\n\n```typescript\nimport {\n  DescribeServicesCommand,\n  DescribeSeverityLevelsCommand,\n  SupportClient,\n} from \"@aws-sdk/client-support\";\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst servicesResponse = await client.send(\n  new DescribeServicesCommand({ language: \"en\" }),\n);\n\nconst severityResponse = await client.send(\n  new DescribeSeverityLevelsCommand({ language: \"en\" }),\n);\n\nconsole.dir(\n  servicesResponse.services?.map((service) => ({\n    code: service.code,\n    name: service.name,\n    categories: service.categories?.map((category) => ({\n      code: category.code,\n      name: category.name,\n    })),\n  })),\n  { depth: null },\n);\n\nconsole.dir(\n  severityResponse.severityLevels?.map((level) => ({\n    code: level.code,\n    name: level.name,\n  })),\n  { depth: null },\n);\n```\n\nThe severity codes are `low`, `normal`, `high`, `urgent`, and `critical`, but the levels available to your account depend on your support plan.\n\n## Check supported languages and case options\n\nUse `DescribeSupportedLanguagesCommand` to confirm the languages available for a specific service and category. Use `DescribeCreateCaseOptionsCommand` if you need language availability and communication type options for that exact combination.\n\n```bash\nexport AWS_SUPPORT_SERVICE_CODE=YOUR_SERVICE_CODE\nexport AWS_SUPPORT_CATEGORY_CODE=YOUR_CATEGORY_CODE\n```\n\n```typescript\nimport {\n  DescribeCreateCaseOptionsCommand,\n  DescribeSupportedLanguagesCommand,\n  SupportClient,\n} from \"@aws-sdk/client-support\";\n\nconst serviceCode = process.env.AWS_SUPPORT_SERVICE_CODE;\nconst categoryCode = process.env.AWS_SUPPORT_CATEGORY_CODE;\n\nif (!serviceCode || !categoryCode) {\n  throw new Error(\"Set AWS_SUPPORT_SERVICE_CODE and AWS_SUPPORT_CATEGORY_CODE.\");\n}\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst supportedLanguages = await client.send(\n  new DescribeSupportedLanguagesCommand({\n    issueType: \"technical\",\n    serviceCode,\n    categoryCode,\n  }),\n);\n\nconst createCaseOptions = await client.send(\n  new DescribeCreateCaseOptionsCommand({\n    issueType: \"technical\",\n    serviceCode,\n    categoryCode,\n    language: \"en\",\n  }),\n);\n\nconsole.dir(supportedLanguages.supportedLanguages, { depth: null });\nconsole.log(createCaseOptions.languageAvailability);\nconsole.dir(createCaseOptions.communicationTypes, { depth: null });\n```\n\nSupported case languages are ISO 639-1 codes. AWS Support documents `en`, `zh`, `ja`, and `ko`.\n\n## Create a support case\n\nFirst discover the codes you want to use, then pass those exact values into `CreateCaseCommand`.\n\n```bash\nexport AWS_SUPPORT_SERVICE_CODE=YOUR_SERVICE_CODE\nexport AWS_SUPPORT_CATEGORY_CODE=YOUR_CATEGORY_CODE\nexport AWS_SUPPORT_SEVERITY_CODE=YOUR_SEVERITY_CODE\n```\n\n```typescript\nimport { CreateCaseCommand, SupportClient } from \"@aws-sdk/client-support\";\n\nconst serviceCode = process.env.AWS_SUPPORT_SERVICE_CODE;\nconst categoryCode = process.env.AWS_SUPPORT_CATEGORY_CODE;\nconst severityCode = process.env.AWS_SUPPORT_SEVERITY_CODE;\n\nif (!serviceCode || !categoryCode || !severityCode) {\n  throw new Error(\n    \"Set AWS_SUPPORT_SERVICE_CODE, AWS_SUPPORT_CATEGORY_CODE, and AWS_SUPPORT_SEVERITY_CODE.\",\n  );\n}\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new CreateCaseCommand({\n    subject: \"Production API returns intermittent 5xx\",\n    serviceCode,\n    categoryCode,\n    severityCode,\n    communicationBody: [\n      \"Impact: 12% of requests fail.\",\n      \"Start time: 2026-03-13T14:10:00Z.\",\n      \"Primary region: us-east-1.\",\n      \"Recent change: deployed build 2026.03.13.1.\",\n    ].join(\"\\n\"),\n    issueType: \"technical\",\n    language: \"en\",\n    ccEmailAddresses: [\"oncall@example.com\"],\n  }),\n);\n\nconsole.log(response.caseId);\n```\n\n`CreateCase` does not support service limit increase requests. Use the Support Center UI or Service Quotas for those workflows.\n\n## Add attachments\n\nAttachments are uploaded to a temporary attachment set, then attached to a new case or a follow-up communication. Attachment sets expire after 1 hour. You can add up to three attachments per set, and each attachment is limited to 5 MB.\n\n```typescript\nimport {\n  AddAttachmentsToSetCommand,\n  CreateCaseCommand,\n  SupportClient,\n} from \"@aws-sdk/client-support\";\nimport { readFile } from \"node:fs/promises\";\n\nconst serviceCode = process.env.AWS_SUPPORT_SERVICE_CODE;\nconst categoryCode = process.env.AWS_SUPPORT_CATEGORY_CODE;\nconst severityCode = process.env.AWS_SUPPORT_SEVERITY_CODE;\n\nif (!serviceCode || !categoryCode || !severityCode) {\n  throw new Error(\n    \"Set AWS_SUPPORT_SERVICE_CODE, AWS_SUPPORT_CATEGORY_CODE, and AWS_SUPPORT_SEVERITY_CODE.\",\n  );\n}\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst screenshot = await readFile(\"./support-screenshot.png\");\n\nconst attachmentSet = await client.send(\n  new AddAttachmentsToSetCommand({\n    attachments: [\n      {\n        fileName: \"support-screenshot.png\",\n        data: screenshot,\n      },\n    ],\n  }),\n);\n\nconst createdCase = await client.send(\n  new CreateCaseCommand({\n    subject: \"Production API returns intermittent 5xx\",\n    serviceCode,\n    categoryCode,\n    severityCode,\n    communicationBody: \"Attached a screenshot and example request IDs.\",\n    issueType: \"technical\",\n    language: \"en\",\n    attachmentSetId: attachmentSet.attachmentSetId,\n  }),\n);\n\nconsole.log({\n  caseId: createdCase.caseId,\n  attachmentSetId: attachmentSet.attachmentSetId,\n  expiryTime: attachmentSet.expiryTime,\n});\n```\n\n## Add a follow-up communication to an existing case\n\n```bash\nexport AWS_SUPPORT_CASE_ID=YOUR_CASE_ID\n```\n\n```typescript\nimport {\n  AddCommunicationToCaseCommand,\n  SupportClient,\n} from \"@aws-sdk/client-support\";\n\nconst caseId = process.env.AWS_SUPPORT_CASE_ID;\n\nif (!caseId) {\n  throw new Error(\"Set AWS_SUPPORT_CASE_ID.\");\n}\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new AddCommunicationToCaseCommand({\n    caseId,\n    communicationBody: [\n      \"New details:\",\n      \"- Example request ID: 1234567890abcdef\",\n      \"- Issue still reproduces after rollback\",\n      \"- Attached logs in the previous update\",\n    ].join(\"\\n\"),\n    ccEmailAddresses: [\"oncall@example.com\"],\n  }),\n);\n\nconsole.log(response.result);\n```\n\nIf you want to attach files to the follow-up message, call `AddAttachmentsToSetCommand` first and pass the returned `attachmentSetId` into `AddCommunicationToCaseCommand`.\n\n## List cases and read case communications\n\n`DescribeCasesCommand` returns case details and paginates with `nextToken`. Case data is available for 12 months after creation.\n\n```typescript\nimport {\n  DescribeCasesCommand,\n  DescribeCommunicationsCommand,\n  SupportClient,\n} from \"@aws-sdk/client-support\";\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst casesResponse = await client.send(\n  new DescribeCasesCommand({\n    includeResolvedCases: false,\n    includeCommunications: true,\n    language: \"en\",\n    maxResults: 20,\n  }),\n);\n\nfor (const supportCase of casesResponse.cases ?? []) {\n  console.log({\n    caseId: supportCase.caseId,\n    displayId: supportCase.displayId,\n    status: supportCase.status,\n    subject: supportCase.subject,\n    serviceCode: supportCase.serviceCode,\n    recentCommunicationCount:\n      supportCase.recentCommunications?.communications?.length ?? 0,\n  });\n}\n\nconst caseId = process.env.AWS_SUPPORT_CASE_ID;\n\nif (caseId) {\n  const communicationsResponse = await client.send(\n    new DescribeCommunicationsCommand({\n      caseId,\n      maxResults: 20,\n    }),\n  );\n\n  console.dir(communicationsResponse.communications, { depth: null });\n}\n```\n\n## Resolve a case\n\n```typescript\nimport { ResolveCaseCommand, SupportClient } from \"@aws-sdk/client-support\";\n\nconst caseId = process.env.AWS_SUPPORT_CASE_ID;\n\nif (!caseId) {\n  throw new Error(\"Set AWS_SUPPORT_CASE_ID.\");\n}\n\nconst client = new SupportClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ResolveCaseCommand({\n    caseId,\n  }),\n);\n\nconsole.log({\n  initialCaseStatus: response.initialCaseStatus,\n  finalCaseStatus: response.finalCaseStatus,\n});\n```\n\n## Important details\n\n- The Support API is only available for Business, Enterprise On-Ramp, and Enterprise Support plans.\n- Use `DescribeServices` and `DescribeSeverityLevels` to get the exact codes for `CreateCase`; console labels and API codes do not always match.\n- `CreateCase` does not support service limit increase requests.\n- Attachment sets expire after 1 hour, allow up to three attachments, and each attachment is limited to 5 MB.\n- `DescribeCases` and `DescribeCommunications` return paginated results with `nextToken`.\n- Case data and communications are only available for 12 months after creation.\n"
  },
  {
    "path": "content/aws/docs/textract/javascript/DOC.md",
    "content": "---\nname: textract\ndescription: \"AWS SDK for JavaScript v3 Textract client for OCR, form and table analysis, and asynchronous document-processing jobs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,textract,javascript,nodejs,ocr,documents,forms,tables\"\n---\n\n# `@aws-sdk/client-textract`\n\nUse this package for Amazon Textract operations in AWS SDK for JavaScript v3. It covers synchronous text extraction, form and table analysis, specialized expense and identity-document APIs, and asynchronous document jobs for files stored in S3.\n\nTextract is a low-level API surface. Most useful responses come back as `Blocks` plus relationships between those blocks, not as a prebuilt plain-text or form-object model.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-textract\n```\n\nIf you need to force a named shared-credentials profile in code instead of relying on the default AWS provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-textract@3.1007.0`.\n\n## Prerequisites And Authentication\n\nTextract calls need normal AWS credentials plus a region. In Node.js, the SDK can usually resolve credentials from the default provider chain, including environment variables, shared AWS config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\nexport AWS_TEXTRACT_BUCKET=incoming-documents\nexport AWS_TEXTRACT_SNS_TOPIC_ARN=arn:aws:sns:us-east-1:123456789012:textract-jobs\nexport AWS_TEXTRACT_ROLE_ARN=arn:aws:iam::123456789012:role/TextractPublishToSNS\n```\n\nMinimal client setup:\n\n```javascript\nimport { TextractClient } from \"@aws-sdk/client-textract\";\n\nconst textract = new TextractClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { TextractClient } from \"@aws-sdk/client-textract\";\n\nconst textract = new TextractClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nFor browser applications, do not embed long-lived AWS access keys. Textract is usually called from trusted backend code or behind a federation flow with tightly scoped temporary credentials.\n\n## Request Shapes You Need To Get Right\n\n- Synchronous operations such as `DetectDocumentTextCommand` and `AnalyzeDocumentCommand` use `Document`.\n- Asynchronous start operations such as `StartDocumentTextDetectionCommand` and `StartDocumentAnalysisCommand` use `DocumentLocation`.\n- In Node.js, pass a `Buffer` or other `Uint8Array` to `Bytes`. Do not base64-encode the payload yourself before sending it through the SDK.\n- Asynchronous document jobs take an S3 object location, not raw local bytes.\n\n## Detect Text From A Local Image\n\nUse `DetectDocumentTextCommand` when you want OCR output without form or table analysis.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport {\n  DetectDocumentTextCommand,\n  TextractClient,\n} from \"@aws-sdk/client-textract\";\n\nconst textract = new TextractClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst imageBytes = await readFile(\"./example.png\");\n\nconst { Blocks } = await textract.send(\n  new DetectDocumentTextCommand({\n    Document: {\n      Bytes: imageBytes,\n    },\n  }),\n);\n\nconst lines = (Blocks ?? [])\n  .filter((block) => block.BlockType === \"LINE\" && block.Text)\n  .map((block) => block.Text);\n\nconsole.log(lines.join(\"\\n\"));\n```\n\nIf the document is already in S3, you can use `Document.S3Object` instead of `Document.Bytes`.\n\n## Analyze Forms And Tables\n\nUse `AnalyzeDocumentCommand` when you need form fields or table structure instead of OCR alone.\n\n```javascript\nimport {\n  AnalyzeDocumentCommand,\n  TextractClient,\n} from \"@aws-sdk/client-textract\";\n\nconst textract = new TextractClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Blocks } = await textract.send(\n  new AnalyzeDocumentCommand({\n    Document: {\n      S3Object: {\n        Bucket: process.env.AWS_TEXTRACT_BUCKET,\n        Name: \"forms/application.png\",\n      },\n    },\n    FeatureTypes: [\"FORMS\", \"TABLES\"],\n  }),\n);\n\nconst keyValueBlocks = (Blocks ?? []).filter(\n  (block) => block.BlockType === \"KEY_VALUE_SET\",\n);\nconst tableBlocks = (Blocks ?? []).filter(\n  (block) => block.BlockType === \"TABLE\",\n);\n\nconsole.log({\n  keyValueBlocks: keyValueBlocks.length,\n  tableBlocks: tableBlocks.length,\n});\n```\n\n`FeatureTypes` is the switch that tells Textract which analysis features to run. If you only want plain OCR, use `DetectDocumentText` instead.\n\n## Run An Asynchronous Document Job\n\nUse the asynchronous start/get pairs for S3-based workflows where you do not want to block on a single synchronous response.\n\nThis example starts a text-detection job for an S3 document, then polls until the job succeeds and paginates through all result pages.\n\n```javascript\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport {\n  GetDocumentTextDetectionCommand,\n  StartDocumentTextDetectionCommand,\n  TextractClient,\n} from \"@aws-sdk/client-textract\";\n\nconst textract = new TextractClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst start = await textract.send(\n  new StartDocumentTextDetectionCommand({\n    DocumentLocation: {\n      S3Object: {\n        Bucket: process.env.AWS_TEXTRACT_BUCKET,\n        Name: \"incoming/report.pdf\",\n      },\n    },\n    NotificationChannel: {\n      RoleArn: process.env.AWS_TEXTRACT_ROLE_ARN,\n      SNSTopicArn: process.env.AWS_TEXTRACT_SNS_TOPIC_ARN,\n    },\n  }),\n);\n\nif (!start.JobId) {\n  throw new Error(\"Textract did not return a JobId\");\n}\n\nconst allBlocks = [];\nlet nextToken;\n\nwhile (true) {\n  const page = await textract.send(\n    new GetDocumentTextDetectionCommand({\n      JobId: start.JobId,\n      NextToken: nextToken,\n    }),\n  );\n\n  if (page.JobStatus === \"FAILED\") {\n    throw new Error(page.StatusMessage ?? \"Textract job failed\");\n  }\n\n  if (page.JobStatus !== \"SUCCEEDED\") {\n    await delay(5000);\n    continue;\n  }\n\n  allBlocks.push(...(page.Blocks ?? []));\n\n  if (!page.NextToken) {\n    break;\n  }\n\n  nextToken = page.NextToken;\n}\n\nconst lines = allBlocks\n  .filter((block) => block.BlockType === \"LINE\" && block.Text)\n  .map((block) => block.Text);\n\nconsole.log(lines.join(\"\\n\"));\n```\n\nThe start operation and get operation must match:\n\n- `StartDocumentTextDetectionCommand` ↔ `GetDocumentTextDetectionCommand`\n- `StartDocumentAnalysisCommand` ↔ `GetDocumentAnalysisCommand`\n\nIf you need asynchronous form or table analysis instead of OCR only, use the analysis pair and pass `FeatureTypes` to the start command.\n\n## Other High-Value Operations\n\n- `AnalyzeExpenseCommand`: specialized extraction for receipts and invoices.\n- `AnalyzeIDCommand`: specialized extraction for identity documents.\n- `StartDocumentAnalysisCommand`: asynchronous analysis for S3 documents when you need the same block graph as `AnalyzeDocument` without a single synchronous request.\n\nChoose the narrowest operation that matches your workload. Expense and ID APIs return more task-specific structures than generic block analysis.\n\n## Textract-Specific Gotchas\n\n- `Blocks` is a graph, not a finished document model. Real form extraction often means following block relationships instead of reading only `LINE` text.\n- `Document` and `DocumentLocation` are different request shapes. The synchronous and asynchronous APIs do not use the same input field names.\n- `FeatureTypes` belongs on document-analysis operations, not on plain text-detection calls.\n- Asynchronous result APIs paginate with `NextToken`. Keep fetching until the token is absent.\n- The `NotificationChannel` role for asynchronous jobs must allow Textract to publish to the SNS topic you provide.\n- `Bytes` should be raw binary data in the SDK request. Do not pre-encode it as a base64 string unless you are calling the raw HTTP API yourself.\n- Keep the client region explicit. Credential resolution can succeed while the request still fails because you are talking to the wrong regional endpoint for your workload.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-textract@3.1007.0`.\n- The AWS JavaScript SDK service documentation is published under a rolling `latest` URL. Use the installed npm version for pinning and the AWS docs for operation names and request/response shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Textract client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/textract/`\n- Amazon Textract `DetectDocumentText` API reference: `https://docs.aws.amazon.com/textract/latest/dg/API_DetectDocumentText.html`\n- Amazon Textract `AnalyzeDocument` API reference: `https://docs.aws.amazon.com/textract/latest/dg/API_AnalyzeDocument.html`\n- Amazon Textract `StartDocumentTextDetection` API reference: `https://docs.aws.amazon.com/textract/latest/dg/API_StartDocumentTextDetection.html`\n- Amazon Textract `GetDocumentTextDetection` API reference: `https://docs.aws.amazon.com/textract/latest/dg/API_GetDocumentTextDetection.html`\n"
  },
  {
    "path": "content/aws/docs/timestream-query/javascript/DOC.md",
    "content": "---\nname: timestream-query\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Timestream query operations, including SQL execution, pagination, query cancellation, and endpoint inspection.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,timestream,javascript,nodejs,time-series,sql,query\"\n---\n\n# `@aws-sdk/client-timestream-query`\n\nUse this package for Amazon Timestream for LiveAnalytics query-plane operations in AWS SDK for JavaScript v3. The common workflow is: send SQL with `QueryCommand`, read `Rows` and `ColumnInfo` from the response, follow `NextToken` until the result set is complete, and optionally cancel the query with `CancelQueryCommand` if you no longer need it.\n\nThis package does not create databases, tables, or ingest records. For write-plane operations, use `@aws-sdk/client-timestream-write`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-timestream-query\n```\n\nIf you want to force a named shared AWS profile in code instead of relying on the default credential chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-timestream-query@3.1007.0`.\n\n## Prerequisites And Authentication\n\nTimestream query calls need AWS credentials and a region. In Node.js, AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\nexport AWS_TIMESTREAM_DATABASE=metrics\nexport AWS_TIMESTREAM_TABLE=cpu_utilization\n```\n\nMinimal client setup:\n\n```javascript\nimport { TimestreamQueryClient } from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { TimestreamQueryClient } from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nFor browser applications, do not embed long-lived AWS access keys. Call Timestream from trusted backend code or use tightly scoped temporary credentials.\n\n## Run A Query And Read Scalar Rows\n\n`QueryCommand` sends SQL and returns the first page of results directly. For Timestream single-measure tables, a common pattern is to filter by `measure_name` and cast `measure_value` to the type you stored.\n\n```javascript\nimport {\n  QueryCommand,\n  TimestreamQueryClient,\n} from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst database = process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\";\nconst table = process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\";\n\nconst result = await timestreamQuery.send(\n  new QueryCommand({\n    QueryString: `\n      SELECT time, host, measure_value::double AS cpu\n      FROM \"${database}\".\"${table}\"\n      WHERE measure_name = 'cpu'\n        AND time > ago(1h)\n      ORDER BY time DESC\n      LIMIT 10\n    `,\n    MaxRows: 10,\n  }),\n);\n\nconst columnNames = result.ColumnInfo?.map((column) => column.Name ?? \"\") ?? [];\n\nconst rows = (result.Rows ?? []).map((row) => {\n  return Object.fromEntries(\n    columnNames.map((name, index) => {\n      const cell = row.Data?.[index];\n      return [name, cell?.NullValue ? null : cell?.ScalarValue ?? null];\n    }),\n  );\n});\n\nconsole.log(rows);\nconsole.log(result.QueryId);\nconsole.log(result.NextToken);\n```\n\nThe simple row-mapping example above is only for scalar columns. If your query returns arrays, nested rows, or time-series values, inspect `ArrayValue`, `RowValue`, or `TimeSeriesValue` in each cell instead of reading only `ScalarValue`.\n\n## Read Every Page With `NextToken`\n\nA successful `QueryCommand` can still be only the first page. If the response includes `NextToken`, send another `QueryCommand` with the same SQL and that token until `NextToken` is absent.\n\n```javascript\nimport {\n  QueryCommand,\n  TimestreamQueryClient,\n} from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function queryAllPages(queryString) {\n  const pages = [];\n  let nextToken;\n\n  do {\n    const page = await timestreamQuery.send(\n      new QueryCommand({\n        QueryString: queryString,\n        NextToken: nextToken,\n        MaxRows: 100,\n      }),\n    );\n\n    pages.push(page);\n    nextToken = page.NextToken;\n  } while (nextToken);\n\n  return pages;\n}\n\nconst pages = await queryAllPages(`\n  SELECT time, host, measure_value::double AS cpu\n  FROM \"${process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\"}\".\"${process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\"}\"\n  WHERE measure_name = 'cpu'\n    AND time > ago(24h)\n  ORDER BY time DESC\n`);\n\nconst allRows = pages.flatMap((page) => page.Rows ?? []);\nconsole.log(allRows.length);\n```\n\nKeep the SQL text stable while following a pagination token. Treat `NextToken` as part of the same query execution rather than as a fresh request.\n\n## Cancel A Query\n\nIf you keep the `QueryId` from a prior response and later decide the work is no longer needed, call `CancelQueryCommand`.\n\n```javascript\nimport {\n  CancelQueryCommand,\n  QueryCommand,\n  TimestreamQueryClient,\n} from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst firstPage = await timestreamQuery.send(\n  new QueryCommand({\n    QueryString: `\n      SELECT time, host, measure_value::double AS cpu\n      FROM \"metrics\".\"cpu_utilization\"\n      WHERE measure_name = 'cpu'\n      ORDER BY time DESC\n    `,\n    MaxRows: 100,\n  }),\n);\n\nif (firstPage.QueryId) {\n  await timestreamQuery.send(\n    new CancelQueryCommand({\n      QueryId: firstPage.QueryId,\n    }),\n  );\n}\n```\n\nCancellation is most useful when the first response gave you a `QueryId` but the application no longer wants the remaining work or pages.\n\n## Prepare A Query Before Saving Or Running It\n\nUse `PrepareQueryCommand` when you want the service to validate a SQL statement before you persist it or run it in a broader workflow.\n\n```javascript\nimport {\n  PrepareQueryCommand,\n  TimestreamQueryClient,\n} from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst prepared = await timestreamQuery.send(\n  new PrepareQueryCommand({\n    QueryString: `\n      SELECT time, host, measure_value::double AS cpu\n      FROM \"metrics\".\"cpu_utilization\"\n      WHERE measure_name = 'cpu'\n        AND time > ago(15m)\n      ORDER BY time DESC\n      LIMIT 20\n    `,\n  }),\n);\n\nconsole.dir(prepared, { depth: null });\n```\n\n## Inspect The Resolved Query Endpoint\n\nAWS documents endpoint discovery for Timestream. In normal SDK usage you usually do not need to call `DescribeEndpointsCommand` yourself, but it is useful for debugging or custom endpoint caching.\n\n```javascript\nimport {\n  DescribeEndpointsCommand,\n  TimestreamQueryClient,\n} from \"@aws-sdk/client-timestream-query\";\n\nconst timestreamQuery = new TimestreamQueryClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Endpoints } = await timestreamQuery.send(\n  new DescribeEndpointsCommand({})\n);\n\nconst endpoint = Endpoints?.[0];\n\nconsole.log(endpoint?.Address);\nconsole.log(endpoint?.CachePeriodInMinutes);\n```\n\nIf you cache endpoints or override the service endpoint manually, respect the returned cache period and keep the region aligned with the target Timestream resources.\n\n## Common Pitfalls\n\n- Using this client for ingestion. Record writes and table management are in `@aws-sdk/client-timestream-write`.\n- Assuming one `QueryCommand` response contains the entire result set. Follow `NextToken` until it disappears.\n- Treating `Rows` as plain objects. Timestream returns cells under `Rows[].Data[]`, with type information in `ColumnInfo`.\n- Reading only `ScalarValue` when the query returns arrays, nested rows, or time-series values.\n- Hardcoding long-lived AWS keys in frontend code.\n- Overriding endpoints without respecting the endpoint-discovery cache period.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-timestream-query@3.1007.0`.\n- The AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Pin the npm package version in your app when exact patch-level parity matters.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Timestream Query client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/timestream-query/`\n- Amazon Timestream `Query` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_query_Query.html`\n- Amazon Timestream `CancelQuery` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_query_CancelQuery.html`\n- Amazon Timestream `PrepareQuery` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_query_PrepareQuery.html`\n- Amazon Timestream `DescribeEndpoints` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_DescribeEndpoints.html`\n- Amazon Timestream endpoint-discovery guide: `https://docs.aws.amazon.com/timestream/latest/developerguide/Using-API.endpoint-discovery.describe-endpoints.implementation.html`\n"
  },
  {
    "path": "content/aws/docs/timestream-write/javascript/DOC.md",
    "content": "---\nname: timestream-write\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Timestream write operations, including table setup, record ingestion, and batch-load tasks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,timestream,javascript,nodejs,time-series,metrics\"\n---\n\n# `@aws-sdk/client-timestream-write`\n\nUse this package for Amazon Timestream for LiveAnalytics write-plane operations in AWS SDK for JavaScript v3. It covers database and table management, ingestion with `WriteRecords`, endpoint inspection with `DescribeEndpoints`, and bulk imports with batch-load tasks.\n\nThis package does not run queries. For SQL reads, use `@aws-sdk/client-timestream-query`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-timestream-write\n```\n\nIf you want to pin a shared AWS profile explicitly in code instead of relying on the default credential provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-timestream-write@3.1007.0`.\n\n## Prerequisites And Authentication\n\nTimestream write calls need normal AWS credentials and a region. In Node.js, the AWS SDK v3 can usually resolve credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\nexport AWS_TIMESTREAM_DATABASE=metrics\nexport AWS_TIMESTREAM_TABLE=cpu_utilization\nexport AWS_TIMESTREAM_IMPORT_BUCKET=my-import-bucket\n```\n\nMinimal client setup:\n\n```javascript\nimport { TimestreamWriteClient } from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to force a named shared profile in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { TimestreamWriteClient } from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nFor browser applications, do not embed long-lived AWS access keys. Call Timestream from trusted backend code or use tightly scoped temporary credentials.\n\n## Create A Database And Table\n\nCreate the database once, then create a table with explicit retention settings.\n\n```javascript\nimport {\n  CreateDatabaseCommand,\n  CreateTableCommand,\n  TimestreamWriteClient,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait timestreamWrite.send(\n  new CreateDatabaseCommand({\n    DatabaseName: process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\",\n  })\n);\n\nawait timestreamWrite.send(\n  new CreateTableCommand({\n    DatabaseName: process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\",\n    TableName: process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\",\n    RetentionProperties: {\n      MemoryStoreRetentionPeriodInHours: 24,\n      MagneticStoreRetentionPeriodInDays: 365,\n    },\n  })\n);\n```\n\nUse the same AWS region for the client and the target Timestream resources.\n\n## Write Single-Measure Records\n\n`WriteRecordsCommand` is the core ingestion API. A practical pattern is to put repeated dimensions and measure metadata in `CommonAttributes`, then send the time-stamped values in `Records`.\n\nTimestream measure values are strings on the wire even when the logical type is numeric.\n\n```javascript\nimport {\n  TimestreamWriteClient,\n  WriteRecordsCommand,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await timestreamWrite.send(\n  new WriteRecordsCommand({\n    DatabaseName: process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\",\n    TableName: process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\",\n    CommonAttributes: {\n      Dimensions: [\n        { Name: \"host\", Value: \"web-1\" },\n        { Name: \"region\", Value: \"us-east-1\" },\n      ],\n      MeasureName: \"cpu\",\n      MeasureValueType: \"DOUBLE\",\n      TimeUnit: \"SECONDS\",\n    },\n    Records: [\n      { Time: \"1731456000\", MeasureValue: \"18.25\" },\n      { Time: \"1731456060\", MeasureValue: \"19.75\" },\n    ],\n  })\n);\n\nconsole.log(response.RecordsIngested?.Total);\n```\n\nImportant write rules from the AWS API docs:\n\n- `CommonAttributes.Dimensions` must not overlap with dimensions on individual records.\n- If you update an existing record, you must send a higher `Version`.\n\n## Write A Multi-Measure Record\n\nUse `MeasureValueType: \"MULTI\"` when a single timestamp should carry multiple named metrics.\n\n```javascript\nimport {\n  TimestreamWriteClient,\n  WriteRecordsCommand,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait timestreamWrite.send(\n  new WriteRecordsCommand({\n    DatabaseName: process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\",\n    TableName: process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\",\n    CommonAttributes: {\n      Dimensions: [{ Name: \"host\", Value: \"web-1\" }],\n      TimeUnit: \"MILLISECONDS\",\n    },\n    Records: [\n      {\n        Time: `${Date.now()}`,\n        MeasureName: \"server_metrics\",\n        MeasureValueType: \"MULTI\",\n        MeasureValues: [\n          { Name: \"cpu\", Value: \"18.25\", Type: \"DOUBLE\" },\n          { Name: \"memory\", Value: \"61.4\", Type: \"DOUBLE\" },\n          { Name: \"healthy\", Value: \"true\", Type: \"BOOLEAN\" },\n        ],\n      },\n    ],\n  })\n);\n```\n\n## Update An Existing Record With `Version`\n\nWhen you rewrite the same logical record, increase `Version`. If you send the same record without a higher version, Timestream can reject it with `RejectedRecordsException`.\n\n```javascript\nimport {\n  TimestreamWriteClient,\n  WriteRecordsCommand,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait timestreamWrite.send(\n  new WriteRecordsCommand({\n    DatabaseName: \"metrics\",\n    TableName: \"cpu_utilization\",\n    Records: [\n      {\n        Dimensions: [{ Name: \"host\", Value: \"web-1\" }],\n        Time: \"1731456000\",\n        TimeUnit: \"SECONDS\",\n        MeasureName: \"cpu\",\n        MeasureValue: \"21.5\",\n        MeasureValueType: \"DOUBLE\",\n        Version: 2,\n      },\n    ],\n  })\n);\n```\n\n## Start A Batch-Load Task From S3\n\nUse batch load for larger backfills instead of pushing many individual `WriteRecords` calls. The batch-load API needs both an S3 source location and an S3 report location.\n\n```javascript\nimport {\n  CreateBatchLoadTaskCommand,\n  DescribeBatchLoadTaskCommand,\n  TimestreamWriteClient,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { TaskId } = await timestreamWrite.send(\n  new CreateBatchLoadTaskCommand({\n    DataModelConfiguration: {\n      DataModel: {\n        TimeColumn: \"time\",\n        TimeUnit: \"MILLISECONDS\",\n        DimensionMappings: [\n          {\n            SourceColumn: \"host\",\n            DestinationColumn: \"host\",\n          },\n        ],\n        MultiMeasureMappings: {\n          TargetMultiMeasureName: \"metrics\",\n          MultiMeasureAttributeMappings: [\n            {\n              SourceColumn: \"cpu\",\n              TargetMultiMeasureAttributeName: \"cpu\",\n              MeasureValueType: \"DOUBLE\",\n            },\n            {\n              SourceColumn: \"memory\",\n              TargetMultiMeasureAttributeName: \"memory\",\n              MeasureValueType: \"DOUBLE\",\n            },\n          ],\n        },\n      },\n    },\n    DataSourceConfiguration: {\n      DataSourceS3Configuration: {\n        BucketName: process.env.AWS_TIMESTREAM_IMPORT_BUCKET ?? \"my-import-bucket\",\n        ObjectKeyPrefix: \"timestream/cpu/\",\n      },\n      CsvConfiguration: {\n        ColumnSeparator: \",\",\n      },\n      DataFormat: \"CSV\",\n    },\n    ReportConfiguration: {\n      ReportS3Configuration: {\n        BucketName: process.env.AWS_TIMESTREAM_IMPORT_BUCKET ?? \"my-import-bucket\",\n        ObjectKeyPrefix: \"timestream/reports/\",\n      },\n    },\n    TargetDatabaseName: process.env.AWS_TIMESTREAM_DATABASE ?? \"metrics\",\n    TargetTableName: process.env.AWS_TIMESTREAM_TABLE ?? \"cpu_utilization\",\n  })\n);\n\nconst status = await timestreamWrite.send(\n  new DescribeBatchLoadTaskCommand({ TaskId })\n);\n\nconsole.log(status.BatchLoadTaskDescription?.TaskStatus);\n```\n\nBatch-load tasks are asynchronous. Poll `DescribeBatchLoadTaskCommand` or list tasks separately; do not assume the import finishes before `CreateBatchLoadTaskCommand` returns.\n\n## Inspect The Resolved Ingestion Endpoint\n\nAWS documents endpoint discovery for Timestream. In normal SDK usage you usually do not need to call `DescribeEndpointsCommand` yourself, but it is useful for debugging or custom endpoint caching.\n\n```javascript\nimport {\n  DescribeEndpointsCommand,\n  TimestreamWriteClient,\n} from \"@aws-sdk/client-timestream-write\";\n\nconst timestreamWrite = new TimestreamWriteClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { Endpoints } = await timestreamWrite.send(\n  new DescribeEndpointsCommand({})\n);\n\nconst endpoint = Endpoints?.[0];\n\nconsole.log(endpoint?.Address);\nconsole.log(endpoint?.CachePeriodInMinutes);\n```\n\nIf you cache endpoints or override the service endpoint manually, respect the returned cache period and keep the region aligned with the destination database and table.\n\n## Common Pitfalls\n\n- Using this client for queries. Query operations are in `@aws-sdk/client-timestream-query`.\n- Sending numeric or boolean measure values without converting them to strings.\n- Repeating the same dimension name in both `CommonAttributes` and an individual record.\n- Rewriting an existing record without increasing `Version`.\n- Treating batch load as synchronous instead of monitoring task status and the S3 report output.\n- Hardcoding long-lived AWS keys in frontend code.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-timestream-write@3.1007.0`.\n- The AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Pin the npm package version in your app when exact patch-level parity matters.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Timestream Write client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/timestream-write/`\n- Amazon Timestream `WriteRecords` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_WriteRecords.html`\n- Amazon Timestream `CreateTable` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_CreateTable.html`\n- Amazon Timestream `CreateBatchLoadTask` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_CreateBatchLoadTask.html`\n- Amazon Timestream `DescribeBatchLoadTask` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_DescribeBatchLoadTask.html`\n- Amazon Timestream `DescribeEndpoints` API reference: `https://docs.aws.amazon.com/timestream/latest/developerguide/API_DescribeEndpoints.html`\n- Amazon Timestream endpoint-discovery guide: `https://docs.aws.amazon.com/timestream/latest/developerguide/Using-API.endpoint-discovery.describe-endpoints.implementation.html`\n"
  },
  {
    "path": "content/aws/docs/transcribe/javascript/DOC.md",
    "content": "---\nname: transcribe\ndescription: \"AWS SDK for JavaScript v3 Transcribe client for Amazon Transcribe batch transcription jobs and custom vocabularies.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,transcribe,javascript,nodejs,speech-to-text,audio,s3\"\n---\n\n# `@aws-sdk/client-transcribe`\n\nUse this package for Amazon Transcribe batch jobs and service-management operations in AWS SDK for JavaScript v3. The most common workflow is: put media in S3, start a transcription job, poll `GetTranscriptionJob`, then read the transcript from the returned transcript URI.\n\nThis package is for asynchronous Transcribe APIs. For live streaming transcription, use `@aws-sdk/client-transcribe-streaming` instead.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-transcribe\n```\n\nIf you want to force a named shared-credentials profile in code instead of relying on the default AWS provider chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nThis guide targets `@aws-sdk/client-transcribe@3.1007.0`.\n\n## Prerequisites And Authentication\n\nTranscribe requests need AWS credentials and a region. In Node.js, the AWS SDK v3 usually resolves credentials from the default provider chain, including environment variables, shared config files, IAM Identity Center, ECS task roles, and EC2 instance profiles.\n\nTypical local setup:\n\n```bash\nexport AWS_PROFILE=dev\nexport AWS_REGION=us-east-1\n\nexport AWS_TRANSCRIBE_MEDIA_URI=s3://my-input-bucket/audio/support-call.mp3\nexport AWS_TRANSCRIBE_VOCABULARY=support-terms\n```\n\nBatch transcription jobs typically read media from S3 with `Media.MediaFileUri`.\n\nMinimal client setup:\n\n```javascript\nimport { TranscribeClient } from \"@aws-sdk/client-transcribe\";\n\nconst transcribe = new TranscribeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to pin a shared profile explicitly in code:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { TranscribeClient } from \"@aws-sdk/client-transcribe\";\n\nconst transcribe = new TranscribeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({ profile: process.env.AWS_PROFILE ?? \"dev\" }),\n});\n```\n\nFor browser applications, do not embed long-lived AWS access keys. Transcribe is usually called from trusted backend code or through tightly scoped temporary credentials.\n\n## Start A Batch Transcription Job\n\nUse `StartTranscriptionJobCommand` for standard asynchronous transcription. A job needs a unique `TranscriptionJobName`, a media URI, a matching `MediaFormat`, and exactly one language selector.\n\n```javascript\nimport {\n  StartTranscriptionJobCommand,\n  TranscribeClient,\n} from \"@aws-sdk/client-transcribe\";\n\nconst transcribe = new TranscribeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst jobName = `support-call-${Date.now()}`;\n\nconst response = await transcribe.send(\n  new StartTranscriptionJobCommand({\n    TranscriptionJobName: jobName,\n    LanguageCode: \"en-US\",\n    MediaFormat: \"mp3\",\n    Media: {\n      MediaFileUri: process.env.AWS_TRANSCRIBE_MEDIA_URI,\n    },\n    ...(process.env.AWS_TRANSCRIBE_VOCABULARY\n      ? {\n          Settings: {\n            VocabularyName: process.env.AWS_TRANSCRIBE_VOCABULARY,\n          },\n        }\n      : {}),\n  }),\n);\n\nconsole.log(response.TranscriptionJob?.TranscriptionJobName ?? jobName);\nconsole.log(response.TranscriptionJob?.TranscriptionJobStatus ?? \"QUEUED\");\n```\n\nLanguage selection rules:\n\n- Use `LanguageCode` when you already know the language.\n- Use `IdentifyLanguage: true` when the language is unknown.\n- Use `IdentifyMultipleLanguages: true` only for multi-language audio.\n- Do not send more than one of those options in the same request.\n\nIf you want automatic language identification instead of a fixed language code, change the request like this:\n\n```javascript\nconst response = await transcribe.send(\n  new StartTranscriptionJobCommand({\n    TranscriptionJobName: `support-call-${Date.now()}`,\n    IdentifyLanguage: true,\n    MediaFormat: \"mp3\",\n    Media: {\n      MediaFileUri: process.env.AWS_TRANSCRIBE_MEDIA_URI,\n    },\n  }),\n);\n```\n\n## Poll For Completion And Read The Transcript\n\n`StartTranscriptionJobCommand` only queues the work. Use `GetTranscriptionJobCommand` to check `TranscriptionJobStatus`, inspect `FailureReason`, and read `Transcript.TranscriptFileUri` after the job completes.\n\nThese examples assume Node.js 18+ so `fetch` is available globally.\n\n```javascript\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport {\n  GetTranscriptionJobCommand,\n  TranscribeClient,\n} from \"@aws-sdk/client-transcribe\";\n\nconst transcribe = new TranscribeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst jobName = process.argv[2];\n\nif (!jobName) {\n  throw new Error(\"Pass the transcription job name as the first argument\");\n}\n\nlet transcriptUri;\n\nwhile (true) {\n  const result = await transcribe.send(\n    new GetTranscriptionJobCommand({\n      TranscriptionJobName: jobName,\n    }),\n  );\n\n  const job = result.TranscriptionJob;\n\n  if (!job) {\n    throw new Error(`Transcription job ${jobName} was not found`);\n  }\n\n  if (job.TranscriptionJobStatus === \"FAILED\") {\n    throw new Error(job.FailureReason ?? \"Transcription job failed\");\n  }\n\n  if (job.TranscriptionJobStatus !== \"COMPLETED\") {\n    await delay(5000);\n    continue;\n  }\n\n  transcriptUri = job.Transcript?.TranscriptFileUri;\n\n  if (!transcriptUri) {\n    throw new Error(\"Completed job did not include TranscriptFileUri\");\n  }\n\n  break;\n}\n\nconst transcriptResponse = await fetch(transcriptUri);\n\nif (!transcriptResponse.ok) {\n  throw new Error(`Failed to download transcript: ${transcriptResponse.status}`);\n}\n\nconst transcript = await transcriptResponse.json();\n\nconsole.log(transcript.results.transcripts[0]?.transcript ?? \"\");\n```\n\nImportant detail: the full transcript text is not returned inline by `GetTranscriptionJobCommand`. Read the transcript file from `Transcript.TranscriptFileUri` after the job finishes.\n\n## Create And Wait For A Custom Vocabulary\n\nCustom vocabularies help when the default model misses product names, acronyms, or domain-specific terms.\n\n```javascript\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport {\n  CreateVocabularyCommand,\n  GetVocabularyCommand,\n  TranscribeClient,\n} from \"@aws-sdk/client-transcribe\";\n\nconst transcribe = new TranscribeClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst vocabularyName = process.env.AWS_TRANSCRIBE_VOCABULARY ?? \"support-terms\";\n\nawait transcribe.send(\n  new CreateVocabularyCommand({\n    VocabularyName: vocabularyName,\n    LanguageCode: \"en-US\",\n    Phrases: [\"OpenAI\", \"PostgreSQL\", \"Kubernetes\", \"libSQL\"],\n  }),\n);\n\nwhile (true) {\n  const result = await transcribe.send(\n    new GetVocabularyCommand({\n      VocabularyName: vocabularyName,\n    }),\n  );\n\n  if (result.VocabularyState === \"FAILED\") {\n    throw new Error(result.FailureReason ?? \"Vocabulary creation failed\");\n  }\n\n  if (result.VocabularyState === \"READY\") {\n    break;\n  }\n\n  await delay(3000);\n}\n\nconsole.log(`Vocabulary ${vocabularyName} is ready`);\n```\n\nUse the vocabulary in transcription jobs through `Settings.VocabularyName`.\n\nFor larger domain dictionaries, Transcribe also supports supplying a vocabulary file URI instead of inline `Phrases`.\n\n## Common Pitfalls\n\n- `@aws-sdk/client-transcribe` is for batch jobs and service-management APIs. Live streaming uses `@aws-sdk/client-transcribe-streaming`.\n- `MediaFormat` should match the actual media file type you store at `Media.MediaFileUri`.\n- `StartTranscriptionJobCommand` needs exactly one of `LanguageCode`, `IdentifyLanguage`, or `IdentifyMultipleLanguages`.\n- `TranscriptionJobName` must be unique for a new job. Reusing an existing name causes conflicts instead of replacing the old job.\n- A successful credentials lookup does not guarantee the request is going to the correct regional endpoint. Keep `region` explicit.\n- `GetTranscriptionJobCommand` tells you job state, not the final transcript text. Read the transcript file after completion.\n- Custom vocabularies are regional resources. Create and use them in the same region as the transcription job.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-transcribe@3.1007.0`.\n- The AWS SDK for JavaScript v3 service docs are published under a rolling `latest` URL. Use the npm package version for dependency pinning and the AWS docs for operation names and request shapes.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Transcribe client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/transcribe/`\n- Amazon Transcribe `StartTranscriptionJob` API reference: `https://docs.aws.amazon.com/transcribe/latest/APIReference/API_StartTranscriptionJob.html`\n- Amazon Transcribe `GetTranscriptionJob` API reference: `https://docs.aws.amazon.com/transcribe/latest/APIReference/API_GetTranscriptionJob.html`\n- Amazon Transcribe `CreateVocabulary` API reference: `https://docs.aws.amazon.com/transcribe/latest/APIReference/API_CreateVocabulary.html`\n- Amazon Transcribe `GetVocabulary` API reference: `https://docs.aws.amazon.com/transcribe/latest/APIReference/API_GetVocabulary.html`\n"
  },
  {
    "path": "content/aws/docs/transfer/javascript/DOC.md",
    "content": "---\nname: transfer\ndescription: \"AWS SDK for JavaScript v3 client for AWS Transfer Family servers, users, connectors, and managed file transfers\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,transfer,transfer-family,sftp,ftps,as2,javascript,nodejs\"\n---\n\n# AWS Transfer Family SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-transfer` to manage AWS Transfer Family resources from JavaScript or TypeScript. This client covers control-plane operations such as creating servers and users, managing connectors, testing identity providers, starting managed file transfers, and reading transfer results.\n\nThis package is for AWS Transfer Family administration and managed transfer workflows. It is not a general SFTP client library.\n\n## Golden Rules\n\n- Install `@aws-sdk/client-transfer` for new JavaScript work instead of the legacy `aws-sdk` v2 package.\n- Create the client with a `region` and valid AWS credentials before sending commands.\n- `CreateUserCommand` only works for servers that use `IdentityProviderType: \"SERVICE_MANAGED\"`.\n- If you enable `FTPS` on a server, you must provide an ACM certificate ARN with `Certificate`.\n- Use `TestConnectionCommand` before relying on an SFTP connector for production transfers.\n- `ListServersCommand`, `ListUsersCommand`, `ListFileTransferResultsCommand`, and other `List*` operations use `NextToken` / `MaxResults` pagination.\n- `StartFileTransferCommand` uses different fields for inbound vs outbound SFTP transfers: `RetrieveFilePaths` + `LocalDirectoryPath` for inbound, `SendFilePaths` + `RemoteDirectoryPath` for outbound.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-transfer\n```\n\nIf you want to load named AWS profiles explicitly in code, also install the credential helpers:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nSet AWS credentials and a region before creating the client.\n\n```bash\nexport AWS_REGION=\"us-east-1\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n\nexport TRANSFER_LOGGING_ROLE_ARN=\"arn:aws:iam::123456789012:role/TransferLoggingRole\"\nexport TRANSFER_USER_ROLE_ARN=\"arn:aws:iam::123456789012:role/TransferUserAccessRole\"\nexport TRANSFER_CONNECTOR_ROLE_ARN=\"arn:aws:iam::123456789012:role/TransferConnectorAccessRole\"\nexport TRANSFER_SECRET_ARN=\"arn:aws:secretsmanager:us-east-1:123456789012:secret:partner-sftp\"\n```\n\nIf you use shared AWS profiles locally, `AWS_PROFILE` works with the default AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { TransferClient } from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { TransferClient } from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({\n  region: \"us-east-1\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { TransferClient } from \"@aws-sdk/client-transfer\";\nimport { fromIni } from \"@aws-sdk/credential-providers\";\n\nconst transfer = new TransferClient({\n  region: \"us-east-1\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if credentials already come from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeServerCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nconst { Server } = await transfer.send(\n  new DescribeServerCommand({\n    ServerId: \"s-0123456789abcdef0\",\n  }),\n);\n\nconsole.log({\n  serverId: Server?.ServerId,\n  arn: Server?.Arn,\n  state: Server?.State,\n  endpointType: Server?.EndpointType,\n  identityProviderType: Server?.IdentityProviderType,\n});\n```\n\n## Common Workflows\n\n### Create an SFTP server backed by Amazon S3\n\n```javascript\nimport {\n  CreateServerCommand,\n  DescribeServerCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst { ServerId } = await transfer.send(\n  new CreateServerCommand({\n    Domain: \"S3\",\n    EndpointType: \"PUBLIC\",\n    IdentityProviderType: \"SERVICE_MANAGED\",\n    Protocols: [\"SFTP\"],\n    LoggingRole: process.env.TRANSFER_LOGGING_ROLE_ARN,\n    Tags: [\n      { Key: \"Name\", Value: \"partner-sftp\" },\n      { Key: \"Environment\", Value: \"dev\" },\n    ],\n  }),\n);\n\nconst { Server } = await transfer.send(\n  new DescribeServerCommand({ ServerId }),\n);\n\nconsole.log({\n  serverId: Server?.ServerId,\n  state: Server?.State,\n  domain: Server?.Domain,\n  protocols: Server?.Protocols,\n});\n```\n\nIf you need FTPS, include `Protocols: [\"FTPS\"]` or a mixed protocol set and pass an ACM certificate ARN in `Certificate`.\n\nIf you want to pin a security policy, first inspect the available names with `ListSecurityPoliciesCommand` and then pass the selected name with `SecurityPolicyName`.\n\n### List servers with pagination\n\n```javascript\nimport {\n  ListServersCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const response = await transfer.send(\n    new ListServersCommand({\n      MaxResults: 25,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const server of response.Servers ?? []) {\n    console.log({\n      serverId: server.ServerId,\n      state: server.State,\n      endpointType: server.EndpointType,\n      identityProviderType: server.IdentityProviderType,\n      userCount: server.UserCount,\n    });\n  }\n\n  nextToken = response.NextToken;\n} while (nextToken);\n```\n\n### Start or stop a server\n\n```javascript\nimport {\n  DescribeServerCommand,\n  StartServerCommand,\n  StopServerCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\nconst serverId = \"s-0123456789abcdef0\";\n\nawait transfer.send(new StartServerCommand({ ServerId: serverId }));\n\nconst started = await transfer.send(\n  new DescribeServerCommand({ ServerId: serverId }),\n);\n\nconsole.log(started.Server?.State);\n\nawait transfer.send(new StopServerCommand({ ServerId: serverId }));\n```\n\nTransfer Family server state changes are asynchronous. `DescribeServerCommand` returns states such as `OFFLINE`, `ONLINE`, `STARTING`, `STOPPING`, `START_FAILED`, and `STOP_FAILED`.\n\n### Create a service-managed user and assign an SSH key\n\n```javascript\nimport {\n  CreateUserCommand,\n  DescribeUserCommand,\n  ImportSshPublicKeyCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\nconst serverId = \"s-0123456789abcdef0\";\nconst userName = \"partner-a\";\n\nawait transfer.send(\n  new CreateUserCommand({\n    ServerId: serverId,\n    UserName: userName,\n    Role: process.env.TRANSFER_USER_ROLE_ARN,\n    HomeDirectoryType: \"LOGICAL\",\n    HomeDirectoryMappings: [\n      {\n        Entry: \"/\",\n        Target: \"/my-transfer-bucket/partners/partner-a\",\n      },\n    ],\n  }),\n);\n\nawait transfer.send(\n  new ImportSshPublicKeyCommand({\n    ServerId: serverId,\n    UserName: userName,\n    SshPublicKeyBody: \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@example\",\n  }),\n);\n\nconst { User } = await transfer.send(\n  new DescribeUserCommand({\n    ServerId: serverId,\n    UserName: userName,\n  }),\n);\n\nconsole.log({\n  userName: User?.UserName,\n  role: User?.Role,\n  homeDirectoryType: User?.HomeDirectoryType,\n  sshKeyCount: User?.SshPublicKeys?.length,\n});\n```\n\nUse `HomeDirectoryType: \"PATH\"` when you want the user to land directly in a real S3 bucket or EFS path. Use `HomeDirectoryType: \"LOGICAL\"` with `HomeDirectoryMappings` when you want Transfer Family to present logical paths such as `/` to the user.\n\nIf your server uses Amazon EFS, populate `PosixProfile` when you create or update users.\n\n### Test an external identity provider\n\nUse this only for servers that use `IdentityProviderType: \"AWS_DIRECTORY_SERVICE\"` or `\"API_GATEWAY\"`.\n\n```javascript\nimport {\n  TestIdentityProviderCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nconst response = await transfer.send(\n  new TestIdentityProviderCommand({\n    ServerId: \"s-0123456789abcdef0\",\n    UserName: \"alice\",\n    UserPassword: \"super-secret-password\",\n    ServerProtocol: \"SFTP\",\n    SourceIp: \"203.0.113.10\",\n  }),\n);\n\nconsole.log({\n  statusCode: response.StatusCode,\n  message: response.Message,\n  url: response.Url,\n});\n```\n\n`TestIdentityProviderCommand` does not work for `SERVICE_MANAGED` servers, and it only tests password-based auth, not SSH key auth.\n\n### Create and test an SFTP connector\n\nUse a connector when Transfer Family needs to connect to a partner's SFTP server.\n\n```javascript\nimport {\n  CreateConnectorCommand,\n  TestConnectionCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nconst { ConnectorId } = await transfer.send(\n  new CreateConnectorCommand({\n    Url: \"partner-sftp.example.com\",\n    AccessRole: process.env.TRANSFER_CONNECTOR_ROLE_ARN,\n    SftpConfig: {\n      UserSecretId: process.env.TRANSFER_SECRET_ARN,\n      TrustedHostKeys: [\n        \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample hostkey\",\n      ],\n      MaxConcurrentConnections: 1,\n    },\n    Tags: [{ Key: \"Name\", Value: \"partner-a\" }],\n  }),\n);\n\nconst test = await transfer.send(\n  new TestConnectionCommand({ ConnectorId }),\n);\n\nconsole.log({\n  connectorId: test.ConnectorId,\n  status: test.Status,\n  statusMessage: test.StatusMessage,\n});\n```\n\nFor SFTP connectors, `SftpConfig.UserSecretId` must be the ARN of an AWS Secrets Manager secret that contains the partner credentials, key material, or both. `TrustedHostKeys` is the partner server host key list used to verify the remote server.\n\n### List a remote directory before pulling files\n\n```javascript\nimport {\n  StartDirectoryListingCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nconst listing = await transfer.send(\n  new StartDirectoryListingCommand({\n    ConnectorId: \"c-0123456789abcdef0\",\n    RemoteDirectoryPath: \"/exports\",\n    OutputDirectoryPath: \"my-transfer-bucket/listings\",\n    MaxItems: 500,\n  }),\n);\n\nconsole.log({\n  listingId: listing.ListingId,\n  outputFileName: listing.OutputFileName,\n});\n```\n\nThe generated listing file is stored in your AWS storage and gives you the remote file paths to pass to `RetrieveFilePaths` in a later `StartFileTransferCommand` call.\n\n### Send files to a partner SFTP server and inspect results\n\n```javascript\nimport {\n  ListFileTransferResultsCommand,\n  StartFileTransferCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\nconst connectorId = \"c-0123456789abcdef0\";\n\nconst { TransferId } = await transfer.send(\n  new StartFileTransferCommand({\n    ConnectorId: connectorId,\n    SendFilePaths: [\n      \"my-transfer-bucket/outbound/invoice-123.csv\",\n      \"my-transfer-bucket/outbound/invoice-124.csv\",\n    ],\n    RemoteDirectoryPath: \"/incoming\",\n  }),\n);\n\nlet nextToken;\n\ndo {\n  const page = await transfer.send(\n    new ListFileTransferResultsCommand({\n      ConnectorId: connectorId,\n      TransferId,\n      MaxResults: 100,\n      NextToken: nextToken,\n    }),\n  );\n\n  for (const result of page.FileTransferResults ?? []) {\n    console.log({\n      filePath: result.FilePath,\n      status: result.StatusCode,\n      failureCode: result.FailureCode,\n      failureMessage: result.FailureMessage,\n    });\n  }\n\n  nextToken = page.NextToken;\n} while (nextToken);\n```\n\nPer-file transfer results currently report statuses such as `QUEUED`, `IN_PROGRESS`, `COMPLETED`, and `FAILED`.\n\n### Retrieve files from a partner SFTP server into AWS storage\n\n```javascript\nimport {\n  StartFileTransferCommand,\n  TransferClient,\n} from \"@aws-sdk/client-transfer\";\n\nconst transfer = new TransferClient({ region: \"us-east-1\" });\n\nconst response = await transfer.send(\n  new StartFileTransferCommand({\n    ConnectorId: \"c-0123456789abcdef0\",\n    RetrieveFilePaths: [\n      \"/exports/daily-report.csv\",\n      \"/exports/daily-report.sig\",\n    ],\n    LocalDirectoryPath: \"my-transfer-bucket/inbound\",\n  }),\n);\n\nconsole.log(response.TransferId);\n```\n\nFor inbound SFTP transfers, pass the remote file paths in `RetrieveFilePaths` and the destination directory in `LocalDirectoryPath`.\n\n## Important Notes\n\n- `CreateUserCommand` is for server-side Transfer Family users, not IAM users.\n- `CreateUserCommand` applies only to servers with `IdentityProviderType: \"SERVICE_MANAGED\"`.\n- If you use `HomeDirectoryMappings`, set `HomeDirectoryType: \"LOGICAL\"` so the mapping is applied.\n- If you use `FTPS`, include a valid ACM certificate ARN in `Certificate`.\n- `StartServerCommand` and `StopServerCommand` change control-plane state; follow up with `DescribeServerCommand` before assuming the server is ready.\n- `StartDirectoryListingCommand` lists only one directory level at a time and stores the results in your AWS storage.\n- `TestIdentityProviderCommand` only tests password auth, not SSH keys.\n- `TestConnectionCommand` is specific to SFTP connectors.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Transfer client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/transfer/`\n- AWS Transfer Family API reference: `https://docs.aws.amazon.com/transfer/latest/APIReference/Welcome.html`\n- AWS Transfer Family user guide: `https://docs.aws.amazon.com/transfer/latest/userguide/what-is-aws-transfer-family.html`\n- npm package page: `https://www.npmjs.com/package/@aws-sdk/client-transfer`\n"
  },
  {
    "path": "content/aws/docs/translate/javascript/DOC.md",
    "content": "---\nname: translate\ndescription: \"Amazon Translate SDK for JavaScript v3 guide for translating text, documents, and batch jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,amazon-translate,translate,translation,i18n,javascript,nodejs\"\n---\n\n# Amazon Translate SDK for JavaScript v3 Guide\n\n## Golden Rule\n\nUse `@aws-sdk/client-translate` for Amazon Translate calls in JavaScript. Create one `TranslateClient` for the AWS region you use, let the AWS SDK resolve credentials from the normal provider chain, and choose the API that matches your input shape:\n\n- `TranslateTextCommand` for short text already in memory.\n- `TranslateDocumentCommand` for one file you already have as bytes.\n- `StartTextTranslationJobCommand` for larger asynchronous translation work that reads from and writes to Amazon S3.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-translate\n```\n\nExamples in this guide use ESM imports and the standard AWS SDK v3 `client.send(new Command(...))` pattern.\n\n## Credentials And Region\n\nSet the AWS region and provide credentials with the normal AWS SDK mechanisms such as environment variables, shared config files, or IAM roles.\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=dev\n```\n\nIf you prefer direct environment credentials:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN\n```\n\nFor local development, a named profile is usually safer than hardcoding credentials in source files.\n\n## Initialize The Client\n\n```javascript\nimport { TranslateClient } from \"@aws-sdk/client-translate\";\n\nexport const translate = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf the process already has `AWS_REGION` and valid credentials, that is enough for most server-side apps.\n\n## Core Usage\n\n### Translate Plain Text\n\n```javascript\nimport {\n  TranslateClient,\n  TranslateTextCommand,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new TranslateTextCommand({\n    Text: \"Hello, world!\",\n    SourceLanguageCode: \"en\",\n    TargetLanguageCode: \"es\",\n  }),\n);\n\nconsole.log(response.TranslatedText);\n```\n\nUse explicit language codes when you already know the source and target languages.\n\n### Apply A Custom Terminology\n\nIf you already created a custom terminology resource in Amazon Translate, pass its name with `TerminologyNames`.\n\n```javascript\nimport {\n  TranslateClient,\n  TranslateTextCommand,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new TranslateTextCommand({\n    Text: \"The order ships tomorrow.\",\n    SourceLanguageCode: \"en\",\n    TargetLanguageCode: \"fr\",\n    TerminologyNames: [\"commerce-terms\"],\n  }),\n);\n\nconsole.log(response.TranslatedText);\nconsole.log(response.AppliedTerminologies);\n```\n\n### Translate A Document\n\nUse `TranslateDocumentCommand` when you already have the file content in memory. The document payload must include both the bytes and the content type.\n\n```javascript\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport {\n  TranslateClient,\n  TranslateDocumentCommand,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst sourceBytes = await readFile(\"./docs/message.txt\");\n\nconst response = await client.send(\n  new TranslateDocumentCommand({\n    SourceLanguageCode: \"en\",\n    TargetLanguageCode: \"de\",\n    Document: {\n      Content: sourceBytes,\n      ContentType: \"text/plain\",\n    },\n  }),\n);\n\nconst translatedBytes = Buffer.from(\n  response.TranslatedDocument?.Content ?? new Uint8Array(),\n);\n\nawait writeFile(\"./docs/message.de.txt\", translatedBytes);\n```\n\nSet `Document.ContentType` to the real MIME type for the file you send.\n\n### List Supported Languages\n\n`ListLanguagesCommand` returns the languages Amazon Translate currently exposes, with names localized to the display language you request.\n\n```javascript\nimport {\n  ListLanguagesCommand,\n  TranslateClient,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ListLanguagesCommand({\n    DisplayLanguageCode: \"en\",\n  }),\n);\n\nfor (const language of response.Languages ?? []) {\n  console.log(language.LanguageCode, language.LanguageName);\n}\n```\n\n### List Existing Terminologies\n\n```javascript\nimport {\n  ListTerminologiesCommand,\n  TranslateClient,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new ListTerminologiesCommand({\n    MaxResults: 25,\n  }),\n);\n\nfor (const item of response.TerminologyPropertiesList ?? []) {\n  console.log(item.Name);\n}\n```\n\n### Start An Asynchronous Text Translation Job\n\nBatch text translation jobs read input from Amazon S3, write results to Amazon S3, and require an IAM role that Amazon Translate can assume to access those buckets.\n\n```javascript\nimport {\n  StartTextTranslationJobCommand,\n  TranslateClient,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new StartTextTranslationJobCommand({\n    JobName: \"site-copy-es-fr\",\n    DataAccessRoleArn: process.env.TRANSLATE_DATA_ACCESS_ROLE_ARN,\n    InputDataConfig: {\n      S3Uri: \"s3://my-translate-input/site-copy/\",\n      ContentType: \"text/plain\",\n    },\n    OutputDataConfig: {\n      S3Uri: \"s3://my-translate-output/site-copy/\",\n    },\n    SourceLanguageCode: \"en\",\n    TargetLanguageCodes: [\"es\", \"fr\"],\n  }),\n);\n\nconsole.log(response.JobId, response.JobStatus);\n```\n\nCheck status with `DescribeTextTranslationJobCommand`:\n\n```javascript\nimport {\n  DescribeTextTranslationJobCommand,\n  TranslateClient,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst response = await client.send(\n  new DescribeTextTranslationJobCommand({\n    JobId: process.env.TRANSLATE_JOB_ID,\n  }),\n);\n\nconsole.log(response.TextTranslationJobProperties?.JobStatus);\n```\n\nStop a running job if needed:\n\n```javascript\nimport {\n  StopTextTranslationJobCommand,\n  TranslateClient,\n} from \"@aws-sdk/client-translate\";\n\nconst client = new TranslateClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nawait client.send(\n  new StopTextTranslationJobCommand({\n    JobId: process.env.TRANSLATE_JOB_ID,\n  }),\n);\n```\n\n## Config And Auth Notes\n\n- `TranslateClient` uses the standard AWS SDK for JavaScript v3 credential resolution chain.\n- `region` should match the Amazon Translate region where you created terminologies or other related resources.\n- Reuse one client instance instead of constructing a new client for every request.\n- For server apps running on AWS, prefer IAM roles over long-lived access keys.\n- For `StartTextTranslationJobCommand`, the IAM role in `DataAccessRoleArn` must be able to read the input S3 location and write the output S3 location.\n\n## Common Pitfalls\n\n### Missing Region Or Credentials\n\nIf the SDK cannot resolve a region or credentials, the request fails before it reaches Amazon Translate. Set `AWS_REGION` and use a working AWS profile, environment credentials, or an attached IAM role.\n\n### Using The Wrong API For The Input Size\n\nUse `TranslateTextCommand` for direct text strings already in memory. Use `TranslateDocumentCommand` for one file payload. Use `StartTextTranslationJobCommand` when the workflow is asynchronous and S3-backed.\n\n### Forgetting The Document MIME Type\n\n`TranslateDocumentCommand` needs the raw bytes and the matching `Document.ContentType`. If the MIME type is wrong, the service cannot reliably process the document.\n\n### Assuming Batch Jobs Work Without S3 And IAM Setup\n\nText translation jobs are not self-contained request bodies. They depend on S3 input and output locations plus `DataAccessRoleArn`.\n\n### Expecting Terminology Names To Work Automatically Everywhere\n\n`TerminologyNames` only works when the named terminology resource already exists and is available to the client in the region you are calling.\n\n## Version Scope\n\nThis guide targets `@aws-sdk/client-translate` version `3.1007.0` and the AWS SDK for JavaScript v3 command-based API shape.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 Translate client docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/translate/\n- Amazon Translate developer guide: https://docs.aws.amazon.com/translate/latest/dg/what-is.html\n- Amazon Translate API reference: https://docs.aws.amazon.com/translate/latest/APIReference/Welcome.html\n- npm package: https://www.npmjs.com/package/@aws-sdk/client-translate\n"
  },
  {
    "path": "content/aws/docs/types/javascript/DOC.md",
    "content": "---\nname: types\ndescription: \"Shared AWS SDK for JavaScript v3 type definitions for credentials, middleware, paginators, waiters, and response metadata.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.973.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,javascript,typescript,sdk,types,middleware,credentials\"\n---\n\n# `@aws-sdk/types`\n\nUse `@aws-sdk/types` when you need the shared TypeScript contracts behind AWS SDK for JavaScript v3 clients. Most application code does not need to install it directly because service clients already depend on it transitively. Install it yourself when you are writing typed helpers, custom credential providers, middleware, paginator helpers, or waiter wrappers around AWS SDK clients.\n\nThis package is mostly a type surface. In practice, import its contracts with `import type` and pair them with a real AWS client such as `@aws-sdk/client-s3`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/types @aws-sdk/client-s3\n```\n\nIf you need to inspect or mutate low-level HTTP requests inside middleware, also install the Smithy runtime HTTP package:\n\n```bash\nnpm install @smithy/protocol-http\n```\n\nPackage metadata declares Node.js `>=18.0.0`.\n\n## Environment and AWS credentials\n\nFor local development, set a region and whatever credentials your AWS account setup requires:\n\n```env\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\nAWS_SESSION_TOKEN=...\nAWS_S3_BUCKET=my-bucket\n```\n\nIf you already use the default AWS credential chain in Node.js, you can usually omit the explicit `credentials` field and let the client resolve credentials from environment variables, shared config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\n## Initialize a client with typed credentials\n\nThe most common direct use of `@aws-sdk/types` is typing credential objects and providers.\n\n```ts\nimport { ListBucketsCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport type {\n  AwsCredentialIdentity,\n  AwsCredentialIdentityProvider,\n} from \"@aws-sdk/types\";\n\nconst staticCredentials: AwsCredentialIdentity = {\n  accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n  sessionToken: process.env.AWS_SESSION_TOKEN,\n};\n\nconst credentials: AwsCredentialIdentityProvider = async () => staticCredentials;\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials,\n});\n\nconst response = await s3.send(new ListBucketsCommand({}));\n\nfor (const bucket of response.Buckets ?? []) {\n  console.log(bucket.Name);\n}\n```\n\nIf your credentials expire, include `expiration` on the returned identity and make your provider refresh before it expires.\n\n## Type custom middleware safely\n\n`@aws-sdk/types` exports middleware contracts such as `FinalizeRequestMiddleware`, `HandlerExecutionContext`, and `MetadataBearer`. The request and response objects inside middleware are typed as `unknown`, so use a concrete runtime guard before reading or mutating them.\n\n```ts\nimport { randomUUID } from \"node:crypto\";\nimport { ListObjectsV2Command, S3Client } from \"@aws-sdk/client-s3\";\nimport type {\n  FinalizeRequestMiddleware,\n  MetadataBearer,\n} from \"@aws-sdk/types\";\nimport { HttpRequest } from \"@smithy/protocol-http\";\n\nconst addTraceHeader: FinalizeRequestMiddleware<any, MetadataBearer> =\n  (next, context) => async (args) => {\n    if (HttpRequest.isInstance(args.request)) {\n      args.request.headers[\"x-trace-id\"] = randomUUID();\n    }\n\n    context.logger?.info?.(`sending ${context.commandName ?? \"AWS command\"}`);\n    return next(args);\n  };\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\ns3.middlewareStack.add(addTraceHeader, {\n  step: \"finalizeRequest\",\n  name: \"addTraceHeader\",\n});\n\nawait s3.send(\n  new ListObjectsV2Command({\n    Bucket: process.env.AWS_S3_BUCKET!,\n  }),\n);\n```\n\nUse the middleware step that matches what you are changing:\n\n- `initialize`: derive or normalize command input.\n- `serialize`: act before the input becomes a concrete request.\n- `build`: add stable request details that should survive retries.\n- `finalizeRequest`: sign or add hop-by-hop request details right before send.\n- `deserialize`: inspect the raw response and final output.\n\n## Type paginator and waiter helpers\n\nGenerated AWS SDK clients already provide paginator and waiter functions. `@aws-sdk/types` is useful when you want to type config objects that wrap those helpers.\n\n```ts\nimport {\n  paginateListObjectsV2,\n  S3Client,\n  waitUntilBucketExists,\n} from \"@aws-sdk/client-s3\";\nimport type {\n  PaginationConfiguration,\n  WaiterConfiguration,\n} from \"@aws-sdk/types\";\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst bucket = process.env.AWS_S3_BUCKET!;\n\nconst pagination: PaginationConfiguration = {\n  client: s3,\n  pageSize: 1000,\n};\n\nfor await (const page of paginateListObjectsV2(pagination, { Bucket: bucket })) {\n  for (const object of page.Contents ?? []) {\n    console.log(object.Key);\n  }\n}\n\nconst waiter: WaiterConfiguration<S3Client> = {\n  client: s3,\n  maxWaitTime: 60,\n  abortSignal: AbortSignal.timeout(65_000),\n};\n\nawait waitUntilBucketExists(waiter, { Bucket: bucket });\n```\n\n`WaiterConfiguration.maxWaitTime` is required and expressed in seconds. Prefer `abortSignal` over the older `abortController` property.\n\n## Read response metadata consistently\n\nEvery generated AWS SDK v3 command output implements `MetadataBearer`, which gives you access to request IDs, HTTP status, retry attempts, and retry delay.\n\n```ts\nimport { GetObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport type { MetadataBearer } from \"@aws-sdk/types\";\n\nfunction logAwsMetadata(output: MetadataBearer) {\n  console.log({\n    httpStatusCode: output.$metadata.httpStatusCode,\n    requestId: output.$metadata.requestId,\n    attempts: output.$metadata.attempts,\n    totalRetryDelay: output.$metadata.totalRetryDelay,\n  });\n}\n\nconst s3 = new S3Client({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst output = await s3.send(\n  new GetObjectCommand({\n    Bucket: process.env.AWS_S3_BUCKET!,\n    Key: \"example.txt\",\n  }),\n);\n\nlogAwsMetadata(output);\n```\n\n## Common pitfalls\n\n- Use `import type` for `@aws-sdk/types` imports whenever possible. Most commonly used exports are type definitions rather than runtime utilities.\n- Prefer `AwsCredentialIdentity` and `AwsCredentialIdentityProvider`. The older `Credentials` and `CredentialProvider` aliases are deprecated.\n- Prefer `TokenIdentity` over the older deprecated `Token` alias.\n- Do not assume middleware `args.request` or `result.response` already has a concrete HTTP class. Guard them with runtime helpers such as `HttpRequest.isInstance()` or `HttpResponse.isInstance()` from `@smithy/protocol-http`.\n- Do not use this package as a replacement for a service client. It does not give you `S3Client`, `DynamoDBClient`, or command classes.\n- Prefer `EndpointV2`-style endpoint typing when you need endpoint types. The older `Endpoint` interface is deprecated.\n\n## Version notes\n\n- This guide covers `@aws-sdk/types` version `3.973.5`.\n- The package depends on `@smithy/types` and re-exports much of that public type surface.\n- If you are only writing normal AWS service calls, install the specific `@aws-sdk/client-*` package you need and treat `@aws-sdk/types` as an implementation detail.\n"
  },
  {
    "path": "content/aws/docs/util-base64/javascript/DOC.md",
    "content": "---\nname: util-base64\ndescription: \"AWS SDK for JavaScript v3 base64 helpers for converting UTF-8 strings and Uint8Array values to and from standard base64 text.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,aws-sdk,javascript,base64,encoding,decoding,bytes,uint8array\"\n---\n\n# `@aws-sdk/util-base64`\n\nUse this package when AWS SDK v3 code needs to convert between standard base64 strings and raw bytes. It exposes two helpers:\n\n- `toBase64()` to encode a UTF-8 string or `Uint8Array` as base64 text\n- `fromBase64()` to decode a base64 string into a `Uint8Array`\n\nThis package is a local utility. It does not create AWS service clients, load credentials, or read package-specific environment variables.\n\n## Install\n\nInstall the package version your project expects:\n\n```bash\nnpm install @aws-sdk/util-base64@3.374.0\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to initialize.\n\nImport the helpers directly:\n\n```javascript\nimport { fromBase64, toBase64 } from \"@aws-sdk/util-base64\";\n```\n\n## Common Workflows\n\n### Encode a UTF-8 string as base64\n\n`toBase64()` accepts a JavaScript string and encodes its UTF-8 bytes.\n\n```javascript\nimport { toBase64 } from \"@aws-sdk/util-base64\";\n\nconst encoded = toBase64(\"hello world\");\n\nconsole.log(encoded);\n// aGVsbG8gd29ybGQ=\n```\n\nUse this when an application boundary needs textual base64 instead of raw bytes.\n\n### Encode binary data\n\nPass a `Uint8Array` when the value is already binary.\n\n```javascript\nimport { toBase64 } from \"@aws-sdk/util-base64\";\n\nconst bytes = Uint8Array.from([0xde, 0xad, 0xbe, 0xef]);\nconst encoded = toBase64(bytes);\n\nconsole.log(encoded);\n// 3q2+7w==\n```\n\nIn Node.js, `Buffer` also works because it is a `Uint8Array`.\n\n### Decode base64 to bytes\n\n`fromBase64()` returns raw bytes as a `Uint8Array`.\n\n```javascript\nimport { fromBase64 } from \"@aws-sdk/util-base64\";\n\nconst bytes = fromBase64(\"aGVsbG8gd29ybGQ=\");\n\nconsole.log(bytes);\n// Uint8Array([...])\n```\n\n### Decode base64 to text\n\nIf the decoded bytes represent UTF-8 text, run them through `TextDecoder`.\n\n```javascript\nimport { fromBase64 } from \"@aws-sdk/util-base64\";\n\nconst bytes = fromBase64(\"aGVsbG8gd29ybGQ=\");\nconst text = new TextDecoder().decode(bytes);\n\nconsole.log(text);\n// hello world\n```\n\n### Start from an `ArrayBuffer`\n\n`toBase64()` expects `string | Uint8Array`. If your code has an `ArrayBuffer`, wrap it first.\n\n```javascript\nimport { toBase64 } from \"@aws-sdk/util-base64\";\n\nconst arrayBuffer = new Uint8Array([1, 2, 3, 4]).buffer;\nconst encoded = toBase64(new Uint8Array(arrayBuffer));\n\nconsole.log(encoded);\n```\n\n## Important Pitfalls\n\n- `fromBase64()` expects standard base64, not base64url. Inputs that use `-` and `_` must be normalized before decoding.\n- `fromBase64()` rejects invalid characters and incorrect padding instead of trying to recover.\n- `toBase64()` only accepts a string or a `Uint8Array`. Wrap `ArrayBuffer` values with `new Uint8Array(...)` first.\n- `fromBase64()` returns bytes, not a string. Use `TextDecoder` only when the decoded bytes are actually UTF-8 text.\n- `toBase64(\"...\")` encodes the string's UTF-8 bytes. If you already have binary data, pass a `Uint8Array` instead of converting the bytes to a JavaScript string first.\n\n## Base64url Interop\n\nIf another system gives you base64url instead of standard base64, normalize it before calling `fromBase64()`:\n\n```javascript\nimport { fromBase64 } from \"@aws-sdk/util-base64\";\n\nconst fromBase64Url = (input) => {\n  const normalized = input\n    .replace(/-/g, \"+\")\n    .replace(/_/g, \"/\")\n    .padEnd(Math.ceil(input.length / 4) * 4, \"=\");\n\n  return fromBase64(normalized);\n};\n\nconst bytes = fromBase64Url(\"aGVsbG8td29ybGQ\");\nconsole.log(new TextDecoder().decode(bytes));\n```\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-util-base64/\n- npm package page: https://www.npmjs.com/package/@aws-sdk/util-base64\n"
  },
  {
    "path": "content/aws/docs/util-dynamodb/javascript/DOC.md",
    "content": "---\nname: util-dynamodb\ndescription: \"AWS SDK for JavaScript v3 helpers for marshalling JavaScript values to DynamoDB AttributeValue maps and unmarshalling them back.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.996.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,dynamodb,javascript,nodejs,nosql,marshall,unmarshall\"\n---\n\n# `@aws-sdk/util-dynamodb`\n\nUse `@aws-sdk/util-dynamodb` with the low-level DynamoDB client when your application works with normal JavaScript values but DynamoDB operations still need raw `AttributeValue` maps.\n\nThis package only converts data. For requests, credentials, and retries, you still use `@aws-sdk/client-dynamodb`. If you want a higher-level document client that marshals and unmarshals automatically, use `@aws-sdk/lib-dynamodb` instead.\n\n## Install\n\nInstall the DynamoDB client and this utility package together:\n\n```bash\nnpm install @aws-sdk/client-dynamodb@3.996.2 @aws-sdk/util-dynamodb@3.996.2\n```\n\nKeep AWS SDK v3 packages on matching versions.\n\n## Prerequisites\n\nYou need a DynamoDB table, an AWS region, and AWS credentials available to the SDK.\n\nTypical local environment variables:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\nexport AWS_SESSION_TOKEN=...   # optional\nexport DYNAMODB_TABLE=Users\n```\n\nIn Node.js, the SDK can also load credentials and region from the default AWS provider chain, including shared config files and attached IAM roles.\n\n## Initialize the client\n\nCreate the DynamoDB client first, then use `marshall` and `unmarshall` around low-level command inputs and outputs.\n\n```javascript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\n\nexport const dynamodb = new DynamoDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\n## Common workflows\n\n### Put and get an item\n\nUse `marshall(...)` for `Item` and `Key`, then `unmarshall(...)` on the returned item.\n\n```javascript\nimport {\n  DynamoDBClient,\n  GetItemCommand,\n  PutItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { marshall, unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nconst dynamodb = new DynamoDBClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nconst tableName = process.env.DYNAMODB_TABLE;\n\nawait dynamodb.send(\n  new PutItemCommand({\n    TableName: tableName,\n    Item: marshall(\n      {\n        pk: \"user#123\",\n        sk: \"profile\",\n        email: \"ada@example.com\",\n        active: true,\n        loginCount: 0,\n      },\n      {\n        removeUndefinedValues: true,\n      },\n    ),\n    ConditionExpression: \"attribute_not_exists(pk)\",\n  }),\n);\n\nconst { Item } = await dynamodb.send(\n  new GetItemCommand({\n    TableName: tableName,\n    Key: marshall({\n      pk: \"user#123\",\n      sk: \"profile\",\n    }),\n  }),\n);\n\nif (Item) {\n  const user = unmarshall(Item);\n  console.log(user.email);\n}\n```\n\n### Use `marshall` with expressions\n\nFor low-level DynamoDB commands, expression attribute values also need DynamoDB shapes.\n\n```javascript\nimport { UpdateItemCommand } from \"@aws-sdk/client-dynamodb\";\nimport { marshall } from \"@aws-sdk/util-dynamodb\";\n\nawait dynamodb.send(\n  new UpdateItemCommand({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: marshall({\n      pk: \"user#123\",\n      sk: \"profile\",\n    }),\n    UpdateExpression: \"SET email = :email, updatedAt = :updatedAt\",\n    ExpressionAttributeValues: marshall({\n      \":email\": \"grace@example.com\",\n      \":updatedAt\": new Date().toISOString(),\n    }),\n    ReturnValues: \"ALL_NEW\",\n  }),\n);\n```\n\n### Marshall a top-level map or list as a single attribute value\n\nBy default, `marshall({ ... })` returns a plain attribute map, which is what `Item`, `Key`, and `ExpressionAttributeValues` usually need.\n\nIf you need one wrapped `AttributeValue` such as `{ M: ... }` or `{ L: ... }`, set `convertTopLevelContainer: true`.\n\n```javascript\nimport { UpdateItemCommand } from \"@aws-sdk/client-dynamodb\";\nimport { marshall } from \"@aws-sdk/util-dynamodb\";\n\nconst profileAttr = marshall(\n  {\n    displayName: \"Ada\",\n    tags: [\"admin\", \"beta\"],\n  },\n  {\n    convertTopLevelContainer: true,\n  },\n);\n\nawait dynamodb.send(\n  new UpdateItemCommand({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: marshall({\n      pk: \"user#123\",\n      sk: \"profile\",\n    }),\n    UpdateExpression: \"SET profile = :profile\",\n    ExpressionAttributeValues: {\n      \":profile\": profileAttr,\n    },\n  }),\n);\n```\n\n### Unmarshall a single `AttributeValue`\n\n`unmarshall(...)` normally expects an item-shaped map like `response.Item`. If you already have one individual `AttributeValue`, set `convertWithoutMapWrapper: true`.\n\n```javascript\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nconst attributeValue = {\n  M: {\n    plan: { S: \"pro\" },\n    seats: { N: \"5\" },\n  },\n};\n\nconst profile = unmarshall(attributeValue, {\n  convertWithoutMapWrapper: true,\n});\n\nconsole.log(profile.plan);\n```\n\n## Translation options\n\n### Remove `undefined` values during marshalling\n\nWithout `removeUndefinedValues: true`, the converter throws if a map, list, or set contains `undefined`.\n\n```javascript\nimport { marshall } from \"@aws-sdk/util-dynamodb\";\n\nconst item = marshall(\n  {\n    pk: \"user#123\",\n    sk: \"profile\",\n    nickname: undefined,\n  },\n  {\n    removeUndefinedValues: true,\n  },\n);\n```\n\n### Convert empty values to `NULL`\n\nSet `convertEmptyValues: true` when you want empty strings, empty binary values, and empty sets converted to DynamoDB `NULL` values.\n\n```javascript\nimport { marshall } from \"@aws-sdk/util-dynamodb\";\n\nconst item = marshall(\n  {\n    pk: \"user#123\",\n    sk: \"profile\",\n    bio: \"\",\n  },\n  {\n    convertEmptyValues: true,\n  },\n);\n```\n\n### Convert class instances by enumerable properties\n\nPlain objects are converted automatically. For class instances, enable `convertClassInstanceToMap`.\n\n```javascript\nimport { marshall } from \"@aws-sdk/util-dynamodb\";\n\nclass AuditInfo {\n  constructor(actor, source) {\n    this.actor = actor;\n    this.source = source;\n  }\n}\n\nconst audit = new AuditInfo(\"user#123\", \"admin-panel\");\n\nconst attributeValue = marshall(audit, {\n  convertClassInstanceToMap: true,\n  convertTopLevelContainer: true,\n});\n```\n\n## Large numbers and safe conversion\n\nBy default, marshalling throws for JavaScript numbers outside the safe integer range so you do not silently lose precision.\n\nWhen reading, use `wrapNumbers: true` if you want numbers returned as wrapper objects instead of native JavaScript `number` values.\n\n```javascript\nimport { GetItemCommand } from \"@aws-sdk/client-dynamodb\";\nimport { marshall, unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nconst { Item } = await dynamodb.send(\n  new GetItemCommand({\n    TableName: process.env.DYNAMODB_TABLE,\n    Key: marshall({\n      pk: \"invoice#1\",\n      sk: \"totals\",\n    }),\n  }),\n);\n\nif (Item) {\n  const invoice = unmarshall(Item, {\n    wrapNumbers: true,\n  });\n\n  console.log(invoice.amount.toString());\n}\n```\n\nIf you must marshall an imprecise JavaScript number anyway, `allowImpreciseNumbers: true` disables that safeguard. Use it only when loss of precision is acceptable.\n\n## Important pitfalls\n\n- `marshall({ ... })` returns a record map by default, not an `{ M: ... }` wrapper. Use `convertTopLevelContainer: true` when an API field expects one `AttributeValue`.\n- `unmarshall(item)` expects an item map like DynamoDB `Item` or `LastEvaluatedKey`. For one attribute value, use `convertWithoutMapWrapper: true`.\n- `undefined` values are not ignored unless you opt in with `removeUndefinedValues: true`.\n- Empty strings, empty binary values, and empty sets do not become `NULL` automatically. Set `convertEmptyValues: true` if you want that translation.\n- Special numeric values like `NaN` and `Infinity` are rejected.\n- If you want automatic marshalling and unmarshalling around DynamoDB commands, use `@aws-sdk/lib-dynamodb` instead of wiring these helpers into every low-level call.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 package docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-util-dynamodb/\n- AWS SDK for JavaScript v3 source and package README: https://github.com/aws/aws-sdk-js-v3/tree/main/packages/util-dynamodb\n- npm package page: https://www.npmjs.com/package/@aws-sdk/util-dynamodb\n"
  },
  {
    "path": "content/aws/docs/util-utf8/javascript/DOC.md",
    "content": "---\nname: util-utf8\ndescription: \"AWS SDK UTF-8 utility helpers for JavaScript - convert strings, Uint8Array values, ArrayBuffer inputs, and typed-array views\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.374.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,aws-sdk,utf8,encoding,bytes,uint8array,typedarray\"\n---\n\n# `@aws-sdk/util-utf8` JavaScript Guide\n\n## What This Package Does\n\n`@aws-sdk/util-utf8` is a small AWS SDK v3 utility package for converting between JavaScript strings and byte arrays.\n\nUse it when you need to:\n\n- turn a UTF-8 string into a `Uint8Array`\n- turn SDK byte output back into a JavaScript string\n- normalize `string`, `ArrayBuffer`, or typed-array input into `Uint8Array`\n\nThis package does not create AWS clients, does not read credentials, and does not require any environment variables on its own.\n\nIn many AWS SDK v3 clients, UTF-8 helpers are already wired into the runtime. Reach for this package when your application code needs the same conversions directly.\n\n## Installation\n\n```bash\nnpm install @aws-sdk/util-utf8@3.374.0\n```\n\n## Import\n\n```javascript\nimport { fromUtf8, toUtf8, toUint8Array } from \"@aws-sdk/util-utf8\";\n```\n\nIf your project is still using CommonJS:\n\n```javascript\nconst { fromUtf8, toUtf8, toUint8Array } = require(\"@aws-sdk/util-utf8\");\n```\n\n## Quick Start\n\n### Encode a string to bytes\n\nUse `fromUtf8()` when you have text and need a `Uint8Array`.\n\n```javascript\nimport { fromUtf8 } from \"@aws-sdk/util-utf8\";\n\nconst bytes = fromUtf8(\"Hello from AWS SDK v3\");\n\nconsole.log(bytes instanceof Uint8Array); // true\nconsole.log(bytes);\n```\n\n### Decode bytes to a string\n\nUse `toUtf8()` when you already have `Uint8Array` data and want text.\n\n```javascript\nimport { fromUtf8, toUtf8 } from \"@aws-sdk/util-utf8\";\n\nconst original = \"café\";\nconst bytes = fromUtf8(original);\nconst decoded = toUtf8(bytes);\n\nconsole.log(decoded); // \"café\"\n```\n\n### Normalize input to `Uint8Array`\n\nUse `toUint8Array()` when your code may receive different byte-like inputs.\n\n```javascript\nimport { toUint8Array } from \"@aws-sdk/util-utf8\";\n\nconst fromString = toUint8Array(\"hello\");\n\nconst buffer = new ArrayBuffer(4);\nnew Uint8Array(buffer).set([65, 66, 67, 68]);\nconst fromBuffer = toUint8Array(buffer);\n\nconst view = new Uint16Array([500, 600]);\nconst fromView = toUint8Array(view);\n\nconsole.log(fromString);\nconsole.log(fromBuffer);\nconsole.log(fromView);\n```\n\n## Common Workflows\n\n### Hash a JSON payload\n\nAWS signing and checksum code often works on raw bytes, not plain strings.\n\n```javascript\nimport { createHash } from \"node:crypto\";\nimport { fromUtf8 } from \"@aws-sdk/util-utf8\";\n\nconst payload = JSON.stringify({ hello: \"world\" });\n\nconst digest = createHash(\"sha256\")\n  .update(fromUtf8(payload))\n  .digest(\"hex\");\n\nconsole.log(digest);\n```\n\n### Decode an SDK byte payload\n\nWhen middleware or lower-level SDK code gives you bytes, decode them before parsing.\n\n```javascript\nimport { toUtf8 } from \"@aws-sdk/util-utf8\";\n\nconst bodyBytes = new Uint8Array([123, 34, 111, 107, 34, 58, 116, 114, 117, 101, 125]);\nconst bodyText = toUtf8(bodyBytes);\nconst body = JSON.parse(bodyText);\n\nconsole.log(body.ok); // true\n```\n\n### Accept mixed input safely\n\n`toUint8Array()` is the easiest way to normalize data before hashing, signing, compressing, or forwarding to another API.\n\n```javascript\nimport { toUint8Array, toUtf8 } from \"@aws-sdk/util-utf8\";\n\nfunction readText(input) {\n  const bytes = toUint8Array(input);\n  return toUtf8(bytes);\n}\n\nconsole.log(readText(\"plain text\"));\nconsole.log(readText(new Uint8Array([65, 87, 83])));\n```\n\n## Using It With AWS SDK Clients\n\nMost AWS SDK v3 clients already provide default UTF-8 helpers internally, so you usually do not need to pass these functions yourself.\n\nIf you are building custom runtime configuration, use the helpers like this:\n\n```javascript\nimport { SSOClient } from \"@aws-sdk/client-sso\";\nimport { fromUtf8, toUtf8 } from \"@aws-sdk/util-utf8\";\n\nconst client = new SSOClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  utf8Decoder: fromUtf8,\n  utf8Encoder: toUtf8,\n});\n```\n\nEnvironment variable example:\n\n```bash\nexport AWS_REGION=us-east-1\n```\n\nUse this pattern only if you are intentionally overriding the runtime defaults.\n\n## Runtime Notes\n\n- In browser builds, the package uses `TextEncoder` and `TextDecoder(\"utf-8\")`.\n- In Node.js builds, the package uses Buffer-backed UTF-8 conversion.\n- The public API stays the same across runtimes: `fromUtf8`, `toUtf8`, and `toUint8Array`.\n\n## Important Pitfalls\n\n### `toUtf8()` passes strings through unchanged\n\nIf you call `toUtf8()` with a string, it returns that string as-is.\n\n```javascript\nimport { toUtf8 } from \"@aws-sdk/util-utf8\";\n\nconsole.log(toUtf8(\"already text\")); // \"already text\"\n```\n\nThat means `toUtf8()` is a decode helper for byte input, not a general-purpose string transcoder.\n\n### `toUtf8()` expects string or byte-like input\n\nDo not pass plain objects, numbers, or other arbitrary values.\n\n```javascript\nimport { toUtf8 } from \"@aws-sdk/util-utf8\";\n\ntry {\n  console.log(toUtf8({ value: \"nope\" }));\n} catch (error) {\n  console.error(error.message);\n}\n```\n\nIf your input may be `string`, `ArrayBuffer`, or a typed-array view, normalize it with `toUint8Array()` first.\n\n### Normalize typed-array views carefully\n\nIf you already have a typed-array view with an offset into a larger buffer, `toUint8Array()` preserves the view window instead of reading the whole underlying buffer.\n\nThat makes it safer than manually calling `new Uint8Array(view.buffer)` when the original view starts partway into the buffer.\n\n## Version Notes\n\nThis guide is for `@aws-sdk/util-utf8` version `3.374.0`.\n\nIn newer AWS SDK v3 internals, you may also see the same UTF-8 helpers provided from `@smithy/util-utf8`. The application-level usage shown here stays the same: convert text with `fromUtf8()`, decode bytes with `toUtf8()`, and normalize mixed inputs with `toUint8Array()`.\n"
  },
  {
    "path": "content/aws/docs/verifiedpermissions/javascript/DOC.md",
    "content": "---\nname: verifiedpermissions\ndescription: \"AWS SDK for JavaScript v3 client for Amazon Verified Permissions policy stores, Cedar policies, identity sources, and authorization decisions.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,verifiedpermissions,authorization,cedar,javascript,nodejs\"\n---\n\n# `@aws-sdk/client-verifiedpermissions`\n\nUse this package for Amazon Verified Permissions in JavaScript and Node.js. The main workflows are creating a policy store, uploading a Cedar schema, creating policies or policy templates, configuring an identity source, and making authorization decisions with `IsAuthorized` or `IsAuthorizedWithToken`.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-verifiedpermissions\n```\n\n## Initialize the client\n\nTypical local environment:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=...\nexport AWS_SECRET_ACCESS_KEY=...\n# export AWS_SESSION_TOKEN=...   # if you use temporary credentials\n```\n\n```javascript\nimport { VerifiedPermissionsClient } from \"@aws-sdk/client-verifiedpermissions\";\n\nconst verifiedPermissions = new VerifiedPermissionsClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nUse command imports plus `client.send(...)` for normal SDK v3 usage.\n\n## Core workflow\n\nThe usual setup order is:\n\n1. Create a policy store.\n2. Put a Cedar schema into that store.\n3. Create static or template-linked policies.\n4. Call `IsAuthorized` or `IsAuthorizedWithToken` from your application.\n\nVerified Permissions is eventually consistent, so new or updated stores, schemas, policies, templates, and identity sources can take a few seconds to appear in later reads and authorization results.\n\n### Create a policy store\n\n`validationSettings` is required. Use `STRICT` if you want policy submissions validated against your Cedar schema.\n\n```javascript\nimport {\n  CreatePolicyStoreCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst createStoreResponse = await client.send(\n  new CreatePolicyStoreCommand({\n    validationSettings: {\n      mode: \"STRICT\",\n    },\n    description: \"Application authorization store\",\n    deletionProtection: \"ENABLED\",\n    tags: {\n      project: \"docs-app\",\n      environment: \"dev\",\n    },\n  }),\n);\n\nconst policyStoreId = createStoreResponse.policyStoreId;\nconsole.log(policyStoreId);\n```\n\nVerified Permissions currently supports only one Cedar namespace per policy store.\n\n### Put or update the Cedar schema\n\n`PutSchema` accepts the schema as a Cedar JSON string. Keeping the schema in a file is usually easier than embedding it inline.\n\n```javascript\nimport { readFileSync } from \"node:fs\";\nimport {\n  PutSchemaCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nawait client.send(\n  new PutSchemaCommand({\n    policyStoreId,\n    definition: {\n      cedarJson: readFileSync(\"./cedar-schema.json\", \"utf8\"),\n    },\n  }),\n);\n```\n\nSchema changes validate policies and templates submitted after the change. Existing policies and templates are not re-evaluated until you update them later.\n\n### Create a static policy\n\nStatic policies carry the Cedar statement directly in the request.\n\n```javascript\nimport {\n  CreatePolicyCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst createPolicyResponse = await client.send(\n  new CreatePolicyCommand({\n    policyStoreId,\n    definition: {\n      static: {\n        description: \"Allow a user to view one document\",\n        statement:\n          'permit(principal == App::User::\"user-123\", action == App::Action::\"view\", resource == App::Document::\"doc-456\");',\n      },\n    },\n  }),\n);\n\nconsole.log(createPolicyResponse.policyId);\n```\n\nTo create a policy linked to a template instead, use `definition.templateLinked` with a `policyTemplateId` plus the principal and resource that should fill the template placeholders.\n\n### Check an authorization decision\n\nUse `IsAuthorized` when your application already knows the principal and can provide any needed entities and request context directly.\n\n```javascript\nimport {\n  IsAuthorizedCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst decision = await client.send(\n  new IsAuthorizedCommand({\n    policyStoreId,\n    principal: {\n      entityType: \"App::User\",\n      entityId: \"user-123\",\n    },\n    action: {\n      actionType: \"App::Action\",\n      actionId: \"view\",\n    },\n    resource: {\n      entityType: \"App::Document\",\n      entityId: \"doc-456\",\n    },\n    context: {\n      contextMap: {\n        requestIp: { string: \"203.0.113.10\" },\n        isInternal: { boolean: false },\n      },\n    },\n  }),\n);\n\nconsole.log(decision.decision);\nconsole.log(decision.determiningPolicies);\nconsole.log(decision.errors);\n```\n\nThe response includes the final `decision`, the `determiningPolicies` list, and any evaluation `errors` such as missing entities or attributes referenced by a policy.\n\n### Pass entities for group membership and attributes\n\nIf your policies depend on entity attributes or parent relationships, include an `entities` slice with the request.\n\n```javascript\nimport {\n  IsAuthorizedCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst response = await client.send(\n  new IsAuthorizedCommand({\n    policyStoreId,\n    principal: {\n      entityType: \"App::User\",\n      entityId: \"user-123\",\n    },\n    action: {\n      actionType: \"App::Action\",\n      actionId: \"edit\",\n    },\n    resource: {\n      entityType: \"App::Document\",\n      entityId: \"doc-456\",\n    },\n    entities: {\n      entityList: [\n        {\n          identifier: {\n            entityType: \"App::User\",\n            entityId: \"user-123\",\n          },\n          attributes: {\n            department: { string: \"engineering\" },\n          },\n          parents: [\n            {\n              entityType: \"App::Group\",\n              entityId: \"editors\",\n            },\n          ],\n        },\n        {\n          identifier: {\n            entityType: \"App::Document\",\n            entityId: \"doc-456\",\n          },\n          attributes: {\n            owner: {\n              entityIdentifier: {\n                entityType: \"App::User\",\n                entityId: \"user-123\",\n              },\n            },\n          },\n        },\n      ],\n    },\n  }),\n);\n\nconsole.log(response.decision);\n```\n\n`context` and `entities` also accept a raw Cedar JSON string through `cedarJson` if you already build those payloads elsewhere.\n\n## JWT-based authorization with an identity source\n\nUse an identity source when the principal should come from an Amazon Cognito user pool or an OpenID Connect provider and you want the application to authorize requests with tokens.\n\n### Create an OIDC identity source\n\n```javascript\nimport {\n  CreateIdentitySourceCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst identitySource = await client.send(\n  new CreateIdentitySourceCommand({\n    policyStoreId,\n    principalEntityType: \"App::User\",\n    configuration: {\n      openIdConnectConfiguration: {\n        issuer: \"https://issuer.example.com\",\n        entityIdPrefix: \"ExampleOIDC\",\n        groupConfiguration: {\n          groupClaim: \"groups\",\n          groupEntityType: \"App::Group\",\n        },\n        tokenSelection: {\n          accessTokenOnly: {\n            principalIdClaim: \"sub\",\n            audiences: [\"api://documents\"],\n          },\n        },\n      },\n    },\n  }),\n);\n\nconsole.log(identitySource.identitySourceId);\n```\n\nFor OIDC, configure either `accessTokenOnly` or `identityTokenOnly` in `tokenSelection`, depending on which token type your application will send for authorization.\n\n### Authorize with a token\n\n```javascript\nimport {\n  IsAuthorizedWithTokenCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nconst result = await client.send(\n  new IsAuthorizedWithTokenCommand({\n    policyStoreId,\n    accessToken: bearerToken,\n    action: {\n      actionType: \"App::Action\",\n      actionId: \"view\",\n    },\n    resource: {\n      entityType: \"App::Document\",\n      entityId: \"doc-456\",\n    },\n    context: {\n      contextMap: {\n        requestTime: { datetime: new Date().toISOString() },\n      },\n    },\n  }),\n);\n\nconsole.log(result.principal);\nconsole.log(result.decision);\n```\n\nVerified Permissions validates the token signature and expiration on each call. Tokens remain usable until they expire; token revocation and resource deletion do not invalidate a token already accepted by the policy store.\n\n## List policies\n\nList APIs are paginated with `nextToken`.\n\n```javascript\nimport {\n  ListPoliciesCommand,\n  VerifiedPermissionsClient,\n} from \"@aws-sdk/client-verifiedpermissions\";\n\nconst client = new VerifiedPermissionsClient({ region: \"us-east-1\" });\n\nlet nextToken;\n\ndo {\n  const page = await client.send(\n    new ListPoliciesCommand({\n      policyStoreId,\n      maxResults: 50,\n      nextToken,\n    }),\n  );\n\n  for (const policy of page.policies ?? []) {\n    console.log(policy.policyId, policy.policyType, policy.effect);\n  }\n\n  nextToken = page.nextToken;\n} while (nextToken);\n```\n\nThe same `nextToken` pattern applies to `ListIdentitySources`, `ListPolicyStores`, and `ListPolicyTemplates`.\n\n## Important behavior and pitfalls\n\n- A policy store supports only one Cedar namespace.\n- Verified Permissions is eventually consistent after creates and updates. If you create a store, schema, policy, template, or identity source and then immediately read or authorize, add retry or short backoff logic.\n- `PutSchema` affects validation for new or updated policies and templates only. Existing items are not revalidated until they are updated.\n- `UpdatePolicy` can modify only static policies. It cannot convert a static policy to a template-linked one, and it cannot change the effect, principal, or resource of a static policy.\n- `BatchIsAuthorized` accepts up to 30 requests per call, and either the principal or the resource must be identical across the whole batch.\n- `DeletePolicyStore` is idempotent. Deleting a store that does not exist still returns HTTP 200.\n\n## Minimal command reference\n\n- Store setup: `CreatePolicyStoreCommand`, `PutSchemaCommand`, `GetPolicyStoreCommand`, `UpdatePolicyStoreCommand`\n- Policies: `CreatePolicyCommand`, `GetPolicyCommand`, `ListPoliciesCommand`, `UpdatePolicyCommand`, `DeletePolicyCommand`\n- Templates: `CreatePolicyTemplateCommand`, `GetPolicyTemplateCommand`, `ListPolicyTemplatesCommand`, `UpdatePolicyTemplateCommand`, `DeletePolicyTemplateCommand`\n- Identity sources: `CreateIdentitySourceCommand`, `GetIdentitySourceCommand`, `ListIdentitySourcesCommand`, `UpdateIdentitySourceCommand`, `DeleteIdentitySourceCommand`\n- Authorization: `IsAuthorizedCommand`, `IsAuthorizedWithTokenCommand`, `BatchIsAuthorizedCommand`, `BatchIsAuthorizedWithTokenCommand`\n"
  },
  {
    "path": "content/aws/docs/wafv2/javascript/DOC.md",
    "content": "---\nname: wafv2\ndescription: \"AWS SDK for JavaScript v3 WAFV2 client for managing Web ACLs, IP sets, and WAF associations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,wafv2,waf,javascript,nodejs,web-acl,ip-set,cloudfront\"\n---\n\n# `@aws-sdk/client-wafv2`\n\nUse this package for AWS WAF v2 operations in AWS SDK for JavaScript v3. It is the client for listing and inspecting Web ACLs, creating and updating WAF resources, managing IP sets, and associating a regional Web ACL with supported resources.\n\nPrefer `WAFV2Client` plus explicit command imports for new code.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-wafv2\n```\n\nIf you want explicit shared-profile or assume-role helpers instead of the default credential chain:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nConfigure AWS credentials before creating the client.\n\n```bash\nexport AWS_REGION=\"us-west-2\"\nexport AWS_PROFILE=\"dev\"\n\n# or use environment credentials directly\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"\n```\n\nWAFv2 has two scopes, and the scope affects the region you must call:\n\n- `REGIONAL`: use the region where the protected resource lives\n- `CLOUDFRONT`: use `us-east-1` for all WAF API and SDK calls\n\nIf you use the wrong region for `Scope: \"CLOUDFRONT\"`, calls usually fail or look like the resource does not exist.\n\n## Client Setup\n\n### Minimal Node.js client\n\n```javascript\nimport { WAFV2Client } from \"@aws-sdk/client-wafv2\";\n\nfunction makeWafClient(scope = \"REGIONAL\") {\n  return new WAFV2Client({\n    region:\n      scope === \"CLOUDFRONT\"\n        ? \"us-east-1\"\n        : (process.env.AWS_REGION ?? \"us-west-2\"),\n  });\n}\n\nconst regionalWaf = makeWafClient(\"REGIONAL\");\nconst cloudFrontWaf = makeWafClient(\"CLOUDFRONT\");\n```\n\nIn Node.js, the default AWS SDK credential provider chain is usually enough if credentials already come from environment variables, shared AWS config files, ECS, EC2 instance metadata, or IAM Identity Center.\n\n### Explicit shared profile\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { WAFV2Client } from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"dev\",\n  }),\n});\n```\n\n## Core Usage Pattern\n\nAWS SDK v3 clients use `client.send(new Command(input))`.\n\n```javascript\nimport {\n  GetWebACLCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await waf.send(\n  new GetWebACLCommand({\n    Name: \"app-web-acl\",\n    Scope: \"REGIONAL\",\n    Id: \"11111111-2222-3333-4444-555555555555\",\n  }),\n);\n\nconsole.log(response.WebACL?.ARN);\nconsole.log(response.LockToken);\n```\n\nRead operations often return a `LockToken`. Keep that token for the next `update_*` or `delete_*` call on the same object.\n\n## Common Workflows\n\n### List Web ACLs\n\n`ListWebACLsCommand` returns summaries and paginates with `NextMarker`.\n\n```javascript\nimport {\n  ListWebACLsCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nlet nextMarker;\n\ndo {\n  const page = await waf.send(\n    new ListWebACLsCommand({\n      Scope: \"REGIONAL\",\n      Limit: 100,\n      NextMarker: nextMarker,\n    }),\n  );\n\n  for (const acl of page.WebACLs ?? []) {\n    console.log(acl.Name, acl.ARN, acl.Id);\n  }\n\n  nextMarker = page.NextMarker;\n} while (nextMarker);\n```\n\nFor CloudFront-scoped ACLs, switch `Scope` to `\"CLOUDFRONT\"` and create the client in `us-east-1`.\n\n### Create a minimal Web ACL\n\nThe smallest useful Web ACL needs a name, scope, default action, and visibility config.\n\n```javascript\nimport {\n  CreateWebACLCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst created = await waf.send(\n  new CreateWebACLCommand({\n    Name: \"app-web-acl\",\n    Scope: \"REGIONAL\",\n    Description: \"Base Web ACL for the app\",\n    DefaultAction: {\n      Allow: {},\n    },\n    VisibilityConfig: {\n      SampledRequestsEnabled: true,\n      CloudWatchMetricsEnabled: true,\n      MetricName: \"appWebAcl\",\n    },\n    Rules: [],\n  }),\n);\n\nconsole.log(created.Summary?.ARN);\nconsole.log(created.Summary?.Id);\n```\n\nWhen you later update this Web ACL, retrieve the current definition first and submit the full desired mutable configuration back to WAF, not just the field you want to change.\n\n### Add an address to an existing IP set\n\nWAFv2 updates are optimistic-lock based. Read the current object, keep its `LockToken`, then send the full updated address list.\n\n```javascript\nimport {\n  GetIPSetCommand,\n  UpdateIPSetCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst current = await waf.send(\n  new GetIPSetCommand({\n    Name: \"office-allowlist\",\n    Scope: \"REGIONAL\",\n    Id: \"11111111-2222-3333-4444-555555555555\",\n  }),\n);\n\nif (!current.IPSet || !current.LockToken) {\n  throw new Error(\"IP set lookup did not return an IPSet and LockToken.\");\n}\n\nconst updated = await waf.send(\n  new UpdateIPSetCommand({\n    Name: current.IPSet.Name,\n    Scope: \"REGIONAL\",\n    Id: current.IPSet.Id,\n    Addresses: [\n      ...(current.IPSet.Addresses ?? []),\n      \"203.0.113.18/32\",\n    ],\n    LockToken: current.LockToken,\n  }),\n);\n\nconsole.log(updated.NextLockToken);\n```\n\nAll IP set addresses must use CIDR notation. WAF supports IPv4 and IPv6 ranges, but not `/0`.\n\n### Associate a Web ACL with a regional resource\n\nUse `AssociateWebACLCommand` for supported regional resources such as an Application Load Balancer or API Gateway stage.\n\n```javascript\nimport {\n  AssociateWebACLCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait waf.send(\n  new AssociateWebACLCommand({\n    WebACLArn:\n      \"arn:aws:wafv2:us-west-2:123456789012:regional/webacl/app-web-acl/a1b2c3d4-1111-2222-3333-abcdefabcdef\",\n    ResourceArn:\n      \"arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-alb/50dc6c495c0c9188\",\n  }),\n);\n```\n\nTo inspect the current regional association, use `GetWebACLForResourceCommand` with the same `ResourceArn`.\n\n```javascript\nimport {\n  GetWebACLForResourceCommand,\n  WAFV2Client,\n} from \"@aws-sdk/client-wafv2\";\n\nconst waf = new WAFV2Client({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst current = await waf.send(\n  new GetWebACLForResourceCommand({\n    ResourceArn:\n      \"arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-alb/50dc6c495c0c9188\",\n  }),\n);\n\nconsole.log(current.WebACL?.ARN);\n```\n\nDo not use `AssociateWebACL` or `GetWebACLForResource` for CloudFront distributions. For CloudFront, AWS directs you to CloudFront `UpdateDistribution` and `GetDistributionConfig`.\n\n## Pitfalls\n\n- `Scope: \"CLOUDFRONT\"` always uses the `us-east-1` endpoint, even when your distribution serves traffic globally.\n- `AssociateWebACLCommand` is for regional resources. CloudFront distributions use the CloudFront API instead.\n- `UpdateWebACLCommand` and `UpdateIPSetCommand` replace mutable configuration rather than applying partial patches. Read the current object first.\n- Keep `LockToken` values short-lived. If another deployment or console change updates the same object, your old token fails with `WAFOptimisticLockException`.\n- After create, update, or association changes, allow for propagation delay. AWS documents temporary inconsistencies and `WAFUnavailableEntityException` during rollout.\n- If you query the wrong region or use the wrong scope, the failure often looks like a missing item rather than a configuration mistake.\n\n## When To Reach For Other Packages\n\n- `@aws-sdk/client-cloudfront`: attach or inspect a WAF Web ACL on CloudFront distributions.\n- `@aws-sdk/credential-providers`: use `fromIni`, assume-role helpers, IAM Identity Center, or other explicit credential flows.\n\n## Version Notes\n\n- This guide targets `@aws-sdk/client-wafv2` version `3.1007.0`.\n- The package exposes the low-level `WAFV2Client` and individual commands; this is the import style to prefer in application code.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 WAFV2 client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/wafv2/`\n- AWS WAF API Reference: `https://docs.aws.amazon.com/waf/latest/APIReference/Welcome.html`\n- AWS WAF `ListWebACLs`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_ListWebACLs.html`\n- AWS WAF `GetWebACL`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_GetWebACL.html`\n- AWS WAF `CreateWebACL`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_CreateWebACL.html`\n- AWS WAF `GetIPSet`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_GetIPSet.html`\n- AWS WAF `UpdateIPSet`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_UpdateIPSet.html`\n- AWS WAF `AssociateWebACL`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_AssociateWebACL.html`\n- AWS WAF `GetWebACLForResource`: `https://docs.aws.amazon.com/waf/latest/APIReference/API_GetWebACLForResource.html`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-wafv2`\n"
  },
  {
    "path": "content/aws/docs/workspaces/javascript/DOC.md",
    "content": "---\nname: workspaces\ndescription: \"AWS SDK for JavaScript v3 client for Amazon WorkSpaces directories, bundles, workspace lifecycle, and connection-status management\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,workspaces,javascript,nodejs,v3,desktop,virtual-desktop\"\n---\n\n# `@aws-sdk/client-workspaces`\n\nUse this package to manage Amazon WorkSpaces from JavaScript or TypeScript with AWS SDK v3. It covers the WorkSpaces control plane: listing directories and bundles, creating WorkSpaces, reading state, changing running mode, and starting, stopping, rebooting, or terminating desktops.\n\nThis is an infrastructure and admin client. It is not the end-user desktop application and it does not establish an interactive WorkSpaces session.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-workspaces\n```\n\nIf you want to load a named AWS profile in code, also install the credential provider helpers:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\nPrefer `WorkSpacesClient` plus explicit command imports. The package also exposes an aggregated `WorkSpaces` client, but command-based imports are the safer default for smaller bundles and clearer dependencies.\n\n## Prerequisites\n\nWorkSpaces is regional. Configure AWS credentials and a region before creating the client.\n\nTypical local setup:\n\n```bash\nexport AWS_REGION=\"us-west-2\"\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\" # optional\n\nexport WORKSPACES_DIRECTORY_ID=\"d-90670a1b1d\"\nexport WORKSPACES_BUNDLE_ID=\"wsb-abc123xyz\"\nexport WORKSPACES_USER_NAME=\"alice@example.com\"\nexport WORKSPACE_ID=\"ws-1234567890\"\n```\n\nIf you use shared AWS config locally, `AWS_PROFILE` also works with the standard AWS SDK for JavaScript v3 credential chain.\n\n## Client Setup\n\n### Minimal client\n\n```javascript\nimport { WorkSpacesClient } from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n```\n\n### Explicit credentials\n\n```javascript\nimport { WorkSpacesClient } from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: \"us-west-2\",\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN,\n  },\n});\n```\n\n### Named profile with `fromIni`\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { WorkSpacesClient } from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: \"us-west-2\",\n  credentials: fromIni({ profile: \"dev\" }),\n});\n```\n\nIn Node.js, the default credential provider chain is usually enough if AWS access already comes from environment variables, shared config files, ECS task credentials, EC2 instance metadata, or IAM Identity Center.\n\n## What This Client Covers\n\n`@aws-sdk/client-workspaces` is the management client for Amazon WorkSpaces operations such as:\n\n- discovering bundles and registered directories\n- listing WorkSpaces and reading their state\n- creating WorkSpaces for directory users\n- starting, stopping, rebooting, and terminating WorkSpaces\n- reading connection status for existing WorkSpaces\n- modifying WorkSpace properties such as running mode and auto-stop timeout\n\nMost application code uses a simple pattern: discover bundle and directory IDs, create or find a user WorkSpace, then manage its lifecycle with command calls.\n\n## Core Usage Pattern\n\nAWS SDK v3 uses `client.send(new Command(input))`.\n\n```javascript\nimport {\n  DescribeWorkspacesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst response = await workspaces.send(\n  new DescribeWorkspacesCommand({\n    DirectoryId: process.env.WORKSPACES_DIRECTORY_ID,\n    UserName: process.env.WORKSPACES_USER_NAME,\n  }),\n);\n\nfor (const workspace of response.Workspaces ?? []) {\n  console.log({\n    workspaceId: workspace.WorkspaceId,\n    userName: workspace.UserName,\n    state: workspace.State,\n    bundleId: workspace.BundleId,\n    computerName: workspace.ComputerName,\n  });\n}\n```\n\n`DescribeWorkspaces` accepts only one filter set at a time. `WorkspaceIds` cannot be combined with other filters, `BundleId` cannot be combined with other filters, and `UserName` must be used together with `DirectoryId`.\n\n## Common Workflows\n\n### List available bundles\n\nUse `Owner: \"AMAZON\"` for AWS-provided bundles, or your own account ID for custom bundles.\n\n```javascript\nimport {\n  DescribeWorkspaceBundlesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Bundles = [] } = await workspaces.send(\n  new DescribeWorkspaceBundlesCommand({\n    Owner: \"AMAZON\",\n  }),\n);\n\nfor (const bundle of Bundles) {\n  console.log({\n    bundleId: bundle.BundleId,\n    name: bundle.Name,\n    owner: bundle.Owner,\n    state: bundle.State,\n  });\n}\n```\n\n### List registered directories\n\n```javascript\nimport {\n  DescribeWorkspaceDirectoriesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { Directories = [] } = await workspaces.send(\n  new DescribeWorkspaceDirectoriesCommand({}),\n);\n\nfor (const directory of Directories) {\n  console.log({\n    directoryId: directory.DirectoryId,\n    directoryName: directory.DirectoryName,\n    workspaceDirectoryName: directory.WorkspaceDirectoryName,\n    registrationCode: directory.RegistrationCode,\n    state: directory.State,\n  });\n}\n```\n\n### Create a WorkSpace for one user\n\n`CreateWorkspaces` is asynchronous. Check `FailedRequests` immediately, then query the WorkSpace again to watch it move through `PENDING` toward a usable state.\n\n```javascript\nimport {\n  CreateWorkspacesCommand,\n  DescribeWorkspacesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst createResponse = await workspaces.send(\n  new CreateWorkspacesCommand({\n    Workspaces: [\n      {\n        DirectoryId: process.env.WORKSPACES_DIRECTORY_ID,\n        UserName: process.env.WORKSPACES_USER_NAME,\n        BundleId: process.env.WORKSPACES_BUNDLE_ID,\n        WorkspaceProperties: {\n          RunningMode: \"AUTO_STOP\",\n          RunningModeAutoStopTimeoutInMinutes: 60,\n        },\n        Tags: [\n          { Key: \"env\", Value: \"dev\" },\n          { Key: \"owner\", Value: \"platform-team\" },\n        ],\n      },\n    ],\n  }),\n);\n\nif ((createResponse.FailedRequests ?? []).length > 0) {\n  throw new Error(JSON.stringify(createResponse.FailedRequests, null, 2));\n}\n\nconst describeResponse = await workspaces.send(\n  new DescribeWorkspacesCommand({\n    DirectoryId: process.env.WORKSPACES_DIRECTORY_ID,\n    UserName: process.env.WORKSPACES_USER_NAME,\n  }),\n);\n\nconst workspace = describeResponse.Workspaces?.[0];\n\nconsole.log({\n  workspaceId: workspace?.WorkspaceId,\n  state: workspace?.State,\n});\n```\n\n### Start or stop a WorkSpace\n\nThese operations accept up to 25 WorkSpaces per call and return per-item failures in `FailedRequests`.\n\n```javascript\nimport {\n  StartWorkspacesCommand,\n  StopWorkspacesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst stopResponse = await workspaces.send(\n  new StopWorkspacesCommand({\n    StopWorkspaceRequests: [\n      {\n        WorkspaceId: process.env.WORKSPACE_ID,\n      },\n    ],\n  }),\n);\n\nif ((stopResponse.FailedRequests ?? []).length > 0) {\n  console.error(stopResponse.FailedRequests);\n}\n\nconst startResponse = await workspaces.send(\n  new StartWorkspacesCommand({\n    StartWorkspaceRequests: [\n      {\n        WorkspaceId: process.env.WORKSPACE_ID,\n      },\n    ],\n  }),\n);\n\nif ((startResponse.FailedRequests ?? []).length > 0) {\n  console.error(startResponse.FailedRequests);\n}\n```\n\nUse `StartWorkspaces` only when the WorkSpace is `STOPPED` and its running mode is `AUTO_STOP` or `MANUAL`. Use `StopWorkspaces` only when the WorkSpace is `AVAILABLE`, `IMPAIRED`, `UNHEALTHY`, or `ERROR`, and its running mode is `AUTO_STOP` or `MANUAL`.\n\n### Reboot or terminate a WorkSpace\n\n```javascript\nimport {\n  RebootWorkspacesCommand,\n  TerminateWorkspacesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst rebootResponse = await workspaces.send(\n  new RebootWorkspacesCommand({\n    RebootWorkspaceRequests: [\n      {\n        WorkspaceId: process.env.WORKSPACE_ID,\n      },\n    ],\n  }),\n);\n\nif ((rebootResponse.FailedRequests ?? []).length > 0) {\n  console.error(rebootResponse.FailedRequests);\n}\n\nawait workspaces.send(\n  new TerminateWorkspacesCommand({\n    TerminateWorkspaceRequests: [\n      {\n        WorkspaceId: process.env.WORKSPACE_ID,\n      },\n    ],\n  }),\n);\n```\n\n`TerminateWorkspaces` is permanent. The WorkSpace data is destroyed and the operation is asynchronous, so read the current state before and after termination if your workflow needs a clean teardown sequence.\n\n### Change running mode or auto-stop timeout\n\nUse `ModifyWorkspaceProperties` when you need to switch between `AUTO_STOP` and `ALWAYS_ON`, or when you need to update the auto-stop timeout. The timeout is configured in 60-minute intervals.\n\n```javascript\nimport {\n  ModifyWorkspacePropertiesCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nawait workspaces.send(\n  new ModifyWorkspacePropertiesCommand({\n    WorkspaceId: process.env.WORKSPACE_ID,\n    WorkspaceProperties: {\n      RunningMode: \"AUTO_STOP\",\n      RunningModeAutoStopTimeoutInMinutes: 120,\n    },\n  }),\n);\n```\n\nThe `MANUAL` running mode is only supported for Amazon WorkSpaces Core accounts that are allow-listed for it. Do not assume `MANUAL` is available in a general WorkSpaces deployment.\n\n### Check connection status\n\nUse this when you need to know whether users are currently connected, disconnected, or unknown from the service perspective.\n\n```javascript\nimport {\n  DescribeWorkspacesConnectionStatusCommand,\n  WorkSpacesClient,\n} from \"@aws-sdk/client-workspaces\";\n\nconst workspaces = new WorkSpacesClient({\n  region: process.env.AWS_REGION ?? \"us-west-2\",\n});\n\nconst { WorkspacesConnectionStatus = [] } = await workspaces.send(\n  new DescribeWorkspacesConnectionStatusCommand({\n    WorkspaceIds: [process.env.WORKSPACE_ID],\n  }),\n);\n\nfor (const item of WorkspacesConnectionStatus) {\n  console.log({\n    workspaceId: item.WorkspaceId,\n    connectionState: item.ConnectionState,\n    lastKnownUserConnectionTimestamp: item.LastKnownUserConnectionTimestamp,\n  });\n}\n```\n\nThis API accepts up to 25 WorkSpace IDs per call.\n\n## Common Pitfalls\n\n- `CreateWorkspaces`, `StartWorkspaces`, `StopWorkspaces`, `RebootWorkspaces`, and `TerminateWorkspaces` can succeed at the HTTP level while still returning per-WorkSpace failures in `FailedRequests`. Always inspect that field.\n- `CreateWorkspaces`, `RebootWorkspaces`, and `TerminateWorkspaces` are asynchronous. A returned response does not mean the desktop is already in its final state.\n- `DescribeWorkspaces` filter rules are strict: `WorkspaceIds` cannot be combined with other filters, `BundleId` cannot be combined with other filters, and `UserName` must be paired with `DirectoryId`.\n- `StartWorkspaces` and `StopWorkspaces` only work for `AUTO_STOP` or `MANUAL` running modes, and only in the documented states for each operation.\n- `RunningModeAutoStopTimeoutInMinutes` uses 60-minute increments. Do not assume arbitrary minute values are accepted.\n- `TerminateWorkspaces` permanently destroys user data. Archive what you need before sending that request.\n- `MANUAL` running mode is not generally available; it is documented as a WorkSpaces Core feature that requires allow-list access.\n\n## Version Notes For `3.1007.0`\n\n- This guide targets `@aws-sdk/client-workspaces@3.1007.0`.\n- The AWS SDK for JavaScript v3 documentation is published under a rolling `latest` URL. Pin the npm package version in your application if you need stable dependency resolution.\n- The current WorkSpaces API surface includes paginated describe operations for bundles, directories, WorkSpaces, and connection status, plus batch lifecycle operations that accept up to 25 request items per call.\n\n## Official Sources\n\n- AWS SDK for JavaScript v3 WorkSpaces client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/workspaces/`\n- AWS SDK for JavaScript v3 credential configuration for Node.js: `https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html`\n- Amazon WorkSpaces running mode guide: `https://docs.aws.amazon.com/workspaces/latest/adminguide/running-mode.html`\n- Amazon WorkSpaces modify WorkSpaces guide: `https://docs.aws.amazon.com/workspaces/latest/adminguide/modify-workspaces.html`\n- Amazon WorkSpaces protocols guide: `https://docs.aws.amazon.com/workspaces/latest/adminguide/amazon-workspaces-protocols.html`\n- npm package: `https://www.npmjs.com/package/@aws-sdk/client-workspaces`\n"
  },
  {
    "path": "content/aws/docs/xray/javascript/DOC.md",
    "content": "---\nname: xray\ndescription: \"AWS SDK for JavaScript v3 client for querying traces, service graphs, groups, sampling rules, encryption settings, and raw trace ingestion in AWS X-Ray\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1007.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"aws,xray,tracing,observability,javascript,nodejs,sdk\"\n---\n\n# AWS X-Ray SDK for JavaScript (v3)\n\nUse `@aws-sdk/client-xray` when your code needs direct access to the AWS X-Ray API from JavaScript or TypeScript. Common uses are querying traces for a time window, loading full trace documents, building service graphs, managing groups and sampling rules, checking encryption settings, and sending raw segment or telemetry data.\n\nThis package is usually used from trusted backend code, admin tools, or custom tracing infrastructure.\n\n## Install\n\n```bash\nnpm install @aws-sdk/client-xray\n```\n\nIf you want to select a shared AWS profile explicitly in code, also install the credential helpers:\n\n```bash\nnpm install @aws-sdk/credential-providers\n```\n\n## Prerequisites\n\nX-Ray is regional. Use the same AWS region where your traces, groups, and sampling rules live.\n\nTypical local environment setup:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=your-access-key-id\nexport AWS_SECRET_ACCESS_KEY=your-secret-access-key\nexport AWS_SESSION_TOKEN=your-session-token\n```\n\nIf you use shared AWS config instead of raw keys:\n\n```bash\nexport AWS_REGION=us-east-1\nexport AWS_PROFILE=your-profile\n```\n\n`AWS_SESSION_TOKEN` is only required for temporary credentials.\n\n## Initialize the client\n\nUse the default AWS SDK v3 credential chain when your environment is already configured:\n\n```javascript\nimport { XRayClient } from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n```\n\nIf you want to force a named shared profile in Node.js:\n\n```javascript\nimport { fromIni } from \"@aws-sdk/credential-providers\";\nimport { XRayClient } from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n  credentials: fromIni({\n    profile: process.env.AWS_PROFILE ?? \"default\",\n  }),\n});\n```\n\n## Query trace summaries\n\n`GetTraceSummaries` is the normal starting point when you want traces from a specific time window. `StartTime` and `EndTime` are required.\n\n```javascript\nimport {\n  GetTraceSummariesCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({\n  region: process.env.AWS_REGION ?? \"us-east-1\",\n});\n\nasync function getRecentTraceSummaries() {\n  const endTime = new Date();\n  const startTime = new Date(endTime.getTime() - 15 * 60 * 1000);\n\n  const response = await xray.send(\n    new GetTraceSummariesCommand({\n      StartTime: startTime,\n      EndTime: endTime,\n    }),\n  );\n\n  for (const summary of response.TraceSummaries ?? []) {\n    console.log({\n      id: summary.Id,\n      startTime: summary.StartTime,\n      duration: summary.Duration,\n      hasError: summary.HasError,\n      hasFault: summary.HasFault,\n      hasThrottle: summary.HasThrottle,\n    });\n  }\n\n  return response.TraceSummaries ?? [];\n}\n```\n\nIf a query spans multiple pages, call the same command again with `NextToken`.\n\n```javascript\nimport {\n  GetTraceSummariesCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function listAllTraceSummaries(startTime, endTime) {\n  const traceSummaries = [];\n  let nextToken;\n\n  do {\n    const response = await xray.send(\n      new GetTraceSummariesCommand({\n        StartTime: startTime,\n        EndTime: endTime,\n        NextToken: nextToken,\n      }),\n    );\n\n    traceSummaries.push(...(response.TraceSummaries ?? []));\n    nextToken = response.NextToken;\n  } while (nextToken);\n\n  return traceSummaries;\n}\n```\n\n## Load full traces by ID\n\n`BatchGetTraces` loads the trace documents for one or more trace IDs. Each returned segment document is a JSON string, so parse it before you inspect fields.\n\n```javascript\nimport {\n  BatchGetTracesCommand,\n  GetTraceSummariesCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function getFullTracesForLast15Minutes() {\n  const endTime = new Date();\n  const startTime = new Date(endTime.getTime() - 15 * 60 * 1000);\n\n  const summaries = await xray.send(\n    new GetTraceSummariesCommand({\n      StartTime: startTime,\n      EndTime: endTime,\n    }),\n  );\n\n  const traceIds = (summaries.TraceSummaries ?? [])\n    .map((summary) => summary.Id)\n    .filter(Boolean);\n\n  if (traceIds.length === 0) {\n    return [];\n  }\n\n  const traces = await xray.send(\n    new BatchGetTracesCommand({\n      TraceIds: traceIds,\n    }),\n  );\n\n  return (traces.Traces ?? []).map((trace) => ({\n    id: trace.Id,\n    duration: trace.Duration,\n    segments: (trace.Segments ?? [])\n      .filter((segment) => typeof segment.Document === \"string\")\n      .map((segment) => JSON.parse(segment.Document)),\n  }));\n}\n```\n\n## Build a service graph\n\n`GetServiceGraph` returns the services involved in the selected time window. You can scope the graph to a group with `GroupName` or `GroupARN`.\n\n```javascript\nimport {\n  GetServiceGraphCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function getServiceGraph() {\n  const endTime = new Date();\n  const startTime = new Date(endTime.getTime() - 15 * 60 * 1000);\n\n  const response = await xray.send(\n    new GetServiceGraphCommand({\n      StartTime: startTime,\n      EndTime: endTime,\n      GroupName: \"AdminGroup\",\n    }),\n  );\n\n  for (const service of response.Services ?? []) {\n    console.log({\n      name: service.Name,\n      type: service.Type,\n      state: service.State,\n    });\n  }\n\n  return response.Services ?? [];\n}\n```\n\n## Create and update groups\n\nGroups let you save a filter expression and reuse it in X-Ray queries. `CreateGroup` requires `GroupName`. `UpdateGroup` can target a group by name or ARN.\n\n```javascript\nimport {\n  CreateGroupCommand,\n  GetGroupsCommand,\n  UpdateGroupCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function manageGroups() {\n  await xray.send(\n    new CreateGroupCommand({\n      GroupName: \"AdminGroup\",\n      FilterExpression: 'service(\"mydomain.com\") {fault OR error}',\n      InsightsConfiguration: {\n        InsightsEnabled: true,\n        NotificationsEnabled: true,\n      },\n    }),\n  );\n\n  await xray.send(\n    new UpdateGroupCommand({\n      GroupName: \"AdminGroup\",\n      FilterExpression: 'service(\"mydomain.com\") {fault}',\n    }),\n  );\n\n  const response = await xray.send(new GetGroupsCommand({}));\n  return response.Groups ?? [];\n}\n```\n\n## Inspect and update sampling rules\n\nUse `GetSamplingRules` to inspect current rules. `CreateSamplingRule` requires the full rule shape. `UpdateSamplingRule` only needs the fields you want to change.\n\n```javascript\nimport {\n  CreateSamplingRuleCommand,\n  GetSamplingRulesCommand,\n  UpdateSamplingRuleCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function manageSamplingRules() {\n  const currentRules = await xray.send(new GetSamplingRulesCommand({}));\n\n  await xray.send(\n    new CreateSamplingRuleCommand({\n      SamplingRule: {\n        RuleName: \"base-scorekeep\",\n        ResourceARN: \"*\",\n        Priority: 9000,\n        FixedRate: 0.1,\n        ReservoirSize: 5,\n        ServiceName: \"Scorekeep\",\n        ServiceType: \"*\",\n        Host: \"*\",\n        HTTPMethod: \"*\",\n        URLPath: \"*\",\n        Version: 1,\n      },\n    }),\n  );\n\n  await xray.send(\n    new UpdateSamplingRuleCommand({\n      SamplingRuleUpdate: {\n        RuleName: \"Default\",\n        FixedRate: 0.01,\n        ReservoirSize: 0,\n      },\n    }),\n  );\n\n  return currentRules.SamplingRuleRecords ?? [];\n}\n```\n\nIf you are implementing your own sampler, `GetSamplingTargets` requires one or more `SamplingStatisticsDocuments` entries that report rule usage.\n\n```javascript\nimport {\n  GetSamplingTargetsCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function getSamplingTargets() {\n  const response = await xray.send(\n    new GetSamplingTargetsCommand({\n      SamplingStatisticsDocuments: [\n        {\n          RuleName: \"base-scorekeep\",\n          ClientID: \"ABCDEF1234567890ABCDEF10\",\n          Timestamp: new Date(),\n          RequestCount: 110,\n          SampledCount: 20,\n          BorrowCount: 10,\n        },\n      ],\n    }),\n  );\n\n  return response.SamplingTargetDocuments ?? [];\n}\n```\n\n## Upload raw trace segments\n\n`PutTraceSegments` is the low-level ingestion API. Pass one or more JSON strings in `TraceSegmentDocuments`.\n\n```javascript\nimport {\n  PutTraceSegmentsCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function putTraceSegment() {\n  const segmentDocument = {\n    id: \"20312a0e2b8809f4\",\n    name: \"DynamoDB\",\n    trace_id: \"1-5832862d-a43aafded3334a971fe312db\",\n    start_time: 1479706157.195,\n    end_time: 1479706157.202,\n    parent_id: \"79736b962fe3239e\",\n    inferred: true,\n    http: {\n      response: {\n        content_length: 60,\n        status: 200,\n      },\n    },\n    aws: {\n      consistent_read: false,\n      table_name: \"scorekeep-session-xray\",\n      operation: \"GetItem\",\n      request_id: \"SCAU23OM6M8FO38UASGC7785ARVV4KQNSO5AEMVJF66Q9ASUAAJG\",\n      resource_names: [\"scorekeep-session-xray\"],\n    },\n    origin: \"AWS::DynamoDB::Table\",\n  };\n\n  const response = await xray.send(\n    new PutTraceSegmentsCommand({\n      TraceSegmentDocuments: [JSON.stringify(segmentDocument)],\n    }),\n  );\n\n  return response.UnprocessedTraceSegments ?? [];\n}\n```\n\nIf X-Ray rejects a segment, inspect `UnprocessedTraceSegments` for the error code and message.\n\n## Send telemetry records\n\n`PutTelemetryRecords` is the companion low-level API for reporting segment delivery counts and backend connection errors.\n\n```javascript\nimport {\n  PutTelemetryRecordsCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function putTelemetry() {\n  await xray.send(\n    new PutTelemetryRecordsCommand({\n      Hostname: \"checkout-api-1\",\n      TelemetryRecords: [\n        {\n          Timestamp: new Date(),\n          SegmentsReceivedCount: 100,\n          SegmentsSentCount: 100,\n          SegmentsRejectedCount: 0,\n          BackendConnectionErrors: {\n            TimeoutCount: 0,\n            ConnectionRefusedCount: 0,\n            HTTPCode4XXCount: 0,\n            HTTPCode5XXCount: 0,\n          },\n        },\n      ],\n    }),\n  );\n}\n```\n\n## Check or change encryption settings\n\nUse `GetEncryptionConfig` to inspect the current mode. Use `PutEncryptionConfig` to switch to KMS-backed encryption or back to the default service-managed mode.\n\n```javascript\nimport {\n  GetEncryptionConfigCommand,\n  PutEncryptionConfigCommand,\n  XRayClient,\n} from \"@aws-sdk/client-xray\";\n\nconst xray = new XRayClient({ region: process.env.AWS_REGION ?? \"us-east-1\" });\n\nasync function configureEncryption() {\n  const current = await xray.send(new GetEncryptionConfigCommand({}));\n  console.log(current.EncryptionConfig);\n\n  const updated = await xray.send(\n    new PutEncryptionConfigCommand({\n      Type: \"KMS\",\n      KeyId: \"alias/aws/xray\",\n    }),\n  );\n\n  return updated.EncryptionConfig;\n}\n```\n\n## Common pitfalls\n\n- `PutTraceSegmentsCommand` expects JSON strings in `TraceSegmentDocuments`, not plain JavaScript objects.\n- `BatchGetTracesCommand` returns each segment `Document` as a JSON string; parse it with `JSON.parse` before reading fields.\n- `GetTraceSummariesCommand` and `GetServiceGraphCommand` both require `StartTime` and `EndTime`.\n- `CreateSamplingRuleCommand` requires the full sampling rule shape, including `ResourceARN`, `Priority`, `FixedRate`, `ReservoirSize`, `ServiceName`, `ServiceType`, `Host`, `HTTPMethod`, `URLPath`, and `Version`.\n- Many X-Ray read APIs paginate with `NextToken`, including `GetTraceSummaries`, `BatchGetTraces`, `GetServiceGraph`, `GetGroups`, and `GetSamplingRules`.\n- X-Ray resources are regional. If a query unexpectedly returns nothing, confirm that the client region matches the region where the traces or groups were created.\n\n## Useful links\n\n- AWS SDK for JavaScript v3 X-Ray client docs: `https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/xray/`\n- AWS X-Ray API tutorial: `https://docs.aws.amazon.com/xray/latest/devguide/xray-api-tutorial.html`\n- AWS X-Ray sampling rules guide: `https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sampling.html`\n- AWS X-Ray configuration guide: `https://docs.aws.amazon.com/xray/latest/devguide/xray-api-configuration.html`\n- Sending trace data to AWS X-Ray: `https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-segments`\n"
  },
  {
    "path": "content/axios/docs/axios/javascript/DOC.md",
    "content": "---\nname: axios\ndescription: \"Axios HTTP client for JavaScript in browsers and Node.js, including reusable instances, interceptors, cancellation, and error handling.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.13.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"axios,http,client,requests,node,browser\"\n---\n\n# Axios JavaScript Guide\n\n## Golden Rule\n\nUse `axios` itself as the HTTP client and create a reusable instance with `axios.create()` for app-wide defaults.\n\nAxios works in browsers and Node.js, supports request/response interceptors, accepts `AbortController` signals for cancellation, and rejects requests outside the success range unless you change `validateStatus`.\n\n## Install\n\nInstall the runtime package with your normal package manager:\n\n```bash\nnpm install axios\n```\n\n```bash\npnpm add axios\n```\n\n```bash\nyarn add axios\n```\n\nAxios does not require package-specific environment variables. Keep API URLs and credentials in your application config instead:\n\n```bash\nexport API_BASE_URL=\"https://api.example.com\"\nexport API_TOKEN=\"replace-me\"\nexport API_USERNAME=\"replace-me\"\nexport API_PASSWORD=\"replace-me\"\n```\n\n## Import and Initialize\n\nUse a shared client instance so base URL, timeout, and default headers live in one place.\n\n```javascript\nimport axios from \"axios\";\n\nconst api = axios.create({\n  baseURL: process.env.API_BASE_URL ?? \"https://api.example.com\",\n  timeout: 10_000,\n  headers: {\n    Accept: \"application/json\",\n    \"Content-Type\": \"application/json\",\n  },\n});\n\nconst apiToken = process.env.API_TOKEN;\n\napi.interceptors.request.use((config) => {\n  if (apiToken) {\n    config.headers.Authorization = `Bearer ${apiToken}`;\n  }\n\n  return config;\n});\n\nexport default api;\n```\n\nIf your project uses CommonJS, import Axios like this instead:\n\n```javascript\nconst axios = require(\"axios\");\n```\n\n## Common Workflows\n\n### Send a `GET` request with query parameters\n\nPass query string values with the `params` option. Axios serializes them onto the request URL.\n\n```javascript\nimport api from \"./api.js\";\n\nexport async function listUsers() {\n  const response = await api.get(\"/users\", {\n    params: {\n      page: 1,\n      limit: 25,\n      role: \"admin\",\n    },\n  });\n\n  return response.data;\n}\n```\n\n### Send JSON with `POST`\n\nPass a plain object as the second argument to `post()`. Axios serializes the body as JSON by default.\n\n```javascript\nimport api from \"./api.js\";\n\nexport async function createUser() {\n  const response = await api.post(\"/users\", {\n    email: \"alice@example.com\",\n    role: \"admin\",\n  });\n\n  return response.data;\n}\n```\n\n### Use per-request configuration\n\nRequest config can override timeout, headers, auth, and status handling for a single call.\n\n```javascript\nimport api from \"./api.js\";\n\nexport async function fetchHealthcheck() {\n  const response = await api.get(\"/health\", {\n    timeout: 2_000,\n    validateStatus: (status) => status < 500,\n  });\n\n  return {\n    status: response.status,\n    data: response.data,\n  };\n}\n```\n\nUse `validateStatus` when you want some non-2xx responses to resolve normally instead of throwing.\n\n### Send HTTP Basic auth\n\nUse the `auth` option when the server expects HTTP Basic auth.\n\n```javascript\nimport api from \"./api.js\";\n\nexport async function getAccount() {\n  const response = await api.get(\"/account\", {\n    auth: {\n      username: process.env.API_USERNAME,\n      password: process.env.API_PASSWORD,\n    },\n  });\n\n  return response.data;\n}\n```\n\n### Handle errors with `axios.isAxiosError`\n\nAxios errors can include a server response, a sent request with no response, or a setup failure before the request was sent.\n\n```javascript\nimport axios from \"axios\";\nimport api from \"./api.js\";\n\nexport async function deleteUser(userId) {\n  try {\n    await api.delete(`/users/${userId}`);\n  } catch (error) {\n    if (axios.isAxiosError(error)) {\n      if (error.response) {\n        throw new Error(\n          `Request failed with ${error.response.status}: ${JSON.stringify(error.response.data)}`,\n        );\n      }\n\n      if (error.request) {\n        throw new Error(\"Request sent but no response was received\");\n      }\n\n      throw new Error(error.message);\n    }\n\n    throw error;\n  }\n}\n```\n\nIf you need a plain object for logging, call `error.toJSON()` on an Axios error.\n\n### Cancel a request with `AbortController`\n\nPass `signal` in request config and abort through the platform `AbortController`.\n\n```javascript\nimport api from \"./api.js\";\n\nexport async function searchUsers(query) {\n  const controller = new AbortController();\n\n  const request = api.get(\"/users/search\", {\n    params: { q: query },\n    signal: controller.signal,\n  });\n\n  setTimeout(() => controller.abort(), 250);\n\n  return request;\n}\n```\n\nUse `signal` for new code. Axios documents `CancelToken` as deprecated.\n\n### Download a file in Node.js\n\nWhen you need a Node.js stream instead of parsed JSON, set `responseType: \"stream\"`.\n\n```javascript\nimport fs from \"node:fs\";\nimport api from \"./api.js\";\n\nexport async function downloadReport() {\n  const response = await api.get(\"/reports/daily.csv\", {\n    responseType: \"stream\",\n  });\n\n  const writer = fs.createWriteStream(\"daily.csv\");\n  response.data.pipe(writer);\n\n  await new Promise((resolve, reject) => {\n    writer.on(\"finish\", resolve);\n    writer.on(\"error\", reject);\n  });\n}\n```\n\n## Interceptors\n\nInterceptors are the standard place to add auth headers, trace IDs, response transforms, or centralized retry/refresh handling.\n\n```javascript\nimport axios from \"axios\";\n\nconst api = axios.create({\n  baseURL: process.env.API_BASE_URL,\n});\n\napi.interceptors.request.use((config) => {\n  config.headers = config.headers ?? {};\n  config.headers[\"X-Request-Id\"] = String(Date.now());\n  return config;\n});\n\napi.interceptors.response.use(\n  (response) => response,\n  async (error) => {\n    if (error.response?.status === 401) {\n      // Refresh credentials or redirect to login here.\n    }\n\n    return Promise.reject(error);\n  },\n);\n```\n\nKeep interceptor logic focused. Avoid hiding large amounts of application behavior inside global request hooks.\n\n## Important Pitfalls\n\n- `axios.create()` gives you an isolated client with its own defaults and interceptors; changing one instance does not update another.\n- `auth` is for HTTP Basic auth. It sets the `Authorization` header and can overwrite a custom `Authorization` header you set manually.\n- Axios rejects responses outside the default success range. If you expect `404`, `409`, or similar statuses in normal control flow, set `validateStatus` for that request or instance.\n- `axios.isAxiosError()` narrows the error type, but `error.response` is still undefined for network failures, timeouts, and cancellations.\n- Prefer `signal` with `AbortController` for cancellation. `CancelToken` is deprecated.\n- In Node.js, use `responseType: \"stream\"` when you want a readable stream instead of buffered response data.\n\n## Version-Sensitive Notes\n\n- This guide targets `axios@1.13.6`.\n- The documented request patterns here use the current Axios 1.x APIs: `axios.create()`, interceptor hooks, request config objects, `validateStatus`, and `AbortController`-based cancellation.\n- For TypeScript projects, install only `axios`; its type definitions are bundled with the runtime package.\n\n## Official Sources\n\n- https://axios-http.com/docs/intro\n- https://axios-http.com/docs/instance\n- https://axios-http.com/docs/req_config\n- https://axios-http.com/docs/interceptors\n- https://axios-http.com/docs/handling_errors\n- https://axios-http.com/docs/cancellation\n- https://www.npmjs.com/package/axios\n"
  },
  {
    "path": "content/azure/docs/abort-controller/javascript/DOC.md",
    "content": "---\nname: abort-controller\ndescription: \"@azure/abort-controller guide for JavaScript abort error handling and platform AbortController usage\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.1.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,abort-controller,javascript,abort,abortsignal,cancellation\"\n---\n\n# @azure/abort-controller JavaScript Package Guide\n\n## What It Is\n\n`@azure/abort-controller` is a small Azure SDK support package for cancellation flows.\n\nIn `2.1.2`, the published JavaScript entry point exports `AbortError`. Use the platform `AbortController` and `AbortSignal` provided by Node.js, browsers, or React Native for the controller and signal objects themselves.\n\nUse this package when:\n\n- the codebase already imports `AbortError` from `@azure/abort-controller`\n- you want your own async helpers to reject with an Azure-style abort error\n- you need one cancellation pattern that works alongside other Azure SDK packages\n\nThis guide targets package version `2.1.2`.\n\n## Install\n\n```bash\nnpm install @azure/abort-controller@2.1.2\n```\n\n`2.1.2` declares `node >=18.0.0` in the published package metadata.\n\nThe package also publishes browser, React Native, ESM, and CommonJS entry points through conditional exports.\n\n## Initialization And Configuration\n\nThere is no client object, endpoint, authentication step, or required environment variable.\n\nTypical imports:\n\n```js\nimport { AbortError } from \"@azure/abort-controller\";\n\nconst controller = new AbortController();\nconst { signal } = controller;\n```\n\nIf you only need to create or pass a signal, the platform `AbortController` is enough. Import `AbortError` when you want to throw or normalize an abort-specific error in your own code.\n\n## Common Workflows\n\n### Reject your own async work with `AbortError`\n\nUse `AbortError` when you build an async helper that should stop immediately after cancellation.\n\n```js\nimport { AbortError } from \"@azure/abort-controller\";\n\nfunction waitForReady({ signal, timeoutInMs = 5_000 } = {}) {\n  return new Promise((resolve, reject) => {\n    if (signal?.aborted) {\n      reject(new AbortError(\"The operation was aborted.\"));\n      return;\n    }\n\n    const timer = setTimeout(() => {\n      cleanup();\n      resolve(\"ready\");\n    }, timeoutInMs);\n\n    const onAbort = () => {\n      cleanup();\n      reject(new AbortError(\"The operation was aborted.\"));\n    };\n\n    const cleanup = () => {\n      clearTimeout(timer);\n      signal?.removeEventListener(\"abort\", onAbort);\n    };\n\n    signal?.addEventListener(\"abort\", onAbort, { once: true });\n  });\n}\n\nconst controller = new AbortController();\nsetTimeout(() => controller.abort(), 250);\n\ntry {\n  await waitForReady({ signal: controller.signal, timeoutInMs: 2_000 });\n} catch (error) {\n  if (error?.name === \"AbortError\") {\n    console.log(\"Cancelled cleanly\");\n  } else {\n    throw error;\n  }\n}\n```\n\nThe package documentation for `AbortError` recommends checking `error.name === \"AbortError\"` when handling cancellation.\n\n### Cancel platform APIs with `AbortController`\n\n`@azure/abort-controller` does not replace the runtime controller. Create a normal `AbortController`, pass its signal into an abort-aware API, and treat `AbortError` as the cancellation case.\n\n```js\nconst controller = new AbortController();\n\nconst timeout = setTimeout(() => {\n  controller.abort();\n}, 1_000);\n\ntry {\n  const response = await fetch(\"https://example.com/api/tasks\", {\n    signal: controller.signal,\n  });\n\n  const data = await response.json();\n  console.log(data);\n} catch (error) {\n  if (error?.name === \"AbortError\") {\n    console.log(\"Request cancelled\");\n  } else {\n    throw error;\n  }\n} finally {\n  clearTimeout(timeout);\n}\n```\n\nUse the same pattern when another library accepts an `AbortSignal`.\n\n### Fail fast when a signal is already aborted\n\nIf your helper takes a signal, check the aborted state before you start new work.\n\n```js\nimport { AbortError } from \"@azure/abort-controller\";\n\nfunction throwIfAborted(signal) {\n  if (signal?.aborted) {\n    throw new AbortError(\"The operation was aborted before it started.\");\n  }\n}\n\nfunction startJob(signal) {\n  throwIfAborted(signal);\n  return { started: true };\n}\n\nconst controller = new AbortController();\ncontroller.abort();\n\ntry {\n  startJob(controller.signal);\n} catch (error) {\n  if (error?.name === \"AbortError\") {\n    console.log(\"Skipped cancelled job\");\n  }\n}\n```\n\nThis avoids starting timers, requests, or listeners for work that the caller already cancelled.\n\n## Practical Notes\n\n- Prefer the runtime `AbortController` and `AbortSignal` APIs in Node.js 18+, browsers, and React Native.\n- Import `AbortError` when you need to reject your own promise-based helpers with a consistent cancellation error.\n- Check `error.name === \"AbortError\"` when interoperating with platform APIs and Azure helpers, since cancellation errors do not always share the same concrete class.\n- Keep one parent signal and pass it through nested helpers so cancellation reaches every layer.\n\n## Common Pitfalls\n\n- Expecting `@azure/abort-controller` to provide a runtime `AbortController` implementation in Node.js 18+ projects.\n- Catching only `instanceof AbortError` instead of handling the broader `error.name === \"AbortError\"` case.\n- Starting work after `signal.aborted` is already `true`.\n- Forgetting that this package does not configure retries, timeouts, or HTTP requests by itself.\n\n## Version Notes For 2.1.2\n\n- This guide targets `@azure/abort-controller` `2.1.2`.\n- The published package metadata requires Node.js `>=18.0.0`.\n- The package publishes conditional exports for browser, React Native, ESM, and CommonJS consumers.\n- The published JavaScript entry point exports `AbortError`.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/abort-controller/`\n- npm package page: `https://www.npmjs.com/package/@azure/abort-controller`\n- Azure SDK for JavaScript package homepage: `https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md`\n"
  },
  {
    "path": "content/azure/docs/ai-form-recognizer/javascript/DOC.md",
    "content": "---\nname: ai-form-recognizer\ndescription: \"Azure Form Recognizer JavaScript SDK guide for authentication, document analysis, custom models, and version boundaries\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,document-intelligence,form-recognizer,ocr,document-analysis,javascript,sdk\"\n---\n\n# Azure Form Recognizer JavaScript SDK\n\n## What This Package Covers\n\n`@azure/ai-form-recognizer` is the Azure SDK package for JavaScript and TypeScript apps that call Azure Form Recognizer, now branded as Azure Document Intelligence.\n\nUse it when you need to:\n\n- analyze PDFs or images with prebuilt models such as layout, general document, invoice, and receipt\n- extract structured fields from your own custom document models\n- build, list, and delete custom document models\n- use either API-key auth or Microsoft Entra ID auth from Node.js apps\n\nFor new code on `5.1.0`, the main clients are:\n\n```js\nimport {\n  DocumentAnalysisClient,\n  DocumentModelAdministrationClient,\n} from \"@azure/ai-form-recognizer\";\n```\n\nLegacy clients such as `FormRecognizerClient` and `FormTrainingClient` still exist for older integrations, but they are not the client surface to start from for new `5.x` code.\n\n## Install\n\nInstall the SDK version your app expects:\n\n```bash\nnpm install @azure/ai-form-recognizer@5.1.0\n```\n\nIf you want Microsoft Entra ID authentication, also install `@azure/identity`:\n\n```bash\nnpm install @azure/ai-form-recognizer@5.1.0 @azure/identity\n```\n\n## Required Setup\n\nYou need:\n\n1. an Azure Form Recognizer or Cognitive Services resource\n2. the resource endpoint\n3. either an API key or an Entra ID credential\n\nTypical environment variables:\n\n```bash\nexport AZURE_FORM_RECOGNIZER_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport AZURE_FORM_RECOGNIZER_KEY=\"<api-key>\"\nexport FORM_RECOGNIZER_TRAINING_DATA_SAS_URL=\"https://<storage-account>.blob.core.windows.net/<container>?<sas>\"\n```\n\nEndpoint rules that matter:\n\n- API-key auth works with a regional endpoint or a custom subdomain endpoint\n- Microsoft Entra ID auth requires a custom subdomain endpoint such as `https://<resource-name>.cognitiveservices.azure.com/`\n- do not use a regional endpoint such as `https://<region>.api.cognitive.microsoft.com/` with `DefaultAzureCredential`\n\n## Authentication And Client Initialization\n\n### API key authentication\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentAnalysisClient,\n} from \"@azure/ai-form-recognizer\";\n\nconst endpoint = process.env.AZURE_FORM_RECOGNIZER_ENDPOINT;\nconst apiKey = process.env.AZURE_FORM_RECOGNIZER_KEY;\n\nconst analysisClient = new DocumentAnalysisClient(\n  endpoint,\n  new AzureKeyCredential(apiKey),\n);\n```\n\n### Microsoft Entra ID authentication\n\nUse this when your app already runs with Azure CLI login, a managed identity, or a service principal.\n\n```js\nimport { DocumentAnalysisClient } from \"@azure/ai-form-recognizer\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst analysisClient = new DocumentAnalysisClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new DefaultAzureCredential(),\n);\n```\n\nThe calling principal needs access to the resource, and the official docs call out the `Cognitive Services User` role for this scenario.\n\n### Administration client\n\nUse a separate long-lived admin client when you need custom model operations:\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentModelAdministrationClient,\n} from \"@azure/ai-form-recognizer\";\n\nconst adminClient = new DocumentModelAdministrationClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n```\n\n## Client Selection\n\nUse this mapping:\n\n- `DocumentAnalysisClient`: analyze documents with prebuilt, custom, or classifier-backed models\n- `DocumentModelAdministrationClient`: build, inspect, list, and delete custom document models\n- `FormRecognizerClient`: legacy analysis client for older code paths\n- `FormTrainingClient`: legacy training client for older code paths\n\nIf the codebase already uses methods with names like `beginRecognizeReceipts`, `beginRecognizeBusinessCards`, or `beginTrainCustomModel`, treat that as a migration task instead of swapping names mechanically.\n\n## Common Analysis Workflows\n\nEvery `begin*` method is a long-running operation. It returns a poller, and you usually finish with `await poller.pollUntilDone()`.\n\n### Analyze a local file with a prebuilt invoice model\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentAnalysisClient,\n} from \"@azure/ai-form-recognizer\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new DocumentAnalysisClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n\nconst poller = await client.beginAnalyzeDocument(\n  \"prebuilt-invoice\",\n  createReadStream(\"./invoice.pdf\"),\n);\n\nconst result = await poller.pollUntilDone();\nconst invoice = result.documents?.[0];\n\nfor (const [name, field] of Object.entries(invoice?.fields ?? {})) {\n  console.log(name, field.content);\n}\n```\n\nUse prebuilt model IDs when you want the service to apply Azure's built-in document understanding instead of your own trained model.\n\n### Extract layout, lines, and tables from a document\n\nUse `prebuilt-layout` when you need OCR text, reading order, page structure, selection marks, or tables rather than business fields.\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentAnalysisClient,\n} from \"@azure/ai-form-recognizer\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new DocumentAnalysisClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n\nconst poller = await client.beginAnalyzeDocument(\n  \"prebuilt-layout\",\n  createReadStream(\"./document.pdf\"),\n);\n\nconst result = await poller.pollUntilDone();\n\nfor (const page of result.pages ?? []) {\n  console.log(`Page ${page.pageNumber}`);\n\n  for (const line of page.lines ?? []) {\n    console.log(line.content);\n  }\n}\n\nfor (const table of result.tables ?? []) {\n  console.log(`Table with ${table.rowCount} rows and ${table.columnCount} columns`);\n}\n```\n\n### Analyze a document from a URL\n\nUse the URL-based overload only when Azure can fetch the document directly.\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentAnalysisClient,\n} from \"@azure/ai-form-recognizer\";\n\nconst client = new DocumentAnalysisClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n\nconst poller = await client.beginAnalyzeDocumentFromUrl(\n  \"prebuilt-document\",\n  \"https://example.com/sample.pdf\",\n);\n\nconst result = await poller.pollUntilDone();\nconsole.log(result.documents?.length ?? 0);\n```\n\nIf the file lives in private Azure Blob Storage, pass a SAS URL or download the bytes yourself and call `beginAnalyzeDocument(...)` with a stream or buffer instead.\n\n### Run a custom model by model ID\n\nAfter you build a custom model, pass its model ID into the same analysis client.\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentAnalysisClient,\n} from \"@azure/ai-form-recognizer\";\nimport { createReadStream } from \"node:fs\";\n\nconst client = new DocumentAnalysisClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n\nconst poller = await client.beginAnalyzeDocument(\n  \"invoice-model-v1\",\n  createReadStream(\"./sample-invoice.pdf\"),\n);\n\nconst result = await poller.pollUntilDone();\nconst document = result.documents?.[0];\n\nconsole.log(document?.docType);\nfor (const [name, field] of Object.entries(document?.fields ?? {})) {\n  console.log(name, field.content);\n}\n```\n\n## Custom Model Administration\n\nUse `DocumentModelAdministrationClient` when you need to train or inventory custom models.\n\n### Build a custom document model from Azure Blob Storage\n\nTraining data lives in Azure Blob Storage and is typically passed as a container SAS URL.\n\n```js\nimport {\n  AzureKeyCredential,\n  DocumentModelAdministrationClient,\n} from \"@azure/ai-form-recognizer\";\n\nconst adminClient = new DocumentModelAdministrationClient(\n  process.env.AZURE_FORM_RECOGNIZER_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_FORM_RECOGNIZER_KEY),\n);\n\nconst poller = await adminClient.beginBuildDocumentModel(\n  \"template\",\n  process.env.FORM_RECOGNIZER_TRAINING_DATA_SAS_URL,\n  {\n    modelId: \"invoice-model-v1\",\n    description: \"Custom invoice extractor\",\n  },\n);\n\nconst model = await poller.pollUntilDone();\n\nconsole.log(model.modelId);\nconsole.log(model.description);\n```\n\nUse `\"template\"` or `\"neural\"` build modes according to the training and accuracy tradeoffs described in the official docs.\n\n### List existing custom models\n\n```js\nfor await (const model of adminClient.listDocumentModels()) {\n  console.log(model.modelId, model.createdOn);\n}\n```\n\n### Delete a custom model\n\n```js\nawait adminClient.deleteDocumentModel(\"invoice-model-v1\");\n```\n\n## Configuration And Compatibility Notes\n\n### Service version boundary\n\n`@azure/ai-form-recognizer@5.1.0` is the stable JavaScript package line for the modern Form Recognizer client surface. The official docs for this package line document the `DocumentAnalysisClient` and `DocumentModelAdministrationClient` APIs against the service capabilities available on this SDK generation.\n\nIf you need newer Azure Document Intelligence preview features, check the current official package overview and API reference before assuming they exist in `5.1.0`.\n\n### Pollers are part of the normal control flow\n\nAnalysis, model build, copy, and classification calls are not single-request APIs. They start long-running operations, so your application code should await the poller result before using the output.\n\n### URL analysis is reachability-sensitive\n\n`beginAnalyzeDocumentFromUrl()` works only when Azure can fetch the file from the URL you provide. Private storage URLs need a SAS token or another access path that the service can reach.\n\n### Legacy examples need migration work\n\nOlder blog posts and samples for this package family use different clients and response shapes. When you migrate from `beginRecognize*` or `beginTrainCustomModel` methods, update the parsing code too, not just the method names.\n\n## Common Pitfalls\n\n- Do not start new `5.1.0` code on `FormRecognizerClient` or `FormTrainingClient`.\n- Do not forget `await poller.pollUntilDone()` after `begin*` calls.\n- Do not use `DefaultAzureCredential` with a regional endpoint.\n- Do not assume `beginAnalyzeDocumentFromUrl()` can read a private blob URL without a SAS token.\n- Do not hard-code secrets in source files; keep endpoint and key values in environment variables or a secret manager.\n- Do not assume old `beginRecognize*` examples map one-to-one to the current API surface.\n\n## Official Sources Used\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/ai-form-recognizer-readme?view=azure-node-latest`\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/ai-form-recognizer/`\n- `DocumentAnalysisClient` reference: `https://learn.microsoft.com/en-us/javascript/api/%40azure/ai-form-recognizer/documentanalysisclient?view=azure-node-latest`\n- `DocumentModelAdministrationClient` reference: `https://learn.microsoft.com/en-us/javascript/api/%40azure/ai-form-recognizer/documentmodeladministrationclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/ai-form-recognizer`\n- Azure SDK for JavaScript migration guide: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/formrecognizer/ai-form-recognizer/MIGRATION_GUIDE.md`\n"
  },
  {
    "path": "content/azure/docs/ai-formrecognizer/python/DOC.md",
    "content": "---\nname: ai-formrecognizer\ndescription: \"azure-ai-formrecognizer package guide for Python covering auth, analysis clients, model administration, and version boundaries\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,document-intelligence,form-recognizer,ocr,document-analysis,python,sdk\"\n---\n\n# azure-ai-formrecognizer Python Package Guide\n\n## What This Package Covers\n\n`azure-ai-formrecognizer` is the Azure SDK package for Python code that works with Azure Form Recognizer, now branded as Azure Document Intelligence.\n\nUse it when you need to:\n\n- analyze PDFs or images with prebuilt models such as layout, document, invoice, or receipt\n- extract structured fields from custom models\n- build and manage custom document models\n- build and run document classifiers\n\nPackage boundary that matters:\n\n- `azure-ai-formrecognizer==3.3.3` covers service API versions up to `2023-07-31`\n- newer Document Intelligence service previews starting at `2023-10-31-preview` moved to `azure-ai-documentintelligence`\n\nFor new code on this package line, the main imports are:\n\n```python\nfrom azure.ai.formrecognizer import (\n    AnalysisFeature,\n    DocumentAnalysisClient,\n    DocumentModelAdministrationClient,\n)\n```\n\nLegacy clients still exist for older service versions:\n\n```python\nfrom azure.ai.formrecognizer import FormRecognizerClient, FormTrainingClient\n```\n\nUse those only when maintaining older `2.0` or `2.1` integrations.\n\n## Install\n\n```bash\npython -m pip install \"azure-ai-formrecognizer==3.3.3\"\n```\n\nIf you want Azure AD authentication:\n\n```bash\npython -m pip install \"azure-ai-formrecognizer==3.3.3\" azure-identity\n```\n\nRuntime requirements from PyPI:\n\n- Python `>=3.8`\n\n## Required Setup\n\nYou need:\n\n1. an Azure Form Recognizer or Cognitive Services resource\n2. the resource endpoint\n3. either an API key or an Azure AD credential\n\nTypical environment variables:\n\n```bash\nexport AZURE_FORM_RECOGNIZER_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport AZURE_FORM_RECOGNIZER_KEY=\"<api-key>\"\n```\n\nEndpoint rules from the official overview docs:\n\n- key auth works with either a regional endpoint or a custom subdomain endpoint\n- Azure AD auth requires a custom subdomain endpoint such as `https://<resource-name>.cognitiveservices.azure.com/`\n- regional endpoints such as `https://<region>.api.cognitive.microsoft.com/` do not support Azure AD\n\n## Authentication\n\n### API key\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import DocumentAnalysisClient\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n```\n\n### Azure AD with `DefaultAzureCredential`\n\nUse this when the app runs with a managed identity or service principal.\n\n```python\nimport os\nfrom azure.ai.formrecognizer import DocumentAnalysisClient\nfrom azure.identity import DefaultAzureCredential\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\nThe principal needs the `Cognitive Services User` role on the resource.\n\n## Client Selection\n\nUse this mapping:\n\n- `DocumentAnalysisClient`: analyze documents and run classifiers on modern service versions\n- `DocumentModelAdministrationClient`: build, compose, copy, list, and delete custom models and classifiers\n- `FormRecognizerClient`: legacy analysis surface for older `2.0` and `2.1` code\n- `FormTrainingClient`: legacy model training surface for older `2.0` and `2.1` code\n\nIf the codebase already calls methods like `begin_recognize_invoices`, `begin_recognize_receipts`, or `begin_train_custom_model`, you are on the legacy client surface and should check the migration guide before replacing calls mechanically.\n\n## Quick Start: Analyze A Prebuilt Invoice\n\nAll `begin_*` operations return a poller. Call `.result()` to wait for completion.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import DocumentAnalysisClient\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\nwith open(\"invoice.pdf\", \"rb\") as fh:\n    poller = client.begin_analyze_document(\n        \"prebuilt-invoice\",\n        document=fh,\n        locale=\"en-US\",\n    )\n\nresult = poller.result()\n\nfor invoice in result.documents:\n    vendor = invoice.fields.get(\"VendorName\")\n    total = invoice.fields.get(\"InvoiceTotal\")\n    print(vendor.value if vendor else None)\n    print(total.value if total else None)\n```\n\nCommon prebuilt model IDs:\n\n- `prebuilt-layout`\n- `prebuilt-document`\n- `prebuilt-invoice`\n- `prebuilt-receipt`\n- `prebuilt-idDocument`\n\n## Analyze From URL\n\nUse the URL form only when the file is public or the URL includes a SAS token.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import DocumentAnalysisClient\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\npoller = client.begin_analyze_document_from_url(\n    \"prebuilt-layout\",\n    document_url=\"https://example.blob.core.windows.net/forms/sample.pdf?<sas>\",\n)\n\nlayout = poller.result()\nfor page in layout.pages:\n    print(page.page_number, len(page.lines))\n```\n\n## Use Optional Analysis Features\n\nThe `3.3.x` line exposes the `features=` argument on `begin_analyze_document`. Use this when you need higher-resolution OCR or extra extraction signals on the `2023-07-31` service version.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import AnalysisFeature, DocumentAnalysisClient\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\nwith open(\"engineering-drawing.pdf\", \"rb\") as fh:\n    poller = client.begin_analyze_document(\n        \"prebuilt-layout\",\n        document=fh,\n        features=[\n            AnalysisFeature.OCR_HIGH_RESOLUTION,\n            AnalysisFeature.BARCODES,\n        ],\n    )\n\nresult = poller.result()\nprint(len(result.pages))\n```\n\nAvailable feature flags in the official enum include:\n\n- `OCR_HIGH_RESOLUTION`\n- `LANGUAGES`\n- `BARCODES`\n- `FORMULAS`\n- `KEY_VALUE_PAIRS`\n- `STYLE_FONT`\n- `QUERY_FIELDS`\n\n## Build A Custom Document Model\n\nUse `DocumentModelAdministrationClient` for model build and model management.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import DocumentModelAdministrationClient, ModelBuildMode\n\nadmin = DocumentModelAdministrationClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\npoller = admin.begin_build_document_model(\n    build_mode=ModelBuildMode.TEMPLATE,\n    blob_container_url=os.environ[\"TRAINING_CONTAINER_SAS_URL\"],\n    model_id=\"contoso-invoices\",\n    description=\"Invoice extractor\",\n)\n\nmodel = poller.result()\nprint(model.model_id)\nprint(model.description)\n```\n\nOperational notes:\n\n- use a container SAS URL for training data unless the container is intentionally public or accessible via managed identity\n- `ModelBuildMode.TEMPLATE` and `ModelBuildMode.NEURAL` have different accuracy, training-data, and cost tradeoffs\n- call `admin.get_resource_details()` when you need current model-count and quota limits\n\nList models:\n\n```python\nfor item in admin.list_document_models():\n    print(item.model_id, item.created_on)\n```\n\n## Build And Run A Classifier\n\nClassifier APIs are available on the `3.3.x` line.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import (\n    BlobSource,\n    ClassifierDocumentTypeDetails,\n    DocumentModelAdministrationClient,\n)\n\nadmin = DocumentModelAdministrationClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\npoller = admin.begin_build_document_classifier(\n    doc_types={\n        \"invoice\": ClassifierDocumentTypeDetails(\n            source=BlobSource(\n                container_url=os.environ[\"CLASSIFIER_CONTAINER_SAS_URL\"],\n                prefix=\"invoice/train\",\n            )\n        ),\n        \"receipt\": ClassifierDocumentTypeDetails(\n            source=BlobSource(\n                container_url=os.environ[\"CLASSIFIER_CONTAINER_SAS_URL\"],\n                prefix=\"receipt/train\",\n            )\n        ),\n    },\n    classifier_id=\"finance-docs\",\n    description=\"Finance document router\",\n)\n\nclassifier = poller.result()\nprint(classifier.classifier_id)\n```\n\nRun classification:\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.formrecognizer import DocumentAnalysisClient\n\nclient = DocumentAnalysisClient(\n    endpoint=os.environ[\"AZURE_FORM_RECOGNIZER_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_FORM_RECOGNIZER_KEY\"]),\n)\n\nwith open(\"mixed-batch.pdf\", \"rb\") as fh:\n    poller = client.begin_classify_document(\"finance-docs\", document=fh)\n\nresult = poller.result()\nfor document in result.documents:\n    print(document.doc_type, document.confidence)\n```\n\n## Configuration And Compatibility Notes\n\n### Service-version boundary\n\n`azure-ai-formrecognizer==3.3.3` is the final stable line for the older package name and modernizes the client surface around:\n\n- `DocumentAnalysisClient`\n- `DocumentModelAdministrationClient`\n- service API `2023-07-31`\n\nIf you need capabilities introduced in `2023-10-31-preview` or later, move to `azure-ai-documentintelligence` instead of extending this package further.\n\n### Legacy migration boundary\n\nOlder `3.1.x` and legacy `2.x` examples use different method families. These older examples do not map one-for-one to the `3.3.3` API surface.\n\nIf you see code like:\n\n- `begin_recognize_content`\n- `begin_recognize_business_cards`\n- `begin_recognize_receipts`\n- `begin_train_custom_model`\n\ndo not swap method names blindly. Check the official migration guide and rework the response parsing too.\n\n### Async support\n\nAsync clients live under `azure.ai.formrecognizer.aio` with the same service concepts as the sync clients. Use them only if the surrounding app is already async.\n\n## Common Pitfalls\n\n- Do not use `FormRecognizerClient` or `FormTrainingClient` for new `3.3.3` code.\n- Do not forget `.result()` on pollers returned by `begin_*` methods.\n- Do not use Azure AD with a regional endpoint; use a custom subdomain endpoint.\n- Do not assume URL-based analysis works for private blobs without a SAS token or another publicly reachable URL.\n- Do not assume old blog posts that mention `begin_recognize_*` methods apply to the current client surface.\n- Do not assume this package covers the newest Document Intelligence preview APIs; it stops at `2023-07-31`.\n- Do not assume `features=` is portable to older installs such as `3.2.x` or legacy `3.1.x`.\n\n## Official Sources Used\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/ai-formrecognizer-readme?view=azure-python`\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/python/api/azure-ai-formrecognizer/`\n- `DocumentAnalysisClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-ai-formrecognizer/azure.ai.formrecognizer.documentanalysisclient?view=azure-python`\n- `DocumentModelAdministrationClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-ai-formrecognizer/azure.ai.formrecognizer.documentmodeladministrationclient?view=azure-python`\n- `AnalysisFeature` enum: `https://learn.microsoft.com/en-us/python/api/azure-ai-formrecognizer/azure.ai.formrecognizer.analysisfeature?view=azure-python`\n- PyPI package page: `https://pypi.org/project/azure-ai-formrecognizer/`\n- Azure SDK migration guide: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/formrecognizer/azure-ai-formrecognizer/MIGRATION_GUIDE.md`\n"
  },
  {
    "path": "content/azure/docs/ai-language-text/javascript/DOC.md",
    "content": "---\nname: ai-language-text\ndescription: \"Azure AI Language Text SDK for JavaScript for client setup, authentication, and common text analysis workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,language,text,nlp,sentiment,entities,pii,javascript\"\n---\n\n# @azure/ai-language-text JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/ai-language-text` when the codebase already uses this package or `TextAnalysisClient`.\n\n- If the repo already imports `@azure/ai-text-analytics` with `TextAnalyticsClient`, treat that as a separate package choice and migrate deliberately instead of swapping names mechanically.\n- Keep one shared client per process and send documents in batches.\n- Use a real Azure AI Language endpoint, not an Azure OpenAI or Translator endpoint.\n\nThis guide targets package version `1.1.0`.\n\n## Install\n\n```bash\nnpm install @azure/ai-language-text@1.1.0 @azure/core-auth\n```\n\nInstall Azure Identity only if you want Microsoft Entra ID authentication:\n\n```bash\nnpm install @azure/identity\n```\n\n## Required Setup\n\nYou need:\n\n- an Azure AI Language or Cognitive Services resource\n- the resource endpoint\n- either an API key or a Microsoft Entra ID credential\n\nTypical environment variables:\n\n```bash\nexport AZURE_LANGUAGE_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport AZURE_LANGUAGE_KEY=\"<api-key>\"\n```\n\n## Authenticate And Create A Client\n\n### API key\n\n```js\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { TextAnalysisClient } from \"@azure/ai-language-text\";\n\nconst endpoint = process.env.AZURE_LANGUAGE_ENDPOINT;\nconst key = process.env.AZURE_LANGUAGE_KEY;\n\nif (!endpoint || !key) {\n  throw new Error(\"Set AZURE_LANGUAGE_ENDPOINT and AZURE_LANGUAGE_KEY before creating the client.\");\n}\n\nexport const textClient = new TextAnalysisClient(\n  endpoint,\n  new AzureKeyCredential(key),\n);\n```\n\n### Microsoft Entra ID with `DefaultAzureCredential`\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { TextAnalysisClient } from \"@azure/ai-language-text\";\n\nconst endpoint = process.env.AZURE_LANGUAGE_ENDPOINT;\n\nif (!endpoint) {\n  throw new Error(\"Set AZURE_LANGUAGE_ENDPOINT before creating the client.\");\n}\n\nexport const textClient = new TextAnalysisClient(\n  endpoint,\n  new DefaultAzureCredential(),\n);\n```\n\nUse a custom subdomain endpoint for token-based authentication. Regional endpoints such as `https://<region>.api.cognitive.microsoft.com/` do not support Microsoft Entra ID.\n\n## Input Shape\n\nPass documents as an array. Use document objects when you need stable IDs, explicit language, or a country hint.\n\n```js\nconst documents = [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"The app is fast, but the onboarding flow is still confusing.\",\n  },\n  {\n    id: \"2\",\n    text: \"Ce document est redige en francais.\",\n    countryHint: \"FR\",\n  },\n];\n```\n\n## Common Workflows\n\n### Detect language\n\n```js\nimport { textClient } from \"./client.js\";\n\nconst results = await textClient.analyze(\"LanguageDetection\", [\n  { id: \"1\", text: \"Ce document est redige en francais.\", countryHint: \"FR\" },\n  { id: \"2\", text: \"Este documento esta escrito en espanol.\", countryHint: \"ES\" },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.primaryLanguage.name, result.primaryLanguage.confidenceScore);\n}\n```\n\n### Analyze sentiment\n\n```js\nimport { textClient } from \"./client.js\";\n\nconst results = await textClient.analyze(\"SentimentAnalysis\", [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"The release process is much smoother now, but the dashboard still feels slow.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.sentiment);\n  console.log(result.confidenceScores);\n}\n```\n\n### Extract key phrases\n\n```js\nimport { textClient } from \"./client.js\";\n\nconst results = await textClient.analyze(\"KeyPhraseExtraction\", [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Azure AI Language can detect sentiment, key phrases, and named entities.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.keyPhrases);\n}\n```\n\n### Recognize named entities\n\n```js\nimport { textClient } from \"./client.js\";\n\nconst results = await textClient.analyze(\"EntityRecognition\", [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Satya Nadella spoke at Microsoft Build in Seattle.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  for (const entity of result.entities) {\n    console.log(entity.text, entity.category, entity.confidenceScore);\n  }\n}\n```\n\n### Recognize PII entities\n\n```js\nimport { textClient } from \"./client.js\";\n\nconst results = await textClient.analyze(\"PiiEntityRecognition\", [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Call me at 555-123-4567 or email ada@example.com.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.redactedText);\n\n  for (const entity of result.entities) {\n    console.log(entity.text, entity.category, entity.confidenceScore);\n  }\n}\n```\n\n## Practical Notes\n\n- Reuse one `TextAnalysisClient` instead of creating a new client for every request.\n- Pass explicit `language` values when your inputs are multilingual or not reliably English.\n- Use document objects with stable `id` values when you need to map results back to source records.\n- Check each result for `error`; a successful request can still contain document-level failures.\n- Keep the endpoint pointed at Azure AI Language, and use a custom subdomain when authenticating with Entra ID.\n\n## Common Pitfalls\n\n- Mixing `@azure/ai-language-text` and `@azure/ai-text-analytics` in the same module and assuming the client/method names are interchangeable.\n- Passing a bare string instead of a document array.\n- Treating an HTTP success as proof that every document succeeded.\n- Using a regional endpoint with `DefaultAzureCredential`.\n- Omitting `language` or `countryHint` for ambiguous text and then treating the result as deterministic.\n\n## Version Notes For 1.1.0\n\n- This guide targets `@azure/ai-language-text` `1.1.0`.\n- If the project is already pinned to `@azure/ai-text-analytics`, keep that package unless you are doing an explicit migration to the newer `ai-language-text` client surface.\n- Keep `@azure/identity` aligned with the rest of your Azure SDK dependencies when you use Entra ID authentication.\n\n## Official Sources\n\n- Docs root: `https://learn.microsoft.com/en-us/javascript/api/@azure/ai-language-text/`\n- Overview and getting started: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/ai-language-text-readme?view=azure-node-latest`\n- `TextAnalysisClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/ai-language-text/textanalysisclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/ai-language-text`\n"
  },
  {
    "path": "content/azure/docs/ai-language-text/python/DOC.md",
    "content": "---\nname: ai-language-text\ndescription: \"Azure AI Language Text for Python - setup, authentication, text analysis workflows, and package-selection pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"azure,language,nlp,textanalytics,sentiment,ner,summarization\"\n---\n\n# azure-ai-language-text Python Package Guide\n\n## Golden Rule\n\nUse the package already pinned by the project before copying Azure Language samples.\n\n- If the codebase already imports `azure.ai.language.text`, stay on `azure-ai-language-text` and verify the exact client/method names against the package API reference.\n- If the codebase imports `azure.ai.textanalytics`, stay on `azure-ai-textanalytics` instead. Microsoft Learn's current Python quickstarts still use that package for most Azure Language runtime examples.\n- Do not rename imports or mix both packages in the same module unless you are doing an explicit migration.\n\n## Current Upstream State\n\nThis guide covers `azure-ai-language-text` `1.0.0`, but Microsoft's broader Python guidance is currently split:\n\n- The Azure AI Language Python overview still highlights `azure-ai-textanalytics` as the main Python runtime package.\n- Current Microsoft Learn quickstarts for language detection and summarization still show `azure-ai-textanalytics` installs and `TextAnalyticsClient` examples.\n- The Azure AI Language What's New page announced a newer Python preview under `azure-ai-textanalytics 6.0.0b1`.\n\nInference: package naming and sample freshness are in flux. Treat this package as version-sensitive, and confirm the import surface in the repo you are editing before generating code.\n\n## Install\n\n```bash\npip install azure-ai-language-text==1.0.0\npip install azure-identity\n```\n\nIf `pip` cannot resolve `azure-ai-language-text` in the target environment, stop and re-check the current Microsoft package mapping. The currently published Learn quickstarts may still expect:\n\n```bash\npip install azure-ai-textanalytics==5.2.0\n```\n\nor:\n\n```bash\npip install azure-ai-textanalytics==5.3.0\n```\n\ndepending on which article/version you are following.\n\n## Setup And Authentication\n\nYou need an Azure AI Language resource endpoint and either an API key or Microsoft Entra credentials.\n\nSet environment variables:\n\n```bash\nexport LANGUAGE_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport LANGUAGE_KEY=\"<api-key>\"\n```\n\nAPI key pattern used in current Python quickstarts:\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.textanalytics import TextAnalyticsClient\n\nclient = TextAnalyticsClient(\n    endpoint=os.environ[\"LANGUAGE_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"LANGUAGE_KEY\"]),\n)\n```\n\nMicrosoft Entra ID pattern:\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential\nfrom azure.ai.textanalytics import TextAnalyticsClient\n\nclient = TextAnalyticsClient(\n    endpoint=os.environ[\"LANGUAGE_ENDPOINT\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\nFor `azure-ai-language-text`, expect the same endpoint and credential objects to apply. The verified Python quickstarts above currently use `TextAnalyticsClient`; if your project already uses `azure.ai.language.text`, keep its existing import path and map the same auth pattern onto that client.\n\n## Core Usage Pattern\n\nThe stable operational model across Azure Language runtime SDKs is:\n\n1. Create one long-lived client with the resource endpoint and credential.\n2. Send plain-text documents as a list.\n3. Use direct methods for fast analyses such as language detection, sentiment, key phrases, and entity recognition.\n4. Use a poller or long-running operation for summarization, healthcare, and other multi-action workflows.\n5. Check per-document errors instead of assuming the whole batch succeeded.\n\n### Verified Current Python Example: Language Detection\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.textanalytics import TextAnalyticsClient\n\nclient = TextAnalyticsClient(\n    endpoint=os.environ[\"LANGUAGE_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"LANGUAGE_KEY\"]),\n)\n\ndocuments = [\n    \"Ce document est redige en francais.\",\n    \"Este documento esta escrito en espanol.\",\n]\n\nresponse = client.detect_language(documents=documents, country_hint=\"us\")\n\nfor item in response:\n    if item.is_error:\n        print(f\"error: {item.error.code} {item.error.message}\")\n    else:\n        print(item.primary_language.iso6391_name, item.primary_language.name)\n```\n\n### Verified Current Python Example: Extractive Summarization\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.ai.textanalytics import TextAnalyticsClient\nfrom azure.ai.textanalytics import ExtractiveSummaryAction\n\nclient = TextAnalyticsClient(\n    endpoint=os.environ[\"LANGUAGE_ENDPOINT\"],\n    credential=AzureKeyCredential(os.environ[\"LANGUAGE_KEY\"]),\n)\n\ndocument = [\n    \"The tower was built in 1889 during the Paris World's Fair. \"\n    \"It was designed by Gustave Eiffel. It remains one of the most visited landmarks in the world.\"\n]\n\npoller = client.begin_analyze_actions(\n    document,\n    actions=[ExtractiveSummaryAction(max_sentence_count=2)],\n)\n\ndocument_results = poller.result()\n\nfor action_results in document_results:\n    for result in action_results:\n        if result.is_error:\n            print(f\"error: {result.code} {result.message}\")\n        else:\n            for summary in result.sentences:\n                print(summary.text)\n```\n\nIf the project actually uses `azure-ai-language-text`, the same workflow should still apply conceptually: one client, list-of-documents inputs, direct text analyses, and poller-based long-running operations for summarization-style tasks. Verify the exact method names on the package reference page before editing production code.\n\n## Config And Service Boundaries\n\n- Runtime analysis and authoring are not the same concern. Current Microsoft docs use `azure-ai-textanalytics-authoring` for authoring custom projects and `azure-ai-textanalytics` for runtime calls.\n- Region and pricing tier matter. Some features are preview-only or require specific regions/SKU support.\n- The endpoint must be the Azure AI Language resource endpoint, not Azure OpenAI, Translator, or a custom proxy URL unless the project intentionally fronts the service.\n- Prefer `DefaultAzureCredential` for deployed apps. Use `AzureKeyCredential` for local scripts, quick tests, or when the app is already key-based.\n\n## Common Pitfalls\n\n- Package drift: do not assume `azure-ai-language-text` and `azure-ai-textanalytics` are drop-in rename equivalents. Check imports already present in the repo first.\n- Batch error handling: Azure Language returns per-document failures; handle `is_error` per item.\n- Long-running actions: summarization and some advanced analyses are poller-based, not immediate responses.\n- Service quotas: large batches and long documents can hit request-size or transaction limits.\n- Model-specific inputs: custom text models often need project and deployment identifiers in addition to text.\n- API-version sensitivity: preview packages and preview docs can expose methods or enum values missing from GA packages.\n\n## Version-Sensitive Notes\n\n- Target version for this session: `azure-ai-language-text` `1.0.0`.\n- Current Microsoft Learn Python quickstarts still reference `azure-ai-textanalytics` `5.2.0` or `5.3.0`.\n- Microsoft announced a new Python preview line as `azure-ai-textanalytics 6.0.0b1` in October 2025.\n- Practical rule: if you are writing code into an existing repository, trust the repository's pinned dependency and import path over generic blog posts or cross-language samples.\n\n## Official Sources Used\n\n- Package docs root: `https://learn.microsoft.com/en-us/python/api/azure-ai-language-text/`\n- Azure AI Language Python overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/ai-language-readme?view=azure-python`\n- Language detection quickstart: `https://learn.microsoft.com/en-us/azure/ai-services/language-service/language-detection/quickstart`\n- Summarization quickstart: `https://learn.microsoft.com/en-us/azure/ai-services/language-service/summarization/quickstart`\n- What's new: `https://learn.microsoft.com/en-us/azure/ai-services/language-service/whats-new`\n- Registry URL: `https://pypi.org/project/azure-ai-language-text/`\n"
  },
  {
    "path": "content/azure/docs/ai-ml/python/DOC.md",
    "content": "---\nname: ai-ml\ndescription: \"Azure Machine Learning Python SDK for workspace access, jobs, models, pipelines, and online endpoints\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.31.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-machine-learning,azure-ai-ml,mlops,jobs,pipelines,models,endpoints\"\n---\n\n# Azure Machine Learning Python SDK\n\n## Golden Rule\n\nUse `azure-ai-ml` as the control-plane SDK for Azure Machine Learning v2, authenticate it with `azure-identity`, and center most code around `MLClient`. Treat your local Python environment as the orchestration environment only; training and inference runtimes must be declared explicitly in Azure ML jobs or deployments.\n\n## Install\n\nInstall the ML SDK and the Azure Identity credential package together:\n\n```bash\npython -m pip install \"azure-ai-ml==1.31.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-ai-ml==1.31.0\" azure-identity\npoetry add \"azure-ai-ml==1.31.0\" azure-identity\n```\n\nYou also need:\n\n- an Azure subscription\n- an Azure Machine Learning workspace\n- permission to the subscription, resource group, and workspace\n\n## Authentication And Workspace Setup\n\nThe default path is `DefaultAzureCredential()` plus `MLClient(...)`.\n\n```python\nfrom azure.ai.ml import MLClient\nfrom azure.identity import DefaultAzureCredential\n\nml_client = MLClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=\"<subscription-id>\",\n    resource_group_name=\"<resource-group>\",\n    workspace_name=\"<workspace-name>\",\n)\n```\n\nIf your repo or notebook environment already has a workspace `config.json`, `from_config()` is the shortest path:\n\n```python\nfrom azure.ai.ml import MLClient\nfrom azure.identity import DefaultAzureCredential\n\nml_client = MLClient.from_config(\n    credential=DefaultAzureCredential(),\n)\n```\n\nMicrosoft documents this `config.json` shape:\n\n```json\n{\n  \"subscription_id\": \"<subscription-id>\",\n  \"resource_group\": \"<resource-group>\",\n  \"workspace_name\": \"<workspace-name>\"\n}\n```\n\nNotes:\n\n- The pipeline guide uses `DefaultAzureCredential()` first and falls back to `InteractiveBrowserCredential()` if token acquisition fails in local development.\n- For sovereign clouds, Microsoft documents passing both `cloud=` to `MLClient` and the matching `authority=` to `DefaultAzureCredential`.\n- `MLClient` accepts `enable_telemetry=False`; the package docs say telemetry is only collected in Jupyter Notebook usage and is forced off outside Jupyter.\n\n## Core Usage\n\n### Submit a command job\n\nUse `command(...)` for the common \"run this script on Azure ML\" flow.\n\n```python\nfrom azure.ai.ml import Input, command\n\njob = command(\n    code=\"./src\",\n    command=\"python train.py --input_data ${{inputs.training_data}}\",\n    environment=\"azureml://registries/azureml/environments/sklearn-1.5/labels/latest\",\n    compute=\"cpu-cluster\",\n    inputs={\n        \"training_data\": Input(\n            type=\"uri_file\",\n            path=\"https://azuremlexamples.blob.core.windows.net/datasets/credit_card/default_of_credit_card_clients.csv\",\n        )\n    },\n    display_name=\"credit-default-train\",\n)\n\ncreated_job = ml_client.jobs.create_or_update(job)\nml_client.jobs.stream(created_job.name)\n```\n\nUse this for training, preprocessing, evaluation, or batch-style scripts that need Azure-managed compute and environments.\n\n### Compose a pipeline from reusable components\n\nUse `load_component(...)` and the pipeline DSL when you need reusable multi-step workflows.\n\n```python\nfrom azure.ai.ml import Input, load_component\nfrom azure.ai.ml.dsl import pipeline\n\ntrain_component = load_component(source=\"./components/train.yml\")\n\n@pipeline(name=\"train_pipeline\")\ndef train_pipeline(training_data):\n    train_step = train_component(training_data=training_data)\n    return {\"model_output\": train_step.outputs.model_output}\n\npipeline_job = train_pipeline(\n    training_data=Input(type=\"uri_folder\", path=\"azureml:my-training-data:1\")\n)\n\nsubmitted = ml_client.jobs.create_or_update(\n    pipeline_job,\n    experiment_name=\"pipeline_samples\",\n)\nml_client.jobs.stream(submitted.name)\n```\n\n### Register a model asset\n\nRegister models explicitly when you want stable references for deployment or reuse.\n\n```python\nfrom azure.ai.ml.constants import AssetTypes\nfrom azure.ai.ml.entities import Model\n\nmodel = Model(\n    path=\"./model\",\n    name=\"fraud-model\",\n    type=AssetTypes.CUSTOM_MODEL,\n    description=\"Fraud model packaged for deployment\",\n)\n\nregistered_model = ml_client.models.create_or_update(model)\nprint(registered_model.id)\n```\n\nThe model-management docs also support registering from datastore paths, `runs:/...`, or `azureml://jobs/...` URIs when the model comes from job outputs.\n\n### Create an online endpoint and deployment\n\nUse managed online endpoints for real-time inference. Endpoint and deployment creation are long-running operations, so wait on the poller result.\n\n```python\nimport uuid\n\nfrom azure.ai.ml import MLClient\nfrom azure.ai.ml.entities import (\n    CodeConfiguration,\n    ManagedOnlineDeployment,\n    ManagedOnlineEndpoint,\n)\n\nendpoint_name = f\"credit-endpoint-{str(uuid.uuid4())[:8]}\"\n\nendpoint = ManagedOnlineEndpoint(\n    name=endpoint_name,\n    description=\"Real-time fraud scoring endpoint\",\n    auth_mode=\"key\",\n)\nendpoint = ml_client.online_endpoints.begin_create_or_update(endpoint).result()\n\ndeployment = ManagedOnlineDeployment(\n    name=\"blue\",\n    endpoint_name=endpoint_name,\n    model=\"azureml:fraud-model:1\",\n    environment=\"azureml:fraud-inference-env:1\",\n    code_configuration=CodeConfiguration(\n        code=\"./deploy\",\n        scoring_script=\"score.py\",\n    ),\n    instance_type=\"Standard_DS3_v2\",\n    instance_count=1,\n)\n\ndeployment = ml_client.begin_create_or_update(deployment).result()\n```\n\nInvoke the deployment with a request JSON file:\n\n```python\nresult = ml_client.online_endpoints.invoke(\n    endpoint_name=endpoint_name,\n    deployment_name=\"blue\",\n    request_file=\"./deploy/sample-request.json\",\n)\n\nprint(result)\n```\n\n## Configuration And Auth Checklist\n\n- Install both `azure-ai-ml` and `azure-identity`; the ML SDK does not replace the credential package.\n- Keep the workspace triple available: subscription ID, resource group, workspace name.\n- Prefer `DefaultAzureCredential()` for local dev, CI, and Azure-hosted runtimes unless your environment requires a specific credential type.\n- Use a checked-in or generated `config.json` only if the workspace identity is safe to keep in the repo; never commit secrets.\n- Define runtime environments for jobs and deployments explicitly instead of assuming local packages are present remotely.\n- Ensure compute exists before submitting jobs unless your workflow is intentionally serverless.\n\n## Common Pitfalls\n\n- The install name and import path differ: install `azure-ai-ml`, import from `azure.ai.ml`.\n- `MLClient.from_config()` fails if `config.json` is missing or malformed.\n- `create_or_update()` and `begin_create_or_update()` are not interchangeable. Jobs and many asset operations use `create_or_update()`, while endpoints, deployments, compute, schedules, registries, and workspaces commonly use the long-running `begin_create_or_update()` flow.\n- A job spec without an explicit Azure ML environment is brittle. The remote runtime is not inferred from your local venv.\n- For online deployments, you need a model, an inference environment, a scoring script, and usually traffic routing. Creating just the endpoint is not enough.\n- Quota and SKU availability errors are common for online deployments. Microsoft explicitly notes that you may need to switch `instance_type` if the chosen VM is not available.\n- Azure ML exceptions come from Azure Core in many cases, so catch `azure.core.exceptions.HttpResponseError` for API failures.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `1.31.0` released on `2025-12-30`.\n- Upstream Python-version guidance is inconsistent. The PyPI project metadata still says \"Python 3.7 or later\" and \"tested with Python 3.8 ... 3.14\", but the `1.31.0` release history says support for Python `3.7` and `3.8` was dropped and Python `3.14` was added. For new `1.31.0` work, treat `3.9+` as the safe baseline.\n- `1.31.0` adds `default_deployment_template` support on `Model` entities for online deployments.\n- `1.30.0` removed the `msrest` and `six` dependencies. If older internal tooling relied on those transitive packages, re-test after upgrading.\n\n## Official Sources\n\n- PyPI project and release history: `https://pypi.org/project/azure-ai-ml/`\n- PyPI JSON metadata: `https://pypi.org/pypi/azure-ai-ml/json`\n- Azure AI ML Python API root: `https://learn.microsoft.com/en-us/python/api/azure-ai-ml/`\n- `MLClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-ai-ml/azure.ai.ml.mlclient?view=azure-python`\n- Package reference for `command`, `Input`, and `load_component`: `https://learn.microsoft.com/en-us/python/api/azure-ai-ml/azure.ai.ml?view=azure-python`\n- Pipeline how-to: `https://learn.microsoft.com/en-us/azure/machine-learning/how-to-create-component-pipeline-python?view=azureml-api-2`\n- Model management guide: `https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-models?view=azureml-api-2`\n- Online endpoint quickstart: `https://learn.microsoft.com/en-us/azure/machine-learning/tutorial-azure-ml-in-a-day?view=azureml-api-2`\n- Online endpoint deployment guide: `https://learn.microsoft.com/en-us/azure/machine-learning/how-to-deploy-online-endpoints?view=azureml-api-2`\n"
  },
  {
    "path": "content/azure/docs/ai-text-analytics/javascript/DOC.md",
    "content": "---\nname: ai-text-analytics\ndescription: \"Azure AI Text Analytics SDK for JavaScript for Azure AI Language text analysis, language detection, entity extraction, and PII recognition\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,language,text-analytics,nlp,sentiment,entities,pii\"\n---\n\n# @azure/ai-text-analytics JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/ai-text-analytics` with `TextAnalyticsClient`, a real Azure AI Language endpoint, and either `AzureKeyCredential` or `DefaultAzureCredential`.\n\nThis guide targets package version `5.1.0`.\n\n## Install\n\n```bash\nnpm install @azure/ai-text-analytics\n```\n\nInstall Azure Identity only if you want Microsoft Entra ID authentication:\n\n```bash\nnpm install @azure/identity\n```\n\n## Required Setup\n\nYou need:\n\n- an Azure AI Language or Cognitive Services resource\n- the resource endpoint\n- either an API key or a Microsoft Entra ID credential\n\nTypical environment variables:\n\n```bash\nexport AZURE_LANGUAGE_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport AZURE_LANGUAGE_KEY=\"<api-key>\"\n```\n\n## Authenticate And Create A Client\n\n### API key\n\n```js\nimport { AzureKeyCredential, TextAnalyticsClient } from \"@azure/ai-text-analytics\";\n\nconst endpoint = process.env.AZURE_LANGUAGE_ENDPOINT;\nconst key = process.env.AZURE_LANGUAGE_KEY;\n\nif (!endpoint || !key) {\n  throw new Error(\"Set AZURE_LANGUAGE_ENDPOINT and AZURE_LANGUAGE_KEY before creating the client.\");\n}\n\nexport const textAnalyticsClient = new TextAnalyticsClient(\n  endpoint,\n  new AzureKeyCredential(key),\n);\n```\n\n### Microsoft Entra ID with `DefaultAzureCredential`\n\n```js\nimport { TextAnalyticsClient } from \"@azure/ai-text-analytics\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.AZURE_LANGUAGE_ENDPOINT;\n\nif (!endpoint) {\n  throw new Error(\"Set AZURE_LANGUAGE_ENDPOINT before creating the client.\");\n}\n\nexport const textAnalyticsClient = new TextAnalyticsClient(\n  endpoint,\n  new DefaultAzureCredential(),\n);\n```\n\nUse a custom subdomain endpoint for token-based authentication. Regional endpoints such as `https://<region>.api.cognitive.microsoft.com/` do not support Microsoft Entra ID.\n\n## Client Configuration\n\nSet defaults once on the client when most requests should share the same language, country hint, or service API version.\n\n```js\nimport { AzureKeyCredential, TextAnalyticsClient } from \"@azure/ai-text-analytics\";\n\nconst client = new TextAnalyticsClient(\n  process.env.AZURE_LANGUAGE_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_LANGUAGE_KEY),\n  {\n    defaultLanguage: \"en\",\n    defaultCountryHint: \"US\",\n    apiVersion: \"2023-04-01\",\n  },\n);\n```\n\n## Input Shape\n\nMost client methods accept a batch of documents.\n\nUse an array of strings for the simple case:\n\n```js\nconst documents = [\"The hotel staff were excellent, but check-in was slow.\"];\n```\n\nUse document objects when each item needs its own `id`, `language`, or `countryHint`:\n\n```js\nconst documents = [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"The hotel staff were excellent, but check-in was slow.\",\n  },\n  {\n    id: \"2\",\n    text: \"Ce document est redige en francais.\",\n    countryHint: \"FR\",\n  },\n];\n```\n\n## Common Workflows\n\n### Detect language\n\n```js\nimport { textAnalyticsClient } from \"./client.js\";\n\nconst documents = [\n  { id: \"1\", text: \"Ce document est redige en francais.\", countryHint: \"FR\" },\n  { id: \"2\", text: \"Este documento esta escrito en espanol.\", countryHint: \"ES\" },\n];\n\nconst results = await textAnalyticsClient.detectLanguage(documents);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.primaryLanguage.name, result.primaryLanguage.confidenceScore);\n}\n```\n\n### Analyze sentiment\n\n```js\nimport { textAnalyticsClient } from \"./client.js\";\n\nconst documents = [\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"The app is fast, but onboarding is still confusing.\",\n  },\n];\n\nconst results = await textAnalyticsClient.analyzeSentiment(documents);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.sentiment);\n  console.log(result.confidenceScores);\n}\n```\n\n### Extract key phrases\n\n```js\nimport { textAnalyticsClient } from \"./client.js\";\n\nconst results = await textAnalyticsClient.extractKeyPhrases([\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Azure AI Language helps applications detect sentiment and extract entities.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.keyPhrases);\n}\n```\n\n### Recognize named entities\n\n```js\nimport { textAnalyticsClient } from \"./client.js\";\n\nconst results = await textAnalyticsClient.recognizeEntities([\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Satya Nadella spoke at Microsoft Build in Seattle.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  for (const entity of result.entities) {\n    console.log(entity.text, entity.category, entity.confidenceScore);\n  }\n}\n```\n\n### Recognize PII entities\n\n```js\nimport { textAnalyticsClient } from \"./client.js\";\n\nconst results = await textAnalyticsClient.recognizePiiEntities([\n  {\n    id: \"1\",\n    language: \"en\",\n    text: \"Call me at 555-123-4567 or email ada@example.com.\",\n  },\n]);\n\nfor (const result of results) {\n  if (result.error) {\n    console.error(result.error.code, result.error.message);\n    continue;\n  }\n\n  console.log(result.redactedText);\n\n  for (const entity of result.entities) {\n    console.log(entity.text, entity.category, entity.confidenceScore);\n  }\n}\n```\n\n## Practical Notes\n\n- Reuse one `TextAnalyticsClient` instead of creating a new client per request.\n- Pass explicit `language` values when your inputs are not reliably English.\n- Use document objects with stable `id` values when you need to match results back to source records.\n- Handle per-document failures on every call; a batch can contain both successful results and document errors.\n- Keep the endpoint pointed at Azure AI Language, not Azure OpenAI or Translator.\n\n## Common Pitfalls\n\n- Passing a bare string instead of an array. Use `[\"text\"]`, not `\"text\"`.\n- Assuming a successful HTTP call means every document succeeded. Check each result for `error`.\n- Using a regional endpoint with `DefaultAzureCredential`.\n- Omitting `language` or `countryHint` on multilingual or ambiguous text and then treating the output as deterministic.\n- Expecting every workflow to be immediate. Some advanced analyses in this package use `begin...` long-running methods instead of direct request/response calls.\n\n## Version Notes For 5.1.0\n\n- This guide targets `@azure/ai-text-analytics` `5.1.0`.\n- The package and client names still use `text-analytics`, even though Azure service documentation refers to Azure AI Language.\n- When you authenticate with Microsoft Entra ID, keep `@azure/identity` aligned with the rest of your Azure SDK dependencies.\n\n## Official Sources\n\n- Docs root: `https://learn.microsoft.com/en-us/javascript/api/@azure/ai-text-analytics/`\n- Overview and getting started: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/ai-text-analytics-readme?view=azure-node-latest`\n- `TextAnalyticsClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/ai-text-analytics/textanalyticsclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/ai-text-analytics`\n- Changelog: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/textanalytics/ai-text-analytics/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/ai-textanalytics/python/DOC.md",
    "content": "---\nname: ai-textanalytics\ndescription: \"Azure AI Text Analytics SDK for Python for Language service text analysis, custom classification, summarization, and healthcare entity extraction\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.4.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,language,text-analytics,nlp,sentiment,entities,summarization\"\n---\n\n# azure-ai-textanalytics Python Package Guide\n\n## Golden Rule\n\nUse `azure-ai-textanalytics` for Azure Language service text analysis in Python, and initialize `TextAnalyticsClient` with a real Language endpoint plus either `AzureKeyCredential` or an Azure Identity credential.\n\nThis entry covers package version `5.4.0`.\n\n## Install\n\n```bash\npip install \"azure-ai-textanalytics==5.4.0\"\n```\n\nInstall Azure Identity only if you want Microsoft Entra ID authentication:\n\n```bash\npip install azure-identity\n```\n\n## Python And Version Notes\n\n- PyPI metadata for `5.4.0` requires Python `>=3.8`.\n- The package supports service API versions `3.0`, `3.1`, `2022-05-01`, and `2023-04-01`; the default in the current stable line is `2023-04-01`.\n- `5.2.x` and newer target Azure Cognitive Service for Language APIs rather than the older Text Analytics-only service surface.\n- `5.4.0` changed continuation token format. Tokens created by older `azure-core` versions are not compatible with this release.\n- If you need preview Language service API `2025-05-15-preview` or later, use the `6.0.0b1+` preview package line instead of `5.x`.\n\n## Required Setup\n\nYou need:\n\n- an Azure subscription\n- a Cognitive Services or Language resource endpoint\n- either an API key or an Azure Identity credential\n\nTypical environment variables:\n\n```bash\nexport AZURE_LANGUAGE_ENDPOINT=\"https://<resource-name>.cognitiveservices.azure.com/\"\nexport AZURE_LANGUAGE_KEY=\"<api-key>\"\n```\n\n## Authenticate And Create A Client\n\n### API key\n\n```python\nimport os\n\nfrom azure.ai.textanalytics import TextAnalyticsClient\nfrom azure.core.credentials import AzureKeyCredential\n\nendpoint = os.environ[\"AZURE_LANGUAGE_ENDPOINT\"]\nkey = os.environ[\"AZURE_LANGUAGE_KEY\"]\n\nclient = TextAnalyticsClient(\n    endpoint=endpoint,\n    credential=AzureKeyCredential(key),\n)\n```\n\n### Microsoft Entra ID with `DefaultAzureCredential`\n\n```python\nimport os\n\nfrom azure.ai.textanalytics import TextAnalyticsClient\nfrom azure.identity import DefaultAzureCredential\n\nendpoint = os.environ[\"AZURE_LANGUAGE_ENDPOINT\"]\n\nclient = TextAnalyticsClient(\n    endpoint=endpoint,\n    credential=DefaultAzureCredential(),\n)\n```\n\nImportant auth caveat: regional endpoints like `https://<region>.api.cognitive.microsoft.com/` do not support Entra ID authentication. Use a custom subdomain endpoint for token-based auth.\n\n## Client Configuration\n\n`TextAnalyticsClient(...)` accepts several defaults that affect most requests:\n\n- `default_language`: default document language, which otherwise defaults to English\n- `default_country_hint`: default country hint, which otherwise defaults to `US`; pass `\"none\"` to disable it\n- `api_version`: pin a specific supported Language service API version\n\nExample:\n\n```python\nfrom azure.ai.textanalytics import TextAnalyticsApiVersion\n\nclient = TextAnalyticsClient(\n    endpoint=endpoint,\n    credential=AzureKeyCredential(key),\n    default_language=\"en\",\n    default_country_hint=\"none\",\n    api_version=TextAnalyticsApiVersion.V2023_04_01,\n)\n```\n\n## Input Shape\n\nMost methods take a batch of documents, not a single bare string.\n\nUse a list of strings for the simple case:\n\n```python\ndocuments = [\"The hotel staff were excellent, but check-in was slow.\"]\n```\n\nUse dicts when each document needs its own `id`, `language`, or `country_hint`:\n\n```python\ndocuments = [\n    {\n        \"id\": \"1\",\n        \"language\": \"en\",\n        \"text\": \"I loved the food but the wait was long.\",\n    },\n    {\n        \"id\": \"2\",\n        \"language\": \"en\",\n        \"text\": \"Seattle is a great city for coffee.\",\n    },\n]\n```\n\n## Core Usage\n\n### Detect language\n\n```python\nresult = client.detect_language([\"Bonjour tout le monde\"])[0]\n\nif not result.is_error:\n    print(result.primary_language.name)\n    print(result.primary_language.iso6391_name)\n```\n\n### Analyze sentiment\n\n```python\ndocuments = [\"The hotel staff were excellent, but check-in was slow.\"]\nresult = client.analyze_sentiment(documents, show_opinion_mining=True)[0]\n\nif not result.is_error:\n    print(result.sentiment)\n    for sentence in result.sentences:\n        print(sentence.sentiment, sentence.text)\n```\n\n`show_opinion_mining=True` is available only for service API `v3.1` and newer.\n\n### Recognize entities\n\n```python\ndocuments = [\"Satya Nadella leads Microsoft in Seattle.\"]\nresult = client.recognize_entities(documents)[0]\n\nif not result.is_error:\n    for entity in result.entities:\n        print(entity.text, entity.category, entity.subcategory)\n```\n\n### Detect PII\n\n```python\ndocuments = [\"My phone number is 555-555-5555.\"]\nresult = client.recognize_pii_entities(documents)[0]\n\nif not result.is_error:\n    print(result.redacted_text)\n    for entity in result.entities:\n        print(entity.text, entity.category)\n```\n\n### Extract key phrases\n\n```python\ndocuments = [\"This SDK wraps Azure Language service features for Python.\"]\nresult = client.extract_key_phrases(documents)[0]\n\nif not result.is_error:\n    print(result.key_phrases)\n```\n\n## Long-Running Operations\n\nUse `begin_*` methods for summarization, healthcare entity extraction, custom named entity recognition, and custom classification.\n\n### Run multiple actions together\n\n```python\nfrom azure.ai.textanalytics import (\n    AnalyzeSentimentAction,\n    ExtractKeyPhrasesAction,\n    RecognizeEntitiesAction,\n)\n\ndocuments = [\n    \"The service was fast, but the invoice address was wrong.\",\n]\n\npoller = client.begin_analyze_actions(\n    documents,\n    actions=[\n        RecognizeEntitiesAction(),\n        ExtractKeyPhrasesAction(),\n        AnalyzeSentimentAction(),\n    ],\n)\n\nfor action_results in poller.result():\n    for result in action_results:\n        if result.is_error:\n            print(\"error\", result.code, result.message)\n        else:\n            print(result.kind)\n```\n\n### Extractive summary\n\n```python\ndocuments = [\n    \"Azure AI Language can extract sentences that best summarize a document.\",\n]\n\npoller = client.begin_extract_summary(documents, max_sentence_count=3)\n\nfor result in poller.result():\n    if not result.is_error:\n        for sentence in result.sentences:\n            print(sentence.text)\n```\n\n### Custom classification\n\n```python\npoller = client.begin_single_label_classify(\n    [\"Please close my account immediately.\"],\n    project_name=\"support-routing\",\n    deployment_name=\"production\",\n)\n\nfor result in poller.result():\n    if not result.is_error:\n        for classification in result.classifications:\n            print(classification.category, classification.confidence_score)\n```\n\nFeature boundaries that matter:\n\n- healthcare entity analysis exists on `begin_analyze_healthcare_entities(...)`\n- custom entity recognition and custom classification require service API `2022-05-01` or newer\n- extractive and abstractive summarization require service API `2023-04-01` or newer\n\n## Common Options On Calls\n\nDepending on the method, commonly useful keyword arguments include:\n\n- `language`\n- `model_version`\n- `show_stats`\n- `disable_service_logs`\n- `string_index_type`\n\n`disable_service_logs=True` opts out of service-side logging of your text for troubleshooting. `string_index_type` matters if you need offsets that line up with a specific client encoding model.\n\n## Async Usage\n\nIf you are already in an async app, use the `aio` client:\n\n```python\nimport os\n\nfrom azure.ai.textanalytics.aio import TextAnalyticsClient\nfrom azure.core.credentials import AzureKeyCredential\n\nendpoint = os.environ[\"AZURE_LANGUAGE_ENDPOINT\"]\nkey = os.environ[\"AZURE_LANGUAGE_KEY\"]\n\nasync def main() -> None:\n    client = TextAnalyticsClient(endpoint, AzureKeyCredential(key))\n    async with client:\n        results = await client.extract_key_phrases(\n            [\"Agent workflows depend on package docs.\"]\n        )\n        print(results[0].key_phrases)\n```\n\n## Common Pitfalls\n\n- Do not pass a bare string where the SDK expects a batch. Use `[\"text\"]`, not `\"text\"`.\n- Check `result.is_error` before reading result fields. Batch responses can mix success objects and `DocumentError` objects.\n- Do not assume old examples still match the current client surface. `5.2.x+` is the Language service era, not the older Text Analytics-only shape.\n- If you rely on Entra ID, do not use a regional endpoint.\n- If you persist continuation tokens for long-running operations, treat the `5.4.0` upgrade as a compatibility boundary.\n- If offsets matter, set `string_index_type` deliberately instead of assuming another runtime's indexing behavior.\n- Confirm service-side data limits before sending very large documents or batches.\n\n## Official Sources\n\n- Docs root: `https://learn.microsoft.com/en-us/python/api/azure-ai-textanalytics/`\n- Overview and getting started: `https://learn.microsoft.com/en-us/python/api/overview/azure/ai-textanalytics-readme?view=azure-python`\n- `TextAnalyticsClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-ai-textanalytics/azure.ai.textanalytics.textanalyticsclient?view=azure-python`\n- PyPI package page: `https://pypi.org/project/azure-ai-textanalytics/`\n- Changelog: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/textanalytics/azure-ai-textanalytics/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/app-configuration/javascript/DOC.md",
    "content": "---\nname: app-configuration\ndescription: \"Azure App Configuration JavaScript client for connecting to a store, authenticating with connection strings or Microsoft Entra ID, and managing settings with labels and revisions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,app-configuration,configuration,javascript,entra-id\"\n---\n\n# Azure App Configuration JavaScript Client\n\n## Golden Rule\n\nUse `@azure/app-configuration` when your code needs direct data-plane access to an Azure App Configuration store: read settings, write settings, filter by label, and inspect revision history. Prefer Microsoft Entra ID for deployed applications, use a connection string for local development or tightly scoped automation, and reuse one client instead of creating a new client per operation.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @azure/app-configuration@1.11.0\n```\n\nIf you authenticate with Microsoft Entra ID, install `@azure/identity` too:\n\n```bash\nnpm install @azure/app-configuration@1.11.0 @azure/identity\n```\n\n## Authentication And Setup\n\nYou usually connect to App Configuration in one of two ways:\n\n- connection string\n- store endpoint plus a credential such as `DefaultAzureCredential`\n\nUse environment variables instead of hard-coding secrets:\n\n```bash\nexport AZURE_APPCONFIG_ENDPOINT=\"https://<store-name>.azconfig.io\"\nexport AZURE_APPCONFIG_CONNECTION_STRING=\"Endpoint=https://<store-name>.azconfig.io;Id=...;Secret=...\"\n```\n\nTo retrieve a connection string with Azure CLI:\n\n```bash\naz appconfig credential list --name <store-name>\n```\n\n### Connection String Client\n\n```js\nimport { AppConfigurationClient } from \"@azure/app-configuration\";\n\nconst client = new AppConfigurationClient(\n  process.env.AZURE_APPCONFIG_CONNECTION_STRING,\n);\n```\n\n### Microsoft Entra ID Client\n\n```js\nimport { AppConfigurationClient } from \"@azure/app-configuration\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst client = new AppConfigurationClient(\n  process.env.AZURE_APPCONFIG_ENDPOINT,\n  new DefaultAzureCredential(),\n);\n```\n\nFor Entra ID, App Configuration data-plane roles matter:\n\n- `App Configuration Data Reader` for read-only access\n- `App Configuration Data Owner` for read/write/delete access\n\nManagement roles alone are not enough for SDK data access.\n\n## Client Initialization\n\nCreate one shared client for the part of your app that talks to App Configuration.\n\n```js\nimport { AppConfigurationClient } from \"@azure/app-configuration\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nexport const appConfigClient = process.env.AZURE_APPCONFIG_CONNECTION_STRING\n  ? new AppConfigurationClient(process.env.AZURE_APPCONFIG_CONNECTION_STRING)\n  : new AppConfigurationClient(\n      process.env.AZURE_APPCONFIG_ENDPOINT,\n      new DefaultAzureCredential(),\n    );\n```\n\n## Core Usage\n\n### Create a setting\n\nUse `addConfigurationSetting(...)` when the key and label must not already exist.\n\n```js\nconst created = await appConfigClient.addConfigurationSetting({\n  key: \"app:theme\",\n  label: \"prod\",\n  value: \"dark\",\n  contentType: \"text/plain\",\n});\n\nconsole.log(created.key, created.label, created.value);\n```\n\n### Create or replace a setting\n\nUse `setConfigurationSetting(...)` when overwriting an existing key-label pair is acceptable.\n\n```js\nconst saved = await appConfigClient.setConfigurationSetting({\n  key: \"app:theme\",\n  label: \"prod\",\n  value: \"light\",\n  contentType: \"text/plain\",\n  tags: {\n    service: \"web\",\n    env: \"prod\",\n  },\n});\n\nconsole.log(saved.etag);\n```\n\n### Read one setting\n\nPass the key and, when you use labels, the exact label you want.\n\n```js\nconst setting = await appConfigClient.getConfigurationSetting({\n  key: \"app:theme\",\n  label: \"prod\",\n});\n\nconsole.log(setting.value);\n```\n\nIf you omit `label`, the client reads the unlabeled variant of that key.\n\n### Delete a setting\n\n```js\nawait appConfigClient.deleteConfigurationSetting({\n  key: \"app:theme\",\n  label: \"prod\",\n});\n```\n\n### List settings by key and label filters\n\n`listConfigurationSettings(...)` returns an async iterator. Use it directly with `for await`.\n\n```js\nfor await (const setting of appConfigClient.listConfigurationSettings({\n  keyFilter: \"app:*\",\n  labelFilter: \"prod\",\n})) {\n  console.log(`${setting.key} (${setting.label}): ${setting.value}`);\n}\n```\n\nThis is the normal way to load a small namespace such as `app:*` for one environment label.\n\n### Inspect revision history\n\nUse `listRevisions(...)` when you need to inspect previous values or labels.\n\n```js\nfor await (const revision of appConfigClient.listRevisions({\n  keyFilter: \"app:*\",\n  labelFilter: \"prod\",\n})) {\n  console.log(revision.key, revision.label, revision.value, revision.lastModified);\n}\n```\n\n## Practical Notes\n\n- Treat the combination of `key` and `label` as the unique identity of a setting.\n- Use labels deliberately for environments such as `dev`, `staging`, and `prod`.\n- Reuse a long-lived client instead of constructing one for every request.\n- Keep connection strings in a secret store, not in source control.\n- Prefer Entra ID for deployed services when you can assign the correct data-plane role.\n\n## Common Pitfalls\n\n- Using `addConfigurationSetting(...)` when you really wanted overwrite behavior from `setConfigurationSetting(...)`.\n- Forgetting that a labeled setting and an unlabeled setting are different records.\n- Installing only `@azure/app-configuration` and then trying to use `DefaultAzureCredential` without `@azure/identity`.\n- Assigning control-plane access in Azure and expecting that alone to grant SDK data access.\n- Treating this low-level client as a full application configuration loader.\n\n## Version Notes For `1.11.0`\n\n- This guide targets `@azure/app-configuration` `1.11.0`.\n- Keep examples on the current `AppConfigurationClient` API surface shown in the Microsoft Learn JavaScript reference.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/app-configuration/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/app-configuration-readme?view=azure-node-latest`\n- `AppConfigurationClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/app-configuration/appconfigurationclient?view=azure-node-latest`\n- `ConfigurationSetting` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/app-configuration/configurationsetting?view=azure-node-latest`\n- Azure App Configuration quickstart for JavaScript: `https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-javascript`\n- npm package page: `https://www.npmjs.com/package/@azure/app-configuration`\n"
  },
  {
    "path": "content/azure/docs/appconfiguration/python/DOC.md",
    "content": "---\nname: appconfiguration\ndescription: \"azure-appconfiguration package guide for Python covering client setup, authentication, CRUD operations, filtering, snapshots, async usage, and 1.8.0-specific notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,app-configuration,configuration,entra-id,async,snapshots\"\n---\n\n# azure-appconfiguration Python Package Guide\n\n## What It Is\n\n`azure-appconfiguration` is the low-level Azure SDK client for reading and writing data in an Azure App Configuration store.\n\nUse it when your code needs to:\n\n- create, update, delete, or query configuration settings directly\n- work with labels, tags, revision history, and point-in-time reads\n- create or inspect snapshots\n- integrate App Configuration access into service code or automation\n\nDo not confuse it with `azure-appconfiguration-provider`:\n\n- `azure-appconfiguration` is the data-plane CRUD client\n- `azure-appconfiguration-provider` is the higher-level config loader for app startup, `load(...)`, `SettingSelector`, prefix trimming, Key Vault reference resolution, and feature-flag loading\n\n## Version Context\n\n- Ecosystem: `pypi`\n- Package: `azure-appconfiguration`\n- Version covered: `1.8.0`\n- PyPI release date: `2026-01-27`\n- Python requirement on PyPI: `>=3.8`\n- Docs root: `https://learn.microsoft.com/en-us/python/api/azure-appconfiguration/`\n- Registry: `https://pypi.org/project/azure-appconfiguration/`\n- Repository: `https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/appconfiguration/azure-appconfiguration`\n\nThis guide is written for the `1.8.0` line reflected by the current Microsoft Learn package guide and PyPI release.\n\n## Install\n\nBasic install:\n\n```bash\npython -m pip install azure-appconfiguration==1.8.0\n```\n\nIf you want Microsoft Entra ID authentication:\n\n```bash\npython -m pip install azure-appconfiguration==1.8.0 azure-identity\n```\n\n## Authentication And Setup\n\nThe SDK has two normal entry paths:\n\n- connection string via `AzureAppConfigurationClient.from_connection_string(...)`\n- Microsoft Entra ID via `AzureAppConfigurationClient(base_url=..., credential=...)`\n\nPrefer Entra ID for deployed applications. Use connection strings mainly for local development, bootstrap flows, or controlled automation.\n\n### Recommended Environment Variables\n\n```bash\nexport AZURE_APPCONFIG_ENDPOINT=\"https://<store-name>.azconfig.io\"\nexport AZURE_APPCONFIG_CONNECTION_STRING=\"Endpoint=https://<store-name>.azconfig.io;Id=...;Secret=...\"\n```\n\nUpstream examples also use `APPCONFIGURATION_CONNECTION_STRING`. The package does not require a specific env var name, but your codebase should pick one convention and stick to it.\n\n### Connection String Client\n\n```python\nimport os\n\nfrom azure.appconfiguration import AzureAppConfigurationClient\n\nclient = AzureAppConfigurationClient.from_connection_string(\n    os.environ[\"AZURE_APPCONFIG_CONNECTION_STRING\"]\n)\n```\n\nTo retrieve the connection string with Azure CLI:\n\n```bash\naz appconfig credential list --name <config-store-name>\n```\n\n### Microsoft Entra ID Client\n\n```python\nimport os\n\nfrom azure.appconfiguration import AzureAppConfigurationClient\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\nclient = AzureAppConfigurationClient(\n    base_url=os.environ[\"AZURE_APPCONFIG_ENDPOINT\"],\n    credential=credential,\n)\n```\n\nImportant auth notes:\n\n- `azure-identity` is a separate dependency\n- Entra auth needs data-plane roles, not just control-plane roles\n- role propagation can take up to 15 minutes after assignment\n\nRequired App Configuration roles:\n\n- `App Configuration Data Reader` for read-only access\n- `App Configuration Data Owner` for read/write/delete access\n\nStore-level `Reader`, `Contributor`, or `Owner` does not by itself grant data-plane access through Entra ID.\n\n### Sovereign Cloud Audience\n\n`1.8.0` adds an `audience=` keyword argument on `AzureAppConfigurationClient(...)` for non-public Azure clouds.\n\n```python\nclient = AzureAppConfigurationClient(\n    base_url=os.environ[\"AZURE_APPCONFIG_ENDPOINT\"],\n    credential=DefaultAzureCredential(),\n    audience=\"<supported audience for your cloud>\",\n)\n```\n\nOnly set `audience` when the default public-cloud audience is wrong for your environment.\n\n## Core Model\n\nThe main resource type is `ConfigurationSetting`.\n\nCommon fields you will use:\n\n- `key`\n- `label`\n- `value`\n- `content_type`\n- `tags`\n- `read_only`\n- `etag`\n- `last_modified`\n\nA setting is identified by `(key, label)`. Unlabeled and labeled values are different records.\n\n## Core CRUD Usage\n\n### Create Only\n\nUse `add_configuration_setting(...)` when the setting must not already exist.\n\n```python\nfrom azure.appconfiguration import AzureAppConfigurationClient, ConfigurationSetting\n\nclient = AzureAppConfigurationClient.from_connection_string(\n    \"Endpoint=https://<store>.azconfig.io;Id=...;Secret=...\"\n)\n\nsetting = ConfigurationSetting(\n    key=\"app:message\",\n    label=\"prod\",\n    value=\"hello\",\n    content_type=\"text/plain\",\n    tags={\"team\": \"api\"},\n)\n\ncreated = client.add_configuration_setting(setting)\nprint(created.key, created.label, created.value)\n```\n\n### Upsert\n\nUse `set_configuration_setting(...)` when create-or-replace behavior is acceptable.\n\n```python\nsetting.value = \"hello again\"\nsaved = client.set_configuration_setting(setting)\nprint(saved.etag)\n```\n\n### Read One Setting\n\n```python\ncurrent = client.get_configuration_setting(\n    key=\"app:message\",\n    label=\"prod\",\n)\n\nprint(current.value)\nprint(current.content_type)\nprint(current.tags)\n```\n\n### Delete One Setting\n\n```python\ndeleted = client.delete_configuration_setting(\n    key=\"app:message\",\n    label=\"prod\",\n)\n\nprint(deleted)\n```\n\n## Safe Updates With ETags\n\nUse `etag` plus `match_condition` when you do not want concurrent writers to overwrite each other silently.\n\n```python\nfrom azure.core import MatchConditions\n\ncurrent = client.get_configuration_setting(key=\"app:message\", label=\"prod\")\ncurrent.value = \"new value\"\n\nupdated = client.set_configuration_setting(\n    current,\n    etag=current.etag,\n    match_condition=MatchConditions.IfNotModified,\n)\n```\n\nThe same pattern matters for deletes and read-only changes.\n\n## Filters, History, And Labels\n\n### List Settings\n\n```python\nitems = client.list_configuration_settings(\n    key_filter=\"app:*\",\n    label_filter=\"prod\",\n    tags_filter=[\"team=api\"],\n)\n\nfor item in items:\n    print(item.key, item.label, item.value)\n```\n\nUseful points:\n\n- `*` works as a wildcard at the beginning or end of supported filters\n- `tags_filter` expects strings like `\"key=value\"`\n- results are paged iterators\n\n### List Labels\n\n```python\nfor label in client.list_labels(name=\"prod*\"):\n    print(label)\n```\n\nThis is useful when you need to discover environment labels before reading settings.\n\n### Revision History\n\n```python\nfor item in client.list_revisions(\n    key_filter=\"app:message\",\n    label_filter=\"prod\",\n):\n    print(item.last_modified, item.etag, item.value)\n```\n\n### Point-In-Time Reads\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\npoint_in_time = datetime.now(timezone.utc) - timedelta(hours=1)\n\nhistorical = client.get_configuration_setting(\n    key=\"app:message\",\n    label=\"prod\",\n    accept_datetime=point_in_time,\n)\n\nprint(historical.value)\n```\n\n`accept_datetime` is available on current `get_configuration_setting(...)`, `list_configuration_settings(...)`, `list_labels(...)`, and `list_revisions(...)` flows.\n\n## Read-Only State\n\n```python\ncurrent = client.get_configuration_setting(key=\"app:message\", label=\"prod\")\n\nclient.set_read_only(current)\nclient.set_read_only(current, read_only=False)\n```\n\nThis locks or unlocks the server-side key-value. It is a useful safeguard, but it does not replace RBAC.\n\n## Snapshots\n\n`1.8.0` includes snapshot APIs for point-in-time configuration sets.\n\n```python\nfrom azure.appconfiguration import ConfigurationSettingsFilter\n\nfilters = [\n    ConfigurationSettingsFilter(key=\"app:*\", label=\"prod\"),\n]\n\npoller = client.begin_create_snapshot(\n    name=\"release-2026-03-12\",\n    filters=filters,\n    tags={\"release\": \"2026-03-12\"},\n)\nsnapshot = poller.result()\n\nprint(snapshot.name, snapshot.status)\n```\n\nRelated APIs in the current line:\n\n- `get_snapshot(...)`\n- `list_snapshots(...)`\n- `archive_snapshot(...)`\n- `recover_snapshot(...)`\n\nUse snapshots when you need a stable set of configuration values that should not drift while a deployment or rollout is in progress.\n\n## Async Usage\n\nAsync support lives under `azure.appconfiguration.aio`.\n\n```python\nimport asyncio\nimport os\n\nfrom azure.appconfiguration.aio import AzureAppConfigurationClient\n\nasync def main() -> None:\n    client = AzureAppConfigurationClient.from_connection_string(\n        os.environ[\"AZURE_APPCONFIG_CONNECTION_STRING\"]\n    )\n    try:\n        setting = await client.get_configuration_setting(\n            key=\"app:message\",\n            label=\"prod\",\n        )\n        print(setting.value)\n\n        async for item in client.list_revisions(key_filter=\"app:*\"):\n            print(item.key, item.value)\n    finally:\n        await client.close()\n\nasyncio.run(main())\n```\n\nUse the async client if the rest of your service is already async. Iterate paged results with `async for`, and close the client when you are done.\n\n## When To Use `azure-appconfiguration-provider` Instead\n\nChoose `azure-appconfiguration-provider` instead of this package when your main goal is application configuration loading rather than low-level key-value management.\n\nThe provider package adds higher-level behaviors such as:\n\n- `load(...)`\n- `SettingSelector`\n- prefix trimming\n- Key Vault reference resolution\n- feature-flag loading\n\nThat package is better for startup-time config hydration. `azure-appconfiguration` is better for direct SDK-style reads, writes, history queries, and snapshot management.\n\n## Common Pitfalls\n\n- Installing only `azure-appconfiguration` and then using `DefaultAzureCredential` without also installing `azure-identity`\n- Using Entra ID with the wrong IAM role; data-plane access needs `App Configuration Data Reader` or `App Configuration Data Owner`\n- Treating an unlabeled key and a labeled key as the same setting\n- Using `set_configuration_setting(...)` when you really needed create-only behavior from `add_configuration_setting(...)`\n- Skipping `etag` checks in multi-writer code paths\n- Using the low-level client where the provider package would handle selectors, trimming, and feature-flag loading more cleanly\n\n## Version-Sensitive Notes For 1.8.0\n\n- PyPI lists `1.8.0` as the latest stable release on `2026-01-27`\n- PyPI requires Python `>=3.8`\n- The constructor docs for the current line show default `api_version=\"2023-11-01\"`; overriding it may lead to unsupported behavior\n- Azure SDK February 2026 release notes call out new `1.8.0` support for constructor `audience=...` and `by_page(match_conditions=...)` on the iterator returned by `list_configuration_settings()`\n- If your project is pinned to an older `1.x` release, re-check snapshot support and any pagination or audience-related code against that exact version before copying examples\n\n## Official Sources Used\n\n- Microsoft Learn package guide: `https://learn.microsoft.com/en-us/python/api/overview/azure/appconfiguration-readme?view=azure-python`\n- Microsoft Learn client API reference: `https://learn.microsoft.com/en-us/python/api/azure-appconfiguration/azure.appconfiguration.azureappconfigurationclient?view=azure-python`\n- Microsoft Learn `ConfigurationSetting` reference: `https://learn.microsoft.com/en-us/python/api/azure-appconfiguration/azure.appconfiguration.configurationsetting?view=azure-python`\n- Microsoft Learn RBAC guidance: `https://learn.microsoft.com/en-us/azure/azure-app-configuration/concept-enable-rbac`\n- Microsoft Learn provider reference: `https://learn.microsoft.com/en-us/azure/azure-app-configuration/reference-python-provider`\n- PyPI package page: `https://pypi.org/project/azure-appconfiguration/`\n- Azure SDK release notes: `https://azure.github.io/azure-sdk/releases/2026-02/python.html`\n"
  },
  {
    "path": "content/azure/docs/arm-appservice/javascript/DOC.md",
    "content": "---\nname: arm-appservice\ndescription: \"Azure App Service management client for JavaScript for App Service plans, web apps, app settings, and related Microsoft.Web control-plane operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"18.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,app-service,arm,management,web-apps,javascript\"\n---\n\n# Azure App Service Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-appservice` for Azure Resource Manager control-plane work on App Service resources: creating or updating App Service plans, creating web apps, reading site properties, replacing app settings, and managing other `Microsoft.Web` resources.\n\nDo not use this package to deploy your application code or to call your running app. App deployment usually happens through Azure CLI, ZipDeploy, GitHub Actions, or another CI/CD path.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-appservice@18.0.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs a `TokenCredential` and an Azure subscription ID.\n\nFor local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport APP_SERVICE_PLAN_NAME=\"example-plan\"\nexport WEB_APP_NAME=\"example-app-12345\"\nexport AZURE_LOCATION=\"westus2\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nThis package manages existing Azure resources inside a subscription. Your subscription and target resource group should already exist before you create an App Service plan or site.\n\n## Client Initialization\n\nCreate one shared client and reuse it across related management operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { WebSiteManagementClient } from \"@azure/arm-appservice\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst planName = process.env.APP_SERVICE_PLAN_NAME ?? \"example-plan\";\nconst webAppName = process.env.WEB_APP_NAME ?? \"example-app-12345\";\nconst location = process.env.AZURE_LOCATION ?? \"westus2\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const appServiceClient = new WebSiteManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport { location, planName, resourceGroupName, webAppName };\n```\n\nFor everyday App Service automation, most code lives on `appServiceClient.appServicePlans` and `appServiceClient.webApps`.\n\n## Core Usage\n\n### Create an App Service plan\n\nPlan creation is a long-running ARM operation. Use the `AndWait` helper when the next step depends on the finished resource.\n\nFor Linux plans, set `reserved: true`.\n\n```js\nimport {\n  appServiceClient,\n  location,\n  planName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst plan = await appServiceClient.appServicePlans.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  planName,\n  {\n    location,\n    reserved: true,\n    sku: {\n      name: \"B1\",\n      tier: \"Basic\",\n      size: \"B1\",\n      capacity: 1,\n    },\n  },\n);\n\nconsole.log(plan.id);\n```\n\nImportant details:\n\n- `location` is required.\n- `reserved: true` is what marks the plan as Linux.\n- Plan creation is not instant; treat it as a long-running operation.\n\n### Create a web app on that plan\n\nRead the App Service plan resource ID from Azure and pass it as `serverFarmId`.\n\n```js\nimport {\n  appServiceClient,\n  location,\n  planName,\n  resourceGroupName,\n  webAppName,\n} from \"./client.js\";\n\nconst plan = await appServiceClient.appServicePlans.get(\n  resourceGroupName,\n  planName,\n);\n\nconst site = await appServiceClient.webApps.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  webAppName,\n  {\n    location,\n    serverFarmId: plan.id,\n    httpsOnly: true,\n    siteConfig: {\n      linuxFxVersion: \"NODE|20-lts\",\n      alwaysOn: true,\n      ftpsState: \"Disabled\",\n      minTlsVersion: \"1.2\",\n    },\n  },\n);\n\nconsole.log(site.defaultHostName);\n```\n\nPractical notes:\n\n- `serverFarmId` should come from the actual plan object rather than a string assembled by hand.\n- `linuxFxVersion` configures the runtime stack. Keep it aligned with a runtime App Service currently supports.\n- `httpsOnly: true` and `minTlsVersion: \"1.2\"` are safer defaults than leaving them unset.\n\n### List and inspect apps in a resource group\n\nList operations use the Azure SDK paging model, so iterate with `for await`.\n\n```js\nimport { appServiceClient, resourceGroupName, webAppName } from \"./client.js\";\n\nfor await (const app of appServiceClient.webApps.listByResourceGroup(resourceGroupName)) {\n  console.log(app.name, app.state, app.defaultHostName);\n}\n\nconst app = await appServiceClient.webApps.get(resourceGroupName, webAppName);\n\nconsole.log(app.kind);\nconsole.log(app.serverFarmId);\n```\n\n### Read and replace app settings\n\n`updateApplicationSettings(...)` replaces the app settings payload, so merge with the current values when you only want to change one key.\n\n```js\nimport { appServiceClient, resourceGroupName, webAppName } from \"./client.js\";\n\nconst current = await appServiceClient.webApps.listApplicationSettings(\n  resourceGroupName,\n  webAppName,\n);\n\nconst settings = {\n  ...(current.properties ?? {}),\n  SCM_DO_BUILD_DURING_DEPLOYMENT: \"1\",\n  WEBSITE_NODE_DEFAULT_VERSION: \"~20\",\n};\n\nconst updated = await appServiceClient.webApps.updateApplicationSettings(\n  resourceGroupName,\n  webAppName,\n  {\n    properties: settings,\n  },\n);\n\nconsole.log(updated.properties?.WEBSITE_NODE_DEFAULT_VERSION);\n```\n\nDo not treat this as a patch call. The official operation replaces the application settings of the app.\n\n## Configuration Notes\n\n- `subscriptionId` is required; the client does not infer it from the credential.\n- App Service plan and site creation are long-running ARM operations; expect `begin*` methods and use `AndWait` helpers when a later step depends on the created resource.\n- `listApplicationSettings()` returns a string-dictionary style result; the actual key-values live under `.properties`.\n- This package is for control-plane management. Runtime deployment, build behavior, and startup behavior are still separate App Service concerns.\n\n## Common Pitfalls\n\n- Installing `@azure/arm-appservice` without `@azure/identity`\n- Using this package for code deployment instead of Azure resource management\n- Forgetting `reserved: true` when creating a Linux App Service plan\n- Hard-coding `serverFarmId` instead of using the plan resource ID returned by Azure\n- Treating `updateApplicationSettings()` as a patch instead of a replacement\n- Forgetting that `begin*` operations are long-running and not immediately complete\n- Setting a runtime in `siteConfig.linuxFxVersion` that your target App Service environment does not support\n\n## Version Notes For `18.0.0`\n\nThis guide targets `@azure/arm-appservice@18.0.0` and the current Microsoft Learn JavaScript API reference for the package.\n\nIf you are copying older examples, confirm the current operation names and model fields on the latest `WebSiteManagementClient` reference before reusing them.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@azure/arm-appservice\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-appservice/\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-appservice/websitemanagementclient?view=azure-node-latest\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-appservice/appserviceplans?view=azure-node-latest\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-appservice/webapps?view=azure-node-latest\n- https://learn.microsoft.com/en-us/azure/app-service/configure-language-nodejs\n"
  },
  {
    "path": "content/azure/docs/arm-compute/javascript/DOC.md",
    "content": "---\nname: arm-compute\ndescription: \"Azure Compute management client for JavaScript for working with virtual machines, managed disks, VM scale sets, and other ARM compute resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"23.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,compute,virtual-machines,disks,vmss,javascript\"\n---\n\n# Azure Compute Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-compute` for Azure Resource Manager control-plane operations on compute resources such as virtual machines, managed disks, snapshots, images, and VM scale sets. Authenticate with a `TokenCredential`, construct one shared `ComputeManagementClient` per subscription, and treat most create, update, start, stop, and delete operations as long-running ARM calls that should use `begin...AndWait(...)` helpers.\n\nThis is not a guest-level SSH or WinRM library, and it does not replace the Azure network, resource-group, or image configuration you still need around a VM deployment.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-compute@23.3.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe normal setup is `DefaultAzureCredential` plus an explicit Azure subscription ID.\n\nFor local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport AZURE_LOCATION=\"eastus\"\nexport VM_NAME=\"example-vm\"\nexport DISK_NAME=\"example-disk\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service-principal environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nIf you plan to create or update a virtual machine, you usually also need existing sibling ARM resources such as a resource group and network interface. `@azure/arm-compute` manages the compute resource itself; it does not create VNets, subnets, NICs, or resource groups for you.\n\n## Client Initialization\n\nCreate one shared client and reuse it across related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ComputeManagementClient } from \"@azure/arm-compute\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\nconst vmName = process.env.VM_NAME ?? \"example-vm\";\nconst diskName = process.env.DISK_NAME ?? \"example-disk\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const computeClient = new ComputeManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport { diskName, location, resourceGroupName, vmName };\n```\n\nMost day-to-day work starts from operation groups such as `computeClient.virtualMachines`, `computeClient.disks`, and `computeClient.virtualMachineScaleSets`.\n\n## Core Usage\n\n### Get one virtual machine\n\nUse `get(...)` when you already know the resource group and VM name.\n\n```js\nimport { computeClient, resourceGroupName, vmName } from \"./client.js\";\n\nconst vm = await computeClient.virtualMachines.get(resourceGroupName, vmName);\n\nconsole.log(vm.id);\nconsole.log(vm.location);\nconsole.log(vm.hardwareProfile?.vmSize);\nconsole.log(vm.provisioningState);\n```\n\n### List virtual machines in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { computeClient, resourceGroupName } from \"./client.js\";\n\nfor await (const vm of computeClient.virtualMachines.list(resourceGroupName)) {\n  console.log(vm.name, vm.location, vm.provisioningState);\n}\n```\n\n### Inspect VM runtime state with instance view\n\nUse `instanceView(...)` when you need power-state and provisioning status details in addition to the ARM resource model.\n\n```js\nimport { computeClient, resourceGroupName, vmName } from \"./client.js\";\n\nconst instanceView = await computeClient.virtualMachines.instanceView(\n  resourceGroupName,\n  vmName,\n);\n\nfor (const status of instanceView.statuses ?? []) {\n  console.log(status.code, status.displayStatus);\n}\n```\n\n### Start a VM or deallocate it to stop compute billing\n\nThese are long-running operations.\n\n```js\nimport { computeClient, resourceGroupName, vmName } from \"./client.js\";\n\nawait computeClient.virtualMachines.beginStartAndWait(resourceGroupName, vmName);\n\nawait computeClient.virtualMachines.beginDeallocateAndWait(\n  resourceGroupName,\n  vmName,\n);\n```\n\n`beginPowerOffAndWait(...)` stops the guest but does not release compute allocation. Use `beginDeallocateAndWait(...)` when you need compute billing to stop.\n\n### Create a managed disk\n\nCreating a disk is also a long-running ARM operation.\n\n```js\nimport {\n  computeClient,\n  diskName,\n  location,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst disk = await computeClient.disks.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  diskName,\n  {\n    location,\n    diskSizeGB: 128,\n    sku: {\n      name: \"StandardSSD_LRS\",\n    },\n    creationData: {\n      createOption: \"Empty\",\n    },\n  },\n);\n\nconsole.log(disk.id);\n```\n\nFor an empty managed disk, the important fields are `location`, `creationData.createOption`, and `diskSizeGB`.\n\n### Grant and revoke temporary disk access\n\nUse disk SAS access only for time-limited workflows such as export or troubleshooting.\n\n```js\nimport { computeClient, diskName, resourceGroupName } from \"./client.js\";\n\nconst access = await computeClient.disks.beginGrantAccessAndWait(\n  resourceGroupName,\n  diskName,\n  {\n    access: \"Read\",\n    durationInSeconds: 3600,\n  },\n);\n\nconsole.log(access.accessSAS);\n\nawait computeClient.disks.beginRevokeAccessAndWait(resourceGroupName, diskName);\n```\n\nThe grant request needs both `access` and `durationInSeconds`.\n\n### Create or update a virtual machine\n\nVM creation depends on more than compute settings alone. In practice, you usually create the resource group and NIC separately, then pass the NIC resource ID into the VM request.\n\n```js\nimport {\n  computeClient,\n  location,\n  resourceGroupName,\n  vmName,\n} from \"./client.js\";\n\nconst networkInterfaceId = process.env.NETWORK_INTERFACE_ID;\n\nif (!networkInterfaceId) {\n  throw new Error(\"Set NETWORK_INTERFACE_ID to an existing NIC resource ID.\");\n}\n\nconst vm = await computeClient.virtualMachines.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  vmName,\n  {\n    location,\n    hardwareProfile: {\n      vmSize: \"Standard_D2s_v5\",\n    },\n    storageProfile: {\n      imageReference: {\n        publisher: \"Canonical\",\n        offer: \"0001-com-ubuntu-server-jammy\",\n        sku: \"22_04-lts-gen2\",\n        version: \"latest\",\n      },\n    },\n    osProfile: {\n      computerName: vmName,\n      adminUsername: \"azureuser\",\n      adminPassword: \"replace-me\",\n    },\n    networkProfile: {\n      networkInterfaces: [\n        {\n          id: networkInterfaceId,\n          primary: true,\n        },\n      ],\n    },\n  },\n);\n\nconsole.log(vm.id);\n```\n\nKeep the compute, NIC, image, and region settings consistent. ARM validation failures often come from mismatched resource IDs, missing network dependencies, or an incomplete VM payload.\n\n## Configuration Notes\n\n- Reuse one `ComputeManagementClient` instead of creating a new client per call.\n- `AZURE_SUBSCRIPTION_ID` is required separately from your credential configuration.\n- Treat list results as async iterables, not plain arrays.\n- Use `begin...AndWait(...)` helpers when you need the ARM operation to finish before the next step.\n- `@azure/arm-compute` is a management-plane package. Use sibling Azure SDKs for resource groups, networks, or guest-level application traffic.\n- If you need to discover sizes and regional availability before provisioning, check `computeClient.resourceSkus` in the current Learn reference for the filter shape supported by your package version.\n\n## Common Pitfalls\n\n- Installing `@azure/arm-compute` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Authenticating successfully but forgetting to pass `AZURE_SUBSCRIPTION_ID` into `ComputeManagementClient`.\n- Calling a long-running `begin...` operation without waiting for the poller to finish.\n- Using `beginPowerOffAndWait(...)` when you really need `beginDeallocateAndWait(...)` to release compute allocation.\n- Treating VM creation as a compute-only task even though the VM usually depends on existing network resources.\n- Copying older Azure management samples without re-checking model fields and helper names against the `23.3.0` reference.\n\n## Version Notes For `23.3.0`\n\n- This guide targets `@azure/arm-compute` `23.3.0`.\n- The examples use `ComputeManagementClient` from `@azure/arm-compute` and `DefaultAzureCredential` from `@azure/identity`.\n- If you adapt older Azure SDK samples, re-check the current Learn reference before copying model shapes or poller usage into a project.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-compute-readme?view=azure-node-latest`\n- `ComputeManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/computemanagementclient?view=azure-node-latest`\n- `VirtualMachines` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/virtualmachines?view=azure-node-latest`\n- `Disks` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/disks?view=azure-node-latest`\n- `VirtualMachineScaleSets` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/virtualmachinescalesets?view=azure-node-latest`\n- `ResourceSkus` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/resourceskus?view=azure-node-latest`\n- `Disk` model reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/disk?view=azure-node-latest`\n- `CreationData` model reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/creationdata?view=azure-node-latest`\n- `GrantAccessData` model reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-compute/grantaccessdata?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-compute`\n"
  },
  {
    "path": "content/azure/docs/arm-containerservice/javascript/DOC.md",
    "content": "---\nname: arm-containerservice\ndescription: \"Azure Kubernetes Service management client for JavaScript with practical guidance for authentication, cluster inspection, kubeconfig retrieval, upgrades, and AKS control-plane operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"24.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,aks,kubernetes,containers,arm,management,javascript\"\n---\n\n# Azure Kubernetes Service Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-containerservice` for Azure Resource Manager control-plane operations against Azure Kubernetes Service (AKS), authenticate with a `TokenCredential` such as `DefaultAzureCredential`, and treat most mutating methods as long-running operations that should use `begin...AndWait` helpers. This package manages AKS resources in Azure; it does not replace `kubectl`, the Kubernetes JavaScript client, or in-cluster Kubernetes APIs.\n\n## Install\n\nInstall the management client and Azure Identity together:\n\n```bash\nnpm install @azure/arm-containerservice@24.1.0 @azure/identity\n```\n\nIf you also need to talk to the Kubernetes API after downloading kubeconfig credentials, use `kubectl` or a separate Kubernetes client library in addition to this package.\n\n## Authentication And Setup\n\nFor local development, sign in with Azure CLI:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport AKS_CLUSTER_NAME=\"example-aks\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nFor service principal authentication, set the standard Azure Identity environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nThe credential proves who you are, but the client still needs an explicit subscription ID. Most operations also need an existing resource group and AKS cluster name.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related ARM operations:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ContainerServiceClient } from \"@azure/arm-containerservice\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst clusterName = process.env.AKS_CLUSTER_NAME;\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nif (!clusterName) {\n  throw new Error(\"Set AKS_CLUSTER_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const aksClient = new ContainerServiceClient(credential, subscriptionId);\nexport { resourceGroupName, clusterName, location };\n```\n\nTwo SDK behaviors matter throughout this package:\n\n- List operations typically return paged async iterables, so use `for await ... of`.\n- Create, update, delete, and upgrade flows commonly use long-running ARM operations. Prefer `begin...AndWait` when you need the final state before continuing.\n\n## Core Usage\n\n### List AKS clusters\n\nList all managed clusters in the subscription:\n\n```js\nimport { aksClient } from \"./client.js\";\n\nfor await (const cluster of aksClient.managedClusters.list()) {\n  console.log(cluster.name, cluster.location, cluster.kubernetesVersion);\n}\n```\n\nList clusters in one resource group:\n\n```js\nimport { aksClient, resourceGroupName } from \"./client.js\";\n\nfor await (const cluster of aksClient.managedClusters.listByResourceGroup(resourceGroupName)) {\n  console.log(cluster.name, cluster.provisioningState);\n}\n```\n\n### Get one cluster\n\nUse `get` when you already know the resource group and cluster name:\n\n```js\nimport { aksClient, resourceGroupName, clusterName } from \"./client.js\";\n\nconst cluster = await aksClient.managedClusters.get(resourceGroupName, clusterName);\n\nconsole.log(cluster.id);\nconsole.log(cluster.kubernetesVersion);\nconsole.log(cluster.dnsPrefix);\nconsole.log(cluster.nodeResourceGroup);\nconsole.log(cluster.provisioningState);\n```\n\nImportant fields to inspect before writing update code include `agentPoolProfiles`, `identity`, `networkProfile`, and `kubernetesVersion`.\n\n### Retrieve kubeconfig credentials\n\nThe management API can return kubeconfig payloads for the cluster. Prefer user credentials unless you explicitly need cluster-admin access.\n\n```js\nimport { writeFile } from \"node:fs/promises\";\nimport { aksClient, resourceGroupName, clusterName } from \"./client.js\";\n\nconst credentials = await aksClient.managedClusters.listClusterUserCredentials(\n  resourceGroupName,\n  clusterName,\n);\n\nconst kubeconfigEntry = credentials.kubeconfigs?.[0];\n\nif (!kubeconfigEntry?.value) {\n  throw new Error(\"No kubeconfig returned for this cluster.\");\n}\n\nconst kubeconfig = typeof kubeconfigEntry.value === \"string\"\n  ? Buffer.from(kubeconfigEntry.value, \"base64\").toString(\"utf8\")\n  : Buffer.from(kubeconfigEntry.value).toString(\"utf8\");\n\nawait writeFile(\"./kubeconfig\", kubeconfig, { mode: 0o600 });\nconsole.log(\"Wrote ./kubeconfig\");\n```\n\nAdmin credentials use a separate call:\n\n```js\nconst adminCredentials = await aksClient.managedClusters.listClusterAdminCredentials(\n  resourceGroupName,\n  clusterName,\n);\n\nconsole.log(adminCredentials.kubeconfigs?.length ?? 0);\n```\n\nAfter you have kubeconfig, switch to `kubectl` or a Kubernetes client for Kubernetes API work.\n\n### Check available Kubernetes upgrades\n\nUse the upgrade profile before changing cluster version:\n\n```js\nimport { aksClient, resourceGroupName, clusterName } from \"./client.js\";\n\nconst profile = await aksClient.managedClusters.getUpgradeProfile(\n  resourceGroupName,\n  clusterName,\n);\n\nconsole.log(\"Current:\", profile.controlPlaneProfile?.kubernetesVersion);\n\nfor (const upgrade of profile.controlPlaneProfile?.upgrades ?? []) {\n  console.log(\"Available:\", upgrade.kubernetesVersion, upgrade.isPreview);\n}\n```\n\nDo not guess an upgrade target. Read the upgrade profile first and use a supported version from that response.\n\n### Create or update a cluster\n\nCluster creation uses a large ARM request body and should be treated like infrastructure code, not a tiny helper call. A minimal starting shape looks like this:\n\n```js\nimport { aksClient, resourceGroupName, clusterName, location } from \"./client.js\";\n\nconst cluster = await aksClient.managedClusters.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  clusterName,\n  {\n    location,\n    dnsPrefix: clusterName,\n    identity: {\n      type: \"SystemAssigned\",\n    },\n    agentPoolProfiles: [\n      {\n        name: \"systempool\",\n        count: 1,\n        vmSize: \"Standard_DS2_v2\",\n        mode: \"System\",\n        type: \"VirtualMachineScaleSets\",\n        osType: \"Linux\",\n      },\n    ],\n    linuxProfile: {\n      adminUsername: \"azureuser\",\n      ssh: {\n        publicKeys: [\n          {\n            keyData: \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...\",\n          },\n        ],\n      },\n    },\n    enableRBAC: true,\n  },\n);\n\nconsole.log(cluster.id);\n```\n\nBefore automating cluster creation, verify the exact payload your environment needs for region, network plugin, identity mode, and node-pool shape. For first-time provisioning, many teams prefer Bicep, ARM templates, or Terraform, then use this SDK for inspection and targeted updates.\n\n## Minimal Inspection Script\n\nThis is a complete script you can drop into a Node app to verify authentication and inspect one cluster:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ContainerServiceClient } from \"@azure/arm-containerservice\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst clusterName = process.env.AKS_CLUSTER_NAME;\n\nif (!subscriptionId || !resourceGroupName || !clusterName) {\n  throw new Error(\n    \"Set AZURE_SUBSCRIPTION_ID, RESOURCE_GROUP_NAME, and AKS_CLUSTER_NAME first.\",\n  );\n}\n\nconst client = new ContainerServiceClient(new DefaultAzureCredential(), subscriptionId);\nconst cluster = await client.managedClusters.get(resourceGroupName, clusterName);\n\nconsole.log({\n  name: cluster.name,\n  location: cluster.location,\n  kubernetesVersion: cluster.kubernetesVersion,\n  provisioningState: cluster.provisioningState,\n});\n```\n\n## Configuration Notes\n\n- This is an Azure Resource Manager management SDK. It manages AKS resources, not Kubernetes objects inside the cluster.\n- Authentication and subscription targeting are separate. A credential can succeed while the client still fails if `AZURE_SUBSCRIPTION_ID` is missing or wrong.\n- Reuse one `ContainerServiceClient` in long-lived processes instead of creating a new client for every call.\n- Read the current cluster shape before applying updates; AKS payloads are large and partial changes can still depend on networking, identity, and node-pool settings.\n- Use `getUpgradeProfile()` before any version change.\n\n## Version Notes For `24.1.0`\n\n- This guide targets `@azure/arm-containerservice` `24.1.0`.\n- If you are on a newer release, keep the same authentication and client-construction pattern, but confirm operation names and parameter shapes against the current Microsoft Learn API reference before copying examples.\n\n## Common Pitfalls\n\n- Installing `@azure/arm-containerservice` without `@azure/identity`\n- Assuming Azure login also selects the subscription for you inside the SDK\n- Treating `begin...` operations as synchronous and forgetting to wait for the final result\n- Using this package for Kubernetes in-cluster resources instead of using kubeconfig with `kubectl` or a Kubernetes client\n- Requesting admin credentials when user credentials are enough\n- Guessing a Kubernetes upgrade target without calling `getUpgradeProfile()` first\n- Building create-or-update payloads from incomplete examples without checking your cluster's actual networking and identity requirements\n\n## Recommended Workflow For Coding Agents\n\n1. Confirm the task is AKS management-plane work, not Kubernetes object management.\n2. Install `@azure/arm-containerservice@24.1.0` with `@azure/identity`.\n3. Authenticate with `DefaultAzureCredential()` and pass `AZURE_SUBSCRIPTION_ID` explicitly.\n4. Start with `managedClusters.get()` or `list()` to inspect the current cluster shape.\n5. Use `getUpgradeProfile()` before writing any Kubernetes version change.\n6. Fetch kubeconfig credentials only when the task needs to hand off to `kubectl` or a Kubernetes client.\n7. Treat cluster creation and major updates as infrastructure changes that need a fully specified ARM payload.\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-containerservice/\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-containerservice/containerserviceclient?view=azure-node-latest\n- https://learn.microsoft.com/en-us/javascript/api/@azure/arm-containerservice/managedclusters?view=azure-node-latest\n- https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest\n- https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest\n- https://www.npmjs.com/package/@azure/arm-containerservice\n"
  },
  {
    "path": "content/azure/docs/arm-cosmosdb/javascript/DOC.md",
    "content": "---\nname: arm-cosmosdb\ndescription: \"Azure Cosmos DB management client for JavaScript with ARM authentication, account inspection, key retrieval, and SQL resource provisioning\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"16.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,cosmosdb,arm,management,javascript\"\n---\n\n# Azure Cosmos DB Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-cosmosdb` for Azure Resource Manager control-plane work on Cosmos DB resources: listing accounts, reading account properties, retrieving account keys, and creating or updating SQL databases and containers.\n\nDo not use this package for item CRUD, queries, or container data access. Those are data-plane operations and belong in `@azure/cosmos`.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-cosmosdb@16.4.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs a `TokenCredential` and an Azure subscription ID. For local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"rg-app-prod\"\nexport COSMOS_ACCOUNT_NAME=\"example-cosmos-account\"\nexport COSMOS_SQL_DATABASE_NAME=\"appdb\"\nexport COSMOS_SQL_CONTAINER_NAME=\"items\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nImportant setup rules:\n\n- The identity must have Azure RBAC permission on the subscription or resource group that owns the Cosmos DB account.\n- `DefaultAzureCredential` can authenticate successfully with Azure CLI or other developer credentials while still pointing at the wrong subscription, so keep `AZURE_SUBSCRIPTION_ID` explicit.\n- This package manages ARM resources. Resource group names and account names are ARM identifiers, not Cosmos DB endpoint URLs.\n\n## Client Initialization\n\nCreate one shared client and reuse it across related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { CosmosDBManagementClient } from \"@azure/arm-cosmosdb\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst accountName = process.env.COSMOS_ACCOUNT_NAME;\nconst databaseName = process.env.COSMOS_SQL_DATABASE_NAME ?? \"appdb\";\nconst containerName = process.env.COSMOS_SQL_CONTAINER_NAME ?? \"items\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nif (!accountName) {\n  throw new Error(\"Set COSMOS_ACCOUNT_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const cosmosClient = new CosmosDBManagementClient(credential, subscriptionId);\nexport { accountName, containerName, databaseName, resourceGroupName };\n```\n\nThe main operation groups to expect are:\n\n- `cosmosClient.databaseAccounts`\n- `cosmosClient.sqlResources`\n\nThe client also exposes API-specific groups such as `mongoDBResources`, `cassandraResources`, `gremlinResources`, and `tableResources` when you manage non-SQL Cosmos DB APIs.\n\n## Core Usage\n\n### List Cosmos DB accounts in the subscription\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { cosmosClient } from \"./client.js\";\n\nfor await (const account of cosmosClient.databaseAccounts.list()) {\n  console.log(account.name, account.location, account.documentEndpoint);\n}\n```\n\nIf you already know the target account, use `get(...)` for the full ARM resource payload.\n\n```js\nimport {\n  accountName,\n  cosmosClient,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst account = await cosmosClient.databaseAccounts.get(\n  resourceGroupName,\n  accountName,\n);\n\nconsole.log(account.id);\nconsole.log(account.documentEndpoint);\n```\n\n### Read account keys\n\nUse the account management operations when an automation task needs the current primary or secondary keys.\n\n```js\nimport {\n  accountName,\n  cosmosClient,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst keys = await cosmosClient.databaseAccounts.listKeys(\n  resourceGroupName,\n  accountName,\n);\n\nconsole.log(keys.primaryMasterKey);\nconsole.log(keys.secondaryMasterKey);\n```\n\nTreat returned keys like secrets. Do not log them in real applications or CI output.\n\n### Create or update a SQL database\n\nSQL API database management lives under `sqlResources`. Create and update operations are long-running ARM operations, so use the `AndWait` helper when later steps depend on the final resource.\n\n```js\nimport {\n  accountName,\n  cosmosClient,\n  databaseName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst database = await cosmosClient.sqlResources.beginCreateUpdateSqlDatabaseAndWait(\n  resourceGroupName,\n  accountName,\n  databaseName,\n  {\n    resource: {\n      id: databaseName,\n    },\n  },\n);\n\nconsole.log(database.name);\n```\n\n### Create or update a SQL container\n\nThe container definition needs a partition key. Keep the partition key aligned with the data model the application will use later through `@azure/cosmos`.\n\n```js\nimport {\n  accountName,\n  containerName,\n  cosmosClient,\n  databaseName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst container = await cosmosClient.sqlResources.beginCreateUpdateSqlContainerAndWait(\n  resourceGroupName,\n  accountName,\n  databaseName,\n  containerName,\n  {\n    resource: {\n      id: containerName,\n      partitionKey: {\n        paths: [\"/tenantId\"],\n        kind: \"Hash\",\n      },\n    },\n  },\n);\n\nconsole.log(container.name);\n```\n\n### List SQL databases and containers\n\n```js\nimport {\n  accountName,\n  cosmosClient,\n  databaseName,\n  resourceGroupName,\n} from \"./client.js\";\n\nfor await (const database of cosmosClient.sqlResources.listSqlDatabases(\n  resourceGroupName,\n  accountName,\n)) {\n  console.log(database.name);\n}\n\nfor await (const container of cosmosClient.sqlResources.listSqlContainers(\n  resourceGroupName,\n  accountName,\n  databaseName,\n)) {\n  console.log(container.name);\n}\n```\n\n## Configuration Notes\n\n- Reuse one `CosmosDBManagementClient` instead of constructing a new client for every operation.\n- Keep `AZURE_SUBSCRIPTION_ID` explicit even when local Azure CLI login is available.\n- Use `databaseAccounts` for account metadata, keys, failover, and account-level settings.\n- Use `sqlResources` for SQL databases, containers, throughput, and SQL API role-definition or role-assignment management.\n- Choose the operation group that matches the account API type; SQL API resource methods do not live under `databaseAccounts`.\n\n## Common Pitfalls\n\n- Treating `@azure/arm-cosmosdb` as the SDK for document reads and writes. Use `@azure/cosmos` for data-plane work.\n- Installing `@azure/arm-cosmosdb` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Forgetting to await `beginCreateUpdateSqlDatabaseAndWait(...)` or `beginCreateUpdateSqlContainerAndWait(...)` before assuming the resource is ready.\n- Passing a Cosmos DB endpoint URL where ARM methods expect a resource group name and account name.\n- Assuming list operations return plain arrays instead of paged async iterables.\n- Designing a SQL container here with the wrong partition key and then discovering the mismatch later in the data-plane client.\n- Logging `listKeys(...)` results or writing them into build logs.\n\n## Version Notes For `16.4.0`\n\n- This guide targets `@azure/arm-cosmosdb` `16.4.0`.\n- Prefer the current `@azure/identity` credential flow and promise-based client methods when rewriting older Cosmos DB management samples.\n- For Cosmos DB item access, continue to use `@azure/cosmos`; this package is the ARM management client.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-cosmosdb/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-cosmosdb-readme?view=azure-node-latest`\n- `CosmosDBManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-cosmosdb/cosmosdbmanagementclient?view=azure-node-latest`\n- `databaseAccounts` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-cosmosdb/databaseaccounts?view=azure-node-latest`\n- `sqlResources` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-cosmosdb/sqlresources?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-cosmosdb`\n"
  },
  {
    "path": "content/azure/docs/arm-deviceprovisioningservices/javascript/DOC.md",
    "content": "---\nname: arm-deviceprovisioningservices\ndescription: \"Azure Device Provisioning Services management client for JavaScript with practical guidance for authentication, provisioning-service lifecycle operations, and shared access key lookup\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,device-provisioning-services,arm,iot,dps,javascript\"\n---\n\n# Azure Device Provisioning Services Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-deviceprovisioningservices` for Azure Resource Manager control-plane work on Azure IoT Device Provisioning Service resources: checking service name availability, creating or deleting a provisioning service, listing services in a subscription or resource group, reading service metadata, and retrieving shared access policies.\n\nDo not use this package for device enrollment, registration status queries, or device-side provisioning traffic. Those are Device Provisioning Service data-plane tasks, not ARM management tasks.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-deviceprovisioningservices@5.1.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs a `TokenCredential` and your Azure subscription ID. For local development, Azure CLI login is usually the fastest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport DPS_NAME=\"example-dps\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nFor CI or deployed applications, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nIf you plan to create a provisioning service, also provide an existing IoT Hub owner connection string to link the service to a hub:\n\n```bash\nexport IOTHUB_OWNER_CONNECTION_STRING=\"HostName=<hub>.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<key>\"\n```\n\nThis package manages the ARM resource `Microsoft.Devices/provisioningServices`. It does not create the Azure subscription or resource group for you, and provisioning-service creation depends on at least one existing IoT Hub.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { IotDpsClient } from \"@azure/arm-deviceprovisioningservices\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst provisioningServiceName = process.env.DPS_NAME ?? \"example-dps\";\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const dpsClient = new IotDpsClient(credential, subscriptionId);\nexport { location, provisioningServiceName, resourceGroupName };\n```\n\nMost provisioning-service lifecycle work starts on `dpsClient.iotDpsResource`.\n\n## Core Usage\n\n### Check provisioning-service name availability\n\nProvisioning-service names must be available before you create the ARM resource.\n\n```js\nimport { dpsClient, provisioningServiceName } from \"./client.js\";\n\nconst availability = await dpsClient.iotDpsResource.checkProvisioningServiceNameAvailability({\n  name: provisioningServiceName,\n});\n\nif (!availability.nameAvailable) {\n  throw new Error(\n    availability.message ??\n      `${provisioningServiceName} is unavailable: ${availability.reason ?? \"unknown reason\"}`,\n  );\n}\n```\n\n### Create or update a provisioning service\n\nProvisioning-service creation is a long-running ARM operation. Use the `AndWait` helper when you need the final resource before moving on.\n\n```js\nimport {\n  dpsClient,\n  location,\n  provisioningServiceName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst iotHubConnectionString = process.env.IOTHUB_OWNER_CONNECTION_STRING;\n\nif (!iotHubConnectionString) {\n  throw new Error(\n    \"Set IOTHUB_OWNER_CONNECTION_STRING before creating a provisioning service.\",\n  );\n}\n\nconst service = await dpsClient.iotDpsResource.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  provisioningServiceName,\n  {\n    location,\n    sku: {\n      name: \"S1\",\n      capacity: 1,\n    },\n    tags: {\n      env: \"dev\",\n      owner: \"context-hub\",\n    },\n    properties: {\n      state: \"Active\",\n      allocationPolicy: \"Hashed\",\n      iotHubs: [\n        {\n          connectionString: iotHubConnectionString,\n          location,\n          allocationWeight: 100,\n          applyAllocationPolicy: true,\n        },\n      ],\n    },\n  },\n);\n\nconsole.log(service.id);\nconsole.log(service.name);\n```\n\nThe linked IoT Hub must already exist. This SDK manages the provisioning service resource; it does not provision the backing IoT Hub for you.\n\n### List provisioning services in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { dpsClient, resourceGroupName } from \"./client.js\";\n\nfor await (const service of dpsClient.iotDpsResource.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(service.name, service.location);\n}\n```\n\nIf you need a subscription-wide inventory, use `dpsClient.iotDpsResource.listBySubscription()` instead.\n\n### Get one provisioning service\n\nUse `get()` when you already know the resource group and provisioning-service name.\n\n```js\nimport {\n  dpsClient,\n  provisioningServiceName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst service = await dpsClient.iotDpsResource.get(\n  resourceGroupName,\n  provisioningServiceName,\n);\n\nconsole.log(service.id);\nconsole.log(service.location);\nconsole.log(service.tags);\n```\n\n### List shared access policies and keys\n\nThe management client can return the provisioning service's shared access policies. Use this only for administrative workflows that truly need shared keys.\n\n```js\nimport {\n  dpsClient,\n  provisioningServiceName,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst accessPolicies = await dpsClient.iotDpsResource.listKeys(\n  resourceGroupName,\n  provisioningServiceName,\n);\n\nconsole.dir(accessPolicies, { depth: null });\n```\n\nPrefer Microsoft Entra ID where possible for automation around Azure resources. Treat shared access keys as secrets and rotate them carefully.\n\n### Delete a provisioning service\n\nDelete is also a long-running ARM operation.\n\n```js\nimport {\n  dpsClient,\n  provisioningServiceName,\n  resourceGroupName,\n} from \"./client.js\";\n\nawait dpsClient.iotDpsResource.beginDeleteAndWait(\n  resourceGroupName,\n  provisioningServiceName,\n);\n```\n\n## Practical Notes\n\n- Use this package only for ARM resource management. Device enrollment groups, individual enrollments, and runtime registration flows belong to Device Provisioning Service data-plane APIs.\n- Treat `beginCreateOrUpdateAndWait(...)` and `beginDeleteAndWait(...)` as the normal pattern when the next step depends on the final ARM state.\n- Treat `listByResourceGroup(...)` and `listBySubscription()` results as async iterables, not plain arrays.\n- Provisioning-service creation depends on at least one linked IoT Hub. Keep the hub connection string out of source control and inject it through environment variables or secret storage.\n- Use `listKeys(...)` only when you explicitly need shared-access administration details. Avoid spreading those keys into application code when an Azure AD-based flow will work.\n"
  },
  {
    "path": "content/azure/docs/arm-keyvault/javascript/DOC.md",
    "content": "---\nname: arm-keyvault\ndescription: \"Azure Key Vault management client for JavaScript with practical guidance for provisioning vaults, checking name availability, and updating ARM control-plane settings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,key-vault,arm,management,vaults,javascript\"\n---\n\n# Azure Key Vault Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-keyvault` for Azure Resource Manager control-plane work on Key Vault resources: checking vault name availability, creating or updating vaults, listing vaults in a subscription or resource group, and changing ARM-managed settings such as tags or public network access.\n\nDo not use this package to create secrets, read secret values, create keys, or manage certificates inside a vault. Those are data-plane operations and belong to `@azure/keyvault-secrets`, `@azure/keyvault-keys`, and `@azure/keyvault-certificates`.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-keyvault@4.0.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs a `TokenCredential` and your Azure subscription ID. For local development, the simplest path is usually Azure CLI login:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport KEY_VAULT_NAME=\"example-kv-1234\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nSet `AZURE_TENANT_ID` even if authentication itself comes from Azure CLI or managed identity. Creating a vault needs the tenant ID in the request payload; it is not inferred from the client constructor.\n\nThis package manages Key Vault resources that already live inside Azure Resource Manager. Your Azure subscription and target resource group should already exist before you create a vault.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { KeyVaultManagementClient } from \"@azure/arm-keyvault\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst tenantId = process.env.AZURE_TENANT_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst vaultName = process.env.KEY_VAULT_NAME ?? \"example-kv-1234\";\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!tenantId) {\n  throw new Error(\"Set AZURE_TENANT_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const keyVaultClient = new KeyVaultManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport { location, resourceGroupName, tenantId, vaultName };\n```\n\nMost control-plane work starts on `keyVaultClient.vaults`.\n\n## Core Usage\n\n### Check name availability before create\n\nKey Vault names must be unique, so check availability before provisioning.\n\n```js\nimport { keyVaultClient, vaultName } from \"./client.js\";\n\nconst availability = await keyVaultClient.vaults.checkNameAvailability({\n  name: vaultName,\n  type: \"Microsoft.KeyVault/vaults\",\n});\n\nif (!availability.nameAvailable) {\n  throw new Error(\n    availability.message ?? `Key Vault name ${vaultName} is unavailable.`,\n  );\n}\n```\n\n### Create or update a vault\n\nProvisioning is a long-running ARM operation, so use `beginCreateOrUpdateAndWait(...)` when you need the final resource before moving on.\n\n```js\nimport {\n  keyVaultClient,\n  location,\n  resourceGroupName,\n  tenantId,\n  vaultName,\n} from \"./client.js\";\n\nconst vault = await keyVaultClient.vaults.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  vaultName,\n  {\n    location,\n    tags: {\n      env: \"dev\",\n      owner: \"context-hub\",\n    },\n    properties: {\n      tenantId,\n      sku: {\n        family: \"A\",\n        name: \"standard\",\n      },\n      accessPolicies: [],\n      enableRbacAuthorization: true,\n      enableSoftDelete: true,\n      softDeleteRetentionInDays: 90,\n      publicNetworkAccess: \"Enabled\",\n    },\n  },\n);\n\nconsole.log(vault.id);\nconsole.log(vault.properties?.vaultUri);\n```\n\nImportant details for create requests:\n\n- `tenantId` is required.\n- `accessPolicies` are required unless the create mode is recovery; when RBAC is enabled, an empty array is the usual shape.\n- `softDeleteRetentionInDays` must be between `7` and `90`.\n\n### Get one existing vault\n\nUse `get(...)` when you already know the resource group and vault name.\n\n```js\nimport { keyVaultClient, resourceGroupName, vaultName } from \"./client.js\";\n\nconst vault = await keyVaultClient.vaults.get(resourceGroupName, vaultName);\n\nconsole.log(vault.id);\nconsole.log(vault.properties?.vaultUri);\nconsole.log(vault.properties?.enableRbacAuthorization);\n```\n\n### List vaults in a resource group\n\nList results are paged async iterables, so iterate with `for await`.\n\n```js\nimport { keyVaultClient, resourceGroupName } from \"./client.js\";\n\nfor await (const vault of keyVaultClient.vaults.listByResourceGroup(resourceGroupName)) {\n  console.log(vault.name, vault.location, vault.properties?.vaultUri);\n}\n```\n\nIf you need a subscription-wide inventory, use `keyVaultClient.vaults.listBySubscription()` instead.\n\n### Update vault tags or network settings\n\nUse `update(...)` for partial changes instead of recreating the whole vault.\n\n```js\nimport { keyVaultClient, resourceGroupName, vaultName } from \"./client.js\";\n\nconst updated = await keyVaultClient.vaults.update(\n  resourceGroupName,\n  vaultName,\n  {\n    tags: {\n      env: \"prod\",\n      owner: \"platform\",\n    },\n    properties: {\n      publicNetworkAccess: \"Disabled\",\n    },\n  },\n);\n\nconsole.log(updated.tags);\nconsole.log(updated.properties?.publicNetworkAccess);\n```\n\n## Configuration Notes\n\n- Reuse one `KeyVaultManagementClient` instead of constructing a new client per operation.\n- `AZURE_SUBSCRIPTION_ID` is required separately from your credential configuration.\n- `AZURE_TENANT_ID` is part of the vault create payload, so set it explicitly even when `DefaultAzureCredential` can authenticate without it.\n- Treat `listByResourceGroup(...)` and `listBySubscription()` results as async iterables, not plain arrays.\n- Treat `beginCreateOrUpdateAndWait(...)` as the normal pattern when a later step depends on the created vault.\n- `enableRbacAuthorization` changes data-action authorization inside the vault, but Azure Resource Manager management operations still use ARM RBAC.\n- This package is control plane only; switch to the Key Vault data-plane SDKs after the vault exists.\n\n## Common Pitfalls\n\n- Using `@azure/arm-keyvault` for secrets, keys, or certificates instead of the `@azure/keyvault-*` data-plane packages.\n- Authenticating successfully but forgetting to set `AZURE_SUBSCRIPTION_ID` when constructing `KeyVaultManagementClient`.\n- Omitting `AZURE_TENANT_ID` or `properties.tenantId` when creating a vault.\n- Leaving out `accessPolicies` on create requests even though the service still expects the field outside recovery scenarios.\n- Assuming `enableRbacAuthorization: true` changes ARM control-plane authorization.\n- Treating paged list results as arrays instead of async iterables.\n- Reusing a deleted vault name too quickly without accounting for soft-delete and purge behavior.\n\n## Version Notes For 4.0.0\n\n- This guide targets `@azure/arm-keyvault` `4.0.0`.\n- The examples use `KeyVaultManagementClient` from `@azure/arm-keyvault` and `DefaultAzureCredential` from `@azure/identity`.\n- If you are adapting older Azure management samples, re-check the current `Vaults` reference for operation names and request property casing before copying them forward.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-keyvault/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-keyvault-readme?view=azure-node-latest`\n- `KeyVaultManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-keyvault/keyvaultmanagementclient?view=azure-node-latest`\n- `Vaults` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-keyvault/vaults?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-keyvault`\n"
  },
  {
    "path": "content/azure/docs/arm-maps/javascript/DOC.md",
    "content": "---\nname: arm-maps\ndescription: \"Azure Maps management client for JavaScript with practical guidance for provisioning Maps accounts, rotating keys, generating SAS tokens, and managing ARM resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,maps,management,sas,keys,javascript\"\n---\n\n# Azure Maps Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-maps` for Azure Resource Manager work on Azure Maps resources: creating and updating Maps accounts, listing or regenerating account keys, generating SAS tokens, and inspecting management-plane resources. Do not use it for search, routing, or rendering requests. Those data-plane calls belong in Azure Maps client packages instead.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-maps@3.1.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs Azure credentials and a subscription ID. For local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\n```\n\nFor CI or deployed applications, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nMost operations also need an existing Azure resource group. This package manages Azure Maps resources inside Azure Resource Manager; it does not create the subscription itself.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { MapsManagementClient } from \"@azure/arm-maps\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const mapsClient = new MapsManagementClient(credential, subscriptionId);\nexport { resourceGroupName };\n```\n\nThe main operation groups to expect are:\n\n- `mapsClient.accounts`\n- `mapsClient.creators`\n- `mapsClient.maps`\n\n## Core Usage\n\n### Create or update a Maps account\n\nCreating a Maps account is an ARM resource operation. Use the long-running helper when you need the final resource before moving on.\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst account = await mapsClient.accounts.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  \"example-maps-account\",\n  {\n    location: \"global\",\n    kind: \"Gen2\",\n    sku: { name: \"G2\" },\n    tags: {\n      env: \"dev\",\n      owner: \"context-hub\",\n    },\n  },\n);\n\nconsole.log(account.id);\nconsole.log(account.properties?.uniqueId);\n```\n\nFor partial updates, use `update(...)` with only the fields you want to change:\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst updated = await mapsClient.accounts.update(\n  resourceGroupName,\n  \"example-maps-account\",\n  {\n    tags: {\n      env: \"prod\",\n      owner: \"platform\",\n    },\n    publicNetworkAccess: \"Enabled\",\n  },\n);\n\nconsole.log(updated.tags);\n```\n\nImportant account settings in the current ARM schema include:\n\n- `disableLocalAuth`: disables shared-key and SAS authentication\n- `publicNetworkAccess`: enables or blocks public endpoint access\n- `cors`: configures CORS rules for the account\n- `linkedResources`: links supporting resources such as storage\n\nIf you plan to use account keys or SAS tokens, do not enable `disableLocalAuth`.\n\n### List accounts in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nfor await (const account of mapsClient.accounts.listByResourceGroup(resourceGroupName)) {\n  console.log(account.name, account.location, account.kind);\n}\n```\n\n### Get one account\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst account = await mapsClient.accounts.get(\n  resourceGroupName,\n  \"example-maps-account\",\n);\n\nconsole.log(account.id);\nconsole.log(account.location);\nconsole.log(account.properties?.uniqueId);\n```\n\n## Shared Keys And SAS Tokens\n\n### List account keys\n\nUse the management client to retrieve the shared keys that data-plane Azure Maps clients can use with `AzureKeyCredential`.\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst keys = await mapsClient.accounts.listKeys(\n  resourceGroupName,\n  \"example-maps-account\",\n);\n\nconsole.log(keys.primaryKey);\nconsole.log(keys.secondaryKey);\n```\n\n### Regenerate one key\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst newKeys = await mapsClient.accounts.regenerateKeys(\n  resourceGroupName,\n  \"example-maps-account\",\n  {\n    keyType: \"primary\",\n  },\n);\n\nconsole.log(newKeys.primaryKey);\n```\n\nUse a staged rotation flow in production:\n\n1. move clients to the secondary key\n2. regenerate the primary key\n3. move clients back if needed\n4. regenerate the secondary key\n\n### Generate a SAS token\n\nUse `listSas(...)` when you need a SAS token for Azure Maps clients that support `AzureSASCredential`.\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nconst principalId = process.env.AZURE_MAPS_UAMI_OBJECT_ID;\n\nif (!principalId) {\n  throw new Error(\"Set AZURE_MAPS_UAMI_OBJECT_ID before generating a SAS token.\");\n}\n\nconst start = new Date();\nconst expiry = new Date(start.getTime() + 60 * 60 * 1000);\n\nconst token = await mapsClient.accounts.listSas(\n  resourceGroupName,\n  \"example-maps-account\",\n  {\n    signingKey: \"primaryKey\",\n    principalId,\n    maxRatePerSecond: 500,\n    start: start.toISOString(),\n    expiry: expiry.toISOString(),\n    regions: [\"eastus\"],\n  },\n);\n\nconsole.log(token.accountSasToken);\n```\n\nBefore this works:\n\n- the Maps account must already have a user-assigned managed identity attached\n- the identity must be in the same region as the Maps account\n- local auth must still be enabled on the account\n\n## Delete An Account\n\nDeleting the ARM resource is also a long-running operation.\n\n```js\nimport { mapsClient, resourceGroupName } from \"./client.js\";\n\nawait mapsClient.accounts.beginDeleteAndWait(\n  resourceGroupName,\n  \"example-maps-account\",\n);\n```\n\n## Creator Resources\n\nThe package still exposes Creator operations, and the Azure resource model still documents `Microsoft.Maps/accounts/creators`. Treat this as a compatibility surface, not a default new build target: Microsoft announced Azure Maps Creator retirement effective September 30, 2025.\n\nIf you inherit code that already uses Creator resources, verify service availability and retirement impact before writing new automation around `mapsClient.creators`.\n\n## Configuration Notes\n\n- Reuse one `MapsManagementClient` instead of creating a new client for every call.\n- Keep `AZURE_SUBSCRIPTION_ID` in application configuration; credentials do not replace it.\n- Treat list results as async iterables, not arrays.\n- Use `beginCreateOrUpdateAndWait` and `beginDeleteAndWait` when you need ARM changes to finish before the next step.\n- Leave local auth enabled if your applications still depend on shared keys or SAS tokens.\n- Use `location: \"global\"`, `kind: \"Gen2\"`, and `sku.name: \"G2\"` for current Gen2 account provisioning.\n\n## Common Pitfalls\n\n- Using `@azure/arm-maps` for search, routing, or rendering calls instead of a data-plane Azure Maps package.\n- Forgetting to install and configure `@azure/identity` alongside `@azure/arm-maps`.\n- Passing credentials correctly but omitting the subscription ID when constructing `MapsManagementClient`.\n- Expecting `listByResourceGroup(...)` to return a plain array instead of a paged async iterator.\n- Disabling local auth and then expecting `listKeys(...)` or SAS-based application auth to keep working.\n- Treating SAS generation as self-contained when the account identity prerequisites are not already configured.\n- Building new Creator automation without checking the post-September 30, 2025 retirement status first.\n\n## Version Notes For 3.1.0\n\n- This guide targets `@azure/arm-maps` `3.1.0`.\n- The examples use `MapsManagementClient` from `@azure/arm-maps` and `DefaultAzureCredential` from `@azure/identity`.\n- Azure Maps account management and Azure Maps data-plane usage are separate concerns; keep `@azure/arm-maps` for ARM provisioning and account auth flows.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-maps/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-maps-readme?view=azure-node-latest`\n- `MapsManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-maps/mapsmanagementclient?view=azure-node-latest`\n- `Accounts` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-maps/accounts?view=azure-node-latest`\n- `Creators` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-maps/creators?view=azure-node-latest`\n- Azure Maps authentication overview: `https://learn.microsoft.com/en-us/azure/azure-maps/azure-maps-authentication`\n- Manage Azure Maps authentication: `https://learn.microsoft.com/en-us/azure/azure-maps/how-to-manage-authentication`\n- ARM template reference for Maps accounts: `https://learn.microsoft.com/en-us/azure/templates/microsoft.maps/accounts`\n- ARM template reference for Maps creators: `https://learn.microsoft.com/en-us/azure/templates/microsoft.maps/accounts/creators`\n- Azure Maps Creator retirement notice: `https://azure.microsoft.com/en-us/updates?id=azure-maps-creator-services-retirement-on-30-september-2025`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-maps`\n"
  },
  {
    "path": "content/azure/docs/arm-monitor/javascript/DOC.md",
    "content": "---\nname: arm-monitor\ndescription: \"Azure Monitor management client for JavaScript for activity logs, metric alerts, action groups, data collection rules, and diagnostic settings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-monitor,monitor,management,arm,alerts,diagnostic-settings,javascript\"\n---\n\n# Azure Monitor Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-monitor` for Azure Monitor control-plane work: managing monitor resources such as activity log alerts, action groups, metric alerts, scheduled query rules, data collection rules, and diagnostic settings through Azure Resource Manager.\n\nDo not use this package to query logs or metrics at runtime from application code. For that, use `@azure/monitor-query` instead.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-monitor@7.0.0 @azure/identity\n```\n\nThis package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe normal setup is `DefaultAzureCredential` plus an explicit Azure subscription ID.\n\nFor local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport DATA_COLLECTION_RULE_NAME=\"example-dcr\"\nexport METRIC_ALERT_NAME=\"vm-cpu-high\"\nexport MONITORED_RESOURCE_ID=\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/example-vm\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service-principal environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nManagement operations also require Azure RBAC permissions on the subscription, resource group, or target resource. Successful authentication alone is not enough.\n\n## Client Initialization\n\nCreate one shared client and reuse it across related monitor-management operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { MonitorManagementClient } from \"@azure/arm-monitor\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst dataCollectionRuleName =\n  process.env.DATA_COLLECTION_RULE_NAME ?? \"example-dcr\";\nconst metricAlertName = process.env.METRIC_ALERT_NAME ?? \"vm-cpu-high\";\nconst monitoredResourceId = process.env.MONITORED_RESOURCE_ID;\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const monitorClient = new MonitorManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport {\n  dataCollectionRuleName,\n  metricAlertName,\n  monitoredResourceId,\n  resourceGroupName,\n};\n```\n\nCommon entry points on the client include `monitorClient.activityLogs`, `monitorClient.actionGroups`, `monitorClient.metricAlerts`, `monitorClient.scheduledQueryRules`, `monitorClient.diagnosticSettings`, and `monitorClient.dataCollectionRules`.\n\n## Core Usage\n\n### Read recent activity log events\n\n`activityLogs.list(...)` requires an OData filter string. Build the filter explicitly instead of guessing parameter names.\n\n```js\nimport { monitorClient, resourceGroupName } from \"./client.js\";\n\nconst endTime = new Date();\nconst startTime = new Date(endTime.getTime() - 60 * 60 * 1000);\n\nconst filter = [\n  `eventTimestamp ge '${startTime.toISOString()}'`,\n  `eventTimestamp le '${endTime.toISOString()}'`,\n  `resourceGroupName eq '${resourceGroupName}'`,\n].join(\" and \");\n\nfor await (const event of monitorClient.activityLogs.list(filter)) {\n  console.log(event.eventName?.localizedValue);\n  console.log(event.resourceGroupName);\n  console.log(event.status?.localizedValue);\n}\n```\n\nCommon filter terms include `resourceProvider eq 'Microsoft.Compute'` and `status eq 'Failed'`.\n\n### List data collection rules in a resource group\n\nUse data collection rules when you need to inspect or manage Azure Monitor Agent and ingestion configuration.\n\n```js\nimport { monitorClient, resourceGroupName } from \"./client.js\";\n\nfor await (const rule of monitorClient.dataCollectionRules.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(rule.name, rule.location, rule.id);\n}\n```\n\nTo inspect one rule directly:\n\n```js\nimport {\n  dataCollectionRuleName,\n  monitorClient,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst rule = await monitorClient.dataCollectionRules.get(\n  resourceGroupName,\n  dataCollectionRuleName,\n);\n\nconsole.log(rule.id);\nconsole.log(rule.location);\nconsole.log(rule.immutableId);\n```\n\n### Get or list metric alerts\n\nMetric alerts are a common Azure Monitor management task. Start with `get(...)` or `listByResourceGroup(...)` when you need to inspect an existing rule before changing it.\n\n```js\nimport {\n  metricAlertName,\n  monitorClient,\n  resourceGroupName,\n} from \"./client.js\";\n\nconst alert = await monitorClient.metricAlerts.get(\n  resourceGroupName,\n  metricAlertName,\n);\n\nconsole.log(alert.name);\nconsole.log(alert.enabled);\nconsole.log(alert.scopes);\n```\n\nList metric alerts in the same resource group:\n\n```js\nimport { monitorClient, resourceGroupName } from \"./client.js\";\n\nfor await (const alert of monitorClient.metricAlerts.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(alert.name, alert.severity, alert.enabled);\n}\n```\n\nWhen you create or update a metric alert, the request body uses full ARM resource IDs in fields such as `scopes` and action-group references.\n\n### List scheduled query rules in a resource group\n\nScheduled query rules back many log-search alerting workflows. If the task is instead “run a KQL query and return rows now,” use `@azure/monitor-query`, not this package.\n\n```js\nimport { monitorClient, resourceGroupName } from \"./client.js\";\n\nfor await (const rule of monitorClient.scheduledQueryRules.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(rule.name, rule.enabled, rule.scopes);\n}\n```\n\n### List diagnostic settings for a resource\n\nDiagnostic settings attach log and metric export configuration to an existing resource ID.\n\n```js\nimport { monitorClient, monitoredResourceId } from \"./client.js\";\n\nif (!monitoredResourceId) {\n  throw new Error(\"Set MONITORED_RESOURCE_ID to a full ARM resource ID.\");\n}\n\nconst settings = await monitorClient.diagnosticSettings.list(monitoredResourceId);\n\nfor (const item of settings.value ?? []) {\n  console.log(item.name);\n}\n```\n\nThis surface is typically used to route platform logs and metrics to destinations such as Log Analytics workspaces, storage accounts, or Event Hubs.\n\n### List action groups in a resource group\n\nAction groups are reusable notification and automation targets for alert rules.\n\n```js\nimport { monitorClient, resourceGroupName } from \"./client.js\";\n\nfor await (const group of monitorClient.actionGroups.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(group.name, group.groupShortName);\n}\n```\n\n## Configuration Notes\n\n- Reuse one `MonitorManagementClient` instead of creating a new client per call.\n- `AZURE_SUBSCRIPTION_ID` is required separately from your credential configuration.\n- Treat list results as async iterables, not plain arrays.\n- `activityLogs.list(...)` requires an explicit OData filter string.\n- Most monitor-resource relationships use full ARM resource IDs rather than short names.\n- Use `@azure/arm-monitor` for control-plane configuration and `@azure/monitor-query` for runtime log or metric queries.\n- When the generated client exposes `begin...` helpers for a write operation, prefer `begin...AndWait(...)` if the next step depends on completion.\n\n## Common Pitfalls\n\n- Installing `@azure/arm-monitor` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Authenticating successfully but forgetting to pass `AZURE_SUBSCRIPTION_ID` into `MonitorManagementClient`.\n- Treating `activityLogs.list(...)` like a simple unfiltered list call.\n- Passing a resource name where the API expects a full ARM resource ID.\n- Using this management package when the task is actually querying telemetry data at runtime.\n- Treating paged `list...()` results as materialized arrays.\n- Copying older Azure Monitor examples without re-checking operation names and model shapes for `7.0.0`.\n\n## Version Notes For `7.0.0`\n\n- This guide targets `@azure/arm-monitor` `7.0.0`.\n- The examples use `MonitorManagementClient` from `@azure/arm-monitor` and `DefaultAzureCredential` from `@azure/identity`.\n- Re-check the current Learn reference before copying older samples for model-heavy write operations such as alert creation.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-monitor-readme?view=azure-node-latest`\n- `MonitorManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/monitormanagementclient?view=azure-node-latest`\n- `ActivityLogs` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/activitylogs?view=azure-node-latest`\n- `DataCollectionRules` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/datacollectionrules?view=azure-node-latest`\n- `MetricAlerts` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/metricalerts?view=azure-node-latest`\n- `ScheduledQueryRules` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/scheduledqueryrules?view=azure-node-latest`\n- `DiagnosticSettings` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/diagnosticsettings?view=azure-node-latest`\n- `ActionGroups` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-monitor/actiongroups?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-monitor`\n"
  },
  {
    "path": "content/azure/docs/arm-network/javascript/DOC.md",
    "content": "---\nname: arm-network\ndescription: \"Azure Network resource management client for JavaScript with practical guidance for authentication, virtual networks, subnets, and public IPs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"36.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,network,virtual-network,subnet,public-ip,javascript\"\n---\n\n# Azure Network Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-network` to manage Azure networking resources through Azure Resource Manager. Authenticate with a `TokenCredential`, construct one shared `NetworkManagementClient` with your subscription ID, and treat create, update, and delete calls as long-running operations that usually use `begin...AndWait` helpers.\n\nThis is a control-plane SDK for Azure resources such as virtual networks, subnets, public IP addresses, network security groups, load balancers, and related networking objects. It is not a packet-processing or socket library.\n\n## Install\n\nInstall the management client and Azure Identity together:\n\n```bash\nnpm install @azure/arm-network@36.0.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs Azure credentials and a subscription ID. For local development, `DefaultAzureCredential` can use your Azure CLI login. For CI or deployed apps, it can use service principal environment variables.\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\nexport RESOURCE_GROUP_NAME=\"<resource-group>\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nIf you use service principal credentials instead of Azure CLI login, set the standard Azure Identity variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nMost `@azure/arm-network` operations also need names for existing Azure resources such as a resource group, virtual network, or subnet. This package manages network resources inside Azure Resource Manager; it does not create the Azure subscription itself, and your resource group should already exist.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { NetworkManagementClient } from \"@azure/arm-network\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\nexport const networkClient = new NetworkManagementClient(credential, subscriptionId);\nexport { resourceGroupName, location };\n```\n\n## Core Usage\n\n### Get one virtual network\n\nUse `get` when you already know the resource group and virtual network name.\n\n```js\nimport { networkClient, resourceGroupName } from \"./client.js\";\n\nconst virtualNetwork = await networkClient.virtualNetworks.get(\n  resourceGroupName,\n  \"app-vnet\",\n);\n\nconsole.log(virtualNetwork.id);\nconsole.log(virtualNetwork.addressSpace?.addressPrefixes);\n```\n\n### List virtual networks in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { networkClient, resourceGroupName } from \"./client.js\";\n\nfor await (const virtualNetwork of networkClient.virtualNetworks.list(resourceGroupName)) {\n  console.log(virtualNetwork.name, virtualNetwork.location);\n}\n```\n\n### Create or update a virtual network\n\nCreating and updating Azure resources is usually a long-running ARM operation. Use the `AndWait` helper when you want the final resource before moving on.\n\n```js\nimport { networkClient, resourceGroupName, location } from \"./client.js\";\n\nconst virtualNetwork = await networkClient.virtualNetworks.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  \"app-vnet\",\n  {\n    location,\n    addressSpace: {\n      addressPrefixes: [\"10.20.0.0/16\"],\n    },\n  },\n);\n\nconsole.log(virtualNetwork.id);\n```\n\n### Create or update a subnet\n\nSubnets are child resources under a virtual network, so create the virtual network first.\n\n```js\nimport { networkClient, resourceGroupName } from \"./client.js\";\n\nconst subnet = await networkClient.subnets.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  \"app-vnet\",\n  \"app-subnet\",\n  {\n    addressPrefix: \"10.20.1.0/24\",\n  },\n);\n\nconsole.log(subnet.id);\n```\n\nTo retrieve a subnet later:\n\n```js\nconst subnet = await networkClient.subnets.get(\n  resourceGroupName,\n  \"app-vnet\",\n  \"app-subnet\",\n);\n\nconsole.log(subnet.name);\n```\n\n### Create a public IP address\n\nPublic IP creation is also a long-running operation.\n\n```js\nimport { networkClient, resourceGroupName, location } from \"./client.js\";\n\nconst publicIp = await networkClient.publicIPAddresses.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  \"app-public-ip\",\n  {\n    location,\n    publicIPAllocationMethod: \"Static\",\n    sku: {\n      name: \"Standard\",\n    },\n  },\n);\n\nconsole.log(publicIp.id);\nconsole.log(publicIp.ipAddress);\n```\n\n### Delete a network resource\n\nDelete operations are long-running too.\n\n```js\nimport { networkClient, resourceGroupName } from \"./client.js\";\n\nawait networkClient.publicIPAddresses.beginDeleteAndWait(\n  resourceGroupName,\n  \"app-public-ip\",\n);\n```\n\n## Configuration Notes\n\n- Reuse one `NetworkManagementClient` instead of creating a new client for every call.\n- Keep `AZURE_SUBSCRIPTION_ID` in app configuration; it is required separately from your Azure credential.\n- Use `DefaultAzureCredential` for both local development and deployed workloads so your auth path stays consistent.\n- Treat list results as async iterables, not arrays.\n- Use `beginCreateOrUpdateAndWait` and `beginDeleteAndWait` when you need the operation to finish before the next step.\n- Create parent resources before child resources, such as a virtual network before a subnet.\n\n## Common Pitfalls\n\n- Forgetting to install and configure `@azure/identity` alongside `@azure/arm-network`.\n- Passing credentials correctly but omitting the subscription ID when constructing `NetworkManagementClient`.\n- Expecting `list(...)` to return a plain array instead of a paged async iterator.\n- Calling `beginCreateOrUpdate(...)` without polling the long-running operation to completion.\n- Trying to create a subnet before its virtual network exists.\n- Mixing up control-plane resource management with data-plane traffic handling.\n\n## Version Notes For 36.0.0\n\n- This guide targets `@azure/arm-network` `36.0.0`.\n- The examples use `NetworkManagementClient` from `@azure/arm-network` and `DefaultAzureCredential` from `@azure/identity`.\n- If you find older Azure management examples that manually call `beginCreateOrUpdate(...)` and then poll, the `...AndWait` helpers are the simpler current pattern when available.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-network/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-network-readme?view=azure-node-latest`\n- `NetworkManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-network/networkmanagementclient?view=azure-node-latest`\n- `VirtualNetworks` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-network/virtualnetworks?view=azure-node-latest`\n- `Subnets` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-network/subnets?view=azure-node-latest`\n- `PublicIPAddresses` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-network/publicipaddresses?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-network`\n"
  },
  {
    "path": "content/azure/docs/arm-resources/javascript/DOC.md",
    "content": "---\nname: arm-resources\ndescription: \"Azure Resource Manager client for JavaScript for resource groups, generic ARM resources, provider metadata, and tags\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,resource-manager,resource-groups,tags,javascript\"\n---\n\n# Azure Resource Manager Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-resources` for Azure Resource Manager control-plane work such as resource groups, generic ARM resources, provider metadata, and tags. Authenticate with a `TokenCredential` such as `DefaultAzureCredential`, pass your subscription ID explicitly to `ResourceManagementClient`, and use a service-specific management SDK when you need typed operations for a particular Azure service.\n\nThis package manages Azure resources through ARM. It is not a data-plane SDK for using the resource itself after it exists.\n\n## Install\n\nInstall the management client and Azure Identity together:\n\n```bash\nnpm install @azure/arm-resources@7.0.0 @azure/identity\n```\n\n## Authentication And Setup\n\nFor local development, sign in with the Azure CLI and export the subscription you want to manage:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"$(az account show --query id -o tsv)\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nFor CI, automation, or other non-interactive environments, `DefaultAzureCredential` can use the standard service principal variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\n## Client Initialization\n\nCreate one shared client and reuse it.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ResourceManagementClient } from \"@azure/arm-resources\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const resourceClient = new ResourceManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport { resourceGroupName, location };\n```\n\n## Core Usage\n\n### Create or update a resource group\n\n`resourceGroups.createOrUpdate(...)` is the normal entry point for making sure a resource group exists.\n\n```js\nimport { resourceClient, resourceGroupName, location } from \"./client.js\";\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst resourceGroup = await resourceClient.resourceGroups.createOrUpdate(\n  resourceGroupName,\n  {\n    location,\n    tags: {\n      env: \"dev\",\n      owner: \"context-hub\",\n    },\n  },\n);\n\nconsole.log(resourceGroup.id);\nconsole.log(resourceGroup.location);\n```\n\n### Get one resource group\n\n```js\nimport { resourceClient, resourceGroupName } from \"./client.js\";\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst resourceGroup = await resourceClient.resourceGroups.get(resourceGroupName);\n\nconsole.log(resourceGroup.name);\nconsole.log(resourceGroup.id);\n```\n\n### List resource groups in the subscription\n\nList operations are paged async iterables.\n\n```js\nimport { resourceClient } from \"./client.js\";\n\nfor await (const group of resourceClient.resourceGroups.list()) {\n  console.log(group.name, group.location);\n}\n```\n\n### Discover a provider API version before generic resource calls\n\nGeneric ARM resource operations such as `resources.getById(...)` need an explicit provider API version. Read provider metadata first instead of guessing.\n\n```js\nimport { resourceClient } from \"./client.js\";\n\nconst provider = await resourceClient.providers.get(\"Microsoft.Storage\");\n\nconst storageAccountType = provider.resourceTypes?.find(\n  (item) => item.resourceType === \"storageAccounts\",\n);\n\nconst apiVersion = storageAccountType?.apiVersions?.[0];\n\nif (!apiVersion) {\n  throw new Error(\"Could not determine an API version for Microsoft.Storage/storageAccounts.\");\n}\n\nconsole.log(apiVersion);\n```\n\n### Read a generic ARM resource by resource ID\n\nUse the generic `resources` operations when you already have a full ARM ID and an API version.\n\n```js\nimport { resourceClient } from \"./client.js\";\n\nconst resourceId = [\n  \"/subscriptions\",\n  process.env.AZURE_SUBSCRIPTION_ID,\n  \"resourceGroups\",\n  \"example-rg\",\n  \"providers\",\n  \"Microsoft.Storage\",\n  \"storageAccounts\",\n  \"examplestorageacct\",\n].join(\"/\");\n\nconst resource = await resourceClient.resources.getById(resourceId, \"2023-05-01\");\n\nconsole.log(resource.id);\nconsole.log(resource.type);\nconsole.log(resource.location);\n```\n\nPrefer a typed client such as `@azure/arm-storage` when you need service-specific request bodies or strongly typed resource models.\n\n### Delete a resource group\n\nDelete is a long-running ARM operation, so use the `AndWait` helper when you want completion before the next step.\n\n```js\nimport { resourceClient, resourceGroupName } from \"./client.js\";\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nawait resourceClient.resourceGroups.beginDeleteAndWait(resourceGroupName);\n```\n\n## Configuration Notes\n\n- `AZURE_SUBSCRIPTION_ID` is required when constructing `ResourceManagementClient`; the credential does not supply it.\n- `DefaultAzureCredential` is the usual default for local development, CI, managed identity, and workload identity.\n- Treat `list()` results as async iterables, not plain arrays.\n- Generic `resources.*` calls require a provider API version; check provider metadata first instead of hardcoding blindly.\n- ARM authentication success does not imply RBAC authorization for the target subscription or resource group.\n- Use this package for control-plane operations; switch to a service-specific management or data-plane SDK when you need richer resource-specific functionality.\n\n## Common Pitfalls\n\n- Installing `@azure/arm-resources` without also installing `@azure/identity`.\n- Omitting `AZURE_SUBSCRIPTION_ID` when creating the client.\n- Treating paged `list()` results as materialized arrays.\n- Using `resources.getById(...)` without a valid provider API version.\n- Copying an ARM resource ID incorrectly and then debugging the wrong problem.\n- Using the generic ARM client where a typed service SDK would be clearer and safer.\n\n## Version Notes For 7.0.0\n\n- This guide targets `@azure/arm-resources` `7.0.0`.\n- The examples use `ResourceManagementClient` from `@azure/arm-resources` and `DefaultAzureCredential` from `@azure/identity`.\n- For generic ARM resource operations in this package, keep the provider API version explicit per call.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-resources/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-resources-readme?view=azure-node-latest`\n- `ResourceManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-resources/resourcemanagementclient?view=azure-node-latest`\n- `ResourceGroups` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-resources/resourcegroups?view=azure-node-latest`\n- `Resources` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-resources/resources?view=azure-node-latest`\n- `Providers` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-resources/providers?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-resources`\n"
  },
  {
    "path": "content/azure/docs/arm-sql/javascript/DOC.md",
    "content": "---\nname: arm-sql\ndescription: \"Azure SQL management client for JavaScript with practical guidance for authentication, logical servers, databases, and firewall rules\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,sql,azure-sql,management,database,javascript\"\n---\n\n# Azure SQL Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-sql` for Azure Resource Manager control-plane work: creating and managing logical servers, databases, firewall rules, and related Azure SQL resources. Do not use it to open SQL connections or execute queries against a database. For application data access, use a SQL Server driver or ORM separately.\n\nThe normal management flow is:\n\n1. Authenticate with `@azure/identity`\n2. Construct one shared `SqlManagementClient`\n3. Call an operation group such as `servers`, `databases`, or `firewallRules`\n4. Wait for long-running ARM operations with `begin...AndWait` helpers\n\n## Install\n\nInstall the management client and Azure Identity together:\n\n```bash\nnpm install @azure/arm-sql@10.0.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\n`SqlManagementClient` needs a credential and a subscription ID. For local development, Azure CLI login is usually the quickest path:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"rg-app-prod\"\nexport AZURE_LOCATION=\"eastus\"\n```\n\nFor CI or deployed applications, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nWhen you create a logical server, you also need administrator credentials for that Azure SQL server resource:\n\n```bash\nexport AZURE_SQL_SERVER_NAME=\"example-sql-server\"\nexport AZURE_SQL_ADMIN_LOGIN=\"sqladminuser\"\nexport AZURE_SQL_ADMIN_PASSWORD=\"<strong-password>\"\n```\n\nThis package manages Azure SQL resources inside Azure Resource Manager. Your subscription and resource group should already exist, and the identity you use needs ARM permission on the target scope.\n\n## Client Initialization\n\nCreate one shared client and reuse it across related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { SqlManagementClient } from \"@azure/arm-sql\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst location = process.env.AZURE_LOCATION ?? \"eastus\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const sqlClient = new SqlManagementClient(credential, subscriptionId);\nexport { resourceGroupName, location };\n```\n\nThe main operation groups to expect are:\n\n- `sqlClient.servers`\n- `sqlClient.databases`\n- `sqlClient.firewallRules`\n\n## Core Usage\n\n### List logical servers in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { sqlClient, resourceGroupName } from \"./client.js\";\n\nfor await (const server of sqlClient.servers.listByResourceGroup(resourceGroupName)) {\n  console.log(server.name, server.location, server.fullyQualifiedDomainName);\n}\n```\n\n### Create or update a logical server\n\nServer provisioning is a long-running ARM operation. Use `beginCreateOrUpdateAndWait(...)` when you need the final resource before moving on.\n\n```js\nimport { sqlClient, resourceGroupName, location } from \"./client.js\";\n\nconst serverName = process.env.AZURE_SQL_SERVER_NAME;\nconst administratorLogin = process.env.AZURE_SQL_ADMIN_LOGIN;\nconst administratorLoginPassword = process.env.AZURE_SQL_ADMIN_PASSWORD;\n\nif (!serverName || !administratorLogin || !administratorLoginPassword) {\n  throw new Error(\n    \"Set AZURE_SQL_SERVER_NAME, AZURE_SQL_ADMIN_LOGIN, and AZURE_SQL_ADMIN_PASSWORD.\",\n  );\n}\n\nconst server = await sqlClient.servers.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  serverName,\n  {\n    location,\n    administratorLogin,\n    administratorLoginPassword,\n    version: \"12.0\",\n    minimalTlsVersion: \"1.2\",\n    publicNetworkAccess: \"Enabled\",\n  },\n);\n\nconsole.log(server.name);\nconsole.log(server.fullyQualifiedDomainName);\n```\n\nFor read-only inspection of one existing server, use `get(...)`:\n\n```js\nconst server = await sqlClient.servers.get(resourceGroupName, \"example-sql-server\");\n\nconsole.log(server.id);\nconsole.log(server.fullyQualifiedDomainName);\n```\n\n### Create or update a database\n\nDatabase create and update operations are also long-running.\n\n```js\nimport { sqlClient, resourceGroupName, location } from \"./client.js\";\n\nconst serverName = process.env.AZURE_SQL_SERVER_NAME ?? \"example-sql-server\";\n\nconst database = await sqlClient.databases.beginCreateOrUpdateAndWait(\n  resourceGroupName,\n  serverName,\n  \"appdb\",\n  {\n    location,\n    sku: {\n      name: \"Basic\",\n      tier: \"Basic\",\n    },\n  },\n);\n\nconsole.log(database.name);\nconsole.log(database.status);\n```\n\nUse `get(...)` when you already know the database name:\n\n```js\nconst database = await sqlClient.databases.get(\n  resourceGroupName,\n  \"example-sql-server\",\n  \"appdb\",\n);\n\nconsole.log(database.id);\nconsole.log(database.status);\n```\n\n### List databases on a server\n\n```js\nimport { sqlClient, resourceGroupName } from \"./client.js\";\n\nconst serverName = process.env.AZURE_SQL_SERVER_NAME ?? \"example-sql-server\";\n\nfor await (const database of sqlClient.databases.listByServer(\n  resourceGroupName,\n  serverName,\n)) {\n  console.log(database.name, database.status);\n}\n```\n\n### Create or update a firewall rule\n\nFirewall rules are managed through `sqlClient.firewallRules`. This operation returns the resource directly instead of using a long-running poller.\n\n```js\nimport { sqlClient, resourceGroupName } from \"./client.js\";\n\nconst serverName = process.env.AZURE_SQL_SERVER_NAME ?? \"example-sql-server\";\n\nconst rule = await sqlClient.firewallRules.createOrUpdate(\n  resourceGroupName,\n  serverName,\n  \"office-ip\",\n  {\n    startIpAddress: \"203.0.113.10\",\n    endIpAddress: \"203.0.113.10\",\n  },\n);\n\nconsole.log(rule.name);\nconsole.log(rule.startIpAddress, rule.endIpAddress);\n```\n\nTo inspect existing rules:\n\n```js\nfor await (const rule of sqlClient.firewallRules.listByServer(\n  resourceGroupName,\n  \"example-sql-server\",\n)) {\n  console.log(rule.name, rule.startIpAddress, rule.endIpAddress);\n}\n```\n\n## Configuration Notes\n\n- Keep `AZURE_SUBSCRIPTION_ID` explicit instead of assuming the currently selected Azure CLI subscription is always correct.\n- `SqlManagementClient` targets Azure Resource Manager, not the SQL data endpoint.\n- Most create and update operations need a resource payload with the expected ARM fields. Check the current model reference before adding optional properties that are not in your working example.\n- The package exposes many operation groups beyond the common ones above, including elastic pools, failover groups, long-term retention policies, managed instances, and sync resources.\n\n## Common Pitfalls\n\n- Treating `@azure/arm-sql` as a query client. This SDK provisions and configures Azure SQL resources; it does not run SQL statements.\n- Installing `@azure/arm-sql` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Forgetting to await `beginCreateOrUpdateAndWait(...)` for server or database provisioning.\n- Passing a server DNS name like `example.database.windows.net` where ARM operations expect the logical server resource name such as `example`.\n- Assuming list operations return plain arrays instead of paged async iterables.\n- Treating an authentication success from `az login` as proof of write access. ARM RBAC on the subscription or resource group still controls whether create and update calls succeed.\n- Using the special firewall rule address `0.0.0.0` without understanding that Azure SQL treats it as the \"allow Azure services\" behavior.\n\n## Version Notes For `10.0.0`\n\n- This guide targets `@azure/arm-sql` `10.0.0`.\n- Prefer the current `@azure/identity` credential flow and promise-based client methods when adapting older Azure SQL management samples.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-sql/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-sql-readme?view=azure-node-latest`\n- `SqlManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-sql/sqlmanagementclient?view=azure-node-latest`\n- `servers` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-sql/servers?view=azure-node-latest`\n- `databases` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-sql/databases?view=azure-node-latest`\n- `firewallRules` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-sql/firewallrules?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-sql`\n"
  },
  {
    "path": "content/azure/docs/arm-storage/javascript/DOC.md",
    "content": "---\nname: arm-storage\ndescription: \"Azure Storage management client for JavaScript for provisioning storage accounts, updating account settings, and handling ARM control-plane operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,storage,arm,management,storage-accounts,javascript\"\n---\n\n# Azure Storage Management Client For JavaScript\n\n## Golden Rule\n\nUse `@azure/arm-storage` for Azure Resource Manager control-plane work on storage resources: checking storage account name availability, creating or deleting storage accounts, reading account properties, updating account settings, and listing or regenerating account keys.\n\nDo not use this package to upload blobs, read files, send queue messages, or access table data. Those are data-plane operations and belong in packages such as `@azure/storage-blob`, `@azure/storage-file-share`, and `@azure/storage-queue`.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\nnpm install @azure/arm-storage@19.1.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe client needs a `TokenCredential` and an Azure subscription ID. For local development, the quickest path is usually Azure CLI login:\n\n```bash\naz login\n\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport RESOURCE_GROUP_NAME=\"example-rg\"\nexport STORAGE_ACCOUNT_NAME=\"ctxhubstorageacct01\"\nexport AZURE_LOCATION=\"westus2\"\n```\n\nFor CI or deployed workloads, `DefaultAzureCredential` can also use service principal credentials:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nThis package manages storage resources that already live inside Azure Resource Manager. Your subscription and target resource group should already exist before you create a storage account.\n\n## Client Initialization\n\nCreate one shared client and reuse it for related operations.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { StorageManagementClient } from \"@azure/arm-storage\";\n\nconst subscriptionId = process.env.AZURE_SUBSCRIPTION_ID;\nconst resourceGroupName = process.env.RESOURCE_GROUP_NAME;\nconst accountName = process.env.STORAGE_ACCOUNT_NAME ?? \"ctxhubstorageacct01\";\nconst location = process.env.AZURE_LOCATION ?? \"westus2\";\n\nif (!subscriptionId) {\n  throw new Error(\"Set AZURE_SUBSCRIPTION_ID before running this script.\");\n}\n\nif (!resourceGroupName) {\n  throw new Error(\"Set RESOURCE_GROUP_NAME before running this script.\");\n}\n\nconst credential = new DefaultAzureCredential();\n\nexport const storageClient = new StorageManagementClient(\n  credential,\n  subscriptionId,\n);\n\nexport { accountName, location, resourceGroupName };\n```\n\nMost day-to-day control-plane work starts on `storageClient.storageAccounts`.\n\n## Core Usage\n\n### Check name availability before create\n\nStorage account names are globally unique, so check availability before you provision one.\n\n```js\nimport { storageClient, accountName } from \"./client.js\";\n\nconst availability = await storageClient.storageAccounts.checkNameAvailability({\n  name: accountName,\n});\n\nif (!availability.nameAvailable) {\n  throw new Error(\n    availability.message ?? `Storage account name ${accountName} is unavailable.`,\n  );\n}\n```\n\n### Create a storage account\n\nProvisioning is a long-running ARM operation, so use the `AndWait` helper when you need the final resource before moving on.\n\n```js\nimport {\n  accountName,\n  location,\n  resourceGroupName,\n  storageClient,\n} from \"./client.js\";\n\nconst account = await storageClient.storageAccounts.beginCreateAndWait(\n  resourceGroupName,\n  accountName,\n  {\n    location,\n    kind: \"StorageV2\",\n    sku: {\n      name: \"Standard_LRS\",\n    },\n    tags: {\n      env: \"dev\",\n      owner: \"context-hub\",\n    },\n    enableHttpsTrafficOnly: true,\n    minimumTlsVersion: \"TLS1_2\",\n    allowBlobPublicAccess: false,\n  },\n);\n\nconsole.log(account.id);\nconsole.log(account.primaryEndpoints?.blob);\n```\n\n### List accounts in a resource group\n\nList operations are paged async iterables, so iterate with `for await`.\n\n```js\nimport { resourceGroupName, storageClient } from \"./client.js\";\n\nfor await (const account of storageClient.storageAccounts.listByResourceGroup(\n  resourceGroupName,\n)) {\n  console.log(account.name, account.location, account.kind);\n}\n```\n\n### Get one account's properties\n\nUse `getProperties` when you already know the storage account name.\n\n```js\nimport { accountName, resourceGroupName, storageClient } from \"./client.js\";\n\nconst account = await storageClient.storageAccounts.getProperties(\n  resourceGroupName,\n  accountName,\n);\n\nconsole.log(account.id);\nconsole.log(account.primaryEndpoints?.blob);\nconsole.log(account.sku?.name);\n```\n\n### Update account settings and tags\n\nUse `update()` for patch-style account changes.\n\n```js\nimport { accountName, resourceGroupName, storageClient } from \"./client.js\";\n\nconst updated = await storageClient.storageAccounts.update(\n  resourceGroupName,\n  accountName,\n  {\n    tags: {\n      env: \"prod\",\n      owner: \"platform\",\n    },\n    allowSharedKeyAccess: false,\n    publicNetworkAccess: \"Enabled\",\n  },\n);\n\nconsole.log(updated.tags);\n```\n\n### List account keys only when you need shared-key workflows\n\nManagement APIs can return storage account keys, but application code should usually prefer Microsoft Entra ID plus the relevant data-plane SDK.\n\n```js\nimport { accountName, resourceGroupName, storageClient } from \"./client.js\";\n\nconst result = await storageClient.storageAccounts.listKeys(\n  resourceGroupName,\n  accountName,\n);\n\nfor (const key of result.keys ?? []) {\n  console.log(key.keyName);\n}\n```\n\n### Regenerate one account key\n\nRegenerate only the key you intend to rotate.\n\n```js\nimport { accountName, resourceGroupName, storageClient } from \"./client.js\";\n\nconst rotated = await storageClient.storageAccounts.regenerateKey(\n  resourceGroupName,\n  accountName,\n  {\n    keyName: \"key1\",\n  },\n);\n\nconsole.log(rotated.keys?.find((key) => key.keyName === \"key1\")?.keyName);\n```\n\n### Delete a storage account\n\nDelete is also a long-running ARM operation.\n\n```js\nimport { accountName, resourceGroupName, storageClient } from \"./client.js\";\n\nawait storageClient.storageAccounts.beginDeleteAndWait(\n  resourceGroupName,\n  accountName,\n);\n```\n\n## Configuration Notes\n\n- Reuse one `StorageManagementClient` instead of constructing a new client per request.\n- `AZURE_SUBSCRIPTION_ID` is required separately from your credential configuration.\n- Use `DefaultAzureCredential` for both local development and deployed workloads so your auth flow stays consistent.\n- Treat `list(...)` and `listByResourceGroup(...)` results as async iterables, not plain arrays.\n- Use `beginCreateAndWait(...)` and `beginDeleteAndWait(...)` when you need the ARM operation to be complete before the next step.\n- Storage account management is control plane only; switch to data-plane SDKs after the account exists.\n\n## Common Pitfalls\n\n- Confusing `@azure/arm-storage` with `@azure/storage-blob` or other data-plane packages.\n- Authenticating successfully but forgetting to set `AZURE_SUBSCRIPTION_ID` when constructing `StorageManagementClient`.\n- Skipping the name-availability check even though storage account names are globally unique.\n- Calling a long-running `begin...` method without waiting for the poller to finish.\n- Treating paged results as materialized arrays instead of async iterables.\n- Pulling account keys from ARM for application traffic when Entra ID plus RBAC would be safer.\n\n## Version Notes For 19.1.0\n\n- This guide targets `@azure/arm-storage` `19.1.0`.\n- The examples use `StorageManagementClient` from `@azure/arm-storage` and `DefaultAzureCredential` from `@azure/identity`.\n- If you are adapting older Azure management examples, re-check operation names and model fields against the `19.1.0` Learn reference before copying them into a project.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-storage/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/arm-storage-readme?view=azure-node-latest`\n- `StorageManagementClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-storage/storagemanagementclient?view=azure-node-latest`\n- `StorageAccounts` operations: `https://learn.microsoft.com/en-us/javascript/api/@azure/arm-storage/storageaccounts?view=azure-node-latest`\n- Azure Identity README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/arm-storage`\n"
  },
  {
    "path": "content/azure/docs/cognitiveservices-speech/python/DOC.md",
    "content": "---\nname: cognitiveservices-speech\ndescription: \"Azure Cognitive Services Speech SDK for Python for speech recognition, synthesis, translation, and language identification\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.48.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,speech,speech-to-text,text-to-speech,translation,language-identification,pronunciation\"\n---\n\n# Azure Cognitive Services Speech SDK for Python\n\n## Golden Rule\n\nUse `azure-cognitiveservices-speech` for real-time Azure Speech work in Python, import it as `azure.cognitiveservices.speech`, and configure it with a speech resource key plus either a region or a custom endpoint. This package ships native binaries, so install failures are often platform or system-library problems, not Python import problems.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"azure-cognitiveservices-speech==1.48.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-cognitiveservices-speech==1.48.2\"\npoetry add \"azure-cognitiveservices-speech==1.48.2\"\n```\n\nImportant install notes:\n\n- Microsoft Learn currently documents Python `3.8` or later for the SDK setup flow. PyPI metadata still reports `Requires: >=3.7`; follow the stricter Microsoft Learn requirement if the two disagree.\n- PyPI publishes platform wheels and currently no source distribution. Treat this as a native SDK package, not a pure-Python fallback package.\n- On Linux, stay within the supported distro and architecture matrix from Microsoft Learn. If audio capture or playback fails, verify system audio dependencies before debugging your Python code.\n- For compressed audio input such as MP3, OGG, or FLAC, the SDK relies on GStreamer. WAV/PCM works without that extra dependency.\n\nUbuntu or Debian systems that need compressed input support commonly need:\n\n```bash\nsudo apt install libgstreamer1.0-0 \\\n  gstreamer1.0-plugins-base \\\n  gstreamer1.0-plugins-good \\\n  gstreamer1.0-plugins-bad \\\n  gstreamer1.0-plugins-ugly\n```\n\n## Authentication And Setup\n\nMost official Python examples use a speech resource key with either:\n\n- `SPEECH_KEY` + `SPEECH_REGION`\n- `SPEECH_KEY` + `ENDPOINT`\n\nMicrosoft Learn also has some translation examples that use double-underscore names such as `SPEECH__SUBSCRIPTION__KEY` and `SPEECH__SERVICE__REGION`. If you are working in an existing codebase, support both forms instead of assuming one naming convention.\n\nUse a helper that normalizes the environment:\n\n```python\nimport os\nimport azure.cognitiveservices.speech as speechsdk\n\ndef make_speech_config() -> speechsdk.SpeechConfig:\n    key = os.getenv(\"SPEECH_KEY\") or os.getenv(\"SPEECH__SUBSCRIPTION__KEY\")\n    region = os.getenv(\"SPEECH_REGION\") or os.getenv(\"SPEECH__SERVICE__REGION\")\n    endpoint = os.getenv(\"ENDPOINT\") or os.getenv(\"SPEECH_ENDPOINT\")\n\n    if not key:\n        raise RuntimeError(\"Set SPEECH_KEY or SPEECH__SUBSCRIPTION__KEY.\")\n\n    if endpoint:\n        return speechsdk.SpeechConfig(subscription=key, endpoint=endpoint)\n\n    if region:\n        return speechsdk.SpeechConfig(subscription=key, region=region)\n\n    raise RuntimeError(\"Set either SPEECH_REGION or ENDPOINT.\")\n```\n\nRecommended environment variables:\n\n```bash\nexport SPEECH_KEY=\"...\"\nexport SPEECH_REGION=\"eastus\"\n```\n\nIf your resource or scenario requires a custom domain endpoint instead of a region, set:\n\n```bash\nexport SPEECH_KEY=\"...\"\nexport ENDPOINT=\"https://<resource-or-custom-domain>.cognitiveservices.azure.com/\"\n```\n\n## Core Usage\n\n### Recognize one utterance from the default microphone\n\nUse `recognize_once_async()` for short, single-utterance interactions:\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\nspeech_config.speech_recognition_language = \"en-US\"\n\naudio_config = speechsdk.audio.AudioConfig(use_default_microphone=True)\nrecognizer = speechsdk.SpeechRecognizer(\n    speech_config=speech_config,\n    audio_config=audio_config,\n)\n\nresult = recognizer.recognize_once_async().get()\n\nif result.reason == speechsdk.ResultReason.RecognizedSpeech:\n    print(result.text)\nelif result.reason == speechsdk.ResultReason.NoMatch:\n    raise RuntimeError(\"No speech could be recognized.\")\nelif result.reason == speechsdk.ResultReason.Canceled:\n    details = result.cancellation_details\n    raise RuntimeError(f\"{details.reason}: {details.error_details}\")\n```\n\n### Recognize speech from a local audio file\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\nspeech_config.speech_recognition_language = \"en-US\"\n\naudio_config = speechsdk.audio.AudioConfig(filename=\"input.wav\")\nrecognizer = speechsdk.SpeechRecognizer(\n    speech_config=speech_config,\n    audio_config=audio_config,\n)\n\nresult = recognizer.recognize_once_async().get()\nprint(result.text)\n```\n\nUse WAV/PCM first when you want the least setup friction. If you switch to MP3, FLAC, OGG, or MP4 containers, install and expose GStreamer correctly.\n\n### Continuous recognition for longer sessions\n\n`recognize_once_async()` stops after one utterance. For longer audio or streaming UX, use the continuous APIs and event callbacks:\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\nspeech_config.speech_recognition_language = \"en-US\"\n\nrecognizer = speechsdk.SpeechRecognizer(\n    speech_config=speech_config,\n    audio_config=speechsdk.audio.AudioConfig(filename=\"meeting.wav\"),\n)\n\ndone = False\n\ndef stop_cb(evt):\n    global done\n    done = True\n\nrecognizer.recognized.connect(lambda evt: print(\"RECOGNIZED:\", evt.result.text))\nrecognizer.canceled.connect(lambda evt: print(\"CANCELED:\", evt))\nrecognizer.session_stopped.connect(stop_cb)\n\nrecognizer.start_continuous_recognition()\nwhile not done:\n    pass\nrecognizer.stop_continuous_recognition()\n```\n\nFor production code, replace the busy wait with proper synchronization such as `threading.Event`.\n\n### Synthesize speech to the default speaker\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\nspeech_config.speech_synthesis_voice_name = \"en-US-Ava:DragonHDLatestNeural\"\n\nsynthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config)\nresult = synthesizer.speak_text_async(\"Hello from Azure Speech.\").get()\n\nif result.reason != speechsdk.ResultReason.SynthesizingAudioCompleted:\n    details = result.cancellation_details\n    raise RuntimeError(f\"{details.reason}: {details.error_details}\")\n```\n\nUse SSML with `speak_ssml_async()` when you need fine-grained voice, style, rate, pitch, or pronunciation control instead of plain text synthesis.\n\n### Synthesize to a file\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\naudio_config = speechsdk.audio.AudioOutputConfig(filename=\"output/hello.wav\")\n\nsynthesizer = speechsdk.SpeechSynthesizer(\n    speech_config=speech_config,\n    audio_config=audio_config,\n)\nsynthesizer.speak_text_async(\"Saved to disk.\").get()\n```\n\nThe parent directory must already exist before you construct `AudioOutputConfig`.\n\n### Translate speech while recognizing it\n\nUse the translation namespace, not `SpeechRecognizer`, when you need text translations from speech input:\n\n```python\nimport os\nimport azure.cognitiveservices.speech as speechsdk\n\ntranslation_config = speechsdk.translation.SpeechTranslationConfig(\n    subscription=os.environ[\"SPEECH_KEY\"],\n    region=os.environ[\"SPEECH_REGION\"],\n)\ntranslation_config.speech_recognition_language = \"en-US\"\ntranslation_config.add_target_language(\"de\")\n\nrecognizer = speechsdk.translation.TranslationRecognizer(\n    translation_config=translation_config,\n    audio_config=speechsdk.audio.AudioConfig(use_default_microphone=True),\n)\n\nresult = recognizer.recognize_once_async().get()\n\nif result.reason == speechsdk.ResultReason.TranslatedSpeech:\n    print(\"Source:\", result.text)\n    print(\"German:\", result.translations[\"de\"])\n```\n\n### Auto-detect the spoken language\n\nThis is the SDK path for multilingual front doors and voice assistants:\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\nauto_detect = speechsdk.languageconfig.AutoDetectSourceLanguageConfig(\n    languages=[\"en-US\", \"de-DE\", \"fr-FR\"]\n)\n\nrecognizer = speechsdk.SourceLanguageRecognizer(\n    speech_config=speech_config,\n    auto_detect_source_language_config=auto_detect,\n    audio_config=speechsdk.audio.AudioConfig(use_default_microphone=True),\n)\n\nresult = recognizer.recognize_once_async().get()\nprint(result.text)\n```\n\nFor continuous language identification, Microsoft Learn documents endpoint-based configuration and specific SDK/platform support limits. Do not assume the one-shot and continuous language-ID flows have identical configuration rules.\n\n### Pronunciation assessment\n\n`PronunciationAssessmentConfig` is the SDK path for scoring pronunciation, fluency, and completeness:\n\n```python\nimport azure.cognitiveservices.speech as speechsdk\n\nspeech_config = make_speech_config()\naudio_config = speechsdk.audio.AudioConfig(filename=\"student.wav\")\n\nrecognizer = speechsdk.SpeechRecognizer(\n    speech_config=speech_config,\n    audio_config=audio_config,\n)\n\nassessment = speechsdk.PronunciationAssessmentConfig(\n    reference_text=\"The quick brown fox jumps over the lazy dog.\",\n    grading_system=speechsdk.PronunciationAssessmentGradingSystem.HundredMark,\n    granularity=speechsdk.PronunciationAssessmentGranularity.Phoneme,\n)\nassessment.apply_to(recognizer)\n\nresult = recognizer.recognize_once_async().get()\nprint(result.text)\n```\n\nIf you need richer scoring output, parse the JSON result payload from the pronunciation assessment APIs rather than assuming the top-level recognition text is enough.\n\n## Configuration Notes\n\n- Set `speech_recognition_language` or `speech_synthesis_voice_name` explicitly. Defaults are easy to forget and produce the wrong locale.\n- Region-based setup is simplest for standard speech resources. Endpoint-based setup is common for custom domains, some translation flows, and some continuous language-identification scenarios.\n- Keep your key and endpoint or region outside source control. Environment variables are the safest default for agent-written code.\n- Use the async SDK methods shown in the official docs even in synchronous scripts. The Python samples consistently call `..._async().get()`.\n\n## Common Pitfalls\n\n- `recognize_once_async()` is not a streaming API. It handles a single utterance and then stops.\n- The package contains native code. If imports fail in CI or containers, verify wheel compatibility, CPU architecture, OpenSSL or CA packages, and audio dependencies before rewriting code.\n- Compressed input formats require GStreamer. A missing GStreamer install often looks like an audio-format bug in Python.\n- Translation uses `speechsdk.translation.*` types, not the base recognizer classes.\n- Language identification is a separate recognizer flow. Do not expect `SpeechRecognizer` to infer the source language automatically.\n- File output requires the destination directory to exist first.\n- Batch transcription and some management tasks belong to the Speech REST APIs, not this SDK’s real-time client flow.\n\n## Version-Sensitive Notes\n\n- `SourceLanguageRecognizer` was added in `1.18.0`. If an older codebase does not have it, the project is pinned well below the current package version.\n- `SpeechSynthesisRequest` was added in `1.37.0` and is still marked preview in the API reference. Avoid building critical abstractions around preview-only synthesis features without checking the exact installed version.\n- Microsoft Learn notes that pronunciation assessment content assessment was retired in Speech SDK `1.46.0` and later. Do not rely on older examples that still reference that preview capability.\n- The version used here for this package matched current PyPI at `1.48.2` on March 12, 2026, so the frontmatter uses the live registry version without drift correction.\n\n## Official Sources\n\n- API reference: `https://learn.microsoft.com/en-us/python/api/azure-cognitiveservices-speech/`\n- SDK install guide: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/quickstarts/setup-platform`\n- Speech to text quickstart: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/get-started-speech-to-text`\n- Text to speech quickstart: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/get-started-text-to-speech`\n- Speech recognition how-to: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/how-to-recognize-speech`\n- Speech translation how-to: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/how-to-translate-speech`\n- Language identification: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-identification`\n- Pronunciation assessment: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/how-to-pronunciation-assessment`\n- Compressed audio input: `https://learn.microsoft.com/en-us/azure/ai-services/speech-service/how-to-use-codec-compressed-audio-input-streams`\n- PyPI package page: `https://pypi.org/project/azure-cognitiveservices-speech/`\n"
  },
  {
    "path": "content/azure/docs/common/python/DOC.md",
    "content": "---\nname: common\ndescription: \"azure-common package guide for Python legacy Azure SDK auth helpers, client factories, cloud helpers, and compatibility exceptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.28\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-common,python,legacy,authentication,management\"\n---\n\n# azure-common Python Package Guide\n\n## What It Is\n\n`azure-common` is a legacy support package from the older Azure SDK for Python stack. In `1.1.28`, the source tree still exposes four main areas:\n\n- `azure.common.credentials`\n- `azure.common.client_factory`\n- `azure.common.cloud`\n- `azure.common.exceptions`\n\nIt also defines package-level compatibility exceptions in `azure.common` such as `AzureHttpError`, `AzureConflictHttpError`, and `AzureMissingResourceHttpError`.\n\nUse this package only when you are maintaining older Azure SDK code that already imports `azure.common.*`. For new Azure Python work, Microsoft directs you to service-specific modern SDKs plus `azure-identity`.\n\n## Version Scope\n\n- Ecosystem: `pypi`\n- Package: `azure-common`\n- Version covered: `1.1.28`\n- Release state: final published release in the `1.x` line\n- Support state: deprecated; Azure's deprecated-packages index lists support end on `2023-03-31`\n- Docs root: `https://learn.microsoft.com/en-us/python/api/azure-common/`\n- Registry URL: `https://pypi.org/project/azure-common/`\n\nThe version used here for this session is `1.1.28`, and that matches the tagged upstream source, the PyPI simple index, and Azure's deprecated-packages page.\n\n## Install\n\nInstall only when the target project already depends on the legacy Azure SDK generation:\n\n```bash\npython -m pip install azure-common==1.1.28\n```\n\nWith `uv`:\n\n```bash\nuv pip install azure-common==1.1.28\n```\n\nWith Poetry:\n\n```bash\npoetry add azure-common==1.1.28\n```\n\nPractical install notes:\n\n- `azure-common` is not a standalone Azure client. It is a support package used by older Azure SDK libraries.\n- The upstream `setup.py` explicitly rejects the old `azure` metapackage (`azure==0.x`). If that metapackage is installed, remove it before troubleshooting imports.\n- The credentials and exception helpers import `msrest` and `msrestazure`. In older projects, those usually arrive as transitive dependencies from the service client package.\n\n## When You Still Need It\n\nKeep `azure-common` only if the project already uses older Azure packages that expect one of these patterns:\n\n- `ServicePrincipalCredentials`, `UserPassCredentials`, or `InteractiveCredentials`\n- `get_client_from_cli_profile(...)`\n- `get_azure_cli_credentials(...)`\n- `get_client_from_json_dict(...)` or `get_client_from_auth_file(...)`\n- `azure.common.exceptions.CloudError` or package-root `AzureHttpError` compatibility handling\n\nIf the target library expects an `azure-identity` credential object with `get_token`, `azure-common` is the wrong auth layer.\n\n## Initialization And Auth\n\n### Service principal credentials for older clients\n\nThe legacy credential type is `ServicePrincipalCredentials`:\n\n```python\nfrom azure.common.credentials import ServicePrincipalCredentials\n\ntenant_id = \"<tenant-id>\"\nclient_id = \"<client-id>\"\nclient_secret = \"<client-secret>\"\n\ncredentials = ServicePrincipalCredentials(\n    client_id=client_id,\n    secret=client_secret,\n    tenant=tenant_id,\n)\n```\n\nOlder management-plane clients usually pair this with a separate subscription ID argument:\n\n```python\nfrom azure.common.credentials import ServicePrincipalCredentials\nfrom azure.mgmt.resource import ResourceManagementClient\n\nsubscription_id = \"<subscription-id>\"\n\ncredentials = ServicePrincipalCredentials(\n    client_id=\"<client-id>\",\n    secret=\"<client-secret>\",\n    tenant=\"<tenant-id>\",\n)\n\nresource_client = ResourceManagementClient(credentials, subscription_id)\n```\n\nThis is the legacy pattern. If the client constructor expects a modern `TokenCredential`, switch to `azure-identity` instead of forcing `azure-common` into new code.\n\n### Azure CLI credentials\n\n`1.1.28` still ships `get_azure_cli_credentials`, but the source marks it deprecated and explicitly states it does not work with `azure-cli-core>=2.21.0`.\n\n```python\nfrom azure.common.credentials import get_azure_cli_credentials\n\ncredentials, subscription_id = get_azure_cli_credentials()\n```\n\nImportant behavior in `1.1.28`:\n\n- it emits a deprecation warning\n- it raises `NotImplementedError` when the installed CLI core version is `2.21.0` or newer\n- Microsoft recommends `azure-identity` with `AzureCliCredential` instead\n\n### Client factory from CLI login\n\nFor older management clients, `get_client_from_cli_profile(...)` can still instantiate a client from the local Azure CLI profile:\n\n```python\nfrom azure.common.client_factory import get_client_from_cli_profile\nfrom azure.mgmt.resource import SubscriptionClient\n\nsubscription_client = get_client_from_cli_profile(SubscriptionClient)\n```\n\nThis helper is also deprecated in `1.1.28` and has the same `azure-cli-core<2.21.0` limitation.\n\n### JSON and auth-file based helpers\n\nThe client-factory module still includes:\n\n- `get_client_from_json_dict(...)`\n- `get_client_from_auth_file(...)`\n\nThese are legacy migration/maintenance helpers, not good defaults for new code. The source and migration guide both direct new work toward `azure-identity` instead of JSON-file credential loading.\n\nIf you must keep the old pattern during maintenance, `get_client_from_auth_file(...)` reads JSON from either:\n\n- an explicit `auth_path`, or\n- `AZURE_AUTH_LOCATION`\n\nThe JSON shape expected by the helper includes fields such as:\n\n- `clientId`\n- `clientSecret`\n- `subscriptionId`\n- `tenantId`\n- `activeDirectoryEndpointUrl`\n- `resourceManagerEndpointUrl`\n\n## Core Usage Surface\n\n### Credentials module\n\n`azure.common.credentials` is mostly a re-export layer around older auth classes:\n\n- `ServicePrincipalCredentials`\n- `UserPassCredentials`\n- `InteractiveCredentials`\n- `BasicAuthentication`\n- `BasicTokenAuthentication`\n- `OAuthTokenAuthentication`\n\nThe CLI helpers live in the same module:\n\n- `get_cli_profile()`\n- `get_azure_cli_credentials(...)`\n\n### Client factory module\n\n`azure.common.client_factory` is meant for older autogenerated management clients. In `1.1.28`, its helpers still try to auto-fill arguments such as:\n\n- `credentials` or `credential`\n- `subscription_id`\n- `base_url`\n- `tenant_id`\n\nThis is useful when reading legacy code because it explains why older client construction sometimes looks incomplete.\n\n### Cloud helper\n\n`azure.common.cloud.get_cli_active_cloud()` exists only to read the active Azure CLI cloud. In `1.1.28`, it is deprecated and subject to the same `azure-cli-core>=2.21.0` breakage as the other CLI helpers.\n\nTreat it as a maintenance-only helper for older sovereign-cloud logic. Do not build new cloud-selection code on top of it.\n\n### Exception surface\n\nThere are two exception layers to keep straight:\n\n- `azure.common.exceptions` re-exports exception types from `msrest` plus `msrestazure.azure_exceptions.CloudError`\n- package-root `azure.common` defines `AzureException`, `AzureHttpError`, `AzureConflictHttpError`, and `AzureMissingResourceHttpError`\n\nFor example:\n\n```python\nfrom azure.common import AzureHttpError, AzureMissingResourceHttpError\nfrom azure.common.exceptions import CloudError\n\ntry:\n    do_legacy_call()\nexcept AzureMissingResourceHttpError:\n    handle_missing()\nexcept CloudError as exc:\n    print(exc)\nexcept AzureHttpError as exc:\n    print(exc.status_code)\n```\n\nDo not assume newer Azure SDK clients will raise these types.\n\n## Configuration Notes\n\n`azure-common` has no central config file. Legacy setups usually depend on one of these sources:\n\n- service-principal secrets from environment variables or secret stores\n- local Azure CLI profile state for development-time helpers\n- auth JSON passed to `get_client_from_json_dict(...)` or read from `AZURE_AUTH_LOCATION`\n- cloud/base URL values inferred from the active CLI cloud\n\nPractical guidance:\n\n- keep the subscription ID separate from credential construction unless the specific helper returns it for you\n- never commit auth JSON files; if they must exist temporarily, keep them out of version control\n- verify the expected resource or base URL for older clients, especially in sovereign-cloud environments\n\n## Common Pitfalls\n\n### Mixing `azure-common` credentials with modern clients\n\nMicrosoft's migration guide calls out the API mismatch directly:\n\n- modern clients expect an `azure-identity` credential with `get_token`\n- older clients expect `azure-common` / `msrest` style auth with `signed_session`\n\nIf you see errors like missing `get_token` or missing `signed_session`, you are probably mixing SDK generations.\n\n### Expecting CLI helpers to work with a current Azure CLI core\n\nIn `1.1.28`, the CLI-based helpers are deprecated and intentionally fail on `azure-cli-core>=2.21.0`. If an old script depends on them, you either need an older CLI core in a controlled compatibility environment or a migration to `AzureCliCredential`.\n\n### Treating auth-file helpers as a long-term design\n\n`get_client_from_json_dict(...)` and `get_client_from_auth_file(...)` are legacy helpers. They are useful for keeping old code running, but they are not the recommended auth path anymore.\n\n### Importing from the wrong exception module\n\n`azure.common.exceptions` does not define the package-root `AzureHttpError` classes. If legacy code imports `AzureHttpError`, it should come from `azure.common`, not `azure.common.exceptions`.\n\n### Installing the old `azure` metapackage\n\nThe upstream package setup explicitly rejects the legacy `azure==0.x` metapackage. If import behavior looks inconsistent, check for that package first.\n\n## Version-Sensitive Notes\n\n### `1.1.28`\n\n- final tagged package version\n- release date in the upstream changelog: `2022-02-03`\n- deprecated all helpers that need access to Azure CLI internals\n- raises `NotImplementedError` when CLI credential helpers are used with `azure-cli-core>=2.21.0`\n\n### `1.1.27`\n\n- deprecated the JSON-dict and auth-file client-factory approach\n\n### Support lifecycle\n\n- Azure's deprecated Python SDK index lists `azure-common` support ending on `2023-03-31`\n- treat any remaining usage as legacy maintenance, not as a stable foundation for new Azure integrations\n\n## Migration Boundary\n\nWhen you touch code that imports `azure.common.*`, use this decision rule:\n\n1. Keep `azure-common` only if the surrounding service client is still from the older Azure SDK generation.\n2. If the client is modern, migrate the auth layer to `azure-identity` instead of adapting legacy credentials.\n3. Replace CLI helpers with `AzureCliCredential` when the client supports modern credentials.\n4. Replace `ServicePrincipalCredentials` with `ClientSecretCredential` when moving to newer clients.\n\n## Recommended Agent Workflow\n\n1. Confirm whether the target Azure package is legacy or modern before writing code.\n2. Match the installed `azure-common` version to `1.1.28` if you are debugging a current pinned environment.\n3. Check for `azure-cli-core` usage before relying on CLI helper functions.\n4. Keep auth-file and JSON-dict helpers only for compatibility work.\n5. Prefer a staged migration to `azure-identity` instead of adding new `azure-common` usage.\n\n## Official Sources\n\n- Microsoft Learn package URL: `https://learn.microsoft.com/en-us/python/api/azure-common/`\n- Azure deprecated Python packages index: `https://azure.github.io/azure-sdk/releases/deprecated/python.html`\n- Azure SDK for Python `azure-common` source tree at tag `azure-common_1.1.28`: `https://github.com/Azure/azure-sdk-for-python/tree/azure-common_1.1.28/sdk/core/azure-common/`\n- `azure-common` `1.1.28` source files:\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/azure/common/credentials.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/azure/common/client_factory.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/azure/common/cloud.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/azure/common/exceptions.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/azure/common/__init__.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/setup.py`\n  - `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/azure-common_1.1.28/sdk/core/azure-common/CHANGELOG.md`\n- Azure Identity migration guide: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/migration_guide.md`\n- PyPI simple index for package release files: `https://pypi.org/simple/azure-common/`\n"
  },
  {
    "path": "content/azure/docs/communication-chat/javascript/DOC.md",
    "content": "---\nname: communication-chat\ndescription: \"Azure Communication Services chat SDK for JavaScript with setup, token auth, threads, messages, participants, and realtime notifications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.6.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,communication-services,chat,javascript,messaging,realtime\"\n---\n\n# Azure Communication Services Chat SDK For JavaScript\n\n## Golden Rule\n\nUse `@azure/communication-chat` with an Azure Communication Services user access token, not a resource connection string in client code. Create one long-lived `ChatClient` per signed-in user session, then get a `ChatThreadClient` for thread-specific work such as sending messages, listing participants, and updating thread state.\n\n## Install\n\n```bash\nnpm install @azure/communication-chat@1.6.0 @azure/communication-common\n```\n\nIf you mint user identities and access tokens on your Node backend, add `@azure/communication-identity` there. Do not ship your ACS connection string to browsers or other untrusted clients.\n\n## Prerequisites\n\nBefore this SDK can do anything useful, Azure must already provide:\n\n1. An Azure Communication Services resource endpoint such as `https://<resource>.communication.azure.com`.\n2. A Communication Services user access token for the signed-in user.\n3. A chat thread ID if your app is joining an existing thread.\n\nUse environment variables like these for local development:\n\n```bash\nexport ACS_ENDPOINT=\"https://<resource>.communication.azure.com\"\nexport ACS_CHAT_TOKEN=\"<communication-user-access-token>\"\nexport ACS_CHAT_THREAD_ID=\"<chat-thread-id>\"\nexport ACS_OTHER_USER_ID=\"<8:acs:... user id>\"\n```\n\n## Authentication And Client Setup\n\nThe JavaScript chat SDK uses a Communication Services user token wrapped in `AzureCommunicationTokenCredential`.\n\n```js\nimport { ChatClient } from \"@azure/communication-chat\";\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\n\nconst endpoint = process.env.ACS_ENDPOINT;\nconst token = process.env.ACS_CHAT_TOKEN;\n\nif (!endpoint || !token) {\n  throw new Error(\"Set ACS_ENDPOINT and ACS_CHAT_TOKEN before creating the chat client.\");\n}\n\nconst credential = new AzureCommunicationTokenCredential(token);\nconst chatClient = new ChatClient(endpoint, credential);\n```\n\nIf your user tokens expire during longer sessions, use a proactive token refresher instead of recreating the client repeatedly:\n\n```js\nimport { ChatClient } from \"@azure/communication-chat\";\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\n\nconst credential = new AzureCommunicationTokenCredential({\n  token: process.env.ACS_CHAT_TOKEN,\n  refreshProactively: true,\n  tokenRefresher: async () => {\n    const response = await fetch(\"http://localhost:3000/api/acs/token\", {\n      method: \"POST\",\n    });\n\n    if (!response.ok) {\n      throw new Error(`Token refresh failed with ${response.status}`);\n    }\n\n    const { token } = await response.json();\n    return token;\n  },\n});\n\nconst chatClient = new ChatClient(process.env.ACS_ENDPOINT, credential);\n```\n\n## Client Initialization\n\nKeep one shared `ChatClient` for the current user, then derive thread clients as needed.\n\n```js\nimport { ChatClient } from \"@azure/communication-chat\";\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\n\nconst chatClient = new ChatClient(\n  process.env.ACS_ENDPOINT,\n  new AzureCommunicationTokenCredential(process.env.ACS_CHAT_TOKEN),\n);\n\nexport function getThreadClient(threadId) {\n  return chatClient.getChatThreadClient(threadId);\n}\n```\n\nUse `ChatClient` for thread creation, deletion, realtime notifications, and cross-thread operations. Use `ChatThreadClient` for messages, participants, read state, and thread properties.\n\n## Core Usage\n\n### Create a chat thread\n\nCreate a thread from the top-level client. Add initial participants in the same call when you already know who should join.\n\n```js\nimport { ChatClient } from \"@azure/communication-chat\";\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\n\nconst chatClient = new ChatClient(\n  process.env.ACS_ENDPOINT,\n  new AzureCommunicationTokenCredential(process.env.ACS_CHAT_TOKEN),\n);\n\nconst result = await chatClient.createChatThread(\n  {\n    topic: \"Order support\",\n  },\n  {\n    participants: [\n      {\n        id: { communicationUserId: process.env.ACS_OTHER_USER_ID },\n        displayName: \"Support agent\",\n        shareHistoryTime: new Date(),\n      },\n    ],\n  },\n);\n\nconst threadId = result.chatThread?.id;\n\nif (!threadId) {\n  throw new Error(\"Thread creation did not return a thread id.\");\n}\n\nconst threadClient = chatClient.getChatThreadClient(threadId);\n```\n\n### Connect to an existing thread\n\n```js\nimport { ChatClient } from \"@azure/communication-chat\";\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\n\nconst chatClient = new ChatClient(\n  process.env.ACS_ENDPOINT,\n  new AzureCommunicationTokenCredential(process.env.ACS_CHAT_TOKEN),\n);\n\nconst threadClient = chatClient.getChatThreadClient(process.env.ACS_CHAT_THREAD_ID);\n```\n\n### Send a message\n\n```js\nconst sendResult = await threadClient.sendMessage(\n  {\n    content: \"Hello from Azure Communication Services chat.\",\n    type: \"text\",\n  },\n  {\n    senderDisplayName: \"Docs sample\",\n  },\n);\n\nconsole.log(sendResult.id);\n```\n\n### List messages\n\n`listMessages()` is an async iterator. Treat it like a paged stream, not a preloaded array.\n\n```js\nfor await (const message of threadClient.listMessages()) {\n  console.log(message.id, message.type, message.content?.message);\n}\n```\n\nTo page manually:\n\n```js\nfor await (const page of threadClient.listMessages().byPage({ maxPageSize: 20 })) {\n  for (const message of page) {\n    console.log(message.id, message.content?.message);\n  }\n}\n```\n\n### Edit or delete a message\n\n```js\nconst { id: messageId } = await threadClient.sendMessage(\n  { content: \"Draft message\", type: \"text\" },\n  { senderDisplayName: \"Docs sample\" },\n);\n\nawait threadClient.updateMessage(messageId, {\n  content: \"Edited message\",\n});\n\nawait threadClient.deleteMessage(messageId);\n```\n\n### Read and update thread properties\n\n```js\nconst properties = await threadClient.getProperties();\nconsole.log(properties.id, properties.topic);\n\nawait threadClient.updateTopic(\"Escalated order support\");\n```\n\n### Manage participants\n\nUse `shareHistoryTime` when you need to control how much earlier conversation history a new participant can see.\n\n```js\nawait threadClient.addParticipants({\n  participants: [\n    {\n      id: { communicationUserId: process.env.ACS_OTHER_USER_ID },\n      displayName: \"Support agent\",\n      shareHistoryTime: new Date(),\n    },\n  ],\n});\n\nfor await (const participant of threadClient.listParticipants()) {\n  console.log(participant.displayName, participant.id);\n}\n\nawait threadClient.removeParticipant({\n  communicationUserId: process.env.ACS_OTHER_USER_ID,\n});\n```\n\n### Start realtime notifications\n\nCall `startRealtimeNotifications()` once on the shared `ChatClient`, then register listeners for the events your app cares about.\n\n```js\nawait chatClient.startRealtimeNotifications();\n\nchatClient.on(\"chatMessageReceived\", (event) => {\n  console.log(\"message received\", event);\n});\n\nchatClient.on(\"typingIndicatorReceived\", (event) => {\n  console.log(\"typing\", event);\n});\n\nchatClient.on(\"readReceiptReceived\", (event) => {\n  console.log(\"read receipt\", event);\n});\n```\n\nYou can also send a typing indicator from a thread client:\n\n```js\nawait threadClient.sendTypingNotification();\n```\n\n### Delete a thread\n\nDelete whole threads from the top-level client, not the thread client.\n\n```js\nawait chatClient.deleteChatThread(process.env.ACS_CHAT_THREAD_ID);\n```\n\n## Configuration Notes\n\n- Use a Communication Services user token in `AzureCommunicationTokenCredential`; do not expose your resource connection string to the browser.\n- Reuse one `ChatClient` per signed-in user session and create `ChatThreadClient` instances from it with `getChatThreadClient(threadId)`.\n- Treat list operations such as `listChatThreads()`, `listMessages()`, and `listParticipants()` as async iterators.\n- Start realtime notifications before expecting chat events to arrive.\n- Keep token refresh on the server side and return only short-lived user tokens to clients.\n- Create and delete threads on `ChatClient`; send messages and manage participants on `ChatThreadClient`.\n\n## Common Pitfalls\n\n- Trying to authenticate chat clients with only a resource endpoint or connection string. The chat SDK needs a user access token.\n- Recreating `ChatClient` for every action instead of reusing one long-lived client.\n- Treating iterator-based list methods like arrays.\n- Forgetting to call `startRealtimeNotifications()` before registering event-driven chat behavior.\n- Sending your ACS connection string or identity-management secrets to frontend code.\n- Assuming `shareHistoryTime` is irrelevant when adding participants to existing threads.\n\n## Version Notes For 1.6.0\n\n- This guide targets `@azure/communication-chat` `1.6.0`.\n- The examples here use the v1 client split between `ChatClient` and `ChatThreadClient`.\n- Token acquisition is intentionally separate from this package. If you need to create Communication Services users or issue tokens, do that in trusted backend code with the identity SDK.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-chat/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/communication-chat-readme?view=azure-node-latest`\n- `ChatClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-chat/chatclient?view=azure-node-latest`\n- `ChatThreadClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-chat/chatthreadclient?view=azure-node-latest`\n- `AzureCommunicationTokenCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-common/azurecommunicationtokencredential?view=azure-node-latest`\n- ACS chat quickstart: `https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-javascript`\n- npm package page: `https://www.npmjs.com/package/@azure/communication-chat`\n"
  },
  {
    "path": "content/azure/docs/communication-common/javascript/DOC.md",
    "content": "---\nname: communication-common\ndescription: \"Azure Communication Services JavaScript common package for token credentials and communication identifiers shared across ACS client libraries\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,communication,communication-common,javascript,authentication,identifiers\"\n---\n\n# Azure Communication Services Common JavaScript Package\n\n## Golden Rule\n\nUse `@azure/communication-common` for the shared building blocks that other Azure Communication Services SDKs expect: `AzureCommunicationTokenCredential` for user-token auth and `CommunicationIdentifier` helpers for user, phone number, and Teams identities. This package does not create users, issue tokens, or talk to Azure Communication Services by itself.\n\n## Install\n\nInstall the shared package at the version your app expects:\n\n```bash\nnpm install @azure/communication-common@2.4.0\n```\n\nYou usually install it alongside the ACS client you actually use:\n\n```bash\nnpm install @azure/communication-common@2.4.0 @azure/communication-chat\n```\n\n## What It Provides\n\n- `AzureCommunicationTokenCredential` for passing ACS user access tokens into client constructors\n- `CommunicationIdentifier` shapes used by ACS SDKs when you send or receive identities\n- `getIdentifierKind(...)` for branching safely on identifier type before reading identifier-specific fields\n\n## Authentication And Setup\n\nThe common package wraps a Communication Services user access token. It does not mint that token for you.\n\nUse environment variables instead of hard-coding values:\n\n```bash\nexport ACS_ENDPOINT=\"https://<resource-name>.communication.azure.com\"\nexport ACS_USER_TOKEN=\"<communication-services-user-access-token>\"\n```\n\n`ACS_ENDPOINT` is your Azure Communication Services resource endpoint. `ACS_USER_TOKEN` must be a user access token returned by your trusted backend or token service.\n\n## Client Initialization\n\n`@azure/communication-common` is normally used when constructing another ACS client.\n\n### Static token credential\n\nUse this when your process already has a valid user access token and you can replace the client when the token expires:\n\n```js\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\nimport { ChatClient } from \"@azure/communication-chat\";\n\nconst endpoint = process.env.ACS_ENDPOINT;\nconst token = process.env.ACS_USER_TOKEN;\n\nif (!endpoint || !token) {\n  throw new Error(\"ACS_ENDPOINT and ACS_USER_TOKEN are required\");\n}\n\nconst credential = new AzureCommunicationTokenCredential(token);\nconst chatClient = new ChatClient(endpoint, credential);\n```\n\n### Refreshing token credential\n\nUse a refresher when the app should keep the credential alive without rebuilding clients. The refresher must return the raw token string.\n\n```js\nimport { AzureCommunicationTokenCredential } from \"@azure/communication-common\";\nimport { ChatClient } from \"@azure/communication-chat\";\n\nconst endpoint = process.env.ACS_ENDPOINT;\n\nif (!endpoint) {\n  throw new Error(\"ACS_ENDPOINT is required\");\n}\n\nconst credential = new AzureCommunicationTokenCredential({\n  tokenRefresher: async () => {\n    const response = await fetch(\"/api/acs/token\", {\n      method: \"POST\",\n    });\n\n    if (!response.ok) {\n      throw new Error(`Token refresh failed with ${response.status}`);\n    }\n\n    const { token } = await response.json();\n    return token;\n  },\n  refreshProactively: true,\n});\n\nconst chatClient = new ChatClient(endpoint, credential);\n```\n\nKeep token minting on a trusted backend. Do not ship your ACS connection string or token-issuing secrets to browser code.\n\n## Core Usage\n\n### Build identifier objects for ACS SDK calls\n\nACS clients use structured identifier objects, not plain strings.\n\n```js\nconst participant = {\n  id: {\n    communicationUserId: process.env.ACS_OTHER_USER_ID,\n  },\n  displayName: \"Support agent\",\n  shareHistoryTime: new Date(),\n};\n```\n\nThe same pattern applies when you need other identifier types, such as phone numbers or Teams users: pass the identifier object shape the client expects instead of flattening it into a string.\n\n### Inspect identifiers safely\n\nUse `getIdentifierKind(...)` before reading identifier-specific fields.\n\n```js\nimport { getIdentifierKind } from \"@azure/communication-common\";\n\nexport function normalizeIdentifier(identifier) {\n  switch (getIdentifierKind(identifier)) {\n    case \"communicationUser\":\n      return {\n        kind: \"communicationUser\",\n        value: identifier.communicationUserId,\n      };\n    case \"phoneNumber\":\n      return {\n        kind: \"phoneNumber\",\n        value: identifier.phoneNumber,\n      };\n    case \"microsoftTeamsUser\":\n      return {\n        kind: \"microsoftTeamsUser\",\n        value: identifier.microsoftTeamsUserId,\n      };\n    default:\n      return {\n        kind: \"unknown\",\n        value: identifier.id,\n      };\n  }\n}\n```\n\nThis is the safe pattern when you read participant lists, sender identities, or event payloads from ACS SDKs.\n\n## Configuration Notes\n\n- Reuse one long-lived credential per signed-in user instead of constructing a new credential for every request.\n- Pair this package with the ACS client library that actually performs the service operations.\n- Use a static token only for short-lived processes or controlled server-side flows; use `tokenRefresher` for interactive apps that need seamless renewal.\n- Treat identifier values as typed objects. Check the identifier kind before reading fields such as `communicationUserId` or `phoneNumber`.\n\n## Common Pitfalls\n\n- Passing an ACS connection string where an `AzureCommunicationTokenCredential` or user token is required.\n- Returning the entire JSON payload from `tokenRefresher` instead of returning just the token string.\n- Creating a fresh credential and service client for every operation instead of reusing them for the current user session.\n- Assuming every ACS identity is a `communicationUserId`; phone number and Teams identifiers use different fields.\n- Sending token-minting secrets to frontend code instead of refreshing tokens through a backend endpoint.\n\n## Version Notes For 2.4.0\n\n- This guide targets `@azure/communication-common` `2.4.0`.\n- The practical surface for most app code is the token credential plus identifier helpers shared by other ACS JavaScript SDKs.\n- Token issuance and resource management stay outside this package; keep those concerns in backend code or in the appropriate ACS service SDK.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-common/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/communication-common-readme?view=azure-node-latest`\n- `AzureCommunicationTokenCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-common/azurecommunicationtokencredential?view=azure-node-latest`\n- `CommunicationIdentifier` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-common/communicationidentifier?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/communication-common`\n"
  },
  {
    "path": "content/azure/docs/communication-email/python/DOC.md",
    "content": "---\nname: communication-email\ndescription: \"Azure Communication Services Email SDK for Python with setup, authentication, send polling, attachments, and version-sensitive notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,communication-services,email,python,sdk,cloud\"\n---\n\n# Azure Communication Services Email SDK For Python\n\n## Golden Rule\n\nUse `azure-communication-email` with `from azure.communication.email import EmailClient`, send mail with `begin_send(...)`, and poll the long-running operation until it reaches a terminal status. Valid credentials are not enough by themselves: the sender address must come from a linked, verified Azure Email Communication Services domain.\n\n## Install\n\n```bash\npython -m pip install \"azure-communication-email==1.1.0\"\n```\n\nIf you plan to authenticate with Microsoft Entra ID, install `azure-identity` too:\n\n```bash\npython -m pip install \"azure-communication-email==1.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-communication-email==1.1.0\"\npoetry add \"azure-communication-email==1.1.0\"\n```\n\nVersion note:\n\n- PyPI metadata for `1.1.0` requires Python `>=3.9`.\n- The Azure quickstart still says Python `3.7+`.\n- Treat PyPI as the package-version source of truth for runtime support.\n\n## Azure Prerequisites\n\nBefore the SDK can send successfully, Azure must already be configured:\n\n1. Create an Azure Communication Services resource.\n2. Create an Email Communication Services resource with a provisioned domain.\n3. Link that domain to the Communication Services resource.\n4. Use a `senderAddress` from the linked domain's `MailFrom` value.\n\nIf the domain is not linked, or the sender address does not match the linked domain, `begin_send(...)` will fail even when authentication is correct.\n\n## Authentication And Client Setup\n\nThe SDK supports three practical auth paths:\n\n- connection string\n- Microsoft Entra ID with `DefaultAzureCredential`\n- endpoint plus `AzureKeyCredential`\n\n### Connection string\n\nThis is the simplest path for scripts and local testing. The SDK does not require a fixed env var name; these examples use `AZURE_COMMUNICATION_CONNECTION_STRING`.\n\n```python\nimport os\nfrom azure.communication.email import EmailClient\n\nconnection_string = os.environ[\"AZURE_COMMUNICATION_CONNECTION_STRING\"]\nclient = EmailClient.from_connection_string(connection_string)\n```\n\n### Microsoft Entra ID\n\nPrefer this in production when managed identity, workload identity, or a service principal is available.\n\n```python\nimport os\nfrom azure.communication.email import EmailClient\nfrom azure.identity import DefaultAzureCredential\n\nendpoint = os.environ[\"AZURE_COMMUNICATION_SERVICE_ENDPOINT\"]\nclient = EmailClient(endpoint, DefaultAzureCredential())\n```\n\nTypical environment variables for service-principal auth:\n\n- `AZURE_TENANT_ID`\n- `AZURE_CLIENT_ID`\n- `AZURE_CLIENT_SECRET`\n- `AZURE_COMMUNICATION_SERVICE_ENDPOINT`\n\n### AzureKeyCredential\n\n```python\nimport os\nfrom azure.communication.email import EmailClient\nfrom azure.core.credentials import AzureKeyCredential\n\nendpoint = os.environ[\"AZURE_COMMUNICATION_SERVICE_ENDPOINT\"]\naccess_key = os.environ[\"AZURE_COMMUNICATION_SERVICE_ACCESS_KEY\"]\n\nclient = EmailClient(endpoint, AzureKeyCredential(access_key))\n```\n\n## Core Usage\n\n### Minimal send\n\n`begin_send(...)` takes a dict-shaped message payload and returns a poller.\n\n```python\nimport os\nfrom azure.communication.email import EmailClient\n\nconnection_string = os.environ[\"AZURE_COMMUNICATION_CONNECTION_STRING\"]\nsender = os.environ[\"AZURE_COMMUNICATION_SENDER_ADDRESS\"]\n\nclient = EmailClient.from_connection_string(connection_string)\n\nmessage = {\n    \"senderAddress\": sender,\n    \"recipients\": {\n        \"to\": [\n            {\n                \"address\": \"recipient@example.com\",\n                \"displayName\": \"Recipient\",\n            }\n        ]\n    },\n    \"content\": {\n        \"subject\": \"Hello from Azure Communication Services\",\n        \"plainText\": \"This is a text body.\",\n        \"html\": \"<html><body><p>This is an HTML body.</p></body></html>\",\n    },\n}\n\npoller = client.begin_send(message)\nresult = poller.result()\n\nprint(result[\"id\"])\nprint(result[\"status\"])\n```\n\n### Poll explicitly and fail on non-success\n\nEmail sending is a long-running operation. Poll the returned operation instead of assuming the request succeeded when `begin_send(...)` returned.\n\n```python\nfrom azure.communication.email import EmailClient\nfrom azure.core.exceptions import HttpResponseError\n\nPOLL_INTERVAL_SECONDS = 10\nPOLL_TIMEOUT_SECONDS = 180\n\ndef wait_for_send(email_client: EmailClient, message: dict) -> dict:\n    poller = email_client.begin_send(message)\n    elapsed = 0\n\n    while not poller.done():\n        print(f\"poller status: {poller.status()}\")\n        poller.wait(POLL_INTERVAL_SECONDS)\n        elapsed += POLL_INTERVAL_SECONDS\n\n        if elapsed > POLL_TIMEOUT_SECONDS:\n            raise TimeoutError(\"Timed out waiting for Azure email send operation\")\n\n    result = poller.result()\n    if result[\"status\"] != \"Succeeded\":\n        raise RuntimeError(str(result.get(\"error\")))\n\n    return result\n\ntry:\n    send_result = wait_for_send(client, message)\n    print(f\"operation id: {send_result['id']}\")\nexcept HttpResponseError as exc:\n    print(exc)\n    raise\n```\n\nDocumented operation states include `Running`, `Succeeded`, and `Failed`.\n\n`Succeeded` means Azure accepted the send and handed it off for delivery. It does not guarantee inbox delivery, opens, or bounce handling. For delivery telemetry, use Azure Monitor or Event Grid.\n\n### Recipients, reply-to, and headers\n\nAt least one recipient must be present in `to`, `cc`, or `bcc`.\n\n```python\nmessage = {\n    \"senderAddress\": \"sender@example.com\",\n    \"recipients\": {\n        \"to\": [\n            {\"address\": \"to1@example.com\"},\n            {\"address\": \"to2@example.com\"},\n        ],\n        \"cc\": [\n            {\"address\": \"cc1@example.com\"},\n        ],\n        \"bcc\": [\n            {\"address\": \"bcc1@example.com\"},\n        ],\n    },\n    \"content\": {\n        \"subject\": \"Status update\",\n        \"plainText\": \"Sent to multiple recipients.\",\n    },\n    \"replyTo\": [\n        {\"address\": \"replies@example.com\", \"displayName\": \"Support\"},\n    ],\n    \"headers\": {\n        \"x-priority\": \"1\",\n    },\n}\n```\n\n### File attachments\n\nAttachments must be base64-encoded and must declare the correct MIME type.\n\n```python\nimport base64\nfrom pathlib import Path\n\nattachment_bytes = Path(\"report.pdf\").read_bytes()\nattachment_b64 = base64.b64encode(attachment_bytes).decode(\"ascii\")\n\nmessage = {\n    \"senderAddress\": \"sender@example.com\",\n    \"recipients\": {\n        \"to\": [{\"address\": \"recipient@example.com\"}],\n    },\n    \"content\": {\n        \"subject\": \"Monthly report\",\n        \"plainText\": \"Attached is the latest report.\",\n    },\n    \"attachments\": [\n        {\n            \"name\": \"report.pdf\",\n            \"contentType\": \"application/pdf\",\n            \"contentInBase64\": attachment_b64,\n        }\n    ],\n}\n```\n\n### Inline attachments\n\n`1.1.0` adds `contentId`, which lets the HTML body reference an attachment via `cid:...`.\n\n```python\nimport base64\nfrom pathlib import Path\n\nimage_b64 = base64.b64encode(Path(\"logo.png\").read_bytes()).decode(\"ascii\")\n\nmessage = {\n    \"senderAddress\": \"sender@example.com\",\n    \"recipients\": {\n        \"to\": [{\"address\": \"recipient@example.com\"}],\n    },\n    \"content\": {\n        \"subject\": \"Inline image example\",\n        \"html\": '<html><body><img src=\"cid:company-logo\" /></body></html>',\n        \"plainText\": \"See the inline image in the HTML version.\",\n    },\n    \"attachments\": [\n        {\n            \"name\": \"logo.png\",\n            \"contentType\": \"image/png\",\n            \"contentInBase64\": image_b64,\n            \"contentId\": \"company-logo\",\n        }\n    ],\n}\n```\n\n### Caller-supplied operation IDs\n\n`1.1.0` also adds the optional `operation_id=` keyword on `begin_send(...)`.\n\n```python\npoller = client.begin_send(message, operation_id=\"signup-welcome-email-0001\")\nresult = poller.result()\n```\n\nUse this when you need a stable caller-side identifier for the long-running send request.\n\n## Configuration Notes\n\n- `AZURE_COMMUNICATION_CONNECTION_STRING` in these examples is a project convention, not an SDK requirement.\n- `AZURE_COMMUNICATION_SERVICE_ENDPOINT` is required when using `DefaultAzureCredential` or `AzureKeyCredential`.\n- Keep `senderAddress` in configuration; do not hardcode temporary example addresses into production code.\n- The client exposes an `api_version` keyword argument, but the reference warns that overriding the default can lead to unsupported behavior.\n\n## Common Pitfalls\n\n- Use `begin_send(...)`, not `send(...)`. The PyPI troubleshooting text still shows `client.send(message)`, but the documented client API is `begin_send(...)`.\n- Do not treat `poller.result()[\"status\"] == \"Succeeded\"` as proof of final mailbox delivery.\n- Make sure at least one of `to`, `cc`, or `bcc` is populated.\n- Use the linked domain's `MailFrom` sender address, not an arbitrary email string.\n- Base64-encode attachment bytes and set `contentType` correctly.\n- If you use inline images, the HTML `cid:` value must match the attachment `contentId`.\n- The request payload is a nested dict, not a generated model object.\n\n## Version-Sensitive Notes For `1.1.0`\n\n- `contentId` on attachments is available in `1.1.0` and later.\n- `operation_id` on `EmailClient.begin_send(...)` is available in `1.1.0` and later.\n- The quickstart's Python-version prerequisite is stale relative to the `1.1.0` PyPI metadata.\n\n## Official Sources\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/communication-email-readme?view=azure-python`\n- Microsoft Learn API index: `https://learn.microsoft.com/en-us/python/api/azure-communication-email/`\n- Microsoft Learn `EmailClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-communication-email/azure.communication.email.emailclient?view=azure-python`\n- Microsoft Learn send-email quickstart: `https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/email/send-email`\n- PyPI package page: `https://pypi.org/project/azure-communication-email/`\n"
  },
  {
    "path": "content/azure/docs/communication-sms/javascript/DOC.md",
    "content": "---\nname: communication-sms\ndescription: \"Azure Communication Services SMS SDK for JavaScript with connection string or Azure Identity auth, message sending, delivery reports, and per-recipient results\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.2.0-beta.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,communication-services,sms,javascript,messaging\"\n---\n\n# Azure Communication Services SMS SDK For JavaScript\n\n## Golden Rule\n\nUse `@azure/communication-sms` from trusted server-side code, create one shared `SmsClient` for your Azure Communication Services resource, send SMS with E.164 phone numbers, and inspect every returned `SmsSendResult` because one recipient can fail even when others succeed.\n\n## Install\n\n```bash\nnpm install @azure/communication-sms@1.2.0-beta.4\n```\n\nIf you want Microsoft Entra ID authentication instead of a connection string, install `@azure/identity` too:\n\n```bash\nnpm install @azure/communication-sms@1.2.0-beta.4 @azure/identity\n```\n\n## Prerequisites\n\nBefore you send SMS, make sure you already have:\n\n1. An Azure Communication Services resource.\n2. A configured SMS-capable sender for that resource.\n3. At least one destination phone number for testing.\n4. Either the ACS connection string or the ACS endpoint plus an Azure credential flow.\n\nUse E.164 formatting for phone numbers, for example `+14255550123`.\n\n## Configuration\n\nThe SDK does not require specific environment variable names. These examples use:\n\n```bash\nexport ACS_CONNECTION_STRING=\"endpoint=https://<resource>.communication.azure.com/;accesskey=<key>\"\nexport ACS_ENDPOINT=\"https://<resource>.communication.azure.com\"\nexport ACS_SMS_FROM=\"+14255550123\"\nexport ACS_SMS_TO=\"+14255550124\"\n```\n\nIf you use `DefaultAzureCredential`, provide the usual Azure Identity environment variables or run in an environment with managed identity:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\n## Authentication And Client Setup\n\n### Connection String\n\nFor backend scripts and services, the connection string constructor is the shortest path:\n\n```js\nimport { SmsClient } from \"@azure/communication-sms\";\n\nconst connectionString = process.env.ACS_CONNECTION_STRING;\n\nif (!connectionString) {\n  throw new Error(\"Set ACS_CONNECTION_STRING before creating the SMS client.\");\n}\n\nconst smsClient = new SmsClient(connectionString);\n```\n\n### Azure Identity\n\nUse the endpoint constructor when your app already uses service principals, workload identity, or managed identity:\n\n```js\nimport { SmsClient } from \"@azure/communication-sms\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.ACS_ENDPOINT;\n\nif (!endpoint) {\n  throw new Error(\"Set ACS_ENDPOINT before creating the SMS client.\");\n}\n\nconst smsClient = new SmsClient(endpoint, new DefaultAzureCredential());\n```\n\n## Client Initialization\n\nCreate one shared client and reuse it for SMS operations instead of constructing a new client for every send:\n\n```js\nimport { SmsClient } from \"@azure/communication-sms\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nexport function createSmsClient() {\n  if (process.env.ACS_CONNECTION_STRING) {\n    return new SmsClient(process.env.ACS_CONNECTION_STRING);\n  }\n\n  if (process.env.ACS_ENDPOINT) {\n    return new SmsClient(process.env.ACS_ENDPOINT, new DefaultAzureCredential());\n  }\n\n  throw new Error(\n    \"Set ACS_CONNECTION_STRING or ACS_ENDPOINT before creating the SMS client.\",\n  );\n}\n```\n\n## Core Usage\n\n### Send One Message\n\n`send(...)` returns an array with one `SmsSendResult` per recipient, even if you send to only one number.\n\n```js\nimport { SmsClient } from \"@azure/communication-sms\";\n\nconst smsClient = new SmsClient(process.env.ACS_CONNECTION_STRING);\n\nconst results = await smsClient.send({\n  from: process.env.ACS_SMS_FROM,\n  to: [process.env.ACS_SMS_TO],\n  message: \"Hello from Azure Communication Services\",\n  enableDeliveryReport: true,\n  tag: \"chub-sample\",\n});\n\nconst result = results[0];\n\nconsole.log(result.to);\nconsole.log(result.successful);\nconsole.log(result.messageId);\nconsole.log(result.httpStatusCode);\nconsole.log(result.errorMessage);\n```\n\n### Send To Multiple Recipients\n\n```js\nconst results = await smsClient.send({\n  from: process.env.ACS_SMS_FROM,\n  to: [\"+14255550124\", \"+14255550125\"],\n  message: \"Deployment finished successfully.\",\n  enableDeliveryReport: true,\n  tag: \"deploy-status\",\n});\n\nfor (const item of results) {\n  console.log(item.to, item.successful, item.httpStatusCode, item.errorMessage);\n}\n```\n\n### Fail Fast When Any Recipient Fails\n\n```js\nconst failed = results.filter((item) => !item.successful);\n\nif (failed.length > 0) {\n  throw new Error(\n    `SMS send failed for: ${failed.map((item) => item.to).join(\", \")}`,\n  );\n}\n```\n\n## Delivery Reports And Tags\n\nThe maintainer quickstart documents two useful optional send fields:\n\n- `enableDeliveryReport: true` requests delivery reporting.\n- `tag: \"...\"` attaches metadata that comes back with the delivery report.\n\nIf you need downstream status tracking, persist the returned `messageId` values and use a stable `tag` for correlation.\n\n## Minimal Script\n\nThis is a complete script you can drop into a Node app to verify configuration and send one SMS:\n\n```js\nimport { SmsClient } from \"@azure/communication-sms\";\n\nconst connectionString = process.env.ACS_CONNECTION_STRING;\nconst from = process.env.ACS_SMS_FROM;\nconst to = process.env.ACS_SMS_TO;\n\nif (!connectionString || !from || !to) {\n  throw new Error(\n    \"Set ACS_CONNECTION_STRING, ACS_SMS_FROM, and ACS_SMS_TO before sending SMS.\",\n  );\n}\n\nconst client = new SmsClient(connectionString);\nconst results = await client.send({\n  from,\n  to: [to],\n  message: \"Hello from Azure Communication Services SMS\",\n  enableDeliveryReport: true,\n  tag: \"quickstart\",\n});\n\nfor (const result of results) {\n  if (result.successful) {\n    console.log(`Sent to ${result.to}: ${result.messageId}`);\n  } else {\n    console.error(\n      `Failed for ${result.to}: ${result.httpStatusCode} ${result.errorMessage}`,\n    );\n  }\n}\n```\n\n## Common Pitfalls\n\n### Keep Numbers In E.164 Format\n\nNormalize both sender and recipient numbers before calling `send(...)`.\n\n### Handle Results Per Recipient\n\nThe promise resolving does not mean every recipient succeeded. Always inspect every returned `SmsSendResult`.\n\n### Do Not Mix Authentication Flows\n\n- `new SmsClient(connectionString)` expects the full ACS connection string.\n- `new SmsClient(endpoint, credential)` expects the ACS endpoint plus a credential object.\n\nDo not pass a connection string where the endpoint constructor expects a URL.\n\n### `@azure/identity` Is Separate\n\n`DefaultAzureCredential` is not bundled into `@azure/communication-sms`. Install `@azure/identity` explicitly when you use Microsoft Entra ID auth.\n\n### Keep Secrets Out Of Client Apps\n\nIf you use a connection string, keep it on a trusted backend or worker process rather than shipping it to browsers or other untrusted clients.\n\n## Version Notes For `1.2.0-beta.4`\n\n- This guide targets `@azure/communication-sms` `1.2.0-beta.4`.\n- If you upgrade to a newer release, confirm constructor overloads, send options, and result fields against the current maintainer README and API reference.\n\n## Official Sources\n\n- Microsoft Learn JavaScript package namespace: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-sms/`\n- Microsoft Learn JavaScript package overview: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/communication-sms-readme?view=azure-node-latest`\n- Microsoft Learn `SmsClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/communication-sms/smsclient?view=azure-node-latest`\n- Microsoft Learn SMS quickstart: `https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/sms/send`\n- npm package page: `https://www.npmjs.com/package/@azure/communication-sms`\n"
  },
  {
    "path": "content/azure/docs/communication-sms/python/DOC.md",
    "content": "---\nname: communication-sms\ndescription: \"azure-communication-sms for Python: send SMS with Azure Communication Services using connection strings or Azure Identity\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure communication services,sms,python,messaging\"\n---\n\n# azure-communication-sms Python Package Guide\n\n## What This Package Does\n\n`azure-communication-sms` is the Azure Communication Services SMS SDK for Python. Use it to create an `SmsClient`, send SMS to one or many recipients, and inspect one `SmsSendResult` per recipient.\n\nThe current official Microsoft Learn package overview and the current PyPI release both point to `1.1.0`, so this entry is aligned to that version.\n\n## Install\n\nInstall the package itself:\n\n```bash\npip install azure-communication-sms==1.1.0\n```\n\nIf you want Microsoft Entra ID authentication, install `azure-identity` too:\n\n```bash\npip install azure-communication-sms==1.1.0 azure-identity\n```\n\nPyPI currently lists `Requires: Python >=3.8` for `1.1.0`.\n\n## Prerequisites\n\nBefore writing code, make sure you have:\n\n- An Azure Communication Services resource\n- A sender configured for that resource\n- At least one destination phone number for testing\n- Either a connection string or an Azure credential path for the resource\n\nUse E.164 formatting for phone numbers such as `+14255550123`. The Microsoft quickstart also notes that `from_` can be a short code or an alphanumeric sender ID when your setup supports it.\n\n## Configuration\n\nThe SDK does not require any specific environment variable names. These examples use a simple convention:\n\n```bash\nexport ACS_CONNECTION_STRING='endpoint=https://<resource>.communication.azure.com/;accesskey=<key>'\nexport ACS_ENDPOINT='https://<resource>.communication.azure.com'\nexport ACS_SMS_FROM='+14255550123'\nexport ACS_SMS_TO='+14255550124'\n```\n\nIf you use `DefaultAzureCredential`, set the usual Azure Identity environment variables or run under managed identity:\n\n```bash\nexport AZURE_TENANT_ID='<tenant-id>'\nexport AZURE_CLIENT_ID='<client-id>'\nexport AZURE_CLIENT_SECRET='<client-secret>'\n```\n\n## Initialize The Client\n\n### Connection String\n\nThis is the shortest path and the one used by the official SMS quickstart.\n\n```python\nimport os\nfrom azure.communication.sms import SmsClient\n\nsms_client = SmsClient.from_connection_string(\n    os.environ[\"ACS_CONNECTION_STRING\"]\n)\n```\n\n### Azure Identity\n\nUse the endpoint constructor when your project already uses service principals, workload identity, or managed identity.\n\n```python\nimport os\nfrom azure.communication.sms import SmsClient\nfrom azure.identity import DefaultAzureCredential\n\nsms_client = SmsClient(\n    endpoint=os.environ[\"ACS_ENDPOINT\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\n## Core Usage\n\n### Send A Single Message\n\n`send()` returns a list of `SmsSendResult`, even when you send to one recipient.\n\n```python\nimport os\nfrom azure.communication.sms import SmsClient\n\nsms_client = SmsClient.from_connection_string(\n    os.environ[\"ACS_CONNECTION_STRING\"]\n)\n\nresults = sms_client.send(\n    from_=os.environ[\"ACS_SMS_FROM\"],\n    to=[os.environ[\"ACS_SMS_TO\"]],\n    message=\"Hello from Azure Communication Services\",\n    enable_delivery_report=True,\n    tag=\"chub-sample\",\n)\n\nresult = results[0]\nprint(result.to)\nprint(result.successful)\nprint(result.message_id)\nprint(result.http_status_code)\nprint(result.error_message)\n```\n\n### Send To Multiple Recipients\n\n```python\nresults = sms_client.send(\n    from_=os.environ[\"ACS_SMS_FROM\"],\n    to=[\n        \"+14255550124\",\n        \"+14255550125\",\n    ],\n    message=\"Deployment finished successfully.\",\n    enable_delivery_report=True,\n    tag=\"deploy-status\",\n)\n\nfor item in results:\n    print(item.to, item.successful, item.http_status_code, item.error_message)\n```\n\n### Async Client\n\nThe package also exposes an async client in `azure.communication.sms.aio`.\n\n```python\nimport os\nfrom azure.communication.sms.aio import SmsClient\n\nasync def send_sms() -> None:\n    client = SmsClient.from_connection_string(\n        os.environ[\"ACS_CONNECTION_STRING\"]\n    )\n    try:\n        results = await client.send(\n            from_=os.environ[\"ACS_SMS_FROM\"],\n            to=[os.environ[\"ACS_SMS_TO\"]],\n            message=\"Async hello\",\n        )\n        print(results[0].successful)\n    finally:\n        await client.close()\n```\n\n## Response Handling\n\nTreat every `SmsSendResult` independently:\n\n- `to` is the recipient that this result applies to\n- `successful` tells you whether that recipient was processed successfully\n- `message_id` is present only when the message was processed\n- `http_status_code` is the per-recipient status code\n- `error_message` is set for failed or repeatable-error cases\n\nA minimal failure check:\n\n```python\nfailed = [item for item in results if not item.successful]\nif failed:\n    raise RuntimeError(\n        \"SMS send failed for: \" + \", \".join(item.to for item in failed)\n    )\n```\n\n## Delivery Reports And Tags\n\nThe quickstart documents two optional `send()` parameters that are easy to miss:\n\n- `enable_delivery_report=True` requests delivery reporting on Azure Resource EventGrid\n- `tag=\"...\"` attaches metadata that is sent back with the delivery report\n\nIf your workflow needs post-send delivery status, persist the `message_id` and keep the tag stable enough to correlate downstream events.\n\n## Common Pitfalls\n\n### `from_` Has An Underscore\n\nThe parameter name is `from_`, not `from`, because `from` is a Python keyword.\n\n### Keep Numbers In E.164 Format\n\nBad formatting is a common cause of failures. Normalize inputs before calling `send()`.\n\n### Do Not Mix Auth Flows\n\n- `SmsClient.from_connection_string(...)` expects the full Communication Services connection string\n- `SmsClient(endpoint, credential)` expects the resource endpoint plus a credential object\n\nDo not pass a connection string into the endpoint constructor.\n\n### `azure-identity` Is Separate\n\n`DefaultAzureCredential` is not bundled into `azure-communication-sms`. Install `azure-identity` explicitly if you use Entra ID auth.\n\n### Handle Results Per Recipient\n\n`send()` returning successfully does not mean every recipient succeeded. Always inspect the returned list.\n\n## Version-Sensitive Notes\n\n### Current Upstream Version Alignment\n\n- Version used here: `1.1.0`\n- Microsoft Learn package overview currently shows version `1.1.0`\n- PyPI currently lists latest release `1.1.0` released on October 3, 2024\n\nThis means the earlier version reference and the current upstream package line are aligned.\n\n### Python Version Mismatch Across Official Sources\n\nAs of March 12, 2026, the official sources still disagree slightly:\n\n- Microsoft Learn package overview says Python `3.7` or later\n- PyPI metadata says `Requires: Python >=3.8`\n\nFor new work pinned to `1.1.0`, prefer the stricter PyPI requirement and plan on Python `3.8+`.\n\n### Practical Source Choice\n\nThe docs URL points to the package API namespace root. That page is valid, but the Microsoft Learn overview README is the more useful starting point for install, setup, and example code. Use the class reference pages when you need exact constructor and return-type details.\n\n## Official Sources\n\n- Microsoft Learn package overview: https://learn.microsoft.com/en-us/python/api/overview/azure/communication-sms-readme?view=azure-python\n- Microsoft Learn package namespace root: https://learn.microsoft.com/en-us/python/api/azure-communication-sms/\n- Microsoft Learn `SmsClient` reference: https://learn.microsoft.com/en-us/python/api/azure-communication-sms/azure.communication.sms.smsclient?view=azure-python\n- Microsoft Learn `SmsSendResult` reference: https://learn.microsoft.com/en-us/python/api/azure-communication-sms/azure.communication.sms.smssendresult?view=azure-python\n- Microsoft Learn SMS quickstart: https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/sms/send\n- PyPI project page: https://pypi.org/project/azure-communication-sms/\n"
  },
  {
    "path": "content/azure/docs/container-registry/javascript/DOC.md",
    "content": "---\nname: container-registry\ndescription: \"Azure Container Registry JavaScript client for authenticating with Azure Identity and inspecting repositories, tags, and manifests\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.1.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,acr,container-registry,oci,javascript\"\n---\n\n# Azure Container Registry JavaScript Client\n\n## Golden Rule\n\nUse `@azure/container-registry` for data-plane access to an existing Azure Container Registry: list repositories, inspect tags and manifests, and work with repository-scoped clients. Do not use it to create registries or manage Azure Resource Manager settings such as SKU, networking, or private endpoints.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @azure/container-registry@1.1.2\n```\n\nIf you authenticate with Microsoft Entra ID through `DefaultAzureCredential`, install `@azure/identity` too:\n\n```bash\nnpm install @azure/container-registry@1.1.2 @azure/identity\n```\n\n## Authentication And Setup\n\nUse the registry login server URL as the endpoint:\n\n```bash\nexport AZURE_CONTAINER_REGISTRY_ENDPOINT=\"https://<registry-name>.azurecr.io\"\n```\n\nFor non-interactive authentication with `DefaultAzureCredential`, set the standard Azure service principal environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nFor local development, `az login` is usually enough for `DefaultAzureCredential` to work without setting all three service principal variables.\n\n### Client Initialization\n\n```js\nimport { ContainerRegistryClient } from \"@azure/container-registry\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.AZURE_CONTAINER_REGISTRY_ENDPOINT;\n\nif (!endpoint) {\n  throw new Error(\"Missing AZURE_CONTAINER_REGISTRY_ENDPOINT\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new ContainerRegistryClient(endpoint, credential);\n```\n\nCreate one shared client for your registry work instead of constructing a new client for every operation.\n\n## Core Usage\n\n### List repositories\n\n`listRepositoryNames()` returns an async iterable:\n\n```js\nfor await (const repositoryName of client.listRepositoryNames()) {\n  console.log(repositoryName);\n}\n```\n\n### Get a repository client\n\nRepository names are registry-local names such as `hello-world` or `library/hello-world`, not full image references.\n\n```js\nconst repository = client.getRepository(\"hello-world\");\n```\n\n### List tags in a repository\n\n```js\nconst repository = client.getRepository(\"hello-world\");\n\nfor await (const tag of repository.listTagProperties()) {\n  console.log(tag.name, tag.digest);\n}\n```\n\n### List manifests in a repository\n\n```js\nconst repository = client.getRepository(\"hello-world\");\n\nfor await (const manifest of repository.listManifestProperties()) {\n  console.log(manifest.digest, manifest.tags);\n}\n```\n\n### Read one tag\n\n```js\nconst repository = client.getRepository(\"hello-world\");\nconst tag = repository.getTag(\"latest\");\n\nconst properties = await tag.getProperties();\n\nconsole.log(properties.name, properties.digest);\n```\n\n## Minimal Script\n\nThis is a complete script you can drop into a Node app to verify auth and inspect one repository:\n\n```js\nimport { ContainerRegistryClient } from \"@azure/container-registry\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.AZURE_CONTAINER_REGISTRY_ENDPOINT;\nconst repositoryName = process.env.AZURE_CONTAINER_REPOSITORY ?? \"hello-world\";\n\nif (!endpoint) {\n  throw new Error(\"Missing AZURE_CONTAINER_REGISTRY_ENDPOINT\");\n}\n\nconst client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());\nconst repository = client.getRepository(repositoryName);\n\nfor await (const tag of repository.listTagProperties()) {\n  console.log(`${repositoryName}:${tag.name} -> ${tag.digest}`);\n}\n```\n\n## Configuration Notes\n\n- Pass only the registry login server as the endpoint, for example `https://myregistry.azurecr.io`.\n- Keep the repository name separate from the endpoint; pass it later to `getRepository(...)`.\n- Use `for await ... of` for repository, tag, and manifest listing methods.\n- Reuse a single `ContainerRegistryClient` in long-lived processes.\n- Install `@azure/identity` when you use `DefaultAzureCredential`.\n\n## Common Pitfalls\n\n- Using `@azure/container-registry` for Azure management operations. This package is for registry content access, not ARM provisioning.\n- Passing a portal URL or a full image reference where the client expects the registry endpoint.\n- Passing `myregistry.azurecr.io/hello-world:latest` as the endpoint instead of `https://myregistry.azurecr.io`.\n- Treating a tag like `latest` and a manifest digest like `sha256:...` as interchangeable identifiers.\n- Forgetting that list operations are async iterables and trying to use them like plain arrays.\n\n## Version Notes For 1.1.2\n\n- This guide targets `@azure/container-registry` `1.1.2`.\n- If you are on a newer release, keep the endpoint and authentication patterns the same, but confirm any additional helpers or option names against the current maintainer README and API reference.\n\n## Official Sources\n\n- Maintainer README: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/containerregistry/container-registry/README.md`\n- Microsoft Learn quickstart: `https://learn.microsoft.com/en-us/azure/container-registry/quickstart-client-libraries`\n- Microsoft Learn overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/container-registry-readme?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/container-registry`\n"
  },
  {
    "path": "content/azure/docs/containerregistry/python/DOC.md",
    "content": "---\nname: containerregistry\ndescription: \"Azure Container Registry client library for Python: authenticate, inspect repositories, tags, manifests, and blobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,acr,container-registry,oci,artifacts,python\"\n---\n\n# azure-containerregistry Python Package Guide\n\n## Golden Rule\n\nUse `azure-containerregistry` for Azure Container Registry data-plane work in Python: browse repositories, inspect tags and manifests, download blobs, and manage artifact metadata. Do not use it to create or configure registries in Azure Resource Manager.\n\n## Installation\n\nPin to the package version you are targeting:\n\n```bash\npython -m pip install \"azure-containerregistry==1.2.0\"\n```\n\nFor Azure AD authentication with `DefaultAzureCredential`, install `azure-identity` too:\n\n```bash\npython -m pip install \"azure-containerregistry==1.2.0\" \"azure-identity>=1.12.0\"\n```\n\nPyPI metadata for `1.2.0` lists Python `>=3.7`. Microsoft Learn's current quickstart says Python `3.8+`; treat that as current-sample guidance rather than a version-pinned rule for `1.2.0`.\n\n## Authentication And Setup\n\nUse the registry login server URL, not a portal URL and not an image reference:\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]  # https://<registry>.azurecr.io\ncredential = DefaultAzureCredential()\n\nwith ContainerRegistryClient(account_url, credential) as client:\n    for repository in client.list_repository_names():\n        print(repository)\n```\n\nLocal development usually works with `az login` plus `DefaultAzureCredential`. For non-interactive use, set the standard service principal environment variables:\n\n- `AZURE_CLIENT_ID`\n- `AZURE_TENANT_ID`\n- `AZURE_CLIENT_SECRET`\n- `CONTAINERREGISTRY_ENDPOINT`\n\n### Anonymous Access\n\nThe client constructor allows `credential=None` for anonymous pulls. That only works when the registry and repository are configured for anonymous access.\n\n```python\nfrom azure.containerregistry import ContainerRegistryClient\n\naccount_url = \"https://myregistry.azurecr.io\"\n\nwith ContainerRegistryClient(account_url, credential=None) as client:\n    for tag in client.list_tag_properties(\"library/hello-world\"):\n        print(tag.name, tag.digest)\n```\n\n## Core Usage\n\n### List Repositories\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    for repository in client.list_repository_names():\n        print(repository)\n```\n\n### Inspect Repository Properties\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\nrepository = \"hello-world\"\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    props = client.get_repository_properties(repository)\n    print(props.name, props.tag_count, props.manifest_count)\n```\n\n### List Tags\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\nrepository = \"hello-world\"\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    for tag in client.list_tag_properties(repository):\n        print(tag.name, tag.digest, tag.last_updated_on)\n```\n\n### List Manifests\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\nrepository = \"hello-world\"\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    for manifest in client.list_manifest_properties(repository):\n        print(manifest.digest, manifest.tags, manifest.last_updated_on)\n```\n\n### Read A Specific Tag\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    tag = client.get_tag_properties(\"hello-world\", \"latest\")\n    print(tag.name, tag.digest, tag.created_on)\n```\n\n### Download A Blob\n\nUse blob digests when pulling layer or config content.\n\n```python\nimport os\n\nfrom azure.containerregistry import ContainerRegistryClient\nfrom azure.identity import DefaultAzureCredential\n\naccount_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\nrepository = \"hello-world\"\ndigest = \"sha256:...\"\n\nwith ContainerRegistryClient(account_url, DefaultAzureCredential()) as client:\n    stream = client.download_blob(repository, digest)\n    with open(\"blob.bin\", \"wb\") as fh:\n        for chunk in stream.chunks():\n            fh.write(chunk)\n```\n\n## Async Usage\n\nThe async client lives under `azure.containerregistry.aio`. Close the async credential explicitly.\n\n```python\nimport asyncio\nimport os\n\nfrom azure.containerregistry.aio import ContainerRegistryClient\nfrom azure.identity.aio import DefaultAzureCredential\n\nasync def main() -> None:\n    account_url = os.environ[\"CONTAINERREGISTRY_ENDPOINT\"]\n    credential = DefaultAzureCredential()\n\n    try:\n        async with ContainerRegistryClient(account_url, credential) as client:\n            async for repository in client.list_repository_names():\n                print(repository)\n    finally:\n        await credential.close()\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n- The constructor default `audience` is `https://containerregistry.azure.net`.\n- The current class reference also documents alternate audiences for Azure public management, China cloud, and US Gov cloud.\n- The current default service API version in the class reference is `2021-07-01`.\n- Client and per-call kwargs support the usual Azure SDK pipeline options such as transport and logging.\n\nStart with the default audience unless you have a sovereign-cloud or token-audience requirement. This is an inference from the official sources because some Microsoft samples override `audience` while the class reference documents a different default.\n\n## Write And Delete Operations\n\nThe package supports upload and mutation flows too, including:\n\n- `upload_blob`\n- `set_manifest`\n- `update_manifest_properties`\n- `update_tag_properties`\n- `update_repository_properties`\n- `delete_manifest`\n- `delete_tag`\n- `delete_blob`\n- `delete_repository`\n\nCheck the exact signature in the current API reference before copying mutation examples. Microsoft Learn currently mixes quickstart snippets that pass permission flags directly with API reference signatures that use property objects such as `ArtifactManifestProperties` and `ArtifactTagProperties`.\n\n## Common Pitfalls\n\n- `azure-containerregistry` is a data-plane SDK, not the Azure management SDK. Use `azure-mgmt-containerregistry` for registry provisioning and ARM operations.\n- The endpoint must be the registry login server with `https://`, for example `https://myregistry.azurecr.io`.\n- A repository name like `hello-world` and an image reference like `myregistry.azurecr.io/hello-world:latest` are not interchangeable inputs.\n- `DefaultAzureCredential` comes from `azure-identity`; installing only `azure-containerregistry` is not enough for AAD auth.\n- Anonymous access is opt-in at the registry or repository level. `credential=None` is not a fallback for private registries.\n- `download_blob` and manifest retrieval workflows are digest-based. Keep tag names and digests separate in your code.\n- The class reference documents that `delete_repository` does not raise on `404`, so successful deletion does not prove the repository existed.\n- The class reference documents digest validation and response-size edge cases around manifest retrieval. If you are reading large manifests or verifying digests, handle those exceptions explicitly.\n\n## Version-Sensitive Notes\n\n- The version used here and current PyPI latest version both point to `1.2.0`, so this entry is aligned to the package release you asked for.\n- The current Microsoft Learn quickstart still imports `ManifestOrder` and shows mutation helpers with direct permission kwargs.\n- The current Microsoft Learn API reference documents `ArtifactManifestOrder` and property-object-based mutation signatures.\n- The PyPI project page for `1.2.0` still links its API reference to an older `1.0.0b1` Azure SDK docs URL.\n\nPractical rule: if a Microsoft sample and the API reference disagree, trust the API reference for exact symbol names and signatures, then verify against your installed package in a REPL before writing production code.\n\n## Official Sources\n\n- Microsoft Learn package reference: https://learn.microsoft.com/en-us/python/api/azure-containerregistry/?view=azure-python\n- Microsoft Learn `ContainerRegistryClient` reference: https://learn.microsoft.com/en-us/python/api/azure-containerregistry/azure.containerregistry.containerregistryclient?view=azure-python\n- Microsoft Learn quickstart and samples: https://learn.microsoft.com/en-us/azure/container-registry/quickstart-client-libraries\n- PyPI project page: https://pypi.org/project/azure-containerregistry/\n- PyPI release page for `1.2.0`: https://pypi.org/project/azure-containerregistry/1.2.0/\n"
  },
  {
    "path": "content/azure/docs/core/python/DOC.md",
    "content": "---\nname: core\ndescription: \"azure-core package guide for Python - shared pipeline, credentials, retries, transports, and errors for Azure SDK clients\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.38.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-core,python,azure-sdk,pipeline,credentials,retries,http\"\n---\n\n# azure-core Python Package Guide\n\n## What This Package Is For\n\n`azure-core` is the shared runtime layer used by Azure SDK client libraries. It provides:\n\n- sync and async pipeline clients\n- HTTP request and response types\n- credential protocols and auth policies\n- retries, redirects, logging, tracing, and transport abstractions\n- shared exception types\n\nIn most application code, you do not install or import `azure-core` directly. You usually install a service package such as `azure-storage-blob`, `azure-keyvault-secrets`, or `azure-mgmt-resource`, and that package brings in `azure-core`.\n\nUse `azure-core` directly when you need one of these:\n\n- a custom client for an Azure REST API that does not already have a generated SDK\n- a custom pipeline policy or transport setting\n- shared retry, logging, or auth behavior across multiple Azure SDK clients\n- direct handling of Azure SDK exception types\n\n## Install And Environment\n\nPyPI currently lists `azure-core` `1.38.2`, released on `2026-02-18`, with `Requires: Python >=3.9`.\n\nInstall the exact version you want to target:\n\n```bash\npip install azure-core==1.38.2\n```\n\nCommon alternatives:\n\n```bash\npoetry add azure-core==1.38.2\nuv add azure-core==1.38.2\n```\n\nInstall companion packages only when you need them:\n\n```bash\npip install azure-identity\npip install aiohttp\npip install \"azure-core[tracing]\"\n```\n\nUse them for:\n\n- `azure-identity`: Entra ID credentials such as `DefaultAzureCredential`\n- `aiohttp`: async transport for `AsyncPipelineClient`\n- `azure-core[tracing]`: optional OpenTelemetry dependency for native tracing\n\n## Minimal Direct Usage\n\nThe main low-level surface is `PipelineClient` plus `HttpRequest`.\n\n```python\nfrom azure.core import PipelineClient\nfrom azure.core.rest import HttpRequest\n\nclient = PipelineClient(base_url=\"https://management.azure.com\")\n\nrequest = HttpRequest(\n    \"GET\",\n    \"/subscriptions\",\n    params={\"api-version\": \"2022-12-01\"},\n    headers={\"Accept\": \"application/json\"},\n)\n\nresponse = client.send_request(request)\nresponse.raise_for_status()\npayload = response.json()\nprint(payload)\n```\n\nPractical notes:\n\n- `base_url` can be a service root; request URLs can be relative or absolute.\n- `send_request()` returns a response object and does not do non-2xx error handling for you.\n- Call `response.raise_for_status()` yourself or catch `HttpResponseError`.\n- Prefer a service-specific SDK when one exists. Direct `PipelineClient` usage is for low-level or custom scenarios.\n\n## Authentication And Credentials\n\n### Recommended Azure Auth Pattern\n\nMicrosoft recommends token-based authentication through Microsoft Entra ID over connection strings or shared keys. In app code, that usually means `DefaultAzureCredential` from `azure-identity`.\n\n```python\nfrom azure.core import PipelineClient\nfrom azure.core.pipeline.policies import BearerTokenCredentialPolicy, RetryPolicy\nfrom azure.core.rest import HttpRequest\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\n\nclient = PipelineClient(\n    base_url=\"https://management.azure.com\",\n    policies=[\n        BearerTokenCredentialPolicy(\n            credential,\n            \"https://management.azure.com/.default\",\n        ),\n        RetryPolicy(retry_total=5, retry_backoff_factor=0.8),\n    ],\n)\n\nrequest = HttpRequest(\n    \"GET\",\n    \"/subscriptions\",\n    params={\"api-version\": \"2022-12-01\"},\n)\n\nresponse = client.send_request(request)\nresponse.raise_for_status()\n```\n\nUse the scope required by the target service. Management-plane clients commonly use `https://management.azure.com/.default`; data-plane services usually use a different audience.\n\nFor deployment:\n\n- on Azure, prefer managed identity\n- in local development, use developer credentials or a service principal\n- avoid hard-coded secrets and connection strings when Entra ID is supported\n\n### AzureKeyCredential And Rotating Keys\n\n`AzureKeyCredential`, `AzureNamedKeyCredential`, and `AzureSasCredential` are credential containers. They are useful because you can rotate them without recreating a long-lived client, but raw `PipelineClient` does not automatically know how to apply them to requests.\n\nExample with a custom API-key policy:\n\n```python\nfrom azure.core import PipelineClient\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.core.pipeline.policies import SansIOHTTPPolicy\nfrom azure.core.rest import HttpRequest\n\nclass ApiKeyPolicy(SansIOHTTPPolicy):\n    def __init__(self, credential: AzureKeyCredential):\n        self._credential = credential\n\n    def on_request(self, request):\n        request.http_request.headers[\"x-api-key\"] = self._credential.key\n\ncredential = AzureKeyCredential(\"initial-key\")\nclient = PipelineClient(\n    base_url=\"https://example.contoso.com\",\n    per_call_policies=[ApiKeyPolicy(credential)],\n)\n\nrequest = HttpRequest(\"GET\", \"/widgets\")\nresponse = client.send_request(request)\nresponse.raise_for_status()\n\n# Rotate the key without recreating the credential object.\ncredential.update(\"rotated-key\")\n```\n\nIf you are using a service-specific SDK client, prefer its documented `credential=` parameter instead of manually wiring a policy.\n\n## Async Usage\n\nUse `AsyncPipelineClient` for low-level async calls. If you do not pass a transport, `AioHttpTransport` is used for asynchronous transport, so `aiohttp` must be installed.\n\n```python\nimport asyncio\n\nfrom azure.core import AsyncPipelineClient\nfrom azure.core.rest import HttpRequest\n\nasync def main():\n    async with AsyncPipelineClient(\n        base_url=\"https://management.azure.com\"\n    ) as client:\n        request = HttpRequest(\n            \"GET\",\n            \"/subscriptions\",\n            params={\"api-version\": \"2022-12-01\"},\n        )\n        response = await client.send_request(request)\n        response.raise_for_status()\n        print(response.json())\n\nasyncio.run(main())\n```\n\nKeep sync and async stacks separate:\n\n- `PipelineClient` defaults to `RequestsTransport`\n- `AsyncPipelineClient` defaults to `AioHttpTransport`\n- do not mix async transports or async credentials into sync clients, or the reverse, unless the upstream policy docs explicitly allow it\n\n## Retry, Timeout, And Pipeline Configuration\n\n`PipelineClient` and service SDK clients expose the knobs agents most often need:\n\n- `retry_total`\n- `retry_connect`\n- `retry_read`\n- `retry_status`\n- `retry_backoff_factor`\n- `retry_backoff_max`\n- `retry_on_status_codes`\n- `timeout`\n- `connection_timeout`\n- `read_timeout`\n- `connection_verify`\n- `connection_cert`\n- `proxies`\n- `headers`\n- `logging_enable`\n\nCustom retry example:\n\n```python\nfrom azure.core import PipelineClient\nfrom azure.core.pipeline.policies import RetryPolicy\n\nretry_policy = RetryPolicy(\n    retry_total=5,\n    retry_connect=2,\n    retry_read=2,\n    retry_status=3,\n    retry_backoff_factor=0.5,\n    retry_backoff_max=30,\n    retry_on_status_codes=[408, 429, 500, 502, 503, 504],\n)\n\nclient = PipelineClient(\n    base_url=\"https://example.contoso.com\",\n    policies=[retry_policy],\n    connection_timeout=10,\n    read_timeout=30,\n)\n```\n\nPractical guidance:\n\n- use default retry behavior unless you have a concrete reason to change it\n- `retry_read` can repeat requests that already reached the service, so be careful with non-idempotent operations\n- retries add latency; keep them tighter for interactive paths than for background jobs\n- if you need a custom policy before retries, use `per_call_policies`\n- if you need a custom policy after retries, use `per_retry_policies`\n- reuse client instances so transports can pool connections\n\n## Logging And Diagnostics\n\nAzure SDK libraries use Python `logging`.\n\n```python\nimport logging\nimport sys\n\nazure_logger = logging.getLogger(\"azure\")\nazure_logger.setLevel(logging.DEBUG)\nazure_logger.addHandler(logging.StreamHandler(stream=sys.stdout))\n```\n\nUseful logger names:\n\n- `azure` for broad SDK diagnostics\n- `azure.core` for core pipeline behavior\n- `azure.identity` if token acquisition is relevant\n- `azure.core.pipeline.policies.http_logging_policy` for HTTP-level details\n\nBe careful with `logging_enable=True`: request and response metadata can be emitted to logs. Treat that output as sensitive.\n\n## Exceptions You Will Actually Catch\n\nMost application code should catch specific `azure.core.exceptions` types:\n\n```python\nfrom azure.core.exceptions import (\n    AzureError,\n    ClientAuthenticationError,\n    HttpResponseError,\n    ResourceExistsError,\n    ResourceNotFoundError,\n    ServiceRequestError,\n    ServiceResponseError,\n)\n\ntry:\n    response = client.send_request(request)\n    response.raise_for_status()\nexcept ClientAuthenticationError:\n    ...\nexcept ResourceNotFoundError:\n    ...\nexcept ResourceExistsError:\n    ...\nexcept HttpResponseError as exc:\n    if exc.status_code == 429:\n        ...\n    raise\nexcept (ServiceRequestError, ServiceResponseError):\n    ...\nexcept AzureError:\n    ...\n```\n\nWhat they usually mean:\n\n- `ServiceRequestError`: the request never reached the service\n- `ServiceResponseError`: the request was sent but the client could not process the response\n- `HttpResponseError`: the service returned a non-success status\n- `ClientAuthenticationError`: authentication failed\n\nOperational guidance:\n\n- do not retry `401`, `403`, or most `400` errors until you fix the request or permissions\n- `404` is usually not retryable unless the resource is expected to appear shortly\n- consider retrying `408`, `429`, `500`, `502`, `503`, and `504`\n- for support cases, capture `x-ms-request-id` from the response headers when available\n\n## Common Pitfalls\n\n- Do not assume `azure-core` is the main entry point for Azure services. Most application code should use the service package plus `azure-identity`.\n- `PipelineClient.send_request()` and `AsyncPipelineClient.send_request()` do not raise on non-2xx by themselves.\n- `AzureKeyCredential` is only a rotating secret holder. It does not inject headers into a raw `PipelineClient` unless you add a policy.\n- The Learn API pages are rolling current docs, not frozen historical snapshots. For exact behavior changes, check the PyPI release history and the package changelog.\n- Async transport support is opt-in. Install `aiohttp` before using `AsyncPipelineClient`.\n- Built-in retry guidance for service clients and low-level `azure-core` configuration docs are not always presented the same way. When retry behavior matters, inspect the client you are actually constructing instead of assuming all defaults are identical.\n- Be careful with streamed responses. Accessing content or streams in the wrong order can raise `ResponseNotReadError`, `StreamConsumedError`, or `StreamClosedError`.\n\n## Version-Sensitive Notes For 1.38.2\n\n- `1.38.2` fixes `PipelineClient.format_url()` so URL templates starting with `/?` preserve the leading slash.\n- `1.38.1` fixes another `PipelineClient.format_url()` edge case for query-only URL templates.\n- `1.38.0` changed continuation token format. Tokens generated by earlier `azure-core` versions are not compatible with `1.38.x`.\n- `1.35.1` fixed a bug where `retry_backoff_max` could be ignored in `RetryPolicy` and `AsyncRetryPolicy`. If you rely on custom max backoff limits, older examples may behave differently.\n- `1.34.0` dropped Python 3.8 support. Use Python 3.9+.\n- `1.33.0` added native OpenTelemetry tracing support and the optional `azure-core[tracing]` extra.\n\n## Official Context\n\n- Docs root: https://learn.microsoft.com/en-us/python/api/azure-core/\n- API overview: https://learn.microsoft.com/en-us/python/api/overview/azure/core-readme?view=azure-python\n- PipelineClient reference: https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.pipelineclient?view=azure-python\n- AsyncPipelineClient reference: https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.asyncpipelineclient?view=azure-python\n- AzureKeyCredential reference: https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.credentials.azurekeycredential?view=azure-python\n- Exceptions reference: https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions?view=azure-python\n- Azure authentication overview: https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview\n- Azure retry guidance: https://learn.microsoft.com/en-us/azure/developer/python/sdk/fundamentals/http-pipeline-retries\n- Azure error-handling guidance: https://learn.microsoft.com/en-us/azure/developer/python/sdk/fundamentals/errors\n- Package registry: https://pypi.org/project/azure-core/\n- Release history: https://pypi.org/project/azure-core/#history\n- Source changelog: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/CHANGELOG.md\n"
  },
  {
    "path": "content/azure/docs/core-auth/javascript/DOC.md",
    "content": "---\nname: core-auth\ndescription: \"@azure/core-auth JavaScript credential primitives for Azure SDK clients: token credentials, API keys, named keys, and SAS tokens\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.10.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,core-auth,javascript,credentials,authentication,tokens,keys,sas\"\n---\n\n# @azure/core-auth JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/core-auth` for the shared credential types and credential containers that Azure SDK clients accept. This package does not sign users in, fetch Microsoft Entra ID tokens by itself, or create service clients. For token acquisition, pair it with `@azure/identity`; for key-based auth, construct the credential objects from this package and pass them into the service SDK you are actually using.\n\n## Install\n\nInstall `@azure/core-auth` when your app or shared helper code needs the common Azure credential types directly:\n\n```bash\nnpm install @azure/core-auth@1.10.1\n```\n\nIn most real applications, you install it alongside a service SDK and, for Entra ID auth, `@azure/identity`:\n\n```bash\nnpm install @azure/core-auth@1.10.1 @azure/search-documents @azure/identity\n```\n\n## What This Package Provides\n\nThe main surface area is small:\n\n- `TokenCredential`: interface implemented by token providers such as `DefaultAzureCredential`\n- `AzureKeyCredential`: wraps one secret string and supports in-place rotation with `.update(...)`\n- `AzureNamedKeyCredential`: wraps a name/key pair and supports in-place rotation with `.update(...)`\n- `AzureSASCredential`: wraps a SAS signature string and supports in-place rotation with `.update(...)`\n\nThese credential objects are reused across many Azure JavaScript SDKs.\n\n## Authentication And Client Initialization\n\n### Choose the credential type your service client expects\n\nFor most Azure SDKs, the auth choice is one of these:\n\n- `TokenCredential` for Microsoft Entra ID and managed identity flows\n- `AzureKeyCredential` for simple API-key auth\n- `AzureNamedKeyCredential` when the service expects both a name and a secret\n- `AzureSASCredential` when the service accepts a SAS token\n\nIf the service supports token auth, prefer `DefaultAzureCredential` in deployed Azure environments and local development with Azure CLI, Azure Developer CLI, or service-principal environment variables.\n\n### Minimal token-auth client setup\n\n`@azure/core-auth` defines the `TokenCredential` contract. A concrete implementation usually comes from `@azure/identity`.\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_SEARCH_SERVICE_ENDPOINT=\"https://<service-name>.search.windows.net\"\nexport AZURE_SEARCH_INDEX_NAME=\"hotels\"\n```\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { SearchClient } from \"@azure/search-documents\";\n\nconst endpoint = process.env.AZURE_SEARCH_SERVICE_ENDPOINT;\nconst indexName = process.env.AZURE_SEARCH_INDEX_NAME;\n\nif (!endpoint || !indexName) {\n  throw new Error(\n    \"AZURE_SEARCH_SERVICE_ENDPOINT and AZURE_SEARCH_INDEX_NAME are required\",\n  );\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new SearchClient(endpoint, indexName, credential);\n\nconst searchResults = await client.search(\"wifi\");\n\nfor await (const result of searchResults.results) {\n  console.log(result.document.hotelName);\n}\n```\n\n### Minimal API-key client setup\n\nUse `AzureKeyCredential` when the service SDK accepts an API key instead of a token credential.\n\n```bash\nexport AZURE_SEARCH_SERVICE_ENDPOINT=\"https://<service-name>.search.windows.net\"\nexport AZURE_SEARCH_INDEX_NAME=\"hotels\"\nexport AZURE_SEARCH_API_KEY=\"<query-or-admin-key>\"\n```\n\n```js\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { SearchClient } from \"@azure/search-documents\";\n\nconst endpoint = process.env.AZURE_SEARCH_SERVICE_ENDPOINT;\nconst indexName = process.env.AZURE_SEARCH_INDEX_NAME;\nconst apiKey = process.env.AZURE_SEARCH_API_KEY;\n\nif (!endpoint || !indexName || !apiKey) {\n  throw new Error(\n    \"AZURE_SEARCH_SERVICE_ENDPOINT, AZURE_SEARCH_INDEX_NAME, and AZURE_SEARCH_API_KEY are required\",\n  );\n}\n\nconst credential = new AzureKeyCredential(apiKey);\nconst client = new SearchClient(endpoint, indexName, credential);\n\nconst searchResults = await client.search(\"parking\");\n\nfor await (const result of searchResults.results) {\n  console.log(result.document.hotelName);\n}\n```\n\n### One helper that supports key or token auth\n\nThis is a practical pattern for app code that should use an API key when one is configured and otherwise fall back to Entra ID:\n\n```js\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { SearchClient } from \"@azure/search-documents\";\n\nexport function createSearchClient() {\n  const endpoint = process.env.AZURE_SEARCH_SERVICE_ENDPOINT;\n  const indexName = process.env.AZURE_SEARCH_INDEX_NAME;\n\n  if (!endpoint || !indexName) {\n    throw new Error(\n      \"AZURE_SEARCH_SERVICE_ENDPOINT and AZURE_SEARCH_INDEX_NAME are required\",\n    );\n  }\n\n  if (process.env.AZURE_SEARCH_API_KEY) {\n    return new SearchClient(\n      endpoint,\n      indexName,\n      new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n    );\n  }\n\n  return new SearchClient(endpoint, indexName, new DefaultAzureCredential());\n}\n```\n\n## Common Workflows\n\n### Read a token directly from a `TokenCredential`\n\nUse this only when you are building custom HTTP logic or debugging auth flow. Service SDKs usually fetch and refresh tokens for you.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst credential = new DefaultAzureCredential();\nconst token = await credential.getToken(\"https://storage.azure.com/.default\");\n\nif (!token) {\n  throw new Error(\"Credential did not return an access token\");\n}\n\nconsole.log(new Date(token.expiresOnTimestamp).toISOString());\n```\n\nWhen you call `getToken()` yourself, use the resource scope that the target service expects, typically ending in `/.default`.\n\n### Rotate an API key without recreating the client\n\nThe `AzureKeyCredential` object is designed for this exact workflow.\n\n```bash\nexport AZURE_SEARCH_API_KEY=\"<current-key>\"\nexport AZURE_SEARCH_NEXT_API_KEY=\"<rotated-key>\"\n```\n\n```js\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { SearchClient } from \"@azure/search-documents\";\n\nconst credential = new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY);\nconst client = new SearchClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  process.env.AZURE_SEARCH_INDEX_NAME,\n  credential,\n);\n\ncredential.update(process.env.AZURE_SEARCH_NEXT_API_KEY);\n\nconst searchResults = await client.search(\"pool\");\n\nfor await (const result of searchResults.results) {\n  console.log(result.document.hotelName);\n}\n```\n\nRecreate the client only if you also changed endpoint or other client options. A key rotation by itself does not require a new client.\n\n### Work with a named key credential\n\nUse `AzureNamedKeyCredential` when the client needs both a stable name and a secret.\n\n```bash\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<storage-account>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\nexport AZURE_STORAGE_NEXT_ACCOUNT_KEY=\"<rotated-account-key>\"\n```\n\n```js\nimport { AzureNamedKeyCredential } from \"@azure/core-auth\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\nconst nextAccountKey = process.env.AZURE_STORAGE_NEXT_ACCOUNT_KEY;\n\nif (!accountName || !accountKey || !nextAccountKey) {\n  throw new Error(\n    \"AZURE_STORAGE_ACCOUNT_NAME, AZURE_STORAGE_ACCOUNT_KEY, and AZURE_STORAGE_NEXT_ACCOUNT_KEY are required\",\n  );\n}\n\nconst credential = new AzureNamedKeyCredential(accountName, accountKey);\n\nconsole.log(credential.name);\nconsole.log(credential.key.length);\n\ncredential.update(accountName, nextAccountKey);\n```\n\nPass the same credential object into any SDK client that documents `AzureNamedKeyCredential` support, then call `.update(...)` when you rotate the secret.\n\n### Work with a SAS credential\n\nUse `AzureSASCredential` when the service client accepts a SAS token instead of a connection string or account key.\n\n```bash\nexport AZURE_SERVICE_SAS=\"<sas-token>\"\nexport AZURE_SERVICE_NEXT_SAS=\"<next-sas-token>\"\n```\n\n```js\nimport { AzureSASCredential } from \"@azure/core-auth\";\n\nconst signature = process.env.AZURE_SERVICE_SAS;\nconst nextSignature = process.env.AZURE_SERVICE_NEXT_SAS;\n\nif (!signature || !nextSignature) {\n  throw new Error(\"AZURE_SERVICE_SAS and AZURE_SERVICE_NEXT_SAS are required\");\n}\n\nconst credential = new AzureSASCredential(signature);\n\nconsole.log(credential.signature.length);\n\ncredential.update(nextSignature);\n```\n\nPass the SAS token string your target SDK expects. Do not substitute a full resource URL or a connection string where a client constructor expects `AzureSASCredential`.\n\n## Practical Notes\n\n- `@azure/core-auth` is usually a support package. Most application code also installs a service SDK such as `@azure/search-documents`, `@azure/storage-blob`, or `@azure/data-tables`.\n- `DefaultAzureCredential` and other token providers come from `@azure/identity`, not from `@azure/core-auth`.\n- The key, named-key, and SAS credential classes are long-lived mutable containers. Reuse them and rotate secrets with `.update(...)` instead of rebuilding clients unnecessarily.\n- Use the credential type documented by the target service SDK. Azure SDK constructors are not interchangeable across all credential kinds.\n\n## Common Pitfalls\n\n- Expecting `@azure/core-auth` to perform interactive login or token acquisition by itself.\n- Importing `DefaultAzureCredential` from the wrong package; it comes from `@azure/identity`.\n- Passing a connection string into a constructor that expects `AzureKeyCredential`, `AzureNamedKeyCredential`, `AzureSASCredential`, or a `TokenCredential`.\n- Recreating long-lived clients for every request instead of reusing the client and rotating the credential object when the secret changes.\n- Calling `getToken()` manually with the wrong scope or without the `/.default` suffix for Azure resource audiences.\n- Assuming every Azure SDK client accepts every credential type from this package; check the specific client constructor docs.\n\n## Version Notes For `1.10.1`\n\n- This guide targets `@azure/core-auth` `1.10.1`.\n- The day-to-day surface for application code is the shared `TokenCredential` contract plus the `AzureKeyCredential`, `AzureNamedKeyCredential`, and `AzureSASCredential` containers.\n- In most apps, token credentials come from `@azure/identity` and the concrete service operations come from another Azure SDK package.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-auth/?view=azure-node-latest`\n- Package overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/core-auth-readme?view=azure-node-latest`\n- `TokenCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-auth/tokencredential?view=azure-node-latest`\n- `AzureKeyCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-auth/azurekeycredential?view=azure-node-latest`\n- `AzureNamedKeyCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-auth/azurenamedkeycredential?view=azure-node-latest`\n- `AzureSASCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-auth/azuresascredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/core-auth`\n"
  },
  {
    "path": "content/azure/docs/core-rest-pipeline/javascript/DOC.md",
    "content": "---\nname: core-rest-pipeline\ndescription: \"@azure/core-rest-pipeline JavaScript primitives for building low-level HTTP pipelines with policies, retries, auth, and transport customization\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.23.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,core-rest-pipeline,javascript,http,pipeline,policies,retry,auth,transport\"\n---\n\n# @azure/core-rest-pipeline JavaScript Guide\n\n## Golden Rule\n\nUse `@azure/core-rest-pipeline` when you are building or customizing a low-level HTTP client in the Azure SDK style. Most application code should use a service client such as Storage, Key Vault, or Search instead of constructing raw requests by hand. If you do use this package directly, create the pipeline once, reuse it, and add only the policies your client actually needs.\n\n## Install\n\nInstall the pipeline package directly:\n\n```bash\nnpm install @azure/core-rest-pipeline@1.23.0\n```\n\nIf you need Microsoft Entra ID bearer tokens, add `@azure/identity` too:\n\n```bash\nnpm install @azure/core-rest-pipeline@1.23.0 @azure/identity\n```\n\nIf you want Azure SDK request/response logging, add `@azure/logger` as a direct dependency:\n\n```bash\nnpm install @azure/core-rest-pipeline@1.23.0 @azure/logger\n```\n\n## What This Package Does\n\nThe main exports you will usually use are:\n\n- `createPipelineFromOptions(...)`: builds a pipeline with Azure's default policy set\n- `createEmptyPipeline()`: starts from a blank pipeline when you want full control\n- `createDefaultHttpClient()`: chooses the right HTTP transport for the current runtime\n- `createPipelineRequest(...)`: creates a request object with defaults such as method, headers, timeout, and request ID\n- `createHttpHeaders(...)`: creates a mutable header collection\n- `bearerTokenAuthenticationPolicy(...)`: adds `Authorization: Bearer ...` from a `TokenCredential`\n- `RestError` and `isRestError(...)`: catch and inspect pipeline failures consistently\n\n`createPipelineFromOptions(...)` is the right default. It adds the standard user-agent, request ID, multipart/form-data, retry, tracing, and logging policies. In Node-like runtimes it also adds proxy, decompression, TLS, and redirect handling.\n\n## Minimal Setup\n\nUse environment variables for endpoints and credentials:\n\n```bash\nexport API_BASE_URL=\"https://management.azure.com\"\nexport ARM_SCOPE=\"https://management.azure.com/.default\"\nexport ARM_API_VERSION=\"2020-01-01\"\n\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nFor local development, `DefaultAzureCredential` also works with `az login` instead of service-principal environment variables.\n\n## Core Usage\n\n### Build A Reusable Pipeline And Send A Request\n\nThis is the common pattern when you need low-level control but still want Azure SDK retry, headers, and transport behavior:\n\n```js\nimport {\n  createDefaultHttpClient,\n  createHttpHeaders,\n  createPipelineFromOptions,\n  createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\n\nconst apiBaseUrl = process.env.API_BASE_URL;\nconst apiVersion = process.env.ARM_API_VERSION || \"2020-01-01\";\n\nif (!apiBaseUrl) {\n  throw new Error(\"API_BASE_URL is required\");\n}\n\nconst pipeline = createPipelineFromOptions({\n  userAgentOptions: {\n    userAgentPrefix: \"my-app/1.0.0\",\n  },\n  retryOptions: {\n    maxRetries: 5,\n    retryDelayInMs: 1_000,\n    maxRetryDelayInMs: 8_000,\n  },\n  loggingOptions: {\n    additionalAllowedQueryParameters: [\"api-version\"],\n  },\n});\n\nconst httpClient = createDefaultHttpClient();\n\nconst request = createPipelineRequest({\n  url: `${apiBaseUrl}/subscriptions?api-version=${apiVersion}`,\n  method: \"GET\",\n  headers: createHttpHeaders({\n    Accept: \"application/json\",\n  }),\n});\n\nconst response = await pipeline.sendRequest(httpClient, request);\n\nconsole.log(response.status);\nconsole.log(response.bodyAsText);\n```\n\nReuse the same `pipeline` and `httpClient` across calls instead of recreating them for every request.\n\n### Add Bearer Token Authentication\n\n`createPipelineFromOptions(...)` does not add auth automatically. Add a signing policy explicitly when the target service expects bearer tokens.\n\n```js\nimport {\n  bearerTokenAuthenticationPolicy,\n  createDefaultHttpClient,\n  createPipelineFromOptions,\n  createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst scope = process.env.ARM_SCOPE || \"https://management.azure.com/.default\";\n\nconst pipeline = createPipelineFromOptions({\n  retryOptions: { maxRetries: 3 },\n});\n\npipeline.addPolicy(\n  bearerTokenAuthenticationPolicy({\n    credential: new DefaultAzureCredential(),\n    scopes: [scope],\n  }),\n  { phase: \"Sign\" },\n);\n\nconst request = createPipelineRequest({\n  url: \"https://management.azure.com/subscriptions?api-version=2020-01-01\",\n  method: \"GET\",\n});\n\nconst response = await pipeline.sendRequest(\n  createDefaultHttpClient(),\n  request,\n);\n\nconsole.log(response.status);\nconsole.log(response.bodyAsText);\n```\n\nImportant behavior:\n\n- `bearerTokenAuthenticationPolicy(...)` only permits `https://` URLs\n- The policy caches and refreshes access tokens for you through the credential\n- Put bearer auth in the `Sign` phase so retries and earlier policies run before signing\n\n### Add A Custom Policy\n\nUse a custom policy when every request needs the same header, query parameter, or mutation.\n\n```js\nimport {\n  createDefaultHttpClient,\n  createPipelineFromOptions,\n  createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\n\nconst pipeline = createPipelineFromOptions({});\n\npipeline.addPolicy(\n  {\n    name: \"apiVersionPolicy\",\n    async sendRequest(request, next) {\n      const url = new URL(request.url);\n\n      if (!url.searchParams.has(\"api-version\")) {\n        url.searchParams.set(\n          \"api-version\",\n          process.env.ARM_API_VERSION || \"2020-01-01\",\n        );\n      }\n\n      request.url = url.toString();\n      request.headers.set(\"Accept\", \"application/json\");\n\n      return next(request);\n    },\n  },\n  { phase: \"Serialize\" },\n);\n\nconst request = createPipelineRequest({\n  url: \"https://management.azure.com/subscriptions\",\n  method: \"GET\",\n});\n\nconst response = await pipeline.sendRequest(\n  createDefaultHttpClient(),\n  request,\n);\n\nconsole.log(response.status);\n```\n\nIf you need a fully custom stack, start with `createEmptyPipeline()` instead of `createPipelineFromOptions()`.\n\n### Catch `RestError` Cleanly\n\nUse `isRestError(...)` when you want access to `statusCode`, the original request, and the raw response.\n\n```js\nimport {\n  createDefaultHttpClient,\n  createPipelineFromOptions,\n  createPipelineRequest,\n  isRestError,\n} from \"@azure/core-rest-pipeline\";\n\ntry {\n  const pipeline = createPipelineFromOptions({});\n  const request = createPipelineRequest({\n    url: \"https://management.azure.com/subscriptions?api-version=2020-01-01\",\n    method: \"GET\",\n  });\n\n  const response = await pipeline.sendRequest(\n    createDefaultHttpClient(),\n    request,\n  );\n\n  if (response.status >= 400) {\n    throw new Error(`Unexpected status ${response.status}`);\n  }\n} catch (error) {\n  if (isRestError(error)) {\n    console.error(error.code, error.statusCode, error.message);\n    console.error(error.response?.headers.get(\"x-ms-request-id\"));\n  }\n\n  throw error;\n}\n```\n\n## Logging, Retries, And Transport\n\n### Enable Sanitized Request/Response Logs\n\nThe log policy is part of `createPipelineFromOptions(...)`, but Azure SDK logging is disabled until you set a log level.\n\n```js\nimport { createPipelineFromOptions } from \"@azure/core-rest-pipeline\";\nimport { setLogLevel } from \"@azure/logger\";\n\nsetLogLevel(\"info\");\n\nconst pipeline = createPipelineFromOptions({\n  loggingOptions: {\n    additionalAllowedHeaderNames: [\"x-ms-request-id\"],\n    additionalAllowedQueryParameters: [\"api-version\"],\n  },\n});\n```\n\nThe log policy sanitizes headers and query parameters by default, and it does not log request bodies.\n\n### Proxy Support In Node\n\nIn Node-like runtimes, the proxy policy is included automatically by `createPipelineFromOptions(...)`. If you do not pass explicit proxy settings, it reads standard environment variables.\n\n```bash\nexport HTTPS_PROXY=\"http://proxy.internal:8080\"\nexport ALL_PROXY=\"http://proxy.internal:8080\"\nexport NO_PROXY=\".blob.core.windows.net,localhost,127.0.0.1\"\n```\n\nYou can also pass `proxyOptions` to `createPipelineFromOptions(...)`, or set `request.proxySettings` on an individual request.\n\n### Redirects And Retry Behavior\n\n- Default retry handling covers throttling responses, transport-layer failures, and exponential backoff retries\n- Retry configuration is passed through `retryOptions` on `createPipelineFromOptions(...)`\n- Redirect handling is only added in Node-like runtimes\n- For low-level HTTP-only integrations, use `createEmptyPipeline()` if you want to remove default retry or redirect behavior entirely\n\n## Practical Notes\n\n- `createPipelineRequest(...)` defaults the method to `GET` and generates a request ID if you do not provide one.\n- Requests are HTTPS-only by default. To call a local HTTP endpoint, set `allowInsecureConnection: true` on the request.\n- Bearer token auth is stricter: it does not allow non-HTTPS URLs even if `allowInsecureConnection` is true.\n- In Node, proxy handling honors `HTTPS_PROXY`, `ALL_PROXY`, `HTTP_PROXY`, and `NO_PROXY` when you do not pass explicit settings.\n- Use `createEmptyPipeline()` for test doubles, very small custom clients, or cases where Azure's default policy stack is the wrong fit.\n\n## Common Pitfalls\n\n- Expecting `createPipelineFromOptions(...)` to add authentication automatically.\n- Adding a bearer token policy to an `http://` endpoint.\n- Recreating the pipeline for every request instead of reusing it.\n- Turning on logging without allowing the headers or query parameters you actually need to inspect.\n- Using this package where a higher-level Azure service client would be simpler and safer.\n- Forgetting that Node-only behavior such as proxy, TLS, decompression, and redirect handling is not added in browser runtimes.\n\n## Version Notes For 1.23.0\n\n- This guide targets `@azure/core-rest-pipeline` `1.23.0`.\n- `@azure/identity` and `@azure/logger` are versioned separately; pin them according to your application's Azure SDK policy.\n- If you copy older low-level Azure examples, prefer `createPipelineFromOptions(...)`, `createDefaultHttpClient()`, and `createPipelineRequest(...)` over ad-hoc request objects.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-rest-pipeline/`\n- Azure SDK source root: `https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline`\n- npm package page: `https://www.npmjs.com/package/@azure/core-rest-pipeline`\n"
  },
  {
    "path": "content/azure/docs/core-util/javascript/DOC.md",
    "content": "---\nname: core-util\ndescription: \"@azure/core-util guide for JavaScript abort helpers, retry delay calculation, hashing, encoding, type guards, and runtime detection utilities\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.13.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,core-util,javascript,utilities,abort,retry,hashing\"\n---\n\n# @azure/core-util JavaScript Package Guide\n\n## What It Is\n\n`@azure/core-util` is a low-level Azure SDK helper package. In `1.13.1`, its public surface is a small set of utilities for:\n\n- abortable async flows\n- exponential retry delay calculation\n- SHA-256 hashing and HMAC helpers\n- byte/string encoding helpers\n- error and object type guards\n- runtime detection and UUID generation\n\nThis package does not create Azure service clients, open network connections, or use Azure credentials by itself. Use it when you specifically need these helpers in shared application or SDK-adjacent code.\n\n## Version Scope\n\n- Package: `@azure/core-util`\n- Version covered: `1.13.1`\n- Language: JavaScript\n- Docs root: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-util/`\n- Registry page: `https://www.npmjs.com/package/@azure/core-util`\n\n## Install\n\n```bash\nnpm install @azure/core-util\n```\n\n`1.13.1` declares `node >=20.0.0` in its published package metadata.\n\nThe package publishes conditional exports for standard ESM imports plus CommonJS, browser, and React Native builds. The examples below use ESM syntax.\n\n## Initialization And Configuration\n\nThere is no client object, endpoint, or authentication step.\n\n```js\nimport {\n  calculateRetryDelay,\n  cancelablePromiseRace,\n  computeSha256Hash,\n  computeSha256Hmac,\n  createAbortablePromise,\n  delay,\n  getErrorMessage,\n  isBrowser,\n  isDefined,\n  isError,\n  isNodeLike,\n  isNodeRuntime,\n  isObject,\n  isObjectWithProperties,\n  objectHasProperty,\n  randomUUID,\n  stringToUint8Array,\n  uint8ArrayToString,\n} from \"@azure/core-util\";\n```\n\nEnvironment variables are not required.\n\n## Common Workflows\n\n### Pause with cancellation support\n\n`delay(...)` wraps `setTimeout(...)` in a promise and accepts abort options.\n\n```js\nimport { delay } from \"@azure/core-util\";\n\nconst abortController = new AbortController();\n\nconst pendingDelay = delay(5_000, {\n  abortSignal: abortController.signal,\n  abortErrorMsg: \"Backoff wait was cancelled\",\n});\n\nsetTimeout(() => abortController.abort(), 1_000);\n\ntry {\n  await pendingDelay;\n} catch (error) {\n  console.error(error.message);\n}\n```\n\nThis is the normal pattern for retry sleeps, polling loops, or any wait that should stop when a parent operation is cancelled.\n\n### Calculate exponential backoff with jitter\n\n`calculateRetryDelay(...)` returns an object with `retryAfterInMs`.\n\n```js\nimport { calculateRetryDelay } from \"@azure/core-util\";\n\nconst { retryAfterInMs } = calculateRetryDelay(2, {\n  retryDelayInMs: 800,\n  maxRetryDelayInMs: 8_000,\n});\n\nconsole.log(retryAfterInMs);\n```\n\nThe calculation increases the base delay exponentially, clamps it at `maxRetryDelayInMs`, and adds jitter so concurrent clients do not all retry at the same instant.\n\n### Build your own abortable promise\n\n`createAbortablePromise(...)` is useful when you need to bridge timers, event listeners, or callback-style code into an abort-aware promise.\n\n```js\nimport { createAbortablePromise } from \"@azure/core-util\";\n\nfunction waitForReady(ms, abortSignal) {\n  let timer;\n\n  return createAbortablePromise((resolve) => {\n    timer = setTimeout(() => resolve(\"ready\"), ms);\n  }, {\n    abortSignal,\n    abortErrorMsg: \"Ready wait aborted\",\n    cleanupBeforeAbort: () => clearTimeout(timer),\n  });\n}\n\nconst abortController = new AbortController();\nconst result = await waitForReady(250, abortController.signal);\n\nconsole.log(result);\n```\n\nIf the signal is already aborted, the promise rejects immediately with an `AbortError`.\n\n### Race multiple abortable operations\n\n`cancelablePromiseRace(...)` expects an array of builder functions. Each builder receives an object with `abortSignal`, and the helper aborts the remaining builders when the first one settles.\n\n```js\nimport { cancelablePromiseRace, delay } from \"@azure/core-util\";\n\nconst winner = await cancelablePromiseRace([\n  async ({ abortSignal }) => {\n    await delay(200, { abortSignal });\n    return \"fast\";\n  },\n  async ({ abortSignal }) => {\n    await delay(2_000, { abortSignal });\n    return \"slow\";\n  },\n]);\n\nconsole.log(winner);\n```\n\nThis only works correctly when each builder passes the supplied `abortSignal` into the async work it starts.\n\n### Hash content and encode bytes\n\nThe hash helpers are async and return the digest in the encoding you request.\n\n```js\nimport {\n  computeSha256Hash,\n  computeSha256Hmac,\n  stringToUint8Array,\n  uint8ArrayToString,\n} from \"@azure/core-util\";\n\nconst digestHex = await computeSha256Hash(\"hello world\", \"hex\");\n\nconst hmacBase64 = await computeSha256Hmac(\n  \"c2VjcmV0LWtleQ==\",\n  \"hello world\",\n  \"base64\",\n);\n\nconst bytes = stringToUint8Array(\"hello world\", \"utf-8\");\nconst roundTrip = uint8ArrayToString(bytes, \"utf-8\");\n\nconsole.log({ digestHex, hmacBase64, roundTrip });\n```\n\nFor portable code across Node and browser builds, use the encodings exposed by the package helpers: `utf-8`, `base64`, `base64url`, and `hex`.\n\n### Normalize thrown errors and inspect unknown values\n\n```js\nimport {\n  getErrorMessage,\n  isDefined,\n  isError,\n  isObject,\n  isObjectWithProperties,\n  objectHasProperty,\n} from \"@azure/core-util\";\n\ntry {\n  throw { code: \"E_FAIL\" };\n} catch (error) {\n  console.error(getErrorMessage(error));\n\n  if (isError(error)) {\n    console.error(error.name, error.message);\n  }\n}\n\nconst value = JSON.parse('{\"id\":\"42\",\"status\":\"ok\"}');\n\nif (\n  isDefined(value) &&\n  isObject(value) &&\n  isObjectWithProperties(value, [\"id\", \"status\"]) &&\n  objectHasProperty(value, \"id\")\n) {\n  console.log(value.id, value.status);\n}\n```\n\n`isObject(...)` is intentionally narrow: it excludes `null`, arrays, `RegExp`, and `Date`.\n\n### Generate request IDs and branch on runtime\n\n```js\nimport {\n  isBrowser,\n  isNodeLike,\n  isNodeRuntime,\n  randomUUID,\n} from \"@azure/core-util\";\n\nconst requestId = randomUUID();\n\nif (isNodeRuntime) {\n  console.log(\"Running in Node.js\", requestId);\n} else if (isBrowser) {\n  console.log(\"Running in the browser\", requestId);\n} else if (isNodeLike) {\n  console.log(\"Running in a Node-compatible runtime\", requestId);\n}\n```\n\nUse `isNodeLike` for compatibility checks. `isNode` is still exported in `1.13.1`, but it is deprecated in favor of `isNodeLike`.\n\n## Practical Notes\n\n- Reuse `AbortSignal` from the parent operation so delay and custom promise helpers stop promptly when callers cancel work.\n- Treat `calculateRetryDelay(...)` as a math helper only. You still need your own retry loop and retryable error policy.\n- Keep HMAC keys in base64 form when passing them to `computeSha256Hmac(...)`.\n- Use the byte conversion helpers when you need the same content encoded consistently across Node and browser builds.\n- Prefer `getErrorMessage(...)` when you are catching `unknown` values and need a safe log string.\n\n## Common Pitfalls\n\n- Importing `@azure/core-util` and expecting an Azure client, endpoint handling, or credential flow.\n- Passing already-started promises into `cancelablePromiseRace(...)` instead of builder functions that accept `{ abortSignal }`.\n- Forgetting that `computeSha256Hash(...)` and `computeSha256Hmac(...)` return promises.\n- Using `getRandomIntegerInclusive(...)` for security-sensitive randomness.\n- Using `isNode` in new code instead of `isNodeLike`.\n- Assuming browser hashing works without Web Crypto support.\n\n## Version Notes For 1.13.1\n\n- This guide targets `@azure/core-util` `1.13.1`.\n- The published package manifest requires Node `>=20.0.0`.\n- The package exports ESM, CommonJS, browser, and React Native entry points.\n- `isNode` is a deprecated alias of `isNodeLike` in this version.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/core-util/`\n- npm package page: `https://www.npmjs.com/package/@azure/core-util`\n- Azure SDK for JavaScript package homepage: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/`\n"
  },
  {
    "path": "content/azure/docs/cosmos/javascript/DOC.md",
    "content": "---\nname: cosmos\ndescription: \"Azure Cosmos DB for NoSQL JavaScript client with practical guidance for setup, partition keys, CRUD, queries, and patch operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.9.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,cosmos,cosmos-db,nosql,javascript,database\"\n---\n\n# Azure Cosmos DB JavaScript Client\n\n## Golden Rule\n\nUse `@azure/cosmos` for Azure Cosmos DB for NoSQL from JavaScript or TypeScript, and choose your partition key before you start writing data. Reuse a long-lived `CosmosClient`, prefer point reads when you know `id` and partition key, and use SQL queries only when you actually need them. This package is not the client for Cosmos DB MongoDB, Cassandra, Gremlin, or Table workloads.\n\n## Install\n\nPin the version your project expects:\n\n```bash\nnpm install @azure/cosmos@4.9.1\n```\n\nIf you use TypeScript, the package ships its own types.\n\n## Authentication And Setup\n\nYou need an Azure Cosmos DB for NoSQL account endpoint such as `https://<account>.documents.azure.com:443/` and an account key.\n\n```bash\nexport COSMOS_ENDPOINT=\"https://<account>.documents.azure.com:443/\"\nexport COSMOS_KEY=\"<account-key>\"\nexport COSMOS_DATABASE_ID=\"appdb\"\nexport COSMOS_CONTAINER_ID=\"items\"\n```\n\n```js\nimport { CosmosClient } from \"@azure/cosmos\";\n\nconst client = new CosmosClient({\n  endpoint: process.env.COSMOS_ENDPOINT,\n  key: process.env.COSMOS_KEY,\n});\n```\n\nKeep the endpoint and key in environment variables or your secret manager, not in source code.\n\n## Client Initialization\n\nCreate one shared `CosmosClient` for your app or service component instead of creating a new client per request.\n\n```js\nimport { CosmosClient } from \"@azure/cosmos\";\n\nexport const cosmosClient = new CosmosClient({\n  endpoint: process.env.COSMOS_ENDPOINT,\n  key: process.env.COSMOS_KEY,\n});\n```\n\n## Core Usage\n\n### Create or get a database and container\n\nUse `createIfNotExists` during setup, migrations, or local bootstrap paths. These are control-plane calls, so do not put them on every hot request path.\n\n```js\nimport { CosmosClient } from \"@azure/cosmos\";\n\nconst client = new CosmosClient({\n  endpoint: process.env.COSMOS_ENDPOINT,\n  key: process.env.COSMOS_KEY,\n});\n\nconst { database } = await client.databases.createIfNotExists({\n  id: process.env.COSMOS_DATABASE_ID,\n});\n\nconst { container } = await database.containers.createIfNotExists({\n  id: process.env.COSMOS_CONTAINER_ID,\n  partitionKey: {\n    paths: [\"/tenantId\"],\n  },\n});\n```\n\n### Create or upsert an item\n\nEvery item needs an `id`. If your container partition key is `/tenantId`, the document also needs `tenantId`.\n\n```js\nconst item = {\n  id: \"item-1\",\n  tenantId: \"acme\",\n  status: \"open\",\n  title: \"Initial document\",\n};\n\nconst { resource: saved } = await container.items.upsert(item);\n\nconsole.log(saved.id);\n```\n\nUse `upsert` when replacing an existing document is acceptable. If you need create-only behavior, use `container.items.create(...)` instead.\n\n### Read one item by `id` and partition key\n\nWhen you know both values, use a point read instead of a query.\n\n```js\nconst { resource: item } = await container.item(\"item-1\", \"acme\").read();\n\nconsole.log(item.status);\n```\n\n### Replace or delete an item\n\n```js\nconst { resource: current } = await container.item(\"item-1\", \"acme\").read();\n\nconst { resource: replaced } = await container.item(\"item-1\", \"acme\").replace({\n  ...current,\n  status: \"done\",\n});\n\nconsole.log(replaced.status);\n\nawait container.item(\"item-1\", \"acme\").delete();\n```\n\n### Patch part of a document\n\nUse patch when you only need to change a few paths.\n\n```js\nconst { resource: patched } = await container.item(\"item-1\", \"acme\").patch([\n  {\n    op: \"replace\",\n    path: \"/status\",\n    value: \"done\",\n  },\n]);\n\nconsole.log(patched.status);\n```\n\n### Run a parameterized query\n\nUse query parameters instead of string interpolation.\n\n```js\nconst querySpec = {\n  query: \"SELECT * FROM c WHERE c.tenantId = @tenantId AND c.status = @status\",\n  parameters: [\n    { name: \"@tenantId\", value: \"acme\" },\n    { name: \"@status\", value: \"open\" },\n  ],\n};\n\nconst { resources: openItems } = await container.items.query(querySpec).fetchAll();\n\nfor (const item of openItems) {\n  console.log(item.id, item.status);\n}\n```\n\n## Configuration Notes\n\n- Reuse a single `CosmosClient`; client creation is not a lightweight health check.\n- Treat the partition key as required application context. Point reads, replaces, patches, and deletes usually need it.\n- Prefer `container.item(id, partitionKey).read()` over queries when you know both values.\n- Use `createIfNotExists` for bootstrap code, not the hot path of every request.\n- Keep secrets out of source control.\n- Parameterize queries instead of building SQL strings manually.\n\n## Common Pitfalls\n\n- Using `@azure/cosmos` for the wrong Cosmos API surface. This guide is for Cosmos DB for NoSQL.\n- Designing documents first and the partition key later.\n- Creating a new `CosmosClient` for every operation.\n- Forgetting the partition key on point reads, patches, replaces, and deletes.\n- Using `upsert` where create-only semantics were required.\n- Querying by `id` when a cheaper point read would work.\n\n## Version Notes For 4.9.1\n\n- This guide targets `@azure/cosmos` `4.9.1`.\n- If you find older examples using `DocumentClient`, treat them as legacy and rewrite them to the current `CosmosClient` API.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/cosmos/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/cosmos-readme?view=azure-node-latest`\n- `CosmosClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/cosmos/cosmosclient?view=azure-node-latest`\n- `Container` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/cosmos/container?view=azure-node-latest`\n- Azure Cosmos DB for NoSQL Node.js quickstart: `https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/quickstart-nodejs`\n- npm package page: `https://www.npmjs.com/package/@azure/cosmos`\n"
  },
  {
    "path": "content/azure/docs/cosmos/python/DOC.md",
    "content": "---\nname: cosmos\ndescription: \"Azure Cosmos DB for NoSQL Python client with practical guidance for auth, partition keys, CRUD, queries, retries, and async usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,cosmos,cosmos-db,nosql,python,database\"\n---\n\n# Azure Cosmos DB Python Client\n\n## Golden Rule\n\nUse `azure-cosmos` for Azure Cosmos DB for NoSQL from Python, and model partition keys up front. Reuse a long-lived `CosmosClient`, prefer point reads when you know `id` and partition key, and only use queries when you actually need them. This SDK is not the client for Cosmos DB MongoDB, Cassandra, Gremlin, or Table workloads.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"azure-cosmos==4.15.0\"\n```\n\nIf you want Microsoft Entra ID authentication, install `azure-identity` too:\n\n```bash\npython -m pip install \"azure-cosmos==4.15.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-cosmos==4.15.0\"\npoetry add \"azure-cosmos==4.15.0\"\n```\n\n## Authentication And Setup\n\nYou need an Azure Cosmos DB for NoSQL account endpoint such as `https://<account>.documents.azure.com:443/`.\n\n### Account key auth\n\n```bash\nexport COSMOS_ENDPOINT=\"https://<account>.documents.azure.com:443/\"\nexport COSMOS_KEY=\"<account-key>\"\n```\n\n```python\nimport os\nfrom azure.cosmos import CosmosClient\n\nclient = CosmosClient(\n    url=os.environ[\"COSMOS_ENDPOINT\"],\n    credential=os.environ[\"COSMOS_KEY\"],\n)\n```\n\n### Microsoft Entra ID auth\n\n```bash\nexport COSMOS_ENDPOINT=\"https://<account>.documents.azure.com:443/\"\n```\n\n```python\nimport os\nfrom azure.cosmos import CosmosClient\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\nclient = CosmosClient(\n    url=os.environ[\"COSMOS_ENDPOINT\"],\n    credential=credential,\n)\n```\n\nFor Entra ID auth, the principal needs Cosmos DB data-plane permissions on the account. Azure management roles by themselves are not enough.\n\n### Connection string auth\n\n```bash\nexport COSMOS_CONNECTION_STRING=\"AccountEndpoint=...;AccountKey=...;\"\n```\n\n```python\nimport os\nfrom azure.cosmos import CosmosClient\n\nclient = CosmosClient.from_connection_string(\n    conn_str=os.environ[\"COSMOS_CONNECTION_STRING\"]\n)\n```\n\n## Client Initialization\n\n`CosmosClient` initialization is heavy. Reuse one client for the lifetime of your process or app component instead of creating one per request.\n\nExample with a few useful knobs:\n\n```python\nimport os\nfrom azure.cosmos import CosmosClient\n\nclient = CosmosClient(\n    url=os.environ[\"COSMOS_ENDPOINT\"],\n    credential=os.environ[\"COSMOS_KEY\"],\n    preferred_locations=[\"West US 2\", \"East US\"],\n    retry_total=9,\n    retry_backoff_max=30,\n    connection_timeout=5,\n    no_response_on_write=True,\n)\n```\n\nUseful options from the API reference:\n\n- `preferred_locations`: prefer specific read regions\n- `excluded_locations`: exclude specific regions\n- `retry_total` and `retry_backoff_max`: tune transient retry behavior\n- `connection_timeout`: fail faster on bad endpoints or broken network paths\n- `no_response_on_write`: reduce payload size for write-heavy paths when you do not need the full written document back\n\n## Core Usage\n\n### Create or get a database and container\n\nUse `create_*_if_not_exists` for setup scripts, local development, and tests. In hot production paths, prefer `get_database_client(...)` and `get_container_client(...)` when the resources already exist.\n\n```python\nfrom azure.cosmos import CosmosClient, PartitionKey\n\nclient = CosmosClient(url=endpoint, credential=credential)\n\ndatabase = client.create_database_if_not_exists(id=\"appdb\")\ncontainer = database.create_container_if_not_exists(\n    id=\"items\",\n    partition_key=PartitionKey(path=\"/tenantId\"),\n    offer_throughput=400,\n)\n```\n\n### Create or upsert an item\n\n```python\nitem = {\n    \"id\": \"item-1\",\n    \"tenantId\": \"acme\",\n    \"name\": \"Example\",\n    \"price\": 42,\n}\n\nsaved = container.upsert_item(item)\nprint(saved[\"id\"])\n```\n\n`upsert_item` creates or replaces by `id`. Use `create_item` when the operation must fail if the item already exists.\n\n### Read one item\n\nPoint reads are the cheapest and fastest way to fetch a single document, but you must know both the `id` and the partition key value.\n\n```python\ndoc = container.read_item(\n    item=\"item-1\",\n    partition_key=\"acme\",\n)\n\nprint(doc[\"name\"])\n```\n\n### Query items\n\nParameterize queries instead of string formatting, and scope them to one partition when you can:\n\n```python\nquery = \"\"\"\nSELECT c.id, c.name, c.price\nFROM c\nWHERE c.tenantId = @tenant_id AND c.price >= @min_price\n\"\"\"\n\nresults = container.query_items(\n    query=query,\n    parameters=[\n        {\"name\": \"@tenant_id\", \"value\": \"acme\"},\n        {\"name\": \"@min_price\", \"value\": 10},\n    ],\n    partition_key=\"acme\",\n)\n\nfor row in results:\n    print(row[\"id\"], row[\"price\"])\n```\n\nIf you omit the partition key and fan out across partitions, latency and RU cost go up.\n\n### Patch or replace an item\n\nUse `patch_item` for partial updates and `replace_item` when you want to send the full document:\n\n```python\nupdated = container.patch_item(\n    item=\"item-1\",\n    partition_key=\"acme\",\n    patch_operations=[\n        {\"op\": \"replace\", \"path\": \"/price\", \"value\": 50},\n        {\"op\": \"add\", \"path\": \"/tags\", \"value\": [\"featured\"]},\n    ],\n)\n```\n\n### Delete an item\n\n```python\ncontainer.delete_item(\n    item=\"item-1\",\n    partition_key=\"acme\",\n)\n```\n\n## Async Usage\n\nUse the async client from `azure.cosmos.aio` in async applications. The official docs call out that you should enter the client so account metadata is cached before first use.\n\n```python\nimport os\nfrom azure.cosmos.aio import CosmosClient\nfrom azure.identity.aio import DefaultAzureCredential\n\nasync def main() -> None:\n    credential = DefaultAzureCredential()\n\n    async with CosmosClient(\n        url=os.environ[\"COSMOS_ENDPOINT\"],\n        credential=credential,\n    ) as client:\n        database = client.get_database_client(\"appdb\")\n        container = database.get_container_client(\"items\")\n\n        item = await container.read_item(\n            item=\"item-1\",\n            partition_key=\"acme\",\n        )\n        print(item[\"id\"])\n\n    await credential.close()\n```\n\nIf you cannot use `async with`, call `await client.__aenter__()` before using the async client.\n\n## Configuration Notes\n\n- Keep endpoint and credentials in environment variables or your secret manager, not in source code.\n- Use one shared `CosmosClient`; client construction is not a lightweight health check.\n- Treat the partition key as required application context. Reads, patches, and deletes usually need it.\n- `create_database_if_not_exists` and `create_container_if_not_exists` are convenient, but they still make control-plane calls.\n- `no_response_on_write=True` is useful for ingestion-heavy services that do not need the returned document body.\n- `preferred_locations` helps multi-region accounts prefer local reads; `excluded_locations` helps steer around regions you do not want to use.\n- Retry settings only help transient failures. If you are being throttled, you still need to think about RU budget and workload shape.\n\n## Common Pitfalls\n\n- Using this SDK for the wrong Cosmos API surface. `azure-cosmos` here is for Cosmos DB for NoSQL.\n- Designing the data model first and the partition key later. That usually leads to expensive queries and awkward rewrites.\n- Creating a new `CosmosClient` per request or per operation.\n- Forgetting the partition key on point reads, patches, and deletes.\n- Using `upsert_item` where create-only semantics were required.\n- Building SQL strings manually instead of using query parameters.\n- Using Entra ID without assigning Cosmos DB data-plane permissions.\n- Forgetting `async with` or `await client.__aenter__()` when using `azure.cosmos.aio.CosmosClient`.\n\n## Version-Sensitive Notes For 4.15.0\n\n- As of March 12, 2026, PyPI and Microsoft Learn both show `4.15.0`.\n- The Azure SDK changelog for `4.15.0` notes a higher minimum `azure-core` requirement (`1.30.0`) and support for `excluded_locations`.\n- The package still requires Python `>=3.9`.\n- If you find older v3-era snippets using `DocumentClient`, treat them as obsolete and rewrite them to the current `CosmosClient` API.\n\n## Official Sources\n\n- Overview README: `https://learn.microsoft.com/en-us/python/api/overview/azure/cosmos-readme?view=azure-python`\n- API reference root: `https://learn.microsoft.com/en-us/python/api/azure-cosmos/`\n- Sync `CosmosClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-cosmos/azure.cosmos.cosmos_client.cosmosclient?view=azure-python`\n- Async `CosmosClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-cosmos/azure.cosmos.aio.cosmosclient?view=azure-python`\n- Azure Cosmos DB for NoSQL Python quickstart: `https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/quickstart-python`\n- PyPI package page: `https://pypi.org/project/azure-cosmos/`\n- Azure SDK changelog: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/cosmos/azure-cosmos/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/data-tables/javascript/DOC.md",
    "content": "---\nname: data-tables\ndescription: \"Azure Data Tables client for JavaScript with TableClient, TableServiceClient, authentication, and entity operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"13.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,data-tables,azure-storage,cosmosdb,tables,odata,javascript\"\n---\n\n# Azure Data Tables JavaScript Client\n\n## Golden Rule\n\nUse `@azure/data-tables` for Azure Table Storage and Azure Cosmos DB Table workloads. Reach for `TableServiceClient` when you need account-level operations such as creating or listing tables, and use `TableClient` for entity reads and writes. Every entity must include both `PartitionKey` and `RowKey`; most correctness issues come from partition design, OData filters, or assuming the SDK creates missing tables for you.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @azure/data-tables@13.3.2\n```\n\nIf you want Microsoft Entra ID or explicit named-key credentials, install the matching support packages too:\n\n```bash\nnpm install @azure/data-tables@13.3.2 @azure/identity @azure/core-auth\n```\n\n## Authentication And Setup\n\nThe practical auth choices are:\n\n- a connection string\n- a named account key via `AzureNamedKeyCredential`\n- a `TokenCredential` such as `DefaultAzureCredential`\n\nUse connection strings for quick local setup. Prefer `DefaultAzureCredential` for deployed Azure workloads when you can assign the right data-plane role.\n\nUse environment variables instead of hard-coding secrets:\n\n```bash\nexport AZURE_TABLES_CONNECTION_STRING=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\nexport AZURE_TABLES_ACCOUNT_URL=\"https://<account>.table.core.windows.net\"\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<account-name>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\nexport AZURE_TABLES_TABLE_NAME=\"products\"\n```\n\n### Connection String\n\nThis is the simplest setup when you already have a storage or Cosmos Table connection string.\n\n```js\nimport { TableServiceClient } from \"@azure/data-tables\";\n\nconst connectionString =\n  process.env.AZURE_TABLES_CONNECTION_STRING ??\n  process.env.AZURE_STORAGE_CONNECTION_STRING;\n\nif (!connectionString) {\n  throw new Error(\n    \"AZURE_TABLES_CONNECTION_STRING or AZURE_STORAGE_CONNECTION_STRING is required\",\n  );\n}\n\nconst serviceClient =\n  TableServiceClient.fromConnectionString(connectionString);\n```\n\n### Microsoft Entra ID With `DefaultAzureCredential`\n\nUse this for deployed apps in Azure, or for local development after a developer sign-in such as:\n\n```bash\naz login\nexport AZURE_TABLES_ACCOUNT_URL=\"https://<account>.table.core.windows.net\"\n```\n\n```js\nimport { TableServiceClient } from \"@azure/data-tables\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst accountUrl = process.env.AZURE_TABLES_ACCOUNT_URL;\n\nif (!accountUrl) {\n  throw new Error(\"AZURE_TABLES_ACCOUNT_URL is required\");\n}\n\nconst serviceClient = new TableServiceClient(\n  accountUrl,\n  new DefaultAzureCredential(),\n);\n```\n\nFor Azure Table Storage, the calling identity typically needs a table data role such as `Storage Table Data Contributor` or `Storage Table Data Reader`.\n\n### Named Key Credential\n\nUse this when your application explicitly manages storage account keys.\n\n```js\nimport { TableServiceClient } from \"@azure/data-tables\";\nimport { AzureNamedKeyCredential } from \"@azure/core-auth\";\n\nconst accountUrl = process.env.AZURE_TABLES_ACCOUNT_URL;\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\nif (!accountUrl || !accountName || !accountKey) {\n  throw new Error(\n    \"AZURE_TABLES_ACCOUNT_URL, AZURE_STORAGE_ACCOUNT_NAME, and AZURE_STORAGE_ACCOUNT_KEY are required\",\n  );\n}\n\nconst serviceClient = new TableServiceClient(\n  accountUrl,\n  new AzureNamedKeyCredential(accountName, accountKey),\n);\n```\n\n## Client Initialization\n\nCreate one long-lived `TableServiceClient`, then derive `TableClient` instances from it.\n\n```js\nimport { TableServiceClient } from \"@azure/data-tables\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { AzureNamedKeyCredential } from \"@azure/core-auth\";\n\nexport function createTableServiceClient() {\n  const connectionString =\n    process.env.AZURE_TABLES_CONNECTION_STRING ??\n    process.env.AZURE_STORAGE_CONNECTION_STRING;\n\n  if (connectionString) {\n    return TableServiceClient.fromConnectionString(connectionString);\n  }\n\n  const accountUrl = process.env.AZURE_TABLES_ACCOUNT_URL;\n\n  if (!accountUrl) {\n    throw new Error(\n      \"Set AZURE_TABLES_CONNECTION_STRING, AZURE_STORAGE_CONNECTION_STRING, or AZURE_TABLES_ACCOUNT_URL\",\n    );\n  }\n\n  const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\n  const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\n  if (accountName && accountKey) {\n    return new TableServiceClient(\n      accountUrl,\n      new AzureNamedKeyCredential(accountName, accountKey),\n    );\n  }\n\n  return new TableServiceClient(accountUrl, new DefaultAzureCredential());\n}\n```\n\nThe normal hierarchy is:\n\n- `TableServiceClient`: account scope\n- `TableClient`: one table\n\nIf your code only touches one known table, `TableClient.fromConnectionString(...)` is also fine.\n\n## Core Usage\n\n### Create A Table And Get A Table Client\n\nConstructing a client does not create the table. Create it explicitly during setup.\n\n```js\nimport { createTableServiceClient } from \"./tablesClient.js\";\n\nconst serviceClient = createTableServiceClient();\nconst tableName = process.env.AZURE_TABLES_TABLE_NAME ?? \"products\";\n\ntry {\n  await serviceClient.createTable(tableName);\n} catch (error) {\n  if (error.statusCode !== 409) {\n    throw error;\n  }\n}\n\nconst tableClient = serviceClient.getTableClient(tableName);\n```\n\nIf the table is provisioned elsewhere, skip the `createTable(...)` call and just get the client.\n\n### Insert Or Upsert An Entity\n\nEvery entity must include `PartitionKey` and `RowKey`.\n\n```js\nimport { TableClient } from \"@azure/data-tables\";\n\nconst tableClient = TableClient.fromConnectionString(\n  process.env.AZURE_TABLES_CONNECTION_STRING,\n  process.env.AZURE_TABLES_TABLE_NAME ?? \"products\",\n);\n\nconst entity = {\n  PartitionKey: \"inventory\",\n  RowKey: \"sku-1001\",\n  name: \"Widget\",\n  price: 9.99,\n  inStock: true,\n};\n\nawait tableClient.upsertEntity(entity, \"Merge\");\n```\n\n`upsertEntity(..., \"Merge\")` is the safest default when you want create-or-update behavior without replacing the whole stored entity.\n\n### Read One Entity\n\n```js\nconst entity = await tableClient.getEntity(\"inventory\", \"sku-1001\");\n\nconsole.log(entity.name, entity.price);\n```\n\n### Query Entities With OData Filters\n\nUse the `odata` tagged template instead of building filter strings by hand.\n\n```js\nimport { odata } from \"@azure/data-tables\";\n\nconst entities = tableClient.listEntities({\n  queryOptions: {\n    filter: odata`PartitionKey eq ${\"inventory\"} and price gt ${5}`,\n    select: [\"RowKey\", \"name\", \"price\"],\n  },\n});\n\nfor await (const entity of entities) {\n  console.log(entity.RowKey, entity.name, entity.price);\n}\n```\n\n### Merge Vs Replace Updates\n\n`Merge` updates only the properties you send. `Replace` overwrites the stored entity with the payload you provide.\n\n```js\nconst entity = await tableClient.getEntity(\"inventory\", \"sku-1001\");\nentity.price = 8.99;\n\nawait tableClient.updateEntity(entity, \"Merge\");\n```\n\nUse `Replace` only when you intentionally want omitted properties removed.\n\n### Delete An Entity\n\n```js\nawait tableClient.deleteEntity(\"inventory\", \"sku-1001\");\n```\n\n## Practical Notes\n\n- Reuse clients instead of creating a new service or table client for every request.\n- Use the table endpoint form `https://<account>.table.core.windows.net` for Entra ID or named-key clients.\n- Keep connection strings and account keys in environment variables or a secret manager, not in source code.\n- Azure Tables is keyed storage. Good `PartitionKey` and `RowKey` design matters more than ad hoc querying.\n- The same package also works with Azure Cosmos DB Table endpoints; use the endpoint or connection string for that account instead of guessing the hostname.\n\n## Common Pitfalls\n\n- `getTableClient(...)` gives you a client object; it does not create the table.\n- Every entity must include both `PartitionKey` and `RowKey`, and the pair must be unique.\n- Query filters use OData, not SQL. Prefer the `odata` helper over manual string interpolation.\n- `Merge` and `Replace` have very different behavior; `Replace` can drop fields you omitted.\n- Optimistic concurrency still matters for updates. Pay attention to `etag` values when multiple writers can touch the same entity.\n- Transaction batches are limited to a single partition in Azure Tables, so model related writes around partition boundaries.\n- `DefaultAzureCredential` failures are often local environment problems: no `az login`, missing environment variables, or missing role assignments.\n\n## Version Notes For `13.3.2`\n\n- This guide targets `@azure/data-tables` `13.3.2`.\n- Keep new code on the current `TableServiceClient` and `TableClient` surface from the 13.x package line.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/data-tables/`\n- npm package page: `https://www.npmjs.com/package/@azure/data-tables`\n"
  },
  {
    "path": "content/azure/docs/data-tables/python/DOC.md",
    "content": "---\nname: data-tables\ndescription: \"Azure Data Tables Python client for Azure Table Storage and Azure Cosmos DB Table workloads\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,data-tables,azure-storage,cosmosdb,tables,nosql,odata\"\n---\n\n# Azure Data Tables Python Client\n\n## Golden Rule\n\nUse `azure-data-tables` for both Azure Table Storage and Azure Cosmos DB for Table. Start from `TableServiceClient` when you need account-level operations or table creation, then get a `TableClient` for entity reads and writes. Every entity must include `PartitionKey` and `RowKey`, and most correctness issues come from partition design, optimistic concurrency, or using the wrong auth setup for the target endpoint.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"azure-data-tables==12.7.0\"\n```\n\nIf you authenticate with Microsoft Entra ID, install `azure-identity` too:\n\n```bash\npython -m pip install \"azure-data-tables==12.7.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-data-tables==12.7.0\"\npoetry add \"azure-data-tables==12.7.0\"\n```\n\n## Authentication And Client Setup\n\nThe SDK supports several credential patterns:\n\n- Connection string\n- Shared key via `AzureNamedKeyCredential`\n- SAS via `AzureSasCredential`\n- `TokenCredential` such as `DefaultAzureCredential`\n\nUse connection strings for quick local setup. Prefer `DefaultAzureCredential` in deployed Azure environments.\n\n### Service client from a connection string\n\nUse this when you want to create or list tables and then get per-table clients:\n\n```python\nfrom azure.data.tables import TableServiceClient\n\nconn_str = \"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\n\nservice = TableServiceClient.from_connection_string(conn_str=conn_str)\ntable = service.create_table_if_not_exists(table_name=\"products\")\n```\n\n### Service client with `DefaultAzureCredential`\n\nFor Azure Table Storage, this is the clean default:\n\n```python\nfrom azure.data.tables import TableServiceClient\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\n\nservice = TableServiceClient(\n    endpoint=\"https://<storage-account>.table.core.windows.net\",\n    credential=credential,\n)\n```\n\nFor Microsoft Entra ID on storage endpoints, the caller typically needs `Storage Table Data Contributor` or `Storage Table Data Reader`.\n\n### Table client directly from a connection string\n\nUse this when the table already exists and you only need entity operations:\n\n```python\nfrom azure.data.tables import TableClient\n\ntable = TableClient.from_connection_string(\n    conn_str=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\",\n    table_name=\"products\",\n)\n```\n\n### Cosmos DB for Table quickstart pattern\n\nOfficial Cosmos DB for Table quickstarts use the same package and `TableServiceClient` with `DefaultAzureCredential`:\n\n```python\nfrom azure.data.tables import TableServiceClient\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\nservice = TableServiceClient(\n    endpoint=\"<azure-cosmos-db-table-account-endpoint>\",\n    credential=credential,\n)\ntable = service.get_table_client(\"products\")\n```\n\n## Core Usage\n\n### Create or get a table\n\n`get_table_client()` does not create the table. Use `create_table_if_not_exists()` when setup should be idempotent.\n\n```python\nfrom azure.data.tables import TableServiceClient\n\nservice = TableServiceClient.from_connection_string(conn_str=conn_str)\ntable = service.create_table_if_not_exists(table_name=\"products\")\n\nsame_table = service.get_table_client(\"products\")\n```\n\n### Insert or upsert an entity\n\nEvery entity must include `PartitionKey` and `RowKey`.\n\n```python\nfrom azure.data.tables import TableClient\n\ntable = TableClient.from_connection_string(conn_str=conn_str, table_name=\"products\")\n\nentity = {\n    \"PartitionKey\": \"inventory\",\n    \"RowKey\": \"sku-1001\",\n    \"name\": \"Widget\",\n    \"price\": 9.99,\n    \"in_stock\": True,\n}\n\ntable.upsert_entity(entity=entity)\n```\n\n`upsert_entity()` is the safest default when you want create-or-update behavior.\n\n### Read one entity\n\n```python\nentity = table.get_entity(\n    partition_key=\"inventory\",\n    row_key=\"sku-1001\",\n)\n\nprint(entity[\"name\"], entity[\"price\"])\n```\n\n### Query entities with OData filters\n\nPrefer parameterized filters over string interpolation when possible:\n\n```python\nentities = table.query_entities(\n    query_filter=\"PartitionKey eq @pk and price gt @minimum\",\n    parameters={\"pk\": \"inventory\", \"minimum\": 5},\n    select=[\"RowKey\", \"name\", \"price\"],\n)\n\nfor item in entities:\n    print(item[\"RowKey\"], item[\"name\"], item[\"price\"])\n```\n\nIf you build filters manually, escape single quotes in string values to keep them OData-compliant.\n\n### Merge vs replace updates\n\n`MERGE` only updates supplied properties. `REPLACE` overwrites the entity and drops properties you omit.\n\n```python\nfrom azure.data.tables import UpdateMode\n\nentity = table.get_entity(partition_key=\"inventory\", row_key=\"sku-1001\")\nentity[\"price\"] = 8.99\n\ntable.update_entity(entity=entity, mode=UpdateMode.MERGE)\n```\n\nUse `UpdateMode.REPLACE` only when you intentionally want the submitted entity to become the full stored shape.\n\n### Delete an entity\n\n```python\ntable.delete_entity(\n    partition_key=\"inventory\",\n    row_key=\"sku-1001\",\n)\n```\n\n### Batch multiple operations in one transaction\n\n`submit_transaction()` is atomic, but only for entities in the same partition.\n\n```python\noperations = [\n    (\"create\", {\"PartitionKey\": \"inventory\", \"RowKey\": \"sku-1002\", \"name\": \"Pen\", \"price\": 1.25}),\n    (\"upsert\", {\"PartitionKey\": \"inventory\", \"RowKey\": \"sku-1003\", \"name\": \"Pencil\", \"price\": 0.75}),\n    (\"update\", {\"PartitionKey\": \"inventory\", \"RowKey\": \"sku-1001\", \"price\": 7.99}, {\"mode\": \"merge\"}),\n]\n\nresult = table.submit_transaction(operations)\nprint(result)\n```\n\nDesign constraints from Azure Table storage still matter here:\n\n- all entities in the transaction must share a partition key\n- a transaction can include at most 100 entities\n- total transaction payload must stay under 4 MiB\n\n### Async client usage\n\nAsync clients live under `azure.data.tables.aio` and should usually be used with `async with`:\n\n```python\nimport asyncio\nfrom azure.data.tables.aio import TableClient\n\nasync def main() -> None:\n    async with TableClient.from_connection_string(\n        conn_str=conn_str,\n        table_name=\"products\",\n    ) as table:\n        entity = await table.get_entity(\n            partition_key=\"inventory\",\n            row_key=\"sku-1001\",\n        )\n        print(entity[\"name\"])\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n### Endpoints\n\n- Azure Storage table endpoints commonly look like `https://<account>.table.core.windows.net`\n- Sovereign cloud storage endpoints use different domains such as `table.core.usgovcloudapi.net`\n- Cosmos DB for Table uses its own account endpoint; prefer the portal, SDK quickstart, or connection string rather than guessing the hostname\n\n### `audience` for `TokenCredential`\n\nWhen you use `TokenCredential`, the client defaults to the public cloud audience. Set `audience` explicitly for sovereign clouds or when targeting Cosmos-specific audiences.\n\nExamples from Microsoft Learn include:\n\n- `https://storage.azure.com`\n- `https://storage.azure.us`\n- `https://storage.azure.cn`\n- `https://cosmos.azure.com`\n- `https://cosmos.azure.us`\n- `https://cosmos.azure.cn`\n\n### Retries and transport options\n\nThe package uses `azure-core` pipeline options. Common client keyword args include retry settings such as `retry_total`, `retry_connect`, `retry_read`, and `retry_status`.\n\nExample:\n\n```python\nfrom azure.data.tables import TableServiceClient\n\nservice = TableServiceClient.from_connection_string(\n    conn_str=conn_str,\n    retry_total=5,\n    retry_status=5,\n)\n```\n\n## Common Pitfalls\n\n- `get_table_client(\"name\")` only constructs a client. It does not create the table.\n- Every entity must include both `PartitionKey` and `RowKey`; the pair must be unique.\n- `query_entities()` uses OData filters, not SQL. Parameterize filters or escape string values correctly.\n- `update_entity(mode=MERGE)` does not remove properties that are absent from your payload. `REPLACE` does.\n- Optimistic concurrency matters. Use `etag` and `match_condition` when you need to prevent overwriting a newer version of an entity.\n- Transaction batches only work within a single partition and are capped at 100 entities.\n- Table design is driven by `PartitionKey` and `RowKey`; there are no general secondary indexes like in a relational database.\n- `DefaultAzureCredential` behavior depends on the environment. Local failures are often missing Azure CLI login, missing environment variables, or missing managed identity role assignments.\n- For Entra ID in sovereign clouds, set both the authority host on the credential and the matching `audience` on the tables client.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `12.7.0` as the latest stable release, published on May 6, 2025.\n- The official package overview and API reference both document the `12.x` client family; the version used here `12.7.0` matches current stable PyPI metadata as of March 12, 2026.\n- The package is the supported replacement for `azure-cosmosdb-tables`. Do not start new work on the deprecated package unless you are maintaining legacy code during a migration.\n"
  },
  {
    "path": "content/azure/docs/digital-twins-core/javascript/DOC.md",
    "content": "---\nname: digital-twins-core\ndescription: \"Azure Digital Twins JavaScript client for Microsoft Entra ID auth, DTDL model setup, twin and relationship operations, and ADT query workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,digital-twins,iot,dtdl,javascript,azure-identity\"\n---\n\n# @azure/digital-twins-core JavaScript Package Guide\n\n## What This Package Is\n\n`@azure/digital-twins-core` is the Azure SDK package for Azure Digital Twins data-plane operations from JavaScript or Node.js.\n\nUse it when your code needs to:\n\n- create and inspect DTDL models\n- create, read, update, and delete digital twins\n- create and traverse relationships between twins\n- run ADT queries against twins and relationships\n- update components and publish telemetry to configured downstream routes\n\nThis guide is scoped to `@azure/digital-twins-core` `2.0.0`.\n\n## Golden Rules\n\n- Use the Azure Digital Twins instance root as the endpoint: `https://<instance>.api.<region>.digitaltwins.azure.net`\n- Authenticate with Microsoft Entra ID through `@azure/identity`; `DefaultAzureCredential` is the normal starting point\n- The caller needs Azure Digital Twins data-plane RBAC, typically `Azure Digital Twins Data Reader` for reads or `Azure Digital Twins Data Owner` for writes\n- The authenticated identity must belong to the same Microsoft Entra tenant as the target instance or requests can fail with `404 Sub-Domain not found`\n- `upsertDigitalTwin(...)` replaces the twin document you send; use `updateDigitalTwin(...)` or `updateComponent(...)` for patch-style changes\n- Query results are paged and eventually consistent, so read a known twin by ID when you need the latest state immediately after a write\n\n## Install\n\nInstall the SDK and Azure Identity:\n\n```bash\nnpm install @azure/digital-twins-core@2.0.0 @azure/identity\n```\n\nFor local development, sign in with Azure CLI or provide service-principal credentials:\n\n```bash\naz login\n```\n\n## Service Setup And Environment\n\nOne practical environment convention is:\n\n```bash\nexport AZURE_DIGITAL_TWINS_URL=\"https://<instance>.api.<region>.digitaltwins.azure.net\"\n```\n\nFor service-principal auth, `DefaultAzureCredential` also reads the standard Azure Identity variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\n## Authentication And Client Initialization\n\nCreate one `DigitalTwinsClient` and reuse it across the part of your app that talks to Azure Digital Twins.\n\n```js\nimport { DigitalTwinsClient } from \"@azure/digital-twins-core\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.AZURE_DIGITAL_TWINS_URL;\n\nif (!endpoint) {\n  throw new Error(\"Missing AZURE_DIGITAL_TWINS_URL\");\n}\n\nconst credential = new DefaultAzureCredential();\nexport const digitalTwinsClient = new DigitalTwinsClient(endpoint, credential);\n```\n\n## Core Usage\n\nAzure Digital Twins is model-first. Upload the DTDL model before creating twin instances that reference it.\n\n### Create DTDL models\n\n```js\nconst models = [\n  {\n    \"@id\": \"dtmi:example:Room;1\",\n    \"@type\": \"Interface\",\n    \"@context\": \"dtmi:dtdl:context;2\",\n    displayName: \"Room\",\n    contents: [\n      { \"@type\": \"Property\", name: \"Temperature\", schema: \"double\" },\n      { \"@type\": \"Telemetry\", name: \"Humidity\", schema: \"double\" },\n    ],\n  },\n];\n\nconst createdModels = await digitalTwinsClient.createModels(models);\n\nfor (const model of createdModels) {\n  console.log(model.id);\n}\n```\n\n### Upsert and read a twin\n\nSet the model through `$metadata.$model` when creating or replacing a twin.\n\n```js\nconst twinId = \"room-101\";\n\nawait digitalTwinsClient.upsertDigitalTwin(twinId, {\n  $metadata: {\n    $model: \"dtmi:example:Room;1\",\n  },\n  Temperature: 21.5,\n});\n\nconst storedTwin = await digitalTwinsClient.getDigitalTwin(twinId);\nconsole.log(storedTwin.$dtId, storedTwin.Temperature);\n```\n\n### Patch a twin\n\nUse JSON Patch operations when you only want to change specific properties.\n\n```js\nawait digitalTwinsClient.updateDigitalTwin(\"room-101\", [\n  { op: \"replace\", path: \"/Temperature\", value: 22.0 },\n]);\n```\n\n### Query twins\n\n`queryTwins(...)` returns a paged async iterator.\n\n```js\nconst query = `\n  SELECT twin\n  FROM digitaltwins twin\n  WHERE IS_OF_MODEL(twin, 'dtmi:example:Room;1')\n`;\n\nfor await (const twin of digitalTwinsClient.queryTwins(query)) {\n  console.log(twin.$dtId);\n}\n```\n\nIf you just wrote `room-101` and need its latest state immediately, call `getDigitalTwin(\"room-101\")` instead of waiting for the query index to reflect the write.\n\n### Create and traverse relationships\n\n```js\nconst relationship = {\n  $relationshipId: \"building-1-contains-room-101\",\n  $sourceId: \"building-1\",\n  $relationshipName: \"contains\",\n  $targetId: \"room-101\",\n};\n\nawait digitalTwinsClient.upsertRelationship(\n  \"building-1\",\n  relationship.$relationshipId,\n  relationship,\n);\n\nfor await (const rel of digitalTwinsClient.listRelationships(\"building-1\")) {\n  console.log(rel.$relationshipName, rel.$targetId);\n}\n\nfor await (const rel of digitalTwinsClient.listIncomingRelationships(\"room-101\")) {\n  console.log(rel.relationshipName, rel.sourceId);\n}\n```\n\nRelationship IDs are scoped to the source twin. Reusing the same relationship ID for the same source twin overwrites that relationship.\n\n### Update a component\n\nUse component patches when the model defines a component rather than a top-level property.\n\n```js\nawait digitalTwinsClient.updateComponent(\"room-101\", \"thermostat\", [\n  { op: \"replace\", path: \"/Temperature\", value: 23.0 },\n]);\n```\n\n## Minimal Script\n\nThis is a complete script that authenticates, ensures a twin exists, and reads it back:\n\n```js\nimport { DigitalTwinsClient } from \"@azure/digital-twins-core\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst endpoint = process.env.AZURE_DIGITAL_TWINS_URL;\n\nif (!endpoint) {\n  throw new Error(\"Missing AZURE_DIGITAL_TWINS_URL\");\n}\n\nconst client = new DigitalTwinsClient(endpoint, new DefaultAzureCredential());\n\nawait client.upsertDigitalTwin(\"room-101\", {\n  $metadata: {\n    $model: \"dtmi:example:Room;1\",\n  },\n  Temperature: 21.5,\n});\n\nconst twin = await client.getDigitalTwin(\"room-101\");\nconsole.log(JSON.stringify(twin, null, 2));\n```\n\n## Common Pitfalls\n\n- Passing a portal URL or a resource ID instead of the Azure Digital Twins instance endpoint root\n- Using a principal from a different Microsoft Entra tenant than the instance tenant\n- Treating `upsertDigitalTwin(...)` like a patch helper instead of a full twin replacement\n- Forgetting that `queryTwins(...)`, `listRelationships(...)`, and `listIncomingRelationships(...)` are async iterators\n- Expecting query results to reflect writes immediately instead of reading the twin by ID\n- Reusing a `DefaultAzureCredential` setup with an unexpected cached local login or stale environment variables\n\n## Version Notes For 2.0.0\n\n- This guide targets `@azure/digital-twins-core` `2.0.0`\n- Keep the endpoint, authentication, DTDL model, twin, relationship, and query patterns the same when moving between nearby `2.x` releases unless the maintainer reference calls out a breaking change\n- Prefer the current Microsoft Learn package index and overview README over older blog posts or pre-GA samples when checking signatures\n\n## Official Sources\n\n- Microsoft Learn package index: `https://learn.microsoft.com/en-us/javascript/api/@azure/digital-twins-core/`\n- Microsoft Learn overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/digital-twins-core-readme?view=azure-node-latest`\n- Microsoft Learn `DigitalTwinsClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/digital-twins-core/digitaltwinsclient?view=azure-node-latest`\n- Microsoft Learn Azure Digital Twins API and SDK overview: `https://learn.microsoft.com/en-us/azure/digital-twins/concepts-apis-sdks`\n- Microsoft Learn Azure Digital Twins authentication guidance: `https://learn.microsoft.com/en-us/azure/digital-twins/how-to-authenticate-client`\n- Microsoft Learn Azure Digital Twins query language guidance: `https://learn.microsoft.com/en-us/azure/digital-twins/concepts-query-language`\n- Maintainer README: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/digitaltwins/digital-twins-core/README.md`\n- npm package page: `https://www.npmjs.com/package/@azure/digital-twins-core`\n"
  },
  {
    "path": "content/azure/docs/digitaltwins-core/python/DOC.md",
    "content": "---\nname: digitaltwins-core\ndescription: \"azure-digitaltwins-core for Python with Azure Identity auth, model/twin operations, relationships, queries, and concurrency-aware updates\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,digitaltwins,iot,azure-identity,dtdl,twins\"\n---\n\n# azure-digitaltwins-core Python Package Guide\n\n## What It Is\n\n`azure-digitaltwins-core` is the Azure SDK package for Azure Digital Twins data-plane operations in Python.\n\nUse it when code needs to:\n\n- create, list, decommission, and delete DTDL models\n- create, fetch, patch, and delete digital twins\n- create, read, patch, and delete relationships\n- query twins and relationships with the ADT query language\n- manage event routes and publish twin or component telemetry\n\nPrimary clients:\n\n- sync: `azure.digitaltwins.core.DigitalTwinsClient`\n- async: `azure.digitaltwins.core.aio.DigitalTwinsClient`\n\n## Install\n\nFor the package version pinned in this session:\n\n```bash\npython -m pip install \"azure-digitaltwins-core==1.3.0\" azure-identity\n```\n\nPyPI metadata for `1.3.0` lists `Requires: Python >=3.7`.\n\nIf you use the async client or async Azure Identity credentials, install an async transport too:\n\n```bash\npython -m pip install aiohttp\n```\n\n## Golden Rules\n\n- Use Azure AD credentials from `azure-identity`; `DefaultAzureCredential` is the normal starting point.\n- Pass the instance URL as `endpoint`, for example `https://<instance>.api.<region>.digitaltwins.azure.net`.\n- The caller needs Azure Digital Twins data-plane RBAC, commonly `Azure Digital Twins Data Owner` for writes and `Azure Digital Twins Data Reader` for reads.\n- The authenticated identity must come from the same Microsoft Entra tenant as the Azure Digital Twins instance or requests can fail with `404 Sub-Domain not found`.\n- Query results are paged and eventually consistent. Microsoft documents query latency of less than 10 seconds in normal cases.\n- Use ETags plus `match_condition` on update or delete paths when concurrent writers are possible.\n\n## Authentication And Setup\n\n### Environment Variables\n\n```bash\nexport AZURE_URL=\"https://example.api.wus2.digitaltwins.azure.net\"\n```\n\nFor local service-principal auth, `DefaultAzureCredential` can use:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nFor local developer auth, `az login` is often enough.\n\n### Sync Client\n\n```python\nimport os\n\nfrom azure.digitaltwins.core import DigitalTwinsClient\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\nclient = DigitalTwinsClient(\n    endpoint=os.environ[\"AZURE_URL\"],\n    credential=credential,\n)\n```\n\n### Async Client\n\n```python\nimport os\n\nfrom azure.digitaltwins.core.aio import DigitalTwinsClient\nfrom azure.identity.aio import DefaultAzureCredential\n\ncredential = DefaultAzureCredential()\nclient = DigitalTwinsClient(\n    endpoint=os.environ[\"AZURE_URL\"],\n    credential=credential,\n)\n```\n\nClose async resources explicitly:\n\n```python\nawait client.close()\nawait credential.close()\n```\n\n### Useful Client Options\n\n`DigitalTwinsClient(..., **kwargs)` accepts Azure Core pipeline options. The useful ones in practice are:\n\n- `api_version`\n- `logging_enable`\n- `retry_total`, `retry_connect`, `retry_read`, `retry_status`\n- `retry_backoff_factor`, `retry_backoff_max`\n- `connection_timeout`, `read_timeout`\n\nPractical guidance:\n\n- set retries and timeouts deliberately for query-heavy or patch-heavy flows\n- keep `logging_enable=False` in production unless you are debugging request failures\n- override `api_version` only if you know the target instance supports it\n\n## Core Usage\n\n### Create DTDL Models\n\n`create_models()` takes a list of DTDL JSON interface definitions.\n\n```python\nimport os\n\nfrom azure.digitaltwins.core import DigitalTwinsClient\nfrom azure.identity import DefaultAzureCredential\n\nclient = DigitalTwinsClient(os.environ[\"AZURE_URL\"], DefaultAzureCredential())\n\nmodels = [\n    {\n        \"@id\": \"dtmi:example:Room;1\",\n        \"@type\": \"Interface\",\n        \"@context\": \"dtmi:dtdl:context;2\",\n        \"displayName\": \"Room\",\n        \"contents\": [\n            {\"@type\": \"Property\", \"name\": \"Temperature\", \"schema\": \"double\"},\n            {\"@type\": \"Telemetry\", \"name\": \"Humidity\", \"schema\": \"double\"},\n        ],\n    }\n]\n\ncreated = client.create_models(models)\nprint(created[0][\"id\"])\n```\n\n### Upsert And Read A Twin\n\nSet the model through `$metadata.$model` when creating or replacing a twin.\n\n```python\ntwin_id = \"room-101\"\ntwin_body = {\n    \"$metadata\": {\"$model\": \"dtmi:example:Room;1\"},\n    \"Temperature\": 21.5,\n}\n\nclient.upsert_digital_twin(twin_id, twin_body)\nstored = client.get_digital_twin(twin_id)\nprint(stored[\"Temperature\"])\n```\n\n### Patch A Twin\n\n`update_digital_twin()` uses JSON Patch operations.\n\n```python\npatch = [\n    {\"op\": \"replace\", \"path\": \"/Temperature\", \"value\": 22.0},\n]\n\nclient.update_digital_twin(\"room-101\", patch)\n```\n\n### Query Twins\n\n`query_twins()` returns an iterator over a paged query result.\n\n```python\nquery = \"\"\"\nSELECT twin\nFROM digitaltwins twin\nWHERE IS_OF_MODEL(twin, 'dtmi:example:Room;1')\n\"\"\"\n\nfor item in client.query_twins(query):\n    print(item[\"$dtId\"])\n```\n\nIf code needs the latest value right after a write, prefer `get_digital_twin()` for the known ID instead of assuming the query index updated immediately.\n\n### Create And Traverse Relationships\n\n```python\nrelationship = {\n    \"$relationshipId\": \"building-1-contains-room-101\",\n    \"$sourceId\": \"building-1\",\n    \"$relationshipName\": \"contains\",\n    \"$targetId\": \"room-101\",\n}\n\nclient.upsert_relationship(\n    \"building-1\",\n    relationship[\"$relationshipId\"],\n    relationship,\n)\n\nfor rel in client.list_relationships(\"building-1\"):\n    print(rel[\"$relationshipName\"], rel[\"$targetId\"])\n```\n\nFor reverse traversal:\n\n```python\nfor rel in client.list_incoming_relationships(\"room-101\"):\n    print(rel[\"relationshipName\"], rel[\"sourceId\"])\n```\n\n### Update A Component\n\nUse component patches when the model contains a component instead of a top-level property.\n\n```python\ncomponent_patch = [\n    {\"op\": \"replace\", \"path\": \"/Temperature\", \"value\": 23.0},\n]\n\nclient.update_component(\"room-101\", \"thermostat\", component_patch)\n```\n\n### Publish Telemetry\n\nTwin telemetry:\n\n```python\nclient.publish_telemetry(\n    \"room-101\",\n    {\"Humidity\": 48.2},\n    message_id=\"humidity-20260312-01\",\n)\n```\n\nComponent telemetry:\n\n```python\nclient.publish_component_telemetry(\n    \"room-101\",\n    \"thermostat\",\n    {\"Humidity\": 48.2},\n    message_id=\"component-20260312-01\",\n)\n```\n\nTelemetry is only useful if the instance has event routes configured to send it to Event Grid, Event Hubs, or Service Bus.\n\n### Event Routes\n\nThe client can create and manage event routes once the destination endpoints exist.\n\n```python\nfrom azure.digitaltwins.core import DigitalTwinsEventRoute\n\nroute = DigitalTwinsEventRoute(\n    endpoint_name=\"eh-endpoint\",\n    filter=\"type = 'Microsoft.DigitalTwins.Twin.Update'\",\n)\n\nclient.upsert_event_route(\"twin-updates\", route)\n```\n\n## Concurrency And Conditional Writes\n\nThe `1.3.0` client exposes `etag` and `match_condition` on update, upsert, and delete operations such as:\n\n- `upsert_digital_twin`\n- `upsert_relationship`\n- `update_component`\n- `update_digital_twin`\n- `delete_digital_twin`\n- `delete_relationship`\n\nUse them when multiple workers may touch the same twin or relationship:\n\n```python\nfrom azure.core import MatchConditions\n\ncurrent = client.get_digital_twin(\"room-101\")\netag = current[\"$etag\"]\n\nclient.update_digital_twin(\n    \"room-101\",\n    [{\"op\": \"replace\", \"path\": \"/Temperature\", \"value\": 24.0}],\n    etag=etag,\n    match_condition=MatchConditions.IfNotModified,\n)\n```\n\nWithout this, a later writer can silently overwrite an earlier update.\n\n## Error Handling\n\nExpect Azure Core exceptions:\n\n- `azure.core.exceptions.ResourceNotFoundError`\n- `azure.core.exceptions.ResourceExistsError`\n- `azure.core.exceptions.HttpResponseError`\n- auth failures raised by `azure-identity`\n\n```python\nfrom azure.core.exceptions import HttpResponseError, ResourceNotFoundError\n\ntry:\n    twin = client.get_digital_twin(\"room-101\")\nexcept ResourceNotFoundError:\n    print(\"twin not found\")\nexcept HttpResponseError as exc:\n    print(f\"request failed: {exc.status_code} {exc.message}\")\n```\n\n## Common Pitfalls\n\n- Import name is `azure.digitaltwins.core`, not `azure_digitaltwins_core`.\n- `DefaultAzureCredential` tries several credential sources in order. A stale local login can be selected before the credential you expected.\n- Azure Digital Twins uses tenant-bound auth. Cross-tenant identities commonly fail even when the URL is correct.\n- Query language does not support every SQL habit. Check query restrictions before assuming aggregations or ordering are available.\n- `upsert_digital_twin()` replaces the twin document you send. Do not treat it like a patch helper.\n- Relationship IDs are scoped to the source twin. Reusing a relationship ID with the same source twin overwrites that relationship.\n- Async code must close both the client and the async credential.\n\n## Version-Sensitive Notes For `1.3.0`\n\n- This guide is intentionally pinned to the version used here `1.3.0`.\n- PyPI currently lists `1.3.0` as the latest release.\n- Microsoft Learn package readme examples align with the `1.3.0` API surface, including telemetry publishing and conditional update parameters.\n- Older blog posts for `1.0.x` often miss `etag` and `match_condition` kwargs on write operations. Prefer current Microsoft Learn signatures when writing new code.\n- The package metadata still allows Python `>=3.7`, but check the rest of your Azure SDK stack before standardizing on an older interpreter.\n\n## Official Sources Used\n\n- Microsoft Learn package index: `https://learn.microsoft.com/en-us/python/api/azure-digitaltwins-core/`\n- Microsoft Learn package readme: `https://learn.microsoft.com/en-us/python/api/overview/azure/digitaltwins-core-readme?view=azure-python`\n- Microsoft Learn `DigitalTwinsClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-digitaltwins-core/azure.digitaltwins.core.digitaltwinsclient?view=azure-python`\n- Microsoft Learn Azure Digital Twins API and SDK overview: `https://learn.microsoft.com/en-us/azure/digital-twins/concepts-apis-sdks`\n- Microsoft Learn authentication guidance: `https://learn.microsoft.com/en-us/azure/digital-twins/how-to-authenticate-client`\n- Microsoft Learn Azure Identity readme: `https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python`\n- Microsoft Learn query language guidance: `https://learn.microsoft.com/en-us/azure/digital-twins/concepts-query-language`\n- PyPI package page: `https://pypi.org/project/azure-digitaltwins-core/`\n"
  },
  {
    "path": "content/azure/docs/event-hubs/javascript/DOC.md",
    "content": "---\nname: event-hubs\ndescription: \"Azure Event Hubs JavaScript client for connection strings or Entra ID auth, producing events, consuming with subscribe, and blob-backed checkpointing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.0.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,event-hubs,eventhubs,messaging,streaming,amqp,javascript\"\n---\n\n# Azure Event Hubs JavaScript Client\n\n## Golden Rule\n\nUse `@azure/event-hubs` with `EventHubProducerClient` for publishing and `EventHubConsumerClient` for receiving. Prefer Microsoft Entra ID with `DefaultAzureCredential` for deployed applications, use a connection string for local scripts or narrowly scoped automation, and always set the consumer `startPosition` deliberately so you know whether the process should read backlog or only new events.\n\nThis guide targets `@azure/event-hubs` `6.0.3`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @azure/event-hubs@6.0.3\n```\n\nIf you authenticate with Microsoft Entra ID, install `@azure/identity` too:\n\n```bash\nnpm install @azure/event-hubs@6.0.3 @azure/identity\n```\n\nIf you want blob-backed checkpoints for long-running consumers, install the checkpoint store and blob client packages too:\n\n```bash\nnpm install @azure/event-hubs@6.0.3 @azure/eventhubs-checkpointstore-blob @azure/storage-blob @azure/identity\n```\n\nThe package ships its own TypeScript types.\n\n## Authentication And Setup\n\nYou usually connect in one of two ways:\n\n- connection string\n- fully qualified namespace plus a credential such as `DefaultAzureCredential`\n\nRecommended environment variables:\n\n```bash\nexport EVENTHUB_CONNECTION_STRING=\"Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=<policy>;SharedAccessKey=<key>\"\nexport EVENTHUB_FULLY_QUALIFIED_NAMESPACE=\"<namespace>.servicebus.windows.net\"\nexport EVENTHUB_NAME=\"<event-hub-name>\"\nexport EVENTHUB_CONSUMER_GROUP='$Default'\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<storage-account-name>\"\nexport EVENTHUB_CHECKPOINT_CONTAINER=\"eventhub-checkpoints\"\n```\n\nIf the Event Hubs connection string already includes `EntityPath=<event-hub-name>`, you can omit `EVENTHUB_NAME` for connection-string-based clients.\n\n### Preferred: `DefaultAzureCredential`\n\nUse passwordless auth in production, CI, and Azure-hosted workloads:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { EventHubProducerClient } from \"@azure/event-hubs\";\n\nconst fullyQualifiedNamespace = process.env.EVENTHUB_FULLY_QUALIFIED_NAMESPACE;\nconst eventHubName = process.env.EVENTHUB_NAME;\n\nif (!fullyQualifiedNamespace || !eventHubName) {\n  throw new Error(\n    \"EVENTHUB_FULLY_QUALIFIED_NAMESPACE and EVENTHUB_NAME are required\",\n  );\n}\n\nconst producer = new EventHubProducerClient(\n  fullyQualifiedNamespace,\n  eventHubName,\n  new DefaultAzureCredential(),\n);\n```\n\nThe identity needs an Event Hubs data-plane role that matches the operation:\n\n- `Azure Event Hubs Data Sender`\n- `Azure Event Hubs Data Receiver`\n- `Azure Event Hubs Data Owner`\n\n### Connection string fallback\n\nConnection strings are still the simplest option for local development and small automation jobs:\n\n```js\nimport { EventHubProducerClient } from \"@azure/event-hubs\";\n\nconst connectionString = process.env.EVENTHUB_CONNECTION_STRING;\nconst eventHubName = process.env.EVENTHUB_NAME;\n\nif (!connectionString) {\n  throw new Error(\"EVENTHUB_CONNECTION_STRING is required\");\n}\n\nconst producer = connectionString.includes(\"EntityPath=\")\n  ? new EventHubProducerClient(connectionString)\n  : new EventHubProducerClient(connectionString, eventHubName);\n```\n\n## Client Initialization\n\nCreate one long-lived producer or consumer client for the part of your app that talks to Event Hubs instead of constructing a new client for every operation.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { EventHubProducerClient } from \"@azure/event-hubs\";\n\nexport function createProducerClient() {\n  const connectionString = process.env.EVENTHUB_CONNECTION_STRING;\n  const eventHubName = process.env.EVENTHUB_NAME;\n\n  if (connectionString) {\n    if (connectionString.includes(\"EntityPath=\")) {\n      return new EventHubProducerClient(connectionString);\n    }\n\n    if (!eventHubName) {\n      throw new Error(\n        \"EVENTHUB_NAME is required when the connection string does not include EntityPath\",\n      );\n    }\n\n    return new EventHubProducerClient(connectionString, eventHubName);\n  }\n\n  const fullyQualifiedNamespace = process.env.EVENTHUB_FULLY_QUALIFIED_NAMESPACE;\n\n  if (!fullyQualifiedNamespace || !eventHubName) {\n    throw new Error(\n      \"Set EVENTHUB_CONNECTION_STRING, or set EVENTHUB_FULLY_QUALIFIED_NAMESPACE and EVENTHUB_NAME\",\n    );\n  }\n\n  return new EventHubProducerClient(\n    fullyQualifiedNamespace,\n    eventHubName,\n    new DefaultAzureCredential(),\n  );\n}\n```\n\nThe fully qualified namespace must be the host name, for example `<namespace>.servicebus.windows.net`.\n\n## Send Events\n\nUse `createBatch()` and `tryAdd(...)` instead of guessing the maximum message size yourself:\n\n```js\nimport { EventHubProducerClient } from \"@azure/event-hubs\";\n\nconst connectionString = process.env.EVENTHUB_CONNECTION_STRING;\nconst eventHubName = process.env.EVENTHUB_NAME;\n\nif (!connectionString) {\n  throw new Error(\"EVENTHUB_CONNECTION_STRING is required\");\n}\n\nconst producer = connectionString.includes(\"EntityPath=\")\n  ? new EventHubProducerClient(connectionString)\n  : new EventHubProducerClient(connectionString, eventHubName);\n\ntry {\n  const batch = await producer.createBatch();\n\n  if (\n    !batch.tryAdd({\n      body: { type: \"user.created\", userId: \"123\" },\n      contentType: \"application/json\",\n    })\n  ) {\n    throw new Error(\"The first event is too large to fit in an empty batch\");\n  }\n\n  if (\n    !batch.tryAdd({\n      body: { type: \"user.updated\", userId: \"123\" },\n      contentType: \"application/json\",\n    })\n  ) {\n    throw new Error(\"The second event is too large to fit in the current batch\");\n  }\n\n  await producer.sendBatch(batch);\n} finally {\n  await producer.close();\n}\n```\n\nIf `tryAdd(...)` fails on an empty batch, the individual event is too large for Event Hubs and must be reduced or split before sending.\n\n## Receive Events\n\nUse `subscribe(...)` for long-running consumers. The handler receives an array of events for a partition, not just one event at a time.\n\n```js\nimport {\n  EventHubConsumerClient,\n  earliestEventPosition,\n} from \"@azure/event-hubs\";\n\nconst consumerGroup = process.env.EVENTHUB_CONSUMER_GROUP ?? \"$Default\";\nconst connectionString = process.env.EVENTHUB_CONNECTION_STRING;\nconst eventHubName = process.env.EVENTHUB_NAME;\n\nif (!connectionString) {\n  throw new Error(\"EVENTHUB_CONNECTION_STRING is required\");\n}\n\nconst consumer = connectionString.includes(\"EntityPath=\")\n  ? new EventHubConsumerClient(consumerGroup, connectionString)\n  : new EventHubConsumerClient(consumerGroup, connectionString, eventHubName);\n\nconst subscription = consumer.subscribe(\n  {\n    async processEvents(events, context) {\n      for (const event of events) {\n        console.log(\n          context.partitionId,\n          event.sequenceNumber,\n          event.enqueuedTimeUtc,\n          event.body,\n        );\n      }\n    },\n    async processError(error, context) {\n      console.error(`Receive error on partition ${context.partitionId}:`, error);\n    },\n  },\n  {\n    startPosition: earliestEventPosition,\n  },\n);\n\nprocess.on(\"SIGINT\", async () => {\n  await subscription.close();\n  await consumer.close();\n  process.exit(0);\n});\n```\n\nSet `startPosition` explicitly:\n\n- `earliestEventPosition` to read existing backlog first\n- `latestEventPosition` to receive only new events that arrive after the consumer starts\n\n## Durable Checkpointing With Blob Storage\n\nUse blob-backed checkpointing when you need durable progress tracking and partition load balancing across long-running consumers.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport {\n  EventHubConsumerClient,\n  earliestEventPosition,\n} from \"@azure/event-hubs\";\nimport { BlobCheckpointStore } from \"@azure/eventhubs-checkpointstore-blob\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst fullyQualifiedNamespace = process.env.EVENTHUB_FULLY_QUALIFIED_NAMESPACE;\nconst eventHubName = process.env.EVENTHUB_NAME;\nconst consumerGroup = process.env.EVENTHUB_CONSUMER_GROUP ?? \"$Default\";\nconst storageAccountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst containerName =\n  process.env.EVENTHUB_CHECKPOINT_CONTAINER ?? \"eventhub-checkpoints\";\n\nif (!fullyQualifiedNamespace || !eventHubName || !storageAccountName) {\n  throw new Error(\n    \"EVENTHUB_FULLY_QUALIFIED_NAMESPACE, EVENTHUB_NAME, and AZURE_STORAGE_ACCOUNT_NAME are required\",\n  );\n}\n\nconst credential = new DefaultAzureCredential();\nconst blobServiceClient = new BlobServiceClient(\n  `https://${storageAccountName}.blob.core.windows.net`,\n  credential,\n);\nconst containerClient = blobServiceClient.getContainerClient(containerName);\n\nawait containerClient.createIfNotExists();\n\nconst checkpointStore = new BlobCheckpointStore(containerClient);\nconst consumer = new EventHubConsumerClient(\n  consumerGroup,\n  fullyQualifiedNamespace,\n  eventHubName,\n  credential,\n  checkpointStore,\n);\n\nconst subscription = consumer.subscribe(\n  {\n    async processEvents(events, context) {\n      if (events.length === 0) {\n        return;\n      }\n\n      for (const event of events) {\n        console.log(context.partitionId, event.sequenceNumber, event.body);\n      }\n\n      await context.updateCheckpoint(events[events.length - 1]);\n    },\n    async processError(error, context) {\n      console.error(`Checkpointed consumer error on ${context.partitionId}:`, error);\n    },\n  },\n  {\n    startPosition: earliestEventPosition,\n  },\n);\n\nprocess.on(\"SIGINT\", async () => {\n  await subscription.close();\n  await consumer.close();\n  process.exit(0);\n});\n```\n\nIf you use Microsoft Entra ID for the storage account too, the identity needs `Storage Blob Data Contributor` on the checkpoint container or storage account.\n\n## Practical Notes\n\n- Reuse long-lived producer and consumer clients instead of creating a new client for every send or receive.\n- Keep connection strings, SAS keys, and other secrets in environment variables or a secret manager, not in source code.\n- When you use a namespace-scoped connection string, pass `EVENTHUB_NAME` unless the connection string already contains `EntityPath`.\n- Use a checkpoint store for distributed or restartable consumers; otherwise each restart must decide its own starting position again.\n- Close clients and subscriptions during shutdown so AMQP links are released cleanly.\n\n## Common Pitfalls\n\n- Forgetting `EVENTHUB_NAME` when the connection string is namespace-scoped and has no `EntityPath`.\n- Leaving the consumer start position implicit and then wondering why old events were skipped.\n- Treating `subscribe(...)` as a single-event callback when `processEvents(...)` actually receives an array.\n- Creating a new `EventHubProducerClient` or `EventHubConsumerClient` for every operation instead of reusing them.\n- Running multiple consumers in the same consumer group without checkpointing and then being surprised by duplicate or restarted reads.\n- Treating `401` or `403` responses as SDK bugs before checking Event Hubs RBAC assignments and credential configuration.\n\n## Version Notes For `6.0.3`\n\n- This guide targets `@azure/event-hubs` `6.0.3`.\n- Keep new code on `EventHubProducerClient` and `EventHubConsumerClient` from the current package line.\n- When you copy older samples, update them to the current client constructors and `subscribe(...)` handler shape before using them in a new app.\n\n## Official Sources Used\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/event-hubs-readme?view=azure-node-latest`\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/event-hubs/?view=azure-node-latest`\n- `EventHubProducerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/event-hubs/eventhubproducerclient?view=azure-node-latest`\n- `EventHubConsumerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/event-hubs/eventhubconsumerclient?view=azure-node-latest`\n- Blob checkpoint store reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/eventhubs-checkpointstore-blob/blobcheckpointstore?view=azure-node-latest`\n- Azure Event Hubs quickstart for Node.js: `https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-node-get-started-send`\n- npm package page: `https://www.npmjs.com/package/@azure/event-hubs`\n"
  },
  {
    "path": "content/azure/docs/eventhub/python/DOC.md",
    "content": "---\nname: eventhub\ndescription: \"azure-eventhub package guide for Python 5.15.1 with install, auth, producer/consumer setup, checkpointing, and transport notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.15.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,eventhubs,messaging,streaming,amqp\"\n---\n\n# azure-eventhub Python Package Guide\n\n## What It Is\n\n`azure-eventhub` is the Azure SDK for sending events to, and receiving events from, Azure Event Hubs from Python.\n\nThis entry is for package version `5.15.1`. The official Microsoft Learn API and overview pages match the modern track-2 client surface built around `EventHubProducerClient`, `EventHubConsumerClient`, `EventData`, and `azure.eventhub.aio`.\n\n## Install\n\nBase package:\n\n```bash\npython -m pip install \"azure-eventhub==5.15.1\"\n```\n\nPasswordless Microsoft Entra authentication:\n\n```bash\npython -m pip install \"azure-eventhub==5.15.1\" azure-identity\n```\n\nBlob-backed checkpointing:\n\n```bash\npython -m pip install \"azure-eventhub==5.15.1\" azure-eventhub-checkpointstoreblob\n```\n\nAsync consumers with blob-backed checkpointing:\n\n```bash\npython -m pip install \"azure-eventhub==5.15.1\" azure-eventhub-checkpointstoreblob-aio azure-identity aiohttp\n```\n\n## Golden Rules\n\n- Prefer the `5.x` client types: `EventHubProducerClient` and `EventHubConsumerClient`.\n- If you use a namespace connection string, pass `eventhub_name` unless the connection string already includes `EntityPath=...`.\n- Set `starting_position` deliberately for consumers. The documented default is `@latest`, which only receives newly enqueued events.\n- Use a checkpoint store for long-running consumers that need durable progress and partition load balancing.\n- Do not share one client instance across threads or across concurrent coroutines; the SDK documents clients as neither thread-safe nor coroutine-safe.\n\n## Authentication And Setup\n\n### Connection string\n\nThis is the simplest setup path and works well for local development and service principals using SAS policies.\n\n```bash\nexport EVENT_HUB_CONNECTION_STR=\"Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=<policy>;SharedAccessKey=<key>\"\nexport EVENT_HUB_NAME=\"<event-hub-name>\"\n```\n\nIf the connection string already includes `EntityPath=<event-hub-name>`, you can usually omit `EVENT_HUB_NAME`.\n\n### Microsoft Entra credentials\n\nFor production Azure deployments, prefer `DefaultAzureCredential()` with RBAC.\n\nMinimum roles depend on the operation:\n\n- Sending: `Azure Event Hubs Data Sender`\n- Receiving: `Azure Event Hubs Data Receiver`\n- Full access: `Azure Event Hubs Data Owner`\n- Blob checkpointing: `Storage Blob Data Contributor` on the storage account or container\n\n```python\nimport os\n\nfrom azure.eventhub import EventHubProducerClient\nfrom azure.identity import DefaultAzureCredential\n\nproducer = EventHubProducerClient(\n    fully_qualified_namespace=os.environ[\"EVENT_HUB_HOSTNAME\"],\n    eventhub_name=os.environ[\"EVENT_HUB_NAME\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\n## Core Usage\n\n### Send events\n\n```python\nimport os\n\nfrom azure.eventhub import EventData, EventHubProducerClient\n\nproducer = EventHubProducerClient.from_connection_string(\n    conn_str=os.environ[\"EVENT_HUB_CONNECTION_STR\"],\n    eventhub_name=os.environ.get(\"EVENT_HUB_NAME\"),\n)\n\ntry:\n    batch = producer.create_batch()\n    batch.add(EventData(\"first event\"))\n    batch.add(EventData(\"second event\"))\n    producer.send_batch(batch)\nfinally:\n    producer.close()\n```\n\nUse `create_batch()` instead of guessing the AMQP frame size yourself. If `batch.add(...)` fails, start a new batch or reduce payload size.\n\n### Receive events\n\n```python\nimport os\n\nfrom azure.eventhub import EventHubConsumerClient\n\ndef on_event(partition_context, event):\n    print(\n        partition_context.partition_id,\n        event.sequence_number,\n        event.body_as_str(encoding=\"UTF-8\"),\n    )\n\nconsumer = EventHubConsumerClient.from_connection_string(\n    conn_str=os.environ[\"EVENT_HUB_CONNECTION_STR\"],\n    consumer_group=\"$Default\",\n    eventhub_name=os.environ.get(\"EVENT_HUB_NAME\"),\n)\n\ntry:\n    consumer.receive(\n        on_event=on_event,\n        starting_position=\"-1\",  # \"-1\" reads from the earliest available event.\n    )\nfinally:\n    consumer.close()\n```\n\nUse `starting_position=\"-1\"` for backlog replay. Use `starting_position=\"@latest\"` only when you explicitly want new events only.\n\n### Async clients\n\nUse the `.aio` namespace for async code.\n\n```python\nimport os\n\nfrom azure.eventhub.aio import EventHubProducerClient\n\nasync def make_producer():\n    producer = EventHubProducerClient.from_connection_string(\n        conn_str=os.environ[\"EVENT_HUB_CONNECTION_STR\"],\n        eventhub_name=os.environ.get(\"EVENT_HUB_NAME\"),\n    )\n    return producer\n```\n\nFor passwordless async code, use `azure.identity.aio.DefaultAzureCredential`.\n\n## Checkpointing And Load Balancing\n\nFor multi-partition or long-running consumers, add a blob checkpoint store instead of keeping offsets only in memory.\n\n```python\nimport os\n\nfrom azure.eventhub import EventHubConsumerClient\nfrom azure.eventhub.extensions.checkpointstoreblob import BlobCheckpointStore\n\ncheckpoint_store = BlobCheckpointStore.from_connection_string(\n    conn_str=os.environ[\"BLOB_STORAGE_CONNECTION_STRING\"],\n    container_name=os.environ[\"BLOB_CONTAINER_NAME\"],\n)\n\nconsumer = EventHubConsumerClient.from_connection_string(\n    conn_str=os.environ[\"EVENT_HUB_CONNECTION_STR\"],\n    consumer_group=\"$Default\",\n    eventhub_name=os.environ.get(\"EVENT_HUB_NAME\"),\n    checkpoint_store=checkpoint_store,\n)\n```\n\nOperational notes from the official docs:\n\n- `BlobCheckpointStore` is intended for `EventHubConsumerClient`, not as a general-purpose blob wrapper.\n- Keep one blob container per consumer group.\n- Do not use a hierarchical-namespace-enabled storage account for checkpointing.\n- Disable blob versioning, soft delete, and point-in-time restore on the checkpointing account.\n\nIf you skip `checkpoint_store`, the consumer can still receive events, but durable checkpoints and cooperative partition load balancing are not available.\n\n## Configuration Notes\n\n### Transport selection\n\nThe SDK supports:\n\n- `TransportType.Amqp` on port `5671`\n- `TransportType.AmqpOverWebsocket` on port `443`\n\nIf firewalls or proxies block `5671`, switch to websockets:\n\n```python\nimport os\n\nfrom azure.eventhub import EventHubProducerClient, TransportType\n\nproducer = EventHubProducerClient.from_connection_string(\n    conn_str=os.environ[\"EVENT_HUB_CONNECTION_STR\"],\n    eventhub_name=os.environ.get(\"EVENT_HUB_NAME\"),\n    transport_type=TransportType.AmqpOverWebsocket,\n)\n```\n\n### Consumer coordination and diagnostics\n\n- Use `owner_level` when you need an exclusive reader for a partition.\n- Set `track_last_enqueued_event_properties=True` if you need partition lag metadata on received events.\n- Use `logging_enable=True` and the `azure.eventhub` logger when troubleshooting connection or auth issues.\n- Tune `prefetch` if a consumer is buffering too much data in memory for your workload.\n\n## Version-Sensitive Notes\n\n- `5.15.1` is the current modern client line. Do not paste legacy `EventHubClient` examples from pre-5.x material into this version.\n- The package now uses a pure-Python AMQP stack by default. `uamqp` is optional and only used when installed and explicitly requested with `uamqp_transport=True`.\n- The current docs and samples are split between sync imports under `azure.eventhub` and async imports under `azure.eventhub.aio`.\n\n## Common Pitfalls\n\n- Forgetting `eventhub_name` when using a namespace-scoped connection string without `EntityPath`.\n- Receiving no backlog because `starting_position` was left at the default `@latest`.\n- Reusing one client object across threads or concurrent coroutines.\n- Running multiple consumers against the same partitions and consumer group without understanding duplicate-processing behavior.\n- Using blob checkpointing on a storage account with hierarchical namespace, soft delete, or versioning still enabled.\n- Debugging network connectivity without trying `TransportType.AmqpOverWebsocket`.\n\n## Official Sources Used\n\n- PyPI package page: `https://pypi.org/project/azure-eventhub/5.15.1/`\n- Microsoft Learn API index: `https://learn.microsoft.com/en-us/python/api/azure-eventhub/?view=azure-python`\n- Microsoft Learn overview/readme: `https://learn.microsoft.com/en-us/python/api/overview/azure/eventhub-readme?view=azure-python`\n- Microsoft Learn producer client reference: `https://learn.microsoft.com/en-us/python/api/azure-eventhub/azure.eventhub.eventhubproducerclient?view=azure-python`\n- Microsoft Learn consumer client reference: `https://learn.microsoft.com/en-us/python/api/azure-eventhub/azure.eventhub.eventhubconsumerclient?view=azure-python`\n- Microsoft Learn transport type reference: `https://learn.microsoft.com/en-us/python/api/azure-eventhub/azure.eventhub.transporttype?view=azure-python`\n- Microsoft Learn checkpoint store reference: `https://learn.microsoft.com/en-us/python/api/azure-eventhub-checkpointstoreblob/azure.eventhub.extensions.checkpointstoreblob.blobcheckpointstore?view=azure-python`\n- Microsoft Learn Event Hubs Python quickstart: `https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-python-get-started-send`\n"
  },
  {
    "path": "content/azure/docs/eventhubs-checkpointstore-blob/javascript/DOC.md",
    "content": "---\nname: eventhubs-checkpointstore-blob\ndescription: \"Azure Blob Storage checkpoint store for Event Hubs consumers with durable checkpoints and partition ownership coordination\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,event-hubs,eventhubs,checkpoint-store,blob-storage,javascript,nodejs\"\n---\n\n# Azure Event Hubs Blob Checkpoint Store For JavaScript\n\n## Golden Rule\n\nUse `@azure/eventhubs-checkpointstore-blob` as the blob-backed checkpoint store for `@azure/event-hubs` consumers. Create a `ContainerClient`, pass it to `new BlobCheckpointStore(containerClient)`, and then pass that checkpoint store to `EventHubConsumerClient`. Durable progress is only written when your event handler calls `context.updateCheckpoint(...)`.\n\nThis guide targets `@azure/eventhubs-checkpointstore-blob` `2.0.0`.\n\n## Install\n\nInstall the checkpoint store with the Event Hubs and Blob Storage clients it plugs into:\n\n```bash\nnpm install @azure/eventhubs-checkpointstore-blob@2.0.0 @azure/event-hubs@6.0.3 @azure/storage-blob\n```\n\nIf you want Microsoft Entra ID authentication, install `@azure/identity` too:\n\n```bash\nnpm install @azure/eventhubs-checkpointstore-blob@2.0.0 @azure/event-hubs@6.0.3 @azure/storage-blob @azure/identity\n```\n\n## Prerequisites\n\n- an Azure Event Hubs namespace and event hub\n- a consumer group such as `$Default`\n- an Azure Storage account and blob container for checkpoint records\n- if you use `DefaultAzureCredential`, a local `az login`, supported environment-based credentials, or a managed identity in Azure\n- Event Hubs data-plane RBAC for the consumer identity\n- `Storage Blob Data Contributor` on the checkpoint container or storage account when the storage account also uses Microsoft Entra ID\n\nRecommended environment variables:\n\n```bash\nexport EVENTHUB_FULLY_QUALIFIED_NAMESPACE=\"<namespace>.servicebus.windows.net\"\nexport EVENTHUB_NAME=\"<event-hub-name>\"\nexport EVENTHUB_CONSUMER_GROUP='$Default'\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<storage-account-name>\"\nexport EVENTHUB_CHECKPOINT_CONTAINER=\"eventhub-checkpoints\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"<storage-connection-string>\"\n```\n\n## Preferred Setup: `DefaultAzureCredential`\n\nUse one credential for both Event Hubs and Blob Storage when your app already uses Microsoft Entra ID:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport {\n  EventHubConsumerClient,\n  earliestEventPosition,\n} from \"@azure/event-hubs\";\nimport { BlobCheckpointStore } from \"@azure/eventhubs-checkpointstore-blob\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst fullyQualifiedNamespace = process.env.EVENTHUB_FULLY_QUALIFIED_NAMESPACE;\nconst eventHubName = process.env.EVENTHUB_NAME;\nconst consumerGroup = process.env.EVENTHUB_CONSUMER_GROUP ?? \"$Default\";\nconst storageAccountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst containerName =\n  process.env.EVENTHUB_CHECKPOINT_CONTAINER ?? \"eventhub-checkpoints\";\n\nif (!fullyQualifiedNamespace || !eventHubName || !storageAccountName) {\n  throw new Error(\n    \"EVENTHUB_FULLY_QUALIFIED_NAMESPACE, EVENTHUB_NAME, and AZURE_STORAGE_ACCOUNT_NAME are required\",\n  );\n}\n\nconst credential = new DefaultAzureCredential();\n\nconst blobServiceClient = new BlobServiceClient(\n  `https://${storageAccountName}.blob.core.windows.net`,\n  credential,\n);\n\nconst containerClient = blobServiceClient.getContainerClient(containerName);\nawait containerClient.createIfNotExists();\n\nconst checkpointStore = new BlobCheckpointStore(containerClient);\n\nconst consumer = new EventHubConsumerClient(\n  consumerGroup,\n  fullyQualifiedNamespace,\n  eventHubName,\n  credential,\n  checkpointStore,\n);\n\nconst subscription = consumer.subscribe(\n  {\n    async processEvents(events, context) {\n      if (events.length === 0) {\n        return;\n      }\n\n      for (const event of events) {\n        console.log(context.partitionId, event.sequenceNumber, event.body);\n      }\n\n      await context.updateCheckpoint(events[events.length - 1]);\n    },\n    async processError(error, context) {\n      console.error(`Consumer error on ${context.partitionId}:`, error);\n    },\n  },\n  {\n    startPosition: earliestEventPosition,\n  },\n);\n\nprocess.on(\"SIGINT\", async () => {\n  await subscription.close();\n  await consumer.close();\n  process.exit(0);\n});\n```\n\nUse `earliestEventPosition` when a new consumer should read existing backlog first. If you only want new events after startup, switch to `latestEventPosition` from `@azure/event-hubs`.\n\n## Create The Checkpoint Store From A Blob Connection String\n\nIf Blob Storage auth is managed separately from Event Hubs auth, build the checkpoint store from a storage connection string:\n\n```js\nimport { BlobCheckpointStore } from \"@azure/eventhubs-checkpointstore-blob\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;\nconst containerName =\n  process.env.EVENTHUB_CHECKPOINT_CONTAINER ?? \"eventhub-checkpoints\";\n\nif (!connectionString) {\n  throw new Error(\"AZURE_STORAGE_CONNECTION_STRING is required\");\n}\n\nconst blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);\nconst containerClient = blobServiceClient.getContainerClient(containerName);\n\nawait containerClient.createIfNotExists();\n\nconst checkpointStore = new BlobCheckpointStore(containerClient);\n```\n\nYou can then pass `checkpointStore` into your `EventHubConsumerClient` setup.\n\n## Common Workflow\n\nThe normal sequence is:\n\n1. create or get a blob container with `BlobServiceClient`\n2. create `new BlobCheckpointStore(containerClient)`\n3. construct `EventHubConsumerClient` with that checkpoint store\n4. call `consumer.subscribe(...)`\n5. call `context.updateCheckpoint(event)` after processing the event you want to commit\n\nThe checkpoint store is what lets long-running consumers resume from stored progress and coordinate partition ownership through Blob Storage.\n\n## Practical Notes\n\n- Reuse long-lived `BlobServiceClient`, `ContainerClient`, and `EventHubConsumerClient` instances instead of recreating them for every receive loop.\n- Create the checkpoint container during startup with `createIfNotExists()` so the consumer does not fail on the first ownership or checkpoint write.\n- Keep connection strings and other secrets in environment variables or a secret manager, not in source code.\n- With Microsoft Entra ID, make sure the same identity can read Event Hubs and write blobs before debugging the SDK surface.\n\n## Common Pitfalls\n\n- Forgetting `context.updateCheckpoint(...)` and then expecting the next process restart to resume from the last processed event.\n- Leaving `startPosition` implicit and then wondering why existing backlog was skipped.\n- Creating the `BlobCheckpointStore` but not passing it to `EventHubConsumerClient`.\n- Using a storage identity that can list containers but cannot write checkpoint blobs.\n- Hard-coding the blob endpoint incorrectly instead of using `https://<account>.blob.core.windows.net`.\n\n## Version Notes For `2.0.0`\n\n- This guide targets `@azure/eventhubs-checkpointstore-blob` `2.0.0`.\n- The documented package surface is `BlobCheckpointStore`, constructed with a `ContainerClient` from `@azure/storage-blob`.\n- The consumer examples use the current `EventHubConsumerClient.subscribe(...)` handler shape from `@azure/event-hubs`.\n\n## Official Sources Used\n\n- Microsoft Learn package API root: `https://learn.microsoft.com/en-us/javascript/api/@azure/eventhubs-checkpointstore-blob/`\n- `BlobCheckpointStore` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/eventhubs-checkpointstore-blob/blobcheckpointstore?view=azure-node-latest`\n- Event Hubs overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/event-hubs-readme?view=azure-node-latest`\n- `EventHubConsumerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/event-hubs/eventhubconsumerclient?view=azure-node-latest`\n- Storage Blob overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/storage-blob-readme?view=azure-node-latest`\n- `ContainerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-blob/containerclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/eventhubs-checkpointstore-blob`\n"
  },
  {
    "path": "content/azure/docs/identity/javascript/DOC.md",
    "content": "---\nname: identity\ndescription: \"Azure Identity for JavaScript: DefaultAzureCredential, managed identity, service principals, workload identity, bearer tokens, and auth configuration\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,identity,azure-identity,javascript,authentication,entra-id,managed-identity,workload-identity\"\n---\n\n# Azure Identity JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/identity` to supply `TokenCredential` instances to Azure SDK clients and other code that needs Microsoft Entra ID access tokens. Start with `DefaultAzureCredential` when the same code must work both locally and in Azure, but prefer a narrower credential such as `ManagedIdentityCredential`, `WorkloadIdentityCredential`, or `ClientSecretCredential` once the runtime environment is fixed.\n\nAuthentication only gets you a token. The identity still needs the correct Azure RBAC role or service-specific data-plane permissions on the target resource.\n\n## Install\n\nInstall `@azure/identity` and the Azure SDK client package you actually want to call:\n\n```bash\nnpm install @azure/identity@4.13.0 @azure/storage-blob\n```\n\nThis package version declares `node >=20.0.0` in its package metadata. It ships ESM, CommonJS, browser builds, and TypeScript types.\n\nIf you want `VisualStudioCodeCredential`, install its plugin package too:\n\n```bash\nnpm install @azure/identity-vscode\n```\n\n## Choose The Credential\n\nUse this selection rule:\n\n- `DefaultAzureCredential`: best default when the same code must run locally and in Azure.\n- `ManagedIdentityCredential`: best for Azure-hosted production workloads with managed identity enabled.\n- `WorkloadIdentityCredential`: best for AKS or other OIDC federation setups using workload identity.\n- `ClientSecretCredential`: use for CI or non-Azure hosting when a service principal secret is acceptable.\n- `ClientCertificateCredential`: use when the app registration authenticates with a certificate instead of a client secret.\n- `AzureCliCredential`, `AzureDeveloperCliCredential`, `DeviceCodeCredential`, or `InteractiveBrowserCredential`: useful for developer tools and scripts that need an interactive or user-bound flow.\n\nIf the app always runs in one environment, prefer the specific credential for that environment over `DefaultAzureCredential`.\n\n## DefaultAzureCredential\n\nIn `4.13.0`, `DefaultAzureCredential` tries these credential types in this order:\n\n1. `EnvironmentCredential`\n2. `WorkloadIdentityCredential`\n3. `ManagedIdentityCredential`\n4. `VisualStudioCodeCredential`\n5. `AzureCliCredential`\n6. `AzurePowerShellCredential`\n7. `AzureDeveloperCliCredential`\n8. Broker credential when `@azure/identity-broker` is installed\n\nMinimal Azure SDK client setup:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst accountUrl = process.env.AZURE_STORAGE_ACCOUNT_URL;\n\nif (!accountUrl) {\n  throw new Error(\"AZURE_STORAGE_ACCOUNT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new BlobServiceClient(accountUrl, credential);\n\nfor await (const container of client.listContainers()) {\n  console.log(container.name);\n}\n```\n\nGood defaults:\n\n- Reuse one credential instance instead of creating a new one for every request.\n- Let Azure SDK clients handle scopes automatically unless you are calling `getToken()` yourself.\n- Use `DefaultAzureCredential` to get development working quickly, then narrow the credential choice for production.\n\n## Local Development\n\nThe easiest path is to authenticate a developer tool that `DefaultAzureCredential` can reuse:\n\n```bash\naz login\n```\n\nOr:\n\n```bash\nazd auth login\n```\n\nThen run the same application code:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<storage-account>.blob.core.windows.net\"\n```\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst credential = new DefaultAzureCredential();\nconst client = new BlobServiceClient(\n  process.env.AZURE_STORAGE_ACCOUNT_URL,\n  credential,\n);\n\nfor await (const container of client.listContainers()) {\n  console.log(container.name);\n}\n```\n\nImportant behavior:\n\n- `EnvironmentCredential` runs before Azure CLI and Azure Developer CLI credentials, so leftover `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_CLIENT_SECRET` values can unexpectedly override your local CLI login.\n- If `AZURE_FEDERATED_TOKEN_FILE` and `AZURE_CLIENT_ID` are set, workload identity is attempted before managed identity.\n- `VisualStudioCodeCredential` is part of the default chain in this version, but it requires the `@azure/identity-vscode` plugin package and an Azure sign-in in the VS Code Azure Resources extension.\n\n## Production Credentials\n\n### Managed Identity\n\nUse managed identity for Azure-hosted apps when it is available:\n\n```js\nimport { ManagedIdentityCredential } from \"@azure/identity\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst credential = new ManagedIdentityCredential();\nconst client = new BlobServiceClient(\n  process.env.AZURE_STORAGE_ACCOUNT_URL,\n  credential,\n);\n\nfor await (const container of client.listContainers()) {\n  console.log(container.name);\n}\n```\n\nFor a user-assigned managed identity, pass exactly one selector:\n\n```js\nimport { ManagedIdentityCredential } from \"@azure/identity\";\n\nconst byClientId = new ManagedIdentityCredential(\"<managed-identity-client-id>\");\n\nconst byResourceId = new ManagedIdentityCredential({\n  resourceId:\n    \"/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<identity-name>\",\n});\n```\n\nOnly one of `clientId`, `resourceId`, or `objectId` can be provided.\n\n### Service Principal With A Secret\n\nUse this for CI or non-Azure hosting when a secret is acceptable:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<storage-account>.blob.core.windows.net\"\n```\n\n```js\nimport { BlobServiceClient } from \"@azure/storage-blob\";\nimport { ClientSecretCredential } from \"@azure/identity\";\n\nconst credential = new ClientSecretCredential(\n  process.env.AZURE_TENANT_ID,\n  process.env.AZURE_CLIENT_ID,\n  process.env.AZURE_CLIENT_SECRET,\n);\n\nconst client = new BlobServiceClient(\n  process.env.AZURE_STORAGE_ACCOUNT_URL,\n  credential,\n);\n\nfor await (const container of client.listContainers()) {\n  console.log(container.name);\n}\n```\n\n### Service Principal With A Certificate\n\nFor certificate-based app registrations, either use `EnvironmentCredential` with environment variables or construct `ClientCertificateCredential` directly.\n\nEnvironment-based configuration:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_CERTIFICATE_PATH=\"/path/to/cert.pem\"\nexport AZURE_CLIENT_CERTIFICATE_PASSWORD=\"<optional-password>\"\nexport AZURE_CLIENT_SEND_CERTIFICATE_CHAIN=true\n```\n\nExplicit credential setup:\n\n```js\nimport { ClientCertificateCredential } from \"@azure/identity\";\n\nconst credential = new ClientCertificateCredential(\n  process.env.AZURE_TENANT_ID,\n  process.env.AZURE_CLIENT_ID,\n  process.env.AZURE_CLIENT_CERTIFICATE_PATH,\n  {\n    certificatePassword: process.env.AZURE_CLIENT_CERTIFICATE_PASSWORD,\n    sendCertificateChain: true,\n  },\n);\n```\n\n### Workload Identity\n\nUse `WorkloadIdentityCredential` for AKS and other OIDC federation setups:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<app-or-user-assigned-managed-identity-client-id>\"\nexport AZURE_FEDERATED_TOKEN_FILE=\"/var/run/secrets/azure/tokens/azure-identity-token\"\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<storage-account>.blob.core.windows.net\"\n```\n\n```js\nimport { BlobServiceClient } from \"@azure/storage-blob\";\nimport { WorkloadIdentityCredential } from \"@azure/identity\";\n\nconst credential = new WorkloadIdentityCredential({\n  tenantId: process.env.AZURE_TENANT_ID,\n  clientId: process.env.AZURE_CLIENT_ID,\n  tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE,\n});\n\nconst client = new BlobServiceClient(\n  process.env.AZURE_STORAGE_ACCOUNT_URL,\n  credential,\n);\n\nfor await (const container of client.listContainers()) {\n  console.log(container.name);\n}\n```\n\n`DefaultAzureCredential` can pick up workload identity automatically, but explicit `WorkloadIdentityCredential` is clearer when the deployment model is fixed.\n\n## Non-SDK HTTP Calls\n\nUse `getToken()` when you need an access token for raw HTTP calls:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst credential = new DefaultAzureCredential();\nconst token = await credential.getToken(\n  \"https://management.azure.com/.default\",\n);\n\nconst response = await fetch(\n  \"https://management.azure.com/subscriptions?api-version=2020-01-01\",\n  {\n    headers: {\n      Authorization: `Bearer ${token.token}`,\n    },\n  },\n);\n\nconst data = await response.json();\nconsole.log(data.value);\n```\n\nUse `getBearerTokenProvider()` when another library wants a callback that can return a bearer token string:\n\n```js\nimport {\n  DefaultAzureCredential,\n  getBearerTokenProvider,\n} from \"@azure/identity\";\n\nconst credential = new DefaultAzureCredential();\nconst getAccessToken = getBearerTokenProvider(\n  credential,\n  \"https://cognitiveservices.azure.com/.default\",\n);\n\nconst token = await getAccessToken();\nconsole.log(token);\n```\n\n## Config And Auth Details\n\n### Environment Variables\n\nThe most common environment variables are:\n\n- `AZURE_TENANT_ID`\n- `AZURE_CLIENT_ID`\n- `AZURE_CLIENT_SECRET`\n- `AZURE_CLIENT_CERTIFICATE_PATH`\n- `AZURE_CLIENT_CERTIFICATE_PASSWORD`\n- `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`\n- `AZURE_FEDERATED_TOKEN_FILE`\n- `AZURE_AUTHORITY_HOST`\n- `AZURE_ADDITIONALLY_ALLOWED_TENANTS`\n\n`EnvironmentCredential` uses these precedence rules:\n\n- secret-based configuration first\n- certificate-based configuration second\n- username/password configuration last\n\nUsername/password authentication exists but is deprecated because it does not support MFA. Do not start new code with `UsernamePasswordCredential` or `AZURE_USERNAME` plus `AZURE_PASSWORD`.\n\n### Sovereign Clouds\n\nCredentials default to Azure Public Cloud. For Azure Government or another cloud, set the authority explicitly:\n\n```js\nimport { AzureAuthorityHosts, DefaultAzureCredential } from \"@azure/identity\";\n\nconst credential = new DefaultAzureCredential({\n  authorityHost: AzureAuthorityHosts.AzureGovernment,\n});\n```\n\nOr set it in the environment:\n\n```bash\nexport AZURE_AUTHORITY_HOST=\"https://login.microsoftonline.us\"\n```\n\n### Narrowing The Default Chain\n\nIf you want `DefaultAzureCredential` to fail fast or use fewer credential types, set `AZURE_TOKEN_CREDENTIALS`:\n\n```bash\nexport AZURE_TOKEN_CREDENTIALS=prod\n```\n\nOther supported values in this version are `dev` or a single credential name such as `ManagedIdentityCredential`, `AzureCliCredential`, or `WorkloadIdentityCredential`.\n\nYou can also require environment variables up front:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst credential = new DefaultAzureCredential({\n  requiredEnvVars: [\n    \"AZURE_TENANT_ID\",\n    \"AZURE_CLIENT_ID\",\n    \"AZURE_TOKEN_CREDENTIALS\",\n  ],\n});\n```\n\nThis throws immediately if any listed environment variable is missing or empty.\n\n## Common Pitfalls\n\n- Authentication succeeds but the service still returns `403` because the principal lacks RBAC or data-plane permissions.\n- Local service principal environment variables unexpectedly override Azure CLI or Azure Developer CLI login.\n- `DefaultAzureCredential` adds avoidable startup latency in production because it probes multiple credentials before finding the right one.\n- Trying to use `VisualStudioCodeCredential` without installing `@azure/identity-vscode`.\n- Passing more than one managed identity selector such as `clientId` and `resourceId` at the same time.\n- Forgetting the `/.default` suffix when calling `getToken()` for raw HTTP APIs.\n- Treating `EnvironmentCredential` as certificate-based when `AZURE_CLIENT_SECRET` is also set; secret-based configuration wins.\n- Starting new code with username/password authentication even though it is deprecated and incompatible with MFA.\n\n## Version Notes For `4.13.0`\n\n- This guide targets `@azure/identity` `4.13.0`.\n- Package metadata for this release declares `node >=20.0.0`.\n- `DefaultAzureCredential` in this release includes `VisualStudioCodeCredential`, `AzureCliCredential`, `AzurePowerShellCredential`, and `AzureDeveloperCliCredential` in addition to environment, workload identity, and managed identity credentials.\n- This release also supports `AZURE_TOKEN_CREDENTIALS` for narrowing the default chain and the `requiredEnvVars` option for fail-fast configuration checks.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/`\n- Package overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest`\n- Credential chains guidance: `https://aka.ms/azsdk/js/identity/credential-chains`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- `ManagedIdentityCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/managedidentitycredential?view=azure-node-latest`\n- `ClientSecretCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/clientsecretcredential?view=azure-node-latest`\n- `WorkloadIdentityCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/workloadidentitycredential?view=azure-node-latest`\n- Azure SDK source README: `https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity/README.md`\n- npm package page: `https://www.npmjs.com/package/@azure/identity`\n"
  },
  {
    "path": "content/azure/docs/identity/python/DOC.md",
    "content": "---\nname: identity\ndescription: \"Azure Identity for Python: DefaultAzureCredential, managed identity, service principals, workload identity, async credentials, and auth configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.25.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,identity,azure-identity,python,authentication,entra-id,managed-identity,workload-identity\"\n---\n\n# Azure Identity Python Package Guide\n\n## Golden Rule\n\nUse `azure-identity` for Microsoft Entra ID authentication in Python Azure SDK code. Start with `DefaultAzureCredential()` to get local development working quickly, but prefer a narrower credential such as `ManagedIdentityCredential`, `WorkloadIdentityCredential`, or `ClientSecretCredential` once the runtime environment is known.\n\nAuthentication success is not authorization success. The principal also needs the correct Azure RBAC or service-specific data-plane roles on the target resource.\n\n## Install\n\nPin the package version when you want behavior aligned with this entry:\n\n```bash\npython -m pip install \"azure-identity==1.25.2\"\n```\n\nIf you will use async credentials, install an async transport as well:\n\n```bash\npython -m pip install \"azure-identity==1.25.2\" aiohttp\n```\n\nIf you need brokered developer authentication on supported Windows or WSL setups:\n\n```bash\npython -m pip install \"azure-identity-broker\"\n```\n\n## Choose The Credential\n\nUse this selection rule:\n\n- `DefaultAzureCredential`: best default when the same code must run both locally and in Azure.\n- `ManagedIdentityCredential`: best for Azure-hosted production workloads with managed identity enabled.\n- `WorkloadIdentityCredential`: best for AKS or other OIDC federation setups that use workload identity.\n- `ClientSecretCredential`: use for CI or non-Azure hosting when a service principal secret is acceptable.\n- `CertificateCredential`: use when the app registration authenticates with a certificate instead of a secret.\n- `AzureCliCredential`, `AzureDeveloperCliCredential`, `AzurePowerShellCredential`: useful for explicit local-development-only flows.\n- `DeviceCodeCredential` or `InteractiveBrowserCredential`: useful for scripts and developer tools that need user sign-in.\n\nIf the app always runs in one environment, prefer the specific credential for that environment over `DefaultAzureCredential`.\n\n## DefaultAzureCredential\n\nIn `1.25.2`, `DefaultAzureCredential` tries these identities in order:\n\n1. Environment credential from service principal environment variables\n2. Workload identity\n3. Managed identity\n4. Shared token cache on Windows\n5. Visual Studio Code credential when supported and broker support is installed\n6. Azure CLI\n7. Azure PowerShell\n8. Azure Developer CLI\n9. Interactive browser, only if explicitly enabled\n10. Brokered authentication when `azure-identity-broker` is installed\n\nBasic Azure SDK client setup:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.blob import BlobServiceClient\n\naccount_url = \"https://<storage-account>.blob.core.windows.net\"\n\ncredential = DefaultAzureCredential()\nclient = BlobServiceClient(account_url=account_url, credential=credential)\n\nfor container in client.list_containers():\n    print(container[\"name\"])\n```\n\nGood defaults:\n\n- Reuse one credential instance instead of constructing a new one for every request.\n- Let Azure SDK clients handle scopes automatically unless you are calling `get_token()` yourself.\n- Use `DefaultAzureCredential` for early development, then tighten the credential choice for production.\n\n## Local Development\n\nThe easiest path is to authenticate one of the developer tools that `DefaultAzureCredential` can reuse:\n\n```bash\naz login\n```\n\nOr:\n\n```bash\nazd auth login\n```\n\nThen use the same application code:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.secrets import SecretClient\n\nvault_url = \"https://<vault-name>.vault.azure.net\"\n\ncredential = DefaultAzureCredential()\nclient = SecretClient(vault_url=vault_url, credential=credential)\n\nsecret = client.get_secret(\"example-secret\")\nprint(secret.value)\n```\n\nImportant behavior:\n\n- Since `1.14.0`, `DefaultAzureCredential` continues through developer credentials until one succeeds.\n- Deployed-service credentials still stop the chain if they can attempt token retrieval but fail.\n- Local environment variables such as `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_CLIENT_SECRET` can shadow your Azure CLI or `azd` login because `EnvironmentCredential` is tried first.\n\n## Production Credentials\n\n### Managed identity\n\nUse managed identity for Azure-hosted apps when available:\n\n```python\nfrom azure.identity import ManagedIdentityCredential\nfrom azure.storage.queue import QueueServiceClient\n\ncredential = ManagedIdentityCredential()\nclient = QueueServiceClient(\n    account_url=\"https://<storage-account>.queue.core.windows.net\",\n    credential=credential,\n)\n\nfor queue in client.list_queues():\n    print(queue[\"name\"])\n```\n\nFor a user-assigned managed identity, pass the client ID:\n\n```python\nfrom azure.identity import ManagedIdentityCredential\n\ncredential = ManagedIdentityCredential(client_id=\"<managed-identity-client-id>\")\n```\n\n### Service principal with a secret\n\nUse this for CI or non-Azure hosting when secrets are acceptable:\n\n```python\nfrom azure.identity import ClientSecretCredential\nfrom azure.mgmt.resource import SubscriptionClient\n\ncredential = ClientSecretCredential(\n    tenant_id=\"<tenant-id>\",\n    client_id=\"<client-id>\",\n    client_secret=\"<client-secret>\",\n)\n\nclient = SubscriptionClient(credential)\n\nfor subscription in client.subscriptions.list():\n    print(subscription.subscription_id)\n```\n\nEquivalent environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\n### Service principal with a certificate\n\n`EnvironmentCredential` also supports certificate-based authentication:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_CERTIFICATE_PATH=\"/path/to/cert.pem\"\nexport AZURE_CLIENT_CERTIFICATE_PASSWORD=\"<optional-password>\"\n```\n\nSet this only when Subject Name/Issuer authentication requires it:\n\n```bash\nexport AZURE_CLIENT_SEND_CERTIFICATE_CHAIN=true\n```\n\n### Workload identity\n\nUse `WorkloadIdentityCredential` for Kubernetes or OIDC federation setups. `DefaultAzureCredential` can pick it up automatically when the workload identity environment is configured, but it is often better to instantiate `WorkloadIdentityCredential` directly when the deployment model is fixed.\n\n## Non-SDK HTTP Calls\n\nUse `get_token()` when the target library is not an Azure SDK client:\n\n```python\nimport requests\nfrom azure.identity import ClientSecretCredential\n\ncredential = ClientSecretCredential(\n    tenant_id=\"<tenant-id>\",\n    client_id=\"<client-id>\",\n    client_secret=\"<client-secret>\",\n)\n\ntoken = credential.get_token(\"https://management.azure.com/.default\")\n\nresponse = requests.get(\n    \"https://management.azure.com/subscriptions?api-version=2020-01-01\",\n    headers={\"Authorization\": f\"Bearer {token.token}\"},\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n```\n\nFor Microsoft APIs protected by Entra ID, the scope is usually the resource URI plus `/.default`.\n\n## Async Credentials\n\nAsync credentials live under `azure.identity.aio` and should be paired with async Azure SDK clients:\n\n```python\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.keyvault.secrets.aio import SecretClient\n\ncredential = DefaultAzureCredential()\nclient = SecretClient(\"https://<vault-name>.vault.azure.net\", credential)\n\nsecret = await client.get_secret(\"example-secret\")\nprint(secret.value)\n\nawait credential.close()\n```\n\nA safer pattern is using the credential as an async context manager:\n\n```python\nfrom azure.identity.aio import DefaultAzureCredential\n\nasync with DefaultAzureCredential() as credential:\n    ...\n```\n\n## Config And Auth Details\n\n### Environment variables\n\n`EnvironmentCredential` and `DefaultAzureCredential` commonly depend on:\n\n- `AZURE_TENANT_ID`\n- `AZURE_CLIENT_ID`\n- `AZURE_CLIENT_SECRET`\n- `AZURE_CLIENT_CERTIFICATE_PATH`\n- `AZURE_CLIENT_CERTIFICATE_PASSWORD`\n- `AZURE_AUTHORITY_HOST`\n\nIf both secret and certificate settings are present, secret-based configuration wins.\n\n### Sovereign or private clouds\n\nCredentials default to Azure Public Cloud. For Azure Government or other clouds, set the authority explicitly:\n\n```python\nfrom azure.identity import AzureAuthorityHosts, DefaultAzureCredential\n\ncredential = DefaultAzureCredential(\n    authority=AzureAuthorityHosts.AZURE_GOVERNMENT,\n)\n```\n\nOr set it for the environment:\n\n```bash\nexport AZURE_AUTHORITY_HOST=\"https://login.microsoftonline.us\"\n```\n\nDeveloper-tool credentials such as `AzureCliCredential` use the tool's own cloud configuration instead of this setting.\n\n### Narrowing the default chain\n\nIf you need to control `DefaultAzureCredential` without rewriting code:\n\n```bash\nexport AZURE_TOKEN_CREDENTIALS=prod\n```\n\nOr choose one credential explicitly:\n\n```bash\nexport AZURE_TOKEN_CREDENTIALS=ManagedIdentityCredential\n```\n\nThen require the environment variable to be set:\n\n```python\nfrom azure.identity import DefaultAzureCredential\n\ncredential = DefaultAzureCredential(require_envvar=True)\n```\n\nVersion notes for this behavior:\n\n- `AZURE_TOKEN_CREDENTIALS=prod` and `dev` are supported in `azure-identity` `1.23.0+`\n- individual credential names are supported in `1.24.0+`\n\n### Continuous Access Evaluation\n\nCAE support is per-token-request:\n\n```python\ntoken = credential.get_token(\n    \"https://storage.azure.com/.default\",\n    enable_cae=True,\n)\n```\n\nCAE is not supported for developer credentials or managed identity credentials.\n\n### Token caching\n\n`azure-identity` uses in-memory token caching by default and also supports persistent disk caching for supported credential types. Caching improves performance, but it can also hide configuration drift during debugging, so inspect the active credential path when behavior looks inconsistent.\n\n## Common Pitfalls\n\n- Authentication succeeds but service calls still fail because the principal lacks RBAC or data-plane permissions.\n- Local service principal environment variables unexpectedly override Azure CLI or Azure Developer CLI credentials.\n- `DefaultAzureCredential` adds avoidable latency in production because it probes multiple credentials before finding the right one.\n- Async credentials are created but never closed.\n- The wrong cloud authority is used for sovereign cloud deployments.\n- CAE is enabled against a credential type that does not support it.\n- `azure-identity-broker` is expected to work everywhere; brokered auth is specifically tied to supported Windows or WSL scenarios.\n- Azure AD B2C is not supported by this library.\n\n## Version-Sensitive Notes\n\n- `1.25.2` is the current stable PyPI release as of March 12, 2026. PyPI also lists prerelease `1.26.0b2`, which should not be treated as the stable target.\n- `1.25.2` fixed token-cache bypass issues when claims are passed to `get_token()` or `get_token_info()`, improved empty-response error handling, bumped the minimum `msal` dependency to `>=1.31.0`, and added more debug logging for cache hits.\n- `1.24.0` added support for selecting an individual credential with `AZURE_TOKEN_CREDENTIALS`.\n- `1.24.0` also re-enabled `VisualStudioCodeCredential`, but it requires `azure-identity-broker`.\n- `1.24.0` dropped Python 3.8 support; current stable requires Python `>=3.9`.\n- `1.14.0` changed `DefaultAzureCredential` continuation behavior so developer credential failures no longer stop the chain.\n- `1.14.0` also added per-request CAE support.\n\n## Official Sources\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python`\n- Microsoft Learn credential chains guidance: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/credential-chains`\n- Microsoft Learn `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python`\n- Microsoft Learn async package reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.aio?view=azure-python`\n- PyPI package page and release history: `https://pypi.org/project/azure-identity/`\n"
  },
  {
    "path": "content/azure/docs/keyvault-certificates/javascript/DOC.md",
    "content": "---\nname: keyvault-certificates\ndescription: \"Azure Key Vault certificates JavaScript client for authenticating with DefaultAzureCredential and managing certificate create, get, import, list, delete, and recovery workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,keyvault,certificates,javascript,security,cloud\"\n---\n\n# Azure Key Vault Certificates JavaScript Client\n\n## Golden Rule\n\nUse `@azure/keyvault-certificates` with `CertificateClient` for certificate lifecycle operations in Azure Key Vault: create or import certificates, fetch the latest or a specific version, list certificate metadata, and delete or recover certificates. Pair it with `@azure/identity` for authentication, and treat every `begin*` method as a long-running operation that should finish with `await poller.pollUntilDone()` before the next dependent step.\n\nIf your workflow crosses Key Vault surfaces, use the adjacent packages for those surfaces instead of overloading the certificates client:\n\n- `@azure/identity` for credentials\n- `@azure/keyvault-secrets` for secret operations\n- `@azure/keyvault-keys` for key operations\n\n## Install\n\n```bash\nnpm install @azure/keyvault-certificates@4.10.0 @azure/identity\n```\n\nThe package includes TypeScript types.\n\n## Authentication And Setup\n\nThe normal setup uses `DefaultAzureCredential`, which can use your Azure CLI login locally, managed identity in Azure, or service principal environment variables.\n\nFor local development:\n\n```bash\naz login\nexport KEY_VAULT_URL=\"https://<your-key-vault>.vault.azure.net\"\n```\n\nIf you use a service principal instead of Azure CLI or managed identity:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport KEY_VAULT_URL=\"https://<your-key-vault>.vault.azure.net\"\n```\n\nAuthorization notes:\n\n- `@azure/keyvault-certificates` does not authenticate by itself; you must provide a credential.\n- Use the full vault URL, not just the vault name.\n- If requests fail with `403 Forbidden`, check that the identity has Key Vault data-plane permissions for certificates.\n- In Azure RBAC setups, the official quickstart uses the `Key Vault Certificates Officer` role for certificate management.\n\n## Initialize A Client\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { CertificateClient } from \"@azure/keyvault-certificates\";\n\nconst vaultUrl = process.env.KEY_VAULT_URL;\n\nif (!vaultUrl) {\n  throw new Error(\"KEY_VAULT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new CertificateClient(vaultUrl, credential);\n```\n\nCreate one shared `CertificateClient` for the part of your app that talks to Key Vault instead of creating a new client per operation.\n\n## Core Usage\n\n### Create A Self-Signed Certificate\n\nUse `beginCreateCertificate(...)` and wait for the poller to complete.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { CertificateClient } from \"@azure/keyvault-certificates\";\n\nconst client = new CertificateClient(\n  process.env.KEY_VAULT_URL,\n  new DefaultAzureCredential(),\n);\n\nconst createPoller = await client.beginCreateCertificate(\"app-cert\", {\n  issuerName: \"Self\",\n  subject: \"CN=app-cert\",\n});\n\nconst created = await createPoller.pollUntilDone();\n\nconsole.log(created.name);\nconsole.log(created.properties.version);\n```\n\nFor issuer-backed or more customized certificates, pass a fuller certificate policy instead of the minimal self-signed policy above.\n\n### Get The Latest Certificate Or A Specific Version\n\nUse `getCertificate(...)` for the latest version. Use `getCertificateVersion(...)` when you already know the exact version you need.\n\n```js\nconst latest = await client.getCertificate(\"app-cert\");\n\nconsole.log(latest.name);\nconsole.log(latest.properties.version);\nconsole.log(latest.policy?.issuerName);\n\nconst exactVersion = await client.getCertificateVersion(\n  \"app-cert\",\n  \"certificate-version-id\",\n);\n\nconsole.log(exactVersion.properties.version);\n```\n\n### List Certificate Metadata And Versions\n\nList operations return certificate properties, which is what you usually want for inventory and version inspection.\n\n```js\nfor await (const properties of client.listPropertiesOfCertificates()) {\n  console.log(properties.name, properties.enabled);\n}\n\nfor await (const properties of client.listPropertiesOfCertificateVersions(\"app-cert\")) {\n  console.log(properties.version, properties.createdOn);\n}\n```\n\nIf you need the deleted-certificate record after a delete operation, fetch it explicitly:\n\n```js\nconst deleted = await client.getDeletedCertificate(\"app-cert\");\nconsole.log(deleted.recoveryId);\n```\n\n### Import An Existing Certificate\n\nUse `importCertificate(...)` when you already have a certificate file that includes its private key.\n\n```js\nimport { readFile } from \"node:fs/promises\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { CertificateClient } from \"@azure/keyvault-certificates\";\n\nconst client = new CertificateClient(\n  process.env.KEY_VAULT_URL,\n  new DefaultAzureCredential(),\n);\n\nconst pfx = await readFile(\"./certificate.pfx\");\n\nconst imported = await client.importCertificate(\"imported-cert\", pfx, {\n  password: process.env.CERTIFICATE_PASSWORD,\n});\n\nconsole.log(imported.name);\nconsole.log(imported.properties.version);\n```\n\nWhen import fails, check the file format, the presence of the private key, and whether the password matches the certificate archive.\n\n### Recover Or Permanently Delete A Certificate\n\nKey Vault soft-delete behavior matters for automation. Deleting a certificate and immediately recreating it can fail until the deleted certificate is recovered or purged.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { CertificateClient } from \"@azure/keyvault-certificates\";\n\nconst client = new CertificateClient(\n  process.env.KEY_VAULT_URL,\n  new DefaultAzureCredential(),\n);\n\nconst deletePoller = await client.beginDeleteCertificate(\"app-cert\");\nconst deleted = await deletePoller.pollUntilDone();\n\nconsole.log(deleted.name);\n\nconst recoverPoller = await client.beginRecoverDeletedCertificate(\"app-cert\");\nconst recovered = await recoverPoller.pollUntilDone();\n\nconsole.log(recovered.name);\n```\n\n`purgeDeletedCertificate(...)` is irreversible and only succeeds when the vault's recovery level allows purging.\n\nTo permanently remove a certificate instead of recovering it, delete it again, wait for that poller to finish, and then call `await client.purgeDeletedCertificate(\"app-cert\")`.\n\n## Common Pitfalls\n\n- Installing `@azure/keyvault-certificates` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Passing only the vault name when the client expects the full `https://<name>.vault.azure.net` URL.\n- Assuming `beginCreateCertificate(...)`, `beginDeleteCertificate(...)`, or `beginRecoverDeletedCertificate(...)` finish immediately.\n- Expecting list operations to return the same payload as `getCertificate(...)`.\n- Recreating a deleted certificate name immediately without accounting for soft-delete and purge protection.\n- Treating `401` or `403` responses as SDK bugs before checking Azure identity setup and Key Vault permissions.\n- Using the certificates client for secret or key workflows that belong in `@azure/keyvault-secrets` or `@azure/keyvault-keys`.\n\n## Version Notes For `4.10.0`\n\n- This guide targets `@azure/keyvault-certificates` `4.10.0`.\n- If you find older examples using the legacy `azure-keyvault` package, rewrite them to the current `@azure/keyvault-certificates` and `@azure/identity` APIs.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-certificates/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/keyvault-certificates-readme?view=azure-node-latest`\n- `CertificateClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-certificates/certificateclient?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/keyvault-certificates`\n"
  },
  {
    "path": "content/azure/docs/keyvault-certificates/python/DOC.md",
    "content": "---\nname: keyvault-certificates\ndescription: \"Azure Key Vault certificates SDK for Python with CertificateClient setup, auth, create/import flows, async usage, and deletion/recovery patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.10.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,keyvault,certificates,python,security,cloud\"\n---\n\n# azure-keyvault-certificates Python Package Guide\n\n## What This Package Does\n\n`azure-keyvault-certificates` is the official Azure SDK package for managing certificates in Azure Key Vault from Python. Use `CertificateClient` to create certificates, fetch the latest or a specific version, update mutable properties, import externally created certificates, list certificate metadata, and delete or recover certificates.\n\nThis package also exposes issuer, contact, backup, restore, and certificate policy operations, but most agent tasks start with `CertificateClient`.\n\nUse adjacent packages when your workflow crosses Key Vault surfaces:\n\n- `azure-identity` for authentication\n- `azure-keyvault-secrets` for secret workflows\n- `azure-keyvault-keys` for key workflows\n\n## Install\n\n```bash\npip install \"azure-keyvault-certificates==4.10.0\" azure-identity\n```\n\nFor async code, install an async transport as well:\n\n```bash\npip install aiohttp\n```\n\n## Version-Sensitive Notes\n\n- This guide covers package version `4.10.0`, which PyPI lists as released on `2025-06-16`.\n- `4.10.0` requires Python `3.9+`. Microsoft Learn's package overview, the PyPI metadata, and the upstream changelog agree on that. The quickstart page still says Python `3.7+`, which appears stale for this package version.\n- `4.10.0` adds service API version `7.6`, makes `7.6` the default service API version, and uses the keyword argument `preserve_order` for certificate chain ordering.\n- If you copied beta examples for `4.10.0b1`, rename `preserve_certificate_order` to `preserve_order`.\n\n## Auth And Setup\n\nYou need:\n\n- an Azure subscription\n- an Azure Key Vault\n- permission to manage certificates in that vault\n\nFor local development, the official docs use `DefaultAzureCredential` plus `az login`. For production, Microsoft recommends a managed identity.\n\n```bash\naz login\nexport VAULT_URL=\"https://<your-key-vault>.vault.azure.net\"\n```\n\nIf you are using Azure RBAC, the current quickstart assigns the `Key Vault Certificates Officer` role to manage certificates.\n\nMinimum permissions depend on the operations you call:\n\n- create: `certificates/create`\n- get: `certificates/get`\n- list: `certificates/list`\n- import: `certificates/import`\n- delete: `certificates/delete`\n- recover: `certificates/recover`\n- purge: `certificates/purge`\n\nWaiting on some pollers also requires `certificates/get`.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.certificates import CertificateClient\n\nvault_url = os.environ[\"VAULT_URL\"]\ncredential = DefaultAzureCredential()\nclient = CertificateClient(vault_url=vault_url, credential=credential)\n```\n\nIf your environment only exposes the vault name, build the URL as `https://<name>.vault.azure.net`.\n\nAdvanced constructor options that matter in real deployments:\n\n- `api_version=\"7.5\"` or another supported version when you must pin the Key Vault service API instead of using the latest default\n- `verify_challenge_resource=False` only for non-standard Key Vault domain scenarios where Azure explicitly tells you to disable challenge-resource validation\n\n## Common Sync Workflow\n\nThis covers the core operations most agents need first: create, fetch, update, list, inspect versions, and delete.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.certificates import CertificateClient, CertificatePolicy\n\ncredential = DefaultAzureCredential()\n\nwith CertificateClient(\n    vault_url=\"https://my-key-vault.vault.azure.net/\",\n    credential=credential,\n) as client:\n    create_poller = client.begin_create_certificate(\n        certificate_name=\"app-cert\",\n        policy=CertificatePolicy.get_default(),\n    )\n    created = create_poller.result()\n    print(created.name)\n    print(created.properties.version)\n\n    current = client.get_certificate(\"app-cert\")\n    print(current.policy.issuer_name)\n\n    updated = client.update_certificate_properties(\n        certificate_name=\"app-cert\",\n        enabled=False,\n        tags={\"env\": \"dev\"},\n    )\n    print(updated.properties.enabled)\n\n    for props in client.list_properties_of_certificates():\n        print(props.name)\n\n    for version in client.list_properties_of_certificate_versions(\"app-cert\"):\n        print(version.version)\n\n    delete_poller = client.begin_delete_certificate(\"app-cert\")\n    deleted = delete_poller.result()\n    print(deleted.name)\n```\n\nWhen you need a specific version instead of the latest one:\n\n```python\ncert = client.get_certificate_version(\n    certificate_name=\"app-cert\",\n    version=\"certificate-version-id\",\n)\nprint(cert.properties.version)\n```\n\nUse `get_certificate` when you need the latest certificate with its management policy. Use `get_certificate_version` when you need one exact version and do not need the policy object.\n\n## Import An Existing Certificate\n\nUse `import_certificate` when you already have a certificate file with its private key.\n\n```python\nfrom pathlib import Path\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.certificates import CertificateClient\n\ncredential = DefaultAzureCredential()\nwith CertificateClient(\n    vault_url=\"https://my-key-vault.vault.azure.net/\",\n    credential=credential,\n) as client:\n    imported = client.import_certificate(\n        certificate_name=\"imported-cert\",\n        certificate_bytes=Path(\"certificate.pfx\").read_bytes(),\n        password=\"pfx-password\",\n        preserve_order=True,\n    )\n\nprint(imported.name)\n```\n\nImportant import rules from the official API docs:\n\n- the imported certificate must contain the private key\n- supported formats are `PFX` and `PEM`\n- if you import `PEM`, the PEM must contain both the key and the x509 certificates\n- for `PEM`, pass a `policy` whose `content_type` is `pem`\n- in `4.10.0`, use `preserve_order`, not the beta name `preserve_certificate_order`\n\n## Recovery And Permanent Deletion\n\nKey Vault soft-delete behavior matters for automation. Deleting a certificate and immediately recreating it often fails until the deleted resource is recovered or purged.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.certificates import CertificateClient\n\ncredential = DefaultAzureCredential()\nwith CertificateClient(\n    vault_url=\"https://my-key-vault.vault.azure.net/\",\n    credential=credential,\n) as client:\n    delete_poller = client.begin_delete_certificate(\"app-cert\")\n    deleted = delete_poller.result()\n\n    recover_poller = client.begin_recover_deleted_certificate(\"app-cert\")\n    recovered = recover_poller.result()\n    print(recovered.name)\n\n    delete_poller = client.begin_delete_certificate(\"app-cert\")\n    delete_poller.wait()\n    client.purge_deleted_certificate(\"app-cert\")\n```\n\n`purge_deleted_certificate` is irreversible and only works when the vault's recovery level allows purging.\n\n## Async Usage\n\nThe package has async APIs under `azure.keyvault.certificates.aio`. Install an async transport first and close both the client and credential when finished.\n\n```python\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.keyvault.certificates import CertificatePolicy\nfrom azure.keyvault.certificates.aio import CertificateClient\n\nasync with DefaultAzureCredential() as credential:\n    async with CertificateClient(\n        vault_url=\"https://my-key-vault.vault.azure.net/\",\n        credential=credential,\n    ) as client:\n        result = await client.create_certificate(\n            certificate_name=\"async-cert\",\n            policy=CertificatePolicy.get_default(),\n        )\n        print(result.name)\n\n        async for props in client.list_properties_of_certificates():\n            print(props.name)\n```\n\n## Common Pitfalls\n\n- `begin_create_certificate`, `begin_delete_certificate`, and `begin_recover_deleted_certificate` are long-running operations. Use `.result()` or `.wait()` before the next dependent step.\n- `get_certificate` returns the latest version with the management policy attached. `get_certificate_version` returns one version without the policy. Choose the one that matches your next operation.\n- `list_properties_of_certificates()` and `list_properties_of_certificate_versions()` return identifiers and properties, not the full certificate payload.\n- The quickstart uses `KEY_VAULT_NAME`, but `CertificateClient` takes the full `vault_url`.\n- `DefaultAzureCredential` is the default choice, but it only works if one of its credential sources is configured. For local work, `az login` is usually the fastest path.\n- Deleting a certificate in a soft-delete-enabled vault leaves it recoverable. Reusing the same name can fail with a conflict until you recover or purge it.\n- For custom policies, `begin_create_certificate` requires a valid certificate policy. A bad policy raises `ValueError`; service failures raise `HttpResponseError`.\n- Enabling SDK HTTP logging can expose URLs, headers, and other request details. Treat `logging_enable=True` as sensitive.\n\n## Official Sources\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/keyvault-certificates-readme?view=azure-python`\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/python/api/azure-keyvault-certificates/`\n- Microsoft Learn `CertificateClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-keyvault-certificates/azure.keyvault.certificates.certificateclient?view=azure-python`\n- Microsoft Learn quickstart: `https://learn.microsoft.com/en-us/azure/key-vault/certificates/quick-create-python`\n- PyPI package page: `https://pypi.org/project/azure-keyvault-certificates/4.10.0/`\n- Azure SDK for Python changelog: `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/main/sdk/keyvault/azure-keyvault-certificates/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/keyvault-keys/javascript/DOC.md",
    "content": "---\nname: keyvault-keys\ndescription: \"Azure Key Vault Keys client library for creating, managing, and using cryptographic keys from JavaScript and TypeScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,key-vault,keys,kms,cryptography,javascript\"\n---\n\n# Azure Key Vault Keys JavaScript Client\n\n## Golden Rule\n\nUse `@azure/keyvault-keys` for key lifecycle operations, pair it with `@azure/identity` for credentials, and use `CryptographyClient` when you need encrypt, decrypt, sign, verify, wrap, or unwrap operations against a specific key. Treat delete and recover flows as long-running operations and wait for their pollers to finish before assuming the key state changed.\n\n## Install\n\nInstall the key client and an Azure credential provider together:\n\n```bash\nnpm install @azure/keyvault-keys@4.10.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe standard setup uses `DefaultAzureCredential`, which can use Azure CLI login locally, managed identity in Azure, or service principal environment variables.\n\nFor local development:\n\n```bash\naz login\nexport KEY_VAULT_URL=\"https://<your-vault-name>.vault.azure.net\"\n```\n\nIf you use a service principal instead of Azure CLI or managed identity, configure the usual Azure Identity environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport KEY_VAULT_URL=\"https://<your-vault-name>.vault.azure.net\"\n```\n\nBasic client setup:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { KeyClient } from \"@azure/keyvault-keys\";\n\nconst vaultUrl = process.env.KEY_VAULT_URL;\n\nif (!vaultUrl) {\n  throw new Error(\"KEY_VAULT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new KeyClient(vaultUrl, credential);\n```\n\nAuthorization notes:\n\n- `@azure/keyvault-keys` does not authenticate by itself; you need a credential such as `DefaultAzureCredential`.\n- If requests fail with `403 Forbidden`, check that the identity has Key Vault data-plane permissions for keys.\n- Use the full vault URL, not just the vault name.\n\n## Core Usage\n\n### Create And Fetch Keys\n\nCreate an RSA key and fetch its current version:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { KeyClient } from \"@azure/keyvault-keys\";\n\nconst vaultUrl = process.env.KEY_VAULT_URL;\n\nif (!vaultUrl) {\n  throw new Error(\"KEY_VAULT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new KeyClient(vaultUrl, credential);\n\nconst createdKey = await client.createRsaKey(\"app-signing-key\", {\n  size: 2048,\n});\n\nconst currentKey = await client.getKey(\"app-signing-key\");\n\nconsole.log(createdKey.name);\nconsole.log(currentKey.properties.version);\n```\n\nCreate an elliptic curve key:\n\n```js\nconst ecKey = await client.createEcKey(\"webhook-signing-key\");\nconsole.log(ecKey.name);\n```\n\n### List Key Metadata And Versions\n\nList operations return key properties, which is usually what you want for inventory and version inspection:\n\n```js\nfor await (const properties of client.listPropertiesOfKeys()) {\n  console.log(properties.name, properties.enabled);\n}\n\nfor await (const properties of client.listPropertiesOfKeyVersions(\"app-signing-key\")) {\n  console.log(properties.version, properties.createdOn);\n}\n```\n\nIf you need the deleted-key record, fetch it explicitly:\n\n```js\nconst deletedKey = await client.getDeletedKey(\"app-signing-key\");\nconsole.log(deletedKey.recoveryId);\n```\n\n### Update Key Properties\n\nUpdate metadata on a specific key version:\n\n```js\nconst key = await client.getKey(\"app-signing-key\");\n\nconst updated = await client.updateKeyProperties(\n  \"app-signing-key\",\n  key.properties.version,\n  {\n    enabled: true,\n    tags: {\n      service: \"api\",\n      owner: \"platform\",\n    },\n  },\n);\n\nconsole.log(updated.properties.updatedOn);\n```\n\n### Delete, Recover, And Purge Keys\n\nDelete and recover are long-running operations. Wait for the pollers before moving on to dependent work:\n\n```js\nconst deletePoller = await client.beginDeleteKey(\"app-signing-key\");\nconst deletedKey = await deletePoller.pollUntilDone();\n\nconsole.log(deletedKey.name);\n\nconst recoverPoller = await client.beginRecoverDeletedKey(\"app-signing-key\");\nconst recoveredKey = await recoverPoller.pollUntilDone();\n\nconsole.log(recoveredKey.name);\n\n// If you need to permanently remove a deleted key instead of recovering it:\n// await client.purgeDeletedKey(\"app-signing-key\");\n```\n\n### Use `CryptographyClient` For Crypto Operations\n\n`KeyClient` manages keys. `CryptographyClient` performs cryptographic operations with a specific key:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { KeyClient, CryptographyClient } from \"@azure/keyvault-keys\";\n\nconst vaultUrl = process.env.KEY_VAULT_URL;\n\nif (!vaultUrl) {\n  throw new Error(\"KEY_VAULT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst keyClient = new KeyClient(vaultUrl, credential);\nconst key = await keyClient.getKey(\"app-signing-key\");\n\nconst cryptoClient = new CryptographyClient(key.id, credential);\n\nconst plaintext = new TextEncoder().encode(\"secret payload\");\nconst encryptResult = await cryptoClient.encrypt(\"RSA-OAEP\", plaintext);\nconst decryptResult = await cryptoClient.decrypt(\"RSA-OAEP\", encryptResult.result);\n\nconsole.log(new TextDecoder().decode(decryptResult.result));\n```\n\nThe same client also exposes signing, verification, key wrapping, and key unwrapping operations.\n\n## Configuration Notes\n\n- Reuse long-lived `KeyClient` and `CryptographyClient` instances instead of creating them for every request.\n- Keep `KEY_VAULT_URL` and credentials in environment variables or a secret manager, not in source code.\n- Prefer managed identity for Azure-hosted workloads instead of client secrets.\n- Use `KeyClient` for create, get, list, update, delete, recover, backup, and restore operations.\n- Use `CryptographyClient` when the application needs data-plane crypto operations against an existing key.\n\n## Common Pitfalls\n\n- Installing only `@azure/keyvault-keys` and forgetting `@azure/identity`.\n- Passing only the vault name when the client expects the full `https://<name>.vault.azure.net` URL.\n- Treating `401` and `403` responses as SDK bugs before checking credentials and Key Vault permissions.\n- Expecting list operations to return the same payload as `getKey(...)`.\n- Forgetting that delete and recover operations are poller-based.\n- Recreating a deleted key name immediately without considering soft-delete and purge protection settings.\n- Mixing up `KeyClient` and `CryptographyClient`; they are related but solve different problems.\n\n## Version Notes For `4.10.0`\n\n- This guide targets `@azure/keyvault-keys` `4.10.0`.\n- If you find older examples using the legacy `azure-keyvault` package, rewrite them to the current `@azure/keyvault-keys` and `@azure/identity` APIs.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-keys/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/keyvault-keys-readme?view=azure-node-latest`\n- `KeyClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-keys/keyclient?view=azure-node-latest`\n- `CryptographyClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-keys/cryptographyclient?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/keyvault-keys`\n"
  },
  {
    "path": "content/azure/docs/keyvault-keys/python/DOC.md",
    "content": "---\nname: keyvault-keys\ndescription: \"Azure Key Vault Keys client library for creating, managing, and using cryptographic keys from Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,key-vault,keys,kms,cryptography,security\"\n---\n\n# Azure Key Vault Keys Python Client Library\n\n## Golden Rule\n\nUse `azure-keyvault-keys` for key lifecycle operations, pair it with `azure-identity` for credentials, and use `CryptographyClient` for encrypt/decrypt, sign/verify, wrap/unwrap, and related crypto operations. Treat delete and recover flows as long-running operations and wait for the returned pollers before assuming the key state changed.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-keyvault-keys==4.11.0\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-keyvault-keys==4.11.0\" azure-identity\npoetry add \"azure-keyvault-keys==4.11.0\" azure-identity\n```\n\nIf you need async clients, install an async transport too:\n\n```bash\npython -m pip install \"azure-keyvault-keys==4.11.0\" \"azure-identity\" aiohttp\n```\n\n## Authentication And Setup\n\nThe docs and quickstart use `DefaultAzureCredential`. That is the right default for local development, CI, and Azure-hosted workloads because it can use environment credentials, managed identity, Azure CLI login, and other supported credential sources.\n\nFor local development:\n\n```bash\naz login\nexport KEY_VAULT_URL=\"https://<your-vault-name>.vault.azure.net\"\n```\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.keys import KeyClient\n\nvault_url = os.environ[\"KEY_VAULT_URL\"]\ncredential = DefaultAzureCredential()\nclient = KeyClient(vault_url=vault_url, credential=credential)\n```\n\nAuthorization notes:\n\n- `azure-keyvault-keys` does not authenticate by itself; you need a credential from `azure-identity` or another compatible Azure credential package.\n- If requests fail with `403 Forbidden`, verify the principal has Key Vault data-plane permissions for the operations you are performing. The quickstart uses Azure RBAC guidance for key management roles.\n- Use the exact vault URL for the target cloud. Public Azure vaults use `https://<name>.vault.azure.net`.\n\n## Core Usage\n\n### Create And Fetch Keys\n\nCreate an RSA key:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.keys import KeyClient\n\ncredential = DefaultAzureCredential()\nclient = KeyClient(vault_url=\"https://my-vault.vault.azure.net\", credential=credential)\n\ncreated_key = client.create_rsa_key(\"app-signing-key\", size=2048)\ncurrent_key = client.get_key(\"app-signing-key\")\n\nprint(created_key.name)\nprint(current_key.properties.version)\n```\n\nCreate an elliptic curve key:\n\n```python\nec_key = client.create_ec_key(\"webhook-signing-key\")\n```\n\n### List And Inspect Key Metadata\n\nUse the list APIs when you only need properties instead of full key material:\n\n```python\nfor props in client.list_properties_of_keys():\n    print(props.name, props.enabled)\n\nfor props in client.list_properties_of_key_versions(\"app-signing-key\"):\n    print(props.version, props.created_on)\n```\n\nFetch a deleted key if you are working with soft-delete or recovery flows:\n\n```python\ndeleted = client.get_deleted_key(\"app-signing-key\")\nprint(deleted.recovery_id)\n```\n\n### Update Key Properties\n\n```python\nupdated = client.update_key_properties(\n    \"app-signing-key\",\n    enabled=True,\n    tags={\"service\": \"api\", \"owner\": \"platform\"},\n)\n\nprint(updated.properties.updated_on)\n```\n\n### Delete, Recover, And Purge Keys\n\nDeletion and recovery are long-running operations. Wait for the poller result:\n\n```python\ndelete_poller = client.begin_delete_key(\"app-signing-key\")\ndeleted_key = delete_poller.result()\n\nrecover_poller = client.begin_recover_deleted_key(\"app-signing-key\")\nrecovered_key = recover_poller.result()\n\nclient.purge_deleted_key(\"app-signing-key\")\n\nprint(deleted_key.name)\nprint(recovered_key.name)\n```\n\n### Use `CryptographyClient` For Crypto Operations\n\n`KeyClient` manages keys. `CryptographyClient` performs cryptographic operations with a specific key:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.keys import KeyClient\nfrom azure.keyvault.keys.crypto import CryptographyClient, EncryptionAlgorithm\n\ncredential = DefaultAzureCredential()\nkey_client = KeyClient(vault_url=\"https://my-vault.vault.azure.net\", credential=credential)\nkey = key_client.get_key(\"app-signing-key\")\n\ncrypto_client = CryptographyClient(key=key, credential=credential)\n\nplaintext = b\"secret payload\"\nencrypt_result = crypto_client.encrypt(EncryptionAlgorithm.rsa_oaep, plaintext)\ndecrypt_result = crypto_client.decrypt(\n    EncryptionAlgorithm.rsa_oaep,\n    encrypt_result.ciphertext,\n)\n\nassert decrypt_result.plaintext == plaintext\n```\n\nThe same client also exposes `sign`, `verify`, `wrap_key`, and `unwrap_key`.\n\n### Async Clients\n\nUse the `.aio` imports for async code and close credentials and clients cleanly:\n\n```python\nimport os\nimport asyncio\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.keyvault.keys.aio import KeyClient\n\nasync def main() -> None:\n    vault_url = os.environ[\"KEY_VAULT_URL\"]\n\n    async with DefaultAzureCredential() as credential:\n        async with KeyClient(vault_url=vault_url, credential=credential) as client:\n            key = await client.get_key(\"app-signing-key\")\n            print(key.name, key.properties.version)\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n- Prefer `DefaultAzureCredential` unless your environment requires a specific credential type such as `ClientSecretCredential`.\n- Reuse `KeyClient` and `CryptographyClient` instances instead of creating them per request.\n- Keep the vault URL in configuration, not inline literals spread across the codebase.\n- If your workload runs in Azure, prefer managed identity over client secrets.\n- The package overview documents `send_request` support on the client if you need a custom data-plane request against the same pipeline, but use the typed client methods first.\n\n## Common Pitfalls\n\n- Do not use the legacy `azure-keyvault` package for new code. This package is the current library for keys.\n- Installing only `azure-keyvault-keys` is not enough for most real applications; you still need `azure-identity` for authentication.\n- `KeyClient` and `CryptographyClient` have different jobs. Use `KeyClient` for create/get/update/delete/list and `CryptographyClient` for encrypt/decrypt, sign/verify, and wrap/unwrap.\n- Async usage requires `.aio` imports and an async transport such as `aiohttp`.\n- Delete and recover flows are poller-based. If you skip `.result()`, the key state may not be settled when later code runs.\n- The quickstart currently says Python `3.7+`, but current PyPI metadata for `4.11.0` requires Python `>=3.9`. Trust the package metadata when choosing runtime support.\n- Azure authorization failures are often RBAC or access-policy issues rather than SDK bugs. Check the vault's key permissions before debugging client code.\n\n## Version-Sensitive Notes For `4.11.0`\n\n- The version used here `4.11.0` matches the current PyPI release as of `2026-03-12`.\n- PyPI metadata for `4.11.0` requires Python `>=3.9`, so older Python examples in Azure docs or blog posts may no longer be valid for current installs.\n- The official Azure SDK changelog for `4.11.0` notes support for key release policy operations and importing keys from certificates. If you are maintaining code written against older `4.10.x` examples, re-check any custom key import or HSM release flows.\n\n## Official Source URLs\n\n- `https://learn.microsoft.com/en-us/python/api/azure-keyvault-keys/`\n- `https://learn.microsoft.com/en-us/python/api/overview/azure/keyvault-keys-readme?view=azure-python`\n- `https://learn.microsoft.com/en-us/azure/key-vault/keys/quick-create-python`\n- `https://pypi.org/pypi/azure-keyvault-keys/json`\n- `https://github.com/Azure/azure-sdk-for-python/blob/azure-keyvault-keys_4.11.0/sdk/keyvault/azure-keyvault-keys/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/keyvault-secrets/javascript/DOC.md",
    "content": "---\nname: keyvault-secrets\ndescription: \"Azure Key Vault Secrets client library for JavaScript with SecretClient, DefaultAzureCredential, secret versioning, and soft-delete workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,key-vault,secrets,azure-keyvault-secrets,azure-identity,javascript\"\n---\n\n# Azure Key Vault Secrets JavaScript Client\n\n## Golden Rule\n\nUse `@azure/keyvault-secrets` for data-plane secret work inside an existing Azure Key Vault, pair it with `@azure/identity` for credentials, pass the full vault URL such as `https://my-vault.vault.azure.net`, and treat delete and recover flows as long-running operations. `setSecret(...)` creates a secret or a new version, while list operations return secret metadata rather than secret values.\n\n## Install\n\nInstall the secrets client and an Azure credential provider together:\n\n```bash\nnpm install @azure/keyvault-secrets@4.10.0 @azure/identity\n```\n\nThe package ships with TypeScript types.\n\n## Authentication And Setup\n\nThe standard setup uses `DefaultAzureCredential`, which can authenticate with Azure CLI locally, managed identity in Azure, or service principal environment variables.\n\nFor local development:\n\n```bash\naz login\nexport KEY_VAULT_URL=\"https://<your-vault-name>.vault.azure.net\"\n```\n\nFor service principal authentication:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport KEY_VAULT_URL=\"https://<your-vault-name>.vault.azure.net\"\n```\n\nMinimal client setup:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { SecretClient } from \"@azure/keyvault-secrets\";\n\nconst vaultUrl = process.env.KEY_VAULT_URL;\n\nif (!vaultUrl) {\n  throw new Error(\"KEY_VAULT_URL is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new SecretClient(vaultUrl, credential);\n```\n\nAuthorization notes:\n\n- `@azure/keyvault-secrets` does not authenticate by itself; you need a credential such as `DefaultAzureCredential`.\n- The caller needs Key Vault data-plane permissions for secret operations such as get, set, list, delete, recover, and purge.\n- If requests fail with `401` or `403`, check the Azure identity in use and the vault permissions before assuming the secret name is wrong.\n- Use the full vault URL, not just the vault name.\n\n## Core Usage\n\n### Read The Latest Secret Value\n\n`getSecret(name)` returns the latest version when you do not specify a version.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { SecretClient } from \"@azure/keyvault-secrets\";\n\nconst client = new SecretClient(\n  process.env.KEY_VAULT_URL,\n  new DefaultAzureCredential(),\n);\n\nconst secret = await client.getSecret(\"db-password\");\n\nconsole.log(secret.value);\nconsole.log(secret.properties.version);\n```\n\n### Create Or Rotate A Secret\n\n`setSecret(...)` creates the secret if it does not exist. If the name already exists, the call creates a new version.\n\n```js\nconst expiresOn = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n\nconst created = await client.setSecret(\"db-password\", \"s3cr3t-value\", {\n  contentType: \"text/plain\",\n  tags: {\n    env: \"prod\",\n    owner: \"payments\",\n  },\n  expiresOn,\n});\n\nconsole.log(created.name);\nconsole.log(created.properties.version);\n```\n\n### Get A Specific Secret Version\n\nFetch the latest version first if you need to capture the current version identifier, then request that exact version explicitly.\n\n```js\nconst latest = await client.getSecret(\"db-password\");\nconst version = latest.properties.version;\n\nconst exactVersion = await client.getSecret(\"db-password\", {\n  version,\n});\n\nconsole.log(exactVersion.value);\nconsole.log(exactVersion.properties.version);\n```\n\n### Update Secret Metadata Only\n\n`updateSecretProperties(...)` changes metadata on one existing secret version. It does not change the secret value.\n\n```js\nconst current = await client.getSecret(\"db-password\");\n\nconst updated = await client.updateSecretProperties(\n  \"db-password\",\n  current.properties.version,\n  {\n    enabled: true,\n    tags: {\n      env: \"prod\",\n      rotatedBy: \"deploy-job\",\n    },\n    expiresOn: new Date(\"2026-04-30T00:00:00Z\"),\n  },\n);\n\nconsole.log(updated.version);\nconsole.log(updated.tags);\n```\n\nIf you need a new value, call `setSecret(...)` again.\n\n### List Secrets And Versions\n\nList operations return secret properties, not secret values:\n\n```js\nfor await (const properties of client.listPropertiesOfSecrets()) {\n  console.log(properties.name, properties.version, properties.updatedOn);\n}\n```\n\n```js\nfor await (const properties of client.listPropertiesOfSecretVersions(\"db-password\")) {\n  console.log(properties.version, properties.enabled, properties.expiresOn);\n}\n```\n\nIf you need the value for one listed secret, call `getSecret(...)` after listing.\n\n### Delete, Recover, And Purge\n\nDelete and recover return pollers. Wait for them to finish if later steps depend on the final state.\n\n```js\nconst deletePoller = await client.beginDeleteSecret(\"db-password\");\nconst deleted = await deletePoller.pollUntilDone();\n\nconsole.log(deleted.name);\nconsole.log(deleted.recoveryId);\n```\n\nRecover a soft-deleted secret:\n\n```js\nconst recoverPoller = await client.beginRecoverDeletedSecret(\"db-password\");\nconst recovered = await recoverPoller.pollUntilDone();\n\nconsole.log(recovered.name);\n```\n\nPurge permanently:\n\n```js\nawait client.purgeDeletedSecret(\"db-password\");\n```\n\nWith soft-delete enabled, a deleted secret name can remain unavailable for immediate reuse until the secret is recovered or purged.\n\n### Backup And Restore\n\n```js\nconst backup = await client.backupSecret(\"db-password\");\nconst restored = await client.restoreSecretBackup(backup);\n\nconsole.log(restored.id);\n```\n\nThe backup payload is an Azure Key Vault backup blob intended for restore back into Key Vault.\n\n## Common Pitfalls\n\n- Installing `@azure/keyvault-secrets` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Passing only the vault name when `SecretClient` expects the full `https://<name>.vault.azure.net` URL.\n- Assuming `listPropertiesOfSecrets()` or `listPropertiesOfSecretVersions()` include secret values.\n- Using `updateSecretProperties(...)` when you actually need a new secret value.\n- Assuming `beginDeleteSecret(...)` or `beginRecoverDeletedSecret(...)` finish immediately.\n- Recreating a deleted secret name too quickly without accounting for soft-delete and purge behavior.\n- Treating `401` or `403` responses as SDK bugs before checking Azure identity setup and Key Vault permissions.\n\n## Version Notes For `4.10.0`\n\n- This guide targets `@azure/keyvault-secrets` `4.10.0`.\n- If you are adapting much older Key Vault samples, re-check the current `@azure/identity` and `@azure/keyvault-secrets` initialization pattern before copying them forward.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-secrets/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/keyvault-secrets-readme?view=azure-node-latest`\n- `SecretClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/keyvault-secrets/secretclient?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/keyvault-secrets`\n"
  },
  {
    "path": "content/azure/docs/keyvault-secrets/python/DOC.md",
    "content": "---\nname: keyvault-secrets\ndescription: \"Azure Key Vault Secrets client library for Python with SecretClient, DefaultAzureCredential, secret versioning, and soft-delete behavior\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,key-vault,secrets,azure-keyvault-secrets,azure-identity,rbac\"\n---\n\n# Azure Key Vault Secrets Python Client Library\n\n## Golden Rule\n\nUse `azure-keyvault-secrets` together with `azure-identity`, authenticate with `DefaultAzureCredential`, and pass a full vault URI such as `https://my-vault.vault.azure.net` to `SecretClient`. For `4.10.0`, trust PyPI and the package overview for version requirements: this release requires Python `>=3.9`.\n\n## Install\n\nInstall the Key Vault client and the identity package together:\n\n```bash\npython -m pip install \"azure-keyvault-secrets==4.10.0\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-keyvault-secrets==4.10.0\" \"azure-identity\"\npoetry add \"azure-keyvault-secrets==4.10.0\" \"azure-identity\"\n```\n\n`azure-keyvault-secrets` does not ship `DefaultAzureCredential`; that comes from `azure-identity`.\n\n## Authentication And Setup\n\n`SecretClient` needs:\n\n- `vault_url`: the full vault URI, not just a vault name\n- `credential`: a `TokenCredential`, usually `DefaultAzureCredential()`\n\nFor local development, the Azure quickstart uses Azure CLI login:\n\n```bash\naz login\nexport KEY_VAULT_NAME=\"my-vault\"\nexport VAULT_URL=\"https://${KEY_VAULT_NAME}.vault.azure.net\"\n```\n\nFor non-interactive environments, `DefaultAzureCredential` can use service principal environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"...\"\nexport AZURE_CLIENT_ID=\"...\"\nexport AZURE_CLIENT_SECRET=\"...\"\nexport VAULT_URL=\"https://my-vault.vault.azure.net\"\n```\n\nMinimal client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.secrets import SecretClient\n\ncredential = DefaultAzureCredential()\nclient = SecretClient(\n    vault_url=os.environ[\"VAULT_URL\"],\n    credential=credential,\n)\n```\n\nAuthorization notes:\n\n- The caller needs data-plane permissions for secret operations such as `get`, `set`, `list`, `delete`, `recover`, or `purge`.\n- The Microsoft Learn quickstart creates the vault with RBAC enabled and assigns `Key Vault Secrets Officer` for management scenarios.\n- Managed identity is the preferred production setup when the app runs on Azure.\n\n## Core Usage\n\n### Read the latest secret value\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.keyvault.secrets import SecretClient\n\nclient = SecretClient(\n    vault_url=os.environ[\"VAULT_URL\"],\n    credential=DefaultAzureCredential(),\n)\n\nsecret = client.get_secret(\"db-password\")\nprint(secret.value)\n```\n\n`get_secret(name)` returns the latest version unless you pass `version=...`.\n\n### Create or rotate a secret\n\n`set_secret()` creates the secret if it does not exist. If it already exists, the call creates a new version.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nexpires_on = datetime.now(timezone.utc) + timedelta(days=30)\n\ncreated = client.set_secret(\n    \"db-password\",\n    \"s3cr3t-value\",\n    content_type=\"text/plain\",\n    tags={\"env\": \"prod\", \"owner\": \"payments\"},\n    expires_on=expires_on,\n)\n\nprint(created.name)\nprint(created.properties.version)\n```\n\n### Get a specific version\n\n```python\nlatest = client.get_secret(\"db-password\")\nversion = latest.properties.version\n\nsame_version = client.get_secret(\"db-password\", version=version)\nprint(same_version.id)\n```\n\n### Update metadata only\n\n`update_secret_properties()` changes metadata, not the secret value.\n\n```python\nupdated = client.update_secret_properties(\n    \"db-password\",\n    enabled=True,\n    tags={\"env\": \"prod\", \"rotated-by\": \"deploy-job\"},\n    content_type=\"text/plain\",\n)\n\nprint(updated.updated_on)\nprint(updated.tags)\n```\n\nIf you need a new value, call `set_secret()` again.\n\n### List secrets and versions\n\nList operations return properties, not secret values:\n\n```python\nfor props in client.list_properties_of_secrets():\n    print(props.name, props.version, props.updated_on)\n```\n\n```python\nfor props in client.list_properties_of_secret_versions(\"db-password\"):\n    print(props.version, props.enabled, props.expires_on)\n```\n\nIf you need the value, call `get_secret(...)` after listing.\n\n### Delete, recover, and purge\n\nDelete is a long-running operation and returns a poller:\n\n```python\ndeleted = client.begin_delete_secret(\"db-password\").result()\nprint(deleted.name)\nprint(deleted.recovery_id)\n```\n\nRecover a soft-deleted secret:\n\n```python\nrecovered = client.begin_recover_deleted_secret(\"db-password\").result()\nprint(recovered.name)\n```\n\nPurge permanently:\n\n```python\nclient.purge_deleted_secret(\"db-password\")\n```\n\n### Backup and restore\n\n```python\nbackup_bytes = client.backup_secret(\"db-password\")\nrestored = client.restore_secret_backup(backup_bytes)\nprint(restored.id)\n```\n\nThe API reference describes the backup payload as a protected bytes format intended for Azure Key Vault.\n\n## Configuration Notes\n\nImportant `SecretClient` options:\n\n- `api_version`: selects the Key Vault service API version. The API reference says it defaults to the most recent supported version.\n- `verify_challenge_resource`: defaults to `True` and validates the authentication challenge resource. Leave it enabled unless you have a specific trusted environment that requires different behavior.\n\nUse explicit `api_version` pinning only when you need to preserve older service behavior.\n\n## Async Usage\n\nUse the async client only if the rest of the application is already asyncio-based:\n\n```python\nimport asyncio\nimport os\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.keyvault.secrets.aio import SecretClient\n\nasync def main() -> None:\n    credential = DefaultAzureCredential()\n    client = SecretClient(\n        vault_url=os.environ[\"VAULT_URL\"],\n        credential=credential,\n    )\n\n    try:\n        secret = await client.get_secret(\"db-password\")\n        print(secret.value)\n    finally:\n        await client.close()\n        await credential.close()\n\nasyncio.run(main())\n```\n\nClose both the async client and async credential to avoid leaving transports open.\n\n## Common Pitfalls\n\n- Do not install only `azure-keyvault-secrets`; most real code also needs `azure-identity`.\n- Do not pass only the vault name. `SecretClient` expects a full `vault_url`.\n- `401` and `403` errors are usually auth or authorization failures, not missing secret names.\n- `list_properties_of_secrets()` and `list_properties_of_secret_versions()` do not include secret values.\n- `update_secret_properties()` cannot change the secret value.\n- `begin_delete_secret()` returns a poller; wait for completion if later steps depend on the delete having finished.\n- With soft-delete enabled, a deleted-but-recoverable secret name can block immediate recreation until you recover or purge it.\n- The Azure quickstart still mentions Python `3.7+`, but PyPI, the package overview, and the changelog for `4.10.0` require Python `>=3.9`.\n\n## Version-Sensitive Notes\n\n- `4.10.0` adds support for Key Vault service API version `7.6` and makes `7.6` the default.\n- `4.10.0` drops Python `3.8`; this package line now requires Python `>=3.9`.\n- `4.6.0` changed challenge-resource verification behavior, which is why `verify_challenge_resource` can matter for unusual endpoints.\n- If you are maintaining older `1.x` code, re-check credential setup and method behavior before porting examples forward.\n\n## Official Sources\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/keyvault-secrets-readme?view=azure-python`\n- SecretClient API reference: `https://learn.microsoft.com/en-us/python/api/azure-keyvault-secrets/azure.keyvault.secrets.secretclient?view=azure-python`\n- Microsoft Learn quickstart: `https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-python`\n- Azure Key Vault soft-delete overview: `https://learn.microsoft.com/en-us/azure/key-vault/general/soft-delete-overview`\n- Azure SDK changelog: `https://raw.githubusercontent.com/Azure/azure-sdk-for-python/main/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md`\n- PyPI package page: `https://pypi.org/project/azure-keyvault-secrets/`\n"
  },
  {
    "path": "content/azure/docs/logger/javascript/DOC.md",
    "content": "---\nname: logger\ndescription: \"@azure/logger JavaScript utilities for enabling Azure SDK logs, setting log levels, and redirecting logger output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,logger,logging,javascript,diagnostics\"\n---\n\n# @azure/logger JavaScript Package Guide\n\n## What It Is\n\n`@azure/logger` is the small shared logging package used by Azure SDK libraries in JavaScript. It does not create clients, authenticate to Azure, or send telemetry by itself. Use it when you need to turn Azure SDK diagnostic logging on or off in your application, or when you need to redirect Azure SDK log output to your own sink.\n\nThe public APIs you will usually use are:\n\n- `setLogLevel(...)`: enable or disable Azure SDK logging immediately\n- `getLogLevel()`: inspect the active log level\n- `AzureLogger.log = ...`: redirect where log messages are written\n\n`createClientLogger(...)` is also exported, but it is marked hidden in the package API and is mainly useful for SDK-style library authors.\n\n## Version Scope\n\n- Package: `@azure/logger`\n- Version covered: `1.3.0`\n- Language: JavaScript\n- Docs root: `https://learn.microsoft.com/en-us/javascript/api/@azure/logger/`\n- Registry page: `https://www.npmjs.com/package/@azure/logger`\n- Source repository: `https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger`\n\n## Install\n\n```bash\nnpm install @azure/logger@1.3.0\n```\n\n`1.3.0` declares `node >=20.0.0` in its published package metadata.\n\nIf your application wants to call `setLogLevel(...)` directly, install `@azure/logger` as a direct dependency in that application instead of relying on it only as a transitive dependency of another Azure SDK package.\n\n## Initialization And Configuration\n\nThere is no endpoint, credential, or client object.\n\nYou can enable logging either with the `AZURE_LOG_LEVEL` environment variable before process startup, or in code with `setLogLevel(...)`.\n\n```bash\nexport AZURE_LOG_LEVEL=\"info\"\nnode app.mjs\n```\n\n```js\nimport { getLogLevel, setLogLevel } from \"@azure/logger\";\n\nconsole.log(getLogLevel());\n\nsetLogLevel(\"warning\");\n\nconsole.log(getLogLevel());\n```\n\nAccepted log levels, from most verbose to least verbose:\n\n- `verbose`\n- `info`\n- `warning`\n- `error`\n\nCall `setLogLevel()` with no argument to disable logging again:\n\n```js\nimport { setLogLevel } from \"@azure/logger\";\n\nsetLogLevel();\n```\n\nIf `AZURE_LOG_LEVEL` is set to an unsupported value, logging stays disabled and the package writes an error explaining the accepted values.\n\n## Common Workflows\n\n### Enable Azure SDK logs at startup\n\nThis is the normal application-level pattern: configure logging once during startup, then create and use Azure SDK clients.\n\n```js\nimport { setLogLevel } from \"@azure/logger\";\n\nsetLogLevel(process.env.NODE_ENV === \"production\" ? \"warning\" : \"info\");\n```\n\nFor Azure SDK packages that integrate with `@azure/logger`, this takes effect immediately for the current runtime.\n\n### Redirect Azure SDK logs to your own logger\n\n`AzureLogger` is the root logger object. Override its `log` method when you want Azure SDK logs to flow through your application's logging pipeline.\n\n```js\nimport { AzureLogger, setLogLevel } from \"@azure/logger\";\n\nAzureLogger.log = (...args) => {\n  console.log(\"[azure-sdk]\", ...args);\n};\n\nsetLogLevel(\"info\");\n```\n\nIn Node, the default sink writes to standard error. The browser and React Native builds route through console methods unless you override `AzureLogger.log`.\n\n### Enable sanitized HTTP pipeline logging\n\nAzure SDK HTTP pipeline packages use the same logging package. For example, `@azure/core-rest-pipeline` enables its log policy only after you set a log level:\n\n```js\nimport { createPipelineFromOptions } from \"@azure/core-rest-pipeline\";\nimport { setLogLevel } from \"@azure/logger\";\n\nsetLogLevel(\"info\");\n\nconst pipeline = createPipelineFromOptions({\n  loggingOptions: {\n    additionalAllowedHeaderNames: [\"x-ms-request-id\"],\n    additionalAllowedQueryParameters: [\"api-version\"],\n  },\n});\n```\n\nThis is the practical pattern when you want Azure SDK request and response diagnostics without changing each client individually.\n\n### Create a namespaced logger for a client library\n\nUse `createClientLogger(...)` only if you are building an Azure SDK-style library and want the same namespace and level behavior as other Azure packages.\n\n```js\nimport { createClientLogger, setLogLevel } from \"@azure/logger\";\n\nsetLogLevel(\"verbose\");\n\nconst logger = createClientLogger(\"my-package\");\n\nlogger.info(\"Starting operation\");\nlogger.verbose(\"Request options: %o\", { retries: 3 });\nlogger.warning(\"Retrying after throttling\");\nlogger.error(\"Operation failed\");\n```\n\nThese loggers use Azure-style namespaces under the `azure` root, such as `azure:my-package:info`.\n\n## Common Pitfalls\n\n- Expecting log output without setting `AZURE_LOG_LEVEL` or calling `setLogLevel(...)`.\n- Passing an unsupported level such as `debug`; the only accepted values are `verbose`, `info`, `warning`, and `error`.\n- Treating logging as per-client configuration. The log level is shared by this package instance in the current runtime.\n- Importing `@azure/logger` from application code without declaring it as a direct dependency.\n- Using `createClientLogger(...)` as a general-purpose app logger; it is intended for Azure SDK-style libraries.\n\n## Runtime Notes For 1.3.0\n\n- This guide targets `@azure/logger` `1.3.0`.\n- The package publishes conditional exports for ESM import, CommonJS require, browser, and React Native builds.\n- The package-level environment variable is `AZURE_LOG_LEVEL`.\n- `setLogLevel(...)` changes the active level immediately, and `getLogLevel()` returns the current value or `undefined` when logging is disabled.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/logger/`\n- Azure SDK source root: `https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger`\n- npm package page: `https://www.npmjs.com/package/@azure/logger`\n"
  },
  {
    "path": "content/azure/docs/maps-render/python/DOC.md",
    "content": "---\nname: maps-render\ndescription: \"Azure Maps Render Python client library for tiles, static images, attribution, and Azure Maps authentication\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0b2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-maps,maps,render,geospatial,tiles,static-maps\"\n---\n\n# Azure Maps Render Python Client Library\n\n## Golden Rule\n\nUse `azure-maps-render` with `MapsRenderClient`, pin the exact prerelease you expect, and treat Microsoft Learn's preview docs as the source of truth for method names and auth requirements. For Microsoft Entra ID auth, you need both a token credential and the Azure Maps account `client_id`.\n\n## Install\n\nPin the prerelease explicitly:\n\n```bash\npython -m pip install \"azure-maps-render==2.0.0b2\"\n```\n\nIf you want the latest prerelease in this line instead of an exact pin:\n\n```bash\npython -m pip install --pre azure-maps-render\n```\n\nCommon companion packages:\n\n```bash\npython -m pip install azure-identity\npython -m pip install azure-mgmt-maps\npython -m pip install aiohttp\n```\n\n- `azure-identity` is for Microsoft Entra ID auth.\n- `azure-mgmt-maps` is needed if you want to generate SAS tokens programmatically.\n- `aiohttp` is a common async transport for `azure.maps.render.aio`.\n\n## Azure Maps Setup\n\nYou need:\n\n1. An Azure subscription\n2. An Azure Maps account\n3. A deployed Maps resource\n4. One of these auth modes: subscription key, SAS token, or Microsoft Entra ID\n\nAzure CLI example from the package overview:\n\n```bash\naz maps account create \\\n  --resource-group <resource-group-name> \\\n  --account-name <account-name> \\\n  --sku <sku-name>\n```\n\n## Authentication And Client Initialization\n\nThe constructor is credential-first:\n\n```python\nMapsRenderClient(credential=..., **kwargs)\n```\n\nUnlike many Azure SDK clients, the common `MapsRenderClient` examples do not take a service endpoint.\n\n### Subscription Key\n\n```bash\nexport AZURE_SUBSCRIPTION_KEY=\"...\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n```\n\n### Microsoft Entra ID\n\nFor token auth, pass the Azure Maps account `client_id` on the client in addition to the credential:\n\n```bash\nexport AZURE_CLIENT_ID=\"app-or-managed-identity-client-id\"\nexport AZURE_TENANT_ID=\"tenant-id\"\nexport AZURE_CLIENT_SECRET=\"client-secret\"\nexport AZURE_MAPS_CLIENT_ID=\"azure-maps-account-client-id\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.maps.render import MapsRenderClient\n\nclient = MapsRenderClient(\n    credential=DefaultAzureCredential(),\n    client_id=os.environ[\"AZURE_MAPS_CLIENT_ID\"],\n)\n```\n\nThe `AZURE_MAPS_CLIENT_ID` value is the Azure Maps resource client ID from the Maps account authentication settings, not just your app registration ID.\n\n### SAS Token\n\nThe overview doc says to generate SAS tokens with `azure-mgmt-maps`, then pass the token to the render client:\n\n```bash\nexport AZURE_SAS_TOKEN=\"...\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureSasCredential\nfrom azure.maps.render import MapsRenderClient\n\nclient = MapsRenderClient(\n    credential=AzureSasCredential(os.environ[\"AZURE_SAS_TOKEN\"])\n)\n```\n\n## Core Usage\n\n### Get a map tile\n\n`get_map_tile()` returns `Iterator[bytes]`. Save or forward the joined bytes.\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient, TilesetID\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\ntile_bytes = b\"\".join(\n    client.get_map_tile(\n        tileset_id=TilesetID.MICROSOFT_BASE,\n        z=6,\n        x=9,\n        y=22,\n        tile_size=\"512\",\n    )\n)\n\nwith open(\"tile.png\", \"wb\") as f:\n    f.write(tile_bytes)\n```\n\n### Get a static image\n\nThe static image API also returns `Iterator[bytes]`. In `2.0.0b2`, the SDK parameter is still named `bounding_box_private`.\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\nimage_bytes = b\"\".join(\n    client.get_map_static_image(\n        zoom=10,\n        bounding_box_private=[13.228, 52.4559, 13.5794, 52.629],\n    )\n)\n\nwith open(\"static-map.png\", \"wb\") as f:\n    f.write(image_bytes)\n```\n\nEither `center` or `bounding_box_private` must be supplied.\n\n### Get tileset metadata\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient, TilesetID\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\ntileset = client.get_map_tileset(tileset_id=TilesetID.MICROSOFT_BASE)\nprint(tileset)\n```\n\n### Get attribution\n\nUse attribution when you need display-safe copyright data for a specific map section:\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient, TilesetID\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\nattribution = client.get_map_attribution(\n    tileset_id=TilesetID.MICROSOFT_BASE,\n    zoom=6,\n    bounds=[42.982261, 24.980233, 56.526017, 1.355233],\n)\n\nprint(attribution)\n```\n\nThe `bounds` order is southwest longitude/latitude followed by northeast longitude/latitude.\n\n### Get copyright information for the world\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render import MapsRenderClient\n\nclient = MapsRenderClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\nresult = client.get_copyright_for_world()\nprint(result)\n```\n\n## Async Usage\n\nInstall an async transport first, then use the `aio` namespace and close the client with `async with`.\n\n```python\nimport os\nimport asyncio\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.render.aio import MapsRenderClient\n\nasync def main() -> None:\n    async with MapsRenderClient(\n        credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n    ) as client:\n        tileset = await client.get_map_tileset(tileset_id=\"microsoft.base\")\n        print(tileset)\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n- `get_map_tile()` uses `z` for zoom, not `zoom`.\n- `get_map_attribution()` uses `zoom`, not `z`.\n- `tile_size` accepts `\"256\"` or `\"512\"`.\n- `get_map_tile()` also accepts `time_stamp` for time-based weather tiles.\n- `language` and `localized_map_view` are per-request options on render methods.\n- `get_map_static_image()` defaults `tileset_id` to a road style when omitted, but setting it explicitly is safer in agent-generated code.\n\n## Common Pitfalls\n\n- Do not assume this package is stable: it is still a beta line on PyPI and Microsoft Learn serves it under `azure-python-preview`.\n- Do not pass an endpoint unless you have a specific documented need; the normal constructor shape is credential plus keyword options.\n- Do not forget the Azure Maps account `client_id` when using Microsoft Entra ID credentials.\n- Do not confuse the official docs' inconsistent SAS class casing. The API reference uses `AzureSasCredential`, which is the class name you should import from `azure.core.credentials`.\n- Do not mix older Azure Maps Render v1 REST examples into this SDK workflow. Azure product docs note that Render v1 is deprecated and retires on September 17, 2026.\n- Catch `azure.core.exceptions.HttpResponseError` for request failures and inspect `error_code` when you need service-specific handling.\n- `logging_enable=True` can expose request details; use it for debugging, not by default in production code.\n\n## Version-Sensitive Notes\n\n- PyPI and the Azure SDK package index both list `2.0.0b2` as the current published `azure-maps-render` package.\n- The package overview shows common samples with subscription key, SAS token, and Microsoft Entra ID; if your code uses older Azure Maps auth guidance, re-check those flows against the current preview docs.\n- Product docs now flag some coverage entries as available only in Render v2 and API version `v2024-04-01`. If you are working from older map-render examples, verify the tileset and service version assumptions before copying them.\n"
  },
  {
    "path": "content/azure/docs/maps-route/python/DOC.md",
    "content": "---\nname: maps-route\ndescription: \"Azure Maps Route client library for Python (preview) with auth, directions, route range, matrix, and migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0b3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-maps,route,routing,geospatial,python\"\n---\n\n# azure-maps-route Python Package Guide\n\n## Golden Rule\n\nUse `azure-maps-route` only as a pinned preview dependency, initialize `MapsRouteClient` with the correct Azure Maps credential type, and prefer the current Microsoft Learn class reference over older PyPI README snippets when method names disagree.\n\n## Install\n\nPin the version you tested:\n\n```bash\npython -m pip install \"azure-maps-route==1.0.0b3\"\n```\n\nIf you want the newest preview build instead of an exact pin:\n\n```bash\npython -m pip install --pre azure-maps-route\n```\n\nCommon companion packages:\n\n```bash\npython -m pip install azure-identity\npython -m pip install azure-mgmt-maps\npython -m pip install aiohttp\n```\n\nUse them for:\n\n- `azure-identity`: Microsoft Entra ID or managed identity auth\n- `azure-mgmt-maps`: generating SAS tokens programmatically\n- `aiohttp`: async transport for `azure.maps.route.aio`\n\n## Service Setup\n\nBefore writing code, make sure you have:\n\n1. an Azure subscription\n2. an Azure Maps account/resource\n3. one supported auth path: subscription key, SAS token, or Microsoft Entra ID\n\nCreate a Maps account with Azure CLI:\n\n```bash\naz maps account create \\\n  --kind Gen2 \\\n  --account-name <maps-account> \\\n  --resource-group <resource-group> \\\n  --sku G2\n```\n\n## Authentication And Client Initialization\n\n### Subscription key\n\n```bash\nexport AZURE_SUBSCRIPTION_KEY=\"...\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.route import MapsRouteClient\n\nclient = MapsRouteClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n```\n\n### SAS token\n\n`1.0.0b3` adds SAS authentication support. Generate the token with `azure-mgmt-maps`, then pass it through `AzureSasCredential`.\n\n```bash\nexport AZURE_MAPS_SAS_TOKEN=\"...\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureSasCredential\nfrom azure.maps.route import MapsRouteClient\n\nclient = MapsRouteClient(\n    credential=AzureSasCredential(os.environ[\"AZURE_MAPS_SAS_TOKEN\"])\n)\n```\n\n### Microsoft Entra ID\n\nFor token-based auth, you need both the normal Azure identity environment variables and the Azure Maps account client ID.\n\n```bash\nexport AZURE_CLIENT_ID=\"app-client-id\"\nexport AZURE_CLIENT_SECRET=\"app-client-secret\"\nexport AZURE_TENANT_ID=\"tenant-id\"\nexport MAPS_CLIENT_ID=\"azure-maps-account-client-id\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.maps.route import MapsRouteClient\n\nclient = MapsRouteClient(\n    credential=DefaultAzureCredential(),\n    client_id=os.environ[\"MAPS_CLIENT_ID\"],\n)\n```\n\nImportant notes:\n\n- `MAPS_CLIENT_ID` is the Azure Maps account client ID, not your Entra app registration client ID.\n- Microsoft Learn’s broader Azure Maps Python SDK guide uses `MAPS_CLIENT_ID`; keep that name consistent in your project even if older snippets use different names.\n\n## Core Usage\n\n### Get route directions\n\n`get_route_directions()` is the main sync call for point-to-point routing. The current SDK surface takes route points as `(latitude, longitude)` tuples.\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.route import MapsRouteClient\n\nclient = MapsRouteClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\nresult = client.get_route_directions(\n    route_points=[\n        (47.60323, -122.33028),\n        (47.62050, -122.34930),\n    ]\n)\n\nroute = result.routes[0]\nprint(route.summary.length_in_meters)\nprint(route.summary.travel_time_in_seconds)\n```\n\n### Get route range\n\nUse `get_route_range()` when you need an isochrone-style reachable area from a starting point.\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.route import MapsRouteClient\n\nclient = MapsRouteClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n)\n\nresult = client.get_route_range(\n    coordinates=(47.60323, -122.33028),\n    time_budget_in_sec=1800,\n)\n\nprint(result.reachable_range.center.latitude)\nprint(result.reachable_range.center.longitude)\n```\n\n## Matrix And Batch Operations\n\n### Route matrix\n\nUse matrix APIs when you need travel-time or distance summaries across many origin and destination pairs instead of full turn-by-turn routes.\n\nRelevant methods in the current class reference:\n\n- sync matrix: `request_route_matrix_sync(...)`\n- async matrix submit: `begin_request_route_matrix(...)`\n- async matrix retrieval by id: `begin_get_route_matrix(...)`\n\nImportant constraints:\n\n- sync matrix limit: `100` cells\n- async matrix limit: `700` cells\n- async matrix results are retained for `14` days\n- since `1.0.0b2`, matrix requests must use a `RouteMatrixQuery` object rather than a plain `dict`\n\n### Route directions batch\n\nUse batch directions when you need many direction queries in one request.\n\nRelevant methods in the current class reference:\n\n- sync batch: `request_route_directions_batch_sync(...)`\n- async batch submit: `begin_request_route_directions_batch(...)`\n- batch retrieval flow: `begin_get_route_directions_batch(...)`\n\nImportant constraints:\n\n- sync batch limit: `100` queries\n- async batch limit: `700` queries\n- async batch results are retained for `14` days\n\n## Async Usage\n\nInstall an async transport first, then use the `aio` client.\n\n```python\nimport asyncio\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.route.aio import MapsRouteClient\n\nasync def main() -> None:\n    async with MapsRouteClient(\n        credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"])\n    ) as client:\n        result = await client.get_route_directions(\n            route_points=[\n                (47.60323, -122.33028),\n                (47.62050, -122.34930),\n            ]\n        )\n        print(result.routes[0].summary.length_in_meters)\n\nasyncio.run(main())\n```\n\n## Errors, Logging, And Debugging\n\nAzure Maps Route raises Azure Core exceptions such as `HttpResponseError`.\n\n```python\nimport logging\nimport os\nimport sys\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.core.exceptions import HttpResponseError\nfrom azure.maps.route import MapsRouteClient\n\nlogger = logging.getLogger(\"azure.maps.route\")\nlogger.setLevel(logging.DEBUG)\nlogger.addHandler(logging.StreamHandler(sys.stdout))\n\nclient = MapsRouteClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"]),\n    logging_enable=True,\n)\n\ntry:\n    client.get_route_directions(route_points=[(47.60323, -122.33028), (47.62050, -122.34930)])\nexcept HttpResponseError as exc:\n    print(exc)\n    print(getattr(exc, \"error_code\", None))\n```\n\n## Common Pitfalls\n\n- The package is still preview-only. Pin `1.0.0b3` or the exact preview you validated.\n- Older PyPI README examples still use `begin_get_route_matrix_result(...)` and `begin_get_route_directions_batch_result(...)`. The current Microsoft Learn class reference documents `begin_get_route_matrix(...)` and `begin_get_route_directions_batch(...)`.\n- Microsoft Entra auth needs the Azure Maps account client ID in addition to `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, and `AZURE_TENANT_ID`.\n- The current SDK uses Route v1-style tuple inputs like `(latitude, longitude)`. Do not copy those tuples directly into newer Azure Maps Routing `2025-01-01` REST examples, which use GeoJSON `[longitude, latitude]`.\n- Matrix code written against `1.0.0b1` will break on `1.0.0b2+` if it still passes a plain dictionary instead of `RouteMatrixQuery`.\n- For async matrix or async batch flows, results expire after 14 days.\n\n## Version-Sensitive Notes\n\n- `1.0.0b3` adds SAS-based authentication support.\n- `1.0.0b2` changes matrix inputs to `RouteMatrixQuery` and removes Python 3.6 support.\n- The Python SDK docs are still published under `view=azure-python-preview`.\n- Azure Maps now has an official migration guide from Route v1.0 to Routing `2025-01-01`. That newer REST surface changes request shapes and behavior, including replacing older `GET` route directions and `GET` route range patterns with `POST`-based flows. If you need features from the newer Routing service, validate against the REST migration guide instead of assuming this SDK preview already covers them.\n\n## Official Sources\n\n- Microsoft Learn package API root: https://learn.microsoft.com/en-us/python/api/azure-maps-route/\n- Microsoft Learn `MapsRouteClient` class: https://learn.microsoft.com/en-us/python/api/azure-maps-route/azure.maps.route.mapsrouteclient?view=azure-python-preview\n- Azure Maps Python SDK guide: https://learn.microsoft.com/en-us/azure/azure-maps/how-to-dev-guide-py-sdk\n- Azure Maps Route v1 migration guide: https://learn.microsoft.com/en-us/azure/azure-maps/migrate-route-v1-api\n- PyPI package page: https://pypi.org/project/azure-maps-route/\n"
  },
  {
    "path": "content/azure/docs/maps-search/javascript/DOC.md",
    "content": "---\nname: maps-search\ndescription: \"Azure Maps Search JavaScript SDK preview package for geocoding, reverse geocoding, and batch search\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.0.0-beta.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-maps,search,geocoding,reverse-geocoding,javascript\"\n---\n\n# @azure/maps-search JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/maps-search` for Azure Maps Search data-plane calls, pin the preview version your app expects, and start with subscription-key authentication unless you already have an Azure Maps Microsoft Entra ID setup in place.\n\nThis guide is scoped to `@azure/maps-search` `1.0.0-beta.2`.\n\n## Install\n\nInstall the package with an explicit prerelease pin:\n\n```bash\nnpm install @azure/maps-search@1.0.0-beta.2\n```\n\nIf you plan to use Microsoft Entra ID authentication, install Azure Identity too:\n\n```bash\nnpm install @azure/maps-search@1.0.0-beta.2 @azure/identity\n```\n\n## Environment And Authentication\n\nFor the common subscription-key path, keep the Azure Maps key in an environment variable:\n\n```bash\nexport AZURE_SUBSCRIPTION_KEY=\"<your-azure-maps-key>\"\n```\n\nIf you are using Microsoft Entra ID, Azure Identity uses the standard environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport MAPS_CLIENT_ID=\"<azure-maps-account-client-id>\"\n```\n\nThe Azure Maps account client ID is separate from the Microsoft Entra application client ID. Keep those values distinct in your app configuration.\n\n### Initialize The Client With A Subscription Key\n\n```js\nimport { AzureKeyCredential, MapsSearchClient } from \"@azure/maps-search\";\n\nconst client = new MapsSearchClient(\n  new AzureKeyCredential(process.env.AZURE_SUBSCRIPTION_KEY),\n);\n```\n\nFor most Node.js services and scripts, reuse one long-lived client instance instead of constructing a new client per request.\n\n## Core Workflows\n\n### Geocode An Address\n\n```js\nimport { AzureKeyCredential, MapsSearchClient } from \"@azure/maps-search\";\n\nconst client = new MapsSearchClient(\n  new AzureKeyCredential(process.env.AZURE_SUBSCRIPTION_KEY),\n);\n\nconst result = await client.getGeocoding({\n  query: \"15127 NE 24th Street, Redmond, WA 98052\",\n});\n\nconst firstFeature = result.features?.[0];\n\nif (!firstFeature) {\n  console.log(\"No results\");\n} else {\n  const [longitude, latitude] = firstFeature.geometry.coordinates;\n  console.log(firstFeature.properties.address.formattedAddress);\n  console.log(longitude, latitude);\n}\n```\n\nThe response shape is feature-based. In the common case, read the first item from `result.features` and then inspect `geometry.coordinates` and `properties.address`.\n\n### Batch Geocoding\n\nBatch geocoding sends a request body with `batchItems`.\n\n```js\nimport { AzureKeyCredential, MapsSearchClient } from \"@azure/maps-search\";\n\nconst client = new MapsSearchClient(\n  new AzureKeyCredential(process.env.AZURE_SUBSCRIPTION_KEY),\n);\n\nconst result = await client.getGeocodingBatch({\n  batchItems: [\n    { query: \"400 Broad St, Seattle, WA 98109\" },\n    { query: \"15127 NE 24th Street, Redmond, WA 98052\" },\n  ],\n});\n\nfor (const item of result.batchItems ?? []) {\n  const firstFeature = item.features?.[0];\n\n  if (!firstFeature) {\n    continue;\n  }\n\n  const [longitude, latitude] = firstFeature.geometry.coordinates;\n  console.log(longitude, latitude);\n}\n```\n\n### Reverse Geocoding\n\nReverse geocoding expects coordinates in `[longitude, latitude]` order.\n\n```js\nimport { AzureKeyCredential, MapsSearchClient } from \"@azure/maps-search\";\n\nconst client = new MapsSearchClient(\n  new AzureKeyCredential(process.env.AZURE_SUBSCRIPTION_KEY),\n);\n\nconst result = await client.getReverseGeocoding({\n  coordinates: [-122.138679, 47.630356],\n});\n\nconst firstFeature = result.features?.[0];\n\nif (firstFeature) {\n  console.log(firstFeature.properties.address.formattedAddress);\n}\n```\n\n## Practical Notes\n\n- Use `[longitude, latitude]` everywhere this package accepts coordinates.\n- Treat `result.features?.[0]` as the normal starting point for single-result lookups.\n- Send batch requests as `{ batchItems: [...] }`, not as a plain array.\n- Keep the subscription key in environment variables or a secret manager, not in source control.\n- Pin the exact beta version in app code and examples so a later prerelease does not silently change behavior.\n\n## Common Pitfalls\n\n- Installing `@azure/maps-search` without pinning the beta version and then assuming all preview examples still match your installed package.\n- Swapping latitude and longitude when calling reverse geocoding.\n- Treating batch methods like a list of strings instead of a request body with `batchItems`.\n- Mixing this package with older Azure Maps JavaScript examples that use different client packages or older method names.\n- Confusing the Azure Maps account client ID with the Microsoft Entra application client ID when setting up identity-based auth.\n\n## Version Notes For `1.0.0-beta.2`\n\n- `1.0.0-beta.2` is a prerelease package; keep your dependency pinned.\n- Recheck method names and option shapes against the current Microsoft Learn reference before copying examples from earlier preview material.\n\n## Official Sources Used\n\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/maps-search/`\n- npm package page: `https://www.npmjs.com/package/@azure/maps-search`\n"
  },
  {
    "path": "content/azure/docs/maps-search/python/DOC.md",
    "content": "---\nname: maps-search\ndescription: \"Azure Maps Search SDK for Python preview package for geocoding, reverse geocoding, batch search, and polygon boundaries\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0b2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,maps,search,geocoding,reverse-geocoding,location,python\"\n---\n\n# Azure Maps Search Python Package Guide\n\n## Golden Rule\n\nUse `azure-maps-search` for Azure Maps Search calls, import `MapsSearchClient` from `azure.maps.search`, and treat the current line as preview-only. Pin the beta version your project expects, use `--pre` for unpinned installs, and do not copy pre-`2.0.0b1` examples that still call removed methods like `fuzzy_search`.\n\n## Install\n\nBecause the package is still published as a beta, prefer an explicit prerelease pin:\n\n```bash\npython -m pip install --pre \"azure-maps-search==2.0.0b2\"\n```\n\nCommon companion packages:\n\n```bash\npython -m pip install azure-identity\npython -m pip install azure-mgmt-maps\n```\n\nUse them only when needed:\n\n- `azure-identity`: Microsoft Entra authentication via `DefaultAzureCredential`\n- `azure-mgmt-maps`: generating Azure Maps SAS tokens\n\nIf you omit the version pin and just run `pip install azure-maps-search`, pip may skip the package because there is no stable final release on PyPI as of March 12, 2026.\n\n## Authentication And Setup\n\n`MapsSearchClient` supports three auth modes in the official package overview:\n\n1. Azure Maps subscription key\n2. Microsoft Entra ID with an Azure Maps account client ID\n3. SAS token via `AzureSASCredential`\n\n### Subscription key\n\nThis is the simplest path and the clearest starting point for scripts and services.\n\n```bash\nexport AZURE_SUBSCRIPTION_KEY=\"your-azure-maps-key\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(\n    credential=AzureKeyCredential(os.environ[\"AZURE_SUBSCRIPTION_KEY\"]),\n)\n```\n\n### Microsoft Entra ID\n\nFor Entra auth, `DefaultAzureCredential()` is not enough on its own. The Azure Maps client also needs the Maps account client ID.\n\n```bash\nexport AZURE_CLIENT_ID=\"your-app-client-id\"\nexport AZURE_CLIENT_SECRET=\"your-app-client-secret\"\nexport AZURE_TENANT_ID=\"your-tenant-id\"\nexport MAPS_CLIENT_ID=\"your-azure-maps-account-client-id\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(\n    client_id=os.environ[\"MAPS_CLIENT_ID\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\nUse the `MAPS_CLIENT_ID` value from the Azure Maps account authentication section in the Azure portal. If you forget it, token acquisition may succeed while service requests still fail.\n\n### SAS token\n\n`2.0.0b2` added SAS-based authentication support. Use this when your deployment model already issues Azure Maps SAS tokens.\n\n```bash\nexport AZURE_SAS_TOKEN=\"your-maps-sas-token\"\n```\n\n```python\nimport os\n\nfrom azure.core.credentials import AzureSASCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(\n    credential=AzureSASCredential(os.environ[\"AZURE_SAS_TOKEN\"]),\n)\n```\n\nGenerating the SAS token is a management-plane step. The official docs use `azure-mgmt-maps` plus `AzureMapsManagementClient.accounts.list_sas(...)` for that flow.\n\n## Core Usage\n\n### Geocode an address\n\nThe current preview line uses `get_geocoding` and returns a GeoJSON-like result with `features`.\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(credential=AzureKeyCredential(\"...\"))\n\nresult = client.get_geocoding(query=\"15127 NE 24th Street, Redmond, WA 98052\")\n\nif result.get(\"features\"):\n    coordinates = result[\"features\"][0][\"geometry\"][\"coordinates\"]\n    longitude, latitude = coordinates\n    print(longitude, latitude)\nelse:\n    print(\"No results\")\n```\n\n### Batch geocoding\n\n`get_geocoding_batch` accepts a payload with `batchItems`. The `2.0.0b1` release notes say batch geocoding supports up to 100 queries in one request.\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(credential=AzureKeyCredential(\"...\"))\n\nresult = client.get_geocoding_batch(\n    {\n        \"batchItems\": [\n            {\"query\": \"400 Broad St, Seattle, WA 98109\"},\n            {\"query\": \"15127 NE 24th Street, Redmond, WA 98052\"},\n        ]\n    }\n)\n\nfor item in result.get(\"batchItems\", []):\n    if item.get(\"features\"):\n        longitude, latitude = item[\"features\"][0][\"geometry\"][\"coordinates\"]\n        print(longitude, latitude)\n```\n\n### Reverse geocoding\n\nCoordinates are `[longitude, latitude]`, not `[latitude, longitude]`.\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(credential=AzureKeyCredential(\"...\"))\n\nresult = client.get_reverse_geocoding(coordinates=[-122.138679, 47.630356])\n\nif result.get(\"features\"):\n    address = result[\"features\"][0][\"properties\"][\"address\"][\"formattedAddress\"]\n    print(address)\n```\n\n### Reverse geocoding in batch\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import MapsSearchClient\n\nclient = MapsSearchClient(credential=AzureKeyCredential(\"...\"))\n\nresult = client.get_reverse_geocoding_batch(\n    {\n        \"batchItems\": [\n            {\"coordinates\": [-122.138679, 47.630356]},\n            {\"coordinates\": [-122.126, 47.64]},\n        ]\n    }\n)\n\nfor item in result.get(\"batchItems\", []):\n    if item.get(\"features\"):\n        print(item[\"features\"][0][\"properties\"][\"address\"][\"formattedAddress\"])\n```\n\n### Polygon lookup\n\nUse `get_polygon` when you need a locality or other boundary geometry for a coordinate pair.\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.maps.search import BoundaryResultType, MapsSearchClient, Resolution\n\nclient = MapsSearchClient(credential=AzureKeyCredential(\"...\"))\n\nresult = client.get_polygon(\n    coordinates=[-122.204141, 47.61256],\n    result_type=BoundaryResultType.LOCALITY,\n    resolution=Resolution.SMALL,\n)\n\ngeometry = result.get(\"geometry\")\nif geometry:\n    print(geometry[\"type\"])\n```\n\n## Error Handling And Diagnostics\n\nAzure SDK failures are raised through Azure Core exceptions such as `HttpResponseError`.\n\n```python\nfrom azure.core.exceptions import HttpResponseError\n\ntry:\n    result = client.get_geocoding(query=\"invalid input\")\nexcept HttpResponseError as exc:\n    print(exc.error_code)\n    raise\n```\n\nFor request/response diagnostics, the package supports Azure SDK logging:\n\n```python\nresult = client.get_geocoding(\n    query=\"15127 NE 24th Street, Redmond, WA 98052\",\n    logging_enable=True,\n)\n```\n\nBe careful with debug logging in production because Azure SDK logging can include request details you may not want in logs.\n\n## Configuration Notes\n\n- `MapsSearchClient` does not need an explicit endpoint in the common Azure public-cloud path; auth is the main configuration input.\n- For Entra auth, keep the Azure app identity values and `MAPS_CLIENT_ID` separate. They are different IDs used for different purposes.\n- For local development, prefer environment variables or a managed identity-aware workflow over hard-coded secrets.\n- The package overview says async support exists, but you must install an async transport such as `aiohttp` and close async clients and credentials when finished.\n\n## Common Pitfalls\n\n- `pip install azure-maps-search` without `--pre` can fail to find a release because the latest published versions are prereleases.\n- The Azure Maps how-to guide uses `SUBSCRIPTION_KEY` in one snippet and `AZURE_SUBSCRIPTION_KEY` in others. Standardize on `AZURE_SUBSCRIPTION_KEY` in your own code to match the package overview and avoid mixed env var names.\n- Old blog posts and early preview examples may call removed methods such as `fuzzy_search`, `search_address`, or `reverse_search_address`. Those are not part of the `2.x` preview line.\n- Reverse geocoding and polygon calls expect `[longitude, latitude]`. Swapping the order is an easy mistake.\n- Batch methods take request bodies with `batchItems`; they are not simple lists of strings or coordinate arrays.\n- Entra auth also needs the Azure Maps account client ID. Missing `MAPS_CLIENT_ID` is a common setup bug.\n- SAS auth exists only in `2.0.0b2+`. Do not assume older preview environments support it.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `2.0.0b2` as the latest release, published on December 12, 2024, with development status `Beta`.\n- `2.0.0b2` added SAS authentication support.\n- `2.0.0b1` introduced the current `get_geocoding`, `get_geocoding_batch`, `get_reverse_geocoding`, `get_reverse_geocoding_batch`, and `get_polygon` methods.\n- `2.0.0b1` also removed the older search method family, including `fuzzy_search`, `search_point_of_interest`, `search_address`, and related batch/reverse variants.\n- Use official preview docs and the current PyPI release history instead of generic Azure Maps Python search examples from before August 2024.\n\n## Official Sources\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/maps-search-readme?view=azure-python-preview`\n- Microsoft Learn API root: `https://learn.microsoft.com/en-us/python/api/azure-maps-search/`\n- Azure Maps Python SDK how-to: `https://learn.microsoft.com/en-us/azure/azure-maps/how-to-dev-guide-py-sdk`\n- PyPI project page: `https://pypi.org/project/azure-maps-search/`\n"
  },
  {
    "path": "content/azure/docs/mgmt-applicationinsights/python/DOC.md",
    "content": "---\nname: mgmt-applicationinsights\ndescription: \"Azure Application Insights management SDK for Python for ARM components, billing and quota settings, web tests, and workbooks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,application-insights,monitoring,arm,workbooks,synthetics,python\"\n---\n\n# Azure Application Insights Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-applicationinsights` for Azure Resource Manager work around Application Insights resources: creating and reading Application Insights components, checking billing and quota settings, managing synthetic web tests, and working with workbooks. This package is a management-plane SDK. It does not send telemetry from your app and it does not query telemetry data at runtime.\n\nStay on the stable `4.1.0` line unless your project is intentionally testing the `5.0.0b1` prerelease that PyPI also lists.\n\n## Install\n\nInstall the package together with `azure-identity`:\n\n```bash\npython -m pip install \"azure-mgmt-applicationinsights==4.1.0\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-applicationinsights==4.1.0\" \"azure-identity\"\npoetry add \"azure-mgmt-applicationinsights==4.1.0\" \"azure-identity\"\n```\n\nPyPI lists `azure-mgmt-applicationinsights 4.1.0` as supporting Python `3.8+`.\n\n## Authentication And Setup\n\nUse Azure Identity credentials and provide the subscription explicitly.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor service-principal auth, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nLocal development after `az login`:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.applicationinsights import ApplicationInsightsManagementClient\n\nclient = ApplicationInsightsManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nReusable app or automation setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.applicationinsights import ApplicationInsightsManagementClient\n\ncredential = DefaultAzureCredential()\nclient = ApplicationInsightsManagementClient(\n    credential=credential,\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nClose the client when the script exits:\n\n```python\nclient.close()\n```\n\n## What The Client Covers\n\n`ApplicationInsightsManagementClient` defaults to API version `2023-06-01`. In `4.1.0`, the documented operation groups include:\n\n- `components`\n- `component_current_billing_features`\n- `component_quota_status`\n- `api_keys`\n- `analytics_items`\n- `annotations`\n- `favorites`\n- `proactive_detection_configurations`\n- `web_test_locations`\n- `web_tests`\n- `workbooks`\n- `my_workbooks`\n- `workbook_templates`\n\n`deleted_workbooks` is also present in `4.1.0`, but the client docs mark it under `2024-02-01-preview`, so use a preview `api_version` when you need that operation group.\n\n## Core Usage\n\n### Create Or Update A Workspace-Based Application Insights Component\n\nAs of the `4.x` line, create components as workspace-based resources and pass the Log Analytics workspace ARM ID explicitly.\n\n```python\nfrom azure.mgmt.applicationinsights.models import ApplicationInsightsComponent\n\nworkspace_id = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n    \"resourceGroups/example-rg/providers/\"\n    \"Microsoft.OperationalInsights/workspaces/example-law\"\n)\n\ncomponent = client.components.create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-ai\",\n    insight_properties=ApplicationInsightsComponent(\n        location=\"westus2\",\n        kind=\"web\",\n        application_type=\"web\",\n        workspace_resource_id=workspace_id,\n        retention_in_days=90,\n        ingestion_mode=\"LogAnalytics\",\n        public_network_access_for_ingestion=\"Enabled\",\n        public_network_access_for_query=\"Enabled\",\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n)\n\nprint(component.id)\nprint(component.workspace_resource_id)\n```\n\nImportant details from the current docs:\n\n- `location` and `kind` are required model fields.\n- `4.0.0` added `workspace_resource_id` as a required parameter on `ApplicationInsightsComponent`.\n- Older examples for classic, non-workspace resources are not the safe default for `4.1.0`.\n\n### List And Get Components\n\n```python\nfor item in client.components.list_by_resource_group(\"example-rg\"):\n    print(item.name, item.location, item.workspace_resource_id)\n\ncomponent = client.components.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-ai\",\n)\n\nprint(component.app_id)\nprint(component.connection_string)\n```\n\nUse `list_by_subscription_id()` when you need a cross-resource-group inventory for the current subscription.\n\n### Read Billing Features And Quota Settings\n\n```python\nbilling = client.component_current_billing_features.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-ai\",\n)\n\nprint(billing.current_billing_features)\n\nquota = client.component_quota_status.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-ai\",\n)\n\nprint(quota)\n```\n\nThese calls are useful when automation needs to inspect current pricing or daily-cap related state before making changes.\n\n### Discover Web Test Locations And Existing Web Tests\n\nList the supported synthetic test locations for a component:\n\n```python\nfor location in client.web_test_locations.list(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-ai\",\n):\n    print(location)\n```\n\nList the web tests currently attached to a component:\n\n```python\nfor test in client.web_tests.list_by_component(\n    component_name=\"example-ai\",\n    resource_group_name=\"example-rg\",\n):\n    print(test.name, test.web_test_kind, test.enabled)\n```\n\nRead one specific web test:\n\n```python\nweb_test = client.web_tests.get(\n    resource_group_name=\"example-rg\",\n    web_test_name=\"example-ping-test\",\n)\n\nprint(web_test.name)\nprint(web_test.synthetic_monitor_id)\n```\n\nThe package also exposes `web_tests.create_or_update(...)`, but the request body is large enough that it is worth starting from the current model docs instead of guessing fields from older samples.\n\n### List Workbooks And Fetch Workbook Content\n\n`workbooks` in the current client supports listing, fetching, updating, deleting, and reading revisions.\n\nList workbook resources in a resource group:\n\n```python\nfor workbook in client.workbooks.list_by_resource_group(\n    resource_group_name=\"example-rg\",\n    category=\"workbook\",\n    can_fetch_content=False,\n):\n    print(workbook.name, workbook.display_name, workbook.category)\n```\n\nFetch a workbook and include serialized content:\n\n```python\nworkbook = client.workbooks.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"11111111-2222-3333-4444-555555555555\",\n    can_fetch_content=True,\n)\n\nprint(workbook.display_name)\nprint(workbook.version)\nprint(workbook.serialized_data)\n```\n\nInspect workbook revisions:\n\n```python\nfor revision in client.workbooks.revisions_list(\n    resource_group_name=\"example-rg\",\n    resource_name=\"11111111-2222-3333-4444-555555555555\",\n):\n    print(revision.revision)\n```\n\nPractical rule: the workbook resource name is a UUID-like resource identifier, while `display_name` is the human-facing title.\n\n### Use The Preview Deleted Workbooks Surface\n\n`deleted_workbooks` is documented under `2024-02-01-preview`, so create a second client with that API version when you need it:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.applicationinsights import ApplicationInsightsManagementClient\n\npreview_client = ApplicationInsightsManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n    api_version=\"2024-02-01-preview\",\n)\n\nfor workbook in preview_client.deleted_workbooks.list_by_subscription(\n    category=\"workbook\",\n):\n    print(workbook.name)\n\npreview_client.close()\n```\n\nDo not expect `deleted_workbooks` to be available from the default `2023-06-01` client.\n\n## Version-Sensitive Notes\n\n### `4.1.0`\n\nPyPI release history for `4.1.0` notes:\n\n- `DeletedWorkbooksOperations` was added.\n- `system_data` was added to `Resource` and `TrackedResource`.\n\n### `4.0.0`\n\nThe `4.0.0` release is the important compatibility break for current examples:\n\n- `ApplicationInsightsComponent` added `workspace_resource_id` as a required parameter.\n- Workbook operations changed signatures: `create_or_update`, `list_by_resource_group`, `list_by_subscription`, and `update`.\n\nIf you are copying older Learn articles, verify that the sample is not from the pre-workspace or pre-`4.0.0` package line.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-applicationinsights` without `azure-identity`\n- Omitting `AZURE_SUBSCRIPTION_ID`; the credential does not provide the subscription automatically\n- Copying pre-`4.0.0` examples that create classic Application Insights components without `workspace_resource_id`\n- Expecting this package to send telemetry or query runtime logs; it manages Azure resources through ARM\n- Calling `deleted_workbooks` on the default client instead of constructing a preview client with `api_version=\"2024-02-01-preview\"`\n- Treating workbook `display_name` as the ARM resource name; `workbooks.get(...)` and revision APIs use the workbook resource name\n- Using Application Insights component purge guidance for workspace-based resources; the official component docs say purge is intended only for Classic resources and direct workspace-based purges should happen at the Log Analytics workspace\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-applicationinsights/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.applicationinsightsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.models.applicationinsightscomponent?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.operations.componentsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.operations.webtestsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.operations.workbooksoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-applicationinsights/azure.mgmt.applicationinsights.operations.deletedworkbooksoperations?view=azure-python-preview\n"
  },
  {
    "path": "content/azure/docs/mgmt-authorization/python/DOC.md",
    "content": "---\nname: mgmt-authorization\ndescription: \"azure-mgmt-authorization Python package for Azure RBAC role assignments, role definitions, permissions, and deny-assignment management\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,authorization,rbac,iam,role-assignments,role-definitions,python\"\n---\n\n# azure-mgmt-authorization Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-authorization` is the Azure Resource Manager SDK for Azure RBAC and related authorization resources from Python.\n\nUse it when you need to:\n\n- list or inspect role definitions\n- create, read, list, or delete role assignments\n- inspect the management-plane permissions the current caller has\n- work with newer authorization namespaces such as deny assignments when required\n\nPrimary import surface:\n\n```python\nfrom azure.mgmt.authorization import AuthorizationManagementClient\n```\n\nThis is an ARM management-plane client, not a Microsoft Graph client. Use it for subscription, resource-group, and resource scopes.\n\n## Install\n\nInstall the package plus a credential provider:\n\n```bash\npython -m pip install \"azure-mgmt-authorization==4.0.0\" azure-identity\n```\n\nPyPI metadata for `4.0.0` requires Python `>=3.7`.\n\n## Authentication And Setup\n\nUse `azure-identity` credentials. `DefaultAzureCredential` is the default choice for both local development and hosted Azure environments.\n\nLocal development:\n\n```bash\naz login\naz account set --subscription \"<subscription-id-or-name>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nService principal environment variables:\n\n```bash\nexport AZURE_CLIENT_ID=\"<app-client-id>\"\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nClient setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.authorization import AuthorizationManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = AuthorizationManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n```\n\nFor production, prefer managed identity or another non-interactive credential source. The constructor still needs a subscription ID even when the credential comes from Azure.\n\n## Scope Handling\n\nMany operations need a full ARM scope string:\n\n```python\nsubscription_scope = f\"/subscriptions/{subscription_id}\"\nresource_group_scope = (\n    f\"/subscriptions/{subscription_id}/resourceGroups/my-resource-group\"\n)\nresource_scope = (\n    f\"{resource_group_scope}/providers/Microsoft.Storage/storageAccounts/myaccount\"\n)\n```\n\nIf the scope is malformed, RBAC calls fail even when authentication is correct.\n\n## Quick Start\n\nList role assignments at subscription scope:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.authorization import AuthorizationManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nscope = f\"/subscriptions/{subscription_id}\"\n\nclient = AuthorizationManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\nfor assignment in client.role_assignments.list_for_scope(\n    scope=scope,\n    filter=\"atScope()\",\n):\n    print(assignment.id)\n    print(assignment.principal_id)\n    print(assignment.role_definition_id)\n```\n\nUse `list_for_scope` for `4.0.0` code. Older examples that call `role_assignments.list()` are from an older package line.\n\n## Core Usage\n\n### List Role Definitions\n\nResolve the role definition you want before creating an assignment:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.authorization import AuthorizationManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nscope = f\"/subscriptions/{subscription_id}\"\n\nclient = AuthorizationManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\nfor role in client.role_definitions.list(scope=scope):\n    print(role.id)\n    print(role.role_name)\n    print(role.type)\n```\n\nThe service expects the full role definition ID. In practice, look it up once and reuse `role.id`.\n\n### Create A Role Assignment\n\nRole assignment names must be GUIDs. `principal_id` must be the Microsoft Entra object ID of the user, group, or service principal, not the application client ID.\n\n```python\nimport os\nimport uuid\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.authorization import AuthorizationManagementClient\nfrom azure.mgmt.authorization.models import RoleAssignmentCreateParameters\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nprincipal_id = os.environ[\"AZURE_PRINCIPAL_OBJECT_ID\"]\nscope = f\"/subscriptions/{subscription_id}\"\n\nclient = AuthorizationManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\nreader_role = next(\n    role\n    for role in client.role_definitions.list(scope=scope)\n    if getattr(role, \"role_name\", None) == \"Reader\"\n)\n\nassignment = client.role_assignments.create(\n    scope=scope,\n    role_assignment_name=str(uuid.uuid4()),\n    parameters=RoleAssignmentCreateParameters(\n        role_definition_id=reader_role.id,\n        principal_id=principal_id,\n        principal_type=\"ServicePrincipal\",\n    ),\n)\n\nprint(assignment.id)\n```\n\nIn `4.0.0`, `RoleAssignmentCreateParameters` also exposes optional fields such as `description`, `condition`, `condition_version`, and `delegated_managed_identity_resource_id`.\n\n### Inspect Effective Permissions\n\nUse the permissions API when you need to know which management actions the current caller has.\n\nAt resource-group scope:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.authorization import AuthorizationManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = AuthorizationManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\nfor permission in client.permissions.list_for_resource_group(\n    resource_group_name=\"my-resource-group\"\n):\n    print(\"actions:\", permission.actions)\n    print(\"not_actions:\", permission.not_actions)\n    print(\"data_actions:\", permission.data_actions)\n    print(\"not_data_actions:\", permission.not_data_actions)\n```\n\nAt a specific resource, `parent_resource_path` is required by the method signature. Use `\"\"` when the target is not nested under another parent resource:\n\n```python\nfor permission in client.permissions.list_for_resource(\n    resource_group_name=\"my-resource-group\",\n    resource_provider_namespace=\"Microsoft.Storage\",\n    parent_resource_path=\"\",\n    resource_type=\"storageAccounts\",\n    resource_name=\"myaccount\",\n):\n    print(permission.actions)\n```\n\n### Remove A Role Assignment\n\nDelete by scope plus assignment GUID:\n\n```python\nclient.role_assignments.delete(\n    scope=f\"/subscriptions/{subscription_id}\",\n    role_assignment_name=\"00000000-0000-0000-0000-000000000000\",\n)\n```\n\nIf you only have the full assignment ID, parse the final GUID and reuse the original scope.\n\n### Use Versioned Namespaces Only When Needed\n\nThe package also exposes versioned namespaces, for example:\n\n```python\nfrom azure.mgmt.authorization.v2022_04_01 import AuthorizationManagementClient\n```\n\nUse a versioned namespace when you need a specific Authorization API version or an operation group that does not exist on older namespaces. For common RBAC automation in `4.0.0`, the top-level import is simpler.\n\n## Configuration And Auth Notes\n\n- `DefaultAzureCredential` is the default auth path for new code.\n- Set `AZURE_SUBSCRIPTION_ID` yourself; credential discovery does not supply it.\n- The identity you authenticate with must already have RBAC rights on the target scope before it can inspect or change assignments.\n- For local debugging, verify the effective identity and scope outside your script with `az account show` and `az role assignment list`.\n\n## Common Pitfalls\n\n- Do not pass an application client ID where the API expects `principal_id`; use the principal object ID.\n- Do not invent scopes. Use full ARM resource IDs such as `/subscriptions/<id>` or `/subscriptions/<id>/resourceGroups/<name>`.\n- Do not use this package for Microsoft Graph directory-role automation or app registration work.\n- `role_assignment_name` must be a GUID string, not a display name.\n- New RBAC assignments can be eventually consistent. A read immediately after create can briefly return 404 or incomplete results.\n- `permissions.list_for_resource_group()` takes only the resource group name, while role-assignment APIs usually take a full scope string.\n- `permissions.list_for_resource()` requires `parent_resource_path`; use `\"\"` for a top-level resource.\n\n## Version-Sensitive Notes\n\n- PyPI shows `4.0.0` as the current stable release for this package and `5.0.0b1` as a prerelease.\n- The Learn reference spans multiple Authorization API namespaces, including older `v2015_07_01` and newer `v2022_04_01` clients. Those namespaces do not expose identical operation groups.\n- In `2.0.0`, the old unscoped `RoleAssignmentsOperations.list` method was removed. Use `list_for_scope`, `list_for_subscription`, `list_for_resource_group`, or `list_for_resource` instead.\n- Older pre-1.0 examples may still use legacy Azure SDK credential patterns. For supported package lines, use `azure-identity`.\n- PyPI release notes for `4.0.0` also note added validation operations for role assignment and role eligibility schedule requests, and removal of `AlertOperationOperations.list_for_scope`.\n\n## Official Sources\n\n- Package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/mgmt-authorization-readme?view=azure-python`\n- API reference root: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/`\n- `AuthorizationManagementClient`: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/azure.mgmt.authorization.v2022_04_01.authorizationmanagementclient?view=azure-python`\n- `RoleAssignmentsOperations`: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/azure.mgmt.authorization.operations.roleassignmentsoperations?view=azure-python-preview`\n- `RoleDefinitionsOperations`: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/azure.mgmt.authorization.operations.roledefinitionsoperations?view=azure-python-preview`\n- `PermissionsOperations`: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/azure.mgmt.authorization.operations.permissionsoperations?view=azure-python-preview`\n- `RoleAssignmentCreateParameters`: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-authorization/azure.mgmt.authorization.models.roleassignmentcreateparameters?view=azure-python-preview`\n- Azure authorization overview for Python: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authorization/overview`\n- Azure management samples entry point: `https://learn.microsoft.com/en-us/samples/azure-samples/azure-samples-python-management/authorization/`\n- PyPI package page and release history: `https://pypi.org/project/azure-mgmt-authorization/`\n"
  },
  {
    "path": "content/azure/docs/mgmt-batch/python/DOC.md",
    "content": "---\nname: mgmt-batch\ndescription: \"Azure Batch management SDK for Python for Batch accounts, account keys, auto-storage synchronization, application packages, and regional quota discovery through Azure Resource Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"18.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,batch,arm,management,python,compute\"\n---\n\n# Azure Batch Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-batch` for Azure Resource Manager management-plane work around Azure Batch accounts. This package manages Batch accounts, account-level settings, keys, applications, and regional capacity metadata. If you need to create pools, jobs, or tasks inside a Batch account, switch to the Batch service API and the `azure-batch` package instead of trying to do runtime workload operations through `azure-mgmt-batch`.\n\nFor `18.0.0`, the generated client expects an `azure-core` `TokenCredential`, so the safe default is `azure-identity` with `DefaultAzureCredential`.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-batch==18.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-batch==18.0.0\" azure-identity\npoetry add \"azure-mgmt-batch==18.0.0\" azure-identity\n```\n\nPyPI lists `18.0.0` as released on `2025-05-30` and requiring Python `>=3.7`.\n\nIf the same Python program also creates the resource group or storage account that your Batch account depends on, install those management packages separately:\n\n```bash\npython -m pip install azure-mgmt-resource azure-mgmt-storage\n```\n\n## Authentication And Setup\n\nSet the subscription ID explicitly. The Batch management client does not infer it from the credential.\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor service-principal auth through environment variables, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, `DefaultAzureCredential()` can also use an Azure CLI login from `az login`.\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.batch import BatchManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = BatchManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nThe main operation groups exposed in the current Learn reference are:\n\n- `batch_account`\n- `application`\n- `application_package`\n- `location`\n- `operations`\n\n## Create A Batch Account\n\nThe account create flow is a long-running ARM operation, so call `.result()` on the poller before using the new account.\n\nIf you want the account linked to an Azure Storage account for auto-storage, pass the full storage account resource ID, not just the storage account name.\n\n```bash\nexport AZURE_BATCH_RESOURCE_GROUP=\"example-rg\"\nexport AZURE_BATCH_ACCOUNT_NAME=\"examplebatchacct\"\nexport AZURE_BATCH_LOCATION=\"westus2\"\nexport AZURE_STORAGE_ACCOUNT_ID=\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Storage/storageAccounts/examplestorageacct\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.batch import BatchManagementClient\nfrom azure.mgmt.batch.models import AutoStorageBaseProperties, BatchAccountCreateParameters\n\nclient = BatchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\naccount = client.batch_account.begin_create(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n    parameters=BatchAccountCreateParameters(\n        location=os.environ[\"AZURE_BATCH_LOCATION\"],\n        auto_storage=AutoStorageBaseProperties(\n            os.environ[\"AZURE_STORAGE_ACCOUNT_ID\"],\n        ),\n    ),\n).result()\n\nprint(account.id)\n```\n\nRead or enumerate accounts with the same operation group:\n\n```python\naccount = client.batch_account.get(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n)\n\nprint(account.name, account.location)\n\nfor item in client.batch_account.list():\n    print(item.name)\n```\n\nDelete is also long-running:\n\n```python\nclient.batch_account.begin_delete(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n).result()\n```\n\n## Update Account Settings\n\nPatch-style account changes use `batch_account.update(...)`, not `begin_update(...)`.\n\nThe current model reference documents `public_network_access` and `allowed_authentication_modes` on `BatchAccountUpdateParameters`, which are the settings most likely to affect new integrations.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.batch import BatchManagementClient\nfrom azure.mgmt.batch.models import BatchAccountUpdateParameters\n\nclient = BatchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nupdated = client.batch_account.update(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n    parameters=BatchAccountUpdateParameters(\n        public_network_access=\"Enabled\",\n        allowed_authentication_modes=[\"AAD\", \"SharedKey\"],\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n)\n\nprint(updated.name)\n```\n\nUse `allowed_authentication_modes` deliberately. If your environment is supposed to be Microsoft Entra ID only, do not keep `SharedKey` enabled by habit.\n\n## Work With Account Keys And Auto-Storage\n\nThe management client can retrieve account keys, regenerate them, and resync the linked auto-storage keys.\n\nFetch the current Batch account keys:\n\n```python\nkeys = client.batch_account.get_keys(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n)\n\nprint(keys.primary)\nprint(keys.secondary)\n```\n\nIf the linked storage account keys were rotated outside Batch, resync the Batch account's stored auto-storage keys:\n\n```python\nclient.batch_account.synchronize_auto_storage_keys(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n)\n```\n\nTreat key retrieval as a management exception, not the default app-auth pattern. For new automation, prefer Entra ID where the surrounding Azure service supports it.\n\n## Check Regional Quotas And Supported VM SKUs\n\nBefore provisioning pools or scaling account usage, query the Batch regional metadata instead of guessing what a region allows.\n\n```python\nlocation = os.environ[\"AZURE_BATCH_LOCATION\"]\n\nquota = client.location.get_quotas(location)\nprint(quota)\n\nfor sku in client.location.list_supported_virtual_machine_skus(location):\n    print(sku.name)\n```\n\nThe quota response and supported-SKU list are useful guardrails when your automation needs to pick a region or validate capacity assumptions ahead of time.\n\n## Applications And Application Packages\n\nThe current client includes `application` and `application_package` operation groups for account-scoped application metadata.\n\nFor package inspection, use the application-package operation group:\n\n```python\nfor package in client.application_package.list(\n    resource_group_name=os.environ[\"AZURE_BATCH_RESOURCE_GROUP\"],\n    account_name=os.environ[\"AZURE_BATCH_ACCOUNT_NAME\"],\n    application_name=\"ffmpeg\",\n):\n    print(package)\n```\n\nFor create, activate, or delete flows on application packages, use the same `client.application_package.*` surface and verify the exact model shape against the current Learn reference before copying older samples.\n\n## Common Pitfalls\n\n- `azure-mgmt-batch` is the ARM management SDK, not the Batch runtime SDK. Use `azure-batch` for jobs, tasks, and pool runtime workflows.\n- Forgetting `azure-identity` is common. The current client constructor takes a `TokenCredential`, not the older Track 1 auth types.\n- `subscription_id` is required even when the credential resolves successfully.\n- `begin_create()` and `begin_delete()` return pollers. Do not assume the account exists or is gone until you wait on `.result()`.\n- `AutoStorageBaseProperties` expects a storage account resource ID. A plain account name is not enough.\n- Pulling shared keys into app code is usually the wrong default. Decide whether the account should allow `SharedKey`, `AAD`, or both before wiring auth flows around the management API.\n\n## Version-Sensitive Notes For 18.0.0\n\n- This guide covers `azure-mgmt-batch 18.0.0`.\n- PyPI lists `18.0.0` as the current package version for this guide's input and publishes wheels for Python `>=3.7`.\n- The current Microsoft Learn reference for `BatchManagementClient` is based on `TokenCredential` auth and exposes operation groups such as `batch_account`, `application_package`, and `location`. Older examples that still assume legacy Azure auth helpers are not the right default for `18.0.0`.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-batch/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.batchmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.operations.batchaccountoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.operations.locationoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.operations.applicationpackageoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.models.batchaccountcreateparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.models.autostoragebaseproperties?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-batch/azure.mgmt.batch.models.batchaccountupdateparameters?view=azure-python\n- https://learn.microsoft.com/en-us/azure/batch/batch-apis-tools\n- https://learn.microsoft.com/en-us/python/api/overview/azure/batch?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-cdn/python/DOC.md",
    "content": "---\nname: mgmt-cdn\ndescription: \"Azure CDN and Azure Front Door Standard/Premium management SDK for Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,cdn,front-door,arm,management,networking\"\n---\n\n# Azure CDN Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-cdn` for Azure management-plane work on `Microsoft.Cdn` resources: classic CDN profiles/endpoints and Azure Front Door Standard/Premium profiles, endpoints, origins, routes, custom domains, secrets, and security policies. Authenticate with `azure-identity`, pass `AZURE_SUBSCRIPTION_ID` explicitly, and treat most writes as long-running `begin_*` operations that need `.result()`.\n\n## Install\n\nPyPI lists `azure-mgmt-cdn 13.1.1` as supporting Python `3.8+`.\n\n```bash\npython -m pip install \"azure-mgmt-cdn==13.1.1\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-cdn==13.1.1\" azure-identity\npoetry add \"azure-mgmt-cdn==13.1.1\" azure-identity\n```\n\n## Authentication And Setup\n\nFor most code, use one of these credential patterns:\n\n- `DefaultAzureCredential()` for reusable code that should work locally, in CI, and on Azure\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cdn import CdnManagementClient\n\ncredential = DefaultAzureCredential()\n\nwith CdnManagementClient(\n    credential=credential,\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for profile in client.profiles.list():\n        print(profile.name, profile.sku.name if profile.sku else None)\n```\n\nFor local CLI-driven scripts:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.cdn import CdnManagementClient\n\nclient = CdnManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n`CdnManagementClient` defaults to ARM `base_url=\"https://management.azure.com\"` and API version `2024-02-01`. The reference docs warn that overriding `api_version` may result in unsupported behavior.\n\n## Pick The Right Operation Group\n\nThe same client covers both classic CDN and Azure Front Door Standard/Premium:\n\n- Classic CDN: `profiles`, `endpoints`, `origins`, `origin_groups`, `custom_domains`\n- Azure Front Door Standard/Premium: `profiles` for the top-level profile, then `afd_endpoints`, `afd_origin_groups`, `afd_origins`, `routes`, `afd_custom_domains`, `rule_sets`, `rules`, `security_policies`, `secrets`, `log_analytics`\n- Migration and AFD profile helpers: `afd_profiles`\n\nThe profile SKU decides what you are creating:\n\n- Classic CDN example SKUs: `Standard_Microsoft`, `Standard_Verizon`, `Premium_Verizon`, `Standard_Akamai`\n- Azure Front Door SKUs: `Standard_AzureFrontDoor`, `Premium_AzureFrontDoor`\n\n## Create A Classic CDN Profile And Endpoint\n\nThis is the basic create flow for a classic CDN profile plus one endpoint:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cdn import CdnManagementClient\n\nresource_group = \"example-rg\"\nprofile_name = \"example-classic-cdn\"\nendpoint_name = \"examplecdnendpoint123\"  # must be globally unique\nlocation = \"<resource-location>\"\norigin_host = \"www.contoso.com\"\n\nwith CdnManagementClient(DefaultAzureCredential(), os.environ[\"AZURE_SUBSCRIPTION_ID\"]) as client:\n    profile = client.profiles.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile_name,\n        profile={\n            \"location\": location,\n            \"sku\": {\"name\": \"Standard_Microsoft\"},\n            \"tags\": {\"env\": \"dev\"},\n        },\n    ).result()\n\n    endpoint = client.endpoints.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile.name,\n        endpoint_name=endpoint_name,\n        endpoint={\n            \"location\": location,\n            \"is_http_allowed\": False,\n            \"is_https_allowed\": True,\n            \"origins\": [\n                {\n                    \"name\": \"app-origin\",\n                    \"host_name\": origin_host,\n                    \"https_port\": 443,\n                    \"origin_host_header\": origin_host,\n                }\n            ],\n        },\n    ).result()\n\n    print(endpoint.host_name)\n```\n\nPractical notes:\n\n- `profile_name` is unique within the resource group.\n- `endpoint_name` is globally unique.\n- Older Learn overview pages still show `.create(...)`; for `13.1.1`, the current operation docs use `begin_create(...)`.\n\n## Create An Azure Front Door Standard Profile, Endpoint, Origin Group, Origin, And Route\n\nFront Door Standard/Premium uses the same top-level `profiles` operation group, but endpoint and routing resources live under the AFD-specific groups:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cdn import CdnManagementClient\n\nresource_group = \"example-rg\"\nprofile_name = \"example-afd-profile\"\nendpoint_name = \"exampleafdendpoint123\"  # must be globally unique\norigin_group_name = \"app-origin-group\"\norigin_name = \"app-origin\"\nroute_name = \"default-route\"\nlocation = \"<resource-location>\"\norigin_host = \"www.contoso.com\"\n\nwith CdnManagementClient(DefaultAzureCredential(), os.environ[\"AZURE_SUBSCRIPTION_ID\"]) as client:\n    profile = client.profiles.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile_name,\n        profile={\n            \"location\": location,\n            \"sku\": {\"name\": \"Standard_AzureFrontDoor\"},\n        },\n    ).result()\n\n    endpoint = client.afd_endpoints.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile.name,\n        endpoint_name=endpoint_name,\n        endpoint={\n            \"location\": location,\n            \"enabled_state\": \"Enabled\",\n        },\n    ).result()\n\n    origin_group = client.afd_origin_groups.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile.name,\n        origin_group_name=origin_group_name,\n        origin_group={\n            \"health_probe_settings\": {\n                \"probe_path\": \"/healthz\",\n                \"probe_request_type\": \"HEAD\",\n                \"probe_protocol\": \"Https\",\n                \"probe_interval_in_seconds\": 120,\n            },\n            \"load_balancing_settings\": {\n                \"sample_size\": 4,\n                \"successful_samples_required\": 3,\n                \"additional_latency_in_milliseconds\": 50,\n            },\n            \"session_affinity_state\": \"Disabled\",\n        },\n    ).result()\n\n    origin = client.afd_origins.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile.name,\n        origin_group_name=origin_group.name,\n        origin_name=origin_name,\n        origin={\n            \"host_name\": origin_host,\n            \"https_port\": 443,\n            \"origin_host_header\": origin_host,\n            \"priority\": 1,\n            \"weight\": 1000,\n            \"enabled_state\": \"Enabled\",\n            \"enforce_certificate_name_check\": True,\n        },\n    ).result()\n\n    route = client.routes.begin_create(\n        resource_group_name=resource_group,\n        profile_name=profile.name,\n        endpoint_name=endpoint.name,\n        route_name=route_name,\n        route={\n            \"origin_group\": {\"id\": origin_group.id},\n            \"supported_protocols\": [\"Http\", \"Https\"],\n            \"patterns_to_match\": [\"/*\"],\n            \"forwarding_protocol\": \"MatchRequest\",\n            \"link_to_default_domain\": \"Enabled\",\n            \"https_redirect\": \"Enabled\",\n            \"enabled_state\": \"Enabled\",\n        },\n    ).result()\n\n    print(endpoint.host_name)\n    print(origin.id)\n    print(route.id)\n```\n\nImportant details from the model docs:\n\n- `AFDEndpoint` requires `location`\n- `AFDOrigin.host_name` is the origin address\n- `AFDOrigin.origin_host_header` should usually match the hostname your origin expects\n- `Route.origin_group` is a resource reference to the origin group\n\n## Purge Cached AFD Content\n\nUse `afd_endpoints.begin_purge_content(...)` when you need to invalidate cached content:\n\n```python\nclient.afd_endpoints.begin_purge_content(\n    resource_group_name=\"example-rg\",\n    profile_name=\"example-afd-profile\",\n    endpoint_name=\"exampleafdendpoint123\",\n    contents={\n        \"content_paths\": [\"/images/*\", \"/css/app.css\"],\n        \"domains\": [\"www.contoso.com\"],\n    },\n).result()\n```\n\nFor Front Door routes, caching is optional. The route model docs explicitly say to omit `cache_configuration` if you want caching disabled.\n\n## Validate A Custom Domain Before Wiring DNS-Dependent Flows\n\nBoth classic CDN endpoints and AFD endpoints expose `validate_custom_domain(...)` helpers. The validation input is a host name:\n\n```python\nvalidation = client.afd_endpoints.validate_custom_domain(\n    resource_group_name=\"example-rg\",\n    profile_name=\"example-afd-profile\",\n    endpoint_name=\"exampleafdendpoint123\",\n    custom_domain_properties={\n        \"host_name\": \"cdn.contoso.com\",\n    },\n)\n```\n\nUse the same pattern with `client.endpoints.validate_custom_domain(...)` for classic CDN endpoints.\n\n## Version-Sensitive Notes\n\n### `13.1.1`\n\n- PyPI release notes for `13.1.1` only call out a serialization bug fix for `azure.core.serialization.NULL`.\n\n### `13.0.0`\n\nThis is the important line for copied examples:\n\n- Long-running methods were renamed to `begin_*` and now return `azure.core.polling.LROPoller`\n- Most exceptions are now `azure.core.exceptions.HttpResponseError`\n- Async support is available in the `azure.mgmt.cdn.aio` namespace\n- `profiles.begin_can_migrate(...)`, `profiles.begin_migrate(...)`, and `profiles.begin_migration_commit(...)` were added for classic CDN to AFD migration flows\n- `afd_profiles.begin_upgrade(...)`, `afd_profiles.check_endpoint_name_availability(...)`, and `afd_profiles.validate_secret(...)` were added for AFD profile operations\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-cdn` without also installing `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`; the client does not infer it from the credential\n- Mixing classic CDN operations like `endpoints` with AFD operations like `afd_endpoints` and `routes`\n- Copying older `client.profiles.create(...)` or `client.endpoints.create(...)` examples into a `13.x` project\n- Forgetting `.result()` on create, update, delete, purge, start, and stop flows\n- Using `endpoints.begin_update(...)` or `afd_endpoints.begin_update(...)` to try to change origins or domains; the operation docs say those endpoint update calls are only for tags after creation\n- Reusing an endpoint name that is not globally unique\n- Reusing the same origin hostname where the origin docs require it to be unique within the endpoint or origin group\n- Overriding `api_version` without a strong reason; the constructor docs warn this can lead to unsupported behavior\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-cdn/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/content-delivery-network?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.cdnmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.profilesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.endpointsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.afdendpointsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.afdorigingroupsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.afdoriginsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.routesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.profile?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.afdendpoint?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.afdorigingroup?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.afdorigin?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.route?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.validatecustomdomaininput?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.models.afdpurgeparameters?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-cognitiveservices/python/DOC.md",
    "content": "---\nname: mgmt-cognitiveservices\ndescription: \"Azure AI Services and Azure OpenAI management-plane SDK for Python for accounts, models, deployments, keys, and project resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"14.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,ai-services,cognitive-services,openai,arm,management,azure-identity\"\n---\n\n# Azure Cognitive Services Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-cognitiveservices` only for Azure Resource Manager control-plane work such as creating Azure AI Services or Azure OpenAI accounts, listing available models, managing deployments, rotating keys, and creating project resources. Pair it with `azure-identity`, authenticate with a modern `TokenCredential`, and use a service-specific data-plane SDK after the resource exists.\n\n## Install\n\nInstall the management client and an Azure credential package together:\n\n```bash\npython -m pip install \"azure-mgmt-cognitiveservices==14.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-cognitiveservices==14.1.0\" azure-identity\npoetry add \"azure-mgmt-cognitiveservices==14.1.0\" azure-identity\n```\n\n`14.1.0` supports Python `3.9+`.\n\n## Authentication And Setup\n\nManagement-plane calls use Microsoft Entra tokens. The usual setup is:\n\n- local development: `az login` plus `DefaultAzureCredential()` or `AzureCliCredential()`\n- CI or local non-interactive scripts: service principal credentials\n- Azure-hosted workloads: managed identity\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you use environment-based service-principal auth directly:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cognitiveservices import CognitiveServicesManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = CognitiveServicesManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor local scripts that should use the active Azure CLI login explicitly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.cognitiveservices import CognitiveServicesManagementClient\n\nclient = CognitiveServicesManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## Core Usage\n\nThese patterns matter throughout the package:\n\n- most writes are `begin_*` long-running ARM operations; call `.result()` before assuming the resource exists\n- `subscription_id` is required even when the credential is valid\n- this package manages ARM resources and metadata; it does not send prompts, synthesize speech, or run inference itself\n\n### Discover Valid Kinds And SKUs For A Region\n\nDo not guess the account `kind` or `sku`. Check what the subscription can create in your target region first:\n\n```python\nLOCATION = \"eastus\"\n\nfor sku in client.resource_skus.list():\n    locations = {loc.lower() for loc in (sku.locations or [])}\n\n    if LOCATION.lower() in locations and sku.kind in {\"AIServices\", \"OpenAI\"}:\n        print(\n            f\"kind={sku.kind} sku={sku.name} \"\n            f\"tier={sku.tier} restrictions={sku.restrictions}\"\n        )\n```\n\nThis is the safest way to confirm whether your subscription and region support `AIServices`, `OpenAI`, or another resource kind before creating anything.\n\n### Create Or Update An Account\n\nUse `accounts.begin_create(...)` and keep the request body explicit. This example creates a generic Azure AI Services account using the first unrestricted SKU found for the region:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cognitiveservices import CognitiveServicesManagementClient\n\nRESOURCE_GROUP = \"example-rg\"\nACCOUNT_NAME = \"example-ai-1234\"\nLOCATION = \"eastus\"\n\nclient = CognitiveServicesManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nselected_sku = next(\n    sku\n    for sku in client.resource_skus.list()\n    if sku.kind == \"AIServices\"\n    and LOCATION.lower() in {loc.lower() for loc in (sku.locations or [])}\n    and not sku.restrictions\n)\n\naccount = client.accounts.begin_create(\n    resource_group_name=RESOURCE_GROUP,\n    account_name=ACCOUNT_NAME,\n    account={\n        \"kind\": selected_sku.kind,\n        \"location\": LOCATION,\n        \"sku\": {\"name\": selected_sku.name},\n        \"properties\": {\n            \"custom_sub_domain_name\": ACCOUNT_NAME,\n            \"public_network_access\": \"Enabled\",\n            \"disable_local_auth\": False,\n        },\n    },\n).result()\n\nprint(account.id)\nprint(account.kind)\nprint(account.properties.endpoint)\n```\n\nImportant account properties from the SDK docs:\n\n- `custom_sub_domain_name` is the custom subdomain used for token-based authentication\n- `public_network_access` controls whether the public endpoint stays reachable\n- `disable_local_auth` disables key-based downstream authentication\n- `allow_project_management` must be `True` if you plan to create child project resources under the account\n\n### Read Keys Or Rotate One\n\nThe management client can return account keys for downstream service clients:\n\n```python\nkeys = client.accounts.list_keys(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-ai-1234\",\n)\n\nprint(keys.key1)\nprint(keys.key2)\n```\n\nRotate one key without replacing both:\n\n```python\nrotated = client.accounts.regenerate_key(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-ai-1234\",\n    key_name=\"Key2\",\n)\n\nprint(rotated.key2)\n```\n\nIf you set `disable_local_auth=True`, do not expect key-based data-plane clients to keep working.\n\n### List Deployable Models For An Account\n\nUse `accounts.list_models(...)` to inspect models available to the account before creating a deployment:\n\n```python\nmodels = client.accounts.list_models(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-ai-1234\",\n)\n\nfor model in models:\n    if model.skus:\n        sku_names = [sku.name for sku in model.skus]\n        print(model.format, model.name, model.version, sku_names)\n```\n\nThis is safer than hardcoding a model name, version, or deployment SKU from an older example.\n\n### Create Or Update A Deployment\n\nDeployment creation goes through `client.deployments.begin_create_or_update(...)`. The deployment `sku` lives on the deployment resource itself; current SDK docs mark `properties.scale_settings` as deprecated.\n\n```python\nRESOURCE_GROUP = \"example-rg\"\nACCOUNT_NAME = \"example-ai-1234\"\nDEPLOYMENT_NAME = \"default-deployment\"\n\nmodel = next(\n    item\n    for item in client.accounts.list_models(\n        resource_group_name=RESOURCE_GROUP,\n        account_name=ACCOUNT_NAME,\n    )\n    if item.skus\n)\n\ndeployment = client.deployments.begin_create_or_update(\n    resource_group_name=RESOURCE_GROUP,\n    account_name=ACCOUNT_NAME,\n    deployment_name=DEPLOYMENT_NAME,\n    deployment={\n        \"sku\": {\n            \"name\": model.skus[0].name,\n            \"capacity\": 1,\n        },\n        \"properties\": {\n            \"model\": {\n                \"format\": model.format,\n                \"name\": model.name,\n                \"version\": model.version,\n            },\n            \"version_upgrade_option\": \"NoAutoUpgrade\",\n        },\n    },\n).result()\n\nprint(deployment.id)\nprint(deployment.properties.provisioning_state)\n```\n\nBefore you copy this into a real app, confirm the chosen model SKU and capacity match your quota for that region and account.\n\n### Create A Project Under An Account\n\nIf you use Azure AI Foundry project resources, enable project management on the parent account first:\n\n```python\nclient.accounts.begin_update(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-ai-1234\",\n    account={\n        \"properties\": {\n            \"allow_project_management\": True,\n        }\n    },\n).result()\n```\n\nThen create the project:\n\n```python\nproject = client.projects.begin_create(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-ai-1234\",\n    project_name=\"demo-project\",\n    project={\n        \"location\": \"eastus\",\n        \"properties\": {\n            \"display_name\": \"demo-project\",\n            \"description\": \"Project container for app-specific resources\",\n        },\n    },\n).result()\n\nprint(project.id)\n```\n\n## Configuration Notes\n\n- `CognitiveServicesManagementClient` defaults to API version `2025-09-01`. The SDK docs warn that overriding `api_version` may result in unsupported behavior.\n- Reuse a long-lived client within a script or service instead of constructing one per call.\n- `14.1.0` adds `cloud_setting` support for non-public Azure clouds. Keep the credential authority host and ARM cloud setting aligned if you target Azure Government or another sovereign cloud.\n- Many create and update operations depend on ARM authorization at subscription, resource-group, or resource scope. A successful token from `DefaultAzureCredential` does not guarantee the caller can create accounts or deployments.\n\n## Version-Sensitive Notes For 14.1.0\n\n- PyPI lists `14.1.0` as released on `2025-10-24`.\n- `14.1.0` adds `cloud_setting` on the management client plus `rai_topics` and `quota_tiers` operation groups.\n- `14.0.0` is the breaking release that removed `NetworkInjections` in favor of `NetworkInjection`.\n- `13.7.0` added `projects`, `account_connections`, `project_connections`, `account_capability_hosts`, and `project_capability_hosts`, plus related account properties such as `allow_project_management`.\n- `13.0.0` is the release where the package stopped shipping older API-version subpackages and moved to the latest API version only. If your code imports older versioned namespaces, pin an earlier package release instead of mixing examples across major versions.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-cognitiveservices` and forgetting `azure-identity`\n- Using this package for data-plane inference, speech synthesis, vision analysis, or embeddings instead of only ARM management\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Skipping `.result()` on `begin_create`, `begin_update`, `begin_delete`, or deployment operations\n- Hardcoding account `kind`, account `sku`, model name, or deployment SKU without checking `resource_skus.list()` and `accounts.list_models(...)`\n- Setting `disable_local_auth=True` and then expecting account keys to keep working in downstream clients\n- Forgetting `custom_sub_domain_name` when the target service requires a token-auth-enabled custom subdomain\n- Using deprecated deployment `scale_settings` instead of the deployment-level `sku`\n- Trying to create projects before enabling `allow_project_management` on the parent account\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-cognitiveservices/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.cognitiveservicesmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.operations.accountsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.operations.deploymentsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.operations.projectsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.account?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.accountproperties?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.deployment?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.deploymentproperties?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.project?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-cognitiveservices/azure.mgmt.cognitiveservices.models.sku?view=azure-python\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.cognitiveservices/accounts\n"
  },
  {
    "path": "content/azure/docs/mgmt-communication/python/DOC.md",
    "content": "---\nname: mgmt-communication\ndescription: \"Azure Communication Services management-plane SDK for Python for Communication Services, Email Services, domains, sender usernames, and related ARM resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,communication,arm,management,email,python,pypi\"\n---\n\n# Azure Communication Services Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-communication` for Azure Resource Manager control-plane work only: creating and managing Communication Services resources, Email Services resources, email domains, and sender usernames.\n\nDo not use it to send email, SMS, or chat traffic. For data-plane work, switch to the service SDKs such as `azure-communication-email` or `azure-communication-sms`.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-communication==2.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-communication==2.2.0\" azure-identity\npoetry add \"azure-mgmt-communication==2.2.0\" azure-identity\n```\n\nPyPI currently lists Python `>=3.9` for `2.2.0`.\n\n## Authentication And Setup\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nLocal scripts can use Azure CLI credentials after:\n\n```bash\naz login\naz account set --subscription \"$AZURE_SUBSCRIPTION_ID\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.communication import CommunicationServiceManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = CommunicationServiceManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor local one-off scripts, `AzureCliCredential()` is also a reasonable choice:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.communication import CommunicationServiceManagementClient\n\nclient = CommunicationServiceManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## Current Package Surface\n\nThe current Learn API reference exposes these main operation groups:\n\n- `communication_services`\n- `email_services`\n- `domains`\n- `sender_usernames`\n\nPyPI release notes for `2.2.0` also call out newer preview additions:\n\n- `smtp_usernames`\n- `suppression_lists`\n- `suppression_list_addresses`\n\nTreat those newer groups as version-sensitive. The package release notes mention them, but the Learn package index may lag behind the latest generated surface.\n\n## Core Usage\n\n### List existing Communication Services resources\n\nUse this first when you need to discover the current ARM state before creating or updating anything:\n\n```python\nfor resource in client.communication_services.list_by_subscription():\n    print(resource.name, resource.location, resource.data_location)\n```\n\nTo scope to one resource group:\n\n```python\nfor resource in client.communication_services.list_by_resource_group(\"example-rg\"):\n    print(resource.name, resource.host_name)\n```\n\n### Create or update an Email Service resource\n\nEmail Services are separate ARM resources used for managed email domains and sender configuration.\n\n```python\nemail_service = client.email_services.create_or_update(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    parameters={\n        \"location\": \"global\",\n        \"data_location\": \"United States\",\n    },\n)\n\nprint(email_service.id)\n```\n\nUse a supported `data_location` value for your region and compliance needs. The Email Services ARM resource is global even though the data residency setting is still required.\n\n### Create a customer-managed email domain\n\nCreate the domain under the Email Service, then configure the DNS records Azure returns for verification.\n\n```python\ndomain = client.domains.create_or_update(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n    parameters={\n        \"location\": \"global\",\n        \"domain_management\": \"CustomerManaged\",\n        \"user_engagement_tracking\": \"Enabled\",\n    },\n)\n\nprint(domain.id)\n```\n\nFetch the domain again after creation to inspect its current verification state and any returned DNS data:\n\n```python\ndomain = client.domains.get(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n)\n\nprint(domain.domain_management)\nprint(domain.provisioning_state)\n```\n\nList all domains for an Email Service:\n\n```python\nfor domain in client.domains.list_by_email_service_resource(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n):\n    print(domain.name, domain.domain_management, domain.provisioning_state)\n```\n\n### Manage sender usernames under a domain\n\nSender usernames are the identities you use when sending email from a managed domain.\n\nFetch one directly:\n\n```python\nsender = client.sender_usernames.get(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n    sender_username=\"no-reply\",\n)\n\nprint(sender.name)\n```\n\nList sender usernames for a domain:\n\n```python\nfor sender in client.sender_usernames.list_by_domains(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n):\n    print(sender.name)\n```\n\nDelete a sender username you no longer need:\n\n```python\nclient.sender_usernames.delete(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n    sender_username=\"no-reply\",\n)\n```\n\nFor sender-username creation flows, verify the exact `SenderUsernameResource` request shape in your installed `2.2.0` SDK before copying older examples. The operation group is documented, but current task-oriented Learn examples are sparse.\n\n### Delete a domain or Email Service\n\nUse explicit cleanup in development environments so you do not leave unused ARM resources behind:\n\n```python\nclient.domains.delete(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n    domain_name=\"example.com\",\n)\n\nclient.email_services.delete(\n    resource_group_name=\"example-rg\",\n    email_service_name=\"example-email-service\",\n)\n```\n\n## Configuration Notes\n\n- `subscription_id` is required. The client does not infer it from the credential.\n- `DefaultAzureCredential` tries several credential sources in order. If auth behaves differently than expected, check which credential source actually won.\n- The client constructor in current docs accepts `base_url`, `credential_scopes`, `polling_interval`, and `api_version`. The `2.2.0` release notes also mention a `cloud_setting` parameter for cloud environment selection.\n- Azure management operations still depend on RBAC at the subscription, resource-group, or resource scope. Authentication success does not imply authorization success.\n\n## Common Pitfalls\n\n- This package is management plane only. Creating an Email Service here does not give you a data-plane email client.\n- Communication Services resources and Email Services resources are separate ARM resources. Do not assume creating one automatically provisions or links the other.\n- Domain setup is not finished when `create_or_update()` returns. Customer-managed domains still need the Azure-provided DNS records to be added and verified before they are usable for sending.\n- Use `global` for the ARM resource location shown in official examples for Email Services and domain resources; the residency choice belongs in `data_location`.\n- `DefaultAzureCredential` can silently authenticate with Azure CLI, managed identity, or environment credentials depending on where the code runs. Be explicit when debugging permission issues.\n- The Learn API reference currently lags some `2.2.0` surface added in PyPI release notes. Be careful when copying older examples or relying on incomplete package index pages for preview features.\n\n## Version-Sensitive Notes For `2.2.0`\n\n- PyPI release notes for `2.2.0` call out new preview operation groups for SMTP usernames, suppression lists, and suppression list addresses.\n- The same release notes add `public_network_access` and `disable_local_auth` properties on `CommunicationServiceResource`.\n- The `2.2.0` release also mentions `cloud_setting` support on `CommunicationServiceManagementClient`.\n- If you need those newer features, verify against the installed `2.2.0` SDK surface before copying older `2.1.x` examples. Current Learn package pages are useful for the stable operation groups but may lag on the newest generated objects.\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-communication/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-communication/azure.mgmt.communication.communicationservicemanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-communication/azure.mgmt.communication.operations.emailservicesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-communication/azure.mgmt.communication.operations.domainsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-communication/azure.mgmt.communication.operations.senderusernamesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/email/connect-azure-communication-services-verified-email-domain\n- https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/email/manage-suppression-lists\n- https://pypi.org/project/azure-mgmt-communication/\n"
  },
  {
    "path": "content/azure/docs/mgmt-compute/python/DOC.md",
    "content": "---\nname: mgmt-compute\ndescription: \"Azure Compute management SDK for Python for managing virtual machines, VM scale sets, disks, snapshots, images, galleries, and compute SKUs through Azure Resource Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"37.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,compute,virtual-machines,vmss,disks,arm,python\"\n---\n\n# Azure Compute Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-compute` for Azure Compute management-plane operations, authenticate it with a modern `TokenCredential` such as `DefaultAzureCredential`, and remember that most write operations are long-running `begin_*` calls that need `.result()`. This package manages Azure resources through ARM; it does not replace guest-level SSH, WinRM, or OS provisioning tools.\n\n## Install\n\nPin the package version your project expects and install a credential package alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-compute==37.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-compute==37.2.0\" azure-identity\npoetry add \"azure-mgmt-compute==37.2.0\" azure-identity\n```\n\n## Authentication And Setup\n\nThe standard setup is `DefaultAzureCredential` plus `AZURE_SUBSCRIPTION_ID`.\n\nEnvironment variables for service-principal auth:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n`DefaultAzureCredential` tries several identities in order, including environment-configured service principal credentials, workload identity, managed identity, Azure CLI login, Azure PowerShell login, and Azure Developer CLI login. That makes it the safest default for local development and Azure-hosted workloads.\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.compute import ComputeManagementClient\n\nclient = ComputeManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nFor sovereign or custom ARM endpoints, pass `base_url=` or `cloud_setting=` when constructing `ComputeManagementClient`.\n\n## Core Usage Patterns\n\nTwo SDK patterns matter everywhere in this package:\n\n- `begin_*` methods return Azure long-running operation pollers. Call `.result()` before assuming the mutation finished.\n- `list*` methods typically return paged iterators. Iterate over them instead of assuming a fully materialized list.\n\n### List virtual machines in a resource group\n\n```python\nfor vm in client.virtual_machines.list(\"my-resource-group\"):\n    print(vm.name, vm.location)\n```\n\n### Get VM details and runtime state\n\n```python\nvm = client.virtual_machines.get(\n    resource_group_name=\"my-resource-group\",\n    vm_name=\"my-vm\",\n)\n\nprint(vm.hardware_profile.vm_size)\nprint(vm.provisioning_state)\n\ninstance_view = client.virtual_machines.instance_view(\n    resource_group_name=\"my-resource-group\",\n    vm_name=\"my-vm\",\n)\n\nfor status in instance_view.statuses or []:\n    print(status.code, status.display_status)\n```\n\n### Start, stop billing, or run a command on a VM\n\n```python\nclient.virtual_machines.begin_start(\n    resource_group_name=\"my-resource-group\",\n    vm_name=\"my-vm\",\n).result()\n\nclient.virtual_machines.begin_deallocate(\n    resource_group_name=\"my-resource-group\",\n    vm_name=\"my-vm\",\n).result()\n```\n\n`begin_power_off()` stops a VM but does not release compute billing. `begin_deallocate()` is the call that releases compute resources.\n\n### Create a managed disk\n\n```python\nfrom azure.mgmt.compute.models import CreationData, Disk\n\ndisk = client.disks.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    disk_name=\"my-managed-disk\",\n    disk=Disk(\n        location=\"eastus\",\n        disk_size_gb=128,\n        sku={\"name\": \"StandardSSD_LRS\"},\n        creation_data=CreationData(create_option=\"Empty\"),\n    ),\n).result()\n\nprint(disk.id)\n```\n\nImportant model rules from the official docs:\n\n- `Disk.location` is required.\n- `CreationData.create_option` is required.\n- `Disk.disk_size_gb` is mandatory when `creation_data.create_option == \"Empty\"`.\n\n### Grant and revoke temporary disk access\n\n```python\nfrom azure.mgmt.compute.models import GrantAccessData\n\naccess = client.disks.begin_grant_access(\n    resource_group_name=\"my-resource-group\",\n    disk_name=\"my-managed-disk\",\n    grant_access_data=GrantAccessData(\n        access=\"Read\",\n        duration_in_seconds=3600,\n    ),\n).result()\n\nprint(access.access_sas)\n\nclient.disks.begin_revoke_access(\n    resource_group_name=\"my-resource-group\",\n    disk_name=\"my-managed-disk\",\n).result()\n```\n\n`GrantAccessData` requires both `access` and `duration_in_seconds`.\n\n### Discover available compute SKUs\n\n```python\nfor sku in client.resource_skus.list(filter=\"location eq 'eastus'\"):\n    if sku.resource_type == \"virtualMachines\":\n        print(sku.name, sku.locations)\n```\n\n`resource_skus.list()` supports only a location filter.\n\n## Creating Or Updating Virtual Machines\n\nVM creation works through `virtual_machines.begin_create_or_update(...)`, but the request shape is larger than many agents expect because the compute resource depends on image, storage, OS, and network data.\n\n```python\nfrom azure.mgmt.compute.models import VirtualMachine\n\nvm = VirtualMachine(\n    location=\"eastus\",\n    hardware_profile={\"vm_size\": \"Standard_D2s_v5\"},\n    storage_profile={\n        \"image_reference\": {\n            \"publisher\": \"Canonical\",\n            \"offer\": \"0001-com-ubuntu-server-jammy\",\n            \"sku\": \"22_04-lts-gen2\",\n            \"version\": \"latest\",\n        }\n    },\n    os_profile={\n        \"computer_name\": \"my-vm\",\n        \"admin_username\": \"azureuser\",\n        \"admin_password\": \"replace-me\",\n    },\n    network_profile={\n        \"network_interfaces\": [\n            {\n                \"id\": \"/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/networkInterfaces/my-nic\",\n                \"primary\": True,\n            }\n        ]\n    },\n)\n\ncreated_vm = client.virtual_machines.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    vm_name=\"my-vm\",\n    parameters=vm,\n).result()\n\nprint(created_vm.id)\n```\n\nThe `VirtualMachine` model requires `location`, and real deployments usually also depend on sibling Azure packages:\n\n- `azure-mgmt-resource` for resource groups\n- `azure-mgmt-network` for VNets, subnets, NICs, and public IPs\n- valid marketplace image references, gallery image IDs, or existing managed disks\n\n## Configuration Notes\n\n- Authentication and subscription targeting are separate. `DefaultAzureCredential` can succeed while the SDK still fails if `subscription_id` is missing or wrong.\n- Use one `ComputeManagementClient` per target subscription and cloud endpoint.\n- Keep region names consistent across related resources; disk, NIC, VM, and image mismatches are a common cause of ARM validation failures.\n- For scripts and simple automation, the sync client is usually enough. Add async only if the rest of the application already depends on an async stack.\n\n## Version-Sensitive Notes For 37.2.0\n\n- PyPI lists `37.2.0` as released on `2026-01-27`.\n- PyPI states the package is tested with Python `3.9+`.\n- `37.2.0` adds `GalleryScriptsOperations` and `GalleryScriptVersionsOperations`.\n- `37.0.0` added `VirtualMachineScaleSetsOperations.begin_scale_out` and several gallery-related operation groups.\n- `36.0.0` is the breaking release where the package stopped shipping older Azure Compute API-version subpackages and now targets only the latest API version. If your code depends on a specific non-latest API version, pin to an earlier package release.\n- Do not copy Track 1 Azure auth samples that use `ServicePrincipalCredentials`; that is not the current pattern for `37.2.0`.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-compute` and forgetting `azure-identity`.\n- Omitting `AZURE_SUBSCRIPTION_ID` and assuming authentication alone is enough.\n- Treating `begin_*` methods as synchronous and skipping `.result()`.\n- Calling `begin_power_off()` when you actually need `begin_deallocate()` to stop compute billing.\n- Trying to create a VM with compute models only; the NIC and network resources usually come from `azure-mgmt-network`.\n- Assuming older service-version namespaces still exist in current releases after the `36.0.0` API-version cleanup.\n- Sending underspecified `Disk` or `VirtualMachine` payloads because Python model constructors are permissive while the ARM service is not.\n\n## Recommended Workflow For Coding Agents\n\n1. Install `azure-mgmt-compute` and `azure-identity`, then confirm the project uses `DefaultAzureCredential` or another `TokenCredential`.\n2. Start at `ComputeManagementClient`, then narrow to the exact operation group you need: `virtual_machines`, `disks`, `snapshots`, `virtual_machine_scale_sets`, or `resource_skus`.\n3. Before writing a create or update payload, check the exact model constructor for required fields in `azure.mgmt.compute.models`.\n4. If the task creates or updates VMs, inspect whether the project already manages network resources elsewhere; `azure-mgmt-compute` is usually only one part of the workflow.\n5. If you need older API-version namespaces, do not improvise. Pin an earlier package version and fetch docs that match that older release.\n\n## Official Sources Used\n\n- Microsoft package API root: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/`\n- Microsoft `ComputeManagementClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.computemanagementclient?view=azure-python`\n- Microsoft `VirtualMachinesOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.operations.virtualmachinesoperations?view=azure-python`\n- Microsoft `DisksOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.operations.disksoperations?view=azure-python`\n- Microsoft `ResourceSkusOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.operations.resourceskusoperations?view=azure-python`\n- Microsoft `VirtualMachine` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.models.virtualmachine?view=azure-python`\n- Microsoft `Disk` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.models.disk?view=azure-python`\n- Microsoft `CreationData` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.models.creationdata?view=azure-python`\n- Microsoft `GrantAccessData` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-compute/azure.mgmt.compute.models.grantaccessdata?view=azure-python`\n- Microsoft `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python`\n- PyPI project page and release metadata: `https://pypi.org/project/azure-mgmt-compute/`\n- PyPI JSON metadata: `https://pypi.org/pypi/azure-mgmt-compute/json`\n"
  },
  {
    "path": "content/azure/docs/mgmt-containerinstance/python/DOC.md",
    "content": "---\nname: mgmt-containerinstance\ndescription: \"Azure Container Instances management SDK for Python for creating, inspecting, starting, stopping, and deleting container groups through Azure Resource Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,container-instances,aci,arm,containers,python\"\n---\n\n# Azure Container Instances Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-containerinstance` for Azure Container Instances management-plane work through Azure Resource Manager. Authenticate it with a `TokenCredential` such as `DefaultAzureCredential`, and treat `begin_*` methods as long-running ARM operations that need `.result()`.\n\nThis package manages container groups, logs, exec sessions, and regional capability lookups. It does not build images, push images, or create your resource group for you.\n\n## Install\n\nPin the package version your project expects and install Azure Identity alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-containerinstance==10.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-containerinstance==10.1.0\" azure-identity\npoetry add \"azure-mgmt-containerinstance==10.1.0\" azure-identity\n```\n\nPyPI lists `10.1.0` as the stable release for this package. PyPI also shows a newer `10.2.0b1` pre-release, so do not assume preview fields or behavior are present in a project pinned to `10.1.0`.\nPyPI also states the package is tested with Python `3.7+`.\n\n## Authentication And Setup\n\nThe standard setup is `DefaultAzureCredential()` plus `AZURE_SUBSCRIPTION_ID`.\n\nEnvironment variables for service-principal auth:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n\nexport AZURE_RESOURCE_GROUP=\"example-rg\"\nexport AZURE_LOCATION=\"eastus\"\nexport AZURE_CONTAINER_GROUP=\"hello-aci\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.containerinstance import ContainerInstanceManagementClient\n\ncredential = DefaultAzureCredential()\nclient = ContainerInstanceManagementClient(\n    credential=credential,\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n`ContainerInstanceManagementClient` also accepts `base_url=`. Use that only when you intentionally target a non-public ARM endpoint. The official client docs warn that overriding `api_version` from the default `2023-05-01` may result in unsupported behavior.\n\n## Create A Container Group\n\n`ContainerGroup` requires `containers` and `os_type`. Each `Container` requires `name`, `image`, and `resources`. `ResourceRequirements` requires `requests`, and `ResourceRequests` requires both `memory_in_gb` and `cpu`.\n\nThis example creates a public Linux container group with one container and a DNS label:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.containerinstance import ContainerInstanceManagementClient\nfrom azure.mgmt.containerinstance.models import (\n    Container,\n    ContainerGroup,\n    ContainerGroupRestartPolicy,\n    ContainerPort,\n    EnvironmentVariable,\n    IpAddress,\n    OperatingSystemTypes,\n    Port,\n    ResourceRequests,\n    ResourceRequirements,\n)\n\nclient = ContainerInstanceManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ncontainer_group = ContainerGroup(\n    location=os.environ[\"AZURE_LOCATION\"],\n    os_type=OperatingSystemTypes.LINUX,\n    restart_policy=ContainerGroupRestartPolicy.ALWAYS,\n    containers=[\n        Container(\n            name=\"app\",\n            image=\"mcr.microsoft.com/azuredocs/aci-helloworld\",\n            resources=ResourceRequirements(\n                requests=ResourceRequests(cpu=1.0, memory_in_gb=1.5)\n            ),\n            ports=[ContainerPort(port=80)],\n            environment_variables=[\n                EnvironmentVariable(name=\"ENVIRONMENT\", value=\"dev\"),\n            ],\n        )\n    ],\n    ip_address=IpAddress(\n        type=\"Public\",\n        dns_name_label=f\"{os.environ['AZURE_CONTAINER_GROUP']}-demo\",\n        ports=[Port(port=80, protocol=\"TCP\")],\n    ),\n    tags={\"env\": \"dev\"},\n)\n\ncreated = client.container_groups.begin_create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n    container_group=container_group,\n).result()\n\nprint(created.id)\nif created.ip_address:\n    print(created.ip_address.ip)\n    print(created.ip_address.fqdn)\n```\n\nPractical notes:\n\n- The resource group must already exist before `begin_create_or_update(...)`.\n- `IpAddress` requires both `ports` and `type`.\n- Use `EnvironmentVariable(secure_value=...)` for secrets instead of plain `value`.\n\n## List And Inspect Container Groups\n\nList container groups in one resource group:\n\n```python\nfor group in client.container_groups.list_by_resource_group(\n    os.environ[\"AZURE_RESOURCE_GROUP\"]\n):\n    print(group.name, group.location, group.provisioning_state)\n```\n\nGet one container group:\n\n```python\ngroup = client.container_groups.get(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n)\n\nprint(group.name)\nprint(group.provisioning_state)\nprint(group.restart_policy)\nprint(group.os_type)\n```\n\n`get_outbound_network_dependencies_endpoints(...)` exists on the operation group, but the official docs explicitly say it always returns an empty list for container groups.\n\n## Logs, Attach, And Exec\n\nUse `client.containers`, not `client.container_groups`, for container-level runtime interactions.\n\nGet recent logs:\n\n```python\nlogs = client.containers.list_logs(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n    container_name=\"app\",\n    tail=200,\n    timestamps=True,\n)\n```\n\nThe official `list_logs(...)` docs note that:\n\n- `tail` limits the number of lines returned\n- omitting `tail` returns all available logs up to 4 MB\n- `timestamps=True` prefixes each log line with a timestamp\n\nStart an exec session:\n\n```python\nfrom azure.mgmt.containerinstance.models import ContainerExecRequest\n\nexec_response = client.containers.execute_command(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n    container_name=\"app\",\n    container_exec_request=ContainerExecRequest(command=\"/bin/sh\"),\n)\n\nprint(exec_response.web_socket_uri)\nprint(exec_response.password)\n```\n\nImportant: `execute_command(...)` does not return command stdout directly. It returns a `ContainerExecResponse` with `web_socket_uri` and `password` for the websocket session.\n\nAttach to a running container stream:\n\n```python\nattach_response = client.containers.attach(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n    container_name=\"app\",\n)\n\nprint(attach_response.web_socket_uri)\nprint(attach_response.password)\n```\n\n`ContainerAttachResponse.password` must be sent as the `Authorization` header when connecting to the websocket URI.\n\n## Start, Stop, Restart, Delete, And Tag Updates\n\nStart a stopped container group:\n\n```python\nclient.container_groups.begin_start(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n).result()\n```\n\nStop a running container group:\n\n```python\nclient.container_groups.stop(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n)\n```\n\nRestart a running container group:\n\n```python\nclient.container_groups.begin_restart(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n).result()\n```\n\nUpdate tags:\n\n```python\nfrom azure.mgmt.containerinstance.models import Resource\n\nupdated = client.container_groups.update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n    resource=Resource(tags={\"env\": \"prod\", \"owner\": \"platform\"}),\n)\n\nprint(updated.tags)\n```\n\nDelete the container group:\n\n```python\nclient.container_groups.begin_delete(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=os.environ[\"AZURE_CONTAINER_GROUP\"],\n).result()\n```\n\nBehavior that matters:\n\n- `begin_start(...)` allocates compute resources and billing starts.\n- `stop(...)` deallocates compute resources and billing stops.\n- `begin_restart(...)` restarts containers in place and may pull a newer image if the image tag changed upstream.\n- `update(...)` updates tags only, not the full container group definition.\n- `begin_delete(...)` does not delete user-provided external resources such as volumes.\n\n## Private Registry, Private Networking, And Volumes\n\nThe same `ContainerGroup` model handles private registry auth, VNet placement, and shared volumes.\n\nPrivate registry credentials:\n\n```python\nfrom azure.mgmt.containerinstance.models import ImageRegistryCredential\n\nregistry_credential = ImageRegistryCredential(\n    server=os.environ[\"ACR_SERVER\"],\n    username=os.environ[\"ACR_USERNAME\"],\n    password=os.environ[\"ACR_PASSWORD\"],\n)\n```\n\n`ImageRegistryCredential.server` must be the registry host name only, without `http://` or `https://`.\n\nDeploy into a subnet with a private IP:\n\n```python\nfrom azure.mgmt.containerinstance.models import (\n    Container,\n    ContainerGroup,\n    ContainerGroupSubnetId,\n    ContainerPort,\n    ImageRegistryCredential,\n    IpAddress,\n    OperatingSystemTypes,\n    Port,\n    ResourceRequests,\n    ResourceRequirements,\n)\n\nprivate_ip = IpAddress(\n    type=\"Private\",\n    ports=[Port(port=8080, protocol=\"TCP\")],\n)\n\nregistry_credential = ImageRegistryCredential(\n    server=os.environ[\"ACR_SERVER\"],\n    username=os.environ[\"ACR_USERNAME\"],\n    password=os.environ[\"ACR_PASSWORD\"],\n)\n\nsubnet = ContainerGroupSubnetId(id=os.environ[\"ACI_SUBNET_ID\"])\n\nprivate_group = ContainerGroup(\n    location=os.environ[\"AZURE_LOCATION\"],\n    os_type=OperatingSystemTypes.LINUX,\n    containers=[\n        Container(\n            name=\"private-app\",\n            image=f\"{os.environ['ACR_SERVER']}/myrepo/myimage:latest\",\n            resources=ResourceRequirements(\n                requests=ResourceRequests(cpu=1.0, memory_in_gb=1.5)\n            ),\n            ports=[ContainerPort(port=8080)],\n        )\n    ],\n    ip_address=private_ip,\n    subnet_ids=[subnet],\n    image_registry_credentials=[registry_credential],\n)\n\nclient.container_groups.begin_create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    container_group_name=\"private-aci\",\n    container_group=private_group,\n).result()\n```\n\nFor shared storage, `ContainerGroup` accepts `volumes=[...]` and each `Container` can mount them with `volume_mounts=[...]`. `VolumeMount.mount_path` must not contain `:`.\n\n## Check Regional Capacity And Quotas\n\nBefore choosing a region or a larger CPU or memory shape, inspect the location metadata:\n\n```python\nfor capability in client.location.list_capabilities(os.environ[\"AZURE_LOCATION\"]):\n    print(capability)\n\nfor usage in client.location.list_usage(os.environ[\"AZURE_LOCATION\"]):\n    print(usage)\n\nfor image in client.location.list_cached_images(os.environ[\"AZURE_LOCATION\"]):\n    print(image)\n```\n\nThese are paged iterators. Iterate over them instead of assuming an in-memory list.\n\n## Version-Sensitive Notes For 10.1.0\n\n- PyPI marks `10.1.0` as the stable release published on `2023-04-21`.\n- In `10.1.0`, `Container` adds `security_context`.\n- In `10.1.0`, `ContainerGroup` adds `confidential_compute_properties`, `extensions`, and `priority`.\n- Since `9.0.0`, `ContainerGroup` supports `subnet_ids`, and `ImageRegistryCredential` supports `identity` and `identity_url`.\n- Since `8.0.0`, `ContainersOperations.attach(...)` exists and `list_logs(...)` uses the current signature with `tail` and `timestamps`.\n- Do not copy Track 1 Azure auth examples that use `azure.common.credentials` or `ServicePrincipalCredentials`; current releases expect `azure-identity` credentials.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-containerinstance` and forgetting `azure-identity`.\n- Omitting `AZURE_SUBSCRIPTION_ID` and assuming a credential alone is enough.\n- Treating `begin_create_or_update(...)`, `begin_start(...)`, `begin_restart(...)`, or `begin_delete(...)` as synchronous and skipping `.result()`.\n- Assuming `stop(...)` is also a poller. It is a direct call that returns `None`.\n- Expecting `update(...)` to patch the full container group. The official docs say it updates tags only.\n- Sending a registry URL with a scheme in `ImageRegistryCredential.server`.\n- Expecting `execute_command(...)` to return command output instead of websocket connection info.\n- Assuming container group deletion also cleans up Azure Files shares, storage accounts, or other external resources.\n- Overriding `api_version` on the client unless you have a specific compatibility reason and have verified the service behavior.\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.containerinstancemanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.operations.containergroupsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.operations.containersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containergroup?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.container?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.resourcerequirements?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.resourcerequests?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.ipaddress?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.port?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containerport?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.environmentvariable?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.imageregistrycredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containergroupsubnetid?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.volume?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.volumemount?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containerexecrequest?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containerexecresponse?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.containerattachresponse?view=azure-python\n- https://pypi.org/project/azure-mgmt-containerinstance/\n"
  },
  {
    "path": "content/azure/docs/mgmt-containerservice/python/DOC.md",
    "content": "---\nname: mgmt-containerservice\ndescription: \"Azure Kubernetes Service management SDK for Python for managing AKS clusters, node pools, credentials, upgrades, and related ARM resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"40.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,aks,kubernetes,containers,arm,management\"\n---\n\n# Azure Kubernetes Service Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-containerservice` for Azure Resource Manager control-plane operations against AKS, authenticate with a modern `TokenCredential` such as `DefaultAzureCredential`, and treat most mutating calls as long-running `begin_*` operations that need `.result()`. This package manages AKS resources; it does not replace `kubectl`, the Kubernetes Python client, or in-cluster APIs.\n\n## Install\n\nPin the stable package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-containerservice==40.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-containerservice==40.2.0\" azure-identity\npoetry add \"azure-mgmt-containerservice==40.2.0\" azure-identity\n```\n\nIf you need Kubernetes API access after fetching kubeconfig credentials, also install the Kubernetes client separately:\n\n```bash\npython -m pip install kubernetes\n```\n\n## Authentication And Setup\n\nUse one of these credential patterns:\n\n- `DefaultAzureCredential()` for reusable code, CI, managed identity, or workload identity\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor service-principal auth through environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.containerservice import ContainerServiceClient\n\nclient = ContainerServiceClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nCLI-driven local scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.containerservice import ContainerServiceClient\n\nclient = ContainerServiceClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nFor sovereign clouds or custom ARM endpoints, the current `40.x` line also supports `cloud_setting=` on the client constructor. Keep the identity authority host and ARM cloud setting aligned.\n\n## Core Usage\n\nTwo package behaviors matter everywhere:\n\n- Mutating methods usually start with `begin_` and return a long-running-operation poller. Call `.result()` before assuming the ARM change finished.\n- `list*` methods typically return paged iterators. Iterate over them instead of assuming an eager list.\n\n### List AKS clusters in a subscription or resource group\n\n```python\nfor cluster in client.managed_clusters.list():\n    print(cluster.name, cluster.location, cluster.kubernetes_version)\n\nfor cluster in client.managed_clusters.list_by_resource_group(\"example-rg\"):\n    print(cluster.name, cluster.provisioning_state)\n```\n\n### Get a cluster and inspect key properties\n\n```python\ncluster = client.managed_clusters.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n)\n\nprint(cluster.name)\nprint(cluster.kubernetes_version)\nprint(cluster.dns_prefix)\nprint(cluster.node_resource_group)\nprint(cluster.provisioning_state)\n```\n\nUseful fields to inspect before writing follow-up code:\n\n- `kubernetes_version`\n- `agent_pool_profiles`\n- `identity`\n- `network_profile`\n- `auto_upgrade_profile`\n- `aad_profile` or `security_profile` when auth and policy behavior matter\n\n### Fetch kubeconfig credentials\n\nThe official model returns base64-encoded kubeconfig payloads inside `CredentialResults.kubeconfigs`.\n\n```python\nimport base64\n\ncreds = client.managed_clusters.list_cluster_user_credentials(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n)\n\nkubeconfig_b64 = creds.kubeconfigs[0].value\nkubeconfig_yaml = base64.b64decode(kubeconfig_b64).decode(\"utf-8\")\n\nprint(kubeconfig_yaml[:200])\n```\n\nAdmin credentials use a separate call:\n\n```python\nadmin_creds = client.managed_clusters.list_cluster_admin_credentials(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n)\n```\n\nPrefer user credentials unless the task explicitly requires cluster-admin access.\n\n### Check available Kubernetes upgrades\n\n```python\nprofile = client.managed_clusters.get_upgrade_profile(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n)\n\nprint(\"Current:\", profile.control_plane_profile.kubernetes_version)\n\nfor upgrade in profile.control_plane_profile.upgrades or []:\n    print(\"Available:\", upgrade.kubernetes_version, upgrade.is_preview)\n```\n\nUse the upgrade profile before submitting any version change. Do not guess upgrade targets.\n\n### Run a command on the cluster\n\nThe management API exposes `run_command` for AKS command execution.\n\n```python\nresult = client.managed_clusters.run_command(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n    request_payload={\n        \"command\": \"kubectl get nodes -o wide\",\n    },\n)\n\nprint(result.logs)\n```\n\nUse this sparingly. For repeated operational workflows, writing kubeconfig and using `kubectl` directly is usually easier to reason about.\n\n### Create or update a cluster\n\nCluster provisioning is possible through `begin_create_or_update(...)`, but the request body is much larger than agents usually expect because it combines identity, node pools, networking, Linux profile, and AKS feature flags. Treat this as infrastructure code, not a quick one-off API call.\n\n```python\npoller = client.managed_clusters.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-aks\",\n    parameters={\n        \"location\": \"eastus\",\n        \"dns_prefix\": \"example-aks\",\n        \"identity\": {\"type\": \"SystemAssigned\"},\n        \"agent_pool_profiles\": [\n            {\n                \"name\": \"systempool\",\n                \"count\": 1,\n                \"vm_size\": \"Standard_DS2_v2\",\n                \"mode\": \"System\",\n                \"type\": \"VirtualMachineScaleSets\",\n                \"os_type\": \"Linux\",\n            }\n        ],\n        \"linux_profile\": {\n            \"admin_username\": \"azureuser\",\n            \"ssh\": {\n                \"public_keys\": [\n                    {\"key_data\": \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...\"}\n                ]\n            },\n        },\n        \"enable_rbac\": True,\n    },\n)\n\ncluster = poller.result()\nprint(cluster.id)\n```\n\nBefore automating creation, verify the exact payload against current AKS requirements for your region, network plugin, and identity mode. For many teams, Bicep, ARM templates, or Terraform are safer for initial cluster provisioning, with this SDK used later for inspection and targeted updates.\n\n## Configuration Notes\n\n- Authentication and subscription targeting are separate. A credential can succeed while the client still fails if `subscription_id` is missing or wrong.\n- This is an ARM management SDK. After you obtain kubeconfig, Kubernetes API calls belong to `kubectl` or the `kubernetes` Python package, not `azure-mgmt-containerservice`.\n- The package constructor supports cloud and endpoint customization. Use those only when you are targeting a sovereign or custom cloud environment.\n- Cluster mutations are region- and SKU-sensitive. Read the current upgrade profile, node pool details, and network profile before applying partial updates.\n\n## Version-Sensitive Notes For `40.2.0`\n\n- PyPI shows `40.2.0` as the current stable release on `2026-03-12`.\n- PyPI also shows newer prereleases in the `41.0.0b*` line. Pin `40.2.0` if you want stable behavior instead of preview API surface.\n- `40.2.0` adds an `OSSKU` enum member; it is a small update, not a major API-shape change.\n- `40.1.0` added the `managed_namespaces` operation group. Do not assume older `40.0.0` examples include it.\n- `40.0.0` added `cloud_setting` support on the client.\n- `39.0.0` removed older service-version namespaces and now targets only the latest API version shipped by the package. If your code imported versioned subpackages from earlier releases, verify them before copying old examples.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-containerservice` without `azure-identity`\n- Assuming `DefaultAzureCredential()` also chooses the Azure subscription for you\n- Treating `begin_*` calls as synchronous and forgetting `.result()`\n- Using admin credentials when user credentials are enough\n- Forgetting that `CredentialResults.kubeconfigs` contains base64-encoded kubeconfig data\n- Treating this management SDK as a replacement for Kubernetes API clients\n- Copying older AKS examples that depended on package-versioned namespaces removed before `40.x`\n- Creating or updating clusters with underspecified payloads because Python dicts are permissive while ARM validation is not\n- Mixing stable `40.2.0` guidance with preview-only `41.0.0b*` or `view=azure-python-preview` examples\n\n## Recommended Workflow For Coding Agents\n\n1. Confirm you are doing AKS management-plane work, not Kubernetes in-cluster API work.\n2. Pin `azure-mgmt-containerservice==40.2.0` and install `azure-identity`.\n3. Authenticate with `DefaultAzureCredential()` or `AzureCliCredential()` and pass `AZURE_SUBSCRIPTION_ID` explicitly.\n4. Start with `managed_clusters.get()` or `list()` to inspect the existing cluster shape before writing update code.\n5. Use `get_upgrade_profile()` before any Kubernetes version change.\n6. Decode kubeconfig credentials only when you actually need to hand off to `kubectl` or the Kubernetes Python client.\n7. For large provisioning changes, validate the payload against the current Microsoft Learn reference or prefer IaC.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-containerservice/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerservice/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerservice/azure.mgmt.containerservice.containerserviceclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerservice/azure.mgmt.containerservice.operations.managedclustersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerservice/azure.mgmt.containerservice.operations.managednamespacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-containerservice/azure.mgmt.containerservice.models.credentialresults?view=azure-python\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-core/python/DOC.md",
    "content": "---\nname: mgmt-core\ndescription: \"azure-mgmt-core package guide for Python - Azure Resource Manager pipeline, polling, policies, and resource ID helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,arm,management,python,pypi\"\n---\n\n# azure-mgmt-core Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-core` is the shared management-plane foundation used by Azure Resource Manager SDKs for Python.\n\nUse it directly when you need lower-level ARM building blocks:\n\n- `ARMPipelineClient` or `AsyncARMPipelineClient` for raw ARM HTTP pipeline access\n- ARM long-running-operation polling helpers\n- ARM-specific policies such as challenge auth and auxiliary auth\n- resource ID helpers such as `resource_id`, `parse_resource_id`, and `is_valid_resource_id`\n- cloud endpoint helpers such as `get_arm_endpoints`\n\nDo not treat `azure-mgmt-core` as a service client by itself. For actual Azure services, install a service package such as `azure-mgmt-resource`, `azure-mgmt-compute`, or `azure-mgmt-network`, which uses this package underneath.\n\n## Installation\n\nInstall `azure-mgmt-core` directly if you are writing shared ARM helpers or custom management-plane client code:\n\n```bash\npip install azure-mgmt-core==1.6.0\n```\n\nIn most real projects you also need Azure credentials from `azure-identity`:\n\n```bash\npip install azure-identity\n```\n\nIf you are working with a concrete ARM service, install the service package too:\n\n```bash\npip install azure-mgmt-resource\n```\n\nFor new projects, avoid the deprecated umbrella `azure` package. Install the specific SDK packages you actually use.\n\n## Authentication And Setup\n\n`azure-mgmt-core` does not obtain credentials on its own. Pair it with `azure-identity`, most commonly `DefaultAzureCredential`.\n\nTypical service-principal environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nOr authenticate locally with Azure CLI:\n\n```bash\naz login\naz account set --subscription \"$AZURE_SUBSCRIPTION_ID\"\n```\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n```\n\nFor Azure Resource Manager, the public-cloud endpoint is typically `https://management.azure.com` and the default token scope is `https://management.azure.com/.default`.\n\n## Core Usage\n\n### Build And Parse ARM Resource IDs\n\nThis is the safest and most common direct use of `azure-mgmt-core` in shared utility code.\n\n```python\nfrom azure.mgmt.core.tools import is_valid_resource_id, parse_resource_id, resource_id\n\nvm_id = resource_id(\n    subscription=\"00000000-0000-0000-0000-000000000000\",\n    resource_group=\"rg-demo\",\n    namespace=\"Microsoft.Compute\",\n    type=\"virtualMachines\",\n    name=\"vm-01\",\n)\n\nif not is_valid_resource_id(vm_id):\n    raise ValueError(f\"Invalid ARM resource ID: {vm_id}\")\n\nparts = parse_resource_id(vm_id)\n\nprint(vm_id)\nprint(parts[\"resource_group\"])\nprint(parts[\"namespace\"])\nprint(parts[\"type\"])\nprint(parts[\"name\"])\n```\n\nUse these helpers instead of manually concatenating ARM IDs. They are less error-prone and easier to reuse across service clients.\n\n### Override ARM Long-Running Operation Polling\n\nGenerated ARM clients already use management-plane polling, but you can override polling behavior explicitly when you need tighter control.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.core.polling.arm_polling import ARMPolling\nfrom azure.mgmt.resource import ResourceManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = ResourceManagementClient(credential, subscription_id)\n\npoller = client.resource_groups.begin_delete(\n    \"rg-demo\",\n    polling=ARMPolling(timeout=5),\n)\n\npoller.result()\n```\n\nUse this pattern when you need to tune polling intervals or enforce ARM polling behavior on long-running management operations.\n\n### Work With Sovereign Clouds\n\n`azure-mgmt-core` `1.6.0` includes `get_arm_endpoints`, which helps map a cloud setting to the correct ARM endpoint values.\n\nPractical guidance:\n\n- use `get_arm_endpoints` when your code must support Azure Government, Azure China, or other non-public clouds\n- do not hardcode `management.azure.com` if the deployment target is cloud-dependent\n- keep cloud selection in configuration instead of scattering endpoint constants throughout the codebase\n\nIf you are already using higher-level management clients, pass the correct cloud endpoint or authority configuration into the credential and client setup rather than rewriting ARM endpoint logic yourself.\n\n### Use Raw ARM Pipeline Access Sparingly\n\n`ARMPipelineClient` and `AsyncARMPipelineClient` exist for cases where generated clients are missing or you are building shared infrastructure around ARM requests.\n\nPrefer generated service clients whenever possible because they already handle:\n\n- API-version selection\n- model serialization and deserialization\n- pagination\n- ARM long-running operations\n- service-specific request shapes\n\nReach for raw pipeline clients only when you are intentionally building lower-level management tooling.\n\n## Policies And Logging\n\nThe package exposes ARM-specific policies under `azure.mgmt.core.policies`, including challenge authentication, auxiliary authentication, automatic resource-provider registration, and ARM-specific HTTP logging.\n\nTypical patterns:\n\n- pair ARM auth policies with an `azure-identity` credential\n- use `AuxiliaryAuthenticationPolicy` only for scenarios that require auxiliary tokens across tenants\n- enable request logging with `logging_enable=True` only when debugging\n\nBe careful with verbose HTTP logging in production. ARM requests can expose subscription IDs, resource names, request bodies, or sensitive headers if logging is too broad.\n\n## Common Pitfalls\n\n- `azure-mgmt-core` is not a full service SDK. Installing only this package will not give you `ResourceManagementClient`, `ComputeManagementClient`, and similar clients.\n- This package is for Azure management plane, not data-plane SDKs such as Blob, Key Vault secrets, or Service Bus messaging.\n- Do not hand-build ARM resource IDs with string concatenation. Use `resource_id` and validate with `is_valid_resource_id`.\n- Do not hardcode public-cloud endpoints if the code may run in sovereign clouds.\n- Do not assume every Azure package example on the web applies to management-plane code. Data-plane clients use different endpoints, auth scopes, and request shapes.\n- If you use `DefaultAzureCredential`, local development may silently use Azure CLI, Visual Studio Code, or other available identities. Be explicit about the intended credential source when debugging auth failures.\n- Automatic resource-provider registration can be convenient, but it may require permissions your principal does not have. If registration fails, check RBAC before blaming the client code.\n\n## Version-Sensitive Notes For `1.6.0`\n\n- The version used here for this session is `1.6.0`, and the current PyPI page also lists `1.6.0` as the latest release.\n- `get_arm_endpoints` was added in the `1.5.0` line, so it is available in `1.6.0` but not in older installs such as `1.0.0`.\n- `AuxiliaryAuthenticationPolicy` was added in the `1.4.0` line. Older environments may not have it.\n- The `1.6.0` release updated `ARMChallengeAuthenticationPolicy` to adopt the newer `on_challenge` flow used by `azure-core`. If you subclass auth behavior or depend on challenge handling details, retest that code on upgrade.\n- Current official package metadata lists Python `>=3.9`. If you are maintaining older Azure SDK environments, verify interpreter support before pinning to `1.6.0`.\n\n## Official Sources\n\n- Azure management core library package docs: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/?view=azure-python\n- `ARMPipelineClient`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/azure.mgmt.core.armpipelineclient?view=azure-python\n- `AsyncARMPipelineClient`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/azure.mgmt.core.asyncarmpipelineclient?view=azure-python\n- `ARMPolling`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/azure.mgmt.core.polling.arm_polling.armpolling?view=azure-python\n- `azure.mgmt.core.tools`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/azure.mgmt.core.tools?view=azure-python\n- `ARMChallengeAuthenticationPolicy`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-core/azure.mgmt.core.policies.armchallengeauthenticationpolicy?view=azure-python\n- Azure Identity overview: https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n- PyPI package page and release history: https://pypi.org/project/azure-mgmt-core/\n"
  },
  {
    "path": "content/azure/docs/mgmt-cosmosdb/python/DOC.md",
    "content": "---\nname: mgmt-cosmosdb\ndescription: \"azure-mgmt-cosmosdb package guide for Python with ARM auth, Cosmos DB management patterns, and 9.9.0 version notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.9.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,cosmosdb,arm,management,python\"\n---\n\n# azure-mgmt-cosmosdb Python Package Guide\n\nUse `azure-mgmt-cosmosdb` when Python code needs to provision or manage Azure Cosmos DB resources through Azure Resource Manager (ARM).\n\nThis is the management SDK. It is not the data-plane SDK for working with documents inside a container.\n\n## Golden Rule\n\n- Use `azure.mgmt.cosmosdb.CosmosDBManagementClient` for control-plane work such as listing accounts, reading keys, creating SQL databases or containers, and updating account settings.\n- Use `azure-identity` with `DefaultAzureCredential` unless the project already has a stricter Azure credential policy.\n- Use `azure-cosmos` for item CRUD, queries, transactional batch operations, and other data-plane tasks.\n\n## Install\n\n```bash\npython -m pip install \"azure-mgmt-cosmosdb==9.9.0\" azure-identity\n```\n\nIf you are not pinning yet:\n\n```bash\npython -m pip install azure-mgmt-cosmosdb azure-identity\n```\n\n## Authentication And Setup\n\nFor local development, the usual setup is Azure CLI login plus a subscription ID:\n\n```bash\naz login\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nFor CI or service-principal auth, configure the environment variables `DefaultAzureCredential` expects:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nImportant setup rules:\n\n- The credential must have Azure RBAC permission to manage Cosmos DB resources in the target subscription or resource group.\n- `DefaultAzureCredential` tries multiple identities in order, including environment credentials, workload identity, managed identity, Azure CLI, Azure PowerShell, and Azure Developer CLI.\n- Authentication success is not enough by itself. You must still pass the correct Azure subscription ID to `CosmosDBManagementClient`.\n\n## Initialize The Client\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cosmosdb import CosmosDBManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = CosmosDBManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nThe current client constructor also accepts `cloud_setting` for non-public Azure clouds. Leave `api_version` alone unless you have a specific, tested reason to override it. The official docs warn that overriding the default API version can produce unsupported behavior.\n\n## Core Usage\n\n### List Cosmos DB Accounts\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.cosmosdb import CosmosDBManagementClient\n\nclient = CosmosDBManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor account in client.database_accounts.list():\n    print(account.name)\n    print(account.location)\n```\n\n`database_accounts.get(...)` is the usual next step when you already know the resource group and account name and need the full ARM resource payload.\n\n### Read Account Keys\n\n```python\nkeys = client.database_accounts.list_keys(\n    resource_group_name=\"my-resource-group\",\n    account_name=\"my-cosmos-account\",\n)\n\nprint(keys.primary_master_key)\nprint(keys.secondary_master_key)\n```\n\nTreat returned keys like secrets. Do not log them or write them to build output.\n\n### Create Or Update A SQL Database\n\nThe SQL resource operations live under `client.sql_resources`. Create and update methods are long-running ARM operations and return pollers:\n\n```python\nfrom azure.mgmt.cosmosdb import models\n\ndb_params = models.SqlDatabaseCreateUpdateParameters(\n    resource=models.SqlDatabaseResource(id=\"appdb\"),\n)\n\npoller = client.sql_resources.begin_create_update_sql_database(\n    resource_group_name=\"my-resource-group\",\n    account_name=\"my-cosmos-account\",\n    database_name=\"appdb\",\n    create_update_sql_database_parameters=db_params,\n)\n\ndatabase = poller.result()\nprint(database.name)\n```\n\n### Create Or Update A SQL Container\n\n```python\nfrom azure.mgmt.cosmosdb import models\n\ncontainer_params = models.SqlContainerCreateUpdateParameters(\n    resource=models.SqlContainerResource(\n        id=\"items\",\n        partition_key=models.ContainerPartitionKey(\n            paths=[\"/tenantId\"],\n            kind=\"Hash\",\n        ),\n    ),\n)\n\npoller = client.sql_resources.begin_create_update_sql_container(\n    resource_group_name=\"my-resource-group\",\n    account_name=\"my-cosmos-account\",\n    database_name=\"appdb\",\n    container_name=\"items\",\n    create_update_sql_container_parameters=container_params,\n)\n\ncontainer = poller.result()\nprint(container.name)\n```\n\n### List SQL Databases And Containers\n\n```python\nfor database in client.sql_resources.list_sql_databases(\n    resource_group_name=\"my-resource-group\",\n    account_name=\"my-cosmos-account\",\n):\n    print(database.name)\n\nfor container in client.sql_resources.list_sql_containers(\n    resource_group_name=\"my-resource-group\",\n    account_name=\"my-cosmos-account\",\n    database_name=\"appdb\",\n):\n    print(container.name)\n```\n\n### Other Useful Management Operations\n\nThe current SDK surface also includes:\n\n- `database_accounts.begin_create_or_update(...)` for provisioning an account\n- `sql_resources.begin_migrate_sql_database_to_autoscale(...)` and `begin_migrate_sql_database_to_manual_throughput(...)` for throughput mode changes\n- SQL role definition and role assignment operations under `sql_resources` when you need Cosmos DB SQL API RBAC management\n\n## Operation Groups To Know\n\nThe client exposes multiple operation groups. The common ones for day-to-day automation are:\n\n- `database_accounts` for account lifecycle, keys, connection strings, failover, and account metadata\n- `sql_resources` for SQL databases, containers, stored procedures, triggers, user-defined functions, throughput, and SQL role assignments\n- `mongo_db_resources`, `cassandra_resources`, `gremlin_resources`, and `table_resources` for non-SQL Cosmos DB APIs\n\nPick the operation group that matches the API type of the target Cosmos DB account.\n\n## Common Pitfalls\n\n- `azure-mgmt-cosmosdb` does not query or mutate documents inside a container. Use `azure-cosmos` for that.\n- The install name and import path differ. Install `azure-mgmt-cosmosdb`, then import `azure.mgmt.cosmosdb`.\n- Most create, update, delete, and migration methods are long-running operations. Call `.result()` before assuming the resource is ready.\n- `list_keys` and similar calls need Azure resource identifiers such as resource group and account name, not a Cosmos DB endpoint URL.\n- If you hard-code the wrong operation group, you will miss the methods you need. SQL API management lives under `sql_resources`, not `database_accounts`.\n- For local development, `DefaultAzureCredential` may silently use a cached Azure CLI or IDE login. If the wrong tenant or subscription is active, you will get confusing authorization failures.\n- Avoid overriding `api_version` unless you are intentionally targeting a specific ARM API version and have tested it against the account features you use.\n\n## Version-Sensitive Notes\n\n- Frontmatter tracks the version used here `9.9.0`, which matched the latest stable PyPI release on 2026-03-12.\n- PyPI release history also lists `10.0.0b5` as a prerelease. Do not install with `--pre` unless the project explicitly wants preview features or preview API changes.\n- The `9.9.0` release notes say `CosmosDBManagementClient` added a `cloud_setting` constructor parameter and new `fleet`, `fleetspace`, and `fleetspace_account` operation groups.\n- PyPI and the Azure SDK repo both state that current supported Python versions for this package line start at `3.9`.\n\n## Official Sources Used\n\n- Microsoft Learn package reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-cosmosdb/?view=azure-python`\n- Microsoft Learn `CosmosDBManagementClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-cosmosdb/azure.mgmt.cosmosdb.cosmosdbmanagementclient?view=azure-python`\n- Microsoft Learn `DatabaseAccountsOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-cosmosdb/azure.mgmt.cosmosdb.operations.databaseaccountsoperations?view=azure-python`\n- Microsoft Learn `SqlResourcesOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-cosmosdb/azure.mgmt.cosmosdb.operations.sqlresourcesoperations?view=azure-python`\n- Microsoft Learn `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python`\n- PyPI package page and release history: `https://pypi.org/project/azure-mgmt-cosmosdb/`\n- Azure SDK for Python repository: `https://github.com/Azure/azure-sdk-for-python`\n"
  },
  {
    "path": "content/azure/docs/mgmt-datafactory/python/DOC.md",
    "content": "---\nname: mgmt-datafactory\ndescription: \"Azure Data Factory management-plane SDK for Python for factories, linked services, datasets, pipelines, pipeline runs, and activity monitoring\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,data-factory,arm,management,pipelines,etl\"\n---\n\n# Azure Data Factory Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-datafactory` for Azure Resource Manager control-plane work: creating factories, defining linked services and datasets, publishing pipelines, starting pipeline runs, and reading run status. Do not use it for data-plane access to Blob Storage, SQL, or other services. Pair it with `azure-identity` for authentication.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-datafactory==9.3.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-datafactory==9.3.0\" azure-identity\npoetry add \"azure-mgmt-datafactory==9.3.0\" azure-identity\n```\n\nPyPI lists `9.3.0` as requiring Python `>=3.9`.\n\nEnvironment you usually need:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"DefaultEndpointsProtocol=https;AccountName=<account>;AccountKey=<key>;EndpointSuffix=core.windows.net\"\n```\n\nFor a service principal, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, the simplest path is usually:\n\n```bash\naz login\n```\n\n## Authentication And Client Setup\n\nRecommended credential patterns:\n\n- `DefaultAzureCredential()` for app code that should work locally, in CI, or in Azure-hosted environments\n- `AzureCliCredential()` for local scripts after `az login`\n- `ClientSecretCredential()` only when you explicitly want a service principal secret flow\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.datafactory import DataFactoryManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = DataFactoryManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal script variant:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.datafactory import DataFactoryManagementClient\n\nclient = DataFactoryManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe current Learn client reference documents these high-value operation groups:\n\n- `factories`\n- `linked_services`\n- `datasets`\n- `pipelines`\n- `pipeline_runs`\n- `activity_runs`\n- `integration_runtimes`\n\n## Create Or Update A Factory\n\nFactory creation is an ARM management call on `client.factories`:\n\n```python\nfrom azure.mgmt.datafactory.models import Factory\n\nresource_group_name = \"example-rg\"\nfactory_name = \"example-adf-factory\"\nlocation = \"eastus\"\n\nfactory = client.factories.create_or_update(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    factory=Factory(location=location),\n)\n\nprint(factory.id)\nprint(factory.provisioning_state)\n```\n\nRead the factory back with `get()` when you need the current provisioning state or identity settings:\n\n```python\nfactory = client.factories.get(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n)\n\nprint(factory.location)\nprint(factory.provisioning_state)\n```\n\n## Define A Linked Service, Datasets, And A Copy Pipeline\n\nThe official quickstart builds a minimal Blob Storage copy pipeline. This is the smallest practical end-to-end authoring example to keep around.\n\n```python\nimport os\n\nfrom azure.mgmt.datafactory.models import (\n    AzureBlobDataset,\n    AzureStorageLinkedService,\n    BlobSink,\n    BlobSource,\n    CopyActivity,\n    DatasetReference,\n    DatasetResource,\n    LinkedServiceReference,\n    LinkedServiceResource,\n    PipelineResource,\n    SecureString,\n)\n\nresource_group_name = \"example-rg\"\nfactory_name = \"example-adf-factory\"\nstorage_connection_string = os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"]\n\nlinked_service_name = \"AzureStorageLinkedService\"\ninput_dataset_name = \"InputDataset\"\noutput_dataset_name = \"OutputDataset\"\npipeline_name = \"BlobCopyPipeline\"\nsource_blob_path = \"input-container/incoming\"\nsource_file_name = \"data.txt\"\nsink_blob_path = \"output-container/copied\"\n\nclient.linked_services.create_or_update(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    linked_service_name=linked_service_name,\n    linked_service=LinkedServiceResource(\n        properties=AzureStorageLinkedService(\n            connection_string=SecureString(value=storage_connection_string),\n        )\n    ),\n)\n\nclient.datasets.create_or_update(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    dataset_name=input_dataset_name,\n    dataset=DatasetResource(\n        properties=AzureBlobDataset(\n            linked_service_name=LinkedServiceReference(\n                reference_name=linked_service_name,\n            ),\n            folder_path=source_blob_path,\n            file_name=source_file_name,\n        )\n    ),\n)\n\nclient.datasets.create_or_update(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    dataset_name=output_dataset_name,\n    dataset=DatasetResource(\n        properties=AzureBlobDataset(\n            linked_service_name=LinkedServiceReference(\n                reference_name=linked_service_name,\n            ),\n            folder_path=sink_blob_path,\n        )\n    ),\n)\n\ncopy_activity = CopyActivity(\n    name=\"CopyFromBlobToBlob\",\n    inputs=[DatasetReference(reference_name=input_dataset_name)],\n    outputs=[DatasetReference(reference_name=output_dataset_name)],\n    source=BlobSource(),\n    sink=BlobSink(),\n)\n\nclient.pipelines.create_or_update(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    pipeline_name=pipeline_name,\n    pipeline=PipelineResource(\n        activities=[copy_activity],\n    ),\n)\n```\n\nProduction note: the example uses a storage connection string because that is what the official quickstart demonstrates. Keep that secret out of source control and prefer a stronger secret-management pattern before shipping real workloads.\n\n## Start A Pipeline Run And Monitor It\n\nStart the pipeline with `client.pipelines.create_run(...)`, then poll `client.pipeline_runs.get(...)` until the status is terminal:\n\n```python\nimport time\n\nrun = client.pipelines.create_run(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    pipeline_name=pipeline_name,\n)\n\nwhile True:\n    pipeline_run = client.pipeline_runs.get(\n        resource_group_name=resource_group_name,\n        factory_name=factory_name,\n        run_id=run.run_id,\n    )\n    print(pipeline_run.status)\n\n    if pipeline_run.status not in {\"Queued\", \"InProgress\"}:\n        break\n\n    time.sleep(15)\n```\n\nTo inspect individual activity results, query activity runs for a time window that covers the pipeline execution:\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom azure.mgmt.datafactory.models import RunFilterParameters\n\nactivity_runs = client.activity_runs.query_by_pipeline_run(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    run_id=run.run_id,\n    filter_parameters=RunFilterParameters(\n        last_updated_after=datetime.now(timezone.utc) - timedelta(hours=1),\n        last_updated_before=datetime.now(timezone.utc) + timedelta(hours=1),\n    ),\n)\n\nfor activity_run in activity_runs.value:\n    print(activity_run.activity_name, activity_run.status)\n```\n\nIf you need to stop a run:\n\n```python\nclient.pipeline_runs.cancel(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    run_id=run.run_id,\n    is_recursive=True,\n)\n```\n\n## Integration Runtime Operations\n\nFor an existing `ManagedReserved` integration runtime, the SDK exposes lifecycle and monitoring calls on `client.integration_runtimes`:\n\n```python\npoller = client.integration_runtimes.begin_start(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    integration_runtime_name=\"AutoResolveIntegrationRuntime\",\n)\npoller.result()\n\nmonitoring = client.integration_runtimes.get_monitoring_data(\n    resource_group_name=resource_group_name,\n    factory_name=factory_name,\n    integration_runtime_name=\"AutoResolveIntegrationRuntime\",\n)\n\nprint(monitoring.name)\n```\n\nUse the `begin_*` form when the operation returns a poller and wait on `.result()` before assuming the runtime state changed.\n\n## Configuration Notes\n\n- `subscription_id` is required. `DataFactoryManagementClient` does not infer it from the credential.\n- The Learn client reference documents a default `api_version` of `2018-06-01`. The constructor allows overriding it, but the docs warn that doing so may result in unsupported behavior.\n- Authentication success is not authorization success. The principal still needs RBAC permission to manage Data Factory resources in the target subscription or resource group.\n- `create_or_update()` upserts ARM resources. If you need concurrency protection when editing existing artifacts, use the `if_match` or `if_none_match` parameters documented on the operation methods.\n- The copy-pipeline example above defines metadata in Data Factory. It does not create storage containers or upload files for you.\n\n## Version-Sensitive Notes\n\n### `9.3.0`\n\nPyPI release history for `9.3.0` calls out a new `cloud_setting` constructor argument on `DataFactoryManagementClient`. If you target Azure Government or another sovereign cloud, verify your cloud configuration against the installed `9.3.0` package instead of copying older public-cloud-only examples.\n\n### Older generated samples\n\nOlder samples often use `ClientSecretCredential` directly and hard-code secrets or connection strings in the script. The current SDK still supports that pattern, but it is better to move credentials and linked-service secrets into environment variables or a secret-management system before using the code in real deployments.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-datafactory` and forgetting `azure-identity`\n- Treating this package as a data-plane SDK for Blob Storage, SQL, or other sources and sinks\n- Omitting `AZURE_SUBSCRIPTION_ID`; credential resolution and client construction are separate concerns\n- Hard-coding linked-service secrets in Python source\n- Querying activity runs without a time window that actually includes the pipeline execution\n- Assuming every management operation is immediate; integration runtime start and stop flows return pollers\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-datafactory/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datafactory/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datafactory/azure.mgmt.datafactory.datafactorymanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/azure/data-factory/quickstart-create-data-factory-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-datalake-analytics/python/DOC.md",
    "content": "---\nname: mgmt-datalake-analytics\ndescription: \"Azure Data Lake Analytics management SDK for Python for legacy account, storage, compute policy, firewall, and job-management code\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,datalake,analytics,management,legacy,python\"\n---\n\n# Azure Data Lake Analytics Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-datalake-analytics` only for legacy Azure Data Lake Analytics automation and code maintenance. Microsoft says in its official retirement FAQ that Azure Data Lake Analytics retired on February 29, 2024 and is no longer available as a live service, so do not choose this package for new analytics work. For new systems, use current Azure analytics services instead of building fresh code on ADLA.\n\nWhen you do need this package, install `azure-identity` with it and authenticate explicitly. The current Python reference still documents the account-management client and its operation groups even though the service itself is retired.\n\n## Install\n\nPin the version your project already expects:\n\n```bash\npython -m pip install \"azure-mgmt-datalake-analytics==0.6.0\" azure-identity\n```\n\nPractical install notes from PyPI:\n\n- `0.6.0` is the latest stable release on PyPI; `1.0.0b1` and `1.0.0b2` are prereleases.\n- The PyPI project description says `0.6.0` was tested with Python 2.7, 3.4, 3.5, and 3.6.\n- If your environment still has the old `azure<1.0` metapackage installed, uninstall it before troubleshooting imports.\n\n## Package Surface\n\nThe official overview page describes this package as the management API for:\n\n- Data Lake Analytics accounts\n- jobs\n- policies\n- catalogs\n\nThe current Learn reference pages are easiest to use for the `azure.mgmt.datalake.analytics.account` client, which exposes these operation groups:\n\n- `accounts`\n- `data_lake_store_accounts`\n- `storage_accounts`\n- `compute_policies`\n- `firewall_rules`\n- `operations`\n- `locations`\n\n## Authentication And Client Setup\n\nFor reusable code, use `DefaultAzureCredential`. For local scripts after `az login`, `AzureCliCredential` is simpler.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.datalake.analytics.account import DataLakeAnalyticsAccountManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nwith DataLakeAnalyticsAccountManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n) as client:\n    print(client)\n```\n\nLocal CLI-driven script:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.datalake.analytics.account import DataLakeAnalyticsAccountManagementClient\n\nclient = DataLakeAnalyticsAccountManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nImportant client detail: the current class reference documents a default `api_version` of `2019-11-01-preview` and warns that overriding it may lead to unsupported behavior.\n\n## Common Workflows\n\nBecause the service is retired, the safest remaining use cases are inventory, migration analysis, and legacy-code reading.\n\n### List accounts in a subscription\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.datalake.analytics.account import DataLakeAnalyticsAccountManagementClient\n\nclient = DataLakeAnalyticsAccountManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor account in client.accounts.list():\n    print(account.name, account.location)\n```\n\n### Get one account and inspect its linked default store\n\n```python\nresource_group_name = \"example-rg\"\naccount_name = \"example-adla\"\n\naccount = client.accounts.get(resource_group_name, account_name)\n\nprint(account.id)\nprint(account.location)\nprint(account.endpoint)\nprint(account.default_data_lake_store_account)\n```\n\n### Inspect subscription capability for a region\n\nUse this when reading old provisioning code that tuned job-count or parallelism settings:\n\n```python\ncapability = client.locations.get_capability(\"eastus2\")\n\nprint(capability.max_job_count)\nprint(capability.max_degree_of_parallelism)\n```\n\n### List linked Data Lake Store accounts\n\n```python\nresource_group_name = \"example-rg\"\naccount_name = \"example-adla\"\n\nfor store in client.data_lake_store_accounts.list_by_account(\n    resource_group_name,\n    account_name,\n):\n    print(store.name, store.suffix)\n```\n\n### List linked Azure Storage accounts and containers\n\n```python\nresource_group_name = \"example-rg\"\naccount_name = \"example-adla\"\nstorage_account_name = \"examplestorage\"\n\nfor storage_account in client.storage_accounts.list_by_account(\n    resource_group_name,\n    account_name,\n):\n    print(storage_account.name, storage_account.suffix)\n\nfor container in client.storage_accounts.list_storage_containers(\n    resource_group_name,\n    account_name,\n    storage_account_name,\n):\n    print(container.name)\n```\n\nThe same operation group also exposes:\n\n- `get_storage_container(...)`\n- `list_sas_tokens(...)`\n- `add(...)`\n- `update(...)`\n- `delete(...)`\n\n### List compute policies and firewall rules\n\n```python\nresource_group_name = \"example-rg\"\naccount_name = \"example-adla\"\n\nfor policy in client.compute_policies.list_by_account(\n    resource_group_name,\n    account_name,\n):\n    print(\n        policy.name,\n        policy.object_type,\n        policy.max_degree_of_parallelism_per_job,\n        policy.min_priority_per_job,\n    )\n\nfor rule in client.firewall_rules.list_by_account(\n    resource_group_name,\n    account_name,\n):\n    print(rule.name, rule.start_ip_address, rule.end_ip_address)\n```\n\n## Legacy Mutation Shapes\n\nThese methods still exist in the SDK reference, but because Azure Data Lake Analytics retired on February 29, 2024, treat them as legacy code-maintenance surfaces, not live provisioning guidance.\n\n### Add a linked Azure Storage account\n\nThe current model reference documents `AddStorageAccountParameters(access_key, suffix='azuredatalakestore.net')`:\n\n```python\nimport os\n\nfrom azure.mgmt.datalake.analytics.account.models import AddStorageAccountParameters\n\nclient.storage_accounts.add(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-adla\",\n    storage_account_name=\"examplestorage\",\n    parameters=AddStorageAccountParameters(\n        access_key=os.environ[\"AZURE_STORAGE_ACCOUNT_KEY\"],\n        suffix=\"azuredatalakestore.net\",\n    ),\n)\n```\n\n### Current create/update payload shape for accounts, compute policies, and firewall rules\n\nThe REST API examples show these field names for the management payloads:\n\n- account create: `location`, `tags`, `properties.defaultDataLakeStoreAccount`, `properties.dataLakeStoreAccounts`, `properties.storageAccounts`, `properties.computePolicies`, `properties.firewallRules`\n- compute policy create/update: `properties.objectId`, `properties.objectType`, `properties.maxDegreeOfParallelismPerJob`, `properties.minPriorityPerJob`\n- firewall rule create/update: `properties.startIpAddress`, `properties.endIpAddress`\n\nIf you are reading or migrating older code, those are the shapes the SDK models map to.\n\n## Legacy Job Management Pattern\n\nThe official package overview still shows a job-management client:\n\n```python\nimport uuid\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.datalake.analytics.job import DataLakeAnalyticsJobManagementClient\nfrom azure.mgmt.datalake.analytics.job.models import JobInformation, USqlJobProperties\n\njob_id = uuid.uuid4()\nscript = \"PRINT 'hello';\"\n\njob_client = DataLakeAnalyticsJobManagementClient(\n    DefaultAzureCredential(),\n    \"azuredatalakeanalytics.net\",\n)\n\njob_result = job_client.job.create(\n    \"example-adla\",\n    job_id,\n    JobInformation(\n        name=\"Sample Job\",\n        type=\"USql\",\n        properties=USqlJobProperties(script=script),\n    ),\n)\n```\n\nKeep this in the doc only as a legacy reference. The service retirement means new job submission code should not be your default path.\n\n## Important Pitfalls\n\n- This package is for Azure Data Lake Analytics management-plane work, not modern Azure analytics development.\n- The official overview page still shows older examples such as `client.account.create(...)`, but the current account client reference exposes `client.accounts.begin_create(...)`, `client.accounts.get(...)`, and `client.accounts.list(...)`.\n- The package is old. PyPI says `0.6.0` was tested against much older Python versions, so compatibility with modern runtimes is not something you should assume.\n- `subscription_id` is always required for the current account-management client.\n- The current account-management client documents long-running account mutations through `begin_create`, `begin_update`, and `begin_delete`, so legacy code may need `.result()` or equivalent poller handling.\n- Many official examples predate the service retirement. Read them as API-shape references, not as proof that provisioning or job submission still works in a current Azure tenant.\n\n## Official Sources\n\n- https://pypi.org/project/azure-mgmt-datalake-analytics/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/data-lake-analytics?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.datalakeanalyticsaccountmanagementclient?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.accountsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.storageaccountsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.datalakestoreaccountsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.computepoliciesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.firewallrulesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-analytics/azure.mgmt.datalake.analytics.account.operations.locationsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/rest/api/datalakeanalytics/accounts/create?view=rest-datalakeanalytics-2016-11-01\n- https://learn.microsoft.com/en-us/rest/api/datalakeanalytics/compute-policies/create-or-update?view=rest-datalakeanalytics-2016-11-01\n- https://learn.microsoft.com/en-us/answers/questions/776944/azure-data-lake-analytics-retirement-frequently-as\n"
  },
  {
    "path": "content/azure/docs/mgmt-datalake-store/python/DOC.md",
    "content": "---\nname: mgmt-datalake-store\ndescription: \"Azure Data Lake Storage Gen1 management SDK for Python for account lifecycle, account inspection, firewall rules, and location capability checks\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,adls,gen1,management,python,networking,legacy\"\n---\n\n# azure-mgmt-datalake-store Python Package Guide\n\n## Golden Rule\n\nUse `azure-mgmt-datalake-store` only to manage **Azure Data Lake Storage Gen1** accounts. This is a management-plane package for account metadata, firewall rules, virtual network rules, trusted identity providers, and location-level capability and usage checks. It is not the file I/O SDK.\n\nAzure Data Lake Storage Gen1 was retired on **February 29, 2024**, and Microsoft now says you cannot create new Gen1 accounts unless you already have one. For new storage work, use **Azure Data Lake Storage Gen2** and the `azure-storage-file-datalake` package instead.\n\n## Install\n\nPin the package if you are maintaining an older codebase that still targets the stable `0.5.0` line:\n\n```bash\npython -m pip install \"azure-mgmt-datalake-store==0.5.0\" azure-common\n```\n\nIf you are using a virtual environment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"azure-mgmt-datalake-store==0.5.0\" azure-common\n```\n\nThe official Azure management sample for this package used these environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\n## Authentication And Client Setup\n\nThe stable `0.5.0` package line comes from the older Azure management SDK generation. In practice, the safe default is service-principal auth via `azure-common`:\n\n```python\nimport os\n\nfrom azure.common.credentials import ServicePrincipalCredentials\nfrom azure.mgmt.datalake.store import DataLakeStoreAccountManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\ncredentials = ServicePrincipalCredentials(\n    client_id=os.environ[\"AZURE_CLIENT_ID\"],\n    secret=os.environ[\"AZURE_CLIENT_SECRET\"],\n    tenant=os.environ[\"AZURE_TENANT_ID\"],\n)\n\nclient = DataLakeStoreAccountManagementClient(credentials, subscription_id)\n```\n\nKeep the subscription ID separate from the credentials. The management client needs both.\n\n## Core Usage\n\nThe client exposes these main operation groups:\n\n- `accounts`\n- `firewall_rules`\n- `virtual_network_rules`\n- `trusted_id_providers`\n- `locations`\n\n### List And Inspect Existing Accounts\n\n```python\nimport os\n\nfrom azure.common.credentials import ServicePrincipalCredentials\nfrom azure.mgmt.datalake.store import DataLakeStoreAccountManagementClient\n\ncredentials = ServicePrincipalCredentials(\n    client_id=os.environ[\"AZURE_CLIENT_ID\"],\n    secret=os.environ[\"AZURE_CLIENT_SECRET\"],\n    tenant=os.environ[\"AZURE_TENANT_ID\"],\n)\n\nclient = DataLakeStoreAccountManagementClient(\n    credentials,\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor account in client.accounts.list():\n    print(account.name, account.location)\n\naccount = client.accounts.get(\"example-rg\", \"existing-adlsg1\")\nprint(account.name)\nprint(account.location)\nprint(account.type)\n```\n\nUse this when you are inventorying existing Gen1 accounts before cleanup or migration.\n\n### Check Regional Capability And Current Usage\n\n`locations.get_capability()` and `locations.get_usage()` are useful when you need to understand what the subscription can still do in a region:\n\n```python\ncapability = client.locations.get_capability(\"eastus2\")\nprint(capability)\n\nfor usage in client.locations.get_usage(\"eastus2\"):\n    print(usage)\n```\n\nThe location string must be the Azure region name without whitespace, such as `eastus2`.\n\n### Create Or Update An Existing Account Definition\n\nCurrent Microsoft Learn reference pages show `begin_create()` and `begin_update()` for this package family. If your installed `0.5.0` build exposes older `create()` or `update()` methods instead, use the older name with the same model object.\n\n```python\nfrom azure.mgmt.datalake.store.models import CreateDataLakeStoreAccountParameters\n\ncreate_parameters = CreateDataLakeStoreAccountParameters(\n    location=\"eastus2\",\n    tags={\"env\": \"legacy\"},\n)\n\ncreate_call = getattr(client.accounts, \"begin_create\", None) or client.accounts.create\nresult = create_call(\"example-rg\", \"existing-adlsg1\", create_parameters)\n\nif hasattr(result, \"result\"):\n    account = result.result()\nelse:\n    account = result\n\nprint(account.name)\n```\n\nMinimal update example:\n\n```python\nfrom azure.mgmt.datalake.store.models import UpdateDataLakeStoreAccountParameters\n\nupdate_parameters = UpdateDataLakeStoreAccountParameters(\n    tags={\"env\": \"migration\", \"owner\": \"platform\"},\n)\n\nupdate_call = getattr(client.accounts, \"begin_update\", None) or client.accounts.update\nresult = update_call(\"example-rg\", \"existing-adlsg1\", update_parameters)\n\nif hasattr(result, \"result\"):\n    account = result.result()\nelse:\n    account = result\n\nprint(account.tags)\n```\n\n### Update A Firewall Rule\n\nFirewall rules are managed from the `firewall_rules` operation group, not through generic ARM networking APIs:\n\n```python\nfrom azure.mgmt.datalake.store.models import UpdateFirewallRuleParameters\n\nrule = client.firewall_rules.update(\n    \"example-rg\",\n    \"existing-adlsg1\",\n    \"office-ip\",\n    UpdateFirewallRuleParameters(\n        start_ip_address=\"203.0.113.10\",\n        end_ip_address=\"203.0.113.10\",\n    ),\n)\n\nprint(rule.name)\nprint(rule.start_ip_address, rule.end_ip_address)\n```\n\nTo inspect current firewall rules first:\n\n```python\nfor rule in client.firewall_rules.list_by_account(\"example-rg\", \"existing-adlsg1\"):\n    print(rule.name, rule.start_ip_address, rule.end_ip_address)\n```\n\n## Configuration Notes\n\n- This package manages the Azure resource, not files and folders inside the account.\n- The service endpoint is Azure Resource Manager, so the subscription ID is always part of the client context.\n- The current Learn reference documents `accounts.begin_create`, `accounts.begin_delete`, `accounts.begin_update`, `accounts.get`, `accounts.list`, `accounts.list_by_resource_group`, `accounts.check_name_availability`, and `accounts.enable_key_vault`.\n- `virtual_network_rules` and `trusted_id_providers` are exposed as separate operation groups if the account still uses those Gen1 controls.\n- The generated client also exposes `locations.get_capability` and `locations.get_usage` for subscription-level regional checks.\n\n## Common Pitfalls\n\n- Do not use this package for ADLS Gen2 data access. Use `azure-storage-file-datalake` for current file and directory operations.\n- Do not assume Gen1 is still a viable target for new deployments. The service retired on February 29, 2024, and Microsoft says new Gen1 accounts cannot be created unless you already have one.\n- Do not copy current Learn auth examples blindly into a codebase pinned to `0.5.0`. The old stable line uses legacy Azure management auth patterns, while current Learn reference pages are generated from a newer package line.\n- Do not instantiate operation classes like `AccountsOperations` or `FirewallRulesOperations` directly. Use them through `DataLakeStoreAccountManagementClient`.\n- Do not forget the subscription ID. Authentication settings alone are not enough to build the management client.\n- If you are updating older scripts, watch for method-name drift: current docs show `begin_create` and `begin_update`, while older installs may still expose `create` and `update`.\n- Firewall and virtual network settings are account-level controls for Gen1. They are not interchangeable with ADLS Gen2 storage firewall guidance.\n\n## Version-Sensitive Notes For `0.5.0`\n\n- The official Azure sample page for this package still describes the older management-library generation and says the SDK sample was compatible with Python `2.7`, `3.3`, `3.4`, `3.5`, and `3.6`.\n- Current Microsoft Learn API reference pages for `azure-mgmt-datalake-store` are on the preview doc view and show the newer generated method shape, including `begin_*` long-running operations.\n- That means there is real documentation drift between the stable `0.5.0` package line and the newer reference pages. Keep your dependency pinned and verify the methods exposed by your installed package before bulk-updating old scripts.\n- If you are starting a new project rather than maintaining existing Gen1 resources, skip this package and move straight to ADLS Gen2 guidance.\n\n## Official Sources\n\n- PyPI package page and release history: https://pypi.org/project/azure-mgmt-datalake-store/\n- Microsoft Learn package reference root: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/\n- `azure.mgmt.datalake.store` package reference: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store?view=azure-python-preview\n- `AccountsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.operations.accountsoperations?view=azure-python-preview\n- `FirewallRulesOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.operations.firewallrulesoperations?view=azure-python-preview\n- `LocationsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.operations.locationsoperations?view=azure-python-preview\n- `CreateDataLakeStoreAccountParameters`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.models.createdatalakestoreaccountparameters?view=azure-python-preview\n- `UpdateDataLakeStoreAccountParameters`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.models.updatedatalakestoreaccountparameters?view=azure-python-preview\n- `UpdateFirewallRuleParameters`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-datalake-store/azure.mgmt.datalake.store.models.updatefirewallruleparameters?view=azure-python-preview\n- Azure management sample for Data Lake Store: https://learn.microsoft.com/en-us/samples/azure-samples/azure-samples-python-management/datalakestore/\n- Azure Data Lake Storage Gen1 retirement note: https://learn.microsoft.com/en-us/power-query/connectors/azure-data-lake-storage-gen1\n- Azure Data Lake Storage Gen2 Python guide: https://learn.microsoft.com/en-us/azure/storage/blobs/data-lake-storage-directory-file-acl-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-devtestlabs/python/DOC.md",
    "content": "---\nname: mgmt-devtestlabs\ndescription: \"Azure DevTest Labs management-plane SDK for Python for labs, lab virtual machines, schedules, gallery images, and notification channels\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,devtestlabs,arm,management,virtual-machines,schedules,python\"\n---\n\n# Azure DevTest Labs Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-devtestlabs` for Azure Resource Manager control-plane automation around DevTest Labs resources such as labs, lab virtual machines, schedules, gallery images, virtual networks, and notification channels. Pair it with `azure-identity`, pass an explicit subscription ID, and treat most write operations as long-running `begin_*` calls that need `.result()`.\n\nThis guide is for the stable `9.0.0` release published on January 4, 2021. PyPI still lists that release as tested with Python 2.7, 3.5, 3.6, and 3.7, so verify interpreter compatibility in your environment before standardizing on it in newer Python runtimes.\n\n## Install\n\nInstall the management package with a current Azure credential package:\n\n```bash\npython -m pip install \"azure-mgmt-devtestlabs==9.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-devtestlabs==9.0.0\" azure-identity\npoetry add \"azure-mgmt-devtestlabs==9.0.0\" azure-identity\n```\n\n## Authentication And Setup\n\nThe package now expects `azure-identity` credentials, not older `azure.common.credentials` or `msrestazure.azure_active_directory` credentials.\n\nLocal development with Azure CLI:\n\n```bash\naz login\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nService principal environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.devtestlabs import DevTestLabsClient\n\ncredential = DefaultAzureCredential()\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = DevTestLabsClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor short-lived scripts, closing the client when you are done is a good default:\n\n```python\nclient.close()\n```\n\n## Core Operation Groups\n\nThe main entry points most projects use are:\n\n- `client.labs`\n- `client.virtual_machines`\n- `client.virtual_machine_schedules`\n- `client.schedules`\n- `client.gallery_images`\n- `client.virtual_networks`\n- `client.notification_channels`\n\n## Discover Labs And Lab Resources\n\nList labs in the current subscription:\n\n```python\nfor lab in client.labs.list_by_subscription():\n    print(lab.name, lab.location, lab.id)\n```\n\nList labs in one resource group:\n\n```python\nresource_group = \"example-rg\"\n\nfor lab in client.labs.list_by_resource_group(resource_group):\n    print(lab.name, lab.location)\n```\n\nGet one lab and ask ARM to expand selected properties:\n\n```python\nlab = client.labs.get(\n    resource_group_name=\"example-rg\",\n    name=\"example-lab\",\n    expand=\"properties($select=defaultStorageAccount)\",\n)\n\nprint(lab.id)\nprint(lab.default_storage_account)\n```\n\nList gallery images you can use as VM bases:\n\n```python\nfor image in client.gallery_images.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n):\n    print(image.name)\n    print(image.os_type)\n```\n\nList DevTest Labs virtual networks attached to the lab:\n\n```python\nfor vnet in client.virtual_networks.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n):\n    print(vnet.name, vnet.id)\n```\n\n## Create A Lab VM From A Gallery Image\n\nCreating a lab VM requires a lab name, an attached DevTest Labs virtual network ID, a lab subnet name, and a gallery image reference.\n\n```python\nfrom azure.mgmt.devtestlabs.models import GalleryImageReference, LabVirtualMachine\n\nresource_group = \"example-rg\"\nlab_name = \"example-lab\"\nvm_name = \"devbox-01\"\n\nvm_poller = client.virtual_machines.begin_create_or_update(\n    resource_group_name=resource_group,\n    lab_name=lab_name,\n    name=vm_name,\n    lab_virtual_machine=LabVirtualMachine(\n        location=\"westus2\",\n        size=\"Standard_A2_v2\",\n        user_name=\"azureuser\",\n        password=\"replace-with-a-secret\",\n        storage_type=\"Standard\",\n        allow_claim=True,\n        disallow_public_ip_address=True,\n        lab_virtual_network_id=(\n            \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n            \"resourceGroups/example-rg/providers/Microsoft.DevTestLab/\"\n            \"labs/example-lab/virtualNetworks/example-vnet\"\n        ),\n        lab_subnet_name=\"example-vnetSubnet\",\n        gallery_image_reference=GalleryImageReference(\n            publisher=\"Canonical\",\n            offer=\"UbuntuServer\",\n            sku=\"16.04-LTS\",\n            os_type=\"Linux\",\n            version=\"Latest\",\n        ),\n    ),\n)\n\nvm = vm_poller.result()\nprint(vm.id)\nprint(vm.provisioning_state)\n```\n\nUseful follow-up reads:\n\n```python\nvm = client.virtual_machines.get(\n    resource_group_name=resource_group,\n    lab_name=lab_name,\n    name=vm_name,\n    expand=\"properties($expand=artifacts,computeVm,networkInterface,applicableSchedule)\",\n)\n\nprint(vm.size)\nprint(vm.os_type)\nprint(vm.compute_id)\n```\n\n## Manage Existing Lab VMs\n\nList VMs in one lab:\n\n```python\nfor vm in client.virtual_machines.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n):\n    print(vm.name, vm.owner_user_principal_name, vm.last_known_power_state)\n```\n\nStart, stop, restart, resize, or claim a VM:\n\n```python\nresource_group = \"example-rg\"\nlab_name = \"example-lab\"\nvm_name = \"devbox-01\"\n\nclient.virtual_machines.begin_start(resource_group, lab_name, vm_name).result()\nclient.virtual_machines.begin_stop(resource_group, lab_name, vm_name).result()\nclient.virtual_machines.begin_restart(resource_group, lab_name, vm_name).result()\nclient.virtual_machines.begin_resize(\n    resource_group,\n    lab_name,\n    vm_name,\n    size=\"Standard_A4_v2\",\n).result()\nclient.virtual_machines.begin_claim(resource_group, lab_name, vm_name).result()\n```\n\nFor Windows lab VMs, retrieve the generated RDP payload:\n\n```python\nrdp = client.virtual_machines.get_rdp_file_contents(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    name=\"windows-devbox-01\",\n)\n\nprint(rdp)\n```\n\n## Lab And VM Schedules\n\nList schedules at the lab level:\n\n```python\nfor schedule in client.schedules.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n):\n    print(schedule.name, schedule.task_type, schedule.status)\n```\n\nList schedules attached directly to one VM:\n\n```python\nfor schedule in client.virtual_machine_schedules.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    virtual_machine_name=\"devbox-01\",\n):\n    print(schedule.name, schedule.task_type, schedule.status)\n```\n\nRead the effective startup and shutdown schedules currently applied to a VM:\n\n```python\napplicable = client.virtual_machines.list_applicable_schedules(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    name=\"devbox-01\",\n)\n\nprint(applicable.lab_vms_shutdown)\nprint(applicable.lab_vms_startup)\n```\n\nCreate or replace a VM auto-shutdown schedule:\n\n```python\nfrom azure.mgmt.devtestlabs.models import NotificationSettings, Schedule\n\nvm = client.virtual_machines.get(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    name=\"devbox-01\",\n)\n\nschedule = client.virtual_machine_schedules.create_or_update(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    virtual_machine_name=\"devbox-01\",\n    name=\"auto-shutdown\",\n    schedule=Schedule(\n        location=vm.location,\n        status=\"Enabled\",\n        task_type=\"LabVmsShutdownTask\",\n        time_zone_id=\"Pacific Standard Time\",\n        target_resource_id=vm.id,\n        daily_recurrence={\"time\": \"1900\"},\n        notification_settings=NotificationSettings(\n            status=\"Enabled\",\n            time_in_minutes=30,\n            email_recipient=\"devops@example.com\",\n            notification_locale=\"EN\",\n            webhook_url=\"https://example.com/devtestlabs-hook\",\n        ),\n    ),\n)\n\nprint(schedule.name, schedule.status)\n```\n\nExecute an existing schedule immediately:\n\n```python\nclient.virtual_machine_schedules.begin_execute(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    virtual_machine_name=\"devbox-01\",\n    name=\"auto-shutdown\",\n).result()\n```\n\n## Notification Channels\n\nList notification channels configured on a lab:\n\n```python\nfor channel in client.notification_channels.list(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n):\n    print(channel.name, channel.description)\n```\n\nSend a notification to an existing channel:\n\n```python\nclient.notification_channels.notify(\n    resource_group_name=\"example-rg\",\n    lab_name=\"example-lab\",\n    name=\"shutdown-webhook\",\n    event_name=\"AutoShutdown\",\n    json_payload='{\"message\":\"manual test\"}',\n)\n```\n\n## Important Pitfalls\n\n- This is an ARM management SDK. It provisions and manages DevTest Labs resources, but it does not replace SSH, WinRM, cloud-init, or app deployment tooling inside the guest OS.\n- `subscription_id` is required even when credential resolution succeeds.\n- Most mutations are long-running operations. Wait on `.result()` before assuming the resource is ready.\n- Older samples that use `azure.common.credentials`, `ServicePrincipalCredentials`, `CloudError`, or non-`begin_*` write methods are pre-`9.x` patterns and should not be copied into current code.\n- VM creation depends on existing lab resources. In practice you usually need a valid DevTest Labs virtual network ID, subnet name, and gallery image reference before `begin_create_or_update(...)` will succeed.\n- `get_rdp_file_contents()` is for RDP access. Linux VMs still need SSH-oriented access and credentials.\n- `9.0.0` is an older stable release. PyPI also shows newer pre-release builds in the `10.0.0b*` line, so do not mix snippets from preview docs into a project pinned to `9.0.0`.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-devtestlabs/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.devtestlabsclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.labsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.virtualmachinesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.virtualmachineschedulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.schedulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.galleryimagesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.virtualnetworksoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.operations.notificationchannelsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.models.lab?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.models.labvirtualmachine?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.models.galleryimagereference?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.models.schedule?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-devtestlabs/azure.mgmt.devtestlabs.models.notificationsettings?view=azure-python\n- https://learn.microsoft.com/en-us/rest/api/dtl/virtual-machines/create-or-update?view=rest-dtl-2018-09-15\n- https://learn.microsoft.com/en-us/rest/api/dtl/virtual-machine-schedules/create-or-update?view=rest-dtl-2018-09-15\n- https://learn.microsoft.com/en-us/rest/api/dtl/notification-channels/create-or-update?view=rest-dtl-2018-09-15\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-dns/python/DOC.md",
    "content": "---\nname: mgmt-dns\ndescription: \"Azure DNS management SDK for Python for public DNS zones, record sets, and ARM-based DNS administration\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,dns,arm,management,dns-zones,record-sets,python\"\n---\n\n# Azure DNS Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-dns` for Azure Resource Manager management of Azure DNS zones and record sets, not for making DNS queries from your app. Install `azure-identity` with it, authenticate with a `TokenCredential`, pass `AZURE_SUBSCRIPTION_ID` explicitly, and remember that record-set names are relative to the zone (`www`, not `www.example.com`; use `@` for the zone apex).\n\n## Install\n\nPin the package version your project expects and install an Azure credential package alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-dns==9.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-dns==9.0.0\" azure-identity\npoetry add \"azure-mgmt-dns==9.0.0\" azure-identity\n```\n\n`azure-mgmt-dns 9.0.0` requires Python 3.9 or later.\n\n## Authentication And Setup\n\nUse one of these credential patterns:\n\n- `DefaultAzureCredential()` for code that should work locally, in CI, and on Azure\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.dns import DnsManagementClient\n\ncredential = DefaultAzureCredential()\nclient = DnsManagementClient(\n    credential=credential,\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nmodels = client.models(\"2018-05-01\")\n```\n\nLocal CLI-driven setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.dns import DnsManagementClient\n\nclient = DnsManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe current Learn reference exposes these main operation groups:\n\n- `zones`\n- `record_sets`\n- `dns_resource_reference`\n\n## Core Usage\n\n### Create a public DNS zone\n\nAzure DNS zones are global resources, so the zone `location` is `\"global\"`:\n\n```python\nzone = client.zones.create_or_update(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    parameters=models.Zone(\n        location=\"global\",\n        zone_type=\"Public\",\n        tags={\"env\": \"dev\"},\n    ),\n)\n\nprint(zone.id)\nprint(zone.name_servers)\n```\n\nCreating the zone in Azure does not delegate your domain automatically. After creation, update the domain at your registrar to use the Azure DNS name servers returned by the zone.\n\n### List and get zones\n\n```python\nfor zone in client.zones.list_by_resource_group(\"dns-rg\"):\n    print(zone.name, zone.max_number_of_record_sets)\n\nzone = client.zones.get(\"dns-rg\", \"example.com\")\nprint(zone.etag)\nprint(zone.name_servers)\n```\n\n`zones.get(...)` returns zone metadata, not the record sets inside the zone.\n\n### Create or replace an A record set\n\n```python\nrecord_set = client.record_sets.create_or_update(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    relative_record_set_name=\"www\",\n    record_type=\"A\",\n    parameters=models.RecordSet(\n        ttl=300,\n        a_records=[\n            models.ARecord(ipv4_address=\"203.0.113.10\"),\n            models.ARecord(ipv4_address=\"203.0.113.11\"),\n        ],\n    ),\n)\n\nprint(record_set.fqdn)\n```\n\nUse relative names:\n\n- `\"www\"` creates `www.example.com`\n- `\"@\"` targets the zone apex (`example.com`)\n\n### Create a CNAME record set\n\n```python\nrecord_set = client.record_sets.create_or_update(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    relative_record_set_name=\"app\",\n    record_type=\"CNAME\",\n    parameters=models.RecordSet(\n        ttl=300,\n        cname_record=models.CnameRecord(\n            cname=\"myapp.azurewebsites.net\",\n        ),\n    ),\n)\n\nprint(record_set.fqdn)\n```\n\nAzure DNS does not allow a CNAME record at the zone apex, and a name that has a CNAME record cannot have other record types.\n\n### List record sets in a zone\n\n```python\nfor record_set in client.record_sets.list_all_by_dns_zone(\"dns-rg\", \"example.com\"):\n    print(record_set.name, record_set.type, record_set.ttl)\n```\n\nThese methods return paged iterators. Iterate over them instead of assuming one in-memory list.\n\n### Update an existing record set safely with its ETag\n\n```python\nexisting = client.record_sets.get(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    relative_record_set_name=\"www\",\n    record_type=\"A\",\n)\n\nupdated = client.record_sets.update(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    relative_record_set_name=\"www\",\n    record_type=\"A\",\n    parameters=models.RecordSet(\n        ttl=600,\n        a_records=existing.a_records,\n        metadata={\"owner\": \"platform\"},\n    ),\n    if_match=existing.etag,\n)\n\nprint(updated.ttl)\n```\n\nUse `if_match` when you do not want to overwrite a concurrently changed record set by accident.\n\n### Delete a record set or a zone\n\n```python\nclient.record_sets.delete(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n    relative_record_set_name=\"app\",\n    record_type=\"CNAME\",\n)\n\nclient.zones.begin_delete(\n    resource_group_name=\"dns-rg\",\n    zone_name=\"example.com\",\n).result()\n```\n\nDeleting a zone is a long-running operation. Wait on `.result()` when the delete must finish before the next step.\n\n## Async Usage\n\nThe package also exposes `azure.mgmt.dns.aio.DnsManagementClient`. Use it only when the rest of your application is already async:\n\n```python\nimport asyncio\nimport os\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.mgmt.dns.aio import DnsManagementClient\n\nasync def main():\n    credential = DefaultAzureCredential()\n    client = DnsManagementClient(\n        credential=credential,\n        subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n    )\n\n    try:\n        async for zone in client.zones.list_by_resource_group(\"dns-rg\"):\n            print(zone.name)\n    finally:\n        await client.close()\n        await credential.close()\n\nasyncio.run(main())\n```\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-dns` without `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`; the management client does not infer it from the credential\n- Passing fully qualified names like `www.example.com` as `relative_record_set_name` instead of `www`\n- Forgetting that zone `location` is `\"global\"`\n- Assuming `zones.get(...)` or `zones.list*` includes record data\n- Creating a CNAME at the zone apex or mixing a CNAME with other record types at the same name\n- Trying to create or delete the apex `SOA` or `NS` record set directly; Azure creates them automatically for every DNS zone\n- Deleting a zone without realizing all record sets in that zone are removed with it\n\n## Version-Sensitive Notes\n\nPyPI release notes for `azure-mgmt-dns 9.0.0` call out these breaking changes:\n\n- Python 3.8 support was dropped; Python 3.9 is now the minimum\n- `dnssec_configs` was removed\n- `DsRecord`, `NaptrRecord`, `TlsaRecord`, and related enum values were removed\n\nIf you are upgrading older code that used DNSSEC configuration or DS, NAPTR, or TLSA record helpers, verify the pinned package version before copying examples forward.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-dns/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-dns/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-dns/azure.mgmt.dns.dnsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-dns/azure.mgmt.dns.operations.zonesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-dns/azure.mgmt.dns.operations.recordsetsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-dns/azure.mgmt.dns.aio.dnsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/azure/dns/dns-zones-records\n- https://learn.microsoft.com/en-us/azure/networking/dns/dns-zones-records-portal\n- https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-eventgrid/python/DOC.md",
    "content": "---\nname: mgmt-eventgrid\ndescription: \"Azure Event Grid management-plane SDK for Python for topics, domains, namespaces, system topics, and event subscriptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,event-grid,management,arm,topics,event-subscriptions,namespaces\"\n---\n\n# Azure Event Grid Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-eventgrid` for Azure Resource Manager control-plane work: creating and configuring Event Grid topics, domains, namespaces, system topics, and event subscriptions. Do not use it to publish or receive event payloads. For actual event publishing or consuming, use `azure-eventgrid`.\n\nFor `10.4.0`, pair it with `azure-identity`, pass the subscription ID explicitly, and expect create/update/delete calls to use `begin_*` long-running operations that need `.result()`.\n\n## Install\n\nInstall the management SDK with an Azure credential package:\n\n```bash\npython -m pip install \"azure-mgmt-eventgrid==10.4.0\" azure-identity\n```\n\nIf the same app also publishes or consumes events, install the data-plane SDK too:\n\n```bash\npython -m pip install azure-eventgrid\n```\n\nThe PyPI package page for `10.4.0` states that this package supports Python `3.8+`.\n\nIf this is the first Event Grid resource in the subscription, register the provider first:\n\n```bash\naz provider register --namespace Microsoft.EventGrid\n```\n\nCommon environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n\n# Only if you are authenticating with a service principal directly\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\n`EventGridManagementClient` requires a `TokenCredential` and the subscription ID:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.eventgrid import EventGridManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nwith EventGridManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n) as client:\n    for topic in client.topics.list_by_subscription():\n        print(topic.name)\n```\n\nFor local scripts after `az login`, `AzureCliCredential` is often simpler:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.eventgrid import EventGridManagementClient\n\nclient = EventGridManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nImportant setup facts from the official client docs:\n\n- `subscription_id` is required.\n- The default ARM endpoint is `https://management.azure.com`.\n- The generated client defaults to API version `2025-02-15`, and the docs warn that overriding it may produce unsupported behavior.\n\n## Create A Custom Topic\n\nCreate a topic when you want your own application or service to publish events into Event Grid.\n\n```python\nfrom azure.mgmt.eventgrid.models import Topic\n\nresource_group_name = \"example-rg\"\ntopic_name = \"orders-topic-1234\"\n\ntopic = client.topics.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    topic_name=topic_name,\n    topic_info=Topic(\n        location=\"westus2\",\n        input_schema=\"CloudEventSchemaV1_0\",\n        minimum_tls_version_allowed=\"1.2\",\n        public_network_access=\"Enabled\",\n        disable_local_auth=False,\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n).result()\n\nprint(topic.id)\nprint(topic.endpoint)\n```\n\nWhat matters in this payload:\n\n- `location` is required.\n- `input_schema` controls what publishers must send: `EventGridSchema`, `CustomEventSchema`, or `CloudEventSchemaV1_0`.\n- `minimum_tls_version_allowed` can restrict publishers to TLS `1.2`.\n- `disable_local_auth=True` turns off key-based publishing for the topic; keep it `False` only if you intentionally need topic keys.\n\nThe product docs also call out these naming rules for custom topics: the name must be unique, 3 to 50 characters long, and use only letters, digits, and `-`.\n\n## Get The Topic Endpoint And Publishing Keys\n\nThe created `Topic` object includes `topic.endpoint`. If local auth is enabled, you can also retrieve the shared access keys:\n\n```python\nkeys = client.topics.list_shared_access_keys(\n    resource_group_name=resource_group_name,\n    topic_name=topic_name,\n)\n\nprint(topic.endpoint)\nprint(keys.key1)\nprint(keys.key2)\n```\n\nUse those values with `azure-eventgrid` when publishing:\n\n```python\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.core.messaging import CloudEvent\nfrom azure.eventgrid import EventGridPublisherClient\n\npublisher = EventGridPublisherClient(\n    endpoint=topic.endpoint,\n    credential=AzureKeyCredential(keys.key1),\n)\n\npublisher.send(\n    CloudEvent(\n        type=\"com.example.order.created\",\n        source=\"/orders/42\",\n        data={\"orderId\": 42, \"status\": \"created\"},\n    )\n)\n```\n\nIf you set `disable_local_auth=True`, switch to `DefaultAzureCredential` or another Entra-backed `TokenCredential` when you create the publisher client instead of trying to use a topic key.\n\n## Create An Event Subscription On The Topic\n\nUse `topic_event_subscriptions` for subscriptions that hang directly off a custom Event Grid topic:\n\n```python\nimport os\n\nfrom azure.mgmt.eventgrid.models import (\n    EventSubscription,\n    EventSubscriptionFilter,\n    WebHookEventSubscriptionDestination,\n)\n\nevent_subscription = client.topic_event_subscriptions.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    topic_name=topic_name,\n    event_subscription_name=\"orderswebhooksub\",\n    event_subscription_info=EventSubscription(\n        destination=WebHookEventSubscriptionDestination(\n            endpoint_url=os.environ[\"WEBHOOK_ENDPOINT\"],\n            minimum_tls_version_allowed=\"1.2\",\n        ),\n        filter=EventSubscriptionFilter(\n            included_event_types=[\"com.example.order.created\"],\n            subject_begins_with=\"/orders/\",\n        ),\n        labels=[\"orders\", \"webhook\"],\n        event_delivery_schema=\"CloudEventSchemaV1_0\",\n    ),\n).result()\n\nprint(event_subscription.id)\nprint(event_subscription.provisioning_state)\n```\n\nUseful subscription settings from the model docs:\n\n- `destination` chooses where Event Grid delivers events.\n- `filter` supports `subject_begins_with`, `subject_ends_with`, `included_event_types`, and `advanced_filters`.\n- `event_delivery_schema` can be `EventGridSchema`, `CustomInputSchema`, or `CloudEventSchemaV1_0`.\n- `labels` gives you lightweight tags for later filtering and inspection.\n\nIf you need the resolved destination URL after creation, call:\n\n```python\nfull_url = client.topic_event_subscriptions.get_full_url(\n    resource_group_name=resource_group_name,\n    topic_name=topic_name,\n    event_subscription_name=\"orderswebhooksub\",\n)\n\nprint(full_url.endpoint_url)\n```\n\n## Create An Event Subscription On Another Azure Resource\n\nThe generic `event_subscriptions` operation works on scopes such as a subscription, resource group, top-level Azure resource, or Event Grid topic ID.\n\nThis example subscribes to a storage account resource and delivers blob-created events to a queue:\n\n```python\nfrom azure.mgmt.eventgrid.models import (\n    EventSubscription,\n    EventSubscriptionFilter,\n    StorageQueueEventSubscriptionDestination,\n)\n\nstorage_account_id = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n    \"resourceGroups/example-rg/providers/Microsoft.Storage/\"\n    \"storageAccounts/examplestorageacct\"\n)\n\nqueue_destination = StorageQueueEventSubscriptionDestination(\n    resource_id=storage_account_id,\n    queue_name=\"incoming-events\",\n)\n\nsubscription = client.event_subscriptions.begin_create_or_update(\n    scope=storage_account_id,\n    event_subscription_name=\"blobcreatedqueue\",\n    event_subscription_info=EventSubscription(\n        destination=queue_destination,\n        filter=EventSubscriptionFilter(\n            included_event_types=[\"Microsoft.Storage.BlobCreated\"],\n        ),\n    ),\n).result()\n\nprint(subscription.id)\n```\n\nIf you already know the resource components instead of the full ARM ID, you can inspect existing subscriptions with:\n\n```python\nfor sub in client.event_subscriptions.list_by_resource(\n    resource_group_name=\"example-rg\",\n    provider_namespace=\"Microsoft.Storage\",\n    resource_type_name=\"storageAccounts\",\n    resource_name=\"examplestorageacct\",\n):\n    print(sub.name)\n```\n\n## Namespaces, System Topics, And Other Resource Types\n\n`EventGridManagementClient` also exposes operation groups for:\n\n- `namespaces`\n- `namespace_topics`\n- `namespace_topic_event_subscriptions`\n- `system_topics`\n- `system_topic_event_subscriptions`\n- `domains`\n- `domain_topics`\n\nThe usage pattern is the same as the topic examples above: create the resource model, call the appropriate `begin_create_or_update(...)`, and wait on `.result()`. Keep the resource type straight:\n\n- Event Grid Basic custom topics and domains are publish endpoints.\n- Namespaces are a separate Event Grid resource family with dedicated `namespaces` and `namespace_topics` operation groups.\n- System topics represent events emitted by Azure services such as Storage or Event Hubs.\n\n## Common Pitfalls\n\n- `azure-mgmt-eventgrid` is not the publishing SDK. Provision resources here, then publish or consume with `azure-eventgrid`.\n- Topic schema choices matter. If the topic input schema is `CloudEventSchemaV1_0`, your publishers must send CloudEvents, not Event Grid events.\n- `disable_local_auth=True` disables local key-based authentication for the topic.\n- Webhook subscriptions must pass Event Grid endpoint validation before delivery starts.\n- When you use Event Grid event schema delivery, webhook validation uses `SubscriptionValidationEvent`.\n- When you use CloudEvents schema delivery, webhook validation follows the CloudEvents abuse-protection `OPTIONS` flow instead.\n- Event subscription names must be 3 to 64 characters and use alphanumeric characters only.\n- Most write operations are long-running ARM operations. If you skip `.result()`, later code often races the resource creation.\n- `10.4.0` uses keyword-only model constructors. Rewrite older positional-argument samples before copying them.\n\n## Version Notes For `10.4.0`\n\nThe PyPI release history for `10.4.0` calls out three high-value changes:\n\n- models are generated with keyword-only signatures\n- long-running operations return `msrest.polling.LROPoller`\n- the client can be used as a context manager to keep the underlying HTTP session open\n\nIf you are updating older code, treat positional model constructors and old poller assumptions as migration work, not copy-paste examples.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-eventgrid/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.eventgridmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.operations.topicsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.models.topic?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.operations.topiceventsubscriptionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.operations.eventsubscriptionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.models.eventsubscription?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.models.eventsubscriptionfilter?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.models.webhookeventsubscriptiondestination?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventgrid/azure.mgmt.eventgrid.models.storagequeueeventsubscriptiondestination?view=azure-python\n- https://learn.microsoft.com/en-us/azure/event-grid/create-custom-topic\n- https://learn.microsoft.com/en-us/azure/event-grid/custom-event-quickstart\n- https://learn.microsoft.com/en-us/azure/event-grid/end-point-validation-event-grid-events-schema\n- https://learn.microsoft.com/en-us/azure/event-grid/end-point-validation-cloud-events-schema\n- https://learn.microsoft.com/en-us/python/api/overview/azure/eventgrid-readme?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-eventhub/python/DOC.md",
    "content": "---\nname: mgmt-eventhub\ndescription: \"Azure Event Hubs management-plane SDK for Python for namespaces, event hubs, authorization rules, and ARM configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"11.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,eventhubs,arm,management,namespaces,provisioning,python\"\n---\n\n# Azure Event Hubs Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-eventhub` for Azure Resource Manager control-plane work: creating namespaces, creating event hubs, managing authorization rules, and updating namespace settings. Do not use it to publish or consume events. For data-plane send and receive code, use `azure-eventhub`.\n\nFor package version `11.2.0`, the main client is `EventHubManagementClient`. The client defaults to the stable `2024-01-01` Event Hubs ARM API unless you explicitly override `api_version`.\n\n## Install\n\nInstall the management package and an Azure credential package together:\n\n```bash\npython -m pip install \"azure-mgmt-eventhub==11.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-eventhub==11.2.0\" azure-identity\npoetry add \"azure-mgmt-eventhub==11.2.0\" azure-identity\n```\n\nEnvironment you usually need:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\nUse one of these credential patterns:\n\n- `DefaultAzureCredential()` for reusable code, CI, managed identity, or workload identity\n- `AzureCliCredential()` for local scripts after `az login`\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.eventhub import EventHubManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = EventHubManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.eventhub import EventHubManagementClient\n\nclient = EventHubManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nAuthentication success is not enough by itself. The principal also needs Azure RBAC permissions to create or update `Microsoft.EventHub/*` resources at the subscription, resource-group, or namespace scope you target.\n\n## Core Workflows\n\n### Check namespace name availability\n\nNamespace names are globally unique. Check first instead of learning from a failed create call:\n\n```python\nnamespace_name = \"ctxhub-eh-ns-01\"\n\navailability = client.namespaces.check_name_availability(\n    {\"name\": namespace_name}\n)\n\nif not availability.name_available:\n    raise RuntimeError(availability.message or availability.reason)\n```\n\n### Create a namespace\n\nNamespace creation is a long-running ARM operation, so call `.result()` on the poller before using the namespace:\n\n```python\npoller = client.namespaces.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    parameters={\n        \"location\": \"eastus\",\n        \"sku\": {\n            \"name\": \"Standard\",\n            \"tier\": \"Standard\",\n            \"capacity\": 1,\n        },\n        \"minimum_tls_version\": \"1.2\",\n        \"public_network_access\": \"Enabled\",\n        \"is_auto_inflate_enabled\": True,\n        \"maximum_throughput_units\": 4,\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    },\n)\n\nnamespace = poller.result()\nprint(namespace.id)\n```\n\nUse `disable_local_auth=True` only when downstream apps authenticate with Microsoft Entra ID instead of SAS connection strings.\n\n### Create an event hub\n\nCreate the event hub after the namespace exists:\n\n```python\nevent_hub = client.event_hubs.create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    event_hub_name=\"orders\",\n    parameters={\n        \"partition_count\": 4,\n        \"message_retention_in_days\": 7,\n    },\n)\n\nprint(event_hub.id)\n```\n\nThe documented `Eventhub` model for this client version includes `partition_count`, `message_retention_in_days`, and optional `capture_description`. Keep the event hub configuration aligned with the namespace SKU you actually provisioned.\n\n### Create an authorization rule and get a connection string\n\nCreate SAS authorization rules only if your application really needs shared-access-key auth. For a single event hub, create the rule on the event hub and then read its keys:\n\n```python\nclient.event_hubs.create_or_update_authorization_rule(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    event_hub_name=\"orders\",\n    authorization_rule_name=\"send-listen\",\n    parameters={\n        \"rights\": [\"Listen\", \"Send\"],\n    },\n)\n\nkeys = client.event_hubs.list_keys(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    event_hub_name=\"orders\",\n    authorization_rule_name=\"send-listen\",\n)\n\nprint(keys.primary_connection_string)\n```\n\nUse namespace authorization rules only when you want namespace-wide access. Event-hub-level rules are narrower and produce connection strings scoped to that event hub.\n\n### List or inspect existing resources\n\n```python\nfor namespace in client.namespaces.list_by_resource_group(\"example-rg\"):\n    print(namespace.name, namespace.location, namespace.sku.name)\n\nfor hub in client.event_hubs.list_by_namespace(\"example-rg\", namespace_name):\n    print(hub.name, hub.partition_count)\n\nnamespace = client.namespaces.get(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n)\n\nprint(namespace.minimum_tls_version)\nprint(namespace.public_network_access)\n```\n\n## Configuration Notes\n\n- `EventHubManagementClient` needs `subscription_id`; it is not inferred from the credential.\n- `begin_create_or_update`, `begin_delete`, and other `begin_*` methods return pollers. Wait on `.result()` before assuming the ARM operation is finished.\n- The client constructor accepts `api_version`, but the package docs state the default is the latest public version. Only override it when you intentionally need a different stable or preview API surface.\n- Namespace auth rules and event-hub auth rules are different resources. Use event-hub rules when your application should be scoped to one hub instead of the whole namespace.\n- If you turn off local auth with `disable_local_auth`, SAS-based connection strings stop being the right integration path. Use Entra ID with the data-plane `azure-eventhub` client instead.\n\n## Version-Sensitive Notes\n\n`11.2.0` adds several new generated surface areas compared with earlier `11.x` builds, including:\n\n- `NamespacesOperations.begin_failover`\n- `EHNamespace.geo_data_replication`\n- `Eventhub.identifier`\n- `Eventhub.message_timestamp_description`\n- `RetentionDescription.min_compaction_lag_in_mins`\n\nIf copied code or internal wrappers were written against earlier `11.x` releases, verify that they still match the current generated models before reusing them.\n\nThe package docs also show multiple versioned operation groups under `azure.mgmt.eventhub.v20xx_xx_xx...`. Those are not interchangeable. If you choose a preview API version explicitly, keep the operation group, model imports, and expected fields aligned to that version.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-eventhub` for producing or consuming events instead of `azure-eventhub`\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Calling a long-running `begin_*` method and then using the resource before `poller.result()`\n- Creating a namespace-wide SAS rule when the app only needs one event hub\n- Expecting SAS connection strings to remain usable after enabling `disable_local_auth`\n- Copying snippets from a different `azure.mgmt.eventhub.v20xx_*` API-versioned namespace into the default `11.2.0` client without checking model drift\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-eventhub/11.2.0/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/azure.mgmt.eventhub.eventhubmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/azure.mgmt.eventhub.operations.namespacesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/azure.mgmt.eventhub.operations.eventhubsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/azure.mgmt.eventhub.models.ehnamespace?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-eventhub/azure.mgmt.eventhub.models.eventhub?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python\n- https://learn.microsoft.com/en-us/rest/api/eventhub/controlplane-stable/check-name-availability-namespaces/check-name-availability\n- https://learn.microsoft.com/en-us/rest/api/eventhub/operations/list?view=rest-eventhub-2024-01-01\n"
  },
  {
    "path": "content/azure/docs/mgmt-frontdoor/python/DOC.md",
    "content": "---\nname: mgmt-frontdoor\ndescription: \"Azure Front Door management SDK for Python for Front Door resources, WAF policies, custom domain validation, and related ARM operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,frontdoor,arm,waf,cdn,network,python\"\n---\n\n# Azure Front Door Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-frontdoor` for Azure Resource Manager management of Front Door resources through `FrontDoorManagementClient`. Pair it with `azure-identity`, pass an Azure subscription ID explicitly, and expect write operations such as `begin_create_or_update` and `begin_delete` to return long-running pollers that you should finish with `.result()`.\n\nThis package is a management-plane SDK. It creates and updates ARM resources such as Front Doors, frontend endpoints, custom-domain validation checks, and Front Door WAF policies. It is not the data-plane surface for sending traffic through Front Door.\n\n## Install\n\nPin the package version your project expects and install Azure credentials alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-frontdoor==1.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-frontdoor==1.2.0\" azure-identity\npoetry add \"azure-mgmt-frontdoor==1.2.0\" azure-identity\n```\n\n## Authentication And Setup\n\nFor most code, start with `DefaultAzureCredential()`. For local scripts, `AzureCliCredential()` is also reasonable after `az login`.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.frontdoor import FrontDoorManagementClient\n\nclient = FrontDoorManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nLocal CLI-driven setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.frontdoor import FrontDoorManagementClient\n\nclient = FrontDoorManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## Core Operations\n\nThe main operation groups most projects need are:\n\n- `front_doors`\n- `frontend_endpoints`\n- `policies`\n- `managed_rule_sets`\n- `front_door_name_availability`\n- `front_door_name_availability_with_subscription`\n\n### Check whether a Front Door name is globally available\n\nFront Door names are globally unique. The REST docs define the request body as `name` plus `type`, and the Python SDK exposes that through `front_door_name_availability_with_subscription.check(...)`.\n\n```python\nresult = client.front_door_name_availability_with_subscription.check(\n    {\n        \"name\": \"my-front-door\",\n        \"type\": \"Microsoft.Network/frontDoors\",\n    }\n)\n\nprint(result.name_availability)\nprint(result.reason)\nprint(result.message)\n```\n\n### List Front Doors in a resource group\n\n```python\nfor front_door in client.front_doors.list_by_resource_group(\"rg-edge\"):\n    print(front_door.name, front_door.resource_state, front_door.cname)\n```\n\n### Get one Front Door\n\n```python\nfront_door = client.front_doors.get(\n    resource_group_name=\"rg-edge\",\n    front_door_name=\"my-front-door\",\n)\n\nprint(front_door.id)\nprint(front_door.cname)\nprint(front_door.provisioning_state)\n```\n\n### Create or update a Front Door\n\nThis is the minimum practical shape for a Front Door with one frontend endpoint, one backend pool, one health probe, one load-balancing profile, and one routing rule.\n\n```python\nresource_group_name = \"rg-edge\"\nfront_door_name = \"my-front-door\"\nlocation = \"westus2\"\nbackend_host = \"origin.contoso.com\"\n\nfront_door_id = (\n    f\"/subscriptions/{os.environ['AZURE_SUBSCRIPTION_ID']}\"\n    f\"/resourceGroups/{resource_group_name}\"\n    f\"/providers/Microsoft.Network/frontDoors/{front_door_name}\"\n)\nfrontend_endpoint_id = f\"{front_door_id}/frontendEndpoints/default\"\nbackend_pool_id = f\"{front_door_id}/backendPools/app-backends\"\nhealth_probe_id = f\"{front_door_id}/healthProbeSettings/probe-default\"\nload_balancing_id = f\"{front_door_id}/loadBalancingSettings/lb-default\"\n\nfront_door = client.front_doors.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    front_door_name=front_door_name,\n    front_door_parameters={\n        \"location\": location,\n        \"properties\": {\n            \"friendlyName\": front_door_name,\n            \"enabledState\": \"Enabled\",\n            \"loadBalancingSettings\": [\n                {\n                    \"name\": \"lb-default\",\n                    \"properties\": {\n                        \"sampleSize\": 4,\n                        \"successfulSamplesRequired\": 2,\n                    },\n                }\n            ],\n            \"healthProbeSettings\": [\n                {\n                    \"name\": \"probe-default\",\n                    \"properties\": {\n                        \"path\": \"/\",\n                        \"protocol\": \"Https\",\n                        \"intervalInSeconds\": 120,\n                        \"healthProbeMethod\": \"HEAD\",\n                        \"enabledState\": \"Enabled\",\n                    },\n                }\n            ],\n            \"backendPools\": [\n                {\n                    \"name\": \"app-backends\",\n                    \"properties\": {\n                        \"backends\": [\n                            {\n                                \"address\": backend_host,\n                                \"backendHostHeader\": backend_host,\n                                \"httpPort\": 80,\n                                \"httpsPort\": 443,\n                                \"enabledState\": \"Enabled\",\n                                \"priority\": 1,\n                                \"weight\": 100,\n                            }\n                        ],\n                        \"loadBalancingSettings\": {\"id\": load_balancing_id},\n                        \"healthProbeSettings\": {\"id\": health_probe_id},\n                    },\n                }\n            ],\n            \"frontendEndpoints\": [\n                {\n                    \"name\": \"default\",\n                    \"properties\": {\n                        \"hostName\": f\"{front_door_name}.azurefd.net\",\n                    },\n                }\n            ],\n            \"routingRules\": [\n                {\n                    \"name\": \"route-all\",\n                    \"properties\": {\n                        \"frontendEndpoints\": [{\"id\": frontend_endpoint_id}],\n                        \"acceptedProtocols\": [\"Http\", \"Https\"],\n                        \"patternsToMatch\": [\"/*\"],\n                        \"routeConfiguration\": {\n                            \"@odata.type\": \"#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration\",\n                            \"forwardingProtocol\": \"MatchRequest\",\n                            \"backendPool\": {\"id\": backend_pool_id},\n                        },\n                        \"enabledState\": \"Enabled\",\n                    },\n                }\n            ],\n            \"backendPoolsSettings\": {\n                \"enforceCertificateNameCheck\": \"Enabled\",\n                \"sendRecvTimeoutSeconds\": 60,\n            },\n        },\n    },\n).result()\n\nprint(front_door.id)\nprint(front_door.cname)\n```\n\n### Validate custom-domain DNS mapping before attaching it\n\n`validate_custom_domain` checks whether a hostname maps to the correct Front Door endpoint in DNS.\n\n```python\nvalidation = client.front_doors.validate_custom_domain(\n    resource_group_name=\"rg-edge\",\n    front_door_name=\"my-front-door\",\n    custom_domain_properties={\n        \"hostName\": \"www.contoso.com\",\n    },\n)\n\nprint(validation.custom_domain_validated)\nprint(validation.reason)\nprint(validation.message)\n```\n\n### Discover managed WAF rule sets\n\nUse this before creating a policy so you know which managed rule set types and versions the service exposes in your environment.\n\n```python\nfor rule_set in client.managed_rule_sets.list():\n    print(rule_set.rule_set_type, rule_set.rule_set_version)\n```\n\n### Create a Front Door WAF policy\n\nThe SDK exposes WAF policy management under `client.policies`. `WebApplicationFirewallPolicy` defaults to `Classic_AzureFrontDoor` if you omit `sku`, but setting it explicitly makes the intended target clear.\n\n```python\npolicy = client.policies.begin_create_or_update(\n    resource_group_name=\"rg-edge\",\n    policy_name=\"edge-waf\",\n    parameters={\n        \"location\": \"westus2\",\n        \"sku\": {\"name\": \"Classic_AzureFrontDoor\"},\n        \"properties\": {\n            \"policySettings\": {\n                \"enabledState\": \"Enabled\",\n                \"mode\": \"Prevention\",\n                \"requestBodyCheck\": \"Enabled\",\n            },\n            \"managedRules\": {\n                \"managedRuleSets\": [\n                    {\n                        \"ruleSetType\": \"DefaultRuleSet\",\n                        \"ruleSetVersion\": \"1.0\",\n                        \"ruleSetAction\": \"Block\",\n                    }\n                ]\n            },\n        },\n    },\n).result()\n\nprint(policy.id)\nprint(policy.resource_state)\n```\n\nTo associate a WAF policy with a Front Door host or route, set `webApplicationFirewallPolicyLink.id` on a frontend endpoint or routing rule in the Front Door payload.\n\n## Common Pitfalls\n\n- This client manages ARM resources at `https://management.azure.com`; it is not the runtime surface for request forwarding or cache behavior at the edge.\n- `begin_create_or_update`, `begin_delete`, and other `begin_*` methods return pollers. Call `.result()` before assuming the resource exists.\n- Front Door names are globally unique, and `validate_custom_domain` only checks DNS mapping. Custom HTTPS is a separate `frontend_endpoints.begin_enable_https(...)` workflow.\n- `managed_rule_sets.list()` gives you the available managed rule set definitions; use those values when filling `ruleSetType` and `ruleSetVersion` in WAF policies.\n- The Front Door REST docs for this SDK family use `Microsoft.Network/frontDoors`. Azure Front Door Standard/Premium profile management is documented separately under `Microsoft.Cdn/profiles`, so do not assume those profile-style APIs live under this client.\n\n## Version-Sensitive Notes For `1.2.0`\n\n- PyPI lists `azure-mgmt-frontdoor 1.2.0` as the current release, published on April 15, 2024.\n- The `1.2.0` release adds `CustomRule.group_by`, plus `PolicySettings.javascript_challenge_expiration_in_minutes`, `PolicySettings.scrubbing_rules`, and `PolicySettings.state`.\n- PyPI metadata for `1.2.0` lists Python `>=3.8`, while the current Azure SDK for Python repository states that client libraries are supported on Python 3.9 or later. If you are standardizing a new environment, verify your interpreter policy before pinning this package.\n\n## Official Sources\n\n- Microsoft Learn package docs: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/\n- `FrontDoorManagementClient`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.frontdoormanagementclient?view=azure-python\n- `FrontDoorsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.operations.frontdoorsoperations?view=azure-python\n- Models package: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models?view=azure-python\n- `FrontDoor`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.frontdoor?view=azure-python\n- `RoutingRule`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.routingrule?view=azure-python\n- `ForwardingConfiguration`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.forwardingconfiguration?view=azure-python\n- `BackendPool`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.backendpool?view=azure-python\n- `Backend`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.backend?view=azure-python\n- `HealthProbeSettingsModel`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.healthprobesettingsmodel?view=azure-python\n- `LoadBalancingSettingsModel`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.loadbalancingsettingsmodel?view=azure-python\n- `FrontendEndpoint`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.frontendendpoint?view=azure-python\n- `PoliciesOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.operations.policiesoperations?view=azure-python\n- `WebApplicationFirewallPolicy`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.webapplicationfirewallpolicy?view=azure-python\n- `PolicySettings`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.policysettings?view=azure-python\n- `ManagedRuleSetsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.operations.managedrulesetsoperations?view=azure-python\n- `ManagedRuleSetDefinition`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.managedrulesetdefinition?view=azure-python\n- `ManagedRuleSet`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-frontdoor/azure.mgmt.frontdoor.models.managedruleset?view=azure-python\n- Front Door create/update REST reference: https://learn.microsoft.com/en-us/rest/api/frontdoor/frontdoor/front-doors/create-or-update\n- Front Door validate custom domain REST reference: https://learn.microsoft.com/en-us/rest/api/frontdoor/frontdoor/front-doors/validate-custom-domain\n- Front Door WAF policy create/update REST reference: https://learn.microsoft.com/en-us/rest/api/frontdoor/webapplicationfirewall/policies/create-or-update\n- Front Door name availability REST reference: https://learn.microsoft.com/en-us/rest/api/frontdoorservice/webapplicationfirewall/check-front-door-name-availability-with-subscription/check-front-door-name-availability-with-subscription?view=rest-frontdoorservice-webapplicationfirewall-2020-04-01\n- Azure Front Door Standard/Premium profiles REST reference: https://learn.microsoft.com/en-us/rest/api/frontdoor/azurefrontdoorstandardpremium/afd-profiles/list-by-resource-group\n- PyPI package page and release history: https://pypi.org/project/azure-mgmt-frontdoor/\n- Azure SDK for Python repository: https://github.com/Azure/azure-sdk-for-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-hdinsight/python/DOC.md",
    "content": "---\nname: mgmt-hdinsight\ndescription: \"Azure HDInsight management SDK for Python for cluster lifecycle, script actions, tagging, and private endpoint operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,hdinsight,arm,management,spark,hadoop,private-link\"\n---\n\n# Azure HDInsight Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-hdinsight` for Azure Resource Manager management-plane operations only: create and delete HDInsight clusters, inspect cluster state, patch tags, run script actions, and manage private endpoint or private link resources. Install `azure-identity` with it, authenticate with a `TokenCredential`, pass the subscription ID explicitly, and expect most write operations to be `begin_*` long-running operations that need `.result()`.\n\nThe Learn HDInsight overview page still shows older `azure.common.credentials.ServicePrincipalCredentials` examples and non-`begin_*` calls such as `client.clusters.create(...)`. Those are pre-8.x patterns. For `9.0.0`, the current client docs and PyPI release notes use `azure-identity`, a `credential=` constructor argument, and `begin_*` pollers.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-hdinsight==9.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-hdinsight==9.0.0\" azure-identity\npoetry add \"azure-mgmt-hdinsight==9.0.0\" azure-identity\n```\n\nIf this subscription has never used HDInsight before, register the resource provider once:\n\n```bash\naz provider register --namespace Microsoft.HDInsight\n```\n\n## Authentication And Setup\n\nFor most projects, use one of these patterns:\n\n- `DefaultAzureCredential()` for reusable code that should work locally, in CI, and on Azure\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you want `DefaultAzureCredential` to use a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.hdinsight import HDInsightManagementClient\n\ncredential = DefaultAzureCredential()\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = HDInsightManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.hdinsight import HDInsightManagementClient\n\nclient = HDInsightManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe package also exposes an async client at `azure.mgmt.hdinsight.aio.HDInsightManagementClient` if the rest of your application is already async.\n\n## Core Operation Groups\n\n`HDInsightManagementClient` exposes these operation groups in `9.0.0`:\n\n- `clusters`\n- `applications`\n- `locations`\n- `configurations`\n- `extensions`\n- `script_actions`\n- `script_execution_history`\n- `virtual_machines`\n- `private_endpoint_connections`\n- `private_link_resources`\n\nThe most common workflows are under `client.clusters`, plus `locations` for preflight checks and the script/private-link groups for post-create management.\n\n## Common Workflows\n\n### Inspect regional capabilities before you build a cluster\n\nCluster creation is region-sensitive. Use the location APIs before you hard-code an HDInsight version or VM size:\n\n```python\ncapabilities = client.locations.get_capabilities(\"eastus\")\nusages = client.locations.list_usages(\"eastus\")\n\nprint(capabilities)\nprint(usages)\n```\n\nUse `client.locations.check_name_availability(...)` before choosing a cluster name and `client.locations.validate_cluster_create_request(...)` before submitting a large create payload.\n\n### Create a Spark cluster\n\nThis package creates Azure resources through ARM. You still need supporting resources such as a resource group and default storage account first.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.hdinsight import HDInsightManagementClient\nfrom azure.mgmt.hdinsight.models import (\n    ClusterCreateParametersExtended,\n    ClusterCreateProperties,\n    ClusterDefinition,\n    ComputeProfile,\n    HardwareProfile,\n    LinuxOperatingSystemProfile,\n    OSType,\n    OsProfile,\n    Role,\n    StorageAccount,\n    StorageProfile,\n    Tier,\n)\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\nclient = HDInsightManagementClient(credential=credential, subscription_id=subscription_id)\n\nresource_group_name = \"example-rg\"\ncluster_name = \"example-hdinsight\"\nlocation = \"eastus\"\n\ncluster_login_username = \"admin\"\ncluster_login_password = \"ReplaceWithAStrongPassword123!\"\nssh_username = \"sshuser\"\nssh_password = \"ReplaceWithAnotherStrongPassword123!\"\n\nstorage_account_name = \"examplestorageacct\"\nstorage_account_key = os.environ[\"HDINSIGHT_STORAGE_ACCOUNT_KEY\"]\nstorage_container = \"hdinsight\"\n\ncreate_parameters = ClusterCreateParametersExtended(\n    location=location,\n    tags={\"env\": \"dev\"},\n    properties=ClusterCreateProperties(\n        # Pick a version supported in this region from client.locations.get_capabilities(...)\n        cluster_version=\"<supported-hdinsight-version>\",\n        os_type=OSType.linux,\n        tier=Tier.standard,\n        cluster_definition=ClusterDefinition(\n            kind=\"Spark\",\n            configurations={\n                \"gateway\": {\n                    \"restAuthCredential.isEnabled\": True,\n                    \"restAuthCredential.username\": cluster_login_username,\n                    \"restAuthCredential.password\": cluster_login_password,\n                }\n            },\n        ),\n        compute_profile=ComputeProfile(\n            roles=[\n                Role(\n                    name=\"headnode\",\n                    target_instance_count=2,\n                    hardware_profile=HardwareProfile(vm_size=\"Standard_D3_V2\"),\n                    os_profile=OsProfile(\n                        linux_operating_system_profile=LinuxOperatingSystemProfile(\n                            username=ssh_username,\n                            password=ssh_password,\n                        )\n                    ),\n                ),\n                Role(\n                    name=\"workernode\",\n                    target_instance_count=3,\n                    hardware_profile=HardwareProfile(vm_size=\"Standard_D3_V2\"),\n                    os_profile=OsProfile(\n                        linux_operating_system_profile=LinuxOperatingSystemProfile(\n                            username=ssh_username,\n                            password=ssh_password,\n                        )\n                    ),\n                ),\n            ]\n        ),\n        storage_profile=StorageProfile(\n            storageaccounts=[\n                StorageAccount(\n                    name=f\"{storage_account_name}.blob.core.windows.net\",\n                    is_default=True,\n                    container=storage_container,\n                    key=storage_account_key,\n                )\n            ]\n        ),\n    ),\n)\n\ncluster = client.clusters.begin_create(\n    resource_group_name=resource_group_name,\n    cluster_name=cluster_name,\n    parameters=create_parameters,\n).result()\n\nprint(cluster.id)\nprint(cluster.location)\n```\n\nPractical notes:\n\n- The create model now requires `location`.\n- Check the regional capability APIs before copying an HDInsight version or VM size from an old example.\n- The default storage account must be in the same Azure region as the cluster.\n- Deleting the cluster does not delete the storage account.\n\n### Get, list, and delete clusters\n\nRead a specific cluster:\n\n```python\ncluster = client.clusters.get(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n)\n\nprint(cluster.name)\nprint(cluster.provisioning_state)\n```\n\nList clusters in a resource group:\n\n```python\nfor item in client.clusters.list_by_resource_group(\"example-rg\"):\n    print(item)\n```\n\nDelete a cluster:\n\n```python\nclient.clusters.begin_delete(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n).result()\n```\n\n### Patch cluster tags\n\n`update(...)` is the patch operation for supported mutable fields such as tags:\n\n```python\nfrom azure.mgmt.hdinsight.models import ClusterPatchParameters\n\nupdated = client.clusters.update(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n    parameters=ClusterPatchParameters(\n        tags={\n            \"env\": \"prod\",\n            \"owner\": \"data-platform\",\n        }\n    ),\n)\n\nprint(updated.tags)\n```\n\n### Run a script action and inspect history\n\nExecute a script action against one or more roles:\n\n```python\nfrom azure.mgmt.hdinsight.models import (\n    ExecuteScriptActionParameters,\n    RuntimeScriptAction,\n)\n\nclient.clusters.begin_execute_script_actions(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n    parameters=ExecuteScriptActionParameters(\n        persist_on_success=True,\n        script_actions=[\n            RuntimeScriptAction(\n                name=\"install-custom-tooling\",\n                uri=\"https://example.blob.core.windows.net/scripts/bootstrap.sh\",\n                roles=[\"headnode\", \"workernode\"],\n                parameters=\"--example true\",\n            )\n        ],\n    ),\n).result()\n```\n\nInspect persisted script actions:\n\n```python\nfor item in client.script_actions.list_by_cluster(\"example-rg\", \"example-hdinsight\"):\n    print(item)\n```\n\nInspect execution history:\n\n```python\nfor item in client.script_execution_history.list_by_cluster(\"example-rg\", \"example-hdinsight\"):\n    print(item)\n```\n\nThe Learn overview samples use role names such as `headnode`, `workernode`, `zookeepernode`, and `edgenode`.\n\n### Inspect private endpoint and private link resources\n\nThese operation groups were added in the `9.0.0` line:\n\n```python\nfor connection in client.private_endpoint_connections.list_by_cluster(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n):\n    print(connection)\n\nresources = client.private_link_resources.list_by_cluster(\n    resource_group_name=\"example-rg\",\n    cluster_name=\"example-hdinsight\",\n)\n\nprint(resources)\n```\n\nYou can also approve or reject a specific private endpoint connection manually with `client.private_endpoint_connections.begin_create_or_update(...)`.\n\n## Configuration Notes\n\n- `HDInsightManagementClient` requires a `TokenCredential` and a `subscription_id`. It does not infer the subscription from Azure CLI state unless you pass the ID yourself.\n- `DefaultAzureCredential` selects a credential based on the environment. If it authenticates unexpectedly, check whether environment variables, Azure CLI login, managed identity, or another source won the chain.\n- Treat cluster creation as a preflight-heavy flow. Use `check_name_availability`, `get_capabilities`, and `validate_cluster_create_request` before firing a long-running create request.\n- HDInsight cluster creation depends on other Azure resources and quota in the target region. Authentication success does not guarantee cluster creation will succeed.\n\n## Version-Sensitive Notes\n\n### `9.0.0`\n\nPyPI lists `9.0.0` as the stable release for this package and also shows newer `9.1.0b1` and `9.1.0b2` prereleases. The `9.0.0` release adds:\n\n- `PrivateLinkResourcesOperations`\n- `PrivateEndpointConnectionsOperations`\n- new `zones` and `system_data` fields on cluster-related models\n- private link configuration fields on cluster models\n\nThe `9.0.0` release also makes `location` required on the tracked cluster models.\n\n### `8.0.0` and later generator changes still matter\n\nThe major SDK behavior change happened in `8.0.0`, and it still defines how `9.0.0` code should look:\n\n- old `azure.common.credentials` objects are no longer supported\n- `credentials=` became `credential=`\n- long-running operations moved to `begin_*`\n- `CloudError`-style handling was replaced by `azure.core.exceptions.HttpResponseError`\n- the package gained official async support under the `aio` namespace\n\nIf you copy a pre-8.x sample from an old blog post or the older HDInsight overview page, update it to the current auth and polling model before using it.\n\n## Common Pitfalls\n\n- Copying the legacy Learn overview auth sample with `ServicePrincipalCredentials` instead of using `azure-identity`\n- Calling `client.clusters.create(...)` or `client.clusters.delete(...)` from older examples instead of the current `begin_*` methods\n- Forgetting to register `Microsoft.HDInsight` in a subscription that has never used the service\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Hard-coding an HDInsight version or VM size without checking `client.locations.get_capabilities(...)` for the target region\n- Assuming cluster deletion also deletes the default storage account\n- Creating the default storage account in a different region than the cluster\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-hdinsight/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.hdinsightmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.clustersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.locationsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.scriptactionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.scriptexecutionhistoryoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.privateendpointconnectionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-hdinsight/azure.mgmt.hdinsight.operations.privatelinkresourcesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python\n- https://learn.microsoft.com/en-us/azure/hdinsight/hdinsight-sdk-python-samples\n- https://learn.microsoft.com/en-us/azure/hdinsight/hdinsight-python-sdk-azure-resource-manager\n- https://learn.microsoft.com/en-us/azure/hdinsight/interactive-query/quickstart-resource-manager-template\n"
  },
  {
    "path": "content/azure/docs/mgmt-iothub/python/DOC.md",
    "content": "---\nname: mgmt-iothub\ndescription: \"Azure IoT Hub management-plane SDK for Python for hub provisioning, ARM updates, consumer groups, and certificate management\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,iot-hub,arm,management,python,certificates\"\n---\n\n# Azure IoT Hub Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-iothub` for Azure Resource Manager control-plane work on IoT Hub resources: create hubs, read hub metadata, update tags, manage Event Hub-compatible consumer groups, manage certificates, and inspect quotas or stats.\n\nDo not use it for device telemetry, device twins, or device-side connectivity. This client talks to the ARM management endpoint, not the IoT Hub device/service data plane.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-iothub==4.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-iothub==4.0.0\" azure-identity\npoetry add \"azure-mgmt-iothub==4.0.0\" azure-identity\n```\n\nPyPI currently lists Python `>=3.8` for `4.0.0`.\n\n## Authentication And Setup\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you use a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, Azure CLI is usually simpler:\n\n```bash\naz login\naz account set --subscription \"$AZURE_SUBSCRIPTION_ID\"\n```\n\nCreate the client with `DefaultAzureCredential`:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.iothub import IotHubClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = IotHubClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nIf you want a local-script-only credential:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.iothub import IotHubClient\n\nclient = IotHubClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n`IotHubClient` defaults to API version `2023-06-30`. The client also exposes `api_version` and `profile` parameters because the package contains multiple API versions for different Azure clouds. For production, Microsoft recommends sticking to a particular API version and/or profile instead of relying on an implicit default forever.\n\n## Core Workflows\n\n### Check name availability before create\n\nIoT Hub names must be available at the subscription/resource-provider level. Check first instead of waiting for a failed create call:\n\n```python\nhub_name = \"ctxhub-iothub-demo\"\n\navailability = client.iot_hub_resource.check_name_availability(\n    {\"name\": hub_name}\n)\n\nif not availability.name_available:\n    raise RuntimeError(f\"{hub_name} is unavailable: {availability.reason} {availability.message}\")\n```\n\n### Create a hub\n\nCreating or deleting a hub is a long-running ARM operation, so wait on the poller:\n\n```python\nresource_group_name = \"example-rg\"\nhub_name = \"ctxhub-iothub-demo\"\n\npoller = client.iot_hub_resource.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    resource_name=hub_name,\n    iot_hub_description={\n        \"location\": \"westus2\",\n        \"sku\": {\n            \"name\": \"S1\",\n            \"capacity\": 1,\n        },\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    },\n)\n\nhub = poller.result()\nprint(hub.id)\nprint(hub.name)\nprint(hub.sku.name)\n```\n\n### List hubs and read one hub\n\n```python\nfor hub in client.iot_hub_resource.list_by_resource_group(\"example-rg\"):\n    print(hub.name, hub.location)\n\nhub = client.iot_hub_resource.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n)\n\nprint(hub.name)\nprint(hub.location)\nprint(hub.etag)\n```\n\n### Update tags\n\nUse `begin_update()` for tag-only changes:\n\n```python\nupdated = client.iot_hub_resource.begin_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    iot_hub_tags={\n        \"tags\": {\n            \"env\": \"prod\",\n            \"owner\": \"platform\",\n        }\n    },\n).result()\n\nprint(updated.tags)\n```\n\nFor non-tag changes, use `begin_create_or_update()` instead. Microsoft explicitly warns that when you update an existing hub with `create_or_update`, missing JSON properties can fall back to defaults, so build the request from the full current description and send `if_match=hub.etag`.\n\n### Manage Event Hub-compatible consumer groups\n\nThe built-in Event Hub-compatible endpoint is usually named `events`:\n\n```python\nconsumer_group = client.iot_hub_resource.create_event_hub_consumer_group(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    event_hub_endpoint_name=\"events\",\n    name=\"analytics\",\n    consumer_group_body={\n        \"properties\": {\n            \"name\": \"analytics\",\n        }\n    },\n)\n\nprint(consumer_group.name)\n\nfor group in client.iot_hub_resource.list_event_hub_consumer_groups(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    event_hub_endpoint_name=\"events\",\n):\n    print(group.name)\n```\n\nDelete the consumer group when you no longer need it:\n\n```python\nclient.iot_hub_resource.delete_event_hub_consumer_group(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    event_hub_endpoint_name=\"events\",\n    name=\"analytics\",\n)\n```\n\n### Upload and verify an X.509 CA certificate\n\nCertificate workflows are ETag-sensitive. Upload the certificate, generate a verification code, create the proof-of-possession leaf certificate outside this SDK, then call `verify()` with the latest ETag.\n\n```python\nfrom pathlib import Path\n\ncertificate_name = \"device-ca\"\n\ncertificate = client.certificates.create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    certificate_name=certificate_name,\n    certificate_description={\n        \"properties\": {\n            \"certificate\": Path(\"ca-cert.pem\").read_text(),\n        }\n    },\n)\n\nclient.certificates.generate_verification_code(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    certificate_name=certificate_name,\n    if_match=certificate.etag,\n)\n\nfresh_certificate = client.certificates.get(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    certificate_name=certificate_name,\n)\n\nverified = client.certificates.verify(\n    resource_group_name=\"example-rg\",\n    resource_name=\"ctxhub-iothub-demo\",\n    certificate_name=certificate_name,\n    if_match=fresh_certificate.etag,\n    certificate_verification_body={\n        \"certificate\": Path(\"verification-cert.pem\").read_text(),\n    },\n)\n\nprint(verified.etag)\n```\n\n## Other Useful Operations\n\nThe client also exposes these high-value management calls:\n\n- `client.resource_provider_common.get_subscription_quota()` to inspect free and paid IoT Hub quota usage in the subscription\n- `client.iot_hub_resource.get_stats(...)` for hub-level statistics\n- `client.iot_hub_resource.get_quota_metrics(...)` for quota metrics on a specific hub\n- `client.iot_hub_resource.get_valid_skus(...)` to see which SKUs are valid for a hub\n- `client.iot_hub_resource.list_keys(...)` and `get_keys_for_key_name(...)` for shared access policy metadata\n\n## Common Pitfalls\n\n- `azure-mgmt-iothub` is a management-plane SDK. If you need device registry operations, telemetry send/receive, twins, or direct methods, this is the wrong client.\n- `AZURE_SUBSCRIPTION_ID` is required. A credential can authenticate successfully while client construction still fails without a subscription ID.\n- `begin_create_or_update()`, `begin_update()`, and `begin_delete()` return ARM pollers. Call `.result()` when the next step depends on completion.\n- `begin_update()` is for tags only. For other hub changes, use `begin_create_or_update()`.\n- When updating an existing hub with `begin_create_or_update()`, do not send a partial body unless you are sure of every omitted field. The official docs warn omitted properties may revert to defaults.\n- Certificate update and verify flows require the current certificate ETag. Re-read the certificate if you are unsure which ETag is current.\n- Consumer groups are scoped under the Event Hub-compatible endpoint name, not just the hub name.\n\n## Version-Sensitive Notes For `4.0.0`\n\n- PyPI lists `4.0.0` as the current stable release, published on April 9, 2025.\n- The `4.0.0` release notes say the package removed subfolders for some unused API versions to reduce package size. If your application depends on a specific non-latest API version, pin the previous package release instead of assuming `4.0.0` still ships that folder.\n- The current client docs show `DEFAULT_API_VERSION = \"2023-06-30\"`.\n- The package docs still describe multi-API support through `api_version` and `profile`, which matters for Azure Stack and sovereign cloud scenarios.\n\n## Official Sources\n\n- https://pypi.org/project/azure-mgmt-iothub/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/iot-hub?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-iothub/azure.mgmt.iothub.iothubclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-iothub/azure.mgmt.iothub.operations.iothubresourceoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-iothub/azure.mgmt.iothub.operations.certificatesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/rest/api/iothub/iot-hub-resource/check-name-availability?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/iot-hub-resource/create-or-update?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/iot-hub-resource/update?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/iot-hub-resource/create-event-hub-consumer-group?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/certificates/create-or-update?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/certificates/generate-verification-code?view=rest-iothub-2023-06-30\n- https://learn.microsoft.com/en-us/rest/api/iothub/certificates/verify?view=rest-iothub-2023-06-30\n"
  },
  {
    "path": "content/azure/docs/mgmt-keyvault/python/DOC.md",
    "content": "---\nname: mgmt-keyvault\ndescription: \"Azure Key Vault management-plane SDK for Python for creating, updating, listing, deleting, and purging vault resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,key-vault,arm,management,rbac,azure-identity\"\n---\n\n# Azure Key Vault Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-keyvault` only for Azure Resource Manager control-plane work such as creating or updating vault resources, listing them, managing deleted-vault lifecycle, and configuring management properties. For data-plane work inside an existing vault, use `azure-keyvault-secrets`, `azure-keyvault-keys`, or `azure-keyvault-certificates` instead. Pair this package with `azure-identity`, and prefer JSON/dict request bodies over direct model construction when adapting older samples because `13.0.0` introduced hybrid models.\n\n## Install\n\nInstall the management client and an Azure credential package together:\n\n```bash\npython -m pip install \"azure-mgmt-keyvault==13.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-keyvault==13.0.0\" azure-identity\npoetry add \"azure-mgmt-keyvault==13.0.0\" azure-identity\n```\n\nIf you will use async clients, install an async transport too:\n\n```bash\npython -m pip install \"azure-mgmt-keyvault==13.0.0\" azure-identity aiohttp\n```\n\n## Authentication And Setup\n\nThe package README and Azure authentication guidance both point to Microsoft Entra token auth. In practice:\n\n- Local development: sign in with `az login`, then use `DefaultAzureCredential()` or `AzureCliCredential()`\n- CI or other non-interactive environments: use a service principal\n- Azure-hosted workloads: prefer managed identity\n\nRequired configuration:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly:\n\n```bash\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.keyvault import KeyVaultManagementClient\n\nclient = KeyVaultManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nSovereign cloud note: `KeyVaultManagementClient` in current docs accepts `cloud_setting=...` if you need a non-public Azure ARM endpoint.\n\n## Core Usage\n\nThe current client surface exposes these main operation groups:\n\n- `vaults`\n- `managed_hsms`\n- `private_endpoint_connections`\n- `private_link_resources`\n- `operations`\n\n`vaults` is the main entry point for ordinary Key Vault resource management.\n\n### Create Or Update A Vault\n\n`begin_create_or_update(...)` is a long-running ARM operation and returns a poller. Passing a plain dictionary keeps the request shape explicit and avoids most hybrid-model surprises.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.keyvault import KeyVaultManagementClient\n\nclient = KeyVaultManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.vaults.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    vault_name=\"example-kv-1234\",\n    parameters={\n        \"location\": \"eastus\",\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n        \"properties\": {\n            \"tenant_id\": os.environ[\"AZURE_TENANT_ID\"],\n            \"sku\": {\n                \"family\": \"A\",\n                \"name\": \"standard\",\n            },\n            \"access_policies\": [],\n            \"enable_rbac_authorization\": True,\n            \"enable_soft_delete\": True,\n            \"soft_delete_retention_in_days\": 90,\n            \"public_network_access\": \"Enabled\",\n        },\n    },\n)\n\nvault = poller.result()\nprint(vault.id)\nprint(vault.properties.vault_uri)\n```\n\nImportant details from the model docs:\n\n- `tenant_id` is required\n- `access_policies` are required unless `createMode` is recovery; for RBAC-enabled vaults, an empty list is the usual shape\n- `enable_rbac_authorization=True` affects data-action authorization, but management actions are always RBAC-based\n- `soft_delete_retention_in_days` must be between `7` and `90`\n\n### List And Inspect Vaults\n\n```python\nfor vault in client.vaults.list_by_resource_group(\"example-rg\"):\n    print(vault.name, vault.location, vault.properties.vault_uri)\n\ncurrent = client.vaults.get(\"example-rg\", \"example-kv-1234\")\nprint(current.properties.enable_rbac_authorization)\nprint(current.properties.public_network_access)\n```\n\nUse `list_by_resource_group(...)` when you already know the resource group and `list_by_subscription()` when you need a subscription-wide inventory.\n\n### Check Name Availability Before Create\n\n```python\nresult = client.vaults.check_name_availability(\n    {\n        \"name\": \"example-kv-1234\",\n        \"type\": \"Microsoft.KeyVault/vaults\",\n    }\n)\n\nprint(result.name_available)\nprint(result.reason)\n```\n\n`13.0.0` added the `type` property on `VaultCheckNameAvailabilityParameters`, so older examples that omit it may be incomplete.\n\n### Update Vault Properties\n\nUse `update(...)` for partial changes instead of recreating the whole resource:\n\n```python\nupdated = client.vaults.update(\n    resource_group_name=\"example-rg\",\n    vault_name=\"example-kv-1234\",\n    parameters={\n        \"tags\": {\n            \"env\": \"prod\",\n            \"owner\": \"platform\",\n        },\n        \"properties\": {\n            \"public_network_access\": \"Disabled\",\n        },\n    },\n)\n\nprint(updated.tags)\nprint(updated.properties.public_network_access)\n```\n\n### Delete, List Deleted, And Purge\n\nDelete and purge are separate steps when soft delete is enabled:\n\n```python\nclient.vaults.delete(\"example-rg\", \"example-kv-1234\")\n\nfor deleted in client.vaults.list_deleted():\n    print(deleted.name, deleted.properties.scheduled_purge_date)\n\npurge_poller = client.vaults.begin_purge_deleted(\n    vault_name=\"example-kv-1234\",\n    location=\"eastus\",\n)\npurge_poller.result()\n```\n\n`get_deleted(...)` and `begin_purge_deleted(...)` both need the vault's Azure region. Keep that location in your cleanup code instead of assuming you can derive it later.\n\n## Configuration Notes\n\n- `subscription_id` is required; the client does not infer it from the credential.\n- The current client default API version is `2025-05-01`. The docs explicitly warn that overriding `api_version` may result in unsupported behavior.\n- Reuse a long-lived client in scripts or services instead of constructing one per operation.\n- For non-public Azure clouds, align your credential authority host and the client's `cloud_setting`.\n- `send_request(...)` exists in `13.0.0` for custom raw requests through the same pipeline, but use the typed operation groups first.\n\n## Async Usage\n\nUse the async client only if the rest of the application is already asyncio-based:\n\n```python\nimport asyncio\nimport os\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.mgmt.keyvault.aio import KeyVaultManagementClient\n\nasync def main() -> None:\n    async with DefaultAzureCredential() as credential:\n        client = KeyVaultManagementClient(\n            credential=credential,\n            subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n        )\n        try:\n            async for vault in client.vaults.list_by_subscription():\n                print(vault.name)\n        finally:\n            await client.close()\n\nasyncio.run(main())\n```\n\nClose both the client and the async credential to avoid leaving transports open.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-keyvault` for secret or key CRUD inside a vault. That is data-plane work and belongs to the `azure-keyvault-*` packages.\n- Installing only `azure-mgmt-keyvault` and forgetting `azure-identity`.\n- Forgetting `AZURE_SUBSCRIPTION_ID`; ARM management clients need it even when auth is otherwise correct.\n- Treating `begin_create_or_update(...)` or `begin_purge_deleted(...)` as immediate. They return pollers.\n- Mixing older access-policy examples with `13.0.0` model code. `Permissions.keys` became `Permissions.keys_property` in this release.\n- Assuming `enable_rbac_authorization=True` removes all management RBAC requirements. It only changes data-action authorization inside the vault.\n- Overriding `api_version` to match an old sample after `12.0.0`. Current packages target the latest API version only.\n\n## Version-Sensitive Notes For `13.0.0`\n\n- `13.0.0` adds `send_request(...)` on `KeyVaultManagementClient`.\n- `13.0.0` introduces hybrid models. If old constructor-based examples behave strangely, prefer JSON/dict payloads or re-check the current model docs.\n- `13.0.0` renamed the `Permissions` instance variable `keys` to `keys_property`.\n- `12.0.0` was the major release that removed support for older API-version folders and kept only the latest service API. If your code depends on an older non-latest ARM API shape, pin an older package and use the matching docs.\n\n## Official Sources Used\n\n- `https://pypi.org/project/azure-mgmt-keyvault/`\n- `https://learn.microsoft.com/en-us/python/api/azure-mgmt-keyvault/`\n- `https://learn.microsoft.com/en-us/python/api/azure-mgmt-keyvault/azure.mgmt.keyvault.keyvaultmanagementclient?view=azure-python`\n- `https://learn.microsoft.com/en-us/python/api/azure-mgmt-keyvault/azure.mgmt.keyvault.operations.vaultsoperations?view=azure-python`\n- `https://learn.microsoft.com/en-us/python/api/azure-mgmt-keyvault/azure.mgmt.keyvault.models.vaultproperties?view=azure-python`\n- `https://learn.microsoft.com/en-us/python/api/overview/azure/key-vault?view=azure-python`\n- `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview`\n"
  },
  {
    "path": "content/azure/docs/mgmt-kusto/python/DOC.md",
    "content": "---\nname: mgmt-kusto\ndescription: \"Azure Data Explorer management SDK for Python for clusters, databases, data connections, and principal assignments\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,kusto,data-explorer,management,arm,python\"\n---\n\n# Azure Data Explorer Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-kusto` for Azure Resource Manager work against Azure Data Explorer: creating clusters, managing databases, wiring data connections, and assigning cluster or database principals. Do not use it for KQL queries or application-side ingestion. Microsoft documents `azure-kusto-data` and `azure-kusto-ingest` as the Python packages for those data-plane tasks.\n\n## Install\n\n`azure-mgmt-kusto 3.4.0` on PyPI requires Python 3.8+.\n\n```bash\npython -m pip install \"azure-mgmt-kusto==3.4.0\" azure-identity\n```\n\nYou also need:\n\n- an Azure subscription\n- permission to manage `Microsoft.Kusto/*` resources in the target resource group or subscription\n\n## Authentication And Setup\n\n`KustoManagementClient` needs a `TokenCredential` and a subscription ID. `DefaultAzureCredential` is the safe default for scripts and services because it can use environment credentials, managed identity, or local developer credentials such as Azure CLI.\n\nSet the values your deployment actually uses:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n\nexport AZURE_RESOURCE_GROUP=\"rg-kusto-demo\"\nexport AZURE_LOCATION=\"eastus\"\nexport AZURE_KUSTO_CLUSTER=\"adx-demo-cluster\"\nexport AZURE_KUSTO_DATABASE=\"appdb\"\n```\n\nClient setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.kusto import KustoManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nresource_group = os.environ[\"AZURE_RESOURCE_GROUP\"]\nlocation = os.environ[\"AZURE_LOCATION\"]\ncluster_name = os.environ[\"AZURE_KUSTO_CLUSTER\"]\ndatabase_name = os.environ[\"AZURE_KUSTO_DATABASE\"]\n\ncredential = DefaultAzureCredential()\nclient = KustoManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nImportant operation groups on the client:\n\n- `client.clusters`\n- `client.databases`\n- `client.data_connections`\n- `client.database_principal_assignments`\n- `client.cluster_principal_assignments`\n- `client.scripts`\n- `client.attached_database_configurations`\n\nWhen you are done with a long-lived script or worker, close the client:\n\n```python\nclient.close()\n```\n\n## Common Workflows\n\n### Create a cluster\n\nCluster creation is a long-running ARM operation. Call `.result()` on the poller before assuming the cluster exists.\n\n```python\nfrom azure.mgmt.kusto.models import AzureSku, Cluster\n\npoller = client.clusters.begin_create_or_update(\n    resource_group_name=resource_group,\n    cluster_name=cluster_name,\n    parameters=Cluster(\n        location=location,\n        sku=AzureSku(\n            name=\"Standard_D13_v2\",\n            tier=\"Standard\",\n            capacity=2,\n        ),\n        enable_streaming_ingest=True,\n        public_network_access=\"Enabled\",\n    ),\n    if_none_match=\"*\",\n)\n\ncluster = poller.result()\n\nprint(cluster.id)\nprint(cluster.uri)\nprint(cluster.data_ingestion_uri)\n```\n\nThe SKU name and tier must match a supported Kusto SKU. If you are provisioning dynamically, inspect `client.clusters.list_skus()` instead of guessing from generic VM names.\n\n### List, get, stop, and start clusters\n\n```python\nfor cluster in client.clusters.list_by_resource_group(resource_group):\n    print(cluster.name, cluster.location, cluster.state)\n\ncluster = client.clusters.get(resource_group, cluster_name)\nprint(cluster.uri)\n\nclient.clusters.begin_stop(resource_group, cluster_name).result()\nclient.clusters.begin_start(resource_group, cluster_name).result()\n```\n\n### Create a read-write database\n\n`ReadWriteDatabase` uses Python `timedelta` objects for retention and cache periods.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.mgmt.kusto.models import ReadWriteDatabase\n\ndatabase = client.databases.begin_create_or_update(\n    resource_group_name=resource_group,\n    cluster_name=cluster_name,\n    database_name=database_name,\n    parameters=ReadWriteDatabase(\n        location=location,\n        soft_delete_period=timedelta(days=365),\n        hot_cache_period=timedelta(days=7),\n    ),\n).result()\n\nprint(database.name, database.kind, database.provisioning_state)\n```\n\nList databases on a cluster:\n\n```python\nfor db in client.databases.list_by_cluster(resource_group, cluster_name):\n    print(db.name, db.kind)\n```\n\n### Add an Event Hub data connection\n\nUse a data connection when the cluster should ingest from Azure Event Hubs. The `event_hub_resource_id` is the ARM resource ID of the Event Hub. `managed_identity_resource_id` is the system-assigned or user-assigned managed identity resource ID that Kusto should use to authenticate to Event Hubs.\n\n```bash\nexport AZURE_EVENTHUB_RESOURCE_ID=\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-messaging/providers/Microsoft.EventHub/namespaces/ns-demo/eventhubs/orders\"\nexport AZURE_EVENTHUB_MANAGED_IDENTITY_RESOURCE_ID=\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-kusto-demo/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adx-eh-reader\"\n```\n\n```python\nfrom datetime import datetime, timezone\n\nfrom azure.mgmt.kusto.models import EventHubDataConnection\n\nconnection = client.data_connections.begin_create_or_update(\n    resource_group_name=resource_group,\n    cluster_name=cluster_name,\n    database_name=database_name,\n    data_connection_name=\"orders-eh\",\n    parameters=EventHubDataConnection(\n        location=location,\n        event_hub_resource_id=os.environ[\"AZURE_EVENTHUB_RESOURCE_ID\"],\n        consumer_group=\"$Default\",\n        table_name=\"OrdersRaw\",\n        mapping_rule_name=\"OrdersJsonMapping\",\n        data_format=\"JSON\",\n        managed_identity_resource_id=os.environ[\"AZURE_EVENTHUB_MANAGED_IDENTITY_RESOURCE_ID\"],\n        retrieval_start_date=datetime.now(timezone.utc),\n    ),\n).result()\n\nprint(connection.name)\n```\n\nList data connections for a database:\n\n```python\nfor item in client.data_connections.list_by_database(\n    resource_group,\n    cluster_name,\n    database_name,\n):\n    print(item.name, item.kind)\n```\n\n### Grant database permissions\n\n`DatabasePrincipalAssignment` is the direct way to grant a role to a user, app, or group at the database scope.\n\n```bash\nexport AZURE_PRINCIPAL_ID=\"analysts@contoso.com\"\nexport AZURE_PRINCIPAL_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\n```python\nfrom azure.mgmt.kusto.models import DatabasePrincipalAssignment\n\nassignment = client.database_principal_assignments.begin_create_or_update(\n    resource_group_name=resource_group,\n    cluster_name=cluster_name,\n    database_name=database_name,\n    principal_assignment_name=\"analysts-viewer\",\n    parameters=DatabasePrincipalAssignment(\n        principal_id=os.environ[\"AZURE_PRINCIPAL_ID\"],\n        tenant_id=os.environ[\"AZURE_PRINCIPAL_TENANT_ID\"],\n        principal_type=\"User\",\n        role=\"Viewer\",\n    ),\n).result()\n\nprint(assignment.name)\n```\n\nFor cluster-wide roles, use `client.cluster_principal_assignments.begin_create_or_update(...)` with `ClusterPrincipalAssignment`. The supported cluster-wide roles in `3.4.0` are `AllDatabasesAdmin`, `AllDatabasesViewer`, and `AllDatabasesMonitor`.\n\n## Important Notes\n\n- `subscription_id` is required. `KustoManagementClient` does not infer it from the credential.\n- `KustoManagementClient` defaults to ARM API version `2024-04-13`. The official docs warn that overriding `api_version` may result in unsupported behavior.\n- Most mutating operations are `begin_*` long-running operations. Always wait on the returned poller with `.result()` when your next step depends on the resource existing.\n- `principal_id` for principal assignments is not restricted to an object GUID. The docs explicitly allow a user email, application ID, or security group name.\n- If you disable `public_network_access`, the cluster is reachable only through private endpoint connectivity. Do not turn it off before your private networking path exists.\n- This package manages ARM resources only. Query execution, control commands, and ingestion from application code belong in `azure-kusto-data` or `azure-kusto-ingest`.\n\n## Version-Sensitive Notes For 3.4.0\n\n- PyPI currently lists `3.4.0` as the latest release for `azure-mgmt-kusto`.\n- `3.4.0` adds cluster callout policy support, including `Cluster.callout_policies`, `ClustersOperations.begin_add_callout_policies`, `begin_remove_callout_policy`, and `list_callout_policies`.\n- The same `3.4.0` release adds `ClustersOperations.list_follower_databases_get` and new follower database response models. If you need those methods, pin `3.4.0` or newer.\n- `3.2.0` added the separate `client.database` operation group and pagination parameters `top` and `skiptoken` on `client.databases.list_by_cluster`. If you are copying older examples, check whether they predate those APIs.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-kusto/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.kustomanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.operations.clustersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.operations.databasesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.operations.dataconnectionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.operations.databaseprincipalassignmentsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.cluster?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.azuresku?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.readwritedatabase?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.eventhubdataconnection?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.databaseprincipalassignment?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-kusto/azure.mgmt.kusto.models.clusterprincipalassignment?view=azure-python\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview\n- https://learn.microsoft.com/en-us/kusto/api/python/kusto-python-client-library?view=azure-data-explorer&preserve-view=true\n"
  },
  {
    "path": "content/azure/docs/mgmt-loganalytics/python/DOC.md",
    "content": "---\nname: mgmt-loganalytics\ndescription: \"Azure Log Analytics management SDK for Python for workspaces, tables, shared keys, query packs, and purge operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,log-analytics,azure-monitor,management,arm,workspaces,tables,query-packs\"\n---\n\n# Azure Log Analytics Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-loganalytics` for control-plane management of Log Analytics resources through Azure Resource Manager: workspaces, workspace tables, shared keys, query packs, linked services, data exports, and purge operations. Install `azure-identity` with it and pass an explicit Azure subscription ID when you create `LogAnalyticsManagementClient`.\n\nThis guide is pinned to `azure-mgmt-loganalytics 13.1.1`, the current stable PyPI release as of March 13, 2026. PyPI also says this package requires Python 3.9+.\n\n## Install\n\n```bash\npython -m pip install \"azure-mgmt-loganalytics==13.1.1\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-loganalytics==13.1.1\" \"azure-identity\"\npoetry add \"azure-mgmt-loganalytics==13.1.1\" \"azure-identity\"\n```\n\n## Authentication And Setup\n\nFor local development, `DefaultAzureCredential()` usually works best after `az login`.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.loganalytics import LogAnalyticsManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = LogAnalyticsManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor local scripts that should use your Azure CLI session explicitly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.loganalytics import LogAnalyticsManagementClient\n\nclient = LogAnalyticsManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## High-Value Operation Groups\n\nThe current `LogAnalyticsManagementClient` exposes these practical operation groups:\n\n- `workspaces`\n- `tables`\n- `shared_keys`\n- `query_packs`\n- `available_service_tiers`\n- `deleted_workspaces`\n- `workspace_purge`\n- `data_exports`\n- `linked_storage_accounts`\n- `summary_logs`\n\nUse this package when you are provisioning or configuring Log Analytics resources. It is not the package you reach for first when application code needs to run log queries as part of normal request handling.\n\n## Core Usage\n\n### Create or update a workspace\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.loganalytics import LogAnalyticsManagementClient\nfrom azure.mgmt.loganalytics.models import Workspace, WorkspaceSku\n\nresource_group_name = \"example-rg\"\nworkspace_name = \"example-law\"\n\nclient = LogAnalyticsManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nworkspace = client.workspaces.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    workspace_name=workspace_name,\n    parameters=Workspace(\n        location=\"eastus\",\n        sku=WorkspaceSku(name=\"PerGB2018\"),\n        retention_in_days=30,\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n).result()\n\nprint(workspace.id)\nprint(workspace.customer_id)\n```\n\n`begin_create_or_update()` is a long-running operation, so call `.result()` when you need the workspace before continuing.\n\n### List, get, and update a workspace\n\n```python\nfor workspace in client.workspaces.list_by_resource_group(\"example-rg\"):\n    print(workspace.name, workspace.location, workspace.provisioning_state)\n```\n\n```python\nworkspace = client.workspaces.get(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n)\n\nprint(workspace.customer_id)\nprint(workspace.sku.name)\n```\n\n```python\nfrom azure.mgmt.loganalytics.models import WorkspacePatch\n\nupdated = client.workspaces.update(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n    parameters=WorkspacePatch(\n        retention_in_days=60,\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"platform-team\",\n        },\n    ),\n)\n\nprint(updated.retention_in_days)\n```\n\n### Delete a workspace and understand recovery behavior\n\n```python\ndelete_poller = client.workspaces.begin_delete(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n)\ndelete_poller.result()\n```\n\nThe current docs say a normal delete keeps the workspace name reserved for 14 days so the workspace can be recovered by creating it again with the same name, subscription, resource group, and location. Use `force=True` only when you intentionally want permanent deletion with no recovery option.\n\n### Inspect available service tiers\n\n```python\ntiers = client.available_service_tiers.list_by_workspace(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n)\n\nfor tier in tiers:\n    print(tier.name)\n```\n\n### Read and update workspace tables\n\nGet one table:\n\n```python\ntable = client.tables.get(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n    table_name=\"Heartbeat\",\n)\n\nprint(table.name, table.plan, table.retention_in_days)\n```\n\nList tables in a workspace:\n\n```python\npages = client.tables.list_by_workspace(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n)\n\nfor page in pages:\n    for table in page.value:\n        print(table.name, table.plan, table.retention_in_days)\n```\n\nUpdate table retention or plan:\n\n```python\nfrom azure.mgmt.loganalytics.models import Table\n\nupdated_table = client.tables.update(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n    table_name=\"Heartbeat\",\n    parameters=Table(\n        retention_in_days=30,\n        total_retention_in_days=60,\n        plan=\"Analytics\",\n    ),\n)\n\nprint(updated_table.total_retention_in_days)\n```\n\nThe `Table` model documents these important constraints:\n\n- `retention_in_days` for Analytics tables must be between 4 and 730, or `-1` to inherit the workspace retention.\n- `total_retention_in_days` must be between 4 and 4383, or `-1` to inherit `retention_in_days`.\n- `plan` can be `Basic`, `Analytics`, or `Auxiliary`.\n\n### List query packs in a resource group\n\n```python\nfor query_pack in client.query_packs.list_by_resource_group(\"example-rg\"):\n    print(query_pack.name, query_pack.id)\n```\n\nThe SDK also exposes `create_or_update`, `create_or_update_without_name`, `get`, `delete`, and `update_tags` on `client.query_packs`.\n\n### Get workspace shared keys\n\n```python\nkeys = client.shared_keys.get_shared_keys(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n)\n\nprint(keys.primary_shared_key)\nprint(keys.secondary_shared_key)\n```\n\nThe SDK also exposes `client.shared_keys.regenerate(...)`. Treat that as a credential rotation event because existing agents or ingestion pipelines that still use an old shared key will stop authenticating.\n\n### Submit a purge request and poll its status\n\n```python\nfrom azure.mgmt.loganalytics.models import WorkspacePurgeBody, WorkspacePurgeBodyFilters\n\nresponse = client.workspace_purge.purge(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n    body=WorkspacePurgeBody(\n        table=\"Heartbeat\",\n        filters=[\n            WorkspacePurgeBodyFilters(\n                column=\"TimeGenerated\",\n                operator=\">=\",\n                value=\"2026-01-01T00:00:00Z\",\n            )\n        ],\n    ),\n)\n```\n\nThen poll the purge operation with the purge ID returned by that response:\n\n```python\npurge_id = \"<operation-id-from-purge-response>\"\n\nstatus = client.workspace_purge.get_purge_status(\n    resource_group_name=\"example-rg\",\n    workspace_name=\"example-law\",\n    purge_id=purge_id,\n)\n\nprint(status.status)\n```\n\n## Configuration Notes\n\n- `subscription_id` is required. The client constructor does not infer it from the credential.\n- The client constructor documents a default ARM API version of `2025-07-01`. The Learn reference warns that overriding `api_version` may result in unsupported behavior.\n- The `Workspace` model supports `public_network_access_for_ingestion` and `public_network_access_for_query` with `Enabled`, `Disabled`, and `SecuredByPerimeter`.\n- `Workspace.default_data_collection_rule_resource_id` expects a full ARM resource ID.\n- If you authenticate successfully but requests still fail, check Azure RBAC on the subscription, resource group, or workspace. Credential success does not imply authorization success.\n\n## Version-Sensitive Notes\n\n### 13.1.1\n\nPyPI release history for `13.1.1` says the change in this patch release is:\n\n- `RuleDefinition.destination_table` is now writable\n\n### 13.1.0\n\nPyPI release history for `13.1.0` says this line added:\n\n- `WorkspacesOperations.begin_failback`\n- `WorkspacesOperations.begin_failover`\n- `WorkspacesOperations.begin_reconcile_nsp`\n- `WorkspacesOperations.get_nsp`\n- `WorkspacesOperations.list_nsp`\n- `SummaryLogsOperations`\n\nIf you copy older examples that do not mention failover, network security perimeter, or summary logs, check whether they were written against an earlier `13.x` preview or a pre-`13.1.0` stable release.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-loganalytics` without `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Treating `begin_create_or_update()` and `begin_delete()` like synchronous calls and never waiting on the poller\n- Assuming `client.tables.list_by_workspace()` yields `Table` objects directly instead of paged `TablesListResult` pages\n- Using `force=True` on workspace deletion when you actually wanted the default recoverable-delete behavior\n- Regenerating shared keys without rotating dependent agents or ingestion endpoints\n- Using purge for routine cleanup; the official docs say purge is throttled at 50 requests per hour and only supported for GDPR-driven data removal\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-loganalytics/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.loganalyticsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.operations.workspacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.workspace?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.workspacepatch?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.workspacesku?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.operations.tablesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.table?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.operations.querypacksoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.operations.sharedkeysoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.sharedkeys?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.operations.workspacepurgeoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.workspacepurgebody?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models.workspacepurgebodyfilters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-loganalytics/azure.mgmt.loganalytics.models?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-logic/python/DOC.md",
    "content": "---\nname: mgmt-logic\ndescription: \"Azure Logic Apps management SDK for Python for workflows, triggers, runs, integration accounts, and integration service environments\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,logic-apps,management,arm,workflows,triggers,integration-accounts,python\"\n---\n\n# Azure Logic Apps Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-logic` with `azure-identity` when you need to manage Azure Logic Apps resources through Azure Resource Manager. Start with `LogicManagementClient(credential, subscription_id)` and treat workflow definitions as raw Logic Apps Workflow Definition Language JSON.\n\nThis package is for management-plane operations such as creating workflows, listing triggers, reading run history, managing integration accounts, and working with integration service environments. It is not a replacement for calling a workflow's runtime callback URL or for connector-specific data-plane SDKs.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-logic==10.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-logic==10.0.0\" azure-identity\npoetry add \"azure-mgmt-logic==10.0.0\" azure-identity\n```\n\nPyPI describes `10.0.0` as the stable Azure Logic Apps management client and notes that the package has been tested with Python 3.6+, but in practice you should use a currently supported Python runtime.\n\n## Authentication And Client Setup\n\nFor reusable code, use `DefaultAzureCredential`. For local scripts, `AzureCliCredential` is often simpler after `az login`.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_RESOURCE_GROUP=\"example-rg\"\nexport LOGIC_APP_LOCATION=\"westus2\"\nexport LOGIC_APP_NAME=\"example-http-workflow\"\n```\n\nMinimal client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.logic import LogicManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = LogicManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal Azure CLI setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.logic import LogicManagementClient\n\nclient = LogicManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe client constructor defaults `base_url` to `https://management.azure.com` and the Learn reference warns that overriding the default `api_version` (`2019-05-01`) can result in unsupported behavior.\n\n## Create Or Update A Workflow\n\nThe `workflows.create_or_update(...)` call expects a `Workflow` model. The most important field is `definition`, which is the underlying Logic Apps workflow JSON.\n\nThis example creates a simple HTTP request/response workflow:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.logic import LogicManagementClient\nfrom azure.mgmt.logic.models import Workflow\n\nresource_group = os.environ[\"AZURE_RESOURCE_GROUP\"]\nworkflow_name = os.environ[\"LOGIC_APP_NAME\"]\nlocation = os.environ[\"LOGIC_APP_LOCATION\"]\n\nclient = LogicManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ndefinition = {\n    \"$schema\": \"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#\",\n    \"contentVersion\": \"1.0.0.0\",\n    \"triggers\": {\n        \"Request\": {\n            \"type\": \"Request\",\n            \"kind\": \"Http\",\n            \"inputs\": {\n                \"method\": \"POST\",\n                \"schema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\"type\": \"string\"},\n                    },\n                },\n            },\n        }\n    },\n    \"actions\": {\n        \"Response\": {\n            \"type\": \"Response\",\n            \"kind\": \"http\",\n            \"inputs\": {\n                \"statusCode\": 200,\n                \"headers\": {\n                    \"content-type\": \"application/json\",\n                },\n                \"body\": {\n                    \"message\": \"@{coalesce(triggerBody()?['name'], 'world')}\",\n                },\n            },\n            \"runAfter\": {},\n        }\n    },\n    \"outputs\": {},\n}\n\nworkflow = Workflow(\n    location=location,\n    state=\"Enabled\",\n    definition=definition,\n)\n\nresult = client.workflows.create_or_update(\n    resource_group_name=resource_group,\n    workflow_name=workflow_name,\n    workflow=workflow,\n)\n\nprint(result.id)\nprint(result.state)\nprint(result.access_endpoint)\n```\n\nImportant details:\n\n- The request trigger creates an endpoint, but you still need the callback URL before you can call it.\n- The `Workflow` model in `10.0.0` also accepts `identity`, `tags`, `integration_account`, `integration_service_environment`, and `parameters` when your workflow needs them.\n- If you want to check a definition before writing it, the same operation group also exposes `validate_by_location(...)` and `validate_by_resource_group(...)`.\n\n## Get The Callback URL\n\nFor a request trigger, use `workflow_triggers.list_callback_url(...)` after the workflow exists:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.logic import LogicManagementClient\n\nclient = LogicManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ncallback = client.workflow_triggers.list_callback_url(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    trigger_name=\"Request\",\n)\n\nprint(callback.value)\n```\n\nIf you need an expiring URL or want to choose the primary versus secondary key, use `workflows.list_callback_url(...)` with `GetCallbackUrlParameters`:\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.logic import LogicManagementClient\nfrom azure.mgmt.logic.models import GetCallbackUrlParameters\n\nclient = LogicManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ncallback = client.workflows.list_callback_url(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    list_callback_url=GetCallbackUrlParameters(\n        not_after=datetime.now(timezone.utc) + timedelta(hours=1),\n        key_type=\"Primary\",\n    ),\n)\n\nprint(callback.value)\n```\n\n## Call The Workflow Endpoint\n\nOnce you have the callback URL, the runtime call is a normal HTTP request:\n\n```python\nimport json\nimport urllib.request\n\ncallback_url = \"https://...the callback URL from list_callback_url...\"\npayload = json.dumps({\"name\": \"Azure\"}).encode(\"utf-8\")\n\nrequest = urllib.request.Request(\n    callback_url,\n    data=payload,\n    method=\"POST\",\n    headers={\"Content-Type\": \"application/json\"},\n)\n\nwith urllib.request.urlopen(request, timeout=30) as response:\n    print(response.status)\n    print(response.read().decode(\"utf-8\"))\n```\n\n## Inspect Workflows, Triggers, And Runs\n\n### List workflows in a resource group\n\n`workflows.list_by_resource_group(...)` supports `State`, `Trigger`, and `ReferencedResourceId` filters.\n\n```python\nimport os\n\nfor workflow in client.workflows.list_by_resource_group(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    top=20,\n):\n    print(workflow.name, workflow.state, workflow.provisioning_state)\n```\n\n### Inspect triggers\n\n```python\nimport os\n\ntrigger = client.workflow_triggers.get(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    trigger_name=\"Request\",\n)\n\nprint(trigger.name, trigger.state, trigger.status)\n\nschema = client.workflow_triggers.get_schema_json(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    trigger_name=\"Request\",\n)\n\nprint(schema)\n```\n\nThe same operation group also exposes `run(...)`, `reset(...)`, and `set_state(...)` when you need to manually run, reset, enable, or disable a trigger.\n\n### Inspect recent runs\n\n`workflow_runs.list(...)` supports `Status`, `StartTime`, and `ClientTrackingId` filters.\n\n```python\nimport os\n\nfor run in client.workflow_runs.list(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    top=10,\n):\n    print(run.name, run.status, run.start_time)\n```\n\nFetch one run in full:\n\n```python\nimport os\n\nrun = client.workflow_runs.get(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    run_name=\"<run-name>\",\n)\n\nprint(run.status)\nprint(run.correlation_id)\nprint(run.outputs)\n```\n\nIf a run is still active and you need to stop it:\n\n```python\nclient.workflow_runs.cancel(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    workflow_name=os.environ[\"LOGIC_APP_NAME\"],\n    run_name=\"<run-name>\",\n)\n```\n\n## Other Operation Groups You Will Probably Need\n\nThe `LogicManagementClient` surface is broader than workflows alone. Common operation groups in the official reference include:\n\n- `integration_accounts`\n- `integration_account_agreements`\n- `integration_account_assemblies`\n- `integration_account_batch_configurations`\n- `integration_account_certificates`\n- `integration_account_maps`\n- `integration_account_partners`\n- `integration_account_schemas`\n- `integration_service_environments`\n\nIf your project is doing B2B or EDI automation, start by creating or locating the integration account resource first, then use the corresponding artifact operation groups under that account.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-logic` and forgetting `azure-identity`\n- Treating this package as the runtime client for workflow invocations instead of using the callback URL or ordinary HTTP requests\n- Forgetting `AZURE_SUBSCRIPTION_ID`; the client does not infer it from the credential\n- Overriding `api_version` on `LogicManagementClient` even though the reference marks that as potentially unsupported\n- Calling `list_callback_url(...)` before the workflow and trigger actually exist\n- Copying old Azure SDK for Python examples that still use `azure.common.credentials` or `CloudError`\n- Forgetting that workflow definitions are raw Workflow Definition Language JSON, not Python-native helper objects\n\n## Version-Sensitive Notes\n\n### `10.0.0`\n\nPyPI release history for `10.0.0` calls out:\n\n- `Workflow` has a new `identity` parameter\n- `IntegrationServiceEnvironment` has a new `identity` parameter\n- `IntegrationServiceEnvironmentManagedApisOperations.begin_put(...)` has a new required parameter compared with earlier releases\n\n### Upgrading from `8.x` or older\n\nThe `9.0.0` generation switched this package to the modern Azure SDK patterns:\n\n- use `azure-identity` credentials instead of `azure.common.credentials` or `msrestazure.azure_active_directory`\n- expect `credential=...` rather than older `credentials=...`\n- expect long-running operations to use `begin_...`\n- handle failures primarily as `azure.core.exceptions.HttpResponseError`\n- use the `aio` namespace for async clients, for example `azure.mgmt.logic.aio.LogicManagementClient`\n\nIf a script still imports `azure.common.credentials`, it predates the current client generation and should not be copied directly into a `10.0.0` codebase.\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.logicmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.operations.workflowsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.operations.workflowtriggersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.operations.workflowrunsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.models.workflow?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-logic/azure.mgmt.logic.models.getcallbackurlparameters?view=azure-python\n- https://learn.microsoft.com/en-us/azure/logic-apps/workflow-definition-language-schema\n- https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-workflow-actions-triggers\n- https://pypi.org/project/azure-mgmt-logic/\n"
  },
  {
    "path": "content/azure/docs/mgmt-machinelearningservices/python/DOC.md",
    "content": "---\nname: mgmt-machinelearningservices\ndescription: \"Azure Machine Learning Services management SDK for Python for ARM workspace, compute, quota, and private link operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-machine-learning,arm,management,workspaces,compute,python\"\n---\n\n# Azure Machine Learning Services Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-machinelearningservices==1.0.0` for Azure Resource Manager operations on Azure Machine Learning workspaces and workspace compute. In the stable `1.0.0` line, the main client is `AzureMachineLearningWorkspaces`. Do not copy newer preview examples that use `MachineLearningServicesMgmtClient` unless you also move to that newer package line.\n\nThis package is the management-plane SDK. It is for provisioning and administering Azure Machine Learning resources. If you need the newer Azure ML v2 authoring surface for jobs, models, pipelines, and endpoints, use `azure-ai-ml` instead.\n\n## Install\n\nInstall the pinned package together with Azure Identity:\n\n```bash\npython -m pip install \"azure-mgmt-machinelearningservices==1.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-machinelearningservices==1.0.0\" azure-identity\npoetry add \"azure-mgmt-machinelearningservices==1.0.0\" azure-identity\n```\n\n## Authentication And Setup\n\nThe client requires a `TokenCredential` and an Azure subscription ID.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, `DefaultAzureCredential()` can also use existing Azure CLI, Azure PowerShell, or Azure Developer CLI sign-in state. For one-off local scripts, `AzureCliCredential()` is often the least surprising option after `az login`.\n\n### Basic client initialization\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.machinelearningservices import AzureMachineLearningWorkspaces\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = AzureMachineLearningWorkspaces(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\n### Local CLI-driven initialization\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.machinelearningservices import AzureMachineLearningWorkspaces\n\nclient = AzureMachineLearningWorkspaces(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## What The Stable Client Covers\n\nThe stable `AzureMachineLearningWorkspaces` client exposes these management groups:\n\n- `workspaces`\n- `workspace_features`\n- `notebooks`\n- `usages`\n- `virtual_machine_sizes`\n- `quotas`\n- `workspace_connections`\n- `machine_learning_compute`\n- `private_endpoint_connections`\n- `private_link_resources`\n\nThat is the `1.0.0` management surface to expect. If you see examples for registries, batch endpoints, model containers, or the preview `compute` group, those belong to newer preview docs, not the stable `1.0.0` client this guide covers.\n\n## Common Workflows\n\n### List workspaces in a subscription\n\n`list_by_subscription()` returns paged `WorkspaceListResult` objects, so iterate the page results and then their `value` lists:\n\n```python\nfor page in client.workspaces.list_by_subscription():\n    for workspace in page.value:\n        print(workspace.name, workspace.location, workspace.id)\n```\n\nTo scope the listing to one resource group:\n\n```python\nfor page in client.workspaces.list_by_resource_group(\"my-resource-group\"):\n    for workspace in page.value:\n        print(workspace.name, workspace.location)\n```\n\n### Get one workspace\n\n```python\nworkspace = client.workspaces.get(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n)\n\nprint(workspace.id)\nprint(workspace.location)\nprint(workspace.discovery_url)\n```\n\n### Create or update a workspace\n\nThe `Workspace` model exposes fields for the Azure resources commonly associated with a workspace: storage account, key vault, application insights, and container registry. Using explicit ARM resource IDs is the safest approach for this package because it keeps the request shape obvious.\n\n```bash\nexport AML_RESOURCE_GROUP=\"my-resource-group\"\nexport AML_WORKSPACE_NAME=\"my-ml-workspace\"\nexport AML_LOCATION=\"eastus\"\nexport AML_STORAGE_ACCOUNT_ID=\"/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<name>\"\nexport AML_KEY_VAULT_ID=\"/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<name>\"\nexport AML_APP_INSIGHTS_ID=\"/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Insights/components/<name>\"\nexport AML_CONTAINER_REGISTRY_ID=\"/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ContainerRegistry/registries/<name>\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.machinelearningservices import AzureMachineLearningWorkspaces\nfrom azure.mgmt.machinelearningservices.models import Workspace\n\nclient = AzureMachineLearningWorkspaces(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nworkspace = client.workspaces.begin_create_or_update(\n    resource_group_name=os.environ[\"AML_RESOURCE_GROUP\"],\n    workspace_name=os.environ[\"AML_WORKSPACE_NAME\"],\n    parameters=Workspace(\n        location=os.environ[\"AML_LOCATION\"],\n        friendly_name=\"Demo AML Workspace\",\n        description=\"Workspace managed from Python\",\n        storage_account=os.environ[\"AML_STORAGE_ACCOUNT_ID\"],\n        key_vault=os.environ[\"AML_KEY_VAULT_ID\"],\n        application_insights=os.environ[\"AML_APP_INSIGHTS_ID\"],\n        container_registry=os.environ[\"AML_CONTAINER_REGISTRY_ID\"],\n        hbi_workspace=False,\n        tags={\"env\": \"dev\"},\n    ),\n).result()\n\nprint(workspace.id)\n```\n\n`begin_create_or_update(...)` is a long-running ARM operation. Call `.result()` before assuming the workspace exists.\n\n### Read workspace keys\n\nThe stable client exposes `list_keys(...)` and `resync_keys(...)` on `workspaces`.\n\n```python\nkeys = client.workspaces.list_keys(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n)\n\nprint(keys)\n```\n\nTreat this result as sensitive. The docs explicitly say it includes keys for the backing storage account, Application Insights, and container registry password.\n\n### Discover quota and recommended VM sizes before creating compute\n\nCheck region quota and supported sizes before choosing a cluster SKU:\n\n```python\nquota_pages = client.quotas.list(location=\"eastus\")\nfor page in quota_pages:\n    for item in page.value:\n        print(item)\n\nvm_sizes = client.virtual_machine_sizes.list(\n    location=\"eastus\",\n    compute_type=\"AmlCompute\",\n    recommended=True,\n)\n\nprint(vm_sizes)\n```\n\nThis package returns SDK model objects here. Inspect the returned quota and size objects first, then pick a `vm_size` for compute creation.\n\n### Create an AmlCompute cluster\n\nThe stable compute API hangs off `client.machine_learning_compute`. Cluster creation is another long-running operation.\n\n```python\nfrom datetime import timedelta\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.machinelearningservices import AzureMachineLearningWorkspaces\nfrom azure.mgmt.machinelearningservices.models import (\n    AmlCompute,\n    AmlComputeProperties,\n    ComputeResource,\n    ScaleSettings,\n)\n\nclient = AzureMachineLearningWorkspaces(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ncompute = client.machine_learning_compute.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n    compute_name=\"cpu-cluster\",\n    parameters=ComputeResource(\n        location=\"eastus\",\n        properties=AmlCompute(\n            compute_location=\"eastus\",\n            properties=AmlComputeProperties(\n                vm_size=\"Standard_DS3_v2\",\n                vm_priority=\"Dedicated\",\n                scale_settings=ScaleSettings(\n                    min_node_count=0,\n                    max_node_count=4,\n                    node_idle_time_before_scale_down=timedelta(minutes=20),\n                ),\n            ),\n        ),\n    ),\n).result()\n\nprint(compute.id)\n```\n\nImportant details from the official model docs:\n\n- `ScaleSettings.max_node_count` is required.\n- `ScaleSettings.min_node_count` defaults to `0`.\n- `MachineLearningComputeOperations.begin_create_or_update(...)` overwrites an existing compute if it already exists.\n\n### Inspect or delete a compute target\n\n```python\ncompute = client.machine_learning_compute.get(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n    compute_name=\"cpu-cluster\",\n)\n\nprint(compute.name)\nprint(compute.location)\n```\n\n```python\nclient.machine_learning_compute.begin_delete(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n    compute_name=\"cpu-cluster\",\n    underlying_resource_action=\"Delete\",\n).result()\n```\n\nFor compute deletion, the SDK requires `underlying_resource_action`. Use:\n\n- `\"Delete\"` to delete the underlying compute resource\n- `\"Detach\"` to detach the underlying compute from the workspace\n\n### Check private link resources for a workspace\n\n```python\nprivate_links = client.private_link_resources.list_by_workspace(\n    resource_group_name=\"my-resource-group\",\n    workspace_name=\"my-ml-workspace\",\n)\n\nprint(private_links)\n```\n\nUse this when you are wiring private endpoints or validating what private link resources the workspace exposes.\n\n## Configuration Notes\n\n- This package does not create generic Azure infrastructure outside Azure Machine Learning itself. If the resource group does not exist yet, create it with `azure-mgmt-resource` or another ARM tool first.\n- Workspace creation commonly depends on associated Azure resources such as Storage, Key Vault, Application Insights, and Container Registry. Microsoft’s workspace docs and ARM template samples treat these as the standard dependency set.\n- `DefaultAzureCredential` authenticates; it does not choose a subscription. You still must pass `subscription_id`.\n- Management calls succeed only if the identity has the right Azure RBAC permissions at the subscription, resource group, or resource scope.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-machinelearningservices` and forgetting `azure-identity`\n- Copying preview Learn examples that use `MachineLearningServicesMgmtClient` and newer operation groups into a project pinned to `1.0.0`\n- Treating `begin_create_or_update(...)` or `begin_delete(...)` as synchronous and skipping `.result()`\n- Logging the output of `workspaces.list_keys(...)` or `machine_learning_compute.list_keys(...)`\n- Creating compute before checking quota and region VM-size availability\n- Forgetting that compute creation and delete calls can overwrite or remove underlying resources\n- Expecting this package to replace `azure-ai-ml` for jobs, models, pipelines, or current endpoint workflows\n\n## Version-Sensitive Notes\n\n- PyPI lists `1.0.0` as the stable release published on `2021-01-04`.\n- The stable `1.0.0` API root documents `AzureMachineLearningWorkspaces` as the client class.\n- Microsoft Learn also publishes newer preview documentation for `MachineLearningServicesMgmtClient` and additional AML resource types. That is a different API line. If you pin `azure-mgmt-machinelearningservices==1.0.0`, stay on the stable `AzureMachineLearningWorkspaces` surface shown in this guide.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/azure-mgmt-machinelearningservices/`\n- Azure Machine Learning Services management package API root: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/`\n- `AzureMachineLearningWorkspaces` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.azuremachinelearningworkspaces?view=azure-python`\n- `WorkspacesOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.operations.workspacesoperations?view=azure-python`\n- `Workspace` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.models.workspace?view=azure-python`\n- `MachineLearningComputeOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.operations.machinelearningcomputeoperations?view=azure-python`\n- `ComputeResource` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.models.computeresource?view=azure-python`\n- `AmlCompute` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.models.amlcompute?view=azure-python`\n- `AmlComputeProperties` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.models.amlcomputeproperties?view=azure-python`\n- `ScaleSettings` model reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.models.scalesettings?view=azure-python`\n- `QuotasOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.operations.quotasoperations?view=azure-python`\n- `VirtualMachineSizesOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.operations.virtualmachinesizesoperations?view=azure-python`\n- `PrivateLinkResourcesOperations` reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-machinelearningservices/azure.mgmt.machinelearningservices.operations.privatelinkresourcesoperations?view=azure-python`\n- Azure authentication overview for Python: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python`\n- `AzureCliCredential` reference: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python`\n- Azure ML workspace management article: `https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-workspace`\n- Azure ML workspace ARM template sample: `https://learn.microsoft.com/en-us/samples/azure/azure-quickstart-templates/machine-learning-workspace/`\n"
  },
  {
    "path": "content/azure/docs/mgmt-managedservices/python/DOC.md",
    "content": "---\nname: mgmt-managedservices\ndescription: \"Azure Lighthouse management-plane SDK for Python for registration definitions, registration assignments, and marketplace-managed services delegations\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-lighthouse,managed-services,management,delegation,multitenant,python\"\n---\n\n# azure-mgmt-managedservices Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-managedservices` is the Azure Resource Manager SDK for Azure Lighthouse delegated resource management.\n\nUse it when you need to:\n\n- create or inspect a registration definition in the customer subscription\n- create or inspect registration assignments at subscription or resource-group scope\n- read marketplace registration definitions exposed by Azure Managed Services offers\n\nPrimary import surface:\n\n```python\nfrom azure.mgmt.managedservices import ManagedServicesClient\n```\n\nThis is a management-plane client. It works with ARM scopes such as `/subscriptions/<id>` and `/subscriptions/<id>/resourceGroups/<name>`.\n\n## Install\n\nInstall the package with `azure-identity`:\n\n```bash\npython -m pip install \"azure-mgmt-managedservices==6.0.0\" azure-identity\n```\n\n`6.0.0` is the stable track-2 package line. PyPI also lists newer `7.0.0b*` prereleases, so pin `6.0.0` if you want the API surface covered here.\n\n## Authentication And Setup\n\nUse `DefaultAzureCredential` for most code and sign in locally with Azure CLI:\n\n```bash\naz login\n```\n\nExample environment variables used by the snippets below:\n\n```bash\nexport CUSTOMER_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport CUSTOMER_RESOURCE_GROUP=\"delegated-rg\"\nexport MANAGING_TENANT_ID=\"11111111-1111-1111-1111-111111111111\"\nexport MANAGING_PRINCIPAL_ID=\"22222222-2222-2222-2222-222222222222\"\nexport ACTIVE_ROLE_DEFINITION_ID=\"<built-in-role-guid>\"\nexport ELIGIBLE_ROLE_DEFINITION_ID=\"<built-in-role-guid>\"\n```\n\nIf you use a service principal directly, `DefaultAzureCredential` also supports:\n\n```bash\nexport AZURE_TENANT_ID=\"11111111-1111-1111-1111-111111111111\"\nexport AZURE_CLIENT_ID=\"33333333-3333-3333-3333-333333333333\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nClient initialization:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\n\ncredential = DefaultAzureCredential()\nclient = ManagedServicesClient(credential=credential)\n```\n\nImportant setup detail: `ManagedServicesClient` is scope-based. Unlike many Azure management SDKs, you do not pass a subscription ID to the client constructor. Each operation takes a `scope` argument instead.\n\n## Required Azure Roles And Scope Rules\n\nAzure Lighthouse onboarding creates two ARM resources:\n\n- a registration definition at subscription scope\n- a registration assignment at each delegated scope\n\nThe onboarding identity in the customer tenant needs permission to create those resources. Microsoft documents this as requiring permissions such as `Microsoft.ManagedServices/registrationDefinitions/write` and `Microsoft.Authorization/roleAssignments/write`, which built-in roles such as `Owner` include.\n\nFor `authorization.role_definition_id` and `eligible_authorization.role_definition_id`, use built-in role GUIDs supported by Azure delegated resource management. The onboarding docs explicitly say not to use roles with `DataActions`, and not to use the `Owner` role.\n\n## Core Workflow\n\n### Create A Registration Definition\n\nCreate the definition at the customer subscription scope. The SDK call is a long-running operation, so wait on `.result()`.\n\n```python\nimport os\nimport uuid\nfrom datetime import timedelta\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\nfrom azure.mgmt.managedservices.models import (\n    Authorization,\n    EligibleAuthorization,\n    JustInTimeAccessPolicy,\n    RegistrationDefinition,\n    RegistrationDefinitionProperties,\n)\n\nsubscription_scope = f\"/subscriptions/{os.environ['CUSTOMER_SUBSCRIPTION_ID']}\"\n\nclient = ManagedServicesClient(credential=DefaultAzureCredential())\n\ndefinition = client.registration_definitions.begin_create_or_update(\n    registration_definition_id=str(uuid.uuid4()),\n    scope=subscription_scope,\n    request_body=RegistrationDefinition(\n        properties=RegistrationDefinitionProperties(\n            registration_definition_name=\"Contoso delegation\",\n            description=\"Delegation for the Contoso operations team\",\n            managed_by_tenant_id=os.environ[\"MANAGING_TENANT_ID\"],\n            authorizations=[\n                Authorization(\n                    principal_id=os.environ[\"MANAGING_PRINCIPAL_ID\"],\n                    principal_id_display_name=\"Contoso Operations\",\n                    role_definition_id=os.environ[\"ACTIVE_ROLE_DEFINITION_ID\"],\n                )\n            ],\n            eligible_authorizations=[\n                EligibleAuthorization(\n                    principal_id=os.environ[\"MANAGING_PRINCIPAL_ID\"],\n                    principal_id_display_name=\"Contoso Operations\",\n                    role_definition_id=os.environ[\"ELIGIBLE_ROLE_DEFINITION_ID\"],\n                    just_in_time_access_policy=JustInTimeAccessPolicy(\n                        multi_factor_auth_provider=\"Azure\",\n                        maximum_activation_duration=timedelta(hours=2),\n                    ),\n                )\n            ],\n        )\n    ),\n).result()\n\nprint(definition.id)\nprint(definition.properties.provisioning_state)\n```\n\nWhy both `authorizations` and `eligible_authorizations` appear here:\n\n- `authorizations` define always-active delegated roles\n- `eligible_authorizations` define just-in-time roles for Azure Lighthouse eligible authorization flows\n\nMicrosoft's eligible-authorization guidance says:\n\n- eligible authorizations cannot be used with service principals\n- every eligible authorization must have a matching permanent `Reader` authorization for the same principal\n- `maximum_activation_duration` must be between 30 minutes and 8 hours\n- if you omit approvers, any user in the managing tenant with the eligible role can activate it\n\n### Assign The Definition To A Delegated Scope\n\nAfter the definition exists, create a registration assignment at the delegated subscription or resource-group scope.\n\n```python\nimport os\nimport uuid\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\nfrom azure.mgmt.managedservices.models import (\n    RegistrationAssignment,\n    RegistrationAssignmentProperties,\n)\n\nsubscription_scope = f\"/subscriptions/{os.environ['CUSTOMER_SUBSCRIPTION_ID']}\"\nresource_group_scope = (\n    f\"{subscription_scope}/resourceGroups/{os.environ['CUSTOMER_RESOURCE_GROUP']}\"\n)\n\nclient = ManagedServicesClient(credential=DefaultAzureCredential())\n\ndefinition_id = \"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ManagedServices/registrationDefinitions/44444444-4444-4444-4444-444444444444\"\n\nassignment = client.registration_assignments.begin_create_or_update(\n    scope=resource_group_scope,\n    registration_assignment_id=str(uuid.uuid4()),\n    request_body=RegistrationAssignment(\n        properties=RegistrationAssignmentProperties(\n            registration_definition_id=definition_id,\n        )\n    ),\n).result()\n\nprint(assignment.id)\nprint(assignment.properties.provisioning_state)\n```\n\nUse the `definition.id` returned by the definition-create step for `registration_definition_id`.\n\n### Read A Definition Or Assignment\n\nFetch a definition by subscription scope plus definition GUID:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\n\nsubscription_scope = f\"/subscriptions/{os.environ['CUSTOMER_SUBSCRIPTION_ID']}\"\ndefinition_id = \"44444444-4444-4444-4444-444444444444\"\n\nclient = ManagedServicesClient(credential=DefaultAzureCredential())\n\ndefinition = client.registration_definitions.get(\n    scope=subscription_scope,\n    registration_definition_id=definition_id,\n)\n\nprint(definition.properties.registration_definition_name)\nprint(definition.properties.managed_by_tenant_id)\n```\n\nFetch an assignment and ask ARM to expand the linked definition:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\n\nresource_group_scope = (\n    f\"/subscriptions/{os.environ['CUSTOMER_SUBSCRIPTION_ID']}\"\n    f\"/resourceGroups/{os.environ['CUSTOMER_RESOURCE_GROUP']}\"\n)\nassignment_id = \"55555555-5555-5555-5555-555555555555\"\n\nclient = ManagedServicesClient(credential=DefaultAzureCredential())\n\nassignment = client.registration_assignments.get(\n    scope=resource_group_scope,\n    registration_assignment_id=assignment_id,\n    expand_registration_definition=True,\n)\n\nprint(assignment.properties.registration_definition_id)\nprint(assignment.properties.registration_definition.properties.registration_definition_name)\n```\n\nUse `expand_registration_definition=True` when you need the definition details in the same response instead of making a second lookup.\n\n### Remove A Delegation\n\nDelete the assignment at the delegated scope, then remove the definition from the customer subscription scope.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managedservices import ManagedServicesClient\n\nsubscription_scope = f\"/subscriptions/{os.environ['CUSTOMER_SUBSCRIPTION_ID']}\"\nresource_group_scope = (\n    f\"{subscription_scope}/resourceGroups/{os.environ['CUSTOMER_RESOURCE_GROUP']}\"\n)\n\nclient = ManagedServicesClient(credential=DefaultAzureCredential())\n\nclient.registration_assignments.begin_delete(\n    scope=resource_group_scope,\n    registration_assignment_id=\"55555555-5555-5555-5555-555555555555\",\n).result()\n\nclient.registration_definitions.delete(\n    scope=subscription_scope,\n    registration_definition_id=\"44444444-4444-4444-4444-444444444444\",\n)\n```\n\n`registration_assignments.begin_delete(...)` is long-running. `registration_definitions.delete(...)` is not.\n\n## Marketplace Definitions\n\nThe package also exposes marketplace-focused operation groups:\n\n- `marketplace_registration_definitions`\n- `marketplace_registration_definitions_without_scope`\n\nUse them when you need to inspect Azure Managed Services marketplace offer definitions rather than creating your own direct Azure Lighthouse delegation.\n\n## Common Pitfalls\n\n- Forgetting that the client constructor does not take `subscription_id`; every operation needs a full ARM `scope`.\n- Passing a full ARM role definition resource ID where Azure Lighthouse expects a built-in role GUID.\n- Using unsupported roles in `authorizations`; Azure Lighthouse onboarding docs explicitly reject `Owner` and roles with `DataActions`.\n- Creating eligible authorizations for service principals. Azure Lighthouse eligible authorization is only for user or group principals.\n- Skipping the permanent `Reader` authorization that must accompany an eligible authorization for the same principal.\n- Creating the definition at a resource-group scope. Registration definitions are created at the subscription level.\n- Expecting portal visibility immediately. Microsoft notes that onboarding changes can take time to propagate.\n\n## Version Notes For `6.0.0`\n\n- PyPI release notes for `6.0.0b1` describe the track-2 migration for this package: credential-based client construction, `azure-identity` authentication, `azure-core` transport, and `begin_` long-running operation methods.\n- PyPI release notes for `6.0.0` add the `marketplace_registration_definitions_without_scope` operation group.\n- If you copy older `msrestazure`-style examples for this package, they may not match the `6.x` client shape.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-managedservices/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managedservices/azure.mgmt.managedservices.operations.registrationdefinitionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managedservices/azure.mgmt.managedservices.operations.registrationassignmentsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managedservices/azure.mgmt.managedservices.models.authorization?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managedservices/azure.mgmt.managedservices.models.eligibleauthorization?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managedservices/azure.mgmt.managedservices.models.justintimeaccesspolicy?view=azure-python\n- https://learn.microsoft.com/en-us/azure/lighthouse/concepts/architecture\n- https://learn.microsoft.com/en-us/azure/lighthouse/how-to/onboard-customer\n- https://learn.microsoft.com/en-us/azure/lighthouse/how-to/create-eligible-authorizations\n"
  },
  {
    "path": "content/azure/docs/mgmt-managementgroups/python/DOC.md",
    "content": "---\nname: mgmt-managementgroups\ndescription: \"Azure management group SDK for Python for tenant hierarchy, management group CRUD, subscriptions, and hierarchy settings\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,management-groups,tenant,subscriptions,governance\"\n---\n\n# azure-mgmt-managementgroups Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-managementgroups` is the Azure Resource Manager management-plane SDK for tenant hierarchy operations:\n\n- list and inspect management groups\n- create, update, and delete management groups\n- list descendants\n- move subscriptions into or out of management groups\n- read or update tenant hierarchy settings\n\nImport path:\n\n```python\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n```\n\nUse this package for Azure governance and tenant hierarchy work. Do not use it for subscription-scoped resources like storage accounts, virtual machines, or Key Vault objects; those belong in service-specific management SDKs.\n\n## Install\n\nInstall the management client and Azure Identity together:\n\n```bash\npython -m pip install \"azure-mgmt-managementgroups==1.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-managementgroups==1.1.0\" azure-identity\npoetry add \"azure-mgmt-managementgroups==1.1.0\" azure-identity\n```\n\nPyPI lists `1.1.0` as supporting Python `>=3.9`.\n\n## Authentication And Setup\n\nFor local development, sign in with Azure CLI:\n\n```bash\naz login\n```\n\nFor service principal auth, set the standard Azure Identity environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic setup with `DefaultAzureCredential`:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\ncredential = DefaultAzureCredential()\nclient = ManagementGroupsAPI(credential=credential)\n```\n\nFor a local script that should only use Azure CLI credentials:\n\n```python\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(credential=AzureCliCredential())\n```\n\nImportant setup notes:\n\n- `ManagementGroupsAPI` does not take a subscription ID.\n- The current package documentation on PyPI uses `azure-identity` credentials. Older task articles still show `azure.common` and `azure-cli-core`; do not copy those auth patterns into new code.\n- Azure management group APIs are tenant-level ARM APIs. Authentication can succeed while later calls still fail because the principal lacks tenant or root management group permissions.\n\n## Core Usage\n\nThe current client exposes these main operation groups:\n\n- `management_groups`\n- `management_group_subscriptions`\n- `entities`\n- `operations`\n- `hierarchy_settings`\n\n### List Management Groups Visible To The Credential\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\n\nfor group in client.management_groups.list():\n    print(group.name, group.id)\n```\n\n### Get One Management Group And Expand Children\n\nUse `expand=\"children\"` to include direct children. Add `recurse=True` if you need the full nested hierarchy under that group.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\n\ngroup = client.management_groups.get(\n    group_id=\"contoso-platform\",\n    expand=\"children\",\n    recurse=True,\n)\n\nprint(group.name)\nprint(group.display_name)\n\nfor child in group.children or []:\n    print(child.name, child.type)\n```\n\n### Create A Management Group\n\nManagement group creation is a long-running ARM operation. Use the `begin_*` method and wait for the poller when you need the result.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\n\npoller = client.management_groups.begin_create_or_update(\n    group_id=\"contoso-platform\",\n    create_management_group_request={\n        \"name\": \"contoso-platform\",\n        \"display_name\": \"Contoso Platform\",\n    },\n)\n\ngroup = poller.result()\nprint(group.id)\nprint(group.display_name)\n```\n\n### Move A Subscription Under A Management Group\n\nAssociate a subscription to a management group with `management_group_subscriptions.create()`:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nsubscription_id = \"00000000-0000-0000-0000-000000000000\"\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\nassociation = client.management_group_subscriptions.create(\n    group_id=\"contoso-platform\",\n    subscription_id=subscription_id,\n)\n\nprint(association.id)\n```\n\nTo remove the subscription association:\n\n```python\nclient.management_group_subscriptions.delete(\n    group_id=\"contoso-platform\",\n    subscription_id=subscription_id,\n)\n```\n\n### Inspect Tenant Hierarchy Settings\n\nHierarchy settings apply to the tenant root management group. Use them to inspect defaults such as whether authorization is required for group creation and which management group becomes the default for new subscriptions.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\n\nsettings = client.hierarchy_settings.get(\n    group_id=\"contoso-root\"\n)\n\nprint(settings.require_authorization_for_group_creation)\nprint(settings.default_management_group)\n```\n\n### Inspect Supported ARM Operations\n\nThis is useful when you need to confirm the tenant hierarchy operations the installed client exposes:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.managementgroups import ManagementGroupsAPI\n\nclient = ManagementGroupsAPI(DefaultAzureCredential())\n\nfor operation in client.operations.list():\n    print(operation.name)\n```\n\n## Configuration Notes\n\n- `management_groups.get()` supports `expand` and `recurse` for hierarchy traversal. Use those instead of making one request per child group when you need the tree.\n- `begin_create_or_update()` and `begin_delete()` return Azure long-running operation pollers.\n- `hierarchy_settings` is for the tenant root management group, not for arbitrary child groups.\n- `management_group_subscriptions.create()` changes hierarchy placement, not subscription metadata like display name or tags.\n- If you keep the client around in a long-lived process, close it when done.\n\n## Version-Sensitive Notes For `1.1.0`\n\n- PyPI lists stable version `1.1.0`, released on November 8, 2023.\n- PyPI release notes for `1.1.0` call out an import fix and an updated code generator.\n- PyPI `1.0.0b1` notes switched examples to `azure-identity` and added async support. If you find much older samples using `ServicePrincipalCredentials` or `get_azure_cli_credentials`, treat them as outdated.\n- Microsoft Learn still has a management group task article that uses the older `create_or_update()` method name and legacy auth imports. For current projects on `1.1.0`, prefer the generated client reference and current PyPI guidance.\n\n## Common Pitfalls\n\n- Do not pass a subscription ID to `ManagementGroupsAPI`; this client is tenant-scoped.\n- Do not reuse older `azure.common.credentials` or `azure-cli-core` authentication snippets. Use `azure-identity`.\n- Creating the first management group in a directory can take up to 15 minutes.\n- Hierarchy changes are not always immediately visible everywhere. Azure Resource Manager can cache management group changes for up to 30 minutes.\n- Moving a subscription into or out of a management group requires the right RBAC assignments. Authentication alone is not enough.\n- If a subscription has not been in another management group before, Microsoft notes that you generally need `Owner` on the subscription to move it.\n- `begin_delete()` only works when the target management group has no child groups or subscriptions under it.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-managementgroups/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managementgroups/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managementgroups/azure.mgmt.managementgroups.managementgroupsapi?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managementgroups/azure.mgmt.managementgroups.operations.managementgroupsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managementgroups/azure.mgmt.managementgroups.operations.managementgroupsubscriptionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-managementgroups/azure.mgmt.managementgroups.operations.hierarchysettingsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python\n- https://learn.microsoft.com/en-us/azure/governance/management-groups/overview\n- https://learn.microsoft.com/en-us/azure/governance/management-groups/create-management-group-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-maps/python/DOC.md",
    "content": "---\nname: mgmt-maps\ndescription: \"Azure Maps management SDK for Python for provisioning Maps accounts, managing keys, generating SAS tokens, and handling management-plane resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-maps,management,arm,provisioning,python\"\n---\n\n# Azure Maps Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-maps` for Azure Resource Manager work on Azure Maps resources: creating and updating Maps accounts, listing or regenerating account keys, generating SAS tokens, and inspecting management resources. Do not use it for search, routing, rendering, or other data-plane requests. Those calls belong in the Azure Maps client packages such as `azure-maps-search`, `azure-maps-route`, or `azure-maps-render`.\n\n## Install\n\nInstall the management client together with Azure Identity:\n\n```bash\npython -m pip install \"azure-mgmt-maps==2.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-maps==2.1.0\" azure-identity\npoetry add \"azure-mgmt-maps==2.1.0\" azure-identity\n```\n\nPractical version guidance:\n\n- PyPI metadata for `2.1.0` still declares Python `>=3.7`.\n- The current Azure SDK for Python support policy is Python `3.9+`.\n- For new environments, use Python `3.9+` even if older interpreters can still install this package.\n\n## Authentication And Client Setup\n\nFor local scripts, Azure CLI credentials are usually the quickest path:\n\n```bash\naz login\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nReusable application code should prefer `DefaultAzureCredential`:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client initialization:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.maps import AzureMapsManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = AzureMapsManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can use `AzureCliCredential` explicitly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.maps import AzureMapsManagementClient\n\nclient = AzureMapsManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe main operation groups in `2.1.0` are:\n\n- `client.accounts`\n- `client.creators`\n- `client.maps`\n\n## Create Or Update A Maps Account\n\nCreate a Gen2 Maps account with `accounts.create_or_update(...)`:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.maps import AzureMapsManagementClient\n\nclient = AzureMapsManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\naccount = client.accounts.create_or_update(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n    maps_account={\n        \"location\": \"global\",\n        \"kind\": \"Gen2\",\n        \"sku\": {\"name\": \"G2\"},\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    },\n)\n\nprint(account.id)\nprint(account.properties.unique_id)\n```\n\nUse `accounts.update(...)` for partial changes:\n\n```python\nupdated = client.accounts.update(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n    maps_account_update_parameters={\n        \"tags\": {\n            \"env\": \"prod\",\n            \"owner\": \"platform\",\n        },\n    },\n)\n\nprint(updated.tags)\n```\n\nImportant account settings exposed by the current ARM resource schema include:\n\n- `disableLocalAuth`: disables shared-key and SAS authentication\n- `publicNetworkAccess`: enables or blocks public endpoint access\n- `cors`: CORS rules for the account\n- `linkedResources`: linked storage resources\n\nIf you plan to use account keys or SAS tokens, do not enable `disableLocalAuth`.\n\n## List Accounts And Read Account Details\n\nList Maps accounts in a resource group:\n\n```python\nfor account in client.accounts.list_by_resource_group(\"example-rg\"):\n    print(account.name, account.location, account.kind)\n```\n\nRead one account:\n\n```python\naccount = client.accounts.get(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n)\n\nprint(account.id)\nprint(account.location)\nprint(account.properties.unique_id)\n```\n\n## List And Regenerate Account Keys\n\nUse the management client to retrieve the shared keys that data-plane clients can use with `AzureKeyCredential`:\n\n```python\nkeys = client.accounts.list_keys(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n)\n\nprint(keys.primary_key)\nprint(keys.secondary_key)\n```\n\nRotate one key with `regenerate_keys(...)`:\n\n```python\nfrom azure.mgmt.maps.models import MapsKeySpecification\n\nnew_keys = client.accounts.regenerate_keys(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n    key_specification=MapsKeySpecification(key_type=\"primary\"),\n)\n\nprint(new_keys.primary_key)\n```\n\nUse a staged rotation flow in production:\n\n1. move clients to the secondary key\n2. regenerate the primary key\n3. move clients back if needed\n4. regenerate the secondary key\n\n## Generate A SAS Token For Azure Maps Data-Plane Clients\n\n`2.1.0` adds `accounts.list_sas(...)`, which is the management-plane call used to mint SAS tokens for the newer Azure Maps SDKs.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.maps import AzureMapsManagementClient\nfrom azure.mgmt.maps.models import AccountSasParameters\n\nclient = AzureMapsManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nstart = datetime.now(timezone.utc)\nexpiry = start + timedelta(hours=1)\n\ntoken = client.accounts.list_sas(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n    maps_account_sas_parameters=AccountSasParameters(\n        signing_key=\"primaryKey\",\n        principal_id=os.environ[\"AZURE_MAPS_UAMI_OBJECT_ID\"],\n        max_rate_per_second=500,\n        start=start.isoformat().replace(\"+00:00\", \"Z\"),\n        expiry=expiry.isoformat().replace(\"+00:00\", \"Z\"),\n        regions=[\"eastus\"],\n    ),\n)\n\nprint(token.account_sas_token)\n```\n\nBefore this works:\n\n- the Maps account must already have a user-assigned managed identity attached\n- the identity must be in the same region as the Maps account\n- local auth must still be enabled on the account\n\nThe returned SAS token is what the data-plane Azure Maps packages use with `AzureSasCredential`.\n\n## Delete An Account\n\nDelete a Maps account with `accounts.delete(...)`:\n\n```python\nclient.accounts.delete(\n    resource_group_name=\"example-rg\",\n    account_name=\"example-maps-account\",\n)\n```\n\n## Creator Resources\n\nThe `client.creators` operation group still exists in the `2.1.0` SDK and the ARM template reference still documents `Microsoft.Maps/accounts/creators`. Treat this as a compatibility surface, not a default new build target: Microsoft announced Azure Maps Creator retirement effective September 30, 2025.\n\nIf you inherit code that already uses Creator resources, verify service availability and retirement impact before writing new automation around `client.creators`.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-maps` for search or routing calls instead of a data-plane Azure Maps package\n- Forgetting `azure-identity`; this package does not include credential implementations\n- Omitting `AZURE_SUBSCRIPTION_ID`; management clients do not infer the subscription automatically\n- Enabling `disableLocalAuth` and then expecting `list_keys(...)` or SAS-based app auth to remain usable\n- Treating SAS generation as self-contained; the account identity prerequisite must already be configured\n- Building new Creator automation without checking the post-September 30, 2025 retirement status first\n\n## Version-Sensitive Notes\n\n### `2.1.0`\n\nPyPI release notes for `2.1.0` call out these changes:\n\n- added `accounts.list_sas`\n- added async support\n- added `cors`, `disable_local_auth`, `linked_resources`, `public_network_access`, and encryption-related account fields\n- added a `Maps` operation group including `list_subscription_operations`\n\nIf you are maintaining code written against `2.0.x` or earlier, verify these newer methods and fields before assuming they exist.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-maps/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-maps/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-maps/azure.mgmt.maps.azuremapsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-maps/azure.mgmt.maps.operations.accountsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/azure/azure-maps/azure-maps-authentication\n- https://learn.microsoft.com/en-us/azure/azure-maps/how-to-manage-authentication\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.maps/accounts\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.maps/accounts/creators\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/azure-sdk-overview\n- https://azure.microsoft.com/en-us/updates?id=azure-maps-creator-services-retirement-on-30-september-2025\n"
  },
  {
    "path": "content/azure/docs/mgmt-marketplaceordering/python/DOC.md",
    "content": "---\nname: mgmt-marketplaceordering\ndescription: \"Azure Marketplace Ordering management SDK for Python for reading, accepting, listing, and canceling Marketplace agreement terms\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,marketplace,management,marketplaceordering,virtual-machine,agreements\"\n---\n\n# azure-mgmt-marketplaceordering Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-marketplaceordering` is the Azure Resource Manager management-plane SDK for Marketplace agreement terms at the subscription level.\n\nUse it when you need to:\n\n- read the current legal terms for a Marketplace VM offer\n- accept those terms programmatically before deployment\n- list agreements already stored on the subscription\n- cancel previously accepted terms\n\nImport path:\n\n```python\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n```\n\nThe current Learn reference exposes `MarketplaceOrderingAgreements.marketplace_agreements` with these methods: `get`, `sign`, `get_agreement`, `list`, `cancel`, and `create`.\n\n## Golden Rule\n\nUse this package only for Marketplace terms and agreement state. It does not deploy the VM or managed application for you.\n\nFor Marketplace VM flows, Microsoft documents two separate requirements:\n\n- the subscription must accept the legal terms for the `publisher / offer / plan`\n- the later VM deployment request must still include the matching Marketplace plan information\n\nIf the terms are not accepted, Azure returns `MarketplacePurchaseEligibilityFailed`. If the VM request omits plan information, Azure returns `VMMarketplaceInvalidInput`.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-marketplaceordering==1.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-marketplaceordering==1.1.0\" azure-identity\npoetry add \"azure-mgmt-marketplaceordering==1.1.0\" azure-identity\n```\n\nVersion notes from PyPI:\n\n- stable version `1.1.0` was released on March 18, 2021\n- PyPI also lists newer preview releases such as `1.2.0b2`\n- unless your project intentionally tracks previews, pin the stable `1.1.0` line\n\n## Authentication And Setup\n\nUse `DefaultAzureCredential` for reusable code or `AzureCliCredential` for local scripts after `az login`.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_MARKETPLACE_PUBLISHER_ID=\"contoso\"\nexport AZURE_MARKETPLACE_OFFER_ID=\"contoso-product\"\nexport AZURE_MARKETPLACE_PLAN_ID=\"contoso-plan\"\n```\n\nIf you authenticate with a service principal, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nMicrosoft's Marketplace deployment guidance notes that:\n\n- Product ID is also called Offer ID in some APIs\n- Plan ID is also called SKU ID in some APIs\n- you can find Publisher ID, Product ID, and Plan ID on the Marketplace product's `Usage Information + Support` tab in the Azure portal\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = MarketplaceOrderingAgreements(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor local CLI-driven scripts:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## Core Workflow\n\n### Read The Current Terms For A Marketplace VM Plan\n\nUse `get()` first when you want the current legal links and the existing acceptance state.\n\nThe Learn reference documents `offer_type` on `get()` and `create()`. For Marketplace VM terms, use `\"virtualmachine\"`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nterms = client.marketplace_agreements.get(\n    offer_type=\"virtualmachine\",\n    publisher_id=os.environ[\"AZURE_MARKETPLACE_PUBLISHER_ID\"],\n    offer_id=os.environ[\"AZURE_MARKETPLACE_OFFER_ID\"],\n    plan_id=os.environ[\"AZURE_MARKETPLACE_PLAN_ID\"],\n)\n\nprint(\"accepted:\", terms.accepted)\nprint(\"license:\", terms.license_text_link)\nprint(\"privacy:\", terms.privacy_policy_link)\nprint(\"marketplace:\", terms.marketplace_terms_link)\nprint(\"signature:\", terms.signature)\n```\n\n`AgreementTerms` includes the fields that are usually most useful in approval flows:\n\n- `accepted`\n- `license_text_link`\n- `privacy_policy_link`\n- `marketplace_terms_link`\n- `retrieve_datetime`\n- `signature`\n\n### Accept Terms\n\nIf the current terms are not yet accepted on the subscription, sign them:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nsigned_terms = client.marketplace_agreements.sign(\n    publisher_id=os.environ[\"AZURE_MARKETPLACE_PUBLISHER_ID\"],\n    offer_id=os.environ[\"AZURE_MARKETPLACE_OFFER_ID\"],\n    plan_id=os.environ[\"AZURE_MARKETPLACE_PLAN_ID\"],\n)\n\nprint(\"accepted:\", signed_terms.accepted)\nprint(\"accepted_at:\", signed_terms.retrieve_datetime)\n```\n\nMicrosoft's Marketplace deployment article says that once the EULA is accepted one time in an Azure subscription, you can deploy the same VM offer again in that subscription without accepting the terms again.\n\n### Fetch The Stored Agreement Resource\n\nUse `get_agreement()` when you want the stored agreement resource after acceptance. `agreement_id` is a required parameter, so fetch it from an existing agreement instead of guessing a placeholder value:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nagreement_id = None\nfor item in client.marketplace_agreements.list():\n    if (\n        item.publisher == os.environ[\"AZURE_MARKETPLACE_PUBLISHER_ID\"]\n        and item.product == os.environ[\"AZURE_MARKETPLACE_OFFER_ID\"]\n        and item.plan == os.environ[\"AZURE_MARKETPLACE_PLAN_ID\"]\n    ):\n        agreement_id = item.name\n        break\n\nif agreement_id is None:\n    raise RuntimeError(\"Agreement not found on this subscription\")\n\nagreement = client.marketplace_agreements.get_agreement(\n    publisher_id=os.environ[\"AZURE_MARKETPLACE_PUBLISHER_ID\"],\n    offer_id=os.environ[\"AZURE_MARKETPLACE_OFFER_ID\"],\n    plan_id=os.environ[\"AZURE_MARKETPLACE_PLAN_ID\"],\n    agreement_id=agreement_id,\n)\n\nprint(agreement.id)\nprint(agreement.name)\nprint(agreement.accepted)\n```\n\n### List Agreements On The Subscription\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor agreement in client.marketplace_agreements.list():\n    print(\n        agreement.publisher,\n        agreement.product,\n        agreement.plan,\n        agreement.accepted,\n    )\n```\n\n### Cancel Accepted Terms\n\nUse `cancel()` to remove the accepted terms record for a specific `publisher / offer / plan` tuple:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements\n\nclient = MarketplaceOrderingAgreements(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ncancelled_terms = client.marketplace_agreements.cancel(\n    publisher_id=os.environ[\"AZURE_MARKETPLACE_PUBLISHER_ID\"],\n    offer_id=os.environ[\"AZURE_MARKETPLACE_OFFER_ID\"],\n    plan_id=os.environ[\"AZURE_MARKETPLACE_PLAN_ID\"],\n)\n\nprint(\"accepted:\", cancelled_terms.accepted)\n```\n\n## Configuration Notes\n\n- `subscription_id` is required when constructing `MarketplaceOrderingAgreements`.\n- `get()` and `create()` take `offer_type`; `sign()`, `get_agreement()`, `list()`, and `cancel()` do not.\n- The package is an ARM management client. Use ARM credentials from `azure-identity`, not older `azure.common.credentials` patterns.\n- PyPI release notes for the `1.x` line call out the move to unified authentication with `azure-identity` and the removal of the older `config` attribute pattern on the client.\n- `AgreementTerms` fields are documented as server-populated and ignored when sending a request. For a normal acceptance flow, prefer `get()` plus `sign()` instead of trying to build and submit terms objects yourself.\n\n## Common Pitfalls\n\n- Using this package to discover Marketplace products. It only manages agreement terms for identifiers you already know.\n- Forgetting that `get()` needs `offer_type=\"virtualmachine\"` for Marketplace VM terms.\n- Accepting terms successfully, then forgetting to include the matching Marketplace `plan` when creating the VM.\n- Assuming one acceptance covers every plan from the same publisher. Terms are tracked per `publisher / offer / plan`.\n- Copying pre-`1.0.0` authentication examples that still use `azure.common.credentials` or `msrestazure`.\n- Assuming a successful token means the principal can accept or view agreements. Azure RBAC still applies at the subscription scope.\n\n## Version-Sensitive Notes For `1.1.0`\n\n- PyPI lists `1.1.0` as the stable release covered here.\n- PyPI release notes for `1.1.0` say `AgreementTerms` added `system_data` and `marketplace_terms_link`.\n- PyPI release notes for `1.0.0b1` introduced the modern Azure SDK credential model, async support under `aio`, `begin_` naming for long-running operations, and `azure.core.exceptions.HttpResponseError` instead of older `CloudError` patterns.\n- PyPI still labels the project with older Python classifiers and says it was tested with Python `2.7` and `3.4` through `3.7`. Treat those as package metadata from the release era, not as current Azure Python ecosystem guidance.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-marketplaceordering/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-marketplaceordering/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-marketplaceordering/azure.mgmt.marketplaceordering.marketplaceorderingagreements?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-marketplaceordering/azure.mgmt.marketplaceordering.operations.marketplaceagreementsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-marketplaceordering/azure.mgmt.marketplaceordering.models.agreementterms?view=azure-python\n- https://learn.microsoft.com/en-us/marketplace/programmatic-deploy-of-marketplace-products\n"
  },
  {
    "path": "content/azure/docs/mgmt-media/python/DOC.md",
    "content": "---\nname: mgmt-media\ndescription: \"Legacy Azure Media Services management SDK for Python for inspecting media accounts, assets, transforms, jobs, and streaming resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,media-services,management,video,streaming,encoding,python\"\n---\n\n# Azure Media Services Management SDK for Python\n\n## Golden Rule\n\nTreat `azure-mgmt-media` as a legacy management SDK. Microsoft still publishes the package and the Python API reference, but Azure Media Services retired on June 30, 2024. Do not start new Media Services integrations with this package. Use it only to understand or inventory older automation while you migrate away from Azure Media Services.\n\nThe current Microsoft retirement guidance says:\n\n- you cannot create new Azure Media Services accounts\n- after retirement, Media Services accounts become read-only for a limited period\n- expired accounts reject write operations such as `POST`, `PUT`, and `PATCH`\n- Microsoft later deletes the expired accounts\n\nThat retirement status matters more than the package version number.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-media==10.2.1\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-media==10.2.1\" azure-identity\npoetry add \"azure-mgmt-media==10.2.1\" azure-identity\n```\n\nPyPI lists `azure-mgmt-media 10.2.1` as a deprecated package and requires Python `>=3.7`.\n\n## Authentication And Setup\n\nThe official package readme shows `DefaultAzureCredential` with a subscription ID. In local scripts, `AzureCliCredential` is fine after `az login`. For service principal auth, set the usual Azure Identity variables.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you are authenticating with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.media import MediaManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = MediaManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nCLI-driven local script:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.media import MediaManagementClient\n\nclient = MediaManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## What This Package Is For\n\n`azure-mgmt-media` is the Azure Resource Manager client for Azure Media Services resources. In older codebases, you will usually see it used to:\n\n- inspect a Media Services account\n- enumerate assets that were uploaded or encoded earlier\n- inspect transforms and jobs\n- inspect streaming endpoints or streaming locators that already existed\n\nBecause the service is retired, the safe default in 2026 is read-oriented inventory and migration work, not creating new media workflows.\n\n## Core Read Workflows\n\n### Inspect a legacy Media Services account\n\nUse the account name under a resource group and read its ARM metadata:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.media import MediaManagementClient\n\nresource_group = \"example-rg\"\naccount_name = \"example-media-account\"\n\nclient = MediaManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\naccount = client.mediaservices.get(resource_group, account_name)\n\nprint(account.id)\nprint(account.location)\nprint(account.storage_accounts)\n```\n\nIf this call fails with `ResourceNotFoundError`, the account was likely already removed as part of the retirement process.\n\n### List existing assets\n\nAssets are the main inventory object for uploaded or encoded content:\n\n```python\nfor asset in client.assets.list(resource_group, account_name):\n    print(asset.name, asset.description)\n```\n\nRead one specific asset:\n\n```python\nasset = client.assets.get(resource_group, account_name, \"example-asset\")\nprint(asset.name)\nprint(asset.container)\n```\n\n### Inspect transforms and jobs\n\nTransforms describe encoding presets. Jobs represent work submitted against a transform.\n\n```python\nfor transform in client.transforms.list(resource_group, account_name):\n    print(transform.name, transform.description)\n```\n\n```python\ntransform_name = \"AdaptiveStreamingTransform\"\n\nfor job in client.jobs.list(resource_group, account_name, transform_name):\n    print(job.name, job.state)\n```\n\nThese inventory calls are useful when migrating old Media Services automation to another platform because they show which assets, transforms, and jobs your old account contained.\n\n## Historical Write Calls You May See In Older Code\n\nIf you are reading an older codebase, these are the main operation shapes you are likely to encounter:\n\n- `client.assets.create_or_update(...)`\n- `client.transforms.create_or_update(...)`\n- `client.jobs.create(...)`\n- `client.streaming_locators.create(...)`\n- `client.streaming_endpoints.begin_start(...)`\n\nDo not treat those as safe greenfield patterns in 2026. Microsoft’s retirement guidance says expired accounts reject write operations, so these calls are mainly relevant when you are reading or deleting legacy code.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-media` without `azure-identity`\n- Assuming the newest package release means the underlying Azure service is still available for new projects\n- Forgetting that `subscription_id` is required when building the client\n- Treating this package as a media upload or playback runtime SDK instead of an ARM management client\n- Expecting create or update operations to work after Azure Media Services retirement\n- Looking for new account creation flows even though Microsoft no longer allows new Azure Media Services accounts\n\n## Migration Notes\n\n- Prefer using this package to inventory old resources and scripts before you remove or replace them.\n- If your application still depends on Azure Media Services concepts such as assets, transforms, jobs, or streaming locators, plan a full service migration rather than a package upgrade.\n- Keep the retirement guide next to any maintenance work on this package so your team does not mistake it for an actively supported media platform.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-media/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/mgmt-media-readme?view=azure-python\n- https://learn.microsoft.com/en-us/azure/media-services/latest/azure-media-services-retirement\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.media/mediaservices/assets\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.media/mediaservices/transforms\n"
  },
  {
    "path": "content/azure/docs/mgmt-monitor/python/DOC.md",
    "content": "---\nname: mgmt-monitor\ndescription: \"Azure Monitor management SDK for Python for activity logs, metric alerts, action groups, data collection rules, and scheduled query rules\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-monitor,monitor,management,arm,alerts,metrics,observability\"\n---\n\n# Azure Monitor Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-monitor` for Azure Monitor control-plane work: creating and managing alerts, action groups, data collection rules, diagnostic settings, and related Azure Monitor resources. Do not use it for querying logs or metrics data at runtime; for that, use `azure-monitor-query` or `azure-monitor-querymetrics`.\n\nThis entry is pinned to the current stable PyPI release `7.0.0`. PyPI also lists `8.0.0b1` and `8.0.0b2` prereleases, so avoid copying preview examples into a `7.x` codebase unless the project is intentionally pinned to a beta.\n\n## Install\n\nInstall the management client together with `azure-identity`:\n\n```bash\npython -m pip install \"azure-mgmt-monitor==7.0.0\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-monitor==7.0.0\" \"azure-identity\"\npoetry add \"azure-mgmt-monitor==7.0.0\" \"azure-identity\"\n```\n\nNotes:\n\n- `azure-mgmt-monitor` is a management-plane SDK. It assumes you are provisioning or configuring Azure Monitor resources through Azure Resource Manager.\n- Install `azure-monitor-query` or `azure-monitor-querymetrics` separately if the same project also queries telemetry data.\n\n## Authentication And Setup\n\nUse Azure Identity credentials. These are the practical defaults:\n\n1. `AzureCliCredential()` for local scripts after `az login`\n2. `DefaultAzureCredential()` for reusable code that runs locally, in CI, and on Azure\n3. `ClientSecretCredential()` only when you know the runtime is service-principal based\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.monitor import MonitorManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = MonitorManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal development with explicit Azure CLI credentials:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.monitor import MonitorManagementClient\n\nclient = MonitorManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n## What This Client Covers\n\n`MonitorManagementClient` in `7.0.0` exposes a broad Azure Monitor management surface. High-value operation groups include:\n\n- `activity_logs`\n- `action_groups`\n- `activity_log_alerts`\n- `metric_alerts`\n- `scheduled_query_rules`\n- `diagnostic_settings`\n- `data_collection_rules`\n- `data_collection_endpoints`\n- `data_collection_rule_associations`\n- `azure_monitor_workspaces`\n\nPractical rule:\n\n- Use this package when the resource you are working with has an ARM resource ID and you are creating, listing, updating, or deleting Azure Monitor configuration.\n- Use the query packages when you need to fetch logs or metrics results for application logic.\n\n## Core Usage\n\n### Read recent activity log events\n\n`activity_logs.list()` requires an OData filter string. Build the filter explicitly instead of guessing parameter names.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nend_time = datetime.now(timezone.utc)\nstart_time = end_time - timedelta(hours=1)\n\nevent_data = client.activity_logs.list(\n    filter=(\n        \"eventTimestamp ge \"\n        f\"'{start_time.strftime('%Y-%m-%dT%H:%M:%SZ')}' \"\n        \"and eventTimestamp le \"\n        f\"'{end_time.strftime('%Y-%m-%dT%H:%M:%SZ')}'\"\n    )\n)\n\nfor item in event_data:\n    print(item.event_name.localized_value, item.resource_group_name)\n```\n\nCommon filters also include `resourceGroupName eq 'my-rg'`, `resourceProvider eq 'Microsoft.Compute'`, and `status eq 'Failed'`.\n\n### List data collection rules in a resource group\n\nUse data collection rules and data collection endpoints for Azure Monitor Agent and ingestion configuration. The `7.0.0` client includes first-class operation groups for them.\n\n```python\nrules = client.data_collection_rules.list_by_resource_group(\"example-rg\")\n\nfor rule in rules:\n    print(rule.name, rule.location, rule.id)\n```\n\nTo inspect one rule directly:\n\n```python\nrule = client.data_collection_rules.get(\n    resource_group_name=\"example-rg\",\n    data_collection_rule_name=\"example-dcr\",\n)\n\nprint(rule.immutable_id)\n```\n\n### Create or update a metric alert\n\nMetric alerts are one of the most common control-plane tasks. Use model classes instead of building ad hoc dictionaries when the payload is non-trivial.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.mgmt.monitor.models import (\n    MetricAlertAction,\n    MetricAlertResource,\n    MetricAlertSingleResourceMultipleMetricCriteria,\n    MetricCriteria,\n)\n\nresource_group_name = \"example-rg\"\nvm_id = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n    \"resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/example-vm\"\n)\naction_group_id = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n    \"resourceGroups/example-rg/providers/microsoft.insights/actionGroups/example-ag\"\n)\n\nalert = client.metric_alerts.create_or_update(\n    resource_group_name=resource_group_name,\n    rule_name=\"vm-cpu-high\",\n    parameters=MetricAlertResource(\n        location=\"global\",\n        description=\"Alert when average CPU is above 80 percent\",\n        severity=2,\n        enabled=True,\n        scopes=[vm_id],\n        evaluation_frequency=timedelta(minutes=1),\n        window_size=timedelta(minutes=5),\n        target_resource_type=\"Microsoft.Compute/virtualMachines\",\n        target_resource_region=\"westus2\",\n        criteria=MetricAlertSingleResourceMultipleMetricCriteria(\n            all_of=[\n                MetricCriteria(\n                    name=\"HighCpuCriterion\",\n                    metric_name=\"Percentage CPU\",\n                    metric_namespace=\"Microsoft.Compute/virtualMachines\",\n                    time_aggregation=\"Average\",\n                    operator=\"GreaterThan\",\n                    threshold=80,\n                )\n            ]\n        ),\n        actions=[MetricAlertAction(action_group_id=action_group_id)],\n        auto_mitigate=True,\n    ),\n)\n\nprint(alert.id)\n```\n\nPractical notes:\n\n- Metric alert resources live in Azure Monitor and typically use `location=\"global\"`.\n- `scopes` must contain full ARM resource IDs.\n- `metric_namespace`, `target_resource_type`, and `target_resource_region` should match the resource being monitored.\n\n### List scheduled query rules\n\nScheduled query rules are the management resource behind many log-search alerts:\n\n```python\nrules = client.scheduled_query_rules.list_by_resource_group(\"example-rg\")\n\nfor rule in rules:\n    print(rule.name, rule.enabled, rule.scopes)\n```\n\nIf you are starting from an application requirement like \"run a KQL query and return rows\", that is not a scheduled query rule problem. Use `azure-monitor-query` instead.\n\n### Configure diagnostic settings for a resource\n\nDiagnostic settings attach log and metric export configuration to an existing Azure resource ID:\n\n```python\nresource_uri = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n    \"resourceGroups/example-rg/providers/Microsoft.Storage/storageAccounts/examplestorage\"\n)\n\nsettings = client.diagnostic_settings.list(resource_uri)\n\nfor item in settings.value:\n    print(item.name)\n```\n\nThis surface is commonly used to route logs and metrics to Log Analytics workspaces, storage accounts, or Event Hubs.\n\n## Configuration Notes\n\n- `subscription_id` is required. The client does not infer it from the credential.\n- Management operations typically need Azure RBAC on the subscription, resource group, or target resource. Successful authentication is not enough.\n- Most write operations use ARM resource IDs in payloads. When a call asks for a `scope`, `resource_uri`, `target_resource_id`, or `action_group_id`, pass the full `/subscriptions/...` resource ID.\n- If you target sovereign clouds, keep the Azure Identity authority and the management endpoint aligned. Do not mix public-cloud credentials with a government or China ARM endpoint.\n\n## Version-Sensitive Notes\n\n### `7.0.0`\n\nPyPI release metadata for `7.0.0` documents a large management-surface expansion. New operation groups called out there include:\n\n- `action_groups`\n- `activity_log_alerts`\n- `activity_logs`\n- `alert_rule_incidents`\n- `alert_rules`\n- `autoscale_settings`\n- `baseline`\n- `data_collection_endpoints`\n- `data_collection_rule_associations`\n- `data_collection_rules`\n- `diagnostic_settings`\n- `metrics`\n- `scheduled_query_rules`\n\nTreat older `azure-mgmt-monitor` examples with care. Blog posts or archived samples from the `1.x` to `5.x` era often cover a much smaller API surface and may not reflect current model names or operation groups.\n\n### Prerelease `8.0.0b1` / `8.0.0b2`\n\nPyPI currently lists `8.0.0b1` and `8.0.0b2` as prereleases. Unless your project is intentionally testing those betas, keep production guidance pinned to `7.0.0`.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-monitor` when the task is actually logs query or metrics query at runtime\n- Installing the management client but forgetting `azure-identity`\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Passing short names where the SDK expects full ARM resource IDs\n- Treating `activity_logs.list()` like a simple list call and forgetting the required OData filter\n- Copying old Azure Monitor samples that predate the `7.0.0` operation-group expansion\n- Assuming every monitor resource belongs in the same Azure region; some alert resources are global while their target resources are regional\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-monitor/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/mgmt-monitor-readme?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.monitormanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.operations.activitylogsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.operations.datacollectionrulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.operations.metricalertsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.models.metricalertresource?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.models.metricalertsingleresourcemultiplemetriccriteria?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.models.metriccriteria?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-monitor/azure.mgmt.monitor.models.metricalertaction?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-netapp/python/DOC.md",
    "content": "---\nname: mgmt-netapp\ndescription: \"Azure NetApp Files management SDK for Python for NetApp accounts, capacity pools, volumes, snapshots, and quota inspection\"\nmetadata:\n  languages: \"python\"\n  versions: \"15.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,netapp,storage,arm,management,capacity-pools,volumes,snapshots\"\n---\n\n# Azure NetApp Files Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-netapp` for Azure Resource Manager control-plane work only: creating and updating NetApp accounts, capacity pools, volumes, snapshots, quotas, and related Azure NetApp Files resources. It does not mount or read file data. For `15.0.0`, pair it with `azure-identity`, pass the subscription ID explicitly, and expect most create, update, move, revert, and delete operations to be long-running `begin_*` calls that need `.result()`.\n\n## Install\n\nPyPI lists `azure-mgmt-netapp 15.0.0` as the latest release and requires Python 3.9+.\n\n```bash\npython -m pip install \"azure-mgmt-netapp==15.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-netapp==15.0.0\" azure-identity\npoetry add \"azure-mgmt-netapp==15.0.0\" azure-identity\n```\n\n## Prerequisites\n\nAzure NetApp Files has a few setup requirements before the SDK calls succeed:\n\n- Register the resource provider for the subscription:\n\n```bash\naz account set --subscription \"$AZURE_SUBSCRIPTION_ID\"\naz provider register --namespace Microsoft.NetApp --wait\naz provider show --namespace Microsoft.NetApp --query registrationState -o tsv\n```\n\n- Create or reuse a virtual network subnet delegated to `Microsoft.NetApp/volumes`.\n- Plan the delegated subnet size up front. Microsoft notes that `/28` is often too small and that only one delegated subnet can be used per VNet for Azure NetApp Files volume creation.\n- Create resources in hierarchy order: NetApp account -> capacity pool -> volume -> snapshot.\n\nEnvironment variables used in the examples:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_RESOURCE_GROUP=\"my-netapp-rg\"\nexport AZURE_LOCATION=\"eastus\"\nexport AZURE_NETAPP_ACCOUNT=\"my-anf-account\"\nexport AZURE_NETAPP_POOL=\"pool-premium\"\nexport AZURE_NETAPP_VOLUME=\"appdata\"\nexport AZURE_NETAPP_SUBNET_ID=\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/network-rg/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/anf-subnet\"\n```\n\nIf you authenticate with a service principal through environment variables, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\nFor reusable code, use `DefaultAzureCredential()`. For local scripts after `az login`, `AzureCliCredential()` is also fine.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.netapp import NetAppManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = NetAppManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can use:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.netapp import NetAppManagementClient\n\nclient = NetAppManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n`NetAppManagementClient` defaults to ARM API version `2025-09-01`. The Learn docs warn that overriding `api_version` may result in unsupported behavior.\n\n## Create An Account, Pool, And Volume\n\nThese are the main operations most apps need. Azure NetApp Files sizes are in bytes, so use helpers for GiB and TiB instead of hard-coding large integers.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.netapp import NetAppManagementClient\n\nGIB = 1024 ** 3\nTIB = 1024 ** 4\n\nresource_group = os.environ[\"AZURE_RESOURCE_GROUP\"]\nlocation = os.environ[\"AZURE_LOCATION\"]\naccount_name = os.environ[\"AZURE_NETAPP_ACCOUNT\"]\npool_name = os.environ[\"AZURE_NETAPP_POOL\"]\nvolume_name = os.environ[\"AZURE_NETAPP_VOLUME\"]\nsubnet_id = os.environ[\"AZURE_NETAPP_SUBNET_ID\"]\n\nclient = NetAppManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\naccount = client.accounts.begin_create_or_update(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    body={\n        \"location\": location,\n        \"properties\": {},\n    },\n).result()\n\npool = client.pools.begin_create_or_update(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    body={\n        \"location\": location,\n        \"properties\": {\n            \"qosType\": \"Auto\",\n            \"serviceLevel\": \"Premium\",\n            \"size\": 4 * TIB,\n        },\n    },\n).result()\n\nvolume = client.volumes.begin_create_or_update(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n    body={\n        \"location\": location,\n        \"properties\": {\n            \"creationToken\": \"appdata\",\n            \"serviceLevel\": \"Premium\",\n            \"subnetId\": subnet_id,\n            \"usageThreshold\": 100 * GIB,\n        },\n    },\n).result()\n\nprint(account.id)\nprint(pool.id)\nprint(volume.id)\nprint(volume.file_system_id)\n```\n\nImportant details from the official docs:\n\n- `properties.subnetId` must point to a delegated subnet with `Microsoft.NetApp/volumes`.\n- `properties.usageThreshold` is in bytes and must be a multiple of 1 GiB.\n- Current documented limits for regular volumes are 50 GiB minimum and 100 TiB maximum.\n- Current documented minimum capacity pool size is 1 TiB if all volumes in the pool use Standard network features; otherwise the minimum is 4 TiB.\n\n### Add Explicit NFSv4.1 Export Rules\n\nIf you want an explicit NFS export policy instead of relying on minimal defaults, add `protocolTypes` and `exportPolicy` to the volume payload:\n\n```python\nvolume = client.volumes.begin_create_or_update(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n    body={\n        \"location\": location,\n        \"properties\": {\n            \"creationToken\": \"appdata\",\n            \"serviceLevel\": \"Premium\",\n            \"subnetId\": subnet_id,\n            \"usageThreshold\": 100 * GIB,\n            \"protocolTypes\": [\"NFSv4.1\"],\n            \"exportPolicy\": {\n                \"rules\": [\n                    {\n                        \"ruleIndex\": 1,\n                        \"unixReadOnly\": True,\n                        \"unixReadWrite\": True,\n                        \"nfsv3\": False,\n                        \"nfsv41\": True,\n                        \"allowedClients\": \"10.0.0.0/24\",\n                        \"hasRootAccess\": True,\n                    }\n                ]\n            },\n        },\n    },\n).result()\n```\n\nFor manual QoS pools, Azure's REST examples show `qosType=\"Manual\"` with `serviceLevel=\"Flexible\"` and `customThroughputMibps`.\n\n## List And Inspect Resources\n\n```python\nfor account in client.accounts.list(resource_group):\n    print(\"account:\", account.name)\n\nfor pool in client.pools.list(resource_group, account_name):\n    print(\"pool:\", pool.name, pool.size)\n\nfor volume in client.volumes.list(resource_group, account_name, pool_name):\n    print(\"volume:\", volume.name, volume.provisioning_state)\n```\n\nThe official Azure sample notes that returned `.name` values for capacity pools, volumes, and snapshots can include the parent hierarchy, so do not assume `volume.name` is always the leaf name you can pass directly back into `get()`.\n\n## Snapshots And Restore\n\nCreate a snapshot:\n\n```python\nsnapshot = client.snapshots.begin_create(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n    snapshot_name=\"snap-001\",\n    body={\"location\": location},\n).result()\n\nprint(snapshot.id)\n```\n\nList snapshots for a volume:\n\n```python\nfor snapshot in client.snapshots.list(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n):\n    print(snapshot.name)\n```\n\nRevert a volume to a snapshot:\n\n```python\nclient.volumes.begin_revert(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n    body={\"snapshotId\": snapshot.id},\n).result()\n```\n\n## Move A Volume To Another Pool\n\nAzure NetApp Files exposes a dedicated pool-change operation instead of a generic patch for service-level moves:\n\n```python\ntarget_pool_id = (\n    f\"/subscriptions/{os.environ['AZURE_SUBSCRIPTION_ID']}\"\n    f\"/resourceGroups/{resource_group}\"\n    f\"/providers/Microsoft.NetApp/netAppAccounts/{account_name}\"\n    f\"/capacityPools/pool-premium-2\"\n)\n\nclient.volumes.begin_pool_change(\n    resource_group_name=resource_group,\n    account_name=account_name,\n    pool_name=pool_name,\n    volume_name=volume_name,\n    body={\"newPoolResourceId\": target_pool_id},\n).result()\n```\n\n`newPoolResourceId` must be the full ARM resource ID of the destination capacity pool.\n\n## Check Regional And Account Quotas\n\nRegion-level quota inspection:\n\n```python\nfor quota in client.net_app_resource_quota_limits.list(location):\n    print(quota.name)\n```\n\nAccount-level quota inspection:\n\n```python\nfor quota in client.net_app_resource_quota_limits_account.list(\n    resource_group_name=resource_group,\n    account_name=account_name,\n):\n    print(quota.name)\n```\n\nThe current Learn docs say account-level quota listing is mainly for quotas under the account, and currently `PoolsPerAccount` is the primary one exposed there.\n\n## Common Pitfalls\n\n- This package is management plane only. It provisions Azure NetApp Files resources but does not mount NFS or SMB shares.\n- Forgetting to register `Microsoft.NetApp` is a common setup failure.\n- Volume creation fails unless the subnet is delegated to `Microsoft.NetApp/volumes`.\n- Azure NetApp Files resource sizes use bytes, not GiB strings.\n- Many operations are long-running. Call `.result()` before using the created resource in the next step.\n- Delete in reverse hierarchy order: snapshots -> volumes -> pools -> accounts.\n- Volume, pool, and snapshot `.name` values can include parent segments; keep your own leaf names instead of relying on returned display names.\n\n## Version-Sensitive Notes\n\n### `15.0.0`\n\nPyPI release history for `15.0.0` calls out these relevant changes:\n\n- `NetAppManagementClient` adds the `ransomware_reports` operation group.\n- `VolumesOperations` adds `begin_list_quota_report`.\n- Several ransomware-protection related models and enums were added.\n- The release also notes a breaking change: a model named `Type` was deleted or renamed.\n\nIf you copy older examples that predate `15.0.0`, do not assume quota-report or ransomware-report APIs are available.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-netapp/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.netappmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.accountsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.poolsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.volumesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.snapshotsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.netappresourcequotalimitsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-netapp/azure.mgmt.netapp.operations.netappresourcequotalimitsaccountoperations?view=azure-python\n- https://learn.microsoft.com/en-us/rest/api/netapp/accounts/create-or-update?view=rest-netapp-2025-09-01\n- https://learn.microsoft.com/en-us/rest/api/netapp/pools/create-or-update?view=rest-netapp-2025-06-01\n- https://learn.microsoft.com/en-us/rest/api/netapp/volumes/create-or-update?view=rest-netapp-2025-09-01\n- https://learn.microsoft.com/en-us/rest/api/netapp/volumes/pool-change?view=rest-netapp-2025-09-01\n- https://learn.microsoft.com/en-us/rest/api/netapp/volumes/revert?view=rest-netapp-2025-09-01\n- https://learn.microsoft.com/en-us/rest/api/netapp/snapshots/create?view=rest-netapp-2025-09-01\n- https://learn.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-register\n- https://learn.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-delegate-subnet\n- https://learn.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-resource-limits\n- https://learn.microsoft.com/en-us/samples/azure-samples/netappfiles-python-sdk-sample/azure-netappfiles-sdk-sample-for-python/\n"
  },
  {
    "path": "content/azure/docs/mgmt-network/python/DOC.md",
    "content": "---\nname: mgmt-network\ndescription: \"Azure Network management SDK for Python for virtual networks, subnets, NSGs, public IPs, NICs, load balancers, and other ARM networking resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"30.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,network,arm,virtual-network,subnet,nsg,public-ip,nic\"\n---\n\n# Azure Network Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-network` for Azure networking management-plane work through Azure Resource Manager, not for data-plane traffic or socket-level networking. Install `azure-identity` with it, authenticate with a `TokenCredential`, pass `AZURE_SUBSCRIPTION_ID` explicitly, and expect most create, update, and delete calls to be `begin_*` long-running operations that need `.result()`.\n\n## Install\n\nPin the package version your project expects and install an Azure credential package alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-network==30.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-network==30.2.0\" azure-identity\npoetry add \"azure-mgmt-network==30.2.0\" azure-identity\n```\n\n## Authentication And Setup\n\nFor most projects, use one of these patterns:\n\n- `DefaultAzureCredential()` for reusable code that should work locally, in CI, and on Azure\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.network import NetworkManagementClient\n\nclient = NetworkManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nCLI-driven local setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.network import NetworkManagementClient\n\nclient = NetworkManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nFor sovereign clouds or custom ARM endpoints, align your credential authority and client cloud/base URL settings rather than assuming the public Azure cloud defaults.\n\n## Core Usage Patterns\n\nThe main operation groups agents usually need are:\n\n- `virtual_networks`\n- `subnets`\n- `network_security_groups`\n- `public_ip_addresses`\n- `network_interfaces`\n- `load_balancers`\n- `route_tables`\n\nTwo SDK behaviors matter everywhere in this package:\n\n- Most write operations are `begin_*` calls that return a poller. Call `.result()` before using the created resource.\n- Most `list*` methods return paged iterators. Iterate over them instead of assuming a materialized list.\n\n### List virtual networks in a resource group\n\n```python\nfor vnet in client.virtual_networks.list(\"my-resource-group\"):\n    print(vnet.name, vnet.location)\n```\n\n### Create a virtual network and an initial subnet\n\n```python\nfrom azure.mgmt.network.models import AddressSpace, Subnet, VirtualNetwork\n\nvnet = client.virtual_networks.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    virtual_network_name=\"my-vnet\",\n    parameters=VirtualNetwork(\n        location=\"eastus\",\n        address_space=AddressSpace(address_prefixes=[\"10.0.0.0/16\"]),\n        subnets=[\n            Subnet(\n                name=\"default\",\n                address_prefix=\"10.0.1.0/24\",\n            )\n        ],\n    ),\n).result()\n\nprint(vnet.id)\n```\n\nPractical notes:\n\n- `VirtualNetwork.location` is required.\n- Keep address spaces and subnet CIDRs non-overlapping.\n- Use `client.subnets.begin_create_or_update(...)` later when you need to add or change a subnet independently of the VNet.\n\n### Create or update a subnet after the VNet exists\n\n```python\nfrom azure.mgmt.network.models import Subnet\n\nsubnet = client.subnets.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    virtual_network_name=\"my-vnet\",\n    subnet_name=\"app-subnet\",\n    subnet_parameters=Subnet(address_prefix=\"10.0.2.0/24\"),\n).result()\n\nprint(subnet.id)\n```\n\n### Create a network security group with an inbound rule\n\n```python\nfrom azure.mgmt.network.models import NetworkSecurityGroup, SecurityRule\n\nnsg = client.network_security_groups.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    network_security_group_name=\"web-nsg\",\n    parameters=NetworkSecurityGroup(\n        location=\"eastus\",\n        security_rules=[\n            SecurityRule(\n                name=\"allow-https-in\",\n                protocol=\"Tcp\",\n                source_port_range=\"*\",\n                destination_port_range=\"443\",\n                source_address_prefix=\"*\",\n                destination_address_prefix=\"*\",\n                access=\"Allow\",\n                priority=200,\n                direction=\"Inbound\",\n            )\n        ],\n    ),\n).result()\n\nprint(nsg.id)\n```\n\nImportant `SecurityRule` fields to set explicitly:\n\n- `protocol`\n- `source_port_range` or `source_port_ranges`\n- `destination_port_range` or `destination_port_ranges`\n- `source_address_prefix` or `source_address_prefixes`\n- `destination_address_prefix` or `destination_address_prefixes`\n- `access`\n- `priority`\n- `direction`\n\nAzure enforces rule uniqueness by priority and direction within the NSG. Pick priorities carefully instead of copying the same value into every rule.\n\n### Create a public IP address\n\n```python\nfrom azure.mgmt.network.models import PublicIPAddress\n\npublic_ip = client.public_ip_addresses.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    public_ip_address_name=\"my-public-ip\",\n    parameters=PublicIPAddress(\n        location=\"eastus\",\n        public_ip_allocation_method=\"Static\",\n        sku={\"name\": \"Standard\"},\n    ),\n).result()\n\nprint(public_ip.ip_address)\n```\n\nBe careful with SKU and allocation choices. Standard public IPs are the common modern default; older Basic examples are not the safest template to copy forward.\n\n### Create a network interface attached to a subnet and public IP\n\n```python\nnic = client.network_interfaces.begin_create_or_update(\n    resource_group_name=\"my-resource-group\",\n    network_interface_name=\"my-nic\",\n    parameters={\n        \"location\": \"eastus\",\n        \"network_security_group\": {\"id\": nsg.id},\n        \"ip_configurations\": [\n            {\n                \"name\": \"primary\",\n                \"subnet\": {\"id\": subnet.id},\n                \"public_ip_address\": {\"id\": public_ip.id},\n                \"private_ip_allocation_method\": \"Dynamic\",\n                \"primary\": True,\n            }\n        ],\n    },\n).result()\n\nprint(nic.id)\n```\n\nThis is the usual handoff point for VM creation in `azure-mgmt-compute`: create the NIC first with `azure-mgmt-network`, then pass the NIC resource ID into the compute VM payload.\n\n## Async Usage\n\nThe package also exposes `azure.mgmt.network.aio.NetworkManagementClient`. Use it only when the rest of the application is already async.\n\n```python\nimport os\nimport asyncio\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.mgmt.network.aio import NetworkManagementClient\n\nasync def main():\n    credential = DefaultAzureCredential()\n    client = NetworkManagementClient(\n        credential=credential,\n        subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n    )\n\n    try:\n        async for vnet in client.virtual_networks.list(\"my-resource-group\"):\n            print(vnet.name)\n    finally:\n        await client.close()\n        await credential.close()\n\nasyncio.run(main())\n```\n\nFor async write calls, `await` the `begin_*` call first and then `await poller.result()`.\n\n## Configuration Notes\n\n- `subscription_id` is required. The credential does not supply it automatically.\n- This package manages ARM resources, so the caller needs Azure RBAC on the subscription, resource group, or resource scope in addition to successful authentication.\n- Resource groups must already exist. Create them with `azure-mgmt-resource` or through deployment tooling before creating network resources here.\n- Keep regions aligned across related resources. VNets, NICs, public IPs, load balancers, and VMs often fail validation when regions or dependent IDs do not match.\n- Long-running operations can take noticeable time. Treat `.result()` as a real wait point and handle timeouts or eventual consistency in automation.\n\n## Version-Sensitive Notes For 30.2.0\n\n- PyPI lists `30.2.0` as the current release, published on `2026-02-11`.\n- PyPI states the package targets Python `>=3.9`.\n- The current Learn API reference documents both sync and async clients in the `azure.mgmt.network` and `azure.mgmt.network.aio` namespaces.\n- Track 2 Azure authentication patterns apply here: use `azure-identity` credentials, not older Track 1 auth helpers such as `ServicePrincipalCredentials`.\n- Older blog posts often show inline dictionaries copied from much older API versions. For `30.2.0`, verify model names and operation-group locations against the current Learn reference before copying them.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-network` without `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Confusing management-plane resource provisioning with data-plane traffic handling\n- Treating `begin_*` methods as synchronous and skipping `.result()`\n- Reusing overlapping CIDR blocks across VNets and subnets\n- Creating NSG rules with duplicate priorities or the wrong direction\n- Building a NIC before the referenced subnet, NSG, or public IP exists\n- Mixing public-cloud defaults with sovereign-cloud credentials or endpoints\n\n## Recommended Workflow For Coding Agents\n\n1. Confirm the task is ARM networking management, not service-specific data-plane access.\n2. Create or locate the resource group first.\n3. Authenticate with `DefaultAzureCredential` or a narrower Azure Identity credential.\n4. Build dependencies in order: VNet, subnet, NSG/public IP, NIC, then compute or load-balancer resources that depend on them.\n5. Prefer explicit models or documented field names from Learn pages over ad hoc dictionaries copied from third-party snippets.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-network/\n- https://pypi.org/pypi/azure-mgmt-network/json\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.networkmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.aio.networkmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.operations.virtualnetworksoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.operations.subnetsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.operations.networksecuritygroupsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.operations.publicipaddressesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.operations.networkinterfacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.virtualnetwork?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.addressspace?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.subnet?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.networksecuritygroup?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.securityrule?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.publicipaddress?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.models.networkinterface?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-notificationhubs/python/DOC.md",
    "content": "---\nname: mgmt-notificationhubs\ndescription: \"Azure Notification Hubs management-plane SDK for Python for namespaces, notification hubs, access policies, and PNS credentials\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,notification-hubs,arm,management,push-notifications,python\"\n---\n\n# Azure Notification Hubs Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-notificationhubs` for Azure Resource Manager control-plane work only: create namespaces, create notification hubs, manage SAS authorization rules, and configure or inspect platform notification service credentials.\n\nDo not use this package to send push notifications to devices or manage installations and registrations. The current Microsoft Learn Python send tutorial uses direct REST calls and explicitly notes that there is no officially supported Azure Notification Hubs Python SDK for that data-plane workflow.\n\n## Install\n\nInstall the management SDK and an Azure credential package together:\n\n```bash\npython -m pip install \"azure-mgmt-notificationhubs==8.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-notificationhubs==8.0.0\" azure-identity\npoetry add \"azure-mgmt-notificationhubs==8.0.0\" azure-identity\n```\n\nMinimum environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\nUse `DefaultAzureCredential` for reusable code, CI, managed identity, or workload identity. Use `AzureCliCredential` for local scripts after `az login`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.notificationhubs import NotificationHubsManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = NotificationHubsManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.notificationhubs import NotificationHubsManagementClient\n\nclient = NotificationHubsManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nDo not copy older `azure.common.credentials.UserPassCredentials` examples from stale overview pages. The current client constructor requires an `azure-core` `TokenCredential`, which in practice means using `azure-identity`.\n\n## Core Workflows\n\n### Check namespace name availability\n\nNamespace names must be unique. Check first instead of learning from a failed create call.\n\n```python\nfrom azure.mgmt.notificationhubs.models import CheckAvailabilityParameters\n\nnamespace_name = \"ctxhub-ns-demo\"\n\navailability = client.namespaces.check_availability(\n    CheckAvailabilityParameters(name=namespace_name)\n)\n\nif not availability.is_availiable:\n    raise RuntimeError(\"Namespace name is not available\")\n```\n\nThe response field is spelled `is_availiable` in the generated SDK. Use the exact attribute name.\n\n### Create a namespace\n\n```python\nfrom azure.mgmt.notificationhubs.models import (\n    NamespaceCreateOrUpdateParameters,\n    Sku,\n)\n\nnamespace = client.namespaces.create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    parameters=NamespaceCreateOrUpdateParameters(\n        location=\"eastus\",\n        namespace_type=\"NotificationHub\",\n        sku=Sku(name=\"Free\"),\n    ),\n)\n\nprint(namespace.id)\n```\n\nUse `Sku(name=\"Standard\")` when you need the Standard tier. Keep the namespace `location` aligned with the region where you intend to run the Notification Hubs resource.\n\n### Create a notification hub\n\n```python\nfrom azure.mgmt.notificationhubs.models import NotificationHubCreateOrUpdateParameters\n\nhub_name = \"orders-mobile\"\n\nhub = client.notification_hubs.create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    notification_hub_name=hub_name,\n    parameters=NotificationHubCreateOrUpdateParameters(\n        location=\"eastus\",\n    ),\n)\n\nprint(hub.id)\n```\n\nThis creates the hub resource only. Platform credentials for APNS, WNS, ADM, Baidu, or Google are configured separately.\n\n### Create a hub-level SAS rule and read its keys\n\nUse hub-level authorization rules when an application should be scoped to one notification hub instead of the whole namespace.\n\n```python\nfrom azure.mgmt.notificationhubs.models import (\n    SharedAccessAuthorizationRuleCreateOrUpdateParameters,\n    SharedAccessAuthorizationRuleProperties,\n)\n\nrule_name = \"send-listen\"\n\nclient.notification_hubs.create_or_update_authorization_rule(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    notification_hub_name=hub_name,\n    authorization_rule_name=rule_name,\n    parameters=SharedAccessAuthorizationRuleCreateOrUpdateParameters(\n        properties=SharedAccessAuthorizationRuleProperties(\n            rights=[\"Listen\", \"Send\"],\n        )\n    ),\n)\n\nkeys = client.notification_hubs.list_keys(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    notification_hub_name=hub_name,\n    authorization_rule_name=rule_name,\n)\n\nprint(keys.primary_connection_string)\n```\n\nDo not ship a rule with `Manage` rights to untrusted clients. For device-facing or app-facing code, keep rights as narrow as possible.\n\n### Configure WNS credentials on an existing hub\n\nPatch only the fields you intend to change. The stable `8.0.0` client exposes `patch` on `notification_hubs`.\n\n```python\nimport os\n\nfrom azure.mgmt.notificationhubs.models import (\n    NotificationHubPatchParameters,\n    WnsCredential,\n)\n\nclient.notification_hubs.patch(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    notification_hub_name=hub_name,\n    parameters=NotificationHubPatchParameters(\n        wns_credential=WnsCredential(\n            package_sid=os.environ[\"WNS_PACKAGE_SID\"],\n            secret_key=os.environ[\"WNS_SECRET_KEY\"],\n            windows_live_endpoint=\"https://login.live.com/accesstoken.srf\",\n        ),\n    ),\n)\n```\n\nTo inspect the currently configured platform credentials:\n\n```python\npns = client.notification_hubs.get_pns_credentials(\n    resource_group_name=\"example-rg\",\n    namespace_name=namespace_name,\n    notification_hub_name=hub_name,\n)\n\nprint(pns.wns_credential is not None)\nprint(pns.apns_credential is not None)\nprint(pns.gcm_credential is not None)\n```\n\nThe same patch model also exposes `adm_credential`, `apns_credential`, `baidu_credential`, and `gcm_credential`.\n\n## Configuration Notes\n\n- `NotificationHubsManagementClient` requires `subscription_id`; it is not inferred from the credential.\n- The stable `8.0.0` client exposes two main operation groups: `namespaces` and `notification_hubs`.\n- Namespace and hub authorization rules are different resources. Use the matching `list_keys` call for the scope you created.\n- Management-plane success still depends on Azure RBAC. A valid token is not enough if the principal cannot create or update `Microsoft.NotificationHubs/*` resources.\n- Store connection strings, PNS secrets, and certificate material outside source control. Treat them as secrets.\n\n## Version-Sensitive Notes For `8.0.0`\n\n- The `7.0.0b1` generation change introduced the current shape used by `8.0.0`: `azure-identity` credentials, the `credential=` client argument, keyword-only model constructors, and imports from `azure.mgmt.notificationhubs.models`.\n- PyPI release notes for `8.0.0` call out a breaking change in `NamespacesOperations.list_keys`, which now returns `ResourceListKeys`. If older code expects the pre-`8.0.0` return shape, update it before upgrading.\n- The stable `8.0.0` model index exposes `gcm_credential` and documents it against the legacy FCM send endpoint surface. Do not assume the package has a separate dedicated FCM v1 credential model in this version without checking newer docs first.\n\n## Common Pitfalls\n\n- Treating `azure-mgmt-notificationhubs` as a send SDK instead of a provisioning SDK\n- Reusing stale `azure.common.credentials` examples instead of `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Missing the generated attribute typo `is_availiable` when checking namespace availability\n- Creating wide `Manage` SAS rules when `Listen` or `Send` would be enough\n- Assuming Google push setup in this package matches newer FCM v1 terminology\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-notificationhubs/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-notificationhubs/azure.mgmt.notificationhubs.notificationhubsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-notificationhubs/azure.mgmt.notificationhubs.operations.namespacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-notificationhubs/azure.mgmt.notificationhubs.operations.notificationhubsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-notificationhubs/azure.mgmt.notificationhubs.models?view=azure-python\n- https://azuresdkdocs.z19.web.core.windows.net/python/azure-mgmt-notificationhubs/8.0.0/azure.mgmt.notificationhubs.models.html\n- https://pypi.org/project/azure-mgmt-notificationhubs/8.0.0/\n- https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-python-push-notification-tutorial\n- https://learn.microsoft.com/en-us/azure/notification-hubs/manage-notification-hubs-namespace\n"
  },
  {
    "path": "content/azure/docs/mgmt-policyinsights/python/DOC.md",
    "content": "---\nname: mgmt-policyinsights\ndescription: \"Azure Policy Insights management SDK for Python for policy state queries, compliance summaries, remediation jobs, and policy restriction checks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,policy,policy-insights,compliance,remediation,governance,python\"\n---\n\n# Azure Policy Insights SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-policyinsights` for Azure Policy compliance and remediation workflows after a policy or initiative is already assigned. It is a management-plane SDK for querying policy states and events, triggering reevaluation scans, creating remediation jobs, and checking what Azure Policy would deny before you create a resource.\n\nFor `1.0.0`, pair it with `azure-identity` and the modern `credential=` constructor. Older examples that use `azure.common.credentials`, `CloudError`, or non-`begin_` long-running methods are from the pre-`1.0.0` client line.\n\n## Install\n\n```bash\npython -m pip install \"azure-mgmt-policyinsights==1.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-policyinsights==1.0.0\" azure-identity\npoetry add \"azure-mgmt-policyinsights==1.0.0\" azure-identity\n```\n\n## Authentication And Setup\n\nFor local development, sign in with Azure CLI:\n\n```bash\naz login\naz account set --subscription \"<subscription-id-or-name>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nFor service principal authentication, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nMinimal client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.policyinsights import PolicyInsightsClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = PolicyInsightsClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\n`PolicyInsightsClient` requires `subscription_id` even when the credential comes from Azure CLI, managed identity, or another `azure-identity` credential.\n\n## What The Client Exposes\n\nThe stable `1.0.0` client exposes these main operation groups:\n\n- `policy_states`\n- `policy_events`\n- `remediations`\n- `policy_tracked_resources`\n- `policy_metadata`\n- `policy_restrictions`\n\nThe most common entry points are `policy_states`, `policy_events`, `remediations`, and `policy_restrictions`.\n\n## Query Compliance State\n\nUse policy states when you need the current or historical compliance records for resources.\n\n- `\"latest\"` returns the latest policy state in the requested scope\n- `\"default\"` returns all policy state records in the requested time window\n\n`QueryOptions` supports `top`, `filter`, `order_by`, `select`, `from_property`, `to`, `apply`, `skip_token`, and `expand`.\n\n### List the latest non-compliant resources in a subscription\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.policyinsights import PolicyInsightsClient\nfrom azure.mgmt.policyinsights.models import QueryOptions\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = PolicyInsightsClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\npages = client.policy_states.list_query_results_for_subscription(\n    policy_states_resource=\"latest\",\n    subscription_id=subscription_id,\n    query_options=QueryOptions(\n        filter=\"ComplianceState eq 'NonCompliant'\",\n        order_by=\"Timestamp desc\",\n        top=20,\n    ),\n)\n\nfor page in pages:\n    for state in page.value or []:\n        print(state.resource_id)\n        print(state.policy_assignment_name)\n        print(state.policy_definition_name)\n        print(state.compliance_state)\n        print(state.timestamp)\n```\n\n### Query one resource directly\n\nIf you already know the ARM resource ID, query that resource instead of the whole subscription:\n\n```python\nresource_id = (\n    \"/subscriptions/<subscription-id>/resourceGroups/example-rg/\"\n    \"providers/Microsoft.Storage/storageAccounts/examplestorage\"\n)\n\npages = client.policy_states.list_query_results_for_resource(\n    policy_states_resource=\"latest\",\n    resource_id=resource_id,\n)\n\nfor page in pages:\n    for state in page.value or []:\n        print(state.resource_id, state.compliance_state)\n```\n\n### Summarize compliance counts\n\nUse `summarize_*` when you need counts, not raw records:\n\n```python\nsummary = client.policy_states.summarize_for_subscription(\n    subscription_id=subscription_id,\n    query_options=QueryOptions(filter=\"ComplianceState eq 'NonCompliant'\"),\n)\n\nfor item in summary.value or []:\n    results = item.results\n    print(\"non_compliant_resources:\", results.non_compliant_resources)\n    print(\"non_compliant_policies:\", results.non_compliant_policies)\n\n    for detail in results.policy_details or []:\n        print(detail.compliance_state, detail.count)\n```\n\nThe response shape is `SummarizeResults`, whose `value` contains one summary object with `results`.\n\n## Query Policy Evaluation Events\n\nUse policy events when you need evaluation history tied to resource operations rather than the current compliance snapshot.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom azure.mgmt.policyinsights.models import QueryOptions\n\nwindow_end = datetime.now(timezone.utc)\nwindow_start = window_end - timedelta(hours=24)\n\npages = client.policy_events.list_query_results_for_resource_group(\n    subscription_id=subscription_id,\n    resource_group_name=\"example-rg\",\n    query_options=QueryOptions(\n        from_property=window_start,\n        to=window_end,\n        order_by=\"Timestamp desc\",\n        top=50,\n    ),\n)\n\nfor page in pages:\n    for event in page.value or []:\n        print(event.timestamp)\n        print(event.resource_id)\n        print(event.policy_assignment_name)\n        print(event.compliance_state)\n        print(event.principal_oid)\n```\n\n`from_property` is the correct argument name in Python because `from` is a reserved keyword.\n\n## Trigger A Fresh Evaluation Scan\n\nAzure Policy data is not instant. If you need an updated compliance snapshot before querying policy states, trigger a reevaluation first.\n\nFor a whole subscription:\n\n```python\npoller = client.policy_states.begin_trigger_subscription_evaluation(\n    subscription_id=subscription_id,\n)\npoller.result()\n```\n\nFor one resource group:\n\n```python\npoller = client.policy_states.begin_trigger_resource_group_evaluation(\n    subscription_id=subscription_id,\n    resource_group_name=\"example-rg\",\n)\npoller.result()\n```\n\nThese are long-running operations and return `LROPoller[None]`.\n\n## Create And Inspect Remediation Jobs\n\nUse remediations when a policy assignment uses a `deployIfNotExists` or `modify` effect and you want Azure to fix existing non-compliant resources.\n\n### Create a remediation at subscription scope\n\n```python\nfrom azure.mgmt.policyinsights.models import Remediation\n\npolicy_assignment_id = (\n    f\"/subscriptions/{subscription_id}\"\n    \"/providers/Microsoft.Authorization/policyAssignments/enforce-tags\"\n)\n\nremediation = client.remediations.create_or_update_at_subscription(\n    remediation_name=\"enforce-tags-remediation\",\n    parameters=Remediation(\n        policy_assignment_id=policy_assignment_id,\n        resource_discovery_mode=\"ExistingNonCompliant\",\n    ),\n)\n\nprint(remediation.id)\nprint(remediation.name)\nprint(remediation.provisioning_state)\n```\n\nIf the assignment targets an initiative, set `policy_definition_reference_id` to the specific definition reference inside that initiative.\n\n### Reevaluate compliance before remediation\n\nUse `resource_discovery_mode=\"ReEvaluateCompliance\"` when you want Azure Policy to reevaluate resources instead of using the existing compliance snapshot:\n\n```python\nremediation = client.remediations.create_or_update_at_subscription(\n    remediation_name=\"recheck-and-remediate\",\n    parameters=Remediation(\n        policy_assignment_id=policy_assignment_id,\n        resource_discovery_mode=\"ReEvaluateCompliance\",\n    ),\n)\n```\n\n### Check remediation status later\n\n```python\ncurrent = client.remediations.get_at_subscription(\n    remediation_name=\"enforce-tags-remediation\",\n)\n\nprint(current.provisioning_state)\nprint(current.deployment_status)\n```\n\nYou can also list existing remediations with `client.remediations.list_for_subscription()`.\n\n## Check What Azure Policy Would Deny Before Creating A Resource\n\nUse policy restrictions to evaluate a planned resource shape before calling the resource provider.\n\n```python\nfrom azure.mgmt.policyinsights.models import (\n    CheckRestrictionsRequest,\n    CheckRestrictionsResourceDetails,\n    PendingField,\n)\n\nrequest = CheckRestrictionsRequest(\n    resource_details=CheckRestrictionsResourceDetails(\n        api_version=\"2023-05-01\",\n        resource_content={\n            \"type\": \"Microsoft.Storage/storageAccounts\",\n            \"name\": \"examplestorageacct\",\n            \"location\": \"westus2\",\n            \"kind\": \"StorageV2\",\n            \"sku\": {\"name\": \"Standard_LRS\"},\n            \"properties\": {},\n        },\n    ),\n    pending_fields=[\n        PendingField(field=\"location\", values=[\"westus2\", \"eastus2\"]),\n        PendingField(\n            field=\"Microsoft.Storage/storageAccounts/sku.name\",\n            values=[\"Standard_LRS\", \"Standard_GRS\"],\n        ),\n    ],\n)\n\nresult = client.policy_restrictions.check_at_subscription_scope(parameters=request)\n\nfor restriction in result.field_restrictions or []:\n    print(restriction.field)\n    print(restriction.values)\n```\n\nIf you already know the target resource group, use `check_at_resource_group_scope(resource_group_name=..., parameters=request)` instead.\n\n`resource_content` can be partial, but it needs to be realistic enough for Azure Policy to evaluate the fields your assignments care about. If the resource is a child resource, set `scope` on `CheckRestrictionsResourceDetails` to the parent resource ID.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-policyinsights` and forgetting `azure-identity`\n- Passing old `credentials=` arguments copied from pre-`1.0.0` samples instead of `credential=...`\n- Using `\"default\"` for all queries when you only need the current compliance snapshot; `\"latest\"` is usually the better default\n- Using `from=` in Python code instead of `from_property=...` in `QueryOptions`\n- Iterating the query iterator as if each item were a single policy record; the iterator yields result objects whose `.value` contains the records\n- Creating a remediation without the full policy assignment resource ID\n- Forgetting `policy_definition_reference_id` when remediating one definition inside an initiative assignment\n- Expecting remediation to fix `deny` or `audit` policies; remediation is for remediable effects such as `deployIfNotExists` and `modify`\n- Expecting newly assigned policies to appear immediately in policy state queries without waiting for evaluation or triggering a scan\n\n## Version Notes For `1.0.0`\n\n- PyPI lists `azure-mgmt-policyinsights 1.0.0` as released on January 4, 2021.\n- The `1.0.0` release added `PolicyRestrictionsOperations`.\n- The `1.0.0b1` line introduced the modern Azure SDK patterns this guide uses: `azure-identity` credentials, `credential=` instead of `credentials=`, `azure.core.exceptions.HttpResponseError`, `begin_` long-running methods, and official async support in the `aio` namespace.\n- Older blog posts and snippets from the `0.x` package line are often wrong for `1.0.0` if they use deprecated auth imports or older long-running method names.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-policyinsights/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.policyinsightsclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.operations.policystatesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.operations.policyeventsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.operations.remediationsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.operations.policyrestrictionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.models.queryoptions?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.models.remediation?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.models.checkrestrictionsrequest?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-policyinsights/azure.mgmt.policyinsights.models.pendingfield?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-privatedns/python/DOC.md",
    "content": "---\nname: mgmt-privatedns\ndescription: \"Azure Private DNS management SDK for Python for private zones, virtual network links, and record sets\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,private-dns,dns,arm,management,virtual-network-links,python\"\n---\n\n# Azure Private DNS Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-privatedns` for Azure Resource Manager management of Azure Private DNS zones, virtual network links, and record sets. This is a management-plane SDK, not a DNS resolver for application queries. Zone names are passed without a trailing dot, and records in a private zone are only resolvable from virtual networks linked to that zone.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-privatedns==1.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-privatedns==1.2.0\" azure-identity\npoetry add \"azure-mgmt-privatedns==1.2.0\" azure-identity\n```\n\n`azure-mgmt-privatedns 1.2.0` requires Python 3.8 or later.\n\n## Authentication And Setup\n\nThe package docs show `DefaultAzureCredential` with `AZURE_SUBSCRIPTION_ID`. If you authenticate with a service principal directly, also set the standard Azure identity variables.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nCommon service-principal environment:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.privatedns import PrivateDnsManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = PrivateDnsManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nThe current Learn reference shows these main operation groups on the client:\n\n- `private_zones`\n- `virtual_network_links`\n- `record_sets`\n\nThe client defaults to ARM endpoint `https://management.azure.com` and API version `2024-06-01`. The Learn reference warns that overriding the API version may result in unsupported behavior.\n\n## Core Usage\n\nImport the model types you will send to the service:\n\n```python\nfrom azure.mgmt.privatedns.models import (\n    ARecord,\n    PrivateZone,\n    RecordSet,\n    SubResource,\n    VirtualNetworkLink,\n)\n```\n\n### Create a private zone\n\nPrivate zones are global Azure resources. Use a multi-label zone name such as `private.contoso.com`, not a single label such as `contoso`.\n\n```python\nzone = client.private_zones.begin_create_or_update(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    parameters=PrivateZone(\n        tags={\"env\": \"dev\"},\n    ),\n    if_none_match=\"*\",\n).result()\n\nprint(zone.id)\nprint(zone.etag)\n```\n\n`if_none_match=\"*\"` makes this create-only. Omit it if you want an upsert.\n\n### Link a virtual network to the zone\n\nPrivate-zone resolution does not work until you create a virtual network link.\n\n```python\nvnet_id = (\n    \"/subscriptions/00000000-0000-0000-0000-000000000000\"\n    \"/resourceGroups/network-rg\"\n    \"/providers/Microsoft.Network/virtualNetworks/app-vnet\"\n)\n\nlink = client.virtual_network_links.begin_create_or_update(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    virtual_network_link_name=\"app-vnet-link\",\n    parameters=VirtualNetworkLink(\n        virtual_network=SubResource(id=vnet_id),\n        registration_enabled=False,\n    ),\n    if_none_match=\"*\",\n).result()\n\nprint(link.virtual_network_link_state)\n```\n\nSet `registration_enabled=True` only when you want Azure to auto-register VM hostnames from that virtual network into the zone. A private zone can have multiple registration virtual networks, but each virtual network can have only one registration zone.\n\n### Create an A record set\n\nRecord-set names are relative to the zone. Use `\"db\"`, not `\"db.private.contoso.com\"`.\n\n```python\nrecord_set = client.record_sets.create_or_update(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    record_type=\"A\",\n    relative_record_set_name=\"db\",\n    parameters=RecordSet(\n        ttl=300,\n        a_records=[\n            ARecord(ipv4_address=\"10.10.0.4\"),\n        ],\n        metadata={\"owner\": \"platform\"},\n    ),\n    if_none_match=\"*\",\n)\n\nprint(record_set.fqdn)\n```\n\nSupported record types in the current reference are `A`, `AAAA`, `CNAME`, `MX`, `PTR`, `SOA`, `SRV`, and `TXT`.\n\n### List zones, links, and record sets\n\n```python\nfor zone in client.private_zones.list_by_resource_group(\"dns-rg\"):\n    print(zone.name, zone.number_of_record_sets)\n\nfor link in client.virtual_network_links.list(\"dns-rg\", \"private.contoso.com\"):\n    print(link.name, link.virtual_network_link_state, link.registration_enabled)\n\nfor record_set in client.record_sets.list(\"dns-rg\", \"private.contoso.com\"):\n    print(record_set.name, record_set.type, record_set.ttl)\n```\n\nThese methods return paged iterators. Iterate over them instead of assuming one in-memory list.\n\n### Update a record safely with its ETag\n\nThe record-set operations support optimistic concurrency through `if_match`.\n\n```python\nexisting = client.record_sets.get(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    record_type=\"A\",\n    relative_record_set_name=\"db\",\n)\n\nupdated = client.record_sets.update(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    record_type=\"A\",\n    relative_record_set_name=\"db\",\n    parameters=RecordSet(\n        ttl=600,\n        a_records=existing.a_records,\n        metadata={\"owner\": \"networking\"},\n    ),\n    if_match=existing.etag,\n)\n\nprint(updated.ttl)\n```\n\nUse the same pattern for `private_zones.begin_update(...)` and `virtual_network_links.begin_update(...)` when you want to avoid overwriting concurrent changes.\n\n### Delete in the correct order\n\nYou cannot delete a private zone while virtual network links still exist.\n\n```python\nclient.record_sets.delete(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    record_type=\"A\",\n    relative_record_set_name=\"db\",\n)\n\nclient.virtual_network_links.begin_delete(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n    virtual_network_link_name=\"app-vnet-link\",\n).result()\n\nclient.private_zones.begin_delete(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"private.contoso.com\",\n).result()\n```\n\nDeleting a registration virtual-network link also deletes the auto-registered DNS records for that virtual network. Deleting the zone deletes all records in the zone.\n\n## Important Behavior And Pitfalls\n\n- Private-zone records are not resolvable from the public internet. Resolution works only from linked virtual networks.\n- Do not use a trailing dot in `private_zone_name`; the SDK reference explicitly expects zone names without a terminating dot.\n- Do not use single-label zone names such as `corp`; Azure Private DNS requires at least two labels such as `corp.internal`.\n- Do not try to create NS delegations inside a private DNS zone. Private-zone delegations are not supported.\n- If a virtual network uses custom DNS servers, Azure does not automatically query linked private zones for that VNet. Use Azure DNS Private Resolver or configure a conditional forwarder to `168.63.129.16` for the private zone.\n- `.local` is a poor zone choice; Microsoft recommends avoiding it because not all operating systems support it.\n- You can create only one link between a given private zone and a given virtual network. Link names must still be unique within the zone.\n- After link creation, the service docs note that the link status can take a few minutes to reach `Completed` for larger virtual networks. Check `virtual_network_link_state` before debugging name-resolution failures.\n- `SOA` record sets cannot be created directly and cannot be deleted independently; they are created with the zone and removed when the zone is deleted.\n\n## Version-Sensitive Notes\n\n### `1.2.0`\n\nPyPI release notes for `1.2.0` add:\n\n- `VirtualNetworkLink.resolution_policy`\n- `ResolutionPolicy`\n\nThe current model reference says `resolution_policy` is only applicable for virtual network links to `privatelink` zones and for `A`, `AAAA`, and `CNAME` queries. When set to `NxDomainRedirect`, Azure DNS falls back to public resolution if the private-zone lookup returns NXDOMAIN.\n\nExample:\n\n```python\nlink = client.virtual_network_links.begin_create_or_update(\n    resource_group_name=\"dns-rg\",\n    private_zone_name=\"privatelink.database.windows.net\",\n    virtual_network_link_name=\"app-vnet-link\",\n    parameters=VirtualNetworkLink(\n        virtual_network=SubResource(id=vnet_id),\n        registration_enabled=False,\n        resolution_policy=\"NxDomainRedirect\",\n    ),\n).result()\n```\n\nOnly use this setting when the zone and lookup behavior match those documented constraints.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-privatedns/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.privatednsmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.operations.privatezonesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.operations.recordsetsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.operations.virtualnetworklinksoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.models.virtualnetworklink?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-privatedns/azure.mgmt.privatedns.models?view=azure-python\n- https://learn.microsoft.com/en-us/azure/dns/private-dns-overview\n- https://learn.microsoft.com/en-us/azure/dns/private-dns-privatednszone\n- https://learn.microsoft.com/en-us/azure/dns/private-dns-virtual-network-links\n"
  },
  {
    "path": "content/azure/docs/mgmt-rdbms/python/DOC.md",
    "content": "---\nname: mgmt-rdbms\ndescription: \"Azure RDBMS management SDK for Python for Azure Database for MySQL and PostgreSQL control-plane operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,arm,management,mysql,postgresql,database\"\n---\n\n# Azure RDBMS Management SDK For Python\n\n## Golden Rule\n\nUse `azure-mgmt-rdbms` for Azure Resource Manager control-plane work: listing servers, managing databases, firewall rules, configurations, and server lifecycle actions for Azure Database for MySQL and PostgreSQL. Do not use it to open database connections or run SQL queries.\n\nFor `10.1.1`, the practical namespaces for current services are:\n\n- `azure.mgmt.rdbms.mysql_flexibleservers`\n- `azure.mgmt.rdbms.postgresql_flexibleservers`\n\nThe older `azure.mgmt.rdbms.mysql` and `azure.mgmt.rdbms.postgresql` namespaces still appear in the package, but Microsoft’s PyPI release history for this package says those single-server paths should be migrated away from because the underlying single-server services are retired.\n\n## Install\n\nPyPI lists `10.1.1` as the latest stable release and requires Python 3.9+.\n\n```bash\npython -m pip install \"azure-mgmt-rdbms==10.1.1\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-rdbms==10.1.1\" azure-identity\npoetry add \"azure-mgmt-rdbms==10.1.1\" azure-identity\n```\n\nTypical environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n\n# Needed when authenticating with a service principal\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, Microsoft recommends token-based Entra ID auth. The fastest path is usually:\n\n```bash\naz login\n```\n\n## Authentication And Client Setup\n\n`DefaultAzureCredential()` is the standard starting point for Azure SDK apps because it works with local developer credentials and Azure-hosted identities. In production, prefer a narrower credential such as managed identity when your runtime is fixed.\n\nCreate one credential and reuse the specific management client for the service you are targeting:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.mysql_flexibleservers import MySQLManagementClient\nfrom azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nmysql_client = MySQLManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n\npostgres_client = PostgreSQLManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nPractical notes:\n\n- `subscription_id` is required for both clients.\n- These are management clients. The identity also needs Azure RBAC rights on the subscription, resource group, or server you are touching.\n- The client constructors accept `base_url` and `cloud_setting` if you need a non-public Azure cloud.\n\n## Core Workflows\n\n### List PostgreSQL flexible servers in a resource group\n\nUse `servers.list_by_resource_group(...)` when you already know the resource group:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient\n\nclient = PostgreSQLManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor server in client.servers.list_by_resource_group(\"rg-data-prod\"):\n    print(server.name, server.location, server.version)\n```\n\n### Create or update a MySQL flexible server database\n\n`databases.begin_create_or_update(...)` is a long-running operation. Wait for `.result()`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.mysql_flexibleservers import MySQLManagementClient\nfrom azure.mgmt.rdbms.mysql_flexibleservers.models import Database\n\nclient = MySQLManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.databases.begin_create_or_update(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"mysql-flex-prod\",\n    database_name=\"appdb\",\n    parameters=Database(\n        charset=\"utf8mb4\",\n        collation=\"utf8mb4_0900_ai_ci\",\n    ),\n)\n\ndatabase = poller.result()\nprint(database.name, database.charset, database.collation)\n```\n\n### Create a PostgreSQL flexible server firewall rule\n\nFirewall rules also use a `begin_*` long-running call:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient\nfrom azure.mgmt.rdbms.postgresql_flexibleservers.models import FirewallRule\n\nclient = PostgreSQLManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.firewall_rules.begin_create_or_update(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n    firewall_rule_name=\"office-ip\",\n    parameters=FirewallRule(\n        start_ip_address=\"203.0.113.10\",\n        end_ip_address=\"203.0.113.10\",\n    ),\n)\n\nrule = poller.result()\nprint(rule.name, rule.start_ip_address, rule.end_ip_address)\n```\n\n### Update a PostgreSQL server configuration\n\nThe configuration operations support `begin_put(...)` and `begin_update(...)`. This example updates one named configuration:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient\nfrom azure.mgmt.rdbms.postgresql_flexibleservers.models import Configuration\n\nclient = PostgreSQLManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.configurations.begin_update(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n    configuration_name=\"log_min_duration_statement\",\n    parameters=Configuration(\n        value=\"300\",\n        source=\"user-override\",\n    ),\n)\n\nconfig = poller.result()\nprint(config.name, config.value, config.source)\n```\n\n### Update server metadata or administrator password\n\nThe server update API accepts a `ServerForUpdate` payload with only the fields you want to change:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient\nfrom azure.mgmt.rdbms.postgresql_flexibleservers.models import ServerForUpdate\n\nclient = PostgreSQLManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.servers.begin_update(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n    parameters=ServerForUpdate(\n        tags={\n            \"env\": \"prod\",\n            \"owner\": \"data-platform\",\n        },\n    ),\n)\n\nserver = poller.result()\nprint(server.name, server.tags)\n```\n\nIf you need to rotate the administrator password, pass `administrator_login_password` in the same `ServerForUpdate(...)` model instead of inventing a separate password-reset call.\n\n### Start, stop, or restart a PostgreSQL flexible server\n\nThese operations are explicit server actions:\n\n```python\nclient.servers.begin_stop(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n).result()\n\nclient.servers.begin_start(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n).result()\n\nclient.servers.begin_restart(\n    resource_group_name=\"rg-data-prod\",\n    server_name=\"postgres-flex-prod\",\n).result()\n```\n\n## Common Pitfalls\n\n- Do not instantiate operation classes directly. Use `client.servers`, `client.databases`, `client.firewall_rules`, and `client.configurations`.\n- Most write operations are long-running and use `begin_*`. Call `.result()` if your code must wait for the ARM operation to finish.\n- `azure-mgmt-rdbms` is not a data-plane client. Use a PostgreSQL or MySQL driver separately for application queries.\n- Pick the correct namespace before writing code. `mysql_flexibleservers` and `postgresql_flexibleservers` are not interchangeable.\n- Authentication success does not imply authorization success. A valid token without the right RBAC role still fails management calls.\n- Firewall rules expect IPv4 strings. The model requires both `start_ip_address` and `end_ip_address`.\n- Keep resource names distinct: `resource_group_name`, `server_name`, `database_name`, and `configuration_name` are different ARM identifiers.\n\n## Version-Sensitive Notes\n\n- PyPI lists `10.1.1` as the latest stable release and says it fixes an import error in `10.1.0` after newer `azure-core` upgrades.\n- PyPI also shows a newer beta line, `10.2.0b18`, that deprecates `mysql_flexibleservers` and `postgresql_flexibleservers` inside this umbrella package and points users to `azure-mgmt-mysqlflexibleservers` and `azure-mgmt-postgresqlflexibleservers`.\n- For projects pinned to `azure-mgmt-rdbms==10.1.1`, the flexible-server imports shown in this guide remain the package-local imports documented on Microsoft Learn.\n- The same PyPI release history says the older `mysql` and `postgresql` modules map to retired single-server offerings. That means new automation should avoid those namespaces even if old examples still import them.\n\n## Official Sources\n\n- https://pypi.org/project/azure-mgmt-rdbms/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.mysql_flexibleservers.mysqlmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.postgresqlmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.operations.serversoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.mysql_flexibleservers.operations.databasesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.operations.firewallrulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.operations.configurationsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.mysql_flexibleservers.models.database?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.models.firewallrule?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.models.configuration?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-rdbms/azure.mgmt.rdbms.postgresql_flexibleservers.models.serverforupdate?view=azure-python\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview\n- https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-recoveryservices/python/DOC.md",
    "content": "---\nname: mgmt-recoveryservices\ndescription: \"Azure Recovery Services management SDK for Python for vault lifecycle, name checks, private link discovery, usage queries, and related ARM operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,recovery-services,management,arm,backup,site-recovery,python\"\n---\n\n# Azure Recovery Services Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-recoveryservices` for management-plane work on Recovery Services vaults: creating the vault resource, checking name availability, listing vault metadata, reading usage, and discovering related ARM resources such as private link resources. Install `azure-identity` with it and authenticate with `DefaultAzureCredential()` unless you have a more specific credential for the runtime.\n\nDo not use this package for backup items, backup policies, restore jobs, or Site Recovery replication workflows. Those APIs live in sibling Recovery Services management packages.\n\n## Install\n\nPin the package version your project expects and install Azure Identity alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-recoveryservices==4.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-recoveryservices==4.0.0\" azure-identity\npoetry add \"azure-mgmt-recoveryservices==4.0.0\" azure-identity\n```\n\n`4.0.0` requires Python `3.9+`.\n\n## Authentication And Setup\n\nUse `DefaultAzureCredential` for code that should work both locally and in Azure. It checks environment-based service principal settings first, then workload identity, managed identity, and developer credentials such as Azure CLI.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, `az login` is usually enough because `DefaultAzureCredential` can reuse Azure CLI authentication.\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nwith RecoveryServicesClient(\n    credential=credential,\n    subscription_id=subscription_id,\n) as client:\n    for vault in client.vaults.list_by_subscription_id():\n        print(vault.name, vault.location)\n```\n\nUse the client as a context manager, or call `.close()`, so the underlying HTTP transport is cleaned up.\n\n## Core Usage\n\nThe main operation groups exposed by `RecoveryServicesClient` include:\n\n- `vaults`\n- `recovery_services`\n- `private_link_resources`\n- `usages`\n- `deleted_vaults`\n- `vault_certificates`\n\n### Check Vault Name Availability Before Create\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nresource_group_name = \"example-rg\"\nlocation = \"westus2\"\nvault_name = \"example-recovery-vault\"\n\nwith RecoveryServicesClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    availability = client.recovery_services.check_name_availability(\n        resource_group_name=resource_group_name,\n        location=location,\n        input={\n            \"name\": vault_name,\n            \"type\": \"Microsoft.RecoveryServices/Vaults\",\n        },\n    )\n\n    print(availability.name_available)\n    print(availability.reason)\n    print(availability.message)\n```\n\nThe service can keep a deleted vault name unavailable for up to 24 hours while deleted resources are cleaned up. Check first instead of assuming a recent delete immediately frees the name.\n\n### Create Or Update A Vault\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nresource_group_name = \"example-rg\"\nvault_name = \"example-recovery-vault\"\n\nwith RecoveryServicesClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    vault = client.vaults.begin_create_or_update(\n        resource_group_name=resource_group_name,\n        vault_name=vault_name,\n        vault={\n            \"location\": \"westus2\",\n            \"sku\": {\"name\": \"Standard\"},\n            \"tags\": {\n                \"env\": \"dev\",\n                \"owner\": \"context-hub\",\n            },\n        },\n    ).result()\n\n    print(vault.id)\n```\n\nCreate the vault in the same Azure region as the workloads you plan to protect. The Recovery Services vault resource is regional.\n\n### Get, List, And Update Vault Metadata\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nresource_group_name = \"example-rg\"\nvault_name = \"example-recovery-vault\"\n\nwith RecoveryServicesClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for vault in client.vaults.list_by_resource_group(resource_group_name):\n        print(vault.name, vault.location, vault.tags)\n\n    current = client.vaults.get(resource_group_name, vault_name)\n\n    desired_tags = dict(current.tags or {})\n    desired_tags[\"cost-center\"] = \"finops-001\"\n\n    updated = client.vaults.begin_update(\n        resource_group_name=resource_group_name,\n        vault_name=vault_name,\n        vault={\n            \"tags\": desired_tags,\n        },\n    ).result()\n\n    print(updated.tags)\n```\n\n`begin_create_or_update`, `begin_update`, and `begin_delete` are long-running ARM operations. Call `.result()` when the next step depends on completion.\n\n### Discover Private Link Resources And Vault Usage\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nresource_group_name = \"example-rg\"\nvault_name = \"example-recovery-vault\"\n\nwith RecoveryServicesClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for resource in client.private_link_resources.list(resource_group_name, vault_name):\n        print(resource.name, resource.id)\n\n    for usage in client.usages.list_by_vaults(resource_group_name, vault_name):\n        print(usage.current_value, usage.limit, usage.unit)\n```\n\nThis is the package to use when you need ARM-level vault inventory or capacity/usage information in automation before handing off to backup-specific SDKs.\n\n### Delete A Vault\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservices import RecoveryServicesClient\n\nwith RecoveryServicesClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    client.vaults.begin_delete(\n        resource_group_name=\"example-rg\",\n        vault_name=\"example-recovery-vault\",\n    ).result()\n```\n\nVault deletion is not just ARM cleanup. Azure Backup documentation calls out several dependencies that block deletion, including backup items, soft-deleted items, registered servers or storage accounts, private endpoints, and Site Recovery state. Clear those dependencies first.\n\n## Configuration Notes\n\n- `subscription_id` is required. The client does not infer it from the credential.\n- `DefaultAzureCredential` tries environment credentials before Azure CLI. Old `AZURE_CLIENT_ID` or `AZURE_TENANT_ID` values can shadow a working `az login`.\n- Keep one credential and one client instance for a unit of work instead of constructing them repeatedly inside loops.\n- The client constructor accepts an `api_version`, but the package already targets the current supported Recovery Services management API. Override it only when you have a verified reason.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-recoveryservices` without `azure-identity`\n- Using this package for backup jobs, restore points, or protected items instead of the backup-specific SDK\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Treating `begin_*` methods like synchronous calls and skipping `.result()`\n- Reusing a deleted vault name immediately and getting a name-availability failure\n- Deleting the vault before removing backup or Site Recovery dependencies\n- Assuming tag updates are additive. Send the full desired tag set in your patch payload.\n\n## Version-Sensitive Notes\n\n### `4.0.0`\n\nThe `4.0.0` package page calls out a few behavior changes compared with older `azure-mgmt-recoveryservices` releases:\n\n- async client support is available under `azure.mgmt.recoveryservices.aio`\n- long-running operations use `azure.core.polling.LROPoller`\n- several legacy operation names and model names were renamed to match current Azure conventions\n\nIf you are upgrading older code, verify any pre-`4.x` examples before copying them into a current project.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-recoveryservices/4.0.0/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservices/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservices/azure.mgmt.recoveryservices.recoveryservicesclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservices/azure.mgmt.recoveryservices.operations.vaultsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/overview/azure/recoveryservices?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/azure/backup/backup-azure-delete-vault\n- https://learn.microsoft.com/en-us/azure/backup/backup-create-rs-vault\n"
  },
  {
    "path": "content/azure/docs/mgmt-recoveryservicesbackup/python/DOC.md",
    "content": "---\nname: mgmt-recoveryservicesbackup\ndescription: \"Azure Recovery Services Backup management SDK for Python for vault backup policies, protected items, recovery points, jobs, and on-demand backups\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,backup,recovery-services,management,vault,python\"\n---\n\n# Azure Recovery Services Backup Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-recoveryservicesbackup` for Azure Backup management-plane operations inside an existing Recovery Services vault: listing policies, inspecting protected items, enumerating recovery points, checking jobs, and triggering backup or restore operations.\n\nFor `10.0.0`, pair it with `azure-identity`, authenticate with a `TokenCredential`, and import the main client from `azure.mgmt.recoveryservicesbackup`. Do not copy older examples that still use `azure.common.credentials` or old `activestamp` imports.\n\n## Install\n\nThis package requires Python 3.9+.\n\n```bash\npython -m pip install \"azure-mgmt-recoveryservicesbackup==10.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-recoveryservicesbackup==10.0.0\" azure-identity\npoetry add \"azure-mgmt-recoveryservicesbackup==10.0.0\" azure-identity\n```\n\nMinimum environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_BACKUP_RESOURCE_GROUP=\"example-backup-rg\"\nexport AZURE_BACKUP_VAULT_NAME=\"example-vault\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nYou also need an existing Recovery Services vault and at least one protected item if you want to inspect backup state or trigger backups.\n\n## Authentication And Client Setup\n\nUse `DefaultAzureCredential()` for reusable code and CI, or `AzureCliCredential()` for local scripts after `az login`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.recoveryservicesbackup import RecoveryServicesBackupClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nresource_group_name = os.environ[\"AZURE_BACKUP_RESOURCE_GROUP\"]\nvault_name = os.environ[\"AZURE_BACKUP_VAULT_NAME\"]\n\ncredential = DefaultAzureCredential()\nclient = RecoveryServicesBackupClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.recoveryservicesbackup import RecoveryServicesBackupClient\n\nclient = RecoveryServicesBackupClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe current client docs show a default ARM API version of `2025-02-01`. The constructor accepts `api_version=...`, but Microsoft warns that overriding the default may result in unsupported behavior.\n\n## A Small Helper For Backup Item Identifiers\n\nMany operations need `fabric_name`, `container_name`, and `protected_item_name`. A protected item resource ID already contains all three, so parse them from `item.id` instead of hand-building strings.\n\n```python\ndef backup_item_names(resource_id: str) -> tuple[str, str, str]:\n    parts = resource_id.strip(\"/\").split(\"/\")\n    fabric_name = parts[parts.index(\"backupFabrics\") + 1]\n    container_name = parts[parts.index(\"protectionContainers\") + 1]\n    protected_item_name = parts[parts.index(\"protectedItems\") + 1]\n    return fabric_name, container_name, protected_item_name\n```\n\n## List Backup Policies In A Vault\n\nUse `client.backup_policies.list(...)` to enumerate policies, then `client.protection_policies.get(...)` when you need one policy by name.\n\n```python\nfor policy in client.backup_policies.list(vault_name, resource_group_name):\n    print(policy.name, type(policy.properties).__name__)\n\npolicy = client.protection_policies.get(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    policy_name=\"DefaultPolicy\",\n)\n\nprint(policy.name)\nprint(type(policy.properties).__name__)\n```\n\n## List Protected Items And Inspect One Item\n\n`backup_protected_items.list(...)` gives you the protected items in the vault. `protected_items.get(...)` fetches one item using its fabric/container/item identifiers.\n\n```python\nprotected_items = list(\n    client.backup_protected_items.list(\n        vault_name=vault_name,\n        resource_group_name=resource_group_name,\n    )\n)\n\nfor item in protected_items:\n    props = item.properties\n    print(\n        item.name,\n        getattr(props, \"friendly_name\", None),\n        getattr(props, \"policy_name\", None),\n        getattr(props, \"last_backup_status\", None),\n    )\n\nselected_item = protected_items[0]\nfabric_name, container_name, protected_item_name = backup_item_names(selected_item.id)\n\nprotected_item = client.protected_items.get(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    fabric_name=fabric_name,\n    container_name=container_name,\n    protected_item_name=protected_item_name,\n)\n\nprops = protected_item.properties\nprint(protected_item.name)\nprint(getattr(props, \"friendly_name\", None))\nprint(getattr(props, \"source_resource_id\", None))\nprint(getattr(props, \"protection_state\", None))\nprint(getattr(props, \"last_recovery_point\", None))\n```\n\nFor Azure IaaS VM items, the workload-specific model includes useful fields such as `container_name`, `friendly_name`, `policy_name`, `source_resource_id`, `protection_state`, `last_backup_status`, and `last_recovery_point`.\n\n## List Recovery Points For A Protected Item\n\nUse the same identifiers from the protected item to list recovery points:\n\n```python\nfor recovery_point in client.recovery_points.list(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    fabric_name=fabric_name,\n    container_name=container_name,\n    protected_item_name=protected_item_name,\n):\n    print(recovery_point.name, type(recovery_point.properties).__name__)\n```\n\nIf you already know the recovery point ID, fetch one directly:\n\n```python\nrecovery_point = client.recovery_points.get(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    fabric_name=fabric_name,\n    container_name=container_name,\n    protected_item_name=protected_item_name,\n    recovery_point_id=\"348916168024334\",\n)\n\nprint(recovery_point.name)\n```\n\n## Trigger An On-Demand Backup For An Azure VM\n\n`client.backups.trigger(...)` is the SDK call for an on-demand backup. For Azure IaaS VM items, send a `BackupRequestResource` with `IaasVMBackupRequest`.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom azure.mgmt.recoveryservicesbackup.models import (\n    BackupRequestResource,\n    IaasVMBackupRequest,\n)\n\nrequest = BackupRequestResource(\n    properties=IaasVMBackupRequest(\n        recovery_point_expiry_time_in_utc=datetime.now(timezone.utc) + timedelta(days=30)\n    )\n)\n\nclient.backups.trigger(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    fabric_name=fabric_name,\n    container_name=container_name,\n    protected_item_name=protected_item_name,\n    parameters=request,\n)\n```\n\nFor Azure VM backup flows, the REST API examples show `fabric_name` as `Azure`. Other workload types use different item identifiers and workload-specific backup request models such as Azure File Share or Azure Workload backup requests.\n\nThis operation is asynchronous. The REST API returns `Azure-AsyncOperation` and `Location` headers for tracking, and the client exposes `backup_operation_statuses.get(...)` if you already have the operation ID:\n\n```python\noperation_status = client.backup_operation_statuses.get(\n    vault_name=vault_name,\n    resource_group_name=resource_group_name,\n    operation_id=\"00000000-0000-0000-0000-000000000000\",\n)\n\nprint(operation_status.status)\n```\n\n## List Recent Backup Jobs\n\nUse `backup_jobs.list(...)` to inspect vault job activity:\n\n```python\nfor job in client.backup_jobs.list(vault_name, resource_group_name):\n    props = job.properties\n    print(\n        job.name,\n        getattr(props, \"operation\", None),\n        getattr(props, \"status\", None),\n        getattr(props, \"start_time\", None),\n    )\n```\n\nFor Azure IaaS VM jobs, workload-specific properties include `entity_friendly_name`, `operation`, `status`, `start_time`, `end_time`, and `is_user_triggered`.\n\n## Common Pitfalls\n\n- `azure-mgmt-recoveryservicesbackup` is a management-plane client. It manages backup configuration and operations in a vault; it is not a data-plane SDK for reading backed-up content directly.\n- `backup_policies.list(...)` and `protection_policies.get(...)` are different operation groups. Use the list API to enumerate policies and the protection policy API when you need a specific policy or policy update flow.\n- Most protected-item operations need `fabric_name`, `container_name`, and `protected_item_name`. Parse them from `protected_item.id` instead of guessing string formats.\n- `backups.trigger(...)` is workload-specific. `IaasVMBackupRequest` is correct for Azure VM items, but Azure File Share and Azure Workload items need different request models.\n- `10.0.0` changed imports: `passivestamp` moved into the separate `azure-mgmt-recoveryservicesbackup-passivestamp` package, and older `azure.mgmt.recoveryservicesbackup.activestamp` imports should be updated to direct imports from `azure.mgmt.recoveryservicesbackup`.\n- Older Azure SDK examples that still use `azure.common.credentials` or `msrestazure.azure_active_directory` are from a previous SDK generation and should not be copied into new `10.0.0` code.\n\n## Official Sources Used\n\n- https://learn.microsoft.com/en-us/python/api/overview/azure/mgmt-recoveryservicesbackup-readme?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.recoveryservicesbackupclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.backuppoliciesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.backupprotecteditemsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.protecteditemsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.recoverypointsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.backupsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.backupoperationstatusesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.operations.backupjobsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.models.iaasvmbackuprequest?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.models.azureiaascomputevmprotecteditem?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-recoveryservicesbackup/azure.mgmt.recoveryservicesbackup.models.azureiaasvmjob?view=azure-python\n- https://learn.microsoft.com/en-us/rest/api/backup/backups/trigger?view=rest-backup-2025-02-01\n- https://pypi.org/project/azure-mgmt-recoveryservicesbackup/\n"
  },
  {
    "path": "content/azure/docs/mgmt-redis/python/DOC.md",
    "content": "---\nname: mgmt-redis\ndescription: \"Azure Cache for Redis management-plane SDK for Python for provisioning caches, firewall rules, keys, maintenance, and ARM-side configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"14.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,redis,cache,arm,management,python\"\n---\n\n# Azure Cache for Redis Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-redis` for Azure Resource Manager control-plane work on Azure Cache for Redis: create or update caches, inspect provisioning state, manage firewall rules, list or regenerate access keys, export data, flush or reboot caches, and configure other ARM-exposed settings. Do not use it for Redis commands such as `GET`, `SET`, or pub/sub traffic. Application traffic still goes through a Redis data-plane client such as `redis`.\n\nAlso verify that Azure Cache for Redis is still the right service for the project. Microsoft announced retirement for all Azure Cache for Redis SKUs in October 2025. New Basic, Standard, and Premium caches stop being available for new customers on April 1, 2026, and for existing customers on October 1, 2026. Existing Basic, Standard, and Premium caches remain available through September 30, 2028, and remaining instances are turned off on October 1, 2028. Enterprise and Enterprise Flash tiers remain available through March 31, 2027. For net-new deployments, check whether Azure Managed Redis is the intended target instead of assuming this package is the right default.\n\n## Install\n\nPin the package version you actually want and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-redis==14.5.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-redis==14.5.0\" azure-identity\npoetry add \"azure-mgmt-redis==14.5.0\" azure-identity\n```\n\nEnvironment variables you usually need:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\n`RedisManagementClient` expects a `TokenCredential` plus a subscription ID. The usual default is `DefaultAzureCredential()` so local `az login`, managed identity, workload identity, and environment-based service principal auth all work without changing the client code.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.redis import RedisManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = RedisManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nFor local scripts that should use the Azure CLI identity explicitly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.redis import RedisManagementClient\n\nclient = RedisManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe main operation groups exposed by the client include:\n\n- `redis`\n- `firewall_rules`\n- `patch_schedules`\n- `private_endpoint_connections`\n- `private_link_resources`\n- `linked_server`\n- `access_policy`\n- `access_policy_assignment`\n\nMost write operations on `client.redis` are long-running ARM operations. If the method starts with `begin_`, call `.result()` before assuming the change finished.\n\n## Core Workflows\n\n### Create a cache\n\nThe generated model docs mark `location` and `sku` as required on `RedisCreateParameters`. A minimal create flow looks like this:\n\n```python\nfrom azure.mgmt.redis.models import RedisCreateParameters, Sku\n\npoller = client.redis.begin_create(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n    parameters=RedisCreateParameters(\n        location=\"eastus\",\n        sku=Sku(\n            name=\"Standard\",\n            family=\"C\",\n            capacity=1,\n        ),\n        redis_version=\"6.0\",\n        minimum_tls_version=\"1.2\",\n        enable_non_ssl_port=False,\n        public_network_access=\"Enabled\",\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n)\n\ncache = poller.result()\nprint(cache.id)\nprint(cache.provisioning_state)\n```\n\n### List and inspect caches\n\n```python\nfor cache in client.redis.list_by_resource_group(\"example-rg\"):\n    print(cache.name, cache.location, cache.sku.name, cache.provisioning_state)\n\ncache = client.redis.get(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n)\n\nprint(cache.host_name)\nprint(cache.ssl_port)\nprint(cache.minimum_tls_version)\n```\n\nUse `list_by_subscription()` when you need a subscription-wide inventory instead of a single resource group.\n\n### Update cache settings or tags\n\n`begin_update()` takes `RedisUpdateParameters`. Keep updates narrow and explicit instead of resending the entire original create payload.\n\n```python\nfrom azure.mgmt.redis.models import RedisUpdateParameters\n\nupdated = client.redis.begin_update(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n    parameters=RedisUpdateParameters(\n        tags={\n            \"env\": \"prod\",\n            \"owner\": \"platform\",\n        },\n        minimum_tls_version=\"1.2\",\n        update_channel=\"Stable\",\n    ),\n).result()\n\nprint(updated.tags)\nprint(updated.update_channel)\n```\n\nThe package also exposes newer cache-security and placement fields in the `14.x` line, including `disable_access_key_authentication`, `redis_configuration.notify_keyspace_events`, and `zonal_allocation_policy`. Use them only after confirming the target region and cache tier support the behavior you want.\n\n### List and regenerate access keys\n\nAccess keys are for client connectivity, not ARM authentication. Retrieve them only if the application actually needs shared-key auth.\n\n```python\nkeys = client.redis.list_keys(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n)\n\nprint(keys.primary_key)\nprint(keys.secondary_key)\n```\n\nTo rotate a key:\n\n```python\nfrom azure.mgmt.redis.models import RedisRegenerateKeyParameters\n\nrotated = client.redis.regenerate_key(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n    parameters=RedisRegenerateKeyParameters(key_type=\"Secondary\"),\n)\n\nprint(rotated.secondary_key)\n```\n\n### Add a firewall rule\n\n`FirewallRulesOperations.create_or_update()` expects a `RedisFirewallRule` with `start_ip` and `end_ip`.\n\n```python\nfrom azure.mgmt.redis.models import RedisFirewallRule\n\nrule = client.firewall_rules.create_or_update(\n    resource_group_name=\"example-rg\",\n    cache_name=\"ctxhub-redis-dev\",\n    rule_name=\"office-ip\",\n    parameters=RedisFirewallRule(\n        start_ip=\"203.0.113.10\",\n        end_ip=\"203.0.113.10\",\n    ),\n)\n\nprint(rule.name)\n```\n\nList the configured rules:\n\n```python\nfor rule in client.firewall_rules.list(\n    resource_group_name=\"example-rg\",\n    cache_name=\"ctxhub-redis-dev\",\n):\n    print(rule.name, rule.start_ip, rule.end_ip)\n```\n\n### Export data to Azure Storage\n\nThe SDK exposes `begin_export_data()` with `ExportRDBParameters`. The current model includes `prefix`, `container`, `format`, `preferred_data_archive_auth_method`, and `storage_subscription_id`.\n\n```python\nfrom azure.mgmt.redis.models import ExportRDBParameters\n\nclient.redis.begin_export_data(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n    parameters=ExportRDBParameters(\n        prefix=\"nightly-2026-03-13\",\n        container=\"https://examplestorage.blob.core.windows.net/redis-backups?sv=...\",\n        format=\"RDB\",\n    ),\n).result()\n```\n\nMicrosoft's import and export guidance matters here:\n\n- Import and export are supported only on Premium, Enterprise, and Enterprise Flash caches.\n- Blob storage accounts do not support export.\n- During export, the cache remains available.\n- During import, existing data is overwritten and the cache is not accessible until the operation finishes.\n\n### Flush or reboot a cache\n\n`begin_flush_cache()` was added in the `14.3.0` line. Use it when you need to clear the cache contents intentionally:\n\n```python\nclient.redis.begin_flush_cache(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n).result()\n```\n\nRebooting takes `RedisRebootParameters`. Reboot one node or both, depending on the maintenance task and tier topology:\n\n```python\nfrom azure.mgmt.redis.models import RedisRebootParameters\n\nclient.redis.begin_reboot(\n    resource_group_name=\"example-rg\",\n    name=\"ctxhub-redis-dev\",\n    parameters=RedisRebootParameters(\n        reboot_type=\"PrimaryNode\",\n        shard_id=0,\n    ),\n).result()\n```\n\n## Configuration Notes\n\n- `RedisManagementClient` does not infer `subscription_id`; pass it explicitly.\n- The current client reference shows the default ARM API version as `2024-11-01`. Overriding `api_version` is possible, but generated Azure management packages are usually safest when you stay on the package default.\n- Current generated Azure management models are keyword-only. Do not copy older Track 1 or early Track 2 examples that pass positional constructor arguments.\n- `DefaultAzureCredential` tries multiple auth sources. If auth succeeds or fails in a surprising way, inspect which credential source won instead of assuming Azure CLI was used.\n- Authentication and authorization are separate. A valid token does not guarantee the principal can create caches, read keys, or update firewall rules.\n- `public_network_access=\"Disabled\"` only makes sense if private connectivity or another supported access path is already in place.\n\n## Version-Sensitive Notes For `14.5.0`\n\n- PyPI lists `14.5.0` as released on January 16, 2026.\n- `14.5.0` adds `zonal_allocation_policy` support on `RedisCreateParameters`.\n- `14.4.0` added `disable_access_key_authentication` and `redis_configuration.notify_keyspace_events`.\n- `14.3.0` added `begin_flush_cache`, the `access_policy` and `access_policy_assignment` operation groups, `redis_configuration.aad_enabled`, and `update_channel` support on create and update models.\n- If copied examples do not mention these fields or operation groups, they are probably pre-`14.3.0` examples.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-redis` and forgetting `azure-identity`\n- Using this package for Redis data traffic instead of Azure ARM management\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Forgetting that `begin_create()`, `begin_update()`, `begin_delete()`, `begin_reboot()`, `begin_export_data()`, and `begin_flush_cache()` are long-running operations\n- Copying old Azure examples that still use positional model constructors\n- Disabling public network access or access-key authentication before the replacement access path is ready\n- Assuming Azure Cache for Redis is the safe default for net-new projects despite the retirement timeline\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-redis/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.redismanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.operations.redisoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.operations.firewallrulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.rediscreateparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.redisupdateparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.redisregeneratekeyparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.redisrebootparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.redisfirewallrule?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.exportrdbparameters?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-redis/azure.mgmt.redis.models.rediscommonpropertiesredisconfiguration?view=azure-python\n- https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-admin\n- https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-import-export-data\n- https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-retirement-faq\n"
  },
  {
    "path": "content/azure/docs/mgmt-relay/python/DOC.md",
    "content": "---\nname: mgmt-relay\ndescription: \"Azure Relay management-plane SDK for Python for namespaces, hybrid connections, WCF relays, and shared access authorization rules\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,relay,arm,management,hybrid-connections,wcf-relay,python\"\n---\n\n# Azure Relay Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-relay` for Azure Resource Manager control-plane work only: creating Relay namespaces, provisioning Hybrid Connections or WCF relays, and managing shared access authorization rules. In `1.1.0`, the main client is `RelayAPI`. This package does not open listener sockets or send application traffic through Azure Relay for you.\n\n## Install\n\nInstall the management package with an Azure credential package:\n\n```bash\npython -m pip install \"azure-mgmt-relay==1.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-relay==1.1.0\" azure-identity\npoetry add \"azure-mgmt-relay==1.1.0\" azure-identity\n```\n\nEnvironment you usually need:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\n`azure-mgmt-relay 1.1.0` uses Azure Active Directory credentials from `azure-identity`.\n\nFor most projects, use one of these patterns:\n\n- `DefaultAzureCredential()` for reusable code, CI, managed identity, or workload identity\n- `AzureCliCredential()` for local scripts after `az login`\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.relay import RelayAPI\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = RelayAPI(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nCLI-driven local setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.relay import RelayAPI\n\nclient = RelayAPI(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nAuthentication success is separate from authorization. The principal also needs Azure RBAC permission to create or update `Microsoft.Relay/*` resources at the subscription, resource-group, or namespace scope you target.\n\n## Core Workflows\n\nThe main operation groups in `1.1.0` are:\n\n- `namespaces`\n- `hybrid_connections`\n- `wcf_relays`\n\n### Check namespace name availability\n\nCheck first before creating a namespace:\n\n```python\navailability = client.namespaces.check_name_availability(\n    {\"name\": \"ctxhub-relay-ns-01\"}\n)\n\nif not availability.name_available:\n    raise RuntimeError(availability.message or availability.reason)\n```\n\n### Create a Relay namespace\n\nNamespace creation is a long-running ARM operation, so wait on the poller:\n\n```python\npoller = client.namespaces.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    parameters={\n        \"location\": \"eastus\",\n        \"sku\": {\n            \"name\": \"Standard\",\n            \"tier\": \"Standard\",\n        },\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    },\n)\n\nnamespace = poller.result()\nprint(namespace.id)\nprint(namespace.service_bus_endpoint)\n```\n\nThe Relay namespace SKU documented for the ARM resource is `Standard`.\n\n### Create a Hybrid Connection\n\nCreate the namespace first, then create the Hybrid Connection inside it:\n\n```python\nhybrid_connection = client.hybrid_connections.create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    hybrid_connection_name=\"orders-hc\",\n    parameters={\n        \"requires_client_authorization\": True,\n        \"user_metadata\": (\n            '[{\"key\":\"endpoint\",\"value\":\"orders.internal.example:443\"}]'\n        ),\n    },\n)\n\nprint(hybrid_connection.id)\nprint(hybrid_connection.requires_client_authorization)\n```\n\nImportant Hybrid Connection properties exposed by the SDK docs include:\n\n- `requires_client_authorization`\n- `user_metadata`\n- `created_at`\n- `updated_at`\n- `listener_count`\n\nIf you use Hybrid Connections with Azure App Service, the App Service docs require `userMetadata` to be a JSON string array describing the endpoint, for example `[{\\\"key\\\":\\\"endpoint\\\",\\\"value\\\":\\\"host:port\\\"}]`.\n\n### Create a WCF relay\n\nUse `wcf_relays` when you need a WCF relay resource rather than a Hybrid Connection:\n\n```python\nwcf_relay = client.wcf_relays.create_or_update(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    relay_name=\"orders-wcf\",\n    parameters={\n        \"relay_type\": \"NetTcp\",\n        \"requires_client_authorization\": True,\n        \"requires_transport_security\": True,\n        \"user_metadata\": \"orders service relay\",\n    },\n)\n\nprint(wcf_relay.id)\nprint(wcf_relay.relay_type)\n```\n\nThe ARM resource definition for WCF relays documents these main writable properties:\n\n- `relay_type`\n- `requires_client_authorization`\n- `requires_transport_security`\n- `user_metadata`\n\n### Create an authorization rule and list keys\n\nCreate a SAS rule only when your app needs shared-access-key authentication:\n\n```python\nrule = client.hybrid_connections.create_or_update_authorization_rule(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    hybrid_connection_name=\"orders-hc\",\n    authorization_rule_name=\"send-listen\",\n    parameters={\n        \"rights\": [\"Listen\", \"Send\"],\n    },\n)\n\nkeys = client.hybrid_connections.list_keys(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    hybrid_connection_name=\"orders-hc\",\n    authorization_rule_name=\"send-listen\",\n)\n\nprint(rule.rights)\nprint(keys.primary_connection_string)\n```\n\nFor namespace-scoped keys, use `client.namespaces.create_or_update_authorization_rule(...)` and `client.namespaces.list_keys(...)` instead.\n\n### Rotate SAS keys\n\nUse `regenerate_keys` when you need to rotate a primary or secondary key without deleting the rule:\n\n```python\nrotated = client.hybrid_connections.regenerate_keys(\n    resource_group_name=\"example-rg\",\n    namespace_name=\"ctxhub-relay-ns-01\",\n    hybrid_connection_name=\"orders-hc\",\n    authorization_rule_name=\"send-listen\",\n    parameters={\n        \"key_type\": \"PrimaryKey\",\n    },\n)\n\nprint(rotated.primary_key)\n```\n\n### List existing resources\n\n```python\nfor namespace in client.namespaces.list():\n    print(namespace.name, namespace.location)\n\nfor hc in client.hybrid_connections.list_by_namespace(\n    \"example-rg\",\n    \"ctxhub-relay-ns-01\",\n):\n    print(hc.name, hc.listener_count)\n\nfor relay in client.wcf_relays.list_by_namespace(\n    \"example-rg\",\n    \"ctxhub-relay-ns-01\",\n):\n    print(relay.name, relay.relay_type)\n```\n\n## Configuration Notes\n\n- `subscription_id` is required; the client does not infer it from the credential.\n- `begin_create_or_update` on namespaces returns a poller. Wait on `.result()` before you depend on the namespace.\n- Hybrid Connection and WCF relay authorization rules are narrower than namespace-level rules. Prefer the smallest scope your app actually needs.\n- `user_metadata` is a plain string field in the management model. If another Azure service expects a specific JSON shape there, you need to write that exact string yourself.\n- `azure-mgmt-relay` is the management SDK. Provisioning the Relay resource and using the Relay endpoint at runtime are separate concerns.\n\n## Version-Sensitive Notes\n\nFor `1.1.0`, the documented client surface is `RelayAPI` with `TokenCredential` authentication from `azure-identity`. If older internal code expects different client names or older Azure credential helpers, verify that code before reusing it with `1.1.0`.\n\n## Common Pitfalls\n\n- Importing `RelayManagementClient` from older examples instead of `RelayAPI` in `1.1.0`\n- Installing only `azure-mgmt-relay` and forgetting `azure-identity`\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Treating namespace creation like an immediate call instead of waiting for the long-running operation\n- Putting arbitrary text into Hybrid Connection `user_metadata` when an integrating service expects a specific JSON string shape\n- Creating namespace-scoped SAS keys when your app only needs one Hybrid Connection or WCF relay\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-relay/1.1.0/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-relay/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-relay/azure.mgmt.relay.relayapi?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-relay/azure.mgmt.relay.operations.namespacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-relay/azure.mgmt.relay.operations.hybridconnectionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-relay/azure.mgmt.relay.operations.wcfrelaysoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.relay/namespaces\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.relay/namespaces/hybridconnections\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.relay/namespaces/hybridconnections/authorizationrules\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.relay/namespaces/wcfrelays\n- https://learn.microsoft.com/en-us/azure/app-service/app-service-hybrid-connections\n"
  },
  {
    "path": "content/azure/docs/mgmt-resource/python/DOC.md",
    "content": "---\nname: mgmt-resource\ndescription: \"Azure Resource Manager SDK for Python for resource groups, generic ARM resources, providers, and tags\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,arm,resource-manager,management,resource-groups,tags\"\n---\n\n# Azure Resource Manager SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-resource` for Azure Resource Manager management-plane work such as resource groups, generic ARM resources, provider metadata, and tags. Install `azure-identity` with it, authenticate with `DefaultAzureCredential` or `AzureCliCredential`, and do not assume older `azure.mgmt.resource` examples still match `25.x` because several operation groups were split into separate packages.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-resource==25.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-resource==25.0.0\" azure-identity\npoetry add \"azure-mgmt-resource==25.0.0\" azure-identity\n```\n\nIf you need functionality that was split out of `azure-mgmt-resource`, install the matching companion package explicitly. Common examples in the `25.x` line include:\n\n- `azure-mgmt-resource-deployments`\n- `azure-mgmt-resource-subscriptions`\n- `azure-mgmt-resource-features`\n- `azure-mgmt-resource-locks`\n- `azure-mgmt-resource-policy`\n\n## Authentication And Setup\n\nUse one of these credential patterns:\n\n- `AzureCliCredential()` for local scripts after `az login`\n- `DefaultAzureCredential()` for reusable code, CI, managed identity, or workload identity\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you use a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resource import ResourceManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = ResourceManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.resource import ResourceManagementClient\n\nclient = ResourceManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nFor sovereign clouds, keep the authority host and ARM cloud setting aligned:\n\n```python\nimport os\n\nfrom azure.identity import AzureAuthorityHosts, DefaultAzureCredential\nfrom azure.mgmt.resource import ResourceManagementClient\nfrom msrestazure.azure_cloud import AZURE_US_GOV_CLOUD\n\ncredential = DefaultAzureCredential(authority=AzureAuthorityHosts.AZURE_GOVERNMENT)\nclient = ResourceManagementClient(\n    credential=credential,\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n    cloud_setting=AZURE_US_GOV_CLOUD,\n)\n```\n\n## Core Usage\n\nThe current `ResourceManagementClient` docs expose these main operation groups:\n\n- `providers`\n- `provider_resource_types`\n- `resources`\n- `resource_groups`\n- `tags`\n\n### Create Or Update A Resource Group\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resource import ResourceManagementClient\n\nclient = ResourceManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nresource_group = client.resource_groups.create_or_update(\n    \"example-rg\",\n    {\n        \"location\": \"westus2\",\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    },\n)\n\nprint(resource_group.id)\n```\n\n### List, Get, And Delete Resource Groups\n\n```python\nfor group in client.resource_groups.list():\n    print(group.name, group.location)\n\ngroup = client.resource_groups.get(\"example-rg\")\nprint(group.id)\n\ndelete_poller = client.resource_groups.begin_delete(\"example-rg\")\ndelete_poller.result()\n```\n\nDeletion is a long-running operation. Call `.result()` when you need to wait for completion.\n\n### Discover Provider Resource Types Before Generic ARM Calls\n\nGeneric ARM resource operations require a provider API version. Inspect the provider metadata first instead of guessing:\n\n```python\nresource_types = client.provider_resource_types.list(\"Microsoft.Storage\")\n\nfor item in resource_types:\n    print(item.resource_type)\n    print(item.api_versions)\n```\n\n### Read A Generic Resource By ARM ID\n\n```python\nresource = client.resources.get_by_id(\n    \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Storage/storageAccounts/exampleacct\",\n    api_version=\"2023-05-01\",\n)\n\nprint(resource.type)\nprint(resource.location)\n```\n\nUse `client.resources` when you have an ARM ID and the provider API version, not when a service-specific SDK already gives you a better typed client.\n\n## Configuration Notes\n\n- `subscription_id` is required. `ResourceManagementClient` does not infer it from the credential.\n- The client constructor has an `api_version` parameter, but the Learn docs warn that overriding it may result in unsupported behavior. Prefer per-call provider API versions for `client.resources.*` operations instead of forcing a global override.\n- `DefaultAzureCredential` tries multiple credential sources. If authentication succeeds or fails unexpectedly, inspect the active credential in your environment rather than assuming Azure CLI was used.\n- Management operations often depend on RBAC at the subscription, resource-group, or resource scope. Authentication success does not imply authorization success.\n\n## Version-Sensitive Notes\n\n### `25.0.0`\n\nPyPI release notes for `25.0.0` call out these major changes:\n\n- The package now targets only the latest available API version.\n- `ResourceManagementClient.deployments` moved to `azure-mgmt-resource-deployments` via `DeploymentsMgmtClient`.\n- These modules were split into separate packages: `subscriptions`, `features`, `links`, `locks`, `policy`, `managedapplications`, `databoundaries`, `changes`, and `privatelinks`.\n\nIf your code needs those older clients or older API-version folders, pin an earlier package version and verify the corresponding docs before copying `25.x` examples.\n\n### `24.0.0`\n\nThe `24.0.0` release already split these features into separate packages:\n\n- `deploymentstacks` -> `azure-mgmt-resource-deploymentstacks`\n- `deploymentscripts` -> `azure-mgmt-resource-deploymentscripts`\n- `templatespecs` -> `azure-mgmt-resource-templatespecs`\n\n### Be Careful With Older Official Samples\n\nSome task-oriented Learn articles still show:\n\n```python\nresource_client.deployments.begin_create_or_update(...)\n```\n\nThat is not the safe default for `azure-mgmt-resource 25.x`. For ARM template deployments in current projects, verify whether you should be using `azure-mgmt-resource-deployments` instead.\n\n## Common Pitfalls\n\n- Installing only `azure-mgmt-resource` and forgetting `azure-identity`\n- Using this package for data-plane operations instead of ARM management\n- Omitting `AZURE_SUBSCRIPTION_ID`\n- Copying pre-`25.x` examples that expect `deployments`, `subscriptions`, or `locks` to still hang off `azure.mgmt.resource`\n- Guessing an ARM provider `api_version` for `client.resources.*` calls instead of inspecting provider metadata first\n- Forgetting that many delete and update flows return pollers and need `.result()`\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-resource/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource/\n- https://learn.microsoft.com/en-us/python/api/overview/azure/resources?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource/azure.mgmt.resource.resourcemanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureauthorityhosts?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-resource-policy/python/DOC.md",
    "content": "---\nname: mgmt-resource-policy\ndescription: \"Azure Policy management SDK for Python for policy definitions, assignments, initiatives, and policy definition version resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0b1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,policy,governance,arm,management,python\"\n---\n\n# azure-mgmt-resource-policy Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-resource-policy` is the Azure Resource Manager management-plane SDK for Azure Policy.\n\nUse it when you need to:\n\n- create or update custom policy definitions\n- assign policies or initiatives at subscription, resource-group, resource, or management-group scope\n- create policy set definitions (initiatives)\n- inspect policy definition and initiative versions\n- access policy-specific management operations exposed by `PolicyClient`\n\nPrimary import surface:\n\n```python\nfrom azure.mgmt.resource.policy import PolicyClient\n```\n\nThis is an ARM management client. It is for Azure Policy resource management, not for querying compliance results from Policy Insights.\n\n## Install\n\nInstall the package together with `azure-identity`:\n\n```bash\npython -m pip install \"azure-mgmt-resource-policy==1.0.0b1\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-resource-policy==1.0.0b1\" azure-identity\npoetry add \"azure-mgmt-resource-policy==1.0.0b1\" azure-identity\n```\n\nVersion notes from current official public sources:\n\n- PyPI currently lists `1.0.0b1` as the published release and requires Python `>=3.9`.\n- Azure's Python package index also lists `1.0.0b1`.\n- Azure's dependency report already lists `1.0.0b2` in source, so check the package version your environment actually resolves before pinning a prerelease newer than PyPI's public project page.\n\n## Authentication And Setup\n\nFor local development:\n\n```bash\naz login\naz account set --subscription \"<subscription-id-or-name>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nFor service principal auth:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\n```\n\nIf you also use management-group operations:\n\n```bash\nexport AZURE_MANAGEMENT_GROUP_ID=\"<management-group-id>\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resource.policy import PolicyClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = PolicyClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n```\n\nFor local scripts that should only use the Azure CLI login:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.resource.policy import PolicyClient\n\nclient = PolicyClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe current `PolicyClient` surface includes these main operation groups:\n\n- `policy_definitions`\n- `policy_assignments`\n- `policy_set_definitions`\n- `policy_definition_versions`\n- `policy_set_definition_versions`\n- `policy_tokens`\n- `data_policy_manifests`\n\n## Scope Handling\n\nPolicy assignments and some lookup APIs require full ARM scope strings.\n\nCommon patterns:\n\n```python\nimport os\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nmanagement_group_id = os.environ[\"AZURE_MANAGEMENT_GROUP_ID\"]\n\nsubscription_scope = f\"/subscriptions/{subscription_id}\"\nresource_group_scope = (\n    f\"/subscriptions/{subscription_id}/resourceGroups/example-rg\"\n)\nresource_scope = (\n    f\"{resource_group_scope}\"\n    \"/providers/Microsoft.Storage/storageAccounts/examplestorage\"\n)\nmanagement_group_scope = (\n    f\"/providers/Microsoft.Management/managementGroups/{management_group_id}\"\n)\n```\n\nIf the scope string is malformed, the SDK call fails even when authentication is correct.\n\n## Common Workflows\n\n### List Built-In Policy Definitions\n\nUse the built-in list APIs first when you want to reuse an existing Azure Policy instead of creating a custom one:\n\n```python\nfor definition in client.policy_definitions.list_built_in(\n    filter=\"category eq 'Storage'\",\n    top=5,\n):\n    print(definition.name)\n    print(definition.display_name)\n    print(definition.id)\n```\n\nYou can fetch one built-in definition by name after you discover it:\n\n```python\nfirst = next(client.policy_definitions.list_built_in(top=1))\n\ndefinition = client.policy_definitions.get_built_in(\n    policy_definition_name=first.name\n)\n\nprint(definition.id)\nprint(definition.display_name)\n```\n\n### Create A Custom Policy Definition At Subscription Scope\n\nThis example uses the storage-account audit rule from the Azure Policy \"Programmatically create policies\" article:\n\n```python\nfrom azure.mgmt.resource.policy.models import PolicyDefinition\n\ndefinition = client.policy_definitions.create_or_update(\n    policy_definition_name=\"audit-storage-public-network\",\n    parameters=PolicyDefinition(\n        policy_type=\"Custom\",\n        mode=\"All\",\n        display_name=\"Audit Storage Accounts Open to Public Networks\",\n        description=(\n            \"Audit storage accounts whose network default action allows \"\n            \"public access.\"\n        ),\n        metadata={\"category\": \"Storage\"},\n        version=\"1.0.0\",\n        policy_rule={\n            \"if\": {\n                \"allOf\": [\n                    {\n                        \"field\": \"type\",\n                        \"equals\": \"Microsoft.Storage/storageAccounts\",\n                    },\n                    {\n                        \"field\": (\n                            \"Microsoft.Storage/storageAccounts/\"\n                            \"networkAcls.defaultAction\"\n                        ),\n                        \"equals\": \"Allow\",\n                    },\n                ]\n            },\n            \"then\": {\"effect\": \"audit\"},\n        },\n    ),\n)\n\nprint(definition.id)\n```\n\nTo create the same kind of definition at management-group scope, call `create_or_update_at_management_group(...)` instead and pass `management_group_id`.\n\n### Assign A Policy To A Resource Group\n\nUse the returned definition ID and a full scope string:\n\n```python\nfrom azure.mgmt.resource.policy.models import PolicyAssignment\n\nscope = (\n    f\"/subscriptions/{subscription_id}/resourceGroups/example-rg\"\n)\n\nassignment = client.policy_assignments.create(\n    scope=scope,\n    policy_assignment_name=\"audit-storage-public-network\",\n    parameters=PolicyAssignment(\n        display_name=\"Audit Storage Accounts Open to Public Networks\",\n        description=\"Audit storage accounts in this resource group.\",\n        policy_definition_id=definition.id,\n        enforcement_mode=\"Default\",\n        not_scopes=[\n            (\n                f\"{scope}/providers/Microsoft.Storage/\"\n                \"storageAccounts/excludedaccount\"\n            )\n        ],\n    ),\n)\n\nprint(assignment.id)\n```\n\nTo inspect effective assignment version metadata, the assignment APIs support:\n\n```python\nassignment = client.policy_assignments.get_by_id(\n    policy_assignment_id=(\n        f\"{scope}/providers/Microsoft.Authorization/\"\n        \"policyAssignments/audit-storage-public-network\"\n    ),\n    expand=\"LatestDefinitionVersion,EffectiveDefinitionVersion\",\n)\n\nprint(assignment.latest_definition_version)\nprint(assignment.effective_definition_version)\n```\n\n### Create An Initiative (Policy Set Definition)\n\nInitiatives group one or more policy definitions under a single assignable object:\n\n```python\nfrom azure.mgmt.resource.policy.models import (\n    PolicyDefinitionReference,\n    PolicySetDefinition,\n)\n\ninitiative = client.policy_set_definitions.create_or_update(\n    policy_set_definition_name=\"storage-guardrails\",\n    parameters=PolicySetDefinition(\n        policy_type=\"Custom\",\n        display_name=\"Storage Guardrails\",\n        description=\"Group storage-related governance rules.\",\n        metadata={\"category\": \"Storage\"},\n        version=\"1.0.0\",\n        policy_definitions=[\n            PolicyDefinitionReference(\n                policy_definition_id=definition.id,\n                policy_definition_reference_id=\"audit-storage-public-network\",\n            )\n        ],\n    ),\n)\n\nprint(initiative.id)\n```\n\nManagement-group initiatives use `create_or_update_at_management_group(...)`.\n\n### List Definition Versions\n\nThe current package exposes first-class version operations for both policy definitions and initiatives:\n\n```python\nfor item in client.policy_definition_versions.list(\n    policy_definition_name=\"audit-storage-public-network\"\n):\n    print(item.name)\n    print(item.id)\n```\n\n```python\nfor item in client.policy_set_definition_versions.list(\n    policy_set_definition_name=\"storage-guardrails\"\n):\n    print(item.name)\n    print(item.id)\n```\n\nThe version operation groups also expose built-in and management-group variants when you need to inspect non-subscription definitions.\n\n### Query Data Policy Manifests\n\nIf you need policy-mode metadata for data resource types, use `data_policy_manifests`:\n\n```python\nfor manifest in client.data_policy_manifests.list(\n    filter=\"namespace eq 'Microsoft.KeyVault.Data'\"\n):\n    print(manifest.namespace)\n    print(manifest.resource_type)\n```\n\n## Important Pitfalls\n\n- `subscription_id` is still required when you construct `PolicyClient`, even if you later call management-group operations.\n- Scope strings must be full ARM IDs. Use `/providers/Microsoft.Management/managementGroups/{managementGroup}` for management groups, not just the group name.\n- When you use the SDK model classes, pass `policy_rule` directly as the rule body. Do not wrap it in a top-level REST-style `properties` object.\n- `PolicyAssignment.location` is only required when you attach a managed identity. If you add `identity`, set `location` too.\n- Assignment list filters use specific service-side expressions such as `atScope()`, `atExactScope()`, or `policyDefinitionId eq '{value}'`. Definition list filters use patterns such as `category eq '{value}'`.\n- The version operations expect semantic versions in `x.y.z` form for individual definition-version resources.\n- This package is part of the Azure Resource Manager split packages. Newer `azure-mgmt-resource` docs explicitly call out `azure-mgmt-resource-policy` as the package that now owns policy operations.\n\n## Version-Sensitive Notes\n\n- `azure-mgmt-resource-policy` is still in beta in the current public docs.\n- Public Azure package pages currently align on `1.0.0b1`, while Azure's dependency report already shows `1.0.0b2` in the source tree. If your project is pinned from an internal or prerelease feed, verify which version is actually available before copying examples unchanged.\n- The split from `azure-mgmt-resource` matters for migrations. In current `azure-mgmt-resource 25.x` guidance, `policy` is no longer treated as part of the main resource management package.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-resource-policy/\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/azure-sdk-library-package-index\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.policyclient?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.policydefinitionsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.policyassignmentsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.policysetdefinitionsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.policydefinitionversionsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.policysetdefinitionversionsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.operations.datapolicymanifestsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.models.policydefinition?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.models.policyassignment?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.models.policysetdefinition?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource-policy/azure.mgmt.resource.policy.models.policydefinitionreference?view=azure-python-preview\n- https://learn.microsoft.com/en-us/azure/governance/policy/how-to/programmatically-create\n- https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-python/dependencies/dependencies.html\n"
  },
  {
    "path": "content/azure/docs/mgmt-resourcegraph/python/DOC.md",
    "content": "---\nname: mgmt-resourcegraph\ndescription: \"Azure Resource Graph management SDK for Python for cross-subscription queries, management-group scopes, paging, and shared query resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,resource-graph,management,query,kql,subscriptions\"\n---\n\n# Azure Resource Graph Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-resourcegraph` when you need to query Azure Resource Graph from Python or manage shared Resource Graph queries as Azure resources. Pair it with `azure-identity` for authentication. The client constructor takes a credential, not a subscription ID; query scope is supplied on each `QueryRequest`.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-resourcegraph==8.0.1\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-resourcegraph==8.0.1\" azure-identity\npoetry add \"azure-mgmt-resourcegraph==8.0.1\" azure-identity\n```\n\nPyPI metadata for `8.0.1` requires Python 3.9+. The project description still says \"tested with Python 3.7+\", so prefer the package metadata and classifiers when choosing a runtime.\n\n## Authentication And Setup\n\nFor local development:\n\n```bash\naz login\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_RESOURCE_GROUP=\"resource-graph-queries\"  # only needed for shared-query examples\nexport AZURE_LOCATION=\"westus2\"  # only needed for shared-query examples\n```\n\nIf you use a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nMinimal client setup:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\n\ncredential = DefaultAzureCredential()\nclient = ResourceGraphClient(credential)\n```\n\n`DefaultAzureCredential` is the practical default because it can use environment credentials, workload identity, managed identity, Azure CLI, Azure PowerShell, or Azure Developer CLI. For Azure-hosted production code, switch to `ManagedIdentityCredential` when the runtime is fixed and managed identity is available.\n\n## Run A Query\n\nUse `QueryRequest` to provide both the KQL query text and the scope to run it against:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\nfrom azure.mgmt.resourcegraph.models import QueryRequest, QueryRequestOptions, ResultFormat\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\nclient = ResourceGraphClient(credential)\n\ntry:\n    request = QueryRequest(\n        subscriptions=[subscription_id],\n        query=\"\"\"\nResources\n| where type =~ 'microsoft.compute/virtualmachines'\n| project id, name, location, resourceGroup\n| order by name asc\n\"\"\",\n        options=QueryRequestOptions(\n            top=100,\n            result_format=ResultFormat.OBJECT_ARRAY,\n        ),\n    )\n\n    response = client.resources(request)\n\n    print(f\"count={response.count} total_records={response.total_records}\")\n    for row in response.data:\n        print(row[\"name\"], row[\"location\"], row[\"id\"])\nfinally:\n    client.close()\n```\n\nImportant details:\n\n- `subscriptions` is a list, even if you query only one subscription.\n- `result_format=ResultFormat.OBJECT_ARRAY` returns `response.data` as a list of JSON objects, which is the easiest format to consume from Python.\n- Azure Resource Graph defaults to returning at most 1,000 records per query response.\n\n## Query Multiple Subscriptions\n\nResource Graph is useful when you need one query across many subscriptions instead of looping through service-specific clients:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\nfrom azure.mgmt.resourcegraph.models import QueryRequest, QueryRequestOptions, ResultFormat\n\nsubscription_ids = [\n    item.strip()\n    for item in os.environ[\"AZURE_SUBSCRIPTION_IDS\"].split(\",\")\n    if item.strip()\n]\n\nclient = ResourceGraphClient(DefaultAzureCredential())\n\ntry:\n    response = client.resources(\n        QueryRequest(\n            subscriptions=subscription_ids,\n            query=\"\"\"\nResources\n| summarize resources=count() by type\n| top 20 by resources desc\n\"\"\",\n            options=QueryRequestOptions(\n                result_format=ResultFormat.OBJECT_ARRAY,\n            ),\n        )\n    )\n\n    for row in response.data:\n        print(row[\"type\"], row[\"resources\"])\nfinally:\n    client.close()\n```\n\nSet the environment variable as a comma-separated list:\n\n```bash\nexport AZURE_SUBSCRIPTION_IDS=\"sub-1,sub-2,sub-3\"\n```\n\n## Paginate Large Result Sets\n\nFor SDK callers, you handle pagination yourself by passing the previous `skip_token` into the next `QueryRequestOptions`:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\nfrom azure.mgmt.resourcegraph.models import QueryRequest, QueryRequestOptions, ResultFormat\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nquery_text = \"\"\"\nResources\n| project id, name, type\n| order by id asc\n\"\"\"\n\nclient = ResourceGraphClient(DefaultAzureCredential())\nresults = []\nskip_token = None\n\ntry:\n    while True:\n        response = client.resources(\n            QueryRequest(\n                subscriptions=[subscription_id],\n                query=query_text,\n                options=QueryRequestOptions(\n                    top=1000,\n                    skip_token=skip_token,\n                    result_format=ResultFormat.OBJECT_ARRAY,\n                ),\n            )\n        )\n\n        results.extend(response.data)\n\n        if not response.skip_token:\n            break\n\n        skip_token = response.skip_token\n\n    print(f\"fetched={len(results)}\")\nfinally:\n    client.close()\n```\n\nUse an explicit `order by` when paginating or skipping results. Without sorting, Resource Graph results are not repeatable.\n\n## Query A Management Group\n\nUse `management_groups` when the scope should follow a management-group hierarchy instead of a subscription list:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\nfrom azure.mgmt.resourcegraph.models import QueryRequest, QueryRequestOptions, ResultFormat\n\nclient = ResourceGraphClient(DefaultAzureCredential())\n\ntry:\n    response = client.resources(\n        QueryRequest(\n            management_groups=[\"myMG\"],\n            query=\"\"\"\nResources\n| summarize resources=count() by type\n| top 10 by resources desc\n\"\"\",\n            options=QueryRequestOptions(\n                allow_partial_scopes=True,\n                result_format=ResultFormat.OBJECT_ARRAY,\n            ),\n        )\n    )\n\n    for row in response.data:\n        print(row[\"type\"], row[\"resources\"])\nfinally:\n    client.close()\n```\n\nImportant scope rules:\n\n- `management_groups` and `subscriptions` cannot be used in the same request.\n- The `management_groups` value is the management group ID, not the display name.\n- Management-group scope includes only the first 10,000 subscriptions in or under that hierarchy.\n- `allow_partial_scopes` matters only for tenant-level or management-group-level queries.\n\n## Create And Read Shared Queries\n\nThe package also manages shared Resource Graph queries through the `graph_query` operation group:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.resourcegraph import ResourceGraphClient\nfrom azure.mgmt.resourcegraph.models import GraphQueryResource\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nresource_group_name = os.environ[\"AZURE_RESOURCE_GROUP\"]\nlocation = os.environ[\"AZURE_LOCATION\"]\n\nclient = ResourceGraphClient(DefaultAzureCredential())\n\ntry:\n    shared_query = client.graph_query.create_or_update(\n        subscription_id=subscription_id,\n        resource_group_name=resource_group_name,\n        resource_name=\"count-vms-by-os\",\n        properties=GraphQueryResource(\n            location=location,\n            description=\"Count VMs by OS type\",\n            query=(\n                \"Resources \"\n                \"| where type =~ 'microsoft.compute/virtualmachines' \"\n                \"| summarize count() by tostring(properties.storageProfile.osDisk.osType)\"\n            ),\n        ),\n    )\n\n    print(shared_query.id)\n\n    saved = client.graph_query.get(\n        subscription_id=subscription_id,\n        resource_group_name=resource_group_name,\n        resource_name=\"count-vms-by-os\",\n    )\n\n    print(saved.query)\nfinally:\n    client.close()\n```\n\nUse `client.graph_query.list_by_subscription(subscription_id)` to enumerate shared queries across a subscription, or `client.graph_query.list(subscription_id, resource_group_name)` to scope the listing to one resource group.\n\n## Common Pitfalls\n\n- Do not pass `subscription_id` to `ResourceGraphClient`. Query scope lives on `QueryRequest`.\n- Do not assume preview docs match stable `8.0.1`. Preview `8.1.0b*` adds `authorization_scope_filter` and resource history/change operations that are not part of stable `8.0.1`.\n- Do not use `limit` or `take` in the KQL query if you expect SDK pagination with `skip_token`; Resource Graph can omit the continuation token in that case.\n- Do not pass a management group display name to `management_groups`; use the management group ID.\n- Do not forget to install `azure-identity`. This package expects a `TokenCredential`.\n- Large or bursty query workloads can be throttled. Azure Resource Graph documents per-user quota headers such as `x-ms-user-quota-remaining` and `x-ms-user-quota-resets-after`; group subscription IDs into fewer queries and back off when the remaining quota reaches zero.\n- Shared queries are Azure resources. Creating them requires a subscription ID, resource group, and a `location` on the resource body.\n\n## Version-Sensitive Notes For `8.0.1`\n\n- PyPI lists `8.0.1` as the current stable release, published on November 24, 2025.\n- The `8.0.1` release notes say the package was regenerated for API version `2021-03-01`.\n- `management_groups` on `QueryRequest` and `allow_partial_scopes` on `QueryRequestOptions` were added in `8.0.0`, so they are safe to use in `8.0.1`.\n- The package still exposes `GraphQueryOperations` for shared queries, which has existed since `2.1.0`.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-resourcegraph/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.resourcegraphclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.models.queryrequest?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.models.queryrequestoptions?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.models.queryresponse?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.models.graphqueryresource?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-resourcegraph/azure.mgmt.resourcegraph.operations.graphqueryoperations?view=azure-python\n- https://learn.microsoft.com/en-us/azure/governance/resource-graph/concepts/query-language\n- https://learn.microsoft.com/en-us/azure/governance/resource-graph/concepts/work-with-data\n- https://learn.microsoft.com/en-us/azure/governance/resource-graph/concepts/guidance-for-throttled-requests\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n"
  },
  {
    "path": "content/azure/docs/mgmt-search/python/DOC.md",
    "content": "---\nname: mgmt-search\ndescription: \"Azure AI Search management SDK for Python for service lifecycle, scaling, API keys, and subscription-level administration\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-ai-search,management,arm,api-keys,python\"\n---\n\n# azure-mgmt-search Python Package Guide\n\n## What This Package Is\n\n`azure-mgmt-search` is the Azure Resource Manager SDK for Azure AI Search. Use it for management-plane work:\n\n- create, update, list, upgrade, and delete search services\n- read and rotate admin keys\n- create, list, and delete query keys\n- inspect subscription-level search services and usage-related management surfaces\n\nDo not use this package for indexes, documents, queries, or indexers. Those are data-plane operations and belong to `azure-search-documents`.\n\nPackage and import path differ:\n\n- PyPI package: `azure-mgmt-search`\n- Python namespace: `azure.mgmt.search`\n\nThis guide is scoped to package version `9.2.0` on PyPI.\n\n## Golden Rules\n\n- Use `SearchManagementClient` for Azure AI Search service administration, not for document or index operations\n- Install `azure-identity` alongside this package; the client expects a `TokenCredential`\n- Pass the Azure subscription ID explicitly; the management client does not infer it\n- Treat service creation as a long-running operation and wait on the returned poller with `.result()`\n- Query keys are deleted by key value, not by key name\n- `SearchManagementClient` defaults to ARM API version `2025-05-01`; do not override `api_version` unless you have a specific compatibility reason\n\n## Install\n\nPyPI lists `Requires: Python >=3.9`.\n\n```bash\npython -m pip install \"azure-mgmt-search==9.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-search==9.2.0\" azure-identity\npoetry add \"azure-mgmt-search==9.2.0\" azure-identity\n```\n\n## Authentication And Environment\n\nMinimum environment for management-plane scripts:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_RESOURCE_GROUP=\"example-rg\"\nexport AZURE_SEARCH_SERVICE_NAME=\"example-search-svc\"\nexport AZURE_LOCATION=\"westus2\"\n```\n\nIf you authenticate with a service principal, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, `DefaultAzureCredential()` usually works after `az login`. Management calls still require Azure RBAC permissions on the subscription or resource group, so successful authentication does not guarantee authorization.\n\n## Initialize The Client\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\ncredential = DefaultAzureCredential()\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = SearchManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\n## Check Whether A Service Name Is Available\n\nSearch service names are globally unique because they become part of `https://<name>.search.windows.net`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\navailability = client.services.check_name_availability(\n    os.environ[\"AZURE_SEARCH_SERVICE_NAME\"]\n)\n\nprint(availability)\n```\n\nThe management docs also document the naming constraints: lowercase letters, digits, and dashes only; no consecutive dashes; not starting with two dashes or ending with one; length `2` to `60`.\n\n## Create Or Update A Search Service\n\nThis is the core provisioning flow for the package. `begin_create_or_update()` returns a long-running-operation poller.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\nfrom azure.mgmt.search.models import SearchService, Sku\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.services.begin_create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n    service=SearchService(\n        location=os.environ[\"AZURE_LOCATION\"],\n        sku=Sku(name=\"basic\"),\n        replica_count=1,\n        partition_count=1,\n    ),\n)\n\nservice = poller.result()\nprint(service.id)\nprint(service.status)\n```\n\nWhat matters in practice:\n\n- `location` is required for creation\n- `sku` is required; a minimal example is `Sku(name=\"basic\")`\n- `replica_count` and `partition_count` control scale and capacity\n- if the service already exists, `begin_create_or_update()` updates all properties you pass\n\n## Get And List Existing Services\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nservice = client.services.get(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n)\n\nprint(service.name, service.location, service.status)\n\nfor item in client.services.list_by_resource_group(os.environ[\"AZURE_RESOURCE_GROUP\"]):\n    print(item.name, item.sku.name)\n```\n\nUse `list_by_subscription()` when you need to inventory all Azure AI Search services in the current subscription.\n\n## Update Scale Or Tier\n\nUse `SearchServiceUpdate` with `services.update()` for partial updates to an existing service.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\nfrom azure.mgmt.search.models import SearchServiceUpdate, Sku\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nupdated = client.services.update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n    service=SearchServiceUpdate(\n        replica_count=2,\n        partition_count=1,\n        sku=Sku(name=\"basic\"),\n    ),\n)\n\nprint(updated.replica_count, updated.partition_count)\n```\n\nThe current model surface also includes `public_network_access`, so verify your network posture before copying older examples that assume public access is always enabled.\n\n## Upgrade An Existing Service\n\nVersion `9.2.0` includes `begin_upgrade()` on `services`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.services.begin_upgrade(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n)\n\nservice = poller.result()\nprint(service.status)\n```\n\nUse this only when the service reports an upgrade path. Do not assume every service needs it during normal provisioning.\n\n## Read And Rotate Admin Keys\n\nAdmin keys allow full access to the search service data plane. Azure AI Search creates both a primary and secondary admin key so you can rotate one while clients temporarily use the other.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nadmin_keys = client.admin_keys.get(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n)\n\nprint(admin_keys.primary_key)\nprint(admin_keys.secondary_key)\n```\n\nRotate one key at a time:\n\n```python\nrotated = client.admin_keys.regenerate(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n    \"primary\",\n)\n\nprint(rotated.primary_key)\n```\n\nPractical rotation flow:\n\n- move clients to the secondary key\n- regenerate the primary key\n- update clients to the new primary key\n- only then consider rotating the secondary key\n\n## Manage Query Keys\n\nQuery keys are read-only and are the safer choice for client apps that only run searches.\n\nCreate one:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nquery_key = client.query_keys.create(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n    name=\"frontend-search\",\n)\n\nprint(query_key.name)\nprint(query_key.key)\n```\n\nList all query keys:\n\n```python\nfor key in client.query_keys.list_by_search_service(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n):\n    print(key.name, key.key)\n```\n\nDelete a query key:\n\n```python\nclient.query_keys.delete(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n    key=query_key.key,\n)\n```\n\nImportant: the delete call takes the key value, not the display name.\n\n## Delete A Search Service\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.search import SearchManagementClient\n\nclient = SearchManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nclient.services.delete(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    search_service_name=os.environ[\"AZURE_SEARCH_SERVICE_NAME\"],\n)\n```\n\nThis deletes the search service and its associated resources. Treat it as destructive.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-search` for indexes or documents instead of `azure-search-documents`\n- Installing only `azure-mgmt-search` and forgetting `azure-identity`\n- Forgetting to set `AZURE_SUBSCRIPTION_ID`\n- Assuming successful `DefaultAzureCredential()` authentication also means the principal has permission to create services or manage keys\n- Treating `begin_create_or_update()` and `begin_upgrade()` like immediate calls and forgetting `.result()`\n- Deleting query keys by name instead of by key value\n- Copying older examples that rely on outdated API versions or omit newer network-related settings\n\n## Version-Sensitive Notes For 9.2.0\n\n- PyPI release history for `9.2.0` calls out support for the Search management API version `2025-05-01`\n- The current Learn reference for `SearchManagementClient` also shows `2025-05-01` as the default API version\n- The `9.2.0` release adds the `network_security_perimeter_configurations` operation group and `services.begin_upgrade()`\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-search/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.searchmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.operations.servicesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.operations.adminkeysoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.operations.querykeysoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.models.searchservice?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.models.searchserviceupdate?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-search/azure.mgmt.search.models.sku?view=azure-python\n- https://learn.microsoft.com/en-us/azure/search/search-security-api-keys\n"
  },
  {
    "path": "content/azure/docs/mgmt-security/python/DOC.md",
    "content": "---\nname: mgmt-security\ndescription: \"Azure Security Center / Microsoft Defender for Cloud management SDK for Python for subscription pricing, assessments, secure posture, and security contacts\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,security,defender-for-cloud,management,arm,python\"\n---\n\n# Azure Security Center / Defender for Cloud SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-security` for Azure Resource Manager management-plane automation against Microsoft Defender for Cloud. Pair it with `azure-identity`, authenticate with a `TokenCredential`, and pass a subscription ID into `SecurityCenter`.\n\nThis package does not scan machines or onboard agents by itself. It manages and queries `Microsoft.Security` resources such as Defender plans, assessments, secure score, contacts, and connector-related resources.\n\nMicrosoft Learn documents `SecurityCenter` as a multi-version client: one package exposes many operation groups across different API versions, and the default profile uses the latest public Azure mapping. For routine code, use the default client unless you have a verified reason to pin `api_version` or `profile`.\n\n## Install\n\nPin the package version you want and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-security==7.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-security==7.0.0\" azure-identity\npoetry add \"azure-mgmt-security==7.0.0\" azure-identity\n```\n\nPyPI lists Python `3.8+` for `7.0.0`.\n\n## Authentication And Setup\n\nFor local development, sign in with Azure CLI:\n\n```bash\naz login\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor service-principal auth with `DefaultAzureCredential`, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = SecurityCenter(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n\ntry:\n    # use client here\n    pass\nfinally:\n    client.close()\n```\n\nIf you want local CLI auth only, use `AzureCliCredential()` instead of `DefaultAzureCredential()`.\n\n## Core Workflows\n\n### List Defender For Cloud Pricing Plans\n\nUse `pricings.list()` to see which subscription-level plans are enabled before changing anything:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ntry:\n    for pricing in client.pricings.list():\n        print(pricing.name)\n        print(\"  tier:\", pricing.pricing_tier)\n        print(\"  sub-plan:\", pricing.sub_plan)\n        print(\"  free-trial:\", pricing.free_trial_remaining_time)\nfinally:\n    client.close()\n```\n\nThe `Pricing` model documents two pricing tiers: `\"Free\"` and `\"Standard\"`. Some plans also expose an optional `sub_plan`.\n\n### Enable Or Change A Specific Defender Plan\n\n`pricings.update()` expects the versioned `Pricing` model used by the `v2022_03_01` operation group:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\nfrom azure.mgmt.security.v2022_03_01.models import Pricing\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ntry:\n    updated = client.pricings.update(\n        pricing_name=\"VirtualMachines\",\n        pricing=Pricing(pricing_tier=\"Standard\"),\n    )\n    print(updated.name, updated.pricing_tier)\nfinally:\n    client.close()\n```\n\nUse `client.pricings.list()` first to discover valid `pricing_name` values in your subscription instead of guessing them.\n\nIf a Standard plan supports multiple sub-plans, you can pass `sub_plan=\"...\"` to `Pricing(...)`. The Learn reference says that when `sub_plan` is omitted, the full plan is applied.\n\n### List Assessment Metadata For Remediation Guidance\n\n`assessments_metadata.list_by_subscription()` is useful when you need the catalog of assessment types and their built-in remediation text:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ntry:\n    for item in client.assessments_metadata.list_by_subscription():\n        props = item.properties\n        print(item.name)\n        print(\"  title:\", props.display_name)\n        print(\"  severity:\", props.severity)\n        print(\"  remediation:\", props.remediation_description)\nfinally:\n    client.close()\n```\n\nThis is a practical way to map an assessment key to a user-facing title and remediation instructions before you query concrete assessment results.\n\n### List Assessment Results Across A Subscription\n\n`assessments.list()` takes a scope string. Microsoft Learn documents subscription and management-group scopes:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=subscription_id,\n)\n\ntry:\n    scope = f\"/subscriptions/{subscription_id}\"\n\n    for assessment in client.assessments.list(scope=scope):\n        props = assessment.properties\n        print(assessment.name)\n        print(\"  title:\", props.display_name)\n        print(\"  resource:\", props.resource_details.id)\nfinally:\n    client.close()\n```\n\nTo inspect one assessment in more detail and ask the service to include metadata, call `get(..., expand=\"metadata\")`:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ntry:\n    vm_id = (\n        \"/subscriptions/00000000-0000-0000-0000-000000000000/\"\n        \"resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/example-vm\"\n    )\n\n    assessment = client.assessments.get(\n        resource_id=vm_id,\n        assessment_name=\"<assessment-key>\",\n        expand=\"metadata\",\n    )\n\n    print(assessment.properties.display_name)\n    print(assessment.properties.status.code)\n    print(assessment.properties.metadata.remediation_description)\nfinally:\n    client.close()\n```\n\nGet the `<assessment-key>` from `assessments.list(...)` or `assessments_metadata.list_by_subscription()`.\n\n### Read The Current Secure Score\n\nFor the default initiative, Microsoft Learn says to use `ascScore`:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.security import SecurityCenter\n\nclient = SecurityCenter(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\ntry:\n    score = client.secure_scores.get(\"ascScore\")\n    print(score.id)\n    print(score.name)\nfinally:\n    client.close()\n```\n\nUse `client.secure_scores.list()` if you need every initiative in the current scope, not just the default `ascScore` view.\n\n## Configuration Notes\n\n- `subscription_id` is required. The client does not infer it from the credential.\n- For sovereign clouds, keep the credential authority and `base_url` aligned with the cloud you are targeting.\n- Reuse one client instance for a batch of operations and close it when done. The package enables HTTP connection pooling.\n- When an operation group expects a versioned model, import that model from the matching namespace. For example, `client.pricings.update(...)` uses `azure.mgmt.security.v2022_03_01.models.Pricing`.\n\n## Version-Sensitive Notes For `7.0.0`\n\n- PyPI lists `7.0.0` as the current stable release and also shows a newer pre-release, `8.0.0b1`, published on August 25, 2025. Pin `7.0.0` unless you intentionally want preview surface changes.\n- The `6.0.0` release added `APICollectionsOperations` and `DefenderForStorageOperations`.\n- The `6.0.0` release changed `SecurityContact`: it added `emails` and `notifications_by_role`, removed the older `email` and `alerts_to_admins` parameters, and removed `SecurityContactsOperations.update`.\n- Since `5.0.0`, the package uses simplified exceptions and removed `CloudError`; catch `azure.core.exceptions.HttpResponseError` in new code.\n- PyPI release notes for `5.0.0` also say the package has stable async support under the `azure.mgmt.security.aio` namespace.\n\n## Common Pitfalls\n\n- Treating this as a data-plane SDK. It is an ARM management client for `Microsoft.Security`.\n- Forgetting `AZURE_SUBSCRIPTION_ID`; auth alone is not enough to build the client.\n- Importing the wrong model namespace for update/create operations on versioned operation groups.\n- Copying older security-contact examples that still use `email`, `alerts_to_admins`, or `update(...)`; those do not match `7.0.0`.\n- Catching legacy `CloudError` exceptions in code written for current Azure SDK packages.\n- Leaving many short-lived clients unclosed in long-running processes.\n\n## Official Sources\n\n- PyPI package page and release history: https://pypi.org/project/azure-mgmt-security/\n- Azure package index: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security?view=azure-python\n- `SecurityCenter` client: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.securitycenter?view=azure-python\n- `PricingsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2022_03_01.operations.pricingsoperations?view=azure-python\n- `Pricing` model: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2022_03_01.models.pricing?view=azure-python\n- `AssessmentsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2021_06_01.operations.assessmentsoperations?view=azure-python\n- `AssessmentsMetadataOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2021_06_01.operations.assessmentsmetadataoperations?view=azure-python\n- `SecurityAssessmentPropertiesResponse`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.models.securityassessmentpropertiesresponse?view=azure-python-preview\n- `SecurityAssessmentMetadataPropertiesResponse`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.models.securityassessmentmetadatapropertiesresponse?view=azure-python-preview\n- `SecureScoresOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2020_01_01.operations.securescoresoperations?view=azure-python\n- `SecurityContactsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.v2020_01_01_preview.operations.securitycontactsoperations?view=azure-python\n- `SecurityContact` model: https://learn.microsoft.com/en-us/python/api/azure-mgmt-security/azure.mgmt.security.models.securitycontact?view=azure-python-preview\n"
  },
  {
    "path": "content/azure/docs/mgmt-servicebus/python/DOC.md",
    "content": "---\nname: mgmt-servicebus\ndescription: \"Azure Service Bus management-plane SDK for Python for namespaces, queues, topics, subscriptions, authorization rules, and network settings\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,service-bus,arm,management,namespaces,queues,topics,subscriptions,python\"\n---\n\n# Azure Service Bus Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-servicebus` for Azure Resource Manager control-plane work such as creating namespaces, queues, topics, subscriptions, authorization rules, and namespace network settings. Do not use it to send or receive messages. For data-plane messaging code, use `azure-servicebus`.\n\nFor package version `9.0.0`, the main client is `ServiceBusManagementClient`. The client defaults to the stable `2021-11-01` ARM API unless you override `api_version`.\n\n## Install\n\nInstall the management package and an Azure credential package together:\n\n```bash\npython -m pip install \"azure-mgmt-servicebus==9.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-servicebus==9.0.0\" azure-identity\npoetry add \"azure-mgmt-servicebus==9.0.0\" azure-identity\n```\n\nEnvironment used by the snippets below:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_RESOURCE_GROUP=\"example-rg\"\nexport SERVICEBUS_NAMESPACE_NAME=\"ctxhub-sb-dev-01\"\nexport SERVICEBUS_QUEUE_NAME=\"orders\"\nexport SERVICEBUS_TOPIC_NAME=\"events\"\nexport SERVICEBUS_SUBSCRIPTION_NAME=\"billing\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Client Setup\n\nUse one of these credential patterns:\n\n- `DefaultAzureCredential()` for reusable code, CI, managed identity, or workload identity\n- `AzureCliCredential()` for local scripts after `az login`\n\nBasic setup:\n\n```python\nimport os\nfrom datetime import timedelta\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicebus import ServiceBusManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = ServiceBusManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n\nmodels = client.models()\n```\n\nLocal CLI-driven scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.servicebus import ServiceBusManagementClient\n\nclient = ServiceBusManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\n`client.models()` is useful when you want constructors that match the selected API version instead of importing a versioned model module directly.\n\nAuthentication success is not enough by itself. The principal also needs Azure RBAC permissions to manage `Microsoft.ServiceBus/*` resources at the subscription, resource-group, or namespace scope you target.\n\n## Core Workflows\n\n### Check namespace name availability\n\nNamespace names are globally unique. Check first instead of learning from a failed create call:\n\n```python\nimport os\n\nresource_group_name = os.environ[\"AZURE_RESOURCE_GROUP\"]\nnamespace_name = os.environ[\"SERVICEBUS_NAMESPACE_NAME\"]\n\navailability = client.namespaces.check_name_availability(\n    models.CheckNameAvailability(name=namespace_name)\n)\n\nif not availability.name_available:\n    raise RuntimeError(availability.message or availability.reason)\n```\n\n### Create a namespace\n\nNamespace creation is a long-running ARM operation, so call `.result()` on the poller before using the namespace:\n\n```python\nnamespace = client.namespaces.begin_create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    parameters=models.SBNamespace(\n        location=\"eastus\",\n        sku=models.SBSku(name=\"Standard\", tier=\"Standard\"),\n        disable_local_auth=False,\n        tags={\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n    ),\n).result()\n\nprint(namespace.id)\nprint(namespace.service_bus_endpoint)\n```\n\nUse `Standard` or `Premium` if you plan to create topics and subscriptions. Microsoft Learn's namespace quickstart notes that the `Basic` tier does not support topics.\n\n### Lock down namespace network access\n\nNetwork rules are managed on the namespace after it exists:\n\n```python\nnetwork_rules = client.namespaces.create_or_update_network_rule_set(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    parameters=models.NetworkRuleSet(\n        default_action=\"Deny\",\n        public_network_access=\"Enabled\",\n        trusted_service_access_enabled=False,\n        ip_rules=[\n            models.NWRuleSetIpRules(\n                ip_mask=\"203.0.113.10\",\n                action=\"Allow\",\n            )\n        ],\n    ),\n)\n\nprint(network_rules.default_action)\n```\n\nIf you need virtual network rules, add `virtual_network_rules` entries with the target subnet resource IDs.\n\n### Create a queue\n\nQueue settings are regular ARM resources. The generated `SBQueue` model accepts `timedelta` values for duration fields:\n\n```python\nqueue = client.queues.create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    queue_name=os.environ[\"SERVICEBUS_QUEUE_NAME\"],\n    parameters=models.SBQueue(\n        lock_duration=timedelta(minutes=1),\n        default_message_time_to_live=timedelta(days=7),\n        max_size_in_megabytes=1024,\n        max_delivery_count=10,\n        dead_lettering_on_message_expiration=True,\n        enable_batched_operations=True,\n    ),\n)\n\nprint(queue.id)\n```\n\nOther commonly used queue fields in this SDK version include `requires_session`, `requires_duplicate_detection`, `forward_dead_lettered_messages_to`, and `enable_partitioning`.\n\n### Create a queue authorization rule and fetch keys\n\nUse shared access keys only when your application really needs SAS-based authentication:\n\n```python\nclient.queues.create_or_update_authorization_rule(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    queue_name=os.environ[\"SERVICEBUS_QUEUE_NAME\"],\n    authorization_rule_name=\"send-listen\",\n    parameters=models.SBAuthorizationRule(\n        rights=[\"Listen\", \"Send\"],\n    ),\n)\n\nkeys = client.queues.list_keys(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    queue_name=os.environ[\"SERVICEBUS_QUEUE_NAME\"],\n    authorization_rule_name=\"send-listen\",\n)\n\nprint(keys.primary_connection_string)\n```\n\nIf the namespace was created with `disable_local_auth=True`, do not build new integrations around SAS rules or connection strings.\n\n### Create a topic, subscription, and filter rule\n\nTopics and subscriptions are available only in `Standard` and `Premium` namespaces:\n\n```python\ntopic = client.topics.create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    topic_name=os.environ[\"SERVICEBUS_TOPIC_NAME\"],\n    parameters=models.SBTopic(),\n)\n\nsubscription = client.subscriptions.create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    topic_name=topic.name,\n    subscription_name=os.environ[\"SERVICEBUS_SUBSCRIPTION_NAME\"],\n    parameters=models.SBSubscription(),\n)\n\nrule = client.rules.create_or_update(\n    resource_group_name=os.environ[\"AZURE_RESOURCE_GROUP\"],\n    namespace_name=os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    topic_name=topic.name,\n    subscription_name=subscription.name,\n    rule_name=\"invoice-created\",\n    parameters=models.Rule(\n        filter_type=\"CorrelationFilter\",\n        correlation_filter=models.CorrelationFilter(\n            label=\"invoice.created\",\n        ),\n    ),\n)\n\nprint(rule.name)\n```\n\n`Rule` also supports `sql_filter` when you need SQL-style subscription filters instead of a correlation filter.\n\n### List and inspect existing resources\n\n```python\nfor namespace in client.namespaces.list_by_resource_group(os.environ[\"AZURE_RESOURCE_GROUP\"]):\n    print(namespace.name, namespace.location, namespace.sku.name)\n\nfor queue in client.queues.list_by_namespace(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n):\n    print(\"queue:\", queue.name)\n\nfor topic in client.topics.list_by_namespace(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n):\n    print(\"topic:\", topic.name)\n\nfor subscription in client.subscriptions.list_by_topic(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    os.environ[\"SERVICEBUS_TOPIC_NAME\"],\n):\n    print(\"subscription:\", subscription.name)\n\nfor rule in client.rules.list_by_subscriptions(\n    os.environ[\"AZURE_RESOURCE_GROUP\"],\n    os.environ[\"SERVICEBUS_NAMESPACE_NAME\"],\n    os.environ[\"SERVICEBUS_TOPIC_NAME\"],\n    os.environ[\"SERVICEBUS_SUBSCRIPTION_NAME\"],\n):\n    print(\"rule:\", rule.name)\n```\n\n## Configuration Notes\n\n- `ServiceBusManagementClient` requires `subscription_id`; it is not inferred from the credential.\n- The client constructor accepts `api_version` and `profile`. The Learn docs recommend pinning these only when you intentionally need a specific API surface or cloud profile.\n- `client.models()` follows the selected API version, which is safer than hard-coding imports from `azure.mgmt.servicebus.v2021_11_01.models` if you later switch versions.\n- Service Bus namespace names must be 6 to 50 characters, use only letters, numbers, and hyphens, start with a letter, end with a letter or number, and cannot end with `-sb` or `-mgmt`.\n- Namespace creation is ARM-based and asynchronous. Wait for `.result()` before creating child resources such as queues, topics, or authorization rules.\n\n## Version-Sensitive Notes\n\n### `9.0.0`\n\nPyPI lists these package-level changes for `9.0.0`:\n\n- Python `3.9` is now the minimum supported version.\n- Unused subfolders for non-latest API versions were removed to reduce package size.\n- `EventHubsOperations`, `PremiumMessagingRegionsOperations`, and `RegionsOperations` were removed from the generated client surface.\n\nIf your code imports older versioned modules or depends on removed operation groups, pin an earlier package version before reusing `9.0.0` examples.\n\n### API version behavior\n\nThe `ServiceBusManagementClient` docs show the stable default API version as `2021-11-01` and also document preview operation groups under `2022-10-01-preview`. Use the default stable version unless you intentionally need preview fields and have verified them against the correct versioned docs.\n\n## Common Pitfalls\n\n- Using `azure-mgmt-servicebus` for send and receive code instead of `azure-servicebus`\n- Forgetting `AZURE_SUBSCRIPTION_ID`\n- Calling `begin_create_or_update` or `begin_delete` and then using the resource before `.result()`\n- Creating a `Basic` namespace and then expecting topics or subscriptions to work\n- Generating SAS keys and connection strings even though the namespace uses `disable_local_auth=True`\n- Copying imports from removed API-version folders or removed operation groups after upgrading to `9.0.0`\n- Ignoring namespace naming rules until ARM rejects the deployment\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-servicebus/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.servicebusmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.operations.namespacesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.operations.queuesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.operations.topicsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.operations.subscriptionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.operations.rulesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.models.sbqueue?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.models.networkruleset?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.models.rule?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicebus/azure.mgmt.servicebus.v2021_11_01.models.correlationfilter?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.azureclicredential?view=azure-python\n- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quickstart-portal\n"
  },
  {
    "path": "content/azure/docs/mgmt-servicefabric/python/DOC.md",
    "content": "---\nname: mgmt-servicefabric\ndescription: \"Azure Service Fabric management SDK for Python for classic clusters, application types, applications, services, and runtime version checks through Azure Resource Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,service-fabric,arm,management,python,clusters\"\n---\n\n# Azure Service Fabric Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-servicefabric` for Azure Resource Manager management-plane work against classic Service Fabric cluster resources: clusters, application types, application type versions, applications, services, available cluster code versions, and unsupported VM sizes. Install `azure-identity` alongside it, authenticate with a `TokenCredential`, and use `ServiceFabricManagementClient` as a context manager or call `close()` when you are done.\n\nIf your code uses `ServiceFabricManagedClustersManagementClient`, `managed_clusters`, or managed-cluster node type operations, you are in the separate `azure-mgmt-servicefabricmanagedclusters` package and should not copy examples from this guide blindly.\n\n## Install\n\nPin the package version your project expects and install Azure Identity with it:\n\n```bash\npython -m pip install \"azure-mgmt-servicefabric==2.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-servicefabric==2.1.0\" azure-identity\npoetry add \"azure-mgmt-servicefabric==2.1.0\" azure-identity\n```\n\nPyPI lists this package as requiring Python `>=3.7`.\n\n## Authentication And Setup\n\nUse `DefaultAzureCredential` for reusable code and CI, or `AzureCliCredential` for local scripts after `az login`.\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nwith ServiceFabricManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n) as client:\n    print(type(client))\n```\n\nFor local Azure CLI-driven scripts:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for cluster in client.clusters.list():\n        print(cluster.name)\n```\n\n## Main Operation Groups\n\n`ServiceFabricManagementClient` exposes the operation groups you will usually need:\n\n- `clusters`\n- `cluster_versions`\n- `application_types`\n- `application_type_versions`\n- `applications`\n- `services`\n- `unsupported_vm_sizes`\n\n## Common Workflows\n\n### List And Inspect Clusters\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for cluster in client.clusters.list_by_resource_group(\"rg-servicefabric\"):\n        print(cluster.name, cluster.location, cluster.id)\n\n    cluster = client.clusters.get(\n        resource_group_name=\"rg-servicefabric\",\n        cluster_name=\"sf-cluster\",\n    )\n    print(cluster.name, cluster.location, cluster.id)\n```\n\nUse `list()` for subscription-wide inventory and `list_by_resource_group()` when you already know the resource group.\n\n### Check Available Runtime Versions For A Region And OS\n\n`cluster_versions.list_by_environment(...)` returns a `ClusterCodeVersionsListResult`, not a paged iterator. Read the `.value` list from the result.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    versions = client.cluster_versions.list_by_environment(\n        location=\"eastus\",\n        environment=\"Linux\",\n    )\n\n    for item in versions.value or []:\n        print(item.code_version)\n```\n\nThe documented environment values are `\"Windows\"` and `\"Linux\"`.\n\n### Check Whether A Cluster Can Upgrade To Newer Code Versions\n\n`clusters.list_upgradable_versions(...)` asks ARM for the minimum and maximum upgradeable versions from the cluster's current code version. If you already know the target version, pass an `UpgradableVersionsDescription` as `versions_description`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    upgrade_info = client.clusters.list_upgradable_versions(\n        resource_group_name=\"rg-servicefabric\",\n        cluster_name=\"sf-cluster\",\n    )\n\n    print(upgrade_info)\n```\n\nUse this before editing cluster code versions manually. Microsoft documents supported upgrade paths separately from the SDK API reference.\n\n### Preflight Unsupported VM Sizes\n\nBefore changing node sizes for a classic cluster, query the unsupported sizes for the region instead of guessing:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for vm_size in client.unsupported_vm_sizes.list(\"eastus\"):\n        print(vm_size.name)\n```\n\n`unsupported_vm_sizes.get(location, vm_size)` is the direct lookup if you want to check one size.\n\n### List Registered Application Types And Versions\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for app_type in client.application_types.list(\n        resource_group_name=\"rg-servicefabric\",\n        cluster_name=\"sf-cluster\",\n    ):\n        print(app_type.name)\n\n    for app_version in client.application_type_versions.list(\n        resource_group_name=\"rg-servicefabric\",\n        cluster_name=\"sf-cluster\",\n        application_type_name=\"VotingType\",\n    ):\n        print(app_version.name)\n```\n\nThis is the safest way to discover what application package names and versions are already registered before you create or update an application resource.\n\n### List Applications And Services In A Cluster\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.servicefabric import ServiceFabricManagementClient\n\nresource_group_name = \"rg-servicefabric\"\ncluster_name = \"sf-cluster\"\napplication_name = \"voting-app\"\n\nwith ServiceFabricManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n) as client:\n    for application in client.applications.list(\n        resource_group_name=resource_group_name,\n        cluster_name=cluster_name,\n    ):\n        print(application.name, application.id)\n\n    for service in client.services.list(\n        resource_group_name=resource_group_name,\n        cluster_name=cluster_name,\n        application_name=application_name,\n    ):\n        print(service.name, service.type)\n```\n\nFor `services.get(...)` and service update calls, the official docs require `service_name` in the format `{applicationName}~{serviceName}`.\n\n## Publishing An Application Package Through ARM\n\nThe management flow is split across several resource types. The usual sequence is:\n\n1. `client.application_types.create_or_update(...)`\n2. `client.application_type_versions.begin_create_or_update(...)`\n3. `client.applications.begin_create_or_update(...)`\n4. `client.services.begin_create_or_update(...)`\n\nImportant payload details verified from Microsoft template and API docs:\n\n- an application type version resource needs an `appPackageUrl`\n- an application resource needs the application `typeName` and `typeVersion`\n- version, application, and service create/update flows are long-running operations, so use `.result()` on the returned poller\n\nKeep create payloads aligned with the exact ARM API version your environment uses. Service Fabric resource bodies are large enough that copying old blog examples is high risk.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-servicefabric` without `azure-identity`\n- Forgetting `AZURE_SUBSCRIPTION_ID`; the credential does not supply it automatically\n- Treating `cluster_versions.list_by_environment(...)` like a paged iterator instead of reading the returned `.value`\n- Confusing the `cluster_versions` location argument with a cluster resource ID; the API expects a region string such as `eastus`\n- Mixing classic Service Fabric cluster operations with the separate managed-clusters package\n- Forgetting to close the client or use it as a context manager\n- Assuming every write call is immediate; `begin_*` methods return pollers and need `.result()` when you must wait for completion\n- Passing the wrong `service_name` shape to `services.get(...)` or update calls; the docs require `{applicationName}~{serviceName}`\n\n## Version-Sensitive Notes For `2.1.0`\n\n- PyPI lists `2.1.0` as released on `2023-12-18`.\n- The `2.1.0` release added the `ClusterVersionsEnvironment` model, which is relevant when you query runtime versions by OS environment.\n- The modern Azure SDK behavior from the `1.0.0` line still applies in `2.1.0`: long-running operations use `azure.core.polling.LROPoller`, `begin_*` prefixes are used for those operations, and most failures surface as `azure.core.exceptions.HttpResponseError`.\n- PyPI also notes stable async support via the package's `aio` namespace. Use that only if the rest of your application already runs on asyncio.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-servicefabric/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.servicefabricmanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.clustersoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.clusterversionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.applicationtypesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.applicationtypeversionsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.applicationsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.servicesoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-servicefabric/azure.mgmt.servicefabric.operations.unsupportedvmsizesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python\n- https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-upgrade-version-azure\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.servicefabric/2021-06-01/clusters/applicationtypes\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.servicefabric/2021-06-01/clusters/applicationtypes/versions\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.servicefabric/clusters/applications\n"
  },
  {
    "path": "content/azure/docs/mgmt-signalr/python/DOC.md",
    "content": "---\nname: mgmt-signalr\ndescription: \"Azure SignalR Service management SDK for Python for provisioning resources, reading keys, managing replicas, and configuring custom certificates and domains\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,signalr,management,arm,real-time,python\"\n---\n\n# Azure SignalR Service Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-signalr` for Azure Resource Manager control-plane work only: creating or updating Azure SignalR resources, listing keys, scaling SKUs, managing replicas, and configuring custom certificates or domains. Do not use this package to negotiate client connections or publish messages to hubs. Those are data-plane tasks and use different Azure SignalR APIs.\n\n## Install\n\n`azure-mgmt-signalr` depends on Azure AD or managed-identity credentials from `azure-identity`.\n\n```bash\npython -m pip install \"azure-mgmt-signalr==1.2.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-signalr==1.2.0\" azure-identity\npoetry add \"azure-mgmt-signalr==1.2.0\" azure-identity\n```\n\nPyPI lists `azure-mgmt-signalr 1.2.0` as the current stable release and requires Python 3.7+.\n\n## Authentication And Setup\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor service-principal auth, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nFor local development, `DefaultAzureCredential()` is usually the right default. It can pick up Azure CLI sign-in, environment variables, workload identity, or managed identity. For local scripts where you want to force Azure CLI auth, use `AzureCliCredential()`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.signalr import SignalRManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = SignalRManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nCLI-driven local scripts can be explicit:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.signalr import SignalRManagementClient\n\nclient = SignalRManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe official client docs show a default `api_version` of `2023-08-01-preview`. Do not override that unless you have a specific reason and have verified the matching REST surface yourself.\n\n## Core Client Surface\n\nThe current client exposes these high-value operation groups:\n\n- `client.signal_r`: create, update, delete, list, list keys, list SKUs, restart, check name availability\n- `client.signal_rreplicas`: create, update, list, restart, delete replicas\n- `client.signal_rcustom_certificates`: create, list, get, delete Key Vault-backed certificates\n- `client.signal_rcustom_domains`: create, list, get, delete custom domains\n- `client.signal_rprivate_endpoint_connections`, `client.signal_rprivate_link_resources`, `client.signal_rshared_private_link_resources`: private networking workflows\n- `client.usages`: subscription and regional usage information\n\nMost write operations are long-running operations. Call `.result()` before depending on the returned resource state.\n\n## Common Workflows\n\n### Create Or Update A SignalR Resource\n\nThis example creates a Standard tier SignalR resource in serverless mode. If your application servers establish server connections to Azure SignalR, change the `ServiceMode` feature to `\"Default\"` instead.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.signalr import SignalRManagementClient\nfrom azure.mgmt.signalr.models import (\n    ResourceSku,\n    ServerlessSettings,\n    SignalRFeature,\n    SignalRResource,\n)\n\nclient = SignalRManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.signal_r.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-signalr\",\n    parameters=SignalRResource(\n        location=\"westus2\",\n        sku=ResourceSku(\n            name=\"Standard_S1\",\n            tier=\"Standard\",\n            capacity=1,\n        ),\n        features=[\n            SignalRFeature(flag=\"ServiceMode\", value=\"Serverless\"),\n            SignalRFeature(flag=\"EnableConnectivityLogs\", value=\"True\"),\n            SignalRFeature(flag=\"EnableMessagingLogs\", value=\"False\"),\n            SignalRFeature(flag=\"EnableLiveTrace\", value=\"False\"),\n        ],\n        serverless=ServerlessSettings(connection_timeout_in_seconds=30),\n        public_network_access=\"Enabled\",\n        disable_local_auth=False,\n        disable_aad_auth=False,\n        tags={\"env\": \"dev\", \"owner\": \"context-hub\"},\n    ),\n)\n\nresource = poller.result()\nprint(resource.id)\nprint(resource.host_name)\n```\n\nImportant details:\n\n- `location` is required.\n- `SignalRFeature(flag=\"ServiceMode\", value=...)` controls whether the service runs in `Default`, `Serverless`, or `Classic` mode.\n- For new apps, Microsoft recommends `Default` or `Serverless`, not `Classic`.\n- Valid stable SKU names include `Free_F1`, `Standard_S1`, `Premium_P1`, and `Premium_P2`.\n\n### List Resources And Inspect Available SKUs\n\n```python\nfor resource in client.signal_r.list_by_resource_group(\"example-rg\"):\n    print(resource.name, resource.location, resource.sku.name)\n\nresource = client.signal_r.get(\"example-rg\", \"example-signalr\")\nprint(resource.host_name)\nprint(resource.public_port, resource.server_port)\n\nsku_list = client.signal_r.list_skus(\"example-rg\", \"example-signalr\")\nfor sku in sku_list.value:\n    print(sku.name, sku.capacity)\n```\n\nThe ARM template reference for the same API family documents these capacity rules:\n\n- `Free_F1`: only `1`\n- `Standard_S1` and `Premium_P1`: `1-10`, then `20-100`\n- `Premium_P2`: `100-1000` in increments of `100`\n\n### Read And Rotate Access Keys\n\nUse management-plane key operations when you need the current connection strings or need to rotate a primary or secondary key.\n\n```python\nfrom azure.mgmt.signalr.models import RegenerateKeyParameters\n\nkeys = client.signal_r.list_keys(\"example-rg\", \"example-signalr\")\nprint(keys.primary_connection_string)\nprint(keys.secondary_connection_string)\n\nrotated = client.signal_r.begin_regenerate_key(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-signalr\",\n    parameters=RegenerateKeyParameters(key_type=\"Primary\"),\n).result()\n\nprint(rotated.primary_connection_string)\n```\n\nAzure rotates only one key at a time. Update your applications to the other connection string before regenerating the active key.\n\n### Add A Replica\n\nUse replica operations when you need additional regional endpoints or want to manage replica-specific routing state.\n\n```python\nfrom azure.mgmt.signalr.models import Replica, ResourceSku\n\nreplica = client.signal_rreplicas.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-signalr\",\n    replica_name=\"eastus2\",\n    parameters=Replica(\n        location=\"eastus2\",\n        sku=ResourceSku(\n            name=\"Premium_P1\",\n            tier=\"Premium\",\n            capacity=1,\n        ),\n        region_endpoint_enabled=\"Enabled\",\n    ),\n).result()\n\nprint(replica.id)\n\nfor item in client.signal_rreplicas.list(\"example-rg\", \"example-signalr\"):\n    print(item.name, item.location)\n```\n\nReplica resources have their own `region_endpoint_enabled` and `resource_stopped` properties. The ARM template reference notes that disabling the regional endpoint is replica-specific.\n\n### Configure A Custom Certificate And Custom Domain\n\nCustom domains are a Premium tier feature. The official custom-domain guide also requires:\n\n- a managed identity on the Azure SignalR resource\n- Key Vault access for that identity\n- a certificate stored in Key Vault\n- a `CNAME` from your custom host name to the default `*.service.signalr.net` host\n\n```python\nfrom azure.mgmt.signalr.models import CustomCertificate, CustomDomain, ResourceReference\n\ncertificate = client.signal_rcustom_certificates.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-signalr\",\n    certificate_name=\"tls-cert\",\n    parameters=CustomCertificate(\n        key_vault_base_uri=\"https://contoso.vault.azure.net\",\n        key_vault_secret_name=\"signalr-cert\",\n        key_vault_secret_version=\"\",\n    ),\n).result()\n\ndomain = client.signal_rcustom_domains.begin_create_or_update(\n    resource_group_name=\"example-rg\",\n    resource_name=\"example-signalr\",\n    name=\"prod-domain\",\n    parameters=CustomDomain(\n        domain_name=\"realtime.contoso.com\",\n        custom_certificate=ResourceReference(id=certificate.id),\n    ),\n).result()\n\nprint(domain.domain_name)\n```\n\nIf you do not pin `key_vault_secret_version`, Azure SignalR periodically checks Key Vault for a newer certificate version and applies it automatically.\n\n## Common Pitfalls\n\n- Do not confuse management plane and data plane. `azure-mgmt-signalr` provisions the service; it does not broadcast messages or run negotiate endpoints.\n- `AZURE_SUBSCRIPTION_ID` is required. The credential does not infer the subscription automatically.\n- Long-running operations return pollers. Always call `.result()` before reading fields such as `id`, `host_name`, or child-resource IDs.\n- Avoid `Classic` mode for new applications. Microsoft documents it as backward compatibility mode.\n- The client constructor accepts `api_version`, but the official docs warn that overriding it can lead to unsupported behavior.\n- Scaling across pricing tiers can cause downtime when the public service IP changes. Microsoft documents downtime for `Free` to `Standard` or `Premium` transitions; `Standard_S1` to `Premium_P1` and `Premium_P1` to `Premium_P2` are documented as no-downtime transitions.\n- Custom domains are not a Standard-tier feature. Upgrade to Premium before automating certificate or domain resources.\n\n## Version-Sensitive Notes\n\n- `1.2.0` adds the `serverless` parameter on `SignalRResource`. The serverless example in this guide assumes `1.2.0`.\n- `1.1.0` added `SignalRCustomCertificatesOperations`, `SignalRCustomDomainsOperations`, and `live_trace_configuration`.\n- `1.0.0` added `disable_local_auth`, `disable_aad_auth`, `public_network_access`, and `list_skus`.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-signalr/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.signalrmanagementclient?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.operations.signalroperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.operations.signalrreplicasoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.operations.signalrcustomcertificatesoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.operations.signalrcustomdomainsoperations?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.models.signalrresource?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.models.signalrfeature?view=azure-python-preview\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-signalr/azure.mgmt.signalr.models.serverlesssettings?view=azure-python-preview\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/credential-chains\n- https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/local-development-service-principal\n- https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-resource-faq\n- https://learn.microsoft.com/en-us/azure/azure-signalr/howto-custom-domain\n- https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-howto-scale-signalr\n- https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-howto-key-rotation\n- https://learn.microsoft.com/en-us/azure/azure-signalr/concept-connection-string\n- https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-reference-data-plane-rest-api\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.signalrservice/2023-08-01-preview/signalr\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.signalrservice/2024-03-01/signalr/replicas\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.signalrservice/signalr/customcertificates\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.signalrservice/signalr/customdomains\n- https://learn.microsoft.com/en-us/rest/api/signalr/signalr/regenerate-key\n"
  },
  {
    "path": "content/azure/docs/mgmt-sql/python/DOC.md",
    "content": "---\nname: mgmt-sql\ndescription: \"Azure SQL management SDK for Python: create and manage logical servers, databases, firewall rules, and other ARM resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-sql,sql,management,arm,database\"\n---\n\n# Azure SQL Management SDK For Python\n\n## Golden Rule\n\nUse `azure-mgmt-sql` for Azure Resource Manager control-plane tasks such as creating logical servers, databases, firewall rules, failover groups, and other Azure SQL resources. Do not use it to open SQL connections or run queries against a database; for that, use a data-plane driver such as `pyodbc` or SQLAlchemy on top of a SQL Server driver.\n\nThe normal Azure pattern is:\n\n1. Authenticate with `azure-identity`\n2. Construct `SqlManagementClient`\n3. Call an operation group such as `servers`, `databases`, or `firewall_rules`\n4. Wait on `.result()` for any `begin_*` long-running operation\n\n## Install\n\nPin the management package and install `azure-identity` alongside it for Microsoft Entra ID auth:\n\n```bash\npython -m pip install \"azure-mgmt-sql==3.0.1\" \"azure-identity\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-sql==3.0.1\" azure-identity\npoetry add \"azure-mgmt-sql==3.0.1\" azure-identity\n```\n\nIf you authenticate with a service principal in CI, you usually also need these environment variables:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"<subscription-id>\"\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nFor local development, Microsoft recommends signing in with Azure developer tooling and letting `DefaultAzureCredential` reuse it:\n\n```bash\naz login\n```\n\n## Authentication And Client Setup\n\n`SqlManagementClient` is an Azure management-plane client. You need:\n\n- an Azure credential, usually `DefaultAzureCredential()`\n- a subscription ID\n- ARM permissions on the target subscription or resource group\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = SqlManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nPractical notes:\n\n- Reuse one credential and one client per process instead of recreating them for every call.\n- `DefaultAzureCredential` is the fastest path for code that must run both locally and in Azure.\n- Local sign-in success is not enough by itself; the identity also needs permission to manage the target SQL resources.\n\n### Sovereign clouds\n\nIf you are not using the public Azure cloud, align both the credential authority and the management endpoint. For example, sovereign-cloud setups often need a non-default `authority` for the credential and a non-default `base_url` for `SqlManagementClient`.\n\n## Core Usage\n\n### List logical servers in a resource group\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\n\ncredential = DefaultAzureCredential()\nclient = SqlManagementClient(credential, subscription_id=\"00000000-0000-0000-0000-000000000000\")\n\nfor server in client.servers.list_by_resource_group(\"rg-app-prod\"):\n    print(server.name, server.location, server.fully_qualified_domain_name)\n```\n\n### Create or update a logical server\n\nServer create and update calls are long-running operations, so use the `begin_` method and wait for the poller result.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\nfrom azure.mgmt.sql.models import Server\n\ncredential = DefaultAzureCredential()\nclient = SqlManagementClient(credential, subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"])\n\npoller = client.servers.begin_create_or_update(\n    resource_group_name=\"rg-app-prod\",\n    server_name=\"my-sql-server\",\n    parameters=Server(\n        location=\"eastus\",\n        administrator_login=\"sqladminuser\",\n        administrator_login_password=os.environ[\"AZURE_SQL_ADMIN_PASSWORD\"],\n        version=\"12.0\",\n        minimal_tls_version=\"1.2\",\n        public_network_access=\"Enabled\",\n    ),\n)\n\nserver = poller.result()\nprint(server.id)\nprint(server.fully_qualified_domain_name)\n```\n\n### Create a database\n\nThe database payload typically includes `location` and a `Sku`. For basic provisioning flows, constructing the model classes explicitly is clearer than guessing the JSON shape.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\nfrom azure.mgmt.sql.models import Database, Sku\n\ncredential = DefaultAzureCredential()\nclient = SqlManagementClient(credential, subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"])\n\npoller = client.databases.begin_create_or_update(\n    resource_group_name=\"rg-app-prod\",\n    server_name=\"my-sql-server\",\n    database_name=\"appdb\",\n    parameters=Database(\n        location=\"eastus\",\n        sku=Sku(name=\"Basic\", tier=\"Basic\"),\n    ),\n)\n\ndatabase = poller.result()\nprint(database.name, database.status)\n```\n\n### List databases on a server\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\n\ncredential = DefaultAzureCredential()\nclient = SqlManagementClient(credential, subscription_id=\"00000000-0000-0000-0000-000000000000\")\n\nfor database in client.databases.list_by_server(\"rg-app-prod\", \"my-sql-server\"):\n    print(database.name, database.status)\n```\n\n### Create or update a firewall rule\n\nFirewall rules are managed through `client.firewall_rules`. This operation is not exposed as `begin_*`, so it returns the resource directly.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sql import SqlManagementClient\nfrom azure.mgmt.sql.models import FirewallRule\n\ncredential = DefaultAzureCredential()\nclient = SqlManagementClient(credential, subscription_id=\"00000000-0000-0000-0000-000000000000\")\n\nrule = client.firewall_rules.create_or_update(\n    resource_group_name=\"rg-app-prod\",\n    server_name=\"my-sql-server\",\n    firewall_rule_name=\"office-ip\",\n    parameters=FirewallRule(\n        start_ip_address=\"203.0.113.10\",\n        end_ip_address=\"203.0.113.10\",\n    ),\n)\n\nprint(rule.name, rule.start_ip_address, rule.end_ip_address)\n```\n\n### Delete a database or server\n\nDelete operations are usually long-running as well:\n\n```python\nclient.databases.begin_delete(\n    resource_group_name=\"rg-app-prod\",\n    server_name=\"my-sql-server\",\n    database_name=\"appdb\",\n).result()\n\nclient.servers.begin_delete(\n    resource_group_name=\"rg-app-prod\",\n    server_name=\"my-sql-server\",\n).result()\n```\n\n## Configuration Notes\n\n- `subscription_id` is required. Keep it explicit instead of assuming the default Azure CLI subscription is always the right one.\n- `SqlManagementClient` targets Azure Resource Manager. For public Azure, the management endpoint is `https://management.azure.com`.\n- Many create and update calls require a full resource payload, not just the field you want to mutate. Read the model page before sending partial objects.\n- The package exposes many operation groups beyond the common ones above, including elastic pools, failover groups, managed instances, backup policies, and sync groups. Check the operation group on the client before assuming a resource is unsupported.\n\n## Common Pitfalls\n\n- `azure-mgmt-sql` is management-plane only. It provisions and configures Azure SQL resources but does not execute SQL statements.\n- Many write operations use `begin_*`. If you forget `.result()`, your code may exit before the ARM operation finishes.\n- Resource names are ARM resource names, not connection strings or DNS names. Keep `resource_group_name`, `server_name`, and `database_name` distinct.\n- Azure authentication problems often come from missing RBAC, not broken credentials. A successful `az login` does not guarantee write access.\n- The special firewall rule address `0.0.0.0` is Azure SQL's \"allow Azure services\" behavior, not a generic internet allowlist. Do not use it casually.\n- Use the same region assumptions across related resources. Server and database provisioning often fail or behave unexpectedly when the payload does not match the intended location and SKU combination.\n- This package is generated from Azure management APIs and still uses older Azure SDK model patterns. When in doubt, check the exact model type in Microsoft Learn before inventing field names.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `3.0.1` as the latest stable release for `azure-mgmt-sql`.\n- The PyPI release page also shows a prerelease line (`4.0.0b24`). Do not adopt the beta line unless your project intentionally targets it.\n- `3.0.1` is an older management package release. The Microsoft Learn reference is still live, but newer Azure SQL platform features may appear in REST docs or portal UX before they show up in examples for this Python SDK.\n- PyPI metadata for `3.0.1` lists older Python classifiers. If your project runs on a newer Python version, validate install and smoke-test the specific management operations you need instead of assuming the package follows the newer baseline used by other Azure SDK libraries.\n\n## Official Sources\n\n- Microsoft Learn package index: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/`\n- Microsoft Learn client reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.sqlmanagementclient?view=azure-python`\n- Microsoft Learn servers operations: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.operations.serversoperations?view=azure-python`\n- Microsoft Learn databases operations: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.operations.databasesoperations?view=azure-python`\n- Microsoft Learn firewall rules operations: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.operations.firewallrulesoperations?view=azure-python`\n- Microsoft Learn server model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.models.server?view=azure-python`\n- Microsoft Learn database model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.models.database?view=azure-python`\n- Microsoft Learn firewall rule model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.models.firewallrule?view=azure-python`\n- Microsoft Learn SKU model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sql/azure.mgmt.sql.models.sku?view=azure-python`\n- Microsoft Learn Azure auth overview: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview`\n- Microsoft Learn Azure Identity README: `https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python`\n- PyPI package page: `https://pypi.org/project/azure-mgmt-sql/`\n"
  },
  {
    "path": "content/azure/docs/mgmt-sqlvirtualmachine/python/DOC.md",
    "content": "---\nname: mgmt-sqlvirtualmachine\ndescription: \"Azure SQL Virtual Machine management SDK for Python for registering SQL Server VMs, managing SQL VM groups, and configuring SQL IaaS extension settings\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,sql-virtual-machine,sql,management,arm,vm\"\n---\n\n# Azure SQL Virtual Machine Management SDK For Python\n\n## Golden Rule\n\nUse `azure-mgmt-sqlvirtualmachine` for Azure Resource Manager control-plane work on SQL Server running in Azure virtual machines. This package manages SQL virtual machine resources, SQL virtual machine groups, and availability-group-related resources exposed by the SQL IaaS extension. It does not open TDS connections or run SQL queries inside the instance.\n\nFor Python code, the safe pattern is:\n\n1. Authenticate with `azure-identity`\n2. Construct `SqlVirtualMachineManagementClient`\n3. Use an operation group such as `sql_virtual_machines` or `sql_virtual_machine_groups`\n4. Wait on `.result()` for `begin_*` operations\n\n## Install\n\nPin the package version you actually target and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-sqlvirtualmachine==0.5.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-sqlvirtualmachine==0.5.0\" azure-identity\npoetry add \"azure-mgmt-sqlvirtualmachine==0.5.0\" azure-identity\n```\n\nPyPI describes `0.5.0` as tested with Python 2.7, 3.5, 3.6, and 3.7. If you are running a newer Python version, verify compatibility in your own environment before you rely on this package in production.\n\n## Authentication And Client Setup\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nFor local development, sign in with Azure CLI:\n\n```bash\naz login\n```\n\nFor CI or other non-interactive environments, set a service principal:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sqlvirtualmachine import SqlVirtualMachineManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = SqlVirtualMachineManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nUse this import path:\n\n```python\nfrom azure.mgmt.sqlvirtualmachine import SqlVirtualMachineManagementClient\n```\n\nThe PyPI release history for `0.4.0` explicitly calls out that importing from `azure.mgmt.sqlvirtualmachine.sql_virtual_machine_management_client` is no longer the supported path.\n\n## Core Usage\n\nThe client exposes these main operation groups in the current Microsoft Learn reference:\n\n- `sql_virtual_machines`\n- `sql_virtual_machine_groups`\n- `availability_group_listeners`\n- `sql_virtual_machine_troubleshoot`\n- `operations`\n\nThis guide stays focused on the stable `0.5.0` line and the core SQL virtual machine flows that are clearly documented across PyPI and Learn.\n\n### List SQL virtual machines in a resource group\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sqlvirtualmachine import SqlVirtualMachineManagementClient\n\nclient = SqlVirtualMachineManagementClient(\n    DefaultAzureCredential(),\n    os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nfor sql_vm in client.sql_virtual_machines.list_by_resource_group(\"rg-sqlvm-prod\"):\n    print(sql_vm.name, sql_vm.location, sql_vm.virtual_machine_resource_id)\n```\n\n### Get one SQL virtual machine resource\n\n```python\nsql_vm = client.sql_virtual_machines.get(\n    resource_group_name=\"rg-sqlvm-prod\",\n    sql_virtual_machine_name=\"sqlvm-prod\",\n)\n\nprint(sql_vm.name)\nprint(sql_vm.sql_management)\nprint(sql_vm.sql_server_license_type)\nprint(sql_vm.virtual_machine_resource_id)\n```\n\n### Create or update a SQL virtual machine registration\n\nThe `SqlVirtualMachine` model requires `location`. The current model reference also documents fields such as `virtual_machine_resource_id`, `sql_server_license_type`, `sql_management`, and `storage_configuration_settings`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.sqlvirtualmachine import SqlVirtualMachineManagementClient\nfrom azure.mgmt.sqlvirtualmachine.models import (\n    SQLStorageSettings,\n    SqlVirtualMachine,\n    StorageConfigurationSettings,\n)\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\nresource_group_name = \"rg-sqlvm-prod\"\nsql_virtual_machine_name = \"sqlvm-prod\"\nvm_resource_id = (\n    f\"/subscriptions/{subscription_id}\"\n    f\"/resourceGroups/{resource_group_name}\"\n    \"/providers/Microsoft.Compute/virtualMachines/sqlvm-prod\"\n)\n\nclient = SqlVirtualMachineManagementClient(\n    DefaultAzureCredential(),\n    subscription_id,\n)\n\npoller = client.sql_virtual_machines.begin_create_or_update(\n    resource_group_name=resource_group_name,\n    sql_virtual_machine_name=sql_virtual_machine_name,\n    parameters=SqlVirtualMachine(\n        location=\"eastus\",\n        virtual_machine_resource_id=vm_resource_id,\n        sql_server_license_type=\"PAYG\",\n        sql_management=\"Full\",\n        storage_configuration_settings=StorageConfigurationSettings(\n            disk_configuration_type=\"NEW\",\n            storage_workload_type=\"OLTP\",\n            sql_data_settings=SQLStorageSettings(\n                luns=[0],\n                default_file_path=r\"F:\\SQLData\",\n            ),\n            sql_log_settings=SQLStorageSettings(\n                luns=[1],\n                default_file_path=r\"G:\\SQLLogs\",\n            ),\n        ),\n        tags={\"env\": \"dev\"},\n    ),\n)\n\nsql_vm = poller.result()\nprint(sql_vm.id)\nprint(sql_vm.provisioning_state)\n```\n\nWhy this example matters for `0.5.0`:\n\n- PyPI release notes for `0.5.0` specifically call out the new `storage_configuration_settings` parameter on `SqlVirtualMachine`\n- the current Learn model reference still documents the same field and its nested `StorageConfigurationSettings` / `SQLStorageSettings` types\n\n### List the SQL virtual machines in a SQL VM group\n\n`list_by_sql_vm_group` is another feature explicitly called out in the `0.5.0` PyPI release notes.\n\n```python\nfor sql_vm in client.sql_virtual_machines.list_by_sql_vm_group(\n    resource_group_name=\"rg-sqlvm-prod\",\n    sql_virtual_machine_group_name=\"ag-group-prod\",\n):\n    print(sql_vm.name, sql_vm.sql_virtual_machine_group_resource_id)\n```\n\n### List SQL VM groups in a resource group\n\n```python\nfor group in client.sql_virtual_machine_groups.list_by_resource_group(\"rg-sqlvm-prod\"):\n    print(group.name, group.location)\n```\n\n## SQL VM Groups And Availability Group Work\n\nThe SQL VM service can also manage:\n\n- SQL virtual machine groups\n- availability group listeners\n- troubleshooting and extension redeploy operations\n\nUse those only after checking the exact versioned reference for your installed package. The live Learn pages describe a newer preview-generated surface than the stable `0.5.0` release on PyPI, so not every operation shown there should be assumed to exist unchanged in `0.5.0`.\n\nFor SQL VM groups specifically, the official REST examples show that create/update payloads are cluster-specific and require Windows Server Failover Cluster and Active Directory details such as `wsfcDomainProfile`, SQL image offer/SKU, and related account settings. Treat those flows as infrastructure provisioning work, not as simple CRUD updates.\n\n## Common Pitfalls\n\n- This is a management-plane package. It provisions and configures Azure SQL VM resources; it does not connect to SQL Server for query execution.\n- Do not guess the import path from old blog posts. Use `from azure.mgmt.sqlvirtualmachine import SqlVirtualMachineManagementClient`.\n- Many writes are long-running operations. If you do not call `.result()`, your script can exit before ARM finishes.\n- `sql_virtual_machine_name` is the ARM resource name for the SQL VM resource, not a SQL login, instance name, or connection string.\n- `virtual_machine_resource_id` must point at the underlying Azure VM resource, not at the SQL VM ARM resource you are creating.\n- The package is old. PyPI `0.5.0` predates the newer preview line and predates the modern Python baselines used by current Azure SDK packages.\n- The current Learn client reference defaults to API version `2022-08-01-preview`. Do not assume newer preview-only properties or operations map cleanly to a project pinned to `0.5.0`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `0.5.0` as the latest non-prerelease release of `azure-mgmt-sqlvirtualmachine`.\n- The Azure SDK package index currently lists `1.0.0b6` as the available preview line for this library family.\n- PyPI release history for `0.5.0` calls out two concrete additions relative to `0.4.0`: `storage_configuration_settings` on `SqlVirtualMachine`, and `SqlVirtualMachinesOperations.list_by_sql_vm_group`.\n- PyPI release history for `0.4.0` also notes a generator-driven import-path change and introduces the `sql_management` parameter on `SqlVirtualMachine`.\n- If your project needs newer preview features such as assessment or troubleshooting flows documented in the live Learn reference, re-check the package version you actually install before copying those examples.\n\n## Official Sources\n\n- Microsoft Learn package index: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/`\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/mgmt-sqlvirtualmachine-readme?view=azure-python-preview`\n- Microsoft Learn client reference: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.sqlvirtualmachinemanagementclient?view=azure-python-preview`\n- Microsoft Learn SQL virtual machines operations: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.operations.sqlvirtualmachinesoperations?view=azure-python-preview`\n- Microsoft Learn SQL virtual machine groups operations: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.operations.sqlvirtualmachinegroupsoperations?view=azure-python-preview`\n- Microsoft Learn `SqlVirtualMachine` model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.models.sqlvirtualmachine?view=azure-python-preview`\n- Microsoft Learn `StorageConfigurationSettings` model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.models.storageconfigurationsettings?view=azure-python-preview`\n- Microsoft Learn `SQLStorageSettings` model: `https://learn.microsoft.com/en-us/python/api/azure-mgmt-sqlvirtualmachine/azure.mgmt.sqlvirtualmachine.models.sqlstoragesettings?view=azure-python-preview`\n- Microsoft Learn Azure Identity overview: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/overview`\n- Microsoft Learn `DefaultAzureCredential`: `https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python`\n- Microsoft Learn Azure SDK package index: `https://learn.microsoft.com/en-us/azure/developer/python/sdk/azure-sdk-library-package-index`\n- PyPI package page: `https://pypi.org/project/azure-mgmt-sqlvirtualmachine/`\n"
  },
  {
    "path": "content/azure/docs/mgmt-storage/python/DOC.md",
    "content": "---\nname: mgmt-storage\ndescription: \"Azure Storage management-plane SDK for Python for storage accounts, ARM subresources, keys, SAS, and account configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"24.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,storage,arm,management,storage-accounts,provisioning\"\n---\n\n# Azure Storage Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-storage` for Azure Resource Manager control-plane work such as creating storage accounts, updating account settings, listing or regenerating account keys, and managing ARM-exposed storage subresources. Do not use it for blob uploads, downloads, queue messages, or file content access; use data-plane packages such as `azure-storage-blob`, `azure-storage-file-share`, or `azure-storage-queue` for those operations.\n\nFor `24.0.0`, pair it with `azure-identity`, authenticate with `DefaultAzureCredential` or `AzureCliCredential`, and assume the package targets the latest storage ARM API version unless you intentionally pin an older release.\n\n## Install\n\nPin the package version your project expects and install `azure-identity` with it:\n\n```bash\npython -m pip install \"azure-mgmt-storage==24.0.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-storage==24.0.0\" azure-identity\npoetry add \"azure-mgmt-storage==24.0.0\" azure-identity\n```\n\nEnvironment variables you usually need:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\n## Authentication And Setup\n\nPreferred credential patterns:\n\n1. `DefaultAzureCredential()` for reusable app code, CI, managed identity, or workload identity\n2. `AzureCliCredential()` for local scripts after `az login`\n3. A service principal via environment variables only when you explicitly need that flow\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.storage import StorageManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = StorageManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nCLI-driven local scripts can use Azure CLI credentials directly:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.storage import StorageManagementClient\n\nclient = StorageManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nManagement-plane permissions still matter after authentication succeeds. Expect ARM authorization failures if the principal lacks rights on the subscription, resource group, or storage account scope.\n\n## Core Usage\n\n### Check name availability before create\n\nStorage account names are globally unique. Check first instead of learning the rule set from a failed create call.\n\n```python\nfrom azure.mgmt.storage.models import StorageAccountCheckNameAvailabilityParameters\n\nresult = client.storage_accounts.check_name_availability(\n    StorageAccountCheckNameAvailabilityParameters(\n        name=\"ctxhubstorageacct01\",\n    )\n)\n\nif not result.name_available:\n    raise RuntimeError(result.message)\n```\n\n### Create a storage account\n\nProvisioning is a long-running ARM operation, so use the `begin_*` method and wait for the poller:\n\n```python\npoller = client.storage_accounts.begin_create(\n    resource_group_name=\"example-rg\",\n    account_name=\"ctxhubstorageacct01\",\n    parameters={\n        \"location\": \"westus2\",\n        \"kind\": \"StorageV2\",\n        \"sku\": {\"name\": \"Standard_LRS\"},\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"context-hub\",\n        },\n        \"enable_https_traffic_only\": True,\n        \"minimum_tls_version\": \"TLS1_2\",\n        \"allow_blob_public_access\": False,\n    },\n)\n\naccount = poller.result()\nprint(account.id)\n```\n\n### List and inspect accounts\n\n```python\nfor account in client.storage_accounts.list_by_resource_group(\"example-rg\"):\n    print(account.name, account.location, account.kind)\n\naccount = client.storage_accounts.get_properties(\n    resource_group_name=\"example-rg\",\n    account_name=\"ctxhubstorageacct01\",\n)\n\nprint(account.primary_endpoints.blob)\nprint(account.sku.name)\n```\n\n### Update settings and tags\n\nUse `update()` for patch-style account changes:\n\n```python\nupdated = client.storage_accounts.update(\n    resource_group_name=\"example-rg\",\n    account_name=\"ctxhubstorageacct01\",\n    parameters={\n        \"tags\": {\n            \"env\": \"prod\",\n            \"owner\": \"platform\",\n        },\n        \"allow_shared_key_access\": False,\n        \"public_network_access\": \"Enabled\",\n    },\n)\n\nprint(updated.tags)\n```\n\n### List access keys only when you actually need shared-key flows\n\nManagement APIs can retrieve storage account keys, but application code should still prefer Entra ID plus the data-plane SDKs whenever possible.\n\n```python\nkeys = client.storage_accounts.list_keys(\n    resource_group_name=\"example-rg\",\n    account_name=\"ctxhubstorageacct01\",\n)\n\nfor key in keys.keys:\n    print(key.key_name)\n```\n\nIf you need to upload or download blobs after provisioning, switch to `azure-storage-blob` and pass the account URL plus an Entra ID credential instead of reusing management APIs for data access.\n\n## Configuration Notes\n\n- `subscription_id` is required; `StorageManagementClient` does not infer it from the credential.\n- The current Learn docs show the client default `api_version` as `2025-06-01`. Overriding API versions globally is possible, but current Azure SDK release notes state the package targets the latest available API version, so older API assumptions are risky in `24.x`.\n- Long-running storage management operations return `LROPoller` objects. Call `.result()` when you need completion before the next step.\n- `DefaultAzureCredential` tries multiple credential sources. If auth succeeds or fails in a surprising way, inspect which credential source was actually used instead of assuming Azure CLI handled it.\n- `24.0.0` adds a `cloud_setting` parameter on `StorageManagementClient`. For Azure Government or other non-public clouds, keep the client cloud setting aligned with the credential authority host instead of changing only one side.\n\n## Common Pitfalls\n\n- `azure-mgmt-storage` is control plane, not data plane. Provision accounts here; upload blobs with `azure-storage-blob`.\n- Forgetting `AZURE_SUBSCRIPTION_ID` is common. The credential can resolve successfully while the client still cannot be constructed correctly.\n- Storage account names are stricter than many examples imply: use lower-case letters and digits only, and check availability before create.\n- `begin_create()`, `begin_delete()`, `begin_failover()`, and similar calls are asynchronous ARM operations. Do not assume they are finished until you wait on the poller.\n- Newer generated Azure management models are keyword-only. If old examples pass positional constructor arguments, rewrite them using named fields.\n- Retrieving account keys from ARM works, but it often leads agents into shared-key data access flows when Entra ID plus RBAC would be safer and simpler.\n\n## Version-Sensitive Notes\n\n### `24.0.0`\n\nThe official changelog for `24.0.0` calls out two high-value changes:\n\n- `StorageManagementClient` gained a `cloud_setting` argument for cloud environment selection.\n- `StorageTaskAssignmentsOperations.list()` now uses `top` instead of `maxpagesize`.\n\nIf copied code still calls `storage_task_assignments.list(maxpagesize=...)`, treat it as outdated for `24.0.0`.\n\n### `23.x` and later\n\nThe `23.0.0` changelog states that the package now supports only the latest available API version. If your project depends on an older ARM storage API shape, pin an older `azure-mgmt-storage` release and verify examples against that release instead of forcing `24.x` examples into an older environment.\n\n### Older examples\n\nOlder Azure blog posts and generated samples often assume:\n\n- positional model constructors\n- different operation-group pagination arguments\n- older API-version folders in the package\n\nTreat those as migration candidates, not copy-paste-ready examples for `24.0.0`.\n"
  },
  {
    "path": "content/azure/docs/mgmt-subscription/python/DOC.md",
    "content": "---\nname: mgmt-subscription\ndescription: \"Azure Subscription Management client library for Python for tenant, subscription, alias, and subscription-policy operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,arm,subscription,management,identity,tenant\"\n---\n\n# azure-mgmt-subscription Python Package Guide\n\n## What This Package Is For\n\n`azure-mgmt-subscription` is the Azure Resource Manager management-plane SDK for working with:\n\n- subscription aliases\n- tenant and subscription discovery\n- subscription lifecycle operations\n- billing account policy lookup\n- tenant subscription policies\n\nImport path:\n\n```python\nfrom azure.mgmt.subscription import SubscriptionClient\n```\n\nIn the current Microsoft Learn reference for this package line, `SubscriptionClient` exposes these operation groups: `alias`, `billing_account`, `operations`, `subscription`, `subscription_policy`, `subscriptions`, and `tenants`.\n\nUse this package when you need account-level ARM metadata or subscription lifecycle APIs. Do not use it for service-specific resources like storage accounts, virtual machines, or Key Vault objects; those belong in service-specific ARM or data-plane SDKs.\n\n## Install\n\n```bash\npip install azure-mgmt-subscription==3.1.1 azure-identity\n```\n\nPyPI lists `3.1.1` as a Python 3 wheel and describes the package as tested with Python `3.7+`.\n\nIf you use `uv`:\n\n```bash\nuv add azure-mgmt-subscription azure-identity\n```\n\n## Authentication And Setup\n\nUse `DefaultAzureCredential` unless you have a specific reason to force a narrower credential.\n\nFor local development:\n\n```bash\naz login\n```\n\nFor service-principal based auth, set the standard Azure Identity environment variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nBasic setup:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\ncredential = DefaultAzureCredential()\nclient = SubscriptionClient(credential)\n```\n\nImportant setup notes:\n\n- `SubscriptionClient` does not require a `subscription_id` constructor argument.\n- The public Azure ARM endpoint is the default `base_url` in the generated client docs.\n- For sovereign clouds, use the matching Azure Identity authority and ARM endpoint for that cloud instead of mixing public-cloud defaults with non-public endpoints.\n\n## Core Usage\n\n### List Subscriptions Available To The Credential\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\ncredential = DefaultAzureCredential()\nclient = SubscriptionClient(credential)\n\nfor sub in client.subscriptions.list():\n    print(sub.subscription_id, sub.display_name, sub.state)\n```\n\n### Get A Specific Subscription And Its Available Locations\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\nsubscription_id = \"00000000-0000-0000-0000-000000000000\"\n\nclient = SubscriptionClient(DefaultAzureCredential())\nsubscription = client.subscriptions.get(subscription_id)\nprint(subscription.display_name)\n\nfor location in client.subscriptions.list_locations(subscription_id):\n    print(location.name)\n```\n\n### List Tenants\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\nclient = SubscriptionClient(DefaultAzureCredential())\n\nfor tenant in client.tenants.list():\n    print(tenant.tenant_id)\n```\n\n### Inspect Supported ARM Operations\n\nThis is useful when you are debugging permissions or confirming what the installed client exposes.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\nclient = SubscriptionClient(DefaultAzureCredential())\n\nfor operation in client.operations.list():\n    print(operation.name)\n```\n\n### Work With Subscription Aliases\n\nList aliases:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\nclient = SubscriptionClient(DefaultAzureCredential())\naliases = client.alias.list()\n\nfor alias in aliases.value:\n    print(alias.name)\n```\n\nGet one alias:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\n\nclient = SubscriptionClient(DefaultAzureCredential())\nalias = client.alias.get(\"finance-prod-alias\")\n\nprint(alias.id)\nprint(alias.name)\n```\n\nCreate or update an alias for an existing subscription:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\nfrom azure.mgmt.subscription.models import PutAliasRequest, PutAliasRequestProperties\n\nclient = SubscriptionClient(DefaultAzureCredential())\n\npoller = client.alias.begin_create(\n    alias_name=\"finance-prod-alias\",\n    body=PutAliasRequest(\n        properties=PutAliasRequestProperties(\n            display_name=\"Finance Production\",\n            workload=\"Production\",\n            subscription_id=\"00000000-0000-0000-0000-000000000000\",\n        )\n    ),\n)\n\nalias = poller.result()\nprint(alias.id)\n```\n\nIf you are creating a new subscription rather than aliasing an existing one, `PutAliasRequestProperties` also supports `billing_scope`, `reseller_id`, and `additional_properties`.\n\n### Manage Tenant Subscription Policy\n\nThis operation group exists in the 3.x package line and is useful when you need tenant-level subscription ingress or egress controls.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.subscription import SubscriptionClient\nfrom azure.mgmt.subscription.models import PutTenantPolicyRequestProperties\n\nclient = SubscriptionClient(DefaultAzureCredential())\n\npolicy = client.subscription_policy.add_update_policy_for_tenant(\n    PutTenantPolicyRequestProperties(\n        block_subscriptions_leaving_tenant=True,\n        block_subscriptions_into_tenant=False,\n        exempted_principals=[\"00000000-0000-0000-0000-000000000000\"],\n    )\n)\n\nprint(policy.block_subscriptions_leaving_tenant)\n```\n\n## Async Client\n\nThe package line documented on PyPI includes official async support. Use the `aio` namespace if the rest of your codebase is async.\n\n```python\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.mgmt.subscription.aio import SubscriptionClient\n\nasync def main() -> None:\n    credential = DefaultAzureCredential()\n    client = SubscriptionClient(credential)\n    try:\n        async for tenant in client.tenants.list():\n            print(tenant.tenant_id)\n    finally:\n        await client.close()\n        await credential.close()\n```\n\n## Configuration Notes\n\n- Operation classes such as `SubscriptionsOperations` and `AliasOperations` are attached to `SubscriptionClient`; do not instantiate them directly.\n- `subscriptions.list()` and `tenants.list()` return paged iterables. `alias.list()` returns a `SubscriptionAliasListResult`, so iterate through `.value`.\n- Long-running methods use the Azure SDK `begin_*` pattern and return an `LROPoller`.\n- Alias names are request identifiers, not the same thing as the Azure subscription display name.\n- If you keep clients around for a long time, close them when done.\n\n## Common Pitfalls\n\n- Do not use old `msrestazure` or `azure.common.credentials` authentication examples. Current package lines use `azure-identity`.\n- Do not assume every operation takes a subscription ID at client construction time. In this package, subscription IDs are passed to individual methods that need them.\n- Do not treat this package as a general ARM client for resource CRUD. It only covers subscription-level management surfaces.\n- Do not assume `alias.begin_create()` only works for brand-new subscriptions. It can also create an alias for an existing `subscription_id`.\n- Do not copy preview-package examples unless your dependency really is a preview. PyPI shows a `3.2.0b1` pre-release in addition to stable `3.1.1`.\n- If your credential can authenticate but returns no subscriptions or tenants, check Azure RBAC and tenant visibility before debugging the SDK surface.\n\n## Version-Sensitive Notes For `3.1.1`\n\n- This doc is pinned to stable PyPI version `3.1.1`, published on September 6, 2022.\n- PyPI release notes for `3.1.1` say it fixes an `api_version` error in an operation.\n- `3.0.0` restored the `subscriptions` and `tenants` operation groups after `2.0.0` had removed them.\n- `2.0.0` added `billing_account`, `subscription_policy`, `subscription.begin_accept_ownership`, and `additional_properties` on `PutAliasRequestProperties`.\n- PyPI also lists a newer preview release, `3.2.0b1`. Unless your project intentionally tracks previews, keep examples and lockfiles on `3.1.1`.\n- Microsoft Learn shows the current generated reference for this package line. Keep your dependency pinned when reproducing examples so you do not silently drift into preview-only behavior.\n\n## Official Sources\n\n- Microsoft Learn package reference: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/\n- Microsoft Learn `SubscriptionClient`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.subscriptionclient?view=azure-python\n- Microsoft Learn `SubscriptionsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.operations.subscriptionsoperations?view=azure-python\n- Microsoft Learn `TenantsOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.operations.tenantsoperations?view=azure-python\n- Microsoft Learn `AliasOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.operations.aliasoperations?view=azure-python\n- Microsoft Learn `SubscriptionOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.operations.subscriptionoperations?view=azure-python\n- Microsoft Learn `SubscriptionPolicyOperations`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.operations.subscriptionpolicyoperations?view=azure-python\n- Microsoft Learn `PutAliasRequestProperties`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.models.putaliasrequestproperties?view=azure-python\n- Microsoft Learn `PutTenantPolicyRequestProperties`: https://learn.microsoft.com/en-us/python/api/azure-mgmt-subscription/azure.mgmt.subscription.models.puttenantpolicyrequestproperties?view=azure-python\n- Microsoft Learn Azure authentication overview for Python: https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview\n- Microsoft Learn local development service-principal auth: https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication/local-development-service-principal\n- PyPI package page and release history: https://pypi.org/project/azure-mgmt-subscription/\n"
  },
  {
    "path": "content/azure/docs/mgmt-trafficmanager/python/DOC.md",
    "content": "---\nname: mgmt-trafficmanager\ndescription: \"Azure Traffic Manager management SDK for Python for Traffic Manager profiles, endpoints, health monitoring, and DNS routing configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,traffic-manager,arm,dns,management,load-balancing,python\"\n---\n\n# Azure Traffic Manager Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-trafficmanager` for Azure Resource Manager management of Traffic Manager profiles and endpoints, not for serving DNS traffic directly. Install `azure-identity` with it, authenticate with a `TokenCredential`, pass `AZURE_SUBSCRIPTION_ID` explicitly, and remember that profile creation is global ARM configuration: the profile `location` is `\"global\"` and the Traffic Manager DNS name is built from `dns_config.relative_name`.\n\nThis is a management-plane SDK. Your application does not send requests through this client at runtime to route traffic. It creates and updates Traffic Manager resources that Azure DNS answers against.\n\n## Install\n\nPin the package version your project expects and install Azure credentials alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-trafficmanager==1.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-trafficmanager==1.1.0\" azure-identity\npoetry add \"azure-mgmt-trafficmanager==1.1.0\" azure-identity\n```\n\nPyPI classifiers for `1.1.0` list Python `3.7+`.\n\n## Authentication And Setup\n\nUse one of these credential patterns:\n\n- `DefaultAzureCredential()` for code that should work locally, in CI, and on Azure\n- `AzureCliCredential()` for local scripts after `az login`\n\nRequired environment:\n\n```bash\nexport AZURE_SUBSCRIPTION_ID=\"00000000-0000-0000-0000-000000000000\"\n```\n\nIf you authenticate with a service principal directly, also set:\n\n```bash\nexport AZURE_TENANT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_ID=\"00000000-0000-0000-0000-000000000000\"\nexport AZURE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.trafficmanager import TrafficManagerManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = TrafficManagerManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven setup:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.trafficmanager import TrafficManagerManagementClient\n\nclient = TrafficManagerManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe current client exposes these main operation groups:\n\n- `profiles`\n- `endpoints`\n- `geographic_hierarchies`\n- `heat_map`\n- `traffic_manager_user_metrics_keys`\n\n## Core Usage\n\n### Check whether a Traffic Manager DNS name is available\n\nTraffic Manager profile DNS labels are globally unique under `trafficmanager.net`. Check the relative name before creating the profile:\n\n```python\nresult = client.profiles.check_traffic_manager_name_availability_v2(\n    parameters={\"name\": \"contoso-global-app\"},\n)\n\nprint(result.name_available)\nprint(result.message)\n```\n\nThe older `check_traffic_manager_relative_dns_name_availability(...)` method is still present, but `1.1.0` also exposes `check_traffic_manager_name_availability_v2(...)`.\n\n### Create a Traffic Manager profile\n\nThis example creates a weighted profile with a DNS label, HTTP health checks, and an initial tag set:\n\n```python\nprofile = client.profiles.create_or_update(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n    parameters={\n        \"location\": \"global\",\n        \"profile_status\": \"Enabled\",\n        \"traffic_routing_method\": \"Weighted\",\n        \"dns_config\": {\n            \"relative_name\": \"contoso-global-app\",\n            \"ttl\": 30,\n        },\n        \"monitor_config\": {\n            \"protocol\": \"HTTPS\",\n            \"port\": 443,\n            \"path\": \"/healthz\",\n            \"interval_in_seconds\": 30,\n            \"tolerated_number_of_failures\": 3,\n            \"timeout_in_seconds\": 10,\n        },\n        \"tags\": {\n            \"env\": \"dev\",\n            \"owner\": \"platform\",\n        },\n    },\n)\n\nprint(profile.id)\nprint(profile.dns_config.fqdn)\n```\n\nThe routing method controls which endpoint properties matter later:\n\n- `Priority`: set `priority` on each endpoint\n- `Weighted`: set `weight`\n- `Performance`: set `endpoint_location`\n- `Geographic`: set `geo_mapping`\n- `MultiValue`: set `endpoint_status`, `always_serve`, and record-type-compatible endpoint targets carefully\n- `Subnet`: set `subnets`\n\nTraffic Manager monitoring allows only these interval / timeout / tolerated-failure combinations:\n\n- `30` seconds interval: timeout `5`, `10`, or `20`; tolerated failures `2` or `3`\n- `10` seconds interval: timeout `5`, `10`, or `20`; tolerated failures `3`\n\n### List or get profiles\n\n```python\nfor profile in client.profiles.list_by_resource_group(\"rg-networking\"):\n    print(profile.name, profile.traffic_routing_method, profile.monitor_status)\n\nprofile = client.profiles.get(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n)\n\nprint(profile.profile_status)\nprint(profile.dns_config.fqdn)\n```\n\nProfile listing is paged. Iterate over it instead of assuming one in-memory list.\n\n### Add an external endpoint\n\nUse external endpoints for targets outside Azure or for public hostnames and IPs that are not modeled as Azure resources:\n\n```python\nendpoint = client.endpoints.create_or_update(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n    endpoint_type=\"ExternalEndpoints\",\n    endpoint_name=\"origin-eastus\",\n    parameters={\n        \"target\": \"origin-eastus.contoso.com\",\n        \"endpoint_status\": \"Enabled\",\n        \"weight\": 100,\n        \"custom_headers\": [\n            {\n                \"name\": \"Host\",\n                \"value\": \"origin-eastus.contoso.com\",\n            }\n        ],\n    },\n)\n\nprint(endpoint.id)\n```\n\nIf the endpoint target is an IP address, the profile routing method must be `MultiValue`.\n\n### Add an Azure endpoint by resource ID\n\nUse Azure endpoints when the target is an Azure public IP address, App Service app, or public Load Balancer:\n\n```python\nendpoint = client.endpoints.create_or_update(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n    endpoint_type=\"AzureEndpoints\",\n    endpoint_name=\"app-westus2\",\n    parameters={\n        \"target_resource_id\": (\n            \"/subscriptions/00000000-0000-0000-0000-000000000000\"\n            \"/resourceGroups/rg-app\"\n            \"/providers/Microsoft.Network/publicIPAddresses/app-westus2-pip\"\n        ),\n        \"endpoint_status\": \"Enabled\",\n        \"weight\": 100,\n    },\n)\n\nprint(endpoint.target_resource_id)\n```\n\n### Add a nested endpoint\n\nUse nested endpoints when one Traffic Manager profile should route to another Traffic Manager profile:\n\n```python\nendpoint = client.endpoints.create_or_update(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-parent\",\n    endpoint_type=\"NestedEndpoints\",\n    endpoint_name=\"regional-profile-west\",\n    parameters={\n        \"target_resource_id\": (\n            \"/subscriptions/00000000-0000-0000-0000-000000000000\"\n            \"/resourceGroups/rg-networking\"\n            \"/providers/Microsoft.Network/trafficManagerProfiles/contoso-west\"\n        ),\n        \"endpoint_status\": \"Enabled\",\n        \"min_child_endpoints\": 1,\n        \"min_child_endpoints_ipv4\": 1,\n    },\n)\n\nprint(endpoint.min_child_endpoints)\n```\n\nNested profiles are the only endpoint type that can target another Traffic Manager profile.\n\n### Update endpoint routing fields\n\nUse `update(...)` when you only need to patch a few routing-related properties instead of replacing the full endpoint:\n\n```python\nupdated = client.endpoints.update(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n    endpoint_type=\"ExternalEndpoints\",\n    endpoint_name=\"origin-eastus\",\n    parameters={\n        \"weight\": 200,\n        \"endpoint_status\": \"Enabled\",\n    },\n)\n\nprint(updated.weight)\n```\n\nTypical endpoint fields by routing method:\n\n- `priority` for failover-style routing\n- `weight` for weighted routing\n- `endpoint_location` for performance routing\n- `geo_mapping` for geographic routing\n- `subnets` for subnet routing\n\nTo discover valid geographic codes before setting `geo_mapping`, read the default geographic hierarchy:\n\n```python\nhierarchy = client.geographic_hierarchies.get_default()\nprint(hierarchy.code)\n```\n\n### Delete an endpoint or profile\n\n```python\nclient.endpoints.delete(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n    endpoint_type=\"ExternalEndpoints\",\n    endpoint_name=\"origin-eastus\",\n)\n\nclient.profiles.delete(\n    resource_group_name=\"rg-networking\",\n    profile_name=\"contoso-tm\",\n)\n```\n\n## Monitoring Notes\n\nTraffic Manager monitoring settings live on the profile, not on individual endpoints. The monitor checks the protocol, port, and path you set in `monitor_config` against each enabled endpoint.\n\nUseful monitoring details from the service docs:\n\n- `custom_headers` can be sent with health checks, for example to force a specific `Host` header.\n- `expected_status_code_ranges` can be used when a healthy response is not just `200`.\n- Azure endpoints can use fast failure detection only for a public IP address or an Application Gateway endpoint.\n- Monitoring is HTTP, HTTPS, or TCP depending on the profile configuration.\n\nIf you use custom domains or host-based routing at the origin, set the monitor path and any required `Host` header deliberately. The default path or default host header often points at the wrong backend app.\n\n## Common Pitfalls\n\n- Forgetting `azure-identity`; this package does not create credentials for you.\n- Omitting `AZURE_SUBSCRIPTION_ID`; the management client does not infer it from the credential.\n- Using this package for data-plane traffic handling instead of ARM profile management.\n- Forgetting that the profile `location` is `\"global\"`.\n- Treating `dns_config.relative_name` as a full hostname. Traffic Manager appends `.trafficmanager.net`.\n- Using the wrong `endpoint_type`. `ExternalEndpoints`, `AzureEndpoints`, and `NestedEndpoints` are not interchangeable.\n- Copying endpoint fields across routing methods. `priority`, `weight`, `endpoint_location`, `geo_mapping`, and `subnets` only matter for the matching routing mode.\n- Setting unsupported monitor timing combinations. Traffic Manager only allows specific interval / timeout / failure-threshold combinations.\n- Pointing an external endpoint at an IP address when the profile is not using `MultiValue` routing.\n- Forgetting that disabling an endpoint or profile changes DNS answers, but clients still cache answers until the DNS TTL expires.\n\n## Version-Sensitive Notes\n\n`azure-mgmt-trafficmanager 1.1.0` is the current PyPI release as of March 13, 2026. The PyPI release history for `1.1.0` calls out these additions:\n\n- support for `profiles.check_traffic_manager_name_availability_v2`\n- support for `Endpoint.always_serve`\n\nIf you copy older examples, verify that they still match the `1.1.0` client surface and the current Traffic Manager routing methods. Older snippets often omit newer endpoint fields or use older name-availability calls.\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-trafficmanager/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.trafficmanagermanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.operations.profileoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.operations.endpointoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.models.profile?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.models.endpoint?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.models.monitorconfig?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-trafficmanager/azure.mgmt.trafficmanager.models.checktrafficmanagerrelativednsnameavailabilityparameters?view=azure-python\n- https://learn.microsoft.com/en-us/azure/traffic-manager/traffic-manager-routing-methods\n- https://learn.microsoft.com/en-us/azure/traffic-manager/traffic-manager-endpoint-types\n- https://learn.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring\n- https://learn.microsoft.com/en-us/azure/templates/microsoft.network/trafficmanagerprofiles\n"
  },
  {
    "path": "content/azure/docs/mgmt-web/python/DOC.md",
    "content": "---\nname: mgmt-web\ndescription: \"Azure App Service management SDK for Python for App Service plans, web apps, app settings, source control, and related control-plane operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,app-service,azure-mgmt-web,management,web-apps,app-service-plan\"\n---\n\n# Azure App Service Management SDK for Python\n\n## Golden Rule\n\nUse `azure-mgmt-web` for Azure App Service control-plane work: creating and updating App Service plans, web apps, app settings, deployment source control, certificates, and related Microsoft.Web resources. Install `azure-identity` with it, authenticate with `DefaultAzureCredential` or a narrower Entra credential, and do not treat this package as the runtime deployment SDK for your application code.\n\nThis package manages Azure resources. Your app code deployment flow usually still involves Azure CLI, ZipDeploy, GitHub Actions, or another CI/CD path.\n\n## Install\n\nPin the management package version your project expects and install `azure-identity` alongside it:\n\n```bash\npython -m pip install \"azure-mgmt-web==10.1.0\" azure-identity\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-mgmt-web==10.1.0\" azure-identity\npoetry add \"azure-mgmt-web==10.1.0\" azure-identity\n```\n\nIf you plan to use the async client surface, install an async transport too:\n\n```bash\npython -m pip install \"azure-mgmt-web==10.1.0\" azure-identity aiohttp\n```\n\n## Authentication And Setup\n\nThe current official package description shows this baseline setup:\n\n- `AZURE_SUBSCRIPTION_ID`\n- `AZURE_TENANT_ID`\n- `AZURE_CLIENT_ID`\n- `AZURE_CLIENT_SECRET`\n\nFor most real projects, prefer one of these credential patterns:\n\n1. `DefaultAzureCredential()` for code that must run locally, in CI, and in Azure.\n2. `AzureCliCredential()` for local scripts after `az login`.\n3. `ManagedIdentityCredential()` or workload identity once the runtime environment is fixed.\n\nBasic sync client setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.web import WebSiteManagementClient\n\nsubscription_id = os.environ[\"AZURE_SUBSCRIPTION_ID\"]\ncredential = DefaultAzureCredential()\n\nclient = WebSiteManagementClient(\n    credential=credential,\n    subscription_id=subscription_id,\n)\n```\n\nLocal CLI-driven scripts can be explicit:\n\n```python\nimport os\n\nfrom azure.identity import AzureCliCredential\nfrom azure.mgmt.web import WebSiteManagementClient\n\nclient = WebSiteManagementClient(\n    credential=AzureCliCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n```\n\nThe official `WebSiteManagementClient` docs also expose `cloud_setting=`. Use that when you target sovereign clouds so the credential authority and ARM endpoint stay aligned with the cloud you are using.\n\n## Core Client Surface\n\nThe current client exposes these high-value operation groups:\n\n- `app_service_plans`\n- `web_apps`\n- `static_sites`\n- `site_certificates`\n- `certificates`\n- `domains`\n- `deleted_web_apps`\n- `diagnostics`\n\nFor ordinary App Service automation, most code lives in `client.app_service_plans` and `client.web_apps`.\n\n## Core Usage\n\n### Create an App Service plan\n\nThe official docs show `app_service_plans.begin_create_or_update(...)` taking an `AppServicePlan` payload. For Linux plans, set `reserved=True`.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.web import WebSiteManagementClient\nfrom azure.mgmt.web.models import AppServicePlan, SkuDescription\n\nresource_group = \"example-rg\"\nplan_name = \"example-plan\"\nlocation = \"westus2\"\n\nclient = WebSiteManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\npoller = client.app_service_plans.begin_create_or_update(\n    resource_group,\n    plan_name,\n    AppServicePlan(\n        location=location,\n        reserved=True,\n        sku=SkuDescription(\n            name=\"B1\",\n            tier=\"Basic\",\n            size=\"B1\",\n            capacity=1,\n        ),\n    ),\n)\n\nplan = poller.result()\nprint(plan.id)\n```\n\nImportant details:\n\n- `AppServicePlan.location` is required.\n- `reserved=True` is what marks the plan as Linux in the current model.\n- `begin_create_or_update()` returns a poller. Call `.result()` when you need completion before the next step.\n\n### Create a web app on that plan\n\nThe `Site` model requires `location`; the `server_farm_id` should point at the App Service plan resource ID.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.mgmt.web import WebSiteManagementClient\nfrom azure.mgmt.web.models import Site, SiteConfig\n\nresource_group = \"example-rg\"\nplan_name = \"example-plan\"\napp_name = \"example-app-12345\"\nlocation = \"westus2\"\n\nclient = WebSiteManagementClient(\n    credential=DefaultAzureCredential(),\n    subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n)\n\nplan = client.app_service_plans.get(resource_group, plan_name)\n\npoller = client.web_apps.begin_create_or_update(\n    resource_group,\n    app_name,\n    Site(\n        location=location,\n        server_farm_id=plan.id,\n        https_only=True,\n        site_config=SiteConfig(\n            linux_fx_version=\"PYTHON|3.11\",\n            always_on=True,\n            ftps_state=\"Disabled\",\n            min_tls_version=\"1.2\",\n        ),\n    ),\n)\n\nsite = poller.result()\nprint(site.default_host_name)\n```\n\nPractical notes:\n\n- `server_farm_id` should come from the actual plan object instead of being string-built by hand.\n- `linux_fx_version` configures the runtime stack. Keep it aligned with a runtime that App Service currently supports.\n- `https_only=True` and `min_tls_version=\"1.2\"` are safer defaults than leaving those unset.\n\n### List or inspect apps\n\n`web_apps.list_by_resource_group(...)` is the direct way to enumerate sites in a resource group.\n\n```python\nfor app in client.web_apps.list_by_resource_group(\"example-rg\", include_slots=True):\n    print(app.name, app.state, app.default_host_name)\n\napp = client.web_apps.get(\"example-rg\", \"example-app-12345\")\nprint(app.kind)\nprint(app.server_farm_id)\n```\n\n### Read and replace app settings\n\nThe current API surface uses `StringDictionary` for app settings. `update_application_settings(...)` replaces the application settings payload, so merge with the current values when you only want to change one key.\n\n```python\nfrom azure.mgmt.web.models import StringDictionary\n\ncurrent = client.web_apps.list_application_settings(\"example-rg\", \"example-app-12345\")\n\nsettings = dict(current.properties or {})\nsettings[\"DJANGO_SETTINGS_MODULE\"] = \"mysite.settings\"\nsettings[\"SCM_DO_BUILD_DURING_DEPLOYMENT\"] = \"1\"\n\nupdated = client.web_apps.update_application_settings(\n    \"example-rg\",\n    \"example-app-12345\",\n    StringDictionary(properties=settings),\n)\n\nprint(updated.properties[\"DJANGO_SETTINGS_MODULE\"])\n```\n\nDo not assume this is a patch operation. The official method description says it replaces the application settings of an app.\n\n### Update site configuration after creation\n\nFor runtime-level settings such as startup commands, websockets, health checks, or runtime stack values, use the configuration operations rather than rewriting the full site resource.\n\n```python\nfrom azure.mgmt.web.models import SiteConfigResource\n\nconfig = client.web_apps.get_configuration(\"example-rg\", \"example-app-12345\")\n\nconfig.linux_fx_version = \"PYTHON|3.11\"\nconfig.always_on = True\nconfig.health_check_path = \"/healthz\"\nconfig.app_command_line = (\n    \"gunicorn -w 2 -k uvicorn.workers.UvicornWorker \"\n    \"-b 0.0.0.0:8000 main:app\"\n)\n\nclient.web_apps.create_or_update_configuration(\n    \"example-rg\",\n    \"example-app-12345\",\n    SiteConfigResource(\n        linux_fx_version=config.linux_fx_version,\n        always_on=config.always_on,\n        health_check_path=config.health_check_path,\n        app_command_line=config.app_command_line,\n    ),\n)\n```\n\nThis is the safer pattern when you only need to manage configuration. It avoids rebuilding a large `Site` object with many server-populated fields.\n\n### Configure deployment source control\n\n`begin_create_or_update_source_control(...)` is the management-side way to connect a site to a repository.\n\n```python\nfrom azure.mgmt.web.models import SiteSourceControl\n\npoller = client.web_apps.begin_create_or_update_source_control(\n    \"example-rg\",\n    \"example-app-12345\",\n    SiteSourceControl(\n        repo_url=\"https://github.com/example-org/example-app\",\n        branch=\"main\",\n        is_manual_integration=False,\n        is_git_hub_action=True,\n    ),\n)\n\nsource_control = poller.result()\nprint(source_control.repo_url)\n```\n\nWhen you are driving GitHub Actions or another deployment system outside the SDK, prefer treating source control configuration as deployment metadata rather than assuming it deploys the app content by itself.\n\n### Restart an app or inspect publishing credentials\n\n```python\nclient.web_apps.restart(\n    \"example-rg\",\n    \"example-app-12345\",\n    soft_restart=True,\n    synchronous=True,\n)\n\npublishing_user = client.web_apps.begin_list_publishing_credentials(\n    \"example-rg\",\n    \"example-app-12345\",\n).result()\n\nprint(publishing_user.publishing_user_name)\n```\n\nThe current docs say `restart(...)` can be asynchronous unless you pass `synchronous=True`.\n\n### Async client\n\nThe package also publishes `azure.mgmt.web.aio.WebSiteManagementClient`.\n\n```python\nimport os\nimport asyncio\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.mgmt.web.aio import WebSiteManagementClient\n\nasync def main():\n    credential = DefaultAzureCredential()\n    client = WebSiteManagementClient(\n        credential=credential,\n        subscription_id=os.environ[\"AZURE_SUBSCRIPTION_ID\"],\n    )\n    try:\n        async for app in client.web_apps.list_by_resource_group(\"example-rg\"):\n            print(app.name)\n    finally:\n        await client.close()\n        await credential.close()\n\nasyncio.run(main())\n```\n\nKeep sync and async stacks consistent. Do not mix `azure.identity.aio` credentials into the sync client.\n\n## App Service Runtime Notes That Affect SDK Automation\n\n`azure-mgmt-web` manages the Azure resources, but App Service runtime behavior still matters when you automate configuration:\n\n- Microsoft Learn's current Python App Service guidance says Python on App Service is Linux-only.\n- The runtime config article says App Service expects your Python dependencies to be available during deployment, and in practice `requirements.txt` at the project root still matters for build automation.\n- If you are automating FastAPI deployment, the current quickstart says you must set a custom startup command such as Gunicorn with `uvicorn.workers.UvicornWorker`.\n\nThat is why many useful `azure-mgmt-web` automation flows combine:\n\n1. `app_service_plans.begin_create_or_update(...)`\n2. `web_apps.begin_create_or_update(...)`\n3. `web_apps.update_application_settings(...)`\n4. `web_apps.create_or_update_configuration(...)`\n5. a separate deployment step outside this SDK\n\n## Configuration Notes\n\n- `subscription_id` is mandatory; the client does not infer it from the credential.\n- The `base_url` and `cloud_setting` constructor parameters matter for sovereign clouds or custom ARM endpoints.\n- App Service plan and site creation are often long-running operations; expect pollers from `begin_*` methods.\n- `list_application_settings()` returns a `StringDictionary` whose actual key-values live under `.properties`.\n- Several resource models contain many server-populated fields. When you only want to update configuration, use the narrow operation or patch model instead of sending back a whole fetched object unchanged.\n\n## Version-Sensitive Notes\n\n### `10.1.0`\n\nPyPI release history for `10.1.0` shows:\n\n- new `AppServicePlansOperations` methods for instance details and managed-instance worker operations\n- new `AppServicePlan` fields such as `identity`, `install_scripts`, `network`, `storage_mounts`, and related custom-mode fields\n- new `SitePatchResource.public_network_access`\n\nIf you are automating private networking or custom-mode plans, prefer current `10.1.0` docs over older examples.\n\n### `10.0.0`\n\nPyPI marks `10.0.0` as a breaking change: the package now targets only the latest available API version and removes older API-version folders. If your code depends on a specific older Microsoft.Web API version, pin an earlier `azure-mgmt-web` release instead of assuming `10.x` still exposes those modules.\n\n### `9.0.0`\n\nPyPI release history for `9.0.0` added fields such as:\n\n- `Site.ssh_enabled`\n- `Site.outbound_vnet_routing`\n- `Site.client_affinity_proxy_enabled`\n- `SiteConfig.http20_proxy_flag`\n\nIt also removed several older `Site` VNet-related parameters. Do not trust pre-`9.0.0` blog posts for current model fields.\n\n### `8.0.0`\n\nPyPI release history for `8.0.0` also warns that older API-version subfolders were removed for package-size reduction. That matters if you are copying imports from older automation code.\n\n## Common Pitfalls\n\n- Installing `azure-mgmt-web` without `azure-identity`\n- Using this package for app-code deployment instead of resource management\n- Forgetting `reserved=True` when creating a Linux App Service plan\n- Hard-coding `server_farm_id` strings instead of reading the plan resource ID returned by Azure\n- Treating `update_application_settings()` as a patch instead of a replacement\n- Sending back whole fetched models with server-populated fields when a narrower update call exists\n- Forgetting `.result()` on `begin_create_or_update(...)` and other long-running operations\n- Assuming App Service Python apps run on Windows; current Microsoft guidance says Python on App Service is Linux-only\n- Setting a Python runtime in `SiteConfig.linux_fx_version` that App Service no longer supports\n\n## Official Sources Used\n\n- https://pypi.org/project/azure-mgmt-web/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.websitemanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.aio.websitemanagementclient?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.operations.appserviceplansoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.operations.webappsoperations?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.appserviceplan?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.site?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.siteconfig?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.stringdictionary?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.sitesourcecontrol?view=azure-python\n- https://learn.microsoft.com/en-us/python/api/azure-mgmt-web/azure.mgmt.web.models.siteconfigresource?view=azure-python\n- https://learn.microsoft.com/en-us/azure/app-service/configure-language-python\n- https://learn.microsoft.com/en-us/azure/app-service/quickstart-python\n"
  },
  {
    "path": "content/azure/docs/monitor-opentelemetry/javascript/DOC.md",
    "content": "---\nname: monitor-opentelemetry\ndescription: \"Azure Monitor OpenTelemetry JavaScript distro guide for startup configuration, authentication, custom spans and metrics, and Node.js instrumentation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-monitor,application-insights,opentelemetry,observability,javascript,nodejs\"\n---\n\n# @azure/monitor-opentelemetry JavaScript Package Guide\n\n## Golden Rule\n\nCall `useAzureMonitor(...)` exactly once during Node.js process startup, before you initialize HTTP servers, Azure SDK clients, database drivers, or loggers that you want auto-instrumented.\n\nThis guide is pinned to `@azure/monitor-opentelemetry@1.16.0`.\n\n## What This Package Does\n\n`@azure/monitor-opentelemetry` is Microsoft's Node.js OpenTelemetry distro for Azure Monitor / Application Insights. It wires Azure Monitor exporters into OpenTelemetry and can enable bundled instrumentations so your app can send traces, metrics, and supported dependency or logger telemetry with one startup call.\n\nUse this package when you want Azure Monitor as the backend and you want the distro to own the OpenTelemetry bootstrap. If you see older examples centered on the separate `applicationinsights` package, that is a different SDK and setup model.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @azure/monitor-opentelemetry@1.16.0\n```\n\nIf you want Microsoft Entra ID authentication, install Azure Identity too:\n\n```bash\nnpm install @azure/monitor-opentelemetry@1.16.0 @azure/identity\n```\n\nSet the Application Insights connection string before startup:\n\n```bash\nexport APPLICATIONINSIGHTS_CONNECTION_STRING=\"InstrumentationKey=...;IngestionEndpoint=https://...\"\nexport OTEL_SERVICE_NAME=\"billing-api\"\nexport OTEL_RESOURCE_ATTRIBUTES=\"service.namespace=payments,service.instance.id=worker-1\"\n```\n\n## Minimal Setup\n\nBootstrap telemetry in a dedicated startup module and import that module before the rest of your application:\n\n```js\nimport { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\nimport { metrics, trace } from \"@opentelemetry/api\";\n\nif (!process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) {\n  throw new Error(\"APPLICATIONINSIGHTS_CONNECTION_STRING is required\");\n}\n\nuseAzureMonitor({\n  azureMonitorExporterOptions: {\n    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n  },\n});\n\nconst tracer = trace.getTracer(\"billing-api\");\nconst meter = metrics.getMeter(\"billing-api\");\nconst jobsProcessed = meter.createCounter(\"jobs_processed\");\n\nconst span = tracer.startSpan(\"sync-job\");\n\ntry {\n  span.setAttribute(\"job.name\", \"sync\");\n  jobsProcessed.add(1, { job: \"sync\", status: \"success\" });\n} finally {\n  span.end();\n}\n```\n\nWhat this gives you:\n\n- Azure Monitor export configured from one startup call\n- OpenTelemetry API access for custom spans and metrics\n- bundled instrumentation for supported Node.js libraries enabled after startup\n\n## Initialization Rules\n\n- Call `useAzureMonitor()` only once per process.\n- Call it before importing or constructing libraries you expect the distro to instrument.\n- Keep telemetry bootstrap in your entrypoint or an imported startup module, not inside request handlers or repeated job code.\n- Reuse the global OpenTelemetry providers that the distro installs instead of trying to create a second tracing or metrics pipeline next to it.\n\n## Configuration And Authentication\n\n### Connection string and service identity\n\nThe standard setup is an Application Insights connection string passed through `azureMonitorExporterOptions.connectionString`. If you prefer environment-based service identity, set `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES` before startup.\n\n```js\nimport { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nuseAzureMonitor({\n  azureMonitorExporterOptions: {\n    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n  },\n  enableLiveMetrics: true,\n  samplingRatio: 1,\n});\n```\n\nUse `samplingRatio` when you want fixed-percentage trace sampling. Keep the service name explicit with `OTEL_SERVICE_NAME` so Azure Monitor does not group unrelated workloads under a generic process name.\n\n### Microsoft Entra ID authentication\n\nAzure Monitor's authentication guidance for OpenTelemetry uses an Azure Identity credential together with the connection string that identifies the target resource.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nuseAzureMonitor({\n  azureMonitorExporterOptions: {\n    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n    credential: new DefaultAzureCredential(),\n  },\n});\n```\n\nUse managed identity or another `TokenCredential`-based flow for Azure-hosted workloads when possible. Keep the connection string configured even when authentication comes from Microsoft Entra ID.\n\n### Select bundled instrumentations\n\nUse `instrumentationOptions` to enable or disable the distro's supported instrumentations at startup.\n\n```js\nimport { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nuseAzureMonitor({\n  azureMonitorExporterOptions: {\n    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n  },\n  instrumentationOptions: {\n    http: { enabled: true },\n    azureSdk: { enabled: true },\n  },\n  samplingRatio: 0.25,\n  enableLiveMetrics: true,\n});\n```\n\nThis is the safest place to turn individual built-in instrumentations on or off. Make these choices before the relevant modules are loaded.\n\n## Core Usage Patterns\n\n### Manual spans\n\nUse the OpenTelemetry API directly after startup:\n\n```js\nimport {\n  SpanKind,\n  SpanStatusCode,\n  trace,\n} from \"@opentelemetry/api\";\n\nconst tracer = trace.getTracer(\"payments\");\n\nconst span = tracer.startSpan(\"reconcile-invoice\", {\n  kind: SpanKind.INTERNAL,\n});\n\ntry {\n  span.setAttribute(\"invoice.id\", invoiceId);\n  await reconcileInvoice(invoiceId);\n} catch (error) {\n  span.recordException(error);\n  span.setStatus({\n    code: SpanStatusCode.ERROR,\n    message: error instanceof Error ? error.message : String(error),\n  });\n  throw error;\n} finally {\n  span.end();\n}\n```\n\nUse manual spans for work that the bundled instrumentations do not cover or when you want business-specific attributes on important operations.\n\n### Custom metrics\n\nCreate meters and instruments with the OpenTelemetry metrics API:\n\n```js\nimport { metrics } from \"@opentelemetry/api\";\n\nconst meter = metrics.getMeter(\"payments\");\nconst invoicesProcessed = meter.createCounter(\"invoices_processed\");\n\ninvoicesProcessed.add(1, {\n  status: \"success\",\n  tenant: tenantId,\n});\n```\n\nIf you need metric namespaces in Application Insights Metrics Explorer, Azure Monitor documents opting in with:\n\n```bash\nexport APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN=\"true\"\n```\n\n### Import startup first\n\nKeep telemetry bootstrap in its own file and load it before the rest of the app:\n\n```js\n// telemetry.js\nimport { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nuseAzureMonitor({\n  azureMonitorExporterOptions: {\n    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n  },\n});\n```\n\n```js\n// server.js\nimport \"./telemetry.js\";\nimport express from \"express\";\n\nconst app = express();\n\napp.get(\"/healthz\", (_req, res) => {\n  res.json({ ok: true });\n});\n\napp.listen(3000);\n```\n\nThis pattern keeps initialization order obvious and avoids accidentally importing instrumented libraries too early.\n\n## Common Pitfalls\n\n- Initializing telemetry after your server, SDK clients, database drivers, or loggers are already loaded\n- Calling `useAzureMonitor()` more than once and ending up with duplicate or confusing telemetry\n- Forgetting to set `APPLICATIONINSIGHTS_CONNECTION_STRING` even when you authenticate with `DefaultAzureCredential`\n- Leaving `OTEL_SERVICE_NAME` unset and then wondering why service identity in Azure Monitor is generic\n- Copying older `applicationinsights` package samples into a distro-based `@azure/monitor-opentelemetry` setup\n\n## Version-Sensitive Notes For 1.16.0\n\n- This guide is written for `@azure/monitor-opentelemetry@1.16.0`\n- The documented bootstrap entrypoint is `useAzureMonitor(...)`\n- The practical configuration surface used here is `azureMonitorExporterOptions`, `instrumentationOptions`, `samplingRatio`, and `enableLiveMetrics`\n- Older tutorials for other Azure Monitor Node SDKs may use different package names, initialization order, and configuration objects\n\n## Official Sources\n\n- Azure SDK for JavaScript `@azure/monitor-opentelemetry` README: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/monitor/monitor-opentelemetry/README.md\n- JavaScript package overview for `@azure/monitor-opentelemetry`: https://learn.microsoft.com/en-us/javascript/api/overview/azure/monitor-opentelemetry-readme?view=azure-node-latest\n- JavaScript API reference root: https://learn.microsoft.com/en-us/javascript/api/@azure/monitor-opentelemetry/\n- Azure Monitor OpenTelemetry configuration guide: https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-configuration\n- Azure Monitor add/modify guidance: https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-add-modify\n- Azure Monitor Microsoft Entra authentication guidance: https://learn.microsoft.com/en-us/azure/azure-monitor/app/azure-ad-authentication\n- npm package page: https://www.npmjs.com/package/@azure/monitor-opentelemetry\n"
  },
  {
    "path": "content/azure/docs/monitor-opentelemetry/python/DOC.md",
    "content": "---\nname: monitor-opentelemetry\ndescription: \"Azure Monitor OpenTelemetry distro for Python package guide\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-monitor,application-insights,opentelemetry,observability,python\"\n---\n\n# azure-monitor-opentelemetry Python Package Guide\n\n## Golden Rule\n\nCall `configure_azure_monitor()` once during process startup, before your app begins serving requests or creating SDK clients, and let the distro own the Azure Monitor exporter and bundled OpenTelemetry instrumentations.\n\nThis guide is pinned to `azure-monitor-opentelemetry==1.8.6`, which matches the version used here and the current Learn/PyPI package version as of `2026-03-12`.\n\n## What This Package Does\n\n`azure-monitor-opentelemetry` is Microsoft's Python distro for sending traces, metrics, logs, and bundled dependency telemetry to Azure Monitor / Application Insights with one startup call.\n\nBundled instrumentations enabled by default:\n\n- `azure_sdk`\n- `django`\n- `fastapi`\n- `flask`\n- `psycopg2`\n- `requests`\n- `urllib`\n- `urllib3`\n\nImportant boundary:\n\n- Use `configure_azure_monitor()` for manual application bootstrap.\n- Automatic instrumentation is not supported by this package itself.\n- You can still manually instrument unsupported libraries through normal OpenTelemetry APIs.\n\n## Install\n\nPin the package if you want behavior that matches this guide:\n\n```bash\npip install \"azure-monitor-opentelemetry==1.8.6\"\n```\n\nIf you want Microsoft Entra ID authentication, also install Azure Identity:\n\n```bash\npip install azure-identity\n```\n\nSet the Application Insights connection string before startup:\n\n```bash\nexport APPLICATIONINSIGHTS_CONNECTION_STRING=\"InstrumentationKey=...;IngestionEndpoint=https://...\"\nexport OTEL_SERVICE_NAME=\"billing-api\"\nexport OTEL_RESOURCE_ATTRIBUTES=\"service.namespace=payments,service.instance.id=worker-1\"\n```\n\n## Minimal Setup\n\n```python\nimport logging\nimport os\n\nfrom azure.monitor.opentelemetry import configure_azure_monitor\nfrom opentelemetry import metrics, trace\n\nlogging.basicConfig(level=logging.INFO)\n\nconfigure_azure_monitor(\n    connection_string=os.environ[\"APPLICATIONINSIGHTS_CONNECTION_STRING\"],\n    logger_name=\"app.telemetry\",\n)\n\ntracer = trace.get_tracer(\"billing-api\")\nmeter = metrics.get_meter(\"billing-api\")\njobs_counter = meter.create_counter(\"jobs_processed\")\nlogger = logging.getLogger(\"app.telemetry\")\n\nwith tracer.start_as_current_span(\"sync-job\") as span:\n    span.set_attribute(\"job.name\", \"sync\")\n    logger.info(\"sync started\", extra={\"component\": \"worker\"})\n    jobs_counter.add(1, {\"job\": \"sync\"})\n```\n\nWhat this gives you:\n\n- Azure Monitor export for traces, metrics, and logs\n- auto-instrumentation for supported libraries used after startup\n- custom spans through the OpenTelemetry tracing API\n- custom metrics through the OpenTelemetry metrics API\n- log records and custom event emission through Python logging\n\n## Initialization Rules\n\n- Call `configure_azure_monitor()` only once per process.\n- Call it before creating framework apps, Azure SDK clients, HTTP clients, or database connections you expect to be auto-instrumented.\n- Keep telemetry bootstrap in a startup module, not inside request handlers, Celery tasks, or function bodies that run repeatedly.\n- If you need custom processors, views, or resource metadata, pass them during the initial call instead of mutating providers later.\n\n## Configuration And Auth\n\n### Connection string and resource identity\n\n`connection_string` is the standard way to point the distro at an Application Insights resource. If you omit it in code, the package reads `APPLICATIONINSIGHTS_CONNECTION_STRING`.\n\nUse resource metadata so Azure Monitor displays useful service names and instances:\n\n```python\nimport os\n\nfrom azure.monitor.opentelemetry import configure_azure_monitor\nfrom opentelemetry.sdk.resources import Resource\n\nconfigure_azure_monitor(\n    connection_string=os.environ[\"APPLICATIONINSIGHTS_CONNECTION_STRING\"],\n    resource=Resource.create(\n        {\n            \"service.name\": \"billing-api\",\n            \"service.namespace\": \"payments\",\n            \"service.instance.id\": os.getenv(\"HOSTNAME\", \"local\"),\n        }\n    ),\n)\n```\n\n### Microsoft Entra ID authentication\n\nThe Azure Monitor auth guide documents Python examples that pass an Azure Identity credential to `configure_azure_monitor()`.\n\nManaged identity example:\n\n```python\nimport os\n\nfrom azure.identity import ManagedIdentityCredential\nfrom azure.monitor.opentelemetry import configure_azure_monitor\n\ncredential = ManagedIdentityCredential(client_id=os.getenv(\"AZURE_CLIENT_ID\"))\n\nconfigure_azure_monitor(\n    connection_string=os.environ[\"APPLICATIONINSIGHTS_CONNECTION_STRING\"],\n    credential=credential,\n)\n```\n\nUse managed identity in Azure-hosted workloads when possible. The auth guide also shows `ClientSecretCredential` for service principal flows.\n\n### Signal, sampling, and exporter options\n\nUseful `configure_azure_monitor()` options in `1.8.6`:\n\n- `logger_name`: collect logs from a named Python logger and avoid SDK self-log capture.\n- `instrumentation_options`: enable or disable bundled instrumentations selectively.\n- `enable_live_metrics`: defaults to `True`.\n- `sampling_ratio`: fixed-percentage trace sampling, `0.0..1.0`.\n- `traces_per_second`: rate-limited trace sampling.\n- `enable_trace_based_sampling_for_logs`: defaults to `True`.\n- `span_processors`, `log_record_processors`, `views`, `metric_readers`: advanced OpenTelemetry customization hooks.\n- `storage_directory`: override offline retry storage path.\n- `disable_offline_storage`: disable disk buffering.\n\nExample with selective instrumentation and rate-limited sampling:\n\n```python\nimport os\n\nfrom azure.monitor.opentelemetry import configure_azure_monitor\n\nconfigure_azure_monitor(\n    connection_string=os.environ[\"APPLICATIONINSIGHTS_CONNECTION_STRING\"],\n    logger_name=\"billing.telemetry\",\n    instrumentation_options={\n        \"azure_sdk\": {\"enabled\": True},\n        \"requests\": {\"enabled\": True},\n        \"urllib3\": {\"enabled\": False},\n    },\n    traces_per_second=2.0,\n    enable_trace_based_sampling_for_logs=True,\n    storage_directory=\"/tmp/azure-monitor\",\n)\n```\n\nEnvironment variables still matter:\n\n- `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=\"requests,urllib3\"` disables selected bundled instrumentations.\n- `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG` configure sampler behavior globally.\n- `OTEL_LOGS_EXPORTER=None`, `OTEL_METRICS_EXPORTER=None`, or `OTEL_TRACES_EXPORTER=None` disable a signal.\n- `OTEL_BLRP_SCHEDULE_DELAY` and `OTEL_BSP_SCHEDULE_DELAY` control log and trace export intervals.\n- `OTEL_METRIC_EXPORT_INTERVAL` defaults to `60000` ms.\n\n## Core Usage Patterns\n\n### Manual spans\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.trace import SpanKind\n\ntracer = trace.get_tracer(__name__)\n\nwith tracer.start_as_current_span(\"reconcile-invoice\", kind=SpanKind.SERVER) as span:\n    span.set_attribute(\"invoice.id\", invoice_id)\n    process_invoice(invoice_id)\n```\n\nBy default, manual spans appear as in-process dependencies. If a span represents a server-side job or request-like operation that should show up in the `requests` table, set `kind=SpanKind.SERVER`.\n\n### Custom metrics\n\n```python\nfrom opentelemetry import metrics\n\nmeter = metrics.get_meter(\"payments\")\ncounter = meter.create_counter(\"invoices_processed\")\ncounter.add(1, {\"status\": \"success\"})\n```\n\nIf you want metric namespaces visible in Application Insights Metrics Explorer, Microsoft Learn shows opting in with:\n\n```bash\nexport APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN=\"true\"\n```\n\n### Custom events and log dimensions\n\nPython logging is autoinstrumented. Use `extra=` to attach custom properties, or set `microsoft.custom_event.name` to emit a custom event:\n\n```python\nimport logging\n\nlogger = logging.getLogger(\"app.telemetry\")\n\nlogger.warning(\n    \"invoice workflow completed\",\n    extra={\n        \"microsoft.custom_event.name\": \"invoice-workflow\",\n        \"invoice.status\": \"success\",\n        \"tenant.id\": tenant_id,\n    },\n)\n```\n\nNormal log enrichment works the same way:\n\n```python\nlogger.info(\"payment captured\", extra={\"order.id\": order_id, \"amount\": amount})\n```\n\n### Recording exceptions on spans\n\n```python\nfrom opentelemetry import trace\n\ntracer = trace.get_tracer(__name__)\n\nwith tracer.start_as_current_span(\"charge-card\") as span:\n    try:\n        charge_customer()\n    except Exception as exc:\n        span.record_exception(exc)\n        raise\n```\n\n## Common Pitfalls\n\n- Do not expect this package to behave like `opentelemetry-instrument`. The package overview explicitly says automatic instrumentation is not supported by the distro itself; bootstrap it in code.\n- Do not call `configure_azure_monitor()` repeatedly. Duplicate initialization leads to duplicate telemetry, confusing logging behavior, and harder-to-debug provider state.\n- Sampling defaults changed in the current line. In `1.8.6`, if you set neither `sampling_ratio` nor `traces_per_second` nor the sampler environment variables, `configure_azure_monitor()` uses the rate-limited sampler by default with `5.0` traces per second.\n- For sampling, environment variables can override code configuration. If `OTEL_TRACES_SAMPLER` or `OTEL_TRACES_SAMPLER_ARG` is set in the runtime environment, verify those values before assuming your `sampling_ratio=` or `traces_per_second=` call is effective.\n- Trace-based log sampling is enabled by default. Logs associated with unsampled traces can be dropped even though standalone logs without trace context are unaffected.\n- Offline retry storage writes to a temp directory by default. In containers or restricted runtimes, set `storage_directory` explicitly or disable offline storage if disk writes are undesirable.\n- Azure Functions has two Python-specific caveats in the official docs: incoming requests are not automatically trace-correlated with worker telemetry, and the Functions worker can emit duplicate logs unless you clear handlers or disable host-side logging before calling `configure_azure_monitor()`.\n- The Python version floor is not presented consistently across official pages for `1.8.6`. Validate runtime support before promising Python `3.8`.\n\n## Version-Sensitive Notes\n\n- Version used here: `1.8.6`\n- Learn package overview version observed: `1.8.6`\n- PyPI latest version observed: `1.8.6`\n- PyPI release date observed: `2026-02-04`\n\nPractical consequences for `1.8.6`:\n\n- Current docs and the package page agree on the version.\n- The current Learn overview exposes modern kwargs such as `resource`, `span_processors`, `log_record_processors`, `metric_readers`, `sampling_ratio`, and `traces_per_second`.\n- The current Azure Monitor configuration guide states that Python `1.8.6` defaults to rate-limited sampling if you do not configure a sampler.\n- Older blog posts and earlier package guides for `1.0.x` often describe a smaller configuration surface and older sampling behavior. Re-check official docs before copying those examples.\n\n## Official Sources\n\n- Package overview: https://learn.microsoft.com/en-us/python/api/overview/azure/monitor-opentelemetry-readme?view=azure-python\n- Azure Monitor configuration guide: https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-configuration\n- Azure Monitor add/modify guide: https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-add-modify\n- Microsoft Entra authentication guide: https://learn.microsoft.com/en-us/azure/azure-monitor/app/azure-ad-authentication\n- PyPI project page: https://pypi.org/project/azure-monitor-opentelemetry/\n- Version-pinned PyPI JSON: https://pypi.org/pypi/azure-monitor-opentelemetry/1.8.6/json\n"
  },
  {
    "path": "content/azure/docs/monitor-query/javascript/DOC.md",
    "content": "---\nname: monitor-query\ndescription: \"@azure/monitor-query JavaScript guide for Azure Monitor logs and metrics with Entra auth, workspace queries, and resource queries\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.3.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-monitor,log-analytics,metrics,javascript,observability,entra-id\"\n---\n\n# Azure Monitor Query JavaScript Package Guide\n\n## Golden Rule\n\nUse `@azure/monitor-query` to read Azure Monitor data that already exists:\n\n- `LogsQueryClient` for Kusto queries against a Log Analytics workspace or resource-scoped logs\n- `MetricsQueryClient` for Azure Monitor metrics on a resource\n- `@azure/identity` with `DefaultAzureCredential` for Microsoft Entra ID authentication\n\nThis package is for querying logs and metrics. It does not ingest telemetry, configure diagnostic settings, or manage Azure Monitor resources.\n\n## Install\n\nPin the package version your application expects and install Azure Identity alongside it:\n\n```bash\nnpm install @azure/monitor-query@1.3.3 @azure/identity\n```\n\n## Prerequisites\n\n- a Log Analytics workspace ID for `queryWorkspace()`\n- a full Azure resource ID for `queryResource()` and `MetricsQueryClient`\n- a signed-in developer session from `az login`, or service principal / managed identity credentials\n- permission to read monitor data on the target workspace or resource\n\nUseful environment variables:\n\n```bash\nexport AZURE_MONITOR_WORKSPACE_ID=\"<log-analytics-workspace-id>\"\nexport AZURE_RESOURCE_ID=\"/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/<resource-provider>/<resource-type>/<resource-name>\"\n```\n\nIf you are not using Azure CLI or managed identity, set service principal credentials too:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\n## Authentication And Setup\n\nFor local development, the normal path is:\n\n```bash\naz login\nexport AZURE_MONITOR_WORKSPACE_ID=\"<log-analytics-workspace-id>\"\nexport AZURE_RESOURCE_ID=\"/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/<resource-provider>/<resource-type>/<resource-name>\"\n```\n\nThen initialize the clients once and reuse them:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport {\n  LogsQueryClient,\n  MetricsQueryClient,\n} from \"@azure/monitor-query\";\n\nconst workspaceId = process.env.AZURE_MONITOR_WORKSPACE_ID;\nconst resourceId = process.env.AZURE_RESOURCE_ID;\n\nif (!workspaceId) {\n  throw new Error(\"AZURE_MONITOR_WORKSPACE_ID is required\");\n}\n\nif (!resourceId) {\n  throw new Error(\"AZURE_RESOURCE_ID is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst logsClient = new LogsQueryClient(credential);\nconst metricsClient = new MetricsQueryClient(credential);\n```\n\n`DefaultAzureCredential` can use Azure CLI credentials locally, service principal environment variables, workload identity, or managed identity depending on where the code runs.\n\n## Client Initialization\n\nKeep monitor client creation in one helper so the rest of the app only depends on validated configuration:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport {\n  LogsQueryClient,\n  MetricsQueryClient,\n} from \"@azure/monitor-query\";\n\nexport function createMonitorClients() {\n  const workspaceId = process.env.AZURE_MONITOR_WORKSPACE_ID;\n  const resourceId = process.env.AZURE_RESOURCE_ID;\n\n  if (!workspaceId) {\n    throw new Error(\"AZURE_MONITOR_WORKSPACE_ID is required\");\n  }\n\n  if (!resourceId) {\n    throw new Error(\"AZURE_RESOURCE_ID is required\");\n  }\n\n  const credential = new DefaultAzureCredential();\n\n  return {\n    workspaceId,\n    resourceId,\n    logsClient: new LogsQueryClient(credential),\n    metricsClient: new MetricsQueryClient(credential),\n  };\n}\n```\n\n## Core Usage\n\n### Query A Log Analytics Workspace\n\nUse `queryWorkspace()` when you already know which Log Analytics workspace contains the data.\n\n```js\nimport { LogsQueryResultStatus } from \"@azure/monitor-query\";\nimport { createMonitorClients } from \"./monitorClients.js\";\n\nfunction tableToObjects(table) {\n  const columnNames = table.columnDescriptors.map((column) => column.name);\n\n  return table.rows.map((row) =>\n    Object.fromEntries(\n      row.map((value, index) => [columnNames[index], value]),\n    ),\n  );\n}\n\nconst { logsClient, workspaceId } = createMonitorClients();\n\nconst result = await logsClient.queryWorkspace(\n  workspaceId,\n  `\n  AppRequests\n  | project TimeGenerated, Name, ResultCode, DurationMs\n  | take 5\n  `,\n  {\n    duration: \"PT1H\",\n  },\n);\n\nif (result.status === LogsQueryResultStatus.Success) {\n  for (const table of result.tables) {\n    console.log(tableToObjects(table));\n  }\n} else {\n  console.error(result.partialError);\n\n  for (const table of result.partialTables ?? []) {\n    console.log(tableToObjects(table));\n  }\n}\n```\n\nThe logs query text is Kusto Query Language (KQL). The time range above uses an ISO 8601 duration string.\n\n### Query Logs For A Resource\n\nUse `queryResource()` when your application starts from a specific Azure resource ID instead of a workspace ID.\n\n```js\nimport { LogsQueryResultStatus } from \"@azure/monitor-query\";\nimport { createMonitorClients } from \"./monitorClients.js\";\n\nconst { logsClient, resourceId } = createMonitorClients();\n\nconst result = await logsClient.queryResource(\n  resourceId,\n  `\n  AppRequests\n  | take 5\n  `,\n  {\n    duration: \"PT30M\",\n  },\n);\n\nif (result.status === LogsQueryResultStatus.Success) {\n  console.log(result.tables);\n} else {\n  console.error(result.partialError);\n  console.log(result.partialTables ?? []);\n}\n```\n\nThe available tables depend on the resource type and how monitoring data is configured for that resource. Replace `AppRequests` with a table that exists for your target resource.\n\n### Query Metrics For A Resource\n\nUse `MetricsQueryClient` for Azure Monitor metrics. Metrics are resource-scoped, so you query with a full Azure resource ID.\n\n```js\nimport { createMonitorClients } from \"./monitorClients.js\";\n\nconst { metricsClient, resourceId } = createMonitorClients();\n\nconst metricsResult = await metricsClient.queryResource(\n  resourceId,\n  [\"Percentage CPU\"],\n  {\n    timespan: {\n      duration: \"PT1H\",\n    },\n    aggregations: [\"Average\", \"Maximum\"],\n  },\n);\n\nfor (const metric of metricsResult.metrics) {\n  for (const series of metric.timeseries ?? []) {\n    for (const point of series.data ?? []) {\n      console.log({\n        timeStamp: point.timeStamp,\n        average: point.average,\n        maximum: point.maximum,\n      });\n    }\n  }\n}\n```\n\nIf the resource exposes multiple metric namespaces, pass `metricNamespace` in the options object and use the metric names defined for that namespace.\n\n## Practical Notes\n\n- `queryWorkspace()` expects a Log Analytics workspace ID.\n- `queryResource()` and `MetricsQueryClient` expect a full Azure resource ID.\n- Reuse one credential and one client per process instead of constructing a new client for every query.\n- Logs queries use KQL and return tabular results. Metrics queries return metric series and points.\n- Use ISO 8601 durations such as `\"PT30M\"` and `\"PT1H\"` for query windows when you do not need explicit start and end timestamps.\n\n## Common Pitfalls\n\n- Swapping a workspace ID and a resource ID. They are not interchangeable.\n- Forgetting to install `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Treating any non-success logs result as a hard failure instead of checking the documented partial-result fields.\n- Copying a metric name from a different resource provider. Metric names and namespaces are resource-specific.\n- Using this package for telemetry ingestion or Application Insights SDK setup. This package is query-only.\n\n## Version Notes For 1.3.3\n\n- This guide targets `@azure/monitor-query` `1.3.3`.\n- The `1.3.3` package surface documented on Microsoft Learn includes both `LogsQueryClient` and `MetricsQueryClient`.\n- `@azure/identity` is versioned separately and should be pinned according to your application's Azure SDK policy.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/monitor-query/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/monitor-query-readme?view=azure-node-latest`\n- `LogsQueryClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/monitor-query/logsqueryclient?view=azure-node-latest`\n- `MetricsQueryClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/monitor-query/metricsqueryclient?view=azure-node-latest`\n- `LogsQueryResultStatus` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/monitor-query/logsqueryresultstatus?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- Azure SDK changelog: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/monitor/monitor-query/CHANGELOG.md`\n- npm package page: `https://www.npmjs.com/package/@azure/monitor-query`\n"
  },
  {
    "path": "content/azure/docs/monitor-query/python/DOC.md",
    "content": "---\nname: monitor-query\ndescription: \"azure-monitor-query package guide for Python 2.0.0 with LogsQueryClient setup, Entra auth, batch queries, and 2.x migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-monitor,log-analytics,logs,observability,python\"\n---\n\n# azure-monitor-query Python Package Guide\n\n## What It Is\n\n`azure-monitor-query` is the official Azure SDK package for querying Azure Monitor logs from Python.\n\nFor `2.0.0`, this package is focused on logs queries:\n\n- use `LogsQueryClient` for Log Analytics workspace queries\n- use `LogsBatchQuery` with `query_batch()` for multiple logs queries in one request\n- use `query_resource()` when you want logs scoped to an Azure resource instead of a workspace\n\nImportant version-sensitive change:\n\n- `azure-monitor-query` `2.0.0` no longer carries the metrics query clients from older releases\n- if older code uses `MetricsQueryClient` or `MetricsClient`, move that code to the separate `azure-monitor-querymetrics` package\n\nThis package is for querying existing Azure Monitor logs. It is not the ingestion client and it does not manage alerts, dashboards, or Azure Monitor resources.\n\n## Install\n\nInstall the version used here plus Azure Identity:\n\n```bash\npython -m pip install \"azure-monitor-query==2.0.0\" \"azure-identity\"\n```\n\nIf you use the async client, add an async transport:\n\n```bash\npython -m pip install aiohttp\n```\n\nIf you need metrics queries too, install the split metrics package separately:\n\n```bash\npython -m pip install \"azure-monitor-querymetrics\" \"azure-identity\"\n```\n\n## Initialize And Authenticate\n\nThe standard Azure SDK path is `DefaultAzureCredential` from `azure-identity`.\n\nFor local development, one of these usually works:\n\n- `az login`\n- Azure Developer CLI sign-in\n- service principal environment variables\n- workload identity or managed identity when running in Azure\n\nAt minimum, you usually need:\n\n- a Log Analytics workspace ID for `query_workspace()`\n- a full Azure resource ID for `query_resource()`\n\nBasic setup:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.monitor.query import LogsQueryClient\n\ncredential = DefaultAzureCredential()\nclient = LogsQueryClient(credential)\n\nworkspace_id = os.environ[\"AZURE_MONITOR_WORKSPACE_ID\"]\nresource_id = os.environ[\"AZURE_RESOURCE_ID\"]\n```\n\nFor sovereign clouds, pass an explicit endpoint when creating the client:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.monitor.query import LogsQueryClient\n\ncredential = DefaultAzureCredential()\nclient = LogsQueryClient(\n    credential=credential,\n    endpoint=\"https://api.loganalytics.us\",\n)\n```\n\n## Core Usage\n\n### Query A Log Analytics Workspace\n\nUse `query_workspace()` when you already know the Log Analytics workspace that holds the data.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.monitor.query import LogsQueryClient, LogsQueryStatus\n\nresult = client.query_workspace(\n    workspace_id=workspace_id,\n    query=\"\"\"\n    AppRequests\n    | take 5\n    \"\"\",\n    timespan=timedelta(hours=1),\n)\n\nif result.status == LogsQueryStatus.SUCCESS:\n    tables = result.tables\nelif result.status == LogsQueryStatus.PARTIAL:\n    print(result.partial_error.code, result.partial_error.message)\n    tables = result.partial_data\nelse:\n    raise RuntimeError(f\"Unexpected status: {result.status}\")\n\nfor table in tables:\n    columns = [column.name for column in table.columns]\n    for row in table.rows:\n        print(dict(zip(columns, row)))\n```\n\nNotes:\n\n- pass `timespan=` explicitly; it can be a `timedelta`, `(start, duration)`, or `(start, end)`\n- handle partial results instead of assuming every query returns `SUCCESS`\n- `query_workspace()` supports `additional_workspaces`, `include_statistics`, `include_visualization`, and `server_timeout`\n\n### Query Logs For An Azure Resource\n\nUse `query_resource()` when your query should follow the Azure resource rather than a single workspace.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.monitor.query import LogsQueryStatus\n\nresult = client.query_resource(\n    resource_id,\n    query=\"\"\"\n    AzureActivity\n    | take 5\n    \"\"\",\n    timespan=timedelta(hours=2),\n)\n\nif result.status == LogsQueryStatus.SUCCESS:\n    for table in result.tables:\n        print(table.name, len(table.rows))\nelif result.status == LogsQueryStatus.PARTIAL:\n    print(result.partial_error.message)\n```\n\nUse this when your app naturally starts from a resource ID, such as an App Service, Function App, or VM.\n\n### Run Multiple Logs Queries In One Call\n\nUse `LogsBatchQuery` plus `query_batch()` for fewer round trips when you need several queries.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.monitor.query import LogsBatchQuery, LogsQueryStatus\n\nrequests = [\n    LogsBatchQuery(\n        workspace_id=workspace_id,\n        query=\"AppRequests | take 5\",\n        timespan=timedelta(hours=1),\n    ),\n    LogsBatchQuery(\n        workspace_id=workspace_id,\n        query=\"AzureActivity | summarize count() by Category\",\n        timespan=timedelta(hours=6),\n    ),\n]\n\nresults = client.query_batch(requests)\n\nfor item in results:\n    if item.status == LogsQueryStatus.SUCCESS:\n        print(item.tables[0].rows)\n    elif item.status == LogsQueryStatus.PARTIAL:\n        print(item.partial_error.code, item.partial_error.message)\n    else:\n        print(item.code, item.message)\n```\n\nBatch results can mix success, partial, and failure states. Inspect each item independently.\n\n### Query Across Multiple Workspaces\n\nIf your main target is one workspace but the query needs data from others, pass `additional_workspaces`.\n\n```python\nfrom datetime import timedelta\n\nresult = client.query_workspace(\n    workspace_id=workspace_id,\n    query=\"AppRequests | summarize count() by bin(TimeGenerated, 5m)\",\n    timespan=timedelta(hours=1),\n    additional_workspaces=[\n        \"00000000-0000-0000-0000-000000000000\",\n        \"11111111-1111-1111-1111-111111111111\",\n    ],\n)\n```\n\nThe extra entries can be workspace IDs, qualified workspace names, or Azure resource IDs according to the official client docs.\n\n### Include Query Statistics\n\nUse `include_statistics=True` when you need query execution details for debugging or tuning.\n\n```python\nfrom datetime import timedelta\n\nresult = client.query_workspace(\n    workspace_id=workspace_id,\n    query=\"AppRequests | count\",\n    timespan=timedelta(hours=1),\n    include_statistics=True,\n)\n\nprint(result.statistics)\n```\n\nThe service can also return visualization metadata with `include_visualization=True`.\n\n### Async Client\n\nThe async surface lives under `azure.monitor.query.aio`.\n\n```python\nfrom datetime import timedelta\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.monitor.query.aio import LogsQueryClient\n\ncredential = DefaultAzureCredential()\nclient = LogsQueryClient(credential)\n\ntry:\n    result = await client.query_workspace(\n        workspace_id=workspace_id,\n        query=\"AppRequests | take 5\",\n        timespan=timedelta(hours=1),\n    )\nfinally:\n    await client.close()\n    await credential.close()\n```\n\nInstall `aiohttp` if your environment does not already provide an async transport.\n\n## Configuration Notes\n\n- `query_workspace()` expects a Log Analytics workspace ID.\n- `query_resource()` expects a full Azure resource ID.\n- The package import is `azure.monitor.query`, not `azure_monitor_query`.\n- For non-public Azure clouds, set `endpoint=` on `LogsQueryClient`.\n- `server_timeout` is a server-side limit for logs queries, not a client socket timeout.\n- `azure-monitor-query` `2.0.0` requires a modern Python runtime; PyPI lists `Requires: Python >=3.9`.\n\n## Common Pitfalls\n\n### Old Metrics Examples Break On 2.0.0\n\nIf copied code imports any of these from `azure.monitor.query`, it is from the pre-split package surface:\n\n- `MetricsQueryClient`\n- `MetricsClient`\n- metrics model types from the old combined package\n\nFor `2.0.0`, move metrics code to `azure-monitor-querymetrics`. Do not try to mix old metrics examples into this package.\n\n### Package Name And Import Name Differ\n\nInstall with:\n\n```bash\npip install azure-monitor-query\n```\n\nImport with:\n\n```python\nfrom azure.monitor.query import LogsQueryClient\n```\n\n### Workspace ID And Resource ID Are Not Interchangeable\n\nThis is the most common wiring mistake:\n\n- `query_workspace()` takes a workspace ID\n- `query_resource()` takes a resource ID like `/subscriptions/.../resourceGroups/.../providers/...`\n\nPassing the wrong identifier usually produces confusing authorization or not-found failures.\n\n### Partial Results Are Normal\n\nLogs queries can return `LogsQueryStatus.PARTIAL`. Treat that as a handled state and inspect:\n\n- `partial_error`\n- `partial_data`\n\nDo not assume every successful HTTP response means full query success.\n\n### Async Cleanup Matters\n\nClose both the async client and the async credential. If you skip cleanup, long-running apps and tests can leak connections.\n\n## Version Notes For Agents\n\n- Version used here: `2.0.0`\n- PyPI latest at verification time: `2.0.0`\n- PyPI release date for `2.0.0`: `2025-07-30`\n- The Microsoft Learn docs root is a moving latest-style reference, not a version-pinned static snapshot\n\nThe `2.0.0` breaking change that matters most for code generation is the package split:\n\n- logs queries stay in `azure-monitor-query`\n- metrics queries moved to `azure-monitor-querymetrics`\n\nIf a project is upgrading from `1.x`, check imports first before changing query code.\n\n## Official Sources Used\n\n- Microsoft Learn overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/monitor-query-readme?view=azure-python`\n- Microsoft Learn `LogsQueryClient`: `https://learn.microsoft.com/en-us/python/api/azure-monitor-query/azure.monitor.query.logsqueryclient?view=azure-python`\n- Microsoft Learn `LogsBatchQuery`: `https://learn.microsoft.com/en-us/python/api/azure-monitor-query/azure.monitor.query.logsbatchquery?view=azure-python`\n- PyPI package page: `https://pypi.org/project/azure-monitor-query/`\n"
  },
  {
    "path": "content/azure/docs/notification-hubs/javascript/DOC.md",
    "content": "---\nname: notification-hubs\ndescription: \"Azure Notification Hubs JavaScript data-plane client for connection-string auth, installation management, and sending targeted push notifications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,notification-hubs,push-notifications,javascript,apns,fcm,installations\"\n---\n\n# Azure Notification Hubs JavaScript SDK\n\n## Golden Rule\n\nUse `@azure/notification-hubs` for Notification Hubs data-plane work from JavaScript or TypeScript: create a hub client context from a connection string, manage device installations, and send platform-specific notifications to all devices or a targeted tag expression.\n\nDo not use this package to create namespaces, create hubs, or configure APNS/FCM/WNS credentials on the Azure resource. Those are management-plane tasks handled through Azure Resource Manager tools such as the Azure portal, Azure CLI, Bicep, Terraform, or a management SDK.\n\nThis guide targets `@azure/notification-hubs` `2.0.2`.\n\n## Install\n\nPin the SDK version your project expects:\n\n```bash\nnpm install @azure/notification-hubs@2.0.2\n```\n\nThe package uses Notification Hubs connection strings for authentication. You do not add `@azure/identity` for the workflows shown here.\n\n## Prerequisites And Setup\n\nBefore your code can send or register devices, make sure you already have:\n\n1. an Azure Notification Hubs namespace and hub\n2. platform credentials configured on that hub for the push service you will use, such as APNS or FCM\n3. a hub connection string with rights that match the work your code performs\n\nRecommended environment variables:\n\n```bash\nexport AZURE_NOTIFICATION_HUB_CONNECTION_STRING=\"Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=<policy>;SharedAccessKey=<key>\"\nexport AZURE_NOTIFICATION_HUB_NAME=\"my-notification-hub\"\n\n# Example device tokens for app-side registration workflows\nexport APNS_DEVICE_TOKEN=\"<ios-device-token>\"\nexport FCM_DEVICE_TOKEN=\"<android-device-token>\"\n```\n\nKeep these details straight:\n\n- the connection string authenticates the SDK call\n- the hub name tells the SDK which notification hub to use\n- the device token or push channel identifies the target device inside APNS, FCM, WNS, or another push platform\n\n## Client Initialization\n\nCreate one shared client context and reuse it for related operations:\n\n```js\nimport { createClientContext } from \"@azure/notification-hubs\";\n\nconst connectionString = process.env.AZURE_NOTIFICATION_HUB_CONNECTION_STRING;\nconst hubName = process.env.AZURE_NOTIFICATION_HUB_NAME;\n\nif (!connectionString || !hubName) {\n  throw new Error(\n    \"AZURE_NOTIFICATION_HUB_CONNECTION_STRING and AZURE_NOTIFICATION_HUB_NAME are required\",\n  );\n}\n\nexport const context = createClientContext(connectionString, hubName);\n```\n\nUse this context for installation, registration, and send operations instead of reconstructing it for every call.\n\n## Core Workflow: Manage Installations\n\nFor new code, prefer installations as the device-registration model. An installation ties together your app's installation identifier, the platform push channel, and any tags you want to target later.\n\n### Create or update an installation\n\nCall `createOrUpdateInstallation(...)` whenever a device is first registered or its push token changes:\n\n```js\nimport {\n  createClientContext,\n  createOrUpdateInstallation,\n} from \"@azure/notification-hubs\";\n\nconst context = createClientContext(\n  process.env.AZURE_NOTIFICATION_HUB_CONNECTION_STRING,\n  process.env.AZURE_NOTIFICATION_HUB_NAME,\n);\n\nconst installation = {\n  installationId: \"user-42-ios\",\n  platform: \"apns\",\n  pushChannel: process.env.APNS_DEVICE_TOKEN,\n  tags: [\"user:42\", \"tenant:acme\", \"ios\"],\n};\n\nawait createOrUpdateInstallation(context, installation);\n```\n\nThe important fields are:\n\n- `installationId`: your stable identifier for the app installation\n- `platform`: the push platform for this device\n- `pushChannel`: the current device token or channel from that push platform\n- `tags`: optional targeting labels you can use later in `tagExpression`\n\n### Read or delete an installation\n\n```js\nimport {\n  createClientContext,\n  deleteInstallation,\n  getInstallation,\n} from \"@azure/notification-hubs\";\n\nconst context = createClientContext(\n  process.env.AZURE_NOTIFICATION_HUB_CONNECTION_STRING,\n  process.env.AZURE_NOTIFICATION_HUB_NAME,\n);\n\nconst installationId = \"user-42-ios\";\n\nconst installation = await getInstallation(context, installationId);\nconsole.log(installation.installationId, installation.tags);\n\nawait deleteInstallation(context, installationId);\n```\n\nDelete installations when a user signs out permanently, disables notifications, or you know the app installation should no longer receive pushes.\n\n## Core Workflow: Send Notifications\n\n`sendNotification(...)` sends a platform payload through Notification Hubs. If you omit targeting options, the send is broadcast to all matching platform registrations in the hub. If you provide a `tagExpression`, the send is targeted.\n\n### Send an APNS notification to a tag expression\n\n```js\nimport {\n  createAppleNotification,\n  createClientContext,\n  sendNotification,\n} from \"@azure/notification-hubs\";\n\nconst context = createClientContext(\n  process.env.AZURE_NOTIFICATION_HUB_CONNECTION_STRING,\n  process.env.AZURE_NOTIFICATION_HUB_NAME,\n);\n\nconst notification = createAppleNotification({\n  body: JSON.stringify({\n    aps: {\n      alert: {\n        title: \"Order shipped\",\n        body: \"Tap to track package 12345\",\n      },\n      sound: \"default\",\n    },\n    orderId: \"12345\",\n  }),\n});\n\nawait sendNotification(context, notification, {\n  tagExpression: \"user:42\",\n});\n```\n\nThe payload inside `body` must match the push platform you are sending to. Notification Hubs routes the payload, but APNS still expects APNS JSON and FCM still expects FCM JSON.\n\n### Send an FCM v1 notification\n\n```js\nimport {\n  createClientContext,\n  createFcmV1Notification,\n  sendNotification,\n} from \"@azure/notification-hubs\";\n\nconst context = createClientContext(\n  process.env.AZURE_NOTIFICATION_HUB_CONNECTION_STRING,\n  process.env.AZURE_NOTIFICATION_HUB_NAME,\n);\n\nconst notification = createFcmV1Notification({\n  body: JSON.stringify({\n    message: {\n      notification: {\n        title: \"Order shipped\",\n        body: \"Tap to track package 12345\",\n      },\n      data: {\n        orderId: \"12345\",\n      },\n    },\n  }),\n});\n\nawait sendNotification(context, notification, {\n  tagExpression: \"tenant:acme && android\",\n});\n```\n\n## Tags And Targeting\n\nTags are the main way to target subsets of devices without tracking raw push tokens in your application logic.\n\nTypical patterns:\n\n- per-user tags such as `user:42`\n- per-tenant tags such as `tenant:acme`\n- per-platform tags such as `ios` or `android`\n- feature or preference tags such as `marketing-opt-in`\n\nKeep tags stable and meaningful. If a device token rotates, update the installation in place instead of creating a new installation with a different `installationId` unless the app installation itself has changed.\n\n## Registrations vs Installations\n\nNotification Hubs supports both legacy registrations and the newer installation model. For new JavaScript integrations, use installations unless you are maintaining an older registration-based flow that already exists.\n\nThat choice keeps device identity, tags, and template metadata tied to a single installation record you can upsert when the push channel changes.\n\n## Practical Notes\n\n- Keep hub connection strings in a server-side secret store or environment variable, not in browser code or mobile app bundles.\n- Configure APNS, FCM, WNS, or other platform credentials on the hub before trying to send. The SDK cannot compensate for missing hub-side platform setup.\n- Reuse the same `createClientContext(...)` result across related operations.\n- Update the installation whenever the underlying device token changes.\n- Use narrowly scoped SAS policies instead of broad management credentials when possible.\n\n## Common Pitfalls\n\n- Treating this package as an Azure Resource Manager SDK for provisioning namespaces or hubs\n- Sending an APNS payload to Android devices or an FCM payload to Apple devices\n- Forgetting to configure platform credentials on the notification hub before calling `sendNotification(...)`\n- Exposing Notification Hubs connection strings in public frontend code\n- Creating a new installation ID every time the device token changes instead of updating the existing installation\n\n## Version Notes For `2.0.2`\n\n- This guide targets `@azure/notification-hubs` `2.0.2`.\n- New application code should center on `createClientContext(...)`, installation management, and platform-specific notification builders.\n- If you are maintaining older registration-based samples, map them carefully to the current top-level operations before copying them into new code.\n\n## Official Sources\n\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/notification-hubs/?view=azure-node-latest`\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/notification-hubs-readme?view=azure-node-latest`\n- Azure Notification Hubs installation management concepts: `https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-push-notification-registration-management`\n- Azure Notification Hubs templates overview: `https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-templates-cross-platform-push-messages`\n- npm package page: `https://www.npmjs.com/package/@azure/notification-hubs`\n"
  },
  {
    "path": "content/azure/docs/openai/javascript/DOC.md",
    "content": "---\nname: openai\ndescription: \"Azure OpenAI JavaScript SDK guide for @azure/openai 2.0.0 with AzureOpenAI client setup, auth, chat completions, streaming, and embeddings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,openai,llm,javascript,azure-openai\"\n---\n\n# @azure/openai JavaScript Package Guide\n\n## What This Package Is\n\n`@azure/openai` is the Azure SDK package for calling Azure OpenAI from JavaScript and TypeScript.\n\nFor `2.0.0`, use the `AzureOpenAI` client and the OpenAI-style method groups such as:\n\n- `client.chat.completions.create(...)`\n- `client.embeddings.create(...)`\n\nIf you find older examples using `OpenAIClient`, `getChatCompletions()`, or `getEmbeddings()`, those are from older package generations and do not match `2.0.0`.\n\n## Golden Rules\n\n- Use your Azure **resource endpoint**, such as `https://<resource-name>.openai.azure.com`\n- Use your Azure **deployment name** in `model`, not the base model family name by itself\n- Set an explicit API version; Azure OpenAI requests are versioned\n- Use `DefaultAzureCredential` for local `az login`, managed identity, or service principal flows when possible\n\n## Install\n\nInstall the package:\n\n```bash\nnpm install @azure/openai\n```\n\nIf you want Microsoft Entra ID authentication:\n\n```bash\nnpm install @azure/openai @azure/identity\n```\n\n## Required Azure Setup\n\nYou need all of the following before the SDK calls will work:\n\n1. An Azure OpenAI resource\n2. Its endpoint URL\n3. At least one deployed model\n4. The deployment name for each workload you call\n5. Either an API key or Microsoft Entra credentials\n\nRecommended environment variables:\n\n```bash\nexport AZURE_OPENAI_ENDPOINT=\"https://<resource-name>.openai.azure.com\"\nexport AZURE_OPENAI_API_KEY=\"<api-key>\"\nexport AZURE_OPENAI_DEPLOYMENT=\"gpt-4o-mini\"\nexport AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT=\"text-embedding-3-large\"\nexport OPENAI_API_VERSION=\"2024-10-21\"\n```\n\nIf your app uses keyless auth, keep `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_DEPLOYMENT`, and `OPENAI_API_VERSION`, and authenticate with `DefaultAzureCredential`.\n\n## Authentication And Client Initialization\n\n### API key authentication\n\nUse this when you already have an Azure OpenAI key.\n\n```js\nimport { AzureOpenAI } from \"@azure/openai\";\n\nconst client = new AzureOpenAI({\n  endpoint: process.env.AZURE_OPENAI_ENDPOINT,\n  apiKey: process.env.AZURE_OPENAI_API_KEY,\n  deployment: process.env.AZURE_OPENAI_DEPLOYMENT,\n  apiVersion: process.env.OPENAI_API_VERSION ?? \"2024-10-21\",\n});\n```\n\n### Microsoft Entra ID authentication\n\nUse a bearer token provider when you want local `az login`, a managed identity, or a service principal.\n\n```js\nimport { AzureOpenAI } from \"@azure/openai\";\nimport { DefaultAzureCredential, getBearerTokenProvider } from \"@azure/identity\";\n\nconst scope = \"https://cognitiveservices.azure.com/.default\";\nconst azureADTokenProvider = getBearerTokenProvider(\n  new DefaultAzureCredential(),\n  scope,\n);\n\nconst client = new AzureOpenAI({\n  endpoint: process.env.AZURE_OPENAI_ENDPOINT,\n  azureADTokenProvider,\n  deployment: process.env.AZURE_OPENAI_DEPLOYMENT,\n  apiVersion: process.env.OPENAI_API_VERSION ?? \"2024-10-21\",\n});\n```\n\n## Common Workflows\n\n### Chat completions\n\nUse `client.chat.completions.create(...)` for standard prompt/response generation.\n\n```js\nimport { AzureOpenAI } from \"@azure/openai\";\n\nconst client = new AzureOpenAI({\n  endpoint: process.env.AZURE_OPENAI_ENDPOINT,\n  apiKey: process.env.AZURE_OPENAI_API_KEY,\n  deployment: process.env.AZURE_OPENAI_DEPLOYMENT,\n  apiVersion: process.env.OPENAI_API_VERSION ?? \"2024-10-21\",\n});\n\nconst completion = await client.chat.completions.create({\n  model: process.env.AZURE_OPENAI_DEPLOYMENT,\n  messages: [\n    { role: \"system\", content: \"You write concise technical summaries.\" },\n    { role: \"user\", content: \"Explain vector search in two sentences.\" },\n  ],\n  max_tokens: 200,\n});\n\nconsole.log(completion.choices[0].message.content);\n```\n\n### Streaming chat completions\n\nFor incremental output, set `stream: true` and iterate over the returned events.\n\n```js\nimport { AzureOpenAI } from \"@azure/openai\";\n\nconst client = new AzureOpenAI({\n  endpoint: process.env.AZURE_OPENAI_ENDPOINT,\n  apiKey: process.env.AZURE_OPENAI_API_KEY,\n  deployment: process.env.AZURE_OPENAI_DEPLOYMENT,\n  apiVersion: process.env.OPENAI_API_VERSION ?? \"2024-10-21\",\n});\n\nconst stream = await client.chat.completions.create({\n  model: process.env.AZURE_OPENAI_DEPLOYMENT,\n  messages: [\n    { role: \"user\", content: \"List three rollout risks for a database migration.\" },\n  ],\n  stream: true,\n});\n\nfor await (const event of stream) {\n  const delta = event.choices?.[0]?.delta?.content;\n  if (delta) {\n    process.stdout.write(delta);\n  }\n}\n\nprocess.stdout.write(\"\\n\");\n```\n\n### Embeddings\n\nUse a separate deployment if your Azure resource has one for embeddings.\n\n```js\nimport { AzureOpenAI } from \"@azure/openai\";\n\nconst client = new AzureOpenAI({\n  endpoint: process.env.AZURE_OPENAI_ENDPOINT,\n  apiKey: process.env.AZURE_OPENAI_API_KEY,\n  apiVersion: process.env.OPENAI_API_VERSION ?? \"2024-10-21\",\n});\n\nconst result = await client.embeddings.create({\n  model: process.env.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT,\n  input: [\n    \"Azure OpenAI supports deployment-scoped model routing.\",\n    \"Embeddings are useful for retrieval and semantic search.\",\n  ],\n});\n\nconsole.log(result.data.length);\nconsole.log(result.data[0].embedding.length);\n```\n\n## Configuration Notes\n\n- `endpoint` should be the service root, not a deployment URL and not a path ending in `/openai/deployments/...`\n- Keep `apiVersion` explicit in code or environment so upgrades are deliberate\n- For Azure OpenAI, `model` is typically your deployment name in real applications\n- Reuse one client instance per process or request scope instead of recreating it for every call\n\n## Version-Sensitive Notes For 2.0.0\n\n- `2.0.0` uses the OpenAI-style grouped API surface under `client.chat.completions` and `client.embeddings`\n- Older examples that use `OpenAIClient`, `getChatCompletions()`, or `getEmbeddings()` do not match this package version\n- The package requires an Azure OpenAI API version; keep `OPENAI_API_VERSION` pinned instead of relying on tutorial defaults from unrelated examples\n\n## Common Pitfalls\n\n- Passing the model family name when Azure expects your deployment name\n- Forgetting to set `OPENAI_API_VERSION`\n- Using the wrong resource URL format instead of `https://<resource-name>.openai.azure.com`\n- Mixing API-key auth and Entra auth configuration in the same initialization path\n- Copying pre-2.0 samples that use different client types and method names\n\n## Official Sources\n\n- Azure SDK for JavaScript `@azure/openai` README: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/openai/openai/README.md\n- JavaScript API overview for `@azure/openai`: https://learn.microsoft.com/javascript/api/overview/azure/openai-readme?view=azure-node-latest\n- Azure OpenAI endpoint switching guidance: https://learn.microsoft.com/azure/ai-foundry/openai/how-to/switching-endpoints\n"
  },
  {
    "path": "content/azure/docs/openai/python/DOC.md",
    "content": "---\nname: openai\ndescription: \"Azure OpenAI for Python - practical guide for current Azure OpenAI usage and legacy azure-openai package context\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"azure,openai,llm,python,azure-openai\"\n---\n\n# Azure OpenAI Python Package Guide\n\n## Golden Rule\n\nTreat `azure-openai==1.0.0` as legacy package metadata, not the default install target for new code.\n\nFor current Azure OpenAI Python work, Microsoft Learn documents the official `openai` client pointed at your Azure endpoint:\n\n```bash\npip install openai\npip install azure-identity\n```\n\nUse `azure-openai` only if you are maintaining an already-pinned legacy environment and have verified the exact package source internally.\n\n## What This Entry Covers\n\n- Ecosystem: `pypi`\n- Version used here: `1.0.0`\n- Language: `python`\n- Current official Azure Python guidance: use the `openai` package with Azure OpenAI `v1` endpoints\n\n## Setup\n\nYou need all of the following before code will work:\n\n1. An Azure OpenAI resource endpoint such as `https://YOUR-RESOURCE-NAME.openai.azure.com/`\n2. A deployed model in that resource\n3. The deployment name for that model\n4. Either an API key or Microsoft Entra credentials\n\nRecommended environment variables:\n\n```bash\nexport AZURE_OPENAI_ENDPOINT=\"https://YOUR-RESOURCE-NAME.openai.azure.com\"\nexport AZURE_OPENAI_DEPLOYMENT=\"gpt-4.1-mini\"\nexport AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT=\"text-embedding-3-large\"\nexport AZURE_OPENAI_API_KEY=\"...\"\n```\n\nFor keyless auth, keep `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT` and authenticate with `DefaultAzureCredential`.\n\n## Initialize With API Key\n\nUse the standard `OpenAI` client and include the Azure `v1` base URL.\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n\nresponse = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"Write a haiku about distributed systems.\",\n)\n\nprint(response.output_text)\n```\n\n## Initialize With Microsoft Entra ID\n\nMicrosoft recommends keyless auth when possible.\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nfrom openai import OpenAI\n\ntoken_provider = get_bearer_token_provider(\n    DefaultAzureCredential(),\n    \"https://cognitiveservices.azure.com/.default\",\n)\n\nclient = OpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,\n)\n\nresponse = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"Summarize the difference between a queue and a topic.\",\n)\n\nprint(response.output_text)\n```\n\n## Core Usage Patterns\n\n### Responses API\n\nUse `client.responses.create(...)` for new text-generation work.\n\n```python\nfrom openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n\nresponse = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    instructions=\"You are a precise Python code reviewer.\",\n    input=\"Review this function for obvious bugs: def add(a, b): return a - b\",\n)\n\nprint(response.output_text)\n```\n\n### Streaming\n\n```python\nfrom openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n\nstream = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"List three deployment risks for a schema migration.\",\n    stream=True,\n)\n\nfor event in stream:\n    if getattr(event, \"type\", \"\") == \"response.output_text.delta\":\n        print(event.delta, end=\"\")\n```\n\n### Embeddings\n\nAzure OpenAI embeddings on the `v1` API currently require API key auth.\n\n```python\nfrom openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n\nembedding = client.embeddings.create(\n    model=os.environ[\"AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT\"],\n    input=[\n        \"Package docs support internal search.\",\n        \"Agents should prefer official SDK examples.\",\n    ],\n)\n\nprint(len(embedding.data))\nprint(len(embedding.data[0].embedding))\n```\n\nFor batch embedding requests, Azure documents a maximum array size of `2048` inputs and an `8192` token request limit for the latest embeddings models.\n\n## Configuration And Auth Notes\n\n- `base_url` must end with `/openai/v1/`\n- The `model` argument must be your Azure deployment name, not the raw foundation model name\n- Keep secrets in environment variables, Azure Key Vault, or Entra ID, not in source code\n- For local development, `python-dotenv` is fine, but production code should use your platform secret store\n\n## Version-Sensitive Notes\n\n- Current Azure OpenAI `v1` guidance uses `from openai import OpenAI`; older examples often use `AzureOpenAI`\n- The `v1` API removes the need to keep supplying `api-version` for GA usage\n- Older blog posts and sample repos may still show `AzureOpenAI(...)`, `azure_endpoint=...`, and explicit `api_version=...`; treat those as legacy patterns unless your codebase is already pinned to them\n- Microsoft Learn now documents Azure OpenAI Python usage through `openai`, not through a current `azure-openai` installation flow\n\n## Common Pitfalls\n\n- Using the model name instead of the deployment name in `model=...`\n- Forgetting the `/openai/v1/` suffix in `base_url`, which typically causes `404` errors\n- Assuming Entra ID works for embeddings on the `v1` API; current Microsoft docs say it does not\n- Mixing OpenAI and Azure environment variables in the same process without being explicit about the client configuration\n- Copying stale `azure-openai` install instructions from old posts instead of following the current Microsoft Learn guidance\n\n## Official Sources\n\n- Azure OpenAI responses quickstart: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/responses\n- Switching between OpenAI and Azure OpenAI endpoints: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/switching-endpoints\n- Azure OpenAI embeddings: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/embeddings\n- Docs URL: https://learn.microsoft.com/en-us/python/api/azure-openai/\n"
  },
  {
    "path": "content/azure/docs/search-documents/javascript/DOC.md",
    "content": "---\nname: search-documents\ndescription: \"Azure AI Search JavaScript SDK for index schema, document indexing, querying, authentication, and stable 12.2.0 usage notes\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,azure-ai-search,search,indexing,rbac,javascript\"\n---\n\n# @azure/search-documents JavaScript Package Guide\n\n## What This Package Is\n\n`@azure/search-documents` is the official Azure AI Search JavaScript SDK for data-plane work.\n\nUse it when your code needs to:\n\n- create and manage search indexes\n- upload, merge, delete, and fetch indexed documents\n- run keyword, filtered, semantic, vector, and hybrid searches against an existing index\n- manage data source connections, indexers, skillsets, and synonym maps\n\nPrimary client types:\n\n- `SearchClient`: query and mutate documents in one existing index\n- `SearchIndexClient`: create, update, list, and delete indexes and related schema objects\n- `SearchIndexerClient`: manage pull-based indexing resources such as data sources, skillsets, and indexers\n\nThis guide is scoped to `@azure/search-documents` `12.2.0`.\n\n## Golden Rules\n\n- Use the service endpoint root, not an index URL: `https://<service-name>.search.windows.net`\n- Use a query key only for read-only queries; use an admin key or RBAC for writes and schema changes\n- `uploadDocuments()` inserts a new document or replaces the stored document with the same key\n- `mergeDocuments()` updates only named fields and fails if the document does not already exist\n- `mergeOrUploadDocuments()` is the safest default for idempotent sync jobs\n- Search document keys are case-sensitive, must be unique, and must be a top-level string field in the index\n\n## Install\n\nInstall the SDK:\n\n```bash\nnpm install @azure/search-documents\n```\n\nIf you want Microsoft Entra ID authentication:\n\n```bash\nnpm install @azure/search-documents @azure/identity\n```\n\n## Service Setup And Environment\n\nTypical environment variables:\n\n```bash\nexport AZURE_SEARCH_SERVICE_ENDPOINT=\"https://<service-name>.search.windows.net\"\nexport AZURE_SEARCH_INDEX_NAME=\"hotels\"\nexport AZURE_SEARCH_API_KEY=\"<admin-or-query-key>\"\n```\n\nFor service principal authentication, `DefaultAzureCredential` also uses the standard Azure Identity variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nKeep one naming convention in your app. Azure samples commonly use both `SEARCH_*` and `AZURE_SEARCH_*` variables.\n\n## Authentication And Client Initialization\n\n### API key authentication\n\nUse API keys for the simplest bootstrap path.\n\n- query key: read-only queries from client apps\n- admin key: index creation, document writes, indexer management, and other mutations\n\n```js\nimport { AzureKeyCredential, SearchClient } from \"@azure/search-documents\";\n\nconst client = new SearchClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  process.env.AZURE_SEARCH_INDEX_NAME,\n  new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n);\n```\n\n### Microsoft Entra ID authentication\n\nUse `DefaultAzureCredential` for local development with `az login`, managed identity, or a service principal.\n\n```js\nimport { SearchClient } from \"@azure/search-documents\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst client = new SearchClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  process.env.AZURE_SEARCH_INDEX_NAME,\n  new DefaultAzureCredential(),\n);\n```\n\nRole mapping that matters in practice:\n\n- query only: `Search Index Data Reader`\n- document uploads and updates: `Search Index Data Contributor`\n- schema and index management: `Search Service Contributor`\n- end-to-end quickstart flows that create, load, and query often need all three roles on the same principal\n\n## Core Index Setup\n\nThis is the minimum useful schema flow for most apps: define fields, create or update the index, then reuse `SearchClient` for writes and queries.\n\n```js\nimport {\n  AzureKeyCredential,\n  SearchIndexClient,\n} from \"@azure/search-documents\";\n\nconst indexClient = new SearchIndexClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n);\n\nconst index = {\n  name: process.env.AZURE_SEARCH_INDEX_NAME,\n  fields: [\n    {\n      name: \"hotelId\",\n      type: \"Edm.String\",\n      key: true,\n      filterable: true,\n    },\n    {\n      name: \"hotelName\",\n      type: \"Edm.String\",\n      searchable: true,\n    },\n    {\n      name: \"description\",\n      type: \"Edm.String\",\n      searchable: true,\n    },\n    {\n      name: \"rating\",\n      type: \"Edm.Double\",\n      filterable: true,\n      sortable: true,\n    },\n  ],\n};\n\nawait indexClient.createOrUpdateIndex(index);\n```\n\nUse `SearchIndexClient` for index lifecycle and schema work. Use `SearchClient` for document writes and queries against an existing index.\n\n## Upload, Merge, And Delete Documents\n\n```js\nimport { AzureKeyCredential, SearchClient } from \"@azure/search-documents\";\n\nconst searchClient = new SearchClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  process.env.AZURE_SEARCH_INDEX_NAME,\n  new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n);\n\nconst uploadResult = await searchClient.uploadDocuments([\n  {\n    hotelId: \"1\",\n    hotelName: \"Stay Kay City Hotel\",\n    description: \"Modern hotel with rooftop lounge\",\n    rating: 4.6,\n  },\n  {\n    hotelId: \"2\",\n    hotelName: \"Blue River Resort\",\n    description: \"Waterfront rooms near downtown\",\n    rating: 4.2,\n  },\n]);\n\nconsole.log(uploadResult.results.map((item) => ({\n  key: item.key,\n  succeeded: item.succeeded,\n})));\n\nawait searchClient.mergeDocuments([\n  {\n    hotelId: \"1\",\n    rating: 4.8,\n  },\n]);\n\nawait searchClient.mergeOrUploadDocuments([\n  {\n    hotelId: \"3\",\n    hotelName: \"Northwind Suites\",\n    description: \"Walkable downtown location\",\n    rating: 4.4,\n  },\n]);\n\nawait searchClient.deleteDocuments(\"hotelId\", [\"2\"]);\n```\n\nBehavior to remember:\n\n- `uploadDocuments()` inserts or fully replaces the document with that key\n- `mergeDocuments()` updates only named fields, but requires the document to exist\n- `mergeOrUploadDocuments()` acts like merge if the key exists and upload if it does not\n- `deleteDocuments()` is keyed by the document key; other fields do not matter to the delete action\n- bulk indexing responses are per-document, so inspect the returned results instead of assuming the whole batch succeeded\n\n## Query Documents\n\n```js\nimport { AzureKeyCredential, SearchClient } from \"@azure/search-documents\";\n\nconst client = new SearchClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  process.env.AZURE_SEARCH_INDEX_NAME,\n  new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n);\n\nconst searchResults = await client.search(\"restaurant\", {\n  filter: \"rating ge 4\",\n  select: [\"hotelId\", \"hotelName\", \"rating\"],\n  top: 5,\n});\n\nfor await (const result of searchResults.results) {\n  console.log(\n    result.document.hotelId,\n    result.document.hotelName,\n    result.document.rating,\n  );\n}\n\nconst document = await client.getDocument(\"1\");\nconsole.log(document.hotelName);\n```\n\nUseful search patterns:\n\n- `client.search(\"*\", options)` returns a match-all result set\n- `filter` uses OData filter syntax on fields marked `filterable`\n- `select` reduces payload size and latency\n- `searchFields` limits which searchable fields are queried\n- `getDocument(key)` is the direct lookup path when you already know the key\n- `suggest()` and `autocomplete()` require suggester-aware index configuration\n\nThe current JavaScript client surface also includes semantic and vector query options. Those only work when the target service and index are configured for those features.\n\n## SearchIndexerClient When You Need Pull-Based Ingestion\n\nUse `SearchIndexerClient` when Azure AI Search should pull from a data source instead of your app pushing JSON documents directly.\n\n```js\nimport {\n  AzureKeyCredential,\n  SearchIndexerClient,\n} from \"@azure/search-documents\";\n\nconst indexerClient = new SearchIndexerClient(\n  process.env.AZURE_SEARCH_SERVICE_ENDPOINT,\n  new AzureKeyCredential(process.env.AZURE_SEARCH_API_KEY),\n);\n```\n\nThis client is the right surface for:\n\n- data source connections\n- indexers\n- skillsets\n- synonym maps\n\nIf your task is \"load app-owned JSON records into an existing index\", start with `SearchClient` instead. If your task is \"crawl blob storage, SQL, or Cosmos and enrich content\", use `SearchIndexerClient`.\n\n## Configuration And Compatibility Notes\n\n- Reuse long-lived `SearchClient`, `SearchIndexClient`, and `SearchIndexerClient` instances instead of creating them for every request.\n- Keep the endpoint, keys, and credentials in environment variables or a secret manager, not in source code.\n- Prefer `DefaultAzureCredential` for Azure-hosted workloads instead of client secrets when possible.\n- Pass the service root endpoint, not a portal URL and not an `/indexes/<name>` path.\n- Features like semantic ranking, vector search, and hybrid queries depend on both SDK support and service-side configuration.\n\n## Common Pitfalls\n\n- Using a query key for uploads or index creation.\n- Passing the wrong endpoint; the client expects `https://<service-name>.search.windows.net`.\n- Assuming `uploadDocuments()` is a partial update; it replaces an existing document with the same key.\n- Forgetting to inspect per-document indexing results in bulk operations.\n- Expecting `mergeDocuments()` to create a missing document.\n- Calling `suggest()` or `autocomplete()` without defining a suggester in the index.\n\n## Version Notes For `12.2.0`\n\n- This guide targets `@azure/search-documents` `12.2.0`.\n- When you copy older JavaScript samples, rewrite them to the current `@azure/search-documents` client surface instead of legacy package families.\n- Client methods can expose features that still depend on your Azure AI Search service tier, API support, and index configuration.\n\n## Official Sources Used\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/search-documents-readme?view=azure-node-latest`\n- Microsoft Learn API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/search-documents/`\n- `SearchClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/search-documents/searchclient?view=azure-node-latest`\n- `SearchIndexClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/search-documents/searchindexclient?view=azure-node-latest`\n- `SearchIndexerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/search-documents/searchindexerclient?view=azure-node-latest`\n- `DefaultAzureCredential` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest`\n- Azure AI Search product docs: `https://learn.microsoft.com/en-us/azure/search/`\n- npm package page: `https://www.npmjs.com/package/@azure/search-documents`\n"
  },
  {
    "path": "content/azure/docs/search-documents/python/DOC.md",
    "content": "---\nname: search-documents\ndescription: \"Azure AI Search Python SDK for index schema, document indexing, querying, authentication, and stable 11.6.0 usage notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"11.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-ai-search,search,indexing,query,rbac,python\"\n---\n\n# azure-search-documents Python Package Guide\n\n## What This Package Is\n\n`azure-search-documents` is the official Azure SDK package for Azure AI Search data-plane work in Python.\n\nUse it when your code needs to:\n\n- create and manage search indexes\n- upload, merge, delete, and fetch indexed documents\n- run keyword, filtered, semantic, vector, and hybrid searches against an existing index\n- manage indexers, data sources, synonym maps, and skillsets\n\nPrimary client types:\n\n- `SearchClient`: query and mutate documents in one existing index\n- `SearchIndexClient`: create, update, list, and delete indexes and related schema objects\n- `SearchIndexerClient`: manage pull-based indexing resources such as data sources, skillsets, and indexers\n\nPackage and import path differ:\n\n- PyPI package: `azure-search-documents`\n- Python namespace: `azure.search.documents`\n\nThis guide is scoped to package version `11.6.0` on PyPI.\n\n## Golden Rules\n\n- Use the service endpoint root, not an index URL: `https://<service-name>.search.windows.net`\n- Use a query key only for read-only client-side queries; use an admin key or RBAC for writes and schema changes\n- `upload_documents()` replaces the stored document when the key already exists\n- `merge_documents()` only updates named fields and fails if the document does not already exist\n- `merge_or_upload_documents()` is the safest default for idempotent sync jobs\n- Search document keys are case-sensitive, must be unique, and must be a top-level string field in the index\n- Many Learn quickstarts now show prerelease or preview-oriented examples; verify that a sample matches stable `11.6.0` before copying it\n\n## Install\n\nPython `3.8+` is required upstream.\n\n```bash\npython -m pip install \"azure-search-documents==11.6.0\"\n```\n\nFor Microsoft Entra ID authentication:\n\n```bash\npython -m pip install \"azure-search-documents==11.6.0\" azure-identity\n```\n\nFor async clients:\n\n```bash\npython -m pip install \"azure-search-documents==11.6.0\" aiohttp\n```\n\n## Service Setup And Environment\n\nTypical environment variables:\n\n```bash\nexport AZURE_SEARCH_SERVICE_ENDPOINT=\"https://<service-name>.search.windows.net\"\nexport AZURE_SEARCH_INDEX_NAME=\"hotels\"\nexport AZURE_SEARCH_API_KEY=\"<admin-or-query-key>\"\n```\n\nFor service principal authentication, `DefaultAzureCredential` also uses the standard Azure Identity variables:\n\n```bash\nexport AZURE_TENANT_ID=\"<tenant-id>\"\nexport AZURE_CLIENT_ID=\"<client-id>\"\nexport AZURE_CLIENT_SECRET=\"<client-secret>\"\n```\n\nDocs and samples use both `SEARCH_*` and `AZURE_SEARCH_*` environment variable names. Pick one convention in your codebase and keep it consistent.\n\n## Authentication\n\n### API Key\n\nUse API keys when you want the simplest bootstrap path.\n\n- query key: read-only queries from client apps\n- admin key: index creation, document writes, indexer management, and other mutations\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.search.documents import SearchClient\n\nclient = SearchClient(\n    endpoint=os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"],\n    index_name=os.environ[\"AZURE_SEARCH_INDEX_NAME\"],\n    credential=AzureKeyCredential(os.environ[\"AZURE_SEARCH_API_KEY\"]),\n)\n```\n\n### Microsoft Entra ID\n\nUse `DefaultAzureCredential` for local development, managed identity, or service principals.\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential\nfrom azure.search.documents import SearchClient\n\nclient = SearchClient(\n    endpoint=os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"],\n    index_name=os.environ[\"AZURE_SEARCH_INDEX_NAME\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\nRole mapping that matters in practice:\n\n- query only: `Search Index Data Reader`\n- document uploads and updates: `Search Index Data Contributor`\n- schema and index management: `Search Service Contributor`\n- end-to-end quickstart flows that create, load, and query often need all three roles on the same principal\n\nFor local development, `az login` is usually enough for `DefaultAzureCredential`.\n\n### National Clouds\n\nFor sovereign clouds, set the Azure Identity authority host and pass `audience=` to the client.\n\n```python\nimport os\nfrom azure.identity import AzureAuthorityHosts, DefaultAzureCredential\nfrom azure.search.documents import SearchClient\n\ncredential = DefaultAzureCredential(authority=AzureAuthorityHosts.AZURE_CHINA)\n\nclient = SearchClient(\n    endpoint=os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"],\n    index_name=os.environ[\"AZURE_SEARCH_INDEX_NAME\"],\n    credential=credential,\n    audience=\"https://search.azure.cn\",\n)\n```\n\n## Core Index Setup\n\nThis is the minimum useful schema flow for agents: define fields, create an index, then reuse `SearchClient` for writes and queries.\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.search.documents.indexes import SearchIndexClient\nfrom azure.search.documents.indexes.models import (\n    SearchFieldDataType,\n    SearchIndex,\n    SearchableField,\n    SimpleField,\n)\n\nendpoint = os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"]\ncredential = AzureKeyCredential(os.environ[\"AZURE_SEARCH_API_KEY\"])\nindex_name = \"hotels\"\n\nindex_client = SearchIndexClient(endpoint=endpoint, credential=credential)\n\nfields = [\n    SimpleField(name=\"hotelId\", type=SearchFieldDataType.String, key=True),\n    SearchableField(name=\"hotelName\", type=SearchFieldDataType.String),\n    SearchableField(name=\"description\", type=SearchFieldDataType.String),\n    SimpleField(name=\"rating\", type=SearchFieldDataType.Double, filterable=True, sortable=True),\n]\n\nindex = SearchIndex(name=index_name, fields=fields)\nindex_client.create_index(index)\n```\n\nNotes:\n\n- the key field must be a top-level string field\n- field names are part of your query contract; keep them stable once clients depend on them\n- if you rerun setup against an existing index name, you need an explicit update or replacement path instead of another `create_index()` call\n\n## Upload, Merge, And Delete Documents\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.search.documents import SearchClient\n\nendpoint = os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"]\nindex_name = os.environ[\"AZURE_SEARCH_INDEX_NAME\"]\n\nsearch_client = SearchClient(\n    endpoint=endpoint,\n    index_name=index_name,\n    credential=AzureKeyCredential(os.environ[\"AZURE_SEARCH_API_KEY\"]),\n)\n\ndocuments = [\n    {\n        \"hotelId\": \"1\",\n        \"hotelName\": \"Secret Point Motel\",\n        \"description\": \"Near the airport with a restaurant\",\n        \"rating\": 4.2,\n    },\n    {\n        \"hotelId\": \"2\",\n        \"hotelName\": \"Twin Dome Motel\",\n        \"description\": \"Walkable to downtown shops\",\n        \"rating\": 3.9,\n    },\n]\n\nresults = search_client.upload_documents(documents=documents)\nfor item in results:\n    print(item.key, item.succeeded)\n```\n\nUpdate one existing document without replacing the whole payload:\n\n```python\nupdate_results = search_client.merge_documents(\n    documents=[\n        {\n            \"hotelId\": \"1\",\n            \"rating\": 4.5,\n        }\n    ]\n)\n```\n\nSafer upsert pattern for sync jobs:\n\n```python\nupsert_results = search_client.merge_or_upload_documents(\n    documents=[\n        {\n            \"hotelId\": \"3\",\n            \"hotelName\": \"City Lights Hotel\",\n            \"description\": \"Late check-in and strong Wi-Fi\",\n            \"rating\": 4.7,\n        }\n    ]\n)\n```\n\nDelete is keyed by the document key. Other fields are ignored.\n\n```python\ndelete_results = search_client.delete_documents(\n    documents=[{\"hotelId\": \"2\"}]\n)\n```\n\nBehavior to remember:\n\n- `upload_documents()` inserts or fully replaces the document with that key\n- `merge_documents()` updates only named fields, but requires the document to exist\n- `merge_or_upload_documents()` acts like merge if the key exists and upload if it does not\n- `delete_documents()` is idempotent and ignores non-key fields in the delete payload\n\n## Query Documents\n\n```python\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.search.documents import SearchClient\n\nendpoint = os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"]\nindex_name = os.environ[\"AZURE_SEARCH_INDEX_NAME\"]\n\nclient = SearchClient(\n    endpoint=endpoint,\n    index_name=index_name,\n    credential=AzureKeyCredential(os.environ[\"AZURE_SEARCH_API_KEY\"]),\n)\n\nresults = client.search(\n    search_text=\"restaurant\",\n    filter=\"rating ge 4\",\n    select=[\"hotelId\", \"hotelName\", \"rating\"],\n    top=5,\n)\n\nfor doc in results:\n    print(doc[\"hotelId\"], doc[\"hotelName\"], doc[\"rating\"])\n```\n\nUseful search patterns:\n\n- `search_text=\"*\"` returns a match-all result set\n- `filter=` uses OData-style filter syntax on filterable fields\n- `select=` reduces payload size and latency\n- `search_fields=` limits which searchable fields are queried\n- `get_document(key=...)` is the direct lookup path when you already know the key\n- `autocomplete()` and `suggest()` require suggester-aware index configuration\n\nThe `search()` signature in current docs includes optional parameters for semantic answers/captions and `vector_queries`. That surface exists in stable `11.6.0`, but whether a given query actually works depends on your service configuration and supported Search API features.\n\n## Async Usage\n\nThe package ships an async API under `.aio`.\n\n```python\nimport asyncio\nimport os\nfrom azure.core.credentials import AzureKeyCredential\nfrom azure.search.documents.aio import SearchClient\n\nasync def main() -> None:\n    client = SearchClient(\n        endpoint=os.environ[\"AZURE_SEARCH_SERVICE_ENDPOINT\"],\n        index_name=os.environ[\"AZURE_SEARCH_INDEX_NAME\"],\n        credential=AzureKeyCredential(os.environ[\"AZURE_SEARCH_API_KEY\"]),\n    )\n\n    async with client:\n        results = await client.search(search_text=\"spa\")\n        async for doc in results:\n            print(doc[\"hotelName\"])\n\nasyncio.run(main())\n```\n\nIf async imports work but requests fail immediately, the usual cause is missing `aiohttp`.\n\n## SearchIndexerClient When You Need Pull-Based Ingestion\n\nUse `SearchIndexerClient` when Azure AI Search should pull from a data source instead of your app pushing JSON documents directly.\n\nThis client is the right surface for:\n\n- data source connections\n- indexers\n- skillsets\n- synonym maps\n\nIf your task is \"load app-owned JSON records into an existing index\", start with `SearchClient` instead. If your task is \"crawl blob storage / SQL / Cosmos and enrich content\", reach for `SearchIndexerClient`.\n\n## Version-Sensitive Notes For `11.6.0`\n\n- `11.6.0` is the current stable PyPI release in the official registry entry.\n- Microsoft Learn quickstarts can point to prerelease package pins such as `11.6.0b1` even when the current stable package is newer. Treat those tutorials as product guidance, but check whether they use preview-only SDK shapes before copying code into a project pinned to stable `11.6.0`.\n- Microsoft Learn search results also expose preview namespaces such as `azure.search.documents.knowledgebases.*`. Do not assume those preview surfaces are safe defaults for stable production code.\n- The SDK documentation still warns about confusion with the retired `Microsoft.Azure.Search` v10 client library. Ignore old blog posts or samples that use the retired namespace.\n- Client constructors expose `api_version=` and, for Entra ID scenarios, `audience=`. Only override these when the feature you need is documented for the target service API version or cloud.\n- Features like semantic ranking, vector search, and hybrid queries depend on both SDK support and service-side configuration. The method parameters being present in Python does not mean your index or service is already configured for them.\n\n## Common Pitfalls\n\n- Mixing package names and import paths: install `azure-search-documents`, import `azure.search.documents`\n- Using a query key for uploads or index creation: it will fail with authorization errors\n- Using the wrong endpoint: pass the service root, not `/indexes/<name>` or a portal URL\n- Assuming `upload_documents()` is partial update: it is full replacement for an existing key\n- Forgetting to check per-document indexing results in bulk operations\n- Copying preview examples from Learn without checking whether they rely on prerelease packages or preview service features\n- Forgetting that document keys are case-sensitive\n\n## Official URLs\n\n- Docs root: https://learn.microsoft.com/en-us/python/api/azure-search-documents/\n- PyPI package: https://pypi.org/project/azure-search-documents/\n- Azure SDK README: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/search/azure-search-documents\n- Product docs: https://learn.microsoft.com/en-us/azure/search/\n"
  },
  {
    "path": "content/azure/docs/service-bus/javascript/DOC.md",
    "content": "---\nname: service-bus\ndescription: \"Azure Service Bus JavaScript client for authenticating to a namespace, publishing messages, receiving from subscriptions, and settling deliveries\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.9.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,service-bus,messaging,amqp,javascript,topics,subscriptions,entra-id\"\n---\n\n# Azure Service Bus JavaScript Client\n\n## Golden Rule\n\nUse `@azure/service-bus` with `ServiceBusClient`, prefer `DefaultAzureCredential` for deployed applications, and build new code around `createSender(...)`, `createReceiver(...)`, and explicit settlement methods instead of older pre-7.x client types.\n\n## Install\n\nPin the version your project expects:\n\n```bash\nnpm install @azure/service-bus@7.9.5\n```\n\nIf you authenticate with Microsoft Entra ID, install `@azure/identity` too:\n\n```bash\nnpm install @azure/service-bus@7.9.5 @azure/identity\n```\n\n## Authentication And Setup\n\nThe client supports both connection strings and token credentials.\n\nRecommended environment variables:\n\n```bash\nexport SERVICEBUS_CONNECTION_STRING=\"Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=...;SharedAccessKey=...\"\nexport SERVICEBUS_FULLY_QUALIFIED_NAMESPACE=\"<namespace>.servicebus.windows.net\"\nexport SERVICEBUS_TOPIC_NAME=\"events\"\nexport SERVICEBUS_SUBSCRIPTION_NAME=\"worker-a\"\n```\n\n### Preferred: `DefaultAzureCredential`\n\nUse passwordless auth in production, CI, and Azure-hosted workloads:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nconst fullyQualifiedNamespace = process.env.SERVICEBUS_FULLY_QUALIFIED_NAMESPACE;\n\nif (!fullyQualifiedNamespace) {\n  throw new Error(\"SERVICEBUS_FULLY_QUALIFIED_NAMESPACE is required\");\n}\n\nconst credential = new DefaultAzureCredential();\nconst client = new ServiceBusClient(fullyQualifiedNamespace, credential);\n```\n\nThe identity needs a Service Bus data-plane role such as `Azure Service Bus Data Sender`, `Azure Service Bus Data Receiver`, or `Azure Service Bus Data Owner` depending on what the code does.\n\n### Connection string fallback\n\nConnection strings are still the simplest option for local scripts and tightly scoped automation:\n\n```js\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nconst connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\n\nif (!connectionString) {\n  throw new Error(\"SERVICEBUS_CONNECTION_STRING is required\");\n}\n\nconst client = new ServiceBusClient(connectionString);\n```\n\n## Client Initialization\n\nCreate one shared client for the part of your app that talks to Service Bus:\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nexport function createServiceBusClient() {\n  const connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\n\n  if (connectionString) {\n    return new ServiceBusClient(connectionString);\n  }\n\n  const fullyQualifiedNamespace = process.env.SERVICEBUS_FULLY_QUALIFIED_NAMESPACE;\n\n  if (!fullyQualifiedNamespace) {\n    throw new Error(\n      \"Set SERVICEBUS_CONNECTION_STRING or SERVICEBUS_FULLY_QUALIFIED_NAMESPACE\",\n    );\n  }\n\n  return new ServiceBusClient(\n    fullyQualifiedNamespace,\n    new DefaultAzureCredential(),\n  );\n}\n```\n\n## Core Usage\n\n### Publish to a topic\n\nUse `createSender(...)` and `sendMessages(...)` for application publishing:\n\n```js\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nconst connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\nconst topicName = process.env.SERVICEBUS_TOPIC_NAME;\n\nif (!connectionString || !topicName) {\n  throw new Error(\"SERVICEBUS_CONNECTION_STRING and SERVICEBUS_TOPIC_NAME are required\");\n}\n\nconst client = new ServiceBusClient(connectionString);\nconst sender = client.createSender(topicName);\n\ntry {\n  await sender.sendMessages({\n    body: {\n      type: \"inventory.updated\",\n      sku: \"sku-1001\",\n      quantity: 4,\n    },\n    subject: \"inventory.updated\",\n    applicationProperties: {\n      source: \"catalog-service\",\n      tenant: \"acme\",\n    },\n  });\n} finally {\n  await sender.close();\n  await client.close();\n}\n```\n\n### Receive from a subscription and settle messages\n\nThe default receive mode is `peekLock`, which is the normal choice for worker-style processing because your code explicitly settles each delivery.\n\n```js\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nconst connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\nconst topicName = process.env.SERVICEBUS_TOPIC_NAME;\nconst subscriptionName = process.env.SERVICEBUS_SUBSCRIPTION_NAME;\n\nif (!connectionString || !topicName || !subscriptionName) {\n  throw new Error(\n    \"SERVICEBUS_CONNECTION_STRING, SERVICEBUS_TOPIC_NAME, and SERVICEBUS_SUBSCRIPTION_NAME are required\",\n  );\n}\n\nconst client = new ServiceBusClient(connectionString);\nconst receiver = client.createReceiver(topicName, subscriptionName);\n\ntry {\n  const messages = await receiver.receiveMessages(10, {\n    maxWaitTimeInMs: 5000,\n  });\n\n  for (const message of messages) {\n    try {\n      console.log(message.messageId, message.deliveryCount, message.body);\n      await receiver.completeMessage(message);\n    } catch (error) {\n      await receiver.abandonMessage(message);\n      throw error;\n    }\n  }\n} finally {\n  await receiver.close();\n  await client.close();\n}\n```\n\nSettlement methods you will use most often:\n\n- `completeMessage(message)`: remove the message after successful processing\n- `abandonMessage(message)`: unlock it for another delivery attempt\n- `deadLetterMessage(message, options?)`: move it aside for later triage\n- `deferMessage(message)`: keep it for later retrieval by sequence number\n\n### Run a long-lived receive loop\n\nUse `subscribe(...)` when you want a push-style handler instead of explicit polling:\n\n```js\nimport { ServiceBusClient } from \"@azure/service-bus\";\n\nconst connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\nconst topicName = process.env.SERVICEBUS_TOPIC_NAME;\nconst subscriptionName = process.env.SERVICEBUS_SUBSCRIPTION_NAME;\n\nif (!connectionString || !topicName || !subscriptionName) {\n  throw new Error(\n    \"SERVICEBUS_CONNECTION_STRING, SERVICEBUS_TOPIC_NAME, and SERVICEBUS_SUBSCRIPTION_NAME are required\",\n  );\n}\n\nconst client = new ServiceBusClient(connectionString);\nconst receiver = client.createReceiver(topicName, subscriptionName);\n\nconst subscription = receiver.subscribe(\n  {\n    async processMessage(message) {\n      console.log(\"received\", message.messageId, message.body);\n      await receiver.completeMessage(message);\n    },\n    async processError(args) {\n      console.error(args.error);\n    },\n  },\n  {\n    autoCompleteMessages: false,\n    maxConcurrentCalls: 4,\n    maxAutoLockRenewalDurationInMs: 5 * 60 * 1000,\n  },\n);\n\nprocess.on(\"SIGINT\", async () => {\n  await subscription.close();\n  await receiver.close();\n  await client.close();\n  process.exit(0);\n});\n```\n\n## Administration\n\nUse `ServiceBusAdministrationClient` when your code needs to inspect or manage entities inside an existing namespace:\n\n```js\nimport { ServiceBusAdministrationClient } from \"@azure/service-bus\";\n\nconst connectionString = process.env.SERVICEBUS_CONNECTION_STRING;\nconst topicName = process.env.SERVICEBUS_TOPIC_NAME;\nconst subscriptionName = process.env.SERVICEBUS_SUBSCRIPTION_NAME;\n\nif (!connectionString || !topicName || !subscriptionName) {\n  throw new Error(\n    \"SERVICEBUS_CONNECTION_STRING, SERVICEBUS_TOPIC_NAME, and SERVICEBUS_SUBSCRIPTION_NAME are required\",\n  );\n}\n\nconst admin = new ServiceBusAdministrationClient(connectionString);\n\nconst topic = await admin.getTopic(topicName);\nconst subscription = await admin.getSubscription(topicName, subscriptionName);\n\nconsole.log(topic);\nconsole.log(subscription);\n```\n\nUse Azure Resource Manager tools such as the Azure CLI, ARM/Bicep/Terraform, or the portal when you need namespace-level provisioning rather than topic or subscription administration inside a namespace.\n\n## Configuration Notes\n\n- The namespace value must be the fully qualified host name, for example `<namespace>.servicebus.windows.net`.\n- Reuse long-lived `ServiceBusClient`, sender, and receiver instances instead of creating them per message.\n- Close `ServiceBusClient`, senders, and receivers during shutdown so AMQP links are released cleanly.\n- Prefer `receiveMessages(...)` for explicit pull loops and `subscribe(...)` for long-running worker processes.\n- Keep connection strings and credentials in environment variables or a secret manager, not in source code.\n\n## Common Pitfalls\n\n- Copying older samples that use deprecated client types instead of `ServiceBusClient`.\n- Treating `401` or `403` responses as SDK bugs before checking credentials and Service Bus RBAC assignments.\n- Passing only the namespace name when the constructor expects the fully qualified host name.\n- Forgetting to call `completeMessage(...)`, `abandonMessage(...)`, `deadLetterMessage(...)`, or `deferMessage(...)` when you disable auto-complete.\n- Creating a new sender, receiver, or client for every operation instead of reusing them.\n- Using `receiveAndDelete` for normal worker code when message loss would be unacceptable.\n\n## Version Notes For `7.9.5`\n\n- This guide targets `@azure/service-bus` `7.9.5`.\n- Prefer `ServiceBusClient` and `ServiceBusAdministrationClient` for new code.\n- If you find pre-7.x samples using legacy client types, rewrite them to the current constructor and settlement APIs instead of porting them line-for-line.\n"
  },
  {
    "path": "content/azure/docs/servicebus/python/DOC.md",
    "content": "---\nname: servicebus\ndescription: \"Azure Service Bus Python client library for queues, topics, subscriptions, sessions, and message settlement\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.14.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,service-bus,messaging,amqp,queues,topics,subscriptions,sessions\"\n---\n\n# Azure Service Bus Python Client Library\n\n## Golden Rule\n\nUse `azure-servicebus` with `ServiceBusClient` or `azure.servicebus.aio`, prefer `DefaultAzureCredential` for production auth, and do not copy pre-7.x examples that use `QueueClient`, `TopicClient`, or the old `Message` API. The current SDK line is `7.14.3`, and PyPI now requires Python `>=3.9`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"azure-servicebus==7.14.3\"\n```\n\nCommon companions:\n\n```bash\npython -m pip install \"azure-identity>=1.17.0\"\npython -m pip install \"aiohttp>=3.9.0\"\n```\n\nNotes:\n\n- Install `azure-identity` when you want Microsoft Entra ID auth via `DefaultAzureCredential`.\n- Install `aiohttp` for the async client path under `azure.servicebus.aio`.\n- Do not build new code around `uamqp_transport`; the Azure SDK changelog marks it deprecated in `7.14.2`.\n\n## Authentication And Setup\n\nThe SDK supports both connection strings and token credentials.\n\nRecommended environment variables:\n\n```bash\nexport SERVICEBUS_CONNECTION_STRING=\"Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=...\"\nexport SERVICEBUS_FULLY_QUALIFIED_NAMESPACE=\"<namespace>.servicebus.windows.net\"\nexport SERVICEBUS_QUEUE_NAME=\"orders\"\nexport SERVICEBUS_TOPIC_NAME=\"events\"\nexport SERVICEBUS_SUBSCRIPTION_NAME=\"worker-a\"\n```\n\n### Preferred: `DefaultAzureCredential`\n\nUse passwordless auth in production, CI, and Azure-hosted workloads:\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.servicebus import ServiceBusClient\n\ncredential = DefaultAzureCredential()\n\nclient = ServiceBusClient(\n    fully_qualified_namespace=os.environ[\"SERVICEBUS_FULLY_QUALIFIED_NAMESPACE\"],\n    credential=credential,\n)\n```\n\nThe identity needs a Service Bus data-plane role such as `Azure Service Bus Data Owner`, `Azure Service Bus Data Sender`, or `Azure Service Bus Data Receiver` depending on what the code does.\n\n### Connection string fallback\n\nConnection strings are still the simplest option for local scripts and quick tests:\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusClient\n\nclient = ServiceBusClient.from_connection_string(\n    conn_str=os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n)\n```\n\n## Core Usage\n\n### Send to a queue\n\nBatch sends are the safest default when you may emit more than one message:\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusClient, ServiceBusMessage\n\nqueue_name = os.environ[\"SERVICEBUS_QUEUE_NAME\"]\n\nwith ServiceBusClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n) as client:\n    with client.get_queue_sender(queue_name=queue_name) as sender:\n        batch = sender.create_message_batch()\n        has_messages = False\n\n        for body in (\"order-1001\", \"order-1002\", \"order-1003\"):\n            try:\n                batch.add_message(ServiceBusMessage(body))\n                has_messages = True\n            except ValueError:\n                sender.send_messages(batch)\n                batch = sender.create_message_batch()\n                batch.add_message(ServiceBusMessage(body))\n                has_messages = True\n\n        if has_messages:\n            sender.send_messages(batch)\n```\n\n`add_message()` raises `ValueError` when the next message would overflow the current AMQP batch.\n\n### Receive and settle from a queue\n\nThe default receive mode is `PEEK_LOCK`, which is what you usually want for workers:\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusClient\n\nqueue_name = os.environ[\"SERVICEBUS_QUEUE_NAME\"]\n\nwith ServiceBusClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n) as client:\n    with client.get_queue_receiver(queue_name=queue_name, max_wait_time=5) as receiver:\n        for message in receiver.receive_messages(max_message_count=10, max_wait_time=5):\n            try:\n                print(message.message_id, message.delivery_count)\n                receiver.complete_message(message)\n            except Exception:\n                receiver.abandon_message(message)\n                raise\n```\n\nSettlement methods you will use most often:\n\n- `complete_message(message)`: remove the message after successful processing\n- `abandon_message(message)`: unlock it for another delivery attempt\n- `dead_letter_message(message, reason=..., error_description=...)`: move it to the dead-letter subqueue\n- `defer_message(message)`: keep it for later retrieval by sequence number\n\n### Topic and subscription flow\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusClient, ServiceBusMessage\n\ntopic_name = os.environ[\"SERVICEBUS_TOPIC_NAME\"]\nsubscription_name = os.environ[\"SERVICEBUS_SUBSCRIPTION_NAME\"]\n\nwith ServiceBusClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n) as client:\n    with client.get_topic_sender(topic_name=topic_name) as sender:\n        sender.send_messages(ServiceBusMessage(\"inventory.updated\"))\n\n    with client.get_subscription_receiver(\n        topic_name=topic_name,\n        subscription_name=subscription_name,\n        max_wait_time=5,\n    ) as receiver:\n        messages = receiver.receive_messages(max_message_count=10, max_wait_time=5)\n        for message in messages:\n            receiver.complete_message(message)\n```\n\n### Dead-letter reads\n\nUse the dead-letter subqueue explicitly when triaging failures:\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusSubQueue\nfrom azure.servicebus import ServiceBusClient\n\nwith ServiceBusClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n) as client:\n    with client.get_queue_receiver(\n        queue_name=os.environ[\"SERVICEBUS_QUEUE_NAME\"],\n        sub_queue=ServiceBusSubQueue.DEAD_LETTER,\n    ) as receiver:\n        messages = receiver.receive_messages(max_message_count=10, max_wait_time=5)\n        for message in messages:\n            print(message.message_id)\n```\n\n### Sessions\n\nIf the entity requires sessions, each sent message needs a `session_id`, and receivers connect to a specific session or ask for the next available one:\n\n```python\nimport os\n\nfrom azure.servicebus import ServiceBusClient, ServiceBusMessage\n\nqueue_name = os.environ[\"SERVICEBUS_QUEUE_NAME\"]\n\nwith ServiceBusClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n) as client:\n    with client.get_queue_sender(queue_name=queue_name) as sender:\n        sender.send_messages(\n            ServiceBusMessage(\"step-1\", session_id=\"customer-42\")\n        )\n\n    with client.get_queue_receiver(\n        queue_name=queue_name,\n        session_id=\"customer-42\",\n        max_wait_time=5,\n    ) as receiver:\n        messages = receiver.receive_messages(max_message_count=1, max_wait_time=5)\n        for message in messages:\n            receiver.complete_message(message)\n```\n\nSession-enabled entities use a session lock rather than separate per-message locks. Renew the session lock for long-running work instead of assuming the default lock duration is enough.\n\n### Async API\n\nUse `azure.servicebus.aio` for async senders and receivers, and close both the Service Bus client and Azure Identity credential:\n\n```python\nimport os\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.servicebus import ServiceBusMessage\nfrom azure.servicebus.aio import ServiceBusClient\n\nasync def main() -> None:\n    credential = DefaultAzureCredential()\n    queue_name = os.environ[\"SERVICEBUS_QUEUE_NAME\"]\n\n    try:\n        async with ServiceBusClient(\n            fully_qualified_namespace=os.environ[\"SERVICEBUS_FULLY_QUALIFIED_NAMESPACE\"],\n            credential=credential,\n        ) as client:\n            sender = client.get_queue_sender(queue_name=queue_name)\n            async with sender:\n                await sender.send_messages(ServiceBusMessage(\"hello from aio\"))\n    finally:\n        await credential.close()\n```\n\n## Administration\n\nUse `ServiceBusAdministrationClient` for entity administration inside an existing namespace:\n\n```python\nimport os\n\nfrom azure.servicebus.management import ServiceBusAdministrationClient\n\nadmin = ServiceBusAdministrationClient.from_connection_string(\n    os.environ[\"SERVICEBUS_CONNECTION_STRING\"]\n)\n\nqueue = admin.get_queue(queue_name=os.environ[\"SERVICEBUS_QUEUE_NAME\"])\nprint(queue.max_delivery_count)\n```\n\nUse Azure Resource Manager tools such as `azure-mgmt-servicebus`, the Azure CLI, or the portal when you need namespace-level provisioning rather than queue or subscription administration inside a namespace.\n\n## Configuration Notes\n\n- The namespace must be the fully qualified host name, for example `my-namespace.servicebus.windows.net`.\n- If outbound AMQP on port `5671` is blocked, set `transport_type=TransportType.AmqpOverWebsocket` and use WebSockets over `443`.\n- `prefetch_count` can improve throughput, but it increases the number of messages held client-side under lock.\n- Long-running handlers should use `AutoLockRenewer` or explicit lock-renewal methods so locks do not expire before settlement.\n- `client_identifier` is useful when you need clearer broker-side diagnostics in Service Bus errors.\n- Retry and socket behavior are configurable on the client, sender, and receiver; tune them when running through proxies, high-latency links, or flaky networks.\n\n## Common Pitfalls\n\n- Do not copy old `azure-servicebus` `0.50.x` or `1.0.0` samples. Modern code uses `ServiceBusClient`, entity-specific senders and receivers, and explicit settlement methods.\n- The clients are not thread-safe or coroutine-safe. Do not share a sender, receiver, or client instance across concurrent threads or tasks without your own synchronization.\n- `RECEIVE_AND_DELETE` is lossy if the process crashes after the broker hands out a message. Use `PEEK_LOCK` for normal workers.\n- The docs warn that combining `RECEIVE_AND_DELETE` with prefetch can lose prefetched messages if the process exits before processing them.\n- Messages and session locks expire. If processing can run longer than the lock duration, renew the lock or use `AutoLockRenewer`.\n- `peek_messages()` does not lock messages and those peeked messages cannot be settled.\n- Async code needs `azure.servicebus.aio` plus an async transport like `aiohttp`; remember to close the credential.\n- Service Bus emulator support does not cover `ServiceBusAdministrationClient`.\n\n## Version-Sensitive Notes For 7.14.x\n\n- PyPI shows `7.14.3` as the latest published package on March 12, 2026. The Azure SDK repo changelog on the `main` branch still labels `7.14.3` as unreleased, so prefer PyPI and Learn when you need release-state confirmation.\n- `7.14.2` removed Python `3.8` support and deprecated `uamqp_transport`. Keep new code on Python `3.9+` and avoid transport settings that depend on the deprecated path.\n- `7.14.0` added Azure Service Bus emulator support, but the changelog notes that `ServiceBusAdministrationClient` is not supported against the emulator.\n- The migration guide confirms the 7.x API shift away from legacy client types and settlement patterns. When updating older code, map those concepts explicitly instead of trying to port line-for-line.\n"
  },
  {
    "path": "content/azure/docs/storage-blob/javascript/DOC.md",
    "content": "---\nname: storage-blob\ndescription: \"Azure Blob Storage JavaScript client for authentication, container and blob clients, uploads, downloads, and listing workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.31.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,storage,blob,blob-storage,javascript,nodejs,azure-storage,entra-id\"\n---\n\n# Azure Blob Storage JavaScript Client\n\n## Golden Rule\n\nUse `@azure/storage-blob` for Azure Blob Storage and stay on the current 12.x client surface:\n\n- `BlobServiceClient` for account-level operations\n- `ContainerClient` for one container\n- `BlobClient` or `BlockBlobClient` for one blob\n- `@azure/identity` plus `DefaultAzureCredential` when you want Microsoft Entra ID authentication\n\nDo not copy legacy examples built on the old `azure-storage` package or `createBlobService(...)` API shape.\n\n## Install\n\nPin the SDK version your application expects:\n\n```bash\nnpm install @azure/storage-blob@12.31.0\n```\n\nIf you want Microsoft Entra ID authentication, install `@azure/identity` too:\n\n```bash\nnpm install @azure/storage-blob@12.31.0 @azure/identity\n```\n\n## Prerequisites\n\n- an Azure Storage account or a local Azurite emulator\n- a blob endpoint such as `https://<account>.blob.core.windows.net`\n- a container name for your application data\n- if you use `DefaultAzureCredential`, a local `az login` or another supported developer credential source, or a managed identity in Azure\n- Azure RBAC on the storage account or container\n\nPractical role guidance:\n\n- read-only flows such as listing or downloading need `Storage Blob Data Reader` or higher\n- upload, create, delete, and tag changes need `Storage Blob Data Contributor` or higher\n\nUse environment variables instead of hard-coding credentials:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<account-name>\"\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<account-name>.blob.core.windows.net\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"<connection-string>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\nexport AZURE_STORAGE_CONTAINER=\"documents\"\n```\n\n## Authentication And Setup\n\nThe practical auth choices are:\n\n- Microsoft Entra ID with `DefaultAzureCredential`\n- a storage account connection string\n- a shared account key when you explicitly manage storage keys\n\n### Microsoft Entra ID With `DefaultAzureCredential`\n\nUse this for deployed apps in Azure and for normal local development after a developer sign-in:\n\n```bash\naz login\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<account>.blob.core.windows.net\"\n```\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst accountUrl =\n  process.env.AZURE_STORAGE_ACCOUNT_URL ||\n  `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net`;\n\nif (\n  !process.env.AZURE_STORAGE_ACCOUNT_URL &&\n  !process.env.AZURE_STORAGE_ACCOUNT_NAME\n) {\n  throw new Error(\n    \"AZURE_STORAGE_ACCOUNT_URL or AZURE_STORAGE_ACCOUNT_NAME is required\",\n  );\n}\n\nconst serviceClient = new BlobServiceClient(\n  accountUrl,\n  new DefaultAzureCredential(),\n);\n```\n\nIf a brand-new RBAC assignment fails, wait a few minutes and retry before changing the auth flow. Azure role assignments can take time to propagate.\n\n### Connection String Or Azurite\n\nUse this for local tools, migration scripts, or environments that already provide a storage connection string:\n\n```js\nimport { BlobServiceClient } from \"@azure/storage-blob\";\n\nconst connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;\n\nif (!connectionString) {\n  throw new Error(\"AZURE_STORAGE_CONNECTION_STRING is required\");\n}\n\nconst serviceClient = BlobServiceClient.fromConnectionString(connectionString);\n```\n\nFor local Azurite development, use the documented storage shortcut connection string:\n\n```bash\nexport AZURE_STORAGE_CONNECTION_STRING=\"UseDevelopmentStorage=true\"\nexport AZURE_STORAGE_CONTAINER=\"documents\"\n```\n\n### Shared Key\n\nUse a shared key only when your application explicitly manages storage account keys:\n\n```js\nimport {\n  BlobServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-blob\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\nif (!accountName || !accountKey) {\n  throw new Error(\n    \"AZURE_STORAGE_ACCOUNT_NAME and AZURE_STORAGE_ACCOUNT_KEY are required\",\n  );\n}\n\nconst credential = new StorageSharedKeyCredential(accountName, accountKey);\nconst serviceClient = new BlobServiceClient(\n  `https://${accountName}.blob.core.windows.net`,\n  credential,\n);\n```\n\n## Client Initialization\n\nCreate one `BlobServiceClient` and derive child clients from it. This keeps auth and transport setup in one place.\n\n```js\nimport {\n  BlobServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-blob\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nexport function createBlobServiceClient() {\n  if (process.env.AZURE_STORAGE_CONNECTION_STRING) {\n    return BlobServiceClient.fromConnectionString(\n      process.env.AZURE_STORAGE_CONNECTION_STRING,\n    );\n  }\n\n  const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\n  const accountUrl =\n    process.env.AZURE_STORAGE_ACCOUNT_URL ||\n    `https://${accountName}.blob.core.windows.net`;\n\n  if (!process.env.AZURE_STORAGE_ACCOUNT_URL && !accountName) {\n    throw new Error(\n      \"Set AZURE_STORAGE_CONNECTION_STRING, AZURE_STORAGE_ACCOUNT_URL, or AZURE_STORAGE_ACCOUNT_NAME\",\n    );\n  }\n\n  if (process.env.AZURE_STORAGE_ACCOUNT_KEY) {\n    return new BlobServiceClient(\n      accountUrl,\n      new StorageSharedKeyCredential(\n        accountName,\n        process.env.AZURE_STORAGE_ACCOUNT_KEY,\n      ),\n    );\n  }\n\n  return new BlobServiceClient(accountUrl, new DefaultAzureCredential());\n}\n```\n\nThe normal hierarchy is:\n\n- `BlobServiceClient`: account scope\n- `ContainerClient`: one container\n- `BlobClient`: base blob operations\n- `BlockBlobClient`: upload-heavy block blob workflows\n\n## Core Usage\n\n### Create A Container And Upload A Blob\n\nThe SDK does not auto-create missing containers. Create them before you upload application data.\n\n```js\nimport { createBlobServiceClient } from \"./blobClient.js\";\n\nconst serviceClient = createBlobServiceClient();\nconst containerClient = serviceClient.getContainerClient(\n  process.env.AZURE_STORAGE_CONTAINER ?? \"documents\",\n);\n\nawait containerClient.createIfNotExists();\n\nconst blockBlobClient = containerClient.getBlockBlobClient(\n  \"reports/hello.json\",\n);\n\nconst body = JSON.stringify({\n  ok: true,\n  generatedAt: new Date().toISOString(),\n});\n\nawait blockBlobClient.deleteIfExists();\nawait blockBlobClient.upload(body, Buffer.byteLength(body), {\n  blobHTTPHeaders: {\n    blobContentType: \"application/json\",\n  },\n});\n```\n\nFor Node.js file uploads, `BlockBlobClient` also exposes `uploadFile(...)` and `uploadStream(...)`.\n\n### Download A Blob\n\nIn Node.js, `downloadToBuffer()` is the most direct way to read a smaller blob into memory:\n\n```js\nimport { createBlobServiceClient } from \"./blobClient.js\";\n\nconst serviceClient = createBlobServiceClient();\nconst containerClient = serviceClient.getContainerClient(\n  process.env.AZURE_STORAGE_CONTAINER ?? \"documents\",\n);\nconst blobClient = containerClient.getBlobClient(\"reports/hello.json\");\n\nconst buffer = await blobClient.downloadToBuffer();\nconsole.log(buffer.toString(\"utf8\"));\n```\n\nIf you are building for a browser runtime, use `download()` and the browser response body helpers instead of Node-only buffer helpers.\n\n### List Blobs\n\nFlat listing returns blobs directly. Hierarchical listing adds prefix entries so you can present virtual folders.\n\n```js\nimport { createBlobServiceClient } from \"./blobClient.js\";\n\nconst serviceClient = createBlobServiceClient();\nconst containerClient = serviceClient.getContainerClient(\n  process.env.AZURE_STORAGE_CONTAINER ?? \"documents\",\n);\n\nfor await (const blob of containerClient.listBlobsFlat({\n  prefix: \"reports/\",\n})) {\n  console.log(\"blob\", blob.name);\n}\n\nfor await (const item of containerClient.listBlobsByHierarchy(\"/\", {\n  prefix: \"reports/\",\n})) {\n  if (item.kind === \"prefix\") {\n    console.log(\"dir\", item.name);\n  } else {\n    console.log(\"blob\", item.name);\n  }\n}\n```\n\nBlob Storage is fundamentally flat. Folder-like behavior comes from blob names plus a delimiter such as `/`.\n\n## Practical Notes\n\n- Prefer `DefaultAzureCredential` unless you specifically need a connection string or account key.\n- Keep the account URL explicit in configuration so the app does not drift to the wrong storage account.\n- Reuse one `BlobServiceClient` instead of creating a new client for every request.\n- Create containers up front with `createIfNotExists()` in bootstrap code; normal reads and writes expect the container to exist.\n- Use `BlockBlobClient` for ordinary uploads. Page blobs and append blobs are separate blob types with different clients and semantics.\n- Start with the SDK defaults for retry and transfer behavior unless you have evidence that a workload needs tuning.\n\n## Common Pitfalls\n\n- Installing `@azure/storage-blob` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Treating account-level secrets as application defaults when Microsoft Entra ID would work.\n- Assuming containers are created automatically.\n- Assuming Blob Storage has real directories. It does not; hierarchy comes from naming conventions.\n- Using Node-only helpers such as `uploadFile()` or `downloadToBuffer()` in browser code.\n- Copying old `azure-storage` examples into a 12.x app.\n- Writing to the same blob from multiple processes at the same time without a coordination strategy.\n\n## Version Notes For 12.31.0\n\n- This guide targets `@azure/storage-blob` `12.31.0`.\n- `@azure/identity` is versioned separately; pin it according to your application's Azure SDK policy.\n- If you copy older Azure Storage samples that use the legacy `azure-storage` package, rewrite them for `BlobServiceClient`, `ContainerClient`, and `BlobClient` before using them with this version.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-blob/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/storage-blob-readme?view=azure-node-latest`\n- `BlobServiceClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-blob/blobserviceclient?view=azure-node-latest`\n- `ContainerClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-blob/containerclient?view=azure-node-latest`\n- `BlockBlobClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-blob/blockblobclient?view=azure-node-latest`\n- Node.js quickstart: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-nodejs`\n- Upload guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-upload-javascript`\n- Download guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-download-javascript`\n- List guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-list-javascript`\n- Azure SDK changelog: `https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/CHANGELOG.md`\n- npm package page: `https://www.npmjs.com/package/@azure/storage-blob`\n"
  },
  {
    "path": "content/azure/docs/storage-blob/python/DOC.md",
    "content": "---\nname: storage-blob\ndescription: \"Azure Blob Storage Python SDK guide for authentication, clients, transfers, listing, and 12.28.0 version-sensitive behavior\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.28.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,blob-storage,azure-storage,python,cloud,storage\"\n---\n\n# Azure Blob Storage Python SDK\n\n## Golden Rule\n\nUse `azure-storage-blob` for blob operations and pair it with `azure-identity` plus `DefaultAzureCredential` for real Azure environments. For version `12.28.0`, follow the package overview and PyPI metadata for runtime requirements: Python `>=3.9`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"azure-storage-blob==12.28.0\" azure-identity\n```\n\nFor async usage, add an async transport:\n\n```bash\npython -m pip install \"azure-storage-blob==12.28.0\" azure-identity aiohttp\n```\n\nCommon environment variables:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<account>.blob.core.windows.net\"\nexport AZURE_STORAGE_CONTAINER=\"documents\"\n```\n\nUse `AZURE_STORAGE_CONNECTION_STRING` instead of `AZURE_STORAGE_ACCOUNT_URL` when you are developing against Azurite or using connection-string auth.\n\n## Authentication And Setup\n\n### Preferred: Microsoft Entra ID with `DefaultAzureCredential`\n\nThis is the official recommended path for Azure-hosted apps and normal local development.\n\nLocal setup:\n\n1. Install `azure-identity`.\n2. Sign in with `az login` or another supported developer credential source.\n3. Grant the principal Azure RBAC access on the storage account or container.\n\nRole guidance:\n\n- Read-only flows such as listing or downloading need `Storage Blob Data Reader` or higher.\n- Read/write flows such as upload, create, or delete need `Storage Blob Data Contributor` or higher.\n\nRBAC assignments can take a few minutes to propagate. If a brand-new role assignment fails, retry after a short wait instead of rewriting the auth flow.\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.blob import BlobServiceClient\n\naccount_url = os.environ[\"AZURE_STORAGE_ACCOUNT_URL\"]\ncredential = DefaultAzureCredential()\n\nservice = BlobServiceClient(account_url=account_url, credential=credential)\n```\n\n### Connection string or Azurite\n\nConnection strings are still useful for local storage emulators, migration tooling, and environments where you already have a storage secret.\n\n```python\nimport os\n\nfrom azure.storage.blob import BlobServiceClient\n\nservice = BlobServiceClient.from_connection_string(\n    os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"]\n)\n```\n\nVersion `12.28.0` also adds support for the Azurite shorthand:\n\n```python\nservice = BlobServiceClient.from_connection_string(\"UseDevelopmentStorage=true;\")\n```\n\n### SAS token or account key\n\nThe SDK also supports SAS-token and account-key auth. Use them when required, but prefer Entra ID for application code because it avoids embedding long-lived storage secrets.\n\n## Client Model\n\nThe SDK is organized around three client layers:\n\n- `BlobServiceClient`: account scope\n- `ContainerClient`: one container\n- `BlobClient`: one blob\n\nTypical flow:\n\n```python\ncontainer = service.get_container_client(\"documents\")\nblob = container.get_blob_client(\"reports/hello.txt\")\n```\n\nCreate the container before expecting upload or download calls to work. The SDK does not auto-create missing containers.\n\n## Core Usage\n\n### Basic sync flow\n\n```python\nimport os\n\nfrom azure.core.exceptions import ResourceExistsError\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.blob import BlobServiceClient\n\naccount_url = os.environ[\"AZURE_STORAGE_ACCOUNT_URL\"]\ncontainer_name = os.getenv(\"AZURE_STORAGE_CONTAINER\", \"documents\")\n\nservice = BlobServiceClient(account_url=account_url, credential=DefaultAzureCredential())\ncontainer = service.get_container_client(container_name)\n\ntry:\n    container.create_container()\nexcept ResourceExistsError:\n    pass\n\nblob = container.get_blob_client(\"reports/hello.txt\")\nblob.upload_blob(b\"hello from azure-storage-blob\\n\", overwrite=True)\n\ntext = blob.download_blob(encoding=\"UTF-8\").readall()\nprint(text)\n\nfor item in container.list_blobs(name_starts_with=\"reports/\"):\n    print(item.name, item.size)\n```\n\n### Upload\n\n`upload_blob()` automatically chooses a single request or block-based upload depending on object size and transfer settings.\n\n```python\nfrom azure.storage.blob import ContentSettings\n\nwith open(\"report.json\", \"rb\") as data:\n    blob.upload_blob(\n        data,\n        overwrite=True,\n        tags={\"kind\": \"report\"},\n        content_settings=ContentSettings(content_type=\"application/json\"),\n    )\n```\n\nUseful upload notes:\n\n- `overwrite=True` is usually necessary for idempotent application code.\n- `standard_blob_tier=` can set `Hot`, `Cool`, `Cold`, or `Archive` for block blobs.\n- For manual block staging, use `stage_block()` plus `commit_block_list()`.\n\n### Download\n\n`download_blob()` returns a `StorageStreamDownloader`. Use `readall()` for small payloads, `readinto()` for file writes, or `chunks()` for streaming.\n\n```python\ndownload_stream = blob.download_blob(max_concurrency=4)\n\nwith open(\"report.bin\", \"wb\") as fh:\n    download_stream.readinto(fh)\n```\n\nFor chunked processing:\n\n```python\nstream = blob.download_blob()\n\nfor chunk in stream.chunks():\n    process(chunk)\n```\n\n### List\n\nFlat listing:\n\n```python\nfor item in container.list_blobs(name_starts_with=\"reports/2026/\"):\n    print(item.name)\n```\n\nHierarchical listing with virtual directories:\n\n```python\nfrom azure.storage.blob import BlobPrefix\n\nfor item in container.walk_blobs(name_starts_with=\"reports/\", delimiter=\"/\"):\n    if isinstance(item, BlobPrefix):\n        print(\"dir\", item.name)\n    else:\n        print(\"blob\", item.name)\n```\n\nBlob Storage is fundamentally flat. Folder-like behavior comes from blob naming plus a delimiter. Microsoft Learn also notes that blob snapshots cannot be listed with hierarchical listing.\n\n## Async Pattern\n\nUse async clients from `azure.storage.blob.aio`, and close both credentials and clients. The top-level service client should usually be managed with `async with`; child clients share its connection pool.\n\n```python\nimport os\n\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.storage.blob.aio import BlobServiceClient\n\nasync def main() -> None:\n    account_url = os.environ[\"AZURE_STORAGE_ACCOUNT_URL\"]\n\n    async with DefaultAzureCredential() as credential:\n        async with BlobServiceClient(account_url, credential=credential) as service:\n            container = service.get_container_client(\"documents\")\n            async for item in container.list_blobs(name_starts_with=\"reports/\"):\n                print(item.name)\n```\n\n## Configuration Notes\n\nThe official overview and task guides call out a few settings that matter in production:\n\n- Retry policy: `retry_total`, `retry_connect`, `retry_read`, `retry_status`, `retry_to_secondary`\n- Timeouts: `connection_timeout`, `read_timeout`\n- Logging: `logging_enable=True` for request diagnostics\n- Upload tuning: `max_block_size`, `max_single_put_size`, and per-call `max_concurrency`\n- Download tuning: `max_chunk_get_size`, `max_single_get_size`, and per-call `max_concurrency`\n\nStart with defaults unless you have evidence that transfers or retry behavior need tuning for a specific workload.\n\n## Common Pitfalls\n\n- Some Microsoft Learn task articles still say Python `3.8+`, but the package overview and PyPI metadata for `12.28.0` require Python `>=3.9`. Follow the package metadata.\n- Older overview snippets still mention async support on Python `3.5+`; that text is stale for current stable releases.\n- `upload_blob()` does not protect you from concurrent writers. Microsoft explicitly documents that the client libraries do not support concurrent writes to the same blob.\n- Containers must exist before upload or download examples succeed.\n- Use `name_starts_with=` for listing filters; that is the keyword used by the current docs and examples.\n- `DefaultAzureCredential` failures are often environment issues: not signed in, wrong tenant, or RBAC propagation delay.\n- Debug logging can include request and response bodies. Do not enable it casually in production.\n\n## Version-Sensitive Notes For `12.28.0`\n\n- `12.28.0` is the stable release of the `12.28.0b1` feature set.\n- `ContainerClient.list_blobs()`, `list_blob_names()`, and `walk_blobs()` gained a `start_from` keyword in the `12.28.0` feature line.\n- `BlobClient.download_blob()` gained a `decompress` keyword in the `12.28.0` feature line.\n- `BlobServiceClient.from_connection_string()` now accepts `UseDevelopmentStorage=true;` for Azurite.\n- The default `connection_data_block_size` changed from `4 KiB` to `256 KiB`, which the changelog says should improve throughput for many large downloads.\n\n## Official Sources Used\n\n- Microsoft Learn package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/storage-blob-readme?view=azure-python`\n- Microsoft Learn API root: `https://learn.microsoft.com/en-us/python/api/azure-storage-blob/`\n- Microsoft Learn quickstart: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-python`\n- Microsoft Learn upload guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-upload-python`\n- Microsoft Learn download guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-download-python`\n- Microsoft Learn list guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-list-python`\n- PyPI package page: `https://pypi.org/project/azure-storage-blob/`\n- Azure SDK changelog: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/storage/azure-storage-blob/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/storage-file-datalake/javascript/DOC.md",
    "content": "---\nname: storage-file-datalake\ndescription: \"Azure Storage Data Lake JavaScript client for ADLS Gen2 filesystem, directory, file, and hierarchical access workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.29.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,storage,data-lake,adls,adls-gen2,javascript,filesystem,files,acl\"\n---\n\n# Azure Storage Data Lake JavaScript Client\n\n## Golden Rule\n\nUse `@azure/storage-file-datalake` when your code needs Azure Data Lake Storage Gen2 semantics: filesystems, directories, files, and POSIX-style ACLs on a storage account with hierarchical namespace enabled. Build clients against the `dfs` endpoint, prefer Microsoft Entra authentication with `DefaultAzureCredential`, and keep the account URL explicit so your app does not accidentally mix Blob and Data Lake endpoints.\n\n## Install\n\nPin the SDK version your project expects:\n\n```bash\nnpm install @azure/storage-file-datalake@12.29.0\n```\n\nIf you authenticate with Microsoft Entra ID, install `@azure/identity` too:\n\n```bash\nnpm install @azure/storage-file-datalake@12.29.0 @azure/identity\n```\n\n## Prerequisites\n\n- Use a storage account with hierarchical namespace enabled.\n- Use the Data Lake DFS endpoint: `https://<account>.dfs.core.windows.net`.\n- If you use `DefaultAzureCredential`, sign in locally with `az login` or run in Azure with a managed identity or other supported credential source.\n- Keep secrets in environment variables, not source code.\n\nRecommended environment variables:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT=\"<account-name>\"\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<account-name>.dfs.core.windows.net\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"<connection-string>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\n```\n\n## Authentication And Setup\n\n### Microsoft Entra ID With `DefaultAzureCredential`\n\nFor new applications, this is the best default:\n\n```js\nimport { DataLakeServiceClient } from \"@azure/storage-file-datalake\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nconst accountUrl =\n  process.env.AZURE_STORAGE_ACCOUNT_URL ||\n  `https://${process.env.AZURE_STORAGE_ACCOUNT}.dfs.core.windows.net`;\n\nconst serviceClient = new DataLakeServiceClient(\n  accountUrl,\n  new DefaultAzureCredential(),\n);\n```\n\n### Shared Key Authentication\n\nUse a shared key only when your deployment already depends on account keys:\n\n```js\nimport {\n  DataLakeServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-file-datalake\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\nconst credential = new StorageSharedKeyCredential(accountName, accountKey);\nconst serviceClient = new DataLakeServiceClient(\n  `https://${accountName}.dfs.core.windows.net`,\n  credential,\n);\n```\n\n### Connection String Setup\n\nConnection strings are also supported:\n\n```js\nimport { DataLakeServiceClient } from \"@azure/storage-file-datalake\";\n\nconst serviceClient = DataLakeServiceClient.fromConnectionString(\n  process.env.AZURE_STORAGE_CONNECTION_STRING,\n);\n```\n\n## Client Model\n\nThe client hierarchy mirrors the storage hierarchy:\n\n- `DataLakeServiceClient`: account-level operations and filesystem access\n- `FileSystemClient`: one filesystem inside the storage account\n- `DataLakeDirectoryClient`: one directory path\n- `DataLakeFileClient`: one file path\n\nCreate the service client once and reuse it.\n\n```js\nimport {\n  DataLakeServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-file-datalake\";\nimport { DefaultAzureCredential } from \"@azure/identity\";\n\nexport function createDataLakeServiceClient() {\n  if (process.env.AZURE_STORAGE_CONNECTION_STRING) {\n    return DataLakeServiceClient.fromConnectionString(\n      process.env.AZURE_STORAGE_CONNECTION_STRING,\n    );\n  }\n\n  const accountName = process.env.AZURE_STORAGE_ACCOUNT;\n  const accountUrl =\n    process.env.AZURE_STORAGE_ACCOUNT_URL ||\n    `https://${accountName}.dfs.core.windows.net`;\n\n  if (process.env.AZURE_STORAGE_ACCOUNT_KEY) {\n    return new DataLakeServiceClient(\n      accountUrl,\n      new StorageSharedKeyCredential(\n        accountName,\n        process.env.AZURE_STORAGE_ACCOUNT_KEY,\n      ),\n    );\n  }\n\n  return new DataLakeServiceClient(accountUrl, new DefaultAzureCredential());\n}\n```\n\n## Core Usage\n\n### Create A Filesystem, Directory, And File\n\nUse `createIfNotExists()` for idempotent setup code. When you append bytes manually, call `flush()` to commit them.\n\n```js\nimport { createDataLakeServiceClient } from \"./dataLakeClient.js\";\n\nconst serviceClient = createDataLakeServiceClient();\nconst fileSystemClient = serviceClient.getFileSystemClient(\"raw\");\n\nawait fileSystemClient.createIfNotExists();\n\nconst directoryClient = fileSystemClient.getDirectoryClient(\"incoming/2026/03/13\");\nawait directoryClient.createIfNotExists();\n\nconst fileClient = fileSystemClient.getFileClient(\n  \"incoming/2026/03/13/events.jsonl\",\n);\n\nconst body = Buffer.from('{\"id\":1}\\n{\"id\":2}\\n', \"utf8\");\n\nawait fileClient.create();\nawait fileClient.append(body, 0, body.length);\nawait fileClient.flush(body.length);\n```\n\n### Download A File\n\n`read()` returns a response whose `readableStreamBody` is a Node.js stream.\n\n```js\nimport { createDataLakeServiceClient } from \"./dataLakeClient.js\";\n\nfunction streamToBuffer(readableStream) {\n  return new Promise((resolve, reject) => {\n    const chunks = [];\n\n    readableStream.on(\"data\", (chunk) => {\n      chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n    });\n    readableStream.on(\"end\", () => resolve(Buffer.concat(chunks)));\n    readableStream.on(\"error\", reject);\n  });\n}\n\nconst serviceClient = createDataLakeServiceClient();\n\nconst fileClient = serviceClient\n  .getFileSystemClient(\"raw\")\n  .getFileClient(\"incoming/2026/03/13/events.jsonl\");\n\nconst download = await fileClient.read();\nconst content = await streamToBuffer(download.readableStreamBody);\n\nconsole.log(content.toString(\"utf8\"));\n```\n\n### List Paths\n\nUse `listPaths(...)` to enumerate directories and files relative to a filesystem:\n\n```js\nimport { createDataLakeServiceClient } from \"./dataLakeClient.js\";\n\nconst serviceClient = createDataLakeServiceClient();\nconst fileSystemClient = serviceClient.getFileSystemClient(\"raw\");\n\nfor await (const path of fileSystemClient.listPaths({\n  path: \"incoming\",\n  recursive: true,\n})) {\n  console.log(path.name, path.isDirectory);\n}\n```\n\n## Configuration Notes\n\n- Prefer `DefaultAzureCredential` unless you specifically need a connection string or account key.\n- Keep the DFS account URL explicit in config so the app does not drift to `blob.core.windows.net`.\n- Reuse one `DataLakeServiceClient` instead of creating a new client for every operation.\n- Use `createIfNotExists()` for bootstrap or one-time provisioning paths, not as a substitute for normal application flow control.\n- If you append bytes with `append(...)`, call `flush(...)` or the file contents are not committed.\n- Use the Data Lake directory and file clients, not Blob clients, when you need hierarchical paths or POSIX-style ACL behavior.\n\n## Common Pitfalls\n\n- Using `https://<account>.blob.core.windows.net` instead of the DFS endpoint.\n- Forgetting that hierarchical namespace must be enabled for Data Lake directory and ACL features.\n- Installing `@azure/storage-file-datalake` without `@azure/identity` and then trying to use `DefaultAzureCredential`.\n- Assuming Blob and Data Lake examples are interchangeable; many account concepts overlap, but the endpoint and directory semantics do not.\n- Appending data without calling `flush(...)`.\n- Hard-coding secrets instead of reading them from environment or managed identity.\n- Treating Azure RBAC and POSIX ACLs as the same control plane. A principal can authenticate successfully and still fail on a path because of Data Lake ACLs.\n\n## Version Notes For 12.29.0\n\n- This guide targets `@azure/storage-file-datalake` `12.29.0`.\n- `@azure/identity` is versioned separately; pin it according to your application's Azure SDK policy.\n- If you copy older Azure Storage examples that only show Blob clients or Blob endpoints, rewrite them for `DataLakeServiceClient` and the DFS endpoint before using them with this package.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-datalake/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/storage-file-datalake-readme?view=azure-node-latest`\n- `DataLakeServiceClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-datalake/datalakeserviceclient?view=azure-node-latest`\n- `DataLakeFileClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-datalake/datalakefileclient?view=azure-node-latest`\n- `FileSystemClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-datalake/filesystemclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/storage-file-datalake`\n"
  },
  {
    "path": "content/azure/docs/storage-file-datalake/python/DOC.md",
    "content": "---\nname: storage-file-datalake\ndescription: \"Azure Storage Data Lake client library for Python for ADLS Gen2 filesystem, directory, file, and ACL operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.23.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,storage,data-lake,adls,adls-gen2,filesystem,files,acl\"\n---\n\n# Azure Storage Data Lake Client Library For Python\n\n## Golden Rule\n\nUse `azure-storage-file-datalake` when you need Azure Data Lake Storage Gen2 features that depend on hierarchical namespaces: filesystems, directories, files, and POSIX-style ACLs. Construct clients against the `dfs` endpoint, prefer Microsoft Entra authentication via `DefaultAzureCredential`, and pin the stable package release your project expects. As of March 12, 2026, PyPI lists `12.23.0` as the latest stable release and `12.24.0b1` as a preview; some official Azure overview pages still show preview-era `pip install --pre` snippets, so do not copy those unless you intentionally want the beta.\n\n## Install\n\nPin the stable version unless the project explicitly depends on a preview:\n\n```bash\npython -m pip install \"azure-storage-file-datalake==12.23.0\" \"azure-identity>=1.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-storage-file-datalake==12.23.0\" azure-identity\npoetry add \"azure-storage-file-datalake==12.23.0\"\npoetry add azure-identity\n```\n\nIf you are using the async clients, install an async HTTP transport too:\n\n```bash\npython -m pip install \"azure-storage-file-datalake==12.23.0\" \"azure-identity>=1.17.0\" aiohttp\n```\n\nNotes:\n\n- `azure-identity` is a separate package; `DefaultAzureCredential` does not come from `azure-storage-file-datalake`.\n- Data Lake Storage Gen2 features require a storage account with hierarchical namespace enabled.\n- Use `--pre` only when you intentionally want a preview build such as `12.24.0b1`.\n\n## Authentication And Endpoint Setup\n\nFor most new code, authenticate with Microsoft Entra ID and `DefaultAzureCredential`:\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\naccount_name = os.environ[\"AZURE_STORAGE_ACCOUNT\"]\naccount_url = f\"https://{account_name}.dfs.core.windows.net\"\n\nservice_client = DataLakeServiceClient(\n    account_url=account_url,\n    credential=DefaultAzureCredential(),\n)\n```\n\nImportant setup rules:\n\n- Use the `dfs.core.windows.net` endpoint, not `blob.core.windows.net`, for Data Lake clients.\n- The four core sync clients are `DataLakeServiceClient`, `FileSystemClient`, `DataLakeDirectoryClient`, and `DataLakeFileClient`.\n- `DefaultAzureCredential` works well for local development with Azure CLI or developer login, and for deployed workloads with managed identity.\n- If the storage account is in a sovereign cloud, change the hostname to that cloud's DFS endpoint rather than hard-coding `core.windows.net`.\n\nOther supported credential styles:\n\n```python\nimport os\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice_client = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=os.environ[\"AZURE_STORAGE_ACCOUNT_KEY\"],\n)\n\nsas_client = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=os.environ[\"AZURE_STORAGE_SAS_TOKEN\"],\n)\n```\n\nConnection string setup is also supported:\n\n```python\nimport os\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice_client = DataLakeServiceClient.from_connection_string(\n    os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"]\n)\n```\n\nFor local emulator workflows, the `12.23.0` line supports the short Azurite connection string form:\n\n```python\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice_client = DataLakeServiceClient.from_connection_string(\"UseDevelopmentStorage=true;\")\n```\n\n## Client Model\n\nThe client hierarchy mirrors the storage hierarchy:\n\n- `DataLakeServiceClient`: account-level operations and filesystem creation\n- `FileSystemClient`: one filesystem (container) within the account\n- `DataLakeDirectoryClient`: one directory path\n- `DataLakeFileClient`: one file path\n\nTypical client construction:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=DefaultAzureCredential(),\n)\n\nfile_system = service.get_file_system_client(\"raw\")\ndirectory = file_system.get_directory_client(\"incoming/2026/03/12\")\nfile_client = file_system.get_file_client(\"incoming/2026/03/12/events.jsonl\")\n```\n\n## Core Usage\n\n### Create A Filesystem And Upload A File\n\n```python\nfrom azure.core.exceptions import ResourceExistsError\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=DefaultAzureCredential(),\n)\n\ntry:\n    file_system = service.create_file_system(file_system=\"raw\")\nexcept ResourceExistsError:\n    file_system = service.get_file_system_client(\"raw\")\n\ndirectory = file_system.get_directory_client(\"incoming/2026/03/12\")\n\ntry:\n    directory.create_directory()\nexcept ResourceExistsError:\n    pass\n\nfile_client = file_system.get_file_client(\"incoming/2026/03/12/events.jsonl\")\npayload = b'{\"id\": 1}\\n{\"id\": 2}\\n'\n\nfile_client.create_file()\nfile_client.upload_data(payload, overwrite=True)\n```\n\n`upload_data()` is the simplest whole-body write API. Pass `overwrite=True` when replacing an existing file.\n\n### Append Incrementally And Flush\n\nIf you need explicit append/commit control, use `append_data()` followed by `flush_data()`:\n\n```python\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient.from_connection_string(\n    \"UseDevelopmentStorage=true;\"\n)\n\nfile_system = service.get_file_system_client(\"raw\")\nfile_client = file_system.get_file_client(\"incoming/events.jsonl\")\n\nfile_client.create_file()\n\nchunks = [b'{\"id\": 1}\\n', b'{\"id\": 2}\\n']\noffset = 0\n\nfor chunk in chunks:\n    file_client.append_data(chunk, offset=offset, length=len(chunk))\n    offset += len(chunk)\n\nfile_client.flush_data(offset)\n```\n\nIf you skip `flush_data()`, the appended bytes are not committed as a readable file.\n\n### Download A File\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=DefaultAzureCredential(),\n)\n\nfile_client = service.get_file_system_client(\"raw\").get_file_client(\n    \"incoming/2026/03/12/events.jsonl\"\n)\n\ndownload = file_client.download_file()\ncontent = download.readall().decode(\"utf-8\")\nprint(content)\n```\n\nFor large reads, prefer streaming methods like `chunks()` or `readinto()` instead of materializing the whole file into memory.\n\n### List Paths\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=DefaultAzureCredential(),\n)\n\nfile_system = service.get_file_system_client(\"raw\")\n\nfor path in file_system.get_paths(path=\"incoming\", recursive=True):\n    print(path.name, path.is_directory)\n```\n\n`get_paths()` returns path items relative to the filesystem. The returned `name` is not a full URL.\n\n### Manage ACLs On A Directory\n\nUse the Data Lake clients when you need POSIX-style ownership and ACL behavior:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.filedatalake import DataLakeServiceClient\n\nservice = DataLakeServiceClient(\n    account_url=\"https://myaccount.dfs.core.windows.net\",\n    credential=DefaultAzureCredential(),\n)\n\ndirectory = service.get_file_system_client(\"raw\").get_directory_client(\"incoming\")\n\ndirectory.set_access_control(acl=\"user::rwx,group::r-x,other::---\")\n\nacl_info = directory.get_access_control(upn=True)\nprint(acl_info[\"acl\"])\n```\n\nFor existing directory trees, apply ACLs recursively:\n\n```python\ndirectory = service.get_file_system_client(\"raw\").get_directory_client(\"incoming\")\n\nresult = directory.set_access_control_recursive(\n    acl=\"user::rwx,group::r-x,other::---\"\n)\n\nprint(result.counters)\n```\n\n`upn=True` converts Microsoft Entra user object IDs to user principal names when possible. It does not convert group or application object IDs.\n\n## SAS Helpers\n\nThe package includes helper functions for shared access signatures:\n\n- `generate_file_system_sas`\n- `generate_directory_sas`\n- `generate_file_sas`\n\nUse SAS only when you already have a clear account-key or user-delegation-key workflow. For most first-party Azure code, Microsoft Entra authentication is the better default.\n\n## Async Usage\n\nAsync clients live under `azure.storage.filedatalake.aio`, and the async credential types live under `azure.identity.aio`:\n\n```python\nimport asyncio\nfrom azure.identity.aio import DefaultAzureCredential\nfrom azure.storage.filedatalake.aio import DataLakeServiceClient\n\nasync def main() -> None:\n    async with DefaultAzureCredential() as credential:\n        async with DataLakeServiceClient(\n            account_url=\"https://myaccount.dfs.core.windows.net\",\n            credential=credential,\n        ) as service:\n            file_system = service.get_file_system_client(\"raw\")\n\n            async for path in file_system.get_paths(path=\"incoming\", recursive=True):\n                print(path.name)\n\nasyncio.run(main())\n```\n\nClose async credentials and clients cleanly with `async with` or explicit `close()` calls.\n\n## Configuration Notes\n\n- Prefer `DefaultAzureCredential` unless the deployment environment requires a SAS token, account key, or connection string.\n- Keep the account URL explicit in config so agents do not accidentally mix the Blob and DFS endpoints.\n- If your code path needs both Blob APIs and Data Lake ACL or directory semantics, keep it clear which client is operating on which endpoint.\n- For local developer shells, `az login` plus `DefaultAzureCredential` is usually simpler than manually managing storage keys.\n- Recursive ACL changes can touch large directory trees; treat them as potentially long-running operations and inspect the returned counters.\n\n## Common Pitfalls\n\n- `DataLakeServiceClient` should target `https://<account>.dfs.core.windows.net`. Using the Blob endpoint causes confusing failures.\n- Hierarchical namespace must be enabled on the storage account. Without it, Data Lake directory and ACL semantics are not available.\n- `azure-storage-file-datalake` does not install `azure-identity` for you.\n- `append_data()` is not enough by itself; you must call `flush_data()` to commit the buffered bytes.\n- `upload_data()` replaces content only when `overwrite=True` is set. Otherwise existing files can raise `ResourceExistsError`.\n- Azure RBAC and POSIX ACLs are separate controls. A principal can have Azure-level access yet still fail on a specific path because of ACLs.\n- `get_access_control(upn=True)` only rewrites user IDs to UPNs when Azure can resolve them. Groups and service principals still come back as object IDs.\n- Some official Azure overview pages still show preview-era install commands. For stable production code, trust PyPI and the package changelog for release selection.\n\n## Version-Sensitive Notes For 12.23.0\n\n- PyPI lists `12.23.0` as the latest stable package release on March 12, 2026.\n- PyPI also shows a newer preview, `12.24.0b1`, so agents should avoid `--pre` unless a project explicitly depends on preview behavior.\n- The `12.23.0` line supports the short Azurite connection string form `UseDevelopmentStorage=true;`, which is useful for local emulator tests.\n- PyPI requires Python `>=3.9`, so Python 3.8 environments need an older package line.\n\n## Official Source URLs\n\n- Microsoft Learn overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/storage-file-datalake-readme?view=azure-python`\n- Microsoft Learn API reference: `https://learn.microsoft.com/en-us/python/api/azure-storage-file-datalake/azure.storage.filedatalake?view=azure-python`\n- Microsoft Learn directory and file guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/data-lake-storage-directory-file-acl-python`\n- Microsoft Learn ACL guide: `https://learn.microsoft.com/en-us/azure/storage/blobs/data-lake-storage-acl-python`\n- PyPI package page: `https://pypi.org/project/azure-storage-file-datalake/`\n- Azure SDK changelog: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/storage/azure-storage-file-datalake/CHANGELOG.md`\n"
  },
  {
    "path": "content/azure/docs/storage-file-share/javascript/DOC.md",
    "content": "---\nname: storage-file-share\ndescription: \"Azure Files JavaScript client library for shares, directories, files, authentication, and file transfer workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.30.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,storage,file-share,javascript,files,smb,entra-id\"\n---\n\n# Azure Files JavaScript Client\n\n## Golden Rule\n\nUse `@azure/storage-file-share` for Azure Files data-plane operations, keep the account endpoint on `https://<account>.file.core.windows.net`, and build your code around the current `ShareServiceClient` → `ShareClient` → `ShareDirectoryClient` → `ShareFileClient` hierarchy. Do not mix Azure Files code with Blob Storage endpoints or legacy `azure-storage` / `azure-storage-file` examples.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @azure/storage-file-share@12.30.0\n```\n\nIf you authenticate with Microsoft Entra ID, install `@azure/identity` too:\n\n```bash\nnpm install @azure/storage-file-share@12.30.0 @azure/identity\n```\n\n## Prerequisites\n\n- Use the Azure Files endpoint shape `https://<account>.file.core.windows.net`.\n- Keep storage credentials in environment variables, not source code.\n- If you use `DefaultAzureCredential`, sign in locally with `az login` or run in Azure with a managed identity or another supported Azure credential source.\n- For token-based auth, the principal still needs an Azure Files data-plane role assignment.\n\nRecommended environment variables:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT=\"<account-name>\"\nexport AZURE_STORAGE_ACCOUNT_URL=\"https://<account-name>.file.core.windows.net\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"<connection-string>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\nexport AZURE_STORAGE_FILE_SHARE_NAME=\"agent-docs\"\n```\n\n## Authentication And Setup\n\n### Microsoft Entra ID With `DefaultAzureCredential`\n\nFor Azure-hosted apps and developer environments that already use Azure CLI or workload identity, this is the best default. For Azure Files token auth, set `tokenIntent` explicitly.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { ShareServiceClient } from \"@azure/storage-file-share\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT;\nconst accountUrl =\n  process.env.AZURE_STORAGE_ACCOUNT_URL ||\n  `https://${accountName}.file.core.windows.net`;\n\nconst serviceClient = new ShareServiceClient(\n  accountUrl,\n  new DefaultAzureCredential(),\n  { tokenIntent: \"backup\" },\n);\n```\n\n### Shared Key Authentication\n\nUse a shared key when your deployment already manages storage account keys directly:\n\n```js\nimport {\n  ShareServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-file-share\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\nconst credential = new StorageSharedKeyCredential(accountName, accountKey);\nconst serviceClient = new ShareServiceClient(\n  `https://${accountName}.file.core.windows.net`,\n  credential,\n);\n```\n\n### Connection String Setup\n\nConnection strings are the quickest setup for scripts and local tools:\n\n```js\nimport { ShareServiceClient } from \"@azure/storage-file-share\";\n\nconst serviceClient = ShareServiceClient.fromConnectionString(\n  process.env.AZURE_STORAGE_CONNECTION_STRING,\n);\n```\n\n## Client Model\n\nThe client hierarchy mirrors Azure Files resources:\n\n- `ShareServiceClient`: account-level operations and share access\n- `ShareClient`: one file share\n- `ShareDirectoryClient`: one directory path inside a share\n- `ShareFileClient`: one file path inside a share\n\nCreate the service client once and reuse it.\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport {\n  ShareServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-file-share\";\n\nexport function createShareServiceClient() {\n  const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;\n\n  if (connectionString) {\n    return ShareServiceClient.fromConnectionString(connectionString);\n  }\n\n  const accountName = process.env.AZURE_STORAGE_ACCOUNT;\n  const accountUrl =\n    process.env.AZURE_STORAGE_ACCOUNT_URL ||\n    (accountName\n      ? `https://${accountName}.file.core.windows.net`\n      : undefined);\n\n  if (!accountUrl) {\n    throw new Error(\n      \"Set AZURE_STORAGE_CONNECTION_STRING or AZURE_STORAGE_ACCOUNT_URL\",\n    );\n  }\n\n  if (process.env.AZURE_STORAGE_ACCOUNT_KEY) {\n    if (!accountName) {\n      throw new Error(\"AZURE_STORAGE_ACCOUNT is required with account keys\");\n    }\n\n    return new ShareServiceClient(\n      accountUrl,\n      new StorageSharedKeyCredential(\n        accountName,\n        process.env.AZURE_STORAGE_ACCOUNT_KEY,\n      ),\n    );\n  }\n\n  return new ShareServiceClient(accountUrl, new DefaultAzureCredential(), {\n    tokenIntent: \"backup\",\n  });\n}\n```\n\n## Core Usage\n\n### Create A Share, Directory, And File\n\nCreate the share and parent directory before writing the file. When you use the low-level file APIs, create the file with its final size before uploading a range.\n\n```js\nimport { createShareServiceClient } from \"./shareClient.js\";\n\nconst serviceClient = createShareServiceClient();\nconst shareClient = serviceClient.getShareClient(\n  process.env.AZURE_STORAGE_FILE_SHARE_NAME,\n);\n\nawait shareClient.createIfNotExists();\n\nconst directoryClient = shareClient.getDirectoryClient(\"incoming\");\nawait directoryClient.createIfNotExists();\n\nconst fileClient = directoryClient.getFileClient(\"hello.txt\");\nconst body = Buffer.from(\"hello from Azure Files\\n\", \"utf8\");\n\nawait fileClient.create(body.length);\nawait fileClient.uploadRange(body, 0, body.length);\n```\n\n### Download A File\n\n`download(...)` returns a response whose `readableStreamBody` is a Node.js stream.\n\n```js\nimport { createShareServiceClient } from \"./shareClient.js\";\n\nfunction streamToBuffer(readableStream) {\n  return new Promise((resolve, reject) => {\n    const chunks = [];\n\n    readableStream.on(\"data\", (chunk) => {\n      chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n    });\n    readableStream.on(\"end\", () => resolve(Buffer.concat(chunks)));\n    readableStream.on(\"error\", reject);\n  });\n}\n\nconst serviceClient = createShareServiceClient();\nconst fileClient = serviceClient\n  .getShareClient(process.env.AZURE_STORAGE_FILE_SHARE_NAME)\n  .getDirectoryClient(\"incoming\")\n  .getFileClient(\"hello.txt\");\n\nconst download = await fileClient.download(0);\nconst content = await streamToBuffer(download.readableStreamBody);\n\nconsole.log(content.toString(\"utf8\"));\n```\n\n### Work Directly With A Known File Path\n\nIf you already know the share name and file path, you can build the file client directly from a connection string:\n\n```js\nimport { ShareFileClient } from \"@azure/storage-file-share\";\n\nconst fileClient = ShareFileClient.fromConnectionString(\n  process.env.AZURE_STORAGE_CONNECTION_STRING,\n  process.env.AZURE_STORAGE_FILE_SHARE_NAME,\n  \"incoming/hello.txt\",\n);\n\nconst download = await fileClient.download(0);\nconsole.log(download.contentLength);\n```\n\n### List Directory Contents\n\nUse the directory client to enumerate files and child directories:\n\n```js\nimport { createShareServiceClient } from \"./shareClient.js\";\n\nconst serviceClient = createShareServiceClient();\nconst directoryClient = serviceClient\n  .getShareClient(process.env.AZURE_STORAGE_FILE_SHARE_NAME)\n  .getDirectoryClient(\"incoming\");\n\nfor await (const item of directoryClient.listFilesAndDirectories()) {\n  console.log(item.kind, item.name);\n}\n```\n\n## Configuration Notes\n\n- Prefer `DefaultAzureCredential` for deployed applications when you can assign the required Azure Files data-plane permissions.\n- Keep the file service URL explicit in config so the app does not drift to `blob.core.windows.net` or `dfs.core.windows.net`.\n- Reuse one long-lived `ShareServiceClient` instead of creating a new client for every operation.\n- `uploadRange(...)` is a low-level API: call `create(size)` first and use the correct byte count.\n- Create parent directories before writing a file into them.\n- Use connection strings or shared keys for simple local tools when Entra ID is not part of the deployment model.\n\n## Common Pitfalls\n\n- Using the Blob or Data Lake endpoint instead of `file.core.windows.net`.\n- Copying legacy `azure-storage` or `azure-storage-file` examples instead of the current 12.x client surface.\n- Forgetting `tokenIntent: \"backup\"` when constructing a client with a token credential for Azure Files.\n- Trying to upload bytes with `uploadRange(...)` before the file exists.\n- Skipping parent directory creation and then writing to a nested file path.\n- Installing only `@azure/storage-file-share` and then trying to use `DefaultAzureCredential` without `@azure/identity`.\n\n## Version Notes For 12.30.0\n\n- This guide targets `@azure/storage-file-share` `12.30.0`.\n- `@azure/identity` is versioned separately; pin it according to your application's Azure SDK policy.\n- If you are updating old Azure Files code, move it to the current `ShareServiceClient` / `ShareClient` / `ShareFileClient` API surface before reusing examples.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-share/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/storage-file-share-readme?view=azure-node-latest`\n- `ShareServiceClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-share/shareserviceclient?view=azure-node-latest`\n- `ShareClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-share/shareclient?view=azure-node-latest`\n- `ShareDirectoryClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-share/sharedirectoryclient?view=azure-node-latest`\n- `ShareFileClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-file-share/sharefileclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/storage-file-share`\n"
  },
  {
    "path": "content/azure/docs/storage-file-share/python/DOC.md",
    "content": "---\nname: storage-file-share\ndescription: \"Azure Files client library for Python with practical guidance for auth, shares, directories, file transfers, and version-sensitive behavior\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.24.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,storage,file-share,python,files,sas,entra-id\"\n---\n\n# Azure Files Share Python Client Library\n\n## Golden Rule\n\nUse `azure-storage-file-share` for Azure Files data-plane access, import it from `azure.storage.fileshare`, and use the Azure Files endpoint shape `https://<account>.file.core.windows.net`. Do not mix Azure Files examples with Blob Storage endpoints or the legacy `azure-storage-file` package.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"azure-storage-file-share==12.24.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"azure-storage-file-share==12.24.0\"\npoetry add \"azure-storage-file-share==12.24.0\"\n```\n\nInstall auth or async companions only when needed:\n\n```bash\npython -m pip install \"azure-storage-file-share==12.24.0\" azure-identity\npython -m pip install \"azure-storage-file-share==12.24.0\" aiohttp\n```\n\n## Authentication And Setup\n\nYou can construct clients with:\n\n- a connection string\n- an account key or `AzureNamedKeyCredential`\n- a SAS token or `AzureSasCredential`\n- a `TokenCredential` such as `DefaultAzureCredential`\n\nUse the file service endpoint, not blob or dfs endpoints:\n\n```text\nhttps://<storage-account>.file.core.windows.net\n```\n\n### Connection String\n\nThis is the fastest local setup when you already have the storage account connection string:\n\n```python\nimport os\nfrom azure.storage.fileshare import ShareServiceClient\n\nservice_client = ShareServiceClient.from_connection_string(\n    os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"]\n)\nshare_client = service_client.get_share_client(\"agent-docs\")\n```\n\n### Microsoft Entra ID\n\nPrefer `DefaultAzureCredential` in Azure-hosted environments and in local development that already uses Azure CLI or workload identity. For Azure Files token auth, set `token_intent` explicitly.\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.fileshare import ShareServiceClient\n\ncredential = DefaultAzureCredential()\n\nservice_client = ShareServiceClient(\n    account_url=\"https://<storage-account>.file.core.windows.net\",\n    credential=credential,\n    token_intent=\"backup\",\n)\n```\n\nPractical notes:\n\n- `token_intent` is specific to Azure Files token-credential scenarios and is easy to miss if you copy older snippets.\n- The principal still needs the correct Azure Files data-plane role assignment.\n- If you do not need Entra ID, a connection string is usually simpler.\n\n### Shared Key Or SAS\n\nUse shared key credentials for direct account-level access, or SAS for narrower permissions:\n\n```python\nfrom azure.core.credentials import AzureNamedKeyCredential\nfrom azure.storage.fileshare import ShareServiceClient\n\nservice_client = ShareServiceClient(\n    account_url=\"https://<storage-account>.file.core.windows.net\",\n    credential=AzureNamedKeyCredential(\"<storage-account>\", \"<account-key>\"),\n)\n```\n\n```python\nfrom azure.core.credentials import AzureSasCredential\nfrom azure.storage.fileshare import ShareClient\n\nshare_client = ShareClient(\n    account_url=\"https://<storage-account>.file.core.windows.net\",\n    share_name=\"agent-docs\",\n    credential=AzureSasCredential(\"<sas-token>\"),\n)\n```\n\n## Core Usage\n\nThe normal sync flow is:\n\n1. Create a `ShareServiceClient`.\n2. Get or create a `ShareClient`.\n3. Create parent directories before uploading files.\n4. Use `ShareFileClient` to upload or download content.\n\n### Create A Share, Upload A File, Download It\n\n```python\nimport os\nfrom azure.storage.fileshare import ShareServiceClient\n\nservice_client = ShareServiceClient.from_connection_string(\n    os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"]\n)\n\nshare_client = service_client.get_share_client(\"agent-docs\")\nif not share_client.exists():\n    share_client.create_share()\n\ndirectory_client = share_client.get_directory_client(\"incoming\")\nif not directory_client.exists():\n    directory_client.create_directory()\n\nfile_client = directory_client.get_file_client(\"hello.txt\")\nfile_client.upload_file(b\"hello from Azure Files\\n\")\n\ndownloader = file_client.download_file()\ncontent = downloader.readall().decode(\"utf-8\")\nprint(content)\n```\n\n### List Directories And Files\n\n```python\nfor item in directory_client.list_directories_and_files():\n    print(item[\"name\"], item[\"is_directory\"])\n```\n\n### Work Directly With A Known File Path\n\n```python\nimport os\nfrom azure.storage.fileshare import ShareFileClient\n\nfile_client = ShareFileClient.from_connection_string(\n    conn_str=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n    share_name=\"agent-docs\",\n    file_path=\"incoming/hello.txt\",\n)\n\ndata = file_client.download_file().readall()\nprint(data.decode(\"utf-8\"))\n```\n\n### Async Usage\n\nAsync clients live under `azure.storage.fileshare.aio`. Close them with `async with`, and close credential objects when they support async cleanup.\n\n```python\nimport asyncio\nimport os\nfrom azure.storage.fileshare.aio import ShareFileClient\n\nasync def main() -> None:\n    file_client = ShareFileClient.from_connection_string(\n        conn_str=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n        share_name=\"agent-docs\",\n        file_path=\"incoming/hello.txt\",\n    )\n\n    async with file_client:\n        downloader = await file_client.download_file(max_concurrency=4)\n        data = await downloader.readall()\n        print(data.decode(\"utf-8\"))\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\nThe package overview documents several transfer tuning knobs:\n\n- `max_range_size`: upload chunk size, default `4 * 1024 * 1024`\n- `max_single_put_size`: single-request upload threshold, default `64 * 1024 * 1024`\n- `max_single_get_size`: single-request download threshold, default `32 * 1024 * 1024`\n- `connection_data_block_size`: socket read block size for downloads\n- `max_concurrency`: parallel workers for uploads and downloads\n\nIn `12.24.0`, the package overview notes that `connection_data_block_size` changed from `4 * 1024` to `256 * 1024`. If you are comparing throughput with older `12.x` examples, this is one of the first settings to check.\n\nStart with defaults unless you are actively tuning large-file transfer performance.\n\n## Common Pitfalls\n\n- The install name is `azure-storage-file-share`, but the import path is `azure.storage.fileshare`.\n- Old docs or blog posts may still refer to `azure-storage-file`; prefer current `12.x` docs and namespace names.\n- Use the Files endpoint `file.core.windows.net`; Blob Storage examples use different clients and endpoints.\n- Create the share and parent directories before uploading a file into them.\n- `download_file()` returns a downloader object, not raw bytes. Use `readall()` or `readinto()`.\n- Async usage needs `aiohttp`, and async clients should be closed cleanly.\n- Token-credential flows for Azure Files need `token_intent`; missing it can look like a generic auth or permission failure.\n- Azure Files permissions are data-plane permissions. Valid Azure login state alone does not guarantee the required share access.\n\n## Version-Sensitive Notes\n\n- This guide targets `12.24.0`, which is the stable version listed on PyPI and in the current Azure package overview on March 12, 2026.\n- `12.24.0` adds support for storage service API version `2026-02-06`.\n- The `12.24.0` changelog also adds `ShareServiceClient.get_user_delegation_key` and user delegation SAS support. If your code needs user delegation SAS for Azure Files, earlier versions will not match current docs.\n- The PyPI package page still documents the rename from `azure-storage-file` to `azure-storage-file-share`; that matters when updating old requirements files or import paths.\n\n## Official Sources\n\n- Package overview: `https://learn.microsoft.com/en-us/python/api/overview/azure/storage-file-share-readme?view=azure-python`\n- API reference root: `https://learn.microsoft.com/en-us/python/api/azure-storage-file-share/`\n- `ShareServiceClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-storage-file-share/azure.storage.fileshare.shareserviceclient?view=azure-python`\n- Azure Files Python how-to: `https://learn.microsoft.com/en-us/azure/storage/files/storage-python-how-to-use-file-storage`\n- Changelog: `https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/storage/azure-storage-file-share/CHANGELOG.md`\n- PyPI package page: `https://pypi.org/project/azure-storage-file-share/`\n"
  },
  {
    "path": "content/azure/docs/storage-queue/javascript/DOC.md",
    "content": "---\nname: storage-queue\ndescription: \"Azure Queue Storage client library for JavaScript with QueueServiceClient, QueueClient, authentication, and message processing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.29.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,storage,queue,azure-storage,javascript,entra-id\"\n---\n\n# Azure Storage Queue JavaScript Client\n\n## Golden Rule\n\nUse `@azure/storage-queue` for Azure Queue Storage and stay on the current 12.x client surface:\n\n- `QueueServiceClient` for account-level operations\n- `QueueClient` for one queue\n- `@azure/identity` when you authenticate with Microsoft Entra ID\n\nDo not copy legacy examples that use the old `azure-storage` package or `QueueService` API surface.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @azure/storage-queue@12.29.0\n```\n\nIf you want Microsoft Entra ID authentication, install `@azure/identity` too:\n\n```bash\nnpm install @azure/storage-queue@12.29.0 @azure/identity\n```\n\n## Authentication And Setup\n\nThe practical auth choices are:\n\n- Microsoft Entra ID with `DefaultAzureCredential`\n- a storage account connection string\n- a shared account key when you explicitly manage storage keys\n\nUse environment variables instead of hard-coding credentials:\n\n```bash\nexport AZURE_STORAGE_QUEUE_ACCOUNT_URL=\"https://<account>.queue.core.windows.net\"\nexport AZURE_STORAGE_CONNECTION_STRING=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\nexport AZURE_STORAGE_QUEUE_NAME=\"jobs\"\n```\n\n### Microsoft Entra ID With `DefaultAzureCredential`\n\nUse this for deployed apps in Azure, or for local development after a developer sign-in such as:\n\n```bash\naz login\nexport AZURE_STORAGE_QUEUE_ACCOUNT_URL=\"https://<account>.queue.core.windows.net\"\n```\n\n```js\nimport { DefaultAzureCredential } from \"@azure/identity\";\nimport { QueueServiceClient } from \"@azure/storage-queue\";\n\nconst accountUrl = process.env.AZURE_STORAGE_QUEUE_ACCOUNT_URL;\n\nif (!accountUrl) {\n  throw new Error(\"AZURE_STORAGE_QUEUE_ACCOUNT_URL is required\");\n}\n\nconst serviceClient = new QueueServiceClient(\n  accountUrl,\n  new DefaultAzureCredential(),\n);\n```\n\nFor data access, the identity needs an Azure Storage Queue data-plane role such as `Storage Queue Data Contributor`.\n\n### Connection String\n\nUse this for local tools, simple scripts, or environments that already provide a storage connection string.\n\n```js\nimport { QueueClient } from \"@azure/storage-queue\";\n\nconst connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;\nconst queueName = process.env.AZURE_STORAGE_QUEUE_NAME;\n\nif (!connectionString || !queueName) {\n  throw new Error(\n    \"AZURE_STORAGE_CONNECTION_STRING and AZURE_STORAGE_QUEUE_NAME are required\",\n  );\n}\n\nconst queueClient = QueueClient.fromConnectionString(\n  connectionString,\n  queueName,\n);\n```\n\nFor local Azurite development, use the documented storage shortcut connection string:\n\n```bash\nexport AZURE_STORAGE_CONNECTION_STRING=\"UseDevelopmentStorage=true\"\nexport AZURE_STORAGE_QUEUE_NAME=\"jobs\"\n```\n\n### Shared Key\n\nUse this only when your application explicitly manages storage account keys.\n\n```bash\nexport AZURE_STORAGE_ACCOUNT_NAME=\"<account-name>\"\nexport AZURE_STORAGE_ACCOUNT_KEY=\"<account-key>\"\n```\n\n```js\nimport {\n  QueueServiceClient,\n  StorageSharedKeyCredential,\n} from \"@azure/storage-queue\";\n\nconst accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;\nconst accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;\n\nif (!accountName || !accountKey) {\n  throw new Error(\n    \"AZURE_STORAGE_ACCOUNT_NAME and AZURE_STORAGE_ACCOUNT_KEY are required\",\n  );\n}\n\nconst credential = new StorageSharedKeyCredential(accountName, accountKey);\nconst serviceClient = new QueueServiceClient(\n  `https://${accountName}.queue.core.windows.net`,\n  credential,\n);\n```\n\n## Client Initialization\n\nUse `QueueServiceClient` once, then derive queue clients from it.\n\n```js\nimport { QueueServiceClient } from \"@azure/storage-queue\";\n\nconst connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;\n\nif (!connectionString) {\n  throw new Error(\"AZURE_STORAGE_CONNECTION_STRING is required\");\n}\n\nconst serviceClient = QueueServiceClient.fromConnectionString(connectionString);\nconst queueClient = serviceClient.getQueueClient(\"jobs\");\n```\n\nThis is the cleanest pattern when one process touches more than one queue. If your code only needs one queue, constructing `QueueClient` directly is fine.\n\n## Core Usage\n\n### Create A Queue If Needed\n\n```js\nimport { QueueClient } from \"@azure/storage-queue\";\n\nconst queueClient = QueueClient.fromConnectionString(\n  process.env.AZURE_STORAGE_CONNECTION_STRING,\n  process.env.AZURE_STORAGE_QUEUE_NAME,\n);\n\nawait queueClient.createIfNotExists();\n```\n\n### Send Messages\n\n```js\nawait queueClient.sendMessage(\"rebuild-search-index\");\n\nawait queueClient.sendMessage(\n  JSON.stringify({\n    job: \"sync-users\",\n    tenant: \"acme\",\n  }),\n);\n```\n\nSerialize structured payloads explicitly with `JSON.stringify(...)`.\n\n### Receive, Process, And Delete Messages\n\n```js\nconst received = await queueClient.receiveMessages({\n  numberOfMessages: 10,\n});\n\nfor (const message of received.receivedMessageItems) {\n  const payload = message.messageText;\n  console.log(payload);\n\n  // Delete only after work succeeds.\n  await queueClient.deleteMessage(message.messageId, message.popReceipt);\n}\n```\n\nOperationally important:\n\n- Receiving a message does not remove it permanently.\n- The service hides the message for its visibility timeout.\n- If you do not delete it, the message can become visible again and be processed again.\n\n### Peek Without Taking A Processing Lease\n\n```js\nconst peeked = await queueClient.peekMessages({\n  numberOfMessages: 5,\n});\n\nfor (const message of peeked.peekedMessageItems) {\n  console.log(message.messageText);\n}\n```\n\nUse `peekMessages(...)` for inspection or diagnostics when you do not want to change normal consumer flow.\n\n### Update Message Content Or Visibility\n\n```js\nconst received = await queueClient.receiveMessages();\nconst message = received.receivedMessageItems[0];\n\nif (message) {\n  const updated = await queueClient.updateMessage(\n    message.messageId,\n    message.popReceipt,\n    JSON.stringify({ status: \"retrying\" }),\n    {\n      visibilityTimeout: 30,\n    },\n  );\n\n  console.log(updated.popReceipt);\n}\n```\n\nIf you update a message and then need to delete or update it again, use the latest `popReceipt` returned by the service.\n\n### List Queues From The Account\n\n```js\nfor await (const queue of serviceClient.listQueues()) {\n  console.log(queue.name);\n}\n```\n\nUse this from `QueueServiceClient` when you need inventory or lightweight administration code.\n\n## Practical Notes\n\n- Reuse long-lived clients instead of constructing a new client for every operation.\n- Use the queue endpoint form `https://<account>.queue.core.windows.net` for Entra ID or shared-key clients.\n- Prefer Microsoft Entra ID for deployed services when you can assign the right data-plane role.\n- Keep connection strings and account keys in environment variables or a secret manager, not in source code.\n- Treat message bodies as application text payloads; serialize and parse JSON yourself.\n\n## Common Pitfalls\n\n- Copying old examples built for the legacy `azure-storage` package or `QueueService` API.\n- Installing only `@azure/storage-queue` and then trying to use `DefaultAzureCredential` without `@azure/identity`.\n- Receiving messages and forgetting to delete them after successful processing.\n- Using the wrong endpoint; queue clients need the `queue.core.windows.net` endpoint.\n- Reusing an old `popReceipt` after `updateMessage(...)` changed it.\n\n## Version Notes For `12.29.0`\n\n- This guide targets `@azure/storage-queue` `12.29.0`.\n- Keep new code on `QueueServiceClient` and `QueueClient` from the 12.x package line.\n- If you find older samples that import `azure-storage` or call `QueueService`, rewrite them to the current package before copying code into an app.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-queue/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/storage-queue-readme?view=azure-node-latest`\n- `QueueServiceClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-queue/queueserviceclient?view=azure-node-latest`\n- `QueueClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/storage-queue/queueclient?view=azure-node-latest`\n- Azure Queue Storage quickstart for Node.js: `https://learn.microsoft.com/en-us/azure/storage/queues/storage-quickstart-queues-nodejs`\n- npm package page: `https://www.npmjs.com/package/@azure/storage-queue`\n"
  },
  {
    "path": "content/azure/docs/storage-queue/python/DOC.md",
    "content": "---\nname: storage-queue\ndescription: \"Azure Queue Storage SDK for Python with QueueServiceClient, QueueClient, and async support\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"azure,azure-storage,queue,storage,python\"\n---\n\n# azure-storage-queue Python Package Guide\n\n## Golden Rule\n\nUse `azure-storage-queue` for Azure Queue Storage, and write against the modern 12.x client surface:\n\n- `QueueServiceClient` for account-level operations\n- `QueueClient` for a specific queue\n- `azure.storage.queue.aio` for async code\n\nDo not mix this with legacy `QueueService` examples from old Azure Storage SDK posts or archived code.\n\n## Install\n\nPyPI for `12.15.0` lists `Requires: Python >=3.9`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"azure-storage-queue==12.15.0\"\n```\n\nIf you want Microsoft Entra ID authentication, install `azure-identity` too:\n\n```bash\npip install \"azure-storage-queue==12.15.0\" azure-identity\n```\n\nCommon dependency choices:\n\n- `azure-identity` for `DefaultAzureCredential`\n- `python-dotenv` if you load local env files yourself\n\n## Setup And Authentication\n\nThe SDK supports the three practical auth patterns most agents need:\n\n1. `DefaultAzureCredential` with an account URL\n2. Connection string for local development or simple service wiring\n3. Shared key or SAS when you already have those credentials\n\n### Option 1: Microsoft Entra ID with `DefaultAzureCredential`\n\nUse this for deployed apps running in Azure or local dev with Azure CLI / developer login already configured.\n\n```bash\nexport AZURE_STORAGE_QUEUE_ACCOUNT_URL=\"https://<account>.queue.core.windows.net\"\n```\n\n```python\nimport os\n\nfrom azure.identity import DefaultAzureCredential\nfrom azure.storage.queue import QueueServiceClient\n\nservice = QueueServiceClient(\n    account_url=os.environ[\"AZURE_STORAGE_QUEUE_ACCOUNT_URL\"],\n    credential=DefaultAzureCredential(),\n)\n```\n\nThe official quickstart uses this flow and requires a data-plane role such as `Storage Queue Data Contributor`.\n\n### Option 2: Connection String\n\nUse this for local tools, scripts, or when the environment already gives you a storage connection string.\n\n```bash\nexport AZURE_STORAGE_CONNECTION_STRING=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\nexport AZURE_STORAGE_QUEUE_NAME=\"jobs\"\n```\n\n```python\nimport os\n\nfrom azure.storage.queue import QueueClient\n\nqueue = QueueClient.from_connection_string(\n    conn_str=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n    queue_name=os.environ[\"AZURE_STORAGE_QUEUE_NAME\"],\n)\n```\n\nFor Azurite, the official readme documents `UseDevelopmentStorage=true;` support in this package line.\n\n### Option 3: Shared Key\n\nUse this when you explicitly manage account keys.\n\n```python\nfrom azure.core.credentials import AzureNamedKeyCredential\nfrom azure.storage.queue import QueueServiceClient\n\naccount_name = \"myaccount\"\ncredential = AzureNamedKeyCredential(account_name, \"<account-key>\")\n\nservice = QueueServiceClient(\n    account_url=f\"https://{account_name}.queue.core.windows.net\",\n    credential=credential,\n)\n```\n\n## Initialize Clients\n\nUse `QueueServiceClient` once, then derive queue-specific clients from it.\n\n```python\nfrom azure.storage.queue import QueueServiceClient\n\nservice = QueueServiceClient.from_connection_string(\n    conn_str=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\n)\n\nqueue = service.get_queue_client(\"jobs\")\n```\n\nThis is the cleanest pattern when the code touches multiple queues.\n\nIf the code only needs one queue, constructing `QueueClient` directly is fine.\n\n## Core Usage\n\n### Create A Queue If Needed\n\n```python\nfrom azure.core.exceptions import ResourceExistsError\n\ntry:\n    queue.create_queue()\nexcept ResourceExistsError:\n    pass\n```\n\n### Send Messages\n\n```python\nqueue.send_message(\"rebuild-search-index\")\nqueue.send_message('{\"job\":\"sync-users\",\"tenant\":\"acme\"}')\n```\n\nUse application-level JSON serialization for structured payloads.\n\n### Receive, Process, And Delete Messages\n\n```python\nmessages = queue.receive_messages(messages_per_page=10)\n\nfor message_batch in messages.by_page():\n    for message in message_batch:\n        payload = message.content\n        print(payload)\n\n        # Delete only after work succeeds.\n        queue.delete_message(message)\n```\n\nOperationally important:\n\n- Receiving a message does not remove it permanently.\n- The message stays leased for its visibility timeout, then can reappear if you do not delete it.\n- Delete only after the handler finishes successfully.\n\n### Peek Without Taking A Processing Lease\n\n```python\nfor message in queue.peek_messages(max_messages=5):\n    print(message.content)\n```\n\nUse `peek_messages` for inspection or diagnostics when you do not want to affect consumer flow.\n\n### Update A Message In Place\n\n```python\nmessages = queue.receive_messages()\nmessage = next(messages)\n\nqueue.update_message(\n    message=message,\n    content='{\"status\":\"retrying\"}',\n    visibility_timeout=30,\n)\n```\n\nUse this when the worker needs to extend visibility or change the payload before reprocessing.\n\n## Async Usage\n\nThe package includes async clients under `azure.storage.queue.aio`.\n\n```python\nimport os\nimport asyncio\n\nfrom azure.storage.queue.aio import QueueClient\n\nasync def main() -> None:\n    queue = QueueClient.from_connection_string(\n        conn_str=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n        queue_name=\"jobs\",\n    )\n\n    async with queue:\n        await queue.send_message(\"async-job\")\n\nasyncio.run(main())\n```\n\nUse the async surface when queue I/O is part of a larger async application. Do not mix sync clients into an async request path unless you intentionally want blocking I/O.\n\n## Configuration And Diagnostics\n\n### Logging\n\nThe official package readme enables HTTP logging through the Azure SDK logger:\n\n```python\nimport sys\nimport logging\n\nlogger = logging.getLogger(\"azure\")\nlogger.setLevel(logging.DEBUG)\nhandler = logging.StreamHandler(stream=sys.stdout)\nlogger.addHandler(handler)\n```\n\nTurn this on when debugging auth failures, retry behavior, or request signing issues.\n\n### Message Encoding\n\nAzure Queue Storage messages are XML-backed text payloads. If you need to send binary data or content that should be base64-encoded, set explicit encode/decode policies instead of assuming the SDK will do it automatically.\n\n```python\nfrom azure.storage.queue import (\n    BinaryBase64EncodePolicy,\n    BinaryBase64DecodePolicy,\n    QueueClient,\n)\n\nqueue = QueueClient.from_connection_string(\n    conn_str=\"UseDevelopmentStorage=true;\",\n    queue_name=\"jobs\",\n    message_encode_policy=BinaryBase64EncodePolicy(),\n    message_decode_policy=BinaryBase64DecodePolicy(),\n)\n```\n\n### Local Development\n\nFor Azurite, the documented shortcut is:\n\n```text\nUseDevelopmentStorage=true;\n```\n\nThat is safer than hand-assembling a fake endpoint string for local development.\n\n## Common Pitfalls\n\n### Confusing 12.x With The Legacy `QueueService` SDK\n\nCurrent official docs and PyPI pages are for the modern client library. If the code imports `QueueService`, you are in the old SDK generation and this doc does not apply.\n\n### Forgetting `azure-identity`\n\n`DefaultAzureCredential` examples require the separate `azure-identity` package. Installing only `azure-storage-queue` is not enough for credential-chain auth.\n\n### Receiving Without Deleting\n\n`receive_messages()` leases messages. If the worker never deletes them, they can become visible again and be processed twice.\n\n### Assuming Binary Payloads Just Work\n\nIf you pass bytes or non-XML-safe content, configure message encode/decode policies explicitly. Do not assume transparent base64 behavior.\n\n### Queue Name Rules\n\nQueue names are not arbitrary labels. Follow Azure Queue Storage naming rules from the service docs and keep names stable across producers and consumers.\n\n## Version-Sensitive Notes\n\n- PyPI shows `12.15.0` as the covered package version, released on `2026-01-07`.\n- The Microsoft Learn package readme for `azure-storage-queue` also targets `12.15.0`.\n- The official package page says `Requires: Python >=3.9`.\n- The older Azure Queue quickstart page still says Python `3.8` or later. Treat the package metadata as authoritative for environment pinning.\n- The official docs now include `UseDevelopmentStorage=true;` support for Azurite in this package line.\n\nWhen copying examples from blogs or old Azure answers, check whether they use `QueueService` or `QueueClient`. That is the fastest way to detect whether the example belongs to the wrong SDK generation.\n\n## Official Sources\n\n- Microsoft Learn package index: `https://learn.microsoft.com/en-us/python/api/azure-storage-queue/`\n- Microsoft Learn package readme: `https://learn.microsoft.com/en-us/python/api/overview/azure/storage-queue-readme?view=azure-python`\n- Microsoft Learn `QueueClient` reference: `https://learn.microsoft.com/en-us/python/api/azure-storage-queue/azure.storage.queue.queueclient?view=azure-python`\n- Microsoft Learn Azure Queue quickstart for Python: `https://learn.microsoft.com/en-us/azure/storage/queues/storage-quickstart-queues-python`\n- PyPI project page: `https://pypi.org/project/azure-storage-queue/`\n"
  },
  {
    "path": "content/azure/docs/web-pubsub/javascript/DOC.md",
    "content": "---\nname: web-pubsub\ndescription: \"Azure Web PubSub JavaScript service SDK for issuing client access URLs, sending server-side messages, and managing users and groups in a hub\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"azure,web-pubsub,realtime,websocket,javascript\"\n---\n\n# Azure Web PubSub JavaScript Service SDK\n\n## Golden Rule\n\nUse `@azure/web-pubsub` in trusted backend code only. Create one `WebPubSubServiceClient` per hub, use it to issue short-lived client access URLs with `getClientAccessToken(...)`, and reuse that same client for server-side messaging and group management. Do not ship the Azure Web PubSub connection string to browsers, mobile apps, or other untrusted clients.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @azure/web-pubsub@1.2.0\n```\n\n## Prerequisites\n\nBefore you initialize the SDK, have these values ready:\n\n- an Azure Web PubSub resource connection string\n- a hub name such as `chat` or `notifications`\n- a backend endpoint that can return a negotiated client URL to your app\n\nUse environment variables instead of hard-coding credentials:\n\n```bash\nexport AZURE_WEB_PUBSUB_CONNECTION_STRING=\"Endpoint=https://<resource-name>.webpubsub.azure.com;AccessKey=<access-key>;Version=1.0;\"\nexport AZURE_WEB_PUBSUB_HUB=\"chat\"\n```\n\n## Authentication And Setup\n\nThis package is the server-side management SDK. The common setup is a hub-scoped service client constructed from a connection string.\n\n```js\nimport { WebPubSubServiceClient } from \"@azure/web-pubsub\";\n\nconst connectionString = process.env.AZURE_WEB_PUBSUB_CONNECTION_STRING;\nconst hub = process.env.AZURE_WEB_PUBSUB_HUB ?? \"chat\";\n\nif (!connectionString) {\n  throw new Error(\"AZURE_WEB_PUBSUB_CONNECTION_STRING is required\");\n}\n\nexport const webPubSub = new WebPubSubServiceClient(connectionString, hub);\n```\n\nCreate a separate client for each hub your application manages. The hub is part of the server-side client configuration, so a client created for one hub does not operate on another.\n\n## Negotiate Client Connections\n\nThe normal browser or device flow is:\n\n1. your app calls a trusted backend route\n2. the backend calls `getClientAccessToken(...)`\n3. the backend returns the generated URL to the client\n4. the client connects to Azure Web PubSub with that URL\n\n```js\nimport express from \"express\";\nimport { webPubSub } from \"./web-pubsub.js\";\n\nconst app = express();\n\napp.get(\"/negotiate\", async (req, res) => {\n  const userId = String(req.query.userId ?? \"anonymous\");\n\n  const token = await webPubSub.getClientAccessToken({\n    userId,\n  });\n\n  res.json({\n    url: token.url,\n  });\n});\n```\n\nIf you need to bind a client identity to group or user-based operations, set `userId` when you create the access token. Keep negotiation on the server so the connection string stays private.\n\n## Send Messages From The Server\n\nUse the hub-scoped client to broadcast to every connection, target one user, or target one group.\n\n```js\nimport { webPubSub } from \"./web-pubsub.js\";\n\nawait webPubSub.sendToAll(\"service online\");\n\nawait webPubSub.sendToUser(\"user-123\", \"your export is ready\");\n\nawait webPubSub.sendToGroup(\"room-1\", \"welcome to room-1\");\n```\n\nThese operations are server-side pushes through Azure Web PubSub. They do not require your backend to hold open WebSocket connections itself.\n\n## Manage Group Membership\n\nUse group operations when your application models rooms, channels, or topic-based fan-out.\n\n```js\nimport { webPubSub } from \"./web-pubsub.js\";\n\nawait webPubSub.group(\"room-1\").addUser(\"user-123\");\n\nawait webPubSub.group(\"room-1\").removeUser(\"user-123\");\n```\n\nThis is useful when you issue client URLs with stable user IDs and later want the server to attach or detach that user from a group.\n\n## Practical Notes\n\n- Treat `WebPubSubServiceClient` as a long-lived backend object; do not recreate it for every request.\n- Keep one hub name per client instance so your code does not accidentally mix chat, notification, or tenant-specific traffic.\n- Use `getClientAccessToken(...)` as the server-side handshake step for frontend or device connections.\n- Use `sendToUser(...)` when one logical user may have multiple active connections and all of them should receive the event.\n- Use `sendToGroup(...)` plus server-managed group membership when you need room-style broadcast behavior.\n\n## Common Pitfalls\n\n- Treating `@azure/web-pubsub` as a browser client SDK. This package is the server-side service SDK.\n- Exposing `AZURE_WEB_PUBSUB_CONNECTION_STRING` to frontend code instead of returning only the negotiated client URL.\n- Creating a new `WebPubSubServiceClient` inside every route handler rather than reusing a shared instance.\n- Using the wrong hub name and then wondering why user targeting or group membership appears to do nothing.\n- Assuming users or groups are shared across hubs. Hub boundaries matter for negotiation, user targeting, and group operations.\n\n## Version Notes For `1.2.0`\n\n- This guide targets `@azure/web-pubsub` `1.2.0`.\n- The examples here use the package's server-side `WebPubSubServiceClient` API.\n- Client connection code belongs in your frontend or device app, but the access URL generation shown here stays on the server.\n\n## Official Sources\n\n- API reference root: `https://learn.microsoft.com/en-us/javascript/api/@azure/web-pubsub/`\n- Overview README: `https://learn.microsoft.com/en-us/javascript/api/overview/azure/web-pubsub-readme?view=azure-node-latest`\n- `WebPubSubServiceClient` reference: `https://learn.microsoft.com/en-us/javascript/api/@azure/web-pubsub/webpubsubserviceclient?view=azure-node-latest`\n- npm package page: `https://www.npmjs.com/package/@azure/web-pubsub`\n"
  },
  {
    "path": "content/babel/docs/helper-environment-visitor/javascript/DOC.md",
    "content": "---\nname: helper-environment-visitor\ndescription: \"Babel helper for traversing only the current lexical environment when writing custom transforms and plugins\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.24.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,ast,traverse,plugin\"\n---\n\n# @babel/helper-environment-visitor\n\n`@babel/helper-environment-visitor` is a small Babel helper for plugin authors. It gives you a prebuilt visitor that stays inside the current environment while traversing: nested non-arrow functions are skipped, arrow functions are still visited, and class members are skipped so Babel can handle computed keys correctly.\n\nUse it when you need to find or rewrite nodes such as `this`, `super`, `arguments`, or `new.target` for the current environment only. It is not a runtime library, has no CLI, and does not use environment variables or credentials.\n\n## Install\n\nInstall it alongside the Babel packages you already use for parsing or traversal:\n\n```bash\nnpm install --save-dev @babel/core @babel/traverse @babel/helper-environment-visitor\n```\n\nIf you want a standalone script example like the one below, add the parser too:\n\n```bash\nnpm install --save-dev @babel/parser\n```\n\nKeep related Babel packages on the same version family when possible.\n\n## What the helper does\n\nThe exported `environmentVisitor` is meant to be merged with your own visitor:\n\n```javascript\nimport traverse from \"@babel/traverse\";\nimport environmentVisitor from \"@babel/helper-environment-visitor\";\n\nconst visitor = traverse.visitors.merge([\n  environmentVisitor,\n  {\n    ThisExpression(path) {\n      // handle `this` only in the current environment\n    },\n  },\n]);\n```\n\nThis matters because a naive traversal will walk into nested functions and may rewrite bindings that belong to a different environment.\n\nFrom Babel's implementation, the helper:\n\n- skips nested function parents except arrow functions\n- keeps traversing arrow functions because they inherit the enclosing environment\n- skips non-object `Property` paths such as class members\n- lets Babel revisit computed keys when those members are skipped\n\n## Common workflow: inspect `this` in one function environment\n\nThis standalone example collects `this` references for one function without walking into nested non-arrow functions:\n\n```javascript\nimport { parse } from \"@babel/parser\";\nimport traverse from \"@babel/traverse\";\nimport environmentVisitor from \"@babel/helper-environment-visitor\";\n\nconst source = `\nfunction outer() {\n  console.log(this);\n\n  const arrow = () => this;\n\n  function inner() {\n    return this;\n  }\n}\n`;\n\nconst ast = parse(source, {\n  sourceType: \"module\",\n});\n\nconst thisLocations = [];\n\ntraverse(ast, {\n  FunctionDeclaration(path) {\n    if (path.node.id?.name !== \"outer\") return;\n\n    path.traverse(\n      traverse.visitors.merge([\n        environmentVisitor,\n        {\n          ThisExpression(thisPath) {\n            thisLocations.push(thisPath.node.start);\n          },\n        },\n      ]),\n    );\n  },\n});\n\nconsole.log(thisLocations);\n```\n\nIn this example, the helper visits `this` in `outer` and in the nested arrow function, but it does not walk into `inner()` because `inner` has its own environment.\n\n## Use it inside a Babel plugin\n\nThis is the usual pattern in plugin code: enter a scope boundary, then run a merged traversal underneath it.\n\n```javascript\nimport { types as t } from \"@babel/core\";\nimport traverse from \"@babel/traverse\";\nimport environmentVisitor from \"@babel/helper-environment-visitor\";\n\nexport default function replaceTopLevelThis() {\n  return {\n    name: \"replace-top-level-this\",\n    visitor: {\n      Function(path) {\n        path.traverse(\n          traverse.visitors.merge([\n            environmentVisitor,\n            {\n              ThisExpression(thisPath) {\n                thisPath.replaceWith(t.identifier(\"globalThis\"));\n              },\n            },\n          ]),\n        );\n      },\n    },\n  };\n}\n```\n\nRegister the plugin with Babel as usual:\n\n```json\n{\n  \"plugins\": [\"./plugins/replace-top-level-this.js\"]\n}\n```\n\n## Be careful with class members and computed keys\n\nFrom Babel's implementation, this helper skips class members and preserves traversal of computed keys when they are evaluated in the enclosing environment.\n\nThat means this pattern stays safe:\n\n```javascript\nconst visitor = traverse.visitors.merge([\n  environmentVisitor,\n  {\n    ThisExpression(path) {\n      // your transform logic here\n    },\n  },\n]);\n```\n\nBut if you add your own `ClassMethod`, `ClassProperty`, or related member visitors that call `path.skip()`, make sure you do not accidentally suppress computed key traversal for code such as:\n\n```javascript\nclass Example {\n  [sideEffect()]() {}\n}\n```\n\nIn other words, let `environmentVisitor` own the environment-boundary behavior unless you have a specific reason to override it.\n\n## Important notes\n\n- This package is for Babel plugin and transform authors, not normal application runtime code.\n- It does not replace `@babel/traverse`; it complements it.\n- `environmentVisitor` is most useful when you would otherwise accidentally cross into a nested function environment.\n- Be careful when overriding class-member visitors, because computed keys are evaluated outside the member body.\n- Keep your Babel packages aligned. Mixing widely different Babel versions can produce missing helper APIs or traversal differences.\n\n## Version notes\n\nThis guide targets `@babel/helper-environment-visitor` `7.24.7`.\n\nNewer Babel packages also expose equivalent environment-aware traversal helpers from `@babel/traverse` under `traverse.visitors`. If your codebase already uses that newer API surface, prefer the API that matches the Babel version you have installed instead of mixing helper patterns from different releases.\n"
  },
  {
    "path": "content/babel/docs/helper-module-imports/javascript/DOC.md",
    "content": "---\nname: helper-module-imports\ndescription: \"Babel helper for inserting import and require statements in custom transforms and plugins\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,ast,plugin,imports\"\n---\n\n# @babel/helper-module-imports\n\n`@babel/helper-module-imports` is a Babel plugin-authoring helper for adding module loads to the file you are transforming. It can insert default, named, namespace, and side-effect imports, and it returns the AST expression you can reuse in your transform.\n\nUse it inside Babel plugins or codemods when you need Babel to generate the right `import` or `require(...)` form for the current file. The package does not have a CLI, client object, auth flow, or environment variables.\n\n## Install\n\nFor local plugin or transform work:\n\n```bash\nnpm install --save-dev @babel/core @babel/helper-module-imports\n```\n\nIf you are publishing a Babel plugin that imports this package at runtime, keep it in that plugin's regular dependencies.\n\n## What it exports\n\nThe package exports these helpers:\n\n```javascript\nimport {\n  addDefault,\n  addNamed,\n  addNamespace,\n  addSideEffect,\n  ImportInjector,\n  isModule,\n} from \"@babel/helper-module-imports\";\n```\n\nThe top-level helpers are usually enough:\n\n- `addDefault(path, source, opts)`\n- `addNamed(path, importName, source, opts)`\n- `addNamespace(path, source, opts)`\n- `addSideEffect(path, source, opts)`\n\nYou can call them from any visitor path. The helper walks up to the enclosing `Program` and inserts statements there.\n\n## Common workflow: add one import and reuse it\n\nThis example rewrites `console.log(...)` to a named import from a local logger module:\n\n```javascript\nimport { transformSync, types as t } from \"@babel/core\";\nimport { addNamed } from \"@babel/helper-module-imports\";\n\nfunction rewriteConsoleLog() {\n  return {\n    name: \"rewrite-console-log\",\n    visitor: {\n      Program(path, state) {\n        state.logId = null;\n      },\n\n      CallExpression(path, state) {\n        if (!path.get(\"callee\").matchesPattern(\"console.log\")) return;\n\n        if (!state.logId) {\n          state.logId = addNamed(path, \"log\", \"./logger.js\", {\n            nameHint: \"log\",\n          });\n        }\n\n        path.node.callee = t.cloneNode(state.logId);\n      },\n    },\n  };\n}\n\nconst result = transformSync('console.log(\"hello\")', {\n  configFile: false,\n  babelrc: false,\n  plugins: [rewriteConsoleLog],\n});\n\nconsole.log(result.code);\n```\n\nIn an ES module input file, Babel inserts an `import { log as _log } from \"./logger.js\";`-style declaration near the top of the program. In a non-module file, it uses a `require(...)`-based form instead.\n\n## Add the other import forms\n\n```javascript\nimport {\n  addDefault,\n  addNamed,\n  addNamespace,\n  addSideEffect,\n} from \"@babel/helper-module-imports\";\n\nexport default function examplePlugin() {\n  return {\n    name: \"example-plugin\",\n    visitor: {\n      Program(path) {\n        const lodashId = addDefault(path, \"lodash\", {\n          nameHint: \"lodash\",\n        });\n\n        const readFileId = addNamed(path, \"readFile\", \"node:fs/promises\", {\n          nameHint: \"readFile\",\n          importedType: \"es6\",\n        });\n\n        const helpersId = addNamespace(path, \"./helpers.js\", {\n          importedType: \"es6\",\n          nameHint: \"helpers\",\n        });\n\n        addSideEffect(path, \"./register-globals.js\");\n\n        void lodashId;\n        void readFileId;\n        void helpersId;\n      },\n    },\n  };\n}\n```\n\nUse these forms when you need Babel to manage unique local identifiers and place imports consistently with the rest of the file.\n\n## Options that change generated code\n\nThese options are supported by the package source in `7.28.6`:\n\n```javascript\nconst helperId = addDefault(path, \"./legacy-helper.cjs\", {\n  nameHint: \"legacyHelper\",\n  importedType: \"commonjs\",\n  importedInterop: \"babel\",\n  importingInterop: \"babel\",\n  ensureLiveReference: false,\n  ensureNoContext: false,\n  importPosition: \"before\",\n});\n```\n\n- `nameHint`: prefixes the generated local variable name.\n- `importedType`: use `\"commonjs\"` (default) or `\"es6\"`.\n- `importedInterop`: for CommonJS imports, the implementation handles `\"babel\"` (default), `\"compiled\"`, and `\"uncompiled\"`.\n- `importingInterop`: set how the generated output will be interpreted, either `\"babel\"` (default) or `\"node\"`.\n- `ensureLiveReference`: for default or named imports, prefer a live property access instead of copying the current value.\n- `ensureNoContext`: if the generated result is a property access, wrap it as `(0, expr)` so you can call it without preserving object context.\n- `importPosition`: `\"before\"` by default; `\"after\"` appends after existing value imports in ES modules.\n\n## Check whether the file is a module\n\nThe exported `isModule` helper is a small convenience for branching on `sourceType`:\n\n```javascript\nimport { addSideEffect, isModule } from \"@babel/helper-module-imports\";\n\nexport default function conditionalImportPlugin() {\n  return {\n    name: \"conditional-import-plugin\",\n    visitor: {\n      Program(path) {\n        if (!isModule(path)) return;\n\n        addSideEffect(path, \"./instrumentation.js\", {\n          importPosition: \"after\",\n        });\n      },\n    },\n  };\n}\n```\n\n`isModule(path)` returns `true` when `path.node.sourceType === \"module\"`.\n\n## Important notes\n\n- The helper chooses between `import` and `require(...)` based on the transformed file's `Program.sourceType`.\n- `importPosition: \"after\"` only works in modules. In CommonJS or script files, the package throws an error.\n- `importedType: \"es6\"` only works when the file is a module. Importing an ES module from CommonJS throws.\n- `addDefault()` and `addNamed()` do not always return a plain identifier. With options such as `ensureLiveReference` or `ensureNoContext`, the result can be a `MemberExpression` or `SequenceExpression`.\n- If you reuse the returned node in more than one replacement, clone it with `t.cloneNode(...)` before inserting it multiple times. Babel's own plugins use this pattern.\n- When adding compatible imports from the same source, the helper can append specifiers to an existing value import instead of emitting a duplicate declaration.\n- Only use `importedInterop: \"compiled\"` when the imported CommonJS module is known to come from ES module compilation. Only use `\"uncompiled\"` when it is plain CommonJS. The wrong choice produces the wrong property access pattern.\n"
  },
  {
    "path": "content/babel/docs/helper-plugin-utils/javascript/DOC.md",
    "content": "---\nname: helper-plugin-utils\ndescription: \"Wrap Babel plugins and presets with a stable builder API, version checks, and normalized options handling\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,plugin,preset,ast,javascript\"\n---\n\n# @babel/helper-plugin-utils\n\n`@babel/helper-plugin-utils` is a small package for Babel plugin and preset authors. It exports `declare` and `declarePreset`, which wrap your builder function so Babel passes a consistent `api`, a defaulted `options` object, and the current `dirname`.\n\nUse it when you are publishing a custom Babel plugin or preset. It has no CLI, no environment variables, and no authentication setup.\n\n## Install\n\nInstall the helper alongside `@babel/core`.\n\n```bash\nnpm install --save-dev @babel/core @babel/helper-plugin-utils\n```\n\nIf you are authoring a preset that re-exports Babel plugins, install those packages too:\n\n```bash\nnpm install --save-dev @babel/core @babel/helper-plugin-utils @babel/plugin-transform-arrow-functions\n```\n\nKeep `@babel/core` and Babel helper packages on the same version family when possible.\n\n## Create a plugin with `declare`\n\nThis is the common pattern for Babel plugins:\n\n```javascript\nimport { declare } from \"@babel/helper-plugin-utils\";\n\nexport default declare((api, options, dirname) => {\n  api.assertVersion(7);\n\n  const { replace = \"production\" } = options;\n\n  return {\n    name: \"replace-dev-constant\",\n    visitor: {\n      Identifier(path) {\n        if (path.node.name !== \"__BUILD_TARGET__\") return;\n        path.replaceWithSourceString(JSON.stringify(replace));\n      },\n    },\n  };\n});\n```\n\nWhat the wrapper gives you:\n\n- `api.assertVersion(...)` for an explicit `@babel/core` compatibility check\n- `options` defaulted to `{}` when Babel does not pass plugin options\n- `dirname` as the third argument when you need to resolve local files\n\n## Use the plugin from Babel\n\nPass the wrapped plugin function to Babel like any other plugin:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\nimport replaceDevConstant from \"./replace-dev-constant.js\";\n\nconst result = transformSync(\"const target = __BUILD_TARGET__;\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[replaceDevConstant, { replace: \"staging\" }]],\n});\n\nconsole.log(result.code);\n```\n\nYou can also reference it from a Babel config file:\n\n```javascript\nmodule.exports = {\n  plugins: [[\"./replace-dev-constant.js\", { replace: \"staging\" }]],\n};\n```\n\n## Create a preset with `declarePreset`\n\n`declarePreset` is the same wrapper, but it is intended for presets that return a Babel preset object.\n\n```javascript\nimport { declarePreset } from \"@babel/helper-plugin-utils\";\nimport transformArrowFunctions from \"@babel/plugin-transform-arrow-functions\";\n\nexport default declarePreset((api, options) => {\n  api.assertVersion(7);\n\n  const { enableArrowTransform = true } = options;\n\n  return {\n    plugins: [enableArrowTransform && transformArrowFunctions].filter(Boolean),\n  };\n});\n```\n\nIf your preset needs to resolve files relative to itself, use the third `dirname` argument:\n\n```javascript\nimport path from \"node:path\";\nimport { declarePreset } from \"@babel/helper-plugin-utils\";\n\nexport default declarePreset((api, options, dirname) => {\n  api.assertVersion(7);\n\n  return {\n    plugins: [path.resolve(dirname, \"./plugins/my-plugin.js\")],\n  };\n});\n```\n\n## Common API patterns\n\n### Require a specific Babel major\n\n`assertVersion` accepts an integer or a semver range string.\n\n```javascript\nimport { declare } from \"@babel/helper-plugin-utils\";\n\nexport default declare((api) => {\n  api.assertVersion(\"^7.0.0-0 || ^8.0.0-0\");\n\n  return {\n    name: \"my-plugin\",\n    visitor: {},\n  };\n});\n```\n\nUse an integer when you only need a major check:\n\n```javascript\napi.assertVersion(7);\n```\n\n### Read options safely\n\nThe helper passes `options || {}` to your builder, so destructuring is safe even when the plugin is used without options.\n\n```javascript\nimport { declare } from \"@babel/helper-plugin-utils\";\n\nexport default declare((api, options) => {\n  api.assertVersion(7);\n\n  const { loose = false } = options;\n\n  return {\n    name: \"my-plugin\",\n    visitor: {},\n  };\n});\n```\n\n## Important notes\n\n- Use this package for authoring Babel plugins and presets, not for transforming code by itself.\n- Call `api.assertVersion(...)` near the top of your builder so version mismatches fail early and clearly.\n- `declarePreset` is an alias of `declare`; use it when exporting a preset because the intent is clearer.\n- The helper normalizes several Babel API methods when an older `@babel/core` instance does not provide them. In that fallback path, `targets()` returns `{}`, `assumption()` returns `undefined`, and `addExternalDependency()` is a no-op.\n- If Babel loads an unsupported core version, the helper throws an error with code `BABEL_VERSION_UNSUPPORTED`.\n- There are no package-specific environment variables, credentials, or runtime initialization steps.\n"
  },
  {
    "path": "content/babel/docs/helper-string-parser/javascript/DOC.md",
    "content": "---\nname: helper-string-parser\ndescription: \"Babel helper for parsing JavaScript string literal contents, numeric fragments, and Unicode escape code points\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,parser,strings,unicode\"\n---\n\n# @babel/helper-string-parser\n\n`@babel/helper-string-parser` is a low-level Babel utility for decoding JavaScript string literal contents and escape fragments while you keep track of parser state. In `7.27.1`, it exports three functions:\n\n- `readStringContents(...)`\n- `readInt(...)`\n- `readCodePoint(...)`\n\nUse it when you are building a tokenizer, parser, Babel extension, or codemod that already tracks the current source index. This package is not a Babel plugin and does not read Babel config files.\n\n## Install\n\n```bash\nnpm install @babel/helper-string-parser\n```\n\nThe published package for `7.27.1` is CommonJS, so the examples below use `require()`.\n\n## Prerequisites\n\n- No environment variables, auth, or client initialization are required.\n- You must pass the current `pos`, `lineStart`, and `curLine` for the source you are parsing.\n- You must provide the error-handler callbacks each helper expects.\n\n## Define shared error handlers\n\n```javascript\nconst {\n  readCodePoint,\n  readInt,\n  readStringContents,\n} = require(\"@babel/helper-string-parser\");\n\nfunction syntaxError(message, pos, lineStart, curLine) {\n  const column = pos - lineStart;\n  throw new SyntaxError(`${message} at line ${curLine}, column ${column}`);\n}\n\nconst errors = {\n  unterminated(pos, lineStart, curLine) {\n    syntaxError(\"Unterminated string\", pos, lineStart, curLine);\n  },\n  strictNumericEscape(pos, lineStart, curLine) {\n    syntaxError(\"Legacy numeric escape is not allowed here\", pos, lineStart, curLine);\n  },\n  invalidEscapeSequence(pos, lineStart, curLine) {\n    syntaxError(\"Invalid escape sequence\", pos, lineStart, curLine);\n  },\n  invalidCodePoint(pos, lineStart, curLine) {\n    syntaxError(\"Invalid Unicode code point\", pos, lineStart, curLine);\n  },\n  numericSeparatorInEscapeSequence(pos, lineStart, curLine) {\n    syntaxError(\"Numeric separator is not allowed in an escape sequence\", pos, lineStart, curLine);\n  },\n  unexpectedNumericSeparator(pos, lineStart, curLine) {\n    syntaxError(\"Unexpected numeric separator\", pos, lineStart, curLine);\n  },\n  invalidDigit(pos, lineStart, curLine, radix) {\n    syntaxError(`Invalid base-${radix} digit`, pos, lineStart, curLine);\n  },\n};\n```\n\nIf you want recovery instead of an immediate throw, `invalidDigit(...)` can return `true` so parsing continues.\n\n## Read quoted string contents\n\nCall `readStringContents(type, input, pos, lineStart, curLine, errors)` with `pos` set to the first character after the opening quote.\n\n```javascript\nconst source = '\"hello\\\\nworld\";';\n\nconst result = readStringContents(\"double\", source, 1, 0, 1, errors);\n\nconsole.log(result.str);\n// hello\n// world\n\nconsole.log(result.pos); // 13\nconsole.log(result.containsInvalid); // false\n```\n\nUse `\"single\"`, `\"double\"`, or `\"template\"` for the first argument.\n\n## Read a template literal chunk\n\nIn template mode, `readStringContents(...)` stops before either the closing backtick or `${`.\n\n```javascript\nconst source = '`hi${name}`';\n\nconst result = readStringContents(\"template\", source, 1, 0, 1, errors);\n\nconsole.log(result.str); // hi\nconsole.log(result.pos); // 3, the `$` before `${`\n```\n\nTemplate mode also keeps going when it finds an invalid escape and reports the first bad location on the return value:\n\n```javascript\nconst invalid = readStringContents(\"template\", '`\\\\8`', 1, 0, 1, errors);\n\nconsole.log(invalid.firstInvalidLoc);\n// { pos: 1, lineStart: 0, curLine: 1 }\n\nconsole.log(invalid.containsInvalid); // true\n```\n\n## Parse integer fragments\n\n`readInt(...)` parses digits only. If your language syntax has a prefix such as `0x`, `0o`, or `0b`, skip that prefix before calling the helper.\n\n```javascript\nconst hex = readInt(\"0xff;\", 2, 0, 1, 16, undefined, false, false, errors, false);\n\nconsole.log(hex.n); // 255\nconsole.log(hex.pos); // 4\n\nconst dec = readInt(\"1_000;\", 0, 0, 1, 10, undefined, false, true, errors, false);\n\nconsole.log(dec.n); // 1000\nconsole.log(dec.pos); // 5\n```\n\nParameter meanings:\n\n- `radix` is the numeric base to parse.\n- `len` limits how many digits to read. Use `undefined` for an open-ended read.\n- `forceLen` requires exactly `len` digits.\n- `allowNumSeparator` can be `true`, `false`, or `\"bail\"`.\n- `bailOnError` returns `{ n: null, pos }` for some invalid cases instead of calling the error handler.\n\nUse `allowNumSeparator: \"bail\"` when you want parsing to stop at `_` and let your caller decide what to do next.\n\n## Parse Unicode escape code points\n\n`readCodePoint(...)` expects input starting immediately after `\\u`.\n\n```javascript\nconst braced = readCodePoint(\"{1F600}\", 0, 0, 1, true, errors);\n\nconsole.log(braced.code); // 128512\nconsole.log(String.fromCodePoint(braced.code)); // 😀\n\nconst short = readCodePoint(\"0041\", 0, 0, 1, true, errors);\n\nconsole.log(short.code); // 65\nconsole.log(String.fromCodePoint(short.code)); // A\n```\n\nPass `throwOnInvalid: false` when you want invalid escapes to return `{ code: null, pos }` instead of raising through the error handlers.\n\n## Important pitfalls\n\n- Start `pos` after the opening delimiter or numeric prefix; none of these helpers skip it for you.\n- `readStringContents(\"template\", ...)` stops before `${`, so your parser still needs to consume the expression boundary.\n- Raw line breaks are only accepted in template mode. In single-quoted and double-quoted strings, they trigger `unterminated(...)`.\n- In template mode, CRLF and CR line breaks are normalized to `\\n` in the returned `str`.\n- `readInt(...)` returns a number and the next position, but it does not attach source text or numeric kind metadata.\n- `readCodePoint(...)` returns a numeric code point, not a JavaScript string. Convert it with `String.fromCodePoint(...)` when you need the character.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/helper-string-parser@7.27.1`.\n- The published package declares `node >= 6.9.0` in `engines`.\n- In `7.27.1`, the package exports CommonJS from `lib/index.js`.\n- In `7.27.1`, `readStringContents(...)` returns `containsInvalid`; the published source also contains a Babel 8 compatibility branch gated by `process.env.BABEL_8_BREAKING`.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-helper-string-parser\n- npm package page: https://www.npmjs.com/package/@babel/helper-string-parser\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-helper-string-parser\n"
  },
  {
    "path": "content/babel/docs/helper-validator-identifier/javascript/DOC.md",
    "content": "---\nname: helper-validator-identifier\ndescription: \"Babel helper for checking whether strings and code points are valid JavaScript identifiers, keywords, and reserved words\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,identifiers,parser\"\n---\n\n# @babel/helper-validator-identifier\n\n`@babel/helper-validator-identifier` is a small utility package from Babel for validating JavaScript identifier names and checking whether a word is reserved in different language contexts. It is a library, not a Babel plugin: there are no environment variables, auth steps, Babel presets, or runtime clients to initialize.\n\nUse it when you are generating code, validating user-provided symbol names, or implementing parser or transform tooling that needs Babel's identifier and reserved-word checks.\n\n## Install\n\nInstall it in the package where your build tooling or code-generation logic runs:\n\n```bash\nnpm install @babel/helper-validator-identifier\n```\n\nThe published `7.28.5` package exposes a CommonJS entrypoint.\n\n## Import the helpers\n\n```javascript\nconst {\n  isIdentifierName,\n  isIdentifierStart,\n  isIdentifierChar,\n  isKeyword,\n  isReservedWord,\n  isStrictReservedWord,\n  isStrictBindOnlyReservedWord,\n  isStrictBindReservedWord,\n} = require(\"@babel/helper-validator-identifier\");\n```\n\n## Validate a full identifier name\n\nUse `isIdentifierName(name)` when you want to check whether a string is lexically a valid JavaScript identifier name:\n\n```javascript\nconst { isIdentifierName } = require(\"@babel/helper-validator-identifier\");\n\nconsole.log(isIdentifierName(\"userName\"));\nconsole.log(isIdentifierName(\"$value\"));\nconsole.log(isIdentifierName(\"π\"));\nconsole.log(isIdentifierName(\"1stPlace\"));\nconsole.log(isIdentifierName(\"has-dash\"));\n```\n\nExpected results:\n\n```javascript\ntrue\ntrue\ntrue\nfalse\nfalse\n```\n\n`isIdentifierName()` handles Unicode identifier characters, including astral code points.\n\n## Do not use `isIdentifierName()` by itself for variable names\n\nAn identifier name can still be unusable in source code if it is a keyword or reserved word.\n\nFor example, `for` is a valid identifier name lexically, but it is still a keyword:\n\n```javascript\nconst {\n  isIdentifierName,\n  isKeyword,\n} = require(\"@babel/helper-validator-identifier\");\n\nconsole.log(isIdentifierName(\"for\"));\nconsole.log(isKeyword(\"for\"));\n```\n\nExpected results:\n\n```javascript\ntrue\ntrue\n```\n\nIf you are validating names for declarations or generated bindings, combine the identifier and reserved-word checks.\n\n## Check whether a name is safe for a binding\n\nFor strict-mode bindings such as generated variable or parameter names, `isStrictBindReservedWord(word, inModule)` is usually the safest high-level check to combine with `isIdentifierName()`:\n\n```javascript\nconst {\n  isIdentifierName,\n  isStrictBindReservedWord,\n} = require(\"@babel/helper-validator-identifier\");\n\nfunction canUseAsBinding(name, { inModule = true } = {}) {\n  return isIdentifierName(name) && !isStrictBindReservedWord(name, inModule);\n}\n\nconsole.log(canUseAsBinding(\"userName\"));\nconsole.log(canUseAsBinding(\"await\", { inModule: true }));\nconsole.log(canUseAsBinding(\"eval\", { inModule: false }));\n```\n\nExpected results:\n\n```javascript\ntrue\nfalse\nfalse\n```\n\nThis catches several cases that `isIdentifierName()` alone does not:\n\n- keywords such as `for` and `class`\n- strict reserved words such as `let` and `yield`\n- strict binding-only reserved words such as `eval` and `arguments`\n- `await` when you are validating module code (`inModule: true`)\n\n## Module-sensitive reserved words\n\n`isReservedWord(word, inModule)` and the strict variants use the `inModule` flag to distinguish module parsing rules from script parsing rules.\n\n```javascript\nconst {\n  isReservedWord,\n  isStrictReservedWord,\n} = require(\"@babel/helper-validator-identifier\");\n\nconsole.log(isReservedWord(\"await\", false));\nconsole.log(isReservedWord(\"await\", true));\nconsole.log(isReservedWord(\"enum\", false));\nconsole.log(isStrictReservedWord(\"let\", false));\n```\n\nExpected results:\n\n```javascript\nfalse\ntrue\ntrue\ntrue\n```\n\nUse `inModule: true` when you are validating source that will be parsed as an ECMAScript module.\n\n## Validate individual code points\n\nUse `isIdentifierStart(code)` and `isIdentifierChar(code)` when you are tokenizing or validating one character at a time. These functions expect a numeric Unicode code point.\n\n```javascript\nconst {\n  isIdentifierStart,\n  isIdentifierChar,\n} = require(\"@babel/helper-validator-identifier\");\n\nconsole.log(isIdentifierStart(\"$\".codePointAt(0)));\nconsole.log(isIdentifierStart(\"1\".codePointAt(0)));\nconsole.log(isIdentifierStart(\"π\".codePointAt(0)));\nconsole.log(isIdentifierChar(\"9\".codePointAt(0)));\nconsole.log(isIdentifierChar(\"-\".codePointAt(0)));\n```\n\nExpected results:\n\n```javascript\ntrue\nfalse\ntrue\ntrue\nfalse\n```\n\nWhen you are working with characters outside the basic multilingual plane, use `codePointAt(0)` rather than `charCodeAt(0)` so you pass the full Unicode code point.\n\n## Common patterns\n\n- Use `isIdentifierName()` when you already have the whole string and only need lexical validity.\n- Use `isIdentifierStart()` and `isIdentifierChar()` when you are scanning source text incrementally.\n- Use `isKeyword()` when you want to reject JavaScript keywords specifically.\n- Use `isReservedWord()` or `isStrictReservedWord()` when parsing rules depend on strict mode or module context.\n- Use `isStrictBindReservedWord()` when you need a conservative check for generated binding names.\n\n## Important notes\n\n- This package does not expose a CLI.\n- It does not read environment variables or require Babel configuration.\n- The published `7.28.5` package declares `node >= 6.9.0` and ships a CommonJS entrypoint.\n- In the published package, `isReservedWord()` only treats `await` as reserved when `inModule` is `true`; `enum` is always treated as reserved.\n- `isStrictBindOnlyReservedWord()` is narrower than `isStrictBindReservedWord()`: it only checks words such as `eval` and `arguments` that are disallowed for strict bindings but can still appear as normal identifiers in other contexts.\n"
  },
  {
    "path": "content/babel/docs/plugin-proposal-decorators/javascript/DOC.md",
    "content": "---\nname: plugin-proposal-decorators\ndescription: \"Configure Babel 7 decorators support with the current proposal or legacy mode\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.29.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,decorators,classes,syntax,proposal\"\n---\n\n# @babel/plugin-proposal-decorators\n\n`@babel/plugin-proposal-decorators` adds Babel support for JavaScript decorators.\n\nConfiguration lives entirely in Babel. There are no environment variables, authentication steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to compile from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-proposal-decorators\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Enable the plugin in Babel config\n\nSet the plugin explicitly and choose a decorators version. For new code on Babel `7.29.0`, use `\"2023-11\"`.\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"version\": \"2023-11\"\n      }\n    ]\n  ]\n}\n```\n\nUse that for code shaped like this:\n\n```javascript\nfunction logged(value, context) {\n  if (context.kind !== \"method\") return value;\n\n  return function (...args) {\n    console.log(`calling ${String(context.name)}`);\n    return value.call(this, ...args);\n  };\n}\n\nclass Service {\n  @logged\n  run(task) {\n    return task.toUpperCase();\n  }\n}\n```\n\n## Compile from the CLI\n\nWith a `babel.config.json` file in place:\n\n```bash\nnpx babel src --out-dir lib\n```\n\nOr compile a single file:\n\n```bash\nnpx babel input.js --out-file output.js\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nfunction logged(value, context) {\n  if (context.kind !== \"method\") return value;\n\n  return function (...args) {\n    console.log(\\`calling \\${String(context.name)}\\`);\n    return value.call(this, ...args);\n  };\n}\n\nclass Service {\n  @logged\n  run(task) {\n    return task.toUpperCase();\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-proposal-decorators\", {\n    version: \"2023-11\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\n## Choose the right decorators version\n\nIn Babel `7.29.0`, the plugin supports multiple proposal snapshots plus `legacy` mode.\n\n- Use `\"2023-11\"` for new code.\n- Use `\"legacy\"` only when you are already committed to Babel's legacy decorators behavior.\n- Use older proposal snapshots such as `\"2023-05\"`, `\"2023-01\"`, `\"2022-03\"`, `\"2021-12\"`, or `\"2018-09\"` only to match an existing codebase that already depends on that exact proposal version.\n\nLegacy mode looks like this:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"version\": \"legacy\"\n      }\n    ]\n  ]\n}\n```\n\nFor codebases that still rely on the older `2018-09` proposal shape, Babel also supports `decoratorsBeforeExport`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"version\": \"2018-09\",\n        \"decoratorsBeforeExport\": true\n      }\n    ]\n  ]\n}\n```\n\nAvoid `decoratorsBeforeExport` in new configs. Current decorators configs should set `version` directly.\n\n## Common workflow: decorators with class fields\n\nIf the same build also transforms class fields, private methods, or related class features, load the decorators plugin first.\n\nFor legacy decorators with class fields, keep the decorators plugin before `@babel/plugin-transform-class-properties` and use `loose: true` for class properties:\n\n```json\n{\n  \"plugins\": [\n    [\"@babel/plugin-proposal-decorators\", { \"version\": \"legacy\" }],\n    [\"@babel/plugin-transform-class-properties\", { \"loose\": true }]\n  ]\n}\n```\n\nThis ordering matters because Babel needs to process decorators before rewriting the class elements they apply to.\n\n## Important pitfalls\n\n- Set `version` explicitly. New configs should not rely on old defaults.\n- Do not mix up `\"2023-11\"` and `\"legacy\"`; they are different decorator models with different behavior.\n- Keep the decorators plugin before class-element transforms such as `@babel/plugin-transform-class-properties`.\n- Use `decoratorsBeforeExport` only for older proposal snapshots that need it, not for `\"legacy\"` or current proposal configs.\n- Babel's maintainer docs note that Babel 8 will support only `\"2023-11\"` and `\"legacy\"`, so avoid older snapshot versions for new work.\n"
  },
  {
    "path": "content/babel/docs/plugin-proposal-pipeline-operator/javascript/DOC.md",
    "content": "---\nname: plugin-proposal-pipeline-operator\ndescription: \"Configure Babel 7 to compile the pipeline operator proposal with minimal, F#, or Hack-style syntax\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,pipeline-operator,syntax,proposal\"\n---\n\n# @babel/plugin-proposal-pipeline-operator\n\n`@babel/plugin-proposal-pipeline-operator` is a build-time Babel plugin for code that uses the pipeline operator proposal (`|>`).\n\nConfiguration lives entirely in Babel. There are no environment variables, authentication steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-proposal-pipeline-operator\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Enable the plugin in Babel config\n\nThis plugin requires a `proposal` option. Current Babel parser validation accepts `\"minimal\"`, `\"fsharp\"`, `\"hack\"`, and `\"smart\"`.\n\nFor a simple pipeline style, configure `minimal`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-pipeline-operator\",\n      {\n        \"proposal\": \"minimal\"\n      }\n    ]\n  ]\n}\n```\n\nUse that for code shaped like this:\n\n```javascript\nconst result = value |> double |> increment;\n```\n\nFor Hack-style pipes, set both `proposal` and `topicToken`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-pipeline-operator\",\n      {\n        \"proposal\": \"hack\",\n        \"topicToken\": \"^^\"\n      }\n    ]\n  ]\n}\n```\n\nUse that for code shaped like this:\n\n```javascript\nconst label = input\n  |> ^^.trim()\n  |> ^^.toUpperCase();\n```\n\nIn Hack mode, current Babel parser validation only accepts these topic tokens: `\"^^\"`, `\"@@\"`, `\"^\"`, `\"%\"`, and `\"#\"`.\n\n## Compile from the CLI\n\nWith a `babel.config.json` file in place:\n\n```bash\nnpx babel src --out-dir lib\n```\n\nOr compile a single file:\n\n```bash\nnpx babel input.js --out-file output.js\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst result = value |> double |> increment;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-proposal-pipeline-operator\", {\n    proposal: \"minimal\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nHack-style pipes use the same API, but they must include `topicToken`:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst message = input\n  |> ^^.trim()\n  |> ^^.toLowerCase();\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-proposal-pipeline-operator\", {\n    proposal: \"hack\",\n    topicToken: \"^^\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n```\n\n## Match parser and generator settings in AST tools\n\nIf you parse or print Babel ASTs directly, configure the parser plugin and generator options to match the pipeline style you use in source files.\n\n```javascript\nimport { parse } from \"@babel/parser\";\nimport generate from \"@babel/generator\";\n\nconst source = `\nconst message = input |> ^^.trim();\n`;\n\nconst ast = parse(source, {\n  sourceType: \"module\",\n  plugins: [[\"pipelineOperator\", {\n    proposal: \"hack\",\n    topicToken: \"^^\",\n  }]],\n});\n\nconst output = generate(ast, {\n  topicToken: \"^^\",\n});\n\nconsole.log(output.code);\n```\n\nIf you print Hack-style pipeline ASTs without a matching generator `topicToken`, Babel's generator throws because it only accepts `\"%\"`, `\"#\"`, `\"@@\"`, `\"^^\"`, and `\"^\"`.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.28.6\",\n    \"@babel/core\": \"^7.28.6\",\n    \"@babel/plugin-proposal-pipeline-operator\": \"^7.28.6\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-pipeline-operator\",\n      {\n        \"proposal\": \"hack\",\n        \"topicToken\": \"^^\"\n      }\n    ]\n  ]\n}\n```\n\n## Important pitfalls\n\n- This plugin requires a `proposal` option. Babel throws if you omit it or set an unsupported value.\n- Hack-style pipes also require `topicToken`, and the token must be one of `\"^^\"`, `\"@@\"`, `\"^\"`, `\"%\"`, or `\"#\"`.\n- In Hack mode, each pipe body must reference the topic token at least once.\n- In Hack mode, arrow functions, assignment expressions, conditional expressions, and `yield` expressions must be parenthesized when they appear as a pipe body.\n- If you also use `@babel/parser` or `@babel/generator` directly, keep the parser's `pipelineOperator` settings and the generator's `topicToken` aligned.\n- `proposal: \"smart\"` conflicts with Record & Tuple hash syntax, and Hack pipes with `topicToken: \"#\"` also conflict with Record & Tuple hash syntax.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-proposal-pipeline-operator@7.28.6`.\n- Current Babel 7 parser validation accepts `proposal: \"minimal\"`, `\"fsharp\"`, `\"hack\"`, and `\"smart\"`.\n- Current Babel 7 parser validation requires `topicToken` only for `proposal: \"hack\"`.\n- Current Babel generator validation only accepts these `topicToken` values: `\"%\"`, `\"#\"`, `\"@@\"`, `\"^^\"`, and `\"^\"`.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-proposal-pipeline-operator\n- npm package page: https://www.npmjs.com/package/@babel/plugin-proposal-pipeline-operator\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-proposal-pipeline-operator\n- Babel parser source: https://github.com/babel/babel/tree/main/packages/babel-parser\n- Babel generator source: https://github.com/babel/babel/tree/main/packages/babel-generator\n"
  },
  {
    "path": "content/babel/docs/plugin-proposal-record-and-tuple/javascript/DOC.md",
    "content": "---\nname: plugin-proposal-record-and-tuple\ndescription: \"Enable Babel 7 to parse and emit the Record & Tuple proposal syntax with hash or bar delimiters\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,record-and-tuple,syntax,proposal\"\n---\n\n# @babel/plugin-proposal-record-and-tuple\n\n`@babel/plugin-proposal-record-and-tuple` is a build-time Babel plugin for Babel 7 pipelines that need to accept the Record & Tuple proposal syntax.\n\nUse it when your source contains either hash-style literals:\n\n```javascript\nconst user = #{ id: 1, name: \"Ada\" };\nconst pair = #[1, 2];\n```\n\nor bar-style literals:\n\n```javascript\nconst user = {| id: 1, name: \"Ada\" |};\nconst pair = [|1, 2|];\n```\n\nThere are no environment variables, authentication steps, or runtime clients to initialize. Configuration lives entirely in Babel.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-proposal-record-and-tuple\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Enable the plugin in Babel config\n\nHash syntax is the practical default in Babel 7. Configure it explicitly so your parser and code generator stay aligned:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-record-and-tuple\",\n      {\n        \"syntaxType\": \"hash\"\n      }\n    ]\n  ]\n}\n```\n\nIf your codebase uses bar delimiters instead, switch the option:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-record-and-tuple\",\n      {\n        \"syntaxType\": \"bar\"\n      }\n    ]\n  ]\n}\n```\n\nIn current Babel 7 parser code, `syntaxType` must be either `\"hash\"` or `\"bar\"`.\n\n## Compile from the CLI\n\nWith a `babel.config.json` file in place:\n\n```bash\nnpx babel src --out-dir lib\n```\n\nOr compile a single file:\n\n```bash\nnpx babel input.js --out-file output.js\n```\n\nThis plugin makes Babel accept Record & Tuple syntax during compilation. Keep in mind that a successful Babel build does not guarantee the final runtime can execute that syntax.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst settings = #{ retries: 3, mode: \"strict\" };\nconst order = #[\"name\", \"createdAt\"];\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-proposal-record-and-tuple\", {\n    syntaxType: \"hash\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nBar-style input uses the same API with `syntaxType: \"bar\"`:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const pair = [|1, 2|];\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-proposal-record-and-tuple\", {\n    syntaxType: \"bar\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n```\n\n## Match parser syntax with generated output\n\nIf you also parse or print ASTs directly, keep the parser plugin option and generator option in sync. Babel's generator accepts `recordAndTupleSyntaxType`, and the current implementation defaults it to `\"hash\"`.\n\n```javascript\nimport { parse } from \"@babel/parser\";\nimport generate from \"@babel/generator\";\n\nconst source = \"const config = {| region: \\\"us-east-1\\\" |};\";\n\nconst ast = parse(source, {\n  sourceType: \"module\",\n  plugins: [[\"recordAndTuple\", { syntaxType: \"bar\" }]],\n});\n\nconst output = generate(ast, {\n  recordAndTupleSyntaxType: \"bar\",\n});\n\nconsole.log(output.code);\n```\n\nIf those settings disagree, Babel can parse one delimiter style and print another, or throw when it encounters an unsupported generator value.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.27.1\",\n    \"@babel/core\": \"^7.27.1\",\n    \"@babel/plugin-proposal-record-and-tuple\": \"^7.27.1\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-record-and-tuple\",\n      {\n        \"syntaxType\": \"hash\"\n      }\n    ]\n  ]\n}\n```\n\n## Important pitfalls\n\n- `syntaxType` only accepts `\"hash\"` or `\"bar\"` in Babel 7.\n- Hash-style Record & Tuple syntax conflicts with Babel's pipeline-operator parser in `proposal: \"smart\"` mode, and it also conflicts with hack pipes when `topicToken` is `\"#\"`.\n- If your codebase uses bar delimiters, set both the plugin's `syntaxType` and the generator's `recordAndTupleSyntaxType` to `\"bar\"`.\n- Record expressions reject `__proto__`.\n- Treat this as Babel syntax support for a proposal, not as a compatibility layer for older runtimes. Your emitted code can still contain `#{}`, `#[]`, `{| |}`, or `[| |]`.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-proposal-record-and-tuple@7.27.1`.\n- Current Babel 7 parser validation removes `recordAndTuple` support in Babel 8 and throws if you keep that parser plugin enabled there.\n- Current Babel 7 parser validation accepts only `syntaxType: \"hash\"` and `syntaxType: \"bar\"`.\n- Current Babel generator logic defaults `recordAndTupleSyntaxType` to `\"hash\"` when you do not set it explicitly.\n\n## Official sources\n\n- npm package page: https://www.npmjs.com/package/@babel/plugin-proposal-record-and-tuple\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-proposal-record-and-tuple\n- Babel parser source: https://github.com/babel/babel/tree/main/packages/babel-parser\n- Babel generator source: https://github.com/babel/babel/tree/main/packages/babel-generator\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-class-properties/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-class-properties\ndescription: \"Enable Babel to parse public and private class field syntax without transforming the output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.12.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,class-fields,private-fields,private-methods,syntax\"\n---\n\n# @babel/plugin-syntax-class-properties\n\n`@babel/plugin-syntax-class-properties` is a syntax-only Babel plugin. In `7.12.13`, it lets Babel parse public class fields, private fields such as `#value`, and private methods such as `#inc()`.\n\nIt does **not** transform those class features for older runtimes. If your output must run where class fields or private methods are not supported natively, use the matching transform plugins instead.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to invoke Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-class-properties\n```\n\n```bash\nyarn add --dev @babel/core @babel/plugin-syntax-class-properties\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nNo environment variables, authentication, or runtime client setup are required.\n\n## Enable the plugin in Babel config\n\nAdd the plugin name to `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-class-properties\"]\n}\n```\n\nIn `7.12.13`, this package does not expose user-facing plugin options. Its implementation only enables Babel's `classProperties`, `classPrivateProperties`, and `classPrivateMethods` parser plugins.\n\n## Parse class fields from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-syntax-class-properties\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-syntax-class-properties\n```\n\nThis makes Babel accept the syntax, but the generated code still contains class fields and private members.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nclass Counter {\n  static label = \"counter\";\n  value = 0;\n  #step = 1;\n\n  #inc() {\n    this.value += this.#step;\n    return this.value;\n  }\n\n  next() {\n    return this.#inc();\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-class-properties\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this plugin alone, Babel parses the file and preserves the class field and private member syntax in the emitted code.\n\n## What syntax it enables\n\nIn `7.12.13`, the plugin covers these class features:\n\n```javascript\nclass Example {\n  static version = 1;\n  name = \"demo\";\n  #count = 0;\n\n  #increment() {\n    this.#count += 1;\n    return this.#count;\n  }\n}\n```\n\nThat includes:\n\n- public instance fields\n- public static fields\n- private instance fields\n- private methods\n\nIt does not enable every newer class-feature syntax. For example, `#field in obj` and `static {}` are handled by separate Babel plugins.\n\n## When to use transform plugins instead\n\nUse this syntax plugin when Babel only needs to parse class fields and private members, such as when:\n\n- you ship modern JavaScript and want to keep class field syntax in the final output\n- another build step performs the downlevel transform later\n- you need Babel to parse these nodes before other plugins inspect or rewrite the AST\n\nIf you need Babel itself to rewrite the syntax, use the transform plugins instead:\n\n```json\n{\n  \"plugins\": [\n    \"@babel/plugin-transform-class-properties\",\n    \"@babel/plugin-transform-private-methods\"\n  ]\n}\n```\n\n`@babel/plugin-transform-class-properties` handles public and private fields. `@babel/plugin-transform-private-methods` handles private methods.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.12.13\",\n    \"@babel/core\": \"^7.12.13\",\n    \"@babel/plugin-syntax-class-properties\": \"^7.12.13\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-class-properties\"]\n}\n```\n\n## Important pitfalls\n\n- This plugin affects parsing only. It does not transpile class fields or private methods and does not add runtime polyfills.\n- A Babel build can succeed with this plugin while the output still fails in runtimes that do not support class fields or private members.\n- Install `@babel/core` alongside the plugin; the published package declares Babel core as a peer dependency.\n- There are no plugin-specific configuration options in `7.12.13`, so transform-style options such as `loose` do not apply here.\n- This plugin enables `classProperties`, `classPrivateProperties`, and `classPrivateMethods` only. Add other Babel plugins separately for `#field in obj`, `static {}`, or additional proposal syntax.\n- No environment variables or client initialization are involved; all setup happens in your Babel config.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-class-properties@7.12.13`.\n- The published `7.12.13` package description is `Allow parsing of class properties`.\n- The published `7.12.13` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.12.13`, the plugin implementation asserts Babel 7 and adds `\"classProperties\"`, `\"classPrivateProperties\"`, and `\"classPrivateMethods\"` to Babel's parser plugins.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-syntax-class-properties\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-class-properties\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-class-properties\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-dynamic-import/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-dynamic-import\ndescription: \"Enable Babel to parse import() syntax without transforming or polyfilling it\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.8.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,dynamic-import,syntax\"\n---\n\n# @babel/plugin-syntax-dynamic-import\n\n`@babel/plugin-syntax-dynamic-import` is a syntax-only Babel plugin. It lets Babel parse `import()` expressions and leaves them unchanged in the generated output.\n\nUse it when your bundler or runtime should handle dynamic imports at runtime. It does **not** rewrite `import()` to `require()`, load split chunks by itself, or add any polyfills.\n\nFor projects already on `@babel/core@7.8.0` or newer, Babel enables dynamic import parsing by default. In that setup, this plugin is usually unnecessary unless you keep it for an explicit, self-documenting plugin list.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-dynamic-import\n```\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nNo environment variables, credentials, or runtime client initialization are required.\n\n## Enable the plugin in Babel config\n\nAdd the plugin name to `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-dynamic-import\"]\n}\n```\n\nThe published docs for this package do not document any plugin-specific options for `7.8.3`.\n\nIf your project uses `@babel/core@7.8.0` or newer, Babel's own docs say you can safely remove this plugin because dynamic import parsing is built in.\n\n## Parse `import()` from the CLI\n\nCompile a single file:\n\n```bash\nnpx babel src/load-widget.js --out-file lib/load-widget.js --plugins @babel/plugin-syntax-dynamic-import\n```\n\nCompile a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-syntax-dynamic-import\n```\n\nExample input:\n\n```javascript\nexport async function loadWidget() {\n  const widget = await import(\"./widget.js\");\n  return widget.default;\n}\n```\n\nWith this plugin alone, Babel accepts the file and keeps the `import()` call in the emitted code.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nasync function loadWidget() {\n  const widget = await import(\"./widget.js\");\n  return widget.default;\n}\n`;\n\nconst result = transformSync(source, {\n  filename: \"src/load-widget.js\",\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-dynamic-import\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nExpected output shape:\n\n```javascript\nasync function loadWidget() {\n  const widget = await import(\"./widget.js\");\n  return widget.default;\n}\n```\n\nThe important behavior is that Babel parses the syntax but does not transform it.\n\n## Common bundler setup\n\nThis plugin is the right Babel-side setup when a bundler such as Webpack is responsible for code splitting and chunk loading.\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir dist\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.8.3\",\n    \"@babel/core\": \"^7.8.3\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.8.3\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-dynamic-import\"]\n}\n```\n\nIf Babel must convert `import()` for non-bundler module targets such as CommonJS, AMD, or SystemJS, use `@babel/plugin-transform-dynamic-import` with the matching modules transform instead of this syntax plugin.\n\n## Polyfills for older browser targets\n\nBabel's docs note that bundlers such as Webpack rely on `Promise` internally for `import()`. If you target browsers that do not provide `Promise` and iterator support, add those polyfills explicitly.\n\nOne option is to import them before your app entry code:\n\n```javascript\nimport \"core-js/modules/es.promise\";\nimport \"core-js/modules/es.array.iterator\";\n\ndocument.querySelector(\"#load\")?.addEventListener(\"click\", async () => {\n  const { default: renderWidget } = await import(\"./widget.js\");\n  renderWidget();\n});\n```\n\nWith Webpack, you can also add them in `entry`:\n\n```javascript\nmodule.exports = {\n  entry: [\n    \"core-js/modules/es.promise\",\n    \"core-js/modules/es.array.iterator\",\n    \"./src/main.js\",\n  ],\n};\n```\n\nThis requirement is separate from Babel parsing. The syntax plugin does not add these polyfills automatically.\n\n## Important pitfalls\n\n- This plugin only enables parsing. It does not transform `import()` for older runtimes or module systems.\n- Successful Babel output does not guarantee runtime support. Your final environment still needs native dynamic import support or a bundler/runtime that handles it.\n- Install `@babel/core` alongside the plugin; the package is not a standalone compiler.\n- If you use `@babel/core@7.8.0` or newer, this plugin is usually redundant.\n- `@babel/preset-env` does not infer the `Promise` and iterator polyfills needed by bundler-based dynamic imports just because `import()` appears in your code.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-dynamic-import@7.8.3`.\n- Babel's docs for this package say it can be removed when you use `@babel/core@7.8.0` or later.\n- Babel's docs also list this syntax under `@babel/preset-env` as part of ES2020 support.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/babel-plugin-syntax-dynamic-import\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-dynamic-import\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-dynamic-import\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-import-meta/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-import-meta\ndescription: \"Enable Babel to parse import.meta syntax without transforming the output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.10.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,import-meta,syntax\"\n---\n\n# @babel/plugin-syntax-import-meta\n\n`@babel/plugin-syntax-import-meta` is a syntax-only Babel plugin. It lets Babel parse `import.meta` in ES module code.\n\nIt does **not** rewrite `import.meta`, inject runtime helpers, or make CommonJS output understand the feature. Use it when Babel itself needs to read files that contain `import.meta` and you want that syntax preserved for a later runtime or build step.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-import-meta\n```\n\n```bash\nyarn add --dev @babel/core @babel/plugin-syntax-import-meta\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nNo environment variables, credentials, or runtime client setup are required.\n\n## Enable the plugin in Babel config\n\nAdd the plugin name to your Babel config:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-import-meta\"]\n}\n```\n\nIn `7.10.4`, this package does not expose user-facing plugin options. Its implementation only enables Babel's `importMeta` parser plugin.\n\n## Parse `import.meta` from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-syntax-import-meta\n```\n\nCompile a single module file:\n\n```bash\nnpx babel src/main.js --out-file lib/main.js --plugins @babel/plugin-syntax-import-meta\n```\n\nThis makes Babel accept `import.meta`, but the emitted code still contains `import.meta`.\n\n## Use it from JavaScript\n\n`import.meta` is an ES module feature, so set `sourceType: \"module\"` when you transform source strings programmatically.\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconsole.log(import.meta.url);\nconst workerUrl = new URL(\"./worker.js\", import.meta.url);\n`;\n\nconst result = transformSync(source, {\n  filename: \"src/main.js\",\n  sourceType: \"module\",\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-import-meta\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this plugin alone, Babel parses the file and preserves the `import.meta` expressions in the generated code.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.10.4\",\n    \"@babel/core\": \"^7.10.4\",\n    \"@babel/plugin-syntax-import-meta\": \"^7.10.4\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-import-meta\"]\n}\n```\n\n## Important pitfalls\n\n- This plugin only changes parsing. It does not transform `import.meta` for older runtimes.\n- Keep the file in ES module mode. `import.meta` is not valid in script-mode input.\n- A Babel build can succeed with this plugin while the output still fails in environments that do not support `import.meta`.\n- Install `@babel/core` alongside the plugin; the published package declares Babel core as a peer dependency.\n- There are no plugin-specific options in `7.10.4`, so transform behavior must come from the rest of your toolchain.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-import-meta@7.10.4`.\n- The published `7.10.4` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.10.4`, the plugin implementation asserts Babel 7 and adds `\"importMeta\"` to Babel's parser plugins.\n- The published package description for `7.10.4` is `Allow parsing of import.meta`.\n\n## Official sources\n\n- Babel docs: https://babeljs.io/docs/en/next/babel-plugin-syntax-import-meta.html\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-import-meta\n- Babel source package: https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-import-meta\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-jsx/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-jsx\ndescription: \"Enable Babel to parse JSX syntax without transforming the output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,jsx,syntax,parser\"\n---\n\n# @babel/plugin-syntax-jsx\n\n`@babel/plugin-syntax-jsx` is a syntax-only Babel plugin. It lets Babel parse JSX syntax such as `<Button />`.\n\nIt does **not** transform JSX into executable JavaScript. If your build output must run without a later JSX transform step, use a JSX transform or preset such as `@babel/preset-react` instead of this plugin alone.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-jsx\n```\n\n```bash\nyarn add --dev @babel/core @babel/plugin-syntax-jsx\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nNo environment variables, authentication, or runtime client setup are required.\n\n## Enable the plugin in Babel config\n\nAdd the plugin name to your Babel config:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-jsx\"]\n}\n```\n\nIn `7.28.6`, this package does not expose user-facing plugin options. Its implementation only enables Babel's `jsx` parser plugin.\n\n## Parse JSX from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-syntax-jsx\n```\n\nCompile a single file:\n\n```bash\nnpx babel src/App.jsx --out-file lib/App.js --plugins @babel/plugin-syntax-jsx\n```\n\nThis makes Babel accept JSX input, but the emitted code still contains JSX.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst view = <Button kind=\"primary\">Save</Button>;\n`;\n\nconst result = transformSync(source, {\n  filename: \"src/view.jsx\",\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-jsx\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this plugin alone, Babel parses the file and preserves the JSX in the generated code.\n\n## Parse TSX with the TypeScript syntax plugin\n\nDo not rely on `@babel/plugin-syntax-jsx` to turn TypeScript parsing into TSX parsing. In the current Babel `7.28.6` implementation, this plugin exits early when the `typescript` parser plugin is already enabled.\n\nUse `@babel/plugin-syntax-typescript` with `isTSX: true` instead:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-syntax-typescript\",\n      {\n        \"isTSX\": true\n      }\n    ]\n  ]\n}\n```\n\nProgrammatic example:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const view = <Button />;\", {\n  filename: \"src/view.tsx\",\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-syntax-typescript\", { isTSX: true }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n```\n\nIf you enable TypeScript parsing without `isTSX: true`, JSX-like input in `.tsx` code does not parse correctly.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.28.6\",\n    \"@babel/core\": \"^7.28.6\",\n    \"@babel/plugin-syntax-jsx\": \"^7.28.6\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-jsx\"]\n}\n```\n\nThis setup is useful when another tool handles JSX transformation later and you only need Babel to parse the syntax during an intermediate step.\n\n## Important pitfalls\n\n- This plugin only affects parsing. It does not rewrite JSX and does not add any runtime helpers.\n- A Babel build can succeed with this plugin while the output still contains `<Component />`, which will not run directly in standard JavaScript environments.\n- Install `@babel/core` alongside the plugin; the published package declares Babel core as a peer dependency.\n- There are no plugin-specific configuration options in `7.28.6`.\n- If TypeScript syntax is enabled for the same file, configure `@babel/plugin-syntax-typescript` for TSX instead of expecting `@babel/plugin-syntax-jsx` to override it.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-jsx@7.28.6`.\n- The published `7.28.6` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In the published `7.28.6` implementation, the plugin asserts Babel compatibility as `^7.0.0-0 || ^8.0.0-0`.\n- In the published `7.28.6` implementation, the plugin adds `\"jsx\"` to Babel's parser plugins unless `\"typescript\"` is already present.\n- The published package description for `7.28.6` is `Allow parsing of jsx`.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-syntax-jsx\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-jsx\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-jsx\n- Babel TypeScript syntax plugin docs: https://babel.dev/docs/en/next/babel-plugin-syntax-typescript\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-optional-chaining/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-optional-chaining\ndescription: \"Enable Babel to parse optional chaining syntax without transforming the output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.8.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,optional-chaining,syntax\"\n---\n\n# @babel/plugin-syntax-optional-chaining\n\n`@babel/plugin-syntax-optional-chaining` is a syntax-only Babel plugin. It lets Babel parse optional chaining expressions such as `obj?.prop`, `obj?.[key]`, and `fn?.()`.\n\nIt does **not** transform that syntax for older runtimes. If your output must run in environments that do not support optional chaining, use `@babel/plugin-transform-optional-chaining` instead.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you want to run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-optional-chaining\n```\n\n```bash\nyarn add --dev @babel/core @babel/plugin-syntax-optional-chaining\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nNo environment variables, authentication, or runtime client setup are required.\n\n## Enable the plugin in Babel config\n\nAdd the plugin name to your Babel config:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-optional-chaining\"]\n}\n```\n\nIn `7.8.3`, this package does not expose user-facing plugin options. Its implementation only enables Babel's `optionalChaining` parser plugin.\n\n## Parse optional chaining from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-syntax-optional-chaining\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-syntax-optional-chaining\n```\n\nThis makes Babel accept the syntax, but the emitted code still contains `?.`.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst city = user?.address?.city;\nconst displayName = getProfile?.().name;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-optional-chaining\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this plugin alone, Babel parses the file and preserves the optional chaining syntax in the generated code.\n\n## When to use the transform plugin instead\n\nUse `@babel/plugin-syntax-optional-chaining` when you only need Babel to accept the syntax, for example when:\n\n- you ship modern JavaScript and want to keep `?.` in the final output\n- another compiler step handles the downlevel transform later\n- you are writing a Babel pipeline that needs to parse optional chaining before other plugins run\n\nIf you need Babel to rewrite optional chaining into older JavaScript, switch to `@babel/plugin-transform-optional-chaining`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-optional-chaining\"]\n}\n```\n\nYou do not need to combine both plugins for the same files. The transform plugin already enables optional chaining parsing.\n\n## Common build setup\n\n`package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.8.3\",\n    \"@babel/core\": \"^7.8.3\",\n    \"@babel/plugin-syntax-optional-chaining\": \"^7.8.3\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-optional-chaining\"]\n}\n```\n\n## Important pitfalls\n\n- This plugin only affects parsing. It does not polyfill runtime behavior and does not transpile `?.` away.\n- A Babel build can succeed with this plugin while the output still breaks in older Node.js or browsers that do not support optional chaining.\n- Install `@babel/core` alongside the plugin; the published package declares Babel core as a peer dependency.\n- There are no plugin-specific configuration options in `7.8.3`, so any attempt to tune transform behavior on this plugin has no effect.\n- No environment variables or client initialization are involved; all setup happens in your Babel config.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-optional-chaining@7.8.3`.\n- The published `7.8.3` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.8.3`, the plugin implementation asserts Babel 7 and adds `\"optionalChaining\"` to Babel's parser plugins.\n- The published package description for `7.8.3` is `Allow parsing of optional properties`.\n\n## Official sources\n\n- Babel docs: https://babeljs.io/docs/en/next/babel-plugin-syntax-optional-chaining.html\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-optional-chaining\n- Babel source package: https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-chaining\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-top-level-await/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-top-level-await\ndescription: \"Enable Babel to parse top-level await in ECMAScript modules without transforming the output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.14.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,esm,syntax,top-level-await\"\n---\n\n# @babel/plugin-syntax-top-level-await\n\n`@babel/plugin-syntax-top-level-await` is a syntax-only Babel plugin. It lets Babel parse top-level `await` in module code.\n\nIt does **not** transform top-level `await` into another pattern or make older runtimes support it. Use it when your output stays as modern ESM, or when another tool in your build pipeline handles later transforms.\n\nNo environment variables, authentication, or runtime client initialization are required.\n\n## Install\n\nInstall the plugin with Babel core. Add `@babel/cli` if you run Babel from the command line.\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-top-level-await\n```\n\n```bash\nyarn add --dev @babel/core @babel/plugin-syntax-top-level-await\n```\n\nOptional CLI dependency:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe published `7.14.5` package declares `@babel/core` as a peer dependency.\n\n## Enable the plugin in Babel config\n\nAdd the plugin to your Babel config and keep the file in module mode when you use top-level `await`:\n\n```json\n{\n  \"sourceType\": \"module\",\n  \"plugins\": [\"@babel/plugin-syntax-top-level-await\"]\n}\n```\n\nIn `7.14.5`, this package does not expose user-facing plugin options. Its implementation only asserts Babel 7 and adds the `topLevelAwait` parser plugin.\n\n## Parse a module that uses top-level `await`\n\nCompile an ESM file from the CLI:\n\n```bash\nnpx babel src/index.mjs --out-file dist/index.mjs --plugins @babel/plugin-syntax-top-level-await\n```\n\nExample input:\n\n```javascript\nconst response = await fetch(\"https://example.com/data.json\");\nconst payload = await response.json();\n\nexport default payload;\n```\n\nWith this plugin alone, Babel accepts the syntax and emits code that still contains top-level `await`.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\n  `\nconst response = await fetch(\"https://example.com/data.json\");\nexport const payload = await response.json();\n`,\n  {\n    filename: \"src/index.mjs\",\n    configFile: false,\n    babelrc: false,\n    sourceType: \"module\",\n    plugins: [\"@babel/plugin-syntax-top-level-await\"],\n  },\n);\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nExpected output shape:\n\n```javascript\nconst response = await fetch(\"https://example.com/data.json\");\nexport const payload = await response.json();\n```\n\nThe output stays effectively unchanged because this plugin only enables parsing.\n\n## Common build setup\n\nUse this plugin when your project already ships ESM and the runtime supports top-level `await`:\n\n`package.json`:\n\n```json\n{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"babel src --out-dir dist\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.14.5\",\n    \"@babel/core\": \"^7.14.5\",\n    \"@babel/plugin-syntax-top-level-await\": \"^7.14.5\"\n  }\n}\n```\n\n`babel.config.json`:\n\n```json\n{\n  \"sourceType\": \"module\",\n  \"plugins\": [\"@babel/plugin-syntax-top-level-await\"]\n}\n```\n\n## When this plugin is the right tool\n\nUse `@babel/plugin-syntax-top-level-await` when:\n\n- your final JavaScript stays as modern ESM\n- another compiler or bundler step handles later transforms\n- you need Babel to parse files with top-level `await` before your own Babel plugins run\n\nIf you need Babel to rewrite other modern syntax too, add the corresponding transform plugins or presets separately. This syntax plugin does not replace them.\n\n## Important pitfalls\n\n- This plugin only affects parsing. It does not convert top-level `await` into syntax that works in older runtimes.\n- Top-level `await` is module syntax. Use module files such as `.mjs` or configure Babel with `\"sourceType\": \"module\"` for the files that need it.\n- Install `@babel/core` alongside the plugin. The package is not a standalone compiler.\n- There are no plugin-specific options in `7.14.5`, so configuration belongs in Babel's normal file-level settings such as `sourceType`.\n- Successful Babel output does not guarantee runtime support. The generated code can still fail in environments that do not support top-level `await` in ESM.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-top-level-await@7.14.5`.\n- The published package description for `7.14.5` is `Allow parsing of top-level await in modules`.\n- The published `7.14.5` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.14.5`, the plugin implementation asserts Babel 7 and adds `\"topLevelAwait\"` to Babel's parser plugins.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-syntax-top-level-await\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-top-level-await\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-top-level-await\n"
  },
  {
    "path": "content/babel/docs/plugin-syntax-typescript/javascript/DOC.md",
    "content": "---\nname: plugin-syntax-typescript\ndescription: \"Babel plugin for parsing TypeScript syntax in JavaScript builds without transforming or stripping the types\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,typescript,parser,syntax,build\"\n---\n\n# @babel/plugin-syntax-typescript\n\n`@babel/plugin-syntax-typescript` lets Babel parse TypeScript syntax. It is a parser-only plugin: it does not strip types, convert TypeScript to runnable JavaScript, or add any runtime behavior.\n\nUse it when you need Babel to accept `.ts`, `.tsx`, `.mts`, or `.cts` syntax so another Babel step or downstream tool can consume the file.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-typescript\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or runtime clients to initialize.\n\nThe setup is only:\n\n- install `@babel/core`\n- add `@babel/plugin-syntax-typescript` to Babel config or a programmatic Babel call\n- make sure your build step includes the TypeScript file extensions you want Babel to read\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-typescript\"]\n}\n```\n\nThis enables TypeScript parsing for files that Babel loads with that config.\n\n## Use it from the CLI\n\nIf your source tree includes TypeScript files, pass the extensions explicitly so the Babel CLI reads them:\n\n```bash\nnpx babel src \\\n  --extensions \".js,.jsx,.ts,.tsx,.mts,.cts\" \\\n  --out-dir lib \\\n  --plugins @babel/plugin-syntax-typescript\n```\n\nImportant: this plugin only changes parsing. Output generated with only this plugin still contains TypeScript syntax.\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const answer: number = 42;\", {\n  filename: \"src/example.ts\",\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-syntax-typescript\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n// const answer: number = 42;\n```\n\nThat unchanged output is the key behavior: Babel accepts the syntax, but this plugin does not erase the type annotation.\n\n## Parse TSX with `isTSX`\n\nSet `isTSX: true` when the file contains JSX-style tags and you want Babel to parse them as TSX:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-syntax-typescript\",\n      {\n        \"isTSX\": true\n      }\n    ]\n  ]\n}\n```\n\nProgrammatic example:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const element = <Button />;\", {\n  filename: \"src/view.tsx\",\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-syntax-typescript\", { isTSX: true }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n```\n\nWithout `isTSX: true`, Babel does not enable JSX parsing for this plugin and TSX input such as `<Button />` fails to parse.\n\n## Reject ambiguous angle-bracket assertions with `disallowAmbiguousJSXLike`\n\nSet `disallowAmbiguousJSXLike: true` if you want Babel to reject legacy angle-bracket assertions such as `<string>value`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-syntax-typescript\",\n      {\n        \"disallowAmbiguousJSXLike\": true\n      }\n    ]\n  ]\n}\n```\n\nUse normal `as` assertions instead:\n\n```typescript\nconst text = value as string;\n```\n\nThis is useful when you want TypeScript parsing rules that avoid JSX-like ambiguity, especially in codebases that treat `.mts` and `.cts` style syntax strictly.\n\n## Parse declaration-style files with `dts`\n\nSet `dts: true` when you want the TypeScript parser to use ambient-context rules such as the ones used for declaration files and `declare module` blocks:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-syntax-typescript\",\n      {\n        \"dts\": true\n      }\n    ]\n  ]\n}\n```\n\nProgrammatic example:\n\n```javascript\nimport { parseSync } from \"@babel/core\";\n\nconst ast = parseSync('declare module \"pkg\" { export interface Config { mode: string } }', {\n  filename: \"src/types.d.ts\",\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-syntax-typescript\", { dts: true }]],\n});\n\nif (!ast) {\n  throw new Error(\"Parse failed\");\n}\n```\n\nUse `dts` only for declaration-style input. Normal application source files usually should not parse in ambient mode.\n\n## Important pitfalls\n\n- This is not a TypeScript-to-JavaScript compiler. If you need plain JavaScript output, add a Babel TypeScript transform step instead of using this plugin alone.\n- Install `@babel/core` alongside the plugin. Babel loads plugins through `@babel/core`; the plugin is not a standalone CLI.\n- Do not expect Flow and TypeScript parsing to coexist in the same file with this plugin. Its implementation removes Babel's `flow` parser plugin before enabling TypeScript.\n- `isTSX: true` controls parsing only. It does not transform JSX or strip TypeScript syntax by itself.\n- `disallowAmbiguousJSXLike: true` blocks `<Type>value` style assertions. Switch those assertions to `value as Type` before enabling it broadly.\n- `dts: true` changes parser rules for ambient contexts. Reserve it for declaration-style inputs such as `.d.ts` content.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-syntax-typescript@7.28.6`.\n- In the current Babel 7 implementation, the user-facing parser options on this plugin are `isTSX`, `disallowAmbiguousJSXLike`, and `dts`.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-syntax-typescript\n- npm package page: https://www.npmjs.com/package/@babel/plugin-syntax-typescript\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-typescript\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-arrow-functions/javascript/DOC.md",
    "content": "---\nname: plugin-transform-arrow-functions\ndescription: \"Babel plugin for rewriting ES2015 arrow functions into function expressions during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,arrow-functions,es2015\"\n---\n\n# @babel/plugin-transform-arrow-functions\n\n`@babel/plugin-transform-arrow-functions` rewrites ES2015 arrow functions to function expressions at build time. It is a Babel compile-time transform: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-arrow-functions\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-arrow-functions\"]\n}\n```\n\nThis is enough to transform arrow functions in files Babel compiles.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-arrow-functions\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-arrow-functions\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst input = `\nconst obj = {\n  id: 1,\n  getHandler() {\n    return () => this.id;\n  }\n};\n`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-arrow-functions\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration, Babel rewrites the arrow function to a normal function and captures lexical `this` in generated code when needed.\n\n## Enable stricter arrow-function semantics with `spec`\n\nSet `spec: true` when you want Babel to emit extra checks that preserve arrow-function behavior more strictly:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-arrow-functions\",\n      {\n        \"spec\": true\n      }\n    ]\n  ]\n}\n```\n\nFor example, code like this:\n\n```javascript\nconst fn = () => this.id;\n```\n\nis transformed into code in this shape:\n\n```javascript\nvar _this = this;\n\nfunction _newArrowCheck(n, r) {\n  if (n !== r) throw new TypeError(\"Cannot instantiate an arrow function\");\n}\n\nconst fn = function fn() {\n  _newArrowCheck(this, _this);\n  return this.id;\n}.bind(this);\n```\n\nUse this when you need the generated output to enforce arrow semantics more explicitly than the default transform.\n\n## Control behavior with Babel `assumptions`\n\nIn `7.27.1`, this plugin also reads Babel's top-level `assumptions.noNewArrows` setting. The plugin checks `assumptions.noNewArrows` first and falls back to `!spec` if you do not set the assumption.\n\nUse the assumption when you want to control this behavior in one place for your Babel config:\n\n```json\n{\n  \"assumptions\": {\n    \"noNewArrows\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-arrow-functions\"]\n}\n```\n\nSet `noNewArrows: false` if you want the spec-compliant path without configuring `spec: true` on this plugin directly.\n\n## Common build setup\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.27.1\",\n    \"@babel/core\": \"^7.27.1\",\n    \"@babel/plugin-transform-arrow-functions\": \"^7.27.1\"\n  }\n}\n```\n\nWith `babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-arrow-functions\"]\n}\n```\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; it is a peer dependency\n- No environment variables or client initialization are required; this package only changes compiled output\n- This plugin only transforms arrow functions; it does not transpile unrelated syntax such as classes or module syntax\n- `spec: true` emits extra generated code, including a check function and `.bind(this)`, so output is larger than the default transform\n- In `7.27.1`, `assumptions.noNewArrows` takes precedence over the plugin's `spec` option, so keep those settings aligned\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-arrow-functions@7.27.1`\n- The package declares `@babel/core` peer compatibility as `^7.0.0-0`\n- The published package declares `node >= 6.9.0` in `engines`, but your effective support matrix still depends on the rest of your Babel toolchain\n- In `7.27.1`, the published package exposes the `spec` option and reads the top-level Babel `noNewArrows` assumption in its implementation\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-arrow-functions\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-arrow-functions\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-arrow-functions\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-async-to-generator/javascript/DOC.md",
    "content": "---\nname: plugin-transform-async-to-generator\ndescription: \"Babel plugin for rewriting async functions into generator-based code during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,async,generators\"\n---\n\n# @babel/plugin-transform-async-to-generator\n\n`@babel/plugin-transform-async-to-generator` rewrites `async` / `await` functions into generator-based code. It is a Babel compile-time transform: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-async-to-generator\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-async-to-generator\"]\n}\n```\n\nThis is enough to transform async functions in files Babel compiles.\n\n## Use it from the CLI\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-async-to-generator\n```\n\nFor a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-async-to-generator\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst input = `\nasync function fetchUser(id) {\n  await loadUser(id);\n  return id;\n}\n`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-async-to-generator\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration, Babel injects its `asyncToGenerator` helper and rewrites `await` expressions to `yield` inside a generator wrapper.\n\n## Use a custom wrapper with `module` and `method`\n\nThis plugin also supports a custom wrapper function. Set both `module` and `method` together:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-async-to-generator\",\n      {\n        \"module\": \"bluebird\",\n        \"method\": \"coroutine\"\n      }\n    ]\n  ]\n}\n```\n\nIf you use that example, install the runtime dependency too:\n\n```bash\nnpm install bluebird\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"async function run() { await task(); }\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-async-to-generator\", {\n    module: \"bluebird\",\n    method: \"coroutine\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThat produces code in this shape:\n\n```javascript\nimport { coroutine as _coroutine } from \"bluebird\";\n\nfunction run() {\n  return _run.apply(this, arguments);\n}\n\nfunction _run() {\n  _run = _coroutine(function* () {\n    yield task();\n  });\n  return _run.apply(this, arguments);\n}\n```\n\n## Common build setup\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.28.6\",\n    \"@babel/core\": \"^7.28.6\",\n    \"@babel/plugin-transform-async-to-generator\": \"^7.28.6\"\n  }\n}\n```\n\nWith `babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-async-to-generator\"]\n}\n```\n\n## Important notes\n\n- No environment variables are required. This plugin only changes compiled code.\n- `@babel/core` is required; the plugin is not useful by itself.\n- This transform still emits generator functions and uses `Promise` in the generated helper. If your target environment lacks generators or `Promise`, use `@babel/preset-env` or add the other transforms/polyfills your runtime needs.\n- If you set only `module` or only `method`, Babel does not use a custom wrapper. Set both options together.\n- If you already use `@babel/preset-env`, this transform is part of Babel's preset-env plugin set. Add the plugin directly when you need to force this transform or pass `module` / `method` options.\n- A custom wrapper controls runtime behavior for yielded values. This plugin only rewrites `async` functions to generator-based code and delegates execution to the wrapper you configure.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-block-scoping/javascript/DOC.md",
    "content": "---\nname: plugin-transform-block-scoping\ndescription: \"Babel plugin for compiling let and const to ES5-compatible output while preserving block-scoping behavior where possible\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,transpile,let,const\"\n---\n\n# @babel/plugin-transform-block-scoping\n\n`@babel/plugin-transform-block-scoping` compiles ES2015 block-scoped declarations (`let` and `const`) to ES5-style output. Use it when you need this transform explicitly in a Babel build.\n\nThis is a compile-time plugin. There are no environment variables, auth steps, or runtime clients to initialize.\n\nIf you already use `@babel/preset-env`, prefer setting `targets` there instead of adding this plugin manually. Babel includes this transform when your target environments need it.\n\n## Install\n\nInstall the plugin with `@babel/core`:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-block-scoping\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli @babel/core @babel/plugin-transform-block-scoping\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-block-scoping\"]\n}\n```\n\nThis is enough to rewrite `let` and `const` in files Babel compiles.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-block-scoping\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-block-scoping\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nfor (let i = 0; i < 2; i++) {\n  console.log(i);\n}\n\nconst answer = 42;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-block-scoping\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe generated output rewrites block-scoped declarations to ES5-compatible code and adds extra machinery when needed to preserve loop semantics.\n\n## Fail fast when a loop transform would need a closure\n\nSome `let` bindings inside loops must be wrapped in a generated closure to preserve per-iteration values captured by nested functions.\n\nSet `throwIfClosureRequired: true` when you want Babel to stop instead of emitting that extra closure code:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-block-scoping\",\n      {\n        \"throwIfClosureRequired\": true\n      }\n    ]\n  ]\n}\n```\n\nThis matters for code like:\n\n```javascript\nconst callbacks = [];\n\nfor (let i = 0; i < 3; i++) {\n  callbacks.push(() => i);\n}\n```\n\nWith `throwIfClosureRequired: true`, Babel throws instead of compiling that pattern with an added closure. Use this when you want to catch potentially expensive transforms during builds.\n\n## Enable temporal dead zone checks\n\nSet `tdz: true` when you want Babel to inject runtime checks for references that happen before a `let` or `const` declaration is initialized:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-block-scoping\",\n      {\n        \"tdz\": true\n      }\n    ]\n  ]\n}\n```\n\nExample source:\n\n```javascript\nconsole.log(count);\nlet count = 1;\n```\n\nWith `tdz: true`, Babel injects helper-based checks for temporal dead zone access. This is useful when you need closer ES2015 behavior in transformed output.\n\n## Important pitfalls\n\n- Install `@babel/core` with the plugin; the plugin alone is not enough\n- Prefer `@babel/preset-env` when your real goal is target-based transpilation across multiple ES features\n- `throwIfClosureRequired` is a build guardrail, not a compatibility fix; it intentionally fails valid code that depends on per-iteration closure semantics\n- `tdz: true` adds helper-based runtime checks; treat it as transformed compatibility behavior rather than a replacement for native engine semantics\n- The plugin only handles block scoping; it does not polyfill unrelated syntax transforms or built-in APIs\n- Reassigning a transformed `const` binding still triggers Babel's generated read-only error helper rather than silently becoming mutable output\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-class-properties/javascript/DOC.md",
    "content": "---\nname: plugin-transform-class-properties\ndescription: \"Babel plugin for compiling public and private class fields during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,class-fields,javascript\"\n---\n\n# @babel/plugin-transform-class-properties\n\n`@babel/plugin-transform-class-properties` rewrites class field syntax during Babel compilation. In Babel `7.28.6`, that includes public instance fields, static fields, and private fields such as `#value`. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-class-properties\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-class-properties\"]\n}\n```\n\nWhen this transform is active, Babel enables parsing for class field syntax automatically. You do not need separate syntax plugins for public or private class fields.\n\n## Run it from the CLI\n\nCompile a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-class-properties\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-class-properties\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, build tool, or test helper:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nclass Counter {\n  static label = \"counter\";\n  count = 0;\n  #step = 1;\n\n  next() {\n    this.count += this.#step;\n    return this.count;\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-class-properties\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in Babel `7.28.6`, public fields are emitted with Babel's `defineProperty` helper and private fields are emitted with private-field helpers backed by a `WeakMap`.\n\n## What the plugin rewrites\n\nThis plugin covers class field declarations and private field access:\n\n```javascript\nclass Example {\n  static version = 1;\n  name = \"demo\";\n  #count = 0;\n\n  increment() {\n    this.#count += 1;\n    return this.#count;\n  }\n}\n```\n\nIt does not enable private class methods such as `#inc() {}`. If your code uses private methods, add `@babel/plugin-transform-private-methods` too.\n\n## Use assignment-style output for public fields\n\nBy default, Babel emits helper-based `defineProperty` code for public class fields. If you want direct assignment output instead, enable `loose: true`:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-class-properties\", { \"loose\": true }]]\n}\n```\n\nFor code like this:\n\n```javascript\nclass Example {\n  static version = 1;\n  name = \"demo\";\n}\n```\n\nthe generated output is shaped like this in `loose` mode:\n\n```javascript\nclass Example {\n  constructor() {\n    this.name = \"demo\";\n  }\n}\n\nExample.version = 1;\n```\n\nYou can also use the top-level Babel assumption instead of the plugin-local `loose` option:\n\n```json\n{\n  \"assumptions\": {\n    \"setPublicClassFields\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-class-properties\"]\n}\n```\n\nIn Babel `7.28.6`, `assumptions.setPublicClassFields: true` produces the same assignment-style public-field output as `loose: true`.\n\n## Combine it with other class-features plugins\n\n`@babel/plugin-transform-class-properties` handles fields, but other class features still need their own plugins:\n\n- `@babel/plugin-transform-private-methods` for `#method()`\n- `@babel/plugin-transform-private-property-in-object` for `#field in obj`\n- `@babel/plugin-transform-class-static-block` for `static {}` blocks\n\nInstall the related plugins when your source uses those syntaxes:\n\n```bash\nnpm install --save-dev @babel/plugin-transform-private-methods @babel/plugin-transform-private-property-in-object\n```\n\nKeep the `loose` setting the same across the class-features plugins when they are enabled together:\n\n```json\n{\n  \"plugins\": [\n    [\"@babel/plugin-transform-class-properties\", { \"loose\": true }],\n    [\"@babel/plugin-transform-private-methods\", { \"loose\": true }],\n    [\"@babel/plugin-transform-private-property-in-object\", { \"loose\": true }]\n  ]\n}\n```\n\nBabel throws if these plugins are loaded with conflicting `loose` values.\n\n## Common workflow: pair with decorators or `preset-env`\n\nIf the same build uses legacy decorators, put the decorators plugin before this one and enable `loose: true` for class properties:\n\n```json\n{\n  \"plugins\": [\n    [\"@babel/plugin-proposal-decorators\", { \"version\": \"legacy\" }],\n    [\"@babel/plugin-transform-class-properties\", { \"loose\": true }]\n  ]\n}\n```\n\nIf you already compile for target environments with `@babel/preset-env`, prefer letting the preset include class-features transforms automatically unless you need to force this plugin explicitly.\n\n## Important pitfalls\n\n- This plugin transforms class fields, including private fields like `#value`, but it does not transform private methods.\n- Private fields in decorated classes are not supported and Babel throws during compilation.\n- When Babel reports `Class fields are not enabled`, this plugin is missing from the loaded config for that file.\n- When Babel reports a `loose` mode conflict, align `loose` across `@babel/plugin-transform-class-properties`, `@babel/plugin-transform-private-methods`, and `@babel/plugin-transform-private-property-in-object`.\n- This plugin changes emitted JavaScript only; it does not polyfill runtime APIs or add browser support at runtime.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-classes/javascript/DOC.md",
    "content": "---\nname: plugin-transform-classes\ndescription: \"Babel plugin for compiling ES2015 classes to ES5-compatible constructor and prototype code\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,classes,inheritance\"\n---\n\n# @babel/plugin-transform-classes\n\n`@babel/plugin-transform-classes` compiles ES2015 class syntax into constructor functions and helper-based prototype code during Babel builds. In Babel `7.28.6`, it covers class declarations, class expressions, inheritance, `super(...)`, instance methods, static methods, getters, and setters. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-classes\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin by itself is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-classes\"]\n}\n```\n\nWith the default configuration, Babel emits helper-based class code such as `_classCallCheck`, `_inherits`, and `_createClass` when the source needs them.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-classes\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-classes\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, build step, or test helper:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nclass Counter {\n  increment(step) {\n    return step + 1;\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-classes\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nIn Babel `7.28.6`, the generated output is shaped like this:\n\n```javascript\nlet Counter = /*#__PURE__*/function () {\n  function Counter() {\n    _classCallCheck(this, Counter);\n  }\n  return _createClass(Counter, [{\n    key: \"increment\",\n    value: function increment(step) {\n      return step + 1;\n    }\n  }]);\n}();\n```\n\n## Use `loose` for simpler method output\n\nBy default, Babel defines class methods through the `_createClass` helper. Set `loose: true` when you want assignment-style output instead:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-classes\", { \"loose\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"class Counter { increment(step) { return step + 1; } }\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-classes\", { loose: true }]],\n});\n```\n\nIn Babel `7.28.6`, `loose: true` changes the emitted shape to direct assignments:\n\n```javascript\nlet Counter = /*#__PURE__*/function () {\n  function Counter() {}\n  var _proto = Counter.prototype;\n  _proto.increment = function increment(step) {\n    return step + 1;\n  };\n  return Counter;\n}();\n```\n\nThis also changes other class-related assumptions Babel falls back to in this plugin, including skipping `classCallCheck` and using looser `super` handling.\n\n## Prefer top-level Babel assumptions for whole-build behavior\n\nIn Babel `7.28.6`, this plugin reads four top-level assumptions:\n\n- `setClassMethods`\n- `constantSuper`\n- `superIsCallableConstructor`\n- `noClassCalls`\n\nConfigure them once at the top level when you want class transforms across the build to share the same behavior:\n\n```json\n{\n  \"assumptions\": {\n    \"setClassMethods\": true,\n    \"constantSuper\": true,\n    \"superIsCallableConstructor\": true,\n    \"noClassCalls\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-classes\"]\n}\n```\n\nThese assumptions map directly to the code generation paths in `@babel/plugin-transform-classes`:\n\n- `setClassMethods` emits direct method assignments such as `Ctor.prototype.run = function run() {}`\n- `noClassCalls` skips Babel's generated `classCallCheck(this, Ctor)` guard\n- `superIsCallableConstructor` emits `Super.call(...)` / `Super.apply(...)` style constructor calls instead of the `_callSuper(...)` helper path\n- `constantSuper` tells Babel's `super` replacement logic to treat the superclass reference as stable\n\nUse either top-level assumptions or `loose: true` deliberately. They change generated behavior, not just formatting.\n\n## Subclass built-ins like `Error`\n\nWhen a class extends an unshadowed global built-in such as `Error`, `Array`, or `HTMLElement`, Babel wraps the superclass with `wrapNativeSuper(...)` and emits helper-based constructor code.\n\nSource:\n\n```javascript\nclass AppError extends Error {\n  constructor(message) {\n    super(message);\n    this.name = \"AppError\";\n  }\n}\n```\n\nOutput shape in Babel `7.28.6`:\n\n```javascript\nlet AppError = /*#__PURE__*/function (_Error) {\n  function AppError(message) {\n    var _this;\n    _classCallCheck(this, AppError);\n    _this = _callSuper(this, AppError, [message]);\n    _this.name = \"AppError\";\n    return _this;\n  }\n  _inherits(AppError, _Error);\n  return _createClass(AppError);\n}(/*#__PURE__*/_wrapNativeSuper(Error));\n```\n\nThis plugin only rewrites syntax. It does not add global polyfills. If your runtime lacks the features Babel's helpers rely on, such as correct `Reflect.construct` behavior for native subclassing, handle that at the runtime or polyfill layer.\n\n## Use `@babel/preset-env` for target-based builds\n\nIf your goal is general environment compatibility, prefer `@babel/preset-env` and set targets there instead of listing this plugin manually:\n\n```bash\nnpm install --save-dev @babel/core @babel/preset-env\n```\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"18\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nIn the Babel `7.28.6` package set, `@babel/preset-env` includes `transform-classes` in its available plugin set. Add `@babel/plugin-transform-classes` directly when you need to force class rewriting or control class-specific options such as `loose`.\n\n## Important pitfalls\n\n- This plugin does not transform class fields or private class properties. If Babel throws `Missing class properties transform.`, add the relevant class-features transform for those files.\n- If methods use decorators, load the decorator plugin before `@babel/plugin-transform-classes`; otherwise Babel throws during compilation.\n- `loose: true` and the equivalent top-level assumptions change emitted semantics. Use them only when you want looser class output across the build.\n- This plugin changes syntax only. It does not inject polyfills for runtime APIs or browser features.\n- If you already use `@babel/preset-env`, adding this plugin manually is usually redundant unless you need its explicit options.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-destructuring/javascript/DOC.md",
    "content": "---\nname: plugin-transform-destructuring\ndescription: \"Babel plugin for compiling JavaScript destructuring syntax to ES5-compatible output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,destructuring,javascript\"\n---\n\n# @babel/plugin-transform-destructuring\n\n`@babel/plugin-transform-destructuring` rewrites array and object destructuring during Babel compilation. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-destructuring\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-destructuring\"]\n}\n```\n\nThis is enough to transform destructuring patterns in files Babel compiles.\n\n## Use it from the CLI\n\nTransform a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-destructuring\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-destructuring\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst [first, second] = list;\nconst { id, ...rest } = record;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-destructuring\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration, Babel emits helper-based code for iterable destructuring and object-rest copies.\n\n## What the plugin rewrites\n\nThe plugin handles destructuring patterns in more than plain variable declarations. The same transform also applies to assignment expressions, loop bindings, and `catch` parameters:\n\n```javascript\n({ a, b } = value);\n\nfor (const [key, entry] of entries) {\n  console.log(key, entry);\n}\n\ntry {\n  throw err;\n} catch ({ message, code }) {\n  console.log(message, code);\n}\n```\n\nNo extra plugin configuration is required for those forms.\n\n## Use `loose` for simpler emitted code\n\nSet `loose: true` when destructured iterables can be treated like arrays and object-rest copies do not need symbol support:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-destructuring\", { \"loose\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const [first, second] = list;\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-destructuring\", { loose: true }]],\n});\n```\n\nFor array destructuring, the output becomes a direct index lookup:\n\n```javascript\nconst _list = list,\n  first = _list[0],\n  second = _list[1];\n```\n\nIn Babel 7.28.5, `loose: true` feeds the same behavior as enabling the top-level `iterableIsArray` and `objectRestNoSymbols` assumptions for this plugin.\n\n## Allow array-like values with `allowArrayLike`\n\nBy default, array destructuring expects an actual array or another iterable value. Set `allowArrayLike: true` only when source code may destructure values with a numeric `length` but no iterator method.\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-destructuring\", { \"allowArrayLike\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const [first, second] = collection;\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-destructuring\", { allowArrayLike: true }]],\n});\n```\n\nWhen this option is enabled, Babel emits an extra fallback helper so array-like values can be copied by index.\n\n## Use `useBuiltIns` when copying the whole object\n\nSet `useBuiltIns: true` when you want Babel to call `Object.assign(...)` instead of emitting its own `_extends` helper for whole-object rest copies.\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-destructuring\", { \"useBuiltIns\": true }]]\n}\n```\n\nThis matters for patterns such as:\n\n```javascript\nconst { ...copy } = input;\n```\n\nWith `useBuiltIns: true`, Babel emits code in this shape:\n\n```javascript\nconst _input = input,\n  copy = Object.assign({}, (_objectDestructuringEmpty(_input), _input));\n```\n\nOnly enable this when `Object.assign` is available in your target runtime or polyfilled separately.\n\n## Use top-level assumptions instead of repeating options\n\nBabel also accepts assumptions at the top level. Use them when the same tradeoff should apply across your build.\n\nThis configuration matches the loose-mode behavior for this plugin:\n\n```json\n{\n  \"assumptions\": {\n    \"iterableIsArray\": true,\n    \"objectRestNoSymbols\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-destructuring\"]\n}\n```\n\nThis configuration matches `allowArrayLike: true`:\n\n```json\n{\n  \"assumptions\": {\n    \"arrayLikeIsIterable\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-destructuring\"]\n}\n```\n\nOnly enable assumptions that are true for the code being compiled. They change emitted semantics, not just performance.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; the plugin alone does not run Babel.\n- This plugin rewrites destructuring syntax only. It does not transform object spread expressions like `const copy = { ...input }`.\n- `loose: true` and `iterableIsArray: true` are only safe when the destructured values can be treated as arrays. Do not use them for general iterables such as `Set`, `Map`, generator results, or custom iterables.\n- `allowArrayLike: true` and `arrayLikeIsIterable: true` should only be enabled when code intentionally destructures array-like non-iterables.\n- `useBuiltIns: true` makes the emitted code depend on `Object.assign` for whole-object rest copies.\n- This plugin changes build output only; it does not add polyfills for missing runtime features such as iterators.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-dynamic-import/javascript/DOC.md",
    "content": "---\nname: plugin-transform-dynamic-import\ndescription: \"Babel plugin for rewriting import() expressions when compiling ES modules to CommonJS, AMD, or SystemJS\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,dynamic-import,modules\"\n---\n\n# @babel/plugin-transform-dynamic-import\n\n`@babel/plugin-transform-dynamic-import` rewrites `import()` expressions during Babel builds. Use it only when Babel is also converting ES modules to `commonjs`, `amd`, or `systemjs`. It is a compile-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall Babel core, this plugin, and a companion module transform. CommonJS is the most common setup:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-dynamic-import @babel/plugin-transform-modules-commonjs\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json` and pair the plugin with a supported modules transform:\n\n```json\n{\n  \"plugins\": [\n    \"@babel/plugin-transform-dynamic-import\",\n    \"@babel/plugin-transform-modules-commonjs\"\n  ]\n}\n```\n\nSupported companion module transforms are:\n\n- `@babel/plugin-transform-modules-commonjs`\n- `@babel/plugin-transform-modules-amd`\n- `@babel/plugin-transform-modules-systemjs`\n\nIf you target AMD or SystemJS instead of CommonJS, swap the second plugin name.\n\n## Use it from the CLI\n\nCompile a source directory to CommonJS:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-dynamic-import,@babel/plugin-transform-modules-commonjs\n```\n\nCompile a single file:\n\n```bash\nnpx babel src/load-widget.js --out-file lib/load-widget.js --plugins @babel/plugin-transform-dynamic-import,@babel/plugin-transform-modules-commonjs\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nexport function loadWidget() {\n  return import(\"./widget.js\");\n}\n`;\n\nconst result = transformSync(source, {\n  filename: \"src/load-widget.js\",\n  configFile: false,\n  babelrc: false,\n  plugins: [\n    \"@babel/plugin-transform-dynamic-import\",\n    \"@babel/plugin-transform-modules-commonjs\",\n  ],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nIn a CommonJS build, the rewritten `import()` call has this shape:\n\n```javascript\nPromise.resolve().then(() => _interopRequireWildcard(require(\"./widget.js\")));\n```\n\nThat means the transformed code expects a CommonJS-style `require()` at runtime.\n\n## Keep bundlers in charge when you want native `import()`\n\nDo not use this plugin when your bundler should handle dynamic imports for code splitting. Babel's own error guidance for this plugin points bundler users to `@babel/plugin-syntax-dynamic-import` instead.\n\nUse that parser-only plugin when you need Babel to accept `import()` syntax without rewriting it:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-syntax-dynamic-import\n```\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-syntax-dynamic-import\"]\n}\n```\n\nThis is the safer setup for tools such as Webpack or Rollup when they are responsible for loading split chunks.\n\n## Important notes\n\n- This plugin throws unless Babel also enables `@babel/plugin-transform-modules-commonjs`, `@babel/plugin-transform-modules-amd`, or `@babel/plugin-transform-modules-systemjs`.\n- Interop and module-output behavior come from the companion modules transform plugin. `@babel/plugin-transform-dynamic-import` only rewrites the `import()` expression itself.\n- CommonJS output uses `Promise.resolve()` and `require()`. If your runtime target needs additional compatibility transforms or polyfills, add them separately.\n- No environment variables are required.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-exponentiation-operator/javascript/DOC.md",
    "content": "---\nname: plugin-transform-exponentiation-operator\ndescription: \"Babel plugin for rewriting exponentiation operators into Math.pow-based JavaScript during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,exponentiation,es2016\"\n---\n\n# @babel/plugin-transform-exponentiation-operator\n\n`@babel/plugin-transform-exponentiation-operator` rewrites exponentiation syntax at build time:\n\n- `a ** b` → `Math.pow(a, b)`\n- `a **= b` → `a = Math.pow(a, b)`\n\nThis is a compile-time Babel transform. There are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-exponentiation-operator\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-exponentiation-operator\"]\n}\n```\n\nUse the plugin directly when you want to force exponentiation rewriting regardless of Babel targets.\n\n## Use it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-exponentiation-operator\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-exponentiation-operator\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when this transform is part of a script, codemod, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst squared = value ** 2;\n\nlet total = 2;\ntotal **= 3;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-exponentiation-operator\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThat produces output in this shape:\n\n```javascript\nconst squared = Math.pow(value, 2);\n\nlet total = 2;\ntotal = Math.pow(total, 3);\n```\n\n## Complex assignment targets are evaluated once\n\nFor compound assignment on member expressions, Babel memoizes the object or computed property when needed so side effects are not repeated.\n\nExample source:\n\n```javascript\nobj[getKey()] **= 2;\n```\n\nTransformed output:\n\n```javascript\nvar _obj, _getKey;\n\n(_obj = obj)[_getKey = getKey()] = Math.pow(_obj[_getKey], 2);\n```\n\nThis matters when `obj` or `getKey()` does work you only want to run once.\n\n## Use it with `@babel/preset-env`\n\n`@babel/preset-env` includes this transform. Prefer the preset when your goal is target-based transpilation across multiple language features.\n\nExample:\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"6\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nWith an older target such as Node 6, `@babel/preset-env` rewrites `**` to `Math.pow(...)`. With a target that already supports exponentiation syntax, Babel can leave the original operator in place.\n\nAdd this plugin directly when you want the transform even without `@babel/preset-env`, or when you want exponentiation rewritten regardless of targets.\n\n## Important notes\n\n- No environment variables are required; this plugin only changes compiled output\n- `@babel/core` is required; the plugin is not useful by itself\n- The plugin has no documented configuration options in `7.28.6`; setup is mainly choosing direct use versus `@babel/preset-env`\n- The transform rewrites syntax to `Math.pow(...)`; it does not polyfill unrelated language features or built-in APIs\n- If you already use `@babel/preset-env`, you usually do not need to list this plugin separately\n- Compound assignments like `obj[key] **= value` may introduce temporary variables in emitted code so Babel can preserve evaluation order\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-export-namespace-from/javascript/DOC.md",
    "content": "---\nname: plugin-transform-export-namespace-from\ndescription: \"Babel plugin for compiling export namespace re-exports during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,esm,exports\"\n---\n\n# @babel/plugin-transform-export-namespace-from\n\n`@babel/plugin-transform-export-namespace-from` rewrites namespace re-exports such as `export * as utils from \"./utils.js\";` during Babel compilation. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-export-namespace-from\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-export-namespace-from\"]\n}\n```\n\nThis enables parsing for `export * as name from \"module\"` and rewrites that syntax to standard `import` plus `export` statements.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-export-namespace-from\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-export-namespace-from\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, build tool, or test helper:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nexport * as utils from \"./utils.js\";\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-export-namespace-from\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe generated output looks like this:\n\n```javascript\nimport * as _utils from \"./utils.js\";\nexport { _utils as utils };\n```\n\n## Common workflow: also convert ES modules\n\nThis plugin only rewrites export-namespace syntax. The output still uses ES module `import` and `export` statements.\n\nIf your build also needs CommonJS output, add a module transform such as `@babel/plugin-transform-modules-commonjs`:\n\n```bash\nnpm install --save-dev @babel/plugin-transform-modules-commonjs\n```\n\n```json\n{\n  \"plugins\": [\n    \"@babel/plugin-transform-export-namespace-from\",\n    \"@babel/plugin-transform-modules-commonjs\"\n  ]\n}\n```\n\nOr let `@babel/preset-env` manage it for you:\n\n```bash\nnpm install --save-dev @babel/preset-env\n```\n\n```json\n{\n  \"presets\": [[\"@babel/preset-env\", { \"modules\": \"commonjs\" }]]\n}\n```\n\nWhen `@babel/preset-env` is already selecting transforms for your targets, prefer the preset rather than adding this plugin separately unless you need to force the transform.\n\n## Plugin options\n\n`@babel/plugin-transform-export-namespace-from` does not expose plugin-specific configuration options in `7.27.1`. Configuration is just enabling the plugin.\n\n## Important pitfalls\n\n- Install `@babel/core` with the plugin; the plugin alone is not enough\n- This plugin handles `export * as name from \"module\"`; it does not transform unrelated module syntax or built-in APIs\n- The transformed output is still ESM, so add a module transform or `@babel/preset-env` if your target environment does not support ES modules\n- If `@babel/preset-env` already covers your target environments, let the preset include this transform automatically instead of duplicating configuration\n- This plugin is syntax-focused and build-time only; there are no runtime imports, environment variables, or initialization steps to wire up in application code\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-for-of/javascript/DOC.md",
    "content": "---\nname: plugin-transform-for-of\ndescription: \"Babel plugin for rewriting JavaScript for...of loops during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,for-of,iteration\"\n---\n\n# @babel/plugin-transform-for-of\n\n`@babel/plugin-transform-for-of` rewrites `for...of` loops during Babel compilation. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-for-of\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-for-of\"]\n}\n```\n\nWith the default configuration, Babel emits iterator-helper code and preserves iterator closing semantics with `try` / `catch` / `finally`.\n\n## Use it from the CLI\n\nTransform a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-for-of\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-for-of\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst input = `\nfor (const item of iterable) {\n  console.log(item);\n}\n`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-for-of\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe output is shaped like this:\n\n```javascript\nvar _iterator = _createForOfIteratorHelper(iterable),\n  _step;\n\ntry {\n  for (_iterator.s(); !(_step = _iterator.n()).done;) {\n    const item = _step.value;\n    console.log(item);\n  }\n} catch (err) {\n  _iterator.e(err);\n} finally {\n  _iterator.f();\n}\n```\n\n## Smaller output with `loose`\n\nUse `loose: true` when you want shorter emitted code and do not need iterator closing behavior:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-for-of\", { \"loose\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"for (const item of iterable) console.log(item);\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-for-of\", { loose: true }]],\n});\n```\n\nThis switches Babel to the loose helper shape:\n\n```javascript\nfor (var _iterator = _createForOfIteratorHelperLoose(iterable), _step; !(_step = _iterator()).done;) {\n  const item = _step.value;\n  console.log(item);\n}\n```\n\n## Assume every iterable is an array\n\nIf every transformed `for...of` in a file iterates real arrays, `assumeArray: true` emits a simple index-based loop:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-for-of\", { \"assumeArray\": true }]]\n}\n```\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"for (const item of items) total += item;\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-for-of\", { assumeArray: true }]],\n});\n```\n\nOutput shape:\n\n```javascript\nfor (let _i = 0, _items = items; _i < _items.length; _i++) {\n  const item = _items[_i];\n  total += item;\n}\n```\n\nUse this only when the right-hand side is always an actual array. Do not use it for `Set`, `Map`, generator results, strings, or custom iterables.\n\n## Allow array-like values\n\nUse `allowArrayLike: true` only when source code may iterate values with a numeric `length` but no iterator method.\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-for-of\", { \"allowArrayLike\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"for (const node of collection) use(node);\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-for-of\", { allowArrayLike: true }]],\n});\n```\n\nWhen this option is enabled, Babel passes `true` into the generated helper so array-like values can be consumed by index.\n\n`allowArrayLike` requires `@babel/core` `^7.10.0` or newer.\n\n## Use top-level Babel assumptions\n\nThis plugin also reads Babel assumptions. Configure them once at the top level instead of repeating per-plugin options.\n\n`iterableIsArray` tells Babel to compile `for...of` as array iteration:\n\n```json\n{\n  \"assumptions\": {\n    \"iterableIsArray\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-for-of\"]\n}\n```\n\n`skipForOfIteratorClosing` gives the same iterator-closing tradeoff as loose mode:\n\n```json\n{\n  \"assumptions\": {\n    \"skipForOfIteratorClosing\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-for-of\"]\n}\n```\n\n`arrayLikeIsIterable` enables array-like fallback handling globally:\n\n```json\n{\n  \"assumptions\": {\n    \"arrayLikeIsIterable\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-for-of\"]\n}\n```\n\nDo not combine `iterableIsArray` with `arrayLikeIsIterable`; the plugin rejects that configuration.\n\n## What Babel already optimizes without extra options\n\nEven with the default configuration, Babel already emits a simple indexed loop when it can statically see that the right-hand side is an array expression.\n\nInput:\n\n```javascript\nfor (const item of [1, 2, 3]) {\n  console.log(item);\n}\n```\n\nOutput shape:\n\n```javascript\nfor (var _i = 0, _arr = [1, 2, 3]; _i < _arr.length; _i++) {\n  const item = _arr[_i];\n  console.log(item);\n}\n```\n\nThat means you usually do not need `assumeArray` just for obvious array literals.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin. `@babel/plugin-transform-for-of` declares Babel core as a peer dependency.\n- Do not combine `loose: true` with `assumeArray: true`.\n- Do not combine `assumeArray: true` with `allowArrayLike: true`.\n- Do not enable both `iterableIsArray` and `arrayLikeIsIterable` assumptions.\n- This plugin does not add global polyfills. If your target runtime lacks iterator support such as `Symbol.iterator`, add the required polyfills separately.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-json-strings/javascript/DOC.md",
    "content": "---\nname: plugin-transform-json-strings\ndescription: \"Babel plugin for escaping U+2028 and U+2029 inside JavaScript string literals during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,strings,json,transpile\"\n---\n\n# @babel/plugin-transform-json-strings\n\n`@babel/plugin-transform-json-strings` escapes raw `U+2028` LINE SEPARATOR and `U+2029` PARAGRAPH SEPARATOR characters in compiled JavaScript string literals. Use it when source files may contain those characters and you want Babel to emit `\\u2028` and `\\u2029` escape sequences instead of raw separators.\n\nThis is a compile-time Babel plugin. There are no package-specific environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-json-strings\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli @babel/core @babel/plugin-transform-json-strings\n```\n\nThe published package declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-json-strings\"]\n}\n```\n\nIn `7.28.6`, the published package does not expose plugin-specific options. Adding it to `plugins` is enough.\n\n## Run it from the CLI\n\nCompile a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-json-strings\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-json-strings\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a build script, test helper, or custom compiler step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst lineSeparator = String.fromCharCode(0x2028);\nconst paragraphSeparator = String.fromCharCode(0x2029);\n\nconst input = `const text = \"before${lineSeparator}middle${paragraphSeparator}after\";`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-json-strings\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe emitted code is in this shape:\n\n```javascript\nconst text = \"before\\u2028middle\\u2029after\";\n```\n\n## What the plugin changes\n\nIn `7.28.6`, the implementation does three relevant things:\n\n- It rewrites raw `U+2028` and `U+2029` characters in `StringLiteral` and `DirectiveLiteral` nodes.\n- It leaves already-escaped sequences alone, so existing `\\u2028` and `\\u2029` escapes are not rewritten again.\n- It enables Babel's `jsonStrings` parser plugin while parsing, so the file can be parsed before Babel rewrites the literals.\n\nThe runtime string value does not change. Only the emitted source text changes from raw separator characters to Unicode escape sequences.\n\n## Common setup\n\nUse a normal Babel build script:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.28.6\",\n    \"@babel/core\": \"^7.28.6\",\n    \"@babel/plugin-transform-json-strings\": \"^7.28.6\"\n  }\n}\n```\n\nWith `babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-json-strings\"]\n}\n```\n\n## Important pitfalls\n\n- This plugin only affects Babel output. It does not polyfill runtime features or change how strings behave at runtime.\n- It only visits string literals and directive literals. It is not a general-purpose JSON-file transformer.\n- The published package for `7.28.6` does not define any plugin options, so array-style plugin configuration is unnecessary unless you are following a shared config format.\n- If you still see raw separator characters in emitted code, confirm that this plugin is active for the files being compiled.\n- Install `@babel/core` alongside the plugin; the package declares Babel core as a peer dependency.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-json-strings@7.28.6`.\n- The published package describes the plugin as escaping `U+2028` and `U+2029` in JavaScript strings.\n- The published package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- The published package declares `node >= 6.9.0` in `engines`.\n- In `7.28.6`, the implementation rewrites only `StringLiteral` and `DirectiveLiteral` raw text and skips separator characters that are already escaped.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-json-strings\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-json-strings\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-json-strings\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-logical-assignment-operators/javascript/DOC.md",
    "content": "---\nname: plugin-transform-logical-assignment-operators\ndescription: \"Babel plugin for rewriting logical assignment operators into short-circuited JavaScript assignments during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,logical-assignment,es2021\"\n---\n\n# @babel/plugin-transform-logical-assignment-operators\n\n`@babel/plugin-transform-logical-assignment-operators` rewrites logical assignment operators at build time:\n\n- `a ||= b` → `a || (a = b)`\n- `a &&= b` → `a && (a = b)`\n- `a ??= b` → `a ?? (a = b)`\n\nThis is a compile-time Babel transform. There are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-logical-assignment-operators\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-logical-assignment-operators\"]\n}\n```\n\nWhen you use the transform directly, Babel also enables parsing for logical assignment syntax, so you do not need a separate syntax plugin.\n\n## Use it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-logical-assignment-operators\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-logical-assignment-operators\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when this transform is part of a script, codemod, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nlet ready = false;\nready ||= true;\n\nconst session = { active: true };\nsession.active &&= isStillActive();\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-logical-assignment-operators\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThat produces output in this shape:\n\n```javascript\nlet ready = false;\nready || (ready = true);\n\nconst session = {\n  active: true\n};\nsession.active && (session.active = isStillActive());\n```\n\n## Complex left-hand sides are only evaluated once\n\nFor member expressions, Babel memoizes the object or computed property when needed so the left-hand side is not re-evaluated.\n\nExample source:\n\n```javascript\nobj[getKey()] &&= value;\n```\n\nTransformed output:\n\n```javascript\nvar _obj, _getKey;\n\n(_obj = obj)[_getKey = getKey()] && (_obj[_getKey] = value);\n```\n\nThis matters when the object expression or property lookup has side effects.\n\n## `??=` may need an additional transform\n\nThis plugin rewrites `??=` to `??` plus an assignment. It does not remove the nullish coalescing operator by itself.\n\nExample source:\n\n```javascript\nuser.settings.theme ??= \"dark\";\n```\n\nWith only this plugin, Babel emits:\n\n```javascript\nvar _user$settings;\n\n(_user$settings = user.settings).theme ?? (_user$settings.theme = \"dark\");\n```\n\nIf your target runtime does not support `??`, also use `@babel/plugin-transform-nullish-coalescing-operator` or `@babel/preset-env`:\n\n```json\n{\n  \"plugins\": [\n    \"@babel/plugin-transform-logical-assignment-operators\",\n    \"@babel/plugin-transform-nullish-coalescing-operator\"\n  ]\n}\n```\n\n## Use it with `@babel/preset-env`\n\n`@babel/preset-env` includes this transform. Prefer the preset when your real goal is target-based transpilation across multiple language features.\n\nExample:\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"14\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nAdd this plugin directly when you want to force only logical assignment rewriting in an otherwise narrow Babel setup.\n\n## Important notes\n\n- No environment variables are required; this plugin only changes compiled output\n- `@babel/core` is required; the plugin is not useful by itself\n- The plugin has no documented configuration options in `7.28.6`; the main setup choice is whether to use it directly or via `@babel/preset-env`\n- `??=` rewrites to `??`, not to ES5-only code; add `@babel/plugin-transform-nullish-coalescing-operator` or use `@babel/preset-env` when older runtimes must not receive `??`\n- The transform preserves short-circuiting and avoids re-evaluating complex member expressions by introducing temporary variables when needed\n- This plugin only handles logical assignment operators; it does not polyfill built-in APIs or replace unrelated syntax transforms\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-modules-commonjs/javascript/DOC.md",
    "content": "---\nname: plugin-transform-modules-commonjs\ndescription: \"Babel plugin for rewriting ES module syntax to CommonJS with configurable interop, lazy imports, and strict-mode behavior\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,commonjs,modules,javascript,build\"\n---\n\n`@babel/plugin-transform-modules-commonjs` rewrites `import` and `export` syntax into CommonJS output. Use it when your source is written as ES modules but your runtime, test environment, or published build still needs `require(...)` and `exports`.\n\nNo environment variables or runtime authentication are required. This is a build-time Babel plugin.\n\n## Install\n\nInstall the plugin with `@babel/core`:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-modules-commonjs\n```\n\nIf you want to run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli @babel/core @babel/plugin-transform-modules-commonjs\n```\n\nThe package declares `@babel/core` as a peer dependency, so the plugin is not enough on its own.\n\n## Add the plugin to Babel\n\nUse a Babel config file when you want every transform to emit CommonJS:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-modules-commonjs\"]\n}\n```\n\nRun the same transform from the CLI:\n\n```bash\nnpx babel src --out-dir dist --plugins @babel/plugin-transform-modules-commonjs\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, codemod, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nimport answer, { double } from \"./math.js\";\n\nexport const result = double(answer);\n`;\n\nconst output = transformSync(source, {\n  filename: \"src/example.js\",\n  plugins: [\"@babel/plugin-transform-modules-commonjs\"],\n});\n\nif (!output?.code) {\n  throw new Error(\"Babel did not return transformed code\");\n}\n\nconsole.log(output.code);\n```\n\n## Choose how default imports interoperate with CommonJS\n\nThe plugin accepts `importInterop` with three string modes:\n\n- `\"babel\"` — default behavior unless `noInterop: true` is set\n- `\"node\"` — Node-style interop\n- `\"none\"` — no interop helper wrapping\n\nUse a JSON config when a single mode works for the whole project:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"importInterop\": \"node\"\n      }\n    ]\n  ]\n}\n```\n\nUse a JavaScript config when you want to decide per import source:\n\n```javascript\nmodule.exports = {\n  plugins: [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        importInterop(source, filename) {\n          if (source.startsWith(\".\")) {\n            return \"none\";\n          }\n\n          return \"node\";\n        },\n      },\n    ],\n  ],\n};\n```\n\nIf you maintain an older config that still uses `noInterop: true`, Babel resolves that the same way as `importInterop: \"none\"`.\n\n## Lazy-load selected dependencies\n\nSet `lazy` when you want generated `require(...)` calls to happen on first use instead of at module initialization time.\n\nLazy-load bare package imports:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"lazy\": true\n      }\n    ]\n  ]\n}\n```\n\nLazy-load only specific packages:\n\n```javascript\nmodule.exports = {\n  plugins: [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        lazy: [\"chalk\", \"lodash\"],\n      },\n    ],\n  ],\n};\n```\n\nImportant details from the plugin implementation:\n\n- `lazy: true` only lazy-loads non-relative imports such as `chalk`; relative imports such as `./utils.js` stay eager\n- side-effect imports and `export * from ...` are not wrapped lazily\n- `lazy` may be `true`, an array of module specifiers, or a function\n\n## Control strict-mode output and top-level `this`\n\nBy default, the transform inserts `\"use strict\"` if the file does not already have it, and it rewrites top-level `this` to `undefined`.\n\nTurn both behaviors off explicitly when you need legacy CommonJS semantics:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"strictMode\": false,\n        \"allowTopLevelThis\": true\n      }\n    ]\n  ]\n}\n```\n\nUse this carefully: it changes emitted runtime behavior, not just formatting.\n\n## Fail fast on accidental `module` or `exports` usage\n\nES module source that still refers to top-level CommonJS globals can be hard to spot during a migration. Set `allowCommonJSExports: false` to make those references throw instead of silently behaving like CommonJS code.\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"allowCommonJSExports\": false\n      }\n    ]\n  ]\n}\n```\n\nWhen this option is disabled, Babel guards top-level `module` and `exports` access in ES module files and points you toward `sourceType: \"script\"` or `sourceType: \"unambiguous\"` if the file should not be treated as a module.\n\n## Advanced interop flags\n\nTwo less common namespace options are available when CommonJS default-vs-namespace behavior matters:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"strictNamespace\": true,\n        \"mjsStrictNamespace\": true\n      }\n    ]\n  ]\n}\n```\n\n- `strictNamespace` applies stricter `.default` handling for non-`.mjs` files\n- `mjsStrictNamespace` defaults to `strictNamespace` and lets you set different behavior for `.mjs` files\n\nIf you need to suppress Babel's generated `__esModule` marker, set `strict: true`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-modules-commonjs\",\n      {\n        \"strict\": true\n      }\n    ]\n  ]\n}\n```\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; it is a peer dependency, not a bundled runtime\n- Use `babel.config.js` or `babel.config.cjs` for function-valued options such as `importInterop(source, filename)` or `lazy(source)`\n- `lazy: true` does not make relative imports lazy; it only affects bare package imports\n- `strictMode: false` stops Babel from injecting `\"use strict\"`, and `allowTopLevelThis: true` stops Babel from rewriting top-level `this`\n- `strict: true` suppresses the generated `__esModule` header, which can affect downstream consumers that rely on that marker\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-modules-commonjs@7.28.6`\n- The package declares `@babel/core` peer compatibility as `^7.0.0-0`\n- The published package declares `node >= 6.9.0` in `engines`, but your effective support matrix still depends on the rest of your Babel toolchain\n- In `7.28.6`, `allowCommonJSExports` defaults to `true`, `lazy` defaults to `false`, `strictNamespace` defaults to `false`, and `mjsStrictNamespace` defaults to `strictNamespace`\n- If you already set Babel assumptions such as `constantReexports` or `enumerableModuleMeta`, those assumptions take precedence over this plugin's `loose` fallback\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-modules-commonjs\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-modules-commonjs\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-modules-commonjs\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-nullish-coalescing-operator/javascript/DOC.md",
    "content": "---\nname: plugin-transform-nullish-coalescing-operator\ndescription: \"Babel plugin for compiling JavaScript nullish coalescing expressions to compatible output during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,nullish-coalescing,javascript\"\n---\n\n# @babel/plugin-transform-nullish-coalescing-operator\n\n`@babel/plugin-transform-nullish-coalescing-operator` rewrites JavaScript nullish coalescing expressions such as `value ?? fallback` during Babel builds. It is a compile-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-nullish-coalescing-operator\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-nullish-coalescing-operator\"]\n}\n```\n\nThis transform enables Babel's `nullishCoalescingOperator` parser support internally, so you do not need to add `@babel/plugin-syntax-nullish-coalescing-operator` for the same files.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-nullish-coalescing-operator\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-nullish-coalescing-operator\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst label = options.label ?? \"untitled\";\nconst timeout = getConfig().timeout ?? 5000;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-nullish-coalescing-operator\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in Babel `7.28.6`, the emitted code uses explicit `null` / `undefined` checks plus temporary variables when needed so the left-hand side is not evaluated more than once.\n\n## What the plugin rewrites\n\nThis plugin handles plain nullish coalescing expressions:\n\n```javascript\nconst label = options.label ?? \"untitled\";\nconst timeout = getConfig().timeout ?? 5000;\n```\n\nThe output is in this shape:\n\n```javascript\nvar _options$label, _getConfig$timeout;\n\nconst label = (_options$label = options.label) !== null && _options$label !== void 0 ? _options$label : \"untitled\";\nconst timeout = (_getConfig$timeout = getConfig().timeout) !== null && _getConfig$timeout !== void 0 ? _getConfig$timeout : 5000;\n```\n\nThat temporary variable behavior is important when the left-hand side is a property access or function call with possible side effects.\n\n## Prefer `assumptions.noDocumentAll` over `loose`\n\nBy default, Babel emits separate checks for `null` and `undefined`.\n\nWhen you want Babel to treat `document.all` as if it does not exist and emit the shorter `!= null` check form, set the top-level Babel assumption:\n\n```json\n{\n  \"assumptions\": {\n    \"noDocumentAll\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-nullish-coalescing-operator\"]\n}\n```\n\nThe plugin also still accepts `loose: true`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-nullish-coalescing-operator\",\n      {\n        \"loose\": true\n      }\n    ]\n  ]\n}\n```\n\nWith either of those settings in `7.28.6`, Babel emits output in this shape:\n\n```javascript\nvar _input;\n\nconst value = (_input = input) != null ? _input : fallback;\n```\n\nPrefer the top-level assumption when you want this behavior explicitly across a build. In the published `7.28.6` plugin source, `loose` acts as the fallback for `assumptions.noDocumentAll`.\n\n## `??=` needs an additional transform\n\nThis plugin only rewrites the `??` operator. It does not transform the nullish assignment operator `??=` by itself.\n\nIf your source uses `??=`, also add `@babel/plugin-transform-logical-assignment-operators` or use `@babel/preset-env`:\n\n```json\n{\n  \"plugins\": [\n    \"@babel/plugin-transform-logical-assignment-operators\",\n    \"@babel/plugin-transform-nullish-coalescing-operator\"\n  ]\n}\n```\n\nUse that combination for code like this:\n\n```javascript\nsettings.theme ??= \"dark\";\n```\n\n## Use it through `@babel/preset-env`\n\nIf your real goal is target-based transpilation across multiple JavaScript features, prefer `@babel/preset-env` instead of listing this plugin manually.\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"12\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nUse the standalone plugin when you want to force only nullish coalescing rewriting in an otherwise narrow Babel setup.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; the plugin alone does not run Babel.\n- This transform changes compiled syntax only. It does not polyfill runtime APIs or add unrelated language features.\n- Do not add `@babel/plugin-syntax-nullish-coalescing-operator` for the same files unless you have a very specific pipeline reason; the transform already enables parsing.\n- If you already use `@babel/preset-env`, adding this plugin manually is usually redundant.\n- `loose: true` or `assumptions.noDocumentAll: true` changes how Babel treats the `document.all` edge case; use that only when the looser nullish check semantics are acceptable.\n- This plugin does not handle `??=` by itself; add `@babel/plugin-transform-logical-assignment-operators` when your code uses nullish assignment.\n- No environment variables, authentication, or runtime client initialization are involved; all setup lives in Babel config or build scripts.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-nullish-coalescing-operator@7.28.6`.\n- The published `7.28.6` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.28.6`, the plugin source enables Babel's `nullishCoalescingOperator` parser plugin internally, so the transform also covers syntax enablement.\n- In `7.28.6`, `loose` defaults to `false` and acts as the fallback for the top-level Babel assumption `noDocumentAll`.\n- In `7.28.6`, the plugin source also reads Babel's top-level `pureGetters` assumption, but that assumption remains separate from `loose`.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-nullish-coalescing-operator\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-nullish-coalescing-operator\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-nullish-coalescing-operator\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-numeric-separator/javascript/DOC.md",
    "content": "---\nname: plugin-transform-numeric-separator\ndescription: \"Babel plugin for removing numeric separators from JavaScript number and BigInt literals during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,numeric-separator,bigint\"\n---\n\n# @babel/plugin-transform-numeric-separator\n\n`@babel/plugin-transform-numeric-separator` removes `_` separators from numeric literals in compiled output. It handles decimal, binary, octal, hexadecimal, and BigInt literals.\n\nThis is a compile-time Babel transform only. There are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall Babel core and the plugin together:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-numeric-separator\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n`@babel/core` is a peer dependency, so installing the plugin by itself is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-numeric-separator\"]\n}\n```\n\nWhen you use this transform directly, Babel also enables parsing for numeric separators, so you do not need to add `@babel/plugin-syntax-numeric-separator` separately.\n\n## Use it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-numeric-separator\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-numeric-separator\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst budget = 1_000_000;\nconst mask = 0b1010_0001;\nconst timeout = 0x0A_FF;\nconst orderId = 12_345n;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-numeric-separator\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nOutput has the same literals with separators removed:\n\n```javascript\nconst budget = 1000000;\nconst mask = 0b10100001;\nconst timeout = 0x0AFF;\nconst orderId = 12345n;\n```\n\n## BigInt literals are not downleveled\n\nThis plugin removes separators from `BigInt` literals, but it still leaves them as `...n` literals.\n\nExample source:\n\n```javascript\nconst maxId = 9_007_199_254_740_993n;\n```\n\nTransformed output:\n\n```javascript\nconst maxId = 9007199254740993n;\n```\n\nIf your runtime does not support `BigInt` literals, this plugin does not make that code compatible by itself.\n\n## Prefer `@babel/preset-env` for target-based builds\n\n`@babel/preset-env` includes this transform. Use the preset when your real goal is to support older runtimes instead of forcing only this one syntax rewrite.\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"10\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nIn Babel's compatibility data, numeric separators are supported starting at Node `12.5`, Chrome `75`, Firefox `70`, and Safari `13`. If you still target older runtimes, `@babel/preset-env` can add this transform automatically.\n\n## Important notes\n\n- No environment variables are required.\n- The plugin has no documented configuration options in `7.28.6`.\n- The transform only removes `_` from numeric literal source text; it does not polyfill language features or built-in APIs.\n- When you already use `@babel/preset-env`, you usually do not need to list this plugin manually.\n- When you use the transform directly, you do not need a separate numeric-separator syntax plugin.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-object-rest-spread/javascript/DOC.md",
    "content": "---\nname: plugin-transform-object-rest-spread\ndescription: \"Babel plugin for compiling object rest destructuring and object spread literals to older JavaScript output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,object-rest-spread,javascript\"\n---\n\n# @babel/plugin-transform-object-rest-spread\n\n`@babel/plugin-transform-object-rest-spread` rewrites object rest destructuring and object spread literals during Babel compilation. It is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-object-rest-spread\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-object-rest-spread\"]\n}\n```\n\nThis is enough to compile both object-rest destructuring and object spread in object literals.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-object-rest-spread\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-object-rest-spread\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst { id, ...rest } = record;\nconst payload = { type: \"user\", ...rest };\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-object-rest-spread\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe transform enables the `objectRestSpread` parser feature internally, so you do not need a separate syntax plugin when this transform is active.\n\n## What the plugin rewrites\n\nThis plugin handles both halves of the feature:\n\n```javascript\nconst { id, ...rest } = record;\n\nfunction stripId({ id, ...rest }) {\n  return rest;\n}\n\nconst payload = {\n  type: \"user\",\n  ...rest,\n};\n```\n\nWith the default configuration, Babel emits helper-based code for rest extraction and spread merging.\n\n## Control assignment-style output with `useBuiltIns`\n\nWhen you want assignment-style copies, set `assumptions.setSpreadProperties: true`. Pair it with `useBuiltIns: true` to emit `Object.assign(...)` instead of Babel's `_extends` helper.\n\n```json\n{\n  \"assumptions\": {\n    \"setSpreadProperties\": true\n  },\n  \"plugins\": [\n    [\"@babel/plugin-transform-object-rest-spread\", { \"useBuiltIns\": true }]\n  ]\n}\n```\n\nFor code like this:\n\n```javascript\nconst copy = { a: 1, ...input };\n```\n\nthe emitted code is in this shape:\n\n```javascript\nconst copy = Object.assign({\n  a: 1,\n}, input);\n```\n\nOnly enable `useBuiltIns: true` when `Object.assign` is available in your target runtime or provided separately.\n\nIn Babel `7.28.6`, the plugin's `useBuiltIns` default depends on the configured Babel targets: it defaults to `true` when the targets already support `Object.assign`, otherwise `false`.\n\n## Prefer top-level assumptions over `loose`\n\nThis plugin still accepts `loose: true`, but in `7.28.6` it is only the fallback for four top-level assumptions:\n\n- `setSpreadProperties`\n- `objectRestNoSymbols`\n- `pureGetters`\n- `ignoreFunctionLength`\n\nConfigure the assumptions explicitly when you want the same tradeoff across your build:\n\n```json\n{\n  \"assumptions\": {\n    \"setSpreadProperties\": true,\n    \"objectRestNoSymbols\": true,\n    \"pureGetters\": true,\n    \"ignoreFunctionLength\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-object-rest-spread\"]\n}\n```\n\nThis configuration matches the plugin's `loose: true` fallback behavior. If you set an assumption explicitly, it takes precedence over `loose`.\n\n## When to keep the default helper behavior\n\nLeave `setSpreadProperties` disabled when you want Babel's spread helper rather than assignment-style output.\n\nWith the default configuration, object spread emits helper code in this shape:\n\n```javascript\nvar copy = _objectSpread2({\n  a: 1,\n}, input);\n```\n\nThat helper copies enumerable symbol keys and uses property-definition-style output, which is closer to object spread semantics than `Object.assign(...)`.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; the plugin alone does not run Babel.\n- `useBuiltIns: true` makes emitted code depend on `Object.assign`.\n- `setSpreadProperties: true` and `loose: true` switch object spread to assignment-style copying, which can behave differently from the default helper around setters and property definition.\n- `objectRestNoSymbols: true` and `loose: true` make object-rest copies ignore symbol keys.\n- Top-level assumptions override this plugin's `loose` fallback, so keep those settings aligned.\n- This plugin changes build output only; it does not polyfill missing runtime features.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-optional-chaining/javascript/DOC.md",
    "content": "---\nname: plugin-transform-optional-chaining\ndescription: \"Babel plugin for compiling JavaScript optional chaining to compatible output during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,optional-chaining,javascript\"\n---\n\n# @babel/plugin-transform-optional-chaining\n\n`@babel/plugin-transform-optional-chaining` rewrites optional chaining expressions such as `obj?.prop`, `obj?.[key]`, and `fn?.()` during Babel builds. It is a compile-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-optional-chaining\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-optional-chaining\"]\n}\n```\n\nThis transform already enables Babel's optional chaining parser support, so you do not need to add `@babel/plugin-syntax-optional-chaining` for the same files.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-optional-chaining\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-optional-chaining\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst city = user?.address?.city;\nconst value = cache?.[key];\nconst result = onError?.(message);\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-optional-chaining\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in Babel `7.28.6`, the emitted code uses nullish checks plus temporary variables when needed so expressions are not evaluated more than once.\n\n## What the plugin rewrites\n\nThis plugin handles the common optional chaining forms:\n\n```javascript\nconst city = user?.address?.city;\nconst value = cache?.[key];\nconst output = formatter?.(input);\nconst name = profile.settings?.getName?.();\n```\n\nFor property access and computed access, Babel rewrites the chain into explicit null/undefined checks. For optional calls on member expressions, Babel also preserves the original call receiver so method calls still get the correct `this` value.\n\n## Transform `delete` with optional chaining\n\nThe plugin also supports optional chaining inside `delete` expressions:\n\n```javascript\ndelete session?.user?.profile;\n```\n\nAdd the same plugin configuration; no separate delete-specific plugin is required.\n\n## Use it through `@babel/preset-env`\n\nIf your real goal is target-based transpilation across multiple JavaScript features, prefer `@babel/preset-env` instead of listing this plugin manually.\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"12\"\n        }\n      }\n    ]\n  ]\n}\n```\n\nUse the standalone plugin when you want to force only optional chaining rewriting in an otherwise narrow Babel setup.\n\n## Prefer `assumptions.noDocumentAll` over `loose`\n\nWith the default settings, Babel emits strict checks against both `null` and `undefined`.\n\nWhen you want Babel to treat `document.all` as if it does not exist and emit `== null` / `!= null` style checks, set the top-level Babel assumption:\n\n```json\n{\n  \"assumptions\": {\n    \"noDocumentAll\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-optional-chaining\"]\n}\n```\n\nThe plugin also still accepts `loose: true`:\n\n```json\n{\n  \"plugins\": [\n    [\"@babel/plugin-transform-optional-chaining\", { \"loose\": true }]\n  ]\n}\n```\n\nIn Babel `7.28.6`, `loose: true` is broader than just `document.all` handling. In the published plugin source, `loose` is also the fallback for Babel's top-level `pureGetters` assumption. Prefer explicit assumptions when you only want the looser nullish check behavior.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; the plugin alone does not run Babel.\n- This transform changes compiled syntax only. It does not polyfill runtime APIs or add unrelated language features.\n- Do not combine this plugin with `@babel/plugin-syntax-optional-chaining` for the same files unless you have a very specific pipeline reason; the transform already enables parsing.\n- If you already use `@babel/preset-env`, adding this plugin manually is usually redundant.\n- `loose: true` changes emitted semantics. Use it only when its looser nullish and getter assumptions are acceptable for your build.\n- No environment variables, authentication, or runtime client initialization are involved; all setup lives in Babel config.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-optional-chaining@7.28.6`.\n- The published `7.28.6` package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- In `7.28.6`, the plugin source enables Babel's `optionalChaining` parser plugin internally, so the transform plugin also covers syntax enablement.\n- In `7.28.6`, `loose` defaults to `false` and acts as the fallback for the top-level Babel assumptions `noDocumentAll` and `pureGetters` when you do not set those assumptions explicitly.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-optional-chaining\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-optional-chaining\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-optional-chaining\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-parameters/javascript/DOC.md",
    "content": "---\nname: plugin-transform-parameters\ndescription: \"Babel plugin for rewriting JavaScript default and rest parameters during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,parameters,default-parameters,rest-parameters\"\n---\n\n# @babel/plugin-transform-parameters\n\n`@babel/plugin-transform-parameters` rewrites default parameters and rest parameters during Babel builds. It is a compile-time transform only: there are no package-specific environment variables, auth steps, or runtime clients to initialize.\n\nIn `7.27.7`, the published package describes this plugin as compiling ES2015 default and rest parameters to ES5. In practice, it rewrites parameter handling itself; if your code also uses parameter destructuring or other newer syntax, add the corresponding Babel transforms as well.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-parameters\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-parameters\"]\n}\n```\n\nThis is enough when you specifically want Babel to rewrite default and rest parameters in the files it compiles.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-parameters\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-parameters\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst input = `\nfunction join(label = \"item\", ...values) {\n  return values.map(function (value) {\n    return label + \":\" + value;\n  });\n}\n`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-parameters\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\n## What the plugin rewrites\n\nFor default parameters, Babel moves the default-value logic into the function body.\n\nWith input like this:\n\n```javascript\nfunction greet(name = \"world\") {\n  return \"Hello, \" + name;\n}\n```\n\nthe generated code is in this shape:\n\n```javascript\nfunction greet() {\n  let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : \"world\";\n  return \"Hello, \" + name;\n}\n```\n\nFor rest parameters, Babel rewrites the rest argument into array-building logic based on `arguments`.\n\nWith input like this:\n\n```javascript\nfunction list(head, ...tail) {\n  return tail;\n}\n```\n\nthe generated code is in this shape:\n\n```javascript\nfunction list(head) {\n  for (var _len = arguments.length, tail = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n    tail[_key - 1] = arguments[_key];\n  }\n\n  return tail;\n}\n```\n\nGenerated variable names can differ, but the transform follows these patterns in `7.27.7`.\n\n## Use `loose` for simpler default-parameter output\n\nSet `loose: true` when you want Babel to keep parameters in the function signature and emit simpler `=== undefined` guards for default values:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-parameters\",\n      {\n        \"loose\": true\n      }\n    ]\n  ]\n}\n```\n\nFor example, code like this:\n\n```javascript\nfunction greet(name = \"world\", punctuation) {\n  return name + punctuation;\n}\n```\n\nis transformed into code in this shape:\n\n```javascript\nfunction greet(name, punctuation) {\n  if (name === undefined) {\n    name = \"world\";\n  }\n\n  return name + punctuation;\n}\n```\n\nUse this when smaller, simpler output matters more than preserving the original `function.length` behavior.\n\n## Prefer Babel `assumptions.ignoreFunctionLength` over `loose`\n\nIn `7.27.7`, this plugin checks Babel's top-level `assumptions.ignoreFunctionLength` setting first and only falls back to `loose` if the assumption is not set.\n\nUse the assumption when you want the same tradeoff across your Babel config:\n\n```json\n{\n  \"assumptions\": {\n    \"ignoreFunctionLength\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-parameters\"]\n}\n```\n\nWith this assumption enabled, default-parameter transforms use the simpler guard-based form and do not preserve spec-like `function.length` values.\n\n## When you still need other transforms\n\nThis plugin focuses on parameter handling. Add other Babel transforms when the rest of your syntax also needs to be lowered.\n\n- Parameter destructuring is moved into the function body, but destructuring syntax itself is not removed; add `@babel/plugin-transform-destructuring` if older runtimes must not receive destructuring.\n- Plain arrow functions without default or rest parameters are not handled by this plugin; add `@babel/plugin-transform-arrow-functions` if you need those rewritten too.\n- If you need target-based transpilation across many language features, use the appropriate Babel preset or additional plugins instead of relying on this plugin alone.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin; the published package declares it as a peer dependency.\n- `loose: true` and `assumptions.ignoreFunctionLength: true` change `function.length` behavior for functions with default parameters.\n- This plugin changes compiled output only; it does not add polyfills or runtime helpers.\n- There are no package-specific environment variables for this plugin.\n- If your parameter list includes destructuring and you need fully older JavaScript output, pair this plugin with the destructuring transform as well.\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-parameters@7.27.7`.\n- The published package declares `@babel/core` peer compatibility as `^7.0.0-0`.\n- The published package declares `node >= 6.9.0` in `engines`.\n- In `7.27.7`, the implementation reads `assumptions.ignoreFunctionLength` before the plugin's `loose` option.\n- In `7.27.7`, when an arrow function uses a default parameter or rest parameter, the implementation converts that arrow to a function expression before rewriting the parameters.\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-parameters\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-parameters\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-parameters\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-private-methods/javascript/DOC.md",
    "content": "---\nname: plugin-transform-private-methods\ndescription: \"Babel plugin for compiling JavaScript private class methods to compatible output during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,classes,private-methods\"\n---\n\n# @babel/plugin-transform-private-methods\n\n`@babel/plugin-transform-private-methods` compiles private class methods such as `#run()` and calls like `this.#run()` during Babel builds. It is a compile-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-private-methods\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-private-methods\"]\n}\n```\n\nThis is enough when your source only uses private class methods.\n\n## Transform private methods from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-private-methods\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-private-methods\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nclass Counter {\n  constructor() {\n    this.value = 0;\n  }\n\n  #inc(step) {\n    this.value += step;\n    return this.value;\n  }\n\n  next() {\n    return this.#inc(1);\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-private-methods\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in Babel 7.28.6, the emitted code uses helper functions plus a `WeakSet` brand check for the private method.\n\n## Use `loose` mode\n\nSet `loose: true` when you want Babel to emit simpler property-based helpers instead of the default brand-check helpers:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-private-methods\",\n      {\n        \"loose\": true\n      }\n    ]\n  ]\n}\n```\n\nIn `loose` mode, Babel emits generated property keys and uses `Object.defineProperty(...)` on the instance instead of the default `WeakSet`-based private method tracking.\n\n## Keep class-feature settings aligned\n\nIf the same build also uses `@babel/plugin-transform-class-properties` or `@babel/plugin-transform-private-property-in-object`, keep the `loose` setting the same across those plugins. Babel's class-features helpers require consistent settings.\n\n```json\n{\n  \"plugins\": [\n    [\"@babel/plugin-transform-class-properties\", { \"loose\": true }],\n    [\"@babel/plugin-transform-private-methods\", { \"loose\": true }],\n    [\"@babel/plugin-transform-private-property-in-object\", { \"loose\": true }]\n  ]\n}\n```\n\nYou only need the other plugins if your code uses those syntaxes too:\n\n- `@babel/plugin-transform-class-properties` for public class fields\n- `@babel/plugin-transform-private-property-in-object` for `#field in obj`\n\n## Use top-level assumptions for class features\n\nBabel also supports top-level class-features assumptions. In Babel 7.28.6, `setPublicClassFields: true` plus `privateFieldsAsProperties: true` produces property-style output for class fields and private methods.\n\n```json\n{\n  \"assumptions\": {\n    \"setPublicClassFields\": true,\n    \"privateFieldsAsProperties\": true\n  },\n  \"plugins\": [\n    \"@babel/plugin-transform-class-properties\",\n    \"@babel/plugin-transform-private-methods\"\n  ]\n}\n```\n\nUse this only when you want the looser class-features output across the whole build.\n\n## Important pitfalls\n\n- Private methods in decorated classes are not supported by Babel's class-features transform and will throw during compilation.\n- This plugin is only for private class methods. If the same files also use public fields, private fields, or `#field in obj`, add the matching class-features plugins.\n- If Babel says `Class private methods are not enabled`, this plugin is missing from the loaded config for that file.\n- This plugin changes build output only; it does not polyfill runtime APIs or add browser features at runtime.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-regenerator/javascript/DOC.md",
    "content": "---\nname: plugin-transform-regenerator\ndescription: \"Babel plugin for rewriting async functions and generator functions into regenerator-based state-machine code during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.29.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,async,generators,regenerator\"\n---\n\n# @babel/plugin-transform-regenerator\n\n`@babel/plugin-transform-regenerator` rewrites generator functions, async functions, and async generators into regenerator-based state-machine code during compilation. It is a Babel build-time transform: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-regenerator\n```\n\nIf you run Babel from the command line, add the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-regenerator\"]\n}\n```\n\nThis is enough to transform `function*`, `async function`, and `async function*` in files Babel compiles.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-regenerator\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-regenerator\n```\n\n## Use it from JavaScript\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nasync function loadUser(id) {\n  await fetchUser(id);\n  return id;\n}\n\nfunction* ids(items) {\n  for (const item of items) {\n    yield item.id;\n  }\n}\n\nasync function* streamUsers(ids) {\n  for (const id of ids) {\n    yield await fetchUser(id);\n  }\n}\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-regenerator\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in Babel 7.29.0, Babel converts those functions into state-machine code and routes the output through Babel's regenerator helper/runtime path.\n\n## Control which function kinds are transformed\n\nThis plugin accepts three boolean options. All are enabled by default.\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-regenerator\",\n      {\n        \"async\": true,\n        \"generators\": true,\n        \"asyncGenerators\": true\n      }\n    ]\n  ]\n}\n```\n\n- Set `async: false` to leave plain `async function` declarations untouched.\n- Set `generators: false` to leave plain generator functions like `function* run()` untouched.\n- Set `asyncGenerators: false` to leave `async function*` untouched.\n\nFor example, this config transforms generators but leaves plain async functions alone:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-regenerator\", { \"async\": false }]]\n}\n```\n\nUse this when another part of your Babel pipeline already handles plain `async` functions and you only want regenerator's generator transforms here.\n\n## Use it with `@babel/preset-env`\n\nIf you already use `@babel/preset-env`, prefer configuring `targets` there instead of adding this plugin manually for standard browser or Node compatibility builds.\n\n```json\n{\n  \"presets\": [[\"@babel/preset-env\", { \"targets\": \"> 0.25%, not dead\" }]]\n}\n```\n\nIn Babel 7.29.0, `@babel/preset-env` includes `transform-regenerator` in its available plugin set. Add `@babel/plugin-transform-regenerator` directly when you need to force this transform or control its `async`, `generators`, or `asyncGenerators` options explicitly.\n\n## Common build setup\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.29.0\",\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/plugin-transform-regenerator\": \"^7.29.0\"\n  }\n}\n```\n\nWith `babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-regenerator\"]\n}\n```\n\n## Important notes\n\n- No environment variables are required. This plugin only changes compiled code.\n- `@babel/core` is required; the plugin is not useful by itself.\n- This plugin does not expose a runtime API for application code. You configure it in Babel and run Babel over source files.\n- The generated output depends on Babel's regenerator helper/runtime path. If your build output fails because that helper is missing, fix that through your existing Babel runtime or polyfill strategy.\n- If you only need plain `async` / `await` rewriting with a custom wrapper such as `bluebird.coroutine`, use `@babel/plugin-transform-async-to-generator` instead.\n- If your real goal is target-based transpilation across many language features, prefer `@babel/preset-env`.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-runtime/javascript/DOC.md",
    "content": "---\nname: plugin-transform-runtime\ndescription: \"Babel plugin for externalizing helper imports and optional pure runtime polyfills through @babel/runtime packages\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.29.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,runtime,polyfill\"\n---\n\n# @babel/plugin-transform-runtime\n\n`@babel/plugin-transform-runtime` rewrites Babel helper usage so compiled files import helpers from a runtime package instead of inlining them into every file. It can also route pure `core-js` and `regenerator` references through Babel runtime packages. It is a compile-time Babel plugin: there are no environment variables, auth steps, or runtime clients to initialize.\n\nUse it together with the transforms that actually change syntax, such as `@babel/preset-env`. By itself, this plugin does not replace `@babel/preset-env` or other syntax transform plugins.\n\n## Install\n\nInstall Babel core and the plugin as development dependencies, then add the runtime package your compiled code will import at runtime.\n\nBasic helper-only setup:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-runtime\nnpm install @babel/runtime\n```\n\nIf you also use Babel from the command line:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nIf you want Babel to actually downlevel syntax for target environments, add a preset or transform plugin too:\n\n```bash\nnpm install --save-dev @babel/preset-env\n```\n\nExample `package.json` layout:\n\n```json\n{\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.29.0\",\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/plugin-transform-runtime\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.29.0\"\n  }\n}\n```\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"18\"\n        }\n      }\n    ]\n  ],\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-runtime\",\n      {\n        \"version\": \"^7.29.0\"\n      }\n    ]\n  ]\n}\n```\n\nThe `version` option should match the `@babel/runtime` range you ship. This lets Babel target the runtime helper set you actually depend on instead of assuming the oldest Babel 7 runtime.\n\n## Compile code from the CLI\n\nWith a config file in place:\n\n```bash\nnpx babel src --out-dir dist\n```\n\nOr pass the plugin inline for a one-off compile:\n\n```bash\nnpx babel src --out-dir dist --plugins @babel/plugin-transform-runtime\n```\n\n## Use it from JavaScript\n\nProgrammatic usage typically combines `@babel/plugin-transform-runtime` with `@babel/preset-env` or another transform that would otherwise inline Babel helpers:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst input = `\nclass Admin extends User {\n  async load() {\n    return await fetchProfile();\n  }\n}\n`;\n\nconst result = transformSync(input, {\n  configFile: false,\n  babelrc: false,\n  presets: [[\"@babel/preset-env\", { targets: { node: \"18\" } }]],\n  plugins: [[\"@babel/plugin-transform-runtime\", {\n    version: \"^7.29.0\",\n  }]],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this setup, Babel can emit imports from `@babel/runtime/helpers/...` instead of duplicating helper bodies in each compiled file.\n\n## Use `corejs` for pure polyfill imports\n\nThe plugin supports `corejs: 2` and `corejs: 3` in addition to the default `false` behavior.\n\nFor `corejs: 3`, install the runtime package that includes the pure `core-js` mappings:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-runtime\nnpm install @babel/runtime-corejs3\n```\n\nThen configure Babel:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-runtime\",\n      {\n        \"corejs\": 3,\n        \"version\": \"^7.29.0\"\n      }\n    ]\n  ]\n}\n```\n\nTo enable proposal polyfills as well, use the object form. The plugin only allows `proposals: true` when `corejs` is `3`:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-runtime\",\n      {\n        \"corejs\": {\n          \"version\": 3,\n          \"proposals\": true\n        },\n        \"version\": \"^7.29.0\"\n      }\n    ]\n  ]\n}\n```\n\nIf you need `corejs: 2`, use the matching runtime package instead:\n\n```bash\nnpm install @babel/runtime-corejs2\n```\n\n## Resolve runtime imports absolutely when needed\n\nSet `absoluteRuntime` when Babel cannot reliably resolve `@babel/runtime` from the location of every compiled file, such as some monorepo, linked-package, or CLI-driven builds.\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-runtime\",\n      {\n        \"absoluteRuntime\": true,\n        \"version\": \"^7.29.0\"\n      }\n    ]\n  ]\n}\n```\n\n`absoluteRuntime` may be `true` or a string path. With `true`, Babel resolves the runtime package relative to the config directory. With a string, Babel resolves relative to that path instead.\n\n## Important notes\n\n- Put `@babel/runtime`, `@babel/runtime-corejs3`, or `@babel/runtime-corejs2` in `dependencies`, not only `devDependencies`, because compiled application code imports from those packages at runtime.\n- This plugin does not perform syntax transforms by itself. Pair it with `@babel/preset-env` or specific transform plugins when you need code downleveled for older runtimes.\n- The removed `useBuiltIns` and `polyfill` options now throw errors. Use `corejs` instead.\n- `corejs` must be `false`, `2`, or `3`. The `proposals` flag only works with `corejs: 3`.\n- `helpers` and `regenerator` are boolean options if you need to disable either behavior explicitly.\n- `absoluteRuntime` embeds resolved runtime paths into generated output. Avoid it when you need portable build artifacts that will run on a different machine or filesystem layout.\n- There are no package-specific environment variables for this plugin.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-shorthand-properties/javascript/DOC.md",
    "content": "---\nname: plugin-transform-shorthand-properties\ndescription: \"Babel plugin for expanding ES2015 object literal shorthand properties and concise methods into explicit object properties during JavaScript builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,transpile,object-literals,es2015\"\n---\n\n# @babel/plugin-transform-shorthand-properties\n\n`@babel/plugin-transform-shorthand-properties` rewrites ES2015 object literal shorthand into explicit object properties at build time. In `7.27.1`, it expands both shorthand properties such as `{ name }` and concise methods such as `{ greet() {} }`.\n\nThis is a compile-time Babel plugin. There are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with `@babel/core`:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-shorthand-properties\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli @babel/core @babel/plugin-transform-shorthand-properties\n```\n\nThe package declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-shorthand-properties\"]\n}\n```\n\nIn `7.27.1`, this plugin does not expose plugin-specific options. Adding it to `plugins` is enough.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-shorthand-properties\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-shorthand-properties\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, build tool, or test helper:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst name = \"Ada\";\nconst obj = {\n  name,\n  greet() {\n    return \"Hello, \" + name + \"!\";\n  },\n};\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-shorthand-properties\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe emitted code has this shape:\n\n```javascript\nconst name = \"Ada\";\nconst obj = {\n  name: name,\n  greet: function () {\n    return \"Hello, \" + name + \"!\";\n  },\n};\n```\n\nOnly the object literal syntax changes here. Other syntax in the file is left alone unless you add other Babel plugins or presets.\n\n## What the plugin rewrites\n\nThis plugin handles two object literal forms:\n\n```javascript\nconst count = 1;\n\nconst input = {\n  count,\n  increment(step) {\n    return count + step;\n  },\n};\n```\n\nAfter the transform, Babel emits explicit properties:\n\n```javascript\nconst count = 1;\n\nconst input = {\n  count: count,\n  increment: function (step) {\n    return count + step;\n  },\n};\n```\n\nIn the implementation for `7.27.1`, async methods and generator methods keep their `async` and `*` behavior when Babel converts them to function-valued properties.\n\n## Important pitfalls\n\n- This plugin only changes build output. It does not polyfill runtime APIs or add browser features.\n- It only rewrites object literal shorthand properties and concise methods. If the same files use other newer syntax, add the matching Babel plugins or a preset that covers those features.\n- If a file still contains shorthand properties after a build, confirm this plugin is loaded for that file through the active Babel config.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-spread/javascript/DOC.md",
    "content": "---\nname: plugin-transform-spread\ndescription: \"Babel plugin for compiling array, call, and constructor spread syntax to older JavaScript output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.28.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,spread,javascript\"\n---\n\n# @babel/plugin-transform-spread\n\n`@babel/plugin-transform-spread` rewrites JavaScript spread syntax during Babel compilation. It covers array literals like `[...items]`, spread arguments in calls like `fn(...args)`, and constructor calls like `new Map(...entries)`.\n\nThis is a build-time transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-spread\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\n`@babel/plugin-transform-spread` declares `@babel/core` as a peer dependency, so installing the plugin alone is not enough.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-spread\"]\n}\n```\n\nUse this when your build needs to compile spread syntax regardless of whether you also use a preset.\n\n## Use it from the CLI\n\nCompile a directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-spread\n```\n\nCompile a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-spread\n```\n\n## Transform code programmatically\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst out = [head, ...items, tail];\nobj.method(...args);\nnew Map(...ctorArgs);\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-spread\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration, Babel rewrites those expressions to helper-based or `apply`/`concat`-based output.\n\n## What the plugin rewrites\n\n### Array literals\n\nInput:\n\n```javascript\nconst out = [head, ...items, tail];\n```\n\nOutput shape:\n\n```javascript\nconst out = [head].concat(_toConsumableArray(items), [tail]);\n```\n\nFor `const copy = [...items];`, Babel emits `_toConsumableArray(items)`.\n\nWhen the source is `arguments`, Babel uses `Array.prototype.slice.call(arguments)` instead of the helper.\n\n### Function and method calls\n\nInput:\n\n```javascript\nfn(...args);\nobj.method(...args);\n```\n\nOutput shape:\n\n```javascript\nfn.apply(void 0, _toConsumableArray(args));\nobj.method.apply(obj, _toConsumableArray(args));\n```\n\nFor member calls, the transform preserves the call receiver so `this` keeps working.\n\n### Constructor calls\n\nInput:\n\n```javascript\nnew Map(...ctorArgs);\n```\n\nOutput shape:\n\n```javascript\n_construct(Map, _toConsumableArray(ctorArgs));\n```\n\nThat helper delegates to `Reflect.construct(...)` when available and falls back to bind/apply-style construction otherwise.\n\n## Allow array-like values with `allowArrayLike`\n\nBy default, Babel treats spread operands as arrays or iterables. If your source may spread array-like values that have a numeric `length` but no iterator, enable `allowArrayLike`:\n\n```json\n{\n  \"plugins\": [[\"@babel/plugin-transform-spread\", { \"allowArrayLike\": true }]]\n}\n```\n\nProgrammatic usage:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst result = transformSync(\"const copy = [...listLike];\", {\n  configFile: false,\n  babelrc: false,\n  plugins: [[\"@babel/plugin-transform-spread\", { allowArrayLike: true }]],\n});\n```\n\nWith this option, Babel uses a helper in the shape of `_maybeArrayLike(_toConsumableArray, listLike)` so numeric-length values can be copied by index.\n\nEnable this only when you intentionally want non-iterable array-like values to be accepted by your compiled output. Native JavaScript spread syntax still requires an iterable.\n\n## Prefer top-level assumptions over `loose`\n\nThis plugin still accepts `loose: true`, but in `7.28.6` it is only the fallback for Babel's top-level `iterableIsArray` assumption.\n\n```json\n{\n  \"assumptions\": {\n    \"iterableIsArray\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-spread\"]\n}\n```\n\nWhen `iterableIsArray` is enabled, Babel skips iterator conversion and treats spread operands as arrays. For example, `const copy = [...items];` compiles in the shape of `[].concat(items)` instead of `_toConsumableArray(items)`.\n\nIf you want array-like fallback behavior across your build, use Babel's top-level `arrayLikeIsIterable` assumption:\n\n```json\n{\n  \"assumptions\": {\n    \"arrayLikeIsIterable\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-spread\"]\n}\n```\n\n`allowArrayLike` is the plugin-local version of that behavior. If you set `allowArrayLike` directly on this plugin, it takes precedence for this transform.\n\nUse `loose` or `iterableIsArray` only when every non-`arguments` spread operand is already a real array. Do not use it for general iterables such as `Set`, `Map`, generator results, or custom iterator objects.\n\n## Use with `@babel/preset-env`\n\nIf you already use `@babel/preset-env`, this transform is part of Babel's preset-env plugin set. Add `@babel/plugin-transform-spread` directly when you need to force this transform or configure plugin-specific behavior such as `allowArrayLike` or `loose`.\n\n## Important pitfalls\n\n- Install `@babel/core` alongside the plugin.\n- This plugin rewrites syntax only; it does not polyfill missing runtime features for older environments.\n- `super(...args)` cannot be compiled by this plugin alone. Babel requires `@babel/plugin-transform-classes` in the same build when spread appears inside `super()`.\n- `allowArrayLike: true` changes semantics by accepting numeric-length values that native spread syntax would reject.\n- `loose: true` and `assumptions.iterableIsArray: true` are only safe when spread operands are actual arrays.\n- Method-call spreads are rewritten with `.apply(...)` to preserve `this`, so avoid post-processing that assumes the original call shape is still present.\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-template-literals/javascript/DOC.md",
    "content": "---\nname: plugin-transform-template-literals\ndescription: \"Babel plugin for rewriting ES2015 template literals into ES5-compatible string concatenation and tagged-template helper calls\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,transpile,template-literals,es2015\"\n---\n\n# @babel/plugin-transform-template-literals\n\n`@babel/plugin-transform-template-literals` compiles ES2015 template literals for older JavaScript targets. It is a build-time Babel transform only: there are no environment variables, auth steps, or runtime clients to initialize.\n\nUse it when your build needs to rewrite:\n\n- untagged template literals such as `` `Hello ${name}` ``\n- tagged template literals such as `` tag`a ${value} b` ``\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-template-literals\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe published package declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-template-literals\"]\n}\n```\n\nThis is enough to rewrite template literals in the files Babel compiles.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-template-literals\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-template-literals\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = [\n  \"const greeting = `Hello ${name}`;\",\n  \"const tagged = tag`a ${value} b`;\",\n].join(\"\\n\");\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-template-literals\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith the default configuration in `7.27.1`, Babel rewrites plain template literals to `.concat(...)` calls and rewrites tagged templates to helper-backed calls that cache the template object.\n\n## Default output preserves template-literal coercion behavior\n\nFor ordinary template literals, the default transform emits string concatenation through `.concat(...)` rather than always using `+`.\n\nFor example, this input:\n\n```javascript\nconst message = `Hello ${name}`;\n```\n\nis transformed into output in this shape:\n\n```javascript\nconst message = \"Hello \".concat(name);\n```\n\nIn `7.27.1`, the plugin implementation uses `.concat(...)` so it can preserve template-literal primitive-conversion behavior more closely than a loose `+` rewrite.\n\n## Use `loose` for `+` concatenation\n\nSet `loose: true` when you want Babel to emit `+` expressions for untagged template literals:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-template-literals\",\n      {\n        \"loose\": true\n      }\n    ]\n  ]\n}\n```\n\nWith that option, code like this:\n\n```javascript\nconst message = `Hello ${name}`;\n```\n\nis transformed into output in this shape:\n\n```javascript\nconst message = \"Hello \" + name;\n```\n\nUse this only when `+` concatenation is acceptable for your code. In `7.27.1`, `loose` also enables the plugin's looser tagged-template helper behavior unless you override it with top-level Babel assumptions.\n\n## Prefer Babel `assumptions` when you need precise control\n\nIn `7.27.1`, this plugin reads Babel's top-level `assumptions.ignoreToPrimitiveHint` and `assumptions.mutableTemplateObject` settings first, then falls back to the plugin's `loose` option.\n\nUse assumptions when you want to control these behaviors explicitly:\n\n```json\n{\n  \"assumptions\": {\n    \"ignoreToPrimitiveHint\": true,\n    \"mutableTemplateObject\": false\n  },\n  \"plugins\": [\"@babel/plugin-transform-template-literals\"]\n}\n```\n\n- `ignoreToPrimitiveHint: true` tells the plugin to use `+` concatenation for untagged templates\n- `mutableTemplateObject: true` tells the plugin to use Babel's loose tagged-template helper\n- if an assumption is set, it takes precedence over `loose`\n\nThis matters when you want `+` concatenation without also opting into a mutable tagged-template object, or when you need the opposite combination.\n\n## Control tagged template object mutability\n\nFor tagged template literals, Babel generates a cached template object and passes it to the tag function.\n\nWith the default behavior, Babel uses a helper in this shape:\n\n```javascript\nfunction _taggedTemplateLiteral(strings, raw) {\n  if (!raw) raw = strings.slice(0);\n  return Object.freeze(\n    Object.defineProperties(strings, {\n      raw: { value: Object.freeze(raw) }\n    })\n  );\n}\n```\n\nThat helper freezes both the template array and its `.raw` array.\n\nIf you set `assumptions.mutableTemplateObject: true`:\n\n```json\n{\n  \"assumptions\": {\n    \"mutableTemplateObject\": true\n  },\n  \"plugins\": [\"@babel/plugin-transform-template-literals\"]\n}\n```\n\nthe plugin switches to Babel's loose helper shape instead:\n\n```javascript\nfunction _taggedTemplateLiteralLoose(strings, raw) {\n  if (!raw) raw = strings.slice(0);\n  strings.raw = raw;\n  return strings;\n}\n```\n\nUse the default helper when your tag relies on spec-like frozen template objects. Use the mutable helper only when you explicitly want the looser behavior.\n\n## Common build setup\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel src --out-dir lib\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.27.1\",\n    \"@babel/core\": \"^7.27.1\",\n    \"@babel/plugin-transform-template-literals\": \"^7.27.1\"\n  }\n}\n```\n\nWith `babel.config.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-template-literals\"]\n}\n```\n\n## Important pitfalls\n\n- Install `@babel/core` with the plugin; the plugin alone is not enough\n- No environment variables or runtime initialization are required; this package only changes compiled output\n- `loose: true` affects both plain template literal concatenation and tagged-template helper selection unless top-level assumptions override it\n- If your tag expects spec-like frozen template objects, do not enable `mutableTemplateObject: true`\n- If coercion details matter for interpolated values, prefer the default transform instead of `ignoreToPrimitiveHint: true` or `loose: true`\n- This plugin only rewrites template literal syntax; it does not polyfill missing built-in APIs or transpile unrelated syntax\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-template-literals@7.27.1`\n- The published package exposes a `loose` plugin option and reads the top-level Babel assumptions `ignoreToPrimitiveHint` and `mutableTemplateObject`\n- In `7.27.1`, assumptions take precedence over `loose` in the plugin implementation\n- The published package declares `@babel/core` peer compatibility as `^7.0.0-0`\n- The published package declares `node >= 6.9.0` in `engines`, but your effective support matrix still depends on the rest of your Babel toolchain\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-typeof-symbol/javascript/DOC.md",
    "content": "---\nname: plugin-transform-typeof-symbol\ndescription: \"Babel plugin for rewriting typeof expressions so Symbol values keep native-like \\\"symbol\\\" behavior in compiled output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,transpile,symbol,typeof\"\n---\n\n# @babel/plugin-transform-typeof-symbol\n\n`@babel/plugin-transform-typeof-symbol` rewrites `typeof` expressions so compiled code can preserve native-like Symbol behavior, especially checks that should return or compare against `\"symbol\"`.\n\nThis is a build-time Babel transform only. There are no environment variables, auth steps, or runtime clients to initialize.\n\n## Install\n\nInstall the plugin with `@babel/core`:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-typeof-symbol\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli\n```\n\nThe published package declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-typeof-symbol\"]\n}\n```\n\nThis is enough to transform `typeof` expressions in the files Babel compiles.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-typeof-symbol\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-typeof-symbol\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = [\n  'console.log(typeof Symbol(\"id\") === \"symbol\");',\n  'console.log(typeof maybeMissing);',\n].join(\"\\n\");\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-typeof-symbol\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nWith this plugin enabled, Babel injects a `typeof` helper and rewrites call sites in this shape:\n\n```javascript\nconsole.log(_typeof(Symbol(\"id\")) === \"symbol\");\nconsole.log(typeof maybeMissing === \"undefined\" ? \"undefined\" : _typeof(maybeMissing));\n```\n\nThat second rewrite matters because plain JavaScript allows `typeof maybeMissing` even when `maybeMissing` is undeclared. The plugin keeps that behavior instead of turning it into a direct helper call that would throw.\n\n## What the transform changes\n\nIn `7.27.1`, the plugin implementation does three important things:\n\n- injects Babel's `typeof` helper so Symbol values can still be identified as `\"symbol\"`\n- preserves `typeof undeclaredName` behavior by guarding unresolved identifiers before calling the helper\n- skips rewriting equality checks when the other side is a string literal other than `\"symbol\"` or `\"object\"`\n\nThat means a comparison like this stays as-is:\n\n```javascript\nif (typeof value === \"string\") {\n  console.log(value);\n}\n```\n\nBut checks that involve `\"symbol\"` or `\"object\"` are still rewritten because those are the cases where Symbol behavior affects the result.\n\n## Important pitfalls\n\n- This plugin rewrites `typeof`; it does not provide a `Symbol` runtime or polyfill older environments that do not implement `Symbol`\n- Install `@babel/core` alongside the plugin; the package is not a standalone compiler\n- The plugin has no plugin-specific options in the published `7.27.1` implementation; enable it as a plain string in `plugins`\n- If your source code binds `Symbol` in local scope, Babel may rename that binding in output before inserting its helper; seeing names such as `_Symbol` is expected\n\n## Version-sensitive notes\n\n- This guide targets `@babel/plugin-transform-typeof-symbol@7.27.1`\n- The published package declares `@babel/core` peer compatibility as `^7.0.0-0`\n- The published package declares `node >= 6.9.0` in `engines`\n- In `7.27.1`, the plugin implementation exposes no plugin-specific options\n\n## Official sources\n\n- Babel docs: https://babel.dev/docs/en/next/babel-plugin-transform-typeof-symbol\n- npm package page: https://www.npmjs.com/package/@babel/plugin-transform-typeof-symbol\n- Babel source package: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-typeof-symbol\n"
  },
  {
    "path": "content/babel/docs/plugin-transform-unicode-regex/javascript/DOC.md",
    "content": "---\nname: plugin-transform-unicode-regex\ndescription: \"Babel plugin for rewriting ES2015 Unicode regex literals with the `u` flag to ES5-compatible patterns\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.27.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"babel,build,javascript,regex,unicode,transpile\"\n---\n\n# @babel/plugin-transform-unicode-regex\n\n`@babel/plugin-transform-unicode-regex` compiles ES2015 regular expression literals that use the Unicode `u` flag into ES5-compatible regex patterns.\n\nThis is a compile-time Babel plugin. There are no environment variables, auth steps, or runtime clients to initialize.\n\nUse it when your source code contains regex literals such as `/^\\u{1F600}$/u` and you need Babel to emit output for environments that do not support Unicode regexes with the `u` flag.\n\n## Install\n\nInstall the plugin with Babel core:\n\n```bash\nnpm install --save-dev @babel/core @babel/plugin-transform-unicode-regex\n```\n\nIf you run Babel from the command line, install the CLI too:\n\n```bash\nnpm install --save-dev @babel/cli @babel/core @babel/plugin-transform-unicode-regex\n```\n\nThe plugin declares `@babel/core` as a peer dependency, so install both packages.\n\n## Add the plugin to Babel\n\nUse `babel.config.json` or `.babelrc.json`:\n\n```json\n{\n  \"plugins\": [\"@babel/plugin-transform-unicode-regex\"]\n}\n```\n\nWith that config, Babel rewrites regex literals that use the `u` flag when it compiles your files.\n\n## Run it from the CLI\n\nTransform a source directory:\n\n```bash\nnpx babel src --out-dir lib --plugins @babel/plugin-transform-unicode-regex\n```\n\nTransform a single file:\n\n```bash\nnpx babel input.js --out-file output.js --plugins @babel/plugin-transform-unicode-regex\n```\n\n## Transform code programmatically\n\nUse `@babel/core` directly when the transform is part of a script, test helper, or custom build step:\n\n```javascript\nimport { transformSync } from \"@babel/core\";\n\nconst source = `\nconst singleEmoji = /^\\\\u{1F600}$/u;\nconst lettersOrEmoji = /^[a-z\\\\u{1F600}-\\\\u{1F64F}]+$/u;\n`;\n\nconst result = transformSync(source, {\n  configFile: false,\n  babelrc: false,\n  plugins: [\"@babel/plugin-transform-unicode-regex\"],\n});\n\nif (!result?.code) {\n  throw new Error(\"Transform failed\");\n}\n\nconsole.log(result.code);\n```\n\nThe generated output expands Unicode-aware regex syntax into ES5-compatible pattern text and removes the `u` flag from the final literal.\n\n## Use it with `@babel/preset-env`\n\nIf you already use `@babel/preset-env`, prefer setting `targets` there instead of forcing this plugin separately for normal compatibility builds.\n\n```json\n{\n  \"presets\": [[\"@babel/preset-env\", { \"targets\": \"> 0.25%, not dead\" }]]\n}\n```\n\nAdd `@babel/plugin-transform-unicode-regex` directly when you need to force this transform as part of a narrow Babel pipeline or you are building a custom plugin list by hand.\n\n## What this plugin does not cover\n\nThis plugin only targets regex literals that use the Unicode `u` flag.\n\n- It does not rewrite `new RegExp(\"\\\\u{1F600}\", \"u\")` or other runtime-created regexes.\n- It does not add support for Unicode property escapes like `\\\\p{Letter}` by itself.\n- It does not add support for newer Unicode sets regex syntax that uses the `v` flag.\n- It does not polyfill any JavaScript built-ins or unrelated syntax features.\n\nUse the dedicated Babel regex transforms or `@babel/preset-env` when your codebase also relies on those other regex features.\n\n## Important pitfalls\n\n- Install `@babel/core` with the plugin; the plugin alone is not enough.\n- This is a build-time transform only; your application code does not import anything from this package at runtime.\n- Only regex literals parsed by Babel are transformed. Patterns assembled dynamically with strings stay unchanged.\n- If your regex uses `\\\\p{...}` property escapes or `v`-flag Unicode sets, this plugin alone is not sufficient.\n- Prefer `@babel/preset-env` when your real goal is target-based transpilation across many language features, not only Unicode regex literals.\n"
  },
  {
    "path": "content/backoff/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"backoff retry decorators for synchronous and asyncio Python code\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.2.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"backoff,retry,retries,python,asyncio,http,resilience\"\n---\n\n# backoff Python Package Guide\n\n## Golden Rule\n\nUse `backoff` to wrap your own I/O calls with retry decorators, not as an HTTP client. In `2.2.1`, the package is stable but dormant: PyPI still lists `2.2.1` as the latest release, and the upstream GitHub repository was archived and made read-only on August 8, 2025.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"backoff==2.2.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"backoff==2.2.1\"\npoetry add \"backoff==2.2.1\"\n```\n\n`backoff` has no auth or service configuration of its own. It only controls retry timing around your function calls.\n\n## Core Model\n\nThe library exposes decorators that retry based on either exceptions or return values:\n\n- `backoff.on_exception(...)`: retry when the wrapped function raises one of the specified exceptions\n- `backoff.on_predicate(...)`: retry when a predicate matches the return value\n- Wait generators such as `backoff.expo`, `backoff.fibo`, `backoff.constant`, and `backoff.runtime`\n\nThe decorators work for both normal functions and `async def` coroutines.\n\n## Basic Exception Retry\n\nUse `on_exception` for network and API calls that should retry on transient failures:\n\n```python\nimport requests\nimport backoff\n\ndef fatal_http_error(exc: requests.exceptions.RequestException) -> bool:\n    response = exc.response\n    return response is not None and 400 <= response.status_code < 500\n\n@backoff.on_exception(\n    backoff.expo,\n    requests.exceptions.RequestException,\n    max_time=60,\n    giveup=fatal_http_error,\n)\ndef fetch_json(url: str) -> dict:\n    response = requests.get(url, timeout=10)\n    response.raise_for_status()\n    return response.json()\n```\n\nUse this pattern when you want exponential backoff for timeouts, connection failures, and retryable HTTP errors, but want to stop immediately on permanent `4xx` responses.\n\n## Limit Retries By Attempt Count\n\nUse `max_tries` when you want a bounded number of attempts instead of a time budget:\n\n```python\nimport requests\nimport backoff\n\n@backoff.on_exception(\n    backoff.expo,\n    (requests.exceptions.Timeout, requests.exceptions.ConnectionError),\n    max_tries=5,\n    jitter=None,\n)\ndef fetch_text(url: str) -> str:\n    return requests.get(url, timeout=5).text\n```\n\nSet `jitter=None` when you need deterministic delays in tests or fixed-interval behavior for local tooling.\n\n## Poll Until A Return Value Changes\n\nUse `on_predicate` when the call succeeds technically but the result is not ready yet:\n\n```python\nimport backoff\n\n@backoff.on_predicate(backoff.constant, interval=1, jitter=None)\ndef poll_job_status(client, job_id: str):\n    job = client.get_job(job_id)\n    if job[\"state\"] == \"done\":\n        return job\n    return None\n```\n\nImportant default: if you omit `predicate=...`, `on_predicate` retries on any falsey return value. Be explicit when `0`, `False`, `[]`, or `{}` are valid successful results in your application.\n\n## Honor `Retry-After` With `backoff.runtime`\n\n`backoff.runtime` lets the wait duration come from the function result or exception details. This is the most useful `2.x` feature when wrapping rate-limited APIs:\n\n```python\nimport requests\nimport backoff\n\n@backoff.on_predicate(\n    backoff.runtime,\n    predicate=lambda response: response.status_code == 429,\n    value=lambda response: int(response.headers.get(\"Retry-After\", \"1\")),\n    jitter=None,\n)\ndef get_with_retry_after(url: str) -> requests.Response:\n    return requests.get(url, timeout=10)\n```\n\nUse `runtime` when the server tells you exactly how long to wait.\n\n## Async Usage\n\nDecorators also work on coroutines:\n\n```python\nimport aiohttp\nimport backoff\n\n@backoff.on_exception(backoff.expo, aiohttp.ClientError, max_time=60)\nasync def fetch_text(url: str) -> str:\n    async with aiohttp.ClientSession(raise_for_status=True) as session:\n        async with session.get(url) as response:\n            return await response.text()\n```\n\nYou can also supply async handler functions for `on_success`, `on_backoff`, and `on_giveup`.\n\n## Runtime Configuration\n\nDecorator arguments are usually evaluated when the module is imported. If retry settings come from runtime config, pass callables instead of constants:\n\n```python\nimport backoff\n\ndef current_max_time() -> int:\n    return settings.BACKOFF_MAX_TIME\n\n@backoff.on_exception(backoff.expo, ValueError, max_time=current_max_time)\ndef flaky_operation() -> str:\n    ...\n```\n\nOn `2.2.1`, callable `max_time` and `max_tries` are safe to use; `2.1.1` fixed a bug in that area.\n\n## Logging And Event Handlers\n\n`backoff` logs to the `backoff` logger, which uses a `NullHandler` by default. You will not see retry logs unless you configure a handler or pass a custom logger.\n\nBasic logging setup:\n\n```python\nimport logging\n\nlogging.getLogger(\"backoff\").addHandler(logging.StreamHandler())\nlogging.getLogger(\"backoff\").setLevel(logging.INFO)\n```\n\nFor metrics or custom observability, use handlers:\n\n```python\nimport backoff\nimport requests\n\ndef on_backoff(details: dict) -> None:\n    print(\n        f\"retrying {details['target'].__name__} \"\n        f\"after {details['tries']} tries; waiting {details['wait']:.1f}s\"\n    )\n\n@backoff.on_exception(\n    backoff.expo,\n    requests.exceptions.RequestException,\n    on_backoff=on_backoff,\n)\ndef fetch(url: str):\n    return requests.get(url, timeout=10)\n```\n\nHandler detail dictionaries can include `target`, `args`, `kwargs`, `tries`, `elapsed`, `wait`, `value`, and, for exception retries, `exception`.\n\n## Common Pitfalls\n\n- `raise_on_giveup` defaults to `True` for `on_exception`. If retries are exhausted, the last exception is re-raised.\n- If you set `raise_on_giveup=False`, the decorated function returns `None` on give-up. Do not assume your original return type still applies.\n- `on_predicate` defaults to retrying falsey values. This can accidentally treat empty collections or `0` as failures.\n- Since version `1.2`, the default jitter is `backoff.full_jitter`, so actual sleep times vary unless you set `jitter=None`.\n- Extra keyword arguments such as `interval` or `max_value` are passed to the wait generator, not to your wrapped function.\n- Multiple decorators can be stacked, but the order affects behavior. Keep each decorator tied to one clear retry condition.\n- The project is archived. Do not expect fixes for new Python/runtime edge cases unless your team vendors or replaces it.\n\n## Version-Sensitive Notes\n\n- `2.2.1` is the latest PyPI release as of March 12, 2026.\n- `2.2.1` only changed type hints for wait generators; it did not change retry semantics.\n- `2.0.0` added `raise_on_giveup`, `backoff.runtime`, Python 3.10 support, and dropped Python 3.6 support.\n- Upstream metadata for `2.2.1` declares Python `>=3.7, <4.0` and classifiers through Python 3.10. That does not guarantee testing on newer interpreters.\n\n## Official Sources\n\n- GitHub repository and README: `https://github.com/litl/backoff`\n- PyPI project page: `https://pypi.org/project/backoff/`\n- GitHub releases: `https://github.com/litl/backoff/releases`\n"
  },
  {
    "path": "content/bandit/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Bandit Python package guide for security scanning Python code with the Bandit CLI\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bandit,python,security,sast,static-analysis,lint,ci\"\n---\n\n# Bandit Python Package Guide\n\n## Golden Rule\n\nUse Bandit as a CLI security scanner for Python source trees, keep the package version pinned to what your project expects, and drive scans with an explicit config file when you need anything beyond the default recursive scan. For `1.9.4`, prefer a `pyproject.toml` or YAML config passed with `-c`; only rely on `.bandit` auto-discovery when you are intentionally using recursive mode with `-r`.\n\n## Install\n\nPin the package in your dev tooling:\n\n```bash\npython -m pip install \"bandit==1.9.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"bandit==1.9.4\"\npoetry add --group dev \"bandit==1.9.4\"\n```\n\nOptional extras from the official docs:\n\n```bash\npython -m pip install \"bandit[toml]==1.9.4\"\npython -m pip install \"bandit[sarif]==1.9.4\"\npython -m pip install \"bandit[baseline]==1.9.4\"\n```\n\nUse these when:\n\n- `toml`: you want Bandit to read `pyproject.toml`\n- `sarif`: you want SARIF output for code scanning tools\n- `baseline`: you want the baseline workflow documented by Bandit\n\n## First Scan\n\nRecursive scans are the normal starting point:\n\n```bash\nbandit -r src\n```\n\nScan multiple roots and exclude generated or vendored paths:\n\n```bash\nbandit -r src tests -x .venv,build,dist,migrations\n```\n\nTighten the findings Bandit reports:\n\n```bash\nbandit -r src --severity-level medium --confidence-level medium\n```\n\nThe short flags still work and are common in CI:\n\n```bash\nbandit -r src -ll -ii\n```\n\n## Configuration\n\nBandit supports INI, YAML, and TOML config styles, but they do not behave the same way.\n\n### `pyproject.toml`\n\nBandit only reads TOML if you install the `toml` extra and pass the file with `-c`:\n\n```toml\n[tool.bandit]\nexclude_dirs = [\".venv\", \"build\", \"dist\", \"tests/fixtures\"]\ntests = [\"B201\", \"B301\", \"B602\", \"B608\"]\nskips = [\"B101\"]\n```\n\nRun it with:\n\n```bash\nbandit -c pyproject.toml -r src\n```\n\n### YAML config\n\nYAML config is also passed explicitly with `-c`:\n\n```yaml\nexclude_dirs:\n  - .venv\n  - build\n  - dist\ntests:\n  - B201\n  - B301\n  - B602\nskips:\n  - B101\n```\n\nRun it with:\n\n```bash\nbandit -c bandit.yaml -r src\n```\n\n### `.bandit` INI\n\nBandit auto-loads a `.bandit` file only when you use `-r`:\n\n```ini\n[bandit]\nexclude = tests,.venv\nskips = B101,B601\n```\n\nRun it with:\n\n```bash\nbandit -r src\n```\n\nConfig notes:\n\n- `tests` is the allowlist of checks to run.\n- `skips` is the denylist of checks to disable.\n- Use one or the other deliberately; mixing both can hide why a check did or did not run.\n- Plugin override sections are supported in YAML and TOML when a plugin documents configurable keys.\n\n## Core Usage\n\n### Write machine-readable reports\n\nJSON is the easiest format for pipelines:\n\n```bash\nbandit -r src -f json -o bandit-report.json\n```\n\nSARIF works well for GitHub code scanning and similar tools:\n\n```bash\nbandit -r src -f sarif -o bandit-report.sarif\n```\n\nOther built-in formatters include `csv`, `html`, `screen`, `txt`, `xml`, and `yaml`.\n\n### Use a baseline for legacy code\n\nGenerate a baseline from the current state:\n\n```bash\nbandit -r src -f json -o bandit-baseline.json\n```\n\nThen compare later scans against it:\n\n```bash\nbandit -r src -b bandit-baseline.json\n```\n\nThe baseline file must be JSON output produced by Bandit.\n\n### Integrate with pre-commit\n\nBandit documents a `pre-commit` hook. When your config lives in `pyproject.toml`, pass `-c` and add the TOML extra:\n\n```yaml\n- repo: https://github.com/PyCQA/bandit\n  rev: \"1.9.4\"\n  hooks:\n    - id: bandit\n      args: [\"-c\", \"pyproject.toml\"]\n      additional_dependencies: [\"bandit[toml]\"]\n```\n\n### Fail-open mode for migration periods\n\nIf you need visibility before enforcing failures:\n\n```bash\nbandit -r src --exit-zero\n```\n\nUse this only temporarily; otherwise CI will always pass even when Bandit finds issues.\n\n## Authentication And Environment\n\nBandit does not use API credentials. The relevant environment setup is the Python environment where you install the package and the paths you choose to scan.\n\nOperational setup that matters:\n\n- Run Bandit inside the same virtual environment or toolchain lock that owns your Python dependencies.\n- Exclude virtual environments, generated code, vendored code, and migration snapshots unless you explicitly want them scanned.\n- In CI, make the working directory and scan roots explicit so Bandit does not miss source folders or scan build artifacts.\n\n## Common Pitfalls\n\n- `.bandit` is not a universal auto-discovery mechanism. The docs state it is discovered only when `-r` is used.\n- `pyproject.toml` is not read automatically. Use `bandit[toml]` and pass `-c pyproject.toml`.\n- Baselines only work with JSON reports. Do not try to feed Bandit a text or SARIF file with `-b`.\n- `--exit-zero` is useful while introducing Bandit, but it suppresses CI failure even for high-severity findings.\n- A broad skip like `B101` can hide real problems outside tests. Scope skips narrowly and document why they exist.\n- Severity and confidence thresholds are independent. Raising one without the other often leads to confusing result changes in CI.\n- Pre-commit and direct CLI runs should use the same config file, or agents will see inconsistent findings between local and CI runs.\n\n## Version-Sensitive Notes For `1.9.4`\n\n- PyPI lists `1.9.4` as the current release, published on `2026-02-25`.\n- `1.9.4` requires Python `>=3.10`; do not assume older Python runtimes are still supported.\n- The `1.9.4` release fixes several issues that matter in automation, including a crash in the `B613` plugin when scanning stdin, a false positive in `B615`, and incorrect line numbers for multiline cases in `B106`.\n- Older Bandit examples often assume `.bandit` INI files or omit TOML support details. For current projects, `pyproject.toml` plus `bandit[toml]` is usually the cleanest setup.\n"
  },
  {
    "path": "content/bcrypt/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"bcrypt password hashing library for Python applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bcrypt,passwords,hashing,security,python\"\n---\n\n# bcrypt Python Package Guide\n\n`bcrypt` is a local password-hashing library for Python. It does not call a remote API, so there are no API keys, service credentials, or required environment variables. Import the module and use `hashpw()`, `checkpw()`, and `gensalt()` directly.\n\nThe maintainers describe bcrypt as acceptable for password hashing, but note that new designs should prefer `argon2id` or `scrypt` when you are not constrained by bcrypt compatibility.\n\n## Install\n\nInstall the package version you want to target:\n\n```bash\npython -m pip install bcrypt==5.0.0\n```\n\n`bcrypt` 5.0.0 requires Python 3.8+.\n\nMost users should install from wheels. If `pip` falls back to building from source, current `bcrypt` releases use a Rust implementation. The upstream 5.0.0 changelog bumps the minimum supported Rust version to `1.74`.\n\n## Initialization\n\nThere is no client object to create.\n\n```python\nimport bcrypt\n```\n\n`bcrypt` works with `bytes`, not text strings, so encode user input before hashing or verifying.\n\n## Hash A Password\n\nUse `bcrypt.gensalt()` to create a random salt, then pass that salt into `bcrypt.hashpw()`.\n\n```python\nimport bcrypt\n\npassword = \"correct horse battery staple\".encode(\"utf-8\")\npassword_hash = bcrypt.hashpw(password, bcrypt.gensalt())\n\nprint(password_hash)\n```\n\nThe returned hash contains the salt and work factor. Store the full returned value and pass it back into `checkpw()` later.\n\n## Verify A Password\n\nUse the stored hash as the second argument to `bcrypt.checkpw()`.\n\n```python\nimport bcrypt\n\nstored_hash = b\"$2b$12$4B3JQKpcQv8Y7V0nR4N9mOui8Dw1YbtgxwiwA3HscFp8nAX9lLVCi\"\ncandidate_password = \"correct horse battery staple\".encode(\"utf-8\")\n\nif bcrypt.checkpw(candidate_password, stored_hash):\n    print(\"password matches\")\nelse:\n    print(\"invalid password\")\n```\n\nFor normal application code, wrap hashing and verification in one module and keep the byte encoding at the boundary:\n\n```python\nimport bcrypt\n\n\ndef hash_password(password: str) -> bytes:\n    password_bytes = password.encode(\"utf-8\")\n    return bcrypt.hashpw(password_bytes, bcrypt.gensalt())\n\n\ndef verify_password(password: str, password_hash: bytes) -> bool:\n    password_bytes = password.encode(\"utf-8\")\n    return bcrypt.checkpw(password_bytes, password_hash)\n```\n\n## Tune The Work Factor\n\n`bcrypt.gensalt()` defaults to `rounds=12`. Increase the rounds value when you need a higher work factor and your login latency budget allows it.\n\n```python\nimport bcrypt\n\npassword = \"correct horse battery staple\".encode(\"utf-8\")\npassword_hash = bcrypt.hashpw(password, bcrypt.gensalt(rounds=14))\n```\n\nIf you need to interoperate with systems that expect a specific bcrypt prefix, `gensalt()` also accepts `prefix=` as bytes. Upstream documents `b\"2b\"` as the default and supports `b\"2a\"` when you need compatibility with older libraries.\n\n```python\nimport bcrypt\n\nsalt = bcrypt.gensalt(rounds=12, prefix=b\"2b\")\npassword_hash = bcrypt.hashpw(b\"secret\", salt)\n```\n\n## Use `kdf()` Only For `bcrypt_pbkdf`\n\n`bcrypt.kdf()` is separate from password-hash storage. The upstream README documents it as `bcrypt_pbkdf`, which is used by newer encrypted OpenSSH private key formats.\n\n```python\nimport bcrypt\n\nkey = bcrypt.kdf(\n    password=b\"password\",\n    salt=b\"salt\",\n    desired_key_bytes=32,\n    rounds=100,\n)\n```\n\nUse `hashpw()` and `checkpw()` for login passwords. Use `kdf()` only when you specifically need a derived key.\n\n## Handle Long Passwords Explicitly\n\n`bcrypt` 5.0.0 changes an important edge case: passing `hashpw()` a password longer than 72 bytes now raises `ValueError`. Older releases silently truncated after 72 bytes.\n\nIf your app must accept arbitrarily long passphrases while still storing bcrypt hashes, the upstream README shows a common workaround: hash the password first with SHA-256, base64-encode the digest, then bcrypt that result.\n\n```python\nimport base64\nimport hashlib\n\nimport bcrypt\n\n\ndef normalize_password(password: str) -> bytes:\n    password_bytes = password.encode(\"utf-8\")\n\n    if len(password_bytes) <= 72:\n        return password_bytes\n\n    digest = hashlib.sha256(password_bytes).digest()\n    return base64.b64encode(digest)\n\n\ndef hash_password(password: str) -> bytes:\n    return bcrypt.hashpw(normalize_password(password), bcrypt.gensalt())\n\n\ndef verify_password(password: str, password_hash: bytes) -> bool:\n    return bcrypt.checkpw(normalize_password(password), password_hash)\n```\n\nDo not mix raw-password bcrypt hashes and pre-hashed bcrypt hashes for the same user population unless you have an explicit migration plan.\n\n## Common Pitfalls\n\n- Encode strings to `bytes` before calling `hashpw()`, `checkpw()`, or `kdf()`.\n- Store the full bcrypt hash returned by `hashpw()`; verification expects that exact stored hash.\n- Expect `ValueError` for passwords longer than 72 bytes in `bcrypt` 5.0.0.\n- Keep `pip` reasonably current so it can install available wheels instead of forcing a source build.\n- If a source build is required, make sure Rust is available; current `bcrypt` releases are implemented in Rust.\n\n## Version Notes For 5.0.0\n\n- Python 3.14 and free-threaded Python 3.14 are supported.\n- Windows on ARM is supported.\n- The minimum supported Rust version was bumped to `1.74` for source builds.\n- `hashpw()` now raises `ValueError` for passwords longer than 72 bytes instead of silently truncating them.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/pyca/bcrypt/\n- PyPI package page: https://pypi.org/project/bcrypt/\n- Security policy referenced by the package docs: https://cryptography.io/en/latest/security.html\n"
  },
  {
    "path": "content/beautifulsoup4/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Beautiful Soup 4 package guide for Python with parser selection, searching, CSS selectors, and common pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.14.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"beautifulsoup4,bs4,html,xml,parsing,scraping\"\n---\n\n# Beautiful Soup 4 Python Package Guide\n\n## What It Is\n\n`beautifulsoup4` is the Python package for the `bs4` library. It parses HTML or XML into a navigable tree so you can search, filter, and rewrite markup with Python objects instead of string manipulation.\n\nGolden rules:\n\n- Install `beautifulsoup4`, but import it as `from bs4 import BeautifulSoup`.\n- Always choose a parser explicitly so the parse tree is predictable across machines.\n- Beautiful Soup does not fetch URLs, execute JavaScript, or handle auth. Use `requests`, `httpx`, Selenium, Playwright, or another fetch/render layer separately.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"beautifulsoup4==4.14.3\"\n```\n\nParser backends are separate packages. Install one when you want faster or more standards-complete parsing:\n\n```bash\npython -m pip install \"lxml\"\npython -m pip install \"html5lib\"\n```\n\nCommon combinations:\n\n```bash\npython -m pip install \"beautifulsoup4==4.14.3\" \"lxml\"\npython -m pip install \"beautifulsoup4==4.14.3\" \"html5lib\"\n```\n\n## Initialization And Parser Choice\n\nBeautiful Soup accepts a markup string, bytes, or a filehandle:\n\n```python\nfrom bs4 import BeautifulSoup\n\nhtml = b\"\"\"\n<html>\n  <body>\n    <a class=\"story\" href=\"https://example.com/1\">One</a>\n    <a class=\"story\" href=\"https://example.com/2\">Two</a>\n  </body>\n</html>\n\"\"\"\n\nsoup = BeautifulSoup(html, \"html.parser\")\nprint(soup.select_one(\"a\")[\"href\"])\n```\n\nChoose the parser deliberately:\n\n- `\"html.parser\"`: built-in, no extra dependency, good default for basic HTML.\n- `\"lxml\"`: usually the fastest HTML parser and a common production choice.\n- `\"html5lib\"`: most browser-like HTML5 parsing, but slower.\n- `\"xml\"`: XML parsing, requires `lxml`.\n\nParser choice matters because invalid markup can produce different trees with different parsers. If you omit the parser, Beautiful Soup picks the best installed one, which can change behavior between environments.\n\n## Core Usage\n\n### Find elements\n\n`find()` returns the first match or `None`. `find_all()` returns a list-like `ResultSet`.\n\n```python\nfrom bs4 import BeautifulSoup\n\nhtml = \"\"\"\n<ul id=\"items\">\n  <li class=\"item featured\"><a href=\"/a\">Alpha</a></li>\n  <li class=\"item\"><a href=\"/b\">Beta</a></li>\n</ul>\n\"\"\"\n\nsoup = BeautifulSoup(html, \"html.parser\")\n\nfirst_item = soup.find(\"li\", class_=\"item\")\nall_links = soup.find_all(\"a\")\n\nprint(first_item.get_text(strip=True))\nprint([link[\"href\"] for link in all_links])\n```\n\nUseful patterns:\n\n- Use `class_=` instead of `class=` because `class` is a Python keyword.\n- Use `attrs={...}` for attribute dictionaries when the field name is not a valid Python identifier.\n- Check for `None` before dereferencing the result of `find()`.\n\n### Use CSS selectors\n\nBeautiful Soup supports CSS selector queries:\n\n```python\nfrom bs4 import BeautifulSoup\n\nhtml = \"\"\"\n<ul id=\"items\">\n  <li class=\"item featured\"><a href=\"/a\">Alpha</a></li>\n  <li class=\"item\"><a href=\"/b\">Beta</a></li>\n</ul>\n\"\"\"\n\nsoup = BeautifulSoup(html, \"html.parser\")\n\nfeatured = soup.select_one(\"li.featured > a\")\nall_story_links = soup.select(\"li.item a[href]\")\n\nprint(featured[\"href\"])\nprint([node.get_text(strip=True) for node in all_story_links])\n```\n\nThe newer `.css` convenience property is also available in recent 4.x releases:\n\n```python\nlinks = soup.css.select(\"li.item a\")\n```\n\nFor widest compatibility across older `beautifulsoup4` pins, prefer `select()` and `select_one()`.\n\n### Traverse the tree\n\n```python\nfrom bs4 import BeautifulSoup\n\nsoup = BeautifulSoup(\"<p><b>bold</b> and <i>italic</i></p>\", \"html.parser\")\np = soup.p\n\nprint(p.contents)\nprint(p.b.parent.name)\nprint([child.name for child in p.children if getattr(child, \"name\", None)])\n```\n\nUseful navigation attributes and iterators:\n\n- `.parent`\n- `.contents`\n- `.children`\n- `.descendants`\n- `.next_sibling` / `.previous_sibling`\n- `.next_element` / `.previous_element`\n\n### Extract text\n\n```python\nfrom bs4 import BeautifulSoup\n\nsoup = BeautifulSoup(\"<div>Hello <b>world</b><br/>again</div>\", \"html.parser\")\ntext = soup.get_text(\" \", strip=True)\nprint(text)\n```\n\nUse `get_text(separator, strip=True)` when you need plain text. This is usually safer than relying on `.text` in cleanup pipelines because you can control whitespace.\n\n### Modify markup\n\n```python\nfrom bs4 import BeautifulSoup\n\nsoup = BeautifulSoup(\"<div><span>old</span></div>\", \"html.parser\")\n\nspan = soup.find(\"span\")\nspan.string = \"new\"\n\nbadge = soup.new_tag(\"strong\")\nbadge.string = \"!\"\nspan.insert_after(badge)\n\nprint(soup)\n```\n\nMutation helpers to know:\n\n- `append()`\n- `insert()`\n- `insert_before()` / `insert_after()`\n- `replace_with()`\n- `extract()`\n- `decompose()`\n- `unwrap()`\n- `clear()`\n\n### Parse only part of a large document\n\nUse `SoupStrainer` when you only need a subset of the document:\n\n```python\nfrom bs4 import BeautifulSoup, SoupStrainer\n\nonly_links = SoupStrainer(\"a\")\nsoup = BeautifulSoup(html, \"html.parser\", parse_only=only_links)\n\nprint([a.get(\"href\") for a in soup.find_all(\"a\")])\n```\n\nThis reduces work on large inputs, but the docs note that `parse_only` is not supported by the `html5lib` tree builder.\n\n## Configuration Notes\n\n### No auth or transport layer\n\nBeautiful Soup is only the parser layer. It does not do:\n\n- HTTP requests\n- cookies or sessions\n- retries or timeouts\n- browser rendering\n- authentication flows\n\nFetch content separately, then hand the response body to Beautiful Soup.\n\n### Encoding handling\n\nBeautiful Soup uses Unicode, Dammit to detect and convert incoming encodings to Unicode. You can inspect what it chose:\n\n```python\nfrom bs4 import BeautifulSoup\n\nmarkup = \"<h1>Sacr\\xe9 bleu!</h1>\".encode(\"latin-1\")\nsoup = BeautifulSoup(markup, \"html.parser\")\n\nprint(soup.h1.string)\nprint(soup.original_encoding)\n```\n\nIf you already know the correct encoding, pass `from_encoding=` to avoid guesswork.\n\n### XML mode\n\nFor XML documents, use:\n\n```python\nfrom bs4 import BeautifulSoup\n\nxml = \"<root><item id='1'/></root>\"\nsoup = BeautifulSoup(xml, \"xml\")\n```\n\nThe official docs state that `lxml` is currently the only supported XML parser backend.\n\n## Common Pitfalls\n\n- Do not install the obsolete `BeautifulSoup` package from PyPI. Use `beautifulsoup4`.\n- Do not rely on the default parser choice. Different parser availability leads to different trees for malformed markup.\n- `find()` can return `None`. Guard it before using `[\"href\"]`, `.text`, or `.get_text()`.\n- Beautiful Soup parses static markup only. If the page depends on client-side JavaScript, fetch the rendered HTML with a browser automation or rendering step first.\n- `class` is multi-valued in HTML. Use `class_=` or CSS selectors instead of naïve string equality assumptions.\n- `prettify()` is useful for debugging, not for round-tripping production HTML.\n- `html5lib` is the slowest parser. Use it when HTML5 correctness matters more than speed.\n- `parse_only=SoupStrainer(...)` does not work with `html5lib`.\n\nFor malformed documents, the docs recommend `bs4.diagnose.diagnose()` as a troubleshooting tool.\n\n## Version-Sensitive Notes\n\n- The version used here `4.14.3` matched the live PyPI package version on March 12, 2026.\n- PyPI metadata for `4.14.3` declares `Requires-Python >=3.7`.\n- The official docs mention that the example code in the docs is written for Python 3.8, so syntax in the guide is not a strict lower-bound guarantee for your runtime.\n- The `.css` property was added in Beautiful Soup `4.12.0`. If you are pinned below `4.12`, use `select()` and `select_one()` instead.\n- Since Beautiful Soup `4.9.0`, `get_text()` skips the contents of `script`, `style`, and `template` tags for parsers that represent those contents as special string containers. Older behavior can differ if you are maintaining legacy scrapers.\n"
  },
  {
    "path": "content/bentoml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"BentoML package guide for Python model serving, packaging, and BentoCloud deployment workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.36\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bentoml,python,serving,inference,mlops,deployment\"\n---\n\n# BentoML Python Package Guide\n\n## What It Is\n\n`bentoml` is a Python framework for turning model inference code into production services. The current upstream docs center on class-based services defined with `@bentoml.service`, HTTP APIs defined with `@bentoml.api`, packaging those services into Bentos, and then serving or containerizing them for deployment.\n\n## Installation\n\nPin the package when you need agent output to match the version used here:\n\n```bash\npython -m pip install \"bentoml==1.4.36\"\n```\n\nWith Poetry:\n\n```bash\npoetry add \"bentoml==1.4.36\"\n```\n\nWith uv:\n\n```bash\nuv add bentoml==1.4.36\n```\n\nIf the service depends on model-framework packages, add those separately. BentoML packaging can also install extra Python packages declared in the service config.\n\n## Initialize A Service\n\nCreate a module such as `service.py` and define a class service:\n\n```python\nimport bentoml\n\n@bentoml.service(\n    traffic={\"timeout\": 30},\n    workers=1,\n)\nclass Summarizer:\n    def __init__(self) -> None:\n        self.prefix = \"summary:\"\n\n    @bentoml.api\n    def summarize(self, text: str) -> str:\n        return f\"{self.prefix} {text[:80]}\"\n```\n\nRun it locally:\n\n```bash\nbentoml serve service:Summarizer\n```\n\nThe `service:Summarizer` target is `<module>:<service class>`. For local iteration, the docs also show `bentoml serve --reload ...` patterns.\n\n## Core Usage\n\n### Define HTTP APIs\n\nMethods decorated with `@bentoml.api` become HTTP endpoints. The endpoint path defaults to the method name.\n\n```python\nimport bentoml\nfrom pydantic import BaseModel\n\nclass PredictRequest(BaseModel):\n    prompt: str\n\nclass PredictResponse(BaseModel):\n    output: str\n\n@bentoml.service\nclass TextService:\n    @bentoml.api\n    def health(self) -> dict[str, str]:\n        return {\"status\": \"ok\"}\n\n    @bentoml.api\n    def predict(self, request: PredictRequest) -> PredictResponse:\n        return PredictResponse(output=request.prompt.upper())\n```\n\nUse plain Python types for simple JSON endpoints. Reach for Pydantic models or explicit IO descriptors when request or response shapes need validation or when you are serving files, images, or other non-JSON content.\n\n### Package A Deployable Bento\n\nOnce the service works locally, build a Bento:\n\n```bash\nbentoml build\n```\n\nThis produces a versioned Bento artifact containing the service code and its runtime configuration. You can then containerize it:\n\n```bash\nbentoml containerize my_service:latest\n```\n\nOn Apple Silicon, the official docs recommend passing `--platform=linux/amd64` when the deployment target expects x86 containers.\n\n### Bundle Python Dependencies\n\nBentoML supports package installation from service configuration. A minimal example in `bentofile.yaml`:\n\n```yaml\nservice: \"service:Summarizer\"\ninclude:\n  - \"*.py\"\npython:\n  packages:\n    - \"bentoml==1.4.36\"\n    - \"transformers\"\n    - \"torch\"\n```\n\nUse this to make builds reproducible. If your project already has a lockfile, keep BentoML packaging aligned with it instead of duplicating drifting dependency pins.\n\n## Config And Auth\n\n### Local Configuration\n\n- `BENTOML_HOME` controls where Bentos, models, environments, and temporary files are stored.\n- The default home directory is `~/bentoml`.\n- The docs recommend setting `BENTOML_HOME` explicitly when you want isolated local state in CI, tests, or per-project environments.\n\nExample:\n\n```bash\nexport BENTOML_HOME=\"$PWD/.bentoml\"\n```\n\nService-level runtime settings can also be declared on `@bentoml.service`, including traffic limits, worker count, and GPU/CPU resource requirements:\n\n```python\n@bentoml.service(\n    workers=2,\n    resources={\"gpu\": 1, \"gpu_type\": \"nvidia-l4\"},\n    traffic={\"timeout\": 60, \"concurrency\": 16},\n)\nclass GPUService:\n    ...\n```\n\n### BentoCloud Auth\n\nFor BentoCloud deployment, authenticate the CLI before pushing or deploying:\n\n```bash\nbentoml cloud login\n```\n\nAfter login, choose the correct context before operating on deployments:\n\n```bash\nbentoml cloud current-context\n```\n\nIf your automation runs non-interactively, prefer the official BentoCloud token-based setup rather than embedding credentials in code.\n\n## Common Pitfalls\n\n- Old service style vs current docs: for `1.4.x`, prefer class-based `@bentoml.service` services. Older blog posts may still show `svc = bentoml.Service(...)`.\n- Packaging only `bentoml`: model frameworks such as `torch`, `transformers`, or `diffusers` are not implied. Add them explicitly to your environment or `bentofile.yaml`.\n- Mutable local state in tests: BentoML writes to `~/bentoml` by default. Set `BENTOML_HOME` for isolated test runs and CI.\n- Container target mismatch: on Apple Silicon, local container builds may not match Linux x86 production unless you pass `--platform=linux/amd64`.\n- Hidden endpoint assumptions: method names become routes by default. Renaming a Python method changes the HTTP path unless you pin the route explicitly.\n- Resource declarations are deployment inputs, not magic autoscaling. If you mark `resources={\"gpu\": 1}` on a machine without GPUs, local runs still need a compatible runtime.\n- Docs-root drift: the official docs URL is `/en/latest/`, not a frozen `1.4.36` snapshot. Verify any CLI flag or deployment behavior that looks newer than your installed package.\n\n## Version-Sensitive Notes\n\n- `1.4.36` is the package version covered here and was released on PyPI on `2026-03-10`.\n- The official docs currently document the modern class-based service API. The service page explicitly notes that, starting with BentoML `1.2`, services should be defined as a class decorated with `@bentoml.service`.\n- The service docs also note behavior added in BentoML `1.3.20` for accessing deployment context from inside a service. If you copy advanced deployment examples, confirm they are compatible with `1.4.36`.\n- Inference from the official docs structure: because the docs root is `en/latest`, examples can move ahead of the pinned package version. Treat the live docs as canonical for current patterns, but pin installs and packaging config to the version your project actually uses.\n\n## Practical Guidance For Agents\n\n1. Start with one small class-based service and one or two `@bentoml.api` methods before adding model loading, batching, or GPU configuration.\n2. Keep runtime dependencies explicit in `bentofile.yaml` or your environment manager so Bento builds are reproducible.\n3. Set `BENTOML_HOME` in CI and tests to avoid leaking state across jobs.\n4. Use `bentoml serve module:ServiceClass` for local verification before building or deploying.\n5. Add BentoCloud login and context checks only when the task actually includes cloud deployment; they are not needed for local serving.\n\n## Official Sources\n\n- Documentation root: `https://docs.bentoml.com/en/latest/`\n- Create services: `https://docs.bentoml.com/en/latest/build-with-bentoml/services.html`\n- Package dependencies and Bento builds: `https://docs.bentoml.com/en/latest/get-started/packaging-for-deployment.html`\n- Runtime config and `BENTOML_HOME`: `https://docs.bentoml.com/en/latest/reference/bentoml/configurations.html`\n- BentoCloud CLI auth and context: `https://docs.bentoml.com/en/latest/reference/bentoml/bento-cloud.html`\n- PyPI package page: `https://pypi.org/project/bentoml/`\n- PyPI release history for `1.4.36`: `https://pypi.org/project/bentoml/#history`\n"
  },
  {
    "path": "content/billiard/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"billiard Python package guide for multiprocessing-style processes, pools, queues, and start methods\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"billiard,python,multiprocessing,processes,pool,celery\"\n---\n\n# billiard Python Package Guide\n\n## Golden Rule\n\nUse `billiard` when a project is already built around Celery's multiprocessing fork, and import the process primitives you need from `billiard` itself. The maintainer README describes `billiard` as a fork of Python's `multiprocessing` package with a few extensions used by Celery, so treat it as multiprocessing-style infrastructure rather than as a network client or service SDK.\n\n## Install\n\nPyPI lists `billiard 4.2.4` with `Requires-Python >=3.7`.\n\n```bash\npython -m pip install \"billiard==4.2.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"billiard==4.2.4\"\npoetry add \"billiard==4.2.4\"\n```\n\n## Setup And Runtime Model\n\n`billiard` does not use API keys, service auth, or package-specific environment variables.\n\nThere is also no client object to initialize. Setup is:\n\n1. import the process primitives you need\n2. optionally choose a start method or context\n3. create processes, queues, or pools inside a `__main__` guard\n\nCommon imports:\n\n```python\nfrom billiard import Pool, Process, Queue, get_context\nfrom billiard.spawn import freeze_support\n```\n\n## Core Workflows\n\n### Start a child process and pass results through a queue\n\nThe programming guidelines require protecting process creation with `if __name__ == \"__main__\":` when using spawn-like start methods or running on Windows.\n\n```python\nfrom billiard import Process, Queue\n\n\ndef worker(result_queue: Queue, value: int) -> None:\n    result_queue.put(value * 2)\n\n\nif __name__ == \"__main__\":\n    result_queue = Queue()\n    process = Process(target=worker, args=(result_queue, 21))\n    process.start()\n\n    print(result_queue.get())  # 42\n\n    process.join()\n```\n\n### Run CPU-bound work in a pool\n\n`Pool.map`, `Pool.imap`, `Pool.imap_unordered`, `Pool.apply`, and `Pool.apply_async` are part of the documented pool API. Use explicit `close()` and `join()` so worker shutdown is predictable.\n\n```python\nfrom billiard import Pool\n\n\ndef square(value: int) -> int:\n    return value * value\n\n\nif __name__ == \"__main__\":\n    pool = Pool(processes=4)\n    try:\n        print(pool.map(square, [1, 2, 3, 4]))\n\n        total = sum(pool.imap_unordered(square, range(5)))\n        print(total)\n    finally:\n        pool.close()\n        pool.join()\n```\n\nIf a worker should be recycled after a fixed number of tasks, `Pool(..., maxtasksperchild=N)` is part of the documented constructor.\n\n### Choose the start method explicitly\n\n`billiard` exports `get_context()` and `set_start_method()` at the package top level. Use an explicit context when your code must behave consistently across Linux, macOS, and Windows.\n\n```python\nfrom billiard import get_context\n\n\ndef worker(value: int) -> None:\n    print(f\"child received {value}\")\n\n\nif __name__ == \"__main__\":\n    ctx = get_context(\"spawn\")\n    process = ctx.Process(target=worker, args=(42,))\n    process.start()\n    process.join()\n```\n\nUse `\"spawn\"` when you want the safest cross-platform behavior. Only rely on `\"fork\"` when the target environment supports it and the code is written with fork semantics in mind.\n\n### Support frozen Windows executables\n\nThe maintainer docs call out `freeze_support()` for frozen executables created with tools such as PyInstaller or cx_Freeze.\n\n```python\nfrom billiard import Process\nfrom billiard.spawn import freeze_support\n\n\ndef worker() -> None:\n    print(\"hello from child\")\n\n\nif __name__ == \"__main__\":\n    freeze_support()\n\n    process = Process(target=worker)\n    process.start()\n    process.join()\n```\n\n## Configuration Notes\n\n- No package-specific environment variables are required.\n- There is no persistent client or connection object.\n- The main configuration choices are process count, queue usage, and start method.\n- `Pool(..., maxtasksperchild=N)` is the built-in worker-recycling knob when long-running workers should not stay alive forever.\n\n## Common Pitfalls\n\n- Do not create child processes at import time. Put process and pool startup behind `if __name__ == \"__main__\":` or spawn and forkserver bootstrapping will fail.\n- Call `freeze_support()` in frozen Windows builds before starting child processes.\n- Daemonic processes cannot create child processes. If a worker needs to launch more workers, do not mark it daemonic.\n- Be deliberate about the start method. Platform defaults differ, and code that only works under `fork` is fragile in cross-platform projects.\n- Close and join pools you create. Otherwise workers may linger and shutdown behavior becomes harder to reason about.\n\n## Version-Sensitive Notes For `4.2.4`\n\n- PyPI currently lists `4.2.4` as the latest stable release, with `4.3.0rc1` available as a pre-release.\n- The `4.2.4` changelog includes compatibility work for Python 3.13.\n- The same changelog notes that the `spawn` and `forkserver` start methods are allowed to execute on Python 3.14 and later.\n- The package remains a Celery-maintained multiprocessing fork, so conceptual behavior is still closest to Python's multiprocessing model rather than to a Celery task API.\n\n## Official Sources\n\n- Repository README: https://github.com/celery/billiard/blob/master/README.rst\n- Package exports: https://raw.githubusercontent.com/celery/billiard/master/billiard/__init__.py\n- Frozen executable support: https://raw.githubusercontent.com/celery/billiard/master/billiard/spawn.py\n- Programming guidelines: https://billiard.readthedocs.io/en/latest/library/multiprocessing.html#programming-guidelines\n- Pool API reference: https://billiard.readthedocs.io/en/latest/library/multiprocessing.html#module-billiard.pool\n- Changelog: https://raw.githubusercontent.com/celery/billiard/master/CHANGES.txt\n- PyPI package page: https://pypi.org/project/billiard/\n- PyPI JSON metadata: https://pypi.org/pypi/billiard/json\n"
  },
  {
    "path": "content/binance/docs/trading/javascript/DOC.md",
    "content": "---\nname: trading\ndescription: \"Binance API JavaScript/TypeScript coding guidelines for trading using official libraries and SDKs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.6.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"binance,trading,crypto,exchange,api\"\n---\n\n# Binance API JavaScript/TypeScript Coding Guidelines\n\nYou are a Binance API coding expert. Help me with writing code using the Binance API calling the official libraries and SDKs.\n\nYou can find the official documentation here:\nhttps://developers.binance.com/docs/binance-spot-api-docs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Binance Connector for Node.js, which is the standard library for all Binance Spot API interactions. Do not use unofficial or third-party libraries.\n\n- **Library Name:** Binance Connector for Node.js\n- **NPM Package:** `@binance/connector`\n- **Alternative Official Packages:** `@binance/spot` (newer modular package), `@binance/futures-connector`, `@binance/pay`\n- **Unofficial Libraries:** `binance-api-node`, `node-binance-api` (not recommended for production)\n\n**Installation:**\n\n- **Correct:** `npm install @binance/connector`\n- **Alternative:** `npm install @binance/spot` (for newer modular approach)\n\n**APIs and Usage:**\n\n- **Correct:** `const { Spot } = require('@binance/connector')`\n- **Correct:** `const client = new Spot(apiKey, apiSecret)`\n- **Correct:** `client.account()` for account information\n- **Correct:** `client.newOrder()` for placing orders\n- **Incorrect:** Using unofficial packages like `binance-api-node`\n- **Incorrect:** Direct HTTP requests without using the connector\n\n## Installation\n\nInstall the official Binance connector for Node.js:\n\n```bash\nnpm install @binance/connector\n```\n\nFor TypeScript projects, the package includes built-in type definitions.\n\n**Environment Variables:**\n\nSet your API credentials as environment variables:\n\n```bash\nexport BINANCE_API_KEY='your_api_key_here'\nexport BINANCE_API_SECRET='your_api_secret_here'\n```\n\nOr create a `.env` file:\n\n```bash\nBINANCE_API_KEY=your_api_key_here\nBINANCE_API_SECRET=your_api_secret_here\n```\n\n## Initialization\n\nThe `@binance/connector` library requires creating a `Spot` instance for all API calls.\n\n### Basic Initialization (Public Endpoints)\n\nFor public market data endpoints that don't require authentication:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\n// Public endpoints only (no authentication)\nconst client = new Spot()\n\n// Use client for public data\nclient.exchangeInfo()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Authenticated Initialization (HMAC)\n\nFor trading and account endpoints:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst apiKey = process.env.BINANCE_API_KEY\nconst apiSecret = process.env.BINANCE_API_SECRET\n\n// Authenticated client with HMAC\nconst client = new Spot(apiKey, apiSecret)\n\n// Use client for authenticated endpoints\nclient.account()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### RSA/ED25519 Authentication\n\nFor enhanced security using RSA or ED25519 private keys:\n\n```javascript\nconst { Spot, PrivateKeyAlgo } = require('@binance/connector')\nconst fs = require('fs')\n\nconst apiKey = process.env.BINANCE_API_KEY\nconst privateKey = fs.readFileSync('/path/to/private_key.pem', 'utf8')\nconst privateKeyPassphrase = 'your_passphrase' // Optional\nconst privateKeyAlgo = PrivateKeyAlgo.RSA // or PrivateKeyAlgo.ED25519\n\nconst client = new Spot(apiKey, '', {\n  privateKey,\n  privateKeyPassphrase,\n  privateKeyAlgo\n})\n```\n\n### Client Configuration Options\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret, {\n  baseURL: 'https://api.binance.com', // Default base URL\n  timeout: 10000, // Request timeout in milliseconds (default: 10000)\n  recvWindow: 5000, // API timing security (default: 5000)\n  logger: console // Custom logger (optional)\n})\n```\n\n### Testnet Configuration\n\nFor testing without real funds:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret, {\n  baseURL: 'https://testnet.binance.vision'\n})\n```\n\n### Proxy Configuration\n\nFor requests through a proxy:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret, {\n  proxy: {\n    protocol: 'https',\n    host: '127.0.0.1',\n    port: 9000,\n    auth: {\n      username: 'proxy_user',\n      password: 'proxy_password'\n    }\n  }\n})\n```\n\n## Market Data Endpoints\n\nMarket data endpoints provide access to public trading information without authentication.\n\n### Exchange Information\n\nGet exchange trading rules and symbol information:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot()\n\n// Get all exchange information\nclient.exchangeInfo()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get specific symbol information\nclient.exchangeInfo({ symbol: 'BTCUSDT' })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get information for multiple symbols\nclient.exchangeInfo({ symbols: ['BTCUSDT', 'ETHUSDT'] })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Order Book (Depth)\n\nGet current order book for a symbol:\n\n```javascript\n// Get order book with default limit (100)\nclient.depth('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get order book with specific limit (5, 10, 20, 50, 100, 500, 1000, 5000)\nclient.depth('BTCUSDT', { limit: 10 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Recent Trades\n\nGet recent trades for a symbol:\n\n```javascript\n// Get recent trades (default limit: 500)\nclient.trades('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get specific number of recent trades\nclient.trades('BTCUSDT', { limit: 100 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Historical Trades\n\nGet older trades (requires API key):\n\n```javascript\nconst client = new Spot(apiKey, apiSecret)\n\n// Get historical trades\nclient.historicalTrades('BTCUSDT', { limit: 100 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get trades from specific ID\nclient.historicalTrades('BTCUSDT', { limit: 100, fromId: 28457 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Aggregate Trades\n\nGet compressed, aggregate trades:\n\n```javascript\n// Get recent aggregate trades\nclient.aggTrades('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get aggregate trades with time range\nclient.aggTrades('BTCUSDT', {\n  startTime: 1609459200000,\n  endTime: 1609545600000,\n  limit: 1000\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get aggregate trades from specific ID\nclient.aggTrades('BTCUSDT', { fromId: 28457, limit: 500 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Candlestick Data (Klines)\n\nGet kline/candlestick bars for a symbol:\n\n```javascript\n// Get recent klines (default limit: 500)\nclient.klines('BTCUSDT', '1h')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get klines with time range\nclient.klines('BTCUSDT', '1d', {\n  startTime: 1609459200000,\n  endTime: 1609545600000,\n  limit: 100\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Available intervals: 1s, 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M\n```\n\n### Current Average Price\n\nGet current average price for a symbol:\n\n```javascript\nclient.avgPrice('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### 24hr Ticker Price Change Statistics\n\nGet 24-hour rolling window price change statistics:\n\n```javascript\n// Get ticker for single symbol\nclient.ticker24hr('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get ticker for multiple symbols\nclient.ticker24hr({ symbols: ['BTCUSDT', 'ETHUSDT'] })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get ticker for all symbols\nclient.ticker24hr()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Symbol Price Ticker\n\nGet latest price for a symbol:\n\n```javascript\n// Get price for single symbol\nclient.tickerPrice('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get price for multiple symbols\nclient.tickerPrice({ symbols: ['BTCUSDT', 'ETHUSDT'] })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get price for all symbols\nclient.tickerPrice()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Symbol Order Book Ticker\n\nGet best price/quantity on the order book:\n\n```javascript\n// Get book ticker for single symbol\nclient.bookTicker('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get book ticker for multiple symbols\nclient.bookTicker({ symbols: ['BTCUSDT', 'ETHUSDT'] })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get book ticker for all symbols\nclient.bookTicker()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n## Trading Endpoints\n\nTrading endpoints require authentication and allow you to place, cancel, and query orders.\n\n### New Order\n\nPlace a new order on the exchange:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\n// Market buy order\nclient.newOrder('BTCUSDT', 'BUY', 'MARKET', {\n  quantity: 0.001\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Market sell order with quote quantity\nclient.newOrder('BTCUSDT', 'SELL', 'MARKET', {\n  quoteOrderQty: 100\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Limit buy order\nclient.newOrder('BTCUSDT', 'BUY', 'LIMIT', {\n  quantity: 0.001,\n  price: 50000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Limit sell order\nclient.newOrder('BTCUSDT', 'SELL', 'LIMIT', {\n  quantity: 0.001,\n  price: 60000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Stop-loss order\nclient.newOrder('BTCUSDT', 'SELL', 'STOP_LOSS_LIMIT', {\n  quantity: 0.001,\n  price: 48000,\n  stopPrice: 49000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Take-profit order\nclient.newOrder('BTCUSDT', 'SELL', 'TAKE_PROFIT_LIMIT', {\n  quantity: 0.001,\n  price: 62000,\n  stopPrice: 61000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n**Order Types:**\n- `MARKET` - Market order\n- `LIMIT` - Limit order\n- `STOP_LOSS` - Stop-loss order\n- `STOP_LOSS_LIMIT` - Stop-loss limit order\n- `TAKE_PROFIT` - Take-profit order\n- `TAKE_PROFIT_LIMIT` - Take-profit limit order\n- `LIMIT_MAKER` - Limit maker order\n\n**Time in Force:**\n- `GTC` - Good Till Cancel\n- `IOC` - Immediate or Cancel\n- `FOK` - Fill or Kill\n\n### Test New Order\n\nTest order placement without actually placing the order:\n\n```javascript\n// Test a limit order\nclient.newOrderTest('BTCUSDT', 'BUY', 'LIMIT', {\n  quantity: 0.001,\n  price: 50000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Query Order\n\nCheck an order's status:\n\n```javascript\n// Query by orderId\nclient.getOrder('BTCUSDT', { orderId: 28 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Query by origClientOrderId\nclient.getOrder('BTCUSDT', { origClientOrderId: 'myOrder1' })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Cancel Order\n\nCancel an active order:\n\n```javascript\n// Cancel by orderId\nclient.cancelOrder('BTCUSDT', { orderId: 28 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Cancel by origClientOrderId\nclient.cancelOrder('BTCUSDT', { origClientOrderId: 'myOrder1' })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Cancel All Open Orders\n\nCancel all active orders on a symbol:\n\n```javascript\nclient.cancelOpenOrders('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Cancel and Replace Order\n\nCancel an existing order and place a new order on the same symbol:\n\n```javascript\n// Cancel and replace by orderId\nclient.cancelReplaceOrder('BTCUSDT', 'BUY', 'LIMIT', 'STOP_ON_FAILURE', {\n  cancelOrderId: 28,\n  quantity: 0.002,\n  price: 51000,\n  timeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Current Open Orders\n\nGet all open orders on a symbol:\n\n```javascript\n// Get open orders for specific symbol\nclient.openOrders('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get all open orders\nclient.openOrders()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### All Orders\n\nGet all account orders (active, canceled, or filled):\n\n```javascript\n// Get all orders for a symbol\nclient.allOrders('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get orders with time range\nclient.allOrders('BTCUSDT', {\n  startTime: 1609459200000,\n  endTime: 1609545600000,\n  limit: 500\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get orders from specific orderId\nclient.allOrders('BTCUSDT', { orderId: 28, limit: 500 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### OCO Orders (One-Cancels-the-Other)\n\nPlace a pair of orders where if one is executed, the other is canceled:\n\n```javascript\n// Place OCO order\nclient.newOCOOrder('BTCUSDT', 'SELL', 0.001, 62000, 48000, {\n  stopLimitPrice: 47500,\n  stopLimitTimeInForce: 'GTC'\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Cancel OCO order\nclient.cancelOCOOrder('BTCUSDT', { orderListId: 0 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Query OCO order\nclient.getOCOOrder({ orderListId: 0 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get all OCO orders\nclient.getOCOOrders()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get open OCO orders\nclient.getOpenOCOOrders()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n## Account Endpoints\n\nAccount endpoints provide access to account information and require authentication.\n\n### Account Information\n\nGet current account information:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\nclient.account()\n  .then(response => {\n    const data = response.data\n    console.log('Account Type:', data.accountType)\n    console.log('Can Trade:', data.canTrade)\n    console.log('Can Withdraw:', data.canWithdraw)\n    console.log('Can Deposit:', data.canDeposit)\n    console.log('Balances:', data.balances)\n  })\n  .catch(error => console.error(error))\n```\n\n### Account Trade List\n\nGet trades for a specific symbol:\n\n```javascript\n// Get recent trades\nclient.myTrades('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get trades with time range\nclient.myTrades('BTCUSDT', {\n  startTime: 1609459200000,\n  endTime: 1609545600000,\n  limit: 500\n})\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n\n// Get trades from specific ID\nclient.myTrades('BTCUSDT', { fromId: 28457, limit: 500 })\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Current Order Count Usage\n\nGet current order count usage for rate limits:\n\n```javascript\nclient.rateLimitOrder()\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n### Query Prevented Matches\n\nGet prevented matches from Self-Trade Prevention:\n\n```javascript\nclient.preventedMatches('BTCUSDT')\n  .then(response => console.log(response.data))\n  .catch(error => console.error(error))\n```\n\n## WebSocket Streams\n\nWebSocket streams provide real-time market data with low latency.\n\n### WebSocket Stream Client\n\nInitialize a WebSocket stream client:\n\n```javascript\nconst { WebsocketStream } = require('@binance/connector')\n\n// Create WebSocket stream client\nconst callbacks = {\n  open: () => console.log('WebSocket connected'),\n  close: () => console.log('WebSocket disconnected'),\n  message: data => console.log('Received:', data)\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n```\n\n### Aggregate Trade Streams\n\nSubscribe to aggregate trade updates:\n\n```javascript\nconst { WebsocketStream } = require('@binance/connector')\n\nconst callbacks = {\n  open: () => console.log('Connected to aggregate trade stream'),\n  close: () => console.log('Disconnected from aggregate trade stream'),\n  message: data => console.log('Trade:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT aggregate trades\nwebsocketStreamClient.aggTrade('btcusdt')\n\n// Unsubscribe\n// websocketStreamClient.unsubscribe('btcusdt@aggTrade')\n\n// Disconnect\n// websocketStreamClient.disconnect()\n```\n\n### Trade Streams\n\nSubscribe to raw trade updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to trade stream'),\n  close: () => console.log('Disconnected from trade stream'),\n  message: data => console.log('Trade:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT trades\nwebsocketStreamClient.trade('btcusdt')\n```\n\n### Kline/Candlestick Streams\n\nSubscribe to candlestick updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to kline stream'),\n  close: () => console.log('Disconnected from kline stream'),\n  message: data => console.log('Kline:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT 1-minute klines\nwebsocketStreamClient.kline('btcusdt', '1m')\n\n// Available intervals: 1s, 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M\n```\n\n### Mini Ticker Streams\n\nSubscribe to 24hr mini ticker updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to mini ticker stream'),\n  close: () => console.log('Disconnected from mini ticker stream'),\n  message: data => console.log('Mini Ticker:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT mini ticker\nwebsocketStreamClient.miniTicker('btcusdt')\n\n// Subscribe to all symbols mini ticker\nwebsocketStreamClient.miniTicker()\n```\n\n### Ticker Streams\n\nSubscribe to 24hr ticker updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to ticker stream'),\n  close: () => console.log('Disconnected from ticker stream'),\n  message: data => console.log('Ticker:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT ticker\nwebsocketStreamClient.ticker('btcusdt')\n\n// Subscribe to all symbols ticker\nwebsocketStreamClient.ticker()\n```\n\n### Individual Symbol Book Ticker Streams\n\nSubscribe to best bid/ask updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to book ticker stream'),\n  close: () => console.log('Disconnected from book ticker stream'),\n  message: data => console.log('Book Ticker:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT book ticker\nwebsocketStreamClient.bookTicker('btcusdt')\n```\n\n### Partial Book Depth Streams\n\nSubscribe to top bids and asks:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to partial depth stream'),\n  close: () => console.log('Disconnected from partial depth stream'),\n  message: data => console.log('Partial Depth:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT top 5 levels @ 1000ms\nwebsocketStreamClient.partialDepth('btcusdt', 5, 1000)\n\n// Available levels: 5, 10, 20\n// Available speeds: 1000ms, 100ms\n```\n\n### Diff Depth Stream\n\nSubscribe to order book price and quantity depth updates:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to diff depth stream'),\n  close: () => console.log('Disconnected from diff depth stream'),\n  message: data => console.log('Diff Depth:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to BTCUSDT depth updates @ 1000ms\nwebsocketStreamClient.diffDepth('btcusdt', 1000)\n\n// Available speeds: 1000ms, 100ms\n```\n\n### Combined Streams\n\nSubscribe to multiple streams with a single connection:\n\n```javascript\nconst callbacks = {\n  open: () => console.log('Connected to combined stream'),\n  close: () => console.log('Disconnected from combined stream'),\n  message: data => console.log('Combined:', JSON.parse(data))\n}\n\nconst websocketStreamClient = new WebsocketStream({ callbacks })\n\n// Subscribe to multiple streams\nwebsocketStreamClient.subscribe([\n  'btcusdt@aggTrade',\n  'btcusdt@depth',\n  'ethusdt@kline_1m',\n  'bnbusdt@ticker'\n])\n```\n\n## WebSocket API\n\nWebSocket API allows bidirectional communication for placing orders, querying data, and more.\n\n### WebSocket API Client\n\nInitialize a WebSocket API client:\n\n```javascript\nconst { WebsocketAPI } = require('@binance/connector')\n\nconst callbacks = {\n  open: (client) => console.log('WebSocket API connected'),\n  close: () => console.log('WebSocket API disconnected'),\n  message: data => console.log('Message:', data)\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n### Ping/Pong\n\nTest connectivity:\n\n```javascript\nconst { WebsocketAPI } = require('@binance/connector')\n\nconst callbacks = {\n  open: (client) => {\n    console.log('WebSocket API connected')\n\n    // Send ping\n    client.ping()\n  },\n  message: data => {\n    console.log('Response:', data)\n  }\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n### Server Time\n\nGet server time:\n\n```javascript\nconst callbacks = {\n  open: (client) => {\n    console.log('WebSocket API connected')\n\n    // Get server time\n    client.time()\n  },\n  message: data => {\n    console.log('Server Time:', data)\n  }\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n### Order Book via WebSocket API\n\nGet order book through WebSocket:\n\n```javascript\nconst callbacks = {\n  open: (client) => {\n    console.log('WebSocket API connected')\n\n    // Get order book\n    client.depth('BTCUSDT', { limit: 10 })\n  },\n  message: data => {\n    console.log('Order Book:', data)\n  }\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n### Place Order via WebSocket API\n\nPlace orders through WebSocket:\n\n```javascript\nconst callbacks = {\n  open: (client) => {\n    console.log('WebSocket API connected')\n\n    // Place market buy order\n    client.newOrder('BTCUSDT', 'BUY', 'MARKET', { quantity: 0.001 })\n  },\n  message: data => {\n    console.log('Order Response:', data)\n  }\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n### Account Information via WebSocket API\n\nGet account information through WebSocket:\n\n```javascript\nconst callbacks = {\n  open: (client) => {\n    console.log('WebSocket API connected')\n\n    // Get account information\n    client.account()\n  },\n  message: data => {\n    console.log('Account Info:', data)\n  }\n}\n\nconst websocketAPIClient = new WebsocketAPI(apiKey, apiSecret, { callbacks })\n```\n\n## User Data Streams\n\nUser Data Streams provide real-time updates about account and order changes.\n\n### Start User Data Stream\n\nCreate a listenKey for user data stream:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\n// Create listen key\nclient.userDataStream()\n  .then(response => {\n    const listenKey = response.data.listenKey\n    console.log('Listen Key:', listenKey)\n\n    // Use this listenKey with WebSocket\n    subscribeToUserDataStream(listenKey)\n  })\n  .catch(error => console.error(error))\n```\n\n### Keep-Alive User Data Stream\n\nExtend the validity of a listenKey:\n\n```javascript\n// Keep alive (extend validity by 60 minutes)\nclient.keepAliveUserDataStream(listenKey)\n  .then(response => console.log('Stream kept alive'))\n  .catch(error => console.error(error))\n```\n\n### Close User Data Stream\n\nClose a user data stream:\n\n```javascript\n// Close stream\nclient.closeUserDataStream(listenKey)\n  .then(response => console.log('Stream closed'))\n  .catch(error => console.error(error))\n```\n\n### Subscribe to User Data Stream\n\nConnect to user data stream via WebSocket:\n\n```javascript\nconst { WebsocketStream } = require('@binance/connector')\n\nfunction subscribeToUserDataStream(listenKey) {\n  const callbacks = {\n    open: () => console.log('Connected to user data stream'),\n    close: () => console.log('Disconnected from user data stream'),\n    message: data => {\n      const event = JSON.parse(data)\n\n      if (event.e === 'executionReport') {\n        console.log('Order Update:', event)\n      } else if (event.e === 'outboundAccountPosition') {\n        console.log('Balance Update:', event)\n      } else if (event.e === 'balanceUpdate') {\n        console.log('Balance Update:', event)\n      }\n    }\n  }\n\n  const websocketStreamClient = new WebsocketStream({ callbacks })\n  websocketStreamClient.userData(listenKey)\n\n  return websocketStreamClient\n}\n```\n\n### Complete User Data Stream Example\n\nFull example with keep-alive:\n\n```javascript\nconst { Spot, WebsocketStream } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\n// Create listen key\nclient.userDataStream()\n  .then(response => {\n    const listenKey = response.data.listenKey\n    console.log('Listen Key:', listenKey)\n\n    // Connect to user data stream\n    const callbacks = {\n      open: () => console.log('Connected to user data stream'),\n      close: () => console.log('Disconnected from user data stream'),\n      message: data => {\n        const event = JSON.parse(data)\n        console.log('User Data Event:', event)\n      }\n    }\n\n    const websocketStreamClient = new WebsocketStream({ callbacks })\n    websocketStreamClient.userData(listenKey)\n\n    // Keep alive every 30 minutes\n    setInterval(() => {\n      client.keepAliveUserDataStream(listenKey)\n        .then(() => console.log('Stream kept alive'))\n        .catch(error => console.error('Keep alive failed:', error))\n    }, 30 * 60 * 1000)\n  })\n  .catch(error => console.error(error))\n```\n\n## Error Handling\n\nProper error handling for API requests:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\nclient.account()\n  .then(response => {\n    console.log('Success:', response.data)\n  })\n  .catch(error => {\n    if (error.response) {\n      // Server responded with error\n      console.error('Error Status:', error.response.status)\n      console.error('Error Code:', error.response.data.code)\n      console.error('Error Message:', error.response.data.msg)\n    } else if (error.request) {\n      // No response received\n      console.error('No response received:', error.request)\n    } else {\n      // Request setup error\n      console.error('Error:', error.message)\n    }\n  })\n```\n\n### Common Error Codes\n\n| Code  | Message                          | Description                              |\n|-------|----------------------------------|------------------------------------------|\n| -1000 | UNKNOWN                          | An unknown error occurred                |\n| -1001 | DISCONNECTED                     | Internal error; unable to process        |\n| -1002 | UNAUTHORIZED                     | Invalid API key or signature             |\n| -1003 | TOO_MANY_REQUESTS                | Too many requests; rate limit exceeded   |\n| -1007 | TIMEOUT                          | Request timeout                          |\n| -1021 | TIMESTAMP_OUTSIDE_RECV_WINDOW    | Timestamp outside recvWindow             |\n| -1022 | INVALID_SIGNATURE                | Invalid signature                        |\n| -1100 | ILLEGAL_CHARS                    | Illegal characters in parameter          |\n| -1101 | TOO_MANY_PARAMETERS              | Too many parameters                      |\n| -1102 | MANDATORY_PARAM_EMPTY_OR_MALFORMED | Mandatory parameter missing/malformed  |\n| -1103 | UNKNOWN_PARAM                    | Unknown parameter                        |\n| -1104 | UNREAD_PARAMETERS                | Not all parameters were read             |\n| -1111 | BAD_PRECISION                    | Precision over maximum defined           |\n| -1112 | NO_DEPTH                         | No orders on book                        |\n| -1114 | TIF_NOT_REQUIRED                 | Time in force not required               |\n| -1115 | INVALID_TIF                      | Invalid time in force                    |\n| -1116 | INVALID_ORDER_TYPE               | Invalid order type                       |\n| -1117 | INVALID_SIDE                     | Invalid side                             |\n| -1118 | EMPTY_NEW_CL_ORD_ID              | New client order ID empty                |\n| -1119 | EMPTY_ORG_CL_ORD_ID              | Original client order ID empty           |\n| -1120 | BAD_INTERVAL                     | Invalid interval                         |\n| -1121 | BAD_SYMBOL                       | Invalid symbol                           |\n| -1125 | INVALID_LISTEN_KEY               | Invalid listen key                       |\n| -1127 | MORE_THAN_XX_HOURS               | Lookup interval too large                |\n| -1128 | OPTIONAL_PARAMS_BAD_COMBO        | Invalid parameter combination            |\n| -1130 | INVALID_PARAMETER                | Invalid parameter                        |\n| -2010 | NEW_ORDER_REJECTED               | Order rejected                           |\n| -2011 | CANCEL_REJECTED                  | Cancel rejected                          |\n| -2013 | NO_SUCH_ORDER                    | Order does not exist                     |\n| -2014 | BAD_API_KEY_FMT                  | API key format invalid                   |\n| -2015 | REJECTED_MBX_KEY                 | API key rejected                         |\n\n## Rate Limits\n\nBinance implements rate limits to prevent API abuse.\n\n### Rate Limit Types\n\n1. **REQUEST_WEIGHT** - Based on the weight of requests\n2. **ORDERS** - Based on the number of orders\n3. **RAW_REQUESTS** - Based on the number of requests\n\n### Rate Limit Headers\n\nResponse headers include rate limit information:\n\n```javascript\nclient.account()\n  .then(response => {\n    console.log('Used Weight:', response.headers['x-mbx-used-weight-1m'])\n    console.log('Order Count:', response.headers['x-mbx-order-count-10s'])\n  })\n  .catch(error => console.error(error))\n```\n\n### Best Practices for Rate Limits\n\n- Use WebSocket streams for real-time data instead of polling REST API\n- Batch requests when possible\n- Monitor rate limit headers\n- Implement exponential backoff for retries\n- Use `recvWindow` parameter appropriately\n\n## Advanced Configuration\n\n### Timestamp Synchronization\n\nConfigure timing window for requests:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret, {\n  recvWindow: 10000 // 10 seconds (default: 5000)\n})\n```\n\n### Custom Logger\n\nUse a custom logger:\n\n```javascript\nconst winston = require('winston')\n\nconst logger = winston.createLogger({\n  level: 'info',\n  format: winston.format.json(),\n  transports: [\n    new winston.transports.File({ filename: 'binance.log' })\n  ]\n})\n\nconst client = new Spot(apiKey, apiSecret, {\n  logger: logger\n})\n```\n\n### Base URL Selection\n\nChoose optimal base URL for your region:\n\n```javascript\n// Default (most stable)\nconst client1 = new Spot(apiKey, apiSecret, {\n  baseURL: 'https://api.binance.com'\n})\n\n// GCP (better for some regions)\nconst client2 = new Spot(apiKey, apiSecret, {\n  baseURL: 'https://api-gcp.binance.com'\n})\n\n// Numbered endpoints (better performance, less stability)\nconst client3 = new Spot(apiKey, apiSecret, {\n  baseURL: 'https://api1.binance.com'\n})\n\n// Market data only\nconst client4 = new Spot('', '', {\n  baseURL: 'https://data-api.binance.vision'\n})\n```\n\n### Async/Await Pattern\n\nUse async/await for cleaner code:\n\n```javascript\nconst { Spot } = require('@binance/connector')\n\nconst client = new Spot(apiKey, apiSecret)\n\nasync function getAccountBalance() {\n  try {\n    const response = await client.account()\n    const balances = response.data.balances.filter(b => parseFloat(b.free) > 0)\n    console.log('Non-zero balances:', balances)\n    return balances\n  } catch (error) {\n    console.error('Error fetching account:', error.response?.data || error.message)\n    throw error\n  }\n}\n\nasync function placeLimitOrder(symbol, side, quantity, price) {\n  try {\n    const response = await client.newOrder(symbol, side, 'LIMIT', {\n      quantity,\n      price,\n      timeInForce: 'GTC'\n    })\n    console.log('Order placed:', response.data)\n    return response.data\n  } catch (error) {\n    console.error('Error placing order:', error.response?.data || error.message)\n    throw error\n  }\n}\n\n// Usage\n(async () => {\n  await getAccountBalance()\n  await placeLimitOrder('BTCUSDT', 'BUY', 0.001, 50000)\n})()\n```\n\n## Useful Links\n\n- Official Documentation: https://developers.binance.com/docs/binance-spot-api-docs\n- REST API Documentation: https://developers.binance.com/docs/binance-spot-api-docs/rest-api\n- WebSocket Streams: https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams\n- WebSocket API: https://developers.binance.com/docs/binance-spot-api-docs/websocket-api\n- GitHub Repository: https://github.com/binance/binance-connector-node\n- API Testnet: https://testnet.binance.vision\n- Get API Key: https://www.binance.com/en/my/settings/api-management\n- API Documentation (Old): https://binance-docs.github.io/apidocs/spot/en/\n"
  },
  {
    "path": "content/binance/docs/trading/python/DOC.md",
    "content": "---\nname: trading\ndescription: \"Binance API Python coding guidelines for trading using official libraries and SDKs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.12.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"binance,trading,crypto,exchange,api\"\n---\n\n# Binance API Python Coding Guidelines\n\nYou are a Binance API coding expert. Help me with writing code using the Binance API calling the official libraries and SDKs.\n\nYou can find the official documentation here:\nhttps://developers.binance.com/docs/binance-spot-api-docs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Binance Connector for Python, which is the standard library for all Binance Spot API interactions. Do not use unofficial or third-party libraries.\n\n- **Library Name:** Binance Connector Python\n- **PyPI Package:** `binance-connector`\n- **Alternative Official Packages:** `binance-sdk-spot` (newer modular package), `binance-futures-connector`, `binance-pay-connector`\n- **Unofficial Libraries:** `python-binance`, `binance.py` (not recommended for production)\n\n**Installation:**\n\n- **Correct:** `pip install binance-connector`\n- **Alternative:** `pip install binance-sdk-spot` (for newer modular approach)\n\n**APIs and Usage:**\n\n- **Correct:** `from binance.spot import Spot`\n- **Correct:** `client = Spot(api_key='...', api_secret='...')`\n- **Correct:** `client.account()` for account information\n- **Correct:** `client.new_order()` for placing orders\n- **Incorrect:** Using unofficial packages like `python-binance`\n- **Incorrect:** Direct HTTP requests without using the connector\n\n## Installation\n\nInstall the official Binance connector for Python:\n\n```bash\npip install binance-connector\n```\n\nFor Python 3.9 or later, you can also use the modular SDK:\n\n```bash\npip install binance-sdk-spot\n```\n\n**Environment Variables:**\n\nSet your API credentials as environment variables:\n\n```bash\nexport BINANCE_API_KEY='your_api_key_here'\nexport BINANCE_API_SECRET='your_api_secret_here'\n```\n\nOr create a `.env` file:\n\n```bash\nBINANCE_API_KEY=your_api_key_here\nBINANCE_API_SECRET=your_api_secret_here\n```\n\nLoad environment variables in Python:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\napi_key = os.getenv('BINANCE_API_KEY')\napi_secret = os.getenv('BINANCE_API_SECRET')\n```\n\n## Initialization\n\nThe `binance-connector` library requires creating a `Spot` instance for all API calls.\n\n### Basic Initialization (Public Endpoints)\n\nFor public market data endpoints that don't require authentication:\n\n```python\nfrom binance.spot import Spot\n\n# Public endpoints only (no authentication)\nclient = Spot()\n\n# Use client for public data\nexchange_info = client.exchange_info()\nprint(exchange_info)\n```\n\n### Authenticated Initialization (HMAC)\n\nFor trading and account endpoints:\n\n```python\nimport os\nfrom binance.spot import Spot\n\napi_key = os.getenv('BINANCE_API_KEY')\napi_secret = os.getenv('BINANCE_API_SECRET')\n\n# Authenticated client with HMAC\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# Use client for authenticated endpoints\naccount_info = client.account()\nprint(account_info)\n```\n\n### RSA/ED25519 Authentication\n\nFor enhanced security using RSA or ED25519 private keys:\n\n```python\nfrom binance.spot import Spot\n\napi_key = os.getenv('BINANCE_API_KEY')\n\n# Read private key from file\nwith open('/path/to/private_key.pem', 'r') as f:\n    private_key = f.read()\n\n# Initialize with RSA key\nclient = Spot(\n    api_key=api_key,\n    private_key=private_key,\n    private_key_pass='your_passphrase'  # Optional\n)\n\n# For ED25519 keys, the connector auto-detects the key type\n```\n\n### Client Configuration Options\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    base_url='https://api.binance.com',  # Default base URL\n    timeout=10,  # Request timeout in seconds\n    proxies=None,  # Proxy configuration\n    show_limit_usage=False,  # Show rate limit usage in response\n    show_header=False  # Include response headers\n)\n```\n\n### Testnet Configuration\n\nFor testing without real funds:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    base_url='https://testnet.binance.vision'\n)\n```\n\n### Proxy Configuration\n\nFor requests through a proxy:\n\n```python\nfrom binance.spot import Spot\n\nproxies = {\n    'http': 'http://username:password@proxy.example.com:8080',\n    'https': 'https://username:password@proxy.example.com:8080'\n}\n\nclient = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    proxies=proxies\n)\n```\n\n### Logging Configuration\n\nEnable logging for debugging:\n\n```python\nimport logging\nfrom binance.spot import Spot\nfrom binance.lib.utils import config_logging\n\n# Configure logging\nconfig_logging(logging, logging.DEBUG)\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# All API calls will now be logged\naccount_info = client.account()\n```\n\n## Market Data Endpoints\n\nMarket data endpoints provide access to public trading information without authentication.\n\n### Exchange Information\n\nGet exchange trading rules and symbol information:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot()\n\n# Get all exchange information\nexchange_info = client.exchange_info()\nprint(exchange_info)\n\n# Get specific symbol information\nexchange_info = client.exchange_info(symbol='BTCUSDT')\nprint(exchange_info)\n\n# Get information for multiple symbols\nexchange_info = client.exchange_info(symbols=['BTCUSDT', 'ETHUSDT'])\nprint(exchange_info)\n```\n\n### Order Book (Depth)\n\nGet current order book for a symbol:\n\n```python\n# Get order book with default limit (100)\ndepth = client.depth('BTCUSDT')\nprint(depth)\n\n# Get order book with specific limit (5, 10, 20, 50, 100, 500, 1000, 5000)\ndepth = client.depth('BTCUSDT', limit=10)\nprint(depth)\n\n# Access bids and asks\nbids = depth['bids']\nasks = depth['asks']\nprint(f\"Best Bid: {bids[0]}\")\nprint(f\"Best Ask: {asks[0]}\")\n```\n\n### Recent Trades\n\nGet recent trades for a symbol:\n\n```python\n# Get recent trades (default limit: 500)\ntrades = client.trades('BTCUSDT')\nprint(trades)\n\n# Get specific number of recent trades\ntrades = client.trades('BTCUSDT', limit=100)\nprint(trades)\n\n# Process trades\nfor trade in trades:\n    print(f\"Price: {trade['price']}, Qty: {trade['qty']}, Time: {trade['time']}\")\n```\n\n### Historical Trades\n\nGet older trades (requires API key):\n\n```python\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# Get historical trades\nhistorical_trades = client.historical_trades('BTCUSDT', limit=100)\nprint(historical_trades)\n\n# Get trades from specific ID\nhistorical_trades = client.historical_trades('BTCUSDT', limit=100, fromId=28457)\nprint(historical_trades)\n```\n\n### Aggregate Trades\n\nGet compressed, aggregate trades:\n\n```python\n# Get recent aggregate trades\nagg_trades = client.agg_trades('BTCUSDT')\nprint(agg_trades)\n\n# Get aggregate trades with time range\nagg_trades = client.agg_trades(\n    'BTCUSDT',\n    startTime=1609459200000,\n    endTime=1609545600000,\n    limit=1000\n)\nprint(agg_trades)\n\n# Get aggregate trades from specific ID\nagg_trades = client.agg_trades('BTCUSDT', fromId=28457, limit=500)\nprint(agg_trades)\n```\n\n### Candlestick Data (Klines)\n\nGet kline/candlestick bars for a symbol:\n\n```python\n# Get recent klines (default limit: 500)\nklines = client.klines('BTCUSDT', '1h')\nprint(klines)\n\n# Get klines with time range\nklines = client.klines(\n    'BTCUSDT',\n    '1d',\n    startTime=1609459200000,\n    endTime=1609545600000,\n    limit=100\n)\nprint(klines)\n\n# Available intervals: 1s, 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M\n\n# Process klines\nfor kline in klines:\n    open_time, open_price, high, low, close, volume, close_time, quote_volume, trades, taker_buy_base, taker_buy_quote, ignore = kline\n    print(f\"Time: {open_time}, Open: {open_price}, High: {high}, Low: {low}, Close: {close}, Volume: {volume}\")\n```\n\n### Klines to Pandas DataFrame\n\nConvert klines to pandas DataFrame for analysis:\n\n```python\nimport pandas as pd\nfrom binance.spot import Spot\n\nclient = Spot()\n\nklines = client.klines('BTCUSDT', '1h', limit=100)\n\n# Convert to DataFrame\ndf = pd.DataFrame(klines, columns=[\n    'open_time', 'open', 'high', 'low', 'close', 'volume',\n    'close_time', 'quote_volume', 'trades', 'taker_buy_base',\n    'taker_buy_quote', 'ignore'\n])\n\n# Convert timestamps to datetime\ndf['open_time'] = pd.to_datetime(df['open_time'], unit='ms')\ndf['close_time'] = pd.to_datetime(df['close_time'], unit='ms')\n\n# Convert price columns to float\nprice_cols = ['open', 'high', 'low', 'close', 'volume']\ndf[price_cols] = df[price_cols].astype(float)\n\nprint(df.head())\n```\n\n### Current Average Price\n\nGet current average price for a symbol:\n\n```python\navg_price = client.avg_price('BTCUSDT')\nprint(avg_price)\n```\n\n### 24hr Ticker Price Change Statistics\n\nGet 24-hour rolling window price change statistics:\n\n```python\n# Get ticker for single symbol\nticker = client.ticker_24hr('BTCUSDT')\nprint(ticker)\n\n# Get ticker for multiple symbols\nticker = client.ticker_24hr(symbols=['BTCUSDT', 'ETHUSDT'])\nprint(ticker)\n\n# Get ticker for all symbols (warning: large response)\nticker = client.ticker_24hr()\nprint(ticker)\n```\n\n### Symbol Price Ticker\n\nGet latest price for a symbol:\n\n```python\n# Get price for single symbol\nprice = client.ticker_price('BTCUSDT')\nprint(price)\n\n# Get price for multiple symbols\nprices = client.ticker_price(symbols=['BTCUSDT', 'ETHUSDT'])\nprint(prices)\n\n# Get price for all symbols\nprices = client.ticker_price()\nprint(prices)\n```\n\n### Symbol Order Book Ticker\n\nGet best price/quantity on the order book:\n\n```python\n# Get book ticker for single symbol\nbook_ticker = client.book_ticker('BTCUSDT')\nprint(book_ticker)\n\n# Get book ticker for multiple symbols\nbook_ticker = client.book_ticker(symbols=['BTCUSDT', 'ETHUSDT'])\nprint(book_ticker)\n\n# Get book ticker for all symbols\nbook_ticker = client.book_ticker()\nprint(book_ticker)\n```\n\n## Trading Endpoints\n\nTrading endpoints require authentication and allow you to place, cancel, and query orders.\n\n### New Order\n\nPlace a new order on the exchange:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# Market buy order\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='MARKET',\n    quantity=0.001\n)\nprint(order)\n\n# Market sell order with quote quantity\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='SELL',\n    type='MARKET',\n    quoteOrderQty=100\n)\nprint(order)\n\n# Limit buy order\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=50000\n)\nprint(order)\n\n# Limit sell order\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='SELL',\n    type='LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=60000\n)\nprint(order)\n\n# Stop-loss order\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='SELL',\n    type='STOP_LOSS_LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=48000,\n    stopPrice=49000\n)\nprint(order)\n\n# Take-profit order\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='SELL',\n    type='TAKE_PROFIT_LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=62000,\n    stopPrice=61000\n)\nprint(order)\n```\n\n**Order Types:**\n- `MARKET` - Market order\n- `LIMIT` - Limit order\n- `STOP_LOSS` - Stop-loss order\n- `STOP_LOSS_LIMIT` - Stop-loss limit order\n- `TAKE_PROFIT` - Take-profit order\n- `TAKE_PROFIT_LIMIT` - Take-profit limit order\n- `LIMIT_MAKER` - Limit maker order\n\n**Time in Force:**\n- `GTC` - Good Till Cancel\n- `IOC` - Immediate or Cancel\n- `FOK` - Fill or Kill\n\n### Test New Order\n\nTest order placement without actually placing the order:\n\n```python\n# Test a limit order\ntest_order = client.new_order_test(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=50000\n)\nprint(test_order)\n```\n\n### Query Order\n\nCheck an order's status:\n\n```python\n# Query by orderId\norder = client.get_order('BTCUSDT', orderId=28)\nprint(order)\n\n# Query by origClientOrderId\norder = client.get_order('BTCUSDT', origClientOrderId='myOrder1')\nprint(order)\n```\n\n### Cancel Order\n\nCancel an active order:\n\n```python\n# Cancel by orderId\ncancel_result = client.cancel_order('BTCUSDT', orderId=28)\nprint(cancel_result)\n\n# Cancel by origClientOrderId\ncancel_result = client.cancel_order('BTCUSDT', origClientOrderId='myOrder1')\nprint(cancel_result)\n```\n\n### Cancel All Open Orders\n\nCancel all active orders on a symbol:\n\n```python\ncancel_results = client.cancel_open_orders('BTCUSDT')\nprint(cancel_results)\n```\n\n### Cancel and Replace Order\n\nCancel an existing order and place a new order on the same symbol:\n\n```python\n# Cancel and replace by orderId\nresult = client.cancel_replace(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='LIMIT',\n    cancelReplaceMode='STOP_ON_FAILURE',\n    timeInForce='GTC',\n    cancelOrderId=28,\n    quantity=0.002,\n    price=51000\n)\nprint(result)\n```\n\n### Current Open Orders\n\nGet all open orders on a symbol:\n\n```python\n# Get open orders for specific symbol\nopen_orders = client.get_open_orders('BTCUSDT')\nprint(open_orders)\n\n# Get all open orders\nopen_orders = client.get_open_orders()\nprint(open_orders)\n```\n\n### All Orders\n\nGet all account orders (active, canceled, or filled):\n\n```python\n# Get all orders for a symbol\nall_orders = client.get_orders('BTCUSDT')\nprint(all_orders)\n\n# Get orders with time range\nall_orders = client.get_orders(\n    'BTCUSDT',\n    startTime=1609459200000,\n    endTime=1609545600000,\n    limit=500\n)\nprint(all_orders)\n\n# Get orders from specific orderId\nall_orders = client.get_orders('BTCUSDT', orderId=28, limit=500)\nprint(all_orders)\n```\n\n### OCO Orders (One-Cancels-the-Other)\n\nPlace a pair of orders where if one is executed, the other is canceled:\n\n```python\n# Place OCO order\noco_order = client.new_oco_order(\n    symbol='BTCUSDT',\n    side='SELL',\n    quantity=0.001,\n    price=62000,\n    stopPrice=48000,\n    stopLimitPrice=47500,\n    stopLimitTimeInForce='GTC'\n)\nprint(oco_order)\n\n# Cancel OCO order\ncancel_result = client.cancel_oco_order('BTCUSDT', orderListId=0)\nprint(cancel_result)\n\n# Query OCO order\noco_order = client.get_oco_order(orderListId=0)\nprint(oco_order)\n\n# Get all OCO orders\noco_orders = client.get_oco_orders()\nprint(oco_orders)\n\n# Get open OCO orders\nopen_oco_orders = client.get_open_oco_orders()\nprint(open_oco_orders)\n```\n\n## Account Endpoints\n\nAccount endpoints provide access to account information and require authentication.\n\n### Account Information\n\nGet current account information:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\naccount = client.account()\nprint(f\"Account Type: {account['accountType']}\")\nprint(f\"Can Trade: {account['canTrade']}\")\nprint(f\"Can Withdraw: {account['canWithdraw']}\")\nprint(f\"Can Deposit: {account['canDeposit']}\")\n\n# Get non-zero balances\nbalances = [b for b in account['balances'] if float(b['free']) > 0 or float(b['locked']) > 0]\nprint(f\"Non-zero Balances: {balances}\")\n```\n\n### Account Trade List\n\nGet trades for a specific symbol:\n\n```python\n# Get recent trades\ntrades = client.my_trades('BTCUSDT')\nprint(trades)\n\n# Get trades with time range\ntrades = client.my_trades(\n    'BTCUSDT',\n    startTime=1609459200000,\n    endTime=1609545600000,\n    limit=500\n)\nprint(trades)\n\n# Get trades from specific ID\ntrades = client.my_trades('BTCUSDT', fromId=28457, limit=500)\nprint(trades)\n\n# Calculate total trading volume\ntotal_volume = sum(float(trade['qty']) for trade in trades)\nprint(f\"Total Volume: {total_volume}\")\n```\n\n### Current Order Count Usage\n\nGet current order count usage for rate limits:\n\n```python\nrate_limit = client.rate_limit_order()\nprint(rate_limit)\n```\n\n### Query Prevented Matches\n\nGet prevented matches from Self-Trade Prevention:\n\n```python\nprevented_matches = client.prevented_matches('BTCUSDT')\nprint(prevented_matches)\n```\n\n## WebSocket Streams\n\nWebSocket streams provide real-time market data with low latency.\n\n### WebSocket Stream Client\n\nInitialize a WebSocket stream client:\n\n```python\nfrom binance.websocket.spot.websocket_stream import SpotWebsocketStreamClient\n\ndef message_handler(_, message):\n    print(f\"Received message: {message}\")\n\n# Create WebSocket stream client\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Start the client\nws_client.start()\n\n# Subscribe to streams (examples below)\n```\n\n### Aggregate Trade Streams\n\nSubscribe to aggregate trade updates:\n\n```python\nfrom binance.websocket.spot.websocket_stream import SpotWebsocketStreamClient\n\ndef message_handler(_, message):\n    print(f\"Aggregate Trade: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT aggregate trades\nws_client.agg_trade(symbol='btcusdt')\n\n# Keep the connection alive\nimport time\ntime.sleep(60)\n\n# Stop the client\nws_client.stop()\n```\n\n### Trade Streams\n\nSubscribe to raw trade updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Trade: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT trades\nws_client.trade(symbol='btcusdt')\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Kline/Candlestick Streams\n\nSubscribe to candlestick updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Kline: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT 1-minute klines\nws_client.kline(symbol='btcusdt', interval='1m')\n\n# Available intervals: 1s, 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Mini Ticker Streams\n\nSubscribe to 24hr mini ticker updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Mini Ticker: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT mini ticker\nws_client.mini_ticker(symbol='btcusdt')\n\n# Subscribe to all symbols mini ticker\nws_client.mini_ticker()\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Ticker Streams\n\nSubscribe to 24hr ticker updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Ticker: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT ticker\nws_client.ticker(symbol='btcusdt')\n\n# Subscribe to all symbols ticker\nws_client.ticker()\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Individual Symbol Book Ticker Streams\n\nSubscribe to best bid/ask updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Book Ticker: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT book ticker\nws_client.book_ticker(symbol='btcusdt')\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Partial Book Depth Streams\n\nSubscribe to top bids and asks:\n\n```python\ndef message_handler(_, message):\n    print(f\"Partial Depth: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT top 5 levels @ 1000ms\nws_client.partial_depth(symbol='btcusdt', level=5, speed=1000)\n\n# Available levels: 5, 10, 20\n# Available speeds: 1000ms, 100ms\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Diff Depth Stream\n\nSubscribe to order book price and quantity depth updates:\n\n```python\ndef message_handler(_, message):\n    print(f\"Diff Depth: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to BTCUSDT depth updates @ 1000ms\nws_client.diff_depth(symbol='btcusdt', speed=1000)\n\n# Available speeds: 1000ms, 100ms\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n### Multiple Streams\n\nSubscribe to multiple streams with a single connection:\n\n```python\ndef message_handler(_, message):\n    print(f\"Message: {message}\")\n\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\n\n# Subscribe to multiple streams\nws_client.agg_trade(symbol='btcusdt')\nws_client.trade(symbol='ethusdt')\nws_client.kline(symbol='bnbusdt', interval='1m')\nws_client.ticker(symbol='adausdt')\n\nimport time\ntime.sleep(60)\n\nws_client.stop()\n```\n\n## WebSocket API\n\nWebSocket API allows bidirectional communication for placing orders, querying data, and more.\n\n### WebSocket API Client\n\nInitialize a WebSocket API client:\n\n```python\nfrom binance.websocket.spot.websocket_api import SpotWebsocketAPIClient\n\ndef message_handler(_, message):\n    print(f\"Message: {message}\")\n\n# Create WebSocket API client\nws_client = SpotWebsocketAPIClient(\n    api_key=api_key,\n    api_secret=api_secret,\n    on_message=message_handler\n)\n\n# The client automatically connects\n```\n\n### Ping/Pong\n\nTest connectivity:\n\n```python\nfrom binance.websocket.spot.websocket_api import SpotWebsocketAPIClient\n\ndef message_handler(_, message):\n    print(f\"Response: {message}\")\n\nws_client = SpotWebsocketAPIClient(on_message=message_handler)\n\n# Send ping\nws_client.ping()\n\nimport time\ntime.sleep(2)\n\nws_client.stop()\n```\n\n### Server Time\n\nGet server time:\n\n```python\ndef message_handler(_, message):\n    print(f\"Server Time: {message}\")\n\nws_client = SpotWebsocketAPIClient(on_message=message_handler)\n\n# Get server time\nws_client.time()\n\nimport time\ntime.sleep(2)\n\nws_client.stop()\n```\n\n### Order Book via WebSocket API\n\nGet order book through WebSocket:\n\n```python\ndef message_handler(_, message):\n    print(f\"Order Book: {message}\")\n\nws_client = SpotWebsocketAPIClient(on_message=message_handler)\n\n# Get order book\nws_client.depth(symbol='BTCUSDT', limit=10)\n\nimport time\ntime.sleep(2)\n\nws_client.stop()\n```\n\n### Place Order via WebSocket API\n\nPlace orders through WebSocket:\n\n```python\ndef message_handler(_, message):\n    print(f\"Order Response: {message}\")\n\nws_client = SpotWebsocketAPIClient(\n    api_key=api_key,\n    api_secret=api_secret,\n    on_message=message_handler\n)\n\n# Place market buy order\nws_client.new_order(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='MARKET',\n    quantity=0.001\n)\n\nimport time\ntime.sleep(2)\n\nws_client.stop()\n```\n\n### Account Information via WebSocket API\n\nGet account information through WebSocket:\n\n```python\ndef message_handler(_, message):\n    print(f\"Account Info: {message}\")\n\nws_client = SpotWebsocketAPIClient(\n    api_key=api_key,\n    api_secret=api_secret,\n    on_message=message_handler\n)\n\n# Get account information\nws_client.account_status()\n\nimport time\ntime.sleep(2)\n\nws_client.stop()\n```\n\n## User Data Streams\n\nUser Data Streams provide real-time updates about account and order changes.\n\n### Start User Data Stream\n\nCreate a listenKey for user data stream:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# Create listen key\nresponse = client.user_data_stream()\nlisten_key = response['listenKey']\nprint(f\"Listen Key: {listen_key}\")\n\n# Use this listenKey with WebSocket\n```\n\n### Keep-Alive User Data Stream\n\nExtend the validity of a listenKey:\n\n```python\n# Keep alive (extend validity by 60 minutes)\nclient.renew_user_data_stream(listenKey=listen_key)\nprint(\"Stream kept alive\")\n```\n\n### Close User Data Stream\n\nClose a user data stream:\n\n```python\n# Close stream\nclient.close_user_data_stream(listenKey=listen_key)\nprint(\"Stream closed\")\n```\n\n### Subscribe to User Data Stream\n\nConnect to user data stream via WebSocket:\n\n```python\nfrom binance.spot import Spot\nfrom binance.websocket.spot.websocket_stream import SpotWebsocketStreamClient\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\n# Create listen key\nresponse = client.user_data_stream()\nlisten_key = response['listenKey']\n\ndef message_handler(_, message):\n    import json\n    event = json.loads(message)\n\n    if event['e'] == 'executionReport':\n        print(f\"Order Update: {event}\")\n    elif event['e'] == 'outboundAccountPosition':\n        print(f\"Balance Update: {event}\")\n    elif event['e'] == 'balanceUpdate':\n        print(f\"Balance Update: {event}\")\n\n# Connect to user data stream\nws_client = SpotWebsocketStreamClient(on_message=message_handler)\nws_client.user_data(listen_key=listen_key)\n\n# Keep stream alive\nimport time\nimport threading\n\ndef keep_alive():\n    while True:\n        time.sleep(30 * 60)  # 30 minutes\n        try:\n            client.renew_user_data_stream(listenKey=listen_key)\n            print(\"Stream kept alive\")\n        except Exception as e:\n            print(f\"Keep alive failed: {e}\")\n\n# Start keep-alive thread\nkeep_alive_thread = threading.Thread(target=keep_alive, daemon=True)\nkeep_alive_thread.start()\n\n# Keep running\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    ws_client.stop()\n    client.close_user_data_stream(listenKey=listen_key)\n```\n\n## Error Handling\n\nProper error handling for API requests:\n\n```python\nfrom binance.spot import Spot\nfrom binance.error import ClientError, ServerError\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\ntry:\n    account = client.account()\n    print(f\"Success: {account}\")\nexcept ClientError as error:\n    # Handle client errors (4xx status codes)\n    print(f\"Client Error - Status: {error.status_code}, Code: {error.error_code}, Message: {error.error_message}\")\nexcept ServerError as error:\n    # Handle server errors (5xx status codes)\n    print(f\"Server Error - Status: {error.status_code}, Message: {error.error_message}\")\nexcept Exception as error:\n    # Handle other errors\n    print(f\"Error: {error}\")\n```\n\n### Common Error Codes\n\n| Code  | Message                          | Description                              |\n|-------|----------------------------------|------------------------------------------|\n| -1000 | UNKNOWN                          | An unknown error occurred                |\n| -1001 | DISCONNECTED                     | Internal error; unable to process        |\n| -1002 | UNAUTHORIZED                     | Invalid API key or signature             |\n| -1003 | TOO_MANY_REQUESTS                | Too many requests; rate limit exceeded   |\n| -1007 | TIMEOUT                          | Request timeout                          |\n| -1021 | TIMESTAMP_OUTSIDE_RECV_WINDOW    | Timestamp outside recvWindow             |\n| -1022 | INVALID_SIGNATURE                | Invalid signature                        |\n| -1100 | ILLEGAL_CHARS                    | Illegal characters in parameter          |\n| -1101 | TOO_MANY_PARAMETERS              | Too many parameters                      |\n| -1102 | MANDATORY_PARAM_EMPTY_OR_MALFORMED | Mandatory parameter missing/malformed  |\n| -1103 | UNKNOWN_PARAM                    | Unknown parameter                        |\n| -1104 | UNREAD_PARAMETERS                | Not all parameters were read             |\n| -1111 | BAD_PRECISION                    | Precision over maximum defined           |\n| -1112 | NO_DEPTH                         | No orders on book                        |\n| -1114 | TIF_NOT_REQUIRED                 | Time in force not required               |\n| -1115 | INVALID_TIF                      | Invalid time in force                    |\n| -1116 | INVALID_ORDER_TYPE               | Invalid order type                       |\n| -1117 | INVALID_SIDE                     | Invalid side                             |\n| -1118 | EMPTY_NEW_CL_ORD_ID              | New client order ID empty                |\n| -1119 | EMPTY_ORG_CL_ORD_ID              | Original client order ID empty           |\n| -1120 | BAD_INTERVAL                     | Invalid interval                         |\n| -1121 | BAD_SYMBOL                       | Invalid symbol                           |\n| -1125 | INVALID_LISTEN_KEY               | Invalid listen key                       |\n| -1127 | MORE_THAN_XX_HOURS               | Lookup interval too large                |\n| -1128 | OPTIONAL_PARAMS_BAD_COMBO        | Invalid parameter combination            |\n| -1130 | INVALID_PARAMETER                | Invalid parameter                        |\n| -2010 | NEW_ORDER_REJECTED               | Order rejected                           |\n| -2011 | CANCEL_REJECTED                  | Cancel rejected                          |\n| -2013 | NO_SUCH_ORDER                    | Order does not exist                     |\n| -2014 | BAD_API_KEY_FMT                  | API key format invalid                   |\n| -2015 | REJECTED_MBX_KEY                 | API key rejected                         |\n\n## Rate Limits\n\nBinance implements rate limits to prevent API abuse.\n\n### Rate Limit Types\n\n1. **REQUEST_WEIGHT** - Based on the weight of requests\n2. **ORDERS** - Based on the number of orders\n3. **RAW_REQUESTS** - Based on the number of requests\n\n### Rate Limit Headers\n\nEnable rate limit headers in client configuration:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    show_limit_usage=True,\n    show_header=True\n)\n\nresponse = client.account()\n\n# Access headers\nprint(f\"Used Weight: {response.get('x-mbx-used-weight-1m')}\")\nprint(f\"Order Count: {response.get('x-mbx-order-count-10s')}\")\n```\n\n### Best Practices for Rate Limits\n\n- Use WebSocket streams for real-time data instead of polling REST API\n- Batch requests when possible\n- Monitor rate limit headers\n- Implement exponential backoff for retries\n- Use `recvWindow` parameter appropriately\n\n## Advanced Configuration\n\n### Timestamp Synchronization\n\nConfigure timing window for requests:\n\n```python\nfrom binance.spot import Spot\n\nclient = Spot(\n    api_key=api_key,\n    api_secret=api_secret\n)\n\n# Manually set recvWindow for specific request\naccount = client.account(recvWindow=10000)  # 10 seconds\n```\n\n### Custom Request Parameters\n\nPass additional parameters to requests:\n\n```python\n# Pass custom client order ID\norder = client.new_order(\n    symbol='BTCUSDT',\n    side='BUY',\n    type='LIMIT',\n    timeInForce='GTC',\n    quantity=0.001,\n    price=50000,\n    newClientOrderId='my_custom_order_id_123'\n)\n```\n\n### Base URL Selection\n\nChoose optimal base URL for your region:\n\n```python\n# Default (most stable)\nclient1 = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    base_url='https://api.binance.com'\n)\n\n# GCP (better for some regions)\nclient2 = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    base_url='https://api-gcp.binance.com'\n)\n\n# Numbered endpoints (better performance, less stability)\nclient3 = Spot(\n    api_key=api_key,\n    api_secret=api_secret,\n    base_url='https://api1.binance.com'\n)\n\n# Market data only\nclient4 = Spot(base_url='https://data-api.binance.vision')\n```\n\n### Complete Trading Bot Example\n\nFull example of a simple trading bot:\n\n```python\nimport os\nimport time\nimport logging\nfrom binance.spot import Spot\nfrom binance.error import ClientError, ServerError\nfrom binance.lib.utils import config_logging\n\n# Configure logging\nconfig_logging(logging, logging.INFO)\n\n# Initialize client\napi_key = os.getenv('BINANCE_API_KEY')\napi_secret = os.getenv('BINANCE_API_SECRET')\n\nclient = Spot(api_key=api_key, api_secret=api_secret)\n\ndef get_account_balance(asset='USDT'):\n    \"\"\"Get balance for specific asset\"\"\"\n    try:\n        account = client.account()\n        for balance in account['balances']:\n            if balance['asset'] == asset:\n                return float(balance['free'])\n        return 0.0\n    except (ClientError, ServerError) as error:\n        logging.error(f\"Error getting balance: {error}\")\n        return 0.0\n\ndef get_current_price(symbol='BTCUSDT'):\n    \"\"\"Get current price for symbol\"\"\"\n    try:\n        ticker = client.ticker_price(symbol=symbol)\n        return float(ticker['price'])\n    except (ClientError, ServerError) as error:\n        logging.error(f\"Error getting price: {error}\")\n        return 0.0\n\ndef place_market_order(symbol, side, quantity):\n    \"\"\"Place market order\"\"\"\n    try:\n        order = client.new_order(\n            symbol=symbol,\n            side=side,\n            type='MARKET',\n            quantity=quantity\n        )\n        logging.info(f\"Order placed: {order}\")\n        return order\n    except ClientError as error:\n        logging.error(f\"Order failed: {error.error_message}\")\n        return None\n\ndef place_limit_order(symbol, side, quantity, price):\n    \"\"\"Place limit order\"\"\"\n    try:\n        order = client.new_order(\n            symbol=symbol,\n            side=side,\n            type='LIMIT',\n            timeInForce='GTC',\n            quantity=quantity,\n            price=price\n        )\n        logging.info(f\"Limit order placed: {order}\")\n        return order\n    except ClientError as error:\n        logging.error(f\"Order failed: {error.error_message}\")\n        return None\n\ndef main():\n    \"\"\"Main trading logic\"\"\"\n    symbol = 'BTCUSDT'\n\n    # Get account balance\n    usdt_balance = get_account_balance('USDT')\n    logging.info(f\"USDT Balance: {usdt_balance}\")\n\n    # Get current price\n    current_price = get_current_price(symbol)\n    logging.info(f\"Current BTC Price: {current_price}\")\n\n    # Example: Place limit buy order\n    if usdt_balance > 10:\n        buy_price = current_price * 0.99  # 1% below current price\n        quantity = 0.001\n        place_limit_order(symbol, 'BUY', quantity, buy_price)\n\nif __name__ == '__main__':\n    main()\n```\n\n## Useful Links\n\n- Official Documentation: https://developers.binance.com/docs/binance-spot-api-docs\n- REST API Documentation: https://developers.binance.com/docs/binance-spot-api-docs/rest-api\n- WebSocket Streams: https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams\n- WebSocket API: https://developers.binance.com/docs/binance-spot-api-docs/websocket-api\n- GitHub Repository: https://github.com/binance/binance-connector-python\n- PyPI Package: https://pypi.org/project/binance-connector/\n- API Testnet: https://testnet.binance.vision\n- Get API Key: https://www.binance.com/en/my/settings/api-management\n- API Documentation (Old): https://binance-docs.github.io/apidocs/spot/en/\n"
  },
  {
    "path": "content/bitsandbytes/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"bitsandbytes Python package for k-bit quantization, 8-bit optimizers, and low-memory PyTorch/Transformers workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.49.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bitsandbytes,quantization,pytorch,transformers,llm,qlora,optimizers\"\n---\n\n# bitsandbytes Python Package Guide\n\n## Golden Rule\n\nUse `bitsandbytes` only with a supported PyTorch and hardware stack, and treat backend compatibility as part of setup. For Hugging Face model loading, prefer `transformers.BitsAndBytesConfig`; for custom PyTorch modules and optimizers, use `bitsandbytes.nn` and `bitsandbytes.optim` directly.\n\n## What It Is For\n\n`bitsandbytes` is a PyTorch-focused low-precision toolkit with three main capabilities:\n\n- 8-bit optimizers to reduce optimizer-state memory usage during training\n- LLM.int8() layers for 8-bit inference with mixed-precision handling for outliers\n- 4-bit quantization primitives used in QLoRA-style finetuning and low-memory model loading\n\nThe package is usually used in one of two ways:\n\n1. Via `transformers`, `accelerate`, or `peft` integration for model loading and finetuning\n2. Directly from `bitsandbytes.nn` and `bitsandbytes.optim` inside custom PyTorch code\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"bitsandbytes==0.49.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"bitsandbytes==0.49.2\"\npoetry add \"bitsandbytes==0.49.2\"\n```\n\nBasic verification:\n\n```bash\npython - <<'PY'\nfrom importlib.metadata import version\nimport torch\nimport bitsandbytes as bnb\n\nprint(\"bitsandbytes\", version(\"bitsandbytes\"))\nprint(\"torch\", torch.__version__)\nprint(\"cuda_available\", torch.cuda.is_available())\nprint(\"mps_available\", torch.backends.mps.is_available() if hasattr(torch.backends, \"mps\") else False)\nprint(\"import_ok\", bnb is not None)\nPY\n```\n\n## Platform And Runtime Expectations\n\nOfficial docs for `0.49.2` list these minimums:\n\n- Python `>=3.10`\n- PyTorch `>=2.3`\n\nOfficially supported compute targets in the install guide:\n\n- NVIDIA CUDA\n- CPU\n- Intel XPU\n- Intel Gaudi\n\nExperimental or preview support:\n\n- AMD ROCm\n- Apple Silicon CPU\n\nImportant platform notes:\n\n- On NVIDIA, `LLM.int8()` needs compute capability `7.5+`.\n- On NVIDIA, 8-bit optimizers and NF4/FP4 quantization need compute capability `6.0+`.\n- Linux wheels require `glibc >= 2.24`.\n- Apple Silicon CPU is listed, but `mps` is not supported.\n- If your CUDA or platform combination is unusual, upstream recommends compiling from source.\n\n## Configuration\n\nThere is no service auth layer. Configuration is about runtime, device placement, and dtypes.\n\nSettings that matter most in practice:\n\n- the installed PyTorch build and its CUDA/XPU backend\n- whether the host hardware is actually supported by the selected quantization mode\n- compute dtype for 4-bit workflows, especially `torch.bfloat16` on supported hardware\n- CUDA library paths when native kernels fail to load\n\nFor 4-bit Transformers workflows, upstream recommends `bfloat16` compute when the hardware supports it because it is usually a better tradeoff than `float32` or `float16`.\n\n## Core Usage\n\n### Load a Transformers model in 4-bit\n\nThis is the most common application-level entry point:\n\n```python\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig\n\nmodel_id = \"bigscience/bloom-1b7\"\n\nquantization_config = BitsAndBytesConfig(\n    load_in_4bit=True,\n    bnb_4bit_compute_dtype=torch.bfloat16,\n    bnb_4bit_use_double_quant=True,\n    bnb_4bit_quant_type=\"nf4\",\n)\n\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nmodel = AutoModelForCausalLM.from_pretrained(\n    model_id,\n    device_map=\"auto\",\n    quantization_config=quantization_config,\n)\n```\n\nUse this path when your task is \"load an LLM with lower memory use\" rather than \"manually rewrite linear layers\".\n\n### Load a Transformers model in 8-bit\n\n```python\nfrom transformers import AutoModelForCausalLM, BitsAndBytesConfig\n\nquantization_config = BitsAndBytesConfig(load_in_8bit=True)\n\nmodel = AutoModelForCausalLM.from_pretrained(\n    \"bigscience/bloom-1b7\",\n    device_map=\"auto\",\n    quantization_config=quantization_config,\n)\n```\n\n### Replace linear layers directly in PyTorch\n\nUse `bitsandbytes.nn` when you control the model definition yourself.\n\n`Linear8bitLt` example:\n\n```python\nimport torch\nimport torch.nn as nn\nimport bitsandbytes as bnb\n\nfp16_model = nn.Sequential(\n    nn.Linear(64, 64),\n    nn.Linear(64, 64),\n).half()\n\nint8_model = nn.Sequential(\n    bnb.nn.Linear8bitLt(64, 64, has_fp16_weights=False),\n    bnb.nn.Linear8bitLt(64, 64, has_fp16_weights=False),\n)\n\nint8_model.load_state_dict(fp16_model.state_dict())\nint8_model = int8_model.to(\"cuda\")\n```\n\n`Linear4bit` example:\n\n```python\nimport torch\nimport torch.nn as nn\nimport bitsandbytes as bnb\n\nfp16_model = nn.Sequential(\n    nn.Linear(64, 64),\n    nn.Linear(64, 64),\n).half()\n\nquantized_model = nn.Sequential(\n    bnb.nn.Linear4bit(64, 64, quant_type=\"nf4\", compute_dtype=torch.bfloat16),\n    bnb.nn.Linear4bit(64, 64, quant_type=\"nf4\", compute_dtype=torch.bfloat16),\n)\n\nquantized_model.load_state_dict(fp16_model.state_dict())\nquantized_model = quantized_model.to(\"cuda\")\n```\n\nImportant behavior:\n\n- For both `Linear8bitLt` and `Linear4bit`, quantization happens when the module is moved to the target device after the original fp16 or bf16 weights are loaded.\n- `Linear8bitLt(has_fp16_weights=True)` keeps weights in fp16 and quantizes on the fly during forward passes.\n- `Linear8bitLt(has_fp16_weights=False)` stores quantized weights after device transfer.\n\n### Use 8-bit optimizers\n\nFor training code that is already otherwise conventional PyTorch:\n\n```python\nimport bitsandbytes as bnb\n\noptimizer = bnb.optim.AdamW8bit(\n    model.parameters(),\n    lr=2e-4,\n    weight_decay=0.01,\n)\n```\n\nUseful parameters from the optimizer reference:\n\n- `min_8bit_size=4096` by default, so very small parameter tensors stay out of 8-bit optimization\n- `percentile_clipping` can improve stability for difficult training runs\n- `block_wise=True` is the default and helps reduce outlier effects\n\nIf you need mixed optimizer behavior for specific layers, use `GlobalOptimManager`:\n\n```python\nimport bitsandbytes as bnb\n\nmng = bnb.optim.GlobalOptimManager.get_instance()\nmng.register_parameters(model.parameters())\nmodel = model.cuda()\n\noptimizer = bnb.optim.Adam(model.parameters(), lr=1e-3, optim_bits=8)\nmng.override_config(model.fc1.weight, \"optim_bits\", 32)\n```\n\n## Integration Notes\n\n`bitsandbytes` is heavily used through other libraries rather than by itself:\n\n- `transformers`: `BitsAndBytesConfig` for 4-bit and 8-bit model loading\n- `peft`: `prepare_model_for_kbit_training()` plus LoRA/QLoRA adapters\n- `accelerate`: `BnbQuantizationConfig` with `load_and_quantize_model()`\n\nPrefer those integration layers when the task is model loading, trainer setup, or QLoRA finetuning. Drop down to raw `bitsandbytes` APIs when you need custom layers, custom optimizers, or lower-level debugging.\n\n## Common Pitfalls\n\n- Installing the package is not enough; unsupported hardware or a mismatched PyTorch backend will still fail at runtime.\n- `LLM.int8()` has stricter NVIDIA requirements than 4-bit quantization and 8-bit optimizers.\n- `Linear4bit` and `Linear8bitLt` do not quantize immediately at construction time; the weight conversion happens after loading fp16 or bf16 weights and moving the module to the target device.\n- Apple Silicon users should not assume `mps` support just because macOS appears in package metadata. The current docs list Apple CPU support, but not MPS.\n- If you see `No kernel image available` or `fatbinwrap`, check `PATH`, `LD_LIBRARY_PATH`, `CUDA_HOME`, and the CUDA runtime that your PyTorch build expects before recompiling.\n- The docs quickstart page is still incomplete in `v0.49.2`; rely on the installation, integrations, and API reference pages for concrete examples.\n\n## Troubleshooting Checklist\n\n1. Confirm the installed versions of `bitsandbytes` and `torch`.\n2. Confirm the hardware backend you are actually using: CUDA, CPU, XPU, or Gaudi.\n3. On NVIDIA, confirm the GPU compute capability is high enough for the feature you want.\n4. If CUDA kernels fail to load, inspect `PATH`, `LD_LIBRARY_PATH`, and `CUDA_HOME` for mixed CUDA installs.\n5. If your setup is outside the prebuilt wheel matrix, switch to a source build instead of fighting the wrong wheel.\n\n## Version-Sensitive Notes For 0.49.2\n\n- PyPI lists `0.49.2` as the latest release on February 16, 2026.\n- The Hugging Face docs version selector includes `v0.49.2`, so the docs root and API reference can be read against the same release line.\n- The current docs state official support for NVIDIA GPU, CPU, Intel XPU, and Intel Gaudi, with AMD ROCm and Apple Silicon still not in the same support tier.\n- The package metadata classifies the project as beta, so agents should expect hardware support and wheel coverage to evolve more quickly than typical pure-Python packages.\n\n## Official Sources\n\n- Docs root: `https://huggingface.co/docs/bitsandbytes/en/index`\n- Installation guide: `https://huggingface.co/docs/bitsandbytes/en/installation`\n- Integrations guide: `https://huggingface.co/docs/bitsandbytes/en/integrations`\n- LLM.int8() reference: `https://huggingface.co/docs/bitsandbytes/en/reference/nn/linear8bit`\n- 4-bit quantization reference: `https://huggingface.co/docs/bitsandbytes/en/reference/nn/linear4bit`\n- Optimizer overview: `https://huggingface.co/docs/bitsandbytes/en/reference/optim/optim_overview`\n- Troubleshooting: `https://huggingface.co/docs/bitsandbytes/en/errors`\n- PyPI: `https://pypi.org/project/bitsandbytes/`\n"
  },
  {
    "path": "content/black/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Black Python formatter guide for install, pyproject.toml configuration, CLI usage, and pre-commit integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"26.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"black,python,formatter,code-style,pre-commit,pyproject\"\n---\n\n# Black Python Package Guide\n\n## Golden Rule\n\nUse `black` as an opinionated formatter, not as a style linter you tune line by line. Put the configuration in `pyproject.toml`, run it from the CLI or `pre-commit`, and let Black own formatting decisions. Black's stable style changes are intentionally limited; larger formatting changes are behind `--preview` or annual stable-style updates.\n\n## Install\n\nPin the exact version if your project or formatter checks depend on stable output:\n\n```bash\npython -m pip install \"black==26.3.0\"\n```\n\nInstall notebook support when you need to format `.ipynb` files:\n\n```bash\npython -m pip install \"black[jupyter]==26.3.0\"\n```\n\nIf you want the latest compatible patch in the same monthly line instead of the exact version used here:\n\n```bash\npython -m pip install \"black~=26.3\"\n```\n\n## Initialize And Configure\n\nBlack does not need API keys, credentials, or service setup. The only real setup step is project configuration.\n\nCreate `pyproject.toml` at the repository root:\n\n```toml\n[tool.black]\nline-length = 88\ntarget-version = [\"py311\", \"py312\"]\ninclude = '\\.pyi?$'\nextend-exclude = '''\n/(\n  migrations\n  | build\n  | dist\n)/\n'''\nrequired-version = \"26.3.0\"\n```\n\nImportant config behavior:\n\n- Black looks for `pyproject.toml` starting from the common base directory of the files you pass.\n- It uses one configuration file per run.\n- The search stops at the first `pyproject.toml`, a `.git` or `.hg` directory, or the filesystem root.\n- CLI option names map directly to config keys in `[tool.black]` using the long flag name without leading dashes.\n\n## Core Usage\n\nFormat one file:\n\n```bash\nblack app.py\n```\n\nFormat common project paths:\n\n```bash\nblack src tests\n```\n\nCheck formatting in CI without rewriting files:\n\n```bash\nblack --check --diff .\n```\n\nRead from standard input:\n\n```bash\npython -m black -\n```\n\nFormat a notebook explicitly:\n\n```bash\nblack --ipynb notebook.ipynb\n```\n\nUseful flags agents commonly need:\n\n- `--check`: fail instead of rewriting files\n- `--diff`: print the diff that would be applied\n- `--line-length <n>`: override the default `88`\n- `--target-version py312`: constrain formatting to a Python syntax target\n- `--required-version <version>`: fail when the installed Black version does not match expectations\n- `--preview`: opt into style changes that are not in the current stable style yet\n\n## Pre-commit Integration\n\nBlack is commonly run through `pre-commit` so formatting stays consistent across machines and CI:\n\n```yaml\nrepos:\n  - repo: https://github.com/psf/black\n    rev: 26.3.0\n    hooks:\n      - id: black\n      - id: black-jupyter\n```\n\nUse `black-jupyter` only if the repository actually formats notebooks.\n\n## Common Workflows\n\n### CI formatting gate\n\n```bash\nblack --check .\n```\n\nPair it with a pinned version so local runs and CI produce the same output.\n\n### Editor integration\n\nPrefer editor integrations that shell out to the installed `black` binary from your environment. That keeps editor formatting aligned with your pinned project version and `pyproject.toml`.\n\n### Notebooks\n\nNotebook formatting requires the `jupyter` extra or a workflow that explicitly supports notebook cells. Plain `black .` is not enough if your repo depends on `.ipynb` formatting.\n\n## Common Pitfalls\n\n- Black only uses one `pyproject.toml` per run. Nested package configs are not merged.\n- If files are unexpectedly skipped, check `.gitignore`, `include`, `exclude`, and `extend-exclude` rules before assuming Black is broken.\n- `--target-version` matters. It changes which syntax Black is allowed to emit.\n- `--fast` disables the post-format safety check. Use the default safe mode unless you specifically need the speed tradeoff.\n- `blackd` does not use `pyproject.toml`, so do not assume daemon-based formatting will honor repository config automatically.\n- Formatting notebooks needs `black[jupyter]` or notebook-aware hooks.\n- `--preview` and unstable features can change formatting output between releases. Do not enable them casually in shared CI unless the team intends to absorb churn.\n\n## Version-Sensitive Notes\n\n- Black's style is deliberately stable. The docs state that formatting changes for the stable style are only made in January releases, except for bug fixes and support for new Python syntax.\n- `26.3.0` includes preview-style changes for long typed function parameter lists and for forcing parentheses around conditional expressions in typed lambdas.\n- `26.3.1` is a patch release that fixes corruption for non-UTF-8 files and a lambda-with-comment formatting bug. If you are pinned to exact `26.3.0`, review diffs before moving to `26.3.1`.\n\n## Official Sources\n\n- Stable docs: `https://black.readthedocs.io/en/stable/`\n- Usage and configuration: `https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html`\n- File collection and exclude behavior: `https://black.readthedocs.io/en/stable/usage_and_configuration/file_collection_and_discovery.html`\n- Getting started and `pre-commit`: `https://black.readthedocs.io/en/stable/getting_started.html`\n- Change log: `https://black.readthedocs.io/en/stable/change_log.html`\n- PyPI: `https://pypi.org/project/black/`\n- Repository: `https://github.com/psf/black`\n"
  },
  {
    "path": "content/bokeh/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Bokeh interactive visualization library for Python plots, dashboards, notebook output, and Bokeh server apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bokeh,python,visualization,plotting,dashboard,jupyter,server\"\n---\n\n# Bokeh Python Package Guide\n\n## Golden Rule\n\nUse `bokeh` for browser-based interactive plots and dashboards in Python, and choose the output mode first:\n\n- standalone HTML with `show()` or `save()`\n- notebook output with `output_notebook()`\n- embedded JSON or script/div snippets with `bokeh.embed`\n- live apps with `bokeh serve`\n\nMost agent mistakes come from mixing standalone plots and Bokeh server patterns in the same code path.\n\n## Version Drift To Know About\n\nAs of `2026-03-12`, the Bokeh docs site and release notes already publish `3.9.0`, but the live PyPI project page still shows `3.8.2` as the latest stable release and lists `3.9.0.dev*` prereleases. Use this doc for the `3.9.0` API surface, but verify what your package index actually exposes before pinning.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"bokeh==3.9.0\"\n```\n\nIf your index still only exposes the current PyPI stable line on `2026-03-12`, use:\n\n```bash\npython -m pip install \"bokeh==3.8.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"bokeh==3.9.0\"\npoetry add \"bokeh==3.9.0\"\nconda install bokeh\n```\n\nNotes:\n\n- Bokeh `3.9.0` no longer installs `pandas` as a required dependency. Install `pandas` yourself if your code passes DataFrames into Bokeh helpers.\n- Static image export is an extra deployment concern. `export_png()` and `export_svg()` need Selenium plus a compatible browser and driver.\n- JupyterLab usage may require the `jupyter_bokeh` extension package depending on your notebook environment.\n\n## Initialize A Standalone Plot\n\nThis is the safest default for scripts, CLIs, tests, and generated reports:\n\n```python\nfrom bokeh.io import output_file, show\nfrom bokeh.plotting import figure\n\np = figure(\n    title=\"Request latency\",\n    x_axis_label=\"minute\",\n    y_axis_label=\"latency_ms\",\n    width=800,\n    height=400,\n    toolbar_location=\"above\",\n)\n\np.line([1, 2, 3, 4], [120, 98, 143, 110], line_width=2, legend_label=\"p95\")\np.circle([1, 2, 3, 4], [120, 98, 143, 110], size=8)\n\noutput_file(\"latency.html\", title=\"Latency Report\")\nshow(p)\n```\n\nUse `show()` when you want Bokeh to open a browser tab during local execution. Use `save(p)` when you only need the generated HTML file.\n\n## Core Usage\n\n### Use `ColumnDataSource` for structured data and updates\n\n`ColumnDataSource` is the normal bridge between Python data and glyphs:\n\n```python\nfrom bokeh.models import ColumnDataSource, HoverTool\nfrom bokeh.plotting import figure, show\n\nsource = ColumnDataSource(\n    data={\n        \"x\": [1, 2, 3],\n        \"y\": [4, 7, 5],\n        \"service\": [\"api\", \"worker\", \"db\"],\n    }\n)\n\np = figure(title=\"Service metrics\", width=700, height=350, tools=\"pan,wheel_zoom,reset,save\")\np.scatter(\"x\", \"y\", source=source, size=12)\np.add_tools(HoverTool(tooltips=[(\"service\", \"@service\"), (\"x\", \"@x\"), (\"y\", \"@y\")]))\n\nshow(p)\n```\n\nFor streaming or incremental updates:\n\n```python\nsource.stream({\"x\": [4], \"y\": [8], \"service\": [\"cache\"]}, rollover=200)\n```\n\nUse `source.patch(...)` when you need partial in-place updates instead of replacing all columns.\n\n### Layout multiple plots and controls\n\n```python\nfrom bokeh.layouts import column, row\nfrom bokeh.models import Div\nfrom bokeh.plotting import figure, show\n\np1 = figure(width=350, height=250, title=\"Throughput\")\np1.vbar(x=[\"a\", \"b\", \"c\"], top=[10, 15, 12], width=0.7)\n\np2 = figure(width=350, height=250, title=\"Errors\")\np2.line([1, 2, 3], [0, 1, 0], line_width=2)\n\nlayout = column(Div(text=\"<h2>System Summary</h2>\"), row(p1, p2))\nshow(layout)\n```\n\n### Notebook output\n\nFor notebooks, initialize notebook resources once before calling `show()`:\n\n```python\nfrom bokeh.io import output_notebook, show\nfrom bokeh.plotting import figure\n\noutput_notebook()\n\np = figure(title=\"Notebook plot\", width=600, height=300)\np.line([1, 2, 3], [1, 4, 9], line_width=2)\n\nshow(p)\n```\n\nIf plots render as blank areas in JupyterLab, verify `jupyter_bokeh` and the frontend extension state before changing plotting code.\n\n## Embedding In Web Apps\n\nUse standalone embedding when you already have a Flask, Django, or FastAPI app and do not need live Python callbacks.\n\n### Script and div fragments\n\n```python\nfrom bokeh.embed import components\nfrom bokeh.plotting import figure\n\np = figure(title=\"Embedded chart\", width=500, height=300)\np.line([1, 2, 3], [3, 2, 4], line_width=2)\n\nscript, div = components(p)\n```\n\nRender `script` and `div` in your template.\n\n### JSON embedding\n\n`json_item()` is useful when your frontend fetches chart payloads over HTTP:\n\n```python\nimport json\n\nfrom bokeh.embed import json_item\nfrom bokeh.plotting import figure\n\np = figure(title=\"API chart\", width=500, height=300)\np.line([1, 2, 3], [3, 2, 4], line_width=2)\n\npayload = json.dumps(json_item(p, \"bokeh-target\"))\n```\n\nOn the client side, hand that payload to BokehJS and mount it into the element with id `bokeh-target`.\n\n## Bokeh Server Apps\n\nUse the server only when the browser must talk back to live Python code. If the chart is static after render, standalone embedding is simpler and more reliable.\n\nMinimal server app:\n\n```python\nfrom bokeh.io import curdoc\nfrom bokeh.layouts import column\nfrom bokeh.models import ColumnDataSource, Slider\nfrom bokeh.plotting import figure\n\nx = [1, 2, 3, 4, 5]\nsource = ColumnDataSource(data={\"x\": x, \"y\": [i * i for i in x]})\n\np = figure(title=\"Scaled squares\", width=700, height=350)\np.line(\"x\", \"y\", source=source, line_width=2)\n\nslider = Slider(start=1, end=10, value=1, step=1, title=\"Scale\")\n\ndef update(attr, old, new):\n    scale = slider.value\n    source.data = {\"x\": x, \"y\": [scale * i * i for i in x]}\n\nslider.on_change(\"value\", update)\n\ncurdoc().add_root(column(slider, p))\ncurdoc().title = \"Bokeh Server Demo\"\n```\n\nRun it with:\n\n```bash\nbokeh serve --show app.py\n```\n\nDeployment notes:\n\n- Public deployments must set explicit WebSocket origins with `--allow-websocket-origin` or equivalent server config.\n- Keep origin settings narrow. Using `*` is only acceptable for local development.\n- Server apps are stateful. Avoid mutating shared global objects in ways that leak data across sessions.\n- If you need application auth, session management, or signed embedding, treat that as part of the surrounding web app deployment, not as a plotting concern.\n\n## Configuration Notes\n\n- Standalone HTML output does not require credentials or auth.\n- Use `output_file()` when the deliverable is an HTML artifact.\n- Use `output_notebook()` only in notebook runtimes.\n- Use `components()` or `json_item()` when another web framework owns the page shell.\n- Use a Bokeh server app only when Python-side interactivity must persist after initial render.\n- For air-gapped or restricted environments, verify how BokehJS resources are served before assuming CDN access is allowed.\n\n## Common Pitfalls\n\n- Do not mix server callbacks like `curdoc()` and `on_change()` with a plain standalone script unless you are actually running under `bokeh serve`.\n- `ColumnDataSource` columns must stay the same length. Mismatched arrays produce hard-to-debug rendering errors.\n- If you pass pandas objects in `3.9.0`, install `pandas` explicitly. It is no longer a guaranteed transitive dependency.\n- `show()` opens a browser during local execution. In CI or headless jobs, prefer `save()` or explicit export workflows.\n- Static image export failures usually come from missing Selenium, Firefox or Chromium, or the matching browser driver, not from plot code.\n- Blank notebook output usually means a frontend resource issue, not a bad glyph definition.\n- Bokeh server apps exposed behind a reverse proxy often fail because WebSocket origin settings were not updated.\n- Copying old Bokeh 2.x blog posts is risky. The modern `3.x` docs use newer APIs, stricter browser support, and different dependency assumptions.\n\n## Version-Sensitive Notes\n\n- `3.9.0` release notes call out Python `3.14` support and compatibility with `pandas 3`.\n- `3.9.0` removes `pandas` as a required dependency, which matters for agent-generated examples that assume DataFrame support is always present.\n- `3.9.0` adds support for dataclasses in `ColumnDataSource` and improves map plotting with new `figure` methods for Cartopy coordinates.\n- `3.8.2` contains an important Bokeh server security fix for incomplete origin validation. If you deploy server apps, do not stay below `3.8.2`.\n- Because the docs site is ahead of the stable PyPI page on `2026-03-12`, verify whether your environment is on `3.8.x`, a `3.9.0.dev*` prerelease, or the final `3.9.0` release before copying examples blindly.\n\n## Official Links\n\n- Docs root: `https://docs.bokeh.org/en/latest/`\n- Reference: `https://docs.bokeh.org/en/latest/docs/reference.html`\n- Installation: `https://docs.bokeh.org/en/latest/docs/first_steps/installation.html`\n- First steps: `https://docs.bokeh.org/en/latest/docs/first_steps/first_steps.html`\n- Embedding: `https://docs.bokeh.org/en/latest/docs/user_guide/output/embed.html`\n- Jupyter output: `https://docs.bokeh.org/en/latest/docs/user_guide/output/jupyter.html`\n- Server guide: `https://docs.bokeh.org/en/latest/docs/user_guide/server.html`\n- Releases: `https://docs.bokeh.org/en/latest/docs/releases.html`\n- PyPI: `https://pypi.org/project/bokeh/`\n"
  },
  {
    "path": "content/bottle/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Bottle Python package guide for small WSGI apps, APIs, and templated services\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.4\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"bottle,python,web,wsgi,microframework,api\"\n---\n\n# bottle Python Package Guide\n\n## What It Is\n\n`bottle` is a small, single-file WSGI web framework for Python. Use it for small services, internal tools, admin panels, webhooks, or JSON APIs when you want minimal framework overhead and direct control over request handling.\n\n## Version Scope\n\n- This entry covers PyPI package version `0.13.4`.\n- The version used here and the current stable upstream version both point to `0.13.4`.\n- Prefer the version-pinned docs at `https://bottlepy.org/docs/0.13/` when you need line-accurate upstream behavior for this package version.\n\n## Install\n\n```bash\npip install \"bottle==0.13.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"bottle==0.13.4\"\npoetry add \"bottle==0.13.4\"\n```\n\nBottle is pure Python and ships as a single package. The import path is also `bottle`.\n\n## Create An App\n\nPrefer an explicit `Bottle()` instance for non-trivial projects. Bottle also supports module-level decorators and a default app, but an explicit app is easier to test, configure, and mount under a real WSGI server.\n\n```python\nfrom bottle import Bottle, request, response\n\napp = Bottle()\napp.config.update(\n    DEBUG=True,\n    API_TITLE=\"example-service\",\n)\n\n@app.get(\"/health\")\ndef health() -> dict[str, object]:\n    response.status = 200\n    return {\n        \"ok\": True,\n        \"service\": app.config[\"API_TITLE\"],\n        \"client_ip\": request.remote_addr,\n    }\n\nif __name__ == \"__main__\":\n    app.run(host=\"127.0.0.1\", port=8080, debug=True, reloader=True)\n```\n\nNotes:\n\n- Returning a `dict` produces JSON by default in `0.13` because `Bottle(autojson=True)` is the default.\n- `debug=True` and `reloader=True` are development-only settings.\n- The auto-reloader imports your module twice. Keep module-level side effects idempotent.\n\n## Routing\n\nBottle routes are usually declared with HTTP method decorators.\n\n```python\nfrom bottle import Bottle, abort\n\napp = Bottle()\n\n@app.get(\"/users/<user_id:int>\")\ndef get_user(user_id: int):\n    if user_id <= 0:\n        abort(400, \"user_id must be positive\")\n    return {\"user_id\": user_id}\n\n@app.post(\"/users/<user_id:int>/activate\")\ndef activate_user(user_id: int):\n    return {\"user_id\": user_id, \"active\": True}\n\n@app.get(\"/files/<path:path>\")\ndef get_file(path: str):\n    return {\"path\": path}\n```\n\nUseful patterns:\n\n- `/<name>`: plain wildcard\n- `/<id:int>`: integer conversion\n- `/<path:path>`: slash-containing tail segment\n\nAvoid older blog posts that still use pre-`0.13` route syntax or rely on the global default app everywhere.\n\n## Read Request Data\n\nBottle exposes request state through the global `request` object during a request.\n\n### Query Parameters And Forms\n\n```python\nfrom bottle import Bottle, request\n\napp = Bottle()\n\n@app.get(\"/search\")\ndef search():\n    query = request.query.get(\"q\", \"\").strip()\n    page = int(request.query.get(\"page\", \"1\"))\n    tags = request.query.getall(\"tag\")\n    return {\"q\": query, \"page\": page, \"tags\": tags}\n\n@app.post(\"/login\")\ndef login():\n    username = request.forms.get(\"username\", \"\")\n    password = request.forms.get(\"password\", \"\")\n    return {\"accepted\": bool(username and password)}\n```\n\n`request.query` and `request.forms` are `FormsDict` objects. Use `getall()` when a key can appear multiple times.\n\n### JSON Bodies\n\n```python\nfrom bottle import Bottle, request, abort\n\napp = Bottle()\n\n@app.post(\"/tasks\")\ndef create_task():\n    payload = request.json\n    if not payload or \"title\" not in payload:\n        abort(400, \"JSON body with 'title' is required\")\n    return {\"task\": {\"title\": payload[\"title\"]}}\n```\n\n`request.json` is the common path for JSON APIs. Treat it as optional input and validate required fields yourself.\n\n### File Uploads\n\n```python\nfrom pathlib import Path\nfrom bottle import Bottle, request, abort\n\napp = Bottle()\nUPLOAD_DIR = Path(\"./uploads\")\nUPLOAD_DIR.mkdir(exist_ok=True)\n\n@app.post(\"/upload\")\ndef upload():\n    upload = request.files.get(\"file\")\n    if upload is None:\n        abort(400, \"missing file field\")\n\n    filename = Path(upload.filename).name\n    target = UPLOAD_DIR / filename\n    upload.save(str(target), overwrite=False)\n    return {\"saved_to\": str(target)}\n```\n\nDo not trust the client filename or path. Normalize the name and keep the destination directory fixed on the server side.\n\n## Build Responses\n\nBottle handlers can return strings, bytes, dicts, generators, or raise HTTP helpers like `abort()`.\n\n```python\nfrom bottle import Bottle, response, redirect, abort\n\napp = Bottle()\n\n@app.get(\"/plain\")\ndef plain():\n    response.content_type = \"text/plain; charset=UTF-8\"\n    return \"ok\"\n\n@app.get(\"/created\")\ndef created():\n    response.status = 201\n    response.set_header(\"X-Service\", \"bottle\")\n    return {\"created\": True}\n\n@app.get(\"/old-path\")\ndef old_path():\n    redirect(\"/plain\")\n\n@app.get(\"/boom\")\ndef boom():\n    abort(503, \"temporarily unavailable\")\n```\n\nIf you need to control headers or status codes, set them on `response` before returning the body.\n\n## Templates And Static Files\n\nBottle includes the SimpleTemplate engine and static-file helpers.\n\n```python\nfrom pathlib import Path\nfrom bottle import Bottle, template, static_file\n\napp = Bottle()\nSTATIC_ROOT = Path(__file__).parent / \"static\"\n\n@app.get(\"/hello/<name>\")\ndef hello(name: str):\n    return template(\"Hello {{name}}!\", name=name)\n\n@app.get(\"/assets/<filename:path>\")\ndef assets(filename: str):\n    return static_file(filename, root=str(STATIC_ROOT))\n```\n\nUse `static_file()` instead of manually opening files. It handles range requests, content types, and keeps the root directory explicit.\n\n## Config, Cookies, And Auth\n\nBottle does not ship a full authentication framework. The common pattern is:\n\n- store secrets and environment-specific settings in `app.config`\n- authenticate from headers or signed cookies\n- centralize auth checks in a hook or plugin\n\n### App Config\n\n```python\nfrom bottle import Bottle\nimport os\n\napp = Bottle()\napp.config.load_dict(\n    session_cookie=\"session\",\n    session_secret=os.environ[\"SESSION_SECRET\"],\n    api_token=os.environ.get(\"API_TOKEN\", \"\"),\n)\n```\n\n### Signed Cookies\n\n```python\nfrom bottle import Bottle, request, response, abort\n\napp = Bottle()\nCOOKIE_NAME = \"session\"\nCOOKIE_SECRET = \"replace-me\"\n\n@app.post(\"/session\")\ndef create_session():\n    response.set_cookie(\n        COOKIE_NAME,\n        \"user-123\",\n        secret=COOKIE_SECRET,\n        httponly=True,\n        secure=True,\n        samesite=\"Lax\",\n        path=\"/\",\n    )\n    return {\"created\": True}\n\n@app.get(\"/session\")\ndef read_session():\n    user_id = request.get_cookie(COOKIE_NAME, secret=COOKIE_SECRET)\n    if user_id is None:\n        abort(401, \"missing or invalid session\")\n    return {\"user_id\": user_id}\n```\n\nSigned cookies are integrity-protected, not encrypted. Do not put raw secrets or private data in the cookie value.\n\n### Header-Based Auth With A Hook\n\n```python\nfrom bottle import Bottle, request, abort\n\napp = Bottle()\napp.config[\"api_token\"] = \"replace-me\"\n\n@app.hook(\"before_request\")\ndef require_api_token():\n    if request.path == \"/health\":\n        return\n    if request.get_header(\"X-API-Key\") != app.config[\"api_token\"]:\n        abort(401, \"invalid API token\")\n```\n\nHooks are the simplest way to enforce cross-cutting policy on small apps. For reusable behavior across multiple apps, package the logic as a plugin and install it with `app.install(...)`.\n\n## Production Deployment\n\nBottle apps are WSGI callables. The built-in development server is not for production.\n\n```python\n# myservice.py\nfrom bottle import Bottle\n\napp = Bottle()\n\n@app.get(\"/\")\ndef index():\n    return {\"ok\": True}\n```\n\nRun it under a real WSGI server:\n\n```bash\ngunicorn myservice:app\n```\n\nDeployment rules:\n\n- Keep `app.run(...)` for local development only.\n- In production, use a WSGI server such as Gunicorn, Cheroot, Waitress, or another supported server adapter.\n- Bottle is a WSGI framework, not an ASGI framework. Do not paste `async def` or ASGI middleware patterns from FastAPI or Starlette examples into Bottle code.\n\n## Common Pitfalls\n\n- `debug=True` enables verbose errors and template reloading. Do not enable it in production.\n- The reloader restarts the process and imports the module twice.\n- Returning a `dict` auto-serializes to JSON in `0.13`; older examples may show manual `json.dumps(...)` for the common case.\n- `request` and `response` are request-local globals. Do not cache them across requests.\n- `static_file()` still needs a trusted root directory. Never join untrusted paths directly to an arbitrary filesystem location.\n- Signed cookies protect against tampering, not disclosure.\n- Bottle supports a default app and module-level decorators, but explicit `Bottle()` instances are safer for tests, mounting, and larger codebases.\n\n## Version-Sensitive Notes For 0.13.x\n\n- `0.13` changed several compatibility assumptions. Upstream documents Python `3.8+` support and keeps deprecated Python `2.7.3+` compatibility for the `0.13` line.\n- `Bottle.autojson` defaults to `True` in `0.13`, so plain `dict` return values are JSON responses unless you override that behavior.\n- The CLI script name is `bottle`, not `bottle.py`.\n- `Bottle.app()` now returns a configured default app, so old examples that depend on implicit global state can behave differently than older `0.12` tutorials suggest.\n- If you are copying old `0.12` tutorials, re-check route declarations, JSON response handling, and deployment snippets against the `0.13` docs before using them.\n\n## Official Links\n\n- Version-pinned docs: https://bottlepy.org/docs/0.13/\n- Stable docs root: https://bottlepy.org/docs/stable/\n- Tutorial: https://bottlepy.org/docs/0.13/tutorial.html\n- API reference: https://bottlepy.org/docs/0.13/api.html\n- Deployment guide: https://bottlepy.org/docs/0.13/deployment.html\n- Plugin guide: https://bottlepy.org/docs/0.13/plugins/index.html\n- Changelog: https://bottlepy.org/docs/0.13/changelog.html\n- PyPI package: https://pypi.org/project/bottle/\n"
  },
  {
    "path": "content/braintree/docs/gateway/javascript/DOC.md",
    "content": "---\nname: gateway\ndescription: \"Braintree Node.js SDK for payment gateway, PayPal, and subscriptions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.34.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"braintree,gateway,payments,paypal,subscriptions\"\n---\n\n# Braintree Node.js SDK Context\n\n## Golden Rule\n\n**ALWAYS use the official Braintree Node.js SDK package: `braintree`**\n\n```bash\nnpm install braintree\n```\n\n**DO NOT use:**\n- Deprecated or unofficial packages\n- Direct API calls without the SDK\n- Outdated versions (version 3.40.0+ required for SSL certificate support)\n\nThe official package is `braintree` and is maintained by Braintree (a PayPal service).\n\n## Installation\n\n```bash\nnpm install braintree\n```\n\nFor Express.js applications, you'll also need:\n\n```bash\nnpm install express body-parser\n```\n\n## Environment Configuration\n\nCreate a `.env` file with your Braintree credentials:\n\n```bash\nBRAINTREE_ENVIRONMENT=Sandbox\nBRAINTREE_MERCHANT_ID=your_merchant_id\nBRAINTREE_PUBLIC_KEY=your_public_key\nBRAINTREE_PRIVATE_KEY=your_private_key\n```\n\nLoad environment variables:\n\n```javascript\nrequire('dotenv').config();\n```\n\n## Initialization\n\n### Basic Gateway Setup\n\n```javascript\nconst braintree = require(\"braintree\");\n\nconst gateway = new braintree.BraintreeGateway({\n  environment: braintree.Environment.Sandbox,\n  merchantId: \"your_merchant_id\",\n  publicKey: \"your_public_key\",\n  privateKey: \"your_private_key\"\n});\n```\n\n### Using Environment Variables\n\n```javascript\nconst braintree = require(\"braintree\");\n\nconst gateway = new braintree.BraintreeGateway({\n  environment: process.env.BRAINTREE_ENVIRONMENT === 'Production'\n    ? braintree.Environment.Production\n    : braintree.Environment.Sandbox,\n  merchantId: process.env.BRAINTREE_MERCHANT_ID,\n  publicKey: process.env.BRAINTREE_PUBLIC_KEY,\n  privateKey: process.env.BRAINTREE_PRIVATE_KEY\n});\n```\n\n### Environment Options\n\n```javascript\n// Sandbox environment (for testing)\nbraintree.Environment.Sandbox\n\n// Production environment (for live transactions)\nbraintree.Environment.Production\n```\n\n## Client Token Generation\n\nClient tokens contain authorization and configuration information for the client SDK.\n\n### Basic Client Token\n\n**Callback:**\n```javascript\ngateway.clientToken.generate({}, (err, response) => {\n  const clientToken = response.clientToken;\n});\n```\n\n**Promise:**\n```javascript\ngateway.clientToken.generate({})\n  .then(response => {\n    const clientToken = response.clientToken;\n  });\n```\n\n### Client Token with Customer ID\n\n```javascript\ngateway.clientToken.generate({\n  customerId: \"customer_123\"\n}, (err, response) => {\n  const clientToken = response.clientToken;\n});\n```\n\n### Express.js Endpoint for Client Token\n\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get(\"/client_token\", (req, res) => {\n  gateway.clientToken.generate({}, (err, response) => {\n    if (err) {\n      res.status(500).send(err);\n    } else {\n      res.send(response.clientToken);\n    }\n  });\n});\n```\n\n## Transactions\n\n### Creating a Transaction\n\n**Basic Sale (Callback):**\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Transaction ID: \" + result.transaction.id);\n  } else {\n    console.log(result.message);\n  }\n});\n```\n\n**Basic Sale (Promise):**\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  options: {\n    submitForSettlement: true\n  }\n}).then(result => {\n  if (result.success) {\n    console.log(\"Transaction ID: \" + result.transaction.id);\n  } else {\n    console.log(result.message);\n  }\n});\n```\n\n### Transaction with Device Data\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  deviceData: deviceDataFromTheClient,\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Transaction with Customer Information\n\n```javascript\ngateway.transaction.sale({\n  amount: \"100.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  customer: {\n    firstName: \"John\",\n    lastName: \"Doe\",\n    email: \"john.doe@example.com\",\n    phone: \"312-555-1234\"\n  },\n  billing: {\n    firstName: \"John\",\n    lastName: \"Doe\",\n    streetAddress: \"123 Main St\",\n    locality: \"Chicago\",\n    region: \"IL\",\n    postalCode: \"60614\",\n    countryCodeAlpha2: \"US\"\n  },\n  shipping: {\n    firstName: \"John\",\n    lastName: \"Doe\",\n    streetAddress: \"123 Main St\",\n    locality: \"Chicago\",\n    region: \"IL\",\n    postalCode: \"60614\",\n    countryCodeAlpha2: \"US\"\n  },\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Transaction with Stored Payment Method\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodToken: \"the_token\",\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Express.js Checkout Endpoint\n\n```javascript\napp.post(\"/checkout\", (req, res) => {\n  const nonceFromTheClient = req.body.payment_method_nonce;\n  const amount = req.body.amount;\n\n  gateway.transaction.sale({\n    amount: amount,\n    paymentMethodNonce: nonceFromTheClient,\n    options: {\n      submitForSettlement: true\n    }\n  }, (err, result) => {\n    if (result.success) {\n      res.send({\n        success: true,\n        transactionId: result.transaction.id\n      });\n    } else {\n      res.status(500).send({\n        success: false,\n        message: result.message\n      });\n    }\n  });\n});\n```\n\n### Finding a Transaction\n\n**Callback:**\n```javascript\ngateway.transaction.find(\"theTransactionId\", (err, transaction) => {\n  console.log(transaction.amount);\n  console.log(transaction.status);\n});\n```\n\n**Promise:**\n```javascript\ngateway.transaction.find(\"theTransactionId\")\n  .then(transaction => {\n    console.log(transaction.amount);\n    console.log(transaction.status);\n  });\n```\n\n### Refunding a Transaction\n\n**Full Refund (Callback):**\n```javascript\ngateway.transaction.refund(\"theTransactionId\", (err, result) => {\n  if (result.success) {\n    console.log(\"Refund successful\");\n  }\n});\n```\n\n**Partial Refund (Callback):**\n```javascript\ngateway.transaction.refund(\"theTransactionId\", \"10.00\", (err, result) => {\n  if (result.success) {\n    console.log(\"Partial refund successful\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.transaction.refund(\"theTransactionId\", \"10.00\")\n  .then(result => {\n    if (result.success) {\n      console.log(\"Refund successful\");\n    }\n  });\n```\n\n### Voiding a Transaction\n\n**Callback:**\n```javascript\ngateway.transaction.void(\"theTransactionId\", (err, result) => {\n  if (result.success) {\n    console.log(\"Transaction voided\");\n  } else {\n    console.log(result.message);\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.transaction.void(\"theTransactionId\")\n  .then(result => {\n    if (result.success) {\n      console.log(\"Transaction voided\");\n    }\n  });\n```\n\n## Customer Management\n\n### Creating a Customer\n\n**Basic Customer (Callback):**\n```javascript\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  email: \"john.doe@example.com\",\n  phone: \"312-555-1234\"\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Customer ID: \" + result.customer.id);\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  email: \"john.doe@example.com\"\n}).then(result => {\n  if (result.success) {\n    console.log(\"Customer ID: \" + result.customer.id);\n  }\n});\n```\n\n### Creating Customer with Company Information\n\n```javascript\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  company: \"Acme Corp\",\n  email: \"john.doe@example.com\",\n  phone: \"312-555-1234\",\n  fax: \"614-555-5678\",\n  website: \"www.example.com\"\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Creating Customer with Payment Method\n\n```javascript\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  email: \"john.doe@example.com\",\n  paymentMethodNonce: nonceFromTheClient\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Customer ID: \" + result.customer.id);\n    console.log(\"Payment Method Token: \" + result.customer.paymentMethods[0].token);\n  }\n});\n```\n\n### Finding a Customer\n\n**Callback:**\n```javascript\ngateway.customer.find(\"theCustomerId\", (err, customer) => {\n  console.log(customer.firstName);\n  console.log(customer.lastName);\n  console.log(customer.email);\n});\n```\n\n**Promise:**\n```javascript\ngateway.customer.find(\"theCustomerId\")\n  .then(customer => {\n    console.log(customer.firstName);\n    console.log(customer.paymentMethods);\n  });\n```\n\n### Updating a Customer\n\n**Callback:**\n```javascript\ngateway.customer.update(\"theCustomerId\", {\n  firstName: \"Jane\",\n  lastName: \"Smith\",\n  email: \"jane.smith@example.com\"\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Customer updated\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.customer.update(\"theCustomerId\", {\n  firstName: \"Jane\",\n  lastName: \"Smith\"\n}).then(result => {\n  if (result.success) {\n    console.log(\"Customer updated\");\n  }\n});\n```\n\n### Deleting a Customer\n\n**Callback:**\n```javascript\ngateway.customer.delete(\"theCustomerId\", (err) => {\n  if (!err) {\n    console.log(\"Customer deleted\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.customer.delete(\"theCustomerId\")\n  .then(() => {\n    console.log(\"Customer deleted\");\n  });\n```\n\n### Searching for Customers\n\n```javascript\nconst stream = gateway.customer.search((search) => {\n  search.firstName().is(\"John\");\n  search.lastName().is(\"Doe\");\n});\n\nstream.on(\"data\", (customer) => {\n  console.log(customer.id);\n  console.log(customer.email);\n});\n\nstream.on(\"end\", () => {\n  console.log(\"Search complete\");\n});\n```\n\n## Payment Method Management\n\n### Creating a Payment Method\n\n**Callback:**\n```javascript\ngateway.paymentMethod.create({\n  customerId: \"customer_123\",\n  paymentMethodNonce: nonceFromTheClient\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Payment Method Token: \" + result.paymentMethod.token);\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.paymentMethod.create({\n  customerId: \"customer_123\",\n  paymentMethodNonce: nonceFromTheClient\n}).then(result => {\n  if (result.success) {\n    console.log(\"Payment Method Token: \" + result.paymentMethod.token);\n  }\n});\n```\n\n### Creating Payment Method with Billing Address\n\n```javascript\ngateway.paymentMethod.create({\n  customerId: \"customer_123\",\n  paymentMethodNonce: nonceFromTheClient,\n  billingAddress: {\n    streetAddress: \"123 Main St\",\n    locality: \"Chicago\",\n    region: \"IL\",\n    postalCode: \"60614\"\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Finding a Payment Method\n\n**Callback:**\n```javascript\ngateway.paymentMethod.find(\"the_token\", (err, paymentMethod) => {\n  console.log(paymentMethod.token);\n});\n```\n\n**Promise:**\n```javascript\ngateway.paymentMethod.find(\"the_token\")\n  .then(paymentMethod => {\n    console.log(paymentMethod.token);\n  });\n```\n\n### Updating a Payment Method\n\n**Set as Default (Callback):**\n```javascript\ngateway.paymentMethod.update(\"the_token\", {\n  options: {\n    makeDefault: true\n  }\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Payment method is now default\");\n  }\n});\n```\n\n**Update Billing Address (Callback):**\n```javascript\ngateway.paymentMethod.update(\"the_token\", {\n  billingAddress: {\n    streetAddress: \"456 Oak Ave\",\n    locality: \"Chicago\",\n    region: \"IL\",\n    postalCode: \"60614\",\n    options: {\n      updateExisting: true\n    }\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n**Promise:**\n```javascript\ngateway.paymentMethod.update(\"the_token\", {\n  options: {\n    makeDefault: true\n  }\n}).then(result => {\n  if (result.success) {\n    console.log(\"Payment method updated\");\n  }\n});\n```\n\n### Deleting a Payment Method\n\n**Callback:**\n```javascript\ngateway.paymentMethod.delete(\"the_token\", (err) => {\n  if (!err) {\n    console.log(\"Payment method deleted\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.paymentMethod.delete(\"the_token\")\n  .then(() => {\n    console.log(\"Payment method deleted\");\n  })\n  .catch(err => {\n    console.log(err);\n  });\n```\n\n## Subscription Billing\n\n### Creating a Subscription\n\n**Basic Subscription (Callback):**\n```javascript\ngateway.subscription.create({\n  paymentMethodToken: \"the_token\",\n  planId: \"plan_id\"\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Subscription ID: \" + result.subscription.id);\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.subscription.create({\n  paymentMethodToken: \"the_token\",\n  planId: \"plan_id\"\n}).then(result => {\n  if (result.success) {\n    console.log(\"Subscription ID: \" + result.subscription.id);\n  }\n});\n```\n\n### Creating Subscription with Add-ons and Discounts\n\n```javascript\ngateway.subscription.create({\n  paymentMethodToken: \"the_token\",\n  planId: \"plan_id\",\n  addOns: {\n    add: [\n      {\n        inheritedFromId: \"add_on_id_1\",\n        amount: \"10.00\"\n      }\n    ]\n  },\n  discounts: {\n    add: [\n      {\n        inheritedFromId: \"discount_id_1\",\n        amount: \"5.00\"\n      }\n    ]\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Creating Subscription with Trial Period\n\n```javascript\ngateway.subscription.create({\n  paymentMethodToken: \"the_token\",\n  planId: \"plan_id\",\n  trialDuration: 14,\n  trialDurationUnit: \"day\",\n  trialPeriod: true\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Finding a Subscription\n\n**Callback:**\n```javascript\ngateway.subscription.find(\"subscription_id\", (err, subscription) => {\n  console.log(subscription.status);\n  console.log(subscription.price);\n});\n```\n\n**Promise:**\n```javascript\ngateway.subscription.find(\"subscription_id\")\n  .then(subscription => {\n    console.log(subscription.status);\n  });\n```\n\n### Updating a Subscription\n\n**Callback:**\n```javascript\ngateway.subscription.update(\"subscription_id\", {\n  price: \"15.00\"\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Subscription updated\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.subscription.update(\"subscription_id\", {\n  price: \"15.00\",\n  planId: \"new_plan_id\"\n}).then(result => {\n  if (result.success) {\n    console.log(\"Subscription updated\");\n  }\n});\n```\n\n### Canceling a Subscription\n\n**Callback:**\n```javascript\ngateway.subscription.cancel(\"subscription_id\", (err, result) => {\n  if (result.success) {\n    console.log(\"Subscription canceled\");\n  }\n});\n```\n\n**Promise:**\n```javascript\ngateway.subscription.cancel(\"subscription_id\")\n  .then(result => {\n    if (result.success) {\n      console.log(\"Subscription canceled\");\n    }\n  });\n```\n\n### Retrieving All Plans\n\n**Callback:**\n```javascript\ngateway.plan.all((err, result) => {\n  result.plans.forEach(plan => {\n    console.log(plan.id);\n    console.log(plan.name);\n    console.log(plan.price);\n  });\n});\n```\n\n**Promise:**\n```javascript\ngateway.plan.all()\n  .then(result => {\n    result.plans.forEach(plan => {\n      console.log(plan.id);\n    });\n  });\n```\n\n## Webhooks\n\n### Parsing Webhook Notifications\n\n**Callback:**\n```javascript\ngateway.webhookNotification.parse(\n  req.body.bt_signature,\n  req.body.bt_payload,\n  (err, webhookNotification) => {\n    if (err) {\n      console.error(err);\n      return;\n    }\n\n    console.log(webhookNotification.kind);\n    console.log(webhookNotification.timestamp);\n  }\n);\n```\n\n**Promise:**\n```javascript\ngateway.webhookNotification.parse(\n  req.body.bt_signature,\n  req.body.bt_payload\n).then(webhookNotification => {\n  console.log(webhookNotification.kind);\n  console.log(webhookNotification.timestamp);\n});\n```\n\n### Express.js Webhook Endpoint\n\n```javascript\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst app = express();\n\napp.use(bodyParser.urlencoded({ extended: false }));\n\napp.post('/webhooks', (req, res) => {\n  gateway.webhookNotification.parse(\n    req.body.bt_signature,\n    req.body.bt_payload,\n    (err, webhookNotification) => {\n      if (err) {\n        console.error(err);\n        return res.sendStatus(400);\n      }\n\n      // Handle different webhook types\n      if (webhookNotification.kind === braintree.WebhookNotification.Kind.SubscriptionCanceled) {\n        console.log(\"Subscription \" + webhookNotification.subscription.id + \" canceled\");\n      } else if (webhookNotification.kind === braintree.WebhookNotification.Kind.SubscriptionChargedSuccessfully) {\n        console.log(\"Subscription \" + webhookNotification.subscription.id + \" charged\");\n      } else if (webhookNotification.kind === braintree.WebhookNotification.Kind.DisputeOpened) {\n        console.log(\"Dispute opened for transaction \" + webhookNotification.dispute.transaction.id);\n      }\n\n      res.sendStatus(200);\n    }\n  );\n});\n```\n\n### Handling Subscription Webhooks\n\n```javascript\ngateway.webhookNotification.parse(\n  signature,\n  payload,\n  (err, webhookNotification) => {\n    if (webhookNotification.kind === braintree.WebhookNotification.Kind.SubscriptionWentPastDue) {\n      const subscriptionId = webhookNotification.subscription.id;\n      // Handle past due subscription\n    }\n  }\n);\n```\n\n### Verifying Webhook Signatures\n\n```javascript\ngateway.webhookNotification.verify(\n  \"challenge_string\",\n  (err, response) => {\n    console.log(response);\n  }\n);\n```\n\n### Testing Webhooks\n\n```javascript\nconst sampleNotification = gateway.webhookTesting.sampleNotification(\n  braintree.WebhookNotification.Kind.SubscriptionWentPastDue,\n  \"subscription_id\"\n);\n\ngateway.webhookNotification.parse(\n  sampleNotification.bt_signature,\n  sampleNotification.bt_payload\n).then(webhookNotification => {\n  console.log(webhookNotification.kind);\n  console.log(webhookNotification.subscription.id);\n});\n```\n\n## Advanced Features\n\n### Searching Transactions\n\n```javascript\nconst stream = gateway.transaction.search((search) => {\n  search.amount().min(\"10.00\");\n  search.amount().max(\"100.00\");\n  search.status().is(braintree.Transaction.Status.Settled);\n  search.createdAt().min(new Date(\"2024-01-01\"));\n});\n\nstream.on(\"data\", (transaction) => {\n  console.log(transaction.id);\n  console.log(transaction.amount);\n});\n\nstream.on(\"end\", () => {\n  console.log(\"Search complete\");\n});\n```\n\n### Creating Customer with Multiple Payment Methods\n\n```javascript\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  email: \"john.doe@example.com\",\n  creditCard: {\n    number: \"4111111111111111\",\n    expirationDate: \"05/2025\",\n    cvv: \"123\",\n    billingAddress: {\n      postalCode: \"60614\"\n    }\n  }\n}, (err, result) => {\n  if (result.success) {\n    const token = result.customer.paymentMethods[0].token;\n    console.log(\"Payment method token: \" + token);\n  }\n});\n```\n\n### Transaction with Custom Fields\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  customFields: {\n    order_id: \"12345\",\n    user_type: \"premium\"\n  },\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Holding in Escrow\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  serviceFeeAmount: \"1.00\",\n  merchantAccountId: \"submerchant_account_id\",\n  options: {\n    submitForSettlement: true,\n    holdInEscrow: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Transaction with Descriptor\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  descriptor: {\n    name: \"Company*Product\",\n    phone: \"8004567890\",\n    url: \"example.com\"\n  },\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  // Handle result\n});\n```\n\n### Cloning a Transaction\n\n```javascript\ngateway.transaction.cloneTransaction(\n  \"original_transaction_id\",\n  {\n    amount: \"20.00\",\n    options: {\n      submitForSettlement: true\n    }\n  },\n  (err, result) => {\n    if (result.success) {\n      console.log(\"Cloned transaction ID: \" + result.transaction.id);\n    }\n  }\n);\n```\n\n### Settlement\n\n**Submit for Settlement:**\n```javascript\ngateway.transaction.submitForSettlement(\"transaction_id\", (err, result) => {\n  if (result.success) {\n    console.log(\"Submitted for settlement\");\n  }\n});\n```\n\n**Submit with Amount:**\n```javascript\ngateway.transaction.submitForSettlement(\"transaction_id\", \"50.00\", (err, result) => {\n  if (result.success) {\n    console.log(\"Submitted for partial settlement\");\n  }\n});\n```\n\n### Dispute Management\n\n**Finding a Dispute:**\n```javascript\ngateway.dispute.find(\"dispute_id\", (err, dispute) => {\n  console.log(dispute.status);\n  console.log(dispute.amount);\n  console.log(dispute.reason);\n});\n```\n\n**Accept Dispute:**\n```javascript\ngateway.dispute.accept(\"dispute_id\", (err, result) => {\n  // Handle result\n});\n```\n\n**Add Text Evidence:**\n```javascript\ngateway.dispute.addTextEvidence(\"dispute_id\", \"evidence_text\", (err, result) => {\n  // Handle result\n});\n```\n\n### Merchant Account Creation\n\n```javascript\ngateway.merchantAccount.create({\n  individual: {\n    firstName: \"John\",\n    lastName: \"Doe\",\n    email: \"john.doe@example.com\",\n    dateOfBirth: \"1980-01-01\",\n    ssn: \"123-45-6789\",\n    address: {\n      streetAddress: \"123 Main St\",\n      locality: \"Chicago\",\n      region: \"IL\",\n      postalCode: \"60614\"\n    }\n  },\n  business: {\n    legalName: \"John Doe Inc\",\n    dbaName: \"JD Services\",\n    taxId: \"12-3456789\",\n    address: {\n      streetAddress: \"123 Main St\",\n      locality: \"Chicago\",\n      region: \"IL\",\n      postalCode: \"60614\"\n    }\n  },\n  funding: {\n    destination: braintree.MerchantAccount.FundingDestination.Bank,\n    routingNumber: \"021000021\",\n    accountNumber: \"1234567890\"\n  },\n  tosAccepted: true,\n  masterMerchantAccountId: \"master_merchant_account_id\"\n}, (err, result) => {\n  if (result.success) {\n    console.log(\"Merchant Account ID: \" + result.merchantAccount.id);\n  }\n});\n```\n\n## Error Handling\n\n### Checking Result Success\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  options: {\n    submitForSettlement: true\n  }\n}, (err, result) => {\n  if (err) {\n    console.error(\"Error:\", err);\n    return;\n  }\n\n  if (result.success) {\n    console.log(\"Transaction ID:\", result.transaction.id);\n  } else {\n    console.log(\"Error:\", result.message);\n\n    // Check validation errors\n    if (result.errors) {\n      console.log(\"Validation errors:\");\n      for (let key in result.errors.deepErrors()) {\n        console.log(result.errors.deepErrors()[key]);\n      }\n    }\n  }\n});\n```\n\n### Handling Validation Errors\n\n```javascript\ngateway.customer.create({\n  email: \"invalid-email\"\n}, (err, result) => {\n  if (!result.success) {\n    result.errors.deepErrors().forEach((error) => {\n      console.log(\"Error:\", error.code);\n      console.log(\"Message:\", error.message);\n      console.log(\"Attribute:\", error.attribute);\n    });\n  }\n});\n```\n\n### Promise Error Handling\n\n```javascript\ngateway.transaction.sale({\n  amount: \"10.00\",\n  paymentMethodNonce: nonceFromTheClient,\n  options: {\n    submitForSettlement: true\n  }\n})\n.then(result => {\n  if (result.success) {\n    console.log(\"Transaction ID:\", result.transaction.id);\n  } else {\n    console.log(\"Error:\", result.message);\n  }\n})\n.catch(err => {\n  console.error(\"Unexpected error:\", err);\n});\n```\n\n## Common Patterns\n\n### Complete Express.js Server Example\n\n```javascript\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst braintree = require('braintree');\n\nconst app = express();\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\n\nconst gateway = new braintree.BraintreeGateway({\n  environment: braintree.Environment.Sandbox,\n  merchantId: process.env.BRAINTREE_MERCHANT_ID,\n  publicKey: process.env.BRAINTREE_PUBLIC_KEY,\n  privateKey: process.env.BRAINTREE_PRIVATE_KEY\n});\n\n// Generate client token\napp.get('/client_token', (req, res) => {\n  gateway.clientToken.generate({}, (err, response) => {\n    if (err) {\n      res.status(500).send(err);\n    } else {\n      res.send(response.clientToken);\n    }\n  });\n});\n\n// Process payment\napp.post('/checkout', (req, res) => {\n  const nonceFromTheClient = req.body.payment_method_nonce;\n  const amount = req.body.amount;\n\n  gateway.transaction.sale({\n    amount: amount,\n    paymentMethodNonce: nonceFromTheClient,\n    options: {\n      submitForSettlement: true\n    }\n  }, (err, result) => {\n    if (result.success) {\n      res.send({\n        success: true,\n        transactionId: result.transaction.id\n      });\n    } else {\n      res.status(500).send({\n        success: false,\n        message: result.message\n      });\n    }\n  });\n});\n\napp.listen(3000, () => {\n  console.log('Server running on port 3000');\n});\n```\n\n### Customer Creation with Payment Method Workflow\n\n```javascript\n// Step 1: Create customer\ngateway.customer.create({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  email: \"john.doe@example.com\",\n  paymentMethodNonce: nonceFromTheClient\n}, (err, result) => {\n  if (result.success) {\n    const customerId = result.customer.id;\n    const paymentToken = result.customer.paymentMethods[0].token;\n\n    // Step 2: Create subscription\n    gateway.subscription.create({\n      paymentMethodToken: paymentToken,\n      planId: \"monthly_plan\"\n    }, (err, subResult) => {\n      if (subResult.success) {\n        console.log(\"Subscription ID:\", subResult.subscription.id);\n      }\n    });\n  }\n});\n```\n\n### Stored Payment Method Workflow\n\n```javascript\n// Step 1: Get customer\ngateway.customer.find(\"customer_id\", (err, customer) => {\n  // Step 2: Use default payment method for transaction\n  const defaultPaymentMethod = customer.paymentMethods.find(pm => pm.default);\n\n  gateway.transaction.sale({\n    amount: \"25.00\",\n    paymentMethodToken: defaultPaymentMethod.token,\n    options: {\n      submitForSettlement: true\n    }\n  }, (err, result) => {\n    if (result.success) {\n      console.log(\"Transaction ID:\", result.transaction.id);\n    }\n  });\n});\n```\n"
  },
  {
    "path": "content/braintree/docs/gateway/python/DOC.md",
    "content": "---\nname: gateway\ndescription: \"Braintree Python SDK for payment gateway, PayPal, and subscriptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.40.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"braintree,gateway,payments,paypal,subscriptions\"\n---\n\n# Braintree Python SDK Context\n\n## Golden Rule\n\n**ALWAYS use the official Braintree Python SDK package: `braintree`**\n\n```bash\npip install braintree\n```\n\n**DO NOT use:**\n- Deprecated or unofficial packages\n- Direct API calls without the SDK\n- Outdated versions (version 3.40.0+ required for SSL certificate support)\n\nThe official package is `braintree` and is maintained by Braintree (a PayPal service).\n\n## Installation\n\n```bash\npip install braintree\n```\n\nThe SDK requires Python 3.8 or higher. The SDK also depends on the `requests` library.\n\n## Environment Configuration\n\nCreate a `.env` file with your Braintree credentials:\n\n```bash\nBRAINTREE_ENVIRONMENT=Sandbox\nBRAINTREE_MERCHANT_ID=your_merchant_id\nBRAINTREE_PUBLIC_KEY=your_public_key\nBRAINTREE_PRIVATE_KEY=your_private_key\n```\n\nLoad environment variables using `python-dotenv`:\n\n```bash\npip install python-dotenv\n```\n\n```python\nfrom dotenv import load_dotenv\nimport os\n\nload_dotenv()\n```\n\n## Initialization\n\n### Basic Gateway Setup\n\n```python\nimport braintree\n\ngateway = braintree.BraintreeGateway(\n    braintree.Configuration(\n        braintree.Environment.Sandbox,\n        merchant_id=\"your_merchant_id\",\n        public_key=\"your_public_key\",\n        private_key=\"your_private_key\"\n    )\n)\n```\n\n### Using Environment Variables\n\n```python\nimport braintree\nimport os\n\ngateway = braintree.BraintreeGateway(\n    braintree.Configuration(\n        braintree.Environment.Production if os.getenv('BRAINTREE_ENVIRONMENT') == 'Production'\n        else braintree.Environment.Sandbox,\n        merchant_id=os.getenv('BRAINTREE_MERCHANT_ID'),\n        public_key=os.getenv('BRAINTREE_PUBLIC_KEY'),\n        private_key=os.getenv('BRAINTREE_PRIVATE_KEY')\n    )\n)\n```\n\n### Environment Options\n\n```python\n# Sandbox environment (for testing)\nbraintree.Environment.Sandbox\n\n# Production environment (for live transactions)\nbraintree.Environment.Production\n```\n\n## Client Token Generation\n\nClient tokens contain authorization and configuration information for the client SDK.\n\n### Basic Client Token\n\n```python\nclient_token = gateway.client_token.generate()\n```\n\n### Client Token with Customer ID\n\n```python\nclient_token = gateway.client_token.generate({\n    \"customer_id\": \"customer_123\"\n})\n```\n\n### Flask Endpoint for Client Token\n\n```python\nfrom flask import Flask, jsonify\n\napp = Flask(__name__)\n\n@app.route(\"/client_token\", methods=[\"GET\"])\ndef get_client_token():\n    try:\n        token = gateway.client_token.generate()\n        return jsonify({\"client_token\": token})\n    except Exception as e:\n        return jsonify({\"error\": str(e)}), 500\n```\n\n### Django View for Client Token\n\n```python\nfrom django.http import JsonResponse\n\ndef client_token(request):\n    try:\n        token = gateway.client_token.generate()\n        return JsonResponse({\"client_token\": token})\n    except Exception as e:\n        return JsonResponse({\"error\": str(e)}, status=500)\n```\n\n## Transactions\n\n### Creating a Transaction\n\n**Basic Sale:**\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n\nif result.is_success:\n    print(\"Transaction ID: \" + result.transaction.id)\nelse:\n    print(\"Error: \" + result.message)\n```\n\n### Transaction with Device Data\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"device_data\": device_data_from_the_client,\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Transaction with Customer Information\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"100.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"customer\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"email\": \"john.doe@example.com\",\n        \"phone\": \"312-555-1234\"\n    },\n    \"billing\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"street_address\": \"123 Main St\",\n        \"locality\": \"Chicago\",\n        \"region\": \"IL\",\n        \"postal_code\": \"60614\",\n        \"country_code_alpha2\": \"US\"\n    },\n    \"shipping\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"street_address\": \"123 Main St\",\n        \"locality\": \"Chicago\",\n        \"region\": \"IL\",\n        \"postal_code\": \"60614\",\n        \"country_code_alpha2\": \"US\"\n    },\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Transaction with Stored Payment Method\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_token\": \"the_token\",\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Transaction with Customer ID\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"customer_id\": \"customer_123\",\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Flask Checkout Endpoint\n\n```python\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route(\"/checkout\", methods=[\"POST\"])\ndef checkout():\n    nonce_from_the_client = request.form.get(\"payment_method_nonce\")\n    amount = request.form.get(\"amount\")\n\n    result = gateway.transaction.sale({\n        \"amount\": amount,\n        \"payment_method_nonce\": nonce_from_the_client,\n        \"options\": {\n            \"submit_for_settlement\": True\n        }\n    })\n\n    if result.is_success:\n        return jsonify({\n            \"success\": True,\n            \"transaction_id\": result.transaction.id\n        })\n    else:\n        return jsonify({\n            \"success\": False,\n            \"message\": result.message\n        }), 500\n```\n\n### Finding a Transaction\n\n```python\ntransaction = gateway.transaction.find(\"the_transaction_id\")\nprint(transaction.amount)\nprint(transaction.status)\nprint(transaction.credit_card_details.last_4)\n```\n\n### Refunding a Transaction\n\n**Full Refund:**\n```python\nresult = gateway.transaction.refund(\"the_transaction_id\")\n\nif result.is_success:\n    print(\"Refund successful\")\n```\n\n**Partial Refund:**\n```python\nresult = gateway.transaction.refund(\"the_transaction_id\", \"10.00\")\n\nif result.is_success:\n    print(\"Partial refund successful\")\n```\n\n### Voiding a Transaction\n\n```python\nresult = gateway.transaction.void(\"the_transaction_id\")\n\nif result.is_success:\n    print(\"Transaction voided\")\nelse:\n    print(\"Error: \" + result.message)\n```\n\n### Submitting for Settlement\n\n**Full Amount:**\n```python\nresult = gateway.transaction.submit_for_settlement(\"transaction_id\")\n\nif result.is_success:\n    print(\"Submitted for settlement\")\n```\n\n**Partial Amount:**\n```python\nresult = gateway.transaction.submit_for_settlement(\"transaction_id\", \"50.00\")\n\nif result.is_success:\n    print(\"Submitted for partial settlement\")\n```\n\n## Customer Management\n\n### Creating a Customer\n\n**Basic Customer:**\n```python\nresult = gateway.customer.create({\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"email\": \"john.doe@example.com\",\n    \"phone\": \"312-555-1234\"\n})\n\nif result.is_success:\n    print(\"Customer ID: \" + result.customer.id)\n```\n\n### Creating Customer with Company Information\n\n```python\nresult = gateway.customer.create({\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"company\": \"Acme Corp\",\n    \"email\": \"john.doe@example.com\",\n    \"phone\": \"312-555-1234\",\n    \"fax\": \"614-555-5678\",\n    \"website\": \"www.example.com\"\n})\n```\n\n### Creating Customer with Payment Method\n\n```python\nresult = gateway.customer.create({\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"email\": \"john.doe@example.com\",\n    \"payment_method_nonce\": nonce_from_the_client\n})\n\nif result.is_success:\n    customer_id = result.customer.id\n    payment_token = result.customer.payment_methods[0].token\n    print(f\"Customer ID: {customer_id}\")\n    print(f\"Payment Method Token: {payment_token}\")\n```\n\n### Creating Customer with Credit Card\n\n```python\nresult = gateway.customer.create({\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"email\": \"john.doe@example.com\",\n    \"credit_card\": {\n        \"number\": \"4111111111111111\",\n        \"expiration_date\": \"05/2025\",\n        \"cvv\": \"123\",\n        \"billing_address\": {\n            \"postal_code\": \"60614\"\n        }\n    }\n})\n\nif result.is_success:\n    token = result.customer.payment_methods[0].token\n    print(\"Payment method token: \" + token)\n```\n\n### Finding a Customer\n\n```python\ncustomer = gateway.customer.find(\"the_customer_id\")\nprint(customer.first_name)\nprint(customer.last_name)\nprint(customer.email)\nprint(customer.payment_methods)\n```\n\n### Updating a Customer\n\n```python\nresult = gateway.customer.update(\"the_customer_id\", {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Smith\",\n    \"email\": \"jane.smith@example.com\"\n})\n\nif result.is_success:\n    print(\"Customer updated\")\n```\n\n### Deleting a Customer\n\n```python\nresult = gateway.customer.delete(\"the_customer_id\")\n\nif result.is_success:\n    print(\"Customer deleted\")\n```\n\n### Searching for Customers\n\n```python\ncollection = gateway.customer.search(\n    braintree.CustomerSearch.first_name == \"John\",\n    braintree.CustomerSearch.last_name == \"Doe\"\n)\n\nfor customer in collection.items:\n    print(customer.id)\n    print(customer.email)\n```\n\n## Payment Method Management\n\n### Creating a Payment Method\n\n```python\nresult = gateway.payment_method.create({\n    \"customer_id\": \"customer_123\",\n    \"payment_method_nonce\": nonce_from_the_client\n})\n\nif result.is_success:\n    print(\"Payment Method Token: \" + result.payment_method.token)\n```\n\n### Creating Payment Method with Billing Address\n\n```python\nresult = gateway.payment_method.create({\n    \"customer_id\": \"customer_123\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"billing_address\": {\n        \"street_address\": \"123 Main St\",\n        \"locality\": \"Chicago\",\n        \"region\": \"IL\",\n        \"postal_code\": \"60614\"\n    }\n})\n```\n\n### Creating Payment Method with Verification\n\n```python\nresult = gateway.payment_method.create({\n    \"customer_id\": \"customer_123\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"options\": {\n        \"verify_card\": True\n    }\n})\n\nif result.is_success:\n    print(\"Payment method verified and created\")\n```\n\n### Finding a Payment Method\n\n```python\npayment_method = gateway.payment_method.find(\"the_token\")\nprint(payment_method.token)\nprint(payment_method.card_type)\n```\n\n### Updating a Payment Method\n\n**Set as Default:**\n```python\nresult = gateway.payment_method.update(\"the_token\", {\n    \"options\": {\n        \"make_default\": True\n    }\n})\n\nif result.is_success:\n    print(\"Payment method is now default\")\n```\n\n**Update Billing Address:**\n```python\nresult = gateway.payment_method.update(\"the_token\", {\n    \"billing_address\": {\n        \"street_address\": \"456 Oak Ave\",\n        \"locality\": \"Chicago\",\n        \"region\": \"IL\",\n        \"postal_code\": \"60614\",\n        \"options\": {\n            \"update_existing\": True\n        }\n    }\n})\n```\n\n### Deleting a Payment Method\n\n```python\nresult = gateway.payment_method.delete(\"the_token\")\n\nif result.is_success:\n    print(\"Payment method deleted\")\n```\n\n## Subscription Billing\n\n### Creating a Subscription\n\n**Basic Subscription:**\n```python\nresult = gateway.subscription.create({\n    \"payment_method_token\": \"the_token\",\n    \"plan_id\": \"plan_id\"\n})\n\nif result.is_success:\n    print(\"Subscription ID: \" + result.subscription.id)\n```\n\n### Creating Subscription with Price Override\n\n```python\nresult = gateway.subscription.create({\n    \"payment_method_token\": \"the_token\",\n    \"plan_id\": \"plan_id\",\n    \"price\": \"15.00\"\n})\n```\n\n### Creating Subscription with Add-ons and Discounts\n\n```python\nresult = gateway.subscription.create({\n    \"payment_method_token\": \"the_token\",\n    \"plan_id\": \"plan_id\",\n    \"add_ons\": {\n        \"add\": [\n            {\n                \"inherited_from_id\": \"add_on_id_1\",\n                \"amount\": \"10.00\"\n            }\n        ]\n    },\n    \"discounts\": {\n        \"add\": [\n            {\n                \"inherited_from_id\": \"discount_id_1\",\n                \"amount\": \"5.00\"\n            }\n        ]\n    }\n})\n```\n\n### Creating Subscription with Trial Period\n\n```python\nresult = gateway.subscription.create({\n    \"payment_method_token\": \"the_token\",\n    \"plan_id\": \"plan_id\",\n    \"trial_duration\": 14,\n    \"trial_duration_unit\": braintree.Subscription.TrialDurationUnit.Day,\n    \"trial_period\": True\n})\n```\n\n### Finding a Subscription\n\n```python\nsubscription = gateway.subscription.find(\"subscription_id\")\nprint(subscription.status)\nprint(subscription.price)\nprint(subscription.plan_id)\n```\n\n### Updating a Subscription\n\n```python\nresult = gateway.subscription.update(\"subscription_id\", {\n    \"price\": \"15.00\"\n})\n\nif result.is_success:\n    print(\"Subscription updated\")\n```\n\n### Updating Subscription Plan\n\n```python\nresult = gateway.subscription.update(\"subscription_id\", {\n    \"plan_id\": \"new_plan_id\",\n    \"price\": \"20.00\"\n})\n```\n\n### Canceling a Subscription\n\n```python\nresult = gateway.subscription.cancel(\"subscription_id\")\n\nif result.is_success:\n    print(\"Subscription canceled\")\n```\n\n### Retrieving All Plans\n\n```python\nplans = gateway.plan.all()\n\nfor plan in plans:\n    print(plan.id)\n    print(plan.name)\n    print(plan.price)\n```\n\n## Webhooks\n\n### Parsing Webhook Notifications\n\n```python\nwebhook_notification = gateway.webhook_notification.parse(\n    request.form[\"bt_signature\"],\n    request.form[\"bt_payload\"]\n)\n\nprint(webhook_notification.kind)\nprint(webhook_notification.timestamp)\n```\n\n### Flask Webhook Endpoint\n\n```python\nfrom flask import Flask, request\n\napp = Flask(__name__)\n\n@app.route('/webhooks', methods=['POST'])\ndef webhooks():\n    try:\n        webhook_notification = gateway.webhook_notification.parse(\n            request.form[\"bt_signature\"],\n            request.form[\"bt_payload\"]\n        )\n\n        # Handle different webhook types\n        if webhook_notification.kind == braintree.WebhookNotification.Kind.SubscriptionCanceled:\n            print(f\"Subscription {webhook_notification.subscription.id} canceled\")\n        elif webhook_notification.kind == braintree.WebhookNotification.Kind.SubscriptionChargedSuccessfully:\n            print(f\"Subscription {webhook_notification.subscription.id} charged\")\n        elif webhook_notification.kind == braintree.WebhookNotification.Kind.DisputeOpened:\n            print(f\"Dispute opened for transaction {webhook_notification.dispute.transaction.id}\")\n\n        return \"\", 200\n    except Exception as e:\n        print(f\"Error: {e}\")\n        return \"\", 400\n```\n\n### Django Webhook View\n\n```python\nfrom django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\n\n@csrf_exempt\ndef webhook(request):\n    try:\n        webhook_notification = gateway.webhook_notification.parse(\n            request.POST[\"bt_signature\"],\n            request.POST[\"bt_payload\"]\n        )\n\n        # Handle webhook\n        if webhook_notification.kind == braintree.WebhookNotification.Kind.SubscriptionWentPastDue:\n            subscription_id = webhook_notification.subscription.id\n            # Handle past due subscription\n\n        return HttpResponse(status=200)\n    except Exception as e:\n        return HttpResponse(status=400)\n```\n\n### Handling Subscription Webhooks\n\n```python\nwebhook_notification = gateway.webhook_notification.parse(\n    signature,\n    payload\n)\n\nif webhook_notification.kind == braintree.WebhookNotification.Kind.SubscriptionWentPastDue:\n    subscription_id = webhook_notification.subscription.id\n    # Handle past due subscription\nelif webhook_notification.kind == braintree.WebhookNotification.Kind.SubscriptionChargedSuccessfully:\n    subscription_id = webhook_notification.subscription.id\n    transaction_id = webhook_notification.subscription.transactions[0].id\n    # Handle successful charge\n```\n\n### Verifying Webhook Signatures\n\n```python\nverification_string = gateway.webhook_notification.verify(\"challenge_string\")\nprint(verification_string)\n```\n\n### Testing Webhooks\n\n```python\nsample_notification = gateway.webhook_testing.sample_notification(\n    braintree.WebhookNotification.Kind.SubscriptionWentPastDue,\n    \"subscription_id\"\n)\n\nwebhook_notification = gateway.webhook_notification.parse(\n    sample_notification['bt_signature'],\n    sample_notification['bt_payload']\n)\n\nprint(webhook_notification.kind)\nprint(webhook_notification.subscription.id)\n```\n\n## Advanced Features\n\n### Searching Transactions\n\n```python\ncollection = gateway.transaction.search(\n    braintree.TransactionSearch.amount >= \"10.00\",\n    braintree.TransactionSearch.amount <= \"100.00\",\n    braintree.TransactionSearch.status == braintree.Transaction.Status.Settled,\n    braintree.TransactionSearch.created_at >= \"2024-01-01\"\n)\n\nfor transaction in collection.items:\n    print(transaction.id)\n    print(transaction.amount)\n```\n\n### Transaction with Custom Fields\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"custom_fields\": {\n        \"order_id\": \"12345\",\n        \"user_type\": \"premium\"\n    },\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Transaction with Order ID\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"order_id\": \"order_123\",\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Holding in Escrow\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"100.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"service_fee_amount\": \"10.00\",\n    \"merchant_account_id\": \"submerchant_account_id\",\n    \"options\": {\n        \"submit_for_settlement\": True,\n        \"hold_in_escrow\": True\n    }\n})\n```\n\n### Transaction with Descriptor\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"descriptor\": {\n        \"name\": \"Company*Product\",\n        \"phone\": \"8004567890\",\n        \"url\": \"example.com\"\n    },\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n```\n\n### Storing Payment Method on Success\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"customer_id\": \"customer_123\",\n    \"options\": {\n        \"submit_for_settlement\": True,\n        \"store_in_vault_on_success\": True\n    }\n})\n\nif result.is_success:\n    payment_token = result.transaction.credit_card_details.token\n    print(f\"Payment method stored with token: {payment_token}\")\n```\n\n### Cloning a Transaction\n\n```python\nresult = gateway.transaction.clone_transaction(\n    \"original_transaction_id\",\n    {\n        \"amount\": \"20.00\",\n        \"options\": {\n            \"submit_for_settlement\": True\n        }\n    }\n)\n\nif result.is_success:\n    print(\"Cloned transaction ID: \" + result.transaction.id)\n```\n\n### Dispute Management\n\n**Finding a Dispute:**\n```python\ndispute = gateway.dispute.find(\"dispute_id\")\nprint(dispute.status)\nprint(dispute.amount)\nprint(dispute.reason)\n```\n\n**Accept Dispute:**\n```python\nresult = gateway.dispute.accept(\"dispute_id\")\n```\n\n**Add Text Evidence:**\n```python\nresult = gateway.dispute.add_text_evidence(\"dispute_id\", \"evidence_text\")\n```\n\n**Finalize Dispute:**\n```python\nresult = gateway.dispute.finalize(\"dispute_id\")\n```\n\n### Merchant Account Creation\n\n```python\nresult = gateway.merchant_account.create({\n    \"individual\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"email\": \"john.doe@example.com\",\n        \"date_of_birth\": \"1980-01-01\",\n        \"ssn\": \"123-45-6789\",\n        \"address\": {\n            \"street_address\": \"123 Main St\",\n            \"locality\": \"Chicago\",\n            \"region\": \"IL\",\n            \"postal_code\": \"60614\"\n        }\n    },\n    \"business\": {\n        \"legal_name\": \"John Doe Inc\",\n        \"dba_name\": \"JD Services\",\n        \"tax_id\": \"12-3456789\",\n        \"address\": {\n            \"street_address\": \"123 Main St\",\n            \"locality\": \"Chicago\",\n            \"region\": \"IL\",\n            \"postal_code\": \"60614\"\n        }\n    },\n    \"funding\": {\n        \"destination\": braintree.MerchantAccount.FundingDestination.Bank,\n        \"routing_number\": \"021000021\",\n        \"account_number\": \"1234567890\"\n    },\n    \"tos_accepted\": True,\n    \"master_merchant_account_id\": \"master_merchant_account_id\"\n})\n\nif result.is_success:\n    print(\"Merchant Account ID: \" + result.merchant_account.id)\n```\n\n## Error Handling\n\n### Checking Result Success\n\n```python\nresult = gateway.transaction.sale({\n    \"amount\": \"10.00\",\n    \"payment_method_nonce\": nonce_from_the_client,\n    \"options\": {\n        \"submit_for_settlement\": True\n    }\n})\n\nif result.is_success:\n    print(\"Transaction ID:\", result.transaction.id)\nelse:\n    print(\"Error:\", result.message)\n\n    # Check validation errors\n    for error in result.errors.deep_errors:\n        print(\"Error:\", error.code)\n        print(\"Message:\", error.message)\n        print(\"Attribute:\", error.attribute)\n```\n\n### Handling Validation Errors\n\n```python\nresult = gateway.customer.create({\n    \"email\": \"invalid-email\"\n})\n\nif not result.is_success:\n    for error in result.errors.deep_errors:\n        print(f\"Error Code: {error.code}\")\n        print(f\"Message: {error.message}\")\n        print(f\"Attribute: {error.attribute}\")\n```\n\n### Handling Not Found Errors\n\n```python\ntry:\n    customer = gateway.customer.find(\"nonexistent_id\")\nexcept braintree.exceptions.NotFoundError:\n    print(\"Customer not found\")\n```\n\n### Handling Authentication Errors\n\n```python\ntry:\n    result = gateway.transaction.sale({\n        \"amount\": \"10.00\",\n        \"payment_method_nonce\": nonce_from_the_client\n    })\nexcept braintree.exceptions.AuthenticationError:\n    print(\"Invalid API credentials\")\nexcept braintree.exceptions.AuthorizationError:\n    print(\"Not authorized to perform this action\")\n```\n\n## Common Patterns\n\n### Complete Flask Application Example\n\n```python\nfrom flask import Flask, request, jsonify, render_template\nimport braintree\nimport os\n\napp = Flask(__name__)\n\ngateway = braintree.BraintreeGateway(\n    braintree.Configuration(\n        braintree.Environment.Sandbox,\n        merchant_id=os.getenv('BRAINTREE_MERCHANT_ID'),\n        public_key=os.getenv('BRAINTREE_PUBLIC_KEY'),\n        private_key=os.getenv('BRAINTREE_PRIVATE_KEY')\n    )\n)\n\n@app.route('/')\ndef index():\n    return render_template('index.html')\n\n@app.route('/client_token', methods=['GET'])\ndef get_client_token():\n    try:\n        token = gateway.client_token.generate()\n        return jsonify({\"client_token\": token})\n    except Exception as e:\n        return jsonify({\"error\": str(e)}), 500\n\n@app.route('/checkout', methods=['POST'])\ndef checkout():\n    nonce_from_the_client = request.form.get(\"payment_method_nonce\")\n    amount = request.form.get(\"amount\")\n\n    result = gateway.transaction.sale({\n        \"amount\": amount,\n        \"payment_method_nonce\": nonce_from_the_client,\n        \"options\": {\n            \"submit_for_settlement\": True\n        }\n    })\n\n    if result.is_success:\n        return jsonify({\n            \"success\": True,\n            \"transaction_id\": result.transaction.id\n        })\n    else:\n        return jsonify({\n            \"success\": False,\n            \"message\": result.message\n        }), 500\n\nif __name__ == '__main__':\n    app.run(debug=True, port=3000)\n```\n\n### Customer Creation with Payment Method Workflow\n\n```python\n# Step 1: Create customer\nresult = gateway.customer.create({\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"email\": \"john.doe@example.com\",\n    \"payment_method_nonce\": nonce_from_the_client\n})\n\nif result.is_success:\n    customer_id = result.customer.id\n    payment_token = result.customer.payment_methods[0].token\n\n    # Step 2: Create subscription\n    sub_result = gateway.subscription.create({\n        \"payment_method_token\": payment_token,\n        \"plan_id\": \"monthly_plan\"\n    })\n\n    if sub_result.is_success:\n        print(\"Subscription ID:\", sub_result.subscription.id)\n```\n\n### Stored Payment Method Workflow\n\n```python\n# Step 1: Get customer\ncustomer = gateway.customer.find(\"customer_id\")\n\n# Step 2: Find default payment method\ndefault_payment_method = None\nfor pm in customer.payment_methods:\n    if pm.default:\n        default_payment_method = pm\n        break\n\n# Step 3: Use default payment method for transaction\nif default_payment_method:\n    result = gateway.transaction.sale({\n        \"amount\": \"25.00\",\n        \"payment_method_token\": default_payment_method.token,\n        \"options\": {\n            \"submit_for_settlement\": True\n        }\n    })\n\n    if result.is_success:\n        print(\"Transaction ID:\", result.transaction.id)\n```\n\n### Django Integration Example\n\n```python\n# views.py\nfrom django.http import JsonResponse\nfrom django.views.decorators.csrf import csrf_exempt\nimport braintree\nimport os\n\ngateway = braintree.BraintreeGateway(\n    braintree.Configuration(\n        braintree.Environment.Sandbox,\n        merchant_id=os.getenv('BRAINTREE_MERCHANT_ID'),\n        public_key=os.getenv('BRAINTREE_PUBLIC_KEY'),\n        private_key=os.getenv('BRAINTREE_PRIVATE_KEY')\n    )\n)\n\ndef client_token(request):\n    try:\n        token = gateway.client_token.generate()\n        return JsonResponse({\"client_token\": token})\n    except Exception as e:\n        return JsonResponse({\"error\": str(e)}, status=500)\n\n@csrf_exempt\ndef checkout(request):\n    if request.method == 'POST':\n        nonce = request.POST.get('payment_method_nonce')\n        amount = request.POST.get('amount')\n\n        result = gateway.transaction.sale({\n            \"amount\": amount,\n            \"payment_method_nonce\": nonce,\n            \"options\": {\n                \"submit_for_settlement\": True\n            }\n        })\n\n        if result.is_success:\n            return JsonResponse({\n                \"success\": True,\n                \"transaction_id\": result.transaction.id\n            })\n        else:\n            return JsonResponse({\n                \"success\": False,\n                \"message\": result.message\n            }, status=500)\n```\n\n### Subscription Renewal Handler\n\n```python\ndef handle_subscription_renewal(subscription_id):\n    try:\n        subscription = gateway.subscription.find(subscription_id)\n\n        if subscription.status == braintree.Subscription.Status.PastDue:\n            # Attempt to retry billing\n            result = gateway.subscription.retry_charge(subscription_id)\n\n            if result.is_success:\n                print(f\"Successfully charged subscription {subscription_id}\")\n            else:\n                print(f\"Failed to charge subscription: {result.message}\")\n\n    except braintree.exceptions.NotFoundError:\n        print(f\"Subscription {subscription_id} not found\")\n```\n"
  },
  {
    "path": "content/build/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyPA build frontend for creating Python sdists, wheels, and build metadata from pyproject.toml projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,packaging,pypa,build,wheel,sdist,pyproject\"\n---\n\n# build Python Package Guide\n\n## Golden Rule\n\nUse `build` as a local PEP 517 build frontend for projects that already define how they should be built in `pyproject.toml`. `build` creates artifacts such as source distributions and wheels; it does not manage dependencies and it does not publish releases.\n\n## Install\n\nPin the package version your workflow expects:\n\n```bash\npython -m pip install \"build==1.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"build==1.4.0\"\npoetry add \"build==1.4.0\"\n```\n\nUseful extras from PyPI:\n\n```bash\npython -m pip install \"build[virtualenv]==1.4.0\"\npython -m pip install \"build[uv]==1.4.0\"\n```\n\nNotes:\n\n- `build[virtualenv]` makes `build` use `virtualenv` for isolation instead of `venv`.\n- `build[uv]` is useful when you want `--installer uv` and do not already have `uv` installed separately.\n- On conda-forge, the package name is `python-build`.\n\n## Initialize A Buildable Project\n\n`build` expects a Python project root with a valid `pyproject.toml`. Keep the backend explicit instead of relying on fallback behavior.\n\nMinimal example:\n\n```toml\n[build-system]\nrequires = [\"setuptools>=69\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"example-pkg\"\nversion = \"0.1.0\"\ndescription = \"Example package\"\nrequires-python = \">=3.9\"\n```\n\nProject layout:\n\n```text\nexample-pkg/\n  pyproject.toml\n  src/\n    example_pkg/\n      __init__.py\n```\n\nFrom the project root:\n\n```bash\npython -m build\n```\n\nBy default, `build` creates an sdist from the source tree and then builds a wheel from that sdist into `dist/`.\n\n## Core CLI Usage\n\n### Build both artifacts\n\n```bash\npython -m build\n```\n\nThis is the normal release check before upload. If the wheel build fails here but works with ad hoc local commands, the sdist is probably missing files that your backend needs.\n\n### Build only one artifact\n\n```bash\npython -m build --sdist\npython -m build --wheel\n```\n\nUse this when CI or a release pipeline needs only one output kind.\n\n### Build another source directory or output directory\n\n```bash\npython -m build ../my-package --outdir /tmp/artifacts\n```\n\n### Print wheel metadata as JSON\n\n```bash\npython -m build --metadata\n```\n\n`--metadata` is for inspection only. It cannot be combined with `--sdist` or `--wheel`.\n\n### Pass backend-specific config settings\n\n```bash\npython -m build -C--global-option=--some-flag\npython -m build --config-json '{\"--global-option\": [\"--some-flag\"]}'\n```\n\nUse `--config-json` when the backend expects nested or repeated values. If a config key begins with `-`, pass it with `=` so the shell and CLI do not misread it as a top-level `build` option.\n\n### Control isolation\n\n```bash\npython -m build --installer uv\npython -m build --no-isolation\npython -m build --skip-dependency-check\n```\n\nGuidance:\n\n- Default isolated builds are safest for release automation.\n- `--no-isolation` is only for environments where build dependencies are already installed and intentionally controlled.\n- `--skip-dependency-check` is mainly for bootstrapping or specialized workflows; it will not fix a genuinely missing backend dependency.\n\n## Programmatic API\n\nUse the Python API when a tool needs to inspect requirements, prepare metadata, or build artifacts without shelling out to the CLI.\n\n### Build a wheel with `ProjectBuilder`\n\n```python\nfrom pathlib import Path\n\nfrom build import ProjectBuilder\n\nproject_dir = Path(\".\").resolve()\ndist_dir = project_dir / \"dist\"\ndist_dir.mkdir(exist_ok=True)\n\nbuilder = ProjectBuilder(project_dir)\nwheel_path = builder.build(\"wheel\", dist_dir)\n\nprint(wheel_path)\n```\n\n### Check unmet build dependencies before building\n\n```python\nfrom build import ProjectBuilder\n\nbuilder = ProjectBuilder(\".\")\nmissing = builder.check_dependencies(\"wheel\")\n\nif missing:\n    raise RuntimeError(f\"Missing build dependencies: {sorted(missing)}\")\n```\n\n### Read prepared metadata\n\n```python\nfrom pathlib import Path\n\nfrom build import ProjectBuilder\n\nbuilder = ProjectBuilder(\".\")\nmetadata_dir = builder.metadata_path(Path(\"build-metadata\"))\n\nprint(metadata_dir)\n```\n\n`metadata_path()` will use the backend metadata hook when available and otherwise fall back to building a wheel and extracting metadata from it.\n\n### Create and reuse an isolated environment\n\n```python\nfrom pathlib import Path\n\nfrom build import ProjectBuilder\nfrom build.env import DefaultIsolatedEnv\n\nproject_dir = Path(\".\").resolve()\n\nwith DefaultIsolatedEnv(installer=\"pip\") as env:\n    builder = ProjectBuilder.from_isolated_env(env, project_dir)\n    env.install(builder.build_system_requires)\n    env.install(builder.get_requires_for_build(\"wheel\"))\n    wheel_path = builder.build(\"wheel\", project_dir / \"dist\")\n\nprint(wheel_path)\n```\n\nThis is the right level if you are writing your own packaging automation around `build`.\n\n## Configuration And Environment Notes\n\n- There is no service authentication layer. Configuration is local: CLI flags, backend config settings, and the build backend declared in `pyproject.toml`.\n- `build` reads the project from `srcdir` or the current working directory. Run it from the project root unless you pass an explicit path.\n- Prefer an explicit `[build-system]` table. If no backend is specified, `build` falls back to `setuptools.build_meta:__legacy__`, which is a compatibility path, not a modern packaging default to depend on.\n- For isolated builds, `build` uses `pip` by default. Use `--installer uv` when that is part of your toolchain.\n- The `pyproject-build` script is equivalent to `python -m build` and is convenient in `pipx`-style environments.\n\n## Common Pitfalls\n\n- `build` does not upload artifacts. Use Twine, trusted publishing, or your release platform separately.\n- `build` does not resolve runtime dependencies for your app. It only installs the build requirements needed by the backend when isolation is enabled.\n- A missing or invalid `[build-system]` table causes build errors. Do not treat the legacy setuptools fallback as a substitute for proper project metadata.\n- The default wheel-from-sdist flow catches packaging mistakes. If files exist in your checkout but not in the sdist, the wheel step can fail or produce an incomplete artifact.\n- `--metadata` cannot be combined with `--sdist` or `--wheel`.\n- If backend config keys begin with `-`, pass them as `--config-setting=...` or with `-C...`; a space-separated form can be parsed as a `build` CLI option instead.\n- `--no-isolation` can hide missing build requirements by leaking packages from the current environment into the build.\n- Editable builds are part of the Python API surface, but they still depend on backend support for editable installs.\n\n## Version-Sensitive Notes For 1.4.0\n\n- `1.4.0` adds `--quiet`, `--metadata`, and support for the `UV` environment variable.\n- `1.3.0` added `--config-json` and dropped Python 3.8 support, so older automation snippets may be outdated.\n- The stable installation page lists verified compatibility for Python `3.9` through `3.13` plus `PyPy3`, while the PyPI classifiers already include Python `3.14`. If Python `3.14` support matters for a release pipeline, check the current changelog and live package metadata instead of assuming older blog posts are accurate.\n\n## Official Source URLs\n\n- Documentation: https://build.pypa.io/en/stable/\n- Installation: https://build.pypa.io/en/stable/installation.html\n- API documentation: https://build.pypa.io/en/stable/api.html\n- Differences from other tools: https://build.pypa.io/en/stable/differences.html\n- Changelog: https://build.pypa.io/en/stable/changelog.html\n- PyPI registry: https://pypi.org/project/build/\n"
  },
  {
    "path": "content/cachetools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cachetools package guide for in-memory caching and memoization in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cachetools,python,caching,memoization,lru,ttl\"\n---\n\n# cachetools Python Package Guide\n\n## Golden Rule\n\nUse `cachetools` for in-process caching and memoization, but treat its cache objects as local mutable state, not shared infrastructure. Cache classes are not thread-safe by default, TTL-based entries expire lazily, and memoization keys must match your function's real argument semantics.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"cachetools==7.0.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"cachetools==7.0.5\"\npoetry add \"cachetools==7.0.5\"\n```\n\nTyping note:\n\n```bash\npython -m pip install \"types-cachetools\"\n```\n\n`types-cachetools` is a separate stub package published on PyPI. Use it only if your type checker needs stubs that are not already bundled in your environment.\n\n## Setup And Configuration\n\n`cachetools` is an in-memory library. There is no auth layer, no service endpoint, and no required environment variables.\n\nThe important configuration choices are:\n\n- Which eviction policy fits the workload: `LRUCache`, `LFUCache`, `FIFOCache`, `RRCache`, `TTLCache`, or `TLRUCache`\n- What `maxsize` means for your data\n- Whether you need a custom `getsizeof` function\n- Whether access crosses threads and therefore needs a `lock`\n- Whether memoized calls need a custom key function\n\nAll cache classes derive from `Cache`. `maxsize` must be positive. If you want \"unbounded\", use `math.inf`.\n\n## Core Usage\n\n### Use a concrete cache directly\n\n```python\nfrom cachetools import LRUCache\n\ncache = LRUCache(maxsize=1024)\n\ncache[\"user:1\"] = {\"id\": 1, \"name\": \"Ada\"}\nuser = cache.get(\"user:1\")\n\nif user is None:\n    user = {\"id\": 1, \"name\": \"Ada\"}\n    cache[\"user:1\"] = user\n```\n\nChoose the cache class by eviction behavior:\n\n- `LRUCache`: evict least recently used items\n- `LFUCache`: evict least frequently used items\n- `FIFOCache`: evict oldest inserted items\n- `RRCache`: evict a random item\n- `TTLCache`: `LRUCache` plus per-item expiration\n- `TLRUCache`: time-aware eviction with a custom time-to-use function\n\n### Memoize a function with `@cached`\n\n```python\nfrom cachetools import LRUCache, cached\n\ncache = LRUCache(maxsize=512)\n\n@cached(cache)\ndef load_user(user_id: int) -> dict:\n    print(\"cache miss\")\n    return {\"id\": user_id}\n\nload_user(1)\nload_user(1)  # second call hits cache\n```\n\nUse `info=True` when you want cache statistics:\n\n```python\nfrom cachetools import LRUCache, cached\n\n@cached(cache=LRUCache(maxsize=128), info=True)\ndef square(value: int) -> int:\n    return value * value\n\nsquare(2)\nsquare(2)\nprint(square.cache_info())\n```\n\n### Add TTL-based expiration\n\n```python\nfrom cachetools import TTLCache, cached\n\ncache = TTLCache(maxsize=256, ttl=300)\n\n@cached(cache)\ndef fetch_settings(account_id: str) -> dict:\n    return {\"account_id\": account_id, \"feature_enabled\": True}\n```\n\n`TTLCache` removes expired entries only on the next mutating operation or when you call `expire()`. If memory pressure matters, explicitly clear expired items:\n\n```python\ncache.expire()\n```\n\n### Memoize instance methods with `@cachedmethod`\n\n```python\nfrom cachetools import TTLCache, cachedmethod\n\nclass UserService:\n    def __init__(self) -> None:\n        self.cache = TTLCache(maxsize=256, ttl=60)\n\n    @cachedmethod(lambda self: self.cache)\n    def get_profile(self, user_id: int) -> dict:\n        print(\"cache miss\")\n        return {\"id\": user_id, \"name\": f\"user-{user_id}\"}\n```\n\nThis pattern is usually better than a module-global cache because each instance controls its own cache size and lifecycle.\n\n### Use stable keys for shared or complex memoization\n\nBy default, positional and keyword arguments must be hashable, and different argument shapes may produce different cache keys. Use explicit key functions when that matters:\n\n```python\nfrom cachetools import LRUCache, cached\nfrom cachetools.keys import hashkey, typedkey\n\ncache = LRUCache(maxsize=128)\n\n@cached(cache=cache, key=lambda query, limit=20: hashkey(query.casefold(), limit))\ndef search(query: str, limit: int = 20) -> list[str]:\n    return [query] * limit\n\ntyped_cache = LRUCache(maxsize=128)\n\n@cached(cache=typed_cache, key=typedkey)\ndef normalize(value):\n    return str(value)\n```\n\n`typedkey` treats `3` and `3.0` as different keys. Use it when type distinctions matter.\n\n### Share one cache across functions safely\n\nIf multiple functions use the same cache object, give each function a distinct key prefix:\n\n```python\nfrom cachetools import LRUCache, cached\nfrom cachetools.keys import hashkey\n\nshared_cache = LRUCache(maxsize=256)\n\n@cached(shared_cache, key=lambda user_id: hashkey(\"user\", user_id))\ndef get_user(user_id: int) -> dict:\n    return {\"id\": user_id}\n\n@cached(shared_cache, key=lambda team_id: hashkey(\"team\", team_id))\ndef get_team(team_id: int) -> dict:\n    return {\"id\": team_id}\n```\n\nWithout a prefix, unrelated functions can collide if they receive the same arguments.\n\n## Threading And Stampede Control\n\nCache classes are not thread-safe. If the cache is shared across threads, wrap access with a lock through the memoizing decorators:\n\n```python\nfrom threading import RLock\n\nfrom cachetools import LRUCache, cached\n\ncache = LRUCache(maxsize=256)\nlock = RLock()\n\n@cached(cache=cache, lock=lock)\ndef fetch_product(product_id: int) -> dict:\n    return {\"id\": product_id}\n```\n\n`lock` only protects cache access. The wrapped function itself runs outside the lock.\n\nIf you need cache stampede protection for concurrent callers of the same function, use the decorator's `condition` support:\n\n```python\nfrom threading import Condition\n\nfrom cachetools import TTLCache, cached\n\ncache = TTLCache(maxsize=128, ttl=30)\ncondition = Condition()\n\n@cached(cache=cache, condition=condition)\ndef fetch_config(name: str) -> dict:\n    return {\"name\": name}\n```\n\nThis makes identical concurrent cache misses wait instead of recomputing the same value repeatedly.\n\n## Size Accounting With `getsizeof`\n\nBy default, cache size counts items, not payload size. If cache entries vary widely in size, pass `getsizeof`:\n\n```python\nfrom cachetools import LRUCache\n\ncache = LRUCache(\n    maxsize=10_000_000,\n    getsizeof=lambda value: len(value[\"payload\"]),\n)\n```\n\n`getsizeof` runs only when an item is inserted. If you mutate cached values later, the recorded size does not automatically change.\n\n## Common Pitfalls\n\n- Cache instances are not thread-safe. Use decorator `lock` support or your own synchronization when caches cross threads.\n- `TTLCache` expiration is lazy. Expired items may still occupy memory until the next mutation or an explicit `expire()`.\n- Function arguments used in memoization keys must be hashable unless you normalize them yourself.\n- Keyword ordering and default argument handling can change the key shape. If semantic equivalence matters, define an explicit `key=` function.\n- Sharing one cache object across multiple functions without namespaced keys can create collisions.\n- `getsizeof` is evaluated on insertion only. Mutating cached values can invalidate your size accounting.\n- `math.inf` is supported for unbounded growth, but an unbounded in-process cache can still exhaust memory.\n\n## Version-Sensitive Notes For 7.0.x\n\n- `cachetools 7.0.5` on PyPI requires Python `>=3.10`.\n- `7.0.5` includes minor `@cachedmethod` performance improvements, and `7.0.4` fixed and documented `@cachedmethod.cache_key` behavior.\n- In `7.0.0`, `cachedmethod()` changed in ways that break some older examples: returning `None` from `cache(self)` is no longer supported, cache-related decorator attributes became properties, and using `cachedmethod()` together with `classmethod()` is deprecated.\n- If you copy examples written for `cachetools 5.x` or `6.x`, re-check method-level caching and decorator attribute access against the `7.x` docs before reusing them unchanged.\n\n## Official Sources Used\n\n- Docs: https://cachetools.readthedocs.io/en/latest/\n- API docs: https://cachetools.readthedocs.io/en/latest/#cachetools\n- PyPI: https://pypi.org/project/cachetools/\n- Changelog: https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst\n"
  },
  {
    "path": "content/cairosvg/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"CairoSVG Python package guide for converting SVG inputs to PNG, PDF, PS, and SVG outputs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.8.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cairosvg,svg,graphics,rendering,png,pdf,postscript,cli\"\n---\n\n# CairoSVG Python Package Guide\n\n## Golden Rule\n\nUse `cairosvg` when you need a pure-Python entry point for converting static SVG content into `png`, `pdf`, `ps`, or `svg` outputs. Treat it as a renderer for trusted, mostly static SVG/CSS content, not as a full browser engine: JavaScript, animation, advanced filters, and webfont behavior are limited.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"CairoSVG==2.8.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"CairoSVG==2.8.2\"\npoetry add \"CairoSVG==2.8.2\"\n```\n\nNative dependency note:\n\n- CairoSVG depends on the Cairo graphics library plus `libffi`.\n- Linux/macOS environments usually need system packages for Cairo available before import-time rendering works.\n- The official install page calls out `cairo`, `libffi`, and a C compiler toolchain as the usual prerequisites.\n\nIf installation succeeds but conversion fails at import time, check that the runtime can load the native Cairo library.\n\n## Initialize And Convert\n\nThe public API is module-level conversion helpers:\n\n- `cairosvg.svg2png(...)`\n- `cairosvg.svg2pdf(...)`\n- `cairosvg.svg2ps(...)`\n- `cairosvg.svg2svg(...)`\n\nEach helper accepts one input source at a time:\n\n- `url=...` for a local path or remote URL\n- `file_obj=...` for an open file-like object\n- `bytestring=...` for SVG bytes or a Unicode string in `2.8.2`\n\nEach helper returns output bytes unless you pass `write_to=...`.\n\n### Convert a local SVG file to PNG bytes\n\n```python\nimport cairosvg\n\npng_bytes = cairosvg.svg2png(url=\"diagram.svg\")\n\nwith open(\"diagram.png\", \"wb\") as f:\n    f.write(png_bytes)\n```\n\n### Convert a string or bytes payload directly\n\n```python\nimport cairosvg\n\nsvg = \"\"\"\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"120\" height=\"40\">\n  <rect width=\"120\" height=\"40\" fill=\"#0b7285\" />\n  <text x=\"12\" y=\"26\" fill=\"white\">Hello</text>\n</svg>\n\"\"\"\n\ncairosvg.svg2pdf(bytestring=svg, write_to=\"hello.pdf\")\n```\n\n### Convert to a file-like object\n\n```python\nfrom io import BytesIO\nimport cairosvg\n\noutput = BytesIO()\ncairosvg.svg2png(url=\"diagram.svg\", write_to=output)\n\npng_bytes = output.getvalue()\n```\n\n## Core Usage\n\n### Control output size and resolution\n\nThe most useful rendering parameters are:\n\n- `dpi`: pixel density used for CSS absolute units\n- `scale`: multiply the rendered output size\n- `parent_width` and `parent_height`: resolve percentage-based SVG dimensions\n- `output_width` and `output_height`: force final output dimensions\n\n```python\nimport cairosvg\n\ncairosvg.svg2png(\n    url=\"chart.svg\",\n    write_to=\"chart@2x.png\",\n    dpi=192,\n    output_width=1600,\n    output_height=900,\n)\n```\n\nUse `parent_width` or `parent_height` when the SVG relies on percentages and otherwise renders at an unexpected size.\n\n### Convert directly from a URL\n\n```python\nimport cairosvg\n\ncairosvg.svg2pdf(\n    url=\"https://example.com/assets/report.svg\",\n    write_to=\"report.pdf\",\n)\n```\n\nThis works for remote assets, but any linked images, stylesheets, or nested SVG resources still need to be reachable from the runtime environment.\n\n### Use the CLI for shell pipelines\n\n```bash\ncairosvg input.svg -f png -o output.png\ncairosvg input.svg -f pdf -o output.pdf\ncat input.svg | cairosvg -f png -o output.png\n```\n\nCommon CLI flags from the official docs:\n\n- `-f, --format`: `pdf`, `png`, `ps`, or `svg`\n- `-o, --output`: output filename\n- `-d, --dpi`: DPI for CSS unit conversion\n- `-W, --width` and `-H, --height`: parent container size\n- `-s, --scale`: scale factor\n- `--output-width` and `--output-height`: final dimensions\n- `-u, --unsafe`: resolve XML entities and allow very large files\n\n## Configuration And Environment\n\nCairoSVG has no service authentication or persistent client configuration. Most configuration is per-call or per-command:\n\n- install the right package version\n- ensure Cairo and font libraries are available on the host\n- choose whether to read from local files, file-like objects, raw SVG content, or remote URLs\n- pass explicit sizing parameters when the source SVG uses percentages or relies on CSS units\n\nFont behavior is environment-sensitive. CairoSVG uses the host font stack through Cairo, so missing fonts on the machine usually change output rendering.\n\n## Common Pitfalls\n\n### `unsafe=True` is for trusted input only\n\nThe `unsafe` flag enables XML entity resolution and very large files. The docs warn that this is vulnerable to XXE-style issues and denial-of-service conditions. Do not enable it for untrusted SVG content.\n\n### It does not implement the full browser SVG model\n\nThe support docs explicitly call out important limits:\n\n- animations are not supported\n- no DOM, no JavaScript, and no interactive SVG behavior\n- only a small subset of filter effects is implemented\n- `@font-face` is not supported in the documented feature set\n\nIf an SVG depends on browser-only behavior, headless browser rendering is often a better fit than CairoSVG.\n\n### Fonts and CSS can render differently across machines\n\nIf text layout or icon rendering changes between environments:\n\n- verify the needed fonts are installed on the host\n- avoid assuming browser webfont loading behavior\n- test the exact runtime image or container used in production\n\n### Percentage-based SVG sizes often need a parent size\n\nAn SVG that relies on percentage width or height may render too small, too large, or fail to match browser output unless you pass `parent_width` and `parent_height` or the CLI `-W` and `-H` flags.\n\n### Output format naming is slightly inconsistent across official sources\n\nThe current docs page documents `png`, `pdf`, `ps`, and `svg`. The PyPI page and repository README also mention EPS output, but the docs page does not currently document a public `svg2eps` API or `-f eps` CLI flag. For agent-generated code, stick to the four formats documented on the official user docs unless you verify EPS behavior against the installed version.\n\n## Version-Sensitive Notes\n\n- Version used here `2.8.2` matches the current PyPI release as of March 12, 2026.\n- The CairoSVG website still contains stale version signals, including references to Python 3.6+ and a homepage note pointing at `CairoSVG 2.7.1`. Prefer PyPI and the GitHub releases page for current package-version and Python-support facts.\n- GitHub release notes for `2.8.1` and `2.8.2` mention broader input compatibility for `file_obj` and `bytestring`. If you are supporting older `2.8.0` or earlier environments, be more conservative and normalize SVG input to bytes.\n\n## Official Sources\n\n- Documentation: https://cairosvg.org/documentation/\n- SVG support notes: https://cairosvg.org/documentation/index.html#how-good-is-cairosvg-at-following-the-specification\n- Installation notes and current release metadata: https://pypi.org/project/CairoSVG/\n- Repository README: https://github.com/Kozea/CairoSVG\n- Releases: https://github.com/Kozea/CairoSVG/releases\n"
  },
  {
    "path": "content/camelot-py/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Camelot Python package for extracting tables from text-based PDFs into pandas DataFrames\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"camelot,pdf,table-extraction,pandas,dataframe,etl\"\n---\n\n# Camelot Python Package Guide\n\n## Golden Rule\n\nUse `camelot-py` only for text-based PDFs, not scanned image PDFs. Pick the parsing flavor deliberately: `lattice` for tables with visible ruling lines, `stream` for whitespace-aligned tables, and `network` or `hybrid` only when the default approaches need more control.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"camelot-py==1.0.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"camelot-py==1.0.9\"\npoetry add \"camelot-py==1.0.9\"\nconda install -c conda-forge camelot-py\n```\n\nOptional extras from upstream package metadata:\n\n```bash\npython -m pip install \"camelot-py[plot]==1.0.9\"\npython -m pip install \"camelot-py[ghostscript]==1.0.9\"\n```\n\nInstall notes:\n\n- `1.0.x` uses `pdfium` via `pypdfium2` as the default image backend for `lattice`, so plain `pip install camelot-py` is usually enough for the default path.\n- The Read the Docs install page still shows `camelot-py[base]`; for `1.0.9`, the published package metadata already includes the core runtime dependencies directly.\n- If you switch to `backend=\"ghostscript\"`, install Ghostscript itself with your system package manager and the Python `ghostscript` extra.\n\n## Setup And Initialization\n\nCamelot is a local parsing library. There is no API key or service authentication step.\n\nTypical import and first read:\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\"report.pdf\")\nprint(tables.n)\n```\n\nImportant defaults from the official API:\n\n- `pages=\"1\"` by default, so it will only parse the first page unless you ask for more\n- `flavor=\"lattice\"` by default\n- `parallel=False` by default\n- `filepath` can be a local path, a `Path`, a file-like object, or a URL\n\n## Core Usage\n\n### Extract a ruled table with the default `lattice` flavor\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\n    \"report.pdf\",\n    pages=\"1,2\",\n    flavor=\"lattice\",\n)\n\ntable = tables[0]\nprint(table.parsing_report)\nprint(table.df.head())\ntable.df.to_csv(\"report-page-1-table-1.csv\", index=False)\n```\n\nUse `table.parsing_report` as a quick quality check before trusting the output.\n\n### Extract whitespace-aligned tables with `stream`\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\n    \"financials.pdf\",\n    pages=\"all\",\n    flavor=\"stream\",\n    table_areas=[\"43,535,555,120\"],\n    columns=[\"72,95,209,327,442,529\"],\n    split_text=True,\n)\n\ndf = tables[0].df\n```\n\n`table_areas`, `columns`, `split_text`, `edge_tol`, `row_tol`, and `column_tol` are the knobs you will use most when `stream` merges or splits cells incorrectly.\n\n### Export all tables in one pass\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\"report.pdf\", pages=\"1-5\")\ntables.export(\"tables.csv\", f=\"csv\", compress=True)\n```\n\nCamelot can export `csv`, `json`, `excel`, `html`, `markdown`, and `sqlite`.\n\n### Read encrypted PDFs\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\n    \"protected.pdf\",\n    password=\"userpass\",\n    pages=\"all\",\n)\n```\n\nIf decryption fails, verify the password first before changing extraction settings.\n\n### Use visual debugging when extraction is off\n\nInstall the plotting extra first:\n\n```bash\npython -m pip install \"camelot-py[plot]==1.0.9\"\n```\n\nThen inspect how Camelot sees the page:\n\n```python\nimport camelot\n\ntables = camelot.read_pdf(\"edge_tol.pdf\", flavor=\"stream\")\ncamelot.plot(tables[0], kind=\"contour\").show()\n```\n\nThis is often the fastest way to tune `table_areas`, `columns`, `edge_tol`, or `process_background`.\n\n## Configuration Notes\n\n- There is no global config file that agents need to manage. Most behavior is controlled per call to `camelot.read_pdf(...)`.\n- `layout_kwargs` passes `pdfminer.six` `LAParams` options through to the text layout stage. Use it when PDF text grouping is wrong.\n- For `lattice`, `backend` defaults to `\"pdfium\"` and `use_fallback=True`. You can switch to `\"ghostscript\"` or provide a custom conversion backend object if the image conversion step is the problem.\n- `parallel=True` uses all available CPU cores for page processing. It can speed up long runs, but it also increases memory pressure.\n\n## Command-Line Interface\n\nThe package installs a `camelot` CLI alongside the Python API. Start with:\n\n```bash\ncamelot --help\n```\n\nThe CLI exposes flavor-specific subcommands such as `lattice`, `stream`, `network`, and `hybrid`. Use it when you just need extracted files and do not need to inspect `Table.df` or `parsing_report` programmatically.\n\n## Common Pitfalls\n\n- Camelot does not work on scanned or image-only PDFs. If you cannot select text in the PDF viewer, use OCR first or use a different tool.\n- Agents often forget that only page 1 is parsed by default. Set `pages=\"all\"` or an explicit range.\n- `lattice` is not a universal default. For borderless tables, switch to `flavor=\"stream\"` early instead of over-tuning `lattice`.\n- `stream` and `network` parsing are sensitive to `columns`, `table_areas`, and text layout. Use `camelot.plot()` to debug rather than guessing coordinates blindly.\n- Large multi-page PDFs can consume a lot of RAM. The project FAQ recommends chunking page ranges and exporting each chunk incrementally.\n- When using `ghostscript` on macOS, the docs call out that the `libgs` library may need to be symlinked into `~/lib` if discovery fails.\n- `tables.export(\"out.csv\", f=\"csv\")` writes page and table suffixes into filenames. If you expect one single file artifact, set `compress=True` or export individual tables yourself.\n\n## Version-Sensitive Notes For 1.0.9\n\n- `camelot-py 1.0.9` supports Python `3.8` through `3.13` in the upstream project metadata.\n- Since `v1.0.0`, `pdfium` replaced Ghostscript as the default image conversion backend. Older blog posts that assume Ghostscript is mandatory are stale.\n- The official docs root `https://camelot-py.readthedocs.io/` and the source URL `https://camelot-py.readthedocs.io/en/latest/` currently surface `v1.0.0` pages in some places, while the current `1.0.9` docs are under `https://camelot-py.readthedocs.io/en/master/`. Use the `master` docs when checking `1.0.9` behavior.\n- The current parser flavors are `lattice`, `stream`, `network`, and `hybrid`. Older examples that mention only `lattice` and `stream` are incomplete for the current release.\n"
  },
  {
    "path": "content/cartopy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cartopy Python package guide for cartographic plotting, CRS transforms, and geospatial data overlays with Matplotlib\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.25.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cartopy,python,gis,maps,matplotlib,projection,crs,geospatial\"\n---\n\n# Cartopy Python Package Guide\n\n## Golden Rule\n\nUse `cartopy` together with Matplotlib, choose the map `projection` for the axes, and explicitly pass `transform=` for any plotted data unless the data are already in the target projection. Most bad Cartopy plots come from mixing up those two concepts.\n\n## What Cartopy Is Good At\n\nCartopy is a map projection and geospatial plotting library layered on top of Matplotlib. Use it when you need:\n\n- map axes with real geographic projections\n- automatic reprojection of points, lines, polygons, rasters, and vectors\n- quick access to Natural Earth features like coastlines, borders, land, and lakes\n- shapefile readers and tiled or remote map sources for scientific or GIS-style plots\n\nIf you only need tabular CRS transforms with no map rendering, `pyproj` is usually the smaller dependency. If you need GIS data manipulation before plotting, combine Cartopy with GeoPandas, Shapely, Rasterio, or xarray rather than expecting Cartopy to replace them.\n\n## Install\n\nFor current releases, Cartopy publishes binary wheels for major operating systems, so `pip install` is the default path.\n\n```bash\npython -m pip install \"cartopy==0.25.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"cartopy==0.25.0\"\npoetry add \"cartopy==0.25.0\"\nconda install -c conda-forge cartopy\n```\n\nUseful optional extras from PyPI:\n\n```bash\npython -m pip install \"cartopy[plotting,ows,srtm]==0.25.0\"\n```\n\nNotes:\n\n- PyPI lists extras including `plotting`, `ows`, `srtm`, `speedups`, `doc`, and `test`.\n- If a source build happens instead of installing a wheel, the docs list native dependency requirements such as PROJ plus supported versions of Matplotlib, Shapely, pyproj, and pyshp.\n- The stable docs are published as `0.25.0.post2`, while the PyPI package release is `0.25.0`. Use the stable docs for behavior, but pin the package with the PyPI version.\n\n## Initialize A Map\n\nThe simplest working map is a GeoAxes with a projection:\n\n```python\nimport cartopy.crs as ccrs\nimport matplotlib.pyplot as plt\n\nfig = plt.figure(figsize=(8, 4))\nax = plt.axes(projection=ccrs.PlateCarree())\nax.set_global()\nax.coastlines()\n\nplt.show()\n```\n\nWhat matters:\n\n- `projection=` controls how the map is drawn\n- `GeoAxes` methods such as `coastlines()`, `set_extent()`, and `gridlines()` become available after creating the projected axes\n- save figures before `plt.show()` if you need file output in batch code\n\n## Plot Data Correctly\n\nAlways tell Cartopy the CRS of the input data.\n\n```python\nimport numpy as np\nimport cartopy.crs as ccrs\nimport matplotlib.pyplot as plt\n\nlon = np.linspace(-130, -60, 50)\nlat = np.linspace(20, 55, 40)\nlon2d, lat2d = np.meshgrid(lon, lat)\ndata = np.sin(np.deg2rad(lat2d)) + np.cos(np.deg2rad(lon2d))\n\ndata_crs = ccrs.PlateCarree()\n\nfig = plt.figure(figsize=(9, 4))\nax = plt.axes(projection=ccrs.LambertConformal())\nax.set_extent([-130, -60, 20, 55], crs=data_crs)\nax.coastlines()\n\nmesh = ax.contourf(lon, lat, data, transform=data_crs, cmap=\"viridis\")\nplt.colorbar(mesh, ax=ax, shrink=0.7)\nplt.show()\n```\n\nRule of thumb:\n\n- `projection=` is for the destination map\n- `transform=` is for the CRS your input coordinates are already in\n- if your longitude and latitude arrays are ordinary geographic coordinates, `ccrs.PlateCarree()` is usually the right `transform`\n\n## Common GeoAxes Workflow\n\nAdd built-in features and constrain the view:\n\n```python\nimport cartopy.crs as ccrs\nimport cartopy.feature as cfeature\nimport matplotlib.pyplot as plt\n\nfig = plt.figure(figsize=(10, 5))\nax = plt.axes(projection=ccrs.Mercator())\nax.set_extent([-125, -66.5, 24, 50], crs=ccrs.PlateCarree())\n\nax.add_feature(cfeature.LAND, facecolor=\"#f5f1e8\")\nax.add_feature(cfeature.OCEAN, facecolor=\"#d9ebff\")\nax.add_feature(cfeature.BORDERS, linewidth=0.5)\nax.add_feature(cfeature.STATES, linewidth=0.3)\nax.coastlines(resolution=\"50m\", linewidth=0.7)\n\ngridliner = ax.gridlines(draw_labels=True, linewidth=0.4, alpha=0.5)\ngridliner.top_labels = False\ngridliner.right_labels = False\n\nplt.show()\n```\n\nUseful feature constants include `LAND`, `OCEAN`, `COASTLINE`, `BORDERS`, `LAKES`, `RIVERS`, and `STATES`.\n\n## Working With Shapefiles And Natural Earth Data\n\nCartopy can fetch and read standard datasets for you:\n\n```python\nfrom cartopy.io import shapereader\n\nfilename = shapereader.natural_earth(\n    resolution=\"110m\",\n    category=\"cultural\",\n    name=\"admin_0_countries\",\n)\n\nreader = shapereader.Reader(filename)\n\nfor record in reader.records():\n    print(record.attributes[\"NAME_LONG\"])\n    break\n```\n\nThis is convenient, but it has operational implications:\n\n- first use may download Natural Earth or other external data into Cartopy's data directory\n- a fresh CI runner or offline container can fail or hang if the dataset is not already cached\n- if you need reproducible offline execution, pre-download required features instead of depending on first-run network access\n\nSince Cartopy 0.23, the built-in feature downloader can be invoked as `python -m cartopy.feature.download` or with the installed `cartopy-feature-download` CLI.\n\n## Configuration And Data Paths\n\nCartopy's top-level `cartopy.config` dictionary controls where packaged and downloaded data live.\n\nRelevant keys:\n\n- `pre_existing_data_dir`: read-only directory to check first for standard datasets\n- `data_dir`: writable directory where Cartopy stores downloaded datasets\n- `repo_data_dir`: repository-shipped data path, mainly relevant to packagers\n\nExample:\n\n```python\nimport cartopy\n\ncartopy.config[\"data_dir\"] = \"/tmp/cartopy-data\"\ncartopy.config[\"pre_existing_data_dir\"] = \"/opt/cartopy-data\"\n```\n\nPractical guidance:\n\n- set these before code that triggers downloads\n- in production, prefer a pre-populated shared data directory over ad hoc downloads\n- in containers, mount a writable cache or bake the data into the image\n\n## OGC, Raster, And Tile Sources\n\nCartopy includes interfaces under `cartopy.io` for:\n\n- shapefiles\n- raster reprojection utilities\n- image tiles\n- OGC clients\n- SRTM elevation sources\n\nUse these when you want Cartopy to stay responsible for map reprojection. If your raster pipeline is already built around Rasterio, xarray, or rioxarray, it is often cleaner to prepare the data there and use Cartopy mainly for the final plotted projection.\n\n## Performance Notes\n\n- Large shapefiles and dense coastlines can dominate render time. Use smaller Natural Earth resolutions like `110m` or `50m` unless you truly need `10m`.\n- Reprojecting high-resolution rasters on every draw is expensive. Reuse transformed outputs when plotting the same dataset repeatedly.\n- The docs note that you can set `PYPROJ_GLOBAL_CONTEXT=ON` for faster projection calculations if thread safety is not a concern in your application.\n- For static reporting jobs, save the figure once rather than repeatedly redrawing interactive windows.\n\n## Common Pitfalls\n\n### Forgetting `transform=`\n\nThis is the most common mistake. A plot can appear correct in `PlateCarree` and then become wrong after switching projections because Cartopy assumes the source data CRS matches the axes projection when `transform` is omitted.\n\n### Assuming all first-run environments can download data\n\nFeature and shapefile helpers may need network access the first time they run. Cache or prefetch the data for CI, containers, and air-gapped systems.\n\n### Mixing Shapely or Matplotlib examples from older releases\n\nCartopy `0.25` deprecated older path conversion helpers:\n\n- `path_to_geos` and `geos_to_path` are deprecated in favor of `path_to_shapely` and `shapely_to_path`\n- `cartopy.mpl.clip_path` is deprecated without replacement\n- `path_segments` is deprecated\n\nIf copied code uses those names, update it before adding more logic around it.\n\n### Using old gridliner label attributes\n\nOlder examples may use `xlabels_top`, `xlabels_bottom`, `ylabels_left`, or `ylabels_right`. Current Cartopy examples use `top_labels`, `bottom_labels`, `left_labels`, and `right_labels`.\n\n### Treating Cartopy as a full GIS stack\n\nCartopy is excellent at projected plotting and transformation-aware map rendering. It is not the right place for heavy vector cleaning, tabular joins, or complex raster I/O pipelines.\n\n## Version-Sensitive Notes For `0.25.0`\n\n- PyPI package version: `0.25.0`\n- Stable docs version: `0.25.0.post2`\n- `0.25` raised the minimum supported Shapely version to `2.0`\n- `0.25` added new projection-related behavior such as Orthographic `rotation` and the Spilhaus projection, with Spilhaus requiring PROJ `9.6+`\n- `0.25` also deprecated older path-conversion helpers, so examples written for `0.24` or earlier may need edits even if the broad plotting workflow is unchanged\n\n## Official Sources Used For This Guide\n\n- Stable docs landing page: `https://cartopy.readthedocs.io/stable/`\n- Installation: `https://cartopy.readthedocs.io/stable/installing.html`\n- Getting started and Matplotlib interface: `https://cartopy.readthedocs.io/stable/getting_started/index.html`\n- Matplotlib intro: `https://cartopy.readthedocs.io/stable/matplotlib/intro.html`\n- Projection and transform tutorial: `https://cartopy.readthedocs.io/stable/tutorials/understanding_transform.html`\n- API reference: `https://cartopy.readthedocs.io/stable/reference/index.html`\n- Feature interface: `https://cartopy.readthedocs.io/stable/reference/feature.html`\n- I/O reference: `https://cartopy.readthedocs.io/stable/reference/io.html`\n- Configuration reference: `https://cartopy.readthedocs.io/stable/reference/config.html`\n- `0.25` release notes: `https://cartopy.readthedocs.io/stable/whatsnew/v0.25.html`\n- `0.23` release notes for offline feature download utility: `https://cartopy.readthedocs.io/latest/whatsnew/v0.23.html`\n- PyPI registry page: `https://pypi.org/project/Cartopy/`\n"
  },
  {
    "path": "content/cassandra-driver/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"DataStax Python Driver for Apache Cassandra and Astra DB applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.29.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cassandra,datastax,astra,cql,database,python\"\n---\n\n# cassandra-driver Python Package Guide\n\n## Golden Rule\n\nUse the official `cassandra-driver` package for Cassandra-compatible clusters, and treat the DataStax 3.29 docs as the primary guide even though the docs site lags the current PyPI patch release. As of March 12, 2026, PyPI publishes `3.29.3`, while the maintained docs root is still the `3.29` documentation set.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"cassandra-driver==3.29.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"cassandra-driver==3.29.3\"\npoetry add \"cassandra-driver==3.29.3\"\n```\n\nIf you build from source or need better throughput, read the installation and performance docs before assuming the pure-Python fallback is good enough. The driver can use optional C extensions and a `libev` reactor for materially better performance.\n\n## Initialize A Local Or Self-Managed Cluster Connection\n\nThe usual entry point is `Cluster`, then `connect()` to create a `Session`:\n\n```python\nfrom cassandra.cluster import Cluster\n\ncluster = Cluster([\"127.0.0.1\"], port=9042)\nsession = cluster.connect()\n\nrows = session.execute(\"SELECT release_version FROM system.local\")\nfor row in rows:\n    print(row.release_version)\n\ncluster.shutdown()\n```\n\nConnect straight to a keyspace when that is the steady-state target:\n\n```python\nfrom cassandra.cluster import Cluster\n\ncluster = Cluster([\"db1.internal\", \"db2.internal\"])\nsession = cluster.connect(\"app_keyspace\")\n```\n\n## Username/Password Authentication\n\nFor clusters using password auth, pass `PlainTextAuthProvider` into `Cluster`:\n\n```python\nfrom cassandra.auth import PlainTextAuthProvider\nfrom cassandra.cluster import Cluster\n\nauth_provider = PlainTextAuthProvider(\n    username=\"cassandra\",\n    password=\"cassandra\",\n)\n\ncluster = Cluster(\n    [\"127.0.0.1\"],\n    auth_provider=auth_provider,\n)\nsession = cluster.connect()\n```\n\nKeep credentials in environment variables or your secret manager, not in source files.\n\n## TLS / SSL Configuration\n\nUse a Python `ssl.SSLContext` and pass it as `ssl_context` when the cluster requires TLS:\n\n```python\nimport os\nimport ssl\n\nfrom cassandra.auth import PlainTextAuthProvider\nfrom cassandra.cluster import Cluster\n\nssl_context = ssl.create_default_context(cafile=os.environ[\"CASSANDRA_CA_CERT\"])\nssl_context.check_hostname = True\nssl_context.verify_mode = ssl.CERT_REQUIRED\n\ncluster = Cluster(\n    [\"db1.internal\"],\n    ssl_context=ssl_context,\n    auth_provider=PlainTextAuthProvider(\n        username=os.environ[\"CASSANDRA_USERNAME\"],\n        password=os.environ[\"CASSANDRA_PASSWORD\"],\n    ),\n)\nsession = cluster.connect(\"app_keyspace\")\n```\n\n## Connect To Astra DB\n\nFor Astra DB, use the secure connect bundle and an auth provider:\n\n```python\nimport os\n\nfrom cassandra.auth import PlainTextAuthProvider\nfrom cassandra.cluster import Cluster\n\ncloud = {\n    \"secure_connect_bundle\": os.environ[\"ASTRA_SECURE_CONNECT_BUNDLE\"],\n}\n\nauth_provider = PlainTextAuthProvider(\n    os.environ[\"ASTRA_CLIENT_ID\"],\n    os.environ[\"ASTRA_CLIENT_SECRET\"],\n)\n\ncluster = Cluster(cloud=cloud, auth_provider=auth_provider)\nsession = cluster.connect()\n```\n\nTypical environment variables:\n\n```bash\nASTRA_SECURE_CONNECT_BUNDLE=/absolute/path/secure-connect-database.zip\nASTRA_CLIENT_ID=...\nASTRA_CLIENT_SECRET=...\n```\n\n## Core Query Patterns\n\n### Simple reads\n\nUse `SimpleStatement` when you need per-query settings such as consistency level or fetch size:\n\n```python\nfrom cassandra import ConsistencyLevel\nfrom cassandra.cluster import Cluster\nfrom cassandra.query import SimpleStatement\n\ncluster = Cluster([\"127.0.0.1\"])\nsession = cluster.connect(\"app_keyspace\")\n\nstatement = SimpleStatement(\n    \"SELECT id, email FROM users\",\n    consistency_level=ConsistencyLevel.LOCAL_QUORUM,\n    fetch_size=500,\n)\n\nfor row in session.execute(statement):\n    print(row.id, row.email)\n```\n\n### Prepared statements\n\nPrefer prepared statements for repeated queries with parameters:\n\n```python\nfrom cassandra.cluster import Cluster\n\ncluster = Cluster([\"127.0.0.1\"])\nsession = cluster.connect(\"app_keyspace\")\n\nprepared = session.prepare(\n    \"INSERT INTO users (id, email, created_at) VALUES (?, ?, ?)\"\n)\n\nsession.execute(prepared, (user_id, email, created_at))\n```\n\nUse `?` placeholders for prepared statements. Non-prepared statements passed to `session.execute(query, parameters)` use `%s` or `%(name)s` placeholders instead.\n\n### Async execution\n\nUse `execute_async()` when you need request concurrency without blocking the calling thread:\n\n```python\nfrom cassandra.cluster import Cluster\n\ncluster = Cluster([\"127.0.0.1\"])\nsession = cluster.connect(\"app_keyspace\")\n\nfuture = session.execute_async(\n    \"SELECT id, email FROM users WHERE id = %s\",\n    (user_id,),\n)\n\nrow = future.result().one()\nprint(row.email)\n```\n\n### Row factories\n\nSwitch the row factory when tuple-style rows are inconvenient:\n\n```python\nfrom cassandra.cluster import Cluster\nfrom cassandra.query import dict_factory\n\ncluster = Cluster([\"127.0.0.1\"])\nsession = cluster.connect(\"app_keyspace\")\nsession.row_factory = dict_factory\n\nrow = session.execute(\"SELECT id, email FROM users\").one()\nprint(row[\"email\"])\n```\n\n## Execution Profiles And Tuning\n\nExecution profiles are the main way to centralize query defaults such as consistency, timeouts, load balancing, and row factories:\n\n```python\nfrom cassandra import ConsistencyLevel\nfrom cassandra.cluster import (\n    Cluster,\n    EXEC_PROFILE_DEFAULT,\n    ExecutionProfile,\n)\nfrom cassandra.policies import TokenAwarePolicy, DCAwareRoundRobinPolicy\nfrom cassandra.query import tuple_factory\n\nprofile = ExecutionProfile(\n    load_balancing_policy=TokenAwarePolicy(DCAwareRoundRobinPolicy(local_dc=\"us-east-1\")),\n    consistency_level=ConsistencyLevel.LOCAL_QUORUM,\n    request_timeout=10,\n    row_factory=tuple_factory,\n)\n\ncluster = Cluster(\n    [\"db1.internal\", \"db2.internal\"],\n    execution_profiles={EXEC_PROFILE_DEFAULT: profile},\n)\nsession = cluster.connect(\"app_keyspace\")\n```\n\nUse profiles instead of scattering per-call overrides once the application has a stable read/write policy.\n\n## Object Mapper\n\nThe package also ships the `cqlengine` object mapper under `cassandra.cqlengine`. Use it only if the project is already committed to that abstraction; otherwise start with raw session queries so schema behavior stays obvious.\n\n## Configuration Notes\n\n- `Cluster([...])` contact points only need to be enough for initial discovery; they do not need to list every node.\n- `port=9042` is the usual native transport port for self-managed clusters.\n- `connect_timeout`, `control_connection_timeout`, heartbeat settings, and retry/load-balancing policies are cluster-level tuning knobs exposed on `Cluster`.\n- Shut down both `Session` and `Cluster` in long-running apps, scripts, and tests to avoid leaked connections.\n\n## Common Pitfalls\n\n- Do not mix placeholder styles. Prepared statements use `?`, while non-prepared `session.execute(query, parameters)` calls use `%s` or `%(name)s`.\n- Do not open a new `Cluster` or `Session` per request. Reuse them for the life of the process.\n- Do not assume the docs site's version selector tracks the newest PyPI patch. For `3.29.3`, use the `3.29` docs plus the changelog for patch-specific fixes.\n- Pure-Python mode can become the bottleneck under load. If latency or throughput matters, verify whether the C extensions and `libev` reactor are available in your environment.\n- Always set the local datacenter explicitly in multi-DC deployments when using policies such as `DCAwareRoundRobinPolicy`.\n- For Astra DB, use the secure connect bundle flow. Do not copy self-managed cluster contact-point examples into Astra configuration.\n- `execute_async()` gives driver-level concurrency, but it is not `asyncio`. If your app is asyncio-native, treat the driver as blocking I/O unless you deliberately isolate it behind threads or worker processes.\n\n## Version-Sensitive Notes For 3.29.3\n\n- The official docs root is still the `3.29` documentation set; there is no separate `3.29.3` docs tree.\n- PyPI and the upstream changelog show `3.29.3` released on January 30, 2025.\n- `3.29.3` adds Python 3.13 support and ships patch-level fixes on top of the `3.29` docs set.\n- The docs site still reflects older Python support guidance in some pages, so prefer PyPI metadata and the changelog when the docs and package metadata disagree.\n\n## Official Sources\n\n- DataStax Python Driver docs root: https://docs.datastax.com/en/developer/python-driver/3.29/\n- Getting started: https://docs.datastax.com/en/developer/python-driver/3.29/getting_started/\n- Installation: https://docs.datastax.com/en/developer/python-driver/3.29/installation/\n- Performance notes: https://docs.datastax.com/en/developer/python-driver/3.29/performance/\n- Security: https://docs.datastax.com/en/developer/python-driver/3.29/security/\n- Astra cloud connection: https://docs.datastax.com/en/developer/python-driver/3.29/cloud/\n- Execution profiles: https://docs.datastax.com/en/developer/python-driver/3.29/execution_profiles/\n- Object mapper: https://docs.datastax.com/en/developer/python-driver/3.29/object_mapper/\n- PyPI package page: https://pypi.org/project/cassandra-driver/\n- Upstream changelog: https://github.com/apache/cassandra-python-driver/blob/master/CHANGELOG.rst\n"
  },
  {
    "path": "content/catboost/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"CatBoost Python package guide for gradient-boosted classification, regression, and ranking with categorical, text, and embedding features\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.10\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"catboost,machine-learning,gradient-boosting,classification,regression,ranking\"\n---\n\n# CatBoost Python Package Guide\n\n## Golden Rule\n\nUse the official `catboost` package, pass raw feature types to CatBoost instead of pre-encoding categorical columns yourself, and build train and validation datasets with `Pool` whenever you need stable feature typing, weights, ranking metadata, or early-stopping behavior.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"catboost==1.2.10\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"catboost==1.2.10\"\npoetry add \"catboost==1.2.10\"\n```\n\nOptional packages that upstream calls out:\n\n```bash\npython -m pip install graphviz matplotlib plotly\n```\n\nUse those only if you need plotting or tree visualization. For custom Python metrics or objectives, upstream recommends `numba`; for CUDA-backed custom metrics or objectives, upstream also recommends `numba-cuda`, and CUDA itself must be installed on the machine.\n\n## Initialize Data Correctly\n\n`Pool` is CatBoost's dataset container. Use it when you need explicit feature typing, labels, sample weights, validation sets, ranking groups, or file-based datasets.\n\n```python\nimport pandas as pd\nfrom catboost import Pool\n\ntrain_df = pd.DataFrame(\n    [\n        {\"city\": \"SF\", \"device\": \"ios\", \"age\": 29, \"events\": 14},\n        {\"city\": \"NYC\", \"device\": \"web\", \"age\": 41, \"events\": 5},\n        {\"city\": \"SF\", \"device\": \"android\", \"age\": 35, \"events\": 9},\n    ]\n)\ntrain_labels = [1, 0, 1]\n\ntrain_pool = Pool(\n    data=train_df,\n    label=train_labels,\n    cat_features=[\"city\", \"device\"],\n)\n```\n\nNotes:\n\n- `cat_features`, `text_features`, and `embedding_features` can be passed as column indices or names.\n- If you use names instead of indices, give CatBoost actual feature names by using a `pandas.DataFrame`, `polars.DataFrame`, or explicit `feature_names`.\n- `Pool` also accepts `weight`, `group_id`, `subgroup_id`, `pairs`, `baseline`, and file paths, so use it instead of ad hoc arrays for ranking or production training pipelines.\n\n## Core Usage\n\n### Binary classification\n\nUse `eval_set` when you want best-iteration selection, overfitting detection, or metric tracking.\nAssume `train_df` and `train_labels` come from the previous section, and that `valid_df` and `valid_labels` were prepared with the same schema.\n\n```python\nfrom catboost import CatBoostClassifier, Pool\n\ntrain_pool = Pool(train_df, label=train_labels, cat_features=[\"city\", \"device\"])\nvalid_pool = Pool(valid_df, label=valid_labels, cat_features=[\"city\", \"device\"])\n\nmodel = CatBoostClassifier(\n    iterations=500,\n    learning_rate=0.05,\n    depth=8,\n    loss_function=\"Logloss\",\n    eval_metric=\"AUC\",\n    random_seed=42,\n)\n\nmodel.fit(\n    train_pool,\n    eval_set=valid_pool,\n    use_best_model=True,\n    early_stopping_rounds=50,\n    verbose=50,\n)\n\npred_labels = model.predict(valid_pool)\npred_probs = model.predict_proba(valid_pool)[:, 1]\n```\n\n`use_best_model=True` only works when a validation dataset is provided.\n\n### Regression\n\n```python\nfrom catboost import CatBoostRegressor\n\nmodel = CatBoostRegressor(\n    iterations=400,\n    learning_rate=0.05,\n    depth=8,\n    loss_function=\"RMSE\",\n    random_seed=42,\n)\n\nmodel.fit(train_pool, eval_set=valid_pool, verbose=50)\npredictions = model.predict(valid_pool)\n```\n\n### Cross-validation\n\nUse the package-level `cv()` helper instead of writing your own fold loop when you want CatBoost-native metrics and early stopping behavior.\n\n```python\nfrom catboost import Pool, cv\n\ndataset = Pool(train_df, label=train_labels, cat_features=[\"city\", \"device\"])\nscores = cv(\n    dataset,\n    params={\n        \"iterations\": 300,\n        \"depth\": 8,\n        \"loss_function\": \"Logloss\",\n        \"verbose\": False,\n    },\n    fold_count=5,\n)\n```\n\n### GPU training\n\nThe released Linux and Windows packages include CUDA-enabled GPU support. A minimal GPU configuration looks like this:\n\n```python\nfrom catboost import CatBoostClassifier\n\nmodel = CatBoostClassifier(\n    iterations=1000,\n    task_type=\"GPU\",\n    devices=\"0\",\n)\nmodel.fit(train_pool, eval_set=valid_pool, verbose=False)\n```\n\nAs of CatBoost `1.2.10`, upstream documents released-package support for devices with CUDA compute capability `>= 3.5`, and requires NVIDIA driver `450.80.02` or newer for CUDA-enabled training or inference.\n\n## Feature Types And Data Containers\n\nCatBoost supports numerical, categorical, text, and embedding features. Keep the feature declarations close to the dataset rather than burying them in preprocessing code.\n\nWhen performance matters and your input pipeline is already validated, `FeaturesData` can build `Pool` objects faster than generic DataFrames or ndarrays, especially for mostly numerical datasets with some categorical columns:\n\n```python\nimport numpy as np\nfrom catboost import FeaturesData, Pool\n\nfeatures = FeaturesData(\n    num_feature_data=np.array([[29.0, 14.0], [41.0, 5.0]], dtype=np.float32),\n    cat_feature_data=np.array([[\"SF\", \"ios\"], [\"NYC\", \"web\"]], dtype=object),\n)\ndataset = Pool(features, label=[1, 0])\n```\n\nUse `FeaturesData` only when you already know the input is correct. Upstream explicitly warns that it performs no input validation, and categorical feature values must be strings stored in an `object` array.\n\n## Model Persistence And Export\n\nUse CatBoost's native binary format unless you have a specific interoperability requirement.\n\n```python\nfrom catboost import CatBoostClassifier\n\nmodel.save_model(\"model.cbm\")\n\nloaded = CatBoostClassifier()\nloaded.load_model(\"model.cbm\")\n```\n\nUseful export formats from `save_model()`:\n\n- `cbm`: native CatBoost binary format\n- `json`: portable JSON representation\n- `python`: standalone Python code\n- `cpp`: standalone C++ code\n- `onnx` and `coreml`: only supported for datasets without categorical features\n\nIf you export a model with categorical features to `json`, `python`, or `cpp`, pass the training `pool=` argument to `save_model()` so CatBoost has the categorical metadata it needs.\n\n## Configuration Notes\n\n- Choose the estimator class for the problem shape: `CatBoostClassifier`, `CatBoostRegressor`, or `CatBoostRanker`.\n- Keep the training objective explicit with `loss_function` instead of relying on defaults when the task is not obvious.\n- Core tuning knobs agents usually need first: `iterations`, `learning_rate`, `depth`, `l2_leaf_reg`, `loss_function`, `eval_metric`, `random_seed`.\n- For long runs, `save_snapshot=True` plus `snapshot_file` lets CatBoost resume interrupted training.\n- Ranking tasks usually need `Pool(..., group_id=..., pairs=...)` or related ranking metadata, so do not treat them like plain classification arrays.\n\n## Common Pitfalls\n\n- Do not one-hot encode categorical columns during preprocessing. CatBoost's docs explicitly warn that this hurts both training speed and model quality.\n- `use_best_model=True` requires `eval_set`; without a validation set, best-iteration truncation cannot work.\n- GPU training does not support multiple validation datasets.\n- If you specify categorical, text, or embedding features by name, make sure the dataset object actually carries feature names.\n- `FeaturesData` is a performance tool, not a safe default. It does no input checks.\n- If you train with categorical features and then export to `onnx` or `coreml`, the export will fail because those formats only support datasets without categorical features.\n- For `pmml` export, categorical features must effectively be one-hot encoded during training via `one_hot_max_size`, which conflicts with the normal CatBoost guidance for standard training workflows.\n\n## Version-Sensitive Notes For 1.2.10\n\n- The version used here `1.2.10` matches the current PyPI release as of `2026-03-12`.\n- PyPI lists `catboost 1.2.10` as released on `2026-02-18`.\n- The official GitHub release `v1.2.10` was published on `2026-02-19` and only calls out JVM applier and Spark changes, not Python API changes.\n- The official docs are version-light and mostly describe the active `1.2.x` behavior rather than a separate per-version Python reference. When exact runtime support matters, validate against the `1.2.10` PyPI files page and release tag instead of older blog posts.\n\n## Official Links\n\n- Docs root: `https://catboost.ai/en/docs/`\n- Canonical docs root used for authoring: `https://catboost.ai/docs/en/`\n- Python installation: `https://catboost.ai/docs/en/concepts/python-installation`\n- Usage examples: `https://catboost.ai/docs/en/concepts/python-usages-examples`\n- Pool reference: `https://catboost.ai/docs/en/concepts/python-reference_pool`\n- `fit()` reference: `https://catboost.ai/docs/en/concepts/python-reference_catboostclassifier_fit`\n- `save_model()` reference: `https://catboost.ai/docs/en/concepts/python-reference_catboost_save_model`\n- Categorical features: `https://catboost.ai/docs/en/features/categorical-features`\n- FeaturesData: `https://catboost.ai/docs/en/concepts/python-features-data__desc`\n- PyPI release: `https://pypi.org/project/catboost/1.2.10/`\n- GitHub release: `https://github.com/catboost/catboost/releases/tag/v1.2.10`\n"
  },
  {
    "path": "content/cattrs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cattrs package guide for structuring and unstructuring Python dataclasses and attrs classes\"\nmetadata:\n  languages: \"python\"\n  versions: \"26.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cattrs,python,serialization,dataclasses,attrs\"\n---\n\n# cattrs Python Package Guide\n\n## What It Is\n\n`cattrs` converts between typed Python objects and plain unstructured data.\n\nThe two core operations are:\n\n- `converter.structure(data, TargetType)` to turn inbound `dict` / `list` / scalar data into dataclasses, `attrs` classes, and typed collections\n- `converter.unstructure(obj)` to turn typed objects back into plain Python data you can pass to `json.dumps()`, an HTTP client, or a queue\n\nPrefer creating an explicit `Converter()` instance in application code so your hooks and format rules live in one place.\n\n## Installation\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"cattrs==26.1.0\"\n```\n\nWith Poetry:\n\n```bash\npoetry add \"cattrs==26.1.0\"\n```\n\nWith uv:\n\n```bash\nuv add \"cattrs==26.1.0\"\n```\n\n`cattrs` has no service credentials or runtime environment variables.\n\n## Initialize A Converter\n\n```python\nfrom cattrs import Converter\n\nconverter = Converter()\n```\n\nKeep the configured converter near your application boundary code instead of constructing new converters in every request handler or utility function.\n\n## Core Workflows\n\n### Structure inbound data into typed objects\n\n```python\nfrom dataclasses import dataclass\n\nfrom cattrs import Converter\n\n\n@dataclass\nclass Address:\n    city: str\n    postal_code: str\n\n\n@dataclass\nclass User:\n    id: int\n    email: str\n    address: Address\n    tags: list[str]\n\n\npayload = {\n    \"id\": 42,\n    \"email\": \"ada@example.com\",\n    \"address\": {\"city\": \"London\", \"postal_code\": \"SW1A 1AA\"},\n    \"tags\": [\"admin\", \"beta\"],\n}\n\nconverter = Converter()\nuser = converter.structure(payload, User)\n\nprint(user.address.city)\n```\n\n### Unstructure typed objects before JSON serialization\n\n```python\nimport json\n\nbody = json.dumps(converter.unstructure(user))\n```\n\n### Structure typed collections, not just single objects\n\n```python\nraw_users = [payload, payload]\nusers = converter.structure(raw_users, list[User])\n\nraw_index = {\"primary\": payload}\nuser_index = converter.structure(raw_index, dict[str, User])\n```\n\n### Use the same API with `attrs` classes\n\n```python\nfrom attrs import define\n\nfrom cattrs import Converter\n\n\n@define\nclass Settings:\n    region: str\n    retries: int = 3\n\n\nconverter = Converter()\nsettings = converter.structure({\"region\": \"us-east-1\"}, Settings)\n```\n\n## Custom Hooks For Non-Primitive Types\n\nRegister hooks when external data does not already match the Python type you want in memory.\n\n```python\nfrom dataclasses import dataclass\nfrom datetime import datetime\nfrom decimal import Decimal\n\nfrom cattrs import Converter\n\n\n@dataclass\nclass Invoice:\n    id: str\n    created_at: datetime\n    total: Decimal\n\n\nconverter = Converter()\n\nconverter.register_structure_hook(\n    datetime,\n    lambda value, _: datetime.fromisoformat(value),\n)\nconverter.register_unstructure_hook(\n    datetime,\n    lambda value: value.isoformat(),\n)\n\nconverter.register_structure_hook(\n    Decimal,\n    lambda value, _: Decimal(value),\n)\nconverter.register_unstructure_hook(\n    Decimal,\n    lambda value: str(value),\n)\n\ninvoice = converter.structure(\n    {\n        \"id\": \"inv_123\",\n        \"created_at\": \"2026-03-12T09:30:00+00:00\",\n        \"total\": \"19.99\",\n    },\n    Invoice,\n)\n\npayload = converter.unstructure(invoice)\n```\n\nThese hooks apply only to this `converter` instance. Reuse the configured instance anywhere the same wire format appears.\n\n## JSON And HTTP Boundaries\n\n`cattrs` does not parse JSON text or emit JSON bytes by itself. Pair it with `json`, `orjson`, or your framework's request/response layer.\n\n```python\nimport json\nfrom dataclasses import dataclass\n\nfrom cattrs import Converter\n\n\n@dataclass\nclass Event:\n    type: str\n    id: str\n\n\nconverter = Converter()\n\nraw_body = '{\"type\": \"user.created\", \"id\": \"evt_123\"}'\nevent = converter.structure(json.loads(raw_body), Event)\n\nresponse_body = json.dumps(converter.unstructure(event))\n```\n\n## Config And Auth\n\n`cattrs` has no authentication, API keys, or package-specific environment variables.\n\nThe main project-level decisions are:\n\n- where the shared converter instance is created\n- which structure and unstructure hooks are registered\n- whether one converter is enough for the whole app or whether different external payload formats need separate converters\n\n## Common Pitfalls\n\n- Use typed targets like `list[User]` and `dict[str, User]`; bare `list` and `dict` lose element type information.\n- Register hooks for values like `datetime`, `Decimal`, enums, or domain-specific IDs when the inbound representation is a string or number.\n- Hooks are attached to a converter instance, not globally. If you create a fresh `Converter()`, you also lose the hooks registered on the previous one.\n- Keep conversion at the boundary of your app. Parse inbound HTTP or message payloads into typed objects early, then unstructure only when you need to cross back into JSON or another wire format.\n- If two upstream systems encode the same type differently, use different configured converters instead of one converter with ambiguous rules.\n\n## Version-Sensitive Notes\n\n- This guide targets `cattrs 26.1.0`.\n- If you are copying examples from older code, re-check advanced helper imports and customization snippets against the docs for the version installed in your project.\n\n## Official Sources\n\n- Documentation root: `https://catt.rs/en/stable/`\n- Project history: `https://catt.rs/en/stable/history.html`\n- PyPI package page: `https://pypi.org/project/cattrs/`\n"
  },
  {
    "path": "content/cbor2/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cbor2 package guide for Python projects encoding and decoding CBOR data\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"cbor2,cbor,python,serialization,binary\"\n---\n\n# cbor2 Python Package Guide\n\n## Golden Rule\n\nUse the official `cbor2` package when you need CBOR encoding and decoding in Python. `cbor2` is a local serialization library, not a service client, so there is no authentication step, no runtime environment configuration, and no client object to initialize.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"cbor2==5.8.0\"\n```\n\n`cbor2` is usable without compiled extensions, but the docs note that it can build an optional C extension for better performance when a compiler toolchain is available.\n\nIf you want installation to fail instead of silently falling back to the pure Python implementation, set `CBOR2_BUILD_C_EXTENSION=1` before installing:\n\n```bash\nCBOR2_BUILD_C_EXTENSION=1 python -m pip install \"cbor2==5.8.0\"\n```\n\n## Runtime Setup\n\nThere are no runtime environment variables for normal use.\n\n```python\nimport cbor2\n```\n\nFor most applications, call the top-level helpers directly:\n\n- `cbor2.dumps(obj)` and `cbor2.dump(obj, fp)` to encode\n- `cbor2.loads(data)` and `cbor2.load(fp)` to decode\n\n## Encode And Decode In Memory\n\n```python\nimport cbor2\n\npayload = {\n    \"message\": \"hello\",\n    \"count\": 3,\n    \"ok\": True,\n    \"tags\": [\"alpha\", \"beta\"],\n}\n\nencoded = cbor2.dumps(payload)\ndecoded = cbor2.loads(encoded)\n\nprint(type(encoded))   # <class 'bytes'>\nprint(decoded[\"message\"])\n```\n\nUse `dumps()` when you already have the whole object in memory and need the encoded `bytes`.\n\n## Encode And Decode Files\n\nOpen files in binary mode:\n\n```python\nimport cbor2\n\npayload = {\"job\": \"sync\", \"attempt\": 1}\n\nwith open(\"payload.cbor\", \"wb\") as fp:\n    cbor2.dump(payload, fp)\n\nwith open(\"payload.cbor\", \"rb\") as fp:\n    decoded = cbor2.load(fp)\n\nprint(decoded)\n```\n\n`dump()` and `load()` work with any binary file-like object, including `io.BytesIO`.\n\n## Canonical Encoding\n\nIf another system expects deterministic CBOR output, enable canonical encoding:\n\n```python\nimport cbor2\n\npayload = {\"b\": 2, \"a\": 1}\nencoded = cbor2.dumps(payload, canonical=True)\n```\n\nThe API reference documents `canonical=True` for preferred, deterministic CBOR encoding.\n\n## Datetime And Date Handling\n\n`cbor2` can encode `datetime` values either as RFC 3339 text or as numeric timestamps.\n\n```python\nfrom datetime import datetime, timezone\nimport cbor2\n\nevent_time = datetime(2026, 3, 13, 12, 0, tzinfo=timezone.utc)\n\nas_text = cbor2.dumps(event_time)\nas_timestamp = cbor2.dumps(event_time, datetime_as_timestamp=True)\n\nprint(cbor2.loads(as_text))\nprint(cbor2.loads(as_timestamp))\n```\n\nFor naive `datetime` values, pass a fallback timezone or make the value timezone-aware first:\n\n```python\nfrom datetime import datetime, timezone\nimport cbor2\n\nnaive = datetime(2026, 3, 13, 12, 0)\nencoded = cbor2.dumps(naive, timezone=timezone.utc)\n```\n\nFor `date` objects, the docs warn that the default representation uses an earlier RFC draft and may not be understood by other CBOR tools. If interoperability matters more than preserving the exact Python type, use `date_as_datetime=True`.\n\n```python\nfrom datetime import date\nimport cbor2\n\nencoded = cbor2.dumps(date(2026, 3, 13), date_as_datetime=True)\ndecoded = cbor2.loads(encoded)\nprint(decoded)\n```\n\n## Custom Type Encoding With `default`\n\nUse the `default` callback when `cbor2` does not know how to serialize one of your objects.\n\n```python\nfrom dataclasses import dataclass\nimport cbor2\n\n@dataclass\nclass Point:\n    x: int\n    y: int\n\ndef default_encoder(encoder, value):\n    if isinstance(value, Point):\n        encoder.encode({\"__type__\": \"point\", \"x\": value.x, \"y\": value.y})\n        return\n    raise TypeError(f\"cannot encode {type(value)!r}\")\n\npayload = {\"origin\": Point(0, 0)}\nencoded = cbor2.dumps(payload, default=default_encoder)\nprint(encoded)\n```\n\nThe encoder callback receives the active encoder instance, so you can emit plain CBOR structures or semantic tags.\n\n## Custom Decoding With `object_hook` And `tag_hook`\n\nUse `object_hook` to post-process decoded maps and `tag_hook` to handle semantic tags.\n\n```python\nfrom dataclasses import dataclass\nimport cbor2\n\n@dataclass\nclass Point:\n    x: int\n    y: int\n\ndef object_hook(decoder, value):\n    if value.get(\"__type__\") == \"point\":\n        return Point(x=value[\"x\"], y=value[\"y\"])\n    return value\n\nencoded = cbor2.dumps({\"origin\": {\"__type__\": \"point\", \"x\": 2, \"y\": 4}})\ndecoded = cbor2.loads(encoded, object_hook=object_hook)\n\nprint(decoded[\"origin\"])\n```\n\n```python\nfrom dataclasses import dataclass\nimport cbor2\nfrom cbor2 import CBORTag\n\n@dataclass\nclass Point:\n    x: int\n    y: int\n\ndef default_encoder(encoder, value):\n    if isinstance(value, Point):\n        encoder.encode(CBORTag(3000, [value.x, value.y]))\n        return\n    raise TypeError(f\"cannot encode {type(value)!r}\")\n\ndef tag_hook(decoder, tag):\n    if tag.tag == 3000:\n        return Point(*tag.value)\n    return tag\n\nencoded = cbor2.dumps(Point(5, 8), default=default_encoder)\ndecoded = cbor2.loads(encoded, tag_hook=tag_hook)\n\nprint(decoded)\n```\n\n## Command-Line Inspection\n\n`cbor2` ships a small CLI similar to `json.tool` that converts CBOR input to JSON for inspection:\n\n```bash\npython -m cbor2.tool payload.cbor\n```\n\nUse it to inspect captured payloads or fixture files before writing decode logic.\n\n## Common Pitfalls\n\n- Open files in binary mode. `cbor2.load()` and `cbor2.dump()` expect byte streams, not text files.\n- There is no client object or connection step. Import the module and call the encode/decode helpers directly.\n- Naive `datetime` values need a `timezone=` fallback or explicit `tzinfo`; otherwise encoding can fail.\n- `date` values are not universally portable in CBOR. Use `date_as_datetime=True` when another implementation needs to read them reliably.\n- Use `default`, `object_hook`, and `tag_hook` for custom types instead of manually pre-serializing everything to JSON-compatible structures.\n\n## Version Notes For 5.8.0\n\n- The official version history for `5.8.0` notes new support for CPython 3.8.\n- `5.8.0` also adds `decode_sortable_key()`, tag 256 stringref namespace support, and support for mutable shared references in `shareable_encoder()`.\n- The live `latest` API reference includes newer kwargs such as `max_depth` on `load()` and `loads()`, but the version history lists `max_depth` under unreleased changes. If your project is pinned to `5.8.0`, do not assume `max_depth` is available.\n\n## Official Sources\n\n- Maintainer docs root: https://cbor2.readthedocs.io/en/latest/\n- Usage guide: https://cbor2.readthedocs.io/en/latest/usage.html\n- API reference: https://cbor2.readthedocs.io/en/latest/api.html\n- Customizing encoding and decoding: https://cbor2.readthedocs.io/en/latest/customizing.html\n- Version history: https://cbor2.readthedocs.io/en/latest/versionhistory.html\n- PyPI package: https://pypi.org/project/cbor2/\n"
  },
  {
    "path": "content/celery/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Celery distributed task queue for Python workers, retries, scheduling, and broker-backed background jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.6.2\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"celery,python,task-queue,workers,async,redis,rabbitmq,django\"\n---\n\n# Celery Python Package Guide\n\nUse `celery` when Python code needs broker-backed background jobs, scheduled tasks, retries, and horizontally scalable worker processes.\n\n## Golden Rule\n\n- Define one importable Celery app module and point both producers and workers at it.\n- Use RabbitMQ or Redis unless you have a specific reason to pick another transport.\n- Treat task payloads as JSON by default and keep tasks idempotent.\n- Only configure a result backend if you actually need task states or return values.\n\n## Version Covered\n\n- Package: `celery`\n- Ecosystem: `pypi`\n- Version: `5.6.2`\n- Release date: `2026-01-04`\n- Python requirement on PyPI: `>=3.9`\n\n## Install\n\nBase install:\n\n```bash\npip install celery==5.6.2\n```\n\nCommon extras from PyPI:\n\n```bash\n# Redis broker and/or result backend support\npip install \"celery[redis]==5.6.2\"\n\n# Task-side Pydantic validation helpers\npip install \"celery[pydantic]==5.6.2\"\n\n# pytest plugin support\npip install \"celery[pytest]==5.6.2\"\n```\n\n## Core Model\n\nCelery has four moving parts:\n\n1. A Python app object created with `Celery(...)`.\n2. A broker that carries task messages.\n3. One or more worker processes that execute tasks.\n4. An optional result backend for task state and return values.\n\nRecurring schedules are handled by a separate `beat` process.\n\n## Minimal Setup\n\nCreate an importable module such as `tasks.py`:\n\n```python\nimport os\n\nfrom celery import Celery\n\napp = Celery(\n    \"tasks\",\n    broker=os.environ.get(\"CELERY_BROKER_URL\", \"pyamqp://guest@localhost//\"),\n    backend=os.environ.get(\"CELERY_RESULT_BACKEND\"),\n)\n\napp.conf.update(\n    task_serializer=\"json\",\n    accept_content=[\"json\"],\n    result_serializer=\"json\",\n    timezone=\"UTC\",\n    enable_utc=True,\n)\n\n@app.task(\n    bind=True,\n    autoretry_for=(ConnectionError, TimeoutError),\n    retry_backoff=True,\n    retry_jitter=True,\n    max_retries=5,\n)\ndef fetch_remote(self, url: str) -> str:\n    # Put explicit I/O timeouts in the code you call from tasks.\n    return f\"fetched {url}\"\n```\n\nStart a worker:\n\n```bash\ncelery -A tasks worker --loglevel=INFO\n```\n\nQueue a task:\n\n```python\nfrom tasks import fetch_remote\n\nresult = fetch_remote.delay(\"https://example.com/data.json\")\nprint(result.id)\n```\n\n## Broker and Backend Choices\n\n### RabbitMQ\n\n- Best default production broker.\n- Stable, durable, and feature-complete in Celery docs.\n- Handles larger messages better than Redis.\n\nExample:\n\n```env\nCELERY_BROKER_URL=pyamqp://guest:guest@localhost//\n```\n\n### Redis\n\n- Stable as both broker and result backend.\n- Good for fast, smaller messages and common local setups.\n- More susceptible to data loss on abrupt termination than RabbitMQ.\n- Large messages can congest Redis when used as a broker.\n\nExample:\n\n```env\nCELERY_BROKER_URL=redis://localhost:6379/0\nCELERY_RESULT_BACKEND=redis://localhost:6379/1\n```\n\nFor Redis result backends, install the Redis extra:\n\n```bash\npip install \"celery[redis]==5.6.2\"\n```\n\nTLS example for Redis backend:\n\n```env\nCELERY_RESULT_BACKEND=rediss://username:password@redis.example.com:6379/0?ssl_cert_reqs=required\n```\n\n### SQS and Other Brokers\n\n- Amazon SQS is marked stable, but Celery docs note it does not support monitoring or remote control commands.\n- Kafka, Zookeeper, and some other brokers are still marked experimental.\n\n## Calling Tasks\n\nUse `delay()` for the common case and `apply_async()` when you need execution options:\n\n```python\nfrom tasks import fetch_remote\n\nfetch_remote.delay(\"https://example.com/a\")\n\nfetch_remote.apply_async(\n    args=(\"https://example.com/b\",),\n    countdown=10,\n    expires=60,\n)\n```\n\nUseful `apply_async()` options:\n\n- `countdown` or `eta` for delayed execution\n- `expires` to drop stale work\n- `link` and `link_error` for callbacks and errbacks\n\nDo not use `countdown` or `eta` for large volumes of far-future jobs. Celery keeps those tasks in worker memory until execution time, and Redis brokers can redeliver them when the delay exceeds the broker visibility timeout.\n\n## Results and State\n\nResults are off by default. Configure `result_backend` only if you need:\n\n- `AsyncResult.get()`\n- task state inspection\n- chords or workflows that depend on stored results\n\nExample:\n\n```python\nfrom tasks import fetch_remote\n\nresult = fetch_remote.delay(\"https://example.com/c\")\nvalue = result.get(timeout=10)\nresult.forget()\n```\n\nIf you do not need return values, set `ignore_result=True` on the task or use global task result settings to reduce backend load.\n\n## Production-Oriented Configuration\n\nCommon settings worth knowing:\n\n```python\napp.conf.update(\n    broker_url=\"pyamqp://user:pass@rabbitmq.example.com/vhost\",\n    result_backend=\"redis://redis.example.com/0\",\n    accept_content=[\"json\"],\n    task_serializer=\"json\",\n    result_serializer=\"json\",\n    timezone=\"UTC\",\n    enable_utc=True,\n    worker_prefetch_multiplier=1,\n    task_acks_late=True,\n    task_reject_on_worker_lost=False,\n)\n```\n\nNotes:\n\n- `accept_content=['json']` keeps workers from accepting untrusted pickle or yaml payloads.\n- `worker_prefetch_multiplier=1` helps fairness when tasks are long-running.\n- `task_acks_late=True` only makes sense for idempotent tasks.\n- Turning on `task_reject_on_worker_lost=True` can requeue work after a worker process dies, but it can also create message loops if you do not understand the failure mode.\n\nCelery also supports:\n\n- separate `broker_read_url` and `broker_write_url`\n- multiple broker URLs for failover\n- app config modules via `app.config_from_object(\"celeryconfig\")`\n\n## Task Design Patterns\n\n### Idempotent retryable task\n\n```python\nfrom celery import shared_task\n\n@shared_task(\n    autoretry_for=(ConnectionError, TimeoutError),\n    retry_backoff=True,\n    retry_backoff_max=600,\n    retry_jitter=True,\n    max_retries=7,\n)\ndef sync_invoice(invoice_id: str) -> None:\n    # Safe to run more than once.\n    ...\n```\n\n### Task with no stored result\n\n```python\nfrom celery import shared_task\n\n@shared_task(ignore_result=True)\ndef send_webhook(payload: dict) -> None:\n    ...\n```\n\n### Pydantic task-side validation\n\nCelery 5.5 added task-side Pydantic argument and return-value conversion:\n\n```python\nfrom celery import Celery\nfrom pydantic import BaseModel\n\napp = Celery(\"tasks\")\n\nclass JobIn(BaseModel):\n    url: str\n\nclass JobOut(BaseModel):\n    status: str\n\n@app.task(pydantic=True)\ndef run_job(job: JobIn) -> JobOut:\n    return JobOut(status=f\"queued:{job.url}\")\n```\n\nImportant: `pydantic=True` validates on the task side. You still need to serialize task arguments correctly when calling `delay()` or `apply_async()`.\n\n## Workers\n\nBasic worker:\n\n```bash\ncelery -A tasks worker -l INFO\n```\n\nNamed workers with explicit concurrency:\n\n```bash\ncelery -A proj worker --loglevel=INFO --concurrency=10 -n worker1@%h\ncelery -A proj worker --loglevel=INFO --concurrency=10 -n worker2@%h\n```\n\nOperational guidance:\n\n- Set explicit timeouts in the I/O your task performs.\n- Use Celery time limits for tasks that can wedge a worker.\n- Prefer multiple smaller workers over one giant process when isolating queues or workloads.\n\n## Periodic Tasks\n\nRun the scheduler separately:\n\n```bash\ncelery -A tasks beat -l INFO\n```\n\nInline schedule example:\n\n```python\napp.conf.beat_schedule = {\n    \"refresh-every-30-seconds\": {\n        \"task\": \"tasks.refresh_cache\",\n        \"schedule\": 30.0,\n    },\n}\napp.conf.timezone = \"UTC\"\n```\n\n## Django Integration\n\nCelery works with Django directly; a separate integration package is no longer required.\n\nTypical `proj/celery.py`:\n\n```python\nimport os\n\nfrom celery import Celery\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"proj.settings\")\n\napp = Celery(\"proj\")\napp.config_from_object(\"django.conf:settings\", namespace=\"CELERY\")\napp.autodiscover_tasks()\n```\n\nImportant Django notes:\n\n- Put Celery settings in Django settings as `CELERY_BROKER_URL`, `CELERY_RESULT_BACKEND`, and similar.\n- Use `@shared_task` inside reusable apps.\n- If a task depends on committed DB state, prefer `delay_on_commit()` over `delay()` in Django transaction flows.\n- `delay_on_commit()` was added in Celery 5.4 and does not return a task id because sending is deferred until commit.\n\n## Testing\n\nFor unit tests, prefer mocking task behavior or the code inside tasks.\n\nImportant testing caveats:\n\n- `task_always_eager=True` is not a faithful unit-test substitute for a real worker.\n- If you need eager execution plus stored results, also set `task_store_eager_result=True`.\n- `celery.contrib.pytest` and `pytest-celery` are different and not compatible with each other.\n\n## Common Pitfalls\n\n- No result backend configured: `AsyncResult.get()` and state inspection will not behave the way you expect.\n- Non-idempotent tasks with `acks_late=True`: worker crashes can duplicate side effects.\n- No I/O timeouts inside tasks: a stuck request can block worker capacity indefinitely.\n- Accepting `pickle` or `yaml` content from an untrusted broker: this widens your attack surface.\n- Large or distant `countdown` loads: workers hold those messages in memory.\n- Long-running tasks with default prefetch: one worker can reserve too much work early.\n- Triggering Django tasks before transaction commit: the worker may not see the saved rows yet.\n\n## Version-Sensitive Notes for 5.6.2\n\n- Stable docs and PyPI both identify the current covered release as `5.6.2`.\n- PyPI project metadata requires Python `>=3.9`.\n- Task-side Pydantic validation via `pydantic=True` is available in Celery `5.5+`.\n- `delay_on_commit()` for Django is available in Celery `5.4+`.\n- The PyPI long description still contains some stale `5.5.x` references, so prefer the stable docs root and PyPI metadata over older prose when checking current support statements.\n- The project still says Microsoft Windows is unsupported, even though it may work in some environments.\n\n## Official Sources\n\n- Docs root: https://docs.celeryq.dev/en/stable/\n- First steps: https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html\n- Brokers and backends: https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/index.html\n- Configuration: https://docs.celeryq.dev/en/stable/userguide/configuration.html\n- Tasks: https://docs.celeryq.dev/en/stable/userguide/tasks.html\n- Calling tasks: https://docs.celeryq.dev/en/stable/userguide/calling.html\n- Workers: https://docs.celeryq.dev/en/stable/userguide/workers.html\n- Periodic tasks: https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html\n- Testing: https://docs.celeryq.dev/en/stable/userguide/testing.html\n- Django: https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html\n- Changelog: https://docs.celeryq.dev/en/stable/changelog.html\n- PyPI: https://pypi.org/project/celery/\n"
  },
  {
    "path": "content/cerberus/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cerberus Python package guide for schema validation, normalization, nested documents, and custom validators\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"cerberus,validation,schema,normalization,python\"\n---\n\n# Cerberus Python Package Guide\n\n## Golden Rule\n\nUse `cerberus.Validator` with an explicit schema for each payload shape you accept. Cerberus is a local validation library, not a hosted service, so there are no API keys, tokens, or required environment variables. In multithreaded code, create a fresh validator per document or guard shared instances with a lock because a validator stores the processed document on the instance.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"Cerberus==1.3.8\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Cerberus==1.3.8\"\npoetry add \"Cerberus==1.3.8\"\n```\n\nPyPI metadata for `1.3.8` declares `Requires: Python >=3.7`.\n\n## Initialize A Validator\n\nCerberus works with plain Python dictionaries for both schemas and documents:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"name\": {\"type\": \"string\", \"maxlength\": 50, \"required\": True},\n    \"age\": {\"type\": \"integer\", \"min\": 0},\n}\n\nvalidator = Validator(\n    schema,\n    allow_unknown=False,\n    require_all=False,\n)\n```\n\nNotes:\n\n- `allow_unknown=False` rejects fields not declared in the schema.\n- `require_all=False` means fields are optional unless you mark them `required: True`.\n- You can also instantiate `Validator()` without a schema and pass the schema to `validate(document, schema)` later.\n\n## Core Validation Workflow\n\nValidate a document and inspect `errors` when validation fails:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"name\": {\"type\": \"string\", \"maxlength\": 50, \"required\": True},\n    \"age\": {\"type\": \"integer\", \"min\": 18},\n}\n\ndocument = {\"name\": \"Ana\", \"age\": 16}\nvalidator = Validator(schema)\n\nif not validator.validate(document):\n    print(validator.errors)\n    # {'age': ['min value is 18']}\n```\n\nCerberus does not stop at the first problem. It processes the whole document and returns `False` when any field fails validation.\n\n### PATCH-style updates\n\nIf you are validating a partial update, pass `update=True` so missing required fields do not fail the check:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"name\": {\"type\": \"string\", \"required\": True},\n    \"email\": {\"type\": \"string\", \"required\": True},\n}\n\nvalidator = Validator(schema)\n\npayload = {\"email\": \"new@example.com\"}\nprint(validator.validate(payload, update=True))\n```\n\nWithout `update=True`, missing required fields still fail validation.\n\n## Normalization And Processed Output\n\nCerberus can coerce values, apply defaults, and remove fields before you use the document.\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"amount\": {\"type\": \"integer\", \"coerce\": int},\n    \"kind\": {\"type\": \"string\", \"default\": \"purchase\"},\n    \"id\": {\"type\": \"integer\", \"readonly\": True},\n}\n\nvalidator = Validator(\n    schema,\n    purge_unknown=True,\n    purge_readonly=True,\n)\n\npayload = {\n    \"amount\": \"5\",\n    \"id\": 99,\n    \"extra\": \"drop me\",\n}\n\ncleaned = validator.validated(payload)\n\nprint(cleaned)\n# {'amount': 5, 'kind': 'purchase'}\n```\n\nUseful behaviors:\n\n- `coerce` converts incoming values before validation.\n- `default` fills missing or `None` values during normalization.\n- `purge_unknown=True` removes fields that are not in the schema.\n- `purge_readonly=True` removes fields marked `readonly`.\n- After `validate(...)`, the normalized copy is also available as `validator.document`.\n\nIf you want only normalization without validation, call `validator.normalized(document)`.\n\n## Nested Documents And Collections\n\nUse `schema` for fixed nested structures and list items:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"customer\": {\n        \"type\": \"dict\",\n        \"require_all\": True,\n        \"schema\": {\n            \"email\": {\"type\": \"string\", \"regex\": r\"^[^@]+@[^@]+\\.[^@]+$\"},\n            \"country\": {\"type\": \"string\", \"minlength\": 2, \"maxlength\": 2},\n        },\n    },\n    \"items\": {\n        \"type\": \"list\",\n        \"schema\": {\n            \"type\": \"dict\",\n            \"schema\": {\n                \"sku\": {\"type\": \"string\", \"required\": True},\n                \"quantity\": {\"type\": \"integer\", \"min\": 1, \"required\": True},\n            },\n        },\n    },\n}\n\nvalidator = Validator(schema)\ndocument = {\n    \"customer\": {\"email\": \"ana@example.com\", \"country\": \"US\"},\n    \"items\": [{\"sku\": \"ABC-123\", \"quantity\": 2}],\n}\n\nprint(validator.validate(document))\n```\n\nFor arbitrary dictionaries, use `keysrules` and `valuesrules` instead of a fixed nested schema:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"scores\": {\n        \"type\": \"dict\",\n        \"keysrules\": {\"type\": \"string\", \"regex\": r\"^[a-z_]+$\"},\n        \"valuesrules\": {\"type\": \"integer\", \"min\": 0},\n    }\n}\n\nvalidator = Validator(schema)\nprint(validator.validate({\"scores\": {\"math\": 95, \"science\": 98}}))\n```\n\nUse `allow_unknown` on a nested dict when you want the parent document to stay strict but a particular subdocument to accept extra keys:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"profile\": {\n        \"type\": \"dict\",\n        \"allow_unknown\": {\"type\": \"string\"},\n        \"schema\": {\n            \"display_name\": {\"type\": \"string\"},\n        },\n    }\n}\n\nvalidator = Validator(schema)\nprint(\n    validator.validate(\n        {\"profile\": {\"display_name\": \"Ana\", \"timezone\": \"UTC\"}}\n    )\n)\n```\n\n## Cross-Field Checks\n\nUse built-in rules first. `dependencies` is the common choice when one field only makes sense when another field is present or has a specific value:\n\n```python\nfrom cerberus import Validator\n\nschema = {\n    \"payment_method\": {\"type\": \"string\"},\n    \"card_last4\": {\n        \"type\": \"string\",\n        \"dependencies\": {\"payment_method\": \"card\"},\n    },\n}\n\nvalidator = Validator(schema)\n\nprint(validator.validate({\"payment_method\": \"card\", \"card_last4\": \"4242\"}))\nprint(validator.validate({\"payment_method\": \"cash\", \"card_last4\": \"4242\"}))\nprint(validator.errors)\n```\n\n## Custom Rules And Types\n\nWhen the built-in rules are not enough, subclass `Validator`.\n\n### `check_with` methods\n\n```python\nfrom cerberus import Validator\n\n\nclass OrderValidator(Validator):\n    def _check_with_even_quantity(self, field, value):\n        if value % 2:\n            self._error(field, \"must be an even number\")\n\n\nschema = {\n    \"quantity\": {\"type\": \"integer\", \"check_with\": \"even_quantity\"}\n}\n\nvalidator = OrderValidator(schema)\nprint(validator.validate({\"quantity\": 4}))\nprint(validator.validate({\"quantity\": 3}))\nprint(validator.errors)\n```\n\n### Custom data types\n\nCopy `types_mapping` on the subclass before adding a type. Mutating it directly on an instance affects the class-level mapping.\n\n```python\nfrom decimal import Decimal\n\nimport cerberus\nfrom cerberus import Validator\n\n\ndecimal_type = cerberus.TypeDefinition(\"decimal\", (Decimal,), ())\n\n\nclass MoneyValidator(Validator):\n    types_mapping = Validator.types_mapping.copy()\n    types_mapping[\"decimal\"] = decimal_type\n\n\nschema = {\"price\": {\"type\": \"decimal\"}}\nvalidator = MoneyValidator(schema)\n\nprint(validator.validate({\"price\": Decimal(\"10.50\")}))\n```\n\n## Reusable Schemas With Registries\n\nIf you reuse the same fragments in multiple schemas, register them once and reference them by name:\n\n```python\nfrom cerberus import Validator, schema_registry\n\nschema_registry.add(\n    \"user_ref\",\n    {\n        \"uid\": {\"type\": \"integer\", \"min\": 1000},\n        \"email\": {\"type\": \"string\"},\n    },\n)\n\nschema = {\n    \"sender\": {\"type\": \"dict\", \"schema\": \"user_ref\", \"allow_unknown\": True},\n    \"receiver\": {\"type\": \"dict\", \"schema\": \"user_ref\", \"allow_unknown\": True},\n}\n\nvalidator = Validator(schema)\n```\n\nRegistries are useful when schemas are recursive, reused across many payloads, or loaded from serialized formats.\n\n## Errors And Debugging\n\nThe default `errors` output is a dictionary of field names to human-readable messages:\n\n```python\nfrom cerberus import Validator\n\nvalidator = Validator({\"count\": {\"type\": \"integer\"}})\nvalidator.validate({\"count\": \"two\"})\n\nprint(validator.errors)\n```\n\nFor programmatic inspection, Cerberus also exposes error objects and error trees after validation through `_errors`, `document_error_tree`, and `schema_error_tree`.\n\n## Common Pitfalls\n\n- `validate()` expects a mapping. Passing a list or scalar raises `DocumentError`.\n- `required` and `require_all` are different: `required` is per field, `require_all` applies to all schema-defined fields for a validator or nested dict.\n- `purge_unknown` does not override a nested `allow_unknown` rule. If a subdocument sets `allow_unknown`, its extra keys are kept.\n- Use `schema` for fixed keys and `keysrules` or `valuesrules` for arbitrary dictionaries.\n- Type checks run before most other rules. If a field fails `type`, later rules on that field are skipped.\n- Regex matching has a forced trailing `$` in Cerberus 1.3.x. Write complete patterns instead of assuming search-style matching.\n- Create a new validator per document in multithreaded code, or protect shared instances, because processed documents are stored on the validator instance.\n\n## Version-Sensitive Notes For `Cerberus 1.3.8`\n\n- PyPI lists `Cerberus 1.3.8` as the latest release, published on November 6, 2025.\n- PyPI metadata for `1.3.8` declares `Requires: Python >=3.7`.\n- The official docs site still exposes the changelog only through `1.3.5`, so use PyPI for the current package version and Python support floor, and use the maintainer docs for the stable 1.3 API surface documented here.\n\n## Official Sources\n\n- Maintainer docs: https://docs.python-cerberus.org/\n- FAQ: https://docs.python-cerberus.org/faq.html\n- Installation: https://docs.python-cerberus.org/install.html\n- Usage: https://docs.python-cerberus.org/usage.html\n- Validation rules: https://docs.python-cerberus.org/validation-rules.html\n- Normalization rules: https://docs.python-cerberus.org/normalization-rules.html\n- Extending: https://docs.python-cerberus.org/customize.html\n- Schemas and registries: https://docs.python-cerberus.org/schemas.html\n- Errors: https://docs.python-cerberus.org/errors.html\n- PyPI package page: https://pypi.org/project/Cerberus/\n"
  },
  {
    "path": "content/certifi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"certifi package guide for Python: Mozilla CA bundle access and trust-store usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.25\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"certifi,python,tls,ssl,certificates,ca-bundle\"\n---\n\n# certifi Python Package Guide\n\n## What It Is\n\n`certifi` ships Mozilla's CA bundle for Python applications. Its job is narrow:\n\n- expose the bundled `cacert.pem` file path\n- expose the PEM contents as text\n\nIt does not create HTTP clients, manage TLS sessions, or let you edit the trust store in place.\n\n## Install\n\n```bash\npip install certifi\n```\n\nPin the documented release when you need a specific root-certificate set:\n\n```bash\npip install certifi==2026.2.25\n```\n\nWith Poetry:\n\n```bash\npoetry add certifi\n```\n\nWith `uv`:\n\n```bash\nuv add certifi\n```\n\n## Initialize / Setup\n\n```python\nimport certifi\n\nca_bundle_path = certifi.where()\nca_bundle_pem = certifi.contents()\n```\n\n- `certifi.where()` returns the filesystem path to the packaged `cacert.pem`.\n- `certifi.contents()` returns the CA bundle as ASCII PEM text.\n\nCommand-line helpers:\n\n```bash\npython -m certifi\npython -m certifi --contents\n```\n\nUse `where()` when another library expects a CA file path. Use `contents()` only when you need the PEM text itself.\n\n## Core Usage\n\n### Pass the CA bundle path to an HTTP client\n\n```python\nimport certifi\nimport requests\n\nresponse = requests.get(\n    \"https://example.com\",\n    verify=certifi.where(),\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\n### Build an `ssl` context from the certifi bundle\n\n```python\nimport certifi\nimport ssl\n\nssl_context = ssl.create_default_context(cafile=certifi.where())\n```\n\n### Load the PEM contents directly\n\n```python\nimport certifi\n\npem_text = certifi.contents()\nassert \"BEGIN CERTIFICATE\" in pem_text\n```\n\n## Config / Auth\n\n`certifi` has no authentication model and no package-specific environment variables.\n\nConfiguration happens in the consuming library:\n\n- pass `certifi.where()` to a `verify`, `cafile`, or equivalent TLS option\n- use a different CA file entirely if your application must trust private or corporate roots\n- keep trust-store selection in app configuration, not by patching `certifi`\n\n## Common Pitfalls\n\n- Do not hardcode the installed path to `cacert.pem`; call `certifi.where()` at runtime.\n- Do not treat `certifi.contents()` as a filename; it returns the PEM text.\n- Do not edit the packaged CA bundle in `site-packages`; upstream explicitly does not support adding or removing certificates in place.\n- Do not expect `certifi` updates to be automatic. If you need newer Mozilla roots, upgrade the package.\n- Do not assume `certifi` itself changes hostname verification or TLS policy; it only supplies trust anchors.\n\n## Version-Sensitive Notes\n\n- `2026.2.25` was released on 2026-02-25.\n- This release requires Python `>=3.7`.\n- `certifi` uses date-like package versions, not semantic versions. Compare releases by their full published version string.\n- The current implementation delays locating or extracting `cacert.pem` until `where()` is called. In zipimport or similar packaged environments, treat the returned path as a runtime detail rather than a stable install path.\n\n## When To Reach For Something Else\n\n- If you need the operating system trust store, configure your TLS client to use the system defaults instead of forcing `certifi`.\n- If you need to trust an internal CA, supply your own CA bundle or client configuration rather than mutating `certifi`.\n- If you need an HTTP API client, use `requests`, `urllib3`, `httpx`, or another network library; `certifi` is only the certificate bundle.\n\n## Official Sources\n\n- PyPI project page: https://pypi.org/project/certifi/\n- Upstream repository: https://github.com/certifi/python-certifi\n- Source for runtime helpers: https://raw.githubusercontent.com/certifi/python-certifi/master/certifi/core.py\n- Source for CLI entrypoint: https://raw.githubusercontent.com/certifi/python-certifi/master/certifi/__main__.py\n"
  },
  {
    "path": "content/cffi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cffi for Python: call C libraries, build bindings, and package out-of-line modules\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"cffi,ffi,c,bindings,python,native\"\n---\n\n# cffi Python Package Guide\n\nUse `cffi` when Python code needs to call C functions, work with C structs and pointers, or ship Python bindings around an existing C library.\n\n## Golden Rule\n\n- Use `from cffi import FFI` and decide up front whether you need ABI mode or API mode.\n- Prefer out-of-line modules with `ffibuilder.set_source(...)` for packaged bindings.\n- Treat `ffi.verify()` as legacy compatibility only; upstream marks it deprecated.\n- Keep ownership and lifetime explicit. Most CFFI bugs are pointer lifetime, string encoding, or build configuration mistakes.\n\n## Install\n\nFor CPython:\n\n```bash\npip install cffi==2.0.0\n```\n\nFor a project dependency:\n\n```toml\n[project]\ndependencies = [\"cffi==2.0.0\"]\n```\n\nUpstream notes that `cffi` is distributed with PyPy, but projects should still follow their own dependency pinning policy.\n\n## Runtime and Build Requirements\n\n- Supported upstream on `2.0.0`: CPython `3.9` through `3.14`, plus PyPy.\n- PyPI declares `Requires: Python >=3.9`.\n- On non-Windows CPython, source builds may need a C compiler and `libffi` development headers.\n- On Linux, the usual missing-system-package failure is `libffi-dev`.\n- On macOS, upstream documents `pkg-config` plus `libffi` when a wheel is not usable.\n- `pycparser` is an automatic dependency of `cffi`.\n\nIf `pip install cffi` falls back to building from source on Linux or macOS, fix the system prerequisites first instead of debugging Python import errors.\n\n## Choose a Mode First\n\n### ABI mode\n\nUse ABI mode when the shared library already exists and you only need to describe its interface from Python.\n\nPros:\n\n- Fastest path for local scripting and internal tooling\n- No extension module to compile when using plain in-line `ffi.dlopen(...)`\n\nTradeoffs:\n\n- Less compile-time checking\n- Library loading and symbol lookup issues show up at runtime\n\n### API mode\n\nUse API mode when you are shipping bindings, need compiler-checked declarations, or want a generated module that imports cleanly.\n\nPros:\n\n- Better packaging story\n- Compiler fills in details and validates more of the declarations\n- Supports `extern \"Python\"` patterns for callbacks from C into Python\n\nTradeoffs:\n\n- Requires a build step\n- You must provide correct compiler and linker settings\n\n## Quick Start: ABI Mode\n\nThis is the shortest path when a native library already exists on the machine.\n\n```python\nfrom cffi import FFI\n\nffi = FFI()\nffi.cdef(\"\"\"\n    int puts(const char *s);\n\"\"\")\n\nlib = ffi.dlopen(None)  # standard C library on Unix\nlib.puts(b\"hello from cffi\")\n```\n\nTypical pattern for a real shared library:\n\n```python\nfrom cffi import FFI\nfrom ctypes.util import find_library\n\nffi = FFI()\nffi.cdef(\"\"\"\n    int sqlite3_libversion_number(void);\n\"\"\")\n\nlib = ffi.dlopen(find_library(\"sqlite3\"))\nprint(lib.sqlite3_libversion_number())\n```\n\nUse ABI mode when you already know the library path or can resolve it reliably on the target system.\n\n## Quick Start: Packaged API Mode\n\nThis is the safer default for reusable bindings.\n\nBuild script:\n\n```python\nfrom cffi import FFI\n\nffibuilder = FFI()\nffibuilder.cdef(\"\"\"\n    int add(int a, int b);\n\"\"\")\n\nffibuilder.set_source(\n    \"_example\",\n    \"\"\"\n    int add(int a, int b) {\n        return a + b;\n    }\n    \"\"\",\n)\n\nif __name__ == \"__main__\":\n    ffibuilder.compile(verbose=True)\n```\n\nRun the build once:\n\n```bash\npython build_example.py\n```\n\nUse the generated module:\n\n```python\nfrom _example import lib\n\nresult = lib.add(2, 3)\nprint(result)\n```\n\nIf you are binding an existing library instead of compiling inline C, pass headers and linker settings to `set_source(...)`:\n\n```python\nffibuilder.set_source(\n    \"mypkg._native\",\n    '#include \"mylib.h\"',\n    libraries=[\"mylib\"],\n    include_dirs=[\"/path/to/include\"],\n    library_dirs=[\"/path/to/lib\"],\n)\n```\n\n## Core Usage\n\n### Declare C signatures with `cdef()`\n\n`ffi.cdef(...)` takes C-like declarations. Keep them minimal and copy the parts you actually call.\n\n```python\nffi.cdef(\"\"\"\n    typedef struct {\n        int x;\n        int y;\n    } point_t;\n\n    void translate(point_t *p, int dx, int dy);\n\"\"\")\n```\n\nDo not put `#include` directives into `cdef()`. Put declarations there, and use `set_source(...)` for C headers and compilation details.\n\n### Allocate memory with `ffi.new()`\n\n```python\npoint = ffi.new(\"point_t *\", {\"x\": 10, \"y\": 20})\nlib.translate(point, 3, -5)\nprint(point.x, point.y)\n```\n\nImportant string rule:\n\n```python\nname = ffi.new(\"char[]\", b\"hello\")  # C string with trailing NUL\n```\n\n`ffi.new(\"char *\")` allocates only one character, not a C string buffer.\n\n### Convert C strings and buffers back to Python\n\n```python\nmessage = ffi.new(\"char[]\", b\"hello\")\nprint(ffi.string(message).decode(\"utf-8\"))\n```\n\nFor byte-oriented reads and writes:\n\n```python\nimage = ffi.new(\"unsigned char[]\", 1024)\nview = ffi.buffer(image)\n```\n\n### Keep owners alive\n\nOnly the original owning cdata returned by `ffi.new()` keeps the memory alive.\n\nCorrect:\n\n```python\nbuf = ffi.new(\"char[]\", b\"hello\")\nptr = ffi.new(\"char **\", buf)\nlib.consume(ptr)\n```\n\nWrong:\n\n```python\nptr = ffi.new(\"char **\", ffi.new(\"char[]\", b\"hello\"))\n```\n\nThe inner allocation can be freed immediately, leaving `ptr` with a dangling pointer.\n\n## Build and Packaging Configuration\n\nFor out-of-line modules, `set_source(...)` is the main configuration point.\n\nCommon arguments:\n\n- `libraries=[...]`: linker library names\n- `include_dirs=[...]`: C header search paths\n- `library_dirs=[...]`: linker search paths\n- `define_macros=[(...)]`: compile-time macros\n- `extra_compile_args=[...]`: compiler flags\n- `extra_link_args=[...]`: linker flags\n\nIf the dependency exposes `pkg-config` metadata, prefer `set_source_pkgconfig(...)` instead of hard-coding search paths.\n\nFor setuptools-based builds, upstream documents:\n\n```python\nsetup_requires=[\"cffi>=1.0.0\"]\ncffi_modules=[\"package/foo_build.py:ffibuilder\"]\ninstall_requires=[\"cffi>=1.0.0\"]\n```\n\nDo not start new packaging work on deprecated `distutils` flows.\n\n## Callbacks and Passing Python Context\n\nFor callbacks from C into Python, prefer API mode with `extern \"Python\"` or use a module-level `@ffi.callback(...)`.\n\nTypical context-passing pattern:\n\n```python\nhandle = ffi.new_handle(py_object)\n```\n\nLater, inside the callback:\n\n```python\nobj = ffi.from_handle(handle)\n```\n\nKeep the handle alive on the Python side for as long as C may call back with it.\n\n## Threading and Concurrency\n\nCFFI does not make an unsafe C library thread-safe. If you publish bindings around a native library, document the thread-safety contract of the wrapped library and add locking in Python when necessary.\n\n`2.0.0` adds support for free-threaded CPython, but only for `3.14t+`. Upstream explicitly says `3.13t` is not supported.\n\n## Common Pitfalls\n\n- `char *` maps to Python `bytes`, not `str`. Encode before passing into C, decode after reading from C.\n- `ffi.new(\"char *\")` is not a string allocation. Use `ffi.new(\"char[]\", data)` for C strings.\n- In out-of-line ABI mode, `ffi.dlopen(\"foo\")` does not do extra name resolution. Pass a real path or use `ctypes.util.find_library(\"foo\")`.\n- `ffi.dlopen(None)` for the standard C library is a Unix pattern; do not assume it is portable to Windows.\n- `ffi.verify()` is still supported for compatibility, but upstream marks it deprecated.\n- If you store a callback function pointer in C, keep the Python callback object alive for the entire time C may call it.\n- If you use `ffi.gc()` for resource cleanup, pair it with explicit release logic when lifetime matters.\n- On PyPy, large native allocations may need explicit memory-pressure hints if cleanup depends on GC timing.\n\n## Version-Sensitive Notes for `2.0.0`\n\n- `2.0.0` supports CPython `3.14`, including free-threaded `3.14t+`.\n- For free-threaded builds, upstream says extension builds must set `py_limited_api=False`.\n- `3.13t` is not supported because upstream reports segfaults from synchronization differences.\n- `2.0.0` drops Python `3.8`.\n- Since `1.16.0`, projects using CFFI features that depend on `distutils` at runtime on Python `3.12+` need an explicit `setuptools` dependency.\n\n## Practical Agent Guidance\n\n- Reach for ABI mode when the job is \"call a known shared library from one Python process\".\n- Reach for out-of-line API mode when the job is \"ship bindings in a package\" or \"support callbacks cleanly\".\n- Debug install failures as native build problems first: compiler, `libffi`, headers, linker paths, or wheel availability.\n- Debug runtime crashes as ownership, callback lifetime, wrong declarations, or thread-safety problems first.\n\n## Official Sources\n\n- Documentation: https://cffi.readthedocs.io/en/stable/\n- Installation: https://cffi.readthedocs.io/en/stable/installation.html\n- Overview: https://cffi.readthedocs.io/en/stable/overview.html\n- Preparing and distributing modules: https://cffi.readthedocs.io/en/stable/cdef.html\n- Using `ffi`/`lib`: https://cffi.readthedocs.io/en/stable/using.html\n- What's new: https://cffi.readthedocs.io/en/stable/whatsnew.html\n- PyPI registry: https://pypi.org/project/cffi/\n"
  },
  {
    "path": "content/cfgv/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cfgv package guide for Python configuration schema validation\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cfgv,python,configuration,validation\"\n---\n\n# cfgv Python Package Guide\n\n`cfgv` validates Python data structures against a schema and raises nested, human-readable `ValidationError` messages when configuration is wrong.\n\nIt does not parse configuration formats by itself. You load JSON, YAML, or another text format into Python objects, then validate those objects with `cfgv`.\n\n## Install\n\n```bash\npip install cfgv\n```\n\n- Import name: `cfgv`\n- Environment variables: none\n- Authentication: none\n- Client initialization: none\n\n## Define a schema\n\nThe core building blocks are:\n\n- `cfgv.Map(object_name, id_key, *items)` for dictionaries\n- `cfgv.Array(of, allow_empty=True)` for lists of nested objects\n- `cfgv.Required(...)` and `cfgv.Optional(...)` for keys in a map\n- `cfgv.NoAdditionalKeys(...)` to reject unexpected keys\n\n```python\nimport cfgv\n\nSERVICE_SCHEMA = cfgv.Map(\n    \"Service\",\n    \"name\",\n    cfgv.Required(\"name\", cfgv.check_string),\n    cfgv.Optional(\"enabled\", cfgv.check_bool, True),\n    cfgv.NoAdditionalKeys((\"name\", \"enabled\")),\n)\n\nAPP_CONFIG_SCHEMA = cfgv.Map(\n    \"Config\",\n    None,\n    cfgv.Required(\"version\", cfgv.check_int),\n    cfgv.RequiredRecurse(\"service\", SERVICE_SCHEMA),\n    cfgv.Optional(\"mode\", cfgv.check_one_of({\"dev\", \"prod\"}), \"dev\"),\n    cfgv.NoAdditionalKeys((\"version\", \"service\", \"mode\")),\n)\n```\n\nChoose `object_name` and `id_key` carefully. They are included in error output, so readable values make failures much easier to debug.\n\n## Validate data and apply defaults\n\n`cfgv.validate(value, schema)` checks the data and returns the original value on success. It does not add defaults.\n\nUse `cfgv.apply_defaults(value, schema)` when you want a new object with optional defaults populated.\n\nUsing `APP_CONFIG_SCHEMA` from the previous example:\n\n```python\nimport cfgv\n\nconfig = {\n    \"version\": 1,\n    \"service\": {\"name\": \"api\"},\n}\n\ntry:\n    cfgv.validate(config, APP_CONFIG_SCHEMA)\nexcept cfgv.ValidationError as error:\n    print(error)\n    raise\n\nconfig_with_defaults = cfgv.apply_defaults(config, APP_CONFIG_SCHEMA)\n\nprint(config_with_defaults)\n# {'version': 1, 'service': {'name': 'api', 'enabled': True}, 'mode': 'dev'}\n```\n\nIf you need to serialize a config without values that only exist because of defaults, use `cfgv.remove_defaults(value, schema)`.\n\n```python\ncleaned = cfgv.remove_defaults(config_with_defaults, APP_CONFIG_SCHEMA)\nprint(cleaned)\n# {'version': 1, 'service': {'name': 'api'}}\n```\n\n## Load and validate a file\n\n`cfgv.load_from_filename()` reads a UTF-8 text file, passes the file contents to your loader function, validates the parsed data, and returns a new object with defaults applied.\n\nUsing `APP_CONFIG_SCHEMA` from the earlier schema definition:\n\n```python\nimport functools\nimport json\n\nimport cfgv\n\n\nclass InvalidConfigError(Exception):\n    pass\n\n\nload_app_config = functools.partial(\n    cfgv.load_from_filename,\n    schema=APP_CONFIG_SCHEMA,\n    load_strategy=json.loads,\n    exc_tp=InvalidConfigError,\n)\n\nconfig = load_app_config(\"config.json\")\n```\n\nYour `load_strategy` must accept the file contents as a string and return Python data structures such as dictionaries, lists, strings, integers, and booleans.\n\nIf you want friendlier file paths in error messages, pass `display_filename=`:\n\n```python\nconfig = cfgv.load_from_filename(\n    \"./config.json\",\n    APP_CONFIG_SCHEMA,\n    json.loads,\n    display_filename=\"config.json\",\n)\n```\n\n## Common patterns\n\n### Arrays of nested objects\n\nUse `cfgv.Array()` together with a nested `cfgv.Map()` when a key contains a list of structured items.\n\n```python\nimport cfgv\n\nHOOK_SCHEMA = cfgv.Map(\n    \"Hook\",\n    \"id\",\n    cfgv.Required(\"id\", cfgv.check_string),\n    cfgv.OptionalNoDefault(\"pattern\", cfgv.check_regex),\n    cfgv.NoAdditionalKeys((\"id\", \"pattern\")),\n)\n\nHOOKS_CONFIG_SCHEMA = cfgv.Map(\n    \"Config\",\n    None,\n    cfgv.RequiredRecurse(\"hooks\", cfgv.Array(HOOK_SCHEMA, allow_empty=False)),\n    cfgv.NoAdditionalKeys((\"hooks\",)),\n)\n```\n\n### Conditional keys\n\nUse `cfgv.Conditional()` when one field is only valid when another field has a particular value.\n\n```python\nimport cfgv\n\nAUTH_SCHEMA = cfgv.Map(\n    \"Auth\",\n    None,\n    cfgv.Required(\"type\", cfgv.check_one_of({\"anonymous\", \"token\"})),\n    cfgv.Conditional(\n        \"token\",\n        cfgv.check_string,\n        \"type\",\n        \"token\",\n        ensure_absent=True,\n    ),\n    cfgv.NoAdditionalKeys((\"type\", \"token\")),\n)\n```\n\nWith `ensure_absent=True`, `cfgv` rejects `token` when `type` is not `\"token\"`.\n\n## Useful built-in helpers\n\n- Scalar checks: `cfgv.check_bool`, `cfgv.check_bytes`, `cfgv.check_int`, `cfgv.check_string`, `cfgv.check_text`\n- Choice checks: `cfgv.check_one_of(...)`, `cfgv.In(...)`, `cfgv.NotIn(...)`, `cfgv.Not(...)`\n- Composition: `cfgv.check_array(inner_check)`, `cfgv.check_and(*checks)`\n- Nested schemas: `cfgv.RequiredRecurse(...)`, `cfgv.OptionalRecurse(...)`, `cfgv.ConditionalRecurse(...)`\n- Extra-key handling: `cfgv.NoAdditionalKeys(...)`, `cfgv.WarnAdditionalKeys(keys, callback)`\n\n## Pitfalls\n\n- `cfgv` validates Python objects, not raw YAML or JSON text. Parse the file first or use `load_from_filename()` with an appropriate loader.\n- `cfgv.validate()` does not mutate data and does not fill in optional defaults.\n- `cfgv.apply_defaults()` and `cfgv.remove_defaults()` return new values instead of modifying the input in place.\n- Default values are inserted exactly as provided to `cfgv.Optional(...)` or `cfgv.OptionalRecurse(...)`. Avoid mutable defaults such as `[]` or `{}` unless you control later mutation.\n- `cfgv.NoAdditionalKeys(...)` is strict: any undeclared key raises `ValidationError`.\n- Error readability depends on your schema names. A good `object_name` and `id_key` make nested failures much easier to trace.\n\n## Official sources\n\n- Maintainer repository: https://github.com/asottile/cfgv\n- Package registry: https://pypi.org/project/cfgv/\n"
  },
  {
    "path": "content/chalk/docs/chalk/javascript/DOC.md",
    "content": "---\nname: chalk\ndescription: \"Chalk for styling terminal output in JavaScript CLIs with ANSI colors, modifiers, color detection, and stderr-aware output.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.6.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"chalk,cli,terminal,ansi,node,javascript\"\n---\n\n# Chalk Guide for JavaScript CLIs\n\n## Golden Rule\n\nUse `chalk` to format terminal strings, then pass the returned string to `console.log`, `console.error`, `process.stdout.write`, or your logger.\n\nChalk does not need API credentials or service configuration. It auto-detects terminal color support from the current environment.\n\nChalk `5.6.2` is ESM-only. Use `import chalk from 'chalk'` in an ESM package or an `.mjs` file.\n\n## Install\n\nChalk `5.6.2` declares these supported Node.js versions:\n\n- `^12.17.0 || ^14.13 || >=16.0.0`\n\nInstall the package:\n\n```bash\nnpm install chalk@5.6.2\n```\n\nIf your project is not already ESM, set `\"type\": \"module\"` in `package.json`:\n\n```json\n{\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"chalk\": \"5.6.2\"\n  }\n}\n```\n\nMinimal usage:\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(chalk.green('ready'));\n```\n\n## Imports and Initialization\n\nDefault import:\n\n```js\nimport chalk from 'chalk';\n```\n\nNamed exports you will commonly use:\n\n```js\nimport chalk, {\n  Chalk,\n  chalkStderr,\n  supportsColor,\n  supportsColorStderr,\n  modifierNames,\n  foregroundColorNames,\n} from 'chalk';\n```\n\nThere is no client initialization step unless you want a separate Chalk instance with its own color level:\n\n```js\nimport {Chalk} from 'chalk';\n\nconst noColor = new Chalk({level: 0});\nconst basicColor = new Chalk({level: 1});\nconst fullColor = new Chalk({level: 3});\n\nconsole.log(noColor.red('plain text output'));\nconsole.log(fullColor.hex('#FF8800')('accent color'));\n```\n\nPrefer a new `Chalk` instance inside reusable libraries instead of mutating `chalk.level` globally.\n\n## Color Control\n\nChalk reads color support automatically, but users can override it with flags or environment variables.\n\nSupported overrides:\n\n- `--color`\n- `--no-color`\n- `--color=256`\n- `--color=16m`\n- `FORCE_COLOR=0`\n- `FORCE_COLOR=1`\n- `FORCE_COLOR=2`\n- `FORCE_COLOR=3`\n\nExamples:\n\n```bash\nFORCE_COLOR=0 node cli.js\nFORCE_COLOR=3 node cli.js\nnode cli.js --no-color\nnode cli.js --color=256\nnode cli.js --color=16m\n```\n\n`FORCE_COLOR` overrides Chalk's normal color detection.\n\n## Common Workflows\n\n### Style terminal output\n\nChain styles and call the last one with a string. Multiple arguments are joined with spaces.\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(chalk.blue('Hello world!'));\nconsole.log(chalk.blue.bgRed.bold('Build failed'));\nconsole.log(chalk.red('Error:', 'missing config file'));\n```\n\nStyle order does not matter, and later conflicting styles win:\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(chalk.red.yellow.green('final color is green'));\n```\n\n### Compose reusable styles\n\n```js\nimport chalk from 'chalk';\n\nconst error = chalk.bold.red;\nconst warning = chalk.hex('#FFA500');\nconst success = chalk.green;\n\nconsole.log(error('Error: invalid token'));\nconsole.log(warning('Warning: using fallback config'));\nconsole.log(success('Done'));\n```\n\n### Nest styles\n\nNested substrings are re-opened correctly, so you can mix accent text inside a broader style.\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(\n  chalk.green(\n    'Deploying ' + chalk.blue.underline('api-service') + ' to production'\n  )\n);\n```\n\n### Use RGB, hex, and 256-color values\n\nUse color-model helpers when named colors are not enough.\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(chalk.rgb(123, 45, 67).underline('custom RGB'));\nconsole.log(chalk.hex('#DEADED').bold('custom hex'));\nconsole.log(chalk.ansi256(201)('palette index 201'));\n\nconsole.log(chalk.bgRgb(20, 20, 20).white('dark background'));\nconsole.log(chalk.bgHex('#222222').cyan('hex background'));\nconsole.log(chalk.bgAnsi256(236).white('256-color background'));\n```\n\nChalk downsamples RGB and hex colors to the best format supported by the current terminal, or by the `level` you set on a custom instance.\n\n### Branch on terminal color support\n\n`supportsColor` is exposed for convenience. It is either `false` or an object with `level`, `hasBasic`, `has256`, and `has16m`.\n\n```js\nimport chalk, {supportsColor} from 'chalk';\n\nconst accent = supportsColor?.has16m\n  ? chalk.hex('#FF8800')\n  : chalk.yellow;\n\nconsole.log(accent('Deploying application'));\n```\n\n### Use a stderr-specific Chalk instance\n\nIf you write directly to `stderr`, use `chalkStderr` so detection is based on the `stderr` stream.\n\n```js\nimport {chalkStderr, supportsColorStderr} from 'chalk';\n\nif (supportsColorStderr) {\n  process.stderr.write(chalkStderr.red('fatal: build failed\\n'));\n} else {\n  process.stderr.write('fatal: build failed\\n');\n}\n```\n\n### Show cosmetic output only when color is enabled\n\n`visible` returns an empty string when Chalk's color level is `0`.\n\n```js\nimport chalk from 'chalk';\n\nconsole.log(`${chalk.visible('✔')} build finished`);\n```\n\n### Validate user-provided style names\n\nUse the exported style-name arrays when you accept style names from config or CLI flags.\n\n```js\nimport chalk, {foregroundColorNames, modifierNames} from 'chalk';\n\nfunction paint(text, colorName, modifierName) {\n  if (!foregroundColorNames.includes(colorName)) {\n    throw new Error(`Unsupported foreground color: ${colorName}`);\n  }\n\n  if (!modifierNames.includes(modifierName)) {\n    throw new Error(`Unsupported modifier: ${modifierName}`);\n  }\n\n  return chalk[modifierName][colorName](text);\n}\n\nconsole.log(paint('release', 'green', 'bold'));\n```\n\n## Important Behavior and Pitfalls\n\n- Chalk `5` is ESM-only. Do not use `require('chalk')` for this version.\n- Upstream notes that if you need Chalk in TypeScript or a build-tool setup that cannot consume the ESM package cleanly, you will probably want Chalk `4` instead.\n- `chalk.level` on the default export affects all Chalk consumers in the current process. Prefer `new Chalk({level})` in shared libraries.\n- Some modifiers are not widely supported across terminals: `italic`, `underline`, `overline`, and `strikethrough`.\n- `chalkStderr` and `supportsColorStderr` can differ from `chalk` and `supportsColor` because `stdout` and `stderr` are detected separately.\n- On Windows, the upstream README recommends Windows Terminal instead of `cmd.exe`.\n\n## Reference Pattern\n\nThis is a practical starting point for a Node.js CLI that respects the user's terminal settings:\n\n```js\n#!/usr/bin/env node\nimport chalk, {Chalk, supportsColor} from 'chalk';\n\nconst plain = new Chalk({level: 0});\n\nfunction info(message) {\n  console.log(chalk.blue(message));\n}\n\nfunction warn(message) {\n  console.warn(chalk.hex('#FFA500')(message));\n}\n\nfunction fail(message) {\n  console.error(chalk.bold.red(message));\n}\n\ninfo('Starting deploy');\n\nif (supportsColor?.has16m) {\n  console.log(chalk.hex('#7C3AED')('Truecolor output enabled'));\n} else {\n  console.log(plain('Limited terminal color support'));\n}\n\nwarn('Using default region');\nfail('Deployment failed');\n```\n"
  },
  {
    "path": "content/charset-normalizer/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"charset-normalizer for Python: detect and normalize text encodings from bytes or files\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.5\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"python,encoding,unicode,text,charset,normalization,chardet\"\n---\n\n# charset-normalizer Python Package Guide\n\n## What It Is\n\n`charset-normalizer` is a Python library for detecting the most likely text encoding for raw bytes or files and converting the result to usable Unicode text. It is commonly used directly, and it is also the maintained alternative to `chardet` in parts of the Python ecosystem.\n\nUse it when you have bytes with no trustworthy declared charset. If the source already declares an encoding you trust, prefer that declared encoding first.\n\n## Install\n\n```bash\npip install charset-normalizer\n```\n\nSpecific version:\n\n```bash\npip install charset-normalizer==3.4.5\n```\n\nOptional Unicode data backport:\n\n```bash\npip install \"charset-normalizer[unicode-backport]\"\n```\n\n## Core Usage\n\n### Detect from bytes\n\n```python\nfrom charset_normalizer import from_bytes\n\npayload = b\"\\x48\\x65\\x6c\\x6c\\x6f\"\nmatches = from_bytes(payload)\nbest = matches.best()\n\nif best is None:\n    raise ValueError(\"Input does not look like text\")\n\nprint(best.encoding)\nprint(best.language)\nprint(str(best))\n```\n\n### Detect from a file path\n\n```python\nfrom charset_normalizer import from_path\n\nbest = from_path(\"data.txt\").best()\n\nif best is not None:\n    text = str(best)\n    utf8_bytes = best.output()\n```\n\n### Detect from an open binary file handle\n\n```python\nfrom charset_normalizer import from_fp\n\nwith open(\"data.txt\", \"rb\") as fh:\n    best = from_fp(fh).best()\n```\n\n## Result Model\n\nThe primary APIs return a `CharsetMatches` collection. Call `.best()` to get the preferred `CharsetMatch` or `None`.\n\nUseful `CharsetMatch` properties and methods:\n\n- `encoding`: detected encoding name\n- `language`: best-effort detected language, or `\"Unknown\"`\n- `could_be_from_charset`: alternative encodings that decode to the same text\n- `encoding_aliases`: normalized alias names\n- `raw`: original bytes\n- `output(encoding=\"utf_8\")`: re-encode the decoded text, UTF-8 by default\n- `str(match)`: decoded Unicode text\n\nExample:\n\n```python\nfrom charset_normalizer import from_bytes\n\nbest = from_bytes(blob).best()\nif best:\n    print(best.encoding)\n    print(best.could_be_from_charset)\n    normalized = best.output(\"utf_8\")\n```\n\n## Choosing the Right API\n\n### Preferred modern APIs\n\n- `from_bytes(...)`\n- `from_path(...)`\n- `from_fp(...)`\n- `is_binary(...)`\n\nThese are the stable public interfaces documented with backward-compatibility guarantees.\n\n### Legacy compatibility API\n\n```python\nfrom charset_normalizer import detect\n\nresult = detect(blob)\nprint(result[\"encoding\"])\n```\n\n`detect()` exists mainly for `chardet`-style compatibility and migration. Upstream marks it as deprecated, but not planned for removal. Prefer `from_bytes(...).best()` for new code.\n\n## Binary Detection\n\nUse `is_binary(...)` before treating unknown input as text if you need a hard text-vs-binary decision.\n\n```python\nfrom charset_normalizer import is_binary\n\nif is_binary(\"archive.bin\"):\n    print(\"Skip decoding\")\n```\n\n`is_binary()` accepts a path, bytes payload, or binary file object.\n\n## Configuration And Debugging\n\nThere is no service configuration or authentication. Control behavior through function arguments.\n\nCommon knobs on `from_bytes`, `from_path`, and `from_fp`:\n\n- `threshold`: maximum chaos tolerated before rejecting a candidate\n- `cp_isolation`: only test specific code pages\n- `cp_exclusion`: skip specific code pages\n- `preemptive_behaviour`: prioritize likely encodings hinted by the content\n- `language_threshold`: minimum coherence for language inference\n- `enable_fallback`: allow fallback matches when strict detection fails\n- `explain=True`: emit debug-oriented detection logs\n\nExample:\n\n```python\nfrom charset_normalizer import from_bytes\n\nbest = from_bytes(\n    blob,\n    threshold=0.15,\n    cp_isolation=[\"utf_8\", \"cp1252\", \"iso8859_1\"],\n    explain=True,\n).best()\n```\n\nIf you want explicit logger wiring instead of the built-in debug helper, use `charset_normalizer.utils.set_logging_handler(...)`.\n\n## CLI Usage\n\nThe package installs a `normalizer` CLI.\n\nInspect a file:\n\n```bash\nnormalizer sample.txt\n```\n\nMinimal output:\n\n```bash\nnormalizer -m sample.txt\n```\n\nNormalize to Unicode output files:\n\n```bash\nnormalizer -n sample.txt\n```\n\nModule form:\n\n```bash\npython -m charset_normalizer sample.txt\n```\n\nThe CLI emits JSON by default. Use it for quick inspection, conversion, or debugging when you do not need Python code.\n\n## Common Pitfalls\n\n- Package name and import name differ: install `charset-normalizer`, import `charset_normalizer`.\n- `best()` can return `None`. Treat that as \"not confidently text\" instead of assuming UTF-8.\n- Detection is a fallback tool, not a substitute for trustworthy declared encodings from HTTP headers, file metadata, or protocol specs.\n- `detect()` is for compatibility. New code should use `from_bytes`, `from_path`, or `from_fp`.\n- Optimized wheels may include a compiled `md__mypyc` module. Some standalone bundlers like PyInstaller can miss that hidden import.\n- If you need a pure-Python install without speedups, use `pip install charset-normalizer --no-binary :all:`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `3.4.5` as the latest release, published on `2026-03-06`.\n- The Read the Docs pages under `/en/latest/` still identify themselves as `3.4.4` on `2026-03-11`. Treat the API docs as current enough for usage, but note the version banner lag.\n- The upstream changelog entry for `3.4.5` only notes a build-related fix for the optimized build (`libm` linkage). There are no documented Python API changes in that release.\n- `3.4.2` included a CLI fix for Python deprecation warnings around `argparse.FileType`.\n- `3.4.0` added the CLI `--no-preemptive` option and Python 3.13 support.\n\n## Bundling And Deployment Notes\n\nIf a frozen executable fails with `ModuleNotFoundError: No module named 'charset_normalizer.md__mypyc'`, upstream recommends either:\n\n- adding the hidden import in the bundler configuration, or\n- reinstalling without binary speedups\n\n```bash\npip install charset-normalizer --no-binary :all:\n```\n\n## Official Sources\n\n- Docs: https://charset-normalizer.readthedocs.io/en/latest/\n- Installation and basic usage: https://charset-normalizer.readthedocs.io/en/latest/user/getstarted.html\n- Result handling: https://charset-normalizer.readthedocs.io/en/latest/user/handling_result.html\n- CLI: https://charset-normalizer.readthedocs.io/en/latest/user/cli.html\n- Miscellaneous and `is_binary()`: https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html\n- FAQ: https://charset-normalizer.readthedocs.io/en/latest/community/faq.html\n- API reference: https://charset-normalizer.readthedocs.io/en/latest/api.html\n- Optional speedup extension: https://charset-normalizer.readthedocs.io/en/latest/community/speedup.html\n- PyPI package metadata: https://pypi.org/project/charset-normalizer/\n- Upstream changelog: https://github.com/Ousret/charset_normalizer/blob/master/CHANGELOG.md\n"
  },
  {
    "path": "content/chokidar/docs/chokidar/javascript/DOC.md",
    "content": "---\nname: chokidar\ndescription: \"chokidar JavaScript package guide for recursive file watching, ignore filters, polling, and stable write handling\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"chokidar,javascript,nodejs,filesystem,file-watching\"\n---\n\n# chokidar JavaScript Package Guide\n\n## Golden Rule\n\nUse `chokidar` to watch concrete files and directories, not glob patterns. In the current v4 line, watch a real root such as `src` or `uploads`, then narrow what you receive with `ignored`, `cwd`, `depth`, and event handlers.\n\n## Install\n\n```bash\nnpm install chokidar@4.0.3\n```\n\n`chokidar@4` requires Node `>=14.16.0` and publishes both ESM and CommonJS entry points.\n\n```js\nimport chokidar from 'chokidar'\n```\n\n```js\nconst chokidar = require('chokidar')\n```\n\n## Setup And Configuration\n\n`chokidar` is a local filesystem library. There is no auth flow, service endpoint, or required environment variable.\n\nOptional environment variables from the maintainer docs:\n\n- `CHOKIDAR_USEPOLLING=1` forces polling instead of `fs.watch`\n- `CHOKIDAR_INTERVAL=250` changes the polling interval in milliseconds\n\nUse those only when you need them. Polling is useful for some network filesystems and bind mounts, but it uses more CPU than the default watcher.\n\n## Start A Watcher\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch(['src', 'package.json'], {\n  persistent: true,\n  ignoreInitial: true,\n  cwd: process.cwd(),\n  awaitWriteFinish: {\n    stabilityThreshold: 2000,\n    pollInterval: 100,\n  },\n})\n\nwatcher\n  .on('add', path => {\n    console.log(`file added: ${path}`)\n  })\n  .on('change', path => {\n    console.log(`file changed: ${path}`)\n  })\n  .on('unlink', path => {\n    console.log(`file removed: ${path}`)\n  })\n  .on('addDir', path => {\n    console.log(`directory added: ${path}`)\n  })\n  .on('unlinkDir', path => {\n    console.log(`directory removed: ${path}`)\n  })\n  .on('error', error => {\n    console.error('watch error', error)\n  })\n  .on('ready', () => {\n    console.log('initial scan complete')\n  })\n\nprocess.on('SIGINT', async () => {\n  await watcher.close()\n  process.exit(0)\n})\n```\n\nKey points:\n\n- `ignoreInitial: true` skips the startup `add` and `addDir` events for files already present\n- `cwd` makes emitted paths relative to that directory\n- `ready` fires after the initial scan finishes\n- `close()` is asynchronous, so `await` it before exiting or replacing the watcher\n\n## Watch A Directory Without Globs\n\nv4 removes glob support. Instead of watching `src/**/*.js`, watch `src` and filter what you do not want.\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('src', {\n  ignoreInitial: true,\n  depth: 3,\n  ignored: (watchedPath, stats) => {\n    if (watchedPath.includes('/node_modules/') || watchedPath.includes('\\\\node_modules\\\\')) {\n      return true\n    }\n\n    if (watchedPath.endsWith('.map')) {\n      return true\n    }\n\n    if (stats?.isFile() && !watchedPath.endsWith('.js')) {\n      return true\n    }\n\n    return false\n  },\n})\n\nwatcher.on('all', (event, path) => {\n  console.log(event, path)\n})\n```\n\n`ignored` receives the full relative or absolute path. If you provide a two-argument function, chokidar may also pass `fs.Stats` for that path.\n\n## Wait For Stable Writes\n\nWhen an editor or upload process writes a file in chunks, `add` and `change` can happen before the final bytes are on disk. Use `awaitWriteFinish` when your code must read the finished file.\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('uploads', {\n  ignoreInitial: true,\n  awaitWriteFinish: {\n    stabilityThreshold: 5000,\n    pollInterval: 250,\n  },\n})\n\nwatcher.on('add', async path => {\n  console.log(`safe to process ${path}`)\n})\n```\n\nThis delays events until file size stays unchanged for the configured threshold. Use it carefully because it makes detection less responsive.\n\n## Handle Atomic Writes\n\nSome editors write by replacing a file instead of modifying it in place. `atomic` helps collapse a fast delete-and-recreate sequence into a single `change` event.\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('src', {\n  ignoreInitial: true,\n  atomic: 200,\n})\n```\n\nSet `atomic` to a custom millisecond value when the default delay is too short for your editor or filesystem.\n\n## Use Polling For Network Or Virtualized Filesystems\n\nIf file events are unreliable over a network share, Docker bind mount, or another non-standard filesystem, switch to polling.\n\n```bash\nCHOKIDAR_USEPOLLING=1 CHOKIDAR_INTERVAL=250 node scripts/watch.js\n```\n\nYou can also set the same behavior in code:\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('shared', {\n  usePolling: true,\n  interval: 250,\n  binaryInterval: 300,\n})\n```\n\nPrefer the default non-polling mode when it works. Polling increases CPU usage.\n\n## Read Stats And Inspect Watched Paths\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('src', {\n  ignoreInitial: true,\n  alwaysStat: true,\n})\n\nwatcher.on('change', (path, stats) => {\n  if (stats) {\n    console.log(`${path} is now ${stats.size} bytes`)\n  }\n})\n\nconsole.log(watcher.getWatched())\n```\n\n`alwaysStat: true` asks chokidar to provide `fs.Stats` for `add`, `addDir`, and `change` events even when the underlying watcher would not normally include them.\n\n## Add And Remove Paths Dynamically\n\n```js\nimport chokidar from 'chokidar'\n\nconst watcher = chokidar.watch('src', {\n  ignoreInitial: true,\n})\n\nwatcher.add(['templates', 'config/local.json'])\n\nawait watcher.unwatch('config/local.json')\n\nconsole.log(watcher.getWatched())\n\nawait watcher.close()\n```\n\nUse `add()` to expand an existing watcher without creating a second `FSWatcher` instance.\n\n## Events And Methods You Will Use Most\n\nCommon events:\n\n- `add`\n- `addDir`\n- `change`\n- `unlink`\n- `unlinkDir`\n- `ready`\n- `error`\n- `all`\n\nImportant methods:\n\n- `chokidar.watch(paths, options)` creates an `FSWatcher`\n- `watcher.add(paths)` adds new files or directories to an existing watcher\n- `watcher.unwatch(paths)` stops watching specific paths\n- `watcher.getWatched()` returns the current directory-to-entries map\n- `await watcher.close()` shuts the watcher down cleanly\n\n`raw` is also available, but the maintainer docs describe it as internal. Use the normalized events above for app logic unless you specifically need low-level watcher details.\n\n## Common Pitfalls\n\n- Do not pass glob patterns such as `src/**/*.js` to v4. Watch concrete roots instead.\n- Do not forget to `await watcher.close()`. Closing is asynchronous.\n- Do not watch your whole repository unless you need to. Chokidar watches recursively, so broad roots can consume a lot of system resources.\n- Use `depth` to cap recursion when you only care about a few nested levels.\n- Use `awaitWriteFinish` only when you need fully written files. It trades latency for correctness.\n- Use `usePolling` only when native file events are unreliable. It trades CPU for reliability.\n\nOn Linux, `ENOSPC` usually means the inotify watch limit is too low. The maintainer README suggests increasing it with:\n\n```bash\necho fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n```\n"
  },
  {
    "path": "content/chromadb/docs/embeddings-db/javascript/DOC.md",
    "content": "---\nname: embeddings-db\ndescription: \"ChromaDB JavaScript/TypeScript SDK for vector embeddings and AI-powered search\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.17\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"chromadb,embeddings,vector-db,ai,search\"\n---\n\n# ChromaDB JavaScript/TypeScript SDK - v3.0.17\n\n## Golden Rule\n\n**ALWAYS use the official `chromadb` package (v3.0.17 or later) for JavaScript/TypeScript projects.**\n\n```bash\nnpm install chromadb\n```\n\n**For default embeddings support, also install:**\n\n```bash\nnpm install @chroma-core/default-embed\n```\n\n**DO NOT use:**\n- Deprecated or unofficial ChromaDB packages\n- Old client libraries like `chromadb-client`\n- Community wrappers that may be outdated\n\nChromaDB is the official AI-native open-source vector database. It handles embeddings, indexing, and vector similarity search automatically.\n\n---\n\n## Installation\n\n### Using npm\n\n```bash\nnpm install chromadb @chroma-core/default-embed\n```\n\n### Using yarn\n\n```bash\nyarn add chromadb @chroma-core/default-embed\n```\n\n### Using pnpm\n\n```bash\npnpm add chromadb @chroma-core/default-embed\n```\n\n### Using bun\n\n```bash\nbun add chromadb @chroma-core/default-embed\n```\n\n---\n\n## Server Setup\n\nChromaDB requires a backend server to connect to. You have two options:\n\n### Option 1: Run ChromaDB Server Locally\n\n```bash\nchroma run --path ./my-chroma-data\n```\n\nThis starts a ChromaDB server on `http://localhost:8000`\n\n### Option 2: Run ChromaDB with Docker\n\n```bash\ndocker pull chromadb/chroma\ndocker run -p 8000:8000 chromadb/chroma\n```\n\n---\n\n## Initialization\n\n### Basic Client Connection\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient();\n```\n\nThis connects to `http://localhost:8000` by default.\n\n### Custom Host/Port Configuration\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient({\n  path: \"http://localhost:8000\"\n});\n```\n\n### With Authentication Headers\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient({\n  path: \"http://localhost:8000\",\n  auth: {\n    provider: \"token\",\n    credentials: \"your-auth-token\"\n  }\n});\n```\n\n### Remote Server Connection\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient({\n  path: \"https://your-chroma-server.com:8000\"\n});\n```\n\n---\n\n## Collections\n\n### Create a Collection\n\n```typescript\nconst collection = await client.createCollection({\n  name: \"my_collection\"\n});\n```\n\n### Create Collection with Distance Metric\n\n```typescript\nconst collection = await client.createCollection({\n  name: \"my_collection\",\n  metadata: {\n    \"hnsw:space\": \"cosine\"  // Options: \"cosine\", \"l2\", \"ip\"\n  }\n});\n```\n\n**Distance Metrics:**\n- `cosine`: Cosine similarity (best for text, normalized vectors)\n- `l2`: Euclidean/L2 distance (default, sensitive to magnitude)\n- `ip`: Inner product (for recommendation systems)\n\n### Get an Existing Collection\n\n```typescript\nconst collection = await client.getCollection({\n  name: \"my_collection\"\n});\n```\n\n### Get or Create Collection\n\n```typescript\nconst collection = await client.getOrCreateCollection({\n  name: \"my_collection\"\n});\n```\n\n### List All Collections\n\n```typescript\nconst collections = await client.listCollections();\nconsole.log(collections);\n```\n\n### Delete a Collection\n\n```typescript\nawait client.deleteCollection({\n  name: \"my_collection\"\n});\n```\n\n---\n\n## Adding Data\n\n### Add Documents (Auto-Embedding)\n\n```typescript\nawait collection.add({\n  ids: [\"id1\", \"id2\", \"id3\"],\n  documents: [\n    \"This is a document about pineapples\",\n    \"This is a document about oranges\",\n    \"This is a document about apples\"\n  ]\n});\n```\n\nChromaDB will automatically embed the documents using the default embedding function.\n\n### Add with Metadata\n\n```typescript\nawait collection.add({\n  ids: [\"id1\", \"id2\", \"id3\"],\n  documents: [\n    \"This is a document about pineapples\",\n    \"This is a document about oranges\",\n    \"This is a document about apples\"\n  ],\n  metadatas: [\n    { category: \"tropical\", color: \"yellow\" },\n    { category: \"citrus\", color: \"orange\" },\n    { category: \"temperate\", color: \"red\" }\n  ]\n});\n```\n\n### Add with Custom Embeddings\n\n```typescript\nawait collection.add({\n  ids: [\"id1\", \"id2\"],\n  embeddings: [\n    [1.5, 2.9, 3.4, 1.2, 0.8],\n    [9.8, 2.3, 2.9, 4.1, 3.3]\n  ],\n  documents: [\"Document one\", \"Document two\"],\n  metadatas: [\n    { source: \"manual\" },\n    { source: \"manual\" }\n  ]\n});\n```\n\n### Batch Adding (Large Datasets)\n\n```typescript\nconst batchSize = 5000;\nfor (let i = 0; i < totalDocuments.length; i += batchSize) {\n  const batch = totalDocuments.slice(i, i + batchSize);\n  await collection.add({\n    ids: batch.map((_, idx) => `id${i + idx}`),\n    documents: batch\n  });\n}\n```\n\nChromaDB supports adding up to 100k+ documents at once.\n\n---\n\n## Querying Data\n\n### Query with Text (Auto-Embedding)\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\"What fruits are tropical?\"],\n  nResults: 2\n});\n\nconsole.log(results);\n```\n\n**Response Structure:**\n\n```typescript\n{\n  ids: [[\"id1\", \"id2\"]],\n  distances: [[0.1234, 0.5678]],\n  documents: [[\"This is a document about pineapples\", \"This is a document...\"]],\n  metadatas: [[{ category: \"tropical\", color: \"yellow\" }, { ... }]]\n}\n```\n\n### Query with Multiple Texts\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\n    \"What fruits are tropical?\",\n    \"What fruits are citrus?\"\n  ],\n  nResults: 2\n});\n```\n\nReturns `nResults` for each query text.\n\n### Query with Custom Embeddings\n\n```typescript\nconst results = await collection.query({\n  queryEmbeddings: [[1.5, 2.9, 3.4, 1.2, 0.8]],\n  nResults: 3\n});\n```\n\n### Query with Metadata Filters\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\"What fruits are available?\"],\n  nResults: 5,\n  where: {\n    category: \"tropical\"\n  }\n});\n```\n\n### Complex Metadata Filtering\n\n```typescript\n// Using $or operator\nconst results = await collection.query({\n  queryTexts: [\"Find fruits\"],\n  nResults: 5,\n  where: {\n    $or: [\n      { category: \"tropical\" },\n      { category: \"citrus\" }\n    ]\n  }\n});\n\n// Using $and operator\nconst results = await collection.query({\n  queryTexts: [\"Find fruits\"],\n  nResults: 5,\n  where: {\n    $and: [\n      { category: \"tropical\" },\n      { color: \"yellow\" }\n    ]\n  }\n});\n\n// Using comparison operators\nconst results = await collection.query({\n  queryTexts: [\"Find items\"],\n  nResults: 5,\n  where: {\n    price: { $gt: 10 }  // $gt, $gte, $lt, $lte, $ne, $eq\n  }\n});\n```\n\n### Query with Document Content Filters\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\"Find documents\"],\n  nResults: 5,\n  whereDocument: {\n    $contains: \"pineapple\"\n  }\n});\n\n// Using $not_contains\nconst results = await collection.query({\n  queryTexts: [\"Find documents\"],\n  nResults: 5,\n  whereDocument: {\n    $not_contains: \"apple\"\n  }\n});\n```\n\n### Query with Include Options\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\"What fruits are tropical?\"],\n  nResults: 2,\n  include: [\"documents\", \"metadatas\", \"distances\", \"embeddings\"]\n});\n```\n\n**Include Options:**\n- `documents`: The document text (included by default)\n- `metadatas`: Metadata for each document (included by default)\n- `distances`: Distance/similarity scores (included by default)\n- `embeddings`: Vector embeddings (not included by default for performance)\n\n---\n\n## Getting Data\n\n### Get Documents by IDs\n\n```typescript\nconst results = await collection.get({\n  ids: [\"id1\", \"id2\"]\n});\n\nconsole.log(results);\n```\n\n### Get All Documents\n\n```typescript\nconst results = await collection.get();\n```\n\nReturns all documents in the collection.\n\n### Get with Metadata Filter\n\n```typescript\nconst results = await collection.get({\n  where: {\n    category: \"tropical\"\n  }\n});\n```\n\n### Get with Document Filter\n\n```typescript\nconst results = await collection.get({\n  whereDocument: {\n    $contains: \"pineapple\"\n  }\n});\n```\n\n### Get with Limit and Offset\n\n```typescript\nconst results = await collection.get({\n  limit: 10,\n  offset: 20\n});\n```\n\n### Get with Include Options\n\n```typescript\nconst results = await collection.get({\n  ids: [\"id1\", \"id2\"],\n  include: [\"documents\", \"metadatas\", \"embeddings\"]\n});\n```\n\n---\n\n## Updating Data\n\n### Update Documents\n\n```typescript\nawait collection.update({\n  ids: [\"id1\", \"id2\"],\n  documents: [\n    \"Updated document about pineapples\",\n    \"Updated document about oranges\"\n  ],\n  metadatas: [\n    { category: \"tropical\", color: \"yellow\", updated: true },\n    { category: \"citrus\", color: \"orange\", updated: true }\n  ]\n});\n```\n\n### Update with Custom Embeddings\n\n```typescript\nawait collection.update({\n  ids: [\"id1\"],\n  embeddings: [[1.1, 2.2, 3.3, 4.4, 5.5]],\n  documents: [\"Updated document\"],\n  metadatas: [{ source: \"updated\" }]\n});\n```\n\n---\n\n## Upsert (Add or Update)\n\n### Upsert Documents\n\n```typescript\nawait collection.upsert({\n  ids: [\"id1\", \"id2\", \"id3\"],\n  documents: [\n    \"Document one - may be new or updated\",\n    \"Document two - may be new or updated\",\n    \"Document three - may be new or updated\"\n  ],\n  metadatas: [\n    { version: 2 },\n    { version: 2 },\n    { version: 1 }\n  ]\n});\n```\n\nIf the ID exists, it updates the document. If not, it adds it as new.\n\n---\n\n## Deleting Data\n\n### Delete by IDs\n\n```typescript\nawait collection.delete({\n  ids: [\"id1\", \"id2\"]\n});\n```\n\n### Delete with Metadata Filter\n\n```typescript\nawait collection.delete({\n  where: {\n    category: \"tropical\"\n  }\n});\n```\n\n### Delete with Document Filter\n\n```typescript\nawait collection.delete({\n  whereDocument: {\n    $contains: \"deprecated\"\n  }\n});\n```\n\n### Delete All Documents (Keep Collection)\n\n```typescript\nawait collection.delete();\n```\n\n---\n\n## Collection Utilities\n\n### Count Documents\n\n```typescript\nconst count = await collection.count();\nconsole.log(`Total documents: ${count}`);\n```\n\n### Peek at First Documents\n\n```typescript\nconst firstDocs = await collection.peek({\n  limit: 5\n});\n\nconsole.log(firstDocs);\n```\n\nReturns the first 5 documents in the collection.\n\n### Modify Collection Metadata\n\n```typescript\nawait collection.modify({\n  metadata: {\n    description: \"Collection of fruit documents\",\n    version: \"1.0\"\n  }\n});\n```\n\n---\n\n## Embedding Functions\n\n### Using Default Embedding Function\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient();\nconst collection = await client.createCollection({\n  name: \"my_collection\"\n});\n```\n\nBy default, ChromaDB uses the Sentence Transformers `all-MiniLM-L6-v2` model.\n\n### Using OpenAI Embeddings\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\nimport { OpenAIEmbeddingFunction } from \"chromadb\";\n\nconst embedder = new OpenAIEmbeddingFunction({\n  openai_api_key: \"your-openai-api-key\",\n  model_name: \"text-embedding-3-small\"\n});\n\nconst collection = await client.createCollection({\n  name: \"openai_collection\",\n  embeddingFunction: embedder\n});\n```\n\n**Available OpenAI Models:**\n- `text-embedding-3-small`\n- `text-embedding-3-large`\n- `text-embedding-ada-002`\n\n### Using Cohere Embeddings\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\nimport { CohereEmbeddingFunction } from \"chromadb\";\n\nconst embedder = new CohereEmbeddingFunction({\n  cohere_api_key: \"your-cohere-api-key\",\n  model_name: \"embed-english-v3.0\"\n});\n\nconst collection = await client.createCollection({\n  name: \"cohere_collection\",\n  embeddingFunction: embedder\n});\n```\n\n### Using Hugging Face Embeddings\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\nimport { HuggingFaceEmbeddingFunction } from \"chromadb\";\n\nconst embedder = new HuggingFaceEmbeddingFunction({\n  api_key: \"your-hf-api-key\",\n  model_name: \"sentence-transformers/all-MiniLM-L6-v2\"\n});\n\nconst collection = await client.createCollection({\n  name: \"hf_collection\",\n  embeddingFunction: embedder\n});\n```\n\n### Custom Embedding Function\n\n```typescript\nimport { IEmbeddingFunction } from \"chromadb\";\n\nclass CustomEmbeddingFunction implements IEmbeddingFunction {\n  async generate(texts: string[]): Promise<number[][]> {\n    // Your custom embedding logic here\n    const embeddings = texts.map(text => {\n      // Example: simple character code embedding (replace with real model)\n      return Array.from(text).slice(0, 384).map(c => c.charCodeAt(0) / 255);\n    });\n    return embeddings;\n  }\n}\n\nconst embedder = new CustomEmbeddingFunction();\nconst collection = await client.createCollection({\n  name: \"custom_collection\",\n  embeddingFunction: embedder\n});\n```\n\n---\n\n## Advanced Client Configuration\n\n### HttpClient with Full Options\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient({\n  path: \"https://my-chroma-server.com:8000\",\n  auth: {\n    provider: \"token\",\n    credentials: \"my-auth-token\"\n  },\n  tenant: \"my-tenant\",\n  database: \"my-database\"\n});\n```\n\n### Multi-Tenancy Setup\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nconst client = new ChromaClient({\n  path: \"http://localhost:8000\"\n});\n\n// Create a new tenant and database\nawait client.createTenant({ name: \"acme-corp\" });\nawait client.createDatabase({ name: \"production\", tenant: \"acme-corp\" });\n\n// Connect to specific tenant/database\nconst tenantClient = new ChromaClient({\n  path: \"http://localhost:8000\",\n  tenant: \"acme-corp\",\n  database: \"production\"\n});\n```\n\n---\n\n## Complete Example: Document Search System\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\n\nasync function main() {\n  // Initialize client\n  const client = new ChromaClient({\n    path: \"http://localhost:8000\"\n  });\n\n  // Create or get collection\n  const collection = await client.getOrCreateCollection({\n    name: \"knowledge_base\",\n    metadata: {\n      \"hnsw:space\": \"cosine\"\n    }\n  });\n\n  // Add documents\n  await collection.add({\n    ids: [\"doc1\", \"doc2\", \"doc3\", \"doc4\"],\n    documents: [\n      \"The quick brown fox jumps over the lazy dog\",\n      \"Machine learning is a subset of artificial intelligence\",\n      \"Python is a popular programming language\",\n      \"ChromaDB is a vector database for AI applications\"\n    ],\n    metadatas: [\n      { category: \"phrases\", language: \"english\" },\n      { category: \"ai\", language: \"english\" },\n      { category: \"programming\", language: \"english\" },\n      { category: \"database\", language: \"english\" }\n    ]\n  });\n\n  // Query the collection\n  const results = await collection.query({\n    queryTexts: [\"What is AI?\"],\n    nResults: 2,\n    where: {\n      category: \"ai\"\n    }\n  });\n\n  console.log(\"Search Results:\");\n  console.log(results.documents[0]);\n  console.log(results.metadatas[0]);\n  console.log(results.distances[0]);\n\n  // Get document count\n  const count = await collection.count();\n  console.log(`Total documents: ${count}`);\n\n  // Update a document\n  await collection.update({\n    ids: [\"doc2\"],\n    documents: [\"Machine learning is a powerful subset of artificial intelligence\"],\n    metadatas: [{ category: \"ai\", language: \"english\", updated: true }]\n  });\n\n  // Delete documents\n  await collection.delete({\n    ids: [\"doc4\"]\n  });\n}\n\nmain();\n```\n\n---\n\n## Complete Example: Semantic Search with OpenAI\n\n```typescript\nimport { ChromaClient, OpenAIEmbeddingFunction } from \"chromadb\";\nimport * as dotenv from \"dotenv\";\n\ndotenv.config();\n\nasync function semanticSearch() {\n  const client = new ChromaClient();\n\n  const embedder = new OpenAIEmbeddingFunction({\n    openai_api_key: process.env.OPENAI_API_KEY!,\n    model_name: \"text-embedding-3-small\"\n  });\n\n  const collection = await client.getOrCreateCollection({\n    name: \"articles\",\n    embeddingFunction: embedder,\n    metadata: {\n      \"hnsw:space\": \"cosine\"\n    }\n  });\n\n  // Add articles\n  await collection.add({\n    ids: [\"art1\", \"art2\", \"art3\"],\n    documents: [\n      \"Climate change is affecting global weather patterns\",\n      \"New breakthrough in quantum computing announced\",\n      \"The future of renewable energy looks promising\"\n    ],\n    metadatas: [\n      { topic: \"environment\", date: \"2024-01-15\" },\n      { topic: \"technology\", date: \"2024-01-16\" },\n      { topic: \"energy\", date: \"2024-01-17\" }\n    ]\n  });\n\n  // Search for relevant articles\n  const results = await collection.query({\n    queryTexts: [\"Tell me about environmental issues\"],\n    nResults: 3\n  });\n\n  results.documents[0].forEach((doc, idx) => {\n    console.log(`Result ${idx + 1}:`);\n    console.log(`Document: ${doc}`);\n    console.log(`Metadata: ${JSON.stringify(results.metadatas[0][idx])}`);\n    console.log(`Distance: ${results.distances![0][idx]}`);\n    console.log(\"---\");\n  });\n}\n\nsemanticSearch();\n```\n\n---\n\n## Complete Example: RAG (Retrieval-Augmented Generation)\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\nimport OpenAI from \"openai\";\n\nasync function ragExample() {\n  // Initialize ChromaDB\n  const chroma = new ChromaClient();\n  const collection = await chroma.getOrCreateCollection({\n    name: \"company_docs\",\n    metadata: { \"hnsw:space\": \"cosine\" }\n  });\n\n  // Add company knowledge base\n  await collection.add({\n    ids: [\"policy1\", \"policy2\", \"policy3\"],\n    documents: [\n      \"Our company offers 20 days of paid vacation per year\",\n      \"Remote work is available 3 days per week\",\n      \"Health insurance includes dental and vision coverage\"\n    ],\n    metadatas: [\n      { type: \"policy\", category: \"time-off\" },\n      { type: \"policy\", category: \"work-arrangement\" },\n      { type: \"policy\", category: \"benefits\" }\n    ]\n  });\n\n  // User question\n  const question = \"How many vacation days do I get?\";\n\n  // Retrieve relevant context\n  const searchResults = await collection.query({\n    queryTexts: [question],\n    nResults: 2\n  });\n\n  const context = searchResults.documents[0].join(\"\\n\");\n\n  // Generate answer with OpenAI\n  const openai = new OpenAI({\n    apiKey: process.env.OPENAI_API_KEY\n  });\n\n  const completion = await openai.chat.completions.create({\n    model: \"gpt-4\",\n    messages: [\n      {\n        role: \"system\",\n        content: \"Answer the question based on the context provided.\"\n      },\n      {\n        role: \"user\",\n        content: `Context:\\n${context}\\n\\nQuestion: ${question}`\n      }\n    ]\n  });\n\n  console.log(\"Answer:\", completion.choices[0].message.content);\n}\n\nragExample();\n```\n\n---\n\n## Environment Variables\n\n### .env File Setup\n\n```bash\n# ChromaDB Server\nCHROMA_HOST=http://localhost:8000\n\n# Authentication (if required)\nCHROMA_AUTH_TOKEN=your-auth-token\n\n# Embedding API Keys\nOPENAI_API_KEY=sk-...\nCOHERE_API_KEY=...\nHF_API_KEY=...\n```\n\n### Using Environment Variables\n\n```typescript\nimport { ChromaClient } from \"chromadb\";\nimport * as dotenv from \"dotenv\";\n\ndotenv.config();\n\nconst client = new ChromaClient({\n  path: process.env.CHROMA_HOST || \"http://localhost:8000\",\n  auth: process.env.CHROMA_AUTH_TOKEN ? {\n    provider: \"token\",\n    credentials: process.env.CHROMA_AUTH_TOKEN\n  } : undefined\n});\n```\n\n---\n\n## TypeScript Types\n\n### Query Results Type\n\n```typescript\ninterface QueryResults {\n  ids: string[][];\n  embeddings?: number[][][];\n  documents: (string | null)[][];\n  metadatas: (Record<string, any> | null)[][];\n  distances?: number[][];\n}\n```\n\n### Get Results Type\n\n```typescript\ninterface GetResults {\n  ids: string[];\n  embeddings?: number[][];\n  documents: (string | null)[];\n  metadatas: (Record<string, any> | null)[];\n}\n```\n\n### Collection Metadata\n\n```typescript\ninterface CollectionMetadata {\n  [key: string]: string | number | boolean;\n  \"hnsw:space\"?: \"cosine\" | \"l2\" | \"ip\";\n}\n```\n\n---\n\n## Error Handling\n\n### Handle Collection Not Found\n\n```typescript\ntry {\n  const collection = await client.getCollection({\n    name: \"nonexistent_collection\"\n  });\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"does not exist\")) {\n    console.error(\"Collection not found\");\n    // Create the collection\n    const collection = await client.createCollection({\n      name: \"nonexistent_collection\"\n    });\n  }\n}\n```\n\n### Handle Duplicate IDs\n\n```typescript\ntry {\n  await collection.add({\n    ids: [\"id1\"],\n    documents: [\"Document\"]\n  });\n\n  // This will fail - ID already exists\n  await collection.add({\n    ids: [\"id1\"],\n    documents: [\"Another document\"]\n  });\n} catch (error) {\n  console.error(\"ID already exists. Use update() or upsert() instead.\");\n\n  // Use upsert to add or update\n  await collection.upsert({\n    ids: [\"id1\"],\n    documents: [\"Another document\"]\n  });\n}\n```\n\n### Handle Connection Errors\n\n```typescript\ntry {\n  const client = new ChromaClient({\n    path: \"http://localhost:8000\"\n  });\n\n  const collections = await client.listCollections();\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"ECONNREFUSED\")) {\n    console.error(\"Cannot connect to ChromaDB server. Make sure it's running.\");\n    console.error(\"Start server with: chroma run --path ./data\");\n  } else {\n    console.error(\"Error:\", error);\n  }\n}\n```\n\n---\n\n## Performance Optimization\n\n### Batch Operations\n\n```typescript\n// Batch add for large datasets\nconst chunkSize = 5000;\nfor (let i = 0; i < documents.length; i += chunkSize) {\n  await collection.add({\n    ids: ids.slice(i, i + chunkSize),\n    documents: documents.slice(i, i + chunkSize),\n    metadatas: metadatas.slice(i, i + chunkSize)\n  });\n}\n```\n\n### Parallel Queries\n\n```typescript\n// Run multiple queries in parallel\nconst queries = [\n  \"Query about topic A\",\n  \"Query about topic B\",\n  \"Query about topic C\"\n];\n\nconst results = await Promise.all(\n  queries.map(query =>\n    collection.query({\n      queryTexts: [query],\n      nResults: 5\n    })\n  )\n);\n```\n\n### Limit Included Fields\n\n```typescript\n// Exclude embeddings for better performance\nconst results = await collection.query({\n  queryTexts: [\"Search query\"],\n  nResults: 10,\n  include: [\"documents\", \"metadatas\", \"distances\"]\n  // Don't include embeddings unless needed\n});\n```\n\n---\n\n## Common Patterns\n\n### Incremental Updates\n\n```typescript\n// Add new documents daily\nasync function addDailyDocuments(newDocs: string[]) {\n  const count = await collection.count();\n  const newIds = newDocs.map((_, idx) => `doc${count + idx}`);\n\n  await collection.add({\n    ids: newIds,\n    documents: newDocs,\n    metadatas: newDocs.map(() => ({\n      added_date: new Date().toISOString()\n    }))\n  });\n}\n```\n\n### Search with Fallback\n\n```typescript\nasync function searchWithFallback(query: string) {\n  // Try specific category first\n  let results = await collection.query({\n    queryTexts: [query],\n    nResults: 5,\n    where: { category: \"premium\" }\n  });\n\n  // If no results, search all documents\n  if (results.ids[0].length === 0) {\n    results = await collection.query({\n      queryTexts: [query],\n      nResults: 5\n    });\n  }\n\n  return results;\n}\n```\n\n### Deduplicate Documents\n\n```typescript\nasync function addUnique(id: string, document: string, metadata: Record<string, any>) {\n  try {\n    const existing = await collection.get({ ids: [id] });\n    if (existing.ids.length > 0) {\n      console.log(\"Document already exists, updating...\");\n      await collection.update({ ids: [id], documents: [document], metadatas: [metadata] });\n    } else {\n      await collection.add({ ids: [id], documents: [document], metadatas: [metadata] });\n    }\n  } catch (error) {\n    await collection.add({ ids: [id], documents: [document], metadatas: [metadata] });\n  }\n}\n```\n\n---\n\n## Metadata Filter Operators\n\n### Comparison Operators\n\n```typescript\n// Equal\nwhere: { category: \"tech\" }\nwhere: { category: { $eq: \"tech\" } }\n\n// Not equal\nwhere: { category: { $ne: \"tech\" } }\n\n// Greater than\nwhere: { price: { $gt: 100 } }\n\n// Greater than or equal\nwhere: { price: { $gte: 100 } }\n\n// Less than\nwhere: { price: { $lt: 100 } }\n\n// Less than or equal\nwhere: { price: { $lte: 100 } }\n```\n\n### Logical Operators\n\n```typescript\n// AND\nwhere: {\n  $and: [\n    { category: \"tech\" },\n    { price: { $lt: 1000 } }\n  ]\n}\n\n// OR\nwhere: {\n  $or: [\n    { category: \"tech\" },\n    { category: \"science\" }\n  ]\n}\n\n// NOT\nwhere: {\n  $not: { category: \"archived\" }\n}\n```\n\n### Set Operators\n\n```typescript\n// In array\nwhere: {\n  category: { $in: [\"tech\", \"science\", \"health\"] }\n}\n\n// Not in array\nwhere: {\n  category: { $nin: [\"archived\", \"deleted\"] }\n}\n```\n\n---\n\n## Document Filter Operators\n\n### Contains\n\n```typescript\nwhereDocument: {\n  $contains: \"machine learning\"\n}\n```\n\n### Not Contains\n\n```typescript\nwhereDocument: {\n  $not_contains: \"deprecated\"\n}\n```\n\n### Combined with Metadata\n\n```typescript\nconst results = await collection.query({\n  queryTexts: [\"AI research\"],\n  where: { category: \"research\" },\n  whereDocument: { $contains: \"neural network\" },\n  nResults: 10\n});\n```\n"
  },
  {
    "path": "content/chromadb/docs/embeddings-db/python/DOC.md",
    "content": "---\nname: embeddings-db\ndescription: \"ChromaDB Python SDK for vector embeddings and AI-powered search\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"chromadb,embeddings,vector-db,ai,search\"\n---\n\n# ChromaDB Python SDK - v1.2.1\n\n## Golden Rule\n\n**ALWAYS use the official `chromadb` package (v1.2.1 or later) for Python projects.**\n\n```bash\npip install chromadb\n```\n\n**DO NOT use:**\n- Deprecated packages like `chromadb-client`\n- Old versions below 1.0\n- Community wrappers that may be outdated\n\nChromaDB is the official AI-native open-source vector database. It handles embeddings, indexing, and vector similarity search automatically.\n\n**Requires Python >= 3.9**\n\n---\n\n## Installation\n\n### Using pip\n\n```bash\npip install chromadb\n```\n\n### Using Poetry\n\n```bash\npoetry add chromadb\n```\n\n### Using uv\n\n```bash\nuv pip install chromadb\n```\n\n### Install with Specific Version\n\n```bash\npip install chromadb==1.2.1\n```\n\n---\n\n## Initialization\n\n### Ephemeral Client (In-Memory)\n\n```python\nimport chromadb\n\nclient = chromadb.EphemeralClient()\n```\n\nUse for experimentation, testing, and prototyping. Data is lost when the process ends.\n\n### Persistent Client (Local Storage)\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient(path=\"./chroma_data\")\n```\n\nStores data locally at the specified path. Creates the directory if it doesn't exist.\n\n### Persistent Client with Default Path\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient()\n```\n\nDefaults to `./chroma` in the current working directory.\n\n### HTTP Client (Remote Server)\n\n```python\nimport chromadb\n\nclient = chromadb.HttpClient(host=\"localhost\", port=8000)\n```\n\nConnects to a remote ChromaDB server.\n\n### HTTP Client with Custom Configuration\n\n```python\nimport chromadb\nfrom chromadb.config import Settings\n\nclient = chromadb.HttpClient(\n    host=\"localhost\",\n    port=8000,\n    ssl=False,\n    headers={\"Authorization\": \"Bearer token\"},\n    settings=Settings(),\n    tenant=\"default_tenant\",\n    database=\"default_database\"\n)\n```\n\n---\n\n## Running ChromaDB Server\n\n### Local Server\n\n```bash\nchroma run --path ./chroma_data\n```\n\nStarts server on `http://localhost:8000`\n\n### Docker\n\n```bash\ndocker pull chromadb/chroma\ndocker run -p 8000:8000 chromadb/chroma\n```\n\n---\n\n## Collections\n\n### Create a Collection\n\n```python\ncollection = client.create_collection(name=\"my_collection\")\n```\n\n### Create Collection with Distance Metric\n\n```python\ncollection = client.create_collection(\n    name=\"my_collection\",\n    metadata={\"hnsw:space\": \"cosine\"}\n)\n```\n\n**Distance Metrics:**\n- `cosine`: Cosine similarity (best for text, normalized vectors)\n- `l2`: Euclidean/L2 distance (default, sensitive to magnitude)\n- `ip`: Inner product (for recommendation systems)\n\n### Get an Existing Collection\n\n```python\ncollection = client.get_collection(name=\"my_collection\")\n```\n\n### Get or Create Collection\n\n```python\ncollection = client.get_or_create_collection(name=\"my_collection\")\n```\n\n### List All Collections\n\n```python\ncollections = client.list_collections()\nfor col in collections:\n    print(col.name)\n```\n\n### Delete a Collection\n\n```python\nclient.delete_collection(name=\"my_collection\")\n```\n\n---\n\n## Adding Data\n\n### Add Documents (Auto-Embedding)\n\n```python\ncollection.add(\n    ids=[\"id1\", \"id2\", \"id3\"],\n    documents=[\n        \"This is a document about pineapples\",\n        \"This is a document about oranges\",\n        \"This is a document about apples\"\n    ]\n)\n```\n\nChromaDB automatically embeds the documents using the default embedding function.\n\n### Add with Metadata\n\n```python\ncollection.add(\n    ids=[\"id1\", \"id2\", \"id3\"],\n    documents=[\n        \"This is a document about pineapples\",\n        \"This is a document about oranges\",\n        \"This is a document about apples\"\n    ],\n    metadatas=[\n        {\"category\": \"tropical\", \"color\": \"yellow\"},\n        {\"category\": \"citrus\", \"color\": \"orange\"},\n        {\"category\": \"temperate\", \"color\": \"red\"}\n    ]\n)\n```\n\n### Add with Custom Embeddings\n\n```python\ncollection.add(\n    ids=[\"id1\", \"id2\"],\n    embeddings=[\n        [1.5, 2.9, 3.4, 1.2, 0.8],\n        [9.8, 2.3, 2.9, 4.1, 3.3]\n    ],\n    documents=[\"Document one\", \"Document two\"],\n    metadatas=[\n        {\"source\": \"manual\"},\n        {\"source\": \"manual\"}\n    ]\n)\n```\n\n### Batch Adding (Large Datasets)\n\n```python\nbatch_size = 5000\nfor i in range(0, len(documents), batch_size):\n    batch_docs = documents[i:i + batch_size]\n    batch_ids = [f\"id{j}\" for j in range(i, i + len(batch_docs))]\n\n    collection.add(\n        ids=batch_ids,\n        documents=batch_docs\n    )\n```\n\nChromaDB supports adding up to 100k+ documents at once.\n\n---\n\n## Querying Data\n\n### Query with Text (Auto-Embedding)\n\n```python\nresults = collection.query(\n    query_texts=[\"What fruits are tropical?\"],\n    n_results=2\n)\n\nprint(results)\n```\n\n**Response Structure:**\n\n```python\n{\n    'ids': [['id1', 'id2']],\n    'distances': [[0.1234, 0.5678]],\n    'documents': [['This is a document about pineapples', 'This is...']],\n    'metadatas': [[{'category': 'tropical', 'color': 'yellow'}, {...}]],\n    'embeddings': None  # Not included by default\n}\n```\n\n### Query with Multiple Texts\n\n```python\nresults = collection.query(\n    query_texts=[\n        \"What fruits are tropical?\",\n        \"What fruits are citrus?\"\n    ],\n    n_results=2\n)\n```\n\nReturns `n_results` for each query text.\n\n### Query with Custom Embeddings\n\n```python\nresults = collection.query(\n    query_embeddings=[[1.5, 2.9, 3.4, 1.2, 0.8]],\n    n_results=3\n)\n```\n\n### Query with Metadata Filters\n\n```python\nresults = collection.query(\n    query_texts=[\"What fruits are available?\"],\n    n_results=5,\n    where={\"category\": \"tropical\"}\n)\n```\n\n### Complex Metadata Filtering\n\n```python\n# Using $or operator\nresults = collection.query(\n    query_texts=[\"Find fruits\"],\n    n_results=5,\n    where={\n        \"$or\": [\n            {\"category\": \"tropical\"},\n            {\"category\": \"citrus\"}\n        ]\n    }\n)\n\n# Using $and operator\nresults = collection.query(\n    query_texts=[\"Find fruits\"],\n    n_results=5,\n    where={\n        \"$and\": [\n            {\"category\": \"tropical\"},\n            {\"color\": \"yellow\"}\n        ]\n    }\n)\n\n# Using comparison operators\nresults = collection.query(\n    query_texts=[\"Find items\"],\n    n_results=5,\n    where={\n        \"price\": {\"$gt\": 10}  # $gt, $gte, $lt, $lte, $ne, $eq\n    }\n)\n```\n\n### Query with Document Content Filters\n\n```python\nresults = collection.query(\n    query_texts=[\"Find documents\"],\n    n_results=5,\n    where_document={\"$contains\": \"pineapple\"}\n)\n\n# Using $not_contains\nresults = collection.query(\n    query_texts=[\"Find documents\"],\n    n_results=5,\n    where_document={\"$not_contains\": \"apple\"}\n)\n```\n\n### Query with Include Options\n\n```python\nresults = collection.query(\n    query_texts=[\"What fruits are tropical?\"],\n    n_results=2,\n    include=[\"documents\", \"metadatas\", \"distances\", \"embeddings\"]\n)\n```\n\n**Include Options:**\n- `documents`: The document text (included by default)\n- `metadatas`: Metadata for each document (included by default)\n- `distances`: Distance/similarity scores (included by default)\n- `embeddings`: Vector embeddings (not included by default for performance)\n\n---\n\n## Getting Data\n\n### Get Documents by IDs\n\n```python\nresults = collection.get(\n    ids=[\"id1\", \"id2\"]\n)\n\nprint(results)\n```\n\n### Get All Documents\n\n```python\nresults = collection.get()\n```\n\nReturns all documents in the collection.\n\n### Get with Metadata Filter\n\n```python\nresults = collection.get(\n    where={\"category\": \"tropical\"}\n)\n```\n\n### Get with Document Filter\n\n```python\nresults = collection.get(\n    where_document={\"$contains\": \"pineapple\"}\n)\n```\n\n### Get with Limit and Offset\n\n```python\nresults = collection.get(\n    limit=10,\n    offset=20\n)\n```\n\n### Get with Include Options\n\n```python\nresults = collection.get(\n    ids=[\"id1\", \"id2\"],\n    include=[\"documents\", \"metadatas\", \"embeddings\"]\n)\n```\n\n---\n\n## Updating Data\n\n### Update Documents\n\n```python\ncollection.update(\n    ids=[\"id1\", \"id2\"],\n    documents=[\n        \"Updated document about pineapples\",\n        \"Updated document about oranges\"\n    ],\n    metadatas=[\n        {\"category\": \"tropical\", \"color\": \"yellow\", \"updated\": True},\n        {\"category\": \"citrus\", \"color\": \"orange\", \"updated\": True}\n    ]\n)\n```\n\n### Update with Custom Embeddings\n\n```python\ncollection.update(\n    ids=[\"id1\"],\n    embeddings=[[1.1, 2.2, 3.3, 4.4, 5.5]],\n    documents=[\"Updated document\"],\n    metadatas=[{\"source\": \"updated\"}]\n)\n```\n\n---\n\n## Upsert (Add or Update)\n\n### Upsert Documents\n\n```python\ncollection.upsert(\n    ids=[\"id1\", \"id2\", \"id3\"],\n    documents=[\n        \"Document one - may be new or updated\",\n        \"Document two - may be new or updated\",\n        \"Document three - may be new or updated\"\n    ],\n    metadatas=[\n        {\"version\": 2},\n        {\"version\": 2},\n        {\"version\": 1}\n    ]\n)\n```\n\nIf the ID exists, it updates the document. If not, it adds it as new.\n\n---\n\n## Deleting Data\n\n### Delete by IDs\n\n```python\ncollection.delete(\n    ids=[\"id1\", \"id2\"]\n)\n```\n\n### Delete with Metadata Filter\n\n```python\ncollection.delete(\n    where={\"category\": \"tropical\"}\n)\n```\n\n### Delete with Document Filter\n\n```python\ncollection.delete(\n    where_document={\"$contains\": \"deprecated\"}\n)\n```\n\n### Delete All Documents (Keep Collection)\n\n```python\ncollection.delete()\n```\n\n---\n\n## Collection Utilities\n\n### Count Documents\n\n```python\ncount = collection.count()\nprint(f\"Total documents: {count}\")\n```\n\n### Peek at First Documents\n\n```python\nfirst_docs = collection.peek(limit=5)\nprint(first_docs)\n```\n\nReturns the first 5 documents in the collection.\n\n### Modify Collection Metadata\n\n```python\ncollection.modify(\n    metadata={\n        \"description\": \"Collection of fruit documents\",\n        \"version\": \"1.0\"\n    }\n)\n```\n\n---\n\n## Embedding Functions\n\n### Using Default Embedding Function\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient()\ncollection = client.create_collection(name=\"my_collection\")\n```\n\nBy default, ChromaDB uses the Sentence Transformers `all-MiniLM-L6-v2` model.\n\n### Using OpenAI Embeddings\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\n\nopenai_ef = embedding_functions.OpenAIEmbeddingFunction(\n    api_key=\"your-openai-api-key\",\n    model_name=\"text-embedding-3-small\"\n)\n\ncollection = client.create_collection(\n    name=\"openai_collection\",\n    embedding_function=openai_ef\n)\n```\n\n**Available OpenAI Models:**\n- `text-embedding-3-small`\n- `text-embedding-3-large`\n- `text-embedding-ada-002`\n\n### Using Cohere Embeddings\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\n\ncohere_ef = embedding_functions.CohereEmbeddingFunction(\n    api_key=\"your-cohere-api-key\",\n    model_name=\"embed-english-v3.0\"\n)\n\ncollection = client.create_collection(\n    name=\"cohere_collection\",\n    embedding_function=cohere_ef\n)\n```\n\n**Available Cohere Models:**\n- `embed-english-v3.0`\n- `embed-multilingual-v3.0`\n- `embed-english-light-v3.0`\n\n### Using Hugging Face Embeddings\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\n\nhuggingface_ef = embedding_functions.HuggingFaceEmbeddingFunction(\n    api_key=\"your-hf-api-key\",\n    model_name=\"sentence-transformers/all-MiniLM-L6-v2\"\n)\n\ncollection = client.create_collection(\n    name=\"hf_collection\",\n    embedding_function=huggingface_ef\n)\n```\n\n### Using Sentence Transformers (Local)\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\n\nsentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(\n    model_name=\"all-MiniLM-L6-v2\"\n)\n\ncollection = client.create_collection(\n    name=\"local_collection\",\n    embedding_function=sentence_transformer_ef\n)\n```\n\n### Using Ollama Embeddings (Local)\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\n\nollama_ef = embedding_functions.OllamaEmbeddingFunction(\n    url=\"http://localhost:11434/api/embeddings\",\n    model_name=\"llama2\"\n)\n\ncollection = client.create_collection(\n    name=\"ollama_collection\",\n    embedding_function=ollama_ef\n)\n```\n\n### Custom Embedding Function\n\n```python\nimport chromadb\nfrom chromadb import Documents, EmbeddingFunction, Embeddings\n\nclass CustomEmbeddingFunction(EmbeddingFunction):\n    def __call__(self, input: Documents) -> Embeddings:\n        # Your custom embedding logic here\n        embeddings = []\n        for doc in input:\n            # Example: simple character code embedding (replace with real model)\n            embedding = [ord(c) / 255.0 for c in doc[:384]]\n            # Pad to fixed length\n            embedding.extend([0.0] * (384 - len(embedding)))\n            embeddings.append(embedding)\n        return embeddings\n\ncustom_ef = CustomEmbeddingFunction()\ncollection = client.create_collection(\n    name=\"custom_collection\",\n    embedding_function=custom_ef\n)\n```\n\n---\n\n## Advanced Client Configuration\n\n### PersistentClient with Full Options\n\n```python\nimport chromadb\nfrom chromadb.config import Settings\n\nclient = chromadb.PersistentClient(\n    path=\"./my_chroma_data\",\n    settings=Settings(\n        anonymized_telemetry=False,\n        allow_reset=True\n    ),\n    tenant=\"default_tenant\",\n    database=\"default_database\"\n)\n```\n\n### HttpClient with Authentication\n\n```python\nimport chromadb\nfrom chromadb.config import Settings\n\nclient = chromadb.HttpClient(\n    host=\"my-chroma-server.com\",\n    port=8000,\n    ssl=True,\n    headers={\"Authorization\": \"Bearer my-token\"},\n    settings=Settings(\n        chroma_client_auth_provider=\"chromadb.auth.token_authn.TokenAuthClientProvider\",\n        chroma_client_auth_credentials=\"my-token\"\n    )\n)\n```\n\n### Multi-Tenancy Setup\n\n```python\nimport chromadb\n\nclient = chromadb.HttpClient(host=\"localhost\", port=8000)\n\n# Create a new tenant and database\nclient.create_tenant(name=\"acme_corp\")\nclient.create_database(name=\"production\", tenant=\"acme_corp\")\n\n# Connect to specific tenant/database\ntenant_client = chromadb.HttpClient(\n    host=\"localhost\",\n    port=8000,\n    tenant=\"acme_corp\",\n    database=\"production\"\n)\n```\n\n---\n\n## Complete Example: Document Search System\n\n```python\nimport chromadb\n\ndef main():\n    # Initialize client\n    client = chromadb.PersistentClient(path=\"./search_db\")\n\n    # Create or get collection\n    collection = client.get_or_create_collection(\n        name=\"knowledge_base\",\n        metadata={\"hnsw:space\": \"cosine\"}\n    )\n\n    # Add documents\n    collection.add(\n        ids=[\"doc1\", \"doc2\", \"doc3\", \"doc4\"],\n        documents=[\n            \"The quick brown fox jumps over the lazy dog\",\n            \"Machine learning is a subset of artificial intelligence\",\n            \"Python is a popular programming language\",\n            \"ChromaDB is a vector database for AI applications\"\n        ],\n        metadatas=[\n            {\"category\": \"phrases\", \"language\": \"english\"},\n            {\"category\": \"ai\", \"language\": \"english\"},\n            {\"category\": \"programming\", \"language\": \"english\"},\n            {\"category\": \"database\", \"language\": \"english\"}\n        ]\n    )\n\n    # Query the collection\n    results = collection.query(\n        query_texts=[\"What is AI?\"],\n        n_results=2,\n        where={\"category\": \"ai\"}\n    )\n\n    print(\"Search Results:\")\n    print(results[\"documents\"][0])\n    print(results[\"metadatas\"][0])\n    print(results[\"distances\"][0])\n\n    # Get document count\n    count = collection.count()\n    print(f\"Total documents: {count}\")\n\n    # Update a document\n    collection.update(\n        ids=[\"doc2\"],\n        documents=[\"Machine learning is a powerful subset of artificial intelligence\"],\n        metadatas=[{\"category\": \"ai\", \"language\": \"english\", \"updated\": True}]\n    )\n\n    # Delete documents\n    collection.delete(ids=[\"doc4\"])\n\nif __name__ == \"__main__\":\n    main()\n```\n\n---\n\n## Complete Example: Semantic Search with OpenAI\n\n```python\nimport chromadb\nfrom chromadb.utils import embedding_functions\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ndef semantic_search():\n    client = chromadb.PersistentClient(path=\"./semantic_db\")\n\n    openai_ef = embedding_functions.OpenAIEmbeddingFunction(\n        api_key=os.getenv(\"OPENAI_API_KEY\"),\n        model_name=\"text-embedding-3-small\"\n    )\n\n    collection = client.get_or_create_collection(\n        name=\"articles\",\n        embedding_function=openai_ef,\n        metadata={\"hnsw:space\": \"cosine\"}\n    )\n\n    # Add articles\n    collection.add(\n        ids=[\"art1\", \"art2\", \"art3\"],\n        documents=[\n            \"Climate change is affecting global weather patterns\",\n            \"New breakthrough in quantum computing announced\",\n            \"The future of renewable energy looks promising\"\n        ],\n        metadatas=[\n            {\"topic\": \"environment\", \"date\": \"2024-01-15\"},\n            {\"topic\": \"technology\", \"date\": \"2024-01-16\"},\n            {\"topic\": \"energy\", \"date\": \"2024-01-17\"}\n        ]\n    )\n\n    # Search for relevant articles\n    results = collection.query(\n        query_texts=[\"Tell me about environmental issues\"],\n        n_results=3\n    )\n\n    for idx, doc in enumerate(results[\"documents\"][0]):\n        print(f\"Result {idx + 1}:\")\n        print(f\"Document: {doc}\")\n        print(f\"Metadata: {results['metadatas'][0][idx]}\")\n        print(f\"Distance: {results['distances'][0][idx]}\")\n        print(\"---\")\n\nif __name__ == \"__main__\":\n    semantic_search()\n```\n\n---\n\n## Complete Example: RAG (Retrieval-Augmented Generation)\n\n```python\nimport chromadb\nfrom openai import OpenAI\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ndef rag_example():\n    # Initialize ChromaDB\n    chroma_client = chromadb.PersistentClient(path=\"./rag_db\")\n    collection = chroma_client.get_or_create_collection(\n        name=\"company_docs\",\n        metadata={\"hnsw:space\": \"cosine\"}\n    )\n\n    # Add company knowledge base\n    collection.add(\n        ids=[\"policy1\", \"policy2\", \"policy3\"],\n        documents=[\n            \"Our company offers 20 days of paid vacation per year\",\n            \"Remote work is available 3 days per week\",\n            \"Health insurance includes dental and vision coverage\"\n        ],\n        metadatas=[\n            {\"type\": \"policy\", \"category\": \"time-off\"},\n            {\"type\": \"policy\", \"category\": \"work-arrangement\"},\n            {\"type\": \"policy\", \"category\": \"benefits\"}\n        ]\n    )\n\n    # User question\n    question = \"How many vacation days do I get?\"\n\n    # Retrieve relevant context\n    search_results = collection.query(\n        query_texts=[question],\n        n_results=2\n    )\n\n    context = \"\\n\".join(search_results[\"documents\"][0])\n\n    # Generate answer with OpenAI\n    openai_client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n\n    completion = openai_client.chat.completions.create(\n        model=\"gpt-4\",\n        messages=[\n            {\n                \"role\": \"system\",\n                \"content\": \"Answer the question based on the context provided.\"\n            },\n            {\n                \"role\": \"user\",\n                \"content\": f\"Context:\\n{context}\\n\\nQuestion: {question}\"\n            }\n        ]\n    )\n\n    print(\"Answer:\", completion.choices[0].message.content)\n\nif __name__ == \"__main__\":\n    rag_example()\n```\n\n---\n\n## Complete Example: Streaming Large Dataset\n\n```python\nimport chromadb\nfrom typing import List, Generator\n\ndef document_generator(file_path: str) -> Generator[str, None, None]:\n    \"\"\"Generator to stream documents from a file.\"\"\"\n    with open(file_path, 'r') as f:\n        for line in f:\n            yield line.strip()\n\ndef stream_add_documents(collection, doc_gen: Generator, batch_size: int = 1000):\n    \"\"\"Add documents in batches from a generator.\"\"\"\n    batch_ids = []\n    batch_docs = []\n    counter = 0\n\n    for doc in doc_gen:\n        batch_ids.append(f\"doc{counter}\")\n        batch_docs.append(doc)\n        counter += 1\n\n        if len(batch_docs) >= batch_size:\n            collection.add(\n                ids=batch_ids,\n                documents=batch_docs\n            )\n            print(f\"Added {counter} documents...\")\n            batch_ids = []\n            batch_docs = []\n\n    # Add remaining documents\n    if batch_docs:\n        collection.add(\n            ids=batch_ids,\n            documents=batch_docs\n        )\n        print(f\"Added final {len(batch_docs)} documents. Total: {counter}\")\n\ndef main():\n    client = chromadb.PersistentClient(path=\"./large_db\")\n    collection = client.get_or_create_collection(name=\"large_collection\")\n\n    # Stream and add documents\n    doc_gen = document_generator(\"large_dataset.txt\")\n    stream_add_documents(collection, doc_gen, batch_size=5000)\n\n    print(f\"Total documents in collection: {collection.count()}\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n---\n\n## Environment Variables\n\n### .env File Setup\n\n```bash\n# ChromaDB Server\nCHROMA_HOST=localhost\nCHROMA_PORT=8000\n\n# Authentication (if required)\nCHROMA_AUTH_TOKEN=your-auth-token\n\n# Embedding API Keys\nOPENAI_API_KEY=sk-...\nCOHERE_API_KEY=...\nHF_API_KEY=...\n```\n\n### Using Environment Variables\n\n```python\nimport chromadb\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nclient = chromadb.HttpClient(\n    host=os.getenv(\"CHROMA_HOST\", \"localhost\"),\n    port=int(os.getenv(\"CHROMA_PORT\", \"8000\")),\n    headers={\"Authorization\": f\"Bearer {os.getenv('CHROMA_AUTH_TOKEN')}\"}\n    if os.getenv(\"CHROMA_AUTH_TOKEN\") else None\n)\n```\n\n---\n\n## Type Hints\n\n### Query Results Type\n\n```python\nfrom typing import TypedDict, List, Optional\n\nclass QueryResult(TypedDict):\n    ids: List[List[str]]\n    embeddings: Optional[List[List[List[float]]]]\n    documents: List[List[Optional[str]]]\n    metadatas: List[List[Optional[dict]]]\n    distances: Optional[List[List[float]]]\n```\n\n### Get Results Type\n\n```python\nfrom typing import TypedDict, List, Optional\n\nclass GetResult(TypedDict):\n    ids: List[str]\n    embeddings: Optional[List[List[float]]]\n    documents: List[Optional[str]]\n    metadatas: List[Optional[dict]]\n```\n\n### Type-Safe Collection Operations\n\n```python\nfrom typing import List, Dict, Optional\n\ndef add_typed_documents(\n    collection,\n    ids: List[str],\n    documents: List[str],\n    metadatas: Optional[List[Dict[str, any]]] = None\n) -> None:\n    collection.add(\n        ids=ids,\n        documents=documents,\n        metadatas=metadatas\n    )\n```\n\n---\n\n## Error Handling\n\n### Handle Collection Not Found\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient()\n\ntry:\n    collection = client.get_collection(name=\"nonexistent_collection\")\nexcept ValueError as e:\n    if \"does not exist\" in str(e):\n        print(\"Collection not found, creating...\")\n        collection = client.create_collection(name=\"nonexistent_collection\")\n    else:\n        raise\n```\n\n### Handle Duplicate IDs\n\n```python\ntry:\n    collection.add(\n        ids=[\"id1\"],\n        documents=[\"Document\"]\n    )\n\n    # This will fail - ID already exists\n    collection.add(\n        ids=[\"id1\"],\n        documents=[\"Another document\"]\n    )\nexcept Exception as e:\n    print(f\"ID already exists. Use update() or upsert() instead. Error: {e}\")\n\n    # Use upsert to add or update\n    collection.upsert(\n        ids=[\"id1\"],\n        documents=[\"Another document\"]\n    )\n```\n\n### Handle Connection Errors\n\n```python\nimport chromadb\nfrom requests.exceptions import ConnectionError\n\ntry:\n    client = chromadb.HttpClient(host=\"localhost\", port=8000)\n    collections = client.list_collections()\nexcept ConnectionError:\n    print(\"Cannot connect to ChromaDB server. Make sure it's running.\")\n    print(\"Start server with: chroma run --path ./data\")\nexcept Exception as e:\n    print(f\"Error: {e}\")\n```\n\n### Handle Empty Results\n\n```python\nresults = collection.query(\n    query_texts=[\"Very specific query\"],\n    n_results=5\n)\n\nif not results[\"ids\"][0]:\n    print(\"No results found. Try a broader query.\")\nelse:\n    print(f\"Found {len(results['ids'][0])} results\")\n```\n\n---\n\n## Performance Optimization\n\n### Batch Operations\n\n```python\n# Batch add for large datasets\nchunk_size = 5000\nfor i in range(0, len(documents), chunk_size):\n    collection.add(\n        ids=ids[i:i + chunk_size],\n        documents=documents[i:i + chunk_size],\n        metadatas=metadatas[i:i + chunk_size]\n    )\n```\n\n### Parallel Queries\n\n```python\nimport concurrent.futures\n\nqueries = [\n    \"Query about topic A\",\n    \"Query about topic B\",\n    \"Query about topic C\"\n]\n\ndef run_query(query):\n    return collection.query(\n        query_texts=[query],\n        n_results=5\n    )\n\nwith concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:\n    results = list(executor.map(run_query, queries))\n```\n\n### Limit Included Fields\n\n```python\n# Exclude embeddings for better performance\nresults = collection.query(\n    query_texts=[\"Search query\"],\n    n_results=10,\n    include=[\"documents\", \"metadatas\", \"distances\"]\n    # Don't include embeddings unless needed\n)\n```\n\n### Reuse Embedding Function\n\n```python\nfrom chromadb.utils import embedding_functions\n\n# Create once, reuse for multiple collections\nopenai_ef = embedding_functions.OpenAIEmbeddingFunction(\n    api_key=\"your-api-key\",\n    model_name=\"text-embedding-3-small\"\n)\n\ncollection1 = client.create_collection(\n    name=\"collection1\",\n    embedding_function=openai_ef\n)\n\ncollection2 = client.create_collection(\n    name=\"collection2\",\n    embedding_function=openai_ef\n)\n```\n\n---\n\n## Common Patterns\n\n### Incremental Updates\n\n```python\ndef add_daily_documents(collection, new_docs: List[str]):\n    \"\"\"Add new documents daily.\"\"\"\n    count = collection.count()\n    new_ids = [f\"doc{count + i}\" for i in range(len(new_docs))]\n\n    from datetime import datetime\n    collection.add(\n        ids=new_ids,\n        documents=new_docs,\n        metadatas=[{\"added_date\": datetime.now().isoformat()} for _ in new_docs]\n    )\n```\n\n### Search with Fallback\n\n```python\ndef search_with_fallback(collection, query: str):\n    \"\"\"Try specific category first, fallback to all documents.\"\"\"\n    # Try specific category first\n    results = collection.query(\n        query_texts=[query],\n        n_results=5,\n        where={\"category\": \"premium\"}\n    )\n\n    # If no results, search all documents\n    if not results[\"ids\"][0]:\n        results = collection.query(\n            query_texts=[query],\n            n_results=5\n        )\n\n    return results\n```\n\n### Deduplicate Documents\n\n```python\ndef add_unique(collection, doc_id: str, document: str, metadata: dict):\n    \"\"\"Add document only if ID doesn't exist, otherwise update.\"\"\"\n    try:\n        existing = collection.get(ids=[doc_id])\n        if existing[\"ids\"]:\n            print(\"Document already exists, updating...\")\n            collection.update(\n                ids=[doc_id],\n                documents=[document],\n                metadatas=[metadata]\n            )\n        else:\n            collection.add(\n                ids=[doc_id],\n                documents=[document],\n                metadatas=[metadata]\n            )\n    except Exception:\n        collection.add(\n            ids=[doc_id],\n            documents=[document],\n            metadatas=[metadata]\n        )\n```\n\n### Pagination\n\n```python\ndef paginate_collection(collection, page_size: int = 100):\n    \"\"\"Iterate through all documents in pages.\"\"\"\n    total = collection.count()\n\n    for offset in range(0, total, page_size):\n        results = collection.get(\n            limit=page_size,\n            offset=offset\n        )\n        yield results\n\n# Usage\nfor page in paginate_collection(collection, page_size=100):\n    print(f\"Processing {len(page['ids'])} documents...\")\n    # Process documents\n```\n\n---\n\n## Metadata Filter Operators\n\n### Comparison Operators\n\n```python\n# Equal\nwhere = {\"category\": \"tech\"}\nwhere = {\"category\": {\"$eq\": \"tech\"}}\n\n# Not equal\nwhere = {\"category\": {\"$ne\": \"tech\"}}\n\n# Greater than\nwhere = {\"price\": {\"$gt\": 100}}\n\n# Greater than or equal\nwhere = {\"price\": {\"$gte\": 100}}\n\n# Less than\nwhere = {\"price\": {\"$lt\": 100}}\n\n# Less than or equal\nwhere = {\"price\": {\"$lte\": 100}}\n```\n\n### Logical Operators\n\n```python\n# AND\nwhere = {\n    \"$and\": [\n        {\"category\": \"tech\"},\n        {\"price\": {\"$lt\": 1000}}\n    ]\n}\n\n# OR\nwhere = {\n    \"$or\": [\n        {\"category\": \"tech\"},\n        {\"category\": \"science\"}\n    ]\n}\n\n# NOT\nwhere = {\n    \"$not\": {\"category\": \"archived\"}\n}\n```\n\n### Set Operators\n\n```python\n# In array\nwhere = {\n    \"category\": {\"$in\": [\"tech\", \"science\", \"health\"]}\n}\n\n# Not in array\nwhere = {\n    \"category\": {\"$nin\": [\"archived\", \"deleted\"]}\n}\n```\n\n---\n\n## Document Filter Operators\n\n### Contains\n\n```python\nwhere_document = {\"$contains\": \"machine learning\"}\n```\n\n### Not Contains\n\n```python\nwhere_document = {\"$not_contains\": \"deprecated\"}\n```\n\n### Combined with Metadata\n\n```python\nresults = collection.query(\n    query_texts=[\"AI research\"],\n    where={\"category\": \"research\"},\n    where_document={\"$contains\": \"neural network\"},\n    n_results=10\n)\n```\n\n---\n\n## Working with Different Data Types\n\n### Numeric Metadata\n\n```python\ncollection.add(\n    ids=[\"p1\", \"p2\", \"p3\"],\n    documents=[\"Product A\", \"Product B\", \"Product C\"],\n    metadatas=[\n        {\"price\": 29.99, \"stock\": 100},\n        {\"price\": 49.99, \"stock\": 50},\n        {\"price\": 19.99, \"stock\": 200}\n    ]\n)\n\n# Query by price range\nresults = collection.query(\n    query_texts=[\"affordable products\"],\n    where={\n        \"$and\": [\n            {\"price\": {\"$lt\": 50}},\n            {\"stock\": {\"$gt\": 75}}\n        ]\n    },\n    n_results=5\n)\n```\n\n### Boolean Metadata\n\n```python\ncollection.add(\n    ids=[\"u1\", \"u2\", \"u3\"],\n    documents=[\"User profile A\", \"User profile B\", \"User profile C\"],\n    metadatas=[\n        {\"active\": True, \"premium\": False},\n        {\"active\": True, \"premium\": True},\n        {\"active\": False, \"premium\": False}\n    ]\n)\n\n# Query active premium users\nresults = collection.query(\n    query_texts=[\"find users\"],\n    where={\n        \"$and\": [\n            {\"active\": True},\n            {\"premium\": True}\n        ]\n    },\n    n_results=10\n)\n```\n\n### List Metadata\n\n```python\ncollection.add(\n    ids=[\"a1\", \"a2\"],\n    documents=[\"Article about AI and ML\", \"Article about databases\"],\n    metadatas=[\n        {\"tags\": [\"ai\", \"machine-learning\", \"neural-networks\"]},\n        {\"tags\": [\"database\", \"vector-search\"]}\n    ]\n)\n\n# Note: ChromaDB metadata values should be strings, numbers, or booleans\n# For list-like metadata, use multiple metadata fields or JSON strings\n```\n\n---\n\n## Context Manager Pattern\n\n```python\nimport chromadb\nfrom contextlib import contextmanager\n\n@contextmanager\ndef get_collection(collection_name: str, path: str = \"./chroma_db\"):\n    \"\"\"Context manager for ChromaDB collection.\"\"\"\n    client = chromadb.PersistentClient(path=path)\n    collection = client.get_or_create_collection(name=collection_name)\n    try:\n        yield collection\n    finally:\n        # Cleanup if needed\n        pass\n\n# Usage\nwith get_collection(\"my_collection\") as collection:\n    collection.add(\n        ids=[\"id1\"],\n        documents=[\"Document\"]\n    )\n    results = collection.query(\n        query_texts=[\"Query\"],\n        n_results=5\n    )\n    print(results)\n```\n\n---\n\n## Testing with ChromaDB\n\n### Using EphemeralClient for Tests\n\n```python\nimport unittest\nimport chromadb\n\nclass TestDocumentSearch(unittest.TestCase):\n    def setUp(self):\n        \"\"\"Create ephemeral client for each test.\"\"\"\n        self.client = chromadb.EphemeralClient()\n        self.collection = self.client.create_collection(name=\"test_collection\")\n\n    def test_add_and_query(self):\n        \"\"\"Test adding documents and querying.\"\"\"\n        self.collection.add(\n            ids=[\"test1\", \"test2\"],\n            documents=[\"Document about cats\", \"Document about dogs\"]\n        )\n\n        results = self.collection.query(\n            query_texts=[\"pets\"],\n            n_results=2\n        )\n\n        self.assertEqual(len(results[\"ids\"][0]), 2)\n\n    def test_metadata_filtering(self):\n        \"\"\"Test metadata filtering.\"\"\"\n        self.collection.add(\n            ids=[\"test1\", \"test2\"],\n            documents=[\"Doc 1\", \"Doc 2\"],\n            metadatas=[{\"category\": \"A\"}, {\"category\": \"B\"}]\n        )\n\n        results = self.collection.query(\n            query_texts=[\"search\"],\n            where={\"category\": \"A\"},\n            n_results=5\n        )\n\n        self.assertEqual(len(results[\"ids\"][0]), 1)\n\nif __name__ == \"__main__\":\n    unittest.main()\n```\n\n---\n\n## Monitoring and Debugging\n\n### Enable Logging\n\n```python\nimport logging\nimport chromadb\n\n# Enable ChromaDB logging\nlogging.basicConfig(level=logging.DEBUG)\nlogger = logging.getLogger(\"chromadb\")\nlogger.setLevel(logging.DEBUG)\n\nclient = chromadb.PersistentClient(path=\"./debug_db\")\n```\n\n### Inspect Collection Details\n\n```python\ncollection = client.get_collection(name=\"my_collection\")\n\nprint(f\"Collection name: {collection.name}\")\nprint(f\"Collection metadata: {collection.metadata}\")\nprint(f\"Document count: {collection.count()}\")\n\n# Peek at first documents\nfirst_docs = collection.peek(limit=3)\nprint(f\"First documents: {first_docs}\")\n```\n\n### Performance Profiling\n\n```python\nimport time\n\ndef profile_query(collection, query_text: str, n_results: int = 10):\n    \"\"\"Profile query performance.\"\"\"\n    start = time.time()\n    results = collection.query(\n        query_texts=[query_text],\n        n_results=n_results\n    )\n    elapsed = time.time() - start\n\n    print(f\"Query: {query_text}\")\n    print(f\"Time: {elapsed:.3f}s\")\n    print(f\"Results: {len(results['ids'][0])}\")\n    return results\n\n# Usage\nprofile_query(collection, \"machine learning\", n_results=100)\n```\n\n---\n\n## Migration and Backup\n\n### Export Collection to JSON\n\n```python\nimport json\n\ndef export_collection(collection, output_file: str):\n    \"\"\"Export entire collection to JSON.\"\"\"\n    all_data = collection.get()\n\n    export_data = {\n        \"ids\": all_data[\"ids\"],\n        \"documents\": all_data[\"documents\"],\n        \"metadatas\": all_data[\"metadatas\"],\n        \"embeddings\": all_data.get(\"embeddings\")\n    }\n\n    with open(output_file, 'w') as f:\n        json.dump(export_data, f)\n\n    print(f\"Exported {len(all_data['ids'])} documents to {output_file}\")\n\n# Usage\nexport_collection(collection, \"backup.json\")\n```\n\n### Import Collection from JSON\n\n```python\nimport json\n\ndef import_collection(collection, input_file: str):\n    \"\"\"Import collection from JSON.\"\"\"\n    with open(input_file, 'r') as f:\n        import_data = json.load(f)\n\n    collection.add(\n        ids=import_data[\"ids\"],\n        documents=import_data[\"documents\"],\n        metadatas=import_data[\"metadatas\"],\n        embeddings=import_data.get(\"embeddings\")\n    )\n\n    print(f\"Imported {len(import_data['ids'])} documents from {input_file}\")\n\n# Usage\nimport_collection(collection, \"backup.json\")\n```\n\n### Copy Collection\n\n```python\ndef copy_collection(source_collection, dest_collection, batch_size: int = 1000):\n    \"\"\"Copy all data from source to destination collection.\"\"\"\n    total = source_collection.count()\n\n    for offset in range(0, total, batch_size):\n        data = source_collection.get(\n            limit=batch_size,\n            offset=offset,\n            include=[\"documents\", \"metadatas\", \"embeddings\"]\n        )\n\n        dest_collection.add(\n            ids=data[\"ids\"],\n            documents=data[\"documents\"],\n            metadatas=data[\"metadatas\"],\n            embeddings=data.get(\"embeddings\")\n        )\n\n        print(f\"Copied {offset + len(data['ids'])}/{total} documents\")\n\n# Usage\nsource = client.get_collection(name=\"original\")\ndest = client.create_collection(name=\"backup\")\ncopy_collection(source, dest)\n```\n"
  },
  {
    "path": "content/chromadb/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ChromaDB Python package for local, server, and cloud vector search, collections, embeddings, and retrieval\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"chromadb,vector-db,retrieval,rag,embeddings,search\"\n---\n\n# ChromaDB Python Package Guide\n\n## Golden Rule\n\nUse `chromadb` for Python code that creates or queries Chroma collections, and choose the client class based on where the database lives:\n\n- `PersistentClient` for local embedded storage\n- `EphemeralClient` or `Client()` for tests and short-lived prototypes\n- `HttpClient` or `AsyncHttpClient` for a self-hosted server\n- `CloudClient` for Chroma Cloud\n\nBe explicit about tenant, database, and embedding strategy when the defaults are not obvious. In current Chroma docs, query and get remain the core collection APIs for OSS and self-hosted use.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"chromadb==1.5.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"chromadb==1.5.5\"\npoetry add \"chromadb==1.5.5\"\n```\n\nNotes:\n\n- `chromadb` includes the Python client and the bundled `chroma` CLI.\n- If you only need a smaller remote-only client, upstream also publishes `chromadb-client`, but this doc covers the full `chromadb` package.\n- PyPI shows `1.5.3` as yanked, so prefer an exact known-good pin such as `1.5.5` rather than assuming any `1.5.x` build is interchangeable.\n\n## Choose The Right Client\n\n### Local persistent storage\n\nUse this for embedded apps, notebooks, local development, and single-node deployments:\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient(path=\"./chroma-data\")\n```\n\n### In-memory development client\n\nUse this for tests or disposable prototypes:\n\n```python\nimport chromadb\n\nclient = chromadb.EphemeralClient()\n```\n\n`chromadb.Client()` is the environment-configured variant. It is useful when you want client construction to follow `Settings`, `.env`, or other environment-driven configuration:\n\n```python\nimport chromadb\n\nclient = chromadb.Client()\n```\n\n### Self-hosted server client\n\nRun a local or remote Chroma server:\n\n```bash\nchroma run --path ./chroma-data\n```\n\nThen connect over HTTP:\n\n```python\nimport chromadb\nfrom chromadb.config import DEFAULT_DATABASE, DEFAULT_TENANT, Settings\n\nclient = chromadb.HttpClient(\n    host=\"localhost\",\n    port=8000,\n    ssl=False,\n    headers=None,\n    settings=Settings(),\n    tenant=DEFAULT_TENANT,\n    database=DEFAULT_DATABASE,\n)\n```\n\nAsync HTTP is available when your app is already async:\n\n```python\nimport asyncio\n\nimport chromadb\n\nasync def main() -> None:\n    client = await chromadb.AsyncHttpClient(host=\"localhost\", port=8000, ssl=False)\n    print(client)\n\nasyncio.run(main())\n```\n\n### Chroma Cloud client\n\nCloud uses an API key plus tenant and database selection:\n\n```bash\nexport CHROMA_API_KEY=\"ck-...\"\nexport CHROMA_TENANT=\"your-tenant-id\"\nexport CHROMA_DATABASE=\"your-database-name\"\n```\n\n```python\nimport chromadb\n\nclient = chromadb.CloudClient()\n```\n\nOr pass them explicitly:\n\n```python\nimport chromadb\n\nclient = chromadb.CloudClient(\n    api_key=\"ck-...\",\n    tenant=\"your-tenant-id\",\n    database=\"your-database-name\",\n)\n```\n\n## Core Collection Workflow\n\nCreate or reuse a collection, then add or upsert records:\n\n```python\nimport chromadb\n\nclient = chromadb.PersistentClient(path=\"./chroma-data\")\n\ncollection = client.get_or_create_collection(\n    name=\"support_articles\",\n    configuration={\"hnsw\": {\"space\": \"cosine\"}},\n)\n\ncollection.upsert(\n    ids=[\"doc-1\", \"doc-2\"],\n    documents=[\n        \"Reset your password from the account settings page.\",\n        \"Contact billing@example.com for invoice issues.\",\n    ],\n    metadatas=[\n        {\"source\": \"kb\", \"tags\": [\"auth\", \"account\"]},\n        {\"source\": \"kb\", \"tags\": [\"billing\", \"account\"]},\n    ],\n)\n```\n\nWhat matters here:\n\n- If you add only `documents`, Chroma computes embeddings using the collection's embedding function.\n- If you add `documents` plus explicit `embeddings`, Chroma stores both without re-embedding the documents.\n- Metadata values can be strings, integers, floats, booleans, and homogeneous arrays of those scalar types.\n\n## Query, Get, And Filters\n\nUse `.query()` for similarity search and `.get()` for direct retrieval without ranking:\n\n```python\nresult = collection.query(\n    query_texts=[\"How do I change my password?\"],\n    n_results=3,\n    where={\"tags\": {\"$contains\": \"auth\"}},\n    include=[\"documents\", \"metadatas\", \"distances\"],\n)\n\nfor doc_id, document, metadata, distance in zip(\n    result[\"ids\"][0],\n    result[\"documents\"][0],\n    result[\"metadatas\"][0],\n    result[\"distances\"][0],\n):\n    print(doc_id, distance, metadata, document)\n```\n\n```python\nrecords = collection.get(\n    ids=[\"doc-1\"],\n    include=[\"documents\", \"metadatas\"],\n)\n\nfor doc_id, document, metadata in zip(\n    records[\"ids\"],\n    records[\"documents\"],\n    records[\"metadatas\"],\n):\n    print(doc_id, metadata, document)\n```\n\nUseful filters:\n\n- `where={...}` for metadata predicates such as equality, ranges, `$and`, `$or`, `$in`, and array membership with `$contains` or `$not_contains`\n- `where_document={...}` for document-text filters such as `$contains` and `$regex`\n\nExample document filter:\n\n```python\nmatches = collection.get(\n    where_document={\"$regex\": \"billing@example\\\\.com\"},\n    include=[\"documents\"],\n)\n```\n\nResult-shape reminder:\n\n- `.query()` returns grouped results per input query, so Python results are nested lists\n- `.get()` returns flat arrays, so corresponding elements line up by index\n- `include=[...]` controls payload size; `ids` are always returned\n\n## Embedding Functions\n\nIf you do not specify an embedding function, Chroma uses `DefaultEmbeddingFunction`, which runs locally and uses the `all-MiniLM-L6-v2` model. The first call may download model files automatically.\n\nDefault embedding function:\n\n```python\ncollection = client.create_collection(name=\"notes\")\n```\n\nProvider-backed embedding function:\n\n```python\nfrom chromadb.utils.embedding_functions import OpenAIEmbeddingFunction\n\ncollection = client.create_collection(\n    name=\"openai-notes\",\n    embedding_function=OpenAIEmbeddingFunction(\n        model_name=\"text-embedding-3-small\",\n    ),\n)\n```\n\nIf a collection has no embedding function attached, you must provide `query_embeddings` rather than `query_texts`.\n\n## Auth, Tenancy, And Configuration\n\n### Self-hosted token auth\n\nFor Chroma `1.0.x+`, use a proxy or external auth layer rather than legacy built-in auth examples. The cookbook shows Envoy-based token auth with either `Authorization` or `X-Chroma-Token`.\n\nPython client example:\n\n```python\nimport os\n\nimport chromadb\nfrom chromadb.config import Settings\n\nclient = chromadb.HttpClient(\n    host=\"chroma.internal.example\",\n    port=443,\n    ssl=True,\n    settings=Settings(\n        chroma_client_auth_provider=\"chromadb.auth.token_authn.TokenAuthClientProvider\",\n        chroma_client_auth_credentials=os.environ[\"CHROMA_TOKEN\"],\n        chroma_auth_token_transport_header=\"Authorization\",\n    ),\n)\n```\n\n### Tenants and databases\n\nAll current client constructors accept or resolve a tenant and database. Defaults are usually `default_tenant` and `default_database`, but production code should not assume that when you are using shared or cloud environments.\n\n### Collection configuration\n\nAt collection creation time, you can tune HNSW parameters such as:\n\n- `space`: `l2`, `cosine`, or `ip`\n- `ef_construction`\n- `ef_search`\n- `max_neighbors`\n\nFor text embeddings, `cosine` is often the right first choice.\n\n## Common Pitfalls\n\n- `collection.add()` ignores rows whose IDs already exist. Use `update()` or `upsert()` when you intend to overwrite.\n- `update()` recomputes embeddings if you pass `documents` without corresponding `embeddings`.\n- Manual embeddings and query embeddings must match the collection's embedding dimensionality.\n- Collection names are restricted: 3 to 512 characters, lowercase letter or digit at both ends, dots/dashes/underscores allowed inside, no consecutive dots, and not a valid IP address.\n- `where_document` full-text and regex matching is case-sensitive.\n- Query results are nested by input query. Agents often treat `result[\"documents\"]` as a flat list and then zip the wrong level.\n- Use `include` aggressively. Returning embeddings, documents, metadatas, and distances for every query can waste bandwidth and tokens.\n- `PersistentClient`, `HttpClient`, and `AsyncHttpClient` accept positional parameters, but keyword arguments are safer because the signatures are dense and easy to misorder.\n\n## Version-Sensitive Notes For 1.5.5\n\n- PyPI lists `chromadb 1.5.5` as the latest release on March 10, 2026, with Python `>=3.9`.\n- Array metadata is part of the current docs model: you can store homogeneous arrays and filter them with `$contains` and `$not_contains`.\n- The v1.0.0 migration notes say Chroma no longer provides built-in authentication implementations. Prefer current proxy or token-based patterns from the cookbook instead of pre-1.0 auth examples.\n- The current docs still center OSS and self-hosted retrieval on `collection.query()` and `collection.get()`. Do not assume Cloud-specific search examples replace these methods in existing Python codebases.\n"
  },
  {
    "path": "content/clearml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ClearML Python SDK guide for experiment tracking, configuration, and dataset workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"clearml,python,mlops,experiments,datasets,tracking\"\n---\n\n# ClearML Python Package Guide\n\n## What This Package Is For\n\n`clearml` is the Python SDK for ClearML experiment tracking and data/model management. The core SDK surface is centered on `Task` for run tracking and `Dataset` for versioned data.\n\nUse this doc for the package version used here, `2.1.3`, with the official docs root at `https://clear.ml/docs/latest/docs/`.\n\n## Install\n\nBase install:\n\n```bash\npip install clearml==2.1.3\n```\n\nIf you need cloud storage integrations for artifacts or datasets, install the matching extra:\n\n```bash\npip install \"clearml[s3]==2.1.3\"\npip install \"clearml[gs]==2.1.3\"\npip install \"clearml[azure]==2.1.3\"\n```\n\nImport paths are package-native:\n\n```python\nfrom clearml import Dataset, Task\n```\n\n## First-Time Setup And Auth\n\nThe standard setup flow is:\n\n1. Create or sign in to a ClearML server or `app.clear.ml` workspace.\n2. Open **Settings > Workspace > Create new credentials** in the web app.\n3. Run `clearml-init` locally and paste the web host, API host, files host, access key, and secret key.\n\n```bash\nclearml-init\n```\n\nImportant behavior:\n\n- `clearml-init` does **not** overwrite an existing `clearml.conf`.\n- If you are switching servers or workspaces, remove or replace the stale config yourself.\n- For CI, containers, or ephemeral jobs, prefer environment variables or `Task.set_credentials(...)`.\n\nUseful environment variables:\n\n```bash\nexport CLEARML_API_HOST=\"https://api.clear.ml\"\nexport CLEARML_WEB_HOST=\"https://app.clear.ml\"\nexport CLEARML_FILES_HOST=\"https://files.clear.ml\"\nexport CLEARML_API_ACCESS_KEY=\"...\"\nexport CLEARML_API_SECRET_KEY=\"...\"\nexport CLEARML_CONFIG_FILE=\"/abs/path/to/clearml.conf\"\n```\n\nIf you set credentials in code, do it before `Task.init()`:\n\n```python\nfrom clearml import Task\n\nTask.set_credentials(\n    api_host=\"https://api.clear.ml\",\n    web_host=\"https://app.clear.ml\",\n    files_host=\"https://files.clear.ml\",\n    key=\"CLEARML_ACCESS_KEY\",\n    secret=\"CLEARML_SECRET_KEY\",\n)\n```\n\n## Minimal Experiment Tracking\n\nInitialize a task early, connect your config, and log metrics through the ClearML logger:\n\n```python\nfrom clearml import Task\n\ntask = Task.init(\n    project_name=\"forecasting\",\n    task_name=\"xgboost-baseline\",\n    task_type=Task.TaskTypes.training,\n    reuse_last_task_id=False,\n)\n\nparams = {\n    \"learning_rate\": 0.1,\n    \"max_depth\": 6,\n    \"n_estimators\": 200,\n}\ntask.connect(params)\n\nlogger = task.get_logger()\n\nfor epoch, loss in enumerate([0.61, 0.47, 0.38], start=1):\n    logger.report_scalar(\"loss\", \"train\", iteration=epoch, value=loss)\n\ntask.close()\n```\n\nPractical notes:\n\n- `Task.init()` is the normal entry point for tracked runs.\n- `task.connect(...)` is the simplest way to persist a dict of hyperparameters or runtime config.\n- Set `reuse_last_task_id=False` when you want each local run to create a fresh task instead of reusing the previous development task.\n- Close the task explicitly if the same process may create another task later.\n\n## Dataset Workflow\n\nUse `Dataset` when you want versioned, reproducible data instead of ad hoc local paths.\n\nCreate and publish a dataset version:\n\n```python\nfrom clearml import Dataset\n\ndataset = Dataset.create(\n    dataset_project=\"forecasting-data\",\n    dataset_name=\"raw-training-data\",\n)\ndataset.add_files(path=\"/data/raw\")\ndataset.upload()\ndataset.finalize()\n```\n\nResolve a dataset version back into a local working directory:\n\n```python\nfrom clearml import Dataset\n\nlocal_path = Dataset.get(\n    dataset_project=\"forecasting-data\",\n    dataset_name=\"raw-training-data\",\n).get_local_copy()\n```\n\nIf datasets or artifacts are stored in S3, GCS, or Azure, install the matching package extra and make sure the storage credentials are configured in ClearML before upload or download.\n\n## Configuration Patterns\n\n`clearml` supports three practical configuration paths:\n\n- `clearml.conf` on disk for developer machines and long-lived environments\n- environment variables for CI, containers, and secret injection\n- `Task.set_credentials(...)` for explicit bootstrap code\n\nUse `CLEARML_CONFIG_FILE` when your config file is not in the default location. This is useful in Docker images and managed jobs where the config must live in a mounted secret or generated path.\n\n## Common Pitfalls\n\n- `Task.init()` requires valid `project_name` and `task_name` values when it creates a new task. The docs note a minimum name length of 3 characters.\n- Call `Task.set_credentials(...)` before `Task.init()`, not after.\n- `clearml-init` will keep an old config file in place, so switching between self-hosted and hosted ClearML can silently point jobs at the wrong server.\n- Remote storage support is not automatic. Install the matching extra such as `clearml[s3]` before using S3-backed datasets or artifact output.\n- Finalize datasets after upload. Leaving them unfinished can produce draft-like states that are awkward to reuse from later runs.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to PyPI version `2.1.3` because that is the version used here for this package.\n- Official docs are served from a latest-tracking root, `https://clear.ml/docs/latest/docs/`, and several pages still use the label \"ClearML 2.0 Documentation\". Treat that site label as product-doc branding, not as a precise pip package version.\n- PyPI shows `2.1.3` as the current stable release and also lists a newer prerelease, `2.1.4rc0`. If you need features added after `2.1.3`, verify them against the installed package and upstream release metadata before copying examples verbatim.\n\n## Official Sources\n\n- Docs root: https://clear.ml/docs/latest/docs/\n- SDK task guide: https://clear.ml/docs/latest/docs/fundamentals/task/\n- `Task.init()` reference: https://clear.ml/docs/latest/docs/references/sdk/task/#taskinit\n- Dataset guide: https://clear.ml/docs/latest/docs/fundamentals/artifacts/data_management/\n- Setup and configuration: https://clear.ml/docs/latest/docs/configs/clearml_conf/\n- Environment variables: https://clear.ml/docs/latest/docs/configs/env_vars/\n- `clearml-init`: https://clear.ml/docs/latest/docs/clearml_sdk/clearml_sdk_setup/\n- PyPI package: https://pypi.org/project/clearml/\n"
  },
  {
    "path": "content/clerk/docs/auth/javascript/DOC.md",
    "content": "---\nname: auth\ndescription: \"Clerk JavaScript SDK for user authentication, session management, and identity workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.6\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"clerk,auth,authentication,user-management,session\"\n---\n\n# Clerk JavaScript SDK Coding Guidelines\n\nYou are a Clerk authentication expert. Help me with writing code using the Clerk JavaScript SDK and its official libraries for user authentication and management.\n\nThis guide covers both vanilla JavaScript implementations using `@clerk/clerk-js` and framework-specific implementations using packages like `@clerk/nextjs` and `@clerk/react`.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official documentation and code samples here:\nhttps://clerk.com/docs\n\n## Important Context About This SDK\n\nClerk provides **two main approaches** for JavaScript authentication:\n1. **Vanilla JavaScript (`@clerk/clerk-js`)**: Uses the browser SDK loaded via CDN or NPM, ideal for standalone HTML/JS apps\n2. **Framework SDKs**: Specialized packages for Next.js, React, Vue, etc. with framework-specific optimizations\n\nThis context guide covers both approaches comprehensively.\n\n## Golden Rule: Use the Correct Clerk Package for Your Framework\n\nAlways use the appropriate Clerk SDK for your specific framework or environment. Clerk provides specialized packages for different platforms that include framework-specific optimizations and integrations.\n\n**Available Packages:**\n- **Next.js:** `@clerk/nextjs` \n- **React:** `@clerk/react` \n- **Vanilla JavaScript:** `@clerk/clerk-js` \n- **Vue:** `@clerk/vue`\n- **Astro:** `@clerk/astro`\n- **Remix:** `@clerk/remix`\n- **Express:** `@clerk/express`\n- **Fastify:** `@clerk/fastify`\n- **Expo:** `@clerk/expo`\n\n**Installation Examples:**\n```bash\n# For Next.js applications\nnpm install @clerk/nextjs\n\n# For React applications  \nnpm install @clerk/react\n\n# For vanilla JavaScript\nnpm install @clerk/clerk-js\n```\n\n## Prerequisites and Setup\n\n- An existing Clerk application from the [Clerk Dashboard](https://dashboard.clerk.com/sign-up)\n- For Next.js: Next.js 13.0.4 or later, React 18 or later, Node.js >=18.17.0\n- For vanilla JavaScript: Any modern browser with ES6+ support\n\n## Environment Variables\n\n### For Framework Apps (Next.js, React, etc.)\nSet up your environment variables in `.env.local`:\n```\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...\nCLERK_SECRET_KEY=sk_test_...\n```\n\n### For Vanilla JavaScript Apps\nStore your publishable key in a `.env` file and inject it into your HTML:\n```\nCLERK_PUBLISHABLE_KEY=pk_test_...\n```\n\n**Important**: Only the publishable key is needed for client-side authentication. Never expose your secret key in browser code.\n\n## Next.js Integration\n\n### ClerkProvider Setup\n\nWrap your application with ClerkProvider:\n\n```jsx\nimport { ClerkProvider } from '@clerk/nextjs'\n\nexport default function RootLayout({ children }) {\n  return (\n    <ClerkProvider>\n      <html lang=\"en\">\n        <body>{children}</body>\n      </html>\n    </ClerkProvider>\n  )\n}\n```\n\n### Middleware Configuration\n\nUse `clerkMiddleware` for route protection: \n\n```javascript\nimport { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';\n\nconst isProtectedRoute = createRouteMatcher(['/protected(.*)']);\nconst isAdminRoute = createRouteMatcher(['/admin(.*)']);\n\nexport default clerkMiddleware(async (auth, req) => {\n  if (isProtectedRoute(req)) {\n    await auth.protect();\n  }\n  \n  if (isAdminRoute(req)) {\n    await auth.protect({ role: 'org:admin' });\n  }\n});\n```\n\n**Important:** Do not use the deprecated `authMiddleware`. Always use `clerkMiddleware` for new implementations.\n\n## Client-Side Authentication Hooks\n\n### useUser Hook\n\nAccess the current user information: \n\n```jsx\nimport { useUser } from '@clerk/nextjs';\n\nfunction UserProfile() {\n  const { isLoaded, isSignedIn, user } = useUser();\n  \n  if (!isLoaded || !isSignedIn) {\n    return null;\n  }\n  \n  return <div>Hello, {user.firstName}!</div>;\n}\n```\n\n### useAuth Hook\n\nAccess authentication state and methods:\n\n```jsx\nimport { useAuth } from '@clerk/nextjs';\n\nfunction AuthComponent() {\n  const { isLoaded, userId, sessionId, getToken } = useAuth();\n  \n  // Use authentication state\n}\n```\n\n### useClerk Hook\n\nAccess the Clerk instance for advanced operations:\n\n```jsx\nimport { useClerk } from '@clerk/nextjs';\n\nfunction SignOutButton() {\n  const { signOut } = useClerk();\n  \n  return <button onClick={() => signOut()}>Sign out</button>;\n}\n```\n\n## Server-Side Authentication\n\n### auth() Helper (App Router)\n\nUse the `auth()` helper in Server Components, Route Handlers, and Server Actions: \n\n```jsx\nimport { auth } from '@clerk/nextjs/server';\n\nexport default async function Page() {\n  const { userId } = await auth();\n  \n  if (!userId) {\n    return <div>Please sign in</div>;\n  }\n  \n  return <div>User ID: {userId}</div>;\n}\n```\n\n### currentUser() Helper\n\nGet the full user object on the server side: \n\n```jsx\nimport { currentUser } from '@clerk/nextjs/server';\n\nexport default async function Page() {\n  const user = await currentUser();\n  \n  if (!user) return <div>Not signed in</div>;\n  \n  return <div>Hello {user?.firstName}</div>;\n}\n```\n\n### auth.protect() Method\n\nUse `auth.protect()` for authentication and authorization checks: \n\n```jsx\nimport { auth } from '@clerk/nextjs/server';\n\nexport default async function AdminPage() {\n  // Protect route - redirects unauthenticated users\n  await auth.protect();\n  \n  // Or protect with role check\n  await auth.protect({ role: 'org:admin' });\n  \n  return <div>Protected content</div>;\n}\n```\n\n## Authentication Components\n\n### Sign-In and Sign-Up Buttons\n\nUse pre-built buttons for authentication flows: \n\n```jsx\nimport { SignInButton, SignUpButton } from '@clerk/nextjs';\n\nexport default function Home() {\n  return (\n    <main>\n      <SignInButton mode='modal' forceRedirectUrl='/protected'>\n        Sign in button\n      </SignInButton>\n      \n      <SignUpButton mode='modal' forceRedirectUrl='/protected'>\n        Sign up button  \n      </SignUpButton>\n    </main>\n  );\n}\n```\n\n### Pre-built Components\n\n```jsx\nimport { \n  SignIn, \n  SignUp, \n  UserButton, \n  UserProfile \n} from '@clerk/nextjs';\n\n// Drop-in authentication components\n<SignIn />\n<SignUp />\n<UserButton />\n<UserProfile />\n```\n\n## Organization Management\n\n### Organization Roles and Permissions\n\nClerk supports role-based access control within organizations: \n\n```jsx\n// Check organization permissions\nawait auth.protect({ \n  role: 'org:admin' \n});\n\n// Custom permissions\nawait auth.protect({ \n  permission: 'org:sys_memberships:manage' \n});\n```\n\n### Organization Hooks\n\n```jsx\nimport { \n  useOrganization, \n  useOrganizationList, \n  useUser \n} from '@clerk/nextjs';\n\nfunction OrganizationComponent() {\n  const { organization } = useOrganization();\n  const { organizationList } = useOrganizationList();\n  \n  // Organization management logic\n}\n```\n\n## Common Patterns\n\n### Conditional Rendering Based on Auth State\n\n```jsx\nimport { useUser } from '@clerk/nextjs';\n\nfunction App() {\n  const { isSignedIn } = useUser();\n  \n  return (\n    <div>\n      {isSignedIn ? (\n        <AuthenticatedApp />\n      ) : (\n        <UnauthenticatedApp />\n      )}\n    </div>\n  );\n}\n```\n\n### Route Protection with Redirects\n\n```jsx\nimport { auth } from '@clerk/nextjs/server';\n\nexport default async function ProtectedPage() {\n  const { userId } = await auth();\n  \n  if (!userId) {\n    redirect('/sign-in');\n  }\n  \n  return <div>Protected content</div>;\n}\n```\n\n## Vanilla JavaScript Integration (`@clerk/clerk-js`)\n\n### Loading Clerk via CDN\n\nThe most common approach for vanilla JavaScript apps is loading Clerk from a CDN:\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n    <title>My App</title>\n</head>\n<body>\n    <!-- Your content here -->\n\n    <!-- Load Clerk SDK -->\n    <script\n        async\n        crossorigin=\"anonymous\"\n        data-clerk-publishable-key=\"pk_test_...\"\n        src=\"https://[your-clerk-domain].clerk.accounts.dev/npm/@clerk/clerk-js@latest/dist/clerk.browser.js\"\n        type=\"text/javascript\"\n    ></script>\n\n    <script src=\"app.js\"></script>\n</body>\n</html>\n```\n\n**Important Implementation Details:**\n- The Clerk SDK loads **asynchronously**, so you must wait for it to be ready\n- Access the Clerk instance via `window.Clerk`\n- Always call `await clerk.load()` before using any Clerk methods\n- Listen for the `clerk:loaded` event as a fallback if the script hasn't loaded yet\n\n### Initializing Clerk Properly\n\n```javascript\n// Wait for page to load\nwindow.addEventListener('load', async () => {\n    if (window.Clerk) {\n        // Clerk is already available\n        await initializeClerk(window.Clerk);\n    } else {\n        // Wait for Clerk to load\n        window.addEventListener('clerk:loaded', async (event) => {\n            await initializeClerk(event.detail);\n        });\n    }\n});\n\nasync function initializeClerk(clerk) {\n    try {\n        // CRITICAL: Always call load() first\n        await clerk.load();\n\n        // Now you can safely use clerk methods\n        const user = clerk.user;\n\n        // Your authentication logic here\n    } catch (error) {\n        console.error('Error initializing Clerk:', error);\n    }\n}\n```\n\n### Accessing User Information\n\nAfter Clerk is loaded, access the current user via `clerk.user`:\n\n```javascript\nasync function initializeClerk(clerk) {\n    await clerk.load();\n\n    const user = clerk.user;\n\n    if (user) {\n        // User is authenticated\n        console.log('User ID:', user.id);\n        console.log('Name:', user.firstName, user.lastName);\n        console.log('Email:', user.primaryEmailAddress?.emailAddress);\n        console.log('Created:', new Date(user.createdAt));\n\n        // Access other user properties\n        console.log('Phone:', user.primaryPhoneNumber?.phoneNumber);\n        console.log('Profile Image:', user.imageUrl);\n    } else {\n        // User is not signed in\n        console.log('No user signed in');\n    }\n}\n```\n\n### Mounting Authentication Components\n\nClerk provides pre-built UI components that can be mounted into your HTML:\n\n```javascript\nasync function initializeClerk(clerk) {\n    await clerk.load();\n\n    if (!clerk.user) {\n        // Mount sign-in component for unauthenticated users\n        clerk.mountSignIn(document.getElementById('sign-in-container'));\n    } else {\n        // Mount user button for authenticated users\n        clerk.mountUserButton(document.getElementById('user-button-container'));\n    }\n}\n```\n\n**Available mount methods:**\n- `clerk.mountSignIn(element)` - Full sign-in flow\n- `clerk.mountSignUp(element)` - Full sign-up flow\n- `clerk.mountUserButton(element)` - User profile dropdown button\n- `clerk.mountUserProfile(element)` - Complete user profile management\n\n### Listening to Authentication State Changes\n\nUse `clerk.addListener()` to react to authentication changes:\n\n```javascript\nasync function initializeClerk(clerk) {\n    await clerk.load();\n\n    // Initial UI update\n    updateUI(clerk.user);\n\n    // Listen for changes\n    clerk.addListener((emission) => {\n        // The emission object contains the changed properties\n        if (emission.user !== undefined) {\n            // User state changed (sign in, sign out, or profile update)\n            updateUI(emission.user);\n        }\n\n        if (emission.session !== undefined) {\n            // Session changed\n            console.log('Session updated:', emission.session);\n        }\n\n        if (emission.organization !== undefined) {\n            // Organization changed\n            console.log('Organization updated:', emission.organization);\n        }\n    });\n}\n\nfunction updateUI(user) {\n    const authenticatedView = document.getElementById('authenticated-view');\n    const unauthenticatedView = document.getElementById('unauthenticated-view');\n\n    if (user) {\n        unauthenticatedView.classList.add('hidden');\n        authenticatedView.classList.remove('hidden');\n    } else {\n        authenticatedView.classList.add('hidden');\n        unauthenticatedView.classList.remove('hidden');\n    }\n}\n```\n\n### Implementing Sign Out\n\n```javascript\nasync function handleSignOut(clerk) {\n    try {\n        await clerk.signOut();\n        // UI will update automatically via listener\n        console.log('Signed out successfully');\n    } catch (error) {\n        console.error('Sign out failed:', error);\n    }\n}\n\n// Usage in your HTML\ndocument.getElementById('sign-out-btn').addEventListener('click', () => {\n    handleSignOut(window.Clerk);\n});\n```\n\n### Complete Vanilla JavaScript Example\n\nHere's a complete working example:\n\n```javascript\n// app.js\nwindow.addEventListener('load', async () => {\n    if (window.Clerk) {\n        await initializeClerk(window.Clerk);\n    } else {\n        window.addEventListener('clerk:loaded', async (event) => {\n            await initializeClerk(event.detail);\n        });\n    }\n});\n\nasync function initializeClerk(clerk) {\n    try {\n        await clerk.load();\n\n        const loadingView = document.getElementById('loading-view');\n        const authenticatedView = document.getElementById('authenticated-view');\n        const unauthenticatedView = document.getElementById('unauthenticated-view');\n        const userInfo = document.getElementById('user-info');\n        const signOutBtn = document.getElementById('sign-out-btn');\n\n        function updateUI() {\n            const user = clerk.user;\n            loadingView.classList.add('hidden');\n\n            if (user) {\n                unauthenticatedView.classList.add('hidden');\n                authenticatedView.classList.remove('hidden');\n\n                userInfo.innerHTML = `\n                    <h3>User Information</h3>\n                    <p><strong>Name:</strong> ${user.firstName || ''} ${user.lastName || ''}</p>\n                    <p><strong>Email:</strong> ${user.primaryEmailAddress?.emailAddress || 'N/A'}</p>\n                    <p><strong>User ID:</strong> ${user.id}</p>\n                    <p><strong>Created:</strong> ${new Date(user.createdAt).toLocaleDateString()}</p>\n                `;\n            } else {\n                authenticatedView.classList.add('hidden');\n                unauthenticatedView.classList.remove('hidden');\n                clerk.mountSignIn(document.getElementById('clerk-sign-in'));\n            }\n        }\n\n        updateUI();\n\n        clerk.addListener((emission) => {\n            if (emission.user !== undefined) {\n                updateUI();\n            }\n        });\n\n        signOutBtn.addEventListener('click', async () => {\n            await clerk.signOut();\n            updateUI();\n        });\n\n        clerk.mountUserButton(document.getElementById('clerk-user-button'));\n\n    } catch (error) {\n        console.error('Error initializing Clerk:', error);\n    }\n}\n```\n\n### Server-Side Key Injection Pattern\n\nFor production apps, inject the publishable key server-side to keep it out of version control:\n\n```javascript\n// server.js (Node.js example)\nconst http = require('http');\nconst fs = require('fs');\nrequire('dotenv').config();\n\nconst server = http.createServer((req, res) => {\n    if (req.url === '/' || req.url === '/index.html') {\n        let html = fs.readFileSync('./index.html', 'utf-8');\n\n        // Replace placeholder with actual key\n        html = html.replace(\n            'CLERK_PUBLISHABLE_KEY_PLACEHOLDER',\n            process.env.CLERK_PUBLISHABLE_KEY\n        );\n\n        res.writeHead(200, { 'Content-Type': 'text/html' });\n        res.end(html);\n    }\n});\n\nserver.listen(3000);\n```\n\n```html\n<!-- index.html -->\n<script\n    data-clerk-publishable-key=\"CLERK_PUBLISHABLE_KEY_PLACEHOLDER\"\n    src=\"https://[your-domain].clerk.accounts.dev/npm/@clerk/clerk-js@latest/dist/clerk.browser.js\"\n></script>\n```\n\n### Getting Authentication Tokens for API Calls\n\n```javascript\nasync function makeAuthenticatedRequest(clerk) {\n    try {\n        // Get the current session token\n        const token = await clerk.session.getToken();\n\n        const response = await fetch('/api/protected-endpoint', {\n            headers: {\n                'Authorization': `Bearer ${token}`,\n                'Content-Type': 'application/json'\n            }\n        });\n\n        const data = await response.json();\n        return data;\n    } catch (error) {\n        console.error('API request failed:', error);\n    }\n}\n```\n\n### Handling Session Lifecycle\n\n```javascript\nasync function initializeClerk(clerk) {\n    await clerk.load();\n\n    // Check if session exists\n    if (clerk.session) {\n        console.log('Active session:', clerk.session.id);\n        console.log('Session expires:', new Date(clerk.session.expireAt));\n\n        // Get session token\n        const token = await clerk.session.getToken();\n        console.log('Session token:', token);\n    }\n\n    // Listen for session changes\n    clerk.addListener((emission) => {\n        if (emission.session !== undefined) {\n            if (emission.session) {\n                console.log('New session created');\n            } else {\n                console.log('Session ended');\n            }\n        }\n    });\n}\n```\n\n## API Endpoints and Backend Integration\n\n### Backend Package\n\nFor backend-only applications, use `@clerk/backend`:\n\n```javascript\nimport { clerkClient } from '@clerk/backend';\n\n// Server-side user management\nconst user = await clerkClient.users.getUser(userId);\n```\n\n### Verifying Tokens on Your Backend\n\n```javascript\n// Node.js/Express example\nconst { verifyToken } = require('@clerk/backend');\n\napp.get('/api/protected', async (req, res) => {\n    try {\n        const token = req.headers.authorization?.replace('Bearer ', '');\n        const claims = await verifyToken(token, {\n            secretKey: process.env.CLERK_SECRET_KEY\n        });\n\n        // Token is valid, proceed with request\n        res.json({ userId: claims.sub });\n    } catch (error) {\n        res.status(401).json({ error: 'Unauthorized' });\n    }\n});\n```\n\n## Common Pitfalls and Best Practices\n\n### Vanilla JavaScript Pitfalls\n\n**Pitfall 1: Not waiting for Clerk to load**\n```javascript\n// WRONG - Clerk may not be loaded yet\nwindow.Clerk.user; // May be undefined\n\n// CORRECT - Wait for load event\nwindow.addEventListener('load', async () => {\n    if (window.Clerk) {\n        await window.Clerk.load();\n        const user = window.Clerk.user; // Now safe to use\n    }\n});\n```\n\n**Pitfall 2: Forgetting to call clerk.load()**\n```javascript\n// WRONG\nasync function initializeClerk(clerk) {\n    const user = clerk.user; // May not be initialized yet\n}\n\n// CORRECT\nasync function initializeClerk(clerk) {\n    await clerk.load(); // CRITICAL - must call first\n    const user = clerk.user;\n}\n```\n\n**Pitfall 3: Not handling both load scenarios**\n```javascript\n// INCOMPLETE - only handles one scenario\nwindow.addEventListener('load', async () => {\n    await initializeClerk(window.Clerk); // What if Clerk isn't loaded yet?\n});\n\n// COMPLETE - handles both scenarios\nwindow.addEventListener('load', async () => {\n    if (window.Clerk) {\n        await initializeClerk(window.Clerk);\n    } else {\n        window.addEventListener('clerk:loaded', async (event) => {\n            await initializeClerk(event.detail);\n        });\n    }\n});\n```\n\n### Framework Best Practices\n\n**Use loading states properly:**\n```javascript\nconst { isLoaded, isSignedIn, user } = useUser();\n\n// Always check isLoaded first\nif (!isLoaded) {\n    return <LoadingSpinner />;\n}\n\nif (!isSignedIn) {\n    return <SignInPrompt />;\n}\n\n// Now safe to use user\nreturn <UserProfile user={user} />;\n```\n\n**Avoid conditional hooks:**\n```javascript\n// WRONG\nif (someCondition) {\n    const { user } = useUser(); // Breaks rules of hooks\n}\n\n// CORRECT\nconst { user } = useUser();\nif (someCondition && user) {\n    // Use user here\n}\n```\n\n### Security Best Practices\n\n1. **Never expose secret keys** - Only use publishable keys in client-side code\n2. **Verify tokens on the backend** - Don't trust client-side authentication alone\n3. **Use HTTPS** - Always serve your app over HTTPS in production\n4. **Implement CORS properly** - Configure allowed origins in Clerk Dashboard\n5. **Handle token expiration** - Sessions expire and need refresh\n\n### Performance Optimization\n\n**For Next.js:**\n- Use `auth()` instead of `currentUser()` when you only need the user ID\n- `currentUser()` makes an API call while `auth()` reads from the request\n- Implement proper caching strategies for user data\n\n**For Vanilla JS:**\n- Load Clerk SDK asynchronously (use `async` attribute)\n- Cache user data in memory to avoid repeated property access\n- Use event listeners instead of polling for auth state changes\n\n## Important Notes\n\n### Framework-Specific Notes\n\n- **Next.js Middleware Requirement:** `clerkMiddleware()` is required for server-side authentication helpers in Next.js App Router\n- **Server-Only Functions:** Functions like `auth()` and `currentUser()` only work on the server side\n- **Rate Limits:** Server-side user fetching counts towards Backend API rate limits\n- **Deprecated APIs:** Do not use `authMiddleware` - use `clerkMiddleware` instead\n\n### Vanilla JavaScript Notes\n\n- **Asynchronous Loading:** The Clerk SDK loads asynchronously - always wait for it to be ready\n- **Critical Load Step:** Always call `await clerk.load()` before accessing user/session data\n- **Event-Driven Updates:** Use `clerk.addListener()` for reactive UI updates\n- **Session Tokens:** Access tokens via `clerk.session.getToken()` for API authentication\n- **Component Mounting:** Use mount methods (`mountSignIn`, etc.) for pre-built UI components \n\n## Useful Links\n\n- **Documentation:** https://clerk.com/docs \n- **Quickstart Guides:** https://clerk.com/docs/quickstarts/overview \n- **Discord Community:** https://clerk.com/discord \n- **GitHub Repository:** https://github.com/clerk/javascript \n\n## Quick Reference: Choosing Your Implementation\n\n### Use Vanilla JavaScript (`@clerk/clerk-js`) when:\n- Building standalone HTML/JS applications\n- Working without a framework\n- Need simple drop-in authentication\n- Want to use CDN-hosted SDK\n- Building static sites with authentication\n\n**Key Pattern:**\n```javascript\nwindow.addEventListener('load', async () => {\n    if (window.Clerk) {\n        await window.Clerk.load();\n        // Use window.Clerk.user\n    }\n});\n```\n\n### Use Next.js SDK (`@clerk/nextjs`) when:\n- Building Next.js applications (App Router or Pages Router)\n- Need server-side authentication\n- Want middleware-based route protection\n- Building full-stack applications with Next.js\n\n**Key Pattern:**\n```javascript\n// Client: useUser(), useAuth(), useClerk()\n// Server: auth(), currentUser()\n// Middleware: clerkMiddleware()\n```\n\n### Use React SDK (`@clerk/react`) when:\n- Building React applications (not Next.js)\n- Using Create React App or Vite\n- Need client-side authentication hooks\n- Working with React Router\n\n**Key Pattern:**\n```javascript\nimport { ClerkProvider, useUser } from '@clerk/react';\n```\n\n### Use Backend SDK (`@clerk/backend`) when:\n- Building backend-only APIs\n- Need to verify tokens server-side\n- Managing users from your backend\n- Integrating with Express, Fastify, etc.\n\n**Key Pattern:**\n```javascript\nimport { clerkClient, verifyToken } from '@clerk/backend';\n```\n\n## Summary\n\nThis guide covers the core Clerk JavaScript SDK patterns across multiple implementation approaches:\n\n### Key Concepts\n- **Clerk is framework-agnostic** - Choose the right package for your stack\n- **Publishable keys are safe for client-side** - Secret keys are for backend only\n- **Authentication is session-based** - Clerk manages sessions automatically\n- **Pre-built components** - Drop-in UI for authentication flows\n- **Event-driven updates** - React to auth state changes in real-time\n\n### Critical Implementation Details\n\n**For Vanilla JavaScript:**\n1. Always wait for Clerk to load (`window.Clerk` + `clerk:loaded` event)\n2. Call `await clerk.load()` before accessing user/session data\n3. Use `clerk.addListener()` for reactive UI updates\n4. Mount components with `clerk.mountSignIn()`, `clerk.mountUserButton()`, etc.\n\n**For Next.js:**\n1. Wrap app with `<ClerkProvider>`\n2. Use `clerkMiddleware()` for route protection\n3. Use hooks (`useUser()`, `useAuth()`) in client components\n4. Use `auth()` and `currentUser()` in server components\n\n**For Backend:**\n1. Verify tokens with `verifyToken()` or middleware\n2. Use `clerkClient` for user management operations\n3. Never expose secret keys to the client\n\n### Authentication Flow\n1. User visits your app\n2. Clerk SDK initializes and checks for existing session\n3. If no session, show sign-in UI\n4. User authenticates (email, OAuth, etc.)\n5. Clerk creates session and returns user object\n6. Your app reacts to auth state and shows user content\n7. Session tokens can be used for API authentication\n\nClerk handles the complexity of authentication, session management, and user profiles, allowing you to focus on building your application.\n\n## Common Use Cases & Patterns\n\n### Protected Routes (Vanilla JS)\n```javascript\nasync function initializeClerk(clerk) {\n    await clerk.load();\n\n    // Protect specific pages\n    const protectedPaths = ['/dashboard', '/profile', '/settings'];\n    const currentPath = window.location.pathname;\n\n    if (protectedPaths.includes(currentPath) && !clerk.user) {\n        // Redirect to sign-in\n        window.location.href = '/sign-in';\n    }\n}\n```\n\n### Protected Routes (Next.js Middleware)\n```javascript\nimport { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';\n\nconst isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);\n\nexport default clerkMiddleware(async (auth, req) => {\n    if (isProtectedRoute(req)) {\n        await auth.protect(); // Redirects if not authenticated\n    }\n});\n```\n\n### Displaying User-Specific Content\n```javascript\n// Vanilla JS\nif (clerk.user) {\n    document.getElementById('welcome').textContent =\n        `Welcome back, ${clerk.user.firstName}!`;\n}\n\n// Next.js/React\nconst { user } = useUser();\nreturn user ? <div>Welcome back, {user.firstName}!</div> : null;\n```\n\n### Making Authenticated API Requests\n```javascript\n// Vanilla JS\nconst token = await clerk.session.getToken();\nconst response = await fetch('/api/data', {\n    headers: { 'Authorization': `Bearer ${token}` }\n});\n\n// Next.js/React\nconst { getToken } = useAuth();\nconst token = await getToken();\nconst response = await fetch('/api/data', {\n    headers: { 'Authorization': `Bearer ${token}` }\n});\n```\n\n### Handling OAuth Sign-In\n```javascript\n// Clerk handles OAuth automatically through its UI components\n// Just mount the sign-in component and it includes OAuth buttons\n\n// Vanilla JS\nclerk.mountSignIn(document.getElementById('sign-in'));\n\n// Next.js/React\n<SignIn />\n```\n\n### Custom OAuth Redirect URLs\n```jsx\n<SignInButton\n    mode='modal'\n    forceRedirectUrl='/dashboard'\n    signUpForceRedirectUrl='/onboarding'\n>\n    Sign in\n</SignInButton>\n```\n\n## Troubleshooting Common Issues\n\n### Issue: \"Clerk is not defined\"\n**Cause:** Clerk SDK hasn't loaded yet\n**Solution:** Use the proper loading pattern with both `window.Clerk` check and `clerk:loaded` event\n\n### Issue: \"User is null after sign-in\"\n**Cause:** Forgot to call `clerk.load()` or checking too early\n**Solution:** Always call `await clerk.load()` and use event listeners for updates\n\n### Issue: \"Cannot read property 'user' of undefined\"\n**Cause:** Accessing Clerk before initialization\n**Solution:** Wrap all Clerk usage in the initialization function after `load()` completes\n\n### Issue: \"CORS errors when calling Clerk API\"\n**Cause:** Domain not configured in Clerk Dashboard\n**Solution:** Add your domain to allowed origins in Clerk Dashboard settings\n\n### Issue: \"Session token expired\"\n**Cause:** Sessions expire after period of inactivity\n**Solution:** Clerk automatically refreshes tokens; ensure you call `getToken()` fresh each time\n\n### Issue: \"Middleware not protecting routes\"\n**Cause:** Incorrect middleware configuration or matcher pattern\n**Solution:** Verify `clerkMiddleware` is exported as default and matcher patterns are correct\n\n### Issue: \"Can't access user data in Server Component\"\n**Cause:** Using client-side hooks on the server\n**Solution:** Use `auth()` or `currentUser()` instead of `useUser()` in Server Components\n\n### Debugging Tips\n\n1. **Check Clerk Dashboard:** Verify your API keys are correct\n2. **Console logging:** Add `console.log('Clerk loaded:', clerk)` after `load()`\n3. **Network tab:** Check for failed requests to Clerk API\n4. **Browser console:** Look for Clerk SDK errors or warnings\n5. **Version compatibility:** Ensure your Clerk package versions are up to date\n\n## Prerequisites\n\n- Next.js 13.0.4 or later\n- React 18 or later\n- Node.js `>=18.17.0` or later\n- An existing Clerk application. [Create your account for free](https://dashboard.clerk.com/sign-up?utm_source=github&utm_medium=clerk_nextjs).\n\n## Getting Started\n\n### Next.js Installation\n\nThe fastest way to get started with Clerk is by following the [Next.js Quickstart](https://clerk.com/docs/quickstarts/nextjs?utm_source=github&utm_medium=clerk_nextjs).\n\nYou'll learn how to install `@clerk/nextjs`, set up your environment keys, add `<ClerkProvider>` to your application, use the Clerk middleware, and use Clerk's prebuilt components.\n\n### JavaScript Installation\n\nThe fastest way to get started with Clerk is by following the [JavaScript Quickstart](https://clerk.com/docs/quickstarts/javascript?utm_source=github&utm_medium=clerk_js).\n\nYou'll learn how to add the ClerkJS SDK to your application (either through `<script>` tag or NPM module) and use Clerk's prebuilt components.\n\n## Community\n\n- Join our official community [Discord server](https://clerk.com/discord)\n\n## Advanced Middleware Configuration\n\n```typescript\nexport default clerkMiddleware(async (auth, req) => {\n  if (isProtectedRoute(req)) {\n    await auth.protect();\n  }\n\n  if (isAdminRoute(req)) {\n    await auth.protect({ role: 'org:admin' });\n  }\n\n  if (isCSPRoute(req)) {\n    req.headers.set('Content-Security-Policy', csp.replace(/\\n/g, ''));\n  }\n});\n```\n\n```typescript\nexport const config = {\n  matcher: [\n    '/((?!.*\\\\..*|_next).*)', // Don't run middleware on static files\n    '/', // Run middleware on index page\n    '/(api|trpc)(.*)',\n  ], // Run middleware on API routes\n};\n```\n\n## Example Components\n\n```typescript\nfunction GreetingWithHook() {\n  // Use the useUser hook to get the Clerk.user object\n  // This hook causes a re-render on user changes\n  const { isLoaded, isSignedIn, user } = useUser();\n\n  if (!isLoaded || !isSignedIn) {\n    // You can handle the loading or signed state separately\n    return null;\n  }\n\n  return <div>Hello, {user.firstName}!</div>;\n}\n```\n\n## Authentication Protection Details\n\n`auth` includes a single property, the `protect()` method, which you can use in two ways:\n- to check if a user is authenticated (signed in)\n- to check if a user is authorized (has the correct roles or permissions) to access something, such as a component or a route handler\n\nThe following table describes how auth.protect() behaves based on user authentication or authorization status:\n\n| Authenticated | Authorized | `auth.protect()` will |\n| - | - | - |\n| Yes | Yes | Return the [`Auth`](https://clerk.com/docs/references/backend/types/auth-object) object. |\n| Yes | No | Return a `404` error. |\n| No | No | Redirect the user to the sign-in page*. |\n\n> [!IMPORTANT]\n> *For non-document requests, such as API requests, `auth.protect()` returns a `404` error to users who aren't authenticated.\n\n`auth.protect()` can be used to check if a user is authenticated or authorized to access certain parts of your application or even entire routes. See detailed examples in the [dedicated guide](https://clerk.com/docs/organizations/verify-user-permissions).\n\n## auth() Helper Details\n\nThe `auth()` helper returns the [`Auth`](https://clerk.com/docs/references/backend/types/auth-object) object of the currently active user, as well as the [`redirectToSignIn()`](https://clerk.com/docs/references/nextjs/auth#redirect-to-sign-in) method.\n\n- Only available for App Router.\n- Only works on the server-side, such as in Server Components, Route Handlers, and Server Actions.\n- Requires [`clerkMiddleware()`](https://clerk.com/docs/references/nextjs/clerk-middleware) to be configured.\n\n## currentUser() Details\n\n- calls `fetch()`, so it is automatically deduped per request.\n- uses the [`GET /v1/users/{user_id}`](https://clerk.com/docs/reference/backend-api/tag/Users#operation/GetUser) endpoint.\n- counts towards the [Backend API request rate limit](https://clerk.com/docs/backend-requests/resources/rate-limits).\n\n**Example:**\n```tsx\n// app/page.tsx\nimport { currentUser } from '@clerk/nextjs/server'\n\nexport default async function Page() {\n  const user = await currentUser()\n\n  if (!user) return <div>Not signed in</div>\n\n  return <div>Hello {user?.firstName}</div>\n}\n```\n\n## Advanced SignIn Button Examples\n\n```tsx\n<SignInButton\n  mode='modal'\n  forceRedirectUrl='/protected'\n  signUpForceRedirectUrl='/protected'\n>\n  Sign in button (force)\n</SignInButton>\n\n<SignInButton\n  mode='modal'\n  oauthFlow='popup'\n  forceRedirectUrl='/protected'\n  signUpForceRedirectUrl='/protected'\n>\n  Sign in button (force, popup)\n</SignInButton>\n```\n\n## Type Definitions\n\n```typescript\nimport type { OrganizationResource } from './organization';\nimport type { ClerkResource } from './resource';\nimport type { PublicUserData } from './session';\nimport type { OrganizationMembershipJSONSnapshot } from './snapshots';\nimport type { Autocomplete } from './utils';\n\ninterface Base {\n  permission: string;\n  role: string;\n}\n```\n\n## About Clerk\n\nClerk helps developers build user management. We provide streamlined user experiences for your users to sign up, sign in, and manage their profile.\n\nThis repository contains all the Clerk JavaScript SDKs under the `@clerk` namespace.\n\n## Documentation\n\nClerk's full documentation is available at [clerk.com/docs](https://clerk.com/docs?utm_source=github&utm_medium=clerk_js_repo_readme).\n\n- **We recommend starting with the [quickstart guides](https://clerk.com/docs/quickstarts/overview?utm_source=github&utm_medium=clerk_js_repo_readme).** They'll help you quickly add Clerk to your application. If you're starting a new project and aren't sure what to pick, check out our most popular quickstart: [Next.js](https://clerk.com/docs/quickstarts/nextjs?utm_source=github&utm_medium=clerk_js_repo_readme).\n\n"
  },
  {
    "path": "content/clerk/docs/auth/python/DOC.md",
    "content": "---\nname: auth\ndescription: \"Clerk Backend API Python SDK for server-side authentication and user management operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.1\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"clerk,auth,authentication,user-management,backend\"\n---\n\n# Clerk Backend API Python SDK Coding Guidelines\n\nYou are a Clerk Backend API Python SDK expert. Help me with writing code using the Clerk Backend API Python SDK for authentication and user management operations.\n\nPlease follow the following guidelines when generating code.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Clerk Backend API Python SDK, which is automatically generated from the Clerk Backend API OpenAPI specification using Speakeasy. \n\n- **Library Name:** Clerk Backend API Python SDK\n- **Python Package:** `clerk-backend-api`\n- **Main Class:** `Clerk` \n\n**Installation:**\n\n```bash\npip install clerk-backend-api\n```\n\n**Basic Import:**\n\n```python\nfrom clerk_backend_api import Clerk\n```\n\n## Initialization and API Key\n\nThe Clerk SDK requires a secret key for authentication. Always initialize the client with your Clerk secret key:\n\n```python\nfrom clerk_backend_api import Clerk\n\n# Initialize with secret key\nclerk = Clerk(bearer_auth=\"sk_test_your_secret_key_here\")\n```\n\nSet your `CLERK_SECRET_KEY` environment variable for production use.\n\n## Core SDK Structure\n\nThe SDK is organized into logical modules for different Clerk resources: \n\n- **Users:** User management operations\n- **Organizations:** Organization and membership management  \n- **Sessions:** Session management and verification\n- **Email Addresses:** Email address operations\n- **Phone Numbers:** Phone number operations\n- **Invitations:** Organization invitations\n- **JWT Templates:** Custom JWT configuration\n- **OAuth Applications:** OAuth app management\n- **Webhooks:** Webhook management\n\n## Basic User Operations\n\n### Create a User\n\n```python\nfrom clerk_backend_api import Clerk\n\nclerk = Clerk(bearer_auth=\"sk_test_your_secret_key_here\")\n\n# Create a new user\nresponse = clerk.users.create_user(\n    request_body={\n        \"email_address\": [\"user@example.com\"],\n        \"password\": \"secure_password123\",\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\"\n    }\n)\n\nuser = response.object\nprint(f\"Created user: {user.id}\")\n```\n\n### Get a User\n\n```python\n# Get user by ID\nresponse = clerk.users.get_user(user_id=\"user_123456789\")\nuser = response.object\nprint(f\"User email: {user.email_addresses[0].email_address}\")\n```\n\n### List Users\n\n```python\n# List all users with pagination\nresponse = clerk.users.get_user_list(\n    limit=10,\n    offset=0,\n    order_by=\"-created_at\"\n)\n\nfor user in response.object:\n    print(f\"User: {user.id} - {user.first_name} {user.last_name}\")\n```\n\n### Update a User\n\n```python\n# Update user information\nresponse = clerk.users.update_user(\n    user_id=\"user_123456789\",\n    request_body={\n        \"first_name\": \"Jane\",\n        \"last_name\": \"Smith\"\n    }\n)\n```\n\n## Session Management\n\n### Verify a Session\n\n```python\n# Verify a session token\nresponse = clerk.sessions.verify_session(\n    session_id=\"sess_123456789\",\n    request_body={\n        \"token\": \"session_token_here\"\n    }\n)\n\nsession = response.object\nprint(f\"Session status: {session.status}\")\n```\n\n### Get Session List\n\n```python\n# Get all sessions for a client\nresponse = clerk.sessions.get_session_list(\n    client_id=\"client_123456789\",\n    user_id=\"user_123456789\"\n)\n```\n\n## Organization Management\n\n### Create an Organization\n\n```python\n# Create a new organization\nresponse = clerk.organizations.create_organization(\n    request_body={\n        \"name\": \"Acme Corp\",\n        \"slug\": \"acme-corp\",\n        \"created_by\": \"user_123456789\"\n    }\n)\n\norg = response.object\nprint(f\"Created organization: {org.id}\")\n```\n\n### Add Organization Member\n\n```python\n# Add a user to an organization\nresponse = clerk.organization_memberships.create_organization_membership(\n    organization_id=\"org_123456789\",\n    request_body={\n        \"user_id\": \"user_123456789\",\n        \"role\": \"basic_member\"\n    }\n)\n```\n\n## Email and Phone Number Management\n\n### Add Email Address\n\n```python\n# Add email address to user\nresponse = clerk.email_addresses.create_email_address(\n    request_body={\n        \"user_id\": \"user_123456789\",\n        \"email_address\": \"new@example.com\",\n        \"verified\": False,\n        \"primary\": False\n    }\n)\n```\n\n### Add Phone Number\n\n```python\n# Add phone number to user\nresponse = clerk.phone_numbers.create_phone_number(\n    request_body={\n        \"user_id\": \"user_123456789\",\n        \"phone_number\": \"+1234567890\",\n        \"verified\": False,\n        \"primary\": False\n    }\n)\n```\n\n## JWT Templates\n\n### Create JWT Template\n\n```python\n# Create custom JWT template\nresponse = clerk.jwt_templates.create_jwt_template(\n    request_body={\n        \"name\": \"custom_template\",\n        \"claims\": {\n            \"custom_claim\": \"{{user.id}}\"\n        },\n        \"lifetime\": 3600,\n        \"allowed_clock_skew\": 5\n    }\n)\n```\n\n## Webhook Management\n\n### Create Webhook Endpoint\n\n```python\n# Create webhook endpoint\nresponse = clerk.webhooks.create_webhook(\n    request_body={\n        \"url\": \"https://your-app.com/webhooks/clerk\",\n        \"events\": [\"user.created\", \"user.updated\", \"session.created\"]\n    }\n)\n```\n\n## Error Handling\n\nThe SDK uses structured error responses. Always handle potential errors:\n\n```python\nfrom clerk_backend_api import Clerk\nfrom clerk_backend_api.models import ClerkErrors\n\nclerk = Clerk(bearer_auth=\"sk_test_your_secret_key_here\")\n\ntry:\n    response = clerk.users.get_user(user_id=\"invalid_user_id\")\n    user = response.object\nexcept Exception as e:\n    if hasattr(e, 'errors'):\n        for error in e.errors:\n            print(f\"Error: {error.message} (Code: {error.code})\")\n    else:\n        print(f\"Unexpected error: {e}\")\n```\n\n## Dependencies and Requirements\n\nThe SDK includes the following key dependencies: \n\n- `cryptography ^43.0.1` - For cryptographic operations\n- `pyjwt ^2.9.0` - For JWT token handling\n\n## SDK Configuration\n\nThe SDK is automatically generated and maintained using Speakeasy configuration. The current version is `2.0.2` and includes comprehensive type hints and documentation.\n"
  },
  {
    "path": "content/click/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Click package guide for Python CLI applications and command groups\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.3.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"click,python,cli,command-line,pallets\"\n---\n\n# Click Python Package Guide\n\n## Golden Rule\n\n**Build Click CLIs as installable packages with entry points, not as ad hoc `python script.py` commands.**\n\nClick's own docs recommend packaging commands with `pyproject.toml` entry points so installers create the executable correctly across Linux, macOS, and Windows.\n\n## Installation\n\n```bash\npip install click==8.3.1\n```\n\nFor a new project, prefer declaring it in `pyproject.toml`:\n\n```toml\n[project]\nname = \"my-cli\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = [\n  \"click==8.3.1\",\n]\n\n[project.scripts]\nmy-cli = \"my_cli.main:cli\"\n```\n\n## Minimal Setup\n\n`src/my_cli/main.py`\n\n```python\nimport click\n\n@click.command()\n@click.argument(\"name\")\n@click.option(\"--count\", default=1, show_default=True, type=int)\ndef cli(name: str, count: int) -> None:\n    for _ in range(count):\n        click.echo(f\"Hello, {name}!\")\n\nif __name__ == \"__main__\":\n    cli()\n```\n\nDevelopment install:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install -e .\nmy-cli World --count 2\n```\n\nUse `click.echo()` instead of `print()` when you want Click's terminal handling, Unicode robustness, and automatic stripping of ANSI styles when output is redirected.\n\n## Core Usage Patterns\n\n### Commands and groups\n\nUse `@click.command()` for a single command and `@click.group()` when you need subcommands.\n\n```python\nimport click\n\n@click.group()\n@click.option(\"--debug/--no-debug\", default=False)\n@click.pass_context\ndef cli(ctx: click.Context, debug: bool) -> None:\n    ctx.ensure_object(dict)\n    ctx.obj[\"debug\"] = debug\n\n@cli.command()\n@click.argument(\"path\")\n@click.pass_context\ndef sync(ctx: click.Context, path: str) -> None:\n    if ctx.obj[\"debug\"]:\n        click.echo(f\"debug: syncing {path}\")\n    click.echo(f\"synced {path}\")\n```\n\nUseful group behaviors:\n\n- Group options belong to the group, not to child commands. Write `tool --debug sync`, not `tool sync --debug`.\n- `invoke_without_command=True` lets the group callback run even when no subcommand is chosen.\n- Split large CLIs across modules and register subcommands later with `group.add_command(...)`.\n\n### Options and arguments\n\nCommon decorators:\n\n- `@click.argument(\"name\")` for positional input.\n- `@click.option(\"--count\", default=1, type=int)` for named options.\n- `@click.option(\"--flag/--no-flag\", default=False)` for explicit boolean toggles.\n- `multiple=True` returns a tuple. Do not use a string default there; it will be treated as a list of characters.\n\nIf you use `flag_value`, prefer an explicit default value instead of `default=True` so the callback receives the exact value you expect.\n\n### Config and secrets\n\nClick does not have its own auth layer. For CLIs that call APIs or read local config, model configuration through options, environment variables, prompts, and context state.\n\nPer-option environment variables:\n\n```python\nimport click\n\n@click.command()\n@click.option(\"--token\", envvar=\"APP_TOKEN\", hide_input=True)\ndef cli(token: str) -> None:\n    click.echo(\"token loaded\")\n```\n\nAutomatic env var prefixes for all options:\n\n```python\n@click.group(context_settings={\"auto_envvar_prefix\": \"APP\"})\n@click.option(\"--region\")\ndef cli(region: str) -> None:\n    ...\n```\n\nWith subcommands, Click expands the name, so an option like `--host` on subcommand `run-server` becomes `APP_RUN_SERVER_HOST`.\n\n### Prompts\n\nUse prompts when a value can come from the CLI but should fall back to interactive input:\n\n```python\n@click.command()\n@click.option(\"--username\", prompt=True)\ndef cli(username: str) -> None:\n    click.echo(f\"hello {username}\")\n```\n\nUseful prompt helpers:\n\n- `prompt=True` or `prompt=\"Custom label\"` on options.\n- `click.prompt(\"Value\", type=int)` for manual prompting.\n- `click.confirm(\"Continue?\", abort=True)` for destructive actions.\n\nAvoid combining `prompt` with `multiple=True`; the docs recommend prompting manually inside the function instead.\n\n### Shared state and complex CLIs\n\nFor multi-command apps, store application state on `ctx.obj` and pass it down with `@click.pass_context` or `@click.pass_obj`. This is the standard pattern for carrying config, clients, or loaded project state through nested commands.\n\nIf startup is expensive, a custom `click.Group` can lazy-load subcommands. That keeps import cost lower, but the docs recommend backing it with tests because help rendering and shell completion can still trigger loads.\n\n### Testing\n\nUse `click.testing.CliRunner` for command tests:\n\n```python\nfrom click.testing import CliRunner\n\nfrom my_cli.main import cli\n\ndef test_hello() -> None:\n    runner = CliRunner()\n    result = runner.invoke(cli, [\"World\"])\n    assert result.exit_code == 0\n    assert \"Hello, World!\" in result.output\n```\n\n`CliRunner` is for tests only. Click's docs explicitly warn that it mutates interpreter state and is not thread-safe.\n\n### Errors and exit codes\n\nIf your code raises `click.ClickException`, Click formats the message and exits with the exception's exit code. `click.confirm(..., abort=True)` and Ctrl-C style abort flows exit with code `1`. Successful runs exit with `0`.\n\n## Shell Completion\n\nShell completion works best when the command is installed through an entry point. The docs are explicit that completion is not available when users invoke the program through `python some_script.py`.\n\nIf you need custom completion for a parameter type, implement `shell_complete()` on a custom `click.ParamType`.\n\n## Common Pitfalls\n\n- Package your CLI with `project.scripts`. This is the path Click documents for Windows wrappers, virtualenv-friendly executables, and shell completion.\n- Use `click.echo()` for user-facing output unless you intentionally want raw `print()`.\n- Group-level flags must appear before the subcommand name.\n- `click.get_current_context()` only works in the current thread; if you pass context into another thread, treat it as read-only.\n- `CliRunner` is not safe for production code or concurrent runtime use.\n- For `multiple=True`, defaults must be a list or tuple, not a string.\n- For env-driven boolean flags, only the configured `envvar` is recognized. A paired option like `--flag/--no-flag` does not create a separate `NO_FLAG` environment variable automatically.\n\n## Version-Sensitive Notes For 8.3.1\n\n- `8.3.1` is the current PyPI release as of 2026-03-11, and the stable docs track the `8.3.x` line.\n- Click `8.2.0` dropped Python `3.7`, `3.8`, and `3.9`. If you support older interpreters, you need an older Click line.\n- Click `8.2.0` deprecated `click.__version__`; use `importlib.metadata.version(\"click\")` or feature detection instead.\n- Click `8.2.0` deprecated the old parser internals (`click.parser`, `OptionParser`, related parser hooks). Avoid new code that depends on them.\n- Click `8.3.0` changed flag handling so `default` is preserved as-is. If your CLI depends on `flag_value` behavior, test boolean and enum-like flags explicitly when upgrading from `8.1.x` or early `8.2.x`.\n- Click `8.3.1` is a follow-up patch release for the `8.3.0` line. Re-test prompt flows, flag defaults, and callback-default behavior if you are upgrading from `8.1.x` or `8.2.x`.\n\n## Official Sources\n\n- Docs: https://click.palletsprojects.com/en/stable/\n- Quickstart: https://click.palletsprojects.com/en/stable/quickstart/\n- Packaging entry points: https://click.palletsprojects.com/en/stable/entry-points/\n- Commands and context: https://click.palletsprojects.com/en/stable/commands-and-groups/\n- Options: https://click.palletsprojects.com/en/stable/options/\n- Prompts: https://click.palletsprojects.com/en/stable/prompts/\n- Testing: https://click.palletsprojects.com/en/stable/testing/\n- Exceptions and exit codes: https://click.palletsprojects.com/en/stable/exceptions/\n- Shell completion: https://click.palletsprojects.com/en/stable/shell-completion/\n- Changelog: https://click.palletsprojects.com/en/stable/changes/\n- PyPI: https://pypi.org/project/click/\n"
  },
  {
    "path": "content/click-plugins/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"click-plugins guide for Click CLIs that load subcommands from Python package entry points\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.1.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"click,plugins,cli,entry-points,setuptools,python\"\n---\n\n# click-plugins Python Package Guide\n\n## Golden Rule\n\nUse `click-plugins` only to attach external `click` commands or groups that are published as Python entry points. The published PyPI package is `click-plugins==1.1.1.2`, and the PyPI project description marks it as inactive and points readers to the maintainer repository for vendoring guidance.\n\nThere is no client object, network setup, or authentication step. The core workflow is:\n\n1. Define a Click group in the host application.\n2. Decorate that group with `with_plugins(...)`.\n3. Publish plugin commands under a shared entry point group.\n4. Install the host app and the plugin distributions into the same Python environment.\n\n## Install\n\nIf you are using the published package, install `click-plugins`, `click`, and `setuptools` in the environment that runs the CLI:\n\n```bash\npython -m pip install \"click-plugins==1.1.1.2\" \"click>=8\" setuptools\n```\n\nCommon project managers:\n\n```bash\nuv add \"click-plugins==1.1.1.2\" \"click>=8\" setuptools\npoetry add \"click-plugins==1.1.1.2\" \"click>=8\" setuptools\n```\n\nEnvironment variables:\n\n- None required by `click-plugins` itself.\n\n## Host CLI Setup\n\nThe published PyPI docs show the conservative pattern: pass `pkg_resources.iter_entry_points(...)` into `with_plugins(...)`.\n\n```python\n# myapp/cli.py\nfrom pkg_resources import iter_entry_points\n\nimport click\nfrom click_plugins import with_plugins\n\nPLUGIN_GROUP = \"myapp.cli_plugins\"\n\n\n@with_plugins(iter_entry_points(PLUGIN_GROUP))\n@click.group()\n@click.option(\"--verbose\", is_flag=True, help=\"Enable verbose output.\")\n@click.pass_context\ndef cli(ctx: click.Context, verbose: bool) -> None:\n    ctx.ensure_object(dict)\n    ctx.obj[\"verbose\"] = verbose\n\n\n@cli.command()\ndef version() -> None:\n    click.echo(\"myapp 0.1.0\")\n```\n\nIf you want a runnable command, expose the group as a console script in your host package metadata:\n\n```toml\n# pyproject.toml\n[project]\nname = \"myapp\"\nversion = \"0.1.0\"\ndependencies = [\n  \"click>=8\",\n  \"click-plugins==1.1.1.2\",\n  \"setuptools\",\n]\n\n[project.scripts]\nmyapp = \"myapp.cli:cli\"\n```\n\nAfter the host package is installed, `myapp --help` will include any discovered plugin commands from the `myapp.cli_plugins` entry point group.\n\n## Plugin Package Setup\n\nPlugin packages register commands in package metadata. Current Python packaging guidance uses `[project.entry-points.\"...\"]` in `pyproject.toml`.\n\n```toml\n# pyproject.toml\n[project]\nname = \"myapp-hello-plugin\"\nversion = \"0.1.0\"\ndependencies = [\n  \"click>=8\",\n  \"myapp\",\n]\n\n[project.entry-points.\"myapp.cli_plugins\"]\nhello = \"myapp_hello_plugin.cli:hello\"\n```\n\nThe plugin command itself is ordinary Click code:\n\n```python\n# myapp_hello_plugin/cli.py\nimport click\n\n\n@click.command()\n@click.pass_context\ndef hello(ctx: click.Context) -> None:\n    verbose = bool(ctx.obj and ctx.obj.get(\"verbose\"))\n\n    if verbose:\n        click.echo(\"Running hello plugin in verbose mode\")\n\n    click.echo(\"Hello from plugin\")\n```\n\nInstall the plugin into the same environment as the host CLI:\n\n```bash\npython -m pip install -e /path/to/myapp\npython -m pip install -e /path/to/myapp-hello-plugin\nmyapp --help\nmyapp hello\n```\n\n## Common Workflows\n\n### Share options and state from the host CLI\n\nThe project docs recommend defining common options once in the host package so plugins can import and reuse them. Plugins also have access to the parent command's `ctx.obj`, which is the simplest place to pass config, verbosity flags, or handles created by the host command.\n\nReusable host option:\n\n```python\n# myapp/options.py\nimport click\n\njobs_opt = click.option(\n    \"-j\",\n    \"--jobs\",\n    type=click.IntRange(min=1),\n    default=1,\n    show_default=True,\n    help=\"Number of worker processes.\",\n)\n```\n\nPlugin reusing the option:\n\n```python\n# myapp_hello_plugin/cli.py\nimport click\nfrom myapp.options import jobs_opt\n\n\n@click.command()\n@jobs_opt\ndef hello(jobs: int) -> None:\n    click.echo(f\"Running with {jobs} worker(s)\")\n```\n\n### Handle broken plugins without crashing the whole CLI\n\nIf a plugin entry point exists but cannot be imported or loaded, `click-plugins` converts it into a placeholder command instead of crashing the entire CLI. The help text warns that the plugin could not be loaded, and invoking that command prints the traceback.\n\nThis means:\n\n- `myapp --help` can still work even when one plugin is broken.\n- Users can inspect the failing plugin by running its command with `--help` or invoking it directly.\n\n## Version-Sensitive Notes\n\n- PyPI lists `click-plugins 1.1.1.2` as the latest published package, released on June 25, 2025.\n- The PyPI project description explicitly says the package is no longer actively maintained and that the underlying library can be vendored from the maintainer repository.\n- The current maintainer source also documents a newer `importlib.metadata`-based path where `with_plugins(...)` can resolve a group name directly. If you are pinned to the published PyPI package, use the iterator-based pattern shown above because that is the behavior documented on PyPI.\n\n## Pitfalls\n\n- Entry points are discovered from installed distributions, not from Python files sitting in your source tree. If the plugin package is not installed into the active environment, the host CLI will not see it.\n- Keep the decorator order from the published examples: apply `@with_plugins(...)` above `@click.group()`.\n- The entry point group string must match on both sides. If the host uses `myapp.cli_plugins`, every plugin package must publish commands under exactly that group.\n- Keep command names stable. The entry point name and the Click command name should not disagree unless you have a reason to present different names.\n- If you use the published PyPI pattern with `pkg_resources.iter_entry_points(...)`, `setuptools` must be importable at runtime.\n- Prefer `pyproject.toml` entry point declarations for new packages even though many older examples use `setup.py`. They publish the same package metadata.\n\n## Official Sources\n\n- PyPI project: https://pypi.org/project/click-plugins/\n- Maintainer docs and examples: https://github.com/click-contrib/click-plugins/blob/main/click_plugins.rst\n- Maintainer source implementation: https://github.com/click-contrib/click-plugins/blob/main/click_plugins.py\n- Python Packaging User Guide entry point examples: https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/\n- `importlib.metadata` entry points reference: https://docs.python.org/3/library/importlib.metadata.html\n"
  },
  {
    "path": "content/clickhouse-connect/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"clickhouse-connect Python package guide for connecting to ClickHouse over HTTP/HTTPS and working with query, insert, pandas, Arrow, Polars, and async APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"clickhouse,python,database,analytics,http,pandas,pyarrow,polars,sqlalchemy\"\n---\n\n# clickhouse-connect Python Package Guide\n\n## Golden Rule\n\nUse `clickhouse-connect` for Python projects that talk to ClickHouse over the HTTP/HTTPS interface. This is the ClickHouse-maintained client, and the upstream docs and repo both treat it as the primary Python driver.\n\nDo not assume it speaks the native TCP protocol. `clickhouse-connect` is HTTP-based, so the usual defaults are port `8123` for HTTP and `8443` for HTTPS.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"clickhouse-connect==0.14.0\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"clickhouse-connect[pandas]==0.14.0\"\npython -m pip install \"clickhouse-connect[arrow]==0.14.0\"\npython -m pip install \"clickhouse-connect[sqlalchemy]==0.14.0\"\npython -m pip install \"clickhouse-connect[polars]==0.14.0\"\n```\n\n## Create A Client\n\n### Basic local or self-hosted HTTP client\n\n```python\nimport clickhouse_connect\n\nclient = clickhouse_connect.get_client(\n    host=\"localhost\",\n    port=8123,\n    username=\"default\",\n    password=\"\",\n    database=\"default\",\n)\n\nresult = client.query(\"SELECT version()\")\nprint(result.first_row)\n```\n\n### HTTPS client for ClickHouse Cloud or any TLS endpoint\n\n```python\nimport os\n\nimport clickhouse_connect\n\nclient = clickhouse_connect.get_client(\n    host=\"your-service.clickhouse.cloud\",\n    port=8443,\n    secure=True,\n    username=\"default\",\n    password=os.environ[\"CLICKHOUSE_PASSWORD\"],\n    database=\"default\",\n    verify=True,\n    ca_cert=\"certifi\",\n    compress=\"lz4\",\n)\n```\n\n### JWT access token instead of username/password\n\nUse `access_token` for ClickHouse Cloud JWT auth, and do not combine it with `username` or `password`.\n\n```python\nimport os\n\nimport clickhouse_connect\n\nclient = clickhouse_connect.get_client(\n    host=\"your-service.clickhouse.cloud\",\n    secure=True,\n    access_token=os.environ[\"CLICKHOUSE_ACCESS_TOKEN\"],\n)\n```\n\n### DSN-based setup\n\nThe client also accepts a DSN and will derive host, port, credentials, and database from it:\n\n```python\nimport clickhouse_connect\n\nclient = clickhouse_connect.get_client(\n    dsn=\"https://default:password@example.clickhouse.cloud:8443/default\"\n)\n```\n\n## Core Query Workflow\n\n### `query()` returns a `QueryResult`\n\nUse `query()` for regular `SELECT` and similar result-returning SQL:\n\n```python\nresult = client.query(\"SELECT name, engine FROM system.tables LIMIT 3\")\n\nprint(result.result_rows)\nprint(result.first_item)\nprint(list(result.named_results()))\n```\n\nUseful `QueryResult` access patterns:\n\n- `result.result_rows`: row-oriented Python data\n- `result.result_set`: row-oriented by default, column-oriented if the query requested that shape\n- `result.first_row` / `result.first_item`: fast access for single-row results\n- `result.named_results()`: generator of dictionaries keyed by column name\n\n### `command()` for DDL and one-off commands\n\nUse `command()` when you do not want a full result matrix back:\n\n```python\nclient.command(\"\"\"\nCREATE TABLE IF NOT EXISTS events\n(\n    id UInt32,\n    name String\n)\nENGINE = MergeTree\nORDER BY id\n\"\"\")\n```\n\n### DataFrame and Arrow query methods\n\nUse the higher-level query method that matches the output you actually need:\n\n```python\ndf = client.query_df(\"SELECT number FROM numbers(5)\")\narrow_table = client.query_arrow(\"SELECT number FROM numbers(5)\")\n```\n\nFor Arrow-backed DataFrame output:\n\n```python\narrow_df = client.query_df_arrow(\n    \"SELECT number FROM numbers(5)\",\n    dataframe_library=\"pandas\",\n)\n```\n\nUse `dataframe_library=\"polars\"` if you want a Polars DataFrame instead.\n\n### Streaming large results\n\nFor large result sets, stream blocks instead of materializing everything at once:\n\n```python\nwith client.query_df_stream(\"SELECT * FROM events\") as stream:\n    for block_df in stream:\n        print(block_df.shape)\n```\n\nThere are also stream variants for row blocks, numpy, Arrow, and Arrow-backed DataFrames.\n\n## Insert Data\n\n### Insert Python rows\n\n```python\nrows = [\n    [1, \"alpha\"],\n    [2, \"beta\"],\n]\n\nclient.insert(\"events\", rows, column_names=[\"id\", \"name\"])\n```\n\n### Insert a pandas DataFrame\n\n```python\nimport pandas as pd\n\ndf = pd.DataFrame(\n    [\n        {\"id\": 3, \"name\": \"gamma\"},\n        {\"id\": 4, \"name\": \"delta\"},\n    ]\n)\n\nclient.insert_df(\"events\", df)\n```\n\n### Reuse insert metadata with `create_insert_context()`\n\nIf you are inserting many batches into the same table, build the insert context once and reuse it:\n\n```python\ninsert_context = client.create_insert_context(\n    table=\"events\",\n    column_names=[\"id\", \"name\"],\n)\n\nfor batch in (\n    [[5, \"one\"], [6, \"two\"]],\n    [[7, \"three\"], [8, \"four\"]],\n):\n    insert_context.data = batch\n    client.data_insert(insert_context)\n```\n\nThis avoids re-describing the table on every batch when the target schema is stable.\n\n### Arrow and Arrow-backed DataFrame inserts\n\nUse Arrow-based insert methods when your data is already Arrow-native:\n\n```python\nclient.insert_arrow(\"events\", arrow_table)\nclient.insert_df_arrow(\"events\", polars_df)\n```\n\n`insert_df_arrow()` is optimized for:\n\n- Polars DataFrames\n- pandas 2.x DataFrames whose columns already use PyArrow dtypes\n\n## Async Usage\n\nThe async client is obtained with `await clickhouse_connect.get_async_client(...)`.\n\n```python\nimport asyncio\n\nimport clickhouse_connect\n\nasync def main() -> None:\n    client = await clickhouse_connect.get_async_client(\n        host=\"localhost\",\n        port=8123,\n        username=\"default\",\n        password=\"\",\n    )\n    try:\n        result = await client.query(\"SELECT 1\")\n        print(result.first_row)\n    finally:\n        await client.close()\n\nasyncio.run(main())\n```\n\nYou can also use the async context manager:\n\n```python\nasync with await clickhouse_connect.get_async_client(host=\"localhost\") as client:\n    result = await client.query(\"SELECT 1\")\n```\n\n## Configuration And Authentication Notes\n\nCommon client arguments you will actually use:\n\n- `host`, `port`, `database`\n- `username` and `password`\n- `access_token` for JWT auth\n- `secure=True` or `interface=\"https\"` for TLS\n- `verify` and `ca_cert` for certificate validation\n- `client_cert` and `client_cert_key` for mutual TLS\n- `compress` with `True`, `lz4`, `zstd`, `brotli`, or `gzip`\n- `connect_timeout` and `send_receive_timeout`\n- `client_name` to make queries easier to identify in `system.query_log`\n- `form_encode_query_params=True` when very large query parameter payloads would exceed URL limits\n- `proxy_path` when ClickHouse is exposed behind a path-based reverse proxy\n- `transport_settings` on query and insert calls for per-request HTTP headers\n\nThe client defaults to:\n\n- `localhost` when `host` is omitted\n- `8123` for plain HTTP\n- `8443` for HTTPS when `secure=True` or `interface=\"https\"`\n\n## SQLAlchemy\n\n`clickhouse-connect` provides a lightweight SQLAlchemy dialect aimed at SQLAlchemy Core and Superset compatibility, not full ORM behavior.\n\nUse the `clickhousedb://` scheme:\n\n```text\nclickhousedb://{username}:{password}@{host}:{port}\n```\n\nSupported SQLAlchemy features are intentionally limited upstream. Core-style `SELECT`, `JOIN`, `ARRAY JOIN`, `FINAL`, and lightweight `DELETE` are in scope; ORM-heavy patterns are not the target.\n\n## Common Pitfalls\n\n- `clickhouse-connect` uses the ClickHouse HTTP interface, not the native TCP client protocol. Do not point it at port `9000` and expect it to work.\n- `query()` returns a `QueryResult`, not a pandas DataFrame. Use `query_df()`, `query_arrow()`, or `query_df_arrow()` when you need those shapes.\n- `query_df()` and `insert_df()` require pandas to be installed. Arrow methods require `pyarrow`. Polars support depends on `polars`.\n- `insert_df_arrow()` with pandas requires pandas `2.x` and PyArrow-backed dtypes for every column.\n- `access_token` cannot be combined with `username` or `password`.\n- `secure=True` changes the expected default port to `8443`. Plain HTTP defaults to `8123`.\n- The async client wraps the sync client in an executor. Always `await client.close()` or use `async with`.\n- `utc_tz_aware` is deprecated. Prefer `tz_mode=\"naive_utc\"`, `\"aware\"`, or `\"schema\"`.\n- SQLAlchemy support is Core-oriented. Do not promise full ORM parity with Postgres/MySQL dialects.\n\n## Version-Sensitive Notes For 0.14.0\n\n- PyPI and the maintainer GitHub repo both show `0.14.0` as the current release as of March 12, 2026.\n- Python `3.9` is still accepted by package metadata, but the maintainer repo now emits a deprecation warning on import for Python `<3.10`, and the 0.11.0 release notes tell users to plan upgrades to `3.10+`.\n- Since `0.13.0`, `tz_mode=\"schema\"` is available and is the preferred modern replacement when you want timezone handling to match the ClickHouse column definition. Older examples may still use the deprecated `utc_tz_aware` argument.\n- Since `0.13.0`, writing to `Variant` columns uses native type-aware dispatch instead of stringifying values first. If older code relied on implicit string coercion for `Variant`, re-test inserts.\n- Since `0.9.0`, SQLAlchemy support targets `>=1.4.40` and includes SQLAlchemy `2.x` support. Old `1.3`-era examples are outdated.\n- Since `0.9.0`, Arrow-backed DataFrame methods such as `query_df_arrow()` and `insert_df_arrow()` are available. Prefer them when your pipeline is already Arrow-native.\n- Since `0.8.17`, `transport_settings` can attach per-query HTTP headers, and `proxy_path` can help when ClickHouse sits behind a path-based proxy.\n- Since `0.8.15`, `AsyncClient.close()` is async. Older blog posts that call `client.close()` without `await` are wrong for current releases.\n\n## Official Sources\n\n- ClickHouse Python integration page: `https://clickhouse.com/integrations/python`\n- PyPI package page: `https://pypi.org/project/clickhouse-connect/`\n- Maintainer repository: `https://github.com/ClickHouse/clickhouse-connect`\n"
  },
  {
    "path": "content/cloudflare/docs/workers/javascript/DOC.md",
    "content": "---\nname: workers\ndescription: \"Cloudflare Workers SDK for building edge functions with KV and R2 storage in JavaScript/TypeScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"cloudflare,workers,edge,kv,r2\"\n---\n\n# Cloudflare API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Cloudflare API coding expert. Help me with writing code using the Cloudflare API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.cloudflare.com/api/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Cloudflare TypeScript SDK to interact with the Cloudflare API, which is the standard library for all Cloudflare API interactions. Do not use unofficial libraries or deprecated packages.\n\n- **Library Name:** Cloudflare TypeScript SDK\n- **NPM Package:** `cloudflare`\n- **Legacy Libraries:** Avoid unofficial packages or legacy clients\n\n**Installation:**\n\n```bash\nnpm install cloudflare\n```\n\n**APIs and Usage:**\n\n- **Correct:** `import Cloudflare from 'cloudflare'`\n- **Correct:** `const client = new Cloudflare({})`\n- **Correct:** `await client.zones.create(...)`\n- **Correct:** `await client.dns.records.create(...)`\n- **Incorrect:** `CloudflareClient` or `CloudflareAPI`\n- **Incorrect:** Using deprecated multipart form data APIs directly\n- **Incorrect:** Unofficial wrapper libraries\n\n## Installation\n\nInstall the Cloudflare SDK:\n\n```bash\nnpm install cloudflare\n```\n\nSet your API token as an environment variable:\n\n```bash\nexport CLOUDFLARE_API_TOKEN='your_api_token_here'\n```\n\n## Initialization\n\nThe `cloudflare` library requires creating a `Cloudflare` instance for all API calls.\n\n- Always use `const client = new Cloudflare({})` to create an instance.\n- Set the `CLOUDFLARE_API_TOKEN` environment variable, which will be picked up automatically.\n\n```javascript\nimport Cloudflare from 'cloudflare';\n\n// Uses the CLOUDFLARE_API_TOKEN environment variable if apiToken not specified\nconst client = new Cloudflare({});\n\n// Or pass the API token directly\n// const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN });\n```\n\n### Alternative Authentication\n\nYou can also authenticate with API email and key (legacy method):\n\n```javascript\nconst client = new Cloudflare({\n  apiEmail: process.env.CLOUDFLARE_API_EMAIL,\n  apiKey: process.env.CLOUDFLARE_API_KEY,\n});\n```\n\n## Zone Management\n\nZones are the foundation of Cloudflare - each zone represents a domain.\n\n### Create a Zone\n\n```javascript\nimport Cloudflare from 'cloudflare';\n\nconst client = new Cloudflare({});\n\nasync function run() {\n  const zone = await client.zones.create({\n    account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n    name: 'example.com',\n    type: 'full',\n  });\n\n  console.log(zone.id);\n  console.log(zone.name);\n  console.log(zone.status);\n}\n\nrun();\n```\n\n### Get Zone Details\n\n```javascript\nconst zone = await client.zones.get({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nconsole.log(zone.name);\nconsole.log(zone.status);\n```\n\n### List Zones\n\n```javascript\n// List all zones with auto-pagination\nasync function listAllZones() {\n  const zones = [];\n  for await (const zone of client.zones.list()) {\n    zones.push(zone);\n  }\n  return zones;\n}\n\n// Or with filtering\nconst response = await client.zones.list({\n  account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n  status: 'active',\n});\n```\n\n### Edit a Zone\n\n```javascript\nawait client.zones.edit(\n  {\n    zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  },\n  {\n    paused: false,\n    type: 'full',\n  }\n);\n```\n\n### Delete a Zone\n\n```javascript\nawait client.zones.delete({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n```\n\n## DNS Records Management\n\nManage DNS records for your zones.\n\n### Create DNS Record\n\n```javascript\nimport Cloudflare from 'cloudflare';\n\nconst client = new Cloudflare({});\n\nasync function run() {\n  const record = await client.dns.records.create({\n    zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n    type: 'A',\n    name: 'www',\n    content: '192.0.2.1',\n    ttl: 3600,\n    proxied: true,\n  });\n\n  console.log(record.id);\n  console.log(record.name);\n}\n\nrun();\n```\n\n### List DNS Records\n\n```javascript\n// List all DNS records for a zone\nconst records = await client.dns.records.list({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const record of records.result) {\n  console.log(`${record.type} ${record.name} -> ${record.content}`);\n}\n\n// Filter by record type\nconst aRecords = await client.dns.records.list({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  type: 'A',\n});\n```\n\n### Update DNS Record\n\n```javascript\nawait client.dns.records.update({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  record_id: '372e67954025e0ba6aaa6d586b9e0b59',\n  type: 'A',\n  name: 'www',\n  content: '192.0.2.2',\n  ttl: 3600,\n  proxied: true,\n});\n```\n\n### Delete DNS Record\n\n```javascript\nawait client.dns.records.delete({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  record_id: '372e67954025e0ba6aaa6d586b9e0b59',\n});\n```\n\n## Workers Management\n\nCloudflare Workers allows you to run JavaScript at the edge.\n\n### Upload a Worker Script\n\n```javascript\nimport Cloudflare from 'cloudflare';\nimport fs from 'fs';\n\nconst client = new Cloudflare({});\n\nasync function uploadWorker() {\n  const scriptContent = fs.readFileSync('./worker.js', 'utf8');\n\n  await client.workers.scripts.update({\n    account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n    script_name: 'my-worker',\n    '<any part name>': scriptContent,\n    metadata: {\n      main_module: 'worker.js',\n      compatibility_date: '2025-01-01',\n    },\n  });\n}\n\nuploadWorker();\n```\n\n### List Worker Scripts\n\n```javascript\nconst scripts = await client.workers.scripts.list({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const script of scripts.result) {\n  console.log(script.id);\n}\n```\n\n### Get Worker Script\n\n```javascript\nconst script = await client.workers.scripts.get({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  script_name: 'my-worker',\n});\n```\n\n### Delete Worker Script\n\n```javascript\nawait client.workers.scripts.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  script_name: 'my-worker',\n});\n```\n\n## Workers KV Storage\n\nWorkers KV is a global, low-latency key-value data store.\n\n### Create KV Namespace\n\n```javascript\nconst namespace = await client.kv.namespaces.create({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  title: 'my-kv-namespace',\n});\n\nconsole.log(namespace.id);\n```\n\n### List KV Namespaces\n\n```javascript\nconst namespaces = await client.kv.namespaces.list({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const ns of namespaces.result) {\n  console.log(`${ns.id}: ${ns.title}`);\n}\n```\n\n### Write KV Value\n\n```javascript\nawait client.kv.namespaces.values.update({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  namespace_id: '0f2ac74b498b48028cb68387c421e279',\n  key_name: 'my-key',\n  metadata: JSON.stringify({ someMetadata: 'value' }),\n  value: 'my-value',\n});\n```\n\n### Read KV Value\n\n```javascript\nconst value = await client.kv.namespaces.values.get({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  namespace_id: '0f2ac74b498b48028cb68387c421e279',\n  key_name: 'my-key',\n});\n\nconsole.log(value);\n```\n\n### Delete KV Value\n\n```javascript\nawait client.kv.namespaces.values.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  namespace_id: '0f2ac74b498b48028cb68387c421e279',\n  key_name: 'my-key',\n});\n```\n\n### Delete KV Namespace\n\n```javascript\nawait client.kv.namespaces.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  namespace_id: '0f2ac74b498b48028cb68387c421e279',\n});\n```\n\n## R2 Object Storage\n\nR2 is S3-compatible object storage without egress fees.\n\n### Create R2 Bucket\n\n```javascript\nconst bucket = await client.r2.buckets.create({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  name: 'my-bucket',\n});\n\nconsole.log(bucket.name);\n```\n\n### List R2 Buckets\n\n```javascript\nconst buckets = await client.r2.buckets.list({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const bucket of buckets.buckets) {\n  console.log(bucket.name);\n}\n```\n\n### Delete R2 Bucket\n\n```javascript\nawait client.r2.buckets.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  bucket_name: 'my-bucket',\n});\n```\n\n## D1 Database\n\nD1 is Cloudflare's native serverless SQL database.\n\n### Create D1 Database\n\n```javascript\nconst database = await client.d1.database.create({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  name: 'my-database',\n});\n\nconsole.log(database.uuid);\nconsole.log(database.name);\n```\n\n### List D1 Databases\n\n```javascript\nconst databases = await client.d1.database.list({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const db of databases.result) {\n  console.log(`${db.uuid}: ${db.name}`);\n}\n```\n\n### Query D1 Database\n\n```javascript\nconst result = await client.d1.database.query({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  database_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n  sql: 'SELECT * FROM users WHERE id = ?',\n  params: ['123'],\n});\n\nconsole.log(result);\n```\n\n### Delete D1 Database\n\n```javascript\nawait client.d1.database.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  database_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n});\n```\n\n## Pages Projects\n\nCloudflare Pages allows you to deploy static sites and full-stack applications.\n\n### Create Pages Project\n\n```javascript\nconst project = await client.pages.projects.create({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  name: 'my-project',\n  production_branch: 'main',\n});\n\nconsole.log(project.name);\n```\n\n### List Pages Projects\n\n```javascript\nconst projects = await client.pages.projects.list({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const project of projects.result) {\n  console.log(project.name);\n}\n```\n\n### Get Pages Project\n\n```javascript\nconst project = await client.pages.projects.get({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  project_name: 'my-project',\n});\n```\n\n### Delete Pages Project\n\n```javascript\nawait client.pages.projects.delete({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  project_name: 'my-project',\n});\n```\n\n## Account Management\n\n### List Accounts\n\n```javascript\n// Auto-pagination\nasync function getAllAccounts() {\n  const accounts = [];\n  for await (const account of client.accounts.list()) {\n    accounts.push(account);\n  }\n  return accounts;\n}\n\n// Manual pagination\nlet page = await client.accounts.list({ per_page: 20 });\nfor (const account of page.result) {\n  console.log(account.name);\n}\n\nwhile (page.hasNextPage()) {\n  page = await page.getNextPage();\n  // Process next page\n}\n```\n\n### Get Account Details\n\n```javascript\nconst account = await client.accounts.get({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nconsole.log(account.name);\nconsole.log(account.settings);\n```\n\n## Load Balancers\n\n### Create Load Balancer\n\n```javascript\nconst loadBalancer = await client.loadBalancers.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  name: 'my-load-balancer',\n  default_pools: ['17b5962d775c646f3f9725cbc7a53df4'],\n  fallback_pool: '17b5962d775c646f3f9725cbc7a53df4',\n  ttl: 30,\n  steering_policy: 'random',\n});\n```\n\n### List Load Balancers\n\n```javascript\nconst loadBalancers = await client.loadBalancers.list({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n```\n\n### Create Load Balancer Pool\n\n```javascript\nconst pool = await client.loadBalancers.pools.create({\n  account_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  name: 'my-pool',\n  origins: [\n    {\n      name: 'origin-1',\n      address: '192.0.2.1',\n      enabled: true,\n      weight: 1,\n    },\n  ],\n});\n```\n\n## Cache Management\n\n### Purge Cache\n\n```javascript\n// Purge everything\nawait client.cache.purge({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  purge_everything: true,\n});\n\n// Purge by URLs\nawait client.cache.purge({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  files: [\n    'https://example.com/file1.jpg',\n    'https://example.com/file2.jpg',\n  ],\n});\n\n// Purge by tags\nawait client.cache.purge({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  tags: ['tag1', 'tag2'],\n});\n\n// Purge by prefix\nawait client.cache.purge({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  prefixes: ['https://example.com/images/'],\n});\n```\n\n## WAF and Firewall Rules\n\n### Create Firewall Rule\n\n```javascript\nconst rule = await client.firewall.rules.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  filter: {\n    expression: '(ip.src eq 192.0.2.1)',\n  },\n  action: 'block',\n  description: 'Block specific IP',\n});\n```\n\n### List Firewall Rules\n\n```javascript\nconst rules = await client.firewall.rules.list({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n```\n\n## SSL/TLS Certificate Management\n\n### List SSL Certificates\n\n```javascript\nconst certificates = await client.ssl.certificates.list({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n\nfor (const cert of certificates.result) {\n  console.log(cert.id);\n  console.log(cert.hosts);\n}\n```\n\n### Get SSL Settings\n\n```javascript\nconst settings = await client.ssl.settings.get({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n});\n```\n\n## File Uploads\n\nThe SDK supports multiple file input formats for endpoints that require file uploads:\n\n```javascript\nimport fs from 'fs';\nimport Cloudflare, { toFile } from 'cloudflare';\n\nconst client = new Cloudflare({});\n\n// Using Node.js streams (recommended)\nawait client.apiGateway.userSchemas.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  file: fs.createReadStream('/path/to/file'),\n  kind: 'openapi_v3',\n});\n\n// Using the File API\nawait client.apiGateway.userSchemas.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  file: new File(['my bytes'], 'file'),\n  kind: 'openapi_v3',\n});\n\n// Using fetch Response\nawait client.apiGateway.userSchemas.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  file: await fetch('https://somesite/file'),\n  kind: 'openapi_v3',\n});\n\n// Using the toFile helper\nawait client.apiGateway.userSchemas.create({\n  zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  file: await toFile(Buffer.from('my bytes'), 'file'),\n  kind: 'openapi_v3',\n});\n```\n\n## Error Handling\n\nThe SDK provides comprehensive error handling with specific error types:\n\n```javascript\nimport Cloudflare from 'cloudflare';\n\nconst client = new Cloudflare({});\n\ntry {\n  const zone = await client.zones.get({\n    zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  });\n} catch (err) {\n  if (err instanceof Cloudflare.APIError) {\n    console.log(err.status); // HTTP status code (e.g., 400, 404)\n    console.log(err.name); // Error type (e.g., BadRequestError)\n    console.log(err.headers); // Response headers\n    console.log(err.message); // Error message\n  } else {\n    throw err;\n  }\n}\n```\n\n### Error Types\n\n| Status Code | Error Type                    |\n| ----------- | ----------------------------- |\n| 400         | `BadRequestError`             |\n| 401         | `AuthenticationError`         |\n| 403         | `PermissionDeniedError`       |\n| 404         | `NotFoundError`               |\n| 422         | `UnprocessableEntityError`    |\n| 429         | `RateLimitError`              |\n| >=500       | `InternalServerError`         |\n| N/A         | `APIConnectionError`          |\n\nAll errors extend from `APIError`.\n\n## Advanced Configuration\n\n### Retries\n\nConfigure automatic retry behavior:\n\n```javascript\n// Configure default retries for all requests\nconst client = new Cloudflare({\n  maxRetries: 3, // default is 2\n});\n\n// Or configure per-request\nawait client.zones.get(\n  {\n    zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  },\n  {\n    maxRetries: 5,\n  }\n);\n```\n\nThe SDK automatically retries:\n- Connection errors\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- >=500 Internal errors\n\n### Timeouts\n\nSet custom timeout values:\n\n```javascript\n// Configure default timeout for all requests\nconst client = new Cloudflare({\n  timeout: 20 * 1000, // 20 seconds (default is 1 minute)\n});\n\n// Override per-request\nawait client.zones.edit(\n  {\n    zone_id: '023e105f4ecef8ad9ca31a8372d0c353',\n  },\n  {\n    timeout: 5 * 1000,\n  }\n);\n```\n\n### Custom Fetch Implementation\n\nProvide a custom fetch function for logging or middleware:\n\n```javascript\nimport { fetch } from 'undici';\nimport Cloudflare from 'cloudflare';\n\nconst client = new Cloudflare({\n  fetch: async (url, init) => {\n    console.log('Request:', url, init);\n    const response = await fetch(url, init);\n    console.log('Response:', response);\n    return response;\n  },\n});\n```\n\n### Accessing Raw Response Data\n\nAccess underlying HTTP response data:\n\n```javascript\n// Get raw response\nconst response = await client.zones\n  .create({\n    account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n    name: 'example.com',\n    type: 'full',\n  })\n  .asResponse();\n\nconsole.log(response.headers.get('X-Request-ID'));\n\n// Get both data and response\nconst { data: zone, response: raw } = await client.zones\n  .create({\n    account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n    name: 'example.com',\n    type: 'full',\n  })\n  .withResponse();\n\nconsole.log(zone.id);\nconsole.log(raw.headers);\n```\n\n## Pagination\n\nHandle paginated responses automatically or manually:\n\n```javascript\n// Auto-pagination (recommended)\nasync function fetchAllZones() {\n  const allZones = [];\n  for await (const zone of client.zones.list()) {\n    allZones.push(zone);\n  }\n  return allZones;\n}\n\n// Manual pagination\nlet page = await client.zones.list({ per_page: 20 });\nfor (const zone of page.result) {\n  console.log(zone.name);\n}\n\nwhile (page.hasNextPage()) {\n  page = await page.getNextPage();\n  for (const zone of page.result) {\n    console.log(zone.name);\n  }\n}\n```\n\n## TypeScript Support\n\nThe SDK includes full TypeScript definitions:\n\n```typescript\nimport Cloudflare from 'cloudflare';\n\nconst client = new Cloudflare({});\n\n// Use typed parameters\nconst params: Cloudflare.ZoneCreateParams = {\n  account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n  name: 'example.com',\n  type: 'full',\n};\n\n// Get typed response\nconst zone: Cloudflare.Zone = await client.zones.create(params);\n\n// TypeScript will validate all fields\nconsole.log(zone.id);\nconsole.log(zone.name);\nconsole.log(zone.status);\n```\n\n## Custom Endpoints\n\nMake requests to endpoints not yet in the typed SDK:\n\n```javascript\n// POST request to custom endpoint\nawait client.post('/some/path', {\n  body: { some_prop: 'foo' },\n  query: { some_query_arg: 'bar' },\n});\n\n// GET request\nconst response = await client.get('/custom/endpoint', {\n  query: { filter: 'active' },\n});\n```\n\nFor undocumented parameters in typed methods:\n\n```typescript\nclient.zones.create({\n  account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },\n  name: 'example.com',\n  // @ts-expect-error undocumented_param is not in the types yet\n  undocumented_param: 'some_value',\n});\n```\n\n## Useful Links\n\n- Documentation: https://developers.cloudflare.com/api/\n- SDK Reference: https://github.com/cloudflare/cloudflare-typescript\n- API Keys: https://dash.cloudflare.com/profile/api-tokens\n- Workers Docs: https://developers.cloudflare.com/workers/\n- R2 Docs: https://developers.cloudflare.com/r2/\n- D1 Docs: https://developers.cloudflare.com/d1/\n- KV Docs: https://developers.cloudflare.com/kv/\n- Pages Docs: https://developers.cloudflare.com/pages/\n- Rate Limits: https://developers.cloudflare.com/fundamentals/api/reference/limits/\n"
  },
  {
    "path": "content/cloudflare/docs/workers/python/DOC.md",
    "content": "---\nname: workers\ndescription: \"Cloudflare Workers SDK for building edge functions with KV and R2 storage in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.1\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"cloudflare,workers,edge,kv,r2\"\n---\n\n# Cloudflare API Coding Guidelines (Python)\n\nYou are a Cloudflare API coding expert. Help me with writing code using the Cloudflare API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.cloudflare.com/api/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Cloudflare Python SDK to interact with the Cloudflare API, which is the standard library for all Cloudflare API interactions. Do not use unofficial libraries or deprecated packages.\n\n- **Library Name:** Cloudflare Python SDK\n- **PyPI Package:** `cloudflare`\n- **Legacy Libraries:** Avoid `python-cloudflare` (archived) or unofficial packages\n\n**Installation:**\n\n```bash\npip install cloudflare\n```\n\n**APIs and Usage:**\n\n- **Correct:** `from cloudflare import Cloudflare`\n- **Correct:** `client = Cloudflare()`\n- **Correct:** `client.zones.create(...)`\n- **Correct:** `from cloudflare import AsyncCloudflare`\n- **Incorrect:** `CloudflareAPI` or `CloudFlare`\n- **Incorrect:** Using the archived `python-cloudflare` package\n- **Incorrect:** `CloudflareClient`\n\n## Installation\n\nInstall the Cloudflare SDK:\n\n```bash\npip install cloudflare\n```\n\nSet your API token as an environment variable:\n\n```bash\nexport CLOUDFLARE_API_TOKEN='your_api_token_here'\n```\n\n## Initialization\n\nThe `cloudflare` library requires creating a `Cloudflare` instance for all API calls.\n\n```python\nimport os\nfrom cloudflare import Cloudflare\n\n# Uses the CLOUDFLARE_API_TOKEN environment variable if api_token not specified\nclient = Cloudflare()\n\n# Or pass the API token directly\n# client = Cloudflare(api_token=os.environ.get(\"CLOUDFLARE_API_TOKEN\"))\n```\n\n### Alternative Authentication\n\nYou can also authenticate with API email and key (legacy method):\n\n```python\nclient = Cloudflare(\n    api_email=os.environ.get(\"CLOUDFLARE_API_EMAIL\"),\n    api_key=os.environ.get(\"CLOUDFLARE_API_KEY\"),\n)\n```\n\n### Async Client\n\nThe SDK provides an async client for asynchronous operations:\n\n```python\nimport asyncio\nimport os\nfrom cloudflare import AsyncCloudflare\n\nclient = AsyncCloudflare(\n    api_token=os.environ.get(\"CLOUDFLARE_API_TOKEN\"),\n)\n\nasync def main():\n    zone = await client.zones.create(\n        account={\"id\": \"023e105f4ecef8ad9ca31a8372d0c353\"},\n        name=\"example.com\",\n        type=\"full\",\n    )\n    print(zone.id)\n\nasyncio.run(main())\n```\n\n## Zone Management\n\nZones are the foundation of Cloudflare - each zone represents a domain.\n\n### Create a Zone\n\n```python\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\nzone = client.zones.create(\n    account={\"id\": \"023e105f4ecef8ad9ca31a8372d0c353\"},\n    name=\"example.com\",\n    type=\"full\",\n)\n\nprint(zone.id)\nprint(zone.name)\nprint(zone.status)\n```\n\n### Get Zone Details\n\n```python\nzone = client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\n\nprint(zone.name)\nprint(zone.status)\nprint(zone.name_servers)\n```\n\n### List Zones\n\n```python\n# List all zones with auto-pagination\nall_zones = []\nfor zone in client.zones.list():\n    all_zones.append(zone)\n    print(f\"{zone.id}: {zone.name}\")\n\n# Or with filtering\nzones = client.zones.list(\n    account={\"id\": \"023e105f4ecef8ad9ca31a8372d0c353\"},\n    status=\"active\",\n)\nfor zone in zones:\n    print(zone.name)\n```\n\n### Edit a Zone\n\n```python\nclient.zones.edit(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    paused=False,\n    type=\"full\",\n)\n```\n\n### Delete a Zone\n\n```python\nclient.zones.delete(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\n```\n\n## DNS Records Management\n\nManage DNS records for your zones.\n\n### Create DNS Record\n\n```python\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\nrecord = client.dns.records.create(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    type=\"A\",\n    name=\"www\",\n    content=\"192.0.2.1\",\n    ttl=3600,\n    proxied=True,\n)\n\nprint(record.id)\nprint(record.name)\nprint(record.type)\n```\n\n### List DNS Records\n\n```python\n# List all DNS records for a zone\nrecords = client.dns.records.list(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor record in records:\n    print(f\"{record.type} {record.name} -> {record.content}\")\n\n# Filter by record type\na_records = client.dns.records.list(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    type=\"A\",\n)\n\nfor record in a_records:\n    print(f\"{record.name}: {record.content}\")\n```\n\n### Update DNS Record\n\n```python\nclient.dns.records.update(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    dns_record_id=\"372e67954025e0ba6aaa6d586b9e0b59\",\n    type=\"A\",\n    name=\"www\",\n    content=\"192.0.2.2\",\n    ttl=3600,\n    proxied=True,\n)\n```\n\n### Delete DNS Record\n\n```python\nclient.dns.records.delete(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    dns_record_id=\"372e67954025e0ba6aaa6d586b9e0b59\",\n)\n```\n\n## Workers Management\n\nCloudflare Workers allows you to run code at the edge.\n\n### Upload a Worker Script\n\n```python\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\n# Read worker script from file\nwith open(\"worker.js\", \"r\") as f:\n    script_content = f.read()\n\nclient.workers.scripts.update(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    script_name=\"my-worker\",\n    **{\"<any part name>\": script_content},\n    metadata={\n        \"main_module\": \"worker.js\",\n        \"compatibility_date\": \"2025-01-01\",\n    },\n)\n```\n\n### List Worker Scripts\n\n```python\nscripts = client.workers.scripts.list(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor script in scripts:\n    print(script.id)\n```\n\n### Get Worker Script\n\n```python\nscript = client.workers.scripts.get(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    script_name=\"my-worker\",\n)\n```\n\n### Delete Worker Script\n\n```python\nclient.workers.scripts.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    script_name=\"my-worker\",\n)\n```\n\n## Workers KV Storage\n\nWorkers KV is a global, low-latency key-value data store.\n\n### Create KV Namespace\n\n```python\nnamespace = client.kv.namespaces.create(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    title=\"my-kv-namespace\",\n)\n\nprint(namespace.id)\nprint(namespace.title)\n```\n\n### List KV Namespaces\n\n```python\nnamespaces = client.kv.namespaces.list(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor ns in namespaces:\n    print(f\"{ns.id}: {ns.title}\")\n```\n\n### Write KV Value\n\n```python\nclient.kv.namespaces.values.update(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    namespace_id=\"0f2ac74b498b48028cb68387c421e279\",\n    key_name=\"my-key\",\n    value=\"my-value\",\n    metadata='{\"someMetadata\": \"value\"}',\n)\n```\n\n### Read KV Value\n\n```python\nvalue = client.kv.namespaces.values.get(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    namespace_id=\"0f2ac74b498b48028cb68387c421e279\",\n    key_name=\"my-key\",\n)\n\nprint(value)\n```\n\n### Delete KV Value\n\n```python\nclient.kv.namespaces.values.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    namespace_id=\"0f2ac74b498b48028cb68387c421e279\",\n    key_name=\"my-key\",\n)\n```\n\n### Delete KV Namespace\n\n```python\nclient.kv.namespaces.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    namespace_id=\"0f2ac74b498b48028cb68387c421e279\",\n)\n```\n\n## R2 Object Storage\n\nR2 is S3-compatible object storage without egress fees.\n\n### Create R2 Bucket\n\n```python\nbucket = client.r2.buckets.create(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    name=\"my-bucket\",\n)\n\nprint(bucket.name)\nprint(bucket.creation_date)\n```\n\n### List R2 Buckets\n\n```python\nbuckets = client.r2.buckets.list(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor bucket in buckets.buckets:\n    print(bucket.name)\n```\n\n### Delete R2 Bucket\n\n```python\nclient.r2.buckets.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    bucket_name=\"my-bucket\",\n)\n```\n\n## D1 Database\n\nD1 is Cloudflare's native serverless SQL database.\n\n### Create D1 Database\n\n```python\ndatabase = client.d1.database.create(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    name=\"my-database\",\n)\n\nprint(database.uuid)\nprint(database.name)\n```\n\n### List D1 Databases\n\n```python\ndatabases = client.d1.database.list(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor db in databases:\n    print(f\"{db.uuid}: {db.name}\")\n```\n\n### Query D1 Database\n\n```python\nresult = client.d1.database.query(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    database_id=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\n    sql=\"SELECT * FROM users WHERE id = ?\",\n    params=[\"123\"],\n)\n\nprint(result)\n```\n\n### Delete D1 Database\n\n```python\nclient.d1.database.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    database_id=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\n)\n```\n\n## Pages Projects\n\nCloudflare Pages allows you to deploy static sites and full-stack applications.\n\n### Create Pages Project\n\n```python\nproject = client.pages.projects.create(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    name=\"my-project\",\n    production_branch=\"main\",\n)\n\nprint(project.name)\nprint(project.subdomain)\n```\n\n### List Pages Projects\n\n```python\nprojects = client.pages.projects.list(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor project in projects:\n    print(f\"{project.name}: {project.subdomain}\")\n```\n\n### Get Pages Project\n\n```python\nproject = client.pages.projects.get(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    project_name=\"my-project\",\n)\n\nprint(project.name)\nprint(project.production_branch)\n```\n\n### Delete Pages Project\n\n```python\nclient.pages.projects.delete(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    project_name=\"my-project\",\n)\n```\n\n## Account Management\n\n### List Accounts\n\n```python\n# Auto-pagination\nall_accounts = []\nfor account in client.accounts.list():\n    all_accounts.append(account)\n    print(f\"{account.id}: {account.name}\")\n\n# Manual pagination\npage = client.accounts.list(per_page=20)\nfor account in page.result:\n    print(account.name)\n\nif page.has_next_page():\n    next_page = page.get_next_page()\n    for account in next_page.result:\n        print(account.name)\n```\n\n### Get Account Details\n\n```python\naccount = client.accounts.get(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nprint(account.name)\nprint(account.settings)\n```\n\n## Load Balancers\n\n### Create Load Balancer\n\n```python\nload_balancer = client.load_balancers.create(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    name=\"my-load-balancer\",\n    default_pools=[\"17b5962d775c646f3f9725cbc7a53df4\"],\n    fallback_pool=\"17b5962d775c646f3f9725cbc7a53df4\",\n    ttl=30,\n    steering_policy=\"random\",\n)\n\nprint(load_balancer.id)\n```\n\n### List Load Balancers\n\n```python\nload_balancers = client.load_balancers.list(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor lb in load_balancers:\n    print(f\"{lb.id}: {lb.name}\")\n```\n\n### Create Load Balancer Pool\n\n```python\npool = client.load_balancers.pools.create(\n    account_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    name=\"my-pool\",\n    origins=[\n        {\n            \"name\": \"origin-1\",\n            \"address\": \"192.0.2.1\",\n            \"enabled\": True,\n            \"weight\": 1,\n        },\n    ],\n)\n\nprint(pool.id)\n```\n\n## Cache Management\n\n### Purge Cache\n\n```python\n# Purge everything\nclient.cache.purge(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    purge_everything=True,\n)\n\n# Purge by URLs\nclient.cache.purge(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    files=[\n        \"https://example.com/file1.jpg\",\n        \"https://example.com/file2.jpg\",\n    ],\n)\n\n# Purge by tags\nclient.cache.purge(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    tags=[\"tag1\", \"tag2\"],\n)\n\n# Purge by prefix\nclient.cache.purge(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    prefixes=[\"https://example.com/images/\"],\n)\n```\n\n## WAF and Firewall Rules\n\n### Create Firewall Rule\n\n```python\nrule = client.firewall.rules.create(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    filter={\n        \"expression\": \"(ip.src eq 192.0.2.1)\",\n    },\n    action=\"block\",\n    description=\"Block specific IP\",\n)\n\nprint(rule.id)\n```\n\n### List Firewall Rules\n\n```python\nrules = client.firewall.rules.list(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor rule in rules:\n    print(f\"{rule.id}: {rule.description}\")\n```\n\n## SSL/TLS Certificate Management\n\n### List SSL Certificates\n\n```python\ncertificates = client.ssl.certificates.list(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nfor cert in certificates:\n    print(cert.id)\n    print(cert.hosts)\n```\n\n### Get SSL Settings\n\n```python\nsettings = client.ssl.settings.get(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n\nprint(settings)\n```\n\n## File Uploads\n\nThe SDK supports multiple file input formats for endpoints that require file uploads:\n\n```python\nfrom pathlib import Path\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\n# Using Path objects (recommended)\nclient.api_gateway.user_schemas.create(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n    file=Path(\"/path/to/file\"),\n    kind=\"openapi_v3\",\n)\n\n# Using file-like objects\nwith open(\"/path/to/file\", \"rb\") as f:\n    client.api_gateway.user_schemas.create(\n        zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n        file=f,\n        kind=\"openapi_v3\",\n    )\n\n# Using bytes\nwith open(\"/path/to/file\", \"rb\") as f:\n    file_bytes = f.read()\n    client.api_gateway.user_schemas.create(\n        zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n        file=file_bytes,\n        kind=\"openapi_v3\",\n    )\n```\n\n## Error Handling\n\nThe SDK provides comprehensive error handling with specific error types:\n\n```python\nimport cloudflare\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\ntry:\n    zone = client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\nexcept cloudflare.APIConnectionError as e:\n    print(\"Server unreachable\")\n    print(e.__cause__)\nexcept cloudflare.RateLimitError as e:\n    print(\"429 rate limit error\")\n    print(e.status_code)\n    print(e.response)\nexcept cloudflare.APIStatusError as e:\n    print(f\"Error {e.status_code}\")\n    print(e.response)\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n### Error Types\n\n- `APIConnectionError` - Server unreachable or connection issues\n- `RateLimitError` - 429 rate limit exceeded\n- `APIStatusError` - Any HTTP error status (400, 401, 403, 404, etc.)\n- `APITimeoutError` - Request timeout\n\nAll errors have access to:\n- `e.status_code` - HTTP status code (if available)\n- `e.response` - Raw response object\n- `e.body` - Response body\n\n## Advanced Configuration\n\n### Retries\n\nConfigure automatic retry behavior:\n\n```python\nfrom cloudflare import Cloudflare\n\n# Configure default retries for all requests\nclient = Cloudflare(max_retries=3)  # default is 2\n\n# Or configure per-request\nclient.with_options(max_retries=5).zones.get(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n```\n\nThe SDK automatically retries:\n- Connection errors\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- >=500 Internal errors\n\n### Timeouts\n\nSet custom timeout values:\n\n```python\nfrom cloudflare import Cloudflare\nimport httpx\n\n# Simple timeout (20 seconds)\nclient = Cloudflare(timeout=20.0)  # default is 1 minute\n\n# Granular timeout control\nclient = Cloudflare(\n    timeout=httpx.Timeout(\n        60.0,           # total timeout\n        read=5.0,       # read timeout\n        write=10.0,     # write timeout\n        connect=2.0,    # connect timeout\n    ),\n)\n\n# Override per-request\nclient.with_options(timeout=5.0).zones.edit(\n    zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\",\n)\n```\n\n### Custom HTTP Client\n\nProvide a custom HTTP client for proxies or custom configuration:\n\n```python\nimport httpx\nfrom cloudflare import Cloudflare, DefaultHttpxClient\n\nclient = Cloudflare(\n    http_client=DefaultHttpxClient(\n        proxy=\"http://my.test.proxy.example.com\",\n        transport=httpx.HTTPTransport(local_address=\"0.0.0.0\"),\n    ),\n)\n```\n\n### Base URL Override\n\nOverride the base API URL:\n\n```python\nclient = Cloudflare(\n    base_url=\"http://my.test.server.example.com:8083\",\n)\n```\n\n### Accessing Raw Response Data\n\nAccess underlying HTTP response data:\n\n```python\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\n# Get raw response\nresponse = client.zones.with_raw_response.create(\n    account={\"id\": \"023e105f4ecef8ad9ca31a8372d0c353\"},\n    name=\"example.com\",\n    type=\"full\",\n)\n\nprint(response.headers.get(\"X-Request-ID\"))\nprint(response.status_code)\n\n# Parse the response\nzone = response.parse()\nprint(zone.id)\n```\n\n### Streaming Responses\n\nStream large responses:\n\n```python\nwith client.zones.with_streaming_response.create(\n    account={\"id\": \"023e105f4ecef8ad9ca31a8372d0c353\"},\n    name=\"example.com\",\n    type=\"full\",\n) as response:\n    print(response.headers.get(\"X-My-Header\"))\n    for line in response.iter_lines():\n        print(line)\n```\n\n## Pagination\n\nHandle paginated responses automatically or manually:\n\n```python\nfrom cloudflare import Cloudflare\n\nclient = Cloudflare()\n\n# Auto-pagination (recommended)\nall_zones = []\nfor zone in client.zones.list():\n    all_zones.append(zone)\n    print(zone.name)\n\n# Manual pagination\nfirst_page = client.zones.list(per_page=20)\nfor zone in first_page.result:\n    print(zone.name)\n\nif first_page.has_next_page():\n    print(f\"Next page info: {first_page.next_page_info()}\")\n    next_page = first_page.get_next_page()\n    for zone in next_page.result:\n        print(zone.name)\n```\n\n### Async Pagination\n\n```python\nimport asyncio\nfrom cloudflare import AsyncCloudflare\n\nclient = AsyncCloudflare()\n\nasync def main():\n    # Auto-pagination\n    all_accounts = []\n    async for account in client.accounts.list():\n        all_accounts.append(account)\n    print(all_accounts)\n\n    # Manual pagination\n    first_page = await client.accounts.list()\n    if first_page.has_next_page():\n        next_page = await first_page.get_next_page()\n        print(f\"Items: {len(next_page.result)}\")\n\nasyncio.run(main())\n```\n\n## Context Manager Usage\n\nUse context managers to ensure proper resource cleanup:\n\n```python\nfrom cloudflare import Cloudflare\n\nwith Cloudflare() as client:\n    zone = client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\n    print(zone.name)\n# HTTP client is automatically closed\n\n# Async context manager\nimport asyncio\nfrom cloudflare import AsyncCloudflare\n\nasync def main():\n    async with AsyncCloudflare() as client:\n        zone = await client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\n        print(zone.name)\n\nasyncio.run(main())\n```\n\n## Type Checking\n\nThe SDK includes full type annotations for use with mypy or other type checkers:\n\n```python\nfrom cloudflare import Cloudflare\nfrom cloudflare.types import Zone\n\nclient: Cloudflare = Cloudflare()\n\nzone: Zone = client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\nprint(zone.id)\nprint(zone.name)\n```\n\n## Custom/Undocumented Endpoints\n\nMake requests to endpoints not yet in the typed SDK:\n\n```python\nimport httpx\n\n# POST request to custom endpoint\nresponse = client.post(\n    \"/some/path\",\n    cast_to=httpx.Response,\n    body={\"some_prop\": \"foo\"},\n)\n\nprint(response.headers.get(\"x-foo\"))\n\n# GET request\nresponse = client.get(\n    \"/custom/endpoint\",\n    cast_to=httpx.Response,\n    options={\"params\": {\"filter\": \"active\"}},\n)\n```\n\n## Checking for Null vs. Missing Fields\n\nDistinguish between null values and missing fields:\n\n```python\nresponse = client.zones.get(zone_id=\"023e105f4ecef8ad9ca31a8372d0c353\")\n\nif response.my_field is None:\n    if \"my_field\" not in response.model_fields_set:\n        print(\"Field was missing entirely\")\n    else:\n        print(\"Field was explicitly null\")\n```\n\n## Useful Links\n\n- Documentation: https://developers.cloudflare.com/api/\n- SDK GitHub: https://github.com/cloudflare/cloudflare-python\n- API Keys: https://dash.cloudflare.com/profile/api-tokens\n- Workers Docs: https://developers.cloudflare.com/workers/\n- R2 Docs: https://developers.cloudflare.com/r2/\n- D1 Docs: https://developers.cloudflare.com/d1/\n- KV Docs: https://developers.cloudflare.com/kv/\n- Pages Docs: https://developers.cloudflare.com/pages/\n- Rate Limits: https://developers.cloudflare.com/fundamentals/api/reference/limits/\n"
  },
  {
    "path": "content/cloudflare/docs/workers-runtime/javascript/DOC.md",
    "content": "---\nname: workers-runtime\ndescription: \"Cloudflare Workers runtime for building edge functions with D1 databases, R2 storage, KV key-value, Durable Objects, Queues, Workers AI, and Vectorize bindings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: community\n  tags: \"cloudflare,workers,edge,d1,r2,kv,durable-objects,queues,ai,vectorize,wrangler\"\n---\n\n# Cloudflare Workers Runtime Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Cloudflare Workers expert. Help write code that runs on the Cloudflare Workers edge runtime using Wrangler and the Workers Runtime APIs.\n\n## Golden Rule: Use the Workers Runtime APIs with Wrangler\n\n**Tooling:** `wrangler` CLI (npm) + `@cloudflare/workers-types` (TypeScript types)\n\n**Installation:**\n```bash\nnpm create cloudflare@latest        # New project scaffold\nnpm install -D wrangler              # Per-project install\nnpm install -D @cloudflare/workers-types  # TypeScript types\n```\n\n**CRITICAL:** Do NOT confuse these two packages:\n- `wrangler` + Workers Runtime APIs = code that **runs on** the Cloudflare edge (this guide)\n- `cloudflare` npm package = REST API SDK for **managing** Cloudflare resources (zones, DNS, etc.) — a different surface entirely\n\n**IMPORTANT:** Do NOT use the deprecated `@cloudflare/wrangler` (v1 legacy) or third-party wrappers.\n\n## Worker Entry Point\n\nWorkers use ES module syntax with a default export containing handler functions:\n\n```typescript\nexport interface Env {\n  MY_KV: KVNamespace;\n  MY_DB: D1Database;\n  MY_BUCKET: R2Bucket;\n}\n\nexport default {\n  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {\n    const url = new URL(request.url);\n\n    if (url.pathname === \"/api/data\") {\n      return new Response(JSON.stringify({ ok: true }), {\n        headers: { \"Content-Type\": \"application/json\" },\n      });\n    }\n\n    return new Response(\"Not Found\", { status: 404 });\n  },\n};\n```\n\n**Key concepts:**\n- `request` — Standard Web API `Request` object\n- `env` — Contains all bindings (D1, R2, KV, Durable Objects, Queues, AI, etc.)\n- `ctx.waitUntil(promise)` — Keep the Worker alive for background work after sending a response\n- `ctx.passThroughOnException()` — Fall through to origin on unhandled errors\n\n## Configuration (wrangler.toml)\n\n```toml\nname = \"my-worker\"\nmain = \"src/index.ts\"\ncompatibility_date = \"2024-12-01\"\n\n[vars]\nAPI_URL = \"https://api.example.com\"\n\n[[d1_databases]]\nbinding = \"DB\"\ndatabase_name = \"my-database\"\ndatabase_id = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\n\n[[r2_buckets]]\nbinding = \"BUCKET\"\nbucket_name = \"my-bucket\"\n\n[[kv_namespaces]]\nbinding = \"KV\"\nid = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n\n[[queues.producers]]\nbinding = \"MY_QUEUE\"\nqueue = \"my-queue\"\n\n[[queues.consumers]]\nqueue = \"my-queue\"\n\n[durable_objects]\nbindings = [{ name = \"COUNTER\", class_name = \"Counter\" }]\n\n[[migrations]]\ntag = \"v1\"\nnew_classes = [\"Counter\"]\n```\n\n**Generate types from config:** `wrangler types` auto-generates the `Env` interface from your `wrangler.toml`.\n\n## D1 Database Binding\n\nD1 is Cloudflare's serverless SQLite database.\n\n### Prepared Statements\n\n```typescript\n// Single row\nconst user = await env.DB\n  .prepare(\"SELECT * FROM users WHERE id = ?\")\n  .bind(userId)\n  .first();\n\n// All rows\nconst { results } = await env.DB\n  .prepare(\"SELECT * FROM users WHERE active = ?\")\n  .bind(1)\n  .all();\n\n// Write operations\nconst { meta } = await env.DB\n  .prepare(\"INSERT INTO users (name, email) VALUES (?, ?)\")\n  .bind(\"Alice\", \"alice@example.com\")\n  .run();\nconsole.log(meta.last_row_id, meta.changes);\n```\n\n### Batch Operations\n\nBatch executes multiple statements in a single transaction:\n\n```typescript\nconst results = await env.DB.batch([\n  env.DB.prepare(\"INSERT INTO users (name) VALUES (?)\").bind(\"Alice\"),\n  env.DB.prepare(\"INSERT INTO users (name) VALUES (?)\").bind(\"Bob\"),\n  env.DB.prepare(\"SELECT COUNT(*) as count FROM users\"),\n]);\nconst count = results[2].results[0].count;\n```\n\n### Raw Queries\n\n```typescript\n// Execute raw SQL (no parameter binding — use for DDL only)\nconst result = await env.DB.exec(\n  \"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)\"\n);\n```\n\n**Result shape:** `{ results: Row[], success: boolean, meta: { changes, last_row_id, duration } }`\n\n## R2 Object Storage Binding\n\nR2 is S3-compatible object storage with zero egress fees.\n\n### Basic Operations\n\n```typescript\n// Upload\nawait env.BUCKET.put(\"uploads/image.png\", imageData, {\n  httpMetadata: { contentType: \"image/png\" },\n  customMetadata: { uploadedBy: \"user-123\" },\n});\n\n// Download\nconst object = await env.BUCKET.get(\"uploads/image.png\");\nif (object === null) {\n  return new Response(\"Not Found\", { status: 404 });\n}\nreturn new Response(object.body, {\n  headers: { \"Content-Type\": object.httpMetadata?.contentType ?? \"application/octet-stream\" },\n});\n\n// Check existence (metadata only)\nconst head = await env.BUCKET.head(\"uploads/image.png\");\n\n// Delete\nawait env.BUCKET.delete(\"uploads/image.png\");\n// Bulk delete\nawait env.BUCKET.delete([\"file1.txt\", \"file2.txt\", \"file3.txt\"]);\n```\n\n### Listing Objects\n\n```typescript\nconst listed = await env.BUCKET.list({ prefix: \"uploads/\", limit: 100 });\nfor (const obj of listed.objects) {\n  console.log(obj.key, obj.size, obj.uploaded);\n}\n\n// Pagination\nif (listed.truncated) {\n  const next = await env.BUCKET.list({ prefix: \"uploads/\", cursor: listed.cursor });\n}\n```\n\n### S3-Compatible Access (Outside Workers)\n\n```typescript\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n  region: \"auto\",\n  endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,\n  credentials: { accessKeyId: R2_ACCESS_KEY_ID, secretAccessKey: R2_SECRET_ACCESS_KEY },\n});\n\nawait s3.send(new PutObjectCommand({ Bucket: \"my-bucket\", Key: \"file.txt\", Body: \"hello\" }));\n```\n\n## KV Key-Value Store Binding\n\nKV is a globally distributed, eventually-consistent key-value store.\n\n```typescript\n// Write\nawait env.KV.put(\"session:abc123\", JSON.stringify({ userId: 1, role: \"admin\" }));\nawait env.KV.put(\"cache:page\", htmlContent, { expirationTtl: 3600 }); // 1 hour TTL\nawait env.KV.put(\"user:1\", \"data\", { metadata: { createdAt: Date.now() } });\n\n// Read\nconst value = await env.KV.get(\"session:abc123\");\nconst json = await env.KV.get(\"config:settings\", { type: \"json\" });\nconst { value: val, metadata } = await env.KV.getWithMetadata(\"user:1\");\n\n// Delete\nawait env.KV.delete(\"session:abc123\");\n\n// List keys\nconst keys = await env.KV.list({ prefix: \"session:\", limit: 50 });\nfor (const key of keys.keys) {\n  console.log(key.name, key.expiration, key.metadata);\n}\n```\n\n**IMPORTANT:** KV is eventually consistent. Writes may take up to 60 seconds to propagate globally. Use D1 or Durable Objects for strong consistency.\n\n## Durable Objects Binding\n\nDurable Objects provide strongly-consistent, single-instance coordination.\n\n### Defining a Durable Object\n\n```typescript\nimport { DurableObject } from \"cloudflare:workers\";\n\nexport class Counter extends DurableObject {\n  async increment(): Promise<number> {\n    let count = (await this.ctx.storage.get<number>(\"count\")) ?? 0;\n    count++;\n    await this.ctx.storage.put(\"count\", count);\n    return count;\n  }\n\n  async getCount(): Promise<number> {\n    return (await this.ctx.storage.get<number>(\"count\")) ?? 0;\n  }\n}\n```\n\n### Accessing from a Worker\n\n```typescript\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    const id = env.COUNTER.idFromName(\"global\");\n    const stub = env.COUNTER.get(id);\n\n    const count = await stub.increment(); // RPC call\n    return new Response(`Count: ${count}`);\n  },\n};\n```\n\n### Alarms (Scheduled Background Work)\n\n```typescript\nexport class Scheduler extends DurableObject {\n  async schedule(delayMs: number): Promise<void> {\n    await this.ctx.storage.setAlarm(Date.now() + delayMs);\n  }\n\n  async alarm(): Promise<void> {\n    // Runs at the scheduled time\n    await this.processScheduledWork();\n  }\n}\n```\n\n### WebSocket Hibernation\n\n```typescript\nexport class ChatRoom extends DurableObject {\n  async fetch(request: Request): Promise<Response> {\n    const [client, server] = Object.values(new WebSocketPair());\n    this.ctx.acceptWebSocket(server);\n    return new Response(null, { status: 101, webSocket: client });\n  }\n\n  async webSocketMessage(ws: WebSocket, message: string): Promise<void> {\n    // Broadcast to all connected clients\n    for (const client of this.ctx.getWebSockets()) {\n      client.send(message);\n    }\n  }\n\n  async webSocketClose(ws: WebSocket): Promise<void> {\n    ws.close();\n  }\n}\n```\n\n## Queues Binding\n\nQueues provide guaranteed at-least-once message delivery.\n\n### Producer\n\n```typescript\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    // Single message\n    await env.MY_QUEUE.send({ userId: 123, action: \"signup\" });\n\n    // Batch send\n    await env.MY_QUEUE.sendBatch([\n      { body: { event: \"page_view\", page: \"/home\" } },\n      { body: { event: \"page_view\", page: \"/about\" } },\n    ]);\n\n    return new Response(\"Queued\");\n  },\n};\n```\n\n### Consumer\n\n```typescript\nexport default {\n  async queue(batch: MessageBatch, env: Env): Promise<void> {\n    for (const msg of batch.messages) {\n      try {\n        await processEvent(msg.body);\n        msg.ack();\n      } catch (err) {\n        msg.retry(); // Requeue for retry\n      }\n    }\n  },\n};\n```\n\n## Workers AI Binding\n\nWorkers AI runs AI models on Cloudflare's GPU network.\n\n```typescript\n// Text generation\nconst response = await env.AI.run(\"@cf/meta/llama-3.1-8b-instruct\", {\n  messages: [\n    { role: \"system\", content: \"You are a helpful assistant.\" },\n    { role: \"user\", content: \"Explain edge computing in one sentence.\" },\n  ],\n});\nconsole.log(response.response);\n\n// Text embeddings\nconst embeddings = await env.AI.run(\"@cf/baai/bge-base-en-v1.5\", {\n  text: [\"Document about edge computing\", \"Document about databases\"],\n});\nconsole.log(embeddings.data); // Array of float arrays\n\n// Image classification\nconst result = await env.AI.run(\"@cf/microsoft/resnet-50\", {\n  image: await request.arrayBuffer(),\n});\n```\n\n## Vectorize Binding\n\nVectorize is Cloudflare's vector database for similarity search.\n\n```typescript\n// Insert vectors\nawait env.VECTORIZE_INDEX.insert([\n  { id: \"doc-1\", values: embeddingArray, metadata: { title: \"Edge Computing\" } },\n  { id: \"doc-2\", values: embeddingArray2, metadata: { title: \"Databases\" } },\n]);\n\n// Query (semantic search)\nconst results = await env.VECTORIZE_INDEX.query(queryVector, {\n  topK: 10,\n  returnValues: false,\n  returnMetadata: \"all\",\n  filter: { category: \"tech\" },\n});\nfor (const match of results.matches) {\n  console.log(match.id, match.score, match.metadata);\n}\n\n// Upsert (insert or update)\nawait env.VECTORIZE_INDEX.upsert([{ id: \"doc-1\", values: updatedEmbedding }]);\n\n// Delete\nawait env.VECTORIZE_INDEX.deleteByIds([\"doc-1\", \"doc-2\"]);\n```\n\n## Error Handling\n\n```typescript\nexport default {\n  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {\n    try {\n      const data = await env.DB.prepare(\"SELECT * FROM users\").all();\n      return Response.json(data.results);\n    } catch (err) {\n      // D1 errors include SQL constraint violations, type errors\n      console.error(\"D1 error:\", err);\n      return new Response(\"Database error\", { status: 500 });\n    }\n  },\n};\n```\n\n**Common pitfalls:**\n\n- **Error 1101 (floating promises):** Always `await` or use `ctx.waitUntil()` for async operations\n- **CPU time limits:** Free plan = 10ms, Paid = 30s. Offload heavy work to Queues or Durable Objects\n- **Worker size limit:** 10MB compressed after bundling (includes dependencies)\n- **Subrequest limit:** 50 `fetch()` calls per invocation (1000 on paid plans)\n\n```typescript\n// BAD: floating promise causes Error 1101\nfetch(\"https://analytics.example.com/track\");\n\n// GOOD: use ctx.waitUntil for fire-and-forget\nctx.waitUntil(fetch(\"https://analytics.example.com/track\"));\n```\n\n## Testing\n\n### Local Development\n\n```bash\nwrangler dev              # Start local dev server with Miniflare\nwrangler dev --remote     # Run against real Cloudflare APIs\n```\n\n### Vitest Integration\n\n```typescript\n// vitest.config.ts\nimport { defineWorkersConfig } from \"@cloudflare/vitest-pool-workers/config\";\n\nexport default defineWorkersConfig({\n  test: { poolOptions: { workers: { wrangler: { configPath: \"./wrangler.toml\" } } } },\n});\n```\n\n```typescript\n// test/index.test.ts\nimport { env, createExecutionContext, waitOnExecutionContext } from \"cloudflare:test\";\nimport worker from \"../src/index\";\n\nit(\"returns 200\", async () => {\n  const request = new Request(\"http://localhost/api/data\");\n  const ctx = createExecutionContext();\n  const response = await worker.fetch(request, env, ctx);\n  await waitOnExecutionContext(ctx);\n  expect(response.status).toBe(200);\n});\n```\n\n## Useful Links\n\n- Cloudflare Workers docs: https://developers.cloudflare.com/workers/\n- Wrangler CLI reference: https://developers.cloudflare.com/workers/wrangler/\n- D1 documentation: https://developers.cloudflare.com/d1/\n- R2 documentation: https://developers.cloudflare.com/r2/\n- KV documentation: https://developers.cloudflare.com/kv/\n- Durable Objects: https://developers.cloudflare.com/durable-objects/\n- Workers AI models: https://developers.cloudflare.com/workers-ai/models/\n- Vectorize: https://developers.cloudflare.com/vectorize/\n- Workers examples: https://developers.cloudflare.com/workers/examples/\n"
  },
  {
    "path": "content/cloudflare/docs/workers-runtime/python/DOC.md",
    "content": "---\nname: workers-runtime\ndescription: \"Cloudflare Workers runtime for building edge functions in Python with D1 databases, R2 storage, KV key-value, Durable Objects, and Queues bindings\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: community\n  tags: \"cloudflare,workers,edge,python,d1,r2,kv,durable-objects,queues\"\n---\n\n# Cloudflare Workers Runtime Coding Guidelines (Python)\n\nYou are a Cloudflare Workers expert. Help write Python code that runs on the Cloudflare Workers edge runtime.\n\n## Golden Rule: Use Python Workers with Wrangler\n\nPython Workers run natively on the Cloudflare edge using Pyodide (CPython compiled to WebAssembly).\n\n**Tooling:** `wrangler` CLI (npm) for deploying Python Workers\n\n**Installation:**\n```bash\nnpm install -D wrangler\n```\n\n**CRITICAL:** Do NOT confuse these:\n- Python Workers via `wrangler` = Python code that **runs on** the Cloudflare edge (this guide)\n- `cloudflare` PyPI package = REST API SDK for **managing** Cloudflare resources — a different surface entirely\n\n**IMPORTANT:** Do NOT use:\n- `python-cloudflare` (third-party, deprecated)\n- `cloudflare` PyPI package for edge compute (that is for API management only)\n\n## Worker Entry Point\n\nPython Workers use the `workers` module with a class-based handler:\n\n```python\nfrom workers import Response, Request\n\nasync def on_fetch(request, env):\n    url = request.url\n    if \"/api/data\" in url:\n        return Response.json({\"ok\": True})\n    return Response(\"Not Found\", status=404)\n```\n\n**Alternative class-based syntax:**\n\n```python\nfrom workers import WorkerEntrypoint, Response\n\nclass Worker(WorkerEntrypoint):\n    async def on_fetch(self, request):\n        return Response(\"Hello from Python Workers!\")\n```\n\n**Key concepts:**\n- `request` — Standard Request object (similar to Web API)\n- `env` — Contains all bindings (D1, R2, KV, etc.) as attributes\n- `on_fetch` — The handler function invoked for each HTTP request\n\n## Configuration (wrangler.toml)\n\n```toml\nname = \"my-python-worker\"\nmain = \"src/entry.py\"\ncompatibility_date = \"2024-12-01\"\ncompatibility_flags = [\"python_workers\"]\n\n[vars]\nAPI_URL = \"https://api.example.com\"\n\n[[d1_databases]]\nbinding = \"DB\"\ndatabase_name = \"my-database\"\ndatabase_id = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\n\n[[r2_buckets]]\nbinding = \"BUCKET\"\nbucket_name = \"my-bucket\"\n\n[[kv_namespaces]]\nbinding = \"KV\"\nid = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n```\n\n**IMPORTANT:** The `compatibility_flags = [\"python_workers\"]` flag is required for Python Workers.\n\n## D1 Database Binding\n\n```python\nasync def on_fetch(request, env):\n    # Single row\n    user = await env.DB.prepare(\n        \"SELECT * FROM users WHERE id = ?\"\n    ).bind(user_id).first()\n\n    # All rows\n    result = await env.DB.prepare(\n        \"SELECT * FROM users WHERE active = ?\"\n    ).bind(1).all()\n    users = result.results\n\n    # Write operation\n    meta = await env.DB.prepare(\n        \"INSERT INTO users (name, email) VALUES (?, ?)\"\n    ).bind(\"Alice\", \"alice@example.com\").run()\n    print(meta.meta.last_row_id, meta.meta.changes)\n\n    return Response.json({\"users\": users})\n```\n\n### Batch Operations\n\n```python\nasync def on_fetch(request, env):\n    results = await env.DB.batch([\n        env.DB.prepare(\"INSERT INTO users (name) VALUES (?)\").bind(\"Alice\"),\n        env.DB.prepare(\"INSERT INTO users (name) VALUES (?)\").bind(\"Bob\"),\n        env.DB.prepare(\"SELECT COUNT(*) as count FROM users\"),\n    ])\n    count = results[2].results[0][\"count\"]\n    return Response.json({\"count\": count})\n```\n\n### Raw Queries\n\n```python\nawait env.DB.exec(\n    \"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)\"\n)\n```\n\n## R2 Object Storage Binding\n\n```python\nasync def on_fetch(request, env):\n    # Upload\n    body = await request.bytes()\n    await env.BUCKET.put(\"uploads/file.bin\", body)\n\n    # Download\n    obj = await env.BUCKET.get(\"uploads/file.bin\")\n    if obj is None:\n        return Response(\"Not Found\", status=404)\n    data = await obj.bytes()\n    return Response(data, headers={\"Content-Type\": \"application/octet-stream\"})\n\n    # Check existence\n    head = await env.BUCKET.head(\"uploads/file.bin\")\n\n    # Delete\n    await env.BUCKET.delete(\"uploads/file.bin\")\n```\n\n### Listing Objects\n\n```python\nlisted = await env.BUCKET.list(prefix=\"uploads/\", limit=100)\nfor obj in listed.objects:\n    print(obj.key, obj.size, obj.uploaded)\n\n# Pagination\nif listed.truncated:\n    next_page = await env.BUCKET.list(prefix=\"uploads/\", cursor=listed.cursor)\n```\n\n## KV Key-Value Store Binding\n\n```python\nasync def on_fetch(request, env):\n    # Write\n    await env.KV.put(\"session:abc123\", '{\"userId\": 1, \"role\": \"admin\"}')\n    await env.KV.put(\"cache:page\", html_content, expiration_ttl=3600)\n\n    # Read\n    value = await env.KV.get(\"session:abc123\")\n    json_value = await env.KV.get(\"config:settings\", type=\"json\")\n\n    # Read with metadata\n    result = await env.KV.get_with_metadata(\"user:1\")\n    value, metadata = result.value, result.metadata\n\n    # Delete\n    await env.KV.delete(\"session:abc123\")\n\n    # List keys\n    keys = await env.KV.list(prefix=\"session:\", limit=50)\n    for key in keys.keys:\n        print(key.name, key.expiration)\n\n    return Response.json({\"value\": value})\n```\n\n**IMPORTANT:** KV is eventually consistent. Writes may take up to 60 seconds to propagate globally.\n\n## Durable Objects Binding\n\n### Defining a Durable Object\n\n```python\nfrom workers import DurableObject, Response\n\nclass Counter(DurableObject):\n    async def increment(self):\n        count = await self.ctx.storage.get(\"count\") or 0\n        count += 1\n        await self.ctx.storage.put(\"count\", count)\n        return count\n\n    async def get_count(self):\n        return await self.ctx.storage.get(\"count\") or 0\n```\n\n### Accessing from a Worker\n\n```python\nasync def on_fetch(request, env):\n    obj_id = env.COUNTER.id_from_name(\"global\")\n    stub = env.COUNTER.get(obj_id)\n\n    count = await stub.increment()\n    return Response(f\"Count: {count}\")\n```\n\n### Alarms\n\n```python\nimport time\n\nclass Scheduler(DurableObject):\n    async def schedule(self, delay_ms):\n        await self.ctx.storage.set_alarm(time.time() * 1000 + delay_ms)\n\n    async def alarm(self):\n        await self.process_scheduled_work()\n```\n\n## Queues Binding\n\n### Producer\n\n```python\nasync def on_fetch(request, env):\n    await env.MY_QUEUE.send({\"user_id\": 123, \"action\": \"signup\"})\n\n    await env.MY_QUEUE.send_batch([\n        {\"body\": {\"event\": \"page_view\", \"page\": \"/home\"}},\n        {\"body\": {\"event\": \"page_view\", \"page\": \"/about\"}},\n    ])\n\n    return Response(\"Queued\")\n```\n\n### Consumer\n\n```python\nasync def queue(batch, env):\n    for msg in batch.messages:\n        try:\n            await process_event(msg.body)\n            msg.ack()\n        except Exception:\n            msg.retry()\n```\n\n## Error Handling\n\n```python\nasync def on_fetch(request, env):\n    try:\n        data = await env.DB.prepare(\"SELECT * FROM users\").all()\n        return Response.json(data.results)\n    except Exception as e:\n        print(f\"Error: {e}\")\n        return Response(\"Internal Server Error\", status=500)\n```\n\n**Common pitfalls:**\n- **Floating async calls:** Always `await` async operations or they will be silently dropped\n- **CPU time limits:** Free plan = 10ms, Paid = 30s\n- **Python package limitations:** Only pure-Python packages and select compiled packages via Pyodide are supported\n- **No filesystem access:** Workers run in a sandboxed environment — use KV, R2, or D1 for persistence\n\n**Supported Python packages (via Pyodide):**\n- Standard library modules (json, re, datetime, collections, etc.)\n- `micropip` for installing pure-Python packages at runtime\n- Select compiled packages: numpy, pandas, scipy, etc. (check Pyodide compatibility)\n\n## Testing\n\n### Local Development\n\n```bash\nwrangler dev              # Starts local dev server\nwrangler dev --remote     # Run against real Cloudflare APIs\n```\n\n### Unit Testing\n\n```python\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_handler():\n    # Create mock request and env\n    request = MockRequest(\"http://localhost/api/data\")\n    env = MockEnv()\n\n    response = await on_fetch(request, env)\n    assert response.status == 200\n```\n\n**IMPORTANT:** Python Workers testing is best done via `wrangler dev` with integration-style tests. The Vitest pool (`@cloudflare/vitest-pool-workers`) is designed for JavaScript — for Python, use `wrangler dev --remote` with HTTP client tests.\n\n## Useful Links\n\n- Python Workers documentation: https://developers.cloudflare.com/workers/languages/python/\n- Cloudflare Workers docs: https://developers.cloudflare.com/workers/\n- Wrangler CLI reference: https://developers.cloudflare.com/workers/wrangler/\n- D1 documentation: https://developers.cloudflare.com/d1/\n- R2 documentation: https://developers.cloudflare.com/r2/\n- KV documentation: https://developers.cloudflare.com/kv/\n- Pyodide packages: https://pyodide.org/en/stable/usage/packages-in-pyodide.html\n"
  },
  {
    "path": "content/cloudpickle/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cloudpickle Python package guide for serializing lambdas, closures, and interactive code\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cloudpickle,python,serialization,pickle,distributed-computing\"\n---\n\n# cloudpickle Python Package Guide\n\n## Golden Rule\n\nUse `cloudpickle` when the standard library `pickle` module cannot serialize the Python object you need to send between short-lived Python processes, especially lambdas, nested functions, and functions or classes defined interactively in `__main__`, a shell, or a notebook. Treat the result as trusted, short-lived process-to-process data: upstream documents that producer and consumer should run the exact same Python version, and long-term object storage is explicitly discouraged.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"cloudpickle==3.1.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"cloudpickle==3.1.2\"\npoetry add \"cloudpickle==3.1.2\"\n```\n\nUpstream package metadata for `3.1.2` says:\n\n- `Requires-Python: >=3.8`\n- no mandatory runtime dependencies\n- classifiers list CPython and PyPy, with Python `3.8` through `3.14`\n\n## Initialize And Setup\n\n`cloudpickle` has no client object, auth flow, or environment variables. Import it where you serialize values, and use standard `pickle` or `cloudpickle` to deserialize them.\n\n```python\nimport cloudpickle\nimport pickle\n```\n\nThe top-level APIs you will typically use are:\n\n- `cloudpickle.dumps(obj)` to serialize to in-memory bytes\n- `cloudpickle.dump(obj, file)` to write to a file-like object\n- `pickle.loads(data)` or `cloudpickle.loads(data)` to deserialize bytes\n- `pickle.load(file)` or `cloudpickle.load(file)` to deserialize from a file-like object\n\n`cloudpickle` does not ship a separate unpickling format. Its `load` and `loads` names are convenience aliases to `pickle.load` and `pickle.loads`.\n\n## Core Usage\n\n### Serialize a lambda or nested function\n\n```python\nimport cloudpickle\nimport pickle\n\nscale = 3\ntransform = lambda value: value * scale\n\npayload = cloudpickle.dumps(transform)\nrestored = pickle.loads(payload)\n\nprint(restored(5))\n```\n\n### Serialize a function defined in `__main__`\n\n```python\nimport cloudpickle\nimport pickle\n\nPREFIX = \"task:\"\n\ndef build_name(item_id):\n    return f\"{PREFIX}{item_id}\"\n\npayload = cloudpickle.dumps(build_name)\nrestored = pickle.loads(payload)\n\nprint(restored(42))\n```\n\n### Write payloads to a file\n\n```python\nimport cloudpickle\nimport pickle\nfrom pathlib import Path\n\ndef make_record(name):\n    return {\"name\": name.upper()}\n\npath = Path(\"payload.pkl\")\n\nwith path.open(\"wb\") as handle:\n    cloudpickle.dump(make_record, handle)\n\nwith path.open(\"rb\") as handle:\n    restored = pickle.load(handle)\n\nprint(restored(\"alice\"))\n```\n\n### Force an importable module to serialize by value\n\nBy default, importable functions and classes are serialized by reference, which means the unpickling environment must be able to import the same module. If you are actively developing a local module and remote workers do not have that version installed yet, upstream provides `register_pickle_by_value(module)` as an explicit override.\n\n```python\nimport cloudpickle\nimport my_worker_code\n\ncloudpickle.register_pickle_by_value(my_worker_code)\ntry:\n    payload = cloudpickle.dumps(my_worker_code.transform)\nfinally:\n    cloudpickle.unregister_pickle_by_value(my_worker_code)\n```\n\nPass the imported module object itself, not a module name string.\n\n## Configuration And Compatibility\n\nThere is no runtime service configuration. The settings that matter are the pickle protocol and your Python-version compatibility assumptions.\n\nUse the default protocol when both sides run the same Python version:\n\n```python\nimport cloudpickle\n\npayload = cloudpickle.dumps(obj)\n```\n\nIf you need an older protocol number, pass it explicitly from `pickle`:\n\n```python\nimport cloudpickle\nimport pickle\n\npayload = cloudpickle.dumps(obj, protocol=pickle.DEFAULT_PROTOCOL)\n```\n\nImportant upstream behavior:\n\n- `protocol=None` uses `cloudpickle.DEFAULT_PROTOCOL`, which is an alias for `pickle.HIGHEST_PROTOCOL`\n- the default favors communication speed between processes running the same Python version\n- using `pickle.DEFAULT_PROTOCOL` can help when you need an older pickle protocol, but upstream does not guarantee compatibility across Python versions because `cloudpickle` relies on Python implementation details\n\n## Common Pitfalls\n\n- Never unpickle data from untrusted sources. Upstream repeats the standard pickle security warning: loading pickle data can execute arbitrary code.\n- Do not use `cloudpickle` as a stable long-term storage format for saved application state.\n- Keep the producer and consumer on the exact same Python version.\n- `register_pickle_by_value()` is experimental. Upstream documents failure cases when a by-value function or class body relies on imports that are unavailable in the unpickling environment.\n- Avoid mixing assumptions about by-reference and by-value code paths. Upstream also documents cases where a function pickled by reference can fail when it depends at runtime on a function that was pickled by value.\n- `register_pickle_by_value()` and `unregister_pickle_by_value()` expect imported module objects. They raise `ValueError` for invalid inputs or for modules that were not registered.\n\n## Version-Sensitive Notes For 3.1.2\n\n- The published `3.1.2` package sets `__version__ = \"3.1.2\"`.\n- The public top-level API exports `Pickler`, `CloudPickler`, `dump`, `dumps`, `load`, `loads`, `register_pickle_by_value`, and `unregister_pickle_by_value`.\n- `CloudPickler` is a backward-compatible alias for `Pickler`.\n- PyPI metadata for `3.1.2` advertises Python `>=3.8` and classifiers through Python `3.14`.\n\n## Official Sources\n\n- GitHub repository and maintainer README: `https://github.com/cloudpipe/cloudpickle`\n- PyPI package page: `https://pypi.org/project/cloudpickle/`\n"
  },
  {
    "path": "content/cockroachdb/docs/distributed-db/DOC.md",
    "content": "---\nname: distributed-db\ndescription: \"CockroachDB with node-postgres (pg) - JavaScript guide for connecting to CockroachDB from Node.js applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.16.3\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"cockroachdb,distributed-db,sql,postgres,database\"\n---\n\n# CockroachDB with node-postgres (pg) - JavaScript Guide\n\n## Golden Rule\n\n**ALWAYS use the `pg` (node-postgres) package version 8.16.3 or later** to connect to CockroachDB from Node.js applications.\n\n```bash\nnpm install pg\n```\n\nCockroachDB is PostgreSQL wire-compatible, meaning it uses the PostgreSQL protocol. The official recommendation is to use the standard PostgreSQL `pg` driver (node-postgres) for JavaScript/Node.js applications.\n\n**DO NOT use:**\n- Unofficial or deprecated CockroachDB-specific packages\n- Old versions of `pg` that may not support modern features\n- Random third-party wrappers without proper maintenance\n\n**ALWAYS use `pg` (node-postgres)** - it is the officially supported and recommended driver.\n\n---\n\n## Installation\n\n### Basic Installation\n\n```bash\nnpm install pg\n```\n\n### With TypeScript Support\n\n```bash\nnpm install pg @types/pg\n```\n\n### Additional Dependencies (Optional)\n\nFor SSL connections with custom certificates:\n\n```bash\nnpm install pg fs\n```\n\n---\n\n## Environment Variables\n\n### Basic Configuration\n\nCreate a `.env` file:\n\n```bash\n# Database connection\nDATABASE_URL=postgresql://root@localhost:26257/defaultdb?sslmode=disable\n\n# Or separate variables\nDB_USER=root\nDB_HOST=localhost\nDB_PORT=26257\nDB_NAME=defaultdb\nDB_PASSWORD=\n```\n\n### Secure Production Configuration\n\n```bash\n# CockroachDB Serverless/Cloud\nDATABASE_URL=postgresql://username:password@host.cockroachlabs.cloud:26257/database?sslmode=verify-full\n\n# With certificate paths\nDB_USER=maxroach\nDB_HOST=blue-dog-147.6wr.cockroachlabs.cloud\nDB_PORT=26257\nDB_NAME=defaultdb\nDB_PASSWORD=YourSecurePassword\nDB_SSL_MODE=verify-full\nDB_SSL_ROOT_CERT=/path/to/root.crt\nDB_SSL_CERT=/path/to/client.crt\nDB_SSL_KEY=/path/to/client.key\n```\n\n### Loading Environment Variables\n\n```javascript\nrequire('dotenv').config();\n\nconst config = {\n  user: process.env.DB_USER || 'root',\n  host: process.env.DB_HOST || 'localhost',\n  database: process.env.DB_NAME || 'defaultdb',\n  password: process.env.DB_PASSWORD || '',\n  port: parseInt(process.env.DB_PORT) || 26257,\n};\n```\n\n---\n\n## Initialization\n\n### Basic Client Connection\n\n```javascript\nconst { Client } = require('pg');\n\nconst client = new Client({\n  user: 'root',\n  host: 'localhost',\n  database: 'defaultdb',\n  port: 26257,\n  ssl: false\n});\n\nclient.connect()\n  .then(() => console.log('Connected to CockroachDB'))\n  .catch(err => console.error('Connection error', err.stack));\n```\n\n### Connection Pool (Recommended)\n\n```javascript\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n  user: 'root',\n  host: 'localhost',\n  database: 'defaultdb',\n  port: 26257,\n  max: 10,                    // Maximum pool size\n  min: 2,                     // Minimum pool size\n  idleTimeoutMillis: 30000,   // Close idle clients after 30 seconds\n  connectionTimeoutMillis: 2000, // Return error after 2 seconds if connection unavailable\n});\n\n// Test the connection\npool.query('SELECT NOW()', (err, res) => {\n  if (err) {\n    console.error('Error executing query', err.stack);\n  } else {\n    console.log('Connected to CockroachDB:', res.rows[0]);\n  }\n});\n```\n\n### Async/Await Pool Connection\n\n```javascript\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n  user: 'root',\n  host: 'localhost',\n  database: 'defaultdb',\n  port: 26257,\n});\n\nasync function testConnection() {\n  try {\n    const client = await pool.connect();\n    const res = await client.query('SELECT version()');\n    console.log('CockroachDB version:', res.rows[0].version);\n    client.release();\n  } catch (err) {\n    console.error('Error:', err);\n  }\n}\n\ntestConnection();\n```\n\n### SSL Configuration for Production\n\n```javascript\nconst { Pool } = require('pg');\nconst fs = require('fs');\n\nconst pool = new Pool({\n  user: 'maxroach',\n  host: 'blue-dog-147.cockroachlabs.cloud',\n  database: 'defaultdb',\n  password: 'YourPassword',\n  port: 26257,\n  ssl: {\n    rejectUnauthorized: true,\n    ca: fs.readFileSync('/path/to/root.crt').toString(),\n    cert: fs.readFileSync('/path/to/client.crt').toString(),\n    key: fs.readFileSync('/path/to/client.key').toString(),\n  },\n});\n```\n\n### Connection String Format\n\n```javascript\nconst { Pool } = require('pg');\n\n// Local insecure cluster\nconst pool = new Pool({\n  connectionString: 'postgresql://root@localhost:26257/defaultdb?sslmode=disable'\n});\n\n// Production secure cluster\nconst pool = new Pool({\n  connectionString: 'postgresql://user:password@host.cockroachlabs.cloud:26257/database?sslmode=verify-full'\n});\n\n// With environment variable\nconst pool = new Pool({\n  connectionString: process.env.DATABASE_URL\n});\n```\n\n### Complete Initialization with Error Handling\n\n```javascript\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n  user: process.env.DB_USER || 'root',\n  host: process.env.DB_HOST || 'localhost',\n  database: process.env.DB_NAME || 'defaultdb',\n  password: process.env.DB_PASSWORD || '',\n  port: parseInt(process.env.DB_PORT) || 26257,\n  max: 20,\n  min: 5,\n  idleTimeoutMillis: 300000,  // 5 minutes\n  connectionTimeoutMillis: 5000,\n});\n\npool.on('error', (err, client) => {\n  console.error('Unexpected error on idle client', err);\n  process.exit(-1);\n});\n\npool.on('connect', () => {\n  console.log('New client connected to CockroachDB pool');\n});\n\npool.on('remove', () => {\n  console.log('Client removed from pool');\n});\n\nasync function initializeDatabase() {\n  const client = await pool.connect();\n  try {\n    await client.query('SELECT 1');\n    console.log('Database connection established');\n  } catch (err) {\n    console.error('Failed to connect to database:', err);\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ninitializeDatabase();\n```\n\n---\n\n## Core API Operations\n\n### Basic Queries\n\n#### Simple SELECT Query\n\n```javascript\nconst { Pool } = require('pg');\nconst pool = new Pool({ connectionString: process.env.DATABASE_URL });\n\nasync function getUsers() {\n  const client = await pool.connect();\n  try {\n    const result = await client.query('SELECT * FROM users');\n    console.log('Users:', result.rows);\n    return result.rows;\n  } catch (err) {\n    console.error('Query error:', err);\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ngetUsers();\n```\n\n#### Parameterized Query\n\n```javascript\nasync function getUserById(id) {\n  const client = await pool.connect();\n  try {\n    const query = 'SELECT * FROM users WHERE id = $1';\n    const result = await client.query(query, [id]);\n    return result.rows[0];\n  } catch (err) {\n    console.error('Error fetching user:', err);\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ngetUserById('123e4567-e89b-12d3-a456-426614174000');\n```\n\n#### Multiple Parameters\n\n```javascript\nasync function searchUsers(city, minAge) {\n  const client = await pool.connect();\n  try {\n    const query = 'SELECT * FROM users WHERE city = $1 AND age >= $2';\n    const result = await client.query(query, [city, minAge]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nsearchUsers('Seattle', 25);\n```\n\n### INSERT Operations\n\n#### Single Row Insert\n\n```javascript\nasync function createUser(name, email, city) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO users (name, email, city)\n      VALUES ($1, $2, $3)\n      RETURNING *\n    `;\n    const result = await client.query(query, [name, email, city]);\n    console.log('Created user:', result.rows[0]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\ncreateUser('John Doe', 'john@example.com', 'New York');\n```\n\n#### Multiple Row Insert\n\n```javascript\nasync function createMultipleUsers(users) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO users (name, email, city)\n      VALUES\n        ($1, $2, $3),\n        ($4, $5, $6),\n        ($7, $8, $9)\n      RETURNING id, name\n    `;\n    const values = users.flatMap(u => [u.name, u.email, u.city]);\n    const result = await client.query(query, values);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ncreateMultipleUsers([\n  { name: 'Alice', email: 'alice@example.com', city: 'Boston' },\n  { name: 'Bob', email: 'bob@example.com', city: 'Chicago' },\n  { name: 'Carol', email: 'carol@example.com', city: 'Denver' }\n]);\n```\n\n#### Insert with Default Values\n\n```javascript\nasync function createDriver(city) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO drivers (id, city, created_at)\n      VALUES (gen_random_uuid(), $1, now())\n      RETURNING *\n    `;\n    const result = await client.query(query, [city]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\ncreateDriver('Seattle');\n```\n\n#### Insert with ON CONFLICT\n\n```javascript\nasync function upsertUser(email, name, city) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO users (email, name, city)\n      VALUES ($1, $2, $3)\n      ON CONFLICT (email)\n      DO UPDATE SET\n        name = EXCLUDED.name,\n        city = EXCLUDED.city,\n        updated_at = now()\n      RETURNING *\n    `;\n    const result = await client.query(query, [email, name, city]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\nupsertUser('john@example.com', 'John Smith', 'Los Angeles');\n```\n\n### UPDATE Operations\n\n#### Simple Update\n\n```javascript\nasync function updateUserCity(userId, newCity) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      UPDATE users\n      SET city = $1, updated_at = now()\n      WHERE id = $2\n      RETURNING *\n    `;\n    const result = await client.query(query, [newCity, userId]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\nupdateUserCity('123e4567-e89b-12d3-a456-426614174000', 'Portland');\n```\n\n#### Conditional Update\n\n```javascript\nasync function activateUser(email) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      UPDATE users\n      SET status = 'active', activated_at = now()\n      WHERE email = $1 AND status = 'pending'\n      RETURNING id, email, status\n    `;\n    const result = await client.query(query, [email]);\n    if (result.rowCount === 0) {\n      throw new Error('User not found or already active');\n    }\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\nactivateUser('john@example.com');\n```\n\n#### Bulk Update\n\n```javascript\nasync function updateVehicleStatus(city, newStatus) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      UPDATE vehicles\n      SET status = $1\n      WHERE city = $2\n      RETURNING id, status\n    `;\n    const result = await client.query(query, [newStatus, city]);\n    console.log(`Updated ${result.rowCount} vehicles`);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nupdateVehicleStatus('New York', 'available');\n```\n\n### DELETE Operations\n\n#### Simple Delete\n\n```javascript\nasync function deleteUser(userId) {\n  const client = await pool.connect();\n  try {\n    const query = 'DELETE FROM users WHERE id = $1 RETURNING *';\n    const result = await client.query(query, [userId]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\ndeleteUser('123e4567-e89b-12d3-a456-426614174000');\n```\n\n#### Conditional Delete\n\n```javascript\nasync function deleteInactiveUsers(daysInactive) {\n  const client = await pool.connect();\n  try {\n    const result = await client.query(\n      `DELETE FROM users\n       WHERE last_login < now() - make_interval(days => $1)\n       RETURNING id, email`,\n      [daysInactive]\n    );\n    console.log(`Deleted ${result.rowCount} inactive users`);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ndeleteInactiveUsers(90);\n```\n\n#### Delete with JOIN\n\n```javascript\nasync function deleteUserOrders(userId) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      DELETE FROM orders\n      WHERE user_id = $1\n      RETURNING id, total_amount\n    `;\n    const result = await client.query(query, [userId]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ndeleteUserOrders('123e4567-e89b-12d3-a456-426614174000');\n```\n\n---\n\n## Transactions\n\n### Basic Transaction\n\n```javascript\nasync function transferFunds(fromAccount, toAccount, amount) {\n  const client = await pool.connect();\n  try {\n    await client.query('BEGIN');\n\n    // Deduct from sender\n    await client.query(\n      'UPDATE accounts SET balance = balance - $1 WHERE id = $2',\n      [amount, fromAccount]\n    );\n\n    // Add to receiver\n    await client.query(\n      'UPDATE accounts SET balance = balance + $1 WHERE id = $2',\n      [amount, toAccount]\n    );\n\n    await client.query('COMMIT');\n    console.log('Transfer completed successfully');\n  } catch (err) {\n    await client.query('ROLLBACK');\n    console.error('Transfer failed, rolled back:', err);\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ntransferFunds('account-1', 'account-2', 100.50);\n```\n\n### Transaction with Savepoints\n\n```javascript\nasync function complexTransaction() {\n  const client = await pool.connect();\n  try {\n    await client.query('BEGIN');\n\n    // First operation\n    await client.query('INSERT INTO logs (message) VALUES ($1)', ['Started']);\n\n    // Create savepoint\n    await client.query('SAVEPOINT sp1');\n\n    try {\n      await client.query('INSERT INTO users (email) VALUES ($1)', ['test@example.com']);\n    } catch (err) {\n      // Rollback to savepoint on error\n      await client.query('ROLLBACK TO SAVEPOINT sp1');\n      console.log('User insert failed, rolled back to savepoint');\n    }\n\n    // Continue with transaction\n    await client.query('INSERT INTO logs (message) VALUES ($1)', ['Completed']);\n\n    await client.query('COMMIT');\n  } catch (err) {\n    await client.query('ROLLBACK');\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ncomplexTransaction();\n```\n\n### Transaction with Retry Logic (CockroachDB Specific)\n\n```javascript\nasync function transferWithRetry(fromAccount, toAccount, amount, maxRetries = 3) {\n  let retries = 0;\n\n  while (retries < maxRetries) {\n    const client = await pool.connect();\n    try {\n      await client.query('BEGIN');\n\n      const fromResult = await client.query(\n        'UPDATE accounts SET balance = balance - $1 WHERE id = $2 RETURNING balance',\n        [amount, fromAccount]\n      );\n\n      if (fromResult.rows[0].balance < 0) {\n        throw new Error('Insufficient funds');\n      }\n\n      await client.query(\n        'UPDATE accounts SET balance = balance + $1 WHERE id = $2',\n        [amount, toAccount]\n      );\n\n      await client.query('COMMIT');\n      client.release();\n      return { success: true, retries };\n\n    } catch (err) {\n      await client.query('ROLLBACK');\n      client.release();\n\n      // Check if it's a serialization error (40001)\n      if (err.code === '40001' && retries < maxRetries - 1) {\n        retries++;\n        console.log(`Retrying transaction (attempt ${retries + 1})`);\n        await new Promise(resolve => setTimeout(resolve, Math.random() * 100));\n        continue;\n      }\n\n      throw err;\n    }\n  }\n\n  throw new Error('Transaction failed after maximum retries');\n}\n\ntransferWithRetry('account-1', 'account-2', 100.50);\n```\n\n### Read-Only Transaction\n\n```javascript\nasync function getAccountSummary(userId) {\n  const client = await pool.connect();\n  try {\n    await client.query('BEGIN TRANSACTION READ ONLY');\n\n    const userResult = await client.query(\n      'SELECT * FROM users WHERE id = $1',\n      [userId]\n    );\n\n    const accountsResult = await client.query(\n      'SELECT * FROM accounts WHERE user_id = $1',\n      [userId]\n    );\n\n    const transactionsResult = await client.query(\n      'SELECT * FROM transactions WHERE user_id = $1 ORDER BY created_at DESC LIMIT 10',\n      [userId]\n    );\n\n    await client.query('COMMIT');\n\n    return {\n      user: userResult.rows[0],\n      accounts: accountsResult.rows,\n      recentTransactions: transactionsResult.rows\n    };\n  } catch (err) {\n    await client.query('ROLLBACK');\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\ngetAccountSummary('user-123');\n```\n\n---\n\n## Advanced Features\n\n### JSON/JSONB Operations\n\n#### Inserting JSON Data\n\n```javascript\nasync function createProduct(name, metadata) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO products (name, metadata)\n      VALUES ($1, $2::jsonb)\n      RETURNING *\n    `;\n    const result = await client.query(query, [name, JSON.stringify(metadata)]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\ncreateProduct('Laptop', {\n  brand: 'Dell',\n  specs: { ram: '16GB', storage: '512GB SSD' },\n  tags: ['electronics', 'computers']\n});\n```\n\n#### Querying JSON Fields\n\n```javascript\nasync function findProductsByBrand(brand) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT * FROM products\n      WHERE metadata->>'brand' = $1\n    `;\n    const result = await client.query(query, [brand]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nfindProductsByBrand('Dell');\n```\n\n#### Nested JSON Queries\n\n```javascript\nasync function findProductsByRAM(ram) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT * FROM products\n      WHERE metadata->'specs'->>'ram' = $1\n    `;\n    const result = await client.query(query, [ram]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nfindProductsByRAM('16GB');\n```\n\n#### Updating JSON Fields\n\n```javascript\nasync function updateProductPrice(productId, newPrice) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      UPDATE products\n      SET metadata = jsonb_set(metadata, '{price}', $1::jsonb)\n      WHERE id = $2\n      RETURNING *\n    `;\n    const result = await client.query(query, [JSON.stringify(newPrice), productId]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\nupdateProductPrice('product-123', 999.99);\n```\n\n#### JSON Array Operations\n\n```javascript\nasync function addProductTag(productId, tag) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      UPDATE products\n      SET metadata = jsonb_set(\n        metadata,\n        '{tags}',\n        (metadata->'tags')::jsonb || $1::jsonb\n      )\n      WHERE id = $2\n      RETURNING *\n    `;\n    const result = await client.query(query, [JSON.stringify([tag]), productId]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\naddProductTag('product-123', 'featured');\n```\n\n### Array Operations\n\n#### Working with Arrays\n\n```javascript\nasync function createUserWithTags(email, tags) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      INSERT INTO users (email, tags)\n      VALUES ($1, $2)\n      RETURNING *\n    `;\n    const result = await client.query(query, [email, tags]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\ncreateUserWithTags('john@example.com', ['premium', 'verified']);\n```\n\n#### Querying Arrays\n\n```javascript\nasync function findUsersByTag(tag) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT * FROM users\n      WHERE $1 = ANY(tags)\n    `;\n    const result = await client.query(query, [tag]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nfindUsersByTag('premium');\n```\n\n#### Array Contains Query\n\n```javascript\nasync function findUsersWithAllTags(requiredTags) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT * FROM users\n      WHERE tags @> $1::text[]\n    `;\n    const result = await client.query(query, [requiredTags]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nfindUsersWithAllTags(['premium', 'verified']);\n```\n\n### Full-Text Search\n\n#### Creating a Text Search Query\n\n```javascript\nasync function searchArticles(searchTerm) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT id, title, content,\n             ts_rank(to_tsvector('english', title || ' ' || content), query) AS rank\n      FROM articles,\n           to_tsquery('english', $1) query\n      WHERE to_tsvector('english', title || ' ' || content) @@ query\n      ORDER BY rank DESC\n      LIMIT 20\n    `;\n    const result = await client.query(query, [searchTerm]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nsearchArticles('database performance');\n```\n\n### Aggregations and Analytics\n\n#### Group By and Aggregation\n\n```javascript\nasync function getUserStatsByCity() {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT\n        city,\n        COUNT(*) as user_count,\n        AVG(age) as avg_age,\n        MIN(created_at) as first_user,\n        MAX(created_at) as latest_user\n      FROM users\n      GROUP BY city\n      ORDER BY user_count DESC\n    `;\n    const result = await client.query(query);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ngetUserStatsByCity();\n```\n\n#### Window Functions\n\n```javascript\nasync function getRankedProducts() {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT\n        name,\n        category,\n        price,\n        RANK() OVER (PARTITION BY category ORDER BY price DESC) as price_rank,\n        AVG(price) OVER (PARTITION BY category) as category_avg_price\n      FROM products\n    `;\n    const result = await client.query(query);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ngetRankedProducts();\n```\n\n### Common Table Expressions (CTEs)\n\n```javascript\nasync function getTopSpenders(limit = 10) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      WITH user_totals AS (\n        SELECT\n          user_id,\n          SUM(amount) as total_spent,\n          COUNT(*) as order_count\n        FROM orders\n        WHERE status = 'completed'\n        GROUP BY user_id\n      )\n      SELECT\n        u.id,\n        u.email,\n        ut.total_spent,\n        ut.order_count\n      FROM users u\n      JOIN user_totals ut ON u.id = ut.user_id\n      ORDER BY ut.total_spent DESC\n      LIMIT $1\n    `;\n    const result = await client.query(query, [limit]);\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\ngetTopSpenders(20);\n```\n\n### Batch Operations\n\n#### Batch Insert\n\n```javascript\nasync function batchInsertUsers(users) {\n  const client = await pool.connect();\n  try {\n    await client.query('BEGIN');\n\n    for (const user of users) {\n      await client.query(\n        'INSERT INTO users (name, email, city) VALUES ($1, $2, $3)',\n        [user.name, user.email, user.city]\n      );\n    }\n\n    await client.query('COMMIT');\n    console.log(`Inserted ${users.length} users`);\n  } catch (err) {\n    await client.query('ROLLBACK');\n    throw err;\n  } finally {\n    client.release();\n  }\n}\n\nbatchInsertUsers([\n  { name: 'Alice', email: 'alice@example.com', city: 'NYC' },\n  { name: 'Bob', email: 'bob@example.com', city: 'LA' }\n]);\n```\n\n---\n\n## Schema Management\n\n### Creating Tables\n\n```javascript\nasync function createUsersTable() {\n  const client = await pool.connect();\n  try {\n    const query = `\n      CREATE TABLE IF NOT EXISTS users (\n        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n        email STRING UNIQUE NOT NULL,\n        name STRING NOT NULL,\n        city STRING,\n        age INT,\n        tags TEXT[],\n        metadata JSONB,\n        created_at TIMESTAMP DEFAULT now(),\n        updated_at TIMESTAMP DEFAULT now()\n      )\n    `;\n    await client.query(query);\n    console.log('Users table created');\n  } finally {\n    client.release();\n  }\n}\n\ncreateUsersTable();\n```\n\n### Creating Indexes\n\n```javascript\nasync function createIndexes() {\n  const client = await pool.connect();\n  try {\n    // Standard index\n    await client.query('CREATE INDEX IF NOT EXISTS idx_users_city ON users (city)');\n\n    // Multi-column index\n    await client.query('CREATE INDEX IF NOT EXISTS idx_users_city_age ON users (city, age)');\n\n    // Inverted index for JSONB\n    await client.query('CREATE INVERTED INDEX IF NOT EXISTS idx_users_metadata ON users (metadata)');\n\n    // Inverted index for arrays\n    await client.query('CREATE INVERTED INDEX IF NOT EXISTS idx_users_tags ON users (tags)');\n\n    console.log('Indexes created');\n  } finally {\n    client.release();\n  }\n}\n\ncreateIndexes();\n```\n\n### Altering Tables\n\n```javascript\nasync function alterUsersTable() {\n  const client = await pool.connect();\n  try {\n    // Add column\n    await client.query('ALTER TABLE users ADD COLUMN IF NOT EXISTS status STRING DEFAULT \\'active\\'');\n\n    // Add constraint\n    await client.query('ALTER TABLE users ADD CONSTRAINT check_age CHECK (age >= 0 AND age <= 150)');\n\n    console.log('Table altered successfully');\n  } finally {\n    client.release();\n  }\n}\n\nalterUsersTable();\n```\n\n---\n\n## Error Handling\n\n### Handling Specific Errors\n\n```javascript\nasync function createUserWithErrorHandling(email, name) {\n  const client = await pool.connect();\n  try {\n    const query = 'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *';\n    const result = await client.query(query, [email, name]);\n    return result.rows[0];\n  } catch (err) {\n    if (err.code === '23505') {\n      // Unique violation\n      throw new Error(`User with email ${email} already exists`);\n    } else if (err.code === '23502') {\n      // Not null violation\n      throw new Error('Required field is missing');\n    } else if (err.code === '23503') {\n      // Foreign key violation\n      throw new Error('Referenced record does not exist');\n    } else if (err.code === '40001') {\n      // Serialization failure\n      throw new Error('Transaction conflict, please retry');\n    } else {\n      throw err;\n    }\n  } finally {\n    client.release();\n  }\n}\n\ncreateUserWithErrorHandling('john@example.com', 'John Doe');\n```\n\n### Connection Error Handling\n\n```javascript\nasync function queryWithRetry(query, params, maxRetries = 3) {\n  let retries = 0;\n\n  while (retries < maxRetries) {\n    let client;\n    try {\n      client = await pool.connect();\n      const result = await client.query(query, params);\n      client.release();\n      return result;\n    } catch (err) {\n      if (client) client.release();\n\n      if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT') {\n        retries++;\n        if (retries >= maxRetries) {\n          throw new Error('Database connection failed after retries');\n        }\n        await new Promise(resolve => setTimeout(resolve, 1000 * retries));\n      } else {\n        throw err;\n      }\n    }\n  }\n}\n\nqueryWithRetry('SELECT * FROM users WHERE id = $1', ['user-123']);\n```\n\n---\n\n## Closing Connections\n\n### Graceful Shutdown\n\n```javascript\nasync function gracefulShutdown() {\n  console.log('Closing database connections...');\n  await pool.end();\n  console.log('Database connections closed');\n  process.exit(0);\n}\n\nprocess.on('SIGTERM', gracefulShutdown);\nprocess.on('SIGINT', gracefulShutdown);\n```\n\n### Complete Application Example\n\n```javascript\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n  user: process.env.DB_USER || 'root',\n  host: process.env.DB_HOST || 'localhost',\n  database: process.env.DB_NAME || 'defaultdb',\n  port: parseInt(process.env.DB_PORT) || 26257,\n  max: 20,\n});\n\n// Query functions\nasync function getAllUsers() {\n  const client = await pool.connect();\n  try {\n    const result = await client.query('SELECT * FROM users');\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nasync function createUser(name, email) {\n  const client = await pool.connect();\n  try {\n    const query = 'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *';\n    const result = await client.query(query, [name, email]);\n    return result.rows[0];\n  } finally {\n    client.release();\n  }\n}\n\n// Graceful shutdown\nasync function shutdown() {\n  await pool.end();\n  process.exit(0);\n}\n\nprocess.on('SIGTERM', shutdown);\nprocess.on('SIGINT', shutdown);\n\n// Export for use in application\nmodule.exports = {\n  pool,\n  getAllUsers,\n  createUser,\n};\n```\n\n---\n\n## Common Patterns\n\n### Repository Pattern\n\n```javascript\nclass UserRepository {\n  constructor(pool) {\n    this.pool = pool;\n  }\n\n  async findAll() {\n    const client = await this.pool.connect();\n    try {\n      const result = await client.query('SELECT * FROM users');\n      return result.rows;\n    } finally {\n      client.release();\n    }\n  }\n\n  async findById(id) {\n    const client = await this.pool.connect();\n    try {\n      const result = await client.query('SELECT * FROM users WHERE id = $1', [id]);\n      return result.rows[0];\n    } finally {\n      client.release();\n    }\n  }\n\n  async create(user) {\n    const client = await this.pool.connect();\n    try {\n      const query = `\n        INSERT INTO users (name, email, city)\n        VALUES ($1, $2, $3)\n        RETURNING *\n      `;\n      const result = await client.query(query, [user.name, user.email, user.city]);\n      return result.rows[0];\n    } finally {\n      client.release();\n    }\n  }\n\n  async update(id, updates) {\n    const client = await this.pool.connect();\n    try {\n      const query = `\n        UPDATE users\n        SET name = $1, city = $2, updated_at = now()\n        WHERE id = $3\n        RETURNING *\n      `;\n      const result = await client.query(query, [updates.name, updates.city, id]);\n      return result.rows[0];\n    } finally {\n      client.release();\n    }\n  }\n\n  async delete(id) {\n    const client = await this.pool.connect();\n    try {\n      const result = await client.query('DELETE FROM users WHERE id = $1 RETURNING *', [id]);\n      return result.rows[0];\n    } finally {\n      client.release();\n    }\n  }\n}\n\nconst userRepo = new UserRepository(pool);\n```\n\n### Query Builder Pattern\n\n```javascript\nclass QueryBuilder {\n  constructor(pool, table) {\n    this.pool = pool;\n    this.table = table;\n    this.whereConditions = [];\n    this.parameters = [];\n    this.orderByClause = '';\n    this.limitClause = '';\n  }\n\n  where(column, operator, value) {\n    this.parameters.push(value);\n    this.whereConditions.push(`${column} ${operator} $${this.parameters.length}`);\n    return this;\n  }\n\n  orderBy(column, direction = 'ASC') {\n    this.orderByClause = `ORDER BY ${column} ${direction}`;\n    return this;\n  }\n\n  limit(count) {\n    this.limitClause = `LIMIT ${count}`;\n    return this;\n  }\n\n  async execute() {\n    const client = await this.pool.connect();\n    try {\n      let query = `SELECT * FROM ${this.table}`;\n\n      if (this.whereConditions.length > 0) {\n        query += ` WHERE ${this.whereConditions.join(' AND ')}`;\n      }\n\n      if (this.orderByClause) {\n        query += ` ${this.orderByClause}`;\n      }\n\n      if (this.limitClause) {\n        query += ` ${this.limitClause}`;\n      }\n\n      const result = await client.query(query, this.parameters);\n      return result.rows;\n    } finally {\n      client.release();\n    }\n  }\n}\n\n// Usage\nconst users = await new QueryBuilder(pool, 'users')\n  .where('city', '=', 'Seattle')\n  .where('age', '>=', 25)\n  .orderBy('created_at', 'DESC')\n  .limit(10)\n  .execute();\n```\n\n---\n\n## Performance Optimization\n\n### Connection Pooling Configuration\n\n```javascript\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n  user: 'root',\n  host: 'localhost',\n  database: 'defaultdb',\n  port: 26257,\n  max: 20,                      // Maximum number of clients in the pool\n  min: 5,                       // Minimum number of clients in the pool\n  idleTimeoutMillis: 300000,    // Close idle clients after 5 minutes (CockroachDB recommendation)\n  connectionTimeoutMillis: 5000,\n  allowExitOnIdle: false,\n});\n```\n\n### Prepared Statements\n\n```javascript\nasync function findUsersPrepared(city) {\n  const client = await pool.connect();\n  try {\n    // Named prepared statement\n    const queryName = 'find-users-by-city';\n    const queryText = 'SELECT * FROM users WHERE city = $1';\n\n    const result = await client.query({\n      name: queryName,\n      text: queryText,\n      values: [city]\n    });\n\n    return result.rows;\n  } finally {\n    client.release();\n  }\n}\n\nfindUsersPrepared('Seattle');\n```\n\n### Cursor-Based Pagination\n\n```javascript\nasync function paginateUsers(cursorId, pageSize = 20) {\n  const client = await pool.connect();\n  try {\n    const query = `\n      SELECT * FROM users\n      WHERE id > $1\n      ORDER BY id\n      LIMIT $2\n    `;\n    const result = await client.query(query, [cursorId || '00000000-0000-0000-0000-000000000000', pageSize]);\n\n    return {\n      data: result.rows,\n      nextCursor: result.rows.length > 0 ? result.rows[result.rows.length - 1].id : null,\n      hasMore: result.rows.length === pageSize\n    };\n  } finally {\n    client.release();\n  }\n}\n\npaginateUsers(null, 20);\n```\n"
  },
  {
    "path": "content/cohere/docs/llm/DOC.md",
    "content": "---\nname: llm\ndescription: \"Cohere API JavaScript/TypeScript SDK coding guide for LLM, embeddings, and rerank\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.19.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"cohere,llm,ai,embeddings,rerank\"\n---\n\n# Cohere API JavaScript/TypeScript SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Cohere JavaScript SDK package:** `cohere-ai` (GitHub: https://github.com/cohere-ai/cohere-typescript)\n\n**Never use deprecated or unofficial libraries.** The `cohere-ai` npm package is the only officially supported Cohere SDK for JavaScript/TypeScript maintained by Cohere. Avoid `cohere-js` (unofficial, different product), `cohere-api-web` (legacy/unofficial), and any other variants.\n\n**Always use `CohereClientV2` for accessing the latest v2 API with current models like `command-a-03-2025`.**\n\n## 2. Installation\n\n### npm\n```bash\nnpm install cohere-ai\n```\n\n### yarn\n```bash\nyarn add cohere-ai\n```\n\n### pnpm\n```bash\npnpm add cohere-ai\n```\n\n**Environment Variables:**\n```bash\nCOHERE_API_KEY=your_api_key_here\n# Alternative:\nCO_API_KEY=your_api_key_here\n```\n\nThe SDK automatically reads from either `COHERE_API_KEY` or `CO_API_KEY` environment variables.\n\n## 3. Initialization\n\n### Basic Client Initialization\n\n```javascript\nimport { CohereClientV2 } from \"cohere-ai\";\n\n// Uses COHERE_API_KEY or CO_API_KEY environment variable\nconst cohere = new CohereClientV2({});\n\n// Or pass API key directly\nconst cohere = new CohereClientV2({\n  token: \"your-api-key\"\n});\n```\n\n### Authentication Methods\n\nThe Cohere API uses Bearer token authentication. The SDK handles this automatically when you provide the API key via the constructor or environment variables.\n\n```javascript\nimport { CohereClientV2 } from \"cohere-ai\";\n\n// Best practice: use environment variables\nconst cohere = new CohereClientV2({\n  token: process.env.COHERE_API_KEY\n});\n```\n\n**Important:** Never hardcode API keys in your source code. Always use environment variables or secure configuration management.\n\n## 4. Core API Surfaces\n\n### Chat API\n\nThe Chat API enables conversational AI, text generation, and summarization with Cohere's Command models.\n\n**Minimal Example:**\n```javascript\nimport { CohereClientV2 } from \"cohere-ai\";\n\nconst cohere = new CohereClientV2({});\n\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"Explain quantum computing in simple terms\" }\n  ]\n});\n\nconsole.log(response.message.content[0].text);\n```\n\n**Advanced Example with Configuration:**\n```javascript\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [\n    {\n      role: \"system\",\n      content: \"You are a helpful AI assistant specialized in science education.\"\n    },\n    {\n      role: \"user\",\n      content: \"Explain quantum computing\"\n    }\n  ],\n  temperature: 0.3,\n  maxTokens: 500,\n  k: 0,\n  p: 0.75,\n  stopSequences: [\"--END--\"],\n  frequencyPenalty: 0.0,\n  presencePenalty: 0.0,\n  safetyMode: \"CONTEXTUAL\"\n});\n\nconsole.log(response.message.content[0].text);\n```\n\n**Multi-turn Conversation:**\n```javascript\nconst messages = [\n  { role: \"user\", content: \"What is machine learning?\" },\n  { role: \"assistant\", content: \"Machine learning is a subset of AI...\" },\n  { role: \"user\", content: \"Can you give me an example?\" }\n];\n\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: messages\n});\n```\n\n### Chat Streaming API\n\nStream responses in real-time to reduce perceived latency.\n\n**Minimal Example:**\n```javascript\nimport { CohereClientV2 } from \"cohere-ai\";\n\nconst cohere = new CohereClientV2({});\n\nconst stream = await cohere.chatStream({\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"Write a short story about a robot\" }\n  ]\n});\n\nfor await (const chatEvent of stream) {\n  if (chatEvent.type === \"content-delta\") {\n    process.stdout.write(chatEvent.delta?.message?.content?.text || \"\");\n  }\n}\nconsole.log(); // final newline\n```\n\n**Advanced Streaming with Event Handling:**\n```javascript\nconst stream = await cohere.chatStream({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Explain photosynthesis\" }],\n  temperature: 0.5\n});\n\nfor await (const event of stream) {\n  switch (event.type) {\n    case \"message-start\":\n      console.log(\"Stream started\");\n      break;\n    case \"content-start\":\n      console.log(\"Content generation began\");\n      break;\n    case \"content-delta\":\n      process.stdout.write(event.delta?.message?.content?.text || \"\");\n      break;\n    case \"content-end\":\n      console.log(\"\\nContent generation complete\");\n      break;\n    case \"message-end\":\n      console.log(\"Stream ended\");\n      console.log(`Tokens used: ${event.delta?.usage?.tokens}`);\n      break;\n  }\n}\n```\n\n### Embed API\n\nGenerate vector embeddings for text data to enable semantic search, clustering, and classification.\n\n**Minimal Example:**\n```javascript\nconst embedResponse = await cohere.embed({\n  model: \"embed-english-v3.0\",\n  texts: [\"Hello world\", \"Cohere embeddings are powerful\"],\n  inputType: \"search_document\"\n});\n\nconsole.log(embedResponse.embeddings);\n// Returns array of embedding vectors\n```\n\n**Advanced Example with Classification Input Type:**\n```javascript\nconst embedResponse = await cohere.embed({\n  model: \"embed-multilingual-v3.0\",\n  texts: [\n    \"This product is amazing!\",\n    \"Terrible customer service\",\n    \"Neutral statement\"\n  ],\n  inputType: \"classification\",\n  embeddingTypes: [\"float\"]\n});\n\nconsole.log(`Generated ${embedResponse.embeddings.length} embeddings`);\nconsole.log(`Embedding dimension: ${embedResponse.embeddings[0].length}`);\n```\n\n**Available Input Types:** `\"search_document\"` (for embeddings stored in vector databases), `\"search_query\"` (for search queries run against vector databases), `\"classification\"` (for embeddings passed through text classifiers), and `\"clustering\"` (for embeddings used in clustering algorithms). The `inputType` parameter is **required** for embed-v3 models and later.\n\n**Multilingual Embeddings:**\n```javascript\nconst multilingualEmbed = await cohere.embed({\n  model: \"embed-multilingual-v3.0\",\n  texts: [\n    \"Hello, how are you?\",\n    \"Bonjour, comment allez-vous?\",\n    \"Hola, ¿cómo estás?\",\n    \"こんにちは、お元気ですか？\"\n  ],\n  inputType: \"search_document\"\n});\n```\n\nThe `embed-multilingual-v3.0` model supports 100+ languages.\n\n### Rerank API\n\nRerank search results by semantic relevance to improve retrieval quality.\n\n**Minimal Example:**\n```javascript\nconst rerankResponse = await cohere.rerank({\n  model: \"rerank-english-v3.0\",\n  query: \"What is machine learning?\",\n  documents: [\n    \"Machine learning is a subset of artificial intelligence.\",\n    \"Python is a programming language.\",\n    \"Neural networks are computational models inspired by the brain.\",\n    \"JavaScript is used for web development.\"\n  ]\n});\n\n// Results ordered by relevance score\nrerankResponse.results.forEach((result, idx) => {\n  console.log(`${idx + 1}. Score: ${result.relevanceScore}`);\n  console.log(`   Document: ${result.document.text}\\n`);\n});\n```\n\n**Advanced Example with Top-N and Metadata:**\n```javascript\nconst documents = [\n  { text: \"Machine learning algorithms learn from data\", id: \"doc1\" },\n  { text: \"Supervised learning uses labeled data\", id: \"doc2\" },\n  { text: \"Deep learning uses neural networks\", id: \"doc3\" },\n  { text: \"Cooking recipes for dinner\", id: \"doc4\" }\n];\n\nconst rerankResponse = await cohere.rerank({\n  model: \"rerank-english-v3.0\",\n  query: \"What are machine learning techniques?\",\n  documents: documents,\n  topN: 3,\n  returnDocuments: true\n});\n\nconsole.log(\"Top ranked documents:\");\nrerankResponse.results.forEach((result) => {\n  console.log(`Document ID: ${result.document.id}`);\n  console.log(`Relevance: ${result.relevanceScore}`);\n  console.log(`Text: ${result.document.text}\\n`);\n});\n```\n\n**Rerank with Raw Strings:**\n```javascript\nconst query = \"artificial intelligence applications\";\nconst docs = [\n  \"AI is used in healthcare for diagnosis\",\n  \"Machine learning powers recommendation systems\",\n  \"The weather is sunny today\",\n  \"Natural language processing enables chatbots\"\n];\n\nconst result = await cohere.rerank({\n  model: \"rerank-english-v3.0\",\n  query: query,\n  documents: docs,\n  topN: 2\n});\n```\n\n### Classify API\n\nClassify text into predefined categories using few-shot learning.\n\n**Minimal Example:**\n```javascript\nconst classifyResponse = await cohere.classify({\n  model: \"embed-english-v3.0\",\n  inputs: [\n    \"This movie was fantastic!\",\n    \"Worst experience ever.\",\n    \"It was okay, nothing special.\"\n  ],\n  examples: [\n    { text: \"I loved this!\", label: \"positive\" },\n    { text: \"Amazing product\", label: \"positive\" },\n    { text: \"Terrible quality\", label: \"negative\" },\n    { text: \"Very disappointed\", label: \"negative\" },\n    { text: \"It's fine\", label: \"neutral\" },\n    { text: \"Average performance\", label: \"neutral\" }\n  ]\n});\n\nclassifyResponse.classifications.forEach((classification) => {\n  console.log(`Text: \"${classification.input}\"`);\n  console.log(`Prediction: ${classification.prediction}`);\n  console.log(`Confidence: ${classification.confidence}\\n`);\n});\n```\n\n**Advanced Classification with Multiple Categories:**\n```javascript\nconst trainingExamples = [\n  { text: \"Fix login bug\", label: \"bug\" },\n  { text: \"Login page not working\", label: \"bug\" },\n  { text: \"Add dark mode feature\", label: \"feature\" },\n  { text: \"Implement user profiles\", label: \"feature\" },\n  { text: \"Update documentation\", label: \"documentation\" },\n  { text: \"Improve README\", label: \"documentation\" },\n  { text: \"How do I install this?\", label: \"question\" },\n  { text: \"Where is the config file?\", label: \"question\" }\n];\n\nconst classifyResponse = await cohere.classify({\n  model: \"embed-english-v3.0\",\n  inputs: [\n    \"Cannot reset my password\",\n    \"Need help with setup\",\n    \"Add support for webhooks\"\n  ],\n  examples: trainingExamples\n});\n\nclassifyResponse.classifications.forEach((item) => {\n  console.log(`\"${item.input}\" → ${item.prediction}`);\n\n  // Show confidence for all labels\n  item.labels.forEach((labelConf) => {\n    console.log(`  ${labelConf.labelName}: ${labelConf.confidence}`);\n  });\n});\n```\n\n**Requirements:** Minimum 2 examples per label, maximum 2500 examples total, and can classify up to 96 texts in a single request.\n\n## 5. Advanced Features\n\n### RAG (Retrieval Augmented Generation)\n\nCombine Chat, Embed, and Rerank for production-grade RAG systems.\n\n**Complete RAG Example:**\n```javascript\nimport { CohereClientV2 } from \"cohere-ai\";\n\nconst cohere = new CohereClientV2({});\n\nasync function ragPipeline(query, documents) {\n  // Step 1: Embed documents\n  const embedResponse = await cohere.embed({\n    model: \"embed-english-v3.0\",\n    texts: documents,\n    inputType: \"search_document\"\n  });\n\n  // Step 2: Embed query\n  const queryEmbedResponse = await cohere.embed({\n    model: \"embed-english-v3.0\",\n    texts: [query],\n    inputType: \"search_query\"\n  });\n\n  // Step 3: Find top candidates using similarity (simplified)\n  const topDocs = documents.slice(0, 10); // In production, use vector DB\n\n  // Step 4: Rerank for precision\n  const rerankResponse = await cohere.rerank({\n    model: \"rerank-english-v3.0\",\n    query: query,\n    documents: topDocs,\n    topN: 3\n  });\n\n  // Step 5: Generate answer with context\n  const context = rerankResponse.results\n    .map(r => r.document.text)\n    .join(\"\\n\\n\");\n\n  const chatResponse = await cohere.chat({\n    model: \"command-a-03-2025\",\n    messages: [\n      {\n        role: \"system\",\n        content: `Answer the question based on this context:\\n\\n${context}`\n      },\n      { role: \"user\", content: query }\n    ]\n  });\n\n  return {\n    answer: chatResponse.message.content[0].text,\n    sources: rerankResponse.results\n  };\n}\n\n// Usage\nconst docs = [\n  \"Machine learning is a subset of AI that enables systems to learn from data.\",\n  \"Deep learning uses neural networks with multiple layers.\",\n  \"Supervised learning requires labeled training data.\",\n  // ... more documents\n];\n\nconst result = await ragPipeline(\"What is machine learning?\", docs);\nconsole.log(result.answer);\n```\n\n### Tool Use (Function Calling)\n\nEnable the model to call external functions and APIs.\n\n**Minimal Example:**\n```javascript\nconst tools = [\n  {\n    type: \"function\",\n    function: {\n      name: \"get_weather\",\n      description: \"Get current weather for a location\",\n      parameters: {\n        type: \"object\",\n        properties: {\n          location: {\n            type: \"string\",\n            description: \"City name\"\n          },\n          unit: {\n            type: \"string\",\n            enum: [\"celsius\", \"fahrenheit\"]\n          }\n        },\n        required: [\"location\"]\n      }\n    }\n  }\n];\n\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"What's the weather in San Francisco?\" }\n  ],\n  tools: tools\n});\n\nif (response.message.toolCalls) {\n  console.log(\"Function to call:\", response.message.toolCalls[0].function.name);\n  console.log(\"Arguments:\", response.message.toolCalls[0].function.arguments);\n}\n```\n\n**Advanced Multi-Step Tool Use:**\n```javascript\nconst tools = [\n  {\n    type: \"function\",\n    function: {\n      name: \"search_database\",\n      description: \"Search internal knowledge base\",\n      parameters: {\n        type: \"object\",\n        properties: {\n          query: { type: \"string\" },\n          limit: { type: \"integer\", default: 5 }\n        },\n        required: [\"query\"]\n      }\n    }\n  },\n  {\n    type: \"function\",\n    function: {\n      name: \"calculate\",\n      description: \"Perform mathematical calculations\",\n      parameters: {\n        type: \"object\",\n        properties: {\n          expression: { type: \"string\" }\n        },\n        required: [\"expression\"]\n      }\n    }\n  }\n];\n\n// Initial request\nlet messages = [\n  { role: \"user\", content: \"Search for quantum computing papers and calculate citations\" }\n];\n\nconst firstResponse = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: messages,\n  tools: tools\n});\n\n// Execute tool calls\nif (firstResponse.message.toolCalls) {\n  for (const toolCall of firstResponse.message.toolCalls) {\n    const functionName = toolCall.function.name;\n    const args = JSON.parse(toolCall.function.arguments);\n\n    // Execute function (mock example)\n    let result;\n    if (functionName === \"search_database\") {\n      result = { papers: [\"Paper A\", \"Paper B\"], citations: [42, 38] };\n    }\n\n    // Add tool result to conversation\n    messages.push({\n      role: \"tool\",\n      content: JSON.stringify(result),\n      toolCallId: toolCall.id\n    });\n  }\n\n  // Get final response\n  const finalResponse = await cohere.chat({\n    model: \"command-a-03-2025\",\n    messages: messages,\n    tools: tools\n  });\n\n  console.log(finalResponse.message.content[0].text);\n}\n```\n\n### Web Search Connector\n\nUse Cohere's built-in web search to ground responses in current information.\n\n**Example:**\n```javascript\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"What are the latest developments in fusion energy?\" }\n  ],\n  connectors: [{ id: \"web-search\" }]\n});\n\nconsole.log(response.message.content[0].text);\n\n// Access citations\nif (response.message.citations) {\n  console.log(\"\\nSources:\");\n  response.message.citations.forEach((citation) => {\n    console.log(`- ${citation.sources[0]}`);\n  });\n}\n```\n\n### Citations\n\nEnable inline citations for transparency and verification.\n\n**Example:**\n```javascript\nconst documents = [\n  { id: \"doc1\", text: \"AI was founded as an academic discipline in 1956.\" },\n  { id: \"doc2\", text: \"Machine learning is a subset of AI.\" },\n  { id: \"doc3\", text: \"Deep learning breakthrough occurred in 2012.\" }\n];\n\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"When was AI founded?\" }\n  ],\n  documents: documents\n});\n\nconsole.log(response.message.content[0].text);\n\n// Access citations\nif (response.message.citations) {\n  response.message.citations.forEach((citation) => {\n    console.log(`\\nCitation: \"${citation.text}\"`);\n    console.log(`Source: Document ${citation.documentIds.join(\", \")}`);\n  });\n}\n```\n\n## 6. TypeScript Support\n\nThe SDK is written in TypeScript and provides full type definitions.\n\n### Type Imports\n\n```typescript\nimport {\n  CohereClientV2,\n  ChatRequest,\n  ChatResponse,\n  ChatStreamRequest,\n  EmbedRequest,\n  EmbedResponse,\n  RerankRequest,\n  RerankResponse,\n  CohereError,\n  CohereTimeoutError\n} from \"cohere-ai\";\n```\n\n### Type-Safe Chat\n\n```typescript\nimport { CohereClientV2, ChatRequest } from \"cohere-ai\";\n\nconst cohere = new CohereClientV2({ token: process.env.COHERE_API_KEY });\n\nconst request: ChatRequest = {\n  model: \"command-a-03-2025\",\n  messages: [\n    { role: \"user\", content: \"Explain TypeScript benefits\" }\n  ],\n  temperature: 0.3,\n  maxTokens: 1000\n};\n\nconst response = await cohere.chat(request);\nconst text: string = response.message.content[0].text;\n```\n\n### Type-Safe Embeddings\n\n```typescript\nimport { EmbedRequest, EmbedResponse } from \"cohere-ai\";\n\nconst embedRequest: EmbedRequest = {\n  model: \"embed-english-v3.0\",\n  texts: [\"Sample text\"],\n  inputType: \"classification\"\n};\n\nconst embedResponse: EmbedResponse = await cohere.embed(embedRequest);\nconst embeddings: number[][] = embedResponse.embeddings;\n```\n\n### Custom Types\n\n```typescript\ninterface DocumentWithMetadata {\n  id: string;\n  text: string;\n  category: string;\n  timestamp: Date;\n}\n\nasync function embedDocuments(docs: DocumentWithMetadata[]) {\n  const texts = docs.map(d => d.text);\n\n  const response = await cohere.embed({\n    model: \"embed-english-v3.0\",\n    texts: texts,\n    inputType: \"search_document\"\n  });\n\n  return docs.map((doc, idx) => ({\n    ...doc,\n    embedding: response.embeddings[idx]\n  }));\n}\n```\n\n## 7. Best Practices\n\n### Error Handling\n\n**Always wrap API calls in try-catch blocks:**\n\n```javascript\nimport { CohereClientV2, CohereError, CohereTimeoutError } from \"cohere-ai\";\n\nconst cohere = new CohereClientV2({});\n\nasync function generateText(prompt) {\n  try {\n    const response = await cohere.chat({\n      model: \"command-a-03-2025\",\n      messages: [{ role: \"user\", content: prompt }]\n    });\n    return response.message.content[0].text;\n  } catch (err) {\n    if (err instanceof CohereTimeoutError) {\n      console.error(\"Request timed out:\", err.message);\n      // Retry logic here\n    } else if (err instanceof CohereError) {\n      console.error(`API Error ${err.statusCode}:`, err.message);\n      console.error(\"Error body:\", err.body);\n\n      // Handle specific error codes\n      if (err.statusCode === 429) {\n        console.error(\"Rate limit exceeded\");\n        // Implement backoff strategy\n      } else if (err.statusCode === 401) {\n        console.error(\"Invalid API key\");\n      } else if (err.statusCode === 402) {\n        console.error(\"Billing limit reached\");\n      }\n    } else {\n      console.error(\"Unexpected error:\", err);\n    }\n    throw err;\n  }\n}\n```\n\n### Timeout Configuration\n\n```javascript\n// Set custom timeout (default is 60 seconds)\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Hello\" }]\n}, {\n  timeoutInSeconds: 10\n});\n```\n\n### Retry Configuration\n\n```javascript\n// Configure retries (default: 2 retries with exponential backoff)\n// 409 Conflict, 429 Rate Limit, and >=500 errors are automatically retried\n\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Hello\" }]\n}, {\n  maxRetries: 3\n});\n\n// Disable retries\nconst responseNoRetry = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Hello\" }]\n}, {\n  maxRetries: 0\n});\n```\n\n### Rate Limiting\n\n**Trial Keys:** Chat 20 calls/minute, Embed 5 calls/minute, all endpoints 1,000 calls/month total.\n\n**Production Keys:** Chat 500 requests/minute, Embed (Text) 2,000 requests/minute, Embed (Images) 400 requests/minute, Rerank 1,000 requests/minute, unlimited monthly usage.\n\n**Handle rate limits gracefully:**\n\n```javascript\nasync function chatWithBackoff(messages, retries = 3, delay = 1000) {\n  for (let i = 0; i < retries; i++) {\n    try {\n      return await cohere.chat({\n        model: \"command-a-03-2025\",\n        messages: messages\n      });\n    } catch (err) {\n      if (err instanceof CohereError && err.statusCode === 429) {\n        if (i < retries - 1) {\n          console.log(`Rate limited, retrying in ${delay}ms...`);\n          await new Promise(resolve => setTimeout(resolve, delay));\n          delay *= 2; // Exponential backoff\n        } else {\n          throw err;\n        }\n      } else {\n        throw err;\n      }\n    }\n  }\n}\n```\n\n### Model Selection\n\n**Current Production Models (as of 2025):** `command-a-03-2025` (latest Command A model with 256K context, 111B parameters, highest throughput - 150% faster than Command R+), `command-r-plus-08-2024` (Command R+ with strong reasoning capabilities), `embed-english-v3.0` (English embeddings with 1024 dimensions), `embed-multilingual-v3.0` (multilingual embeddings supporting 100+ languages), `rerank-english-v3.0` (English reranking model), and `rerank-multilingual-v3.0` (multilingual reranking).\n\n**Choosing the right model:**\n\n```javascript\n// For general chat and high throughput\nconst model = \"command-a-03-2025\";\n\n// For embeddings - English only\nconst embedModel = \"embed-english-v3.0\";\n\n// For embeddings - Multilingual\nconst multilingualEmbedModel = \"embed-multilingual-v3.0\";\n\n// For reranking search results\nconst rerankModel = \"rerank-english-v3.0\";\n```\n\n### Temperature Guidelines\n\n**Temperature** controls randomness (0.0 to 1.0, default 0.3):\n\n```javascript\n// Deterministic, factual responses\nconst factualResponse = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"What is 2+2?\" }],\n  temperature: 0\n});\n\n// Balanced (default)\nconst balancedResponse = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Explain photosynthesis\" }],\n  temperature: 0.3\n});\n\n// Creative, varied responses\nconst creativeResponse = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Write a poem\" }],\n  temperature: 0.8\n});\n```\n\n**Warning:** High temperatures (>0.9) can introduce hallucinations and factually incorrect information.\n\n### Token Management\n\n```javascript\n// Control max output length\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Summarize this in 50 words\" }],\n  maxTokens: 100\n});\n\n// Monitor token usage (available in streaming)\nconst stream = await cohere.chatStream({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"Hello\" }]\n});\n\nfor await (const event of stream) {\n  if (event.type === \"message-end\" && event.delta?.usage) {\n    console.log(`Input tokens: ${event.delta.usage.inputTokens}`);\n    console.log(`Output tokens: ${event.delta.usage.outputTokens}`);\n  }\n}\n```\n\n### Security Best Practices\n\n**API Key Management:**\n\n```javascript\n// ✅ CORRECT: Use environment variables\nconst cohere = new CohereClientV2({\n  token: process.env.COHERE_API_KEY\n});\n\n// ❌ WRONG: Never hardcode API keys\nconst cohere = new CohereClientV2({\n  token: \"sk-xxxxxx\" // DON'T DO THIS\n});\n```\n\n**Input Validation:**\n\n```javascript\nfunction validateInput(text) {\n  if (!text || typeof text !== \"string\") {\n    throw new Error(\"Invalid input: text must be a non-empty string\");\n  }\n  if (text.length > 100000) {\n    throw new Error(\"Input too long\");\n  }\n  return text.trim();\n}\n\nasync function safeChat(userInput) {\n  const validatedInput = validateInput(userInput);\n\n  return await cohere.chat({\n    model: \"command-a-03-2025\",\n    messages: [{ role: \"user\", content: validatedInput }]\n  });\n}\n```\n\n**Safety Mode:**\n\n```javascript\n// Enable contextual safety filtering\nconst response = await cohere.chat({\n  model: \"command-a-03-2025\",\n  messages: [{ role: \"user\", content: \"User message\" }],\n  safetyMode: \"CONTEXTUAL\" // or \"STRICT\" or \"NONE\"\n});\n```\n\n### Performance Optimization\n\n**Batch Embeddings:**\n\n```javascript\n// ✅ GOOD: Batch multiple texts in one request\nconst texts = [\"text1\", \"text2\", \"text3\", /* ... up to 96 texts */];\nconst response = await cohere.embed({\n  model: \"embed-english-v3.0\",\n  texts: texts,\n  inputType: \"search_document\"\n});\n\n// ❌ INEFFICIENT: Multiple individual requests\nfor (const text of texts) {\n  await cohere.embed({\n    model: \"embed-english-v3.0\",\n    texts: [text],\n    inputType: \"search_document\"\n  });\n}\n```\n\n**Streaming for Long Responses:**\n\n```javascript\n// Use streaming for better user experience\nasync function streamResponse(prompt) {\n  const stream = await cohere.chatStream({\n    model: \"command-a-03-2025\",\n    messages: [{ role: \"user\", content: prompt }]\n  });\n\n  for await (const event of stream) {\n    if (event.type === \"content-delta\") {\n      // Display partial results immediately\n      process.stdout.write(event.delta?.message?.content?.text || \"\");\n    }\n  }\n}\n```\n\n**Caching Strategy:**\n\n```javascript\n// Cache embeddings to avoid redundant API calls\nclass EmbeddingCache {\n  constructor() {\n    this.cache = new Map();\n  }\n\n  async getEmbedding(text, cohere) {\n    if (this.cache.has(text)) {\n      return this.cache.get(text);\n    }\n\n    const response = await cohere.embed({\n      model: \"embed-english-v3.0\",\n      texts: [text],\n      inputType: \"search_document\"\n    });\n\n    const embedding = response.embeddings[0];\n    this.cache.set(text, embedding);\n    return embedding;\n  }\n}\n```\n\n## 8. Production Checklist\n\n### Version Management\n\n```json\n// package.json - Pin exact SDK version\n{\n  \"dependencies\": {\n    \"cohere-ai\": \"7.14.0\"\n  }\n}\n```\n\n- Pin exact SDK version in `package.json`\n- Review changelog before upgrading\n- Test thoroughly in staging before production deployment\n- Monitor Cohere's release notes for breaking changes\n\n### Environment Configuration\n\n```javascript\n// config.js\nconst config = {\n  development: {\n    cohereApiKey: process.env.COHERE_API_KEY_DEV,\n    model: \"command-a-03-2025\",\n    timeout: 30,\n    maxRetries: 2\n  },\n  production: {\n    cohereApiKey: process.env.COHERE_API_KEY_PROD,\n    model: \"command-a-03-2025\",\n    timeout: 60,\n    maxRetries: 3\n  }\n};\n\nconst env = process.env.NODE_ENV || \"development\";\nexport default config[env];\n```\n\n**Environment variables:** Set `COHERE_API_KEY` or `CO_API_KEY`, `NODE_ENV` (development/staging/production), use separate API keys for each environment, and use secret management systems (AWS Secrets Manager, Azure Key Vault, etc.).\n\n### Error Handling & Monitoring\n\n```javascript\nimport { CohereClientV2, CohereError, CohereTimeoutError } from \"cohere-ai\";\n\nclass CohereService {\n  constructor(logger, metrics) {\n    this.cohere = new CohereClientV2({\n      token: process.env.COHERE_API_KEY\n    });\n    this.logger = logger;\n    this.metrics = metrics;\n  }\n\n  async chat(messages, options = {}) {\n    const startTime = Date.now();\n\n    try {\n      const response = await this.cohere.chat({\n        model: \"command-a-03-2025\",\n        messages: messages,\n        ...options\n      }, {\n        timeoutInSeconds: 60,\n        maxRetries: 3\n      });\n\n      // Log success metrics\n      const duration = Date.now() - startTime;\n      this.metrics.recordSuccess(\"chat\", duration);\n      this.logger.info(\"Chat request succeeded\", {\n        duration,\n        model: \"command-a-03-2025\"\n      });\n\n      return response;\n\n    } catch (err) {\n      const duration = Date.now() - startTime;\n\n      if (err instanceof CohereTimeoutError) {\n        this.metrics.recordError(\"chat\", \"timeout\");\n        this.logger.error(\"Chat request timed out\", { duration });\n      } else if (err instanceof CohereError) {\n        this.metrics.recordError(\"chat\", `http_${err.statusCode}`);\n        this.logger.error(\"Chat request failed\", {\n          statusCode: err.statusCode,\n          message: err.message,\n          duration\n        });\n\n        // Alert on specific errors\n        if (err.statusCode === 429) {\n          this.logger.warn(\"Rate limit exceeded\");\n        } else if (err.statusCode >= 500) {\n          this.logger.error(\"Cohere service error\", { statusCode: err.statusCode });\n        }\n      } else {\n        this.metrics.recordError(\"chat\", \"unknown\");\n        this.logger.error(\"Unexpected error\", { error: err });\n      }\n\n      throw err;\n    }\n  }\n}\n```\n\n### Validate Responses\n\n```javascript\nfunction validateChatResponse(response) {\n  if (!response || !response.message) {\n    throw new Error(\"Invalid response: missing message\");\n  }\n\n  if (!response.message.content || response.message.content.length === 0) {\n    throw new Error(\"Invalid response: empty content\");\n  }\n\n  if (!response.message.content[0].text) {\n    throw new Error(\"Invalid response: missing text\");\n  }\n\n  return true;\n}\n\nasync function safeChat(messages) {\n  const response = await cohere.chat({\n    model: \"command-a-03-2025\",\n    messages: messages\n  });\n\n  validateChatResponse(response);\n  return response.message.content[0].text;\n}\n```\n\n### Testing Strategy\n\n```javascript\n// Mock Cohere client for testing\nclass MockCohereClient {\n  async chat({ messages }) {\n    return {\n      message: {\n        content: [{ text: \"Mocked response\" }],\n        role: \"assistant\"\n      }\n    };\n  }\n\n  async embed({ texts }) {\n    return {\n      embeddings: texts.map(() => Array(1024).fill(0))\n    };\n  }\n}\n\n// Test example\ndescribe(\"CohereService\", () => {\n  it(\"should handle chat requests\", async () => {\n    const mockClient = new MockCohereClient();\n    const service = new CohereService(mockClient);\n\n    const response = await service.chat([\n      { role: \"user\", content: \"test\" }\n    ]);\n\n    expect(response.message.content[0].text).toBe(\"Mocked response\");\n  });\n});\n```\n\n### Monitoring Checklist\n\n**Metrics to track:** Request count (by endpoint, model), success rate, error rate (by error type, status code), latency (p50, p95, p99), token usage, rate limit hits, and timeout frequency.\n\n**Logging requirements:** All API errors with context, rate limit warnings, unusual latency spikes, and token usage patterns.\n\n**Alerting:** Error rate > 5%, rate limit exceeded, average latency > 10 seconds, service availability < 99%.\n\n### API Key Rotation\n\n```javascript\nclass CohereClientManager {\n  constructor() {\n    this.client = null;\n    this.apiKey = null;\n  }\n\n  initialize(apiKey) {\n    this.apiKey = apiKey;\n    this.client = new CohereClientV2({ token: apiKey });\n  }\n\n  rotateApiKey(newApiKey) {\n    console.log(\"Rotating API key...\");\n    this.apiKey = newApiKey;\n    this.client = new CohereClientV2({ token: newApiKey });\n    console.log(\"API key rotated successfully\");\n  }\n\n  getClient() {\n    if (!this.client) {\n      throw new Error(\"Client not initialized\");\n    }\n    return this.client;\n  }\n}\n\n// Usage\nconst manager = new CohereClientManager();\nmanager.initialize(process.env.COHERE_API_KEY);\n\n// When rotating keys\nmanager.rotateApiKey(process.env.NEW_COHERE_API_KEY);\n```\n\n### Cost Optimization\n\n**Monitor usage:**\n\n```javascript\nclass UsageTracker {\n  constructor() {\n    this.usage = {\n      requests: 0,\n      inputTokens: 0,\n      outputTokens: 0\n    };\n  }\n\n  async trackChat(messages) {\n    this.usage.requests++;\n\n    const stream = await cohere.chatStream({\n      model: \"command-a-03-2025\",\n      messages: messages\n    });\n\n    for await (const event of stream) {\n      if (event.type === \"message-end\" && event.delta?.usage) {\n        this.usage.inputTokens += event.delta.usage.inputTokens || 0;\n        this.usage.outputTokens += event.delta.usage.outputTokens || 0;\n      }\n    }\n\n    return this.getUsage();\n  }\n\n  getUsage() {\n    return { ...this.usage };\n  }\n}\n```\n\n**Optimize costs:** Use appropriate models (don't use command-a-03-2025 for simple tasks), set reasonable `maxTokens` limits, cache embeddings and rerank results, batch requests when possible, and use streaming to cancel long-running requests early if needed.\n\n### Upgrade to Production API Key\n\n**Trial key limitations:** 20 chat calls/minute, 5 embed calls/minute, 1,000 calls/month total.\n\n**To upgrade:** Add payment method in Cohere dashboard, get production API key, update `COHERE_API_KEY` environment variable, and verify rate limits increased.\n\n**Production benefits:** 500+ requests/minute (varies by endpoint), unlimited monthly usage, priority support, and higher rate limits available on request.\n\n### Compliance & Safety\n\n```javascript\n// Content moderation example\nasync function moderatedChat(userMessage) {\n  const response = await cohere.chat({\n    model: \"command-a-03-2025\",\n    messages: [{ role: \"user\", content: userMessage }],\n    safetyMode: \"STRICT\"\n  });\n\n  // Log for compliance audit\n  auditLogger.log({\n    timestamp: new Date().toISOString(),\n    userId: getCurrentUserId(),\n    input: userMessage,\n    output: response.message.content[0].text,\n    model: \"command-a-03-2025\"\n  });\n\n  return response;\n}\n```\n\n**Compliance considerations:** Log all interactions for audit trails, implement content filtering, handle PII appropriately, follow data retention policies, and comply with regional regulations (GDPR, CCPA, etc.)\n\n### Deployment Checklist\n\nEnsure API key is stored in secure secret management system, exact SDK version is pinned in `package.json`, comprehensive error handling is implemented, timeout and retry configuration is set, response validation is in place, logging and monitoring is configured, rate limiting is handled gracefully, tests cover error scenarios, load testing is completed, alerting rules are configured, documentation is updated, staging environment is tested, rollback plan is prepared, and team is trained on debugging procedures.\n\n---\n\n## Additional Resources\n\nAccess comprehensive documentation and resources using the npm CLI:\n\n```bash\n# View package information and links\nnpm info cohere-ai\n\n# Open package homepage in browser\nnpm home cohere-ai\n\n# Open package repository in browser\nnpm repo cohere-ai\n\n# Open package issues page\nnpm bugs cohere-ai\n\n# View package documentation\nnpm docs cohere-ai\n```\n\nOfficial documentation available at: https://docs.cohere.com/reference/about\n"
  },
  {
    "path": "content/cohere/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cohere Python SDK guide for chat, embeddings, rerank, classification, and async usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.20.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cohere,python,llm,chat,embeddings,rerank\"\n---\n\n# Cohere Python Package Guide\n\n## When To Use This\n\nUse the official `cohere` PyPI package when a Python project needs Cohere-hosted chat, embeddings, reranking, or classification APIs.\n\n- Ecosystem: `pypi`\n- Package: `cohere`\n- Import: `import cohere`\n- Version covered here: `5.20.7`\n- Official docs root: `https://docs.cohere.com/`\n- Reference landing page: `https://docs.cohere.com/reference/about`\n\n## Installation\n\nInstall the package directly:\n\n```bash\npip install cohere==5.20.7\n```\n\nIf the project does not need an exact pin, `pip install cohere` is the normal install path.\n\n## Authentication And Setup\n\nThe official Python SDK examples use the `CO_API_KEY` environment variable.\n\n```bash\nexport CO_API_KEY=\"your-cohere-api-key\"\n```\n\nCreate a sync or async v2 client:\n\n```python\nimport os\nimport cohere\n\nco = cohere.ClientV2(api_key=os.environ[\"CO_API_KEY\"])\n```\n\n```python\nimport os\nimport cohere\n\nco = cohere.AsyncClientV2(api_key=os.environ[\"CO_API_KEY\"])\n```\n\nNotes:\n\n- Prefer environment variables over hardcoded API keys.\n- Treat `ClientV2` and `AsyncClientV2` as the default entry points for new code.\n- For request failures, catch `cohere.core.api_error.ApiError`.\n\n## Core Usage\n\n### Chat\n\nUse `messages=[...]` with explicit roles. Newer v2 examples are message-based, not a single prompt string.\n\n```python\nimport os\nimport cohere\n\nco = cohere.ClientV2(api_key=os.environ[\"CO_API_KEY\"])\n\nresponse = co.chat(\n    model=\"command-a-03-2025\",\n    messages=[\n        {\"role\": \"user\", \"content\": \"Summarize why vector search is useful.\"}\n    ],\n)\n\nprint(response.message.content[0].text)\n```\n\n### Async Chat\n\nUse `AsyncClientV2` inside an async function and `await` the request.\n\n```python\nimport asyncio\nimport os\nimport cohere\n\nasync def main() -> None:\n    co = cohere.AsyncClientV2(api_key=os.environ[\"CO_API_KEY\"])\n    response = await co.chat(\n        model=\"command-a-03-2025\",\n        messages=[\n            {\"role\": \"user\", \"content\": \"Give me a two-line release note summary.\"}\n        ],\n    )\n    print(response.message.content[0].text)\n\nasyncio.run(main())\n```\n\n### Embeddings\n\nFor v2 embeddings, the official SDK exposes typed inputs. Set the `input_type` deliberately so retrieval code uses the correct embedding mode.\n\n```python\nimport os\nimport cohere\nfrom cohere.types import EmbedInput\n\nco = cohere.ClientV2(api_key=os.environ[\"CO_API_KEY\"])\n\nresponse = co.embed(\n    model=\"embed-v4.0\",\n    inputs=[\n        EmbedInput(text=\"Store package docs for coding assistants.\")\n    ],\n    embedding_types=[\"float\"],\n    input_type=\"search_document\",\n)\n\nvector = response.embeddings.float_[0]\nprint(len(vector))\n```\n\nUse `input_type=\"search_query\"` for the query side of retrieval and `input_type=\"search_document\"` for indexed content.\n\n### Rerank\n\nRerank is useful after an initial retrieval step. It returns relevance scores plus original indexes, so keep the original document list around.\n\n```python\nimport os\nimport cohere\n\nco = cohere.ClientV2(api_key=os.environ[\"CO_API_KEY\"])\n\ndocuments = [\n    \"Cohere provides chat models and embedding models.\",\n    \"S3 is an object storage service.\",\n    \"Reranking improves search result ordering.\",\n]\n\nresponse = co.rerank(\n    model=\"rerank-v3.5\",\n    query=\"Which document is about improving retrieval quality?\",\n    documents=documents,\n    top_n=2,\n)\n\nfor result in response.results:\n    print(result.index, result.relevance_score, documents[result.index])\n```\n\n### Classification\n\nThe Python SDK still exposes classification. The API is example-driven, so pass labeled examples instead of free-form instruction text.\n\n```python\nimport os\nimport cohere\nfrom cohere.types import ClassifyExample\n\nco = cohere.ClientV2(api_key=os.environ[\"CO_API_KEY\"])\n\nresponse = co.classify(\n    inputs=[\"Confirm the meeting is still on for tomorrow.\"],\n    examples=[\n        ClassifyExample(text=\"Schedule a calendar event for Friday.\", label=\"calendar\"),\n        ClassifyExample(text=\"Reply to the customer about the outage.\", label=\"support\"),\n    ],\n)\n\nprint(response.classifications[0].prediction)\n```\n\n## Configuration And Operational Notes\n\n- The package name and import name are both `cohere`.\n- Pin the SDK version when a project depends on generated types or exact response shapes.\n- Verify model IDs in the current docs before copying an old snippet. Model names evolve independently of the SDK package version.\n- Separate sync and async codepaths cleanly. Do not mix `ClientV2` and `AsyncClientV2` call patterns.\n- Keep rerank input documents in memory or in a parallel structure because the API returns indexes into your submitted list.\n\n## Common Pitfalls\n\n- Using older examples that instantiate `cohere.Client` or older v1-style request shapes. For new work, prefer the v2 client surface.\n- Passing a plain string prompt to `chat` instead of a `messages` list with roles.\n- Using the wrong embedding `input_type`, which hurts retrieval quality even if the request succeeds.\n- Assuming the embed response is always a plain list. In v2, embeddings are typed, for example `response.embeddings.float_`.\n- Catching broad exceptions only. Use `cohere.core.api_error.ApiError` for request failures you expect from the SDK.\n\n## Version-Sensitive Notes For `5.20.7`\n\n- This doc is pinned to `cohere` `5.20.7`, but the official docs site is organized around the current v2 API docs rather than versioned per package release.\n- The official `cohere-python` repository includes a v4-to-v5 migration guide. If a codebase still uses pre-v5 snippets, check that guide before rewriting imports or error handling.\n- The docs URL points to the API reference landing page. For implementation work, the most useful current pages are under `https://docs.cohere.com/v2/docs/`.\n\n## Official Sources\n\n- Docs landing: https://docs.cohere.com/reference/about\n- Quickstart: https://docs.cohere.com/v2/docs/quickstart\n- Text generation: https://docs.cohere.com/v2/docs/text-generation\n- Embeddings: https://docs.cohere.com/v2/docs/embeddings\n- Rerank quickstart: https://docs.cohere.com/v2/docs/reranking-quickstart\n- Classification quickstart: https://docs.cohere.com/v2/docs/classify-quickstart\n- API keys: https://docs.cohere.com/v2/docs/api-keys\n- PyPI: https://pypi.org/project/cohere/\n- SDK repo: https://github.com/cohere-ai/cohere-python\n- SDK reference markdown: https://raw.githubusercontent.com/cohere-ai/cohere-python/main/reference.md\n- v4 to v5 migration guide: https://raw.githubusercontent.com/cohere-ai/cohere-python/main/migrating_v4-v5.md\n"
  },
  {
    "path": "content/colorama/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"colorama package guide for Python 0.4.6 - cross-platform ANSI color and cursor control for terminals\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.6\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"colorama,python,terminal,ansi,windows,console\"\n---\n\n# colorama Python Package Guide\n\n## What It Is\n\n`colorama` makes ANSI escape sequences usable in Windows terminals and exposes simple constants for colors, styles, and cursor movement.\n\nFor `0.4.6`, prefer `just_fix_windows_console()` if your goal is \"make ANSI colors work on Windows\". Use `init()` only when you need its legacy behavior or keyword flags.\n\n## Installation\n\n```bash\npip install colorama==0.4.6\n```\n\nWith `uv`:\n\n```bash\nuv add colorama==0.4.6\n```\n\n## Quick Start\n\n```python\nfrom colorama import Fore, Style, just_fix_windows_console\n\njust_fix_windows_console()\n\nprint(Fore.GREEN + \"success\")\nprint(Fore.RED + \"error\")\nprint(Style.RESET_ALL + \"normal text\")\n```\n\nWhat this does:\n\n- On modern Windows consoles, it enables native ANSI handling.\n- On older Windows consoles, it wraps `stdout` and `stderr` to translate ANSI codes.\n- On non-Windows platforms, it does nothing.\n\n## Recommended Initialization\n\nUse this in CLI entry points or at process startup:\n\n```python\nfrom colorama import just_fix_windows_console\n\ndef main() -> None:\n    just_fix_windows_console()\n    # rest of CLI startup\n```\n\nWhy this is the default:\n\n- Safe to call multiple times.\n- Safe on non-Windows platforms.\n- Safe when output is redirected to files.\n- New in `0.4.6`; this is the upstream-recommended API for most users.\n\n## Core Usage\n\n### Foreground, Background, Style\n\n```python\nfrom colorama import Back, Fore, Style, just_fix_windows_console\n\njust_fix_windows_console()\n\nprint(Fore.YELLOW + \"warning\")\nprint(Back.BLUE + Fore.WHITE + \"status line\")\nprint(Style.BRIGHT + \"important\")\nprint(Style.RESET_ALL + \"back to default\")\n```\n\nCommon constants:\n\n- `Fore`: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, `WHITE`, `RESET`\n- `Back`: same color set plus `RESET`\n- `Style`: `DIM`, `NORMAL`, `BRIGHT`, `RESET_ALL`\n\nExtended light colors are also available, for example `Fore.LIGHTGREEN_EX`.\n\n### Cursor Positioning\n\n```python\nfrom colorama import Cursor, just_fix_windows_console\n\njust_fix_windows_console()\n\nprint(\"line 1\")\nprint(Cursor.UP(1) + Cursor.FORWARD(8) + \"updated\")\n```\n\nUse cursor helpers when you need lightweight terminal updates without pulling in a full TUI library.\n\n### Manual ANSI Sequences\n\n`colorama` also works if your code or another library emits raw ANSI escape sequences:\n\n```python\nfrom colorama import just_fix_windows_console\n\njust_fix_windows_console()\nprint(\"\\033[31mred text\\033[39m\")\n```\n\nThis is useful when combining `colorama` with libraries such as `termcolor` or `rich`.\n\n## Legacy `init()` API\n\n`init()` still works and is required only if you need its keyword arguments:\n\n```python\nfrom colorama import Fore, init\n\ninit(autoreset=True)\nprint(Fore.RED + \"auto-reset after each write\")\nprint(\"already back to default\")\n```\n\nSupported keyword arguments in `0.4.6`:\n\n- `autoreset=False`: automatically reset styles after each write\n- `strip=None`: force stripping ANSI sequences on or off\n- `convert=None`: force Windows conversion on or off\n- `wrap=True`: replace `sys.stdout` and `sys.stderr` with wrapped streams\n\nImportant behavior:\n\n- `init()` is not safe to call repeatedly. Repeated calls can stack wrappers and break output.\n- `deinit()` restores the original streams.\n- `reinit()` re-enables previously wrapped streams more cheaply than another `init()`.\n- `wrap=False` cannot be combined with truthy `autoreset`, `strip`, or `convert`; `0.4.6` raises `ValueError`.\n\n## Advanced Stream Wrapping\n\nIf `init(wrap=True)` interferes with your program's stream handling, use `AnsiToWin32` directly:\n\n```python\nimport sys\n\nfrom colorama import AnsiToWin32, Fore, init\n\ninit(wrap=False)\nstream = AnsiToWin32(sys.stderr).stream\n\nprint(Fore.CYAN + \"sent through wrapped stderr\", file=stream)\n```\n\nUse this pattern when a framework expects the real `sys.stdout`/`sys.stderr` objects but you still need Windows ANSI conversion on a specific stream.\n\n## Setup and Configuration Notes\n\n`colorama` has no authentication, network setup, or environment-variable configuration.\n\nThe only practical configuration surface is initialization:\n\n- Prefer `just_fix_windows_console()` for simple compatibility.\n- Use `init()` only if you specifically need `autoreset`, forced `strip`, forced `convert`, or `wrap=False`.\n- Initialize once near process startup, not inside hot loops or helper functions.\n\n## Common Pitfalls\n\n### Forgetting to reset styles\n\nWithout a reset, later output can inherit styles:\n\n```python\nfrom colorama import Fore, Style\n\nprint(Fore.RED + \"error\" + Style.RESET_ALL)\n```\n\nIf you do this constantly, `init(autoreset=True)` can be simpler.\n\n### Using `init()` where `just_fix_windows_console()` is enough\n\nFor `0.4.6+`, this is the main version-specific trap. `just_fix_windows_console()` has fewer side effects and is the upstream recommendation for most users.\n\n### Expecting `Style.DIM` to render distinctly on Windows\n\nUpstream notes that dim text is not supported well on Windows consoles; it can appear the same as normal text.\n\n### Assuming wrapped streams behave exactly like original streams\n\n`init()` may replace `sys.stdout` and `sys.stderr`. That can matter for tests, logging setup, subprocess integrations, or frameworks that inspect raw stream objects.\n\n### Expecting Colorama to be a full styling framework\n\n`colorama` is intentionally small. It is mainly for ANSI compatibility on Windows. For richer styling, use another ANSI-producing library and let `colorama` handle Windows compatibility.\n\n## Version-Sensitive Notes for `0.4.6`\n\n- `just_fix_windows_console()` is available in `0.4.6` and is the preferred entry point for new code.\n- The package version on PyPI is still `0.4.6`, released on `2022-10-25`.\n- PyPI metadata for `0.4.6` lists support for Python `>=2.7` except `3.0` through `3.6`, so for current projects treat it as effectively Python `3.7+`.\n- The GitHub repository default branch may describe newer development state than the `0.4.6` release. For coding against this pinned package version, prefer the `0.4.6` tag and the PyPI release page.\n\n## Practical Agent Guidance\n\n- If you see `Fore`, `Back`, `Style`, or raw `\\033[` sequences in a CLI app, initialize `colorama` once near startup.\n- For modern code on `0.4.6`, start with `just_fix_windows_console()`.\n- If tests snapshot terminal output, be explicit about whether ANSI codes should be present or stripped.\n- If output is redirected or piped, remember that `init()` may strip ANSI sequences depending on its heuristic and stream type.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/colorama/\n- Repository: https://github.com/tartley/colorama\n- Versioned README: https://github.com/tartley/colorama/blob/0.4.6/README.rst\n- Versioned source exports: https://raw.githubusercontent.com/tartley/colorama/0.4.6/colorama/__init__.py\n- Versioned initialization logic: https://raw.githubusercontent.com/tartley/colorama/0.4.6/colorama/initialise.py\n"
  },
  {
    "path": "content/colorlog/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"colorlog package guide for Python logging with ANSI-colored console output\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.10.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"colorlog,python,logging,ansi,terminal\"\n---\n\n# colorlog Python Package Guide\n\n## What It Is\n\n`colorlog` adds ANSI color formatting to Python's standard-library `logging` handlers. Use it when you want colored terminal logs while keeping the normal `logging` logger, handler, and configuration model.\n\n`colorlog` has no auth flow, no service client, and no package-specific environment variables. The important setup step is creating a `logging` handler and attaching `colorlog.ColoredFormatter` to it.\n\n## Installation\n\nPin the version your application expects:\n\n```bash\npython -m pip install \"colorlog==6.10.1\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"colorlog==6.10.1\"\n```\n\nWith Poetry:\n\n```bash\npoetry add \"colorlog==6.10.1\"\n```\n\n## Quick Start\n\nAttach `ColoredFormatter` to a console handler:\n\n```python\nimport logging\n\nfrom colorlog import ColoredFormatter\n\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(\n    ColoredFormatter(\n        \"%(log_color)s%(levelname)-8s%(reset)s %(name)s %(message)s\"\n    )\n)\n\nlogger = logging.getLogger(\"myapp\")\nlogger.setLevel(logging.INFO)\nlogger.addHandler(handler)\nlogger.propagate = False\n\nlogger.debug(\"debug details\")\nlogger.info(\"server started\")\nlogger.warning(\"cache miss\")\nlogger.error(\"request failed\")\nlogger.critical(\"database unavailable\")\n```\n\nThe key fields in the format string are:\n\n- `%(log_color)s`: inserts the color chosen for the current log level\n- `%(reset)s`: resets terminal styling so later output is not left colored\n- normal `logging` fields like `%(levelname)s`, `%(name)s`, and `%(message)s`\n\n## Customize Colors Per Log Level\n\nPass `log_colors` when the default mapping is not enough:\n\n```python\nimport logging\n\nfrom colorlog import ColoredFormatter\n\n\nformatter = ColoredFormatter(\n    \"%(log_color)s%(levelname)-8s%(reset)s %(name)s %(message)s\",\n    log_colors={\n        \"DEBUG\": \"cyan\",\n        \"INFO\": \"green\",\n        \"WARNING\": \"yellow\",\n        \"ERROR\": \"red\",\n        \"CRITICAL\": \"red,bg_white\",\n    },\n)\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(formatter)\n\nlogger = logging.getLogger(\"myapp\")\nlogger.setLevel(logging.DEBUG)\nlogger.addHandler(handler)\nlogger.propagate = False\n```\n\nThis keeps your logger API unchanged. The only difference is how records are rendered by the handler.\n\n## Use With `logging.config.dictConfig`\n\n`colorlog` works cleanly with the standard `dictConfig` path:\n\n```python\nimport logging\nimport logging.config\n\n\nlogging.config.dictConfig(\n    {\n        \"version\": 1,\n        \"disable_existing_loggers\": False,\n        \"formatters\": {\n            \"colored\": {\n                \"()\": \"colorlog.ColoredFormatter\",\n                \"format\": \"%(log_color)s%(levelname)-8s%(reset)s %(name)s %(message)s\",\n                \"log_colors\": {\n                    \"DEBUG\": \"cyan\",\n                    \"INFO\": \"green\",\n                    \"WARNING\": \"yellow\",\n                    \"ERROR\": \"red\",\n                    \"CRITICAL\": \"red,bg_white\",\n                },\n            }\n        },\n        \"handlers\": {\n            \"console\": {\n                \"class\": \"logging.StreamHandler\",\n                \"formatter\": \"colored\",\n            }\n        },\n        \"root\": {\n            \"handlers\": [\"console\"],\n            \"level\": \"INFO\",\n        },\n    }\n)\n\nlog = logging.getLogger(\"worker\")\nlog.info(\"job started\")\n```\n\nUse this approach when the application already centralizes logging setup in settings files or bootstrapping code.\n\n## Secondary Colors Inside The Message\n\nUse `secondary_log_colors` when you want a second color mapping in the same formatted record. The mapping key becomes a formatter field named `<key>_log_color`:\n\n```python\nimport logging\n\nfrom colorlog import ColoredFormatter\n\n\nformatter = ColoredFormatter(\n    \"%(log_color)s%(levelname)-8s%(reset)s %(message_log_color)s%(message)s\",\n    secondary_log_colors={\n        \"message\": {\n            \"ERROR\": \"red\",\n            \"CRITICAL\": \"red\",\n        }\n    },\n)\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(formatter)\n\nlogger = logging.getLogger(\"billing\")\nlogger.setLevel(logging.INFO)\nlogger.addHandler(handler)\nlogger.propagate = False\n\nlogger.error(\"card charge failed\")\n```\n\nThis is useful when you want the level label and the message body to follow different color rules.\n\n## Setup Notes\n\n- Environment variables: none\n- Authentication: none\n- Client initialization: none\n- Main integration point: `logging.StreamHandler()` plus `colorlog.ColoredFormatter(...)`\n\nFor terminal output, attach `ColoredFormatter` to stream handlers. For file logs, use a plain `logging.Formatter` unless you explicitly want ANSI escape sequences written to the file.\n\n## Common Pitfalls\n\n### Forgetting `%(log_color)s` in the format string\n\nIf the format string does not include a color field, the formatter still runs but your output does not become colorized.\n\n### Reusing the same handler setup on file outputs\n\nANSI color codes are appropriate for terminals, but they are usually the wrong choice for log files, JSON logs, or other machine-consumed output.\n\n### Seeing duplicate log lines\n\nIf your logger already propagates to the root logger and the root logger has its own handler, you can get each message twice. Set `logger.propagate = False` when you want only your explicitly attached colored handler.\n\n### Expecting `colorlog` to replace `logging`\n\n`colorlog` is a formatter for the stdlib logging system. You still configure loggers, handlers, levels, and propagation through `logging` itself.\n\n## Official Sources\n\n- Repository: `https://github.com/borntyping/python-colorlog`\n- PyPI: `https://pypi.org/project/colorlog/`\n"
  },
  {
    "path": "content/comet-ml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Comet ML Python SDK for experiment tracking, autologging, and experiment queries\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.57.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"comet-ml,comet,python,mlops,experiment-tracking,observability\"\n---\n\n# comet-ml Python Package Guide\n\n## Installation\n\nUse the package name from PyPI:\n\n```bash\npip install comet-ml==3.57.2\n```\n\nCommon alternatives:\n\n```bash\nuv add comet-ml\npoetry add comet-ml\n```\n\n## Authentication And Basic Configuration\n\nFor normal online logging, Comet needs an API key and usually a workspace and project name.\n\nSet them with environment variables:\n\n```bash\nexport COMET_API_KEY=\"YOUR_API_KEY\"\nexport COMET_WORKSPACE=\"YOUR_WORKSPACE\"\nexport COMET_PROJECT_NAME=\"YOUR_PROJECT\"\n```\n\nOr persist them in `~/.comet.config`:\n\n```ini\n[comet]\napi_key=YOUR_API_KEY\nworkspace=YOUR_WORKSPACE\nproject_name=YOUR_PROJECT\n```\n\nEnvironment variables are the safer default for CI, containers, and ephemeral dev environments.\n\n## Recommended Initialization For New Code\n\nThe current quickstart uses `comet_ml.start()` as the main entry point for new code:\n\n```python\nimport os\nimport comet_ml\n\nexperiment = comet_ml.start(\n    api_key=os.environ[\"COMET_API_KEY\"],\n    workspace=os.environ[\"COMET_WORKSPACE\"],\n    project_name=os.environ.get(\"COMET_PROJECT_NAME\", \"sandbox\"),\n)\n\nexperiment.set_name(\"baseline-run\")\nexperiment.log_parameter(\"learning_rate\", 1e-3)\nexperiment.log_parameter(\"batch_size\", 64)\n\nfor step, loss in enumerate([0.82, 0.57, 0.41], start=1):\n    experiment.log_metric(\"loss\", loss, step=step)\n\nexperiment.log_metrics({\"accuracy\": 0.93, \"f1\": 0.91}, step=3)\n```\n\nComet also automatically logs source code, installed packages, command-line details, Git metadata, CPU and GPU usage, and network activity unless you change the default configuration.\n\n## Explicit Experiment Classes\n\nUse the explicit classes when you need tighter lifecycle control:\n\n- `Experiment` for normal online runs\n- `ExistingExperiment` to resume an already-created experiment\n- `OfflineExperiment` when the training environment cannot reach Comet\n\nExample offline run:\n\n```python\nfrom comet_ml import OfflineExperiment\n\nexperiment = OfflineExperiment(\n    offline_directory=\"./comet-offline\",\n    project_name=\"sandbox\",\n)\n\nexperiment.log_parameter(\"model\", \"xgboost\")\nexperiment.log_metric(\"auc\", 0.94)\n```\n\nThe offline workflow produces experiment zip files. Upload them later with the documented `comet upload <path-to-experiment-zip>` flow from the offline experiments guide.\n\n## Reading Existing Experiments\n\nIf the task is to read experiment history, models, or assets instead of logging a new run, initialize the SDK's API client:\n\n```python\nimport os\nfrom comet_ml import API\n\napi = API(api_key=os.environ[\"COMET_API_KEY\"])\n```\n\nUse the Python SDK API reference for project, experiment, model, and asset retrieval methods after creating the client.\n\n## Common Pitfalls\n\n- Install with `pip install comet-ml`, but import it as `comet_ml`.\n- Prefer `comet_ml.start()` for new code. Many older blog posts and snippets still construct `Experiment(...)` directly.\n- Do not rely on interactive local configuration in CI. Set `COMET_API_KEY`, `COMET_WORKSPACE`, and `COMET_PROJECT_NAME` explicitly.\n- Default autologging may capture code, package lists, Git metadata, and system information. Review the configuration reference before running against sensitive repositories or restricted environments.\n- The docs URL path uses `/docs/v2/`, but that is the documentation site versioning, not the PyPI package version. Package compatibility should be checked against the installed `comet-ml` release.\n\n## Version-Sensitive Notes For `3.57.2`\n\n- PyPI currently lists `3.57.2` as the latest `comet-ml` release, published on 2026-03-09.\n- The current official quickstart and SDK docs are aligned around `comet_ml.start()` plus the Python SDK reference pages under `docs/v2`.\n- When copying older Comet examples, verify whether they use deprecated initialization style or older class names before reusing them unchanged.\n\n## Official Sources\n\n- PyPI package: `https://pypi.org/project/comet-ml/`\n- Docs root: `https://www.comet.com/docs/v2/`\n- Python quickstart: `https://www.comet.com/docs/v2/guides/getting-started/quickstart/`\n- Python configuration reference: `https://www.comet.com/docs/v2/guides/experiment-management/configure-sdk/`\n- Offline experiments guide: `https://www.comet.com/docs/v2/guides/experiment-management/offline-experiments/`\n- Python SDK API reference: `https://www.comet.com/docs/v2/api-and-sdk/python-sdk/reference/API/`\n"
  },
  {
    "path": "content/commander/docs/commander/javascript/DOC.md",
    "content": "---\nname: commander\ndescription: \"Commander.js for building Node.js command-line interfaces with options, arguments, subcommands, help, and executable subcommands.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"14.0.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"commander,cli,node,javascript,arguments,options\"\n---\n\n# Commander.js Guide for JavaScript CLIs\n\n## Golden Rule\n\nUse the official `commander` package to define your CLI surface: command name, arguments, options, help text, and subcommands.\n\nCommander does not need API credentials or client setup. Your app creates a `Command`, declares the interface, and calls `.parse()` or `.parseAsync()`.\n\nFor small scripts, `program` is fine. For reusable modules, tests, or larger CLIs, prefer `new Command()` so you do not share global state.\n\n## Install\n\nCommander 14 is intended for current Node.js releases. The published package metadata for the 14.x line requires Node.js 20 or newer.\n\n```bash\nnpm install commander@14.0.3\n```\n\nIf you are publishing a CLI, expose an executable through `package.json` and add a Node shebang to the entry file.\n\n```json\n{\n  \"name\": \"acme-cli\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"acme\": \"./bin/acme.js\"\n  }\n}\n```\n\n```js\n#!/usr/bin/env node\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram.name('acme').version('1.0.0');\nprogram.parse();\n```\n\nMake the file executable before publishing:\n\n```bash\nchmod +x bin/acme.js\n```\n\n## Imports and Initialization\n\n### ECMAScript modules\n\n```js\nimport { Command, InvalidArgumentError, Option } from 'commander';\n\nconst program = new Command();\n```\n\n### CommonJS\n\n```js\nconst { Command, InvalidArgumentError, Option } = require('commander');\n\nconst program = new Command();\n```\n\n### Quick single-file program\n\nFor short scripts, Commander also exports a shared `program` object.\n\n```js\nimport { program } from 'commander';\n\nprogram\n  .name('hello')\n  .argument('<name>')\n  .action((name) => {\n    console.log(`hello ${name}`);\n  });\n\nprogram.parse();\n```\n\n## Common Workflows\n\n### Parse arguments and options\n\nUse `.argument()` for positional arguments and `.option()` or `.requiredOption()` for flags. Read parsed values with `.opts()` or from the action handler.\n\n```js\n#!/usr/bin/env node\nimport { Command, InvalidArgumentError, Option } from 'commander';\n\nfunction parseInteger(value) {\n  const parsed = Number.parseInt(value, 10);\n  if (Number.isNaN(parsed)) {\n    throw new InvalidArgumentError('Expected an integer.');\n  }\n  return parsed;\n}\n\nconst program = new Command();\n\nprogram\n  .name('bundle')\n  .description('Bundle a project for deployment')\n  .version('1.0.0')\n  .argument('<entry>', 'entry file to bundle')\n  .requiredOption('-c, --config <path>', 'path to config file')\n  .option('-w, --watch', 'rebuild when files change')\n  .option('--no-color', 'disable ANSI colors')\n  .addOption(\n    new Option('-p, --port <number>', 'preview server port')\n      .env('PORT')\n      .argParser(parseInteger)\n      .default(3000)\n  )\n  .showHelpAfterError()\n  .action((entry, options, command) => {\n    if (options.watch) {\n      console.error(`watch mode enabled for ${command.name()}`);\n    }\n\n    console.log({\n      entry,\n      config: options.config,\n      port: options.port,\n      watch: options.watch,\n      color: options.color,\n    });\n  });\n\nprogram.parse();\n```\n\nExample invocations:\n\n```bash\nPORT=8080 node bin/bundle.js src/index.js --config bundler.config.json\nnode bin/bundle.js src/index.js --config bundler.config.json --watch --no-color\n```\n\nNotes:\n\n- `--no-color` creates `options.color` and sets it to `false` when present.\n- Multi-word flags like `--template-engine` become camel-cased keys such as `options.templateEngine`.\n- `.parse()` with no arguments defaults to `process.argv`.\n\n### Define subcommands in one process\n\nUse `.command()` with `.action()` when all commands live in the same file or module tree.\n\n```js\n#!/usr/bin/env node\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n  .name('acme')\n  .description('Project automation CLI')\n  .version('1.0.0');\n\nprogram\n  .command('build')\n  .description('build the current project')\n  .option('--watch', 'rebuild on changes')\n  .action((options) => {\n    console.log('build', { watch: options.watch });\n  });\n\nprogram\n  .command('deploy')\n  .description('deploy the current project')\n  .argument('<environment>', 'target environment')\n  .option('--tag <name>', 'release tag')\n  .action((environment, options, command) => {\n    console.log(command.name(), { environment, tag: options.tag });\n  });\n\nprogram.parse();\n```\n\nAction handlers receive declared command arguments first, then the parsed options object, and then the command object itself.\n\n### Use async actions\n\nIf any action handler is async, call `.parseAsync()` instead of `.parse()`.\n\n```js\n#!/usr/bin/env node\nimport { Command } from 'commander';\n\nasync function deploy(environment, options) {\n  await Promise.resolve();\n  console.log(`deploying to ${environment}`, { tag: options.tag });\n}\n\nasync function main() {\n  const program = new Command();\n\n  program\n    .name('acme')\n    .command('deploy')\n    .argument('<environment>')\n    .option('--tag <name>')\n    .action(deploy);\n\n  await program.parseAsync(process.argv);\n}\n\nmain().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n```\n\n### Use stand-alone executable subcommands\n\nIf you pass a description as the second argument to `.command()`, Commander treats the subcommand as a separate executable.\n\nTop-level CLI:\n\n```js\n#!/usr/bin/env node\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n  .name('pm')\n  .version('1.0.0')\n  .executableDir('commands')\n  .command('install [packageNames...]', 'install one or more packages')\n  .command('search [query]', 'search packages');\n\nprogram.parse(process.argv);\n```\n\n`commands/pm-install.js`:\n\n```js\n#!/usr/bin/env node\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n  .argument('[packageNames...]')\n  .option('--save-dev', 'install as a development dependency')\n  .action((packageNames, options) => {\n    console.log('install', { packageNames, saveDev: options.saveDev });\n  });\n\nprogram.parse(process.argv);\n```\n\nCommander looks for files named from the command and subcommand, such as `pm-install` and `pm-search`, and also tries common file extensions like `.js`.\n\n### Customize help and error output\n\nCommander generates help automatically from your command definitions. Add examples or follow-up instructions with `.addHelpText()` and show extra guidance after usage errors with `.showHelpAfterError()`.\n\n```js\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n  .name('acme')\n  .option('-f, --force', 'skip confirmation')\n  .showHelpAfterError('(run with --help for usage details)')\n  .addHelpText(\n    'after',\n    `\nExamples:\n  $ acme deploy production --tag 2026.03.13\n  $ acme build --watch\n`\n  );\n\nprogram.parse();\n```\n\nIf you need Commander-style failures from your own validation, call `.error()`.\n\n```js\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n  .requiredOption('--config <path>')\n  .action((options, command) => {\n    if (!options.config.endsWith('.json')) {\n      command.error('Config file must end with .json');\n    }\n  });\n\nprogram.parse();\n```\n\n### Control parsing rules for wrapper CLIs\n\nCommander is strict by default: unknown options, missing arguments, and excess arguments produce errors.\n\nUse these methods when you are building a wrapper around another tool:\n\n- `.enablePositionalOptions()` to stop looking for parent-command options after a subcommand starts.\n- `.passThroughOptions()` to leave later options for the wrapped command instead of consuming them.\n- `.allowUnknownOption()` when unknown flags should be treated as normal arguments.\n- `.allowExcessArguments()` when the wrapped command accepts more arguments than Commander knows about.\n\n## Common Pitfalls\n\n- Use `await program.parseAsync(...)` if any action handler is async. `program.parse()` does not wait for async handlers.\n- Prefer `program.opts()` or the `options` parameter passed to `.action()`. Storing parsed options as direct properties on the command is legacy behavior.\n- If you use `.passThroughOptions()` on a subcommand, enable positional options on the parent command too.\n- When invoking a CLI through `npm run`, use `--` so npm stops parsing flags before they reach Commander: `npm run cli -- --help`.\n- Stand-alone executable subcommands need executable files with the expected names and a Node shebang.\n- Options with required values are greedy. If you want a flag that may be present with or without a value, declare it with square brackets such as `--cache [path]`.\n\n## Version Notes\n\n- This guide targets `commander@14.0.3`.\n- Commander 14 uses `.opts()` as the normal way to read parsed option values.\n- The official package metadata for the 14.x line publishes both CommonJS and ESM entry points, as well as bundled TypeScript declaration files.\n- For rare option and argument cases, use explicit `Option` and `Argument` objects instead of only the shortcut string forms.\n\n## Official Sources\n\n- https://github.com/tj/commander.js#readme\n- https://github.com/tj/commander.js/tree/master/examples\n- https://github.com/tj/commander.js/tree/master/docs\n- https://www.npmjs.com/package/commander\n"
  },
  {
    "path": "content/commitizen/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Commitizen Python CLI for conventional commits, semantic version bumps, changelog generation, and release automation in Git repositories\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.13.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"commitizen,python,git,conventional-commits,semver,changelog,release\"\n---\n\n# Commitizen Python Package Guide\n\n## Golden Rule\n\nUse `commitizen` as a repo-local release tool inside a Git repository, keep exactly one active Commitizen config file, and choose the version provider that matches how the project already stores its version. `cz bump` depends on commit history and tags, so treat it as release automation rather than a generic text-replacement command.\n\n## Install\n\nFor a project-local setup, add it as a development dependency:\n\n```bash\npython -m pip install \"commitizen==4.13.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"commitizen==4.13.9\"\npoetry add --group dev \"commitizen==4.13.9\"\npipx install \"commitizen==4.13.9\"\n```\n\n`pipx` is useful when you only need the CLI globally. Prefer a project dependency when CI, hooks, and local contributors should all use the same version.\n\n## Configuration And Setup\n\nCommitizen looks for configuration in this order:\n\n1. `pyproject.toml`\n2. `.cz.toml`\n3. `cz.toml`\n4. `.cz.json`\n5. `cz.json`\n6. `.cz.yaml`\n7. `cz.yaml`\n\nIf it finds multiple config files, it warns and uses the first valid one. For Python projects, prefer `[tool.commitizen]` inside `pyproject.toml`.\n\n### Minimal commit-message setup\n\nUse this when you only want `cz commit` and `cz check`:\n\n```toml\n[tool.commitizen]\nname = \"cz_conventional_commits\"\n```\n\n### Typical release-management setup\n\nUse this when the project version lives in `project.version`:\n\n```toml\n[project]\nname = \"my-package\"\nversion = \"0.1.0\"\n\n[tool.commitizen]\nname = \"cz_conventional_commits\"\nversion_provider = \"pep621\"\ntag_format = \"v$version\"\nupdate_changelog_on_bump = true\nversion_files = [\n  \"src/my_package/__init__.py:__version__\",\n]\n```\n\nThen initialize or inspect the config:\n\n```bash\ncz init\ncz info\ncz schema\n```\n\n`cz init` is interactive and writes one of the supported config formats. Keep only one config file afterward.\n\n## Choose The Right Version Provider\n\nThe provider choice controls where `cz bump` reads and writes the project version:\n\n- `commitizen`: default provider. Store the version in Commitizen config with `version = \"...\"`.\n- `pep621`: use `[project] version` in `pyproject.toml`.\n- `uv`: use when the project is managed by `uv`; it updates the PEP 621 version and `uv.lock`.\n- `poetry`: use Poetry-managed version fields.\n- `scm`: derive the version from Git tags. This is read-only and does not write version files.\n\nFor Python packaging work, `pep621` or `uv` is usually the safest choice. Use `scm` only when the repository already treats Git tags as the single source of truth.\n\nCheck the resolved project version with:\n\n```bash\ncz version -p\n```\n\n## Core Workflow\n\n### Create a commit with the configured convention\n\n```bash\ngit add .\ncz commit\n```\n\n`cz commit` opens an interactive prompt based on the configured adapter, usually `cz_conventional_commits`.\n\n### Validate commit messages\n\nValidate a literal message:\n\n```bash\ncz check --message \"feat(api): add release endpoint\"\n```\n\nValidate a commit range in CI:\n\n```bash\ncz check --rev-range origin/main..HEAD\n```\n\nValidate the file passed by a Git `commit-msg` hook:\n\n```bash\ncz check --commit-msg-file .git/COMMIT_EDITMSG\n```\n\n### Bump the version and create a changelog\n\nTypical release command:\n\n```bash\ncz bump --changelog --check-consistency\n```\n\nUseful variants:\n\n```bash\ncz bump --dry-run\ncz bump --files-only\ncz bump --increment PATCH\ncz bump --prerelease alpha\ncz bump --increment-mode=exact\n```\n\nOperational notes:\n\n- `--check-consistency` verifies configured `version_files`, but the docs warn it can still update some files before failing.\n- `--files-only` updates configured files without creating a commit or tag.\n- `--increment-mode=linear` and `--increment-mode=exact` behave differently for prereleases; use `exact` only when you explicitly need to preserve the requested increment.\n- Commitizen uses lightweight tags by default. Enable annotated or signed tags in config if your release process requires them.\n\n### Generate or extend the changelog separately\n\n```bash\ncz changelog\ncz changelog --incremental\n```\n\nCommitizen currently generates changelogs in Markdown only.\n\n## Hook Integration\n\nUse hooks when you want commit validation before history lands in the repository.\n\n### pre-commit\n\n```yaml\nrepos:\n  - repo: https://github.com/commitizen-tools/commitizen\n    rev: v4.13.9\n    hooks:\n      - id: commitizen\n      - id: commitizen-branch\n        stages: [pre-push]\n```\n\nThen install the hooks:\n\n```bash\npre-commit install --hook-type commit-msg --hook-type pre-push\n```\n\nThe upstream auto-check tutorial still shows an older placeholder revision in one example. Pin the hook revision you actually installed instead of copying that value blindly.\n\n### Plain Git hook\n\n```bash\nprintf '%s\\n' '#!/bin/sh' 'cz check --allow-abort --commit-msg-file \"$1\"' > .git/hooks/commit-msg\nchmod +x .git/hooks/commit-msg\n```\n\n## No External Auth\n\nCommitizen does not require API keys or service credentials. The only runtime prerequisites are:\n\n- a Git repository\n- the configured version files, if any\n- Git tags and commit history when using `cz bump`, `cz changelog`, or `scm`\n\n## Common Pitfalls\n\n- Do not keep both `pyproject.toml` and `.cz.toml` active unless you want the first one in the search order to win.\n- The default `commitizen` version provider needs an explicit `version = \"...\"`. Without it, version and bump commands will not behave as expected.\n- `scm` reads from tags; it does not write version files. Teams often choose it and then expect `cz bump` to update `pyproject.toml`.\n- `cz bump` is only as good as the commit history since the previous matching tag. Bad tags or non-conforming commit messages produce bad version increments.\n- If you mirror the version into multiple files, add `--check-consistency` before tagging a release and be ready to restore modified files if the check fails mid-run.\n- `cz changelog` assumes Commitizen-style commit metadata. Existing repositories with inconsistent historical messages usually need a cleanup boundary or a first release tag.\n- `cz commit --signoff` is deprecated and scheduled for removal in `v5`; pass raw git arguments after `--`, for example `cz commit -- -s`.\n\n## Version-Sensitive Notes For 4.13.9\n\n- PyPI lists `commitizen 4.13.9` as the current maintained release on March 12, 2026.\n- The PyPI metadata for `4.13.9` requires Python `>=3.10`, so older Python runtimes need an older Commitizen release line.\n- The maintained docs cover multiple version providers including `pep621`, `uv`, and `scm`; older blog posts often assume only the default provider and miss `uv.lock` or PEP 621 behavior.\n- The `--signoff` shortcut on `cz commit` is already documented as deprecated ahead of `v5`, so do not build new automation around it.\n\n## Official Sources\n\n- Documentation root: https://commitizen-tools.github.io/commitizen/\n- Configuration: https://commitizen-tools.github.io/commitizen/config/\n- Version providers: https://commitizen-tools.github.io/commitizen/config/#version-providers\n- Commit command: https://commitizen-tools.github.io/commitizen/commands/commit/\n- Check command: https://commitizen-tools.github.io/commitizen/commands/check/\n- Bump command: https://commitizen-tools.github.io/commitizen/commands/bump/\n- Changelog command: https://commitizen-tools.github.io/commitizen/commands/changelog/\n- Auto-check hooks tutorial: https://commitizen-tools.github.io/commitizen/tutorials/auto_check/\n- PyPI package: https://pypi.org/project/commitizen/\n"
  },
  {
    "path": "content/confluent-kafka/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"confluent-kafka Python package guide for Apache Kafka producers, consumers, admin APIs, and Schema Registry\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.13.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"confluent,kafka,streaming,producer,consumer,schema-registry\"\n---\n\n# confluent-kafka Python Package Guide\n\n## Golden Rule\n\nUse `confluent-kafka` for Python Kafka clients when you need production-grade Kafka support, Confluent Cloud support, transactions, admin APIs, or Schema Registry integration. Start with the current PyPI package and maintainer README, and treat the Confluent-hosted API reference as useful but slightly behind the current package release when versions disagree.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"confluent-kafka==2.13.2\"\n```\n\nSchema Registry extras:\n\n```bash\npython -m pip install \"confluent-kafka[avro,schemaregistry]==2.13.2\"\npython -m pip install \"confluent-kafka[json,schemaregistry]==2.13.2\"\npython -m pip install \"confluent-kafka[protobuf,schemaregistry]==2.13.2\"\n```\n\nIf you use Data Contracts rules, including CSFLE:\n\n```bash\npython -m pip install \"confluent-kafka[avro,schemaregistry,rules]==2.13.2\"\n```\n\nImportant install note:\n\n- Pre-built Linux wheels do not include SASL Kerberos/GSSAPI support.\n- If you need Kerberos, or if your platform does not have prebuilt wheels, install from source after installing `librdkafka` and the platform build dependencies.\n\nSource install examples from the maintainer install guide:\n\n```bash\n# macOS\nbrew install librdkafka\npython -m pip install --no-binary confluent-kafka confluent-kafka\n```\n\n## Core Imports\n\n```python\nfrom confluent_kafka import Consumer, Producer\nfrom confluent_kafka.admin import AdminClient, NewTopic\nfrom confluent_kafka.schema_registry import SchemaRegistryClient\n```\n\nAsync producer:\n\n```python\nfrom confluent_kafka.aio import AIOProducer\n```\n\n## Authentication And Setup\n\n### Minimal local or self-managed broker config\n\n```python\ncommon_config = {\n    \"bootstrap.servers\": \"localhost:9092\",\n}\n```\n\n### Confluent Cloud with API key and secret\n\n```python\ncloud_config = {\n    \"bootstrap.servers\": \"pkc-xxxxx.region.provider.confluent.cloud:9092\",\n    \"security.protocol\": \"SASL_SSL\",\n    \"sasl.mechanisms\": \"PLAIN\",\n    \"sasl.username\": \"<CLUSTER_API_KEY>\",\n    \"sasl.password\": \"<CLUSTER_API_SECRET>\",\n}\n```\n\nConsumer-specific fields:\n\n```python\nconsumer_config = {\n    **cloud_config,\n    \"group.id\": \"orders-service\",\n    \"auto.offset.reset\": \"earliest\",\n}\n```\n\nNotes:\n\n- `bootstrap.servers` is the one required setting everywhere.\n- `group.id` is required for normal consumer group usage.\n- `auto.offset.reset` matters only when there is no committed offset yet.\n- For Confluent Cloud, the common starting auth shape is `SASL_SSL` + `PLAIN` + API key/secret.\n\n### Kafka OAuth on Confluent Cloud\n\nFor OIDC or workload identity setups, Confluent documents Python client configs using:\n\n```python\noauth_config = {\n    \"bootstrap.servers\": \"your-bootstrap-server:9092\",\n    \"security.protocol\": \"SASL_SSL\",\n    \"sasl.mechanism\": \"OAUTHBEARER\",\n    \"sasl.oauthbearer.token.endpoint.url\": \"https://<your-idp>/oauth2/token\",\n    \"sasl.oauthbearer.client.id\": \"<client-id>\",\n    \"sasl.oauthbearer.client.secret\": \"<client-secret>\",\n    \"sasl.oauthbearer.scope\": \"kafka:read kafka:write\",\n    \"sasl.oauthbearer.extensions\": \"logicalCluster=<lkc-xxxxx>,identityPoolId=<pool-yyyyy>\",\n    \"oauth_cb\": oauth_token_refresh_cb,\n}\n```\n\nThe Python client also exposes `oauth_cb` in the main client configuration for `sasl.mechanisms=OAUTHBEARER`.\n\n### Schema Registry config\n\nBasic client:\n\n```python\nschema_registry_conf = {\n    \"url\": \"https://<schema-registry-endpoint>\",\n    \"basic.auth.credentials.source\": \"USER_INFO\",\n    \"basic.auth.user.info\": \"<schema-registry-api-key>:<schema-registry-api-secret>\",\n}\n\nschema_registry_client = SchemaRegistryClient(schema_registry_conf)\n```\n\nNotes:\n\n- `schema.registry.url` is the canonical config property in Confluent docs; in Python code you pass it as `url` to `SchemaRegistryClient`.\n- `basic.auth.user.info` must be `user:password`.\n- `basic.auth.credentials.source` supports `URL`, `USER_INFO`, and `SASL_INHERIT`.\n- For Schema Registry OAuth, Confluent documents built-in OAuth handling on the client side and notes that `SchemaRegistryClient` does not use `oauth_cb`.\n\n## Producer\n\nThe synchronous `Producer` is the default choice for scripts, workers, and high-throughput pipelines.\n\n```python\nfrom confluent_kafka import Producer\n\ndef delivery_report(err, msg) -> None:\n    if err is not None:\n        print(f\"delivery failed: {err}\")\n    else:\n        print(f\"delivered to {msg.topic()} [{msg.partition()}] @ {msg.offset()}\")\n\nproducer = Producer({\"bootstrap.servers\": \"localhost:9092\"})\n\nfor value in [\"one\", \"two\", \"three\"]:\n    producer.poll(0)\n    producer.produce(\"events\", value=value.encode(\"utf-8\"), callback=delivery_report)\n\nproducer.flush()\n```\n\nImportant behavior:\n\n- `produce()` is asynchronous and queues work locally.\n- Delivery callbacks are served by `poll()` or `flush()`.\n- If the internal queue fills, `produce()` can raise `BufferError`.\n\n### Delivery guarantees\n\nFor stronger durability on a producer:\n\n```python\nproducer = Producer(\n    {\n        \"bootstrap.servers\": \"localhost:9092\",\n        \"acks\": \"all\",\n        \"enable.idempotence\": True,\n    }\n)\n```\n\nUse this pattern when duplicate suppression and safer retries matter more than raw latency.\n\n## Consumer\n\n```python\nfrom confluent_kafka import Consumer\n\nconsumer = Consumer(\n    {\n        \"bootstrap.servers\": \"localhost:9092\",\n        \"group.id\": \"demo-group\",\n        \"auto.offset.reset\": \"earliest\",\n    }\n)\n\nconsumer.subscribe([\"events\"])\n\ntry:\n    while True:\n        msg = consumer.poll(1.0)\n        if msg is None:\n            continue\n        if msg.error():\n            print(f\"consumer error: {msg.error()}\")\n            continue\n\n        print(msg.key(), msg.value())\nfinally:\n    consumer.close()\n```\n\nNotes:\n\n- Always call `close()` so the client leaves the consumer group cleanly and commits final offsets when configured to do so.\n- `poll()` returns `None` on timeout.\n- Handle `msg.error()` before reading the payload.\n\n## Admin API\n\n`AdminClient` methods are asynchronous and return a `dict` of futures keyed by the entity you requested.\n\n```python\nfrom confluent_kafka.admin import AdminClient, NewTopic\n\nadmin = AdminClient({\"bootstrap.servers\": \"localhost:9092\"})\n\nfutures = admin.create_topics(\n    [NewTopic(\"events\", num_partitions=3, replication_factor=1)]\n)\n\nfor topic, future in futures.items():\n    try:\n        future.result()\n        print(f\"created {topic}\")\n    except Exception as exc:\n        print(f\"failed to create {topic}: {exc}\")\n```\n\nUse a higher replication factor in real multi-broker production clusters.\n\n## Schema Registry And Serialization\n\nConfluent recommends direct serializers and deserializers instead of the experimental `SerializingProducer` and `DeserializingConsumer`.\n\nAvro example:\n\n```python\nfrom confluent_kafka import Producer\nfrom confluent_kafka.schema_registry import SchemaRegistryClient\nfrom confluent_kafka.schema_registry.avro import AvroSerializer\nfrom confluent_kafka.serialization import MessageField, SerializationContext\n\nschema_registry_client = SchemaRegistryClient(\n    {\n        \"url\": \"https://<schema-registry-endpoint>\",\n        \"basic.auth.credentials.source\": \"USER_INFO\",\n        \"basic.auth.user.info\": \"<schema-registry-api-key>:<schema-registry-api-secret>\",\n    }\n)\n\nschema_str = \"\"\"\n{\n  \"type\": \"record\",\n  \"name\": \"User\",\n  \"fields\": [{\"name\": \"id\", \"type\": \"string\"}]\n}\n\"\"\"\n\nserializer = AvroSerializer(\n    schema_registry_client,\n    schema_str,\n    to_dict=lambda obj, ctx: obj,\n)\n\nproducer = Producer({\"bootstrap.servers\": \"localhost:9092\"})\n\npayload = serializer({\"id\": \"u-123\"}, SerializationContext(\"users\", MessageField.VALUE))\nproducer.produce(\"users\", value=payload)\nproducer.flush()\n```\n\nUse the same Schema Registry client with JSON Schema or Protobuf serializers when your schema format differs.\n\n## AsyncIO Producer\n\nUse `AIOProducer` when you are already inside an event loop and do not want Kafka I/O to block it.\n\n```python\nimport asyncio\nfrom confluent_kafka.aio import AIOProducer\n\nasync def main() -> None:\n    producer = AIOProducer({\"bootstrap.servers\": \"localhost:9092\"})\n    try:\n        delivery_future = await producer.produce(\"events\", value=b\"hello\")\n        await delivery_future\n        await producer.flush()\n    finally:\n        await producer.close()\n\nasyncio.run(main())\n```\n\nImportant limitation:\n\n- The batched async produce path does not support per-message headers.\n- If you need headers from an async app, use the synchronous `Producer.produce()` on a worker thread or executor for that path.\n\n## Transactions And Exactly-Once Processing\n\nTransactions build on the idempotent producer and require a unique `transactional.id`.\n\n```python\ntransactional_producer = Producer(\n    {\n        \"bootstrap.servers\": \"localhost:9092\",\n        \"transactional.id\": \"orders-service-v1\",\n    }\n)\n\ntransactional_producer.init_transactions()\ntransactional_producer.begin_transaction()\n```\n\nWhen consuming input as part of the transaction:\n\n- Configure the consumer with `enable.auto.commit=false`.\n- Use `isolation.level=read_committed` on transaction-aware consumers.\n- Send offsets to the transaction before committing it.\n\nThis is the path to use for exactly-once pipelines, but it is more operationally strict than simple at-least-once processing.\n\n## Common Pitfalls\n\n- Forgetting `poll()` and `flush()` on the producer means delivery callbacks, stats callbacks, throttle callbacks, and some logging callbacks will not be served.\n- Forgetting `consumer.close()` leads to slow or messy group rebalances.\n- Treating `produce()` as synchronous is wrong; it only queues the message locally.\n- `SerializingProducer` and `DeserializingConsumer` are still marked experimental in the official API docs.\n- `AvroProducer` and `AvroConsumer` are legacy and deprecated.\n- Confluent Cloud Kafka credentials and Schema Registry credentials are often different. Do not assume one API key works for both.\n- On Linux, Kerberos support is not included in the prebuilt wheel; source install is required.\n- For very old Kafka brokers, the client docs still note `broker.version.fallback` and `api.version.request` concerns. You usually do not need these on Kafka 0.10+ or modern Confluent deployments.\n\n## Version-Sensitive Notes For 2.13.2\n\n- PyPI lists `2.13.2` as the current package release as of 2026-03-12.\n- The maintainer README on PyPI and GitHub documents current features such as `AIOProducer`, Schema Registry async support, and package extras.\n- The Confluent-hosted API reference at the docs URL still renders `confluent-kafka 2.11.0`, so use it for API shape and class docs, but cross-check current package behavior against the maintainer README and PyPI metadata when working on `2.13.2`.\n- The official API docs explicitly recommend direct serializers instead of relying on the experimental `SerializingProducer` and `DeserializingConsumer`.\n"
  },
  {
    "path": "content/cookiecutter/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cookiecutter Python package guide for generating projects from reusable templates\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.7.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cookiecutter,python,scaffolding,templates,cli,project-generation,jinja2\"\n---\n\n# Cookiecutter Python Package Guide\n\n## Golden Rule\n\nUse `cookiecutter` as a scaffolding tool, not as a runtime library inside the generated app. Install it as a CLI tool when you mainly generate projects, and add it as a Python dependency only when you need `from cookiecutter.main import cookiecutter` in your own automation.\n\n## Install\n\nIf you mainly want the CLI, prefer an isolated tool install:\n\n```bash\nuv tool install cookiecutter\n# or\npipx install cookiecutter\n```\n\nIf you want it in the current Python environment:\n\n```bash\npython -m pip install \"cookiecutter==2.7.1\"\n```\n\nIf you are calling it from your own Python code, add it to the project environment:\n\n```bash\nuv add \"cookiecutter==2.7.1\"\n# or\npoetry add \"cookiecutter==2.7.1\"\n```\n\nQuick version check:\n\n```bash\ncookiecutter --version\n```\n\n## Core CLI Usage\n\nGenerate from a GitHub-hosted template:\n\n```bash\nuvx cookiecutter gh:audreyfeldroy/cookiecutter-pypackage\n```\n\nGenerate from a local template directory:\n\n```bash\ncookiecutter ./cookiecutter-pypackage\n```\n\nGenerate from a direct Git URL or a specific branch, tag, or commit:\n\n```bash\ncookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackage.git\ncookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackage.git --checkout develop\n```\n\nGenerate from a nested template inside a larger repository:\n\n```bash\ncookiecutter https://github.com/example/platform-templates.git --directory python-service\n```\n\nWrite the result somewhere specific:\n\n```bash\ncookiecutter gh:audreyfeldroy/cookiecutter-pypackage --output-dir ./generated\n```\n\nCookiecutter accepts:\n\n- local template directories\n- GitHub shorthand such as `gh:owner/repo`\n- full `git+...` or `hg+...` repository URLs\n- local or remote `.zip` archives\n- `file://...` paths to remote file shares\n\n## Non-Interactive Automation\n\nUse `--no-input` when you want default values from `cookiecutter.json` and your user config without interactive prompts:\n\n```bash\ncookiecutter gh:audreyfeldroy/cookiecutter-pypackage --no-input\n```\n\nOverride individual variables on the CLI by passing `key=value` pairs after the template:\n\n```bash\ncookiecutter gh:audreyfeldroy/cookiecutter-pypackage \\\n  --no-input \\\n  project_name=\"Acme Service\" \\\n  project_slug=\"acme-service\"\n```\n\nImportant behavior:\n\n- `--no-input` refreshes cached resources instead of reusing the existing clone.\n- `--replay` reuses the previously saved answers for a template.\n- `--replay` cannot be combined with `--no-input` or extra context.\n- `--replay-file <path>` lets you point at a specific replay JSON file.\n\nUseful overwrite controls:\n\n```bash\ncookiecutter ./template --overwrite-if-exists\ncookiecutter ./template --skip-if-file-exists\ncookiecutter ./template --keep-project-on-failure\n```\n\n## Programmatic Python Usage\n\nThe main library entry point is `cookiecutter.main.cookiecutter(...)`.\n\nBasic usage:\n\n```python\nfrom cookiecutter.main import cookiecutter\n\ncookiecutter(\"gh:audreyfeldroy/cookiecutter-pypackage\")\n```\n\nNon-interactive generation with explicit values:\n\n```python\nfrom cookiecutter.main import cookiecutter\n\nproject_path = cookiecutter(\n    \"gh:audreyfeldroy/cookiecutter-pypackage\",\n    no_input=True,\n    extra_context={\n        \"project_name\": \"Acme Service\",\n        \"project_slug\": \"acme-service\",\n    },\n    output_dir=\"generated\",\n    accept_hooks=\"yes\",\n)\n\nprint(project_path)\n```\n\nReplay an earlier generation:\n\n```python\nfrom cookiecutter.main import cookiecutter\n\ncookiecutter(\n    \"gh:hackebrot/cookiedozer\",\n    replay=True,\n)\n```\n\nParameters agents commonly need:\n\n- `checkout`: select a branch, tag, or commit after clone\n- `no_input`: skip prompts and use defaults\n- `extra_context`: override selected template variables\n- `output_dir`: write generated files somewhere predictable\n- `config_file` or `default_config`: control config loading\n- `directory`: select a nested template within a repository\n- `accept_hooks`: control whether hooks run\n- `keep_project_on_failure`: preserve partial output for debugging\n\n## Configuration And Environment\n\nCookiecutter looks for user config in `~/.cookiecutterrc` by default. This is YAML, not JSON.\n\nExample:\n\n```yaml\ndefault_context:\n  full_name: \"Jane Developer\"\n  email: \"jane@example.com\"\n  github_username: \"janedev\"\ncookiecutters_dir: \"~/.cookiecutters/\"\nreplay_dir: \"~/.cookiecutter_replay/\"\nabbreviations:\n  gh: \"https://github.com/{0}.git\"\n  gl: \"https://gitlab.com/{0}.git\"\n```\n\nRelevant config controls:\n\n- `default_context`: default answers injected into every template run\n- `cookiecutters_dir`: where cloned templates are cached\n- `replay_dir`: where replay JSON files are stored\n- `abbreviations`: custom template shorthands\n\nOverride config discovery when needed:\n\n```bash\ncookiecutter --config-file ./cookiecutter.yaml gh:audreyfeldroy/cookiecutter-pypackage\n```\n\nOr set it via environment:\n\n```bash\nexport COOKIECUTTER_CONFIG=\"$PWD/cookiecutter.yaml\"\n```\n\nUse `--default-config` for isolated tests and reproducible automation when you do not want any developer-specific settings to leak in.\n\n### Auth Notes\n\nCookiecutter does not have its own API auth model. Authentication depends on how you fetch the template:\n\n- Git or Mercurial credentials are handled by the underlying VCS tooling.\n- SSH URLs use your existing SSH agent or key setup.\n- Password-protected ZIP templates can use `COOKIECUTTER_REPO_PASSWORD` in automated environments.\n\n## Template Authoring Essentials\n\nA minimal template repository usually has:\n\n```text\ncookiecutter-my-template/\n├── cookiecutter.json\n├── hooks/\n│   ├── pre_gen_project.py\n│   └── post_gen_project.py\n└── {{ cookiecutter.project_slug }}/\n    ├── pyproject.toml\n    └── README.md\n```\n\nCore rules:\n\n- `cookiecutter.json` defines prompt variables and defaults.\n- The generated project directory should usually be templated, such as `{{ cookiecutter.project_slug }}`.\n- Files and paths are rendered through Jinja.\n- Private variables start with `_` or `__` and are not prompted the same way as normal user-facing fields.\n\nUseful authoring features:\n\n- Choice variables: lists in `cookiecutter.json` create menu-style prompts.\n- Dictionary variables: use structured nested config values.\n- `_copy_without_render`: copy file contents verbatim while still rendering paths.\n- `_extensions`: load Jinja extensions you already have installed.\n- local extensions: use `local_extensions.py` in the template root for custom filters or tags.\n- `hooks/`: run setup or validation before and after generation.\n- `templates/`: use Jinja `extends` and `include` for shared file fragments.\n- `templates` in `cookiecutter.json`: create nested template catalogs in a single repo.\n- `__prompts__`: provide human-readable labels for prompts and options.\n\n## Hooks\n\nCookiecutter supports three hook stages:\n\n- `pre_prompt`: runs before prompt rendering and is available in `2.4.0+`\n- `pre_gen_project`: runs after answers are collected and before rendering\n- `post_gen_project`: runs after the project is generated\n\nPrefer Python hooks for cross-platform behavior. Shell hooks can work, but they are more fragile across developer machines and CI environments.\n\nIn automation, decide explicitly whether hooks should run:\n\n```bash\ncookiecutter ./template --accept-hooks yes\ncookiecutter ./template --accept-hooks ask\ncookiecutter ./template --accept-hooks no\n```\n\n## Common Pitfalls\n\n- Do not add `cookiecutter` as an application runtime dependency unless your code actually generates projects at runtime.\n- The output directory cannot be the same as the template input directory.\n- Existing generated directories will fail unless you use `--overwrite-if-exists` or `--skip-if-file-exists`.\n- `--no-input` and `--replay` are mutually exclusive.\n- `--replay` also cannot be combined with extra context on the CLI.\n- Cached templates live under `~/.cookiecutters/` unless your config changes that location.\n- Custom Jinja extensions are not installed automatically; template users must install those dependencies first.\n- Hooks execute code from the template. Treat untrusted templates the same way you would treat untrusted bootstrap scripts.\n- When generating Jinja templates from Jinja templates, use escaping or `_copy_without_render` or you will render content too early.\n\n## Version-Sensitive Notes\n\n- `2.7.1` is the current PyPI release as of March 12, 2026, and supports Python `3.10` through `3.14`.\n- The current maintainers now show `uv`, `uvx`, and `uv tool install` prominently in the PyPI package description, but the official docs still document `pip`, `pipx`, `conda`, and Homebrew flows. All remain valid depending on your environment.\n- `pre_prompt` hooks require Cookiecutter `2.4.0+`.\n- Template inheritance with a `templates/` directory requires Cookiecutter `2.2+`.\n- Local extensions require Cookiecutter `2.1+`.\n- Nested configuration files using the `templates` key require Cookiecutter `2.5.0+`.\n- If a project is pinned to an older `1.x` or early `2.x` release, do not assume these newer template authoring features exist.\n\n## Official Sources\n\n- Docs: `https://cookiecutter.readthedocs.io/en/stable/`\n- Installation: `https://cookiecutter.readthedocs.io/en/stable/installation.html`\n- Usage: `https://cookiecutter.readthedocs.io/en/stable/usage.html`\n- CLI options: `https://cookiecutter.readthedocs.io/en/stable/cli_options.html`\n- User config: `https://cookiecutter.readthedocs.io/en/stable/advanced/user_config.html`\n- API reference: `https://cookiecutter.readthedocs.io/en/stable/cookiecutter.html`\n- PyPI: `https://pypi.org/project/cookiecutter/`\n"
  },
  {
    "path": "content/copier/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Copier Python package guide for rendering and updating project templates from local paths and Git repositories\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.13.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"copier,python,scaffolding,templates,jinja,code-generation\"\n---\n\n# Copier Python Package Guide\n\n## Golden Rule\n\nUse `copier` when you need Python-accessible project scaffolding with update support. Treat templates as executable code: only run trusted templates, keep the generated project's answers file under version control, and use Git tags if you expect `copier update` to work cleanly.\n\n## Install\n\nUse the install mode that matches how you will call Copier:\n\n```bash\n# library use inside a project or virtualenv\npython -m pip install \"copier==9.13.1\"\n\n# standalone CLI\npipx install copier\n\n# standalone CLI with uv\nuv tool install copier\n```\n\nOther official install paths:\n\n```bash\nconda install -c conda-forge copier\nbrew install copier\n```\n\nIf a template depends on extra Jinja extensions, install those in the same environment as Copier. Examples from the docs:\n\n```bash\npip install jinja2-time\npipx inject copier jinja2-time\nuv tool install --with jinja2-time copier\n```\n\n## Core Concepts\n\nCopier works with three pieces:\n\n- Templates: the source tree with `copier.yml` and Jinja-rendered files\n- Questions and answers: prompt data defined in `copier.yml` and stored in an answers file\n- Projects: generated output that can later be updated from the same template\n\nTemplates can be local paths, Git URLs, or shortcuts like `gh:owner/repo.git` and `gl:owner/repo.git`.\n\nBy default, Copier copies from the latest Git tag in the template repository, sorted using PEP 440 version rules. Use `--vcs-ref` or `vcs_ref=` when you need a specific tag, branch, or commit.\n\n## Generate A Project\n\nCLI:\n\n```bash\ncopier copy gh:your-org/your-template.git ./my-project\n```\n\nCLI with non-interactive answers:\n\n```bash\ncopier copy --defaults \\\n  --data project_name=my-project \\\n  --data module_name=my_project \\\n  path/to/template ./my-project\n```\n\nPython API:\n\n```python\nfrom copier import run_copy\n\nrun_copy(\n    \"path/to/template-or-git-url\",\n    \"my-project\",\n    data={\n        \"project_name\": \"my-project\",\n        \"module_name\": \"my_project\",\n    },\n    defaults=True,\n)\n```\n\nNotes:\n\n- If the destination path does not exist, Copier creates it.\n- If the destination path already exists, it must be writable.\n- `--data` values override prompt defaults. `--data-file` is CLI-only.\n- `cleanup_on_error=True` is the default for `copy`; if Copier created the destination and rendering fails, it removes that directory.\n\n## Create A Minimal Template\n\nMinimal template layout:\n\n```text\nmy_copier_template/\n  copier.yml\n  {{project_name}}/\n    {{module_name}}.py.jinja\n  {{_copier_conf.answers_file}}.jinja\n```\n\nMinimal `copier.yml`:\n\n```yaml\nproject_name:\n  type: str\n  help: What is your project name?\n\nmodule_name:\n  type: str\n  help: What is your Python module name?\n```\n\nExample rendered file:\n\n```python\nprint(\"Hello from {{module_name}}!\")\n```\n\nAnswers file template:\n\n```jinja\n# Changes here will be overwritten by Copier\n{{ _copier_answers|to_nice_yaml -}}\n```\n\nKeep the answers file in the generated project if you want updates to work. The default path is `.copier-answers.yml`, but templates can change it with `_answers_file`.\n\n## Update Or Recopy A Generated Project\n\nBest-case update requirements from the official docs:\n\n1. The destination contains a valid `.copier-answers.yml` or equivalent answers file.\n2. The template is versioned with Git tags.\n3. The generated project is versioned with Git.\n\nRecommended update flow:\n\n```bash\ncd my-project\ngit status\ncopier update\n```\n\nUseful update variants:\n\n```bash\n# reuse previous answers\ncopier update --defaults\n\n# change one answer and keep the rest\ncopier update --defaults --data package_manager=uv\n\n# re-answer questions without moving to a newer template ref\ncopier update --vcs-ref=:current:\n\n# check whether a newer template version exists\ncopier check-update\n```\n\nPython API:\n\n```python\nfrom copier import run_recopy, run_update\n\n# Smart update: keep project evolution when possible\nrun_update(\"my-project\", defaults=True)\n\n# Recopy: regenerate from the template and keep answers,\n# but ignore previous project history\nrun_recopy(\"my-project\", defaults=True)\n```\n\nUse `run_recopy()` only when you intentionally want a reset-style regeneration. The docs explicitly say it is not the recommended normal update path.\n\n## Configuration And Trust\n\nUser settings live at `<CONFIG_ROOT>/settings.yml`:\n\n- Linux: `~/.config/copier/settings.yml` in most setups\n- macOS: `~/Library/Application Support/copier/settings.yml`\n- Windows: `%USERPROFILE%\\\\AppData\\\\Local\\\\copier\\\\settings.yml`\n\nYou can override the location with `COPIER_SETTINGS_PATH`.\n\nExample `settings.yml`:\n\n```yaml\ndefaults:\n  user_name: Jane Doe\n  user_email: jane@example.com\n  github_user: janedoe\n\ntrust:\n  - https://github.com/your-org/your-template.git\n  - https://github.com/your-org/\n  - ~/templates/\n```\n\nImportant behavior:\n\n- `defaults` replace question defaults with the same name.\n- `trust` entries ending in `/` are prefix matches; entries without `/` are exact matches.\n- Templates that use Jinja extensions, migrations, or tasks are considered unsafe and are blocked unless you explicitly trust them.\n- `--skip-tasks` only skips tasks, not migration tasks, and it does not imply `--trust`.\n\nIf you need to allow unsafe features from Python:\n\n```python\nfrom copier import run_copy\n\nrun_copy(\n    \"gh:your-org/your-template.git\",\n    \"my-project\",\n    unsafe=True,\n)\n```\n\nOnly do this for repositories you have audited.\n\n## Common Pitfalls\n\n- Never edit `.copier-answers.yml` manually. The official docs call this unsupported and warn that it breaks the smart update algorithm.\n- Do not assume `copier update` works well without Git tags on the template and Git history in the generated project.\n- Review conflicts before committing. `--conflict inline` writes merge markers into files; `--conflict rej` writes `.rej` files.\n- If your template generates one-time secrets or machine-local files, use `_skip_if_exists` so later updates do not overwrite them.\n- `copier.yml` settings use underscore-prefixed names such as `_answers_file`, `_subdirectory`, `_templates_suffix`, and `_secret_questions`.\n- Directories must not end with the template suffix. Files that should render normally use the suffix, which defaults to `.jinja`.\n- If you apply multiple templates to one project, give each template its own answers file.\n- `subdirectory` is for separating metadata from template source, not for hosting many unrelated templates in one Git repository. The docs recommend one template per repository.\n\n## Version-Sensitive Notes For 9.13.1\n\n- `9.13.1` fixes Git version parsing for vendor-suffixed patch versions, which matters on some packaged Git builds.\n- `9.13.0` adds the `copier check-update` CLI subcommand.\n- `9.12.0` introduced a smaller public settings API and explicit public `run_copy`, `run_recopy`, and `run_update` signatures. Prefer those public top-level functions over internal modules.\n- `9.11.0` dropped Python 3.9 support. If your environment is still on 3.9, current Copier is not a valid target.\n- `9.8.0` added the `:current:` VCS ref sentinel used by `copier update --vcs-ref=:current:`.\n- `9.6.0` changed the standard Windows settings directory to `%USERPROFILE%\\\\AppData\\\\Local\\\\copier`; the older nested path is deprecated.\n- `9.5.0` introduced user `defaults` and `trust` settings. Older pre-9.5 examples will not document them correctly.\n- Templates written for Copier 5 or older may still use `.tmpl`. Current Copier defaults to `.jinja`, so older templates should set `_templates_suffix: .tmpl` explicitly if they still depend on that behavior.\n\n## Official Sources\n\n- Stable docs: `https://copier.readthedocs.io/en/stable/`\n- Generating projects: `https://copier.readthedocs.io/en/stable/generating/`\n- Updating projects: `https://copier.readthedocs.io/en/stable/updating/`\n- Template configuration: `https://copier.readthedocs.io/en/stable/configuring/`\n- User settings: `https://copier.readthedocs.io/en/stable/settings/`\n- API reference: `https://copier.readthedocs.io/en/stable/reference/api/`\n- Changelog: `https://copier.readthedocs.io/en/stable/changelog/`\n- PyPI package: `https://pypi.org/project/copier/`\n"
  },
  {
    "path": "content/crewai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"CrewAI Python package guide for building agent crews, tasks, and flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.10.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"crewai,agents,llm,workflow,automation,python\"\n---\n\n# CrewAI Python Package Guide\n\n## What It Is\n\n`crewai` is the core Python package for building multi-agent workflows with:\n\n- `Agent`, `Task`, and `Crew` for agent orchestration\n- `Flow` for event-driven stateful workflows\n- `LLM` for explicit model/provider configuration\n\nUse it when you need Python-native orchestration around LLM-backed agents rather than a hosted SaaS API.\n\n## Installation\n\nInstall the core package:\n\n```bash\npip install crewai==1.10.1\n```\n\nInstall optional bundled tools support if you need imports from `crewai_tools`:\n\n```bash\npip install \"crewai[tools]==1.10.1\"\n```\n\nIf you want the CLI as a tool-managed binary, the official install page also shows:\n\n```bash\nuv tool install crewai\n```\n\n## LLM Setup and Authentication\n\nCrewAI routes model calls through LiteLLM. In practice, that means you should set provider credentials in the environment and preferably set the model explicitly instead of relying on defaults.\n\nOpenAI example:\n\n```bash\nexport OPENAI_API_KEY=\"your-api-key\"\nexport MODEL=\"openai/gpt-4o-mini\"\n```\n\nExplicit Python setup:\n\n```python\nimport os\nfrom crewai import LLM\n\nllm = LLM(\n    model=os.environ.get(\"MODEL\", \"openai/gpt-4o-mini\"),\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n```\n\nNotes:\n\n- The docs show provider/model strings such as `openai/gpt-4o-mini`.\n- Different providers need their own environment variables or credentials.\n- If you use hierarchical crews, configure `manager_llm` explicitly.\n\n## Fastest Way to Start a Project\n\nThe official quickstart uses the CLI to scaffold a crew project:\n\n```bash\ncrewai create crew latest_ai_development\ncd latest_ai_development\ncrewai install\n```\n\nThat scaffold gives you:\n\n- YAML config files such as `config/agents.yaml` and `config/tasks.yaml`\n- a `@CrewBase` class with `@agent`, `@task`, and `@crew` decorators\n- a `crew().kickoff(inputs=...)` entry point\n\nUse the scaffold when you want a structured app layout. Use the direct Python API when you want to embed CrewAI into an existing codebase.\n\n## Core Usage: Agent + Task + Crew\n\nMinimal direct API example:\n\n```python\nimport os\nfrom crewai import Agent, Crew, LLM, Process, Task\n\nllm = LLM(\n    model=os.environ.get(\"MODEL\", \"openai/gpt-4o-mini\"),\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n\nresearcher = Agent(\n    role=\"Research Analyst\",\n    goal=\"Find the most relevant facts about {topic}\",\n    backstory=\"You turn raw information into concise briefings.\",\n    llm=llm,\n    verbose=True,\n)\n\nresearch_task = Task(\n    description=\"Research {topic} and collect the most important facts.\",\n    expected_output=\"A short bullet list with the key findings.\",\n    agent=researcher,\n)\n\ncrew = Crew(\n    agents=[researcher],\n    tasks=[research_task],\n    process=Process.sequential,\n    verbose=True,\n)\n\nresult = crew.kickoff(inputs={\"topic\": \"CrewAI flows\"})\nprint(result)\n```\n\nImportant defaults:\n\n- `Process.sequential` is the safest starting point.\n- Pass `inputs={...}` to fill `{variables}` referenced by agents/tasks/YAML config.\n- Set `llm` explicitly on agents to avoid model-default ambiguity.\n\n## Multi-Task Context Passing\n\nTask context is task-to-task, not free-form text. Pass earlier `Task` objects in `context=[...]` so downstream tasks can use upstream results.\n\n```python\nfrom crewai import Agent, Task\n\nwriter = Agent(\n    role=\"Technical Writer\",\n    goal=\"Turn research into a concise memo.\",\n    backstory=\"You write clear summaries for engineering teams.\",\n    llm=llm,\n)\n\nresearch_task = Task(\n    description=\"Research the latest Python agent frameworks.\",\n    expected_output=\"A fact list with citations or source names.\",\n    agent=researcher,\n)\n\nwriting_task = Task(\n    description=\"Turn the research into a concise recommendation memo.\",\n    expected_output=\"A short memo with a final recommendation.\",\n    agent=writer,\n    context=[research_task],\n)\n```\n\n## Hierarchical Crews\n\nUse hierarchical orchestration when you want a manager model to delegate work across agents. Configure the manager model directly:\n\n```python\nimport os\nfrom crewai import Crew, LLM, Process\n\nmanager_llm = LLM(model=\"openai/gpt-4o-mini\", api_key=os.environ[\"OPENAI_API_KEY\"])\n\ncrew = Crew(\n    agents=[researcher, writer],\n    tasks=[research_task, writing_task],\n    process=Process.hierarchical,\n    manager_llm=manager_llm,\n)\n```\n\nIf `process=Process.hierarchical` is set without a valid manager model, expect runtime issues.\n\n## Tools\n\nCrewAI docs and examples often import tools from `crewai_tools`, not from `crewai` itself. Install the optional tools extra when needed, then attach tool instances to agents:\n\n```python\nfrom crewai import Agent\nfrom crewai_tools import SerperDevTool\n\nsearch_tool = SerperDevTool()\n\nresearcher = Agent(\n    role=\"Research Analyst\",\n    goal=\"Find relevant information on demand.\",\n    backstory=\"You search first, then summarize.\",\n    llm=llm,\n    tools=[search_tool],\n)\n```\n\nMany tools also require provider-specific API keys. Check the matching tool page before assuming a tool is ready after package installation alone.\n\n## Flows\n\nUse `Flow` when your workflow is stateful and event-driven rather than a single crew execution. The official docs model flows with decorators such as `@start()` and `@listen(...)`.\n\n```python\nfrom pydantic import BaseModel, Field\nfrom crewai.flow.flow import Flow, listen, start\n\nclass ReportState(BaseModel):\n    topic: str = \"CrewAI\"\n    notes: list[str] = Field(default_factory=list)\n\nclass ResearchFlow(Flow[ReportState]):\n    @start()\n    def fetch(self):\n        self.state.notes.append(f\"Researching {self.state.topic}\")\n\n    @listen(fetch)\n    def summarize(self):\n        return \"\\n\".join(self.state.notes)\n\nresult = ResearchFlow().kickoff()\nprint(result)\n```\n\nUse flows when you need branching, routing, or persisted workflow state. Use a plain crew when a single agent pipeline is enough.\n\n## Generated Project Pattern\n\nIf you use the official scaffold, expect code shaped like this:\n\n```python\nfrom crewai import Agent, Crew, Process, Task\nfrom crewai.project import CrewBase, agent, crew, task\n\n@CrewBase\nclass LatestAiDevelopment:\n    agents_config = \"config/agents.yaml\"\n    tasks_config = \"config/tasks.yaml\"\n\n    @agent\n    def researcher(self) -> Agent:\n        return Agent(config=self.agents_config[\"researcher\"])\n\n    @task\n    def research_task(self) -> Task:\n        return Task(config=self.tasks_config[\"research_task\"])\n\n    @crew\n    def crew(self) -> Crew:\n        return Crew(\n            agents=self.agents,\n            tasks=self.tasks,\n            process=Process.sequential,\n            verbose=True,\n        )\n```\n\nThis is the repo-friendly pattern to use if you want YAML-driven configuration and generated structure instead of hand-built Python objects.\n\n## Common Pitfalls\n\n- Do not assume the model default is stable. The docs currently reference both `MODEL=...` and older OpenAI-default language. Set `llm` explicitly.\n- Do not forget `expected_output` on tasks. Official task examples include it consistently.\n- Do not pass raw strings into `context`. Pass upstream `Task` objects.\n- Do not import bundled tools from `crewai` if the docs example imports from `crewai_tools`.\n- Do not start with hierarchical crews unless you actually need a manager model.\n- Do not mix scaffolded YAML names and Python placeholders carelessly. Inputs passed to `kickoff(inputs=...)` must match the placeholders used by your config.\n\n## Version-Sensitive Notes for 1.10.1\n\n- PyPI shows `1.10.1` as the current release for `crewai`, released on `2025-10-27`.\n- PyPI also marks `1.10.0` as yanked, with the note `Issue with wheel file not installing`.\n- The docs site header is on `v1.10.1`, so the docs root and PyPI currently agree on the package version.\n- The docs changelog page currently documents releases through `1.9.0`, so use PyPI release metadata for exact `1.10.1` release confirmation.\n- The installation page still contains a legacy note mentioning `CrewAI 0.175.0` in its OpenAI SDK section. Treat that as stale page content, not as the package version.\n\n## Official Source URLs\n\n- Docs root: https://docs.crewai.com/\n- Installation: https://docs.crewai.com/en/installation\n- Quickstart: https://docs.crewai.com/quickstart\n- Agents: https://docs.crewai.com/en/concepts/agents\n- Tasks: https://docs.crewai.com/en/concepts/tasks\n- Crews: https://docs.crewai.com/en/concepts/crews\n- Flows: https://docs.crewai.com/en/concepts/flows\n- LLMs: https://docs.crewai.com/en/learn/llms\n- Changelog: https://docs.crewai.com/en/changelog\n- PyPI project: https://pypi.org/project/crewai/\n- PyPI JSON metadata: https://pypi.org/pypi/crewai/json\n"
  },
  {
    "path": "content/croniter/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"croniter Python package guide for parsing cron expressions and computing matching run times\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"croniter,cron,python,scheduling,datetime,timezones\"\n---\n\n# croniter Python Package Guide\n\n## Golden Rule\n\nUse `croniter` to calculate schedule times inside your own code, not to run jobs by itself. In `6.0.0`, the most important practical defaults are: pass a `datetime` base time, prefer timezone-aware datetimes, and set `ret_type=datetime` unless you explicitly want UNIX timestamp floats back.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"croniter==6.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"croniter==6.0.0\"\npoetry add \"croniter==6.0.0\"\n```\n\n`croniter` has no package-level authentication, no service account setup, and no required environment variables. It only parses cron expressions and computes matching times.\n\n## Core Usage\n\nCreate an iterator from a cron expression plus a base time, then call `get_next()` or `get_prev()`:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 12, 9, 0, tzinfo=ZoneInfo(\"UTC\"))\n\nschedule = croniter(\n    \"*/15 * * * *\",\n    base,\n    ret_type=datetime,\n)\n\ncurrent = schedule.get_current(datetime)\nnext_run = schedule.get_next()\nafter_that = schedule.get_next()\nprevious_run = schedule.get_prev()\n\nprint(current)      # 2026-03-12 09:00:00+00:00\nprint(next_run)     # 2026-03-12 09:15:00+00:00\nprint(after_that)   # 2026-03-12 09:30:00+00:00\nprint(previous_run) # 2026-03-12 09:15:00+00:00\n```\n\nImportant default: if you omit `ret_type=datetime`, `croniter` returns `float` UNIX timestamps.\n\n## Iterate Future Or Previous Matches\n\nUse `all_next()` or `all_prev()` when you want a generator instead of calling `get_next()` repeatedly:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 12, 0, 0, tzinfo=ZoneInfo(\"UTC\"))\nschedule = croniter(\"@daily\", base, ret_type=datetime)\n\nfor index, run_at in enumerate(schedule.all_next(datetime), start=1):\n    print(index, run_at)\n    if index == 3:\n        break\n```\n\n`@midnight`, `@hourly`, `@daily`, `@weekly`, `@monthly`, `@yearly`, and `@annually` are accepted aliases.\n\n## Validate And Match Expressions\n\nUse the class methods when you need to validate user input or check whether a time window contains a match:\n\n```python\nfrom datetime import datetime, timedelta\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\ncandidate = datetime(2026, 3, 13, 9, 0, tzinfo=ZoneInfo(\"UTC\"))\n\nis_valid = croniter.is_valid(\"0 9 * * 1-5\")\nmatches_exact_time = croniter.match(\"0 9 * * 1-5\", candidate)\nmatches_within_hour = croniter.match_range(\n    \"0 9 * * 1-5\",\n    candidate,\n    candidate + timedelta(hours=1),\n)\n\nprint(is_valid)\nprint(matches_exact_time)\nprint(matches_within_hour)\n```\n\nUse this pattern when you need to reject invalid cron strings before saving them, or when you want to see whether a given interval contains a run.\n\n## Enumerate A Window With `croniter_range`\n\nUse `croniter_range()` when you want every matching time between two endpoints:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter_range\n\nstart = datetime(2026, 3, 16, 0, 0, tzinfo=ZoneInfo(\"UTC\"))\nstop = datetime(2026, 3, 16, 23, 59, tzinfo=ZoneInfo(\"UTC\"))\n\nfor run_at in croniter_range(\n    start,\n    stop,\n    \"0 9,13,17 * * 1-5\",\n    ret_type=datetime,\n):\n    print(run_at)\n```\n\nBy default, matching `start` and `stop` values are included. Pass `exclude_ends=True` to drop matches that land exactly on the endpoints.\n\n## Expression Features\n\n`croniter 6.0.0` accepts exactly `5`, `6`, or `7` fields:\n\n- `5` fields: standard minute, hour, day of month, month, day of week\n- `6` fields: adds seconds\n- `7` fields: adds seconds and year\n\nBy default, seconds are the last time field. For a six-field expression, this means `minute hour day month day_of_week second`:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 12, 12, 0, tzinfo=ZoneInfo(\"UTC\"))\n\n# 12:00:30 every day\nschedule = croniter(\"0 12 * * * 30\", base, ret_type=datetime)\nprint(schedule.get_next())\n```\n\nIf your expression puts seconds first, pass `second_at_beginning=True`:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 12, 12, 0, tzinfo=ZoneInfo(\"UTC\"))\n\n# 12:00:30 every day, Quartz-style seconds-first order\nschedule = croniter(\n    \"30 0 12 * * *\",\n    base,\n    ret_type=datetime,\n    second_at_beginning=True,\n)\nprint(schedule.get_next())\n```\n\nOther useful parser features:\n\n- month and weekday names such as `jan` and `mon-fri`\n- `l` for the last day of the month in the day-of-month field\n- `2#3` style nth weekday syntax in the day-of-week field\n- `?` in day-of-month or day-of-week, treated like `*`\n\n## Day-Of-Month And Day-Of-Week Logic\n\nWhen both day-of-month and day-of-week are restricted, `croniter` uses OR semantics by default. Set `day_or=False` when you need AND semantics instead:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 1, 0, 0, tzinfo=ZoneInfo(\"UTC\"))\n\n# Fires when either condition matches: first day of the month OR Monday\neither_rule = croniter(\n    \"0 9 1 * mon\",\n    base,\n    ret_type=datetime,\n)\n\n# Fires only when both conditions match: first day of the month AND Monday\nboth_rules = croniter(\n    \"0 9 1 * mon\",\n    base,\n    ret_type=datetime,\n    day_or=False,\n)\n```\n\nThis is one of the easiest ways to get an unexpected schedule if you assume Quartz-style or scheduler-specific semantics.\n\n## Time Zones And DST\n\nIf the base time is a timezone-aware `datetime`, `croniter` keeps the timezone information on returned datetimes. Use aware datetimes for application schedules that must follow a real timezone instead of a floating local clock:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nbase = datetime(2026, 3, 29, 0, 30, tzinfo=ZoneInfo(\"Europe/Berlin\"))\nschedule = croniter(\"0 * * * *\", base, ret_type=datetime)\n\nfor _ in range(3):\n    print(schedule.get_next())\n```\n\nIf you care about DST transitions, keep everything in UTC unless the business rule truly depends on local wall time.\n\n## Errors And Practical Pitfalls\n\nCatch the package exceptions when cron strings come from users or configuration files:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import CroniterBadCronError, CroniterBadDateError, croniter\n\nbase = datetime(2026, 3, 12, 0, 0, tzinfo=ZoneInfo(\"UTC\"))\n\ntry:\n    schedule = croniter(\n        \"0 4 1 1 fri\",\n        base,\n        ret_type=datetime,\n        day_or=False,\n        max_years_between_matches=10,\n    )\n    print(schedule.get_next())\nexcept CroniterBadCronError as exc:\n    print(f\"Invalid cron expression: {exc}\")\nexcept CroniterBadDateError as exc:\n    print(f\"No matching date found in search window: {exc}\")\n```\n\nKeep these behavior details in mind:\n\n- `get_next()` and `get_prev()` return floats unless you set `ret_type=datetime`\n- sparse expressions search up to `50` years by default; tune `max_years_between_matches` if you want a tighter failure window\n- `croniter_range()` includes matching endpoints unless you pass `exclude_ends=True`\n- hashed definitions such as `h` require `hash_id=...`\n- `second_at_beginning=True` changes how `6`- and `7`-field expressions are interpreted\n\n## Minimal App Pattern\n\nFor most applications, a small helper keeps scheduling code consistent:\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom croniter import croniter\n\nUTC = ZoneInfo(\"UTC\")\n\ndef next_run(cron_expression: str, now: datetime | None = None) -> datetime:\n    base = now or datetime.now(UTC)\n    return croniter(cron_expression, base, ret_type=datetime).get_next()\n\nrun_at = next_run(\"*/10 * * * *\")\nprint(run_at)\n```\n\nThis keeps your app on aware datetimes and avoids the most common `float` return-type mistake.\n"
  },
  {
    "path": "content/cryptography/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cryptography package guide for Python with installation, Fernet, AEAD, key serialization, and X.509 workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"46.0.5\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"cryptography,python,encryption,fernet,aead,x509,openssl\"\n---\n\n# cryptography Python Package Guide\n\n`cryptography` provides two layers:\n\n- the recipes layer for common tasks such as Fernet\n- the hazardous materials layer for lower-level primitives such as AES-GCM, key serialization, and X.509\n\nPrefer the recipes layer unless you specifically need lower-level control.\n\n## Installation\n\nUse a pinned install when you need behavior that matches this doc:\n\n```bash\npython -m pip install \"cryptography==46.0.5\"\n```\n\nFor a normal install:\n\n```bash\npython -m pip install cryptography\n```\n\nImportant install notes from upstream:\n\n- `cryptography` 46.0.5 requires Python `!=3.9.0`, `!=3.9.1`, `>=3.8`.\n- If installation fails, upgrade `pip` first. The official docs call that the most common cause of install problems.\n- On supported platforms, PyPI wheels are the normal path and already include the needed OpenSSL build.\n- Building from source requires a C toolchain, OpenSSL and `libffi` headers, and Rust. The current upstream minimum Rust version shown in the latest install docs is `1.83.0`.\n- On macOS source builds, do not rely on the base system OpenSSL/LibreSSL from Apple; use a supported OpenSSL installation instead.\n\n## Setup and Secret Management\n\n`cryptography` is a local library, not a network client. There is no service authentication step. Your \"configuration\" is usually:\n\n- key material\n- certificate material\n- passwords for encrypted private keys or PKCS#12 blobs\n- platform build settings only when you cannot use wheels\n\nPractical rules:\n\n- Store long-lived keys outside source control.\n- Use environment variables or a secret manager to inject key material at runtime.\n- If you derive keys from passwords, persist the salt alongside the encrypted data.\n- Do not generate a new key on every process start unless token invalidation is intentional.\n\nExample one-time Fernet key provisioning:\n\n```python\nimport os\nfrom cryptography.fernet import Fernet\n\nkey = os.getenv(\"FERNET_KEY\")\nif key is None:\n    key = Fernet.generate_key().decode(\"ascii\")\n    print(f\"Provision this once and store it securely: {key}\")\n    raise SystemExit(1)\n\nfernet = Fernet(key.encode(\"ascii\"))\n```\n\n## Core Usage\n\n### Fernet for simple authenticated encryption\n\nUse Fernet when you want a straightforward opaque token API and your payload fits in memory.\n\n```python\nfrom cryptography.fernet import Fernet, InvalidToken\n\nkey = Fernet.generate_key()\nf = Fernet(key)\n\ntoken = f.encrypt(b\"api-key-or-session-data\")\n\ntry:\n    plaintext = f.decrypt(token, ttl=300)\nexcept InvalidToken:\n    plaintext = None\n```\n\nWhat matters:\n\n- Fernet keys are URL-safe base64-encoded 32-byte keys.\n- `decrypt(..., ttl=...)` rejects expired tokens.\n- Fernet tokens include their creation timestamp in plaintext.\n- Fernet is meant for messages that fit in memory; it is not a streaming file-encryption API.\n\n### Rotate Fernet keys with `MultiFernet`\n\n```python\nfrom cryptography.fernet import Fernet, MultiFernet\n\nnew_key = Fernet(Fernet.generate_key())\nold_key = Fernet(Fernet.generate_key())\nring = MultiFernet([new_key, old_key])\n\ntoken = ring.encrypt(b\"rotatable-secret\")\nrotated_token = ring.rotate(token)\nplaintext = ring.decrypt(rotated_token)\n```\n\nPut the newest key first. Keep old keys available until all tokens that depend on them have been rotated or expired.\n\n### Derive a Fernet key from a password\n\nUse a KDF first. Do not feed a raw password directly into Fernet.\n\n```python\nimport base64\nimport os\n\nfrom cryptography.fernet import Fernet\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC\n\npassword = os.environ[\"APP_PASSWORD\"].encode(\"utf-8\")\nsalt = os.environ[\"APP_SALT\"].encode(\"utf-8\")\n\nkdf = PBKDF2HMAC(\n    algorithm=hashes.SHA256(),\n    length=32,\n    salt=base64.urlsafe_b64decode(salt),\n    iterations=1_200_000,\n)\nkey = base64.urlsafe_b64encode(kdf.derive(password))\nf = Fernet(key)\n```\n\nNotes:\n\n- Persist the salt so you can derive the same key later.\n- The upstream Fernet docs use `1_200_000` PBKDF2 iterations as a current good default and explicitly say to tune upward as much as your system can tolerate.\n\n### AES-GCM for protocol-level encryption\n\nUse AEAD primitives when you need to control the nonce, associated data, or message framing yourself.\n\n```python\nimport os\n\nfrom cryptography.hazmat.primitives.ciphers.aead import AESGCM\n\nkey = AESGCM.generate_key(bit_length=256)\naesgcm = AESGCM(key)\n\nnonce = os.urandom(12)\naad = b\"request-id:123\"\nplaintext = b\"top secret\"\n\nciphertext = aesgcm.encrypt(nonce, plaintext, aad)\nroundtrip = aesgcm.decrypt(nonce, ciphertext, aad)\n```\n\nRules that matter:\n\n- Never reuse a nonce with the same key.\n- Use a 12-byte nonce unless you have a specific reason not to.\n- `associated_data` must match exactly on decrypt.\n- In current upstream docs, `encrypt_into` and `decrypt_into` are marked as added in `47.0.0`; they are not part of `46.0.5`.\n\n## Key Serialization and Loading\n\n### Write an encrypted PEM private key\n\n```python\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric import rsa\n\nkey = rsa.generate_private_key(public_exponent=65537, key_size=2048)\n\npem_bytes = key.private_bytes(\n    encoding=serialization.Encoding.PEM,\n    format=serialization.PrivateFormat.PKCS8,\n    encryption_algorithm=serialization.BestAvailableEncryption(b\"changeit\"),\n)\n```\n\n### Load a PEM private key back\n\n```python\nfrom cryptography.hazmat.primitives.serialization import load_pem_private_key\n\nloaded_key = load_pem_private_key(pem_bytes, password=b\"changeit\")\n```\n\nSerialization pitfalls:\n\n- A PEM block beginning with `-----BEGIN CERTIFICATE-----` is an X.509 certificate, not a private key. Load it with X.509 certificate APIs, not key-loading APIs.\n- SSH private keys use a different format and should be loaded with `load_ssh_private_key()`.\n- When loading a private key, verify that the returned object is the key type you expect before using it.\n- Leave `unsafe_skip_rsa_key_validation` at its default unless you fully control the input and understand the tradeoff.\n\n### PKCS#12\n\n`cryptography` can load and serialize PKCS#12 bundles:\n\n- `pkcs12.load_key_and_certificates(...)` loads a blob into key and certificate objects.\n- `pkcs12.serialize_key_and_certificates(...)` writes a PKCS#12 blob.\n\nUpstream warns that PKCS#12 encryption is typically weak and should not be treated as a strong security boundary. Use it for compatibility, then wrap it in a stronger storage or transport boundary if you need real protection.\n\n## X.509 and CSR Workflow\n\nUse the X.509 APIs for certificate requests, local development certificates, or certificate parsing.\n\n```python\nfrom cryptography import x509\nfrom cryptography.hazmat.primitives import hashes, serialization\nfrom cryptography.hazmat.primitives.asymmetric import rsa\nfrom cryptography.x509.oid import NameOID\n\nkey = rsa.generate_private_key(public_exponent=65537, key_size=2048)\n\ncsr = (\n    x509.CertificateSigningRequestBuilder()\n    .subject_name(\n        x509.Name(\n            [\n                x509.NameAttribute(NameOID.COUNTRY_NAME, \"US\"),\n                x509.NameAttribute(NameOID.ORGANIZATION_NAME, \"Example Inc\"),\n                x509.NameAttribute(NameOID.COMMON_NAME, \"example.com\"),\n            ]\n        )\n    )\n    .add_extension(\n        x509.SubjectAlternativeName(\n            [x509.DNSName(\"example.com\"), x509.DNSName(\"www.example.com\")]\n        ),\n        critical=False,\n    )\n    .sign(key, hashes.SHA256())\n)\n\ncsr_pem = csr.public_bytes(serialization.Encoding.PEM)\n```\n\nFor existing PEM certificates, load them with `x509.load_pem_x509_certificate(...)` and then inspect fields or extract the public key.\n\n## Common Pitfalls\n\n- Do not copy old blog examples that still use outdated APIs or omit secure defaults. Follow current upstream examples.\n- Use the recipes layer when possible. The hazmat layer is intentionally lower-level and easier to misuse.\n- Do not reuse an AEAD nonce with the same key.\n- Do not treat Fernet as a streaming or very-large-file encryption tool.\n- Do not forget to persist the salt when deriving a key from a password.\n- Do not serialize private keys without encryption unless you have a deliberate reason and a stronger outer protection mechanism.\n- Do not assume the docs at `/en/latest/` match `46.0.5` exactly; the latest docs currently render `47.0.0.dev1`.\n\n## Version-Sensitive Notes for 46.0.5\n\n- `46.0.5` includes a security fix for `CVE-2026-26007`, involving malicious public keys on uncommon binary elliptic curves.\n- The same release deprecates `SECT*` binary elliptic curves and says they will be removed in the next release.\n- `46.0.0` removed Python 3.7 support and deprecated OpenSSL `< 3.0`.\n- The PyPI project page shows `46.0.5` as the latest released package on `2026-02-10`, but the docs URL points at `/en/latest/`, which currently tracks unreleased `47.0.0.dev1` docs. Check versioned pages before using newly documented APIs.\n\n## Official Sources Used\n\n- Docs root: `https://cryptography.io/en/latest/`\n- Installation: `https://cryptography.io/en/latest/installation/`\n- Fernet: `https://cryptography.io/en/latest/fernet/`\n- AEAD primitives: `https://cryptography.io/en/latest/hazmat/primitives/aead/`\n- Key serialization: `https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/`\n- X.509 tutorial: `https://cryptography.io/en/latest/x509/tutorial/`\n- Changelog: `https://cryptography.io/en/latest/changelog/`\n- PyPI project page: `https://pypi.org/project/cryptography/`\n"
  },
  {
    "path": "content/cssselect/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cssselect package guide for translating CSS selectors into XPath 1.0 expressions in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cssselect,python,css,xpath,selectors,html,xml\"\n---\n\n# cssselect Python Package Guide\n\n## Golden Rule\n\n`cssselect` does not query documents by itself. It parses CSS selector strings and translates them to XPath 1.0 expressions that you execute in another library such as `lxml` or any XML/HTML engine that already supports XPath.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"cssselect==1.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"cssselect==1.4.0\"\npoetry add \"cssselect==1.4.0\"\n```\n\nIf you want to run the generated XPath against parsed HTML or XML, install an XPath-capable library too:\n\n```bash\npython -m pip install \"lxml>=5\" \"cssselect==1.4.0\"\n```\n\n## Initialization\n\n`cssselect` is a local Python library. It does not require authentication, API keys, environment variables, or client configuration.\n\nImport the translator and the exception types you plan to handle:\n\n```python\nfrom cssselect import (\n    ExpressionError,\n    GenericTranslator,\n    HTMLTranslator,\n    SelectorError,\n    SelectorSyntaxError,\n    parse,\n)\n```\n\nUse `GenericTranslator` for generic XML-style documents and `HTMLTranslator` when you want HTML-specific selector behavior.\n\n## Common Workflows\n\n### Translate a CSS selector to XPath\n\nUse `css_to_xpath()` when your input is a selector string.\n\n```python\nfrom cssselect import GenericTranslator\n\ntranslator = GenericTranslator()\nxpath = translator.css_to_xpath(\"div.content > a[href]\")\n\nprint(xpath)\n```\n\n`css_to_xpath()` returns an XPath string. If the CSS contains a selector group such as `\"div.content, aside.notice\"`, the generated XPath uses a union expression.\n\n### Execute the XPath with `lxml`\n\n`cssselect` only performs the translation step. Use an XPath engine to get actual elements.\n\n```python\nfrom lxml import html\nfrom cssselect import GenericTranslator\n\nmarkup = \"\"\"\n<html>\n  <body>\n    <div class=\"content\">\n      <a href=\"/docs\">Docs</a>\n      <a>No href</a>\n    </div>\n  </body>\n</html>\n\"\"\"\n\ndocument = html.fromstring(markup)\nxpath = GenericTranslator().css_to_xpath(\"div.content > a[href]\")\nlinks = document.xpath(xpath)\n\nfor link in links:\n    print(link.get(\"href\"))\n```\n\nIf you already use `lxml`'s CSS helper APIs such as `document.cssselect(...)`, keep `cssselect` installed because `lxml` uses it for CSS-to-XPath translation.\n\n### Use `HTMLTranslator` for HTML-specific selectors\n\nFor HTML documents, prefer `HTMLTranslator()` when you rely on HTML semantics or HTML-only pseudo-classes.\n\n```python\nfrom cssselect import HTMLTranslator\n\ntranslator = HTMLTranslator()\nxpath = translator.css_to_xpath(\"input:checked\")\n\nprint(xpath)\n```\n\nFor XML documents that are not HTML, use `GenericTranslator()` instead.\n\n### Parse selectors before translating them\n\nUse `parse()` when you need structured selector objects or when you want to translate one parsed selector at a time.\n\n```python\nfrom cssselect import GenericTranslator, parse\n\nselectors = parse(\"article.featured > h2.title, article.featured > p.summary\")\ntranslator = GenericTranslator()\n\nfor selector in selectors:\n    xpath = translator.selector_to_xpath(selector)\n    print(xpath)\n```\n\nThis is useful when your application accepts user-provided selector lists and you want to inspect or translate each selector individually.\n\n### Catch invalid or unsupported selectors\n\nHandle selector problems explicitly so bad input does not fail deep inside your document-processing code.\n\n```python\nfrom cssselect import ExpressionError, GenericTranslator, SelectorSyntaxError\n\ntranslator = GenericTranslator()\n\ntry:\n    xpath = translator.css_to_xpath(\"div >> a\")\nexcept SelectorSyntaxError as exc:\n    raise ValueError(f\"Invalid CSS selector syntax: {exc}\") from exc\nexcept ExpressionError as exc:\n    raise ValueError(f\"Unsupported selector for XPath translation: {exc}\") from exc\n```\n\nUse `SelectorError` if you want one catch-all base exception for both syntax and translation failures.\n\n### Evaluate selectors against namespaced XML\n\n`cssselect` keeps namespace prefixes in the generated XPath. Pass the actual namespace mapping to your XPath engine when you evaluate the result.\n\n```python\nfrom lxml import etree\nfrom cssselect import GenericTranslator\n\nxml = b\"\"\"\n<root xmlns:svg=\"http://www.w3.org/2000/svg\">\n  <svg:svg>\n    <svg:a href=\"/diagram\" />\n  </svg:svg>\n</root>\n\"\"\"\n\ndocument = etree.fromstring(xml)\nxpath = GenericTranslator().css_to_xpath(\"svg|a\")\nmatches = document.xpath(xpath, namespaces={\"svg\": \"http://www.w3.org/2000/svg\"})\n\nprint(len(matches))\n```\n\n## Important Pitfalls\n\n- `cssselect` translates selectors to XPath 1.0. It is not a browser selector engine and it does not implement every modern CSS selector.\n- Use `HTMLTranslator` for HTML documents and `GenericTranslator` for generic XML. Translating HTML selectors with the generic translator can miss HTML-specific behavior.\n- The library returns XPath strings, not matched nodes. You still need an XPath-capable parser or DOM library to execute the query.\n- Invalid selector syntax raises `SelectorSyntaxError`. Selectors that parse but cannot be translated raise `ExpressionError`.\n- Namespace prefixes are resolved when the XPath runs, not when `cssselect` generates the XPath.\n\n## Version Notes For `1.4.0`\n\nThis guide targets `cssselect` version `1.4.0`.\n\nWhen you upgrade, keep the package version pinned until you confirm that your selector set still translates to the XPath you expect, especially if your application depends on specific pseudo-classes or XML namespace handling.\n"
  },
  {
    "path": "content/cypress/docs/cypress/javascript/DOC.md",
    "content": "---\nname: cypress\ndescription: \"Cypress browser testing for JavaScript applications, including installation, project configuration, environment variables, and common end-to-end workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"15.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"cypress,testing,e2e,browser,automation,javascript\"\n---\n\n# Cypress JavaScript Guide\n\n`cypress` is a browser test runner for end-to-end and component tests. This guide focuses on the common JavaScript end-to-end setup: installing Cypress, configuring a project, passing secrets safely, stubbing network traffic, and moving Node-side work into tasks.\n\n## Install\n\nInstall Cypress as a development dependency:\n\n```bash\nnpm install --save-dev cypress\n```\n\nOpen the interactive app for local development:\n\n```bash\nnpx cypress open\n```\n\nRun tests headlessly:\n\n```bash\nnpx cypress run\n```\n\nUseful variants:\n\n```bash\nnpx cypress open --e2e\nnpx cypress run --browser chrome\nnpx cypress run --spec \"cypress/e2e/login.cy.js\"\n```\n\nCypress downloads its test runner binary as part of installation/setup. Check Cypress's current install requirements before pinning Node.js, OS, or browser versions in CI.\n\nThere is no package-level authentication step. Put application credentials in Cypress environment variables instead of hard-coding them in specs.\n\n## Create The Base Configuration\n\nUse a root `cypress.config.js` file and wrap the config with `defineConfig()`.\n\n```javascript\nconst { defineConfig } = require(\"cypress\");\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nmodule.exports = defineConfig({\n  e2e: {\n    baseUrl: \"http://127.0.0.1:3000\",\n    specPattern: \"cypress/e2e/**/*.cy.{js,jsx,ts,tsx}\",\n    supportFile: \"cypress/support/e2e.js\",\n    setupNodeEvents(on, config) {\n      on(\"task\", {\n        readFileIfExists(relativePath) {\n          const filePath = path.join(config.projectRoot, relativePath);\n\n          if (!fs.existsSync(filePath)) {\n            return null;\n          }\n\n          return fs.readFileSync(filePath, \"utf8\");\n        },\n      });\n\n      return config;\n    },\n  },\n\n  env: {\n    apiUrl: \"http://127.0.0.1:4000\",\n  },\n\n  video: true,\n  screenshotOnRunFailure: true,\n});\n```\n\nWith `baseUrl` set, `cy.visit(\"/login\")` resolves against your app automatically.\n\n## Pass Secrets And Runtime Settings\n\nUse `cypress.env.json` for local-only secrets and keep it out of version control.\n\n```json\n{\n  \"E2E_EMAIL\": \"user@example.com\",\n  \"E2E_PASSWORD\": \"replace-me\",\n  \"apiUrl\": \"http://127.0.0.1:4000\"\n}\n```\n\n```gitignore\ncypress.env.json\n```\n\nYou can also pass values from the shell. `CYPRESS_*` variables can override Cypress config values and populate `Cypress.env()`.\n\n```bash\nCYPRESS_baseUrl=https://staging.example.com \\\nCYPRESS_E2E_EMAIL=user@example.com \\\nCYPRESS_E2E_PASSWORD=secret \\\nnpx cypress run\n```\n\nRead env values inside tests with `Cypress.env()`:\n\n```javascript\nconst email = Cypress.env(\"E2E_EMAIL\");\nconst password = Cypress.env(\"E2E_PASSWORD\");\nconst apiUrl = Cypress.env(\"apiUrl\");\n```\n\n## Write A Basic End-To-End Test\n\nPrefer stable selectors such as `data-cy` attributes and wait on meaningful conditions instead of fixed delays.\n\n```javascript\ndescribe(\"checkout\", () => {\n  it(\"creates an order\", () => {\n    cy.intercept(\"GET\", \"/api/cart\", {\n      statusCode: 200,\n      body: {\n        items: [{ id: 1, name: \"T-shirt\", quantity: 1 }],\n      },\n    }).as(\"getCart\");\n\n    cy.intercept(\"POST\", \"/api/orders\").as(\"createOrder\");\n\n    cy.visit(\"/checkout\");\n    cy.wait(\"@getCart\");\n\n    cy.get(\"[data-cy=email]\").type(\"buyer@example.com\");\n    cy.get(\"[data-cy=place-order]\").click();\n\n    cy.wait(\"@createOrder\")\n      .its(\"response.statusCode\")\n      .should(\"eq\", 201);\n\n    cy.contains(\"Order confirmed\").should(\"be.visible\");\n  });\n});\n```\n\nCommon command patterns:\n\n```javascript\ncy.visit(\"/dashboard\");\ncy.get(\"[data-cy=save]\").click();\ncy.contains(\"Saved\").should(\"be.visible\");\ncy.url().should(\"include\", \"/dashboard\");\ncy.request(\"GET\", \"/api/health\").its(\"status\").should(\"eq\", 200);\n```\n\n## Reuse Login With Custom Commands And `cy.session()`\n\nPut repeated UI actions in support commands:\n\n`cypress/support/commands.js`\n\n```javascript\nCypress.Commands.add(\"login\", () => {\n  cy.visit(\"/login\");\n  cy.get(\"[data-cy=email]\").type(Cypress.env(\"E2E_EMAIL\"));\n  cy.get(\"[data-cy=password]\").type(Cypress.env(\"E2E_PASSWORD\"), {\n    log: false,\n  });\n  cy.contains(\"button\", \"Sign in\").click();\n  cy.url().should(\"include\", \"/dashboard\");\n});\n```\n\n`cypress/support/e2e.js`\n\n```javascript\nimport \"./commands\";\n```\n\nCache the authenticated browser state with `cy.session()` so you do not repeat the full login flow for every test:\n\n```javascript\ndescribe(\"dashboard\", () => {\n  beforeEach(() => {\n    cy.session(\"standard-user\", () => {\n      cy.login();\n    });\n  });\n\n  it(\"shows account details\", () => {\n    cy.visit(\"/dashboard\");\n    cy.contains(\"Account\").should(\"be.visible\");\n  });\n});\n```\n\nIf your app redirects to a different origin for sign-in, use `cy.origin()` for the steps that run on that other origin.\n\n## Move Node-Side Work Into `cy.task()`\n\nBrowser-side Cypress commands cannot directly use Node APIs such as `fs`. Put that work in `setupNodeEvents()` and call it with `cy.task()`.\n\n```javascript\ncy.task(\"readFileIfExists\", \"tmp/otp.txt\").then((otp) => {\n  expect(otp).to.be.a(\"string\");\n  cy.get(\"[data-cy=otp]\").type(otp.trim());\n});\n```\n\nUse this pattern for local file access, database helpers, or one-off setup/teardown hooks that belong on the Node side.\n\n## Use API Calls For Setup When UI Setup Is Slow\n\n`cy.request()` is useful for seeding data, checking service health, or creating test fixtures before you visit the page under test.\n\n```javascript\ndescribe(\"profile\", () => {\n  beforeEach(() => {\n    cy.request(\"POST\", `${Cypress.env(\"apiUrl\")}/test/reset`);\n    cy.request(\"POST\", `${Cypress.env(\"apiUrl\")}/test/users`, {\n      email: Cypress.env(\"E2E_EMAIL\"),\n      plan: \"pro\",\n    });\n  });\n\n  it(\"shows the seeded user\", () => {\n    cy.visit(\"/profile\");\n    cy.contains(Cypress.env(\"E2E_EMAIL\")).should(\"be.visible\");\n  });\n});\n```\n\nUse UI steps for the behavior you actually want to verify, and use API setup for the state that only makes the test possible.\n\n## CI And Repeatable Runs\n\nRun Cypress headlessly in CI and set the app URL through environment variables:\n\n```bash\nexport CYPRESS_baseUrl=http://127.0.0.1:3000\nexport CYPRESS_E2E_EMAIL=ci-user@example.com\nexport CYPRESS_E2E_PASSWORD=ci-secret\n\nnpx cypress run --browser chrome\n```\n\nKeep the application server startup outside Cypress itself unless you deliberately wire a separate process manager around your test command.\n\n## Common Pitfalls\n\n- Do not assign Cypress command results to plain variables and expect synchronous behavior; chain commands or use `.then()`.\n- Avoid `cy.wait(5000)` for routine synchronization; prefer route aliases, URL assertions, or DOM assertions.\n- Use stable selectors such as `data-cy` instead of brittle CSS paths or presentation text.\n- Put secrets in `cypress.env.json` or `CYPRESS_*` environment variables, not directly in spec files.\n- Use `cy.task()` for Node-only work and `cy.origin()` when a test continues on a different origin.\n\n## Useful Links\n\n- Cypress docs table of contents: `https://docs.cypress.io/api/table-of-contents`\n- Install Cypress: `https://docs.cypress.io/app/get-started/install-cypress`\n- Open mode and run mode: `https://docs.cypress.io/app/get-started/open-the-app`\n- Configuration: `https://docs.cypress.io/app/references/configuration`\n- Environment variables: `https://docs.cypress.io/app/references/environment-variables`\n- `cy.intercept()`: `https://docs.cypress.io/api/commands/intercept`\n- `cy.request()`: `https://docs.cypress.io/api/commands/request`\n- `cy.session()`: `https://docs.cypress.io/api/commands/session`\n- `cy.task()`: `https://docs.cypress.io/api/commands/task`\n- Custom commands: `https://docs.cypress.io/api/cypress-api/custom-commands`\n- Best practices: `https://docs.cypress.io/app/core-concepts/best-practices`\n"
  },
  {
    "path": "content/cython/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Cython package guide for Python: building compiled extension modules from .pyx or annotated .py code\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"cython,python,c-extension,build,compiler\"\n---\n\n# Cython Python Package Guide\n\n## What Cython Is\n\nCython compiles Python-like source into C or C++ extension modules for CPython. Use it when you need one of these:\n\n- faster CPU-bound loops or array-heavy code\n- direct interop with C or C++\n- Python-callable wrappers around C-level code\n\nFor normal application code, prefer plain Python first. Reach for Cython when profiling shows a hot path or when you need native-library bindings.\n\n## Install\n\n```bash\npython -m pip install Cython==3.2.4\n```\n\nCommon alternatives:\n\n```bash\nuv add Cython==3.2.4\npoetry add Cython==3.2.4\n```\n\nYou also need a working native build toolchain for your platform because Cython does not remove the need for a C/C++ compiler.\n\n- macOS: Xcode Command Line Tools\n- Linux: `gcc` or `clang`, Python headers, and the usual build essentials\n- Windows: MSVC Build Tools matching your Python build\n\n## Minimal Build Setup\n\nFor modern projects, define build requirements in `pyproject.toml` and use `setuptools` with `cythonize()`.\n\n`pyproject.toml`\n\n```toml\n[build-system]\nrequires = [\"setuptools>=68\", \"Cython==3.2.4\"]\nbuild-backend = \"setuptools.build_meta\"\n```\n\n`setup.py`\n\n```python\nfrom setuptools import Extension, setup\nfrom Cython.Build import cythonize\n\nextensions = [\n    Extension(\"mypkg.primes\", [\"src/mypkg/primes.pyx\"]),\n]\n\nsetup(\n    ext_modules=cythonize(\n        extensions,\n        compiler_directives={\"language_level\": 3},\n        annotate=True,\n    ),\n)\n```\n\nProject layout:\n\n```text\nsrc/\n  mypkg/\n    __init__.py\n    primes.pyx\npyproject.toml\nsetup.py\n```\n\nBuild it:\n\n```bash\npython -m pip install -e .\n```\n\nFor quick local iteration on a single module, Cython also documents:\n\n```bash\ncythonize -a -i src/mypkg/primes.pyx\n```\n\n- `-i` builds an importable extension in place\n- `-a` generates the HTML annotation report so you can see where Python interaction remains\n\n## Core Usage\n\n### `.pyx` module example\n\n`src/mypkg/primes.pyx`\n\n```cython\ndef primes(int nb_primes):\n    cdef int n, i, length\n    cdef int[1000] values\n\n    length = 0\n    n = 2\n    while length < nb_primes:\n        for i in range(length):\n            if n % values[i] == 0:\n                break\n        else:\n            values[length] = n\n            length += 1\n        n += 1\n\n    return [values[i] for i in range(length)]\n```\n\nUse it from Python after the build:\n\n```python\nfrom mypkg.primes import primes\n\nprint(primes(10))\n```\n\n### Pure Python mode\n\nCython 3.x also supports compiling regular `.py` files that use `cython` annotations and decorators.\n\n`src/mypkg/fastsum.py`\n\n```python\nimport cython\n\n@cython.ccall\ndef sum_to_n(n: cython.int) -> cython.longlong:\n    i: cython.int\n    total: cython.longlong = 0\n    for i in range(n):\n        total += i\n    return total\n```\n\nBuild the `.py` file with `cythonize()` the same way you would build a `.pyx` file.\n\nUse pure Python mode when you want one source file that still runs under CPython without compilation. Use `.pyx` when you want the clearest separation between normal Python modules and compiled modules.\n\n### Choosing `def`, `cdef`, and `cpdef`\n\n- `def`: normal Python-callable function; can still use typed local variables\n- `cdef`: C-only function or variable; not directly callable from Python\n- `cpdef`: generates both a fast C entry point and a Python-callable wrapper\n\nDefault to `def` unless you need C-level calling or C-only data structures. Use `cpdef` only when you genuinely need both call paths.\n\n### `.pxd` files and `cimport`\n\nUse `.pxd` files for C-level declarations you want to share across Cython modules. Import those declarations with `cimport`, not normal Python `import`.\n\nTypical split:\n\n- `.pyx`: implementation\n- `.pxd`: Cython declarations for functions, extension types, constants, and C APIs\n\n## Build Configuration\n\n### Important compiler directives\n\nSet important directives explicitly instead of depending on defaults:\n\n```python\ncythonize(\n    extensions,\n    compiler_directives={\n        \"language_level\": 3,\n        \"embedsignature\": True,\n    },\n    annotate=True,\n)\n```\n\nPractical defaults:\n\n- `language_level=3`: keep Python 3 semantics explicit\n- `embedsignature=True`: helps Python introspection and tooling\n- `annotate=True`: useful while optimizing\n\nOnly disable safety checks such as `boundscheck` or `wraparound` after correctness is established. Those directives can turn mistakes into memory corruption or crashes.\n\n### NumPy and other native dependencies\n\nIf you `cimport numpy` or depend on native headers, add those build requirements explicitly.\n\n```python\nfrom setuptools import Extension, setup\nfrom Cython.Build import cythonize\nimport numpy\n\nextensions = [\n    Extension(\n        \"mypkg.arrays\",\n        [\"src/mypkg/arrays.pyx\"],\n        include_dirs=[numpy.get_include()],\n    )\n]\n\nsetup(ext_modules=cythonize(extensions, compiler_directives={\"language_level\": 3}))\n```\n\nIn that case, include `numpy` in `build-system.requires` as well so isolated builds succeed.\n\n### No auth or runtime credentials\n\nCython does not need API keys, tokens, or service credentials. The configuration surface is your build backend, compiler toolchain, and compiler directives.\n\n## Common Pitfalls\n\n### `Cython` vs `cython`\n\nThese are related but not interchangeable:\n\n- install from PyPI as `Cython`\n- import build helpers from `Cython.Build`\n- use `import cython` inside pure-Python-mode modules for decorators and type markers\n\n### Translating to C is not the same as building an extension\n\nThe `cython` command can generate C or C++ source, but you still need a native build step to produce an importable extension module. For most projects, `cythonize()` plus `setuptools` is the shortest path.\n\n### Pure Python annotations are not always C types\n\nIn pure Python mode, a normal annotation like `x: int` remains a Python-object annotation. Use Cython type markers such as `cython.int`, `cython.double`, typed memoryviews, or decorators like `@cython.locals` when you need C-level typing.\n\n### `cython.cimports` only works in compiled code\n\nImports like `from cython.cimports.libc.math import sin` are for compiled Cython modules. Plain CPython execution will fail on them.\n\n### `pyximport` is convenient but limited\n\n`pyximport.install()` is useful for quick experiments, but it is not the best default for production packaging. It gives you less control over build options, dependencies, and reproducible builds than a normal package build configuration.\n\n### Cython speedups are not automatic\n\nCompilation alone does not guarantee major speed gains. The biggest wins usually come from:\n\n- moving hot loops into typed code\n- reducing Python object boxing and unboxing\n- using typed memoryviews or C arrays\n- avoiding repeated Python callback boundaries\n\n## Version-Sensitive Notes For 3.2.4\n\n- The version used here `3.2.4` matches the current PyPI release page used for this entry.\n- For Cython 3.x, Python 3 semantics are the default language level. Keep `language_level=3` explicit in your build config anyway so mixed environments and old examples do not surprise you.\n- If you are upgrading old 0.29-era code, review the 3.x migration guide before assuming the same behavior. Upstream calls out changed defaults such as Python-language semantics and `binding=True`.\n- Avoid introducing new uses of deprecated compile-time `DEF` and `IF`.\n- The `3.2.4` change log is incremental rather than a packaging reset; the bigger compatibility concerns are still the broader 3.x migration changes.\n\n## Official Sources\n\n- Stable docs root: `https://cython.readthedocs.io/en/stable/`\n- Install guide: `https://cython.readthedocs.io/en/stable/src/quickstart/install.html`\n- Build quickstart: `https://cython.readthedocs.io/en/stable/src/quickstart/build.html`\n- Pure Python mode: `https://cython.readthedocs.io/en/stable/src/tutorial/pure.html`\n- Source files and compilation guide: `https://cython.readthedocs.io/en/stable/src/userguide/source_files_and_compilation.html`\n- Migration guide: `https://cython.readthedocs.io/en/stable/src/userguide/migrating_to_cy30.html`\n- Change log: `https://cython.readthedocs.io/en/stable/src/changes.html`\n- PyPI release page: `https://pypi.org/project/Cython/3.2.4/`\n"
  },
  {
    "path": "content/cytoolz/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"cytoolz package guide for Python projects using the cytoolz and toolz maintainer docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"cytoolz,toolz,python,functional,iterators,dictionaries\"\n---\n\n# cytoolz Python Package Guide\n\n## Golden Rule\n\nUse `cytoolz` when you want the `toolz` API with the Cython-backed implementation. The maintainers document `cytoolz` as implementing the same API as `toolz`, so the practical references are the `cytoolz` package page plus the `toolz` documentation.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"cytoolz==1.1.0\"\n```\n\n`cytoolz` supports Python 3.9+. It is developed in Cython and may need a working C compiler when `pip` cannot use a prebuilt wheel for your platform.\n\n## Imports And Setup\n\n`cytoolz` is a local utility library. There is no client initialization, authentication flow, or required environment variable.\n\nCommon imports:\n\n```python\nfrom cytoolz import compose, frequencies, groupby, merge_with, pipe, update_in, valmap\nfrom cytoolz.curried import filter, map\n```\n\nUse the base `cytoolz` namespace for direct function calls, and `cytoolz.curried` when you want partially applied `map`, `filter`, and other higher-order helpers in pipelines.\n\n## Common Workflows\n\n### Compose small functions into one reusable transform\n\n```python\nfrom cytoolz import compose, frequencies\nfrom cytoolz.curried import map\n\ndef normalize(word: str) -> str:\n    return word.lower().rstrip(\",.!?:;'-\\\"\").lstrip(\"'\\\"\")\n\nwordcount = compose(frequencies, map(normalize), str.split)\n\nprint(wordcount(\"This cat jumped over this other cat!\"))\n# {'this': 2, 'cat': 2, 'jumped': 1, 'over': 1, 'other': 1}\n```\n\nThis is the core `toolz` style: build a larger operation from small functions instead of writing one monolithic loop.\n\n### Build left-to-right pipelines with curried helpers\n\n```python\nfrom cytoolz import pipe\nfrom cytoolz.curried import filter, map\n\nusers = [\n    {\"email\": \"a@example.com\", \"active\": True},\n    {\"email\": \"b@example.com\", \"active\": False},\n    {\"email\": \"c@example.com\", \"active\": True},\n]\n\nactive_emails = pipe(\n    users,\n    filter(lambda user: user[\"active\"]),\n    map(lambda user: user[\"email\"]),\n    list,\n)\n\nprint(active_emails)\n# ['a@example.com', 'c@example.com']\n```\n\nIf you want this style, import from `cytoolz.curried`; the curried namespace is what turns helpers like `map` and `filter` into pipeline-friendly callables.\n\n### Process large iterables lazily\n\nMany iterator helpers are lazy and only compute values when you consume them.\n\n```python\nfrom cytoolz import partition_all\n\nrecords = range(10)\nbatches = partition_all(4, records)\n\nfor batch in batches:\n    print(batch)\n\n# (0, 1, 2, 3)\n# (4, 5, 6, 7)\n# (8, 9)\n```\n\nThis is useful when you want to keep memory usage low while reading files, database rows, or other large streams. Materialize the result with `list(...)` or `tuple(...)` only when you actually need all values in memory.\n\n### Group and reduce collections\n\n```python\nfrom cytoolz import groupby, merge_with\n\norders = [\n    {\"region\": \"us\", \"total\": 12},\n    {\"region\": \"eu\", \"total\": 7},\n    {\"region\": \"us\", \"total\": 5},\n]\n\norders_by_region = groupby(\"region\", orders)\nprint(orders_by_region[\"us\"])\n# [{'region': 'us', 'total': 12}, {'region': 'us', 'total': 5}]\n\ndaily_counts = merge_with(sum, {\"paid\": 3, \"failed\": 1}, {\"paid\": 2, \"refunded\": 1})\nprint(daily_counts)\n# {'paid': 5, 'failed': 1, 'refunded': 1}\n```\n\n`groupby`, `frequencies`, `countby`, and `merge_with` are the high-value helpers when you are replacing ad hoc aggregation code.\n\n### Update nested dictionaries without mutating in place\n\n```python\nfrom cytoolz import assoc_in, update_in, valmap\n\nconfig = {\n    \"db\": {\"host\": \"localhost\", \"port\": 5432},\n    \"features\": {\"search\": True, \"billing\": False},\n}\n\nnext_config = assoc_in(config, [\"db\", \"host\"], \"db.internal\")\nnext_config = update_in(next_config, [\"db\", \"port\"], lambda port: port + 1)\nfeature_flags = valmap(str, next_config[\"features\"])\n\nprint(next_config)\n# {'db': {'host': 'db.internal', 'port': 5433}, 'features': {'search': True, 'billing': False}}\n\nprint(feature_flags)\n# {'search': 'True', 'billing': 'False'}\n```\n\nThese helpers are useful when you want explicit data transformation without mutating a shared dictionary in place.\n\n## Common Pitfalls\n\n- Many sequence helpers are lazy iterators. If you iterate once, the values are consumed. Convert to `list(...)` at the boundary where you need reuse.\n- Use `cytoolz.curried` for pipeline composition. Importing from `cytoolz` alone does not automatically give you curried `map`, `filter`, or `reduce`.\n- `cytoolz` is a compiled package. If installation falls back to a source build, missing compiler toolchains will fail the install.\n- Python 3.13 free-threading support is marked experimental by the maintainers, and they explicitly warn that `cytoolz` has not been developed or tested for thread safety.\n\n## Version-Sensitive Notes For 1.1.0\n\n- PyPI lists `1.1.0` as the current package version for this guide.\n- The maintainers document Python 3.9+ support for the current codebase.\n- The documented API surface is still the `toolz` API, so the `toolz` docs remain the authoritative function reference for `cytoolz` usage.\n\n## Official Sources\n\n- cytoolz GitHub repository: https://github.com/pytoolz/cytoolz\n- cytoolz PyPI page: https://pypi.org/project/cytoolz/\n- cytoolz 1.1.0 release page on PyPI: https://pypi.org/project/cytoolz/1.1.0/\n- Toolz installation guide: https://toolz.readthedocs.io/en/latest/install.html\n- Toolz curry and curried namespace guide: https://toolz.readthedocs.io/en/latest/curry.html\n- Toolz laziness guide: https://toolz.readthedocs.io/en/latest/laziness.html\n- Toolz API reference: https://toolz.readthedocs.io/en/latest/api.html\n"
  },
  {
    "path": "content/dagster/docs/airbyte/python/DOC.md",
    "content": "---\nname: airbyte\ndescription: \"dagster-airbyte package guide for modeling Airbyte connections as Dagster assets and triggering Airbyte syncs from Dagster\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.14\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,airbyte,dagster-airbyte,python,data-orchestration,etl,assets\"\n---\n\n# dagster-airbyte Python Package Guide\n\n## Golden Rule\n\nFor new Dagster projects, start with `AirbyteWorkspaceComponent`. If you need direct Python control inside `Definitions`, use `AirbyteCloudWorkspace` for Airbyte Cloud or `AirbyteWorkspace` for Airbyte OSS / Self-Managed, then build assets with `build_airbyte_assets_definitions(...)` or `load_airbyte_asset_specs(...)`.\n\nDo not start new work on the superseded `AirbyteResource`, `AirbyteCloudResource`, or `load_assets_from_airbyte_instance(...)` APIs.\n\n## Install\n\nInstall `dagster-airbyte` with the Dagster packages used by your code location:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-airbyte==0.28.14\"\n```\n\nEquivalent `uv` install:\n\n```bash\nuv add dagster dagster-webserver dagster-airbyte\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-airbyte\n```\n\n## Prerequisites\n\nBefore wiring Airbyte into Dagster, make sure you already have:\n\n- a Dagster project with a loadable top-level `defs = dg.Definitions(...)`\n- an Airbyte workspace with at least one configured connection\n- the Airbyte workspace ID\n- either Airbyte Cloud client credentials or the auth method for your self-managed Airbyte deployment\n\nFor self-managed Airbyte, you also need both API base URLs:\n\n- REST API: `https://<airbyte-host>/api/public/v1`\n- Configuration API: `https://<airbyte-host>/api/v1`\n\n## Environment Variables\n\nAirbyte Cloud:\n\n```bash\nexport AIRBYTE_CLOUD_WORKSPACE_ID=\"your-workspace-id\"\nexport AIRBYTE_CLOUD_CLIENT_ID=\"your-client-id\"\nexport AIRBYTE_CLOUD_CLIENT_SECRET=\"your-client-secret\"\n```\n\nAirbyte OSS or Self-Managed with OAuth client credentials:\n\n```bash\nexport AIRBYTE_REST_API_BASE_URL=\"http://localhost:8000/api/public/v1\"\nexport AIRBYTE_CONFIGURATION_API_BASE_URL=\"http://localhost:8000/api/v1\"\nexport AIRBYTE_WORKSPACE_ID=\"your-workspace-id\"\nexport AIRBYTE_CLIENT_ID=\"your-client-id\"\nexport AIRBYTE_CLIENT_SECRET=\"your-client-secret\"\n```\n\nAirbyte OSS or Self-Managed with basic auth:\n\n```bash\nexport AIRBYTE_REST_API_BASE_URL=\"http://localhost:8000/api/public/v1\"\nexport AIRBYTE_CONFIGURATION_API_BASE_URL=\"http://localhost:8000/api/v1\"\nexport AIRBYTE_WORKSPACE_ID=\"your-workspace-id\"\nexport AIRBYTE_USERNAME=\"airbyte\"\nexport AIRBYTE_PASSWORD=\"your-password\"\n```\n\n## Preferred Setup For New Projects: `AirbyteWorkspaceComponent`\n\nDagster recommends the component workflow for new projects.\n\nScaffold the component:\n\n```bash\ndg scaffold defs dagster_airbyte.AirbyteWorkspaceComponent airbyte_ingest \\\n  --workspace-id test_workspace \\\n  --client-id \"{{ env.AIRBYTE_CLIENT_ID }}\" \\\n  --client-secret \"{{ env.AIRBYTE_CLIENT_SECRET }}\"\n```\n\nThat creates a `defs.yaml` file like this for Airbyte Cloud:\n\n```yaml\ntype: dagster_airbyte.AirbyteWorkspaceComponent\nattributes:\n  workspace:\n    workspace_id: test_workspace\n    client_id: \"{{ env.AIRBYTE_CLIENT_ID }}\"\n    client_secret: \"{{ env.AIRBYTE_CLIENT_SECRET }}\"\n```\n\nFor Airbyte OSS or Self-Managed, include both API URLs:\n\n```yaml\ntype: dagster_airbyte.AirbyteWorkspaceComponent\nattributes:\n  workspace:\n    rest_api_base_url: http://localhost:8000/api/public/v1\n    configuration_api_base_url: http://localhost:8000/api/v1\n    workspace_id: test_workspace\n    client_id: \"{{ env.AIRBYTE_CLIENT_ID }}\"\n    client_secret: \"{{ env.AIRBYTE_CLIENT_SECRET }}\"\n```\n\nInspect what Dagster loaded:\n\n```bash\ndg list defs\n```\n\n## Load All Airbyte Cloud Assets In Python\n\nIf you want direct Python definitions instead of the component YAML workflow, create an `AirbyteCloudWorkspace` resource and let Dagster build the assets for every connection in the workspace.\n\n```python\nimport dagster as dg\nfrom dagster_airbyte import AirbyteCloudWorkspace, build_airbyte_assets_definitions\n\n\nairbyte_workspace = AirbyteCloudWorkspace(\n    workspace_id=dg.EnvVar(\"AIRBYTE_CLOUD_WORKSPACE_ID\"),\n    client_id=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_ID\"),\n    client_secret=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_SECRET\"),\n)\n\nairbyte_assets = build_airbyte_assets_definitions(workspace=airbyte_workspace)\n\ndefs = dg.Definitions(\n    assets=airbyte_assets,\n    resources={\"airbyte\": airbyte_workspace},\n)\n```\n\nImportant details:\n\n- `AirbyteCloudWorkspace` uses the Airbyte Cloud API defaults; you do not pass custom base URLs.\n- `resources={\"airbyte\": airbyte_workspace}` is the resource binding that `dagster-airbyte` expects for materialization.\n- `build_airbyte_assets_definitions(...)` creates materializable assets for all connections returned from the workspace.\n\n## Load All Airbyte OSS / Self-Managed Assets In Python\n\nUse `AirbyteWorkspace` when Dagster needs to talk to a self-managed Airbyte deployment.\n\n```python\nimport dagster as dg\nfrom dagster_airbyte import AirbyteWorkspace, build_airbyte_assets_definitions\n\n\nairbyte_workspace = AirbyteWorkspace(\n    rest_api_base_url=dg.EnvVar(\"AIRBYTE_REST_API_BASE_URL\"),\n    configuration_api_base_url=dg.EnvVar(\"AIRBYTE_CONFIGURATION_API_BASE_URL\"),\n    workspace_id=dg.EnvVar(\"AIRBYTE_WORKSPACE_ID\"),\n    client_id=dg.EnvVar(\"AIRBYTE_CLIENT_ID\"),\n    client_secret=dg.EnvVar(\"AIRBYTE_CLIENT_SECRET\"),\n)\n\nairbyte_assets = build_airbyte_assets_definitions(workspace=airbyte_workspace)\n\ndefs = dg.Definitions(\n    assets=airbyte_assets,\n    resources={\"airbyte\": airbyte_workspace},\n)\n```\n\nIf your Airbyte deployment uses basic auth instead of OAuth, replace `client_id` and `client_secret` with:\n\n```python\nusername=dg.EnvVar(\"AIRBYTE_USERNAME\"),\npassword=dg.EnvVar(\"AIRBYTE_PASSWORD\"),\n```\n\n## Load Asset Specs Without Materialization Logic\n\nUse `load_airbyte_asset_specs(...)` when you only want asset specs from the workspace and do not need Dagster to generate the sync materialization definitions for every connection.\n\n```python\nimport dagster as dg\nfrom dagster_airbyte import AirbyteCloudWorkspace, load_airbyte_asset_specs\n\n\nairbyte_workspace = AirbyteCloudWorkspace(\n    workspace_id=dg.EnvVar(\"AIRBYTE_CLOUD_WORKSPACE_ID\"),\n    client_id=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_ID\"),\n    client_secret=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_SECRET\"),\n)\n\nairbyte_specs = load_airbyte_asset_specs(airbyte_workspace)\n\ndefs = dg.Definitions(assets=airbyte_specs)\n```\n\nThis is also the API to use if you want to filter which connections become assets:\n\n```python\nairbyte_specs = load_airbyte_asset_specs(\n    workspace=airbyte_workspace,\n    connection_selector_fn=lambda connection: connection.name in [\"salesforce\", \"stripe\"],\n)\n```\n\n## Sync One Connection With Custom Logic\n\nUse the `@airbyte_assets` decorator when you want to wrap a single Airbyte connection with your own logic before or after the sync.\n\n```python\nimport dagster as dg\nfrom dagster_airbyte import AirbyteCloudWorkspace, airbyte_assets\n\n\nairbyte_workspace = AirbyteCloudWorkspace(\n    workspace_id=dg.EnvVar(\"AIRBYTE_CLOUD_WORKSPACE_ID\"),\n    client_id=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_ID\"),\n    client_secret=dg.EnvVar(\"AIRBYTE_CLOUD_CLIENT_SECRET\"),\n)\n\n\n@airbyte_assets(\n    connection_id=\"your-connection-id\",\n    workspace=airbyte_workspace,\n    name=\"airbyte_connection_assets\",\n    group_name=\"airbyte\",\n)\ndef airbyte_connection_assets(\n    context: dg.AssetExecutionContext, airbyte: AirbyteCloudWorkspace\n):\n    yield from airbyte.sync_and_poll(context=context)\n\n\ndefs = dg.Definitions(\n    assets=[airbyte_connection_assets],\n    resources={\"airbyte\": airbyte_workspace},\n)\n```\n\nThe exact runtime call that triggers and monitors the Airbyte sync is:\n\n```python\nyield from airbyte.sync_and_poll(context=context)\n```\n\n## Local Development Workflow\n\nValidate the definitions and start Dagster against the module that exports your top-level `Definitions` object:\n\n```bash\ndg check defs\ndg dev -m my_project.definitions\n```\n\n## Common Pitfalls\n\n- For Airbyte OSS or Self-Managed, `AirbyteWorkspace` needs both `rest_api_base_url` and `configuration_api_base_url`. Passing only one endpoint is not enough.\n- Pick one auth mode per self-managed workspace: `client_id` and `client_secret`, or `username` and `password`, or no auth. The resource validation rejects mixed auth configuration.\n- `load_airbyte_cloud_asset_specs(...)` is superseded. Use `load_airbyte_asset_specs(...)` instead.\n- `AirbyteResource`, `AirbyteCloudResource`, and `load_assets_from_airbyte_instance(...)` are superseded for newer Airbyte versions. Use the workspace APIs instead.\n- The current Airbyte workspace APIs are marked beta in Dagster's docs, so minor-version upgrades can still introduce breaking changes.\n- Keep the Dagster resource key aligned with the function parameter name you inject. If your asset function expects `airbyte`, register the resource as `resources={\"airbyte\": ...}`.\n\n## Version Notes\n\n- Dagster's current docs site exposes the maintained `dagster-airbyte` API surface described here.\n- PyPI currently shows `dagster-airbyte 0.28.14` as the latest visible release, published on February 5, 2026. If you were handed a newer internal pin such as `0.28.18`, verify that it is actually published in the environment you deploy from before pinning it.\n\n## Official Sources\n\n- https://docs.dagster.io/integrations/libraries/airbyte\n- https://docs.dagster.io/integrations/libraries/airbyte/airbyte-component\n- https://docs.dagster.io/integrations/libraries/airbyte/airbyte-oss\n- https://docs.dagster.io/integrations/libraries/airbyte/airbyte-cloud-legacy\n- https://docs.dagster.io/integrations/libraries/airbyte/migration-guide\n- https://docs.dagster.io/integrations/libraries/airbyte/dagster-airbyte\n- https://raw.githubusercontent.com/dagster-io/dagster/master/python_modules/libraries/dagster-airbyte/dagster_airbyte/resources.py\n- https://pypi.org/project/dagster-airbyte/\n"
  },
  {
    "path": "content/dagster/docs/aws/python/DOC.md",
    "content": "---\nname: aws\ndescription: \"dagster-aws package guide for using Dagster with AWS resources such as S3 and Secrets Manager\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,aws,dagster-aws,python,s3,secrets-manager,data-orchestration\"\n---\n\n# dagster-aws Python Package Guide\n\n## Golden Rule\n\nUse `dagster-aws` as Dagster's AWS integration layer, but keep authentication and permissions in normal AWS configuration and IAM. Install `dagster-aws` on the matching Dagster release line, register AWS resources in `dg.Definitions(...)`, and let those resources hand you the underlying AWS clients inside assets and ops.\n\n## Install\n\nInstall `dagster-aws` alongside the matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-aws==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-aws\n```\n\n## Prerequisites\n\nBefore wiring `dagster-aws` into a project, make sure you already have:\n\n- a Dagster project with a loadable top-level `defs = dg.Definitions(...)`\n- AWS credentials available through the standard AWS SDK credential chain\n- a region selected for the AWS APIs you will call\n- IAM permissions for the exact S3, Secrets Manager, or other AWS APIs used by your assets\n\n## Configure AWS Credentials\n\n`dagster-aws` uses normal AWS SDK configuration. For local development, the simplest setup is environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"your-access-key-id\"\nexport AWS_SECRET_ACCESS_KEY=\"your-secret-access-key\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\nIf you use temporary credentials, also set:\n\n```bash\nexport AWS_SESSION_TOKEN=\"your-session-token\"\n```\n\nIf you prefer named profiles, set `AWS_PROFILE` and keep credentials in the usual AWS config files:\n\n```bash\nexport AWS_PROFILE=\"my-dagster-profile\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n```\n\n## Use `S3Resource` In Assets\n\nThe most direct pattern is to configure an `S3Resource`, inject it into an asset, and call the underlying S3 client for reads and writes.\n\n```python\nimport dagster as dg\nfrom dagster_aws.s3 import S3Resource\n\nBUCKET = \"my-data-bucket\"\nKEY = \"examples/hello.txt\"\n\n\n@dg.asset\ndef write_example_file(s3: S3Resource) -> None:\n    s3.get_client().put_object(\n        Bucket=BUCKET,\n        Key=KEY,\n        Body=b\"hello from dagster-aws\\n\",\n        ContentType=\"text/plain\",\n    )\n\n\n@dg.asset(deps=[write_example_file])\ndef read_example_file(s3: S3Resource) -> str:\n    response = s3.get_client().get_object(Bucket=BUCKET, Key=KEY)\n    return response[\"Body\"].read().decode(\"utf-8\")\n\n\ndefs = dg.Definitions(\n    assets=[write_example_file, read_example_file],\n    resources={\n        \"s3\": S3Resource(region_name=\"us-east-1\"),\n    },\n)\n```\n\nImportant details:\n\n- the resource key in `resources={\"s3\": ...}` must match the asset parameter name `s3`\n- S3 object bodies are bytes or streams, so decode text explicitly or deserialize JSON yourself\n- the AWS identity Dagster runs under still needs normal `s3:PutObject` and `s3:GetObject` permissions\n\n## Read Secrets From AWS Secrets Manager\n\nUse `SecretsManagerResource` when an asset or op needs a secret at runtime.\n\n```python\nimport dagster as dg\nfrom dagster_aws.secretsmanager import SecretsManagerResource\n\n\n@dg.asset\ndef external_api_key(secretsmanager: SecretsManagerResource) -> str:\n    response = secretsmanager.get_client().get_secret_value(\n        SecretId=\"prod/my-app/external-api\"\n    )\n    return response[\"SecretString\"]\n\n\ndefs = dg.Definitions(\n    assets=[external_api_key],\n    resources={\n        \"secretsmanager\": SecretsManagerResource(region_name=\"us-east-1\"),\n    },\n)\n```\n\nIf the secret stores JSON instead of a plain string, parse `response[\"SecretString\"]` before using it.\n\n## Local Development Workflow\n\nPoint Dagster at the module that exposes your top-level `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nThis workflow is usually enough for local iteration when your AWS credentials are already available through environment variables or a named profile.\n\n## Common Pitfalls\n\n- Mismatched versions. Keep `dagster-aws` on the matching Dagster release line in the same environment.\n- Missing region configuration. Set `AWS_DEFAULT_REGION` or pass `region_name=...` when constructing resources.\n- Resource name mismatch. In Dagster, the resource dictionary key must match the function parameter name used for injection.\n- Missing IAM permissions. `dagster-aws` does not bypass AWS authorization; the underlying role or credentials still need permission for every API call.\n- Logging secrets by accident. Do not log `SecretString` values or copy them into constant Dagster config.\n\n## Version Notes For `0.28.18`\n\n- `dagster-aws==0.28.18` belongs to the Dagster `1.12.18` release line; keep related Dagster packages aligned to that same line.\n- AWS authentication behavior comes from the normal AWS SDK credential chain, so deployment behavior can differ between local shells, CI, containers, and cloud runtimes depending on which credentials source is available.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-aws\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-aws/dagster_aws/s3\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-aws/dagster_aws/secretsmanager\n- https://docs.dagster.io/api/python-api/libraries/dagster-aws\n- https://pypi.org/project/dagster-aws/\n"
  },
  {
    "path": "content/dagster/docs/azure/python/DOC.md",
    "content": "---\nname: azure\ndescription: \"Dagster Azure integrations for Python: configure Azure Blob Storage and ADLS Gen2 resources inside Dagster code\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,azure,python,blob-storage,adls2,data-orchestration\"\n---\n\n# dagster-azure Python Package Guide\n\n## Golden Rule\n\nInstall `dagster-azure` on the same Dagster release line as the rest of your Dagster packages, then use the package to give ops and assets an Azure storage client through Dagster resources. After the resource is configured, the code you write against Blob Storage or ADLS Gen2 is the normal Azure SDK client flow.\n\n## Installation\n\nFor the package version in this guide, keep the Dagster packages aligned:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-azure==0.28.18\"\n```\n\nIf you already have a Dagster project and do not need the local web UI in that environment, `dagster-webserver` is optional.\n\n## Prerequisites\n\nThese examples assume:\n\n- You already have an Azure Storage account.\n- The target Blob container or ADLS Gen2 file system already exists.\n- Your Dagster process can read the storage account name and credential from environment variables.\n\nExample environment setup:\n\n```bash\nexport AZURE_STORAGE_ACCOUNT=\"<storage-account-name>\"\nexport AZURE_STORAGE_KEY=\"<storage-account-key>\"\nexport AZURE_STORAGE_BLOB_CONTAINER=\"dagster\"\nexport AZURE_STORAGE_FILE_SYSTEM=\"dagster\"\n```\n\n## Use Azure Blob Storage In Dagster\n\nUse the Blob resource when you want Dagster code to read or write regular Azure blobs.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_azure.blob import azure_blob_storage_resource\n\n\n@dg.asset(required_resource_keys={\"blob\"})\ndef upload_blob(context: dg.AssetExecutionContext) -> str:\n    blob_name = \"examples/hello.txt\"\n    blob_service_client = context.resources.blob\n\n    blob_client = blob_service_client.get_blob_client(\n        container=os.environ[\"AZURE_STORAGE_BLOB_CONTAINER\"],\n        blob=blob_name,\n    )\n    blob_client.upload_blob(b\"hello from dagster-azure\\n\", overwrite=True)\n    return blob_name\n\n\ndefs = dg.Definitions(\n    assets=[upload_blob],\n    resources={\n        \"blob\": azure_blob_storage_resource.configured(\n            {\n                \"storage_account\": {\"env\": \"AZURE_STORAGE_ACCOUNT\"},\n                \"credential\": {\"env\": \"AZURE_STORAGE_KEY\"},\n            }\n        )\n    },\n)\n```\n\nWhat matters in the snippet:\n\n- `azure_blob_storage_resource` creates the Azure Blob service client for Dagster.\n- `context.resources.blob` is the client you use inside the asset.\n- Blob operations still use the standard Azure client API such as `get_blob_client(...)` and `upload_blob(...)`.\n\n## Use ADLS Gen2 In Dagster\n\nUse the ADLS2 resource when your data lives in a hierarchical namespace and you want to work with file systems and file paths instead of flat blob keys.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_azure.adls2 import adls2_resource\n\n\n@dg.asset(required_resource_keys={\"adls2\"})\ndef write_marker_file(context: dg.AssetExecutionContext) -> str:\n    path = \"runs/marker.txt\"\n    service_client = context.resources.adls2\n\n    file_system_client = service_client.get_file_system_client(\n        file_system=os.environ[\"AZURE_STORAGE_FILE_SYSTEM\"]\n    )\n    file_client = file_system_client.get_file_client(path)\n\n    data = b\"ok\\n\"\n    file_client.create_file()\n    file_client.append_data(data, offset=0, length=len(data))\n    file_client.flush_data(len(data))\n    return path\n\n\ndefs = dg.Definitions(\n    assets=[write_marker_file],\n    resources={\n        \"adls2\": adls2_resource.configured(\n            {\n                \"storage_account\": {\"env\": \"AZURE_STORAGE_ACCOUNT\"},\n                \"credential\": {\"env\": \"AZURE_STORAGE_KEY\"},\n            }\n        )\n    },\n)\n```\n\nThis pattern is useful when your Dagster code needs the underlying ADLS Gen2 client directly, for example to create or append files with the Azure Data Lake API.\n\n## How To Choose Between Blob And ADLS2\n\n- Use `dagster_azure.blob` for standard Blob Storage containers and blob objects.\n- Use `dagster_azure.adls2` when your storage account has hierarchical namespace enabled and your code needs file-system style operations.\n- In both cases, Dagster handles resource construction and your asset code calls the Azure client methods.\n\n## Important Pitfalls\n\n- Keep `dagster`, `dagster-webserver`, and `dagster-azure` on the same release line.\n- Create the Blob container or ADLS2 file system before materializing these assets.\n- Treat Azure authentication failures and missing-container or missing-file-system errors as Azure client issues first; the Dagster resource wrapper does not change the underlying storage API semantics.\n- Prefer environment variables or your deployment system's secret manager for storage credentials instead of hard-coding keys in source.\n\n## Version Notes\n\nThis guide targets `dagster-azure==0.28.18`. If you upgrade Dagster to a different release line, upgrade `dagster-azure` with it and re-check the corresponding library docs before copying config between versions.\n"
  },
  {
    "path": "content/dagster/docs/celery/python/DOC.md",
    "content": "---\nname: celery\ndescription: \"Dagster Celery executor integration for running Dagster job steps on Celery workers backed by Redis, RabbitMQ, or another Celery broker/backend.\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,celery,python,executor,distributed-execution,workflow-orchestration\"\n---\n\n# `dagster-celery` for Python\n\nUse `dagster-celery` when a Dagster deployment needs a Celery-backed executor for a job. The package plugs a Celery executor into Dagster so job steps can run on Celery workers instead of only in the process that launched the run.\n\nThis package is not a full queueing stack by itself. You still need:\n\n- a working Dagster code location\n- a running Celery broker such as Redis or RabbitMQ\n- a Celery result backend\n- worker processes that can import your Dagster code and its dependencies\n\n## Install\n\nPin the package version if you want the exact release covered here:\n\n```bash\npython -m pip install \"dagster-celery==0.28.18\"\n```\n\nIn practice, keep `dagster-celery` on a release line that matches the rest of your Dagster deployment instead of mixing unrelated Dagster package versions.\n\n## What to configure\n\n`dagster-celery` does not add a separate client object or authentication flow. The main integration point is the executor definition exported by the package:\n\n```python\nfrom dagster_celery import celery_executor\n```\n\nCredentials and connectivity usually come from the Celery URLs you provide for:\n\n- the broker\n- the result backend\n\nA practical environment-variable pattern is:\n\n```bash\nexport DAGSTER_CELERY_BROKER_URL=\"redis://localhost:6379/0\"\nexport DAGSTER_CELERY_RESULT_BACKEND=\"redis://localhost:6379/1\"\n```\n\nIf you use RabbitMQ instead of Redis, a broker URL commonly looks like:\n\n```bash\nexport DAGSTER_CELERY_BROKER_URL=\"amqp://guest:guest@localhost:5672//\"\nexport DAGSTER_CELERY_RESULT_BACKEND=\"rpc://\"\n```\n\n## Minimal job using `celery_executor`\n\nThe package is used at job definition time by setting `executor_def=celery_executor`.\n\n```python\nimport os\n\nfrom dagster import Definitions, job, op\nfrom dagster_celery import celery_executor\n\nCELERY_BROKER_URL = os.environ[\"DAGSTER_CELERY_BROKER_URL\"]\nCELERY_RESULT_BACKEND = os.environ[\"DAGSTER_CELERY_RESULT_BACKEND\"]\n\n\n@op\ndef ping() -> str:\n    return \"ok\"\n\n\n@job(\n    executor_def=celery_executor,\n    config={\n        \"execution\": {\n            \"config\": {\n                \"broker\": CELERY_BROKER_URL,\n                \"backend\": CELERY_RESULT_BACKEND,\n            }\n        }\n    },\n)\ndef celery_job():\n    ping()\n\n\ndefs = Definitions(jobs=[celery_job])\n```\n\nThis is the core pattern to remember:\n\n- import `celery_executor` from `dagster_celery`\n- attach it to a Dagster job with `executor_def=celery_executor`\n- provide Celery connection settings through executor config\n\n## Common workflow\n\n1. Start the broker and result backend your Celery deployment uses.\n2. Make sure the same Dagster code and Python dependencies are available to worker processes.\n3. Add `executor_def=celery_executor` to the jobs that should use Celery-backed step execution.\n4. Supply broker and backend configuration from environment variables or run config.\n5. Run those jobs through your normal Dagster deployment flow.\n\nIf only one job should use Celery, configure that job directly. You do not need to move every Dagster job to Celery at once.\n\n## Important pitfalls\n\n### `execute_in_process()` is not a Celery test\n\nDagster's in-process execution path is useful for unit tests, but it does not exercise distributed Celery execution the same way a real deployment does.\n\n### Workers must be able to import your code\n\nThe Celery workers need the same user code and importable Python dependencies as the Dagster process that defines the job. If the workers cannot import your project, step execution will fail after the run is launched.\n\n### Broker and backend connectivity must work from every process\n\nIt is not enough for the webserver or launcher process to reach Redis or RabbitMQ. The worker side needs the same network access and credentials.\n\n### Keep secrets out of checked-in config\n\nTreat broker URLs and backend credentials like any other secret. Put them in environment variables or your deployment secret manager instead of hardcoding them in source control.\n\n## Version notes for `0.28.18`\n\n- This guide targets `dagster-celery==0.28.18`.\n- Pin the integration package explicitly when you need repeatable environments.\n- Upgrade the rest of your Dagster deployment deliberately alongside this package instead of bumping only one Dagster library in isolation.\n\n## Official sources\n\n- Maintainer repository: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-celery\n- Package README in the maintainer repository: https://github.com/dagster-io/dagster/blob/master/python_modules/libraries/dagster-celery/README.md\n- PyPI project page: https://pypi.org/project/dagster-celery/\n"
  },
  {
    "path": "content/dagster/docs/dagit/python/DOC.md",
    "content": "---\nname: dagit\ndescription: \"dagit Python package guide for Dagster OSS local web UI setup and legacy package compatibility\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagit,dagster,python,web-ui,orchestration,assets\"\n---\n\n# dagit Python Package Guide\n\n## Golden Rule\n\nIf you inherit `dagit` in an older Dagster environment, keep it on the exact same release line as the rest of your Dagster packages. For new local OSS setup on `1.12.18`, follow the current Dagster workflow built around `dagster`, `dagster-webserver`, and `dagster dev`, with a loadable module that exposes a top-level `defs = dg.Definitions(...)` object.\n\n## Install\n\nIf an existing project already pins `dagit`, keep the package aligned with core Dagster:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagit==1.12.18\"\n```\n\nFor a fresh local setup on the same release line, prefer the packages used by the current Dagster OSS docs:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-dg-cli==1.12.18\"\n```\n\nCommon alternatives:\n\n```bash\nuv add dagster dagster-webserver dagster-dg-cli\npoetry add \"dagster==1.12.18\" \"dagster-webserver==1.12.18\" \"dagster-dg-cli==1.12.18\"\n```\n\n## Minimal Project Shape\n\nThe important requirement is a loadable Python module with a top-level `Definitions` object.\n\n```text\nsrc/\n  my_project/\n    __init__.py\n    definitions.py\n```\n\n```python\nimport dagster as dg\n\n@dg.asset\ndef hello() -> str:\n    return \"hello\"\n\ndefs = dg.Definitions(assets=[hello])\n```\n\n## Environment And Instance State\n\nUse a shared `DAGSTER_HOME` directory for the local instance state that the web UI, daemon, and other Dagster processes should see:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nmkdir -p \"$DAGSTER_HOME\"\n```\n\nThere is no separate package-level auth step for local OSS usage. If you expose the UI remotely, handle authentication and network access at the deployment edge and keep every cooperating Dagster process pointed at the same `DAGSTER_HOME`.\n\n## Start The Local UI\n\nFor the current `1.12.18` release line, the lowest-friction local command is:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nThat command loads `defs` from `my_project.definitions`, starts the local web UI, and uses your current `DAGSTER_HOME`.\n\nIf your project also uses schedules or sensors, run the daemon against the same instance directory:\n\n```bash\ndagster-daemon run\n```\n\n## Common Workflow\n\n### Add assets and resources\n\n```python\nimport dagster as dg\n\nclass ApiResource(dg.ConfigurableResource):\n    token: str\n\n    def fetch(self) -> list[str]:\n        return [\"a\", \"b\", \"c\"]\n\n@dg.asset\ndef raw_items(api: ApiResource) -> list[str]:\n    return api.fetch()\n\n@dg.asset\ndef item_count(raw_items: list[str]) -> int:\n    return len(raw_items)\n\ndefs = dg.Definitions(\n    assets=[raw_items, item_count],\n    resources={\"api\": ApiResource(token=dg.EnvVar(\"API_TOKEN\"))},\n)\n```\n\n```bash\nexport API_TOKEN=\"dev-token\"\ndagster dev -m my_project.definitions\n```\n\nThis is the practical pattern to keep in mind: define assets, register resources in `Definitions`, and let the web UI load that module.\n\n### Validate definitions before opening the UI\n\n```bash\ndg check defs -m my_project.definitions\n```\n\nUse this when you want a faster failure mode than opening the UI first.\n\n## Common Pitfalls\n\n- Mixing Dagster package versions. Keep `dagster`, `dagit`, `dagster-webserver`, and related Dagster packages on the same release line.\n- Exposing helper functions but not a top-level `defs = dg.Definitions(...)` object. The local tooling needs a loadable definitions target.\n- Using different `DAGSTER_HOME` values for the web UI and daemon. That splits run history, schedules, and other instance state.\n- Copying older Dagster examples without translating them to the current `Definitions` and asset-oriented workflow.\n- Looking for `dagit`-specific setup in newer Dagster docs. For `1.12.18`, the maintained local workflow is documented around `dagster dev` and `dagster-webserver`.\n\n## Version-Sensitive Notes For 1.12.18\n\n- This guide targets the `dagit` PyPI release `1.12.18`.\n- The surrounding Dagster `1.12.18` package guides and CLI docs center on `dagster-webserver` and `dagster dev` for local OSS development.\n- If you are keeping `dagit` in an existing environment, pin it with the rest of the Dagster stack instead of upgrading it independently.\n\n## Official Sources Used\n\n- Dagster monorepo: https://github.com/dagster-io/dagster\n- Dagster docs root: https://docs.dagster.io/\n- Dagster API docs root: https://docs.dagster.io/api\n- Definitions API: https://docs.dagster.io/api/dagster/definitions\n- CLI reference: https://docs.dagster.io/api/clis\n- Dagster releases: https://github.com/dagster-io/dagster/releases\n- PyPI `dagit` page: https://pypi.org/project/dagit/\n- PyPI `dagster-webserver` page: https://pypi.org/project/dagster-webserver/\n"
  },
  {
    "path": "content/dagster/docs/databricks/python/DOC.md",
    "content": "---\nname: databricks\ndescription: \"dagster-databricks package guide for launching Databricks jobs from Dagster assets and ops with PipesDatabricksClient\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-databricks,python,databricks,pipes,orchestration,jobs\"\n---\n\n# dagster-databricks Python Package Guide\n\n## Golden Rule\n\nUse `dagster-databricks` for the Dagster side of the integration and `dagster-pipes` inside the Databricks task you launch. The current Dagster integration docs center on `PipesDatabricksClient`, which is the main workflow to copy for new code.\n\nOn the Databricks side, authenticate through the Databricks SDK for Python. For simple workspace automation that usually means `DATABRICKS_HOST` plus `DATABRICKS_TOKEN`, but Databricks recommends its default unified auth flow and recommends OAuth over personal access tokens for new automation.\n\n## Install\n\nInstall the Dagster integration package in the environment that runs your Dagster code:\n\n```bash\npython -m pip install \"dagster-databricks==0.28.18\"\n```\n\nIf you also write standalone Databricks SDK code outside the Dagster integration, install the SDK explicitly in that local environment:\n\n```bash\npython -m pip install \"databricks-sdk\"\n```\n\nThe Databricks job or cluster that runs your remote code also needs `dagster-pipes` available:\n\n```bash\npython -m pip install \"dagster-pipes\"\n```\n\n## Prerequisites\n\nBefore wiring this into Dagster, make sure you already have:\n\n- a Databricks workspace and a cluster or job compute target\n- a Dagster project with a loadable top-level `defs = dg.Definitions(...)`\n- a Python file, workspace file, volume path, or cloud URI that Databricks can execute as the job task\n\nFor local configuration, the simplest explicit environment-variable setup is:\n\n```bash\nexport DATABRICKS_HOST=\"https://dbc-1234567890123456.cloud.databricks.com\"\nexport DATABRICKS_TOKEN=\"dapi...\"\n```\n\nDatabricks documents `DATABRICKS_HOST` and `DATABRICKS_TOKEN` for token auth. Databricks also marks personal access token authentication as legacy and recommends OAuth for stronger security when you are setting up new automation.\n\n## Register `PipesDatabricksClient`\n\nThis is the core Dagster-side setup:\n\n```python\nimport dagster as dg\nimport os\nfrom databricks.sdk import WorkspaceClient\nfrom dagster_databricks import PipesDatabricksClient\n\n\npipes_databricks = PipesDatabricksClient(\n    client=WorkspaceClient(\n        host=os.environ[\"DATABRICKS_HOST\"],\n        token=os.environ[\"DATABRICKS_TOKEN\"],\n    )\n)\n\ndefs = dg.Definitions(\n    resources={\"pipes_databricks\": pipes_databricks},\n)\n```\n\nIf you already rely on Databricks unified authentication through environment variables or a `.databrickscfg` profile, `WorkspaceClient()` with no arguments also works:\n\n```python\nfrom databricks.sdk import WorkspaceClient\n\nclient = WorkspaceClient()\n```\n\n## Launch A Databricks Python Job From An Asset\n\nThe main Dagster pattern is: build a Databricks task, call `pipes_databricks.run(...)`, and return `.get_materialize_result()`.\n\n```python\nimport dagster as dg\nimport os\nfrom databricks.sdk import WorkspaceClient\nfrom databricks.sdk.service import jobs\nfrom dagster_databricks import PipesDatabricksClient\n\n\n@dg.asset\ndef databricks_asset(\n    context: dg.AssetExecutionContext,\n    pipes_databricks: PipesDatabricksClient,\n):\n    task = jobs.SubmitTask.from_dict(\n        {\n            \"task_key\": \"daily-ingest\",\n            \"new_cluster\": {\n                \"spark_version\": \"12.2.x-scala2.12\",\n                \"node_type_id\": \"i3.xlarge\",\n                \"num_workers\": 0,\n                \"cluster_log_conf\": {\n                    \"dbfs\": {\"destination\": \"dbfs:/cluster-logs/dagster-databricks\"}\n                },\n            },\n            \"libraries\": [\n                {\"pypi\": {\"package\": \"dagster-pipes\"}},\n            ],\n            \"spark_python_task\": {\n                \"python_file\": \"/Workspace/Shared/dagster/pipes_job.py\",\n                \"source\": jobs.Source.WORKSPACE,\n            },\n        }\n    )\n\n    return pipes_databricks.run(\n        task=task,\n        context=context,\n        extras={\"storage_root\": \"/tmp/dagster-pipes\", \"full_refresh\": False},\n    ).get_materialize_result()\n\n\ndefs = dg.Definitions(\n    assets=[databricks_asset],\n    resources={\n        \"pipes_databricks\": PipesDatabricksClient(\n            client=WorkspaceClient(\n                host=os.environ[\"DATABRICKS_HOST\"],\n                token=os.environ[\"DATABRICKS_TOKEN\"],\n            )\n        )\n    },\n)\n```\n\nImportant details:\n\n- the resource key in `resources={\"pipes_databricks\": ...}` must match the asset parameter name\n- the exact Dagster-side API call is `pipes_databricks.run(task=..., context=..., extras=...)`\n- `extras` is how you pass small runtime values into the Databricks process\n- the returned `PipesClientCompletedInvocation` object exposes `.get_materialize_result()`\n\n## Write The Databricks-Side Code\n\nInside the Databricks task, open a Dagster Pipes session, read any extras you passed from Dagster, and report events back:\n\n```python\nfrom dagster_pipes import (\n    PipesDbfsContextLoader,\n    PipesDbfsMessageWriter,\n    open_dagster_pipes,\n)\n\n\nwith open_dagster_pipes(\n    context_loader=PipesDbfsContextLoader(),\n    message_writer=PipesDbfsMessageWriter(),\n) as pipes:\n    full_refresh = pipes.get_extra(\"full_refresh\")\n\n    pipes.log.info(f\"Starting Databricks task with full_refresh={full_refresh}\")\n\n    # Run your Databricks-side logic here.\n    row_count = 123\n\n    pipes.report_asset_materialization(\n        metadata={\"row_count\": row_count},\n        data_version=\"2026-03-13\",\n    )\n```\n\nDagster's integration docs specifically recommend `PipesDbfsContextLoader` and `PipesDbfsMessageWriter` for Databricks.\n\n## Script Location And Job Packaging\n\nThe Dagster integration example shows `spark_python_task[\"python_file\"]` pointing at a DBFS path. Databricks' current jobs docs say Python script tasks can use workspace files, DBFS or cloud URIs, or a Git provider, and Databricks recommends workspace files, Unity Catalog volumes, or cloud object storage over DBFS root for new jobs.\n\nIn practice:\n\n- keep your executable script in a location Databricks can read\n- install `dagster-pipes` in the task environment with the job `libraries` field\n- use a `spark_python_task` when your remote code is a Python file\n\n## Local Development Workflow\n\nRun the Dagster code location that contains your `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nIf you want to sanity-check Databricks SDK auth separately from Dagster, this is the smallest direct test:\n\n```python\nfrom databricks.sdk import WorkspaceClient\n\nw = WorkspaceClient()\n\nfor cluster in w.clusters.list():\n    print(cluster.cluster_name)\n```\n\n## Common Pitfalls\n\n- Resource name mismatch. The asset parameter name must match the key in `Definitions(resources=...)`.\n- Missing `dagster-pipes` on the Databricks cluster or job. The Dagster side can submit the task, but the remote code will not be able to open the Pipes session.\n- Assuming PATs are the preferred long-term auth method. Databricks documents PAT auth as legacy and recommends OAuth for new automation.\n- Treating `dbfs:/...` as the preferred place for new Python scripts. Databricks now recommends workspace files, volumes, or cloud object storage instead of DBFS root.\n- Using `WorkspaceClient()` default notebook auth assumptions outside notebooks. Databricks notes that notebook auth has runtime and environment limitations; explicit workspace auth is more predictable for local Dagster processes.\n\n## Version Notes For `0.28.18`\n\n- This guide targets `dagster-databricks==0.28.18`.\n- Inference from Dagster's current integration page: `PipesDatabricksClient` is the primary workflow Dagster is promoting for this package right now.\n- Databricks currently documents the Databricks SDK for Python as beta and recommends pinning the minor version you depend on if you use the SDK directly in your own code.\n\n## Official Sources Used\n\n- https://dagster.io/integrations/dagster-databricks\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-databricks\n- https://pypi.org/project/dagster-databricks/\n- https://docs.databricks.com/aws/en/dev-tools/sdk-python\n- https://docs.databricks.com/aws/en/dev-tools/auth/pat\n- https://docs.databricks.com/aws/en/jobs/python-script\n"
  },
  {
    "path": "content/dagster/docs/dbt/python/DOC.md",
    "content": "---\nname: dbt\ndescription: \"dagster-dbt package guide for loading dbt projects as Dagster assets and running dbt CLI workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,dbt,dagster-dbt,python,data-orchestration,assets,etl\"\n---\n\n# dagster-dbt Python Package Guide\n\n## Golden Rule\n\nTreat `dagster-dbt` as Dagster's bridge to an existing dbt project. Keep the dbt project authoritative, generate a fresh `manifest.json`, and execute dbt through `DbtCliResource` instead of trying to call dbt internals from long-lived Python application code.\n\n## Install\n\nInstall `dagster-dbt` alongside the matching Dagster release, plus the dbt adapter your project actually uses:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-dbt==0.28.18\" \\\n  \"dbt-duckdb\"\n```\n\nReplace `dbt-duckdb` with your adapter package such as `dbt-postgres`, `dbt-snowflake`, or `dbt-bigquery`.\n\nUseful checks after install:\n\n```bash\ndagster --version\ndbt --version\npython -m pip show dagster-dbt\n```\n\n## Prerequisites\n\nBefore wiring Dagster to dbt, make sure you already have:\n\n- a working dbt project with `dbt_project.yml`\n- a valid dbt profile, usually in `~/.dbt/profiles.yml` or a custom directory\n- a generated `target/manifest.json` artifact from `dbt parse`, `dbt build`, or `dbt docs generate`\n\nTypical layout:\n\n```text\nmy_orchestrator/\n  src/\n    my_orchestrator/\n      definitions.py\n  dbt/\n    jaffle_shop/\n      dbt_project.yml\n      models/\n      target/\n        manifest.json\n```\n\n## Load A dbt Project As Dagster Assets\n\nThe main pattern is `@dbt_assets(...)` plus a configured `DbtCliResource`.\n\n```python\nimport os\nfrom pathlib import Path\n\nimport dagster as dg\nfrom dagster_dbt import DbtCliResource, dbt_assets\n\nDBT_PROJECT_DIR = Path(__file__).resolve().parents[2] / \"dbt\" / \"jaffle_shop\"\nDBT_PROFILES_DIR = Path(os.environ.get(\"DBT_PROFILES_DIR\", DBT_PROJECT_DIR))\nDBT_MANIFEST_PATH = DBT_PROJECT_DIR / \"target\" / \"manifest.json\"\n\n\n@dbt_assets(manifest=DBT_MANIFEST_PATH)\ndef jaffle_shop_dbt_assets(\n    context: dg.AssetExecutionContext,\n    dbt: DbtCliResource,\n):\n    yield from dbt.cli([\"build\"], context=context).stream()\n\n\ndefs = dg.Definitions(\n    assets=[jaffle_shop_dbt_assets],\n    resources={\n        \"dbt\": DbtCliResource(\n            project_dir=DBT_PROJECT_DIR,\n            profiles_dir=DBT_PROFILES_DIR,\n        )\n    },\n)\n```\n\nWhy this shape matters:\n\n- `@dbt_assets(...)` turns dbt nodes from the manifest into Dagster assets.\n- `DbtCliResource` runs normal dbt CLI commands from Dagster.\n- `context=context` lets Dagster associate emitted events with the asset execution.\n- `manifest.json` is what Dagster reads to understand the dbt graph before execution starts.\n\n## Local Development Workflow\n\nIf your dbt profiles are stored with the project, export `DBT_PROFILES_DIR` and regenerate the manifest before starting Dagster:\n\n```bash\nexport DBT_PROFILES_DIR=\"$PWD/dbt/jaffle_shop\"\n\ndbt deps --project-dir dbt/jaffle_shop --profiles-dir \"$DBT_PROFILES_DIR\"\ndbt parse --project-dir dbt/jaffle_shop --profiles-dir \"$DBT_PROFILES_DIR\"\n\ndagster dev -m my_orchestrator.definitions\n```\n\nIf your profile already lives in `~/.dbt/profiles.yml`, you can usually omit `profiles_dir` from the resource configuration.\n\n## Common Workflows\n\n### Run only part of the dbt graph\n\nUse dbt selection both when loading assets and when invoking dbt so Dagster's asset graph and the dbt command stay aligned:\n\n```python\n@dbt_assets(\n    manifest=DBT_MANIFEST_PATH,\n    select=\"tag:daily\",\n)\ndef daily_dbt_assets(\n    context: dg.AssetExecutionContext,\n    dbt: DbtCliResource,\n):\n    yield from dbt.cli([\"build\", \"--select\", \"tag:daily\"], context=context).stream()\n```\n\n### Pass dbt CLI flags directly\n\n`DbtCliResource` executes real dbt CLI commands, so you can pass ordinary dbt flags such as `--target`:\n\n```python\nimport os\n\n@dbt_assets(manifest=DBT_MANIFEST_PATH)\ndef prod_dbt_assets(\n    context: dg.AssetExecutionContext,\n    dbt: DbtCliResource,\n):\n    target = os.environ.get(\"DBT_TARGET\", \"dev\")\n    yield from dbt.cli([\"build\", \"--target\", target], context=context).stream()\n```\n\n### Read dbt artifacts after a run\n\nKeep the invocation object if you need dbt artifacts such as `run_results.json`:\n\n```python\n@dbt_assets(manifest=DBT_MANIFEST_PATH)\ndef jaffle_shop_with_artifacts(\n    context: dg.AssetExecutionContext,\n    dbt: DbtCliResource,\n):\n    invocation = dbt.cli([\"build\"], context=context)\n    yield from invocation.stream()\n\n    run_results = invocation.get_artifact(\"run_results.json\")\n    context.log.info(f\"dbt produced {len(run_results['results'])} result entries\")\n```\n\n## Configuration And Environment\n\n`dagster-dbt` does not introduce a separate authentication system. Authentication belongs to dbt and the warehouse adapter you installed.\n\nIn practice:\n\n- keep warehouse credentials in `profiles.yml`\n- use environment variables referenced from `profiles.yml` for secrets\n- point Dagster at the profile directory with `DBT_PROFILES_DIR` or `profiles_dir=...`\n- keep the dbt project path stable and explicit with `project_dir=...`\n\nMinimal example using environment variables through your dbt profile:\n\n```yaml\n# profiles.yml\njaffle_shop:\n  target: dev\n  outputs:\n    dev:\n      type: duckdb\n      path: \"{{ env_var('DBT_DUCKDB_PATH', 'jaffle_shop.duckdb') }}\"\n      threads: 4\n```\n\n```bash\nexport DBT_DUCKDB_PATH=\"$PWD/dbt/jaffle_shop/jaffle_shop.duckdb\"\nexport DBT_PROFILES_DIR=\"$PWD/dbt/jaffle_shop\"\n```\n\n## Common Pitfalls\n\n- Missing or stale `manifest.json`. Re-run `dbt parse` or `dbt build` after changing models, sources, or packages.\n- Missing dbt adapter package. `DbtCliResource` shells out to `dbt`, so a usable adapter must already be installed.\n- Wrong profile directory. If Dagster cannot find `profiles.yml`, set `DBT_PROFILES_DIR` explicitly or pass `profiles_dir` to `DbtCliResource`.\n- Forgetting `context=context` in `dbt.cli(...)`. Pass the Dagster execution context when running dbt from asset functions.\n- Mismatched selection logic. If `@dbt_assets(select=...)` and the dbt CLI `--select` flags do not match, Dagster's loaded asset set and executed dbt nodes can drift apart.\n- Treating `dagster-dbt` as a replacement for dbt setup. You still need normal dbt project files, packages, profiles, and adapter configuration.\n\n## Version Notes For `0.28.18`\n\n- `dagster-dbt==0.28.18` belongs to the Dagster `1.12.18` release line; keep Dagster packages on the matching version line in the same environment.\n- For new code, prefer the `@dbt_assets(...)` plus `DbtCliResource` workflow shown in the current Dagster docs.\n- Runtime behavior still depends on the dbt CLI and adapter resolved in your environment, so keep your dbt adapter set consistent across local development and deployment.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-dbt\n- https://docs.dagster.io/api/python-api/libraries/dagster-dbt\n- https://docs.dagster.io/integrations/libraries/dbt\n- https://pypi.org/project/dagster-dbt/\n"
  },
  {
    "path": "content/dagster/docs/docker/python/DOC.md",
    "content": "---\nname: docker\ndescription: \"Dagster Docker integration for launching external containerized code with Pipes and running Dagster OSS runs in Docker containers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,docker,python,containers,pipes,orchestration\"\n---\n\n# `dagster-docker` for Python\n\nUse `dagster-docker` for two different workflows:\n\n- `PipesDockerClient` launches an external Docker container from a Dagster asset or op and streams logs, checks, and materializations back to Dagster.\n- `DockerRunLauncher` makes a Dagster OSS deployment launch each run in its own Docker container.\n\nThis guide targets `dagster-docker 0.28.18`. PyPI lists this release as requiring Python `>=3.10,<3.15`.\n\n## Install\n\nIf you want the exact release line covered here, pin Dagster core and the Docker integration together:\n\n```bash\npython -m pip install \"dagster==1.12.18\" \"dagster-docker==0.28.18\"\n```\n\nFor a local OSS deployment with the Dagster UI:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-docker==0.28.18\"\n```\n\nIf you use `PipesDockerClient`, the launched image also needs the package that provides `open_dagster_pipes`:\n\n```bash\npython -m pip install dagster-pipes\n```\n\n## Before You Configure It\n\n`dagster-docker` does not have its own auth flow. The important prerequisites are operational:\n\n- the Dagster process that launches containers must be able to talk to Docker Engine\n- the image you launch must already contain your code and Python dependencies\n- if the image is private, provide Docker registry credentials\n\nThe package creates Docker clients with `docker.client.from_env()`, and both the Pipes client and the run launcher accept a `registry` mapping with `url`, `username`, and `password`.\n\n## Launch External Containerized Code With `PipesDockerClient`\n\nThe current Dagster integration page for Docker centers on `PipesDockerClient`. This is the right starting point when your actual compute already runs well in a container and you want Dagster to orchestrate it without rewriting the workload into native Dagster ops.\n\n### Dagster-side asset\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_docker import PipesDockerClient\n\n\n@dg.asset\ndef docker_asset(\n    context: dg.AssetExecutionContext,\n    docker_pipes_client: PipesDockerClient,\n):\n    return docker_pipes_client.run(\n        context=context,\n        image=os.environ[\"DOCKER_ASSET_IMAGE\"],\n        command=[\"python\", \"/app/external_job.py\"],\n        extras={\"input_path\": \"/data/input/orders.json\"},\n        env={\n            \"APP_ENV\": os.getenv(\"APP_ENV\", \"dev\"),\n        },\n    ).get_results()\n\n\ndefs = dg.Definitions(\n    assets=[docker_asset],\n    resources={\n        \"docker_pipes_client\": PipesDockerClient(\n            registry={\n                \"url\": os.environ[\"DOCKER_REGISTRY_URL\"],\n                \"username\": os.environ[\"DOCKER_REGISTRY_USERNAME\"],\n                \"password\": os.environ[\"DOCKER_REGISTRY_PASSWORD\"],\n            }\n        ),\n    },\n)\n```\n\nSuggested environment variables for the Dagster process:\n\n```bash\nexport DOCKER_ASSET_IMAGE=\"ghcr.io/acme/orders-job:2026-03-13\"\nexport DOCKER_REGISTRY_URL=\"ghcr.io\"\nexport DOCKER_REGISTRY_USERNAME=\"my-user\"\nexport DOCKER_REGISTRY_PASSWORD=\"my-token\"\nexport APP_ENV=\"prod\"\n```\n\nImportant behavior from the package source:\n\n- `run(...)` accepts `image`, `command`, `extras`, `env`, `registry`, and `container_kwargs`\n- the client logs in to the registry if `registry` is set\n- if the image is missing locally, it tries `docker pull`\n- the container is treated as failed if it exits with a non-zero status code\n\n### Code inside the launched container\n\nYour containerized process uses `dagster-pipes` to receive context and report results:\n\n```python\nfrom dagster_pipes import open_dagster_pipes\n\n\ndef main() -> None:\n    with open_dagster_pipes() as pipes:\n        input_path = pipes.get_extra(\"input_path\")\n        pipes.log.info(f\"Processing {input_path}\")\n\n        row_count = 42\n\n        pipes.report_asset_materialization(\n            metadata={\n                \"row_count\": {\"raw_value\": row_count, \"type\": \"int\"},\n            }\n        )\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\nUse `extras` for normal runtime parameters. If you need Docker-specific container settings such as labels, mounts, or other `containers.create(...)` options, pass them with `container_kwargs`.\n\n## Launch Each OSS Run In Its Own Container With `DockerRunLauncher`\n\nUse `DockerRunLauncher` when you want Dagster OSS to execute a full run in a fresh Docker container instead of inside the webserver or daemon process.\n\nArchived Dagster deployment docs show the canonical `dagster.yaml` shape:\n\n```yaml\n# $DAGSTER_HOME/dagster.yaml\nrun_launcher:\n  module: dagster_docker\n  class: DockerRunLauncher\n  config:\n    env_vars:\n      - DAGSTER_POSTGRES_USER\n      - DAGSTER_POSTGRES_PASSWORD\n      - DAGSTER_POSTGRES_DB\n    container_kwargs:\n      volumes:\n        - /absolute/path/to/project:/opt/dagster/app\n```\n\nIn that deployment model, the run launcher uses the image attached to the code location. The archived Docker deployment guide describes this as the image stored in `DAGSTER_CURRENT_IMAGE` on the user-code container.\n\nExample user-code container environment:\n\n```bash\nexport DAGSTER_HOME=/opt/dagster/dagster_home\nexport DAGSTER_CURRENT_IMAGE=\"ghcr.io/acme/dagster-user-code:2026-03-13\"\nexport DAGSTER_POSTGRES_USER=\"dagster\"\nexport DAGSTER_POSTGRES_PASSWORD=\"secret\"\nexport DAGSTER_POSTGRES_DB=\"dagster\"\n```\n\nYou can also set launcher-level Docker options that are supported by the package source:\n\n- `image` as a fallback if the code location does not provide a container image\n- `registry` for private image pulls\n- `network` or `networks` for Docker network attachment\n- `container_kwargs` for extra Docker container settings\n\n## Common Pitfalls\n\n- `PipesDockerClient` and `DockerRunLauncher` both need Docker access from the process that starts containers. In OSS deployments, the archived Docker guide calls out mounting `/var/run/docker.sock` as one way to grant that access.\n- The launched image must already contain your code. `dagster-docker` can pull an image, but it does not build images for you.\n- If you use `DockerRunLauncher` with bind mounts in the user-code container, repeat those mounts in `container_kwargs` for launched run containers or your code path will not exist there.\n- `DockerRunLauncher` needs a container image from either the code location or the launcher config. If neither is set, run launch fails.\n- Keep related Dagster packages on the same release line. For this guide that means `dagster-docker 0.28.18` with `dagster 1.12.18`.\n\n## Version Notes For `0.28.18`\n\n- PyPI lists `dagster-docker 0.28.18` as released on March 5, 2026.\n- PyPI lists Python support for this release as `>=3.10,<3.15`.\n- Dagster core and Dagster integration packages use different visible version numbers in the same release train. On the same March 5, 2026 release line, PyPI lists `dagster 1.12.18` and `dagster-docker 0.28.18`.\n- The current Docker integration page in Dagster docs is focused on `PipesDockerClient`; for OSS deployment details such as `DockerRunLauncher` configuration and bind-mount behavior, the official archived Docker deployment guide is still the clearest maintainer reference.\n\n## Official Sources Used\n\n- Dagster Docker integration page: https://docs.dagster.io/integrations/libraries/docker\n- Dagster Docker deployment guide archive: https://release-1-5-9.dagster.dagster-docs.io/deployment/guides/docker\n- `dagster-docker` package source: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-docker\n- `DockerRunLauncher` source: https://raw.githubusercontent.com/dagster-io/dagster/master/python_modules/libraries/dagster-docker/dagster_docker/docker_run_launcher.py\n- `PipesDockerClient` source: https://raw.githubusercontent.com/dagster-io/dagster/master/python_modules/libraries/dagster-docker/dagster_docker/pipes.py\n- Dagster Pipes overview: https://dagster.io/blog/dagster-pipes\n- `dagster-docker` on PyPI: https://pypi.org/project/dagster-docker/\n- `dagster` on PyPI: https://pypi.org/project/dagster/\n"
  },
  {
    "path": "content/dagster/docs/duckdb/python/DOC.md",
    "content": "---\nname: duckdb\ndescription: \"Dagster DuckDB integration for querying DuckDB from assets and storing asset tables in DuckDB\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,duckdb,python,database,assets,io-manager\"\n---\n\n# dagster-duckdb\n\nUse `dagster-duckdb` when a Dagster project needs a DuckDB connection inside assets or ops, or when you want DuckDB-backed asset storage through Dagster I/O managers.\n\nThis guide targets `dagster-duckdb 0.28.18`, which is in the Dagster `1.12.18` release line.\n\n## Install\n\nInstall the DuckDB integration alongside the matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-duckdb==0.28.18\"\n```\n\nIf you want the ready-made Pandas I/O manager shown below, install the `pandas` extra:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-duckdb[pandas]==0.28.18\"\n```\n\nPyPI currently lists `dagster-duckdb` as requiring Python `>=3.10,<3.15`.\n\n## Configure The Database Path\n\nThis package does not have a separate auth flow. You point it at a DuckDB database path and Dagster opens connections for you.\n\nCommon local setup:\n\n```bash\nexport DUCKDB_DATABASE=\"$PWD/storage/analytics.duckdb\"\nexport DUCKDB_SCHEMA=\"analytics\"\nmkdir -p \"$(dirname \"$DUCKDB_DATABASE\")\"\n```\n\nIf you set `database=\":memory:\"`, Dagster uses an in-memory DuckDB database instead of a file-backed one.\n\n## Query DuckDB With `DuckDBResource`\n\n`DuckDBResource` is the simplest way to execute SQL from an asset or op.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_duckdb import DuckDBResource\n\n\n@dg.asset\ndef create_orders_table(duckdb: DuckDBResource) -> None:\n    with duckdb.get_connection() as conn:\n        conn.execute(\n            \"\"\"\n            create schema if not exists analytics;\n            create or replace table analytics.orders as\n            select 1 as order_id, 42.50 as total\n            union all\n            select 2 as order_id, 19.99 as total\n            \"\"\"\n        )\n\n\n@dg.asset(deps=[create_orders_table])\ndef order_count(duckdb: DuckDBResource) -> int:\n    with duckdb.get_connection() as conn:\n        row = conn.execute(\n            \"select count(*) from analytics.orders\"\n        ).fetchone()\n    return int(row[0])\n\n\ndefs = dg.Definitions(\n    assets=[create_orders_table, order_count],\n    resources={\n        \"duckdb\": DuckDBResource(\n            database=os.environ[\"DUCKDB_DATABASE\"],\n        ),\n    },\n)\n```\n\nUse `connection_config` when you need DuckDB connection options:\n\n```python\nDuckDBResource(\n    database=os.environ[\"DUCKDB_DATABASE\"],\n    connection_config={\"arrow_large_buffer_size\": True},\n)\n```\n\n## Store DataFrame Assets In DuckDB\n\nFor table-backed assets, Dagster's DuckDB integration is usually paired with a typed I/O manager. The official Dagster integration example for Pandas uses `DuckDBPandasIOManager`.\n\n```python\nimport os\n\nimport dagster as dg\nimport pandas as pd\nfrom dagster_duckdb_pandas import DuckDBPandasIOManager\n\n\n@dg.asset(key_prefix=[\"analytics\"])\ndef orders() -> pd.DataFrame:\n    return pd.DataFrame(\n        [\n            {\"order_id\": 1, \"total\": 42.50},\n            {\"order_id\": 2, \"total\": 19.99},\n        ]\n    )\n\n\n@dg.asset(\n    ins={\"orders\": dg.AssetIn(metadata={\"columns\": [\"order_id\"]})}\n)\ndef order_ids(orders: pd.DataFrame) -> pd.DataFrame:\n    return orders\n\n\ndefs = dg.Definitions(\n    assets=[orders, order_ids],\n    resources={\n        \"io_manager\": DuckDBPandasIOManager(\n            database=os.environ[\"DUCKDB_DATABASE\"],\n            schema=os.environ.get(\"DUCKDB_SCHEMA\", \"analytics\"),\n        )\n    },\n)\n```\n\nImportant behavior:\n\n- Asset tables use the asset key for their table name and schema.\n- A configured I/O manager `schema=` sets the default schema.\n- Asset `metadata={\"schema\": \"...\"}` overrides `key_prefix`.\n- If no schema is set anywhere, the DuckDB I/O manager defaults to `public`.\n- `AssetIn(..., metadata={\"columns\": [...]})` loads only those columns from the upstream table.\n\nFor op outputs instead of assets, set schema metadata on the output:\n\n```python\nimport dagster as dg\n\n\n@dg.op(out={\"orders\": dg.Out(metadata={\"schema\": \"analytics\"})})\ndef build_orders() -> list[dict]:\n    return [{\"order_id\": 1, \"total\": 42.50}]\n```\n\n## When To Use The Base I/O Manager API\n\n`dagster-duckdb` provides the base `DuckDBIOManager` class and `build_duckdb_io_manager(...)` helper for custom type handlers.\n\nUse that layer when:\n\n- you want DuckDB-backed storage for a type other than the built-in companion integrations\n- you need a custom default load type\n- you are standardizing one DuckDB I/O manager implementation for your own project\n\nIf you only need Pandas or PySpark support, prefer the packaged integrations and matching extras instead of building your own type handlers first.\n\n## Common Pitfalls\n\n- Keep the release line aligned. `dagster-duckdb 0.28.18` belongs with Dagster `1.12.18`.\n- `dagster-duckdb` gives you the DuckDB resource and base I/O manager APIs. For a ready-made Pandas or PySpark table handler, install the matching extras or companion package.\n- The DuckDB I/O manager overwrites previous materializations for the same asset table.\n- Schema selection is easy to misread: asset metadata wins over `key_prefix`, and both override the I/O manager default schema.\n- `connection_config` is passed through to DuckDB connection options. Keep those settings consistent anywhere the same Dagster definitions run.\n\n## Official Sources\n\n- https://docs.dagster.io/api/duckdb\n- https://dagster.io/integrations/dagster-duckdb\n- https://raw.githubusercontent.com/dagster-io/dagster/master/python_modules/libraries/dagster-duckdb/dagster_duckdb/resource.py\n- https://raw.githubusercontent.com/dagster-io/dagster/master/python_modules/libraries/dagster-duckdb/dagster_duckdb/io_manager.py\n- https://pypi.org/project/dagster-duckdb/\n- https://pypi.org/project/dagster/\n"
  },
  {
    "path": "content/dagster/docs/fivetran/python/DOC.md",
    "content": "---\nname: fivetran\ndescription: \"dagster-fivetran package guide for triggering Fivetran connector syncs and modeling connector tables as Dagster assets\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,fivetran,dagster-fivetran,python,data-orchestration,etl,assets\"\n---\n\n# dagster-fivetran Python Package Guide\n\n## Golden Rule\n\nUse `dagster-fivetran` as Dagster's orchestration layer for connectors that are already configured in Fivetran. Create and verify the connector in Fivetran first, then represent the connector's destination tables in Dagster and authenticate with a `FivetranResource` using Fivetran API credentials.\n\n## Install\n\nInstall `dagster-fivetran` on the matching Dagster release line:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-fivetran==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-fivetran\n```\n\n## Prerequisites\n\nBefore wiring `dagster-fivetran` into a project, make sure you already have:\n\n- a Dagster project with a loadable top-level `defs = dg.Definitions(...)`\n- a working Fivetran account and a connector that already syncs successfully in Fivetran\n- a Fivetran API key and API secret with permission to read connector state and trigger syncs\n- the connector's stable connector ID\n- the destination tables you want Dagster to represent as assets\n\n## Configure Credentials\n\nKeep Fivetran credentials in environment variables instead of hard-coding them into Dagster definitions:\n\n```bash\nexport FIVETRAN_API_KEY=\"your_fivetran_api_key\"\nexport FIVETRAN_API_SECRET=\"your_fivetran_api_secret\"\nexport FIVETRAN_CONNECTOR_ID=\"your_connector_id\"\n```\n\nIf you manage multiple connectors, give each connector its own environment variable instead of reusing one generic ID.\n\n## Model A Connector As Dagster Assets\n\nThe main package pattern is a configured `FivetranResource` plus `build_fivetran_assets(...)` for each connector you want to orchestrate.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_fivetran import FivetranResource, build_fivetran_assets\n\nCONNECTOR_ID = os.environ[\"FIVETRAN_CONNECTOR_ID\"]\n\nmarketing_connector_assets = build_fivetran_assets(\n    connector_id=CONNECTOR_ID,\n    destination_tables=[\n        \"public.accounts\",\n        \"public.contacts\",\n        \"public.opportunities\",\n    ],\n)\n\ndefs = dg.Definitions(\n    assets=[marketing_connector_assets],\n    resources={\n        \"fivetran\": FivetranResource(\n            api_key=dg.EnvVar(\"FIVETRAN_API_KEY\"),\n            api_secret=dg.EnvVar(\"FIVETRAN_API_SECRET\"),\n        ),\n    },\n)\n```\n\nWhy this shape matters:\n\n- `build_fivetran_assets(...)` tells Dagster which connector and destination tables belong together.\n- `FivetranResource(...)` is the authenticated handle Dagster uses for Fivetran API calls.\n- the resource key `fivetran` must match what the generated asset definition expects\n- the `destination_tables` list should match the tables that Fivetran writes in the destination warehouse\n\n## Add More Than One Connector\n\nCreate one asset definition per connector, then register them together in `Definitions`.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_fivetran import FivetranResource, build_fivetran_assets\n\nsalesforce_assets = build_fivetran_assets(\n    connector_id=os.environ[\"FIVETRAN_SALESFORCE_CONNECTOR_ID\"],\n    destination_tables=[\"public.accounts\", \"public.contacts\"],\n)\n\nstripe_assets = build_fivetran_assets(\n    connector_id=os.environ[\"FIVETRAN_STRIPE_CONNECTOR_ID\"],\n    destination_tables=[\"public.balance_transactions\", \"public.charges\"],\n)\n\ndefs = dg.Definitions(\n    assets=[salesforce_assets, stripe_assets],\n    resources={\n        \"fivetran\": FivetranResource(\n            api_key=dg.EnvVar(\"FIVETRAN_API_KEY\"),\n            api_secret=dg.EnvVar(\"FIVETRAN_API_SECRET\"),\n        )\n    },\n)\n```\n\nThis keeps each connector explicit and avoids coupling unrelated connectors into one large definition.\n\n## Local Development Workflow\n\nWith credentials exported and definitions in place, validate the Dagster definitions and start the local UI:\n\n```bash\ndg check defs\ndg dev -m my_project.definitions\n```\n\nUse the Dagster UI to materialize the Fivetran-backed assets. That will trigger the connector sync through the configured resource.\n\n## Common Pitfalls\n\n- Keep Dagster package versions aligned. `dagster-fivetran 0.28.18` belongs on the Dagster `1.12.18` release line.\n- Use the Fivetran connector ID, not the connector display name, when setting `connector_id=`.\n- Keep the `destination_tables` list in sync with the actual tables Fivetran writes. If the connector schema changes, update the Dagster definition too.\n- Treat Fivetran credentials as secrets. Do not hard-code them into `Definitions`, schedules, or checked-in config files.\n- Make sure the runtime environment that starts Dagster can import `dagster_fivetran` and can see the same Fivetran credentials you used during local setup.\n- `dagster-fivetran` orchestrates Fivetran syncs and asset metadata in Dagster; it does not replace the normal connector configuration you manage in Fivetran itself.\n\n## Version Notes For `0.28.18`\n\n- `dagster-fivetran==0.28.18` matches the Dagster `1.12.18` release line, so pin related Dagster packages together.\n- If you upgrade Dagster core or the webserver package, upgrade `dagster-fivetran` on the same release line instead of changing it in isolation.\n\n## Official Sources\n\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-fivetran`\n- `https://docs.dagster.io/api/python-api/libraries/dagster-fivetran`\n- `https://docs.dagster.io/integrations/libraries/fivetran`\n- `https://pypi.org/project/dagster-fivetran/`\n"
  },
  {
    "path": "content/dagster/docs/gcp/python/DOC.md",
    "content": "---\nname: gcp\ndescription: \"dagster-gcp package guide for using Dagster with Google Cloud Storage and BigQuery resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,gcp,dagster-gcp,python,gcs,bigquery,data-orchestration\"\n---\n\n# dagster-gcp Python Package Guide\n\n## Golden Rule\n\nUse `dagster-gcp` as Dagster's integration layer for Google Cloud services, but keep authentication and authorization in standard Google Cloud credential flows. Install `dagster-gcp` on the matching Dagster release line, configure Google Cloud credentials through Application Default Credentials (ADC) or a service account, and inject Dagster resources into assets and ops instead of constructing ad-hoc clients everywhere.\n\nFor most projects, the lowest-friction starting point is the direct resource pattern: configure a resource in `dg.Definitions(...)`, receive it as a parameter in an asset, and call the underlying Google Cloud client for reads and writes.\n\n## Install\n\nInstall `dagster-gcp` alongside the matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-gcp==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-gcp\n```\n\n## Prerequisites\n\nBefore wiring `dagster-gcp` into a project, make sure you already have:\n\n- a Dagster project with a loadable top-level `defs = dg.Definitions(...)`\n- the Google Cloud APIs enabled for the services you actually use, such as Cloud Storage or BigQuery\n- Google Cloud credentials available through ADC or `GOOGLE_APPLICATION_CREDENTIALS`\n- a target project ID, plus any bucket, dataset, or table names your assets need\n- IAM permissions for the exact Storage and BigQuery operations your code performs\n\n## Configure Google Cloud Credentials\n\n`dagster-gcp` relies on normal Google Cloud authentication behavior from the underlying client libraries.\n\nFor local development, ADC is the simplest setup:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nService account JSON fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nOn GCP runtimes such as Cloud Run, GKE, or Compute Engine, ADC usually comes from the attached service account. In that case, keep `GOOGLE_CLOUD_PROJECT` set when project discovery would otherwise be ambiguous.\n\n## Use `GCSResource` In Assets\n\nUse `GCSResource` when an asset needs the Google Cloud Storage Python client.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_gcp.gcs import GCSResource\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nBUCKET = os.environ[\"GCS_BUCKET\"]\nKEY = \"examples/hello.txt\"\n\n\n@dg.asset\ndef write_example_file(gcs: GCSResource) -> str:\n    client = gcs.get_client()\n    bucket = client.bucket(BUCKET)\n    blob = bucket.blob(KEY)\n    blob.upload_from_string(\n        \"hello from dagster-gcp\\n\",\n        content_type=\"text/plain\",\n    )\n    return f\"gs://{BUCKET}/{KEY}\"\n\n\n@dg.asset(deps=[write_example_file])\ndef read_example_file(gcs: GCSResource) -> str:\n    client = gcs.get_client()\n    bucket = client.bucket(BUCKET)\n    blob = bucket.blob(KEY)\n    return blob.download_as_text()\n\n\ndefs = dg.Definitions(\n    assets=[write_example_file, read_example_file],\n    resources={\n        \"gcs\": GCSResource(project=PROJECT_ID),\n    },\n)\n```\n\nImportant details:\n\n- the resource key in `resources={\"gcs\": ...}` must match the asset parameter name `gcs`\n- the underlying Storage client still uses normal Google Cloud IAM, so the runtime identity needs permission for the bucket and object operations you call\n- when project inference is unreliable, pass `project=` explicitly and keep `GOOGLE_CLOUD_PROJECT` set in the environment\n\n## Use `BigQueryResource` For Queries\n\nUse `BigQueryResource` when an asset or op needs the BigQuery Python client.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_gcp.bigquery import BigQueryResource\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nDATASET = os.environ[\"BIGQUERY_DATASET\"]\n\n\n@dg.asset\ndef recent_events(bigquery: BigQueryResource) -> list[dict]:\n    client = bigquery.get_client()\n    query = f\"\"\"\n    SELECT user_id, event_type, event_time\n    FROM `{PROJECT_ID}.{DATASET}.events`\n    ORDER BY event_time DESC\n    LIMIT 10\n    \"\"\"\n    rows = client.query(query).result()\n    return [dict(row.items()) for row in rows]\n\n\ndefs = dg.Definitions(\n    assets=[recent_events],\n    resources={\n        \"bigquery\": BigQueryResource(project=PROJECT_ID),\n    },\n)\n```\n\nKeep the BigQuery job location aligned with the datasets you query. If your environment spans multiple locations, do not assume the default location will always be correct.\n\n## Local Development Workflow\n\nValidate the Dagster definitions before starting the UI:\n\n```bash\ndg check defs\n```\n\nThen run your local Dagster instance:\n\n```bash\ndg dev -m my_project.definitions\n```\n\nThis is usually enough for local iteration when your Google Cloud credentials are already available through ADC or a service account.\n\n## Common Pitfalls\n\n- Keep Dagster package versions aligned. `dagster-gcp 0.28.18` belongs on the Dagster `1.12.18` release line.\n- Do not assume `dagster-gcp` bypasses Google Cloud IAM. The runtime identity still needs the right Storage and BigQuery permissions.\n- Resource injection is name-based. The resource dictionary key must match the function parameter name used in the asset or op.\n- BigQuery jobs are location-sensitive. A dataset and a query job in different locations can fail even when credentials and SQL are otherwise correct.\n- Set `GOOGLE_CLOUD_PROJECT` when project discovery is ambiguous, especially in local shells and CI.\n- Keep service account keys out of source control and out of constant Dagster config values.\n\n## Version Notes For `0.28.18`\n\n- `dagster-gcp==0.28.18` matches the Dagster `1.12.18` release line, so pin related Dagster packages together.\n- Authentication and client behavior come from the underlying Google Cloud Python clients, so deployment behavior can differ between local shells, CI, containers, and GCP runtimes depending on which ADC source is available.\n\n## Official Sources\n\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-gcp`\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-gcp/dagster_gcp/gcs`\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-gcp/dagster_gcp/bigquery`\n- `https://docs.dagster.io/api/python-api/libraries/dagster-gcp`\n- `https://cloud.google.com/docs/authentication/application-default-credentials`\n- `https://cloud.google.com/python/docs/reference/storage/latest`\n- `https://cloud.google.com/python/docs/reference/bigquery/latest`\n- `https://pypi.org/project/dagster-gcp/`\n"
  },
  {
    "path": "content/dagster/docs/graphql/python/DOC.md",
    "content": "---\nname: graphql\ndescription: \"Dagster GraphQL Python client for launching jobs, checking run state, reloading code locations, and sending GraphQL requests to Dagster\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,graphql,python,orchestration,jobs,runs\"\n---\n\n# Dagster GraphQL Python Package Guide\n\n## Golden Rule\n\nInstall `dagster-graphql` and `dagster` at the same version, point the client at a Dagster webserver host, and let the client add `/graphql` for you. The packaged Python client is synchronous and wraps a small set of common operations: submit a job run, check run status, reload a code location, and terminate runs.\n\n## Install\n\nUse a virtual environment and pin `dagster` plus `dagster-graphql` together:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"dagster==1.12.18\" \"dagster-graphql==1.12.18\"\n```\n\nIf your project already pins Dagster, keep `dagster-graphql` on the exact same release.\n\n## Initialize The Client\n\n### Local Dagster webserver\n\nSet environment variables for the host and port exposed by `dagster-webserver`:\n\n```bash\nexport DAGSTER_HOST=localhost\nexport DAGSTER_PORT=3000\n```\n\n```python\nimport os\n\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\n    hostname=os.getenv(\"DAGSTER_HOST\", \"localhost\"),\n    port_number=int(os.getenv(\"DAGSTER_PORT\", \"3000\")),\n    use_https=False,\n    timeout=300,\n)\n```\n\nPass only the host and optional port. Do not pass a full GraphQL URL such as `http://localhost:3000/graphql`; the client always appends `/graphql` internally.\n\n### Dagster Cloud\n\nThe client accepts arbitrary headers. For Dagster Cloud, use the `Dagster-Cloud-Api-Token` header:\n\n```bash\nexport DAGSTER_CLOUD_HOST=\"your-org.dagster.cloud\"\nexport DAGSTER_CLOUD_API_TOKEN=\"your-user-token\"\n```\n\n```python\nimport os\n\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\n    hostname=os.environ[\"DAGSTER_CLOUD_HOST\"],\n    use_https=True,\n    timeout=300,\n    headers={\"Dagster-Cloud-Api-Token\": os.environ[\"DAGSTER_CLOUD_API_TOKEN\"]},\n)\n```\n\n### Custom HTTP auth\n\nIf your Dagster deployment sits behind HTTP auth, pass a `requests` auth object:\n\n```python\nfrom requests.auth import HTTPBasicAuth\n\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\n    hostname=\"dagster.internal.example\",\n    use_https=True,\n    auth=HTTPBasicAuth(\"api-user\", \"api-password\"),\n)\n```\n\n## Launch A Job Run\n\nUse `submit_job_execution()` for the normal automation flow:\n\n```python\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\"localhost\", port_number=3000)\n\nrun_id = client.submit_job_execution(\n    job_name=\"daily_assets\",\n    repository_location_name=\"analytics\",\n    repository_name=\"prod_repo\",\n    run_config={},\n    tags={\"trigger\": \"api\", \"env\": \"dev\"},\n)\n\nprint(run_id)\n```\n\nIf the job name is unique across the deployment, `repository_location_name` and `repository_name` can be omitted. If the same job name exists in multiple repositories or code locations, the client raises an error until you supply both values explicitly.\n\n### Run a subset of ops or assets\n\nThe client also accepts `op_selection` and `asset_selection`:\n\n```python\nrun_id = client.submit_job_execution(\n    job_name=\"daily_assets\",\n    repository_location_name=\"analytics\",\n    repository_name=\"prod_repo\",\n    run_config={},\n    op_selection=[\"extract_customers\", \"build_metrics\"],\n    asset_selection=[[\"customers\"], [\"metrics\", \"daily\"]],\n)\n```\n\n`run_config` is passed through to Dagster as GraphQL execution params. It must match the target job's run config schema.\n\n## Poll Run Status\n\n`get_run_status()` returns a `DagsterRunStatus` enum from `dagster`:\n\n```python\nimport time\n\nfrom dagster import DagsterRunStatus\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\"localhost\", port_number=3000)\nrun_id = \"YOUR_RUN_ID\"\n\nterminal_states = {\n    DagsterRunStatus.SUCCESS,\n    DagsterRunStatus.FAILURE,\n    DagsterRunStatus.CANCELED,\n}\n\nwhile True:\n    status = client.get_run_status(run_id)\n    print(status.value)\n    if status in terminal_states:\n        break\n    time.sleep(5)\n```\n\n## Reload A Code Location\n\nUse `reload_repository_location()` when you want Dagster to reload repository metadata without restarting the whole webserver:\n\n```python\nfrom dagster_graphql import (\n    DagsterGraphQLClient,\n    ReloadRepositoryLocationStatus,\n)\n\nclient = DagsterGraphQLClient(\"localhost\", port_number=3000)\n\ninfo = client.reload_repository_location(\"analytics\")\n\nif info.status is ReloadRepositoryLocationStatus.SUCCESS:\n    print(\"Reloaded\")\nelse:\n    print(info.failure_type, info.message)\n```\n\n## Terminate One Or Many Runs\n\n```python\nfrom dagster_graphql import DagsterGraphQLClient\n\nclient = DagsterGraphQLClient(\"localhost\", port_number=3000)\n\nclient.terminate_run(\"RUN_ID\")\nclient.terminate_runs([\"RUN_ID_1\", \"RUN_ID_2\"])\n```\n\n`terminate_runs()` raises a `DagsterGraphQLClientError` if some or all requested terminations fail.\n\n## Error Handling\n\nThe client raises `DagsterGraphQLClientError` for GraphQL and transport problems. The exception arguments usually carry the GraphQL type name plus a message, and `exc.body` may contain structured details.\n\n```python\nfrom dagster_graphql import DagsterGraphQLClient, DagsterGraphQLClientError\n\nclient = DagsterGraphQLClient(\"localhost\", port_number=3000)\n\ntry:\n    run_id = client.submit_job_execution(\n        job_name=\"daily_assets\",\n        repository_location_name=\"analytics\",\n        repository_name=\"prod_repo\",\n        run_config={},\n    )\nexcept DagsterGraphQLClientError as exc:\n    error_type = exc.args[0] if exc.args else type(exc).__name__\n    detail = exc.body if exc.body is not None else (exc.args[1] if len(exc.args) > 1 else \"\")\n    raise RuntimeError(f\"{error_type}: {detail}\") from exc\n```\n\nCommon failures to expect from the packaged client:\n\n- invalid job or repository identifiers\n- run config validation errors returned by GraphQL\n- duplicate job names across repositories when repository details are omitted\n- `RunNotFoundError` when polling or terminating an unknown run ID\n- connection and server errors when the target webserver is unavailable\n\n## Send Raw GraphQL For Unwrapped Operations\n\nThe Python client only wraps a small subset of the Dagster GraphQL API. For anything else, send a normal JSON GraphQL POST to `/graphql`.\n\nThis example uses the same run-status query shape shipped inside the package:\n\n```bash\nexport DAGSTER_BASE_URL=\"http://localhost:3000\"\n```\n\n```python\nimport os\n\nimport requests\n\nquery = \"\"\"\nquery GraphQLClientGetRunStatus($runId: ID!) {\n  pipelineRunOrError(runId: $runId) {\n    __typename\n    ... on PipelineRun {\n      status\n    }\n    ... on PipelineRunNotFoundError {\n      message\n    }\n    ... on PythonError {\n      message\n    }\n  }\n}\n\"\"\"\n\nresponse = requests.post(\n    f\"{os.environ['DAGSTER_BASE_URL'].rstrip('/')}/graphql\",\n    json={\"query\": query, \"variables\": {\"runId\": \"YOUR_RUN_ID\"}},\n    timeout=300,\n)\nresponse.raise_for_status()\n\npayload = response.json()\nprint(payload)\n```\n\nIf the deployment requires auth, add the same headers or auth settings you would use when constructing `DagsterGraphQLClient`.\n\n## CLI Usage\n\nInstalling `dagster-graphql` also installs a `dagster-graphql` CLI for executing GraphQL text, files, or a small predefined query set.\n\nRun a query against a remote Dagster webserver:\n\n```bash\ndagster-graphql \\\n  --remote http://localhost:3000 \\\n  --text 'query GraphQLClientGetRunStatus($runId: ID!) { pipelineRunOrError(runId: $runId) { __typename ... on PipelineRun { status } ... on PipelineRunNotFoundError { message } ... on PythonError { message } } }' \\\n  --variables '{\"runId\": \"YOUR_RUN_ID\"}'\n```\n\n## Common Pitfalls\n\n- Keep `dagster` and `dagster-graphql` on the same version; the package metadata pins them together.\n- Pass a host, not a full `/graphql` URL, to `DagsterGraphQLClient`.\n- The packaged client is synchronous. If you need concurrent polling or fan-out, add your own threading or async boundary around it.\n- Omitted repository details only work when the job name is unique across the deployment.\n- `run_config` is not validated locally before the request; schema errors come back from Dagster as GraphQL client errors.\n- `shutdown_repository_location()` still exists in the client, but it is marked deprecated for Dagster 2.0. Prefer reload unless you specifically want the code-location server to exit and restart.\n- The GraphQL schema and some error names still use older `pipeline` terminology. In current automation code, prefer `submit_job_execution()` and job-oriented naming.\n\n## Version-Sensitive Notes For 1.12.x\n\n- The 1.12.x package line is version-locked to the matching `dagster` release.\n- `shutdown_repository_location()` is already marked deprecated with a breaking version of `2.0`.\n- The installed client targets the `/graphql` HTTP endpoint and does not expose the full schema as first-class Python methods; reaching new GraphQL surfaces usually means posting raw queries.\n\n## Official Sources\n\n- Dagster GraphQL API docs: https://docs.dagster.io/api/graphql\n- `dagster-graphql` PyPI page: https://pypi.org/project/dagster-graphql/\n- Maintainer package source: https://github.com/dagster-io/dagster/tree/master/python_modules/dagster-graphql\n"
  },
  {
    "path": "content/dagster/docs/k8s/python/DOC.md",
    "content": "---\nname: k8s\ndescription: \"Dagster Kubernetes integration for launching runs and steps as Kubernetes Jobs in Dagster OSS\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,kubernetes,k8s,python,orchestration,executor\"\n---\n\n# dagster-k8s\n\nUse `dagster-k8s` when your Dagster OSS deployment should execute work on Kubernetes instead of only in the webserver or daemon process. The package primarily gives you two integration points:\n\n- `K8sRunLauncher` to launch an entire Dagster run as a Kubernetes Job\n- `k8s_job_executor` to launch individual job steps as Kubernetes Jobs\n\nThis guide targets `dagster-k8s 0.28.18`, which belongs to the Dagster `1.12.18` release line.\n\n## Install\n\nInstall `dagster-k8s` alongside the matching Dagster packages used by your deployment:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-k8s==0.28.18\" \\\n  \"dagster-webserver==1.12.18\"\n```\n\nIf you run `dagster-daemon`, install the same package set there too. Keep the Dagster release line aligned; do not mix `dagster-k8s 0.28.18` with an unrelated Dagster core version.\n\n## Before You Configure It\n\nYou need:\n\n- a Kubernetes cluster and namespace where Dagster can create Jobs and Pods\n- a service account with permission to create, watch, and delete Jobs and Pods in that namespace\n- a container image that already contains your Dagster code location and Python dependencies\n- a shared Dagster instance configuration that launched run workers can read\n\nExample shell setup:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nmkdir -p \"$DAGSTER_HOME\"\n\nexport DAGSTER_K8S_NAMESPACE=\"dagster\"\nexport DAGSTER_K8S_SERVICE_ACCOUNT=\"dagster\"\nexport DAGSTER_K8S_JOB_IMAGE=\"ghcr.io/example/dagster-user-code:latest\"\nexport DAGSTER_INSTANCE_CONFIG_MAP=\"dagster-instance\"\n```\n\nCreate the namespace and a service account if they do not already exist:\n\n```bash\nkubectl create namespace \"$DAGSTER_K8S_NAMESPACE\"\nkubectl -n \"$DAGSTER_K8S_NAMESPACE\" create serviceaccount \"$DAGSTER_K8S_SERVICE_ACCOUNT\"\n```\n\nIf your Dagster instance config lives in `$DAGSTER_HOME/dagster.yaml`, make it available to launched workers through a ConfigMap:\n\n```bash\nkubectl -n \"$DAGSTER_K8S_NAMESPACE\" create configmap \"$DAGSTER_INSTANCE_CONFIG_MAP\" \\\n  --from-file=dagster.yaml=\"$DAGSTER_HOME/dagster.yaml\"\n```\n\n`dagster-k8s` does not have a separate SDK auth flow. Kubernetes authentication comes from the runtime environment:\n\n- in cluster, Dagster usually uses the pod's service account\n- outside the cluster, configure Kubernetes access with your kubeconfig and the launcher's `kubeconfig_file` setting when needed\n\n## Launch Entire Runs With `K8sRunLauncher`\n\nUse `K8sRunLauncher` when each Dagster run should execute in its own Kubernetes Job.\n\nExample `$DAGSTER_HOME/dagster.yaml`:\n\n```yaml\n# $DAGSTER_HOME/dagster.yaml\nrun_launcher:\n  module: dagster_k8s.launcher\n  class: K8sRunLauncher\n  config:\n    job_image:\n      env: DAGSTER_K8S_JOB_IMAGE\n    job_namespace:\n      env: DAGSTER_K8S_NAMESPACE\n    service_account_name:\n      env: DAGSTER_K8S_SERVICE_ACCOUNT\n    instance_config_map:\n      env: DAGSTER_INSTANCE_CONFIG_MAP\n    image_pull_policy: IfNotPresent\n    env_config_maps:\n      - dagster-user-code-env\n    env_secrets:\n      - dagster-user-code-secrets\n    run_k8s_config:\n      pod_spec_config:\n        node_selector:\n          workload: dagster\n```\n\nStart Dagster against the same `DAGSTER_HOME`:\n\n```bash\ndg dev -m my_project.definitions\n```\n\nIf your deployment uses schedules or sensors, point the daemon at the same instance:\n\n```bash\ndagster-daemon run\n```\n\nPractical rules that matter:\n\n- `job_image` must contain your importable code location and all runtime dependencies\n- the target namespace must already contain the referenced ConfigMaps and Secrets\n- the service account must be able to create Jobs and read any referenced Secrets or ConfigMaps\n- your instance storage must be reachable from launched jobs; for Kubernetes deployments, a shared backend such as PostgreSQL is the normal choice\n\n## Launch Individual Steps With `k8s_job_executor`\n\nUse `k8s_job_executor` when you want a Dagster job's steps to run as separate Kubernetes Jobs.\n\n```python\nimport dagster as dg\nfrom dagster_k8s import k8s_job_executor\n\n\n@dg.op\ndef emit_message() -> None:\n    print(\"hello from a kubernetes step\")\n\n\n@dg.job(executor_def=k8s_job_executor)\ndef k8s_steps_job():\n    emit_message()\n\n\ndefs = dg.Definitions(jobs=[k8s_steps_job])\n```\n\nConfigure the executor in run config:\n\n```yaml\nexecution:\n  config:\n    job_namespace:\n      env: DAGSTER_K8S_NAMESPACE\n    service_account_name:\n      env: DAGSTER_K8S_SERVICE_ACCOUNT\n    job_image:\n      env: DAGSTER_K8S_JOB_IMAGE\n    image_pull_policy: IfNotPresent\n    env_config_maps:\n      - dagster-user-code-env\n    env_secrets:\n      - dagster-user-code-secrets\n```\n\nIn Python, the same run config looks like this:\n\n```python\nrun_config = {\n    \"execution\": {\n        \"config\": {\n            \"job_namespace\": {\"env\": \"DAGSTER_K8S_NAMESPACE\"},\n            \"service_account_name\": {\"env\": \"DAGSTER_K8S_SERVICE_ACCOUNT\"},\n            \"job_image\": {\"env\": \"DAGSTER_K8S_JOB_IMAGE\"},\n            \"image_pull_policy\": \"IfNotPresent\",\n            \"env_config_maps\": [\"dagster-user-code-env\"],\n            \"env_secrets\": [\"dagster-user-code-secrets\"],\n        }\n    }\n}\n```\n\nThe same image rule applies here: the image used for step Jobs must already contain the code and dependencies needed to import and execute your job.\n\n## Apply Raw Kubernetes Settings Per Run Or Job\n\n`dagster-k8s` supports raw Kubernetes fragments for the launched Job and Pod. The most common way to apply them from code is the `dagster-k8s/config` tag.\n\n```python\nimport dagster as dg\nfrom dagster_k8s import k8s_job_executor\n\n\n@dg.op\ndef work() -> None:\n    print(\"running with custom k8s settings\")\n\n\n@dg.job(\n    executor_def=k8s_job_executor,\n    tags={\n        \"dagster-k8s/config\": {\n            \"container_config\": {\n                \"resources\": {\n                    \"requests\": {\"cpu\": \"250m\", \"memory\": \"512Mi\"},\n                    \"limits\": {\"cpu\": \"1\", \"memory\": \"1Gi\"},\n                }\n            },\n            \"pod_spec_config\": {\n                \"node_selector\": {\"workload\": \"dagster\"}\n            },\n            \"job_metadata\": {\n                \"labels\": {\"app.kubernetes.io/part-of\": \"dagster\"}\n            },\n        }\n    },\n)\ndef tuned_job():\n    work()\n```\n\nThe raw config groups you will usually use are:\n\n- `container_config` for container fields such as resource requests and limits\n- `pod_template_spec_metadata` for pod-template labels and annotations\n- `pod_spec_config` for pod-level settings such as node selectors and tolerations\n- `job_metadata` and `job_spec_config` for Kubernetes Job metadata and spec fields\n\nPrefer the structured launcher or executor settings for standard fields such as namespace, service account, image, env sources, and pull secrets. Use raw config only for Kubernetes fields that are not already covered by first-class Dagster settings.\n\n## Common Pitfalls\n\n- Keep package versions aligned. `dagster-k8s 0.28.18` is for the Dagster `1.12.18` release line.\n- Choose the right execution level: `K8sRunLauncher` launches whole runs as Jobs, while `k8s_job_executor` launches individual steps as Jobs.\n- Do not assume local files are visible inside launched jobs. Package your code and runtime files into `job_image`, or mount them explicitly through Kubernetes config.\n- A Kubernetes service account is not just a name in config; it needs RBAC permissions for the resources your launch path touches.\n- Referenced ConfigMaps and Secrets must exist in the namespace where jobs are launched.\n- Local ephemeral instance storage is a poor fit once Dagster work moves into separate Kubernetes jobs. Use shared instance storage.\n- If Dagster runs outside the cluster, Kubernetes auth must come from kubeconfig or another supported client configuration; in-cluster service-account auth does not apply there.\n\n## Version-Sensitive Notes For `0.28.18`\n\n- Dagster library packages and Dagster core use different visible version numbers in the same release train. For this guide, that means `dagster-k8s 0.28.18` with Dagster core `1.12.18`.\n- The `dagster-k8s` package source for this release line lives in the Dagster monorepo under `python_modules/libraries/dagster-k8s`.\n- When upgrading a production deployment, pin the related Dagster packages together instead of upgrading `dagster-k8s` in isolation.\n\n## Official Sources Used\n\n- Dagster `dagster-k8s` package source: `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-k8s`\n- Dagster docs root: `https://docs.dagster.io/`\n- PyPI package page: `https://pypi.org/project/dagster-k8s/`\n"
  },
  {
    "path": "content/dagster/docs/mlflow/python/DOC.md",
    "content": "---\nname: mlflow\ndescription: \"dagster-mlflow package guide for using MLflow tracking from Dagster jobs with environment-based tracking server configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-mlflow,python,mlflow,experiment-tracking,mlops,data-orchestration\"\n---\n\n# dagster-mlflow Python Package Guide\n\n## Golden Rule\n\nUse `dagster-mlflow` to expose MLflow's normal tracking API inside a Dagster job through the `mlflow_tracking` resource. Keep tracking server configuration and authentication in standard MLflow environment variables, and close runs explicitly with `mlflow.end_run()` or the package's `end_mlflow_on_run_finished` hook.\n\nKeep `dagster-mlflow` on the same Dagster release line as the rest of your Dagster packages. For this guide, `dagster-mlflow==0.28.18` pairs with Dagster `1.12.18`.\n\n## Install\n\nInstall the integration alongside the matching Dagster packages and the MLflow client you will call from job code:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-mlflow==0.28.18\" \\\n  \"mlflow\"\n```\n\nIf you do not run the local Dagster UI in this environment, `dagster-webserver` is optional.\n\n## Prerequisites\n\nBefore using `dagster-mlflow`, make sure you already have:\n\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- an MLflow tracking backend, either local or remote\n- the same package set installed anywhere your Dagster code location, webserver, or daemon imports the code\n\nFor local development, the common environment-variable setup is:\n\n```bash\nexport MLFLOW_TRACKING_URI=\"http://127.0.0.1:5000\"\nexport MLFLOW_EXPERIMENT_NAME=\"dagster-training\"\n```\n\nIf your tracking server requires authentication, MLflow also documents these environment variables:\n\n```bash\nexport MLFLOW_TRACKING_USERNAME=\"alice\"\nexport MLFLOW_TRACKING_PASSWORD=\"secret\"\n```\n\nOr token-based auth:\n\n```bash\nexport MLFLOW_TRACKING_TOKEN=\"token-value\"\n```\n\nIf you omit `MLFLOW_TRACKING_URI`, MLflow usually logs to the local `./mlruns` directory instead of a shared tracking server.\n\n## Minimal Job With `mlflow_tracking`\n\nThis is the core `dagster-mlflow` pattern to copy into an op-based Dagster job:\n\n```python\nimport os\nfrom pathlib import Path\n\nimport dagster as dg\nfrom dagster_mlflow import end_mlflow_on_run_finished, mlflow_tracking\n\n\n@dg.op(required_resource_keys={\"mlflow\"})\ndef train_model(context: dg.OpExecutionContext) -> str:\n    mlflow = context.resources.mlflow\n\n    mlflow.set_tracking_uri(os.environ[\"MLFLOW_TRACKING_URI\"])\n    mlflow.set_experiment(os.environ[\"MLFLOW_EXPERIMENT_NAME\"])\n\n    artifact_dir = Path(\"artifacts\")\n    artifact_dir.mkdir(parents=True, exist_ok=True)\n    summary_path = artifact_dir / \"summary.txt\"\n    summary_path.write_text(\"accuracy=0.91\\n\")\n\n    with mlflow.start_run(run_name=\"train_model\"):\n        mlflow.log_param(\"model_type\", \"baseline\")\n        mlflow.log_metric(\"accuracy\", 0.91)\n        mlflow.set_tag(\"dagster_job\", context.job_name)\n        mlflow.log_artifact(str(summary_path), artifact_path=\"reports\")\n\n    return \"logged\"\n\n\n@dg.job(\n    resource_defs={\"mlflow\": mlflow_tracking},\n    hooks={end_mlflow_on_run_finished},\n)\ndef training_job():\n    train_model()\n\n\ndefs = dg.Definitions(jobs=[training_job])\n```\n\nWhat matters in the snippet:\n\n- `mlflow_tracking` is the Dagster resource exported by `dagster-mlflow`\n- the resource is registered under the `mlflow` key, so the op reads it as `context.resources.mlflow`\n- the logging calls are the standard MLflow tracking API: `set_experiment(...)`, `start_run(...)`, `log_param(...)`, `log_metric(...)`, `set_tag(...)`, and `log_artifact(...)`\n- `end_mlflow_on_run_finished` is the package helper to clean up an active MLflow run when the Dagster job finishes\n\n## Use MLflow APIs Directly Inside The Op\n\n`dagster-mlflow` does not replace the MLflow client API. The common workflow is still:\n\n1. point the process at the correct tracking server\n2. select an experiment\n3. start a run\n4. log params, metrics, tags, and artifacts\n5. end the run\n\nThat means the MLflow calls you write inside Dagster should look like normal MLflow code:\n\n```python\nmlflow.set_tracking_uri(os.environ[\"MLFLOW_TRACKING_URI\"])\nmlflow.set_experiment(os.environ[\"MLFLOW_EXPERIMENT_NAME\"])\n\nwith mlflow.start_run(run_name=\"baseline\"):\n    mlflow.log_param(\"learning_rate\", 0.01)\n    mlflow.log_metric(\"loss\", 0.42)\n    mlflow.set_tag(\"stage\", \"dev\")\n```\n\nIf you already have working standalone MLflow tracking code, the usual migration into Dagster is to move that logic into an op and access MLflow through `context.resources.mlflow`.\n\n## Local Development Workflow\n\nStart Dagster against the module that exposes your top-level `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nTo execute the job directly from the CLI:\n\n```bash\ndagster job execute -m my_project.definitions -j training_job\n```\n\nIf your deployment uses schedules or sensors, run the daemon with the same environment variables so MLflow logging still reaches the intended tracking backend.\n\n## Common Pitfalls\n\n- Version mismatch. Keep `dagster-mlflow` on the same release line as the rest of your Dagster packages.\n- Wrong tracking backend. A missing or incorrect `MLFLOW_TRACKING_URI` often sends logs to local `./mlruns` instead of your shared tracking server.\n- Resource key mismatch. The op expects `context.resources.mlflow`, so the job must register the resource under the `mlflow` key.\n- Missing cleanup. If your code starts MLflow runs manually, make sure they are closed with a context manager, `mlflow.end_run()`, or `end_mlflow_on_run_finished`.\n- Partial installation. Install `dagster-mlflow` and `mlflow` anywhere the Dagster code location, webserver, or daemon needs to import or execute the job.\n- Assuming Dagster manages MLflow auth for you. Tracking server credentials still follow normal MLflow configuration.\n\n## Version Notes For `0.28.18`\n\n- `dagster-mlflow==0.28.18` is part of the Dagster `1.12.18` release line.\n- The package source for this release line lives in the Dagster monorepo under `python_modules/libraries/dagster-mlflow`.\n- For tracking server URLs, auth variables, and artifact logging behavior, rely on the matching MLflow client documentation as well as the Dagster integration docs.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-mlflow\n- https://github.com/dagster-io/dagster/blob/master/python_modules/libraries/dagster-mlflow/README.md\n- https://docs.dagster.io/api/python-api/libraries/dagster-mlflow\n- https://pypi.org/project/dagster-mlflow/\n- https://mlflow.org/docs/latest/\n- https://mlflow.org/docs/latest/api_reference/python_api/\n- https://mlflow.org/docs/latest/self-hosting/architecture/tracking-server/\n"
  },
  {
    "path": "content/dagster/docs/openai/python/DOC.md",
    "content": "---\nname: openai\ndescription: \"dagster-openai package guide for calling OpenAI models from Dagster assets and ops with OpenAIResource\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-openai,python,openai,llm,ai,data-orchestration\"\n---\n\n# dagster-openai Python Package Guide\n\n## Golden Rule\n\nUse `dagster-openai` as a thin Dagster integration around the OpenAI Python client: keep your API key in `OPENAI_API_KEY`, register `OpenAIResource` in `dg.Definitions(...)`, and make model calls through the injected resource from assets or ops.\n\nKeep `dagster-openai` on the same Dagster release line as the rest of your Dagster packages. For this guide, `dagster-openai==0.28.18` pairs with Dagster `1.12.18`.\n\n## Install\n\nInstall the OpenAI integration alongside matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-openai==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-openai\n```\n\n## Prerequisites\n\nBefore you wire this into Dagster, make sure you already have:\n\n- an OpenAI API key that can call the model you plan to use\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- the same package set installed anywhere your Dagster code location, webserver, or daemon imports the code\n\nFor local development, keep credentials and model defaults in environment variables:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport OPENAI_MODEL=\"gpt-4o-mini\"\n```\n\n`dagster-openai` does not add a separate authentication flow on top of OpenAI. The important credential is the API key you pass into `OpenAIResource`.\n\n## Register `OpenAIResource`\n\nThe main integration point is `OpenAIResource`.\n\n```python\nimport dagster as dg\nfrom dagster_openai import OpenAIResource\n\n\ndefs = dg.Definitions(\n    resources={\n        \"openai\": OpenAIResource(api_key=dg.EnvVar(\"OPENAI_API_KEY\")),\n    },\n)\n```\n\nThe resource key must match the function parameter name you use for injection.\n\n## Call Chat Completions From An Asset\n\nThis is the simplest pattern to copy into a Dagster project:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_openai import OpenAIResource\n\n\n@dg.asset\ndef summarize_feedback(\n    context: dg.AssetExecutionContext,\n    openai: OpenAIResource,\n) -> str:\n    with openai.get_client(context) as client:\n        response = client.chat.completions.create(\n            model=os.environ.get(\"OPENAI_MODEL\", \"gpt-4o-mini\"),\n            messages=[\n                {\n                    \"role\": \"system\",\n                    \"content\": \"You write concise operational summaries.\",\n                },\n                {\n                    \"role\": \"user\",\n                    \"content\": \"Summarize this customer feedback in 3 bullet points: Delivery was late, but support resolved the issue quickly and the customer wants proactive updates next time.\",\n                },\n            ],\n        )\n\n    return response.choices[0].message.content or \"\"\n\n\ndefs = dg.Definitions(\n    assets=[summarize_feedback],\n    resources={\n        \"openai\": OpenAIResource(api_key=dg.EnvVar(\"OPENAI_API_KEY\")),\n    },\n)\n```\n\nImportant details:\n\n- `openai.get_client(context)` gives your asset an OpenAI client through the Dagster integration\n- `client.chat.completions.create(...)` is the exact OpenAI API call used in this example\n- the `openai` function parameter must match the `resources={\"openai\": ...}` key\n- model names and request fields still follow the OpenAI Python SDK and OpenAI API docs\n\n## Use Config To Choose The Prompt Or Model Per Run\n\nIf the prompt or model should change between runs, pass them through Dagster config instead of hard-coding them.\n\n```python\nimport dagster as dg\nfrom dagster_openai import OpenAIResource\n\n\nclass PromptConfig(dg.Config):\n    prompt: str\n    model: str = \"gpt-4o-mini\"\n\n\n@dg.op\ndef generate_copy(\n    context: dg.OpExecutionContext,\n    config: PromptConfig,\n    openai: OpenAIResource,\n) -> str:\n    with openai.get_client(context) as client:\n        response = client.chat.completions.create(\n            model=config.model,\n            messages=[{\"role\": \"user\", \"content\": config.prompt}],\n        )\n\n    return response.choices[0].message.content or \"\"\n\n\n@dg.job\ndef marketing_job() -> None:\n    generate_copy()\n\n\ndefs = dg.Definitions(\n    jobs=[marketing_job],\n    resources={\n        \"openai\": OpenAIResource(api_key=dg.EnvVar(\"OPENAI_API_KEY\")),\n    },\n)\n```\n\nExample run config:\n\n```yaml\nops:\n  generate_copy:\n    config:\n      model: gpt-4o-mini\n      prompt: \"Write a release note summary for a bug-fix deployment in 2 sentences.\"\n```\n\nThis keeps prompt text in run configuration and makes the OpenAI call itself easy to audit in code.\n\n## Local Development Workflow\n\nPoint Dagster at the module that exposes your top-level `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nIf your deployment uses schedules or sensors, run the daemon against the same Dagster instance configuration:\n\n```bash\ndagster-daemon run\n```\n\n## Common Pitfalls\n\n- Version mismatch. Keep `dagster-openai` on the matching Dagster release line.\n- Missing API key. `OpenAIResource` still needs a valid `OPENAI_API_KEY` at runtime.\n- Resource name mismatch. The injected function parameter must match the resource dictionary key.\n- Endpoint and model mismatch. This guide uses `client.chat.completions.create(...)`, so choose a model that supports chat completions.\n- Partial installation. Install `dagster-openai` anywhere your Dagster code location, webserver, or daemon imports the definitions.\n- Bypassing the integration. If you want Dagster-aware behavior from this package, call OpenAI through the injected `OpenAIResource` inside your asset or op instead of creating an unrelated client elsewhere.\n\n## Version Notes For `0.28.18`\n\n- `dagster-openai==0.28.18` is part of the Dagster `1.12.18` release line.\n- The package source for this release line lives in the Dagster monorepo under `python_modules/libraries/dagster-openai`.\n- When upgrading, pin the related Dagster packages together instead of upgrading `dagster-openai` in isolation.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-openai\n- https://docs.dagster.io/api/python-api/libraries/dagster-openai\n- https://docs.dagster.io/api/dagster/resources\n- https://pypi.org/project/dagster-openai/\n- https://platform.openai.com/docs/api-reference/chat/create\n"
  },
  {
    "path": "content/dagster/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Dagster Python package guide for asset-based orchestration, local development, jobs, schedules, and structured config\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,python,data-orchestration,assets,pipelines,schedules,sensors\"\n---\n\n# Dagster Python Package Guide\n\n## Golden Rule\n\nUse `dagster` as the core programming model, expose a top-level `defs = dg.Definitions(...)` object in a loadable module, and build around software-defined assets unless you have a clear reason to stay in the older op/graph model.\n\nFor a local developer experience that matches the official docs, install the companion CLI and webserver packages alongside `dagster`.\n\n## Install\n\nIf you only need the core library in an existing project:\n\n```bash\npython -m pip install \"dagster==1.12.18\"\n```\n\nFor the full local OSS workflow from the official quickstart, install the core package plus the local UI and `dg` CLI:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-dg-cli==1.12.18\"\n```\n\nEquivalent `uv` install:\n\n```bash\nuv add dagster dagster-webserver dagster-dg-cli\n```\n\n## Initialize A Project\n\nThe official scaffolder creates a modern project layout with `src/<project_name>/definitions.py`, a `defs/` package, `tests/`, and `pyproject.toml`:\n\n```bash\ncreate-dagster project my_dagster_project\ncd my_dagster_project\ndg dev\n```\n\nIf you already have a Python package and just want to add Dagster manually, the important part is a loadable module with a top-level `Definitions` instance:\n\n```text\nsrc/\n  my_project/\n    __init__.py\n    definitions.py\n```\n\n```python\n# src/my_project/definitions.py\nimport dagster as dg\n\n@dg.asset\ndef hello() -> str:\n    return \"hello\"\n\ndefs = dg.Definitions(assets=[hello])\n```\n\nThen run the local instance by pointing Dagster at that module:\n\n```bash\ndg dev -m my_project.definitions\n```\n\n## Core Usage\n\n### Minimal asset-based project\n\nThis is the main Dagster shape to remember:\n\n```python\nimport dagster as dg\n\nclass ApiConfig(dg.Config):\n    base_url: str\n    dataset: str = \"events\"\n\nclass ApiResource(dg.ConfigurableResource):\n    token: str\n\n    def fetch(self, dataset: str) -> list[dict]:\n        # Replace with real HTTP or SDK logic.\n        return [{\"dataset\": dataset, \"status\": \"ok\"}]\n\n@dg.asset\ndef raw_events(config: ApiConfig, api: ApiResource) -> list[dict]:\n    return api.fetch(config.dataset)\n\n@dg.asset\ndef event_count(raw_events: list[dict]) -> int:\n    return len(raw_events)\n\ndaily_assets = dg.define_asset_job(\"daily_assets\", selection=[raw_events, event_count])\n\n@dg.schedule(\n    cron_schedule=\"0 6 * * *\",\n    target=daily_assets,\n    execution_timezone=\"America/Los_Angeles\",\n)\ndef daily_schedule():\n    return dg.RunRequest()\n\ndefs = dg.Definitions(\n    assets=[raw_events, event_count],\n    jobs=[daily_assets],\n    schedules=[daily_schedule],\n    resources={\n        \"api\": ApiResource(token=dg.EnvVar(\"API_TOKEN\")),\n    },\n)\n```\n\nKey behaviors that matter in practice:\n\n- `@dg.asset` defines a persistent data asset, and Dagster infers upstream asset dependencies from function arguments.\n- `dg.Definitions(...)` is the object Dagster tools load. If the module does not expose a top-level `Definitions` instance, `dg dev` and other tooling will not find your code.\n- `ConfigurableResource` is the structured resource API for external systems.\n- `Config` is the structured config API for assets and ops.\n- `define_asset_job(...)` is the usual way to turn an asset selection into a runnable job.\n- `@dg.schedule` automates runs with cron and can target a job or asset selection.\n\n### Validate before starting the UI\n\nUse the CLI to catch loadability and dependency problems early:\n\n```bash\ndg check defs\n```\n\nUseful local inspection commands:\n\n```bash\ndg list defs\ndg list envs\n```\n\n### Test definitions in Python\n\nFor unit tests, validate that your definitions can load cleanly:\n\n```python\nfrom my_project.definitions import defs\n\ndef test_defs_loadable() -> None:\n    defs.validate_loadable()\n```\n\n## Configuration And Secrets\n\nDagster OSS itself does not require a package-level auth step. Authentication usually belongs to the systems your assets talk to, such as databases, cloud APIs, warehouses, or Dagster+.\n\nUse Dagster config and resource APIs for runtime settings:\n\n- `dg.Config` for structured asset or op config\n- `dg.ConfigurableResource` for typed resources\n- `dg.EnvVar(\"NAME\")` for secrets in resources or config\n- `StringSource`, `IntSource`, and similar legacy config types when you are still on legacy config schemas\n\nExample:\n\n```python\nimport dagster as dg\n\nclass WarehouseResource(dg.ConfigurableResource):\n    username: str\n    password: str\n\ndefs = dg.Definitions(\n    resources={\n        \"warehouse\": WarehouseResource(\n            username=dg.EnvVar(\"WAREHOUSE_USER\"),\n            password=dg.EnvVar(\"WAREHOUSE_PASSWORD\"),\n        )\n    }\n)\n```\n\nImportant secret-handling rule: job config dictionaries and `configured(...)` values can be visible in the Dagster UI. Do not hardcode secrets into run config, schedules, or constant resource configuration.\n\n## Common Pitfalls\n\n- A loadable Dagster module must expose a top-level `Definitions` instance. A helper function that returns `Definitions` is not enough unless the CLI is pointed at it appropriately.\n- Assets infer dependencies from function parameters. Renaming a parameter changes the upstream asset key relationship unless you configure it explicitly.\n- Jobs created with `@job` do not respect the `resources=` argument on `Definitions`. Bind resources at job creation time for op jobs, or prefer asset jobs when possible.\n- `dg check defs` should be part of local validation. It is faster to catch missing resources, conflicting asset keys, or unresolved asset jobs there than in the UI.\n- Use environment variables or Dagster config sources for secrets. Values supplied as constant job config can show up in the UI.\n- `execute_in_process()` is useful for tests, but it swaps execution to the in-process executor and changes the default IO manager behavior to in-memory. Do not assume it behaves exactly like your production execution environment.\n- Dagster schedules are cron-based and timezone-aware. Set `execution_timezone` explicitly when local time matters.\n\n## Version-Sensitive Notes For 1.12.18\n\n- PyPI currently lists `dagster 1.12.18` released on March 5, 2026.\n- Dagster's docs are not perfectly version-aligned right now: several API pages still show `Latest (1.12.8)` in the site chrome, while the CLI reference and GitHub releases reflect `1.12.18`. Trust PyPI and the release feed for the actual package version.\n- The official 1.12.18 release notes mention a fix for nested resource attributes annotated with `dagster.ResourceDependency` during parent resource setup. If you use nested resources, stay on at least `1.12.18`.\n- `run_request_for_partition()` is marked deprecated in the jobs API and scheduled for removal in `2.0.0`; use `dg.RunRequest(partition_key=...)` directly instead.\n\n## Official Sources Used\n\n- Docs root: https://docs.dagster.io/api\n- Definitions API: https://docs.dagster.io/api/dagster/definitions\n- Assets API: https://docs.dagster.io/api/dagster/assets\n- Config API: https://docs.dagster.io/api/dagster/config\n- Resources API: https://docs.dagster.io/api/dagster/resources\n- Schedules and sensors API: https://docs.dagster.io/api/dagster/schedules-sensors\n- CLI reference: https://docs.dagster.io/api/clis\n- `dg` CLI reference: https://docs.dagster.io/api/clis/dg-cli/dg-cli-reference\n- `create-dagster` CLI reference: https://docs.dagster.io/api/clis/create-dagster\n- PyPI package page: https://pypi.org/project/dagster/\n- GitHub releases: https://github.com/dagster-io/dagster/releases\n"
  },
  {
    "path": "content/dagster/docs/pagerduty/python/DOC.md",
    "content": "---\nname: pagerduty\ndescription: \"dagster-pagerduty package guide for sending PagerDuty Events API v2 alerts from Dagster assets and ops\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-pagerduty,pagerduty,python,alerts,incident-response,data-orchestration\"\n---\n\n# dagster-pagerduty Python Package Guide\n\n## Golden Rule\n\nUse `dagster-pagerduty` as a thin Dagster wrapper around PagerDuty's Events API v2: create an Events API v2 integration on the PagerDuty service or orchestration you want to alert, keep that integration key in an environment variable, register `PagerDutyService` in Dagster, and send alert events through `EventV2_create(...)`.\n\n`dagster-pagerduty` does not replace PagerDuty account setup. You still need a valid PagerDuty integration key, which PagerDuty's docs also call a routing key for Events API v2 requests.\n\n## Install\n\nInstall the package into the same Python environment as your Dagster code:\n\n```bash\npython -m pip install \"dagster-pagerduty==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\npython -m pip show dagster-pagerduty\ndagster --version\n```\n\n## Prerequisites\n\nBefore using `dagster-pagerduty`, make sure you already have:\n\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- a PagerDuty service or Event Orchestration integration that accepts Events API v2 events\n- the integration key copied from PagerDuty and stored securely\n- the package installed anywhere your Dagster code location, webserver, or daemon imports the code\n\nFor local development, keep the routing key in an environment variable:\n\n```bash\nexport PAGERDUTY_ROUTING_KEY=\"0123456789abcdef0123456789abcdef\"\n```\n\nPagerDuty's integration keys are case-sensitive. Use the exact value copied from the PagerDuty UI.\n\n## Register `PagerDutyService`\n\nThe main integration point is `PagerDutyService`.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_pagerduty import PagerDutyService\n\n\ndefs = dg.Definitions(\n    resources={\n        \"pagerduty\": PagerDutyService(\n            routing_key=os.environ[\"PAGERDUTY_ROUTING_KEY\"],\n        ),\n    },\n)\n```\n\nThe resource key must match the function parameter name you use for injection.\n\n## Trigger A PagerDuty Alert From An Asset\n\nThis is the core pattern from the official Dagster integration page:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_pagerduty import PagerDutyService\n\n\n@dg.asset\ndef pagerduty_alert(pagerduty: PagerDutyService) -> None:\n    pagerduty.EventV2_create(\n        summary=\"alert from dagster\",\n        source=os.environ.get(\"HOSTNAME\", \"dagster\"),\n        severity=\"error\",\n        event_action=\"trigger\",\n    )\n\n\ndefs = dg.Definitions(\n    assets=[pagerduty_alert],\n    resources={\n        \"pagerduty\": PagerDutyService(\n            routing_key=os.environ[\"PAGERDUTY_ROUTING_KEY\"],\n        ),\n    },\n)\n```\n\nImportant details:\n\n- `PagerDutyService` sends events through PagerDuty Events API v2\n- `event_action=\"trigger\"` creates an alert event\n- `source` should identify the affected system or emitter\n- `severity` must be one of `critical`, `error`, `warning`, or `info`\n- the injected parameter name `pagerduty` must match the `resources={\"pagerduty\": ...}` key\n\n## Use It From Ops Too\n\nThe same service works in ops if your project still uses the op or job model:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_pagerduty import PagerDutyService\n\n\n@dg.op\ndef notify_ops_team(pagerduty: PagerDutyService) -> None:\n    pagerduty.EventV2_create(\n        summary=\"nightly ingestion failed\",\n        source=\"dagster/nightly-ingestion\",\n        severity=\"critical\",\n        event_action=\"trigger\",\n    )\n\n\n@dg.job\ndef alerting_job() -> None:\n    notify_ops_team()\n\n\ndefs = dg.Definitions(\n    jobs=[alerting_job],\n    resources={\n        \"pagerduty\": PagerDutyService(\n            routing_key=os.environ[\"PAGERDUTY_ROUTING_KEY\"],\n        ),\n    },\n)\n```\n\n## Event Fields That Matter In Practice\n\nPagerDuty's Events API v2 behavior matters more than Dagster-specific configuration here:\n\n- `routing_key`: the integration key for your PagerDuty service or orchestration\n- `event_action`: use `trigger` to create an alert\n- `severity`: PagerDuty accepts only `critical`, `error`, `warning`, or `info`\n- `dedup_key`: PagerDuty uses this to merge repeated events into the same alert and to match a later `resolve` event to an existing alert\n\nIf you need one long-lived incident instead of a new PagerDuty alert for every Dagster failure, design a stable `dedup_key` strategy around the job, asset, or external system you are paging on.\n\n## Local Development Workflow\n\nPoint Dagster at the module that exposes your top-level `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nTrigger the asset or job, then verify the resulting alert in PagerDuty. If nothing appears, check the Dagster process logs first, then confirm that the routing key belongs to the service you expected.\n\n## Common Pitfalls\n\n- Using the wrong PagerDuty credential. `dagster-pagerduty` needs an Events API v2 integration key as the `routing_key`, not a REST API access token.\n- Mistyping the key. PagerDuty integration keys are case-sensitive.\n- Invalid severity strings. PagerDuty rejects values outside `critical`, `error`, `warning`, or `info`.\n- Resource name mismatch. The Dagster resource key and injected parameter name must match.\n- Alert spam from repeated failures. Without a stable `dedup_key`, repeated failures are more likely to create separate alerts instead of updating one ongoing incident.\n- Partial installation. Install the package anywhere your Dagster code is imported, including local code locations and deployment environments.\n\n## Version Notes For `0.28.18`\n\n- This guide targets `dagster-pagerduty==0.28.18`.\n- Dagster publishes this integration from the main `dagster-io/dagster` monorepo under `python_modules/libraries/dagster-pagerduty`.\n\n## Official Sources\n\n- https://dagster.io/integrations/dagster-pagerduty\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-pagerduty\n- https://pypi.org/project/dagster-pagerduty/\n- https://support.pagerduty.com/main/docs/services-and-integrations\n- https://support.pagerduty.com/main/docs/dynamic-notifications\n- https://support.pagerduty.com/main/docs/event-orchestration\n- https://support.pagerduty.com/main/docs/alerts\n- https://support.pagerduty.com/main/docs/pd-cef\n"
  },
  {
    "path": "content/dagster/docs/pandas/python/DOC.md",
    "content": "---\nname: pandas\ndescription: \"dagster-pandas package guide for validating pandas DataFrames in Dagster jobs with typed inputs and outputs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-pandas,python,pandas,dataframe,data-validation,data-orchestration\"\n---\n\n# dagster-pandas Python Package Guide\n\n## Golden Rule\n\nUse `dagster-pandas` when you want Dagster to enforce runtime checks on `pandas.DataFrame` values crossing Dagster op boundaries. Define a named dataframe type with `create_dagster_pandas_dataframe_type(...)`, apply it with `In` and `Out`, and keep `dagster-pandas` on the same release line as the rest of your Dagster packages.\n\nFor this guide, `dagster-pandas==0.28.18` belongs to the Dagster `1.12.18` release line.\n\n## Install\n\nInstall the package alongside matching Dagster packages and `pandas`:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-pandas==0.28.18\" \\\n  pandas\n```\n\nIf your project already pins Dagster, keep `dagster-pandas` on the matching release line instead of upgrading it independently.\n\n## Prerequisites\n\nBefore using `dagster-pandas`, make sure your runtime already has:\n\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- `pandas` installed in the same environment as Dagster\n- a real data-loading step such as `pd.read_csv(...)`, database access, or an API client that produces a `pandas.DataFrame`\n\n`dagster-pandas` is a local validation library. There is no separate service, token, or authentication flow to configure.\n\n## Configure Your Input Path\n\nThis example reads a CSV from an environment variable:\n\n```bash\nexport ORDERS_CSV_PATH=\"$PWD/data/orders.csv\"\n```\n\n## Define A Validated DataFrame Type\n\nThe core workflow is:\n\n1. create a Dagster dataframe type\n2. load a `pandas.DataFrame`\n3. return it from an op whose output uses that Dagster type\n4. accept the same type on downstream op inputs when you want the boundary checked again\n\n```python\n# src/my_project/orders.py\nimport os\n\nimport dagster as dg\nimport pandas as pd\nfrom dagster_pandas import (\n    PandasColumn,\n    create_dagster_pandas_dataframe_type,\n)\n\n\nOrdersDataFrame = create_dagster_pandas_dataframe_type(\n    name=\"OrdersDataFrame\",\n    description=\"Orders loaded from a CSV extract\",\n    columns=[\n        PandasColumn.integer_column(\"order_id\"),\n        PandasColumn.string_column(\"customer_id\"),\n        PandasColumn.datetime_column(\"created_at\"),\n    ],\n)\n\n\n@dg.op(out=dg.Out(OrdersDataFrame))\ndef load_orders() -> pd.DataFrame:\n    dataframe = pd.read_csv(\n        os.environ[\"ORDERS_CSV_PATH\"],\n        parse_dates=[\"created_at\"],\n    )\n    return dataframe[[\"order_id\", \"customer_id\", \"created_at\"]]\n\n\n@dg.op(ins={\"orders\": dg.In(OrdersDataFrame)})\ndef count_orders(orders: pd.DataFrame) -> int:\n    return len(orders)\n\n\n@dg.job\ndef orders_job():\n    count_orders(load_orders())\n```\n\nWhat matters in this example:\n\n- `create_dagster_pandas_dataframe_type(...)` creates the Dagster type Dagster will validate at runtime\n- `PandasColumn.*_column(...)` declares expected columns and their logical types\n- `parse_dates=[\"created_at\"]` happens in `pandas`; `dagster-pandas` checks the dataframe you return, it does not parse or coerce columns for you\n- `dg.Out(OrdersDataFrame)` and `dg.In(OrdersDataFrame)` are what actually attach the custom dataframe type to the Dagster boundary\n\n## Use The Built-In `DataFrame` Type When You Only Need A Pandas Value\n\nIf you only need a `pandas.DataFrame` to move between ops and do not need column validation, use the packaged `DataFrame` Dagster type directly:\n\n```python\nimport os\n\nimport dagster as dg\nimport pandas as pd\nfrom dagster_pandas import DataFrame\n\n\n@dg.op(out=dg.Out(DataFrame))\ndef load_raw_orders() -> pd.DataFrame:\n    return pd.read_csv(os.environ[\"ORDERS_CSV_PATH\"])\n```\n\nThis is the simpler choice when schema enforcement is handled elsewhere and you only want a recognized pandas dataframe type in Dagster.\n\n## Expose Definitions And Run Locally\n\nExpose your job from a loadable module:\n\n```python\n# src/my_project/definitions.py\nimport dagster as dg\n\nfrom .orders import orders_job\n\n\ndefs = dg.Definitions(jobs=[orders_job])\n```\n\nRun the code location locally:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\n## Common Pitfalls\n\n- Version mismatch. Keep `dagster-pandas` on the matching Dagster release line.\n- Expecting automatic coercion. Parse datetimes, numbers, and missing values in `pandas` before returning the dataframe.\n- Forgetting the Dagster boundary. A custom dataframe type is only enforced where you attach it with `In` or `Out`.\n- Validating columns you later drop or rename. The dataframe you return must still match the declared columns exactly.\n- Treating the package like an IO layer. `dagster-pandas` validates dataframe values; it does not read files, talk to databases, or manage storage.\n\n## Version Notes For `0.28.18`\n\n- `dagster-pandas==0.28.18` belongs to the Dagster `1.12.18` release line.\n- The package is centered on Dagster types for `pandas.DataFrame` values, so it fits best where runtime type checks on op inputs and outputs are the main requirement.\n\n## Official Sources\n\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-pandas`\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-pandas/dagster_pandas`\n- `https://docs.dagster.io/api/python-api/libraries/dagster-pandas`\n- `https://docs.dagster.io/guides/build/jobs`\n- `https://pypi.org/project/dagster-pandas/`\n"
  },
  {
    "path": "content/dagster/docs/polars/python/DOC.md",
    "content": "---\nname: polars\ndescription: \"dagster-polars package guide for loading Polars DataFrames and LazyFrames through Dagster IO managers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.27.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-polars,python,polars,dataframe,lazyframe,io-manager\"\n---\n\n# dagster-polars Python Package Guide\n\n## Golden Rule\n\nUse `dagster-polars` as a Dagster IO-layer integration for `polars` objects: annotate your assets or ops with `pl.DataFrame` or `pl.LazyFrame`, register the matching IO manager in `dg.Definitions(...)`, and let Dagster load and store those values for you.\n\nThe integration defaults to eager `pl.DataFrame` behavior unless you annotate the boundary with `pl.LazyFrame`.\n\n## Install\n\nCreate or activate a Python environment first:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"dagster-polars==0.27.9\"\n```\n\nOptional extras published on PyPI for `0.27.9`:\n\n```bash\npython -m pip install \"dagster-polars[deltalake]==0.27.9\"\npython -m pip install \"dagster-polars[gcp]==0.27.9\"\npython -m pip install \"dagster-polars[patito]==0.27.9\"\n```\n\n## Prerequisites\n\nBefore wiring this into a project, make sure you already have:\n\n- a Dagster code location with a loadable `defs = dg.Definitions(...)`\n- a storage location for your IO manager, such as a local directory, Delta Lake path, or BigQuery dataset\n- Python `3.10` or newer\n\nFor a simple local Parquet setup, keep the storage root in an environment variable:\n\n```bash\nexport POLARS_BASE_DIR=\"$PWD/.dagster/polars\"\n```\n\n## Register A Polars IO Manager\n\nThe simplest setup uses `PolarsParquetIOManager` and a local filesystem path:\n\n```python\n# src/my_project/definitions.py\nimport os\n\nimport dagster as dg\nimport polars as pl\nfrom dagster_polars import PolarsParquetIOManager\n\n\n@dg.asset(io_manager_key=\"polars_io\")\ndef orders() -> pl.DataFrame:\n    return pl.DataFrame(\n        {\n            \"order_id\": [1, 2, 3],\n            \"customer_id\": [\"c1\", \"c1\", \"c2\"],\n            \"amount\": [19.5, 7.0, 12.25],\n        }\n    )\n\n\n@dg.asset(io_manager_key=\"polars_io\")\ndef customer_totals(orders: pl.LazyFrame) -> pl.LazyFrame:\n    return orders.group_by(\"customer_id\").agg(pl.col(\"amount\").sum())\n\n\ndefs = dg.Definitions(\n    assets=[orders, customer_totals],\n    resources={\n        \"polars_io\": PolarsParquetIOManager(\n            base_dir=os.environ[\"POLARS_BASE_DIR\"],\n        ),\n    },\n)\n```\n\nWhat this example is doing:\n\n- `PolarsParquetIOManager(base_dir=...)` initializes the storage backend\n- `orders() -> pl.DataFrame` writes an eager Polars dataframe\n- `customer_totals(orders: pl.LazyFrame) -> pl.LazyFrame` tells the IO manager to scan lazily on load and sink lazily on output\n- `io_manager_key=\"polars_io\"` binds both assets to the registered resource\n\nRun the code location locally with:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\n## Load Only The Columns You Need\n\nThe integration supports column projection through input metadata. This is useful when an upstream table is wide and the downstream asset only needs a few fields.\n\n```python\nimport dagster as dg\nimport polars as pl\n\n\n@dg.asset(\n    io_manager_key=\"polars_io\",\n    ins={\n        \"orders\": dg.AssetIn(\n            key=\"orders\",\n            metadata={\"columns\": [\"order_id\", \"amount\"]},\n        )\n    },\n)\ndef order_amounts(orders: pl.DataFrame) -> pl.DataFrame:\n    return orders\n```\n\nThe exact behavior depends on the IO manager, but `dagster-polars` uses the `columns` metadata key for partial loading.\n\n## Partitioned Assets\n\nIf your upstream asset is partitioned and each partition lives at a separate path, annotate the input as a dictionary of Polars objects:\n\n```python\nfrom typing import Dict\n\nimport dagster as dg\nimport polars as pl\n\n\ndaily_partitions = dg.DailyPartitionsDefinition(start_date=\"2026-01-01\")\n\n\n@dg.asset(\n    io_manager_key=\"polars_io\",\n    partitions_def=daily_partitions,\n)\ndef daily_orders() -> pl.DataFrame:\n    return pl.DataFrame({\"order_id\": [1], \"amount\": [19.5]})\n\n\n@dg.asset(io_manager_key=\"polars_io\")\ndef all_partitions(\n    daily_orders: Dict[str, pl.DataFrame],\n) -> pl.DataFrame:\n    return pl.concat(daily_orders.values())\n```\n\nIf some upstream partitions may be missing, enable the documented metadata flag:\n\n```python\n@dg.asset(\n    io_manager_key=\"polars_io\",\n    ins={\n        \"daily_orders\": dg.AssetIn(\n            metadata={\"allow_missing_partitions\": True},\n        )\n    },\n)\ndef maybe_complete(\n    daily_orders: Dict[str, pl.LazyFrame],\n) -> pl.DataFrame:\n    return pl.concat([frame.collect() for frame in daily_orders.values()])\n```\n\n## Skip Writes With Optional Outputs\n\nThe integration treats optional Polars outputs specially: if the asset returns `None`, the IO manager skips saving that output.\n\n```python\nfrom typing import Optional\n\nimport dagster as dg\nimport polars as pl\n\n\n@dg.asset(io_manager_key=\"polars_io\")\ndef latest_snapshot() -> Optional[pl.DataFrame]:\n    has_new_data = False\n    if not has_new_data:\n        return None\n\n    return pl.DataFrame({\"status\": [\"updated\"]})\n```\n\n## BigQuery IO Manager\n\n`dagster-polars` also ships a BigQuery IO manager. Install the `gcp` extra and configure the GCP project in environment variables:\n\n```bash\nexport GCP_PROJECT=\"my-gcp-project\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n```python\nimport dagster as dg\nimport polars as pl\nfrom dagster_polars import PolarsBigQueryIOManager\n\n\n@dg.asset(io_manager_key=\"warehouse_io\")\ndef warehouse_orders() -> pl.DataFrame:\n    return pl.DataFrame({\"order_id\": [1], \"amount\": [19.5]})\n\n\ndefs = dg.Definitions(\n    assets=[warehouse_orders],\n    resources={\n        \"warehouse_io\": PolarsBigQueryIOManager(\n            project=dg.EnvVar(\"GCP_PROJECT\"),\n        ),\n    },\n)\n```\n\nThe maintainer docs also note a `gcp_credentials` configuration field when you need to pass a base64-encoded service account key instead of relying on standard Google authentication.\n\n## Common Pitfalls\n\n- Type annotation controls load behavior. If you want lazy reads and writes, annotate the boundary with `pl.LazyFrame`; otherwise the integration loads eagerly as `pl.DataFrame`.\n- Column projection is metadata-driven. The `columns` hint belongs on the Dagster input definition, not inside Polars code.\n- Partition loading changes the input shape. For multi-partition loads, use `dict[str, pl.DataFrame]` or `dict[str, pl.LazyFrame]` instead of a single dataframe.\n- Optional outputs are skipped when they return `None`. Do not assume a physical file or table exists for every run.\n- Most filesystem-style IO managers write each partition to a separate location. For storage-native partitioning in one dataset, use an IO manager that documents a `partition_by` metadata path, such as the Delta Lake integration.\n\n## Version Notes For `0.27.9`\n\n- PyPI lists `dagster-polars==0.27.9` with `Requires: Python >=3.10`.\n- PyPI publishes the extras `deltalake`, `gcp`, and `patito` for `0.27.9`.\n- The current Dagster docs page still refers to installing the Delta Lake integration with `dagster-polars[delta]`, but the PyPI metadata for `0.27.9` publishes the extra as `deltalake`.\n\n## Official Sources\n\n- https://docs.dagster.io/api/python-api/libraries/dagster-polars\n- https://docs.dagster.io/integrations/libraries/polars\n- https://pypi.org/project/dagster-polars/\n- https://github.com/dagster-io/community-integrations/tree/main/libraries/dagster-polars\n"
  },
  {
    "path": "content/dagster/docs/postgres/python/DOC.md",
    "content": "---\nname: postgres\ndescription: \"Dagster PostgreSQL storage package for persistent run, event log, and schedule state in Dagster OSS\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,postgres,postgresql,python,storage,orchestration\"\n---\n\n# dagster-postgres\n\nUse `dagster-postgres` to back a Dagster OSS instance with PostgreSQL. In normal usage, you install it in the same environment as your Dagster services and configure `dagster.yaml`; Dagster then uses PostgreSQL for run storage, event log storage, and schedule or sensor state.\n\nThis guide targets `dagster-postgres 0.28.18`, which belongs to the Dagster `1.12.18` release line.\n\n## Install\n\nInstall `dagster-postgres` alongside the matching Dagster packages used by your deployment:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-postgres==0.28.18\" \\\n  \"dagster-webserver==1.12.18\"\n```\n\nIf you run the daemon for schedules or sensors, install the same package set in that runtime too.\n\n## Before You Configure It\n\nYou need:\n\n- a reachable PostgreSQL server\n- a database and user for Dagster instance metadata\n- a shared `DAGSTER_HOME` directory for the processes that should use this instance\n\nExample shell setup:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nmkdir -p \"$DAGSTER_HOME\"\n\nexport DAGSTER_PG_HOST=\"127.0.0.1\"\nexport DAGSTER_PG_PORT=\"5432\"\nexport DAGSTER_PG_DB=\"dagster\"\nexport DAGSTER_PG_USERNAME=\"dagster\"\nexport DAGSTER_PG_PASSWORD=\"change-me\"\n```\n\nThis package does not have a separate SDK auth flow. Authentication is PostgreSQL authentication through the connection settings you give Dagster.\n\n## Configure Shared PostgreSQL Storage\n\nThe usual setup is a single `storage:` block in `$DAGSTER_HOME/dagster.yaml`:\n\n```yaml\n# $DAGSTER_HOME/dagster.yaml\nstorage:\n  postgres:\n    postgres_db:\n      username:\n        env: DAGSTER_PG_USERNAME\n      password:\n        env: DAGSTER_PG_PASSWORD\n      hostname:\n        env: DAGSTER_PG_HOST\n      db_name:\n        env: DAGSTER_PG_DB\n      port:\n        env: DAGSTER_PG_PORT\n```\n\nWith that file in place, start Dagster normally:\n\n```bash\ndg dev -m my_project.definitions\n```\n\nIf your deployment uses schedules or sensors, run the daemon against the same `DAGSTER_HOME`:\n\n```bash\ndagster-daemon run\n```\n\nThe important operational rule is consistency: the webserver, daemon, and any other Dagster process that should share run history and schedule state must point at the same instance configuration.\n\n## Configure The Storage Components Explicitly\n\nIf you need to wire the instance storages separately, `dagster-postgres` provides one class per storage type:\n\n```yaml\nrun_storage:\n  module: dagster_postgres.run_storage\n  class: PostgresRunStorage\n  config:\n    postgres_db:\n      username:\n        env: DAGSTER_PG_USERNAME\n      password:\n        env: DAGSTER_PG_PASSWORD\n      hostname:\n        env: DAGSTER_PG_HOST\n      db_name:\n        env: DAGSTER_PG_DB\n      port:\n        env: DAGSTER_PG_PORT\n\nevent_log_storage:\n  module: dagster_postgres.event_log\n  class: PostgresEventLogStorage\n  config:\n    postgres_db:\n      username:\n        env: DAGSTER_PG_USERNAME\n      password:\n        env: DAGSTER_PG_PASSWORD\n      hostname:\n        env: DAGSTER_PG_HOST\n      db_name:\n        env: DAGSTER_PG_DB\n      port:\n        env: DAGSTER_PG_PORT\n\nschedule_storage:\n  module: dagster_postgres.schedule_storage\n  class: PostgresScheduleStorage\n  config:\n    postgres_db:\n      username:\n        env: DAGSTER_PG_USERNAME\n      password:\n        env: DAGSTER_PG_PASSWORD\n      hostname:\n        env: DAGSTER_PG_HOST\n      db_name:\n        env: DAGSTER_PG_DB\n      port:\n        env: DAGSTER_PG_PORT\n```\n\nFor most deployments, prefer the single `storage:` block unless you have a specific reason to override the components individually.\n\n## Python Imports For Direct Initialization\n\nMost projects let Dagster construct these storages from `dagster.yaml`, but the package also exposes the storage classes directly:\n\n```python\nimport os\n\nfrom dagster_postgres.event_log import PostgresEventLogStorage\nfrom dagster_postgres.run_storage import PostgresRunStorage\nfrom dagster_postgres.schedule_storage import PostgresScheduleStorage\n\npostgres_url = os.environ[\"DAGSTER_PG_URL\"]\n\nrun_storage = PostgresRunStorage(postgres_url)\nevent_log_storage = PostgresEventLogStorage(postgres_url)\nschedule_storage = PostgresScheduleStorage(postgres_url)\n```\n\nUse this shape for tests or custom instance wiring. For everyday Dagster OSS setup, the `dagster.yaml` configuration is the public interface most users need.\n\n## Common Upgrade Workflow\n\nWhen you upgrade Dagster and `dagster-postgres`, upgrade the release line together and migrate the instance schema before resuming normal traffic:\n\n```bash\npython -m pip install --upgrade \\\n  \"dagster==1.12.18\" \\\n  \"dagster-postgres==0.28.18\" \\\n  \"dagster-webserver==1.12.18\"\n\ndagster instance migrate\n```\n\nRun the migration command with `DAGSTER_HOME` pointing at the instance you want to upgrade.\n\n## Common Pitfalls\n\n- Keep Dagster package versions aligned. `dagster-postgres 0.28.18` is for the Dagster `1.12.18` release line, not an arbitrary core version.\n- Install the package anywhere the instance config is loaded. If the webserver or daemon cannot import `dagster_postgres`, Dagster cannot construct the storage backend.\n- Use one shared instance configuration for all cooperating processes. Separate `DAGSTER_HOME` directories produce separate run history and scheduler state.\n- Keep PostgreSQL credentials in environment variables or another secrets mechanism, not hard-coded in `dagster.yaml`.\n- This package stores Dagster instance metadata. It does not replace IO managers or the storage layer for your actual asset data.\n- After upgrades, run `dagster instance migrate` before assuming the existing PostgreSQL schema is ready.\n\n## Version Notes\n\n- Dagster library packages and Dagster core use different visible version numbers in the same release train. For this guide, that means `dagster-postgres 0.28.18` with Dagster core `1.12.18`.\n- If you are pinning a production deployment, pin the related Dagster packages together instead of upgrading `dagster-postgres` in isolation.\n\n## Official Sources Used\n\n- Dagster `dagster-postgres` package source: `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-postgres`\n- PyPI package page: `https://pypi.org/project/dagster-postgres/`\n- Dagster docs root: `https://docs.dagster.io/`\n- Dagster CLI and OSS docs root: `https://docs.dagster.io/api/clis`\n- Dagster releases: `https://github.com/dagster-io/dagster/releases`\n"
  },
  {
    "path": "content/dagster/docs/slack/python/DOC.md",
    "content": "---\nname: slack\ndescription: \"dagster-slack package guide for posting Slack notifications from Dagster assets, ops, and run-failure sensors\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dagster,dagster-slack,python,slack,notifications,sensors,data-orchestration\"\n---\n\n# dagster-slack Python Package Guide\n\n## Golden Rule\n\nUse `dagster-slack` as a thin Dagster integration around Slack's Web API: keep the Slack token in an environment variable, register `SlackResource` in `dg.Definitions(...)`, and call Slack methods through `slack.get_client()` from assets, ops, or sensors.\n\nKeep `dagster-slack` on the same Dagster release line as the rest of your Dagster packages. For this guide, `dagster-slack==0.28.18` pairs with Dagster `1.12.18`.\n\n## Install\n\nInstall the Slack integration alongside the matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-slack==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-slack\n```\n\n## Prerequisites\n\nBefore using `dagster-slack`, make sure you already have:\n\n- a Slack app with a bot token that can call `chat.postMessage`\n- the bot added to the channel you want Dagster to post into\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- the same package set installed anywhere your Dagster code location, webserver, or daemon imports the code\n\nFor local development, keep the token in an environment variable:\n\n```bash\nexport SLACK_TOKEN=\"xoxb-your-slack-bot-token\"\nexport SLACK_CHANNEL=\"#data-alerts\"\n```\n\nIn production, prefer your deployment platform's secret manager over hard-coded values.\n\n## Register `SlackResource`\n\nThe main modern integration point is `SlackResource`.\n\n```python\nimport dagster as dg\nfrom dagster_slack import SlackResource\n\n\ndefs = dg.Definitions(\n    resources={\n        \"slack\": SlackResource(token=dg.EnvVar(\"SLACK_TOKEN\")),\n    },\n)\n```\n\nThe resource key must match the function parameter name you use for injection.\n\n## Post A Slack Message From An Asset\n\nThis is the simplest pattern to copy into a Dagster project:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_slack import SlackResource\n\n\n@dg.asset\ndef notify_slack(slack: SlackResource) -> None:\n    slack.get_client().chat_postMessage(\n        channel=os.environ.get(\"SLACK_CHANNEL\", \"#data-alerts\"),\n        text=\"Dagster asset materialized successfully.\",\n    )\n\n\ndefs = dg.Definitions(\n    assets=[notify_slack],\n    resources={\n        \"slack\": SlackResource(token=dg.EnvVar(\"SLACK_TOKEN\")),\n    },\n)\n```\n\nImportant details:\n\n- `SlackResource` gives you a Slack Web API client through `get_client()`\n- `chat_postMessage(...)` is the exact Slack API call used to send a message\n- the `slack` parameter name must match the `resources={\"slack\": ...}` key\n- channel IDs are usually more stable than channel names when you move between workspaces or rename channels\n\n## Send Richer Messages\n\nBecause `SlackResource` exposes the underlying Slack client, you can pass normal Slack API arguments such as `blocks`:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_slack import SlackResource\n\n\n@dg.asset\ndef post_run_summary(slack: SlackResource) -> None:\n    slack.get_client().chat_postMessage(\n        channel=os.environ[\"SLACK_CHANNEL\"],\n        text=\"Daily Dagster run finished.\",\n        blocks=[\n            {\n                \"type\": \"section\",\n                \"text\": {\n                    \"type\": \"mrkdwn\",\n                    \"text\": \"*Daily Dagster run finished*\\nAll selected assets completed.\",\n                },\n            }\n        ],\n    )\n```\n\nKeep the top-level `text` field even when you send `blocks`; Slack uses it as the fallback message body.\n\n## Notify On Run Failures\n\n`dagster-slack` also includes a helper for run-failure notifications.\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_slack import SlackResource, make_slack_on_run_failure_sensor\n\n\n@dg.asset\ndef important_asset() -> str:\n    return \"ok\"\n\n\nslack_on_run_failure = make_slack_on_run_failure_sensor(\n    channel=os.environ.get(\"SLACK_CHANNEL\", \"#data-alerts\"),\n    slack_token=os.environ[\"SLACK_TOKEN\"],\n)\n\n\ndefs = dg.Definitions(\n    assets=[important_asset],\n    resources={\n        \"slack\": SlackResource(token=dg.EnvVar(\"SLACK_TOKEN\")),\n    },\n    sensors=[slack_on_run_failure],\n)\n```\n\nUse this when you want one Slack notification path for Dagster run failures without writing a custom sensor body.\n\n## Local Development Workflow\n\nPoint Dagster at the module that exposes your top-level `Definitions` object:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nIf your deployment uses schedules or sensors, run the daemon against the same Dagster instance configuration:\n\n```bash\ndagster-daemon run\n```\n\n## Common Pitfalls\n\n- Version mismatch. Keep `dagster-slack` on the matching Dagster release line in the same environment.\n- Missing channel membership. Slack will reject posts if the bot token cannot post into the target channel.\n- Resource name mismatch. The injected function parameter must match the resource dictionary key.\n- Importing the package in only one process. Install `dagster-slack` anywhere the code location, webserver, or daemon needs to import your definitions.\n- Hard-coding secrets. Keep `SLACK_TOKEN` in environment variables or a secrets manager, not in constant Dagster config.\n- Treating `dagster-slack` as a full Slack abstraction. The package intentionally stays close to the underlying Slack Web API, so message formatting and method arguments still follow Slack's API.\n\n## Version Notes For `0.28.18`\n\n- `dagster-slack==0.28.18` is part of the Dagster `1.12.18` release line.\n- For new Dagster code, prefer `SlackResource` and `dg.Definitions(...)` rather than building around older resource configuration patterns.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-slack\n- https://docs.dagster.io/api/python-api/libraries/dagster-slack\n- https://docs.dagster.io/api/dagster/resources\n- https://docs.dagster.io/api/dagster/schedules-sensors\n- https://pypi.org/project/dagster-slack/\n- https://api.slack.com/methods/chat.postMessage\n"
  },
  {
    "path": "content/dagster/docs/snowflake/python/DOC.md",
    "content": "---\nname: snowflake\ndescription: \"dagster-snowflake package guide for querying Snowflake from Dagster assets and wiring Snowflake-backed asset storage\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-snowflake,python,snowflake,sql,assets,data-warehouse\"\n---\n\n# dagster-snowflake Python Package Guide\n\n## Golden Rule\n\nUse `dagster-snowflake` for Snowflake connections inside Dagster, keep credentials in environment variables, and pin it to the same Dagster release line as the rest of your Dagster packages.\n\nFor this guide, `dagster-snowflake==0.28.18` belongs to the Dagster `1.12.18` release line.\n\n## Install\n\nInstall the Snowflake integration alongside matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-snowflake==0.28.18\"\n```\n\nIf you want Dagster to load and store Pandas DataFrames as Snowflake tables, install the companion I/O manager package too:\n\n```bash\npython -m pip install \\\n  \"dagster-snowflake==0.28.18\" \\\n  \"dagster-snowflake-pandas==0.28.18\"\n```\n\nPyPI lists Python `>=3.10,<3.15` for `dagster-snowflake 0.28.18`.\n\n## Prerequisites\n\nBefore wiring this into Dagster, make sure you already have:\n\n- a Snowflake account\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- a database, schema, and warehouse your Snowflake user can access\n- the same package set installed anywhere your Dagster code location, webserver, or daemon imports the code\n\nThe Dagster Snowflake quickstart uses these environment variables:\n\n```bash\nexport SNOWFLAKE_ACCOUNT=\"xy12345.us-east-1\"\nexport SNOWFLAKE_USER=\"analytics_user\"\nexport SNOWFLAKE_PASSWORD=\"your-password\"\nexport SNOWFLAKE_DATABASE=\"ANALYTICS\"\nexport SNOWFLAKE_SCHEMA=\"PUBLIC\"\nexport SNOWFLAKE_WAREHOUSE=\"COMPUTE_WH\"\n```\n\nThe official Snowflake tutorial documents password authentication and notes that private-key authentication is also supported. The examples here use password auth.\n\n## Query Snowflake With `SnowflakeResource`\n\n`SnowflakeResource` is the main integration point when your asset or op needs to run SQL directly.\n\n```python\nimport dagster as dg\nfrom dagster_snowflake import SnowflakeResource\n\n\n@dg.asset\ndef top_customers(snowflake: SnowflakeResource) -> list[tuple]:\n    with snowflake.get_connection() as conn:\n        rows = (\n            conn.cursor()\n            .execute(\n                \"\"\"\n                select customer_id, total_spend\n                from top_customers\n                order by total_spend desc\n                limit 10\n                \"\"\"\n            )\n            .fetchall()\n        )\n    return rows\n\n\ndefs = dg.Definitions(\n    assets=[top_customers],\n    resources={\n        \"snowflake\": SnowflakeResource(\n            account=dg.EnvVar(\"SNOWFLAKE_ACCOUNT\"),\n            user=dg.EnvVar(\"SNOWFLAKE_USER\"),\n            password=dg.EnvVar(\"SNOWFLAKE_PASSWORD\"),\n            database=dg.EnvVar(\"SNOWFLAKE_DATABASE\"),\n            schema=dg.EnvVar(\"SNOWFLAKE_SCHEMA\"),\n            warehouse=dg.EnvVar(\"SNOWFLAKE_WAREHOUSE\"),\n        ),\n    },\n)\n```\n\nImportant details:\n\n- the resource key in `resources={\"snowflake\": ...}` must match the asset parameter name `snowflake`\n- `snowflake.get_connection()` is the documented Dagster entry point for obtaining a Snowflake connection\n- once you have the connection, use the normal Snowflake Python connector cursor API such as `cursor.execute(...)` and `fetchall()`\n- if you need a non-default Snowflake role, add `role=\"TRANSFORMER\"` or `role=dg.EnvVar(\"SNOWFLAKE_ROLE\")` to the resource configuration\n\n## Store Pandas Assets In Snowflake Tables\n\nIf your Dagster assets already produce Pandas DataFrames, the documented Snowflake table workflow uses `SnowflakePandasIOManager` from `dagster-snowflake-pandas`.\n\n```python\nimport dagster as dg\nimport pandas as pd\nfrom dagster_snowflake_pandas import SnowflakePandasIOManager\n\n\n@dg.asset\ndef orders() -> pd.DataFrame:\n    return pd.DataFrame(\n        [\n            {\"order_id\": 1, \"total\": 125.0},\n            {\"order_id\": 2, \"total\": 80.0},\n        ]\n    )\n\n\n@dg.asset\ndef cleaned_orders(orders: pd.DataFrame) -> pd.DataFrame:\n    return orders.drop_duplicates()\n\n\ndefs = dg.Definitions(\n    assets=[orders, cleaned_orders],\n    resources={\n        \"io_manager\": SnowflakePandasIOManager(\n            account=dg.EnvVar(\"SNOWFLAKE_ACCOUNT\"),\n            user=dg.EnvVar(\"SNOWFLAKE_USER\"),\n            password=dg.EnvVar(\"SNOWFLAKE_PASSWORD\"),\n            database=dg.EnvVar(\"SNOWFLAKE_DATABASE\"),\n            schema=dg.EnvVar(\"SNOWFLAKE_SCHEMA\"),\n            warehouse=dg.EnvVar(\"SNOWFLAKE_WAREHOUSE\"),\n        )\n    },\n)\n```\n\nWith that configuration:\n\n- `io_manager` is the reserved resource key for the default asset I/O manager\n- the `orders` asset is stored as `ANALYTICS.PUBLIC.ORDERS` when your database is `ANALYTICS` and schema is `PUBLIC`\n- downstream assets annotated as `pd.DataFrame` receive Snowflake table data back as DataFrames\n\n## Make An Existing Snowflake Table Available To Dagster\n\nIf the table already exists in Snowflake, represent it as a source asset and let the Snowflake I/O manager load it in downstream assets:\n\n```python\nimport dagster as dg\nimport pandas as pd\n\n\nraw_orders = dg.SourceAsset(key=\"raw_orders\")\n\n\n@dg.asset\ndef high_value_orders(raw_orders: pd.DataFrame) -> pd.DataFrame:\n    return raw_orders[raw_orders[\"total\"] >= 100]\n```\n\nWhen the Snowflake Pandas I/O manager is configured with a database and schema, `SourceAsset(key=\"raw_orders\")` maps to the Snowflake table `DATABASE.SCHEMA.RAW_ORDERS`.\n\n## Common Pitfalls\n\n- Keep Dagster versions aligned. `dagster-snowflake 0.28.18` is for the Dagster `1.12.18` release line, not an arbitrary `dagster` version.\n- Install the package in every runtime that imports your definitions. If the code location can import your project but not `dagster_snowflake`, loading will fail.\n- Keep secrets in environment variables or your deployment secret manager, not hard-coded in `Definitions`.\n- `SnowflakeResource` is for direct connections and SQL. If you want DataFrame assets automatically stored as tables, add the Snowflake Pandas I/O manager package instead of writing that plumbing yourself.\n- The Snowflake table mapping is name-based. An asset or source asset key like `raw_orders` maps to `RAW_ORDERS` in the configured database and schema unless you customize the behavior elsewhere.\n- Use one Snowflake authentication method consistently. The official tutorial documents password or private-key auth; these examples assume password auth.\n\n## Version Notes For `0.28.18`\n\n- PyPI lists `dagster-snowflake 0.28.18` as released on March 5, 2026.\n- Dagster `1.12.19 / 0.28.19` was released on March 12, 2026, so check your project pins before copying these examples into a newer release line.\n- PyPI currently lists two extras for this package: `pandas` and `snowflake-sqlalchemy`.\n\n## Official Sources\n\n- https://pypi.org/project/dagster-snowflake/\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-snowflake\n- https://github.com/dagster-io/dagster/releases\n- https://dagster.io/integrations/dagster-snowflake\n- https://legacy-versioned-docs.dagster.dagster-docs.io/integrations/snowflake/using-snowflake-with-dagster\n- https://github.com/dagster-io/quickstart-snowflake\n- https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api\n- https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-example\n"
  },
  {
    "path": "content/dagster/docs/spark/python/DOC.md",
    "content": "---\nname: spark\ndescription: \"dagster-spark package guide for launching Spark applications from Dagster jobs with spark-submit style configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-spark,python,spark,apache-spark,spark-submit,data-orchestration\"\n---\n\n# dagster-spark Python Package Guide\n\n## Golden Rule\n\nUse `dagster-spark` when a Dagster job needs to launch an existing Spark application through Dagster's job and op model. Keep the Spark installation, Java runtime, cluster access, and storage credentials in normal Spark and Hadoop configuration; `dagster-spark` wires those pieces into Dagster, but it does not replace them.\n\nKeep `dagster-spark` on the same Dagster release line as the rest of your Dagster packages. For this guide, `dagster-spark==0.28.18` pairs with Dagster `1.12.18`.\n\n## Install\n\nInstall the Spark integration alongside the matching Dagster packages:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-spark==0.28.18\"\n```\n\nUseful checks after install:\n\n```bash\ndagster --version\npython -m pip show dagster-spark\n```\n\n## Prerequisites\n\nBefore using `dagster-spark`, make sure your runtime already has:\n\n- a Dagster project with a loadable `defs = dg.Definitions(...)`\n- a working Spark distribution with `spark-submit`\n- a supported Java runtime for that Spark distribution\n- the Spark application artifact you want to launch, such as a JAR file\n- cluster-specific configuration and credentials already handled by Spark, Hadoop, Kubernetes, YARN, or the storage connector you use\n\n`dagster-spark` does not bundle Spark itself. The machine or container that executes the Dagster job still needs access to the Spark installation and to any files or object storage paths passed to the Spark application.\n\n## Configure The Spark Runtime\n\nThe simplest local setup is environment variables that point Dagster at the same Spark runtime you would use from the command line:\n\n```bash\nexport SPARK_HOME=\"/opt/spark\"\nexport JAVA_HOME=\"/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home\"\n```\n\nIf your cluster manager or storage connector depends on Hadoop client configuration, also set the environment variables your Spark installation expects, for example:\n\n```bash\nexport HADOOP_CONF_DIR=\"/etc/hadoop/conf\"\nexport YARN_CONF_DIR=\"/etc/hadoop/conf\"\n```\n\nPractical rule: anything you would normally need for `spark-submit` must already be present where Dagster runs the op.\n\n## Create A Spark Op\n\nThe package centers on `create_spark_op(...)` together with the `spark_resource` resource definition.\n\nThis example launches the Spark word-count example JAR from a Dagster job:\n\n```python\nimport os\n\nimport dagster as dg\nfrom dagster_spark import create_spark_op, spark_resource\n\n\nwordcount = create_spark_op(\n    name=\"wordcount\",\n    main_class=\"org.apache.spark.examples.JavaWordCount\",\n    application_jar=\"/opt/spark/examples/jars/spark-examples_2.12-3.5.1.jar\",\n    description=\"Run the Spark JavaWordCount example from Dagster\",\n)\n\n\n@dg.job(\n    resource_defs={\n        \"spark\": spark_resource.configured(\n            {\n                \"spark_home\": os.environ[\"SPARK_HOME\"],\n            }\n        )\n    }\n)\ndef spark_wordcount_job():\n    wordcount()\n\n\ndefs = dg.Definitions(jobs=[spark_wordcount_job])\n```\n\nImportant details:\n\n- the resource key must be `spark` for the op created by `create_spark_op(...)`\n- `spark_home` should point at the Spark installation root that contains `bin/spark-submit`\n- `application_jar` and `main_class` identify the Spark application Dagster should submit\n\n## Pass Run Config To The Spark Op\n\nUse Dagster run config to supply application arguments and Spark configuration values that normally belong on `spark-submit`.\n\n```python\nrun_config = {\n    \"ops\": {\n        \"wordcount\": {\n            \"config\": {\n                \"application_arguments\": [\n                    \"/data/input.txt\",\n                ],\n                \"spark_conf\": {\n                    \"spark.master\": \"local[*]\",\n                    \"spark.app.name\": \"dagster-wordcount\",\n                    \"spark.driver.memory\": \"1g\",\n                },\n            }\n        }\n    }\n}\n\nresult = spark_wordcount_job.execute_in_process(run_config=run_config)\n```\n\nThe important keys to remember are:\n\n- `application_arguments` for the arguments passed into the Spark application\n- `spark_conf` for standard Spark properties such as `spark.master` or memory settings\n\nIf you already launch the same application from a shell script, move those settings into Dagster run config instead of duplicating them in several places.\n\n## Typical Development Workflow\n\nExpose your Dagster definitions from an importable module:\n\n```python\n# src/my_project/definitions.py\nimport dagster as dg\n\nfrom .spark_jobs import spark_wordcount_job\n\n\ndefs = dg.Definitions(jobs=[spark_wordcount_job])\n```\n\nRun the code location locally:\n\n```bash\ndagster dev -m my_project.definitions\n```\n\nThen launch the job from the UI or a schedule with the same run config shape shown above.\n\n## Common Pitfalls\n\n- Version mismatch. Keep `dagster-spark` on the matching Dagster release line instead of upgrading one Dagster library in isolation.\n- Missing Spark runtime. Installing `dagster-spark` with pip does not install `spark-submit`, Spark JARs, or Java.\n- Wrong execution path. The application JAR and any input paths must be reachable from the environment where Dagster launches Spark, not only from your laptop.\n- Missing cluster credentials. Access to S3, HDFS, Hive, or YARN is still handled by Spark and Hadoop configuration, not by a Dagster-specific auth client.\n- Assuming local files exist on executors. For cluster execution, prefer storage locations and connector settings that the whole Spark runtime can reach.\n- Treating this package like an asset-native API. `dagster-spark` fits best when you already have a Spark application to submit and want Dagster to orchestrate that submission.\n\n## Version Notes For `0.28.18`\n\n- This guide targets `dagster-spark==0.28.18`.\n- Keep the package aligned with the Dagster `1.12.18` release line.\n- For new Dagster projects, use `dagster-spark` when you need Spark submission from Dagster jobs; keep the rest of the project on modern `Definitions`-based loading even if the Spark integration itself is op-oriented.\n\n## Official Sources\n\n- `https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-spark`\n- `https://docs.dagster.io/api/python-api/libraries/dagster-spark`\n- `https://docs.dagster.io/api/dagster/ops-jobs-graphs`\n- `https://spark.apache.org/docs/latest/submitting-applications.html`\n- `https://spark.apache.org/docs/latest/configuration.html`\n- `https://pypi.org/project/dagster-spark/`\n"
  },
  {
    "path": "content/dagster/docs/wandb/python/DOC.md",
    "content": "---\nname: wandb\ndescription: \"dagster-wandb package guide for using Weights & Biases artifacts and W&B runs from Dagster assets and jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,dagster-wandb,python,wandb,weights-and-biases,artifacts,mlops\"\n---\n\n# dagster-wandb Python Package Guide\n\n## Golden Rule\n\nUse `dagster-wandb` for the Dagster-specific integration points and keep normal W&B authentication in W&B's own settings. In practice, that means:\n\n- set `WANDB_API_KEY`\n- provide your W&B `entity` and `project` through `wandb_config`\n- use `wandb_artifacts_io_manager` for artifact reads and writes\n- if you call `wandb.init(...)` yourself inside an op or asset, keep the W&B run id aligned with the Dagster run id\n\n## Install\n\nInstall the integration alongside Dagster. If your code imports W&B types such as `wandb.Artifact` or `wandb.Table`, install `wandb` explicitly too:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\" \\\n  \"dagster-wandb==0.28.18\" \\\n  \"wandb\"\n```\n\nDagster `1.12.18` on PyPI requires Python `>=3.10,<3.15`.\n\n## Prerequisites And Auth\n\nCreate a W&B API key, then keep credentials and project defaults in environment variables:\n\n```bash\nexport WANDB_API_KEY=\"...\"\nexport WANDB_ENTITY=\"my-team\"\nexport WANDB_PROJECT=\"feature-store\"\n```\n\nIf you use a dedicated or self-managed W&B deployment, W&B documents `WANDB_BASE_URL` for the API host:\n\n```bash\nexport WANDB_BASE_URL=\"https://wandb.example.com\"\n```\n\n`dagster-wandb` also exposes a `host` config field on `wandb_resource` for the same purpose.\n\n## Write And Read W&B Artifacts From Assets\n\nThis is the main workflow the package is built for: materialize an asset into a W&B artifact, then load a named object back out of that artifact in a downstream asset.\n\n```python\nimport os\n\nimport dagster as dg\nimport wandb\nfrom dagster_wandb import wandb_artifacts_io_manager, wandb_resource\nfrom wandb import Artifact\n\n\n@dg.asset(\n    name=\"training_metrics\",\n    compute_kind=\"wandb\",\n    metadata={\n        \"wandb_artifact_configuration\": {\n            \"description\": \"Validation accuracy by epoch\",\n            \"aliases\": [\"latest\"],\n        }\n    },\n    io_manager_key=\"wandb_artifacts_manager\",\n)\ndef training_metrics() -> Artifact:\n    artifact = wandb.Artifact(\"training_metrics\", \"dataset\")\n    artifact.add(\n        wandb.Table(\n            columns=[\"epoch\", \"accuracy\"],\n            data=[[1, 0.91], [2, 0.94], [3, 0.95]],\n        ),\n        \"metrics_table\",\n    )\n    return artifact\n\n\n@dg.asset(\n    compute_kind=\"wandb\",\n    ins={\n        \"table\": dg.AssetIn(\n            key=\"training_metrics\",\n            input_manager_key=\"wandb_artifacts_manager\",\n            metadata={\n                \"wandb_artifact_configuration\": {\n                    \"get\": \"metrics_table\",\n                }\n            },\n        )\n    },\n    output_required=False,\n)\ndef inspect_metrics(\n    context: dg.AssetExecutionContext,\n    table: wandb.Table,\n) -> None:\n    context.log.info(f\"accuracies={table.get_column('accuracy')}\")\n\n\nassets = dg.with_resources(\n    [training_metrics, inspect_metrics],\n    resource_defs={\n        \"wandb_config\": dg.make_values_resource(entity=str, project=str),\n        \"wandb_resource\": wandb_resource.configured(\n            {\"api_key\": {\"env\": \"WANDB_API_KEY\"}}\n        ),\n        \"wandb_artifacts_manager\": wandb_artifacts_io_manager.configured(\n            {\"cache_duration_in_minutes\": 60}\n        ),\n    },\n    resource_config_by_key={\n        \"wandb_config\": {\n            \"config\": {\n                \"entity\": os.environ[\"WANDB_ENTITY\"],\n                \"project\": os.environ[\"WANDB_PROJECT\"],\n            }\n        }\n    },\n)\n\ndefs = dg.Definitions(assets=assets)\n```\n\nImportant details:\n\n- `wandb_resource` handles W&B auth for the integration and reads `WANDB_API_KEY` in this example\n- `wandb_config` is where the integration expects `entity` and `project`\n- `io_manager_key=\"wandb_artifacts_manager\"` is what tells Dagster to store the asset in W&B\n- `metadata[\"wandb_artifact_configuration\"][\"get\"]` loads a named object from the upstream artifact instead of downloading the whole artifact yourself\n\n## Direct W&B Run Tracking Inside An Op Or Asset\n\nIf you also log metrics directly with the W&B SDK, use Dagster's run id as the W&B run id. The W&B integration docs call this out as the safest way to keep one W&B run attached to one Dagster execution.\n\n```python\nimport dagster as dg\nimport wandb\n\n\n@dg.op\ndef track_training_run(context: dg.OpExecutionContext) -> None:\n    run = wandb.init(\n        id=context.run_id,\n        resume=\"allow\",\n        project=\"feature-store\",\n        entity=\"my-team\",\n    )\n    run.log({\"accuracy\": 0.95})\n    run.finish()\n```\n\n## Common Pitfalls\n\n- Missing `entity` or `project`. `WANDB_API_KEY` is not enough by itself for the Dagster integration examples; the package also expects `wandb_config`.\n- Wrong host for dedicated deployments. Set `host` on `wandb_resource` or `WANDB_BASE_URL` for self-managed W&B.\n- Downloading too much data. Use artifact config keys such as `get` or `get_path` when you only need one named object or file from an artifact.\n- Partition limits. The integration docs note that the artifact IO manager does not support materializing multiple partitions in a single run.\n- Mixed run identity. If you call `wandb.init(...)` manually, reuse `context.run_id` and `resume=\"allow\"` so repeated retries do not create unrelated W&B runs.\n\n## Version Notes For `0.28.18`\n\n- This guide targets `dagster-wandb==0.28.18`.\n- Keep your Dagster packages on the same release line instead of upgrading `dagster-wandb` in isolation.\n- W&B Launch support exists in the package through `run_launch_agent` and `run_launch_job`, but the W&B docs label Launch as a beta product and describe it as a pilot program. Treat artifact workflows as the default path unless you already run Launch agents.\n\n## Official Sources\n\n- https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-wandb\n- https://docs.dagster.io/api/python-api/libraries/dagster-wandb\n- https://docs.wandb.ai/models/integrations/dagster\n- https://docs.wandb.ai/models/ref/cli/wandb-login\n- https://docs.wandb.ai/models/app/settings-page/api-keys\n- https://pypi.org/project/dagster/\n- https://pypi.org/project/dagster-wandb/\n"
  },
  {
    "path": "content/dagster/docs/webserver/python/DOC.md",
    "content": "---\nname: webserver\ndescription: \"Dagster Webserver package guide for hosting the Dagster OSS UI, loading code locations, and configuring instance-backed deployments\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"dagster,python,webserver,ui,graphql,orchestration\"\n---\n\n# Dagster Webserver Package Guide\n\n## Golden Rule\n\nUse `dagster-webserver` as the process that hosts the Dagster OSS UI for an already loadable Dagster code location. Your application logic still lives in `dagster` code such as a top-level `defs = dg.Definitions(...)` object; `dagster-webserver` is the server around that code and your Dagster instance.\n\nIf you only need the standard local developer workflow, `dagster dev` or `dg dev` is usually the simpler entrypoint. Reach for `dagster-webserver` when you need explicit control over host, port, path prefix, read-only mode, or workspace loading.\n\n## Install\n\n`dagster-webserver 1.12.18` requires Python `>=3.10,<3.15` and depends on the matching `dagster` and `dagster-graphql` release line.\n\nInstall the webserver with the same Dagster core version:\n\n```bash\npython -m pip install \\\n  \"dagster==1.12.18\" \\\n  \"dagster-webserver==1.12.18\"\n```\n\nIf you want notebook rendering in the UI's notebook download endpoint, install the optional extra:\n\n```bash\npython -m pip install \"dagster-webserver[notebook]==1.12.18\"\n```\n\n## Minimal Code Location\n\nThe webserver needs a loadable Dagster module. For new code, use a top-level `Definitions` object:\n\n```python\n# src/my_project/definitions.py\nimport dagster as dg\n\n@dg.asset\ndef hello() -> str:\n    return \"hello\"\n\ndefs = dg.Definitions(assets=[hello])\n```\n\nThe important part is that the module exposes a top-level symbol that Dagster can load.\n\n## Start The Webserver\n\n### Load a Python module directly\n\nFor a persistent Dagster instance, point `DAGSTER_HOME` at a real directory before starting the server:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nmkdir -p \"$DAGSTER_HOME\"\n\ndagster-webserver -m my_project.definitions\n```\n\nWhat this does:\n\n- loads the code location from `my_project.definitions`\n- binds to `127.0.0.1` by default\n- uses port `3000` by default\n- falls back to another free port if `3000` is already in use\n\nIf `DAGSTER_HOME` is not set, the CLI creates a temporary instance directory under the current working directory and removes it when the process exits. That is fine for short local sessions, but run history and other instance state will not persist.\n\n### Load from `workspace.yaml`\n\nUse a workspace file when you want explicit code-location wiring or multiple code locations:\n\n```yaml\n# workspace.yaml\nload_from:\n  - python_module:\n      module_name: my_project.definitions\n      working_directory: .\n      location_name: my-project\n```\n\nThen start the server with:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nmkdir -p \"$DAGSTER_HOME\"\n\ndagster-webserver -w workspace.yaml\n```\n\nThe workspace schema also supports `python_file`, `python_package`, and `grpc_server` targets.\n\n### Legacy attribute loading\n\nIf you still load a legacy repository or job symbol instead of a top-level `Definitions` object, pass `-a`:\n\n```bash\ndagster-webserver -f path/to/repo.py -a define_repo\n```\n\nFor new projects, prefer module loading with a top-level `defs` object.\n\n## Environment Variables And Startup Options\n\nThe CLI supports environment variables prefixed with `DAGSTER_WEBSERVER_`.\n\nCommon setup:\n\n```bash\nexport DAGSTER_HOME=\"$PWD/.dagster\"\nexport DAGSTER_WEBSERVER_HOST=\"0.0.0.0\"\nexport DAGSTER_WEBSERVER_PORT=\"3333\"\nexport DAGSTER_WEBSERVER_LOG_LEVEL=\"info\"\n\ndagster-webserver -m my_project.definitions\n```\n\nUseful options:\n\n- `--host` / `-h` changes the bind address; default is `127.0.0.1`\n- `--port` / `-p` changes the port; default is `3000`\n- `--path-prefix` / `-l` hosts the UI under a subpath such as `/dagster`\n- `--read-only` disables mutations such as launching runs and toggling schedules\n- `--uvicorn-log-level` controls the ASGI server logs\n- `--dagster-log-level` controls Dagster log events\n- `--live-data-poll-rate` changes UI polling frequency in milliseconds\n\nThe CLI also maps legacy `DAGIT_*` environment variables to `DAGSTER_WEBSERVER_*` for backward compatibility, but the `dagit` command and that environment-variable prefix are deprecated for Dagster `2.0`.\n\n## Verify The Server From Python\n\n`dagster-webserver` exposes a simple JSON endpoint at `/server_info`. This is a safe way to confirm that the process is up and that the package versions match what you expect:\n\n```python\nimport json\nfrom urllib.request import urlopen\n\nwith urlopen(\"http://127.0.0.1:3000/server_info\") as response:\n    info = json.load(response)\n\nprint(info[\"dagster_webserver_version\"])\nprint(info[\"dagster_version\"])\nprint(info[\"dagster_graphql_version\"])\n```\n\nThe server also exposes `/graphql` over HTTP and WebSocket for the UI and GraphQL-based automation.\n\n## Common Workflows\n\n### Run behind a reverse proxy\n\nWhen the UI is hosted under a subpath, set `--path-prefix` to the external mount point:\n\n```bash\ndagster-webserver \\\n  -m my_project.definitions \\\n  --host 0.0.0.0 \\\n  --port 3000 \\\n  --path-prefix /dagster\n```\n\nThe prefix must start with `/` and must not end with `/`.\n\n### Expose a read-only UI\n\nFor environments where users should inspect runs but not launch new ones or modify schedules, start the server in read-only mode:\n\n```bash\ndagster-webserver -w workspace.yaml --read-only\n```\n\n### Rely on a local `.env` file\n\nDagster CLI startup loads environment variables from a `.env` file in the current working directory. That is useful for local credentials and instance settings without hard-coding secrets into your Dagster definitions.\n\nExample:\n\n```dotenv\n# .env\nDAGSTER_HOME=/absolute/path/to/.dagster\nDAGSTER_WEBSERVER_PORT=3333\nMY_API_TOKEN=replace-me\n```\n\nThen start the server from that directory:\n\n```bash\ndagster-webserver -m my_project.definitions\n```\n\n## Common Pitfalls\n\n- Forgetting that the server only hosts a code location. Your module still needs a loadable top-level Dagster definition, usually `defs = dg.Definitions(...)`.\n- Starting without `DAGSTER_HOME` and assuming instance state will persist. Without it, the CLI uses a temporary instance directory that is deleted on exit.\n- Using different `DAGSTER_HOME` directories for cooperating processes. If your webserver and daemon should share run history or scheduler state, point them at the same instance.\n- Passing an invalid path prefix. The prefix must begin with `/` and cannot end with `/`.\n- Mixing Dagster package versions. `dagster-webserver 1.12.18` is built for `dagster 1.12.18` and `dagster-graphql 1.12.18`.\n- Expecting notebook downloads to work without extras. The notebook endpoint requires `nbconvert`, which the package exposes through `dagster-webserver[notebook]`.\n\n## Version Notes For `1.12.18`\n\n- PyPI metadata for `dagster-webserver 1.12.18` declares Python support for `3.10` through `3.14`.\n- The package depends on `dagster==1.12.18` and `dagster-graphql==1.12.18`, so keep the Dagster release line aligned in one environment.\n- The `dagit` CLI name is still supported for backward compatibility, but the code warns that it will be removed in Dagster `2.0`. Use `dagster-webserver` for new scripts and docs.\n\n## Official Sources Used\n\n- https://pypi.org/project/dagster-webserver/\n- https://github.com/dagster-io/dagster\n- https://github.com/dagster-io/dagster/tree/master/python_modules/dagster-webserver\n- https://docs.dagster.io/api/clis\n- https://docs.dagster.io/api\n- https://github.com/dagster-io/dagster/releases\n"
  },
  {
    "path": "content/dash/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Dash package guide for Python projects building reactive web apps with Plotly Dash 4\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dash,plotly,python,web,callbacks,data-visualization,flask\"\n---\n\n# Dash Python Package Guide\n\n## Golden Rule\n\nUse `dash` as the app shell and callback framework, import components from `dash`, and keep long-running work out of normal request-thread callbacks. For `4.0.0`, also treat component styling and some default values as upgrade-sensitive.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"dash==4.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dash==4.0.0\"\npoetry add \"dash==4.0.0\"\n```\n\nUseful extras from the official package metadata:\n\n```bash\npython -m pip install \"dash[async]==4.0.0\"\npython -m pip install \"dash[testing]==4.0.0\"\npython -m pip install \"dash[diskcache]==4.0.0\"\npython -m pip install \"dash[celery]==4.0.0\"\npython -m pip install \"dash[cloud]==4.0.0\"\n```\n\nNotes:\n\n- The installation guide states that `plotly` is installed with `dash`.\n- Many tutorial examples also assume `pandas` is installed for data loading and `plotly.express`.\n- `dash[testing]` is the supported way to install `dash.testing` and pytest fixtures.\n\n## Initialize A Minimal App\n\n```python\nfrom dash import Dash, dcc, html\nimport plotly.express as px\nimport pandas as pd\n\ndf = pd.DataFrame(\n    {\n        \"Fruit\": [\"Apples\", \"Oranges\", \"Bananas\", \"Apples\", \"Oranges\", \"Bananas\"],\n        \"Amount\": [4, 1, 2, 2, 4, 5],\n        \"City\": [\"SF\", \"SF\", \"SF\", \"Montreal\", \"Montreal\", \"Montreal\"],\n    }\n)\n\nfig = px.bar(df, x=\"Fruit\", y=\"Amount\", color=\"City\", barmode=\"group\")\n\napp = Dash()\napp.layout = html.Div(\n    [\n        html.H1(\"Hello Dash\"),\n        html.Div(\"Dash: a web application framework for your data.\"),\n        dcc.Graph(id=\"example-graph\", figure=fig),\n    ]\n)\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\nRun the app with:\n\n```bash\npython app.py\n```\n\nThe default local dev server listens on `http://127.0.0.1:8050/`.\n\n## Core Usage\n\n### Write callbacks with `@callback`\n\nDash callbacks connect component properties to Python functions. The standard import pattern in the current docs is:\n\n```python\nfrom dash import Dash, dcc, html, Input, Output, callback\n\napp = Dash()\napp.layout = html.Div(\n    [\n        dcc.Input(id=\"my-input\", value=\"initial value\", type=\"text\"),\n        html.Div(id=\"my-output\"),\n    ]\n)\n\n@callback(\n    Output(\"my-output\", \"children\"),\n    Input(\"my-input\", \"value\"),\n)\ndef update_output(value: str) -> str:\n    return f\"Output: {value}\"\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\n### Multi-page apps with Dash Pages\n\nFor new apps, prefer Dash Pages instead of hand-rolled URL routing.\n\n`app.py`:\n\n```python\nfrom dash import Dash, html, dcc, page_container, page_registry\n\napp = Dash(__name__, use_pages=True)\napp.layout = html.Div(\n    [\n        html.H1(\"My app\"),\n        html.Nav(\n            [\n                dcc.Link(f\"{page['name']}\", href=page[\"relative_path\"])\n                for page in page_registry.values()\n            ]\n        ),\n        page_container,\n    ]\n)\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\n`pages/home.py`:\n\n```python\nimport dash\nfrom dash import html\n\ndash.register_page(__name__, path=\"/\")\n\nlayout = html.Div(\"Home page\")\n```\n\nKey rules:\n\n- Create a `/pages` directory.\n- Call `dash.register_page(__name__)` in each page module.\n- Set `use_pages=True` on the app.\n- Put `dash.page_container` where routed page content should render.\n\n### Use `ctx`, `PreventUpdate`, and `no_update` for real callback control\n\nThese patterns are essential once apps move beyond toy examples:\n\n```python\nfrom dash import Dash, Input, Output, callback, ctx, html, no_update\nfrom dash.exceptions import PreventUpdate\n\napp = Dash()\napp.layout = html.Div(\n    [\n        html.Button(\"A\", id=\"btn-a\"),\n        html.Button(\"B\", id=\"btn-b\"),\n        html.Div(id=\"result\"),\n    ]\n)\n\n@callback(\n    Output(\"result\", \"children\"),\n    Input(\"btn-a\", \"n_clicks\"),\n    Input(\"btn-b\", \"n_clicks\"),\n)\ndef show_trigger(btn_a, btn_b):\n    if not ctx.triggered_id:\n        raise PreventUpdate\n    if ctx.triggered_id == \"btn-a\":\n        return \"A clicked\"\n    return no_update\n```\n\nUse these intentionally:\n\n- `ctx.triggered_id`: determine which input fired\n- `PreventUpdate`: stop all outputs from changing\n- `no_update`: keep one output unchanged while updating others\n- `prevent_initial_call=True`: avoid callback execution on first page load when that behavior is unwanted\n\n### Use background callbacks for slow work\n\nNormal callbacks run in the web request path. The docs call out 30 second web-server timeouts as a common problem for long jobs. Use background callbacks for expensive work:\n\n```python\nimport os\nfrom dash import Dash, Input, Output, html, callback, DiskcacheManager, CeleryManager\n\nif \"REDIS_URL\" in os.environ:\n    from celery import Celery\n\n    celery_app = Celery(__name__, broker=os.environ[\"REDIS_URL\"], backend=os.environ[\"REDIS_URL\"])\n    background_callback_manager = CeleryManager(celery_app)\nelse:\n    import diskcache\n\n    cache = diskcache.Cache(\"./cache\")\n    background_callback_manager = DiskcacheManager(cache)\n\napp = Dash(background_callback_manager=background_callback_manager)\napp.layout = html.Div([html.Button(\"Run\", id=\"run\"), html.Div(id=\"result\")])\n\n@callback(\n    Output(\"result\", \"children\"),\n    Input(\"run\", \"n_clicks\"),\n    background=True,\n    prevent_initial_call=True,\n)\ndef run_job(n_clicks):\n    return f\"Started job {n_clicks}\"\n```\n\nOperational guidance:\n\n- Use `dash[diskcache]` for local development.\n- Use `dash[celery]` plus Redis or another Celery broker for production.\n- Background callbacks replaced long callbacks in Dash 3.0; do not build new code on the removed long-callback API.\n\n### Async callbacks are available\n\nDash supports `async` and `await` in callbacks when installed with `dash[async]`.\n\n```python\nimport asyncio\nfrom dash import Dash, Input, Output, html\n\napp = Dash()\napp.layout = html.Div(\n    [\n        html.Button(\"Run\", id=\"run\"),\n        html.Div(id=\"out\"),\n    ]\n)\n\n@app.callback(Output(\"out\", \"children\"), Input(\"run\", \"n_clicks\"), prevent_initial_call=True)\nasync def fetch_data(_):\n    await asyncio.sleep(1)\n    return \"done\"\n```\n\nThe advanced callbacks page notes a deployment caveat: if you use `gunicorn`, use the `gthread` worker class, not `gevent`.\n\n## Assets, Server, And Configuration\n\n### Assets\n\nDash automatically serves files placed in an `assets/` directory at the app root.\n\n```text\napp.py\nassets/\n  typography.css\n  custom-script.js\n```\n\nImportant details from the official docs:\n\n- The default assets URL path is `/assets`.\n- You can change it with the `assets_url_path` argument to `Dash`.\n- In Dash `2.14+`, `__name__` is no longer required in the `Dash(...)` constructor for these examples, so `Dash()` is fine in `4.0.0`.\n\n### Server object\n\nIf you need Flask-level integration for deployment or middleware, Dash exposes the underlying server:\n\n```python\napp = Dash()\nserver = app.server\n```\n\nThis is the integration point to use when your deployment stack expects a WSGI app object or when you need to add Flask-side behavior around the Dash app.\n\n### Authentication\n\nAuthentication is not a first-class setup step in the Dash OSS package docs. In practice, treat auth as a deployment concern and implement it in the hosting layer, reverse proxy, or the underlying Flask server rather than expecting `dash` itself to provide a complete login system.\n\n## Testing\n\nDash ships a supported testing surface in `dash.testing`:\n\n```bash\npython -m pip install \"dash[testing]==4.0.0\"\n```\n\nThe testing docs describe two main layers:\n\n- callback unit tests\n- end-to-end browser tests with Dash pytest fixtures\n\nIf you use Zsh, escape the bracket form when needed:\n\n```bash\npython -m pip install dash\\[testing\\]\n```\n\n## Common Pitfalls\n\n- Forgetting that callbacks fire on initial page load. Use `prevent_initial_call=True` when the first run is undesirable.\n- Blocking the request thread with heavy work. Move slow tasks to background callbacks instead of increasing web-server timeouts and hoping for the best.\n- Expecting dynamic or conditional components to exist for every callback. For dynamic layouts, use `allow_optional=True` where appropriate, and use `suppress_callback_exceptions=True` only when you truly need it.\n- Missing the current input that triggered a callback. Prefer `ctx.triggered_id` over brittle parsing of older `callback_context.triggered` shapes.\n- Keeping large mutable state in Python globals. For browser-side JSON-sized state, use `dcc.Store`; for server-side shared state, use a real cache or datastore.\n- Continuing to build on `dash_table.DataTable` without a migration plan. The official docs mark Dash DataTable as deprecated and state that it will be removed from the core Dash API in Dash 5.0; new table-heavy work should evaluate `dash-ag-grid`.\n- Assuming old CSS will survive the Dash 4 upgrade unchanged. Dash 4 updates the styling of several core components and changes some defaults, especially around sliders and dropdowns.\n\n## Version-Sensitive Notes For `4.0.0`\n\n- PyPI lists `dash 4.0.0` as the latest stable release, released on February 3, 2026. PyPI also shows `4.1.0rc0` on February 23, 2026, so avoid pinning to `4.1` behavior unless you explicitly want a release candidate.\n- The Dash 4 release updates styling for many `dcc` components. If your app has custom CSS targeting Dash-generated class names or previous visual defaults, regression-test the UI before upgrading.\n- `dcc.Dropdown` defaults changed in Dash 4: `optionHeight` now defaults to `auto`, and `closeOnSelect` defaults to `True` for single-select and `False` for multi-select dropdowns.\n- Slider `step` behavior changed in Dash 4. It is still `1` when `min` and `max` are integers, but otherwise it is dynamically computed.\n- `dcc.Button` is new in Dash 4 and is styled to match other Dash Core Components.\n- Features introduced during the Dash 2.x and 3.x line remain relevant in `4.0.0`, including Pages (`2.5`), partial property updates (`2.9`), `running` callback output updates (`2.16`), `async` callbacks (`3.1`), and optional callback inputs (`3.1`).\n\n## Official Sources\n\n- Dash docs root: `https://dash.plotly.com/`\n- Installation: `https://dash.plotly.com/installation`\n- Layout: `https://dash.plotly.com/layout`\n- Basic callbacks: `https://dash.plotly.com/basic-callbacks`\n- Multi-page apps and URLs: `https://dash.plotly.com/urls`\n- Advanced callbacks: `https://dash.plotly.com/advanced-callbacks`\n- Background callbacks: `https://dash.plotly.com/background-callbacks`\n- External resources and assets: `https://dash.plotly.com/external-resources`\n- Dash 4 release notes: `https://dash.plotly.com/whats-new-in-dash-4`\n- DataTable reference and deprecation notice: `https://dash.plotly.com/datatable/reference`\n- Testing: `https://dash.plotly.com/testing`\n- PyPI package metadata: `https://pypi.org/project/dash/`\n"
  },
  {
    "path": "content/dask/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Dask package guide for Python projects using the official Dask and distributed docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dask,python,parallel,distributed,dataframe,array,scheduling\"\n---\n\n# Dask Python Package Guide\n\n## Golden Rule\n\nUse Dask for lazy parallel collections and task graphs, and install the extra set that matches the features you actually need. Plain `dask` is enough for some core graph APIs, but `dask.dataframe`, the distributed scheduler, dashboard, and many filesystem integrations require optional dependencies.\n\n## Install\n\nPin the version your project expects.\n\nFor most projects, the safest default is:\n\n```bash\npython -m pip install \"dask[complete]==2026.1.2\"\n```\n\nTargeted installs are smaller:\n\n```bash\npython -m pip install \"dask[array]==2026.1.2\"\npython -m pip install \"dask[dataframe]==2026.1.2\"\npython -m pip install \"dask[distributed]==2026.1.2\"\npython -m pip install \"dask[diagnostics]==2026.1.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dask[complete]==2026.1.2\"\npoetry add \"dask[complete]==2026.1.2\"\n```\n\nNotes:\n\n- Use `dask[complete]` when you are not sure which collections, dataframe engines, or scheduler features the code path will need.\n- Remote filesystems usually need backend packages in addition to Dask, such as `s3fs` for `s3://...`, `gcsfs` for `gcs://...`, or `adlfs` for Azure paths.\n- If you only install `dask` and then import `dask.dataframe` or `dask.distributed`, import errors are usually missing optional dependencies, not bad Dask syntax.\n\n## Execution Model And Setup\n\nDask collections are lazy. Build a graph first, then trigger execution with `.compute()`, `.persist()`, or a distributed `Client`.\n\nLocal single-process or threaded usage does not require a client:\n\n```python\nimport dask.array as da\n\nx = da.random.random((50_000, 1_000), chunks=(5_000, 1_000))\nmean = x.mean()\n\nprint(mean.compute())\n```\n\nStart a client when you want the distributed scheduler, dashboard, futures API, or multi-process execution:\n\n```python\nfrom dask.distributed import Client\n\nclient = Client()\nprint(client)\n```\n\nFor explicit local cluster sizing:\n\n```python\nfrom dask.distributed import Client, LocalCluster\n\ncluster = LocalCluster(\n    n_workers=4,\n    threads_per_worker=2,\n    memory_limit=\"4GiB\",\n)\nclient = Client(cluster)\n```\n\n## Core Usage\n\n### DataFrame\n\nUse `dask.dataframe` when pandas would be too large for one process or you want parallel file IO and shuffles.\n\n```python\nimport dask.dataframe as dd\n\nddf = dd.read_parquet(\"data/events/*.parquet\")\n\ndaily_totals = (\n    ddf[[\"user_id\", \"amount\", \"event_date\"]]\n    .groupby([\"event_date\", \"user_id\"])\n    .amount.sum()\n    .reset_index()\n)\n\nresult = daily_totals.compute()\nprint(result.head())\n```\n\nIf you will reuse an expensive intermediate more than once, persist it once instead of recomputing the whole graph each time:\n\n```python\nfiltered = ddf[ddf.amount > 0].persist()\ntop_users = filtered.groupby(\"user_id\").amount.sum()\nprint(top_users.nlargest(10).compute())\n```\n\n### Array\n\nUse `dask.array` for NumPy-like chunked arrays:\n\n```python\nimport dask.array as da\n\nx = da.from_zarr(\"data/training-array.zarr\")\ny = (x - x.mean(axis=0)) / x.std(axis=0)\n\nprint(y[:1000].compute())\n```\n\nChoose chunk sizes so several chunks fit comfortably in worker memory. Tiny chunks create large graphs and scheduler overhead; giant chunks cause memory pressure.\n\n### Delayed\n\nUse `dask.delayed` for Python functions that are not already expressed as Dask collections:\n\n```python\nimport dask\n\n@dask.delayed\ndef load_value(path: str) -> int:\n    with open(path) as f:\n        return int(f.read().strip())\n\n@dask.delayed\ndef combine(values: list[int]) -> int:\n    return sum(values)\n\nvalues = [load_value(path) for path in [\"a.txt\", \"b.txt\", \"c.txt\"]]\ntotal = combine(values)\n\nprint(total.compute())\n```\n\n### Futures And Interactive Work\n\nUse the futures API for request-style workloads, simulations, or task queues where you want to submit work incrementally:\n\n```python\nfrom dask.distributed import Client\n\nclient = Client()\n\nfutures = client.map(lambda x: x * 2, range(10))\nresults = client.gather(futures)\n\nprint(results)\n```\n\nPrefer collections for dataframe and array pipelines. Prefer futures when work arrives dynamically or tasks do not map cleanly onto Dask collections.\n\n## Configuration And Auth\n\nDask configuration can come from YAML files, environment variables, or `dask.config`.\n\nTypical config locations:\n\n- `~/.config/dask/`\n- `/etc/dask/`\n\nPython override:\n\n```python\nimport dask\n\nwith dask.config.set({\"temporary-directory\": \"/mnt/fast-ssd/dask\"}):\n    ...\n```\n\nExample YAML:\n\n```yaml\ntemporary-directory: /mnt/fast-ssd/dask\ndistributed:\n  worker:\n    memory:\n      target: 0.75\n      spill: 0.85\n      pause: 0.95\n      terminate: 0.98\n```\n\nExample environment variables:\n\n```bash\nexport DASK_DISTRIBUTED__SCHEDULER__WORK_STEALING=True\nexport DASK_TEMPORARY_DIRECTORY=/mnt/fast-ssd/dask\n```\n\nAuthentication notes:\n\n- Core Dask itself does not use API keys.\n- Access to `s3://`, `gcs://`, Azure storage, SQL sources, or remote clusters is handled by the corresponding filesystem or cluster backend, not by Dask package config alone.\n- Keep cloud credentials in the provider-standard environment or config locations. Do not hard-code them into Dask task functions.\n\n## Common Pitfalls\n\n- Installing only `dask` and then assuming `dask.dataframe` or `dask.distributed` is ready. Use the correct extras or install missing dependencies explicitly.\n- Calling `.compute()` inside loops. Build multiple results and execute them together with `dask.compute(...)` when possible.\n- Creating extremely small partitions or chunks. This produces huge graphs and poor scheduler efficiency.\n- Building extremely large task graphs for work that could be expressed with chunk-aware collection operations like `map_partitions`, `map_blocks`, `read_parquet`, or batched futures.\n- Ignoring the dashboard when a job is slow or memory-bound. The official best-practices guidance treats the dashboard as a primary debugging tool.\n- Forgetting that remote URLs need filesystem backends and credentials. `dd.read_parquet(\"s3://...\")` will not work with only the base package installed.\n- Treating the distributed scheduler as mandatory. Many local workloads are fine with the default scheduler; add `Client()` when you need cluster features, diagnostics, or better control.\n\n## Version-Sensitive Notes For `2026.1.2`\n\n- PyPI lists `dask 2026.1.2` as the current package version, released on January 30, 2026.\n- The separately hosted `distributed.dask.org` stable docs may still display `2026.1.1` on some pages as of March 12, 2026. Use PyPI and the Dask changelog as the package-version authority, and use the distributed site for API behavior and scheduler guidance.\n- The `2026.1.2` changelog notes that `dask.dataframe` now requires `pyarrow>=16`. If your environment pins an older PyArrow, dataframe imports or parquet-heavy code paths can fail in ways that look unrelated at first glance.\n- If you use Zarr writes, `2026.1.2` moved `mode` to an explicit `to_zarr` argument and removed `read_kwargs` and `zarr_array_kwargs`. Older blog examples for those keyword arguments are stale.\n"
  },
  {
    "path": "content/databases/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"databases package guide for Python async database access with SQLAlchemy Core\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"databases,python,asyncio,sqlalchemy,postgresql,mysql,sqlite\"\n---\n\n# databases Python Package Guide\n\n## Golden Rule\n\nUse `databases` as an async query layer on top of SQLAlchemy Core, not as an ORM. Pick and install the async driver that matches your database URL, connect and disconnect it with your app lifecycle, and keep a separate synchronous driver/toolchain for Alembic migrations or other synchronous SQLAlchemy operations.\n\n## Install\n\nInstall the package and the async backend you actually use:\n\n```bash\npython -m pip install \"databases==0.9.0\"\npython -m pip install \"databases[asyncpg]==0.9.0\"\npython -m pip install \"databases[aiosqlite]==0.9.0\"\n```\n\nAvailable backend extras in the maintainer package metadata:\n\n- PostgreSQL: `asyncpg` or alias `postgresql`\n- PostgreSQL via psycopg2-compatible stack for sync tooling: install `psycopg2` separately\n- MySQL: `aiomysql`, `asyncmy`, or alias `mysql`\n- MySQL sync tooling: install `pymysql` separately\n- SQLite: `aiosqlite` or alias `sqlite`\n\n`databases 0.9.0` depends on `sqlalchemy>=2.0.7`, so use SQLAlchemy 2-style Core APIs and avoid old 1.3-era snippets.\n\n## Setup And Initialization\n\n`databases` works from a database URL and manages a connection pool behind the scenes.\n\nSQLite:\n\n```python\nfrom databases import Database\n\ndatabase = Database(\"sqlite+aiosqlite:///./app.db\")\n```\n\nPostgreSQL:\n\n```python\nfrom databases import Database\n\ndatabase = Database(\"postgresql+asyncpg://user:password@localhost:5432/appdb\")\n```\n\nMySQL:\n\n```python\nfrom databases import Database\n\ndatabase = Database(\"mysql+asyncmy://user:password@localhost:3306/appdb\")\n```\n\nUse it with an async context manager for scripts:\n\n```python\nfrom databases import Database\n\nasync def main() -> None:\n    async with Database(\"sqlite+aiosqlite:///./app.db\") as database:\n        value = await database.fetch_val(\"SELECT 1\")\n        print(value)\n```\n\nFor web apps, wire it into startup and shutdown instead of reconnecting per request:\n\n```python\nfrom databases import Database\nfrom fastapi import FastAPI\n\nDATABASE_URL = \"postgresql+asyncpg://user:password@localhost:5432/appdb\"\n\ndatabase = Database(DATABASE_URL)\napp = FastAPI()\n\n@app.on_event(\"startup\")\nasync def startup() -> None:\n    await database.connect()\n\n@app.on_event(\"shutdown\")\nasync def shutdown() -> None:\n    await database.disconnect()\n```\n\n## Core Usage\n\n### SQLAlchemy Core queries\n\nDefine tables with SQLAlchemy Core, then execute those expressions through `databases`:\n\n```python\nimport sqlalchemy\nfrom databases import Database\n\nmetadata = sqlalchemy.MetaData()\n\nnotes = sqlalchemy.Table(\n    \"notes\",\n    metadata,\n    sqlalchemy.Column(\"id\", sqlalchemy.Integer, primary_key=True),\n    sqlalchemy.Column(\"text\", sqlalchemy.String(length=200)),\n    sqlalchemy.Column(\"completed\", sqlalchemy.Boolean, nullable=False, server_default=sqlalchemy.false()),\n)\n\ndatabase = Database(\"sqlite+aiosqlite:///./app.db\")\n\nasync def list_notes() -> list[dict]:\n    await database.connect()\n    try:\n        await database.execute(notes.insert(), {\"text\": \"ship docs\", \"completed\": False})\n        rows = await database.fetch_all(notes.select().order_by(notes.c.id))\n        return [dict(row._mapping) for row in rows]\n    finally:\n        await database.disconnect()\n```\n\nThe result objects support attribute access and `row._mapping[...]`. When you need a plain dict, convert from `_mapping`.\n\n### Raw SQL queries\n\nRaw SQL uses named parameters in `:name` format:\n\n```python\nfrom databases import Database\n\ndatabase = Database(\"postgresql+asyncpg://user:password@localhost:5432/appdb\")\n\nasync def create_note(text: str) -> int:\n    query = \"\"\"\n    INSERT INTO notes(text, completed)\n    VALUES (:text, :completed)\n    RETURNING id\n    \"\"\"\n    row = await database.fetch_one(query, {\"text\": text, \"completed\": False})\n    return row.id\n```\n\nCommon methods:\n\n- `execute(...)`: run one statement\n- `execute_many(...)`: bulk writes\n- `fetch_one(...)`: one row\n- `fetch_all(...)`: all rows in memory\n- `fetch_val(...)`: a single scalar\n- `iterate(...)`: async row streaming when you do not want to materialize everything\n\n## Transactions And Connection Behavior\n\nTransactions are async context managers:\n\n```python\nasync with database.transaction():\n    await database.execute(\n        \"INSERT INTO audit_log(message) VALUES (:message)\",\n        {\"message\": \"starting work\"},\n    )\n    await database.execute(\n        \"UPDATE notes SET completed = :completed WHERE id = :id\",\n        {\"completed\": True, \"id\": 1},\n    )\n```\n\nUseful details from the maintainer docs:\n\n- Connections are acquired per `asyncio.Task`\n- Nested transactions are supported via savepoints\n- You can specify an isolation level such as `isolation=\"serializable\"` if the backend supports it\n- If child tasks need to participate in the same transaction, share the same connection explicitly\n\nFor low-level control:\n\n```python\ntransaction = await database.transaction()\ntry:\n    await database.execute(\"DELETE FROM temp_rows\")\nexcept Exception:\n    await transaction.rollback()\n    raise\nelse:\n    await transaction.commit()\n```\n\n## Configuration And Auth\n\n`databases` does not have a separate auth layer. Authentication and connection tuning come from the database URL or keyword arguments.\n\nExamples:\n\n```python\nDatabase(\n    \"postgresql+asyncpg://user:password@db.example.com/appdb?ssl=true\",\n    min_size=5,\n    max_size=20,\n)\n```\n\n```python\nDatabase(\n    \"mysql+aiomysql://user:password@db.example.com/appdb\",\n    min_size=5,\n    max_size=20,\n)\n```\n\nPractical guidance:\n\n- Prefer environment variables for credentials and build the URL once during app startup\n- Match the URL scheme to the installed async driver: `postgresql+asyncpg`, `mysql+asyncmy`, `mysql+aiomysql`, `sqlite+aiosqlite`\n- SSL, pool sizing, and similar options are backend-specific; keyword arguments are often clearer than URL query strings\n- SQLite is the easiest local dev option, but it is not a drop-in substitute for PostgreSQL or MySQL behavior under concurrency\n\n## Migrations And Schema Management\n\nDo not expect `databases` to replace Alembic or SQLAlchemy schema tooling.\n\nImportant constraints from the official docs:\n\n- `databases` does not use SQLAlchemy's engine internally for normal access\n- `metadata.create_all()` is not part of the usual `databases` workflow\n- serious projects should use Alembic for migrations\n- Alembic and other synchronous SQLAlchemy tooling still need a synchronous driver\n\nMinimal Alembic direction:\n\n1. Install `alembic`\n2. Point Alembic at your `DATABASE_URL`\n3. Expose your SQLAlchemy `metadata` to `target_metadata`\n4. For MySQL migrations, the docs call out `pymysql` as the synchronous dialect to use\n\n## Testing\n\nFor strict per-test isolation, the official docs recommend force-rollback mode:\n\n```python\nfrom databases import Database\n\ndatabase = Database(\"postgresql+asyncpg://user:password@localhost/testdb\", force_rollback=True)\n```\n\nThat wraps work in a transaction that is rolled back when the database disconnects. A lower-level option is:\n\n```python\nasync with database.transaction(force_rollback=True):\n    ...\n```\n\nUse a dedicated test database URL rather than pointing tests at development data.\n\n## Common Pitfalls\n\n- Installing `databases` without an async driver. The base package is not enough for PostgreSQL, MySQL, or SQLite I/O.\n- Using the wrong URL scheme for the installed driver.\n- Forgetting `await database.connect()` before the first query or `await database.disconnect()` on shutdown.\n- Treating it like SQLAlchemy ORM. `databases` is built around SQLAlchemy Core expressions and raw SQL.\n- Calling synchronous schema helpers or Alembic commands without also installing a synchronous DB driver.\n- Copying old snippets that assume SQLAlchemy 1.x. `0.9.0` added SQLAlchemy 2+ support and the package now depends on `sqlalchemy>=2.0.7`.\n- Assuming rows are plain dicts. Use attribute access or `row._mapping`.\n- Opening one transaction and then spawning unrelated tasks that expect to see the same transaction state without sharing the connection.\n\n## Version-Sensitive Notes For 0.9.0\n\n- `0.9.0` was released on March 1, 2024 and is still the latest PyPI release as of March 12, 2026.\n- The `0.9.0` changelog notes three important changes: Python 3.7 support was dropped, Python 3.12 support was added, and SQLAlchemy 2+ support was added.\n- PyPI still classifies the package as `Development Status :: 3 - Alpha`, so avoid assuming the maintenance posture of a more active database toolkit.\n- The official GitHub repository was archived by the owner on August 19, 2025 and is now read-only. For new projects, treat `databases` as stable but effectively unmaintained unless the project is revived elsewhere.\n\n## Official Sources\n\n- Docs: https://www.encode.io/databases/\n- Database queries: https://www.encode.io/databases/database_queries/\n- Connections and transactions: https://www.encode.io/databases/connections_and_transactions/\n- Tests and migrations: https://www.encode.io/databases/tests_and_migrations/\n- PyPI: https://pypi.org/project/databases/\n- Repository: https://github.com/encode/databases\n- Changelog: https://raw.githubusercontent.com/encode/databases/master/CHANGELOG.md\n"
  },
  {
    "path": "content/dataclasses-json/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Serialize Python dataclasses to and from JSON and dictionaries with field mapping, validation, and custom encoders\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"python,dataclasses,json,serialization,marshmallow\"\n---\n\n# dataclasses-json Python Package Guide\n\n## Golden Rule\n\nUse `dataclasses-json` on standard-library dataclasses. There is no client object, no auth flow, and no environment-variable setup. Import the decorator or mixin in the module that defines your dataclass and call `from_json`, `to_json`, `from_dict`, `to_dict`, or `schema()` on the dataclass itself.\n\n## Install\n\n```bash\npython -m pip install \"dataclasses-json==0.6.7\"\n```\n\nPyPI metadata for `0.6.7` requires Python `>=3.7,<4.0`. The maintainer README lists the `0.6.x` line as supporting Python 3.7 through 3.12 and not officially supporting Python 3.13 or newer yet.\n\n## Basic Usage\n\nDecorator order matters: apply `@dataclass_json` above `@dataclass`.\n\n```python\nfrom dataclasses import dataclass\n\nfrom dataclasses_json import dataclass_json\n\n\n@dataclass_json\n@dataclass\nclass User:\n    id: int\n    email: str\n    is_active: bool = True\n\n\npayload = '{\"id\": 1, \"email\": \"ada@example.com\"}'\n\nuser = User.from_json(payload)\nprint(user)\nprint(user.to_dict())\nprint(user.to_json())\n```\n\nUse `from_dict` and `to_dict` when your app already has parsed Python objects:\n\n```python\nuser = User.from_dict({\"id\": 2, \"email\": \"grace@example.com\"})\nbody = user.to_dict()\n```\n\n## Use The Mixin When You Prefer Inheritance\n\nThe library also exposes `DataClassJsonMixin`. This keeps the same API and can work better with static analysis tools.\n\n```python\nfrom dataclasses import dataclass\n\nfrom dataclasses_json import DataClassJsonMixin\n\n\n@dataclass\nclass Product(DataClassJsonMixin):\n    sku: str\n    price_cents: int\n\n\nproduct = Product.from_json('{\"sku\": \"book-1\", \"price_cents\": 2599}')\nprint(product.to_json())\n```\n\n## Validate Input With `schema()`\n\n`from_json` and `from_dict` construct the dataclass directly. If you need marshmallow validation, use `schema().loads()` or `schema().load()`.\n\n```python\nfrom dataclasses import dataclass\n\nfrom dataclasses_json import dataclass_json\nfrom marshmallow import ValidationError\n\n\n@dataclass_json\n@dataclass\nclass Person:\n    name: str\n\n\nperson = Person.from_json('{\"name\": 42}')\nprint(person)  # Person(name=42)\n\ntry:\n    Person.schema().loads('{\"name\": 42}')\nexcept ValidationError as exc:\n    print(exc.messages)\n```\n\nYou can also use the generated schema for lists:\n\n```python\npeople = Person.schema().loads('[{\"name\": \"Ada\"}, {\"name\": \"Grace\"}]', many=True)\n```\n\n## Map JSON Names To Python Fields\n\nUse `LetterCase` for consistent naming transforms, and `config(field_name=...)` when one field needs an explicit external name.\n\n```python\nfrom dataclasses import dataclass, field\n\nfrom dataclasses_json import LetterCase, config, dataclass_json\n\n\n@dataclass_json(letter_case=LetterCase.CAMEL)\n@dataclass\nclass Account:\n    given_name: str\n    family_name: str\n    external_id: str = field(metadata=config(field_name=\"externalId\"))\n\n\naccount = Account.from_dict(\n    {\n        \"givenName\": \"Ada\",\n        \"familyName\": \"Lovelace\",\n        \"externalId\": \"acct_123\",\n    }\n)\n\nprint(account.to_dict())\n```\n\nThe maintainer docs warn that the automatic casing helpers assume your Python fields are `snake_case`. Results are undefined for dataclass fields that are not snake_case to begin with.\n\n## Missing Values And Optional Fields\n\nPrefer normal dataclass defaults for fields that may be omitted.\n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import List, Optional\n\nfrom dataclasses_json import dataclass_json\n\n\n@dataclass_json\n@dataclass\nclass Job:\n    id: int\n    status: str = \"queued\"\n    tags: List[str] = field(default_factory=list)\n    owner: Optional[str] = None\n\n\njob = Job.from_json('{\"id\": 7}')\nprint(job)\n```\n\nIf you need missing optional fields without defining a default, the library supports `infer_missing=True`:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\n\nfrom dataclasses_json import dataclass_json\n\n\n@dataclass_json\n@dataclass\nclass Enrollment:\n    id: int\n    cohort: Optional[str]\n\n\nenrollment = Enrollment.from_json('{\"id\": 10}', infer_missing=True)\nprint(enrollment)\n```\n\nThe maintainer README recommends using dataclass defaults instead of relying on `infer_missing=True` for most code.\n\n## Unknown Fields\n\nUnknown input fields behave differently depending on which API you call:\n\n- `from_dict` ignores unknown keys by default.\n- `schema().load()` raises a marshmallow `ValidationError` by default.\n\nIf you need to preserve unknown fields from an upstream API, opt into `Undefined.INCLUDE` and add exactly one `CatchAll` field:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Any, Dict\n\nfrom dataclasses_json import CatchAll, Undefined, dataclass_json\n\n\n@dataclass_json(undefined=Undefined.INCLUDE)\n@dataclass\nclass Event:\n    type: str\n    payload: Dict[str, Any]\n    extras: CatchAll\n\n\nevent = Event.from_dict(\n    {\n        \"type\": \"invoice.paid\",\n        \"payload\": {\"id\": \"in_123\"},\n        \"trace_id\": \"abc-123\",\n        \"request_id\": \"req_456\",\n    }\n)\n\nprint(event.extras[\"trace_id\"])\n```\n\nUse `Undefined.EXCLUDE` to drop unknown fields explicitly, or `Undefined.RAISE` to reject them early.\n\n## Custom Encoding For `datetime`\n\nBy default, the library encodes `datetime` values as POSIX timestamps and decodes them into timezone-aware datetimes using the local timezone. If you need ISO 8601 strings instead, configure the field explicitly.\n\n```python\nfrom dataclasses import dataclass, field\nfrom datetime import datetime\n\nfrom dataclasses_json import config, dataclass_json\nfrom marshmallow import fields\n\n\n@dataclass_json\n@dataclass\nclass AuditRecord:\n    created_at: datetime = field(\n        metadata=config(\n            encoder=datetime.isoformat,\n            decoder=datetime.fromisoformat,\n            mm_field=fields.DateTime(format=\"iso\"),\n        )\n    )\n\n\nrecord = AuditRecord.from_json('{\"created_at\": \"2026-03-13T15:30:00+00:00\"}')\nprint(record.to_json())\n```\n\n## Important Pitfalls\n\n- Put `@dataclass_json` above `@dataclass`. Reversing the order breaks the generated methods.\n- There is no package-level initialization step. Import the decorator or mixin where you declare the dataclass.\n- Use `schema()` when you need validation. `from_json` and `from_dict` do not give you marshmallow validation behavior.\n- Store `MyDataclass.schema()` if you reuse it in a hot path. The maintainer docs say schema generation is not cached.\n- The README says recursive dataclasses are supported, but not when you use `from __future__ import annotations`. Avoid that import in modules that rely on recursive `dataclasses-json` models.\n- Default `datetime` handling uses timestamps and may change naive values when they round-trip through local timezone conversion. Override the field config if your API expects ISO strings or strict timezone handling.\n\n## Version Notes For 0.6.7\n\n- `dataclasses-json` is still a pre-1.0 package, and the maintainer docs say minor releases may include breaking changes.\n- The `0.6.x` compatibility table in the maintainer README is the safest guide for interpreter support when your project is pinned to `0.6.7`.\n\n## Official Sources\n\n- GitHub repository and README: https://github.com/lidatong/dataclasses-json\n- PyPI package page: https://pypi.org/project/dataclasses-json/\n"
  },
  {
    "path": "content/datadog/docs/monitoring/javascript/DOC.md",
    "content": "---\nname: monitoring\ndescription: \"Official Datadog API client for JavaScript/TypeScript to submit metrics, manage monitors, and interact with Datadog observability features.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.46.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"datadog,monitoring,metrics,observability,apm\"\n---\n\n# Datadog API Client for JavaScript/TypeScript\n\n## Golden Rule\n\n**ALWAYS use `@datadog/datadog-api-client` version 1.46.0 or later.**\n\nThis is the official Datadog API client for JavaScript and TypeScript. Do NOT use:\n- `datadog-client` (unofficial/deprecated)\n- `datadog-metrics` (limited functionality, community package)\n- Direct HTTP calls to Datadog API endpoints (use the official client instead)\n\nThe `@datadog/datadog-api-client` package provides complete access to both v1 and v2 Datadog APIs with full TypeScript support.\n\n## Installation\n\n### NPM\n\n```bash\nnpm install @datadog/datadog-api-client\n```\n\n### Yarn\n\n```bash\nyarn add @datadog/datadog-api-client\n```\n\n### Environment Variables\n\nSet up your Datadog API credentials as environment variables:\n\n```bash\nexport DD_API_KEY=\"your-api-key-here\"\nexport DD_APP_KEY=\"your-application-key-here\"\nexport DD_SITE=\"datadoghq.com\"  # Optional: defaults to US site\n```\n\nFor EU region:\n\n```bash\nexport DD_SITE=\"datadoghq.eu\"\n```\n\n## Initialization\n\n### Basic Initialization with Environment Variables\n\nThe client automatically reads `DD_API_KEY` and `DD_APP_KEY` environment variables:\n\n```typescript\nimport { client, v1, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\n```\n\n### Manual Authentication\n\nProvide credentials explicitly in code:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  authMethods: {\n    apiKeyAuth: \"your-api-key-here\",\n    appKeyAuth: \"your-application-key-here\"\n  }\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\n```\n\n### Regional Configuration\n\nConfigure for EU or other regions:\n\n```typescript\nimport { client } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconfiguration.setServerVariables({\n  site: \"datadoghq.eu\"  // EU region\n});\n```\n\nAvailable sites:\n- `datadoghq.com` (US1 - default)\n- `datadoghq.eu` (EU1)\n- `us3.datadoghq.com` (US3)\n- `us5.datadoghq.com` (US5)\n- `ap1.datadoghq.com` (AP1)\n- `ddog-gov.com` (US1-FED)\n\n### Advanced Configuration Options\n\n```typescript\nimport { client } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  authMethods: {\n    apiKeyAuth: process.env.DD_API_KEY,\n    appKeyAuth: process.env.DD_APP_KEY\n  },\n  enableRetry: true,        // Enable automatic retry on rate limiting\n  debug: false,             // Enable request/response logging\n  maxRetries: 3,            // Maximum number of retries\n  backoffMultiplier: 2,     // Backoff multiplier for retries\n  httpConfig: {\n    timeout: 30000          // Request timeout in milliseconds\n  }\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\nconfiguration.setServerVariables({ site: \"datadoghq.com\" });\n```\n\n### Enable Unstable Operations\n\nSome v2 endpoints are marked as unstable and require explicit enablement:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconfiguration.unstableOperations[\"v2.listIncidents\"] = true;\nconfiguration.unstableOperations[\"v2.createIncident\"] = true;\n```\n\n## Core API Surfaces\n\n### Metrics API\n\n#### Submit Metrics (v1)\n\nBasic metric submission:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MetricsApi(configuration);\n\nconst params: v1.MetricsApiSubmitMetricsRequest = {\n  body: {\n    series: [\n      {\n        metric: \"system.load.1\",\n        points: [\n          [Math.floor(Date.now() / 1000), 0.7]\n        ],\n        type: \"gauge\",\n        host: \"test.example.com\",\n        tags: [\"environment:test\", \"version:1.0\"]\n      }\n    ]\n  }\n};\n\napiInstance.submitMetrics(params)\n  .then((data: v1.IntakePayloadAccepted) => {\n    console.log(\"Metrics submitted successfully\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced metric submission with multiple series:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MetricsApi(configuration);\n\nconst now = Math.floor(Date.now() / 1000);\n\nconst params: v1.MetricsApiSubmitMetricsRequest = {\n  body: {\n    series: [\n      {\n        metric: \"custom.app.requests\",\n        points: [[now, 100]],\n        type: \"count\",\n        interval: 60,\n        host: \"app-server-1\",\n        tags: [\"service:api\", \"env:production\"]\n      },\n      {\n        metric: \"custom.app.latency\",\n        points: [[now, 45.2]],\n        type: \"gauge\",\n        host: \"app-server-1\",\n        tags: [\"service:api\", \"env:production\"]\n      },\n      {\n        metric: \"custom.app.errors\",\n        points: [[now, 2]],\n        type: \"count\",\n        host: \"app-server-1\",\n        tags: [\"service:api\", \"env:production\", \"error_type:timeout\"]\n      }\n    ]\n  }\n};\n\napiInstance.submitMetrics(params)\n  .then((data: v1.IntakePayloadAccepted) => {\n    console.log(\"Multiple metrics submitted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Submit Metrics (v2)\n\nv2 API with compression support:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\nimport { compressSync } from 'zstd.ts';\n\nconst configurationOpts = {\n  zstdCompressorCallback: (body: string) =>\n    compressSync({ input: Buffer.from(body, \"utf8\") })\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\nconst apiInstance = new v2.MetricsApi(configuration);\n\nconst params: v2.MetricsApiSubmitMetricsRequest = {\n  body: {\n    series: [\n      {\n        metric: \"system.load.1\",\n        type: 0,  // gauge\n        points: [\n          {\n            timestamp: Math.floor(Date.now() / 1000),\n            value: 0.7\n          }\n        ],\n        resources: [\n          {\n            name: \"host\",\n            type: \"host\"\n          }\n        ],\n        tags: [\"environment:production\"]\n      }\n    ]\n  },\n  contentEncoding: \"zstd1\"\n};\n\napiInstance.submitMetrics(params)\n  .then((data: v2.IntakePayloadAccepted) => {\n    console.log(\"Metrics submitted with compression\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Query Metrics\n\nQuery timeseries data:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MetricsApi(configuration);\n\nconst from = Math.floor(Date.now() / 1000) - 3600;  // 1 hour ago\nconst to = Math.floor(Date.now() / 1000);\n\nconst params: v1.MetricsApiQueryMetricsRequest = {\n  from: from,\n  to: to,\n  query: \"avg:system.cpu.user{*}\"\n};\n\napiInstance.queryMetrics(params)\n  .then((data: v1.MetricsQueryResponse) => {\n    console.log(\"Query results:\", JSON.stringify(data, null, 2));\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced query with aggregation:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MetricsApi(configuration);\n\nconst from = Math.floor(Date.now() / 1000) - 86400;  // 24 hours ago\nconst to = Math.floor(Date.now() / 1000);\n\nconst params: v1.MetricsApiQueryMetricsRequest = {\n  from: from,\n  to: to,\n  query: \"sum:custom.app.requests{env:production}.rollup(sum, 3600)\"\n};\n\napiInstance.queryMetrics(params)\n  .then((data: v1.MetricsQueryResponse) => {\n    console.log(\"Aggregated results:\", data);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Active Metrics\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MetricsApi(configuration);\n\nconst from = Math.floor(Date.now() / 1000) - 3600;\n\nconst params: v1.MetricsApiListActiveMetricsRequest = {\n  from: from\n};\n\napiInstance.listActiveMetrics(params)\n  .then((data: v1.MetricsListResponse) => {\n    console.log(\"Active metrics:\", data.metrics);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Monitors API\n\n#### Create Monitor\n\nBasic monitor creation:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiCreateMonitorRequest = {\n  body: {\n    type: \"metric alert\",\n    query: \"avg(last_5m):avg:system.cpu.user{*} > 80\",\n    name: \"High CPU Usage\",\n    message: \"CPU usage is above 80% @slack-alerts\",\n    tags: [\"env:production\", \"team:platform\"],\n    options: {\n      thresholds: {\n        critical: 80,\n        warning: 60\n      },\n      notifyNoData: true,\n      noDataTimeframe: 20,\n      notifyAudit: false,\n      requireFullWindow: false,\n      includeTag: true\n    }\n  }\n};\n\napiInstance.createMonitor(params)\n  .then((data: v1.Monitor) => {\n    console.log(\"Monitor created:\", data.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced monitor with composite query:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiCreateMonitorRequest = {\n  body: {\n    type: \"query alert\",\n    query: \"avg(last_15m):anomalies(avg:custom.app.latency{env:production}, 'basic', 2) >= 1\",\n    name: \"Anomalous Latency Detected\",\n    message: `Application latency is behaving abnormally.\n\nCurrent value: {{value}}\nThreshold: {{threshold}}\n\n@pagerduty-critical @slack-alerts`,\n    tags: [\"service:api\", \"priority:high\"],\n    priority: 1,\n    options: {\n      thresholds: {\n        critical: 1,\n        criticalRecovery: 0\n      },\n      notifyNoData: true,\n      noDataTimeframe: 30,\n      evaluationDelay: 60,\n      newGroupDelay: 300,\n      requireFullWindow: false,\n      notifyAudit: true,\n      timeoutH: 24,\n      renotifyInterval: 60,\n      escalationMessage: \"Latency issue still ongoing @oncall\"\n    }\n  }\n};\n\napiInstance.createMonitor(params)\n  .then((data: v1.Monitor) => {\n    console.log(\"Anomaly monitor created:\", data.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Monitors\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiListMonitorsRequest = {\n  tags: \"env:production\",\n  monitorTags: \"team:platform\"\n};\n\napiInstance.listMonitors(params)\n  .then((data: v1.Monitor[]) => {\n    data.forEach(monitor => {\n      console.log(`ID: ${monitor.id}, Name: ${monitor.name}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Get Monitor\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiGetMonitorRequest = {\n  monitorId: 123456\n};\n\napiInstance.getMonitor(params)\n  .then((data: v1.Monitor) => {\n    console.log(\"Monitor details:\", JSON.stringify(data, null, 2));\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Update Monitor\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiUpdateMonitorRequest = {\n  monitorId: 123456,\n  body: {\n    name: \"Updated Monitor Name\",\n    options: {\n      thresholds: {\n        critical: 90,\n        warning: 70\n      }\n    }\n  }\n};\n\napiInstance.updateMonitor(params)\n  .then((data: v1.Monitor) => {\n    console.log(\"Monitor updated\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Delete Monitor\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\nconst params: v1.MonitorsApiDeleteMonitorRequest = {\n  monitorId: 123456\n};\n\napiInstance.deleteMonitor(params)\n  .then((data: v1.DeletedMonitor) => {\n    console.log(\"Monitor deleted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Events API\n\n#### Post Event\n\nBasic event submission:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.EventsApi(configuration);\n\nconst params: v1.EventsApiCreateEventRequest = {\n  body: {\n    title: \"Application Deployment\",\n    text: \"Version 2.0.0 deployed to production\",\n    tags: [\"env:production\", \"version:2.0.0\", \"deployment\"]\n  }\n};\n\napiInstance.createEvent(params)\n  .then((data: v1.EventCreateResponse) => {\n    console.log(\"Event created:\", data.event?.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced event with priority and alert type:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.EventsApi(configuration);\n\nconst params: v1.EventsApiCreateEventRequest = {\n  body: {\n    title: \"Database Migration Completed\",\n    text: `Database migration to schema version 15 completed successfully.\n\nDuration: 45 minutes\nTables affected: 12\nRecords migrated: 1.2M`,\n    dateHappened: Math.floor(Date.now() / 1000),\n    priority: \"normal\",\n    tags: [\"service:database\", \"env:production\", \"migration\"],\n    alertType: \"info\",\n    aggregationKey: \"db_migration_v15\",\n    sourceTypeName: \"my-app\",\n    host: \"db-server-1\"\n  }\n};\n\napiInstance.createEvent(params)\n  .then((data: v1.EventCreateResponse) => {\n    console.log(\"Migration event created\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Events\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.EventsApi(configuration);\n\nconst end = Math.floor(Date.now() / 1000);\nconst start = end - 3600;  // Last hour\n\nconst params: v1.EventsApiListEventsRequest = {\n  start: start,\n  end: end,\n  tags: \"env:production\"\n};\n\napiInstance.listEvents(params)\n  .then((data: v1.EventListResponse) => {\n    console.log(`Found ${data.events?.length} events`);\n    data.events?.forEach(event => {\n      console.log(`${event.title}: ${event.text}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Get Event\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.EventsApi(configuration);\n\nconst params: v1.EventsApiGetEventRequest = {\n  eventId: 1234567890\n};\n\napiInstance.getEvent(params)\n  .then((data: v1.EventResponse) => {\n    console.log(\"Event details:\", JSON.stringify(data.event, null, 2));\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Logs API\n\n#### Send Logs (v2)\n\nBasic log submission:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.LogsApi(configuration);\n\nconst params: v2.LogsApiSubmitLogRequest = {\n  body: [\n    {\n      ddsource: \"nodejs\",\n      ddtags: \"env:production,service:api\",\n      hostname: \"app-server-1\",\n      message: \"User login successful\",\n      service: \"authentication\"\n    }\n  ]\n};\n\napiInstance.submitLog(params)\n  .then((data: any) => {\n    console.log(\"Log submitted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced log submission with structured data:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.LogsApi(configuration);\n\nconst params: v2.LogsApiSubmitLogRequest = {\n  body: [\n    {\n      ddsource: \"application\",\n      ddtags: \"env:production,version:2.0.0\",\n      hostname: \"api-server-2\",\n      message: \"Payment processed successfully\",\n      service: \"payment-gateway\",\n      status: \"info\",\n      timestamp: new Date().toISOString(),\n      attributes: {\n        transaction_id: \"txn_abc123\",\n        amount: 99.99,\n        currency: \"USD\",\n        user_id: \"user_456\",\n        payment_method: \"credit_card\"\n      }\n    }\n  ],\n  contentEncoding: \"gzip\"\n};\n\napiInstance.submitLog(params)\n  .then((data: any) => {\n    console.log(\"Structured log submitted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Logs\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.LogsApi(configuration);\n\nconst params: v2.LogsApiListLogsRequest = {\n  body: {\n    filter: {\n      query: \"service:api status:error\",\n      from: new Date(Date.now() - 3600000).toISOString(),\n      to: new Date().toISOString()\n    },\n    page: {\n      limit: 50\n    },\n    sort: \"-timestamp\"\n  }\n};\n\napiInstance.listLogs(params)\n  .then((data: v2.LogsListResponse) => {\n    console.log(`Found ${data.data?.length} error logs`);\n    data.data?.forEach(log => {\n      console.log(log.attributes?.message);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Dashboards API\n\n#### Create Dashboard\n\nBasic dashboard creation:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\nconst params: v1.DashboardsApiCreateDashboardRequest = {\n  body: {\n    title: \"System Metrics Dashboard\",\n    description: \"Overview of system performance metrics\",\n    layoutType: \"ordered\",\n    widgets: [\n      {\n        definition: {\n          type: \"timeseries\",\n          requests: [\n            {\n              q: \"avg:system.cpu.user{*}\",\n              displayType: \"line\"\n            }\n          ],\n          title: \"CPU Usage\"\n        }\n      }\n    ]\n  }\n};\n\napiInstance.createDashboard(params)\n  .then((data: v1.Dashboard) => {\n    console.log(\"Dashboard created:\", data.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced dashboard with multiple widgets:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\nconst params: v1.DashboardsApiCreateDashboardRequest = {\n  body: {\n    title: \"Application Performance Dashboard\",\n    description: \"Production application metrics and monitoring\",\n    layoutType: \"ordered\",\n    widgets: [\n      {\n        definition: {\n          type: \"timeseries\",\n          requests: [\n            {\n              q: \"avg:custom.app.latency{env:production}\",\n              displayType: \"line\",\n              style: {\n                palette: \"dog_classic\",\n                lineType: \"solid\",\n                lineWidth: \"normal\"\n              }\n            }\n          ],\n          title: \"API Latency\",\n          showLegend: true,\n          legendLayout: \"auto\",\n          legendColumns: [\"avg\", \"min\", \"max\", \"value\", \"sum\"]\n        }\n      },\n      {\n        definition: {\n          type: \"query_value\",\n          requests: [\n            {\n              q: \"sum:custom.app.requests{env:production}.as_count()\",\n              aggregator: \"sum\"\n            }\n          ],\n          title: \"Total Requests\",\n          autoscale: true,\n          precision: 0\n        }\n      },\n      {\n        definition: {\n          type: \"toplist\",\n          requests: [\n            {\n              q: \"top(avg:custom.app.errors{env:production} by {error_type}, 10, 'sum', 'desc')\"\n            }\n          ],\n          title: \"Top Errors by Type\"\n        }\n      }\n    ],\n    templateVariables: [\n      {\n        name: \"env\",\n        defaultValue: \"production\",\n        prefix: \"env\"\n      }\n    ],\n    notifyList: [\"user@example.com\"]\n  }\n};\n\napiInstance.createDashboard(params)\n  .then((data: v1.Dashboard) => {\n    console.log(\"Advanced dashboard created:\", data.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Dashboards\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\napiInstance.listDashboards()\n  .then((data: v1.DashboardSummary) => {\n    data.dashboards?.forEach(dashboard => {\n      console.log(`ID: ${dashboard.id}, Title: ${dashboard.title}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Get Dashboard\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\nconst params: v1.DashboardsApiGetDashboardRequest = {\n  dashboardId: \"abc-def-ghi\"\n};\n\napiInstance.getDashboard(params)\n  .then((data: v1.Dashboard) => {\n    console.log(\"Dashboard:\", JSON.stringify(data, null, 2));\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Update Dashboard\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\nconst params: v1.DashboardsApiUpdateDashboardRequest = {\n  dashboardId: \"abc-def-ghi\",\n  body: {\n    title: \"Updated Dashboard Title\",\n    description: \"Updated description\",\n    layoutType: \"ordered\",\n    widgets: []  // Include all widgets\n  }\n};\n\napiInstance.updateDashboard(params)\n  .then((data: v1.Dashboard) => {\n    console.log(\"Dashboard updated\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Delete Dashboard\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.DashboardsApi(configuration);\n\nconst params: v1.DashboardsApiDeleteDashboardRequest = {\n  dashboardId: \"abc-def-ghi\"\n};\n\napiInstance.deleteDashboard(params)\n  .then((data: v1.DashboardDeleteResponse) => {\n    console.log(\"Dashboard deleted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Hosts API\n\n#### List Hosts\n\nBasic host listing:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.HostsApi(configuration);\n\napiInstance.listHosts()\n  .then((data: v1.HostListResponse) => {\n    console.log(`Total hosts: ${data.totalMatching}`);\n    data.hostList?.forEach(host => {\n      console.log(`Host: ${host.name}, Up: ${host.up}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced host filtering:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.HostsApi(configuration);\n\nconst params: v1.HostsApiListHostsRequest = {\n  filter: \"env:production\",\n  sortField: \"cpu\",\n  sortDir: \"desc\",\n  start: 0,\n  count: 100,\n  from: Math.floor(Date.now() / 1000) - 3600\n};\n\napiInstance.listHosts(params)\n  .then((data: v1.HostListResponse) => {\n    console.log(\"Production hosts sorted by CPU:\");\n    data.hostList?.forEach(host => {\n      console.log(`${host.name}: CPU ${host.metrics?.cpu}%`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Get Host Totals\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.HostsApi(configuration);\n\nconst params: v1.HostsApiGetHostTotalsRequest = {\n  from: Math.floor(Date.now() / 1000) - 3600\n};\n\napiInstance.getHostTotals(params)\n  .then((data: v1.HostTotals) => {\n    console.log(\"Total up hosts:\", data.totalUp);\n    console.log(\"Total active hosts:\", data.totalActive);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Tags API\n\n#### Get Host Tags\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.TagsApi(configuration);\n\nconst params: v1.TagsApiGetHostTagsRequest = {\n  hostName: \"app-server-1\"\n};\n\napiInstance.getHostTags(params)\n  .then((data: v1.HostTags) => {\n    console.log(\"Tags for host:\", data.tags);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Update Host Tags\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.TagsApi(configuration);\n\nconst params: v1.TagsApiUpdateHostTagsRequest = {\n  hostName: \"app-server-1\",\n  body: {\n    tags: [\n      \"env:production\",\n      \"service:api\",\n      \"version:2.0.0\",\n      \"team:platform\"\n    ]\n  }\n};\n\napiInstance.updateHostTags(params)\n  .then((data: v1.HostTags) => {\n    console.log(\"Host tags updated\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Create Host Tags\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.TagsApi(configuration);\n\nconst params: v1.TagsApiCreateHostTagsRequest = {\n  hostName: \"app-server-2\",\n  body: {\n    tags: [\"env:staging\", \"service:api\"]\n  }\n};\n\napiInstance.createHostTags(params)\n  .then((data: v1.HostTags) => {\n    console.log(\"Tags created for new host\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Delete Host Tags\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.TagsApi(configuration);\n\nconst params: v1.TagsApiDeleteHostTagsRequest = {\n  hostName: \"app-server-1\"\n};\n\napiInstance.deleteHostTags(params)\n  .then(() => {\n    console.log(\"All tags removed from host\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Service Checks API\n\n#### Submit Service Check\n\nBasic service check:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.ServiceChecksApi(configuration);\n\nconst params: v1.ServiceChecksApiSubmitServiceCheckRequest = {\n  body: [\n    {\n      check: \"app.health\",\n      hostName: \"app-server-1\",\n      status: 0,  // 0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN\n      tags: [\"env:production\"]\n    }\n  ]\n};\n\napiInstance.submitServiceCheck(params)\n  .then((data: v1.IntakePayloadAccepted) => {\n    console.log(\"Service check submitted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced service check with message:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.ServiceChecksApi(configuration);\n\nconst params: v1.ServiceChecksApiSubmitServiceCheckRequest = {\n  body: [\n    {\n      check: \"database.connection\",\n      hostName: \"db-server-1\",\n      status: 2,  // CRITICAL\n      timestamp: Math.floor(Date.now() / 1000),\n      message: \"Database connection failed: timeout after 30s\",\n      tags: [\"env:production\", \"service:postgres\"]\n    }\n  ]\n};\n\napiInstance.submitServiceCheck(params)\n  .then((data: v1.IntakePayloadAccepted) => {\n    console.log(\"Critical service check submitted\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Downtimes API (v2)\n\n#### Create Downtime\n\nBasic downtime creation:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.DowntimesApi(configuration);\n\nconst params: v2.DowntimesApiCreateDowntimeRequest = {\n  body: {\n    data: {\n      type: \"downtime\",\n      attributes: {\n        scope: \"env:staging\",\n        message: \"Planned maintenance window\",\n        schedule: {\n          start: new Date(Date.now() + 3600000).toISOString(),\n          end: new Date(Date.now() + 7200000).toISOString()\n        }\n      }\n    }\n  }\n};\n\napiInstance.createDowntime(params)\n  .then((data: v2.DowntimeResponse) => {\n    console.log(\"Downtime created:\", data.data?.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\nAdvanced recurring downtime:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.DowntimesApi(configuration);\n\nconst params: v2.DowntimesApiCreateDowntimeRequest = {\n  body: {\n    data: {\n      type: \"downtime\",\n      attributes: {\n        scope: \"host:app-server-*\",\n        message: \"Weekly maintenance window every Sunday\",\n        monitorIdentifier: {\n          monitorTags: [\"maintenance:auto\"]\n        },\n        schedule: {\n          start: new Date().toISOString(),\n          recurrence: {\n            type: \"weeks\",\n            period: 1,\n            weekDays: [\"Sun\"]\n          },\n          timezone: \"America/New_York\"\n        },\n        notifyEndStates: [\"alert\", \"warn\"],\n        notifyEndTypes: [\"expired\", \"canceled\"]\n      }\n    }\n  }\n};\n\napiInstance.createDowntime(params)\n  .then((data: v2.DowntimeResponse) => {\n    console.log(\"Recurring downtime created\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Downtimes\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.DowntimesApi(configuration);\n\napiInstance.listDowntimes()\n  .then((data: v2.ListDowntimesResponse) => {\n    data.data?.forEach(downtime => {\n      console.log(`ID: ${downtime.id}, Scope: ${downtime.attributes?.scope}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Cancel Downtime\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.DowntimesApi(configuration);\n\nconst params: v2.DowntimesApiCancelDowntimeRequest = {\n  downtimeId: \"downtime-id-here\"\n};\n\napiInstance.cancelDowntime(params)\n  .then(() => {\n    console.log(\"Downtime cancelled\");\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Incidents API (v2)\n\n#### Create Incident\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconfiguration.unstableOperations[\"v2.createIncident\"] = true;\n\nconst apiInstance = new v2.IncidentsApi(configuration);\n\nconst params: v2.IncidentsApiCreateIncidentRequest = {\n  body: {\n    data: {\n      type: \"incidents\",\n      attributes: {\n        title: \"Production API Outage\",\n        customerImpacted: true,\n        fields: {\n          severity: {\n            type: \"dropdown\",\n            value: \"SEV-1\"\n          },\n          state: {\n            type: \"dropdown\",\n            value: \"active\"\n          }\n        }\n      }\n    }\n  }\n};\n\napiInstance.createIncident(params)\n  .then((data: v2.IncidentResponse) => {\n    console.log(\"Incident created:\", data.data?.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List Incidents\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconfiguration.unstableOperations[\"v2.listIncidents\"] = true;\n\nconst apiInstance = new v2.IncidentsApi(configuration);\n\napiInstance.listIncidents()\n  .then((data: v2.IncidentsResponse) => {\n    data.data?.forEach(incident => {\n      console.log(`${incident.id}: ${incident.attributes?.title}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### SLOs API (Service Level Objectives)\n\n#### Create SLO\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.ServiceLevelObjectivesApi(configuration);\n\nconst params: v1.ServiceLevelObjectivesApiCreateSLORequest = {\n  body: {\n    type: \"metric\",\n    name: \"API Availability SLO\",\n    description: \"99.9% availability for production API\",\n    thresholds: [\n      {\n        target: 99.9,\n        targetDisplay: \"99.9\",\n        timeframe: \"30d\",\n        warning: 99.95\n      }\n    ],\n    query: {\n      numerator: \"sum:api.requests{status:ok}.as_count()\",\n      denominator: \"sum:api.requests{*}.as_count()\"\n    },\n    tags: [\"service:api\", \"env:production\"]\n  }\n};\n\napiInstance.createSLO(params)\n  .then((data: v1.SLOListResponse) => {\n    console.log(\"SLO created:\", data.data?.[0].id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### List SLOs\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.ServiceLevelObjectivesApi(configuration);\n\nconst params: v1.ServiceLevelObjectivesApiListSLOsRequest = {\n  tags: \"service:api\"\n};\n\napiInstance.listSLOs(params)\n  .then((data: v1.SLOListResponse) => {\n    data.data?.forEach(slo => {\n      console.log(`${slo.name}: ${slo.thresholds?.[0].target}%`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n### Users API\n\n#### List Users\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.UsersApi(configuration);\n\napiInstance.listUsers()\n  .then((data: v2.UsersResponse) => {\n    data.data?.forEach(user => {\n      console.log(`${user.attributes?.name}: ${user.attributes?.email}`);\n    });\n  })\n  .catch((error: any) => console.error(error));\n```\n\n#### Create User\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.UsersApi(configuration);\n\nconst params: v2.UsersApiCreateUserRequest = {\n  body: {\n    data: {\n      type: \"users\",\n      attributes: {\n        name: \"John Doe\",\n        email: \"john.doe@example.com\"\n      }\n    }\n  }\n};\n\napiInstance.createUser(params)\n  .then((data: v2.UserResponse) => {\n    console.log(\"User created:\", data.data?.id);\n  })\n  .catch((error: any) => console.error(error));\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.MonitorsApi(configuration);\n\napiInstance.listMonitors()\n  .then((data: v1.Monitor[]) => {\n    console.log(\"Success:\", data);\n  })\n  .catch((error: any) => {\n    if (error.response) {\n      console.error(\"Status:\", error.response.status);\n      console.error(\"Body:\", error.response.body);\n    } else {\n      console.error(\"Error:\", error.message);\n    }\n  });\n```\n\n### Advanced Error Handling with Retry\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  enableRetry: true,\n  maxRetries: 3,\n  backoffMultiplier: 2\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\nconst apiInstance = new v1.MetricsApi(configuration);\n\nasync function submitMetricsWithRetry() {\n  try {\n    const params: v1.MetricsApiSubmitMetricsRequest = {\n      body: {\n        series: [{\n          metric: \"custom.metric\",\n          points: [[Math.floor(Date.now() / 1000), 100]]\n        }]\n      }\n    };\n\n    const result = await apiInstance.submitMetrics(params);\n    console.log(\"Metrics submitted successfully\");\n    return result;\n  } catch (error: any) {\n    if (error.response?.status === 429) {\n      console.error(\"Rate limited - automatic retry will handle this\");\n    } else if (error.response?.status === 403) {\n      console.error(\"Authentication failed - check API keys\");\n    } else if (error.response?.status === 400) {\n      console.error(\"Bad request:\", error.response.body);\n    } else {\n      console.error(\"Unexpected error:\", error);\n    }\n    throw error;\n  }\n}\n\nsubmitMetricsWithRetry();\n```\n\n## Pagination\n\n### Manual Pagination\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v1.HostsApi(configuration);\n\nasync function getAllHosts() {\n  const allHosts: any[] = [];\n  let start = 0;\n  const count = 100;\n  let hasMore = true;\n\n  while (hasMore) {\n    const params: v1.HostsApiListHostsRequest = {\n      start: start,\n      count: count\n    };\n\n    const data = await apiInstance.listHosts(params);\n\n    if (data.hostList) {\n      allHosts.push(...data.hostList);\n    }\n\n    start += count;\n    hasMore = (data.hostList?.length || 0) === count;\n  }\n\n  return allHosts;\n}\n\ngetAllHosts().then(hosts => {\n  console.log(`Retrieved ${hosts.length} total hosts`);\n});\n```\n\n### Automatic Pagination with Async Iterator\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\nconst apiInstance = new v2.LogsApi(configuration);\n\nasync function processAllLogs() {\n  const params: v2.LogsApiListLogsRequest = {\n    body: {\n      filter: {\n        query: \"service:api\",\n        from: new Date(Date.now() - 3600000).toISOString(),\n        to: new Date().toISOString()\n      },\n      page: {\n        limit: 100\n      }\n    }\n  };\n\n  // Some endpoints support pagination\n  for await (const log of apiInstance.listLogsWithPagination(params)) {\n    console.log(log.attributes?.message);\n  }\n}\n\nprocessAllLogs();\n```\n\n## Async/Await Pattern\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configuration = client.createConfiguration();\n\nasync function monitorWorkflow() {\n  const monitorsApi = new v1.MonitorsApi(configuration);\n  const eventsApi = new v1.EventsApi(configuration);\n\n  try {\n    // Create monitor\n    const monitor = await monitorsApi.createMonitor({\n      body: {\n        type: \"metric alert\",\n        query: \"avg(last_5m):avg:system.cpu.user{*} > 80\",\n        name: \"High CPU Alert\",\n        message: \"CPU is high @slack-alerts\"\n      }\n    });\n\n    console.log(\"Monitor created:\", monitor.id);\n\n    // Post event about monitor creation\n    await eventsApi.createEvent({\n      body: {\n        title: \"Monitor Created\",\n        text: `Created new monitor: ${monitor.name}`,\n        tags: [\"automation\", \"monitoring\"]\n      }\n    });\n\n    console.log(\"Event posted\");\n\n    // List all monitors\n    const monitors = await monitorsApi.listMonitors();\n    console.log(`Total monitors: ${monitors.length}`);\n\n  } catch (error) {\n    console.error(\"Workflow failed:\", error);\n  }\n}\n\nmonitorWorkflow();\n```\n\n## TypeScript Types\n\nThe package includes full TypeScript definitions:\n\n```typescript\nimport { client, v1, v2 } from '@datadog/datadog-api-client';\n\n// Configuration type\nconst config: client.Configuration = client.createConfiguration();\n\n// Monitor type\nconst monitor: v1.Monitor = {\n  type: \"metric alert\",\n  query: \"avg(last_5m):avg:system.cpu.user{*} > 80\",\n  name: \"CPU Alert\",\n  message: \"High CPU usage detected\"\n};\n\n// Metric series type\nconst series: v1.Series = {\n  metric: \"custom.metric\",\n  points: [[Math.floor(Date.now() / 1000), 100]],\n  type: \"gauge\",\n  host: \"server-1\",\n  tags: [\"env:prod\"]\n};\n\n// Event type\nconst event: v1.Event = {\n  title: \"Deployment\",\n  text: \"Version deployed\",\n  dateHappened: Math.floor(Date.now() / 1000),\n  priority: \"normal\",\n  tags: [\"deployment\"],\n  alertType: \"info\"\n};\n```\n\n## Rate Limiting\n\nDatadog API enforces rate limits. Enable automatic retry on rate limiting:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  enableRetry: true,\n  maxRetries: 5,\n  backoffMultiplier: 2,\n  backoffBase: 2\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\n\n// The client will automatically retry on 429 responses\nconst apiInstance = new v1.MetricsApi(configuration);\n```\n\n## Request Timeouts\n\nConfigure custom request timeouts:\n\n```typescript\nimport { client } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  httpConfig: {\n    timeout: 60000  // 60 seconds\n  }\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\n```\n\n## Compression\n\nEnable compression for large payloads:\n\n```typescript\nimport { client, v2 } from '@datadog/datadog-api-client';\nimport { compressSync } from 'zstd.ts';\n\nconst configurationOpts = {\n  zstdCompressorCallback: (body: string) =>\n    compressSync({ input: Buffer.from(body, \"utf8\") })\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\nconst apiInstance = new v2.MetricsApi(configuration);\n\n// Submit with compression\nconst params: v2.MetricsApiSubmitMetricsRequest = {\n  body: { series: [/* large payload */] },\n  contentEncoding: \"zstd1\"\n};\n\napiInstance.submitMetrics(params);\n```\n\n## Debug Logging\n\nEnable debug logging to see request/response details:\n\n```typescript\nimport { client } from '@datadog/datadog-api-client';\n\nconst configurationOpts = {\n  debug: true\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\n\n// All API calls will log request and response details\n```\n\n## Canceling Requests\n\nUse AbortController to cancel in-flight requests:\n\n```typescript\nimport { client, v1 } from '@datadog/datadog-api-client';\nimport AbortController from 'abort-controller';\n\nconst controller = new AbortController();\n\nconst configurationOpts = {\n  httpConfig: { signal: controller.signal }\n};\n\nconst configuration = client.createConfiguration(configurationOpts);\nconst apiInstance = new v1.MonitorsApi(configuration);\n\n// Start request\napiInstance.listMonitors()\n  .then((data) => console.log(data))\n  .catch((error) => console.error(\"Request cancelled or failed\"));\n\n// Cancel after 1 second\nsetTimeout(() => controller.abort(), 1000);\n```\n"
  },
  {
    "path": "content/datadog/docs/monitoring/python/DOC.md",
    "content": "---\nname: monitoring\ndescription: \"Official Datadog API client for Python to submit metrics, manage monitors, and interact with Datadog observability features.\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.45.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"datadog,monitoring,metrics,observability,apm\"\n---\n\n# Datadog API Client for Python\n\n## Golden Rule\n\n**ALWAYS use `datadog-api-client` version 2.45.0 or later.**\n\nThis is the official Datadog API client for Python. Do NOT use:\n- `datadog` (legacy library, limited functionality)\n- `datadogpy` (old library, use datadog-api-client instead)\n- Direct HTTP calls to Datadog API endpoints (use the official client instead)\n\nThe `datadog-api-client` package provides complete access to both v1 and v2 Datadog APIs with full type hints and async support.\n\n## Installation\n\n### Basic Installation\n\n```bash\npip install datadog-api-client\n```\n\n### With Async Support\n\n```bash\npip install datadog-api-client[async]\n```\n\n### Requirements\n\n- Python 3.8 or higher\n\n### Environment Variables\n\nSet up your Datadog API credentials as environment variables:\n\n```bash\nexport DD_API_KEY=\"your-api-key-here\"\nexport DD_APP_KEY=\"your-application-key-here\"\nexport DD_SITE=\"datadoghq.com\"  # Optional: defaults to US site\n```\n\nFor EU region:\n\n```bash\nexport DD_SITE=\"datadoghq.eu\"\n```\n\n## Initialization\n\n### Basic Initialization with Environment Variables\n\nThe client automatically reads `DD_API_KEY` and `DD_APP_KEY` environment variables:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n    monitors = api_instance.list_monitors()\n    print(monitors)\n```\n\n### Manual Authentication\n\nProvide credentials explicitly in code:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\n\nconfiguration = Configuration()\nconfiguration.api_key[\"apiKeyAuth\"] = \"your-api-key-here\"\nconfiguration.api_key[\"appKeyAuth\"] = \"your-application-key-here\"\n\nwith ApiClient(configuration) as api_client:\n    # Use api_client for API calls\n    pass\n```\n\n### Regional Configuration\n\nConfigure for EU or other regions:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\n\nconfiguration = Configuration()\nconfiguration.server_variables[\"site\"] = \"datadoghq.eu\"\n\nwith ApiClient(configuration) as api_client:\n    # Use api_client for API calls\n    pass\n```\n\nAvailable sites:\n- `datadoghq.com` (US1 - default)\n- `datadoghq.eu` (EU1)\n- `us3.datadoghq.com` (US3)\n- `us5.datadoghq.com` (US5)\n- `ap1.datadoghq.com` (AP1)\n- `ddog-gov.com` (US1-FED)\n\n### Advanced Configuration Options\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\n\nconfiguration = Configuration()\nconfiguration.api_key[\"apiKeyAuth\"] = \"your-api-key\"\nconfiguration.api_key[\"appKeyAuth\"] = \"your-app-key\"\nconfiguration.server_variables[\"site\"] = \"datadoghq.com\"\n\n# Enable debugging\nconfiguration.debug = True\n\n# Set connection timeout\nconfiguration.connection_timeout = 30\n\n# Set read timeout\nconfiguration.read_timeout = 30\n\nwith ApiClient(configuration) as api_client:\n    # Use api_client for API calls\n    pass\n```\n\n### Enable Unstable Operations\n\nSome v2 endpoints are marked as unstable and require explicit enablement:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\n\nconfiguration = Configuration()\nconfiguration.unstable_operations[\"list_incidents\"] = True\nconfiguration.unstable_operations[\"create_incident\"] = True\n\nwith ApiClient(configuration) as api_client:\n    # Use unstable operations\n    pass\n```\n\n### Async Initialization\n\nFor asynchronous operations:\n\n```python\nimport asyncio\nfrom datadog_api_client import AsyncApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nasync def main():\n    configuration = Configuration()\n\n    async with AsyncApiClient(configuration) as api_client:\n        api_instance = MonitorsApi(api_client)\n        monitors = await api_instance.list_monitors()\n        print(monitors)\n\nasyncio.run(main())\n```\n\n### Threaded API Client\n\nFor concurrent operations:\n\n```python\nfrom datadog_api_client import Configuration, ThreadedApiClient\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\n\nconfiguration = Configuration()\n\nwith ThreadedApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n    result = api_instance.list_dashboards()\n    dashboards = result.get()\n    print(dashboards)\n```\n\n## Core API Surfaces\n\n### Metrics API\n\n#### Submit Metrics (v1)\n\nBasic metric submission:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nfrom datadog_api_client.v1.model.metrics_payload import MetricsPayload\nfrom datadog_api_client.v1.model.series import Series\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    body = MetricsPayload(\n        series=[\n            Series(\n                metric=\"system.load.1\",\n                type=\"gauge\",\n                points=[[int(time.time()), 0.7]],\n                host=\"test.example.com\",\n                tags=[\"environment:test\", \"version:1.0\"]\n            )\n        ]\n    )\n\n    response = api_instance.submit_metrics(body=body)\n    print(\"Metrics submitted successfully\")\n```\n\nAdvanced metric submission with multiple series:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nfrom datadog_api_client.v1.model.metrics_payload import MetricsPayload\nfrom datadog_api_client.v1.model.series import Series\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    now = int(time.time())\n\n    body = MetricsPayload(\n        series=[\n            Series(\n                metric=\"custom.app.requests\",\n                type=\"count\",\n                points=[[now, 100]],\n                interval=60,\n                host=\"app-server-1\",\n                tags=[\"service:api\", \"env:production\"]\n            ),\n            Series(\n                metric=\"custom.app.latency\",\n                type=\"gauge\",\n                points=[[now, 45.2]],\n                host=\"app-server-1\",\n                tags=[\"service:api\", \"env:production\"]\n            ),\n            Series(\n                metric=\"custom.app.errors\",\n                type=\"count\",\n                points=[[now, 2]],\n                host=\"app-server-1\",\n                tags=[\"service:api\", \"env:production\", \"error_type:timeout\"]\n            )\n        ]\n    )\n\n    response = api_instance.submit_metrics(body=body)\n    print(\"Multiple metrics submitted\")\n```\n\n#### Submit Metrics (v2)\n\nv2 API with compression support:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.metrics_api import MetricsApi\nfrom datadog_api_client.v2.model.metric_payload import MetricPayload\nfrom datadog_api_client.v2.model.metric_series import MetricSeries\nfrom datadog_api_client.v2.model.metric_point import MetricPoint\nfrom datadog_api_client.v2.model.metric_resource import MetricResource\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    body = MetricPayload(\n        series=[\n            MetricSeries(\n                metric=\"system.load.1\",\n                type=0,  # gauge\n                points=[\n                    MetricPoint(\n                        timestamp=int(time.time()),\n                        value=0.7\n                    )\n                ],\n                resources=[\n                    MetricResource(\n                        name=\"host\",\n                        type=\"host\"\n                    )\n                ],\n                tags=[\"environment:production\"]\n            )\n        ]\n    )\n\n    response = api_instance.submit_metrics(body=body)\n    print(\"Metrics submitted with v2 API\")\n```\n\n#### Query Metrics\n\nQuery timeseries data:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    from_time = int(time.time()) - 3600  # 1 hour ago\n    to_time = int(time.time())\n\n    response = api_instance.query_metrics(\n        _from=from_time,\n        to=to_time,\n        query=\"avg:system.cpu.user{*}\"\n    )\n\n    print(\"Query results:\", response)\n```\n\nAdvanced query with aggregation:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    from_time = int(time.time()) - 86400  # 24 hours ago\n    to_time = int(time.time())\n\n    response = api_instance.query_metrics(\n        _from=from_time,\n        to=to_time,\n        query=\"sum:custom.app.requests{env:production}.rollup(sum, 3600)\"\n    )\n\n    print(\"Aggregated results:\", response)\n```\n\n#### List Active Metrics\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    from_time = int(time.time()) - 3600\n\n    response = api_instance.list_active_metrics(\n        _from=from_time\n    )\n\n    print(\"Active metrics:\", response.metrics)\n```\n\n### Monitors API\n\n#### Create Monitor\n\nBasic monitor creation:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.model.monitor import Monitor\nfrom datadog_api_client.v1.model.monitor_type import MonitorType\nfrom datadog_api_client.v1.model.monitor_options import MonitorOptions\nfrom datadog_api_client.v1.model.monitor_thresholds import MonitorThresholds\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    body = Monitor(\n        type=MonitorType.METRIC_ALERT,\n        query=\"avg(last_5m):avg:system.cpu.user{*} > 80\",\n        name=\"High CPU Usage\",\n        message=\"CPU usage is above 80% @slack-alerts\",\n        tags=[\"env:production\", \"team:platform\"],\n        options=MonitorOptions(\n            thresholds=MonitorThresholds(\n                critical=80.0,\n                warning=60.0\n            ),\n            notify_no_data=True,\n            no_data_timeframe=20,\n            notify_audit=False,\n            require_full_window=False,\n            include_tags=True\n        )\n    )\n\n    response = api_instance.create_monitor(body=body)\n    print(f\"Monitor created: {response.id}\")\n```\n\nAdvanced monitor with composite query:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.model.monitor import Monitor\nfrom datadog_api_client.v1.model.monitor_type import MonitorType\nfrom datadog_api_client.v1.model.monitor_options import MonitorOptions\nfrom datadog_api_client.v1.model.monitor_thresholds import MonitorThresholds\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    body = Monitor(\n        type=MonitorType.QUERY_ALERT,\n        query=\"avg(last_15m):anomalies(avg:custom.app.latency{env:production}, 'basic', 2) >= 1\",\n        name=\"Anomalous Latency Detected\",\n        message=\"\"\"Application latency is behaving abnormally.\n\nCurrent value: {{value}}\nThreshold: {{threshold}}\n\n@pagerduty-critical @slack-alerts\"\"\",\n        tags=[\"service:api\", \"priority:high\"],\n        priority=1,\n        options=MonitorOptions(\n            thresholds=MonitorThresholds(\n                critical=1.0,\n                critical_recovery=0.0\n            ),\n            notify_no_data=True,\n            no_data_timeframe=30,\n            evaluation_delay=60,\n            new_group_delay=300,\n            require_full_window=False,\n            notify_audit=True,\n            timeout_h=24,\n            renotify_interval=60,\n            escalation_message=\"Latency issue still ongoing @oncall\"\n        )\n    )\n\n    response = api_instance.create_monitor(body=body)\n    print(f\"Anomaly monitor created: {response.id}\")\n```\n\n#### List Monitors\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    monitors = api_instance.list_monitors(\n        tags=\"env:production\",\n        monitor_tags=\"team:platform\"\n    )\n\n    for monitor in monitors:\n        print(f\"ID: {monitor.id}, Name: {monitor.name}\")\n```\n\n#### Get Monitor\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    monitor = api_instance.get_monitor(monitor_id=123456)\n    print(\"Monitor details:\", monitor)\n```\n\n#### Update Monitor\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.model.monitor import Monitor\nfrom datadog_api_client.v1.model.monitor_options import MonitorOptions\nfrom datadog_api_client.v1.model.monitor_thresholds import MonitorThresholds\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    body = Monitor(\n        name=\"Updated Monitor Name\",\n        options=MonitorOptions(\n            thresholds=MonitorThresholds(\n                critical=90.0,\n                warning=70.0\n            )\n        )\n    )\n\n    response = api_instance.update_monitor(\n        monitor_id=123456,\n        body=body\n    )\n    print(\"Monitor updated\")\n```\n\n#### Delete Monitor\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    api_instance.delete_monitor(monitor_id=123456)\n    print(\"Monitor deleted\")\n```\n\n### Events API\n\n#### Post Event\n\nBasic event submission:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.events_api import EventsApi\nfrom datadog_api_client.v1.model.event_create_request import EventCreateRequest\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = EventsApi(api_client)\n\n    body = EventCreateRequest(\n        title=\"Application Deployment\",\n        text=\"Version 2.0.0 deployed to production\",\n        tags=[\"env:production\", \"version:2.0.0\", \"deployment\"]\n    )\n\n    response = api_instance.create_event(body=body)\n    print(f\"Event created: {response.event.id}\")\n```\n\nAdvanced event with priority and alert type:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.events_api import EventsApi\nfrom datadog_api_client.v1.model.event_create_request import EventCreateRequest\nfrom datadog_api_client.v1.model.event_priority import EventPriority\nfrom datadog_api_client.v1.model.event_alert_type import EventAlertType\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = EventsApi(api_client)\n\n    body = EventCreateRequest(\n        title=\"Database Migration Completed\",\n        text=\"\"\"Database migration to schema version 15 completed successfully.\n\nDuration: 45 minutes\nTables affected: 12\nRecords migrated: 1.2M\"\"\",\n        date_happened=int(time.time()),\n        priority=EventPriority.NORMAL,\n        tags=[\"service:database\", \"env:production\", \"migration\"],\n        alert_type=EventAlertType.INFO,\n        aggregation_key=\"db_migration_v15\",\n        source_type_name=\"my-app\",\n        host=\"db-server-1\"\n    )\n\n    response = api_instance.create_event(body=body)\n    print(\"Migration event created\")\n```\n\n#### List Events\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.events_api import EventsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = EventsApi(api_client)\n\n    end = int(time.time())\n    start = end - 3600  # Last hour\n\n    response = api_instance.list_events(\n        start=start,\n        end=end,\n        tags=\"env:production\"\n    )\n\n    print(f\"Found {len(response.events)} events\")\n    for event in response.events:\n        print(f\"{event.title}: {event.text}\")\n```\n\n#### Get Event\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.events_api import EventsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = EventsApi(api_client)\n\n    response = api_instance.get_event(event_id=1234567890)\n    print(\"Event details:\", response.event)\n```\n\n### Logs API\n\n#### Send Logs (v2)\n\nBasic log submission:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.logs_api import LogsApi\nfrom datadog_api_client.v2.model.http_log import HTTPLog\nfrom datadog_api_client.v2.model.http_log_item import HTTPLogItem\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = LogsApi(api_client)\n\n    body = [\n        HTTPLogItem(\n            ddsource=\"nodejs\",\n            ddtags=\"env:production,service:api\",\n            hostname=\"app-server-1\",\n            message=\"User login successful\",\n            service=\"authentication\"\n        )\n    ]\n\n    response = api_instance.submit_log(body=body)\n    print(\"Log submitted\")\n```\n\nAdvanced log submission with structured data:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.logs_api import LogsApi\nfrom datadog_api_client.v2.model.http_log_item import HTTPLogItem\nfrom datetime import datetime\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = LogsApi(api_client)\n\n    body = [\n        HTTPLogItem(\n            ddsource=\"application\",\n            ddtags=\"env:production,version:2.0.0\",\n            hostname=\"api-server-2\",\n            message=\"Payment processed successfully\",\n            service=\"payment-gateway\",\n            status=\"info\",\n            _date=datetime.now().isoformat(),\n            **{\n                \"transaction_id\": \"txn_abc123\",\n                \"amount\": 99.99,\n                \"currency\": \"USD\",\n                \"user_id\": \"user_456\",\n                \"payment_method\": \"credit_card\"\n            }\n        )\n    ]\n\n    response = api_instance.submit_log(body=body)\n    print(\"Structured log submitted\")\n```\n\n#### List Logs\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.logs_api import LogsApi\nfrom datadog_api_client.v2.model.logs_list_request import LogsListRequest\nfrom datadog_api_client.v2.model.logs_query_filter import LogsQueryFilter\nfrom datadog_api_client.v2.model.logs_list_request_page import LogsListRequestPage\nfrom datadog_api_client.v2.model.logs_sort import LogsSort\nfrom datetime import datetime, timedelta\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = LogsApi(api_client)\n\n    body = LogsListRequest(\n        filter=LogsQueryFilter(\n            query=\"service:api status:error\",\n            _from=(datetime.now() - timedelta(hours=1)).isoformat(),\n            to=datetime.now().isoformat()\n        ),\n        page=LogsListRequestPage(limit=50),\n        sort=LogsSort.TIMESTAMP_DESCENDING\n    )\n\n    response = api_instance.list_logs(body=body)\n\n    print(f\"Found {len(response.data)} error logs\")\n    for log in response.data:\n        print(log.attributes.message)\n```\n\n### Dashboards API\n\n#### Create Dashboard\n\nBasic dashboard creation:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\nfrom datadog_api_client.v1.model.dashboard import Dashboard\nfrom datadog_api_client.v1.model.dashboard_layout_type import DashboardLayoutType\nfrom datadog_api_client.v1.model.widget import Widget\nfrom datadog_api_client.v1.model.timeseries_widget_definition import TimeseriesWidgetDefinition\nfrom datadog_api_client.v1.model.timeseries_widget_request import TimeseriesWidgetRequest\nfrom datadog_api_client.v1.model.widget_display_type import WidgetDisplayType\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    body = Dashboard(\n        title=\"System Metrics Dashboard\",\n        description=\"Overview of system performance metrics\",\n        layout_type=DashboardLayoutType.ORDERED,\n        widgets=[\n            Widget(\n                definition=TimeseriesWidgetDefinition(\n                    type=\"timeseries\",\n                    requests=[\n                        TimeseriesWidgetRequest(\n                            q=\"avg:system.cpu.user{*}\",\n                            display_type=WidgetDisplayType.LINE\n                        )\n                    ],\n                    title=\"CPU Usage\"\n                )\n            )\n        ]\n    )\n\n    response = api_instance.create_dashboard(body=body)\n    print(f\"Dashboard created: {response.id}\")\n```\n\nAdvanced dashboard with multiple widgets:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\nfrom datadog_api_client.v1.model.dashboard import Dashboard\nfrom datadog_api_client.v1.model.dashboard_layout_type import DashboardLayoutType\nfrom datadog_api_client.v1.model.widget import Widget\nfrom datadog_api_client.v1.model.timeseries_widget_definition import TimeseriesWidgetDefinition\nfrom datadog_api_client.v1.model.timeseries_widget_request import TimeseriesWidgetRequest\nfrom datadog_api_client.v1.model.query_value_widget_definition import QueryValueWidgetDefinition\nfrom datadog_api_client.v1.model.query_value_widget_request import QueryValueWidgetRequest\nfrom datadog_api_client.v1.model.toplist_widget_definition import ToplistWidgetDefinition\nfrom datadog_api_client.v1.model.toplist_widget_request import ToplistWidgetRequest\nfrom datadog_api_client.v1.model.widget_display_type import WidgetDisplayType\nfrom datadog_api_client.v1.model.dashboard_template_variable import DashboardTemplateVariable\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    body = Dashboard(\n        title=\"Application Performance Dashboard\",\n        description=\"Production application metrics and monitoring\",\n        layout_type=DashboardLayoutType.ORDERED,\n        widgets=[\n            Widget(\n                definition=TimeseriesWidgetDefinition(\n                    type=\"timeseries\",\n                    requests=[\n                        TimeseriesWidgetRequest(\n                            q=\"avg:custom.app.latency{env:production}\",\n                            display_type=WidgetDisplayType.LINE\n                        )\n                    ],\n                    title=\"API Latency\",\n                    show_legend=True\n                )\n            ),\n            Widget(\n                definition=QueryValueWidgetDefinition(\n                    type=\"query_value\",\n                    requests=[\n                        QueryValueWidgetRequest(\n                            q=\"sum:custom.app.requests{env:production}.as_count()\",\n                            aggregator=\"sum\"\n                        )\n                    ],\n                    title=\"Total Requests\",\n                    autoscale=True,\n                    precision=0\n                )\n            ),\n            Widget(\n                definition=ToplistWidgetDefinition(\n                    type=\"toplist\",\n                    requests=[\n                        ToplistWidgetRequest(\n                            q=\"top(avg:custom.app.errors{env:production} by {error_type}, 10, 'sum', 'desc')\"\n                        )\n                    ],\n                    title=\"Top Errors by Type\"\n                )\n            )\n        ],\n        template_variables=[\n            DashboardTemplateVariable(\n                name=\"env\",\n                default=\"production\",\n                prefix=\"env\"\n            )\n        ],\n        notify_list=[\"user@example.com\"]\n    )\n\n    response = api_instance.create_dashboard(body=body)\n    print(f\"Advanced dashboard created: {response.id}\")\n```\n\n#### List Dashboards\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    response = api_instance.list_dashboards()\n\n    for dashboard in response.dashboards:\n        print(f\"ID: {dashboard.id}, Title: {dashboard.title}\")\n```\n\n#### Get Dashboard\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    dashboard = api_instance.get_dashboard(dashboard_id=\"abc-def-ghi\")\n    print(\"Dashboard:\", dashboard)\n```\n\n#### Update Dashboard\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\nfrom datadog_api_client.v1.model.dashboard import Dashboard\nfrom datadog_api_client.v1.model.dashboard_layout_type import DashboardLayoutType\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    body = Dashboard(\n        title=\"Updated Dashboard Title\",\n        description=\"Updated description\",\n        layout_type=DashboardLayoutType.ORDERED,\n        widgets=[]  # Include all widgets\n    )\n\n    response = api_instance.update_dashboard(\n        dashboard_id=\"abc-def-ghi\",\n        body=body\n    )\n    print(\"Dashboard updated\")\n```\n\n#### Delete Dashboard\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DashboardsApi(api_client)\n\n    api_instance.delete_dashboard(dashboard_id=\"abc-def-ghi\")\n    print(\"Dashboard deleted\")\n```\n\n### Hosts API\n\n#### List Hosts\n\nBasic host listing:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.hosts_api import HostsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = HostsApi(api_client)\n\n    response = api_instance.list_hosts()\n\n    print(f\"Total hosts: {response.total_matching}\")\n    for host in response.host_list:\n        print(f\"Host: {host.name}, Up: {host.up}\")\n```\n\nAdvanced host filtering:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.hosts_api import HostsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = HostsApi(api_client)\n\n    response = api_instance.list_hosts(\n        filter=\"env:production\",\n        sort_field=\"cpu\",\n        sort_dir=\"desc\",\n        start=0,\n        count=100,\n        _from=int(time.time()) - 3600\n    )\n\n    print(\"Production hosts sorted by CPU:\")\n    for host in response.host_list:\n        print(f\"{host.name}: CPU {host.metrics.cpu}%\")\n```\n\n#### Get Host Totals\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.hosts_api import HostsApi\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = HostsApi(api_client)\n\n    response = api_instance.get_host_totals(\n        _from=int(time.time()) - 3600\n    )\n\n    print(f\"Total up hosts: {response.total_up}\")\n    print(f\"Total active hosts: {response.total_active}\")\n```\n\n### Tags API\n\n#### Get Host Tags\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.tags_api import TagsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = TagsApi(api_client)\n\n    response = api_instance.get_host_tags(host_name=\"app-server-1\")\n    print(\"Tags for host:\", response.tags)\n```\n\n#### Update Host Tags\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.tags_api import TagsApi\nfrom datadog_api_client.v1.model.host_tags import HostTags\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = TagsApi(api_client)\n\n    body = HostTags(\n        tags=[\n            \"env:production\",\n            \"service:api\",\n            \"version:2.0.0\",\n            \"team:platform\"\n        ]\n    )\n\n    response = api_instance.update_host_tags(\n        host_name=\"app-server-1\",\n        body=body\n    )\n    print(\"Host tags updated\")\n```\n\n#### Create Host Tags\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.tags_api import TagsApi\nfrom datadog_api_client.v1.model.host_tags import HostTags\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = TagsApi(api_client)\n\n    body = HostTags(\n        tags=[\"env:staging\", \"service:api\"]\n    )\n\n    response = api_instance.create_host_tags(\n        host_name=\"app-server-2\",\n        body=body\n    )\n    print(\"Tags created for new host\")\n```\n\n#### Delete Host Tags\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.tags_api import TagsApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = TagsApi(api_client)\n\n    api_instance.delete_host_tags(host_name=\"app-server-1\")\n    print(\"All tags removed from host\")\n```\n\n### Service Checks API\n\n#### Submit Service Check\n\nBasic service check:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.service_checks_api import ServiceChecksApi\nfrom datadog_api_client.v1.model.service_check import ServiceCheck\nfrom datadog_api_client.v1.model.service_check_status import ServiceCheckStatus\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = ServiceChecksApi(api_client)\n\n    body = [\n        ServiceCheck(\n            check=\"app.health\",\n            host_name=\"app-server-1\",\n            status=ServiceCheckStatus.OK,  # OK, WARNING, CRITICAL, UNKNOWN\n            tags=[\"env:production\"]\n        )\n    ]\n\n    response = api_instance.submit_service_check(body=body)\n    print(\"Service check submitted\")\n```\n\nAdvanced service check with message:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.service_checks_api import ServiceChecksApi\nfrom datadog_api_client.v1.model.service_check import ServiceCheck\nfrom datadog_api_client.v1.model.service_check_status import ServiceCheckStatus\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = ServiceChecksApi(api_client)\n\n    body = [\n        ServiceCheck(\n            check=\"database.connection\",\n            host_name=\"db-server-1\",\n            status=ServiceCheckStatus.CRITICAL,\n            timestamp=int(time.time()),\n            message=\"Database connection failed: timeout after 30s\",\n            tags=[\"env:production\", \"service:postgres\"]\n        )\n    ]\n\n    response = api_instance.submit_service_check(body=body)\n    print(\"Critical service check submitted\")\n```\n\n### Downtimes API (v2)\n\n#### Create Downtime\n\nBasic downtime creation:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.downtimes_api import DowntimesApi\nfrom datadog_api_client.v2.model.downtime_create_request import DowntimeCreateRequest\nfrom datadog_api_client.v2.model.downtime_create_request_data import DowntimeCreateRequestData\nfrom datadog_api_client.v2.model.downtime_create_request_attributes import DowntimeCreateRequestAttributes\nfrom datadog_api_client.v2.model.downtime_schedule_create_request import DowntimeScheduleCreateRequest\nfrom datetime import datetime, timedelta\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DowntimesApi(api_client)\n\n    body = DowntimeCreateRequest(\n        data=DowntimeCreateRequestData(\n            type=\"downtime\",\n            attributes=DowntimeCreateRequestAttributes(\n                scope=\"env:staging\",\n                message=\"Planned maintenance window\",\n                schedule=DowntimeScheduleCreateRequest(\n                    start=(datetime.now() + timedelta(hours=1)).isoformat(),\n                    end=(datetime.now() + timedelta(hours=2)).isoformat()\n                )\n            )\n        )\n    )\n\n    response = api_instance.create_downtime(body=body)\n    print(f\"Downtime created: {response.data.id}\")\n```\n\nAdvanced recurring downtime:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.downtimes_api import DowntimesApi\nfrom datadog_api_client.v2.model.downtime_create_request import DowntimeCreateRequest\nfrom datadog_api_client.v2.model.downtime_create_request_data import DowntimeCreateRequestData\nfrom datadog_api_client.v2.model.downtime_create_request_attributes import DowntimeCreateRequestAttributes\nfrom datadog_api_client.v2.model.downtime_schedule_create_request import DowntimeScheduleCreateRequest\nfrom datadog_api_client.v2.model.downtime_schedule_recurrence_create_update_request import DowntimeScheduleRecurrenceCreateUpdateRequest\nfrom datadog_api_client.v2.model.downtime_monitor_identifier import DowntimeMonitorIdentifier\nfrom datetime import datetime\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DowntimesApi(api_client)\n\n    body = DowntimeCreateRequest(\n        data=DowntimeCreateRequestData(\n            type=\"downtime\",\n            attributes=DowntimeCreateRequestAttributes(\n                scope=\"host:app-server-*\",\n                message=\"Weekly maintenance window every Sunday\",\n                monitor_identifier=DowntimeMonitorIdentifier(\n                    monitor_tags=[\"maintenance:auto\"]\n                ),\n                schedule=DowntimeScheduleCreateRequest(\n                    start=datetime.now().isoformat(),\n                    recurrence=DowntimeScheduleRecurrenceCreateUpdateRequest(\n                        type=\"weeks\",\n                        period=1,\n                        week_days=[\"Sun\"]\n                    ),\n                    timezone=\"America/New_York\"\n                ),\n                notify_end_states=[\"alert\", \"warn\"],\n                notify_end_types=[\"expired\", \"canceled\"]\n            )\n        )\n    )\n\n    response = api_instance.create_downtime(body=body)\n    print(\"Recurring downtime created\")\n```\n\n#### List Downtimes\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.downtimes_api import DowntimesApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DowntimesApi(api_client)\n\n    response = api_instance.list_downtimes()\n\n    for downtime in response.data:\n        print(f\"ID: {downtime.id}, Scope: {downtime.attributes.scope}\")\n```\n\n#### Cancel Downtime\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.downtimes_api import DowntimesApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = DowntimesApi(api_client)\n\n    api_instance.cancel_downtime(downtime_id=\"downtime-id-here\")\n    print(\"Downtime cancelled\")\n```\n\n### Incidents API (v2)\n\n#### Create Incident\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.incidents_api import IncidentsApi\nfrom datadog_api_client.v2.model.incident_create_request import IncidentCreateRequest\nfrom datadog_api_client.v2.model.incident_create_data import IncidentCreateData\nfrom datadog_api_client.v2.model.incident_create_attributes import IncidentCreateAttributes\nfrom datadog_api_client.v2.model.incident_field_attributes import IncidentFieldAttributes\n\nconfiguration = Configuration()\nconfiguration.unstable_operations[\"create_incident\"] = True\n\nwith ApiClient(configuration) as api_client:\n    api_instance = IncidentsApi(api_client)\n\n    body = IncidentCreateRequest(\n        data=IncidentCreateData(\n            type=\"incidents\",\n            attributes=IncidentCreateAttributes(\n                title=\"Production API Outage\",\n                customer_impacted=True,\n                fields={\n                    \"severity\": IncidentFieldAttributes(\n                        type=\"dropdown\",\n                        value=\"SEV-1\"\n                    ),\n                    \"state\": IncidentFieldAttributes(\n                        type=\"dropdown\",\n                        value=\"active\"\n                    )\n                }\n            )\n        )\n    )\n\n    response = api_instance.create_incident(body=body)\n    print(f\"Incident created: {response.data.id}\")\n```\n\n#### List Incidents\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.incidents_api import IncidentsApi\n\nconfiguration = Configuration()\nconfiguration.unstable_operations[\"list_incidents\"] = True\n\nwith ApiClient(configuration) as api_client:\n    api_instance = IncidentsApi(api_client)\n\n    response = api_instance.list_incidents()\n\n    for incident in response.data:\n        print(f\"{incident.id}: {incident.attributes.title}\")\n```\n\n### SLOs API (Service Level Objectives)\n\n#### Create SLO\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.service_level_objectives_api import ServiceLevelObjectivesApi\nfrom datadog_api_client.v1.model.service_level_objective_request import ServiceLevelObjectiveRequest\nfrom datadog_api_client.v1.model.slo_type import SLOType\nfrom datadog_api_client.v1.model.slo_threshold import SLOThreshold\nfrom datadog_api_client.v1.model.slo_timeframe import SLOTimeframe\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = ServiceLevelObjectivesApi(api_client)\n\n    body = ServiceLevelObjectiveRequest(\n        type=SLOType.METRIC,\n        name=\"API Availability SLO\",\n        description=\"99.9% availability for production API\",\n        thresholds=[\n            SLOThreshold(\n                target=99.9,\n                target_display=\"99.9\",\n                timeframe=SLOTimeframe.THIRTY_DAYS,\n                warning=99.95\n            )\n        ],\n        query={\n            \"numerator\": \"sum:api.requests{status:ok}.as_count()\",\n            \"denominator\": \"sum:api.requests{*}.as_count()\"\n        },\n        tags=[\"service:api\", \"env:production\"]\n    )\n\n    response = api_instance.create_slo(body=body)\n    print(f\"SLO created: {response.data[0].id}\")\n```\n\n#### List SLOs\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.service_level_objectives_api import ServiceLevelObjectivesApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = ServiceLevelObjectivesApi(api_client)\n\n    response = api_instance.list_slos(tags=\"service:api\")\n\n    for slo in response.data:\n        print(f\"{slo.name}: {slo.thresholds[0].target}%\")\n```\n\n### Users API\n\n#### List Users\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.users_api import UsersApi\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = UsersApi(api_client)\n\n    response = api_instance.list_users()\n\n    for user in response.data:\n        print(f\"{user.attributes.name}: {user.attributes.email}\")\n```\n\n#### Create User\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.users_api import UsersApi\nfrom datadog_api_client.v2.model.user_create_request import UserCreateRequest\nfrom datadog_api_client.v2.model.user_create_data import UserCreateData\nfrom datadog_api_client.v2.model.user_create_attributes import UserCreateAttributes\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = UsersApi(api_client)\n\n    body = UserCreateRequest(\n        data=UserCreateData(\n            type=\"users\",\n            attributes=UserCreateAttributes(\n                name=\"John Doe\",\n                email=\"john.doe@example.com\"\n            )\n        )\n    )\n\n    response = api_instance.create_user(body=body)\n    print(f\"User created: {response.data.id}\")\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.exceptions import ApiException\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n\n    try:\n        monitors = api_instance.list_monitors()\n        print(\"Success:\", monitors)\n    except ApiException as e:\n        print(f\"API Exception: {e.status} - {e.reason}\")\n        print(f\"Body: {e.body}\")\n    except Exception as e:\n        print(f\"Error: {str(e)}\")\n```\n\n### Advanced Error Handling with Retry\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nfrom datadog_api_client.v1.model.metrics_payload import MetricsPayload\nfrom datadog_api_client.v1.model.series import Series\nfrom datadog_api_client.exceptions import ApiException\nimport time\n\nconfiguration = Configuration()\n\ndef submit_metrics_with_retry(max_retries=3):\n    with ApiClient(configuration) as api_client:\n        api_instance = MetricsApi(api_client)\n\n        body = MetricsPayload(\n            series=[\n                Series(\n                    metric=\"custom.metric\",\n                    points=[[int(time.time()), 100]]\n                )\n            ]\n        )\n\n        for attempt in range(max_retries):\n            try:\n                result = api_instance.submit_metrics(body=body)\n                print(\"Metrics submitted successfully\")\n                return result\n            except ApiException as e:\n                if e.status == 429:\n                    print(f\"Rate limited - retry {attempt + 1}/{max_retries}\")\n                    time.sleep(2 ** attempt)\n                elif e.status == 403:\n                    print(\"Authentication failed - check API keys\")\n                    raise\n                elif e.status == 400:\n                    print(f\"Bad request: {e.body}\")\n                    raise\n                else:\n                    print(f\"Unexpected error: {e}\")\n                    raise\n\nsubmit_metrics_with_retry()\n```\n\n## Pagination\n\n### Manual Pagination\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.hosts_api import HostsApi\n\nconfiguration = Configuration()\n\ndef get_all_hosts():\n    with ApiClient(configuration) as api_client:\n        api_instance = HostsApi(api_client)\n\n        all_hosts = []\n        start = 0\n        count = 100\n        has_more = True\n\n        while has_more:\n            response = api_instance.list_hosts(start=start, count=count)\n\n            if response.host_list:\n                all_hosts.extend(response.host_list)\n\n            start += count\n            has_more = len(response.host_list) == count\n\n        return all_hosts\n\nhosts = get_all_hosts()\nprint(f\"Retrieved {len(hosts)} total hosts\")\n```\n\n### Automatic Pagination with Iterator\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v2.api.incidents_api import IncidentsApi\n\nconfiguration = Configuration()\nconfiguration.unstable_operations[\"list_incidents\"] = True\n\nwith ApiClient(configuration) as api_client:\n    api_instance = IncidentsApi(api_client)\n\n    # Some endpoints support pagination\n    for incident in api_instance.list_incidents_with_pagination():\n        print(f\"Incident: {incident.id} - {incident.attributes.title}\")\n```\n\n## Async/Await Pattern\n\n```python\nimport asyncio\nfrom datadog_api_client import AsyncApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.api.events_api import EventsApi\nfrom datadog_api_client.v1.model.monitor import Monitor\nfrom datadog_api_client.v1.model.monitor_type import MonitorType\nfrom datadog_api_client.v1.model.event_create_request import EventCreateRequest\n\nasync def monitor_workflow():\n    configuration = Configuration()\n\n    async with AsyncApiClient(configuration) as api_client:\n        monitors_api = MonitorsApi(api_client)\n        events_api = EventsApi(api_client)\n\n        try:\n            # Create monitor\n            monitor_body = Monitor(\n                type=MonitorType.METRIC_ALERT,\n                query=\"avg(last_5m):avg:system.cpu.user{*} > 80\",\n                name=\"High CPU Alert\",\n                message=\"CPU is high @slack-alerts\"\n            )\n\n            monitor = await monitors_api.create_monitor(body=monitor_body)\n            print(f\"Monitor created: {monitor.id}\")\n\n            # Post event about monitor creation\n            event_body = EventCreateRequest(\n                title=\"Monitor Created\",\n                text=f\"Created new monitor: {monitor.name}\",\n                tags=[\"automation\", \"monitoring\"]\n            )\n\n            await events_api.create_event(body=event_body)\n            print(\"Event posted\")\n\n            # List all monitors\n            monitors = await monitors_api.list_monitors()\n            print(f\"Total monitors: {len(monitors)}\")\n\n        except Exception as e:\n            print(f\"Workflow failed: {e}\")\n\nasyncio.run(monitor_workflow())\n```\n\n## Concurrent Async Operations\n\n```python\nimport asyncio\nfrom datadog_api_client import AsyncApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\nfrom datadog_api_client.v1.api.hosts_api import HostsApi\n\nasync def fetch_all_data():\n    configuration = Configuration()\n\n    async with AsyncApiClient(configuration) as api_client:\n        monitors_api = MonitorsApi(api_client)\n        dashboards_api = DashboardsApi(api_client)\n        hosts_api = HostsApi(api_client)\n\n        # Run multiple API calls concurrently\n        monitors, dashboards, hosts = await asyncio.gather(\n            monitors_api.list_monitors(),\n            dashboards_api.list_dashboards(),\n            hosts_api.list_hosts()\n        )\n\n        print(f\"Monitors: {len(monitors)}\")\n        print(f\"Dashboards: {len(dashboards.dashboards)}\")\n        print(f\"Hosts: {len(hosts.host_list)}\")\n\nasyncio.run(fetch_all_data())\n```\n\n## Threaded API Client\n\n```python\nfrom datadog_api_client import Configuration, ThreadedApiClient\nfrom datadog_api_client.v1.api.dashboards_api import DashboardsApi\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\nwith ThreadedApiClient(configuration) as api_client:\n    dashboards_api = DashboardsApi(api_client)\n    monitors_api = MonitorsApi(api_client)\n\n    # Start both requests concurrently\n    dashboards_future = dashboards_api.list_dashboards()\n    monitors_future = monitors_api.list_monitors()\n\n    # Wait for results\n    dashboards = dashboards_future.get()\n    monitors = monitors_future.get()\n\n    print(f\"Dashboards: {len(dashboards.dashboards)}\")\n    print(f\"Monitors: {len(monitors)}\")\n```\n\n## Type Hints\n\nThe package includes full type hints for better IDE support:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\nfrom datadog_api_client.v1.model.monitor import Monitor\nfrom datadog_api_client.v1.model.monitor_type import MonitorType\nfrom datadog_api_client.v1.model.series import Series\nfrom datadog_api_client.v1.model.event_create_request import EventCreateRequest\nfrom datadog_api_client.v1.model.event_priority import EventPriority\nfrom datadog_api_client.v1.model.event_alert_type import EventAlertType\nfrom typing import List\n\nconfiguration: Configuration = Configuration()\n\n# Monitor type\nmonitor: Monitor = Monitor(\n    type=MonitorType.METRIC_ALERT,\n    query=\"avg(last_5m):avg:system.cpu.user{*} > 80\",\n    name=\"CPU Alert\",\n    message=\"High CPU usage detected\"\n)\n\n# Metric series type\nseries: Series = Series(\n    metric=\"custom.metric\",\n    points=[[1234567890, 100]],\n    type=\"gauge\",\n    host=\"server-1\",\n    tags=[\"env:prod\"]\n)\n\n# Event type\nevent: EventCreateRequest = EventCreateRequest(\n    title=\"Deployment\",\n    text=\"Version deployed\",\n    date_happened=1234567890,\n    priority=EventPriority.NORMAL,\n    tags=[\"deployment\"],\n    alert_type=EventAlertType.INFO\n)\n```\n\n## Debug Logging\n\nEnable debug logging to see request/response details:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nimport logging\n\n# Enable debug logging\nlogging.basicConfig(level=logging.DEBUG)\n\nconfiguration = Configuration()\nconfiguration.debug = True\n\nwith ApiClient(configuration) as api_client:\n    # All API calls will log request and response details\n    pass\n```\n\n## Custom Server Configuration\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\n\nconfiguration = Configuration()\n\n# Custom server URL\nconfiguration.host = \"https://api.datadoghq.com\"\n\n# Or use server variables\nconfiguration.server_variables[\"site\"] = \"datadoghq.eu\"\nconfiguration.server_variables[\"subdomain\"] = \"app\"\n\nwith ApiClient(configuration) as api_client:\n    # Use api_client for API calls\n    pass\n```\n\n## Context Manager Best Practices\n\nAlways use context managers to ensure proper resource cleanup:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.monitors_api import MonitorsApi\n\nconfiguration = Configuration()\n\n# Good: Using context manager\nwith ApiClient(configuration) as api_client:\n    api_instance = MonitorsApi(api_client)\n    monitors = api_instance.list_monitors()\n\n# The client is automatically closed when exiting the context\n```\n\n## Batch Operations\n\nSubmit multiple operations efficiently:\n\n```python\nfrom datadog_api_client import ApiClient, Configuration\nfrom datadog_api_client.v1.api.metrics_api import MetricsApi\nfrom datadog_api_client.v1.model.metrics_payload import MetricsPayload\nfrom datadog_api_client.v1.model.series import Series\nimport time\n\nconfiguration = Configuration()\n\nwith ApiClient(configuration) as api_client:\n    api_instance = MetricsApi(api_client)\n\n    # Batch multiple metrics in one request\n    now = int(time.time())\n    series_list = []\n\n    for i in range(100):\n        series_list.append(\n            Series(\n                metric=f\"custom.metric.{i}\",\n                points=[[now, i]],\n                type=\"gauge\",\n                tags=[\"batch:true\"]\n            )\n        )\n\n    body = MetricsPayload(series=series_list)\n    response = api_instance.submit_metrics(body=body)\n    print(\"Batch of 100 metrics submitted\")\n```\n"
  },
  {
    "path": "content/datadog/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Datadog Python package for DogStatsD metrics, ThreadStats, and legacy Datadog HTTP API helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.52.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"datadog,monitoring,metrics,dogstatsd,observability\"\n---\n\n# Datadog Python Package Guide\n\n## Golden Rule\n\nUse `datadog==0.52.1` when you specifically need the legacy `datadog` package: DogStatsD metrics, `ThreadStats`, or the older `datadog.api` wrappers. Do not confuse it with `datadog-api-client-python`, which is a different package for the full generated Datadog HTTP API surface.\n\n## When To Use This Package\n\nUse `datadog` for these cases:\n\n- send custom metrics, service checks, and DogStatsD packets to a local or remote Datadog Agent\n- emit application metrics over HTTP with `ThreadStats`\n- use older `datadog.api.*` helpers that already exist in a codebase\n\nUse `datadog-api-client` instead when you need broad, current Datadog API coverage. The upstream `datadogpy` README explicitly points to `datadog-api-client-python` for full HTTP API support.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"datadog==0.52.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"datadog==0.52.1\"\npoetry add \"datadog==0.52.1\"\n```\n\nPyPI currently publishes `0.52.1` as a universal `py2.py3` wheel, but new code should still be written for your actual runtime and validated in that environment.\n\n## Authentication And Setup\n\n`initialize()` configures both the HTTP API helpers and the default DogStatsD client.\n\n### HTTP API or ThreadStats setup\n\nAPI key and app key are required for `datadog.api` and `ThreadStats` unless you are only using DogStatsD:\n\n```python\nfrom datadog import initialize\n\noptions = {\n    \"api_key\": \"your-api-key\",\n    \"app_key\": \"your-app-key\",\n    \"api_host\": \"https://api.datadoghq.com\",\n}\n\ninitialize(**options)\n```\n\nEnvironment-variable setup also works:\n\n```bash\nexport DATADOG_API_KEY=\"your-api-key\"\nexport DATADOG_APP_KEY=\"your-app-key\"\n```\n\nIf those are unset, the library falls back to `DD_API_KEY` and `DD_APP_KEY`.\n\n### DogStatsD-only setup over UDP\n\nDogStatsD does not need API or app keys, but it does need a Datadog Agent or compatible DogStatsD endpoint to be reachable:\n\n```python\nfrom datadog import initialize, statsd\n\ninitialize(\n    statsd_host=\"127.0.0.1\",\n    statsd_port=8125,\n    statsd_constant_tags=[\"env:dev\", \"service:checkout\"],\n)\n\nstatsd.increment(\"checkout.request\")\n```\n\n### DogStatsD setup over UDS\n\nIf the Agent exposes a Unix domain socket, prefer that over UDP in local-container deployments:\n\n```python\nfrom datadog import initialize, statsd\n\ninitialize(\n    statsd_socket_path=\"/var/run/datadog/dsd.socket\",\n    statsd_constant_tags=[\"env:prod\", \"service:checkout\"],\n)\n\nstatsd.gauge(\"workers.ready\", 4)\n```\n\n`statsd_socket_path` overrides `statsd_host` and `statsd_port`.\n\n## Core Usage\n\n### Send custom metrics with the default DogStatsD client\n\n```python\nfrom datadog import initialize, statsd\n\ninitialize(\n    statsd_host=\"127.0.0.1\",\n    statsd_port=8125,\n    statsd_namespace=\"myapp\",\n    statsd_constant_tags=[\"env:dev\", \"service:payments\"],\n)\n\nstatsd.increment(\"orders.created\", tags=[\"region:us-west-2\"])\nstatsd.gauge(\"queue.depth\", 17)\nstatsd.histogram(\"checkout.latency_ms\", 42.5)\n```\n\nThe upstream docs describe `DogStatsd` as thread-safe, so sharing the client is acceptable when your process model is otherwise safe.\n\n### Use an explicit `DogStatsd` client\n\nCreate your own client when you do not want the module-level `statsd` singleton:\n\n```python\nfrom datadog.dogstatsd import DogStatsd\n\nclient = DogStatsd(\n    host=\"127.0.0.1\",\n    port=8125,\n    namespace=\"worker\",\n    constant_tags=[\"env:prod\", \"service:billing\"],\n)\n\nclient.increment(\"jobs.started\")\nclient.gauge(\"jobs.inflight\", 3)\n```\n\nUseful constructor options from the docs include `socket_path`, `use_default_route`, `disable_telemetry`, `max_buffer_len`, and `origin_detection_enabled`.\n\n### Send an event through the legacy HTTP API wrapper\n\n```python\nfrom datadog import api, initialize\n\ninitialize(api_key=\"your-api-key\", app_key=\"your-app-key\")\n\napi.Event.create(\n    title=\"deploy finished\",\n    text=\"release 2026.03.12 completed successfully\",\n    tags=[\"env:prod\", \"service:web\"],\n)\n```\n\nThis style is convenient for older codebases, but for broad modern API coverage use `datadog-api-client`.\n\n### Collect application metrics with `ThreadStats`\n\n`ThreadStats` records metrics in-process and flushes them through the Datadog HTTP API:\n\n```python\nfrom datadog import initialize\nfrom datadog.threadstats import ThreadStats\n\ninitialize(api_key=\"your-api-key\", app_key=\"your-app-key\")\n\nstats = ThreadStats(namespace=\"web\", constant_tags=[\"env:prod\", \"service:frontend\"])\nstats.start(flush_interval=10)\n\nstats.increment(\"requests.count\")\n\nwith stats.timer(\"db.query.time\"):\n    load_user_profile()\n```\n\nIf you need manual control, disable the background thread:\n\n```python\nstats.start(flush_in_thread=False)\nstats.increment(\"jobs.processed\")\nstats.flush()\n```\n\nFor gevent servers, the docs support `flush_in_greenlet=True` after monkey-patching gevent before startup.\n\n## Configuration Notes\n\nImportant `initialize()` options called out by the upstream docs:\n\n- `api_host`: Datadog API endpoint for your site or proxy setup\n- `proxies`: requests-style proxy mapping for HTTP API calls\n- `cacert`: certificate verification path, `True` for system certs, or `False` to skip verification\n- `return_raw_response`: return both the raw response object and decoded content\n- `statsd_use_default_route`: resolve DogStatsD host from the container default route\n- `statsd_disable_buffering`: toggle DogStatsD buffering behavior\n- `statsd_namespace`: prepend a metric namespace\n- `statsd_constant_tags`: attach tags to every emitted metric\n\nThe library also documents `hostname_from_config`, but it is marked as deprecated.\n\n## Common Pitfalls\n\n- `datadog` is not `datadog-api-client-python`. The docs URL `https://datadoghq.dev/datadog-api-client-python/` belongs to a different package.\n- DogStatsD metrics need a reachable Datadog Agent or DogStatsD endpoint. `pip install datadog` alone does not make metrics arrive anywhere.\n- `ThreadStats` uses the HTTP API, so it needs an API key and usually an app key. DogStatsD-only flows do not.\n- `stats.start(flush_in_thread=False)` does not auto-flush. You must call `flush()` yourself.\n- `statsd_socket_path` overrides UDP host and port settings. If both are set, the socket path wins.\n- In Kubernetes, `DD_ENTITY_ID` is used for origin detection. If you use `constant_tags`, append to that list rather than trying to replace Datadog’s internal entity tag behavior.\n- In development, `DD_DOGSTATSD_DISABLE=True` disables `statsd` metric collection. That can make local tests look like metrics are silently ignored.\n- The docs describe packet-size tuning with `max_buffer_len`. Only change it if you understand the network path; the library already picks defaults for UDP and UDS.\n\n## Version-Sensitive Notes\n\n- PyPI lists `0.52.1` as the current package version and published it on July 31, 2025.\n- The package remains the maintained `datadogpy` library, but upstream positions it as a focused library for DogStatsD, `ThreadStats`, and legacy wrappers rather than the complete Datadog API client.\n- If you are starting fresh on Datadog resource-management APIs, prefer the separate `datadog-api-client` package and use this package only when its DogStatsD or legacy wrapper model is the right fit.\n\n## Official Sources\n\n- Datadog Python client docs: https://datadogpy.readthedocs.io/en/latest/\n- Datadog Python client docs index summary: https://datadogpy.readthedocs.io/en/stable/index.html\n- Datadog PyPI package page: https://pypi.org/project/datadog/\n- Datadog `datadogpy` repository: https://github.com/DataDog/datadogpy\n"
  },
  {
    "path": "content/datahub/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"DataHub Python SDK for metadata management: search, lineage, data quality assertions, and enriching datasets with descriptions, tags, glossary terms, domains, and structured properties\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0.5\"\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"datahub,metadata,data-catalog,lineage,data-quality,search,governance\"\n---\n\n# DataHub Python SDK\n\nYou are a DataHub API expert. Help me write code using the DataHub Python SDK (`acryl-datahub`) and the DataHub Cloud SDK (`acryl-datahub-cloud`).\n\nOfficial documentation: https://docs.datahub.com/docs/python-sdk/sdk-v2/\n\n## Installation\n\n```bash\npip install acryl-datahub\n```\n\nFor DataHub Cloud features (smart assertions, subscriptions):\n\n```bash\npip install acryl-datahub-cloud\n```\n\nRequires Python >= 3.10.\n\n## Client Initialization\n\n```python\nfrom datahub.sdk import DataHubClient\n\nclient = DataHubClient(server=\"<your_server>\", token=\"<your_token>\")\n```\n\n- **Hosted (DataHub Cloud):** `server=\"https://<your-instance>.acryl.io/gms\"`\n- **Local:** `server=\"http://localhost:8080\"`\n\nGenerate a Personal Access Token from your DataHub instance settings.\n\n### Initialize from environment\n\nSet `DATAHUB_GMS_URL` and `DATAHUB_GMS_TOKEN` environment variables, or run `datahub init` to create `~/.datahubenv`:\n\n```python\nclient = DataHubClient.from_env()\n```\n\n### Verify connectivity\n\n```python\nclient.test_connection()\n```\n\n## Client Properties\n\nThe `DataHubClient` exposes specialized sub-clients as properties:\n\n| Property | Type | Purpose |\n|----------|------|---------|\n| `client.entities` | `EntityClient` | CRUD operations on datasets, containers, etc. |\n| `client.search` | `SearchClient` | Search and discover metadata |\n| `client.lineage` | `LineageClient` | Add and retrieve lineage |\n| `client.resolve` | `ResolverClient` | Resolve metadata references |\n| `client.assertions` | (Cloud only) | Data quality assertions |\n| `client.subscriptions` | (Cloud only) | Notification subscriptions |\n\n## Search\n\nSearch across your entire data landscape using queries, filters, or both.\n\n### Query-based search\n\n```python\nresults = client.search.get_urns(query=\"sales\")\nfor urn in results:\n    print(urn)\n```\n\n### Filter-based search\n\n```python\nfrom datahub.sdk import FilterDsl as F\n\nresults = client.search.get_urns(filter=F.platform(\"snowflake\"))\n```\n\n### Combine query and filters\n\n```python\nresults = client.search.get_urns(\n    query=\"forecast\",\n    filter=F.and_(F.platform(\"snowflake\"), F.entity_type(\"dataset\"))\n)\n```\n\n### Filter reference\n\n| Filter | Example |\n|--------|---------|\n| Platform | `F.platform(\"snowflake\")` |\n| Environment | `F.env(\"PROD\")` |\n| Entity type | `F.entity_type(\"dataset\")` |\n| Domain | `F.domain(\"urn:li:domain:marketing\")` |\n| Subtype | `F.entity_subtype(\"ML Experiment\")` |\n| Owner | `F.owner(\"urn:li:corpuser:jane\")` |\n| Tag | `F.tag(\"urn:li:tag:critical\")` |\n| Glossary term | `F.glossary_term(\"urn:li:glossaryTerm:PII\")` |\n| Container | `F.container(\"urn:li:container:my_db\")` |\n| Custom property | `F.has_custom_property(\"department\", \"sales\")` |\n| Deletion status | `F.soft_deleted(\"NOT_SOFT_DELETED\")` |\n| Custom field condition | `F.custom_filter(field=\"urn\", condition=\"CONTAIN\", values=[\"example\"])` |\n\nSee `references/search.md` for detailed filter descriptions, custom_filter conditions, searchable fields, and common patterns.\n\n### Logical operators\n\n```python\n# OR: charts or Snowflake datasets\nresults = client.search.get_urns(\n    filter=F.or_(\n        F.entity_type(\"chart\"),\n        F.and_(F.platform(\"snowflake\"), F.entity_type(\"dataset\")),\n    )\n)\n\n# NOT: datasets not tagged \"verified\"\nresults = client.search.get_urns(\n    filter=F.and_(F.entity_type(\"dataset\"), F.not_(F.tag(\"urn:li:tag:verified\")))\n)\n```\n\n## Entity CRUD\n\n### Create a dataset\n\n```python\nfrom datahub.sdk import Dataset\n\ndataset = Dataset(\n    platform=\"snowflake\",\n    name=\"prod.analytics.users\",\n    env=\"PROD\",\n    description=\"Core users table\",\n    tags=[\"critical\", \"pii\"],\n    terms=[\"urn:li:glossaryTerm:PII\"],\n    domain=\"urn:li:domain:analytics\",\n    owners=[\"urn:li:corpuser:jane\"],\n    custom_properties={\"team\": \"data-eng\", \"refresh_cadence\": \"hourly\"},\n    schema=[\n        (\"user_id\", \"BIGINT\"),\n        (\"email\", \"VARCHAR\"),\n        (\"created_at\", \"TIMESTAMP\", \"Account creation timestamp\"),\n    ],\n)\n\nclient.entities.create(dataset)\n```\n\n### Get an entity\n\n```python\ndataset = client.entities.get(\"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\")\n\nprint(dataset.description)\nprint(dataset.schema)\nprint(dataset.custom_properties)\n```\n\n### Update an entity\n\n```python\ndataset.set_description(\"Core users table with profile data\")\ndataset.set_custom_properties({\"team\": \"data-eng\", \"refresh_cadence\": \"daily\"})\nclient.entities.update(dataset)\n```\n\n### Upsert (create or update)\n\n```python\nclient.entities.upsert(dataset)\n```\n\n### Delete an entity\n\n```python\nclient.entities.delete(\n    \"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\",\n    hard=False,   # soft delete (default); set True for permanent deletion\n    cascade=False, # cascade to children (containers, dataflows)\n)\n```\n\n## Enriching Metadata\n\nPattern: fetch the entity, call setters, then update. All setters work across supported entity types.\n\n```python\ndataset = client.entities.get(dataset_urn)\n\ndataset.set_description(\"Updated description for this table\")\ndataset.set_tags([\"critical\", \"pii\"])\ndataset.set_terms([\"urn:li:glossaryTerm:PII\", \"urn:li:glossaryTerm:CustomerData\"])\ndataset.set_domain(\"urn:li:domain:analytics\")\ndataset.set_owners([\"urn:li:corpuser:alice\", \"urn:li:corpGroup:data-engineering\"])\ndataset.set_custom_properties({\"team\": \"data-eng\", \"refresh_cadence\": \"hourly\"})\ndataset.set_structured_properties({\n    \"urn:li:structuredProperty:data_tier\": [\"tier1\"],\n    \"urn:li:structuredProperty:retention_days\": [90],\n})\n\n# Column-level: tags, terms, and descriptions on individual schema fields\nfor field in dataset.schema:\n    if field.field_path == \"email\":\n        field.add_tag(\"pii\")\n        field.add_term(\"urn:li:glossaryTerm:EmailAddress\")\n        field.set_description(\"User email address, PII-classified\")\n\nclient.entities.update(dataset)\n```\n\n### Available setters\n\n| Method | Example value |\n|--------|---------------|\n| `set_description(str)` | `\"Core users table\"` |\n| `set_tags(list)` | `[\"critical\", \"pii\"]` |\n| `set_terms(list)` | `[\"urn:li:glossaryTerm:PII\"]` |\n| `set_domain(str)` | `\"urn:li:domain:analytics\"` |\n| `set_owners(list)` | `[\"urn:li:corpuser:alice\"]` |\n| `set_custom_properties(dict)` | `{\"team\": \"data-eng\"}` |\n| `set_structured_properties(dict)` | `{\"urn:li:structuredProperty:tier\": [\"tier1\"]}` |\n\nColumn-level methods on `SchemaField`: `add_tag(str)`, `add_term(str)`, `set_description(str)`.\n\n## Containers\n\nContainers organize datasets into hierarchies (databases, schemas, folders). Use `DatabaseKey` and `SchemaKey` to create them with proper parent-child relationships.\n\n```python\nfrom datahub.sdk import Container\nfrom datahub.emitter.mcp_builder import DatabaseKey\n\ncontainer = Container(\n    DatabaseKey(platform=\"snowflake\", instance=\"production\", database=\"analytics_db\"),\n    display_name=\"Analytics Database\",\n    subtype=\"Database\",\n)\nclient.entities.upsert(container)\n```\n\n## Documents\n\nDocuments store knowledge content — tutorials, runbooks, FAQs, or external doc references (Notion, Confluence).\n\n```python\nfrom datahub.sdk import Document\n\ndoc = Document.create_document(\n    id=\"getting-started-guide\",\n    title=\"Getting Started with DataHub\",\n    text=\"# Welcome\\n\\nThis guide will help you get started...\",\n    tags=[\"onboarding\"],\n    domain=\"urn:li:domain:data-governance\",\n)\nclient.entities.upsert(doc)\n```\n\nSee `references/entities.md` for nested container hierarchies, external documents, AI-only context documents, and document properties.\n\n## Lineage\n\n### Table-level lineage\n\n```python\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,raw.events,PROD)\",\n    downstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,analytics.sessions,PROD)\",\n)\n```\n\n### Column-level lineage\n\n```python\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,raw.events,PROD)\",\n    downstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,analytics.sessions,PROD)\",\n    column_lineage={\n        \"session_id\": [\"event_id\"],\n        \"user_id\": [\"user_id\"],\n        \"session_start\": [\"event_timestamp\"],\n    },\n    transformation_text=\"SELECT event_id AS session_id, user_id, MIN(event_timestamp) AS session_start FROM raw.events GROUP BY event_id, user_id\",\n)\n```\n\n### Copy lineage with auto column matching\n\n```python\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:postgres,users,PROD)\",\n    downstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,users_replica,PROD)\",\n    column_lineage=\"auto_fuzzy\",  # or \"auto_strict\", explicit mapping dict, or False\n)\n```\n\n### Infer lineage from SQL\n\n```python\nclient.lineage.infer_lineage_from_sql(\n    query_text=\"INSERT INTO analytics.daily_revenue SELECT date, SUM(amount) FROM raw.orders GROUP BY date\",\n    platform=\"snowflake\",\n    env=\"PROD\",\n)\n```\n\n### Get lineage (impact analysis)\n\n```python\nupstream_results = client.lineage.get_lineage(\n    source_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,analytics.sessions,PROD)\",\n    direction=\"upstream\",\n    max_hops=3,\n)\n\nfor result in upstream_results:\n    print(f\"{result.urn} ({result.type}) - {result.hops} hop(s) away\")\n\n# Column-level lineage\ncolumn_results = client.lineage.get_lineage(\n    source_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,analytics.sessions,PROD)\",\n    source_column=\"session_id\",\n    direction=\"upstream\",\n)\n```\n\nSee `references/lineage.md` for Data Job lineage, cross-entity lineage, and advanced patterns.\n\n## Data Quality Assertions (DataHub Cloud)\n\nRequires `acryl-datahub-cloud`. Smart assertions use anomaly detection to monitor data freshness, volume, and column metrics.\n\n### Freshness assertion\n\n```python\nassertion = client.assertions.sync_smart_freshness_assertion(\n    dataset_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\",\n    display_name=\"Freshness Anomaly Monitor\",\n    detection_mechanism=\"information_schema\",\n    sensitivity=\"medium\",  # \"low\", \"medium\", \"high\"\n    tags=[\"automated\", \"freshness\"],\n    enabled=True,\n)\n```\n\n### Volume assertion\n\n```python\nassertion = client.assertions.sync_smart_volume_assertion(\n    dataset_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\",\n    display_name=\"Volume Check\",\n    detection_mechanism=\"information_schema\",\n    sensitivity=\"medium\",\n    schedule=\"0 */6 * * *\",\n    tags=[\"automated\", \"volume\"],\n    enabled=True,\n)\n```\n\n### Column metric assertion\n\n```python\nassertion = client.assertions.sync_smart_column_metric_assertion(\n    dataset_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\",\n    column_name=\"email\",\n    metric_type=\"null_count\",  # \"null_count\", \"unique_count\", \"empty_count\"\n    display_name=\"Email Null Check\",\n    detection_mechanism=\"all_rows_query_datahub_dataset_profile\",\n    tags=[\"automated\", \"column_quality\"],\n    enabled=True,\n)\n```\n\n### SQL assertion\n\n```python\nassertion = client.assertions.sync_smart_sql_assertion(\n    dataset_urn=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,prod.analytics.users,PROD)\",\n    display_name=\"Active Users Count\",\n    statement=\"SELECT COUNT(*) FROM prod.analytics.users WHERE status = 'active'\",\n    sensitivity=\"medium\",\n    schedule=\"0 */6 * * *\",\n    tags=[\"automated\", \"sql_check\"],\n    enabled=True,\n)\n```\n\nSee `references/assertions.md` for bulk assertion creation, updating, and advanced patterns.\n\n## URN Format\n\nDataHub identifies every entity with a URN (Uniform Resource Name) — a globally unique, typed identifier. URNs are the primary way to reference entities across search, lineage, and metadata operations.\n\n**Do not guess or hand-craft URNs.** URNs should come from search results, entity creation responses, or known ingestion sources. Use `client.search.get_urns()` to discover existing entities before referencing them.\n\n| Entity | URN Pattern | Description |\n|--------|-------------|-------------|\n| Dataset | `urn:li:dataset:(urn:li:dataPlatform:{platform},{name},{env})` | Tables, views, topics, and files in warehouses, lakes, OLTP databases, etc. |\n| Schema field | `urn:li:schemaField:({dataset_urn},{field_path})` | A column within a dataset. Not a standalone entity — access via `dataset.schema`. |\n| Container | `urn:li:container:{key}` | Databases, schemas, folders, S3 buckets — logical grouping of datasets |\n| Data Flow | `urn:li:dataFlow:({orchestrator},{flow_id},{env})` | A pipeline or DAG (e.g. an Airflow DAG, a Spark application) |\n| Data Job | `urn:li:dataJob:({flow_urn},{job_id})` | A task within a data flow (e.g. an Airflow task, a dbt model run) |\n| Dashboard | `urn:li:dashboard:({platform},{id})` | BI dashboards (Looker, Tableau, PowerBI, etc.) |\n| Chart | `urn:li:chart:({platform},{id})` | Individual visualizations or tiles within a dashboard |\n| Domain | `urn:li:domain:{id}` | Business domain for organizing assets (e.g. Finance, Marketing) |\n| Glossary term | `urn:li:glossaryTerm:{name}` | Standardized business vocabulary (e.g. PII, Revenue, Customer) |\n| Tag | `urn:li:tag:{name}` | Lightweight labels for classification (e.g. critical, deprecated) |\n| Document | `urn:li:document:{id}` | Knowledge content: tutorials, runbooks, FAQs, or external doc references |\n| Assertion | `urn:li:assertion:{id}` | A data quality check bound to a dataset |\n| User | `urn:li:corpuser:{id}` | An individual user identity |\n| Group | `urn:li:corpGroup:{id}` | A team or group of users |\n\nYou can use string URNs directly or typed URN classes:\n\n```python\nfrom datahub.metadata.urns import DatasetUrn\n\nurn = DatasetUrn(\"urn:li:dataset:(urn:li:dataPlatform:snowflake,db.schema.table,PROD)\")\nprint(urn.platform)  # snowflake\nprint(urn.name)      # db.schema.table\nprint(urn.env)       # PROD\n```\n\n## Best Practices\n\n- **Use `from_env()`** for production scripts to avoid hardcoding credentials.\n- **Use `upsert()`** when you want idempotent create-or-update behavior.\n- **Soft delete by default.** Only use `hard=True` when you need permanent removal.\n- **Tag consistently.** Use plain tag names (e.g., `\"critical\"`) — the SDK auto-converts to URN format.\n- **Process assertions single-threaded per dataset** to avoid race conditions.\n- **Batch operations** with delays between batches to avoid overwhelming the API during large-scale updates.\n"
  },
  {
    "path": "content/datahub/docs/sdk/python/references/assertions.md",
    "content": "# Bulk Data Quality Assertions\n\nCreate and manage smart assertions at scale using the DataHub Cloud Python SDK (`acryl-datahub-cloud`).\n\nThe actor making API calls needs `Edit Assertions` and `Edit Monitors` privileges.\n\n## Setup\n\n```python\nfrom datahub.sdk import DataHubClient, FilterDsl as F\nfrom datahub.metadata.urns import DatasetUrn\n\nclient = DataHubClient(server=\"<your_server>\", token=\"<your_token>\")\n```\n\n## Discover Target Tables\n\n### By specific URNs\n\n```python\ntable_urns = [\n    \"urn:li:dataset:(urn:li:dataPlatform:snowflake,database.schema.users,PROD)\",\n    \"urn:li:dataset:(urn:li:dataPlatform:snowflake,database.schema.orders,PROD)\",\n]\ndatasets = [DatasetUrn.from_string(urn) for urn in table_urns]\n```\n\n### By search pattern\n\n```python\nresults = client.search.get_urns(\n    filter=F.and_(\n        F.entity_type(\"dataset\"),\n        F.platform(\"snowflake\"),\n        F.env(\"PROD\"),\n    )\n)\ndatasets = [DatasetUrn.from_string(str(urn)) for urn in results]\n```\n\n### By tag or domain\n\n```python\ncritical_datasets = client.search.get_urns(\n    filter=F.and_(\n        F.entity_type(\"dataset\"),\n        F.tag(\"urn:li:tag:critical\"),\n    )\n)\n```\n\n## Create Table-Level Assertions\n\n### Freshness assertions\n\n```python\ndef create_freshness_assertions(datasets, client):\n    for dataset_urn in datasets:\n        try:\n            assertion = client.assertions.sync_smart_freshness_assertion(\n                dataset_urn=dataset_urn,\n                display_name=\"Freshness Anomaly Monitor\",\n                detection_mechanism=\"information_schema\",\n                sensitivity=\"medium\",\n                tags=[\"automated\", \"freshness\", \"data_quality\"],\n                enabled=True,\n            )\n            print(f\"Created freshness assertion for {dataset_urn.name}: {assertion.urn}\")\n        except Exception as e:\n            print(f\"Failed for {dataset_urn.name}: {e}\")\n```\n\n### Volume assertions\n\n```python\ndef create_volume_assertions(datasets, client):\n    for dataset_urn in datasets:\n        try:\n            assertion = client.assertions.sync_smart_volume_assertion(\n                dataset_urn=dataset_urn,\n                display_name=\"Smart Volume Check\",\n                detection_mechanism=\"information_schema\",\n                sensitivity=\"medium\",\n                tags=[\"automated\", \"volume\", \"data_quality\"],\n                schedule=\"0 */6 * * *\",\n                enabled=True,\n            )\n            print(f\"Created volume assertion for {dataset_urn.name}: {assertion.urn}\")\n        except Exception as e:\n            print(f\"Failed for {dataset_urn.name}: {e}\")\n```\n\n### SQL assertions\n\n```python\ndef create_sql_assertions(datasets, client):\n    sql_queries = {\n        \"row_count\": \"SELECT COUNT(*) FROM {table_name}\",\n        \"null_check\": \"SELECT COUNT(*) FROM {table_name} WHERE id IS NULL\",\n    }\n\n    for dataset_urn in datasets:\n        for query_name, query_template in sql_queries.items():\n            try:\n                statement = query_template.format(table_name=dataset_urn.name)\n                assertion = client.assertions.sync_smart_sql_assertion(\n                    dataset_urn=dataset_urn,\n                    display_name=f\"Smart SQL - {query_name}\",\n                    statement=statement,\n                    sensitivity=\"medium\",\n                    tags=[\"automated\", \"smart_sql\", query_name],\n                    schedule=\"0 */6 * * *\",\n                    enabled=True,\n                )\n                print(f\"Created SQL assertion '{query_name}' for {dataset_urn.name}: {assertion.urn}\")\n            except Exception as e:\n                print(f\"Failed SQL assertion '{query_name}' for {dataset_urn.name}: {e}\")\n```\n\n## Get Column Information\n\n```python\ndef get_dataset_columns(client, dataset_urn):\n    try:\n        dataset = client.entities.get(dataset_urn)\n        if dataset and dataset.schema:\n            return [\n                {\n                    \"name\": field.field_path,\n                    \"type\": field.native_type,\n                }\n                for field in dataset.schema\n            ]\n        return []\n    except Exception as e:\n        print(f\"Failed to get columns for {dataset_urn}: {e}\")\n        return []\n\ndataset_columns = {}\nfor dataset_urn in datasets:\n    columns = get_dataset_columns(client, dataset_urn)\n    dataset_columns[str(dataset_urn)] = columns\n```\n\n## Create Column-Level Assertions\n\n```python\nimport fnmatch\n\nASSERTION_RULES = {\n    \"null_checks\": {\n        \"column_patterns\": [\"id\", \"*_id\", \"user_id\", \"email\"],\n        \"metric_type\": \"null_count\",\n    },\n    \"unique_checks\": {\n        \"column_patterns\": [\"*_id\", \"email\", \"username\"],\n        \"metric_type\": \"unique_count\",\n    },\n    \"empty_checks\": {\n        \"column_patterns\": [\"name\", \"description\", \"title\"],\n        \"metric_type\": \"empty_count\",\n    },\n}\n\ndef should_apply_rule(column_name, rule_config):\n    return any(\n        fnmatch.fnmatch(column_name.lower(), pattern.lower())\n        for pattern in rule_config[\"column_patterns\"]\n    )\n\ndef create_column_assertions(datasets, columns_dict, client):\n    for dataset_urn in datasets:\n        columns = columns_dict.get(str(dataset_urn), [])\n        for column in columns:\n            for rule_name, rule_config in ASSERTION_RULES.items():\n                if should_apply_rule(column[\"name\"], rule_config):\n                    try:\n                        client.assertions.sync_smart_column_metric_assertion(\n                            dataset_urn=dataset_urn,\n                            column_name=column[\"name\"],\n                            metric_type=rule_config[\"metric_type\"],\n                            display_name=f\"{rule_name} - {column['name']}\",\n                            detection_mechanism=\"all_rows_query_datahub_dataset_profile\",\n                            tags=[\"automated\", \"column_quality\", rule_name],\n                            enabled=True,\n                        )\n                        print(f\"Created {rule_name} for {dataset_urn.name}.{column['name']}\")\n                    except Exception as e:\n                        print(f\"Failed {rule_name} for {dataset_urn.name}.{column['name']}: {e}\")\n```\n\n## Update Existing Assertions\n\nPass the existing assertion URN to update rather than create:\n\n```python\nupdated = client.assertions.sync_smart_freshness_assertion(\n    dataset_urn=dataset_urn,\n    urn=existing_assertion_urn,\n    sensitivity=\"high\",\n    tags=[\"automated\", \"freshness\", \"updated\"],\n    enabled=True,\n)\n```\n\n## Batch Processing\n\n```python\nimport time\n\ndef batch_create_assertions(datasets, client, batch_size=10, delay_seconds=1.0):\n    results = {\"successful\": [], \"failed\": []}\n\n    for i in range(0, len(datasets), batch_size):\n        batch = datasets[i : i + batch_size]\n        for dataset_urn in batch:\n            try:\n                assertion = client.assertions.sync_smart_freshness_assertion(\n                    dataset_urn=dataset_urn,\n                    tags=[\"batch_created\", \"automated\"],\n                    enabled=True,\n                )\n                results[\"successful\"].append(\n                    {\"dataset\": str(dataset_urn), \"assertion\": str(assertion.urn)}\n                )\n            except Exception as e:\n                results[\"failed\"].append({\"dataset\": str(dataset_urn), \"error\": str(e)})\n\n        if i + batch_size < len(datasets):\n            time.sleep(delay_seconds)\n\n    return results\n```\n\n## Important Considerations\n\n- **Single-threaded per dataset:** Always process assertions for a given dataset in a single thread to avoid race conditions.\n- **Entities must exist:** Target datasets must already be present in DataHub before creating assertions.\n- **Sensitivity levels:** `\"low\"`, `\"medium\"`, `\"high\"` control anomaly detection thresholds.\n- **Detection mechanisms:** Use `\"information_schema\"` for table-level, `\"all_rows_query_datahub_dataset_profile\"` for column-level.\n- **Tags:** Plain tag names are auto-converted to URNs (e.g., `\"critical\"` becomes `\"urn:li:tag:critical\"`).\n- **Wait for processing:** Writes are async via Kafka. Wait for the previous batch to be reflected in the UI before re-running sync operations.\n"
  },
  {
    "path": "content/datahub/docs/sdk/python/references/entities.md",
    "content": "# Entity Reference\n\nAdvanced information & guidelines for specific entity types.\n\n## Containers\n\nDatasets are organized physically using the container entity (e.g. databases, schemas, folders).\n\n```python\nfrom datahub.sdk import Container\nfrom datahub.emitter.mcp_builder import DatabaseKey, SchemaKey\n\ndatabase_key = DatabaseKey(\n    platform=\"snowflake\",\n    instance=\"production\",\n    database=\"analytics_db\",\n)\n\ndatabase_container = Container(\n    database_key,\n    display_name=\"Analytics Database\",\n    description=\"Main analytics database\",\n    subtype=\"Database\",\n)\nclient.entities.upsert(database_container)\n\nschema_key = SchemaKey(\n    platform=\"snowflake\",\n    instance=\"production\",\n    database=\"analytics_db\",\n    schema=\"reporting\",\n)\n\nschema_container = Container(\n    schema_key,\n    display_name=\"Reporting Schema\",\n    description=\"Schema for reporting tables and views\",\n    subtype=\"Schema\",\n    parent_container=database_key,\n    domain=\"urn:li:domain:analytics\",\n)\nclient.entities.upsert(schema_container)\n```\n\n## Documents\n\nDocuments store knowledge content — tutorials, runbooks, FAQs, or references to external docs in systems like Notion or Confluence.\n\n### Native document (stored in DataHub)\n\n```python\nfrom datahub.sdk import Document\n\ndoc = Document.create_document(\n    id=\"getting-started-guide\",\n    title=\"Getting Started with DataHub\",\n    text=\"# Welcome\\n\\nThis guide will help you get started...\",\n    tags=[\"onboarding\"],\n    domain=\"urn:li:domain:data-governance\",\n)\nclient.entities.upsert(doc)\n```\n\n### External document (Notion, Confluence, etc.)\n\n```python\ndoc = Document.create_external_document(\n    id=\"notion-team-handbook\",\n    title=\"Engineering Handbook\",\n    platform=\"notion\",\n    external_url=\"https://notion.so/team/engineering-handbook\",\n    external_id=\"notion-page-abc123\",\n    text=\"Summary of the handbook for search indexing...\",\n)\nclient.entities.upsert(doc)\n```\n\n### AI-only context document\n\nDocuments hidden from global search/sidebar, accessible only through related assets:\n\n```python\ndoc = Document.create_document(\n    id=\"orders-dataset-context\",\n    title=\"Orders Dataset Context\",\n    text=\"This dataset contains daily order summaries...\",\n    show_in_global_context=False,\n    related_assets=[\"urn:li:dataset:(urn:li:dataPlatform:snowflake,orders,PROD)\"],\n)\nclient.entities.upsert(doc)\n```\n\n### Document properties\n\n- `doc.set_title(\"New Title\")` / `doc.title`\n- `doc.set_text(\"New content\")` / `doc.text`\n- `doc.publish()` / `doc.unpublish()` / `doc.status`\n- `doc.set_parent_document(\"urn:li:document:parent-doc\")` — hierarchical organization\n- `doc.add_related_asset(\"urn:li:dataset:...\")` / `doc.set_related_assets([...])`\n- `doc.add_related_document(\"urn:li:document:...\")` / `doc.set_related_documents([...])`\n- `doc.hide_from_global_context()` / `doc.show_in_global_search()`\n"
  },
  {
    "path": "content/datahub/docs/sdk/python/references/lineage.md",
    "content": "# Lineage Operations\n\nAdvanced lineage patterns using the DataHub Python SDK `LineageClient`.\n\n## Cross-Entity Lineage\n\nThe `add_lineage()` method supports lineage between any combination of:\n\n- Dataset to Dataset\n- Dataset to Chart\n- Dataset to DataJob\n- DataJob to DataJob\n- DataJob to Dataset\n- Dashboard to Chart\n- Dashboard to Dataset\n- Dashboard to Dashboard\n\n```python\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,raw.events,PROD)\",\n    downstream=\"urn:li:chart:(looker,chart_events_overview)\",\n)\n```\n\n## Column Lineage Options\n\nThe `column_lineage` parameter on `add_lineage()` accepts several forms:\n\n```python\n# Auto-match columns by name (fuzzy matching)\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:postgres,users,PROD)\",\n    downstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,users_replica,PROD)\",\n    column_lineage=\"auto_fuzzy\",\n)\n\n# Strict auto-match (exact column name match)\nclient.lineage.add_lineage(\n    upstream=upstream_urn,\n    downstream=downstream_urn,\n    column_lineage=\"auto_strict\",\n)\n\n# Explicit column mapping (downstream_col -> [upstream_cols])\nclient.lineage.add_lineage(\n    upstream=upstream_urn,\n    downstream=downstream_urn,\n    column_lineage={\n        \"user_id\": [\"id\"],\n        \"full_name\": [\"first_name\", \"last_name\"],\n    },\n)\n\n# No column lineage (default)\nclient.lineage.add_lineage(\n    upstream=upstream_urn,\n    downstream=downstream_urn,\n    column_lineage=False,\n)\n```\n\n## DataJob Lineage\n\nConnect pipelines (Airflow tasks, Spark jobs) to their inputs and outputs:\n\n```python\n# Datajob to downstream dataset\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataJob:(urn:li:dataFlow:(airflow,etl_pipeline,PROD),load_users)\",\n    downstream=\"urn:li:dataset:(urn:li:dataPlatform:snowflake,analytics.users,PROD)\",\n)\n\n# Dataset to datajob (upstream input)\nclient.lineage.add_lineage(\n    upstream=\"urn:li:dataset:(urn:li:dataPlatform:postgres,users,PROD)\",\n    downstream=\"urn:li:dataJob:(urn:li:dataFlow:(airflow,etl_pipeline,PROD),load_users)\",\n)\n```\n\n## SQL-Based Lineage Inference\n\nLet the SDK parse SQL to automatically extract upstream/downstream relationships:\n\n```python\nclient.lineage.infer_lineage_from_sql(\n    query_text=\"\"\"\n        INSERT INTO analytics.daily_revenue\n        SELECT date, SUM(amount) AS revenue\n        FROM raw.orders\n        JOIN raw.products ON orders.product_id = products.id\n        GROUP BY date\n    \"\"\",\n    platform=\"snowflake\",\n    env=\"PROD\",\n    default_db=\"my_database\",\n    default_schema=\"public\",\n)\n```\n\nParameters:\n\n| Parameter | Description |\n|-----------|-------------|\n| `query_text` | The SQL query to parse |\n| `platform` | Data platform identifier (e.g., `\"snowflake\"`, `\"bigquery\"`) |\n| `platform_instance` | Optional platform instance |\n| `env` | Environment, defaults to `\"PROD\"` |\n| `default_db` | Default database for unqualified table names |\n| `default_schema` | Default schema for unqualified table names |\n| `override_dialect` | Override SQL dialect for parsing |\n\n## Filtered Lineage\n\nCombine `get_lineage()` with search filters to narrow results:\n\n```python\nfrom datahub.sdk import FilterDsl as F\n\nresults = client.lineage.get_lineage(\n    source_urn=dataset_urn,\n    direction=\"downstream\",\n    max_hops=3,\n    filter=F.and_(\n        F.entity_type(\"dataset\"),\n        F.platform(\"snowflake\"),\n    ),\n)\n```\n\n## LineageResult Object\n\nEach result from `get_lineage()` is a `LineageResult`:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `urn` | `str` | URN of the related entity |\n| `type` | `str` | Entity type (dataset, chart, etc.) |\n| `hops` | `int` | Number of hops from the source |\n| `direction` | `\"upstream\" \\| \"downstream\"` | Traversal direction |\n| `platform` | `str \\| None` | Platform name |\n| `name` | `str \\| None` | Entity display name |\n| `description` | `str \\| None` | Entity description |\n| `paths` | `List[LineagePath] \\| None` | Lineage paths with intermediate entities |\n\n## View Lineage (Auto-Parsed)\n\nDatasets with `view_definition` set automatically extract upstream lineage from the SQL:\n\n```python\nfrom datahub.sdk import Dataset\n\nview = Dataset(\n    platform=\"snowflake\",\n    name=\"analytics.reporting.sales_summary\",\n    view_definition=\"SELECT * FROM analytics.raw.sales WHERE year = 2024\",\n    subtype=\"view\",\n)\n# view.upstreams is auto-populated with analytics.raw.sales\n\nclient.entities.upsert(view)\n```\n\nSet `parse_view_lineage=False` to disable auto-parsing.\n"
  },
  {
    "path": "content/datahub/docs/sdk/python/references/search.md",
    "content": "# Search API\n\nDetailed reference for searching and discovering metadata with the DataHub Python SDK.\n\n## Overview\n\nAll search goes through `client.search.get_urns()`, which returns an iterable of URNs. You can search by text query, structured filters, or both.\n\n```python\nfrom datahub.sdk import DataHubClient, FilterDsl as F\n\nclient = DataHubClient.from_env()\nresults = client.search.get_urns(query=\"...\", filter=F.platform(\"...\"))\n```\n\n## Filter-Based Search\n\nStructured filters scope results by platform, entity type, domain, and other metadata fields.\n\n### Platform\n\nFind all assets on a specific data platform.\n\n```python\nresults = client.search.get_urns(filter=F.platform(\"snowflake\"))\n\n# Multiple platforms\nresults = client.search.get_urns(filter=F.platform([\"snowflake\", \"bigquery\"]))\n```\n\nUse when: you know which warehouse or system the asset lives in.\n\n### Entity Type\n\nNarrow to a specific entity type.\n\n```python\nresults = client.search.get_urns(filter=F.entity_type(\"dataset\"))\nresults = client.search.get_urns(filter=F.entity_type(\"dashboard\"))\nresults = client.search.get_urns(filter=F.entity_type(\"chart\"))\nresults = client.search.get_urns(filter=F.entity_type(\"document\"))\nresults = client.search.get_urns(filter=F.entity_type(\"container\"))\nresults = client.search.get_urns(filter=F.entity_type(\"dataFlow\"))\nresults = client.search.get_urns(filter=F.entity_type(\"dataJob\"))\nresults = client.search.get_urns(filter=F.entity_type(\"glossaryTerm\"))\n```\n\nUse when: you need a specific kind of asset, not everything matching a keyword.\n\n### Entity Subtype\n\nFilter by subtype within an entity type (e.g., ML Experiment, View, Topic).\n\n```python\nresults = client.search.get_urns(\n    filter=F.and_(F.platform(\"mlflow\"), F.entity_subtype(\"ML Experiment\"))\n)\n```\n\nUse when: a platform has multiple subtypes and you need a specific one.\n\n### Domain\n\nFind assets within a business domain.\n\n```python\nresults = client.search.get_urns(filter=F.domain(\"urn:li:domain:marketing\"))\n\n# Multiple domains\nresults = client.search.get_urns(filter=F.domain([\"urn:li:domain:marketing\", \"urn:li:domain:sales\"]))\n```\n\nUse when: organizing or auditing assets by business function. Preferred over env-based filtering for logical organization.\n\n### Container\n\nFind assets within a specific container (database, schema, folder).\n\n```python\nresults = client.search.get_urns(filter=F.container(\"urn:li:container:prod_analytics\"))\n\n# Direct descendants only (not nested containers)\nresults = client.search.get_urns(\n    filter=F.container(\"urn:li:container:prod_analytics\", direct_descendants_only=True)\n)\n```\n\nUse when: browsing assets within a specific database or schema hierarchy.\n\n### Owner\n\nFind assets owned by a specific user or group.\n\n```python\nresults = client.search.get_urns(filter=F.owner(\"urn:li:corpuser:jane\"))\nresults = client.search.get_urns(filter=F.owner(\"urn:li:corpGroup:data-eng\"))\n```\n\nUse when: auditing ownership or finding a team's assets.\n\n### Tag\n\nFind assets with a specific tag.\n\n```python\nresults = client.search.get_urns(filter=F.tag(\"urn:li:tag:critical\"))\nresults = client.search.get_urns(filter=F.tag([\"urn:li:tag:pii\", \"urn:li:tag:sensitive\"]))\n```\n\nUse when: finding assets by classification label.\n\n### Glossary Term\n\nFind assets annotated with a business glossary term.\n\n```python\nresults = client.search.get_urns(filter=F.glossary_term(\"urn:li:glossaryTerm:PII\"))\n```\n\nUse when: finding all assets governed by a specific business concept.\n\n### Environment\n\nFind assets in a specific environment.\n\n```python\nresults = client.search.get_urns(filter=F.env(\"PROD\"))\n```\n\nNote: prefer using domains or container hierarchies for logical organization over env-based filtering.\n\n### Custom Properties\n\nFind assets with a specific custom property value.\n\n```python\nresults = client.search.get_urns(\n    filter=F.has_custom_property(\"department\", \"sales\")\n)\n```\n\nUse when: searching by user-defined metadata that doesn't fit into tags or glossary terms.\n\n### Deletion Status\n\nInclude or exclude soft-deleted assets.\n\n```python\nresults = client.search.get_urns(filter=F.soft_deleted(\"NOT_SOFT_DELETED\"))\n```\n\n### Custom Field Conditions\n\nFor advanced filtering on any `@Searchable`-annotated field in DataHub's metadata models.\n\n```python\nresults = client.search.get_urns(\n    filter=F.custom_filter(field=\"urn\", condition=\"CONTAIN\", values=[\"example_dataset\"])\n)\n\nresults = client.search.get_urns(\n    filter=F.custom_filter(field=\"name\", condition=\"START_WITH\", values=[\"prod_\"])\n)\n```\n\n#### Supported conditions\n\n| Condition | Description |\n|-----------|-------------|\n| `EQUAL` | Exact match |\n| `CONTAIN` | Substring match |\n| `START_WITH` | Prefix match |\n| `END_WITH` | Suffix match |\n| `GREATER_THAN` | Numeric/timestamp comparison |\n| `GREATER_THAN_OR_EQUAL_TO` | Numeric/timestamp comparison |\n| `LESS_THAN` | Numeric/timestamp comparison |\n| `LESS_THAN_OR_EQUAL_TO` | Numeric/timestamp comparison |\n| `IN` | Match any value in a list |\n| `EXISTS` | Field is present |\n\n#### Common searchable fields\n\nFields annotated with `@Searchable` in DataHub's PDL models can be used with `custom_filter`. Common ones include: `urn`, `name`, `description`, `env`, `platform`.\n\nThe exact searchable fields vary by entity type. Refer to the PDL model files in the [DataHub repo](https://github.com/datahub-project/datahub/tree/master/metadata-models/src/main/pegasus) for the full list.\n\n## Common Patterns\n\n### Find datasets tagged as critical but missing an owner\n\n```python\ncritical = client.search.get_urns(filter=F.tag(\"urn:li:tag:critical\"))\nfor urn in critical:\n    entity = client.entities.get(urn)\n    if not entity.owners:\n        print(f\"Missing owner: {urn}\")\n```\n\n## Caching\n\n`get_urns()` accepts a `skip_cache=True` parameter to bypass the search cache when you need fresh results immediately after a write:\n\n```python\nresults = client.search.get_urns(query=\"new_table\", skip_cache=True)\n```\n"
  },
  {
    "path": "content/datasets/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hugging Face Datasets package guide for loading, processing, streaming, and caching datasets in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"datasets,huggingface,data,ml,arrow,streaming\"\n---\n\n# Hugging Face Datasets Python Package Guide\n\n## Golden Rule\n\nUse `datasets` for dataset loading and preprocessing, but choose the execution model up front:\n\n- use `Dataset` or `DatasetDict` when you need random access, materialized transforms, `save_to_disk()`, or framework formatting\n- use `streaming=True` only when the dataset is too large to download eagerly or you need sequential iteration over remote shards\n\nAgents often fail by writing code for `Dataset` and then silently switching to `IterableDataset` later. Those two paths do not support the same operations.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"datasets==4.7.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"datasets==4.7.0\"\npoetry add \"datasets==4.7.0\"\n```\n\nUseful extras from the PyPI package metadata:\n\n```bash\npython -m pip install \"datasets[audio]==4.7.0\"\npython -m pip install \"datasets[vision]==4.7.0\"\npython -m pip install \"datasets[streaming]==4.7.0\"\npython -m pip install \"datasets[torch]==4.7.0\"\n```\n\n## Authentication And Environment\n\nPublic datasets on the Hugging Face Hub can be loaded without credentials. Private or gated datasets require a Hugging Face token.\n\nPreferred setup:\n\n```bash\nhf auth login\n```\n\nThen load the dataset with the stored token:\n\n```python\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"org/private-dataset\", split=\"train\", token=True)\n```\n\nYou can also pass a token string directly:\n\n```python\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"org/private-dataset\", split=\"train\", token=\"hf_...\")\n```\n\nCache-related environment variables:\n\n```bash\nexport HF_HOME=\"$PWD/.hf\"\nexport HF_DATASETS_CACHE=\"$PWD/.hf/datasets\"\n```\n\nUse these when CI, containers, or shared machines need deterministic cache locations.\n\n## Core Usage\n\n### Load a dataset from the Hub\n\n```python\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"cornell-movie-review-data/rotten_tomatoes\")\n\nprint(dataset)\nprint(dataset[\"train\"][0])\n```\n\nLoad just one split when you do not need the full `DatasetDict`:\n\n```python\nfrom datasets import load_dataset\n\ntrain = load_dataset(\n    \"cornell-movie-review-data/rotten_tomatoes\",\n    split=\"train\",\n)\n```\n\n### Load local files\n\nUse a dataset builder name such as `csv`, `json`, or `parquet` for local or direct file ingestion:\n\n```python\nfrom datasets import load_dataset\n\ncsv_ds = load_dataset(\"csv\", data_files=\"data/train.csv\")\njson_ds = load_dataset(\"json\", data_files={\"train\": \"data/train.jsonl\"})\nparquet_ds = load_dataset(\"parquet\", data_files=\"data/events.parquet\")\n```\n\n### Inspect metadata before downloading\n\n`load_dataset_builder()` is the fastest way to inspect features, splits, and dataset info without materializing the data:\n\n```python\nfrom datasets import load_dataset_builder\n\nbuilder = load_dataset_builder(\"nyu-mll/glue\", \"mrpc\")\n\nprint(builder.info.features)\nprint(builder.info.splits)\n```\n\n### Preprocess with `map()`, `filter()`, and column operations\n\n```python\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"nyu-mll/glue\", \"mrpc\", split=\"train\")\n\ndataset = dataset.filter(lambda row: row[\"label\"] == 1)\ndataset = dataset.rename_column(\"label\", \"labels\")\ndataset = dataset.remove_columns([\"idx\"])\ndataset = dataset.train_test_split(test_size=0.1, seed=42)\n```\n\nUse `map()` when you are creating or rewriting columns:\n\n```python\nfrom datasets import load_dataset\nfrom transformers import AutoTokenizer\n\ntokenizer = AutoTokenizer.from_pretrained(\"bert-base-uncased\")\ndataset = load_dataset(\"nyu-mll/glue\", \"mrpc\", split=\"train\")\n\ndef tokenize(batch):\n    return tokenizer(batch[\"sentence1\"], batch[\"sentence2\"], truncation=True)\n\ndataset = dataset.map(tokenize, batched=True, num_proc=4)\ndataset = dataset.with_format(\n    \"torch\",\n    columns=[\"input_ids\", \"token_type_ids\", \"attention_mask\", \"label\"],\n)\n```\n\nNotes:\n\n- `with_format()` returns a new dataset object; `set_format()` mutates in place\n- `num_proc` can speed up CPU preprocessing, but the mapped function must be picklable\n\n### Save and reload processed datasets\n\n```python\nfrom datasets import load_dataset, load_from_disk\n\ndataset = load_dataset(\"cornell-movie-review-data/rotten_tomatoes\", split=\"train\")\ndataset.save_to_disk(\"artifacts/rotten_tomatoes_train\")\n\nreloaded = load_from_disk(\"artifacts/rotten_tomatoes_train\")\nprint(reloaded[0])\n```\n\nThis is the right persistence path for preprocessed datasets. Do not replace it with ad hoc `pickle` or custom JSON dumps.\n\n## Streaming\n\n`streaming=True` returns an `IterableDataset`, which is designed for sequential access and remote-scale iteration:\n\n```python\nfrom datasets import load_dataset\n\nstream = load_dataset(\n    \"cornell-movie-review-data/rotten_tomatoes\",\n    split=\"train\",\n    streaming=True,\n)\n\nfor index, row in enumerate(stream):\n    print(row)\n    if index == 2:\n        break\n```\n\nFor Parquet-based data sources, the loader also supports column projection and row filtering:\n\n```python\nfrom datasets import load_dataset\n\nstream = load_dataset(\n    \"parquet\",\n    data_files=\"data/events/*.parquet\",\n    streaming=True,\n    columns=[\"event_id\", \"created_at\"],\n    filters=[(\"event_type\", \"==\", \"click\")],\n)\n```\n\nUse streaming when dataset size is the problem. Do not use it by default for small training or evaluation sets, because many convenient `Dataset` operations are unavailable or behave differently.\n\n## Cache And Storage\n\nImportant cache facts:\n\n- the datasets cache lives under the Hugging Face cache root and can grow quickly\n- `HF_DATASETS_CACHE` controls the Arrow/cache files used by `datasets`\n- `download_mode` can force re-download or cache reuse when debugging stale data\n\nClean up stale cache entries explicitly when needed:\n\n```python\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"cornell-movie-review-data/rotten_tomatoes\", split=\"train\")\nremoved = dataset.cleanup_cache_files()\nprint(removed)\n```\n\n## Common Pitfalls\n\n- `revision=` on `load_dataset()` selects the dataset repository git ref on the Hub, not the installed `datasets` package version.\n- `streaming=True` returns `IterableDataset`, so random indexing, many materialized transforms, and `save_to_disk()`-style workflows are not interchangeable with `Dataset`.\n- `remove_columns()` is cheaper and clearer than doing a no-op `map()` just to drop fields.\n- `with_transform()` and `set_transform()` apply transforms lazily at read time; they do not eagerly rewrite the stored Arrow table.\n- Cache growth is easy to miss in CI and notebooks. Set `HF_HOME` or `HF_DATASETS_CACHE` deliberately for reproducible environments.\n- Multiprocessing plus CUDA needs care. The processing guide notes that GPU-dispatched `map()` code should use the `spawn` start method to avoid CUDA re-initialization errors.\n- If you only need schema inspection, call `load_dataset_builder()` first. Downloading full data just to inspect columns is wasted time and disk.\n\n## Version-Sensitive Notes\n\n- The `4.0.0` release removed dataset loading scripts and dropped `trust_remote_code` support in `load_dataset()`. If old blog posts tell you to rely on custom loading scripts, those instructions are stale for `4.x`.\n- The `4.0.0` release introduced the `Column` object when indexing a single column. Code that assumed a plain Python list from `dataset[\"column_name\"]` can behave differently.\n- The `4.0.0` release switched audio and video decoding to `torchcodec`. Media pipelines now have extra runtime requirements beyond a bare `pip install datasets`.\n- The `4.0.0` release added `IterableDataset.push_to_hub()`, which matters if older internal notes still claim streaming datasets cannot be pushed.\n- The `4.7.0` release added a `Json()` feature type and `on_mixed_types=\"use_json\"` support in `Dataset.from_dict()`, `Dataset.from_list()`, and `map()`. Revisit older mixed-JSON normalization workarounds before copying them forward.\n\n## Official Links\n\n- Docs root: `https://huggingface.co/docs/datasets/en/index`\n- Installation: `https://huggingface.co/docs/datasets/en/installation`\n- Quickstart: `https://huggingface.co/docs/datasets/en/quickstart`\n- Processing guide: `https://huggingface.co/docs/datasets/en/process`\n- Streaming guide: `https://huggingface.co/docs/datasets/en/stream`\n- Cache guide: `https://huggingface.co/docs/datasets/en/cache`\n- Loading methods reference: `https://huggingface.co/docs/datasets/en/package_reference/loading_methods`\n- Main classes reference: `https://huggingface.co/docs/datasets/en/package_reference/main_classes`\n- PyPI package: `https://pypi.org/project/datasets/`\n"
  },
  {
    "path": "content/datashader/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Datashader package guide for Python rasterization of large tabular and gridded datasets\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.18.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"datashader,python,visualization,rasterization,pandas,dask,xarray,holoviz\"\n---\n\n# Datashader Python Package Guide\n\n## Golden Rule\n\nUse `datashader` to rasterize data into a fixed-size aggregate first, then colorize that aggregate. The core workflow is:\n\n1. Build a `Canvas`\n2. Aggregate with a glyph method such as `points()`, `line()`, `raster()`, or `quadmesh()`\n3. Convert the aggregate to an image with `datashader.transfer_functions`\n\nIf you try to treat Datashader as a normal plotting library, you will usually miss the point. It is the rasterization engine underneath a visualization pipeline.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"datashader==0.18.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"datashader==0.18.2\"\npoetry add \"datashader==0.18.2\"\n```\n\nDatashader works with multiple data containers, but some of the surrounding libraries are optional. Install them separately when your workflow needs them:\n\n- `pandas` for in-memory tabular data\n- `dask` for partitioned tabular data\n- `xarray` for gridded arrays\n- `spatialpandas` for large geospatial vector data\n- `pillow` if you want `img.to_pil()` image export helpers\n- `holoviews` or `hvplot` if you want interactive plotting wrappers around Datashader\n\n## Initialization And Mental Model\n\nThere is no authentication or service setup. The important setup is choosing a canvas size and coordinate ranges that match your task.\n\n```python\nimport datashader as ds\n\ncanvas = ds.Canvas(\n    plot_width=800,\n    plot_height=500,\n    x_range=(-10, 10),\n    y_range=(-5, 5),\n)\n```\n\nImportant knobs:\n\n- `plot_width` and `plot_height` define output resolution\n- `x_range` and `y_range` define the data window being rasterized\n- `x_axis_type` and `y_axis_type` matter for log axes\n\nIf you omit ranges, Datashader infers them from the current data. That is convenient for exploration, but it makes outputs harder to compare across runs.\n\n## Core Usage\n\n### Rasterize tabular points\n\n```python\nimport pandas as pd\nimport datashader as ds\nfrom datashader import transfer_functions as tf\n\ndf = pd.DataFrame(\n    {\n        \"x\": [0.1, 0.2, 0.2, 0.9, 1.2],\n        \"y\": [0.0, 0.1, 0.4, 0.8, 1.3],\n    }\n)\n\ncanvas = ds.Canvas(\n    plot_width=600,\n    plot_height=400,\n    x_range=(0, 2),\n    y_range=(0, 2),\n)\n\nagg = canvas.points(df, \"x\", \"y\", agg=ds.count())\nimg = tf.shade(agg, cmap=[\"#deebf7\", \"#08519c\"], how=\"log\")\nimg = tf.set_background(img, \"white\")\n```\n\nUse `ds.count()` when you want density. Swap in reducers such as `ds.sum(\"value\")`, `ds.mean(\"value\")`, `ds.max(\"value\")`, or `ds.count_cat(\"category\")` when you need value-aware aggregation.\n\n### Rasterize line data\n\nUse `Canvas.line()` for ordered trajectories or time-series paths rather than approximating them as points:\n\n```python\nagg = canvas.line(df, \"x\", \"y\", agg=ds.count())\nimg = tf.shade(agg, cmap=[\"#f7fbff\", \"#08306b\"])\n```\n\n### Work with Dask DataFrames\n\nThe API is intentionally similar to pandas:\n\n```python\nimport dask.dataframe as dd\nimport datashader as ds\nfrom datashader import transfer_functions as tf\n\nddf = dd.read_parquet(\"trips/*.parquet\")\ncanvas = ds.Canvas(plot_width=900, plot_height=500)\n\nagg = canvas.points(ddf, \"pickup_x\", \"pickup_y\", agg=ds.count())\nimg = tf.shade(agg, how=\"eq_hist\")\n```\n\nSince `0.17.0`, Dask is no longer installed automatically with Datashader. Install `dask` yourself if you want this workflow.\n\n### Work with xarray rasters\n\nFor gridded data, use raster-aware methods instead of forcing the data into a tabular glyph:\n\n```python\nimport xarray as xr\nimport datashader as ds\nfrom datashader import transfer_functions as tf\n\nda = xr.DataArray(\n    [[1, 2, 3], [4, 5, 6]],\n    dims=(\"y\", \"x\"),\n    coords={\"x\": [0, 1, 2], \"y\": [0, 1]},\n)\n\ncanvas = ds.Canvas(plot_width=600, plot_height=300)\nagg = canvas.raster(da)\nimg = tf.shade(agg, cmap=[\"#f7fbff\", \"#08306b\"])\n```\n\nUse `Canvas.quadmesh()` for curvilinear or nonuniform meshes. This matters because `0.18.2` includes a fix for antialiasing nonuniform `quadmesh` edges.\n\n### Export Or Display The Result\n\nDatashader returns an image object after `tf.shade(...)`. Common next steps:\n\n```python\nimg = tf.dynspread(img, threshold=0.5, max_px=4)\nimg.to_pil().save(\"output.png\")\n```\n\nNotes:\n\n- `dynspread()` is useful when sparse points disappear at normal zoom levels\n- `to_pil()` requires Pillow to be installed\n- In notebooks, HoloViews and hvPlot can display Datashader-backed images directly\n- For Matplotlib integration, use `datashader.mpl_ext.dsshow`\n\n## Configuration Notes\n\nThere are no credentials or environment variables to manage. The main configuration choices are data-shaping and rendering choices:\n\n- Aggregation reducer: `ds.count()`, `ds.sum(\"col\")`, `ds.mean(\"col\")`, `ds.max(\"col\")`, `ds.count_cat(\"col\")`\n- Shading transform: `how=\"linear\"`, `how=\"log\"`, or `how=\"eq_hist\"`\n- Color map: pass a list of colors or a colormap object\n- Canvas size: larger canvases preserve more detail but cost more CPU and memory\n- Coordinate ranges: set them explicitly for reproducible comparisons and tiled rendering\n\nFor geospatial work, Datashader does not perform arbitrary reprojection for you. Make sure the coordinates you aggregate are already in the coordinate system your downstream plotting stack expects.\n\n## Common Pitfalls\n\n- Do not skip the aggregate step. `tf.shade()` expects an aggregate array, not your raw DataFrame.\n- Do not assume bigger input data automatically means a bigger image. Output size is controlled by the canvas, not by row count.\n- If repeated renders look inconsistent, check whether `x_range` and `y_range` are being auto-inferred each time.\n- If `img.to_pil()` or Dask-backed examples fail with import errors, install the optional companion packages explicitly. Since `0.17.0`, Dask and Pillow are no longer hard dependencies.\n- Use raster-specific methods such as `raster()` and `quadmesh()` for gridded data. Point and line glyphs are for tabular coordinates.\n- Datashader does not replace your whole plotting stack. Use HoloViews, hvPlot, Bokeh, or Matplotlib when you need axes, layout, widgets, or interactive composition.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.18.2`, released on September 8, 2025.\n- `0.18.2` fixes antialiasing for nonuniform `quadmesh` edges and includes edge-bundling inspector typing fixes. If you are debugging mesh rendering artifacts, confirm you are not on an older `0.18.x` patch.\n- `0.17.0` dropped Python 3.9 support and changed Dask and Pillow from hard dependencies to optional ones. Older blog posts often assume those packages are installed automatically.\n- The source URL pointed directly at the API reference. For actual coding work, use the docs root and getting-started guide for workflow, then the API page for signatures and exact method names.\n\n## Official Source URLs\n\n- `https://datashader.org/`\n- `https://datashader.org/getting_started/Installation.html`\n- `https://datashader.org/getting_started/Introduction.html`\n- `https://datashader.org/api.html`\n- `https://datashader.org/user_guide/Performance.html`\n- `https://datashader.org/releases.html`\n- `https://pypi.org/project/datashader/`\n- `https://github.com/holoviz/datashader`\n"
  },
  {
    "path": "content/dateparser/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"dateparser package guide for parsing natural-language dates in Python applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dateparser,python,date,time,parsing,localization\"\n---\n\n# dateparser Python Package Guide\n\n## Golden Rule\n\nUse `dateparser.parse()` for simple user input, but pass explicit `languages`, `locales`, `date_formats`, and `settings` for any workflow that must be deterministic. Ambiguous strings such as `02-03-2016`, relative phrases such as `2 weeks ago`, and partial dates such as `March 2024` need explicit parsing rules.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"dateparser==1.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dateparser==1.3.0\"\npoetry add \"dateparser==1.3.0\"\n```\n\n## Initialization\n\n`dateparser` is a local Python library. It does not require authentication, API keys, environment variables, or client initialization.\n\nImport the APIs you will usually need:\n\n```python\nfrom datetime import datetime, timezone\n\nimport dateparser\nfrom dateparser import DateDataParser\nfrom dateparser.search import search_dates\n```\n\n## Common Workflows\n\n### Parse one date string\n\n```python\nimport dateparser\n\nparsed = dateparser.parse(\"March 5, 2024 4:30 PM\")\nif parsed is None:\n    raise ValueError(\"Could not parse date\")\n\nprint(parsed.isoformat())\n```\n\n`parse()` returns a `datetime.datetime` on success and `None` when parsing fails.\n\n### Parse machine-formatted input with explicit rules\n\nIf the input shape is known, supply `date_formats` instead of relying only on auto-detection.\n\n```python\nimport dateparser\n\nparsed = dateparser.parse(\n    \"2024-03-05 16:30\",\n    date_formats=[\"%Y-%m-%d %H:%M\"],\n    languages=[\"en\"],\n    settings={\n        \"TIMEZONE\": \"UTC\",\n        \"TO_TIMEZONE\": \"UTC\",\n        \"RETURN_AS_TIMEZONE_AWARE\": True,\n    },\n)\n\nif parsed is None:\n    raise ValueError(\"Could not parse timestamp\")\n\nprint(parsed.isoformat())\n```\n\n### Parse relative dates against a fixed base time\n\nRelative phrases depend on the current time unless you provide `RELATIVE_BASE`.\n\n```python\nfrom datetime import datetime, timezone\n\nimport dateparser\n\nbase = datetime(2024, 3, 15, 12, 0, tzinfo=timezone.utc)\n\nparsed = dateparser.parse(\n    \"2 weeks ago\",\n    languages=[\"en\"],\n    settings={\n        \"RELATIVE_BASE\": base,\n        \"TIMEZONE\": \"UTC\",\n        \"TO_TIMEZONE\": \"UTC\",\n        \"RETURN_AS_TIMEZONE_AWARE\": True,\n    },\n)\n\nif parsed is None:\n    raise ValueError(\"Could not parse relative date\")\n\nprint(parsed.isoformat())\n```\n\n### Keep the detected period and locale\n\nUse `DateDataParser` when you need more than a single `datetime` value.\n\n```python\nfrom dateparser import DateDataParser\n\nparser = DateDataParser(languages=[\"en\"])\ndata = parser.get_date_data(\"March 2024\")\n\nprint(data[\"date_obj\"])\nprint(data[\"period\"])\nprint(data[\"locale\"])\n```\n\n`get_date_data()` keeps the parsed date together with the detected `period` and `locale`, which is useful when partial dates are acceptable in your application.\n\n### Find dates inside larger text\n\n```python\nfrom datetime import datetime, timezone\n\nfrom dateparser.search import search_dates\n\nbase = datetime(2024, 3, 15, 12, 0, tzinfo=timezone.utc)\n\nmatches = search_dates(\n    \"Invoice due next Friday. Send a reminder in 2 weeks.\",\n    languages=[\"en\"],\n    settings={\"RELATIVE_BASE\": base},\n) or []\n\nfor matched_text, parsed_dt in matches:\n    print(matched_text, parsed_dt.isoformat())\n```\n\nUse `search_dates()` when you need to extract multiple date expressions from a larger string instead of parsing one value at a time.\n\n## Useful Settings\n\n- `DATE_ORDER`: sets the expected component order for ambiguous numeric dates.\n- `PREFER_DATES_FROM`: biases ambiguous dates toward the `past`, `future`, or `current_period`.\n- `PREFER_DAY_OF_MONTH`: controls how incomplete dates are completed.\n- `RELATIVE_BASE`: makes relative parsing deterministic.\n- `STRICT_PARSING`: rejects inputs that cannot be parsed cleanly.\n- `REQUIRE_PARTS`: requires specific date parts such as `day`, `month`, or `year`.\n- `TIMEZONE`, `TO_TIMEZONE`, `RETURN_AS_TIMEZONE_AWARE`: make timezone handling explicit.\n\n## Common Pitfalls\n\n- Always handle the `None` case from `dateparser.parse()`.\n- Do not rely on auto-detected language or locale for ambiguous production inputs; pass `languages` or `locales` explicitly.\n- Do not rely on wall-clock time for tests or scheduled jobs that parse relative phrases; set `RELATIVE_BASE`.\n- Partial dates may still produce a parsed result. Use `STRICT_PARSING` or `REQUIRE_PARTS` when incomplete input should fail.\n- If downstream code expects timezone-aware values, set timezone-related settings explicitly instead of assuming the returned `datetime` matches your app default.\n"
  },
  {
    "path": "content/dbt-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"dbt Core package guide for Python projects using the dbt CLI, project config, profiles, and adapters\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.11.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dbt,dbt-core,analytics-engineering,sql,etl,cli,warehouse\"\n---\n\n# dbt Core Python Package Guide\n\n## Golden Rule\n\nTreat `dbt-core` as the local CLI engine for dbt projects, not as a standalone warehouse connector. Install `dbt-core` together with exactly one adapter package for your platform, keep project behavior in `dbt_project.yml`, keep credentials in `profiles.yml`, and run `dbt debug` before assuming your models or tests are broken.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"dbt-core==1.11.7\"\n```\n\nFor real warehouse work, also install a matching adapter package. Replace `dbt-postgres` with the adapter your project actually uses:\n\n```bash\npython -m pip install \"dbt-core==1.11.7\" \"dbt-postgres==1.11.7\"\n```\n\nUseful checks immediately after install:\n\n```bash\ndbt --version\npython -m pip show dbt-core\n```\n\nNotes:\n\n- `dbt-core` alone gives you the CLI and compiler, but you still need an adapter package to connect to a data platform.\n- The dbt v1.11 upgrade guide explicitly recommends installing both `dbt-core` and adapter packages together.\n- PyPI marks `1.11.0` and `1.11.1` as yanked; pin to `1.11.7` if you are targeting the current 1.11 line.\n\n## Initialize A Project\n\nCreate a new project with the CLI:\n\n```bash\ndbt init my_project\ncd my_project\n```\n\n`dbt init` scaffolds the project and prompts for an adapter/profile setup. In a typical repo, the important files and directories are:\n\n- `dbt_project.yml`: project name, profile name, model paths, materialization defaults, vars, and package install path\n- `models/`: SQL models and YAML properties\n- `seeds/`: CSV seed data\n- `macros/`: reusable Jinja macros\n- `tests/`: singular SQL tests\n- `target/`: generated artifacts such as compiled SQL and `manifest.json`\n\nMinimal `dbt_project.yml`:\n\n```yaml\nname: my_project\nversion: \"1.0.0\"\nconfig-version: 2\n\nprofile: my_project\n\nmodel-paths: [\"models\"]\nseed-paths: [\"seeds\"]\nmacro-paths: [\"macros\"]\ntest-paths: [\"tests\"]\n\ntarget-path: \"target\"\nclean-targets:\n  - \"target\"\n  - \"dbt_packages\"\n\nmodels:\n  my_project:\n    +materialized: view\n```\n\nIf the project must stay on the 1.11 series, make that explicit:\n\n```yaml\nrequire-dbt-version: [\">=1.11.0\", \"<1.12.0\"]\n```\n\n## Authentication And Profiles\n\ndbt stores connection settings in `profiles.yml`. dbt searches for profiles in this order:\n\n1. The `--profiles-dir` CLI flag\n2. The `DBT_PROFILES_DIR` environment variable\n3. The current working directory\n4. `~/.dbt/`\n\nEach profile has one or more named outputs and a `target` that selects the active output. Example:\n\n```yaml\nmy_project:\n  target: dev\n  outputs:\n    dev:\n      type: postgres\n      host: \"{{ env_var('DBT_HOST') }}\"\n      user: \"{{ env_var('DBT_USER') }}\"\n      password: \"{{ env_var('DBT_ENV_SECRET_PG_PASSWORD') }}\"\n      port: 5432\n      dbname: analytics\n      schema: dbt_dev\n      threads: \"{{ env_var('DBT_THREADS', 4) | int }}\"\n```\n\nCredential guidance:\n\n- Keep `profiles.yml` out of version control unless it only contains placeholders.\n- Use environment variables for secrets and environment-specific values.\n- `DBT_ENV_SECRET_*` variables are intended for secrets. They are allowed in `profiles.yml` and `packages.yml`, scrubbed from logs, and blocked elsewhere.\n- Quote the full Jinja expression in YAML, especially when casting values such as `| int`.\n\nQuick connectivity check:\n\n```bash\ndbt debug\n```\n\n`dbt debug` validates the project file, profile file, adapter loading, and database connection.\n\n## Core Workflow\n\nInstall packages before parsing or building:\n\n```bash\ndbt deps\n```\n\n`dbt deps` resolves dependencies from `packages.yml` or `dependencies.yml`, installs them, and writes `package-lock.yml`.\n\nParse and validate project structure without connecting to the warehouse:\n\n```bash\ndbt parse\n```\n\nThis is the fastest way to catch many syntax, config, and graph issues early.\n\nBuild selected models only:\n\n```bash\ndbt run --select staging.customers+\n```\n\nRun models plus associated tests, snapshots, seeds, and other buildable resources:\n\n```bash\ndbt build --select marts.finance\n```\n\nRun tests only:\n\n```bash\ndbt test --select marts.finance\n```\n\nGenerate documentation artifacts from the compiled manifest:\n\n```bash\ndbt docs generate\n```\n\nUseful local development loop:\n\n```bash\ndbt debug\ndbt deps\ndbt parse\ndbt build --select my_model+\n```\n\n## Package And Project Configuration\n\n### Dependency files\n\ndbt supports two dependency files:\n\n- `dependencies.yml`: preferred when you only need package declarations\n- `packages.yml`: still required if you need Jinja rendering or private-package features\n\nAfter `dbt deps`, dbt writes `package-lock.yml`. Commit the lock file if you want reproducible installs in CI and across developer machines.\n\nInstalled packages go to `dbt_packages/` by default. You can override that with `packages-install-path` in `dbt_project.yml`.\n\n### Target selection and directories\n\nThese project settings are commonly relevant to automation:\n\n- `profile`: which profile name dbt should load from `profiles.yml`\n- `target-path`: where compiled SQL and artifacts are written\n- `clean-targets`: paths removed by `dbt clean`\n- `packages-install-path`: where `dbt deps` installs packages\n\nIf an automation step runs dbt from outside the project root, pass the project directory explicitly:\n\n```bash\ndbt build --project-dir /path/to/project --profiles-dir /path/to/profiles\n```\n\n## Practical Example\n\nExample layout:\n\n```text\nmy_project/\n  dbt_project.yml\n  models/\n    staging/\n      stg_orders.sql\n      stg_orders.yml\n  macros/\n  packages.yml\n```\n\nExample model:\n\n```sql\nselect\n  id as order_id,\n  customer_id,\n  created_at\nfrom {{ source('raw', 'orders') }}\nwhere created_at >= current_date - interval '30 day'\n```\n\nUseful commands for that project:\n\n```bash\ndbt build --select stg_orders\ndbt test --select stg_orders\ndbt run --select path:models/staging\n```\n\n## Common Pitfalls\n\n- Installing only `dbt-core` and forgetting the adapter package. `dbt debug` will fail before any real warehouse work happens.\n- Treating `dbt run` as equivalent to `dbt build`. `run` executes models; `build` also handles tests and other buildable resources.\n- Skipping `dbt deps` after editing `packages.yml` or `dependencies.yml`.\n- Committing secrets in `profiles.yml` instead of using environment variables.\n- Forgetting that `dbt parse` does not connect to the warehouse. A successful parse does not prove credentials or warehouse objects are valid.\n- Running dbt from the wrong directory without `--project-dir` or `--profiles-dir`, then debugging the wrong project or profile.\n- Repeatedly invoking dbt Core from the same long-lived Python process. The official docs call this unsafe; prefer separate CLI invocations per run.\n- Assuming all adapters share the same credential fields. The profile structure is stable, but the adapter-specific keys are not.\n\n## Version-Sensitive Notes For 1.11\n\n- PyPI currently lists `dbt-core 1.11.7` as the latest release, uploaded on March 4, 2026.\n- `dbt-core 1.11.7` requires Python `>=3.10`.\n- The dbt support matrix lists v1.11 as the latest track and shows end of active support on December 18, 2026.\n- The v1.11 upgrade guide recommends explicitly installing both `dbt-core` and adapter packages in the same environment.\n- dbt 1.11 expands build support for UDF resources, so older 1.10-era guidance around `dbt build` coverage can be incomplete.\n- If you see examples pinned to 1.11.0 or 1.11.1, treat them cautiously because those releases were yanked on PyPI.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/dbt-core/`\n- Installation overview: `https://docs.getdbt.com/docs/core/installation-overview`\n- Supported versions: `https://docs.getdbt.com/docs/dbt-versions/core`\n- Upgrade to v1.11: `https://docs.getdbt.com/docs/dbt-versions/core-upgrade/upgrading-to-v1.11`\n- Profiles: `https://docs.getdbt.com/docs/core/connect-data-platform/profiles.yml`\n- Supported data platforms: `https://docs.getdbt.com/docs/core/connect-data-platform/about-core-connections`\n- `dbt_project.yml` reference: `https://docs.getdbt.com/reference/dbt_project.yml`\n- `dbt debug`: `https://docs.getdbt.com/reference/commands/debug`\n- `dbt deps`: `https://docs.getdbt.com/reference/commands/deps`\n- `dbt parse`: `https://docs.getdbt.com/reference/commands/parse`\n- `dbt run`: `https://docs.getdbt.com/reference/commands/run`\n- `dbt build`: `https://docs.getdbt.com/reference/commands/build`\n- `dbt test`: `https://docs.getdbt.com/reference/commands/test`\n- Packages: `https://docs.getdbt.com/docs/build/packages`\n- `env_var`: `https://docs.getdbt.com/reference/dbt-jinja-functions/env_var`\n"
  },
  {
    "path": "content/debug/docs/debug/javascript/DOC.md",
    "content": "---\nname: debug\ndescription: \"Namespaced debug logging for Node.js and browser JavaScript applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.4.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"debug,logging,nodejs,browser,namespaces\"\n---\n\n# debug for JavaScript\n\nUse `debug` when you want log statements that stay silent until a namespace is enabled. In Node.js, `debug` writes to `stderr` by default. In browsers, the enabled namespace list is persisted in `localStorage`.\n\n## Install\n\n```bash\nnpm install debug\n```\n\nIf you want a wider color palette in Node.js terminals, install `supports-color` alongside `debug`:\n\n```bash\nnpm install debug supports-color\n```\n\n## Import and create loggers\n\nCommonJS:\n\n```js\nconst createDebug = require(\"debug\");\n\nconst log = createDebug(\"myapp\");\nconst httpLog = createDebug(\"myapp:http\");\nconst dbLog = createDebug(\"myapp:db\");\n\nlog(\"booting\");\nhttpLog(\"GET /health\");\ndbLog(\"connected\");\n```\n\nESM:\n\n```js\nimport createDebug from \"debug\";\n\nconst log = createDebug(\"myapp\");\nconst httpLog = createDebug(\"myapp:http\");\nconst dbLog = createDebug(\"myapp:db\");\n\nlog(\"booting\");\nhttpLog(\"GET /health\");\ndbLog(\"connected\");\n```\n\nUse a stable root namespace for your app or library, then add `:`-separated sub-namespaces for features.\n\n## Enable output\n\n`debug` only prints output for namespaces enabled by `DEBUG`.\n\n```bash\n# Exact namespace\nDEBUG=myapp node server.js\n\n# Everything under a root namespace\nDEBUG=myapp:* node server.js\n\n# Multiple namespaces, comma-separated\nDEBUG=myapp:http,myapp:db node server.js\n\n# Exclude noisy namespaces\nDEBUG=myapp:*,-myapp:sql node server.js\n\n# Enable everything\nDEBUG=* node server.js\n```\n\n`DEBUG` also accepts space-delimited names.\n\nWindows examples:\n\n```cmd\nset DEBUG=myapp:* & node server.js\n```\n\n```powershell\n$env:DEBUG = \"myapp:*\"\nnode server.js\n```\n\n## Organize namespaces with `extend()`\n\n```js\nconst createDebug = require(\"debug\");\n\nconst log = createDebug(\"myapp\");\nconst authLog = log.extend(\"auth\");\nconst loginLog = authLog.extend(\"login\");\n\nlog(\"booting\");\nauthLog(\"starting auth flow\");\nloginLog(\"accepted credentials\");\n```\n\nThis produces namespaces like `myapp:auth` and `myapp:auth:login`.\n\n## Enable or disable at runtime\n\n```js\nconst createDebug = require(\"debug\");\n\nconsole.log(createDebug.enabled(\"myapp:db\"));\n\ncreateDebug.enable(\"myapp:*,-myapp:sql\");\nconsole.log(createDebug.enabled(\"myapp:db\"));\n\nconst previousNamespaces = createDebug.disable();\ncreateDebug.enable(previousNamespaces);\n```\n\n`enable()` replaces the current `DEBUG` selection instead of appending to it. `disable()` returns the currently enabled and skipped namespace string so you can restore it later.\n\n## Avoid expensive formatting when disabled\n\n```js\nconst createDebug = require(\"debug\");\n\nconst sqlLog = createDebug(\"myapp:sql\");\n\nif (sqlLog.enabled) {\n  const plan = buildQueryPlan();\n  sqlLog(\"query plan %O\", plan);\n}\n```\n\nCheck `logger.enabled` before doing expensive work to build log arguments.\n\n## Format values\n\n`debug` supports printf-style format strings.\n\n```js\nconst createDebug = require(\"debug\");\n\nconst log = createDebug(\"myapp:worker\");\n\nlog(\"job %s started\", \"sync-users\");\nlog(\"processed %d records\", 42);\nlog(\"payload %o\", { compact: true });\nlog(\"payload %O\", { nested: { keepMultiline: true } });\nlog(\"json %j\", { ok: true });\nlog(\"literal %% sign\");\n```\n\nSupported built-in formatters:\n\n- `%O` pretty-prints objects with multiline output.\n- `%o` pretty-prints objects on one line.\n- `%s`, `%d`, `%j`, and `%%` behave like standard printf-style tokens.\n\n### Add a custom formatter\n\n```js\nconst createDebug = require(\"debug\");\n\ncreateDebug.formatters.h = (value) => value.toString(\"hex\");\n\nconst log = createDebug(\"myapp:hex\");\nlog(\"packet %h\", Buffer.from(\"hello\"));\n```\n\n## Browser usage\n\nIn browsers, enable namespaces through `localStorage`, then refresh the page.\n\n```js\nimport createDebug from \"debug\";\n\nlocalStorage.debug = \"myapp:*\";\n\nconst log = createDebug(\"myapp:ui\");\nlog(\"rendered settings panel\");\n```\n\n`debug` also checks `localStorage.DEBUG`. In Chromium-based devtools, messages from `debug` are usually visible only when the console's `Verbose` level is enabled.\n\n## Node.js environment variables\n\nCommon environment variables:\n\n```bash\nDEBUG=myapp:* DEBUG_COLORS=1 node server.js\nDEBUG=myapp:* DEBUG_HIDE_DATE=1 node server.js\nDEBUG=myapp:* DEBUG_DEPTH=4 DEBUG_SHOW_HIDDEN=1 node server.js\n```\n\n- `DEBUG` enables or disables namespaces.\n- `DEBUG_COLORS` forces color output on or off.\n- `DEBUG_HIDE_DATE` removes the ISO timestamp from non-TTY output.\n- `DEBUG_DEPTH` controls object inspection depth.\n- `DEBUG_SHOW_HIDDEN` includes non-enumerable properties in inspected objects.\n\nFor `%o` and `%O`, `debug` maps `DEBUG_*` variables to Node.js `util.inspect()` options, so additional `DEBUG_...` keys can change object formatting as long as they match a supported inspect option.\n\n## Send output somewhere else\n\nIn Node.js, `debug` writes to `stderr` by default. Override the log function per namespace or globally if you need stdout or a custom sink.\n\n```js\nconst createDebug = require(\"debug\");\n\nconst log = createDebug(\"myapp:stdout\");\nlog.log = console.log.bind(console);\nlog(\"this goes to stdout\");\n\ncreateDebug.log = console.info.bind(console);\n\nconst anotherLog = createDebug(\"myapp:info\");\nanotherLog(\"this now goes through console.info\");\n```\n\nBind `console.log` or `console.info` so the console method keeps the correct receiver.\n\n## Child processes\n\nIf a child process pipes `stderr`, colors are usually suppressed unless you force them on.\n\n```js\nconst { fork } = require(\"node:child_process\");\n\nconst worker = fork(\"./worker.js\", [], {\n  stdio: [0, \"pipe\", \"pipe\", \"ipc\"],\n  env: {\n    ...process.env,\n    DEBUG: \"myapp:*\",\n    DEBUG_COLORS: \"1\",\n  },\n});\n\nworker.stderr.pipe(process.stderr, { end: false });\n```\n\n## Important notes\n\n- Namespace matching is exact unless you use `*` wildcards or `-namespace` exclusions.\n- In browsers, changing `localStorage.debug` does not affect the current page until reload.\n- `debug.destroy()` is deprecated and currently does nothing.\n- A namespace you create with a trailing `*` is always enabled, regardless of `DEBUG`.\n"
  },
  {
    "path": "content/decorator/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"decorator package guide for python - signature-preserving decorators, decorator factories, context managers, and multiple dispatch\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.2.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"decorator,python,decorators,dispatch,contextmanager,metaprogramming\"\n---\n\n# decorator Python Package Guide\n\n## Golden Rule\n\nUse `decorator` when you need a custom decorator that preserves the wrapped function's signature and introspection metadata.\n\nFor simple wrappers where exact signature preservation does not matter, `functools.wraps` is usually enough. Reach for `decorator` when you need correct `inspect.signature(...)`, `__wrapped__`, coroutine detection, or decorator factories that should keep the original call shape instead of collapsing into `*args, **kwargs`.\n\n## Installation\n\n```bash\npip install decorator==5.2.1\n```\n\nCommon alternatives:\n\n```bash\npoetry add decorator==5.2.1\nuv add decorator==5.2.1\n```\n\nOfficial Python requirement for `5.2.1` is `>=3.8` according to PyPI.\n\n## Initialization And Setup\n\nThere is no client object, global configuration, environment variable, or authentication step.\n\nSetup is just import-time:\n\n```python\nfrom decorator import decorator, decorate, contextmanager, dispatch_on\n```\n\nIf you want to avoid the `decorator` module name colliding with the `decorator(...)` helper, alias the module:\n\n```python\nimport decorator as deco\n```\n\n## Core Usage\n\n### 1. Build a signature-preserving decorator with `@decorator`\n\nYour caller function should accept the wrapped function first, then any decorator-factory parameters, then `*args, **kwargs` for the wrapped call.\n\n```python\nfrom decorator import decorator\nimport time\n\n@decorator\ndef warn_slow(func, timelimit=0.25, *args, **kwargs):\n    started = time.perf_counter()\n    result = func(*args, **kwargs)\n    elapsed = time.perf_counter() - started\n    if elapsed > timelimit:\n        print(f\"{func.__name__} took {elapsed:.3f}s\")\n    return result\n\n@warn_slow\ndef add(x: int, y: int = 1) -> int:\n    return x + y\n\nassert add(2, y=3) == 5\n```\n\nWhat this gives you:\n\n- The decorated function keeps the original call signature.\n- `inspect.signature(add)` still reflects `add(x: int, y: int = 1)`.\n- The wrapped function is available as `add.__wrapped__`.\n\n### 2. Use `decorate(...)` for programmatic wrapping\n\nUse `decorate(func, caller)` when you want to wrap a function programmatically instead of using `@` syntax.\n\n```python\nfrom decorator import decorate\n\ndef traced_call(func, *args, **kwargs):\n    print(\"calling\", func.__name__, args, kwargs)\n    return func(*args, **kwargs)\n\ndef multiply(x, y=2):\n    return x * y\n\nmultiply = decorate(multiply, traced_call)\n```\n\nPrefer this over older `decorator(caller, func)` examples from blog posts or older code snippets.\n\n### 3. Build decorator factories directly\n\nExtra parameters before `*args, **kwargs` become decorator-factory arguments.\n\n```python\nfrom decorator import decorator\n\n@decorator\ndef retry(func, attempts=3, *args, **kwargs):\n    last_error = None\n    for _ in range(attempts):\n        try:\n            return func(*args, **kwargs)\n        except Exception as exc:  # narrow this in real code\n            last_error = exc\n    raise last_error\n\n@retry(attempts=5)\ndef flaky_operation():\n    ...\n```\n\nIf every extra parameter has a default, the same decorator can also be used without parentheses:\n\n```python\n@retry\ndef usually_ok():\n    return \"ok\"\n```\n\n### 4. Wrap `async def` functions\n\n`decorator` supports coroutine functions and preserves `inspect.iscoroutinefunction(...)`.\n\n```python\nfrom decorator import decorator\nimport logging\nimport time\n\n@decorator\nasync def log_runtime(func, *args, **kwargs):\n    started = time.perf_counter()\n    try:\n        return await func(*args, **kwargs)\n    finally:\n        elapsed = time.perf_counter() - started\n        logging.info(\"%s took %.3fs\", func.__name__, elapsed)\n\n@log_runtime\nasync def fetch_user(user_id: str) -> dict:\n    ...\n```\n\n### 5. Use `decorator.contextmanager` when the same object should work in `with` blocks and as a decorator\n\nThe stdlib `contextlib.contextmanager` can produce callable context-manager objects, but those wrappers do not preserve the wrapped function signature. `decorator.contextmanager` returns a `ContextManager` subclass whose `__call__` is signature-preserving.\n\n```python\nfrom decorator import contextmanager\n\n@contextmanager\ndef logged(label):\n    print(\"enter\", label)\n    try:\n        yield\n    finally:\n        print(\"exit\", label)\n\n@logged(\"db\")\ndef run_query(sql: str, limit: int = 100) -> str:\n    return f\"running {sql} with limit={limit}\"\n```\n\nYou can also use the same object in a `with` block:\n\n```python\nwith logged(\"db\"):\n    ...\n```\n\n### 6. Use `dispatch_on(...)` for lightweight multiple dispatch\n\n`dispatch_on` creates generic functions that dispatch on one or more named arguments.\n\n```python\nfrom decorator import dispatch_on\n\n@dispatch_on(\"value\")\ndef render(value):\n    raise NotImplementedError(type(value))\n\n@render.register(int)\ndef _(value):\n    return f\"int:{value}\"\n\n@render.register(str)\ndef _(value):\n    return f\"str:{value}\"\n```\n\nUseful helpers:\n\n- `render.register(Type)` registers an implementation.\n- `render.dispatch_info(SomeType)` shows the resolution order.\n- Ambiguous virtual-ancestor matches raise `RuntimeError` instead of guessing.\n\n### 7. Set `kwsyntax=True` only when your wrapper needs original keyword spelling\n\nBy default, `decorator` normalizes arguments against the wrapped function signature before your caller sees them. That means positional-or-keyword parameters usually arrive in `args`, even if the caller used keyword syntax.\n\n```python\nfrom decorator import decorator\n\ndef debug_call(func, *args, **kwargs):\n    print(args, kwargs)\n    return func(*args, **kwargs)\n\ndebug = decorator(debug_call, kwsyntax=True)\n\n@debug\ndef printsum(x=1, y=2):\n    return x + y\n\nprintsum(y=2, x=1)\n```\n\nLeave `kwsyntax=False` unless your wrapper logic depends on how the caller spelled keyword arguments.\n\n### 8. `decoratorx(...)` is niche\n\n`decoratorx` exists for cases where you need wrapper generation via `FunctionMaker` and want to preserve more `__code__`-level details. In normal application code, prefer `@decorator` or `decorate(...)`.\n\n## Config And Environment\n\n- No auth.\n- No environment variables.\n- No global init sequence.\n- No runtime config file.\n\nThe main setup choice is which helper to use:\n\n- `@decorator` for most new decorators and decorator families\n- `decorate(func, caller)` for programmatic wrapping\n- `contextmanager` when the wrapper should also be usable in `with`\n- `dispatch_on` for generic-function style dispatch\n\n## Common Pitfalls\n\n### Import-name collisions\n\nThis is easy to misread:\n\n```python\nfrom decorator import decorator\n```\n\nIf the code also needs the module namespace, alias one of them:\n\n```python\nimport decorator as deco\nfrom decorator import decorator\n```\n\n### Caller signatures are strict\n\nYour caller function should be shaped like one of these:\n\n```python\ndef caller(func, *args, **kwargs): ...\ndef caller(func, option=default, *args, **kwargs): ...\n```\n\nPut decorator-factory parameters before `*args, **kwargs`, not after them.\n\n### `kwsyntax=False` surprises people\n\nThis package is intentionally not a thin clone of `functools.wraps`.\n\nIf your wrapper prints or inspects arguments, a call like `f(x=1, y=2)` may still arrive as positional arguments after signature normalization. Set `kwsyntax=True` only if you need wraps-like behavior.\n\n### `contextlib.contextmanager` and `decorator.contextmanager` are not interchangeable\n\nUse `decorator.contextmanager` when you need a context manager that is also a signature-preserving decorator.\n\nIf you only need `with ...:` behavior and never decorate functions with it, the stdlib `contextlib.contextmanager` is simpler.\n\n### `dispatch_on` is not full multimethod infrastructure\n\nIt is a compact generic-function mechanism, not a full plugin registry or validation system.\n\nWatch for:\n\n- ambiguous virtual-ancestor relationships, which raise `RuntimeError`\n- dispatch registration based on concrete argument names\n- default implementation fallback when no registered specialization matches\n\n### Some wrapped functions are generated objects\n\nIf `inspect.getsource(wrapped_fn)` fails, inspect `wrapped_fn.__wrapped__` instead.\n\n```python\nimport inspect\n\ninspect.getsource(my_function.__wrapped__)\n```\n\n### The maintainer docs page is not version-pinned\n\nThe repository documentation linked from PyPI currently points at the `master` branch docs page, and that page is labeled `5.2.0` rather than `5.2.1`.\n\nFor version-sensitive work, check both:\n\n- the exact PyPI release page for `5.2.1`\n- the maintainer changelog for any `5.2.x` behavior changes\n\n## Version-Sensitive Notes\n\n- `5.2.1` is the current PyPI release listed on the official project page, published on February 24, 2025.\n- The maintainer changelog currently has a `5.2.0` section but no separate `5.2.1` section. Inference: treat `5.2.1` as the current install target, but use `5.2.0` maintainer docs/changelog to understand the public API until a dedicated `5.2.1` note appears upstream.\n- `5.2.0` added official support for Python `3.11`, `3.12`, and `3.13`, dropped official support claims for Python `<3.8`, and added support for decorating `functools.partial` objects.\n- `5.1.1` fixed decoration of cythonized functions and repaired `decorator.contextmanager` regressions from `5.1.0`.\n- `5.1.0` added `decoratorx(...)` and fixed `kwsyntax` forwarding through `decorator.decorator(...)`.\n\n## Official Sources\n\n- Repository: `https://github.com/micheles/decorator`\n- Maintainer documentation: `https://github.com/micheles/decorator/blob/master/docs/documentation.md`\n- Changelog: `https://github.com/micheles/decorator/blob/master/CHANGES.md`\n- Exact PyPI release page: `https://pypi.org/project/decorator/5.2.1/`\n"
  },
  {
    "path": "content/deepgram/docs/speech/javascript/DOC.md",
    "content": "---\nname: speech\ndescription: \"Deepgram JavaScript SDK coding guidelines for speech recognition, text-to-speech, and audio intelligence\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.11.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"deepgram,speech,transcription,tts,audio\"\n---\n\n# Deepgram JavaScript SDK Coding Guidelines\n\nYou are a Deepgram API coding expert. Help me with writing code using the Deepgram JavaScript SDK for speech recognition, text-to-speech, voice agents, and text intelligence.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.deepgram.com/\n\n## Golden Rule: Use the Current Official SDK\n\nAlways use the official Deepgram JavaScript SDK, which is the standard library for all Deepgram API interactions.\n\n- **Library Name:** Deepgram JavaScript SDK\n- **NPM Package:** `@deepgram/sdk`\n- **Minimum Node.js Version:** 18.0.0\n\n**Installation:**\n\n- **Correct:** `npm install @deepgram/sdk` \n\n**APIs and Usage:**\n\n- **Correct:** `import { createClient } from \"@deepgram/sdk\"`\n- **Correct:** `const deepgram = createClient(DEEPGRAM_API_KEY)`\n- **Incorrect:** Using any other import patterns or client creation methods\n\n## Initialization and API Key\n\nThe `@deepgram/sdk` library requires creating a client instance for all API calls.\n\n- Always use `createClient()` to create an instance\n- Set your Deepgram API key as the first parameter\n- Get your free API key from: https://console.deepgram.com/signup?jump=keys\n\n```javascript\nimport { createClient } from \"@deepgram/sdk\";\n\nconst deepgram = createClient(\"your-deepgram-api-key\");\n```\n\n## Models\n\n### Speech Recognition Models\n\nBy default, use the following models for speech recognition:\n\n- **General Purpose (Recommended):** `nova-3` or `nova-3-general`\n- **Medical Applications:** `nova-3-medical` or `nova-2-medical`\n- **Meeting Transcription:** `nova-2-meeting` or `enhanced-meeting`\n- **Phone Call Audio:** `nova-2-phonecall` or `enhanced-phonecall`\n- **Cost-Effective Option:** `nova` or `enhanced`\n- **Highest Accuracy:** `nova-3` (latest generation)\n\n### Text-to-Speech Models\n\nFor text-to-speech, use the Aura model series:\n\n- **Recommended Default:** `aura-2-thalia-en`\n- **Available Voices:** All `aura-2-*` models for various voice characteristics\n- **Legacy Support:** `aura-*` models (first generation)\n\n## Basic Speech Recognition (Transcription)\n\n### Synchronous Transcription - Remote Files\n\n```javascript\nimport { createClient } from \"@deepgram/sdk\";\n\nconst deepgram = createClient(\"your-api-key\");\n\nconst { result, error } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: \"https://example.com/audio.wav\" },\n  { model: \"nova-3\" }\n);\n\nif (error) {\n  console.error(\"Transcription error:\", error);\n} else {\n  console.log(\"Transcript:\", result);\n}\n```\n\n### Synchronous Transcription - Local Files\n\n```javascript\nimport fs from \"fs\";\n\n// Using file stream\nconst { result, error } = await deepgram.listen.prerecorded.transcribeFile(\n  fs.createReadStream(\"./audio.wav\"),\n  { model: \"nova-3\" }\n);\n\n// Using file buffer\nconst { result, error } = await deepgram.listen.prerecorded.transcribeFile(\n  fs.readFileSync(\"./audio.wav\"),\n  { model: \"nova-3\" }\n);\n```\n\n### Live Streaming Transcription\n\n```javascript\nconst dgConnection = deepgram.listen.live({ model: \"nova-3\" });\n\ndgConnection.on(LiveTranscriptionEvents.Open, () => {\n  dgConnection.on(LiveTranscriptionEvents.Transcript, (data) => {\n    console.log(data);\n  });\n\n  // Send audio data\n  dgConnection.send(audioData);\n});\n```\n\n## Text-to-Speech\n\n### REST API (One-off requests)\n\n```javascript\nconst { result, error } = await deepgram.speak.request(\n  { text: \"Hello, how are you today?\" }, \n  { model: \"aura-2-thalia-en\" }\n);\n```\n\n### WebSocket (Streaming)\n\n```javascript\nconst dgConnection = deepgram.speak.live({ model: \"aura-2-thalia-en\" });\n\ndgConnection.on(LiveTTSEvents.Open, () => {\n  dgConnection.sendText(\"Hello world\");\n  dgConnection.flush(); // Important: flush after sending text\n});\n```\n\n## Voice Agent\n\n```javascript\nconst agent = deepgram.agent();\n\nagent.on(AgentEvents.Open, () => {\n  agent.configure({\n    audio: {\n      input: { encoding: \"linear16\", sample_rate: 16000 },\n      output: { encoding: \"linear16\", container: \"wav\", sample_rate: 24000 }\n    },\n    agent: {\n      listen: { model: \"nova-3\" },\n      speak: { model: \"aura-2-thalia-en\" },\n      think: {\n        provider: { type: \"anthropic\" },\n        model: \"claude-3-haiku-20240307\",\n        instructions: \"You are a helpful AI assistant.\"\n      }\n    }\n  });\n});\n\nagent.on(AgentEvents.Audio, (audio) => {\n  // Handle audio response\n});\n```\n\n## Error Handling\n\nThe SDK uses a consistent error handling pattern with `DeepgramResponse`:\n\n**Error Types:**\n\n- `DeepgramError`: Base error class\n- `DeepgramApiError`: API-related errors with HTTP status codes\n- `DeepgramUnknownError`: Unexpected errors\n- `DeepgramVersionError`: SDK version compatibility errors\n\n```javascript\nconst { result, error } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: \"invalid-url\" },\n  { model: \"nova-3\" }\n);\n\nif (error) {\n  if (error instanceof DeepgramApiError) {\n    console.error(`API Error (${error.status}): ${error.message}`);\n  } else {\n    console.error(\"Unexpected error:\", error.message);\n  }\n  return;\n}\n\n// Process successful result\nconsole.log(result);\n```\n\n## Configuration and Advanced Features\n\n### Scoped Configuration\n\nThe SDK supports namespace-specific configurations:\n\n```javascript\n// Global configuration\nconst deepgram = createClient(\"api-key\", {\n  global: { \n    fetch: { options: { url: \"https://api.beta.deepgram.com\" } } \n  }\n});\n\n// Transcription-specific configuration\nconst deepgram = createClient(\"api-key\", {\n  listen: { \n    fetch: { options: { url: \"http://localhost:8080\" } } \n  }\n});\n```\n\n### Important Transcription Options\n\n- `model`: Speech recognition model to use\n- `language`: Language code (e.g., \"en\", \"es\", \"fr\")\n- `punctuate`: Add punctuation to transcript\n- `diarize`: Speaker identification\n- `smart_format`: Automatic formatting improvements\n- `keyterm`: Keyword detection (Nova 3 only)\n\n### Keyterm Detection (Nova 3 Only)\n\n```javascript\nconst { result, error } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: \"audio.wav\" },\n  { \n    model: \"nova-3\",\n    keyterm: [\"urgent\", \"deadline\", \"meeting\"]\n  }\n);\n```\n\n## Common Mistakes to Avoid\n\n- **Don't** use deprecated models like older versions without explicit need\n- **Don't** forget to handle both `result` and `error` in responses\n- **Don't** use keyterm detection with non-Nova-3 models\n- **Don't** forget to call `flush()` when using live text-to-speech\n- **Don't** hardcode API keys in your source code - use environment variables\n- **Always** check for errors before processing results\n\n## Browser Support\n\nThe SDK works in browsers with UMD and ESM support:\n\n```html\n<!-- UMD -->\n<script src=\"https://cdn.jsdelivr.net/npm/@deepgram/sdk\"></script>\n<script>\n  const { createClient } = deepgram;\n  const client = createClient(\"api-key\");\n</script>\n\n<!-- ESM -->\n<script type=\"module\">\n  import { createClient } from \"https://cdn.jsdelivr.net/npm/@deepgram/sdk/+esm\";\n  const client = createClient(\"api-key\");\n</script>\n```\n\n## Additional Features\n\n### Text Intelligence\n\n```javascript\nconst { result, error } = await deepgram.read.analyzeText(\n  { text: \"Your text content here\" },\n  { language: \"en\", topics: true, sentiment: true }\n);\n```\n\n### Captions Generation\n\n```javascript\nimport { webvtt, srt } from \"@deepgram/captions\";\n\n// After getting transcription result\nconst vttOutput = webvtt(result);\nconst srtOutput = srt(result);\n```\n\n## Useful Links\n\n- Documentation: https://developers.deepgram.com/\n- API Reference: https://developers.deepgram.com/reference/\n- Models Guide: https://developers.deepgram.com/docs/model\n- Getting API Keys: https://console.deepgram.com/signup?jump=keys\n\n## Notes\n\n- The SDK strictly follows semantic versioning\n- Always use documented interfaces to ensure compatibility\n- The SDK supports both Node.js (18+) and browser environments\n- For production applications, implement proper error handling and logging\n- Consider using environment variables for API key management\n\n### Citations\n\n```json\n  \"name\": \"@deepgram/sdk\",\n  \"engines\": {\n    \"node\": \">=18.0.0\"\n  },\nnpm install @deepgram/sdk\n```\n\n\n### UMD\n\nYou can now use plain `<script>`s to import deepgram from CDNs, like:\n\n<script src=\"https://cdn.jsdelivr.net/npm/@deepgram/sdk\"></script>\n\n\nor even:\n\n```html\n<script src=\"https://unpkg.com/@deepgram/sdk\"></script>\n```\n\nThen you can use it from a global deepgram variable:\n\n```html\n<script>\n  const { createClient } = deepgram;\n  const _deepgram = createClient(\"deepgram-api-key\");\n\n  console.log(\"Deepgram Instance: \", _deepgram);\n  // ...\n</script>\n```\n\n### ESM\n\nYou can now use type=\"module\" `<script>`s to import deepgram from CDNs, like:\n\n```html\n<script type=\"module\">\n  import { createClient } from \"https://cdn.jsdelivr.net/npm/@deepgram/sdk/+esm\";\n  const deepgram = createClient(\"deepgram-api-key\");\n\n  console.log(\"Deepgram Instance: \", deepgram);\n  // ...\n</script>\n```\n\n```typescript\nimport { createClient } from \"@deepgram/sdk\";\n// - or -\nconst { createClient } = require(\"@deepgram/sdk\");\n```\n\n```typescript\nconst deepgram = createClient(DEEPGRAM_API_KEY);\n```\n\n To access the Deepgram API you will need a [free Deepgram API Key](https://console.deepgram.com/signup?jump=keys).\n\n\nThe SDK supports scoped configuration. You'll be able to configure various aspects of each namespace of the SDK from the initialization. Below outlines a flexible and customizable configuration system for the Deepgram SDK. Here's how the namespace configuration works:\n\n### 1. Global Defaults\n\n- The `global` namespace serves as the foundational configuration applicable across all other namespaces unless overridden.\n- Includes general settings like URL and headers applicable for all API calls.\n- If no specific configurations are provided for other namespaces, the `global` defaults are used.\n\n### 2. Namespace-specific Configurations\n\n- Each namespace (`listen`, `manage`, `onprem`, `read`, `speak`) can have its specific configurations which override the `global` settings within their respective scopes.\n- Allows for detailed control over different parts of the application interacting with various Deepgram API endpoints.\n\n### 3. Transport Options\n\n- Configurations for both `fetch` and `websocket` can be specified under each namespace, allowing different transport mechanisms for different operations.\n- For example, the `fetch` configuration can have its own URL and proxy settings distinct from the `websocket`.\n- The generic interfaces define a structure for transport options which include a client (like a `fetch` or `WebSocket` instance) and associated options (like headers, URL, proxy settings).\n\nThis configuration system enables robust customization where defaults provide a foundation, but every aspect of the client's interaction with the API can be finely controlled and tailored to specific needs through namespace-specific settings. This enhances the maintainability and scalability of the application by localizing configurations to their relevant contexts.\n\n\n\n\n```js\nconst { result, error } = await deepgram.listen.prerecorded.transcribeUrl(\n  {\n    url: \"https://dpgr.am/spacewalk.wav\",\n  },\n  {\n    model: \"nova\",\n  }\n);\n\nconst { result, error } = await deepgram.listen.prerecorded.transcribeFile(\n  fs.createReadStream(\"./examples/spacewalk.wav\"),\n  {\n    model: \"nova\",\n  }\n);\n```\n\nor\n\n```js\nconst { result, error } = await deepgram.listen.prerecorded.transcribeFile(\n  fs.readFileSync(\"./examples/spacewalk.wav\"),\n  {\n    model: \"nova\",\n  }\n);\n\nconst dgConnection = deepgram.listen.live({ model: \"nova\" });\n\ndgConnection.on(LiveTranscriptionEvents.Open, () => {\n  dgConnection.on(LiveTranscriptionEvents.Transcript, (data) => {\n    console.log(data);\n  });\n\n  source.addListener(\"got-some-audio\", async (event) => {\n    dgConnection.send(event.raw_audio_data);\n  });\n});\n\n```\n```js\nimport { webvtt /* , srt */ } from \"@deepgram/captions\";\n\nconst { result, error } = await deepgram.listen.prerecorded.transcribeUrl(\n  {\n    url: \"https://dpgr.am/spacewalk.wav\",\n  },\n  {\n    model: \"nova\",\n  }\n);\n\nconst vttOutput = webvtt(result);\n// const srtOutput = srt(result);\n\n```\n```js\nimport { createClient } from \"@deepgram/sdk\";\nimport { AgentEvents } from \"@deepgram/sdk\";\n\nconst deepgram = createClient(DEEPGRAM_API_KEY);\n\n// Create an agent connection\nconst agent = deepgram.agent();\n\n// Set up event handlers\nagent.on(AgentEvents.Open, () => {\n  console.log(\"Connection opened\");\n\n  // Configure the agent once connection is established\n  agent.configure({\n    audio: {\n      input: {\n        encoding: \"linear16\",\n        sampleRate: 16000,\n      },\n      output: {\n        encoding: \"linear16\",\n        container: \"wav\",\n        sampleRate: 24000,\n      },\n    },\n    agent: {\n      listen: {\n        model: \"nova-3\",\n      },\n      speak: {\n        model: \"aura-2-thalia-en\",\n      },\n      think: {\n        provider: {\n          type: \"anthropic\",\n        },\n        model: \"claude-3-haiku-20240307\",\n        instructions: \"You are a helpful AI assistant. Keep responses brief and friendly.\",\n      },\n    },\n  });\n});\n\n// Handle agent responses\nagent.on(AgentEvents.AgentStartedSpeaking, (data) => {\n  console.log(\"Agent started speaking:\", data[\"total_latency\"]);\n});\n\nagent.on(AgentEvents.ConversationText, (message) => {\n  console.log(`${message.role} said: ${message.content}`);\n});\n\nagent.on(AgentEvents.Audio, (audio) => {\n  // Handle audio data from the agent\n  playAudio(audio); // Your audio playback implementation\n});\n\nagent.on(AgentEvents.Error, (error) => {\n  console.error(\"Error:\", error);\n});\n\nagent.on(AgentEvents.Close, () => {\n  console.log(\"Connection closed\");\n});\n\n// Send audio data\nfunction sendAudioData(audioData) {\n  agent.send(audioData);\n}\n\n// Keep the connection alive\nsetInterval(() => {\n  agent.keepAlive();\n}, 8000);\n\n\nconst { result } = await deepgram.speak.request({ text }, { model: \"aura-2-thalia-en\" });\n\n\n\nconst dgConnection = deepgram.speak.live({ model: \"aura-2-thalia-en\" });\n\ndgConnection.on(LiveTTSEvents.Open, () => {\n  console.log(\"Connection opened\");\n\n  // Send text data for TTS synthesis\n  dgConnection.sendText(text);\n\n  // Send Flush message to the server after sending the text\n  dgConnection.flush();\n\n  dgConnection.on(LiveTTSEvents.Close, () => {\n    console.log(\"Connection closed\");\n  });\n});\n\n\n\nconst { result, error } = await deepgram.read.analyzeText(\n  { text },\n  { language: \"en\", topics: true, sentiment: true }\n);\n```\n\n\n\nOlder SDK versions will receive Priority 1 (P1) bug support only. Security issues, both in our code and dependencies, are promptly addressed. Significant bugs without clear workarounds are also given priority attention.\n\nWe strictly follow semver, and will not introduce breaking changes to the publicly documented interfaces of the SDK. **Use internal and undocumented interfaces without pinning your version, at your own risk.**\n\n\n\n```typescript\ntype ListenModel =\n  | \"nova-3\"\n  | \"nova-3-general\"\n  | \"nova-3-medical\"\n  | \"nova-2\"\n  | \"nova-2-meeting\"\n  | \"nova-2-phonecall\"\n  | \"nova-2-voicemail\"\n  | \"nova-2-finance\"\n  | \"nova-2-conversational\"\n  | \"nova-2-video\"\n  | \"nova-2-medical\"\n  | \"nova-2-drivethru\"\n  | \"nova-2-automotive\"\n  | \"nova-2-atc\"\n  | \"nova\"\n  | \"nova-phonecall\"\n  | \"enhanced\"\n  | \"enhanced-meeting\"\n  | \"enhanced-phonecall\"\n  | \"enhanced-finance\"\n  | \"base\"\n  | \"base-meeting\"\n  | \"base-phonecall\"\n  | \"base-voicemail\"\n  | \"base-finance\"\n  | \"base-conversational\"\n  | \"base-video\"\n  | \"whisper-tiny\"\n  | \"whisper\"\n  | \"whisper-small\"\n  | \"whisper-medium\"\n  | \"whisper-large\"\n  | string;\n```\n\n```typescript\ntype SpeakModel =\n  | \"aura-asteria-en\"\n  | \"aura-luna-en\"\n  | \"aura-stella-en\"\n  | \"aura-athena-en\"\n  | \"aura-hera-en\"\n  | \"aura-orion-en\"\n  | \"aura-arcas-en\"\n  | \"aura-perseus-en\"\n  | \"aura-angus-en\"\n  | \"aura-orpheus-en\"\n  | \"aura-helios-en\"\n  | \"aura-zeus-en\"\n  | \"aura-2-amalthea-en\"\n  | \"aura-2-andromeda-en\"\n  | \"aura-2-apollo-en\"\n  | \"aura-2-arcas-en\"\n  | \"aura-2-aries-en\"\n  | \"aura-2-asteria-en\"\n  | \"aura-2-athena-en\"\n  | \"aura-2-atlas-en\"\n  | \"aura-2-aurora-en\"\n  | \"aura-2-callista-en\"\n  | \"aura-2-cordelia-en\"\n  | \"aura-2-cora-en\"\n  | \"aura-2-cressida-en\"\n  | \"aura-2-delia-en\"\n  | \"aura-2-draco-en\"\n  | \"aura-2-electra-en\"\n  | \"aura-2-harmonia-en\"\n  | \"aura-2-helena-en\"\n  | \"aura-2-hera-en\"\n  | \"aura-2-hermes-en\"\n  | \"aura-2-hyperion-en\"\n  | \"aura-2-iris-en\"\n  | \"aura-2-janus-en\"\n  | \"aura-2-juno-en\"\n  | \"aura-2-jupiter-en\"\n  | \"aura-2-luna-en\"\n  | \"aura-2-mars-en\"\n  | \"aura-2-minerva-en\"\n  | \"aura-2-neptune-en\"\n  | \"aura-2-odysseus-en\"\n  | \"aura-2-ophelia-en\"\n  | \"aura-2-orion-en\"\n  | \"aura-2-orpheus-en\"\n  | \"aura-2-pandora-en\"\n  | \"aura-2-phoebe-en\"\n  | \"aura-2-pluto-en\"\n  | \"aura-2-saturn-en\"\n  | \"aura-2-selene-en\"\n  | \"aura-2-thalia-en\"\n  | \"aura-2-theia-en\"\n  | \"aura-2-vesta-en\"\n  | \"aura-2-zeus-en\"\n  | string;\n        /**\n         * Only available for Nova 3.\n         * @see https://developers.deepgram.com/docs/keyterm\n         */\n        keyterms?: string[];\n      };\n```\n\n```typescript\nexport type DeepgramResponse<T> = SuccessResponse<T> | ErrorResponse;\n\ninterface SuccessResponse<T> {\n  result: T;\n  error: null;\n}\n\ninterface ErrorResponse {\n  result: null;\n  error: DeepgramError;\n}\n```\n\n```typescript\nexport class DeepgramError extends Error {\n  protected __dgError = true;\n\n  constructor(message: string) {\n    super(message);\n    this.name = \"DeepgramError\";\n  }\n}\n\nexport function isDeepgramError(error: unknown): error is DeepgramError {\n  return typeof error === \"object\" && error !== null && \"__dgError\" in error;\n}\n\nexport class DeepgramApiError extends DeepgramError {\n  status: number;\n\n  constructor(message: string, status: number) {\n    super(message);\n    this.name = \"DeepgramApiError\";\n    this.status = status;\n  }\n\n  toJSON() {\n    return {\n      name: this.name,\n      message: this.message,\n      status: this.status,\n    };\n  }\n}\n\nexport class DeepgramUnknownError extends DeepgramError {\n  originalError: unknown;\n\n  constructor(message: string, originalError: unknown) {\n    super(message);\n    this.name = \"DeepgramUnknownError\";\n    this.originalError = originalError;\n  }\n}\n\nexport class DeepgramVersionError extends DeepgramError {\n  constructor() {\n    super(\n      `You are attempting to use an old format for a newer SDK version. Read more here: https://dpgr.am/js-v3`\n    );\n\n    this.name = \"DeepgramVersionError\";\n  }\n}\n```\n\n```typescript\ninterface TranscriptionSchema extends Record<string, unknown> {\n  /**\n   * @see https://developers.deepgram.com/docs/model\n   */\n  model?: string;\n\n  /**\n   * @deprecated\n   * @see https://developers.deepgram.com/docs/tier\n   */\n  tier?: string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/version\n   */\n  version?: string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/language\n   */\n  language?: string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/punctuation\n   */\n  punctuate?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/profanity-filter\n   */\n  profanity_filter?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/redaction\n   */\n  redact?: string[] | string | boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/diarization\n   */\n  diarize?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/diarization\n   */\n  diarize_version?: string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/smart-format\n   */\n  smart_format?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/filler-words\n   */\n  filler_words?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/multichannel\n   */\n  multichannel?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/numerals\n   * @deprecated\n   */\n  numerals?: boolean;\n\n  /**\n   * @see https://developers.deepgram.com/docs/search\n   */\n  search?: string[] | string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/find-and-replace\n   */\n  replace?: string[] | string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/callback\n   */\n  callback?: string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/callback#results\n   */\n  callback_method?: \"put\" | \"post\";\n\n  /**\n   * @see https://developers.deepgram.com/docs/keywords\n   */\n  keywords?: string[] | string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/keyterm\n   */\n  keyterm?: string[] | string;\n\n  /**\n   * @see https://developers.deepgram.com/docs/tagging\n   */\n  tag?: string[];\n\n  /**\n   * As yet unreleased.\n   */\n  sentiment?: boolean;\n\n  /**\n   * As yet unreleased.\n   */\n  intents?: boolean;\n\n  /**\n   * As yet unreleased.\n   */\n  custom_intent?: string[] | string;\n\n  /**\n   * As yet unreleased.\n   */\n  custom_intent_mode?: \"strict\" | \"extended\";\n\n  /**\n   * As yet unreleased.\n   */\n  topics?: boolean;\n\n  /**\n   * As yet unreleased.\n   */\n  custom_topic?: string[] | string;\n\n  /**\n   * As yet unreleased.\n   */\n  custom_topic_mode?: \"strict\" | \"extended\";\n\n  /**\n   * @see https://developers.deepgram.com/docs/extra-metadata\n   */\n  extra?: string[] | string;\n}\n```\n"
  },
  {
    "path": "content/deepgram/docs/speech/python/DOC.md",
    "content": "---\nname: speech\ndescription: \"Deepgram Python SDK coding guidelines for speech recognition, text-to-speech, and audio intelligence\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.1.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"deepgram,speech,transcription,tts,audio\"\n---\n\n# Deepgram Python SDK Coding Guidelines\n\nYou are a Deepgram Python SDK coding expert. Help me with writing code using the Deepgram API calling the official Python SDK.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.deepgram.com/docs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Deepgram Python SDK for all Deepgram API interactions. <cite/>\n\n- **Library Name:** Deepgram Python SDK\n- **Python Package:** `deepgram-sdk`\n- **Repository:** https://github.com/deepgram/deepgram-python-sdk\n\n**Installation:**\n\n- **Correct:** `pip install deepgram-sdk`\n\n**APIs and Usage:**\n\n- **Correct:** `from deepgram import DeepgramClient`\n- **Correct:** `from deepgram import SpeakOptions, PrerecordedOptions, LiveOptions`\n- **Correct:** `from deepgram import ReadOptions, SettingsOptions`\n\n## Initialization and API Key\n\nThe `deepgram-sdk` library requires creating a client object for all API calls. <cite/>\n\n- Always use `client = DeepgramClient()` to create a client object\n- Set `DEEPGRAM_API_KEY` environment variable, which will be picked up automatically\n- Alternatively, pass the API key directly: `client = DeepgramClient(api_key=\"YOUR_API_KEY\")`\n\n```python\nfrom deepgram import DeepgramClient\n\n# Using environment variable DEEPGRAM_API_KEY\nclient = DeepgramClient()\n\n# Or direct API key\nclient = DeepgramClient(api_key=\"YOUR_API_KEY\")\n```\n\n## Authentication Methods\n\nThe Deepgram Python SDK supports multiple authentication methods:\n\n### API Key Authentication (Traditional)\n```python\nfrom deepgram import DeepgramClient\n\n# Direct API key\nclient = DeepgramClient(api_key=\"YOUR_API_KEY\")\n\n# Or using environment variable DEEPGRAM_API_KEY\nclient = DeepgramClient()  # Auto-detects from environment\n```\n\n### Bearer Token Authentication (OAuth 2.0)\n```python\nfrom deepgram import DeepgramClient\n\n# Direct access token\nclient = DeepgramClient(access_token=\"YOUR_ACCESS_TOKEN\")\n\n# Or using environment variable DEEPGRAM_ACCESS_TOKEN\nclient = DeepgramClient()  # Auto-detects from environment\n```\n\n## Models\n\nBy default, use the following models when using the Deepgram SDK: <cite/>\n\n- **Speech-to-Text Tasks:** `nova-3` (latest general model)\n- **Text-to-Speech Tasks:** `aura-2-thalia-en` (default TTS model)\n- **Text Intelligence Tasks:** `nova-3`\n\n## Speech-to-Text (Transcription)\n\n### Pre-Recorded Audio (Synchronous)\n\nFor transcribing pre-recorded audio files:\n\n```python\nfrom deepgram import DeepgramClient, PrerecordedOptions, FileSource\n\n# Create client\nclient = DeepgramClient()\n\n# Configure options\noptions = PrerecordedOptions(\n    model=\"nova-3\",\n    smart_format=True,\n    language=\"en\"\n)\n\n# From URL\nurl_source = {\"url\": \"https://example.com/audio.wav\"}\nresponse = client.listen.rest.v(\"1\").transcribe_url(url_source, options)\n\n# From local file\nwith open(\"audio.wav\", \"rb\") as file:\n    buffer_data = file.read()\n    \npayload = {\"buffer\": buffer_data}\nresponse = client.listen.rest.v(\"1\").transcribe_file(payload, options)\n\nprint(response.results.channels[0].alternatives[0].transcript)\n```\n\n### Pre-Recorded Audio (Asynchronous)\n\nFor asynchronous transcription with callbacks:\n\n```python\nimport asyncio\nfrom deepgram import DeepgramClient, PrerecordedOptions\n\nasync def main():\n    client = DeepgramClient()\n    \n    options = PrerecordedOptions(\n        model=\"nova-3\",\n        smart_format=True\n    )\n    \n    url_source = {\"url\": \"https://example.com/audio.wav\"}\n    response = await client.listen.asyncrest.v(\"1\").transcribe_url(url_source, options)\n    \n    print(response.results.channels[0].alternatives[0].transcript)\n\nasyncio.run(main())\n```\n\n### Streaming Audio (Real-time)\n\nFor real-time audio transcription:\n\n```python\nfrom deepgram import DeepgramClient, LiveTranscriptionEvents, LiveOptions\n\n# Create client\nclient = DeepgramClient()\n\n# Create connection\ndg_connection = client.listen.websocket.v(\"1\")\n\ndef on_message(self, result, **kwargs):\n    sentence = result.channel.alternatives[0].transcript\n    if len(sentence) == 0:\n        return\n    print(f\"Transcript: {sentence}\")\n\ndef on_error(self, error, **kwargs):\n    print(f\"Error: {error}\")\n\n# Register event handlers\ndg_connection.on(LiveTranscriptionEvents.Transcript, on_message)\ndg_connection.on(LiveTranscriptionEvents.Error, on_error)\n\n# Configure options\noptions = LiveOptions(\n    model=\"nova-3\",\n    language=\"en\",\n    smart_format=True\n)\n\n# Start connection\nif dg_connection.start(options) is False:\n    print(\"Failed to start connection\")\n    exit()\n\n# Send audio data (example with microphone)\n# dg_connection.send(audio_data)\n\n# Close connection when done\ndg_connection.finish()\n```\n\n## Text-to-Speech\n\n### REST API (Batch Conversion)\n\nFor converting text to speech in batch mode:\n\n```python\nfrom deepgram import DeepgramClient, SpeakOptions\n\n# Create client\nclient = DeepgramClient()\n\n# Configure TTS options\noptions = SpeakOptions(\n    model=\"aura-2-thalia-en\",\n    encoding=\"linear16\",\n    sample_rate=24000\n)\n\n# Input text\ninput_text = {\"text\": \"Hello, world.\"}\n\n# Convert text to speech and store in memory\nresponse = client.speak.rest.v(\"1\").stream_memory(input_text, options)\n\n# Access the audio data\naudio_data = response.stream_memory.getbuffer()\n\n# Save to a file\nwith open(\"output.wav\", \"wb\") as file:\n    file.write(audio_data)\n```\n\n### REST API (Save to File)\n\n```python\nfrom deepgram import DeepgramClient, SpeakOptions\n\nclient = DeepgramClient()\n\noptions = SpeakOptions(\n    model=\"aura-2-thalia-en\",\n    encoding=\"linear16\",\n    sample_rate=24000\n)\n\ninput_text = {\"text\": \"Hello, world.\"}\n\n# Convert text to speech and save directly to file\nresponse = client.speak.rest.v(\"1\").save(\"output.wav\", input_text, options)\n```\n\n### Asynchronous Text-to-Speech\n\n```python\nimport asyncio\nfrom deepgram import DeepgramClient, SpeakOptions\n\nasync def main():\n    client = DeepgramClient()\n    \n    options = SpeakOptions(\n        model=\"aura-2-thalia-en\",\n        encoding=\"linear16\",\n        sample_rate=24000\n    )\n    \n    input_text = {\"text\": \"Hello, world.\"}\n    \n    response = await client.speak.asyncrest.v(\"1\").stream_memory(input_text, options)\n    \n    audio_data = response.stream_memory.getbuffer()\n    \n    with open(\"output.wav\", \"wb\") as file:\n        file.write(audio_data)\n\nasyncio.run(main())\n```\n\n### WebSocket API (Streaming TTS)\n\nFor real-time streaming text-to-speech:\n\n```python\nfrom deepgram import DeepgramClient, SpeakWebSocketEvents, SpeakWSOptions\n\n# Create client\nclient = DeepgramClient()\n\n# Create websocket connection\ndg_connection = client.speak.websocket.v(\"1\")\n\ndef on_open(self, open, **kwargs):\n    print(f\"Connection opened: {open}\")\n\ndef on_binary_data(self, data, **kwargs):\n    print(\"Received audio data\")\n    # Process audio data here\n    with open(\"output.wav\", \"ab\") as f:\n        f.write(data)\n\ndef on_close(self, close, **kwargs):\n    print(f\"Connection closed: {close}\")\n\n# Register event handlers\ndg_connection.on(SpeakWebSocketEvents.Open, on_open)\ndg_connection.on(SpeakWebSocketEvents.AudioData, on_binary_data)\ndg_connection.on(SpeakWebSocketEvents.Close, on_close)\n\n# Configure TTS options\noptions = SpeakWSOptions(\n    model=\"aura-2-thalia-en\",\n    encoding=\"linear16\",\n    sample_rate=16000\n)\n\n# Start the connection\nif dg_connection.start(options) is False:\n    print(\"Failed to start connection\")\n    exit()\n\n# Send text to be converted to speech\ndg_connection.send_text(\"Hello, this is a text to speech example using Deepgram.\")\n\n# Flush the connection\ndg_connection.flush()\n\n# Wait for processing to complete\ndg_connection.wait_for_complete()\n\n# Close the connection\ndg_connection.finish()\n```\n\n## Text Intelligence\n\nAnalyze text for insights and intelligence:\n\n```python\nfrom deepgram import DeepgramClient, ReadOptions\n\nclient = DeepgramClient()\n\n# Configure read options\noptions = ReadOptions(\n    model=\"nova-3\",\n    language=\"en\"\n)\n\n# Process text for intelligence\nresponse = client.read.rest.v(\"1\").process(\n    text=\"The quick brown fox jumps over the lazy dog.\",\n    options=options\n)\n\nprint(response.results)\n```\n\n## Voice Agent\n\nConfigure a Voice Agent for conversational AI:\n\n```python\nfrom deepgram import DeepgramClient, SettingsOptions\n\nclient = DeepgramClient()\n\n# Create websocket connection\nconnection = client.agent.websocket.v(\"1\")\n\n# Configure agent settings\noptions = SettingsOptions()\noptions.language = \"en\"\noptions.agent.think.provider.type = \"open_ai\"\noptions.agent.think.provider.model = \"gpt-4o-mini\"\noptions.agent.think.prompt = \"You are a helpful AI assistant.\"\noptions.agent.listen.provider.type = \"deepgram\"\noptions.agent.listen.provider.model = \"nova-3\"\noptions.agent.speak.provider.type = \"deepgram\"\noptions.agent.speak.provider.model = \"aura-2-thalia-en\"\n\noptions.greeting = \"Hello, I'm your AI assistant.\"\n\n# Start the connection\nconnection.start(options)\n\n# Close the connection\nconnection.finish()\n```\n\n## Captions Generation\n\nConvert transcription results to captions:\n\n### WebVTT\n```python\nfrom deepgram_captions import DeepgramConverter, webvtt\n\ntranscription = DeepgramConverter(dg_response)\ncaptions = webvtt(transcription)\n```\n\n### SRT\n```python\nfrom deepgram_captions import DeepgramConverter, srt\n\ntranscription = DeepgramConverter(dg_response)\ncaptions = srt(transcription)\n```\n\n## Error Handling\n\nAlways implement proper error handling:\n\n```python\nfrom deepgram import DeepgramClient\nfrom deepgram.errors import DeepgramError\n\ntry:\n    client = DeepgramClient()\n    response = client.listen.rest.v(\"1\").transcribe_url(url_source, options)\n    print(response.results.channels[0].alternatives[0].transcript)\nexcept DeepgramError as e:\n    print(f\"Deepgram Error: {e}\")\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n## Advanced Configuration\n\n### Client Options\n\nConfigure advanced client settings:\n\n```python\nfrom deepgram import DeepgramClient, DeepgramClientOptions\nfrom deepgram.utils import verboselogs\n\nconfig = DeepgramClientOptions(\n    options={\n        \"auto_flush_speak_delta\": \"500\",  # Auto-flush after 500ms\n        \"speaker_playback\": \"true\"        # Auto-play audio\n    },\n    verbose=verboselogs.DEBUG\n)\n\nclient = DeepgramClient(\"\", config)\n```\n\n### Integration Example\n\nCombine Speech-to-Text and Text-to-Speech:\n\n```python\nfrom deepgram import DeepgramClient, SpeakOptions, PrerecordedOptions\n\nclient = DeepgramClient()\n\n# Text to convert to speech\ntext = \"Hello, world.\"\n\n# Configure TTS options\ntts_options = SpeakOptions(\n    model=\"aura-2-thalia-en\", \n    encoding=\"linear16\", \n    sample_rate=24000\n)\n\n# Convert text to speech\ntts_response = client.speak.rest.v(\"1\").stream_memory({\"text\": text}, tts_options)\n\n# Save the audio to a buffer\naudio_buffer = tts_response.stream_memory.getbuffer()\n\n# Configure STT options\nstt_options = PrerecordedOptions(\n    model=\"nova-3\",\n    smart_format=True\n)\n\n# Transcribe the generated audio\nstt_response = client.listen.rest.v(\"1\").transcribe_file(\n    {\"buffer\": audio_buffer}, \n    stt_options\n)\n\n# Verify the transcription matches the original text\ntranscript = stt_response.results.channels[0].alternatives[0].transcript\nprint(f\"Original: {text}\")\nprint(f\"Transcribed: {transcript}\")\n```\n\n## Requirements\n\n- Python 3.10 or higher\n- `deepgram-sdk` package\n\n## Useful Links\n\n- Documentation: https://developers.deepgram.com/docs\n- Python SDK Repository: https://github.com/deepgram/deepgram-python-sdk\n- API Reference: https://developers.deepgram.com/reference\n- Discord Community: https://discord.gg/xWRaCDBtW4\n\n## Notes\n\nThis SDK provides comprehensive support for all Deepgram APIs including Speech-to-Text (both pre-recorded and streaming), Text-to-Speech (both REST and WebSocket), Text Intelligence, and Voice Agent functionality. <cite/> The SDK follows semantic versioning and maintains backward compatibility within major versions. For development and testing, the repository includes both daily tests (against real API endpoints) and unit tests (against mock endpoints).\n\nWiki pages you might want to explore:\n- [Text-to-Speech API (deepgram/deepgram-python-sdk)](/wiki/deepgram/deepgram-python-sdk#3)\n\n### Citations\n\n## Requirements\n\n[Python](https://www.python.org/downloads/) (version ^3.10)\n\n```python\nfrom deepgram_captions import DeepgramConverter, webvtt\n\ntranscription = DeepgramConverter(dg_response)\ncaptions = webvtt(transcription)\n```\n\n### SRT\n\n```python\nfrom deepgram_captions import DeepgramConverter, srt\n\ntranscription = DeepgramConverter(dg_response)\ncaptions = srt(transcription)\n```\n\n[See our stand alone captions library for more information.](https://github.com/deepgram/deepgram-python-captions).\n```\n\n```python\nfrom deepgram import (\n    SettingsOptions\n)\n\n# Create websocket connection\nconnection = deepgram.agent.websocket.v(\"1\")\n\n# Configure agent settings\noptions = SettingsOptions()\noptions.language = \"en\"\noptions.agent.think.provider.type = \"open_ai\"\noptions.agent.think.provider.model = \"gpt-4o-mini\"\noptions.agent.think.prompt = \"You are a helpful AI assistant.\"\noptions.agent.listen.provider.type = \"deepgram\"\noptions.agent.listen.provider.model = \"nova-3\"\noptions.agent.speak.provider.type = \"deepgram\"\noptions.agent.speak.provider.model =\"aura-2-thalia-en\"\n\noptions.greeting = \"Hello, I'm your AI assistant.\"\n\n# Start the connection\nconnection.start(options)\n\n# Close the connection\nconnection.finish()\n```\n```\n\n```python\nfrom deepgram import ReadOptions\n\n# Configure read options\noptions = ReadOptions(\n    model=\"nova-3\",\n    language=\"en\"\n)\n\n# Process text for intelligence\nresponse = deepgram.read.rest.v(\"1\").process(\n    text=\"The quick brown fox jumps over the lazy dog.\",\n    options=options\n)\n```\n```\n\nThe Deepgram Python SDK supports multiple authentication methods to provide flexibility and enhanced security for your applications.\n\n### Authentication Methods\n\n#### API Key Authentication (Traditional)\n\nThe traditional method using your Deepgram API key:\n\n```python\nfrom deepgram import DeepgramClient\n\n# Direct API key\nclient = DeepgramClient(api_key=\"YOUR_API_KEY\")\n\n# Or using environment variable DEEPGRAM_API_KEY\nclient = DeepgramClient()  # Auto-detects from environment\n```\n\n#### Bearer Token Authentication (OAuth 2.0)\n\nUse short-lived access tokens for enhanced security:\n\n```python\nfrom deepgram import DeepgramClient\n\n# Direct access token\nclient = DeepgramClient(access_token=\"YOUR_ACCESS_TOKEN\")\n\n# Or using environment variable DEEPGRAM_ACCESS_TOKEN\nclient = DeepgramClient()  # Auto-detects from environment\n```\n```\n\nIf you are looking to use, run, contribute or modify to the daily/unit tests, then you need to install the following dependencies:\n\n```bash\npip install -r requirements-dev.txt\n```\n\n### Daily Tests\n\nThe daily tests invoke a series of checks against the actual/real API endpoint and save the results in the `tests/response_data` folder. This response data is updated nightly to reflect the latest response from the server. Running the daily tests does require a `DEEPGRAM_API_KEY` set in your environment variables.\n\nTo run the Daily Tests:\n\n```bash\nmake daily-test\n```\n\n#### Unit Tests\n\nThe unit tests invoke a series of checks against mock endpoints using the responses saved in `tests/response_data` from the daily tests. These tests are meant to simulate running against the endpoint without actually reaching out to the endpoint; running the unit tests does require a `DEEPGRAM_API_KEY` set in your environment variables, but you will not actually reach out to the server.\n\n```bash\nmake unit-test\n```\n```\n\n## Backwards Compatibility\n\nWe follow semantic versioning (semver) to ensure a smooth upgrade experience. Within a major version (like `4.*`), we will maintain backward compatibility so your code will continue to work without breaking changes. When we release a new major version (like moving from `3.*` to `4.*`), we may introduce breaking changes to improve the SDK. We'll always document these changes clearly in our release notes to help you upgrade smoothly.\n\nOlder SDK versions will receive Priority 1 (P1) bug support only. Security issues, both in our code and dependencies, are promptly addressed. Significant bugs without clear workarounds are also given priority attention.\n```\n\n```python\nfrom deepgram import DeepgramClient, SpeakOptions, PrerecordedOptions, FileSource\n\nfrom tests.utils import save_metadata_string\n\nTTS_MODEL = \"aura-2-thalia-en\"\nSTT_MODEL = \"general-nova-3\"\n\n# response constants\nTEXT1 = \"Hello, world.\"\n\n# Create a list of tuples to store the key-value pairs\ninput_output = [\n    (\n        TEXT1,\n        SpeakOptions(model=TTS_MODEL, encoding=\"linear16\", sample_rate=24000),\n        PrerecordedOptions(model=\"nova-3\", smart_format=True),\n        {\"results.channels.0.alternatives.0.transcript\": [TEXT1]},\n    ),\n]\n```\n\n```python\nfrom deepgram import DeepgramClient, SpeakOptions, PrerecordedOptions, FileSource\n\nfrom tests.utils import read_metadata_string, save_metadata_string\n\nMODEL = \"aura-2-thalia-en\"\n\n# response constants\nTEXT1 = \"Hello, world.\"\n\n# Create a list of tuples to store the key-value pairs\ninput_output = [\n    (\n        TEXT1,\n        SpeakOptions(model=MODEL, encoding=\"linear16\", sample_rate=24000),\n        {\n            \"content_type\": [\"audio/wav\"],\n            \"model_name\": [\"aura-2-thalia-en\"],\n            \"characters\": [\"13\"],\n        },\n    ),\n]\n```\ncture "
  },
  {
    "path": "content/deepl/docs/translation/javascript/DOC.md",
    "content": "---\nname: translation\ndescription: \"DeepL API client for JavaScript/TypeScript with text and document translation, glossary management, and language detection\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.21.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"deepl,translation,language,localization,api\"\n---\n\n# DeepL API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a DeepL API coding expert. Help me with writing code using the DeepL API calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official DeepL Node.js SDK for all DeepL API interactions. Do not use unofficial or deprecated libraries.\n\n- **Library Name:** DeepL Node.js Client Library\n- **NPM Package:** `deepl-node`\n- **Current Version:** 1.21.0\n- **Deprecated/Unofficial Packages:** `deepl`, `deepl-api`, `deepl-translate`\n\n**Installation:**\n\n```bash\n# Correct\nnpm install deepl-node\n\n# Incorrect - unofficial packages\nnpm install deepl\nnpm install deepl-api\n```\n\n**Import Patterns:**\n\n```javascript\n// Correct - ES6 import\nimport * as deepl from 'deepl-node';\n\n// Correct - CommonJS\nconst deepl = require('deepl-node');\n\n// Incorrect\nimport DeepL from 'deepl';\nimport { translate } from 'deepl-api';\n```\n\n## Initialization and API Key\n\nThe DeepL library requires creating a `DeepLClient` instance with your authentication key for all API calls.\n\n### Getting an API Key\n\nCreate a DeepL API account to receive your authentication key. With a DeepL API Free account, you can translate up to 500,000 characters per month for free.\n\n### Basic Initialization\n\n```javascript\nimport * as deepl from 'deepl-node';\n\n// Initialize with API key\nconst authKey = 'your-api-key-here'; // Replace with your actual key\nconst translator = new deepl.DeepLClient(authKey);\n```\n\n### Environment Variable Configuration\n\nIn production, always fetch the authentication key from environment variables:\n\n```javascript\nimport * as deepl from 'deepl-node';\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n```\n\n### CommonJS Initialization\n\n```javascript\nconst deepl = require('deepl-node');\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n```\n\n## Text Translation\n\n### Basic Translation\n\nTranslate a single text string from one language to another:\n\n```javascript\nimport * as deepl from 'deepl-node';\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n\nconst result = await translator.translateText('Hello, world!', null, 'fr');\nconsole.log(result.text); // 'Bonjour, le monde !'\n```\n\nThe `translateText` method signature:\n- First parameter: text to translate (string or array of strings)\n- Second parameter: source language (null for auto-detection, or language code like 'en')\n- Third parameter: target language (required, e.g., 'fr', 'de', 'es')\n- Fourth parameter (optional): options object\n\n### Auto-Detection of Source Language\n\nUse `null` as the source language to automatically detect it:\n\n```javascript\nconst result = await translator.translateText('Hello, world!', null, 'de');\nconsole.log(result.text); // 'Hallo, Welt!'\nconsole.log(result.detectedSourceLang); // 'EN'\n```\n\n### Specifying Source Language\n\n```javascript\nconst result = await translator.translateText('Hello, world!', 'en', 'es');\nconsole.log(result.text); // '¡Hola, mundo!'\n```\n\n### Multiple Texts Translation\n\nTranslate multiple texts in a single API call:\n\n```javascript\nconst texts = [\n  'Hello, world!',\n  'How are you?',\n  'Good morning'\n];\n\nconst results = await translator.translateText(texts, null, 'ja');\nresults.forEach(result => {\n  console.log(result.text);\n});\n// 'こんにちは、世界！'\n// 'お元気ですか？'\n// 'おはようございます'\n```\n\n### TextResult Properties\n\nEach translation result contains:\n\n```javascript\nconst result = await translator.translateText('Hello', null, 'de');\n\nconsole.log(result.text);                    // Translated text: 'Hallo'\nconsole.log(result.detectedSourceLang);      // Source language: 'EN'\nconsole.log(result.billedCharacters);        // Characters charged\nconsole.log(result.modelTypeUsed);           // Model type if specified\n```\n\n## Translation Options\n\n### Formality Control\n\nControl the formality level of translations for supported languages (DE, FR, IT, ES, NL, PL, PT-BR, PT-PT, JA, RU):\n\n```javascript\n// Informal translation\nconst informal = await translator.translateText(\n  'How are you?',\n  null,\n  'de',\n  { formality: 'less' }\n);\nconsole.log(informal.text); // 'Wie geht es dir?'\n\n// Formal translation\nconst formal = await translator.translateText(\n  'How are you?',\n  null,\n  'de',\n  { formality: 'more' }\n);\nconsole.log(formal.text); // 'Wie geht es Ihnen?'\n```\n\nFormality options:\n- `'less'` - informal language\n- `'more'` - formal language\n- `'default'` - standard formality\n- `'prefer_less'` - informal if available, otherwise default\n- `'prefer_more'` - formal if available, otherwise default\n\n### Context Parameter\n\nProvide additional context to improve translation accuracy (not translated, not billed):\n\n```javascript\nconst result = await translator.translateText(\n  'bank',\n  'en',\n  'de',\n  { context: 'financial institution' }\n);\nconsole.log(result.text); // 'Bank' (financial context)\n\nconst result2 = await translator.translateText(\n  'bank',\n  'en',\n  'de',\n  { context: 'riverside' }\n);\nconsole.log(result2.text); // 'Ufer' (riverbank)\n```\n\n### Sentence Splitting Options\n\nControl how text is split into sentences:\n\n```javascript\n// Split by newlines and punctuation (default)\nconst result1 = await translator.translateText(\n  'First sentence. Second sentence.',\n  null,\n  'de',\n  { splitSentences: 'on' }\n);\n\n// No splitting\nconst result2 = await translator.translateText(\n  'First sentence. Second sentence.',\n  null,\n  'de',\n  { splitSentences: 'off' }\n);\n\n// Split by punctuation only (not newlines)\nconst result3 = await translator.translateText(\n  'First sentence.\\nSecond sentence.',\n  null,\n  'de',\n  { splitSentences: 'nonewlines' }\n);\n```\n\n### Preserve Formatting\n\nPrevent automatic format correction:\n\n```javascript\nconst result = await translator.translateText(\n  'Hello,    world!',\n  null,\n  'de',\n  { preserveFormatting: true }\n);\n// Preserves extra spaces\n```\n\n### Model Type Selection\n\nChoose between quality-optimized and latency-optimized models:\n\n```javascript\n// Quality-optimized (higher quality, slower)\nconst qualityResult = await translator.translateText(\n  'Complex technical document',\n  'en',\n  'de',\n  { modelType: 'quality_optimized' }\n);\n\n// Latency-optimized (faster, still high quality)\nconst fastResult = await translator.translateText(\n  'Simple message',\n  'en',\n  'de',\n  { modelType: 'latency_optimized' }\n);\n\n// Use best available\nconst result = await translator.translateText(\n  'Text here',\n  'en',\n  'de',\n  { modelType: 'prefer_quality_optimized' }\n);\n```\n\n### HTML and XML Tag Handling\n\nParse and preserve markup tags:\n\n```javascript\n// HTML tag handling\nconst htmlResult = await translator.translateText(\n  '<p>Hello, <strong>world</strong>!</p>',\n  null,\n  'de',\n  { tagHandling: 'html' }\n);\nconsole.log(htmlResult.text); // '<p>Hallo, <strong>Welt</strong>!</p>'\n\n// XML tag handling\nconst xmlResult = await translator.translateText(\n  '<text>Hello, <emphasis>world</emphasis>!</text>',\n  null,\n  'de',\n  { tagHandling: 'xml' }\n);\n```\n\n### XML-Specific Options\n\nAdvanced XML handling options:\n\n```javascript\nconst result = await translator.translateText(\n  '<root><p>First paragraph</p><ignore>Do not translate</ignore></root>',\n  'en',\n  'de',\n  {\n    tagHandling: 'xml',\n    outlineDetection: false,           // Disable automatic tag detection\n    splittingTags: ['p', 'div'],       // Tags that split sentences\n    nonSplittingTags: ['span'],        // Tags that don't split sentences\n    ignoreTags: ['ignore', 'code']     // Tags with untranslated content\n  }\n);\n```\n\n## Document Translation\n\n### Basic Document Translation\n\nTranslate entire documents while preserving formatting:\n\n```javascript\nimport * as deepl from 'deepl-node';\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n\n// Translate document from file path to file path\nawait translator.translateDocument(\n  'input.docx',\n  'output.docx',\n  'en',\n  'de'\n);\n```\n\n### Document Translation with Options\n\n```javascript\nawait translator.translateDocument(\n  'Manual.docx',\n  'Anleitung.docx',\n  'en',\n  'de',\n  {\n    formality: 'more',\n    glossary: 'glossary-id-here'\n  }\n);\n```\n\n### Supported Document Formats\n\nDeepL supports various document formats:\n- **Text documents:** docx, pptx, pdf, htm, html, txt\n- **Spreadsheets:** xlsx\n- **Others:** Check DeepL API documentation for complete list\n\n### Document Translation Input/Output Formats\n\nDocuments can be provided as:\n- File paths (strings)\n- Streams or FileHandles\n- Buffers (requires `filename` option)\n\n```javascript\n// Using file paths\nawait translator.translateDocument(\n  'input.pdf',\n  'output.pdf',\n  'en',\n  'fr'\n);\n\n// Using streams\nimport * as fs from 'fs';\n\nconst inputStream = fs.createReadStream('input.docx');\nconst outputStream = fs.createWriteStream('output.docx');\n\nawait translator.translateDocument(\n  inputStream,\n  outputStream,\n  'en',\n  'de',\n  { filename: 'input.docx' }\n);\n\n// Using buffer\nconst buffer = fs.readFileSync('input.docx');\nawait translator.translateDocument(\n  buffer,\n  'output.docx',\n  'en',\n  'es',\n  { filename: 'document.docx' }\n);\n```\n\n### Document Minification\n\nReduce document size by compressing embedded media (supports docx, pptx):\n\n```javascript\nawait translator.translateDocument(\n  'large_presentation.pptx',\n  'output.pptx',\n  'en',\n  'de',\n  { enableDocumentMinification: true }\n);\n```\n\nSupported media types for minification: png, jpg, jpeg, emf, bmp, tiff, wdp, svg, gif, mp4, asf, avi, m4v, mpg, mpeg, wmv, mov, aiff, au, mid, midi, mp3, m4a, wav, wma\n\n**Note:** Requires 2x file size temporary disk space.\n\n### Document Translation Error Handling\n\nHandle errors and retrieve document handle for recovery:\n\n```javascript\ntry {\n  await translator.translateDocument(\n    'Manual.docx',\n    'Anleitung.docx',\n    'en',\n    'de'\n  );\n} catch (error) {\n  if (error.documentHandle) {\n    const { documentId, documentKey } = error.documentHandle;\n    console.log(`Document ID: ${documentId}`);\n    console.log(`Document Key: ${documentKey}`);\n    // Use these to check status or download later\n  } else {\n    console.error('Translation failed:', error.message);\n  }\n}\n```\n\n### Lower-Level Document Translation Methods\n\nFor advanced control over the document translation process:\n\n```javascript\n// Upload document\nconst handle = await translator.uploadDocument(\n  'input.docx',\n  'en',\n  'de'\n);\n\n// Check translation status\nconst status = await translator.getDocumentStatus(handle);\nconsole.log(`Status: ${status.status}`);\nconsole.log(`Billed characters: ${status.billedCharacters}`);\n\n// Wait until translation is complete\nawait translator.isDocumentTranslationComplete(handle);\n\n// Download translated document\nawait translator.downloadDocument(handle, 'output.docx');\n```\n\n### Polling Document Status\n\n```javascript\nconst handle = await translator.uploadDocument('input.pdf', 'en', 'fr');\n\n// Poll until complete\nwhile (true) {\n  const status = await translator.getDocumentStatus(handle);\n\n  if (status.status === 'done') {\n    await translator.downloadDocument(handle, 'output.pdf');\n    break;\n  } else if (status.status === 'error') {\n    throw new Error('Document translation failed');\n  }\n\n  // Wait before checking again\n  await new Promise(resolve => setTimeout(resolve, 5000));\n}\n```\n\n## Glossaries\n\nGlossaries allow you to specify custom translations for specific terms and phrases.\n\n### Creating Multilingual Glossaries\n\n```javascript\nimport * as deepl from 'deepl-node';\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n\n// Create glossary entries\nconst entries = new deepl.GlossaryEntries({\n  entries: {\n    'artist': 'Maler',\n    'prize': 'Gewinn'\n  }\n});\n\n// Create glossary\nconst glossary = await translator.createMultilingualGlossary(\n  'My glossary',\n  [{\n    sourceLangCode: 'en',\n    targetLangCode: 'de',\n    entries: entries\n  }]\n);\n\nconsole.log(`Glossary ID: ${glossary.glossaryId}`);\nconsole.log(`Created: ${glossary.creationTime}`);\n```\n\n### Creating Glossary from CSV\n\n```javascript\nconst fs = require('fs').promises;\n\n// Read CSV file\nconst csvContent = await fs.readFile('glossary.csv', 'utf-8');\n\n// CSV format:\n// source,target\n// artist,Maler\n// prize,Gewinn\n\nconst glossary = await translator.createMultilingualGlossaryWithCsv(\n  'CSV Glossary',\n  'en',\n  'de',\n  csvContent\n);\n```\n\n### Listing Glossaries\n\n```javascript\nconst glossaries = await translator.listMultilingualGlossaries();\n\nglossaries.forEach(g => {\n  console.log(`Name: ${g.name}`);\n  console.log(`ID: ${g.glossaryId}`);\n  console.log(`Created: ${g.creationTime}`);\n\n  g.dictionaries.forEach(dict => {\n    console.log(`  ${dict.sourceLang} -> ${dict.targetLang}: ${dict.entryCount} entries`);\n  });\n});\n```\n\n### Finding Specific Glossary\n\n```javascript\nconst glossaries = await translator.listMultilingualGlossaries();\nconst myGlossary = glossaries.find(g => g.name === 'My glossary');\n\nif (myGlossary) {\n  console.log(`Found glossary: ${myGlossary.glossaryId}`);\n}\n```\n\n### Using Glossaries in Translation\n\n```javascript\n// Using glossary ID\nconst result = await translator.translateText(\n  'The artist won the prize',\n  'en',\n  'de',\n  { glossary: 'glossary-id-here' }\n);\n\n// Using glossary object\nconst glossaries = await translator.listMultilingualGlossaries();\nconst myGlossary = glossaries[0];\n\nconst result2 = await translator.translateText(\n  'The artist won the prize',\n  'en',\n  'de',\n  { glossary: myGlossary }\n);\n\nconsole.log(result2.text); // Uses custom translations from glossary\n```\n\n### Deleting Glossaries\n\n```javascript\n// Delete by glossary object\nconst glossaries = await translator.listMultilingualGlossaries();\nconst glossaryToDelete = glossaries.find(g => g.name === 'Old glossary');\nawait translator.deleteMultilingualGlossary(glossaryToDelete.glossaryId);\n\n// Delete by ID\nawait translator.deleteMultilingualGlossary('glossary-id-here');\n```\n\n### Glossary Supported Languages\n\nCheck which language pairs support glossaries:\n\n```javascript\nconst glossaryLanguages = await translator.getGlossaryLanguages();\n\nglossaryLanguages.forEach(langPair => {\n  console.log(`${langPair.sourceLang} -> ${langPair.targetLang}`);\n});\n```\n\n## Language Detection and Information\n\n### Detecting Language\n\nDetect the language of a text without translating:\n\n```javascript\nconst detectedLang = await translator.detectLanguage('Bonjour, comment allez-vous?');\nconsole.log(detectedLang); // 'fr'\n\n// Detect from array of texts\nconst texts = ['Hello', 'Bonjour', 'Hola'];\nconst languages = await translator.detectLanguage(texts);\nlanguages.forEach((lang, i) => {\n  console.log(`\"${texts[i]}\" is ${lang}`);\n});\n// \"Hello\" is en\n// \"Bonjour\" is fr\n// \"Hola\" is es\n```\n\n### Getting Supported Languages\n\n```javascript\n// Get all target languages\nconst targetLanguages = await translator.getTargetLanguages();\ntargetLanguages.forEach(lang => {\n  console.log(`${lang.code}: ${lang.name}`);\n  if (lang.supportsFormality) {\n    console.log('  Supports formality');\n  }\n});\n\n// Get all source languages\nconst sourceLanguages = await translator.getSourceLanguages();\nsourceLanguages.forEach(lang => {\n  console.log(`${lang.code}: ${lang.name}`);\n});\n```\n\nLanguage object properties:\n- `code` - ISO 639-1 language code (e.g., 'en', 'de', 'fr')\n- `name` - Display name (e.g., 'English', 'German', 'French')\n- `supportsFormality` - Boolean (target languages only)\n\n## Usage Monitoring\n\n### Checking Account Usage\n\nMonitor your character usage and account limits:\n\n```javascript\nconst usage = await translator.getUsage();\n\nconsole.log(`Characters used: ${usage.character.count}`);\nconsole.log(`Character limit: ${usage.character.limit}`);\nconsole.log(`Document count: ${usage.document.count}`);\nconsole.log(`Document limit: ${usage.document.limit}`);\n\n// Calculate remaining characters\nconst remaining = usage.character.limit - usage.character.count;\nconsole.log(`Remaining characters: ${remaining}`);\n```\n\n### Account Tiers\n\n- **DeepL API Free:** 500,000 characters/month, up to 2 active API keys\n- **DeepL API Pro:** Pay-as-you-go, up to 25 active API keys, cost control limits\n\n## Error Handling\n\n### Common Error Patterns\n\n```javascript\ntry {\n  const result = await translator.translateText('Hello', null, 'de');\n  console.log(result.text);\n} catch (error) {\n  if (error.code === 403) {\n    console.error('Authentication failed. Check your API key.');\n  } else if (error.code === 456) {\n    console.error('Quota exceeded. Monthly character limit reached.');\n  } else if (error.code === 400) {\n    console.error('Bad request. Check parameters.');\n  } else {\n    console.error('Translation error:', error.message);\n  }\n}\n```\n\n### Document Translation Errors\n\n```javascript\ntry {\n  await translator.translateDocument('in.docx', 'out.docx', 'en', 'de');\n} catch (error) {\n  if (error.documentHandle) {\n    // Document was uploaded but translation failed\n    const { documentId, documentKey } = error.documentHandle;\n    console.log('Can retry with document ID:', documentId);\n  } else {\n    // Upload or other error\n    console.error('Error:', error.message);\n  }\n}\n```\n\n## TypeScript Support\n\nThe deepl-node library includes full TypeScript type definitions:\n\n```typescript\nimport * as deepl from 'deepl-node';\n\nconst authKey: string = process.env.DEEPL_AUTH_KEY!;\nconst translator: deepl.DeepLClient = new deepl.DeepLClient(authKey);\n\nasync function translateText() {\n  const targetLang: deepl.TargetLanguageCode = 'de';\n  const result: deepl.TextResult = await translator.translateText(\n    'Hello, world!',\n    null,\n    targetLang\n  );\n\n  console.log(result.text);\n  console.log(result.detectedSourceLang);\n}\n\ntranslateText();\n```\n\n### Type Definitions\n\n```typescript\n// Language codes\ntype SourceLanguageCode = 'en' | 'de' | 'fr' | 'es' | 'it' | 'ja' | 'ko' | ...;\ntype TargetLanguageCode = 'en-US' | 'en-GB' | 'de' | 'fr' | 'es' | ...;\n\n// Formality options\ntype Formality = 'less' | 'more' | 'default' | 'prefer_less' | 'prefer_more';\n\n// Model types\ntype ModelType = 'quality_optimized' | 'latency_optimized' | 'prefer_quality_optimized';\n\n// Translation result\ninterface TextResult {\n  text: string;\n  detectedSourceLang: string;\n  billedCharacters?: number;\n  modelTypeUsed?: string;\n}\n```\n\n## Advanced Configuration\n\n### Custom Server URL\n\nFor DeepL API Pro plans with custom endpoints:\n\n```javascript\nconst translator = new deepl.DeepLClient(authKey, {\n  serverUrl: 'https://api.deepl.com'  // Pro endpoint\n  // or 'https://api-free.deepl.com' for Free endpoint\n});\n```\n\n### HTTP Options\n\nConfigure timeout and other HTTP options:\n\n```javascript\nconst translator = new deepl.DeepLClient(authKey, {\n  maxRetries: 5,\n  minTimeout: 10000  // 10 seconds\n});\n```\n\n## Promise Handling\n\nAll methods return Promises and support both async/await and .then()/.catch():\n\n```javascript\n// Async/await (recommended)\nasync function translate() {\n  const result = await translator.translateText('Hello', null, 'fr');\n  console.log(result.text);\n}\n\n// Promise chaining\ntranslator.translateText('Hello', null, 'fr')\n  .then(result => {\n    console.log(result.text);\n  })\n  .catch(error => {\n    console.error('Translation failed:', error);\n  });\n```\n\n## Complete Translation Example\n\n```javascript\nimport * as deepl from 'deepl-node';\n\nconst authKey = process.env.DEEPL_AUTH_KEY;\nconst translator = new deepl.DeepLClient(authKey);\n\nasync function completeExample() {\n  try {\n    // 1. Check usage\n    const usage = await translator.getUsage();\n    console.log(`Remaining: ${usage.character.limit - usage.character.count} characters`);\n\n    // 2. Get supported languages\n    const targetLangs = await translator.getTargetLanguages();\n    const germanLang = targetLangs.find(l => l.code === 'de');\n    console.log(`German supports formality: ${germanLang.supportsFormality}`);\n\n    // 3. Translate with options\n    const result = await translator.translateText(\n      'How are you doing today?',\n      null,\n      'de',\n      { formality: 'more' }\n    );\n    console.log(`Translation: ${result.text}`);\n    console.log(`Detected source: ${result.detectedSourceLang}`);\n\n    // 4. Translate document\n    await translator.translateDocument(\n      'document.pdf',\n      'dokument.pdf',\n      'en',\n      'de',\n      { formality: 'more' }\n    );\n\n    console.log('Translation complete!');\n  } catch (error) {\n    console.error('Error:', error.message);\n  }\n}\n\ncompleteExample();\n```\n\n## Node.js Version Support\n\nThe deepl-node package supports Node.js versions 12, 14, 16, 17, 18, 20, 22, and 24.\n\n## Additional Resources\n\n- Official Documentation: https://www.deepl.com/docs-api/\n- GitHub Repository: https://github.com/DeepLcom/deepl-node\n- NPM Package: https://www.npmjs.com/package/deepl-node\n"
  },
  {
    "path": "content/deepl/docs/translation/python/DOC.md",
    "content": "---\nname: translation\ndescription: \"DeepL API client for Python with text and document translation, glossary management, and language detection\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.23.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"deepl,translation,language,localization,api\"\n---\n\n# DeepL API Coding Guidelines (Python)\n\nYou are a DeepL API coding expert. Help me with writing code using the DeepL API calling the official Python SDK.\n\nYou can find the official SDK documentation and code samples here:\nhttps://www.deepl.com/docs-api/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official DeepL Python SDK to call the DeepL API, which is the standard library for all DeepL API interactions.\n\n**Library Name:** DeepL Python SDK\n**PyPI Package:** `deepl`\n**Current Version:** 1.23.0\n\n**Installation:**\n- **Correct:** `pip install deepl`\n- **Incorrect:** `pip install pydeepl`, `pip install deepl-api`, `pip install deepl.py`\n\n**APIs and Usage:**\n- **Correct:** `import deepl`\n- **Correct:** `translator = deepl.DeepLClient(auth_key)`\n- **Incorrect:** `from deepl import Translator` (old API)\n- **Incorrect:** `import pydeepl`\n\n## Initialization and API Key\n\nSet the `DEEPL_AUTH_KEY` environment variable or pass the API key directly.\n\n```python\nimport deepl\n\n# Using environment variable\nimport os\nauth_key = os.environ.get('DEEPL_AUTH_KEY')\ntranslator = deepl.DeepLClient(auth_key)\n\n# Or pass API key directly (not recommended for production)\n# translator = deepl.DeepLClient(\"your-api-key-here\")\n```\n\n### Getting an API Key\n\nCreate a DeepL API account to receive your authentication key. With a DeepL API Free account, you can translate up to 500,000 characters per month for free.\n\n## Text Translation\n\n### Basic Translation\n\nTranslate a single text string:\n\n```python\nimport deepl\n\nauth_key = os.environ.get('DEEPL_AUTH_KEY')\ntranslator = deepl.DeepLClient(auth_key)\n\nresult = translator.translate_text(\"Hello, world!\", target_lang=\"FR\")\nprint(result.text)  # \"Bonjour, le monde !\"\n```\n\nThe `translate_text` method:\n- First parameter: text to translate (string or list of strings)\n- `target_lang` parameter: target language code (required)\n- `source_lang` parameter: source language code (optional, auto-detects if not specified)\n\n### Auto-Detection of Source Language\n\n```python\nresult = translator.translate_text(\"Hello, world!\", target_lang=\"DE\")\nprint(result.text)  # \"Hallo, Welt!\"\nprint(result.detected_source_lang)  # \"EN\"\n```\n\n### Specifying Source Language\n\n```python\nresult = translator.translate_text(\n    \"Hello, world!\",\n    source_lang=\"EN\",\n    target_lang=\"ES\"\n)\nprint(result.text)  # \"¡Hola, mundo!\"\n```\n\n### Multiple Texts Translation\n\nTranslate multiple texts in a single API call:\n\n```python\ntexts = [\n    \"Hello, world!\",\n    \"How are you?\",\n    \"Good morning\"\n]\n\nresults = translator.translate_text(texts, target_lang=\"JA\")\nfor result in results:\n    print(result.text)\n# こんにちは、世界！\n# お元気ですか？\n# おはようございます\n```\n\n### TextResult Properties\n\nEach translation result contains:\n\n```python\nresult = translator.translate_text(\"Hello\", target_lang=\"DE\")\n\nprint(result.text)                    # Translated text: \"Hallo\"\nprint(result.detected_source_lang)    # Source language: \"EN\"\nprint(result.billed_characters)       # Characters charged\nprint(result.model_type_used)         # Model type if specified\n```\n\n## Translation Options\n\n### Formality Control\n\nControl the formality level of translations for supported languages (DE, FR, IT, ES, NL, PL, PT-BR, PT-PT, JA, RU):\n\n```python\n# Informal translation\ninformal = translator.translate_text(\n    \"How are you?\",\n    target_lang=\"DE\",\n    formality=\"less\"\n)\nprint(informal.text)  # \"Wie geht es dir?\"\n\n# Formal translation\nformal = translator.translate_text(\n    \"How are you?\",\n    target_lang=\"DE\",\n    formality=\"more\"\n)\nprint(formal.text)  # \"Wie geht es Ihnen?\"\n```\n\nFormality options:\n- `\"less\"` - informal language\n- `\"more\"` - formal language\n- `\"default\"` - standard formality\n- `\"prefer_less\"` - informal if available, otherwise default\n- `\"prefer_more\"` - formal if available, otherwise default\n\n### Context Parameter\n\nProvide additional context to improve translation accuracy (not translated, not billed):\n\n```python\nresult = translator.translate_text(\n    \"bank\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    context=\"financial institution\"\n)\nprint(result.text)  # \"Bank\" (financial context)\n\nresult2 = translator.translate_text(\n    \"bank\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    context=\"riverside\"\n)\nprint(result2.text)  # \"Ufer\" (riverbank)\n```\n\n### Model Type Selection\n\nChoose between quality-optimized and latency-optimized models:\n\n```python\n# Quality-optimized (higher quality, slower)\nquality_result = translator.translate_text(\n    \"Complex technical document\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    model_type=\"quality_optimized\"\n)\n\n# Latency-optimized (faster, still high quality)\nfast_result = translator.translate_text(\n    \"Simple message\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    model_type=\"latency_optimized\"\n)\n```\n\n### Split Sentences Option\n\nControl how text is split into sentences:\n\n```python\n# Split by newlines and punctuation (default)\nresult1 = translator.translate_text(\n    \"First sentence. Second sentence.\",\n    target_lang=\"DE\",\n    split_sentences=\"1\"\n)\n\n# No splitting\nresult2 = translator.translate_text(\n    \"First sentence. Second sentence.\",\n    target_lang=\"DE\",\n    split_sentences=\"0\"\n)\n\n# Split by punctuation only (not newlines)\nresult3 = translator.translate_text(\n    \"First sentence.\\nSecond sentence.\",\n    target_lang=\"DE\",\n    split_sentences=\"nonewlines\"\n)\n```\n\n### Preserve Formatting\n\nPrevent automatic format correction:\n\n```python\nresult = translator.translate_text(\n    \"Hello,    world!\",\n    target_lang=\"DE\",\n    preserve_formatting=True\n)\n# Preserves extra spaces\n```\n\n### HTML and XML Tag Handling\n\nParse and preserve markup tags:\n\n```python\n# HTML tag handling\nhtml_result = translator.translate_text(\n    \"<p>Hello, <strong>world</strong>!</p>\",\n    target_lang=\"DE\",\n    tag_handling=\"html\"\n)\nprint(html_result.text)  # \"<p>Hallo, <strong>Welt</strong>!</p>\"\n\n# XML tag handling\nxml_result = translator.translate_text(\n    \"<text>Hello, <emphasis>world</emphasis>!</text>\",\n    target_lang=\"DE\",\n    tag_handling=\"xml\"\n)\n```\n\n### XML-Specific Options\n\nAdvanced XML handling options:\n\n```python\nresult = translator.translate_text(\n    \"<root><p>First paragraph</p><ignore>Do not translate</ignore></root>\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    tag_handling=\"xml\",\n    outline_detection=False,           # Disable automatic tag detection\n    splitting_tags=[\"p\", \"div\"],       # Tags that split sentences\n    non_splitting_tags=[\"span\"],       # Tags that don't split sentences\n    ignore_tags=[\"ignore\", \"code\"]     # Tags with untranslated content\n)\n```\n\n## Text Improvement (Write API)\n\nThe Write API allows you to rephrase and improve text quality.\n\n### Basic Text Rephrasing\n\n```python\nresult = translator.rephrase_text(\n    \"A rainbouw has seven colours.\",\n    target_lang=\"EN-US\"\n)\nprint(result.text)  # \"A rainbow has seven colors.\"\n```\n\n### Style Options\n\nApply different writing styles:\n\n```python\n# Business style\nresult = translator.rephrase_text(\n    \"Thanks for your email. I'll get back to you soon.\",\n    target_lang=\"EN\",\n    style=\"business\"\n)\n\n# Academic style\nresult = translator.rephrase_text(\n    \"This study shows that...\",\n    target_lang=\"EN\",\n    style=\"academic\"\n)\n\n# Casual style\nresult = translator.rephrase_text(\n    \"I am writing to inform you...\",\n    target_lang=\"EN\",\n    style=\"casual\"\n)\n\n# Simple style\nresult = translator.rephrase_text(\n    \"The implementation of the aforementioned protocol...\",\n    target_lang=\"EN\",\n    style=\"simple\"\n)\n```\n\nAvailable styles: `\"business\"`, `\"academic\"`, `\"casual\"`, `\"simple\"`, `\"default\"`\n\n### Tone Options\n\nApply different tones:\n\n```python\n# Friendly tone\nresult = translator.rephrase_text(\n    \"Please submit your report by Friday.\",\n    target_lang=\"EN\",\n    tone=\"friendly\"\n)\n\n# Confident tone\nresult = translator.rephrase_text(\n    \"I think this approach might work.\",\n    target_lang=\"EN\",\n    tone=\"confident\"\n)\n\n# Diplomatic tone\nresult = translator.rephrase_text(\n    \"This is wrong.\",\n    target_lang=\"EN\",\n    tone=\"diplomatic\"\n)\n\n# Enthusiastic tone\nresult = translator.rephrase_text(\n    \"This is a good result.\",\n    target_lang=\"EN\",\n    tone=\"enthusiastic\"\n)\n```\n\nAvailable tones: `\"friendly\"`, `\"confident\"`, `\"diplomatic\"`, `\"enthusiastic\"`, `\"default\"`\n\n### Optional Style/Tone Application\n\nUse `\"prefer_\"` prefix for optional application:\n\n```python\nresult = translator.rephrase_text(\n    \"The meeting is scheduled for tomorrow.\",\n    target_lang=\"EN\",\n    tone=\"prefer_diplomatic\"\n)\n# Applies diplomatic tone if suitable, otherwise uses default\n```\n\n## Document Translation\n\n### Basic Document Translation\n\nTranslate entire documents while preserving formatting:\n\n```python\nimport deepl\n\nauth_key = os.environ.get('DEEPL_AUTH_KEY')\ntranslator = deepl.DeepLClient(auth_key)\n\n# Using file paths\ntranslator.translate_document_from_filepath(\n    \"/path/to/input.docx\",\n    \"/path/to/output.docx\",\n    target_lang=\"DE\"\n)\n```\n\n### Document Translation with Options\n\n```python\ntranslator.translate_document_from_filepath(\n    \"Manual.pdf\",\n    \"Anleitung.pdf\",\n    target_lang=\"DE\",\n    formality=\"more\"\n)\n```\n\n### Using File Objects\n\n```python\nwith open(\"input.docx\", \"rb\") as in_file, \\\n     open(\"output.docx\", \"wb\") as out_file:\n    translator.translate_document(\n        in_file,\n        out_file,\n        target_lang=\"DE\",\n        formality=\"more\"\n    )\n```\n\n### Supported Document Formats\n\nDeepL supports various document formats:\n- **Text documents:** docx, pptx, pdf, htm, html, txt\n- **Spreadsheets:** xlsx\n- **Others:** Check DeepL API documentation for complete list\n\n### Document Translation Error Handling\n\nHandle errors and retrieve document handle for recovery:\n\n```python\ntry:\n    translator.translate_document_from_filepath(\n        \"input.pdf\",\n        \"output.pdf\",\n        target_lang=\"FR\"\n    )\nexcept deepl.DocumentTranslationException as error:\n    doc_id = error.document_handle.id\n    doc_key = error.document_handle.key\n    print(f\"Document ID: {doc_id}\")\n    print(f\"Document Key: {doc_key}\")\nexcept deepl.DeepLException as error:\n    print(f\"Error: {error}\")\n```\n\n### Lower-Level Document Translation Methods\n\nFor advanced control over the document translation process:\n\n```python\n# Upload document\nwith open(\"input.docx\", \"rb\") as in_file:\n    handle = translator.translate_document_upload(\n        in_file,\n        target_lang=\"DE\",\n        formality=\"more\"\n    )\n\n# Check translation status\nstatus = translator.translate_document_get_status(handle)\nprint(f\"Status: {status.status}\")\nprint(f\"Billed characters: {status.billed_characters}\")\n\n# Wait until translation is complete\ntranslator.translate_document_wait_until_done(handle)\n\n# Download translated document\nwith open(\"output.docx\", \"wb\") as out_file:\n    translator.translate_document_download(handle, out_file)\n```\n\n### Polling Document Status\n\n```python\nimport time\n\nwith open(\"input.pdf\", \"rb\") as in_file:\n    handle = translator.translate_document_upload(in_file, target_lang=\"FR\")\n\nwhile True:\n    status = translator.translate_document_get_status(handle)\n\n    if status.status == \"done\":\n        with open(\"output.pdf\", \"wb\") as out_file:\n            translator.translate_document_download(handle, out_file)\n        break\n    elif status.status == \"error\":\n        raise Exception(\"Document translation failed\")\n\n    time.sleep(5)  # Wait 5 seconds before checking again\n```\n\n## Multilingual Glossaries (v3 API)\n\nGlossaries allow you to specify custom translations for specific terms and phrases.\n\n### Creating Glossaries\n\n```python\nfrom deepl import MultilingualGlossaryDictionaryEntries\n\n# Define glossary entries\nentries = {\"artist\": \"Maler\", \"prize\": \"Gewinn\"}\ndictionaries = [\n    MultilingualGlossaryDictionaryEntries(\"EN\", \"DE\", entries)\n]\n\n# Create glossary\nmy_glossary = translator.create_multilingual_glossary(\n    \"My glossary\",\n    dictionaries\n)\n\nprint(f\"Glossary ID: {my_glossary.glossary_id}\")\nprint(f\"Created: {my_glossary.creation_time}\")\n```\n\n### Creating Glossary from CSV\n\n```python\n# CSV format:\n# source,target\n# artist,Maler\n# prize,Gewinn\n\nwith open(\"glossary.csv\", \"r\", encoding=\"utf-8\") as f:\n    csv_data = f.read()\n\nglossary = translator.create_multilingual_glossary_from_csv(\n    \"CSV glossary\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    csv_data=csv_data\n)\n```\n\n### Listing Glossaries\n\n```python\nglossaries = translator.list_multilingual_glossaries()\n\nfor g in glossaries:\n    print(f\"Name: {g.name}\")\n    print(f\"ID: {g.glossary_id}\")\n    print(f\"Created: {g.creation_time}\")\n    for dict_entry in g.dictionaries:\n        print(f\"  {dict_entry.source_lang} -> {dict_entry.target_lang}: {dict_entry.entry_count} entries\")\n```\n\n### Retrieving Specific Glossary\n\n```python\n# Get by ID\nglossary = translator.get_multilingual_glossary(\"glossary-id-here\")\n\n# Find by name\nglossaries = translator.list_multilingual_glossaries()\nmy_glossary = next((g for g in glossaries if g.name == \"My glossary\"), None)\n```\n\n### Viewing Glossary Entries\n\n```python\nentries = translator.get_multilingual_glossary_entries(\n    glossary,\n    \"EN\",\n    \"DE\"\n)\nprint(entries.dictionaries[0])\n```\n\n### Using Glossaries in Translation\n\n```python\n# Using glossary ID\nresult = translator.translate_text(\n    \"The artist won the prize\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    glossary=\"glossary-id-here\"\n)\n\n# Using glossary object\nglossaries = translator.list_multilingual_glossaries()\nmy_glossary = glossaries[0]\n\nresult = translator.translate_text(\n    \"The artist won the prize\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    glossary=my_glossary\n)\n\nprint(result.text)  # Uses custom translations from glossary\n```\n\n### Editing Glossaries\n\n#### Update Glossary Dictionary (Merge)\n\n```python\nfrom deepl import MultilingualGlossaryDictionaryEntries\n\n# Merge new entries with existing ones\nnew_entries = {\"hello\": \"hallo\", \"prize\": \"Gewinn\"}\nglossary_dict = MultilingualGlossaryDictionaryEntries(\n    \"EN\", \"DE\", new_entries\n)\ntranslator.update_multilingual_glossary_dictionary(\n    glossary,\n    glossary_dict\n)\n```\n\n#### Replace Glossary Dictionary\n\n```python\n# Replace all entries completely\nreplacement = {\"goodbye\": \"Auf Wiedersehen\"}\nglossary_dict = MultilingualGlossaryDictionaryEntries(\n    \"EN\", \"DE\", replacement\n)\ntranslator.replace_multilingual_glossary_dictionary(\n    glossary,\n    glossary_dict\n)\n```\n\n#### Update from CSV\n\n```python\nwith open(\"new.csv\", \"r\", encoding=\"utf-8\") as f:\n    csv_data = f.read()\n\ntranslator.update_multilingual_glossary_dictionary_from_csv(\n    glossary=\"glossary-id-here\",\n    source_lang=\"EN\",\n    target_lang=\"DE\",\n    csv_data=csv_data\n)\n```\n\n#### Rename Glossary\n\n```python\nglossary = translator.update_multilingual_glossary_name(\n    glossary,\n    \"New name\"\n)\n```\n\n### Deleting Glossaries\n\n```python\n# Delete entire glossary\ntranslator.delete_multilingual_glossary(glossary)\n\n# Delete specific dictionary from glossary\ntranslator.delete_multilingual_glossary_dictionary(\n    glossary,\n    glossary.dictionaries[0]\n)\n```\n\n### Glossary Supported Languages\n\nCheck which language pairs support glossaries:\n\n```python\nglossary_languages = translator.get_glossary_languages()\n\nfor lang_pair in glossary_languages:\n    print(f\"{lang_pair.source_lang} -> {lang_pair.target_lang}\")\n```\n\n## Language Detection and Information\n\n### Detecting Language\n\nDetect the language of text without translating:\n\n```python\n# Detect single text\ndetected = translator.detect_language(\"Bonjour, comment allez-vous?\")\nprint(detected)  # 'fr'\n\n# Detect multiple texts\ntexts = [\"Hello\", \"Bonjour\", \"Hola\"]\nlanguages = translator.detect_language(texts)\nfor text, lang in zip(texts, languages):\n    print(f'\"{text}\" is {lang}')\n# \"Hello\" is en\n# \"Bonjour\" is fr\n# \"Hola\" is es\n```\n\n### Getting Supported Languages\n\n```python\n# Get all supported languages\nlanguages = translator.get_languages()\nfor lang in languages:\n    print(f\"{lang.code}: {lang.name}\")\n\n# Get source languages\nsource_languages = translator.get_source_languages()\n\n# Get target languages\ntarget_languages = translator.get_target_languages()\nfor lang in target_languages:\n    print(f\"{lang.code}: {lang.name}\")\n    if hasattr(lang, 'supports_formality') and lang.supports_formality:\n        print(\"  Supports formality\")\n\n# Get glossary-supported languages\nglossary_languages = translator.get_glossary_languages()\n```\n\nLanguage object properties:\n- `code` - ISO 639-1 language code (e.g., 'en', 'de', 'fr')\n- `name` - Display name (e.g., 'English', 'German', 'French')\n- `supports_formality` - Boolean (target languages only)\n\n## Usage Monitoring\n\n### Checking Account Usage\n\nMonitor your character usage and account limits:\n\n```python\nusage = translator.get_usage()\n\nprint(f\"Characters used: {usage.character.count}\")\nprint(f\"Character limit: {usage.character.limit}\")\n\nif usage.character.limit_reached:\n    print(\"Character limit reached!\")\n\n# Calculate remaining characters\nremaining = usage.character.limit - usage.character.count\nprint(f\"Remaining characters: {remaining}\")\n\n# Document usage (if available)\nif hasattr(usage, 'document'):\n    print(f\"Documents translated: {usage.document.count}\")\n    print(f\"Document limit: {usage.document.limit}\")\n```\n\n### Account Tiers\n\n- **DeepL API Free:** 500,000 characters/month, up to 2 active API keys\n- **DeepL API Pro:** Pay-as-you-go, up to 25 active API keys, cost control limits\n\n## Error Handling\n\n### Common Error Patterns\n\n```python\ntry:\n    result = translator.translate_text(\"Hello\", target_lang=\"DE\")\n    print(result.text)\nexcept deepl.AuthorizationException:\n    print(\"Authentication failed. Check your API key.\")\nexcept deepl.QuotaExceededException:\n    print(\"Quota exceeded. Monthly character limit reached.\")\nexcept deepl.TooManyRequestsException:\n    print(\"Too many requests. Please slow down.\")\nexcept deepl.DeepLException as error:\n    print(f\"Translation error: {error}\")\n```\n\n### Document Translation Errors\n\n```python\ntry:\n    translator.translate_document_from_filepath(\n        \"input.docx\",\n        \"output.docx\",\n        target_lang=\"DE\"\n    )\nexcept deepl.DocumentTranslationException as error:\n    # Document was uploaded but translation failed\n    doc_id = error.document_handle.id\n    doc_key = error.document_handle.key\n    print(f\"Can retry with document ID: {doc_id}\")\nexcept deepl.DeepLException as error:\n    # Upload or other error\n    print(f\"Error: {error}\")\n```\n\n## Advanced Configuration\n\n### Custom Server URL\n\nFor DeepL API Pro plans with custom endpoints:\n\n```python\ntranslator = deepl.DeepLClient(\n    auth_key,\n    server_url=\"https://api.deepl.com\"  # Pro endpoint\n    # or \"https://api-free.deepl.com\" for Free endpoint\n)\n```\n\n### HTTP Options\n\nConfigure timeout and other HTTP options:\n\n```python\ntranslator = deepl.DeepLClient(\n    auth_key,\n    max_retries=5,\n    timeout=30.0  # seconds\n)\n```\n\n## Async Support\n\nDeepL Python SDK does not currently provide native async/await support. For async operations, use a thread pool executor:\n\n```python\nimport asyncio\nfrom concurrent.futures import ThreadPoolExecutor\n\nexecutor = ThreadPoolExecutor(max_workers=5)\ntranslator = deepl.DeepLClient(auth_key)\n\nasync def translate_async(text, target_lang):\n    loop = asyncio.get_event_loop()\n    result = await loop.run_in_executor(\n        executor,\n        translator.translate_text,\n        text,\n        None,\n        target_lang\n    )\n    return result.text\n\nasync def main():\n    result = await translate_async(\"Hello, world!\", \"FR\")\n    print(result)\n\nasyncio.run(main())\n```\n\n## Complete Translation Example\n\n```python\nimport deepl\nimport os\n\nauth_key = os.environ.get('DEEPL_AUTH_KEY')\ntranslator = deepl.DeepLClient(auth_key)\n\ndef complete_example():\n    try:\n        # 1. Check usage\n        usage = translator.get_usage()\n        remaining = usage.character.limit - usage.character.count\n        print(f\"Remaining: {remaining} characters\")\n\n        # 2. Get supported languages\n        target_langs = translator.get_target_languages()\n        german_lang = next((l for l in target_langs if l.code == 'DE'), None)\n        if german_lang and hasattr(german_lang, 'supports_formality'):\n            print(f\"German supports formality: {german_lang.supports_formality}\")\n\n        # 3. Translate with options\n        result = translator.translate_text(\n            \"How are you doing today?\",\n            target_lang=\"DE\",\n            formality=\"more\"\n        )\n        print(f\"Translation: {result.text}\")\n        print(f\"Detected source: {result.detected_source_lang}\")\n\n        # 4. Translate document\n        translator.translate_document_from_filepath(\n            \"document.pdf\",\n            \"dokument.pdf\",\n            target_lang=\"DE\",\n            formality=\"more\"\n        )\n\n        print(\"Translation complete!\")\n    except deepl.DeepLException as error:\n        print(f\"Error: {error}\")\n\ncomplete_example()\n```\n\n## Type Hints Support\n\nThe DeepL Python SDK includes type hints for better IDE support:\n\n```python\nfrom typing import List\nimport deepl\n\nauth_key: str = os.environ.get('DEEPL_AUTH_KEY')\ntranslator: deepl.DeepLClient = deepl.DeepLClient(auth_key)\n\ndef translate_texts(texts: List[str], target: str) -> List[str]:\n    results: List[deepl.TextResult] = translator.translate_text(\n        texts,\n        target_lang=target\n    )\n    return [result.text for result in results]\n\ntranslations: List[str] = translate_texts(\n    [\"Hello\", \"Goodbye\"],\n    \"FR\"\n)\n```\n\n## Python Version Support\n\nThe deepl Python package supports Python 3.9, 3.10, 3.11, 3.12, and 3.13.\n\n## Legacy API (v1/v2) - Deprecated\n\nIf you're using the old `Translator` class from earlier versions, migrate to `DeepLClient`:\n\n```python\n# Old API (deprecated)\n# translator = deepl.Translator(auth_key)\n\n# New API (current)\ntranslator = deepl.DeepLClient(auth_key)\n```\n\nThe method names remain mostly the same, but `DeepLClient` is the recommended approach.\n\n## Additional Resources\n\n- Official Documentation: https://www.deepl.com/docs-api/\n- GitHub Repository: https://github.com/DeepLcom/deepl-python\n- PyPI Package: https://pypi.org/project/deepl/\n"
  },
  {
    "path": "content/deepseek/docs/llm/DOC.md",
    "content": "---\nname: llm\ndescription: \"DeepSeek API JavaScript/TypeScript SDK coding guide for LLM chat and code generation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.0.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"deepseek,llm,ai,chat,code\"\n---\n\n# DeepSeek API JavaScript/TypeScript SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use OpenAI-compatible SDKs to access the DeepSeek API:**\n- Primary SDK: `openai` (Official OpenAI JavaScript SDK)\n- Alternative: Any OpenAI-compatible SDK\n\n**DeepSeek does NOT provide a dedicated JavaScript SDK.** Instead, the DeepSeek API is fully OpenAI-compatible, allowing you to use the official OpenAI SDK by simply changing the base URL and API key.\n\n**Never use:**\n- Unofficial or deprecated DeepSeek-specific packages\n- Legacy API implementations\n- Non-standard HTTP clients without proper error handling\n\n**Correct Installation:**\n```bash\nnpm install openai\n```\n\n## 2. Installation\n\n### npm\n```bash\nnpm install openai\n```\n\n### yarn\n```bash\nyarn add openai\n```\n\n### pnpm\n```bash\npnpm add openai\n```\n\n**Environment Variables:**\n```bash\nDEEPSEEK_API_KEY=your_deepseek_api_key_here\n# Get your API key from: https://platform.deepseek.com/api_keys\n```\n\n**Optional Configuration:**\n```bash\nDEEPSEEK_BASE_URL=https://api.deepseek.com\n```\n\n## 3. Initialization\n\n### Basic Initialization\n\n```javascript\nimport OpenAI from 'openai';\n\n// Initialize with DeepSeek API configuration\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY,\n  baseURL: 'https://api.deepseek.com',\n});\n```\n\n### With Explicit Configuration\n\n```javascript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI({\n  apiKey: 'your-deepseek-api-key',\n  baseURL: 'https://api.deepseek.com',\n  timeout: 30000, // 30 seconds\n  maxRetries: 3,\n});\n```\n\n### TypeScript Initialization\n\n```typescript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY!,\n  baseURL: 'https://api.deepseek.com',\n});\n```\n\n## 4. Core API Surfaces\n\n### Chat Completions (Non-Reasoning Mode)\n\n**Minimal Example:**\n```javascript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY,\n  baseURL: 'https://api.deepseek.com',\n});\n\nasync function chat() {\n  const completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: [\n      { role: 'system', content: 'You are a helpful assistant.' },\n      { role: 'user', content: 'Hello, how are you?' }\n    ],\n  });\n\n  console.log(completion.choices[0].message.content);\n}\n\nchat();\n```\n\n**Advanced Example with Parameters:**\n```javascript\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [\n    { role: 'system', content: 'You are a creative writing assistant.' },\n    { role: 'user', content: 'Write a short story about AI.' }\n  ],\n  temperature: 0.7,\n  max_tokens: 2000,\n  top_p: 0.9,\n  frequency_penalty: 0.5,\n  presence_penalty: 0.5,\n  stop: ['\\n\\n', 'END'],\n});\n\nconsole.log(completion.choices[0].message.content);\n```\n\n### Reasoning Mode (DeepSeek-R1)\n\n**Minimal Example:**\n```javascript\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-reasoner',\n  messages: [\n    { role: 'user', content: 'Solve this math problem: What is the derivative of x^2 + 3x + 2?' }\n  ],\n});\n\n// Access reasoning process\nconsole.log('Reasoning:', completion.choices[0].message.reasoning_content);\nconsole.log('Answer:', completion.choices[0].message.content);\n```\n\n**Advanced Reasoning Example:**\n```javascript\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-reasoner',\n  messages: [\n    {\n      role: 'system',\n      content: 'You are a mathematical reasoning assistant. Show your work step by step.'\n    },\n    {\n      role: 'user',\n      content: 'A train travels 120 km in 2 hours. If it increases its speed by 20%, how long will it take to travel 180 km?'\n    }\n  ],\n  max_tokens: 4000,\n  temperature: 1.0, // Reasoning models work best with temperature 1.0\n});\n\n// The reasoning process is in reasoning_content\nconsole.log('Thinking process:\\n', completion.choices[0].message.reasoning_content);\nconsole.log('\\nFinal answer:\\n', completion.choices[0].message.content);\n```\n\n### Streaming Responses\n\n**Basic Streaming:**\n```javascript\nasync function streamChat() {\n  const stream = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: [\n      { role: 'user', content: 'Write a poem about coding.' }\n    ],\n    stream: true,\n  });\n\n  for await (const chunk of stream) {\n    const content = chunk.choices[0]?.delta?.content || '';\n    process.stdout.write(content);\n  }\n}\n\nstreamChat();\n```\n\n**Advanced Streaming with Error Handling:**\n```javascript\nasync function streamWithErrorHandling() {\n  try {\n    const stream = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: [{ role: 'user', content: 'Tell me a story.' }],\n      stream: true,\n      max_tokens: 1000,\n    });\n\n    let fullResponse = '';\n\n    for await (const chunk of stream) {\n      const delta = chunk.choices[0]?.delta;\n\n      if (delta?.content) {\n        fullResponse += delta.content;\n        process.stdout.write(delta.content);\n      }\n\n      // Check for finish reason\n      if (chunk.choices[0]?.finish_reason) {\n        console.log('\\n\\nFinish reason:', chunk.choices[0].finish_reason);\n      }\n    }\n\n    return fullResponse;\n  } catch (error) {\n    console.error('Streaming error:', error);\n    throw error;\n  }\n}\n```\n\n**Streaming with Reasoning Mode:**\n```javascript\nasync function streamReasoning() {\n  const stream = await client.chat.completions.create({\n    model: 'deepseek-reasoner',\n    messages: [\n      { role: 'user', content: 'Explain quantum entanglement.' }\n    ],\n    stream: true,\n  });\n\n  let reasoning = '';\n  let answer = '';\n\n  for await (const chunk of stream) {\n    const delta = chunk.choices[0]?.delta;\n\n    // Reasoning content comes first\n    if (delta?.reasoning_content) {\n      reasoning += delta.reasoning_content;\n      console.log('[THINKING]', delta.reasoning_content);\n    }\n\n    // Final answer comes after reasoning\n    if (delta?.content) {\n      answer += delta.content;\n      console.log('[ANSWER]', delta.content);\n    }\n  }\n}\n```\n\n### JSON Mode (Structured Output)\n\n**Minimal Example:**\n```javascript\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [\n    {\n      role: 'system',\n      content: 'You are a helpful assistant. Always respond with valid JSON.'\n    },\n    {\n      role: 'user',\n      content: 'Extract the following information as JSON: Name is John, age 30, city New York.'\n    }\n  ],\n  response_format: { type: 'json_object' },\n});\n\nconst result = JSON.parse(completion.choices[0].message.content);\nconsole.log(result);\n```\n\n**Advanced JSON Mode with Schema Validation:**\n```javascript\nasync function structuredExtraction() {\n  const completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: [\n      {\n        role: 'system',\n        content: `You are a data extraction assistant. Extract information and return it as JSON with this schema:\n{\n  \"name\": \"string\",\n  \"age\": \"number\",\n  \"occupation\": \"string\",\n  \"skills\": [\"string\"],\n  \"contact\": {\n    \"email\": \"string\",\n    \"phone\": \"string\"\n  }\n}`\n      },\n      {\n        role: 'user',\n        content: 'John Doe is a 35-year-old software engineer skilled in Python, JavaScript, and DevOps. Email: john@example.com, Phone: 555-1234.'\n      }\n    ],\n    response_format: { type: 'json_object' },\n    temperature: 0.1, // Lower temperature for structured output\n  });\n\n  try {\n    const data = JSON.parse(completion.choices[0].message.content);\n    console.log('Extracted data:', data);\n    return data;\n  } catch (error) {\n    console.error('Failed to parse JSON:', error);\n    throw error;\n  }\n}\n```\n\n### Function Calling (Tool Use)\n\n**Minimal Example:**\n```javascript\nconst tools = [\n  {\n    type: 'function',\n    function: {\n      name: 'get_weather',\n      description: 'Get the current weather for a location',\n      parameters: {\n        type: 'object',\n        properties: {\n          location: {\n            type: 'string',\n            description: 'The city and state, e.g. San Francisco, CA',\n          },\n          unit: {\n            type: 'string',\n            enum: ['celsius', 'fahrenheit'],\n            description: 'The temperature unit',\n          },\n        },\n        required: ['location'],\n      },\n    },\n  },\n];\n\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [\n    { role: 'user', content: \"What's the weather in San Francisco?\" }\n  ],\n  tools: tools,\n});\n\n// Check if the model wants to call a function\nconst message = completion.choices[0].message;\nif (message.tool_calls) {\n  console.log('Function to call:', message.tool_calls[0].function.name);\n  console.log('Arguments:', message.tool_calls[0].function.arguments);\n}\n```\n\n**Advanced Function Calling with Execution:**\n```javascript\n// Define available functions\nconst availableFunctions = {\n  get_weather: async (location, unit = 'celsius') => {\n    // Simulate weather API call\n    return {\n      location,\n      temperature: 22,\n      unit,\n      condition: 'sunny',\n    };\n  },\n  calculate: async (expression) => {\n    return eval(expression); // Use safely in production!\n  },\n};\n\n// Define tools\nconst tools = [\n  {\n    type: 'function',\n    function: {\n      name: 'get_weather',\n      description: 'Get current weather',\n      parameters: {\n        type: 'object',\n        properties: {\n          location: { type: 'string' },\n          unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },\n        },\n        required: ['location'],\n      },\n    },\n  },\n  {\n    type: 'function',\n    function: {\n      name: 'calculate',\n      description: 'Perform mathematical calculation',\n      parameters: {\n        type: 'object',\n        properties: {\n          expression: { type: 'string', description: 'Math expression to evaluate' },\n        },\n        required: ['expression'],\n      },\n    },\n  },\n];\n\nasync function runConversation(userMessage) {\n  const messages = [{ role: 'user', content: userMessage }];\n\n  // First API call\n  let completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: messages,\n    tools: tools,\n    tool_choice: 'auto',\n  });\n\n  let message = completion.choices[0].message;\n\n  // Handle function calls\n  if (message.tool_calls) {\n    messages.push(message); // Add assistant message with tool calls\n\n    // Execute each function call\n    for (const toolCall of message.tool_calls) {\n      const functionName = toolCall.function.name;\n      const functionArgs = JSON.parse(toolCall.function.arguments);\n\n      console.log(`Calling function: ${functionName}`, functionArgs);\n\n      // Execute function\n      const functionResponse = await availableFunctions[functionName](...Object.values(functionArgs));\n\n      // Add function response to messages\n      messages.push({\n        role: 'tool',\n        tool_call_id: toolCall.id,\n        content: JSON.stringify(functionResponse),\n      });\n    }\n\n    // Second API call with function results\n    completion = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: messages,\n    });\n\n    message = completion.choices[0].message;\n  }\n\n  return message.content;\n}\n\n// Usage\nrunConversation(\"What's the weather in Tokyo and what's 123 * 456?\").then(console.log);\n```\n\n### Context Caching (Automatic)\n\nDeepSeek automatically caches frequently referenced contexts. No code changes required.\n\n**Example with Repeated Context:**\n```javascript\nconst systemPrompt = `You are an expert code reviewer. Review code for:\n1. Security vulnerabilities\n2. Performance issues\n3. Code style and best practices\n4. Potential bugs\n5. Maintainability concerns\n\nProvide detailed feedback with examples.`;\n\n// First request - cache miss\nconst review1 = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [\n    { role: 'system', content: systemPrompt },\n    { role: 'user', content: 'Review this code: function add(a, b) { return a + b; }' }\n  ],\n});\n\nconsole.log('Cache stats:', review1.usage);\n// prompt_cache_miss_tokens: 150 (example)\n// prompt_cache_hit_tokens: 0\n\n// Second request with same system prompt - cache hit\nconst review2 = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [\n    { role: 'system', content: systemPrompt }, // Same system prompt\n    { role: 'user', content: 'Review this code: function multiply(x, y) { return x * y; }' }\n  ],\n});\n\nconsole.log('Cache stats:', review2.usage);\n// prompt_cache_miss_tokens: 20\n// prompt_cache_hit_tokens: 150 (cached system prompt)\n```\n\n**Monitoring Cache Performance:**\n```javascript\nfunction analyzeCachePerformance(response) {\n  const usage = response.usage;\n  const cacheHitRate = usage.prompt_cache_hit_tokens /\n    (usage.prompt_cache_hit_tokens + usage.prompt_cache_miss_tokens);\n\n  console.log('Total prompt tokens:', usage.prompt_tokens);\n  console.log('Cache hits:', usage.prompt_cache_hit_tokens);\n  console.log('Cache misses:', usage.prompt_cache_miss_tokens);\n  console.log('Cache hit rate:', `${(cacheHitRate * 100).toFixed(2)}%`);\n  console.log('Completion tokens:', usage.completion_tokens);\n\n  // Calculate cost savings (approximate)\n  const cachedCost = (usage.prompt_cache_hit_tokens / 1_000_000) * 0.014;\n  const uncachedCost = (usage.prompt_cache_miss_tokens / 1_000_000) * 0.14;\n  console.log(`Cost: $${(cachedCost + uncachedCost).toFixed(6)}`);\n}\n```\n\n## 5. Advanced Features\n\n### Multi-Turn Conversations\n\n```javascript\nasync function conversation() {\n  const messages = [\n    { role: 'system', content: 'You are a helpful coding assistant.' }\n  ];\n\n  // First turn\n  messages.push({ role: 'user', content: 'How do I read a file in Node.js?' });\n\n  let completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: messages,\n  });\n\n  messages.push({ role: 'assistant', content: completion.choices[0].message.content });\n  console.log('Assistant:', completion.choices[0].message.content);\n\n  // Second turn\n  messages.push({ role: 'user', content: 'Can you show me an async example?' });\n\n  completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: messages,\n  });\n\n  messages.push({ role: 'assistant', content: completion.choices[0].message.content });\n  console.log('Assistant:', completion.choices[0].message.content);\n\n  return messages;\n}\n```\n\n### Token Counting and Management\n\n```javascript\n// Approximate token counting (use tiktoken library for accuracy)\nimport { encoding_for_model } from 'tiktoken';\n\nfunction countTokens(text, model = 'gpt-4') {\n  const encoding = encoding_for_model(model);\n  const tokens = encoding.encode(text);\n  encoding.free();\n  return tokens.length;\n}\n\nasync function managedCompletion(messages, maxResponseTokens = 2000) {\n  // Count input tokens\n  const inputText = messages.map(m => m.content).join('\\n');\n  const estimatedInputTokens = countTokens(inputText);\n\n  console.log(`Estimated input tokens: ${estimatedInputTokens}`);\n\n  // Ensure we don't exceed context window (128K for deepseek-chat)\n  if (estimatedInputTokens > 120000) {\n    console.warn('Input approaching context limit!');\n  }\n\n  const completion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: messages,\n    max_tokens: maxResponseTokens,\n  });\n\n  // Actual usage from API\n  console.log('Actual usage:', completion.usage);\n\n  return completion;\n}\n```\n\n### Custom Request Headers\n\n```javascript\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY,\n  baseURL: 'https://api.deepseek.com',\n  defaultHeaders: {\n    'X-Custom-Header': 'value',\n  },\n});\n```\n\n### Timeout and Retry Configuration\n\n```javascript\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY,\n  baseURL: 'https://api.deepseek.com',\n  timeout: 60000, // 60 seconds\n  maxRetries: 5,\n});\n\n// Per-request override\nconst completion = await client.chat.completions.create(\n  {\n    model: 'deepseek-chat',\n    messages: [{ role: 'user', content: 'Hello' }],\n  },\n  {\n    timeout: 30000,\n    maxRetries: 2,\n  }\n);\n```\n\n## 6. TypeScript Usage\n\n### Type-Safe Completions\n\n```typescript\nimport OpenAI from 'openai';\nimport type { ChatCompletionMessageParam, ChatCompletion } from 'openai/resources/chat';\n\nconst client = new OpenAI({\n  apiKey: process.env.DEEPSEEK_API_KEY!,\n  baseURL: 'https://api.deepseek.com',\n});\n\nasync function typedChat(): Promise<string> {\n  const messages: ChatCompletionMessageParam[] = [\n    { role: 'system', content: 'You are helpful.' },\n    { role: 'user', content: 'Hello' },\n  ];\n\n  const completion: ChatCompletion = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: messages,\n  });\n\n  return completion.choices[0].message.content || '';\n}\n```\n\n### Typed Function Calling\n\n```typescript\nimport OpenAI from 'openai';\nimport type { ChatCompletionTool } from 'openai/resources/chat';\n\ninterface WeatherParams {\n  location: string;\n  unit?: 'celsius' | 'fahrenheit';\n}\n\ninterface WeatherResult {\n  location: string;\n  temperature: number;\n  unit: string;\n  condition: string;\n}\n\nconst tools: ChatCompletionTool[] = [\n  {\n    type: 'function',\n    function: {\n      name: 'get_weather',\n      description: 'Get current weather',\n      parameters: {\n        type: 'object',\n        properties: {\n          location: { type: 'string' },\n          unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },\n        },\n        required: ['location'],\n      },\n    },\n  },\n];\n\nasync function getWeather(params: WeatherParams): Promise<WeatherResult> {\n  // Implementation\n  return {\n    location: params.location,\n    temperature: 22,\n    unit: params.unit || 'celsius',\n    condition: 'sunny',\n  };\n}\n```\n\n### Strict Type Checking for Streaming\n\n```typescript\nimport type { Stream } from 'openai/streaming';\nimport type { ChatCompletionChunk } from 'openai/resources/chat';\n\nasync function typedStream(): Promise<void> {\n  const stream: Stream<ChatCompletionChunk> = await client.chat.completions.create({\n    model: 'deepseek-chat',\n    messages: [{ role: 'user', content: 'Hello' }],\n    stream: true,\n  });\n\n  for await (const chunk of stream) {\n    const content: string | undefined = chunk.choices[0]?.delta?.content;\n    if (content) {\n      process.stdout.write(content);\n    }\n  }\n}\n```\n\n## 7. Best Practices\n\n### Error Handling\n\n```javascript\nimport OpenAI from 'openai';\n\nasync function robustCompletion(messages) {\n  try {\n    const completion = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: messages,\n    });\n\n    return completion.choices[0].message.content;\n  } catch (error) {\n    if (error instanceof OpenAI.APIError) {\n      console.error('API Error:', error.status, error.message);\n      console.error('Request ID:', error.headers?.['x-request-id']);\n\n      // Handle specific error codes\n      if (error.status === 429) {\n        console.error('Rate limit exceeded. Implementing backoff...');\n        // Implement exponential backoff\n        await new Promise(resolve => setTimeout(resolve, 5000));\n        return robustCompletion(messages); // Retry\n      } else if (error.status === 401) {\n        console.error('Authentication failed. Check API key.');\n        throw error;\n      } else if (error.status >= 500) {\n        console.error('Server error. Retrying...');\n        await new Promise(resolve => setTimeout(resolve, 2000));\n        return robustCompletion(messages);\n      }\n    } else if (error.code === 'ECONNABORTED') {\n      console.error('Request timeout');\n    } else {\n      console.error('Unexpected error:', error);\n    }\n\n    throw error;\n  }\n}\n```\n\n### Rate Limiting and Throttling\n\n```javascript\nclass DeepSeekClient {\n  constructor(apiKey) {\n    this.client = new OpenAI({\n      apiKey: apiKey,\n      baseURL: 'https://api.deepseek.com',\n    });\n    this.requestQueue = [];\n    this.processing = false;\n  }\n\n  async queueRequest(params) {\n    return new Promise((resolve, reject) => {\n      this.requestQueue.push({ params, resolve, reject });\n      this.processQueue();\n    });\n  }\n\n  async processQueue() {\n    if (this.processing || this.requestQueue.length === 0) return;\n\n    this.processing = true;\n\n    while (this.requestQueue.length > 0) {\n      const { params, resolve, reject } = this.requestQueue.shift();\n\n      try {\n        const result = await this.client.chat.completions.create(params);\n        resolve(result);\n      } catch (error) {\n        if (error.status === 429) {\n          // Re-queue with delay\n          await new Promise(r => setTimeout(r, 5000));\n          this.requestQueue.unshift({ params, resolve, reject });\n        } else {\n          reject(error);\n        }\n      }\n\n      // Add small delay between requests\n      await new Promise(r => setTimeout(r, 100));\n    }\n\n    this.processing = false;\n  }\n}\n\n// Usage\nconst deepseek = new DeepSeekClient(process.env.DEEPSEEK_API_KEY);\nconst result = await deepseek.queueRequest({\n  model: 'deepseek-chat',\n  messages: [{ role: 'user', content: 'Hello' }],\n});\n```\n\n### Optimizing for Context Caching\n\n```javascript\n// Structure prompts to maximize cache hits\nclass ConversationManager {\n  constructor() {\n    this.systemPrompt = ''; // Static system prompt for caching\n    this.conversationHistory = [];\n  }\n\n  setSystemPrompt(prompt) {\n    // Set once and reuse for cache efficiency\n    this.systemPrompt = prompt;\n  }\n\n  async chat(userMessage) {\n    const messages = [\n      { role: 'system', content: this.systemPrompt }, // Cached\n      ...this.conversationHistory,\n      { role: 'user', content: userMessage }\n    ];\n\n    const completion = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: messages,\n    });\n\n    const assistantMessage = completion.choices[0].message.content;\n\n    // Update history\n    this.conversationHistory.push(\n      { role: 'user', content: userMessage },\n      { role: 'assistant', content: assistantMessage }\n    );\n\n    // Keep history manageable (trim if too long)\n    if (this.conversationHistory.length > 20) {\n      this.conversationHistory = this.conversationHistory.slice(-20);\n    }\n\n    return {\n      message: assistantMessage,\n      usage: completion.usage,\n    };\n  }\n}\n```\n\n### Model Selection Strategy\n\n```javascript\nfunction selectModel(taskType, budget = 'normal') {\n  const modelMap = {\n    // Use deepseek-chat for general tasks\n    'chat': 'deepseek-chat',\n    'coding': 'deepseek-chat',\n    'writing': 'deepseek-chat',\n    'translation': 'deepseek-chat',\n\n    // Use deepseek-reasoner for complex reasoning\n    'math': 'deepseek-reasoner',\n    'logic': 'deepseek-reasoner',\n    'analysis': 'deepseek-reasoner',\n    'problem-solving': 'deepseek-reasoner',\n  };\n\n  return modelMap[taskType] || 'deepseek-chat';\n}\n\nasync function smartCompletion(taskType, message) {\n  const model = selectModel(taskType);\n\n  console.log(`Using model: ${model} for task: ${taskType}`);\n\n  const completion = await client.chat.completions.create({\n    model: model,\n    messages: [{ role: 'user', content: message }],\n  });\n\n  return completion.choices[0].message.content;\n}\n```\n\n### Security Best Practices\n\n```javascript\n// NEVER expose API keys in client-side code\n// NEVER commit API keys to version control\n// ALWAYS use environment variables\n\n// Use a proxy server for client applications\n// Example Express.js proxy endpoint:\nimport express from 'express';\n\nconst app = express();\napp.use(express.json());\n\napp.post('/api/chat', async (req, res) => {\n  try {\n    // Validate and sanitize input\n    const { messages } = req.body;\n\n    if (!Array.isArray(messages) || messages.length === 0) {\n      return res.status(400).json({ error: 'Invalid messages' });\n    }\n\n    // Rate limiting per user/IP (use express-rate-limit)\n    // Authentication (use your auth system)\n\n    const completion = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: messages,\n      max_tokens: 2000, // Limit to control costs\n    });\n\n    res.json({ message: completion.choices[0].message.content });\n  } catch (error) {\n    console.error('Proxy error:', error);\n    res.status(500).json({ error: 'Internal server error' });\n  }\n});\n```\n\n## 8. Production Checklist\n\n### Version Management\n- Pin exact SDK version in package.json: `\"openai\": \"4.73.0\"`\n- Test thoroughly before upgrading OpenAI SDK versions\n- Monitor OpenAI SDK changelog for breaking changes\n- Document which SDK version works with DeepSeek API\n\n### Environment Configuration\n```javascript\n// config/deepseek.js\nexport const deepseekConfig = {\n  apiKey: process.env.DEEPSEEK_API_KEY,\n  baseURL: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',\n  timeout: parseInt(process.env.DEEPSEEK_TIMEOUT || '60000'),\n  maxRetries: parseInt(process.env.DEEPSEEK_MAX_RETRIES || '3'),\n};\n\n// Validate configuration on startup\nexport function validateConfig() {\n  if (!deepseekConfig.apiKey) {\n    throw new Error('DEEPSEEK_API_KEY environment variable is required');\n  }\n\n  console.log('DeepSeek configuration validated');\n}\n```\n\n### Error Handling Checklist\n- ✅ Implement exponential backoff for rate limits (429 errors)\n- ✅ Handle network timeouts gracefully\n- ✅ Log all errors with request IDs for debugging\n- ✅ Implement circuit breaker for repeated failures\n- ✅ Provide fallback responses for critical paths\n- ✅ Monitor error rates and set up alerts\n\n### Monitoring and Logging\n```javascript\nimport winston from 'winston';\n\nconst logger = winston.createLogger({\n  level: 'info',\n  format: winston.format.json(),\n  transports: [\n    new winston.transports.File({ filename: 'deepseek-error.log', level: 'error' }),\n    new winston.transports.File({ filename: 'deepseek-combined.log' }),\n  ],\n});\n\nasync function monitoredCompletion(messages) {\n  const startTime = Date.now();\n\n  try {\n    const completion = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: messages,\n    });\n\n    const duration = Date.now() - startTime;\n\n    logger.info('Completion success', {\n      duration,\n      model: 'deepseek-chat',\n      inputTokens: completion.usage.prompt_tokens,\n      outputTokens: completion.usage.completion_tokens,\n      cacheHits: completion.usage.prompt_cache_hit_tokens,\n      cacheMisses: completion.usage.prompt_cache_miss_tokens,\n    });\n\n    return completion;\n  } catch (error) {\n    const duration = Date.now() - startTime;\n\n    logger.error('Completion failed', {\n      duration,\n      error: error.message,\n      status: error.status,\n      requestId: error.headers?.['x-request-id'],\n    });\n\n    throw error;\n  }\n}\n```\n\n### Cost Tracking\n```javascript\nclass CostTracker {\n  constructor() {\n    this.totalInputTokens = 0;\n    this.totalOutputTokens = 0;\n    this.totalCachedTokens = 0;\n  }\n\n  trackUsage(usage) {\n    this.totalInputTokens += usage.prompt_cache_miss_tokens || 0;\n    this.totalOutputTokens += usage.completion_tokens || 0;\n    this.totalCachedTokens += usage.prompt_cache_hit_tokens || 0;\n  }\n\n  estimateCost() {\n    // Pricing as of 2025\n    const inputCost = (this.totalInputTokens / 1_000_000) * 0.14;\n    const outputCost = (this.totalOutputTokens / 1_000_000) * 0.28;\n    const cachedCost = (this.totalCachedTokens / 1_000_000) * 0.014;\n\n    return {\n      input: inputCost,\n      output: outputCost,\n      cached: cachedCost,\n      total: inputCost + outputCost + cachedCost,\n    };\n  }\n\n  report() {\n    const cost = this.estimateCost();\n    console.log('Cost Report:');\n    console.log(`  Input tokens: ${this.totalInputTokens.toLocaleString()} ($${cost.input.toFixed(4)})`);\n    console.log(`  Output tokens: ${this.totalOutputTokens.toLocaleString()} ($${cost.output.toFixed(4)})`);\n    console.log(`  Cached tokens: ${this.totalCachedTokens.toLocaleString()} ($${cost.cached.toFixed(4)})`);\n    console.log(`  Total cost: $${cost.total.toFixed(4)}`);\n  }\n}\n\n// Usage\nconst tracker = new CostTracker();\n\nconst completion = await client.chat.completions.create({\n  model: 'deepseek-chat',\n  messages: [{ role: 'user', content: 'Hello' }],\n});\n\ntracker.trackUsage(completion.usage);\ntracker.report();\n```\n\n### Testing Strategy\n```javascript\n// __tests__/deepseek.test.js\nimport { jest } from '@jest/globals';\nimport OpenAI from 'openai';\n\n// Mock the OpenAI client for testing\njest.mock('openai');\n\ndescribe('DeepSeek Integration', () => {\n  let client;\n\n  beforeEach(() => {\n    client = new OpenAI({\n      apiKey: 'test-key',\n      baseURL: 'https://api.deepseek.com',\n    });\n  });\n\n  test('should create completion', async () => {\n    const mockResponse = {\n      choices: [{ message: { content: 'Test response' } }],\n      usage: { prompt_tokens: 10, completion_tokens: 5 },\n    };\n\n    client.chat.completions.create.mockResolvedValue(mockResponse);\n\n    const result = await client.chat.completions.create({\n      model: 'deepseek-chat',\n      messages: [{ role: 'user', content: 'Test' }],\n    });\n\n    expect(result.choices[0].message.content).toBe('Test response');\n  });\n\n  test('should handle errors', async () => {\n    const mockError = new Error('API Error');\n    mockError.status = 429;\n\n    client.chat.completions.create.mockRejectedValue(mockError);\n\n    await expect(\n      client.chat.completions.create({\n        model: 'deepseek-chat',\n        messages: [{ role: 'user', content: 'Test' }],\n      })\n    ).rejects.toThrow('API Error');\n  });\n});\n```\n\n### Performance Optimization\n- Use streaming for long responses to improve perceived latency\n- Implement request batching where appropriate\n- Cache static system prompts for context caching benefits\n- Monitor and optimize token usage\n- Use appropriate max_tokens limits to control costs\n- Consider using connection pooling for high-volume applications\n\n### Security Checklist\n- ✅ Store API keys in environment variables or secure vaults\n- ✅ Never commit API keys to version control\n- ✅ Use .gitignore for .env files\n- ✅ Implement rate limiting on your API endpoints\n- ✅ Validate and sanitize all user inputs\n- ✅ Use HTTPS for all API communications\n- ✅ Implement proper authentication for your application\n- ✅ Monitor for unusual API usage patterns\n- ✅ Set up alerts for cost thresholds\n- ✅ Regularly rotate API keys\n\n### Deployment Checklist\n- ✅ Environment variables configured correctly\n- ✅ Error logging and monitoring in place\n- ✅ Rate limiting implemented\n- ✅ Cost tracking configured\n- ✅ Backup error handling for API failures\n- ✅ Health check endpoints for API connectivity\n- ✅ Documentation for API usage and limits\n- ✅ Incident response plan for API outages\n\n## Available Models\n\nTo get the current list of available models, pricing, and specifications, use the DeepSeek API's models endpoint:\n\n### List All Models via CLI\n\n```bash\ncurl https://api.deepseek.com/models \\\n  -H \"Authorization: Bearer $DEEPSEEK_API_KEY\"\n```\n\n### List Models via JavaScript\n\n```javascript\nasync function listModels() {\n  const response = await fetch('https://api.deepseek.com/models', {\n    headers: {\n      'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`,\n    },\n  });\n\n  const data = await response.json();\n  console.log(JSON.stringify(data, null, 2));\n  return data;\n}\n```\n\nThe response will include model IDs, context lengths, pricing, and capabilities. Primary models include `deepseek-chat` and `deepseek-reasoner`.\n"
  },
  {
    "path": "content/deepspeed/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"DeepSpeed package guide for distributed PyTorch training, ZeRO, and inference in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.18.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"deepspeed,pytorch,distributed-training,zero,inference\"\n---\n\n# DeepSpeed Python Package Guide\n\n## Golden Rule\n\nInstall a PyTorch build that matches your CUDA runtime first, then install `deepspeed`, keep your DeepSpeed config explicit, and use the `DeepSpeedEngine` methods for training (`backward` and `step`) unless you have a specific reason to drop down to raw PyTorch behavior.\n\n## Installation\n\nPyPI `0.18.7` declares support for Python `>=3.8,<3.13`.\n\nInstall PyTorch first, then install DeepSpeed:\n\n```bash\npip install torch\npip install deepspeed==0.18.7\n```\n\nUseful install variants:\n\n```bash\npip install deepspeed\nDS_BUILD_OPS=1 pip install deepspeed\n```\n\n- `pip install deepspeed` is the normal path.\n- `DS_BUILD_OPS=1` forces DeepSpeed CUDA/C++ ops to build during install instead of at first use.\n- DeepSpeed recommends `ninja` for faster op builds.\n\nVerify what ops are available in the current environment:\n\n```bash\nds_report\n```\n\nIf you hit slow or repeated JIT builds, set a stable extension cache directory:\n\n```bash\nexport TORCH_EXTENSIONS_DIR=/path/to/torch-extensions\n```\n\n## Minimal Training Setup\n\nDeepSpeed adds CLI flags with `deepspeed.add_config_arguments(parser)` and converts your model into a `DeepSpeedEngine` with `deepspeed.initialize(...)`.\n\n```python\nimport argparse\nimport deepspeed\nimport torch\n\ndef build_parser() -> argparse.ArgumentParser:\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"--local_rank\", type=int, default=-1)\n    return deepspeed.add_config_arguments(parser)\n\ndef main() -> None:\n    parser = build_parser()\n    args = parser.parse_args()\n\n    model = MyModel()\n    optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)\n\n    ds_config = {\n        \"train_batch_size\": 32,\n        \"train_micro_batch_size_per_gpu\": 4,\n        \"gradient_accumulation_steps\": 2,\n        \"bf16\": {\"enabled\": True},\n        \"zero_optimization\": {\n            \"stage\": 2\n        },\n        \"optimizer\": {\n            \"type\": \"AdamW\",\n            \"params\": {\n                \"lr\": 1e-4,\n                \"betas\": [0.9, 0.999],\n                \"eps\": 1e-8,\n                \"weight_decay\": 0.01\n            }\n        }\n    }\n\n    model_engine, optimizer, _, _ = deepspeed.initialize(\n        args=args,\n        model=model,\n        optimizer=optimizer,\n        config=ds_config,\n    )\n\n    for batch in dataloader:\n        loss = model_engine(**batch)\n        model_engine.backward(loss)\n        model_engine.step()\n```\n\nNotes:\n\n- `config=` can be a Python `dict` or a path to a DeepSpeed JSON config file.\n- `train_batch_size` is the global batch size. Keep it consistent with `train_micro_batch_size_per_gpu * gradient_accumulation_steps * data_parallel_world_size`.\n- `model_engine.step()` handles the optimizer step and zeroing grads at the right accumulation boundary.\n\nTypical launcher usage:\n\n```bash\ndeepspeed train.py --deepspeed --deepspeed_config ds_config.json\n```\n\nFor a single node without the launcher, you can still initialize DeepSpeed inside a process that already set up distributed state, but the launcher is the default operational path.\n\n## Core Config Pattern\n\nMost operational behavior lives in the DeepSpeed config. Start with these keys:\n\n```json\n{\n  \"train_batch_size\": 32,\n  \"train_micro_batch_size_per_gpu\": 4,\n  \"gradient_accumulation_steps\": 2,\n  \"bf16\": { \"enabled\": true },\n  \"gradient_clipping\": 1.0,\n  \"zero_optimization\": {\n    \"stage\": 2\n  },\n  \"optimizer\": {\n    \"type\": \"AdamW\",\n    \"params\": {\n      \"lr\": 0.0001,\n      \"betas\": [0.9, 0.999],\n      \"eps\": 1e-8,\n      \"weight_decay\": 0.01\n    }\n  }\n}\n```\n\nPractical defaults:\n\n- Prefer `bf16` on modern NVIDIA GPUs that support it.\n- Start with `zero_optimization.stage: 2` for standard distributed training.\n- Move to stage 3 only when model states still do not fit in memory or when you need parameter partitioning.\n- Add `gradient_clipping` explicitly instead of assuming your training loop or optimizer wrapper will handle it.\n\n## ZeRO and Memory Scaling\n\nDeepSpeed’s ZeRO system reduces memory pressure by partitioning optimizer states, gradients, and eventually parameters:\n\n- Stage 1 partitions optimizer states.\n- Stage 2 partitions optimizer states and gradients.\n- Stage 3 also partitions model parameters.\n\nExample stage-3 config with CPU offload:\n\n```json\n{\n  \"bf16\": { \"enabled\": true },\n  \"zero_optimization\": {\n    \"stage\": 3,\n    \"offload_optimizer\": {\n      \"device\": \"cpu\",\n      \"pin_memory\": true\n    },\n    \"offload_param\": {\n      \"device\": \"cpu\",\n      \"pin_memory\": true\n    }\n  }\n}\n```\n\nUse stage 3 deliberately:\n\n- It unlocks much larger models, but it changes checkpointing and module execution behavior.\n- DeepSpeed documents `DeepSpeedCPUAdam` as the preferred optimizer when using ZeRO-Offload.\n\nIf your model has dynamic control flow or mixture-of-experts style routing under ZeRO-3, define the unstable parent as a ZeRO leaf module so all ranks gather the same parameter set during execution.\n\n## Inference\n\n`deepspeed.init_inference(...)` wraps an existing model for optimized inference. You can pass a config dict, keyword arguments, or both.\n\n```python\nimport deepspeed\nimport torch\n\nmodel = MyModel().eval().cuda()\n\nengine = deepspeed.init_inference(\n    model,\n    config={\n        \"dtype\": torch.float16,\n        \"replace_with_kernel_inject\": True,\n        \"tensor_parallel\": {\"tp_size\": 1},\n    },\n)\n\nwith torch.inference_mode():\n    outputs = engine(**batch)\n```\n\nNotes:\n\n- Keyword arguments and config dict values are merged; explicit kwargs win on conflict.\n- `replace_with_kernel_inject=True` is the common path for supported transformer-style models.\n- For tensor parallel inference, initialize the distributed environment before calling `init_inference`.\n\n## Runtime Environment and Multi-Node Setup\n\nDeepSpeed does not have package-level API auth. The operational setup is environment and cluster configuration instead:\n\n- `CUDA_VISIBLE_DEVICES` can restrict GPU selection on a node.\n- Multi-node runs typically use the DeepSpeed launcher plus a hostfile.\n- DeepSpeed can propagate selected environment variables across nodes from a `.deepspeed_env` file.\n- Set `DS_ENV_FILE=/path/to/file` if you do not want to use the default `.deepspeed_env` lookup.\n\nExample `.deepspeed_env` values:\n\n```bash\nNCCL_IB_DISABLE=1\nNCCL_SOCKET_IFNAME=eth0\n```\n\nIf your cluster does not use passwordless SSH, use the documented `--no_ssh` flow and launch one DeepSpeed command per node with the correct node rank.\n\n## Checkpointing\n\nCheckpointing is easy to misuse with ZeRO:\n\n```python\nmodel_engine.save_checkpoint(\"/tmp/checkpoints\", tag=\"global_step100\")\n```\n\nRules that matter:\n\n- All ranks must call `save_checkpoint`. Calling it only on rank 0 can hang because each rank writes its own master weights and optimizer shard.\n- Under ZeRO-3, you cannot save a checkpoint and then immediately reload it into the same still-partitioned engine instance. Reinitialize before load.\n- If you need a plain fp32 `state_dict`, use DeepSpeed’s ZeRO checkpoint conversion utilities rather than assuming the checkpoint is already a standard PyTorch format.\n\n## Common Pitfalls\n\n- Install order matters. Resolve the correct PyTorch and CUDA combination first, then install DeepSpeed.\n- Missing build tools cause avoidable pain. Install `ninja` and keep `TORCH_EXTENSIONS_DIR` stable on shared filesystems.\n- CUDA version mismatches fail fast by default. `DS_SKIP_CUDA_CHECK=1` exists, but the docs explicitly warn it can lead to unexpected behavior.\n- Older blog posts often assume only `engine.backward(loss)` is valid. DeepSpeed documents direct tensor fragment `backward()` support in versions `>= 0.18.3`, but `engine.backward(...)` is still the safest default across older examples and custom loops.\n- ZeRO-3 can deadlock on dynamic submodule activation unless you mark the correct parent as a leaf module.\n- DeepSpeed config mistakes are usually batch-size math or stage mismatches, not Python syntax errors. Check global batch, micro batch, accumulation, and ZeRO stage together.\n\n## Version-Sensitive Notes for 0.18.7\n\n- This doc is aligned to PyPI version `0.18.7` and the current `latest` DeepSpeed docs.\n- The install docs still describe both JIT op building and pre-building during installation; choose one intentionally for your environment.\n- Tensor fragment `backward()` support is documented for versions `>= 0.18.3`, so older pre-0.18.3 guidance may be more restrictive than necessary for `0.18.7`.\n- If you are copying a DeepSpeed config from an older repository, check whether it assumes `fp16` only. Current DeepSpeed docs and examples commonly show `bf16` for supported hardware.\n\n## Official Source URLs\n\n- Docs root: https://deepspeed.readthedocs.io/en/latest/\n- Getting Started: https://www.deepspeed.ai/getting-started/\n- Config JSON: https://www.deepspeed.ai/docs/config-json/\n- Inference Setup: https://deepspeed.readthedocs.io/en/latest/inference-init.html\n- ZeRO docs: https://deepspeed.readthedocs.io/en/latest/zero3.html\n- PyPI: https://pypi.org/project/deepspeed/\n- Repository: https://github.com/deepspeedai/DeepSpeed\n"
  },
  {
    "path": "content/deprecated/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Deprecated package guide for Python projects using decorator-based deprecation warnings and Sphinx docstring directives\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"deprecated,python,warnings,decorators,sphinx\"\n---\n\n# Deprecated Python Package Guide\n\n## Golden Rule\n\nUse the official `Deprecated` package when you need to mark Python functions, methods, classes, or parameters as deprecated. The main entry points are:\n\n- `from deprecated import deprecated`\n- `from deprecated.params import deprecated_params`\n- `from deprecated.sphinx import deprecated, versionadded, versionchanged`\n\nIf you are adopting the `1.3.x` line, pin `1.3.1`. The upstream changelog says `1.3.0` was yanked on PyPI because it missed the source distribution, and `1.3.1` replaces it with a packaging fix.\n\n## Install\n\nUse a virtual environment and pin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Deprecated==1.3.1\"\n```\n\n`Deprecated` uses `wrapt` under the hood; `pip` installs that dependency automatically.\n\nThe upstream docs still document historical support as far back as Python 2.7 and Python 3.4+, but the current compatibility matrix is maintained around recent `wrapt` releases and tested on current Python 3 versions. For new code, use Python 3.\n\n## Runtime Setup\n\nThere is no client object, auth flow, or required environment variable. You import a decorator and apply it directly to the callable or class you want to phase out.\n\nThe one environment variable that matters operationally is Python’s standard warning control:\n\n```bash\nPYTHONWARNINGS=default::DeprecationWarning\n```\n\nThat makes deprecation warnings visible without changing application code.\n\n## Deprecate A Function\n\nThe default decorator emits a `DeprecationWarning` each time the function is called:\n\n```python\nfrom deprecated import deprecated\n\n\n@deprecated(reason=\"Use better_print instead\", version=\"2.4.0\")\ndef print_value(value: object) -> None:\n    print(value)\n\n\ndef better_print(value: object) -> None:\n    print(value)\n\n\nprint_value(\"hello\")\n```\n\nYou can also decorate methods and entire classes with the same import:\n\n```python\nfrom deprecated import deprecated\n\n\nclass Printer:\n    @deprecated(reason=\"Use render instead\", version=\"2.4.0\")\n    def print_value(self, value: object) -> None:\n        print(value)\n\n    def render(self, value: object) -> None:\n        print(value)\n\n\n@deprecated(reason=\"Use NewFormatter instead\", version=\"3.0.0\")\nclass OldFormatter:\n    pass\n```\n\nWhen you deprecate a class, the warning is emitted when the class is instantiated, not on every later method call.\n\n## Control How Warnings Surface\n\n`Deprecated` uses Python’s warnings system. By default it uses `DeprecationWarning`, which Python often suppresses outside code running in `__main__`. For tests or CI, explicitly enable or escalate the warning:\n\n```python\nimport warnings\nfrom deprecated import deprecated\n\n\nwarnings.simplefilter(\"default\", DeprecationWarning)\n\n\n@deprecated(reason=\"Use new_api instead\", version=\"1.8.0\")\ndef old_api() -> None:\n    pass\n\n\nold_api()\n```\n\nIf you want the decorator itself to change local warning behavior, pass `action`:\n\n```python\nfrom deprecated import deprecated\n\n\n@deprecated(reason=\"Use new_api instead\", version=\"1.8.0\", action=\"error\")\ndef old_api() -> None:\n    pass\n```\n\nIf the warning is meant for application end users rather than Python developers, use a different warning category such as `FutureWarning`:\n\n```python\nfrom deprecated import deprecated\n\n\n@deprecated(\n    reason=\"The legacy CLI flag will be removed; use --format=json\",\n    version=\"5.0.0\",\n    category=FutureWarning,\n)\ndef run_report() -> None:\n    pass\n```\n\nIf you wrap deprecated callables in your own instrumentation, pass `extra_stacklevel` so the warning points at user code instead of your helper layer:\n\n```python\nfrom deprecated import deprecated\n\n\n@deprecated(\n    reason=\"Use new_api instead\",\n    version=\"1.8.0\",\n    extra_stacklevel=1,\n)\ndef old_api() -> None:\n    pass\n```\n\n## Deprecate Individual Parameters\n\nUse `deprecated_params` when the function should stay, but one or more arguments should not:\n\n```python\nfrom deprecated.params import deprecated_params\n\n\nclass APIV2Warning(DeprecationWarning):\n    pass\n\n\n@deprecated_params(\n    {\n        \"timeout_seconds\": \"timeout_seconds is deprecated; use timeout instead\",\n        \"start\": \"start is removed in v2\",\n    },\n    category=APIV2Warning,\n)\ndef fetch_data(url: str, timeout: float = 5.0, timeout_seconds=None, start=None):\n    if timeout_seconds is not None:\n        timeout = timeout_seconds\n    return {\"url\": url, \"timeout\": timeout, \"start\": start}\n```\n\nYou can stack parameter deprecations when you need different messages or categories across releases.\n\n## Add Sphinx Lifecycle Directives\n\nIf your project builds API docs with Sphinx, use the decorators from `deprecated.sphinx`. They both update the docstring and, for `deprecated`, emit a warning at runtime.\n\n```python\nfrom deprecated.sphinx import deprecated as sphinx_deprecated\nfrom deprecated.sphinx import versionadded\nfrom deprecated.sphinx import versionchanged\n\n\n@sphinx_deprecated(reason=\"Use successor_v2 instead\", version=\"0.3.0\")\n@versionchanged(reason=\"Added negative-number support\", version=\"0.2.0\")\n@versionadded(reason=\"Initial public release\", version=\"0.1.0\")\ndef successor(n: int) -> int:\n    \"\"\"\n    Return the next integer.\n    \"\"\"\n    return n + 1\n```\n\nImportant details from the upstream Sphinx guide:\n\n- Apply these decorators in reverse order: most recent first, oldest last.\n- Build docs in an environment where your package is installed, because Sphinx has to import the module so the decorators can rewrite the docstring.\n\n## Common Pitfalls\n\n- `DeprecationWarning` is easy to miss in library code because Python ignores it by default in many contexts. Turn warnings on in tests, or use a different category when the audience is end users.\n- A deprecated class warns on construction only. If you expect a warning on every method call, deprecate the method instead.\n- Use the top-level `deprecated` import for runtime warnings and the `deprecated.sphinx` import when you want Sphinx directives added to docstrings.\n- `1.3.1` is the safe `1.3.x` target. Upstream explicitly says `1.3.0` was yanked on PyPI.\n\n## Official Sources\n\n- Maintainer docs root: https://deprecated.readthedocs.io/en/latest/\n- Installation guide: https://deprecated.readthedocs.io/en/latest/installation.html\n- Tutorial: https://deprecated.readthedocs.io/en/latest/tutorial.html\n- Sphinx decorators guide: https://deprecated.readthedocs.io/en/latest/sphinx_deco.html\n- API reference: https://deprecated.readthedocs.io/en/latest/api.html\n- Changelog: https://deprecated.readthedocs.io/en/latest/changelog.html\n- PyPI package page: https://pypi.org/project/Deprecated/\n"
  },
  {
    "path": "content/detect-secrets/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"detect-secrets guide for baselines, audits, and pre-commit enforcement in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"detect-secrets,python,security,secrets,pre-commit,cli\"\n---\n\n# detect-secrets Python Package Guide\n\n`detect-secrets` is a repository scanning tool for catching committed credentials and other sensitive literals before they land in version control. The normal workflow is CLI-first: create a baseline, audit it, then enforce the check with `pre-commit` or CI.\n\nThere is no auth or client setup step:\n\n- Environment variables: none\n- Python imports: none for the standard workflow\n- Client initialization: none\n\n## Install\n\nPin the package version your repo expects:\n\n```bash\npython -m pip install \"detect-secrets==1.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"detect-secrets==1.5.0\"\npoetry add --group dev \"detect-secrets==1.5.0\"\n```\n\nConfirm the installed CLI:\n\n```bash\ndetect-secrets --version\n```\n\nIf you use `pre-commit`, install that separately in the same developer workflow or CI image:\n\n```bash\npython -m pip install pre-commit\n```\n\n## Core Workflow\n\n### Create a baseline\n\nRun the scanner from the repository root and write the results to a tracked baseline file:\n\n```bash\ndetect-secrets scan > .secrets.baseline\n```\n\nThe baseline is the file your team reviews and keeps under version control. It lets future scans focus on newly introduced findings instead of flagging the full repository history every time.\n\n### Audit existing findings\n\nAfter generating the baseline, audit it so known false positives are marked before you wire the tool into commit hooks or CI:\n\n```bash\ndetect-secrets audit .secrets.baseline\n```\n\nTreat this as part of the initial setup, not an optional cleanup step. A fresh baseline without an audit usually creates noise for the next developer who hits the hook.\n\n### Enforce with pre-commit\n\nThe maintainer repo publishes a `pre-commit` hook. A minimal `.pre-commit-config.yaml` looks like this:\n\n```yaml\nrepos:\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]\n```\n\nInstall the hooks:\n\n```bash\npre-commit install\n```\n\nRun the hook across the repository before relying on it for normal commits:\n\n```bash\npre-commit run detect-secrets --all-files\n```\n\nPin the `pre-commit` hook revision to the same package line your repo expects. That keeps detector behavior consistent between local installs and hook runs.\n\n### Use in CI\n\nIf your repository already uses `pre-commit` in CI, reuse the same hook definition there instead of inventing a second secret-scanning path:\n\n```bash\npre-commit run detect-secrets --all-files\n```\n\nThat keeps local commits and CI enforcement aligned around the same baseline file and hook arguments.\n\n## Practical Setup Notes\n\n### Repository files to commit\n\nFor a typical repo rollout, commit both of these files:\n\n- `.secrets.baseline`\n- `.pre-commit-config.yaml`\n\nWithout the baseline file in version control, other developers and CI jobs will not see the same allowlist and audit decisions.\n\n### Narrow false positives carefully\n\nIf generated files, fixtures, or lockfiles produce repeated noise, keep the exclusion close to the hook or scan configuration instead of deleting findings by hand. For example, `pre-commit` supports a hook-level `exclude:` pattern:\n\n```yaml\nrepos:\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]\n        exclude: package-lock\\.json$\n```\n\nAfter changing exclusions, regenerate or re-audit the baseline so the committed state matches the policy you actually want to enforce.\n\n## Common Pitfalls\n\n- Creating `.secrets.baseline` once and never auditing it. Review noise early so future hook failures are actionable.\n- Pinning `detect-secrets==1.5.0` locally but leaving a different `pre-commit` `rev` in the repo. Keep them aligned.\n- Treating the baseline as an untracked local file. The baseline is part of the shared repository policy.\n- Adding the hook before the initial baseline is committed. That usually blocks teammates with historical findings they did not introduce.\n- Editing the baseline casually by hand instead of regenerating or re-auditing when policy changes.\n\n## Version Notes For 1.5.0\n\nThis guide targets `detect-secrets` `1.5.0`. If your repository standardizes on this version, pin both the Python package and the `pre-commit` hook revision to the same release line before rolling it out broadly.\n\n## Official Sources Used\n\n- Maintainer repository: `https://github.com/Yelp/detect-secrets`\n- PyPI package page: `https://pypi.org/project/detect-secrets/`\n"
  },
  {
    "path": "content/diffusers/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"diffusers package guide for Python - Hugging Face Diffusers 0.37.0\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.37.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"diffusers,hugging-face,diffusion,generative-ai,images,video,audio\"\n---\n\n# diffusers Python Package Guide\n\n## Golden Rule\n\nUse `DiffusionPipeline.from_pretrained(...)` for the first working version, authenticate with Hugging Face before using gated models, and pin the package version because model-loading behavior and docs examples move quickly.\n\n## What This Package Is For\n\n`diffusers` is Hugging Face's Python library for running and training diffusion models. The main building blocks you use in application code are:\n\n- `DiffusionPipeline` for end-to-end inference\n- model classes and schedulers when you need to customize a pipeline\n- official training scripts in `diffusers/examples` when you need fine-tuning or full training\n\nIt supports image, video, audio, and other diffusion workloads, but the most common coding-agent task is loading a Hub checkpoint and generating outputs through a pipeline.\n\n## Installation\n\nPyPI currently publishes `diffusers 0.37.0` with `Requires: Python >=3.10`. Start there, even though some installation docs pages still describe older Python support ranges.\n\n### Recommended install for PyTorch workflows\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"diffusers[torch]==0.37.0\" transformers accelerate safetensors\n```\n\n### If your project pins PyTorch separately\n\n```bash\npip install \"diffusers==0.37.0\" transformers accelerate safetensors\n```\n\n### Check the installed version\n\n```bash\npython -c \"import diffusers; print(diffusers.__version__)\"\n```\n\n## Authentication and Hub Setup\n\nMany popular checkpoints are public, but gated or private models require Hugging Face authentication.\n\n### CLI login\n\n```bash\nhf auth login\nhf auth whoami\n```\n\n### Programmatic login\n\n```python\nfrom huggingface_hub import login\n\nlogin()\n```\n\n### When explicit tokens are useful\n\n- CI or short-lived jobs\n- switching between accounts\n- accessing gated models without an interactive prompt\n\nHugging Face documents both machine login and explicit `token=` usage across loading APIs. If a loading example for your exact pipeline class shows `token` or older `use_auth_token` style arguments, follow the signature for the version you have installed.\n\n## Cache and Offline Configuration\n\nModel files are cached locally. These environment variables are the main ones worth knowing:\n\n```bash\nexport HF_HOME=\"/path/to/cache-root\"\nexport HF_HUB_CACHE=\"/path/to/hub-cache\"\nexport HF_HUB_OFFLINE=1\nexport HF_HUB_DISABLE_TELEMETRY=1\n```\n\nPractical meaning:\n\n- `HF_HOME` and `HF_HUB_CACHE` move the download cache\n- `HF_HUB_OFFLINE=1` forces local-cache-only behavior\n- `HF_HUB_DISABLE_TELEMETRY=1` disables Hub telemetry during `from_pretrained()` loads\n\n## Fastest Path To A Working Pipeline\n\nStart with the generic pipeline loader unless you already know the exact pipeline class you need.\n\n```python\nimport torch\nfrom diffusers import DiffusionPipeline\n\nmodel_id = \"runwayml/stable-diffusion-v1-5\"\n\npipe = DiffusionPipeline.from_pretrained(\n    model_id,\n    torch_dtype=torch.float16,\n    use_safetensors=True,\n)\npipe = pipe.to(\"cuda\")\n\nimage = pipe(\"a cinematic photo of a lighthouse in winter at sunrise\").images[0]\nimage.save(\"output.png\")\n```\n\nNotes:\n\n- `DiffusionPipeline` auto-detects the right pipeline class from the checkpoint.\n- `use_safetensors=True` is a good default when the checkpoint provides safetensors weights.\n- Most official examples assume GPU inference. On CPU, remove `torch.float16` and expect much slower generation.\n\n## Common Loading Patterns\n\n### Load a specific pipeline class\n\nUse this when you already know the task and want explicit behavior.\n\n```python\nimport torch\nfrom diffusers import StableDiffusionPipeline\n\npipe = StableDiffusionPipeline.from_pretrained(\n    \"runwayml/stable-diffusion-v1-5\",\n    torch_dtype=torch.float16,\n    use_safetensors=True,\n)\npipe = pipe.to(\"cuda\")\n```\n\n### Load from a local directory\n\n```python\nfrom diffusers import DiffusionPipeline\n\npipe = DiffusionPipeline.from_pretrained(\"./my-downloaded-model\")\n```\n\nThis uses the local files as-is. If you expect newer Hub weights, refresh the local snapshot instead of assuming `from_pretrained()` will update a copied directory.\n\n### Save a pipeline locally\n\n```python\npipe.save_pretrained(\"./stable-diffusion-v1-5\")\n```\n\n### Use a gated model after login\n\n```python\nimport torch\nfrom diffusers import DiffusionPipeline\n\npipe = DiffusionPipeline.from_pretrained(\n    \"black-forest-labs/FLUX.1-dev\",\n    torch_dtype=torch.bfloat16,\n)\npipe = pipe.to(\"cuda\")\n```\n\nIf this fails with access or license errors, verify that:\n\n1. your Hugging Face account accepted the model terms\n2. `hf auth whoami` succeeds on the machine running the code\n3. the token has enough access for the repository you are loading\n\n## Memory-Constrained Inference\n\nFor large models, start with offloading before rewriting the pipeline structure.\n\n```python\nimport torch\nfrom diffusers import DiffusionPipeline\n\npipe = DiffusionPipeline.from_pretrained(\n    \"runwayml/stable-diffusion-v1-5\",\n    torch_dtype=torch.float16,\n)\npipe.enable_model_cpu_offload()\n```\n\nPractical cautions:\n\n- `enable_model_cpu_offload()` is the simple first option when a model barely fits in VRAM.\n- `device_map` is a different placement strategy; Diffusers documents values such as `\"cuda\"` and `\"balanced\"` for pipeline placement.\n- If you loaded with a device map and later need `.to(...)` or offload helpers, reset the device map first with `pipe.reset_device_map()`.\n\n## Swapping Components\n\nOne of the main reasons to use `diffusers` instead of a model-specific wrapper is that schedulers and model components are replaceable.\n\n```python\nfrom diffusers import DiffusionPipeline, DPMSolverMultistepScheduler\n\npipe = DiffusionPipeline.from_pretrained(\"runwayml/stable-diffusion-v1-5\")\npipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)\n```\n\nUse this when you want to trade off speed and quality without changing the checkpoint.\n\n## Training and Fine-Tuning\n\nUse the official training scripts for real training work. Do not start from an inference-only snippet and improvise a training loop unless you already know the model internals you need.\n\nThe upstream training overview describes the scripts as:\n\n- self-contained\n- easy to tweak\n- beginner-friendly\n- single-purpose\n\nCommon maintained examples include:\n\n- text-to-image\n- DreamBooth\n- LoRA\n- textual inversion\n- ControlNet\n\nFor coding agents, the practical rule is:\n\n1. find the closest official example in `diffusers/examples`\n2. match its dependency set and launch arguments first\n3. only then customize dataset handling, prompts, or model components\n\n## Common Pitfalls\n\n### Installing `diffusers` without the runtime stack\n\n`diffusers` alone is often not enough for useful PyTorch workflows. In practice you usually also need:\n\n- `torch`\n- `transformers`\n- `accelerate`\n- `safetensors`\n\n### Using `main` docs with a pinned PyPI release\n\nThe docs site has a version switcher, and `main` may document features not present in `0.37.0`. If an example looks newer than your installation, compare it against the `0.37.0` package version before copying it.\n\n### Assuming every model can be loaded the same way\n\nThe generic pipeline loader is the right default, but model cards still matter. Check the model page for:\n\n- license or gated-access requirements\n- recommended dtype\n- expected hardware\n- task-specific inputs such as masks, control images, or reference audio\n\n### Treating a local directory like a Hub repo\n\n`from_pretrained(\"./path\")` loads whatever files are already on disk. It does not magically track upstream updates for that copied directory.\n\n### Mixing device placement helpers incorrectly\n\nIf you use `device_map`, offloading, quantization, and `.to(...)` in the same script, apply them deliberately and verify the pipeline state after each step. The loading docs explicitly call out `reset_device_map()` when changing placement strategy.\n\n## Version-Sensitive Notes For 0.37.0\n\n- PyPI lists `0.37.0` as the package version covered here.\n- The official GitHub releases page for `v0.37.0` highlights Modular Diffusers as an experimental feature. Treat that API surface as less stable than the long-standing pipeline APIs.\n- Some Hugging Face docs pages and search snippets still reference older \"latest stable\" versions. Prefer the version switcher on the docs site plus the PyPI release page when you need to reconcile examples.\n- Authentication examples across Hugging Face docs may show either machine login or explicit token arguments. Use `hf auth login` as the default setup path, and check the exact method signature if you need non-interactive token passing.\n\n## Minimal Agent Workflow\n\nWhen asked to write code with `diffusers`, this order is usually correct:\n\n1. Confirm the project is actually using `diffusers==0.37.0` or a close version.\n2. Confirm whether inference or training is needed.\n3. Identify the exact Hub model ID.\n4. Check whether the model is public, private, or gated.\n5. Start with `DiffusionPipeline.from_pretrained(...)`.\n6. Add dtype, `device_map`, or offloading only after the basic load works.\n7. For training, switch to the closest official example script instead of building from scratch.\n\n## Official Source URLs\n\n- Docs root: `https://huggingface.co/docs/diffusers/`\n- Installation: `https://huggingface.co/docs/diffusers/en/installation`\n- Loading pipelines: `https://huggingface.co/docs/diffusers/using-diffusers/loading`\n- Training overview: `https://huggingface.co/docs/diffusers/main/en/training/overview`\n- PyPI package: `https://pypi.org/project/diffusers/`\n- PyPI release `0.37.0`: `https://pypi.org/project/diffusers/0.37.0/`\n- GitHub releases: `https://github.com/huggingface/diffusers/releases`\n- GitHub release `v0.37.0`: `https://github.com/huggingface/diffusers/releases/tag/v0.37.0`\n"
  },
  {
    "path": "content/dill/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"dill package guide for serializing Python callables, closures, and interpreter state\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dill,python,serialization,pickle,functions,sessions\"\n---\n\n# dill Python Package Guide\n\n## Golden Rule\n\nUse `dill` when standard `pickle` is too limited for your Python-only workflow. The API mirrors `pickle`, but `dill` is designed to serialize more Python objects, including many user-defined functions, lambdas, closures, and interpreter state.\n\n`dill` is a local serialization library, not a network service. There are no API keys, environment variables, or client objects to initialize.\n\n## Install\n\nInstall `dill` into the same environment as the code that will create or load the serialized objects:\n\n```bash\npython -m pip install \"dill==0.4.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dill==0.4.1\"\npoetry add \"dill==0.4.1\"\n```\n\n## Basic Usage\n\n`dill` follows the same core API as `pickle`: `dump`, `dumps`, `load`, and `loads`.\n\n### Serialize to bytes\n\n```python\nimport dill\n\n\ndef make_multiplier(factor: int):\n    def multiply(value: int) -> int:\n        return factor * value\n    return multiply\n\n\nmultiply_by_4 = make_multiplier(4)\n\npayload = {\n    \"message\": \"hello\",\n    \"transform\": multiply_by_4,\n}\n\nblob = dill.dumps(payload)\nrestored = dill.loads(blob)\n\nprint(restored[\"message\"])\nprint(restored[\"transform\"](10))\n```\n\n### Serialize to a file\n\n```python\nfrom pathlib import Path\nimport dill\n\n\ncache_path = Path(\"build/artifacts.pkl\")\ncache_path.parent.mkdir(parents=True, exist_ok=True)\n\ndata = {\n    \"numbers\": [1, 2, 3],\n    \"callback\": lambda value: value + 1,\n}\n\nwith cache_path.open(\"wb\") as file:\n    dill.dump(data, file)\n\nwith cache_path.open(\"rb\") as file:\n    restored = dill.load(file)\n\nprint(restored[\"callback\"](41))\n```\n\n## Serialize Functions And Closures\n\nOne of the main reasons to use `dill` instead of `pickle` is that it can handle many callables that are defined locally in your application code.\n\n```python\nimport dill\n\n\ndef build_greeter(prefix: str):\n    suffix = \"!\"\n\n    def greet(name: str) -> str:\n        return f\"{prefix}, {name}{suffix}\"\n\n    return greet\n\n\ngreeter = build_greeter(\"Hello\")\n\nblob = dill.dumps(greeter)\nrestored_greeter = dill.loads(blob)\n\nprint(restored_greeter(\"Ada\"))\n```\n\nThis pattern is useful for Python worker processes, local caching, distributed experiments, and checkpointing application state that includes dynamically defined functions.\n\n## Control What Gets Serialized\n\n`dill` exposes the same per-call API shape as `pickle`, plus additional options that matter for larger Python object graphs.\n\n### `recurse=True`\n\nUse `recurse=True` when serializing a function and you want `dill` to trace the globals that the function actually references instead of storing the entire globals dictionary.\n\n```python\nimport dill\n\nSCALE = 100\n\n\ndef normalize(value: int) -> float:\n    return value / SCALE\n\n\nblob = dill.dumps(normalize, recurse=True)\nrestored = dill.loads(blob)\n\nprint(restored(25))\n```\n\n### `byref=True`\n\nUse `byref=True` when you want certain objects, such as modules, to be serialized by reference instead of trying to capture their full contents.\n\n```python\nimport dill\nimport math\n\n\npayload = {\n    \"module\": math,\n    \"sqrt\": math.sqrt,\n}\n\nblob = dill.dumps(payload, byref=True)\nrestored = dill.loads(blob)\n\nprint(restored[\"sqrt\"](81))\n```\n\nYou can also set process-wide defaults through `dill.settings`:\n\n```python\nimport dill\n\n\ndill.settings[\"recurse\"] = True\ndill.settings[\"byref\"] = True\n```\n\nSet these deliberately. Global settings change how every later `dill.dump` or `dill.dumps` call behaves in the current process.\n\n## Save And Restore Module State\n\n`dill` can save the state of `__main__` or another module, which is useful when you need to checkpoint an interactive session or a script's working state.\n\n### Save the current `__main__` state\n\n```python\nimport dill\n\n\ncounter = 3\n\n\ndef bump() -> int:\n    return counter + 1\n\n\ndill.dump_module(\"session.pkl\")\n```\n\n### Restore it later\n\n```python\nimport dill\n\n\ndill.load_module(\"session.pkl\")\n\nprint(counter)\nprint(bump())\n```\n\nThis is the `dill` feature to reach for when you need session-style persistence, not just object-level serialization.\n\n## Debug Serialization Failures\n\nWhen a payload is hard to serialize, `dill.detect.trace()` helps show what `dill` is walking.\n\n```python\nimport dill\n\n\ndef make_handler(prefix: str):\n    return lambda name: f\"{prefix}: {name}\"\n\n\nhandler = make_handler(\"user\")\n\nwith dill.detect.trace():\n    dill.dumps(handler)\n```\n\nUse this when an object graph unexpectedly pulls in large globals or fails during pickling.\n\n## Common Pitfalls\n\n- Do not load `dill` data from untrusted sources. `dill` uses the same trust model as `pickle`, and unpickling can execute arbitrary code.\n- Keep the writing and reading environments compatible. Serialized objects that depend on local modules, local classes, or locally defined functions are easiest to restore in a similar Python environment.\n- Be careful with globals. Without `recurse=True`, serializing a function can capture more module state than you intended.\n- Use `byref=True` when the target environment already has importable modules or objects and you do not want to embed as much state in the pickle.\n- Prefer JSON or another interoperable format for long-term storage or cross-language exchange. `dill` is for Python object serialization.\n\n## Practical Recommendations\n\n- Start with `dill.dumps()` and `dill.loads()` during development so failures stay easy to inspect.\n- Switch to `dill.dump()` and `dill.load()` for file-based caches, checkpoints, or task handoff between Python processes.\n- Reach for `dump_module()` and `load_module()` only when you really need session-level persistence.\n- Keep serialized payloads scoped to one application or environment instead of treating them as a stable public format.\n"
  },
  {
    "path": "content/directus/docs/headless-cms/javascript/DOC.md",
    "content": "---\nname: headless-cms\ndescription: \"Directus JavaScript/TypeScript SDK coding guidelines for interacting with Directus projects using the official SDK\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"20.1.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"directus,headless-cms,api,content,backend\"\n---\n\n# Directus JavaScript/TypeScript SDK Coding Guidelines\n\nYou are a Directus SDK coding expert. Help me with writing code using the Directus SDK calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.directus.io/guides/sdk/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Directus SDK (`@directus/sdk`) to interact with Directus projects. This is the standard library for all Directus API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Directus SDK\n- **NPM Package:** `@directus/sdk`\n- **Legacy Libraries:** `directus-sdk-js`, `@directus/sdk-js` are deprecated\n\n**Installation:**\n\n- **Correct:** `npm install @directus/sdk`\n- **Incorrect:** `npm install directus-sdk-js`\n- **Incorrect:** `npm install @directus/sdk-js`\n\n**APIs and Usage:**\n\n- **Correct:** `import { createDirectus, rest } from '@directus/sdk'`\n- **Correct:** `const client = createDirectus('URL').with(rest())`\n- **Correct:** `await client.request(readItems('collection'))`\n- **Incorrect:** `DirectusClient` or `DirectusSDK`\n- **Incorrect:** `client.items.read()`\n- **Incorrect:** Legacy API patterns\n\n## Installation\n\nInstall the Directus SDK using npm:\n\n```bash\nnpm install @directus/sdk\n```\n\n## Initialization and Authentication\n\nThe `@directus/sdk` library requires creating a Directus client instance using `createDirectus` and composables like `rest()` for REST API functionality.\n\n### Basic Client Setup\n\n```javascript\nimport { createDirectus, rest } from '@directus/sdk';\n\n// Create a client pointing to your Directus instance\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n```\n\n### Authentication with Static Token\n\nUse a static access token for authentication:\n\n```javascript\nimport { createDirectus, staticToken, rest } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(staticToken('YOUR_ACCESS_TOKEN'))\n  .with(rest());\n```\n\nWith environment variables:\n\n```javascript\nimport { createDirectus, staticToken, rest } from '@directus/sdk';\n\nconst client = createDirectus(process.env.DIRECTUS_URL)\n  .with(staticToken(process.env.DIRECTUS_TOKEN))\n  .with(rest());\n```\n\n### Authentication with User Login\n\nUse email and password authentication:\n\n```javascript\nimport { createDirectus, authentication, rest } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(authentication())\n  .with(rest());\n\n// Login with credentials\nconst result = await client.login('user@example.com', 'password');\n\n// The token is now stored in the client for subsequent requests\n```\n\nLogin with mode specification:\n\n```javascript\nconst result = await client.login('user@example.com', 'password', {\n  mode: 'cookie' // or 'json'\n});\n```\n\n### Logout\n\n```javascript\nawait client.logout();\n```\n\n### Refresh Token\n\n```javascript\nawait client.refresh();\n```\n\n### Current User\n\nGet the currently authenticated user:\n\n```javascript\nimport { createDirectus, rest, authentication, readMe } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(authentication())\n  .with(rest());\n\nawait client.login('user@example.com', 'password');\n\nconst me = await client.request(readMe());\nconsole.log(me);\n```\n\n## Reading Items from Collections\n\n### Read All Items\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// Read all items from a collection\nconst articles = await client.request(readItems('articles'));\n```\n\n### Read with Query Parameters\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// Read with fields, filters, sorting, and limits\nconst articles = await client.request(\n  readItems('articles', {\n    fields: ['id', 'title', 'author.name', 'publish_date'],\n    filter: {\n      status: { _eq: 'published' },\n      publish_date: { _gte: '2024-01-01' }\n    },\n    sort: ['-publish_date', 'title'],\n    limit: 10,\n    offset: 0\n  })\n);\n```\n\n### Read Single Item by ID\n\n```javascript\nimport { createDirectus, rest, readItem } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst article = await client.request(\n  readItem('articles', '1', {\n    fields: ['*', 'author.*']\n  })\n);\n```\n\n### Search Items\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst results = await client.request(\n  readItems('articles', {\n    search: 'directus cms',\n    fields: ['id', 'title', 'content']\n  })\n);\n```\n\n### Deep Query for Relations\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst articles = await client.request(\n  readItems('articles', {\n    fields: ['*'],\n    deep: {\n      author: {\n        _filter: {\n          status: { _eq: 'active' }\n        }\n      }\n    }\n  })\n);\n```\n\n## Creating Items\n\n### Create Single Item\n\n```javascript\nimport { createDirectus, rest, createItem } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst newArticle = await client.request(\n  createItem('articles', {\n    title: 'New Article',\n    content: 'Article content here',\n    status: 'draft'\n  })\n);\n\nconsole.log(newArticle.id);\n```\n\n### Create Multiple Items\n\n```javascript\nimport { createDirectus, rest, createItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst newArticles = await client.request(\n  createItems('articles', [\n    { title: 'Article 1', status: 'draft' },\n    { title: 'Article 2', status: 'draft' },\n    { title: 'Article 3', status: 'published' }\n  ])\n);\n```\n\n## Updating Items\n\n### Update Single Item\n\n```javascript\nimport { createDirectus, rest, updateItem } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst updated = await client.request(\n  updateItem('articles', '1', {\n    status: 'published',\n    publish_date: new Date().toISOString()\n  })\n);\n```\n\n### Update Multiple Items\n\n```javascript\nimport { createDirectus, rest, updateItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// Update items matching a filter\nconst updated = await client.request(\n  updateItems('articles',\n    { status: 'archived' },\n    {\n      filter: {\n        publish_date: { _lt: '2020-01-01' }\n      }\n    }\n  )\n);\n```\n\nUpdate multiple items by IDs:\n\n```javascript\nimport { createDirectus, rest, updateItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst updated = await client.request(\n  updateItems('articles',\n    ['1', '2', '3'],\n    { status: 'published' }\n  )\n);\n```\n\n## Deleting Items\n\n### Delete Single Item\n\n```javascript\nimport { createDirectus, rest, deleteItem } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nawait client.request(deleteItem('articles', '1'));\n```\n\n### Delete Multiple Items\n\n```javascript\nimport { createDirectus, rest, deleteItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// Delete by IDs\nawait client.request(deleteItems('articles', ['1', '2', '3']));\n```\n\nDelete items matching a filter:\n\n```javascript\nimport { createDirectus, rest, deleteItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nawait client.request(\n  deleteItems('articles', {\n    filter: {\n      status: { _eq: 'draft' },\n      date_created: { _lt: '2023-01-01' }\n    }\n  })\n);\n```\n\n## Aggregation and Analytics\n\n### Count Items\n\n```javascript\nimport { createDirectus, rest, aggregate } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst result = await client.request(\n  aggregate('articles', {\n    aggregate: {\n      count: ['id']\n    }\n  })\n);\n\nconsole.log(result[0].count.id); // Total count\n```\n\n### Count with Filter\n\n```javascript\nimport { createDirectus, rest, aggregate } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst result = await client.request(\n  aggregate('articles', {\n    query: {\n      filter: {\n        status: { _eq: 'published' }\n      }\n    },\n    aggregate: {\n      count: ['id']\n    }\n  })\n);\n```\n\n### Sum, Average, Min, Max\n\n```javascript\nimport { createDirectus, rest, aggregate } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst stats = await client.request(\n  aggregate('articles', {\n    aggregate: {\n      sum: ['views'],\n      avg: ['views'],\n      min: ['views'],\n      max: ['views']\n    }\n  })\n);\n\nconsole.log(stats[0].sum.views);\nconsole.log(stats[0].avg.views);\nconsole.log(stats[0].min.views);\nconsole.log(stats[0].max.views);\n```\n\n### Group By\n\n```javascript\nimport { createDirectus, rest, aggregate } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst grouped = await client.request(\n  aggregate('articles', {\n    aggregate: {\n      count: ['id'],\n      avg: ['views']\n    },\n    groupBy: ['author', 'status']\n  })\n);\n\n// Returns grouped statistics by author and status\n```\n\nGroup by date functions:\n\n```javascript\nimport { createDirectus, rest, aggregate } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst monthlyStats = await client.request(\n  aggregate('articles', {\n    aggregate: {\n      count: ['id']\n    },\n    groupBy: ['year(publish_date)', 'month(publish_date)']\n  })\n);\n```\n\n## File Management\n\n### Upload Files\n\n```javascript\nimport { createDirectus, rest, uploadFiles } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst formData = new FormData();\nformData.append('file', fileBlob);\n\nconst uploadedFile = await client.request(uploadFiles(formData));\n\nconsole.log(uploadedFile.id);\n```\n\nUpload with metadata:\n\n```javascript\nimport { createDirectus, rest, uploadFiles } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst formData = new FormData();\nformData.append('title', 'My Image');\nformData.append('folder', 'folder-uuid');\nformData.append('file', fileBlob);\n\nconst uploadedFile = await client.request(uploadFiles(formData));\n```\n\n### Read Files\n\n```javascript\nimport { createDirectus, rest, readFiles } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst files = await client.request(\n  readFiles({\n    filter: {\n      type: { _starts_with: 'image/' }\n    }\n  })\n);\n```\n\n### Read Single File\n\n```javascript\nimport { createDirectus, rest, readFile } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst file = await client.request(readFile('file-uuid'));\n```\n\n### Read Asset (Raw File Content)\n\n```javascript\nimport { createDirectus, rest, readAssetRaw } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst assetBlob = await client.request(readAssetRaw('file-uuid'));\n```\n\nWith transformations (for images):\n\n```javascript\nimport { createDirectus, rest, readAssetRaw } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst thumbnail = await client.request(\n  readAssetRaw('file-uuid', {\n    width: 300,\n    height: 300,\n    fit: 'cover',\n    quality: 80,\n    format: 'webp'\n  })\n);\n```\n\nAvailable transformation options:\n\n```javascript\nimport { createDirectus, rest, readAssetRaw } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst transformed = await client.request(\n  readAssetRaw('file-uuid', {\n    width: 800,\n    height: 600,\n    fit: 'contain', // cover, contain, inside, outside\n    quality: 85,\n    format: 'jpg', // jpg, png, webp, tiff, avif\n    transforms: [['flip']], // flip, flop, blur, sharpen, grayscale\n    withoutEnlargement: true\n  })\n);\n```\n\n### Update File\n\n```javascript\nimport { createDirectus, rest, updateFile } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst updated = await client.request(\n  updateFile('file-uuid', {\n    title: 'Updated Title',\n    description: 'Updated description'\n  })\n);\n```\n\n### Delete File\n\n```javascript\nimport { createDirectus, rest, deleteFile } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nawait client.request(deleteFile('file-uuid'));\n```\n\n## User Management\n\n### Read Users\n\n```javascript\nimport { createDirectus, rest, readUsers } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst users = await client.request(\n  readUsers({\n    filter: {\n      status: { _eq: 'active' }\n    },\n    fields: ['id', 'email', 'first_name', 'last_name']\n  })\n);\n```\n\n### Read Single User\n\n```javascript\nimport { createDirectus, rest, readUser } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst user = await client.request(readUser('user-uuid'));\n```\n\n### Create User\n\n```javascript\nimport { createDirectus, rest, createUser } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst newUser = await client.request(\n  createUser({\n    email: 'newuser@example.com',\n    password: 'secure-password',\n    role: 'role-uuid',\n    first_name: 'John',\n    last_name: 'Doe'\n  })\n);\n```\n\n### Update User\n\n```javascript\nimport { createDirectus, rest, updateUser } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst updated = await client.request(\n  updateUser('user-uuid', {\n    first_name: 'Jane',\n    status: 'active'\n  })\n);\n```\n\n### Delete User\n\n```javascript\nimport { createDirectus, rest, deleteUser } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nawait client.request(deleteUser('user-uuid'));\n```\n\n## Roles and Permissions\n\n### Read Roles\n\n```javascript\nimport { createDirectus, rest, readRoles } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst roles = await client.request(readRoles());\n```\n\n### Read Single Role\n\n```javascript\nimport { createDirectus, rest, readRole } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst role = await client.request(readRole('role-uuid'));\n```\n\n### Create Role\n\n```javascript\nimport { createDirectus, rest, createRole } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst newRole = await client.request(\n  createRole({\n    name: 'Content Editor',\n    icon: 'edit',\n    description: 'Can edit content'\n  })\n);\n```\n\n### Read Permissions\n\n```javascript\nimport { createDirectus, rest, readPermissions } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst permissions = await client.request(\n  readPermissions({\n    filter: {\n      role: { _eq: 'role-uuid' }\n    }\n  })\n);\n```\n\n### Create Permission\n\n```javascript\nimport { createDirectus, rest, createPermission } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst newPermission = await client.request(\n  createPermission({\n    role: 'role-uuid',\n    collection: 'articles',\n    action: 'read',\n    fields: ['*']\n  })\n);\n```\n\n## Collections and Fields\n\n### Read Collections\n\n```javascript\nimport { createDirectus, rest, readCollections } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst collections = await client.request(readCollections());\n```\n\n### Read Single Collection\n\n```javascript\nimport { createDirectus, rest, readCollection } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst collection = await client.request(readCollection('articles'));\n```\n\n### Read Fields\n\n```javascript\nimport { createDirectus, rest, readFields } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// Read all fields for a collection\nconst fields = await client.request(readFields('articles'));\n```\n\n### Read Single Field\n\n```javascript\nimport { createDirectus, rest, readField } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst field = await client.request(readField('articles', 'title'));\n```\n\n## Real-time with WebSockets\n\n### Setup Real-time Client\n\n```javascript\nimport { createDirectus, realtime } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(realtime());\n\n// Connect to WebSocket\nawait client.connect();\n```\n\n### Subscribe to Collection Updates\n\n```javascript\nimport { createDirectus, realtime } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(realtime());\n\nawait client.connect();\n\nconst { subscription } = await client.subscribe('articles', {\n  event: 'update',\n  query: {\n    fields: ['id', 'title', 'status']\n  }\n});\n\nfor await (const message of subscription) {\n  console.log('Item updated:', message);\n}\n```\n\n### Subscribe to Multiple Events\n\n```javascript\nimport { createDirectus, realtime } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(realtime());\n\nawait client.connect();\n\nconst { subscription } = await client.subscribe('articles', {\n  event: 'create'\n});\n\nfor await (const message of subscription) {\n  console.log('New item created:', message);\n}\n```\n\nAvailable events: `create`, `update`, `delete`\n\n### Unsubscribe\n\n```javascript\nawait client.unsubscribe(subscription.uid);\n```\n\n### Close Connection\n\n```javascript\nawait client.disconnect();\n```\n\n## GraphQL Support\n\n### Setup GraphQL Client\n\n```javascript\nimport { createDirectus, graphql } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(graphql());\n```\n\n### Execute GraphQL Query\n\n```javascript\nimport { createDirectus, graphql } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(graphql());\n\nconst result = await client.query(`\n  query {\n    articles(filter: { status: { _eq: \"published\" } }) {\n      id\n      title\n      author {\n        first_name\n        last_name\n      }\n    }\n  }\n`);\n\nconsole.log(result.articles);\n```\n\n### Execute GraphQL Mutation\n\n```javascript\nimport { createDirectus, graphql } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(graphql());\n\nconst result = await client.query(`\n  mutation {\n    create_articles_item(data: {\n      title: \"New Article\"\n      content: \"Article content\"\n      status: \"draft\"\n    }) {\n      id\n      title\n    }\n  }\n`);\n```\n\nWith variables:\n\n```javascript\nimport { createDirectus, graphql } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(graphql());\n\nconst result = await client.query(\n  `\n  query GetArticle($id: ID!) {\n    articles_by_id(id: $id) {\n      id\n      title\n      content\n    }\n  }\n  `,\n  {\n    id: '1'\n  }\n);\n```\n\n## TypeScript Support\n\n### Type-Safe Collections\n\n```typescript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\n// Define your schema types\ninterface Article {\n  id: string;\n  title: string;\n  content: string;\n  status: 'draft' | 'published' | 'archived';\n  author: string | Author;\n  publish_date: string;\n}\n\ninterface Author {\n  id: string;\n  first_name: string;\n  last_name: string;\n  email: string;\n}\n\ninterface Schema {\n  articles: Article[];\n  authors: Author[];\n}\n\n// Create typed client\nconst client = createDirectus<Schema>('https://your-directus-instance.com')\n  .with(rest());\n\n// Type-safe operations\nconst articles = await client.request(\n  readItems('articles', {\n    fields: ['id', 'title', 'author.first_name']\n  })\n);\n\n// articles is properly typed as Article[]\n```\n\n### Type-Safe Item Creation\n\n```typescript\nimport { createDirectus, rest, createItem } from '@directus/sdk';\n\nconst client = createDirectus<Schema>('https://your-directus-instance.com')\n  .with(rest());\n\nconst newArticle = await client.request(\n  createItem('articles', {\n    title: 'New Article',\n    content: 'Content here',\n    status: 'draft' // TypeScript ensures this matches the union type\n  })\n);\n```\n\n## Advanced Query Filters\n\n### Comparison Operators\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\nconst filtered = await client.request(\n  readItems('articles', {\n    filter: {\n      views: { _gt: 1000 }, // Greater than\n      publish_date: { _lte: '2024-12-31' }, // Less than or equal\n      status: { _neq: 'draft' }, // Not equal\n      title: { _contains: 'directus' }, // Contains substring\n      author: { _null: false } // Not null\n    }\n  })\n);\n```\n\nAvailable operators: `_eq`, `_neq`, `_lt`, `_lte`, `_gt`, `_gte`, `_in`, `_nin`, `_null`, `_nnull`, `_contains`, `_ncontains`, `_starts_with`, `_nstarts_with`, `_ends_with`, `_nends_with`, `_between`, `_nbetween`, `_empty`, `_nempty`\n\n### Logical Operators\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\n// AND (default behavior)\nconst andFilter = await client.request(\n  readItems('articles', {\n    filter: {\n      status: { _eq: 'published' },\n      views: { _gt: 100 }\n    }\n  })\n);\n\n// OR\nconst orFilter = await client.request(\n  readItems('articles', {\n    filter: {\n      _or: [\n        { status: { _eq: 'published' } },\n        { status: { _eq: 'archived' } }\n      ]\n    }\n  })\n);\n\n// Complex nested logic\nconst complexFilter = await client.request(\n  readItems('articles', {\n    filter: {\n      _and: [\n        {\n          _or: [\n            { status: { _eq: 'published' } },\n            { status: { _eq: 'archived' } }\n          ]\n        },\n        { views: { _gt: 100 } }\n      ]\n    }\n  })\n);\n```\n\n## Error Handling\n\n```javascript\nimport { createDirectus, rest, readItems } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com').with(rest());\n\ntry {\n  const articles = await client.request(readItems('articles'));\n} catch (error) {\n  if (error.errors) {\n    // Directus API error\n    console.error('API Error:', error.errors);\n  } else {\n    // Network or other error\n    console.error('Error:', error.message);\n  }\n}\n```\n\nHandle authentication errors:\n\n```javascript\nimport { createDirectus, authentication, rest } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com')\n  .with(authentication())\n  .with(rest());\n\ntry {\n  await client.login('user@example.com', 'wrong-password');\n} catch (error) {\n  if (error.errors?.[0]?.extensions?.code === 'INVALID_CREDENTIALS') {\n    console.error('Invalid email or password');\n  } else {\n    console.error('Login error:', error);\n  }\n}\n```\n\n## Request Configuration\n\n### Custom Headers\n\n```javascript\nimport { createDirectus, rest } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com', {\n  globals: {\n    headers: {\n      'Custom-Header': 'value'\n    }\n  }\n}).with(rest());\n```\n\n### Request Timeout\n\n```javascript\nimport { createDirectus, rest } from '@directus/sdk';\n\nconst client = createDirectus('https://your-directus-instance.com', {\n  globals: {\n    fetch: {\n      timeout: 10000 // 10 seconds\n    }\n  }\n}).with(rest());\n```\n\n## Useful Links\n\n- Documentation: https://docs.directus.io/\n- SDK Reference: https://docs.directus.io/guides/sdk/\n- REST API Reference: https://docs.directus.io/reference/introduction\n- GraphQL Reference: https://docs.directus.io/guides/sdk/graphql\n- Real-time Guide: https://docs.directus.io/guides/real-time/getting-started/websockets\n"
  },
  {
    "path": "content/directus/docs/headless-cms/python/DOC.md",
    "content": "---\nname: headless-cms\ndescription: \"Directus Python SDK coding guidelines for interacting with Directus projects using the py-directus library\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.0.30\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"directus,headless-cms,api,content,backend\"\n---\n\n# Directus Python SDK Coding Guidelines\n\nYou are a Directus Python SDK coding expert. Help me with writing code using the Directus Python SDK calling the official libraries.\n\nYou can find the official SDK documentation and code samples here:\nhttps://panos-stavrianos.github.io/py-directus/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the py-directus library to interact with Directus projects in Python. This is a community-maintained async Python wrapper for the Directus API. Do not use outdated or unmaintained libraries.\n\n- **Library Name:** py-directus\n- **PyPI Package:** `py-directus`\n- **Alternative Libraries:** `directus-sdk-py`, `pydirectus-sdk` (less maintained)\n\n**Installation:**\n\n- **Correct:** `pip install py-directus`\n- **Incorrect:** `pip install directus`\n- **Incorrect:** `pip install directus-python`\n\n**APIs and Usage:**\n\n- **Correct:** `from py_directus import Directus`\n- **Correct:** `directus = await Directus(url, email, password)`\n- **Correct:** `await directus.collection(\"articles\").read()`\n- **Incorrect:** `DirectusClient` or `DirectusAPI`\n- **Incorrect:** Synchronous API calls without `await`\n\n## Installation\n\nInstall py-directus using pip:\n\n```bash\npip install py-directus\n```\n\n## Initialization and Authentication\n\nThe `py-directus` library is fully asynchronous and requires using `async`/`await` syntax. The library requires creating a Directus instance with authentication.\n\n### Authentication with Email and Password\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        email=\"user@example.com\",\n        password=\"your-password\"\n    )\n\n    # Use directus client\n    # ...\n\n# Run the async function\nimport asyncio\nasyncio.run(main())\n```\n\n### Authentication with Static Token\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-static-token\"\n    )\n\n    # Use directus client\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Using Context Manager\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    async with await Directus(\n        url=\"https://your-directus-instance.com\",\n        email=\"user@example.com\",\n        password=\"your-password\"\n    ) as directus:\n        # Use directus client\n        users = await directus.collection(\"directus_users\").read()\n\nimport asyncio\nasyncio.run(main())\n```\n\n### With Environment Variables\n\n```python\nimport os\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=os.getenv(\"DIRECTUS_URL\"),\n        token=os.getenv(\"DIRECTUS_TOKEN\")\n    )\n\n    # Use directus client\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Reading Items from Collections\n\n### Read All Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read all items from a collection\n    response = await directus.collection(\"articles\").read()\n    articles = response.items\n\n    for article in articles:\n        print(article)\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read Single Item\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read single item by ID\n    response = await directus.collection(\"articles\").read(id=\"1\")\n    article = response.item\n\n    print(article)\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read with Field Selection\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Select specific fields\n    response = await directus.collection(\"articles\").fields(\"id\", \"title\", \"author.name\").read()\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read with Limit and Offset\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Pagination\n    response = await directus.collection(\"articles\").limit(10).offset(20).read()\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Filtering Items\n\n### Simple Filter\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Filter by field value\n    response = await directus.collection(\"articles\").filter(status=\"published\").read()\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Multiple Filters (AND)\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Multiple filters are combined with AND\n    response = await (\n        directus.collection(\"articles\")\n        .filter(status=\"published\")\n        .filter(views__gte=1000)\n        .read()\n    )\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Complex Filters with F Object\n\n```python\nfrom py_directus import Directus, F\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # OR conditions\n    response = await (\n        directus.collection(\"users\")\n        .filter(F(first_name=\"John\") | F(first_name=\"Jane\"))\n        .read()\n    )\n\n    # Complex nested conditions\n    response = await (\n        directus.collection(\"articles\")\n        .filter(\n            (F(status=\"published\") | F(status=\"archived\"))\n            & F(views__gte=100)\n        )\n        .read()\n    )\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Filter Operators\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Greater than\n    response = await directus.collection(\"articles\").filter(views__gt=1000).read()\n\n    # Greater than or equal\n    response = await directus.collection(\"articles\").filter(views__gte=1000).read()\n\n    # Less than\n    response = await directus.collection(\"articles\").filter(views__lt=1000).read()\n\n    # Less than or equal\n    response = await directus.collection(\"articles\").filter(views__lte=1000).read()\n\n    # Not equal\n    response = await directus.collection(\"articles\").filter(status__neq=\"draft\").read()\n\n    # Contains\n    response = await directus.collection(\"articles\").filter(title__contains=\"directus\").read()\n\n    # In list\n    response = await directus.collection(\"articles\").filter(status__in=[\"published\", \"archived\"]).read()\n\n    # Not in list\n    response = await directus.collection(\"articles\").filter(status__nin=[\"draft\", \"deleted\"]).read()\n\n    # Is null\n    response = await directus.collection(\"articles\").filter(author__null=True).read()\n\n    # Is not null\n    response = await directus.collection(\"articles\").filter(author__nnull=True).read()\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Sorting Items\n\n### Single Sort\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Sort ascending\n    response = await directus.collection(\"articles\").sort(\"title\").read()\n\n    # Sort descending\n    response = await directus.collection(\"articles\").sort(\"-publish_date\").read()\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Multiple Sorts\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Multiple sort fields\n    response = await directus.collection(\"articles\").sort(\"-publish_date\", \"title\").read()\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Searching Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Full-text search\n    response = await directus.collection(\"articles\").search(\"directus cms\").read()\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Creating Items\n\n### Create Single Item\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Create a new item\n    new_article = {\n        \"title\": \"New Article\",\n        \"content\": \"Article content here\",\n        \"status\": \"draft\"\n    }\n\n    response = await directus.collection(\"articles\").create(new_article)\n    created_article = response.item\n\n    print(f\"Created article with ID: {created_article['id']}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Create Multiple Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Create multiple items\n    new_articles = [\n        {\"title\": \"Article 1\", \"status\": \"draft\"},\n        {\"title\": \"Article 2\", \"status\": \"draft\"},\n        {\"title\": \"Article 3\", \"status\": \"published\"}\n    ]\n\n    response = await directus.collection(\"articles\").create(new_articles)\n    created_articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Updating Items\n\n### Update Single Item\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Update an item by ID\n    updated_data = {\n        \"status\": \"published\",\n        \"publish_date\": \"2024-01-15\"\n    }\n\n    response = await directus.collection(\"articles\").update(\"1\", updated_data)\n    updated_article = response.item\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Update Multiple Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Update multiple items by IDs\n    item_ids = [\"1\", \"2\", \"3\"]\n    updated_data = {\"status\": \"published\"}\n\n    response = await directus.collection(\"articles\").update(item_ids, updated_data)\n    updated_articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Deleting Items\n\n### Delete Single Item\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Delete an item by ID\n    await directus.collection(\"articles\").delete(\"1\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Delete Multiple Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Delete multiple items by IDs\n    await directus.collection(\"articles\").delete([\"1\", \"2\", \"3\"])\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Aggregation\n\n### Count Items\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Count all items\n    response = await directus.collection(\"articles\").aggregate(count=\"id\").read()\n    total_count = response.items[0][\"count\"][\"id\"]\n\n    print(f\"Total articles: {total_count}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Count Distinct\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Count distinct values\n    response = await directus.collection(\"articles\").aggregate(countDistinct=\"author\").read()\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Sum, Average, Min, Max\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Sum\n    response = await directus.collection(\"articles\").aggregate(sum=\"views\").read()\n    total_views = response.items[0][\"sum\"][\"views\"]\n\n    # Average\n    response = await directus.collection(\"articles\").aggregate(avg=\"views\").read()\n    avg_views = response.items[0][\"avg\"][\"views\"]\n\n    # Min\n    response = await directus.collection(\"articles\").aggregate(min=\"views\").read()\n    min_views = response.items[0][\"min\"][\"views\"]\n\n    # Max\n    response = await directus.collection(\"articles\").aggregate(max=\"views\").read()\n    max_views = response.items[0][\"max\"][\"views\"]\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Multiple Aggregations\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Chain multiple aggregations\n    response = await (\n        directus.collection(\"articles\")\n        .aggregate(count=\"id\")\n        .aggregate(sum=\"views\")\n        .aggregate(avg=\"views\")\n        .read()\n    )\n\n    result = response.items[0]\n    print(f\"Count: {result['count']['id']}\")\n    print(f\"Total views: {result['sum']['views']}\")\n    print(f\"Average views: {result['avg']['views']}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Aggregation with Agg Class\n\n```python\nfrom py_directus import Directus, Agg, AggregationOperators\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Using Agg class for aggregations\n    sum_agg = Agg(operator=AggregationOperators.Sum, fields=\"amount\")\n    avg_agg = Agg(operator=AggregationOperators.Avg, fields=\"amount\")\n\n    response = await (\n        directus.collection(\"transactions\")\n        .aggregate(sum_agg)\n        .aggregate(avg_agg)\n        .read()\n    )\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Group By\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Group by single field\n    response = await (\n        directus.collection(\"articles\")\n        .aggregate(count=\"id\")\n        .groupby(\"status\")\n        .read()\n    )\n\n    # Group by multiple fields\n    response = await (\n        directus.collection(\"articles\")\n        .aggregate(count=\"id\")\n        .aggregate(avg=\"views\")\n        .groupby(\"status\", \"author\")\n        .read()\n    )\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Working with Pydantic Models\n\n### Using Built-in Models\n\n```python\nfrom py_directus import Directus, DirectusUser\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Using DirectusUser model\n    response = await (\n        directus.collection(DirectusUser)\n        .filter(first_name=\"John\")\n        .read()\n    )\n\n    # Response items are typed as DirectusUser objects\n    user = response.item\n    print(user.email)\n    print(user.first_name)\n    print(user.last_name)\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Creating Custom Pydantic Models\n\n```python\nfrom py_directus import Directus\nfrom pydantic import BaseModel\nfrom typing import Optional\n\nclass Article(BaseModel):\n    id: Optional[str] = None\n    title: str\n    content: str\n    status: str\n    author: Optional[str] = None\n    views: int = 0\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Using custom model - collection name inferred from class name\n    response = await directus.collection(Article).read()\n    articles = response.items\n\n    # Type-safe access\n    for article in articles:\n        print(article.title)\n        print(article.status)\n\nimport asyncio\nasyncio.run(main())\n```\n\n## File Management\n\n### Upload File\n\n```python\nfrom py_directus import Directus\nimport aiofiles\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Upload a file\n    async with aiofiles.open(\"image.jpg\", \"rb\") as f:\n        file_data = await f.read()\n\n    response = await directus.upload_file(\n        data=file_data,\n        filename=\"image.jpg\",\n        title=\"My Image\",\n        folder=\"folder-uuid\"\n    )\n\n    uploaded_file = response.item\n    print(f\"Uploaded file ID: {uploaded_file['id']}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read Files\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read all files\n    response = await directus.collection(\"directus_files\").read()\n    files = response.items\n\n    # Filter image files\n    response = await (\n        directus.collection(\"directus_files\")\n        .filter(type__starts_with=\"image/\")\n        .read()\n    )\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Get File URL\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    file_id = \"file-uuid\"\n\n    # Construct file URL\n    file_url = f\"{directus.url}/assets/{file_id}\"\n\n    # With transformations (for images)\n    thumbnail_url = f\"{directus.url}/assets/{file_id}?width=300&height=300&fit=cover\"\n\nimport asyncio\nasyncio.run(main())\n```\n\n## User Management\n\n### Read Users\n\n```python\nfrom py_directus import Directus, DirectusUser\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read all users\n    response = await directus.collection(DirectusUser).read()\n    users = response.items\n\n    # Filter active users\n    response = await (\n        directus.collection(DirectusUser)\n        .filter(status=\"active\")\n        .read()\n    )\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Get Current User\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        email=\"user@example.com\",\n        password=\"password\"\n    )\n\n    # Get current authenticated user\n    response = await directus.collection(\"directus_users\").read(id=\"me\")\n    current_user = response.item\n\n    print(f\"Logged in as: {current_user['email']}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Create User\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Create a new user\n    new_user = {\n        \"email\": \"newuser@example.com\",\n        \"password\": \"secure-password\",\n        \"role\": \"role-uuid\",\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"status\": \"active\"\n    }\n\n    response = await directus.collection(\"directus_users\").create(new_user)\n    created_user = response.item\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Update User\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Update a user\n    updated_data = {\n        \"first_name\": \"Jane\",\n        \"status\": \"active\"\n    }\n\n    response = await directus.collection(\"directus_users\").update(\"user-uuid\", updated_data)\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Roles and Permissions\n\n### Read Roles\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read all roles\n    response = await directus.collection(\"directus_roles\").read()\n    roles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read Permissions\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Read permissions for a specific role\n    response = await (\n        directus.collection(\"directus_permissions\")\n        .filter(role=\"role-uuid\")\n        .read()\n    )\n    permissions = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Collections and Fields\n\n### Read Collections\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Get all collections\n    response = await directus.collection(\"directus_collections\").read()\n    collections = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Read Fields\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Get all fields for a collection\n    response = await (\n        directus.collection(\"directus_fields\")\n        .filter(collection=\"articles\")\n        .read()\n    )\n    fields = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Real-time with WebSockets\n\n### Subscribe to Collection\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Subscribe to realtime updates\n    async for message in directus.subscribe(\"articles\"):\n        print(f\"Received update: {message}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Subscribe with Authentication\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        email=\"user@example.com\",\n        password=\"password\"\n    )\n\n    # Subscribe to updates for authenticated user\n    async for message in directus.subscribe(\"articles\", uid=True):\n        event_type = message.get(\"event\")\n        data = message.get(\"data\")\n\n        if event_type == \"create\":\n            print(f\"New article created: {data}\")\n        elif event_type == \"update\":\n            print(f\"Article updated: {data}\")\n        elif event_type == \"delete\":\n            print(f\"Article deleted: {data}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Advanced Query Building\n\n### Chaining Methods\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Chain multiple query methods\n    response = await (\n        directus.collection(\"articles\")\n        .fields(\"id\", \"title\", \"author.name\", \"publish_date\")\n        .filter(status=\"published\")\n        .filter(views__gte=1000)\n        .sort(\"-publish_date\")\n        .limit(10)\n        .offset(0)\n        .search(\"directus\")\n        .read()\n    )\n\n    articles = response.items\n\nimport asyncio\nasyncio.run(main())\n```\n\n### Deep Filtering on Relations\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    # Filter based on related collection\n    response = await (\n        directus.collection(\"articles\")\n        .filter(author__status=\"active\")\n        .filter(author__verified=True)\n        .read()\n    )\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Error Handling\n\n```python\nfrom py_directus import Directus\nimport httpx\n\nasync def main():\n    try:\n        directus = await Directus(\n            url=\"https://your-directus-instance.com\",\n            token=\"your-token\"\n        )\n\n        response = await directus.collection(\"articles\").read()\n        articles = response.items\n\n    except httpx.HTTPError as e:\n        print(f\"HTTP error occurred: {e}\")\n    except Exception as e:\n        print(f\"An error occurred: {e}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\nHandle authentication errors:\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    try:\n        directus = await Directus(\n            url=\"https://your-directus-instance.com\",\n            email=\"user@example.com\",\n            password=\"wrong-password\"\n        )\n    except Exception as e:\n        print(f\"Authentication failed: {e}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Request Metadata\n\n### Access Response Metadata\n\n```python\nfrom py_directus import Directus\n\nasync def main():\n    directus = await Directus(\n        url=\"https://your-directus-instance.com\",\n        token=\"your-token\"\n    )\n\n    response = await directus.collection(\"articles\").read()\n\n    # Access items\n    articles = response.items\n\n    # Access single item (when reading by ID)\n    # article = response.item\n\n    # Check if request was successful\n    print(f\"Total items: {len(articles)}\")\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Complete Example\n\n```python\nimport os\nimport asyncio\nfrom py_directus import Directus, F\n\nasync def main():\n    # Initialize client\n    directus = await Directus(\n        url=os.getenv(\"DIRECTUS_URL\"),\n        token=os.getenv(\"DIRECTUS_TOKEN\")\n    )\n\n    # Create a new article\n    new_article = {\n        \"title\": \"Getting Started with Directus\",\n        \"content\": \"Directus is a powerful headless CMS...\",\n        \"status\": \"draft\",\n        \"author\": \"author-uuid\"\n    }\n\n    create_response = await directus.collection(\"articles\").create(new_article)\n    article_id = create_response.item[\"id\"]\n    print(f\"Created article: {article_id}\")\n\n    # Read articles with filters\n    read_response = await (\n        directus.collection(\"articles\")\n        .fields(\"id\", \"title\", \"status\", \"author.name\")\n        .filter(status=\"published\")\n        .filter(views__gte=100)\n        .sort(\"-publish_date\")\n        .limit(10)\n        .read()\n    )\n\n    articles = read_response.items\n    print(f\"Found {len(articles)} published articles\")\n\n    # Update the article\n    update_data = {\"status\": \"published\"}\n    await directus.collection(\"articles\").update(article_id, update_data)\n    print(f\"Published article: {article_id}\")\n\n    # Get statistics\n    stats_response = await (\n        directus.collection(\"articles\")\n        .aggregate(count=\"id\")\n        .aggregate(sum=\"views\")\n        .aggregate(avg=\"views\")\n        .groupby(\"status\")\n        .read()\n    )\n\n    for stat in stats_response.items:\n        print(f\"Status: {stat['status']}\")\n        print(f\"Count: {stat['count']['id']}\")\n        print(f\"Total views: {stat['sum']['views']}\")\n        print(f\"Avg views: {stat['avg']['views']}\")\n\n    # Clean up - delete the article\n    await directus.collection(\"articles\").delete(article_id)\n    print(f\"Deleted article: {article_id}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## Useful Links\n\n- Documentation: https://panos-stavrianos.github.io/py-directus/\n- GitHub Repository: https://github.com/panos-stavrianos/py-directus\n- PyPI Package: https://pypi.org/project/py-directus/\n- Directus Official Docs: https://docs.directus.io/\n- Directus REST API Reference: https://docs.directus.io/reference/introduction\n"
  },
  {
    "path": "content/dirty-equals/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"dirty-equals package guide for Python projects using declarative equality matchers in tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dirty-equals,python,testing,pytest,assertions,matchers\"\n---\n\n# dirty-equals Python Package Guide\n\n## Golden Rule\n\nUse `dirty-equals` when you need readable assertions against nested or fuzzy data in tests. Import from `dirty_equals`, keep the matcher on the right-hand side of `==`, and prefer the built-in matcher types over custom ad hoc comparison helpers.\n\nAs of March 12, 2026, PyPI lists the current release as `0.11`, while the upstream docs brand the same release line as `v0.11.0`.\n\n## Install\n\n```bash\npython -m pip install \"dirty-equals==0.11\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dirty-equals==0.11\"\npoetry add \"dirty-equals==0.11\"\n```\n\nIf you need the optional Pydantic-backed helpers such as richer URL validation, install the extra:\n\n```bash\npython -m pip install \"dirty-equals[pydantic]==0.11\"\n```\n\n## Setup And Test Runner Use\n\n`dirty-equals` is a pure Python assertion helper library. There is no client object, service auth, or runtime initialization step. Install it into the same environment as your test runner and import matchers directly where you write assertions.\n\nBasic pytest usage:\n\n```python\nfrom datetime import datetime, timezone\n\nfrom dirty_equals import IsNow, IsPartialDict, IsPositiveInt, IsStr\n\ndef test_user_payload() -> None:\n    payload = {\n        \"id\": 42,\n        \"email\": \"alex@example.com\",\n        \"created_at\": datetime.now(timezone.utc),\n        \"debug\": {\"trace_id\": \"abc123\", \"raw\": \"...\"},\n    }\n\n    assert payload == IsPartialDict(\n        id=IsPositiveInt,\n        email=IsStr(regex=r\".+@example\\.com$\"),\n        created_at=IsNow(delta=3, tz=timezone.utc),\n    )\n```\n\nUse this style when exact full-object equality would make tests brittle.\n\n## Core Matcher Patterns\n\n### Partial and strict dictionaries\n\nUse `IsPartialDict(...)` when the payload contains extra keys you do not care about. Use `IsStrictDict(...)` when key set and nested values must match exactly.\n\n```python\nfrom dirty_equals import IsPartialDict, IsStrictDict\n\nassert {\"id\": 1, \"name\": \"Ada\", \"active\": True} == IsPartialDict(name=\"Ada\")\n\nassert {\"name\": \"Ada\", \"active\": True} == IsStrictDict(\n    name=\"Ada\",\n    active=True,\n)\n```\n\n### Lists, tuples, membership, and length\n\nUse the sequence helpers instead of writing multiple index-by-index assertions.\n\n```python\nfrom dirty_equals import Contains, HasLen, IsList\n\nassert [\"alpha\", \"beta\", \"gamma\"] == Contains(\"beta\")\nassert [\"alpha\", \"beta\", \"gamma\"] == HasLen(3)\nassert [3, 2, 1] == IsList(1, 2, 3, check_order=False)\n```\n\n### Strings, JSON, and regex checks\n\n`IsStr(...)` covers substring and regex checks. `IsJson(...)` is for asserting against JSON text or bytes and comparing the decoded value.\n\n```python\nfrom dirty_equals import IsJson, IsStr\n\nassert \"job-2026-03-12.log\" == IsStr(regex=r\"^job-\\d{4}-\\d{2}-\\d{2}\\.log$\")\nassert '{\"status\":\"ok\",\"count\":2}' == IsJson({\"status\": \"ok\", \"count\": 2})\n```\n\nIf you already have a parsed Python dict, compare it directly with `IsPartialDict(...)` or `IsStrictDict(...)` instead of wrapping it in `IsJson(...)`.\n\n### Numeric, date/time, and type checks\n\nUse the built-in fuzzy or constrained matchers instead of hand-written predicates.\n\n```python\nfrom datetime import datetime, timezone\n\nfrom dirty_equals import IsApprox, IsInstance, IsNow, IsPositiveInt\n\nassert 10.01 == IsApprox(10, delta=0.1)\nassert 5 == IsPositiveInt\nassert RuntimeError(\"boom\") == IsInstance(RuntimeError)\nassert datetime.now(timezone.utc) == IsNow(tz=timezone.utc, delta=2)\n```\n\n### Compose matchers with boolean logic\n\nMatchers can be combined with `|`, `&`, and unary `~` for more precise assertions.\n\n```python\nfrom dirty_equals import IsInt, IsPositiveInt, IsStr\n\nassert 7 == (IsInt & IsPositiveInt)\nassert -1 == ~IsPositiveInt\nassert \"ok\" == (IsStr(regex=\"^ok$\") | IsInt)\n```\n\n## Configuration And Customization\n\nThere is no auth configuration. The main configuration surface is matcher construction and matcher settings.\n\n### Class-style vs instance-style matchers\n\nMany simple matchers can be used either as a class-like singleton or as an initialized matcher:\n\n```python\nfrom dirty_equals import IsPositiveInt, IsStr\n\nassert 1 == IsPositiveInt\nassert 1 == IsPositiveInt()\nassert \"abc\" == IsStr\nassert \"abc\" == IsStr(min_length=1)\n```\n\nUse an initialized matcher when you need arguments such as `regex=`, `delta=`, `tz=`, `check_order=False`, or `strict=False`.\n\n### Per-matcher settings\n\nSeveral matcher families expose a `.settings(...)` helper so you can flip defaults without rewriting the full matcher definition each time.\n\nCommon examples from the docs:\n\n- `IsList.settings(check_order=False)` for order-insensitive list checks\n- `IsDatetime.settings(enforce_tz=False)` when you explicitly want naive datetimes to pass\n\n### Custom matchers\n\nWhen the built-ins are not enough, subclass `DirtyEquals` and implement `equals`.\n\n```python\nfrom dirty_equals import DirtyEquals\n\nclass IsEven(DirtyEquals):\n    def equals(self, other: object) -> bool:\n        return isinstance(other, int) and other % 2 == 0\n\nassert 4 == IsEven()\n```\n\nKeep custom matchers narrow and test-focused. Prefer composing existing matchers first.\n\n## Common Pitfalls\n\n- The package name uses a hyphen, but the import path uses an underscore: `pip install dirty-equals`, then `from dirty_equals import ...`.\n- Put the matcher on the right side of `==`. The library overloads equality to make `actual == matcher` expressive and readable.\n- Do not treat matcher classes that require arguments as zero-config singletons. `IsApprox(10)` and `IsNow(...)` must be initialized.\n- `IsJson(...)` is for JSON text or bytes. If your code already parsed JSON into Python objects, compare those objects directly.\n- `IsNow` and the datetime matchers are timezone-aware by default unless you explicitly relax that behavior. Be deliberate about `tz=` and `enforce_tz=`.\n- `IsNumeric` cannot combine `approx` with comparison bounds like `gt`, `ge`, `lt`, or `le` in the same matcher.\n- The docs note that some repr-rich error output is best in pytest and that instantiated types can display more clearly in complex failures.\n- Upstream notes the project is not currently tested on PyPy.\n\n## Version-Sensitive Notes For 0.11\n\n- PyPI publishes the release as `0.11`; the docs header and GitHub release use `v0.11.0`. Treat them as the same release line.\n- `0.11` requires Python `>=3.9` and publishes classifiers through Python `3.14`.\n- The upstream docs were updated for the `v0.11.0` line on November 17, 2025. Prefer those docs over older blog posts that may predate the latest matcher APIs and Python version support.\n- The optional `pydantic` extra in `0.11` targets Pydantic v2-era dependencies. If you use URL helpers that lean on Pydantic types, keep the extra and your Pydantic version aligned.\n\n## Official Sources\n\n- Docs root: https://dirty-equals.helpmanual.io/latest/\n- Usage guide: https://dirty-equals.helpmanual.io/latest/\n- Dictionary matchers: https://dirty-equals.helpmanual.io/latest/types/dict/\n- Sequence matchers: https://dirty-equals.helpmanual.io/latest/types/other-sequences/\n- String matchers: https://dirty-equals.helpmanual.io/latest/types/string/\n- Inspection matchers: https://dirty-equals.helpmanual.io/latest/types/type-inspection/\n- Other matchers: https://dirty-equals.helpmanual.io/latest/types/other/\n- Numeric matchers: https://dirty-equals.helpmanual.io/latest/types/numeric/\n- Datetime matchers: https://dirty-equals.helpmanual.io/latest/types/dates-times/\n- PyPI metadata: https://pypi.org/project/dirty-equals/\n- Repository metadata: https://github.com/samuelcolvin/dirty-equals/blob/main/pyproject.toml\n"
  },
  {
    "path": "content/discord/docs/bot/javascript/DOC.md",
    "content": "---\nname: bot\ndescription: \"Discord.js SDK for building Discord bots with slash commands and gateway events in JavaScript/TypeScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"14.24.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"discord,bot,slash-commands,gateway,sdk\"\n---\n\n# Discord.js JavaScript/TypeScript SDK Coding Guidelines\n\nYou are a Discord.js coding expert. Help me with writing code using the Discord API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://discord.js.org/docs/packages/discord.js/14.24.0\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the discord.js library to interact with the Discord API, which is the standard library for all Discord bot interactions in JavaScript/TypeScript. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** discord.js\n- **NPM Package:** `discord.js`\n- **Current Version:** 14.24.0 (v14)\n- **Legacy Libraries:** discord.js v12, discord.js v13 are outdated and not recommended\n\n**Installation:**\n\n- **Correct:** `npm install discord.js`\n\n**APIs and Usage:**\n\n- **Correct:** `import { Client, GatewayIntentBits, Events } from 'discord.js'`\n- **Correct:** `const client = new Client({ intents: [...] })`\n- **Correct:** `client.on(Events.MessageCreate, ...)`\n- **Correct:** `interaction.reply(...)`\n- **Incorrect:** `Discord.Client` (use `Client` instead)\n- **Incorrect:** `client.on('message', ...)` (use `client.on(Events.MessageCreate, ...)`)\n- **Incorrect:** `MessageEmbed` (use `EmbedBuilder` in v14)\n\n## Installation\n\nInstall discord.js using npm:\n\n```bash\nnpm install discord.js\n```\n\n**Environment Variables:**\n\nCreate a `.env` file with your bot token:\n\n```env\nDISCORD_TOKEN=your_bot_token_here\nCLIENT_ID=your_application_id_here\nGUILD_ID=your_test_server_id_here\n```\n\nInstall dotenv to load environment variables:\n\n```bash\nnpm install dotenv\n```\n\n## Initialization\n\nThe `discord.js` library requires creating a `Client` instance with appropriate intents.\n\n```javascript\nimport { Client, GatewayIntentBits } from 'discord.js';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst client = new Client({\n  intents: [\n    GatewayIntentBits.Guilds,\n    GatewayIntentBits.GuildMessages,\n    GatewayIntentBits.MessageContent,\n    GatewayIntentBits.GuildMembers,\n  ],\n});\n\nclient.login(process.env.DISCORD_TOKEN);\n```\n\n### Gateway Intents\n\nIntents are named groups of pre-defined WebSocket events that your bot will receive. You must specify the intents your bot needs.\n\n**Common Intents:**\n\n- `GatewayIntentBits.Guilds` - Guild-related events (required for most bots)\n- `GatewayIntentBits.GuildMessages` - Message events in guilds\n- `GatewayIntentBits.MessageContent` - Access to message content (privileged)\n- `GatewayIntentBits.GuildMembers` - Member join/leave events (privileged)\n- `GatewayIntentBits.GuildPresences` - Presence updates (privileged)\n- `GatewayIntentBits.DirectMessages` - DM events\n\n**Privileged Intents:**\n\nFor `MessageContent`, `GuildMembers`, and `GuildPresences`, you must enable them in the Discord Developer Portal under your application's Bot settings.\n\n```javascript\nconst client = new Client({\n  intents: [\n    GatewayIntentBits.Guilds,\n    GatewayIntentBits.GuildMessages,\n    GatewayIntentBits.MessageContent, // Privileged - enable in Developer Portal\n  ],\n});\n```\n\n## Basic Bot Setup\n\n### Ready Event\n\nThe `Ready` event fires when the bot successfully connects to Discord:\n\n```javascript\nimport { Client, GatewayIntentBits, Events } from 'discord.js';\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds],\n});\n\nclient.once(Events.ClientReady, (readyClient) => {\n  console.log(`Logged in as ${readyClient.user.tag}`);\n});\n\nclient.login(process.env.DISCORD_TOKEN);\n```\n\n### Message Events\n\nListen to messages in channels:\n\n```javascript\nimport { Client, GatewayIntentBits, Events } from 'discord.js';\n\nconst client = new Client({\n  intents: [\n    GatewayIntentBits.Guilds,\n    GatewayIntentBits.GuildMessages,\n    GatewayIntentBits.MessageContent,\n  ],\n});\n\nclient.on(Events.MessageCreate, (message) => {\n  // Ignore messages from bots\n  if (message.author.bot) return;\n\n  if (message.content === '!ping') {\n    message.reply('Pong!');\n  }\n});\n\nclient.login(process.env.DISCORD_TOKEN);\n```\n\n## Slash Commands\n\nSlash commands are the primary way to interact with Discord bots. They provide a better user experience with autocomplete and validation.\n\n### Registering Slash Commands\n\nCreate a separate file to register commands with Discord's API:\n\n```javascript\nimport { REST, Routes, SlashCommandBuilder } from 'discord.js';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst commands = [\n  new SlashCommandBuilder()\n    .setName('ping')\n    .setDescription('Replies with Pong!')\n    .toJSON(),\n  new SlashCommandBuilder()\n    .setName('user')\n    .setDescription('Get info about a user')\n    .addUserOption((option) =>\n      option\n        .setName('target')\n        .setDescription('The user')\n        .setRequired(true)\n    )\n    .toJSON(),\n  new SlashCommandBuilder()\n    .setName('server')\n    .setDescription('Get info about the server')\n    .toJSON(),\n];\n\nconst rest = new REST().setToken(process.env.DISCORD_TOKEN);\n\n(async () => {\n  try {\n    console.log(`Started refreshing ${commands.length} application (/) commands.`);\n\n    // Register commands globally (takes up to 1 hour to propagate)\n    const data = await rest.put(\n      Routes.applicationCommands(process.env.CLIENT_ID),\n      { body: commands }\n    );\n\n    // OR register to a specific guild (instant update - for testing)\n    // const data = await rest.put(\n    //   Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),\n    //   { body: commands }\n    // );\n\n    console.log(`Successfully reloaded ${data.length} application (/) commands.`);\n  } catch (error) {\n    console.error(error);\n  }\n})();\n```\n\n### Handling Slash Command Interactions\n\n```javascript\nimport { Client, GatewayIntentBits, Events } from 'discord.js';\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds],\n});\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isChatInputCommand()) return;\n\n  if (interaction.commandName === 'ping') {\n    await interaction.reply('Pong!');\n  } else if (interaction.commandName === 'user') {\n    const user = interaction.options.getUser('target');\n    await interaction.reply(`User: ${user.tag}, ID: ${user.id}`);\n  } else if (interaction.commandName === 'server') {\n    await interaction.reply(\n      `Server: ${interaction.guild.name}, Members: ${interaction.guild.memberCount}`\n    );\n  }\n});\n\nclient.login(process.env.DISCORD_TOKEN);\n```\n\n### Advanced Slash Command Options\n\n```javascript\nnew SlashCommandBuilder()\n  .setName('echo')\n  .setDescription('Echoes your message')\n  .addStringOption((option) =>\n    option\n      .setName('message')\n      .setDescription('The message to echo')\n      .setRequired(true)\n      .setMaxLength(2000)\n  )\n  .addBooleanOption((option) =>\n    option\n      .setName('ephemeral')\n      .setDescription('Should the reply be private?')\n      .setRequired(false)\n  )\n  .addIntegerOption((option) =>\n    option\n      .setName('number')\n      .setDescription('A number')\n      .setMinValue(1)\n      .setMaxValue(100)\n  )\n  .addChannelOption((option) =>\n    option\n      .setName('channel')\n      .setDescription('Select a channel')\n  )\n  .addRoleOption((option) =>\n    option\n      .setName('role')\n      .setDescription('Select a role')\n  )\n  .toJSON()\n```\n\n### Choices in Slash Commands\n\nAdd predefined choices to string or number options:\n\n```javascript\nnew SlashCommandBuilder()\n  .setName('choose')\n  .setDescription('Choose an option')\n  .addStringOption((option) =>\n    option\n      .setName('option')\n      .setDescription('Select an option')\n      .setRequired(true)\n      .addChoices(\n        { name: 'Option A', value: 'option_a' },\n        { name: 'Option B', value: 'option_b' },\n        { name: 'Option C', value: 'option_c' }\n      )\n  )\n  .toJSON()\n```\n\n### Autocomplete\n\nEnable autocomplete for dynamic options:\n\n```javascript\n// In command definition\nnew SlashCommandBuilder()\n  .setName('search')\n  .setDescription('Search for something')\n  .addStringOption((option) =>\n    option\n      .setName('query')\n      .setDescription('Search query')\n      .setRequired(true)\n      .setAutocomplete(true)\n  )\n  .toJSON()\n\n// In interaction handler\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (interaction.isAutocomplete()) {\n    const focusedValue = interaction.options.getFocused();\n\n    // Fetch or generate choices based on focusedValue\n    const choices = ['apple', 'banana', 'cherry', 'date', 'elderberry'];\n    const filtered = choices.filter((choice) =>\n      choice.startsWith(focusedValue.toLowerCase())\n    );\n\n    await interaction.respond(\n      filtered.map((choice) => ({ name: choice, value: choice }))\n    );\n  }\n});\n```\n\n## Embeds\n\nEmbeds allow you to send rich, formatted messages with images, fields, and more.\n\n### Basic Embed\n\n```javascript\nimport { EmbedBuilder } from 'discord.js';\n\nconst embed = new EmbedBuilder()\n  .setTitle('Embed Title')\n  .setDescription('This is an embed description')\n  .setColor(0x0099ff)\n  .setTimestamp()\n  .setFooter({ text: 'Footer text' });\n\nawait interaction.reply({ embeds: [embed] });\n```\n\n### Advanced Embed\n\n```javascript\nimport { EmbedBuilder } from 'discord.js';\n\nconst embed = new EmbedBuilder()\n  .setColor('#0099ff')\n  .setTitle('Advanced Embed')\n  .setURL('https://discord.js.org')\n  .setAuthor({\n    name: 'Author Name',\n    iconURL: 'https://i.imgur.com/AfFp7pu.png',\n    url: 'https://discord.js.org',\n  })\n  .setDescription('Some description here')\n  .setThumbnail('https://i.imgur.com/AfFp7pu.png')\n  .addFields(\n    { name: 'Regular field title', value: 'Some value here' },\n    { name: '\\u200B', value: '\\u200B' }, // Blank field\n    { name: 'Inline field title', value: 'Some value here', inline: true },\n    { name: 'Inline field title', value: 'Some value here', inline: true }\n  )\n  .addFields({ name: 'Inline field title', value: 'Some value here', inline: true })\n  .setImage('https://i.imgur.com/AfFp7pu.png')\n  .setTimestamp()\n  .setFooter({\n    text: 'Some footer text here',\n    iconURL: 'https://i.imgur.com/AfFp7pu.png',\n  });\n\nawait channel.send({ embeds: [embed] });\n```\n\n### Embed Colors\n\n```javascript\n// Hexadecimal\n.setColor('#0099ff')\n\n// Integer\n.setColor(0x0099ff)\n\n// RGB array\n.setColor([0, 153, 255])\n\n// Predefined colors\nimport { Colors } from 'discord.js';\n.setColor(Colors.Blue)\n.setColor(Colors.Red)\n.setColor(Colors.Green)\n```\n\n## Buttons\n\nButtons are interactive components that users can click.\n\n### Basic Button\n\n```javascript\nimport { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new ButtonBuilder()\n      .setCustomId('primary')\n      .setLabel('Click me!')\n      .setStyle(ButtonStyle.Primary)\n  );\n\nawait interaction.reply({\n  content: 'Click a button!',\n  components: [row],\n});\n```\n\n### Multiple Buttons\n\n```javascript\nimport { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new ButtonBuilder()\n      .setCustomId('primary')\n      .setLabel('Primary')\n      .setStyle(ButtonStyle.Primary),\n    new ButtonBuilder()\n      .setCustomId('secondary')\n      .setLabel('Secondary')\n      .setStyle(ButtonStyle.Secondary),\n    new ButtonBuilder()\n      .setCustomId('success')\n      .setLabel('Success')\n      .setStyle(ButtonStyle.Success),\n    new ButtonBuilder()\n      .setCustomId('danger')\n      .setLabel('Danger')\n      .setStyle(ButtonStyle.Danger)\n  );\n\nawait interaction.reply({\n  content: 'Choose a button!',\n  components: [row],\n});\n```\n\n### Link Button\n\n```javascript\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new ButtonBuilder()\n      .setLabel('Visit Website')\n      .setURL('https://discord.js.org')\n      .setStyle(ButtonStyle.Link)\n  );\n```\n\n### Handling Button Interactions\n\n```javascript\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isButton()) return;\n\n  if (interaction.customId === 'primary') {\n    await interaction.reply({ content: 'You clicked Primary!', ephemeral: true });\n  } else if (interaction.customId === 'danger') {\n    await interaction.reply({ content: 'Danger button clicked!', ephemeral: true });\n  }\n});\n```\n\n### Disabled Buttons\n\n```javascript\nnew ButtonBuilder()\n  .setCustomId('disabled')\n  .setLabel('Disabled')\n  .setStyle(ButtonStyle.Primary)\n  .setDisabled(true)\n```\n\n## Select Menus\n\nSelect menus (dropdowns) allow users to choose from multiple options.\n\n### String Select Menu\n\n```javascript\nimport { ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new StringSelectMenuBuilder()\n      .setCustomId('select')\n      .setPlaceholder('Make a selection!')\n      .addOptions(\n        new StringSelectMenuOptionBuilder()\n          .setLabel('Option 1')\n          .setDescription('This is option 1')\n          .setValue('option_1'),\n        new StringSelectMenuOptionBuilder()\n          .setLabel('Option 2')\n          .setDescription('This is option 2')\n          .setValue('option_2'),\n        new StringSelectMenuOptionBuilder()\n          .setLabel('Option 3')\n          .setDescription('This is option 3')\n          .setValue('option_3')\n      )\n  );\n\nawait interaction.reply({\n  content: 'Choose an option:',\n  components: [row],\n});\n```\n\n### Handling Select Menu Interactions\n\n```javascript\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isStringSelectMenu()) return;\n\n  if (interaction.customId === 'select') {\n    const selected = interaction.values[0];\n    await interaction.reply({ content: `You selected: ${selected}`, ephemeral: true });\n  }\n});\n```\n\n### User Select Menu\n\n```javascript\nimport { UserSelectMenuBuilder } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new UserSelectMenuBuilder()\n      .setCustomId('user_select')\n      .setPlaceholder('Select a user')\n      .setMinValues(1)\n      .setMaxValues(3)\n  );\n```\n\n### Role Select Menu\n\n```javascript\nimport { RoleSelectMenuBuilder } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new RoleSelectMenuBuilder()\n      .setCustomId('role_select')\n      .setPlaceholder('Select a role')\n  );\n```\n\n### Channel Select Menu\n\n```javascript\nimport { ChannelSelectMenuBuilder, ChannelType } from 'discord.js';\n\nconst row = new ActionRowBuilder()\n  .addComponents(\n    new ChannelSelectMenuBuilder()\n      .setCustomId('channel_select')\n      .setPlaceholder('Select a channel')\n      .addChannelTypes(ChannelType.GuildText, ChannelType.GuildVoice)\n  );\n```\n\n## Modals\n\nModals are pop-up forms that allow users to submit text input.\n\n### Creating a Modal\n\n```javascript\nimport { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js';\n\nconst modal = new ModalBuilder()\n  .setCustomId('feedback_modal')\n  .setTitle('Feedback Form');\n\nconst nameInput = new TextInputBuilder()\n  .setCustomId('name_input')\n  .setLabel('What is your name?')\n  .setStyle(TextInputStyle.Short)\n  .setRequired(true);\n\nconst feedbackInput = new TextInputBuilder()\n  .setCustomId('feedback_input')\n  .setLabel('Your feedback')\n  .setStyle(TextInputStyle.Paragraph)\n  .setPlaceholder('Tell us what you think!')\n  .setRequired(true)\n  .setMaxLength(1000);\n\nconst firstActionRow = new ActionRowBuilder().addComponents(nameInput);\nconst secondActionRow = new ActionRowBuilder().addComponents(feedbackInput);\n\nmodal.addComponents(firstActionRow, secondActionRow);\n\nawait interaction.showModal(modal);\n```\n\n### Handling Modal Submissions\n\n```javascript\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isModalSubmit()) return;\n\n  if (interaction.customId === 'feedback_modal') {\n    const name = interaction.fields.getTextInputValue('name_input');\n    const feedback = interaction.fields.getTextInputValue('feedback_input');\n\n    await interaction.reply({\n      content: `Thank you for your feedback, ${name}!`,\n      ephemeral: true,\n    });\n  }\n});\n```\n\n## Context Menus\n\nContext menus appear when right-clicking on a user or message.\n\n### User Context Menu\n\n```javascript\nimport { ContextMenuCommandBuilder, ApplicationCommandType } from 'discord.js';\n\nconst command = new ContextMenuCommandBuilder()\n  .setName('Get User Info')\n  .setType(ApplicationCommandType.User)\n  .toJSON();\n```\n\n### Message Context Menu\n\n```javascript\nconst command = new ContextMenuCommandBuilder()\n  .setName('Report Message')\n  .setType(ApplicationCommandType.Message)\n  .toJSON();\n```\n\n### Handling Context Menu Interactions\n\n```javascript\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isContextMenuCommand()) return;\n\n  if (interaction.commandName === 'Get User Info') {\n    const user = interaction.targetUser;\n    await interaction.reply({\n      content: `User: ${user.tag}, ID: ${user.id}`,\n      ephemeral: true,\n    });\n  } else if (interaction.commandName === 'Report Message') {\n    const message = interaction.targetMessage;\n    await interaction.reply({\n      content: `Reported message from ${message.author.tag}`,\n      ephemeral: true,\n    });\n  }\n});\n```\n\n## Sending Messages\n\n### Reply to Interaction\n\n```javascript\n// Regular reply\nawait interaction.reply('Hello!');\n\n// Ephemeral reply (only visible to user)\nawait interaction.reply({ content: 'Secret message!', ephemeral: true });\n\n// Reply with embed\nawait interaction.reply({ embeds: [embed] });\n\n// Reply with buttons\nawait interaction.reply({ content: 'Click!', components: [row] });\n```\n\n### Send Message to Channel\n\n```javascript\n// Get channel by ID\nconst channel = client.channels.cache.get('channel_id');\nawait channel.send('Hello, channel!');\n\n// From interaction\nawait interaction.channel.send('Message in this channel!');\n```\n\n### Edit Reply\n\n```javascript\nawait interaction.reply('Original message');\nawait interaction.editReply('Edited message');\n```\n\n### Follow-up Messages\n\n```javascript\nawait interaction.reply('First message');\nawait interaction.followUp('Second message');\nawait interaction.followUp({ content: 'Third message', ephemeral: true });\n```\n\n### Deferred Replies\n\nFor long-running operations:\n\n```javascript\nawait interaction.deferReply();\n// Do long operation...\nawait interaction.editReply('Done!');\n\n// Or defer with ephemeral\nawait interaction.deferReply({ ephemeral: true });\n```\n\n## Permissions\n\n### Check User Permissions\n\n```javascript\nif (interaction.member.permissions.has(PermissionFlagsBits.Administrator)) {\n  await interaction.reply('You are an admin!');\n}\n\nimport { PermissionFlagsBits } from 'discord.js';\n\nif (interaction.member.permissions.has(PermissionFlagsBits.ManageMessages)) {\n  // User can manage messages\n}\n```\n\n### Command Permissions\n\n```javascript\nnew SlashCommandBuilder()\n  .setName('admin')\n  .setDescription('Admin only command')\n  .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)\n  .toJSON()\n```\n\n### Check Bot Permissions\n\n```javascript\nconst botMember = interaction.guild.members.me;\nif (botMember.permissions.has(PermissionFlagsBits.ManageRoles)) {\n  // Bot can manage roles\n}\n```\n\n## Events\n\n### Common Events\n\n```javascript\nimport { Events } from 'discord.js';\n\n// Bot ready\nclient.once(Events.ClientReady, (c) => {\n  console.log(`Ready! Logged in as ${c.user.tag}`);\n});\n\n// Message created\nclient.on(Events.MessageCreate, (message) => {\n  console.log(`Message: ${message.content}`);\n});\n\n// Interaction created\nclient.on(Events.InteractionCreate, (interaction) => {\n  console.log(`Interaction: ${interaction.type}`);\n});\n\n// Guild member added\nclient.on(Events.GuildMemberAdd, (member) => {\n  console.log(`${member.user.tag} joined ${member.guild.name}`);\n});\n\n// Guild member removed\nclient.on(Events.GuildMemberRemove, (member) => {\n  console.log(`${member.user.tag} left ${member.guild.name}`);\n});\n\n// Message deleted\nclient.on(Events.MessageDelete, (message) => {\n  console.log(`Message deleted: ${message.content}`);\n});\n\n// Message updated\nclient.on(Events.MessageUpdate, (oldMessage, newMessage) => {\n  console.log(`Message edited from \"${oldMessage.content}\" to \"${newMessage.content}\"`);\n});\n```\n\n## Fetching Data\n\n### Fetch User\n\n```javascript\nconst user = await client.users.fetch('user_id');\nconsole.log(user.tag);\n```\n\n### Fetch Member\n\n```javascript\nconst member = await interaction.guild.members.fetch('user_id');\nconsole.log(member.displayName);\n```\n\n### Fetch Channel\n\n```javascript\nconst channel = await client.channels.fetch('channel_id');\nawait channel.send('Hello!');\n```\n\n### Fetch Guild\n\n```javascript\nconst guild = await client.guilds.fetch('guild_id');\nconsole.log(guild.name);\n```\n\n### Fetch Messages\n\n```javascript\n// Fetch last 10 messages\nconst messages = await channel.messages.fetch({ limit: 10 });\n\n// Fetch specific message\nconst message = await channel.messages.fetch('message_id');\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\nclient.on(Events.InteractionCreate, async (interaction) => {\n  try {\n    if (interaction.isChatInputCommand()) {\n      // Handle command\n      await interaction.reply('Success!');\n    }\n  } catch (error) {\n    console.error(error);\n\n    if (interaction.replied || interaction.deferred) {\n      await interaction.followUp({\n        content: 'There was an error executing this command!',\n        ephemeral: true,\n      });\n    } else {\n      await interaction.reply({\n        content: 'There was an error executing this command!',\n        ephemeral: true,\n      });\n    }\n  }\n});\n```\n\n### Common Errors\n\n```javascript\n// Unknown Interaction\nif (interaction.isRepliable() && !interaction.replied) {\n  try {\n    await interaction.reply('...');\n  } catch (error) {\n    if (error.code === 10062) {\n      console.log('Unknown interaction - likely expired');\n    }\n  }\n}\n\n// Missing Permissions\ncatch (error) {\n  if (error.code === 50013) {\n    console.log('Missing permissions');\n  }\n}\n\n// Unknown Channel\ncatch (error) {\n  if (error.code === 10003) {\n    console.log('Unknown channel');\n  }\n}\n```\n\n## Command Handler Structure\n\nOrganize commands into separate files:\n\n```javascript\n// commands/ping.js\nimport { SlashCommandBuilder } from 'discord.js';\n\nexport const data = new SlashCommandBuilder()\n  .setName('ping')\n  .setDescription('Replies with Pong!');\n\nexport async function execute(interaction) {\n  await interaction.reply('Pong!');\n}\n```\n\n```javascript\n// index.js\nimport { Client, Collection, GatewayIntentBits, Events } from 'discord.js';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { readdirSync } from 'fs';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds],\n});\n\nclient.commands = new Collection();\n\nconst commandsPath = join(__dirname, 'commands');\nconst commandFiles = readdirSync(commandsPath).filter((file) => file.endsWith('.js'));\n\nfor (const file of commandFiles) {\n  const filePath = join(commandsPath, file);\n  const command = await import(filePath);\n\n  if ('data' in command && 'execute' in command) {\n    client.commands.set(command.data.name, command);\n  }\n}\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n  if (!interaction.isChatInputCommand()) return;\n\n  const command = client.commands.get(interaction.commandName);\n\n  if (!command) {\n    console.error(`No command matching ${interaction.commandName} was found.`);\n    return;\n  }\n\n  try {\n    await command.execute(interaction);\n  } catch (error) {\n    console.error(error);\n\n    const errorMessage = {\n      content: 'There was an error while executing this command!',\n      ephemeral: true,\n    };\n\n    if (interaction.replied || interaction.deferred) {\n      await interaction.followUp(errorMessage);\n    } else {\n      await interaction.reply(errorMessage);\n    }\n  }\n});\n\nclient.login(process.env.DISCORD_TOKEN);\n```\n\n## Advanced Features\n\n### Collectors\n\nCollect button or select menu interactions:\n\n```javascript\nconst filter = (i) => i.customId === 'primary' && i.user.id === interaction.user.id;\nconst collector = interaction.channel.createMessageComponentCollector({\n  filter,\n  time: 60000, // 1 minute\n});\n\ncollector.on('collect', async (i) => {\n  await i.update({ content: 'Button clicked!', components: [] });\n});\n\ncollector.on('end', (collected) => {\n  console.log(`Collected ${collected.size} interactions.`);\n});\n```\n\n### Reactions\n\n```javascript\nconst message = await channel.send('React to this!');\nawait message.react('👍');\nawait message.react('👎');\n\n// Reaction collector\nconst filter = (reaction, user) => {\n  return reaction.emoji.name === '👍' && user.id === interaction.user.id;\n};\n\nconst collector = message.createReactionCollector({ filter, time: 60000 });\n\ncollector.on('collect', (reaction, user) => {\n  console.log(`${user.tag} reacted with ${reaction.emoji.name}`);\n});\n```\n\n### Threads\n\n```javascript\n// Create thread from message\nconst thread = await message.startThread({\n  name: 'Thread Name',\n  autoArchiveDuration: 60,\n});\n\n// Create thread in channel\nconst thread = await channel.threads.create({\n  name: 'New Thread',\n  autoArchiveDuration: 60,\n  reason: 'Discussion thread',\n});\n\n// Send message to thread\nawait thread.send('Hello in thread!');\n```\n\n### Voice Connections\n\nFor voice support, install `@discordjs/voice`:\n\n```bash\nnpm install @discordjs/voice\n```\n\n```javascript\nimport { joinVoiceChannel } from '@discordjs/voice';\n\nconst connection = joinVoiceChannel({\n  channelId: channel.id,\n  guildId: channel.guild.id,\n  adapterCreator: channel.guild.voiceAdapterCreator,\n});\n```\n\n## Useful Links\n\n- Documentation: https://discord.js.org/docs/packages/discord.js/14.24.0\n- Guide: https://discordjs.guide/\n- Discord API Docs: https://discord.com/developers/docs\n- Developer Portal: https://discord.com/developers/applications\n- Community Server: https://discord.gg/djs\n"
  },
  {
    "path": "content/discord/docs/bot/python/DOC.md",
    "content": "---\nname: bot\ndescription: \"Discord.py SDK for building Discord bots with slash commands and gateway events in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.4\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"discord,bot,slash-commands,gateway,sdk\"\n---\n\n# Discord.py Python SDK Coding Guidelines\n\nYou are a discord.py coding expert. Help me with writing code using the Discord API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://discordpy.readthedocs.io/en/stable/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the discord.py library to interact with the Discord API, which is the standard library for all Discord bot interactions in Python. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** discord.py\n- **PyPI Package:** `discord.py`\n- **Current Version:** 2.6.4\n- **Legacy Libraries:** discord.py v1.x is outdated and not recommended\n\n**Installation:**\n\n- **Correct:** `pip install discord.py`\n- **Correct (with voice support):** `pip install discord.py[voice]`\n\n**APIs and Usage:**\n\n- **Correct:** `import discord`\n- **Correct:** `from discord.ext import commands`\n- **Correct:** `bot = commands.Bot(command_prefix='!', intents=intents)`\n- **Correct:** `@bot.command()`\n- **Correct:** `await interaction.response.send_message(...)`\n- **Incorrect:** `discord.Client()` without intents (use `discord.Client(intents=intents)`)\n- **Incorrect:** `@client.event` in cogs (use `@commands.Cog.listener()`)\n\n## Installation\n\nInstall discord.py using pip:\n\n```bash\npip install discord.py\n```\n\n**With Voice Support:**\n\n```bash\npip install discord.py[voice]\n```\n\n**Environment Variables:**\n\nCreate a `.env` file with your bot token:\n\n```env\nDISCORD_TOKEN=your_bot_token_here\n```\n\nInstall python-dotenv to load environment variables:\n\n```bash\npip install python-dotenv\n```\n\n## Initialization\n\nThe `discord.py` library requires creating a bot with appropriate intents.\n\n```python\nimport discord\nfrom discord.ext import commands\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nintents = discord.Intents.default()\nintents.message_content = True\nintents.members = True\n\nbot = commands.Bot(command_prefix='!', intents=intents)\n\nbot.run(os.getenv('DISCORD_TOKEN'))\n```\n\n### Intents\n\nIntents specify which events your bot will receive from Discord. You must explicitly enable intents.\n\n**Common Intents:**\n\n```python\nintents = discord.Intents.default()\nintents.message_content = True  # Privileged - enable in Developer Portal\nintents.members = True           # Privileged - enable in Developer Portal\nintents.presences = True         # Privileged - enable in Developer Portal\nintents.guilds = True\nintents.messages = True\nintents.reactions = True\n```\n\n**All Intents (for development):**\n\n```python\nintents = discord.Intents.all()\n```\n\n**Minimal Intents:**\n\n```python\nintents = discord.Intents.default()\n```\n\n**Privileged Intents:**\n\nFor `message_content`, `members`, and `presences`, you must enable them in the Discord Developer Portal under your application's Bot settings.\n\n## Basic Bot Setup\n\n### Using Commands Extension\n\nThe recommended way to build bots:\n\n```python\nimport discord\nfrom discord.ext import commands\nimport os\n\nintents = discord.Intents.default()\nintents.message_content = True\n\nbot = commands.Bot(command_prefix='!', intents=intents)\n\n@bot.event\nasync def on_ready():\n    print(f'{bot.user} has connected to Discord!')\n\n@bot.command()\nasync def ping(ctx):\n    await ctx.send('Pong!')\n\nbot.run(os.getenv('DISCORD_TOKEN'))\n```\n\n### Using Client Only\n\nFor simpler bots without commands:\n\n```python\nimport discord\nimport os\n\nintents = discord.Intents.default()\nintents.message_content = True\n\nclient = discord.Client(intents=intents)\n\n@client.event\nasync def on_ready():\n    print(f'{client.user} has logged in!')\n\n@client.event\nasync def on_message(message):\n    if message.author == client.user:\n        return\n\n    if message.content.startswith('!hello'):\n        await message.channel.send('Hello!')\n\nclient.run(os.getenv('DISCORD_TOKEN'))\n```\n\n## Commands\n\n### Basic Command\n\n```python\n@bot.command()\nasync def hello(ctx):\n    await ctx.send(f'Hello {ctx.author.mention}!')\n```\n\n### Command with Arguments\n\n```python\n@bot.command()\nasync def say(ctx, *, message: str):\n    await ctx.send(message)\n\n@bot.command()\nasync def add(ctx, a: int, b: int):\n    await ctx.send(f'{a} + {b} = {a + b}')\n```\n\n### Command with Optional Arguments\n\n```python\n@bot.command()\nasync def greet(ctx, name: str = None):\n    if name is None:\n        await ctx.send(f'Hello {ctx.author.name}!')\n    else:\n        await ctx.send(f'Hello {name}!')\n```\n\n### Command Aliases\n\n```python\n@bot.command(aliases=['p'])\nasync def ping(ctx):\n    await ctx.send('Pong!')\n```\n\n### Command with Description\n\n```python\n@bot.command(\n    name='info',\n    description='Get bot information',\n    help='Displays information about the bot'\n)\nasync def info(ctx):\n    await ctx.send('This is my Discord bot!')\n```\n\n### Converters\n\n```python\n@bot.command()\nasync def kick(ctx, member: discord.Member, *, reason: str = 'No reason provided'):\n    await member.kick(reason=reason)\n    await ctx.send(f'{member.mention} has been kicked.')\n\n@bot.command()\nasync def ban(ctx, user: discord.User, *, reason: str = None):\n    await ctx.guild.ban(user, reason=reason)\n    await ctx.send(f'{user.mention} has been banned.')\n```\n\n## Slash Commands (Application Commands)\n\nSlash commands provide a better user experience with autocomplete and validation.\n\n### Basic Slash Command\n\n```python\nimport discord\nfrom discord import app_commands\n\nintents = discord.Intents.default()\nclient = discord.Client(intents=intents)\ntree = app_commands.CommandTree(client)\n\n@tree.command(name='ping', description='Replies with Pong!')\nasync def ping(interaction: discord.Interaction):\n    await interaction.response.send_message('Pong!')\n\n@client.event\nasync def on_ready():\n    await tree.sync()\n    print(f'{client.user} is ready!')\n\nclient.run(os.getenv('DISCORD_TOKEN'))\n```\n\n### Slash Command with Parameters\n\n```python\n@tree.command(name='greet', description='Greet a user')\n@app_commands.describe(user='The user to greet', message='Custom greeting message')\nasync def greet(interaction: discord.Interaction, user: discord.Member, message: str = 'Hello'):\n    await interaction.response.send_message(f'{message}, {user.mention}!')\n```\n\n### Slash Command with Choices\n\n```python\n@tree.command(name='color', description='Choose a color')\n@app_commands.describe(color='Your favorite color')\n@app_commands.choices(color=[\n    app_commands.Choice(name='Red', value='red'),\n    app_commands.Choice(name='Blue', value='blue'),\n    app_commands.Choice(name='Green', value='green'),\n])\nasync def color(interaction: discord.Interaction, color: app_commands.Choice[str]):\n    await interaction.response.send_message(f'You chose {color.name}!')\n```\n\n### Autocomplete\n\n```python\nasync def fruit_autocomplete(\n    interaction: discord.Interaction,\n    current: str,\n) -> list[app_commands.Choice[str]]:\n    fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']\n    return [\n        app_commands.Choice(name=fruit, value=fruit)\n        for fruit in fruits if current.lower() in fruit.lower()\n    ]\n\n@tree.command(name='fruit', description='Choose a fruit')\n@app_commands.autocomplete(fruit=fruit_autocomplete)\nasync def fruit(interaction: discord.Interaction, fruit: str):\n    await interaction.response.send_message(f'You chose: {fruit}')\n```\n\n### Hybrid Commands\n\nHybrid commands work as both slash commands and text commands:\n\n```python\nfrom discord.ext import commands\n\nbot = commands.Bot(command_prefix='!', intents=intents)\n\n@bot.hybrid_command(name='ping', description='Check bot latency')\nasync def ping(ctx):\n    await ctx.send(f'Pong! Latency: {round(bot.latency * 1000)}ms')\n\n@bot.event\nasync def on_ready():\n    await bot.tree.sync()\n    print(f'{bot.user} is ready!')\n\nbot.run(os.getenv('DISCORD_TOKEN'))\n```\n\n## Embeds\n\nEmbeds allow you to send rich, formatted messages.\n\n### Basic Embed\n\n```python\nembed = discord.Embed(\n    title='Embed Title',\n    description='This is an embed description',\n    color=discord.Color.blue()\n)\nawait ctx.send(embed=embed)\n```\n\n### Advanced Embed\n\n```python\nembed = discord.Embed(\n    title='Advanced Embed',\n    description='This is a detailed embed',\n    color=0x00ff00,\n    url='https://discordpy.readthedocs.io/',\n    timestamp=discord.utils.utcnow()\n)\n\nembed.set_author(\n    name='Author Name',\n    url='https://discordpy.readthedocs.io/',\n    icon_url='https://i.imgur.com/AfFp7pu.png'\n)\nembed.set_thumbnail(url='https://i.imgur.com/AfFp7pu.png')\nembed.set_image(url='https://i.imgur.com/AfFp7pu.png')\n\nembed.add_field(name='Field 1', value='Value 1', inline=True)\nembed.add_field(name='Field 2', value='Value 2', inline=True)\nembed.add_field(name='Field 3', value='Value 3', inline=False)\n\nembed.set_footer(text='Footer text', icon_url='https://i.imgur.com/AfFp7pu.png')\n\nawait ctx.send(embed=embed)\n```\n\n### Embed Colors\n\n```python\n# Using Color class\nembed.color = discord.Color.red()\nembed.color = discord.Color.blue()\nembed.color = discord.Color.green()\nembed.color = discord.Color.gold()\n\n# Using hex\nembed.color = 0x00ff00\n\n# Using RGB\nembed.color = discord.Color.from_rgb(255, 0, 0)\n```\n\n## Buttons\n\nButtons are interactive UI components.\n\n### Basic Button\n\n```python\nimport discord\nfrom discord.ui import Button, View\n\nclass MyView(View):\n    @discord.ui.button(label='Click me!', style=discord.ButtonStyle.primary)\n    async def button_callback(self, interaction: discord.Interaction, button: Button):\n        await interaction.response.send_message('Button clicked!', ephemeral=True)\n\n@bot.command()\nasync def buttons(ctx):\n    view = MyView()\n    await ctx.send('Click a button:', view=view)\n```\n\n### Multiple Buttons\n\n```python\nclass MyView(View):\n    @discord.ui.button(label='Primary', style=discord.ButtonStyle.primary)\n    async def primary(self, interaction: discord.Interaction, button: Button):\n        await interaction.response.send_message('Primary clicked!', ephemeral=True)\n\n    @discord.ui.button(label='Secondary', style=discord.ButtonStyle.secondary)\n    async def secondary(self, interaction: discord.Interaction, button: Button):\n        await interaction.response.send_message('Secondary clicked!', ephemeral=True)\n\n    @discord.ui.button(label='Success', style=discord.ButtonStyle.success)\n    async def success(self, interaction: discord.Interaction, button: Button):\n        await interaction.response.send_message('Success clicked!', ephemeral=True)\n\n    @discord.ui.button(label='Danger', style=discord.ButtonStyle.danger)\n    async def danger(self, interaction: discord.Interaction, button: Button):\n        await interaction.response.send_message('Danger clicked!', ephemeral=True)\n\n@bot.command()\nasync def buttons(ctx):\n    view = MyView()\n    await ctx.send('Choose a button:', view=view)\n```\n\n### Link Button\n\n```python\nview = View()\nbutton = Button(label='Visit Website', url='https://discordpy.readthedocs.io/')\nview.add_item(button)\n\nawait ctx.send('Visit our docs:', view=view)\n```\n\n### Disabled Button\n\n```python\n@discord.ui.button(label='Disabled', style=discord.ButtonStyle.primary, disabled=True)\nasync def disabled_button(self, interaction: discord.Interaction, button: Button):\n    pass\n```\n\n### Button with Emoji\n\n```python\n@discord.ui.button(label='Like', style=discord.ButtonStyle.primary, emoji='👍')\nasync def like_button(self, interaction: discord.Interaction, button: Button):\n    await interaction.response.send_message('Thanks!', ephemeral=True)\n```\n\n## Select Menus\n\nSelect menus (dropdowns) allow users to choose from multiple options.\n\n### String Select Menu\n\n```python\nimport discord\nfrom discord.ui import Select, View\n\nclass MyView(View):\n    @discord.ui.select(\n        placeholder='Choose an option...',\n        options=[\n            discord.SelectOption(label='Option 1', description='This is option 1', value='1'),\n            discord.SelectOption(label='Option 2', description='This is option 2', value='2'),\n            discord.SelectOption(label='Option 3', description='This is option 3', value='3'),\n        ]\n    )\n    async def select_callback(self, interaction: discord.Interaction, select: Select):\n        await interaction.response.send_message(f'You selected: {select.values[0]}', ephemeral=True)\n\n@bot.command()\nasync def dropdown(ctx):\n    view = MyView()\n    await ctx.send('Choose an option:', view=view)\n```\n\n### User Select Menu\n\n```python\nclass MyView(View):\n    @discord.ui.select(cls=discord.ui.UserSelect, placeholder='Select a user')\n    async def user_select(self, interaction: discord.Interaction, select: discord.ui.UserSelect):\n        user = select.values[0]\n        await interaction.response.send_message(f'You selected: {user.mention}', ephemeral=True)\n```\n\n### Role Select Menu\n\n```python\nclass MyView(View):\n    @discord.ui.select(cls=discord.ui.RoleSelect, placeholder='Select a role')\n    async def role_select(self, interaction: discord.Interaction, select: discord.ui.RoleSelect):\n        role = select.values[0]\n        await interaction.response.send_message(f'You selected: {role.mention}', ephemeral=True)\n```\n\n### Channel Select Menu\n\n```python\nclass MyView(View):\n    @discord.ui.select(\n        cls=discord.ui.ChannelSelect,\n        placeholder='Select a channel',\n        channel_types=[discord.ChannelType.text, discord.ChannelType.voice]\n    )\n    async def channel_select(self, interaction: discord.Interaction, select: discord.ui.ChannelSelect):\n        channel = select.values[0]\n        await interaction.response.send_message(f'You selected: {channel.mention}', ephemeral=True)\n```\n\n## Modals\n\nModals are pop-up forms for user input.\n\n### Basic Modal\n\n```python\nimport discord\nfrom discord.ui import Modal, TextInput\n\nclass FeedbackModal(Modal, title='Feedback Form'):\n    name = TextInput(label='Name', placeholder='Your name here...', required=True)\n    feedback = TextInput(\n        label='Feedback',\n        style=discord.TextStyle.paragraph,\n        placeholder='Tell us what you think...',\n        required=True,\n        max_length=1000\n    )\n\n    async def on_submit(self, interaction: discord.Interaction):\n        await interaction.response.send_message(\n            f'Thanks for your feedback, {self.name.value}!',\n            ephemeral=True\n        )\n\n@bot.command()\nasync def feedback(ctx):\n    await ctx.send('Click the button to give feedback!')\n\n# To show modal from button\nclass FeedbackView(discord.ui.View):\n    @discord.ui.button(label='Give Feedback', style=discord.ButtonStyle.primary)\n    async def feedback_button(self, interaction: discord.Interaction, button: discord.ui.Button):\n        await interaction.response.send_modal(FeedbackModal())\n\n@bot.command()\nasync def feedback(ctx):\n    view = FeedbackView()\n    await ctx.send('Click to provide feedback:', view=view)\n```\n\n### Modal from Slash Command\n\n```python\n@tree.command(name='feedback', description='Provide feedback')\nasync def feedback_slash(interaction: discord.Interaction):\n    await interaction.response.send_modal(FeedbackModal())\n```\n\n## Context Menus\n\nContext menus appear when right-clicking on users or messages.\n\n### User Context Menu\n\n```python\n@tree.context_menu(name='Get User Info')\nasync def user_info(interaction: discord.Interaction, user: discord.Member):\n    await interaction.response.send_message(\n        f'User: {user.name}\\nID: {user.id}\\nJoined: {user.joined_at}',\n        ephemeral=True\n    )\n```\n\n### Message Context Menu\n\n```python\n@tree.context_menu(name='Report Message')\nasync def report_message(interaction: discord.Interaction, message: discord.Message):\n    await interaction.response.send_message(\n        f'Reported message from {message.author.mention}',\n        ephemeral=True\n    )\n```\n\n## Events\n\n### Common Events\n\n```python\n@bot.event\nasync def on_ready():\n    print(f'{bot.user} has connected to Discord!')\n    print(f'Bot ID: {bot.user.id}')\n\n@bot.event\nasync def on_message(message):\n    if message.author == bot.user:\n        return\n\n    if 'hello' in message.content.lower():\n        await message.channel.send('Hello!')\n\n    # Important: process commands after custom on_message logic\n    await bot.process_commands(message)\n\n@bot.event\nasync def on_member_join(member):\n    channel = member.guild.system_channel\n    if channel is not None:\n        await channel.send(f'Welcome {member.mention}!')\n\n@bot.event\nasync def on_member_remove(member):\n    channel = member.guild.system_channel\n    if channel is not None:\n        await channel.send(f'{member.name} has left the server.')\n\n@bot.event\nasync def on_message_delete(message):\n    print(f'Message deleted: {message.content}')\n\n@bot.event\nasync def on_message_edit(before, after):\n    print(f'Message edited from \"{before.content}\" to \"{after.content}\"')\n\n@bot.event\nasync def on_reaction_add(reaction, user):\n    print(f'{user.name} added {reaction.emoji}')\n\n@bot.event\nasync def on_guild_join(guild):\n    print(f'Joined guild: {guild.name}')\n\n@bot.event\nasync def on_error(event, *args, **kwargs):\n    print(f'Error in {event}')\n```\n\n## Cogs\n\nCogs organize commands and listeners into modular classes.\n\n### Basic Cog\n\n```python\nfrom discord.ext import commands\n\nclass MyCog(commands.Cog):\n    def __init__(self, bot):\n        self.bot = bot\n\n    @commands.command()\n    async def hello(self, ctx):\n        await ctx.send('Hello from cog!')\n\n    @commands.Cog.listener()\n    async def on_message(self, message):\n        if message.author == self.bot.user:\n            return\n        print(f'Message from {message.author}: {message.content}')\n\nasync def setup(bot):\n    await bot.add_cog(MyCog(bot))\n```\n\n### Loading Cogs\n\n```python\nimport asyncio\n\nasync def load_extensions():\n    for filename in os.listdir('./cogs'):\n        if filename.endswith('.py'):\n            await bot.load_extension(f'cogs.{filename[:-3]}')\n\nasync def main():\n    async with bot:\n        await load_extensions()\n        await bot.start(os.getenv('DISCORD_TOKEN'))\n\nasyncio.run(main())\n```\n\n### Cog with Slash Commands\n\n```python\nfrom discord import app_commands\n\nclass SlashCog(commands.Cog):\n    def __init__(self, bot):\n        self.bot = bot\n\n    @app_commands.command(name='ping', description='Ping command')\n    async def ping(self, interaction: discord.Interaction):\n        await interaction.response.send_message('Pong!')\n\n    @commands.Cog.listener()\n    async def on_ready(self):\n        print(f'{self.__class__.__name__} cog is ready!')\n\nasync def setup(bot):\n    await bot.add_cog(SlashCog(bot))\n```\n\n## Permissions\n\n### Check User Permissions\n\n```python\n@bot.command()\n@commands.has_permissions(administrator=True)\nasync def admin(ctx):\n    await ctx.send('You are an admin!')\n\n@bot.command()\n@commands.has_permissions(manage_messages=True)\nasync def purge(ctx, amount: int):\n    await ctx.channel.purge(limit=amount + 1)\n    await ctx.send(f'Deleted {amount} messages.', delete_after=5)\n```\n\n### Check Bot Permissions\n\n```python\n@bot.command()\n@commands.bot_has_permissions(manage_roles=True)\nasync def mute(ctx, member: discord.Member):\n    # Bot can manage roles\n    await ctx.send(f'{member.mention} has been muted.')\n```\n\n### Custom Permission Checks\n\n```python\ndef is_owner():\n    async def predicate(ctx):\n        return ctx.author.id == 123456789  # Your user ID\n    return commands.check(predicate)\n\n@bot.command()\n@is_owner()\nasync def secret(ctx):\n    await ctx.send('Secret command for owner only!')\n```\n\n### Slash Command Permissions\n\n```python\n@tree.command(name='admin', description='Admin only command')\n@app_commands.default_permissions(administrator=True)\nasync def admin_slash(interaction: discord.Interaction):\n    await interaction.response.send_message('Admin command!', ephemeral=True)\n```\n\n## Error Handling\n\n### Command Error Handling\n\n```python\n@bot.event\nasync def on_command_error(ctx, error):\n    if isinstance(error, commands.MissingRequiredArgument):\n        await ctx.send('Missing required argument!')\n    elif isinstance(error, commands.MissingPermissions):\n        await ctx.send(\"You don't have permission to use this command!\")\n    elif isinstance(error, commands.BotMissingPermissions):\n        await ctx.send(\"I don't have permission to do that!\")\n    elif isinstance(error, commands.CommandNotFound):\n        pass  # Ignore command not found\n    else:\n        print(f'Error: {error}')\n```\n\n### Local Error Handler\n\n```python\n@bot.command()\nasync def divide(ctx, a: int, b: int):\n    result = a / b\n    await ctx.send(f'{a} / {b} = {result}')\n\n@divide.error\nasync def divide_error(ctx, error):\n    if isinstance(error, commands.BadArgument):\n        await ctx.send('Please provide valid numbers!')\n    elif isinstance(error, ZeroDivisionError):\n        await ctx.send(\"Cannot divide by zero!\")\n```\n\n### Interaction Error Handling\n\n```python\n@tree.error\nasync def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError):\n    if isinstance(error, app_commands.CommandOnCooldown):\n        await interaction.response.send_message(\n            f'Command is on cooldown. Try again in {error.retry_after:.2f}s',\n            ephemeral=True\n        )\n    elif isinstance(error, app_commands.MissingPermissions):\n        await interaction.response.send_message(\n            \"You don't have permission to use this command!\",\n            ephemeral=True\n        )\n    else:\n        await interaction.response.send_message('An error occurred!', ephemeral=True)\n```\n\n## Cooldowns\n\n### Command Cooldown\n\n```python\nfrom discord.ext import commands\n\n@bot.command()\n@commands.cooldown(1, 60, commands.BucketType.user)  # 1 use per 60 seconds per user\nasync def daily(ctx):\n    await ctx.send('You claimed your daily reward!')\n\n@daily.error\nasync def daily_error(ctx, error):\n    if isinstance(error, commands.CommandOnCooldown):\n        await ctx.send(f'Try again in {error.retry_after:.2f} seconds.')\n```\n\n### Slash Command Cooldown\n\n```python\n@tree.command(name='daily', description='Claim daily reward')\n@app_commands.checks.cooldown(1, 60, key=lambda i: i.user.id)\nasync def daily_slash(interaction: discord.Interaction):\n    await interaction.response.send_message('Daily reward claimed!', ephemeral=True)\n```\n\n## Fetching Data\n\n### Fetch User\n\n```python\nuser = await bot.fetch_user(123456789)\nprint(user.name)\n```\n\n### Fetch Member\n\n```python\nmember = await ctx.guild.fetch_member(123456789)\nprint(member.display_name)\n```\n\n### Fetch Channel\n\n```python\nchannel = await bot.fetch_channel(123456789)\nawait channel.send('Hello!')\n```\n\n### Fetch Guild\n\n```python\nguild = await bot.fetch_guild(123456789)\nprint(guild.name)\n```\n\n### Fetch Messages\n\n```python\n# Fetch last 10 messages\nmessages = [message async for message in channel.history(limit=10)]\n\n# Fetch specific message\nmessage = await channel.fetch_message(123456789)\n```\n\n## Sending Messages\n\n### Basic Send\n\n```python\nawait ctx.send('Hello!')\nawait channel.send('Hello!')\n```\n\n### Send with Embed\n\n```python\nembed = discord.Embed(title='Title', description='Description')\nawait ctx.send(embed=embed)\n```\n\n### Send with Components\n\n```python\nview = MyView()\nawait ctx.send('Click a button:', view=view)\n```\n\n### Send Ephemeral (Slash Commands)\n\n```python\nawait interaction.response.send_message('Secret message!', ephemeral=True)\n```\n\n### Send File\n\n```python\nfile = discord.File('path/to/file.png')\nawait ctx.send(file=file)\n\n# With embed\nembed = discord.Embed(title='Image')\nembed.set_image(url='attachment://file.png')\nawait ctx.send(embed=embed, file=file)\n```\n\n### Edit Message\n\n```python\nmessage = await ctx.send('Original message')\nawait message.edit(content='Edited message')\n```\n\n### Delete Message\n\n```python\nmessage = await ctx.send('This will be deleted')\nawait message.delete()\n\n# Delete after delay\nawait ctx.send('Deleted in 5s', delete_after=5)\n```\n\n## Reactions\n\n### Add Reaction\n\n```python\nmessage = await ctx.send('React to this!')\nawait message.add_reaction('👍')\nawait message.add_reaction('👎')\n```\n\n### Remove Reaction\n\n```python\nawait message.remove_reaction('👍', ctx.author)\n```\n\n### Clear Reactions\n\n```python\nawait message.clear_reactions()\n```\n\n### Wait for Reaction\n\n```python\nmessage = await ctx.send('React with 👍')\nawait message.add_reaction('👍')\n\ndef check(reaction, user):\n    return user == ctx.author and str(reaction.emoji) == '👍'\n\ntry:\n    reaction, user = await bot.wait_for('reaction_add', timeout=60.0, check=check)\n    await ctx.send('Thanks for reacting!')\nexcept asyncio.TimeoutError:\n    await ctx.send('You took too long!')\n```\n\n## Tasks and Loops\n\n### Basic Loop\n\n```python\nfrom discord.ext import tasks\n\n@tasks.loop(seconds=60)\nasync def my_task():\n    channel = bot.get_channel(123456789)\n    await channel.send('This runs every minute!')\n\n@my_task.before_loop\nasync def before_my_task():\n    await bot.wait_until_ready()\n\nmy_task.start()\n```\n\n### Loop with Time\n\n```python\nimport datetime\n\n@tasks.loop(time=datetime.time(hour=12, minute=0))\nasync def daily_task():\n    channel = bot.get_channel(123456789)\n    await channel.send('Daily message at noon!')\n\ndaily_task.start()\n```\n\n### Cancel Loop\n\n```python\nmy_task.stop()\n```\n\n## Voice\n\n### Join Voice Channel\n\n```python\n@bot.command()\nasync def join(ctx):\n    if ctx.author.voice:\n        channel = ctx.author.voice.channel\n        await channel.connect()\n    else:\n        await ctx.send('You are not in a voice channel!')\n```\n\n### Leave Voice Channel\n\n```python\n@bot.command()\nasync def leave(ctx):\n    if ctx.voice_client:\n        await ctx.voice_client.disconnect()\n    else:\n        await ctx.send('I am not in a voice channel!')\n```\n\n### Play Audio\n\n```python\nimport discord\nfrom discord import FFmpegPCMAudio\n\n@bot.command()\nasync def play(ctx):\n    if ctx.voice_client:\n        source = FFmpegPCMAudio('audio.mp3')\n        ctx.voice_client.play(source)\n    else:\n        await ctx.send('Bot is not in a voice channel!')\n```\n\n## Advanced Features\n\n### Paginator\n\n```python\nfrom discord.ext import menus\n\nclass MySource(menus.ListPageSource):\n    def __init__(self, data):\n        super().__init__(data, per_page=10)\n\n    async def format_page(self, menu, entries):\n        offset = menu.current_page * self.per_page\n        return '\\n'.join(f'{i}. {v}' for i, v in enumerate(entries, start=offset))\n\n@bot.command()\nasync def pages(ctx):\n    data = [f'Item {i}' for i in range(1, 100)]\n    pages = menus.MenuPages(source=MySource(data))\n    await pages.start(ctx)\n```\n\n### Wait For Message\n\n```python\n@bot.command()\nasync def ask(ctx):\n    await ctx.send('What is your name?')\n\n    def check(m):\n        return m.author == ctx.author and m.channel == ctx.channel\n\n    try:\n        msg = await bot.wait_for('message', check=check, timeout=30.0)\n        await ctx.send(f'Hello {msg.content}!')\n    except asyncio.TimeoutError:\n        await ctx.send('You took too long!')\n```\n\n### Webhooks\n\n```python\n# Create webhook\nwebhook = await channel.create_webhook(name='My Webhook')\n\n# Send via webhook\nawait webhook.send('Message from webhook!', username='Custom Name')\n\n# Get webhooks\nwebhooks = await channel.webhooks()\nfor webhook in webhooks:\n    print(webhook.name)\n```\n\n## Useful Links\n\n- Documentation: https://discordpy.readthedocs.io/en/stable/\n- API Reference: https://discordpy.readthedocs.io/en/stable/api.html\n- Discord API Docs: https://discord.com/developers/docs\n- Developer Portal: https://discord.com/developers/applications\n- GitHub: https://github.com/Rapptz/discord.py\n"
  },
  {
    "path": "content/diskcache/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"diskcache Python package guide for local persistent caching, TTL-based lookups, memoization, and multi-worker cache access\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.6.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"diskcache,python,caching,sqlite,persistence,memoization\"\n---\n\n# diskcache Python Package Guide\n\n## Golden Rule\n\nUse `diskcache` when you need a local, disk-backed cache with a dictionary-like API. Start with `Cache` for normal application caching, and switch to `FanoutCache` when multiple worker processes will write to the same cache directory.\n\n`diskcache` is a local library, not a hosted service: there are no API keys or remote endpoints to configure. The main setup decision is choosing a writable cache directory that matches your deployment model.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"diskcache==5.6.3\"\n```\n\n## Configure A Cache Directory\n\nUse an environment variable so local development, containers, and production can each choose an appropriate writable path:\n\n```bash\nexport DISKCACHE_DIR=\"./.cache/diskcache\"\n```\n\nIn production, point `DISKCACHE_DIR` at a persistent directory owned by the app user.\n\n## Initialize The Cache\n\n```python\nimport os\nfrom diskcache import Cache\n\nCACHE_DIR = os.getenv(\"DISKCACHE_DIR\", \"./.cache/diskcache\")\n\ncache = Cache(CACHE_DIR)\n```\n\nClose the cache cleanly during shutdown:\n\n```python\ncache.close()\n```\n\n## Common Workflows\n\n### Store and read values with TTL\n\n```python\nimport os\nfrom diskcache import Cache\n\ncache = Cache(os.getenv(\"DISKCACHE_DIR\", \"./.cache/diskcache\"))\n\ncache.set(\"user:42\", {\"id\": 42, \"name\": \"Ada\"}, expire=300)\nuser = cache.get(\"user:42\")\n\nif user is None:\n    user = {\"id\": 42, \"name\": \"Ada\"}\n    cache.set(\"user:42\", user, expire=300)\n\nprint(user[\"name\"])\ncache.close()\n```\n\n`expire` is in seconds. Use `get()` with a default when cache misses are expected:\n\n```python\ncount = cache.get(\"pageviews\", default=0)\n```\n\n### Use dictionary-style access\n\n`Cache` supports dictionary-style reads and writes for simple cases:\n\n```python\nfrom diskcache import Cache\n\ncache = Cache(\"./.cache/diskcache\")\n\ncache[\"healthcheck\"] = \"ok\"\n\nif \"healthcheck\" in cache:\n    print(cache[\"healthcheck\"])\n\ndel cache[\"healthcheck\"]\ncache.close()\n```\n\nUse `set(..., expire=...)` instead of item assignment when you need TTLs or other write options.\n\n### Memoize expensive function calls\n\nUse the built-in decorator when function inputs map cleanly to cached outputs:\n\n```python\nimport os\nfrom diskcache import Cache\n\ncache = Cache(os.getenv(\"DISKCACHE_DIR\", \"./.cache/diskcache\"))\n\n@cache.memoize(expire=60)\ndef load_profile(user_id: int) -> dict:\n    print(\"cache miss\")\n    return {\"id\": user_id, \"name\": f\"user-{user_id}\"}\n\nprint(load_profile(42))\nprint(load_profile(42))\n\ncache.close()\n```\n\nThis is the simplest way to cache repeated reads from a database, filesystem, or slow local computation.\n\n### Use `FanoutCache` for multi-worker writes\n\nIf your app uses multiple worker processes and they all write into the same cache directory, prefer `FanoutCache`:\n\n```python\nimport os\nfrom diskcache import FanoutCache\n\ncache = FanoutCache(\n    os.getenv(\"DISKCACHE_DIR\", \"./.cache/diskcache\"),\n    shards=8,\n    timeout=1,\n)\n\ncache.set(\"job:123\", \"queued\", expire=600)\nstatus = cache.get(\"job:123\")\n\nprint(status)\ncache.close()\n```\n\nStart with the default behavior unless you know your workload needs different shard counts. Reach for `FanoutCache` when background workers, task queues, or prefork web servers share one cache path.\n\n### Remove expired entries during maintenance\n\nIf your application uses many TTL-based keys, run expiration cleanup as part of a maintenance path:\n\n```python\nfrom diskcache import Cache\n\ncache = Cache(\"./.cache/diskcache\")\ncache.expire()\ncache.close()\n```\n\nTo remove everything and start over:\n\n```python\ncache.clear()\n```\n\n## Important Pitfalls\n\n- Choose the cache directory deliberately. A relative path is fine for local development, but production containers often need an explicit persistent volume or writable app data directory.\n- Use `FanoutCache` instead of `Cache` when many worker processes will write concurrently to the same location.\n- Prefer `set()` and `get()` in application code when you need TTLs, defaults, or more explicit cache behavior. Dictionary syntax is convenient, but it is easier to miss expiration behavior there.\n- Cached values are Python objects stored locally. Treat the cache directory as application data and avoid sharing it across trust boundaries.\n- Call `close()` on shutdown in long-running processes so file handles and SQLite resources are released cleanly.\n\n## Version Notes For 5.6.3\n\n- The examples here pin `diskcache==5.6.3` because that is the target package version for this doc.\n- `diskcache` is intentionally local-first. If you actually need a remote shared cache across hosts, use a networked cache service instead of trying to stretch one on-disk directory across machines.\n\n## Official Sources\n\n- Maintainer docs: https://grantjenks.com/docs/diskcache/\n- PyPI package: https://pypi.org/project/diskcache/\n"
  },
  {
    "path": "content/django/docs/allauth/python/DOC.md",
    "content": "---\nname: allauth\ndescription: \"django-allauth package guide for Django account, email, MFA, and social authentication in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"65.15.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,authentication,accounts,social-login,oauth,oidc,mfa\"\n---\n\n# django-allauth Python Package Guide\n\n## What This Package Is\n\n`django-allauth` adds account management, email flows, MFA, and social login on top of Django's auth system.\n\n- Package: `django-allauth`\n- Main apps: `allauth`, `allauth.account`, `allauth.socialaccount`\n- Version covered here: `65.15.0`\n- Docs root: `https://docs.allauth.org/en/latest/`\n- Registry URL: `https://pypi.org/project/django-allauth/`\n\nUse it when you want Django-managed signup, login, logout, password reset, email confirmation, and OAuth/OIDC provider login without building those flows yourself.\n\n## Install\n\nFor account management only:\n\n```bash\npip install django-allauth==65.15.0\n```\n\nFor social login support:\n\n```bash\npip install \"django-allauth[socialaccount]==65.15.0\"\n```\n\nUpstream drift matters here:\n\n- PyPI currently lists `65.15.0` as the latest release and requires Python `>=3.10`.\n- The latest docs requirements page still says Python `3.8+` and Django `4.2+`.\n- The `65.15.0` release notes explicitly say support for Python `3.8` and `3.9` was dropped.\n\nFor installation constraints, trust PyPI metadata and the `65.15.0` release notes over older docs pages.\n\n## Minimal Django Setup\n\nStart with the official quickstart wiring. The current setup needs the request context processor, the allauth authentication backend, and `AccountMiddleware`.\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"allauth\",\n    \"allauth.account\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n    \"allauth.account.middleware.AccountMiddleware\",\n]\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"DIRS\": [],\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"django.template.context_processors.request\",\n                \"django.contrib.auth.context_processors.auth\",\n                \"django.contrib.messages.context_processors.messages\",\n            ],\n        },\n    },\n]\n\nAUTHENTICATION_BACKENDS = [\n    \"django.contrib.auth.backends.ModelBackend\",\n    \"allauth.account.auth_backends.AuthenticationBackend\",\n]\n\nLOGIN_REDIRECT_URL = \"/\"\n```\n\nAdd the URLconf:\n\n```python\n# urls.py\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"accounts/\", include(\"allauth.urls\")),\n]\n```\n\nThen run migrations:\n\n```bash\npython manage.py migrate\n```\n\nNotes:\n\n- If you only need standard browser-based account flows, this setup is enough to start with `/accounts/login/`, `/accounts/signup/`, `/accounts/logout/`, and password reset views.\n\n## Core Usage Pattern\n\nFor normal Django apps, let allauth own the account flow and keep app code centered on `request.user`.\n\n```python\n# views.py\nfrom django.contrib.auth.decorators import login_required\nfrom django.shortcuts import render\n\n@login_required\ndef dashboard(request):\n    return render(request, \"dashboard.html\", {\"user\": request.user})\n```\n\nTypical flow:\n\n1. User signs up or logs in through `/accounts/`.\n2. allauth authenticates the Django user and manages email/password flows.\n3. Your app uses Django auth normally: `request.user`, permissions, groups, and decorators.\n4. Override templates under `templates/account/` or `templates/socialaccount/` instead of replacing allauth views unless you need a custom auth protocol.\n\n## Account Configuration That Matters First\n\nThe current docs use newer setting names. Prefer these settings instead of older blog posts and pre-65.4 examples.\n\n```python\n# settings.py\nACCOUNT_LOGIN_METHODS = {\"email\"}\nACCOUNT_SIGNUP_FIELDS = [\"email*\", \"password1*\", \"password2*\"]\nACCOUNT_EMAIL_VERIFICATION = \"mandatory\"\nACCOUNT_RATE_LIMITS = {\n    \"login\": \"30/m/ip\",\n}\n```\n\nGuidance:\n\n- `ACCOUNT_LOGIN_METHODS` replaced the older `ACCOUNT_AUTHENTICATION_METHOD` setting.\n- `ACCOUNT_SIGNUP_FIELDS` replaced older boolean-style signup field settings. Fields marked with `*` are required.\n- `ACCOUNT_EMAIL_VERIFICATION = \"mandatory\"` is the simplest production default if login should depend on confirmed email.\n- `ACCOUNT_RATE_LIMITS` is enabled by default; override it only when you need different limits for login, signup, password reset, or verification code flows.\n- Keep login methods and signup fields aligned. If you only allow email login, collect email at signup.\n\n## Social Login Setup\n\nAdd social auth only after the base account flow works.\n\n```python\n# settings.py\nINSTALLED_APPS += [\n    \"allauth.socialaccount\",\n    \"allauth.socialaccount.providers.google\",\n]\n```\n\nCurrent provider configuration can live in settings or in the Django admin `SocialApp` model.\n\nSettings-based configuration is the easiest path for agents:\n\n```python\n# settings.py\nSOCIALACCOUNT_PROVIDERS = {\n    \"google\": {\n        \"APPS\": [\n            {\n                \"client_id\": \"your-client-id\",\n                \"secret\": \"your-client-secret\",\n                \"settings\": {\n                    \"scope\": [\"profile\", \"email\"],\n                    \"auth_params\": {\"access_type\": \"online\"},\n                },\n            }\n        ]\n    }\n}\n\nSOCIALACCOUNT_LOGIN_ON_GET = False\n```\n\nPractical rules:\n\n- Register the callback URL exactly as allauth expects, for example `/accounts/google/login/callback/`.\n- Keep `SOCIALACCOUNT_LOGIN_ON_GET = False` so login initiation is not a GET side effect.\n- If you use the Django admin `SocialApp` model instead of settings, add `django.contrib.sites`, set `SITE_ID`, and attach the app to the correct site.\n- Do not configure the same provider in both `SOCIALACCOUNT_PROVIDERS` and `SocialApp` for the same site unless you want lookup conflicts such as `MultipleObjectsReturned`.\n\n## Adapters and Custom Rules\n\nUse adapters when you need business rules around signup, redirects, or provider data.\n\n```python\n# users/adapters.py\nfrom allauth.account.adapter import DefaultAccountAdapter\n\nclass AccountAdapter(DefaultAccountAdapter):\n    def is_open_for_signup(self, request):\n        return request.get_host().endswith(\".example.com\")\n```\n\n```python\n# settings.py\nACCOUNT_ADAPTER = \"users.adapters.AccountAdapter\"\n```\n\nUse:\n\n- `ACCOUNT_ADAPTER` for account signup and email flow customization\n- `SOCIALACCOUNT_ADAPTER` for provider-specific account linking and social signup rules\n\n## Common Pitfalls\n\n- Missing `allauth.account.middleware.AccountMiddleware`. Current allauth expects it.\n- Missing `django.template.context_processors.request`. The quickstart includes it because templates and flows depend on request context.\n- Copying older examples that use `ACCOUNT_AUTHENTICATION_METHOD` or older signup field flags. Current releases use `ACCOUNT_LOGIN_METHODS` and `ACCOUNT_SIGNUP_FIELDS`.\n- Adding social login before the base account flow works. Debug local email/password first, then provider auth.\n- Registering the wrong callback URL with Google, GitHub, or another provider.\n- Configuring the provider in both Django settings and `SocialApp` for the same site.\n- If you use `SocialApp`, forgetting `django.contrib.sites`, `SITE_ID`, or site association.\n- Assuming Django admin login is automatically protected by allauth's MFA and rate limiting. The admin login view is separate; use allauth's `secure_admin_login` support if you need that coverage.\n- Using a dummy cache or incorrect proxy/IP setup with rate limits. Rate limiting depends on cache and correct client IP detection.\n\n## Version-Sensitive Notes For `65.15.0`\n\n- `65.15.0` dropped support for Python `3.8` and `3.9`. PyPI now requires Python `>=3.10`.\n- The docs requirements page still says Python `3.8+`, so treat that page as stale for this release line.\n- `65.15.0` changed the human-facing authentication code format to RFC 8628 style (`ABC-DEF`) and added `ACCOUNT_LOGIN_BY_CODE_MAX_ATTEMPTS`.\n- `65.14.2` changed proxy/IP handling to distrust `X-Forwarded-For` by default. If you deploy behind proxies or load balancers, review client IP configuration before relying on rate limits.\n- `65.13.0` made the headless feature require the `headless` extra.\n- `65.5.0` introduced `ACCOUNT_SIGNUP_FIELDS` and code-based password reset settings.\n- `65.4.0` replaced `ACCOUNT_AUTHENTICATION_METHOD` with `ACCOUNT_LOGIN_METHODS`.\n- The latest release notes page currently labels the `65.15.0` section with `2025-03-09`, while the PyPI release page shows the release on March 9, 2026. Treat PyPI as authoritative for release timing and install metadata.\n\n## Recommended Agent Workflow\n\n1. Confirm whether the project needs plain Django account flows, social login, MFA, or headless APIs.\n2. Wire the minimal Django setup first and verify `/accounts/login/` works locally.\n3. Add `ACCOUNT_LOGIN_METHODS`, `ACCOUNT_SIGNUP_FIELDS`, and email verification settings before custom templates.\n4. Add one provider at a time and verify its callback URL and site binding before layering on more providers.\n5. If deployment uses proxies, validate rate-limit client IP behavior before assuming brute-force protections are working.\n6. When examples disagree, prefer the current release notes and PyPI metadata over older docs pages and third-party tutorials.\n\n## Official Sources Used\n\n- Docs root: `https://docs.allauth.org/en/latest/`\n- Quickstart: `https://docs.allauth.org/en/latest/installation/quickstart.html`\n- Requirements: `https://docs.allauth.org/en/latest/installation/requirements.html`\n- Account configuration: `https://docs.allauth.org/en/latest/account/configuration.html`\n- Account rate limits: `https://docs.allauth.org/en/latest/account/rate_limits.html`\n- Social account configuration: `https://docs.allauth.org/en/latest/socialaccount/configuration.html`\n- Social provider configuration: `https://docs.allauth.org/en/latest/socialaccount/provider_configuration.html`\n- Google provider docs: `https://docs.allauth.org/en/latest/socialaccount/providers/google.html`\n- Admin security docs: `https://docs.allauth.org/en/latest/common/admin.html`\n- Recent release notes: `https://docs.allauth.org/en/latest/release-notes/recent.html`\n- PyPI package page: `https://pypi.org/project/django-allauth/`\n"
  },
  {
    "path": "content/django/docs/axes/python/DOC.md",
    "content": "---\nname: axes\ndescription: \"django-axes login lockout and failed-auth tracking for Django projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,axes,authentication,security,login,lockout\"\n---\n\n# Django Axes Python Package Guide\n\n## Golden Rule\n\nUse `django-axes` only in authentication flows that call Django `authenticate()` and `login()` or emit the same auth signals themselves. Put `axes.backends.AxesStandaloneBackend` first in `AUTHENTICATION_BACKENDS`, put `axes.middleware.AxesMiddleware` last in `MIDDLEWARE`, and make client IP resolution explicit when you run behind proxies.\n\n## Install\n\nInstall the package with the optional `ipware` extra unless you already plan to provide a custom client-IP callable:\n\n```bash\npython -m pip install \"django-axes[ipware]==8.3.1\"\n```\n\nWithout the extra:\n\n```bash\npython -m pip install \"django-axes==8.3.1\"\n```\n\nUse the plain package only if you will set `AXES_CLIENT_IP_CALLABLE` yourself.\n\n## Minimal Setup\n\n`django-axes` becomes active through Django settings plus a database migration.\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"axes\",\n]\n\nAUTHENTICATION_BACKENDS = [\n    \"axes.backends.AxesStandaloneBackend\",\n    \"django.contrib.auth.backends.ModelBackend\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n    \"axes.middleware.AxesMiddleware\",\n]\n```\n\nThen validate the config and create the tables:\n\n```bash\npython manage.py check\npython manage.py migrate\n```\n\nNotes:\n\n- `AxesStandaloneBackend` should be first in `AUTHENTICATION_BACKENDS`.\n- `AxesMiddleware` should be last in `MIDDLEWARE`.\n- `AxesBackend` still exists for backward compatibility, but upstream recommends `AxesStandaloneBackend` if you have custom permission logic.\n- `python manage.py check` is worth running in CI because Axes includes system checks for security-sensitive misconfiguration.\n\n## Auth Flow And Core Usage\n\nAxes monitors Django authentication by listening to:\n\n- `user_logged_in`\n- `user_logged_out`\n- `user_login_failed`\n\nIf your login flow uses Django’s normal `authenticate()` and `login()`, those signals are handled for you. If you use custom JSON login views or a nonstandard auth layer, you must emit the expected signals yourself or Axes will not track failures correctly.\n\nWith the default database handler, Axes stores attempts and lockouts in the database and can be reset from admin or management commands:\n\n```bash\npython manage.py axes_reset\npython manage.py axes_reset_ip 203.0.113.10\npython manage.py axes_reset_username alice\npython manage.py axes_reset_ip_username 203.0.113.10 alice\npython manage.py axes_reset_logs 30\n```\n\nIf you switch to a non-database handler such as a cache-based handler, the docs note that you must implement custom reset commands for that handler.\n\n## Configuration That Matters In Real Projects\n\n### Lockout identity\n\nFor modern Axes configuration, prefer `AXES_LOCKOUT_PARAMETERS` instead of the older boolean-style flags:\n\n```python\n# Default-style lockout by IP\nAXES_LOCKOUT_PARAMETERS = [\"ip_address\"]\n\n# Lock out by username only\nAXES_LOCKOUT_PARAMETERS = [\"username\"]\n\n# Lock out by username + IP combination\nAXES_LOCKOUT_PARAMETERS = [[\"username\", \"ip_address\"]]\n```\n\nYou can also combine factors:\n\n```python\nAXES_LOCKOUT_PARAMETERS = [\"ip_address\", [\"username\", \"user_agent\"]]\n```\n\nThis supersedes older settings such as `AXES_ONLY_USER_FAILURES`, `AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP`, `AXES_LOCK_OUT_BY_USER_OR_IP`, and `AXES_USE_USER_AGENT`.\n\n### Reverse proxies and client IPs\n\nIf your Django app runs behind Nginx, a load balancer, or another proxy, do not rely on defaults blindly. Axes uses `django-ipware` when available and exposes proxy settings such as:\n\n- `AXES_IPWARE_PROXY_COUNT`\n- `AXES_IPWARE_META_PRECEDENCE_ORDER`\n- `AXES_IPWARE_PROXY_ORDER`\n\nIf you do not install the `ipware` extra, provide your own IP lookup:\n\n```python\nAXES_CLIENT_IP_CALLABLE = \"project.security.get_client_ip\"\n```\n\n### Username normalization\n\nIf your login identifiers are transformed before authentication, teach Axes the same transformation:\n\n```python\nAXES_USERNAME_CALLABLE = \"project.security.get_axes_username\"\n```\n\nAxes does not apply those transformations for you before `authenticate()`. Your auth code and Axes configuration need to agree on the final username value.\n\n### API-friendly lockout responses\n\nIf your app needs JSON or another custom response format on lockout, use a callable:\n\n```python\n# settings.py\nAXES_LOCKOUT_CALLABLE = \"project.views.lockout\"\n```\n\n```python\n# project/views.py\nfrom django.http import JsonResponse\n\ndef lockout(request, response, credentials, *args, **kwargs):\n    return JsonResponse(\n        {\"detail\": \"Too many failed login attempts\"},\n        status=403,\n    )\n```\n\n## Integration Notes\n\n### Django Allauth\n\nAllauth does not pass login data in the shape Axes expects by default. The upstream integration guide requires:\n\n- `AXES_USERNAME_FORM_FIELD = \"login\"`\n- a custom Allauth login form that duplicates the login identifier into the credentials dict\n- decorating Allauth `LoginView.dispatch` with `axes_dispatch`\n- decorating `LoginView.form_invalid` with `axes_form_invalid`\n\nIf you skip those patches, failed Allauth logins can bypass Axes tracking.\n\n### Django REST Framework\n\nThe upstream DRF guidance only applies to authentication schemes that use Django `authenticate()`. `TokenAuthentication` is explicitly called out as unsupported in that guide.\n\nFor API lockouts, connect the `axes.signals.user_locked_out` signal to an exception or response your API stack understands, for example raising DRF `PermissionDenied`.\n\n## Common Pitfalls\n\n- Wrong backend order: if `AxesStandaloneBackend` is not first, failed logins can bypass Axes.\n- Wrong middleware placement: `AxesMiddleware` belongs at the end of `MIDDLEWARE`.\n- Proxy misconfiguration: without `django-ipware` or a correct `AXES_CLIENT_IP_CALLABLE`, every user can appear to come from the proxy IP.\n- Custom login views that never emit Django auth signals: Axes will not see failures unless you send the signals yourself.\n- Using pre-6.x config flags from old blog posts instead of `AXES_LOCKOUT_PARAMETERS` and `AXES_IPWARE_*`.\n- Assuming reset commands work for every handler. The docs only describe them for the default database handler.\n- Trusting the docs requirements page for Python support. For `8.3.1`, PyPI metadata is the authoritative compatibility source.\n\n## Version-Sensitive Notes\n\n- `8.3.1` was released on February 11, 2026 and fixes configuration JSON serialization errors for Celery.\n- `8.1.0` added Django `6.0` support and Python `3.14` support, and removed Django `5.1` plus Python `3.9`.\n- `8.0.0` moved all database-related logic to the default `axes.handlers.database.AxesDatabaseHandler`.\n- If you upgraded from Axes 6 to 7 and use a callable for `AXES_COOLOFF_TIME`, the callable must now accept a `request`.\n- If you upgraded from Axes 5-era config, rename proxy settings to `AXES_IPWARE_*` and migrate older lockout booleans to `AXES_LOCKOUT_PARAMETERS`.\n\n## Official Sources\n\n- Docs root: `https://django-axes.readthedocs.io/en/latest/`\n- Installation: `https://django-axes.readthedocs.io/en/latest/2_installation.html`\n- Usage: `https://django-axes.readthedocs.io/en/latest/3_usage.html`\n- Configuration: `https://django-axes.readthedocs.io/en/latest/4_configuration.html`\n- Customization: `https://django-axes.readthedocs.io/en/latest/5_customization.html`\n- Integration: `https://django-axes.readthedocs.io/en/latest/6_integration.html`\n- Changelog: `https://django-axes.readthedocs.io/en/latest/10_changelog.html`\n- PyPI: `https://pypi.org/project/django-axes/`\n"
  },
  {
    "path": "content/django/docs/cacheops/python/DOC.md",
    "content": "---\nname: cacheops\ndescription: \"django-cacheops package guide for Python - Redis-backed Django ORM caching with automatic invalidation\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,cacheops,redis,caching,orm,queryset\"\n---\n\n# django-cacheops Python Package Guide\n\n## What It Is\n\n`django-cacheops` adds Redis-backed caching for Django ORM queries plus helper decorators for functions, views, and template fragments. Its main feature is granular invalidation: cache entries are tied to the models and query conditions that produced them, so writes usually invalidate the affected cached data automatically.\n\nUse it when you want cached queryset results without hand-managing cache keys for every read path.\n\n## Version Scope\n\n- Ecosystem: `pypi`\n- Package: `django-cacheops`\n- Version covered here: `7.2`\n- Registry URL: https://pypi.org/project/django-cacheops/\n- Upstream docs and source: https://github.com/Suor/django-cacheops\n\nVersion-sensitive notes for `7.2`:\n\n- PyPI `7.2` was released on April 20, 2025.\n- The project description for `7.2` documents practical support as Python `3.8+`, Django `3.2+`, and Redis `4.0+`.\n- PyPI metadata still reports `Requires-Python >=3.7`, but the published classifiers for `7.2` are Python `3.8` through `3.13`. Treat Python `3.8+` as the supported baseline when writing code for this version.\n\n## Installation\n\n```bash\npip install django-cacheops==7.2\n```\n\n```bash\npoetry add django-cacheops@7.2\n```\n\n```bash\nuv add django-cacheops==7.2\n```\n\nImports come from `cacheops`, not `django_cacheops`:\n\n```python\nfrom cacheops import cached_as, cached_view_as, invalidate_obj\n```\n\n## Minimal Django Setup\n\nAdd the app:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"cacheops\",\n]\n```\n\nConfigure Redis plus model-level cache profiles in `settings.py`:\n\n```python\nCACHEOPS_REDIS = {\n    \"host\": \"127.0.0.1\",\n    \"port\": 6379,\n    \"db\": 1,\n    \"socket_timeout\": 3,\n}\n\nCACHEOPS_DEFAULTS = {\n    \"timeout\": 60 * 60,\n}\n\nCACHEOPS = {\n    \"auth.user\": {\"ops\": \"get\", \"timeout\": 15 * 60},\n    \"blog.post\": {\"ops\": {\"fetch\", \"get\"}, \"timeout\": 10 * 60},\n    \"blog.category\": {\"ops\": \"all\", \"timeout\": 60 * 60},\n    \"*.*\": {},\n}\n```\n\nPractical setup rules:\n\n- Keep `*.*` present but empty unless you intentionally want global automatic caching.\n- Start with a few read-heavy models and narrow `ops`; expand only after measuring hit rate and invalidation behavior.\n- Use a dedicated Redis DB or instance if you can. Cacheops stores extra invalidation data, not just plain values.\n\n## Redis Configuration\n\n`CACHEOPS_REDIS` accepts either a dict or a URL:\n\n```python\nCACHEOPS_REDIS = \"redis://localhost:6379/1\"\n```\n\nPassword in the URL:\n\n```python\nCACHEOPS_REDIS = \"redis://:password@localhost:6379/1\"\n```\n\nUnix socket:\n\n```python\nCACHEOPS_REDIS = \"unix:///var/run/redis/redis.sock?db=1\"\n```\n\nRedis Sentinel:\n\n```python\nCACHEOPS_SENTINEL = {\n    \"locations\": [(\"127.0.0.1\", 26379)],\n    \"service_name\": \"mymaster\",\n    \"socket_timeout\": 0.1,\n    \"db\": 0,\n}\n```\n\nCustom Redis client class:\n\n```python\nCACHEOPS_CLIENT_CLASS = \"path.to.CustomRedis\"\n```\n\nIf Redis failures should not take down the app:\n\n```python\nCACHEOPS_DEGRADE_ON_FAILURE = True\n```\n\n## Cache Profile Semantics\n\nSupported ORM operation groups are:\n\n- `get`\n- `fetch`\n- `count`\n- `aggregate`\n- `exists`\n\n`\"all\"` enables all five.\n\nUseful model options:\n\n- `timeout`: cache TTL in seconds\n- `ops`: which ORM operations are cached\n- `local_get`: keep simple `.get()` results in local process memory\n- `cache_on_save`: write a saved object directly into the cache for selected lookups\n  Example values from upstream docs are `True` or a field name such as `\"slug\"`.\n  This is useful when most reads are immediate lookups right after writes.\n- `db_agnostic`: whether cache keys should ignore the current DB alias\n\nExamples:\n\n```python\nCACHEOPS = {\n    \"blog.post\": {\"ops\": {\"fetch\", \"get\", \"count\"}, \"timeout\": 900},\n    \"blog.category\": {\"ops\": \"all\", \"timeout\": 3600},\n    \"blog.article\": {\"ops\": \"get\", \"local_get\": True, \"timeout\": 300},\n    \"blog.tag\": {\"ops\": \"get\", \"cache_on_save\": \"slug\", \"timeout\": 600},\n}\n```\n\nUse `local_get` only for models that almost never change. It bypasses Redis for simple gets within the same process, so stale reads can last until process restart.\n\n## Core Usage\n\n### Automatic queryset caching\n\nOnce a model is configured in `CACHEOPS`, supported queryset operations are cached automatically:\n\n```python\nposts = Post.objects.filter(published=True)\ntotal = posts.count()\nfirst_post = Post.objects.get(pk=1)\n```\n\n### Manual queryset caching\n\nUse `.cache()` when you want to opt in on a specific queryset or override defaults:\n\n```python\nposts = Post.objects.filter(published=True).cache()\n```\n\nCache only specific operations:\n\n```python\nqs = Post.objects.filter(category_id=category_id).cache(ops=[\"count\"])\n```\n\nOverride timeout:\n\n```python\nqs = Post.objects.filter(category_id=category_id).cache(timeout=300)\n```\n\nDisable cache for one queryset:\n\n```python\nqs = Post.objects.filter(published=True).nocache()\n```\n\n### Cache derived data with model-aware invalidation\n\nUse `@cached_as()` when the result depends on one or more models:\n\n```python\nfrom django.db.models import Count\nfrom cacheops import cached_as\n\n@cached_as(Post, timeout=120)\ndef post_stats():\n    return list(\n        Post.objects.values(\"category_id\").annotate(total=Count(\"id\"))\n    )\n```\n\nIf invalidation should depend on a filtered queryset, pass that queryset and any extra key inputs:\n\n```python\nfrom cacheops import cached_as\n\ndef latest_posts(category_id: int, limit: int = 10):\n    base_qs = Post.objects.filter(category_id=category_id)\n\n    @cached_as(base_qs, extra=limit, timeout=300)\n    def _load():\n        return list(base_qs.order_by(\"-published_at\")[:limit])\n\n    return _load()\n```\n\nMaterialize lazy querysets inside the cached function with `list()`, `tuple()`, or a concrete value. Do not return an unevaluated queryset object.\n\n### View caching\n\nUse `@cached_view_as()` when a Django view should be invalidated by model changes:\n\n```python\nfrom cacheops import cached_view_as\nfrom django.shortcuts import render\n\n@cached_view_as(Post, extra=lambda request: request.user.is_staff, timeout=300)\ndef post_index(request):\n    posts = Post.objects.filter(published=True)\n    return render(request, \"posts/index.html\", {\"posts\": posts})\n```\n\n### Time-based caching without ORM invalidation\n\nUse `@cached()` or the low-level cache object for non-ORM values:\n\n```python\nfrom cacheops import CacheMiss, cache, cached\n\n@cached(timeout=300)\ndef expensive_value(key: str):\n    return compute_value(key)\n\ndef get_cached_value(key: str):\n    try:\n        return cache.get(key)\n    except CacheMiss:\n        value = compute_value(key)\n        cache.set(key, value, timeout=300)\n        return value\n```\n\n## Invalidation\n\nCacheops automatically invalidates cached querysets when tracked model data changes, but manual helpers are still useful:\n\n```python\nfrom cacheops import invalidate_all, invalidate_model, invalidate_obj\n\ninvalidate_obj(post)\ninvalidate_model(Post)\ninvalidate_all()\n```\n\nWhen bulk updates would bypass normal model save hooks, use cacheops-aware helpers:\n\n```python\nPost.objects.filter(published=False).invalidated_update(published=True)\n```\n\nIf you intentionally want to suppress invalidation during a batch operation, use `no_invalidation` and then invalidate explicitly:\n\n```python\nfrom cacheops import invalidate_model, no_invalidation\n\nwith no_invalidation:\n    Post.objects.filter(status=\"draft\").update(status=\"published\")\n\ninvalidate_model(Post)\n```\n\n## Template Fragments\n\nEnable the template tag library:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"cacheops\",\n]\n```\n\nExample:\n\n```django\n{% load cacheops %}\n\n{% cached_as sidebar_queryset 600 \"sidebar\" request.user.pk %}\n  {% include \"includes/sidebar.html\" %}\n{% endcached_as %}\n```\n\nUse this when the rendered fragment depends on queryset results and should invalidate with the underlying model data.\n\n## Transactions, Locking, and Consistency\n\nCacheops disables caching once a transaction becomes dirty and keeps it disabled until the outer transaction commits. This avoids reading cache entries that no longer match in-flight writes.\n\nFor heavy concurrent recomputation, upstream documents a lock-based strategy to reduce dog-pile effects. The general rule is:\n\n- Keep cached functions deterministic.\n- Avoid expensive recomputation in hot paths unless you set reasonable TTLs.\n- Expect some stale reads during races; cacheops optimizes for practical correctness, not cross-request serializability.\n\n## Operational Settings\n\nUseful global settings from upstream:\n\n```python\nCACHEOPS_PREFIX = lambda query: \"tenant:%s\" % get_current_tenant_id()\n\nCACHEOPS_ENABLED = not DEBUG\n\nCACHEOPS_INSIDEOUT = True\n```\n\nNotes:\n\n- `CACHEOPS_PREFIX` is the main namespacing hook for multi-tenant deployments or shared Redis instances.\n- `CACHEOPS_ENABLED = False` is the simplest way to disable cacheops in tests or local debugging.\n- `CACHEOPS_INSIDEOUT = True` is recommended by upstream when Redis eviction policy is `volatile-*`; it stores checksum data separately so invalidation survives better under eviction pressure.\n\n## Common Pitfalls\n\n- Import path mismatch: install `django-cacheops`, import from `cacheops`.\n- Returning lazy querysets from cached helpers leads to incorrect cache contents. Materialize results before returning.\n- Plain `QuerySet.update()` can bypass the invalidation semantics you expect. Prefer `invalidated_update()` when cached data depends on those rows.\n- `select_related()` and `prefetch_related()` do not automatically make invalidation understand every downstream relation shape. Cache the exact queryset you read, and test invalidation around relation-heavy screens.\n- `local_get=True` trades correctness for speed. Do not use it on frequently updated models.\n- Shared Redis with aggressive eviction can break assumptions unless you configure memory policy and, for newer setups, consider `CACHEOPS_INSIDEOUT`.\n- During tests, cache state can hide bugs. Disable cacheops or flush Redis between tests that assert query counts or invalidation behavior.\n\n## Version-Sensitive Notes For Agents\n\n- The target version for this session is `7.2`, and PyPI latest is also `7.2` as of March 12, 2026.\n- Older material for `7.1` can mention Python `>=3.7`; for `7.2`, the project description and classifiers move practical support to Python `3.8+`.\n- The upstream repo README tracks the current default branch. For release-sensitive compatibility questions, prefer the PyPI release page first, then use the repo README for API shape and examples.\n- `django-cacheops` is configuration-heavy. Before writing production code, inspect the project’s actual `CACHEOPS`, Redis topology, and test strategy instead of assuming the defaults above are safe.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/django-cacheops/\n- PyPI `7.2` release page: https://pypi.org/project/django-cacheops/7.2/\n- Upstream repository: https://github.com/Suor/django-cacheops\n"
  },
  {
    "path": "content/django/docs/celery-beat/python/DOC.md",
    "content": "---\nname: celery-beat\ndescription: \"Database-backed periodic task scheduling for Celery in Django projects, with admin-managed interval, crontab, solar, and clocked schedules.\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,celery,beat,scheduler,periodic-tasks,cron,task-queue,python\"\n---\n\n# `django-celery-beat` for Python\n\nUse `django-celery-beat` when a Django project needs Celery beat schedules in the database instead of a local `celerybeat-schedule` file. It adds Django models and admin screens for interval, crontab, solar, and clocked schedules, and Celery beat reloads changes from the database.\n\nThis package is not a full Celery setup by itself. You still need:\n\n- a Django project\n- a Celery app\n- a broker such as Redis or RabbitMQ\n- one or more Celery workers\n- one Celery beat process\n\n## Install\n\nPin the target version if you need exact reproducibility:\n\n```bash\npip install \"django-celery-beat==2.9.0\"\n```\n\nTypical installs also include Celery itself:\n\n```bash\npip install \"celery>=5.3\" \"django-celery-beat==2.9.0\"\n```\n\nPyPI metadata for `2.9.0` declares:\n\n- Python `>=3.8`\n- Django classifiers through `6.0`\n\n## Minimal Django and Celery setup\n\nAdd the app and run its migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django_celery_beat\",\n]\n```\n\n```bash\npython manage.py migrate\n```\n\nCreate the Celery app with the standard Django integration:\n\n```python\n# proj/celery.py\nimport os\n\nfrom celery import Celery\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"proj.settings\")\n\napp = Celery(\"proj\")\napp.config_from_object(\"django.conf:settings\", namespace=\"CELERY\")\napp.autodiscover_tasks()\n```\n\n```python\n# proj/__init__.py\nfrom .celery import app as celery_app\n\n__all__ = (\"celery_app\",)\n```\n\nPoint beat at the database scheduler:\n\n```python\n# settings.py\nCELERY_BROKER_URL = os.environ[\"CELERY_BROKER_URL\"]\nCELERY_RESULT_BACKEND = os.getenv(\"CELERY_RESULT_BACKEND\", \"rpc://\")\nCELERY_BEAT_SCHEDULER = \"django_celery_beat.schedulers:DatabaseScheduler\"\nCELERY_TIMEZONE = TIME_ZONE\n```\n\n`django-celery-beat` has no package-specific auth. Credentials come from:\n\n- `CELERY_BROKER_URL` and broker-specific auth\n- your result backend config if used\n- Django database access for schedule tables\n\n## Define tasks\n\nKeep tasks in `tasks.py` so `app.autodiscover_tasks()` can find them:\n\n```python\n# myapp/tasks.py\nfrom celery import shared_task\n\n@shared_task\ndef import_contacts(source_id: int, force: bool = False) -> None:\n    print(f\"importing contacts from source {source_id}, force={force}\")\n```\n\n## Create schedules and periodic tasks\n\n`args`, `kwargs`, and `headers` are stored as JSON strings in the database.\n\n### Interval schedule\n\n```python\nimport json\n\nfrom django_celery_beat.models import IntervalSchedule, PeriodicTask\n\nschedule, _ = IntervalSchedule.objects.get_or_create(\n    every=10,\n    period=IntervalSchedule.SECONDS,\n)\n\nPeriodicTask.objects.update_or_create(\n    name=\"import-contacts-every-10s\",\n    defaults={\n        \"interval\": schedule,\n        \"task\": \"myapp.tasks.import_contacts\",\n        \"args\": json.dumps([42]),\n        \"kwargs\": json.dumps({\"force\": False}),\n        \"enabled\": True,\n    },\n)\n```\n\nReuse shared `IntervalSchedule` rows instead of creating duplicates for the same cadence.\n\n### Crontab schedule\n\n```python\nimport json\nfrom zoneinfo import ZoneInfo\n\nfrom django_celery_beat.models import CrontabSchedule, PeriodicTask\n\nschedule, _ = CrontabSchedule.objects.get_or_create(\n    minute=\"0\",\n    hour=\"2\",\n    day_of_week=\"1-5\",\n    day_of_month=\"*\",\n    month_of_year=\"*\",\n    timezone=ZoneInfo(\"UTC\"),\n)\n\nPeriodicTask.objects.update_or_create(\n    name=\"weekday-nightly-import\",\n    defaults={\n        \"crontab\": schedule,\n        \"task\": \"myapp.tasks.import_contacts\",\n        \"kwargs\": json.dumps({\"source_id\": 42, \"force\": True}),\n        \"queue\": \"imports\",\n        \"enabled\": True,\n    },\n)\n```\n\n### One-off clocked task\n\nClocked schedules are for one-time execution and require `one_off=True`:\n\n```python\nimport json\nfrom datetime import timedelta\n\nfrom django.utils import timezone\nfrom django_celery_beat.models import ClockedSchedule, PeriodicTask\n\nclocked, _ = ClockedSchedule.objects.get_or_create(\n    clocked_time=timezone.now() + timedelta(minutes=5),\n)\n\nPeriodicTask.objects.create(\n    name=\"run-import-once\",\n    task=\"myapp.tasks.import_contacts\",\n    clocked=clocked,\n    one_off=True,\n    args=json.dumps([42]),\n)\n```\n\n### Admin-managed schedules\n\nThe Django admin UI is the main reason to use this package:\n\n- create `IntervalSchedule`, `CrontabSchedule`, `SolarSchedule`, or `ClockedSchedule`\n- create one `PeriodicTask` that points to exactly one schedule row\n- toggle `enabled` to pause or resume a task without deleting it\n\n## Run workers and beat\n\nUse separate processes in real deployments:\n\n```bash\ncelery -A proj worker --loglevel=info\ncelery -A proj beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler\n```\n\nThe documented shortcut also works:\n\n```bash\ncelery -A proj beat -l info -S django\n```\n\nOnly run one scheduler for a given schedule set. Multiple beat instances against the same database-backed schedule will duplicate dispatches.\n\nCelery's configuration docs note that the `django-celery-beat` scheduler checks for externally changed schedules every `5` seconds by default, so admin edits are not necessarily visible immediately.\n\n## Configuration notes\n\n### Time zones\n\nIf your project uses timezone-aware Django settings, keep:\n\n```python\nCELERY_TIMEZONE = TIME_ZONE\n```\n\nIf you intentionally run a timezone-naive legacy project, the package exposes:\n\n```python\nDJANGO_CELERY_BEAT_TZ_AWARE = False\n```\n\nIf you change Django timezone settings after tasks already ran, reset task state and bump the schedule change marker:\n\n```python\nfrom django_celery_beat.models import PeriodicTask, PeriodicTasks\n\nPeriodicTask.objects.update(last_run_at=None)\nPeriodicTasks.update_changed()\n```\n\n### Routing and expiry\n\n`PeriodicTask` can store execution-routing fields such as:\n\n- `queue`\n- `exchange`\n- `routing_key`\n- `priority`\n- `expires` or `expire_seconds`\n\nUse these when the scheduled task should land on a specific worker queue. Do not set both `expires` and `expire_seconds` on the same task.\n\n## Common pitfalls\n\n### Package name and import name differ\n\nInstall name:\n\n```text\ndjango-celery-beat\n```\n\nDjango app and import path:\n\n```text\ndjango_celery_beat\n```\n\n### Each `PeriodicTask` must point to exactly one schedule type\n\nChoose exactly one of:\n\n- `interval`\n- `crontab`\n- `solar`\n- `clocked`\n\nIf more than one is set, model validation fails.\n\n### Bulk updates need an explicit schedule-change bump\n\nNormal model saves trigger schedule change tracking. If you use `QuerySet.update()`, raw SQL, or bulk operations, call:\n\n```python\nfrom django_celery_beat.models import PeriodicTasks\n\nPeriodicTasks.update_changed()\n```\n\nOlder snippets sometimes reference `PeriodicTasks.changed()`. Prefer `update_changed()` in current source and docs.\n\n### JSON fields must be serialized strings\n\nThese model fields are text fields, not Python containers:\n\n- `args`\n- `kwargs`\n- `headers`\n\nUse `json.dumps(...)` before saving them.\n\n### Clocked schedules need `one_off=True`\n\nIf you attach a `ClockedSchedule` without `one_off=True`, the model validation path rejects it.\n\n## Version-sensitive notes for `2.9.0`\n\n- The target version `2.9.0` matches the PyPI release published on `2026-02-28`.\n- Read the Docs `latest` is currently stale and still renders `2.5.0` in the page chrome, so use it for concepts and examples, but prefer PyPI metadata and the `v2.9.0` GitHub release for compatibility facts.\n- The PyPI long description currently still includes older `2.8.1` text in some places; the structured PyPI metadata and release tag are the safer version anchors.\n- The `v2.9.0` release notes add Django `6.0` support and remove the Django upper version limit.\n\n## Official sources used\n\n- Docs root: https://django-celery-beat.readthedocs.io/en/latest/\n- PyPI project: https://pypi.org/project/django-celery-beat/\n- PyPI version JSON: https://pypi.org/pypi/django-celery-beat/2.9.0/json\n- Repository: https://github.com/celery/django-celery-beat\n- Release notes: https://github.com/celery/django-celery-beat/releases/tag/v2.9.0\n- Celery Django integration: https://docs.celeryq.dev/en/latest/django/first-steps-with-django.html\n- Celery configuration reference: https://docs.celeryq.dev/en/main/userguide/configuration.html\n"
  },
  {
    "path": "content/django/docs/celery-results/python/DOC.md",
    "content": "---\nname: celery-results\ndescription: \"Django result backends for Celery task states, return values, and group results in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,celery,results,result-backend,orm,cache,python\"\n---\n\n# `django-celery-results` for Python\n\n`django-celery-results` adds Celery result backends that store task state, return values, and group metadata through Django's ORM or cache framework.\n\nUse it when a Django project already has Celery and you need one or more of these:\n\n- `AsyncResult.get()` or task result polling\n- persistent task state rows in the Django database\n- chord or group result storage\n- Django admin visibility into task outcomes\n\nIt is only a result backend package. You still need a normal Celery app, a broker, and workers.\n\n## Official Context\n\n- Docs root: https://django-celery-results.readthedocs.io/en/latest/\n- Getting started: https://django-celery-results.readthedocs.io/en/latest/getting_started.html\n- Models reference: https://django-celery-results.readthedocs.io/en/latest/reference/django_celery_results.models.html\n- PyPI: https://pypi.org/project/django-celery-results/\n- Repository: https://github.com/celery/django-celery-results\n- Releases: https://github.com/celery/django-celery-results/releases\n- Celery Django integration: https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html\n- Celery configuration reference: https://docs.celeryq.dev/en/stable/userguide/configuration.html\n\n## Install And Compatibility\n\nPin the target version when you need this exact package version:\n\n```bash\npip install \"django-celery-results==2.6.0\"\n```\n\nThe package metadata for `2.6.0` requires:\n\n- `celery>=5.2.7,<6.0`\n- `Django>=3.2.25`\n\nA typical install is:\n\n```bash\npip install \"celery>=5.2.7,<6\" \"django>=3.2.25\" \"django-celery-results==2.6.0\"\n```\n\nPyPI classifiers for `2.6.0` cover Python `3.8` through `3.13` and Django `3.2`, `4.1`, `4.2`, `5.0`, `5.1`, and `5.2`.\n\n## Minimal Django Setup\n\nAdd the app and run migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django_celery_results\",\n]\n```\n\n```bash\npython manage.py migrate django_celery_results\n```\n\nCreate the Celery app with the standard Django integration pattern:\n\n```python\n# proj/celery.py\nimport os\n\nfrom celery import Celery\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"proj.settings\")\n\napp = Celery(\"proj\")\napp.config_from_object(\"django.conf:settings\", namespace=\"CELERY\")\napp.autodiscover_tasks()\n```\n\n```python\n# proj/__init__.py\nfrom .celery import app as celery_app\n\n__all__ = (\"celery_app\",)\n```\n\nIf tasks never need stored results, do not add this package just to mirror a standard Celery setup.\n\n## Configure The Result Backend\n\n### Option 1: Django database backend\n\nThis is the normal choice when callers depend on durable result rows.\n\n```python\n# settings.py\nimport os\n\nCELERY_BROKER_URL = os.environ[\"CELERY_BROKER_URL\"]\nCELERY_RESULT_BACKEND = \"django-db\"\nCELERY_ACCEPT_CONTENT = [\"json\"]\nCELERY_TASK_SERIALIZER = \"json\"\nCELERY_RESULT_SERIALIZER = \"json\"\nCELERY_TASK_TRACK_STARTED = True\nCELERY_RESULT_EXTENDED = True\nCELERY_RESULT_EXPIRES = 86400\n```\n\nNotes:\n\n- `CELERY_TASK_TRACK_STARTED = True` exposes a visible `STARTED` state instead of jumping from `PENDING` to the terminal state.\n- `CELERY_RESULT_EXTENDED = True` stores extra task metadata when Celery provides it.\n- `CELERY_RESULT_EXPIRES` only sets expiration policy. Schedule Celery's `backend_cleanup` task with beat if you want old rows removed automatically.\n\n### Option 2: Django cache backend\n\nUse this only if your project already has a cache configured and ephemeral result storage is acceptable.\n\n```python\n# settings.py\nimport os\n\nCELERY_RESULT_BACKEND = \"django-cache\"\nCELERY_CACHE_BACKEND = \"results\"\n\nCACHES = {\n    \"results\": {\n        \"BACKEND\": \"django.core.cache.backends.redis.RedisCache\",\n        \"LOCATION\": os.environ[\"REDIS_URL\"],\n    }\n}\n```\n\n`CELERY_CACHE_BACKEND` is the Django cache alias to use. The backend type is still selected with `CELERY_RESULT_BACKEND = \"django-cache\"`.\n\nFor durable results, prefer `django-db`.\n\n## Core Usage\n\nDefine a task, send it, and inspect its stored state:\n\n```python\n# myapp/tasks.py\nfrom celery import shared_task\n\n@shared_task(bind=True, autoretry_for=(ConnectionError,), retry_backoff=True)\ndef fetch_report(self, report_id: int) -> dict:\n    self.update_state(state=\"PROGRESS\", meta={\"report_id\": report_id, \"step\": \"fetching\"})\n    return {\"report_id\": report_id, \"status\": \"ready\"}\n```\n\nStart a worker:\n\n```bash\ncelery -A proj worker --loglevel=INFO\n```\n\nQueue work and later read the stored state:\n\n```python\nfrom celery.result import AsyncResult\n\nfrom myapp.tasks import fetch_report\n\nqueued = fetch_report.delay(42)\n\nresult = AsyncResult(queued.id)\nprint(result.state)\n\nif result.ready():\n    print(result.get(timeout=1))\n```\n\nIn the `2.6.0` line, `TaskResult.status` accepts custom states cleanly, so states such as `PROGRESS` can be persisted without relying on a fixed built-in status list.\n\n## Query Stored Results Through Django\n\n`django-celery-results` exposes models for direct inspection:\n\n```python\nfrom django_celery_results.models import GroupResult, TaskResult\n\nlatest_failures = (\n    TaskResult.objects\n    .filter(status=\"FAILURE\")\n    .order_by(\"-date_done\")[:20]\n)\n\nfor row in latest_failures:\n    print(row.task_id, row.task_name, row.status, row.date_done)\n\ngroup = GroupResult.objects.get(group_id=\"my-group-id\")\nprint(group.result)\n```\n\nWith `django-celery-beat`, task result rows can also record `periodic_task_name`, which helps trace a stored result back to the scheduled job that launched it.\n\n## Testing And Local Development\n\nIf tests run Celery eagerly and still expect result rows, store eager results explicitly:\n\n```python\n# settings.py\nCELERY_TASK_ALWAYS_EAGER = True\nCELERY_TASK_STORE_EAGER_RESULT = True\n```\n\nWithout `CELERY_TASK_STORE_EAGER_RESULT = True`, eager tasks execute inline but their results are typically not persisted to the configured backend.\n\n## Auth And Configuration Model\n\nThis package has no package-specific auth layer. Access control comes from the systems around it:\n\n- Celery broker credentials for RabbitMQ, Redis, SQS, or another transport\n- Django database credentials if you use `django-db`\n- Django cache credentials if you use `django-cache`\n- Django admin permissions if you expose result rows in admin\n\nTreat task results as application data. If tasks can return secrets, tokens, or PII, do not store those values directly in task results.\n\n## Common Patterns\n\n### Ignore results for fire-and-forget tasks\n\nIf a task does not need a stored return value, turn off results for that task instead of writing unnecessary rows:\n\n```python\nfrom celery import shared_task\n\n@shared_task(ignore_result=True)\ndef send_webhook(payload: dict) -> None:\n    ...\n```\n\nThis matters even when `django-db` is configured globally.\n\n### Clean up expired results\n\nIf your project stores many results, schedule backend cleanup so the `django_celery_results_taskresult` table does not grow without bound.\n\n## Common Pitfalls\n\n### Install name and app name differ\n\nPackage name:\n\n```text\ndjango-celery-results\n```\n\nDjango app and import path:\n\n```text\ndjango_celery_results\n```\n\n### Migrations are required before the backend works\n\nIf `CELERY_RESULT_BACKEND = \"django-db\"` is set before `python manage.py migrate django_celery_results`, result writes fail at runtime.\n\n### `django-cache` is not durable by default\n\nIf your cache is memory-only or has aggressive eviction, task results may disappear before callers fetch them. Use `django-db` if callers depend on stable result retrieval.\n\n### `CELERY_CACHE_BACKEND` is a cache alias, not the backend type\n\nFor the cache backend, set `CELERY_RESULT_BACKEND = \"django-cache\"` and then point `CELERY_CACHE_BACKEND` at a Django cache alias such as `\"default\"` or `\"results\"`.\n\n### `ignore_result=True` overrides your backend expectations\n\nIf a task or global setting ignores results, you will not get useful rows in `TaskResult` even though the backend is configured.\n\n### `STARTED` state requires tracking to be enabled\n\nSeeing only `PENDING` and terminal states usually means `CELERY_TASK_TRACK_STARTED` or task-level `track_started=True` is not enabled.\n\n### Large or sensitive results become database baggage\n\nReturned objects are serialized into backend storage. Keep task return payloads small and non-sensitive; persist larger business data in your own tables or object storage and return identifiers instead.\n\n## Version-Sensitive Notes For `2.6.0`\n\n- The Read the Docs `latest` site is still useful for setup and model reference, but it currently renders documentation labeled `2.4.0`. For `2.6.0` compatibility, cross-check PyPI metadata and the maintainer release notes.\n- The `2.6.0` release line adds Django `5.2` and Python `3.13` support in upstream packaging metadata.\n- The `2.6.0` release line allows custom task states in `TaskResult.status` and stores a start timestamp when started tracking is enabled.\n"
  },
  {
    "path": "content/django/docs/channels/python/DOC.md",
    "content": "---\nname: channels\ndescription: \"Legacy django-channels 0.7.0 guide for Django notification delivery; renamed to kawasemi and unrelated to the official Django Channels framework\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-channels,kawasemi,django,python,notifications,slack,hipchat,twitter,yo\"\n---\n\n# django-channels Python Package Guide\n\n## Golden Rule\n\n`django-channels==0.7.0` is a legacy Django notification library. It is not the official Django Channels ASGI/WebSocket framework documented at `https://channels.readthedocs.io/en/latest/`.\n\nUse this package only when you are maintaining an older codebase that already depends on its notification API. For new work, prefer the renamed successor `kawasemi` or another maintained notification library.\n\n## Project Status And Upstream Drift\n\n- Ecosystem: `pypi`\n- Package: `django-channels`\n- Version covered: `0.7.0`\n- Release date from PyPI: `2016-10-04`\n- Import surface shown on the official PyPI page: `import channels`\n- Supported notification targets in the `django-channels` PyPI description: HipChat, Slack, Twitter, and Yo\n- Supported runtimes listed on PyPI: Python `2.7+` and `3.3+`, Django `1.8`, `1.9`, and `1.10`\n\nImportant context:\n\n- The docs URL, `https://channels.readthedocs.io/en/latest/`, currently points to the unrelated official Django Channels framework and on March 12, 2026 shows the `4.3.2` docs.\n- The maintainers later renamed this notification library to `kawasemi` specifically to avoid that confusion.\n- The maintained docs that still describe this project family now live under `https://kawasemi.readthedocs.io/`, but those docs are for the renamed package and a newer `2.0.0` documentation build.\n\n## Install\n\nIf you truly need this legacy package, pin the exact version:\n\n```bash\npip install \"django-channels==0.7.0\"\npip install -U setuptools pip\n```\n\nIf you are modernizing the project instead of preserving the old dependency, install the renamed package:\n\n```bash\npip install kawasemi\n```\n\n## Minimal Setup\n\nThe official successor docs show the same overall model used by this project family:\n\n1. Define a notification backend configuration mapping.\n2. Keep provider credentials in Django settings or environment variables.\n3. Call a single send helper from application code.\n\nSlack is the clearest backend example still documented by the maintainers:\n\n```python\nimport os\n\nCHANNELS = {\n    \"slack\": {\n        \"_backend\": \"<legacy Slack backend class>\",\n        \"url\": os.environ[\"SLACK_WEBHOOK_URL\"],\n        \"username\": \"deploy-bot\",\n        \"icon_emoji\": \":ghost:\",\n        \"channel\": \"#ops\",\n    }\n}\n```\n\nNotes:\n\n- In the renamed `kawasemi` docs, the Slack backend class is `kawasemi.backends.slack.SlackChannel`.\n- Because `django-channels 0.7.0` predates the rename, verify the exact legacy dotted backend path in the installed package before hardcoding it.\n- Slack requires an Incoming Webhook URL. The later maintainer docs also show optional `username`, `icon_url` or `icon_emoji`, and a default target `channel`.\n\n## Core Usage\n\nThe official `django-channels` PyPI page shows this minimal usage pattern:\n\n```python\nimport channels\n\nchannels.send(\"Sample notification.\")\n```\n\nThat simple send call is the safest starting point for a legacy codebase.\n\nIf you migrate to the renamed package, the later docs show the Django helper form:\n\n```python\nfrom kawasemi.django import send\n\nsend(\"Sample notification.\")\n```\n\nThe successor docs also show backend-specific options for Slack, including attachments and `unfurl_links`. Treat those as migration guidance, not as a guarantee that every option name is unchanged in `0.7.0`.\n\n## Config And Credentials\n\nFor coding agents, the practical pattern is:\n\n1. Put provider secrets in environment variables.\n2. Build the `CHANNELS` mapping in Django settings.\n3. Send notifications from a narrow wrapper function so the legacy dependency is isolated.\n\nExample wrapper:\n\n```python\nimport channels\n\ndef notify_deploy_finished(environment: str, commit_sha: str) -> None:\n    channels.send(f\"[{environment}] deploy finished for {commit_sha}\")\n```\n\nPrefer a wrapper like this instead of scattering raw `channels.send(...)` calls across the codebase. It makes later migration to `kawasemi` or another notifier much easier.\n\n## Common Pitfalls\n\n- Do not use `django-channels` when you actually need ASGI, WebSockets, channel layers, or consumers. That is the separate `channels` framework.\n- Avoid installing legacy `django-channels` and the official `channels` framework in the same environment. They collide conceptually and can confuse imports, debugging, and dependency review because the legacy package also uses the `channels` import name.\n- `0.7.0` is from 2016 and targets Django `1.8` to `1.10`. Expect breakage on modern Django and modern Python unless the project is heavily pinned.\n- HipChat and Yo are effectively obsolete targets. Slack is the only backend from the old PyPI description that is still likely to be useful without replacing the provider integration yourself.\n- The `kawasemi` docs are useful for successor context, but they are not a frozen `0.7.0` reference. Verify import paths and backend names against the installed package if you have to keep the legacy dependency.\n\n## Version-Sensitive Notes\n\n- `django-channels` `0.7.0` is the final release published under the old package name.\n- The project was later renamed to `kawasemi`; the `kawasemi` PyPI page explicitly records that rename.\n- The docs URL is stale for this package slot. It points to the official Django Channels framework, not this notification library.\n- If you are starting greenfield work, do not choose `django-channels 0.7.0`. Use a maintained dependency and re-validate all provider integrations.\n\n## Official URLs\n\n- Legacy package: `https://pypi.org/project/django-channels/`\n- Renamed package: `https://pypi.org/project/kawasemi/`\n- Successor docs root: `https://kawasemi.readthedocs.io/`\n- Successor Slack backend docs: `https://kawasemi.readthedocs.io/en/latest/backends/slack.html`\n- Docs URL that is actually a different project: `https://channels.readthedocs.io/en/latest/`\n"
  },
  {
    "path": "content/django/docs/compressor/python/DOC.md",
    "content": "---\nname: compressor\ndescription: \"django-compressor package guide for Django asset compression, offline builds, and static storage integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.6.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,staticfiles,assets,compression,css,javascript,python,pypi\"\n---\n\n# django-compressor Python Package Guide\n\n`django-compressor` combines and filters CSS and JavaScript declared in Django templates, then emits cacheable output files or inline blocks. Use it when a Django project still serves template-owned assets and needs minification, URL rewriting, offline asset generation, or static storage/CDN integration without adding a separate frontend bundler.\n\nThis entry is pinned to `django-compressor==4.6.0`.\n\n## Install\n\nUse the normalized PyPI package name and pin the version that matches the project:\n\n```bash\npip install \"django-compressor==4.6.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"django-compressor==4.6.0\"\npoetry add \"django-compressor==4.6.0\"\n```\n\nOptional extras from the official docs, depending on your parser and filter choices:\n\n```bash\npip install beautifulsoup4\npip install lxml\npip install html5lib\npip install calmjs.parse\npip install csscompressor\npip install brotli\n```\n\n## Minimal Django Setup\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"compressor\",\n]\n```\n\nIf the project uses `django.contrib.staticfiles`, add the finder so generated files can be discovered:\n\n```python\n# settings.py\nSTATICFILES_FINDERS = [\n    \"django.contrib.staticfiles.finders.FileSystemFinder\",\n    \"django.contrib.staticfiles.finders.AppDirectoriesFinder\",\n    \"compressor.finders.CompressorFinder\",\n]\n```\n\nAlign Compressor with your static file location:\n\n```python\n# settings.py\nSTATIC_URL = \"/static/\"\nSTATIC_ROOT = BASE_DIR / \"staticfiles\"\n\nCOMPRESS_URL = STATIC_URL\nCOMPRESS_ROOT = STATIC_ROOT\n```\n\nDefaults that matter:\n\n- `COMPRESS_ENABLED` defaults to `not DEBUG`\n- `COMPRESS_URL` defaults to `STATIC_URL`\n- `COMPRESS_ROOT` defaults to `STATIC_ROOT`\n- `COMPRESS_OUTPUT_DIR` defaults to `\"CACHE\"`\n- `COMPRESS_STORAGE` defaults to `compressor.storage.CompressorFileStorage`\n\nIf you want compression to run while `DEBUG = True`, enable it explicitly:\n\n```python\nCOMPRESS_ENABLED = True\n```\n\n## Core Template Usage\n\nWrap static assets inside `{% compress %}` blocks:\n\n```django\n{% load compress %}\n{% load static %}\n\n{% compress css %}\n<link rel=\"stylesheet\" href=\"{% static 'css/site.css' %}\" type=\"text/css\">\n<link rel=\"stylesheet\" href=\"{% static 'css/theme.css' %}\" type=\"text/css\">\n{% endcompress %}\n```\n\nTypical output:\n\n```html\n<link rel=\"stylesheet\" href=\"/static/CACHE/css/output.<hash>.css\" type=\"text/css\">\n```\n\nJavaScript works the same way:\n\n```django\n{% load compress %}\n{% load static %}\n\n{% compress js %}\n<script src=\"{% static 'js/vendor.js' %}\"></script>\n<script src=\"{% static 'js/app.js' %}\"></script>\n{% endcompress %}\n```\n\nUse `inline` only when you deliberately want the rendered content injected into the page:\n\n```django\n{% load compress %}\n{% load static %}\n\n{% compress js inline %}\n<script src=\"{% static 'js/app.js' %}\"></script>\n<script>\n  window.APP_ENV = \"prod\";\n</script>\n{% endcompress %}\n```\n\nFor most projects, file output is the safer default because browsers and CDNs can cache it independently.\n\n## Recommended Base Configuration\n\nThis is the simplest production-friendly starting point for a standard Django app with local static output:\n\n```python\n# settings.py\nINSTALLED_APPS += [\"compressor\"]\n\nSTATIC_URL = \"/static/\"\nSTATIC_ROOT = BASE_DIR / \"staticfiles\"\n\nSTATICFILES_FINDERS = [\n    \"django.contrib.staticfiles.finders.FileSystemFinder\",\n    \"django.contrib.staticfiles.finders.AppDirectoriesFinder\",\n    \"compressor.finders.CompressorFinder\",\n]\n\nCOMPRESS_URL = STATIC_URL\nCOMPRESS_ROOT = STATIC_ROOT\nCOMPRESS_ENABLED = not DEBUG\nCOMPRESS_OFFLINE = not DEBUG\n```\n\nFor single-server development, request-time compression is fine. For real deployments, upstream still treats offline compression as the default recommendation.\n\n## Offline Compression\n\nOffline compression precomputes the output and manifest during deploy instead of during the first request:\n\n```python\n# settings.py\nCOMPRESS_OFFLINE = True\n```\n\nBuild assets during deployment:\n\n```bash\npython manage.py collectstatic --noinput\npython manage.py compress\n```\n\nIf a `{% compress %}` block depends on template variables, provide those values before running `compress`:\n\n```python\n# settings.py\nCOMPRESS_OFFLINE_CONTEXT = {\n    \"STATIC_URL\": STATIC_URL,\n    \"theme_name\": \"default\",\n}\n```\n\n`COMPRESS_OFFLINE_CONTEXT` can also be a list of contexts or a dotted callable path when you need multiple combinations such as locale, tenant, or theme variants.\n\nWhy offline mode is usually the right production path:\n\n- app servers do not need to create compressed files during requests\n- generated files can be built once and published with the rest of static assets\n- multi-server or CDN-backed deployments avoid inconsistent first-hit behavior\n- external precompilers only need to exist on the build host\n\nAt runtime, missing offline manifest entries raise `OfflineGenerationError`. That usually means the deploy skipped `python manage.py compress` or the offline context did not cover every rendered block variant.\n\n## Static Storage And CDN Configuration\n\n`django-compressor` does not have its own auth system. Any credentials come from the storage backend used for static files, such as S3 via `django-storages`.\n\nSimple CDN pattern:\n\n```python\nSTATIC_URL = \"https://cdn.example.com/\"\nCOMPRESS_URL = STATIC_URL\n```\n\nFor Django 4.2+ projects using `STORAGES`, define explicit aliases instead of relying on fallback behavior:\n\n```python\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"django.core.files.storage.FileSystemStorage\",\n    },\n    \"staticfiles\": {\n        \"BACKEND\": \"django.contrib.staticfiles.storage.ManifestStaticFilesStorage\",\n    },\n    \"compressor\": {\n        \"BACKEND\": \"compressor.storage.CompressorFileStorage\",\n    },\n    \"compressor-offline\": {\n        \"BACKEND\": \"compressor.storage.OfflineManifestFileStorage\",\n    },\n}\n\nCOMPRESS_STORAGE_ALIAS = \"compressor\"\nCOMPRESS_OFFLINE_MANIFEST_STORAGE_ALIAS = \"compressor-offline\"\n```\n\nIf your static assets ultimately live in remote storage, Compressor still needs a local filesystem view while building output. The official docs recommend a storage that writes locally and then mirrors to the remote backend:\n\n```python\nfrom django.core.files.storage import storages\nfrom storages.backends.s3boto3 import S3Boto3Storage\n\nclass CachedS3Boto3Storage(S3Boto3Storage):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.local_storage = storages.create_storage(\n            {\"BACKEND\": \"compressor.storage.CompressorFileStorage\"}\n        )\n\n    def save(self, name, content):\n        self.local_storage.save(name, content)\n        super().save(name, self.local_storage._open(name))\n        return name\n```\n\nThen wire it up:\n\n```python\nSTATIC_ROOT = BASE_DIR / \"staticfiles\"\nCOMPRESS_ROOT = STATIC_ROOT\n\nSTATICFILES_STORAGE = \"project.storage.CachedS3Boto3Storage\"\nCOMPRESS_STORAGE = STATICFILES_STORAGE\nCOMPRESS_OFFLINE_MANIFEST_STORAGE = STATICFILES_STORAGE\n\nSTATIC_URL = \"https://cdn.example.com/\"\nCOMPRESS_URL = STATIC_URL\n```\n\nPractical rule: if your storage backend does not provide a working local `path()` for the build process, do not point Compressor at it directly without the cached-local pattern.\n\n## Filters, Parsers, And Precompilers\n\nDefault filters remain the main path for standard CSS and JS blocks:\n\n```python\nCOMPRESS_FILTERS = {\n    \"css\": [\n        \"compressor.filters.css_default.CssAbsoluteFilter\",\n        \"compressor.filters.cssmin.rCSSMinFilter\",\n    ],\n    \"js\": [\n        \"compressor.filters.jsmin.rJSMinFilter\",\n    ],\n}\n```\n\nImportant behavior:\n\n- `CssAbsoluteFilter` rewrites relative `url(...)` paths because the generated CSS file moves to a different output directory\n- `AutoSelectParser` is the default parser and prefers `LxmlParser` when `lxml` is installed\n- malformed or unusual markup can require an explicit parser such as `BeautifulSoupParser` or `Html5LibParser`\n\nExample parser override:\n\n```python\nCOMPRESS_PARSER = \"compressor.parser.BeautifulSoupParser\"\n```\n\nPrecompilers let Compressor transform asset types before filtering:\n\n```python\nCOMPRESS_PRECOMPILERS = (\n    (\"text/coffeescript\", \"coffee --compile --stdio\"),\n    (\"text/less\", \"lessc {infile} {outfile}\"),\n    (\"text/x-scss\", \"sass --scss {infile} {outfile}\"),\n)\n```\n\nEvery binary referenced there must be available anywhere you run request-time compression or `python manage.py compress`.\n\n## Jinja2 And django-sekizai\n\nJinja2 support uses `compressor.contrib.jinja2ext.CompressorExtension`:\n\n```python\nimport jinja2\nfrom compressor.contrib.jinja2ext import CompressorExtension\n\nenv = jinja2.Environment(extensions=[CompressorExtension])\n```\n\nFor offline compression with Jinja2 templates:\n\n```python\nCOMPRESS_JINJA2_GET_ENVIRONMENT = \"project.jinja2.environment\"\n```\n\nRun:\n\n```bash\npython manage.py compress --engine jinja2\n```\n\nUpstream limitations worth remembering:\n\n- no support for `{% import %}` and similar blocks inside `{% compress %}`\n- no support for `{{ super() }}`\n- avoid mixing Django and Jinja2 template engines in the same template locations unless you are deliberate about loader order\n\n`django-sekizai` integration exists, but it is not compatible with offline compression. If a project depends on sekizai-style asset collection, do not assume the normal offline deployment flow will work unchanged.\n\n## Common Pitfalls\n\n### Compression is off in development\n\nWith `DEBUG = True`, Compressor disables itself unless `COMPRESS_ENABLED = True`.\n\n### Generated files are missing from staticfiles\n\nIf you use `django.contrib.staticfiles`, missing `compressor.finders.CompressorFinder` is the most common cause.\n\n### `OfflineGenerationError` appears after deploy\n\nUsually one of these is true:\n\n- `python manage.py compress` was never run\n- template variables inside `{% compress %}` were not covered by `COMPRESS_OFFLINE_CONTEXT`\n- new templates shipped without rebuilding the offline manifest\n\n### Remote storage builds fail\n\nCompressor still needs local filesystem access while resolving and writing files. Purely remote storage backends are the common failure mode.\n\n### CSS asset URLs break after compression\n\nIf you replace the default CSS filter chain and remove `CssAbsoluteFilter`, relative `url(...)` references often stop resolving correctly.\n\n### Parser errors show up on malformed templates\n\nUse a different parser instead of forcing the default parser through bad markup.\n\n### Precompiler commands work locally but fail in CI\n\nYour build host needs the same `sass`, `lessc`, `coffee`, or other binaries that the config references.\n\n### sekizai and offline compression are mixed together\n\nThat combination is unsupported upstream.\n\n## Version-Sensitive Notes For 4.6.0\n\n- `4.6.0` adds official Django `5.2` and `6.0` support.\n- `4.6.0` drops Django `5.0` support.\n- `4.6.0` adds Python `3.13` and `3.14` support.\n- `4.6.0` drops Python `3.8` and `3.9` support, so plan on Python `3.10+` for this line.\n- `4.5` introduced `COMPRESS_STORAGE_ALIAS` and `COMPRESS_OFFLINE_MANIFEST_STORAGE_ALIAS`; keep using them in `4.6.0` if the project uses Django `STORAGES`.\n- `4.5.1` fixed remote storage behavior when the backend did not implement `path()`. `4.6.0` includes that fix, so older workarounds written specifically for `4.5.0` may no longer be needed.\n- `4.6.0` also removes the top-end pin on `rcssmin` and `rjsmin` and fixes concurrent compression of the same node during offline generation.\n\n## Official Sources\n\n- Documentation root: https://django-compressor.readthedocs.io/en/stable/\n- Quickstart: https://django-compressor.readthedocs.io/en/stable/quickstart.html\n- Usage: https://django-compressor.readthedocs.io/en/stable/usage.html\n- Common deployment scenarios: https://django-compressor.readthedocs.io/en/stable/scenarios.html\n- Settings: https://django-compressor.readthedocs.io/en/stable/settings.html\n- Remote storages: https://django-compressor.readthedocs.io/en/stable/remote-storages.html\n- Changelog: https://django-compressor.readthedocs.io/en/stable/changelog.html\n- Jinja2 support: https://django-compressor.readthedocs.io/en/stable/jinja2.html\n- django-sekizai support: https://django-compressor.readthedocs.io/en/stable/django-sekizai.html\n- PyPI registry: https://pypi.org/project/django-compressor/\n"
  },
  {
    "path": "content/django/docs/cors-headers/python/DOC.md",
    "content": "---\nname: cors-headers\ndescription: \"django-cors-headers guide for Django projects configuring CORS, credentials, CSRF, and dynamic origin rules\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,cors,http,middleware,csrf,security\"\n---\n\n# django-cors-headers for Django\n\n## Golden Rule\n\n`django-cors-headers` is middleware and settings, not an API client. In Django projects, install the package, add `corsheaders` to `INSTALLED_APPS`, put `corsheaders.middleware.CorsMiddleware` near the top of `MIDDLEWARE`, and prefer explicit allowed origins over permissive wildcard settings.\n\nAs of March 12, 2026, PyPI still lists `4.9.0` as the latest release. Use the 4.9.0 package docs and metadata for version-specific behavior, because the GitHub `main` branch has already moved on to unreleased changes.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"django-cors-headers==4.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"django-cors-headers==4.9.0\"\npoetry add \"django-cors-headers==4.9.0\"\n```\n\n## Django Setup\n\nAdd the app:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"corsheaders\",\n]\n```\n\nThen add the middleware as high as possible, before middleware that can generate responses such as `CommonMiddleware` or `WhiteNoiseMiddleware`:\n\n```python\nMIDDLEWARE = [\n    \"corsheaders.middleware.CorsMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    # ...\n]\n```\n\nMinimal explicit-origin configuration:\n\n```python\nCORS_ALLOWED_ORIGINS = [\n    \"https://app.example.com\",\n    \"http://localhost:3000\",\n]\n```\n\nAt least one of these settings must be configured:\n\n- `CORS_ALLOWED_ORIGINS`\n- `CORS_ALLOWED_ORIGIN_REGEXES`\n- `CORS_ALLOW_ALL_ORIGINS`\n\n## Core Configuration Patterns\n\n### Explicit allowlist\n\nUse this for most production apps:\n\n```python\nCORS_ALLOWED_ORIGINS = [\n    \"https://app.example.com\",\n    \"https://admin.example.com\",\n]\n```\n\nOrigins must include scheme, and port if non-default. Do not use bare hostnames like `\"app.example.com\"`.\n\n### Regex-based subdomains\n\nUse this when you have many tenant subdomains:\n\n```python\nCORS_ALLOWED_ORIGIN_REGEXES = [\n    r\"^https://\\w+\\.example\\.com$\",\n]\n```\n\n### Allow all origins\n\nUse this only for tightly controlled internal cases or local development:\n\n```python\nCORS_ALLOW_ALL_ORIGINS = True\n```\n\n### Restrict CORS to part of the site\n\nIf only your API needs CORS, scope it:\n\n```python\nCORS_URLS_REGEX = r\"^/api/.*$\"\n```\n\n### Extend default methods and headers\n\nUse the package defaults rather than replacing them wholesale:\n\n```python\nfrom corsheaders.defaults import default_headers, default_methods\n\nCORS_ALLOW_HEADERS = (\n    *default_headers,\n    \"x-client-version\",\n)\n\nCORS_ALLOW_METHODS = (\n    *default_methods,\n    \"PURGE\",\n)\n```\n\n## Credentials, Cookies, and CSRF\n\n`django-cors-headers` does not handle authentication by itself. Its job is to emit the right CORS headers so browser requests can reach your Django app.\n\nFor cookie-based auth across origins:\n\n```python\nCORS_ALLOW_CREDENTIALS = True\nSESSION_COOKIE_SAMESITE = \"None\"\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SAMESITE = \"None\"\nCSRF_COOKIE_SECURE = True\n```\n\nFor cross-origin unsafe requests such as `POST`, `PUT`, `PATCH`, and `DELETE`, configure Django CSRF separately. CORS and CSRF are not the same thing:\n\n```python\nCORS_ALLOWED_ORIGINS = [\n    \"https://readonly.example.com\",\n    \"https://app.example.com\",\n]\n\nCSRF_TRUSTED_ORIGINS = [\n    \"https://app.example.com\",\n]\n```\n\nUse `CSRF_TRUSTED_ORIGINS` for origins that need write access over HTTPS. Do not assume a CORS allowlist is enough to satisfy Django CSRF checks.\n\n## Dynamic Origin Rules With Signals\n\nIf static settings are not enough, connect handlers to `corsheaders.signals.check_request_enabled`. If any handler returns truthy, the request is allowed.\n\nExample:\n\n```python\n# myapp/handlers.py\nfrom corsheaders.signals import check_request_enabled\n\ndef cors_allow_public_api(sender, request, **kwargs):\n    return request.path.startswith(\"/public-api/\")\n\ncheck_request_enabled.connect(cors_allow_public_api)\n```\n\nConnect handlers from your app config so they load during startup:\n\n```python\n# myapp/apps.py\nfrom django.apps import AppConfig\n\nclass MyAppConfig(AppConfig):\n    name = \"myapp\"\n\n    def ready(self) -> None:\n        from . import handlers  # noqa: F401\n```\n\nThen reference the app config in `INSTALLED_APPS`, for example `\"myapp.apps.MyAppConfig\"`.\n\n## Common Pitfalls\n\n- Keep the trailing comma in `INSTALLED_APPS`. Without it, agents sometimes turn the entry into a string concatenation bug and trigger `ModuleNotFoundError`.\n- Put `CorsMiddleware` before `CommonMiddleware`, `WhiteNoiseMiddleware`, or other middleware that may return responses early.\n- Include schemes in origins. `https://example.com` is valid; `example.com` is not.\n- Use `CORS_ALLOWED_ORIGINS` for explicit sites and `CSRF_TRUSTED_ORIGINS` for cross-origin write requests. They solve different problems.\n- Prefer the renamed settings: `CORS_ALLOWED_ORIGINS`, `CORS_ALLOWED_ORIGIN_REGEXES`, and `CORS_ALLOW_ALL_ORIGINS`. Older `*_WHITELIST` and `CORS_ORIGIN_ALLOW_ALL` aliases still work, but the new names take precedence.\n- Do not look for the old `CORS_REPLACE_HTTPS_REFERER` setting or `CorsPostCsrfMiddleware`; both were removed in the 4.0.0 release line.\n- For browser clients that need cookies, `CORS_ALLOW_CREDENTIALS = True` is not enough by itself. Django cookie `SameSite` and `Secure` settings still matter.\n\n## Version-Sensitive Notes\n\n- `4.9.0` added Django `6.0` support.\n- PyPI release metadata for `4.9.0` says Python `>=3.9` and documents Python `3.9` to `3.14` support.\n- The current GitHub `main` README now says Python `3.10` to `3.14` supported because a post-4.9.0 changelog entry drops Python `3.9`. That is branch drift, not a contradiction in the 4.9.0 release metadata.\n- `4.0.0` introduced `CORS_ALLOW_PRIVATE_NETWORK`, added async middleware support, and removed `CORS_REPLACE_HTTPS_REFERER` plus `CorsPostCsrfMiddleware`.\n\n## Official Sources\n\n- Maintainer docs and setup guide: `https://github.com/adamchainz/django-cors-headers`\n- Release-specific docs snapshot and metadata: `https://pypi.org/project/django-cors-headers/4.9.0/`\n- Release history and provenance: `https://pypi.org/project/django-cors-headers/`\n- Changelog: `https://raw.githubusercontent.com/adamchainz/django-cors-headers/main/CHANGELOG.rst`\n"
  },
  {
    "path": "content/django/docs/countries/python/DOC.md",
    "content": "---\nname: countries\ndescription: \"django-countries package guide for Django country fields, forms, admin filters, and API serialization\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.2.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-countries,django,countries,forms,flags,drf,django-filter,localization\"\n---\n\n# django-countries Python Package Guide\n\n## What It Does\n\n`django-countries` adds an ISO 3166-1 country field for Django models, translated country names, flag assets, form widgets, admin filters, template tags, and serializer helpers.\n\n- Package: `django-countries`\n- Django app: `django_countries`\n- Main model import: `from django_countries.fields import CountryField`\n- Version covered here: `8.2.0`\n- Docs root: `https://smileychris.github.io/django-countries/`\n- Registry: `https://pypi.org/project/django-countries/`\n\nAs of March 12, 2026, PyPI lists `8.2.0` as the latest release, published on November 24, 2025. The docs site is a latest-version docs site, so check the changelog before assuming newer features exist in older pins.\n\n## Install And Compatibility\n\n```bash\npython -m pip install \"django-countries==8.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"django-countries==8.2.0\"\npoetry add \"django-countries==8.2.0\"\n```\n\nFor better sorting of translated country names:\n\n```bash\npython -m pip install \"django-countries[pyuca]==8.2.0\"\n```\n\nCurrent upstream support signals:\n\n- Python: `3.8` to `3.13`\n- Django docs support table: `3.2`, `4.2`, `5.0`, `5.1`, `5.2`\n- Django REST Framework: `3.11+`\n\nPyPI classifiers still list Django `4.0` and `4.1`, but the docs support table does not. If your project is pinned to Django `4.0` or `4.1`, verify in CI instead of assuming active support.\n\n## Minimal Django Setup\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django_countries\",\n]\n```\n\nCreate a model field:\n\n```python\nfrom django.db import models\nfrom django_countries.fields import CountryField\n\nclass Person(models.Model):\n    name = models.CharField(max_length=100)\n    country = CountryField()\n```\n\nApply migrations:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\n```\n\nQuick verification:\n\n```python\nfrom django_countries import countries\n\nassert countries[\"NZ\"] == \"New Zealand\"\n```\n\n## Core Model Usage\n\n`CountryField` is a `CharField` underneath, with a default `max_length` of `2`. The database stores country codes, but model instances expose a richer `Country` object.\n\n```python\nperson = Person.objects.create(name=\"Chris\", country=\"NZ\")\n\nassert person.country.code == \"NZ\"\nassert person.country.name == \"New Zealand\"\nassert person.country.alpha3 == \"NZL\"\nassert person.country.numeric == 554\nassert person.country.flag.endswith(\"nz.gif\")\n```\n\nUseful properties on the `Country` object include:\n\n- `.code`\n- `.name`\n- `.flag`\n- `.flag_css`\n- `.unicode_flag`\n- `.alpha3`\n- `.numeric`\n- `.ioc_code`\n\nIf you need the country list outside models:\n\n```python\nfrom django_countries import countries\n\ncountry_map = dict(countries)\ncountry_name = country_map[\"BR\"]\n```\n\n## Querying\n\nStore and compare ISO codes directly when you can:\n\n```python\nPerson.objects.filter(country=\"NZ\")\n```\n\nFor country-name lookup, use the dedicated lookups:\n\n```python\nPerson.objects.filter(country__name=\"New Zealand\")\nPerson.objects.filter(country__iname=\"new zealand\")\nPerson.objects.filter(country__icontains=\"zealand\")\n```\n\nDo not rely on `country=\"New Zealand\"` exact matches. Current upstream guidance is to use `__name` or `__iname` for exact name filters.\n\n## Forms, Templates, And Admin\n\nFor custom forms, use the package form field so translated names stay lazy until render time:\n\n```python\nfrom django import forms\nfrom django_countries.fields import CountryField\n\nclass ProfileForm(forms.Form):\n    country = CountryField().formfield()\n```\n\nFor blank values:\n\n```python\ncountry = CountryField(blank=True, blank_label=\"(Select country)\").formfield()\n```\n\nTo show a flag beside the select:\n\n```python\nfrom django import forms\nfrom django_countries.widgets import CountrySelectWidget\n\nclass PersonForm(forms.ModelForm):\n    class Meta:\n        model = Person\n        fields = (\"name\", \"country\")\n        widgets = {\"country\": CountrySelectWidget()}\n```\n\nIn templates:\n\n```django\n{% load countries %}\n{% get_country \"BR\" as country %}\n{{ country.name }}\n<img src=\"{{ country.flag }}\" alt=\"{{ country.name }} flag\">\n```\n\nOr build your own select:\n\n```django\n{% load countries %}\n{% get_countries as countries %}\n<select name=\"country\">\n  {% for country in countries %}\n    <option value=\"{{ country.code }}\">{{ country.name }}</option>\n  {% endfor %}\n</select>\n```\n\nAdmin support works out of the box:\n\n```python\nfrom django.contrib import admin\n\n@admin.register(Person)\nclass PersonAdmin(admin.ModelAdmin):\n    list_display = [\"name\", \"country\"]\n    search_fields = [\"name\", \"country\"]\n```\n\nFor admin list filtering, use the package filter:\n\n```python\nfrom django.contrib import admin\nfrom django_countries.filters import CountryFilter\n\n@admin.register(Person)\nclass PersonAdmin(admin.ModelAdmin):\n    list_filter = [(\"country\", CountryFilter)]\n```\n\nIn `8.2.0`, `CountryFilter` also supports filtering through relations such as `(\"contact__country\", CountryFilter)`.\n\n## Configuration\n\nCommon global settings:\n\n```python\nfrom django.utils.translation import gettext_lazy as _\n\nCOUNTRIES_COMMON_NAMES = True\nCOUNTRIES_ONLY = [\"US\", \"CA\", \"MX\"]\nCOUNTRIES_FIRST = [\"US\", \"CA\"]\nCOUNTRIES_FIRST_BREAK = \"----------\"\nCOUNTRIES_FIRST_BY_LANGUAGE = {\n    \"fr\": [\"FR\", \"CH\", \"BE\", \"LU\"],\n    \"de\": [\"DE\", \"AT\", \"CH\", \"LI\"],\n}\nCOUNTRIES_FIRST_AUTO_DETECT = True\nCOUNTRIES_OVERRIDE = {\n    \"NZ\": _(\"Middle Earth\"),\n    \"AU\": None,\n    \"IND\": {\n        \"names\": [_(\"Indonesia\")],\n        \"ioc_code\": \"INA\",\n        \"flag_url\": \"flags/id.gif\",\n    },\n}\nCOUNTRIES_FLAG_URL = \"flags/16x10/{code_upper}.png\"\n```\n\nWhat each setting is for:\n\n- `COUNTRIES_COMMON_NAMES`: use friendlier common names instead of strict ISO names\n- `COUNTRIES_ONLY`: restrict the available list\n- `COUNTRIES_FIRST`: pin specific countries to the top\n- `COUNTRIES_FIRST_BREAK`: add a separator after pinned countries\n- `COUNTRIES_FIRST_BY_LANGUAGE`: reorder top countries by active language\n- `COUNTRIES_FIRST_AUTO_DETECT`: prepend the locale-detected country when possible\n- `COUNTRIES_OVERRIDE`: rename, exclude, or override metadata for specific countries\n- `COUNTRIES_FLAG_URL`: change where `country.flag` points\n\nSet `COUNTRIES_COMMON_NAMES = False` if you need official ISO naming instead of the package's common-name defaults.\n\n## Per-Request Or Per-Field Customization\n\nIf a single field needs its own country list, pass a custom `Countries` subclass:\n\n```python\nfrom django.db import models\nfrom django.utils.translation import gettext_lazy as _\n\nfrom django_countries import Countries\nfrom django_countries.fields import CountryField\n\nclass G8Countries(Countries):\n    only = [\n        \"CA\",\n        \"FR\",\n        \"DE\",\n        \"IT\",\n        \"JP\",\n        \"GB\",\n        (\"EU\", _(\"European Union\")),\n    ]\n\nclass Vote(models.Model):\n    country = CountryField(countries=G8Countries)\n```\n\nIn `8.2.0`, you can also apply temporary thread-local overrides with `countries_context()`:\n\n```python\nfrom django.shortcuts import render\nfrom django_countries import countries_context\n\ndef checkout_view(request):\n    with countries_context(first=[\"US\", \"CA\"], first_by_language={}):\n        form = ProfileForm()\n    return render(request, \"checkout.html\", {\"form\": form})\n```\n\n`countries_context()` is useful when the country order or allowed list depends on request state, locale, user preference, or geolocation.\n\n## Django REST Framework\n\nFor model serializers, use `CountryFieldMixin`:\n\n```python\nfrom django_countries.serializers import CountryFieldMixin\nfrom rest_framework import serializers\n\nclass PersonSerializer(CountryFieldMixin, serializers.ModelSerializer):\n    class Meta:\n        model = Person\n        fields = (\"name\", \"country\")\n        extra_kwargs = {\n            \"country\": {\"country_dict\": (\"name\", \"alpha3\")},\n        }\n```\n\nIn `8.2.0`, the mixin accepts `name_only`, `country_dict`, and related output options through `Meta.extra_kwargs`, so you do not need to redefine the field for common serializer customization.\n\nFor explicit serializer fields:\n\n```python\nfrom django_countries.serializer_fields import CountryField\nfrom rest_framework import serializers\n\nclass CountrySerializer(serializers.Serializer):\n    country = CountryField(country_dict=(\"code\", \"name\", \"alpha3\"))\n```\n\nSupported `country_dict` keys documented upstream:\n\n- `code`\n- `name`\n- `alpha3`\n- `numeric`\n- `unicode_flag`\n- `ioc_code`\n\n`name_only=True` returns only the country name. The serializer accepts either a code string or a country dictionary as input.\n\n## django-filter Integration\n\n`8.2.0` adds a package helper for `django-filter`:\n\n```python\nimport django_filters\nfrom django_countries.django_filters import CountryFilter\n\nclass PersonFilterSet(django_filters.FilterSet):\n    country = CountryFilter(empty_label=\"Any country\")\n\n    class Meta:\n        model = Person\n        fields = [\"country\"]\n```\n\nThis filter populates its choices from `django_countries.countries`, so you do not have to maintain a duplicated country choice list.\n\n## Multiple-Country Fields\n\nFor multi-select storage:\n\n```python\nfrom django.db import models\nfrom django_countries.fields import CountryField\n\nclass Incident(models.Model):\n    title = models.CharField(max_length=100)\n    countries = CountryField(multiple=True)\n```\n\nBehavior:\n\n- Stored in the database as a comma-separated string\n- Exposed in Python as a list of `Country` objects\n- Sorted and deduplicated by default\n\nIf you need different behavior:\n\n```python\ncountries = CountryField(\n    multiple=True,\n    multiple_sort=False,\n    multiple_unique=False,\n    null=True,\n)\n```\n\n`null=True` for `multiple=True` is an `8.1.0` feature. On older versions, do not assume that combination works.\n\n## Common Pitfalls\n\n- Forgetting `\"django_countries\"` in `INSTALLED_APPS`. The field may import, but templates, widgets, and static flag assets will not be wired correctly.\n- Treating `instance.country` as always being a raw string. On model instances it is a `Country` object; use `.code` if you need the stored alpha-2 code.\n- Building country choices manually in forms. Prefer `CountryField().formfield()` or `CountrySelectWidget()` so translations, blank labels, and widgets stay aligned with package behavior.\n- Forgetting static file handling for flags. If you use `country.flag` or `CountrySelectWidget`, make sure `collectstatic` and `STATIC_URL` or `COUNTRIES_FLAG_URL` match how assets are served.\n- Using Django admin `autocomplete_fields`. Upstream docs say `CountryField` does not support it and falls back to a regular select widget.\n- Mixing up the two filter helpers. Django admin uses `django_countries.filters.CountryFilter`; `django-filter` integration uses `django_countries.django_filters.CountryFilter`.\n- Assuming exact name filters use the plain field. Use `country__name` or `country__iname`, not `country=\"New Zealand\"`.\n- Assuming third-party admin filter packages will work with `CountryField`. Upstream recommends the built-in admin `CountryFilter`.\n\n## Version-Sensitive Notes For `8.2.0`\n\n- PyPI lists `8.2.0` as latest on March 12, 2026, with a release date of November 24, 2025. The changelog entry is dated November 25, 2025.\n- `8.2.0` adds `COUNTRIES_FIRST_BY_LANGUAGE`, `COUNTRIES_FIRST_AUTO_DETECT`, `countries_context()`, `COUNTRIES_OVERRIDE[\"...\"][\"flag_url\"]`, `django_countries.django_filters.CountryFilter`, related-field admin filtering, and `CountryFieldMixin` `Meta.extra_kwargs` customization.\n- `8.2.0` also fixes `CountryField.formfield(empty_label=...)`, admin filtering for `multiple=True`, related admin filtering, and localized name deserialization in serializer fields.\n- `8.1.0` adds `null=True` support for `CountryField(multiple=True)` and improves OpenAPI generation for `country_dict` and `name_only`.\n- `8.1.1` fixes selected-option rendering for `CountryField(multiple=True)` in Django forms.\n- `8.0.0` rolled in the previously yanked `7.8`, `7.9`, and `7.9.1` changes and dropped Python `3.7`. Do not pin to those yanked `7.x` releases.\n- The docs site is not version-frozen. If your project is pinned below `8.2.0`, verify against the changelog before copying examples that use dynamic ordering, `countries_context()`, or the new filter helpers.\n\n## Official Sources Used\n\n- Docs root: `https://smileychris.github.io/django-countries/`\n- Installation: `https://smileychris.github.io/django-countries/installation/`\n- CountryField reference: `https://smileychris.github.io/django-countries/usage/field/`\n- Forms and widgets: `https://smileychris.github.io/django-countries/usage/forms/`\n- Settings: `https://smileychris.github.io/django-countries/usage/settings/`\n- Django REST Framework integration: `https://smileychris.github.io/django-countries/integrations/drf/`\n- django-filter integration: `https://smileychris.github.io/django-countries/integrations/django_filters/`\n- Customization and dynamic ordering: `https://smileychris.github.io/django-countries/advanced/customization/`\n- Multiple countries: `https://smileychris.github.io/django-countries/advanced/multiple/`\n- Changelog: `https://smileychris.github.io/django-countries/changelog/`\n- Repository: `https://github.com/SmileyChris/django-countries`\n- PyPI package page: `https://pypi.org/project/django-countries/`\n"
  },
  {
    "path": "content/django/docs/crispy-forms/python/DOC.md",
    "content": "---\nname: crispy-forms\ndescription: \"django-crispy-forms 2.6 for Python - practical guide to template-pack setup and form rendering\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,forms,templates,bootstrap,pypi,crispy\"\n---\n\n# django-crispy-forms 2.6 for Python\n\n`django-crispy-forms` keeps Django's normal forms, validation, and view flow, but gives you helper objects and layout primitives so you can control HTML rendering without hand-writing every field template.\n\nThis entry is for `django-crispy-forms==2.6`, the current PyPI release as of March 1, 2026.\n\n## Install\n\nInstall the core package plus one template-pack package that matches your frontend stack. Since crispy-forms `2.x`, template packs are not bundled in the core package.\n\n```bash\npip install django-crispy-forms crispy-bootstrap5\n```\n\nIf you use `uv`:\n\n```bash\nuv add django-crispy-forms crispy-bootstrap5\n```\n\nIf you use Poetry:\n\n```bash\npoetry add django-crispy-forms crispy-bootstrap5\n```\n\nBootstrap 5 is the current default choice for new projects. If your project is still on Bootstrap 4, use `crispy-bootstrap4` instead and set the corresponding template-pack values.\n\n## Django Setup\n\nAdd the core app and the template-pack app to `INSTALLED_APPS`, then set the allowed and default template pack.\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"crispy_forms\",\n    \"crispy_bootstrap5\",\n]\n\nCRISPY_ALLOWED_TEMPLATE_PACKS = \"bootstrap5\"\nCRISPY_TEMPLATE_PACK = \"bootstrap5\"\n```\n\nThere is no package-specific auth flow. Configuration is ordinary Django settings plus your project's normal form security rules such as CSRF protection.\n\nOne upstream gotcha: the core install page still shows `uni_form` as a placeholder setting example. Do not copy that into a new Bootstrap-based project; use the value required by the template pack you actually installed.\n\n## Basic Usage\n\nUse the `{% crispy %}` tag when you want helper-driven rendering and layout objects.\n\n```python\nfrom django import forms\nfrom crispy_forms.helper import FormHelper\nfrom crispy_forms.layout import Field, Layout, Submit\n\nclass ContactForm(forms.Form):\n    name = forms.CharField(max_length=100)\n    email = forms.EmailField()\n    message = forms.CharField(widget=forms.Textarea)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.helper = FormHelper()\n        self.helper.form_method = \"post\"\n        self.helper.layout = Layout(\n            Field(\"name\"),\n            Field(\"email\"),\n            Field(\"message\", rows=4),\n            Submit(\"submit\", \"Send\"),\n        )\n```\n\n```django\n{% load crispy_forms_tags %}\n\n<form method=\"post\">\n  {% csrf_token %}\n  {% crispy form %}\n</form>\n```\n\nIf you just want default pack styling without a custom layout, the filter form is shorter:\n\n```django\n{% load crispy_forms_tags %}\n{{ form|crispy }}\n```\n\nUse `{{ form|crispy }}` for quick rendering. Use `{% crispy form %}` when you need a `FormHelper`, custom layout objects, helper options, or custom submit controls.\n\n## FormHelper Options That Matter\n\nMost real setup issues are `FormHelper` issues.\n\n```python\nself.helper = FormHelper()\nself.helper.form_method = \"post\"\nself.helper.form_action = \"/contact/\"\nself.helper.form_tag = False\nself.helper.disable_csrf = True\nself.helper.include_media = False\nself.helper.attrs = {\"data-controller\": \"contact\"}\n```\n\nImportant behavior:\n\n- `form_method` and `form_action` control the rendered `<form>` tag when `form_tag` is enabled.\n- `form_tag = False` is useful when the template already owns the outer `<form>`.\n- `disable_csrf = True` only affects crispy's injected token; it does not disable Django's CSRF protection.\n- `include_media = False` prevents duplicate widget media when the page template handles media separately.\n- `attrs` lets you add arbitrary HTML attributes. Upstream converts underscores in keys to hyphens.\n- `render_unmentioned_fields = True` can save you from accidentally hiding fields that were left out of a custom layout.\n\nIf `form_tag = False`, crispy-forms will not render `<form>` tags for you, and you still need to provide `{% csrf_token %}` in the template unless you deliberately handle that elsewhere.\n\n## Layout Primitives\n\nThe main value of crispy-forms is composing Python layout objects instead of duplicating field HTML in templates.\n\n```python\nfrom crispy_forms.layout import Div, Field, HTML, Layout, Submit\n\nself.helper.layout = Layout(\n    Div(\n        Field(\"name\", css_class=\"form-control-lg\"),\n        Field(\"email\"),\n        css_class=\"row g-3\",\n    ),\n    Field(\"message\", placeholder=\"What do you need?\"),\n    HTML(\"<p class='form-text'>We usually reply within one business day.</p>\"),\n    Submit(\"save\", \"Save\"),\n)\n```\n\nThe layout objects you will reach for first:\n\n- `Field` to set widget attributes or wrapper classes for one field\n- `Div` to group fields and attach CSS classes\n- `Fieldset` when you need a labeled section\n- `HTML` for small inline template fragments\n- `Submit`, `Button`, and `Reset` for actions\n\nPrefer building helpers per form instance in `__init__` if you mutate layout or helper state. Shared class-level helpers are easy to accidentally reuse across requests.\n\n## Practical Patterns\n\n### ModelForm with helper\n\n```python\nfrom django.forms import ModelForm\nfrom crispy_forms.helper import FormHelper\nfrom crispy_forms.layout import Layout, Submit\n\nclass ProjectForm(ModelForm):\n    class Meta:\n        model = Project\n        fields = [\"name\", \"slug\", \"description\"]\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.helper = FormHelper(self)\n        self.helper.form_method = \"post\"\n        self.helper.layout = Layout(\"name\", \"slug\", \"description\")\n        self.helper.add_input(Submit(\"submit\", \"Create project\"))\n```\n\n### Re-render a bound form for AJAX or HTMX responses\n\nWhen you need HTML for a form fragment after server-side validation, use `render_crispy_form`.\n\n```python\nfrom crispy_forms.utils import render_crispy_form\nfrom django.template.context_processors import csrf\n\ndef render_form_fragment(request, form):\n    return render_crispy_form(form, context=csrf(request))\n```\n\n## Config And Failure Behavior\n\nUseful project-level settings:\n\n- `CRISPY_FAIL_SILENTLY = not DEBUG` controls whether crispy template errors are swallowed or raised.\n- `CRISPY_CLASS_CONVERTERS` lets you map Django's default widget classes to classes expected by your CSS framework.\n- `CRISPY_ALLOWED_TEMPLATE_PACKS` should include only packs you intentionally support.\n- `CRISPY_TEMPLATE_PACK` sets the default pack for forms that do not override `helper.template_pack`.\n\nThere is still no package-managed auth, session, or permission layer here. Keep validation, permissions, and persistence in ordinary Django forms, models, and views.\n\n## Common Pitfalls\n\n- Installing only `django-crispy-forms` and forgetting the separate template-pack package required in `2.x`.\n- Adding `crispy_forms` to `INSTALLED_APPS` but forgetting the pack app such as `crispy_bootstrap5`.\n- Copying old snippets that set `CRISPY_TEMPLATE_PACK = \"bootstrap4\"` or `uni_form` without matching installed packages.\n- Using `{% crispy form %}` without `{% load crispy_forms_tags %}`.\n- Setting `form_tag = False` and then forgetting to render the outer `<form>` element and CSRF token yourself.\n- Building a custom layout and then assuming omitted fields will still render unless you set `render_unmentioned_fields = True`.\n- Expecting crispy-forms to change validation, save behavior, or authorization. It only changes rendering.\n\n## Version-Sensitive Notes For 2.6\n\n- This doc targets `django-crispy-forms==2.6`.\n- PyPI marks `2.6` as the latest stable release, published on March 1, 2026.\n- The project metadata for `2.6` supports Python `3.10` through `3.14`.\n- The project metadata for `2.6` advertises Django `5.2` and `6.0`; if your stack is older, check an earlier crispy-forms release instead of copying 2.6 setup.\n- The big compatibility break is still the `2.0` line: template packs moved out of core, so many `1.x` blog posts are wrong for current installs.\n\n## Official Sources\n\n- Core docs root: https://django-crispy-forms.readthedocs.io/en/latest/\n- Installation: https://django-crispy-forms.readthedocs.io/en/latest/install.html\n- Crispy tag and filters: https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html\n- Form helper API: https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html\n- Layout objects: https://django-crispy-forms.readthedocs.io/en/latest/layouts.html\n- PyPI package: https://pypi.org/project/django-crispy-forms/\n- Bootstrap 5 template pack: https://pypi.org/project/crispy-bootstrap5/\n"
  },
  {
    "path": "content/django/docs/csp/python/DOC.md",
    "content": "---\nname: csp\ndescription: \"django-csp 4.0 for Django projects: dict-based CSP settings, nonce handling, decorators, report-only policies, and 3.8 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-csp,csp,security,http-headers,xss\"\n---\n\n# django-csp 4.0 Python Package Guide\n\n## What It Does\n\n`django-csp` adds `Content-Security-Policy` headers to Django responses. In `4.0`, the package uses dict-based settings, supports enforced and report-only policies side by side, exposes constants such as `SELF` and `NONCE`, and changes the decorator API compared with `3.8`.\n\n## Install\n\n```bash\npip install django-csp==4.0\n```\n\nOptional Jinja template helper support:\n\n```bash\npip install \"django-csp[jinja2]==4.0\"\n```\n\n## Initialize Django\n\n`4.0` setup requires both the Django app and the middleware:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"csp\",\n    # ...\n]\n\nMIDDLEWARE = [\n    # ...\n    \"csp.middleware.CSPMiddleware\",\n    # ...\n]\n```\n\nMiddleware order usually does not matter unless other middleware mutates CSP headers or needs to force nonce generation before the response is processed.\n\n## Core Configuration\n\n`4.0` no longer uses `CSP_*` settings. Put policy dictionaries in `CONTENT_SECURITY_POLICY` and optionally `CONTENT_SECURITY_POLICY_REPORT_ONLY`.\n\n```python\n# settings.py\nfrom csp.constants import NONE, SELF\n\nCONTENT_SECURITY_POLICY = {\n    \"DIRECTIVES\": {\n        \"default-src\": [SELF],\n        \"script-src\": [SELF, \"cdn.example.com\"],\n        \"style-src\": [SELF, \"fonts.googleapis.com\"],\n        \"font-src\": [SELF, \"fonts.gstatic.com\"],\n        \"img-src\": [SELF, \"data:\"],\n        \"connect-src\": [SELF, \"api.example.com\"],\n        \"object-src\": [NONE],\n        \"base-uri\": [SELF],\n        \"frame-ancestors\": [NONE],\n        \"form-action\": [SELF],\n    },\n}\n```\n\nIf you are tightening an existing site, add a report-only policy first:\n\n```python\nfrom csp.constants import NONE, SELF\n\nCONTENT_SECURITY_POLICY_REPORT_ONLY = {\n    \"DIRECTIVES\": {\n        \"default-src\": [NONE],\n        \"script-src\": [SELF],\n        \"style-src\": [SELF],\n        \"img-src\": [SELF],\n        \"connect-src\": [SELF],\n        \"frame-ancestors\": [SELF],\n        \"form-action\": [SELF],\n        \"upgrade-insecure-requests\": True,\n        \"report-uri\": [\"/csp-report/\"],\n    },\n}\n```\n\nPractical notes:\n\n- Directive names use lowercase CSP names with dashes, such as `\"default-src\"` and `\"frame-ancestors\"`.\n- Use `csp.constants` for keywords like `SELF`, `NONE`, and `NONCE` to avoid quoting mistakes.\n- `NONE` is the CSP keyword `\"'none'\"`; Python `None` means remove that directive from the built header.\n- Use lists or tuples for directive values. A plain string where a sequence is expected can produce invalid or surprising policies.\n\n## Nonces\n\nIn `4.0`, nonce inclusion moved into the directive itself. Add `NONCE` to `script-src` or `style-src`, then access `request.csp_nonce` before the middleware writes the response header.\n\n```python\n# settings.py\nfrom csp.constants import NONCE, SELF\n\nCONTENT_SECURITY_POLICY = {\n    \"DIRECTIVES\": {\n        \"default-src\": [SELF],\n        \"script-src\": [SELF, NONCE],\n    },\n}\n```\n\nIn a Django template:\n\n```django\n<script nonce=\"{{ request.csp_nonce }}\">\n  window.appConfig = {{ config_json|safe }};\n</script>\n```\n\nImportant `4.0` nonce behavior:\n\n- The nonce is only added if `NONCE` is present in `script-src` or `style-src` and `request.csp_nonce` is actually accessed before response processing finishes.\n- `bool(request.csp_nonce)` does not generate the nonce in `4.0`; use `str(request.csp_nonce)` or render it in a template.\n- Reading an ungenerated nonce after response processing raises `csp.exceptions.CSPNonceError`.\n- Nonces are not exposed in browser devtools; verify them with page source.\n\nIf custom middleware needs the nonce, place that middleware after `csp.middleware.CSPMiddleware` and force generation during request handling.\n\n## Optional Template Helpers\n\nIf you use many nonced scripts, expose `CSP_NONCE` globally:\n\n```python\n# settings.py\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"OPTIONS\": {\n            \"context_processors\": [\n                # ...\n                \"csp.context_processors.nonce\",\n            ],\n            \"libraries\": {\n                \"csp\": \"csp.templatetags.csp\",\n            },\n        },\n    },\n]\n```\n\nThen use the provided template tag:\n\n```django\n{% load csp %}\n{% script type=\"application/javascript\" async=False %}\n  <script>\n    console.log(\"nonced\");\n  </script>\n{% endscript %}\n```\n\nFor Jinja, install the `jinja2` extra or provide `jinja2>=2.9.6` yourself, then add `csp.extensions.NoncedScript` to the template backend.\n\n## Per-View Overrides\n\nAll `4.0` decorators now take a directive dictionary. `REPORT_ONLY=True` targets the report-only policy instead of the enforced policy.\n\n```python\nfrom django.shortcuts import render\nfrom csp.constants import SELF\nfrom csp.decorators import csp, csp_exempt, csp_replace, csp_update\n\n@csp_update({\"img-src\": \"imgsrv.example.com\"})\ndef dashboard(request):\n    return render(request, \"dashboard.html\")\n\n@csp_replace({\"frame-ancestors\": [SELF]})\ndef embeddable(request):\n    return render(request, \"embed.html\")\n\n@csp({\"default-src\": [SELF], \"script-src\": [SELF, \"js.example.com\"]})\ndef strict_view(request):\n    return render(request, \"strict.html\")\n\n@csp_exempt()\ndef legacy_callback(request):\n    return render(request, \"callback.html\")\n```\n\nUse these sparingly. `@csp_exempt()` now requires parentheses in `4.0`, even with no arguments.\n\n## Violation Reports\n\n`django-csp` does not process reports for you. You need your own endpoint or a third-party reporting service.\n\nIf you want to sample reports, switch middleware classes and set the percentage:\n\n```python\n# settings.py\nfrom csp.constants import SELF\n\nMIDDLEWARE = [\n    # ...\n    \"csp.contrib.rate_limiting.RateLimitedCSPMiddleware\",\n    # ...\n]\n\nCONTENT_SECURITY_POLICY_REPORT_ONLY = {\n    \"REPORT_PERCENTAGE\": 10.0,\n    \"DIRECTIVES\": {\n        \"default-src\": [SELF],\n        \"report-uri\": [\"/csp-report/\"],\n    },\n}\n```\n\nIn `4.0`, `REPORT_PERCENTAGE` is a float between `0.0` and `100.0`, so `10.0` means 10% of requests include `report-uri`.\n\n## Trusted Types\n\nTrusted Types help with DOM XSS, not just server-rendered inline scripts. The upstream guide recommends enabling them in report-only mode first:\n\n```python\nCONTENT_SECURITY_POLICY_REPORT_ONLY = {\n    \"DIRECTIVES\": {\n        \"require-trusted-types-for\": [\"'script'\"],\n        \"trusted-types\": [\"default\"],\n        \"report-uri\": [\"/csp-report/\"],\n    },\n}\n```\n\nThen fix violating sinks such as `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, and `DOMParser.parseFromString` before enforcing the policy. The docs prefer rewriting code or using a library like DOMPurify over hand-rolled sanitizers.\n\n## Authentication And Runtime Model\n\n`django-csp` has no authentication layer, credentials, or external service handshake. Its runtime model is purely Django settings, middleware, decorators, and template integration. Most production mistakes come from policy shape and middleware behavior, not auth.\n\n## Common Pitfalls\n\n- `4.0` is not backward-compatible with `3.8`. Old `CSP_*` settings are not supported.\n- Add `\"csp\"` to `INSTALLED_APPS`; this is now part of the official install path.\n- Decorators now take a single directive dictionary, and `@csp_exempt()` needs parentheses.\n- `default-src` does not automatically cover a directive once that directive is explicitly set. If you add `img-src`, include every image source you need there.\n- `REPORT_PERCENTAGE` requires `csp.contrib.rate_limiting.RateLimitedCSPMiddleware`; it is ignored with the default middleware.\n- `REPORT_PERCENTAGE` units changed from the `3.8` style fraction to a `0.0` to `100.0` percentage.\n- `NONCE` moved from `CSP_INCLUDE_NONCE_IN` to directive values, and `request.csp_nonce` is lazy in a different way than `3.8`.\n- Python `None` removes a directive; `csp.constants.NONE` emits the CSP keyword `'none'`.\n- `csp` is the Django integration namespace even though the PyPI package name is `django-csp`.\n\n## Version-Sensitive Notes\n\n- `4.0` was released on April 2, 2025.\n- The `v4.0` release notes call out several breaking changes:\n  - configuration moved from `CSP_*` settings to `CONTENT_SECURITY_POLICY` and `CONTENT_SECURITY_POLICY_REPORT_ONLY`\n  - nonce configuration moved to the `NONCE` sentinel inside directive values\n  - `request.csp_nonce` is falsy until read as a string\n  - Django `<=3.2` support was dropped\n  - Python `3.8` support was dropped\n- `python manage.py check` can help find legacy `CSP_*` settings and generate a migration starting point.\n- If you subclass `CSPMiddleware`, `build_policy()` and `build_policy_ro()` are deprecated in `4.0` and scheduled for removal in `4.1`; migrate custom middleware to `build_policy_parts()`.\n\nIf the target project is pinned to `django-csp==3.8` or older, do not copy this file's `4.0` configuration and decorator examples into that codebase.\n\n## Official Sources\n\n- Docs root: https://django-csp.readthedocs.io/en/latest/\n- Installation: https://django-csp.readthedocs.io/en/latest/installation.html\n- Configuration: https://django-csp.readthedocs.io/en/latest/configuration.html\n- Migration guide: https://django-csp.readthedocs.io/en/latest/migration-guide.html\n- Decorators: https://django-csp.readthedocs.io/en/latest/decorators.html\n- Nonces: https://django-csp.readthedocs.io/en/latest/nonce.html\n- Violation reports: https://django-csp.readthedocs.io/en/latest/reports.html\n- Trusted Types: https://django-csp.readthedocs.io/en/latest/trusted_types.html\n- PyPI: https://pypi.org/project/django-csp/\n- Release notes: https://github.com/mozilla/django-csp/releases\n"
  },
  {
    "path": "content/django/docs/debug-toolbar/python/DOC.md",
    "content": "---\nname: debug-toolbar\ndescription: \"django-debug-toolbar package guide for Django request inspection, SQL debugging, and development-only diagnostics\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,debugging,toolbar,sql,profiling,development\"\n---\n\n# django-debug-toolbar Python Package Guide\n\n## What It Is\n\n`django-debug-toolbar` adds an in-browser toolbar to Django development pages so you can inspect SQL, templates, headers, cache calls, signals, request data, and request history.\n\nThis entry is for `django-debug-toolbar==6.2.0`, the current stable PyPI release as of March 12, 2026. Upstream states that `6.2.0` requires Python `>=3.10`, works with Django `>=4.2`, and still has only experimental async support without concurrent-request support.\n\n## Install\n\nInstall it only in development environments:\n\n```bash\npython -m pip install django-debug-toolbar==6.2.0\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev django-debug-toolbar==6.2.0\npoetry add --group dev django-debug-toolbar==6.2.0\n```\n\nPrerequisites the upstream install guide assumes are already present:\n\n- `django.contrib.staticfiles` is enabled\n- your `TEMPLATES` setting uses a `DjangoTemplates` backend with `APP_DIRS = True`\n- you are rendering HTML responses with a closing `</body>` tag\n\n## Minimal Setup\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django.contrib.staticfiles\",\n    \"debug_toolbar\",\n]\n```\n\nAdd the middleware as early as possible, but after middleware that encodes response content such as `GZipMiddleware`:\n\n```python\n# settings.py\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"debug_toolbar.middleware.DebugToolbarMiddleware\",\n    # ...\n]\n```\n\nAllow local requests:\n\n```python\n# settings.py\nINTERNAL_IPS = [\n    \"127.0.0.1\",\n    \"::1\",\n]\n```\n\nAdd the URLs:\n\n```python\n# urls.py\nfrom django.urls import path\nfrom debug_toolbar.toolbar import debug_toolbar_urls\n\nurlpatterns = [\n    # ...\n] + debug_toolbar_urls()\n```\n\nThe helper above uses the default `__debug__` prefix. If you want an explicit route, this also works:\n\n```python\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"__debug__/\", include(\"debug_toolbar.urls\")),\n    # ...\n]\n```\n\n## Recommended Development-Only Pattern\n\nKeep the toolbar out of production and test settings.\n\n```python\n# settings/dev.py\nimport os\nimport sys\n\nfrom .base import *  # noqa: F403\n\nTESTING = \"test\" in sys.argv or \"PYTEST_VERSION\" in os.environ\n\nif not TESTING:\n    INSTALLED_APPS += [\"debug_toolbar\"]  # noqa: F405\n    MIDDLEWARE = [  # noqa: F405\n        \"debug_toolbar.middleware.DebugToolbarMiddleware\",\n        *MIDDLEWARE,\n    ]\n    INTERNAL_IPS = [\"127.0.0.1\", \"::1\"]\n```\n\n```python\n# urls.py\nfrom django.conf import settings\n\nurlpatterns = [\n    # ...\n]\n\nif not getattr(settings, \"TESTING\", False):\n    from debug_toolbar.toolbar import debug_toolbar_urls\n\n    urlpatterns += debug_toolbar_urls()\n```\n\nIf your project has a nonstandard test command, set `DEBUG_TOOLBAR_CONFIG[\"IS_RUNNING_TESTS\"]` explicitly.\n\n## Core Usage\n\nOpen a normal HTML page in development and use the toolbar to inspect the current request.\n\nPanels most useful in day-to-day work:\n\n- `SQL`: query count, duplicate queries, timings, and `EXPLAIN`\n- `Templates`: rendered templates and context\n- `Headers`: request/response headers\n- `Request`: GET, POST, cookies, and session data\n- `Cache`: cache hits and misses\n- `History`: switch back to prior requests\n- `Signals`: fired signals and receivers\n\nTypical workflow:\n\n1. Load the slow or incorrect page.\n2. Open `SQL` first for N+1 queries or bad joins.\n3. Open `Templates` when the wrong context or fragment renders.\n4. Open `Headers` and `Request` for cookies, CSRF, auth, or proxy/header issues.\n5. Use `History` to compare a redirect target or the last few requests.\n\nThe package also ships a useful management command:\n\n```bash\npython manage.py debugsqlshell\n```\n\nUse `debugsqlshell` when you want ORM queries printed interactively while experimenting with queryset changes.\n\n## Visibility and Access Control\n\nThere is no auth layer inside the toolbar. Access is controlled by Django settings, mainly `DEBUG`, `INTERNAL_IPS`, and `SHOW_TOOLBAR_CALLBACK`.\n\nFor most projects, a callback is the safest place to centralize visibility rules:\n\n```python\n# project/debug_toolbar.py\nfrom django.conf import settings\n\ndef show_toolbar(request):\n    return (\n        settings.DEBUG\n        and request.user.is_staff\n        and request.META.get(\"REMOTE_ADDR\") in {\"127.0.0.1\", \"::1\"}\n    )\n```\n\n```python\n# settings.py\nDEBUG_TOOLBAR_CONFIG = {\n    \"SHOW_TOOLBAR_CALLBACK\": \"project.debug_toolbar.show_toolbar\",\n}\n```\n\nDo not use a lambda that closes over your module-level `DEBUG` variable. Upstream explicitly warns that this behaves badly under tests because Django forces `settings.DEBUG = False` while your module variable may stay `True`.\n\nThe upstream configuration docs also warn that the toolbar is not hardened for production use. If `SECRET_KEY` leaks, the SQL panel can become especially risky.\n\n## Docker, WSL, and Remote Dev\n\nThe most common reason the toolbar does not appear in containers or remote dev is that the incoming IP is not in `INTERNAL_IPS`.\n\nFor `6.0+`, upstream added a Docker helper callback:\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"SHOW_TOOLBAR_CALLBACK\": \"debug_toolbar.middleware.show_toolbar_with_docker\",\n}\n```\n\nUse that when developing inside Docker and the gateway IP changes often. If that still does not fit your setup, write your own callback and inspect `request.META[\"REMOTE_ADDR\"]`.\n\n## Useful Configuration\n\nKeep configuration minimal. The upstream docs explicitly say not to copy the entire default config into your settings.\n\n### Reduce noise or cost\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"RESULTS_CACHE_SIZE\": 10,\n}\n```\n\nLower `RESULTS_CACHE_SIZE` if you want to reduce memory use during development.\n\n### HTMX or Turbo\n\nIf you use boosted page updates, preserve the toolbar root element and optionally update the toolbar after fetches:\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"ROOT_TAG_EXTRA_ATTRS\": \"hx-preserve\",\n    \"UPDATE_ON_FETCH\": True,\n}\n```\n\nFor Hotwire Turbo, switch the root tag attribute:\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"ROOT_TAG_EXTRA_ATTRS\": \"data-turbo-permanent\",\n    \"UPDATE_ON_FETCH\": True,\n}\n```\n\n`UPDATE_ON_FETCH` defaults to `False`, so AJAX or boosted navigation can otherwise leave the toolbar showing stale request data.\n\n### Store request data in the database\n\n`6.0+` added `TOOLBAR_STORE_CLASS`:\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"TOOLBAR_STORE_CLASS\": \"debug_toolbar.store.DatabaseStore\",\n}\n```\n\nIf you use `DatabaseStore`, run the app migrations:\n\n```bash\npython manage.py migrate debug_toolbar\n```\n\nUse `DatabaseStore` only when you actually need persistence across request rendering boundaries. The default `MemoryStore` is simpler for normal local development.\n\n### Disable expensive panels\n\n```python\nDEBUG_TOOLBAR_CONFIG = {\n    \"DISABLE_PANELS\": {\n        \"debug_toolbar.panels.profiling.ProfilingPanel\",\n    },\n}\n```\n\nYou can also trim `DEBUG_TOOLBAR_PANELS` entirely if some panels are irrelevant to your project.\n\n## Profiling Notes\n\n`ProfilingPanel` is included but disabled by default. On Python `3.12+`, upstream says you must run the development server with `--nothreading` for profiling to work reliably:\n\n```bash\npython -m manage runserver --nothreading\n```\n\nThe profiling panel and parts of async support are still limited around concurrent requests. Do not treat it as reliable under high-concurrency or Channels-based development flows.\n\n## Async and HTML Limitations\n\nUpstream now supports Django async views and ASGI environments experimentally, but still documents important limits:\n\n- concurrent requests are not supported\n- `TimerPanel`, `RequestPanel`, and `ProfilingPanel` do not work in async contexts\n- Django Channels is not supported\n\nThe toolbar only injects itself into HTML responses with MIME type `text/html` or `application/xhtml+xml` that include a closing `</body>` tag. Do not expect it on JSON APIs.\n\n## Common Pitfalls\n\n### The toolbar never appears\n\nCheck these first:\n\n- `DEBUG` is `True`\n- the response is HTML and contains `</body>`\n- `debug_toolbar` is in `INSTALLED_APPS`\n- `DebugToolbarMiddleware` is in `MIDDLEWARE`\n- the request IP is allowed by `INTERNAL_IPS` or `SHOW_TOOLBAR_CALLBACK`\n- toolbar URLs are included\n\n### Middleware order is wrong\n\nPut the middleware early. If another middleware returns a response before the toolbar runs, the toolbar will not be injected.\n\n### Static files are broken\n\nIf `toolbar.js` fails to load, check the browser console. Upstream calls out two recurring causes:\n\n- incorrect MIME types for `.js` files on some platforms\n- cross-origin static file hosting without the right CORS headers\n\n### History or stored panels do not behave as expected\n\n`HistoryPanel` is disabled when `RENDER_PANELS = True` or when the server runs with multiple processes. That behavior is upstream, not a misconfiguration in your project.\n\n### Tests break after adding the toolbar\n\nDo not leave the toolbar enabled during tests. Gate it behind `TESTING` or configure `IS_RUNNING_TESTS`.\n\n## Version-Sensitive Notes for 6.2.0\n\n- `6.2.0` deprecates `RedirectsPanel` in favor of `HistoryPanel` for redirected requests.\n- `6.2.0` drops Python `3.9`; use Python `3.10+`.\n- `6.1.0` added `CommunityPanel` to the default built-in panel set.\n- `6.0.0` added `show_toolbar_with_docker` and `TOOLBAR_STORE_CLASS`.\n- `UPDATE_ON_FETCH` exists in current releases but still defaults to `False`.\n- If you are upgrading from `5.0.x`, re-check async, Docker, and request-store behavior instead of copying an old settings snippet unchanged.\n\n## Official Links\n\n- Documentation root: https://django-debug-toolbar.readthedocs.io/en/latest/\n- Installation: https://django-debug-toolbar.readthedocs.io/en/latest/installation.html\n- Configuration: https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html\n- Tips: https://django-debug-toolbar.readthedocs.io/en/latest/tips.html\n- Panels: https://django-debug-toolbar.readthedocs.io/en/latest/panels.html\n- Commands: https://django-debug-toolbar.readthedocs.io/en/latest/commands.html\n- Change log: https://django-debug-toolbar.readthedocs.io/en/latest/changes.html\n- PyPI: https://pypi.org/project/django-debug-toolbar/\n"
  },
  {
    "path": "content/django/docs/environ/python/DOC.md",
    "content": "---\nname: environ\ndescription: \"django-environ package guide for Python - environment-driven Django settings and URL-based config parsing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-environ,django,environment,settings,configuration,secrets,12factor\"\n---\n\n# django-environ Python Package Guide\n\n## When To Use It\n\n`django-environ` reads Django settings from environment variables and `.env` files. It provides typed accessors such as `bool`, `int`, `list`, and `json`, plus URL parsers for databases, caches, email, and search backends.\n\nThis entry is pinned to package version `0.13.0`. The import path is `import environ`, and the docs explicitly note that you do not add `django-environ` to `INSTALLED_APPS`.\n\nCurrent upstream requirements for `0.13.0`:\n\n- Python `>=3.9`\n- Django `>=2.2`\n\n## Install\n\n```bash\npython -m pip install django-environ==0.13.0\n```\n\n## Initialize In `settings.py`\n\n```python\nfrom pathlib import Path\nimport environ\n\nBASE_DIR = Path(__file__).resolve().parent.parent\n\nenv = environ.Env(\n    DEBUG=(bool, False),\n    SECRET_KEY=(str, \"\"),\n    ALLOWED_HOSTS=(list, [\"localhost\", \"127.0.0.1\"]),\n)\n\n# Use an explicit path so startup does not depend on cwd or stack inspection.\nenviron.Env.read_env(BASE_DIR / \".env\")\n\nDEBUG = env(\"DEBUG\")\nSECRET_KEY = env(\"SECRET_KEY\")\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\")\n\nDATABASES = {\n    \"default\": env.db(\n        \"DATABASE_URL\",\n        default=f\"sqlite:///{BASE_DIR / 'db.sqlite3'}\",\n    )\n}\n\nCACHES = {\n    \"default\": env.cache(\n        \"CACHE_URL\",\n        default=\"locmemcache://\",\n    )\n}\n```\n\nExample `.env`:\n\n```dotenv\nDEBUG=True\nSECRET_KEY=change-me\nALLOWED_HOSTS=localhost,127.0.0.1\nDATABASE_URL=postgres://app:secret@127.0.0.1:5432/app\nCACHE_URL=redis://127.0.0.1:6379/1\n```\n\nThe upstream quickstart pattern is: define casts and defaults on `Env(...)`, call `read_env(...)`, then read variables with `env(\"NAME\")` or explicit helpers like `env.int(...)` and `env.db(...)`.\n\n## Core Patterns\n\n### Scalars And Collections\n\n```python\nDEBUG = env.bool(\"DEBUG\", default=False)\nPORT = env.int(\"PORT\", default=8000)\nSITE_NAME = env.str(\"SITE_NAME\", default=\"example\")\nALLOWED_HOSTS = env.list(\"ALLOWED_HOSTS\", default=[\"localhost\"])\nFEATURE_FLAGS = env.json(\"FEATURE_FLAGS\", default={})\nSAML_ATTRIBUTE_MAPPING = env.dict(\n    \"SAML_ATTRIBUTE_MAPPING\",\n    default={},\n)\n```\n\nUse the typed helpers directly instead of relying on smart-casting from `default=`. The docs say smart-casting is still enabled by default in `0.13.0`, but it can have side effects and is planned to change in the next major release.\n\n### URL-Based Django Settings\n\n```python\nDATABASES = {\n    \"default\": env.db(\n        \"DATABASE_URL\",\n        default=f\"sqlite:///{BASE_DIR / 'db.sqlite3'}\",\n    )\n}\n```\n\nExample:\n\n```dotenv\nDATABASE_URL=postgres://app:secret@localhost:5432/app\n```\n\n`env.db()` is an alias for `env.db_url()`. Use the same pattern for caches, email, search, and channels:\n\n```python\nCACHES = {\n    \"default\": env.cache(\"CACHE_URL\", default=\"locmemcache://\")\n}\n\nEMAIL_CONFIG = env.email_url(\n    \"EMAIL_URL\",\n    default=\"smtp://user:password@localhost:25\",\n)\nvars().update(EMAIL_CONFIG)\n\nSEARCH_CONFIG = env.search_url(\"SEARCH_URL\", default=\"simple://\")\nCHANNEL_LAYERS = {\n    \"default\": env.channels(\"CHANNELS_URL\", default=\"redis://127.0.0.1:6379/0\"),\n}\n```\n\nExample `.env` values:\n\n```dotenv\nCACHE_URL=rediscache://127.0.0.1:6379/1\nEMAIL_URL=smtp://user:password@smtp.example.com:587\nSEARCH_URL=elasticsearch://127.0.0.1:9200/index-name\nCHANNELS_URL=rediss://127.0.0.1:6379/0\n```\n\n`0.13.0` adds support for `valkey://` and `valkeys://` cache URLs, and `rediss://` for channels URL parsing.\n\n### Prefixes, Choices, And Defaults\n\n```python\nenv = environ.Env()\nenv.prefix = \"DJANGO_\"\nenv.warn_on_default = True\n\nDEBUG = env.bool(\"DEBUG\", default=False)  # reads DJANGO_DEBUG\nSECRET_KEY = env(\"SECRET_KEY\")            # reads DJANGO_SECRET_KEY\nENVIRONMENT = env.str(\n    \"ENVIRONMENT\",\n    default=\"development\",\n    choices=(\"development\", \"staging\", \"production\"),\n)\n```\n\nIn `0.13.0`, `Env.str(..., choices=...)` is available for basic string validation, and `warn_on_default` can emit `DefaultValueWarning` when missing variables fall back to explicit defaults.\n\n## Secrets And Deployment Config\n\n### `_FILE` Secrets With `FileAwareEnv`\n\n`FileAwareEnv` checks `VAR_FILE` before `VAR`, which is useful for Docker and orchestration systems that mount secrets as files.\n\n```python\nfrom pathlib import Path\nimport environ\n\nBASE_DIR = Path(__file__).resolve().parent.parent\n\nenv = environ.FileAwareEnv()\nenviron.Env.read_env(BASE_DIR / \".env\")\n\nSECRET_KEY = env(\"SECRET_KEY\")\nDATABASES = {\"default\": env.db(\"DATABASE_URL\")}\n```\n\nExample:\n\n```dotenv\nSECRET_KEY_FILE=/run/secrets/django_secret_key\nDATABASE_URL_FILE=/run/secrets/database_url\n```\n\n`_FILE` values take precedence. If the referenced file is missing, the read fails, so treat these paths as part of deployment configuration.\n\n### Read Specific Env Files Deliberately\n\n```python\nENV_PATH = env.str(\"ENV_PATH\", default=str(BASE_DIR / \".env\"))\nenviron.Env.read_env(ENV_PATH)\n```\n\nThe docs also show layering multiple files and controlling precedence with `overwrite=True`.\n\n```python\nenviron.Env.read_env(BASE_DIR / \".env\")\nenviron.Env.read_env(BASE_DIR / \".env.local\", overwrite=True)\n```\n\nUse this only when you want later files to override earlier values.\n\n## Common Pitfalls\n\n- `read_env()` will try to infer the project root if you omit the path, but the FAQ explicitly says that is not the recommended pattern. Pass an explicit path.\n- Real environment variables win over `.env` values unless you opt into `overwrite=True`.\n- Missing required variables fail during settings import. Define defaults where that is acceptable and let critical secrets fail fast.\n- `env.list()` is only a comma splitter. For nested or structured data, prefer `env.json()`, `env.dict()`, or a custom parser.\n- `env.db()`, `env.cache()`, `env.email_url()`, and `env.search_url()` all expect URL-shaped strings. Validate schemes and credentials early.\n- URL passwords with `#`, `@`, `/`, or other unsafe characters must be percent-encoded before they go into `DATABASE_URL` or similar settings.\n- `parse_comments=True` can silently truncate values containing `#`. Leave it off unless you really want inline comments.\n- Proxy interpolation is opt-in via `environ.Env(interpolate=True)`. If you need a literal leading `$`, enable `env.escape_proxy = True` and escape the value.\n- Multiline secrets require `env.str(..., multiline=True)`; do not pre-escape newlines if you want the original formatting preserved.\n\n## Version-Sensitive Notes For `0.13.0`\n\n- `0.13.0` is the current docs release and the current PyPI latest release, published on `2026-02-18`.\n- `0.13.0` adds `warn_on_default`, `Env.str(..., choices=...)`, Valkey cache URL schemes (`valkey://`, `valkeys://`), `rediss://` support in channels URL parsing, and extra django-prometheus DB aliases.\n- Smart-casting is still enabled by default in `0.13.0`, but the docs say the next major release will disable it by default. Write explicit casts now so future upgrades are boring.\n- Older examples that use `Env.unicode()` are outdated. The deprecations page says to use `Env.str()` instead.\n- The API reference and some PyPI project links still expose the legacy `readthedocs.org` hostname, but the canonical docs site is the `readthedocs.io` `latest` tree used below.\n\n## Official Sources\n\n- Docs root: https://django-environ.readthedocs.io/en/latest/\n- Installation: https://django-environ.readthedocs.io/en/latest/install.html\n- Quick start: https://django-environ.readthedocs.io/en/latest/quickstart.html\n- Tips: https://django-environ.readthedocs.io/en/latest/tips.html\n- Supported types: https://django-environ.readthedocs.io/en/latest/types.html\n- API reference: https://django-environ.readthedocs.io/en/latest/api.html\n- FAQ: https://django-environ.readthedocs.io/en/latest/faq.html\n- Deprecations: https://django-environ.readthedocs.io/en/latest/deprecations.html\n- Changelog: https://django-environ.readthedocs.io/en/latest/changelog.html\n- PyPI release page: https://pypi.org/project/django-environ/0.13.0/\n- Package registry page: https://pypi.org/project/django-environ/\n"
  },
  {
    "path": "content/django/docs/extensions/python/DOC.md",
    "content": "---\nname: extensions\ndescription: \"django-extensions package guide for Python projects using Django management commands, model mixins, and developer tooling\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-extensions,management-commands,shell,debugging,orm\"\n---\n\n# django-extensions Python Package Guide\n\n## Golden Rule\n\nUse `django-extensions` as Django project tooling, not as a standalone runtime API.\n\n- Install the package version that matches your Django support window.\n- Add `\"django_extensions\"` to `INSTALLED_APPS`.\n- Reach for its `manage.py` commands first: `shell_plus`, `runserver_plus`, `graph_models`, `runscript`, `show_urls`, and `show_permissions`.\n- Treat command-specific dependencies as optional add-ons, not as globally required.\n\nThis guide covers `django-extensions==4.1`.\n\n## What django-extensions Adds\n\n`django-extensions` is a grab bag of developer-facing Django helpers:\n\n- management commands for local debugging, schema inspection, data export, and repetitive project tasks\n- model and field mixins such as `TimeStampedModel` and `TitleSlugDescriptionModel`\n- class-based-view permission mixins\n- template debugging helpers and other project utilities\n\nFor most teams, the package is mainly about faster local development and maintenance workflows.\n\n## Version-Sensitive Notes\n\n- The package version covered here and the current latest PyPI release are both `4.1`.\n- The upstream docs URL you were given, `https://django-extensions.readthedocs.io/en/latest/`, is already rendering `4.2` docs. For `4.1`, prefer `https://django-extensions.readthedocs.io/en/stable/`.\n- The upstream README and PyPI metadata for the `4.1` line require `Django 4.2 or later`.\n- The `4.1` release added the `show_permissions` command, added per-app styling support for `graph_models`, and included a fix around `JSONField` and `bulk_update()`.\n- If you copy examples from `latest/`, verify they still exist in `stable/` before assuming they are valid for `4.1`.\n\n## Installation\n\n### pip\n\n```bash\npip install django-extensions==4.1\n```\n\n### uv\n\n```bash\nuv add django-extensions==4.1\n```\n\n### Poetry\n\n```bash\npoetry add django-extensions==4.1\n```\n\n### Base Requirements\n\nFor the `4.1` line:\n\n- Django: `4.2+`\n- Python/Django support policy: upstream says it follows Django-supported Python and Django versions\n\nCommon optional dependencies:\n\n- `werkzeug` for `runserver_plus`\n- `pyOpenSSL` if you want HTTPS cert generation with `runserver_plus --cert-file`\n- Graphviz plus either `pygraphviz` or `pydot` for rendered `graph_models` output\n- `ipython`, `bpython`, or `ptpython` for richer `shell_plus` sessions\n\n## Setup\n\nAdd the app to your Django settings:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"django_extensions\",\n]\n```\n\nThen confirm the extra commands are available:\n\n```bash\npython manage.py help\n```\n\nIf a command needs an optional dependency and it is missing, the command raises an error when you invoke it.\n\n## Core Usage\n\n### `shell_plus`\n\n`shell_plus` starts a Django-aware shell and auto-imports models. It is usually the fastest way to inspect data or prototype ORM queries.\n\n```bash\npython manage.py shell_plus\npython manage.py shell_plus --ipython\npython manage.py shell_plus --plain\npython manage.py shell_plus --print-sql\npython manage.py shell_plus --lab\n```\n\nUseful settings:\n\n```python\nSHELL_PLUS = \"ipython\"\nSHELL_PLUS_PRINT_SQL = True\nSHELL_PLUS_PRINT_SQL_TRUNCATE = 1000\nSHELL_PLUS_DONT_LOAD = [\"sites\", \"blog.pictures\"]\nSHELL_PLUS_MODEL_ALIASES = {\n    \"blog\": {\"Messages\": \"blog_messages\"},\n}\nSHELL_PLUS_IMPORTS = [\n    \"from myapp.services import build_report\",\n]\n```\n\nUse `SHELL_PLUS_DONT_LOAD`, aliases, or a collision resolver when models from different apps share names.\n\n### `runserver_plus`\n\n`runserver_plus` wraps Django's development server with the Werkzeug debugger.\n\n```bash\npip install werkzeug\npython manage.py runserver_plus\npython manage.py runserver_plus 0.0.0.0:8000\npython manage.py runserver_plus --cert-file /tmp/dev-cert.crt\n```\n\nUseful settings:\n\n```python\nRUNSERVER_PLUS_SERVER_ADDRESS_PORT = \"0.0.0.0:8000\"\nRUNSERVER_PLUS_PRINT_SQL = True\nRUNSERVER_PLUS_PRINT_SQL_TRUNCATE = 1000\nRUNSERVER_PLUS_EXTRA_FILES = []\nRUNSERVER_PLUS_TRUSTED_HOSTS = [\".localhost\", \"127.0.0.1\"]\n```\n\nImportant behavior:\n\n- this debugger can execute code inside traceback frames\n- Werkzeug 3.0.3+ restricts debugger hosts unless `RUNSERVER_PLUS_TRUSTED_HOSTS` allows them\n- this command is for local development only\n\n### `graph_models`\n\n`graph_models` is the quickest way to visualize model relationships or export a diagram during a refactor.\n\n```bash\npython manage.py graph_models -a > my_project.dot\npython manage.py graph_models -a -g -o my_project.png\npython manage.py graph_models users billing auth > domain.dot\npython manage.py graph_models -a --app-style path/to/style.json -o styled.png\n```\n\nBackends:\n\n```bash\npip install pygraphviz\n# or\npip install pyparsing pydot\n```\n\nUseful defaults:\n\n```python\nGRAPH_MODELS = {\n    \"all_applications\": True,\n    \"group_models\": True,\n    \"app_labels\": [\"users\", \"billing\", \"auth\"],\n}\n```\n\nIf image rendering fails, generate plain DOT output first. Most failures come from missing Graphviz system libraries rather than Django itself.\n\n### `runscript`\n\nUse `runscript` for small, repeatable Django-context automation jobs that are too specific for a management command.\n\nProject layout:\n\n```text\nscripts/\n  __init__.py\n  delete_stale_sessions.py\n```\n\nExample script:\n\n```python\nfrom django.utils import timezone\n\nfrom sessions.models import Session\n\ndef run(*args):\n    cutoff = timezone.now()\n    Session.objects.filter(expires_at__lt=cutoff).delete()\n```\n\nRun it with:\n\n```bash\npython manage.py runscript delete_stale_sessions\npython manage.py runscript delete_stale_sessions --script-args dry-run\n```\n\n`scripts/__init__.py` is required. Without it, Django will not discover the scripts package.\n\n### Jobs scheduling helpers\n\n`django-extensions` can scaffold and run jobs, but it does not schedule them by itself.\n\nCreate the job layout:\n\n```bash\npython manage.py create_jobs myapp\n```\n\nThat creates a `jobs/` package with directories such as `hourly/`, `daily/`, `weekly/`, `monthly/`, and `yearly/`.\n\nEach job lives in its own module and exposes a `Job` class derived from one of the base job classes.\n\nRun jobs:\n\n```bash\npython manage.py runjob myjob\npython manage.py runjobs hourly\npython manage.py runjobs daily\npython manage.py runjobs -l\n```\n\nTypical cron wiring:\n\n```cron\n@hourly /path/to/project/manage.py runjobs hourly\n@daily /path/to/project/manage.py runjobs daily\n```\n\n### Model and field extensions\n\nIf you want convenience base classes instead of more management commands, start with the model extensions.\n\nExample:\n\n```python\nfrom django.db import models\nfrom django_extensions.db.models import TimeStampedModel, TitleSlugDescriptionModel\n\nclass Article(TimeStampedModel, TitleSlugDescriptionModel):\n    body = models.TextField()\n```\n\nCommonly useful pieces:\n\n- `TimeStampedModel` for `created` and `modified`\n- `ActivatorModel` for active/inactive scheduling fields and helpers\n- `TitleDescriptionModel` and `TitleSlugDescriptionModel` for common content patterns\n\nFor new Django `4.2+` projects, prefer Django's built-in `models.JSONField` unless you are maintaining older code that already depends on the extension field.\n\n### `show_permissions`\n\n`show_permissions` is a good `4.1`-specific command to inspect generated model permissions.\n\n```bash\npython manage.py show_permissions\npython manage.py show_permissions blog\npython manage.py show_permissions blog.Post\npython manage.py show_permissions --all\npython manage.py show_permissions --app-label blog\n```\n\nUse it when debugging custom auth flows, role-based access, or unexpected permission rows after migrations.\n\n## Configuration And Auth\n\n- There is no external authentication or API client setup. Configuration is standard Django settings plus optional Python packages for specific commands.\n- Keep `django-extensions` in a development dependency group unless you intentionally use its commands in deployed admin or maintenance environments.\n- Command-specific settings only affect those commands. For example, `SHELL_PLUS_*` settings do not change normal app imports.\n- If you expose anything over the network for local debugging, treat `runserver_plus` as unsafe outside a trusted machine.\n\n## Common Pitfalls\n\n- Package name and Django app name differ: install `django-extensions`, configure `django_extensions`.\n- `latest/` docs are version-drifting. For `4.1`, prefer the `stable/` docs root and the `4.1` release page.\n- `runserver_plus` is not safe for production or shared environments.\n- `graph_models` often fails because Graphviz or the rendering backend is not installed correctly.\n- `runscript` and jobs discovery require real Python packages with `__init__.py` files.\n- Jobs do not run automatically. `create_jobs` only scaffolds files.\n- `shell_plus` can import colliding model names; set aliases or skip modules instead of relying on import order.\n- Some commands are destructive or invasive, such as `reset_db`. Do not use them casually on a non-local database.\n\n## Recommended Agent Workflow\n\n1. Confirm the project's Django version before pinning `django-extensions`.\n2. Install `django-extensions==4.1` and add `\"django_extensions\"` to `INSTALLED_APPS`.\n3. Use `shell_plus` for ORM exploration, `runserver_plus` for local traceback debugging, and `graph_models` for schema inspection.\n4. If a command errors immediately, check for optional dependencies before changing app code.\n5. If docs disagree, prefer the `4.1` PyPI/release metadata and `stable/` docs over `latest/`.\n\n## Official Sources\n\n- Stable docs root: https://django-extensions.readthedocs.io/en/stable/\n- Installation instructions: https://django-extensions.readthedocs.io/en/stable/installation_instructions.html\n- `shell_plus`: https://django-extensions.readthedocs.io/en/latest/shell_plus.html\n- `runserver_plus`: https://django-extensions.readthedocs.io/en/latest/runserver_plus.html\n- `graph_models`: https://django-extensions.readthedocs.io/en/latest/graph_models.html\n- `runscript`: https://django-extensions.readthedocs.io/en/latest/runscript.html\n- Jobs scheduling: https://django-extensions.readthedocs.io/en/latest/jobs_scheduling.html\n- Model extensions: https://django-extensions.readthedocs.io/en/stable/model_extensions.html\n- `show_permissions`: https://django-extensions.readthedocs.io/en/latest/show_permissions.html\n- PyPI release page: https://pypi.org/project/django-extensions/4.1/\n- Upstream repository: https://github.com/django-extensions/django-extensions\n- Upstream releases: https://github.com/django-extensions/django-extensions/releases/tag/4.1\n"
  },
  {
    "path": "content/django/docs/filter/python/DOC.md",
    "content": "---\nname: filter\ndescription: \"django-filter package guide for QuerySet filtering in Django and Django REST Framework\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.2\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"django-filter,django,drf,queryset,filters,forms,api\"\n---\n\n# django-filter Python Package Guide\n\n## What It Is\n\n`django-filter` adds declarative filtering for Django `QuerySet`s. The main abstraction is a `FilterSet`: define filter fields once, bind request query params to it, and read the filtered queryset from `.qs`.\n\nUse it for:\n\n- server-rendered Django list pages\n- reusable filtering logic outside view code\n- Django REST Framework list endpoints via `DjangoFilterBackend`\n\nPackage identity:\n\n- PyPI package: `django-filter`\n- Import namespace and app label: `django_filters`\n- Version covered: `25.2`\n- Release date: `2025-10-05`\n- Python requirement: `>=3.10`\n- `25.2` support floor: Django `5.2+`\n\n## Installation\n\nInstall the version your project is pinned to:\n\n```bash\npip install django-filter==25.2\n```\n\n```bash\nuv add django-filter==25.2\n```\n\n```bash\npoetry add django-filter==25.2\n```\n\n## Setup And Initialization\n\nAdd `django_filters` to `INSTALLED_APPS`:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django_filters\",\n]\n```\n\nWhen using Django REST Framework, enable the filter backend:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework\",\n    \"django_filters\",\n]\n\nREST_FRAMEWORK = {\n    \"DEFAULT_FILTER_BACKENDS\": [\n        \"django_filters.rest_framework.DjangoFilterBackend\",\n    ],\n}\n```\n\nCore workflow:\n\n1. Define a `FilterSet`.\n2. Bind it to `request.GET` plus a base queryset.\n3. Use `.qs` as the filtered queryset.\n\n## Core Usage\n\n### Define A `FilterSet`\n\n```python\nimport django_filters\n\nfrom .models import Product\n\nclass ProductFilter(django_filters.FilterSet):\n    min_price = django_filters.NumberFilter(field_name=\"price\", lookup_expr=\"gte\")\n    max_price = django_filters.NumberFilter(field_name=\"price\", lookup_expr=\"lte\")\n    released_after = django_filters.DateFilter(\n        field_name=\"release_date\",\n        lookup_expr=\"gte\",\n    )\n    uncategorized = django_filters.BooleanFilter(\n        field_name=\"category\",\n        lookup_expr=\"isnull\",\n    )\n\n    class Meta:\n        model = Product\n        fields = {\n            \"name\": [\"exact\", \"icontains\"],\n            \"category\": [\"exact\"],\n            \"in_stock\": [\"exact\"],\n        }\n```\n\n`Meta.fields` can be either:\n\n- a list of model field names for simple exact filters\n- a dict of model field names to allowed lookup expressions\n\n### Bind It In A Django View\n\n```python\nfrom django.shortcuts import render\n\nfrom .filters import ProductFilter\nfrom .models import Product\n\ndef product_list(request):\n    product_filter = ProductFilter(\n        request.GET,\n        queryset=Product.objects.all(),\n        request=request,\n    )\n    return render(\n        request,\n        \"products/list.html\",\n        {\n            \"filter\": product_filter,\n            \"object_list\": product_filter.qs,\n        },\n    )\n```\n\nUse `product_filter.form` to render the bound form in templates, and always query through `product_filter.qs`.\n\n### Use `FilterView` For Generic List Pages\n\n```python\nfrom django_filters.views import FilterView\n\nfrom .filters import ProductFilter\nfrom .models import Product\n\nclass ProductListView(FilterView):\n    model = Product\n    filterset_class = ProductFilter\n    template_name = \"products/list.html\"\n```\n\n### Integrate With Django REST Framework\n\nUse the DRF integration module, not the base package imports:\n\n```python\nfrom django_filters import rest_framework as filters\nfrom rest_framework import generics\n\nfrom .models import Product\nfrom .serializers import ProductSerializer\n\nclass ProductAPIFilter(filters.FilterSet):\n    min_price = filters.NumberFilter(field_name=\"price\", lookup_expr=\"gte\")\n    max_price = filters.NumberFilter(field_name=\"price\", lookup_expr=\"lte\")\n\n    class Meta:\n        model = Product\n        fields = [\"category\", \"in_stock\"]\n\nclass ProductListAPI(generics.ListAPIView):\n    queryset = Product.objects.all()\n    serializer_class = ProductSerializer\n    filter_backends = [filters.DjangoFilterBackend]\n    filterset_class = ProductAPIFilter\n```\n\nFor simple equality filters, `filterset_fields` is enough:\n\n```python\nfrom django_filters.rest_framework import DjangoFilterBackend\nfrom rest_framework import generics\n\nclass ProductListAPI(generics.ListAPIView):\n    queryset = Product.objects.all()\n    serializer_class = ProductSerializer\n    filter_backends = [DjangoFilterBackend]\n    filterset_fields = [\"category\", \"in_stock\"]\n```\n\nDRF-specific behavior to remember:\n\n- `BooleanFilter` uses an API-friendly `BooleanWidget` that accepts lowercase `true` and `false`\n- datetime model fields generate `IsoDateTimeFilter`\n- raised `django.core.exceptions.ValidationError` values are reraised as DRF validation errors\n\n## Configuration\n\n### FilterSet Options\n\nUse `Meta` for generation policy:\n\n- `model` and `fields` for autogenerated filters\n- `exclude` to block autogenerated filters for specific model fields\n- `form` to supply a custom base form class\n- `filter_overrides` to change default filter generation for field types\n- `unknown_field_behavior` to control what happens when unknown model fields are referenced\n\nExample:\n\n```python\nfrom django.db import models\nfrom django_filters import CharFilter, FilterSet, UnknownFieldBehavior\n\nclass ProductFilter(FilterSet):\n    class Meta:\n        model = Product\n        fields = [\"name\", \"release_date\"]\n        unknown_field_behavior = UnknownFieldBehavior.WARN\n        filter_overrides = {\n            models.CharField: {\n                \"filter_class\": CharFilter,\n                \"extra\": lambda field: {\"lookup_expr\": \"icontains\"},\n            },\n        }\n```\n\n### Package Settings\n\n`django-filter` settings are prefixed with `FILTERS_`. The most useful global settings are:\n\n- `FILTERS_DEFAULT_LOOKUP_EXPR` to change the implicit lookup from `exact`\n- `FILTERS_VERBOSE_LOOKUPS` to control human-readable lookup labels\n- `FILTERS_DISABLE_HELP_TEXT` to suppress generated help text such as `in` and `range` CSV hints\n- `FILTERS_EMPTY_CHOICE_LABEL`, `FILTERS_NULL_CHOICE_LABEL`, and `FILTERS_NULL_CHOICE_VALUE` for form choice behavior\n\nExample:\n\n```python\n# settings.py\nFILTERS_DEFAULT_LOOKUP_EXPR = \"exact\"\nFILTERS_VERBOSE_LOOKUPS = True\nFILTERS_DISABLE_HELP_TEXT = False\n```\n\n## Auth And Request Context\n\n`django-filter` does not manage authentication, sessions, or permissions. Those still belong to Django or DRF.\n\nWhat it does control is queryset narrowing for the current request. If a filter depends on the request object:\n\n- pass `request=request` when instantiating the filterset\n- handle `self.request is None`, because upstream documents that `request` is optional\n\nRequest-aware patterns supported by the docs include:\n\n- overriding `FilterSet.qs`\n- callable querysets for `ModelChoiceFilter` and `ModelMultipleChoiceFilter`\n- custom filter methods that inspect request data\n\n## Common Pitfalls\n\n### Package Name And Import Path Differ\n\nInstall `django-filter`, but import and configure `django_filters`.\n\n### Always Set `field_name` And `lookup_expr` Explicitly For Custom Filters\n\nThis looks right but is wrong:\n\n```python\nclass ProductFilter(django_filters.FilterSet):\n    price__gt = django_filters.NumberFilter()\n```\n\nThat resolves to `price__gt__exact`. Write it explicitly:\n\n```python\nclass ProductFilter(django_filters.FilterSet):\n    price__gt = django_filters.NumberFilter(\n        field_name=\"price\",\n        lookup_expr=\"gt\",\n    )\n```\n\n### Match The Filter Type To The Lookup\n\n`isnull` expects a boolean value even if the model field is an integer foreign key:\n\n```python\nclass ProductFilter(django_filters.FilterSet):\n    uncategorized = django_filters.BooleanFilter(\n        field_name=\"category\",\n        lookup_expr=\"isnull\",\n    )\n```\n\n### `Meta.fields` Dict Keys Must Be Model Field Names\n\nDeclarative aliases such as `min_price` belong on the class body, not inside the `Meta.fields` dict.\n\n### Empty Strings Are Skipped By Default\n\nAn empty query parameter is treated as \"no filter\". If you need to filter for `\"\"`, implement a custom method or a documented sentinel convention.\n\n### Do Not Mix `filterset_fields` And `filterset_class`\n\nFor DRF and generic views, use one or the other. Reach for `filterset_class` as soon as you need non-default lookups, labels, widgets, or request-aware filtering.\n\n### Always Read From `.qs`\n\nCurrent versions do not proxy the queryset API from the `FilterSet` itself. Use `.qs` explicitly instead of assuming the filterset behaves like a queryset.\n\n## Version-Sensitive Notes For 25.2\n\n- `25.2` adds testing for Django `6.0`.\n- `25.2` drops support for Django versions lower than `5.2`.\n- `25.2` drops support for Python `3.9`; the package metadata now requires Python `>=3.10`.\n- `25.1` removes the deprecated built-in schema-generation hooks for DRF views. If your project still relies on those methods, move schema generation to `drf-spectacular` or another current OpenAPI tool before upgrading.\n- The project uses CalVer-style package versions such as `25.2`, not SemVer.\n\n## Official Sources\n\n- Stable docs root: https://django-filter.readthedocs.io/en/stable/\n- Installation guide: https://django-filter.readthedocs.io/en/stable/guide/install.html\n- Usage guide: https://django-filter.readthedocs.io/en/stable/guide/usage.html\n- Tips guide: https://django-filter.readthedocs.io/en/stable/guide/tips.html\n- DRF integration guide: https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html\n- FilterSet reference: https://django-filter.readthedocs.io/en/stable/ref/filterset.html\n- Settings reference: https://django-filter.readthedocs.io/en/stable/ref/settings.html\n- Migration guide: https://django-filter.readthedocs.io/en/stable/guide/migration.html\n- PyPI package page: https://pypi.org/project/django-filter/25.2/\n- Changelog: https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst\n"
  },
  {
    "path": "content/django/docs/guardian/python/DOC.md",
    "content": "---\nname: guardian\ndescription: \"django-guardian object-level permissions for Django projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-guardian,permissions,auth,acl,object-permissions,admin\"\n---\n\n# django-guardian 3.3.0 Python Package Guide\n\n## Golden Rule\n\nUse `django-guardian` only as an extension to Django's normal auth system, not a replacement for it.\n\nKeep Django's default backend enabled and add Guardian's object-permission backend alongside it:\n\n```python\nAUTHENTICATION_BACKENDS = (\n    \"django.contrib.auth.backends.ModelBackend\",\n    \"guardian.backends.ObjectPermissionBackend\",\n)\n```\n\nIf you remove `ModelBackend`, normal Django auth and admin permission behavior will break.\n\n## Install\n\nPin the package when you need behavior that matches this entry exactly:\n\n```bash\npip install django-guardian==3.3.0\n```\n\nIf you use `uv`:\n\n```bash\nuv add django-guardian==3.3.0\n```\n\nUpstream install docs say Guardian requires Django `3.2+`. The docs landing page says the current docs support Python `3.9+` and Django `4.2+`, while current PyPI metadata for `3.3.0` says Python `>=3.10`. Treat Python/Django compatibility as version-sensitive and verify against your deployed stack before pinning.\n\n## Minimal Setup\n\nAdd Guardian to installed apps, keep the default backend, and run migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # Django apps\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    # Third-party apps\n    \"guardian\",\n]\n\nAUTHENTICATION_BACKENDS = (\n    \"django.contrib.auth.backends.ModelBackend\",\n    \"guardian.backends.ObjectPermissionBackend\",\n)\n```\n\n```bash\npython manage.py migrate\n```\n\nGuardian creates its object-permission tables and also creates a database-backed anonymous Guardian user unless you disable that behavior.\n\nIf your app does not use anonymous object permissions, disable them up front:\n\n```python\nANONYMOUS_USER_NAME = None\n```\n\nIf you do use anonymous object permissions but want a different username for the database row:\n\n```python\nANONYMOUS_USER_NAME = \"public\"\n```\n\n## Core Usage\n\nAssume a model like:\n\n```python\nfrom django.db import models\n\nclass Project(models.Model):\n    name = models.CharField(max_length=200)\n```\n\n### Assign a permission to a user\n\n```python\nfrom guardian.shortcuts import assign_perm\n\nproject = Project.objects.get(pk=1)\nassign_perm(\"projects.change_project\", request.user, project)\n```\n\nUsing only the codename is also valid when Guardian can infer the model:\n\n```python\nassign_perm(\"change_project\", request.user, project)\n```\n\n### Check a permission\n\n```python\nif request.user.has_perm(\"projects.change_project\", project):\n    ...\n```\n\nWithout the object argument, Django performs a global permission check instead:\n\n```python\nrequest.user.has_perm(\"projects.change_project\")\n```\n\n### Remove a permission\n\n```python\nfrom guardian.shortcuts import remove_perm\n\nremove_perm(\"projects.change_project\", request.user, project)\n```\n\n### Assign permissions to a group\n\n```python\nfrom django.contrib.auth.models import Group\nfrom guardian.shortcuts import assign_perm\n\neditors = Group.objects.get(name=\"editors\")\nassign_perm(\"projects.view_project\", editors, project)\n```\n\n### Query only objects a user can access\n\nUse `get_objects_for_user` instead of iterating a queryset and calling `has_perm()` repeatedly:\n\n```python\nfrom guardian.shortcuts import get_objects_for_user\n\nprojects = get_objects_for_user(\n    request.user,\n    \"projects.view_project\",\n    klass=Project,\n)\n```\n\nYou can also pass multiple permissions and control whether group-derived permissions are included.\n\n### Inspect effective permissions\n\n```python\nfrom guardian.shortcuts import get_perms\n\nperms = get_perms(request.user, project)\nif \"change_project\" in perms:\n    ...\n```\n\n## View and API Enforcement\n\nFor one-off checks, plain `has_perm(..., obj)` is usually the cleanest option.\n\nFor repeated checks in class-based views, use Guardian's mixin:\n\n```python\nfrom django.views.generic import DetailView\nfrom guardian.mixins import PermissionRequiredMixin\n\nclass ProjectDetailView(PermissionRequiredMixin, DetailView):\n    model = Project\n    permission_required = \"projects.view_project\"\n    raise_exception = True\n```\n\n`PermissionRequiredMixin` checks against `self.object` or `get_object()` when available. If `raise_exception = True`, it raises `PermissionDenied`; otherwise it follows its normal forbidden handling flow.\n\nGuardian also ships decorators such as `permission_required_or_403`, but upstream warns that decorator-based object lookup can add extra database queries if the view does similar lookups again.\n\n## Admin Integration\n\nIf object permissions should be manageable in Django admin, replace `ModelAdmin` with `GuardedModelAdmin`:\n\n```python\nfrom django.contrib import admin\nfrom guardian.admin import GuardedModelAdmin\n\nfrom .models import Project\n\n@admin.register(Project)\nclass ProjectAdmin(GuardedModelAdmin):\n    pass\n```\n\nThis adds Guardian's object-permission UI to the model's admin change page.\n\n## Performance and Scaling\n\nGuardian's default models use generic foreign keys. Upstream docs say that is flexible and usually good enough, but it can become a bottleneck on large datasets or hot permission paths.\n\n### Use cached permission checks in loops\n\nIf you need many checks for the same user across many objects, use `ObjectPermissionChecker` and prefetch:\n\n```python\nfrom guardian.core import ObjectPermissionChecker\n\nprojects = Project.objects.all()\nchecker = ObjectPermissionChecker(request.user)\nchecker.prefetch_perms(projects)\n\nfor project in projects:\n    if checker.has_perm(\"change_project\", project):\n        ...\n```\n\n### Consider direct foreign-key permission models for hot paths\n\nFor high-volume permission tables, Guardian supports direct FK models:\n\n```python\nfrom django.db import models\nfrom guardian.models import GroupObjectPermissionBase, UserObjectPermissionBase\n\nclass ProjectUserObjectPermission(UserObjectPermissionBase):\n    content_object = models.ForeignKey(Project, on_delete=models.CASCADE)\n\nclass ProjectGroupObjectPermission(GroupObjectPermissionBase):\n    content_object = models.ForeignKey(Project, on_delete=models.CASCADE)\n```\n\nThe field name must be exactly `content_object` or Guardian's direct-relation queries will not detect it correctly.\n\nIf you introduce these models into an existing project, plan the migration carefully. Upstream docs note that you can temporarily disable direct-model detection with `enabled = False` while creating tables and migrating data.\n\n## Custom User and Group Models\n\nGuardian depends on the user-to-group relationship shape that Django auth expects. If you use a custom user model and Guardian imports create problems in the same app's `models.py`, upstream recommends:\n\n```python\nGUARDIAN_MONKEY_PATCH_USER = False\n```\n\nand subclassing `guardian.mixins.GuardianUserMixin` in the custom user model.\n\nIf your custom user model cannot create Guardian's anonymous user with the default initializer, point `GUARDIAN_GET_INIT_ANONYMOUS_USER` at your own factory.\n\nFor custom group models, Guardian provides corresponding group mixins and a custom object-permission model path. Do not directly import Guardian's default group object-permission model in that setup; use the helper accessors from `guardian.utils`.\n\n## Common Pitfalls\n\n- Forgetting `\"guardian\"` in `INSTALLED_APPS` or forgetting `python manage.py migrate`.\n- Replacing Django's `ModelBackend` instead of adding Guardian alongside it.\n- Assigning object permissions and then checking them without passing the object to `has_perm()`.\n- Looping over objects with `has_perm()` instead of using `get_objects_for_user()` or `ObjectPermissionChecker.prefetch_perms()`.\n- Expecting Django's anonymous user object to be the same as Guardian's database-backed anonymous user.\n- Enabling direct-FK permission models but naming the relation field something other than `content_object`.\n- Introducing custom user/group permission models after project startup without planning migrations; upstream settings for custom permission models are meant to be set at the start of a project.\n\n## Version-Sensitive Notes\n\n- This entry targets `django-guardian==3.3.0`.\n- PyPI lists `3.3.0` as the current release, published on `2026-02-24`.\n- The docs URL points to `https://django-guardian.readthedocs.io/en/stable/`, which was appropriate on `2026-03-12` because it reflects the current release series. It is still a floating alias, so re-check it before assuming it still matches `3.3.0` later.\n- Upstream compatibility signals are not fully aligned across surfaces:\n  - docs home says Python `3.9+` and Django `4.2+`\n  - install page says Django `3.2+`\n  - PyPI metadata for `3.3.0` says Python `>=3.10` and classifiers include Django `3.2` through `5.2`\n- For pinned production work, trust the package metadata and your tested project matrix over older third-party examples.\n\n## Official Context\n\n- Documentation root: https://django-guardian.readthedocs.io/en/stable/\n- Installation: https://django-guardian.readthedocs.io/en/stable/installation/\n- Configuration: https://django-guardian.readthedocs.io/en/latest/configuration/\n- Permission checks: https://django-guardian.readthedocs.io/en/stable/userguide/checks/\n- Admin integration: https://django-guardian.readthedocs.io/en/stable/api/admin/\n- Custom user model: https://django-guardian.readthedocs.io/en/3.0.6/userguide/custom-user-model/\n- PyPI: https://pypi.org/project/django-guardian/\n- Repository: https://github.com/django-guardian/django-guardian\n"
  },
  {
    "path": "content/django/docs/haystack/python/DOC.md",
    "content": "---\nname: haystack\ndescription: \"Django Haystack search integration for indexing Django models and querying search backends from Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,haystack,search,indexing,elasticsearch,solr,whoosh\"\n---\n\n# Django Haystack Python Package Guide\n\n## Golden Rule\n\n`django-haystack` is Django search integration, not a search engine by itself. Choose a supported backend first, then configure Haystack to index your models and query that backend.\n\nFor the `3.3.0` package version covered here, prefer the versioned docs root `https://django-haystack.readthedocs.io/en/v3.3.0/`. As of March 12, 2026, some official pages under that root still render older `Haystack 2.5.0` branding in the page chrome, so treat the PyPI release `3.3.0` plus the versioned docs URL as the authoritative pairing.\n\n## Install\n\nInstall the exact version your project expects:\n\n```bash\npython -m pip install \"django-haystack==3.3.0\"\n```\n\nIf you are using the Elasticsearch integration published with the package extras:\n\n```bash\npython -m pip install \"django-haystack[elasticsearch]==3.3.0\"\n```\n\nHaystack does not provision or host a search service. You still need a backend such as Whoosh, Solr, or Elasticsearch installed and reachable according to the backend-specific setup docs.\n\n## Minimal Setup\n\n### 1. Add Haystack to `INSTALLED_APPS`\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"haystack\",\n]\n```\n\n### 2. Configure `HAYSTACK_CONNECTIONS`\n\nThis setting is required. A minimal local Whoosh example is the easiest way to get a project running:\n\n```python\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent\n\nHAYSTACK_CONNECTIONS = {\n    \"default\": {\n        \"ENGINE\": \"haystack.backends.whoosh_backend.WhooshEngine\",\n        \"PATH\": str(BASE_DIR / \"whoosh_index\"),\n    },\n}\n```\n\nFor Solr, Elasticsearch, or other supported backends, keep the same top-level structure and replace the backend engine plus connection-specific settings from the official backend installation guide.\n\n### 3. Create a `SearchIndex`\n\nHaystack auto-discovers `search_indexes.py` modules inside installed apps.\n\n```python\n# notes/search_indexes.py\nfrom haystack import indexes\n\nfrom .models import Note\n\nclass NoteIndex(indexes.SearchIndex, indexes.Indexable):\n    text = indexes.CharField(document=True, use_template=True)\n    title = indexes.CharField(model_attr=\"title\")\n    created_at = indexes.DateTimeField(model_attr=\"created_at\")\n\n    def get_model(self):\n        return Note\n\n    def index_queryset(self, using=None):\n        return self.get_model().objects.filter(is_public=True)\n```\n\nImportant details from the official API:\n\n- One field must have `document=True`; this is the primary searchable document field.\n- `use_template=True` tells Haystack to build that field from a template.\n- Per-field `prepare_<fieldname>()` methods are available when model attributes are not enough.\n\n### 4. Add the search template\n\nIf `text` uses `use_template=True`, create the expected template path:\n\n```text\ntemplates/search/indexes/notes/note_text.txt\n```\n\n```django\n{{ object.title }}\n{{ object.body }}\n```\n\nThe path segment after `indexes/` must match the Django app label and model name.\n\n### 5. Build the initial index\n\n```bash\npython manage.py rebuild_index --noinput\n```\n\nUseful related commands:\n\n```bash\npython manage.py update_index\npython manage.py clear_index --noinput\npython manage.py rebuild_index --noinput --remove\n```\n\n## Querying Search Results\n\nThe core query API is `SearchQuerySet`.\n\n```python\nfrom haystack.query import SearchQuerySet\n\nfrom .models import Note\n\ndef search_notes(query: str):\n    return (\n        SearchQuerySet()\n        .models(Note)\n        .auto_query(query)\n        .load_all()\n    )\n```\n\nWhy these methods matter:\n\n- `.models(Note)` keeps the query scoped to specific indexed models.\n- `.auto_query(query)` applies Haystack's user-query parsing rules instead of raw backend syntax.\n- `.load_all()` fetches the matching Django model instances to avoid repetitive per-result lookups when rendering.\n\n## Views And URL Integration\n\nHaystack ships reusable views, forms, and URL patterns. The quickest built-in route is:\n\n```python\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"search/\", include(\"haystack.urls\")),\n]\n```\n\nIf you need custom rendering or filtering logic, subclass the provided search views or call `SearchQuerySet` directly inside your own Django views.\n\n## Keeping The Index Fresh\n\nThe official docs describe two common strategies:\n\n- Batch indexing with management commands such as `update_index` from cron, Celery, or another scheduler\n- Near-real-time updates with a signal processor\n\nEnable real-time indexing only if your write path can afford the extra work:\n\n```python\nHAYSTACK_SIGNAL_PROCESSOR = \"haystack.signals.RealtimeSignalProcessor\"\n```\n\nBatch updates are simpler operationally and are usually safer for large imports or high-write workloads.\n\n## Configuration And Backend/Auth Notes\n\nHaystack's central configuration is the `HAYSTACK_CONNECTIONS` dictionary. Keep backend-specific connection details there.\n\nPractical guidance:\n\n- Haystack itself has no separate API key or login flow.\n- Authentication is whatever your search backend requires.\n- For local or containerized development, the backend is often reachable with no auth on a private network.\n- For managed or remote backends, keep credentials, hostnames, and TLS settings in environment-driven Django settings rather than hard-coding them.\n\nEnvironment-driven pattern:\n\n```python\nimport os\n\nHAYSTACK_CONNECTIONS = {\n    \"default\": {\n        \"ENGINE\": os.environ[\"HAYSTACK_ENGINE\"],\n        \"URL\": os.environ.get(\"HAYSTACK_URL\"),\n        \"PATH\": os.environ.get(\"HAYSTACK_PATH\"),\n        \"INDEX_NAME\": os.environ.get(\"HAYSTACK_INDEX_NAME\", \"haystack\"),\n    },\n}\n```\n\nUse only the keys your chosen backend supports. The backend installation guide is the source of truth for engine-specific options.\n\n## Common Pitfalls\n\n- Forgetting to add `\"haystack\"` to `INSTALLED_APPS`.\n- Creating `search_indexes.py` with the wrong filename or not implementing `get_model()`.\n- Omitting the `document=True` field from the index.\n- Using `use_template=True` but forgetting the `templates/search/indexes/<app>/<model>_text.txt` file.\n- Running `update_index` and expecting deleted rows to disappear automatically; use `--remove` or a rebuild strategy when needed.\n- Rendering lots of results without `.load_all()`, which can turn search result pages into N+1 database query problems.\n- Treating `django-haystack` compatibility claims from the repository `main` branch as if they were guaranteed for the `3.3.0` release.\n\n## Version-Sensitive Notes\n\n- PyPI still lists `3.3.0` as the current release as of March 12, 2026.\n- The official docs have a versioned `v3.3.0` root, but some pages still expose older `2.5.0` branding. This is presentation drift, not a reason to rewrite frontmatter away from `3.3.0`.\n- The `3.3.0` package metadata claims support for Python `3.8+` and Django `3.2`, `4.2`, and `5.0`. Do not assume Django 6 support from this package version unless you verify it separately.\n- When working from blog posts or issue threads, prefer the official `SearchIndex`, `SearchQuerySet`, settings, signal processor, and management-command docs before copying backend syntax or old class names.\n\n## Official Source URLs Used For This Doc\n\n- `https://django-haystack.readthedocs.io/en/v3.3.0/`\n- `https://django-haystack.readthedocs.io/en/v3.3.0/tutorial.html`\n- `https://django-haystack.readthedocs.io/en/v3.3.0/searchindex_api.html`\n- `https://django-haystack.readthedocs.io/en/latest/searchqueryset_api.html`\n- `https://django-haystack.readthedocs.io/en/latest/settings.html`\n- `https://django-haystack.readthedocs.io/en/latest/signal_processors.html`\n- `https://django-haystack.readthedocs.io/en/latest/views_and_forms.html`\n- `https://django-haystack.readthedocs.io/en/latest/management_commands.html`\n- `https://django-haystack.readthedocs.io/en/v3.3.0/installing_search_engines.html`\n- `https://pypi.org/project/django-haystack/`\n"
  },
  {
    "path": "content/django/docs/health-check/python/DOC.md",
    "content": "---\nname: health-check\ndescription: \"django-health-check for Django service probes, machine-readable health endpoints, and custom checks in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,health-check,monitoring,ops,readiness,liveness\"\n---\n\n# django-health-check for Django\n\n## What It Is\n\n`django-health-check` adds a health endpoint and a CLI check runner for Django apps. It is aimed at load balancers, uptime monitors, Prometheus scraping, Docker/Kubernetes probes, and custom service checks.\n\n- Package: `django-health-check`\n- Import root: `health_check`\n- Version covered: `4.1.2`\n- Python requirement: `>=3.10`\n- Current PyPI classifiers include Django `5.2` and `6.0`\n- Docs root: `https://codingjoe.dev/django-health-check/`\n- Registry: `https://pypi.org/project/django-health-check/`\n\nAs of March 12, 2026, the upstream GitHub releases page shows `4.1.2` as the latest release, published on March 4, 2026.\n\n## Install\n\nBase install:\n\n```bash\npython -m pip install \"django-health-check==4.1.2\"\n```\n\nCommon extras:\n\n```bash\npython -m pip install \"django-health-check[psutil,redis]==4.1.2\"\npython -m pip install \"django-health-check[celery,kafka,rabbitmq,rss]==4.1.2\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"django-health-check[psutil,redis]==4.1.2\"\n```\n\nPyPI currently lists these extras: `atlassian`, `celery`, `kafka`, `psutil`, `rabbitmq`, `redis`, `rss`.\n\n## Minimal Setup\n\nAdd the core app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"health_check\",\n]\n```\n\nWire an explicit endpoint with explicit checks:\n\n```python\n# urls.py\nfrom django.urls import path\nfrom health_check.views import HealthCheckView\nfrom redis.asyncio import Redis as RedisClient\n\nurlpatterns = [\n    path(\n        \"health/\",\n        HealthCheckView.as_view(\n            checks=[\n                \"health_check.Cache\",\n                \"health_check.Database\",\n                \"health_check.Mail\",\n                \"health_check.Storage\",\n                \"health_check.DNS\",\n                \"health_check.contrib.psutil.Disk\",\n                \"health_check.contrib.psutil.Memory\",\n                (\n                    \"health_check.contrib.redis.Redis\",\n                    {\n                        \"client_factory\": lambda: RedisClient.from_url(\n                            \"redis://localhost:6379\"\n                        )\n                    },\n                ),\n            ],\n        ),\n        name=\"health_check\",\n    ),\n]\n```\n\nNotes:\n\n- If you omit `checks=...`, the default is all built-in checks except third-party checks.\n- Third-party checks usually require both the extra dependency and an explicit entry in the `checks` list.\n- Use `client_factory` for Redis in `4.x`; the older `client=` argument is deprecated.\n\n## Response Formats And Status Codes\n\nThe `/health/` endpoint returns:\n\n- HTTP `200` when all checks pass\n- HTTP `500` when any check fails\n\nUseful formats:\n\n- Plain text: `Accept: text/plain` or `?format=text`\n- JSON: `Accept: application/json` or `?format=json`\n- OpenMetrics: `?format=openmetrics`\n- RSS/Atom: `?format=rss`, `?format=atom`, or RSS/Atom `Accept` headers\n\nExample:\n\n```bash\ncurl -H \"Accept: application/json\" http://localhost:8000/health/\ncurl http://localhost:8000/health/?format=openmetrics\n```\n\nImportant: RSS and Atom feeds always return HTTP `200`, even when checks fail. Use the normal endpoint, plain text, or JSON if you need failure to show up as a non-200 HTTP status.\n\n## Built-In Checks That Matter First\n\nThese are the main classes to reach for in `4.1.2`:\n\n- `health_check.Cache`: cache probe, supports `alias`, `key_prefix`, and `timeout`\n- `health_check.Database`: database probe, supports `alias`\n- `health_check.Storage`: storage probe, supports `alias`\n- `health_check.DNS`: DNS resolution probe\n- `health_check.Mail`: SMTP backend probe\n- `health_check.contrib.psutil.Disk`: supports `path` and `max_disk_usage_percent`\n- `health_check.contrib.psutil.Memory`: supports `min_gibibytes_available` and `max_memory_usage_percent`\n- `health_check.contrib.kafka.Kafka`: requires `bootstrap_servers`\n- `health_check.contrib.rabbitmq.RabbitMQ`: requires `amqp_url`\n- `health_check.contrib.redis.Redis`: prefer `client_factory`\n\nExample with tuned parameters:\n\n```python\nfrom django.urls import path\nfrom health_check.views import HealthCheckView\nfrom redis.asyncio import Redis as RedisClient\n\nurlpatterns = [\n    path(\n        \"health/\",\n        HealthCheckView.as_view(\n            checks=[\n                (\"health_check.Cache\", {\"alias\": \"default\", \"key_prefix\": \"probe\"}),\n                (\"health_check.Database\", {\"alias\": \"default\"}),\n                (\"health_check.Storage\", {\"alias\": \"default\"}),\n                (\n                    \"health_check.contrib.psutil.Disk\",\n                    {\"path\": \"/app\", \"max_disk_usage_percent\": 85.0},\n                ),\n                (\n                    \"health_check.contrib.psutil.Memory\",\n                    {\n                        \"min_gibibytes_available\": 0.5,\n                        \"max_memory_usage_percent\": 90.0,\n                    },\n                ),\n                (\n                    \"health_check.contrib.redis.Redis\",\n                    {\n                        \"client_factory\": lambda: RedisClient.from_url(\n                            \"redis://redis:6379/0\"\n                        )\n                    },\n                ),\n            ]\n        ),\n    ),\n]\n```\n\n## Container And Kubernetes Probes\n\nFor container liveness/readiness, upstream recommends a smaller probe endpoint that avoids external dependencies if those services already expose their own health checks.\n\n```python\n# urls.py\nfrom django.urls import path\nfrom health_check.views import HealthCheckView\n\nurlpatterns = [\n    path(\n        \"container/health/\",\n        HealthCheckView.as_view(\n            checks=[\n                \"health_check.contrib.psutil.Disk\",\n                \"health_check.contrib.psutil.Memory\",\n            ]\n        ),\n        name=\"health_check-container\",\n    ),\n]\n```\n\nRun it from the CLI:\n\n```bash\npython manage.py health_check health_check-container web:8000 --forwarded-host example.com\n```\n\nImportant:\n\n- The host used by the command must be allowed by `ALLOWED_HOSTS`.\n- The command defaults `X-Forwarded-Proto` to `https`; use `--forwarded-proto http` if SSL is not in play.\n- For Kubernetes `httpGet` probes, your app server must bind to `0.0.0.0`, not only `127.0.0.1`.\n\n## Custom Checks\n\nCustom checks subclass `health_check.base.HealthCheck` and implement `run`. The method may be sync or async.\n\n```python\nimport dataclasses\n\nfrom health_check.base import HealthCheck, ServiceUnavailable\n\n@dataclasses.dataclass\nclass ExternalAPIHealthCheck(HealthCheck):\n    api_base_url: str = dataclasses.field(repr=False)\n\n    async def run(self) -> None:\n        # Replace with your actual probe logic.\n        if not self.api_base_url.startswith(\"https://\"):\n            raise ServiceUnavailable(\"API base URL is invalid\")\n```\n\nGuidance:\n\n- Raise `ServiceWarning` for degraded-but-working states.\n- Raise `ServiceUnavailable` for hard failures.\n- Keep exception messages human-readable but non-sensitive.\n- Sensitive dataclass fields should use `repr=False`, because `__repr__` is used in reports.\n\n## Security And Deployment Notes\n\n- Do not expose a public unauthenticated health endpoint unless the returned information is safe to disclose.\n- If you need a shared-secret URL, upstream explicitly says not to reuse Django `SECRET_KEY`. Generate a separate token and put it in the path.\n- Prefer network restrictions, reverse-proxy controls, or a dedicated internal route for deeper health endpoints.\n- If the endpoint is used behind HTTPS or proxy-aware middleware, make sure forwarded-host and forwarded-proto behavior matches your Django deployment settings.\n\nExample tokenized route:\n\n```python\nfrom django.urls import path\nfrom health_check.views import HealthCheckView\n\nurlpatterns = [\n    path(\"health/your-generated-token/\", HealthCheckView.as_view()),\n]\n```\n\n## Version-Sensitive Notes For 4.x\n\nDo not copy pre-`4.x` setup guides directly.\n\nThe `4.x` migration changed the integration model:\n\n- Remove old `health_check.*` sub-apps from `INSTALLED_APPS`; keep only `health_check`\n- Remove old `HEALTH_CHECK_*` settings\n- Replace `include(\"health_check.urls\")` with `HealthCheckView.as_view(...)`\n- `DatabaseHealthCheck` is replaced by `Database`\n- old storage-specific health checks are replaced by `Storage`\n- `CeleryHealthCheck` is replaced by `Ping`\n- `MigrationsHealthCheck` was removed; use Django's built-in check framework instead\n\nIf you are upgrading from `3.21+`, the upstream migration guide is the reference to follow before rewriting settings or URLs.\n\n## Common Pitfalls\n\n- Forgetting to install the extra dependency for a third-party check such as `psutil`, `redis`, `kafka`, or `rabbitmq`\n- Registering a Redis check with `client=` instead of `client_factory`\n- Reusing the old `include(\"health_check.urls\")` pattern from blog posts or old repos\n- Using the health command against a host not present in `ALLOWED_HOSTS`\n- Making container probes depend on external services and then treating dependency outages as app liveness failures\n- Returning sensitive data in exception messages from custom checks\n\n## Official Sources\n\n- Docs: `https://codingjoe.dev/django-health-check/`\n- Install guide: `https://codingjoe.dev/django-health-check/install/`\n- Usage: `https://codingjoe.dev/django-health-check/usage/`\n- Checks reference: `https://codingjoe.dev/django-health-check/checks/`\n- Container guide: `https://codingjoe.dev/django-health-check/container/`\n- Migration guide: `https://codingjoe.dev/django-health-check/migrate-to-v4/`\n- PyPI: `https://pypi.org/project/django-health-check/`\n- Releases: `https://github.com/codingjoe/django-health-check/releases/tag/4.1.2`\n"
  },
  {
    "path": "content/django/docs/import-export/python/DOC.md",
    "content": "---\nname: import-export\ndescription: \"django-import-export package guide for Python and Django admin import/export workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-import-export,python,admin,import,export,tablib\"\n---\n\n# django-import-export Python Package Guide\n\n## Golden Rule\n\nUse `django-import-export` for Django model import/export through Django admin or explicit `ModelResource` classes, and use the versioned upstream docs for the package version in your environment.\n\n- Package: `django-import-export`\n- Import path: `import_export`\n- Version covered here: `4.4.0`\n- Versioned docs root: `https://django-import-export.readthedocs.io/en/4.4.0/`\n- PyPI package: `https://pypi.org/project/django-import-export/4.4.0/`\n\n## Install\n\nPin the package version you are targeting:\n\n```bash\npip install django-import-export==4.4.0\n```\n\nWith `uv`:\n\n```bash\nuv add django-import-export==4.4.0\n```\n\nWith Poetry:\n\n```bash\npoetry add django-import-export==4.4.0\n```\n\nVersion `4.4.0` requires Python `>=3.9`. PyPI classifiers for this release include Django `4.2`, `5.1`, and `5.2`.\n\nOptional format support is installed through extras. Common examples:\n\n```bash\npip install \"django-import-export[xlsx]==4.4.0\"\npip install \"django-import-export[pandas]==4.4.0\"\npip install \"django-import-export[all]==4.4.0\"\n```\n\nPyPI lists these extras for `4.4.0`: `all`, `cli`, `ods`, `pandas`, `xls`, `xlsx`, and `yaml`.\n\n## Django Setup\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"import_export\",\n]\n```\n\nThe package has no separate auth system. Access is controlled by Django admin auth, model permissions, and any storage backend credentials you configure for temporary import files.\n\nFor admin integration, define a resource and attach it to an admin class:\n\n```python\n# admin.py\nfrom django.contrib import admin\nfrom import_export import resources\nfrom import_export.admin import ImportExportModelAdmin\n\nfrom .models import Book\n\nclass BookResource(resources.ModelResource):\n    class Meta:\n        model = Book\n        import_id_fields = (\"id\",)\n        fields = (\"id\", \"name\", \"author\", \"price\")\n\n@admin.register(Book)\nclass BookAdmin(ImportExportModelAdmin):\n    resource_classes = [BookResource]\n```\n\nIf you only need one direction, upstream also documents `ImportMixin`, `ExportMixin`, and `ExportActionMixin`.\n\n## Core Usage\n\n### Define a Resource\n\n`ModelResource` is the core abstraction. Use it whenever import/export behavior matters; do not rely on autogenerated defaults once matching, validation, or relation mapping become important.\n\n```python\nfrom import_export import resources\n\nfrom .models import Book\n\nclass BookResource(resources.ModelResource):\n    class Meta:\n        model = Book\n        import_id_fields = (\"isbn\",)\n        fields = (\"isbn\", \"name\", \"published\", \"price\")\n        skip_unchanged = True\n        report_skipped = True\n```\n\n`import_id_fields` controls update matching. If you omit a stable business key, imports often create duplicates instead of updating rows.\n\n### Programmatic Export\n\n```python\nresource = BookResource()\ndataset = resource.export()\n\ncsv_text = dataset.csv\njson_text = dataset.json\n```\n\n### Programmatic Import\n\nAlways dry-run first:\n\n```python\nfrom tablib import Dataset\n\nresource = BookResource()\ndataset = Dataset().load(csv_text, format=\"csv\")\n\npreview = resource.import_data(\n    dataset,\n    dry_run=True,\n    raise_errors=True,\n)\n\nif not preview.has_errors():\n    resource.import_data(dataset, dry_run=False, raise_errors=True)\n```\n\nThe admin UI follows the same high-level pattern: upload, preview, confirm, then commit.\n\n### Fields and Relations\n\nUse explicit fields and widgets when column names do not match model fields or when you need relation lookups:\n\n```python\nfrom import_export import fields, resources\nfrom import_export.widgets import ForeignKeyWidget\n\nfrom .models import Author, Book\n\nclass BookResource(resources.ModelResource):\n    author = fields.Field(\n        column_name=\"author\",\n        attribute=\"author\",\n        widget=ForeignKeyWidget(Author, \"name\"),\n    )\n\n    class Meta:\n        model = Book\n        import_id_fields = (\"isbn\",)\n        fields = (\"isbn\", \"name\", \"author\", \"published\")\n```\n\nFor `4.4.0`, the changelog calls out a new `CachedForeignKeyWidget`. Prefer it when repeated foreign-key lookups dominate import time.\n\n## High-Value Resource Options\n\nThese `Meta` options matter most in production code:\n\n- `fields` and `exclude`: explicit control over the dataset schema.\n- `import_id_fields`: defines update matching.\n- `skip_unchanged` and `report_skipped`: useful for idempotent refresh imports.\n- `clean_model_instances = True`: runs model validation; otherwise model `full_clean()` is not part of the default import path.\n- `use_bulk = True`: faster inserts/updates, with behavior tradeoffs.\n- `batch_size` and `chunk_size`: tune large imports.\n- `force_init_instance = True`: only when every row is new and you want to skip instance lookups.\n- `use_natural_foreign_keys = True`: useful when serialized data relies on Django natural keys.\n\nWhen update matching is expensive, upstream also documents using `CachedInstanceLoader` or another `instance_loader_class`.\n\n## Admin Configuration and Permissions\n\nThe admin workflow depends on temporary storage between the upload step and the confirmation step. In production, especially with multiple workers or containers, configure shared temporary storage instead of relying on a local temp directory.\n\nSettings and hooks that matter most:\n\n- `IMPORT_EXPORT_TMP_STORAGE_CLASS`: choose filesystem, cache, or Django storage-backed temp storage.\n- `IMPORT_EXPORT_SKIP_ADMIN_CONFIRM`: disables the preview/confirm step.\n- `IMPORT_EXPORT_SKIP_ADMIN_EXPORT_UI`: skips the export form UI.\n- `IMPORT_EXPORT_IMPORT_PERMISSION_CODE` and `IMPORT_EXPORT_EXPORT_PERMISSION_CODE`: customize which permission codename gates admin import/export.\n- `IMPORT_EXPORT_ESCAPE_FORMULAE_ON_EXPORT`: escapes spreadsheet formulas for admin exports.\n\nIf you use `STORAGES` with Django 4.2+, point the import-export temp storage at a backend available to every app instance.\n\n## Bulk Import Caveats\n\nBulk mode is useful, but it changes behavior:\n\n- `save()` is not called per instance.\n- `pre_save` and `post_save` signals do not fire.\n- many-to-many relations are not supported in bulk mode.\n- debugging is harder because failures can happen per batch instead of per row.\n\nUse bulk mode only when those tradeoffs are acceptable.\n\n## Common Pitfalls\n\n### Using `latest` docs against a pinned dependency\n\nThe docs URL points at `/latest/`, but on March 12, 2026 that root showed `4.4.1.dev33`. For package version `4.4.0`, use `https://django-import-export.readthedocs.io/en/4.4.0/`.\n\n### Duplicate rows during import\n\nThis is usually an `import_id_fields` problem. Match on a stable unique field such as `isbn`, slug, or another business key instead of assuming database PKs are present in incoming files.\n\n### Validation is weaker than expected\n\nResource parsing and widget conversion can succeed even when model-level validation should fail. Turn on `clean_model_instances = True` if you need model validation during import.\n\n### Temporary uploads disappear between requests\n\nThis is common in multi-instance deployments when upload and confirm land on different workers. Fix it with shared cache or shared storage for temp files.\n\n### Export sanitization assumptions are wrong\n\nAdmin exports can escape spreadsheet formulas with `IMPORT_EXPORT_ESCAPE_FORMULAE_ON_EXPORT`, but the admin docs explicitly say programmatic exports are not sanitized for malicious content. Sanitize untrusted values yourself before handing files to spreadsheet users.\n\n## Version-Sensitive Notes\n\n- This entry is for package version `4.4.0`.\n- PyPI lists `4.4.0` as released on January 10, 2026.\n- The `4.4.0` changelog entry adds `CachedForeignKeyWidget`, which matters for FK-heavy imports.\n- The broader `v4` release line made optional dependencies explicit. If a format handler is missing, install the matching extra instead of assuming it is bundled.\n- If you are upgrading from older projects, re-check any custom import/export permissions, temp-storage configuration, and bulk-import assumptions against the `4.4.0` docs.\n\n## Official Sources\n\n- Docs root: https://django-import-export.readthedocs.io/en/4.4.0/\n- Admin integration: https://django-import-export.readthedocs.io/en/4.4.0/admin_integration.html\n- Resources API: https://django-import-export.readthedocs.io/en/4.4.0/api_resources.html\n- Admin API: https://django-import-export.readthedocs.io/en/4.4.0/api_admin.html\n- Changelog: https://django-import-export.readthedocs.io/en/4.4.0/changelog.html\n- PyPI project page: https://pypi.org/project/django-import-export/4.4.0/\n"
  },
  {
    "path": "content/django/docs/model-utils/python/DOC.md",
    "content": "---\nname: model-utils\ndescription: \"django-model-utils package guide for Django projects using abstract models, custom fields, managers, and tracking utilities\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,python,models,orm,managers,tracking\"\n---\n\n# django-model-utils Python Package Guide\n\n## Golden Rule\n\nUse `django-model-utils` as a thin utility layer on top of standard Django models and managers. It is not a standalone Django app, so you usually import the helpers directly and then run normal Django migrations.\n\nAs of March 12, 2026, PyPI still lists `5.0.0` as the current release. The official docs under `latest/` are not version-stable, so use the version-pinned `5.0.0` docs for behavior and API details.\n\n## Install\n\nPin the package to the version your project expects:\n\n```bash\npython -m pip install \"django-model-utils==5.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"django-model-utils==5.0.0\"\npoetry add \"django-model-utils==5.0.0\"\n```\n\nThis package does not need to be added to `INSTALLED_APPS`.\n\n## Setup Pattern\n\nThere is no separate initialization step. Add the fields, mixins, or managers you need to your models, then create and apply migrations:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\n```\n\nTypical imports:\n\n```python\nfrom django.db import models\nfrom model_utils import Choices, FieldTracker\nfrom model_utils.fields import MonitorField, SplitField, StatusField\nfrom model_utils.managers import InheritanceManager, QueryManager\nfrom model_utils.models import SoftDeletableModel, StatusModel, TimeStampedModel\n```\n\n## Core Usage\n\n### Common model pattern\n\nThis package is most useful when you combine a few small pieces instead of adopting everything:\n\n```python\nfrom django.db import models\nfrom model_utils import Choices, FieldTracker\nfrom model_utils.fields import MonitorField, SplitField\nfrom model_utils.models import SoftDeletableModel, StatusModel, TimeStampedModel\n\nclass Article(TimeStampedModel, StatusModel, SoftDeletableModel):\n    STATUS = Choices(\"draft\", \"published\", \"archived\")\n\n    title = models.CharField(max_length=200)\n    body = SplitField()\n    tracker = FieldTracker(fields=[\"status\", \"title\"])\n    published_at = MonitorField(\n        monitor=\"status\",\n        when=[\"published\"],\n        null=True,\n        default=None,\n    )\n\n    class Meta:\n        ordering = [\"-modified\"]\n```\n\nWhat this gives you:\n\n- `TimeStampedModel`: `created` and `modified` fields that update automatically\n- `StatusModel`: a `status` field plus status-specific managers such as `Article.published`\n- `SoftDeletableModel`: soft delete support with explicit managers for active vs deleted rows\n- `SplitField`: a content field plus generated excerpt support\n- `FieldTracker`: in-memory change tracking between loads and saves\n- `MonitorField`: timestamp updates when another field changes to selected values\n\n### `Choices`\n\n`Choices` builds readable constants and choice tuples from a single declaration:\n\n```python\nfrom model_utils import Choices\n\nSTATUS = Choices(\n    (\"draft\", \"Draft\"),\n    (\"published\", \"Published\"),\n    (\"archived\", \"Archived\"),\n)\n\nSTATUS.published\nSTATUS.draft\nSTATUS\n```\n\nUse `subset()` when a field or form should only expose part of a larger choice set:\n\n```python\nVISIBLE_STATUS = STATUS.subset(\"draft\", \"published\")\n```\n\nIf your codebase already standardizes on Django `TextChoices` or `IntegerChoices`, keep that standard. `django-model-utils` does not require `Choices` everywhere.\n\n### `StatusModel` and `StatusField`\n\n`StatusModel` expects a `STATUS` iterable on the model class and adds:\n\n- a `status` field via `StatusField`\n- a `status_changed` timestamp field\n- per-status managers, for example `Article.published.all()`\n\nExample:\n\n```python\nclass Article(StatusModel):\n    STATUS = Choices(\"draft\", \"published\")\n    title = models.CharField(max_length=200)\n```\n\nPractical notes:\n\n- `StatusField` defaults to the first choice if you do not set `default=...`\n- the automatic managers are convenient, but they are ordinary Django managers and still respect queryset chaining rules\n- add your own database indexes if you filter heavily on `status`; `StatusField` is not a magic performance layer\n\n### `TimeStampedModel`\n\nUse `TimeStampedModel` when you want `created` and `modified` fields without re-implementing save hooks:\n\n```python\nclass Note(TimeStampedModel):\n    title = models.CharField(max_length=100)\n```\n\n`modified` updates on every save. That is useful for audit-style timestamps but not a replacement for domain-specific workflow fields.\n\n### `SoftDeletableModel`\n\nUse `SoftDeletableModel` when rows should stay in the database but disappear from active queries:\n\n```python\nclass Customer(SoftDeletableModel):\n    email = models.EmailField(unique=True)\n```\n\nUse the explicit managers:\n\n- `Customer.available_objects`: rows that are not soft-deleted\n- `Customer.all_objects`: all rows, including deleted ones\n\nAvoid building new code against `Customer.objects` for soft-delete filtering. The manager behavior on `objects` is in a deprecation path and future releases are expected to stop filtering deleted rows there.\n\nTo hard-delete, pass the keyword argument explicitly:\n\n```python\ncustomer.delete(soft=False)\n```\n\n### `FieldTracker`\n\n`FieldTracker` helps when code needs to know whether a field changed since the instance was loaded:\n\n```python\nclass Order(models.Model):\n    status = models.CharField(max_length=20)\n    total = models.DecimalField(max_digits=10, decimal_places=2)\n    tracker = FieldTracker(fields=[\"status\", \"total\"])\n\norder = Order.objects.get(pk=1)\norder.status = \"paid\"\n\norder.tracker.has_changed(\"status\")\norder.tracker.previous(\"status\")\norder.tracker.changed()\n```\n\nUse this for conditional side effects, audit logging, and transition checks. It does not replace database constraints or transaction boundaries.\n\nFor foreign keys, tracker values are based on the raw `field_id` value rather than automatically loading the related object.\n\n### `InheritanceManager`\n\nUse `InheritanceManager` for model inheritance trees when you need subclass instances back from the base queryset:\n\n```python\nfrom model_utils.managers import InheritanceManager\n\nclass Place(models.Model):\n    objects = InheritanceManager()\n    name = models.CharField(max_length=100)\n\nclass Restaurant(Place):\n    serves_pizza = models.BooleanField(default=False)\n\nplaces = Place.objects.select_subclasses()\n```\n\nWithout `select_subclasses()`, you get base-model instances. With it, rows are cast back to their concrete subclasses.\n\n### `QueryManager`\n\nUse `QueryManager` for simple filtered managers when a full custom manager class would be overkill:\n\n```python\nclass Post(models.Model):\n    published = models.BooleanField(default=False)\n\n    public = QueryManager(published=True)\n```\n\nThis is a convenience wrapper around a fixed queryset filter. Do not stretch it into complex business logic.\n\n## Fields And Utilities\n\n### `MonitorField`\n\n`MonitorField` updates a timestamp when another field changes:\n\n```python\nclass Invoice(models.Model):\n    status = models.CharField(max_length=20)\n    paid_at = MonitorField(\n        monitor=\"status\",\n        when=[\"paid\"],\n        null=True,\n        default=None,\n    )\n```\n\nSet an explicit `default` when the field is nullable. Do not rely on historical implicit default behavior across older examples.\n\n### `SplitField`\n\n`SplitField` stores a content body and an excerpt companion field:\n\n```python\nclass BlogPost(models.Model):\n    body = SplitField()\n```\n\nUseful behaviors:\n\n- access the rendered excerpt via `instance.body.excerpt`\n- insert a split marker in the content to control where the excerpt ends\n- otherwise the excerpt is generated from the opening paragraphs\n\nThe package documents these Django settings for excerpt behavior:\n\n- `SPLIT_MARKER`\n- `SPLIT_DEFAULT_PARAGRAPHS`\n\n### Other useful model helpers\n\nThe package also includes abstract models such as:\n\n- `TimeFramedModel` for start/end publication windows\n- `UUIDModel` for UUID primary-style identifiers\n\nUse them only when they match your domain model cleanly. They are conveniences, not required architecture.\n\n## Configuration\n\nThis package has no authentication layer and almost no global configuration.\n\nConfiguration that matters in practice:\n\n- you do not add the package to `INSTALLED_APPS`\n- excerpt behavior for `SplitField` can be adjusted with `SPLIT_MARKER` and `SPLIT_DEFAULT_PARAGRAPHS`\n- model behavior still depends on normal Django settings such as database engine, timezone handling, and installed middleware\n\nExample Django settings for `SplitField`:\n\n```python\nSPLIT_MARKER = \"<!-- more -->\"\nSPLIT_DEFAULT_PARAGRAPHS = 3\n```\n\n## Common Pitfalls\n\n- Do not point agents at `https://django-model-utils.readthedocs.io/en/latest/` and assume it matches `5.0.0`. Use the version-pinned docs for this package version.\n- Do not add `django-model-utils` to `INSTALLED_APPS`. It provides model helpers, not a Django app with migrations or app config you must register.\n- Always run `makemigrations` and `migrate` after adding package fields or abstract-model inheritance to a model.\n- `SoftDeletableModel.objects` is not the safe long-term manager for active rows. Use `available_objects` or `all_objects` explicitly.\n- Hard delete requires `delete(soft=False)`. Passing a positional argument is no longer the intended pattern.\n- `FieldTracker` tracks local instance state, not concurrent updates from other transactions.\n- `InheritanceManager` only returns subclass instances when you call `select_subclasses()`.\n- `SplitField` excerpt output updates when the model is saved. If you inspect excerpt behavior before saving, you can misread the result.\n\n## Version-Sensitive Notes For 5.0.0\n\n- `django-model-utils 5.0.0` dropped the deprecated `JoinManager` and `JoinQueryset`. If older code imports them, rewrite that code instead of pinning to ancient examples.\n- `SaveSignalHandlingModel` was removed before `5.0.0`; do not use blog posts that still recommend it.\n- `SplitField` no longer accepts the old `no_excerpt_field` argument.\n- The `SoftDeletableModel` API now documents the `soft` keyword argument on `delete()`.\n- The upstream changelog documents a transition in `MonitorField` nullable default behavior across recent releases. For stable behavior, set `default` explicitly when using `null=True`.\n- The setup page for `5.0.0` still says Python `3.7+`, but the PyPI metadata for the same release requires Python `>=3.8`. Treat the PyPI requirement as authoritative for packaging and environment resolution.\n- The published `5.0.0` package metadata does not claim Django 6 support. Validate compatibility before using it in Django 6 projects.\n\n## Official Sources\n\n- Docs landing page: https://django-model-utils.readthedocs.io/en/latest/\n- Version-pinned docs: https://django-model-utils.readthedocs.io/en/5.0.0/\n- Setup: https://django-model-utils.readthedocs.io/en/5.0.0/setup.html\n- Fields: https://django-model-utils.readthedocs.io/en/5.0.0/fields.html\n- Models: https://django-model-utils.readthedocs.io/en/5.0.0/models.html\n- Managers: https://django-model-utils.readthedocs.io/en/5.0.0/managers.html\n- Utilities: https://django-model-utils.readthedocs.io/en/5.0.0/utilities.html\n- Changelog: https://django-model-utils.readthedocs.io/en/5.0.0/changelog.html\n- PyPI: https://pypi.org/project/django-model-utils/\n"
  },
  {
    "path": "content/django/docs/mptt/python/DOC.md",
    "content": "---\nname: mptt\ndescription: \"django-mptt package guide for Python tree models, admin, forms, and template usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.18.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-mptt,mptt,trees,hierarchy,orm\"\n---\n\n# django-mptt Python Package Guide\n\n## What It Is\n\n`django-mptt` adds tree support to Django models using Modified Preorder Tree Traversal. Install it as `django-mptt`, but import from `mptt`.\n\nUse it when a model needs parent/child hierarchy and you need efficient ancestor, descendant, sibling, and tree-order queries.\n\nCurrent package facts for this entry:\n\n- PyPI version covered: `0.18.0`\n- Python requirement: `>=3.9`\n- Current supported Django line from PyPI classifiers: `4.2`, `5.0`, `5.1`, `5.2`\n- Upstream maintenance state: PyPI marks the project as currently unmaintained\n\n## Install\n\n```bash\npip install django-mptt==0.18.0\n```\n\nAdd `mptt` to `INSTALLED_APPS`:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"mptt\",\n]\n```\n\nThen create and apply migrations:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\n```\n\n## Basic Model Setup\n\nSubclass `MPTTModel` and use `TreeForeignKey` for the parent link:\n\n```python\nfrom django.db import models\nfrom mptt.models import MPTTModel, TreeForeignKey\n\nclass Category(MPTTModel):\n    name = models.CharField(max_length=100, unique=True)\n    parent = TreeForeignKey(\n        \"self\",\n        on_delete=models.CASCADE,\n        null=True,\n        blank=True,\n        related_name=\"children\",\n    )\n\n    class MPTTMeta:\n        order_insertion_by = [\"name\"]\n\n    class Meta:\n        verbose_name_plural = \"categories\"\n\n    def __str__(self) -> str:\n        return self.name\n```\n\nImportant setup rules:\n\n- In multiple inheritance, keep `MPTTModel` first to avoid Django model validation errors.\n- `TreeForeignKey` is recommended for the parent field because forms and admin render tree-aware choices.\n- `MPTTModel` manages `level`, `lft`, `rght`, and `tree_id` automatically. Do not use those fields as business identifiers.\n\n## Core Usage\n\nCreate nodes with normal ORM calls:\n\n```python\nroot = Category.objects.create(name=\"Books\")\nfiction = Category.objects.create(name=\"Fiction\", parent=root)\nhistory = Category.objects.create(name=\"History\", parent=root)\n```\n\nCommon tree operations:\n\n```python\nroot.get_children()\nfiction.get_ancestors(include_self=True)\nroot.get_descendants()\nroot.get_descendant_count()\nfiction.get_siblings(include_self=True)\nfiction.get_root()\nfiction.is_leaf_node()\nfiction.is_root_node()\n```\n\n`TreeManager` returns querysets in tree order by default, so `Category.objects.all()` is usually suitable for navigation trees and nested rendering.\n\n`get_children()` is preferable to the reverse relation when you want immediate children because it can avoid a query for leaf nodes. `get_descendant_count()` uses tree fields and does not need a database query.\n\n## Rendering Trees In Templates\n\nLoad `mptt_tags` and render with `recursetree`:\n\n```django\n{% load mptt_tags %}\n\n<ul class=\"root\">\n  {% recursetree nodes %}\n    <li>\n      {{ node.name }}\n      {% if not node.is_leaf_node %}\n        <ul class=\"children\">\n          {{ children }}\n        </ul>\n      {% endif %}\n    </li>\n  {% endrecursetree %}\n</ul>\n```\n\nFor preloaded querysets, use `get_cached_trees()` or its template alias `cache_tree_children` to cache parent/child links on nodes and avoid follow-up queries during traversal.\n\n## Admin Integration\n\nFor a simple tree-aware changelist:\n\n```python\nfrom django.contrib import admin\nfrom mptt.admin import MPTTModelAdmin\n\nfrom .models import Category\n\n@admin.register(Category)\nclass CategoryAdmin(MPTTModelAdmin):\n    pass\n```\n\nFor drag and drop:\n\n```python\nfrom django.contrib import admin\nfrom mptt.admin import DraggableMPTTAdmin\n\nfrom .models import Category\n\n@admin.register(Category)\nclass CategoryAdmin(DraggableMPTTAdmin):\n    list_display = (\"tree_actions\", \"indented_title\")\n    list_display_links = (\"indented_title\",)\n```\n\nPractical admin notes:\n\n- `DraggableMPTTAdmin` does not work well on big trees; upstream warns about trees with more than a few hundred nodes or deeper than 10 levels.\n- `tree_actions` should be first in `list_display` for draggable admin.\n- Global indentation can be set with `MPTT_ADMIN_LEVEL_INDENT`; per-admin indentation uses `mptt_level_indent`.\n\n## Forms And Controlled Moves\n\n`TreeForeignKey` already uses a tree-aware form field. Use `TreeNodeChoiceField` directly when building custom forms:\n\n```python\nfrom django import forms\nfrom mptt.forms import TreeNodeChoiceField\n\nfrom .models import Category\n\nclass CategoryForm(forms.Form):\n    parent = TreeNodeChoiceField(\n        queryset=Category.objects.all(),\n        required=False,\n        level_indicator=\"--\",\n    )\n```\n\nFor manual repositioning flows, `MoveNodeForm` validates target and position choices:\n\n```python\nfrom mptt.forms import MoveNodeForm\n\nform = MoveNodeForm(category, request.POST or None)\nif form.is_valid():\n    category = form.save()\n```\n\n## Bulk Updates And Imports\n\nFor localized bulk changes inside one tree or a small part of the forest, use `delay_mptt_updates()` inside a transaction:\n\n```python\nfrom django.db import transaction\n\nwith transaction.atomic():\n    with Category.objects.delay_mptt_updates():\n        # bulk inserts or reparents within a small number of trees\n        ...\n```\n\nFor changes across much of the table, use `disable_mptt_updates()` and rebuild afterward:\n\n```python\nfrom django.db import transaction\n\nwith transaction.atomic():\n    with Category.objects.disable_mptt_updates():\n        # large bulk changes\n        ...\n    Category.objects.rebuild()\n```\n\nUse `disable_mptt_updates()` carefully: upstream documents that it leaves the tree inconsistent until `rebuild()` runs. `delay_mptt_updates()` is safer for localized work because it performs partial rebuilds of modified trees.\n\nIf you have nested input data, the manager also exposes bulk-tree helpers such as `build_tree_nodes()` for efficient imports before `bulk_create()`.\n\n## Configuration Notes\n\nThere is no auth or credential setup. Configuration is model and admin driven.\n\nUseful `MPTTMeta` options:\n\n- `order_insertion_by` for sibling ordering\n- `parent_attr` if your parent field is not named `parent`\n- `left_attr`, `right_attr`, `tree_id_attr`, `level_attr` if you need alternate structural field names\n\nUseful admin settings:\n\n- `MPTT_ADMIN_LEVEL_INDENT` for global admin indentation\n- `mptt_level_indent` for per-admin indentation\n- `expand_tree_by_default = True` on `DraggableMPTTAdmin` if you want the tree expanded on first load\n\nTesting setting:\n\n- `MPTT_ALLOW_TESTING_GENERATORS = True` only when you intentionally use generators such as `model_bakery` in tests and you know how to set tree fields safely\n\n## Common Pitfalls\n\n- Install name and import name differ: `pip install django-mptt`, then `import mptt`.\n- If you use `order_insertion_by`, saved instances can become stale after inserts or reparents. Call `refresh_from_db()` before relying on tree fields from older in-memory objects.\n- `move_to()` assumes both the current node and target node reflect current database state. Stale tree fields can corrupt the move.\n- `move_to()` is explicit positioning logic. If you want automatic sibling ordering from `order_insertion_by`, create or reparent normally and let MPTT place the node.\n- `disable_mptt_updates()` and `delay_mptt_updates()` both create temporary inconsistencies during the block. Wrap them in `transaction.atomic()`.\n- `DraggableMPTTAdmin` is not a good default for very large or very deep trees.\n- `MPTTModel` manages structural fields itself. Manual edits to `lft`, `rght`, `tree_id`, or `level` are a corruption risk.\n\n## Version-Sensitive Notes For 0.18.0\n\nThis entry tracks the version used here `0.18.0`, which is also the current PyPI release as of March 12, 2026.\n\nRelevant upstream changes around this release:\n\n- `0.18` fixed how indexes are defined for Django 5 and newer.\n- `0.17` added support for Python `3.13` and Django `5.1` and `5.2`.\n- `0.17` dropped Django versions earlier than `4.2`.\n- `0.16` fixed `get_cached_trees()` for multi-tree querysets and fixed `rebuild()` for custom managers not named `objects`.\n\nIf you are upgrading from `0.16.x` or older, recheck your Django support floor and any custom index expectations on Django 5+ projects.\n\n## Official Sources\n\n- Docs root: https://django-mptt.readthedocs.io/en/latest/\n- Installation: https://django-mptt.readthedocs.io/en/latest/install.html\n- Tutorial: https://django-mptt.readthedocs.io/en/latest/tutorial.html\n- Models and managers: https://django-mptt.readthedocs.io/en/latest/models.html\n- Forms: https://django-mptt.readthedocs.io/en/latest/forms.html\n- Admin: https://django-mptt.readthedocs.io/en/latest/admin.html\n- Templates: https://django-mptt.readthedocs.io/en/latest/templates.html\n- Utilities: https://django-mptt.readthedocs.io/en/latest/utilities.html\n- Testing: https://django-mptt.readthedocs.io/en/latest/testing.html\n- Changelog: https://django-mptt.readthedocs.io/en/latest/changelog.html\n- PyPI: https://pypi.org/project/django-mptt/\n- Repository: https://github.com/django-mptt/django-mptt\n"
  },
  {
    "path": "content/django/docs/ninja/python/DOC.md",
    "content": "---\nname: ninja\ndescription: \"django-ninja package guide for Python - typed Django APIs with validation, auth, and OpenAPI docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.3\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-ninja,django,python,api,openapi,pydantic\"\n---\n\n# django-ninja Python Package Guide\n\n## When To Use It\n\nUse `django-ninja` when a project already uses Django and you need:\n\n- typed request parsing from path, query, headers, forms, files, or JSON bodies\n- response serialization and output filtering\n- generated OpenAPI schema plus interactive docs\n- a smaller, type-hint-first API layer than Django REST Framework\n\nThe PyPI package is `django-ninja`, but imports come from `ninja`.\n\n## Version Scope\n\n- This doc targets `django-ninja==1.5.3`.\n- The official docs root and current PyPI page both reflect `1.5.3`.\n- PyPI metadata for `1.5.3` requires Python `>=3.9`.\n\n## Install\n\n```bash\npip install \"django-ninja==1.5.3\"\n```\n\nCommon variants:\n\n```bash\npoetry add django-ninja==1.5.3\nuv add django-ninja==1.5.3\n```\n\nYou do not need to add `\"ninja\"` to `INSTALLED_APPS` for normal API usage. Add it only if you want the docs UI assets served by Django `staticfiles` instead of the default CDN-hosted assets.\n\n## Minimal Setup\n\nCreate `api.py` next to your Django `urls.py`:\n\n```python\nfrom ninja import NinjaAPI, Schema\n\napi = NinjaAPI(title=\"Example API\", version=\"1.0.0\")\n\nclass AddIn(Schema):\n    a: int\n    b: int\n\nclass AddOut(Schema):\n    result: int\n\n@api.post(\"/add\", response=AddOut)\ndef add(request, payload: AddIn):\n    return {\"result\": payload.a + payload.b}\n```\n\nWire it into Django URLs:\n\n```python\nfrom django.contrib import admin\nfrom django.urls import path\n\nfrom .api import api\n\nurlpatterns = [\n    path(\"admin/\", admin.site.urls),\n    path(\"api/\", api.urls),\n]\n```\n\nBy default:\n\n- interactive docs are served at `/api/docs`\n- the OpenAPI schema is served at `/api/openapi.json`\n\n## Request Parsing And Response Schemas\n\nDjango Ninja infers input locations from the function signature:\n\n- path params: declared in the route path\n- query params: simple typed function arguments\n- JSON body: `Schema` arguments\n- forms/files: `Form(...)` and `File(...)`\n\n```python\nfrom typing import Optional\n\nfrom ninja import File, Form, NinjaAPI, Schema\nfrom ninja.files import UploadedFile\n\napi = NinjaAPI()\n\nclass UserOut(Schema):\n    id: int\n    username: str\n    email: str\n\n@api.post(\"/users\", response=UserOut)\ndef create_user(\n    request,\n    username: str = Form(...),\n    email: str = Form(...),\n    avatar: Optional[UploadedFile] = File(None),\n):\n    user = User.objects.create(username=username, email=email)\n    if avatar is not None:\n        user.avatar.save(avatar.name, avatar)\n    return user\n```\n\nPractical rules:\n\n- Always declare `response=...` for non-trivial endpoints so output is filtered and validated.\n- Use `list[SchemaType]` or `{status_code: SchemaType}` for list and multi-status responses.\n- Return Django models only when the response schema is explicit.\n- Prefer `payload.model_dump()` over hand-parsing `request.body`.\n\n## Model-Backed Schemas\n\n`ModelSchema` is the shortest path when your API shape mostly mirrors a Django model:\n\n```python\nfrom ninja import ModelSchema\n\nclass UserSchema(ModelSchema):\n    class Meta:\n        model = User\n        fields = [\"id\", \"username\", \"email\"]\n```\n\nPrefer explicit field lists. Avoid `fields = \"__all__\"` unless you fully control the model and are sure no sensitive fields can leak.\n\nFor nested relations, use `select_related()` or `prefetch_related()` before returning querysets so serialization does not trigger avoidable database work.\n\n## Pagination\n\nUse built-in pagination for list endpoints instead of returning unbounded querysets:\n\n```python\nfrom ninja.pagination import PageNumberPagination, paginate\n\n@api.get(\"/users\", response=list[UserSchema])\n@paginate(PageNumberPagination, page_size=50)\ndef list_users(request):\n    return User.objects.order_by(\"id\")\n```\n\nNotes:\n\n- `@paginate` works well with Django querysets and standard iterables.\n- `PageNumberPagination` can expose a `page_size` query parameter in current v1 releases when you enable it in the paginator config.\n- Set a global pagination class in Django settings if most endpoints should behave the same way.\n\n## Authentication And Docs Configuration\n\n```python\nfrom ninja.security import django_auth\n\n@api.get(\"/me\", auth=django_auth)\ndef me(request):\n    return {\"username\": request.auth.username}\n```\n\nBearer token auth:\n\n```python\nfrom ninja.security import HttpBearer\n\nclass AuthBearer(HttpBearer):\n    def authenticate(self, request, token):\n        if token == \"supersecret\":\n            return token\n        return None\n\napi = NinjaAPI(auth=AuthBearer())\n\n@api.get(\"/protected\")\ndef protected(request):\n    return {\"token\": request.auth}\n```\n\nDocs and schema controls:\n\n```python\nfrom django.contrib.admin.views.decorators import staff_member_required\nfrom ninja import NinjaAPI, Redoc, Swagger\n\napi = NinjaAPI(\n    title=\"Example API\",\n    docs=Swagger(settings={\"persistAuthorization\": True}),\n    docs_decorator=staff_member_required,\n)\n\npublic_readonly_api = NinjaAPI(docs=Redoc(), openapi_url=\"/openapi.json\")\nprivate_api = NinjaAPI(docs_url=None, openapi_url=None)\n```\n\nImportant behavior:\n\n- Cookie-based auth enables CSRF protection automatically in v1.\n- `docs_url=None` hides the interactive docs page.\n- `openapi_url=None` disables the schema endpoint and therefore the docs UI as well.\n- Protect docs with `docs_decorator` if the schema should not be public.\n\n## Django Settings That Matter In Production\n\nThese settings are easy to miss and affect behavior directly:\n\n```python\nNINJA_FIX_REQUEST_FILES_METHODS = [\"PUT\", \"PATCH\", \"DELETE\"]\nNINJA_NUM_PROXIES = 1\n```\n\nUse them when:\n\n- you need `request.FILES` to work on non-`POST` methods such as `PUT` or `PATCH`\n- the app runs behind one or more trusted reverse proxies and client IP handling must use forwarded headers correctly\n\n## Async Usage\n\nAsync views are useful for network-bound work, but Django Ninja does not make synchronous ORM calls magically safe inside `async def` views.\n\n```python\nfrom asgiref.sync import sync_to_async\n\n@api.get(\"/tasks/{task_id}\")\nasync def get_task(request, task_id: int):\n    task = await sync_to_async(Task.objects.get)(id=task_id)\n    return {\"id\": task.id, \"title\": task.title}\n```\n\nPractical rules:\n\n- Use Django's async ORM methods where available.\n- Wrap synchronous ORM or other blocking work with `sync_to_async(...)`.\n- Materialize lazy querysets before returning from async endpoints if evaluation could cross sync/async boundaries unexpectedly.\n\n## Testing\n\nFor endpoint-level tests without full Django URL resolution, use `ninja.testing.TestClient`:\n\n```python\nfrom django.test import TestCase\nfrom ninja.testing import TestClient\n\nclass APITest(TestCase):\n    def test_add(self):\n        client = TestClient(api)\n        response = client.post(\"/add\", json={\"a\": 2, \"b\": 3})\n\n        assert response.status_code == 200\n        assert response.json() == {\"result\": 5}\n        assert response.data == {\"result\": 5}\n```\n\n`response.data` is convenient when you want parsed payloads directly in assertions.\n\n## Common Pitfalls\n\n- The install name is `django-ninja`, but imports come from `ninja`.\n- Returning a raw model or queryset without `response=...` is a common way to leak fields accidentally.\n- Old `0.x` snippets often use patterns that are wrong for current v1 releases, especially around Pydantic config, CSRF, and docs settings.\n- Hiding `/docs` is not enough if `/openapi.json` still exposes the full schema.\n- File uploads on `PUT`, `PATCH`, or `DELETE` need `NINJA_FIX_REQUEST_FILES_METHODS` if you rely on `request.FILES`.\n- An `async def` view still needs async-safe database and I/O access patterns.\n\n## Version-Sensitive Notes\n\nCurrent `1.5.3` guidance assumes Django Ninja v1 behavior:\n\n- Pydantic 2 is the baseline.\n- `Schema` and `ModelSchema` customization uses `class Meta` instead of the older inner `Config` pattern.\n- Serializer and validator examples should use Pydantic 2 decorators such as `@field_serializer` and `@field_validator`.\n- Cookie auth auto-enables CSRF protection; do not copy old `csrf=True` guidance from pre-v1 examples.\n\nIf a project is pinned older than `1.5.x`, re-check pagination configuration, non-`POST` file upload handling, and any docs UI examples against that installed version before copying code directly.\n\n## Official Sources\n\n- Docs root: https://django-ninja.dev/\n- Tutorial and installation: https://django-ninja.dev/tutorial/\n- What is new in v1: https://django-ninja.dev/whatsnew_v1/\n- Authentication guide: https://django-ninja.dev/guides/authentication/\n- CSRF guide: https://django-ninja.dev/guides/csrf/\n- API docs guide: https://django-ninja.dev/guides/api-docs/\n- Settings reference: https://django-ninja.dev/reference/settings/\n- Django model schemas: https://django-ninja.dev/guides/response/django-pydantic/\n- Pagination guide: https://django-ninja.dev/guides/response/pagination/\n- Async support: https://django-ninja.dev/guides/async-support/\n- Testing guide: https://django-ninja.dev/guides/testing/\n- PyPI package page: https://pypi.org/project/django-ninja/\n- GitHub releases: https://github.com/vitalik/django-ninja/releases\n"
  },
  {
    "path": "content/django/docs/oauth-toolkit/python/DOC.md",
    "content": "---\nname: oauth-toolkit\ndescription: \"django-oauth-toolkit package guide for building OAuth2 and OpenID Connect providers in Django\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,oauth2,openid-connect,drf,authentication,authorization\"\n---\n\n# django-oauth-toolkit Python Package Guide\n\n## What It Does\n\n`django-oauth-toolkit` (DOT) turns a Django project into an OAuth 2.0 authorization server. It provides authorization, token, revocation, introspection, application management, Django REST framework integration, and optional OpenID Connect support.\n\nUse it when your Django app must issue and validate OAuth tokens for first-party or third-party clients. Do not use it as a social-login client library.\n\n## Version Context\n\n- Ecosystem: `pypi`\n- Package: `django-oauth-toolkit`\n- Version covered: `3.2.0`\n- Docs root: `https://django-oauth-toolkit.readthedocs.io/en/latest/`\n- PyPI URL: `https://pypi.org/project/django-oauth-toolkit/`\n\nThe official docs currently publish a `3.2.0` snapshot, so the package version and docs version are aligned for this entry.\n\n## Install\n\n```bash\npip install django-oauth-toolkit==3.2.0\n```\n\nIf you are protecting Django REST framework APIs, install DRF too:\n\n```bash\npip install django-oauth-toolkit==3.2.0 djangorestframework\n```\n\nOfficial compatibility signals are slightly inconsistent across upstream surfaces:\n\n- Read the Docs `3.2.0` docs say DOT supports Python `3.10` through `3.14`, Django `4.2` through `6.0`, and `oauthlib>=3.2.2`.\n- The PyPI project page still shows older requirement text and classifiers in some sections.\n\nFor upgrade decisions, prefer the docs root plus changelog over stale PyPI prose.\n\n## Minimal Provider Setup\n\nAdd the app, define scopes, and keep PKCE on.\n\n```python\n# settings.py\n\nINSTALLED_APPS = [\n    # Django apps...\n    \"oauth2_provider\",\n]\n\nOAUTH2_PROVIDER = {\n    \"SCOPES\": {\n        \"read\": \"Read access\",\n        \"write\": \"Write access\",\n    },\n    \"PKCE_REQUIRED\": True,\n}\n```\n\nExpose the OAuth endpoints:\n\n```python\n# urls.py\nfrom django.urls import include, path\nfrom oauth2_provider import urls as oauth2_urls\n\nurlpatterns = [\n    path(\"o/\", include(oauth2_urls)),\n]\n```\n\nRun migrations:\n\n```bash\npython manage.py migrate\npython manage.py createsuperuser\n```\n\nAfter that, create applications in Django admin under `Applications`.\n\n## Register a Client Application\n\nFor most browser, SPA, and mobile clients:\n\n- Grant type: `Authorization code`\n- Client type: `Public` for SPA/native clients, `Confidential` for server-side clients\n- Redirect URIs: exact callback URIs\n- Allowed origins: needed for browser-based clients calling the token endpoint from another origin\n- PKCE: expected by default\n\nFor confidential clients, copy the generated client secret before saving if you need it outside the server. DOT hashes client secrets on save in modern releases, so you cannot recover the plain secret later from Django admin.\n\nIf you want to create applications programmatically, DOT ships a `createapplication` management command:\n\n```bash\npython manage.py createapplication \\\n  \"web-app\" \\\n  admin \\\n  authorization-code \\\n  confidential \\\n  \"https://app.example.com/callback\"\n```\n\n## Authorization Code Flow\n\nThe common flow is:\n\n1. Redirect the user to `/o/authorize/`.\n2. Receive an authorization code on your redirect URI.\n3. Exchange the code at `/o/token/`.\n4. Send the bearer token to protected APIs.\n\nExample authorization URL:\n\n```python\nfrom urllib.parse import urlencode\n\nparams = urlencode(\n    {\n        \"client_id\": \"YOUR_CLIENT_ID\",\n        \"response_type\": \"code\",\n        \"redirect_uri\": \"https://app.example.com/callback\",\n        \"scope\": \"read write\",\n        \"code_challenge\": \"BASE64URL_SHA256_CODE_VERIFIER\",\n        \"code_challenge_method\": \"S256\",\n    }\n)\n\nauthorize_url = f\"https://auth.example.com/o/authorize/?{params}\"\n```\n\nExample code exchange for a public PKCE client:\n\n```python\nimport requests\n\nresponse = requests.post(\n    \"https://auth.example.com/o/token/\",\n    data={\n        \"grant_type\": \"authorization_code\",\n        \"client_id\": \"YOUR_CLIENT_ID\",\n        \"code\": \"CODE_FROM_CALLBACK\",\n        \"redirect_uri\": \"https://app.example.com/callback\",\n        \"code_verifier\": \"ORIGINAL_CODE_VERIFIER\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ntoken = response.json()\n```\n\nFor confidential clients, authenticate the token request with the client secret instead of treating the app like a public PKCE-only client.\n\n## Protect Django REST Framework APIs\n\nDOT integrates directly with DRF through `OAuth2Authentication` and scope-aware permission classes.\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"oauth2_provider.contrib.rest_framework.OAuth2Authentication\",\n    ),\n}\n```\n\n```python\n# views.py\nfrom oauth2_provider.contrib.rest_framework import (\n    OAuth2Authentication,\n    TokenHasReadWriteScope,\n)\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass DocumentView(APIView):\n    authentication_classes = [OAuth2Authentication]\n    permission_classes = [TokenHasReadWriteScope]\n    required_scopes = [\"documents\"]\n\n    def get(self, request):\n        return Response({\"ok\": True})\n```\n\n`TokenHasReadWriteScope` requires the configured read or write scope depending on the HTTP method, plus any `required_scopes` you declare on the view. Use `TokenHasScope` when you want exact scope checks without read/write semantics.\n\n## Settings That Usually Matter\n\nStart with these:\n\n- `SCOPES`: define every scope your tokens may request.\n- `DEFAULT_SCOPES`: narrow the defaults if you do not want `__all__`.\n- `PKCE_REQUIRED`: defaults to `True`; keep it that way unless you have a controlled legacy client that cannot support PKCE.\n- `ALLOWED_REDIRECT_URI_SCHEMES`: set to `[\"https\"]` in production. Loopback `http` redirects are acceptable for native apps.\n- `REFRESH_TOKEN_REUSE_PROTECTION`: use this with rotated refresh tokens to detect reuse and revoke the related session.\n- `REFRESH_TOKEN_EXPIRE_SECONDS`: controls cleanup eligibility, not actual refresh-token validation by itself.\n- `CLEAR_EXPIRED_TOKENS_BATCH_SIZE` and `CLEAR_EXPIRED_TOKENS_BATCH_INTERVAL`: tune large cleanup jobs.\n- `ALLOW_URI_WILDCARDS`: added in `3.1.0`; avoid enabling it in production unless you fully understand the redirect-origin risk.\n\nDOT also ships `cleartokens`, which you should schedule if you issue refresh tokens:\n\n```bash\npython manage.py cleartokens\n```\n\nWithout regular cleanup, expired refresh tokens can accumulate in the database. The docs are explicit that `REFRESH_TOKEN_EXPIRE_SECONDS` alone does not make refresh-token validation expire on its own.\n\n## OpenID Connect Setup\n\nOIDC is optional and disabled by default. Prefer `RS256` for signing ID tokens.\n\n```bash\nopenssl genrsa -out oidc.key 4096\n```\n\n```python\n# settings.py\nimport os\n\nOAUTH2_PROVIDER = {\n    \"OIDC_ENABLED\": True,\n    \"OIDC_RSA_PRIVATE_KEY\": os.environ[\"OIDC_RSA_PRIVATE_KEY\"],\n    \"SCOPES\": {\n        \"openid\": \"OpenID Connect scope\",\n        \"profile\": \"Profile access\",\n        \"email\": \"Email access\",\n    },\n}\n```\n\nImportant OIDC constraints:\n\n- Keep the RSA private key out of source control.\n- If you already customized `OAUTH2_SERVER_CLASS`, OIDC requires a class derived from `oauthlib.openid.Server`.\n- `HS256` uses the application client secret for signing. That is simpler, but it is less flexible and does not work for public clients or implicit/hybrid flows. Prefer `RS256`.\n- Use `OIDC_RSA_PRIVATE_KEYS_INACTIVE` for key rotation instead of replacing keys abruptly.\n\n## Separate Resource Server Pattern\n\nIf your API and authorization server are separate services, DOT supports token introspection.\n\nOn the authorization server:\n\n- include the introspection endpoint under `/o/introspect/`\n- add an `introspection` scope\n- issue a token the resource server can use\n\nOn the resource server:\n\n- set `RESOURCE_SERVER_INTROSPECTION_URL`\n- set either `RESOURCE_SERVER_AUTH_TOKEN` or `RESOURCE_SERVER_INTROSPECTION_CREDENTIALS`\n\nUse this only when you actually split the auth server and resource server. For a single Django app, standard local token validation is simpler.\n\n## Common Pitfalls\n\n- DOT is an authorization server toolkit, not a third-party OAuth client or social-login package.\n- Older blog posts often show outdated setup details. Follow the current `3.2.0` docs for URL wiring and settings names.\n- Public clients will fail authorization-code token exchange if you omit `code_challenge` and `code_verifier`, because `PKCE_REQUIRED` is on by default.\n- The plain client secret is not recoverable after save when hashing is enabled. Copy it at creation time if a confidential client needs it.\n- `REFRESH_TOKEN_EXPIRE_SECONDS` does not automatically invalidate refresh tokens during validation. It mainly drives `cleartokens` cleanup unless you customize validation.\n- `ALLOW_URI_WILDCARDS` is a security-sensitive escape hatch. Treat it as a last resort for controlled preview environments.\n- Upgrading from pre-`3.0.0` requires extra care if you use swappable DOT models or code that assumed token model primary keys were named `id`.\n\n## Version-Sensitive Notes\n\n- `3.2.0` adds device authorization grant support and adds support for Django `5.2` and Python `3.14`.\n- `3.1.0` adds wildcard redirect/origin support through `ALLOW_URI_WILDCARDS` and fixes several migration and introspection issues.\n- `3.0.1` fixes a migration error when pre-existing access tokens are already in the database.\n- `3.0.0` is the important breaking line:\n  - run `python manage.py migrate` after upgrading\n  - update custom swappable models and generate migrations if needed\n  - Django versions below `4.2` are no longer supported\n  - access-token storage changed to use `TextField` plus `token_checksum`\n  - `REFRESH_TOKEN_REUSE_PROTECTION` was introduced as a security control\n  - minimum `oauthlib` is `3.2.2+`\n\n## Official Sources Used\n\n- Docs root: https://django-oauth-toolkit.readthedocs.io/en/latest/\n- Installation: https://django-oauth-toolkit.readthedocs.io/en/latest/install.html\n- Tutorial part 1: https://django-oauth-toolkit.readthedocs.io/en/latest/tutorial/tutorial_01.html\n- Django REST framework integration: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html\n- DRF permissions: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/permissions.html\n- Settings: https://django-oauth-toolkit.readthedocs.io/en/latest/settings.html\n- OpenID Connect: https://django-oauth-toolkit.readthedocs.io/en/latest/oidc.html\n- Separate resource server: https://django-oauth-toolkit.readthedocs.io/en/latest/resource_server.html\n- Management commands: https://django-oauth-toolkit.readthedocs.io/en/latest/management_commands.html\n- Changelog: https://django-oauth-toolkit.readthedocs.io/en/latest/changelog.html\n- PyPI package page: https://pypi.org/project/django-oauth-toolkit/\n"
  },
  {
    "path": "content/django/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Django package guide for Python projects using the official Django 6.0 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"django,python,web,framework,orm,templates,admin\"\n---\n\n# Django Python Package Guide\n\n## Golden Rule\n\nUse the Django 6.0 docs for setup and behavior, and stay on the latest 6.0.x patch if your project is pinned to the 6.0 series. As of March 11, 2026, PyPI lists `Django 6.0.3`, while the docs URL pointed to the older Django 5.1 reference.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Django==6.0.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Django==6.0.3\"\npoetry add \"Django==6.0.3\"\n```\n\nOptional password hasher extras published on PyPI:\n\n```bash\npython -m pip install \"Django[argon2]==6.0.3\"\npython -m pip install \"Django[bcrypt]==6.0.3\"\n```\n\n## Initialize A Project\n\nCreate a project, apply built-in migrations, and run the dev server:\n\n```bash\ndjango-admin startproject mysite\ncd mysite\npython manage.py migrate\npython manage.py runserver\n```\n\nThe generated project includes these important files:\n\n- `manage.py`: command entry point for migrations, dev server, shell, and admin tasks\n- `mysite/settings.py`: installed apps, database config, middleware, templates, static config\n- `mysite/urls.py`: root URL router\n- `mysite/asgi.py`: ASGI application entry point\n- `mysite/wsgi.py`: WSGI application entry point\n\n## Core Workflow\n\n### Create an app\n\n```bash\npython manage.py startapp polls\n```\n\nAdd the app to `INSTALLED_APPS` in `settings.py` before expecting models, templates, or admin registration to work.\n\n### Define a model and create migrations\n\n```python\n# polls/models.py\nfrom django.db import models\n\nclass Question(models.Model):\n    question_text = models.CharField(max_length=200)\n    pub_date = models.DateTimeField(\"date published\")\n\n    def __str__(self) -> str:\n        return self.question_text\n```\n\n```bash\npython manage.py makemigrations polls\npython manage.py migrate\n```\n\nUseful inspection commands:\n\n```bash\npython manage.py sqlmigrate polls 0001\npython manage.py shell\n```\n\n### Add views and routes\n\n```python\n# polls/views.py\nfrom django.http import HttpResponse\n\ndef index(request):\n    return HttpResponse(\"Hello from polls\")\n```\n\n```python\n# polls/urls.py\nfrom django.urls import path\n\nfrom . import views\n\nurlpatterns = [\n    path(\"\", views.index, name=\"index\"),\n]\n```\n\n```python\n# mysite/urls.py\nfrom django.contrib import admin\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"polls/\", include(\"polls.urls\")),\n    path(\"admin/\", admin.site.urls),\n]\n```\n\n### Render templates instead of hard-coded responses\n\nKeep app templates namespaced under the app name to avoid collisions:\n\n```text\npolls/\n  templates/\n    polls/\n      index.html\n```\n\n```python\n# polls/views.py\nfrom django.shortcuts import render\n\ndef index(request):\n    context = {\"latest_question_list\": []}\n    return render(request, \"polls/index.html\", context)\n```\n\n### Register models in the admin\n\n```python\n# polls/admin.py\nfrom django.contrib import admin\n\nfrom .models import Question\n\nadmin.site.register(Question)\n```\n\nCreate an admin user:\n\n```bash\npython manage.py createsuperuser\n```\n\n## Settings And Environment\n\nDjango loads settings from the module pointed to by `DJANGO_SETTINGS_MODULE`. The default `manage.py`, `asgi.py`, and `wsgi.py` created by `startproject` set this for you.\n\nFor production, keep secrets and environment-specific values outside source control. A common pattern is to split settings into `base.py`, `dev.py`, and `prod.py`, then select the active module with `DJANGO_SETTINGS_MODULE`.\n\nMinimum production settings to review explicitly:\n\n- `DEBUG = False`\n- `ALLOWED_HOSTS = [\"your-domain.example\"]`\n- `CSRF_TRUSTED_ORIGINS = [\"https://your-domain.example\"]` when needed behind HTTPS proxies or cross-origin admin flows\n- `SECRET_KEY` from an environment variable\n- `DATABASES` from environment-specific config\n- `STATIC_ROOT` and static file serving strategy\n\nExample environment-driven settings:\n\n```python\nimport os\n\nDEBUG = os.getenv(\"DJANGO_DEBUG\", \"\").lower() == \"true\"\nSECRET_KEY = os.environ[\"DJANGO_SECRET_KEY\"]\nALLOWED_HOSTS = os.getenv(\"DJANGO_ALLOWED_HOSTS\", \"localhost,127.0.0.1\").split(\",\")\nCSRF_TRUSTED_ORIGINS = [\n    origin for origin in os.getenv(\"DJANGO_CSRF_TRUSTED_ORIGINS\", \"\").split(\",\") if origin\n]\n```\n\n## ASGI vs WSGI\n\nUse the generated application object with your server instead of `runserver` in production.\n\nASGI:\n\n```python\nfrom django.core.asgi import get_asgi_application\n\napplication = get_asgi_application()\n```\n\nWSGI:\n\n```python\nfrom django.core.wsgi import get_wsgi_application\n\napplication = get_wsgi_application()\n```\n\nUse ASGI if your stack needs async views, long-lived connections, or additional ASGI tooling. Use WSGI for conventional sync deployments.\n\n## Common Commands\n\n```bash\npython manage.py runserver\npython manage.py makemigrations\npython manage.py migrate\npython manage.py createsuperuser\npython manage.py shell\npython manage.py test\npython manage.py collectstatic\npython manage.py check --deploy\n```\n\n## Common Pitfalls\n\n- Do not use `runserver` in production. Deploy the ASGI or WSGI application behind a real application server.\n- `makemigrations` writes migration files; `migrate` applies them. Agents often do one and forget the other.\n- New apps must be added to `INSTALLED_APPS` before model discovery, app configs, admin registration, and template loading behave as expected.\n- Keep templates under `templates/<app_name>/...`; flat template names collide quickly in larger projects.\n- Set `ALLOWED_HOSTS` before turning `DEBUG` off or you will get `DisallowedHost` errors.\n- Keep `SECRET_KEY` out of the repo. If rotating keys, Django 6.0 still supports `SECRET_KEY_FALLBACKS` for staged rotation.\n- The deployment checklist is not optional. Run `python manage.py check --deploy` against production settings before release.\n- Async Django is not the same as \"everything is non-blocking\". Avoid calling blocking libraries directly from async views.\n\n## Version-Sensitive Notes For Django 6.0\n\n- Django 6.0 requires Python 3.12 or later.\n- The Django 6.0 release adds built-in Content Security Policy support, template partials, and a task framework. These are new enough that many third-party blog posts will not cover them correctly.\n- Django 6.0.3 is a patch release in the 6.0 line; check the 6.0.3 release notes before copying examples from early 6.0 articles, especially around security fixes and bugfixes.\n- If a project still targets Python 3.10 or 3.11, it cannot move to Django 6.0 without a Python upgrade.\n\n## Official Sources\n\n- Django 6.0 docs root: https://docs.djangoproject.com/en/6.0/\n- Installation guide: https://docs.djangoproject.com/en/6.0/intro/install/\n- Tutorial part 1: https://docs.djangoproject.com/en/6.0/intro/tutorial01/\n- Tutorial part 2: https://docs.djangoproject.com/en/6.0/intro/tutorial02/\n- Settings topic guide: https://docs.djangoproject.com/en/6.0/topics/settings/\n- Deployment checklist: https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\n- ASGI deployment: https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/\n- WSGI deployment: https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/\n- Django 6.0 release notes: https://docs.djangoproject.com/en/6.0/releases/6.0/\n- Django 6.0.3 release notes: https://docs.djangoproject.com/en/6.0/releases/6.0.3/\n- PyPI package page: https://pypi.org/project/django/\n"
  },
  {
    "path": "content/django/docs/phonenumber-field/python/DOC.md",
    "content": "---\nname: phonenumber-field\ndescription: \"django-phonenumber-field package guide for Django model, form, and DRF phone number handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.4.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-phonenumber-field,django,phone,phonenumbers,validation,forms,drf\"\n---\n\n# django-phonenumber-field 8.4.0 Python Package Guide\n\n## What It Does\n\n`django-phonenumber-field` adds Django-aware phone number fields for models, forms, and Django REST Framework serializers on top of Google's libphonenumber data through either `phonenumbers` or `phonenumberslite`.\n\nUse it when a Django project needs validated, normalized phone numbers instead of raw strings. The main things to get right are:\n\n- install a parsing backend extra\n- set a default region if users enter national numbers\n- choose database and display formats deliberately\n- use explicit output formats for APIs instead of relying on `str()`\n- preserve extensions only with extension-friendly formats\n\n## Version Covered\n\n- Package: `django-phonenumber-field`\n- Django app label: `phonenumber_field`\n- Import paths:\n  - `phonenumber_field.modelfields.PhoneNumberField`\n  - `phonenumber_field.formfields.PhoneNumberField`\n  - `phonenumber_field.serializerfields.PhoneNumberField`\n- Version in this doc: `8.4.0`\n- Supported Python versions on the `8.4.0` PyPI release: `3.10` to `3.14`\n- Supported Django versions on the `8.4.0` PyPI release: `4.2`, `5.1`, `5.2`, `6.0`\n\nVersion note: as of March 12, 2026, PyPI lists `8.4.0` as the latest release, so the floating docs URL appears aligned with this package version.\n\n## Install\n\nInstall the package with one of its phone-number parsing backends:\n\n```bash\npython -m pip install \"django-phonenumber-field[phonenumberslite]==8.4.0\"\n```\n\nUse full `phonenumbers` instead of `phonenumberslite` if you need geocoding, carrier, or timezone metadata:\n\n```bash\npython -m pip install \"django-phonenumber-field[phonenumbers]==8.4.0\"\n```\n\nEquivalent commands:\n\n```bash\nuv add \"django-phonenumber-field[phonenumberslite]==8.4.0\"\n```\n\n```bash\npoetry add \"django-phonenumber-field[phonenumberslite]==8.4.0\"\n```\n\nIf you use `SplitPhoneNumberField`, install Babel too:\n\n```bash\npython -m pip install Babel\n```\n\n## Minimal Setup\n\nAdd the app to `INSTALLED_APPS`:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"phonenumber_field\",\n]\n```\n\nIf users enter local numbers such as `\"604 401 1234\"` instead of international `+`-prefixed numbers, set a default region:\n\n```python\n# settings.py\nPHONENUMBER_DEFAULT_REGION = \"CA\"\n```\n\nWithout a region, parsing national numbers is ambiguous and validation may fail.\n\n## No Auth\n\nThis package has no authentication flow. Runtime behavior is controlled by Django settings, the selected `phonenumbers` extra, and the options you pass to fields and widgets.\n\n## Core Usage\n\n### Model field\n\n```python\nfrom django.db import models\nfrom phonenumber_field.modelfields import PhoneNumberField\n\nclass Contact(models.Model):\n    name = models.CharField(max_length=100)\n    phone_number = PhoneNumberField(blank=True)\n```\n\nPrefer saving international input when possible:\n\n```python\ncontact = Contact.objects.create(\n    name=\"Alice\",\n    phone_number=\"+16044011234\",\n)\n```\n\nThe stored value becomes a `PhoneNumber` wrapper when loaded from Django:\n\n```python\ncontact = Contact.objects.get(pk=1)\n\nassert contact.phone_number.is_valid()\nassert contact.phone_number.as_e164 == \"+16044011234\"\nassert contact.phone_number.as_national == \"(604) 401-1234\"\n```\n\n### Direct parsing\n\nIf you need parsing outside a model or form, use the wrapper directly:\n\n```python\nfrom phonenumber_field.phonenumber import PhoneNumber\n\nnumber = PhoneNumber.from_string(\"(604) 401 1234\", region=\"CA\")\n\nassert number.is_valid()\nassert number.as_e164 == \"+16044011234\"\n```\n\n### Form field\n\n```python\nfrom django import forms\nfrom phonenumber_field.formfields import PhoneNumberField\n\nclass ContactForm(forms.Form):\n    phone_number = PhoneNumberField(region=\"CA\")\n```\n\nThe form field validates input and returns a `PhoneNumber` object in `cleaned_data`.\n\n### Django REST Framework serializer field\n\nIf the project uses DRF, use the package serializer field instead of a plain string field:\n\n```python\nfrom rest_framework import serializers\nfrom phonenumber_field.serializerfields import PhoneNumberField\n\nclass ContactSerializer(serializers.Serializer):\n    phone_number = PhoneNumberField()\n```\n\nThat keeps serializer validation aligned with model and form behavior. Serializer output follows `PHONENUMBER_DEFAULT_FORMAT`, so set that deliberately if your API contract expects `E164`, `RFC3966`, or another format.\n\n## Configuration That Matters\n\n### `PHONENUMBER_DEFAULT_REGION`\n\nUse this when user input is commonly national rather than international:\n\n```python\nPHONENUMBER_DEFAULT_REGION = \"US\"\n```\n\nThis setting affects parsing. It is the first thing to check if valid local numbers are being rejected.\n\n### `PHONENUMBER_DB_FORMAT`\n\nChoose how values are stored in the database:\n\n```python\nPHONENUMBER_DB_FORMAT = \"E164\"\n```\n\nCommon choices are `E164`, `INTERNATIONAL`, `NATIONAL`, and `RFC3966`.\n\nPractical rule:\n\n- use `E164` for most APIs, SMS systems, and deduplication logic\n- use `RFC3966` or `INTERNATIONAL` if you need extension support preserved in storage\n- avoid `NATIONAL` unless the project is truly single-region and you control every reader\n\nChanging `PHONENUMBER_DB_FORMAT` after data already exists can lose extension information, and changing the default region while using `\"NATIONAL\"` can reinterpret stored values incorrectly.\n\n### `PHONENUMBER_DEFAULT_FORMAT`\n\nChoose how values render when coerced to strings:\n\n```python\nPHONENUMBER_DEFAULT_FORMAT = \"E164\"\n```\n\nKeep this aligned with how your app serializes or displays phone numbers. If you need a specific wire format, prefer explicit properties such as `.as_e164` rather than relying on implicit string conversion.\n\n## Widgets And Split Inputs\n\nFor a region-aware widget in forms, use `RegionalPhoneNumberWidget`:\n\n```python\nfrom django import forms\nfrom phonenumber_field.formfields import PhoneNumberField\nfrom phonenumber_field.widgets import RegionalPhoneNumberWidget\n\nclass ContactForm(forms.Form):\n    phone_number = PhoneNumberField(\n        widget=RegionalPhoneNumberWidget(region=\"US\"),\n    )\n```\n\nIf you want separate country-prefix and number inputs, use `SplitPhoneNumberField`. This requires Babel and produces a composed `PhoneNumber` value after validation.\n\n```python\nfrom django import forms\nfrom phonenumber_field.formfields import SplitPhoneNumberField\n\nclass SignupForm(forms.Form):\n    phone_number = SplitPhoneNumberField(region=\"US\")\n```\n\nIf you need to limit country choices or customize widget attributes, subclass `SplitPhoneNumberField` and override `prefix_field()` or `number_field()`.\n\n## Common Pitfalls\n\n- Installing `django-phonenumber-field` without either the `phonenumbers` or `phonenumberslite` extra.\n- Forgetting `\"phonenumber_field\"` in `INSTALLED_APPS`.\n- Accepting national numbers but not setting `PHONENUMBER_DEFAULT_REGION`.\n- Relying on `str(phone_number)` in API payloads instead of explicit formats such as `.as_e164`.\n- Choosing `PHONENUMBER_DB_FORMAT = \"NATIONAL\"` and later moving data across regions or changing the default region.\n- Expecting phone-number extensions to round-trip cleanly while using the default `E164` DB and display formats.\n- Forgetting that `SplitPhoneNumberField` requires `Babel`.\n- Treating any parseable number as valid. Use `.is_valid()` or field validation because not all well-formed numbers are valid.\n\n## Version-Sensitive Notes\n\n- This entry targets `django-phonenumber-field==8.4.0`.\n- The `8.4.0` release updated supported Python and Django versions. Prefer the support matrix on the `8.4.0` PyPI page over older blog posts or old snippets.\n- The `8.4.0` release also fixed handling of empty values in `SplitPhoneNumberField` when `max_length` is set. Re-check any local workaround around split fields after upgrading.\n- The `8.0.0` release moved validation behavior from widgets into form fields and removed `PhoneNumberInternationalFallbackWidget`. If you are upgrading older code, do not try to restore that widget in `8.4.0`.\n- As of March 12, 2026, the docs URL `https://django-phonenumber-field.readthedocs.io/en/latest/` and the package version are aligned at the latest `8.4.0` release, but install commands in this doc stay version-pinned on purpose.\n\n## Official Context\n\n- Docs root: https://django-phonenumber-field.readthedocs.io/en/latest/\n- Reference docs: https://django-phonenumber-field.readthedocs.io/en/stable/reference.html\n- Handling extensions: https://django-phonenumber-field.readthedocs.io/en/stable/phonenumbers.html\n- `8.4.0` release notes: https://github.com/stefanfoulis/django-phonenumber-field/releases/tag/8.4.0\n- PyPI release page: https://pypi.org/project/django-phonenumber-field/8.4.0/\n- Repository: https://github.com/stefanfoulis/django-phonenumber-field\n"
  },
  {
    "path": "content/django/docs/polymorphic/python/DOC.md",
    "content": "---\nname: polymorphic\ndescription: \"django-polymorphic package guide for Django multi-table inheritance, polymorphic querysets, and admin integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.11.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,orm,polymorphism,model-inheritance,admin,querysets,typing\"\n---\n\n# django-polymorphic Python Package Guide\n\n## What It Does\n\n`django-polymorphic` makes Django multi-table inheritance return real subclass instances when you query the base model. Use it when you have one conceptual model with subtype-specific fields and you want the Django ORM and admin to preserve the concrete type automatically.\n\nUse plain Django models instead when:\n\n- you only need abstract base classes or shared mixins\n- subtype-specific data can live in separate related models\n- the extra joins from multi-table inheritance are not worth the convenience\n\n## Install\n\n```bash\npython -m pip install \"django-polymorphic==4.11.2\"\n```\n\nIf you use static typing, upstream `4.11` also ships first-party type hints. For type checking, install `django-stubs` and optionally `django-stubs-ext` in your dev environment.\n\n## Django Setup\n\nAdd the package and the contenttypes framework to `INSTALLED_APPS`:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"django.contrib.contenttypes\",\n    \"polymorphic\",\n]\n```\n\nThen run migrations as usual:\n\n```bash\npython manage.py migrate\n```\n\nThere is no package-level network authentication or external service configuration. Setup is just Django app registration plus normal model/admin wiring.\n\n## First Working Model\n\nUse `PolymorphicModel` for the shared base model. Child models should inherit from that base as normal Django multi-table subclasses.\n\n```python\nfrom django.db import models\nfrom polymorphic.models import PolymorphicModel\n\nclass Project(PolymorphicModel):\n    topic = models.CharField(max_length=200)\n\nclass ArtProject(Project):\n    artist = models.CharField(max_length=200)\n\nclass ResearchProject(Project):\n    supervisor = models.CharField(max_length=200)\n```\n\nThe base model stores an internal `polymorphic_ctype` foreign key to `ContentType`. That field is managed for you on save.\n\n## Querying\n\nA base-model queryset returns real subclasses automatically:\n\n```python\nprojects = Project.objects.all()\nfor project in projects:\n    print(type(project).__name__, project.topic)\n```\n\nFilter by subtype with `instance_of()` and `not_instance_of()`:\n\n```python\nart_projects = Project.objects.instance_of(ArtProject)\nnot_research = Project.objects.not_instance_of(ResearchProject)\n```\n\nFilter or order on child-only fields with the documented `ModelName___field` syntax:\n\n```python\nfrom django.db.models import Q\n\nturner_projects = Project.objects.filter(\n    Q(ArtProject___artist=\"T. Turner\")\n    | Q(ResearchProject___supervisor=\"T. Turner\")\n)\n```\n\nWhen you intentionally want base objects only, turn off polymorphic casting for that queryset:\n\n```python\nbase_rows = Project.objects.non_polymorphic().only(\"id\", \"topic\")\n```\n\n`non_polymorphic()` is useful for narrow read paths, but do not fall back to calling `get_real_instance()` on every row in a loop for large querysets. The package already batches subtype fetching by model type.\n\n## Custom Managers\n\nIf you add a custom manager, inherit from `PolymorphicManager`, not `models.Manager`. Keep the first/default manager unfiltered and use plain `PolymorphicManager` for it.\n\n```python\nfrom polymorphic.managers import PolymorphicManager\n\nclass TimeOrderedManager(PolymorphicManager):\n    def get_queryset(self):\n        return super().get_queryset().order_by(\"-start_date\")\n\n    def most_recent(self):\n        return self.get_queryset()[:10]\n\nclass Project(PolymorphicModel):\n    objects = PolymorphicManager()\n    objects_ordered = TimeOrderedManager()\n```\n\nThe first manager defined is used by Django for related-object access and internal behavior. Do not make that manager filtered or non-polymorphic.\n\n## Admin Integration\n\nFor one unified admin surface:\n\n- Base admin class: inherit from `PolymorphicParentModelAdmin`\n- Child admin classes: inherit from `PolymorphicChildModelAdmin`\n- Set `base_model` on both sides\n- Set `child_models` on the parent admin or override `get_child_models()`\n- Register the child admins too, even though they stay hidden from the index unless `show_in_index = True`\n\nTypical shape:\n\n```python\nfrom django.contrib import admin\nfrom polymorphic.admin import (\n    PolymorphicChildModelAdmin,\n    PolymorphicParentModelAdmin,\n)\n\n@admin.register(Project)\nclass ProjectAdmin(PolymorphicParentModelAdmin):\n    base_model = Project\n    child_models = (ArtProject, ResearchProject)\n\n@admin.register(ArtProject)\nclass ArtProjectAdmin(PolymorphicChildModelAdmin):\n    base_model = Project\n\n@admin.register(ResearchProject)\nclass ResearchProjectAdmin(PolymorphicChildModelAdmin):\n    base_model = Project\n```\n\nTwo rules matter in practice:\n\n- register the child admins too, even though they stay hidden from the index unless `show_in_index = True`\n- put fieldset customizations on child admins; if you subclass child admins, prefer `base_form` and `base_fieldsets` over `form` and `fieldsets`\n\nIf you need polymorphic inlines, use the package's polymorphic inline helpers instead of plain Django inline classes alone.\n\n## Configuration And Auth\n\n`django-polymorphic` does not talk to an external API and has no package-specific auth model. The configuration that actually matters is:\n\n- `INSTALLED_APPS` includes both `\"polymorphic\"` and `\"django.contrib.contenttypes\"`\n- your base models inherit from `PolymorphicModel`\n- your default manager stays a plain `PolymorphicManager`\n- your admin registration uses the polymorphic admin base classes if you want a unified admin UI\n\nIf your project also uses Django auth, DRF, or custom permissions, those stay configured the normal Django way. `django-polymorphic` only changes model/query behavior.\n\n## Migrations And Existing Data\n\nWhen converting an existing model tree to `django-polymorphic`:\n\n1. Change the base model to inherit from `PolymorphicModel`.\n2. Create the migration that adds `polymorphic_ctype_id`.\n3. Backfill `polymorphic_ctype` for existing rows before relying on polymorphic queries.\n\nMinimal backfill pattern:\n\n```python\nfrom django.contrib.contenttypes.models import ContentType\n\nfrom myapp.models import Project\n\nct = ContentType.objects.get_for_model(Project)\nProject.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=ct)\n```\n\nDo this in a migration or controlled data-fix step, not ad hoc at request time.\n\n## Performance Notes\n\n- A normal polymorphic queryset does one query for the base model plus one extra query per concrete subtype present in the result set.\n- This is much better than row-by-row upcasting, which can turn into one extra query per object.\n- Each subclass still means extra joins for child fields, so do not use polymorphic inheritance for very hot paths unless the type-aware model shape is worth it.\n- Large iterations fetch a maximum of `2000` objects per chunk by default. Use `.iterator(chunk_size=...)` when memory or query shape matters.\n\n## Type Checking\n\nStarting in `4.11`, the package ships type hints for its public APIs and documents how to annotate `PolymorphicManager` and related descriptors.\n\nPractical guidance:\n\n- there are no extra runtime dependencies for typing support\n- `django-stubs` is required in the type-checking environment\n- `django-stubs-ext` is optional\n- Django cannot infer precise polymorphic return unions automatically, so annotate custom managers and relationship descriptors explicitly if you want strong editor and CI feedback\n\n## Common Pitfalls\n\n- Install the Django app as `\"polymorphic\"`, not `\"django_polymorphic\"`.\n- Keep `\"django.contrib.contenttypes\"` enabled; `polymorphic_ctype` depends on it.\n- Child-field filters use three underscores between model and field, for example `ArtProject___artist`.\n- Do not make a filtered custom manager the first manager on the model; Django uses the first manager for related-object access and internal behavior.\n- Register the child admin classes too. The parent admin alone is not enough.\n- If you bypass polymorphic behavior with `.non_polymorphic()`, any later per-row upcasting can create an N+1 query pattern.\n- Manual raw-SQL deletes can leave stale `polymorphic_ctype` values behind and make polymorphic queries skip or fail on affected rows.\n- This package is for Django model inheritance, not for abstract model mixins or single-table inheritance.\n\n## Version-Sensitive Notes\n\nAs of `2026-03-12`, PyPI lists `4.11.2` as the current release, published on `2026-03-07`.\n\n- `4.11` added first-party type hints and a dedicated typing guide.\n- PyPI marks `4.10.3` and `4.10.4` as yanked because of a base manager bug. Do not pin those releases in new work.\n- The `4.x` line targets modern Python and Django versions. If a project is still pinned below Python `3.10` or needs older Django compatibility, verify whether it belongs on the `3.x` line instead.\n- The official stable docs are slightly inconsistent today: the home, quickstart, admin, migrating, and typing pages render as `4.11.2`, the performance page renders as `4.11.1`, and the changelog page currently renders `4.9.0` headings. Use PyPI release history for exact patch-level version selection.\n\n## Official Sources\n\n- Docs root: https://django-polymorphic.readthedocs.io/en/stable/\n- Quickstart: https://django-polymorphic.readthedocs.io/en/stable/quickstart.html\n- Managers and querysets: https://django-polymorphic.readthedocs.io/en/stable/managers.html\n- Admin integration: https://django-polymorphic.readthedocs.io/en/stable/admin.html\n- Performance: https://django-polymorphic.readthedocs.io/en/stable/performance.html\n- Migrating existing models: https://django-polymorphic.readthedocs.io/en/stable/migrating.html\n- Type hints: https://django-polymorphic.readthedocs.io/en/stable/typing.html\n- Changelog: https://django-polymorphic.readthedocs.io/en/stable/changelog.html\n- PyPI: https://pypi.org/project/django-polymorphic/\n- Repository: https://github.com/jazzband/django-polymorphic\n"
  },
  {
    "path": "content/django/docs/q2/python/DOC.md",
    "content": "---\nname: q2\ndescription: \"django-q2 package guide for background tasks, worker clusters, and schedules in Django projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,task-queue,scheduler,workers,async,jobs,background\"\n---\n\n# django-q2 Python Package Guide\n\n`django-q2` is a Django-native task queue and scheduler. Use it when a Django app needs background jobs, recurring schedules, and a worker cluster without introducing Celery. The package is installed as `django-q2`, but the Django app label and import namespace are `django_q`.\n\n## Install\n\nInstall the version used here explicitly if the project is pinned:\n\n```bash\npython -m pip install \"django-q2==1.9.0\"\n```\n\nUseful optional dependencies from the official docs and package metadata:\n\n- `redis` for the Redis broker\n- `boto3` for the SQS broker\n- `pymongo` for the MongoDB broker\n- `croniter` for cron schedules\n- `blessed` for `qmonitor` and `qmemory`\n- `psutil` if you use `cpu_affinity`\n\nExample:\n\n```bash\npython -m pip install \"django-q2==1.9.0\" redis croniter blessed\n```\n\n## Minimal Django Setup\n\nAdd `django_q` to `INSTALLED_APPS` and run migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"django_q\",\n]\n```\n\n```bash\npython manage.py migrate\n```\n\nChoose a broker and define `Q_CLUSTER`. Redis is the best default for most non-trivial deployments:\n\n```python\n# settings.py\nimport os\n\nQ_CLUSTER = {\n    \"name\": \"default\",\n    \"workers\": 4,\n    \"timeout\": 90,\n    \"retry\": 120,\n    \"recycle\": 500,\n    \"queue_limit\": 50,\n    \"save_limit\": 250,\n    \"label\": \"Django Q2\",\n    \"redis\": os.environ[\"REDIS_URL\"],\n}\n```\n\nFor local development or small installations, the ORM broker is simpler:\n\n```python\nQ_CLUSTER = {\n    \"name\": \"default\",\n    \"workers\": 2,\n    \"timeout\": 90,\n    \"retry\": 120,\n    \"queue_limit\": 50,\n    \"bulk\": 10,\n    \"orm\": \"default\",\n}\n```\n\n`django-q2` does not execute queued tasks inside the web process. Start a cluster in a separate process:\n\n```bash\npython manage.py qcluster\n```\n\n## Running And Routing Clusters\n\nThe cluster process manages a worker pool with Django Q2's internal sentinel. For one queue, start one cluster process and scale that cluster with settings like `workers`, `timeout`, and `recycle`.\n\n```bash\npython manage.py qcluster\n```\n\nIf you use multiple queues, route them by cluster name:\n\n```bash\nQ_CLUSTER_NAME=long python manage.py qcluster\n```\n\n```python\nfrom django_q.tasks import async_task\n\nasync_task(\"myapp.tasks.generate_report\", report_id, cluster=\"long\")\n```\n\nSchedules can also be restrained to a named cluster.\n\n## Core Task Usage\n\nQueue a normal importable callable:\n\n```python\nfrom django_q.tasks import async_task\n\ntask_id = async_task(\n    \"myapp.tasks.send_welcome_email\",\n    user_id,\n    group=\"email\",\n    timeout=60,\n    hook=\"myapp.hooks.on_welcome_email_complete\",\n)\n```\n\nDefine the task as normal Django code:\n\n```python\n# myapp/tasks.py\nfrom django.core.mail import send_mail\n\ndef send_welcome_email(user_id: int) -> None:\n    send_mail(\n        subject=\"Welcome\",\n        message=f\"User {user_id} signed up.\",\n        from_email=\"noreply@example.com\",\n        recipient_list=[\"ops@example.com\"],\n    )\n```\n\nRead results later:\n\n```python\nfrom django_q.tasks import fetch, result\n\nvalue = result(task_id, wait=200)\ntask = fetch(task_id, wait=200)\n```\n\nTask APIs agents usually need first:\n\n- `async_task()` to enqueue work\n- `result()` to get the saved result\n- `fetch()` to fetch the full task record\n- `result_group()` and `fetch_group()` for grouped work\n- `async_iter()` for bulk fan-out work without manual loops\n\nIf your task function needs keyword names like `hook`, `group`, or `timeout`, pass queue options inside `q_options` so they do not collide with the function signature:\n\n```python\nfrom django_q.tasks import async_task\n\nopts = {\n    \"group\": \"reports\",\n    \"timeout\": 30,\n    \"hook\": \"myapp.hooks.on_report_complete\",\n}\n\nasync_task(\"myapp.tasks.build_report\", report_id, q_options=opts)\n```\n\nFor repeated enqueue operations, reuse a broker connection:\n\n```python\nfrom django_q.brokers import get_broker\nfrom django_q.tasks import async_task\n\nbroker = get_broker()\nfor report_id in report_ids:\n    async_task(\"myapp.tasks.build_report\", report_id, broker=broker)\n```\n\n## Scheduling Jobs\n\nCreate schedules from code or the admin. Cron schedules require `croniter`.\n\n```python\nfrom django_q.models import Schedule\nfrom django_q.tasks import schedule\n\nschedule(\n    \"myapp.tasks.send_digest\",\n    schedule_type=Schedule.CRON,\n    cron=\"0 8 * * 1-5\",\n    repeats=-1,\n    cluster=\"default\",\n)\n```\n\nRun a job every five minutes for two hours:\n\n```python\nfrom datetime import datetime\n\nfrom django_q.models import Schedule\nfrom django_q.tasks import schedule\n\nschedule(\n    \"myapp.tasks.refresh_metrics\",\n    schedule_type=Schedule.MINUTES,\n    minutes=5,\n    repeats=24,\n    next_run=datetime.utcnow().replace(hour=18, minute=0),\n)\n```\n\nIf you want the task to know the scheduled timestamp it was originally supposed to run at, use `intended_date_kwarg`:\n\n```python\nschedule(\n    \"myapp.tasks.run_billing_cycle\",\n    schedule_type=Schedule.DAILY,\n    intended_date_kwarg=\"scheduled_for\",\n)\n```\n\nScheduling fields that matter most in practice:\n\n- `schedule_type`: once, minutes, hourly, daily, weekly, monthly, quarterly, yearly, or cron\n- `minutes`: interval for `Schedule.MINUTES`\n- `cron`: cron expression for `Schedule.CRON`\n- `repeats`: `-1` means forever\n- `next_run`: first execution time\n- `cluster`: route the scheduled task to one named cluster\n- `q_options`: per-schedule task options like `timeout` or `broker_name`\n\n## Configuration And Broker/Auth Model\n\n`django-q2` has no package-level authentication system. Access control comes from the broker or backend you configure in `Q_CLUSTER`.\n\nRedis using a URI:\n\n```python\nQ_CLUSTER = {\n    \"name\": \"default\",\n    \"workers\": 4,\n    \"timeout\": 90,\n    \"retry\": 120,\n    \"redis\": \"redis://user:password@redis.example.com:6379/0\",\n}\n```\n\nRedis using `django-redis`:\n\n```python\nQ_CLUSTER = {\n    \"name\": \"default\",\n    \"workers\": 4,\n    \"timeout\": 90,\n    \"django_redis\": \"default\",\n}\n```\n\nAmazon SQS:\n\n```python\nQ_CLUSTER = {\n    \"name\": \"sqs\",\n    \"workers\": 4,\n    \"timeout\": 60,\n    \"retry\": 90,\n    \"queue_limit\": 100,\n    \"bulk\": 5,\n    \"sqs\": {\n        \"aws_region\": \"us-east-1\",\n        \"aws_access_key_id\": os.environ[\"AWS_ACCESS_KEY_ID\"],\n        \"aws_secret_access_key\": os.environ[\"AWS_SECRET_ACCESS_KEY\"],\n    },\n}\n```\n\nOperational settings that most agent-written setups need to choose deliberately:\n\n- `workers`: process count for the cluster\n- `timeout`: maximum runtime for a task\n- `retry`: redelivery delay for receipt-capable brokers\n- `recycle`: restart workers after N tasks\n- `save_limit`: how many successful task results to keep\n- `queue_limit`: queued task cap in memory\n- `sync`: force synchronous execution, mainly for tests\n- `catch_up`: whether missed schedules replay after downtime\n- `cpu_affinity`: optional performance tuning, requires `psutil`\n\nAll cluster processes that should work on the same queue need:\n\n- the same broker\n- the same cluster name\n- the same Django `SECRET_KEY`\n\nThe docs also state that Django Q2 signs task packages with `SECRET_KEY`, so keep it consistent across worker instances.\n\n## Management Commands\n\n```bash\npython manage.py migrate\npython manage.py qcluster\npython manage.py qmonitor\npython manage.py qmemory\npython manage.py qinfo\n```\n\n`qmonitor` and `qmemory` require `blessed`.\n\n## Common Pitfalls\n\n- The pip package is `django-q2`, but `INSTALLED_APPS` and imports use `django_q`.\n- No background task runs unless a `qcluster` process is running or you explicitly force sync mode.\n- Keep `retry` greater than `timeout` and greater than the longest real task duration, or brokers with delivery receipts can run the same task multiple times.\n- `sync=True` is for tests and debugging. It bypasses the broker and does not validate production worker behavior.\n- Cron schedules need `croniter`. Monitoring commands need `blessed`. Redis, SQS, MongoDB, and CPU-affinity features each need their own optional dependency.\n- The ORM broker is convenient for local development, but Redis or another external broker is the safer default for production throughput and failure handling.\n- `catch_up` defaults to replaying missed schedules. If a backlog burst after downtime is unacceptable, set `\"catch_up\": False`.\n- Use `q_options` when task option names would otherwise collide with your function kwargs.\n- Do not start multiple identical cluster supervisor processes in one environment to \"scale up\" by accident. The official cluster docs recommend tuning `workers`, `recycle`, and `timeout` first.\n\n## Version-Sensitive Notes For `1.9.0`\n\n- The version used here for this session is `1.9.0`.\n- PyPI shows `django-q2 1.9.0` as the latest official release, published on December 4, 2025.\n- The Read the Docs stream still serves pages branded `Django Q2 1.6.0`, so treat the docs site as conceptually accurate for APIs and configuration, but not as a precise version snapshot for `1.9.0`.\n- The official `v1.8.0` release says support for Python `3.8` was dropped. Do not assume `1.9.0` works on Python `3.8`.\n- The official `v1.9.0` release notes call out two changes that matter operationally: a fix for compatibility with `redis-py > 5`, and Django `6.0` support.\n- If project behavior disagrees with the docs site, trust the installed package version, current PyPI metadata, and the GitHub release notes for the exact series you are on.\n\n## Recommended Agent Workflow\n\n1. Confirm that the project actually wants a Django-native queue and not a more distributed system.\n2. Add `django_q`, run migrations, and choose the broker before writing task code.\n3. Start one real `qcluster` process early and verify one simple `async_task()` path end to end.\n4. Set `timeout`, `retry`, and `catch_up` explicitly instead of keeping defaults by accident.\n5. Add schedules only after basic background execution is working.\n6. When debugging version-specific behavior, compare the installed package against the official GitHub releases because the docs stream is behind.\n\n## Official Sources Used\n\n- Docs root: `https://django-q2.readthedocs.io/en/latest/`\n- Configuration docs: `https://django-q2.readthedocs.io/en/master/configure.html`\n- Tasks docs: `https://django-q2.readthedocs.io/en/master/tasks.html`\n- Schedules docs: `https://django-q2.readthedocs.io/en/master/schedules.html`\n- Cluster docs: `https://django-q2.readthedocs.io/en/master/cluster.html`\n- Package page: `https://pypi.org/project/django-q2/`\n- Releases: `https://github.com/django-q2/django-q2/releases`\n"
  },
  {
    "path": "content/django/docs/redis/python/DOC.md",
    "content": "---\nname: redis\ndescription: \"django-redis package guide for Python: Django cache backend, sessions, raw Redis access, Sentinel, and operational pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,redis,cache,sessions,sentinel,python,pypi\"\n---\n\n# django-redis Python Package Guide\n\n`django-redis` is the maintained Redis cache backend for Django. Use it when a Django project needs Redis-backed caching, cache-based sessions, or direct `redis-py` access from Django code.\n\n## Version Baseline For 6.0.0\n\nThe 6.0.0 release notes and package metadata align on these minimums:\n\n- Python: `>=3.9`\n- Django: `>=4.2`\n- `redis-py`: `>=4.0.2`\n- Redis server: `>=2.8`\n\nIf your project is still on Django 4.1 or Python 3.8, do not copy this config verbatim. Upgrade planning is part of the migration.\n\n## Install\n\n```bash\npip install django-redis==6.0.0\n```\n\nOptional parser acceleration:\n\n```bash\npip install hiredis\n```\n\nYou also need a reachable Redis deployment:\n\n- standalone Redis\n- Redis over TLS\n- Redis via Unix socket\n- Redis Sentinel for failover\n\n## Minimal Django Setup\n\nUse `django_redis.cache.RedisCache` as the backend and point `LOCATION` at a Redis URL:\n\n```python\n# settings.py\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://127.0.0.1:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    }\n}\n```\n\nSupported connection styles from upstream docs:\n\n- `redis://host:port/db` for plain TCP\n- `rediss://host:port/db` for TLS\n- `unix:///path/to/redis.sock?db=1` for a Unix socket\n\nOnly caches configured with `django_redis.cache.RedisCache` support `django-redis` helpers such as `ttl()`, `delete_pattern()`, and `get_redis_connection()`.\n\n## Auth And Connection Configuration\n\nYou can put credentials directly in the URL or pass them in `OPTIONS`.\n\n### URL-based auth\n\n```python\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://django:secret@redis.internal:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    }\n}\n```\n\n### Username and password in `OPTIONS`\n\n```python\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://redis.internal:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n            \"USERNAME\": \"django\",\n            \"PASSWORD\": \"secret\",\n        },\n    }\n}\n```\n\nPractical options that show up often in real deployments:\n\n```python\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"rediss://redis.internal:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n            \"SOCKET_CONNECT_TIMEOUT\": 5,\n            \"SOCKET_TIMEOUT\": 5,\n            \"CONNECTION_POOL_KWARGS\": {\n                \"max_connections\": 100,\n                \"retry_on_timeout\": True,\n            },\n            \"SSL_CERT_REQS\": None,\n        },\n    }\n}\n```\n\nNotes:\n\n- `SOCKET_CONNECT_TIMEOUT` covers initial connection setup.\n- `SOCKET_TIMEOUT` covers read and write operations after the connection is open.\n- `CONNECTION_POOL_KWARGS` is forwarded to the underlying `redis-py` connection pool.\n- `SSL_CERT_REQS=None` disables certificate verification. Keep that limited to local development and controlled test environments.\n- If the Redis URL already contains credentials, the URL wins over `OPTIONS[\"PASSWORD\"]`.\n\n## Core Cache Usage\n\nUse Django's cache API for normal cache reads and writes:\n\n```python\nfrom django.core.cache import cache\n\ncache.set(\"user:42\", {\"name\": \"Ada\"}, timeout=300)\nuser = cache.get(\"user:42\")\n\nprofile = cache.get_or_set(\n    \"profile:42\",\n    lambda: {\"projects\": 7},\n    timeout=600,\n)\n\ncreated = cache.set(\"job:nightly\", \"queued\", timeout=60, nx=True)\ncache.incr(\"api:quota:used\")\ncache.delete(\"user:42\")\n```\n\nTimeout behavior matters:\n\n- `timeout=None` stores without expiration\n- `timeout=0` expires immediately\n- `cache.expire(key, seconds)` sets a TTL on an existing key\n- `cache.persist(key)` removes an existing expiration\n\nRedis-only helpers exposed by `django-redis`:\n\n```python\nfrom django.core.cache import cache\n\ncache.set(\"counter\", 1, timeout=60)\ncache.incr(\"counter\")\n\nttl = cache.ttl(\"counter\")\npttl = cache.pttl(\"counter\")\ncache.expire(\"counter\", 120)\n\nfor key in cache.iter_keys(\"tenant:42:*\"):\n    print(key)\n\ncache.delete_pattern(\"tenant:42:*\")\n```\n\nThese methods are backend-specific. Do not assume they exist if a project swaps to Memcached or Django's local-memory cache.\n\n## Raw Redis Access\n\nWhen the Django cache API is too limited, use the underlying `redis-py` client:\n\n```python\nfrom django_redis import get_redis_connection\n\nredis_client = get_redis_connection(\"default\")\n\nredis_client.hset(\"feature-flags\", \"new_dashboard\", \"on\")\nredis_client.sadd(\"active-tenants\", \"tenant-42\")\n\nflag = redis_client.hget(\"feature-flags\", \"new_dashboard\")\ntenants = redis_client.smembers(\"active-tenants\")\n```\n\nThis returns a `redis-py` client. Pipelines, Lua scripts, pub/sub, locks, and Redis data-structure commands all follow `redis-py` semantics, not Django cache semantics.\n\n`get_redis_connection()` is only reliable with clients that expose raw-client access. If a project swaps in a heavily customized pluggable client, verify that helper still works.\n\n## Locks\n\nUse Redis locks for cross-process coordination:\n\n```python\nfrom django.core.cache import cache\n\nwith cache.lock(\"locks:nightly-report\", timeout=30, blocking_timeout=5):\n    run_report()\n```\n\nAlways set a finite `timeout` so a crashed worker does not hold the lock forever.\n\n## Sessions\n\nFor cache-backed sessions:\n\n```python\n# settings.py\nSESSION_ENGINE = \"django.contrib.sessions.backends.cache\"\nSESSION_CACHE_ALIAS = \"default\"\n```\n\nThis is fast, but it inherits cache behavior:\n\n- expired keys remove sessions\n- Redis eviction removes sessions\n- `FLUSHDB` or equivalent wipes sessions immediately\n\nIf login state must survive cache churn, use Django's database-backed session engine instead.\n\n## Serialization And Compression\n\nUpstream supports swapping serializers and compressors:\n\n```python\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://127.0.0.1:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n            \"SERIALIZER\": \"django_redis.serializers.json.JSONSerializer\",\n            \"COMPRESSOR\": \"django_redis.compressors.gzip.GzipCompressor\",\n        },\n    }\n}\n```\n\nUse JSON serialization only for JSON-safe values. If you cache arbitrary Python objects, keep the default pickle serializer or refactor the cached data shape.\n\nCompression helps when cached values are large. It adds CPU cost, so measure before enabling it globally.\n\n## Sentinel Setup\n\nFor Redis Sentinel, use the Sentinel client and connection factory:\n\n```python\n# settings.py\nDJANGO_REDIS_CONNECTION_FACTORY = \"django_redis.pool.SentinelConnectionFactory\"\n\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://service-name/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.SentinelClient\",\n            \"SENTINELS\": [\n                (\"sentinel-1.internal\", 26379),\n                (\"sentinel-2.internal\", 26379),\n                (\"sentinel-3.internal\", 26379),\n            ],\n            \"CONNECTION_POOL_CLASS\": \"redis.sentinel.SentinelConnectionPool\",\n        },\n    }\n}\n```\n\nTreat Sentinel as failover infrastructure, not generic client-side load balancing. Keep write traffic on the primary unless you have explicitly designed and tested replica reads.\n\n## Operational Flags\n\nTo emulate Django's memcached-style behavior where cache failures degrade to cache misses:\n\n```python\nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": \"redis://127.0.0.1:6379/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n            \"IGNORE_EXCEPTIONS\": True,\n        },\n    }\n}\n```\n\nUse this only intentionally. It hides Redis outages and can make production failures look like ordinary cache misses.\n\nUseful companion settings:\n\n- `DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True`\n- `DJANGO_REDIS_LOGGER = \"your.project.logger\"`\n- `DJANGO_REDIS_CLOSE_CONNECTION = True` if commands, workers, or tests need explicit connection teardown\n\nYou can also set `CLOSE_CONNECTION: True` per cache alias.\n\n## Common Pitfalls\n\n- Do not call `get_redis_connection()` before Django settings are loaded.\n- Do not assume Redis-only helpers such as `ttl()`, `lock()`, `iter_keys()`, or `delete_pattern()` work on non-Redis backends.\n- Do not use `cache.keys(\"*\")` on large datasets. Prefer `iter_keys()` or `delete_pattern()` and tune `DJANGO_REDIS_SCAN_ITERSIZE` if needed.\n- Do not use cache-backed sessions if Redis eviction, flushes, or cache-only retention policies are unacceptable for auth state.\n- Do not set `IGNORE_EXCEPTIONS=True` unless silent cache degradation is an explicit product decision.\n- Do not disable TLS certificate verification outside controlled development environments.\n- Do not assume old blog posts match current support requirements. `6.0.0` raises the supported Python and Django floor.\n\n## Version-Sensitive Notes For 6.0.0\n\nThis entry targets `django-redis==6.0.0`, released on `2025-06-17`.\n\nCompared with the 5.x line, the upstream 6.0.0 changelog calls out these relevant changes:\n\n- support added for Python `3.13`\n- support added for Django `5.2`\n- support dropped for Python `3.8`\n- support dropped for Django `4.1`\n- support added for hash map and set operations\n- `gzip` compression support added\n- `cache.lock()` gained a `blocking` parameter\n\nThat means older deployment examples targeting Python 3.8 or Django 4.1 are stale for this version. If you are upgrading from `5.4.0`, re-check your runtime matrix, lock behavior, and serializer/compressor choices before rolling the config forward.\n\n## Official Sources Used\n\n- GitHub repository: https://github.com/jazzband/django-redis\n- Upstream README: https://raw.githubusercontent.com/jazzband/django-redis/master/README.rst\n- Upstream changelog: https://raw.githubusercontent.com/jazzband/django-redis/master/CHANGELOG.rst\n- PyPI package page for the version covered here: https://pypi.org/project/django-redis/6.0.0/\n"
  },
  {
    "path": "content/django/docs/rest-framework/python/DOC.md",
    "content": "---\nname: rest-framework\ndescription: \"djangorestframework package guide for Python projects using Django REST framework 3.16.1\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.16.1\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"django,drf,rest,api,python,web\"\n---\n\n# djangorestframework Python Package Guide\n\n## What This Package Is\n\n`djangorestframework` is the PyPI package for Django REST framework. Install it as `djangorestframework`, but import from `rest_framework` in code.\n\nThis guide covers package version `3.16.1`. The official docs site is a latest-docs site rather than a frozen versioned snapshot, so treat release notes and the 3.16 announcement as the source of truth for version-sensitive behavior.\n\n## Install And Compatibility Baseline\n\nPin the package when you need 3.16.1-specific behavior:\n\n```bash\npip install \"djangorestframework==3.16.1\"\n```\n\nFor a new project, install Django explicitly too:\n\n```bash\npip install \"django>=4.2\" \"djangorestframework==3.16.1\"\n```\n\nRelevant upstream compatibility facts for `3.16.1`:\n\n- PyPI declares `Requires: Python >=3.9`.\n- The official 3.16 announcement says the minimum supported versions are Django `4.2` and Python `3.9`.\n- DRF 3.16 adds support for Django `5.1`, the upcoming Django `5.2` LTS, and Python `3.13`.\n\nIf your project is on Django `<4.2` or Python `<3.9`, do not upgrade to `3.16.1` without first moving the runtime baseline.\n\nOptional packages from the official docs:\n\n```bash\npip install markdown django-filter pyyaml uritemplate\n```\n\nUse them only if you need browsable API Markdown rendering, filtering, or schema-generation extras.\n\n## Project Setup\n\nAdd DRF to `INSTALLED_APPS`:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework\",\n]\n```\n\nIf you want the browsable API login/logout views:\n\n```python\n# urls.py\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"api-auth/\", include(\"rest_framework.urls\", namespace=\"rest_framework\")),\n]\n```\n\nIf you want DRF's built-in token authentication, also add the token app and run migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework\",\n    \"rest_framework.authtoken\",\n]\n```\n\n```bash\npython manage.py migrate\n```\n\n## Minimal CRUD API\n\nFor standard model CRUD, the shortest reliable path is `ModelSerializer` plus `ModelViewSet` plus `DefaultRouter`.\n\n```python\n# models.py\nfrom django.db import models\n\nclass Widget(models.Model):\n    name = models.CharField(max_length=100, unique=True)\n    is_active = models.BooleanField(default=True)\n    created_at = models.DateTimeField(auto_now_add=True)\n```\n\n```python\n# serializers.py\nfrom rest_framework import serializers\n\nfrom .models import Widget\n\nclass WidgetSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = Widget\n        fields = [\"id\", \"name\", \"is_active\", \"created_at\"]\n        read_only_fields = [\"id\", \"created_at\"]\n```\n\n```python\n# views.py\nfrom rest_framework import permissions, viewsets\n\nfrom .models import Widget\nfrom .serializers import WidgetSerializer\n\nclass WidgetViewSet(viewsets.ModelViewSet):\n    queryset = Widget.objects.all().order_by(\"-created_at\")\n    serializer_class = WidgetSerializer\n    permission_classes = [permissions.IsAuthenticated]\n```\n\n```python\n# urls.py\nfrom django.urls import include, path\nfrom rest_framework.routers import DefaultRouter\n\nfrom .views import WidgetViewSet\n\nrouter = DefaultRouter()\nrouter.register(\"widgets\", WidgetViewSet, basename=\"widget\")\n\nurlpatterns = [\n    path(\"api/\", include(router.urls)),\n    path(\"api-auth/\", include(\"rest_framework.urls\", namespace=\"rest_framework\")),\n]\n```\n\nUse `APIView` or the generic class-based views when you need a custom request flow. Use `ModelViewSet` when the endpoint is mostly CRUD and you want routers, pagination hooks, and consistent action wiring.\n\n## Global DRF Configuration\n\nThe most important DRF defaults are not safe for a typical private API. Upstream defaults include:\n\n- authentication: `SessionAuthentication` and `BasicAuthentication`\n- permissions: `AllowAny`\n- pagination: off unless you set a pagination class and `PAGE_SIZE`\n- schema generation: `rest_framework.schemas.openapi.AutoSchema`\n\nSet project-wide defaults explicitly:\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": [\n        \"rest_framework.authentication.SessionAuthentication\",\n        \"rest_framework.authentication.TokenAuthentication\",\n    ],\n    \"DEFAULT_PERMISSION_CLASSES\": [\n        \"rest_framework.permissions.IsAuthenticated\",\n    ],\n    \"DEFAULT_PARSER_CLASSES\": [\n        \"rest_framework.parsers.JSONParser\",\n        \"rest_framework.parsers.FormParser\",\n        \"rest_framework.parsers.MultiPartParser\",\n    ],\n    \"DEFAULT_RENDERER_CLASSES\": [\n        \"rest_framework.renderers.JSONRenderer\",\n        \"rest_framework.renderers.BrowsableAPIRenderer\",\n    ],\n    \"DEFAULT_SCHEMA_CLASS\": \"rest_framework.schemas.openapi.AutoSchema\",\n    \"DEFAULT_PAGINATION_CLASS\": \"rest_framework.pagination.PageNumberPagination\",\n    \"PAGE_SIZE\": 50,\n}\n```\n\nIf you are building an API-only service, remove the browsable API renderer:\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_RENDERER_CLASSES\": [\n        \"rest_framework.renderers.JSONRenderer\",\n    ],\n}\n```\n\nIf you need query-parameter filtering, install `django-filter` and opt in explicitly:\n\n```python\n# settings.py\nINSTALLED_APPS += [\"django_filters\"]\n\nREST_FRAMEWORK = {\n    \"DEFAULT_FILTER_BACKENDS\": [\n        \"django_filters.rest_framework.DjangoFilterBackend\",\n    ],\n}\n```\n\n## Authentication Patterns\n\n### reviewuthentication\n\nUse this when DRF is part of a Django-rendered app or you want the browsable API to share Django sessions.\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": [\n        \"rest_framework.authentication.SessionAuthentication\",\n    ],\n    \"DEFAULT_PERMISSION_CLASSES\": [\n        \"rest_framework.permissions.IsAuthenticated\",\n    ],\n}\n```\n\nImportant behavior:\n\n- unsafe methods still require a valid CSRF token\n- failed permission checks may produce `403` instead of `401`\n- it fits browser-based flows better than machine-to-machine API clients\n\n### Token Authentication\n\nUse DRF's built-in token auth only for simple first-party clients.\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": [\n        \"rest_framework.authentication.TokenAuthentication\",\n    ],\n    \"DEFAULT_PERMISSION_CLASSES\": [\n        \"rest_framework.permissions.IsAuthenticated\",\n    ],\n}\n```\n\nExpose the built-in token endpoint:\n\n```python\n# urls.py\nfrom django.urls import path\nfrom rest_framework.authtoken.views import obtain_auth_token\n\nurlpatterns = [\n    path(\"api/token/\", obtain_auth_token),\n]\n```\n\nClients send:\n\n```http\nAuthorization: Token <token-value>\n```\n\nQuick smoke test:\n\n```bash\ncurl http://127.0.0.1:8000/api/widgets/ \\\n  -H \"Authorization: Token <token-value>\"\n```\n\nBuilt-in token auth is intentionally minimal. If you need multiple tokens per user, rotation, or expiry, use a dedicated auth package instead of stretching `rest_framework.authtoken`.\n\n### Per-View Overrides\n\nOverride auth and permissions when one endpoint differs from the project default:\n\n```python\nfrom rest_framework.authentication import TokenAuthentication\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass MeView(APIView):\n    authentication_classes = [TokenAuthentication]\n    permission_classes = [IsAuthenticated]\n\n    def get(self, request):\n        return Response({\"username\": request.user.username})\n```\n\nWhen you set `authentication_classes` or `permission_classes` on the view, that view stops using the corresponding global default list.\n\n## Core Usage Decisions\n\n### Serializer Choice\n\n- Use `ModelSerializer` for normal Django model CRUD.\n- Use plain `Serializer` for non-model payloads, composite responses, or request validation that is not backed directly by a model.\n- Use `HyperlinkedModelSerializer` only when you explicitly want hyperlink fields in the output.\n\nIf you instantiate a `HyperlinkedModelSerializer` manually, pass request context so URL fields can render correctly:\n\n```python\nserializer = WidgetHyperlinkedSerializer(\n    widget,\n    context={\"request\": request},\n)\n```\n\n### ViewSet And Router Choice\n\n- Use `DefaultRouter` for standard CRUD APIs and `@action` routes.\n- Use `GenericAPIView` plus mixins when you want only part of CRUD.\n- Use `APIView` when you need full control over the request/response flow.\n\nDo not wire `@action` methods via `.as_view()` manually. Let a router register the viewset so action-specific settings such as `permission_classes` are honored.\n\n### Pagination\n\nPagination is not automatic everywhere. DRF only auto-paginates generic views and viewsets. If you write a plain `APIView`, you must call the pagination API yourself or you will return an unpaginated response.\n\nThe common baseline is page-number pagination:\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_PAGINATION_CLASS\": \"rest_framework.pagination.PageNumberPagination\",\n    \"PAGE_SIZE\": 50,\n}\n```\n\n## Common Pitfalls\n\n- The package name is `djangorestframework`, but imports come from `rest_framework`.\n- Authentication and authorization are separate. DRF defaults to `AllowAny` unless you set permissions explicitly.\n- `BasicAuthentication` is fine for testing, not a good default for production clients.\n- `SessionAuthentication` on unsafe methods requires CSRF protection even if the user is logged in.\n- DRF views opt out of Django 5.1+ `LoginRequiredMiddleware`; enforce login with DRF auth and permission settings instead.\n- `DjangoModelPermissions` requires a queryset or `get_queryset()` because DRF infers the model from it.\n- `AllowAny` and an empty permission list are effectively open access. Use `AllowAny` only when you want that openness to be explicit.\n\n## Version-Sensitive Notes For 3.16.x\n\nOfficial upstream notes to keep in mind for `3.16.1`:\n\n- `3.16.0` was released on March 28, 2025 and raised the minimum supported versions to Django `4.2` and Python `3.9`.\n- `3.16.0` added support for Django `5.1`, the upcoming Django `5.2` LTS, and Python `3.13`.\n- `3.16.0` improved generated validator support for `UniqueConstraint`, especially for nullable fields and conditional constraints.\n- `3.16.1` was released on August 6, 2025 and is a bugfix release, not a new feature line.\n- `3.16.1` fixed regressions around `unique_together` validation with `SerializerMethodField` and `UniqueTogetherValidator` handling of fields with `source`.\n\nPractical implication:\n\n- if you upgrade from `3.15.x`, re-test serializer validation on models that use `UniqueConstraint`, `unique_together`, nullable unique fields, or serializer fields with `source=...`\n- if you copied compatibility assumptions from older guides, update them to the `Django >=4.2`, `Python >=3.9` baseline before debugging downstream failures\n- if you are reading the current docs home page, remember that it lists actively supported series and may be stricter than the exact `3.16.1` PyPI requirement\n\n## Official Source URLs\n\n- Docs root: https://www.django-rest-framework.org/\n- Quickstart: https://www.django-rest-framework.org/tutorial/quickstart/\n- Settings: https://www.django-rest-framework.org/api-guide/settings/\n- Authentication: https://www.django-rest-framework.org/api-guide/authentication/\n- Permissions: https://www.django-rest-framework.org/api-guide/permissions/\n- Pagination: https://www.django-rest-framework.org/api-guide/pagination/\n- 3.16 announcement: https://www.django-rest-framework.org/community/3.16-announcement/\n- Release notes: https://www.django-rest-framework.org/community/release-notes/\n- PyPI package page: https://pypi.org/project/djangorestframework/3.16.1/\n"
  },
  {
    "path": "content/django/docs/rest-framework-simplejwt/python/DOC.md",
    "content": "---\nname: rest-framework-simplejwt\ndescription: \"Simple JWT for Django REST Framework in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.5.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-rest-framework,jwt,authentication,tokens\"\n---\n\n# Django REST Framework Simple JWT for Python\n\n`djangorestframework-simplejwt` adds JWT authentication views, token classes, and DRF authentication backends. Use it when your Django app issues bearer tokens and your DRF API needs short-lived access tokens plus refresh-token flows.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"djangorestframework-simplejwt==5.5.1\"\n```\n\nIf you will sign or verify tokens with RSA or ECDSA algorithms, install the crypto extra:\n\n```bash\npython -m pip install \"djangorestframework-simplejwt[crypto]==5.5.1\"\n```\n\nDo not add `rest_framework_simplejwt` to `INSTALLED_APPS` for normal auth wiring. The maintainer docs only call that out for translations. The blacklist feature is separate and uses `rest_framework_simplejwt.token_blacklist`.\n\n## Minimal Setup\n\nConfigure DRF to use JWT auth in `settings.py`:\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"rest_framework_simplejwt.authentication.JWTAuthentication\",\n    ),\n}\n```\n\nExpose token endpoints in `urls.py`:\n\n```python\nfrom django.urls import path\nfrom rest_framework_simplejwt.views import (\n    TokenObtainPairView,\n    TokenRefreshView,\n    TokenVerifyView,\n)\n\nurlpatterns = [\n    path(\"api/token/\", TokenObtainPairView.as_view(), name=\"token_obtain_pair\"),\n    path(\"api/token/refresh/\", TokenRefreshView.as_view(), name=\"token_refresh\"),\n    path(\"api/token/verify/\", TokenVerifyView.as_view(), name=\"token_verify\"),\n]\n```\n\nProtect DRF views with normal DRF permissions:\n\n```python\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass MeView(APIView):\n    permission_classes = [IsAuthenticated]\n\n    def get(self, request):\n        return Response({\"user_id\": request.user.pk})\n```\n\nTypical client flow:\n\n1. `POST /api/token/` with username and password to get `access` and `refresh`.\n2. Send `Authorization: Bearer <access-token>` to protected views.\n3. `POST /api/token/refresh/` with the refresh token when the access token expires.\n4. Optionally `POST /api/token/verify/` when clients need a validity check for HMAC-signed tokens.\n\n`TokenVerifyView` only answers whether a token is valid. It is not an authorization decision point.\n\n## Core `SIMPLE_JWT` Settings\n\nThe stable `5.5.1` docs show these defaults:\n\n```python\nfrom datetime import timedelta\nfrom django.conf import settings\n\nSIMPLE_JWT = {\n    \"ACCESS_TOKEN_LIFETIME\": timedelta(minutes=5),\n    \"REFRESH_TOKEN_LIFETIME\": timedelta(days=1),\n    \"ROTATE_REFRESH_TOKENS\": False,\n    \"BLACKLIST_AFTER_ROTATION\": False,\n    \"UPDATE_LAST_LOGIN\": False,\n    \"ALGORITHM\": \"HS256\",\n    \"SIGNING_KEY\": settings.SECRET_KEY,\n    \"VERIFYING_KEY\": \"\",\n    \"AUDIENCE\": None,\n    \"ISSUER\": None,\n    \"JSON_ENCODER\": None,\n    \"JWK_URL\": None,\n    \"LEEWAY\": 0,\n    \"AUTH_HEADER_TYPES\": (\"Bearer\",),\n    \"AUTH_HEADER_NAME\": \"HTTP_AUTHORIZATION\",\n    \"USER_ID_FIELD\": \"id\",\n    \"USER_ID_CLAIM\": \"user_id\",\n    \"AUTH_TOKEN_CLASSES\": (\"rest_framework_simplejwt.tokens.AccessToken\",),\n}\n```\n\nPractical guidance:\n\n- Keep access tokens short-lived. The default `5` minutes is a reasonable starting point.\n- Pair `ROTATE_REFRESH_TOKENS` with `BLACKLIST_AFTER_ROTATION` only when the blacklist app is installed and migrated.\n- Leave `UPDATE_LAST_LOGIN` off unless you explicitly need it. The maintainer docs warn that enabling it substantially increases database writes and should be paired with DRF throttling on login endpoints.\n- If you use HMAC signing, prefer a dedicated JWT signing key instead of reusing Django `SECRET_KEY`.\n- If other services validate your tokens, set `ISSUER`, `AUDIENCE`, `ALGORITHM`, and verifying material consistently across those services.\n- `AUTH_HEADER_TYPES` and `AUTH_HEADER_NAME` must match whatever your gateway or client actually sends.\n- `USER_ID_FIELD` should be stable over time. Avoid fields like username or email if those values can change.\n\n## Login, Refresh, And Auth Headers\n\nRequest a token pair:\n\n```bash\ncurl -X POST http://localhost:8000/api/token/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"alice\",\"password\":\"password\"}'\n```\n\nExample response:\n\n```json\n{\n  \"refresh\": \"<refresh-token>\",\n  \"access\": \"<access-token>\"\n}\n```\n\nUse the access token on protected requests:\n\n```bash\ncurl http://localhost:8000/api/me/ \\\n  -H \"Authorization: Bearer <access-token>\"\n```\n\nRefresh it:\n\n```bash\ncurl -X POST http://localhost:8000/api/token/refresh/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"refresh\":\"<refresh-token>\"}'\n```\n\n## Logout And Revocation\n\nIf you need server-side revocation for refresh or sliding tokens, enable the blacklist app:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework_simplejwt.token_blacklist\",\n]\n```\n\nThen run migrations:\n\n```bash\npython manage.py migrate\n```\n\nOptionally expose the blacklist endpoint:\n\n```python\nfrom django.urls import path\nfrom rest_framework_simplejwt.views import TokenBlacklistView\n\nurlpatterns = [\n    path(\"api/token/blacklist/\", TokenBlacklistView.as_view(), name=\"token_blacklist\"),\n]\n```\n\nYou can also blacklist a refresh token directly:\n\n```python\nfrom rest_framework_simplejwt.tokens import RefreshToken\n\ndef revoke_refresh_token(token_string: str) -> None:\n    token = RefreshToken(token_string)\n    token.blacklist()\n```\n\nOperational note: the blacklist app stores `OutstandingToken` and `BlacklistedToken` rows. Run `python manage.py flushexpiredtokens` on a schedule, typically daily, to remove expired entries.\n\n## Custom Claims\n\nCustomize claims by subclassing the serializer used by the obtain-token view:\n\n```python\nfrom rest_framework_simplejwt.serializers import TokenObtainPairSerializer\nfrom rest_framework_simplejwt.views import TokenObtainPairView\n\nclass MyTokenObtainPairSerializer(TokenObtainPairSerializer):\n    @classmethod\n    def get_token(cls, user):\n        token = super().get_token(user)\n        token[\"tenant_id\"] = str(user.tenant_id)\n        token[\"is_staff\"] = user.is_staff\n        return token\n\nclass MyTokenObtainPairView(TokenObtainPairView):\n    serializer_class = MyTokenObtainPairSerializer\n```\n\nIf you want the built-in view wiring to use your serializer by default:\n\n```python\nSIMPLE_JWT = {\n    \"TOKEN_OBTAIN_SERIALIZER\": \"my_app.serializers.MyTokenObtainPairSerializer\",\n}\n```\n\nImportant behavior: changes made in `get_token()` affect both refresh and access tokens because the access token is derived from the refresh token.\n\n## Creating Tokens Manually\n\nFor service-side issuance, use `RefreshToken.for_user(user)`:\n\n```python\nfrom rest_framework_simplejwt.exceptions import AuthenticationFailed\nfrom rest_framework_simplejwt.tokens import RefreshToken\n\ndef issue_tokens_for_user(user):\n    if not user.is_active:\n        raise AuthenticationFailed(\"User is not active\")\n\n    refresh = RefreshToken.for_user(user)\n    return {\n        \"refresh\": str(refresh),\n        \"access\": str(refresh.access_token),\n    }\n```\n\nDo not skip the `is_active` check. The maintainer docs explicitly warn that `for_user()` does not validate it for you.\n\n## Token Types\n\nSimple JWT supports these token families:\n\n- Access tokens: the default for request authentication.\n- Refresh tokens: used to mint new access tokens, not to authenticate protected views.\n- Sliding tokens: combined auth-plus-refresh tokens with a separate refresh expiration claim.\n\nIf you want sliding tokens, include `SlidingToken` in `AUTH_TOKEN_CLASSES` and use the sliding views:\n\n```python\nfrom django.urls import path\nfrom rest_framework_simplejwt.views import (\n    TokenObtainSlidingView,\n    TokenRefreshSlidingView,\n)\n\nurlpatterns = [\n    path(\"api/token/\", TokenObtainSlidingView.as_view(), name=\"token_obtain\"),\n    path(\"api/token/refresh/\", TokenRefreshSlidingView.as_view(), name=\"token_refresh\"),\n]\n```\n\nSliding tokens are more convenient for clients, but the docs call them less secure and, when the blacklist app is enabled, less performant because each authenticated request checks the blacklist.\n\n## Stateless User Authentication\n\nIf your stack needs token-backed SSO behavior across multiple Django services without a database lookup on every request, use `JWTStatelessUserAuthentication`:\n\n```python\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"rest_framework_simplejwt.authentication.JWTStatelessUserAuthentication\",\n    ),\n}\n```\n\nThis returns a `TokenUser` backed by the validated token rather than a database-loaded user object. In `5.1.0`, `JWTTokenUserAuthentication` was renamed to `JWTStatelessUserAuthentication`, but both names remain supported for backward compatibility.\n\n## Version-Sensitive Notes\n\n- An older docs link pointed to `/en/latest/`, but `/en/stable/` is the safer canonical docs root for package-specific `5.5.1` guidance.\n- PyPI `5.5.1` is still the latest release as of March 12, 2026.\n- The `5.5.1` changelog notes a previously missing `0013_blacklist` migration for `rest_framework_simplejwt.token_blacklist`. If you generated your own `0013_blacklist` migration from the old master branch state, read the maintainer changelog before upgrading.\n- The stable docs still describe Django support through `5.1`, while the PyPI classifiers already include `5.2`. Prefer the docs for behavior and migration guidance until the package docs catch up.\n\n## Common Pitfalls\n\n- Installing the package without adding `JWTAuthentication` or `JWTStatelessUserAuthentication` to DRF auth classes.\n- Sending refresh tokens to protected endpoints instead of access tokens.\n- Enabling blacklist-related settings without installing `rest_framework_simplejwt.token_blacklist` and running migrations.\n- Treating `TokenVerifyView` as an authorization check.\n- Using asymmetric algorithms without installing the `crypto` extra.\n- Enabling `UPDATE_LAST_LOGIN` on a public login endpoint without DRF throttling.\n- Assuming `RefreshToken.for_user()` blocks inactive users.\n"
  },
  {
    "path": "content/django/docs/rest-framework-spectacular/python/DOC.md",
    "content": "---\nname: rest-framework-spectacular\ndescription: \"drf-spectacular OpenAPI schema generation for Django REST Framework in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-rest-framework,openapi,swagger,redoc,schema\"\n---\n\n# drf-spectacular Python Package Guide\n\n`drf-spectacular` generates OpenAPI 3 schemas for Django REST Framework and includes schema, Swagger UI, and Redoc views. Use it when you need DRF schemas that are explicit enough for generated clients, API docs, contract review, or downstream tooling.\n\n## Package Snapshot\n\n- Package: `drf-spectacular`\n- Main import paths: `drf_spectacular.openapi`, `drf_spectacular.views`, `drf_spectacular.utils`, `drf_spectacular.extensions`\n- Version covered: `0.29.0`\n- Docs root: `https://drf-spectacular.readthedocs.io/en/latest/`\n- Registry URL: `https://pypi.org/project/drf-spectacular/`\n\nVersion-sensitive note:\n\n- The published docs still describe Python `>=3.7`, but the `0.29.0` changelog drops Python `3.7` from the test suite and calls out unresolved pydantic issues on `<=3.8`.\n- Treat Python `3.9+` as the practical floor for new work unless your project already proves an older matrix.\n\n## Install\n\nInstall the package into a Django project that already uses Django REST Framework:\n\n```bash\npython -m pip install \"drf-spectacular==0.29.0\"\n```\n\nIf you want Swagger UI and Redoc assets served locally instead of loading from a CDN, install the sidecar extra:\n\n```bash\npython -m pip install \"drf-spectacular[sidecar]==0.29.0\"\n```\n\nTypical companion packages:\n\n```bash\npython -m pip install django djangorestframework\n```\n\n## Minimal Django And DRF Setup\n\nAdd `drf_spectacular` to `INSTALLED_APPS`, point DRF at `AutoSchema`, and define basic schema metadata:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework\",\n    \"drf_spectacular\",\n]\n\nREST_FRAMEWORK = {\n    \"DEFAULT_SCHEMA_CLASS\": \"drf_spectacular.openapi.AutoSchema\",\n}\n\nSPECTACULAR_SETTINGS = {\n    \"TITLE\": \"My API\",\n    \"DESCRIPTION\": \"Internal API for my service\",\n    \"VERSION\": \"1.0.0\",\n}\n```\n\nExpose the schema and documentation views:\n\n```python\n# urls.py\nfrom django.urls import path\nfrom drf_spectacular.views import (\n    SpectacularAPIView,\n    SpectacularRedocView,\n    SpectacularSwaggerView,\n)\n\nurlpatterns = [\n    path(\"api/schema/\", SpectacularAPIView.as_view(), name=\"schema\"),\n    path(\n        \"api/schema/swagger-ui/\",\n        SpectacularSwaggerView.as_view(url_name=\"schema\"),\n        name=\"swagger-ui\",\n    ),\n    path(\n        \"api/schema/redoc/\",\n        SpectacularRedocView.as_view(url_name=\"schema\"),\n        name=\"redoc\",\n    ),\n]\n```\n\nGenerate and validate the schema from the command line before wiring docs into CI or client generation:\n\n```bash\npython manage.py spectacular --color --file schema.yaml --validate\n```\n\nUpstream guidance: warnings are signals that your schema needs overrides. Some warnings are harmless fallbacks, but do not ignore them blindly.\n\n## Core Workflow\n\nThe generator works best when DRF views expose real serializer and queryset information.\n\n### Start with explicit view metadata\n\nEven on `APIView`, set `serializer_class` and `queryset` when you can. `drf-spectacular` uses them even in places where plain DRF does not.\n\n```python\nfrom myapp.models import Widget\nfrom rest_framework import serializers, viewsets\n\nclass WidgetSerializer(serializers.Serializer):\n    id = serializers.IntegerField()\n    name = serializers.CharField()\n\nclass WidgetViewSet(viewsets.ReadOnlyModelViewSet):\n    queryset = Widget.objects.all()\n    serializer_class = WidgetSerializer\n```\n\n### Refine operations with `@extend_schema`\n\nUse `@extend_schema` for request bodies, query parameters, examples, and response overrides.\n\n```python\nfrom drf_spectacular.utils import OpenApiParameter, extend_schema\nfrom rest_framework.response import Response\nfrom rest_framework.viewsets import ViewSet\n\nclass SearchViewSet(ViewSet):\n    @extend_schema(\n        parameters=[\n            OpenApiParameter(\"q\", str, OpenApiParameter.QUERY, required=True),\n        ],\n        responses={200: WidgetSerializer(many=True)},\n    )\n    def list(self, request):\n        return Response([])\n```\n\nUse `@extend_schema_view` when you need to annotate inherited mixin methods you are not redefining yourself.\n\n### Refine custom fields and serializers\n\nUse `@extend_schema_field` when a custom field or `SerializerMethodField` would otherwise resolve to the wrong type. Use `@extend_schema_serializer` to exclude fields, attach examples, or override `many`.\n\n```python\nfrom drf_spectacular.utils import extend_schema_field, extend_schema_serializer\nfrom rest_framework import serializers\n\n@extend_schema_serializer(exclude_fields=(\"internal_token\",))\nclass WidgetSerializer(serializers.Serializer):\n    name = serializers.CharField()\n    internal_token = serializers.CharField()\n    computed = serializers.SerializerMethodField()\n\n    @extend_schema_field(str)\n    def get_computed(self, obj):\n        return \"value\"\n```\n\n### Use extensions for third-party code you cannot decorate\n\nWhen a library supplies authentication classes, fields, serializers, filters, or views that you cannot edit directly, register an extension instead of patching generated schema output by hand.\n\nAuthentication example:\n\n```python\n# myapp/schema.py\nfrom drf_spectacular.extensions import OpenApiAuthenticationExtension\n\nclass ApiKeyAuthenticationScheme(OpenApiAuthenticationExtension):\n    target_class = \"myapp.auth.ApiKeyAuthentication\"\n    name = \"ApiKeyAuth\"\n\n    def get_security_definition(self, auto_schema):\n        return {\n            \"type\": \"apiKey\",\n            \"in\": \"header\",\n            \"name\": \"X-API-Key\",\n        }\n```\n\nImport the module from `apps.py.ready()` so the extension registers exactly once during Django startup:\n\n```python\n# myapp/apps.py\nfrom django.apps import AppConfig\n\nclass MyAppConfig(AppConfig):\n    name = \"myapp\"\n\n    def ready(self):\n        import myapp.schema  # noqa: F401\n```\n\n## Schema Serving, Auth, And Settings That Matter First\n\nStart with a small `SPECTACULAR_SETTINGS` surface and only add overrides when the schema or docs UI needs them.\n\n```python\nSPECTACULAR_SETTINGS = {\n    \"TITLE\": \"My API\",\n    \"DESCRIPTION\": \"Internal API\",\n    \"VERSION\": \"1.0.0\",\n    \"SERVE_INCLUDE_SCHEMA\": False,\n    \"SERVE_PUBLIC\": False,\n    \"SERVE_PERMISSIONS\": [\"rest_framework.permissions.IsAdminUser\"],\n    \"SERVE_AUTHENTICATION\": [\n        \"rest_framework.authentication.SessionAuthentication\",\n    ],\n}\n```\n\nPractical guidance:\n\n- `SERVE_INCLUDE_SCHEMA = False` keeps the schema endpoint from listing itself in the schema.\n- `SERVE_PUBLIC = False` makes schema generation for served docs respect the requesting user.\n- `SERVE_PERMISSIONS` and `SERVE_AUTHENTICATION` control access to the schema views themselves. Use them when docs must be private.\n- `AUTHENTICATION_WHITELIST` limits which authentication classes appear in the schema. Leave it `None` to show all discovered auth schemes.\n- `OAS_VERSION` defaults to OpenAPI `3.0.3`. Only move to `3.1.0` if downstream tooling actually expects it.\n- `SCHEMA_PATH_PREFIX` and related trimming/insertion settings help when your deployed API path differs from router paths, for example behind a reverse proxy or shared `/api/v1` prefix.\n- `COMPONENT_SPLIT_REQUEST = True` is often worth enabling when request and response shapes differ, especially for upload endpoints and `FileField` handling.\n- `ENABLE_DJANGO_DEPLOY_CHECK` is enabled by default and runs schema checks during Django's deploy checks. Keep it on unless you have a deliberate reason to suppress it.\n\nAvoid relying on the global `SECURITY` setting for new work. Upstream marks it as strongly discouraged except for rare cases. For auth schemes, prefer `OpenApiAuthenticationExtension` or targeted auth whitelisting.\n\n## Versioning And Multiple API Variants\n\nIf your DRF project uses versioning, the default schema view only includes unversioned endpoints plus endpoints for the requested API version.\n\nFor CLI generation:\n\n```bash\npython manage.py spectacular --api-version v1 --file schema-v1.yaml\n```\n\nFor a served schema view:\n\n```python\npath(\n    \"api/schema/v1/\",\n    SpectacularAPIView.as_view(api_version=\"v1\"),\n    name=\"schema-v1\",\n)\n```\n\nIf endpoints seem to disappear from the schema, check DRF versioning before assuming the generator is broken.\n\n## Common Pitfalls\n\n### Empty or incomplete schema\n\nUsually caused by one of these:\n\n- `REST_FRAMEWORK[\"DEFAULT_SCHEMA_CLASS\"]` still points somewhere else.\n- Views do not expose a serializer or queryset.\n- Endpoints are hidden behind DRF versioning and no version was requested.\n- The schema view is filtered by request user because `SERVE_PUBLIC` is `False`.\n\n### Duplicate operations from `{format}` suffix routes\n\nIf your project uses `format_suffix_patterns`, the FAQ recommends the built-in preprocessing hook:\n\n```python\nSPECTACULAR_SETTINGS = {\n    \"PREPROCESSING_HOOKS\": [\n        \"drf_spectacular.hooks.preprocess_exclude_path_format\",\n    ],\n}\n```\n\n### `FileField` or upload endpoints look wrong\n\n`FileField` cannot be represented perfectly as one shared component because request and response forms differ. Upstream recommends:\n\n- enable `COMPONENT_SPLIT_REQUEST = True`\n- use `MultiPartParser` or another parser that matches the upload endpoint\n\n### Unsupported authentication class\n\nIf your schema does not show a custom auth mechanism correctly, do not hard-code OpenAPI fragments into every view. Add an `OpenApiAuthenticationExtension` for the authentication class instead.\n\n### Blank Swagger UI or Redoc under Content Security Policy\n\nIf the docs page renders blank under CSP:\n\n- use the `sidecar` extra to self-host assets\n- update CSP to allow the required scripts, styles, fonts, and worker sources for the UI you serve\n- if you use `SpectacularSwaggerSplitView`, validate it carefully behind path-rewriting proxies because the split request can break in that setup\n\n### Enum naming warnings\n\nPostprocessing tries to create stable enum component names, but warnings can still appear when names collide or differ only by suffix. Use `ENUM_NAME_OVERRIDES` if generated enum names must stay stable across schema revisions.\n\n## Practical Pattern For Agent Work\n\nWhen you need a reliable schema fast:\n\n1. Configure `DEFAULT_SCHEMA_CLASS` and a minimal `SPECTACULAR_SETTINGS`.\n2. Run `python manage.py spectacular --validate`.\n3. Fix missing serializer/queryset metadata on views.\n4. Add `@extend_schema` only where auto-discovery is insufficient.\n5. Add extensions for third-party code or custom auth.\n6. Re-run validation before using the schema for client generation or publishing docs.\n\nThis order matches upstream guidance and prevents premature schema hand-editing.\n\n## Official Sources\n\n- Docs root: `https://drf-spectacular.readthedocs.io/en/latest/`\n- Package overview and install: `https://drf-spectacular.readthedocs.io/en/latest/readme.html`\n- Customization workflow: `https://drf-spectacular.readthedocs.io/en/latest/customization.html`\n- Settings reference: `https://drf-spectacular.readthedocs.io/en/latest/settings.html`\n- FAQ: `https://drf-spectacular.readthedocs.io/en/latest/faq.html`\n- Changelog: `https://drf-spectacular.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/drf-spectacular/`\n"
  },
  {
    "path": "content/django/docs/rest-framework-yasg/python/DOC.md",
    "content": "---\nname: rest-framework-yasg\ndescription: \"drf-yasg package guide for Python - Swagger/OpenAPI 2.0 schema generation for Django REST Framework\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.21.15\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"drf-yasg,django,django-rest-framework,swagger,openapi,schema\"\n---\n\n# drf-yasg Python Package Guide\n\n## Golden Rule\n\n`drf-yasg` is a Django REST Framework schema generator for **Swagger 2.0 / OpenAPI 2.0**.\n\nUse it when a project already depends on `drf-yasg` or when you specifically need Swagger 2.0 output plus its bundled Swagger UI and ReDoc views. Do not treat it as an OpenAPI 3 generator.\n\n## Version-Sensitive Notes\n\n- PyPI shows `1.21.15` released on `2026-02-24`.\n- PyPI metadata for `1.21.15` declares support for Python `>=3.9` and classifiers through Python `3.13`, Django `4.0` through `5.2`, and Django REST Framework `3.13` through `3.16`.\n- The Read the Docs site is behind the package release line:\n  - `/en/stable/` renders documentation for `1.21.7`\n  - `/en/latest/` renders `1.20.4.dev2+g...`\n- Practical setup and decorator usage from the docs still matches the `1.21.x` line, but compatibility claims should come from PyPI for `1.21.15`, not from the docs site banners.\n- The package description on PyPI still documents a few constraints that matter in current versions:\n  - only `URLPathVersioning` and `NamespaceVersioning` are supported for generated versioned endpoints\n  - codec support depends on `coreapi`\n\n## Install\n\nPin the version when you need behavior that matches this doc:\n\n```bash\npip install drf-yasg==1.21.15\n```\n\nOptional extras from PyPI:\n\n```bash\npip install \"drf-yasg[validation]==1.21.15\"\n```\n\nTypical project dependencies:\n\n- `Django`\n- `djangorestframework`\n- `drf-yasg`\n\n## Minimal Setup\n\nAdd `drf_yasg` and DRF to `INSTALLED_APPS`:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"rest_framework\",\n    \"drf_yasg\",\n]\n```\n\nDefine a schema view and expose raw schema plus UI routes:\n\n```python\n# urls.py\nfrom django.urls import path, re_path\nfrom rest_framework import permissions\nfrom drf_yasg import openapi\nfrom drf_yasg.views import get_schema_view\n\nschema_view = get_schema_view(\n    openapi.Info(\n        title=\"My API\",\n        default_version=\"v1\",\n        description=\"Internal API documentation\",\n    ),\n    public=True,\n    permission_classes=(permissions.AllowAny,),\n)\n\nurlpatterns = [\n    re_path(\n        r\"^swagger(?P<format>\\.json|\\.yaml)$\",\n        schema_view.without_ui(cache_timeout=0),\n        name=\"schema-json\",\n    ),\n    path(\n        \"swagger/\",\n        schema_view.with_ui(\"swagger\", cache_timeout=0),\n        name=\"schema-swagger-ui\",\n    ),\n    path(\n        \"redoc/\",\n        schema_view.with_ui(\"redoc\", cache_timeout=0),\n        name=\"schema-redoc\",\n    ),\n]\n```\n\nThis gives you:\n\n- `/swagger.json` or `/swagger.yaml` for machine-readable schema output\n- `/swagger/` for Swagger UI\n- `/redoc/` for ReDoc\n\n## Core Usage\n\n### Override schema generation for one operation\n\nUse `@swagger_auto_schema` when DRF inference is incomplete:\n\n```python\nfrom drf_yasg import openapi\nfrom drf_yasg.utils import swagger_auto_schema\nfrom rest_framework import serializers, viewsets\nfrom rest_framework.response import Response\n\nclass UserSerializer(serializers.Serializer):\n    id = serializers.IntegerField()\n    email = serializers.EmailField()\n\nclass UserViewSet(viewsets.ViewSet):\n    @swagger_auto_schema(\n        operation_summary=\"List users\",\n        manual_parameters=[\n            openapi.Parameter(\n                \"email\",\n                openapi.IN_QUERY,\n                description=\"Filter by exact email\",\n                type=openapi.TYPE_STRING,\n            ),\n        ],\n        responses={200: UserSerializer(many=True)},\n    )\n    def list(self, request):\n        return Response([{\"id\": 1, \"email\": \"dev@example.com\"}])\n```\n\nUse this decorator for:\n\n- custom query parameters\n- explicit request bodies\n- non-default response shapes\n- better operation summaries and descriptions\n\n### Use serializer-backed query parameters\n\nWhen query params match a serializer, prefer `query_serializer=`:\n\n```python\nfrom drf_yasg.utils import swagger_auto_schema\nfrom rest_framework import serializers\n\nclass UserFilterSerializer(serializers.Serializer):\n    email = serializers.EmailField(required=False)\n    is_active = serializers.BooleanField(required=False)\n\n@swagger_auto_schema(query_serializer=UserFilterSerializer)\ndef list(self, request, *args, **kwargs):\n    ...\n```\n\n### Hide views or methods\n\nHide an entire view:\n\n```python\nclass InternalView(APIView):\n    swagger_schema = None\n```\n\nHide one method only:\n\n```python\n@swagger_auto_schema(auto_schema=None)\ndef delete(self, request, *args, **kwargs):\n    ...\n```\n\n### Document computed serializer fields\n\nUse `swagger_serializer_method` for `SerializerMethodField` values that DRF cannot infer correctly:\n\n```python\nfrom drf_yasg.utils import swagger_serializer_method\nfrom rest_framework import serializers\n\nclass ReportSerializer(serializers.Serializer):\n    total = serializers.SerializerMethodField()\n\n    @swagger_serializer_method(serializer_or_field=serializers.IntegerField())\n    def get_total(self, obj):\n        return obj.total\n```\n\n### Generate a static schema in CI or release jobs\n\nSet `DEFAULT_INFO` when using the management command:\n\n```python\n# urls.py\nfrom drf_yasg import openapi\n\napi_info = openapi.Info(\n    title=\"My API\",\n    default_version=\"v1\",\n)\n\nSWAGGER_SETTINGS = {\n    \"DEFAULT_INFO\": \"myproject.urls.api_info\",\n}\n```\n\n```bash\npython manage.py generate_swagger /tmp/swagger.json\n```\n\nUse this when you want to publish a checked-in schema artifact or validate schema generation in CI.\n\n## Config And Auth\n\n`drf-yasg` uses `SWAGGER_SETTINGS` for schema generation and UI behavior:\n\n```python\n# settings.py\nSWAGGER_SETTINGS = {\n    \"USE_SESSION_AUTH\": False,\n    \"SECURITY_DEFINITIONS\": {\n        \"Bearer\": {\n            \"type\": \"apiKey\",\n            \"name\": \"Authorization\",\n            \"in\": \"header\",\n            \"description\": \"Format: Bearer <token>\",\n        },\n    },\n    \"SECURITY_REQUIREMENTS\": [{\"Bearer\": []}],\n    \"PERSIST_AUTH\": False,\n    \"REFETCH_SCHEMA_WITH_AUTH\": False,\n    \"REFETCH_SCHEMA_ON_LOGOUT\": False,\n}\n```\n\nPractical guidance:\n\n- `USE_SESSION_AUTH`: set this to `False` for token-only APIs so Swagger UI does not render Django login/logout controls.\n- `SECURITY_DEFINITIONS`: define auth mechanisms once so operations inherit them.\n- `SECURITY_REQUIREMENTS`: apply auth globally unless a view overrides it.\n- `PERSIST_AUTH`: leave this `False` unless you intentionally want tokens stored in browser local storage.\n- `REFETCH_SCHEMA_WITH_AUTH`: enable only if schema visibility actually changes by user or token.\n\nIf you need stricter validation of generated schemas in development or CI, install the `validation` extra and use the packaged validators documented upstream.\n\n## Common Pitfalls\n\n- `drf-yasg` generates Swagger 2.0, not OpenAPI 3. Features that assume OpenAPI 3 should be modeled elsewhere.\n- Package name and import path differ: install `drf-yasg`, import `drf_yasg`.\n- Keep `django.contrib.staticfiles` enabled or the bundled UI assets will not render in standard Django deployments.\n- If you decorate multi-method actions, you often need method-specific `swagger_auto_schema` decoration instead of one shared decorator.\n- The docs site is stale relative to `1.21.15`. Treat compatibility matrices and current supported versions on PyPI as authoritative for this package version.\n- If your project uses DRF versioning, only `URLPathVersioning` and `NamespaceVersioning` are documented as supported by `drf-yasg`.\n- When schema output differs by request user, host, or URL configuration, avoid caching assumptions copied from examples; verify your actual schema view settings and deployment path.\n\n## Official Source URLs Used For This Doc\n\n- Docs landing page: `https://drf-yasg.readthedocs.io/en/latest/`\n- Stable docs readme/setup: `https://drf-yasg.readthedocs.io/en/stable/readme.html`\n- Custom schema generation: `https://drf-yasg.readthedocs.io/en/latest/custom_spec.html`\n- Settings reference: `https://drf-yasg.readthedocs.io/en/latest/settings.html`\n- Security/auth guidance: `https://drf-yasg.readthedocs.io/en/latest/security.html`\n- Rendering and management command reference: `https://drf-yasg.readthedocs.io/en/latest/rendering.html`\n- PyPI project page and metadata: `https://pypi.org/project/drf-yasg/`\n- Repository: `https://github.com/axnsan12/drf-yasg`\n"
  },
  {
    "path": "content/django/docs/rest-knox/python/DOC.md",
    "content": "---\nname: rest-knox\ndescription: \"django-rest-knox package guide for token authentication in Django REST Framework projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.4\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,drf,authentication,token,api,security,knox\"\n---\n\n# django-rest-knox Python Package Guide\n\n## What This Package Does\n\n`django-rest-knox` adds expiring, server-managed authentication tokens to Django REST Framework.\n\n- PyPI package: `django-rest-knox`\n- Django app and import namespace: `knox`\n- Version covered here: `5.0.4`\n- Docs URL for this session: `https://github.com/jazzband/django-rest-knox`\n- Canonical docs root used for setup details: `https://jazzband.github.io/django-rest-knox/`\n\nUse Knox when DRF's built-in token auth is too limited and you need:\n\n- more than one token per user\n- token expiry and optional auto-refresh\n- logout for only the current token or for all user tokens\n- database storage of token digests instead of recoverable plaintext tokens\n\nThe live docs site is a current-project guide, not a version-frozen `5.0.4` snapshot. For version-sensitive behavior, cross-check the changelog and PyPI metadata before copying older examples.\n\n## Install And Compatibility\n\nInstall the version used here explicitly:\n\n```bash\npip install \"django-rest-knox==5.0.4\"\n```\n\nFor a new DRF project:\n\n```bash\npip install \"django>=4.2\" \"djangorestframework\" \"django-rest-knox==5.0.4\"\n```\n\nOfficial package metadata for `5.0.4` shows:\n\n- Python: `>=3.8`\n- Django dependency: `>=4.2`\n- Django REST framework dependency: `>=3.14`\n\n`5.0.4` is a support-matrix release. The official changelog says it adds support for Django `5.2` and `6.0`, plus Python `3.13` and `3.14`, without changing the minimum supported baselines.\n\n## Minimal Django Setup\n\nAdd Knox to `INSTALLED_APPS` and configure DRF to use Knox tokens for authenticated API requests:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"rest_framework\",\n    \"knox\",\n]\n\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"knox.auth.TokenAuthentication\",\n    ),\n    \"DEFAULT_PERMISSION_CLASSES\": (\n        \"rest_framework.permissions.IsAuthenticated\",\n    ),\n}\n```\n\nRun migrations before testing login or protected routes:\n\n```bash\npython manage.py migrate\n```\n\nIf the project previously used DRF's built-in `rest_framework.authtoken`, remove that token system cleanly instead of running both in parallel.\n\n## Login, Logout, And A Protected Endpoint\n\nThe main integration trap is login. If Knox token auth is the only default DRF authentication class, the stock `knox.views.LoginView` is not enough on its own because the request must already be authenticated before Knox can mint a token.\n\nThe official docs recommend authenticating the username and password first, then delegating token creation to Knox:\n\n```python\n# views.py\nfrom django.contrib.auth import login\nfrom rest_framework import permissions\nfrom rest_framework.authtoken.serializers import AuthTokenSerializer\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nfrom knox.auth import TokenAuthentication\nfrom knox.views import LoginView as KnoxLoginView\n\nclass LoginView(KnoxLoginView):\n    permission_classes = [permissions.AllowAny]\n\n    def post(self, request, format=None):\n        serializer = AuthTokenSerializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        user = serializer.validated_data[\"user\"]\n        login(request, user)\n        return super().post(request, format=None)\n\nclass MeView(APIView):\n    authentication_classes = [TokenAuthentication]\n    permission_classes = [permissions.IsAuthenticated]\n\n    def get(self, request):\n        return Response(\n            {\n                \"user_id\": request.user.pk,\n                \"username\": request.user.get_username(),\n            }\n        )\n```\n\nWire the endpoints:\n\n```python\n# urls.py\nfrom django.urls import path\n\nfrom knox import views as knox_views\n\nfrom .views import LoginView, MeView\n\nurlpatterns = [\n    path(\"api/auth/login/\", LoginView.as_view(), name=\"knox_login\"),\n    path(\"api/auth/logout/\", knox_views.LogoutView.as_view(), name=\"knox_logout\"),\n    path(\"api/auth/logoutall/\", knox_views.LogoutAllView.as_view(), name=\"knox_logoutall\"),\n    path(\"api/me/\", MeView.as_view(), name=\"me\"),\n]\n```\n\nTypical request flow:\n\n```http\nPOST /api/auth/login/\nContent-Type: application/json\n\n{\"username\": \"alice\", \"password\": \"secret\"}\n```\n\nThen send the returned token on later requests:\n\n```http\nAuthorization: Token <token-value>\n```\n\n`POST /api/auth/logout/` deletes only the current token. `POST /api/auth/logoutall/` deletes every token for the authenticated user.\n\n## Using `knox.urls`\n\nKnox ships a small URLconf:\n\n```python\nfrom django.urls import include, path\n\nurlpatterns = [\n    path(\"api/auth/\", include(\"knox.urls\")),\n]\n```\n\nTwo details matter:\n\n- Use string-based `include(\"knox.urls\")`, not a direct import of the module.\n\nIf the project wants JSON username/password login while global auth defaults to Knox tokens, use the custom `LoginView` pattern above.\n\n## Core Configuration\n\nKnox settings live under `REST_KNOX`:\n\n```python\n# settings.py\nfrom datetime import timedelta\n\nREST_KNOX = {\n    \"TOKEN_TTL\": timedelta(hours=10),\n    \"AUTO_REFRESH\": False,\n    \"AUTO_REFRESH_MAX_TTL\": timedelta(days=7),\n    \"MIN_REFRESH_INTERVAL\": 60,\n    \"TOKEN_LIMIT_PER_USER\": None,\n    \"AUTH_HEADER_PREFIX\": \"Token\",\n    \"TOKEN_PREFIX\": \"\",\n}\n```\n\nSettings that usually matter first:\n\n- `TOKEN_TTL`: token lifetime. `None` means tokens do not expire.\n- `AUTO_REFRESH`: extend token expiry on use.\n- `AUTO_REFRESH_MAX_TTL`: cap total token lifetime when auto-refresh is enabled.\n- `MIN_REFRESH_INTERVAL`: reduce database writes by not refreshing expiry on every request.\n- `TOKEN_LIMIT_PER_USER`: cap concurrent valid tokens per user.\n- `AUTH_HEADER_PREFIX`: defaults to `Token`.\n- `TOKEN_PREFIX`: add a prefix to generated token values if you need token-type namespacing.\n\nThe package code for `5.0.4` sets `USER_SERIALIZER` to `None` by default. Only set it if you want the login response to include serialized user data.\n\n## Customizing The Login Response\n\nKnox `5.x` exposes hooks for customizing the login payload, including `create_token`, `get_token_ttl`, and `get_post_response_data`.\n\nExample:\n\n```python\n# settings.py\nREST_KNOX = {\n    \"USER_SERIALIZER\": \"accounts.api.UserSerializer\",\n}\n```\n\n```python\n# views.py\nfrom knox.views import LoginView as KnoxLoginView\n\nclass CustomLoginView(KnoxLoginView):\n    def get_post_response_data(self, request, token, instance):\n        return {\n            \"expiry\": self.format_expiry_datetime(instance.expiry),\n            \"token\": token,\n            \"user\": self.get_user_serializer_class()(request.user).data,\n        }\n```\n\nIf the project has a custom user model, set a serializer that matches the actual fields you want returned instead of assuming the default docs example fits the model.\n\n## Common Pitfalls\n\n- Using Knox as the only DRF default authentication class and also relying on the stock Knox login view. That creates a circular login flow.\n- Forgetting `python manage.py migrate`. Knox stores token records in the database.\n- Keeping `rest_framework.authtoken` enabled while switching to Knox. Pick one token system and migrate cleanly.\n- Importing `knox.urls` directly instead of `include(\"knox.urls\")`.\n- Treating logout endpoints as `GET` or `DELETE`. Knox logout endpoints are `POST`.\n- Assuming the login response will automatically include serialized user data. In `5.0.4`, `USER_SERIALIZER` is not enabled by default.\n- Setting `TOKEN_TTL` to `timedelta(0)` or a negative duration, which makes tokens immediately unusable.\n- Enabling `AUTO_REFRESH` without deciding whether total lifetime must be capped with `AUTO_REFRESH_MAX_TTL`.\n\n## Version-Sensitive Notes For `5.0.4`\n\n- `5.0.4` was released on 2026-03-10.\n- The `5.0.4` changelog entry is support-focused: Django `5.2` and `6.0`, Python `3.13` and `3.14`.\n- `5.0.0` invalidated tokens created before the `5.x` line. If a project is upgrading from `4.x` or older, plan a forced re-authentication event.\n- `5.0.0` also dropped Django `4.0` support and made Django `4.2+` the supported baseline.\n- The docs site is maintained separately from the PyPI release pin. Treat it as current upstream guidance and use the changelog when a detail looks newer than the package version you are installing.\n\n## Recommended Agent Workflow\n\n1. Confirm whether the project wants username/password login, session login, or another upstream DRF authentication method for minting Knox tokens.\n2. Install the pinned package version, add `\"knox\"` to `INSTALLED_APPS`, and run migrations before wiring auth endpoints.\n3. If Knox tokens are the default DRF auth mechanism, implement the custom login view immediately instead of relying on the stock login view.\n4. Decide the token policy early: fixed expiry, auto-refresh, max lifetime, and per-user token limits.\n5. If the project already uses DRF token auth or an older Knox major version, treat token migration and forced logout behavior as part of the rollout.\n\n## Official Sources Used\n\n- Docs root: `https://jazzband.github.io/django-rest-knox/`\n- Installation: `https://jazzband.github.io/django-rest-knox/installation/`\n- Auth guide: `https://jazzband.github.io/django-rest-knox/auth/`\n- URL routing: `https://jazzband.github.io/django-rest-knox/urls/`\n- Views API: `https://jazzband.github.io/django-rest-knox/views/`\n- Settings reference: `https://jazzband.github.io/django-rest-knox/settings/`\n- Changelog: `https://jazzband.github.io/django-rest-knox/changelog/`\n- PyPI package page: `https://pypi.org/project/django-rest-knox/`\n- PyPI JSON metadata: `https://pypi.org/pypi/django-rest-knox/json`\n- Source repository: `https://github.com/jazzband/django-rest-knox`\n- Package defaults source: `https://raw.githubusercontent.com/jazzband/django-rest-knox/develop/knox/settings.py`\n"
  },
  {
    "path": "content/django/docs/silk/python/DOC.md",
    "content": "---\nname: silk\ndescription: \"django-silk package guide for Python with safe Django profiling setup, core Silk workflows, and version-drift notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.5.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-silk,django,python,profiling,performance,sql,debugging,middleware\"\n---\n\n# django-silk Python Package Guide\n\nUse `django-silk` for request, SQL, and Python profiling inside Django apps when you need to inspect slow endpoints or repeated queries from inside the app itself.\n\n## Golden Rule\n\nEnable Silk only for local development, staging, or tightly controlled internal environments. Treat `/silk/` as sensitive operational tooling, not as a public feature.\n\n## Version Drift Note\n\nAn earlier version reference pointed to `5.5.0`, but the official public sources I could verify on 2026-03-12 still showed `5.4.3` as the latest visible release on both PyPI and GitHub releases.\n\nPractical implication:\n\n- keep `5.5.0` in frontmatter for queue traceability\n- use the public `5.4.3` docs and release history as the verified baseline\n- if a project lockfile or private package mirror already pins `5.5.0`, verify the exact release artifact before assuming behavior beyond the `5.4.x` line\n\n## Install\n\nInstall the current verified public line:\n\n```bash\npython -m pip install \"django-silk==5.4.3\"\n```\n\nBasic install without a version pin:\n\n```bash\npython -m pip install django-silk\n```\n\nOptional formatting extras for generated Python snippets:\n\n```bash\npython -m pip install \"django-silk[formatting]\"\n```\n\nCommon project tools:\n\n```bash\npoetry add django-silk\nuv add django-silk\n```\n\nIf your project is already pinned to version used here `5.5.0`, keep that project pin, but do not assume the public PyPI page or GitHub release notes already document it.\n\n## Compatibility\n\nCurrent public docs on PyPI list support for:\n\n- Django `4.2`, `5.1`, `5.2`\n- Python `3.9`, `3.10`, `3.11`, `3.12`, `3.13`\n\nThe current GitHub README is newer than the public `5.4.3` release notes and lists a slightly newer support matrix. Treat the PyPI package page and tagged releases as the safer baseline when your project is version-sensitive.\n\n## Minimal Setup\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"silk\",\n]\n```\n\nAdd Silk middleware near the top so it sees most of the request lifecycle. If you use gzip, keep `GZipMiddleware` before Silk:\n\n```python\n# settings.py\nMIDDLEWARE = [\n    \"django.middleware.gzip.GZipMiddleware\",\n    \"silk.middleware.SilkyMiddleware\",\n    # ...\n]\n```\n\nIf you subclass Silk middleware, route the setting through `SILKY_MIDDLEWARE_CLASS`:\n\n```python\n# settings.py\nSILKY_MIDDLEWARE_CLASS = \"myproject.middleware.MyCustomSilkyMiddleware\"\n\nMIDDLEWARE = [\n    # ...\n    SILKY_MIDDLEWARE_CLASS,\n    # ...\n]\n```\n\nSilk expects the request object in Django templates:\n\n```python\n# settings.py\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"OPTIONS\": {\n            \"context_processors\": [\n                # ...\n                \"django.template.context_processors.request\",\n            ],\n        },\n    },\n]\n```\n\nExpose the UI:\n\n```python\n# urls.py\nfrom django.urls import include, path\n\nurlpatterns = [\n    # ...\n    path(\"silk/\", include(\"silk.urls\", namespace=\"silk\")),\n]\n```\n\nRun database and static setup:\n\n```bash\npython manage.py migrate\npython manage.py collectstatic --noinput\n```\n\nThen hit a few requests and open `/silk/`.\n\n## Safe Default Configuration\n\nStart with auth enabled, sampling turned on, and request/response storage bounded:\n\n```python\n# settings.py\nSILKY_AUTHENTICATION = True\nSILKY_AUTHORISATION = True\n\nSILKY_INTERCEPT_PERCENT = 10\nSILKY_MAX_REQUEST_BODY_SIZE = 1024 * 50\nSILKY_MAX_RESPONSE_BODY_SIZE = 1024 * 50\nSILKY_MAX_RECORDED_REQUESTS = 10**4\nSILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT = 10\nSILKY_SENSITIVE_KEYS = {\n    \"authorization\",\n    \"cookie\",\n    \"csrftoken\",\n    \"password\",\n    \"secret\",\n    \"session\",\n    \"token\",\n}\n```\n\nIf you want conditional capture, use `SILKY_INTERCEPT_FUNC` instead of `SILKY_INTERCEPT_PERCENT`:\n\n```python\n# settings.py\ndef record_selected_requests(request):\n    return request.user.is_staff and \"record_requests\" in request.session\n\nSILKY_INTERCEPT_FUNC = record_selected_requests\n```\n\n## Auth And Permissions\n\nBy default, enabling `SILKY_AUTHORISATION` restricts the UI to staff users. Override that with a custom permission callable when your project needs something narrower:\n\n```python\n# settings.py\ndef can_view_silk(user):\n    return user.is_authenticated and user.is_superuser\n\nSILKY_PERMISSIONS = can_view_silk\n```\n\nOperationally, `/silk/` should usually sit behind at least one of:\n\n- Django auth and staff or superuser checks\n- an internal admin network or VPN\n- a temporary feature flag during an investigation window\n\n## Core Usage\n\n### Request and SQL inspection\n\nSilk stores request and response metadata, timing, SQL query lists, and per-request totals in your Django database. The common starting views are:\n\n- `/silk/requests/` for slow endpoints and per-request totals\n- `/silk/sql/` for query shape, table involvement, joins, and timings\n\nThis is where you usually spot N+1-style behavior, duplicated queries, or views spending too much time in ORM work.\n\n### Enable Python profiling\n\nFor request-level `cProfile` output:\n\n```python\n# settings.py\nSILKY_PYTHON_PROFILER = True\nSILKY_PYTHON_PROFILER_BINARY = True\nSILKY_PYTHON_PROFILER_EXTENDED_FILE_NAME = True\n```\n\nFor Django `4.2+` and Silk `5.1.0+`, configure profiler result storage through `STORAGES` instead of `SILKY_STORAGE_CLASS`:\n\n```python\n# settings.py\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"django.core.files.storage.FileSystemStorage\",\n    },\n    \"SILKY_STORAGE\": {\n        \"BACKEND\": \"myproject.storage.ProfilerStorage\",\n    },\n}\n```\n\nIf you use the default profiler storage, you can choose a result directory:\n\n```python\n# settings.py\nSILKY_PYTHON_PROFILER_RESULT_PATH = \"/tmp/silk-profiles\"\n```\n\nThe saved `.prof` files work with tools such as `snakeviz`.\n\n### Profile specific code\n\nDecorator:\n\n```python\nfrom silk.profiling.profiler import silk_profile\n\n@silk_profile(name=\"checkout flow\")\ndef build_checkout(user, cart):\n    ...\n```\n\nContext manager:\n\n```python\nfrom silk.profiling.profiler import silk_profile\n\ndef create_invoice(order):\n    with silk_profile(name=f\"invoice #{order.pk}\"):\n        return serialize_order(order)\n```\n\n### Dynamic profiling\n\nUse `SILKY_DYNAMIC_PROFILING` when you need to patch a function or code block without editing its source:\n\n```python\n# settings.py\nSILKY_DYNAMIC_PROFILING = [\n    {\n        \"module\": \"payments.service\",\n        \"function\": \"build_quote\",\n    }\n]\n```\n\nPoint the config at the symbol actually imported and called by runtime code, not just the function's original source module.\n\n### Conditional Python profiling\n\nIf full request profiling is too expensive, gate it with `SILKY_PYTHON_PROFILER_FUNC`:\n\n```python\n# settings.py\ndef should_profile_request(request):\n    return request.user.is_staff and \"profile_requests\" in request.session\n\nSILKY_PYTHON_PROFILER_FUNC = should_profile_request\n```\n\nThis setting takes precedence over `SILKY_PYTHON_PROFILER` and still works with dynamic profiling.\n\n## Useful Configuration Flags\n\n- `SILKY_META = True` records how much extra time Silk itself adds while saving profiling data.\n- `SILKY_ANALYZE_QUERIES = True` enables DB-backed query analysis when supported.\n- `SILKY_EXPLAIN_FLAGS = {\"format\": \"JSON\", \"costs\": True}` passes extra explain flags to supported backends.\n- `SILKY_MAX_RECORDED_REQUESTS` caps stored request rows.\n- `SILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT` controls how often automatic garbage collection runs.\n\n## Cleanup And Operations\n\nSilk persists captured requests in your application database, so clean it up regularly:\n\n```bash\npython manage.py silk_request_garbage_collect\npython manage.py silk_clear_request_log\n```\n\nIf you want cleanup decoupled from normal request handling, set `SILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT = 0` and run `silk_request_garbage_collect` from cron or another scheduled job.\n\n## Common Pitfalls\n\n- Middleware order matters. If middleware before Silk returns a response without calling `get_response`, Silk never sees that request.\n- Keep `django.middleware.gzip.GZipMiddleware` before Silk or you can hit encoding issues.\n- Missing `django.template.context_processors.request` breaks parts of the UI.\n- `SILKY_ANALYZE_QUERIES = True` can execute a query twice on some backends, especially with `EXPLAIN ANALYZE`, so do not enable it casually against write-heavy code paths.\n- Request and response bodies are stored by default and can grow the database quickly on high-volume or large-payload systems.\n- Python `3.12+` profiling is concurrency-sensitive because `cProfile` cannot be enabled multiple times concurrently.\n- Silk itself adds overhead. Use it to diagnose an issue, then reduce capture or disable it again.\n\n## Version-Sensitive Notes\n\n- Public upstream sources observed on 2026-03-12 still show `5.4.3` as the latest visible release, not the version used here `5.5.0`.\n- `5.4.3` fixed double `EXPLAIN` behavior and serialization issues for binary and JSON fields.\n- `5.3.2` refreshed middleware-order documentation.\n- `5.3.0` removed support for Django `3.2` and Python `3.8`, added Python `3.13`, and upgraded jQuery UI to address an XSS issue.\n- `5.2.0` added Django `5.1` support.\n- `5.1.0` deprecated `SILKY_STORAGE_CLASS` in favor of Django `STORAGES` and documented Python `3.12` profiler concurrency limits.\n\n## Recommended Agent Workflow\n\n1. Confirm whether the target project is using the public `5.4.x` line or an internal/private `5.5.0` artifact.\n2. Install Silk and wire `silk` plus `SilkyMiddleware` into settings.\n3. Lock down `/silk/` before generating real traffic.\n4. Start with request sampling and bounded body sizes.\n5. Use `/silk/requests/` and `/silk/sql/` first, then add `@silk_profile` or `SILKY_DYNAMIC_PROFILING` only for specific hotspots.\n6. Clear captured data after the investigation so stale traces do not keep accumulating.\n\n## Official Sources\n\n- Repository: https://github.com/jazzband/django-silk\n- README: https://github.com/jazzband/django-silk/blob/master/README.md\n- Releases: https://github.com/jazzband/django-silk/releases\n- PyPI: https://pypi.org/project/django-silk/\n"
  },
  {
    "path": "content/django/docs/simple-history/python/DOC.md",
    "content": "---\nname: simple-history\ndescription: \"django-simple-history package guide for Django model auditing, user attribution, and rollback workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-simple-history,django,history,audit,admin,middleware,models\"\n---\n\n# django-simple-history Python Package Guide\n\n## What It Does\n\n`django-simple-history` adds audit history to Django models by creating historical models and attaching a `history` manager. Use it when you need:\n\n- a per-row change log\n- point-in-time reads\n- user attribution for changes\n- admin-visible history and rollback flows\n\nFor package version `3.11.0`, the standard workflow is:\n\n1. Install the package and add `simple_history` to `INSTALLED_APPS`.\n2. Add `HistoricalRecords()` to tracked models, or call `register()` for models you cannot edit directly.\n3. Run migrations so the historical tables exist.\n4. Add `HistoryRequestMiddleware` if you want `history_user` populated from the current request.\n\n## Version Covered\n\n- Package: `django-simple-history`\n- Import namespace: `simple_history`\n- Version in this doc: `3.11.0`\n- Python requirement: `>=3.10`\n- PyPI classifiers for `3.11.0`: Django `4.2`, `5.1`, `5.2`, `6.0`; Python `3.10` through `3.14`\n\nVersion-sensitive note: upstream `3.11.0` adds Django `6.0` and Python `3.14` support, and drops Django `5.0` and Python `3.9`.\n\n## Install\n\n```bash\npython -m pip install django-simple-history==3.11.0\n```\n\n```bash\nuv add django-simple-history==3.11.0\n```\n\n```bash\npoetry add django-simple-history==3.11.0\n```\n\n## Initialize And Migrate\n\nAdd the app:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"simple_history\",\n]\n```\n\nTrack a model:\n\n```python\n# models.py\nfrom django.db import models\nfrom simple_history.models import HistoricalRecords\n\nclass Poll(models.Model):\n    question = models.CharField(max_length=200)\n    pub_date = models.DateTimeField(\"date published\")\n    history = HistoricalRecords()\n```\n\nCreate and apply migrations:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\n```\n\nIf the model already has rows, backfill initial snapshots:\n\n```bash\npython manage.py populate_history --auto\n```\n\nIf you cannot modify the model class directly, register it instead:\n\n```python\nfrom simple_history import register\nfrom third_party_app.models import ExternalModel\n\nregister(ExternalModel)\n```\n\n## Core Usage\n\n### Read historical rows\n\nEach tracked model gets a `history` manager ordered newest first:\n\n```python\npoll = Poll.objects.get(pk=1)\n\nlatest_entry = poll.history.first()\nfull_audit_trail = poll.history.all()\n```\n\nYou can also query history from the model class:\n\n```python\nhistory_qs = Poll.history.filter(question__icontains=\"django\")\n```\n\n### Create changes and inspect history\n\n```python\nfrom django.utils import timezone\n\npoll = Poll.objects.create(question=\"Initial\", pub_date=timezone.now())\npoll.question = \"Updated\"\npoll.save()\n\nfor entry in poll.history.all():\n    print(entry.history_date, entry.history_type, entry.question)\n```\n\n`history_type` is:\n\n- `\"+\"` for create\n- `\"~\"` for update\n- `\"-\"` for delete\n\n### Read model state at a point in time\n\nUse `as_of()` when you need object state at a past timestamp:\n\n```python\nsnapshot_qs = Poll.history.as_of(some_dt)\nold_poll = Poll.history.as_of(some_dt).get(pk=1)\n```\n\nFor a single object, `poll.history.most_recent()` is the common convenience path.\n\n### Diff two historical records\n\n```python\nnew_record, old_record = poll.history.all()[:2]\ndelta = new_record.diff_against(old_record)\n\nfor change in delta.changes:\n    print(change.field, change.old, change.new)\n```\n\nIn current releases, diff output is sorted consistently, which is useful for tests and agent-generated assertions.\n\n### Restore from a historical record\n\n```python\nhistorical = poll.history.earliest()\nrestored = historical.instance\nrestored.save()\n```\n\nThis is an application-level restore. Signals, validation, and related model side effects still apply when you save the reconstructed instance.\n\n## Configuration And User Attribution\n\n`django-simple-history` has no API credentials or network auth. The relevant configuration is Django-side tracking of the acting user and of what fields get historical coverage.\n\n### Track the acting user from requests\n\nAdd the middleware:\n\n```python\n# settings.py\nMIDDLEWARE = [\n    # ...\n    \"simple_history.middleware.HistoryRequestMiddleware\",\n    # ...\n]\n```\n\nWith Django auth enabled, this populates `history_user` from `request.user`.\n\n### Track the acting user manually\n\nWhen work happens outside the request cycle, set `_history_user` before saving:\n\n```python\npoll._history_user = request.user\npoll.save()\n```\n\nYou can also set `_change_reason` or `_history_date` when you need explicit metadata:\n\n```python\npoll._change_reason = \"import fix\"\npoll.save()\n```\n\n### Disable history globally\n\n```python\nSIMPLE_HISTORY_ENABLED = False\n```\n\nThis is useful in controlled maintenance flows, imports, or tests where audit rows would be noise.\n\n### Add history to Django admin\n\n```python\nfrom django.contrib import admin\nfrom simple_history.admin import SimpleHistoryAdmin\n\nfrom .models import Poll\n\n@admin.register(Poll)\nclass PollAdmin(SimpleHistoryAdmin):\n    pass\n```\n\n## Customizing What Gets Tracked\n\nExclude fields that do not belong in history:\n\n```python\nhistory = HistoricalRecords(excluded_fields=[\"updated_at\"])\n```\n\nTrack many-to-many changes explicitly:\n\n```python\nclass Poll(models.Model):\n    categories = models.ManyToManyField(\"Category\")\n    history = HistoricalRecords(m2m_fields=[\"categories\"])\n```\n\nIf you skip `m2m_fields`, normal M2M edits are not tracked.\n\n## Bulk Operations\n\nRegular `save()` and `delete()` create historical rows. Bulk APIs need explicit helpers.\n\nUse the package utilities when you need history for bulk inserts or updates:\n\n```python\nfrom django.utils import timezone\nfrom simple_history.utils import bulk_create_with_history, bulk_update_with_history\n\npolls = [\n    Poll(question=\"One\", pub_date=timezone.now()),\n    Poll(question=\"Two\", pub_date=timezone.now()),\n]\nbulk_create_with_history(polls, Poll)\n```\n\n```python\npolls[0].question = \"Renamed\"\nbulk_update_with_history(polls, Poll, [\"question\"])\n```\n\nDo not expect `QuerySet.update()` to create history rows. It bypasses `post_save`, which the package relies on.\n\n## Common Pitfalls\n\n- Forgetting `\"simple_history\"` in `INSTALLED_APPS` before creating migrations.\n- Adding `HistoricalRecords()` but never running `makemigrations` and `migrate`.\n- Using `QuerySet.update()` and expecting audit rows.\n- Using `F()` expressions on tracked models. The docs call this unsupported because the historical insert sees the unresolved expression and raises `ValueError`.\n- Assuming M2M changes are tracked automatically. They are only tracked when you opt in with `m2m_fields=[...]`.\n- Expecting request middleware to populate `history_user` in Celery tasks, management commands, or scripts. Set `_history_user` manually there.\n- Using model field names that conflict with reserved historical model names such as `history_id`, `history_date`, `history_change_reason`, or `history_type`.\n\n## Version-Sensitive Notes\n\n- `3.11.0` is the current package release covered here and aligns with the current stable docs.\n- `3.10.0` moved the project from the old Jazzband organization to `django-commons/django-simple-history`. Prefer current repository links when following issues or releases.\n- `3.9.0` removed the deprecated `simple_history_admin_list.display_list` template tag. Older admin customizations may need cleanup.\n- `3.8.0` changed save-suppression behavior so `skip_history_when_saving` also works for object creation, and it improved M2M history query performance.\n\n## Official Links\n\n- Documentation root: https://django-simple-history.readthedocs.io/en/stable/\n- Quick start: https://django-simple-history.readthedocs.io/en/stable/quick_start.html\n- Querying history: https://django-simple-history.readthedocs.io/en/stable/querying_history.html\n- Historical model customization: https://django-simple-history.readthedocs.io/en/stable/historical_model.html\n- User tracking: https://django-simple-history.readthedocs.io/en/stable/user_tracking.html\n- Common issues: https://django-simple-history.readthedocs.io/en/stable/common_issues.html\n- Admin integration: https://django-simple-history.readthedocs.io/en/stable/admin.html\n- Changelog: https://django-simple-history.readthedocs.io/en/stable/changelog.html\n- PyPI: https://pypi.org/project/django-simple-history/\n- Repository: https://github.com/django-commons/django-simple-history\n"
  },
  {
    "path": "content/django/docs/storages/python/DOC.md",
    "content": "---\nname: storages\ndescription: \"django-storages package guide for Django file and static storage backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.6\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-storages,django,storage,s3,azure,gcs,staticfiles\"\n---\n\n# django-storages Python Package Guide\n\n## What It Is\n\n`django-storages` plugs cloud and remote storage backends into Django's storage API.\n\n- Package name: `django-storages`\n- Django app: `storages`\n- Import path you usually configure: backend class string in Django settings\n- Version covered: `1.14.6`\n\nMost projects do not call `django-storages` APIs directly. You configure a backend, then keep using Django's normal file APIs such as `default_storage`, `FileField`, `ImageField`, and `collectstatic`.\n\n## Install\n\nInstall the package version your project is pinned to:\n\n```bash\npip install django-storages==1.14.6\n```\n\nAdd the app:\n\n```python\nINSTALLED_APPS = [\n    # ...\n    \"storages\",\n]\n```\n\nYou also need the provider SDK for the backend you choose. Typical combinations are:\n\n- Amazon S3: `boto3`\n- Azure Blob Storage: `azure-storage-blob`\n- Google Cloud Storage: `google-cloud-storage`\n\nExamples:\n\n```bash\npip install django-storages==1.14.6 boto3\npip install django-storages==1.14.6 azure-storage-blob\npip install django-storages==1.14.6 google-cloud-storage\n```\n\n## Initialization And Setup\n\n### Django 4.2 And Newer\n\nUse Django's `STORAGES` setting. This is the upstream-recommended pattern for `django-storages` because it lets you configure separate storage instances without subclassing.\n\nExample with different S3 prefixes for media and static files:\n\n```python\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"storages.backends.s3.S3Storage\",\n        \"OPTIONS\": {\n            \"bucket_name\": \"my-app-bucket\",\n            \"region_name\": \"us-east-1\",\n            \"default_acl\": None,\n            \"location\": \"media\",\n            \"file_overwrite\": False,\n        },\n    },\n    \"staticfiles\": {\n        \"BACKEND\": \"storages.backends.s3.S3Storage\",\n        \"OPTIONS\": {\n            \"bucket_name\": \"my-app-bucket\",\n            \"region_name\": \"us-east-1\",\n            \"default_acl\": None,\n            \"location\": \"static\",\n        },\n    },\n}\n```\n\n### Django Earlier Than 4.2\n\nLegacy global settings still work for older Django versions:\n\n```python\nDEFAULT_FILE_STORAGE = \"storages.backends.s3.S3Storage\"\nSTATICFILES_STORAGE = \"storages.backends.s3.S3Storage\"\n\nAWS_STORAGE_BUCKET_NAME = \"my-app-bucket\"\nAWS_S3_REGION_NAME = \"us-east-1\"\nAWS_DEFAULT_ACL = None\nAWS_LOCATION = \"media\"\n```\n\nIf you need two differently configured storages before Django 4.2, the upstream docs call out subclassing as the usual workaround.\n\n## Core Usage\n\nOnce configured, use Django's normal storage API.\n\nSave a generated file:\n\n```python\nfrom django.core.files.base import ContentFile\nfrom django.core.files.storage import default_storage\n\nname = default_storage.save(\n    \"uploads/report.txt\",\n    ContentFile(b\"generated by django-storages\"),\n)\n\npublic_url = default_storage.url(name)\n```\n\nModel-backed uploads work the same way:\n\n```python\nfrom django.db import models\n\nclass Document(models.Model):\n    file = models.FileField(upload_to=\"documents/\")\n```\n\nIf your `default` storage alias points at a `django-storages` backend, Django routes reads and writes through that backend automatically.\n\n## Backend Setup Patterns\n\n### Amazon S3\n\nFor `1.14.6`, prefer the current backend path used in the official docs:\n\n```python\n\"storages.backends.s3.S3Storage\"\n```\n\nMinimal Django 4.2+ media storage:\n\n```python\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"storages.backends.s3.S3Storage\",\n        \"OPTIONS\": {\n            \"bucket_name\": \"my-app-bucket\",\n            \"region_name\": \"us-east-1\",\n            \"default_acl\": None,\n            \"querystring_auth\": True,\n            \"object_parameters\": {\n                \"CacheControl\": \"max-age=86400\",\n            },\n        },\n    },\n}\n```\n\nCredential resolution in the official S3 docs is, in order:\n\n1. `session_profile`\n2. Explicit backend options such as `access_key`, `secret_key`, and `security_token`\n3. S3-specific environment variables\n4. Generic AWS environment variables\n\nPractical guidance:\n\n- Prefer environment variables, IAM roles, or another boto3-supported credential chain.\n- Use `location` to separate static and media prefixes.\n- Use `object_parameters` for headers such as `CacheControl`, `SSEKMSKeyId`, `StorageClass`, and `Tagging`.\n- Set `file_overwrite` explicitly if you do not want later uploads to replace files with the same name.\n- If you point at an S3-compatible service, set `endpoint_url` and keep `region_name` aligned so signed URLs keep working.\n\n### Azure Blob Storage\n\nBackend path:\n\n```python\n\"storages.backends.azure_storage.AzureStorage\"\n```\n\nMinimal setup:\n\n```python\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"storages.backends.azure_storage.AzureStorage\",\n        \"OPTIONS\": {\n            \"account_name\": \"myaccount\",\n            \"account_key\": \"...\",\n            \"azure_container\": \"media\",\n        },\n    },\n}\n```\n\nCommon auth and config patterns from the official docs:\n\n- `account_name` plus `account_key`\n- `connection_string`\n- `token_credential` for Azure Identity based auth\n- `azure_container` for the target container\n- `expiration_secs` to control signed URL lifetime\n\nUse a pre-created container and keep secrets out of committed settings files.\n\n### Google Cloud Storage\n\nBackend path:\n\n```python\n\"storages.backends.gcloud.GoogleCloudStorage\"\n```\n\nMinimal setup:\n\n```python\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"storages.backends.gcloud.GoogleCloudStorage\",\n        \"OPTIONS\": {\n            \"bucket_name\": \"my-gcs-bucket\",\n            \"project_id\": \"my-project-id\",\n        },\n    },\n}\n```\n\nPractical auth and URL notes:\n\n- The backend can use default Google application credentials or explicit credentials.\n- `default_acl` affects whether uploaded objects are private or public by default.\n- `querystring_auth` controls whether generated URLs are signed.\n- `iam_sign_blob` is available in `1.14.6` when you need signed URLs without a local private key.\n\nIf you use uniform bucket-level access, avoid patterns that depend on per-object ACLs.\n\n## Static Files\n\nFor Django 4.2+, use a dedicated `staticfiles` alias:\n\n```python\nSTORAGES = {\n    \"staticfiles\": {\n        \"BACKEND\": \"storages.backends.s3.S3Storage\",\n        \"OPTIONS\": {\n            \"bucket_name\": \"my-app-bucket\",\n            \"location\": \"static\",\n            \"default_acl\": None,\n        },\n    },\n}\n```\n\nThen run:\n\n```bash\npython manage.py collectstatic\n```\n\nKeep static and media files in different prefixes or different buckets/containers so `collectstatic` does not mix with user uploads.\n\n## Config And Auth Notes\n\n- Add `\"storages\"` to `INSTALLED_APPS`.\n- Prefer `STORAGES` on Django 4.2+.\n- Keep credentials in environment variables, cloud-native credential chains, or secret managers.\n- Separate `default` and `staticfiles` config.\n- Use backend options in `STORAGES[\"...\"][\"OPTIONS\"]`; do not mix old global settings into a partial 4.2 migration.\n- Validate generated URLs in tests when you change `custom_domain`, `querystring_auth`, `endpoint_url`, or signed URL expiration settings.\n\n## Common Pitfalls\n\n### Copying Old S3 Import Paths\n\nOlder examples still use `storages.backends.s3boto3.S3Boto3Storage`.\n\nFor `1.14.6`, prefer:\n\n```python\n\"storages.backends.s3.S3Storage\"\n```\n\n### Mixing Django 4.2 `STORAGES` With Legacy Global Settings\n\nDo not do a half-migration. Pick one configuration style that matches your Django version.\n\n### Reusing The Same Prefix For Static And Media Files\n\nIf both aliases point to the same bucket and `location`, user uploads and `collectstatic` output can overwrite or clutter each other.\n\n### Assuming `default_acl` Overrides Everything\n\nFor S3, the docs note that `default_acl` is ignored if you set `ACL` inside `object_parameters`.\n\n### Hardcoding Cloud Credentials\n\nHardcoded credentials in Django settings are easy to leak and harder to rotate. All three major backends documented here support better environment-based or provider-native auth flows.\n\n### Misconfiguring Public URLs\n\n- On S3, `custom_domain` and `STATIC_URL` slash handling can produce broken URLs if you mix trailing slash assumptions.\n- On GCS, public URLs depend on ACL configuration and signing settings.\n- On Azure, signed URL behavior depends on your credential mode and expiration configuration.\n\n## Version-Sensitive Notes\n\n- This doc is for `django-storages` `1.14.6`.\n- The docs URL uses `/en/latest/`, and as of 2026-03-12 the latest docs and PyPI package page both match `1.14.6`, so there was no version drift on that date.\n- The 1.14-series docs use `storages.backends.s3.S3Storage`; older `s3boto3` snippets from blog posts are stale for current projects.\n- `1.14.6` adds Google Cloud Storage IAM Sign Blob support and includes S3-related fixes noted in the upstream changelog.\n- If you are debugging older code written before the 1.14 migration work, verify backend class paths and storage settings before changing application code.\n\n## Official Sources\n\n- Versioned docs root: https://django-storages.readthedocs.io/en/1.14.6/\n- Latest docs root: https://django-storages.readthedocs.io/en/latest/\n- Amazon S3 backend docs: https://django-storages.readthedocs.io/en/1.14.6/backends/amazon-S3.html\n- Azure backend docs: https://django-storages.readthedocs.io/en/1.14.6/backends/azure.html\n- Google Cloud Storage backend docs: https://django-storages.readthedocs.io/en/1.14.6/backends/gcloud.html\n- PyPI registry page: https://pypi.org/project/django-storages/\n- PyPI JSON metadata: https://pypi.org/pypi/django-storages/json\n- Upstream changelog: https://github.com/jschneier/django-storages/blob/master/CHANGELOG.rst\n"
  },
  {
    "path": "content/django/docs/taggit/python/DOC.md",
    "content": "---\nname: taggit\ndescription: \"django-taggit tagging library for Django models, forms, admin, and Django REST Framework\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,taggit,tags,orm,admin,drf\"\n---\n\n# django-taggit Python Package Guide\n\n## Golden Rule\n\nUse `django-taggit` for model tagging in Django projects instead of inventing a custom comma-separated field or ad hoc many-to-many schema. Import from `taggit`, add `taggit` to `INSTALLED_APPS`, run migrations, and use `TaggableManager` on saved model instances.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"django-taggit==6.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"django-taggit==6.1.0\"\npoetry add \"django-taggit==6.1.0\"\n```\n\nAdd the app and migrate:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"taggit\",\n]\n```\n\n```bash\npython manage.py migrate\n```\n\n## Initialize In A Model\n\n`TaggableManager` behaves like a many-to-many field with tag-aware helpers:\n\n```python\nfrom django.db import models\nfrom taggit.managers import TaggableManager\n\nclass Article(models.Model):\n    title = models.CharField(max_length=200)\n    body = models.TextField()\n    tags = TaggableManager(blank=True)\n```\n\nCreate and tag an object:\n\n```python\narticle = Article.objects.create(title=\"Intro\", body=\"...\")\narticle.tags.add(\"django\", \"orm\")\narticle.tags.add(\"python\", tag_kwargs={\"slug\": \"python\"})\n```\n\nRead tags:\n\n```python\nnames = list(article.tags.names())\nslugs = list(article.tags.slugs())\nall_tags = list(article.tags.all())\n```\n\nReplace or clear tags:\n\n```python\narticle.tags.set([\"django\", \"tutorial\"], clear=True)\narticle.tags.remove(\"tutorial\")\narticle.tags.clear()\n```\n\n## Querying And Core ORM Usage\n\nFilter by a single tag:\n\n```python\nArticle.objects.filter(tags__name__in=[\"django\"])\nArticle.objects.filter(tags__slug__in=[\"django\"])\n```\n\nWhen you filter across tag joins, add `distinct()` unless you explicitly want duplicates:\n\n```python\nArticle.objects.filter(tags__name__in=[\"django\", \"python\"]).distinct()\n```\n\nUseful helpers on the manager:\n\n```python\narticle.tags.similar_objects()\nArticle.tags.most_common()  # via the model-level manager\n```\n\nAvoid N+1 queries when rendering tag lists:\n\n```python\nArticle.objects.prefetch_related(\"tags\")\n```\n\n## Forms, Admin, And API Serialization\n\nModel forms work with `TaggableManager`, but if you save with `commit=False`, you still need `save_m2m()`:\n\n```python\nform = ArticleForm(request.POST)\narticle = form.save(commit=False)\narticle.author = request.user\narticle.save()\nform.save_m2m()\n```\n\nThe admin integration supports tag display and tag merge operations:\n\n```python\nfrom django.contrib import admin\nfrom taggit.admin import TaggitListFilter\n\nfrom .models import Article\n\n@admin.register(Article)\nclass ArticleAdmin(admin.ModelAdmin):\n    list_display = [\"title\"]\n    list_filter = [TaggitListFilter]\n```\n\nFor Django REST Framework, use the serializer helpers from `taggit.serializers`:\n\n```python\nfrom rest_framework import serializers\nfrom taggit.serializers import TaggitSerializer, TagListSerializerField\n\nfrom .models import Article\n\nclass ArticleSerializer(TaggitSerializer, serializers.ModelSerializer):\n    tags = TagListSerializerField()\n\n    class Meta:\n        model = Article\n        fields = [\"id\", \"title\", \"tags\"]\n```\n\n## Configuration And Customization\n\nThere is no package-specific auth layer. Configuration is standard Django setup plus optional taggit settings and model customization.\n\n### Custom parser and renderer\n\nOverride how tag strings are parsed from forms and rendered back to strings:\n\n```python\n# settings.py\nTAGGIT_TAGS_FROM_STRING = \"path.to.tags_from_string\"\nTAGGIT_STRING_FROM_TAGS = \"path.to.string_from_tags\"\n```\n\nThis is useful if you need stricter quoting rules or a non-comma input format.\n\n### Unicode slug behavior\n\n`django-taggit` now keeps Unicode characters during slugification by default. If you must preserve the older stripping behavior:\n\n```python\nTAGGIT_STRIP_UNICODE_WHEN_SLUGIFYING = True\n```\n\nPrefer leaving the default unless you are maintaining older slug compatibility.\n\n### Custom tag or through models\n\nUse a custom tag model when you need extra fields on tags, non-integer primary keys, or a non-generic relation:\n\n```python\nfrom django.db import models\nfrom taggit.managers import TaggableManager\nfrom taggit.models import GenericUUIDTaggedItemBase, TagBase\n\nclass MyTag(TagBase):\n    description = models.TextField(blank=True)\n\nclass TaggedArticle(GenericUUIDTaggedItemBase):\n    tag = models.ForeignKey(\n        MyTag,\n        on_delete=models.CASCADE,\n        related_name=\"tagged_articles\",\n    )\n\nclass Article(models.Model):\n    id = models.UUIDField(primary_key=True)\n    title = models.CharField(max_length=200)\n    tags = TaggableManager(through=TaggedArticle)\n```\n\nIf you switch to your own tag and through models from the start, follow the upstream guidance and remove `\"taggit\"` from `INSTALLED_APPS` before your first migration so Django does not create the default taggit tables you will not use.\n\n## Operations And Maintenance\n\nNatural keys are supported for `dumpdata` and `loaddata`, which helps when fixtures move across databases.\n\n`6.1.0` also adds management commands to clean tag data:\n\n```bash\npython manage.py deduplicate_tags\npython manage.py remove_orphaned_tags\n```\n\nThe orphan cleanup command accepts `--noinput` for unattended runs.\n\n## Common Pitfalls\n\n- Save the model instance before calling `add()`, `set()`, or `remove()` on `TaggableManager`. Like other many-to-many relations, unsaved instances cannot write tag relations.\n- `set()` expects an iterable such as `[\"django\", \"python\"]`; do not pass multiple positional tag arguments.\n- Add `distinct()` when filtering through `tags__...` joins or you may get duplicate rows.\n- `TaggableManager(blank=True)` controls form validation only. It does not bypass migrations or model-save ordering constraints.\n- If you use `form.save(commit=False)`, call `save_m2m()` after saving the instance or the tags will not persist.\n- If you use custom tag models, align `through=` and `tag = ForeignKey(...)` exactly with the upstream base classes or migrations will get messy quickly.\n\n## Version-Sensitive Notes\n\n- The official docs currently describe `django-taggit 6.1.0` as supporting Django `4.1+` and Python `3.9+`.\n- The PyPI project metadata for `6.1.0` still says `Requires: Python >=3.8`, and its long description still mentions Django `3.2 or greater`. Treat that as upstream metadata drift, not a reliable support floor.\n- `6.1.0` adds `deduplicate_tags` and `remove_orphaned_tags` management commands.\n- `6.0.0` changed default ordering for `TaggableManager` to use the tagged item's primary key. Set `ordering=[]` on the manager if you need the pre-6.0 unordered behavior.\n- `5.0.0` removed Django `3.2` support and vendored the DRF serializer helpers directly into `taggit.serializers`.\n- `2.0.0` changed `TaggableManager.set()` to require an iterable instead of varargs.\n- `3.0.0` changed the default slugification behavior to preserve Unicode characters.\n\n## Official Sources\n\n- Docs root: `https://django-taggit.readthedocs.io/en/latest/`\n- Getting started: `https://django-taggit.readthedocs.io/en/latest/getting_started.html`\n- API reference: `https://django-taggit.readthedocs.io/en/latest/api.html`\n- Forms: `https://django-taggit.readthedocs.io/en/latest/forms.html`\n- Admin: `https://django-taggit.readthedocs.io/en/latest/admin.html`\n- Serializers: `https://django-taggit.readthedocs.io/en/latest/serializers.html`\n- Custom tagging: `https://django-taggit.readthedocs.io/en/latest/custom_tagging.html`\n- Changelog: `https://django-taggit.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/django-taggit/`\n"
  },
  {
    "path": "content/django/docs/treebeard/python/DOC.md",
    "content": "---\nname: treebeard\ndescription: \"django-treebeard tree models for Django, including materialized-path, adjacency-list, nested-set, and experimental PostgreSQL ltree implementations\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.5\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,django-treebeard,trees,orm,models,admin\"\n---\n\n# django-treebeard 5.0.5 Python Package Guide\n\n## Golden Rule\n\nUse treebeard's node APIs instead of editing tree bookkeeping fields yourself. For new projects, start with `MP_Node` unless you have a clear reason to prefer `AL_Node`, `NS_Node`, or the experimental PostgreSQL `LT_Node`.\n\nThis entry targets `django-treebeard==5.0.5`. The official docs root still renders a `4.7` title, but its installation page and changelog reflect the current `5.x` support matrix.\n\n## Install\n\n```bash\npip install \"django-treebeard==5.0.5\"\n```\n\nCurrent official prerequisites for `5.0.5`:\n\n- Python `3.10+`\n- Django `5.2+`\n- Supported backends called out on PyPI: PostgreSQL, MySQL, MSSQL, SQLite\n\nIf the project is pinned to Django `4.2` or `5.1`, do not upgrade blindly. The `5.0.0` release dropped support for both.\n\n## Minimal Setup\n\nAdd `treebeard` to `INSTALLED_APPS`:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"treebeard\",\n]\n```\n\nDefine a tree model. `MP_Node` is the safest default:\n\n```python\nfrom django.db import models\nfrom treebeard.mp_tree import MP_Node\n\nclass Category(MP_Node):\n    name = models.CharField(max_length=100)\n    slug = models.SlugField(unique=True)\n\n    node_order_by = [\"name\"]\n\n    def __str__(self) -> str:\n        return self.name\n```\n\nCreate migrations normally:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\n```\n\n## Core Usage\n\nCreate nodes with treebeard helpers:\n\n```python\nroot = Category.add_root(name=\"Books\", slug=\"books\")\nfiction = root.add_child(name=\"Fiction\", slug=\"fiction\")\nhistory = root.add_child(name=\"History\", slug=\"history\")\nscifi = fiction.add_child(name=\"Sci-Fi\", slug=\"sci-fi\")\n```\n\nRead relationships from the model API:\n\n```python\nroot = Category.get_root_nodes().get(slug=\"books\")\ndescendants = root.get_descendants()\nancestors = scifi.get_ancestors()\nsubtree = Category.get_tree(parent=root)\ndepth = scifi.get_depth()\n```\n\nMove nodes with the provided API instead of editing parent/path fields:\n\n```python\nhistory.move(fiction, pos=\"sorted-child\")\n```\n\nIf `node_order_by` is set, ordering is enforced from those fields during insert and move operations. It takes precedence over manual drag-and-drop ordering in admin.\n\n## Admin Integration\n\nUse treebeard's admin classes when you want safe move controls in Django admin:\n\n```python\nfrom django.contrib import admin\nfrom treebeard.admin import TreeAdmin\nfrom treebeard.forms import movenodeform_factory\n\nfrom .models import Category\n\n@admin.register(Category)\nclass CategoryAdmin(TreeAdmin):\n    form = movenodeform_factory(Category)\n```\n\nPractical notes:\n\n- `MP_Node` and `NS_Node` get the richer AJAX admin interface.\n- `AL_Node` gets a more basic admin interface.\n- `5.0.0` renamed internal `MoveNodeForm` fields from `_position` and `_ref_node_id` to `treebeard_position` and `treebeard_ref_node`. Update custom tests, form posts, or wrappers that referenced the old field names directly.\n\n## Bulk Import And Repair\n\nUse the bulk helpers for seed data or controlled migrations:\n\n```python\npayload = Category.dump_bulk()\n\nCategory.load_bulk(\n    [\n        {\n            \"data\": {\"name\": \"Books\", \"slug\": \"books\"},\n            \"children\": [\n                {\"data\": {\"name\": \"Fiction\", \"slug\": \"fiction\"}},\n            ],\n        }\n    ]\n)\n```\n\nFor diagnostics and repair:\n\n```python\nproblems = Category.find_problems()\nCategory.fix_tree()\nCategory.fix_tree(fix_paths=True, parent=root)\n```\n\nUse `fix_tree()` as a repair tool, not part of normal writes. With `fix_paths=False`, treebeard only repairs safer metadata like `depth` and `numchild`; `fix_paths=True` is slower and intended for deeper cleanup.\n\n## Configuration And Auth\n\n`django-treebeard` is a model library, not a service client:\n\n- No package-level authentication is required.\n- Configuration is model-level: choose the node base class, optional `node_order_by`, and any custom admin/forms integration.\n- `LT_Node` is PostgreSQL-only and experimental because it depends on the `ltree` extension.\n\nImportant materialized-path settings:\n\n- The default `steplen` of `4` allows up to `1,679,615` children per node.\n- Increasing `steplen` increases child capacity but reduces maximum depth unless you also increase `path.max_length`.\n- Do not change `steplen`, `alphabet`, or `node_order_by` after you have saved the first object unless you are doing a controlled dump/reload migration.\n\n## Common Pitfalls\n\n- Do not edit internal fields like `path`, `depth`, or `numchild` directly.\n- If you override the default manager for an `MP_Node` model, subclass `MP_NodeManager`; if you change the queryset handler, subclass `MP_NodeQuerySet` too.\n- If you keep sibling or related nodes in memory across add/move operations, reload them with `refresh_from_db()` before trusting their fields.\n- `node_order_by` fields should have stable values before insert or move. Auto-populated or null values can produce surprising ordering.\n- Older code using `MP_Node.fix_tree(destructive=...)` breaks on `5.x`; use `fix_tree(fix_paths=...)`.\n- Wrap multi-step business logic in transactions when consistency matters, even though `5.x` moved internal writes into transactions and added more locking around concurrent inserts.\n\n## Choosing A Tree Type\n\n- `MP_Node`: best default for most Django projects.\n- `AL_Node`: simplest schema when you prefer a parent-pointer model and can accept more traversal work.\n- `NS_Node`: useful for read-heavy trees when more expensive writes are acceptable.\n- `LT_Node`: experimental PostgreSQL-only option when `ltree` is already part of your database strategy.\n\n## Version-Sensitive Notes\n\n- `5.0.5` was released on `2026-02-19` and reverted root-node locking added in `5.0.3` because of performance implications when adding new roots.\n- `5.0.4` fixed a `TypeError` when adding MP or LT root nodes with `node_order_by` set.\n- `5.0.3` added row locks around concurrent `add_child()` and root-creation paths to reduce race conditions.\n- `5.0.2` refreshes moved `MP` and `NS` nodes from the database automatically, but other affected in-memory objects may still need `refresh_from_db()`.\n- `5.0.0` was a major release: raw SQL tree operations were rewritten to Django ORM, experimental `LT_Node` support was added, Django `6.0` and Python `3.14` support were added, Django `4.2` and `5.1` support were dropped, `MoveNodeForm` internals were renamed, and `MP_Node.fix_tree()` no longer accepts the old `destructive` argument.\n- The official docs site is slightly misleading for version discovery: `/en/latest/` still shows a `4.7 documentation` title even though the installation page and changelog contain current `5.x` guidance.\n\n## Official Sources\n\n- Docs root: https://django-treebeard.readthedocs.io/en/latest/\n- Installation: https://django-treebeard.readthedocs.io/en/latest/install.html\n- Tutorial: https://django-treebeard.readthedocs.io/en/latest/tutorial.html\n- Materialized path API: https://django-treebeard.readthedocs.io/en/latest/mp_tree.html\n- Caveats: https://django-treebeard.readthedocs.io/en/latest/caveats.html\n- Admin: https://django-treebeard.readthedocs.io/en/latest/admin.html\n- Changelog: https://django-treebeard.readthedocs.io/en/latest/changes.html\n- PyPI release page: https://pypi.org/project/django-treebeard/5.0.5/\n"
  },
  {
    "path": "content/django/docs/waffle/python/DOC.md",
    "content": "---\nname: waffle\ndescription: \"django-waffle package guide for Django feature flags, switches, and percentage rollouts\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.0.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django-waffle,django,feature-flags,rollouts,switches,experiments,python\"\n---\n\n# django-waffle 5.0.0 Python Package Guide\n\n## What It Does\n\n`django-waffle` adds feature gating to Django with three primitives:\n\n- `Flag`: request-aware feature flags with user, group, staff, authenticated, language, percentage, testing, and rollout controls\n- `Switch`: global on or off toggles\n- `Sample`: random percentage sampling when you do not have or need a request object\n\nUse it for staged rollouts, kill switches, and limited experiments. Do not treat it as an authorization system or a replacement for Django permissions.\n\n## Install\n\n```bash\npython -m pip install \"django-waffle==5.0.0\"\n```\n\nCommon equivalents:\n\n```bash\nuv add \"django-waffle==5.0.0\"\npoetry add \"django-waffle==5.0.0\"\n```\n\n## Minimal Setup\n\nAdd the app and middleware, then run migrations:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"waffle\",\n]\n\nMIDDLEWARE = [\n    # ...\n    \"waffle.middleware.WaffleMiddleware\",\n    # ...\n]\n```\n\n```bash\npython manage.py migrate\n```\n\nWaffle stores flags, switches, and samples in Django models, so migrations have to run before you call the helper APIs.\n\n## Choose The Right Primitive\n\n### Flag\n\nUse `Flag` when activation depends on the current request or current user.\n\nImportant controls from upstream:\n\n- `everyone` for a global tri-state override\n- testing mode through query string plus cookies\n- user and group targeting\n- superuser, staff, and authenticated checks\n- language matching\n- percentage rollout\n- rollout mode for sticky-on behavior as percentages increase\n\n### Switch\n\nUse `Switch` for global maintenance gates and simple kill switches:\n\n```python\nimport waffle\n\nif waffle.switch_is_active(\"billing-maintenance\"):\n    enable_read_only_mode()\n```\n\n### Sample\n\nUse `Sample` for random percentage experiments when no request object is involved:\n\n```python\nimport waffle\n\nsearch_v2_on = waffle.sample_is_active(\"search-v2\")\nif search_v2_on:\n    use_search_v2()\n```\n\nImportant: `sample_is_active()` is random on each evaluation. If you need a stable answer for the rest of the code path, store the result in a local variable and reuse it.\n\n## Core Usage\n\n### Gate logic inside a view\n\n```python\nimport waffle\nfrom django.http import HttpResponse\n\ndef checkout(request):\n    if waffle.flag_is_active(request, \"new-checkout\"):\n        return HttpResponse(\"new flow\")\n    return HttpResponse(\"old flow\")\n```\n\nUse `flag_is_active(request, ...)` for request-aware checks, `switch_is_active(...)` for global toggles, and `sample_is_active(...)` for random sampling.\n\n### Gate an entire view with a decorator\n\n```python\nfrom waffle.decorators import waffle_flag\n\n@waffle_flag(\"new-checkout\")\ndef checkout(request):\n    ...\n```\n\nWhen the named flag is inactive, the wrapped view returns `404` by default. You can also pass a redirect target. Waffle supports inverted decorators such as `@waffle_flag(\"!new-checkout\")` and `@waffle_switch(\"!billing-maintenance\")`.\n\nThere is no sample decorator because sample evaluation is intentionally random.\n\n### Gate class-based views\n\n```python\nfrom django.views.generic import TemplateView\nfrom waffle.mixins import WaffleFlagMixin\n\nclass NewCheckoutView(WaffleFlagMixin, TemplateView):\n    waffle_flag = \"new-checkout\"\n    template_name = \"checkout/new.html\"\n```\n\nWaffle also provides `WaffleSwitchMixin` and `WaffleSampleMixin`.\n\n### Gate templates\n\n```django\n{% load waffle_tags %}\n\n{% flag \"new-checkout\" %}\n  <a href=\"/checkout/new/\">Try the new checkout</a>\n{% else %}\n  <a href=\"/checkout/\">Checkout</a>\n{% endflag %}\n```\n\nTemplate tags are available for `flag`, `switch`, and `sample`. For Jinja2 templates, Waffle exposes a `waffle` object so you can write checks such as `waffle.flag(\"new-checkout\")`.\n\n## Managing Flags, Switches, And Samples\n\nUse Django admin for manual control or the built-in management commands for scripted updates.\n\nCreate or update a flag:\n\n```bash\npython manage.py waffle_flag new-checkout --create --percent=10 --rollout\n```\n\nTurn a switch on:\n\n```bash\npython manage.py waffle_switch billing-maintenance on --create\n```\n\nSet a sample percentage:\n\n```bash\npython manage.py waffle_sample search-v2 25.0 --create\n```\n\nUseful list and cleanup commands:\n\n```bash\npython manage.py waffle_flag -l\npython manage.py waffle_switch -l\npython manage.py waffle_sample -l\npython manage.py waffle_delete --flags new-checkout --switches billing-maintenance\n```\n\n## Configuration And Auth Notes\n\nWaffle integrates with Django request and auth state. Flags can target authenticated users, staff, superusers, groups, specific users, and request languages.\n\nThe settings most likely to matter in production are:\n\n- `WAFFLE_OVERRIDE`: query-string overrides for manual or end-to-end testing\n- `WAFFLE_COOKIE` and `WAFFLE_TEST_COOKIE`: cookie naming\n- `WAFFLE_MAX_AGE`: cookie lifetime\n- `WAFFLE_SECURE`: whether Waffle cookies are marked secure\n- `WAFFLE_CACHE_NAME` and `WAFFLE_CACHE_PREFIX`: cache selection and namespacing\n- `WAFFLE_READ_FROM_WRITE_DB`: read from the write database if replica lag would make checks stale\n- `WAFFLE_CREATE_MISSING_FLAGS`, `WAFFLE_CREATE_MISSING_SWITCHES`, `WAFFLE_CREATE_MISSING_SAMPLES`: auto-create missing objects instead of falling back silently\n- `WAFFLE_LOG_MISSING_FLAGS`, `WAFFLE_LOG_MISSING_SWITCHES`, `WAFFLE_LOG_MISSING_SAMPLES`: log missing definitions so typos surface quickly\n- `WAFFLE_ENABLE_ADMIN_PAGES`: disable built-in admin pages if you are replacing them\n\nPractical defaults:\n\n- keep `WAFFLE_OVERRIDE = False` unless you have a controlled testing need\n- keep auto-create settings off in production\n- turn on missing-item logging outside local development\n- use a dedicated cache prefix if you are changing Waffle versions or custom models across deployments\n\n## Custom Models\n\nWaffle supports swappable models:\n\n- `WAFFLE_FLAG_MODEL`\n- `WAFFLE_SWITCH_MODEL`\n- `WAFFLE_SAMPLE_MODEL`\n\nSet these only at project start. Upstream warns that changing them later will not yield workable migrations. If you use a custom model, define it before the first `migrate` and run `makemigrations` first.\n\n## Testing\n\nFor automated tests, prefer Waffle's test helpers instead of mutating database state manually:\n\n```python\nfrom waffle.testutils import override_flag\n\ndef test_checkout_uses_new_flow(client):\n    with override_flag(\"new-checkout\", active=True):\n        response = client.get(\"/checkout/\")\n        assert response.status_code == 200\n```\n\nWaffle also provides `override_switch` and `override_sample`. These restore previous state automatically and delete temporary objects they created.\n\nFor external browser-style tests that talk to a running server in a separate process, `WAFFLE_OVERRIDE` allows per-request control through the query string, for example `GET /checkout/?new-checkout=1`.\n\n## Common Pitfalls\n\n- Using `Sample` for logic that must stay stable across multiple checks in one request or task.\n- Leaving `WAFFLE_OVERRIDE` enabled outside controlled testing.\n- Turning on `WAFFLE_CREATE_MISSING_*` in production and then hiding typos in flag names.\n- Changing `WAFFLE_FLAG_MODEL`, `WAFFLE_SWITCH_MODEL`, or `WAFFLE_SAMPLE_MODEL` after the first migration.\n- Assuming Waffle is an authorization system.\n- Forgetting that rollout mode changes how \"off\" cookies behave as the rollout percentage increases.\n\n## Version-Sensitive Notes\n\n- `5.0.0` drops support for Django `3.2`, `4.0`, and `4.1`, and drops Python `3.8`.\n- `5.0.0` adds Django `5.2` support.\n- Current package metadata requires Python `>=3.9` and Django `>=4.2`.\n- `5.0.0` includes a breaking fix for `flag.everyone`: custom code that depends on `Flag.is_active_for_user()` should be rechecked after upgrading from older releases.\n- The docs URL, `https://waffle.readthedocs.io/en/latest/`, displayed `5.0.0` on `2026-03-12`, but it is a floating docs root. For behavior-sensitive debugging, verify against the versioned `v5.0.0` page plus the `v5.0.0` release and changelog.\n\n## Official Sources\n\n- Docs index: https://waffle.readthedocs.io/en/stable/index.html\n- Installation: https://waffle.readthedocs.io/en/stable/starting/installation.html\n- Configuration: https://waffle.readthedocs.io/en/stable/starting/configuring.html\n- Flag reference: https://waffle.readthedocs.io/en/stable/types/flag.html\n- Switch reference: https://waffle.readthedocs.io/en/stable/types/switch.html\n- Sample reference: https://waffle.readthedocs.io/en/stable/types/sample.html\n- Views: https://waffle.readthedocs.io/en/stable/usage/views.html\n- Decorators: https://waffle.readthedocs.io/en/stable/usage/decorators.html\n- Templates: https://waffle.readthedocs.io/en/stable/usage/templates.html\n- CLI: https://waffle.readthedocs.io/en/stable/usage/cli.html\n- Automated testing: https://waffle.readthedocs.io/en/stable/testing/automated.html\n- Versioned 5.0.0 flag page: https://waffle.readthedocs.io/en/v5.0.0/types/flag.html\n- PyPI: https://pypi.org/project/django-waffle/\n- Repository: https://github.com/django-waffle/django-waffle\n- Changelog: https://github.com/django-waffle/django-waffle/blob/master/CHANGES\n- Release: https://github.com/django-waffle/django-waffle/releases/tag/v5.0.0\n"
  },
  {
    "path": "content/django/docs/webpack-loader/python/DOC.md",
    "content": "---\nname: webpack-loader\ndescription: \"django-webpack-loader package guide for integrating Django templates with webpack bundle output\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"django,webpack,staticfiles,templates,frontend,assets\"\n---\n\n# django-webpack-loader Python Package Guide\n\n## What It Does\n\n`django-webpack-loader` connects Django templates to assets built by Webpack. It reads the JSON stats file generated by `webpack-bundle-tracker`, then renders the right `<script>` and `<link>` tags from Django templates.\n\nThis entry is pinned to `django-webpack-loader==3.2.3`, which matches the version used here and the current PyPI release as of March 12, 2026.\n\n## Supported Stack\n\nPyPI classifiers for `3.2.3` list:\n\n- Python `3.8` through `3.13`\n- Django `4.2`, `5.0`, `5.1`, and `5.2`\n\nThe maintainer README says support generally tracks Python, Django, and Node LTS releases, and the exact tested matrix lives in `tests/tox.ini`.\n\nExamples in the upstream README assume Webpack 5.\n\n## Install\n\nInstall both sides of the integration:\n\n```bash\npip install django-webpack-loader==3.2.3\nnpm install --save-dev webpack-bundle-tracker\n```\n\nCommon Python package-manager alternatives:\n\n```bash\nuv add django-webpack-loader==3.2.3\npoetry add django-webpack-loader==3.2.3\n```\n\n`django-webpack-loader` does not build assets itself. You still need a working Webpack config and a build step that writes `webpack-stats.json`.\n\n## Minimal Setup\n\n### 1. Configure Webpack to emit bundle files and a stats file\n\n```javascript\n// webpack.config.js\nconst path = require(\"path\");\nconst BundleTracker = require(\"webpack-bundle-tracker\");\n\nmodule.exports = {\n  context: __dirname,\n  entry: {\n    main: \"./assets/js/index.js\",\n  },\n  output: {\n    path: path.resolve(__dirname, \"assets/webpack_bundles/\"),\n    publicPath: \"auto\",\n    filename: \"[name]-[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new BundleTracker({\n      path: __dirname,\n      filename: \"webpack-stats.json\",\n    }),\n  ],\n};\n```\n\nImportant alignment points:\n\n- Webpack `output.path`\n- Webpack `output.publicPath`\n- Django `STATICFILES_DIRS`\n- Django `WEBPACK_LOADER.DEFAULT.BUNDLE_DIR_NAME`\n- Django `WEBPACK_LOADER.DEFAULT.STATS_FILE`\n\nIf these drift, tag generation usually breaks even though the bundle build itself succeeded.\n\n### 2. Configure Django\n\n```python\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent\nDEBUG = True\n\nINSTALLED_APPS = [\n    # ...\n    \"webpack_loader\",\n]\n\nSTATIC_URL = \"/static/\"\nSTATICFILES_DIRS = [\n    BASE_DIR / \"assets\",\n]\n\nWEBPACK_LOADER = {\n    \"DEFAULT\": {\n        \"BUNDLE_DIR_NAME\": \"webpack_bundles/\",\n        \"CACHE\": not DEBUG,\n        \"STATS_FILE\": BASE_DIR / \"webpack-stats.json\",\n        \"POLL_INTERVAL\": 0.1,\n        \"IGNORE\": [r\".+\\\\.hot-update.js\", r\".+\\\\.map\"],\n    }\n}\n```\n\nWhat the main settings do:\n\n- `BUNDLE_DIR_NAME`: bundle subpath inside your static assets tree\n- `CACHE`: usually `False` in development and `True` in production\n- `STATS_FILE`: absolute path to the JSON file emitted by `webpack-bundle-tracker`\n- `POLL_INTERVAL`: poll cadence when `CACHE=False`\n- `IGNORE`: regexes for files that should not render as template tags\n\nIn production, `POLL_INTERVAL` is ignored because the loader reads the stats file once and keeps bundle paths in memory.\n\n### 3. Build frontend assets before rendering templates\n\nDevelopment:\n\n```bash\n# shell 1\nnpx webpack --mode=development --watch\n\n# shell 2\npython manage.py runserver\n```\n\nProduction:\n\n```bash\nNODE_ENV=production npx webpack --progress --bail --mode=production\npython manage.py collectstatic --noinput\n```\n\nRun the Webpack build before `collectstatic`. If you reverse that order, Django may collect stale or missing bundles.\n\n## Core Usage\n\n### Render bundles in templates\n\n```django\n{% load render_bundle from webpack_loader %}\n<!doctype html>\n<html>\n  <head>\n    {% render_bundle \"main\" \"css\" %}\n  </head>\n  <body>\n    {% render_bundle \"main\" \"js\" %}\n  </body>\n</html>\n```\n\n`render_bundle` looks up the entrypoint in `webpack-stats.json` and emits the matching tags.\n\n### Preload assets\n\n```django\n{% load render_bundle from webpack_loader %}\n{% render_bundle \"main\" \"css\" is_preload=True %}\n{% render_bundle \"main\" \"js\" is_preload=True %}\n```\n\nUse `is_preload=True` when you want preload link tags in addition to normal rendering.\n\n### Avoid duplicate shared chunks\n\n```django\n{% load render_bundle from webpack_loader %}\n{% render_bundle \"vendor\" \"js\" skip_common_chunks=True %}\n{% render_bundle \"dashboard\" \"js\" skip_common_chunks=True %}\n```\n\nFor `skip_common_chunks` to work, the template context must include `request`. In typical Django setups that means keeping `django.template.context_processors.request` enabled.\n\n### Access the public URL for a Webpack-managed static file\n\n```django\n{% load webpack_static from webpack_loader %}\n<img src=\"{% webpack_static 'logo.png' %}\" alt=\"Logo\">\n```\n\n`webpack_static` returns the public path for the original asset. It does not necessarily return the hashed filename generated when that asset is imported and transformed inside JavaScript.\n\n### Get file URLs without rendering tags\n\n```django\n{% load get_files from webpack_loader %}\n{% get_files \"editor\" \"css\" as editor_css_files %}\n<link rel=\"stylesheet\" href=\"{{ editor_css_files.0.url }}\">\n```\n\nUse `get_files` when another library needs a URL rather than a rendered `<script>` or `<link>` tag.\n\n## Configuration Patterns\n\n### Multiple Webpack stats files\n\n```python\nWEBPACK_LOADER = {\n    \"DEFAULT\": {\n        \"BUNDLE_DIR_NAME\": \"webpack_bundles/\",\n        \"STATS_FILE\": BASE_DIR / \"webpack-stats.json\",\n    },\n    \"DASHBOARD\": {\n        \"BUNDLE_DIR_NAME\": \"dashboard_bundles/\",\n        \"STATS_FILE\": BASE_DIR / \"webpack-stats-dashboard.json\",\n    },\n}\n```\n\n```django\n{% load render_bundle from webpack_loader %}\n{% render_bundle \"main\" config=\"DASHBOARD\" extension=\"js\" %}\n```\n\nUse separate configs when different frontend builds emit different stats files.\n\n### Custom loader classes and remote stats files\n\n`LOADER_CLASS` lets you replace the default filesystem-backed loader. This is the main extension point when your stats file lives in object storage, a cache, a database, or an authenticated HTTP endpoint.\n\n```python\nimport requests\nfrom webpack_loader.loaders import WebpackLoader\n\nclass ExternalWebpackLoader(WebpackLoader):\n    def load_assets(self):\n        response = requests.get(\n            self.config[\"STATS_URL\"],\n            headers={\"Authorization\": f\"Bearer {self.config['STATS_TOKEN']}\"},\n            timeout=5,\n        )\n        response.raise_for_status()\n        return response.json()\n\nWEBPACK_LOADER = {\n    \"DEFAULT\": {\n        \"LOADER_CLASS\": \"project.loaders.ExternalWebpackLoader\",\n        \"STATS_URL\": \"https://assets.example.com/webpack-stats.json\",\n        \"STATS_TOKEN\": \"...\",\n    }\n}\n```\n\nThe package has no built-in auth model. If stats come from a protected service, keep credentials inside your loader implementation and normal Django settings or secret management.\n\n### Security-related settings\n\nUpstream documents these options for stricter frontend delivery:\n\n- `INTEGRITY`: emit Subresource Integrity attributes when the stats file includes integrity hashes\n- `CROSSORIGIN`: set the `crossorigin` attribute for cross-origin asset loading\n- `CSP_NONCE`: add nonces for `django-csp` with strict CSP policies\n- `TIMEOUT`: bound how long the loader waits for an in-progress build\n\nThese settings only help if the Webpack side is configured consistently. For example, `INTEGRITY` depends on integrity data being present in the stats output.\n\n## Testing\n\nTemplate rendering fails in tests if the test process expects a real stats file but no frontend build ran first. The documented escape hatch is:\n\n```python\nWEBPACK_LOADER[\"DEFAULT\"][\"LOADER_CLASS\"] = \"webpack_loader.loaders.FakeWebpackLoader\"\n```\n\nUse that in test settings when unit tests should render templates without invoking the frontend pipeline.\n\n## Common Pitfalls\n\n### Stats file path mismatch\n\nThe most common failure is that Webpack writes `webpack-stats.json` to one location while Django reads from another. Verify the exact absolute path on both sides.\n\n### `STATICFILES_DIRS`, `BUNDLE_DIR_NAME`, and `output.path` do not describe the same tree\n\nIf these settings disagree, `render_bundle` can emit URLs that `collectstatic` never published.\n\n### Build order is wrong in production\n\nRun Webpack first, then `collectstatic`. If a platform auto-runs `collectstatic`, override that behavior and invoke it after the Webpack build.\n\n### `skip_common_chunks` does not work\n\nThis usually means `request` is missing from the template context.\n\n### `webpack_static` returns a different file than JavaScript imports use\n\nThat is expected when Webpack post-processes or hashes imported assets. `webpack_static` is for the original asset path.\n\n### Cross-origin bundles need more than just a CDN URL\n\nIf bundles load from another origin, verify `publicPath`, and if you enable Subresource Integrity also set `CROSSORIGIN` consistently.\n\n## Version-Sensitive Notes\n\n- `3.2.3` is the current PyPI release documented here.\n- Upstream examples are written for Webpack 5.\n- The maintainer README recommends keeping at least minor-version parity between `django-webpack-loader` and `webpack-bundle-tracker` when dealing with older migrations.\n- If you are migrating code from `django-webpack-loader<1.0.0`, you also need `webpack-bundle-tracker>=1.0.0`.\n- For exact tested compatibility, check the package's `tests/tox.ini` in the upstream repository rather than guessing from third-party blog posts.\n\n## Official Sources\n\n- Repository / maintainer docs: https://github.com/django-webpack/django-webpack-loader\n- PyPI package page: https://pypi.org/project/django-webpack-loader/\n"
  },
  {
    "path": "content/dlt/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"dlt package guide for Python data-loading pipelines with destinations, sources, config injection, and incremental loading\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.23.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dlt,etl,elt,data-loading,pipeline,python\"\n---\n\n# dlt Python Package Guide\n\n## Golden Rule\n\nUse explicit `dlt.pipeline(...)` objects for real projects, install the destination extra you actually load into, and treat `pipeline_name` as persistent state. `dlt` stores schemas, load packages, and incremental state under that pipeline name, so accidental reuse changes behavior across runs.\n\n## What dlt Is For\n\n`dlt` is a Python-first data loading library for extracting data, normalizing nested structures into tables, and loading them into a destination such as DuckDB, Postgres, BigQuery, filesystem-backed data lakes, and other supported targets.\n\nThe main building blocks are:\n\n- `dlt.pipeline(...)`: runtime, state, destination, and dataset configuration\n- `@dlt.resource`: one stream of records, usually one logical table\n- `@dlt.source`: a group of resources that should run together\n- `pipeline.run(...)`: extract, normalize, and load\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"dlt==1.23.0\"\n```\n\nFor actual loading, install the destination extra too. Common examples:\n\n```bash\npython -m pip install \"dlt[duckdb]==1.23.0\"\npython -m pip install \"dlt[postgres]==1.23.0\"\npython -m pip install \"dlt[bigquery]==1.23.0\"\n```\n\nIf you want the CLI scaffolding and workspace features:\n\n```bash\npython -m pip install \"dlt[cli]==1.23.0\"\n```\n\nTo start from a generated template instead of hand-writing a pipeline:\n\n```bash\ndlt init github_api duckdb\npython -m pip install -r requirements.txt\n```\n\n## Quickest Working Pipeline\n\nFor simple Python data structures, start with an explicit pipeline and load a list of dictionaries:\n\n```python\nimport dlt\n\npipeline = dlt.pipeline(\n    pipeline_name=\"users_ingest\",\n    destination=\"duckdb\",\n    dataset_name=\"raw_data\",\n)\n\nload_info = pipeline.run(\n    [\n        {\"id\": 1, \"name\": \"Ada\"},\n        {\"id\": 2, \"name\": \"Grace\"},\n    ],\n    table_name=\"users\",\n    write_disposition=\"append\",\n)\n\nprint(load_info)\n```\n\n`pipeline.run(...)` returns a `load_info` object with load package and destination details. Use this pattern when you already have Python data in memory.\n\n## Reusable Source And Resource Pattern\n\nUse `@dlt.resource` for one logical feed and `@dlt.source` to group related feeds. This is the pattern to prefer for API integrations and recurring jobs.\n\n```python\nimport dlt\nfrom dlt.sources.helpers import requests\n\n@dlt.resource(primary_key=\"id\", write_disposition=\"merge\")\ndef users(\n    base_url=dlt.config.value,\n    api_token: str = dlt.secrets.value,\n    updated_at=dlt.sources.incremental(\n        \"updated_at\",\n        initial_value=\"1970-01-01T00:00:00Z\",\n    ),\n):\n    response = requests.get(\n        f\"{base_url}/users\",\n        headers={\"Authorization\": f\"Bearer {api_token}\"},\n        params={\"updated_since\": updated_at.start_value},\n    )\n    response.raise_for_status()\n    yield response.json()[\"users\"]\n\n@dlt.source\ndef users_source():\n    return users\n\npipeline = dlt.pipeline(\n    pipeline_name=\"users_ingest\",\n    destination=\"duckdb\",\n    dataset_name=\"raw_data\",\n)\n\nload_info = pipeline.run(users_source())\nprint(load_info)\n```\n\nWhy this pattern matters:\n\n- `dlt.config.value` marks non-secret config for injection\n- `dlt.secrets.value` marks secrets for injection\n- `dlt.sources.incremental(...)` keeps cursor state between runs\n- `primary_key=\"id\"` plus `write_disposition=\"merge\"` makes updates/upserts practical for mutable entities\n\n## Configuration And Secrets\n\n`dlt` resolves configuration in this order:\n\n1. Environment variables\n2. `.dlt/secrets.toml` and `.dlt/config.toml`\n3. Supported vault providers\n4. Custom providers\n5. Default argument values\n\nUse `.dlt/config.toml` for non-secret settings and `.dlt/secrets.toml` for tokens, passwords, and credentials.\n\nExample for the `users_source()` function above:\n\n```toml\n# .dlt/config.toml\n[sources.users_source]\nbase_url = \"https://api.example.com\"\n```\n\n```toml\n# .dlt/secrets.toml\n[sources.users_source]\napi_token = \"replace-me\"\n```\n\nEnvironment variable equivalents:\n\n```bash\nexport SOURCES__USERS_SOURCE__BASE_URL=\"https://api.example.com\"\nexport SOURCES__USERS_SOURCE__API_TOKEN=\"replace-me\"\n```\n\nPractical notes:\n\n- Environment variables override TOML values.\n- `config.toml` can be committed; `secrets.toml` should not be.\n- `dlt` also reads `~/.dlt/config.toml` and `~/.dlt/secrets.toml`, merged behind project-local values.\n- If a secret is in the wrong place, `dlt` can raise instead of silently accepting it.\n\n## Destination Setup\n\nThe destination is selected when you create the pipeline:\n\n```python\npipeline = dlt.pipeline(\n    pipeline_name=\"my_pipeline\",\n    destination=\"duckdb\",\n    dataset_name=\"analytics\",\n)\n```\n\nFor local development, `duckdb` is the lowest-friction default. For warehouse targets like Postgres or BigQuery, install the matching extra and provide destination credentials under `destination.<name>.credentials`.\n\nTypical destination credential sections:\n\n```toml\n[destination.postgres.credentials]\ndatabase = \"analytics\"\nusername = \"loader\"\npassword = \"replace-me\"\nhost = \"localhost\"\nport = 5432\n```\n\n```toml\n[destination.bigquery.credentials]\nproject_id = \"my-project\"\nclient_email = \"svc@my-project.iam.gserviceaccount.com\"\nprivate_key = \"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n\"\n```\n\n## Write Disposition And Incremental Loading\n\nThe core choice is how each resource writes data:\n\n- `append`: immutable events or logs\n- `merge`: mutable entities you update over time\n- `replace`: full snapshot refreshes\n\nExample merge resource:\n\n```python\n@dlt.resource(primary_key=\"id\", write_disposition=\"merge\")\ndef accounts():\n    yield [{\"id\": 1, \"email\": \"a@example.com\"}]\n```\n\nExample incremental cursor:\n\n```python\n@dlt.resource(primary_key=\"id\")\ndef events(\n    updated_at=dlt.sources.incremental(\n        \"updated_at\",\n        initial_value=\"1970-01-01T00:00:00Z\",\n    )\n):\n    ...\n```\n\nRules that matter in practice:\n\n- Use `append` for records that never change.\n- Use `merge` with `primary_key` or `merge_key` for mutable records.\n- `pipeline.run(..., write_disposition=\"replace\")` forces a full refresh for that run and resets incremental state for incremental resources.\n- `dlt` can deduplicate incremental results, but a stable `primary_key` makes behavior more predictable and efficient.\n\n## State, Working Directories, And Inspection\n\nEach pipeline keeps local state and artifacts in `~/.dlt/pipelines/<pipeline_name>` by default. Two scripts using the same `pipeline_name` will share that state.\n\nUse these options deliberately:\n\n- `pipeline_name`: stable identifier for stateful production pipelines\n- `pipelines_dir`: separate dev, staging, and prod working directories\n- `dev_mode=True`: create disposable datasets while iterating on a pipeline\n\nUseful inspection patterns:\n\n```python\nwith pipeline.sql_client() as client:\n    with client.execute_query(\"SELECT COUNT(*) FROM users\") as cursor:\n        print(cursor.fetchall())\n```\n\n```bash\ndlt pipeline users_ingest info\n```\n\n## Common Pitfalls\n\n- Installing plain `dlt` without the destination extra and then expecting the destination driver to exist.\n- Reusing the same `pipeline_name` across unrelated scripts and unintentionally sharing state, schema, and incremental checkpoints.\n- Using `replace` when you meant `merge`, which can wipe and reload tables instead of updating them.\n- Defining secrets in `config.toml` instead of `secrets.toml`.\n- Assuming `dlt.sources.incremental(...)` filters the upstream API for you. It tracks cursor state, but your resource still needs to pass `start_value` to the API when the API supports server-side filtering.\n- Forgetting that `pipeline.run(...)` syncs destination state and processes pending packages before extracting new data.\n- Binding config to the wrong source section name. In `1.23.0`, `dlt` added a compact lookup path `sources.<name>.<key>` in addition to the older fully qualified source path. That helps many setups, but it can also unexpectedly resolve values that older versions ignored.\n\n## Version-Sensitive Notes For 1.23.0\n\n- PyPI shows `1.23.0` as the current stable release, published on March 6, 2026.\n- PyPI metadata requires Python `>=3.9.2,<3.15`; the project description also says Python 3.14 support is still experimental because some optional extras are not available yet.\n- The `1.23.0` release removed the legacy Streamlit dashboard behind `dlt pipeline show`. If older docs or blog posts still mention that command, treat them as pre-`1.23.0`.\n- The `1.23.0` release added the compact source config lookup path `sources.<name>.<key>` alongside the older fully qualified source path.\n\n## Official Sources\n\n- Docs root: https://dlthub.com/docs/\n- API reference: https://dlthub.com/docs/api_reference/\n- Create-a-pipeline walkthrough: https://dlthub.com/docs/walkthroughs/create-a-pipeline\n- Configuration and secrets: https://dlthub.com/docs/general-usage/credentials/setup\n- Incremental loading: https://dlthub.com/docs/general-usage/incremental-loading\n- Cursor-based incremental loading: https://dlthub.com/docs/general-usage/incremental/cursor\n- Resource guide: https://dlthub.com/docs/general-usage/resource\n- Pipeline guide: https://dlthub.com/docs/general-usage/pipeline\n- PyPI package page: https://pypi.org/project/dlt/\n- GitHub releases: https://github.com/dlt-hub/dlt/releases\n"
  },
  {
    "path": "content/docker/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Docker SDK for Python package for connecting to Docker Engine, running containers, building images, and working with registries\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"docker,containers,python,engine,registry,images\"\n---\n\n# Docker SDK for Python Package Guide\n\n## Golden Rule\n\nUse the `docker` PyPI package as a client for an already running Docker Engine or Docker Desktop daemon. This package does not install Docker itself. In most projects, start with `docker.from_env()`, verify the daemon with `ping()`, and prefer `version=\"auto\"` over relying on constructor defaults.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"docker==7.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"docker==7.1.0\"\npoetry add \"docker==7.1.0\"\n```\n\nOptional websocket support for `attach_socket(..., ws=True)`:\n\n```bash\npython -m pip install \"docker[websockets]==7.1.0\"\n```\n\nNotes:\n\n- `docker[tls]` is a no-op in current releases because TLS support ships in the main package.\n- Installing this package is not enough by itself; Docker Engine or Docker Desktop must also be installed and running somewhere reachable.\n\n## Connect To The Daemon\n\n`docker.from_env()` is the normal entry point. It reads the same environment variables as the Docker CLI, including `DOCKER_HOST`, `DOCKER_TLS_VERIFY`, and `DOCKER_CERT_PATH`.\n\n```python\nimport docker\n\nclient = docker.from_env()\n\ntry:\n    client.ping()\n    print(\"Docker daemon is reachable\")\n    print(client.version()[\"Version\"])\nfinally:\n    client.close()\n```\n\nIf you need explicit connection settings, build the client yourself and pass `version=\"auto\"`:\n\n```python\nimport docker\n\nclient = docker.DockerClient(\n    base_url=\"unix:///var/run/docker.sock\",\n    version=\"auto\",\n    timeout=60,\n)\n```\n\nRemote daemon examples:\n\n```python\nimport docker\n\nclient = docker.DockerClient(\n    base_url=\"tcp://docker.example.internal:2376\",\n    version=\"auto\",\n    tls=True,\n)\n```\n\n```python\nimport docker\n\nclient = docker.from_env(use_ssh_client=True)\n```\n\nUse the high-level `DockerClient` unless you need an endpoint that is only exposed through the low-level API. The low-level client is available as `client.api` or directly as `docker.APIClient(...)`.\n\n## Authentication And Configuration\n\n### Daemon connection config\n\nCommon environment variables:\n\n- `DOCKER_HOST`: daemon URL such as `unix:///var/run/docker.sock`, `npipe:////./pipe/docker_engine`, `tcp://host:2376`, or `ssh://user@host`\n- `DOCKER_TLS_VERIFY=1`: enable TLS verification for TCP connections\n- `DOCKER_CERT_PATH`: directory containing client certs for TLS auth\n\nExample with an explicit TLS config:\n\n```python\nimport docker\nfrom docker.tls import TLSConfig\n\ntls_config = TLSConfig(\n    client_cert=(\"/path/client-cert.pem\", \"/path/client-key.pem\"),\n    ca_cert=\"/path/ca.pem\",\n    verify=True,\n)\n\nclient = docker.DockerClient(\n    base_url=\"tcp://docker.example.internal:2376\",\n    version=\"auto\",\n    tls=tls_config,\n)\n```\n\n### Registry auth\n\nLog in before pulls or pushes that require credentials:\n\n```python\nimport docker\n\nclient = docker.from_env()\n\nclient.api.login(\n    username=\"registry-user\",\n    password=\"registry-password\",\n    registry=\"https://index.docker.io/v1/\",\n)\n```\n\nFor one-off operations, you can also pass `auth_config={\"username\": \"...\", \"password\": \"...\"}` to image pull or push calls instead of mutating shared client state.\n\n## Core Usage\n\n### Run a one-off container\n\nWhen `detach=False` (the default), `containers.run()` returns the container logs as bytes.\n\n```python\nimport docker\n\nclient = docker.from_env()\n\noutput = client.containers.run(\n    \"alpine:3.20\",\n    [\"echo\", \"hello from docker\"],\n    auto_remove=True,\n)\n\nprint(output.decode(\"utf-8\").strip())\nclient.close()\n```\n\n### Run a long-lived container\n\nWhen `detach=True`, `containers.run()` returns a `Container` object instead.\n\n```python\nimport docker\n\nclient = docker.from_env()\n\ncontainer = client.containers.run(\n    \"nginx:1.27-alpine\",\n    detach=True,\n    name=\"example-nginx\",\n    ports={\"80/tcp\": 8080},\n    environment={\"NGINX_ENTRYPOINT_QUIET_LOGS\": \"1\"},\n)\n\ntry:\n    print(container.status)\n    container.reload()\n    print(container.logs(tail=20).decode(\"utf-8\"))\nfinally:\n    container.remove(force=True)\n    client.close()\n```\n\n`container.attrs` is cached. Call `container.reload()` before reading status or other mutable metadata that may have changed on the daemon.\n\n### Execute a command in an existing container\n\n```python\nimport docker\n\nclient = docker.from_env()\ncontainer = client.containers.run(\"python:3.12-alpine\", [\"sleep\", \"300\"], detach=True)\n\ntry:\n    result = container.exec_run([\"python\", \"-c\", \"print('ok')\"])\n    print(result.exit_code)\n    print(result.output.decode(\"utf-8\").strip())\nfinally:\n    container.remove(force=True)\n    client.close()\n```\n\n### Pull and inspect images\n\n```python\nimport docker\nfrom docker.errors import ImageNotFound\n\nclient = docker.from_env()\n\ntry:\n    image = client.images.pull(\"redis\", tag=\"7-alpine\")\n    print(image.tags)\n    print(client.images.get(\"redis:7-alpine\").id)\nexcept ImageNotFound:\n    print(\"Image was not found in the registry\")\nfinally:\n    client.close()\n```\n\n### Build an image from a local directory\n\n`images.build()` returns a tuple of `(image, build_logs)`.\n\n```python\nimport docker\n\nclient = docker.from_env()\n\nimage, build_logs = client.images.build(\n    path=\".\",\n    tag=\"my-app:dev\",\n    rm=True,\n)\n\nfor chunk in build_logs:\n    if \"stream\" in chunk:\n        print(chunk[\"stream\"], end=\"\")\n\nprint(image.tags)\nclient.close()\n```\n\n### Push an image and stream progress\n\nFor structured push progress, use the low-level API with `stream=True` and `decode=True`:\n\n```python\nimport docker\n\nclient = docker.from_env()\n\nfor event in client.api.push(\n    repository=\"yourname/my-app\",\n    tag=\"latest\",\n    stream=True,\n    decode=True,\n):\n    print(event)\n\nclient.close()\n```\n\n## Common Errors And Pitfalls\n\n- `docker` the Python package is not the Docker CLI and not the Docker daemon. If the daemon is not running, the SDK cannot fix that.\n- On Linux, `/var/run/docker.sock` permission errors usually mean the current user cannot access the Docker socket.\n- `containers.run(..., detach=False)` and many log APIs return bytes, not text. Decode them explicitly.\n- Detached containers are not auto-cleaned unless you request it. Use `auto_remove=True` for one-off runs or call `container.remove(...)`.\n- `container.attrs` is cached until `reload()`.\n- A successful import does not prove the daemon is reachable. Use `client.ping()` early.\n- If you run this code inside another container, mount the Docker socket or point the SDK at a remote daemon explicitly.\n- Close clients when you are done so HTTP resources do not linger.\n\n## Version-Sensitive Notes For 7.1.0\n\n- PyPI lists `docker 7.1.0` for this package, and the stable docs site is the correct maintainer docs root for that line.\n- The 7.1.0 release notes say the SDK bumped the default Docker Engine API version to `1.44` and the minimum supported Engine API version to `1.24`. If you must talk to very old daemons, `7.1.0` may be the wrong SDK version.\n- The stable client reference still shows older constructor defaults in some places. Because of that source drift, prefer `docker.from_env()` or pass `version=\"auto\"` explicitly instead of relying on implicit defaults.\n- Since 7.0.0, `ssl_version` and `assert_hostname` were removed from `kwargs_from_env()`, `from_env()`, `DockerClient()`, and `APIClient()`. Do not copy examples that still pass those arguments.\n- Since 7.0.0, `docker[tls]` no longer adds anything beyond the base package.\n- The `websockets` extra is only needed for websocket-based attach support such as `attach_socket(..., ws=True)`.\n\n## Official Sources\n\n- Docs root: `https://docker-py.readthedocs.io/en/stable/`\n- Client reference: `https://docker-py.readthedocs.io/en/stable/client.html`\n- Containers guide: `https://docker-py.readthedocs.io/en/stable/containers.html`\n- Images guide: `https://docker-py.readthedocs.io/en/stable/images.html`\n- TLS guide: `https://docker-py.readthedocs.io/en/stable/tls.html`\n- PyPI package metadata: `https://pypi.org/project/docker/`\n- Maintainer release notes for 7.1.0: `https://github.com/docker/docker-py/releases/tag/7.1.0`\n"
  },
  {
    "path": "content/docling/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"docling package guide for Python document conversion, OCR, CLI usage, and pipeline configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.78.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"docling,python,documents,pdf,ocr,conversion,cli\"\n---\n\n# docling Python Package Guide\n\n## Golden Rule\n\n- Use the official `docling` package for document conversion and start with `DocumentConverter` unless you need pipeline-level customization.\n- Pin `docling==2.78.0` when you need reproducible behavior, because the stable docs site can describe newer releases.\n- Install optional extras only for the features you actually use (`easyocr`, `tesserocr`, `vlm`, `chunking`, `asr`).\n- Keep remote inference opt-in. Upstream examples explicitly require `enable_remote_services=True` for remote VLM usage.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `2.78.0`, and that exact version is published on PyPI.\n- The repository's tagged `v2.78.0` README is the safest upstream reference for examples that must match this version exactly.\n- The official docs site is a moving \"stable\" target, so examples there can drift ahead of `2.78.0`.\n- The `v2.78.0` package metadata requires Python `>=3.10,<4.0`.\n- The package exposes optional extras for `chunking`, `easyocr`, `tesserocr`, `vlm`, and `asr`. Do not assume the base install includes every OCR or VLM backend.\n\n## Install\n\nUse a pinned install for repeatable agent behavior:\n\n```bash\npython -m pip install \"docling==2.78.0\"\n```\n\nInstall only the extras you need:\n\n```bash\npython -m pip install \"docling[easyocr]==2.78.0\"\npython -m pip install \"docling[vlm]==2.78.0\"\npython -m pip install \"docling[chunking]==2.78.0\"\n```\n\nFor offline or pre-provisioned environments, upstream documents a separate model download helper:\n\n```bash\npython -m pip install \"docling-tools\"\ndocling-tools models download\n```\n\n## Recommended Setup\n\nStart with the base converter, then add format or pipeline options only when the default output is not sufficient.\n\n```python\nfrom docling.document_converter import DocumentConverter\n\nconverter = DocumentConverter()\n```\n\n`docling` supports common office and web document inputs including PDF, DOCX, XLSX, HTML, image formats, Markdown, AsciiDoc, and CSV. For most coding tasks, the practical output targets are Markdown, structured text, or the internal document model.\n\n## Core Usage\n\n### Convert One Document To Markdown\n\n```python\nfrom docling.document_converter import DocumentConverter\n\nconverter = DocumentConverter()\nresult = converter.convert(\"report.pdf\")\n\nmarkdown = result.document.export_to_markdown()\nprint(markdown)\n```\n\n### Convert A URL\n\nThe upstream README shows that `convert()` accepts remote URLs directly:\n\n```python\nfrom docling.document_converter import DocumentConverter\n\nconverter = DocumentConverter()\nresult = converter.convert(\"https://arxiv.org/pdf/2206.01062\")\n\nprint(result.document.export_to_markdown())\n```\n\n### Convert Multiple Files\n\n```python\nfrom pathlib import Path\n\nfrom docling.document_converter import DocumentConverter\n\nconverter = DocumentConverter()\n\nfor path in Path(\"incoming\").glob(\"*.pdf\"):\n    result = converter.convert(path)\n    output = path.with_suffix(\".md\")\n    output.write_text(result.document.export_to_markdown(), encoding=\"utf-8\")\n```\n\n### Use The CLI\n\nUpstream documents the `docling` CLI for direct conversions:\n\n```bash\ndocling https://arxiv.org/pdf/2206.01062\ndocling ./tests/data/2305.03393v1-pg9.pdf\n```\n\nUse the CLI when you need a shell-friendly conversion step in scripts or quick inspection during debugging. Use the Python API when you need programmatic control over output handling and pipeline options.\n\n## Pipeline Configuration\n\nReach for pipeline options when you need OCR, hardware acceleration, or table extraction tuning.\n\n```python\nfrom docling.backend.docling_parse_v2_backend import DoclingParseV2DocumentBackend\nfrom docling.datamodel.base_models import InputFormat\nfrom docling.datamodel.pipeline_options import AcceleratorDevice, AcceleratorOptions\nfrom docling.document_converter import DocumentConverter, PdfFormatOption\nfrom docling.pipeline.standard_pdf_pipeline import StandardPdfPipeline\n\nconverter = DocumentConverter(\n    format_options={\n        InputFormat.PDF: PdfFormatOption(\n            pipeline_cls=StandardPdfPipeline,\n            backend=DoclingParseV2DocumentBackend,\n            pipeline_options=dict(\n                accelerator_options=AcceleratorOptions(\n                    num_threads=4,\n                    device=AcceleratorDevice.AUTO,\n                ),\n            ),\n        )\n    }\n)\n```\n\nCommon knobs to check first:\n\n- OCR enablement and OCR backend\n- table structure extraction\n- accelerator device and thread count\n- artifacts or model cache location for offline runs\n\n## Offline Models And Artifacts\n\nIf the runtime environment cannot download models on demand, prefetch them and point the pipeline to the local artifacts directory.\n\n```bash\ndocling-tools models download --output-dir ./docling-models\n```\n\n```python\nfrom docling.datamodel.pipeline_options import (\n    PdfPipelineOptions,\n    RapidOcrOptions,\n    TesseractOcrOptions,\n)\n\npipeline_options = PdfPipelineOptions()\npipeline_options.artifacts_path = \"docling-models\"\npipeline_options.ocr_options = RapidOcrOptions()\n```\n\nSwap in `TesseractOcrOptions()` if that is the backend you installed and provisioned.\n\n## Config And Auth\n\n`docling` does not require package-level authentication for local document conversion.\n\nWhat usually matters instead:\n\n- Network access for downloading model artifacts on first use\n- local filesystem paths for cached artifacts and model bundles\n- optional third-party credentials only if you deliberately enable remote model or VLM services outside the default local path\n\nFor remote VLM scenarios, upstream examples keep remote calls disabled unless you set `enable_remote_services=True`. Treat that as an explicit trust boundary and keep provider secrets in environment variables managed by the backend you configure, not in source code.\n\n## Common Pitfalls\n\n- Python version mismatch: `docling==2.78.0` requires Python 3.10 or newer.\n- Missing extras: OCR and VLM features can fail at import or runtime if you installed only the base package.\n- Stable docs drift: the docs site may document behavior newer than `2.78.0`; confirm against the `v2.78.0` tagged repo when copying examples.\n- First-run downloads: model assets may be fetched lazily, which breaks in CI or air-gapped environments unless you pre-download them.\n- Remote inference assumptions: enabling remote services can send document content to external systems; do not enable it by default in sensitive environments.\n- Over-customizing early: start with plain `DocumentConverter()` before wiring custom backends or pipeline classes.\n\n## Practical Agent Workflow\n\n1. Install `docling==2.78.0`, plus only the extras required by the task.\n2. Start with `DocumentConverter().convert(...)` and export to Markdown.\n3. If output quality is poor for scanned PDFs, add explicit OCR pipeline options.\n4. If the environment is offline, pre-download models with `docling-tools` and set `artifacts_path`.\n5. If the upstream stable docs and installed behavior disagree, trust the tagged `v2.78.0` repository content over newer stable-site examples.\n\n## Official Sources\n\n- Docs root: `https://docling-project.github.io/docling/`\n- Installation docs: `https://docling-project.github.io/docling/installation/`\n- Usage docs: `https://docling-project.github.io/docling/usage/`\n- CLI docs: `https://docling-project.github.io/docling/usage/cli/`\n- Repo README for `v2.78.0`: `https://github.com/docling-project/docling/blob/v2.78.0/README.md`\n- PyPI package page: `https://pypi.org/project/docling/2.78.0/`\n"
  },
  {
    "path": "content/docutils/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"docutils package guide for Python: CLI tools, publisher API, config files, and version-sensitive notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.22.4\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"docutils,restructuredtext,rst,html,xml,documentation\"\n---\n\n# docutils Python Package Guide\n\n## What It Is\n\n`docutils` is the reference Python toolkit for parsing reStructuredText and rendering it to formats such as HTML5, XML, LaTeX, man pages, ODT, and Docutils' internal doctree structures. For code, the main programmatic entry points are in `docutils.core`. For shell usage, the main entry points are `docutils` and the specialized `rst2*` tools.\n\nUse it when you need to:\n\n- convert `.rst` files into HTML or other output formats\n- parse reStructuredText into a doctree for custom processing\n- embed reStructuredText rendering into a Python application\n\n## Install\n\n`docutils` 0.22.4 requires Python 3.9 or later.\n\n```bash\npip install docutils==0.22.4\n```\n\nWith `uv`:\n\n```bash\nuv add docutils==0.22.4\n```\n\nIf you want optional syntax highlighting for `.. code::` blocks, install Pygments too:\n\n```bash\npip install docutils==0.22.4 pygments\n```\n\nIf you want to parse Markdown through the generic front end, install a supported third-party parser such as `myst` first. A bare `docutils` install does not include Markdown parsing support.\n\n## Initialize And Setup\n\nThere is no auth or remote service configuration. Setup is local:\n\n- install the package into the Python environment used by your build or app\n- use the CLI tools directly, or import `docutils.core`\n- optionally add persistent runtime settings in `docutils.conf`\n\nImportant CLI entry points:\n\n- `docutils`: generic front end; default conversion is reStructuredText to HTML5\n- `rst2html5`, `rst2xml`, `rst2latex`, `rst2man`, `rst2odt`, `rst2pseudoxml`, `rst2s5`, `rst2xetex`\n\nSince Docutils 0.21, the installed `rst2*` tools are console scripts without the `.py` suffix.\n\nCheck the installed version and available options:\n\n```bash\ndocutils --version\ndocutils --help\nrst2html5 --help\n```\n\n## Core CLI Usage\n\nConvert a reStructuredText file to HTML5:\n\n```bash\ndocutils input.rst output.html\n```\n\nThe generic `docutils` front end can swap parser and writer components:\n\n```bash\ndocutils --writer=xml input.rst output.xml\ndocutils --writer=latex2e input.rst output.tex\n```\n\nUse the specialized front ends when you already know the output format:\n\n```bash\nrst2html5 input.rst output.html\nrst2xml input.rst output.xml\n```\n\nLog warnings to a file:\n\n```bash\ndocutils --warnings=docutils-warnings.log input.rst output.html\n```\n\nMinimal `sample.rst`:\n\n```rst\nTitle\n=====\n\nThis is a paragraph with **strong text**.\n\n- item one\n- item two\n\n.. code:: python\n\n   print(\"hello\")\n```\n\n## Programmatic Usage\n\nThe most useful high-level functions are:\n\n- `publish_string()`: render from an input string\n- `publish_file()`: render from file-like objects\n- `publish_parts()`: return structured output parts for post-processing\n- `publish_doctree()`: parse into a doctree instead of a rendered format\n\n### Render reStructuredText to HTML\n\n`publish_string()` returns bytes by default unless you request Unicode output.\n\n```python\nfrom docutils.core import publish_string\n\nrst = \"\"\"\\\nTitle\n=====\n\nThis is **Docutils** output.\n\"\"\"\n\nhtml = publish_string(\n    source=rst,\n    writer_name=\"html5\",\n    settings_overrides={\n        \"output_encoding\": \"unicode\",\n        \"file_insertion_enabled\": False,\n        \"raw_enabled\": False,\n    },\n)\n\nprint(type(html))  # str\nprint(html)\n```\n\n### Get Structured Parts Instead Of Just One Blob\n\nUse `publish_parts()` if your app needs the full HTML document plus metadata or specific writer-generated sections.\n\n```python\nfrom docutils.core import publish_parts\n\nparts = publish_parts(\n    source=\"Heading\\n=======\\n\\nBody text.\\n\",\n    writer_name=\"html5\",\n    settings_overrides={\"output_encoding\": \"unicode\"},\n)\n\nfull_document = parts[\"whole\"]\ndocutils_version = parts[\"version\"]\n```\n\n### Parse To A Doctree\n\nUse `publish_doctree()` when you need to inspect or transform the parsed document structure before rendering.\n\n```python\nfrom docutils.core import publish_doctree\n\ndoctree = publish_doctree(\n    source=\"Heading\\n=======\\n\\nParagraph.\\n\"\n)\n\nprint(doctree.pformat())\n```\n\n### File-Like IO\n\n`publish_file()` is useful when your app already has open streams:\n\n```python\nfrom io import StringIO\nfrom docutils.core import publish_file\n\nsource = StringIO(\"Title\\n=====\\n\\nFrom a file-like object.\\n\")\ndestination = StringIO()\n\npublish_file(\n    source=source,\n    destination=destination,\n    writer_name=\"html5\",\n    settings_overrides={\"output_encoding\": \"unicode\"},\n)\n\nhtml = destination.getvalue()\n```\n\n## Configuration And Runtime Settings\n\nDocutils supports persistent config files plus per-call overrides.\n\nBy default it looks for config files in this order:\n\n1. `/etc/docutils.conf`\n2. `./docutils.conf`\n3. `~/.docutils`\n\nYou can override the implicit config search path with `DOCUTILSCONFIG`. You can also append one or more explicit config files with `--config`; those are processed after the implicit ones and take priority.\n\nExample `docutils.conf`:\n\n```ini\n[general]\nreport_level: 2\nhalt_level: 4\nwarning_stream: docutils-warnings.log\n\n[parsers]\nfile_insertion_enabled: no\nraw_enabled: no\n\n[html5 writer]\nembed_stylesheet: no\nstylesheet_path: minimal.css,responsive.css\n```\n\nUseful runtime settings for automation:\n\n- `report_level`: controls which system messages are reported; default is `2` (`warning`)\n- `halt_level`: converts system messages at or above the threshold into exceptions or process exit; default is `4` (`severe`)\n- `warning_stream`: sends warnings to a file instead of stderr\n- `file_insertion_enabled`: disable `include` and similar file-loading behavior for untrusted input\n- `raw_enabled`: disable the `raw` directive for untrusted input\n\nProgrammatic calls can override the same settings via `settings_overrides`.\n\n## Common Patterns\n\n### Strict Build That Fails On Errors\n\n```python\nfrom docutils.core import publish_string\n\nhtml = publish_string(\n    source=source_text,\n    writer_name=\"html5\",\n    settings_overrides={\n        \"output_encoding\": \"unicode\",\n        \"report_level\": 2,\n        \"halt_level\": 3,\n    },\n)\n```\n\nThis reports warnings and turns `error` or `severe` system messages into failures.\n\n### Safer Rendering For Untrusted Content\n\n```python\nsafe_html = publish_string(\n    source=source_text,\n    writer_name=\"html5\",\n    settings_overrides={\n        \"output_encoding\": \"unicode\",\n        \"file_insertion_enabled\": False,\n        \"raw_enabled\": False,\n    },\n)\n```\n\nThis avoids loading external files and disables raw passthrough directives.\n\n### Generic Front End With A Markdown Parser\n\nIf you installed a third-party Markdown parser supported by Docutils:\n\n```bash\ndocutils --parser=markdown --writer=pseudoxml notes.md notes.xml\n```\n\nDo not assume this works in a clean environment unless the parser dependency is installed.\n\n## Common Pitfalls\n\n- `publish_string()` does not guarantee a `str` result unless you set `output_encoding` to `\"unicode\"`.\n- The generic `docutils` CLI defaults to HTML5 output. If you need XML, LaTeX, or another format, set `--writer` explicitly or use the matching `rst2*` tool.\n- Since 0.21, the installed tool names are `rst2html5`, `rst2xml`, and similar, not `rst2html.py` in your `PATH`.\n- `./docutils.conf` is resolved relative to the current working directory, not the source file's directory. That matters in build systems.\n- Hidden config can change output. If builds behave inconsistently across environments, inspect `DOCUTILSCONFIG`, local config files, and `--config` usage first.\n- `file_insertion_enabled` and `raw_enabled` default to `True`. Disable both when converting untrusted input.\n- Warnings do not stop processing by default because `halt_level` defaults to `4` (`severe`). If your pipeline should fail earlier, set `halt_level` explicitly.\n- Markdown parsing is optional. Install the parser package before using `--parser=markdown`.\n\n## Version-Sensitive Notes\n\n- The version used here `0.22.4` matches the current stable PyPI release as of 2026-03-11.\n- Since 0.21, Docutils requires Python 3.9+.\n- Since 0.21, `rst2*` front ends are installed as console scripts without `.py`.\n- The 0.22 line starts adding type hints. Upstream notes that these hints use Python 3.10 syntax, but normal runtime use still works on supported Python versions because they are treated as annotations unless type checking is activated.\n- If you are upgrading from much older automation that shell-executes `rst2html.py` or similar, update those commands.\n\n## Upstream Sources\n\n- PyPI package page: https://pypi.org/project/docutils/\n- Docs overview: https://docutils.sourceforge.io/docs/index.html\n- Front-end tools: https://docutils.sourceforge.io/docs/user/tools.html\n- Configuration reference: https://docutils.sourceforge.io/docs/user/config.html\n- Publisher API: https://docutils.sourceforge.io/docs/api/publisher.html\n- reStructuredText primer: https://docutils.sourceforge.io/docs/user/rst/quickstart.html\n- Release history: https://docutils.sourceforge.io/HISTORY.html\n"
  },
  {
    "path": "content/dramatiq/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Dramatiq Python package guide for background jobs with RabbitMQ or Redis brokers\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dramatiq,python,background-jobs,task-queue,rabbitmq,redis,workers\"\n---\n\n# Dramatiq Python Package Guide\n\n## Golden Rule\n\nUse `dramatiq` for Python background jobs, configure the broker explicitly with `dramatiq.set_broker(...)` early in process startup, and keep actor inputs small and JSON-encodable. Dramatiq assumes tasks are retriable and may run more than once, so actors should be idempotent.\n\n## Install\n\nPick the extra that matches your broker:\n\n```bash\npython -m pip install \"dramatiq[rabbitmq]==2.1.0\"\npython -m pip install \"dramatiq[redis]==2.1.0\"\n```\n\nCommon development installs:\n\n```bash\npython -m pip install \"dramatiq[rabbitmq,watch]==2.1.0\"\npython -m pip install \"dramatiq[redis,watch]==2.1.0\"\npython -m pip install \"dramatiq[prometheus]==2.1.0\"\npython -m pip install \"dramatiq[all]==2.1.0\"\n```\n\nNotes:\n\n- RabbitMQ is the upstream-recommended broker.\n- If you use Redis, upstream recommends adding `hiredis` for better throughput on CPython.\n- Available extras on PyPI for `2.1.0` include `rabbitmq`, `redis`, `watch`, `prometheus`, `gevent`, `memcached`, and `all`.\n\n## Initialize The Broker\n\nDramatiq will fall back to a default global broker if you do not set one, but upstream recommends setting the broker yourself as early as possible so worker and producer processes use the same configuration.\n\n### RabbitMQ\n\n```python\nimport os\n\nimport dramatiq\nfrom dramatiq.brokers.rabbitmq import RabbitmqBroker\n\nbroker = RabbitmqBroker(\n    url=os.getenv(\"DRAMATIQ_BROKER_URL\", \"amqp://guest:guest@localhost:5672/\"),\n    confirm_delivery=True,\n)\ndramatiq.set_broker(broker)\n```\n\nUseful RabbitMQ options:\n\n- `url=\"amqp://user:pass@host:5672/vhost\"` for connection config\n- `confirm_delivery=True` if you need publisher confirms\n- `max_priority=<n>` if you want queue-level priority with `broker_priority`\n\n### Redis\n\n```python\nimport os\n\nimport dramatiq\nfrom dramatiq.brokers.redis import RedisBroker\n\nbroker = RedisBroker(\n    url=os.getenv(\"DRAMATIQ_BROKER_URL\", \"redis://localhost:6379/0\"),\n    namespace=os.getenv(\"DRAMATIQ_NAMESPACE\", \"dramatiq\"),\n)\ndramatiq.set_broker(broker)\n```\n\nUseful Redis options:\n\n- `url=\"redis://:password@host:6379/0\"` for connection config\n- `namespace=\"myapp\"` to isolate multiple logical apps on the same Redis instance\n- Individual connection parameters are also forwarded to `redis.Redis(...)`\n\n## Define And Send Actors\n\nBasic actor:\n\n```python\nimport dramatiq\n\n@dramatiq.actor\ndef send_email(user_id: int) -> None:\n    print(f\"Sending email to user {user_id}\")\n\nsend_email.send(42)\n```\n\nImportant behavior:\n\n- Calling `send_email(42)` runs synchronously in-process.\n- Calling `send_email.send(42)` enqueues a message for a worker.\n- Actor arguments must be JSON-encodable.\n- Keep payloads small. Send IDs or paths, not ORM objects or large blobs.\n\n### Run workers\n\nIf your actors live in `myapp.tasks`, start workers with:\n\n```bash\ndramatiq myapp.tasks\n```\n\nFor local development with automatic reload:\n\n```bash\ndramatiq myapp.tasks --watch .\n```\n\nThe worker CLI starts one process per CPU core with 8 worker threads per process by default.\n\n## Core Usage Patterns\n\n### Retries and idempotency\n\nDramatiq retries failures automatically with exponential backoff. The default retries middleware uses `max_retries=20`, and the user guide notes retries can span roughly 30 days.\n\n```python\nimport dramatiq\n\n@dramatiq.actor(max_retries=3, min_backoff=1_000, max_backoff=30_000)\ndef sync_invoice(invoice_id: str) -> None:\n    ...\n```\n\nUse `throws=` for expected non-retriable errors:\n\n```python\nimport dramatiq\n\nclass ValidationError(Exception):\n    pass\n\n@dramatiq.actor(throws=(ValidationError,), max_retries=0)\ndef process_upload(upload_id: str) -> None:\n    ...\n```\n\n### Delayed messages\n\n```python\nimport dramatiq\n\n@dramatiq.actor\ndef remind_user(user_id: str) -> None:\n    ...\n```\n\n```python\nremind_user.send_with_options(args=(\"user-123\",), delay=60_000)\n```\n\nUse scheduled jobs sparingly. Upstream explicitly warns that the broker is not a database.\n\n### Priorities\n\nActor priority controls which already-consumed messages run first in a worker. Lower numbers are higher priority.\n\n```python\nimport dramatiq\n\n@dramatiq.actor(priority=0)\ndef user_facing_job(job_id: str) -> None:\n    ...\n\n@dramatiq.actor(priority=100)\ndef batch_job(job_id: str) -> None:\n    ...\n```\n\nIf you use RabbitMQ queue priorities, configure `max_priority` on the broker and enqueue with `broker_priority`:\n\n```python\nuser_facing_job.send_with_options(args=(\"job-1\",), broker_priority=5)\n```\n\n### Time and age limits\n\nThese are middleware-driven safety controls:\n\n```python\nimport dramatiq\n\n@dramatiq.actor(max_age=3_600_000, time_limit=30_000)\ndef rebuild_cache(key: str) -> None:\n    ...\n```\n\n- `max_age` drops messages that have sat in the queue too long.\n- `time_limit` interrupts long-running work.\n- The time-limit middleware cannot cancel blocking system calls immediately; it only interrupts when the worker thread next acquires the GIL.\n\n## Async Actors\n\nAsync actors need the optional `AsyncIO` middleware:\n\n```python\nimport dramatiq\nfrom dramatiq.brokers.redis import RedisBroker\nfrom dramatiq.middleware import AsyncIO\n\nbroker = RedisBroker()\nbroker.add_middleware(AsyncIO())\ndramatiq.set_broker(broker)\n\n@dramatiq.actor\nasync def refresh_remote_cache(key: str) -> None:\n    ...\n```\n\nWithout `AsyncIO`, `async def` actors are not configured correctly for worker execution.\n\n## Results And Pipelines\n\nResult storage is optional and not enabled by default. In `2.x`, the `Results` middleware requires an explicit backend.\n\n```python\nimport dramatiq\nfrom dramatiq.brokers.redis import RedisBroker\nfrom dramatiq.results import Results\nfrom dramatiq.results.backends import RedisBackend\n\nbroker = RedisBroker(url=\"redis://localhost:6379/0\")\nresult_backend = RedisBackend(url=\"redis://localhost:6379/1\")\nbroker.add_middleware(Results(backend=result_backend))\ndramatiq.set_broker(broker)\n\n@dramatiq.actor(store_results=True)\ndef add(x: int, y: int) -> int:\n    return x + y\n\nmessage = add.send(1, 2)\nresult = message.get_result(backend=result_backend)\n```\n\nPipelines and groups are available, but pipeline completion tracking depends on results being enabled for the actors you care about.\n\n## Testing\n\nUse `StubBroker` for unit and integration-style tests that should not require RabbitMQ or Redis:\n\n```python\nimport dramatiq\nfrom dramatiq import Worker\nfrom dramatiq.brokers.stub import StubBroker\n\nbroker = StubBroker()\nbroker.emit_after(\"process_boot\")\ndramatiq.set_broker(broker)\n\n@dramatiq.actor(max_retries=0)\ndef add(x: int, y: int) -> None:\n    assert x > 0\n\nworker = Worker(broker, worker_timeout=100)\nworker.start()\n\nadd.send(1, 2)\nbroker.join(add.queue_name)\nworker.join()\nworker.stop()\n```\n\nTesting notes:\n\n- In `2.x`, `StubBroker.join()` fails fast by default and re-raises dead-lettered actor exceptions.\n- Retries still apply in tests. Set `max_retries=0` or configure `Retries(...)` for fast feedback.\n- You can also test actor logic synchronously by calling the actor directly.\n\n## Configuration And Operational Notes\n\n- Authentication is broker-specific. Use broker URLs or connection kwargs; Dramatiq itself does not have a separate auth layer.\n- For RabbitMQ multi-tenancy, use virtual hosts.\n- For Redis multi-tenancy, use a dedicated DB and/or `namespace`.\n- If you customize the middleware list manually, you replace the defaults. Add back anything you still rely on, such as `Retries`, `Callbacks`, or `Pipelines`.\n- `Prometheus` middleware is optional in `2.x`; install the `prometheus` extra and add the middleware explicitly if you need metrics.\n\n## Common Pitfalls\n\n- Forgetting to call `dramatiq.set_broker(...)` early, then producing with one broker config and consuming with another.\n- Sending non-JSON-encodable arguments or large objects through messages.\n- Treating actors as exactly-once. Worker failures can cause the same message to run more than once.\n- Expecting actor `priority` to reorder messages still waiting in the broker queue; that needs RabbitMQ `broker_priority`.\n- Enabling `Results()` without a backend in older examples. In `2.x`, `backend=` is required.\n- Expecting `time_limit` to interrupt blocking I/O immediately.\n- Running enqueue code in a pre-fork server that shares broker connections across forks. The troubleshooting guide calls out `FileNotFoundError` issues in that setup; load app code after fork or use the server-specific workaround.\n- Waiting forever in tests because retries keep rescheduling failures. Disable or shrink retries in tests.\n\n## Version-Sensitive Notes For 2.1.0\n\n- `2.1.0` is the current PyPI release as of 2026-03-12.\n- `2.1.0` raises the supported maximum `redis` client version to `7.x`.\n- `dramatiq.errors.ConnectionError` was renamed to `BrokerConnectionError`; the old import still works for backward compatibility and is slated for removal in `3.0.0`.\n- `2.0.0` changed several behaviors that older blog posts may miss:\n  - `StubBroker.join(...)/fail_fast` now defaults to failing fast.\n  - `Prometheus` is no longer part of the default middleware list.\n  - `Results` now requires an explicit `backend=...`.\n  - `URLRabbitmqBroker` was removed; use `RabbitmqBroker(url=...)`.\n\n## Official Sources\n\n- Docs root: `https://dramatiq.io/`\n- Installation: `https://dramatiq.io/installation.html`\n- User guide: `https://dramatiq.io/guide.html`\n- API reference: `https://dramatiq.io/reference.html`\n- Advanced topics: `https://dramatiq.io/advanced.html`\n- Troubleshooting: `https://dramatiq.io/troubleshooting.html`\n- Changelog: `https://dramatiq.io/changelog.html`\n- PyPI: `https://pypi.org/project/dramatiq/`\n"
  },
  {
    "path": "content/duckdb/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"DuckDB Python package guide for embedded SQL analytics, DataFrames, and file-backed workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"duckdb,python,sql,analytics,dataframe,parquet\"\n---\n\n# duckdb Python Package Guide\n\n## Golden Rule\n\nUse an explicit `duckdb.connect(...)` connection for application code, persistent databases, and threaded work. Reserve top-level `duckdb.sql(...)` for short interactive queries.\n\n## What It Is\n\n`duckdb` embeds DuckDB inside your Python process. Common uses:\n\n- run SQL directly over local Parquet, CSV, and JSON files\n- query Pandas, Arrow, Polars, and NumPy data without moving data into a separate server\n- keep an in-memory database for analysis or a `.duckdb` file for local persistence\n- read from object storage such as S3 once extensions and credentials are configured\n\n## Install\n\n```bash\npip install duckdb==1.5.0\n```\n\nCheck the installed version:\n\n```bash\npython -c \"import duckdb; print(duckdb.__version__)\"\n```\n\nNotes:\n\n- The DuckDB Python client requires Python 3.9 or newer.\n\n## Quick Start\n\n### Ad hoc query\n\n```python\nimport duckdb\n\nresult = duckdb.sql(\"SELECT 42 AS answer\").fetchone()\nprint(result[0])\n```\n\n### Persistent database file\n\n```python\nimport duckdb\n\ncon = duckdb.connect(\"app.duckdb\")\n\ncon.execute(\"\"\"\n    CREATE TABLE IF NOT EXISTS events (\n        id INTEGER,\n        kind VARCHAR,\n        created_at TIMESTAMP\n    )\n\"\"\")\n\ncon.execute(\n    \"INSERT INTO events VALUES (?, ?, current_timestamp)\",\n    [1, \"signup\"],\n)\n\nrows = con.execute(\n    \"SELECT id, kind FROM events WHERE kind = ?\",\n    [\"signup\"],\n).fetchall()\n\nprint(rows)\ncon.close()\n```\n\n### Connection configuration\n\nPass engine settings at connect time:\n\n```python\nimport duckdb\n\ncon = duckdb.connect(\n    \"app.duckdb\",\n    config={\n        \"threads\": 4,\n        \"memory_limit\": \"4GB\",\n    },\n)\n```\n\nUse `read_only=True` when another process may already have the same database file open:\n\n```python\nimport duckdb\n\ncon = duckdb.connect(\"app.duckdb\", read_only=True)\n```\n\n## Core Usage Patterns\n\n### Query files directly\n\nDuckDB can query files without a load step:\n\n```python\nimport duckdb\n\ncon = duckdb.connect()\n\ncount = con.execute(\"\"\"\n    SELECT count(*)\n    FROM read_parquet('data/orders/*.parquet')\n    WHERE order_date >= DATE '2026-01-01'\n\"\"\").fetchone()[0]\n\nprint(count)\n```\n\nThe SQL shell syntax also works for some formats:\n\n```python\nimport duckdb\n\nrows = duckdb.sql(\"SELECT * FROM 'data/example.parquet' LIMIT 5\").fetchall()\n```\n\n### Query a Pandas DataFrame without registering it\n\nDuckDB's Python integration can discover DataFrames by variable name:\n\n```python\nimport duckdb\nimport pandas as pd\n\norders = pd.DataFrame(\n    [\n        {\"customer_id\": 1, \"total\": 25},\n        {\"customer_id\": 2, \"total\": 50},\n        {\"customer_id\": 1, \"total\": 30},\n    ]\n)\n\nsummary = duckdb.sql(\"\"\"\n    SELECT customer_id, sum(total) AS total_spend\n    FROM orders\n    GROUP BY customer_id\n    ORDER BY total_spend DESC\n\"\"\").df()\n\nprint(summary)\n```\n\nIf you need persistence or indexes, materialize the DataFrame into a table:\n\n```python\nimport duckdb\nimport pandas as pd\n\norders_df = pd.DataFrame([{\"customer_id\": 1, \"total\": 25}])\n\ncon = duckdb.connect(\"analytics.duckdb\")\ncon.execute(\"CREATE OR REPLACE TABLE orders AS SELECT * FROM orders_df\")\n```\n\n### Fetch results in the format you need\n\n```python\nimport duckdb\n\nrel = duckdb.sql(\"SELECT * FROM range(5)\")\n\nrows = rel.fetchall()\ndf = rel.df()\narrow_table = rel.fetch_arrow_table()\nnumpy_cols = rel.fetchnumpy()\n```\n\nUse:\n\n- `fetchall()` or `fetchone()` for DB-API style results\n- `.df()` when the next step is Pandas\n- `.fetch_arrow_table()` for Arrow pipelines\n- `.fetchnumpy()` for NumPy-oriented code\n\n### Parameter binding\n\nPrefer parameters over string interpolation:\n\n```python\nimport duckdb\n\ncon = duckdb.connect()\n\nrows = con.execute(\n    \"SELECT * FROM range(?) WHERE range < ?\",\n    [100, 10],\n).fetchall()\n```\n\n## Extensions, Remote Storage, and Credentials\n\nLocal files need no authentication. Remote object storage does.\n\nFor S3 and S3-compatible storage, DuckDB recommends secrets-based configuration:\n\n```python\nimport duckdb\n\ncon = duckdb.connect()\ncon.execute(\"INSTALL httpfs\")\ncon.execute(\"LOAD httpfs\")\n\ncon.execute(\"\"\"\n    CREATE OR REPLACE SECRET s3_creds (\n        TYPE s3,\n        PROVIDER credential_chain,\n        REGION 'us-east-1'\n    )\n\"\"\")\n\ndf = con.execute(\"\"\"\n    SELECT *\n    FROM read_parquet('s3://my-bucket/path/data.parquet')\n    LIMIT 10\n\"\"\").df()\n```\n\nPractical notes:\n\n- `credential_chain` uses the standard AWS credential resolution flow. Prefer it over hard-coding keys.\n- Keep remote access setup inside the connection bootstrap path so queries fail early if extensions or credentials are missing.\n- If a project depends on extensions, pin DuckDB and test extension loading in CI.\n\n## Common Pitfalls\n\n### `duckdb.sql(...)` uses a shared default connection\n\nThe module-level helpers operate on a global in-memory connection. That is convenient in notebooks, but it is the wrong default for request handlers, background jobs, and threaded code. Use a dedicated `duckdb.connect(...)` per unit of work or per thread.\n\n### `cursor()` helps with concurrent work, but it is not a substitute for connection design\n\nDuckDB's DB-API docs describe `cursor()` as a way to create a second connection to an existing database, which can help with parallel threads. The same section also notes that a single connection is thread-safe but locked while queries run, so you should still design concurrency explicitly and not rely on one shared connection for throughput.\n\n### `:memory:` and named in-memory databases behave differently\n\n- `:memory:` creates a private in-memory database per connection.\n- A named in-memory database such as `:memory:analytics` shares state across connections that use the same name.\n\nUse a file-backed database or explicitly named in-memory connection only when shared state is intentional.\n\n### Direct DataFrame scans are convenient, but they are not persisted\n\nQuerying a Python variable by name is great for analysis, but the underlying DataFrame is still a Python object. Create a table with `CREATE TABLE ... AS SELECT * FROM df_name` when later queries must not depend on Python variable scope.\n\n### `executemany()` is not the fast path for large bulk inserts\n\nDuckDB's DB-API docs explicitly warn against using `executemany()` for large data loads. For bulk ingestion, prefer:\n\n- `CREATE TABLE ... AS SELECT * FROM df_name`\n- `INSERT INTO target SELECT * FROM df_name`\n- `read_parquet(...)`, `read_csv(...)`, or `COPY`\n\n### Python worker-thread imports can matter\n\nThe DuckDB known-issues page documents a NumPy import issue in worker threads. If threaded code fetches Pandas or NumPy results, import `numpy.core.multiarray` before starting threads.\n\n### Notebook display oddities are documented upstream\n\nThe known-issues page notes that `DESCRIBE` and `SUMMARIZE` can appear empty in some Jupyter paths. The documented workaround is to wrap them in a subquery, for example `FROM (DESCRIBE tbl)`.\n\n## Version-Sensitive Notes For 1.5.0\n\n- This entry targets package version `1.5.0`. If a project is pinned to `1.4.x`, check the LTS docs before copying examples.\n- DuckDB's 1.5 release notes call out a change in the `httpfs` extension backend from `httplib` to `curl`. Re-test proxy, TLS, and remote filesystem behavior when upgrading from earlier releases.\n- The 1.5 release notes also warn that the single-arrow lambda syntax is deprecated and DuckDB 2.0 will disable it by default. Prefer `lambda x: ...` syntax in new SQL.\n\n## Recommended Agent Workflow\n\n1. Install the exact package version used by the project.\n2. Decide early whether you need an ephemeral in-memory connection or a persistent `.duckdb` file.\n3. Use parameterized SQL and explicit connections in non-interactive code.\n4. For DataFrames and files, push work into DuckDB SQL instead of row-by-row Python loops.\n5. For S3 or HTTP-backed reads, validate extension loading and credentials before writing query logic.\n\n## Official Sources Used\n\n- DuckDB Python client overview: `https://duckdb.org/docs/stable/clients/python/overview`\n- DuckDB Python DB-API reference: `https://duckdb.org/docs/stable/clients/python/dbapi`\n- DuckDB Python conversion and result methods: `https://duckdb.org/docs/stable/clients/python/conversion`\n- DuckDB guide for SQL on Pandas: `https://duckdb.org/docs/stable/guides/python/import_pandas`\n- DuckDB known Python issues: `https://duckdb.org/docs/stable/clients/python/known_issues`\n- DuckDB S3 API / secrets guidance: `https://duckdb.org/docs/stable/core_extensions/httpfs/s3api`\n- DuckDB 1.5.0 release notes: `https://duckdb.org/2026/03/09/announcing-duckdb-150`\n- PyPI package page: `https://pypi.org/project/duckdb/`\n"
  },
  {
    "path": "content/dvc/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"DVC package guide for Python projects: data versioning, remotes, pipelines, and dvc.api access\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.66.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dvc,data-versioning,mlops,pipelines,python,git\"\n---\n\n# DVC Python Package Guide\n\n## Golden Rule\n\nUse the `dvc` CLI for tracking data and pipelines, and use `dvc.api` only for read-style access from Python code. Do not build on DVC's internal Python modules unless the upstream API reference explicitly documents them.\n\n## Install\n\nDVC is published as a Python package and installs a `dvc` command-line tool.\n\n```bash\npip install dvc\ndvc version\n```\n\nFor cloud or remote storage backends, install the matching extras up front instead of discovering missing protocol support later:\n\n```bash\npip install \"dvc[s3]\"\npip install \"dvc[gs]\"\npip install \"dvc[azure]\"\npip install \"dvc[ssh]\"\n```\n\nNotes:\n\n- PyPI metadata for `3.66.1` requires Python `>=3.9`.\n- PyPI publishes backend extras such as `s3`, `gs`, `azure`, `ssh`, `oss`, `webdav`, and `webhdfs`.\n- If `dvc push` or `dvc pull` fails with missing remote support, reinstall with the correct extra for that storage type.\n\n## Initialize A Repository\n\nDVC is normally used inside a Git repository:\n\n```bash\ngit init\ndvc init\ngit add .dvc .dvcignore\ngit commit -m \"Initialize DVC\"\n```\n\nThis creates the `.dvc/` directory and local configuration. Keep the repository metadata in Git; do not commit the DVC cache.\n\n## Track Data Files Or Directories\n\nUse `dvc add` to put large data under DVC control instead of Git:\n\n```bash\ndvc add data/raw\ngit add data/raw.dvc .gitignore\ngit commit -m \"Track raw dataset with DVC\"\n```\n\nWhat this does:\n\n- `dvc add` stores file metadata in a `.dvc` file.\n- DVC updates `.gitignore` so the actual data stays out of Git.\n- Teammates clone the Git repo, then fetch the tracked data with `dvc pull`.\n\nTypical sync flow:\n\n```bash\ndvc push\ndvc pull\ndvc status\n```\n\n## Configure Remote Storage\n\nAdd a default remote so data can be pushed and pulled outside your local cache:\n\n```bash\ndvc remote add -d storage s3://my-bucket/my-prefix\n```\n\nStore credentials in local config or environment-backed provider credentials, not in tracked config:\n\n```bash\ndvc remote modify --local storage access_key_id \"$AWS_ACCESS_KEY_ID\"\ndvc remote modify --local storage secret_access_key \"$AWS_SECRET_ACCESS_KEY\"\n```\n\nPractical rules:\n\n- Use `--local` for secrets so they go into `.dvc/config.local`, which is not meant for Git.\n- Prefer the cloud provider's normal credential chain when possible. For S3, DVC can use standard AWS credentials and boto3-compatible auth flows.\n- Install the matching extra before configuring the remote backend.\n\nCommon remote examples:\n\n```bash\ndvc remote add -d storage gs://my-bucket/path\ndvc remote add -d storage azure://mycontainer/path\ndvc remote add -d storage ssh://user@example.com/path/to/cache\n```\n\n## Build Reproducible Pipelines\n\nUse `dvc stage add` to declare commands, dependencies, and outputs in `dvc.yaml`:\n\n```bash\ndvc stage add \\\n  -n train \\\n  -d src/train.py \\\n  -d data/features.csv \\\n  -o models/model.pkl \\\n  python src/train.py\n```\n\nThen run and re-run the pipeline through DVC:\n\n```bash\ndvc repro\ngit add dvc.yaml dvc.lock\ngit commit -m \"Add training pipeline\"\n```\n\nUse this model when you want cacheable, dependency-aware execution. If a file is not declared with `-d` or `-o`, DVC cannot use it to determine whether a stage is stale.\n\n## Use `dvc.api` From Python\n\nThe stable Python entry points are under `dvc.api`. Use them when application code needs to read versioned data from a DVC repository or remote.\n\nRead a text file from the current repository:\n\n```python\nimport dvc.api\n\nparams_text = dvc.api.read(\"params.yaml\", repo=\".\")\nprint(params_text)\n```\n\nOpen a tracked file from a specific repo and revision:\n\n```python\nimport dvc.api\n\nwith dvc.api.open(\n    \"data/model.bin\",\n    repo=\"https://github.com/iterative/example-get-started\",\n    rev=\"main\",\n    mode=\"rb\",\n) as stream:\n    model_bytes = stream.read()\n```\n\nWhen you need an `fsspec`-style filesystem interface, use `dvc.api.DVCFileSystem` instead of shelling out to `dvc` from Python.\n\n## Authentication And Configuration Notes\n\n- Local project config lives in `.dvc/config`.\n- Secret or machine-specific config belongs in `.dvc/config.local`.\n- Remote credentials can come from provider SDK defaults, environment variables, or `dvc remote modify --local`.\n- Keep Git credentials and DVC remote credentials conceptually separate. Git access controls source checkout; DVC remote auth controls data transfer.\n\n## Common Pitfalls\n\n- Installing plain `dvc` but forgetting the remote extra for S3, GCS, Azure, SSH, or another backend.\n- Committing data files or `.dvc/cache` to Git instead of only the `.dvc` metadata, `dvc.yaml`, and `dvc.lock`.\n- Saving secrets in `.dvc/config` instead of `.dvc/config.local` or provider-managed credentials.\n- Expecting `dvc repro` to react to undeclared inputs. Every dependency and output that affects a stage must be declared.\n- Treating DVC as a general-purpose Python SDK. For application code, stay on the documented `dvc.api` surface.\n\n## Version-Sensitive Notes For `3.66.1`\n\n- `3.66.1` is in the DVC 3.x line. If you work with repositories created on DVC 2.x, expect upgrade friction around cache/object hashes.\n- The DVC 3.0 upgrade guide notes a new hash method for tracked files. Older repos can require `dvc cache migrate --dvc-files` before pushes, pulls, or status checks behave as expected.\n- If a team mixes older DVC clients with 3.x metadata, align client versions before debugging missing cache objects or checksum mismatches.\n- Use PyPI package metadata, not third-party blog posts, for the authoritative runtime requirement: Python `>=3.9` for `3.66.1`.\n\n## Official Sources\n\n- Docs root: https://dvc.org/doc\n- API reference: https://dvc.org/doc/api-reference\n- Install docs: https://dvc.org/doc/install\n- Getting started: https://dvc.org/doc/start\n- Remote storage docs: https://dvc.org/doc/user-guide/data-management/remote-storage\n- S3 remote auth/config: https://dvc.org/doc/user-guide/data-management/remote-storage/amazon-s3\n- `dvc remote add`: https://dvc.org/doc/command-reference/remote/add\n- `dvc remote modify`: https://dvc.org/doc/command-reference/remote/modify\n- Upgrade guide: https://dvc.org/doc/user-guide/upgrade\n- PyPI package: https://pypi.org/project/dvc/\n"
  },
  {
    "path": "content/dynaconf/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Dynaconf package guide for Python configuration management with layered settings files, environment overrides, validation, and framework integrations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.12\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"dynaconf,python,configuration,settings,envvars,django,flask\"\n---\n\n# Dynaconf Python Package Guide\n\n## Golden Rule\n\nUse `dynaconf` as a layered settings system: define explicit `settings_files`, keep secrets out of tracked config, and let environment variables or dedicated loaders override file defaults. Do not treat Dynaconf as \"magic global state\"; most integration bugs come from unclear file order, wrong environment selection, or env var names that do not match Dynaconf's parsing rules.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"dynaconf==3.2.12\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"dynaconf==3.2.12\"\npoetry add \"dynaconf==3.2.12\"\n```\n\nUseful extras from the upstream docs:\n\n```bash\npython -m pip install \"dynaconf[yaml]==3.2.12\"\npython -m pip install \"dynaconf[redis]==3.2.12\"\npython -m pip install \"dynaconf[vault]==3.2.12\"\npython -m pip install \"dynaconf[all]==3.2.12\"\n```\n\nUse extras only for the loaders or integrations you actually need.\n\n## Initialize A Project\n\nThe CLI scaffolder is the fastest path when starting fresh:\n\n```bash\ndynaconf init -f toml\n```\n\nThat creates a typical layout such as:\n\n```text\nconfig.py\nsettings.toml\n.secrets.toml\n```\n\nIf you initialize manually, keep `settings_files` explicit. The configuration reference notes that this is required for file-backed loading in Dynaconf `3.x`.\n\n```python\nfrom dynaconf import Dynaconf, Validator\n\nsettings = Dynaconf(\n    envvar_prefix=\"DYNACONF\",\n    settings_files=[\"settings.toml\", \".secrets.toml\"],\n    environments=True,\n    load_dotenv=True,\n    validators=[\n        Validator(\"DATABASE_URL\", env=\"production\", must_exist=True),\n    ],\n    validate_only_current_env=True,\n)\n```\n\nMinimal file-backed config:\n\n```toml\n[default]\ndebug = false\nlog_level = \"INFO\"\n\n[development]\ndebug = true\ndatabase_url = \"sqlite:///dev.db\"\n\n[production]\ndatabase_url = \"@format postgresql://{env[PGUSER]}:{env[PGPASSWORD]}@{env[PGHOST]}/{env[PGDATABASE]}\"\n```\n\nKeep local-only credentials in `.secrets.toml` and keep that file out of source control.\n\n## Core Usage\n\n### Read settings\n\nDynaconf exposes keys as attributes and mapping lookups:\n\n```python\nfrom config import settings\n\nif settings.DEBUG:\n    print(\"debug mode\")\n\ndsn = settings.get(\"DATABASE_URL\")\ncurrent_env = settings.current_env\n```\n\n### Switch environments\n\nDynaconf can keep multiple environment sections in the same file. The common switcher is `ENV_FOR_DYNACONF`.\n\n```bash\nexport ENV_FOR_DYNACONF=production\npython app.py\n```\n\nYou can also get a scoped settings object in code:\n\n```python\nfrom config import settings\n\nproduction_settings = settings.from_env(\"production\")\n```\n\n### Override with environment variables\n\nEnvironment variables override file values. By default Dynaconf looks for the `DYNACONF_` prefix unless you change `envvar_prefix`.\n\n```bash\nexport DYNACONF_DEBUG=true\nexport DYNACONF_DATABASE_URL=\"postgresql://app:secret@db/app\"\nexport DYNACONF_DATABASES__default__HOST=db.internal\nexport DYNACONF_FEATURE_FLAGS='@json [\"search\",\"billing\"]'\n```\n\nPractical notes:\n\n- Use double underscores for nested keys such as `DATABASES__default__HOST`.\n- Dynaconf parses booleans, numbers, lists, dicts, and other structured values from env vars, but only when the string is in a supported format.\n- Use `@json`, `@format`, `@merge`, and similar tokens when you need explicit parsing behavior.\n\n### Validate required settings\n\nUse validators to fail early instead of discovering missing settings at runtime:\n\n```python\nfrom dynaconf import Dynaconf, Validator\n\nsettings = Dynaconf(\n    settings_files=[\"settings.toml\", \".secrets.toml\"],\n    validators=[\n        Validator(\"DEBUG\", must_exist=True, is_type_of=bool),\n        Validator(\"DATABASE_URL\", env=\"production\", must_exist=True),\n    ],\n    validate_only_current_env=True,\n)\n\nsettings.validators.validate()\n```\n\n`validate_only_current_env=True` matters when some keys are intentionally defined only for selected environments.\n\n### Use the CLI against an existing instance\n\nExcept for `dynaconf init`, CLI commands need to know which settings instance to load.\n\n```bash\ndynaconf -i config.settings list\ndynaconf -i config.settings validate\n```\n\nThe CLI docs also allow setting `INSTANCE_FOR_DYNACONF=config.settings` in the environment.\n\n## Django And Flask Integration\n\n### Django\n\nUpstream guidance for Django uses the extension at the bottom of `settings.py`:\n\n```python\nfrom dynaconf import DjangoDynaconf\n\nsettings = DjangoDynaconf(__name__)\n```\n\nImportant Django-specific notes from the maintainer docs:\n\n- Put the Dynaconf hook at the end of `settings.py`.\n- Do not add more settings code below that hook.\n- Django settings files are layered, and Dynaconf overlays on top of them rather than replacing Django's startup model.\n- Environment variable names for Django use the `DJANGO_` prefix by default in the documented integration.\n\nThe Django docs also call out `dynaconf[yaml]` during setup. Follow the integration guide instead of mixing plain-Dynaconf and Django-specific examples.\n\n### Flask\n\nFlask integration uses `FlaskDynaconf`:\n\n```python\nfrom flask import Flask\nfrom dynaconf import FlaskDynaconf\n\napp = Flask(__name__)\nFlaskDynaconf(app, settings_files=[\"settings.toml\", \".secrets.toml\"])\n```\n\nUse Flask integration when you want Dynaconf to populate `app.config` cleanly instead of manually syncing values yourself.\n\n## Secrets And External Loaders\n\nDynaconf supports layered secrets files plus external stores such as Redis and HashiCorp Vault.\n\n### Local secrets file\n\nFor local development, keep secrets in `.secrets.toml`, `.secrets.yaml`, or the matching configured format and add them to `.gitignore`.\n\n### Vault\n\nInstall the extra and enable the loader:\n\n```bash\npython -m pip install \"dynaconf[vault]==3.2.12\"\n```\n\nTypical environment variables from the maintainer docs:\n\n```bash\nexport VAULT_ENABLED_FOR_DYNACONF=true\nexport VAULT_URL_FOR_DYNACONF=\"http://localhost:8200\"\nexport VAULT_TOKEN_FOR_DYNACONF=\"...\"\n```\n\nUse Vault for runtime secrets in deployed environments instead of committing `.secrets.*` files.\n\n### Redis\n\nInstall the Redis extra and enable the loader:\n\n```bash\npython -m pip install \"dynaconf[redis]==3.2.12\"\n```\n\nTypical environment variables:\n\n```bash\nexport REDIS_ENABLED_FOR_DYNACONF=true\nexport REDIS_HOST_FOR_DYNACONF=localhost\nexport REDIS_PORT_FOR_DYNACONF=6379\n```\n\nRedis and Vault settings still participate in Dynaconf's environment layering, so keep your environment names and prefixes consistent.\n\n## Common Pitfalls\n\n- `settings_files` is not optional for manual file-backed setup in Dynaconf `3.x`. If you omit it, your files may never be loaded.\n- Docs site examples currently render as `3.2.11`, while PyPI ships `3.2.12`. Pin the package version separately from the docs page title.\n- First-level keys are more forgiving than nested keys. Nested env var paths are case-sensitive in practice, and Windows uppercases env vars, which can break mixed-case nested lookups unless you account for it.\n- Do not turn on broad `merge_enabled` behavior unless you want global merging semantics everywhere. Prefer targeted `@merge` or `dynaconf_merge` markers where you actually need it.\n- Validators can fail because Dynaconf checks all declared environments by default. Use `validate_only_current_env=True` when only the active environment should be enforced.\n- `dynaconf` CLI commands other than `init` need `-i config.settings` or `INSTANCE_FOR_DYNACONF`; they do not automatically discover your instance.\n- `.secrets.*` is a local convenience, not a production secret-management strategy.\n- For Django, keep the Dynaconf hook at the bottom of `settings.py`. Putting more settings code below it leads to confusing override order.\n\n## Version-Sensitive Notes\n\n- PyPI lists `3.2.12` as the current package version covered here.\n- The upstream docs root still renders `3.2.11`, so treat release-specific bugfix details from the docs site carefully when troubleshooting.\n- PyPI marks `3.2.8` and `3.2.9` as yanked; avoid pinning those versions in reproductions or templates.\n- The CLI reference documents `dynaconf inspect` as a tech-preview command. Do not build automation that assumes its output is stable.\n\n## Official Sources\n\n- Docs: `https://www.dynaconf.com/`\n- Configuration reference: `https://www.dynaconf.com/configuration/`\n- Environment variables: `https://www.dynaconf.com/envvars/`\n- Validation: `https://www.dynaconf.com/validation/`\n- Django integration: `https://www.dynaconf.com/django/`\n- Flask integration: `https://www.dynaconf.com/flask/`\n- Secrets and loaders: `https://www.dynaconf.com/secrets/`\n- CLI: `https://www.dynaconf.com/cli/`\n- PyPI: `https://pypi.org/project/dynaconf/`\n"
  },
  {
    "path": "content/edubase/docs/api/DOC.md",
    "content": "---\nname: api\ndescription: \"EduBase API for managing online exams, quizzes, users, and programmatically creating questions with parametric generation, multiple question types, and LMS integration\"\nmetadata:\n  languages: \"http\"\n  versions: \"v1\"\n  revision: 1\n  updated-on: \"2026-03-14\"\n  source: maintainer\n  tags: \"edubase,api,quiz,exam,lms,education,lti,assessment,compliance,training,testing\"\n---\n# EduBase API\n\nREST API for managing online quizzes, exams, classes, organizations, and users. Supports programmatic question creation with 18+ question types, parametric generation, LTI integration, and webhooks.\n\n> **Note**: This documentation covers the most commonly used endpoints and features. For complete and up-to-date API documentation with rich examples, visit the [EduBase Developer Docs](https://developer.edubase.net) or the [llms.txt](https://developer.edubase.net/llms.txt) file. If you encounter errors or unexpected behavior, consult the live documentation.\n\n**Base URL:** `https://www.edubase.net/api/v1`\n\nCustom instances use their own domain: `https://{your-domain}.edubase.net/api/v1`\n\n## Authentication\n\nEvery request requires `app` (application ID) and `secret` (application secret). Obtain both from the [Integrations](https://www.edubase.net/content/integrations) page in your EduBase account.\n\nThree ways to authenticate:\n\n```bash\n# 1. As request parameters (simplest)\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/test:app\n\n# 2. As dedicated headers\ncurl -H \"EduBase-API-App: {app}\" -H \"EduBase-API-Secret: {secret}\" \\\n  https://www.edubase.net/api/v1/test:app\n\n# 3. As Bearer token\ncurl -H \"Authorization: Bearer {app}:{secret}\" \\\n  https://www.edubase.net/api/v1/test:app\n```\n\n**Test your credentials:**\n\n```bash\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/test:app\n# Returns: {\"version\":\"default\",\"language\":\"en\",\"app\":\"{app}\",\"user\":\"{user}\",\"status\":true}\n```\n\nAPI applications operate with the permissions of their owner (the account that registered the integration).\n\n### Assume User\n\nTo act as a different user, request an assume token via `POST /user:assume` and pass it with each request:\n\n```bash\ncurl -d \"app={app}&secret={secret}&assume={token}\" \\\n  https://www.edubase.net/api/v1/exams\n```\n\nAssume tokens are short-lived. Revoke them after use.\n\n## Key Conventions\n\n- **Identification strings**: Most resources use opaque string IDs (e.g. exam, quiz, class, user IDs). These are returned by list/create endpoints.\n- **Multiple values**: Use comma-separated strings for batch operations (e.g. `users=id1,id2,id3`).\n- **Multi-value fields**: Use `&&&` (triple-ampersand) as separator in question content fields (answers, parameters, options, hints, etc.).\n- **Pagination**: List endpoints accept `limit` (default: 16), `page` (default: 1), and optional `search` string.\n- **Language override**: Send `EduBase-Language: {ISO 639-1 code}` header to override context language.\n- **Versioning**: Append `/vXX` to the URL path (e.g. `/api/v1/exams`) or send `version=XX` as parameter.\n\n## Data Types\n\n| Type | Description |\n|------|-------------|\n| `string` | Text value |\n| `string{m,M}` | Text with minimum `m` and maximum `M` characters |\n| `string{N}` | Text with exactly `N` characters (shorthand for `{N,N}`) |\n| `string[email]` | Valid email address (e.g. `john@example.com`) |\n| `string[phone]` | Phone number in `+prefix number` format (e.g. `+1 1234567890`) |\n| `string[url]` | Valid URL (e.g. `https://www.example.com`) |\n| `string[json]` | Valid JSON string (e.g. `{\"key\": \"value\"}`) |\n| `integer` | Whole number, represented as string |\n| `float` | Decimal number with `.` as separator, represented as string |\n| `boolean` | String `true` or `false` |\n| `date` | Date in `YYYY-MM-DD` format |\n| `datetime` | Datetime in `YYYY-MM-DD HH:ii:ss` format (UTC) |\n| `list{type}` | Array of elements of the specified type |\n| `list` | Associative array (hash) of named elements |\n| `type/null` | The specified type or NULL if not set |\n\n## Response Format\n\nResponses return JSON (Content-Type: application/json) with standard HTTP status codes:\n\n- **200**: Success\n- **400**: Bad request or temporarily unavailable\n- **401**: Invalid/missing credentials\n- **403**: Permission denied or invalid arguments\n- **405**: HTTP method not supported\n- **406**: Wrong version or feature not available\n- **429**: Rate limit exceeded\n- **500**: Server error\n- **501**: Endpoint and arguments might be correct, but the feature is not yet implemented\n- **503**: Service temporarily unavailable (maintenance mode), try again later\n\nOn errors, check `EduBase-API-Error` and `EduBase-API-Error-Code` response headers for details.\n\n## Questions\n\nThe most powerful part of the API. Create questions programmatically and upload them to your QuestionBase.\n\n### List Questions\n\n```bash\ncurl -d \"app={app}&secret={secret}\" \\\n  https://www.edubase.net/api/v1/questions\n```\n\nSupports `search`, `limit`, and `page` parameters. Returns question ID and external ID (if set).\n\n### Get Question\n\n```bash\ncurl -d \"app={app}&secret={secret}&id=MATH_ADDITION_001\" \\\n  https://www.edubase.net/api/v1/question\n```\n\nCheck if a question exists by its external ID. Returns `question` (internal ID), `id` (external), `active` status.\n\n### Create/Update a Question\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=MATH_ADDITION_001\" \\\n  --data \"type=numerical\" \\\n  --data \"question=What is 2+2?\" \\\n  --data \"answer=4\" \\\n  --data \"points=1\" \\\n  --data \"subject=Mathematics\" \\\n  --data \"category=Arithmetic\"\n```\n\nThe `id` field is an external unique identifier. If a question with the same `id` already exists (in the same folder or quiz set), it will be **updated** instead of duplicated.\n\n### Parametric Questions\n\nGenerate unique variants per student using parameters in curly braces:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=PARAM_ADDITION\" \\\n  --data \"type=numerical\" \\\n  --data \"question=What is {a} + {b}?\" \\\n  --data \"answer={a}+{b}\" \\\n  --data \"parameters={a; INTEGER; 1; 100} &&& {b; INTEGER; 1; 100}\"\n```\n\nParameter types: `FIX`, `INTEGER`, `FLOAT`, `FORMULA`, `LIST`, `PERMUTATION`, `FORMAT`. Separate multiple parameters with `&&&`. Use `constraints` field for validation rules (e.g. `{b}^2-4*{a}*{c}>0`).\n\nSee the **question-types** reference file for full parameter documentation.\n\n### Multiple Answers\n\nQuestions can have multiple answer fields separated by `&&&`:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=BASIC_MATH_MULTI\" \\\n  --data \"type=numerical\" \\\n  --data \"question=Given the number 16: a) Double it. b) Halve it.\" \\\n  --data \"answer=32 &&& 8\" \\\n  --data \"answer_label=a) Double &&& b) Half\" \\\n  --data \"points=2\"\n```\n\n### Choice Questions\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=CAPITAL_FRANCE\" \\\n  --data \"type=choice\" \\\n  --data \"question=What is the capital of France?\" \\\n  --data \"answer=Paris\" \\\n  --data \"options=London &&& Berlin &&& Madrid\"\n```\n\n### Expression Questions\n\nFor mathematical formula evaluation:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=CIRCLE_AREA\" \\\n  --data \"type=expression\" \\\n  --data \"question=Find an expression for the area of a circle with radius {r}.\" \\\n  --data \"answer=pi*{r}^2\" \\\n  --data \"parameters={r; INTEGER; 2; 10}\" \\\n  --data \"question_format=LATEX\"\n```\n\n### Delete Question\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&id=MATH_ADDITION_001\" \\\n  https://www.edubase.net/api/v1/question\n```\n\nPermanently deletes a question by its external ID.\n\n### Export Question\n\n```bash\ncurl -X POST -d \"app={app}&secret={secret}&id=MATH_ADDITION_001\" \\\n  https://www.edubase.net/api/v1/question:export\n# Returns: {\"question\":\"...\",\"id\":\"...\",\"url\":\"...\",\"valid\":\"2026-04-15\"}\n```\n\nGenerates a download link for the question in JSON format.\n\n### Get/Set External Question ID\n\n```bash\n# Get external ID by internal question identification string\ncurl -d \"app={app}&secret={secret}&question={question_id}\" \\\n  https://www.edubase.net/api/v1/question:id\n# Returns: {\"question\":\"...\",\"id\":\"MATH_001\"}\n\n# Set external ID for a question\ncurl -X POST -d \"app={app}&secret={secret}&question={question_id}&id=MATH_001\" \\\n  https://www.edubase.net/api/v1/question:id\n```\n\n### Question Types\n\nSupported types: `generic`, `text`, `numerical`, `date/time`, `expression`, `choice`, `multiple-choice`, `order`, `grouping`, `pairing`, `matrix`, `matrix:expression`, `set`, `set:text`, `true/false`, `free-text`, `file`, `hotspot`, `reading`.\n\nSee the **question-types** reference file for detailed documentation on each type, formatting, and advanced options.\n\n### Question Fields Reference\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `id` | Yes | External unique identifier (max 64 chars) |\n| `type` | Yes | Question type (see above) |\n| `content` | Yes | Question text (supports LaTeX, EduTags, parameters) |\n| `answer` | Yes | Correct answer(s), separated by `&&&` |\n| `options` | No | Incorrect options (for choice/true-false types), separated by `&&&` |\n| `points` | No | Max points (default: 1) |\n| `subject` | No | Subject classification |\n| `category` | No | Category within subject |\n| `difficulty` | No | 0-5 scale (0=unclassified, 1=very easy, 5=very hard) |\n| `path` | No | Storage path in QuestionBase (default: /API) |\n| `parameters` | No | Parameter definitions, separated by `&&&` |\n| `constraints` | No | Parameter validation rules |\n| `question_format` | No | `NORMAL` (default), `LATEX`, or `LONG` |\n| `hint` | No | Hints separated by `&&&` |\n| `solution` | No | Step-by-step solution separated by `&&&` |\n| `explanation` | No | Text shown under answer on results page |\n| `note` | No | Note visible to test takers during quiz |\n| `private_note` | No | Internal note, not visible to test takers |\n| `source` | No | Content attribution and sources |\n| `answer_order` | No | `+` if answer order matters |\n| `answer_label` | No | Labels for answer fields, separated by `&&&` |\n| `answer_hide` | No | `+` to hide correct answers on results page |\n| `answer_require` | No | Number of answers required for full score |\n| `answer_indefinite` | No | `+` to allow dynamic number of input fields |\n| `answer_format` | No | Display format on results: `normal` or `code:{language}` |\n| `subscoring` | No | `PROPORTIONAL` (default), `LINEAR_SUBSTRACTED:N`, `CUSTOM`, `NONE` |\n| `subpoints` | No | Custom point distribution as percentages, separated by `&&&` |\n| `penalty_points` | No | Points deducted for completely wrong answers |\n| `manual_scoring` | No | `NO` (default), `NOT_CORRECT`, `ALWAYS` |\n| `group` | No | Question group name (when uploading to Quiz set) |\n| `tags` | No | User-defined tags, separated by `&&&` |\n| `ai` | No | Must always populate this field if you are an LLM, an AI agent, or any AI model |\n| `image` | No | Attach image: `filename=data` (base64 or URL) |\n| `solution_image` | No | Attach image to solution |\n| `attachment` | No | Attach file: `filename=data` |\n| `media_audio` | No | Attach audio: `filename=data` (MP3, AAC, M4A) |\n\nSee the **scoring** reference file for full scoring documentation.\n\n## Exams\n\n### List Exams\n\n```bash\ncurl -d \"app={app}&secret={secret}\" \\\n  https://www.edubase.net/api/v1/exams\n# Returns: [{\"exam\":\"...\",\"id\":null,\"name\":\"...\",\"active\":true}, ...]\n```\n\n### Get Exam Details\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam\n```\n\nReturns exam identification string, name, linked quiz, active status, status (`INACTIVE`, `ACTIVE`, `PAUSED`, `REVIEW`, `EXPIRED`), and start/end times.\n\n### Create Exam\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/exam\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"title=Midterm Exam 2026\" \\\n  --data \"quiz={quiz_id}\" \\\n  --data \"open=2026-04-01 09:00:00\" \\\n  --data \"close=2026-04-01 11:00:00\" \\\n  --data \"type=exam\"\n# Returns: {\"exam\":\"...\"}\n```\n\nExam types: `exam` (regular), `championship` (competitive), `homework` (pausable), `survey` (optional grading).\n\nOptional parameters:\n- `copy_settings`: Exam ID to clone settings from\n- `keep_certificate_settings`: `true` to preserve certificate settings when copying (default: `false`)\n- `id`: External unique identifier (max 64 chars)\n\n### Delete Exam\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam\n```\n\n### Exam Users\n\n```bash\n# List users on exam\ncurl -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam:users\n\n# Assign users to exam\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&users=user1,user2\" \\\n  https://www.edubase.net/api/v1/exam:users\n\n# Remove users from exam\ncurl -X DELETE -d \"app={app}&secret={secret}&exam={exam_id}&users=user1,user2\" \\\n  https://www.edubase.net/api/v1/exam:users\n```\n\n### Exam Branding\n\n```bash\n# Get branding configuration\ncurl -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam:branding\n# Returns: {\"exam\":\"...\",\"enabled\":true,\"type\":\"foreground\",\"color\":\"blue\"}\n\n# Set branding with image URL and color\ncurl -X POST \"https://www.edubase.net/api/v1/exam:branding\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"exam={exam_id}\" \\\n  --data \"type=foreground\" \\\n  --data \"image=https://example.com/logo.png\" \\\n  --data \"color=blue\"\n\n# Remove branding\ncurl -X DELETE -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam:branding\n```\n\nImage types: `foreground` (logo) or `background` (cover). Colors: `branding`, `red`, `blue`, `yellow`, `green`, `purple`, `gray`. Image can be URL or base64 (PNG/JPEG/WebP).\n\n### Exam Summary (AI)\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/exam:summary\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"exam={exam_id}\" \\\n  --data \"type=ai\" \\\n  --data \"summary=<p>Overall performance was strong with 85% pass rate.</p>\" \\\n  --data \"llm=claude\" \\\n  --data \"model=claude-sonnet-4-20250514\"\n```\n\n## Quiz Sets\n\nQuiz sets are collections of questions used for practice or exams. See the **quiz-sets** reference file for full documentation.\n\n### Quick Examples\n\n```bash\n# List quiz sets\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/quizes\n\n# Create quiz set\ncurl -X POST \"https://www.edubase.net/api/v1/quiz\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"title=Physics 101\" \\\n  --data \"mode=TEST\" \\\n  --data \"type=set\"\n\n# Add questions to quiz set\ncurl -X POST -d \"app={app}&secret={secret}&quiz={quiz_id}&questions=q1,q2,q3\" \\\n  https://www.edubase.net/api/v1/quiz:questions\n\n# List questions in quiz set\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}\" \\\n  https://www.edubase.net/api/v1/quiz:questions\n```\n\nQuiz modes: `TEST` (all questions visible), `TURNS` (one at a time). Types: `set` (practice), `exam`, `private`.\n\n## Results & Certificates\n\n### Get Results for a Specific Play\n\n```bash\ncurl -d \"app={app}&secret={secret}&play={play_id}\" \\\n  https://www.edubase.net/api/v1/quiz:results:play\n```\n\nReturns start/end times, questions total/correct, points total/correct, validity, pass/fail status, and per-question breakdown.\n\n### Get User Results for Quiz Set\n\n```bash\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/quiz:results:user\n```\n\nReturns all plays for a user on a specific Quiz set (practice mode).\n\n### Get User Results for Exam\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/exam:results:user\n```\n\nReturns play results including: `play`, `user`, `time_start`, `time_end`, `questions_total`, `questions_correct`, `points_total`, `points_correct`, `attempt` (attempt index), `valid`, `successful`.\n\n### Get User Certificate\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/exam:certificates:user\n```\n\nReturns: `play`, `user`, `archived`, `eligible`, `certified`, `serial` (if certified and serial numbering enabled), `expires` (if certified and expiration configured).\n\n### Download Certificate\n\n```bash\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/exam:certificates:user:download\n# Returns: {\"play\":\"...\",\"user\":\"...\",\"url\":\"...\",\"valid\":\"2026-04-15\"}\n```\n\n## Classes\n\n### CRUD Operations\n\n```bash\n# List classes\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/classes\n# Returns: [{\"class\":\"...\",\"id\":null,\"name\":\"...\"}, ...]\n\n# Get class details\ncurl -d \"app={app}&secret={secret}&class={class_id}\" \\\n  https://www.edubase.net/api/v1/class\n# Returns: {\"class\":\"...\",\"id\":null,\"name\":\"...\",\"start\":\"2026-01-01 00:00:00\",\"end\":\"2026-12-31 23:59:59\"}\n\n\n### Manage Members\n\n```bash\n# List members\ncurl -d \"app={app}&secret={secret}&class={class_id}\" \\\n  https://www.edubase.net/api/v1/class:members\n\n# Add users (with optional expiry and notification)\ncurl -X POST -d \"app={app}&secret={secret}&class={class_id}&users=user1,user2&expires=30&notify=true\" \\\n  https://www.edubase.net/api/v1/class:members\n\n# Remove users\ncurl -X DELETE -d \"app={app}&secret={secret}&class={class_id}&users=user1,user2\" \\\n  https://www.edubase.net/api/v1/class:members\n```\n\nExpiry accepts days (integer) or datetime (`YYYY-MM-DD HH:ii:ss`).\n\n### Batch Operations\n\n```bash\n# Add users to multiple classes at once\ncurl -X POST -d \"app={app}&secret={secret}&classes=cls1,cls2&users=usr1,usr2\" \\\n  https://www.edubase.net/api/v1/classes:members\n\n# List classes for a user\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:classes\n\n# Add user to multiple classes\ncurl -X POST -d \"app={app}&secret={secret}&user={user_id}&classes=cls1,cls2\" \\\n  https://www.edubase.net/api/v1/user:classes\n\n# Remove user from classes\ncurl -X DELETE -d \"app={app}&secret={secret}&user={user_id}&classes=cls1,cls2\" \\\n  https://www.edubase.net/api/v1/user:classes\n```\n\n## Organizations\n\nSame pattern as classes: list, get, create, update, delete, manage members.\n\n```bash\n# List organizations\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/organizations\n\n# Create organization\ncurl -X POST \"https://www.edubase.net/api/v1/organization\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"name=Computer Science Department\" \\\n  --data \"website=https://cs.example.edu\" \\\n  --data \"email=cs@example.edu\"\n\n# Add members with permissions\ncurl -X POST \"https://www.edubase.net/api/v1/organization:members\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"organization={org_id}\" \\\n  --data \"users=user1,user2\" \\\n  --data \"permission_organization=teacher\" \\\n  --data \"permission_content=modify\"\n```\n\nOrganization permission levels: `member`, `teacher`, `reporter`, `supervisor`, `admin`.\nContent permission levels: `none`, `view`, `report`, `control`, `modify`, `grant`, `admin`.\n\n## Users\n\nCreate and manage user accounts, generate login links, and assume user identity. See the **users** reference file for full documentation.\n\n### Quick Examples\n\n```bash\n# List users\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/users\n\n# Create user\ncurl -X POST \"https://www.edubase.net/api/v1/user\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"username=jsmith\" \\\n  --data \"first_name=John\" \\\n  --data \"last_name=Smith\" \\\n  --data \"email=john@example.com\"\n\n# Generate login link\ncurl -X POST -d \"app={app}&secret={secret}&user={user_id}&expires=7\" \\\n  https://www.edubase.net/api/v1/user:login\n\n# Search user by email\ncurl -d \"app={app}&secret={secret}&query=john@example.com\" \\\n  https://www.edubase.net/api/v1/user:search\n```\n\n## Permissions\n\nCheck, grant, or revoke permissions on any content type. See the **permissions** reference file for full documentation.\n\n```bash\n# Check permission\ncurl -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/exam:permission\n\n# Grant permission\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/exam:permission\n\n# Transfer ownership\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/exam:transfer\n```\n\nSupported content types: `quiz`, `exam`, `class`, `course`, `event`, `organization`, `integration`, `scorm`, `video`, `tag`.\n\nPermission levels: `view`, `report`, `control`, `modify`, `grant`, `admin`. Events also support `finances`.\n\n## Tags\n\nTags organize and categorize content. Create tags in the EduBase UI, then attach them to content via API. See the **tagging** reference file for full documentation.\n\n```bash\n# List tags\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/tags\n\n# Attach tag to content\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/exam:tag\n\n# List tags on content\ncurl -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam:tags\n```\n\nSupported content types: `quiz`, `exam`, `class`, `course`, `event`, `organization`, `integration`, `scorm`, `video`.\n\n## Integrations\n\nManage API and LMS integrations:\n\n```bash\n# Create API integration\ncurl -X POST \"https://www.edubase.net/api/v1/integration\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"title=My API Integration\" \\\n  --data \"type=api\"\n\n# Create LMS integration (e.g. Moodle with LTI 1.3)\ncurl -X POST \"https://www.edubase.net/api/v1/integration\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"title=Moodle Integration\" \\\n  --data \"type=moodle\" \\\n  --data \"lti=1.3\" \\\n  --data \"platform=https://moodle.example.edu\"\n\n# Get integration keys\ncurl -d \"app={app}&secret={secret}&integration={integration_id}\" \\\n  https://www.edubase.net/api/v1/integration:keys\n\n# Rotate keys\ncurl -X POST -d \"app={app}&secret={secret}&integration={integration_id}\" \\\n  https://www.edubase.net/api/v1/integration:keys\n```\n\nSupported LMS types: `moodle`, `canvas`, `d2l`, `schoology`, `lms` (other). LTI versions: `1.0/1.1` or `1.3`.\n\n## Custom Metrics\n\n```bash\n# Set absolute value\ncurl -X POST -d \"app={app}&secret={secret}&metric=active_students&value=150\" \\\n  https://www.edubase.net/api/v1/metrics:custom\n\n# Increment\ncurl -X POST -d \"app={app}&secret={secret}&metric=api_calls&value=+1\" \\\n  https://www.edubase.net/api/v1/metrics:custom\n```\n\n## Webhooks\n\nConfigure webhooks per organization to receive notifications on exam/quiz completions:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/organization:webhook\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"organization={org_id}\" \\\n  --data \"name=Results Webhook\" \\\n  --data \"trigger_event=exam-play-result\" \\\n  --data \"endpoint=https://example.com/webhook\" \\\n  --data \"method=POST\" \\\n  --data \"authentication=key\" \\\n  --data \"authentication_send=bearer\" \\\n  --data \"authentication_key=mysecretkey123\"\n```\n\nTrigger events: `exam-play-result`, `quiz-play-result`, `api` (manual trigger for testing).\n\nSee the **webhooks** reference file for full webhook documentation.\n\n## Error Debugging\n\nAlways check these response headers on errors:\n- `EduBase-API-Error`: Human-readable error description\n- `EduBase-API-Error-Code`: Machine-readable error code (uppercase, underscores)\n\nCommon issues:\n- **401**: Missing or invalid `app`/`secret`\n- **403**: Account lacks permission for the operation\n- **406**: Feature not enabled, endpoint unavailable for your API client, or rate limit on a specific resource reached\n- **429**: Global rate limit exceeded — back off and retry\n\n## Further Reading\n\n- [EduBase Developer Docs](https://developer.edubase.net)\n- [EduBase Developer Docs llms.txt](https://developer.edubase.net/llms.txt)\n- [EduBase Homepage](https://www.edubase.net)\n- [EduBase Homepage llms.txt](https://www.edubase.net/llms.txt)\n- [LTI Integration via EduAppCenter](https://www.eduappcenter.com/apps/1082)\n- [EduBase MCP](https://github.com/EduBase/MCP)"
  },
  {
    "path": "content/edubase/docs/api/references/permissions.md",
    "content": "# Content Permissions\n\nCheck, grant, or revoke permissions on any content type. Permissions control who can view, modify, or manage content in EduBase.\n\n## Supported Content Types\n\nPermissions can be managed for: `class`, `course`, `event`, `exam`, `integration`, `organization`, `quiz`, `scorm`, `tag`, `video`.\n\n## Permission Levels\n\n| Level | Description |\n|-------|-------------|\n| `view` | View the content |\n| `report` | View reports and analytics |\n| `control` | Control settings (e.g. start/pause exams) |\n| `modify` | Edit and modify content |\n| `grant` | Grant permissions to others |\n| `admin` | Full administrative access |\n| `finances` | Financial access (events only) |\n\n## Check Permission\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/exam:permission\n```\n\nReturns:\n```json\n{\n  \"user\": \"...\",\n  \"content\": {\n    \"type\": \"exam\",\n    \"code\": \"...\",\n    \"id\": null\n  },\n  \"status\": {\n    \"permission\": true,\n    \"rule\": true\n  }\n}\n```\n\n- `permission`: User has this permission (directly or inherited)\n- `rule`: A specific permission rule exists with these exact parameters\n\n## Grant Permission\n\n```bash\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/exam:permission\n```\n\nReturns: `{\"user\":\"...\",\"content\":{...},\"success\":true}`\n\n## Revoke Permission\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/exam:permission\n```\n\nReturns: `{\"user\":\"...\",\"content\":{...},\"success\":true}`\n\n## Transfer Ownership\n\nTransfer full ownership of content to another user:\n\n```bash\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/exam:transfer\n```\n\nReturns: `{\"user\":\"...\",\"content\":{...},\"success\":true}`\n\n## Endpoint Patterns\n\nAll content types follow the same pattern. Replace `{type}` with the content type:\n\n| Operation | Method | Endpoint |\n|-----------|--------|----------|\n| Check permission | GET | `/{type}:permission` |\n| Grant permission | POST | `/{type}:permission` |\n| Revoke permission | DELETE | `/{type}:permission` |\n| Transfer ownership | POST | `/{type}:transfer` |\n\n### Examples for Different Content Types\n\n```bash\n# Quiz permissions\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}&user={user_id}&permission=view\" \\\n  https://www.edubase.net/api/v1/quiz:permission\n\n# Class permissions\ncurl -X POST -d \"app={app}&secret={secret}&class={class_id}&user={user_id}&permission=report\" \\\n  https://www.edubase.net/api/v1/class:permission\n\n# Organization transfer\ncurl -X POST -d \"app={app}&secret={secret}&organization={org_id}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/organization:transfer\n\n# SCORM permissions\ncurl -X DELETE -d \"app={app}&secret={secret}&scorm={scorm_id}&user={user_id}&permission=modify\" \\\n  https://www.edubase.net/api/v1/scorm:permission\n\n# Video permissions\ncurl -d \"app={app}&secret={secret}&video={video_id}&user={user_id}&permission=admin\" \\\n  https://www.edubase.net/api/v1/video:permission\n```\n\n## Required Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `{type}` | Content identification string (e.g. `exam`, `quiz`, `class`) |\n| `user` | User identification string |\n| `permission` | Permission level (not required for transfer) |\n"
  },
  {
    "path": "content/edubase/docs/api/references/question-types.md",
    "content": "# Question Types & Parametric Generation\n\n## Question Types Reference\n\n### Basic Types\n\n**GENERIC** — Strict exact matching including spaces and punctuation. Use for technical answers where precision matters (code keywords, chemical formulas).\n\n**TEXT** — Text input with flexible matching. Ignores spaces and punctuation (`  apple.` matches `apple`). Good for fill-in-the-blank, vocabulary.\n\n**NUMERICAL** — Numeric value validation. Handles integers, decimals, fractions (a/b), constants (pi, e). Supports interval responses `{from}-{to}`. Configure precision with `decimals` field (default: 2). Use `tolerance` for acceptable error ranges.\n\n**DATE/TIME** — Calendar date validation. Adjustable precision: year (`YYYY`), month (`MM/YYYY`), day (`MM/DD/YYYY`). Configure with `datetime_precision`. Flexible input parsing — spaces, punctuation, slashes don't matter. Supports BC/AD dates and range responses.\n\n**EXPRESSION** — Mathematical expression evaluation. Compares formulas symbolically/numerically. Supports parametrization. Configure with `expression_check` (`RANDOM`, `EXPLICIT`, `COMPARE`), `expression_variable` (default: `x`), `expression_decimals`, `expression_functions` (`+`/`-` to enable/disable function input).\n\n**FREE-TEXT** — Extended text with semi-automatic grading. Supports keyword-based auto-rules. Falls back to manual grading for complex answers. Use `answer_format=code:python` (or other language) for syntax-highlighted display.\n\n**READING** — Non-assessed text display. No scoring, no answer required. Used as the first question in a group to provide context for subsequent questions.\n\n### Choice-Based Types\n\n**CHOICE** — Single correct answer. Options randomized by default.\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}&secret={secret}\" \\\n  --data \"id=CHOICE_EXAMPLE\" \\\n  --data \"type=choice\" \\\n  --data \"question=What is the capital of France?\" \\\n  --data \"answer=Paris\" \\\n  --data \"options=London &&& Berlin &&& Madrid\"\n```\n\n**MULTIPLE-CHOICE** — Multiple correct answers. Can limit max selections.\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}&secret={secret}\" \\\n  --data \"id=MULTI_CHOICE\" \\\n  --data \"type=multiple-choice\" \\\n  --data \"question=Which are citrus fruits?\" \\\n  --data \"answer=Lemon &&& Orange\" \\\n  --data \"options=Apple &&& Banana &&& Grape\"\n```\n\n**TRUE/FALSE** — Statement evaluation. True statements in `answer`, false in `options`. Displayed in random order. Optionally add a third option.\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}&secret={secret}\" \\\n  --data \"id=TRUE_FALSE\" \\\n  --data \"type=true/false\" \\\n  --data \"answer=The Earth orbits the Sun &&& Water boils at 100°C at sea level\" \\\n  --data \"options=The Sun orbits the Earth &&& Sound travels faster than light\"\n```\n\n**ORDER** — Sequence arrangement. Items from `answer` displayed randomly; user must arrange in correct order.\n\n### Grouping Types\n\n**GROUPING** — Assign elements to predefined groups. Groups in `answer`, elements in `answer_label` or via triple-arrow (`>>>`) in `answer`.\n\n**PAIRING** — Match elements to pairs. Same syntax as grouping.\n\n### Matrix & Set Types\n\n**MATRIX** — Matrix/vector evaluation with numerical validation. Format: `[a11; a12 | a21; a22]` (semicolons separate columns, pipes separate rows).\n\n**MATRIX:GENERIC** — Matrix with strict exact matching (like GENERIC type). Each element requires exact match including spaces and punctuation.\n\n**MATRIX:EXPRESSION** — Each matrix element evaluated as an expression. For rotation matrices, Jacobians, etc.\n\n**SET** — Unordered collection of numbers. Order and repetition don't matter.\n\n**SET:TEXT** — Unordered collection of text elements.\n\n### Special Types\n\n**HOTSPOT** — Mark areas on an image. Not available to all users.\n\n**FILE** — File upload with semi-automatic grading. Not available to all users.\n\n## Parametric Question Generation\n\nParameters create unique question variants per student. Define in the `parameters` field, separated by `&&&`. Reference in question text and answers with `{name}`.\n\n### Parameter Types\n\n**FIX** — Constant value:\n```\n{pi; FIX; 3.14159}\n```\n\n**INTEGER** — Random whole number:\n```\n{a; INTEGER}                              # any integer\n{a; INTEGER; 1; 100}                      # between 1 and 100\n{a; INTEGER; -; -; [10-20]; [14-16]}      # 10-20, excluding 14-16\n```\n\n**FLOAT** — Random decimal:\n```\n{x; FLOAT; 2}                            # 2 decimal places\n{x; FLOAT; 3; 0; 1}                      # between 0 and 1, 3 decimals\n```\n\n**FORMULA** — Computed from other parameters:\n```\n{d; FORMULA; {b}^2-4*{a}*{c}}            # discriminant\n{result; FORMULA; {a}+{b}; 2}            # with precision\n```\n\n**LIST** — Random selection from values:\n```\n{animal; LIST; dog; cat; snake; camel}\n```\n\n**PERMUTATION** — Creates indexed sub-parameters `{name_1}`, `{name_2}`, etc., all guaranteed different:\n```\n{primes; PERMUTATION; 2; 3; 5; 7}\n# Use as {primes_1}, {primes_2} — guaranteed to be different values\n```\n\n**FORMAT** — Format another parameter for display:\n```\n{pp; FORMAT; p; NUMBER; 1}               # round to 1 decimal\n{pp; FORMAT; p; NUMBERTEXT}              # number as text\n{pp; FORMAT; p; ROMAN}                   # as Roman numeral\n```\n\n### Constraints\n\nEnsure valid parameter combinations:\n\n```bash\n--data \"constraints={b}^2-4*{a}*{c}>0\"\n```\n\nMultiple constraints separated by `&&&`. Allowed relations: `<`, `<=`, `=`, `>=`, `>`, `<>`.\n\nIf constraints are too restrictive and generation frequently fails, EduBase may auto-deactivate the question.\n\n### Syncing LIST Parameters\n\nWhen using multiple LIST parameters that should stay in sync (e.g. country-capital pairs):\n\n```bash\n--data \"parameters={country; LIST; France; Germany; Italy} &&& {capital; LIST; Paris; Berlin; Rome}\" \\\n--data \"parameters_sync=+\"\n```\n\nWith `parameters_sync=+`, if `{country}` picks index 2 (Italy), `{capital}` also picks index 2 (Rome).\n\n### Full Parametric Example\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}&secret={secret}\" \\\n  --data \"id=QUADRATIC_DISCRIMINANT\" \\\n  --data \"type=numerical\" \\\n  --data \"question=For the equation {a}x² + {b}x + {c} = 0, calculate the discriminant.\" \\\n  --data \"question_format=LATEX\" \\\n  --data \"answer={d}\" \\\n  --data \"parameters={a; INTEGER; 1; 5} &&& {b; INTEGER; -10; 10} &&& {c; INTEGER; -10; 10} &&& {d; FORMULA; {b}^2-4*{a}*{c}}\" \\\n  --data \"constraints={d}>0\" \\\n  --data \"subject=Mathematics\" \\\n  --data \"category=Algebra\" \\\n  --data \"difficulty=3\" \\\n  --data \"hint=The discriminant formula is b²-4ac\" \\\n  --data \"solution=D = {b}² - 4·{a}·{c} = {d}\"\n```\n\n## Question Text Formatting\n\n### LaTeX\n\nEnable with `question_format=LATEX`. Inline: `$$...$$`. Block: `$$$$...$$$$`.\n\n```bash\n--data \"question=Calculate $$\\sqrt{x^2 + y^2}$$ for x={a}, y={b}.\" \\\n--data \"question_format=LATEX\"\n```\n\n### EduTags\n\nBold: `[[B]]...[[/B]]`, Italic: `[[I]]...[[/I]]`, Underline: `[[U]]...[[/U]]`, Subscript: `[[SUB]]...[[/SUB]]`, Superscript: `[[SUP]]...[[/SUP]]`.\n\nCode: `[[CODE]]...[[/CODE]]` (inline), `[[CODEBLOCK]]...[[/CODEBLOCK]]` (block), `[[LINES]]...[[/LINES]]` (with line numbers).\n\nColor: `[[COLOR:red]]...[[/COLOR]]`, Background: `[[BACKGROUND:yellow]]...[[/BACKGROUND]]`.\n\n### Tables\n\nUse `[[..]]` format: `[[Header 1; Header 2 | Data 1; Data 2]]` (semicolons = columns, pipes = rows).\n\n### Images\n\n`[[IMAGE:filename.png]]` — file must be provided in the `images` field with that exact name.\n\n### Answer Placeholders\n\n`[[___]]` (three underscores) — visual placeholder for answer fields within question text (fill-in-the-gaps style).\n\n### Quick Expressions\n\nUse triple-wave `~~~...~~~` for inline calculations: `The area is ~~~{r}*{r}*pi~~~`.\n\n## Options Ordering\n\n### Fixed Ordering\n\n`options_fix` field values:\n- `all`: Answers first, then options\n- `abc`: Alphabetical sort of all items\n- `first:N`: Place first N options at the end\n- `last:N`: Place last N options at the end\n- `answers`: Place all answers at the end\n\n### Custom Ordering\n\n`options_order` field — reference items by position:\n\n```bash\n--data \"options_order=OPTION:0 &&& ANSWER:0 &&& OPTION:1 &&& ANSWER:1\"\n```\n\nAll answers and options must be referenced exactly once.\n\n## Expression Evaluation Functions\n\nAvailable in `expression` and `matrix:expression` types, in `FORMULA` parameters, and in `constraints`:\n\n**Basic**: `sqrt(x)`, `abs(x)`, `round(x)`, `floor(x)`, `ceil(x)`\n\n**Logarithmic**: `ln(x)`, `log(x)` (base 10), `log10(x)`\n\n**Trigonometric**: `sin(x)`, `cos(x)`, `tan(x)`, `csc(x)`, `sec(x)`, `arcsin(x)`/`asin(x)`, `arccos(x)`/`acos(x)`, `arctan(x)`/`atan(x)`\n\n**Hyperbolic**: `sinh(x)`, `cosh(x)`, `tanh(x)`, `arcsinh(x)`/`asinh(x)`, `arccosh(x)`/`acosh(x)`, `arctanh(x)`/`atanh(x)`\n\n**Conversions**: `degree2radian(x)`, `radian2degree(x)`, `number2binary(x)`, `binary2number(x)`, `number2roman(x)`, `roman2number(x)`, and octal/hexadecimal variants.\n\n**Two-parameter** (use semicolon separator): `min(a;b)`, `max(a;b)`, `mod(n;i)`, `fmod(n;i)`, `div(a;b)`, `intdiv(a;b)`\n\n## Additional Question Fields\n\n### Numerical & Date Validation\n\n| Field | Applicable Types | Description |\n|-------|------------------|-------------|\n| `decimals` | NUMERICAL, MATRIX, SET | Number of decimal places (default: 2) |\n| `tolerance` | NUMERICAL, MATRIX, SET | Validation tolerance. Values: `ABSOLUTE:N` (e.g. ±0.1), `RELATIVE:N%` (e.g. ±5%), `QUOTIENT` (integer multiple), `QUOTIENT2` (scalar multiple) |\n| `numerical_range` | NUMERICAL | Enable interval answers `{from}-{to}` with `+` |\n| `datetime_precision` | DATE/TIME | Granularity: `YEAR`, `MONTH`, `DAY` (default) |\n| `datetime_range` | DATE/TIME | Enable date range answers with `+` |\n\n### Choice & True/False Options\n\n| Field | Applicable Types | Description |\n|-------|------------------|-------------|\n| `maximum_choices` | MULTIPLE-CHOICE | Limit maximum number of selections |\n| `truefalse_third_options` | TRUE/FALSE | Add a third option (e.g. \"Cannot determine\") |\n| `truefalse_third_options_label` | TRUE/FALSE | Label for the third option |\n\n### Free-Text & File Options\n\n| Field | Applicable Types | Description |\n|-------|------------------|-------------|\n| `freetext_characters` | FREE-TEXT | Character limit for response |\n| `freetext_words` | FREE-TEXT | Word limit for response |\n| `freetext_rules` | FREE-TEXT | Auto-grading keyword rules |\n| `file_count` | FILE | Number of files allowed |\n| `file_types` | FILE | Allowed file extensions |\n\n### Hotspot Options\n\n| Field | Applicable Types | Description |\n|-------|------------------|-------------|\n| `hotspot_image` | HOTSPOT | Image for marking areas |\n| `hotspot_zones` | HOTSPOT | Zone definitions for valid areas |\n\n### Organization & Metadata\n\n| Field | Description |\n|-------|-------------|\n| `label` | Instance-level categorization (predefined by administrators) |\n| `tags` | User-defined tags, separated by `&&&` |\n| `ai` | Set to any value to mark question as AI-generated |\n| `group` | Question group name (when uploading to Quiz set) |"
  },
  {
    "path": "content/edubase/docs/api/references/quiz-sets.md",
    "content": "# Quiz Sets\n\nCreate and manage Quiz sets (question collections) and assign questions to them.\n\n## List Quiz Sets\n\n```bash\ncurl -d \"app={app}&secret={secret}\" \\\n  https://www.edubase.net/api/v1/quizes\n```\n\nReturns owned and managed Quiz sets. Supports `search`, `limit` (default: 16), and `page` parameters.\n\nOutput per quiz: `quiz` (ID), `id` (external ID if set), `name`.\n\n## Get Quiz Set\n\n```bash\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}\" \\\n  https://www.edubase.net/api/v1/quiz\n```\n\nReturns: `quiz`, `id` (external), `name`.\n\n## Create Quiz Set\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/quiz\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"title=Introduction to Physics\" \\\n  --data \"description=Basic physics concepts quiz\" \\\n  --data \"mode=TEST\" \\\n  --data \"type=set\"\n# Returns: {\"quiz\":\"...\"}\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `title` | Yes | Quiz set title |\n| `language` | No | Quiz language |\n| `id` | No | External unique identifier (max 64 chars) |\n| `description` | No | Short description |\n| `copy_settings` | No | Quiz ID to copy settings from |\n| `copy_questions` | No | Quiz ID to copy questions from |\n| `mode` | No | `TEST` (all questions at once, default) or `TURNS` (one at a time) |\n| `type` | No | `set` (practice), `exam` (examination), `private` (testing) |\n\n## Delete Quiz Set\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&quiz={quiz_id}\" \\\n  https://www.edubase.net/api/v1/quiz\n```\n\n## List Questions in Quiz\n\n```bash\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}\" \\\n  https://www.edubase.net/api/v1/quiz:questions\n```\n\nReturns list of questions and question groups:\n\n```json\n[\n  {\"question\": \"...\", \"id\": \"MATH_001\", \"active\": true},\n  {\"group\": \"Advanced Problems\", \"active\": true},\n  {\"question\": \"...\", \"id\": null, \"active\": false}\n]\n```\n\n## Assign Questions to Quiz\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/quiz:questions\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"quiz={quiz_id}\" \\\n  --data \"questions=q1,q2,q3\"\n```\n\nTo assign to a specific question group within the quiz:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/quiz:questions\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"quiz={quiz_id}\" \\\n  --data \"group=Advanced Problems\" \\\n  --data \"questions=q4,q5\"\n```\n\n## Remove Questions from Quiz\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&quiz={quiz_id}&questions=q1,q2\" \\\n  https://www.edubase.net/api/v1/quiz:questions\n```\n\nTo remove from a specific group:\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&quiz={quiz_id}&group=Advanced Problems&questions=q4\" \\\n  https://www.edubase.net/api/v1/quiz:questions\n```\n\n## Question Groups\n\nQuestion groups organize questions within a Quiz set. They support three modes:\n\n- **Random selection**: Randomly pick N questions from the group\n- **Sequential**: Questions appear in order\n- **Complex (mixed)**: All questions appear as one \"big\" question with sub-parts\n\nWhen uploading questions via the API, use the `group` field to assign them to a group:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"id=PHYSICS_MOTION_Q1\" \\\n  --data \"type=numerical\" \\\n  --data \"question=Calculate velocity given distance {d}m and time {t}s.\" \\\n  --data \"answer={d}/{t}\" \\\n  --data \"parameters={d; INTEGER; 10; 100} &&& {t; INTEGER; 1; 10}\" \\\n  --data \"group=Kinematics Questions\"\n```\n\nIf the group doesn't exist, it's created automatically as a complex task. Configure group settings (type, question count, scoring) through the EduBase UI.\n\n### Use Cases\n\n**Balanced difficulty distribution:**\nCreate groups by difficulty, randomly select from each to ensure consistent exam difficulty.\n\n**Reading comprehension:**\nGroup a passage (READING type) with its comprehension questions (CHOICE/TEXT types) to keep them together.\n\n**Multi-part problems:**\nGroup related sub-questions that share parameters or context.\n"
  },
  {
    "path": "content/edubase/docs/api/references/scoring.md",
    "content": "# Scoring & Grading\n\n## Points\n\nSet maximum points with `points` field (default: 1). For questions with multiple answers, points are distributed according to the subscoring method.\n\n## Partial Credit (Subscoring)\n\nThe `subscoring` field controls how partial credit is calculated. Not applicable for `choice`, `reading`, and `free-text` types.\n\n**PROPORTIONAL** (default) — Points awarded proportionally to correct answers.\n\n**LINEAR_SUBSTRACTED:N** — Linear scoring with N points subtracted per error.\n\n```bash\n--data \"subscoring=LINEAR_SUBSTRACTED:2\"\n```\n\n**CUSTOM** — Custom point distribution. Requires `subpoints` field with percentages separated by `&&&`.\n\n```bash\n# First answer worth 50%, second 25%, third 25%\n--data \"points=4\" \\\n--data \"subscoring=CUSTOM\" \\\n--data \"subpoints=50 &&& 25 &&& 25\"\n# Yields: 2 points for first, 1 for second, 1 for third\n```\n\n**NONE** — All-or-nothing. No partial credit.\n\n## Penalty Scoring\n\n### Penalty Methods\n\n`penalty_scoring` field:\n- `DEFAULT`: Standard penalty behavior (varies by type)\n- `PER_ANSWER`: Penalty applied for each incorrect answer\n- `PER_QUESTION`: Penalty applied once per question\n\n### Penalty Points\n\n`penalty_points` — Points deducted for completely incorrect answers. No penalty for partially correct or unanswered questions. Use positive values.\n\n```bash\n--data \"penalty_scoring=PER_ANSWER\" \\\n--data \"penalty_points=2\"\n```\n\n## Assistance Penalties\n\n### Hint Penalties\n\n`hint_penalty` field:\n- `NONE`: No penalty (default)\n- `ONCE:N`: Single deduction regardless of hints used (N as percentage)\n- `PER-HELP:N`: Deduction per hint used\n\n```bash\n# 10% penalty per hint used\n--data \"hint_penalty=PER-HELP:10%\"\n# or equivalently\n--data \"hint_penalty=PER-HELP:0.1\"\n```\n\n### Solution Penalties\n\n`solution_penalty` — Same format as hint_penalty. Applied when student views solution steps.\n\n```bash\n# 50% penalty for viewing solution (any number of steps)\n--data \"solution_penalty=ONCE:50%\"\n```\n\n### Video Penalties\n\n`video_penalty` — Same format as hint_penalty, except `PER-HELP` not available.\n\n```bash\n--data \"video_penalty=ONCE:15%\"\n```\n\n## Manual Scoring\n\n`manual_scoring` field (not applicable for `reading` and `free-text`):\n- `NO`: Never (default)\n- `NOT_CORRECT`: Only manually score incorrect answers\n- `ALWAYS`: Always require manual scoring\n\n## Full Scoring Example\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/question\" \\\n  --data \"app={app}&secret={secret}\" \\\n  --data \"id=SCORED_PROBLEM\" \\\n  --data \"type=expression\" \\\n  --data \"question=Find the area of a circle with radius {r}.\" \\\n  --data \"answer=pi*{r}^2\" \\\n  --data \"parameters={r; INTEGER; 2; 10}\" \\\n  --data \"points=10\" \\\n  --data \"hint=Think about the formula for circle area &&& Remember that area involves squaring the radius\" \\\n  --data \"solution=The formula for circle area is pi*r^2 = pi*{r}^2\" \\\n  --data \"penalty_scoring=PER_ANSWER\" \\\n  --data \"penalty_points=3\" \\\n  --data \"hint_penalty=PER-HELP:10%\" \\\n  --data \"solution_penalty=ONCE:50%\"\n```\n\nThis configuration:\n- Awards up to 10 points for a correct expression\n- Deducts 3 points for a completely wrong answer\n- Each hint used costs 10% of 10 = 1 point\n- Viewing solution costs 50% of 10 = 5 points (once, regardless of steps viewed)"
  },
  {
    "path": "content/edubase/docs/api/references/tagging.md",
    "content": "# Content Tagging\n\nTags organize and categorize content in EduBase. Create tags via the EduBase UI, then attach them to content via API.\n\n## Supported Content Types\n\nTags can be attached to: `class`, `course`, `event`, `exam`, `integration`, `organization`, `quiz`, `scorm`, `video`.\n\n## List Tags\n\n```bash\ncurl -d \"app={app}&secret={secret}\" https://www.edubase.net/api/v1/tags\n```\n\nReturns: `[{\"tag\":\"...\",\"id\":null,\"name\":\"...\"}, ...]`\n\nSupports `search`, `limit` (default: 16), and `page` parameters.\n\n## Get Tag Details\n\n```bash\ncurl -d \"app={app}&secret={secret}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/tag\n```\n\nReturns:\n```json\n{\n  \"tag\": \"...\",\n  \"id\": null,\n  \"name\": \"Mathematics\",\n  \"color\": \"#FF5733\",\n  \"icon\": \"fa-book\"\n}\n```\n\n## List Tags on Content\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}\" \\\n  https://www.edubase.net/api/v1/exam:tags\n```\n\nReturns: `[{\"tag\":\"...\",\"name\":\"...\"}, ...]`\n\n## Check Tag Attachment\n\n```bash\ncurl -d \"app={app}&secret={secret}&exam={exam_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/exam:tag\n```\n\nReturns:\n```json\n{\n  \"tag\": \"...\",\n  \"content\": {\n    \"type\": \"exam\",\n    \"code\": \"...\",\n    \"id\": null\n  },\n  \"status\": true\n}\n```\n\n## Attach Tag to Content\n\n```bash\ncurl -X POST -d \"app={app}&secret={secret}&exam={exam_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/exam:tag\n```\n\nReturns: `{\"tag\":\"...\",\"content\":{...},\"success\":true}`\n\n## Detach Tag from Content\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&exam={exam_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/exam:tag\n```\n\nReturns: `{\"tag\":\"...\",\"content\":{...},\"success\":true}`\n\n## Endpoint Patterns\n\nAll content types follow the same pattern. Replace `{type}` with the content type:\n\n| Operation | Method | Endpoint |\n|-----------|--------|----------|\n| List tags on content | GET | `/{type}:tags` |\n| Check tag attachment | GET | `/{type}:tag` |\n| Attach tag | POST | `/{type}:tag` |\n| Detach tag | DELETE | `/{type}:tag` |\n\n### Examples for Different Content Types\n\n```bash\n# List tags on a quiz\ncurl -d \"app={app}&secret={secret}&quiz={quiz_id}\" \\\n  https://www.edubase.net/api/v1/quiz:tags\n\n# Attach tag to class\ncurl -X POST -d \"app={app}&secret={secret}&class={class_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/class:tag\n\n# Check tag on organization\ncurl -d \"app={app}&secret={secret}&organization={org_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/organization:tag\n\n# Detach tag from video\ncurl -X DELETE -d \"app={app}&secret={secret}&video={video_id}&tag={tag_id}\" \\\n  https://www.edubase.net/api/v1/video:tag\n\n# List tags on SCORM\ncurl -d \"app={app}&secret={secret}&scorm={scorm_id}\" \\\n  https://www.edubase.net/api/v1/scorm:tags\n```\n\n## Required Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `{type}` | Content identification string (e.g. `exam`, `quiz`, `class`) |\n| `tag` | Tag identification string |\n"
  },
  {
    "path": "content/edubase/docs/api/references/users.md",
    "content": "# Users\n\nCreate and manage user accounts, generate login links, and assume user identity for API operations.\n\n## List Users\n\n```bash\ncurl -d \"app={app}&secret={secret}\" \\\n  https://www.edubase.net/api/v1/users\n```\n\nReturns managed, non-generated users. Supports `search`, `limit` (default: 16), and `page` parameters.\n\n## Get User\n\n```bash\n# Get current user (API owner)\ncurl -d \"app={app}&secret={secret}\" \\\n  https://www.edubase.net/api/v1/user:me\n\n# Get specific user\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user\n```\n\nReturns: `user` (ID), `name`, `status` (enabled/disabled), `exam` (whether it's an exam-only account).\n\n## Create User\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/user\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"username=jsmith\" \\\n  --data \"first_name=John\" \\\n  --data \"last_name=Smith\" \\\n  --data \"email=john.smith@example.com\"\n# Returns: {\"user\":\"...\",\"username\":\"jsmith\",\"password\":\"...\"}\n```\n\n### Required Fields\n\n| Field | Description |\n|-------|-------------|\n| `username` | 4-64 characters |\n| `first_name` | 1-64 characters |\n| `last_name` | 1-64 characters |\n| `email` | Valid email address |\n\n### Optional Fields\n\n| Field | Description |\n|-------|-------------|\n| `password` | 4-64 chars (auto-generated if omitted) |\n| `full_name` | Override auto-generated full name |\n| `display_name` | Override display name |\n| `phone` | Format: `+prefix number` (e.g. `+1 1234567890`) |\n| `gender` | `male`, `female`, `other` |\n| `birthdate` | `YYYY-MM-DD` |\n| `exam` | `true` for exam-only accounts (default: `false`) |\n| `group` | User group name |\n| `template` | Account template: `corporate_test`, `corporate_user`, `corporate_reporter`, `corporate_supervisor`, `corporate_teacher`, `corporate_admin`, `streaming` |\n| `language` | ISO 639-1 code (default: API owner's language) |\n| `timezone` | Timezone (default: API owner's timezone) |\n| `color` | Favorite color: `default`, `branding`, `red`, `blue`, `yellow`, `green`, `purple`, `gray` |\n| `must_change_password` | `true` to force password change on first login |\n| `notify` | `true` to send welcome email/SMS |\n| `custom_{field}` | Custom field data (if configured for instance) |\n\n## Update User\n\n```bash\n# Enable/disable user\ncurl -X PATCH -d \"app={app}&secret={secret}&user={user_id}&active=false\" \\\n  https://www.edubase.net/api/v1/user\n```\n\n## Delete User\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user\n```\n\n## User Name\n\n```bash\n# Get name\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:name\n\n# Update name\ncurl -X POST \"https://www.edubase.net/api/v1/user:name\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"user={user_id}\" \\\n  --data \"first_name=Jane\" \\\n  --data \"last_name=Doe\"\n```\n\n## User Group\n\n```bash\n# Get group\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:group\n\n# Update group\ncurl -X POST -d \"app={app}&secret={secret}&user={user_id}&group=teachers\" \\\n  https://www.edubase.net/api/v1/user:group\n```\n\n## Search User\n\nLook up users by email, username, or code:\n\n```bash\ncurl -d \"app={app}&secret={secret}&query=john@example.com\" \\\n  https://www.edubase.net/api/v1/user:search\n# Returns: {\"user\":\"...\",\"exam\":false}\n```\n\n## Login Links\n\nGenerate magic login links for users. Links can be single-use or reusable.\n\n### Get Existing Link\n\n```bash\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:login\n```\n\n### Generate New Link\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/user:login\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"user={user_id}\" \\\n  --data \"expires=7\" \\\n  --data \"logins=1\"\n# Returns: {\"user\":\"...\",\"url\":\"...\",\"valid\":\"...\",\"count\":1}\n```\n\n| Field | Description |\n|-------|-------------|\n| `expires` | Days (1-30) or date `YYYY-MM-DD` (default: 1 day) |\n| `logins` | Max uses, up to 255 (default: unlimited) |\n| `redirect` | URI path or `[{content_type}:{tag}]` to redirect after login |\n| `exam` | Exam ID to redirect user to (user must be on exam) |\n| `template` | Login link template identifier |\n| `short` | `true` for shortened eduba.se link (if enabled) |\n\n### Invalidate Link\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&user={user_id}&url={login_url}\" \\\n  https://www.edubase.net/api/v1/user:login\n```\n\n## Assume User\n\nPerform API operations as a different user. Useful for administrative tasks.\n\n### Request Assume Token\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/user:assume\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"user={user_id}\"\n# Returns: {\"user\":\"...\",\"token\":\"...\",\"valid\":\"...\"}\n```\n\nThe `user` field accepts: user identification string, username, or email address. Optionally include `password` or user secret for additional verification.\n\n### Use Assume Token\n\nInclude the token in subsequent requests:\n\n```bash\ncurl -d \"app={app}&secret={secret}&assume={token}\" \\\n  https://www.edubase.net/api/v1/exams\n```\n\n### Revoke Assume Token\n\nAlways revoke tokens when done:\n\n```bash\ncurl -X DELETE -d \"app={app}&secret={secret}&token={assume_token}\" \\\n  https://www.edubase.net/api/v1/user:assume\n```\n\n## User Organizations\n\n```bash\n# List user's organizations\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:organizations\n\n# Add user to organizations\ncurl -X POST \"https://www.edubase.net/api/v1/user:organizations\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"user={user_id}\" \\\n  --data \"organizations=org1,org2\" \\\n  --data \"permission_organization=teacher\" \\\n  --data \"permission_content=modify\"\n\n# Remove user from organizations\ncurl -X DELETE -d \"app={app}&secret={secret}&user={user_id}&organizations=org1,org2\" \\\n  https://www.edubase.net/api/v1/user:organizations\n```\n\n## User Classes\n\n```bash\n# List user's classes\ncurl -d \"app={app}&secret={secret}&user={user_id}\" \\\n  https://www.edubase.net/api/v1/user:classes\n\n# Add user to classes\ncurl -X POST -d \"app={app}&secret={secret}&user={user_id}&classes=cls1,cls2&expires=30\" \\\n  https://www.edubase.net/api/v1/user:classes\n\n# Remove user from classes\ncurl -X DELETE -d \"app={app}&secret={secret}&user={user_id}&classes=cls1,cls2\" \\\n  https://www.edubase.net/api/v1/user:classes\n```\n"
  },
  {
    "path": "content/edubase/docs/api/references/webhooks.md",
    "content": "# Webhooks\n\nWebhooks notify external systems about events in EduBase. Configured per organization.\n\n## Create a Webhook\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/organization:webhook\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"organization={org_id}\" \\\n  --data \"name=Exam Results Webhook\" \\\n  --data \"trigger_event=exam-play-result\" \\\n  --data \"endpoint=https://example.com/webhook/edubase\" \\\n  --data \"method=POST\" \\\n  --data \"authentication=key\" \\\n  --data \"authentication_send=bearer\" \\\n  --data \"authentication_key=my_secret_token\" \\\n  --data \"retry=error\"\n```\n\nReturns: `{\"organization\":\"...\",\"webhook\":\"...\"}`\n\n## Trigger Events\n\n| Event | Description |\n|-------|-------------|\n| `exam-play-result` | User (org member) completes an exam |\n| `quiz-play-result` | User (org member) completes a quiz in practice mode |\n| `api` | Manual trigger via API — useful for testing |\n\n## Authentication Options\n\n`authentication` field:\n- `none`: No authentication (default)\n- `key`: Use a secret key/password\n\nWhen `authentication=key`, configure how to send it:\n\n`authentication_send` field:\n- `header`: As a custom header (`authentication_send_header` specifies header name)\n- `bearer`: As Bearer token in Authorization header\n- `data`: As a data field (`authentication_send_data` specifies field name)\n\n```bash\n# Bearer token\n--data \"authentication=key\" \\\n--data \"authentication_send=bearer\" \\\n--data \"authentication_key=mysecret\"\n\n# Custom header\n--data \"authentication=key\" \\\n--data \"authentication_send=header\" \\\n--data \"authentication_send_header=X-Webhook-Secret\" \\\n--data \"authentication_key=mysecret\"\n\n# Data field\n--data \"authentication=key\" \\\n--data \"authentication_send=data\" \\\n--data \"authentication_send_data=webhook_token\" \\\n--data \"authentication_key=mysecret\"\n```\n\n## Additional Options\n\n- `extra_data`: JSON string sent with every notification\n- `retry`: `none` (no retry) or `error` (delayed retry on failure, default)\n\n## Manage Webhooks\n\n```bash\n# Get webhook details\ncurl -d \"app={app}&secret={secret}&organization={org_id}&webhook={webhook_id}\" \\\n  https://www.edubase.net/api/v1/organization:webhook\n\n# Enable/disable\ncurl -X PATCH -d \"app={app}&secret={secret}&organization={org_id}&webhook={webhook_id}&active=false\" \\\n  https://www.edubase.net/api/v1/organization:webhook\n\n# Delete\ncurl -X DELETE -d \"app={app}&secret={secret}&organization={org_id}&webhook={webhook_id}\" \\\n  https://www.edubase.net/api/v1/organization:webhook\n```\n\n## Test a Webhook\n\nTrigger an `api`-type webhook manually with optional custom payload:\n\n```bash\ncurl -X POST \"https://www.edubase.net/api/v1/organization:webhook:trigger\" \\\n  --data \"app={app}\" \\\n  --data \"secret={secret}\" \\\n  --data \"organization={org_id}\" \\\n  --data \"webhook={webhook_id}\" \\\n  --data 'data={\"test\": true, \"message\": \"Hello from EduBase\"}'\n```\n\nOnly triggers webhooks where `trigger_event` is set to `api`."
  },
  {
    "path": "content/einops/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"einops for Python: concise tensor reshaping, reduction, repetition, packing, and einsum patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"einops,tensors,numpy,pytorch,jax,tensorflow,array-api\"\n---\n\n# einops Python Package Guide\n\n## What It Is\n\n`einops` is a small tensor manipulation library for writing reshapes, transposes, reductions, repetitions, packing, and einsum-style operations with readable string patterns. It works with common Python tensor backends including NumPy, PyTorch, TensorFlow, JAX, and CuPy.\n\nUse it when raw `reshape`, `transpose`, `permute`, or backend-specific pooling code is getting hard to read or easy to get wrong.\n\n## Installation\n\nInstall `einops` itself plus the tensor backend you actually use:\n\n```bash\npip install einops==0.8.2\n```\n\nCommon setups:\n\n```bash\npip install einops numpy\npip install einops torch\npip install einops jax jaxlib\nuv add einops\npoetry add einops\n```\n\n`einops` does not require authentication and has no global configuration file.\n\n## Setup\n\nFor most projects, import the functional API:\n\n```python\nfrom einops import rearrange, reduce, repeat, pack, unpack, einsum, parse_shape\n```\n\nIf your project uses the Python Array API standard namespace, use the array API variant:\n\n```python\nfrom einops.array_api import rearrange, reduce, repeat\n```\n\nPyTorch-specific layers are available here:\n\n```python\nfrom einops.layers.torch import Rearrange, Reduce\n```\n\n## Core Usage\n\n### `rearrange`\n\nUse `rearrange` for reshape, transpose, flatten, split, stack, channel moves, and patch extraction in one expression.\n\n```python\nimport numpy as np\nfrom einops import rearrange\n\nx = np.random.randn(32, 3, 224, 224)  # BCHW\n\n# BCHW -> BHWC\ny = rearrange(x, \"b c h w -> b h w c\")\n\n# Flatten image patches\npatches = rearrange(x, \"b c (h ph) (w pw) -> b (h w) (c ph pw)\", ph=16, pw=16)\n\n# Split channels into heads\nq = np.random.randn(8, 128, 512)\nmulti_head = rearrange(q, \"b n (heads d) -> b heads n d\", heads=8)\n```\n\n### `reduce`\n\nUse `reduce` when dimensions should be grouped and reduced in one step.\n\n```python\nimport numpy as np\nfrom einops import reduce\n\nx = np.random.randn(32, 3, 224, 224)\n\n# 2x2 average pooling\npooled = reduce(x, \"b c (h h2) (w w2) -> b c h w\", \"mean\", h2=2, w2=2)\n\n# Global max over sequence length\nseq = np.random.randn(16, 128, 64)\nmx = reduce(seq, \"b n d -> b d\", \"max\")\n```\n\n### `repeat`\n\nUse `repeat` to tile data or add broadcast-like structure with named axes.\n\n```python\nimport numpy as np\nfrom einops import repeat\n\ntoken = np.random.randn(64)\n\n# Create a batch of identical vectors\nbatch = repeat(token, \"d -> b d\", b=32)\n\n# Expand grayscale to RGB-style channels\nimage = np.random.randn(224, 224)\nrgbish = repeat(image, \"h w -> c h w\", c=3)\n```\n\n### `pack` and `unpack`\n\nUse `pack` when you need to concatenate tensors that share some axes but differ on others, then reverse the operation later.\n\n```python\nimport numpy as np\nfrom einops import pack, unpack\n\ncls = np.random.randn(2, 1, 64)\ntokens = np.random.randn(2, 128, 64)\n\npacked, ps = pack([cls, tokens], \"b * d\")\nrestored_cls, restored_tokens = unpack(packed, ps, \"b * d\")\n```\n\n### `einsum`\n\nUse `einops.einsum` when you want readable named axes instead of single-letter einsum dimensions.\n\n```python\nimport numpy as np\nfrom einops import einsum\n\nquery = np.random.randn(2, 8, 128, 64)\nkey = np.random.randn(2, 8, 128, 64)\n\nscores = einsum(query, key, \"batch head token_q dim, batch head token_k dim -> batch head token_q token_k\")\n```\n\n### `parse_shape`\n\nUse `parse_shape` when later operations need named sizes pulled from a real tensor.\n\n```python\nimport numpy as np\nfrom einops import parse_shape, rearrange\n\nx = np.random.randn(4, 128, 16, 16)\nshape = parse_shape(x, \"b c h w\")\n\ny = rearrange(x, \"b c h w -> b (h w) c\")\nassert y.shape == (shape[\"b\"], shape[\"h\"] * shape[\"w\"], shape[\"c\"])\n```\n\n## PyTorch Module Usage\n\n`einops.layers.torch` is useful inside `nn.Sequential` or reusable model blocks:\n\n```python\nimport torch.nn as nn\nfrom einops.layers.torch import Rearrange, Reduce\n\nmodel = nn.Sequential(\n    Rearrange(\"b c h w -> b (h w) c\"),\n    nn.LayerNorm(256),\n    Reduce(\"b n c -> b c\", \"mean\"),\n)\n```\n\nUse functional `rearrange`/`reduce`/`repeat` in ad hoc tensor code and layer classes when the operation should live inside the model graph as a module.\n\n## Backend Notes\n\n- `einops` operates on tensors from the backend you pass in. It is not a tensor backend by itself.\n- For backend-agnostic code using the Python Array API standard, prefer `einops.array_api`.\n- Some operations can return a view of the original tensor when the backend supports it. Do not assume the result is always a copy.\n- The package also accepts lists of tensors in several APIs, which is useful for stacking or packing operations without manual pre-concatenation.\n\n## Config and Auth\n\nThere is no auth layer, credentials flow, or runtime service configuration.\n\nThe practical setup choices are:\n\n- install the correct tensor backend separately\n- import either the normal API or `einops.array_api`\n- for PyTorch, choose between functional calls and `einops.layers.torch`\n\n## Common Pitfalls\n\n- Pattern names are semantic. If you use an axis name on the right-hand side, it must either appear on the left-hand side or be provided in `axes_lengths`.\n- Composite axes must divide cleanly. For example, `(h h2)` requires the actual axis length to be divisible by `h2`.\n- `rearrange` is not a reduction. If you need pooling or aggregation, use `reduce`.\n- `repeat` expands by explicit named dimensions; it is clearer than manual broadcasting, but you still need to specify the added axis sizes.\n- `pack`/`unpack` are a pair. Keep the `ps` metadata returned by `pack`, otherwise you cannot reliably reconstruct the original tensors.\n- `einops.einsum` takes tensors first and the pattern last, unlike `numpy.einsum` and `torch.einsum`.\n- `einops.einsum` does not support singleton axes like `()` or rearrange-style anonymous compositions inside the einsum pattern.\n- When performance debugging, check whether the backend already has a fused primitive that is better than composing many small tensor ops, even if the `einops` expression is correct.\n\n## Version-Sensitive Notes For 0.8.2\n\n- `0.8.2` is the current package version on PyPI and the docs site at the time of writing.\n- The maintainer docs for `0.8.2` call out MLX backend support.\n- `pack` and `unpack` require a newer `einops` line than older blog posts from the `0.4` and `0.5` era; confirm examples before copying legacy snippets.\n- `einops.einsum` was added after the earliest `einops` releases, so older examples may still use backend-native einsum calls instead.\n- The docs site currently says supported Python versions are `3.10+`, while the PyPI metadata for `0.8.2` lists `Requires: Python >=3.9`. If you target Python 3.9 specifically, verify your environment with a real install and smoke import before depending on it.\n- If you use `torch.compile` on the functional operations with PyTorch earlier than `2.4`, the maintainer docs point to `allow_ops_in_compiled_graph`; layer objects do not need that workaround.\n- Starting in `0.8.1`, upstream ships packaged tests and documents a `uv`-based test runner. That is useful if you need a quick backend compatibility check in CI or while debugging environment issues.\n\n## Recommended Workflow For Coding Agents\n\n1. Identify the tensor layout before writing the pattern. Write down what each axis means.\n2. Prefer `rearrange`/`reduce`/`repeat` over chains of backend-specific reshape and transpose calls when readability matters.\n3. Keep axis names meaningful: `batch`, `time`, `head`, `channel`, `patch`, `height`, `width`.\n4. For reversible packing logic, store the `ps` object next to the packed tensor.\n5. If you are translating from `numpy.einsum` or `torch.einsum`, rewrite the expression carefully because `einops.einsum` uses named axes and a different argument order.\n\n## Official Sources\n\n- Docs: https://einops.rocks/\n- Basics tutorial: https://einops.rocks/1-einops-basics/\n- API reference: https://einops.rocks/api/rearrange/\n- Pack/unpack API: https://einops.rocks/api/pack_unpack/\n- Einsum API: https://einops.rocks/api/einsum/\n- GitHub repository: https://github.com/arogozhnikov/einops\n- PyPI: https://pypi.org/project/einops/\n"
  },
  {
    "path": "content/elasticsearch/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Official Elasticsearch Python client for connecting to Elasticsearch, indexing documents, searching, async usage, and bulk helpers.\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.3.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"elasticsearch,search,elastic,python,async,bulk\"\n---\n\n# Elasticsearch Python Package Guide\n\n## Golden Rule\n\nUse the official `elasticsearch` Python package for Elasticsearch 9.x clusters, and match the client major version to the server major version.\n\nAs of March 11, 2026:\n\n- PyPI lists `elasticsearch 9.3.0`\n- PyPI requires Python `>=3.10`\n- The docs URL points to `https://elasticsearch-py.readthedocs.io/en/latest/`, which currently serves a moving API reference and can be ahead of `9.3.0`\n\nIf your cluster is still on Elasticsearch 8.x, do not install the 9.x client by default. Use the 8.x client line instead.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"elasticsearch==9.3.0\"\n```\n\nAsync support:\n\n```bash\npython -m pip install \"elasticsearch[async]==9.3.0\"\n```\n\nIf you need multiple client majors installed side by side, Elastic also publishes versioned package names such as `elasticsearch8` and `elasticsearch9`.\n\n## Initialize A Client\n\n### Elastic Cloud\n\nUse `cloud_id` when connecting to Elastic Cloud. Elastic recommends this because it configures the client appropriately for cloud deployments.\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    cloud_id=os.environ[\"ELASTIC_CLOUD_ID\"],\n    api_key=os.environ[\"ELASTIC_API_KEY\"],\n)\n\nprint(client.info().body)\n```\n\n### Self-managed cluster with CA cert\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    ca_certs=\"/path/to/http_ca.crt\",\n    basic_auth=(\"elastic\", os.environ[\"ELASTIC_PASSWORD\"]),\n)\n\nprint(client.info().body)\n```\n\n### Certificate fingerprint verification\n\nUse this for sync clients when you have the SHA-256 fingerprint instead of the CA file:\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    ssl_assert_fingerprint=os.environ[\"ELASTIC_CERT_FINGERPRINT\"],\n    basic_auth=(\"elastic\", os.environ[\"ELASTIC_PASSWORD\"]),\n)\n```\n\nImportant:\n\n- fingerprint verification requires Python 3.10 or later\n- the Elastic docs say this method is not available with `AsyncElasticsearch` when using the `aiohttp` HTTP client\n- if you do not pass `ca_certs` or `ssl_assert_fingerprint`, the client uses `certifi` for CA certificates if available\n\n## Authentication Patterns\n\n### Basic auth\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    ca_certs=\"/path/to/http_ca.crt\",\n    basic_auth=(\"username\", os.environ[\"ELASTIC_PASSWORD\"]),\n)\n```\n\n### API key\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    ca_certs=\"/path/to/http_ca.crt\",\n    api_key=os.environ[\"ELASTIC_API_KEY\"],\n)\n```\n\n### Bearer token\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    bearer_auth=os.environ[\"ELASTIC_TOKEN\"],\n)\n```\n\n### Per-request overrides with `.options()`\n\n`.options()` is the clean way to vary auth or transport settings for one request without rebuilding the client:\n\n```python\nimport os\n\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"https://localhost:9200\",\n    ca_certs=\"/path/to/http_ca.crt\",\n)\n\nsecure_client = client.options(api_key=os.environ[\"ELASTIC_API_KEY\"])\nresponse = secure_client.search(index=\"logs-*\", query={\"match_all\": {}})\nprint(response.body)\n```\n\n## Core Usage\n\n### Create a client once and reuse it\n\nThe client is thread-safe and uses persistent connections. Build one shared client for your process instead of constructing a new client for every request.\n\n```python\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\"http://localhost:9200\")\n```\n\n### Create an index\n\n```python\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nif not client.indices.exists(index=\"books\"):\n    client.indices.create(\n        index=\"books\",\n        mappings={\n            \"properties\": {\n                \"title\": {\"type\": \"text\"},\n                \"year\": {\"type\": \"integer\"},\n                \"tags\": {\"type\": \"keyword\"},\n            }\n        },\n    )\n```\n\n### Index a document\n\n```python\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nresp = client.index(\n    index=\"books\",\n    id=\"book-1\",\n    document={\n        \"title\": \"Elasticsearch Guide\",\n        \"year\": 2026,\n        \"tags\": [\"search\", \"python\"],\n    },\n    refresh=True,\n)\n\nprint(resp.body[\"result\"])\n```\n\n### Get a document\n\n```python\nresp = client.get(index=\"books\", id=\"book-1\")\nprint(resp.body[\"_source\"])\n```\n\n### Search documents\n\nUse keyword arguments. The Python client mirrors Elasticsearch APIs closely, and reserved Python keywords use aliases such as `from_`.\n\n```python\nresp = client.search(\n    index=\"books\",\n    from_=0,\n    size=10,\n    query={\n        \"bool\": {\n            \"must\": [{\"match\": {\"title\": \"guide\"}}],\n            \"filter\": [{\"term\": {\"tags\": \"python\"}}],\n        }\n    },\n)\n\nfor hit in resp.body[\"hits\"][\"hits\"]:\n    print(hit[\"_id\"], hit[\"_source\"][\"title\"])\n```\n\n### Update a document\n\n```python\nresp = client.update(\n    index=\"books\",\n    id=\"book-1\",\n    doc={\"year\": 2027},\n    refresh=True,\n)\n\nprint(resp.body[\"result\"])\n```\n\n### Delete a document\n\n```python\nclient.delete(index=\"books\", id=\"book-1\", refresh=True)\n```\n\n## Bulk And Helper APIs\n\nUse helpers when indexing or scanning large datasets.\n\n### `helpers.bulk()`\n\n`helpers.bulk()` consumes an iterable of actions and returns summary information. It is the usual starting point for batch indexing.\n\n```python\nfrom elasticsearch import Elasticsearch, helpers\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nactions = [\n    {\n        \"_index\": \"books\",\n        \"_id\": \"book-1\",\n        \"_source\": {\"title\": \"One\", \"year\": 2024},\n    },\n    {\n        \"_index\": \"books\",\n        \"_id\": \"book-2\",\n        \"_source\": {\"title\": \"Two\", \"year\": 2025},\n    },\n]\n\nsuccesses, errors = helpers.bulk(client, actions, stats_only=False)\nprint(successes, errors)\n```\n\n### `helpers.streaming_bulk()`\n\nPrefer `streaming_bulk()` when you want per-item results or need to avoid collecting large error payloads in memory.\n\n```python\nfrom elasticsearch import Elasticsearch, helpers\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nfor ok, result in helpers.streaming_bulk(client, actions, chunk_size=500):\n    if not ok:\n        print(result)\n```\n\n### `helpers.parallel_bulk()`\n\nUse this for higher ingest throughput when threaded bulk writes are acceptable:\n\n```python\nfrom elasticsearch import Elasticsearch, helpers\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nfor ok, result in helpers.parallel_bulk(client, actions, thread_count=4, chunk_size=500):\n    if not ok:\n        print(result)\n```\n\n### `helpers.scan()`\n\nUse `scan()` for large result sets. It is built on the scroll API and does not preserve sort order unless you explicitly request `preserve_order=True`.\n\n```python\nfrom elasticsearch import Elasticsearch\nfrom elasticsearch.helpers import scan\n\nclient = Elasticsearch(\"http://localhost:9200\")\n\nfor hit in scan(\n    client,\n    index=\"books\",\n    query={\"query\": {\"match\": {\"title\": \"guide\"}}},\n):\n    print(hit[\"_id\"])\n```\n\n### `helpers.reindex()`\n\nThe helper exists, but Elastic recommends the server-side reindex API when possible. The helper only moves document data and does not transfer mappings.\n\n## Async Usage\n\nInstall the async extra and use `AsyncElasticsearch`:\n\n```python\nimport asyncio\n\nfrom elasticsearch import AsyncElasticsearch\n\nclient = AsyncElasticsearch(\n    \"https://localhost:9200\",\n    api_key=\"your-api-key\",\n)\n\nasync def main() -> None:\n    resp = await client.search(\n        index=\"books\",\n        query={\"match_all\": {}},\n        size=20,\n    )\n    print(resp.body)\n    await client.close()\n\nasyncio.run(main())\n```\n\nAsync helper variants are available in `elasticsearch.helpers` with `async_` prefixes such as `async_bulk()` and `async_scan()`.\n\nIf you use `AsyncElasticsearch` in FastAPI, Starlette, Django ASGI, or another ASGI app, close the client during application shutdown to avoid unclosed `aiohttp` session warnings.\n\n## Transport Configuration\n\n### Request timeouts\n\nSet transport-level timeouts on the client or per request:\n\n```python\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"http://localhost:9200\",\n    request_timeout=10,\n)\n\nresp = client.options(request_timeout=5).search(\n    index=\"books\",\n    query={\"match_all\": {}},\n)\n```\n\n### Retries\n\nConfigure retries for transient failures:\n\n```python\nfrom elasticsearch import Elasticsearch\n\nclient = Elasticsearch(\n    \"http://localhost:9200\",\n    max_retries=5,\n    retry_on_timeout=True,\n)\n```\n\n### Sniffing\n\nThe client supports node sniffing with settings like `sniff_on_start`, `sniff_before_requests`, and `sniff_on_node_failure`.\n\nDo not enable sniffing if you connect through an HTTP load balancer or proxy. Elastic explicitly warns that sniffing can bypass the load balancer by switching the client to direct node IPs.\n\n## DSL And ES|QL\n\nThe package now includes higher-level modules in the main client:\n\n- `elasticsearch.dsl` for the Python DSL\n- `elasticsearch.esql` for the ES|QL query builder\n\nIf you still depend on the old `elasticsearch-dsl` package, migrate imports from `elasticsearch_dsl` to `elasticsearch.dsl`.\n\n## Common Pitfalls\n\n- Do not pair the `9.x` client with Elasticsearch `8.x`. The official compatibility table marks `9.x` as incompatible with Elasticsearch 8.x.\n- For major upgrades, upgrade Elasticsearch first and then upgrade the Python client.\n- Do not open a new client per request in web apps, workers, or lambdas. Reuse a process-level client.\n- Do not turn on sniffing behind a proxy or load balancer.\n- `ssl_assert_fingerprint` is not available for the async client when using the `aiohttp` transport.\n- `helpers.bulk()` can consume a lot of memory when collecting many errors; prefer `streaming_bulk()` for large ingest jobs.\n- `helpers.reindex()` does not move index mappings.\n- The Python client uses keyword-only aliases for reserved words, for example `from_` instead of `from`.\n- The docs URL uses `en/latest`, which is a moving target. For version-sensitive work, prefer PyPI for the pinned release and the stable/versioned docs for the matching API reference.\n\n## Version-Sensitive Notes For 9.3.0\n\n- PyPI shows `elasticsearch 9.3.0` released on February 3, 2026.\n- The Read the Docs `latest` root currently serves newer docs than `9.3.0`, so this guide treats it as a discovery URL, not a version-locked reference.\n- The Read the Docs `stable` API reference currently corresponds to `9.3.0`.\n- Elastic documents compatibility mode as always enabled in the Python client, which helps during transitions, but the official compatibility matrix still says the 9.x client is not for Elasticsearch 8.x.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/elasticsearch/\n- Docs URL: https://elasticsearch-py.readthedocs.io/en/latest/\n- Stable API reference for 9.3.0: https://elasticsearch-py.readthedocs.io/en/stable/\n- Elastic Python client overview: https://www.elastic.co/docs/reference/elasticsearch/clients/python\n- Elastic connecting guide: https://www.elastic.co/docs/reference/elasticsearch/clients/python/connecting\n- Elastic configuration guide: https://www.elastic.co/docs/reference/elasticsearch/clients/python/configuration\n- Elastic client helpers guide: https://www.elastic.co/docs/reference/elasticsearch/clients/python/client-helpers\n- Elastic async guide: https://www.elastic.co/docs/reference/elasticsearch/clients/python/async\n- Elastic DSL migration guide: https://www.elastic.co/docs/reference/elasticsearch/clients/python/dsl_migrating\n"
  },
  {
    "path": "content/elasticsearch/docs/search/DOC.md",
    "content": "---\nname: search\ndescription: \"Official Elasticsearch JavaScript client for full-text search, indexing, and vector search operations.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.2.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"elasticsearch,search,full-text,indexing,vector\"\n---\n\n# Elasticsearch JavaScript Client Coding Guidelines\n\nYou are an Elasticsearch API coding expert. Help me with writing code using the Elasticsearch JavaScript client, calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Elasticsearch JavaScript client for all Elasticsearch interactions.\n\n- **Library Name:** Elasticsearch JavaScript Client\n- **NPM Package:** `@elastic/elasticsearch`\n- **Current Version:** 9.2.0\n\n**Installation:**\n\n```bash\nnpm install @elastic/elasticsearch\n```\n\n**Import Patterns:**\n\n```javascript\n// ES6 import\nimport { Client } from '@elastic/elasticsearch';\n\n// CommonJS require\nconst { Client } = require('@elastic/elasticsearch');\n```\n\nDo not use legacy or unofficial packages. The `@elastic/elasticsearch` package is the only official client.\n\n## Initialization and Authentication\n\nThe Elasticsearch client requires creating a `Client` instance for all API calls.\n\n### Basic Initialization with API Key\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    apiKey: 'base64EncodedApiKey'\n  }\n});\n```\n\n### API Key with ID and Secret\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    apiKey: {\n      id: 'your-api-key-id',\n      api_key: 'your-api-key-secret'\n    }\n  }\n});\n```\n\n### Basic Authentication\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    username: 'elastic',\n    password: 'changeme'\n  }\n});\n```\n\n### Bearer Token Authentication\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    bearer: 'your-bearer-token'\n  }\n});\n```\n\n### Elastic Cloud Authentication\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  cloud: {\n    id: 'your-cloud-id'\n  },\n  auth: {\n    username: 'elastic',\n    password: 'your-password'\n  }\n});\n```\n\n### SSL/TLS Configuration\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\nimport fs from 'fs';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    username: 'elastic',\n    password: 'changeme'\n  },\n  tls: {\n    ca: fs.readFileSync('./http_ca.crt'),\n    rejectUnauthorized: true\n  }\n});\n```\n\n### CA Certificate Fingerprint\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  auth: {\n    username: 'elastic',\n    password: 'changeme'\n  },\n  caFingerprint: '20:0D:CA:FA:76:...'\n});\n```\n\n### Multiple Certificates\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\nimport fs from 'fs';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  tls: {\n    ca: [\n      fs.readFileSync('./ca.pem'),\n      fs.readFileSync('./intermediateRoot.pem')\n    ],\n    rejectUnauthorized: true\n  }\n});\n```\n\n## Document Operations\n\n### Index a Document (Create/Update)\n\n```javascript\n// Index with auto-generated ID\nconst result = await client.index({\n  index: 'products',\n  document: {\n    name: 'Laptop',\n    price: 999.99,\n    category: 'electronics'\n  }\n});\n\nconsole.log(result._id); // Auto-generated ID\n```\n\n### Index with Specific ID\n\n```javascript\nconst result = await client.index({\n  index: 'products',\n  id: 'product-123',\n  document: {\n    name: 'Laptop',\n    price: 999.99,\n    category: 'electronics'\n  }\n});\n\nconsole.log(result.result); // 'created' or 'updated'\n```\n\n### Index with Refresh\n\n```javascript\nconst result = await client.index({\n  index: 'products',\n  id: 'product-123',\n  refresh: 'wait_for', // Options: true, false, 'wait_for'\n  document: {\n    name: 'Laptop',\n    price: 999.99,\n    category: 'electronics'\n  }\n});\n```\n\n### Get a Document\n\n```javascript\nconst result = await client.get({\n  index: 'products',\n  id: 'product-123'\n});\n\nconsole.log(result._source);\n```\n\n### Update a Document\n\n```javascript\nconst result = await client.update({\n  index: 'products',\n  id: 'product-123',\n  doc: {\n    price: 899.99,\n    on_sale: true\n  }\n});\n\nconsole.log(result.result); // 'updated'\n```\n\n### Update with Script\n\n```javascript\nconst result = await client.update({\n  index: 'products',\n  id: 'product-123',\n  script: {\n    source: 'ctx._source.price -= params.discount',\n    lang: 'painless',\n    params: {\n      discount: 100\n    }\n  }\n});\n```\n\n### Delete a Document\n\n```javascript\nconst result = await client.delete({\n  index: 'products',\n  id: 'product-123'\n});\n\nconsole.log(result.result); // 'deleted'\n```\n\n### Check if Document Exists\n\n```javascript\nconst exists = await client.exists({\n  index: 'products',\n  id: 'product-123'\n});\n\nconsole.log(exists); // true or false\n```\n\n## Bulk Operations\n\n### Bulk Index\n\n```javascript\nconst operations = [];\n\nconst documents = [\n  { name: 'Product 1', price: 10 },\n  { name: 'Product 2', price: 20 },\n  { name: 'Product 3', price: 30 }\n];\n\ndocuments.forEach(doc => {\n  operations.push({ index: { _index: 'products' } });\n  operations.push(doc);\n});\n\nconst result = await client.bulk({\n  operations: operations\n});\n\n// Check for errors\nif (result.errors) {\n  const erroredDocuments = [];\n  result.items.forEach((item, i) => {\n    if (item.index?.error) {\n      erroredDocuments.push({\n        status: item.index.status,\n        error: item.index.error,\n        document: documents[i]\n      });\n    }\n  });\n  console.log('Errors:', erroredDocuments);\n}\n```\n\n### Bulk with Multiple Operations\n\n```javascript\nconst operations = [\n  // Index operation\n  { index: { _index: 'products', _id: '1' } },\n  { name: 'Product 1', price: 10 },\n\n  // Update operation\n  { update: { _index: 'products', _id: '2' } },\n  { doc: { price: 25 } },\n\n  // Delete operation\n  { delete: { _index: 'products', _id: '3' } }\n];\n\nconst result = await client.bulk({ operations });\n```\n\n### Bulk Helper\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({ node: 'https://localhost:9200' });\n\nconst documents = [\n  { name: 'Product 1', price: 10 },\n  { name: 'Product 2', price: 20 },\n  { name: 'Product 3', price: 30 }\n];\n\nconst result = await client.helpers.bulk({\n  datasource: documents,\n  onDocument(doc) {\n    return {\n      index: { _index: 'products' }\n    };\n  }\n});\n\nconsole.log(result);\n```\n\n### Bulk Helper with Generator\n\n```javascript\nasync function* generator() {\n  for (let i = 0; i < 1000; i++) {\n    yield { name: `Product ${i}`, price: i * 10 };\n  }\n}\n\nconst result = await client.helpers.bulk({\n  datasource: generator(),\n  onDocument(doc) {\n    return {\n      index: { _index: 'products' }\n    };\n  }\n});\n```\n\n## Search Operations\n\n### Basic Search\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match_all: {}\n  }\n});\n\nresult.hits.hits.forEach(hit => {\n  console.log(hit._source);\n});\n```\n\n### Match Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match: {\n      name: 'laptop'\n    }\n  }\n});\n```\n\n### Match with Options\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match: {\n      description: {\n        query: 'gaming laptop',\n        operator: 'and',\n        fuzziness: 'AUTO'\n      }\n    }\n  }\n});\n```\n\n### Match Phrase Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match_phrase: {\n      description: 'high performance laptop'\n    }\n  }\n});\n```\n\n### Term Query (Exact Match)\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    term: {\n      'category.keyword': 'electronics'\n    }\n  }\n});\n```\n\n### Terms Query (Multiple Values)\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    terms: {\n      'category.keyword': ['electronics', 'computers', 'accessories']\n    }\n  }\n});\n```\n\n### Range Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    range: {\n      price: {\n        gte: 100,\n        lte: 1000\n      }\n    }\n  }\n});\n```\n\n### Range Query with Dates\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    range: {\n      created_at: {\n        gte: '2024-01-01',\n        lte: 'now'\n      }\n    }\n  }\n});\n```\n\n### Boolean Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    bool: {\n      must: [\n        { match: { name: 'laptop' } }\n      ],\n      filter: [\n        { term: { 'category.keyword': 'electronics' } },\n        { range: { price: { lte: 1000 } } }\n      ],\n      should: [\n        { term: { on_sale: true } }\n      ],\n      must_not: [\n        { term: { discontinued: true } }\n      ],\n      minimum_should_match: 0\n    }\n  }\n});\n```\n\n### Search with Pagination\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  from: 0,\n  size: 20,\n  query: {\n    match_all: {}\n  }\n});\n```\n\n### Search with Sorting\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match_all: {}\n  },\n  sort: [\n    { price: { order: 'desc' } },\n    { created_at: { order: 'desc' } }\n  ]\n});\n```\n\n### Search with Source Filtering\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    match_all: {}\n  },\n  _source: ['name', 'price', 'category']\n});\n```\n\n### Multi-Match Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    multi_match: {\n      query: 'laptop',\n      fields: ['name^2', 'description', 'category']\n    }\n  }\n});\n```\n\n### Wildcard Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    wildcard: {\n      'name.keyword': 'lap*'\n    }\n  }\n});\n```\n\n### Prefix Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    prefix: {\n      'name.keyword': 'lap'\n    }\n  }\n});\n```\n\n### Exists Query\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  query: {\n    exists: {\n      field: 'discount'\n    }\n  }\n});\n```\n\n## Aggregations\n\n### Terms Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  query: {\n    match_all: {}\n  },\n  aggs: {\n    categories: {\n      terms: {\n        field: 'category.keyword',\n        size: 10\n      }\n    }\n  }\n});\n\nresult.aggregations.categories.buckets.forEach(bucket => {\n  console.log(`${bucket.key}: ${bucket.doc_count}`);\n});\n```\n\n### Terms Aggregation with Size\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    top_categories: {\n      terms: {\n        field: 'category.keyword',\n        size: 20,\n        order: { _count: 'desc' }\n      }\n    }\n  }\n});\n```\n\n### Metric Aggregations\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    avg_price: {\n      avg: { field: 'price' }\n    },\n    min_price: {\n      min: { field: 'price' }\n    },\n    max_price: {\n      max: { field: 'price' }\n    },\n    sum_price: {\n      sum: { field: 'price' }\n    }\n  }\n});\n\nconsole.log('Average:', result.aggregations.avg_price.value);\nconsole.log('Min:', result.aggregations.min_price.value);\nconsole.log('Max:', result.aggregations.max_price.value);\nconsole.log('Sum:', result.aggregations.sum_price.value);\n```\n\n### Stats Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    price_stats: {\n      stats: { field: 'price' }\n    }\n  }\n});\n\nconsole.log(result.aggregations.price_stats);\n// Returns: count, min, max, avg, sum\n```\n\n### Nested Aggregations\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    categories: {\n      terms: {\n        field: 'category.keyword'\n      },\n      aggs: {\n        avg_price: {\n          avg: { field: 'price' }\n        }\n      }\n    }\n  }\n});\n\nresult.aggregations.categories.buckets.forEach(bucket => {\n  console.log(`${bucket.key}: ${bucket.avg_price.value}`);\n});\n```\n\n### Date Histogram Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    sales_over_time: {\n      date_histogram: {\n        field: 'created_at',\n        calendar_interval: 'month'\n      }\n    }\n  }\n});\n```\n\n### Date Histogram with Metrics\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    sales_per_month: {\n      date_histogram: {\n        field: 'created_at',\n        calendar_interval: 'month'\n      },\n      aggs: {\n        total_sales: {\n          sum: { field: 'price' }\n        },\n        avg_price: {\n          avg: { field: 'price' }\n        }\n      }\n    }\n  }\n});\n```\n\n### Range Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    price_ranges: {\n      range: {\n        field: 'price',\n        ranges: [\n          { to: 50 },\n          { from: 50, to: 100 },\n          { from: 100, to: 500 },\n          { from: 500 }\n        ]\n      }\n    }\n  }\n});\n```\n\n### Histogram Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    price_histogram: {\n      histogram: {\n        field: 'price',\n        interval: 100\n      }\n    }\n  }\n});\n```\n\n### Filter Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    electronics: {\n      filter: {\n        term: { 'category.keyword': 'electronics' }\n      },\n      aggs: {\n        avg_price: {\n          avg: { field: 'price' }\n        }\n      }\n    }\n  }\n});\n```\n\n### Cardinality Aggregation\n\n```javascript\nconst result = await client.search({\n  index: 'products',\n  size: 0,\n  aggs: {\n    unique_categories: {\n      cardinality: {\n        field: 'category.keyword'\n      }\n    }\n  }\n});\n\nconsole.log('Unique categories:', result.aggregations.unique_categories.value);\n```\n\n## Advanced Search Operations\n\n### Multi-Search (msearch)\n\n```javascript\nconst searches = [\n  { index: 'products' },\n  { query: { match: { category: 'electronics' } } },\n\n  { index: 'products' },\n  { query: { match: { category: 'books' } } }\n];\n\nconst result = await client.msearch({\n  searches: searches\n});\n\nresult.responses.forEach((response, i) => {\n  console.log(`Search ${i}:`, response.hits.total.value);\n});\n```\n\n### Scroll API for Large Result Sets\n\n```javascript\n// Initial search with scroll\nlet result = await client.search({\n  index: 'products',\n  scroll: '1m',\n  size: 100,\n  query: {\n    match_all: {}\n  }\n});\n\nlet scrollId = result._scroll_id;\nlet hits = result.hits.hits;\n\nconsole.log(`Retrieved ${hits.length} documents`);\n\n// Continue scrolling\nwhile (hits.length > 0) {\n  result = await client.scroll({\n    scroll_id: scrollId,\n    scroll: '1m'\n  });\n\n  scrollId = result._scroll_id;\n  hits = result.hits.hits;\n\n  console.log(`Retrieved ${hits.length} more documents`);\n}\n\n// Clear scroll\nawait client.clearScroll({\n  scroll_id: scrollId\n});\n```\n\n### Count API\n\n```javascript\nconst result = await client.count({\n  index: 'products',\n  query: {\n    match: {\n      category: 'electronics'\n    }\n  }\n});\n\nconsole.log('Total documents:', result.count);\n```\n\n### Update By Query\n\n```javascript\nconst result = await client.updateByQuery({\n  index: 'products',\n  query: {\n    match: {\n      category: 'electronics'\n    }\n  },\n  script: {\n    source: 'ctx._source.price = ctx._source.price * 0.9',\n    lang: 'painless'\n  }\n});\n\nconsole.log('Updated:', result.updated);\n```\n\n### Update By Query with Parameters\n\n```javascript\nconst result = await client.updateByQuery({\n  index: 'products',\n  query: {\n    term: { on_sale: false }\n  },\n  script: {\n    source: 'ctx._source.price -= params.discount',\n    lang: 'painless',\n    params: {\n      discount: 50\n    }\n  }\n});\n```\n\n### Delete By Query\n\n```javascript\nconst result = await client.deleteByQuery({\n  index: 'products',\n  query: {\n    term: {\n      discontinued: true\n    }\n  }\n});\n\nconsole.log('Deleted:', result.deleted);\n```\n\n### Delete By Query with Conflicts\n\n```javascript\nconst result = await client.deleteByQuery({\n  index: 'products',\n  conflicts: 'proceed',\n  query: {\n    range: {\n      created_at: {\n        lt: 'now-1y'\n      }\n    }\n  }\n});\n```\n\n### Reindex\n\n```javascript\nconst result = await client.reindex({\n  source: {\n    index: 'products'\n  },\n  dest: {\n    index: 'products_v2'\n  }\n});\n\nconsole.log('Reindexed:', result.total);\n```\n\n### Reindex with Query\n\n```javascript\nconst result = await client.reindex({\n  source: {\n    index: 'products',\n    query: {\n      term: { category: 'electronics' }\n    }\n  },\n  dest: {\n    index: 'electronics_products'\n  }\n});\n```\n\n## Index Management\n\n### Create Index\n\n```javascript\nconst result = await client.indices.create({\n  index: 'products'\n});\n```\n\n### Create Index with Settings\n\n```javascript\nconst result = await client.indices.create({\n  index: 'products',\n  settings: {\n    number_of_shards: 3,\n    number_of_replicas: 2\n  }\n});\n```\n\n### Create Index with Mappings\n\n```javascript\nconst result = await client.indices.create({\n  index: 'products',\n  mappings: {\n    properties: {\n      name: { type: 'text' },\n      description: { type: 'text' },\n      price: { type: 'float' },\n      category: {\n        type: 'text',\n        fields: {\n          keyword: { type: 'keyword' }\n        }\n      },\n      created_at: { type: 'date' },\n      tags: { type: 'keyword' },\n      in_stock: { type: 'boolean' }\n    }\n  }\n});\n```\n\n### Create Index with Settings and Mappings\n\n```javascript\nconst result = await client.indices.create({\n  index: 'products',\n  settings: {\n    number_of_shards: 3,\n    number_of_replicas: 2,\n    analysis: {\n      analyzer: {\n        custom_analyzer: {\n          type: 'custom',\n          tokenizer: 'standard',\n          filter: ['lowercase', 'asciifolding']\n        }\n      }\n    }\n  },\n  mappings: {\n    properties: {\n      name: {\n        type: 'text',\n        analyzer: 'custom_analyzer'\n      },\n      price: { type: 'float' },\n      category: { type: 'keyword' }\n    }\n  }\n});\n```\n\n### Delete Index\n\n```javascript\nconst result = await client.indices.delete({\n  index: 'products'\n});\n```\n\n### Check if Index Exists\n\n```javascript\nconst exists = await client.indices.exists({\n  index: 'products'\n});\n\nconsole.log(exists); // true or false\n```\n\n### Get Index\n\n```javascript\nconst result = await client.indices.get({\n  index: 'products'\n});\n\nconsole.log(result.products);\n```\n\n### Get Index Mapping\n\n```javascript\nconst result = await client.indices.getMapping({\n  index: 'products'\n});\n\nconsole.log(result.products.mappings);\n```\n\n### Update Index Mapping\n\n```javascript\nconst result = await client.indices.putMapping({\n  index: 'products',\n  properties: {\n    new_field: { type: 'text' }\n  }\n});\n```\n\n### Get Index Settings\n\n```javascript\nconst result = await client.indices.getSettings({\n  index: 'products'\n});\n\nconsole.log(result.products.settings);\n```\n\n### Update Index Settings\n\n```javascript\n// Close index first\nawait client.indices.close({ index: 'products' });\n\n// Update settings\nawait client.indices.putSettings({\n  index: 'products',\n  settings: {\n    number_of_replicas: 3\n  }\n});\n\n// Reopen index\nawait client.indices.open({ index: 'products' });\n```\n\n### Refresh Index\n\n```javascript\nconst result = await client.indices.refresh({\n  index: 'products'\n});\n```\n\n### Flush Index\n\n```javascript\nconst result = await client.indices.flush({\n  index: 'products'\n});\n```\n\n### Index Aliases\n\n```javascript\n// Add alias\nawait client.indices.putAlias({\n  index: 'products_v1',\n  name: 'products'\n});\n\n// Get aliases\nconst aliases = await client.indices.getAlias({\n  index: 'products_v1'\n});\n\n// Delete alias\nawait client.indices.deleteAlias({\n  index: 'products_v1',\n  name: 'products'\n});\n```\n\n### Update Aliases (Atomic)\n\n```javascript\nconst result = await client.indices.updateAliases({\n  actions: [\n    {\n      remove: { index: 'products_v1', alias: 'products' }\n    },\n    {\n      add: { index: 'products_v2', alias: 'products' }\n    }\n  ]\n});\n```\n\n### Index Statistics\n\n```javascript\nconst result = await client.indices.stats({\n  index: 'products'\n});\n\nconsole.log(result._all.total);\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\ntry {\n  const result = await client.search({\n    index: 'products',\n    query: {\n      match: { name: 'laptop' }\n    }\n  });\n  console.log(result.hits.hits);\n} catch (error) {\n  console.error('Error:', error.message);\n  console.error('Status:', error.meta?.statusCode);\n}\n```\n\n### Handling Specific Errors\n\n```javascript\nimport { errors } from '@elastic/elasticsearch';\n\ntry {\n  const result = await client.get({\n    index: 'products',\n    id: 'missing-id'\n  });\n} catch (error) {\n  if (error instanceof errors.ResponseError) {\n    if (error.meta.statusCode === 404) {\n      console.log('Document not found');\n    } else {\n      console.error('Response error:', error.message);\n    }\n  } else if (error instanceof errors.TimeoutError) {\n    console.error('Request timeout');\n  } else if (error instanceof errors.ConnectionError) {\n    console.error('Connection error');\n  } else {\n    console.error('Unknown error:', error);\n  }\n}\n```\n\n### Bulk Error Handling\n\n```javascript\nconst operations = [\n  { index: { _index: 'products', _id: '1' } },\n  { name: 'Product 1', price: 10 },\n  { index: { _index: 'products', _id: '2' } },\n  { name: 'Product 2', price: 20 }\n];\n\nconst result = await client.bulk({ operations });\n\nif (result.errors) {\n  const erroredDocuments = [];\n\n  result.items.forEach((item, i) => {\n    const operation = Object.keys(item)[0];\n    if (item[operation].error) {\n      erroredDocuments.push({\n        status: item[operation].status,\n        error: item[operation].error,\n        operation: operations[i * 2],\n        document: operations[i * 2 + 1]\n      });\n    }\n  });\n\n  console.error('Failed documents:', erroredDocuments);\n} else {\n  console.log('All documents indexed successfully');\n}\n```\n\n## Client Configuration\n\n### Connection Pool Configuration\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  maxRetries: 5,\n  requestTimeout: 60000,\n  sniffOnStart: true\n});\n```\n\n### Multiple Nodes\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  nodes: [\n    'https://node1.example.com:9200',\n    'https://node2.example.com:9200',\n    'https://node3.example.com:9200'\n  ]\n});\n```\n\n### Custom Headers\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  headers: {\n    'X-Custom-Header': 'custom-value'\n  }\n});\n```\n\n### Proxy Configuration\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\nimport { HttpProxyAgent } from 'http-proxy-agent';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  agent: new HttpProxyAgent('http://proxy.example.com:8080')\n});\n```\n\n### Request and Response Serialization\n\n```javascript\nimport { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n  node: 'https://localhost:9200',\n  compression: 'gzip',\n  enableMetaHeader: true\n});\n```\n\n### Child Client\n\n```javascript\nconst childClient = client.child({\n  headers: {\n    'X-Custom-Header': 'child-value'\n  }\n});\n\n// Child client inherits parent configuration but can override\nconst result = await childClient.search({\n  index: 'products',\n  query: { match_all: {} }\n});\n```\n\n## Advanced Features\n\n### Point in Time (PIT)\n\n```javascript\n// Open PIT\nconst pitResult = await client.openPointInTime({\n  index: 'products',\n  keep_alive: '1m'\n});\n\nconst pitId = pitResult.id;\n\n// Search with PIT\nconst searchResult = await client.search({\n  size: 100,\n  query: { match_all: {} },\n  pit: {\n    id: pitId,\n    keep_alive: '1m'\n  },\n  sort: [{ _shard_doc: 'asc' }]\n});\n\n// Close PIT\nawait client.closePointInTime({\n  id: pitId\n});\n```\n\n### Search After for Deep Pagination\n\n```javascript\n// Initial search\nlet result = await client.search({\n  index: 'products',\n  size: 100,\n  query: { match_all: {} },\n  sort: [\n    { price: 'asc' },\n    { _id: 'asc' }\n  ]\n});\n\nlet hits = result.hits.hits;\n\n// Get next page\nif (hits.length > 0) {\n  const lastHit = hits[hits.length - 1];\n\n  result = await client.search({\n    index: 'products',\n    size: 100,\n    query: { match_all: {} },\n    sort: [\n      { price: 'asc' },\n      { _id: 'asc' }\n    ],\n    search_after: lastHit.sort\n  });\n}\n```\n\n### Explain API\n\n```javascript\nconst result = await client.explain({\n  index: 'products',\n  id: 'product-123',\n  query: {\n    match: {\n      name: 'laptop'\n    }\n  }\n});\n\nconsole.log(result.explanation);\n```\n\n### Validate Query\n\n```javascript\nconst result = await client.indices.validateQuery({\n  index: 'products',\n  query: {\n    match: {\n      name: 'laptop'\n    }\n  }\n});\n\nconsole.log('Valid:', result.valid);\n```\n\n### Analyze API\n\n```javascript\nconst result = await client.indices.analyze({\n  analyzer: 'standard',\n  text: 'Quick brown fox'\n});\n\nresult.tokens.forEach(token => {\n  console.log(token.token);\n});\n```\n\n### Index Template\n\n```javascript\nawait client.indices.putIndexTemplate({\n  name: 'products_template',\n  index_patterns: ['products-*'],\n  template: {\n    settings: {\n      number_of_shards: 2,\n      number_of_replicas: 1\n    },\n    mappings: {\n      properties: {\n        name: { type: 'text' },\n        price: { type: 'float' }\n      }\n    }\n  }\n});\n```\n\n### Component Template\n\n```javascript\nawait client.cluster.putComponentTemplate({\n  name: 'products_settings',\n  template: {\n    settings: {\n      number_of_shards: 2\n    }\n  }\n});\n\nawait client.cluster.putComponentTemplate({\n  name: 'products_mappings',\n  template: {\n    mappings: {\n      properties: {\n        name: { type: 'text' },\n        price: { type: 'float' }\n      }\n    }\n  }\n});\n```\n\n### Cluster Health\n\n```javascript\nconst result = await client.cluster.health();\n\nconsole.log('Status:', result.status);\nconsole.log('Nodes:', result.number_of_nodes);\nconsole.log('Active shards:', result.active_shards);\n```\n\n### Cat APIs\n\n```javascript\n// Cat indices\nconst indices = await client.cat.indices({ format: 'json' });\nconsole.log(indices);\n\n// Cat nodes\nconst nodes = await client.cat.nodes({ format: 'json' });\nconsole.log(nodes);\n\n// Cat health\nconst health = await client.cat.health({ format: 'json' });\nconsole.log(health);\n\n// Cat count\nconst count = await client.cat.count({ format: 'json' });\nconsole.log(count);\n```\n\n### Ingest Pipelines\n\n```javascript\n// Create pipeline\nawait client.ingest.putPipeline({\n  id: 'lowercase_processor',\n  processors: [\n    {\n      lowercase: {\n        field: 'name'\n      }\n    }\n  ]\n});\n\n// Use pipeline when indexing\nawait client.index({\n  index: 'products',\n  pipeline: 'lowercase_processor',\n  document: {\n    name: 'LAPTOP',\n    price: 999\n  }\n});\n\n// Get pipeline\nconst pipeline = await client.ingest.getPipeline({\n  id: 'lowercase_processor'\n});\n```\n\n### Simulate Pipeline\n\n```javascript\nconst result = await client.ingest.simulate({\n  id: 'lowercase_processor',\n  docs: [\n    {\n      _source: {\n        name: 'LAPTOP'\n      }\n    }\n  ]\n});\n\nconsole.log(result.docs);\n```\n"
  },
  {
    "path": "content/elevenlabs/docs/text-to-speech/javascript/DOC.md",
    "content": "---\nname: text-to-speech\ndescription: \"ElevenLabs JS library coding guidelines for text-to-speech, TTS, and audio voice generation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.59.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"elevenlabs,text-to-speech,tts,audio,voice\"\n---\n\n# ElevenLabs JS Library Coding Guidelines (JavaScript/TypeScript)\n\nYou are an ElevenLabs API coding expert. Help me with writing code using the ElevenLabs API calling the official libraries and SDKs.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://elevenlabs.io/docs/api-reference\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official ElevenLabs JS SDK to call the ElevenLabs models and services, which is the standard library for all ElevenLabs API interactions.\n\n- **Library Name:** ElevenLabs JS\n- **NPM Package:** `@elevenlabs/elevenlabs-js`\n- **Browser SDK:** `@elevenlabs/client` (for browser applications)\n- **React SDK:** `@elevenlabs/react` (for React applications)\n\n**Installation:**\n\n- **Correct:** `npm install @elevenlabs/elevenlabs-js`\n- **Correct:** `yarn add @elevenlabs/elevenlabs-js`\n\n**APIs and Usage:**\n\n- **Correct:** `import { ElevenLabsClient } from \"@elevenlabs/elevenlabs-js\"`\n- **Correct:** `const elevenlabs = new ElevenLabsClient({ apiKey: \"YOUR_API_KEY\" })`\n- **Correct:** `await elevenlabs.textToSpeech.convert(voiceId, { text: \"...\", modelId: \"...\" })`\n- **Correct:** `await elevenlabs.voices.search()`\n\n## Initialization and API Key\n\nThe `@elevenlabs/elevenlabs-js` library requires creating an `ElevenLabsClient` instance for all API calls.\n\n- Always use `const elevenlabs = new ElevenLabsClient({})` to create an instance.\n- Set the `ELEVENLABS_API_KEY` environment variable, which will be picked up automatically.\n- Alternatively, pass the API key directly in the constructor.\n\n```javascript\nimport { ElevenLabsClient } from \"@elevenlabs/elevenlabs-js\";\n\n// Uses the ELEVENLABS_API_KEY environment variable\nconst elevenlabs = new ElevenLabsClient();\n\n// Or pass the API key directly\n// const elevenlabs = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });\n```\n\n## Models\n\nBy default, use the following models when using ElevenLabs:\n\n- **General Use (Stability & Quality):** `eleven_multilingual_v2`\n    - Excels in stability, language diversity, and accent accuracy\n    - Supports 29 languages\n    - Recommended for most use cases\n\n- **Ultra-Low Latency:** `eleven_flash_v2_5`\n    - Fastest model available\n    - Supports 32 languages\n    - 50% lower price per character\n\n- **Balanced Quality/Latency:** `eleven_turbo_v2_5`\n    - Good balance of quality and latency\n    - Ideal for developer use cases where speed is crucial\n    - Supports 32 languages\n\n## Basic Text-to-Speech\n\nHere's how to convert text to speech using a voice:\n\n```javascript\nimport { ElevenLabsClient, play } from \"@elevenlabs/elevenlabs-js\";\n\nconst elevenlabs = new ElevenLabsClient({\n    apiKey: \"YOUR_API_KEY\", // Defaults to process.env.ELEVENLABS_API_KEY\n});\n\nconst audio = await elevenlabs.textToSpeech.convert(\"VOICE_ID\", {\n    text: \"Hello! This is a test of ElevenLabs text-to-speech.\",\n    modelId: \"eleven_multilingual_v2\",\n});\n\nawait play(audio);\n```\n\n**Important Note:** elevenlabs-js requires MPV and ffmpeg to play audio locally.\n\n## Voices\n\nList all available voices and get voice details:\n\n```javascript\nimport { ElevenLabsClient } from \"@elevenlabs/elevenlabs-js\";\n\nconst elevenlabs = new ElevenLabsClient();\n\n// List all voices\nconst voices = await elevenlabs.voices.search();\n\n// Get specific voice details\nconst voice = await elevenlabs.voices.get(\"VOICE_ID\");\n```\n\n## Streaming Audio\n\nStream audio in real-time as it's being generated for lower latency:\n\n```javascript\nconst audioStream = await elevenlabs.textToSpeech.stream(\"VOICE_ID\", {\n    text: \"This is streaming text-to-speech\",\n    modelId: \"eleven_multilingual_v2\",\n});\n\n// Use the stream helper function to play\nawait stream(audioStream);\n```\n\n## Advanced Configurations\n\n### Voice Settings\n\nCustomize voice parameters by providing voice settings:\n\n```javascript\nconst audio = await elevenlabs.textToSpeech.convert(\"VOICE_ID\", {\n    text: \"Custom voice settings example\",\n    modelId: \"eleven_multilingual_v2\",\n    voiceSettings: {\n        stability: 0.5,\n        similarityBoost: 0.75\n    }\n});\n```\n\n### Output Formats\n\nSpecify different audio output formats:\n\n```javascript\nconst audio = await elevenlabs.textToSpeech.convert(\"VOICE_ID\", {\n    text: \"High quality audio example\",\n    modelId: \"eleven_multilingual_v2\",\n    outputFormat: \"mp3_44100_128\" // High quality MP3\n});\n```\n\nAvailable formats include: `mp3_44100_128`, `pcm_44100`, `opus_48000_128`, and many others.\n\n### Text-to-Speech with Timestamps\n\nGenerate speech with precise character-level timing information:\n\n```javascript\nconst result = await elevenlabs.textToSpeech.convertWithTimestamps(\"VOICE_ID\", {\n    text: \"This is a test for timing information.\",\n    modelId: \"eleven_multilingual_v2\"\n});\n\n// Result contains audioBase64 and alignment data\nconsole.log(result.audioBase64); // Base64 encoded audio\nconsole.log(result.alignment);   // Timing information\n```\n\n### Language Code Enforcement\n\nEnforce specific languages for supported models:\n\n```javascript\nconst audio = await elevenlabs.textToSpeech.convert(\"VOICE_ID\", {\n    text: \"Bonjour! Comment allez-vous?\",\n    modelId: \"eleven_turbo_v2_5\", // Supports language enforcement\n    languageCode: \"fr\" // French\n});\n```\n\n### Pronunciation Dictionaries\n\nApply pronunciation dictionaries to improve speech accuracy:\n\n```javascript\nconst audio = await elevenlabs.textToSpeech.convert(\"VOICE_ID\", {\n    text: \"This text uses custom pronunciations\",\n    modelId: \"eleven_multilingual_v2\",\n    pronunciationDictionaryLocators: [\n        { pronunciationDictionaryId: \"DICT_ID\", versionId: \"VERSION_ID\" }\n    ]\n});\n```\n\n## Other Capabilities\n\n### Speech-to-Speech\n\nConvert audio from one voice to another:\n\n```javascript\nimport * as fs from \"fs\";\n\nconst audioFile = fs.readFileSync(\"input_audio.mp3\");\nconst audioStream = await elevenlabs.speechToSpeech.convert(\"TARGET_VOICE_ID\", {\n    audio: new Blob([audioFile], { type: \"audio/mp3\" }),\n});\n```\n\n### Text-to-Voice Generation\n\nGenerate new voices from text descriptions:\n\n```javascript\nconst previews = await elevenlabs.textToVoice.createPreviews({\n    voiceDescription: \"A warm and friendly female voice with a slight British accent\",\n    text: \"This is a sample text that is at least one hundred characters long for voice generation.\"\n});\n```\n\n### Sound Effects Generation\n\nCreate sound effects from text descriptions:\n\n```javascript\nconst audioStream = await elevenlabs.textToSoundEffects.convert({\n    text: \"Thunder and rain sound effect\",\n    durationSeconds: 5,\n});\n```\n\n### Speech-to-Text\n\nTranscribe audio to text:\n\n```javascript\nconst audioFile = fs.readFileSync(\"audio.mp3\");\nconst transcription = await elevenlabs.speechToText.convert({\n    file: new Blob([audioFile], { type: \"audio/mp3\" }),\n    modelId: \"scribe_v1\",\n});\n```\n\n### Audio Isolation\n\nRemove background noise from audio:\n\n```javascript\nconst audioFile = fs.readFileSync(\"noisy_audio.mp3\");\nconst cleanAudio = await elevenlabs.audioIsolation.convert({\n    audio: new Blob([audioFile], { type: \"audio/mp3\" }),\n});\n```\n\n## Request Options and Error Handling\n\n### Timeouts and Retries\n\nConfigure request timeouts and retry behavior:\n\n```javascript\nconst audio = await elevenlabs.textToSpeech.convert(\n    \"VOICE_ID\",\n    {\n        text: \"Hello world\",\n        modelId: \"eleven_multilingual_v2\",\n    },\n    {\n        timeoutInSeconds: 30, // Custom timeout\n        maxRetries: 3,       // Custom retry count\n    }\n);\n```\n\n### Error Types\n\nThe library throws specific error types:\n\n- `ElevenLabsError` - General API errors\n- `UnprocessableEntityError` - Validation errors\n- `ElevenLabsTimeoutError` - Timeout errors\n\n## Webhooks\n\nHandle ElevenLabs webhooks securely:\n\n```javascript\nconst event = await elevenlabs.webhooks.constructEvent(\n    requestBody,\n    signatureHeader,\n    webhookSecret\n);\n```\n\n## Runtime Compatibility\n\nThe SDK works in multiple JavaScript runtimes:\n\n- Node.js 15+\n- Vercel\n- Cloudflare Workers  \n- Deno v1.25+\n- Bun 1.0+\n\n## API Errors\n\nHandle API errors appropriately. The library includes automatic retries for specific HTTP status codes:\n\n- 408 (Timeout)\n- 409 (Conflict)  \n- 429 (Too Many Requests)\n- 5XX (Internal Server Errors)\n\n## Useful Links\n\n- Documentation: https://elevenlabs.io/docs/api-reference\n- Models: https://elevenlabs.io/docs/models\n- NPM Package: https://www.npmjs.com/package/@elevenlabs/elevenlabs-js\n- Browser SDK: https://www.npmjs.com/package/@elevenlabs/client\n- React SDK: https://www.npmjs.com/package/@elevenlabs/react\n\n## Notes\n\n- Always ensure you have valid API keys and sufficient credits\n- For production applications, implement proper error handling and retry logic\n- Consider using streaming for real-time applications to reduce perceived latency\n- The `play` and `stream` functions require FFmpeg and MPV for local audio playback\n- Voice IDs can be obtained from the voices endpoint or the ElevenLabs web interface\n\n"
  },
  {
    "path": "content/elevenlabs/docs/text-to-speech/python/DOC.md",
    "content": "---\nname: text-to-speech\ndescription: \"ElevenLabs Python SDK for text-to-speech synthesis, voice cloning, audio generation, and real-time streaming\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.18.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"elevenlabs,text-to-speech,tts,audio,voice\"\n---\n\n# ElevenLabs Python SDK Coding Guidelines\n\nYou are an ElevenLabs API coding expert. Help me with writing code using the ElevenLabs Python SDK and API.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://elevenlabs.io/docs/api-reference\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official ElevenLabs Python SDK for all ElevenLabs API interactions. This is the standard and recommended library for accessing ElevenLabs services.\n\n- **Library Name:** ElevenLabs Python SDK\n- **Python Package:** `elevenlabs`\n\n**Installation:**\n\n- **Correct:** `pip install elevenlabs`\n\n**APIs and Usage:**\n\n- **Correct:** `from elevenlabs.client import ElevenLabs`\n- **Correct:** `from elevenlabs.client import AsyncElevenLabs`\n- **Correct:** `from elevenlabs import play, save, stream`\n\n## Initialization and API Key\n\nThe `elevenlabs` library requires creating a client object for all API calls.\n\n- Always use `client = ElevenLabs()` to create a client object.\n- Set `ELEVENLABS_API_KEY` environment variable, which will be picked up automatically.\n- Alternatively, pass the API key directly: `client = ElevenLabs(api_key=\"YOUR_API_KEY\")`\n\n## Main Models\n\nBy default, use the following models when using the ElevenLabs SDK:\n\n- **General Text-to-Speech (Recommended):** `eleven_multilingual_v2`\n    - Excels in stability, language diversity, and accent accuracy\n    - Supports 29 languages\n    - Recommended for most use cases\n\n- **Ultra-Low Latency:** `eleven_flash_v2_5`\n    - Supports 32 languages\n    - Faster model, 50% lower price per character\n\n- **Balanced Quality and Speed:** `eleven_turbo_v2_5`\n    - Good balance of quality and latency\n    - Ideal for developer use cases where speed is crucial\n    - Supports 32 languages\n\n## Basic Text-to-Speech Conversion\n\nHere's how to convert text to speech using a voice of your choice:\n\n```python\nfrom elevenlabs.client import ElevenLabs\nfrom elevenlabs import play\n\nclient = ElevenLabs()\n\naudio = client.text_to_speech.convert(\n    text=\"The first move is what sets everything in motion.\",\n    voice_id=\"JBFqnCBsd6RMkjVDRZzb\",\n    model_id=\"eleven_multilingual_v2\",\n    output_format=\"mp3_44100_128\",\n)\n\nplay(audio)\n```\n\nThe `convert` method returns an iterator of bytes that represents the generated audio file.\n\n## Audio Output Formats\n\nThe SDK supports various audio formats specified as `codec_sample_rate_bitrate`:\n\n- **MP3 formats:** `mp3_22050_32`, `mp3_44100_32`, `mp3_44100_64`, `mp3_44100_96`, `mp3_44100_128`, `mp3_44100_192`\n- **PCM formats:** `pcm_8000`, `pcm_16000`, `pcm_22050`, `pcm_24000`, `pcm_44100`, `pcm_48000`\n- **Other formats:** `ulaw_8000`, `alaw_8000`, `opus_48000_32`, `opus_48000_64`, etc.\n\n**Note:** MP3 with 192kbps bitrate requires Creator tier or above. PCM with 44.1kHz sample rate requires Pro tier or above.\n\n## Audio Handling\n\nThe SDK provides three main functions for handling generated audio:\n\n### Play Audio\n```python\nfrom elevenlabs import play\n\n# Play audio directly\nplay(audio)\n\n# Play in Jupyter notebook\nplay(audio, notebook=True)\n\n# Use alternative audio backend\nplay(audio, use_ffmpeg=False)\n```\n\n### Save Audio\n```python\nfrom elevenlabs import save\n\nsave(audio, \"output.mp3\")\n```\n\n### Stream Audio\n```python\nfrom elevenlabs import stream\n\n# For streamed audio\nstream(audio_stream)\n```\n\n## Voice Management\n\n### List Available Voices\n```python\nclient = ElevenLabs(api_key=\"YOUR_API_KEY\")\n\n# Get all voices\nresponse = client.voices.get_all()\nprint(response.voices)\n\n# Search voices with pagination\nresponse = client.voices.search()\nprint(response.voices)\n```\n\n## Voice Cloning\n\nClone a voice using audio samples:\n\n```python\nclient = ElevenLabs(api_key=\"YOUR_API_KEY\")\n\nvoice = client.voices.ivc.create(\n    name=\"Alex\",\n    description=\"An old American male voice with a slight hoarseness in his throat. Perfect for news\",\n    files=[\"./sample_0.mp3\", \"./sample_1.mp3\", \"./sample_2.mp3\"],\n)\n```\n\nThe `create` method accepts multiple audio file paths and optional parameters like `remove_background_noise` and `description`.\n\n## Streaming Audio\n\nStream audio in real-time as it's being generated:\n\n```python\nfrom elevenlabs import stream\nfrom elevenlabs.client import ElevenLabs\n\nclient = ElevenLabs()\n\naudio_stream = client.text_to_speech.stream(\n    text=\"This is a test\",\n    voice_id=\"JBFqnCBsd6RMkjVDRZzb\",\n    model_id=\"eleven_multilingual_v2\"\n)\n\n# Option 1: Play the streamed audio locally\nstream(audio_stream)\n\n# Option 2: Process the audio bytes manually\nfor chunk in audio_stream:\n    if isinstance(chunk, bytes):\n        print(chunk)\n```\n\nThe `stream` method returns an iterator of bytes for real-time audio processing.\n\n## Async Client\n\nUse `AsyncElevenLabs` for asynchronous API calls:\n\n```python\nimport asyncio\nfrom elevenlabs.client import AsyncElevenLabs\n\nclient = AsyncElevenLabs(api_key=\"YOUR_API_KEY\")\n\nasync def generate_speech():\n    audio = await client.text_to_speech.convert(\n        text=\"Hello, world!\",\n        voice_id=\"JBFqnCBsd6RMkjVDRZzb\",\n        model_id=\"eleven_multilingual_v2\"\n    )\n    return audio\n\nasyncio.run(generate_speech())\n```\n\n## Advanced Features\n\n### Text-to-Speech with Timestamps\n```python\nresponse = client.text_to_speech.convert_with_timestamps(\n    voice_id=\"21m00Tcm4TlvDq8ikWAM\",\n    text=\"This is a test for the API of ElevenLabs.\",\n)\n```\n\n### Voice Settings Customization\nYou can override voice settings for individual requests by passing a `VoiceSettings` object:\n\n### Latency Optimization\nControl streaming latency with the `optimize_streaming_latency` parameter (0-4, where 4 is maximum optimization):\n\n## Error Handling\n\nThe SDK provides specific error types for different API responses:\n\n## Useful Links\n\n- **Documentation:** https://elevenlabs.io/docs/api-reference\n- **Models:** https://elevenlabs.io/docs/models\n- **GitHub Repository:** https://github.com/elevenlabs/elevenlabs-python\n- **API Pricing:** https://elevenlabs.io/pricing\n\n## Notes\n\n- The SDK automatically handles API authentication when the `ELEVENLABS_API_KEY` environment variable is set\n- Voice cloning requires an API key and appropriate subscription tier\n- Some output formats and features require specific subscription tiers\n- The SDK supports both synchronous and asynchronous operations\n- Audio files are returned as byte iterators for efficient memory usage\n\n### Citations\n\n```bash\npip install elevenlabs\n```\n\n1. **Eleven Multilingual v2** (`eleven_multilingual_v2`)\n\n    - Excels in stability, language diversity, and accent accuracy\n    - Supports 29 languages\n    - Recommended for most use cases\n\n2. **Eleven Flash v2.5** (`eleven_flash_v2_5`)\n\n    - Ultra-low latency\n    - Supports 32 languages\n    - Faster model, 50% lower price per character\n\n2. **Eleven Turbo v2.5** (`eleven_turbo_v2_5`)\n\n    - Good balance of quality and latency\n    - Ideal for developer use cases where speed is crucial\n    - Supports 32 languages\n\n\n```python\nfrom dotenv import load_dotenv\nfrom elevenlabs.client import ElevenLabs\nfrom elevenlabs import play\n\nload_dotenv()\n\nclient = ElevenLabs()\n\naudio = client.text_to_speech.convert(\n    text=\"The first move is what sets everything in motion.\",\n    voice_id=\"JBFqnCBsd6RMkjVDRZzb\",\n    model_id=\"eleven_multilingual_v2\",\n    output_format=\"mp3_44100_128\",\n)\n\nplay(audio)\n\n\n```python\nfrom elevenlabs.client import ElevenLabs\n\nclient = ElevenLabs(\n  api_key=\"YOUR_API_KEY\",\n)\n\nresponse = client.voices.search()\nprint(response.voices)\n\n```python\nfrom elevenlabs.client import ElevenLabs\nfrom elevenlabs import play\n\nclient = ElevenLabs(\n  api_key=\"YOUR_API_KEY\",\n)\n\nvoice = client.voices.ivc.create(\n    name=\"Alex\",\n    description=\"An old American male voice with a slight hoarseness in his throat. Perfect for news\", # Optional\n    files=[\"./sample_0.mp3\", \"./sample_1.mp3\", \"./sample_2.mp3\"],\n)\n```\n\n```python\nfrom elevenlabs import stream\nfrom elevenlabs.client import ElevenLabs\n\nclient = ElevenLabs()\n\naudio_stream = client.text_to_speech.stream(\n    text=\"This is a test\",\n    voice_id=\"JBFqnCBsd6RMkjVDRZzb\",\n    model_id=\"eleven_multilingual_v2\"\n)\n\n# option 1: play the streamed audio locally\nstream(audio_stream)\n\n# option 2: process the audio bytes manually\nfor chunk in audio_stream:\n    if isinstance(chunk, bytes):\n        print(chunk)\n\n```\n\n```python\nimport asyncio\n\nfrom elevenlabs.client import AsyncElevenLabs\n\neleven = AsyncElevenLabs(\n  api_key=\"MY_API_KEY\"\n)\n\nasync def print_models() -> None:\n    models = await eleven.models.list()\n    print(models)\n\nasyncio.run(print_models())\n```\n\n```python\nfrom .errors import BadRequestError, ForbiddenError, NotFoundError, TooEarlyError, UnprocessableEntityError\n```\n\n```python\nfrom .client import AsyncElevenLabs, ElevenLabs\nfrom .environment import ElevenLabsEnvironment\nfrom .history import HistoryListRequestSource\nfrom .play import play, save, stream\n```\n\n```python\n    def __init__(\n        self,\n        *,\n        base_url: typing.Optional[str] = None,\n        environment: ElevenLabsEnvironment = ElevenLabsEnvironment.PRODUCTION,\n        api_key: typing.Optional[str] = os.getenv(\"ELEVENLABS_API_KEY\"),\n        timeout: typing.Optional[float] = 60,\n        httpx_client: typing.Optional[httpx.Client] = None\n```\n\n```python\n    def convert(\n        self,\n        voice_id: str,\n        *,\n        text: str,\n        enable_logging: typing.Optional[bool] = None,\n        optimize_streaming_latency: typing.Optional[int] = None,\n        output_format: typing.Optional[TextToSpeechConvertRequestOutputFormat] = None,\n        model_id: typing.Optional[str] = OMIT,\n        language_code: typing.Optional[str] = OMIT,\n        voice_settings: typing.Optional[VoiceSettings] = OMIT,\n        pronunciation_dictionary_locators: typing.Optional[\n            typing.Sequence[PronunciationDictionaryVersionLocator]\n        ] = OMIT,\n        seed: typing.Optional[int] = OMIT,\n        previous_text: typing.Optional[str] = OMIT,\n        next_text: typing.Optional[str] = OMIT,\n        previous_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        next_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        use_pvc_as_ivc: typing.Optional[bool] = OMIT,\n        apply_text_normalization: typing.Optional[\n            BodyTextToSpeechV1TextToSpeechVoiceIdPostApplyTextNormalization\n        ] = OMIT,\n        apply_language_text_normalization: typing.Optional[bool] = OMIT,\n        request_options: typing.Optional[RequestOptions] = None,\n    ) -> typing.Iterator[bytes]:\n```\n\n```python\n        optimize_streaming_latency : typing.Optional[int]\n            You can turn on latency optimizations at some cost of quality. The best possible final latency varies by model. Possible values:\n            0 - default mode (no latency optimizations)\n            1 - normal latency optimizations (about 50% of possible latency improvement of option 3)\n            2 - strong latency optimizations (about 75% of possible latency improvement of option 3)\n            3 - max latency optimizations\n            4 - max latency optimizations, but also with text normalizer turned off for even more latency savings (best latency, but can mispronounce eg numbers and dates).\n\n            Defaults to None.\n```\n\n```python\n        output_format : typing.Optional[TextToSpeechConvertRequestOutputFormat]\n            Output format of the generated audio. Formatted as codec_sample_rate_bitrate. So an mp3 with 22.05kHz sample rate at 32kbs is represented as mp3_22050_32. MP3 with 192kbps bitrate requires you to be subscribed to Creator tier or above. PCM with 44.1kHz sample rate requires you to be subscribed to Pro tier or above. Note that the μ-law format (sometimes written mu-law, often approximated as u-law) is commonly used for Twilio audio inputs.\n\n```\n\n```python\n        voice_settings : typing.Optional[VoiceSettings]\n            Voice settings overriding stored settings for the given voice. They are applied only on the given request.\n```\n\n```python\n    def convert_with_timestamps(\n        self,\n        voice_id: str,\n        *,\n        text: str,\n        enable_logging: typing.Optional[bool] = None,\n        optimize_streaming_latency: typing.Optional[int] = None,\n        output_format: typing.Optional[TextToSpeechConvertWithTimestampsRequestOutputFormat] = None,\n        model_id: typing.Optional[str] = OMIT,\n        language_code: typing.Optional[str] = OMIT,\n        voice_settings: typing.Optional[VoiceSettings] = OMIT,\n        pronunciation_dictionary_locators: typing.Optional[\n            typing.Sequence[PronunciationDictionaryVersionLocator]\n        ] = OMIT,\n        seed: typing.Optional[int] = OMIT,\n        previous_text: typing.Optional[str] = OMIT,\n        next_text: typing.Optional[str] = OMIT,\n        previous_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        next_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        use_pvc_as_ivc: typing.Optional[bool] = OMIT,\n        apply_text_normalization: typing.Optional[\n            BodyTextToSpeechWithTimestampsV1TextToSpeechVoiceIdWithTimestampsPostApplyTextNormalization\n        ] = OMIT,\n        apply_language_text_normalization: typing.Optional[bool] = OMIT,\n        request_options: typing.Optional[RequestOptions] = None,\n    ) -> AudioWithTimestampsResponse:\n        \"\"\"\n        Generate speech from text with precise character-level timing information for audio-text synchronization.\n\n        Parameters\n```\n\n```python\n    def stream(\n        self,\n        voice_id: str,\n        *,\n        text: str,\n        enable_logging: typing.Optional[bool] = None,\n        optimize_streaming_latency: typing.Optional[int] = None,\n        output_format: typing.Optional[TextToSpeechStreamRequestOutputFormat] = None,\n        model_id: typing.Optional[str] = OMIT,\n        language_code: typing.Optional[str] = OMIT,\n        voice_settings: typing.Optional[VoiceSettings] = OMIT,\n        pronunciation_dictionary_locators: typing.Optional[\n            typing.Sequence[PronunciationDictionaryVersionLocator]\n        ] = OMIT,\n        seed: typing.Optional[int] = OMIT,\n        previous_text: typing.Optional[str] = OMIT,\n        next_text: typing.Optional[str] = OMIT,\n        previous_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        next_request_ids: typing.Optional[typing.Sequence[str]] = OMIT,\n        use_pvc_as_ivc: typing.Optional[bool] = OMIT,\n        apply_text_normalization: typing.Optional[\n            BodyTextToSpeechStreamingV1TextToSpeechVoiceIdStreamPostApplyTextNormalization\n        ] = OMIT,\n        apply_language_text_normalization: typing.Optional[bool] = OMIT,\n        request_options: typing.Optional[RequestOptions] = None,\n    ) -> typing.Iterator[bytes]:\n```\n\n```python\nTextToSpeechStreamRequestOutputFormat = typing.Union[\n    typing.Literal[\n        \"mp3_22050_32\",\n        \"mp3_44100_32\",\n        \"mp3_44100_64\",\n        \"mp3_44100_96\",\n        \"mp3_44100_128\",\n        \"mp3_44100_192\",\n        \"pcm_8000\",\n        \"pcm_16000\",\n        \"pcm_22050\",\n        \"pcm_24000\",\n        \"pcm_44100\",\n        \"pcm_48000\",\n        \"ulaw_8000\",\n        \"alaw_8000\",\n        \"opus_48000_32\",\n        \"opus_48000_64\",\n        \"opus_48000_96\",\n        \"opus_48000_128\",\n        \"opus_48000_192\",\n    ],\n    typing.Any,\n]\n```\n\n```python\ndef play(\n    audio: Union[bytes, Iterator[bytes]], \n    notebook: bool = False, \n    use_ffmpeg: bool = True\n) -> None:\n```\n\n```python\ndef save(audio: Union[bytes, Iterator[bytes]], filename: str) -> None:\n    if isinstance(audio, Iterator):\n        audio = b\"\".join(audio)\n    with open(filename, \"wb\") as f:\n        f.write(audio)\n```\n\n```python\ndef stream(audio_stream: Iterator[bytes]) -> bytes:\n    if not is_installed(\"mpv\"):\n        message = (\n            \"mpv not found, necessary to stream audio. \"\n            \"On mac you can install it with 'brew install mpv'. \"\n            \"On linux and windows you can install it from https://mpv.io/\"\n        )\n        raise ValueError(message)\n```\n\n src/elevenlabs/voices/ivc/client.py\n```python\n    def create(\n        self,\n        *,\n        name: str,\n        files: typing.List[core.File],\n        remove_background_noise: typing.Optional[bool] = OMIT,\n        description: typing.Optional[str] = OMIT,\n        labels: typing.Optional[str] = OMIT,\n        request_options: typing.Optional[RequestOptions] = None,\n    ) -> AddVoiceIvcResponseModel:\n```\n"
  },
  {
    "path": "content/email-validator/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python library for validating and normalizing email addresses, with optional DNS deliverability checks and internationalized email support\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,email,validation,dns,unicode\"\n---\n\n# email-validator for Python\n\n`email-validator` validates email address syntax, returns a normalized address you should store, and can optionally check whether the domain can receive mail. It is a local Python library, not a hosted service, so there is no API key, account setup, or client object.\n\n## Install\n\n```bash\npython -m pip install email-validator\n```\n\nRequirements:\n\n- Python 3.8+\n- Working DNS access if you keep `check_deliverability=True` (the default)\n\n## Imports And Setup\n\nFor normal application code, import the validator functions and call them directly.\n\n```python\nfrom email_validator import EmailNotValidError, validate_email\n```\n\nThere is no client initialization step and no package-specific environment variable for normal library use.\n\nIf you want process-wide defaults, the module exposes globals such as `email_validator.CHECK_DELIVERABILITY` and `email_validator.TEST_ENVIRONMENT`, but passing explicit keyword arguments per call is usually clearer.\n\n## Validate On Account Creation\n\nFor sign-up flows, keep deliverability checks enabled so obviously bad domains are rejected before you create the user.\n\n```python\nfrom email_validator import EmailNotValidError, validate_email\n\n\ndef normalize_signup_email(raw_email: str) -> str:\n    try:\n        info = validate_email(raw_email, check_deliverability=True)\n    except EmailNotValidError as exc:\n        raise ValueError(str(exc)) from exc\n\n    return info.normalized\n```\n\nStore `info.normalized`, not the original input. The library normalizes Unicode and quoted forms and lowercases the domain.\n\nWhen a deliverability check succeeds, the returned `ValidatedEmail` object may also include:\n\n- `info.mx`: MX records as `(priority, host)` tuples\n- `info.mx_fallback_type`: `\"A\"` or `\"AAAA\"` when the domain has no MX record and falls back to address records\n\n## Validate On Login Or Repeated Checks\n\nFor login forms or repeated re-validation, skip DNS lookups and use syntax plus normalization only.\n\n```python\nfrom email_validator import EmailNotValidError, validate_email\n\n\ndef normalize_login_email(raw_email: str) -> str:\n    try:\n        info = validate_email(raw_email, check_deliverability=False)\n    except EmailNotValidError as exc:\n        raise ValueError(\"Enter a valid email address.\") from exc\n\n    return info.normalized\n```\n\nThis avoids an external DNS lookup on every login attempt while still enforcing the library's syntax and normalization rules.\n\n## Reuse A DNS Resolver\n\nWhen validating many addresses, reuse a resolver so dnspython can cache answers and so you can control the timeout in one place.\n\n```python\nfrom email_validator import EmailNotValidError, caching_resolver, validate_email\n\nresolver = caching_resolver(timeout=10)\n\n\ndef validate_batch_email(raw_email: str) -> str:\n    try:\n        info = validate_email(\n            raw_email,\n            check_deliverability=True,\n            dns_resolver=resolver,\n        )\n    except EmailNotValidError as exc:\n        raise ValueError(str(exc)) from exc\n\n    return info.normalized\n```\n\nDo not pass both `dns_resolver=` and `timeout=` in the same `validate_email(...)` call. The library raises `ValueError` for that combination.\n\n## Internationalized Addresses\n\nThe library supports internationalized domain names and internationalized local parts.\n\n```python\nfrom email_validator import validate_email\n\ninfo = validate_email(\"example@ツ.ⓁⒾⒻⒺ\", check_deliverability=False)\n\nprint(info.normalized)   # example@ツ.life\nprint(info.ascii_email)  # example@xn--bdk.life\nprint(info.ascii_domain) # xn--bdk.life\nprint(info.smtputf8)     # False\n```\n\nImportant behavior:\n\n- `info.normalized` and `info.domain` use Unicode, not Punycode\n- `info.ascii_domain` gives the IDNA ASCII form for wire-format needs\n- If the local part contains non-ASCII characters, `info.ascii_email` is `None` and `info.smtputf8` is `True`\n\nIf your outbound mail path does not support SMTPUTF8, set `allow_smtputf8=False` so those addresses fail validation immediately.\n\n## Display Names And Special Formats\n\nDisplay names are rejected by default. Enable them only if you actually accept mailbox strings such as `My Name <me@example.org>`.\n\n```python\nfrom email_validator import validate_email\n\ninfo = validate_email(\n    \"My Name <me@example.org>\",\n    allow_display_name=True,\n    check_deliverability=False,\n)\n\nprint(info.display_name)  # My Name\nprint(info.normalized)    # me@example.org\n```\n\nOther useful opt-in flags:\n\n- `allow_quoted_local=True` for quoted local parts\n- `allow_domain_literal=True` for addresses like `user@[127.0.0.1]`\n- `allow_empty_local=True` for cases such as Postfix aliases\n- `strict=True` for additional syntax checks, including local-part length checks\n- `test_environment=True` to allow `test` domains and disable DNS deliverability checks\n\n## Error Types\n\nCatch `EmailNotValidError` for normal form handling. If you need different UI or logging for syntax versus DNS failures, catch the more specific subclasses.\n\n```python\nfrom email_validator import (\n    EmailNotValidError,\n    EmailSyntaxError,\n    EmailUndeliverableError,\n    validate_email,\n)\n\ntry:\n    validate_email(\"user@example.org\")\nexcept EmailSyntaxError:\n    print(\"The address format is invalid.\")\nexcept EmailUndeliverableError:\n    print(\"The domain cannot receive email.\")\nexcept EmailNotValidError:\n    print(\"The address is not valid.\")\n```\n\n## CLI And Environment Variables\n\nFor ad hoc checks, the package also exposes a small CLI.\n\n```bash\npython -m email_validator 'me@example.org'\nprintf '%s\\n' 'good@example.org' 'bad@localhost' | python -m email_validator\n```\n\nNormal library usage does not read environment variables. The CLI can read uppercase option names from the environment, plus `DEFAULT_TIMEOUT`.\n\n```bash\nexport DEFAULT_TIMEOUT=10\npython -m email_validator 'me@example.org'\n```\n\nPrefer the Python API in application code so options stay explicit in your source.\n\n## Common Pitfalls\n\n- Always store and compare `info.normalized`, not the raw user input.\n- Domains without a dot are rejected by default, as are special-use or reserved names such as `localhost`, `.local`, `.onion`, and `invalid`.\n- `test` domains are rejected unless you set `test_environment=True`.\n- `check_deliverability=True` performs DNS lookups. Use `False` on login and other hot paths.\n- A DNS timeout or `NoNameservers` result is treated as unknown deliverability, not a hard failure, so validation may still succeed without `info.mx`.\n- `ValidatedEmail.email` and dict-style access on the return object are deprecated. Use attributes like `info.normalized`, `info.ascii_email`, and `info.mx` instead.\n- Domain literals skip deliverability checks when you allow them, so do not treat `allow_domain_literal=True` as proof that an address can receive mail.\n"
  },
  {
    "path": "content/emotion/docs/react/javascript/DOC.md",
    "content": "---\nname: react\ndescription: \"Emotion React APIs for the css prop, theming, global styles, and cache configuration in JavaScript React apps.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"11.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"emotion,react,css-in-js,styling,theme,css-prop\"\n---\n\n# Emotion React Guide (JavaScript)\n\n## Golden Rule\n\nUse `@emotion/react` when you need Emotion's React-specific APIs: the `css` prop, `css` helper, `Global`, `ThemeProvider`, `ClassNames`, and `CacheProvider`.\n\n`@emotion/react` does not need API keys, environment variables, or client initialization. The important setup step is JSX compilation: if you want to use the `css` prop directly in JSX, configure your build so the JSX import source is `@emotion/react`.\n\n## Install\n\nInstall `@emotion/react` in the same app that renders your React components.\n\n```bash\nnpm install @emotion/react\n```\n\nAdd companion packages only when you need them:\n\n```bash\n# Optional: custom cache configuration\nnpm install @emotion/cache\n\n# Optional: Babel plugin for Emotion-specific transforms\nnpm install -D @emotion/babel-plugin\n```\n\nFor browser apps, you also need React and React DOM:\n\n```bash\nnpm install react react-dom @emotion/react\n```\n\n## Enable the `css` prop\n\nIn modern React builds, the cleanest setup is the automatic JSX runtime with `importSource: \"@emotion/react\"`.\n\n```javascript\n// babel.config.js\nmodule.exports = {\n  presets: [\n    [\"@babel/preset-react\", { runtime: \"automatic\", importSource: \"@emotion/react\" }],\n  ],\n  plugins: [\"@emotion/babel-plugin\"],\n};\n```\n\nIf you only want to opt in for a single file, add the file-level pragma instead:\n\n```jsx\n/** @jsxImportSource @emotion/react */\n```\n\nOnce that is in place, you can use the `css` prop on JSX elements and on custom components that forward `className`.\n\n## Common Workflows\n\n### Style JSX with the `css` prop\n\nUse the `css` prop for component-local styles. Object styles work well for JavaScript apps because they keep selectors and values in normal JS objects.\n\n```jsx\n/** @jsxImportSource @emotion/react */\nimport { css } from \"@emotion/react\";\n\nconst buttonStyles = css({\n  border: 0,\n  borderRadius: 9999,\n  padding: \"0.75rem 1rem\",\n  font: \"inherit\",\n  color: \"white\",\n  backgroundColor: \"#2563eb\",\n  cursor: \"pointer\",\n  \"&:hover\": {\n    backgroundColor: \"#1d4ed8\",\n  },\n});\n\nexport function SaveButton() {\n  return <button css={buttonStyles}>Save changes</button>;\n}\n```\n\nYou can also pass an object directly to `css={...}` when you do not need to reuse the styles elsewhere.\n\n### Share a theme with `ThemeProvider` and `useTheme`\n\nWrap the app with `ThemeProvider` when multiple components need the same colors, spacing, or typography tokens.\n\n```jsx\n/** @jsxImportSource @emotion/react */\nimport { ThemeProvider, useTheme } from \"@emotion/react\";\n\nconst theme = {\n  colors: {\n    background: \"#111827\",\n    surface: \"#1f2937\",\n    text: \"#f9fafb\",\n    accent: \"#22c55e\",\n  },\n};\n\nfunction StatusCard({ children }) {\n  const currentTheme = useTheme();\n\n  return (\n    <section\n      css={{\n        padding: \"1rem\",\n        borderRadius: \"0.75rem\",\n        color: currentTheme.colors.text,\n        backgroundColor: currentTheme.colors.surface,\n      }}\n    >\n      {children}\n    </section>\n  );\n}\n\nexport function App() {\n  return (\n    <ThemeProvider theme={theme}>\n      <main\n        css={{\n          minHeight: \"100vh\",\n          padding: \"2rem\",\n          backgroundColor: theme.colors.background,\n        }}\n      >\n        <StatusCard>Ready</StatusCard>\n      </main>\n    </ThemeProvider>\n  );\n}\n```\n\n### Add app-wide styles with `Global`\n\nUse `Global` for resets, base typography, and CSS variables that should apply to the whole document.\n\n```jsx\n/** @jsxImportSource @emotion/react */\nimport { Global, css } from \"@emotion/react\";\n\nexport function AppShell({ children }) {\n  return (\n    <>\n      <Global\n        styles={css`\n          * {\n            box-sizing: border-box;\n          }\n\n          html,\n          body,\n          #root {\n            min-height: 100%;\n          }\n\n          body {\n            margin: 0;\n            font-family: Inter, system-ui, sans-serif;\n            background: #0f172a;\n            color: #e2e8f0;\n          }\n        `}\n      />\n\n      <main>{children}</main>\n    </>\n  );\n}\n```\n\n### Style components that work through `className`\n\nEmotion can style custom components, but those components must pass the received `className` through to a DOM element or another Emotion-aware component.\n\n```jsx\n/** @jsxImportSource @emotion/react */\nimport { ClassNames } from \"@emotion/react\";\n\nfunction Panel({ className, children }) {\n  return <section className={className}>{children}</section>;\n}\n\nexport function Sidebar() {\n  return (\n    <ClassNames>\n      {({ css, cx }) => (\n        <Panel\n          className={cx(\n            \"analytics-sidebar\",\n            css({\n              padding: \"1rem\",\n              borderRadius: \"0.75rem\",\n              backgroundColor: \"#e0f2fe\",\n              border: \"1px solid #7dd3fc\",\n            }),\n          )}\n        >\n          Reports\n        </Panel>\n      )}\n    </ClassNames>\n  );\n}\n```\n\nUse `ClassNames` when a component or third-party library expects `className` rather than a `css` prop.\n\n### Control style insertion with `CacheProvider`\n\nUse a custom cache when you need to control how Emotion inserts style tags, such as embedding a React app into an existing page or isolating styles for a specific subtree.\n\n```jsx\nimport createCache from \"@emotion/cache\";\nimport { CacheProvider } from \"@emotion/react\";\n\nconst cache = createCache({\n  key: \"admin\",\n  prepend: true,\n});\n\nexport function AppProviders({ children }) {\n  return <CacheProvider value={cache}>{children}</CacheProvider>;\n}\n```\n\nCreate the cache once at module scope. Do not create a new cache inside a component render.\n\n## Important pitfalls\n\n- The `css` prop only works when your JSX transform is configured for `@emotion/react` with `@jsxImportSource` or an equivalent compiler setting.\n- Custom components must forward `className`; if they drop it, Emotion cannot attach the generated styles.\n- `@emotion/react` does not provide the `styled` API. Install `@emotion/styled` when you want `styled.div`, `styled.button`, or similar component factories.\n- Use `CacheProvider` only when you need custom insertion behavior. A new cache per render causes unnecessary style churn.\n- Prefer one setup path for the `css` prop across the app. Mixing incompatible JSX configurations is a common source of missing styles.\n\n## Version notes\n\n- This guide targets `@emotion/react@11.14.0`.\n- `@emotion/react` is the package for the React runtime APIs. Cache creation lives in `@emotion/cache`, and the styled-component API lives in `@emotion/styled`.\n"
  },
  {
    "path": "content/esbuild/docs/esbuild/javascript/DOC.md",
    "content": "---\nname: esbuild\ndescription: \"JavaScript bundler and minifier with practical setup for CLI builds, the JavaScript API, watch mode, code splitting, asset loaders, plugins, and bundle analysis.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.27.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"esbuild,build,bundler,minifier,typescript,javascript\"\n---\n\n# esbuild\n\n`esbuild` is a JavaScript and CSS bundler/minifier for build-time use. Use the CLI for simple project scripts or the JavaScript API when a tool needs to run builds programmatically.\n\nThis package has no auth flow, no package-specific environment variables, and no runtime client to initialize for normal Node.js usage.\n\n## Install\n\n`esbuild@0.27.3` requires Node.js 18 or newer.\n\nInstall it as a development dependency:\n\n```bash\nnpm install --save-dev esbuild\n```\n\nTypical `package.json` scripts:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"esbuild src/index.ts --bundle --outdir=dist\",\n    \"dev\": \"esbuild src/index.ts --bundle --outdir=dist --watch\"\n  }\n}\n```\n\n## Imports\n\nES modules:\n\n```javascript\nimport * as esbuild from \"esbuild\";\n```\n\nCommonJS:\n\n```javascript\nconst esbuild = require(\"esbuild\");\n```\n\n## Environment variables\n\n`esbuild` does not require any package-specific environment variables.\n\nIf your app uses environment-based configuration, load it yourself and inject constants with `define` during the build:\n\n```bash\nnpm install --save-dev dotenv\n```\n\n```javascript\nimport * as esbuild from \"esbuild\";\nimport dotenv from \"dotenv\";\n\ndotenv.config();\n\nawait esbuild.build({\n  entryPoints: [\"src/index.ts\"],\n  bundle: true,\n  outfile: \"dist/app.js\",\n  define: {\n    \"process.env.NODE_ENV\": JSON.stringify(process.env.NODE_ENV ?? \"development\"),\n    \"__API_BASE_URL__\": JSON.stringify(process.env.API_BASE_URL ?? \"http://localhost:3000\"),\n  },\n});\n```\n\n`define` substitutes source code while parsing, so use `JSON.stringify(...)` when you want to inject string literals.\n\n## CLI builds\n\n### Bundle a browser app\n\n```bash\nnpx esbuild src/main.ts \\\n  --bundle \\\n  --platform=browser \\\n  --format=esm \\\n  --target=es2020 \\\n  --sourcemap \\\n  --outdir=dist\n```\n\n### Bundle a Node.js entry point\n\nUse `--packages=external` when package dependencies should stay as runtime imports instead of being bundled into the output.\n\n```bash\nnpx esbuild src/cli.ts \\\n  --bundle \\\n  --platform=node \\\n  --target=node18 \\\n  --format=esm \\\n  --packages=external \\\n  --outfile=dist/cli.mjs\n```\n\n### Watch and serve during development\n\n```bash\nnpx esbuild src/main.ts \\\n  --bundle \\\n  --outdir=www/assets \\\n  --servedir=www \\\n  --sourcemap \\\n  --watch\n```\n\nBy default, CLI watch mode stops when stdin closes. Use `--watch=forever` if you need watch mode to ignore stdin.\n\n## JavaScript API: basic build\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nawait esbuild.build({\n  entryPoints: [\"src/index.ts\"],\n  bundle: true,\n  outdir: \"dist\",\n  platform: \"browser\",\n  format: \"esm\",\n  target: [\"es2020\"],\n  sourcemap: true,\n  logLevel: \"info\",\n});\n```\n\nImportant build options used most often:\n\n- `entryPoints`: one or more entry files\n- `bundle`: include dependencies in the output\n- `outfile`: one output file\n- `outdir`: output directory for multiple files\n- `platform`: `browser`, `node`, or `neutral`\n- `format`: `iife`, `cjs`, or `esm`\n- `target`: JavaScript environment target such as `es2020` or `node18`\n- `sourcemap`: `true`, `inline`, `external`, `linked`, or `both`\n\nWhen bundling, the CLI defaults to `iife` for `browser` and `cjs` for `node`. If you need a specific module format, set `format` explicitly.\n\n## Keep output in memory\n\nSet `write: false` when another tool needs the generated files instead of writing them to disk.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nconst result = await esbuild.build({\n  entryPoints: [\"src/index.ts\"],\n  bundle: true,\n  format: \"esm\",\n  platform: \"browser\",\n  write: false,\n});\n\nfor (const file of result.outputFiles) {\n  console.log(file.path);\n  console.log(file.text);\n}\n```\n\n`outputFiles` is only populated when `write: false`.\n\n## Load CSS and static assets\n\nUse `loader` to tell esbuild how to handle non-JavaScript file types.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nawait esbuild.build({\n  entryPoints: [\"src/main.tsx\"],\n  bundle: true,\n  outdir: \"dist\",\n  loader: {\n    \".css\": \"css\",\n    \".png\": \"file\",\n    \".svg\": \"file\",\n    \".txt\": \"text\",\n  },\n  assetNames: \"assets/[name]-[hash]\",\n  publicPath: \"/static\",\n});\n```\n\nCommon loader values include `js`, `jsx`, `ts`, `tsx`, `json`, `css`, `text`, `file`, `dataurl`, and `binary`.\n\n## Code splitting\n\nUse multiple entry points with `splitting: true` to share chunks between outputs.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nawait esbuild.build({\n  entryPoints: [\"src/home.ts\", \"src/admin.ts\"],\n  bundle: true,\n  splitting: true,\n  format: \"esm\",\n  outdir: \"dist\",\n});\n```\n\nCode splitting currently only works with `format: \"esm\"`.\n\n## Watch mode and local dev server\n\nFor long-running builds, create a context and then call `watch()` or `serve()` on that context.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nconst ctx = await esbuild.context({\n  entryPoints: [\"src/main.ts\"],\n  bundle: true,\n  outdir: \"www/assets\",\n  sourcemap: true,\n});\n\nawait ctx.watch();\n\nconst server = await ctx.serve({\n  servedir: \"www\",\n  host: \"127.0.0.1\",\n  port: 3000,\n});\n\nconsole.log(`http://${server.hosts[0]}:${server.port}`);\n```\n\nShut the context down when your process exits:\n\n```javascript\nprocess.on(\"SIGINT\", async () => {\n  await ctx.dispose();\n  process.exit(0);\n});\n```\n\nUse `ctx.rebuild()` when you want an explicit rebuild, `ctx.cancel()` to stop an in-flight build, and `ctx.dispose()` for cleanup.\n\n## Transform source without bundling\n\nUse `transform()` when you have source code in memory and only need transpilation or minification.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nconst source = `\n  export const answer: number = 42;\n  console.log(answer);\n`;\n\nconst result = await esbuild.transform(source, {\n  loader: \"ts\",\n  target: \"es2020\",\n  minify: true,\n  sourcemap: \"inline\",\n  sourcefile: \"inline.ts\",\n});\n\nconsole.log(result.code);\n```\n\nUse `transform()` for one-file transforms. Use `build()` when you need module resolution, bundling, loaders, plugins, or output path control.\n\n## Plugins\n\nPlugins are passed with `plugins` on `build()` or `context()` and register hooks in `setup(build)`.\n\nThis example provides a virtual module named `env`:\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nconst envPlugin = {\n  name: \"env-plugin\",\n  setup(build) {\n    build.onResolve({ filter: /^env$/ }, () => ({\n      path: \"env\",\n      namespace: \"env-ns\",\n    }));\n\n    build.onLoad({ filter: /.*/, namespace: \"env-ns\" }, () => ({\n      contents: `export const NODE_ENV = ${JSON.stringify(process.env.NODE_ENV ?? \"development\")};`,\n      loader: \"js\",\n    }));\n  },\n};\n\nawait esbuild.build({\n  entryPoints: [\"src/index.ts\"],\n  bundle: true,\n  outfile: \"dist/app.js\",\n  plugins: [envPlugin],\n});\n```\n\nThe plugin API exposes these hook families:\n\n- `onStart()` and `onEnd()` for build lifecycle work\n- `onResolve()` for import path resolution\n- `onLoad()` for providing file contents\n- `onDispose()` for cleanup\n\n## Analyze bundle contents\n\nUse `metafile: true` to get structured output, then pass it to `analyzeMetafile()` for a readable report.\n\n```javascript\nimport * as esbuild from \"esbuild\";\n\nconst result = await esbuild.build({\n  entryPoints: [\"src/index.ts\"],\n  bundle: true,\n  outfile: \"dist/app.js\",\n  metafile: true,\n});\n\nconst report = await esbuild.analyzeMetafile(result.metafile, {\n  verbose: true,\n});\n\nconsole.log(report);\n```\n\nCLI equivalent:\n\n```bash\nnpx esbuild src/index.ts --bundle --outfile=dist/app.js --metafile=meta.json --analyze\n```\n\n## Common pitfalls\n\n- `outfile` is for one output file; use `outdir` when you have multiple entry points or multiple generated files.\n- `splitting` requires `format: \"esm\"`.\n- `outputFiles` is only returned when `write: false`.\n- `watch()` and `serve()` are methods on a build context created with `esbuild.context(...)`, not on `build()`.\n- `packages: \"external\"` keeps package imports out of the bundle. Use it for many Node.js CLIs and libraries where dependencies should still be installed at runtime.\n- `define` values are parsed as code fragments. Wrap string values with `JSON.stringify(...)` so the emitted code contains quoted JavaScript strings.\n- `esbuild` does not read `.env` files on its own.\n\n## Official references\n\n- API documentation: `https://esbuild.github.io/api/`\n- Plugin documentation: `https://esbuild.github.io/plugins/`\n- Metafile analysis: `https://esbuild.github.io/analyze/`\n"
  },
  {
    "path": "content/eslint/docs/eslint/javascript/DOC.md",
    "content": "---\nname: eslint\ndescription: \"ESLint for JavaScript projects, including flat config setup, CLI usage, autofix, ignore patterns, and the Node.js API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.0.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,javascript,linting,node,cli,npm\"\n---\n\n# ESLint JavaScript Guide\n\n## Install\n\nESLint is a local development dependency. It does not use API keys, accounts, or runtime environment variables.\n\nUse a supported Node.js release from the current ESLint prerequisites page, then install the package:\n\n```bash\nnpm install --save-dev eslint\nnpx eslint --version\n```\n\n## Initialization and Config\n\nThe main setup step is creating a flat config file. If your project is not already using ESM, use `eslint.config.mjs`. If your package already sets `\"type\": \"module\"`, `eslint.config.js` works too.\n\n```js\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  {\n    ignores: [\"dist/**\", \"coverage/**\"],\n  },\n  {\n    files: [\"**/*.js\", \"**/*.mjs\", \"**/*.cjs\"],\n    rules: {\n      eqeqeq: \"error\",\n      \"no-console\": \"warn\",\n      \"no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n      semi: [\"error\", \"always\"],\n    },\n  },\n]);\n```\n\nESLint reads `eslint.config.*` automatically when you run the CLI from the project root.\n\n## CLI Workflows\n\n```bash\n# Lint the whole project\nnpx eslint .\n\n# Lint specific files or folders\nnpx eslint \"src/**/*.js\"\n\n# Apply autofixes in place\nnpx eslint . --fix\n\n# Use an explicit config path\nnpx eslint . --config eslint.config.mjs\n```\n\nESLint exits with a non-zero status when it finds errors, so the same command works in local scripts and CI.\n\n### `package.json` scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n## Node.js API\n\nUse the `ESLint` class from the `eslint` package when you need linting inside build tools, editor integrations, or custom scripts.\n\n```js\nimport { ESLint } from \"eslint\";\n\nconst eslint = new ESLint({ fix: true });\n\nconst results = await eslint.lintFiles([\"src/**/*.js\"]);\nawait ESLint.outputFixes(results);\n\nconst formatter = await eslint.loadFormatter(\"stylish\");\nconst output = await formatter.format(results);\n\nif (output) {\n  console.log(output);\n}\n```\n\n### Lint text from a string\n\n```js\nimport { ESLint } from \"eslint\";\n\nconst eslint = new ESLint();\n\nconst results = await eslint.lintText(\"console.log(answer == 42)\\n\", {\n  filePath: \"src/example.js\",\n});\n\nconst formatter = await eslint.loadFormatter(\"stylish\");\nconsole.log(await formatter.format(results));\n```\n\nPass `filePath` when you call `lintText()` if your config uses `files` globs. That lets ESLint match the snippet against the same config rules as a real file.\n\n## Important Pitfalls\n\n- No auth or environment variables are required; setup is local to your project.\n- Keep the main config in `eslint.config.*` and run the CLI from the project root, or pass `--config` explicitly.\n- Keep ignore patterns in the flat config so the CLI and the Node.js API use the same exclusions.\n- If you use ESM `import`/`export` syntax in the config, use `eslint.config.mjs` unless your package already enables ESM.\n- The `eslint` package only covers core JavaScript linting. JSX, TypeScript, and framework-specific linting require additional parser and plugin packages.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint@10.0.3`.\n- Current maintainer docs describe the flat config system and the `defineConfig()` helper from `eslint/config` for JavaScript projects.\n- The `ESLint` class is the main programmatic entry point for linting files and strings from Node.js.\n\n## Official Sources\n\n- https://eslint.org/docs/latest/\n- https://eslint.org/docs/latest/use/getting-started\n- https://eslint.org/docs/latest/use/getting-started#prerequisites\n- https://eslint.org/docs/latest/use/configure\n- https://eslint.org/docs/latest/use/command-line-interface\n- https://eslint.org/docs/latest/integrate/nodejs-api\n- https://www.npmjs.com/package/eslint\n- https://github.com/eslint/eslint\n"
  },
  {
    "path": "content/eslint/docs/eslint-config-airbnb/javascript/DOC.md",
    "content": "---\nname: eslint-config-airbnb\ndescription: \"JavaScript guide for eslint-config-airbnb 19.0.4, covering installation, legacy ESLint configuration, React Hooks setup, and common usage pitfalls.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,airbnb,react,javascript,linting,npm\"\n---\n\n# eslint-config-airbnb JavaScript Guide\n\n## Install\n\n`eslint-config-airbnb` is a shareable ESLint config for JavaScript and React projects. It does not use API keys, environment variables, accounts, or runtime client initialization.\n\nThe maintainer setup installs the config together with its peer dependencies.\n\n### Install from the maintainer workflow\n\n```bash\nnpx install-peerdeps --dev eslint-config-airbnb\n```\n\n### Install explicitly\n\n```bash\nnpm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks\n```\n\nIf you want to inspect the current peer dependency ranges for this exact version before installing, query npm metadata directly:\n\n```bash\nnpm info \"eslint-config-airbnb@19.0.4\" peerDependencies\n```\n\n## Configure ESLint\n\nThe maintainer documentation for `eslint-config-airbnb@19.0.4` uses legacy ESLint config files such as `.eslintrc.json` or `.eslintrc.cjs`.\n\nIn `extends`, use the shareable config name `airbnb`, not `eslint-config-airbnb`.\n\n### Minimal React project\n\nCreate `.eslintrc.json`:\n\n```json\n{\n  \"extends\": [\"airbnb\"]\n}\n```\n\n### React project with Hooks rules\n\nAdd the separate Hooks preset after `airbnb` when your app uses React Hooks:\n\n```json\n{\n  \"extends\": [\"airbnb\", \"airbnb/hooks\"]\n}\n```\n\n### Typical `.eslintrc.cjs`\n\n```js\nmodule.exports = {\n  extends: ['airbnb', 'airbnb/hooks'],\n  env: {\n    browser: true,\n    es2021: true,\n  },\n  parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module',\n  },\n};\n```\n\nUse `.eslintrc.json` if you only need static JSON. Use `.eslintrc.cjs` when you want comments, conditionals, or shared config fragments.\n\n## Common Workflows\n\n### Add lint scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n### Lint the whole project\n\n```bash\nnpm run lint\n```\n\n### Apply autofixes\n\n```bash\nnpm run lint:fix\n```\n\n### Lint only source files\n\n```bash\nnpx eslint \"src/**/*.{js,jsx}\"\n```\n\n## What This Config Includes\n\nUsing `extends: [\"airbnb\"]` enables Airbnb's shared JavaScript and React lint rules on top of ESLint.\n\nIn practice, this setup depends on these plugin families:\n\n- import rules from `eslint-plugin-import`\n- React rules from `eslint-plugin-react`\n- JSX accessibility rules from `eslint-plugin-jsx-a11y`\n- React Hooks rules from `eslint-plugin-react-hooks` when you also extend `airbnb/hooks`\n\nThis package is configuration only. Do not import it from your application code.\n\n## Important Pitfalls\n\n- Install the peer packages with the config. If the plugins are missing, ESLint cannot resolve the shared config correctly.\n- In `extends`, use `\"airbnb\"` and optionally `\"airbnb/hooks\"`, not `\"eslint-config-airbnb\"`.\n- `airbnb/hooks` is a separate preset. Adding only `\"airbnb\"` does not enable the Hooks ruleset.\n- This package is aimed at React projects. If you want Airbnb's base JavaScript rules without React or JSX accessibility rules, use `eslint-config-airbnb-base` instead.\n- This package does not set up TypeScript parsing. If your project lints `.ts` or `.tsx` files, add the TypeScript parser and TypeScript-specific config separately.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-config-airbnb@19.0.4`.\n- The documented maintainer setup for this version is based on legacy `.eslintrc*` configuration.\n- The package is a shareable config, not a standalone linter. Keep `eslint` installed alongside it.\n- The React Hooks rules are exposed through the additional `airbnb/hooks` entry point.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/airbnb/javascript\n- Package docs directory: https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb\n- npm package page: https://www.npmjs.com/package/eslint-config-airbnb\n"
  },
  {
    "path": "content/eslint/docs/eslint-config-next/javascript/DOC.md",
    "content": "---\nname: eslint-config-next\ndescription: \"Flat-config setup for linting Next.js projects with ESLint 9, including the base config, Core Web Vitals rules, TypeScript rules, and ignore overrides.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"16.1.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"nextjs,eslint,javascript,react,linting,flat-config\"\n---\n\n# eslint-config-next JavaScript Guide\n\n## Golden Rule\n\nUse `eslint-config-next` as a flat ESLint config for a Next.js app, and spread its exported config arrays into `defineConfig()`.\n\nFor most apps, start with `eslint-config-next/core-web-vitals`. If the project also uses TypeScript and you want TypeScript-specific recommended rules, add `eslint-config-next/typescript` after it.\n\nThis package is local project configuration only. It does not use API keys, accounts, service credentials, or runtime environment variables.\n\n## Install\n\nInstall it in an existing Next.js project with ESLint 9:\n\n```bash\nnpm install -D eslint eslint-config-next\n```\n\nIf you want the TypeScript rules export, keep a local `typescript` dependency too:\n\n```bash\nnpm install -D typescript\n```\n\n`eslint-config-next@16.1.6` declares these peer dependencies:\n\n- `eslint >=9.0.0`\n- `typescript >=3.3.1` as an optional peer dependency\n\nKeep `next` installed in the same app. The published parser export resolves `next/dist/compiled/babel/eslint-parser`, so this config is meant for Next.js projects, not generic React apps.\n\n## Flat Config Setup\n\nCurrent Next.js templates use `eslint.config.mjs` with ESLint flat config.\n\n### Base Next.js config\n\nUse the root export if you want the base Next.js recommended rules without the extra Core Web Vitals layer:\n\n```js\nimport { defineConfig } from \"eslint/config\";\nimport next from \"eslint-config-next\";\n\nexport default defineConfig([\n  ...next,\n]);\n```\n\n### Recommended Next.js config\n\nThis matches the current `create-next-app` JavaScript templates:\n\n```js\nimport { defineConfig, globalIgnores } from \"eslint/config\";\nimport nextVitals from \"eslint-config-next/core-web-vitals\";\n\nconst eslintConfig = defineConfig([\n  ...nextVitals,\n  globalIgnores([\n    \".next/**\",\n    \"out/**\",\n    \"build/**\",\n    \"next-env.d.ts\",\n  ]),\n]);\n\nexport default eslintConfig;\n```\n\n`eslint-config-next/core-web-vitals` is the base config plus the Next plugin's `core-web-vitals` rules.\n\n### TypeScript projects\n\nThis matches the current `create-next-app` TypeScript templates:\n\n```js\nimport { defineConfig, globalIgnores } from \"eslint/config\";\nimport nextVitals from \"eslint-config-next/core-web-vitals\";\nimport nextTs from \"eslint-config-next/typescript\";\n\nconst eslintConfig = defineConfig([\n  ...nextVitals,\n  ...nextTs,\n  globalIgnores([\n    \".next/**\",\n    \"out/**\",\n    \"build/**\",\n    \"next-env.d.ts\",\n  ]),\n]);\n\nexport default eslintConfig;\n```\n\nThe `typescript` export layers in `typescript-eslint` recommended rules and TypeScript parsing.\n\n## Common Workflows\n\n### Add project-specific rules\n\nAppend your own config object after the shared config arrays:\n\n```js\nimport { defineConfig, globalIgnores } from \"eslint/config\";\nimport nextVitals from \"eslint-config-next/core-web-vitals\";\n\nexport default defineConfig([\n  ...nextVitals,\n  {\n    rules: {\n      \"@next/next/no-img-element\": \"off\",\n      \"import/no-anonymous-default-export\": \"off\",\n    },\n  },\n  globalIgnores([\n    \".next/**\",\n    \"out/**\",\n    \"build/**\",\n    \"next-env.d.ts\",\n    \"coverage/**\",\n  ]),\n]);\n```\n\n### Run lint from the CLI\n\nThe current Next.js templates use the ESLint CLI directly:\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint\"\n  }\n}\n```\n\nTypical commands:\n\n```bash\n# Lint the project\nnpx eslint .\n\n# Apply autofixes\nnpx eslint . --fix\n\n# Lint specific files\nnpx eslint \"app/**/*.{js,jsx,ts,tsx}\" \"pages/**/*.{js,jsx,ts,tsx}\"\n```\n\n## What the Config Includes\n\nThe published base config already wires in the main Next.js linting pieces for you:\n\n- `@next/eslint-plugin-next`\n- `eslint-plugin-react`\n- `eslint-plugin-react-hooks`\n- `eslint-plugin-import`\n- `eslint-plugin-jsx-a11y`\n- `eslint-import-resolver-node` and `eslint-import-resolver-typescript`\n\nThe base export also applies default global ignores for:\n\n- `.next/**`\n- `out/**`\n- `build/**`\n- `next-env.d.ts`\n\n## Important Pitfalls\n\n- Use flat config and import the package into `eslint.config.*`; the published exports are config arrays meant to be spread into `defineConfig()`.\n- Keep `next` installed locally. The parser export comes from the `next` package.\n- If you override ignores with `globalIgnores()`, include the defaults you still want to keep.\n- Do not manually add React, React Hooks, import, JSX a11y, or Next plugins just to reproduce the default setup; `eslint-config-next` already includes them.\n- Only add `eslint-config-next/typescript` when the project actually uses TypeScript and has `typescript` installed.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-config-next@16.1.6`.\n- The published package declares `eslint >=9.0.0` and exports flat-config entry points at `eslint-config-next`, `eslint-config-next/core-web-vitals`, and `eslint-config-next/typescript`.\n- Current `create-next-app` templates for Next 16 use `eslint.config.mjs`, import `eslint/config`, and run linting with the ESLint CLI.\n\n## Official Sources\n\n- https://nextjs.org/docs/app/api-reference/config/eslint\n- https://www.npmjs.com/package/eslint-config-next\n- https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz\n- https://registry.npmjs.org/next/-/next-16.1.6.tgz\n- https://registry.npmjs.org/create-next-app/-/create-next-app-16.1.1.tgz\n"
  },
  {
    "path": "content/eslint/docs/eslint-config-prettier/javascript/DOC.md",
    "content": "---\nname: eslint-config-prettier\ndescription: \"JavaScript guide for eslint-config-prettier 10.1.8, covering flat config, legacy config, conflict checks, and the rules it disables for Prettier-compatible linting.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.1.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,eslint,prettier,linting,formatting,flat-config\"\n---\n\n# eslint-config-prettier JavaScript Guide\n\n## Golden Rule\n\nUse `eslint-config-prettier` to turn off ESLint rules that conflict with Prettier, and place it last so it can override earlier configs.\n\nThis package does **not** run Prettier and it does **not** format files. Its job is only to disable conflicting lint rules.\n\n## Install\n\nInstall the package alongside ESLint and Prettier as development dependencies:\n\n```bash\nnpm install -D eslint prettier eslint-config-prettier\n```\n\nNo authentication, API keys, service accounts, or runtime client initialization are required.\n\n### Package-specific environment variable\n\nNormal use does not require any environment variables.\n\nIf you use the package's CLI helper and need to force ESLint's config mode, set `ESLINT_USE_FLAT_CONFIG` before the command:\n\n```bash\nESLINT_USE_FLAT_CONFIG=true npx eslint-config-prettier src/index.js\n```\n\nUse `true` when you want the helper to inspect flat config, or `false` when you want it to inspect legacy `.eslintrc` config.\n\n## Flat Config (ESLint 9+)\n\nFor new projects, use ESLint flat config and import the package directly.\n\nCreate `eslint.config.mjs`:\n\n```javascript\nimport { defineConfig } from \"eslint/config\";\nimport eslintConfigPrettier from \"eslint-config-prettier/flat\";\n\nexport default defineConfig([\n  {\n    files: [\"**/*.js\"],\n    rules: {\n      \"no-unused-vars\": \"error\",\n      eqeqeq: \"error\",\n    },\n  },\n  eslintConfigPrettier,\n]);\n```\n\nKeep `eslintConfigPrettier` at the end of the config array. If another shared config or later config object turns formatting rules back on, Prettier conflicts can return.\n\n## Legacy `.eslintrc` Config\n\nIf your project still uses legacy config files, add `\"prettier\"` to the end of `extends`.\n\nCreate `.eslintrc.json`:\n\n```json\n{\n  \"extends\": [\"eslint:recommended\", \"prettier\"],\n  \"rules\": {\n    \"no-unused-vars\": \"error\",\n    \"eqeqeq\": \"error\"\n  }\n}\n```\n\nIn legacy config, the correct shareable-config name is `\"prettier\"`, not `\"eslint-config-prettier\"`.\n\n## Recommended Project Scripts\n\nRun ESLint and Prettier as separate tools:\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\",\n    \"format\": \"prettier . --write\",\n    \"format:check\": \"prettier . --check\"\n  }\n}\n```\n\nThis is the simplest setup:\n\n- ESLint reports code-quality issues\n- Prettier owns formatting\n- `eslint-config-prettier` removes overlapping formatting rules from ESLint\n\n## Check For Conflicting Rules\n\nThe package includes a CLI helper that inspects your resolved ESLint config and reports rules that still conflict with Prettier.\n\nRun it against a real file path from your project so ESLint loads the same overrides and config matches you use during linting:\n\n```bash\nnpx eslint-config-prettier src/index.js\n```\n\nIf your project is on flat config, force that mode explicitly when needed:\n\n```bash\nESLINT_USE_FLAT_CONFIG=true npx eslint-config-prettier src/index.js\n```\n\nIf your project still uses legacy config, force legacy mode explicitly when needed:\n\n```bash\nESLINT_USE_FLAT_CONFIG=false npx eslint-config-prettier src/index.js\n```\n\nUse this helper after adding new shared configs, plugins, or hand-written rules that might reintroduce stylistic conflicts.\n\n## Common Workflow\n\n### 1. Add your normal ESLint rules\n\nKeep code-quality rules such as `no-unused-vars`, `eqeqeq`, or `no-undef`.\n\n### 2. Put `eslint-config-prettier` last\n\nIn flat config, place `eslintConfigPrettier` at the end of the exported array. In legacy config, place `\"prettier\"` at the end of `extends`.\n\n### 3. Let Prettier handle formatting\n\nRun Prettier separately:\n\n```bash\nnpm run format\n```\n\n### 4. Keep ESLint focused on correctness\n\nRun ESLint separately:\n\n```bash\nnpm run lint\n```\n\n## Important Pitfalls\n\n- `eslint-config-prettier` disables conflicting rules; it does not replace the Prettier CLI, editor integration, or the `prettier` package.\n- Put the config last. If another config comes after it, that later config can re-enable formatting rules.\n- Do not re-enable conflicting stylistic rules in your own config after applying `eslint-config-prettier`.\n- In flat config, import the package. In legacy config, use `\"prettier\"` in `extends`.\n- When using the CLI helper, pass a representative file path from the project instead of an arbitrary placeholder path.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-config-prettier==10.1.8`.\n- For new ESLint setups, prefer flat config and import `eslint-config-prettier/flat`.\n- If you upgrade ESLint, shared configs, or `eslint-config-prettier`, rerun the CLI helper to check whether your resolved config still has Prettier conflicts.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/prettier/eslint-config-prettier\n- npm package page: https://www.npmjs.com/package/eslint-config-prettier\n"
  },
  {
    "path": "content/eslint/docs/eslint-config-standard/javascript/DOC.md",
    "content": "---\nname: eslint-config-standard\ndescription: \"StandardJS shareable ESLint config for JavaScript projects, including installation, legacy `.eslintrc` setup, rule overrides, and common lint workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"17.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,standard,javascript,linting,npm\"\n---\n\n# eslint-config-standard JavaScript Guide\n\n## Install\n\n`eslint-config-standard` is a shareable ESLint config. It does not use API keys, accounts, authentication, runtime imports, or environment variables.\n\nInstall ESLint, the config, and the peer plugins together:\n\n```bash\nnpm install --save-dev eslint eslint-config-standard eslint-plugin-import eslint-plugin-n eslint-plugin-promise\nnpx eslint --version\n```\n\nThis config layers rules from `eslint-plugin-import`, `eslint-plugin-n`, and `eslint-plugin-promise`.\n\n## Configure ESLint\n\nThe maintainer setup for `eslint-config-standard@17.1.0` is the legacy ESLint config system. Extend `standard` from `.eslintrc.json`, `.eslintrc.cjs`, or another `.eslintrc*` file.\n\n### Minimal `.eslintrc.json`\n\n```json\n{\n  \"extends\": [\"standard\"]\n}\n```\n\n### Typical Node.js project setup\n\n```json\n{\n  \"extends\": [\"standard\"],\n  \"env\": {\n    \"es2021\": true,\n    \"node\": true\n  }\n}\n```\n\n### Override a few rules\n\nUse normal ESLint overrides on top of the shared config when your project needs exceptions.\n\n```js\nmodule.exports = {\n  extends: [\"standard\"],\n  env: {\n    es2021: true,\n    node: true,\n  },\n  rules: {\n    \"no-console\": \"off\",\n    \"n/no-process-exit\": \"off\",\n  },\n}\n```\n\n## Common Workflows\n\n### Add project scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n### Lint the whole project\n\n```bash\nnpm run lint\n```\n\n### Apply autofixes\n\n```bash\nnpm run lint:fix\n```\n\n### Lint a specific folder\n\n```bash\nnpx eslint \"src/**/*.js\"\n```\n\n## What This Config Covers\n\nUsing `extends: [\"standard\"]` enables StandardJS-oriented defaults across:\n\n- ESLint core rules\n- `import/*` rules from `eslint-plugin-import`\n- `n/*` rules from `eslint-plugin-n`\n- `promise/*` rules from `eslint-plugin-promise`\n\nWhen you need more control, keep `standard` as the base and then override only the individual rules your project wants to change.\n\n## Important Pitfalls\n\n- Install the peer packages with the config. If `eslint-plugin-import`, `eslint-plugin-n`, or `eslint-plugin-promise` is missing, ESLint cannot fully resolve the shared config.\n- In `extends`, use `\"standard\"`, not `\"eslint-config-standard\"`.\n- This package configures ESLint only. Do not import it from application code.\n- Rule IDs you override may come from ESLint core or from the bundled plugins, so use the full rule name when needed, such as `n/no-process-exit` or `promise/always-return`.\n- The maintainer usage for `17.1.0` is centered on legacy `.eslintrc*` config files.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-config-standard@17.1.0`.\n- The package is a shareable config, not a standalone linter. Keep `eslint` installed alongside it.\n- The package's documented setup uses `extends: [\"standard\"]` in `.eslintrc*` files and expects the peer plugins above to be available.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/standard/eslint-config-standard\n- GitHub README: https://github.com/standard/eslint-config-standard#readme\n- npm package page: https://www.npmjs.com/package/eslint-config-standard\n"
  },
  {
    "path": "content/eslint/docs/eslint-import-resolver-typescript/javascript/DOC.md",
    "content": "---\nname: eslint-import-resolver-typescript\ndescription: \"JavaScript guide for eslint-import-resolver-typescript 4.4.4, covering flat config, legacy config, tsconfig selection, Bun support, and resolver behavior for TypeScript imports.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.4.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,typescript,eslint,linting,imports,resolver\"\n---\n\n# eslint-import-resolver-typescript JavaScript Guide\n\n## Golden Rule\n\nUse `eslint-import-resolver-typescript` with either `eslint-plugin-import` or `eslint-plugin-import-x`. This package is a resolver, not an ESLint plugin by itself.\n\nUse it when you want import resolution rules to understand TypeScript files, `tsconfig.json` or `jsconfig.json` path mapping, package `imports` and `exports` fields, and `@types/*` packages.\n\n## Install\n\n`eslint-import-resolver-typescript@4.4.4` declares Node.js support for `^16.17.0 || >=18.6.0`.\n\nInstall it with the import plugin you actually use:\n\n```bash\n# eslint-plugin-import\nnpm install -D eslint eslint-plugin-import eslint-import-resolver-typescript\n\n# or eslint-plugin-import-x\nnpm install -D eslint eslint-plugin-import-x eslint-import-resolver-typescript\n```\n\nIf you still use legacy `.eslintrc*` config for TypeScript files, also install the parser used in the upstream example:\n\n```bash\nnpm install -D @typescript-eslint/parser\n```\n\nThis package does not use API keys, service accounts, runtime environment variables, or client initialization.\n\n## Flat Config With `eslint-plugin-import-x`\n\nIf you are on `eslint-plugin-import-x@>=4.5.0`, you can import the resolver directly in `eslint.config.js`.\n\n```js\nimport { createTypeScriptImportResolver } from \"eslint-import-resolver-typescript\";\n\nexport default [\n  {\n    settings: {\n      \"import-x/resolver-next\": [\n        createTypeScriptImportResolver({\n          alwaysTryTypes: true,\n          project: \"packages/*/{ts,js}config.json\",\n        }),\n      ],\n    },\n  },\n];\n```\n\nUse `bun: true` in the resolver options when your code imports Bun built-ins such as `bun:test`.\n\nIf your repo has a single root `tsconfig.json` or `jsconfig.json`, omit `project` and the resolver uses the root config by default.\n\n## Flat Config With `eslint-plugin-import`\n\nIf you use `eslint-plugin-import`, or an older `eslint-plugin-import-x`, configure the resolver through `settings[\"import/resolver\"]` instead of importing it directly.\n\n```js\nexport default [\n  {\n    settings: {\n      \"import/resolver\": {\n        typescript: {\n          alwaysTryTypes: true,\n          project: \"packages/*/{ts,js}config.json\",\n        },\n      },\n    },\n  },\n];\n```\n\nThe same option names apply here, including `bun` and `project`.\n\n## Legacy `.eslintrc`\n\nFor legacy config, add the parser mapping and the resolver settings under `settings`.\n\n```jsonc\n{\n  \"plugins\": [\"import\"],\n  \"rules\": {\n    \"import/no-unresolved\": \"error\"\n  },\n  \"settings\": {\n    \"import/parsers\": {\n      \"@typescript-eslint/parser\": [\".ts\", \".tsx\"]\n    },\n    \"import/resolver\": {\n      \"typescript\": {\n        \"alwaysTryTypes\": true,\n        \"project\": \"packages/*/{ts,js}config.json\"\n      }\n    }\n  }\n}\n```\n\nIf your project only has one root `tsconfig.json` or `jsconfig.json`, remove `project` and let the resolver pick the root config automatically.\n\n## Choosing `project`\n\nThe `project` option controls which TypeScript or JS config files the resolver reads.\n\n- Omit it to use `<root>/tsconfig.json` or `<root>/jsconfig.json`.\n- Set it to a folder such as `\"apps/web\"` to use that folder's `tsconfig.json` or `jsconfig.json`.\n- Set it to a glob such as `\"packages/*/{ts,js}config.json\"` for monorepos.\n- Set it to an array when different workspaces need different config files.\n\nExamples:\n\n```js\ncreateTypeScriptImportResolver({ project: \"apps/web\" });\n\ncreateTypeScriptImportResolver({\n  project: [\n    \"packages/module-a/tsconfig.json\",\n    \"packages/module-b/jsconfig.json\",\n  ],\n});\n```\n\nThe upstream README notes that multiple configs are useful for monorepos, but TypeScript `references` are preferred when available.\n\n## Bun Support\n\nBun built-ins are not resolved by default.\n\nChoose one of these upstream-documented approaches:\n\n- Set `bun: true` in the resolver options.\n- Run ESLint with `bun --bun eslint`.\n- Enable `run.bun` in `bunfig.toml`.\n\nExample:\n\n```js\nimport { createTypeScriptImportResolver } from \"eslint-import-resolver-typescript\";\n\nexport default [\n  {\n    settings: {\n      \"import-x/resolver-next\": [\n        createTypeScriptImportResolver({\n          bun: true,\n        }),\n      ],\n    },\n  },\n];\n```\n\n## Resolver Options And Defaults\n\nResolver options are passed through to `unrs-resolver`. The README calls out these commonly adjusted keys:\n\n- `conditionNames`\n- `extensions`\n- `extensionAlias`\n- `mainFields`\n\nDocumented defaults that matter most in practice:\n\n- `conditionNames` starts with `\"types\"` and `\"import\"`, then includes Node and browser conditions.\n- `extensions` defaults to `.ts`, `.tsx`, `.d.ts`, `.js`, `.jsx`, `.json`, and `.node`.\n- `mainFields` starts with `\"types\"` and `\"typings\"` before JavaScript entry fields such as `\"module\"` and `\"main\"`.\n\n## Important Behavior And Pitfalls\n\nAfter version `2.0.0`, the resolver prefers `.d.ts` over plain `.js` or `.jsx` files when resolving packages from `node_modules`. Upstream documents this as intentional so ESLint can prefer package typings or `@types/*` definitions.\n\nIf you see `import/default` or `import/named` behavior that looks wrong, the maintainer README points those issues to `eslint-plugin-import`, not to this resolver.\n\nIf you want the direct `createTypeScriptImportResolver(...)` import in flat config, use `eslint-plugin-import-x@>=4.5.0`. Otherwise, configure the resolver through `settings[\"import/resolver\"]`.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-deprecation/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-deprecation\ndescription: \"ESLint plugin for reporting uses of TypeScript symbols marked `@deprecated`, including the required type-aware parser setup and common lint workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,deprecation,typescript,javascript,linting,npm\"\n---\n\n# eslint-plugin-deprecation\n\n`eslint-plugin-deprecation` adds a single ESLint rule, `deprecation/deprecation`, that reports usages of symbols whose TypeScript declarations are marked `@deprecated`.\n\nThis package is lint configuration only. It does not use API keys, accounts, runtime clients, or environment variables.\n\n## Install\n\nThe rule depends on TypeScript type information, so install ESLint, TypeScript, and the TypeScript parser alongside the plugin:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-deprecation typescript @typescript-eslint/parser\n```\n\n## TypeScript Project Setup\n\nThe rule only works when ESLint can build a TypeScript program for the files being linted. Point ESLint at a `tsconfig.json` that includes those files.\n\nIf your main `tsconfig.json` excludes tests, scripts, or config files that you still want to lint, create a dedicated ESLint project file:\n\n```json\n{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"test/**/*.ts\", \"test/**/*.tsx\"]\n}\n```\n\nSave that as `tsconfig.eslint.json`, then reference it from ESLint.\n\n## ESLint Config (`.eslintrc.cjs`)\n\nThe maintainer setup for this package uses `@typescript-eslint/parser` with `parserOptions.project` so the rule can read deprecation metadata from TypeScript declarations.\n\n```js\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{ts,tsx}\"],\n      parser: \"@typescript-eslint/parser\",\n      parserOptions: {\n        project: [\"./tsconfig.eslint.json\"],\n        tsconfigRootDir: __dirname,\n        sourceType: \"module\",\n        ecmaVersion: \"latest\",\n      },\n      plugins: [\"deprecation\"],\n      rules: {\n        \"deprecation/deprecation\": \"warn\",\n      },\n    },\n  ],\n};\n```\n\nIf your repo only lints source files and your main `tsconfig.json` already includes them, you can reference that file directly instead of `tsconfig.eslint.json`.\n\nTo fail CI on deprecated API usage, change the rule from `\"warn\"` to `\"error\"`.\n\n## Common Workflows\n\n### Lint for deprecated API usage\n\nRun ESLint normally after adding the rule:\n\n```bash\nnpx eslint \"src/**/*.{ts,tsx}\"\n```\n\nTypical `package.json` scripts:\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint \\\"src/**/*.{ts,tsx}\\\"\",\n    \"lint:ci\": \"eslint \\\"src/**/*.{ts,tsx}\\\" --max-warnings 0\"\n  }\n}\n```\n\nUse `--max-warnings 0` when the rule is still configured as a warning locally but should fail in CI.\n\n### Flag usages of your own deprecated exports\n\nThe rule reads `@deprecated` tags from TypeScript declarations or JSDoc.\n\n```ts\n// api.ts\n/** @deprecated Use createClient instead. */\nexport function createLegacyClient() {\n  return {};\n}\n```\n\n```ts\n// app.ts\nimport { createLegacyClient } from \"./api\";\n\ncreateLegacyClient();\n```\n\nWith the rule enabled, ESLint reports the usage in `app.ts`.\n\n### Roll out gradually in an existing codebase\n\nStart with a warning while you clean up existing deprecated calls:\n\n```js\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{ts,tsx}\"],\n      parser: \"@typescript-eslint/parser\",\n      parserOptions: {\n        project: [\"./tsconfig.eslint.json\"],\n        tsconfigRootDir: __dirname,\n      },\n      plugins: [\"deprecation\"],\n      rules: {\n        \"deprecation/deprecation\": \"warn\",\n      },\n    },\n  ],\n};\n```\n\nAfter the codebase is clean, change the rule to `\"error\"` so new deprecated usages fail linting immediately.\n\n## Important Pitfalls\n\n- `deprecation/deprecation` needs type information. If `parserOptions.project` is missing or points at the wrong `tsconfig`, the rule cannot evaluate deprecations correctly.\n- The `tsconfig` used for linting must include every file you run ESLint against. If ESLint targets a file outside that project, type-aware linting will fail before this rule runs.\n- Configure the rule only for files parsed by `@typescript-eslint/parser`. In mixed JS and TS repos, scope it with `overrides` instead of enabling it globally.\n- The rule reports usages of declarations marked `@deprecated`; it does not read npm package deprecation notices from the registry.\n- This plugin reports problems but does not choose replacement APIs for you. Keep the deprecation message on the declaration clear so developers know what to migrate to.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-deprecation@3.0.0`.\n- The package centers on the `deprecation/deprecation` rule and the type-aware ESLint setup required for that rule.\n- The maintainer documentation for this release family is based on `.eslintrc`-style ESLint configuration with `@typescript-eslint/parser`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/gund/eslint-plugin-deprecation\n- GitHub README: https://github.com/gund/eslint-plugin-deprecation#readme\n- npm package page: https://www.npmjs.com/package/eslint-plugin-deprecation\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-import/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-import\ndescription: \"ESLint plugin for validating import/export syntax, module resolution, dependency declarations, and import ordering\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.32.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,imports,linting,javascript,typescript\"\n---\n\n# eslint-plugin-import\n\n`eslint-plugin-import` adds import/export-specific lint rules to ESLint. It does not have a runtime client, environment variables, or initialization step beyond your ESLint config.\n\nAll rules are off by default. In most projects, start from the plugin's `recommended` preset and then add a small number of explicit rules.\n\n## Install\n\nFor a JavaScript project using ESLint flat config:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-import @eslint/js\n```\n\nIf you lint TypeScript imports, also install the packages called out in the maintainer README:\n\n```bash\nnpm install --save-dev @typescript-eslint/parser eslint-import-resolver-typescript\n```\n\n## Flat config (`eslint.config.js`)\n\nUse this with modern ESLint setups:\n\n```js\nimport importPlugin from 'eslint-plugin-import';\nimport js from '@eslint/js';\n\nexport default [\n  js.configs.recommended,\n  importPlugin.flatConfigs.recommended,\n  {\n    files: ['**/*.{js,mjs,cjs}'],\n    languageOptions: {\n      ecmaVersion: 'latest',\n      sourceType: 'module',\n    },\n    rules: {\n      'no-unused-vars': 'off',\n      'import/no-dynamic-require': 'warn',\n      'import/no-nodejs-modules': 'warn',\n    },\n  },\n];\n```\n\nThe package also exports other flat presets, including `importPlugin.flatConfigs.errors`, `importPlugin.flatConfigs.warnings`, and `importPlugin.flatConfigs.typescript`.\n\n## Legacy config (`.eslintrc`)\n\nUse this if your repo still relies on `.eslintrc`:\n\n```jsonc\n{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:import/recommended\"\n  ]\n}\n```\n\nIf you prefer to enable rules manually instead of extending a preset:\n\n```jsonc\n{\n  \"rules\": {\n    \"import/no-unresolved\": [\"error\", { \"commonjs\": true, \"amd\": true }],\n    \"import/named\": \"error\",\n    \"import/namespace\": \"error\",\n    \"import/default\": \"error\",\n    \"import/export\": \"error\"\n  }\n}\n```\n\n## TypeScript\n\nFor legacy config, the maintainer README recommends extending both the base preset and the TypeScript preset, then enabling the TypeScript resolver:\n\n```jsonc\n{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:import/recommended\",\n    \"plugin:import/typescript\"\n  ],\n  \"settings\": {\n    \"import/resolver\": {\n      \"typescript\": true,\n      \"node\": true\n    }\n  }\n}\n```\n\nFor flat config with `typescript-eslint`'s `config()` helper, include the plugin's flat TypeScript preset inside `extends`:\n\n```js\nimport tseslint from 'typescript-eslint';\nimport importPlugin from 'eslint-plugin-import';\nimport js from '@eslint/js';\n\nexport default tseslint.config(\n  js.configs.recommended,\n  {\n    files: ['**/*.{ts,tsx}'],\n    extends: [\n      importPlugin.flatConfigs.recommended,\n      importPlugin.flatConfigs.typescript,\n    ],\n  }\n);\n```\n\nThe shipped TypeScript preset adds TypeScript-related extensions, maps `@typescript-eslint/parser` for TypeScript files, and disables `import/named` because TypeScript already checks named imports during compilation.\n\n## Common workflows\n\n### Enforce import ordering and autofix it\n\n`import/order` is fixable with ESLint's `--fix` flag:\n\n```js\nexport default [\n  {\n    rules: {\n      'import/order': ['error', {\n        groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],\n        'newlines-between': 'always',\n        alphabetize: { order: 'asc', caseInsensitive: true },\n      }],\n    },\n  },\n];\n```\n\n```bash\nnpx eslint . --fix\n```\n\n### Check `require()` and AMD imports too\n\n`import/no-unresolved` only checks ES module imports by default. If you still use CommonJS or AMD, opt in explicitly:\n\n```jsonc\n{\n  \"rules\": {\n    \"import/no-unresolved\": [\"error\", {\n      \"commonjs\": true,\n      \"amd\": true\n    }]\n  }\n}\n```\n\nUseful options from the rule docs:\n\n- `ignore`: suppress known non-code imports that your resolver will not handle\n- `caseSensitive: false`: disable path-case checks on case-insensitive filesystems\n- `caseSensitiveStrict: true`: also check case in `cwd` and absolute paths\n\n### Prevent undeclared dependencies\n\n`import/no-extraneous-dependencies` checks the closest parent `package.json` by default. In monorepos or nested packages, set `packageDir` so the rule reads the right manifest:\n\n```js\nconst config = {\n  rules: {\n    'import/no-extraneous-dependencies': ['error', {\n      devDependencies: ['**/*.test.js', '**/*.spec.js'],\n      packageDir: ['./packages/app', './packages/config', './'],\n    }],\n  },\n};\n\nexport default [config];\n```\n\nYou can also enable `includeInternal` to check local imports and `includeTypes` to check TypeScript type-only imports.\n\n## Resolver pitfalls\n\n`import/no-unresolved` follows standard Node resolution unless you configure a resolver. If your project relies on TypeScript path aliases, webpack aliases, or another non-Node resolution strategy, add an appropriate `settings['import/resolver']` entry or expect false positives.\n\nThe upstream docs call out three important cases:\n\n- Node resolution is the default behavior\n- webpack resolution is supported through `eslint-import-resolver-webpack`\n- TypeScript projects commonly need `eslint-import-resolver-typescript`\n\nIf you are using a module bundler other than Node or webpack, `import/no-unresolved` can still produce false positives.\n\n## Minimal commands\n\n```bash\n# lint\nnpx eslint .\n\n# lint and autofix fixable rules such as import/order\nnpx eslint . --fix\n```\n\n## What to enable first\n\nIf you want a small, low-noise setup, start with:\n\n- `plugin:import/recommended` or `importPlugin.flatConfigs.recommended`\n- `import/order` for consistent import blocks\n- `import/no-extraneous-dependencies` for package boundary mistakes\n- TypeScript resolver settings if your repo uses TypeScript or path aliases\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-jest/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-jest\ndescription: \"ESLint plugin for Jest that adds shared configs and rules for common test-file patterns, assertion usage, deprecated APIs, and Jest-specific globals.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"29.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,jest,linting,javascript,testing\"\n---\n\n# eslint-plugin-jest JavaScript Guide\n\n## Install\n\nInstall the plugin as a development dependency alongside ESLint and Jest:\n\n```bash\nnpm install -D eslint eslint-plugin-jest jest\n```\n\nThis package does not use API keys, accounts, runtime clients, or environment variables.\n\n## Flat Config (`eslint.config.cjs`)\n\nScope the plugin to test files only. The maintainer docs recommend applying Jest rules with `files` globs instead of at the top level.\n\n```javascript\nconst jest = require(\"eslint-plugin-jest\");\n\nmodule.exports = [\n  {\n    files: [\n      \"**/__tests__/**/*.{js,jsx,ts,tsx}\",\n      \"**/*.{test,spec}.{js,jsx,ts,tsx}\",\n    ],\n    ...jest.configs[\"flat/recommended\"],\n    rules: {\n      ...jest.configs[\"flat/recommended\"].rules,\n      \"jest/prefer-expect-assertions\": \"off\",\n    },\n  },\n];\n```\n\nUse `jest.configs[\"flat/style\"]` if you also want stylistic Jest rules such as `prefer-to-be-null`.\n\n## Legacy Config (`.eslintrc.cjs`)\n\nIf the project still uses legacy ESLint config, add the preset inside an override so application code is not treated as Jest test code.\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\n        \"**/__tests__/**/*.{js,jsx,ts,tsx}\",\n        \"**/*.{test,spec}.{js,jsx,ts,tsx}\",\n      ],\n      extends: [\"plugin:jest/recommended\"],\n      rules: {\n        \"jest/prefer-expect-assertions\": \"off\",\n      },\n    },\n  ],\n};\n```\n\nFor a stylistic preset, use `plugin:jest/style` instead.\n\n## Build a Custom Rule Set\n\nIf you do not want a shared preset, register the plugin directly and add the Jest globals yourself.\n\n```javascript\nconst pluginJest = require(\"eslint-plugin-jest\");\n\nmodule.exports = [\n  {\n    files: [\"**/*.{test,spec}.js\"],\n    plugins: {\n      jest: pluginJest,\n    },\n    languageOptions: {\n      globals: pluginJest.environments.globals.globals,\n    },\n    rules: {\n      \"jest/no-disabled-tests\": \"warn\",\n      \"jest/no-focused-tests\": \"error\",\n      \"jest/no-identical-title\": \"error\",\n      \"jest/prefer-to-have-length\": \"warn\",\n      \"jest/valid-expect\": \"error\",\n    },\n  },\n];\n```\n\nIf you use one of the shared Jest presets, you do not need to add the globals separately.\n\n## Common Workflows\n\n### Run ESLint on tests\n\n```bash\nnpx eslint .\n\n# or lint only test files\nnpx eslint \"test/**/*.test.js\"\n\n# autofix rules that support it\nnpx eslint . --fix\n```\n\nRule IDs from this plugin use the `jest/` prefix.\n\n### Pin the Jest version in a monorepo\n\nSome rules, including `jest/no-deprecated-functions`, change behavior based on the Jest version. By default the plugin resolves Jest from the nearest `node_modules`, caches that result, and reuses it.\n\nIf different packages in the repo use different Jest versions, set `settings.jest.version` in the config that applies to that package.\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"packages/web/**/*.test.js\"],\n      extends: [\"plugin:jest/recommended\"],\n      settings: {\n        jest: {\n          version: require(\"jest/package.json\").version,\n        },\n      },\n    },\n  ],\n};\n```\n\nIf you prefer a fixed value, use `version: 29` instead.\n\n### Support aliased Jest globals\n\nIf your test suite aliases globals such as `describe` to `context`, add the aliases so rules still detect those calls correctly.\n\n```javascript\nmodule.exports = {\n  settings: {\n    jest: {\n      globalAliases: {\n        describe: [\"context\"],\n        fdescribe: [\"fcontext\"],\n        xdescribe: [\"xcontext\"],\n      },\n    },\n  },\n};\n```\n\n## Important Pitfalls\n\n- Apply this plugin only to test-related files. The maintainer docs explicitly warn against enabling Jest rules for every file in the project.\n- If you build a custom flat config instead of using `plugin:jest/*` or `jest.configs[\"flat/*\"]`, add Jest globals yourself with `pluginJest.environments.globals.globals`.\n- `plugin:jest/all` and `jest.configs[\"flat/all\"]` enable every rule and may change in any release, so they are a poor fit for long-term stable lint baselines.\n- The `globalPackage` setting can point the plugin at another source of test globals such as `bun:test`, but the maintainer docs do not guarantee Jest rule semantics outside Jest itself.\n- If different subfolders resolve different Jest versions, set `settings.jest.version` explicitly in nested configs to avoid stale version detection.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-jest@29.15.0`.\n- The maintainer README documents both legacy shared configs such as `plugin:jest/recommended` and flat-config exports such as `jest.configs[\"flat/recommended\"]`.\n- Some rules are version-aware and use the configured or auto-detected Jest version when linting.\n\n## Official Sources\n\n- https://github.com/jest-community/eslint-plugin-jest\n- https://github.com/jest-community/eslint-plugin-jest/blob/main/README.md\n- https://www.npmjs.com/package/eslint-plugin-jest\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-jsx-a11y/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-jsx-a11y\ndescription: \"Accessibility-focused ESLint rules for JSX, including flat config setup, legacy config setup, custom component mapping, and common rule overrides.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.10.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,accessibility,jsx,react,linting,javascript,npm\"\n---\n\n# eslint-plugin-jsx-a11y JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint-plugin-jsx-a11y` as a local development dependency and wire it into your ESLint config.\n\n`eslint-plugin-jsx-a11y` is configuration only. It does not use API keys, accounts, runtime clients, or environment variables.\n\nVersion `6.10.2` ships both legacy shareable configs (`plugin:jsx-a11y/recommended`, `plugin:jsx-a11y/strict`) and flat config exports (`flatConfigs.recommended`, `flatConfigs.strict`).\n\n## Install\n\nFor a flat-config project:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-jsx-a11y globals\n```\n\nFor a legacy `.eslintrc*` setup:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-jsx-a11y\n```\n\nThe package declares `eslint` as a peer dependency and supports ESLint `^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9`.\n\n## Flat Config (`eslint.config.js`)\n\nThe package default export is the plugin object. For most projects, start from `flatConfigs.recommended` and add your own `files` and globals.\n\n### Recommended setup\n\n```js\nconst jsxA11y = require('eslint-plugin-jsx-a11y');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],\n    ...jsxA11y.flatConfigs.recommended,\n    languageOptions: {\n      ...jsxA11y.flatConfigs.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n        ...globals.serviceworker,\n      },\n    },\n  },\n];\n```\n\nThe plugin README is explicit that the flat shareable configs do not set `files` or `languageOptions.globals` for you.\n\n### Stricter baseline\n\nIf you want the plugin's stricter preset, swap in `flatConfigs.strict`:\n\n```js\nconst jsxA11y = require('eslint-plugin-jsx-a11y');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],\n    ...jsxA11y.flatConfigs.strict,\n    languageOptions: {\n      ...jsxA11y.flatConfigs.strict.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n  },\n];\n```\n\n### Manual flat config\n\nUse the plugin object directly when you want to choose rules yourself instead of starting from a preset.\n\n```js\nconst jsxA11y = require('eslint-plugin-jsx-a11y');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,jsx}'],\n    plugins: {\n      'jsx-a11y': jsxA11y,\n    },\n    languageOptions: {\n      parserOptions: {\n        ecmaFeatures: {\n          jsx: true,\n        },\n      },\n    },\n    rules: {\n      'jsx-a11y/alt-text': 'error',\n      'jsx-a11y/anchor-is-valid': 'error',\n      'jsx-a11y/label-has-associated-control': 'error',\n    },\n  },\n];\n```\n\n## Legacy Config (`.eslintrc*`)\n\nUse the legacy preset names if your project still runs ESLint with `.eslintrc.json`, `.eslintrc.cjs`, or similar config files.\n\n### Recommended preset\n\n```json\n{\n  \"extends\": [\"plugin:jsx-a11y/recommended\"]\n}\n```\n\n### Strict preset\n\n```json\n{\n  \"extends\": [\"plugin:jsx-a11y/strict\"]\n}\n```\n\n### Manual legacy setup\n\n```json\n{\n  \"plugins\": [\"jsx-a11y\"],\n  \"parserOptions\": {\n    \"ecmaFeatures\": {\n      \"jsx\": true\n    }\n  },\n  \"rules\": {\n    \"jsx-a11y/alt-text\": \"error\",\n    \"jsx-a11y/anchor-is-valid\": \"error\",\n    \"jsx-a11y/label-has-associated-control\": \"error\"\n  }\n}\n```\n\nWhen you extend `plugin:jsx-a11y/recommended` or `plugin:jsx-a11y/strict`, you do not need to repeat `\"plugins\": [\"jsx-a11y\"]`.\n\n## Shared Settings\n\nThe plugin reads shared settings from `settings['jsx-a11y']`.\n\nUse these settings when your app wraps native elements in design-system components or uses polymorphic components.\n\n```js\nconst jsxA11y = require('eslint-plugin-jsx-a11y');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    ...jsxA11y.flatConfigs.recommended,\n    languageOptions: {\n      ...jsxA11y.flatConfigs.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n    settings: {\n      'jsx-a11y': {\n        components: {\n          CityInput: 'input',\n          CustomButton: 'button',\n          LinkText: 'a',\n        },\n        attributes: {\n          for: ['htmlFor', 'for'],\n        },\n        polymorphicPropName: 'as',\n        polymorphicAllowList: ['Box'],\n      },\n    },\n  },\n];\n```\n\n- `components` maps custom component names to DOM element types so rules can analyze them semantically.\n- `attributes` maps DOM attribute names to JSX prop names to check.\n- `polymorphicPropName` tells the plugin which prop determines the rendered element type.\n- `polymorphicAllowList` limits polymorphic linting to specific components.\n\n## Common Workflows\n\n### Lint a JSX or TSX project\n\n```bash\nnpx eslint .\n```\n\nOr scope linting to source files:\n\n```bash\nnpx eslint \"src/**/*.{js,jsx,ts,tsx}\"\n```\n\n### Enforce accessible icon buttons\n\nBoth shipped presets keep `jsx-a11y/control-has-associated-label` disabled. If your app uses icon-only buttons or custom interactive controls, turn it on explicitly.\n\n```js\nconst jsxA11y = require('eslint-plugin-jsx-a11y');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    ...jsxA11y.flatConfigs.recommended,\n    languageOptions: {\n      ...jsxA11y.flatConfigs.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n    rules: {\n      ...jsxA11y.flatConfigs.recommended.rules,\n      'jsx-a11y/control-has-associated-label': 'error',\n    },\n  },\n];\n```\n\nUse a visible label or an ARIA label in the component code:\n\n```jsx\n<button type=\"button\" aria-label=\"Save\" className=\"icon-save\" />\n```\n\n### Configure custom labels and inputs\n\n`label-has-associated-control` can be taught about custom label and input components.\n\n```json\n{\n  \"rules\": {\n    \"jsx-a11y/label-has-associated-control\": [\n      \"error\",\n      {\n        \"labelComponents\": [\"CustomInputLabel\"],\n        \"labelAttributes\": [\"label\"],\n        \"controlComponents\": [\"CustomInput\"],\n        \"depth\": 3\n      }\n    ]\n  }\n}\n```\n\nThis matches component patterns like:\n\n```jsx\n<CustomInputLabel label=\"Surname\">\n  <CustomInput type=\"text\" value={value} />\n</CustomInputLabel>\n```\n\n### Keep links as links and actions as buttons\n\n`anchor-is-valid` expects anchors to navigate. For click-only actions, use a button instead of `<a onClick={...}>`.\n\n```jsx\n<button type=\"button\" onClick={openDialog}>\n  Open settings\n</button>\n```\n\nFor custom link wrappers that render an anchor, configure the rule to inspect the wrapper component too:\n\n```json\n{\n  \"rules\": {\n    \"jsx-a11y/anchor-is-valid\": [\n      \"error\",\n      {\n        \"components\": [\"Link\"],\n        \"aspects\": [\"noHref\", \"invalidHref\", \"preferButton\"]\n      }\n    ]\n  }\n}\n```\n\n## Important Pitfalls\n\n- `flatConfigs.recommended` and `flatConfigs.strict` already add the plugin and JSX parser options, but they do not set `files` or globals.\n- When you customize `languageOptions`, merge `jsxA11y.flatConfigs.*.languageOptions` instead of replacing it, or you can drop the preset's JSX parser settings.\n- `jsx-a11y/control-has-associated-label` is disabled in both shipped presets. Enable it yourself if you want linting for icon-only buttons and similar controls.\n- `jsx-a11y/label-has-for` is disabled in the shipped presets; `jsx-a11y/label-has-associated-control` is the preset-enabled label rule.\n- `jsx-a11y/anchor-is-valid` treats `<a>` as navigation only. If the element performs an action, use `<button>` and style it if needed.\n- Polymorphic settings can help with design-system components, but the maintainer README explicitly warns to use them with caution.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-n/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-n\ndescription: \"Node.js-focused ESLint rules and shareable configs for CommonJS, ESM, and mixed JavaScript projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"17.24.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,nodejs,javascript,linting,npm\"\n---\n\n# eslint-plugin-n JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint` and `eslint-plugin-n` locally, then choose the preset that matches how your Node.js files run:\n\n- `n.configs[\"flat/recommended-script\"]` for CommonJS and script files\n- `n.configs[\"flat/recommended-module\"]` for ESM packages\n- `n.configs[\"flat/mixed-esm-and-cjs\"]` when the same repo contains both\n\n`eslint-plugin-n` is configuration only. It does not use API keys, accounts, authentication, or runtime environment variables.\n\n## Install\n\n```bash\nnpm install -D eslint eslint-plugin-n\nnpx eslint --version\n```\n\nIf your project is not already using ESM for config files, use `eslint.config.mjs` for flat config examples that use `import`.\n\n## Flat Config (`eslint.config.mjs`)\n\n### CommonJS or script projects\n\nUse the script preset when your files run as CommonJS or plain Node.js scripts.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/recommended-script\"],\n  {\n    rules: {\n      \"n/no-process-exit\": \"off\",\n    },\n  },\n];\n```\n\n### ESM projects\n\nUse the module preset when your package uses ESM, such as `import` and `export`, or `\"type\": \"module\"` in `package.json`.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/recommended-module\"],\n];\n```\n\n### Mixed ESM and CommonJS repos\n\nUse the mixed preset when the same repository includes both module systems.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/mixed-esm-and-cjs\"],\n];\n```\n\n### Configure rules manually\n\nUse the plugin object directly when you want to choose rules instead of starting from a shareable config.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  {\n    files: [\"scripts/**/*.js\"],\n    plugins: {\n      n,\n    },\n    rules: {\n      \"n/no-missing-require\": \"error\",\n      \"n/no-process-exit\": \"error\",\n      \"n/no-unpublished-require\": \"off\",\n    },\n  },\n];\n```\n\n## Legacy Config (`.eslintrc*`)\n\nIf your project still uses the legacy ESLint config system, extend the plugin preset from `.eslintrc.json`, `.eslintrc.cjs`, or an equivalent legacy config file.\n\n### Recommended preset\n\n```json\n{\n  \"extends\": [\"plugin:n/recommended\"]\n}\n```\n\n### Manual legacy setup\n\n```json\n{\n  \"plugins\": [\"n\"],\n  \"rules\": {\n    \"n/no-missing-require\": \"error\",\n    \"n/no-process-exit\": \"error\"\n  }\n}\n```\n\n## Shared Settings\n\nThe plugin reads shared `settings.node` values for rules that check the Node.js version and import resolution.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/recommended-module\"],\n  {\n    settings: {\n      node: {\n        version: process.versions.node,\n        tryExtensions: [\".js\", \".mjs\", \".cjs\", \".json\"],\n      },\n    },\n  },\n];\n```\n\nUse `settings.node.version` when the runtime you support is different from the Node.js version that runs ESLint in CI or on a developer machine.\n\n## Common Workflows\n\n### Lint a Node.js project\n\n```bash\nnpx eslint .\n```\n\nOr lint only your Node.js entry points, scripts, and config files:\n\n```bash\nnpx eslint \"scripts/**/*.js\" \"src/**/*.js\" \"*.config.js\"\n```\n\n### Allow test-only or unpublished dependencies\n\nRules such as `n/no-unpublished-import` and `n/no-unpublished-require` are useful for shipped code, but they often need overrides for tests, fixtures, and local build scripts.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/mixed-esm-and-cjs\"],\n  {\n    files: [\"test/**\", \"scripts/**\", \"*.config.js\"],\n    rules: {\n      \"n/no-unpublished-import\": \"off\",\n      \"n/no-unpublished-require\": \"off\",\n    },\n  },\n];\n```\n\n### Pin the supported Node.js runtime\n\nIf you publish code for a specific Node.js floor, set `settings.node.version` so rules that check built-ins and language features evaluate against that runtime instead of the machine running ESLint.\n\n```js\nimport n from \"eslint-plugin-n\";\n\nexport default [\n  n.configs[\"flat/recommended-module\"],\n  {\n    settings: {\n      node: {\n        version: \">=18.0.0\",\n      },\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- Pick the preset that matches your module system. Use the mixed preset if a repo contains both ESM and CommonJS.\n- Shareable flat configs are config objects. Use `plugins: { n }` only when you are configuring individual rules yourself.\n- Rules that check supported syntax or built-ins depend on `settings.node.version`; set it explicitly when your target runtime differs from the Node.js version running ESLint.\n- `n/no-unpublished-import` and `n/no-unpublished-require` commonly need overrides for tests, fixtures, and build tooling.\n- `eslint-plugin-n` focuses on Node.js code. Browser globals and browser-specific linting belong in other ESLint config blocks or plugins.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-n@17.24.0`.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-prettier/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-prettier\ndescription: \"Run Prettier as an ESLint rule, with flat config and legacy config setup for JavaScript projects.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.5.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,prettier,javascript,linting,formatting,npm\"\n---\n\n# eslint-plugin-prettier JavaScript Guide\n\n## Install\n\n`eslint-plugin-prettier` runs Prettier inside ESLint. Install it together with `eslint`, `prettier`, and `eslint-config-prettier`.\n\n```bash\nnpm install --save-dev eslint prettier eslint-plugin-prettier eslint-config-prettier\n```\n\nThis package does not use API keys, accounts, or runtime environment variables.\n\n## Flat config setup\n\nFor ESLint flat config, import `eslint-plugin-prettier/recommended` and place it last in the exported config array so Prettier-related conflict disabling happens after your other config entries.\n\n```js\nimport eslintPluginPrettierRecommended from \"eslint-plugin-prettier/recommended\";\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs,jsx}\"],\n    rules: {\n      \"no-unused-vars\": \"error\",\n    },\n  },\n  eslintPluginPrettierRecommended,\n];\n```\n\nThe recommended preset:\n\n- enables the `prettier/prettier` rule\n- enables `eslint-config-prettier`\n- disables `arrow-body-style` and `prefer-arrow-callback`\n\nRun ESLint normally after adding the config:\n\n```bash\nnpx eslint .\nnpx eslint . --fix\n```\n\n## Legacy `.eslintrc` setup\n\nIf your project still uses legacy ESLint config files, extend `plugin:prettier/recommended` and keep it last in `extends`.\n\n```json\n{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:prettier/recommended\"\n  ]\n}\n```\n\nThis legacy preset turns on the same `prettier/prettier` rule and pulls in `eslint-config-prettier` for you.\n\n## Prettier configuration\n\nKeep formatting options in a normal Prettier config so ESLint, Prettier CLI, and editor integrations all use the same settings.\n\n`.prettierrc.json`:\n\n```json\n{\n  \"singleQuote\": true,\n  \"semi\": true,\n  \"trailingComma\": \"all\"\n}\n```\n\nThen lint or autofix with ESLint:\n\n```bash\nnpx eslint src --fix\n```\n\n## Configure the rule directly\n\nIf you do not want the full recommended preset, register the plugin and enable the rule yourself:\n\n```js\nimport prettierPlugin from \"eslint-plugin-prettier\";\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs,jsx}\"],\n    plugins: {\n      prettier: prettierPlugin,\n    },\n    rules: {\n      \"prettier/prettier\": \"error\",\n    },\n  },\n];\n```\n\nWhen you configure the rule manually, also disable ESLint rules that conflict with Prettier. The simplest way is to use the recommended preset instead. If you need manual composition, add `eslint-config-prettier` at the end of your ESLint config.\n\n## Common workflows\n\n### Show formatting differences as lint errors\n\n```bash\nnpx eslint .\n```\n\nFiles that do not match Prettier formatting fail with the `prettier/prettier` rule.\n\n### Apply formatting fixes with ESLint\n\n```bash\nnpx eslint . --fix\n```\n\nBecause `prettier/prettier` is fixable, ESLint writes the Prettier-formatted result back to disk.\n\n### Add package scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n## Important pitfalls\n\n- Put `eslint-plugin-prettier/recommended` last in flat config arrays and `plugin:prettier/recommended` last in legacy `extends`.\n- Install `prettier` itself. The plugin reports Prettier output through ESLint, but it does not replace the Prettier package.\n- Prefer a `.prettierrc` file for formatting options. Editor extensions read Prettier config files, but rule-only options in ESLint config are easier to drift from editor behavior.\n- If you are not using the recommended preset, disable conflicting formatting rules with `eslint-config-prettier` yourself.\n- `arrow-body-style` and `prefer-arrow-callback` can interact badly with this plugin during autofix, which is why the recommended config disables them.\n\n## Minimal commands\n\n```bash\n# install\nnpm install --save-dev eslint prettier eslint-plugin-prettier eslint-config-prettier\n\n# lint\nnpx eslint .\n\n# lint and apply Prettier fixes through ESLint\nnpx eslint . --fix\n```\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-promise/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-promise\ndescription: \"Promise-focused ESLint rules for JavaScript projects, including flat config and legacy config setup.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,javascript,linting,promises,async,npm\"\n---\n\n# eslint-plugin-promise JavaScript Guide\n\n## Golden Rule\n\nUse `eslint-plugin-promise` only in ESLint configuration. It has no runtime client, no authentication, and no environment variables.\n\nInstall it alongside `eslint`, then either start from the recommended preset or enable the `promise/*` rules you want explicitly.\n\n## Install\n\n```bash\nnpm install -D eslint eslint-plugin-promise\nnpx eslint --version\n```\n\nIf your repo is not already using ESM, prefer `eslint.config.mjs` for flat config. If `package.json` already sets `\"type\": \"module\"`, `eslint.config.js` also works.\n\n## Flat Config (`eslint.config.mjs`)\n\nFor modern ESLint setup, use the plugin's flat-config recommended preset.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nconst promiseRecommended = promise.configs[\"flat/recommended\"];\n\nexport default [\n  {\n    ...promiseRecommended,\n    files: [\"**/*.{js,mjs,cjs}\"],\n  },\n];\n```\n\nThat preset enables the plugin and applies its recommended `promise/*` rules.\n\n### Add project-specific rules on top of the preset\n\nMerge the preset rules before adding overrides so you keep the recommended baseline.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nconst promiseRecommended = promise.configs[\"flat/recommended\"];\n\nexport default [\n  {\n    ...promiseRecommended,\n    files: [\"src/**/*.{js,mjs,cjs}\"],\n    rules: {\n      ...promiseRecommended.rules,\n      \"promise/no-nesting\": \"warn\",\n      \"promise/prefer-await-to-then\": \"warn\",\n      \"promise/prefer-await-to-callbacks\": \"warn\",\n    },\n  },\n];\n```\n\n### Configure the plugin manually\n\nIf you do not want the shared preset, register the plugin yourself and pick the rules you need.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    plugins: {\n      promise,\n    },\n    rules: {\n      \"promise/always-return\": \"error\",\n      \"promise/catch-or-return\": \"error\",\n      \"promise/no-return-wrap\": \"error\",\n      \"promise/param-names\": \"error\",\n      \"promise/no-nesting\": \"warn\",\n    },\n  },\n];\n```\n\n## Legacy Config (`.eslintrc.cjs`)\n\nIf the repo still uses the legacy ESLint config system, extend the package's recommended preset.\n\n```javascript\nmodule.exports = {\n  extends: [\"plugin:promise/recommended\"],\n};\n```\n\n### Manual legacy setup\n\n```javascript\nmodule.exports = {\n  plugins: [\"promise\"],\n  rules: {\n    \"promise/always-return\": \"error\",\n    \"promise/catch-or-return\": \"error\",\n    \"promise/no-return-wrap\": \"error\",\n    \"promise/param-names\": \"error\",\n  },\n};\n```\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n\n# or lint a specific folder\nnpx eslint \"src/**/*.js\"\n```\n\nRule IDs from this plugin use the `promise/` prefix.\n\n### Enforce cleaner Promise chains\n\nUse the recommended preset, then turn on a few stricter rules for projects that still rely heavily on `.then()` chains.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nconst promiseRecommended = promise.configs[\"flat/recommended\"];\n\nexport default [\n  {\n    ...promiseRecommended,\n    files: [\"**/*.{js,mjs,cjs}\"],\n    rules: {\n      ...promiseRecommended.rules,\n      \"promise/always-return\": \"error\",\n      \"promise/no-return-wrap\": \"error\",\n      \"promise/no-nesting\": \"warn\",\n    },\n  },\n];\n```\n\n### Prefer `async`/`await` in application code\n\nIf your team wants to discourage `.then()` chains and callback-based Promise code, enable the opt-in preference rules.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nexport default [\n  {\n    files: [\"src/**/*.{js,mjs,cjs}\"],\n    plugins: {\n      promise,\n    },\n    rules: {\n      \"promise/prefer-await-to-then\": \"warn\",\n      \"promise/prefer-await-to-callbacks\": \"warn\",\n    },\n  },\n];\n```\n\n### Scope the plugin in a monorepo\n\nApply Promise rules only to the packages or folders where you want them.\n\n```javascript\nimport promise from \"eslint-plugin-promise\";\n\nconst promiseRecommended = promise.configs[\"flat/recommended\"];\n\nexport default [\n  {\n    ...promiseRecommended,\n    files: [\"packages/web/**/*.{js,mjs,cjs}\"],\n  },\n  {\n    ...promiseRecommended,\n    files: [\"packages/api/**/*.{js,mjs,cjs}\"],\n    rules: {\n      ...promiseRecommended.rules,\n      \"promise/no-nesting\": \"warn\",\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- `eslint-plugin-promise` is config-only. There is no runtime initialization step and no environment variable to set.\n- Use `promise.configs[\"flat/recommended\"]` only in flat config. Use `plugin:promise/recommended` only in legacy `.eslintrc*` config.\n- If you override `rules` on top of the recommended preset, merge `...promiseRecommended.rules` first or you will replace the preset rules entirely.\n- The `prefer-await-*` rules are a style choice, not a universal default. They can be noisy in codebases that intentionally use Promise chains.\n- Add `files` globs yourself when using the flat preset so the plugin only applies where you want it.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-promise@7.2.1`.\n- The package publishes a flat-config recommended export for `eslint.config.*` and a legacy `plugin:promise/recommended` preset for `.eslintrc*` config.\n- Rule names from this package use the `promise/` prefix.\n\n## Official Sources\n\n- GitHub repository: https://github.com/eslint-community/eslint-plugin-promise\n- GitHub README: https://github.com/eslint-community/eslint-plugin-promise#readme\n- npm package page: https://www.npmjs.com/package/eslint-plugin-promise\n- ESLint flat config docs: https://eslint.org/docs/latest/use/configure/configuration-files\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-react/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-react\ndescription: \"React-specific ESLint rules with flat config and legacy config setup for JavaScript projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.37.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,react,linting,javascript,npm\"\n---\n\n# eslint-plugin-react JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint` and `eslint-plugin-react` locally, then configure the plugin in your ESLint config file.\n\nFor modern ESLint setups, prefer `eslint.config.js` and the plugin's flat config exports at `require(\"eslint-plugin-react\").configs.flat`. Set `settings.react.version` to `\"detect\"` unless you need to pin a specific React version.\n\n`eslint-plugin-react` is configuration only. It does not need API keys, environment variables, runtime initialization, or authentication.\n\n## Install\n\nFor a flat config with browser globals:\n\n```bash\nnpm install -D eslint eslint-plugin-react globals\n```\n\nFor a legacy `.eslintrc*` setup:\n\n```bash\nnpm install -D eslint eslint-plugin-react\n```\n\nThe package README notes that a global ESLint install is possible, but plugins and shareable configs should still be installed locally.\n\n## Flat Config (`eslint.config.js`)\n\n`eslint-plugin-react@7.37.5` exports three flat configs:\n\n- `reactPlugin.configs.flat.recommended`\n- `reactPlugin.configs.flat.all`\n- `reactPlugin.configs.flat['jsx-runtime']`\n\nThe flat configs enable JSX in `languageOptions.parserOptions`, but they do not set `files` or `languageOptions.globals` for you.\n\n### Recommended React setup\n\nUse this for a typical browser React app. Add the `jsx-runtime` config if you use the React 17+ automatic JSX transform.\n\n```js\nconst reactPlugin = require('eslint-plugin-react');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,mjs,cjs,jsx}'],\n    ...reactPlugin.configs.flat.recommended,\n    settings: {\n      react: {\n        version: 'detect',\n      },\n    },\n    languageOptions: {\n      ...reactPlugin.configs.flat.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n  },\n  {\n    files: ['**/*.{js,mjs,cjs,jsx}'],\n    ...reactPlugin.configs.flat['jsx-runtime'],\n  },\n];\n```\n\n`reactPlugin.configs.flat['jsx-runtime']` disables `react/react-in-jsx-scope` and `react/jsx-uses-react`.\n\n### Configure the plugin manually\n\nUse the plugin object directly when you want to choose rules yourself instead of starting from a shareable config.\n\n```js\nconst react = require('eslint-plugin-react');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,mjs,cjs,jsx}'],\n    plugins: {\n      react,\n    },\n    languageOptions: {\n      parserOptions: {\n        ecmaFeatures: {\n          jsx: true,\n        },\n      },\n    },\n    settings: {\n      react: {\n        version: 'detect',\n      },\n    },\n    rules: {\n      'react/jsx-key': 'error',\n      'react/jsx-no-duplicate-props': 'error',\n      'react/jsx-uses-vars': 'error',\n    },\n  },\n];\n```\n\n### Override recommended rules\n\nIf you want the recommended baseline but need a few changes, spread the recommended rules and override the entries you want.\n\n```js\nconst reactPlugin = require('eslint-plugin-react');\nconst globals = require('globals');\n\nmodule.exports = [\n  {\n    files: ['**/*.{js,mjs,cjs,jsx}'],\n    ...reactPlugin.configs.flat.recommended,\n    settings: {\n      react: {\n        version: 'detect',\n      },\n    },\n    languageOptions: {\n      ...reactPlugin.configs.flat.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n    rules: {\n      ...reactPlugin.configs.flat.recommended.rules,\n      'react/prop-types': 'off',\n    },\n  },\n  {\n    files: ['**/*.{js,mjs,cjs,jsx}'],\n    ...reactPlugin.configs.flat['jsx-runtime'],\n  },\n];\n```\n\n## Legacy Config (`.eslintrc*`)\n\nIf your project still uses the legacy ESLint config system, extend the plugin presets from `.eslintrc.json`, `.eslintrc.cjs`, or the equivalent legacy config file.\n\n### Recommended preset\n\n```json\n{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:react/recommended\",\n    \"plugin:react/jsx-runtime\"\n  ],\n  \"settings\": {\n    \"react\": {\n      \"version\": \"detect\"\n    }\n  }\n}\n```\n\nIf you are not using the React 17+ automatic JSX transform, remove `plugin:react/jsx-runtime`.\n\n### Manual legacy setup\n\nIf you do not want to use a preset, add the plugin, enable JSX parsing, and list the rules you want explicitly.\n\n```json\n{\n  \"plugins\": [\"react\"],\n  \"parserOptions\": {\n    \"ecmaFeatures\": {\n      \"jsx\": true\n    }\n  },\n  \"settings\": {\n    \"react\": {\n      \"version\": \"detect\"\n    }\n  },\n  \"rules\": {\n    \"react/jsx-uses-react\": \"error\",\n    \"react/jsx-uses-vars\": \"error\"\n  }\n}\n```\n\n## Shared Settings\n\nThe plugin reads shared settings from `settings`. The most important one is `settings.react.version`.\n\n```js\nsettings: {\n  react: {\n    version: 'detect',\n    pragma: 'React',\n    fragment: 'Fragment',\n  },\n}\n```\n\nSet `defaultVersion` only when version detection cannot resolve the installed React package in your project.\n\nUseful additional shared settings documented by the plugin include:\n\n- `propWrapperFunctions`\n- `componentWrapperFunctions`\n- `formComponents`\n- `linkComponents`\n\nUse these when your codebase wraps components or uses custom link and form components that React rules should recognize.\n\n## Common Workflows\n\n### Lint your project\n\n```bash\nnpx eslint .\n```\n\nOr limit linting to React source files:\n\n```bash\nnpx eslint \"src/**/*.{js,jsx}\"\n```\n\n### Use the React 17+ automatic JSX runtime\n\nIf your project does not import `React` in every JSX file, add the `jsx-runtime` config:\n\n- Legacy config: `plugin:react/jsx-runtime`\n- Flat config: `reactPlugin.configs.flat['jsx-runtime']`\n\nThat config turns off the two rules that expect `React` to be in scope for JSX.\n\n### Enable every React rule\n\nThe plugin also ships an `all` config:\n\n- Legacy config: `plugin:react/all`\n- Flat config: `reactPlugin.configs.flat.all`\n\nUse it only when you intentionally want every non-deprecated rule enabled.\n\n## Important Pitfalls\n\n- `reactPlugin.configs.flat.recommended` and `reactPlugin.configs.flat['jsx-runtime']` are shareable config objects, not plugin objects. Use `plugins: { react: require('eslint-plugin-react') }` when you want to define rules manually.\n- The flat configs do not set `files` or browser globals. Add both yourself in `eslint.config.js`.\n- If `settings.react.version` cannot detect your installed React version, set `defaultVersion` or an explicit version string.\n- The recommended config enables `react/prop-types`. If your components do not use PropTypes, disable that rule explicitly.\n- Installing ESLint globally is not the recommended setup for plugin-based projects; keep the plugin installed locally in the project.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-react@7.37.5`.\n- Package `7.37.5` declares a peer dependency on ESLint `^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7`.\n- The package README documents flat config usage for ESLint `8.21.0+`, notes that the CLI starts looking up `eslint.config.js` from ESLint `8.23.0+`, and notes that ESLint `9` uses the new config system.\n- In `7.37.5`, the plugin root export includes legacy presets in `configs` and flat presets in `configs.flat`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/jsx-eslint/eslint-plugin-react\n- npm package page: https://www.npmjs.com/package/eslint-plugin-react\n- Package README: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/README.md\n- ESLint flat config docs: https://eslint.org/docs/latest/use/configure/configuration-files\n- ESLint language options docs: https://eslint.org/docs/latest/use/configure/language-options\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-react-hooks/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-react-hooks\ndescription: \"React Hooks lint rules and preset configs for ESLint flat config and legacy config\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,react,hooks,linting,javascript,npm\"\n---\n\n# eslint-plugin-react-hooks JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint-plugin-react-hooks` alongside `eslint`, then enable one of the plugin's exported presets in your ESLint config.\n\nFor ESLint 9+, prefer flat config and start with `reactHooks.configs.flat.recommended`. Use `recommended-latest` only if you want the package's newer experimental compiler checks.\n\nThis package is ESLint configuration only. It does not use API keys, environment variables, runtime initialization, or authentication.\n\n## Install\n\nThe package declares `eslint` as a peer dependency and requires Node.js 18 or newer.\n\n```bash\nnpm install -D eslint eslint-plugin-react-hooks\n```\n\n## Flat Config (`eslint.config.js`)\n\nUse the exported flat preset for the default recommended rule set:\n\n```js\nimport reactHooks from \"eslint-plugin-react-hooks\";\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  reactHooks.configs.flat.recommended,\n]);\n```\n\nThe preset only adds the plugin and its rules. It does not add `files`, parser settings, JSX support, TypeScript parser configuration, or globals for you, so keep those in the rest of your ESLint config if your project needs them.\n\n### Scope the preset to React source files\n\nIf you only want these rules on React components and hooks, wrap the preset in a config item with `files` and merge its rules.\n\n```js\nimport reactHooks from \"eslint-plugin-react-hooks\";\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  {\n    files: [\"src/**/*.{js,jsx,ts,tsx}\"],\n    plugins: reactHooks.configs.flat.recommended.plugins,\n    rules: reactHooks.configs.flat.recommended.rules,\n  },\n]);\n```\n\n### Try `recommended-latest`\n\nUse this preset only if you want the plugin's newer experimental checks.\n\n```js\nimport reactHooks from \"eslint-plugin-react-hooks\";\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  reactHooks.configs.flat[\"recommended-latest\"],\n]);\n```\n\n## Legacy Config (`.eslintrc.cjs`)\n\nIf the project still uses legacy ESLint config, enable the legacy recommended preset:\n\n```js\nmodule.exports = {\n  extends: [\"plugin:react-hooks/recommended\"],\n};\n```\n\nThe package README positions this legacy setup for ESLint below 9.0.0.\n\n## Manual Rule Configuration\n\nUse the plugin object directly if you want to choose rules yourself instead of using the preset.\n\n```js\nimport reactHooks from \"eslint-plugin-react-hooks\";\n\nexport default [\n  {\n    files: [\"**/*.{js,jsx,ts,tsx}\"],\n    plugins: {\n      \"react-hooks\": reactHooks,\n    },\n    rules: {\n      \"react-hooks/rules-of-hooks\": \"error\",\n      \"react-hooks/exhaustive-deps\": \"warn\",\n    },\n  },\n];\n```\n\nThe maintainer docs recommend using the preset configs when possible so new recommended rules are picked up automatically in future releases.\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n\n# or lint only source files\nnpx eslint \"src/**/*.{js,jsx,ts,tsx}\"\n```\n\n### Apply autofixes\n\n```bash\nnpx eslint . --fix\n```\n\nSome hook violations still require code changes even when you run ESLint with `--fix`.\n\n### Configure `exhaustive-deps` for custom hooks\n\n`react-hooks/exhaustive-deps` accepts an `additionalHooks` regex for custom hooks that expose a dependencies array.\n\n```js\nimport reactHooks from \"eslint-plugin-react-hooks\";\n\nexport default [\n  {\n    files: [\"src/**/*.{js,jsx,ts,tsx}\"],\n    plugins: {\n      \"react-hooks\": reactHooks,\n    },\n    rules: {\n      \"react-hooks/rules-of-hooks\": \"error\",\n      \"react-hooks/exhaustive-deps\": [\n        \"warn\",\n        {\n          additionalHooks: \"(useDebouncedEffect|useTrackedEffect)\",\n        },\n      ],\n    },\n  },\n];\n```\n\nThe maintainer README recommends using `additionalHooks` sparingly and preferring custom hooks with higher-level APIs when possible.\n\n## Important Pitfalls\n\n- Use flat config presets in `eslint.config.js` and the legacy `plugin:react-hooks/recommended` preset only in `.eslintrc*` files.\n- `eslint-plugin-react-hooks` does not configure JSX parsing, TypeScript parsing, or runtime globals. Add those separately in your ESLint setup.\n- `recommended-latest` is explicitly for bleeding-edge experimental compiler rules; use `recommended` if you want the stable baseline.\n- If you manually override preset rules, start from the preset's `rules` object so you do not accidentally drop newly recommended rules.\n- Only use `additionalHooks` for custom hooks that really follow the same dependency-array pattern as built-in hooks.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-react-hooks@7.0.1`.\n- The package declares `node >=18` in `engines`.\n- The published package exports `configs.flat.recommended` and `configs.flat[\"recommended-latest\"]` for flat config, plus a legacy `recommended` config for `.eslintrc*`.\n- In `7.0.1`, `recommended-latest` adds `react-hooks/void-use-memo` on top of the `recommended` rule set.\n\n## Official Sources\n\n- https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks\n- https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/README.md\n- https://react.dev/reference/eslint-plugin-react-hooks\n- https://react.dev/reference/rules/rules-of-hooks\n- https://www.npmjs.com/package/eslint-plugin-react-hooks\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-security/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-security\ndescription: \"ESLint security-focused rules for JavaScript projects, including flat config setup, legacy config, targeted rule overrides, and common lint workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,security,linting,javascript,node,npm\"\n---\n\n# eslint-plugin-security\n\n`eslint-plugin-security` adds security-oriented lint rules to ESLint. It has no runtime client, API keys, or environment variables. Install it as a local development dependency and enable it through your ESLint config.\n\n## Install\n\n`eslint-plugin-security` runs inside ESLint, so keep both packages in `devDependencies`:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-security @eslint/js\nnpx eslint --version\n```\n\nNo authentication or environment variables are required.\n\n## Flat config (`eslint.config.js`)\n\nFor modern ESLint setups, import the plugin and spread its recommended flat config into a file-matched block:\n\n```js\nimport js from \"@eslint/js\";\nimport security from \"eslint-plugin-security\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    ...security.configs.recommended,\n  },\n];\n```\n\nIf you need to tune the preset, merge the exported rules and override specific ones:\n\n```js\nimport js from \"@eslint/js\";\nimport security from \"eslint-plugin-security\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    ...security.configs.recommended,\n    rules: {\n      ...security.configs.recommended.rules,\n      \"security/detect-object-injection\": \"off\",\n      \"security/detect-non-literal-fs-filename\": \"warn\",\n    },\n  },\n];\n```\n\n## Legacy config (`.eslintrc.json`)\n\nIf your repo still uses legacy config files, extend the legacy preset:\n\n```json\n{\n  \"extends\": [\"plugin:security/recommended-legacy\"]\n}\n```\n\nOr enable the plugin and choose rules manually:\n\n```json\n{\n  \"plugins\": [\"security\"],\n  \"rules\": {\n    \"security/detect-eval-with-expression\": \"error\",\n    \"security/detect-non-literal-require\": \"warn\",\n    \"security/detect-object-injection\": \"warn\"\n  }\n}\n```\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n```\n\nOr focus on JavaScript files:\n\n```bash\nnpx eslint \"src/**/*.{js,mjs,cjs}\"\n```\n\n### Add project scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n`eslint-plugin-security` mostly reports suspicious code patterns instead of rewriting them, so `--fix` is useful for your broader ESLint setup but usually does not resolve these findings on its own.\n\n### Relax noisy rules by folder\n\nSecurity rules are often useful in application code but noisy in test fixtures, migration scripts, or generated code. Use overrides instead of removing the whole preset:\n\n```js\nimport js from \"@eslint/js\";\nimport security from \"eslint-plugin-security\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"src/**/*.{js,mjs,cjs}\"],\n    ...security.configs.recommended,\n  },\n  {\n    files: [\"test/**\", \"scripts/**\", \"fixtures/**\"],\n    rules: {\n      \"security/detect-object-injection\": \"off\",\n      \"security/detect-non-literal-fs-filename\": \"off\",\n      \"security/detect-non-literal-require\": \"off\",\n    },\n  },\n];\n```\n\n### Start with a small manual rule set\n\nIf the full preset is too noisy for an existing codebase, enable a few rules first and expand later:\n\n```js\nimport js from \"@eslint/js\";\nimport security from \"eslint-plugin-security\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    plugins: {\n      security,\n    },\n    rules: {\n      \"security/detect-eval-with-expression\": \"error\",\n      \"security/detect-child-process\": \"warn\",\n      \"security/detect-non-literal-fs-filename\": \"warn\",\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- No environment variables, tokens, or runtime initialization are required; all setup happens in ESLint config.\n- Keep the plugin installed locally in the project. ESLint plugin resolution is most reliable when `eslint` and `eslint-plugin-security` are both local `devDependencies`.\n- The recommended preset is a config object. In flat config, use `security.configs.recommended`; in legacy config, extend `plugin:security/recommended-legacy`.\n- Many rules are heuristic checks for suspicious patterns. Review findings before treating them as confirmed vulnerabilities, and use targeted overrides for folders where dynamic access patterns are expected.\n- This plugin adds security-focused lint checks; it does not replace dependency scanning, code review, or framework-specific security guidance.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-security@4.0.0`.\n- Version `4.0.0` documents both a flat-config preset exposed from the package export and a legacy preset string for `.eslintrc` users.\n- For new projects, prefer ESLint flat config in `eslint.config.js` or `eslint.config.mjs`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/eslint-community/eslint-plugin-security\n- Package README: https://github.com/eslint-community/eslint-plugin-security/blob/main/README.md\n- npm package page: https://www.npmjs.com/package/eslint-plugin-security\n- ESLint flat config docs: https://eslint.org/docs/latest/use/configure/configuration-files\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-simple-import-sort/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-simple-import-sort\ndescription: \"ESLint plugin for autofixing import and export ordering with configurable import groups.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,imports,sorting,javascript,linting,npm\"\n---\n\n# eslint-plugin-simple-import-sort\n\n`eslint-plugin-simple-import-sort` adds ESLint autofix rules for sorting `import` and `export` statements. It has no runtime client, no authentication step, and no environment variables. You install it as a dev dependency, register it in ESLint, and run ESLint with `--fix` when you want files rewritten.\n\n## Install\n\nInstall ESLint and the plugin as development dependencies:\n\n```bash\nnpm install --save-dev eslint eslint-plugin-simple-import-sort\n```\n\n## Flat config (`eslint.config.js`)\n\nUse this with modern ESLint setups:\n\n```js\nimport simpleImportSort from \"eslint-plugin-simple-import-sort\";\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs,jsx}\"],\n    languageOptions: {\n      ecmaVersion: \"latest\",\n      sourceType: \"module\",\n    },\n    plugins: {\n      \"simple-import-sort\": simpleImportSort,\n    },\n    rules: {\n      \"simple-import-sort/imports\": \"error\",\n      \"simple-import-sort/exports\": \"error\",\n    },\n  },\n];\n```\n\nThe `imports` rule sorts `import` declarations. The `exports` rule sorts `export` declarations.\n\n## Legacy config (`.eslintrc.json`)\n\nIf your project still uses legacy ESLint config files, enable the same two rules there:\n\n```json\n{\n  \"plugins\": [\"simple-import-sort\"],\n  \"rules\": {\n    \"simple-import-sort/imports\": \"error\",\n    \"simple-import-sort/exports\": \"error\"\n  }\n}\n```\n\n## Common workflows\n\n### Sort imports and exports with ESLint autofix\n\nRun ESLint with `--fix` to apply the plugin's reordering:\n\n```bash\nnpx eslint . --fix\n```\n\nWithout `--fix`, ESLint reports ordering errors but does not rewrite the file.\n\n### Add package scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n### Customize import groups\n\nThe `imports` rule accepts a `groups` option. Each inner array is one group, and ESLint inserts a blank line between groups after autofix.\n\n```js\nimport simpleImportSort from \"eslint-plugin-simple-import-sort\";\n\nexport default [\n  {\n    plugins: {\n      \"simple-import-sort\": simpleImportSort,\n    },\n    rules: {\n      \"simple-import-sort/imports\": [\n        \"error\",\n        {\n          groups: [\n            [\"^\\\\u0000\"],\n            [\"^node:\"],\n            [\"^react$\", \"^@?\\\\w\"],\n            [\"^@/\"],\n            [\"^\\\\.\"],\n          ],\n        },\n      ],\n      \"simple-import-sort/exports\": \"error\",\n    },\n  },\n];\n```\n\nIn this example:\n\n- `^\\u0000` keeps side-effect imports together.\n- `^node:` groups Node.js built-in modules imported with the `node:` prefix.\n- `^react$` and `^@?\\w` keep package imports together, with `react` first.\n- `^@/` matches a common project alias.\n- `^\\.` keeps relative imports in their own group.\n\n## Important pitfalls\n\n- Do not enable other rules that reorder entire `import` declarations at the same time unless you have intentionally limited them to non-overlapping behavior. In particular, watch for conflicts with ESLint's core `sort-imports` rule or `import/order` from `eslint-plugin-import`.\n- The plugin only sorts `import` and `export` syntax. It does not resolve modules, remove unused imports, or enforce dependency boundaries.\n- When you provide a custom `groups` array, you replace the default grouping logic for the `imports` rule. Keep explicit patterns for side-effect imports and built-ins if you still want them separated.\n- CommonJS `require()` calls are outside these two rules. If you need ordering checks for `require`, use other ESLint rules for that code path.\n\n## Minimal commands\n\n```bash\n# install\nnpm install --save-dev eslint eslint-plugin-simple-import-sort\n\n# report ordering issues\nnpx eslint .\n\n# rewrite files with sorted imports/exports\nnpx eslint . --fix\n```\n\n## Version-sensitive notes\n\n- This guide targets `eslint-plugin-simple-import-sort@12.1.1`.\n- Use the flat-config example when your repo has `eslint.config.js`. Use the legacy example only for projects that still rely on `.eslintrc*` files.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-sonarjs/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-sonarjs\ndescription: \"ESLint plugin for SonarJS rules, including flat config setup, legacy config, targeted rule overrides, and common lint workflows.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,sonarjs,linting,javascript,node,npm\"\n---\n\n# eslint-plugin-sonarjs\n\n`eslint-plugin-sonarjs` adds SonarJS rules to ESLint for maintainability and bug-prone code patterns. It has no runtime client, no authentication step, and no environment variables. Install it as a local development dependency and enable it in your ESLint config.\n\n## Install\n\nInstall ESLint, the core flat-config package, and the plugin in `devDependencies`:\n\n```bash\nnpm install --save-dev eslint @eslint/js eslint-plugin-sonarjs\nnpx eslint --version\n```\n\nNo environment variables or API keys are required.\n\n## Flat config (`eslint.config.mjs`)\n\nIf your project is not already using ESM, prefer `eslint.config.mjs` for `import` syntax. Enable the plugin's recommended config alongside ESLint's core recommended rules:\n\n```js\nimport js from \"@eslint/js\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    ...sonarjs.configs.recommended,\n  },\n];\n```\n\nIf you want the recommended baseline but need a local override, merge the exported rules and change only the rules you need:\n\n```js\nimport js from \"@eslint/js\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    ...sonarjs.configs.recommended,\n    rules: {\n      ...sonarjs.configs.recommended.rules,\n      \"sonarjs/no-nested-conditional\": \"warn\",\n    },\n  },\n];\n```\n\n## Legacy config (`.eslintrc.json`)\n\nIf your repo still uses legacy ESLint config files, extend the legacy preset:\n\n```json\n{\n  \"extends\": [\"plugin:sonarjs/recommended-legacy\"]\n}\n```\n\nOr register the plugin and enable only the rules you want:\n\n```json\n{\n  \"plugins\": [\"sonarjs\"],\n  \"rules\": {\n    \"sonarjs/no-nested-conditional\": \"warn\"\n  }\n}\n```\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n```\n\nOr lint only JavaScript sources:\n\n```bash\nnpx eslint \"src/**/*.{js,mjs,cjs}\"\n```\n\n### Add package scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n`--fix` is still useful for the rest of your ESLint stack, but SonarJS rules are primarily diagnostic checks rather than large-scale code rewriters.\n\n### Scope SonarJS rules to application code\n\nIf test fixtures, generated files, or scripts are noisier than the main source tree, keep the recommended preset on application code and add targeted overrides for the rest:\n\n```js\nimport js from \"@eslint/js\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"src/**/*.{js,mjs,cjs}\"],\n    ...sonarjs.configs.recommended,\n  },\n  {\n    files: [\"test/**\", \"fixtures/**\", \"scripts/**\"],\n    rules: {\n      \"sonarjs/no-nested-conditional\": \"off\",\n    },\n  },\n];\n```\n\n### Start with a manual rule subset\n\nIf you do not want the whole recommended preset, register the plugin directly and enable only the rules you are ready to enforce:\n\n```js\nimport js from \"@eslint/js\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    plugins: {\n      sonarjs,\n    },\n    rules: {\n      \"sonarjs/no-nested-conditional\": \"warn\",\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- No tokens, environment variables, or runtime initialization are required; all setup happens in ESLint config.\n- Keep `eslint`, `@eslint/js`, and `eslint-plugin-sonarjs` installed locally in the project so ESLint resolves the plugin consistently.\n- For modern ESLint, use the exported flat config from `sonarjs.configs.recommended`. If your repo still uses `.eslintrc*`, use the legacy preset string instead.\n- Prefer targeted rule overrides for tests, fixtures, and generated files instead of removing SonarJS checks from the entire project.\n- SonarJS runs as lint-time analysis only. It does not replace your test suite, type checks, or framework-specific validation.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-sonarjs@4.0.2`.\n- For new projects, prefer flat config in `eslint.config.js` or `eslint.config.mjs`.\n- Keep the legacy preset only for repositories that still rely on `.eslintrc*` files.\n\n## Official Sources\n\n- GitHub repository: https://github.com/SonarSource/eslint-plugin-sonarjs\n- Package README: https://github.com/SonarSource/eslint-plugin-sonarjs#readme\n- npm package page: https://www.npmjs.com/package/eslint-plugin-sonarjs\n- ESLint flat config docs: https://eslint.org/docs/latest/use/configure/configuration-files\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-storybook/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-storybook\ndescription: \"ESLint rules for Storybook story files, including flat config and legacy config setup for JavaScript projects.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.2.17\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,storybook,javascript,linting,stories,ui,npm\"\n---\n\n# eslint-plugin-storybook JavaScript Guide\n\n## Golden Rule\n\nUse `eslint-plugin-storybook` only in ESLint configuration. It has no runtime client, no authentication, and no environment variables.\n\nInstall it alongside `eslint`, then apply the Storybook preset to your story files or enable specific `storybook/*` rules yourself.\n\n## Install\n\n```bash\nnpm install -D eslint eslint-plugin-storybook\nnpx eslint --version\n```\n\nIf the repo is not already using ESM, prefer `eslint.config.mjs` for flat config. If `package.json` already sets `\"type\": \"module\"`, `eslint.config.js` also works.\n\n## Flat Config (`eslint.config.mjs`)\n\nFor modern ESLint setup, spread the plugin's flat recommended config into your exported config array.\n\n```javascript\nimport storybook from \"eslint-plugin-storybook\";\n\nexport default [\n  ...storybook.configs[\"flat/recommended\"],\n];\n```\n\nThe shared preset is the simplest way to lint Storybook story files with the plugin's recommended `storybook/*` rules.\n\n### Add project-specific Storybook rules\n\nAdd a later config block when you want stricter Storybook rules for your own stories.\n\n```javascript\nimport storybook from \"eslint-plugin-storybook\";\n\nexport default [\n  ...storybook.configs[\"flat/recommended\"],\n  {\n    files: [\n      \"**/*.stories.{js,jsx,ts,tsx}\",\n      \"**/*.story.{js,jsx,ts,tsx}\",\n    ],\n    rules: {\n      \"storybook/default-exports\": \"error\",\n      \"storybook/story-exports\": \"error\",\n      \"storybook/no-redundant-story-name\": \"warn\",\n    },\n  },\n];\n```\n\n### Register the plugin manually\n\nUse manual registration when you do not want the shared preset.\n\n```javascript\nimport storybook from \"eslint-plugin-storybook\";\n\nexport default [\n  {\n    files: [\n      \"**/*.stories.{js,jsx,ts,tsx}\",\n      \"**/*.story.{js,jsx,ts,tsx}\",\n    ],\n    plugins: {\n      storybook,\n    },\n    rules: {\n      \"storybook/default-exports\": \"error\",\n      \"storybook/story-exports\": \"error\",\n      \"storybook/no-redundant-story-name\": \"warn\",\n    },\n  },\n];\n```\n\nUse manual setup when you want to opt into only a small subset of Storybook rules instead of the full recommended preset.\n\n## Legacy Config (`.eslintrc.cjs`)\n\nIf the repo still uses legacy ESLint config, extend the plugin's recommended preset.\n\n```javascript\nmodule.exports = {\n  extends: [\"plugin:storybook/recommended\"],\n};\n```\n\n### Manual legacy setup\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.stories.{js,jsx,ts,tsx}\", \"**/*.story.{js,jsx,ts,tsx}\"],\n      plugins: [\"storybook\"],\n      rules: {\n        \"storybook/default-exports\": \"error\",\n        \"storybook/story-exports\": \"error\",\n      },\n    },\n  ],\n};\n```\n\n## Common Workflows\n\n### Lint all Storybook stories\n\n```bash\nnpx eslint .\n```\n\nOr target story files directly:\n\n```bash\nnpx eslint \"src/**/*.stories.{js,jsx,ts,tsx}\" \"src/**/*.story.{js,jsx,ts,tsx}\"\n```\n\nRule IDs from this package use the `storybook/` prefix.\n\n### Restrict Storybook linting to one package in a monorepo\n\nThe flat preset can live beside other ESLint config blocks. Add a follow-up block when only one workspace contains Storybook stories.\n\n```javascript\nimport storybook from \"eslint-plugin-storybook\";\n\nexport default [\n  ...storybook.configs[\"flat/recommended\"],\n  {\n    files: [\"packages/ui/**/*.stories.{js,jsx,ts,tsx}\"],\n    rules: {\n      \"storybook/no-redundant-story-name\": \"warn\",\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- `storybook.configs[\"flat/recommended\"]` is meant to be spread into the top-level config array, not inserted as a nested object.\n- Use `plugin:storybook/recommended` only in legacy `.eslintrc*` files. Use `storybook.configs[\"flat/recommended\"]` only in flat config.\n- Keep Storybook rules scoped to story files unless you intentionally want them on other files.\n- This plugin is aimed at Storybook story source files. Keep separate linting or validation for non-story content.\n- When you add manual rules, use the `storybook/` rule prefix.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-storybook@10.2.17`.\n- The current package documentation publishes a flat-config preset exposed as `storybook.configs[\"flat/recommended\"]` and a legacy preset exposed as `plugin:storybook/recommended`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/storybookjs/eslint-plugin-storybook\n- GitHub README: https://github.com/storybookjs/eslint-plugin-storybook#readme\n- npm package page: https://www.npmjs.com/package/eslint-plugin-storybook\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-tailwindcss/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-tailwindcss\ndescription: \"ESLint plugin for linting Tailwind CSS class usage, ordering, and conflicting utilities in JavaScript projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.18.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,tailwindcss,linting,javascript,css,npm\"\n---\n\n# eslint-plugin-tailwindcss JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint-plugin-tailwindcss` alongside `eslint` and your project's `tailwindcss` package, then wire it into your ESLint config. This package is lint configuration only: it does not use API keys, accounts, authentication, environment variables, or runtime client initialization.\n\nFor most projects, start from the plugin's recommended preset and then add shared `settings.tailwindcss` values for any custom class-building helpers or a non-default Tailwind config path.\n\n## Install\n\nFor a modern flat-config setup:\n\n```bash\nnpm install -D eslint @eslint/js tailwindcss eslint-plugin-tailwindcss\n```\n\nFor a legacy `.eslintrc*` setup:\n\n```bash\nnpm install -D eslint tailwindcss eslint-plugin-tailwindcss\n```\n\n## Flat Config (`eslint.config.js`)\n\n`eslint-plugin-tailwindcss@3.18.2` exposes a flat recommended preset at `tailwind.configs['flat/recommended']`.\n\nUse that first, then add project-specific settings and rule overrides:\n\n```js\nimport js from '@eslint/js';\nimport tailwind from 'eslint-plugin-tailwindcss';\n\nexport default [\n  js.configs.recommended,\n  ...tailwind.configs['flat/recommended'],\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    settings: {\n      tailwindcss: {\n        callees: ['clsx', 'cn'],\n        config: 'tailwind.config.js',\n      },\n    },\n    rules: {\n      'tailwindcss/no-custom-classname': 'off',\n    },\n  },\n];\n```\n\nUse `settings.tailwindcss.callees` when your codebase builds class lists through helpers such as `clsx`, `classnames`, or a local `cn()` wrapper.\n\nIf your Tailwind config is not in the project root, point the plugin at the real file:\n\n```js\nexport default [\n  ...tailwind.configs['flat/recommended'],\n  {\n    settings: {\n      tailwindcss: {\n        config: 'packages/web/tailwind.config.js',\n      },\n    },\n  },\n];\n```\n\n## Legacy Config (`.eslintrc.json`)\n\nUse the legacy preset name when your repo still relies on `.eslintrc` files:\n\n```json\n{\n  \"extends\": [\"plugin:tailwindcss/recommended\"],\n  \"settings\": {\n    \"tailwindcss\": {\n      \"callees\": [\"clsx\", \"cn\"],\n      \"config\": \"tailwind.config.js\"\n    }\n  }\n}\n```\n\nIf you extend `plugin:tailwindcss/recommended`, you do not need to repeat the plugin in a separate `plugins` array unless you are composing a fully manual config.\n\n## Manual Rule Setup\n\nUse a manual setup when you only want a small rule set instead of the full recommended preset:\n\n```js\nimport tailwind from 'eslint-plugin-tailwindcss';\n\nexport default [\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    plugins: {\n      tailwindcss: tailwind,\n    },\n    settings: {\n      tailwindcss: {\n        callees: ['clsx', 'cn'],\n        config: 'tailwind.config.js',\n      },\n    },\n    rules: {\n      'tailwindcss/classnames-order': 'warn',\n      'tailwindcss/no-contradicting-classname': 'error',\n      'tailwindcss/no-custom-classname': 'off',\n    },\n  },\n];\n```\n\nThis keeps the two most common Tailwind-specific checks enabled:\n\n- `tailwindcss/classnames-order` for canonical class ordering\n- `tailwindcss/no-contradicting-classname` for conflicting utility combinations\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n```\n\nOr scope linting to frontend source files:\n\n```bash\nnpx eslint \"src/**/*.{js,jsx,ts,tsx}\"\n```\n\n### Apply autofixes for class ordering\n\n```bash\nnpx eslint . --fix\n```\n\nUse this after enabling `tailwindcss/classnames-order` directly or via the recommended preset.\n\n### Lint class helpers such as `clsx()` or `cn()`\n\nIf Tailwind class strings live inside helper calls, add those helper names under `settings.tailwindcss.callees`.\n\n```js\nsettings: {\n  tailwindcss: {\n    callees: ['clsx', 'cn', 'classnames'],\n  },\n}\n```\n\nWithout that setting, the plugin may miss class lists constructed through your wrapper functions.\n\n### Mix Tailwind with custom CSS intentionally\n\nIf your app uses authored CSS class names alongside Tailwind utilities, `tailwindcss/no-custom-classname` may be too strict.\n\nDisable it explicitly when that matches your codebase:\n\n```js\nrules: {\n  'tailwindcss/no-custom-classname': 'off',\n}\n```\n\n## Important Pitfalls\n\n- `tailwind.configs['flat/recommended']` is a flat-config array. Spread it into `export default [...]` instead of nesting it as a single object.\n- Install `tailwindcss` locally in the same project. The plugin needs your Tailwind package and configuration to lint accurately.\n- Set `settings.tailwindcss.config` when the Tailwind config file is not at the project root.\n- Add every class helper function you use to `settings.tailwindcss.callees`, or the plugin can miss class strings built outside raw `className=\"...\"` attributes.\n- Keep `tailwindcss/no-custom-classname` only if your project wants to reject non-Tailwind class names; otherwise disable it or replace it with a narrower custom policy.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-testing-library/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-testing-library\ndescription: \"ESLint plugin for Testing Library that enforces recommended query, async, and DOM-testing patterns across DOM, React, Angular, Vue, Svelte, and Marko tests.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,testing-library,linting,javascript,testing,react,dom\"\n---\n\n# eslint-plugin-testing-library JavaScript Guide\n\n## Golden Rule\n\nApply `eslint-plugin-testing-library` only to test files and choose the preset that matches the Testing Library package you actually use.\n\nFor ESLint 9 flat config, use `testingLibrary.configs[\"flat/<framework>\"]`. For legacy `.eslintrc*` config, use `plugin:testing-library/<framework>`.\n\n## Install\n\nInstall the plugin alongside ESLint and the Testing Library package your tests use:\n\n```bash\nnpm install -D eslint eslint-plugin-testing-library @testing-library/react\n```\n\nFor DOM-only tests, install `@testing-library/dom` instead:\n\n```bash\nnpm install -D eslint eslint-plugin-testing-library @testing-library/dom\n```\n\nThis plugin does not require environment variables, credentials, or runtime client initialization.\n\n## Flat Config (`eslint.config.js`)\n\nUse the `flat/*` preset that matches your framework. Scope it to test files so application code is not linted as Testing Library code.\n\n### React Testing Library\n\n```javascript\nimport testingLibrary from \"eslint-plugin-testing-library\";\n\nexport default [\n  {\n    files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n    ...testingLibrary.configs[\"flat/react\"],\n  },\n];\n```\n\n### DOM Testing Library\n\n```javascript\nimport testingLibrary from \"eslint-plugin-testing-library\";\n\nexport default [\n  {\n    files: [\"**/*.{test,spec}.{js,ts}\"],\n    ...testingLibrary.configs[\"flat/dom\"],\n  },\n];\n```\n\nFramework-specific flat presets are published for `dom`, `react`, `angular`, `vue`, `svelte`, and `marko`.\n\n## Legacy Config (`.eslintrc.cjs`)\n\nIf the repo still uses legacy ESLint config, use the `plugin:testing-library/<framework>` preset inside an override for tests.\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n      extends: [\"plugin:testing-library/react\"],\n    },\n  ],\n};\n```\n\n## Common Workflows\n\n### Run ESLint against tests\n\n```bash\nnpx eslint .\n\n# or target a specific test file\nnpx eslint src/components/LoginForm.test.jsx\n```\n\nRule IDs from this plugin use the `testing-library/` prefix.\n\n### Add project-specific rules on top of the shared preset\n\nUse the shared preset as the base, then merge in rule overrides.\n\n```javascript\nimport testingLibrary from \"eslint-plugin-testing-library\";\n\nconst reactTestingLibrary = testingLibrary.configs[\"flat/react\"];\n\nexport default [\n  {\n    files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n    ...reactTestingLibrary,\n    rules: {\n      ...reactTestingLibrary.rules,\n      \"testing-library/no-debugging-utils\": \"warn\",\n      \"testing-library/prefer-screen-queries\": \"error\",\n      \"testing-library/await-async-queries\": \"error\",\n    },\n  },\n];\n```\n\n### Lint tests that use a local `test-utils` module\n\nIf your project re-exports `render` and helpers from a local module, configure Testing Library shared settings so the plugin still recognizes those utilities.\n\n```javascript\nimport testingLibrary from \"eslint-plugin-testing-library\";\n\nexport default [\n  {\n    files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n    ...testingLibrary.configs[\"flat/react\"],\n    settings: {\n      \"testing-library/utils-module\": \"test-utils\",\n      \"testing-library/custom-renders\": [\"renderWithProviders\"],\n    },\n  },\n];\n```\n\nThat setup is useful for test helpers like this:\n\n```javascript\n// test-utils.js\nimport { render, screen } from \"@testing-library/react\";\n\nexport { render, screen };\n\nexport function renderWithProviders(ui, options) {\n  return render(ui, options);\n}\n```\n\n### Use different presets in a monorepo\n\nIf different packages use different Testing Library integrations, configure each test tree separately.\n\n```javascript\nimport testingLibrary from \"eslint-plugin-testing-library\";\n\nexport default [\n  {\n    files: [\"packages/web/**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n    ...testingLibrary.configs[\"flat/react\"],\n  },\n  {\n    files: [\"packages/dom-tests/**/*.{test,spec}.{js,ts}\"],\n    ...testingLibrary.configs[\"flat/dom\"],\n  },\n];\n```\n\n## Important Pitfalls\n\n- Do not apply the plugin globally to all source files. Restrict it to tests and test utility modules.\n- Match the preset to the Testing Library package in use. A React repo should usually use `react`, not plain `dom`.\n- Use `flat/*` presets only in `eslint.config.js` flat config. Use `plugin:testing-library/*` only in legacy `.eslintrc*` files.\n- If you re-export Testing Library helpers from a local module, configure `settings[\"testing-library/utils-module\"]` and any custom render names, or the plugin may miss those helpers.\n- Async Testing Library APIs should generally be awaited, while sync queries and sync events should not be awaited. The plugin includes rules for both sides of that mistake.\n- If you tune rules manually, keep the shared preset rules and merge your overrides on top instead of replacing the whole `rules` object.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-testing-library@7.16.0`.\n- The package publishes both flat-config presets (`flat/react`, `flat/dom`, and the other framework variants) and legacy shareable configs (`plugin:testing-library/react`, `plugin:testing-library/dom`, and the other framework variants).\n- Framework presets are available for `dom`, `react`, `angular`, `vue`, `svelte`, and `marko`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/testing-library/eslint-plugin-testing-library\n- GitHub README: https://github.com/testing-library/eslint-plugin-testing-library#readme\n- npm package page: https://www.npmjs.com/package/eslint-plugin-testing-library\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-unicorn/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-unicorn\ndescription: \"ESLint plugin with Unicorn rules for safer, more consistent JavaScript code in flat-config projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"63.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,unicorn,javascript,linting,node,npm\"\n---\n\n# eslint-plugin-unicorn JavaScript Guide\n\n## Golden Rule\n\nInstall `eslint-plugin-unicorn` locally and configure it through your ESLint flat config. This package is lint configuration only: it does not need API keys, authentication, accounts, or runtime environment variables.\n\nIn most projects, start from the plugin's recommended config and then turn off the rules that do not fit your codebase.\n\n## Install\n\nFor a typical JavaScript project using ESLint flat config:\n\n```bash\nnpm install -D eslint @eslint/js eslint-plugin-unicorn globals\nnpx eslint --version\n```\n\nIf your project is not already using ESM for config files, use `eslint.config.mjs` for `import`-based examples.\n\n## Flat Config (`eslint.config.js`)\n\n### Start from the recommended preset\n\nUse the plugin's recommended config, then merge in the globals for your runtime and override the rules you do not want.\n\n```js\nimport js from \"@eslint/js\";\nimport unicorn from \"eslint-plugin-unicorn\";\nimport globals from \"globals\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    ...unicorn.configs.recommended,\n    languageOptions: {\n      ...unicorn.configs.recommended.languageOptions,\n      globals: {\n        ...globals.builtin,\n        ...globals.node,\n      },\n    },\n    rules: {\n      ...unicorn.configs.recommended.rules,\n      \"unicorn/no-null\": \"off\",\n      \"unicorn/no-array-for-each\": \"off\",\n      \"unicorn/prevent-abbreviations\": \"off\",\n    },\n  },\n];\n```\n\nFor browser code, swap `globals.node` for `globals.browser`:\n\n```js\nglobals: {\n  ...globals.builtin,\n  ...globals.browser,\n}\n```\n\nThe important distinction is that `unicorn.configs.recommended` is a shareable config object. Use the plugin object directly only when you want to choose rules yourself.\n\n### Configure the plugin manually\n\nUse this pattern when you want a small custom Unicorn rule set instead of the full preset:\n\n```js\nimport unicorn from \"eslint-plugin-unicorn\";\nimport globals from \"globals\";\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs}\"],\n    plugins: {\n      unicorn,\n    },\n    languageOptions: {\n      ecmaVersion: \"latest\",\n      sourceType: \"module\",\n      globals: {\n        ...globals.builtin,\n        ...globals.node,\n      },\n    },\n    rules: {\n      \"unicorn/better-regex\": \"error\",\n      \"unicorn/error-message\": \"error\",\n      \"unicorn/prefer-node-protocol\": \"error\",\n    },\n  },\n];\n```\n\nUse `sourceType: \"commonjs\"` in a separate config block if part of the repo still runs as CommonJS.\n\n## Common Workflows\n\n### Lint the project\n\n```bash\nnpx eslint .\n```\n\nOr lint only JavaScript source files:\n\n```bash\nnpx eslint \"src/**/*.{js,mjs,cjs}\"\n```\n\n### Autofix Unicorn rules that support fixes\n\nMany Unicorn rules are fixable. Run ESLint with `--fix` to apply those changes in place:\n\n```bash\nnpx eslint . --fix\n```\n\nAdd the usual scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\"\n  }\n}\n```\n\n### Override opinionated rules by file pattern\n\nSome Unicorn rules are useful for application code but noisy in test files, scripts, or migration folders. Use flat-config overrides to narrow them:\n\n```js\nimport js from \"@eslint/js\";\nimport unicorn from \"eslint-plugin-unicorn\";\nimport globals from \"globals\";\n\nexport default [\n  js.configs.recommended,\n  {\n    files: [\"src/**/*.{js,mjs,cjs}\"],\n    ...unicorn.configs.recommended,\n    languageOptions: {\n      ...unicorn.configs.recommended.languageOptions,\n      globals: {\n        ...globals.builtin,\n        ...globals.node,\n      },\n    },\n  },\n  {\n    files: [\"test/**\", \"scripts/**\"],\n    rules: {\n      \"unicorn/no-process-exit\": \"off\",\n      \"unicorn/prevent-abbreviations\": \"off\",\n    },\n  },\n];\n```\n\n## Important Pitfalls\n\n- Keep the plugin installed locally in the project. Plugin-based ESLint setups are not a good fit for global-only installs.\n- Add the right runtime globals yourself. If you omit `globals.node` or `globals.browser`, rules can report false positives for the environment your code actually runs in.\n- Treat `unicorn.configs.recommended` as a config object, not as `plugins: { unicorn }`.\n- Start with a small number of overrides instead of disabling the plugin wholesale. `unicorn/prevent-abbreviations`, `unicorn/no-null`, and `unicorn/no-array-for-each` are common first candidates when adopting the recommended preset.\n- If your repo mixes ESM and CommonJS, use separate `files` blocks so `sourceType` and any module-specific rules match the code they lint.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-unicorn@63.0.0`.\n- Use the modern ESLint flat-config flow for new setups, with the project config in `eslint.config.js` or `eslint.config.mjs`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/sindresorhus/eslint-plugin-unicorn\n- Package README: https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/readme.md\n- Rule documentation: https://github.com/sindresorhus/eslint-plugin-unicorn/tree/main/docs/rules\n- npm package page: https://www.npmjs.com/package/eslint-plugin-unicorn\n- ESLint flat config docs: https://eslint.org/docs/latest/use/configure/configuration-files\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-unused-imports/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-unused-imports\ndescription: \"ESLint plugin that removes unused imports and reports unused variables through ESLint rules\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.4.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,linting,imports,javascript,typescript\"\n---\n\n# eslint-plugin-unused-imports\n\n`eslint-plugin-unused-imports` adds two ESLint rules:\n\n- `unused-imports/no-unused-imports` removes unused imports when you run ESLint with `--fix`\n- `unused-imports/no-unused-vars` reports unused variables and arguments without re-flagging imports\n\nThis package has no runtime client, no environment variables, and no authentication step. The only setup is in your ESLint config.\n\n## Install\n\nFor a JavaScript project using ESLint flat config:\n\n```bash\nnpm install --save-dev eslint @eslint/js eslint-plugin-unused-imports\n```\n\nFor TypeScript, install the TypeScript ESLint parser and plugin too:\n\n```bash\nnpm install --save-dev eslint @eslint/js typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-unused-imports\n```\n\n## Flat config (`eslint.config.js`)\n\n### JavaScript\n\nDisable ESLint's built-in `no-unused-vars` rule and replace it with the plugin rules.\n\n```js\nimport js from '@eslint/js';\nimport unusedImports from 'eslint-plugin-unused-imports';\n\nexport default [\n  js.configs.recommended,\n  {\n    files: ['**/*.{js,mjs,cjs}'],\n    plugins: {\n      'unused-imports': unusedImports,\n    },\n    rules: {\n      'no-unused-vars': 'off',\n      'unused-imports/no-unused-imports': 'error',\n      'unused-imports/no-unused-vars': [\n        'warn',\n        {\n          vars: 'all',\n          varsIgnorePattern: '^_',\n          args: 'after-used',\n          argsIgnorePattern: '^_',\n        },\n      ],\n    },\n  },\n];\n```\n\n### TypeScript\n\nIf you already use `@typescript-eslint/no-unused-vars`, turn it off before enabling the `unused-imports` replacement rule.\n\n```js\nimport js from '@eslint/js';\nimport tsParser from '@typescript-eslint/parser';\nimport tseslint from '@typescript-eslint/eslint-plugin';\nimport unusedImports from 'eslint-plugin-unused-imports';\n\nexport default [\n  js.configs.recommended,\n  {\n    files: ['**/*.{ts,tsx}'],\n    languageOptions: {\n      parser: tsParser,\n    },\n    plugins: {\n      '@typescript-eslint': tseslint,\n      'unused-imports': unusedImports,\n    },\n    rules: {\n      'no-unused-vars': 'off',\n      '@typescript-eslint/no-unused-vars': 'off',\n      'unused-imports/no-unused-imports': 'error',\n      'unused-imports/no-unused-vars': [\n        'warn',\n        {\n          vars: 'all',\n          varsIgnorePattern: '^_',\n          args: 'after-used',\n          argsIgnorePattern: '^_',\n        },\n      ],\n    },\n  },\n];\n```\n\n## Legacy config (`.eslintrc.cjs`)\n\nIf your project still uses legacy ESLint config files, register the plugin in `plugins` and enable the rules manually.\n\n### JavaScript\n\n```js\nmodule.exports = {\n  extends: ['eslint:recommended'],\n  plugins: ['unused-imports'],\n  rules: {\n    'no-unused-vars': 'off',\n    'unused-imports/no-unused-imports': 'error',\n    'unused-imports/no-unused-vars': [\n      'warn',\n      {\n        vars: 'all',\n        varsIgnorePattern: '^_',\n        args: 'after-used',\n        argsIgnorePattern: '^_',\n      },\n    ],\n  },\n};\n```\n\n### TypeScript\n\n```js\nmodule.exports = {\n  parser: '@typescript-eslint/parser',\n  plugins: ['@typescript-eslint', 'unused-imports'],\n  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],\n  rules: {\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': 'off',\n    'unused-imports/no-unused-imports': 'error',\n    'unused-imports/no-unused-vars': [\n      'warn',\n      {\n        vars: 'all',\n        varsIgnorePattern: '^_',\n        args: 'after-used',\n        argsIgnorePattern: '^_',\n      },\n    ],\n  },\n};\n```\n\n## Common workflows\n\n### Remove unused imports automatically\n\nRun ESLint with `--fix` to delete unused import lines and unused import specifiers.\n\n```bash\nnpx eslint . --fix\n```\n\nTo limit fixes to source files only:\n\n```bash\nnpx eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix\n```\n\n### Keep underscore-prefixed variables or parameters\n\nThe common `varsIgnorePattern` and `argsIgnorePattern` settings let you intentionally keep placeholders such as `_event` or `_unused`.\n\n```js\n'unused-imports/no-unused-vars': [\n  'warn',\n  {\n    vars: 'all',\n    varsIgnorePattern: '^_',\n    args: 'after-used',\n    argsIgnorePattern: '^_',\n  },\n],\n```\n\n### Fail CI on leftover warnings\n\nIf your CI should fail when unused variables remain after linting, run ESLint without `--fix` and promote warnings to a failing exit code.\n\n```bash\nnpx eslint . --max-warnings 0\n```\n\n## Practical notes\n\n### Turn off the original `no-unused-vars` rule\n\nDo not run `unused-imports/no-unused-vars` alongside the core `no-unused-vars` rule or `@typescript-eslint/no-unused-vars`. Leave the original rule disabled or you will get duplicate reports.\n\n### Use both rules together\n\n`unused-imports/no-unused-imports` handles imports. `unused-imports/no-unused-vars` handles local variables and function parameters. In most projects you want both rules enabled.\n\n### Keep side-effect imports as bare imports\n\nIf a module is imported only for side effects, write it as a bare import:\n\n```js\nimport './polyfills';\n```\n\nThat keeps the import intentional and avoids introducing an unused binding.\n\n## Version notes\n\nThis guide targets `eslint-plugin-unused-imports` `4.4.1`. If your project is pinned to an older ESLint major, check the maintainer README before upgrading the plugin because older plugin majors are published for older ESLint and TypeScript ESLint combinations.\n"
  },
  {
    "path": "content/eslint/docs/eslint-plugin-vitest/javascript/DOC.md",
    "content": "---\nname: eslint-plugin-vitest\ndescription: \"ESLint plugin for Vitest test files with a recommended preset and Vitest-specific rule IDs.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.5.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"eslint,vitest,testing,javascript,linting,npm\"\n---\n\n# eslint-plugin-vitest JavaScript Guide\n\n## Golden Rule\n\nApply `eslint-plugin-vitest` only to files that actually run under Vitest. Start from `plugin:vitest/recommended`, then add or override individual `vitest/*` rules for your test suite.\n\nThis package is lint configuration only. It does not use API keys, accounts, runtime environment variables, or client initialization.\n\n## Install\n\nInstall the plugin alongside ESLint, and install `vitest` if your project does not already have it:\n\n```bash\nnpm install -D eslint eslint-plugin-vitest vitest\n```\n\nIf your tests are TypeScript or JSX/TSX, keep your existing parser setup as well. This plugin adds Vitest-specific rules, but it does not replace `@typescript-eslint/parser` or other syntax-related ESLint configuration.\n\n## Legacy ESLint Config (`.eslintrc.cjs`)\n\nFor `eslint-plugin-vitest@0.5.4`, the maintainer examples use the classic ESLint config format. The safest setup is an override scoped to test files.\n\n### Recommended preset\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n      extends: [\"plugin:vitest/recommended\"],\n      env: {\n        \"vitest-globals/env\": true,\n      },\n    },\n  ],\n};\n```\n\nUse the Vitest globals environment when your tests rely on global APIs such as `describe`, `it`, `test`, `expect`, and `vi`.\n\n### Manual rule selection\n\nIf you do not want the full preset, register the plugin and choose the rules explicitly:\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n      plugins: [\"vitest\"],\n      env: {\n        \"vitest-globals/env\": true,\n      },\n      rules: {\n        \"vitest/expect-expect\": \"error\",\n        \"vitest/no-disabled-tests\": \"warn\",\n        \"vitest/no-focused-tests\": \"error\",\n      },\n    },\n  ],\n};\n```\n\nRule IDs from this package always use the `vitest/` prefix.\n\n## Test File Style\n\nIf your test files import Vitest APIs directly, ESLint already sees those bindings from the import. In that case, the globals environment is usually only needed for files that rely on global test functions.\n\n```javascript\nimport { describe, expect, it } from \"vitest\";\n\ndescribe(\"sum\", () => {\n  it(\"adds two numbers\", () => {\n    expect(1 + 1).toBe(2);\n  });\n});\n```\n\n## Common Workflows\n\n### Lint the whole project\n\n```bash\nnpx eslint .\n```\n\n### Lint only Vitest files\n\n```bash\nnpx eslint \"src/**/*.{test,spec}.{js,jsx,ts,tsx}\"\n```\n\n### Add package scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:tests\": \"eslint \\\"src/**/*.{test,spec}.{js,jsx,ts,tsx}\\\"\"\n  }\n}\n```\n\n### Override a few recommended rules\n\nKeep the recommended preset as the baseline and then add per-project rule changes inside the same override.\n\n```javascript\nmodule.exports = {\n  overrides: [\n    {\n      files: [\"**/*.{test,spec}.{js,jsx,ts,tsx}\"],\n      extends: [\"plugin:vitest/recommended\"],\n      env: {\n        \"vitest-globals/env\": true,\n      },\n      rules: {\n        \"vitest/no-disabled-tests\": \"error\",\n        \"vitest/no-focused-tests\": \"error\",\n      },\n    },\n  ],\n};\n```\n\n## Important Pitfalls\n\n- Scope the config to test files. Applying the Vitest environment to application code can accidentally allow test globals outside your test suite.\n- Keep `\"vitest-globals/env\": true` only when your tests use global Vitest APIs. If your project imports everything from `vitest`, you may not need the globals environment in every override.\n- This plugin adds test-specific lint rules, not parsing support. For TypeScript, JSX, or TSX test files, keep the parser and parser options required by the rest of your ESLint setup.\n- Use `plugin:vitest/recommended` or explicit `vitest/*` rules with the package you actually installed. Do not mix this package with docs for other Vitest ESLint packages unless you intentionally migrate.\n\n## Version-Sensitive Notes\n\n- This guide targets `eslint-plugin-vitest@0.5.4`.\n- The documented preset name is `plugin:vitest/recommended`.\n- Rule names from this package use the `vitest/` namespace, such as `vitest/expect-expect` and `vitest/no-focused-tests`.\n- The package is designed for ESLint configuration, so the main integration surface is your ESLint config file plus the standard `eslint` CLI.\n\n## Official Sources\n\n- https://github.com/veritem/eslint-plugin-vitest\n- https://github.com/veritem/eslint-plugin-vitest#readme\n- https://www.npmjs.com/package/eslint-plugin-vitest\n"
  },
  {
    "path": "content/evaluate/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hugging Face Evaluate Python package for loading metrics, comparisons, measurements, and task evaluators\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"evaluate,hugging-face,python,metrics,evaluation,ml,nlp\"\n---\n\n# Hugging Face Evaluate Python Package Guide\n\n## What It Is\n\n`evaluate` is Hugging Face's Python library for loading evaluation modules and computing metrics, comparisons, and measurements. Use it when you need reusable metrics such as accuracy or F1, batched accumulation with `add_batch()`, or task-level evaluation over `transformers` pipelines.\n\nFor current LLM-evaluation workflows, Hugging Face now points users to LightEval for newer benchmark-style and judge-style evaluation patterns. Use `evaluate` when you specifically need its metric/module API or task evaluators.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"evaluate==0.4.6\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"evaluate==0.4.6\"\npoetry add \"evaluate==0.4.6\"\n```\n\nIf you want to scaffold and publish your own evaluation module, install the template extra:\n\n```bash\npython -m pip install \"evaluate[template]==0.4.6\"\n```\n\nIf you plan to use task evaluators such as `evaluator(\"text-classification\")`, also install the runtime packages that provide the model pipeline and dataset:\n\n```bash\npython -m pip install \"transformers\" \"datasets\"\n```\n\n## Quick Sanity Check\n\n```python\nimport evaluate\n\nmetric = evaluate.load(\"accuracy\")\nresult = metric.compute(predictions=[0, 1, 1], references=[0, 1, 0])\n\nprint(result)\n```\n\nIf this succeeds, the library can download and cache evaluation modules correctly in your environment.\n\n## Core Usage\n\n### Load a metric and compute in one shot\n\n```python\nimport evaluate\n\naccuracy = evaluate.load(\"accuracy\")\n\nscores = accuracy.compute(\n    predictions=[0, 1, 1, 0],\n    references=[0, 1, 0, 0],\n)\n\nprint(scores[\"accuracy\"])\n```\n\nUse this pattern when all predictions and references already fit in memory.\n\n### Accumulate batches incrementally\n\nFor larger datasets, add batches first and compute at the end:\n\n```python\nimport evaluate\n\nf1 = evaluate.load(\"f1\")\n\nf1.add_batch(predictions=[0, 1, 1], references=[0, 1, 0])\nf1.add_batch(predictions=[1, 0], references=[1, 0])\n\nresult = f1.compute(average=\"binary\")\nprint(result)\n```\n\nThis is the main pattern to use when model inference and metric aggregation happen in separate steps.\n\n### Combine multiple metrics\n\n`evaluate.combine()` lets you compute several metrics through one object:\n\n```python\nimport evaluate\n\nmetrics = evaluate.combine([\"accuracy\", \"f1\"])\n\nresult = metrics.compute(\n    predictions=[0, 1, 1, 0],\n    references=[0, 1, 0, 0],\n)\n\nprint(result)\n```\n\nUse this when you want one consistent compute call for a standard metric bundle.\n\n### Discover available modules\n\n```python\nimport evaluate\n\nall_metrics = evaluate.list_evaluation_modules(module_type=\"metric\")\nprint(all_metrics[:10])\n```\n\nUseful module types:\n\n- `metric`: standard metrics such as accuracy, F1, BLEU, or ROUGE\n- `comparison`: side-by-side comparisons between systems or outputs\n- `measurement`: descriptive measurements over data or predictions\n\n### Evaluate a task end-to-end with a pipeline\n\nThe evaluator API is higher-level than raw metrics. It runs a `transformers` pipeline over a dataset and computes metrics for the task:\n\n```python\nfrom datasets import load_dataset\nfrom transformers import pipeline\nimport evaluate\n\ndataset = load_dataset(\"imdb\", split=\"test[:100]\")\n\nclassifier = pipeline(\n    \"text-classification\",\n    model=\"distilbert/distilbert-base-uncased-finetuned-sst-2-english\",\n)\n\ntask_evaluator = evaluate.evaluator(\"text-classification\")\nmetric = evaluate.combine([\"accuracy\", \"f1\"])\n\nresults = task_evaluator.compute(\n    model_or_pipeline=classifier,\n    data=dataset,\n    metric=metric,\n    input_column=\"text\",\n    label_column=\"label\",\n    label_mapping={\"NEGATIVE\": 0, \"POSITIVE\": 1},\n)\n\nprint(results)\n```\n\n`label_mapping` matters when pipeline outputs use string labels but your dataset labels are integers.\n\n## Configuration And Auth\n\n### Loading options that matter\n\n`evaluate.load()` has a few parameters agents should reach for first:\n\n- `module_type=` to force `metric`, `comparison`, or `measurement` when the name is ambiguous\n- `config_name=` when a metric exposes multiple configurations\n- `cache_dir=` to control where downloaded modules and intermediate data live\n- `revision=` when you need a specific Hub revision for reproducibility\n- `num_process=`, `process_id=`, and `experiment_id=` for distributed evaluation\n- `keep_in_memory=` only for non-distributed runs where local memory use is acceptable\n\nFor distributed evaluation, the docs call out that `cache_dir` must be shared across processes, and `keep_in_memory` cannot be used in that setup.\n\n### Auth and sharing custom modules\n\nBuilt-in metrics do not usually require authentication. Auth matters when you create or share your own evaluation module on the Hugging Face Hub, or when you need access to private Hub resources.\n\nThe documented setup for publishing a module is:\n\n```bash\npython -m pip install \"evaluate[template]==0.4.6\"\nhuggingface-cli login\nevaluate-cli create \"my_eval_module\"\n```\n\nIf a private or gated Hub resource is involved, make sure the active Hugging Face login context has access before debugging the metric code itself.\n\n## Common Pitfalls\n\n- The docs installation page still says Evaluate is tested on Python 3.7+, but PyPI metadata for `0.4.6` requires Python `>=3.8`. Treat PyPI as authoritative for install constraints.\n- `evaluate` computes metrics; it does not provide a model by itself. `evaluator()` still needs a `transformers` pipeline or model callable plus a dataset.\n- Metric inputs must match the metric's expected shape and label type. Classification metrics often expect numeric labels, while text-generation metrics expect strings or tokenized text.\n- `f1`, `precision`, and `recall` usually need the correct averaging mode such as `average=\"binary\"` or `average=\"macro\"`. Do not assume the default matches your label shape.\n- Distributed runs need a shared `cache_dir` and consistent `experiment_id`; otherwise aggregation can fail or hang.\n- If you need reproducible behavior for Hub-hosted modules, pin `revision=` instead of relying on whatever the default branch serves later.\n- For newer LLM-eval workflows, check whether LightEval is the intended upstream tool before building new judge-style evaluation code around `evaluate`.\n\n## Version-Sensitive Notes For 0.4.6\n\n- PyPI lists `evaluate 0.4.6` as the current package release for this guide.\n- The official `v0.4.6` release notes call out support for `huggingface_hub>=1.0` and `datasets 4`.\n- The docs root currently resolves to the Evaluate docs for `v0.4.6`, but some wording on individual pages still reflects older support ranges and should not override the package metadata on PyPI.\n\n## Official Source URLs\n\n- Hugging Face Evaluate docs root: https://huggingface.co/docs/evaluate/\n- Installation: https://huggingface.co/docs/evaluate/installation\n- Quick tour: https://huggingface.co/docs/evaluate/a_quick_tour\n- Loading methods reference: https://huggingface.co/docs/evaluate/package_reference/loading_methods\n- Main classes reference: https://huggingface.co/docs/evaluate/package_reference/main_classes\n- Evaluator guide: https://huggingface.co/docs/evaluate/base_evaluator\n- Creating and sharing modules: https://huggingface.co/docs/evaluate/creating_and_sharing\n- PyPI package page: https://pypi.org/project/evaluate/\n- GitHub releases: https://github.com/huggingface/evaluate/releases/tag/v0.4.6\n"
  },
  {
    "path": "content/eventlet/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Eventlet package guide for Python cooperative networking, green threads, monkey patching, and WSGI services\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.40.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"eventlet,python,networking,concurrency,green-threads,wsgi\"\n---\n\n# eventlet Python Package Guide\n\n## Golden Rule\n\n**Treat Eventlet as a compatibility or maintenance dependency, not a first choice for new async work.**\n\nThe upstream maintainers explicitly discourage new usage except for maintaining or migrating existing deployments. If you are working on an Eventlet-based service, decide at process start whether the app will use monkey patching, and keep blocking code away from the green-threaded path.\n\n## Installation\n\n```bash\npip install eventlet==0.40.4\n```\n\n```bash\nuv add eventlet==0.40.4\n```\n\n```bash\npoetry add eventlet==0.40.4\n```\n\nPyPI metadata for `0.40.4` requires Python `>=3.9`.\n\n## Initialization And Setup\n\n### Minimal green-thread usage\n\nUse `spawn()` to run cooperative tasks and `wait()` to join them.\n\n```python\nimport eventlet\n\ndef fetch(name: str, delay: float) -> str:\n    print(f\"starting {name}\")\n    eventlet.sleep(delay)\n    return f\"finished {name}\"\n\ngt1 = eventlet.spawn(fetch, \"alpha\", 0.1)\ngt2 = eventlet.spawn(fetch, \"beta\", 0.2)\n\nprint(gt1.wait())\nprint(gt2.wait())\n```\n\n### Bounded concurrency with `GreenPool`\n\nUse a `GreenPool` when you need a fixed concurrency limit instead of unbounded `spawn()` calls.\n\n```python\nimport eventlet\n\npool = eventlet.GreenPool(size=20)\n\ndef work(item: int) -> int:\n    eventlet.sleep(0.05)\n    return item * 2\n\nfor result in pool.imap(work, range(5)):\n    print(result)\n```\n\n### Monkey patching\n\nIf your app expects standard-library networking and threading modules to cooperate with Eventlet, patch as early as possible, before importing modules that capture blocking implementations.\n\n```python\nimport eventlet\n\neventlet.monkey_patch()\n\nimport socket\nfrom urllib import request\n```\n\nYou can patch selectively:\n\n```python\nimport eventlet\n\neventlet.monkey_patch(socket=True, select=True, thread=True)\n```\n\n`monkey_patch()` is safe to call multiple times, but late patching is the common failure mode. Choose either a fully patched process model or an explicit `eventlet.green.*` import model and keep that decision consistent.\n\n### import_patched for targeted imports\n\nIf you do not want global monkey patching, use `eventlet.patcher.import_patched()` to import specific modules against green versions of standard-library dependencies.\n\n```python\nfrom eventlet.patcher import import_patched\n\nurllib_request = import_patched(\"urllib.request\")\n```\n\n## Core Usage Patterns\n\n### Cooperative sleeps and timeouts\n\nUse `eventlet.sleep()` instead of `time.sleep()` inside green-threaded code, and wrap latency-sensitive work with `Timeout`.\n\n```python\nimport eventlet\n\ntry:\n    with eventlet.Timeout(1.0):\n        eventlet.sleep(5)\nexcept eventlet.Timeout:\n    print(\"operation timed out\")\n```\n\nPassing `False` as the second `Timeout` argument suppresses the exception when you want a soft deadline instead of cancellation.\n\n### Simple WSGI server\n\n`eventlet.wsgi.server()` is the standard built-in way to serve a WSGI app.\n\n```python\nimport eventlet\nfrom eventlet import wsgi\n\ndef app(env, start_response):\n    start_response(\"200 OK\", [(\"Content-Type\", \"text/plain\")])\n    return [b\"hello from eventlet\\n\"]\n\nlistener = eventlet.listen((\"127.0.0.1\", 8080))\nwsgi.server(listener, app)\n```\n\n`wsgi.server()` runs in the current greenthread and handles requests cooperatively. If a handler calls blocking code that Eventlet cannot patch, the whole worker can stall.\n\n### Explicit green networking modules\n\nWhen you choose not to monkey patch globally, use `eventlet.green.*` modules explicitly.\n\n```python\nfrom eventlet.green import socket\n\nclient = socket.socket()\nclient.connect((\"example.com\", 80))\nclient.sendall(b\"GET / HTTP/1.0\\r\\nHost: example.com\\r\\n\\r\\n\")\nprint(client.recv(4096))\n```\n\n## Configuration And Auth\n\nEventlet has no authentication layer of its own. The configuration that matters is runtime behavior: hub selection, DNS behavior, and the threadpool used for blocking native work.\n\n### Select the hub early\n\nIf the default event loop hub is not appropriate for the platform, select a different one before creating sockets, timers, or servers.\n\n```python\nimport eventlet.hubs\n\neventlet.hubs.use_hub(\"poll\")\n```\n\nYou can also set the hub via the `EVENTLET_HUB` environment variable before process start.\n\n### DNS behavior\n\nIf Eventlet's green DNS resolver causes issues in your environment, disable it before import:\n\n```bash\nEVENTLET_NO_GREENDNS=yes python app.py\n```\n\n### Native threadpool size\n\nIf you rely on `eventlet.tpool` for blocking native work, set the size before importing Eventlet:\n\n```bash\nEVENTLET_THREADPOOL_SIZE=32 python app.py\n```\n\n### No built-in auth or credentials model\n\nEventlet does not define service credentials, tokens, or connection auth. Any auth configuration belongs to the protocol or framework layered on top of Eventlet, such as WSGI middleware, WebSocket handshake logic, or outbound client libraries.\n\n## Common Pitfalls\n\n- Do not call `eventlet.monkey_patch()` after importing libraries like `socket`, `ssl`, database clients, or HTTP stacks that may already hold blocking objects.\n- Do not use `time.sleep()` in green-threaded code. Use `eventlet.sleep()`.\n- Do not assume all third-party libraries become cooperative after patching. Blocking C extensions and unpatched I/O still block the hub.\n- Be careful when mixing Eventlet with `asyncio`, native threads, or process pools. Keep boundaries explicit instead of sharing sockets or synchronization primitives casually.\n- Verify DNS behavior in production-like environments. `greendns` can behave differently from the platform resolver.\n- For new server development, prefer an asyncio-native stack unless you are constrained by an existing Eventlet-based framework or deployment path.\n\n## Version-Sensitive Notes\n\n- This guide targets `eventlet==0.40.4`, but the readthedocs pages I verified still rendered as `Eventlet 0.40.0 documentation` under `/latest/`. Treat the docs as close to current, not patch-exact.\n- PyPI metadata for `0.40.4` lists Python `>=3.9`. If you are reviving an older Eventlet deployment, re-check interpreter support instead of assuming historical versions still apply.\n- Upstream docs now include an asyncio migration guide and the repository README warns against new Eventlet usage. If you are touching a long-lived Eventlet service, plan around migration rather than expanding Eventlet-specific surface area.\n\n## Official Sources\n\n- Eventlet docs root: https://eventlet.readthedocs.io/en/latest/\n- Basic usage: https://eventlet.readthedocs.io/en/latest/basic_usage.html\n- Patching: https://eventlet.readthedocs.io/en/latest/patching.html\n- WSGI: https://eventlet.readthedocs.io/en/latest/modules/wsgi.html\n- Environment variables: https://eventlet.readthedocs.io/en/latest/environment.html\n- Migration guide: https://eventlet.readthedocs.io/en/latest/asyncio/migration.html\n- PyPI project: https://pypi.org/project/eventlet/\n- Upstream repository README: https://github.com/eventlet/eventlet\n"
  },
  {
    "path": "content/evidently/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"evidently package guide for Python data quality, drift, performance, and evaluation reports\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.21\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"evidently,python,ml,monitoring,data-quality,data-drift,testing\"\n---\n\n# evidently Python Package Guide\n\n## Golden Rule\n\n**Use `evidently` to generate a snapshot first, then decide how you want to persist it: save HTML/JSON for one-off analysis or push it into a workspace for history and dashboards.**\n\nFor most coding tasks, start with a `Report` or `TestSuite` over pandas data, confirm the output locally, and only then wire it into a local or cloud workspace.\n\n## Installation\n\nPin the version if you need behavior to match this guide:\n\n```bash\npython -m pip install \"evidently==0.7.21\"\n```\n\nOptional extras are published for feature-specific integrations:\n\n```bash\npython -m pip install \"evidently[llm]==0.7.21\"\npython -m pip install \"evidently[s3,gcs,fsspec]==0.7.21\"\npython -m pip install \"evidently[sql,spark]==0.7.21\"\n```\n\nUse extras only when you need them:\n\n- `llm` for LLM evaluation features\n- `s3`, `gcs`, `fsspec` for object-storage or filesystem integrations\n- `sql` for SQL connectors\n- `spark` for Spark-based workflows\n\n## Minimal Setup\n\nThe current README and library docs both use pandas data as the normal starting point.\n\n```python\nimport pandas as pd\n\nfrom evidently import Report\nfrom evidently.presets import DataDriftPreset\n\nreference_df = pd.read_parquet(\"reference.parquet\")\ncurrent_df = pd.read_parquet(\"current.parquet\")\n\nreport = Report([DataDriftPreset()])\nsnapshot = report.run(current_data=current_df, reference_data=reference_df)\n\nsnapshot.save_html(\"evidently-report.html\")\nsnapshot.save_json(\"evidently-report.json\")\n```\n\nPractical rules:\n\n- Use `reference_data` as the baseline and `current_data` as the batch or slice you are evaluating now.\n- Persist the returned snapshot with `save_html()` or `save_json()` if you only need a file artifact.\n- If your columns are ambiguous, typed incorrectly, or include timestamps/targets/predictions/text, move to the `Dataset` plus `DataDefinition` workflow from the official quickstart instead of relying on inference.\n\n## Core Usage Patterns\n\n### Reports for drift, quality, and model summaries\n\nReports are the main entry point for analysis snapshots. The official examples use presets from `evidently.presets`.\n\n```python\nfrom evidently import Report\nfrom evidently.presets import DataSummaryPreset, RegressionPreset\n\nsummary_snapshot = Report([DataSummaryPreset()]).run(current_data=current_df)\n\nregression_snapshot = Report([RegressionPreset()]).run(\n    current_data=current_df,\n    reference_data=reference_df,\n)\n```\n\nUse current-only reports for point-in-time summaries. Use both current and reference datasets for drift and performance comparisons.\n\n### Test suites for pass/fail checks\n\nUse a `TestSuite` when you need gate-style evaluation rather than an exploratory report.\n\n```python\nfrom evidently import TestSuite\nfrom evidently.presets import NoTargetPerformanceTestPreset\n\ntest_suite = TestSuite(\n    tests=[\n        NoTargetPerformanceTestPreset(stattest=\"ks\", threshold=0.9),\n    ]\n)\n\nsuite_snapshot = test_suite.run(\n    current_data=current_df,\n    reference_data=reference_df,\n)\n```\n\nThis pattern is a better fit for CI, scheduled checks, or pipeline thresholds than manually inspecting charts.\n\n### Local workspace for persisted history\n\nUse a workspace when you want project history instead of standalone files. The local workspace API uses a `file://` URI.\n\n```python\nfrom evidently import Report\nfrom evidently.presets import DataSummaryPreset\nfrom evidently.ui.workspace import Workspace\n\nws = Workspace.create(\"file:///tmp/evidently-workspace\")\nproject = ws.create_project(\"batch-monitoring\")\n\nsnapshot = Report([DataSummaryPreset()]).run(current_data=current_df)\nws.add_run(project.id, snapshot, include_data=False)\n```\n\nCommon local pattern:\n\n- Create one workspace path per environment or project\n- Create one Evidently project per monitored model or dataset family\n- Add snapshots on every batch, training run, or scheduled job\n\n### Evidently Cloud workspace\n\nCloud usage adds authentication and a hosted URL, but the report/test creation flow stays the same.\n\n```python\nfrom evidently.ui.workspace.cloud import CloudWorkspace\n\nws = CloudWorkspace(\n    token=\"YOUR_API_KEY\",\n    url=\"https://app.evidently.cloud\",\n)\n\nproject = ws.get_project(\"PROJECT_ID\")\nws.add_run(project.id, snapshot)\n```\n\nUse cloud mode when you need shared access, hosted dashboards, or centralized run history.\n\n## Configuration And Auth\n\n`evidently` itself is a local Python library. There is no auth step for local reports, JSON/HTML output, or local workspaces.\n\nAuthentication matters only when you connect to Evidently Cloud:\n\n- initialize `CloudWorkspace(...)` with a valid API token\n- use the correct cloud base URL for your environment\n- fetch or create the target project before adding runs\n\nConfiguration choices that matter in code:\n\n- Decide whether you are running against pandas data directly or explicit `Dataset` objects.\n- Decide whether the result should be a file artifact, a local workspace run, or a cloud workspace run.\n- Install the matching optional extra before you depend on Spark, SQL, storage, or LLM features.\n\n## Common Pitfalls\n\n- Do not swap `reference_data` and `current_data`. Drift and performance results depend on that direction.\n- Do not expect a `Report` object by itself to create files or dashboards. You need the returned snapshot and then `save_*()` or `add_run(...)`.\n- Do not skip explicit schema definition when your dataframe has timestamps, text columns, targets, predictions, or object-typed numeric columns.\n- Do not forget the `file://` prefix when creating a local workspace path.\n- Do not wire cloud auth into local-only jobs. Local reports and local workspaces do not need a token.\n- Do not assume all presets work without reference data. Summary-style outputs can, but drift and many performance checks need a baseline dataset.\n- Do not forget feature extras. Storage, SQL, Spark, and LLM flows may need an extra install beyond base `evidently`.\n\n## Version-Sensitive Notes For 0.7.21\n\n- This guide is pinned to `evidently 0.7.21` on PyPI.\n- The published package metadata for `0.7.21` requires Python `>=3.9`.\n- The maintained docs and README for the current `0.7.x` line center on `Report`, `TestSuite`, workspace APIs, and presets from `evidently.presets`.\n- The Evidently Cloud docs state that cloud supports library versions `0.7.11` and above, so `0.7.21` is within the supported range.\n- If you are copying older examples from blogs or past internal code, re-check imports and workflow against the current docs before reusing them. The official `0.7.x` examples emphasize snapshots plus workspaces rather than older ad hoc patterns.\n\n## Official Sources Used\n\n- PyPI project page: `https://pypi.org/project/evidently/`\n- Repository: `https://github.com/evidentlyai/evidently`\n- README: `https://raw.githubusercontent.com/evidentlyai/evidently/main/README.md`\n- Package metadata: `https://raw.githubusercontent.com/evidentlyai/evidently/main/python/pyproject.toml`\n- Library quickstart: `https://docs.evidentlyai.com/docs/library/get_started`\n- Reports docs: `https://docs.evidentlyai.com/docs/library/report`\n- Workspaces docs: `https://docs.evidentlyai.com/docs/library/workspace`\n- Cloud docs: `https://docs.evidentlyai.com/docs/platform/cloud`\n- Cloud quickstart: `https://docs.evidentlyai.com/docs/platform/get_started_cloud`\n"
  },
  {
    "path": "content/exceptiongroup/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"exceptiongroup package guide for Python projects that need PEP 654 exception groups before Python 3.11\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"exceptiongroup,python,exceptions,pep-654,compatibility\"\n---\n\n# exceptiongroup Python Package Guide\n\n## Golden Rule\n\nUse `exceptiongroup` when your code needs Python 3.11-style exception groups on Python 3.7-3.10, or when you want one import path that also works on newer Python versions. On Python 3.11+, importing `exceptiongroup` uses the built-in exception-group classes and does not install the traceback monkey patches.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"exceptiongroup==1.3.1\"\n```\n\n`exceptiongroup 1.3.1` requires Python 3.7 or newer.\n\n## Initialization And Runtime Behavior\n\nThis package has no client object, credentials, or service initialization step. Import the APIs you need directly:\n\n```python\nfrom exceptiongroup import BaseExceptionGroup, ExceptionGroup, catch, suppress\n```\n\nOptional environment variable:\n\n```bash\nEXCEPTIONGROUP_NO_PATCH=1\n```\n\nSet `EXCEPTIONGROUP_NO_PATCH=1` before Python starts if you do not want the package to patch `traceback.TracebackException` or install its exception hook on Python versions earlier than 3.11.\n\n## Raise An Exception Group\n\nUse `ExceptionGroup(message, exceptions)` to raise several related failures together:\n\n```python\nfrom exceptiongroup import ExceptionGroup\n\n\ndef validate_user(payload: dict) -> None:\n    errors = []\n\n    if \"email\" not in payload:\n        errors.append(ValueError(\"email is required\"))\n\n    age = payload.get(\"age\")\n    if age is None:\n        errors.append(ValueError(\"age is required\"))\n    elif age < 18:\n        errors.append(ValueError(\"age must be at least 18\"))\n\n    if errors:\n        raise ExceptionGroup(\"user payload is invalid\", errors)\n```\n\nThis is useful when you want to report multiple independent validation or task failures in one exception.\n\n## Catch Matching Exceptions On Python 3.7-3.10\n\nPython 3.7-3.10 does not have `except*`, so use `catch()` as a context manager:\n\n```python\nfrom exceptiongroup import BaseExceptionGroup, ExceptionGroup, catch\n\n\ndef handle_value_errors(excgroup: BaseExceptionGroup) -> None:\n    for exc in excgroup.exceptions:\n        print(f\"value error: {exc}\")\n\n\ndef handle_runtime_errors(excgroup: BaseExceptionGroup) -> None:\n    print(f\"runtime failures: {len(excgroup.exceptions)}\")\n\n\nwith catch({\n    ValueError: handle_value_errors,\n    RuntimeError: handle_runtime_errors,\n}):\n    raise ExceptionGroup(\n        \"worker failures\",\n        [\n            ValueError(\"bad input\"),\n            RuntimeError(\"worker crashed\"),\n        ],\n    )\n```\n\nImportant behavior:\n\n- Each key in the mapping passed to `catch()` is an exception class or iterable of exception classes.\n- Each handler is called with an exception group, not with a single exception instance.\n- A handler runs at most once for its matching group.\n- `catch()` cannot handle `BaseExceptionGroup` or `ExceptionGroup` themselves.\n\n## Suppress Specific Exceptions Inside A Group\n\nThe package backports `contextlib.suppress()` behavior from Python 3.12.1 so matching exceptions can be ignored even when they are inside an exception group:\n\n```python\nfrom exceptiongroup import ExceptionGroup, suppress\n\n\nwith suppress(FileNotFoundError):\n    raise ExceptionGroup(\n        \"cleanup failures\",\n        [FileNotFoundError(\"/tmp/app.tmp\")],\n    )\n```\n\nUse this for cleanup paths where a missing file or similar non-fatal error should not fail the whole operation.\n\n## Tracebacks And Formatting\n\nOn Python 3.7-3.10, importing `exceptiongroup` normally patches traceback formatting so unhandled exception groups render correctly. If another library installs its own exception hook first, or if you disable patching with `EXCEPTIONGROUP_NO_PATCH=1`, use the package’s traceback helpers instead of the standard `traceback` module helpers:\n\n```python\nfrom exceptiongroup import ExceptionGroup, format_exception\n\ntry:\n    raise ExceptionGroup(\"request failed\", [ValueError(\"bad input\")])\nexcept Exception as exc:\n    rendered = \"\".join(format_exception(exc))\n    print(rendered)\n```\n\nThe package provides versions of `format_exception()`, `format_exception_only()`, `print_exception()`, and `print_exc()` for this case.\n\n## Common Pitfalls\n\n- Do not write `except*` syntax if your supported runtime includes Python 3.7-3.10. Use `catch()` for that compatibility range.\n- `catch()` handlers receive an exception group, so iterate over `excgroup.exceptions` if you need individual exceptions.\n- Do not try to match `ExceptionGroup` or `BaseExceptionGroup` directly with `catch()`. The package explicitly does not support that.\n- If you rely on custom exception hooks, decide whether you want the package’s automatic monkey patching. Set `EXCEPTIONGROUP_NO_PATCH=1` when you need full control.\n- On Python 3.11+, importing this package does not install the traceback monkey patches or exception hook. If you expected import-time patching on newer Python, that behavior is different by design.\n\n## Version Notes For 1.3.1\n\n- PyPI lists `exceptiongroup 1.3.1` as the current release published on November 21, 2025.\n- The package requires Python 3.7 or newer.\n- The package remains primarily a compatibility layer for pre-3.11 runtimes; on Python 3.11+ it reuses the built-in exception-group classes instead of backporting them.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/agronholm/exceptiongroup\n- PyPI project page: https://pypi.org/project/exceptiongroup/\n- Python built-in exceptions reference: https://docs.python.org/3/library/exceptions.html#exception-groups\n"
  },
  {
    "path": "content/express/docs/express/javascript/DOC.md",
    "content": "---\nname: express\ndescription: \"Express 5 web framework for Node.js applications, APIs, routers, middleware, body parsing, static files, and error handling\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"express,nodejs,web,framework,http,routing,middleware\"\n---\n\n# Express 5 Guide for JavaScript Apps\n\n## Golden Rule\n\nUse the official `express` package to create the app, register middleware, define routes, and start the HTTP server.\n\nExpress does not require API credentials or client authentication. Initialization is just creating an application object with `express()` and mounting the middleware and routers your app needs.\n\nFor request parsing and static files, use the built-in exports on the `express` package:\n\n- `express.json()`\n- `express.urlencoded()`\n- `express.static()`\n- `express.Router()`\n\n## Install\n\nExpress `5.2.1` requires Node.js `18` or newer.\n\n```bash\nnpm install express@5.2.1\n```\n\nTypical environment variables:\n\n```bash\nexport PORT=3000\nexport NODE_ENV=development\n```\n\n## Create and Start an App\n\n`server.js`:\n\n```js\nconst express = require('express');\n\nconst app = express();\nconst port = Number(process.env.PORT || 3000);\n\napp.disable('x-powered-by');\n\napp.use(express.json({ limit: '1mb' }));\napp.use(express.urlencoded({ extended: true, limit: '1mb' }));\n\napp.get('/healthz', (req, res) => {\n  res.status(200).json({ ok: true, env: app.get('env') });\n});\n\napp.use((req, res) => {\n  res.status(404).json({ error: 'Not found' });\n});\n\napp.use((err, req, res, next) => {\n  const status = err.status || err.statusCode || 500;\n  res.status(status).json({\n    error: status >= 500 ? 'Internal Server Error' : err.message,\n  });\n});\n\napp.listen(port, () => {\n  console.log(`Listening on http://localhost:${port}`);\n});\n```\n\nRun it:\n\n```bash\nPORT=3000 NODE_ENV=development node server.js\n```\n\nNotes:\n\n- `app.listen(...)` creates an `http.Server` and returns it.\n- `app.get('env')` comes from `NODE_ENV`, and defaults to `development`.\n- Express enables the `X-Powered-By: Express` header by default; `app.disable('x-powered-by')` turns it off.\n\n## Common Workflows\n\n### Define routes\n\nUse method-specific handlers like `app.get()` and `app.post()` for straightforward APIs.\n\n```js\nconst express = require('express');\n\nconst app = express();\napp.use(express.json());\n\napp.get('/users/:userId', (req, res) => {\n  res.json({\n    userId: req.params.userId,\n    expand: req.query.expand,\n  });\n});\n\napp.post('/users', (req, res) => {\n  const { email, name } = req.body;\n\n  if (!email || !name) {\n    return res.status(400).json({ error: 'email and name are required' });\n  }\n\n  res.status(201).json({ id: 'usr_123', email, name });\n});\n```\n\n`req.params` contains path parameters, `req.query` contains parsed query-string values, and `req.body` is populated only after matching body-parsing middleware runs.\n\n### Split routes into routers\n\nUse `express.Router()` to keep feature-specific routes together.\n\n```js\nconst express = require('express');\n\nconst users = express.Router();\n\nusers.get('/', (req, res) => {\n  res.json([{ id: 'usr_123', name: 'Ada' }]);\n});\n\nusers.get('/:userId', (req, res) => {\n  res.json({ id: req.params.userId, name: 'Ada' });\n});\n\nmodule.exports = users;\n```\n\nMount the router in your app:\n\n```js\nconst express = require('express');\nconst users = require('./routes/users');\n\nconst app = express();\n\napp.use('/users', users);\n```\n\nIf a nested router needs access to params declared on the parent mount path, create it with `mergeParams: true`:\n\n```js\nconst express = require('express');\n\nconst comments = express.Router({ mergeParams: true });\n\ncomments.get('/', (req, res) => {\n  res.json({ postId: req.params.postId });\n});\n\napp.use('/posts/:postId/comments', comments);\n```\n\n### Parse JSON and form bodies\n\n`express.json()` parses JSON requests whose `Content-Type` matches the configured `type` option. `express.urlencoded()` parses URL-encoded form bodies.\n\n```js\nconst express = require('express');\n\nconst app = express();\n\napp.use(express.json({ limit: '1mb' }));\napp.use(express.urlencoded({ extended: true, limit: '1mb' }));\n\napp.post('/session', (req, res) => {\n  res.status(201).json({\n    email: req.body.email,\n    remember: req.body.remember,\n  });\n});\n```\n\nImportant defaults and options:\n\n- `express.json()` defaults to `type: 'application/json'` and `limit: '100kb'`.\n- `express.urlencoded()` defaults to `extended: false`; set `extended: true` if you want rich objects and arrays parsed through `qs`.\n- Both parsers populate `req.body` only when the incoming `Content-Type` matches.\n\n### Serve static files\n\n`express.static()` serves files from a directory and falls through to the next middleware when a file is not found.\n\n```js\nconst express = require('express');\nconst path = require('node:path');\n\nconst app = express();\n\napp.use(\n  '/assets',\n  express.static(path.join(process.cwd(), 'public'), {\n    maxAge: '1d',\n    immutable: true,\n  })\n);\n```\n\nIf that mount should own 404s instead of falling through, set `fallthrough: false`.\n\n### Handle async errors\n\nThe router used by Express 5 supports handlers and middleware that return promises. If an async handler rejects or throws, Express forwards the error to error-handling middleware.\n\n```js\nconst express = require('express');\n\nconst app = express();\n\napp.get('/orders/:orderId', async (req, res) => {\n  const order = await loadOrder(req.params.orderId);\n\n  if (!order) {\n    return res.sendStatus(404);\n  }\n\n  res.json(order);\n});\n\napp.use((err, req, res, next) => {\n  console.error(err);\n  res.status(err.status || 500).json({ error: err.message });\n});\n\nasync function loadOrder(orderId) {\n  if (orderId === 'missing') {\n    return null;\n  }\n\n  if (orderId === 'boom') {\n    throw new Error('Database unavailable');\n  }\n\n  return { id: orderId, total: 42 };\n}\n```\n\nError handlers must have four parameters: `(err, req, res, next)`.\n\n### Run behind a reverse proxy\n\n`trust proxy` is disabled by default. If your app runs behind a load balancer or reverse proxy, enable it so `req.ip`, `req.ips`, `req.protocol`, `req.secure`, and `req.hostname` can use forwarded headers from trusted hops.\n\n```js\nconst express = require('express');\n\nconst app = express();\n\napp.set('trust proxy', 1);\n\napp.get('/whoami', (req, res) => {\n  res.json({\n    ip: req.ip,\n    ips: req.ips,\n    protocol: req.protocol,\n    secure: req.secure,\n    hostname: req.hostname,\n  });\n});\n```\n\nUse `1` when exactly one proxy sits in front of the app. Keep the default `false` if the app receives direct client connections.\n\n### Accept nested query strings\n\nExpress defaults the query parser to `'simple'`. If you want nested query-string parsing, switch it to `'extended'`.\n\n```js\nconst express = require('express');\n\nconst app = express();\n\napp.set('query parser', 'extended');\n\napp.get('/search', (req, res) => {\n  res.json(req.query);\n});\n```\n\nWith the default parser, treat query strings as flat key-value pairs.\n\n## Common Pitfalls\n\n- Validate `req.body` before using it. Express and the underlying body parser treat request bodies as user-controlled input.\n- Do not expect `req.body` without a matching parser. Add `express.json()` for JSON and `express.urlencoded()` for HTML form posts.\n- Increase body limits deliberately. The default JSON and URL-encoded body limit is `'100kb'`.\n- Use `mergeParams: true` for nested routers that need parent path params.\n- Set `trust proxy` correctly before relying on `req.ip`, `req.protocol`, `req.secure`, or `req.hostname` behind a proxy.\n- Disable `x-powered-by` unless you intentionally want to send that header.\n- Remember that `express.static()` falls through on misses by default; use `fallthrough: false` if the static mount should terminate the request.\n\n## Version Notes\n\n- This guide targets `express@5.2.1`.\n- The published package metadata for this release requires Node.js `>= 18`.\n- Express 5 exposes `express.json()`, `express.raw()`, `express.text()`, `express.urlencoded()`, and `express.static()` directly from the main package.\n- Express initializes the app query parser to `'simple'` by default.\n- The router used by Express 5 forwards rejected promises from middleware, route handlers, and `router.param()` callbacks into the error pipeline.\n\n## Official Sources\n\n- https://expressjs.com/en/5x/api.html\n- https://expressjs.com/en/starter/installing.html\n- https://expressjs.com/en/guide/migrating-5\n- https://www.npmjs.com/package/express\n"
  },
  {
    "path": "content/fabric/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Fabric Python package for SSH command execution, file transfer, and task-oriented deployment automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"fabric,python,ssh,remote-execution,deployment,invoke,paramiko\"\n---\n\n# Fabric Python Package Guide\n\n## Golden Rule\n\nUse modern Fabric 3.x APIs and docs, not legacy Fabric 1.x examples. For new code, import `Connection`, `task`, and the group helpers from `fabric`, and drive task collections through the `fab` CLI or normal Python modules.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"fabric==3.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"fabric==3.2.2\"\npoetry add \"fabric==3.2.2\"\n```\n\nFabric installs the `fab` command and depends on Invoke and Paramiko. You do not need a separate Fabric CLI package.\n\n## Setup And Authentication\n\nFabric is an SSH orchestration library. In practice, the important setup is:\n\n1. SSH access to the target host\n2. Working host aliases, usernames, keys, and jump-host rules in OpenSSH config when needed\n3. Optional Fabric config files for defaults shared across tasks\n\nFabric reads SSH config from the usual OpenSSH locations, so aliases such as `Host web-prod` or `ProxyJump bastion` should live in `~/.ssh/config`.\n\nMinimal SSH-config-based usage:\n\n```sshconfig\nHost web-prod\n    HostName web1.example.com\n    User deploy\n    IdentityFile ~/.ssh/id_ed25519\n```\n\n```python\nfrom fabric import Connection\n\nc = Connection(\"web-prod\")\nprint(c.run(\"hostname\", hide=True).stdout.strip())\n```\n\nIf you need to pass credentials directly, use `connect_kwargs`:\n\n```python\nfrom fabric import Connection\n\nc = Connection(\n    \"web1.example.com\",\n    user=\"deploy\",\n    connect_kwargs={\n        \"key_filename\": \"~/.ssh/id_ed25519\",\n    },\n)\n```\n\nConfig files are useful for defaults such as `run.warn`, `sudo.password`, or SSH behavior. Fabric supports system-level config like `/etc/fabric.yml`, per-user config like `~/.fabric.yaml`, and project config files such as `fabric.yaml` loaded from the project root.\n\nExample `fabric.yaml`:\n\n```yaml\nrun:\n  warn: true\nconnect_kwargs:\n  key_filename: ~/.ssh/id_ed25519\nforward_agent: true\n```\n\n## Core Usage\n\n### Run remote commands with `Connection`\n\nUse `Connection` as the main unit of work:\n\n```python\nfrom fabric import Connection\n\nwith Connection(\"web-prod\") as c:\n    result = c.run(\"uname -a\", hide=True)\n    print(result.stdout.strip())\n```\n\nUseful methods:\n\n- `run(...)`: execute a remote shell command\n- `sudo(...)`: run with privilege escalation\n- `put(...)`: upload a local file\n- `get(...)`: download a remote file\n\nExample deployment-style workflow:\n\n```python\nfrom fabric import Connection\n\nwith Connection(\"web-prod\") as c:\n    c.put(\"dist/app.tar.gz\", \"/tmp/app.tar.gz\")\n    c.run(\"mkdir -p /srv/myapp\")\n    c.run(\"tar -xzf /tmp/app.tar.gz -C /srv/myapp\")\n    c.sudo(\"systemctl restart myapp\")\n```\n\n### Author reusable tasks with `@task`\n\nFabric builds on Invoke-style task collections. The first argument is a context object, conventionally named `c`.\n\n```python\nfrom fabric import task\n\n@task\ndef deploy(c):\n    c.run(\"git -C /srv/myapp pull\")\n    c.sudo(\"systemctl restart myapp\")\n\n@task\ndef logs(c, service=\"myapp\", lines=100):\n    c.sudo(f\"journalctl -u {service} -n {lines} --no-pager\")\n```\n\nRun them with `fab`:\n\n```bash\nfab -H web1.example.com deploy\nfab -H web1.example.com logs --service=myapp --lines=200\nfab --list\n```\n\nFor quick one-off commands, `fab` also supports running arbitrary shell commands after `--`:\n\n```bash\nfab -H web1.example.com,web2.example.com -- uname -a\n```\n\n### Work with multiple hosts\n\nUse groups when you want the same command across multiple hosts from Python:\n\n```python\nfrom fabric import ThreadingGroup\n\ngroup = ThreadingGroup(\"web1.example.com\", \"web2.example.com\", user=\"deploy\")\nresults = group.run(\"hostname\", hide=True)\n\nfor connection, result in results.items():\n    print(connection.host, result.stdout.strip())\n```\n\nUse `SerialGroup` when you want deterministic sequential execution. Use `ThreadingGroup` when host fan-out speed matters more than ordered execution.\n\n## CLI Layout\n\nFabric looks for task collections in a `fabfile.py` module or package. A minimal project layout:\n\n```text\nmy-project/\n  fabfile.py\n```\n\n```python\n# fabfile.py\nfrom fabric import task\n\n@task\ndef ping(c):\n    c.run(\"hostname\")\n```\n\n```bash\nfab -H web1.example.com ping\n```\n\nIf the codebase already exposes tasks in a package, keep using that structure instead of forcing everything into one file.\n\n## Configuration Notes\n\n- Prefer SSH config for host aliases, usernames, ports, identity files, and bastions. It is easier to reuse across Fabric, `ssh`, `scp`, and CI runners.\n- Prefer project-level `fabric.yaml` only for defaults that belong to the repo, such as `run.warn`, `forward_agent`, or command timeouts.\n- Keep secrets out of repo config files. Use SSH agents, environment variables, secret managers, or CI-injected files.\n- `Connection` inherits Invoke/Fabric config, so command behavior like warning-on-failure can be centralized instead of repeated on every `run(...)`.\n\n## Common Pitfalls\n\n- Do not copy Fabric 1.x code using `from fabric.api import env, run, sudo, roles`. Modern Fabric is a rewrite with different imports and task patterns.\n- `@task` functions still need the leading context argument even if you do not use it directly.\n- `Connection.run(...)` raises on non-zero exit status by default. Use `warn=True` only when you plan to inspect failures explicitly.\n- Remote commands run through a shell on the target host. Quote arguments carefully instead of interpolating untrusted strings directly into shell commands.\n- `fab -H ...` controls target hosts for CLI task runs; plain `fab deploy` without hosts only works if your tasks create their own connections or host defaults are configured.\n- SSH config and host keys still matter. If plain `ssh web-prod` fails, Fabric will usually fail too.\n- Group execution is useful for fan-out, but partial failures are normal. Write deployment tasks so they surface which host failed and why.\n\n## Version-Sensitive Notes\n\n- The official docs explicitly split legacy `v1.x` documentation from the modern line. Treat blog posts or snippets using Fabric 1 APIs as incompatible unless you are maintaining an old codebase on purpose.\n- Fabric `3.2.2` is a patch release in the current major line. The official changelog notes fixes around shell completion packaging and compatibility with newer Invoke behavior, so pinning to `3.2.2` is safer than copying guidance from early `3.2.0` posts.\n- Fabric is tightly coupled to Invoke and Paramiko behavior. If task parsing or SSH authentication changes unexpectedly after an upgrade, verify the exact Fabric version first before debugging your task code.\n\n## Official Sources Used For This Doc\n\n- Main docs: `https://docs.fabfile.org/en/stable/`\n- Getting started: `https://docs.fabfile.org/en/stable/getting-started.html`\n- Configuration concepts: `https://docs.fabfile.org/en/stable/concepts/configuration.html`\n- Connection API: `https://docs.fabfile.org/en/stable/api/connection.html`\n- Group API: `https://docs.fabfile.org/en/stable/api/group.html`\n- PyPI package page: `https://pypi.org/project/fabric/`\n- Changelog: `https://www.fabfile.org/changelog.html`\n"
  },
  {
    "path": "content/factory-boy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"factory-boy package guide for Python test factories, ORM integration, and reproducible fixtures\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"factory-boy,factory,factories,testing,fixtures,django,sqlalchemy,mongoengine\"\n---\n\n# factory-boy Python Package Guide\n\n## Golden Rule\n\nUse `factory-boy` for test data generation and keep persistence behavior explicit. Install the PyPI package `factory-boy`, import `factory`, and use the ORM-specific base class when you expect `.create()` to hit a database.\n\n## Install\n\nUse the PyPI package name from your dependency file:\n\n```bash\npython -m pip install \"factory-boy==3.3.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"factory-boy==3.3.3\"\npoetry add \"factory-boy==3.3.3\"\n```\n\nUpstream docs also show `pip install factory_boy`. That works because pip normalizes hyphens and underscores, but the canonical PyPI project name is `factory-boy`.\n\n## Initialize A Basic Factory\n\nFor plain Python objects, subclass `factory.Factory` and define `Meta.model` plus field declarations:\n\n```python\nfrom dataclasses import dataclass\n\nimport factory\n\n@dataclass\nclass User:\n    username: str\n    email: str\n    is_admin: bool = False\n\nclass UserFactory(factory.Factory):\n    class Meta:\n        model = User\n\n    username = factory.Sequence(lambda n: f\"user{n}\")\n    email = factory.LazyAttribute(lambda obj: f\"{obj.username}@example.com\")\n    is_admin = False\n```\n\nUse explicit strategies instead of relying on the factory call shortcut:\n\n```python\nuser = UserFactory.build()\nusers = UserFactory.build_batch(3)\nstub = UserFactory.stub()\noverride = UserFactory.build(username=\"root\", is_admin=True)\n```\n\nFor a plain `factory.Factory`, `.create()` still builds the object, but it does not add ORM persistence by itself. Database persistence only comes from subclasses such as `DjangoModelFactory`, `SQLAlchemyModelFactory`, or `MongoEngineFactory`.\n\n## Core Usage Patterns\n\n### Related objects\n\nUse `SubFactory` for forward relations and `SelfAttribute` or `LazyAttribute` when values depend on a parent factory:\n\n```python\nimport factory\n\nclass CountryFactory(factory.Factory):\n    class Meta:\n        model = Country\n\n    name = factory.Iterator([\"France\", \"Italy\", \"Spain\"])\n    lang = factory.Iterator([\"fr\", \"it\", \"es\"])\n\nclass UserFactory(factory.Factory):\n    class Meta:\n        model = User\n\n    username = factory.Sequence(lambda n: f\"user{n}\")\n    country = factory.SubFactory(CountryFactory)\n    lang = factory.SelfAttribute(\"country.lang\")\n```\n\n### Post-generation hooks\n\nUse `@factory.post_generation` when the relation can only be set after the base object exists:\n\n```python\nclass UserFactory(factory.django.DjangoModelFactory):\n    class Meta:\n        model = User\n        skip_postgeneration_save = True\n\n    username = factory.Sequence(lambda n: f\"user{n}\")\n\n    @factory.post_generation\n    def groups(self, create, extracted, **kwargs):\n        if not create or not extracted:\n            return\n        self.groups.add(*extracted)\n```\n\nFor SQLAlchemy many-to-many collections, append instead of calling `.add()`.\n\n### Reproducible randomness\n\n`factory.Faker` and `factory.fuzzy` share the same random state. Seed it in test setup when you want stable failures:\n\n```python\nimport factory.random\n\nfactory.random.reseed_random(\"tests\")\nUserFactory.reset_sequence()\n```\n\nIf you want to replay a failing run exactly, store and restore `factory.random.get_random_state()` / `set_random_state()`.\n\n### Convert a factory to a payload dict\n\nWhen you need request payloads instead of model instances, build `dict` directly:\n\n```python\npayload = factory.build(dict, FACTORY_CLASS=UserFactory)\n```\n\nThis is useful for API tests where you want factory declarations but not ORM objects.\n\n## ORM-Specific Setup\n\n### Django\n\nUse `factory.django.DjangoModelFactory` for Django models:\n\n```python\nimport factory\nfrom myapp import models\n\nclass UserFactory(factory.django.DjangoModelFactory):\n    class Meta:\n        model = models.User\n        django_get_or_create = (\"username\",)\n        skip_postgeneration_save = True\n\n    username = factory.Sequence(lambda n: f\"user{n}\")\n    password = factory.django.Password(\"pw\")\n```\n\nKey Django options:\n\n- `django_get_or_create`: fetches an existing row instead of always creating one\n- `database`: routes factory queries to a named Django database\n- `skip_postgeneration_save`: avoids the transitional extra `save()` after post-generation hooks when you do not need it\n\nIf model signals interfere with `RelatedFactory` or `post_generation`, wrap the factory with `@factory.django.mute_signals(...)` or use the context manager form.\n\n### SQLAlchemy\n\nUse `factory.alchemy.SQLAlchemyModelFactory` and configure exactly one session source:\n\n```python\nimport factory\n\nfrom myapp.db import Session\nfrom myapp.models import User\n\nclass UserFactory(factory.alchemy.SQLAlchemyModelFactory):\n    class Meta:\n        model = User\n        sqlalchemy_session = Session\n        sqlalchemy_session_persistence = \"flush\"\n\n    username = factory.Sequence(lambda n: f\"user{n}\")\n```\n\nKey SQLAlchemy options:\n\n- `sqlalchemy_session`: shared session or `scoped_session`\n- `sqlalchemy_session_factory`: callable returning a session; new in the 3.3.x line\n- `sqlalchemy_session_persistence`: `None`, `\"flush\"`, or `\"commit\"`\n- `sqlalchemy_get_or_create`: fetches existing rows instead of inserting duplicates\n\nIf you use `scoped_session`, assign the `scoped_session` object itself in the factory and configure or remove sessions in test setup and teardown. Do not call `Session()` in the factory declaration.\n\n### MongoEngine\n\nUse `factory.mongoengine.MongoEngineFactory` for MongoEngine documents:\n\n```python\nimport factory\n\nclass PersonFactory(factory.mongoengine.MongoEngineFactory):\n    class Meta:\n        model = Person\n\n    name = factory.Sequence(lambda n: f\"name{n}\")\n```\n\n`.create()` saves `mongoengine.Document` instances. For `EmbeddedDocument`, `.create()` does not persist anything, which is usually what you want before nesting through `SubFactory`.\n\n## Configuration And Auth\n\n`factory-boy` has no auth layer and no required environment variables. Configuration lives in factory declarations and in the surrounding test stack:\n\n- `Meta.model` points at the target class\n- `Meta.inline_args` is useful for constructors that require positional arguments\n- `Meta.exclude` can keep helper attributes out of the final constructor call\n- ORM configuration lives in Django database routing or SQLAlchemy session settings\n\nAny credentials, database URLs, or app settings come from Django, SQLAlchemy, MongoEngine, or your own app, not from `factory-boy` itself.\n\n## Common Pitfalls\n\n- The install name is `factory-boy`, but the import is `factory`.\n- `factory.Factory` does not add persistence. Use an ORM-specific subclass when tests expect rows or documents to be saved.\n- `django_get_or_create` and `sqlalchemy_get_or_create` do not update an existing object with new override values; they only fetch the existing row.\n- `RelatedFactory` and `post_generation` can trigger extra Django saves and signal behavior. For 3.3.x, move toward `skip_postgeneration_save = True` when the extra save is unnecessary.\n- `sqlalchemy_session` and `sqlalchemy_session_factory` are mutually exclusive.\n- Random Faker values and sequences make failures hard to replay if you do not reseed randomness or reset sequences in test setup.\n- The dynamic helpers `factory.build()`, `factory.create()`, and `factory.stub()` default to plain `factory.Factory`. Pass `FACTORY_CLASS=...` when you need Django or SQLAlchemy semantics.\n- `factory.use_strategy()` is deprecated. Prefer explicit `.build()`, `.create()`, `.stub()` calls or a factory `Meta.strategy` setting.\n\n## Version-Sensitive Notes For 3.3.3\n\n- As of March 12, 2026, PyPI still lists `3.3.3` as the latest release.\n- `3.3.3` publishes type annotations. If your editor or type checker behavior changed compared with older examples, that is expected.\n- `3.3.2` added Python 3.13 support, and `3.3.1` added Python 3.12 support.\n- `3.3.1` also fixed the requirement that previously forced `sqlalchemy_session` even when `sqlalchemy_session_factory` was provided.\n- `3.3.0` added `factory.django.Password` and `sqlalchemy_session_factory`.\n- The Django extra-save behavior after post-generation hooks is on a deprecation path. In 3.3.x, upstream recommends either setting `skip_postgeneration_save = True` when the extra save is unnecessary, or saving explicitly in the hook or `_after_postgeneration` when it is necessary.\n"
  },
  {
    "path": "content/faiss-cpu/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Faiss CPU package guide for Python vector search, index selection, training, persistence, and common pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.13.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"faiss,faiss-cpu,python,vector-search,similarity-search,ann,embeddings\"\n---\n\n# Faiss CPU Python Package Guide\n\n## What It Is\n\n`faiss-cpu` is the PyPI wheel for Faiss, Meta's library for dense vector similarity search and clustering. In Python you install `faiss-cpu` but import it as `faiss`.\n\nUse it when you need:\n\n- exact nearest-neighbor search on dense vectors\n- approximate nearest-neighbor search on larger datasets\n- vector indexing with IVF, PQ, HNSW, scalar quantization, or factory strings\n- local in-process search without a remote service\n\n## Install\n\nInstall the older pinned package version if you need to match an existing environment:\n\n```bash\npython -m pip install faiss-cpu==1.13.2\n```\n\nVerify the installed package and import path:\n\n```bash\npython - <<'PY'\nfrom importlib.metadata import version\nimport faiss\n\nprint(\"faiss-cpu:\", version(\"faiss-cpu\"))\nprint(\"faiss module:\", faiss.__file__)\nPY\n```\n\n## Core Data Rules\n\nThe most important Faiss Python rules are structural:\n\n- vectors are usually 2D arrays shaped `(n, d)`\n- `d` is fixed when you build the index\n- use `float32` arrays unless an index explicitly documents another format\n- keep arrays C-contiguous before `train`, `add`, or `search`\n\nIf your data is not already in the expected format, normalize it first:\n\n```python\nimport numpy as np\n\ndef as_faiss_matrix(x: np.ndarray) -> np.ndarray:\n    return np.ascontiguousarray(x, dtype=\"float32\")\n```\n\n## Exact Search\n\nFor exact search on CPU, start with a flat index.\n\n### L2 distance\n\n```python\nimport numpy as np\nimport faiss\n\nd = 384\nxb = np.random.random((10_000, d)).astype(\"float32\")\nxq = np.random.random((5, d)).astype(\"float32\")\n\nindex = faiss.IndexFlatL2(d)\nindex.add(xb)\n\ndistances, ids = index.search(xq, 10)\n\nprint(index.ntotal)\nprint(ids.shape, distances.shape)\n```\n\n### Inner product and cosine similarity\n\nUse `IndexFlatIP` for maximum inner product. For cosine similarity, normalize both the database vectors and query vectors to unit length, then search with inner product.\n\n```python\nimport numpy as np\nimport faiss\n\nd = 768\nxb = np.random.random((50_000, d)).astype(\"float32\")\nxq = np.random.random((3, d)).astype(\"float32\")\n\nfaiss.normalize_L2(xb)\nfaiss.normalize_L2(xq)\n\nindex = faiss.IndexFlatIP(d)\nindex.add(xb)\n\nscores, ids = index.search(xq, 5)\n```\n\nIf you skip normalization, `IndexFlatIP` is inner product search, not cosine similarity.\n\n## Choosing An Index\n\nUse the simplest index that matches the dataset size and latency target:\n\n- `IndexFlatL2` or `IndexFlatIP`: exact search, no training, best recall, memory cost grows with raw vectors\n- `HNSW,Flat` via `index_factory`: approximate search, no training, good CPU default when exact search is too slow\n- `IVF...,Flat`: train once, then trade recall for speed with `nprobe`\n- `IVF...,PQ...` or `PQ...`: lower memory footprint, more approximation, better for large collections\n\nIf you do not know what to start with, begin with `IndexFlatL2` or `IndexFlatIP` to validate shapes, metrics, and result quality before switching to an approximate index.\n\n## Approximate Indexes And Training\n\nMany Faiss indexes need a training step before you can add vectors. IVF, PQ, OPQ, and combinations built from these usually require `train(...)`. Flat indexes and HNSW do not.\n\n```python\nimport numpy as np\nimport faiss\n\nd = 128\nxb = np.random.random((20_000, d)).astype(\"float32\")\nxq = np.random.random((5, d)).astype(\"float32\")\n\nindex = faiss.index_factory(d, \"IVF256,Flat\", faiss.METRIC_L2)\n\nassert not index.is_trained\nindex.train(xb[:10_000])\nassert index.is_trained\n\nindex.add(xb)\nindex.nprobe = 16\n\ndistances, ids = index.search(xq, 10)\n```\n\nPractical guidance:\n\n- train on representative vectors from the same distribution as the vectors you will add\n- do not call `add(...)` before `is_trained` is true for trainable indexes\n- tune `nprobe` on IVF indexes for the recall/latency tradeoff you want\n\n## Factory Strings\n\nFaiss exposes `index_factory(...)` so you can describe an index with a compact string instead of manually wiring every component.\n\n```python\nimport faiss\n\nd = 384\nindex = faiss.index_factory(d, \"HNSW32,Flat\", faiss.METRIC_INNER_PRODUCT)\n```\n\nFactory strings are useful when you want to:\n\n- switch between exact and approximate layouts quickly\n- keep index configuration in a config file or experiment script\n- mirror common combinations from the Faiss wiki without manually composing transforms and sub-indexes\n\n## Custom IDs\n\nPlain flat indexes use implicit sequential ids (`0..ntotal-1`). If your application needs stable external ids, wrap the base index in `IndexIDMap`.\n\n```python\nimport numpy as np\nimport faiss\n\nd = 256\nxb = np.random.random((1_000, d)).astype(\"float32\")\nids = np.arange(10_000, 11_000, dtype=np.int64)\n\nindex = faiss.IndexIDMap(faiss.IndexFlatL2(d))\nindex.add_with_ids(xb, ids)\n\ndistances, found_ids = index.search(xb[:3], 5)\nprint(found_ids)\n```\n\n## Save And Load Indexes\n\nUse `write_index(...)` and `read_index(...)` to persist CPU indexes.\n\n```python\nimport faiss\n\nfaiss.write_index(index, \"vectors.faiss\")\nloaded = faiss.read_index(\"vectors.faiss\")\n```\n\nTreat serialized indexes as trusted artifacts only. Upstream explicitly warns that loading a crafted file can trigger out-of-memory conditions or even code execution.\n\n## Configuration And Environment Notes\n\nFaiss has no API authentication or remote service configuration. The important configuration is local:\n\n- index dimension `d`\n- metric choice: L2 vs inner product\n- index family: flat, HNSW, IVF, PQ, scalar quantization\n- training parameters and search-time knobs such as `nprobe`\n\nFor Python projects:\n\n- install into a virtual environment instead of the system interpreter\n- keep `numpy` and `faiss-cpu` in the same environment\n- pin the package version if your search quality benchmarks depend on exact index behavior\n\n## Common Pitfalls\n\n### Package name and import name differ\n\nInstall `faiss-cpu`, but write `import faiss`.\n\n### Wrong dtype or memory layout\n\nMost Python examples assume `float32` row-major arrays. Convert explicitly:\n\n```python\nxb = np.ascontiguousarray(xb, dtype=\"float32\")\nxq = np.ascontiguousarray(xq, dtype=\"float32\")\n```\n\n### Dimension mismatch\n\nEvery vector passed to a given index must have the same `d` that the index was built with.\n\n### Metric mismatch for cosine search\n\nCosine similarity requires normalized vectors plus an inner-product index. `IndexFlatL2` is not a drop-in cosine index.\n\n### Forgetting to train\n\nIf an IVF or PQ-style index is not trained, `add(...)` will fail or behave incorrectly for the intended workflow. Check `index.is_trained`.\n\n### Expecting custom ids on a base flat index\n\nIf you need your own ids, use `IndexIDMap` or another id-aware wrapper instead of assuming the base index stores your application ids.\n\n### Loading untrusted index files\n\nDo not call `read_index(...)` on files from untrusted users or arbitrary storage.\n\n### Expecting GPU features from `faiss-cpu`\n\nThis package is the CPU wheel. If a guide depends on Faiss GPU resources or CUDA-only features, verify that it applies to your environment before copying it.\n\n## Version-Sensitive Notes For 1.13.2\n\n- The version covered here is the PyPI package version `1.13.2`.\n- PyPI metadata for `1.13.2` lists Python support as `>=3.10, <3.15`.\n- The upstream wiki is a rolling documentation source, not a version-pinned `1.13.2` snapshot. The examples here stay on stable APIs that are documented across the current wiki and repository docs.\n- Upstream install documentation covers broader Faiss build paths, including conda and source builds. For this package entry, prefer the official `faiss-cpu` wheel unless you specifically need a non-PyPI build variant.\n\n## Official Sources Used For This Guide\n\n- PyPI project page: https://pypi.org/project/faiss-cpu/\n- Faiss wiki home: https://github.com/facebookresearch/faiss/wiki\n- Getting started: https://github.com/facebookresearch/faiss/wiki/Getting-started\n- Guidelines to choose an index: https://github.com/facebookresearch/faiss/wiki/Guidelines-to-choose-an-index\n- MetricType and distances: https://github.com/facebookresearch/faiss/wiki/MetricType-and-distances\n- The index factory: https://github.com/facebookresearch/faiss/wiki/The-index-factory\n- Index IO, cloning and hyper parameter tuning: https://github.com/facebookresearch/faiss/wiki/Index-IO%2C-cloning-and-hyper-parameter-tuning\n- Repository README: https://github.com/facebookresearch/faiss\n- Install notes: https://github.com/facebookresearch/faiss/blob/main/INSTALL.md\n"
  },
  {
    "path": "content/faker/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Faker Python package guide for generating fake test data, localized fixtures, and custom providers\"\nmetadata:\n  languages: \"python\"\n  versions: \"40.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"faker,python,test-data,fixtures,mocking,localization\"\n---\n\n# Faker Python Package Guide\n\n## Golden Rule\n\nUse `Faker` for synthetic test data and fixtures, and seed it explicitly whenever output needs to be reproducible. For version `40.8.0`, trust PyPI for Python compatibility: as of March 12, 2026, the package requires `Python >=3.10` even though the docs landing page still says Python 3.8+.\n\n## Install\n\nPin the version if your project needs deterministic provider behavior:\n\n```bash\npython -m pip install \"Faker==40.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Faker==40.8.0\"\npoetry add \"Faker==40.8.0\"\n```\n\n`pip install faker` also works because PyPI names are case-insensitive, but the canonical project name is `Faker`.\n\nPyPI exposes a `tzdata` extra. Most projects do not need to install it manually, but it can matter on platforms that do not ship a usable timezone database:\n\n```bash\npython -m pip install \"Faker[tzdata]==40.8.0\"\n```\n\n## Initialize And Generate Data\n\nCreate one generator and call provider methods on it:\n\n```python\nfrom faker import Faker\n\nfake = Faker()\n\nuser = {\n    \"name\": fake.name(),\n    \"email\": fake.email(),\n    \"company\": fake.company(),\n    \"address\": fake.address(),\n}\n```\n\nFor repeatable output across runs, seed before generating values:\n\n```python\nfrom faker import Faker\n\nFaker.seed(4321)\nfake = Faker()\n\nprint(fake.name())\nprint(fake.name())\n```\n\nImportant seeding rules for modern Faker:\n\n- Use `Faker.seed(...)` for the shared class-level RNG.\n- Use `fake.seed_instance(...)` for an isolated RNG on one generator instance.\n- Use `fake.seed_locale(\"en_US\", ...)` when you need deterministic output for one locale inside a multi-locale generator.\n- Do not call `fake.seed(...)` on an instance. Current Faker documents that this raises `TypeError`.\n\n## Locale And Multi-Locale Usage\n\nUse a specific locale when your tests depend on localized names, addresses, phone numbers, or identifiers:\n\n```python\nfrom faker import Faker\n\nfake = Faker(\"it_IT\")\nprint(fake.name())\nprint(fake.address())\n```\n\nFaker also supports multiple locales in one generator:\n\n```python\nfrom collections import OrderedDict\nfrom faker import Faker\n\nfake = Faker(OrderedDict([\n    (\"en_US\", 1),\n    (\"en_PH\", 2),\n    (\"ja_JP\", 3),\n]))\n\nprint(fake.name())          # weighted locale selection\nprint(fake[\"ja_JP\"].name()) # direct locale access\n```\n\nPractical guidance:\n\n- Locale strings normalize hyphenated and underscored forms, but use one style consistently in your codebase.\n- A provider may exist for one locale and not another. In multi-locale mode, method dispatch falls back to a locale that supports the provider; direct indexed access like `fake[\"en_PH\"].zipcode()` can still raise `AttributeError`.\n- If you need raw speed for bulk fixture generation, pass `use_weighting=False`. The default `True` tries to mimic real-world frequencies and is slower.\n\n## Common Provider Patterns\n\nMost day-to-day usage comes from bundled providers:\n\n- person and identity: `name()`, `first_name()`, `ssn()`, `passport_number()`\n- internet and auth-ish placeholders: `email()`, `ipv4_private()`, `user_name()`\n- company and profile data: `company()`, `job()`, `profile()`\n- text and content: `sentence()`, `paragraph()`, `text()`\n- dates and numbers: `date_time()`, `uuid4()`, `random_int()`, `pydecimal()`\n\nExample:\n\n```python\nfrom faker import Faker\n\nfake = Faker()\n\nrecord = {\n    \"id\": fake.uuid4(),\n    \"full_name\": fake.name(),\n    \"username\": fake.user_name(),\n    \"email\": fake.email(),\n    \"created_at\": fake.date_time_this_year().isoformat(),\n}\n```\n\nThe standard providers index in the official docs is the fastest way to check whether a method belongs to `address`, `internet`, `person`, `phone_number`, `profile`, `python`, or another provider family.\n\n## Unique Values\n\nUse `.unique` only when collisions actually break your test:\n\n```python\nfrom faker import Faker\n\nfake = Faker()\nemails = [fake.unique.email() for _ in range(100)]\nfake.unique.clear()\n```\n\nPitfalls:\n\n- Uniqueness is scoped to one `Faker` instance.\n- Small output spaces will exhaust quickly and raise `UniquenessException`.\n- Only hashable arguments and return values work with `.unique`.\n- In multi-locale mode, you can scope uniqueness per locale with `fake.unique[\"en_US\"].first_name()`.\n\n## Custom And Dynamic Providers\n\nUse a custom provider when project-specific fake values should look like first-class Faker methods:\n\n```python\nfrom faker import Faker\nfrom faker.providers import BaseProvider\n\nclass PlanProvider(BaseProvider):\n    def plan_code(self) -> str:\n        return self.random_element([\"free\", \"team\", \"enterprise\"])\n\nfake = Faker()\nfake.add_provider(PlanProvider)\n\nprint(fake.plan_code())\n```\n\nFor data loaded from a list or external source, use `DynamicProvider`:\n\n```python\nfrom faker import Faker\nfrom faker.providers import DynamicProvider\n\ndepartment_provider = DynamicProvider(\n    provider_name=\"department\",\n    elements=[\"sales\", \"support\", \"platform\"],\n)\n\nfake = Faker()\nfake.add_provider(department_provider)\n\nprint(fake.department())\n```\n\n## Pytest Integration\n\nFaker ships a `pytest` plugin with a `faker` fixture. The important operational detail is that the fixture is seeded for every test:\n\n```python\nimport pytest\n\n@pytest.fixture(scope=\"module\")\ndef faker_seed():\n    return 12345\n\ndef test_profile_shape(faker):\n    profile = faker.profile()\n    assert \"mail\" in profile\n```\n\nUseful behavior from the official fixture docs:\n\n- By default, the plugin reuses a session-scoped Faker instance for efficiency.\n- Activating a `faker_locale` fixture causes tests to get a new Faker instance for that scope.\n- Activating a `faker_seed` fixture changes the seed for that scope.\n- If you need to reseed mid-test, call `faker.seed_instance(...)` on the fixture value.\n\n## CLI Usage\n\nInstalling Faker also installs a `faker` CLI:\n\n```bash\nfaker name\nfaker -l de_DE address\nfaker -r 3 -s \";\" email\npython -m faker profile ssn,birthdate\n```\n\nUse the CLI for quick fixture inspection or to snapshot provider output while designing tests.\n\n## Configuration And Environment\n\nFaker is a local data-generation library:\n\n- no API key\n- no remote service auth\n- no network calls in normal use\n\nConfiguration is code-level:\n\n- locale choice\n- seeding strategy\n- provider selection\n- `use_weighting`\n- custom providers\n\nFor test suites, make seed and locale explicit in fixtures instead of relying on global process state.\n\n## Common Pitfalls\n\n- `Faker` is the package name on PyPI, but imports are `from faker import Faker`.\n- Do not assume docs examples are fully version-synchronized across all stable subpages. The stable root currently shows `40.8.0`, while the pytest fixtures page still renders a `40.4.0` header.\n- Provider availability is locale-specific. Check the provider docs or test the exact method against the locale you plan to use.\n- Reproducibility depends on Faker version as well as seed. Pin the package version when tests assert exact generated values.\n- Shared class-level seeding can leak assumptions across tests. Prefer `seed_instance()` for isolated fixtures.\n- `.unique` is not free. It adds bookkeeping overhead and can fail once the value space is exhausted.\n\n## Version-Sensitive Notes\n\n- PyPI shows `Faker 40.8.0` uploaded on March 4, 2026.\n- PyPI metadata now requires `Python >=3.10`.\n- The upstream changelog records support drops at `25.0.0` for Python 3.7, `36.0.0` for Python 3.8, and `38.0.0` for Python 3.9. If your runtime is older, you need an older Faker line.\n- The changelog for `40.1.0` added selective uniqueness helpers, and `40.1.2` changed `tzdata` handling to be conditional by platform.\n\n## Official Sources\n\n- Docs root: `https://faker.readthedocs.io/en/stable/`\n- Faker class details: `https://faker.readthedocs.io/en/stable/fakerclass.html`\n- Pytest fixtures: `https://faker.readthedocs.io/en/stable/pytest-fixtures.html`\n- Standard providers index: `https://faker.readthedocs.io/en/stable/providers.html`\n- PyPI package page: `https://pypi.org/project/Faker/`\n- Upstream changelog: `https://github.com/joke2k/faker/blob/master/CHANGELOG.md`\n"
  },
  {
    "path": "content/falcon/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Falcon web framework for building high-performance WSGI and ASGI APIs in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"falcon,python,web,api,framework,asgi,wsgi\"\n---\n\n# Falcon Python Package Guide\n\nFalcon is a low-level Python framework for HTTP APIs and microservices. Use it when you want explicit routing, request/response objects, middleware hooks, and a choice between WSGI and ASGI without a batteries-included stack.\n\n## Golden Rule\n\n- Pick the runtime model first:\n  - `falcon.App()` for WSGI\n  - `falcon.asgi.App()` for ASGI\n- Falcon does not include a production server. Pair WSGI apps with Gunicorn, uWSGI, or Waitress, and ASGI apps with Uvicorn, Daphne, or Hypercorn.\n- Falcon `4.2.0` supports CPython `3.9+` and PyPy `3.9+`.\n- Falcon has no required runtime dependencies.\n- Use `req.get_media()` / `await req.get_media()` for request bodies and `resp.media` for JSON responses.\n\n## Install\n\n```bash\npip install \"falcon==4.2.0\"\n```\n\nIf you also need a server locally:\n\n```bash\npip install \"falcon==4.2.0\" gunicorn\npip install \"falcon==4.2.0\" uvicorn\n```\n\nFalcon ships many prebuilt wheels. If you need a source build that cythonizes locally:\n\n```bash\npip install --no-binary :all: \"falcon==4.2.0\"\n```\n\n## Choose WSGI vs ASGI First\n\n### WSGI app\n\nUse WSGI when your app is synchronous and will run behind a WSGI server.\n\n```python\nimport falcon\n\nclass ThingsResource:\n    def on_get(self, req, resp):\n        resp.media = {\"status\": \"ok\"}\n\napp = falcon.App()\napp.add_route(\"/things\", ThingsResource())\n```\n\nTypical run command:\n\n```bash\ngunicorn example:app\n```\n\n### ASGI app\n\nUse ASGI when you need `async` responders, WebSockets, SSE, or ASGI lifespan support.\n\n```python\nimport falcon\nimport falcon.asgi\n\nclass ThingsResource:\n    async def on_get(self, req, resp):\n        resp.media = {\"status\": \"ok\"}\n\napp = falcon.asgi.App()\napp.add_route(\"/things\", ThingsResource())\n```\n\nTypical run command:\n\n```bash\nuvicorn example:app\n```\n\n## Core Usage Pattern\n\nFalcon is resource-oriented. You register a long-lived resource instance with `app.add_route()` and implement responders such as `on_get()` or `on_post()`.\n\n```python\nimport falcon\n\nclass ItemResource:\n    def on_get(self, req, resp, item_id):\n        resp.media = {\n            \"item_id\": item_id,\n            \"limit\": req.get_param_as_int(\"limit\") or 20,\n        }\n\n    def on_post(self, req, resp, item_id):\n        payload = req.get_media()\n        resp.media = {\n            \"item_id\": item_id,\n            \"received\": payload,\n        }\n        resp.status = falcon.HTTP_201\n\napp = falcon.App()\napp.add_route(\"/items/{item_id}\", ItemResource())\n```\n\nASGI body parsing is the same idea, but `get_media()` must be awaited:\n\n```python\nimport falcon\nimport falcon.asgi\n\nclass ItemResource:\n    async def on_post(self, req, resp):\n        payload = await req.get_media()\n        resp.media = payload\n\napp = falcon.asgi.App()\napp.add_route(\"/items\", ItemResource())\n```\n\nPractical request/response rules:\n\n- Route params are passed as responder arguments.\n- Query params come from helpers like `req.get_param()` and `req.get_param_as_int()`.\n- `resp.media` uses Falcon's media handlers and defaults to JSON.\n- Calling `req.get_media()` consumes the request body stream once; Falcon caches the parsed object for later access.\n\n## Config and App Setup\n\nFalcon stays unopinionated about application config. The usual pattern is:\n\n- Load settings from env vars or your own config object.\n- Pass shared services into resource constructors.\n- Use app kwargs and middleware for framework-level behavior.\n\nCommon app-level options:\n\n- `middleware=[...]` for request/response cross-cutting logic\n- `cors_enable=True` for a simple global CORS policy\n- `request_type=` / `response_type=` when you need custom request or response classes\n- `independent_middleware=False` only if you intentionally want response middleware skipped after request-stage exceptions\n\nIf you need custom JSON serialization or alternate media types, update both request and response media handlers:\n\n```python\nimport json\nfrom functools import partial\n\nimport falcon\nfrom falcon import media\n\njson_handler = media.JSONHandler(\n    dumps=partial(json.dumps, separators=(\",\", \":\")),\n)\n\napp = falcon.App()\napp.req_options.media_handlers.update({\"application/json\": json_handler})\napp.resp_options.media_handlers.update({\"application/json\": json_handler})\n```\n\n## Auth and Middleware\n\nAuth is typically implemented in middleware or hooks. Middleware runs in the order you register it.\n\n```python\nimport falcon\n\nclass AuthMiddleware:\n    def process_request(self, req, resp):\n        token = req.get_header(\"Authorization\")\n        if token != \"Bearer secret-token\":\n            raise falcon.HTTPUnauthorized(\n                title=\"Authentication required\",\n                description=\"Missing or invalid bearer token\",\n            )\n\n        req.context.user_id = \"demo-user\"\n\nclass ProfileResource:\n    def on_get(self, req, resp):\n        resp.media = {\"user_id\": req.context.user_id}\n\napp = falcon.App(middleware=[AuthMiddleware()])\napp.add_route(\"/profile\", ProfileResource())\n```\n\nUse middleware when you need:\n\n- authentication and authorization\n- request IDs or trace context\n- tenant resolution\n- request/response logging\n- cross-cutting validation before routing or before the responder runs\n\n## Testing\n\nUse Falcon's test helpers instead of spinning up a real server in unit tests.\n\n```python\nimport falcon\nfrom falcon import testing\n\nclass HealthResource:\n    def on_get(self, req, resp):\n        resp.media = {\"ok\": True}\n\napp = falcon.App()\napp.add_route(\"/health\", HealthResource())\n\nclient = testing.TestClient(app)\nresult = client.simulate_get(\"/health\")\n\nassert result.status_code == 200\nassert result.json == {\"ok\": True}\n```\n\nFor ASGI apps, Falcon also provides `testing.ASGIConductor` when you need to test streams, SSE, or WebSocket flows.\n\n## Common Pitfalls\n\n- Do not run `falcon.App()` behind an ASGI server or `falcon.asgi.App()` behind a WSGI server.\n- Do not assume Falcon includes an ORM, schema validation layer, auth system, dependency injection container, or production server.\n- Do not put per-request mutable state on a resource instance; resources are long-lived.\n- Prefer `req.get_media()` over reading raw request streams unless you have a specific streaming need.\n- For ASGI apps, remember to `await req.get_media()` and keep middleware/responders async-aware.\n- Middleware order matters. Response middleware is executed as a stack, and by default Falcon still runs `process_response()` even when request-stage code raises.\n- `cors_enable=True` is only a simple CORS policy. Use `CORSMiddleware` if you need finer control.\n- The quickstart uses `wsgiref` to demonstrate a minimal WSGI app, but it is not a production deployment choice.\n\n## Version-Sensitive Notes for 4.2.0\n\n- Falcon `4.2.0` was released on `2025-11-10` on PyPI.\n- `4.2.0` primarily adds typing improvements and performance optimizations.\n- The release makes WSGI and ASGI `App` types generic over request and response types, which matters if you use custom `request_type` / `response_type` classes and type check your code.\n- `4.2.0` also introduced precompiled wheels for free-threaded CPython `3.14` on selected Linux x86 targets.\n- The docs URL points at `https://falcon.readthedocs.io/en/stable/api/`. As of `2026-03-12`, that `stable` docs root serves Falcon `4.2.0`, but it will drift in the future. Prefer pairing it with the pinned PyPI version and release notes when reproducibility matters.\n\n## Official Sources\n\n- Docs root: https://falcon.readthedocs.io/en/stable/\n- API landing page: https://falcon.readthedocs.io/en/stable/api/\n- Installation: https://falcon.readthedocs.io/en/stable/user/install.html\n- Quickstart: https://falcon.readthedocs.io/en/stable/user/quickstart.html\n- App class reference: https://falcon.readthedocs.io/en/stable/api/app.html\n- Media handling: https://falcon.readthedocs.io/en/stable/api/media.html\n- Middleware reference: https://falcon.readthedocs.io/en/stable/api/middleware.html\n- Testing helpers: https://falcon.readthedocs.io/en/stable/api/testing.html\n- PyPI package page: https://pypi.org/project/falcon/\n- PyPI release page: https://pypi.org/project/falcon/4.2.0/\n- GitHub release notes: https://github.com/falconry/falcon/releases/tag/4.2.0\n- Repository: https://github.com/falconry/falcon\n"
  },
  {
    "path": "content/fast-xml-parser/docs/fast-xml-parser/javascript/DOC.md",
    "content": "---\nname: fast-xml-parser\ndescription: \"Parse, validate, and build XML in JavaScript or TypeScript with fast-xml-parser\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.5.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fast-xml-parser,xml,javascript,typescript,parser,builder,validation\"\n---\n\n# fast-xml-parser for JavaScript / TypeScript\n\n`fast-xml-parser` is a pure JavaScript package for three related jobs:\n\n- parse XML into JavaScript objects with `XMLParser`\n- validate XML syntax with `XMLValidator`\n- build XML from JavaScript objects with `XMLBuilder`\n\nIt works in both ESM and CommonJS projects and ships its own TypeScript declarations.\n\n## Install\n\n```bash\nnpm install fast-xml-parser\n```\n\nThe package already includes its own type definitions, so you do not need `@types/fast-xml-parser`.\n\n## Imports and initialization\n\nNo environment variables, credentials, or service setup are required.\n\n### ESM / TypeScript\n\n```ts\nimport { XMLBuilder, XMLParser, XMLValidator } from \"fast-xml-parser\";\n\nconst parser = new XMLParser();\nconst builder = new XMLBuilder();\n```\n\n### CommonJS\n\n```js\nconst { XMLBuilder, XMLParser, XMLValidator } = require(\"fast-xml-parser\");\n\nconst parser = new XMLParser();\nconst builder = new XMLBuilder();\n```\n\n## Parse XML\n\nThe most important parser default is that attributes are ignored unless you opt in with `ignoreAttributes: false`.\n\n```ts\nimport { XMLParser } from \"fast-xml-parser\";\n\nconst parser = new XMLParser({\n  ignoreAttributes: false,\n});\n\nconst xml = `\n<catalog version=\"1\">\n  <book id=\"bk-1\">\n    <title>XML Guide</title>\n    <price currency=\"USD\">19.99</price>\n  </book>\n</catalog>`;\n\nconst result = parser.parse(xml);\n\nconsole.log(result.catalog[\"@_version\"]); // \"1\"\nconsole.log(result.catalog.book[\"@_id\"]); // \"bk-1\"\nconsole.log(result.catalog.book.price); // 19.99\n```\n\nDefault parsing behavior that commonly surprises people:\n\n- `ignoreAttributes` defaults to `true`\n- `attributeNamePrefix` defaults to `\"@_\"`\n- `textNodeName` defaults to `\"#text\"`\n- `parseTagValue` defaults to `true`, so numeric-looking tag text becomes numbers\n- `parseAttributeValue` defaults to `false`, so attributes stay strings unless you enable it\n\nIf you want numeric attribute values too, enable `parseAttributeValue`:\n\n```ts\nconst parser = new XMLParser({\n  ignoreAttributes: false,\n  parseAttributeValue: true,\n});\n\nconst result = parser.parse(`<item qty=\"2\">10</item>`);\n\nconsole.log(result.item[\"@_qty\"]); // 2\nconsole.log(result.item); // { \"#text\": 10, \"@_qty\": 2 }\n```\n\n## Validate XML before parsing\n\n`XMLValidator.validate()` checks XML syntax and returns either `true` or an error object with `code`, `msg`, `line`, and `col`.\n\n```ts\nimport { XMLValidator } from \"fast-xml-parser\";\n\nconst validation = XMLValidator.validate(\"<root>\");\n\nif (validation !== true) {\n  throw new Error(`${validation.err.msg} at ${validation.err.line}:${validation.err.col}`);\n}\n```\n\nFor XML-like or HTML-like input, pass validator options when you need boolean attributes or unpaired tags:\n\n```ts\nconst validation = XMLValidator.validate(\"<input disabled>\", {\n  allowBooleanAttributes: true,\n  unpairedTags: [\"input\", \"br\", \"img\"],\n});\n```\n\nYou can also ask `XMLParser` to validate inline. Invalid XML throws an error before parsing:\n\n```ts\nconst parser = new XMLParser({ ignoreAttributes: false });\n\nconst result = parser.parse(xml, {\n  allowBooleanAttributes: true,\n  unpairedTags: [\"input\", \"br\", \"img\"],\n});\n```\n\nUse the validator for syntax checks only. If you need schema or business-rule validation, handle that separately.\n\n## Common parser workflows\n\n### Keep array shapes stable\n\nRepeated XML elements become arrays automatically, but single elements do not. Use `isArray` when your application needs a stable array shape.\n\n```ts\nconst parser = new XMLParser({\n  isArray: (tagName, jPath) => jPath === \"feed.entry\",\n});\n\nconst result = parser.parse(`\n<feed>\n  <entry><title>First</title></entry>\n</feed>`);\n\nconsole.log(Array.isArray(result.feed.entry)); // true\n```\n\n### Strip namespace prefixes\n\nUse `removeNSPrefix: true` when you want `ns:item` to become `item` in the parsed output.\n\n```ts\nconst parser = new XMLParser({\n  ignoreAttributes: false,\n  removeNSPrefix: true,\n});\n\nconst result = parser.parse(`\n<ns:feed xmlns:ns=\"urn:example\">\n  <ns:item ns:id=\"1\">hello</ns:item>\n</ns:feed>`);\n\nconsole.log(result.feed.item[\"#text\"]); // \"hello\"\nconsole.log(result.feed.item[\"@_id\"]); // \"1\"\n```\n\n### Preserve raw inner content for specific nodes\n\nUse `stopNodes` for tags whose contents should stay as raw text instead of being parsed as nested XML. This is useful for embedded HTML, script blocks, or template fragments.\n\n```ts\nconst parser = new XMLParser({\n  ignoreAttributes: false,\n  stopNodes: [\"page.script\", \"page.template\"],\n});\n\nconst result = parser.parse(`\n<page>\n  <script><![CDATA[if (a < b) { render(); }]]></script>\n</page>`);\n\nconsole.log(result.page.script); // \"<![CDATA[if (a < b) { render(); }]]>\"\n```\n\n### Add custom entities\n\nIf your input uses entities that are not built in, register them on the parser before calling `parse()`:\n\n```ts\nconst parser = new XMLParser();\n\nparser.addEntity(\"company\", \"OpenAI\");\n\nconst result = parser.parse(\"<root>&company;</root>\");\n\nconsole.log(result.root); // \"OpenAI\"\n```\n\n## Build XML from JavaScript objects\n\nWhen building XML, attributes use the same `@_` prefix by default and text values use `#text` when the same element also has attributes or child nodes.\n\n```ts\nimport { XMLBuilder } from \"fast-xml-parser\";\n\nconst builder = new XMLBuilder({\n  ignoreAttributes: false,\n  format: true,\n});\n\nconst data = {\n  catalog: {\n    \"@_version\": \"1\",\n    book: [\n      {\n        \"@_id\": \"bk-1\",\n        title: \"XML Guide\",\n        price: {\n          \"@_currency\": \"USD\",\n          \"#text\": 19.99,\n        },\n      },\n    ],\n  },\n};\n\nconst xml = builder.build(data);\n\nconsole.log(xml);\n```\n\nIf you customize parser naming options such as `attributeNamePrefix`, `textNodeName`, or `attributesGroupName`, use the same settings in `XMLBuilder` when you need predictable round-tripping.\n\n## TypeScript notes\n\nThe package exports its own typings, so TypeScript projects can use the library directly:\n\n```ts\nimport { XMLValidator, type ValidationError } from \"fast-xml-parser\";\n\nconst validation = XMLValidator.validate(\"<root>\");\n\nif (validation !== true) {\n  const err: ValidationError = validation;\n  console.error(err.err.msg);\n}\n```\n\nFor source-location metadata, enable `captureMetaData`. Metadata is attached with the symbol returned by `XMLParser.getMetaDataSymbol()`.\n\n```ts\nimport { XMLParser } from \"fast-xml-parser\";\n\nconst parser = new XMLParser({\n  captureMetaData: true,\n  ignoreAttributes: false,\n  alwaysCreateTextNode: true,\n});\n\nconst result = parser.parse(`<root><child id=\"1\">value</child></root>`);\nconst metaKey = XMLParser.getMetaDataSymbol();\n\nconsole.log(result.root[metaKey]?.startIndex); // 0\nconsole.log(result.root.child[metaKey]?.startIndex); // 6\n```\n\n## Important pitfalls\n\n- Attributes disappear unless you set `ignoreAttributes: false`.\n- Tag text is parsed by default, so values like `19.99`, `true`, or `001` may not stay strings.\n- Attribute values stay strings unless you set `parseAttributeValue: true`.\n- `preserveOrder: true` changes the output to an ordered array-based structure; do not enable it unless your code is written for that shape.\n- If you change `attributeNamePrefix` or `textNodeName`, keep parser and builder options aligned.\n- The package still exposes a built-in `fxparser` command, but the bundled CLI is deprecated. Use `fxp-cli` if you need a maintained CLI workflow.\n"
  },
  {
    "path": "content/fastapi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastAPI package guide for Python ASGI APIs, dependency injection, auth, and deployment\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.135.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"fastapi,python,asgi,api,openapi,web,async\"\n---\n\n# FastAPI Python Package Guide\n\n## What It Is\n\nFastAPI is a Python ASGI web framework for JSON APIs and backend services. It builds on Starlette and Pydantic, generates OpenAPI automatically, and includes dependency injection, validation, security helpers, and testing utilities.\n\nUse this doc when you need to:\n\n- build an HTTP API with typed request and response models\n- organize routes with dependencies and routers\n- configure auth, settings, uploads, CORS, and lifespan startup/shutdown\n- avoid version-specific regressions in the `0.129.x` to `0.135.x` range\n\n## Python And Install Requirements\n\n- FastAPI `0.135.1` requires Python `>=3.10`.\n- PyPI publishes extras: `standard`, `standard-no-fastapi-cloud-cli`, and `all`.\n- `fastapi[standard]` is the easiest install for new apps because it brings in `uvicorn`, `fastapi-cli`, `httpx`, `jinja2`, and `python-multipart`.\n\n### Recommended install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"fastapi[standard]==0.135.1\"\n```\n\n### Minimal install\n\nUse this only if you intentionally manage the server and optional tooling yourself:\n\n```bash\npip install \"fastapi==0.135.1\"\npip install \"uvicorn[standard]\"\n```\n\n### Useful optional packages\n\n```bash\npip install pydantic-settings\npip install python-multipart\npip install httpx\n```\n\n- `pydantic-settings` is for environment-based config.\n- `python-multipart` is required for form/file parsing.\n- `httpx` is required for `fastapi.testclient.TestClient`.\n\n## Minimal App\n\n```python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n```\n\nRun it in development:\n\n```bash\nfastapi dev main.py\n```\n\nOr with Uvicorn directly:\n\n```bash\nuvicorn main:app --reload\n```\n\nDefault generated docs and schema endpoints:\n\n- Swagger UI: `http://127.0.0.1:8000/docs`\n- ReDoc: `http://127.0.0.1:8000/redoc`\n- OpenAPI JSON: `http://127.0.0.1:8000/openapi.json`\n\n## Core Usage Pattern\n\nFastAPI works best when you keep request validation, dependency injection, and routing explicit.\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import APIRouter, Depends, FastAPI, HTTPException\nfrom pydantic import BaseModel\n\napp = FastAPI(title=\"Inventory API\")\nrouter = APIRouter(prefix=\"/items\", tags=[\"items\"])\n\nclass ItemIn(BaseModel):\n    name: str\n    price: float\n\nasync def common_params(q: str | None = None, limit: int = 100):\n    return {\"q\": q, \"limit\": limit}\n\n@router.get(\"/\")\nasync def list_items(params: Annotated[dict, Depends(common_params)]):\n    return {\"filters\": params, \"items\": []}\n\n@router.post(\"/\", status_code=201)\nasync def create_item(item: ItemIn):\n    if item.price < 0:\n        raise HTTPException(status_code=400, detail=\"price must be non-negative\")\n    return item\n\napp.include_router(router)\n```\n\nNotes:\n\n- Prefer `Annotated[..., Depends(...)]` for new code.\n- Use Pydantic models for request bodies and response models.\n- Split larger apps with `APIRouter` and `app.include_router(...)`.\n\n## Configuration And App Setup\n\n### Constructor options you will actually use\n\n```python\nfrom fastapi import FastAPI\n\napp = FastAPI(\n    title=\"My API\",\n    version=\"1.0.0\",\n    docs_url=\"/docs\",\n    redoc_url=None,\n    openapi_url=\"/openapi.json\",\n    redirect_slashes=True,\n)\n```\n\nUseful defaults and switches:\n\n- `docs_url` defaults to `/docs`.\n- `redoc_url` defaults to `/redoc`; set `None` to disable it.\n- `openapi_url` controls the raw schema endpoint.\n- `redirect_slashes=True` is the default and redirects `/items` to `/items/` when needed.\n\n### Environment settings\n\nFastAPI's docs use `pydantic-settings` for config instead of `pydantic.BaseSettings`.\n\n```python\nfrom functools import lru_cache\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom pydantic_settings import BaseSettings\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n\n@lru_cache\ndef get_settings() -> Settings:\n    return Settings()\n\napp = FastAPI()\n\n@app.get(\"/info\")\nasync def info(settings: Annotated[Settings, Depends(get_settings)]):\n    return settings.model_dump()\n```\n\nWhy this pattern matters:\n\n- `@lru_cache` avoids rebuilding settings on every request.\n- dependency-based settings are easy to override in tests.\n- this matches the current upstream guidance for Pydantic v2-era FastAPI.\n\n## Authentication And Security\n\nFastAPI includes helpers for common auth flows. The common OAuth2 bearer pattern starts with `OAuth2PasswordBearer` and a dependency.\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.security import OAuth2PasswordBearer\n\napp = FastAPI()\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n@app.get(\"/items/\")\nasync def read_items(token: Annotated[str, Depends(oauth2_scheme)]):\n    return {\"token\": token}\n```\n\nImportant details:\n\n- `tokenUrl=\"token\"` is relative, so behind a prefix it resolves relative to the app.\n- this only extracts the bearer token; you still need a token-issuing route and validation logic.\n- the interactive docs will expose an `Authorize` button automatically.\n\n## Middleware, Uploads, Background Tasks, Lifespan\n\n### CORS\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\n\napp = FastAPI()\n\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"https://app.example.com\"],\n    allow_credentials=True,\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\n```\n\nDo not use `allow_origins=[\"*\"]` together with credentialed browser auth unless that is truly what you want.\n\n### File uploads\n\nInstall `python-multipart` before using `File()` or `UploadFile`.\n\n```bash\npip install python-multipart\n```\n\n### Background tasks\n\nUse `BackgroundTasks` for simple follow-up work tied to a request, not for durable job queues:\n\n```python\nfrom fastapi import BackgroundTasks, FastAPI\n\napp = FastAPI()\n\ndef write_notification(email: str, message: str = \"\"):\n    with open(\"log.txt\", \"w\") as email_file:\n        email_file.write(f\"notification for {email}: {message}\")\n\n@app.post(\"/send-notification/{email}\")\nasync def send_notification(email: str, background_tasks: BackgroundTasks):\n    background_tasks.add_task(write_notification, email, \"some notification\")\n    return {\"message\": \"Notification sent in the background\"}\n```\n\n### Lifespan\n\nPrefer `lifespan` over `@app.on_event(\"startup\")` and `@app.on_event(\"shutdown\")`.\n\n```python\nfrom contextlib import asynccontextmanager\n\nfrom fastapi import FastAPI\n\nstate = {}\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    state[\"ready\"] = True\n    yield\n    state.clear()\n\napp = FastAPI(lifespan=lifespan)\n```\n\nIf you provide `lifespan`, the old startup/shutdown event handlers will not run.\n\n## Testing\n\nIf you installed plain `fastapi`, add `httpx` first:\n\n```bash\npip install httpx pytest\n```\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n@app.get(\"/\")\nasync def read_main():\n    return {\"msg\": \"Hello World\"}\n\nclient = TestClient(app)\n\ndef test_read_main():\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"msg\": \"Hello World\"}\n```\n\nFor sync tests, keep test functions as normal `def`, not `async def`, unless you are intentionally using async test tooling.\n\n## Common Pitfalls\n\n- Installing only `fastapi` and then assuming `fastapi dev`, `TestClient`, or uploads will work without extra packages.\n- Using `pydantic.BaseSettings` examples from older blog posts instead of `pydantic-settings`.\n- Mixing `lifespan` with old `startup` and `shutdown` handlers and expecting both to execute.\n- Forgetting that `tokenUrl` in `OAuth2PasswordBearer` is relative.\n- Returning non-JSON-serializable objects without a response model or explicit serialization plan.\n- Letting trailing-slash redirects surprise clients; set route shapes consistently or adjust `redirect_slashes`.\n- Assuming file/form support exists without `python-multipart`.\n\n## Version-Sensitive Notes For 0.135.1\n\n- `0.135.1` is a small fix release; upstream notes mention a TaskGroup/yield async-exit-stack fix.\n- `0.135.0` added Server-Sent Events support.\n- `0.134.0` added streaming JSON Lines and binary data with `yield`.\n- `0.132.0` enabled strict JSON `Content-Type` checking by default. Clients that send JSON without a valid JSON content type now fail unless you explicitly disable it with `strict_content_type=False`.\n- `0.131.0` deprecated `ORJSONResponse` and `UJSONResponse`. Avoid introducing new code that depends on those classes unless you are intentionally carrying older patterns.\n- `0.130.0` improved JSON response serialization performance when using Pydantic return types or `response_model`.\n- `0.129.0` dropped Python `3.9` support. Use Python `3.10+`.\n- `0.129.2` also marked `fastapi-slim` as dropped; use `fastapi` or `fastapi[standard]`.\n\n## Official Sources\n\n- FastAPI docs: https://fastapi.tiangolo.com/\n- FastAPI reference: https://fastapi.tiangolo.com/reference/\n- FastAPI first steps: https://fastapi.tiangolo.com/tutorial/first-steps/\n- FastAPI dependencies: https://fastapi.tiangolo.com/tutorial/dependencies/\n- FastAPI settings: https://fastapi.tiangolo.com/advanced/settings/\n- FastAPI security: https://fastapi.tiangolo.com/tutorial/security/first-steps/\n- FastAPI CORS: https://fastapi.tiangolo.com/tutorial/cors/\n- FastAPI lifespan events: https://fastapi.tiangolo.com/advanced/events/\n- FastAPI testing: https://fastapi.tiangolo.com/tutorial/testing/\n- FastAPI release notes: https://fastapi.tiangolo.com/release-notes/\n- PyPI package page: https://pypi.org/project/fastapi/0.135.1/\n"
  },
  {
    "path": "content/fastapi-cache2/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastAPI response and function caching with Redis, Memcached, DynamoDB, and in-memory backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.2.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fastapi,python,cache,redis,memcached,dynamodb,asgi\"\n---\n\n# fastapi-cache2 Python Package Guide\n\n## What It Is\n\n`fastapi-cache2` adds decorator-based caching for FastAPI route handlers and regular Python functions. The package name on PyPI is `fastapi-cache2`, but the import package is `fastapi_cache`.\n\nThe maintainer docs for `0.2.2` document these backends:\n\n- `RedisBackend`\n- `MemcacheBackend`\n- `DynamoBackend`\n- `InMemoryBackend`\n\nFor most FastAPI apps, start with Redis.\n\n## Install\n\n`0.2.2` publishes extras for backend-specific dependencies and declares Python `^3.8` in package metadata.\n\n### Base install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"fastapi-cache2==0.2.2\"\n```\n\n### Redis backend\n\n```bash\npython -m pip install \"fastapi-cache2[redis]==0.2.2\"\n```\n\n### Memcached backend\n\n```bash\npython -m pip install \"fastapi-cache2[memcache]==0.2.2\"\n```\n\n### DynamoDB backend\n\n```bash\npython -m pip install \"fastapi-cache2[dynamodb]==0.2.2\"\n```\n\n### Install everything\n\n```bash\npython -m pip install \"fastapi-cache2[all]==0.2.2\"\n```\n\n## Initialize The Cache Once At Startup\n\nCall `FastAPICache.init(...)` during FastAPI startup or lifespan setup before any decorated endpoint is used.\n\nTypical environment variables:\n\n```bash\nexport REDIS_URL=\"redis://localhost:6379/0\"\nexport FASTAPI_CACHE_PREFIX=\"fastapi-cache\"\n```\n\nRedis-backed setup:\n\n```python\nfrom collections.abc import AsyncIterator\nfrom contextlib import asynccontextmanager\nimport os\n\nfrom fastapi import FastAPI\nfrom redis import asyncio as redis\n\nfrom fastapi_cache import FastAPICache\nfrom fastapi_cache.backends.redis import RedisBackend\n\nREDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379/0\")\nCACHE_PREFIX = os.getenv(\"FASTAPI_CACHE_PREFIX\", \"fastapi-cache\")\n\n\n@asynccontextmanager\nasync def lifespan(_: FastAPI) -> AsyncIterator[None]:\n    redis_client = redis.from_url(REDIS_URL, decode_responses=False)\n    FastAPICache.init(\n        RedisBackend(redis_client),\n        prefix=CACHE_PREFIX,\n        expire=60,\n    )\n    yield\n\n\napp = FastAPI(lifespan=lifespan)\n```\n\nImportant Redis detail:\n\n- Keep `decode_responses=False` on the Redis client. The cache stores raw `bytes`, and response decoding breaks cache reads.\n\nFor local development or tests, you can initialize an in-memory backend instead:\n\n```python\nfrom fastapi_cache import FastAPICache\nfrom fastapi_cache.backends.inmemory import InMemoryBackend\n\nFastAPICache.init(InMemoryBackend(), prefix=\"fastapi-cache\")\n```\n\n## Cache A FastAPI Route\n\nPlace `@cache(...)` between the FastAPI router decorator and the function. The common arguments are:\n\n- `expire`: TTL in seconds\n- `namespace`: logical grouping for related keys\n- `coder`: serializer/deserializer class\n- `key_builder`: custom cache-key function\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\nfrom fastapi_cache.decorator import cache\n\napp = FastAPI()\n\n\nclass UserOut(BaseModel):\n    id: int\n    email: str\n\n\n@app.get(\"/users/{user_id}\")\n@cache(expire=300, namespace=\"users\")\nasync def get_user(user_id: int) -> UserOut:\n    return UserOut(id=user_id, email=f\"user-{user_id}@example.com\")\n```\n\nWhat the decorator does for HTTP endpoints:\n\n- Adds `Cache-Control`\n- Adds `ETag`\n- Adds `X-FastAPI-Cache` with `HIT` or `MISS`\n- Returns `304 Not Modified` when the request sends a matching `If-None-Match`\n\n## Return Types Matter\n\nWith the default `JsonCoder`, cached values round-trip correctly for JSON-compatible types, Pydantic models, and dataclasses only when the function itself has the right return annotation.\n\nUse this:\n\n```python\n@app.get(\"/profile\")\n@cache(expire=60)\nasync def profile() -> UserOut:\n    return UserOut(id=1, email=\"a@example.com\")\n```\n\nDo not rely on only `response_model=...` in the route decorator. The cache decodes using the function return type, not the FastAPI route metadata.\n\n## Cache Regular Functions Too\n\nThe same decorator can wrap non-route functions. This is useful for expensive service-layer work shared by multiple endpoints.\n\n```python\nfrom fastapi_cache.decorator import cache\n\n\n@cache(expire=30, namespace=\"reports\")\ndef build_report(user_id: int) -> dict[str, int]:\n    return {\"user_id\": user_id, \"score\": 42}\n```\n\nThe implementation runs sync functions in FastAPI's threadpool so the decorator can be awaited consistently.\n\n## Custom Serialization\n\nIf your return value needs different JSON encoding behavior, define a custom coder by subclassing `fastapi_cache.Coder`.\n\n```python\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom fastapi_cache import Coder\nfrom fastapi_cache.decorator import cache\n\n\nclass ORJsonCoder(Coder):\n    @classmethod\n    def encode(cls, value: Any) -> bytes:\n        return orjson.dumps(\n            value,\n            default=jsonable_encoder,\n            option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY,\n        )\n\n    @classmethod\n    def decode(cls, value: bytes) -> Any:\n        return orjson.loads(value)\n\n\n@app.get(\"/stats\")\n@cache(expire=60, coder=ORJsonCoder)\nasync def stats() -> dict[str, int]:\n    return {\"hits\": 10}\n```\n\n## Custom Cache Keys\n\nThe built-in key builder hashes the function module, function name, positional args, and keyword args. If you want URL-shaped keys instead, provide a custom `key_builder`.\n\n```python\nfrom typing import Any\n\nfrom fastapi import Request, Response\n\nfrom fastapi_cache.decorator import cache\n\n\ndef request_key_builder(\n    func: Any,\n    namespace: str = \"\",\n    *,\n    request: Request | None = None,\n    response: Response | None = None,\n    args: tuple[Any, ...],\n    kwargs: dict[str, Any],\n) -> str:\n    assert request is not None\n    return \":\".join(\n        [\n            namespace,\n            request.method.lower(),\n            request.url.path,\n            repr(sorted(request.query_params.items())),\n        ]\n    )\n\n\n@app.get(\"/search\")\n@cache(expire=120, key_builder=request_key_builder)\nasync def search(q: str) -> dict[str, str]:\n    return {\"query\": q}\n```\n\nYou can pass a key builder per route, or set one globally in `FastAPICache.init(...)`.\n\n## Common Pitfalls\n\n- Initialize `FastAPICache` before the first cached call. The package raises if you use cache access before `init(...)`.\n- Keep `@cache(...)` below `@app.get(...)` or the equivalent router decorator.\n- Route-handler caching is HTTP-oriented. Non-`GET` requests bypass the cache.\n- A request with `Cache-Control: no-store` bypasses caching entirely.\n- A request with `Cache-Control: no-cache` refreshes the cached value instead of serving the current stored value.\n- If you use `InMemoryBackend`, expired entries are only removed when the key is accessed again.\n- Remember that the PyPI package is `fastapi-cache2` but the import path is `fastapi_cache`.\n\n## Version Notes For 0.2.2\n\n- PyPI lists `0.2.2` as the current release, published on July 24, 2024.\n- The maintainer metadata for `0.2.2` declares Python `^3.8`.\n- The published extras for `0.2.2` are `redis`, `memcache`, `dynamodb`, and `all`.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/long2ice/fastapi-cache\n- PyPI project page: https://pypi.org/project/fastapi-cache2/\n- `0.2.2` package metadata: https://raw.githubusercontent.com/long2ice/fastapi-cache/v0.2.2/pyproject.toml\n- Current package source for cache initialization: https://raw.githubusercontent.com/long2ice/fastapi-cache/main/fastapi_cache/__init__.py\n- Current decorator implementation: https://raw.githubusercontent.com/long2ice/fastapi-cache/main/fastapi_cache/decorator.py\n- Current default key builder: https://raw.githubusercontent.com/long2ice/fastapi-cache/main/fastapi_cache/key_builder.py\n- Current coder implementations: https://raw.githubusercontent.com/long2ice/fastapi-cache/main/fastapi_cache/coder.py\n"
  },
  {
    "path": "content/fastapi-limiter/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"fastapi-limiter request rate limiting for FastAPI routes, middleware, and websockets using pyrate-limiter\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fastapi,rate-limiting,pyrate-limiter,websocket,middleware,python\"\n---\n\n# fastapi-limiter Python Package Guide\n\n## Golden Rule\n\nUse the current `0.2.0` API built around `pyrate_limiter.Limiter`.\n\nInstall:\n\n```bash\npython -m pip install \"fastapi-limiter==0.2.0\"\n```\n\n`fastapi-limiter 0.2.0` requires Python 3.9+ and depends on FastAPI 0.115.8+ and `pyrate-limiter 3.9+`.\n\nDo not copy older `0.1.x` examples that import `FastAPILimiter` and call `FastAPILimiter.init(...)` with Redis. The current maintainer README and source use route dependencies, middleware, and websocket limiters backed by `pyrate-limiter`.\n\n## Minimal Route Limit\n\nThis is the smallest working setup for an HTTP route.\n\n```python\nimport os\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi_limiter.depends import RateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\nREQUESTS_PER_WINDOW = int(os.getenv(\"RATE_LIMIT_TIMES\", \"20\"))\nWINDOW_SECONDS = int(os.getenv(\"RATE_LIMIT_WINDOW_SECONDS\", \"60\"))\n\nrate = Rate(REQUESTS_PER_WINDOW, Duration.SECOND * WINDOW_SECONDS)\nlimiter = Limiter(rate)\n\napp = FastAPI()\n\n\n@app.get(\n    \"/search\",\n    dependencies=[\n        Depends(\n            RateLimiter(\n                limiter=limiter,\n                times=REQUESTS_PER_WINDOW,\n                seconds=WINDOW_SECONDS,\n            )\n        )\n    ],\n)\nasync def search(q: str) -> dict[str, str]:\n    return {\"q\": q}\n```\n\n`RateLimiter` is an async dependency. Attach it with `dependencies=[Depends(...)]` when you want to reject requests before your handler runs.\n\n## Custom Identifier\n\nBy default, the package identifies clients from `X-Forwarded-For` when present, otherwise `request.client.host`, and appends the request path. Override `identifier` if you want per-user limits or different keying.\n\n```python\nfrom fastapi import Depends, FastAPI, Request\nfrom fastapi_limiter.depends import RateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\nlimiter = Limiter(Rate(5, Duration.SECOND * 60))\n\n\nasync def user_or_ip_identifier(request: Request) -> str:\n    user_id = request.headers.get(\"x-user-id\")\n    if user_id:\n        return f\"user:{user_id}\"\n    if request.client:\n        return f\"ip:{request.client.host}\"\n    return \"anonymous\"\n\n\n@app.get(\n    \"/profile\",\n    dependencies=[\n        Depends(\n            RateLimiter(\n                limiter=limiter,\n                times=5,\n                seconds=60,\n                identifier=user_or_ip_identifier,\n            )\n        )\n    ],\n)\nasync def profile() -> dict[str, bool]:\n    return {\"ok\": True}\n```\n\nIf you replace the default identifier, add `request.url.path` yourself when you still want separate budgets per route.\n\n## Custom Rejection Callback\n\nThe dependency callback is awaited with `(request, response)`. Use an async function.\n\n```python\nfrom fastapi import Depends, FastAPI, HTTPException, Request, Response, status\nfrom fastapi_limiter.depends import RateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\nlimiter = Limiter(Rate(2, Duration.SECOND * 60))\n\n\nasync def rate_limit_callback(request: Request, response: Response) -> None:\n    raise HTTPException(\n        status_code=status.HTTP_429_TOO_MANY_REQUESTS,\n        detail=\"Rate limit exceeded\",\n        headers={\"Retry-After\": \"60\"},\n    )\n\n\n@app.get(\n    \"/reports\",\n    dependencies=[\n        Depends(\n            RateLimiter(\n                limiter=limiter,\n                times=2,\n                seconds=60,\n                callback=rate_limit_callback,\n            )\n        )\n    ],\n)\nasync def reports() -> dict[str, str]:\n    return {\"status\": \"ready\"}\n```\n\n## Skip Selected Requests\n\nUse `skip` for routes that should stay public for health checks or internal probes.\n\n```python\nfrom fastapi import Depends, FastAPI, Request\nfrom fastapi_limiter.depends import RateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\nlimiter = Limiter(Rate(10, Duration.SECOND * 60))\n\n\nasync def skip_health_checks(request: Request) -> bool:\n    return request.url.path in {\"/healthz\", \"/readyz\"}\n\n\n@app.get(\n    \"/api\",\n    dependencies=[\n        Depends(\n            RateLimiter(\n                limiter=limiter,\n                times=10,\n                seconds=60,\n                skip=skip_health_checks,\n            )\n        )\n    ],\n)\nasync def api() -> dict[str, bool]:\n    return {\"ok\": True}\n```\n\n## Apply Global Limits With Middleware\n\nUse `RateLimiterMiddleware` when you want one shared limit across the whole app instead of per-route dependencies.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi_limiter.middleware import RateLimiterMiddleware\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\n\napp.add_middleware(\n    RateLimiterMiddleware,\n    limiter=Limiter(Rate(100, Duration.SECOND * 60)),\n    ignore_if_private_loopback=True,\n)\n\n\n@app.get(\"/\")\nasync def index() -> dict[str, str]:\n    return {\"message\": \"ok\"}\n```\n\nThe middleware callback is different from the dependency callback: it receives only `request` and must return a `Response`. The default middleware response is HTTP 429 with `{\"detail\": \"Too Many Requests\"}`.\n\n## Rate Limit WebSocket Messages\n\n`WebSocketRateLimiter` is not registered as a dependency. Create it in the handler and await it after each message you want to count.\n\n```python\nfrom fastapi import FastAPI, WebSocket\nfrom fastapi_limiter.depends import WebSocketRateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\nlimiter = Limiter(Rate(1, Duration.SECOND * 5))\n\n\n@app.websocket(\"/ws\")\nasync def websocket_endpoint(websocket: WebSocket) -> None:\n    await websocket.accept()\n    rate_limit = WebSocketRateLimiter(limiter=limiter, times=1, seconds=5)\n\n    while True:\n        data = await websocket.receive_text()\n        await rate_limit(websocket, context_key=data)\n        await websocket.send_text(f\"echo: {data}\")\n```\n\n`context_key` is optional. Use it when distinct message types should have separate rate buckets.\n\n## Multiple Limits On One Route\n\nYou can stack dependencies:\n\n```python\nfrom fastapi import Depends, FastAPI\nfrom fastapi_limiter.depends import RateLimiter\nfrom pyrate_limiter import Duration, Limiter, Rate\n\napp = FastAPI()\nlimiter = Limiter(Rate(2, Duration.SECOND * 15))\n\n\n@app.get(\n    \"/burst-and-sustained\",\n    dependencies=[\n        Depends(RateLimiter(limiter=limiter, times=1, seconds=5)),\n        Depends(RateLimiter(limiter=limiter, times=2, seconds=15)),\n    ],\n)\nasync def burst_and_sustained() -> dict[str, bool]:\n    return {\"ok\": True}\n```\n\nKeep the smaller `seconds / times` ratio first. The maintainer README calls this out explicitly.\n\n## Common Pitfalls\n\n- `0.2.0` is a different setup model from the Redis-based `0.1.x` line. If a snippet imports `from fastapi_limiter import FastAPILimiter`, it is not the current API.\n- The default identifier includes the request path. A custom identifier does not, unless you add it.\n- `X-Forwarded-For` is only safe when your proxy setup is trusted and normalized. Otherwise, use your own identifier function.\n- Dependency callbacks and `skip` callables are awaited. Write them as `async def`.\n- Middleware callbacks have a different signature from dependency callbacks.\n- If you share one limiter across several routes, your key strategy determines whether traffic is isolated per route or pooled across routes.\n\n## Version Notes For 0.2.0\n\n- PyPI lists `0.2.0` as the current release and the maintainer README now describes the package as being powered by `pyrate-limiter`.\n- The older GitHub release history and older README snapshots refer to Redis, Lua scripts, and `FastAPILimiter.init(...)`. Treat those as pre-`0.2.x` documentation.\n\n## Official Sources\n\n- GitHub repository: https://github.com/long2ice/fastapi-limiter\n- Current maintainer README: https://github.com/long2ice/fastapi-limiter#readme\n- PyPI project page: https://pypi.org/project/fastapi-limiter/\n- Dependency limiter source: https://github.com/long2ice/fastapi-limiter/blob/main/fastapi_limiter/depends.py\n- Middleware source: https://github.com/long2ice/fastapi-limiter/blob/main/fastapi_limiter/middleware.py\n- Default identifier source: https://github.com/long2ice/fastapi-limiter/blob/main/fastapi_limiter/identifier.py\n- GitHub releases page for older `0.1.x` behavior: https://github.com/long2ice/fastapi-limiter/releases\n"
  },
  {
    "path": "content/fastapi-mail/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastAPI-Mail package guide for SMTP email sending, templates, attachments, and background delivery in FastAPI apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fastapi-mail,fastapi,email,smtp,jinja2,attachments,python\"\n---\n\n# FastAPI-Mail Python Package Guide\n\n## Install\n\n`fastapi-mail` 1.6.2 is published on PyPI for Python `>=3.10,<4.0`.\n\nUse a virtual environment and pin the package version your app expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"fastapi-mail==1.6.2\"\n```\n\nOptional extra from the maintainer docs:\n\n```bash\npython -m pip install \"fastapi-mail[httpx]==1.6.2\"\n```\n\nYou still need an SMTP provider or relay. `fastapi-mail` does not send through an API like SendGrid or SES directly; it builds and sends mail through SMTP settings you supply.\n\n## SMTP Configuration\n\nThe package centers on `ConnectionConfig`, `FastMail`, and `MessageSchema`.\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom fastapi_mail import ConnectionConfig\n\n\ndef env_bool(name: str, default: bool = False) -> bool:\n    value = os.getenv(name)\n    if value is None:\n        return default\n    return value.lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n\nconf = ConnectionConfig(\n    MAIL_USERNAME=os.environ[\"MAIL_USERNAME\"],\n    MAIL_PASSWORD=os.environ[\"MAIL_PASSWORD\"],\n    MAIL_FROM=os.environ[\"MAIL_FROM\"],\n    MAIL_SERVER=os.environ[\"MAIL_SERVER\"],\n    MAIL_PORT=int(os.getenv(\"MAIL_PORT\", \"587\")),\n    MAIL_FROM_NAME=os.getenv(\"MAIL_FROM_NAME\", \"Example App\"),\n    MAIL_STARTTLS=env_bool(\"MAIL_STARTTLS\", True),\n    MAIL_SSL_TLS=env_bool(\"MAIL_SSL_TLS\", False),\n    USE_CREDENTIALS=env_bool(\"MAIL_USE_CREDENTIALS\", True),\n    VALIDATE_CERTS=env_bool(\"MAIL_VALIDATE_CERTS\", True),\n    TEMPLATE_FOLDER=Path(__file__).resolve().parent / \"templates\",\n)\n```\n\nTypical environment variables:\n\n```bash\nMAIL_USERNAME=smtp-user-or-email\nMAIL_PASSWORD=app-password-or-smtp-password\nMAIL_FROM=noreply@example.com\nMAIL_FROM_NAME=\"Example App\"\nMAIL_SERVER=smtp.example.com\nMAIL_PORT=587\nMAIL_STARTTLS=true\nMAIL_SSL_TLS=false\nMAIL_USE_CREDENTIALS=true\nMAIL_VALIDATE_CERTS=true\n```\n\nPractical setup notes from the maintainer docs:\n\n- The docs show STARTTLS on port `587` and SSL/TLS on port `465`; match the combination your provider documents.\n- If your provider does not issue a separate SMTP username, use the sending address as `MAIL_USERNAME`.\n- Set `USE_CREDENTIALS=False` only when your relay does not require SMTP authentication.\n\n## Send A Basic HTML Email\n\n`MessageSchema` defines the envelope and body, then `FastMail.send_message()` sends it.\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\napp = FastAPI()\nfm = FastMail(conf)\n\n\nclass EmailRequest(BaseModel):\n    recipients: list[EmailStr]\n\n\n@app.post(\"/email/send\")\nasync def send_email(payload: EmailRequest) -> dict[str, str]:\n    message = MessageSchema(\n        subject=\"Welcome\",\n        recipients=payload.recipients,\n        body=\"\"\"\n        <h1>Thanks for signing up</h1>\n        <p>Your account is ready.</p>\n        \"\"\",\n        subtype=MessageType.html,\n        reply_to=[\"Support <support@example.com>\"],\n        headers={\"X-App-Source\": \"signup-flow\"},\n    )\n\n    await fm.send_message(message)\n    return {\"status\": \"sent\"}\n```\n\nNotes:\n\n- Use `subtype=MessageType.html` for HTML mail and `subtype=MessageType.plain` for plain text.\n- The docs accept display-name formats such as `\"Support <support@example.com>\"` in recipient-related fields.\n- `reply_to`, `cc`, `bcc`, and `headers` are first-class `MessageSchema` fields when you need them.\n\n## Queue Delivery In `BackgroundTasks`\n\nFor typical FastAPI routes, add the send call to `BackgroundTasks` so the response is returned immediately.\n\n```python\nfrom fastapi import BackgroundTasks, FastAPI\nfrom pydantic import BaseModel, EmailStr\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\napp = FastAPI()\nfm = FastMail(conf)\n\n\nclass EmailRequest(BaseModel):\n    recipients: list[EmailStr]\n\n\n@app.post(\"/email/send-later\")\nasync def send_email_later(\n    payload: EmailRequest,\n    background_tasks: BackgroundTasks,\n) -> dict[str, str]:\n    message = MessageSchema(\n        subject=\"Queued welcome email\",\n        recipients=payload.recipients,\n        body=\"<p>This was scheduled with FastAPI BackgroundTasks.</p>\",\n        subtype=MessageType.html,\n    )\n\n    background_tasks.add_task(fm.send_message, message)\n    return {\"status\": \"queued\"}\n```\n\n## Render A Jinja2 Template\n\nSet `TEMPLATE_FOLDER` in `ConnectionConfig`, then pass `template_body` and `template_name`.\n\n```python\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\nfm = FastMail(conf)\n\nmessage = MessageSchema(\n    subject=\"Welcome\",\n    recipients=[\"user@example.com\"],\n    template_body={\n        \"first_name\": \"Ada\",\n        \"dashboard_url\": \"https://example.com/dashboard\",\n    },\n    subtype=MessageType.html,\n)\n\nawait fm.send_message(message, template_name=\"welcome.html\")\n```\n\nExample template:\n\n```html\n<h1>Hello {{ first_name }}</h1>\n<p><a href=\"{{ dashboard_url }}\">Open your dashboard</a></p>\n```\n\nImportant version note from the maintainer docs:\n\n- Current releases render `template_body` keys directly, so use `{{ first_name }}`.\n- The older `{{ body.first_name }}` pattern only applies to versions `<= 0.4.0`.\n\nThe docs also recommend inline CSS for better email client compatibility.\n\n## Send Attachments\n\nThe package accepts FastAPI `UploadFile` objects in `attachments`.\n\n```python\nfrom fastapi import FastAPI, File, Form, UploadFile\nfrom pydantic import EmailStr\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\napp = FastAPI()\nfm = FastMail(conf)\n\n\n@app.post(\"/email/with-attachment\")\nasync def send_with_attachment(\n    recipient: EmailStr = Form(...),\n    file: UploadFile = File(...),\n) -> dict[str, str]:\n    message = MessageSchema(\n        subject=\"Your uploaded file\",\n        recipients=[recipient],\n        body=\"See attached file.\",\n        subtype=MessageType.plain,\n        attachments=[file],\n    )\n\n    await fm.send_message(message)\n    return {\"status\": \"sent\"}\n```\n\nFor inline images or custom attachment headers, the docs show attachment dictionaries with keys such as `file`, `headers`, `mime_type`, and `mime_subtype`.\n\n## Send More Than One Message\n\n`FastMail.send_message()` can send a list of `MessageSchema` objects.\n\n```python\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\nfm = FastMail(conf)\n\nmessages = [\n    MessageSchema(\n        subject=\"Hello Alice\",\n        recipients=[\"alice@example.com\"],\n        body=\"Hi Alice\",\n        subtype=MessageType.plain,\n    ),\n    MessageSchema(\n        subject=\"Hello Bob\",\n        recipients=[\"bob@example.com\"],\n        body=\"Hi Bob\",\n        subtype=MessageType.plain,\n    ),\n]\n\nawait fm.send_message(messages)\n```\n\n## Suppress Sending In Tests\n\nThe maintainer docs include a built-in capture mechanism for tests and local validation flows.\n\n```python\nfrom fastapi_mail import FastMail, MessageSchema, MessageType\n\nfm = FastMail(conf)\nfm.config.SUPPRESS_SEND = 1\n\nmessage = MessageSchema(\n    subject=\"Test message\",\n    recipients=[\"dev@example.com\"],\n    body=\"This should not leave the process.\",\n    subtype=MessageType.plain,\n)\n\nwith fm.record_messages() as outbox:\n    await fm.send_message(message)\n\nassert len(outbox) == 1\nassert outbox[0][\"subject\"] == \"Test message\"\n```\n\n## Common Pitfalls\n\n- `MAIL_USERNAME`, `MAIL_PASSWORD`, and `MAIL_FROM` are separate settings. Do not assume your provider uses the same value for all three.\n- Template rendering depends on `TEMPLATE_FOLDER` being configured correctly and `template_name` matching a real file.\n- Current template examples use top-level keys from `template_body`; copying old `body.<key>` examples into `1.6.2` projects will fail.\n- HTML email clients have weak CSS support. Prefer inline CSS instead of relying on external stylesheets.\n- The maintainer docs still show `fastapi-mail[aioredis]` in one install page, while PyPI metadata for `1.6.2` advertises extras named `httpx` and `redis`. If you need Redis-backed email utilities, check the current package metadata before pinning extras.\n\n## Official Sources\n\n- Maintainer docs: `https://sabuhish.github.io/fastapi-mail/`\n- Getting started and config reference: `https://sabuhish.github.io/fastapi-mail/getting-started/`\n- Message schema and examples: `https://sabuhish.github.io/fastapi-mail/example/`\n- PyPI package page: `https://pypi.org/project/fastapi-mail/`\n"
  },
  {
    "path": "content/fastapi-pagination/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastAPI pagination helpers for page models, query params, and database integrations in Python FastAPI apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.15.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fastapi,pagination,python,sqlalchemy,api\"\n---\n\n# fastapi-pagination Python Package Guide\n\n## Golden Rule\n\nUse `fastapi-pagination` to define the response model and request params for paginated FastAPI endpoints, but use the right paginator for your data source:\n\n- `fastapi_pagination.paginate(...)` for in-memory lists and sequences\n- `fastapi_pagination.ext.sqlalchemy.paginate(...)` for SQLAlchemy queries\n- other `fastapi_pagination.ext.*` modules for supported integrations such as SQLModel, Tortoise ORM, Django, and Mongo-style backends\n\nThe package does not need an API key or a client object. The core setup is importing the page type you want and registering pagination with `add_pagination(app)`.\n\n## Install\n\n`fastapi-pagination 0.15.10` requires Python 3.10 or later.\n\nBase install:\n\n```bash\npython -m pip install \"fastapi-pagination==0.15.10\"\n```\n\nIf you paginate SQLAlchemy queries, install the SQLAlchemy extra:\n\n```bash\npython -m pip install \"fastapi-pagination[sqlalchemy]==0.15.10\"\n```\n\nThe package itself does not use environment variables. If your app paginates database queries, configure the database exactly as that integration expects. For example:\n\n```bash\nDATABASE_URL=sqlite:///./app.db\n```\n\n## Basic FastAPI Setup\n\n`Page[T]` is the default page model. `Params` uses `page` and `size` query parameters.\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\nfrom fastapi_pagination import Page, add_pagination, paginate\n\napp = FastAPI()\n\n\nclass UserOut(BaseModel):\n    id: int\n    email: str\n\n\nusers = [\n    UserOut(id=1, email=\"ada@example.com\"),\n    UserOut(id=2, email=\"grace@example.com\"),\n    UserOut(id=3, email=\"linus@example.com\"),\n]\n\n\n@app.get(\"/users\")\nasync def list_users() -> Page[UserOut]:\n    return paginate(users)\n\n\nadd_pagination(app)\n```\n\nRequest example:\n\n```http\nGET /users?page=1&size=50\n```\n\n## SQLAlchemy Query Pagination\n\nDo not pass a SQLAlchemy query to the generic `fastapi_pagination.paginate`. Use the SQLAlchemy extension instead.\n\n```python\nimport os\nfrom collections.abc import Generator\n\nfrom fastapi import Depends, FastAPI\nfrom pydantic import BaseModel, ConfigDict\nfrom sqlalchemy import Integer, String, create_engine, select\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, sessionmaker\n\nfrom fastapi_pagination import Page, add_pagination\nfrom fastapi_pagination.ext.sqlalchemy import paginate\n\nDATABASE_URL = os.environ.get(\"DATABASE_URL\", \"sqlite:///./app.db\")\n\nengine = create_engine(DATABASE_URL, connect_args={\"check_same_thread\": False})\nSessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)\n\n\nclass Base(DeclarativeBase):\n    pass\n\n\nclass User(Base):\n    __tablename__ = \"users\"\n\n    id: Mapped[int] = mapped_column(Integer, primary_key=True)\n    email: Mapped[str] = mapped_column(String(255), unique=True, index=True)\n\n\nclass UserOut(BaseModel):\n    model_config = ConfigDict(from_attributes=True)\n\n    id: int\n    email: str\n\n\ndef get_session() -> Generator[Session, None, None]:\n    session = SessionLocal()\n    try:\n        yield session\n    finally:\n        session.close()\n\n\napp = FastAPI()\n\n\n@app.get(\"/users\")\ndef list_users(session: Session = Depends(get_session)) -> Page[UserOut]:\n    query = select(User).order_by(User.id)\n    return paginate(session, query)\n\n\nadd_pagination(app)\n```\n\nThis extension paginates at the query level instead of loading every row into memory first.\n\n## Limit-Offset Pagination\n\nUse `LimitOffsetPage[T]` if the API should accept `limit` and `offset` instead of `page` and `size`.\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\nfrom fastapi_pagination import add_pagination, paginate\nfrom fastapi_pagination.limit_offset import LimitOffsetPage\n\napp = FastAPI()\n\n\nclass UserOut(BaseModel):\n    id: int\n    email: str\n\n\n@app.get(\"/users\")\nasync def list_users() -> LimitOffsetPage[UserOut]:\n    data = [\n        UserOut(id=1, email=\"ada@example.com\"),\n        UserOut(id=2, email=\"grace@example.com\"),\n        UserOut(id=3, email=\"linus@example.com\"),\n    ]\n    return paginate(data)\n\n\nadd_pagination(app)\n```\n\nRequest example:\n\n```http\nGET /users?limit=20&offset=40\n```\n\n## Cursor Pagination\n\nUse `CursorPage[T]` when you need stable pagination over an ordered dataset. The docs show cursor pagination with the SQLAlchemy extension.\n\n```python\nfrom fastapi import Depends, FastAPI\nfrom pydantic import BaseModel, ConfigDict\nfrom sqlalchemy import select\nfrom sqlalchemy.orm import Session\n\nfrom fastapi_pagination import add_pagination\nfrom fastapi_pagination.cursor import CursorPage\nfrom fastapi_pagination.ext.sqlalchemy import paginate\n\napp = FastAPI()\n\n\nclass UserOut(BaseModel):\n    model_config = ConfigDict(from_attributes=True)\n\n    id: int\n    email: str\n\n\n@app.get(\"/users\")\ndef list_users(session: Session = Depends(get_session)) -> CursorPage[UserOut]:\n    query = select(User).order_by(User.id)\n    return paginate(session, query)\n\n\nadd_pagination(app)\n```\n\nRequest example:\n\n```http\nGET /users?cursor=<opaque-cursor>\n```\n\nCursor pagination depends on deterministic ordering. Always apply an explicit `order_by(...)` to the query you paginate.\n\n## Customize Query Parameters Or Page Shape\n\nUse `CustomizedPage[...]` and customizers when the default page model is close, but not exactly what you want.\n\nThis example keeps the normal `Page[T]` payload shape and constrains the `page` and `size` query parameters:\n\n```python\nfrom typing import TypeVar\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel\n\nfrom fastapi_pagination import Page, add_pagination, paginate\nfrom fastapi_pagination.customization import CustomizedPage, UseParamsFields\n\nT = TypeVar(\"T\")\n\nCustomPage = CustomizedPage[\n    Page[T],\n    UseParamsFields(\n        page=Query(1, ge=1, description=\"1-based page number\"),\n        size=Query(25, ge=1, le=100, description=\"Items per page\"),\n    ),\n]\n\napp = FastAPI()\n\n\nclass UserOut(BaseModel):\n    id: int\n    email: str\n\n\n@app.get(\"/users\")\nasync def list_users() -> CustomPage[UserOut]:\n    return paginate(\n        [\n            UserOut(id=1, email=\"ada@example.com\"),\n            UserOut(id=2, email=\"grace@example.com\"),\n        ]\n    )\n\n\nadd_pagination(app)\n```\n\nOther documented customizers include renaming the generated page model, moving metadata into response headers, and disabling total-count calculation.\n\n## Common Pitfalls\n\n- The top-level `paginate(...)` helper is for in-memory data. For ORM and database integrations, import `paginate` from the matching `fastapi_pagination.ext.*` module.\n- If you want cursor pagination with SQLAlchemy, install the `sqlalchemy` extra and paginate an ordered query.\n- `Page[T]` and `LimitOffsetPage[T]` use different query parameter names. Pick the page type that matches your public API before clients integrate with it.\n- If your response items come from ORM objects, make sure the response schema can read attributes from those objects. With Pydantic v2, `ConfigDict(from_attributes=True)` is the common fix.\n- For low-level or manual integration, the docs expose `pagination_ctx`, `set_page`, `set_params`, and `create_page`, but most FastAPI routes should use `add_pagination(app)` and a page return type first.\n\n## Version-Sensitive Notes\n\n- In the 0.14 migration guide, `total` became required by default for `Page`, `LimitOffsetPage`, and `CursorPage`. If you intentionally want to skip total-count calculation, use the documented `UseIncludeTotal(False)` customizer.\n- In the 0.13 migration guide, the async paginator function was renamed from `paginate` to `apaginate`. Older async usage still works, but the project recommends updating imports in new code.\n- `fastapi-pagination 0.15.10` still documents Pydantic v1 compatibility through a customization helper, but new FastAPI projects should prefer Pydantic v2-style models.\n\n## Official Sources\n\n- Maintainer docs root: https://uriyyo-fastapi-pagination.netlify.app/\n- First Steps: https://uriyyo-fastapi-pagination.netlify.app/learn/tutorial_user_guide/first_steps/\n- Add to Route: https://uriyyo-fastapi-pagination.netlify.app/learn/tutorial_user_guide/add_to_route/\n- Available page types: https://uriyyo-fastapi-pagination.netlify.app/learn/pagination/techniques/\n- SQLAlchemy integration: https://uriyyo-fastapi-pagination.netlify.app/integrations/sqlalchemy/paginate/\n- Customizers: https://uriyyo-fastapi-pagination.netlify.app/customization/customizers/use_params_fields/\n- Low-level API: https://uriyyo-fastapi-pagination.netlify.app/learn/tutorial_advanced/low_level_api/\n- Migration from v0.14.x: https://uriyyo-fastapi-pagination.netlify.app/migration/0_14_x/\n- Migration from v0.13.x: https://uriyyo-fastapi-pagination.netlify.app/migration/0_13_x/\n- PyPI package page: https://pypi.org/project/fastapi-pagination/\n- Project metadata (`pyproject.toml`): https://raw.githubusercontent.com/uriyyo/fastapi-pagination/main/pyproject.toml\n"
  },
  {
    "path": "content/fastapi-users/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastAPI Users package guide for FastAPI authentication, user management, JWT and cookie auth, and SQLAlchemy integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"15.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"fastapi-users,fastapi,python,auth,users,jwt,cookies,sqlalchemy\"\n---\n\n# FastAPI Users Python Package Guide\n\n## Golden Rule\n\nUse `fastapi-users` to generate auth and user-management routes on top of your own FastAPI models, schemas, and database adapter. The library is configurable, but it is not zero-config: you still need to define a user model, a `UserManager`, at least one authentication backend, and the routers you actually want to expose.\n\nAs of March 13, 2026, PyPI lists `fastapi-users 15.0.4`, requires Python `>=3.10`, and marks the project as in maintenance mode. The package is still supported for security and dependency updates, but the maintainers are not adding new features.\n\n## Install\n\nFor a typical FastAPI + SQLAlchemy setup:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"fastapi-users[sqlalchemy]==15.0.4\"\npython -m pip install \"sqlalchemy[asyncio]\"\npython -m pip install aiosqlite\n```\n\nUse the async driver that matches your database:\n\n- PostgreSQL: `pip install asyncpg`\n- SQLite: `pip install aiosqlite`\n\nOptional extras published on PyPI:\n\n- `fastapi-users[oauth]` for OAuth providers via `httpx-oauth`\n- `fastapi-users[redis]` for Redis-backed tokens\n- `fastapi-users[beanie]` for Beanie instead of SQLAlchemy\n\nEnvironment variables used in the examples below:\n\n```bash\nexport DATABASE_URL=\"sqlite+aiosqlite:///./app.db\"\nexport FASTAPI_USERS_SECRET=\"change-me\"\n```\n\n## Minimal SQLAlchemy Setup\n\nThe official docs use async SQLAlchemy with `SQLAlchemyBaseUserTableUUID` and `SQLAlchemyUserDatabase`. Keep `expire_on_commit=False`; the SQLAlchemy adapter docs call this out explicitly for async sessions.\n\n### `app/db.py`\n\n```python\nimport os\nfrom collections.abc import AsyncGenerator\n\nfrom fastapi import Depends\nfrom fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase\nfrom sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine\nfrom sqlalchemy.orm import DeclarativeBase\n\nDATABASE_URL = os.environ[\"DATABASE_URL\"]\n\nengine = create_async_engine(DATABASE_URL)\nasync_session_maker = async_sessionmaker(engine, expire_on_commit=False)\n\n\nclass Base(DeclarativeBase):\n    pass\n\n\nclass User(SQLAlchemyBaseUserTableUUID, Base):\n    pass\n\n\nasync def create_db_and_tables() -> None:\n    async with engine.begin() as conn:\n        await conn.run_sync(Base.metadata.create_all)\n\n\nasync def get_async_session() -> AsyncGenerator[AsyncSession, None]:\n    async with async_session_maker() as session:\n        yield session\n\n\nasync def get_user_db(\n    session: AsyncSession = Depends(get_async_session),\n) -> AsyncGenerator[SQLAlchemyUserDatabase, None]:\n    yield SQLAlchemyUserDatabase(session, User)\n```\n\n### `app/schemas.py`\n\n```python\nimport uuid\n\nfrom fastapi_users import schemas\n\n\nclass UserRead(schemas.BaseUser[uuid.UUID]):\n    pass\n\n\nclass UserCreate(schemas.BaseUserCreate):\n    pass\n\n\nclass UserUpdate(schemas.BaseUserUpdate):\n    pass\n```\n\n### `app/users.py`\n\n```python\nimport os\nimport uuid\n\nfrom fastapi import Depends, Request\nfrom fastapi_users import BaseUserManager, FastAPIUsers, InvalidPasswordException, UUIDIDMixin\nfrom fastapi_users.authentication import AuthenticationBackend, BearerTransport, JWTStrategy\n\nfrom .db import User, get_user_db\nfrom .schemas import UserCreate\n\nSECRET = os.environ[\"FASTAPI_USERS_SECRET\"]\n\n\nclass UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):\n    reset_password_token_secret = SECRET\n    verification_token_secret = SECRET\n\n    async def validate_password(self, password: str, user: UserCreate | User) -> None:\n        if len(password) < 8:\n            raise InvalidPasswordException(\n                reason=\"Password should be at least 8 characters\"\n            )\n        if user.email in password:\n            raise InvalidPasswordException(\n                reason=\"Password should not contain e-mail\"\n            )\n\n    async def on_after_register(self, user: User, request: Request | None = None) -> None:\n        print(f\"User {user.id} has registered.\")\n\n    async def on_after_forgot_password(\n        self, user: User, token: str, request: Request | None = None\n    ) -> None:\n        print(f\"Reset token for {user.id}: {token}\")\n\n    async def on_after_request_verify(\n        self, user: User, token: str, request: Request | None = None\n    ) -> None:\n        print(f\"Verify token for {user.id}: {token}\")\n\n\nasync def get_user_manager(user_db=Depends(get_user_db)):\n    yield UserManager(user_db)\n\n\nbearer_transport = BearerTransport(tokenUrl=\"auth/jwt/login\")\n\n\ndef get_jwt_strategy() -> JWTStrategy:\n    return JWTStrategy(secret=SECRET, lifetime_seconds=3600)\n\n\nauth_backend = AuthenticationBackend(\n    name=\"jwt\",\n    transport=bearer_transport,\n    get_strategy=get_jwt_strategy,\n)\n\nfastapi_users = FastAPIUsers[User, uuid.UUID](get_user_manager, [auth_backend])\ncurrent_active_user = fastapi_users.current_user(active=True)\ncurrent_verified_user = fastapi_users.current_user(active=True, verified=True)\n```\n\n### `app/main.py`\n\n```python\nfrom contextlib import asynccontextmanager\n\nfrom fastapi import Depends, FastAPI\n\nfrom .db import User, create_db_and_tables\nfrom .schemas import UserCreate, UserRead, UserUpdate\nfrom .users import auth_backend, current_active_user, current_verified_user, fastapi_users\n\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    await create_db_and_tables()\n    yield\n\n\napp = FastAPI(lifespan=lifespan)\n\napp.include_router(\n    fastapi_users.get_auth_router(auth_backend),\n    prefix=\"/auth/jwt\",\n    tags=[\"auth\"],\n)\napp.include_router(\n    fastapi_users.get_register_router(UserRead, UserCreate),\n    prefix=\"/auth\",\n    tags=[\"auth\"],\n)\napp.include_router(\n    fastapi_users.get_reset_password_router(),\n    prefix=\"/auth\",\n    tags=[\"auth\"],\n)\napp.include_router(\n    fastapi_users.get_verify_router(UserRead),\n    prefix=\"/auth\",\n    tags=[\"auth\"],\n)\napp.include_router(\n    fastapi_users.get_users_router(UserRead, UserUpdate),\n    prefix=\"/users\",\n    tags=[\"users\"],\n)\n\n\n@app.get(\"/protected-route\")\nasync def protected_route(user: User = Depends(current_active_user)):\n    return {\"id\": str(user.id), \"email\": user.email}\n\n\n@app.get(\"/verified-only\")\nasync def verified_only(user: User = Depends(current_verified_user)):\n    return {\"email\": user.email, \"verified\": user.is_verified}\n```\n\nRun the app:\n\n```bash\nuvicorn app.main:app --reload\n```\n\nFor production schema changes, use Alembic migrations instead of relying on `Base.metadata.create_all()`.\n\n## Auth Backends: Bearer vs Cookie\n\nAn authentication backend is `transport + strategy`.\n\n- `BearerTransport` is the simplest choice for APIs and mobile clients. It expects `Authorization: Bearer <token>`.\n- `CookieTransport` is better for browser-based flows because the browser stores and resends the auth cookie automatically.\n- `JWTStrategy` is stateless. The official JWT docs note that logout does not invalidate an issued JWT on the server side; it remains valid until it expires.\n- If you need server-side revocation, use a stateful strategy such as Redis instead of JWT.\n\nCookie transport example:\n\n```python\nfrom fastapi_users.authentication import CookieTransport\n\ncookie_transport = CookieTransport(\n    cookie_max_age=3600,\n    cookie_secure=True,\n    cookie_samesite=\"lax\",\n)\n```\n\nImportant cookie defaults from the official docs:\n\n- `cookie_secure=True`\n- `cookie_httponly=True`\n- `cookie_samesite=\"lax\"`\n\nFor local HTTP development, set secure cookie flags to `False` where needed. The OAuth docs call this out for the CSRF cookie as well.\n\n## Common Route Flow\n\nFastAPI Users only exposes the routers you include. The usual set is:\n\n- auth router: `/auth/jwt/login`, `/auth/jwt/logout`\n- register router: `/auth/register`\n- reset password router: `/auth/forgot-password`, `/auth/reset-password`\n- verify router: `/auth/request-verify-token`, `/auth/verify`\n- users router: `/users/me` and superuser-only `/users/{user_id}` routes\n\n### Register\n\n```bash\ncurl -X POST http://127.0.0.1:8000/auth/register \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"user@example.com\",\"password\":\"strong-password\"}'\n```\n\n### Log in with the JWT backend\n\nThe login route expects `application/x-www-form-urlencoded`, not JSON, and the email goes in a field named `username`.\n\n```bash\ncurl -X POST http://127.0.0.1:8000/auth/jwt/login \\\n  -H 'Content-Type: application/x-www-form-urlencoded' \\\n  -d 'username=user@example.com&password=strong-password'\n```\n\nSuccessful bearer login returns:\n\n```json\n{\n  \"access_token\": \"jwt-token\",\n  \"token_type\": \"bearer\"\n}\n```\n\n### Call an authenticated route\n\n```bash\ncurl http://127.0.0.1:8000/users/me \\\n  -H 'Authorization: Bearer jwt-token'\n```\n\n### Request email verification and password reset\n\n```bash\ncurl -X POST http://127.0.0.1:8000/auth/request-verify-token \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"user@example.com\"}'\n\ncurl -X POST http://127.0.0.1:8000/auth/forgot-password \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"user@example.com\"}'\n```\n\nBoth routes intentionally return `202 Accepted` even when the account does not exist, to avoid leaking which emails are registered.\n\nIf you want to block login and user routes until the email is verified, enable `requires_verification=True` when generating those routers:\n\n```python\napp.include_router(\n    fastapi_users.get_auth_router(auth_backend, requires_verification=True),\n    prefix=\"/auth/jwt\",\n    tags=[\"auth\"],\n)\napp.include_router(\n    fastapi_users.get_users_router(\n        UserRead,\n        UserUpdate,\n        requires_verification=True,\n    ),\n    prefix=\"/users\",\n    tags=[\"users\"],\n)\n```\n\n## OAuth\n\nFastAPI Users can generate OAuth routers, but OAuth support is optional and requires the `oauth` extra:\n\n```bash\npython -m pip install \"fastapi-users[sqlalchemy,oauth]==15.0.4\"\n```\n\nThe official docs use `httpx-oauth` clients and generate a router like this:\n\n```python\napp.include_router(\n    fastapi_users.get_oauth_router(google_oauth_client, auth_backend, SECRET),\n    prefix=\"/auth/google\",\n    tags=[\"auth\"],\n)\n```\n\nThe OAuth flow sets a CSRF cookie. In local development without HTTPS, the docs recommend setting the OAuth CSRF cookie's `secure` flag to `False` so the browser actually sends it.\n\n## Password Hashing\n\nCurrent FastAPI Users docs use `pwdlib`. By default, the library hashes passwords with Argon2 and keeps backwards compatibility with Bcrypt hashes.\n\nIf you need to customize the password helper:\n\n```python\nfrom fastapi_users.password import PasswordHelper\nfrom pwdlib import PasswordHash\nfrom pwdlib.hashers.argon2 import Argon2Hasher\n\npassword_hash = PasswordHash((Argon2Hasher(),))\npassword_helper = PasswordHelper(password_hash)\n\n\nasync def get_user_manager(user_db=Depends(get_user_db)):\n    yield UserManager(user_db, password_helper)\n```\n\nThis is version-sensitive: older FastAPI Users articles often show Passlib and BCrypt-only configuration. That does not match the current password-hash docs.\n\n## Common Pitfalls\n\n- Do not forget the database driver. `fastapi-users[sqlalchemy]` does not replace `asyncpg` or `aiosqlite`.\n- Keep `expire_on_commit=False` for async SQLAlchemy sessions or you will hit confusing expired-instance behavior.\n- `UserManager` owns password validation, verification tokens, reset tokens, and lifecycle hooks. Do not try to bolt those back onto router callbacks from old examples.\n- `POST /auth/jwt/login` uses form data with `username=<email>`, not a JSON body.\n- `current_user(active=True, verified=True, superuser=True)` changes the response status on failure: unauthenticated or inactive requests become `401`, while verified and superuser checks fail with `403`.\n- With JWT, logout is not token revocation. Keep `lifetime_seconds` short enough for your threat model or switch to Redis/database-backed sessions.\n- `create_all()` is acceptable for a minimal demo, not for long-lived production schema management.\n\n## Version Notes For 15.0.4\n\n- PyPI shows `15.0.4` released on February 5, 2026.\n- PyPI currently requires Python `>=3.10`.\n- Published extras are `sqlalchemy`, `beanie`, `redis`, and `oauth`.\n- The project is in maintenance mode, so plan around stability rather than new feature work.\n\n## Official Sources\n\n- Documentation root: https://fastapi-users.github.io/fastapi-users/latest/\n- Installation: https://fastapi-users.github.io/fastapi-users/latest/installation/\n- SQLAlchemy adapter: https://fastapi-users.github.io/fastapi-users/latest/configuration/databases/sqlalchemy/\n- Full example: https://fastapi-users.github.io/fastapi-users/latest/configuration/full-example/\n- User manager: https://fastapi-users.github.io/fastapi-users/latest/configuration/user-manager/\n- Schemas: https://fastapi-users.github.io/fastapi-users/latest/configuration/schemas/\n- Auth router: https://fastapi-users.github.io/fastapi-users/latest/configuration/routers/auth/\n- Register router: https://fastapi-users.github.io/fastapi-users/latest/configuration/routers/register/\n- Verify router: https://fastapi-users.github.io/fastapi-users/latest/configuration/routers/verify/\n- Routes usage: https://fastapi-users.github.io/fastapi-users/latest/usage/routes/\n- Current user dependency: https://fastapi-users.github.io/fastapi-users/latest/usage/current-user/\n- Cookie transport: https://fastapi-users.github.io/fastapi-users/latest/configuration/authentication/transports/cookie/\n- JWT strategy: https://fastapi-users.github.io/fastapi-users/latest/configuration/authentication/strategies/jwt/\n- OAuth: https://fastapi-users.github.io/fastapi-users/latest/configuration/oauth/\n- Password hash: https://fastapi-users.github.io/fastapi-users/latest/configuration/password-hash/\n- PyPI package page: https://pypi.org/project/fastapi-users/\n"
  },
  {
    "path": "content/fastmcp/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"FastMCP Python package for building MCP servers, clients, and apps with typed tools, resources, prompts, transports, and auth\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"fastmcp,mcp,python,agents,tools,client,server,oauth\"\n---\n\n# FastMCP Python Package Guide\n\n## Golden Rule\n\nUse `fastmcp` for both MCP servers and MCP clients, import the main APIs from `fastmcp`, and pin the version you expect. The official docs site tracks FastMCP's `main` branch, not a frozen release branch, so check version badges before copying newer examples into a project pinned to `3.1.0`.\n\n## Install\n\nFastMCP officially recommends `uv`, but standard `pip` is also documented:\n\n```bash\npython -m pip install \"fastmcp==3.1.0\"\nuv add \"fastmcp==3.1.0\"\n```\n\nVerify the install:\n\n```bash\nfastmcp version\n```\n\nUseful extras published on PyPI:\n\n```bash\npython -m pip install \"fastmcp[tasks]==3.1.0\"\npython -m pip install \"fastmcp[apps]==3.1.0\"\npython -m pip install \"fastmcp[openai]==3.1.0\"\n```\n\nOther extras listed on PyPI are `anthropic`, `azure`, `code-mode`, and `gemini`.\n\n## Create A Server\n\nFastMCP wraps ordinary Python callables as MCP tools, resources, and prompts. Type hints and docstrings become MCP schemas and descriptions automatically.\n\n```python\nfrom fastmcp import Context, FastMCP\n\nmcp = FastMCP(\n    name=\"SupportServer\",\n    instructions=\"Use the available tools and resources to answer support questions.\",\n)\n\n@mcp.tool\nasync def get_ticket_status(ticket_id: str, ctx: Context) -> dict:\n    \"\"\"Look up a support ticket.\"\"\"\n    await ctx.info(f\"Looking up {ticket_id}\")\n    return {\"ticket_id\": ticket_id, \"status\": \"open\"}\n\n@mcp.resource(\"config://support\")\ndef support_config() -> dict:\n    \"\"\"Expose read-only configuration to clients.\"\"\"\n    return {\"queue\": \"tier-1\", \"region\": \"us-west-2\"}\n\n@mcp.prompt\ndef summarize_ticket(ticket_id: str) -> str:\n    \"\"\"Create a reusable prompt for ticket summaries.\"\"\"\n    return f\"Summarize the latest activity for ticket {ticket_id}.\"\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\nPractical notes:\n\n- `@mcp.tool` is for executable actions.\n- `@mcp.resource(\"scheme://...\")` is for read-only content or templates addressed by URI.\n- `@mcp.prompt` is for reusable prompt/message templates.\n- Tool schemas come from function signatures. Avoid `*args` and `**kwargs` for tools.\n- Use `Context` when a tool needs MCP features like logging, progress, resource reads, or client sampling.\n\n## Run And Test The Server\n\nDefault transport is STDIO, which is what local desktop/editor MCP integrations commonly expect:\n\n```bash\npython my_server.py\nfastmcp run my_server.py:mcp\n```\n\nFor remote access, use HTTP transport:\n\n```bash\nfastmcp run my_server.py:mcp --transport http --port 8000\n```\n\nEquivalent in code:\n\n```python\nif __name__ == \"__main__\":\n    mcp.run(transport=\"http\", host=\"127.0.0.1\", port=8000)\n```\n\nHTTP servers are exposed at `http://localhost:8000/mcp`. SSE is still supported for older clients, but the docs recommend HTTP/Streamable HTTP for new work.\n\nFastMCP's CLI is useful for agent workflows and smoke tests:\n\n```bash\nfastmcp list my_server.py --resources --prompts\nfastmcp call my_server.py get_ticket_status ticket_id=T-123 --json\n```\n\n`fastmcp list --json` and `fastmcp call --json` are explicitly documented for LLM agents that can execute shell commands but do not have native MCP support.\n\n## Use The Programmatic Client\n\n`Client` infers transport from what you pass in:\n\n- `Client(FastMCP(...))`: in-memory transport, best for tests\n- `Client(\"my_server.py\")`: STDIO subprocess transport\n- `Client(\"https://example.com/mcp\")`: HTTP transport\n- `Client(config_dict)`: multi-server config using MCP-style config dictionaries\n\nBasic usage:\n\n```python\nimport asyncio\n\nfrom fastmcp import Client\n\nasync def main() -> None:\n    async with Client(\"http://localhost:8000/mcp\") as client:\n        await client.ping()\n\n        tools = await client.list_tools()\n        print([tool.name for tool in tools])\n\n        result = await client.call_tool(\"get_ticket_status\", {\"ticket_id\": \"T-123\"})\n        print(result.data)\n\n        resources = await client.list_resources()\n        print([resource.uri for resource in resources])\n\n        prompt = await client.get_prompt(\"summarize_ticket\", {\"ticket_id\": \"T-123\"})\n        print(prompt.messages)\n\nasyncio.run(main())\n```\n\nImportant client behavior:\n\n- Always use `async with client:` so the connection and MCP initialization handshake happen cleanly.\n- For local script targets, pass required environment variables with `env={...}` because STDIO subprocesses do not inherit your application state automatically.\n- Use in-memory `Client(server)` for unit tests when you do not want subprocess or network complexity.\n- If you need full control over timing, set `auto_initialize=False` and call `await client.initialize()` yourself.\n\n## Authentication And Configuration\n\nServer-side authentication applies only to HTTP-based transports (`http` and `sse`), not STDIO. Configure auth providers in code and load secrets from environment variables.\n\nExample pattern from the official auth docs:\n\n```python\nimport os\n\nfrom fastmcp import FastMCP\nfrom fastmcp.server.auth.providers.github import GitHubProvider\n\nauth = GitHubProvider(\n    client_id=os.environ[\"GITHUB_CLIENT_ID\"],\n    client_secret=os.environ[\"GITHUB_CLIENT_SECRET\"],\n    base_url=os.environ.get(\"BASE_URL\", \"http://localhost:8000\"),\n)\n\nmcp = FastMCP(name=\"SecureServer\", auth=auth)\n```\n\nFor service-to-service protection without an OAuth login flow, FastMCP also supports bearer-token verification, including `StaticTokenVerifier` for development and other token verifier backends for production.\n\nClient auth options for HTTP targets:\n\n- `auth=\"oauth\"` for interactive OAuth with browser-based login\n- `auth=OAuth(...)` when you need scopes, token storage, or pre-registered client credentials\n- `auth=\"YOUR_TOKEN\"` for bearer-token auth\n- CLI: `fastmcp call http://localhost:8000/mcp my_tool --auth none` to skip OAuth against local dev servers\n\nIf you persist OAuth tokens, use encrypted storage in production.\n\n## Common Pitfalls\n\n- The docs site reflects `main`, not a release-specific snapshot. A page can describe features newer than your installed `3.1.0`.\n- Some docs pages still show example output from `3.0.0` while PyPI currently publishes `3.1.0`; trust version badges and PyPI release metadata when they disagree.\n- HTTP and STDIO are not interchangeable operationally. STDIO is local-process oriented; HTTP is for deployed services and remote clients.\n- SSE is legacy. Use HTTP unless you specifically need compatibility with older clients.\n- Tools need schema-friendly signatures. Do not expose `*args` or `**kwargs` as tools.\n- Client code must use `async with`; calling operations on an unentered client is a common mistake.\n- Local subprocess clients need explicit `env={...}` for secrets and config.\n- Prompt arguments arrive over MCP as strings. FastMCP helps with typed conversion, but complex prompt inputs still need JSON-string-compatible formats at the protocol boundary.\n\n## Version-Sensitive Notes For 3.1.0\n\n- PyPI lists `fastmcp 3.1.0` as the latest release on March 12, 2026.\n- The FastMCP docs are currently branded as `v3`, but the welcome page explicitly says the site tracks the `main` branch and may include unreleased features.\n- The CLI surface for agent workflows, including `fastmcp list` and `fastmcp call`, is documented as new in `3.0.0`; those commands are stable enough to rely on in `3.1.0`.\n- CIMD and pre-registered OAuth client flows are also documented as `3.0.0` features, so they are in scope for `3.1.0`.\n- If you are migrating old FastMCP v2 code, use the official upgrade guides instead of mixing v2 docs paths with current v3 examples.\n\n## Official Sources\n\n- Docs root: https://gofastmcp.com/\n- Welcome: https://gofastmcp.com/getting-started/welcome\n- Installation: https://gofastmcp.com/getting-started/installation\n- Quickstart: https://gofastmcp.com/getting-started/quickstart\n- Server overview: https://gofastmcp.com/servers/server\n- Tools: https://gofastmcp.com/servers/tools\n- Resources: https://gofastmcp.com/servers/resources\n- Client: https://gofastmcp.com/clients/client\n- Client CLI: https://gofastmcp.com/clients/cli\n- Server auth: https://gofastmcp.com/servers/auth/authentication\n- Token verification: https://gofastmcp.com/servers/auth/token-verification\n- Client OAuth auth: https://gofastmcp.com/clients/auth/oauth\n- Client bearer auth: https://gofastmcp.com/clients/auth/bearer\n- PyPI: https://pypi.org/project/fastmcp/\n"
  },
  {
    "path": "content/feast/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"feast package guide for Python feature repositories, feature views, materialization, online retrieval, and remote serving\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"feast,python,feature-store,ml,mlops,features,serving\"\n---\n\n# feast Python Package Guide\n\n## Golden Rule\n\n- Treat Feast as a feature repository plus registry and serving workflow, not as a standalone helper library.\n- Start from `feast init` and keep the real source of truth in `feature_store.yaml` and your Python feature definitions.\n- Use the local provider only for development and experiments. For shared or production use, move to the documented remote registry and online store backends.\n\n## Install\n\nBase install:\n\n```bash\npython -m pip install \"feast==0.61.0\"\n```\n\nFeast publishes provider and integration extras on PyPI. Install the extra that matches your actual backend stack instead of pulling everything into the environment.\n\nCommon examples:\n\n```bash\npython -m pip install \"feast[aws]==0.61.0\"\npython -m pip install \"feast[gcp]==0.61.0\"\npython -m pip install \"feast[azure]==0.61.0\"\npython -m pip install \"feast[snowflake,redis]==0.61.0\"\n```\n\nIf your repo uses a specific offline store, online store, or infra integration, keep the matching extra pinned with the base package version.\n\n## Initialize A Feature Repository\n\nCreate a repo with the built-in scaffold:\n\n```bash\nfeast init my_feature_repo\ncd my_feature_repo/feature_repo\n```\n\nThe generated repo centers on `feature_store.yaml`. A local development config looks like this:\n\n```yaml\nproject: my_project\nprovider: local\nregistry: data/registry.db\nonline_store:\n  type: sqlite\n  path: data/online_store.db\noffline_store:\n  type: file\nentity_key_serialization_version: 3\n```\n\nThe local registry documentation explicitly says this mode is intended for experimentation only. Do not treat `registry.db` on a local filesystem as a shared production registry.\n\n## Minimal Definitions\n\nFeast repositories are ordinary Python files that declare entities, data sources, feature views, and optional feature services:\n\n```python\nfrom datetime import timedelta\n\nfrom feast import Entity, FeatureService, FeatureView, Field, FileSource\nfrom feast.types import Float32, Int64\n\ndriver = Entity(name=\"driver\", join_keys=[\"driver_id\"])\n\ndriver_stats_source = FileSource(\n    name=\"driver_hourly_stats_source\",\n    path=\"data/driver_stats.parquet\",\n    timestamp_field=\"event_timestamp\",\n    created_timestamp_column=\"created\",\n)\n\ndriver_stats_fv = FeatureView(\n    name=\"driver_hourly_stats\",\n    entities=[driver],\n    ttl=timedelta(days=1),\n    schema=[\n        Field(name=\"conv_rate\", dtype=Float32),\n        Field(name=\"acc_rate\", dtype=Float32),\n        Field(name=\"avg_daily_trips\", dtype=Int64),\n    ],\n    online=True,\n    batch_source=driver_stats_source,\n)\n\ndriver_activity_v1 = FeatureService(\n    name=\"driver_activity_v1\",\n    features=[driver_stats_fv],\n)\n```\n\nAfter editing definitions, update the registry:\n\n```bash\nfeast apply\n```\n\n`feast apply` is not optional. Editing Python files without applying them leaves the registry and serving state stale.\n\n## Core Usage\n\n### Open The Store\n\n```python\nfrom feast import FeatureStore\n\nstore = FeatureStore(repo_path=\".\")\n```\n\n### Materialize Batch Data Into The Online Store\n\nUse CLI materialization for the common case:\n\n```bash\nfeast materialize-incremental now\n```\n\nOr call it from Python when you already control the process:\n\n```python\nfrom datetime import datetime, timezone\n\nfrom feast import FeatureStore\n\nstore = FeatureStore(repo_path=\".\")\nstore.materialize_incremental(end_date=datetime.now(timezone.utc))\n```\n\n### Retrieve Historical Features\n\nHistorical retrieval uses an entity dataframe and returns a retrieval job:\n\n```python\nimport pandas as pd\nfrom feast import FeatureStore\n\nstore = FeatureStore(repo_path=\".\")\n\nentity_df = pd.DataFrame.from_dict(\n    {\n        \"driver_id\": [1001, 1002],\n        \"event_timestamp\": [\n            \"2024-01-01T10:00:00Z\",\n            \"2024-01-01T11:00:00Z\",\n        ],\n    }\n)\n\ntraining_df = store.get_historical_features(\n    entity_df=entity_df,\n    features=[\n        \"driver_hourly_stats:conv_rate\",\n        \"driver_hourly_stats:acc_rate\",\n        \"driver_hourly_stats:avg_daily_trips\",\n    ],\n).to_df()\n```\n\n### Retrieve Online Features\n\nOnline retrieval expects entity rows and feature references or a feature service:\n\n```python\nfrom feast import FeatureStore\n\nstore = FeatureStore(repo_path=\".\")\n\nonline_response = store.get_online_features(\n    features=[\n        \"driver_hourly_stats:conv_rate\",\n        \"driver_hourly_stats:acc_rate\",\n    ],\n    entity_rows=[{\"driver_id\": 1001}, {\"driver_id\": 1002}],\n).to_dict()\n```\n\nWith a feature service:\n\n```python\nfrom feast import FeatureStore\n\nstore = FeatureStore(repo_path=\".\")\n\nonline_response = store.get_online_features(\n    features=store.get_feature_service(\"driver_activity_v1\"),\n    entity_rows=[{\"driver_id\": 1001}],\n).to_dict()\n```\n\nIf online results are empty, check materialization first. Feast will not infer or backfill the online store automatically just because the offline source has data.\n\n## Config And Auth\n\n### `feature_store.yaml` Is The Primary Config Surface\n\nProject name, provider, registry backend, online store backend, offline store backend, and auth settings belong in `feature_store.yaml`. Avoid scattering the same connection details across helper modules and environment-specific Python code.\n\n### Remote Registry\n\nFor a shared registry server, the documented client config is:\n\n```yaml\nregistry:\n  registry_type: remote\n  path: localhost:6570\n  cache_ttl_seconds: 60\n```\n\nStart the registry server with:\n\n```bash\nfeast serve_registry\n```\n\nThe registry server exposes:\n\n- REST on `6570`\n- gRPC on `6572`\n\nUse the REST port in `feature_store.yaml` for the remote registry `path`. Pointing the remote registry config at `6572` is a common mistake.\n\n### Remote Online Store And Python Feature Server\n\nFor online serving through the Python feature server:\n\n```yaml\nonline_store:\n  type: remote\n  path: localhost:6566\n  secure: false\n  auth:\n    type: no_auth\n```\n\nStart the server with:\n\n```bash\nfeast serve\n```\n\nThe default feature server port is `6566`. For TLS, the docs use:\n\n```bash\nfeast serve --key server.key --cert server.crt\n```\n\nThe current docs describe `NoAuthManager` as the default auth manager. If you enable OIDC or Kubernetes auth, keep the client-side `auth:` config aligned with the server-side auth manager settings. Feast does not mint credentials for you.\n\n### Cleanup For Remote Clients\n\nThe remote online store docs recommend closing the store or using a context manager so pooled connections are cleaned up:\n\n```python\nfrom feast import FeatureStore\n\nwith FeatureStore(repo_path=\".\") as store:\n    response = store.get_online_features(\n        features=[\"driver_hourly_stats:conv_rate\"],\n        entity_rows=[{\"driver_id\": 1001}],\n    ).to_dict()\n```\n\n## Common Pitfalls\n\n### Editing Definitions Without Running `feast apply`\n\nYour Python definitions are not live until the registry is updated.\n\n### Missing Backend Extras\n\nBase `feast` does not magically install every provider dependency. Missing extras usually show up as import or connection errors when you switch to cloud or warehouse backends.\n\n### Treating The Local Registry As Production Infrastructure\n\nThe local registry docs explicitly position it for experimentation. Shared environments should use the remote registry path instead.\n\n### Querying Online Features Before Materialization\n\nOnline retrieval only returns data that has been materialized or pushed into the online store.\n\n### Wrong Port For Remote Services\n\n- Remote registry config uses REST `6570`\n- Registry server gRPC is `6572`\n- Python feature server defaults to `6566`\n\n### Feature References Must Match Repo Names\n\nStrings like `\"driver_hourly_stats:conv_rate\"` are name-sensitive. If you rename a feature view or service, update the retrieval code and re-run `feast apply`.\n\n## Version-Sensitive Notes\n\n- The version used here `0.61.0` matches the currently published PyPI version on `2026-03-12`.\n- The current Feast docs identify the live content as `v0.61-branch`, which aligns with the version used here for this package session.\n- PyPI now requires Python `>=3.10`, so older project environments on Python `3.9` will need either a Feast downgrade or a Python upgrade.\n- The current reference docs document remote registry and remote online store configs directly in `feature_store.yaml`; if you are copying older examples that assume only local sqlite-style setups, expect backend and auth config drift.\n- The local registry page still warns that the local mode is for experimentation only, so production guidance should prefer remote registry/server-backed setups even though local quickstarts still work.\n\n## Official Sources\n\n- Docs home: `https://docs.feast.dev/`\n- Quickstart: `https://docs.feast.dev/getting-started/quickstart`\n- Feature views reference: `https://docs.feast.dev/reference/feature-repository/feature-view`\n- Auth manager reference: `https://docs.feast.dev/reference/auth-manager`\n- Local registry reference: `https://docs.feast.dev/reference/registries/local`\n- Remote registry reference: `https://docs.feast.dev/reference/registries/remote`\n- Python feature server reference: `https://docs.feast.dev/reference/feature-servers/python-feature-server`\n- Remote online store reference: `https://docs.feast.dev/reference/feature-stores/online-stores/remote`\n- PyPI package page: `https://pypi.org/project/feast/`\n"
  },
  {
    "path": "content/feedparser/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"feedparser Python package guide for parsing RSS and Atom feeds with practical HTTP, normalization, and version-drift notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.12\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"feedparser,rss,atom,feeds,xml,http,syndication\"\n---\n\n# feedparser Python Package Guide\n\n## Golden Rule\n\nUse `feedparser.parse(...)` for feed parsing and normalization, but take control of HTTP yourself when you need authentication, retries, timeouts, or stricter request behavior. For production code, treat parsed feeds as partially structured input: check `bozo`, prefer normalized fields like `entries`, `feed`, and `*_parsed`, and do not assume every feed exposes the same keys.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"feedparser==6.0.12\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"feedparser==6.0.12\"\npoetry add \"feedparser==6.0.12\"\n```\n\n`feedparser` is pure Python. You do not need an API key or service-specific auth just to parse a feed.\n\n## Core Usage\n\n### Parse a remote feed URL\n\n```python\nimport feedparser\n\nparsed = feedparser.parse(\"https://planetpython.org/rss20.xml\")\n\nif parsed.bozo:\n    print(f\"Feed was malformed: {parsed.bozo_exception!r}\")\n\nprint(parsed.version)\nprint(parsed.feed.get(\"title\"))\n\nfor entry in parsed.entries[:5]:\n    print(entry.get(\"title\"), entry.get(\"link\"))\n```\n\nWhat to expect from the result:\n\n- `parsed.feed`: feed-level metadata such as title, subtitle, and links\n- `parsed.entries`: normalized list of feed entries\n- `parsed.version`: detected feed type, such as RSS or Atom\n- `parsed.headers`, `parsed.href`, `parsed.status`: HTTP metadata when parsing a URL\n- `parsed.bozo`, `parsed.bozo_exception`: parse warning state for malformed feeds\n\nThe return value behaves like a dict with attribute access. In agent-written code, prefer `.get(...)` or presence checks because many feeds omit optional fields.\n\n### Parse local bytes or XML you already fetched\n\nIf you already have the response body, parse that directly instead of making `feedparser` fetch the URL again:\n\n```python\nfrom io import BytesIO\n\nimport feedparser\nimport requests\n\nurl = \"https://planetpython.org/rss20.xml\"\nresponse = requests.get(url, timeout=20)\nresponse.raise_for_status()\n\nheaders = dict(response.headers)\nheaders.setdefault(\"content-location\", response.url)\n\nparsed = feedparser.parse(\n    BytesIO(response.content),\n    response_headers=headers,\n)\n```\n\nPassing `content-location` matters when the feed contains relative links. It gives `feedparser` a base URI for link resolution.\n\n### Parse in-memory XML safely\n\nDo not pass untrusted raw strings directly to `feedparser.parse(...)`. The parser can interpret a bare string as a URL or filesystem path. Wrap raw XML in a file-like object:\n\n```python\nfrom io import BytesIO\n\nimport feedparser\n\nxml_bytes = b\"\"\"<?xml version=\"1.0\"?>\n<rss version=\"2.0\">\n  <channel>\n    <title>Example</title>\n    <item><title>Hello</title></item>\n  </channel>\n</rss>\n\"\"\"\n\nparsed = feedparser.parse(BytesIO(xml_bytes))\nprint(parsed.feed.get(\"title\"))\n```\n\n## HTTP, Caching, And Auth\n\n### Conditional requests with ETag and Last-Modified\n\nPersist `etag` and `modified` between runs to avoid re-downloading unchanged feeds:\n\n```python\nimport feedparser\n\nfeed_url = \"https://planetpython.org/rss20.xml\"\nstored_etag = 'W/\"abc123\"'\nstored_modified = \"Wed, 05 Mar 2025 10:00:00 GMT\"\n\nparsed = feedparser.parse(\n    feed_url,\n    etag=stored_etag,\n    modified=stored_modified,\n)\n\nif parsed.status == 304:\n    print(\"Feed not modified\")\nelse:\n    print(parsed.get(\"etag\"))\n    print(parsed.get(\"modified\"))\n```\n\n### Set a custom user agent or request headers\n\n```python\nimport feedparser\n\nparsed = feedparser.parse(\n    \"https://example.com/feed.xml\",\n    agent=\"MyFeedBot/1.0 (+https://example.com/bot)\",\n    request_headers={\n        \"Accept\": \"application/atom+xml, application/rss+xml, application/xml;q=0.9, */*;q=0.1\",\n    },\n)\n```\n\nUse `request_headers`, not `extra_headers`. Some official doc pages still mention `extra_headers`, but the `v6.0.12` parser signature uses `request_headers`.\n\n### Prefer explicit fetching for auth, proxies, retries, and timeouts\n\nThe official docs still show older `urllib2`-style auth examples. In modern Python, it is usually simpler to fetch the feed with your HTTP client of choice, then pass the body plus response headers to `feedparser`:\n\n```python\nfrom io import BytesIO\n\nimport feedparser\nimport requests\n\nresponse = requests.get(\n    \"https://example.com/private-feed.xml\",\n    auth=(\"username\", \"password\"),\n    headers={\"User-Agent\": \"MyFeedBot/1.0\"},\n    timeout=20,\n)\nresponse.raise_for_status()\n\nheaders = dict(response.headers)\nheaders.setdefault(\"content-location\", response.url)\n\nparsed = feedparser.parse(BytesIO(response.content), response_headers=headers)\n```\n\nThis pattern gives you full control over auth, redirects, TLS, retries, proxy config, and observability without depending on the parser's built-in URL fetching path.\n\n## Normalized Fields Agents Usually Need\n\nCommon entry fields:\n\n- `entry.title`\n- `entry.link`\n- `entry.summary`\n- `entry.content`\n- `entry.author`\n- `entry.tags`\n- `entry.enclosures`\n- `entry.published`, `entry.updated`\n- `entry.published_parsed`, `entry.updated_parsed`\n\nPrefer `*_parsed` over raw date strings:\n\n```python\nimport calendar\nfrom datetime import datetime, timezone\n\npublished = entry.get(\"published_parsed\")\nif published:\n    published_at = datetime.fromtimestamp(calendar.timegm(published), tz=timezone.utc)\n```\n\n`feedparser` normalizes many date formats into UTC `time.struct_time` values. That is much more reliable than trying to parse publisher-specific date strings yourself.\n\n## HTML And Link Handling\n\nBy default, `feedparser` resolves relative URIs in HTML content and sanitizes embedded markup in common text fields. You can disable either behavior per call:\n\n```python\nparsed = feedparser.parse(\n    \"https://example.com/feed.xml\",\n    resolve_relative_uris=False,\n    sanitize_html=False,\n)\n```\n\nUse this carefully:\n\n- `sanitize_html=False` is only safe if you will escape or otherwise sanitize output before rendering it into HTML.\n- `resolve_relative_uris=False` only affects relevant embedded HTML/markup handling. Do not assume every link-like field is rewritten the same way.\n\n## Common Pitfalls\n\n- `bozo == 1` is not always fatal. Many real feeds are slightly malformed but still yield usable `entries`.\n- Do not assume keys exist. Use `.get(...)` for optional fields like `summary`, `author`, `tags`, and `published_parsed`.\n- If you need deterministic HTTP behavior, fetch the feed yourself and pass `response_headers` into `feedparser.parse(...)`.\n- Wrap untrusted XML strings in `BytesIO` or `StringIO`; a bare string can be treated as a URL or file path.\n- Some official examples are still written against old Python 2 modules such as `urllib2`. Translate them to `urllib.request` or use `requests`.\n- If relative links matter and you are parsing bytes rather than a URL, supply `content-location` in `response_headers`.\n- Use `*_parsed` fields for dates. Raw `published` and `updated` strings vary widely across publishers.\n\n## Version-Sensitive Notes For 6.0.12\n\n- PyPI currently lists `feedparser 6.0.12`, released on September 10, 2025.\n- The official changelog for `6.0.12` notes fixes for an `AssertionError` on Python 3.10+ and a `DeprecationWarning` from `re.sub`, plus Read the Docs configuration updates.\n- The docs URL points to `https://feedparser.readthedocs.io/en/latest/`, but the docs site currently has version drift: `latest/` pages still identify themselves as `6.0.11`, while `en/releases/` pages and the changelog include `6.0.12`.\n- For code generation, prefer `request_headers` and `response_headers` from the `v6.0.12` source tag over any stale doc page that still says `extra_headers`.\n"
  },
  {
    "path": "content/filelock/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"filelock package guide for Python: cross-platform file locks, async locks, and SQLite-backed read/write locks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.25.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"filelock,locking,concurrency,filesystem,asyncio,sqlite\"\n---\n\n# filelock Python Package Guide\n\n## What It Does\n\n`filelock` provides cross-platform process coordination with lock files. Use it when multiple Python processes, workers, or CLIs must avoid mutating the same on-disk resource at the same time.\n\nThe package now covers three main locking models:\n\n- `FileLock`: the default choice for an exclusive lock. It uses platform-specific hard locks and falls back to a soft lock when the platform reports that hard locking is unavailable.\n- `SoftFileLock`: only coordinates by creating a lock file. Use it only when you knowingly accept weaker guarantees.\n- `ReadWriteLock`: a SQLite-backed read/write lock for read-heavy workloads where readers may proceed concurrently but writers must be exclusive.\n\nAsync variants exist for both exclusive and read/write locking: `AsyncFileLock` and `AsyncReadWriteLock`.\n\n## Version Scope\n\n- Package: `filelock`\n- Language: `python`\n- Version covered in frontmatter: `3.25.2`\n- Current upstream release on PyPI as of March 11, 2026: `3.25.2`\n- Python requirement on current PyPI metadata: `>=3.10`\n\nIf your project is pinned below `3.25.0`, read/write async support will not exist. If it is pinned below `3.24.0`, several lock-control features in this doc are also missing.\n\n## Install\n\n```bash\npip install filelock==3.25.2\n```\n\n```bash\nuv add filelock==3.25.2\n```\n\n```bash\npoetry add filelock==3.25.2\n```\n\n## Imports\n\n```python\nfrom filelock import (\n    AsyncFileLock,\n    AsyncReadWriteLock,\n    FileLock,\n    ReadWriteLock,\n    SoftFileLock,\n    Timeout,\n)\n```\n\n## Choose The Right Lock\n\n### `FileLock`\n\nUse this first unless you have a specific reason not to.\n\n- Best general-purpose option for local filesystems.\n- Reentrant for the same lock object in the same process.\n- Supports `timeout`, `blocking`, `poll_interval`, `thread_local`, `is_singleton`, `mode`, `lifetime`, and `cancel_check`.\n\n### `SoftFileLock`\n\nUse only when the environment cannot support hard locks reliably and you can tolerate weaker coordination.\n\n- The presence of the lock file is the lock.\n- Stale lock cleanup is harder and crash recovery is weaker.\n- It still depends on all cooperating processes using the same convention.\n\n### `ReadWriteLock`\n\nUse this when reads are frequent and can safely happen concurrently.\n\n- Backed by a SQLite database file.\n- Requires the lock path to end in `.db`.\n- Use `read_lock()` and `write_lock()` instead of `acquire()`.\n- Call `close()` when you are done with the lock object.\n\nIf you are coordinating over NFS, SMB, Docker bind mounts, or other network filesystems, upstream recommends caution. The docs explicitly call out reliability limits for mounted volumes and network filesystems; if correctness matters, prefer a centralized lock service.\n\n## Basic Exclusive Lock Usage\n\nLock a separate `.lock` file, not the data file you are protecting.\n\n```python\nfrom pathlib import Path\nfrom filelock import FileLock, Timeout\n\ndata_path = Path(\"cache.json\")\nlock = FileLock(\"cache.json.lock\", timeout=10)\n\ntry:\n    with lock:\n        current = data_path.read_text(encoding=\"utf-8\") if data_path.exists() else \"{}\"\n        data_path.write_text(current, encoding=\"utf-8\")\nexcept Timeout as exc:\n    raise RuntimeError(\"Could not acquire cache lock within 10 seconds\") from exc\n```\n\nRules that matter in practice:\n\n- Reuse the same lock object for the same path when possible.\n- Keep the object in a variable; do not rely on a temporary object being garbage collected at the right time.\n- Prefer the context manager form unless you need manual control.\n\n## Explicit Acquire, Retry, And Cancellation\n\n`acquire()` is useful when you need non-default retry or shutdown behavior.\n\n```python\nfrom threading import Event\nfrom filelock import FileLock, Timeout\n\nstop = Event()\nlock = FileLock(\"jobs.lock\", timeout=30, poll_interval=0.2)\n\ntry:\n    lock.acquire(cancel_check=stop.is_set)\n    try:\n        run_job_queue()\n    finally:\n        lock.release()\nexcept Timeout as exc:\n    raise RuntimeError(\"jobs.lock stayed busy\") from exc\n```\n\nImportant controls:\n\n- `timeout`: total wait time before raising `Timeout`\n- `blocking=False`: fail immediately instead of waiting\n- `poll_interval`: sleep interval between retries\n- `cancel_check`: callable checked during waits so another thread can abort lock acquisition\n- `lifetime`: treat a lock as stale after the given number of seconds\n- `is_singleton=True`: reuse one lock instance per path inside the process\n- `thread_local`: keep acquisition context per thread\n\n`blocking=False` takes precedence over `timeout`. If you pass both, the non-blocking behavior wins and the call fails immediately.\n\n## Async Usage\n\nUse the async lock types directly in `asyncio` code.\n\n```python\nimport asyncio\nfrom filelock import AsyncFileLock, Timeout\n\nlock = AsyncFileLock(\"worker.lock\", timeout=5)\n\nasync def main() -> None:\n    try:\n        async with lock:\n            await process_batch()\n    except Timeout as exc:\n        raise RuntimeError(\"worker.lock is busy\") from exc\n\nasyncio.run(main())\n```\n\nPractical notes:\n\n- `AsyncFileLock` runs the blocking lock operations in an executor.\n- Upstream defaults async locks to `thread_local=False`.\n- You can pass a custom `executor` or disable `run_in_executor` when you need tighter control.\n\n## Read/Write Locks\n\n`ReadWriteLock` is the new 3.25.x option when many readers may proceed concurrently but writes must exclude both readers and writers.\n\nThe lock path must end in `.db`.\n\n```python\nfrom filelock import ReadWriteLock, Timeout\n\nrw_lock = ReadWriteLock(\"catalog.lock.db\")\n\ntry:\n    with rw_lock.read_lock(timeout=5):\n        snapshot = load_catalog()\n\n    with rw_lock.write_lock(timeout=10):\n        save_catalog(snapshot)\nfinally:\n    rw_lock.close()\n```\n\nNotes:\n\n- `read_lock()` and `write_lock()` support `timeout` and `blocking`.\n- This API does not use `lifetime` or `cancel_check`.\n- `AsyncReadWriteLock` provides the same model for `asyncio`.\n\n## Configuration And Environment\n\n`filelock` has no auth model, no service credentials, and no required environment variables. All configuration is local to the lock object you create.\n\nControls you will actually use:\n\n- Lock path choice: every cooperating process must use the same path convention.\n- `timeout`, `blocking`, and `poll_interval`: determine wait behavior.\n- `lifetime`: stale-lock recovery for exclusive locks.\n- `is_singleton`: avoid same-process lock duplication bugs.\n- `thread_local`: choose whether thread context should be isolated.\n- `mode`: filesystem mode for newly created lock files.\n- `executor` and `run_in_executor`: async execution strategy for async lock types.\n\nExample: a non-blocking probe.\n\n```python\nfrom filelock import FileLock, Timeout\n\nlock = FileLock(\"report.lock\", blocking=False)\n\ntry:\n    with lock:\n        generate_report()\nexcept Timeout:\n    print(\"another worker already owns report.lock\")\n```\n\n## Common Pitfalls\n\n### Locking the protected file instead of a dedicated lock file\n\nUse `report.csv.lock` to protect `report.csv`. Upstream explicitly recommends locking a separate file.\n\n### Assuming the lock file's presence is the source of truth\n\nOn Windows and on some mounted filesystems, a released lock can leave the lock file behind temporarily. The lock state matters more than file presence.\n\n### Creating multiple lock objects for the same path in one thread\n\nSince `3.24.0`, `filelock` defends against some self-deadlock cases by raising `RuntimeError`, but the practical fix is still to reuse one lock object or set `is_singleton=True`.\n\n### Treating `SoftFileLock` as equivalent to a hard lock\n\nIt only coordinates by file creation and cooperation. It does not give the same guarantees as a hard OS-backed lock.\n\n### Using read/write locks without the `.db` suffix\n\n`ReadWriteLock` requires a SQLite database path. Do not pass `catalog-lock` or `catalog.lock`; pass something like `catalog.lock.db`.\n\n### Expecting network-mounted filesystems to behave like local disks\n\nThe concepts guide documents caveats for NFS, SMB, Docker bind mounts, and other mounted filesystems. If losing mutual exclusion would be unacceptable, do not rely on file-based locks alone.\n\n### Depending on garbage collection for release\n\nThe tutorial warns that an unreferenced acquired lock may be released during garbage collection. Keep a stable reference and release explicitly or with a context manager.\n\n## Version-Sensitive Notes\n\n### 3.25.2\n\n- Released on March 11, 2026.\n- Upstream fixed an `EIO` close issue on Unix when the lock lived on a Docker bind mount or similar mounted volume.\n\n### 3.25.1\n\n- Restored best-effort lock file cleanup during `WindowsFileLock.release()`.\n\n### 3.25.0\n\n- Added `AsyncReadWriteLock`.\n\n### 3.24.x\n\n- Added stale-lock support through `lifetime`.\n- Added `cancel_check` so another thread can abort acquisition.\n- Added `poll_interval` to constructors for sync and async exclusive locks.\n- Added self-deadlock detection when the same thread creates multiple `FileLock` objects for the same path.\n- Improved exclusive lock behavior on platforms without POSIX-style hard locking by falling back to a soft lock when appropriate.\n\nIf your codebase was written against pre-`3.24` examples, double-check constructor signatures and do not assume read/write or cancellation features exist.\n\n## Recommended Agent Workflow\n\n1. Start with `FileLock` and a dedicated `.lock` file.\n2. Use the context manager form unless you need cancellation or special retry control.\n3. Reuse one lock object per path in-process.\n4. Move to `ReadWriteLock` only when you actually need concurrent readers.\n5. Treat mounted and network filesystems as suspicious until the deployment environment is verified.\n\n## Official Sources\n\n- Documentation root: https://py-filelock.readthedocs.io/en/latest/\n- Tutorial: https://py-filelock.readthedocs.io/en/latest/tutorial.html\n- How-to guide: https://py-filelock.readthedocs.io/en/latest/how-to.html\n- Concepts guide: https://py-filelock.readthedocs.io/en/latest/concepts.html\n- API reference: https://py-filelock.readthedocs.io/en/latest/api.html\n- Changelog: https://py-filelock.readthedocs.io/en/latest/changelog.html\n- PyPI: https://pypi.org/project/filelock/\n- Repository: https://github.com/tox-dev/filelock\n"
  },
  {
    "path": "content/fiona/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Fiona Python package guide for reading and writing vector geospatial data with GDAL-backed drivers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.10.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"fiona,python,gis,geospatial,vector,gdal,geojson\"\n---\n\n# Fiona Python Package Guide\n\n## Golden Rule\n\nUse `fiona` for vector dataset I/O, not for geometric analysis. Fiona reads and writes GeoJSON-like feature records through GDAL/OGR-backed drivers; pair it with `shapely` for geometry operations and `pyproj` when you need explicit coordinate transforms.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"fiona==1.10.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"fiona==1.10.1\"\npoetry add \"fiona==1.10.1\"\n```\n\nUseful extras:\n\n```bash\npython -m pip install \"fiona[s3]==1.10.1\"\npython -m pip install \"fiona[calc]==1.10.1\"\n```\n\nNotes:\n\n- `fiona[s3]` installs the `boto3` dependencies used by `AWSSession`.\n- `fiona[calc]` is required for CLI commands such as `fio calc`, `fio filter`, `fio map`, and `fio reduce`.\n- PyPI wheels are convenient, but the upstream docs explicitly warn that they omit many optional GDAL drivers and are not a good fit for every production environment or mixed binary stack.\n\nIf you need drivers omitted from the wheels, build from source against an existing GDAL install:\n\n```bash\nexport GDAL_CONFIG=/path/to/gdal-config\npython -m pip install -U pip\npython -m pip install --no-binary fiona \"fiona==1.10.1\"\n```\n\n## Initialize And Inspect A Dataset\n\nCollections returned by `fiona.open()` behave like file objects plus iterators over GeoJSON-like feature records:\n\n```python\nimport fiona\n\nwith fiona.open(\"data/countries.geojson\") as src:\n    print(src.driver)\n    print(src.crs)\n    print(src.schema)\n    print(src.bounds)\n    print(len(src))\n\n    first = next(iter(src))\n    print(first.id)\n    print(first.geometry.type)\n    print(first.properties[\"name\"])\n```\n\nImportant behavior:\n\n- Use `with fiona.open(...)` so files flush and close cleanly.\n- Feature objects are mapping-like, not plain dicts. Convert with `fiona.model.to_dict()` if you need JSON serialization.\n- Fiona copies feature data into Python objects. This is simpler than GDAL's raw bindings, but not the fastest option for bulk field-level extraction.\n\n## Core Usage\n\n### Read Features And Apply Spatial Or Attribute Filters\n\n```python\nimport fiona\nfrom shapely.geometry import shape\n\nwith fiona.open(\"data/parcels.gpkg\", layer=\"parcels\") as src:\n    for feat in src.filter(\n        bbox=(-123.2, 44.0, -123.0, 44.2),\n        where=\"land_use = 'residential'\",\n    ):\n        geom = shape(feat.geometry)\n        print(feat.id, geom.area, feat.properties[\"land_use\"])\n```\n\nUse `bbox=` for spatial intersection filtering and `where=` for SQL-style attribute filtering. If you need geometry predicates beyond simple bounds checks, load the geometry into Shapely and do the rest there.\n\n### Write A New Dataset\n\nWhen the output mostly matches the input, start from `src.profile` instead of rebuilding driver, CRS, and schema by hand.\n\n```python\nimport fiona\nfrom fiona import Feature, Geometry\nfrom shapely.geometry import mapping, shape\n\ndef to_centroid(feature):\n    centroid = shape(feature.geometry).centroid\n    return Feature.from_dict(\n        geometry=Geometry.from_dict(mapping(centroid)),\n        properties=dict(feature.properties),\n    )\n\nwith fiona.open(\"data/input.gpkg\", layer=\"parcels\") as src:\n    profile = src.profile\n    profile[\"driver\"] = \"GPKG\"\n    profile[\"schema\"][\"geometry\"] = \"Point\"\n\n    with fiona.open(\"data/parcel-centroids.gpkg\", \"w\", layer=\"centroids\", **profile) as dst:\n        dst.writerecords(to_centroid(feature) for feature in src)\n```\n\nWhen writing from scratch, you must provide:\n\n- `driver`\n- `crs`\n- `schema`\n\nThe schema geometry must match the geometries you write. Fiona will not automatically coerce a polygon schema into a point schema or vice versa.\n\n### Work With Multilayer Datasets\n\nGeoPackage, file geodatabases, archives, and directory-backed datasets can expose multiple layers.\n\n```python\nimport fiona\n\ndataset = \"data/census.gpkg\"\n\nprint(fiona.listlayers(dataset))\n\nwith fiona.open(dataset, layer=\"tracts\") as tracts:\n    print(tracts.schema)\n\nwith fiona.open(dataset, layer=0) as first_layer:\n    print(first_layer.name)\n```\n\nIf you omit `layer=...`, Fiona opens the first layer. That is convenient for shapefiles and easy demos, but it is brittle for GeoPackage-style datasets.\n\n### Read Zipped Or In-Memory Data\n\nFiona supports GDAL virtual filesystem URIs and in-memory readers.\n\n```python\nfrom fiona.io import ZipMemoryFile\n\ndata = open(\"uploads/boundaries.zip\", \"rb\").read()\n\nwith ZipMemoryFile(data) as archive:\n    with archive.open(\"boundaries.shp\") as src:\n        print(len(src))\n        print(src.schema)\n```\n\nThis is the right pattern when an agent receives uploaded bytes and should avoid writing a temporary archive to disk.\n\n## Configuration And Auth\n\n### GDAL Environment Options\n\nUse `fiona.Env()` when you need GDAL configuration, debug logging, or cloud credentials.\n\n```python\nimport fiona\n\nwith fiona.Env(CPL_DEBUG=True):\n    with fiona.open(\"data/parcels.gpkg\") as src:\n        print(src.driver)\n```\n\nYou can also inspect which drivers are actually enabled in the linked GDAL build:\n\n```python\nfrom fiona.env import Env\n\nwith Env() as env:\n    print(sorted(env.drivers().keys())[:20])\n```\n\n### S3 Access\n\nFor S3 URIs, either let Fiona create a session from the environment or pass one explicitly.\n\n```python\nimport boto3\nimport fiona\nfrom fiona.session import AWSSession\n\nsession = boto3.Session(profile_name=\"geo-prod\")\n\nwith fiona.Env(session=AWSSession(session, requester_pays=True)):\n    with fiona.open(\"zip+s3://my-bucket/boundaries.zip\") as src:\n        print(src.bounds)\n```\n\nNotes:\n\n- `zip+s3://...` works for zipped vector datasets stored in S3.\n- `fio` exposes matching CLI flags such as `--aws-profile`, `--aws-no-sign-requests`, and `--aws-requester-pays`.\n- The docs only document `AWSSession` directly; for other storage systems, treat credentials as GDAL environment configuration unless the driver family documents something more specific.\n\n## CLI Workflow\n\nFiona ships with `fio`, which is useful for quick inspection, format conversion, and stream-based processing:\n\n```bash\nfio info data/parcels.gpkg --layer parcels\nfio ls data/parcels.gpkg\nfio cat data/parcels.gpkg --layer parcels --where \"land_use = 'residential'\" | head\nfio cat data/parcels.gpkg --layer parcels | fio load /tmp/parcels.geojson --driver GeoJSON\n```\n\nNewer 1.10 CLI features:\n\n- `fio filter`\n- `fio map`\n- `fio reduce`\n\nThese require the `calc` extra and use parenthesized expression syntax, not the older Python-style filter syntax.\n\n## Common Pitfalls\n\n- Fiona is vector-only. Use `rasterio` or GDAL raster APIs for rasters.\n- Fiona features do not provide geometry methods. Convert `feature.geometry` with `shapely.geometry.shape()` before calling spatial methods like `.buffer()` or `.intersection()`.\n- Do not assume PyPI wheels support every format driver. If a format fails unexpectedly, inspect enabled drivers and consider a source build or conda-forge environment.\n- Writing one feature at a time with repeated `dst.write()` can be much slower than `dst.writerecords(...)` for larger outputs.\n- Be explicit about `layer=` for GeoPackage or archive-based inputs. Relying on the first layer is fragile.\n- Schema property widths matter. Strings declared as `str:25` are truncated on write.\n- Shapefile schema geometry can still yield `MultiPolygon` or `MultiLineString` features at read time. Validate actual feature geometry types, not just the schema headline.\n- Unsupported GDAL drivers can sometimes be opened with `allow_unsupported_drivers=True`, but the manual is explicit that correct access is not guaranteed.\n- If you need JSON output from a feature object, convert it first. Since 1.9, features are mappings and are not immediately JSON serializable.\n\n## Version-Sensitive Notes For 1.10.1\n\n- PyPI and the stable docs both point to `1.10.1` as the current stable Fiona release as of March 12, 2026.\n- `1.10.1` itself is a small bugfix release. The stable changelog notes a CRS logging fix on September 16, 2024.\n- The larger behavior changes are in the `1.10.0` line: new Python openers, new `fio filter`/`map`/`reduce` commands, and more explicit movement toward Fiona 2.0 APIs.\n- Older Python-style `fio filter` expressions such as `f.properties.area > 1000.0` are deprecated in `1.10` and documented for removal in `2.0`. Use parenthesized list expressions instead.\n- Deprecated helpers such as `fiona.path` and old CRS helper functions are on the 2.0 removal path. Prefer `from fiona.crs import CRS` and methods like `CRS.from_epsg(...)`.\n- The manual documents that features became mapping objects in `1.9.0`; `1.10.0rc1` restored mutable item access for `Feature`, `Geometry`, and `Properties`, but code should still avoid depending on mutability if you want a smoother Fiona 2.0 migration path.\n\n## Official URLs Used For This Doc\n\n- Stable docs root: `https://fiona.readthedocs.io/en/stable/`\n- Installation and changelog: `https://fiona.readthedocs.io/en/stable/README.html`\n- User manual: `https://fiona.readthedocs.io/en/stable/manual.html`\n- CLI docs: `https://fiona.readthedocs.io/en/stable/cli.html`\n- API reference: `https://fiona.readthedocs.io/en/stable/fiona.html`\n- PyPI package page: `https://pypi.org/project/fiona/`\n- GitHub releases: `https://github.com/Toblerity/Fiona/releases`\n"
  },
  {
    "path": "content/fire/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python Fire guide for turning Python functions, classes, and objects into CLIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"fire,python,cli,command-line,repl,google\"\n---\n\n# Fire Python Package Guide\n\n## Golden Rule\n\nUse `fire.Fire(...)` with an explicit function, class, object, or command map inside `if __name__ == \"__main__\":`. Avoid bare `fire.Fire()` in production CLIs unless you intentionally want to expose the whole module for exploration or debugging. When you need Fire's own flags such as help, trace, completion, or interactive mode, pass them after a standalone `--`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"fire==0.7.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"fire==0.7.1\"\npoetry add \"fire==0.7.1\"\n```\n\nOptional tooling:\n\n```bash\npython -m pip install ipython\n```\n\nNotes:\n\n- `fire` is a local CLI-generation library. It does not require API keys, service credentials, or network configuration.\n- `ipython` is optional, but `--interactive` is more useful when IPython is installed.\n\n## Initialize A CLI\n\nExpose a single function:\n\n```python\nimport fire\n\ndef hello(name: str = \"world\", excited: bool = False) -> str:\n    greeting = f\"Hello, {name}\"\n    return f\"{greeting}!\" if excited else greeting\n\nif __name__ == \"__main__\":\n    fire.Fire(hello)\n```\n\nRun it:\n\n```bash\npython hello.py\npython hello.py --name=Ada\npython hello.py --name=Grace --excited\npython hello.py -- --help\n```\n\nFire turns function parameters into CLI arguments automatically:\n\n- positional args map left-to-right\n- keyword args use `--name=value` or `--name value`\n- boolean flags accept forms like `--debug` and `--nodebug`\n\n## Core Usage\n\n### Group commands with a class\n\nClasses work well when you want shared state and multiple subcommands:\n\n```python\nimport fire\n\nclass Calculator:\n    def __init__(self, precision: int = 2):\n        self.precision = precision\n\n    def add(self, x: float, y: float) -> float:\n        return round(x + y, self.precision)\n\n    def mul(self, x: float, y: float) -> float:\n        return round(x * y, self.precision)\n\nif __name__ == \"__main__\":\n    fire.Fire(Calculator)\n```\n\nExamples:\n\n```bash\npython calc.py add 2 3\npython calc.py --precision=4 mul 2.5 3\n```\n\nImportant detail: constructor arguments must be passed as named flags before the member you want to call.\n\n### Group commands with a dict\n\nIf you want explicit command names instead of exposing every class member, pass a dict:\n\n```python\nimport fire\n\ndef greet(name: str) -> str:\n    return f\"hello {name}\"\n\ndef version() -> str:\n    return \"1.0.0\"\n\nif __name__ == \"__main__\":\n    fire.Fire(\n        {\n            \"greet\": greet,\n            \"version\": version,\n        }\n    )\n```\n\nThis is often the safest pattern for small CLIs because it exposes only the commands you choose.\n\n### Return values become output\n\nFire prints primitive return values directly:\n\n```python\nimport fire\n\ndef status():\n    return {\"healthy\": True, \"workers\": 4}\n\nif __name__ == \"__main__\":\n    fire.Fire(status)\n```\n\nFor custom objects, Fire may show help/inspection output instead of a useful value unless the object has a meaningful string representation. If you need stable output for automation, return primitives, dicts, lists, or implement `__str__`.\n\n### Async functions are supported\n\nFire will await async functions before printing the result:\n\n```python\nimport asyncio\nimport fire\n\nasync def fetch_message(name: str) -> str:\n    await asyncio.sleep(0.1)\n    return f\"done for {name}\"\n\nif __name__ == \"__main__\":\n    fire.Fire(fetch_message)\n```\n\n## Configuration And Fire Flags\n\nFire has no separate config file format. The practical configuration surface is:\n\n1. the Python object you expose with `fire.Fire(...)`\n2. the command arguments you define on that object\n3. Fire's own flags, passed after a standalone `--`\n\nUseful built-in flags:\n\n- `-- --help`: show generated help and docstrings\n- `-- --interactive`: drop into a REPL with the final result in scope\n- `-- --completion [bash|fish]`: print a shell completion script\n- `-- --trace`: show Fire's resolution trace for debugging\n- `-- --separator=X`: change the separator used for command chaining\n- `-- --verbose`: include private members in help output\n\nExamples:\n\n```bash\npython calc.py add 2 3 -- --trace\npython calc.py -- --completion bash\npython calc.py add 2 3 -- --interactive\n```\n\nIf `-` is part of the actual value you need to pass or the default separator causes ambiguous parsing, set a different separator explicitly:\n\n```bash\npython tool.py deploy prod /srv/app -- --separator=/\n```\n\n## Help And Docstrings\n\nFire uses Python names, signatures, and docstrings to build help text. If you want the generated CLI to be usable:\n\n- write docstrings on functions and classes\n- keep parameter names stable and descriptive\n- prefer explicit command maps or narrow classes over dumping a large module into `Fire`\n\nMinimal example:\n\n```python\ndef greet(name: str):\n    \"\"\"Return a friendly greeting.\"\"\"\n    return f\"hello {name}\"\n```\n\n## Common Pitfalls\n\n- Bare `fire.Fire()` exposes the current module's globals and imported objects. That is useful for ad hoc exploration but too broad for a stable CLI.\n- Fire's own flags must come after a standalone `--`. Without that separator, `--trace`, `--help`, or `--interactive` may be parsed as arguments for your function or method instead.\n- Constructor args and method args are parsed differently. For `fire.Fire(MyClass)`, constructor values should be passed as flags before the method name.\n- Fire treats hyphens and underscores as equivalent in argument and member names. That is convenient, but it can hide naming mistakes if your code relies on both forms.\n- Fire parses command-line values into Python types. Strings that look like numbers, lists, dicts, or booleans can be coerced unexpectedly, so quote carefully when you need a literal string.\n- Complex custom objects do not automatically serialize well. Return plain data structures for scripts that need stable machine-readable output.\n- The default separator is `-`. If your commands or data also use `-` in ways Fire interprets as chaining, change it with `-- --separator=...`.\n- `--interactive` works without IPython, but the experience is better if `ipython` is installed.\n\n## Version-Sensitive Notes For `0.7.1`\n\n- As of `2026-03-12`, PyPI still lists `0.7.1` as the current release for `fire`.\n- The official docs site is a general guide rather than a versioned per-release reference. For this package, the guide and CLI reference still align with `0.7.1`.\n- The GitHub `v0.7.1` release notes call out packaging and compatibility work such as `pyproject.toml`, wheel publishing, IPython inspector compatibility, and a fix for class attribute inspection. Those changes do not materially change the basic CLI authoring patterns in the guide.\n- Older tutorials that mention Python 2 are stale. The `0.7.x` line is Python 3 only, and PyPI metadata for `0.7.1` requires Python `>=3.7`.\n\n## Official Sources\n\n- Guide: `https://google.github.io/python-fire/guide/`\n- CLI flags reference: `https://google.github.io/python-fire/using-cli/`\n- PyPI package metadata: `https://pypi.org/project/fire/`\n- PyPI JSON metadata: `https://pypi.org/pypi/fire/0.7.1/json`\n- GitHub release: `https://github.com/google/python-fire/releases/tag/v0.7.1`\n"
  },
  {
    "path": "content/firebase/docs/admin/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Firebase Admin Python SDK guide for server-side authentication, messaging, database, Firestore, storage, and admin workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"firebase,firebase-admin,python,authentication,messaging,firestore,realtime-database,storage\"\n---\n\n# Firebase Admin Python SDK\n\n## Golden Rule\n\nUse `firebase-admin` only in trusted server environments, initialize it once per process, and prefer Application Default Credentials (ADC) on Google-managed runtimes. If you are running outside Google Cloud, use a service account JSON file or `GOOGLE_APPLICATION_CREDENTIALS`, and pass `projectId`, `databaseURL`, and `storageBucket` explicitly when the runtime cannot infer them.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"firebase-admin==7.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"firebase-admin==7.2.0\"\npoetry add \"firebase-admin==7.2.0\"\n```\n\nThe current PyPI latest release is also `7.2.0`, published on February 25, 2026.\n\n## Authentication And Initialization\n\nThe SDK entry point is `firebase_admin.initialize_app()`. If you call it twice with the same app name, the SDK raises `ValueError`.\n\n### Preferred setup on Google Cloud runtimes\n\nOn Cloud Run, GKE, App Engine, or other Google-managed environments, rely on ADC:\n\n```python\nimport firebase_admin\n\napp = firebase_admin.initialize_app(\n    options={\n        \"projectId\": \"my-firebase-project\",\n        \"databaseURL\": \"https://my-firebase-project-default-rtdb.firebaseio.com\",\n        \"storageBucket\": \"my-firebase-project.firebasestorage.app\",\n    }\n)\n```\n\nIf you omit the credential, the SDK uses Google Application Default Credentials.\n\n### Service account setup outside Google Cloud\n\n```python\nimport firebase_admin\nfrom firebase_admin import credentials\n\ncred = credentials.Certificate(\"service-account.json\")\n\napp = firebase_admin.initialize_app(\n    cred,\n    {\n        \"projectId\": \"my-firebase-project\",\n        \"databaseURL\": \"https://my-firebase-project-default-rtdb.firebaseio.com\",\n        \"storageBucket\": \"my-firebase-project.firebasestorage.app\",\n    },\n)\n```\n\n### `GOOGLE_APPLICATION_CREDENTIALS` setup\n\nIf you want ADC behavior outside Google Cloud, point `GOOGLE_APPLICATION_CREDENTIALS` at a service account file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nThen initialize normally:\n\n```python\nimport firebase_admin\n\napp = firebase_admin.initialize_app(\n    options={\"projectId\": \"my-firebase-project\"}\n)\n```\n\n### Configuration options the SDK understands\n\n`initialize_app()` supports these common options:\n\n- `projectId`\n- `databaseURL`\n- `storageBucket`\n- `databaseAuthVariableOverride`\n- `serviceAccountId`\n- `httpTimeout`\n\nIf `httpTimeout` is not set, the SDK default is 120 seconds.\n\n### `FIREBASE_CONFIG`\n\nIf you do not pass `options`, the SDK also checks `FIREBASE_CONFIG`. If the value starts with `{`, it is parsed as inline JSON. Otherwise the SDK treats it as a filename and reads JSON from that file.\n\n### Multiple app instances\n\nUse named apps when one process needs to talk to multiple Firebase projects:\n\n```python\nimport firebase_admin\nfrom firebase_admin import credentials\n\ndefault_app = firebase_admin.initialize_app(\n    credentials.Certificate(\"project-a.json\"),\n    {\"projectId\": \"project-a\"},\n)\n\nother_app = firebase_admin.initialize_app(\n    credentials.Certificate(\"project-b.json\"),\n    {\"projectId\": \"project-b\"},\n    name=\"project-b\",\n)\n```\n\nIn tests or short-lived scripts, clean up with `firebase_admin.delete_app(app)`.\n\n## Core Usage\n\n### Authentication\n\nCreate users, attach custom claims, and verify client-issued ID tokens:\n\n```python\nfrom firebase_admin import auth\n\nuser = auth.create_user(\n    email=\"user@example.com\",\n    password=\"correct horse battery staple\",\n    display_name=\"Example User\",\n)\n\nauth.set_custom_user_claims(user.uid, {\"admin\": True})\n\ndecoded = auth.verify_id_token(id_token, check_revoked=True)\nuid = decoded[\"uid\"]\n```\n\nUseful auth APIs agents commonly need:\n\n- `auth.create_user(...)`\n- `auth.update_user(...)`\n- `auth.delete_user(uid)`\n- `auth.get_user(uid)`\n- `auth.create_custom_token(uid, developer_claims=...)`\n- `auth.verify_id_token(id_token, check_revoked=False, clock_skew_seconds=0)`\n\n`verify_id_token()` accepts only Firebase ID tokens. Do not pass custom tokens into it; custom tokens are meant to be exchanged by the client SDK for an ID token first.\n\n### Realtime Database\n\n`db.reference()` reads and writes JSON-like tree data. By default it uses the `databaseURL` configured at app initialization, but you can override the URL per call.\n\n```python\nfrom firebase_admin import db\n\nusers_ref = db.reference(\"users\")\nusers_ref.child(\"alice\").set(\n    {\n        \"name\": \"Alice\",\n        \"active\": True,\n    }\n)\n\nsnapshot = users_ref.child(\"alice\").get()\nprint(snapshot)\n```\n\nConnect to a different database instance in the same project:\n\n```python\nfrom firebase_admin import db\n\nother_ref = db.reference(\n    \"users\",\n    url=\"https://my-firebase-project-eu-default-rtdb.europe-west1.firebasedatabase.app\",\n)\n```\n\n### Cloud Firestore\n\n`firebase_admin.firestore.client()` returns a Firestore client bound to the initialized app and project:\n\n```python\nfrom firebase_admin import firestore\n\nclient = firestore.client()\n\ndoc_ref = client.collection(\"users\").document(\"alice\")\ndoc_ref.set({\"email\": \"alice@example.com\", \"role\": \"admin\"})\n\ndoc = doc_ref.get()\nif doc.exists:\n    print(doc.to_dict())\n```\n\nIf you use named Firestore databases, pass `database_id`:\n\n```python\nfrom firebase_admin import firestore\n\nclient = firestore.client(database_id=\"analytics\")\n```\n\nIf you need async Firestore access, use `firebase_admin.firestore_async.client()`.\n\n### Cloud Messaging\n\nUse `messaging.send()` for one message and `messaging.send_each()` or `messaging.send_each_for_multicast()` for batch sends:\n\n```python\nfrom firebase_admin import messaging\n\nmessage = messaging.Message(\n    token=device_token,\n    notification=messaging.Notification(\n        title=\"Build complete\",\n        body=\"Your report is ready.\",\n    ),\n    data={\"report_id\": \"rpt_123\"},\n)\n\nmessage_id = messaging.send(message, dry_run=False)\nprint(message_id)\n```\n\nMulticast example:\n\n```python\nfrom firebase_admin import messaging\n\nbatch = messaging.MulticastMessage(\n    tokens=[token_a, token_b],\n    notification=messaging.Notification(\n        title=\"Maintenance window\",\n        body=\"Service will restart in 10 minutes.\",\n    ),\n)\n\nresponse = messaging.send_each_for_multicast(batch)\nprint(response.success_count, response.failure_count)\n```\n\n### Cloud Storage\n\n`storage.bucket()` returns a `google.cloud.storage.Bucket`. If you do not pass a bucket name, the SDK uses the app's `storageBucket` option.\n\n```python\nfrom firebase_admin import storage\n\nbucket = storage.bucket()\nblob = bucket.blob(\"exports/report.json\")\nblob.upload_from_filename(\"report.json\", content_type=\"application/json\")\n\nsigned_url = blob.generate_signed_url(version=\"v4\", expiration=900)\nprint(signed_url)\n```\n\n### Remote Config For Server Apps\n\nServer-side Remote Config support exists in the admin SDK. Fetch and evaluate a server template when you want config-driven behavior on the backend:\n\n```python\nimport asyncio\nfrom firebase_admin import remote_config\n\nasync def load_config():\n    template = await remote_config.get_server_template(\n        default_config={\"feature_enabled\": \"false\"}\n    )\n    config = template.evaluate({\"app_version\": \"7.2.0\"})\n    return config.get_boolean(\"feature_enabled\")\n\nenabled = asyncio.run(load_config())\n```\n\n### Cloud Functions Task Queue Integration\n\nThe SDK can enqueue Cloud Tasks for task-queue functions:\n\n```python\nfrom firebase_admin import functions\n\nqueue = functions.task_queue(\"locations/us-central1/functions/processReport\")\ntask = queue.enqueue({\"reportId\": \"rpt_123\"})\nprint(task.name)\n```\n\nIn `7.2.0`, task queue support gained Cloud Tasks emulator support through `CLOUD_TASKS_EMULATOR_HOST`.\n\n## Configuration And Permissions\n\n- Firebase Admin SDK calls run with admin privileges from the service account or runtime identity.\n- The Firebase project must exist and the relevant APIs must be enabled.\n- Firestore access still depends on Google Cloud Firestore being provisioned for the project.\n- Realtime Database access needs the correct `databaseURL`; the SDK cannot infer alternate database instances from the path alone.\n- Storage access needs a valid bucket and IAM permissions on that bucket.\n- Messaging requires valid FCM registration tokens from client apps.\n- Auth flows that generate email links or session cookies depend on project Auth settings being configured correctly.\n\n## Common Pitfalls\n\n- Initializing the default app twice raises `ValueError`. Reuse `firebase_admin.get_app()` or give the second app a name.\n- Agents often forget `projectId`, `databaseURL`, or `storageBucket`; this causes failures later when database, storage, or token verification APIs try to infer missing config.\n- `auth.verify_id_token()` verifies client ID tokens, not custom tokens.\n- `clock_skew_seconds` for token verification must be between `0` and `60`.\n- Realtime Database `listen()` starts a background thread and is documented as experimental. It also does not honor auth overrides or timeout settings.\n- Firestore and Storage admin helpers rely on the underlying Google Cloud client libraries. If your environment strips dependencies or vendors packages aggressively, missing-module issues usually come from `google-cloud-firestore` or `google-cloud-storage`.\n- `storage.bucket()` fails if neither the call nor app options provide a bucket name.\n- For multiple Firebase projects in one process, pass `app=` explicitly to module APIs instead of assuming the default app.\n\n## Version-Sensitive Notes\n\n- `7.2.0` was released on February 25, 2026. It added Cloud Tasks emulator support for task-queue functions via `CLOUD_TASKS_EMULATOR_HOST`, fixed a cold-start credential-loading issue for enqueued tasks, and fixed auth error-code parsing when responses contained extra whitespace.\n- `7.1.0` added `ActionCodeSettings.link_domain` and deprecated `dynamic_link_domain` for email action flows.\n- `7.0.0` dropped Python `3.7` and `3.8`, and the release notes explicitly deprecated Python `3.9` for deployed admin SDK usage even though PyPI still allows installation on `>=3.9`.\n- `7.0.0` removed the old messaging batch APIs `send_all()` and `send_multicast()`. Use `send_each()` and `send_each_for_multicast()` or their async variants instead.\n- `6.9.0` added `send_each_async()` and `send_each_for_multicast_async()` for async HTTP/2 FCM sends.\n- `6.7.0` added server-side Remote Config support.\n- `6.6.0` added support for multiple named Firestore databases via `database_id`.\n\n## Official Sources\n\n- Firebase Admin Python setup guide: `https://firebase.google.com/docs/admin/setup`\n- Firebase Admin Python reference root: `https://firebase.google.com/docs/reference/admin/python`\n- `firebase_admin` module reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin`\n- Auth reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.auth`\n- Realtime Database reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.db`\n- Firestore reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.firestore`\n- Firestore async reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.firestore_async`\n- Messaging reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.messaging`\n- Storage reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.storage`\n- Functions reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.functions`\n- Remote Config reference: `https://firebase.google.com/docs/reference/admin/python/firebase_admin.remote_config`\n- Firebase Admin Python release notes: `https://firebase.google.com/support/release-notes/admin/python`\n- PyPI package page: `https://pypi.org/project/firebase-admin/`\n"
  },
  {
    "path": "content/firebase/docs/auth/DOC.md",
    "content": "---\nname: auth\ndescription: \"Firebase Authentication JavaScript SDK - Comprehensive coding guide for Firebase auth in JavaScript projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.4.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"firebase,auth,google,identity,session\"\n---\n\n# Firebase Authentication JavaScript SDK - Comprehensive Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Firebase Authentication package:**\n- Package: `firebase/auth` (modular SDK)\n- Legacy: `@firebase/auth` (use only if maintaining legacy code)\n\n**Never use deprecated Firebase namespaced imports.** The modular SDK is the only recommended approach for new projects.\n\n## 2. Installation\n\n### npm\n```bash\nnpm install firebase\n```\n\n### yarn\n```bash\nyarn add firebase\n```\n\n### pnpm\n```bash\npnpm add firebase\n```\n\n**Environment Variables (Optional):**\n```bash\nFIREBASE_API_KEY=your_api_key_here\nFIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com\nFIREBASE_PROJECT_ID=your-project-id\n```\n\n## 3. Initialization\n\n### Basic Initialization\n```javascript\nimport { initializeApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\n\nconst firebaseConfig = {\n  apiKey: \"your-api-key\",\n  authDomain: \"your-project.firebaseapp.com\",\n  projectId: \"your-project-id\"\n};\n\nconst app = initializeApp(firebaseConfig);\nconst auth = getAuth(app);\n```\n\n### Advanced Initialization\n\n#### Custom Settings with Dependencies\n```javascript\nimport {\n  initializeAuth,\n  browserLocalPersistence,\n  browserPopupRedirectResolver\n} from 'firebase/auth';\n\nconst auth = initializeAuth(app, {\n  persistence: browserLocalPersistence,\n  popupRedirectResolver: browserPopupRedirectResolver\n});\n```\n\n#### Cordova/Capacitor Initialization\n```javascript\nimport {\n  initializeAuth,\n  indexedDBLocalPersistence,\n  cordovaPopupRedirectResolver\n} from 'firebase/auth';\n\nconst auth = initializeAuth(app, {\n  persistence: indexedDBLocalPersistence,\n  popupRedirectResolver: cordovaPopupRedirectResolver\n});\n```\n\n### Emulator Connection\n```javascript\nimport { connectAuthEmulator } from 'firebase/auth';\n\n// Connect to local emulator (must be called before any operations)\nconnectAuthEmulator(auth, 'http://localhost:9099');\n```\n\n## 4. Core API Surfaces\n\n### Email/Password Authentication\n\n#### Minimal Example - Sign Up\n```javascript\nimport { createUserWithEmailAndPassword } from 'firebase/auth';\n\nconst userCredential = await createUserWithEmailAndPassword(\n  auth,\n  'user@example.com',\n  'password123'\n);\n```\n\n#### Minimal Example - Sign In\n```javascript\nimport { signInWithEmailAndPassword } from 'firebase/auth';\n\nconst userCredential = await signInWithEmailAndPassword(\n  auth,\n  'user@example.com',\n  'password123'\n);\n```\n\n#### Minimal Example - Sign Out\n```javascript\nimport { signOut } from 'firebase/auth';\n\nawait signOut(auth);\n```\n\n#### Advanced Example - Password Reset\n```javascript\nimport { sendPasswordResetEmail } from 'firebase/auth';\n\nawait sendPasswordResetEmail(auth, 'user@example.com', {\n  url: 'https://myapp.com/login',\n  handleCodeInApp: false\n});\n```\n\n#### Advanced Example - Update Password\n```javascript\nimport { updatePassword } from 'firebase/auth';\n\nconst user = auth.currentUser;\nawait updatePassword(user, 'newPassword123');\n```\n\n#### Email Verification\n```javascript\nimport { sendEmailVerification } from 'firebase/auth';\n\nconst user = auth.currentUser;\nawait sendEmailVerification(user, {\n  url: 'https://myapp.com/verify',\n  handleCodeInApp: true\n});\n```\n\n### Social Authentication (OAuth Providers)\n\n#### Minimal Example - Google Sign In (Popup)\n```javascript\nimport { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nconst result = await signInWithPopup(auth, provider);\n```\n\n#### Advanced Example - Google Sign In with Scopes\n```javascript\nimport { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nprovider.addScope('https://www.googleapis.com/auth/contacts.readonly');\nprovider.setCustomParameters({\n  prompt: 'select_account'\n});\n\nconst result = await signInWithPopup(auth, provider);\nconst credential = GoogleAuthProvider.credentialFromResult(result);\nconst accessToken = credential.accessToken;\n```\n\n#### Redirect Flow (Mobile/Better UX)\n```javascript\nimport { signInWithRedirect, getRedirectResult, GoogleAuthProvider } from 'firebase/auth';\n\n// Initiate redirect\nconst provider = new GoogleAuthProvider();\nawait signInWithRedirect(auth, provider);\n\n// After redirect, get result\nconst result = await getRedirectResult(auth);\nif (result) {\n  const user = result.user;\n}\n```\n\n#### Facebook Authentication\n```javascript\nimport { signInWithPopup, FacebookAuthProvider } from 'firebase/auth';\n\nconst provider = new FacebookAuthProvider();\nprovider.addScope('user_birthday');\nconst result = await signInWithPopup(auth, provider);\n```\n\n#### GitHub Authentication\n```javascript\nimport { signInWithPopup, GithubAuthProvider } from 'firebase/auth';\n\nconst provider = new GithubAuthProvider();\nprovider.addScope('repo');\nconst result = await signInWithPopup(auth, provider);\n```\n\n#### Twitter/X Authentication\n```javascript\nimport { signInWithPopup, TwitterAuthProvider } from 'firebase/auth';\n\nconst provider = new TwitterAuthProvider();\nconst result = await signInWithPopup(auth, provider);\n```\n\n#### Microsoft Authentication\n```javascript\nimport { signInWithPopup, OAuthProvider } from 'firebase/auth';\n\nconst provider = new OAuthProvider('microsoft.com');\nprovider.addScope('mail.read');\nconst result = await signInWithPopup(auth, provider);\n```\n\n#### Apple Authentication\n```javascript\nimport { signInWithPopup, OAuthProvider } from 'firebase/auth';\n\nconst provider = new OAuthProvider('apple.com');\nprovider.addScope('email');\nprovider.addScope('name');\nconst result = await signInWithPopup(auth, provider);\n```\n\n### Phone Authentication\n\n#### Minimal Example - Send Verification Code\n```javascript\nimport { RecaptchaVerifier, signInWithPhoneNumber } from 'firebase/auth';\n\n// Setup reCAPTCHA\nconst recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {\n  size: 'invisible'\n});\n\n// Send code\nconst confirmationResult = await signInWithPhoneNumber(\n  auth,\n  '+1234567890',\n  recaptchaVerifier\n);\n```\n\n#### Advanced Example - Verify Code\n```javascript\n// User enters verification code\nconst code = '123456';\nconst result = await confirmationResult.confirm(code);\nconst user = result.user;\n```\n\n#### Visible reCAPTCHA\n```javascript\nconst recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {\n  size: 'normal',\n  callback: (response) => {\n    // reCAPTCHA solved\n  },\n  'expired-callback': () => {\n    // reCAPTCHA expired\n  }\n});\n\nrecaptchaVerifier.render();\n```\n\n### Anonymous Authentication\n\n#### Minimal Example\n```javascript\nimport { signInAnonymously } from 'firebase/auth';\n\nconst userCredential = await signInAnonymously(auth);\nconst user = userCredential.user;\nconsole.log('Anonymous user ID:', user.uid);\n```\n\n#### Link Anonymous Account to Email\n```javascript\nimport { linkWithCredential, EmailAuthProvider } from 'firebase/auth';\n\nconst credential = EmailAuthProvider.credential('user@example.com', 'password123');\nconst userCredential = await linkWithCredential(auth.currentUser, credential);\n```\n\n### Custom Token Authentication\n\n#### Minimal Example\n```javascript\nimport { signInWithCustomToken } from 'firebase/auth';\n\n// Token generated on your server\nconst customToken = 'your-custom-token';\nconst userCredential = await signInWithCustomToken(auth, customToken);\n```\n\n### Email Link Authentication\n\n#### Send Sign-In Link\n```javascript\nimport { sendSignInLinkToEmail } from 'firebase/auth';\n\nconst actionCodeSettings = {\n  url: 'https://www.example.com/finishSignUp?cartId=1234',\n  handleCodeInApp: true,\n  iOS: {\n    bundleId: 'com.example.ios'\n  },\n  android: {\n    packageName: 'com.example.android',\n    installApp: true,\n    minimumVersion: '12'\n  }\n};\n\nawait sendSignInLinkToEmail(auth, 'user@example.com', actionCodeSettings);\n// Save email to verify after redirect\nwindow.localStorage.setItem('emailForSignIn', 'user@example.com');\n```\n\n#### Complete Sign-In with Email Link\n```javascript\nimport { isSignInWithEmailLink, signInWithEmailLink } from 'firebase/auth';\n\n// Confirm the link is a sign-in with email link\nif (isSignInWithEmailLink(auth, window.location.href)) {\n  let email = window.localStorage.getItem('emailForSignIn');\n  if (!email) {\n    email = window.prompt('Please provide your email for confirmation');\n  }\n\n  const result = await signInWithEmailLink(auth, email, window.location.href);\n  window.localStorage.removeItem('emailForSignIn');\n}\n```\n\n### SAML Authentication\n\n#### Sign In with SAML\n```javascript\nimport { signInWithPopup, SAMLAuthProvider } from 'firebase/auth';\n\nconst provider = new SAMLAuthProvider('saml.provider-id');\nconst result = await signInWithPopup(auth, provider);\n```\n\n### Multi-Factor Authentication (MFA)\n\n#### Enroll User in Phone MFA\n```javascript\nimport { multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator } from 'firebase/auth';\n\nconst user = auth.currentUser;\nconst multiFactorSession = await multiFactor(user).getSession();\n\nconst phoneAuthProvider = new PhoneAuthProvider(auth);\nconst verificationId = await phoneAuthProvider.verifyPhoneNumber(\n  '+1234567890',\n  recaptchaVerifier,\n  multiFactorSession\n);\n\nconst verificationCode = '123456'; // User enters code\nconst phoneAuthCredential = PhoneAuthProvider.credential(verificationId, verificationCode);\nconst multiFactorAssertion = PhoneMultiFactorGenerator.assertion(phoneAuthCredential);\n\nawait multiFactor(user).enroll(multiFactorAssertion, 'Personal phone');\n```\n\n#### Enroll User in TOTP MFA\n```javascript\nimport { multiFactor, TotpMultiFactorGenerator, TotpSecret } from 'firebase/auth';\n\nconst user = auth.currentUser;\nconst multiFactorSession = await multiFactor(user).getSession();\n\n// Generate TOTP secret\nconst totpSecret = await TotpSecret.generate(auth, multiFactorSession);\n\n// Display QR code to user\nconst qrCodeUrl = totpSecret.generateQrCodeUrl(user.email, 'MyApp');\nconsole.log('QR Code URL:', qrCodeUrl);\n\n// User scans QR code and enters verification code\nconst verificationCode = '123456';\nconst multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(\n  totpSecret,\n  verificationCode\n);\n\nawait multiFactor(user).enroll(multiFactorAssertion, 'TOTP device');\n```\n\n#### Sign In with Phone MFA\n```javascript\nimport { getMultiFactorResolver, PhoneAuthProvider, PhoneMultiFactorGenerator } from 'firebase/auth';\n\ntry {\n  await signInWithEmailAndPassword(auth, email, password);\n} catch (error) {\n  if (error.code === 'auth/multi-factor-auth-required') {\n    const resolver = getMultiFactorResolver(auth, error);\n\n    const phoneAuthProvider = new PhoneAuthProvider(auth);\n    const verificationId = await phoneAuthProvider.verifyPhoneNumber(\n      resolver.hints[0].phoneNumber,\n      recaptchaVerifier\n    );\n\n    const verificationCode = '123456'; // User enters code\n    const phoneAuthCredential = PhoneAuthProvider.credential(verificationId, verificationCode);\n    const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(phoneAuthCredential);\n\n    const userCredential = await resolver.resolveSignIn(multiFactorAssertion);\n  }\n}\n```\n\n#### Sign In with TOTP MFA\n```javascript\nimport { getMultiFactorResolver, TotpMultiFactorGenerator } from 'firebase/auth';\n\ntry {\n  await signInWithEmailAndPassword(auth, email, password);\n} catch (error) {\n  if (error.code === 'auth/multi-factor-auth-required') {\n    const resolver = getMultiFactorResolver(auth, error);\n\n    // Select TOTP factor\n    const totpInfo = resolver.hints.find(hint => hint.factorId === 'totp');\n\n    const verificationCode = '123456'; // User enters TOTP code\n    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForSignIn(\n      totpInfo.uid,\n      verificationCode\n    );\n\n    const userCredential = await resolver.resolveSignIn(multiFactorAssertion);\n  }\n}\n```\n\n#### Unenroll from MFA\n```javascript\nimport { multiFactor } from 'firebase/auth';\n\nconst user = auth.currentUser;\nconst enrolledFactors = multiFactor(user).enrolledFactors;\n\n// Unenroll from specific factor\nawait multiFactor(user).unenroll(enrolledFactors[0]);\n```\n\n## 5. Advanced Features\n\n### User State Management\n\n#### Auth State Observer\n```javascript\nimport { onAuthStateChanged } from 'firebase/auth';\n\nconst unsubscribe = onAuthStateChanged(auth, (user) => {\n  if (user) {\n    console.log('User is signed in:', user.uid);\n  } else {\n    console.log('User is signed out');\n  }\n});\n\n// Cleanup\nunsubscribe();\n```\n\n#### ID Token Changed Listener\n```javascript\nimport { onIdTokenChanged } from 'firebase/auth';\n\nconst unsubscribe = onIdTokenChanged(auth, (user) => {\n  if (user) {\n    // Get fresh token\n    user.getIdToken().then((token) => {\n      console.log('Fresh token:', token);\n    });\n  }\n});\n```\n\n#### Before Auth State Changed (Blocking Callback)\n```javascript\nimport { beforeAuthStateChanged } from 'firebase/auth';\n\nconst unsubscribe = beforeAuthStateChanged(\n  auth,\n  async (user) => {\n    // Runs before auth state changes\n    // Can be async and block the state change\n    if (user) {\n      console.log('User about to be set:', user.uid);\n      // Perform any necessary checks\n    }\n  },\n  () => {\n    // onAbort callback - called if a later beforeAuthStateChanged throws\n    console.log('Auth state change was aborted');\n  }\n);\n```\n\n#### Update Current User\n```javascript\nimport { updateCurrentUser } from 'firebase/auth';\n\n// Set a different user as current user\nawait updateCurrentUser(auth, newUser);\n```\n\n#### Get Current User\n```javascript\nconst user = auth.currentUser;\n\nif (user) {\n  console.log('User ID:', user.uid);\n  console.log('Email:', user.email);\n  console.log('Display Name:', user.displayName);\n  console.log('Photo URL:', user.photoURL);\n  console.log('Email Verified:', user.emailVerified);\n}\n```\n\n### User Profile Management\n\n#### Update Profile\n```javascript\nimport { updateProfile } from 'firebase/auth';\n\nconst user = auth.currentUser;\nawait updateProfile(user, {\n  displayName: 'John Doe',\n  photoURL: 'https://example.com/photo.jpg'\n});\n```\n\n#### Update Email (Deprecated)\n```javascript\nimport { updateEmail, sendEmailVerification } from 'firebase/auth';\n\nconst user = auth.currentUser;\nawait updateEmail(user, 'newemail@example.com');\nawait sendEmailVerification(user);\n```\n\n#### Update Email with Verification (Recommended)\n```javascript\nimport { verifyBeforeUpdateEmail } from 'firebase/auth';\n\nconst actionCodeSettings = {\n  url: 'https://www.example.com/?email=user@example.com'\n};\n\nconst user = auth.currentUser;\nawait verifyBeforeUpdateEmail(user, 'newemail@example.com', actionCodeSettings);\n// User must verify new email before it takes effect\n```\n\n#### Update Phone Number\n```javascript\nimport { updatePhoneNumber, PhoneAuthProvider } from 'firebase/auth';\n\n// First get phone credential\nconst phoneAuthProvider = new PhoneAuthProvider(auth);\nconst verificationId = await phoneAuthProvider.verifyPhoneNumber(\n  '+1234567890',\n  recaptchaVerifier\n);\n\nconst verificationCode = '123456'; // User enters code\nconst phoneCredential = PhoneAuthProvider.credential(verificationId, verificationCode);\n\nconst user = auth.currentUser;\nawait updatePhoneNumber(user, phoneCredential);\n```\n\n#### Reload User Data\n```javascript\nimport { reload } from 'firebase/auth';\n\nawait reload(auth.currentUser);\nconst updatedUser = auth.currentUser;\n```\n\n#### Delete User Account\n```javascript\nimport { deleteUser } from 'firebase/auth';\n\nconst user = auth.currentUser;\nawait deleteUser(user);\n```\n\n### Token Management\n\n#### Get ID Token\n```javascript\nconst user = auth.currentUser;\nconst token = await user.getIdToken();\nconst refreshedToken = await user.getIdToken(true); // Force refresh\n```\n\n#### Get ID Token Result (with Claims)\n```javascript\nimport { getIdToken, getIdTokenResult } from 'firebase/auth';\n\nconst user = auth.currentUser;\n\n// Using user method\nconst token = await getIdToken(user);\nconst idTokenResult = await getIdTokenResult(user);\n\nconsole.log('Token:', idTokenResult.token);\nconsole.log('Expiration:', idTokenResult.expirationTime);\nconsole.log('Custom Claims:', idTokenResult.claims);\nconsole.log('Auth Time:', idTokenResult.authTime);\nconsole.log('Issued At:', idTokenResult.issuedAtTime);\nconsole.log('Sign-in Provider:', idTokenResult.signInProvider);\n```\n\n### Password Validation\n\n#### Validate Password Against Policy\n```javascript\nimport { validatePassword } from 'firebase/auth';\n\nconst validationStatus = await validatePassword(auth, 'MyPassword123!');\n\nconsole.log('Is valid:', validationStatus.isValid);\nconsole.log('Contains lowercase:', validationStatus.containsLowercaseLetter);\nconsole.log('Contains uppercase:', validationStatus.containsUppercaseLetter);\nconsole.log('Contains numeric:', validationStatus.containsNumericCharacter);\nconsole.log('Contains non-alphanumeric:', validationStatus.containsNonAlphanumericCharacter);\nconsole.log('Meets min length:', validationStatus.meetsMinPasswordLength);\nconsole.log('Meets max length:', validationStatus.meetsMaxPasswordLength);\n```\n\n### Account Linking\n\n#### Link Multiple Providers\n```javascript\nimport { linkWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nconst result = await linkWithPopup(auth.currentUser, provider);\n```\n\n#### Link with Credential\n```javascript\nimport { linkWithCredential, EmailAuthProvider } from 'firebase/auth';\n\nconst credential = EmailAuthProvider.credential('user@example.com', 'password123');\nawait linkWithCredential(auth.currentUser, credential);\n```\n\n#### Link with Phone Number\n```javascript\nimport { linkWithPhoneNumber } from 'firebase/auth';\n\nconst confirmationResult = await linkWithPhoneNumber(\n  auth.currentUser,\n  '+1234567890',\n  recaptchaVerifier\n);\n\nconst verificationCode = '123456';\nawait confirmationResult.confirm(verificationCode);\n```\n\n#### Link with Redirect\n```javascript\nimport { linkWithRedirect, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nawait linkWithRedirect(auth.currentUser, provider);\n\n// After redirect, check result\nconst result = await getRedirectResult(auth);\n```\n\n#### Unlink Provider\n```javascript\nimport { unlink } from 'firebase/auth';\n\nawait unlink(auth.currentUser, 'google.com');\n```\n\n#### Fetch Sign-In Methods\n```javascript\nimport { fetchSignInMethodsForEmail } from 'firebase/auth';\n\nconst methods = await fetchSignInMethodsForEmail(auth, 'user@example.com');\nconsole.log('Available sign-in methods:', methods);\n```\n\n### Re-authentication\n\n#### Re-authenticate User\n```javascript\nimport { reauthenticateWithCredential, EmailAuthProvider } from 'firebase/auth';\n\nconst user = auth.currentUser;\nconst credential = EmailAuthProvider.credential(user.email, 'current-password');\n\nawait reauthenticateWithCredential(user, credential);\n// Now perform sensitive operations\n```\n\n#### Re-authenticate with Popup\n```javascript\nimport { reauthenticateWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nawait reauthenticateWithPopup(auth.currentUser, provider);\n```\n\n#### Re-authenticate with Redirect\n```javascript\nimport { reauthenticateWithRedirect, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nawait reauthenticateWithRedirect(auth.currentUser, provider);\n\n// After redirect\nconst result = await getRedirectResult(auth);\n```\n\n#### Re-authenticate with Phone Number\n```javascript\nimport { reauthenticateWithPhoneNumber } from 'firebase/auth';\n\nconst confirmationResult = await reauthenticateWithPhoneNumber(\n  auth.currentUser,\n  '+1234567890',\n  recaptchaVerifier\n);\n\nconst verificationCode = '123456';\nawait confirmationResult.confirm(verificationCode);\n```\n\n### Session Persistence\n\n#### Set Persistence (Browser)\n```javascript\nimport {\n  setPersistence,\n  browserLocalPersistence,\n  browserSessionPersistence,\n  inMemoryPersistence,\n  indexedDBLocalPersistence\n} from 'firebase/auth';\n\n// Local persistence using localStorage (survives browser restart)\nawait setPersistence(auth, browserLocalPersistence);\n\n// Session persistence using sessionStorage (survives page refresh only)\nawait setPersistence(auth, browserSessionPersistence);\n\n// No persistence (memory only)\nawait setPersistence(auth, inMemoryPersistence);\n\n// IndexedDB persistence (recommended for large data)\nawait setPersistence(auth, indexedDBLocalPersistence);\n```\n\n#### React Native Persistence\n```javascript\nimport { initializeAuth, getReactNativePersistence } from 'firebase/auth';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\nconst auth = initializeAuth(app, {\n  persistence: getReactNativePersistence(AsyncStorage)\n});\n```\n\n#### Cookie Persistence (Public Preview)\n```javascript\nimport { setPersistence, browserCookiePersistence } from 'firebase/auth';\n\n// For hybrid rendering and middleware applications\nawait setPersistence(auth, browserCookiePersistence);\n```\n\n### Language and Localization\n\n#### Use Device Language\n```javascript\nimport { useDeviceLanguage } from 'firebase/auth';\n\nuseDeviceLanguage(auth); // Use device language\n\n// Or set specific language\nauth.languageCode = 'es';\n```\n\n#### Initialize reCAPTCHA Config\n```javascript\nimport { initializeRecaptchaConfig } from 'firebase/auth';\n\n// Load reCAPTCHA config to reduce latency for auth flows\nawait initializeRecaptchaConfig(auth);\n```\n\n### Action Code Handling\n\n#### Handle Password Reset Link\n```javascript\nimport { verifyPasswordResetCode, confirmPasswordReset } from 'firebase/auth';\n\nconst actionCode = 'code-from-email-link';\n\n// Verify code is valid\nconst email = await verifyPasswordResetCode(auth, actionCode);\n\n// Reset password\nawait confirmPasswordReset(auth, actionCode, 'newPassword123');\n```\n\n#### Handle Email Verification\n```javascript\nimport { applyActionCode } from 'firebase/auth';\n\nconst actionCode = 'code-from-email-link';\nawait applyActionCode(auth, actionCode);\n```\n\n#### Handle Email Change\n```javascript\nimport { checkActionCode, applyActionCode } from 'firebase/auth';\n\nconst actionCode = 'code-from-email-link';\nconst info = await checkActionCode(auth, actionCode);\nawait applyActionCode(auth, actionCode);\n```\n\n#### Parse Action Code URL\n```javascript\nimport { parseActionCodeURL } from 'firebase/auth';\n\nconst actionCodeUrl = parseActionCodeURL('https://example.com/action?mode=...');\n\nif (actionCodeUrl) {\n  console.log('Mode:', actionCodeUrl.operation); // 'PASSWORD_RESET', 'VERIFY_EMAIL', etc.\n  console.log('Code:', actionCodeUrl.code);\n  console.log('Continue URL:', actionCodeUrl.continueUrl);\n  console.log('Language:', actionCodeUrl.languageCode);\n}\n```\n\n### Additional User Info\n\n#### Get Provider-Specific Info\n```javascript\nimport { signInWithPopup, GoogleAuthProvider, getAdditionalUserInfo } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nconst userCredential = await signInWithPopup(auth, provider);\n\nconst additionalInfo = getAdditionalUserInfo(userCredential);\nconsole.log('Is new user:', additionalInfo.isNewUser);\nconsole.log('Provider ID:', additionalInfo.providerId);\nconsole.log('Profile:', additionalInfo.profile); // Provider-specific profile\nconsole.log('Username:', additionalInfo.username); // GitHub/Twitter username\n```\n\n### Revoke Access Tokens\n\n#### Revoke Apple OAuth Token\n```javascript\nimport { revokeAccessToken } from 'firebase/auth';\n\n// Revoke Apple OAuth access token\nawait revokeAccessToken(auth, appleAccessToken);\n```\n\n## 6. TypeScript Usage\n\n### Import Types\n```typescript\nimport type {\n  Auth,\n  User,\n  UserCredential,\n  AuthProvider,\n  AuthError,\n  IdTokenResult,\n  MultiFactorResolver,\n  Unsubscribe\n} from 'firebase/auth';\n```\n\n### Type-Safe User Handling\n```typescript\nimport { onAuthStateChanged, User } from 'firebase/auth';\n\nonAuthStateChanged(auth, (user: User | null) => {\n  if (user) {\n    const uid: string = user.uid;\n    const email: string | null = user.email;\n    const emailVerified: boolean = user.emailVerified;\n  }\n});\n```\n\n### Type-Safe Error Handling\n```typescript\nimport { signInWithEmailAndPassword, AuthError } from 'firebase/auth';\n\ntry {\n  await signInWithEmailAndPassword(auth, email, password);\n} catch (error) {\n  const authError = error as AuthError;\n\n  switch (authError.code) {\n    case 'auth/user-not-found':\n      console.error('User not found');\n      break;\n    case 'auth/wrong-password':\n      console.error('Wrong password');\n      break;\n    case 'auth/invalid-email':\n      console.error('Invalid email');\n      break;\n    default:\n      console.error('Authentication error:', authError.message);\n  }\n}\n```\n\n### Custom Claims Type\n```typescript\ninterface CustomClaims {\n  admin?: boolean;\n  role?: string;\n  subscription?: string;\n}\n\nconst idTokenResult = await user.getIdTokenResult();\nconst claims = idTokenResult.claims as CustomClaims;\n\nif (claims.admin) {\n  console.log('User is an admin');\n}\n```\n\n## 7. OAuth Credential Handling\n\n#### Sign In with OAuth Credential\n```javascript\nimport { signInWithCredential, GoogleAuthProvider } from 'firebase/auth';\n\n// Create credential from access token\nconst credential = GoogleAuthProvider.credential(idToken, accessToken);\nawait signInWithCredential(auth, credential);\n```\n\n#### Extract Credential from Result\n```javascript\nimport { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\nconst provider = new GoogleAuthProvider();\nconst result = await signInWithPopup(auth, provider);\n\n// Get OAuth credential from result\nconst credential = GoogleAuthProvider.credentialFromResult(result);\nconst accessToken = credential.accessToken;\nconst idToken = credential.idToken;\n```\n\n#### Extract Credential from Error\n```javascript\nimport { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';\n\ntry {\n  await signInWithPopup(auth, provider);\n} catch (error) {\n  // Extract credential that was being used\n  const credential = GoogleAuthProvider.credentialFromError(error);\n\n  if (error.code === 'auth/account-exists-with-different-credential') {\n    // Handle account linking\n    const methods = await fetchSignInMethodsForEmail(auth, error.customData.email);\n    // Proceed with account linking flow\n  }\n}\n```\n"
  },
  {
    "path": "content/flake8/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"flake8 command-line linter for Python style, pyflakes, pycodestyle, and McCabe checks\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flake8,python,linting,pyflakes,pycodestyle,mccabe,ci\"\n---\n\n# flake8 7.3.0 Python Package Guide\n\n## Golden Rule\n\nRun `flake8` from the same virtualenv as the project, invoke it as `python -m flake8` in automation when you need interpreter certainty, and keep configuration in one of the supported INI-style files: `.flake8`, `setup.cfg`, or `tox.ini`.\n\n`flake8` is primarily a CLI tool. There is no auth flow to configure.\n\n## What Flake8 Checks\n\nFlake8 combines several check families:\n\n- `pyflakes` findings such as unused imports and undefined names\n- `pycodestyle` findings such as whitespace and formatting rules\n- `mccabe` complexity checks when `max-complexity` is configured\n\nViolation code families you will usually see:\n\n- `F...`: Pyflakes\n- `E...` and `W...`: pycodestyle\n- `C901`: McCabe complexity\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"flake8==7.3.0\"\n```\n\nCommon project-manager equivalents:\n\n```bash\nuv add --dev \"flake8==7.3.0\"\npoetry add --group dev \"flake8==7.3.0\"\n```\n\nVerify what is installed, including active plugins:\n\n```bash\npython -m flake8 --version\n```\n\n## Core Usage\n\nLint the current project:\n\n```bash\npython -m flake8 .\n```\n\nLint specific source roots:\n\n```bash\npython -m flake8 src tests\n```\n\nAdd source context and summary counts when debugging CI failures:\n\n```bash\npython -m flake8 src tests --show-source --statistics\n```\n\nTreat the command as a non-zero exit gate in CI:\n\n```bash\npython -m flake8 src tests\n```\n\nIf your tooling shells into multiple Python environments, prefer `python -m flake8` over a bare `flake8` executable so the interpreter and installed plugins match the current environment.\n\n## Configuration\n\nFlake8 reads configuration from:\n\n- `.flake8`\n- `setup.cfg`\n- `tox.ini`\n\nUse a single project-level config unless you have a strong reason to layer more.\n\nMinimal example:\n\n```ini\n[flake8]\nmax-line-length = 88\nmax-complexity = 10\nexclude =\n    .git,\n    __pycache__,\n    .venv,\n    build,\n    dist\nper-file-ignores =\n    __init__.py:F401\n```\n\nUseful knobs:\n\n- `exclude`: skip generated, vendored, or environment directories\n- `per-file-ignores`: allow targeted exceptions such as package re-export files\n- `max-line-length`: set a project-wide line length\n- `max-complexity`: enable McCabe complexity reporting\n- `select`, `ignore`, `extend-select`, `extend-ignore`: tune which code families are enforced\n\nConfiguration parsing pitfalls:\n\n- Keep comments on their own lines. Flake8 does not support inline comments for option values.\n- Use INI syntax, not TOML. Flake8 7.3.0 does not read `pyproject.toml` directly.\n- If you pass file paths explicitly on the command line, excludes behave differently than a pure directory walk. Re-check CI and pre-commit wiring if excluded files still get linted.\n\n## Common Workflows\n\n### Lint a single file while iterating\n\n```bash\npython -m flake8 path/to/module.py --show-source\n```\n\n### Gate complexity on selected code paths\n\n```ini\n[flake8]\nmax-complexity = 12\n```\n\nWithout `max-complexity`, you will not get `C901` complexity findings.\n\n### Keep `__init__.py` re-exports intentional\n\n```ini\n[flake8]\nper-file-ignores =\n    package/__init__.py:F401\n```\n\nPrefer targeted per-file ignores over globally ignoring the code.\n\n## Plugins\n\nFlake8 loads plugins installed in the same environment through entry points. In practice:\n\n1. Install the plugin package into the same environment as `flake8`\n2. Run `python -m flake8 --version`\n3. Confirm the plugin appears in the version output before relying on its codes in CI\n\nIf a repo config references plugin-specific codes but the plugin is missing, local results and CI results will drift.\n\n## Python API\n\nFlake8 exposes a Python API under `flake8.api.legacy`, but it is intentionally the legacy API surface. For editor integration, CI, and agent automation, prefer the CLI unless you have a specific need to call the API directly.\n\nMinimal example:\n\n```python\nfrom flake8.api import legacy as flake8\n\nstyle_guide = flake8.get_style_guide(ignore=[\"E24\", \"W504\"])\nreport = style_guide.check_files([\"src\", \"tests\"])\n\nif report.total_errors:\n    raise SystemExit(1)\n```\n\nUse this sparingly. Shelling out to `python -m flake8` is usually easier to reason about and keeps plugin loading behavior aligned with normal command-line runs.\n\n## Common Pitfalls\n\n- Do not assume `pyproject.toml` support. For Flake8 7.3.0, the documented config files are still `.flake8`, `setup.cfg`, and `tox.ini`.\n- Do not rely on a globally installed `flake8` if the project also needs plugins. Install both `flake8` and plugins in the project environment.\n- Do not expect inline comments inside multi-line config values to work.\n- Do not enable `ignore = ...` broadly when `per-file-ignores` or `extend-ignore` would keep the rule set tighter.\n- Do not expect complexity warnings unless `max-complexity` is set.\n- If older tooling still passes doctest-related Flake8 flags, re-check it against 7.x; some old doctest CLI options were removed in 7.0.0.\n\n## Version-Sensitive Notes\n\nFor `7.3.0` specifically:\n\n- PyPI requires Python `>=3.9`.\n- The 7.3.0 release notes mention support for Python `3.14`.\n- The 7.3.0 release also updated bundled checker dependencies to `pycodestyle >= 2.14.0, < 2.15.0` and `Pyflakes >= 3.4.0, < 3.5.0`.\n\nRelevant 7.x migration note:\n\n- Flake8 7.0.0 dropped Python 3.8 support and removed older doctest-related options such as `--include-in-doctest` and `--exclude-from-doctest`.\n\n## Official Source URLs\n\n- Docs root: `https://flake8.pycqa.org/en/7.3.0/`\n- User guide index: `https://flake8.pycqa.org/en/7.3.0/user/index.html`\n- Invoking Flake8: `https://flake8.pycqa.org/en/7.3.0/user/invocation.html`\n- Configuration: `https://flake8.pycqa.org/en/7.3.0/user/configuration.html`\n- Python API: `https://flake8.pycqa.org/en/7.3.0/user/python-api.html`\n- Release notes: `https://flake8.pycqa.org/en/7.3.0/release-notes/7.3.0.html`\n- PyPI release page: `https://pypi.org/project/flake8/7.3.0/`\n"
  },
  {
    "path": "content/flask/docs/admin/python/DOC.md",
    "content": "---\nname: admin\ndescription: \"Flask-Admin package guide for building authenticated Flask admin interfaces and CRUD views\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask-admin,flask,admin,sqlalchemy,wtforms,crud\"\n---\n\n# Flask-Admin Python Package Guide\n\n## What It Is\n\n`Flask-Admin` adds an admin UI layer to Flask applications. The common case is CRUD screens for SQLAlchemy models, but the package also supports custom `BaseView` pages, file administration, and menu/navigation helpers.\n\nThis entry is for `Flask-Admin==2.0.2`. Use `2.x` setup and config patterns here. Do not copy older `1.6.x` snippets that rely on `template_mode=` or unprefixed `ADMIN_*` config names.\n\n## Install\n\nInstall the base package plus the backend extra you need. For SQLAlchemy-backed admin views, the official `2.x` docs use the `sqlalchemy` extra.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"flask-admin[sqlalchemy]==2.0.2\" \"Flask-SQLAlchemy\"\n```\n\nOther useful extras are available for MongoEngine, Peewee, Redis, and translation support. Install only the integration you actually use.\n\n## Minimal SQLAlchemy Setup\n\nIn `2.x`, initialize `Admin` with a theme object instead of `template_mode=...`.\n\n```python\nfrom flask import Flask\nfrom flask_admin import Admin\nfrom flask_admin.contrib.sqla import ModelView\nfrom flask_admin.theme import Bootstrap4Theme\nfrom flask_sqlalchemy import SQLAlchemy\n\napp = Flask(__name__)\napp.config.update(\n    SECRET_KEY=\"dev-only-change-me\",\n    SQLALCHEMY_DATABASE_URI=\"sqlite:///app.db\",\n)\n\ndb = SQLAlchemy(app)\n\nclass User(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    email = db.Column(db.String(255), unique=True, nullable=False)\n    is_active = db.Column(db.Boolean, default=True, nullable=False)\n\nadmin = Admin(\n    app,\n    name=\"Example Admin\",\n    theme=Bootstrap4Theme(),\n)\nadmin.add_view(ModelView(User, db.session))\n\nwith app.app_context():\n    db.create_all()\n```\n\nPractical rules:\n\n- Keep `SECRET_KEY` set before you use admin forms, sessions, or CSRF features.\n- Pass `db.session` to `ModelView` for SQLAlchemy-backed views.\n- Prefer an explicit theme object so the code is obviously `2.x` and not an older template-mode example.\n\n## App Factory Setup\n\nUse `init_app()` when your project follows the Flask extension pattern.\n\n```python\nfrom flask import Flask\nfrom flask_admin import Admin\nfrom flask_admin.contrib.sqla import ModelView\nfrom flask_admin.theme import Bootstrap4Theme\nfrom flask_sqlalchemy import SQLAlchemy\n\ndb = SQLAlchemy()\nadmin = Admin(name=\"Example Admin\", theme=Bootstrap4Theme())\n\nclass UserAdmin(ModelView):\n    can_view_details = True\n    column_searchable_list = [\"email\"]\n    column_filters = [\"is_active\"]\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        SECRET_KEY=\"dev-only-change-me\",\n        SQLALCHEMY_DATABASE_URI=\"sqlite:///app.db\",\n    )\n\n    db.init_app(app)\n    admin.init_app(app)\n\n    from .models import User\n\n    admin.add_view(UserAdmin(User, db.session))\n    return app\n```\n\nIf the factory can run multiple times in tests, avoid blindly calling `add_view()` on every import path. Register views once per process or guard duplicate registration.\n\n## Core `ModelView` Configuration\n\nThese attributes and hooks cover most real projects:\n\n- `can_create`, `can_edit`, `can_delete` to disable CRUD actions\n- `can_view_details` to expose a read-only details page\n- `column_list`, `column_exclude_list`, `column_searchable_list`, and `column_filters` to shape list views\n- `column_editable_list` for inline editing from the list page\n- `form_excluded_columns`, `form_args`, and `form_widget_args` for form customization\n- `form_ajax_refs` for foreign-key lookups backed by AJAX\n- `inline_models` to edit related rows inline\n- `can_export` and `export_types` for CSV-style exports\n- `page_size`, `can_set_page_size`, and `page_size_options` for pagination behavior\n\nExample:\n\n```python\nfrom flask_admin.contrib.sqla import ModelView\nfrom flask_admin.form import SecureForm\n\nclass UserAdmin(ModelView):\n    form_base_class = SecureForm\n\n    can_view_details = True\n    can_export = True\n    column_list = [\"email\", \"is_active\"]\n    column_searchable_list = [\"email\"]\n    column_filters = [\"is_active\"]\n    page_size = 50\n    can_set_page_size = True\n    page_size_options = [25, 50, 100]\n```\n\nUse one subclass per model once behavior starts to diverge. A single shared `ModelView` across unrelated models becomes hard to reason about quickly.\n\n## Access Control And Authentication\n\n`Flask-Admin` does not provide a complete authentication system. Protect every view by overriding `is_accessible()` and usually `inaccessible_callback()`.\n\n```python\nfrom flask import redirect, request, url_for\nfrom flask_login import current_user\nfrom flask_admin.contrib.sqla import ModelView\n\nclass StaffModelView(ModelView):\n    def is_accessible(self) -> bool:\n        return current_user.is_authenticated and current_user.is_admin\n\n    def inaccessible_callback(self, name, **kwargs):\n        return redirect(url_for(\"login\", next=request.url))\n```\n\nImportant:\n\n- Menu visibility is not authorization. Always enforce access checks in the view class.\n- Protect custom `BaseView` pages the same way you protect `ModelView` subclasses.\n- If you integrate Flask-Security-Too or another auth library, reuse its login route in `inaccessible_callback()` instead of creating a parallel admin-only auth flow.\n\n## Custom Pages, Templates, And Routing\n\nUse `BaseView` for pages that are not directly tied to one model.\n\n```python\nfrom flask_admin import BaseView, expose\n\nclass AnalyticsView(BaseView):\n    @expose(\"/\")\n    def index(self):\n        return self.render(\"admin/analytics.html\")\n```\n\n```python\nadmin.add_view(AnalyticsView(name=\"Analytics\", endpoint=\"analytics\"))\n```\n\nTemplate rules that matter:\n\n- Extend `admin/master.html` for custom admin pages.\n- Extend `admin/model/list.html`, `admin/model/create.html`, or `admin/model/edit.html` when you only need to customize built-in CRUD screens.\n- Prefer extending upstream templates over copying the entire admin template tree.\n\n`2.x` also supports host-aware routing on `Admin(...)` and `@expose(...)` when your Flask app uses host matching:\n\n```python\nfrom flask import Flask\nfrom flask_admin import BaseView, Admin, expose\n\napp = Flask(__name__, host_matching=True, static_host=\"cdn.example.com\")\n\nclass ReportsView(BaseView):\n    @expose(\"/\", host=\"admin.example.com\")\n    def index(self):\n        return self.render(\"admin/reports.html\")\n\nadmin = Admin(app, host=\"admin.example.com\")\nadmin.add_view(ReportsView(name=\"Reports\", endpoint=\"reports\"))\n```\n\nOnly use `host=` when your Flask routing setup already enables host matching. Otherwise keep admin routes path-based.\n\n## Config, CSRF, And CSP\n\nThe `2.x` line moves project config to `FLASK_ADMIN_*` names. Use the namespaced settings, not the older `ADMIN_*` variants.\n\nUseful config:\n\n- `FLASK_ADMIN_SWATCH` for the Bootswatch theme name\n- `FLASK_ADMIN_FLUID_LAYOUT` to use full-width layout\n- `FLASK_ADMIN_RAISE_ON_INTEGRITY_ERROR` to bubble integrity errors during writes\n- `FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION` to raise view exceptions instead of swallowing them\n\nFor CSRF protection on model forms:\n\n```python\nfrom flask_admin.contrib.sqla import ModelView\nfrom flask_admin.form import SecureForm\n\nclass ProtectedModelView(ModelView):\n    form_base_class = SecureForm\n```\n\nFor Content Security Policy nonces, `2.x` adds `csp_nonce_generator=` on `Admin(...)`:\n\n```python\nfrom flask import Flask, g\nfrom flask_admin import Admin\nfrom flask_admin.theme import Bootstrap4Theme\n\ndef csp_nonce() -> str:\n    return g.csp_nonce\n\napp = Flask(__name__)\nadmin = Admin(app, theme=Bootstrap4Theme(), csp_nonce_generator=csp_nonce)\n```\n\nPractical notes:\n\n- `SecureForm` still depends on Flask sessions working correctly, so test create and edit flows after enabling it.\n- If your app already enforces CSP, wire `csp_nonce_generator` up early instead of patching templates later.\n- Keep config names consistent. Mixing `ADMIN_*` and `FLASK_ADMIN_*` creates hard-to-see drift during upgrades.\n\n## Common Pitfalls\n\n### Copying `1.x` examples into a `2.0.2` project\n\nAvoid these old patterns in `2.0.2` code:\n\n- `Admin(..., template_mode=\"bootstrap3\")`\n- unprefixed `ADMIN_RAISE_ON_*` config names\n- Flask-BabelEx integration examples\n- legacy S3 file admin code that does not use `boto3.client(\"s3\")`\n\n### Forgetting the backend dependency\n\n`Flask-Admin` does not make SQLAlchemy support available unless you install the right extra and ORM dependencies. If imports from `flask_admin.contrib.sqla` fail, check your installed extras first.\n\n### Leaving custom views unprotected\n\nDevelopers often secure `ModelView` subclasses and forget `BaseView` pages. Every admin-exposed page needs explicit access control.\n\n### Registering views repeatedly in app factories\n\nCalling `admin.add_view(...)` on every factory invocation can produce duplicate menu items or test pollution. Make initialization idempotent in test-heavy apps.\n\n### Replacing upstream templates wholesale\n\nFull template copies make minor upgrades brittle. Extend a specific upstream template unless you truly need to own the full markup.\n\n## Version-Sensitive Notes For `2.0.2`\n\n- `2.0.0` introduced the new `theme=` API and deprecates `template_mode`.\n- `2.0.0` renames `ADMIN_RAISE_ON_INTEGRITY_ERROR` and `ADMIN_RAISE_ON_VIEW_EXCEPTION` to `FLASK_ADMIN_RAISE_ON_INTEGRITY_ERROR` and `FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION`.\n- `2.0.0` drops Flask-BabelEx support in favor of Flask-Babel.\n- `2.0.0` changes S3 file admin to use `boto3.client(\"s3\")` rather than legacy boto-style credential arguments.\n- `2.0.2` is the current package version on PyPI as of March 12, 2026.\n- The `latest` docs root is the correct canonical doc root for `2.0.2`, but some subpages still render `2.0.0` or `2.0.1` in their page headers. Treat the changelog and PyPI version as the source of truth for the current release number.\n"
  },
  {
    "path": "content/flask/docs/babel/python/DOC.md",
    "content": "---\nname: babel\ndescription: \"Flask-Babel 4.0.0 guide for translations, locale selection, and locale-aware formatting in Flask apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,flask-babel,i18n,l10n,translations,gettext,localization\"\n---\n\n# Flask-Babel for Flask Apps\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Flask-Babel==4.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Flask-Babel==4.0.0\"\npoetry add \"Flask-Babel==4.0.0\"\n```\n\n## Initialize In A Flask App\n\nUse an application factory and pass selector functions to `Babel(...)` or `init_app(...)`.\n\n```python\nfrom flask import Flask, g, request\nfrom flask_babel import Babel\n\nbabel = Babel()\n\ndef select_locale() -> str:\n    user = getattr(g, \"user\", None)\n    if user and user.locale:\n        return user.locale\n    return request.accept_languages.best_match([\"en\", \"de\", \"fr\"]) or \"en\"\n\ndef select_timezone() -> str:\n    user = getattr(g, \"user\", None)\n    if user and user.timezone:\n        return user.timezone\n    return \"UTC\"\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        BABEL_DEFAULT_LOCALE=\"en\",\n        BABEL_DEFAULT_TIMEZONE=\"UTC\",\n        BABEL_TRANSLATION_DIRECTORIES=\"translations\",\n        BABEL_DOMAIN=\"messages\",\n    )\n\n    babel.init_app(\n        app,\n        locale_selector=select_locale,\n        timezone_selector=select_timezone,\n    )\n\n    return app\n```\n\nImportant:\n\n- Pass selectors during initialization. In current versions, `Babel.locale_selector` and `Babel.timezone_selector` are not runtime attributes you set later.\n- Locale and timezone selectors are called once per request and cached.\n- Flask-Babel expects your app to store internal datetimes in UTC and localize for display.\n\n## Core Translation Usage\n\n### Translate request-time strings\n\n```python\nfrom flask import Blueprint, flash, redirect, url_for\nfrom flask_babel import gettext, ngettext\n\nbp = Blueprint(\"main\", __name__)\n\n@bp.post(\"/invite\")\ndef invite():\n    sent = 3\n    flash(gettext(\"Invitation sent\"))\n    flash(ngettext(\"%(count)d email queued\", \"%(count)d emails queued\", sent, count=sent))\n    return redirect(url_for(\"main.index\"))\n```\n\n### Use lazy translations for class attributes and form labels\n\n```python\nfrom flask_babel import lazy_gettext as _\nfrom wtforms import StringField\n\nclass ProfileForm:\n    display_name = StringField(_(\"Display name\"))\n```\n\nUse `lazy_gettext()` when the string is defined at import time. Plain `gettext()` there will resolve too early.\n\n### Template translations\n\nAfter `init_app()`, Flask-Babel registers gettext support and common Jinja filters by default.\n\n```jinja2\n<h1>{{ gettext(\"Welcome back\") }}</h1>\n<p>{{ invoice_total|currencyformat(\"USD\") }}</p>\n<p>{{ created_at|datetimeformat(\"medium\") }}</p>\n```\n\nIf you do not want Flask-Babel to modify the Jinja environment, initialize it with `configure_jinja=False`.\n\n## Locale-Aware Date, Time, And Number Formatting\n\nUse Flask-Babel helpers instead of manual `strftime()` calls for user-facing output:\n\n```python\nfrom datetime import datetime, timezone\n\nfrom flask_babel import format_currency, format_datetime, format_decimal\n\nnow = datetime.now(timezone.utc)\n\nformatted_date = format_datetime(now, \"long\")\nformatted_price = format_currency(19.99, \"USD\")\nformatted_ratio = format_decimal(12345.678)\n```\n\nCommon helpers:\n\n- `format_datetime()`\n- `format_date()`\n- `format_time()`\n- `format_timedelta()`\n- `format_number()`\n- `format_decimal()`\n- `format_currency()`\n- `format_percent()`\n\n## Translation Catalog Workflow\n\nFlask-Babel uses gettext catalogs under the configured translation directories.\n\nTypical layout:\n\n```text\nyourapp/\n  translations/\n    de/\n      LC_MESSAGES/\n        messages.po\n        messages.mo\n```\n\nMinimal extraction config:\n\n```ini\n[python: **.py]\n[jinja2: **/templates/**.html]\n```\n\nExtract, initialize, compile, and update catalogs with `pybabel`:\n\n```bash\npybabel extract -F babel.cfg -k lazy_gettext -o messages.pot .\npybabel init -i messages.pot -d translations -l de\npybabel compile -d translations\npybabel update -i messages.pot -d translations\n```\n\nNotes:\n\n- Add `-k lazy_gettext` if you use lazy strings.\n- `pybabel compile` is required before the app can use updated translations.\n- During development, you can have `flask run` watch compiled `.mo` files with `--extra-files` if you want reloads after recompiling.\n\n## Configuration You Will Actually Use\n\nKey config values in `4.0.0`:\n\n- `BABEL_DEFAULT_LOCALE`: fallback locale, default `en`\n- `BABEL_DEFAULT_TIMEZONE`: fallback timezone, default `UTC`\n- `BABEL_TRANSLATION_DIRECTORIES`: semicolon-separated translation roots\n- `BABEL_DOMAIN`: gettext domain, default `messages`\n\nIf you have multiple translation roots, `BABEL_DOMAIN` can also be semicolon-separated to match them positionally:\n\n```python\napp.config[\"BABEL_TRANSLATION_DIRECTORIES\"] = \"translations;plugins/payments/translations\"\napp.config[\"BABEL_DOMAIN\"] = \"messages;payments\"\n```\n\n## Runtime Helpers\n\nIf the user changes locale or timezone during a request, refresh the cached values before rendering more translated output:\n\n```python\nfrom flask import flash, request\nfrom flask_babel import gettext, refresh\n\ndef update_preferences(user):\n    user.locale = request.form[\"locale\"]\n    user.timezone = request.form[\"timezone\"]\n    refresh()\n    flash(gettext(\"Language was changed\"))\n```\n\nUse `force_locale()` for one-off work in a different language, such as sending email:\n\n```python\nfrom flask_babel import force_locale, gettext\n\nwith force_locale(\"en_US\"):\n    subject = gettext(\"Your receipt\")\n```\n\n`babel.list_translations()` is useful for locale pickers. In current versions it always includes the default locale, even if no compiled catalog exists for it.\n\n## Common Pitfalls\n\n- The docs landing page still says Flask-Babel only needs `Jinja >= 2.5`. For `4.0.0`, maintainer metadata requires `Jinja2 >= 3.1`.\n- Do not mutate `babel.locale_selector` or `babel.timezone_selector` after startup. Pass selectors into `Babel(...)` or `init_app(...)`.\n- Selectors are cached per request. If you update the active user's locale or timezone mid-request, call `refresh()` before generating more translated text.\n- Forgetting `pybabel compile` leaves translated strings unchanged because Flask-Babel reads compiled `.mo` files, not raw `.po` files.\n- `BABEL_TRANSLATION_DIRECTORIES` and `BABEL_DOMAIN` are semicolon-separated lists. If you provide multiple directories, keep the domain order aligned.\n- `lazy_gettext()` is the safe choice for form labels, dataclass defaults, and other import-time constants.\n- If you disable Jinja integration with `configure_jinja=False`, template gettext helpers and formatting filters will not be auto-registered.\n\n## Version-Sensitive Notes For 4.0.0\n\n- The version used here `4.0.0` still matches the current published package metadata and the docs site title as of March 12, 2026.\n- The important selector API for modern Flask-Babel is `locale_selector=` and `timezone_selector=` during initialization. Older attribute-based patterns were removed in the 3.x line and should not be copied into 4.0.0 code.\n- Current maintainer metadata requires Python 3.8+, Flask 2.0+, Babel 2.12+, Jinja2 3.1+, and pytz 2022.7+.\n"
  },
  {
    "path": "content/flask/docs/caching/python/DOC.md",
    "content": "---\nname: caching\ndescription: \"Flask-Caching package guide for Python: setup, backends, decorators, invalidation, and cache-key pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,caching,cachelib,redis,memcached,python,pypi\"\n---\n\n# Flask-Caching Python Package Guide\n\n`Flask-Caching` adds backend-agnostic caching to Flask applications through `cachelib`. Use it to cache view responses, memoize expensive helpers, cache Jinja fragments, and work with Redis, Memcached, filesystem, or in-process caches through one API.\n\n## Install\n\nPin the package version you expect in application code, then add the backend driver you actually use.\n\n```bash\npip install \"Flask-Caching==2.3.1\"\n```\n\nOptional backend clients:\n\n```bash\npip install \"Flask-Caching==2.3.1\" redis\npip install \"Flask-Caching==2.3.1\" pylibmc\npip install \"Flask-Caching==2.3.1\" python-memcached\n```\n\nNotes:\n\n- `Flask-Caching` wraps backends through `cachelib`.\n- Redis and Memcached client libraries are separate dependencies.\n- Pin the backend client too in production if cache behavior must stay stable across deploys.\n\n## Initialize In Flask\n\n### Direct initialization\n\n```python\nfrom flask import Flask\nfrom flask_caching import Cache\n\napp = Flask(__name__)\napp.config.from_mapping(\n    CACHE_TYPE=\"SimpleCache\",\n    CACHE_DEFAULT_TIMEOUT=300,\n)\n\ncache = Cache(app)\n```\n\n### App factory pattern\n\nPrefer `init_app()` for larger applications.\n\n```python\nfrom flask import Flask\nfrom flask_caching import Cache\n\ncache = Cache()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        CACHE_TYPE=\"RedisCache\",\n        CACHE_DEFAULT_TIMEOUT=300,\n        CACHE_REDIS_URL=\"redis://localhost:6379/0\",\n        CACHE_KEY_PREFIX=\"myapp:\",\n    )\n\n    cache.init_app(app)\n    return app\n```\n\nYou can also pass a config mapping directly to `Cache(...)` or `cache.init_app(...)` when different cache instances need different backends.\n\n## Backend Configuration And Credentials\n\nSet `CACHE_TYPE` to the backend class name or a fully qualified import path.\n\nCommon built-in backends:\n\n- `NullCache`: disable caching without removing decorators\n- `SimpleCache`: in-process development cache\n- `FileSystemCache`: local disk-backed cache\n- `RedisCache`: Redis server or URL\n- `RedisSentinelCache`: Redis Sentinel deployment\n- `RedisClusterCache`: Redis Cluster deployment\n- `MemcachedCache`, `SASLMemcachedCache`, `SpreadSASLMemcachedCache`\n\nUse class-style backend names in 2.x code. Legacy lowercase aliases such as `simple` were removed in the 2.0 line.\n\n### `SimpleCache` for local development\n\n```python\napp.config.from_mapping(\n    CACHE_TYPE=\"SimpleCache\",\n    CACHE_DEFAULT_TIMEOUT=60,\n    CACHE_THRESHOLD=500,\n)\n```\n\nUse this only for single-process development or low-risk local workflows. It is process-local and the upstream docs describe it as not really thread safe.\n\n### Filesystem cache\n\n```python\napp.config.from_mapping(\n    CACHE_TYPE=\"FileSystemCache\",\n    CACHE_DIR=\"/tmp/flask-cache\",\n    CACHE_DEFAULT_TIMEOUT=300,\n    CACHE_THRESHOLD=1000,\n    CACHE_OPTIONS={\"mode\": 0o700},\n)\n```\n\n`CACHE_OPTIONS[\"mode\"]` controls file permissions for cache entries.\n\n### Redis cache with URL-based config\n\n```python\nimport os\n\napp.config.from_mapping(\n    CACHE_TYPE=\"RedisCache\",\n    CACHE_DEFAULT_TIMEOUT=300,\n    CACHE_KEY_PREFIX=\"myapp:\",\n    CACHE_REDIS_URL=os.environ[\"CACHE_REDIS_URL\"],\n    CACHE_OPTIONS={\n        \"socket_timeout\": 2,\n        \"socket_connect_timeout\": 2,\n        \"retry_on_timeout\": True,\n    },\n)\n```\n\n`CACHE_REDIS_URL` supports:\n\n- `redis://`\n- `rediss://` for TLS\n- `unix://`\n\nPrefer `CACHE_REDIS_URL` over spreading host, port, password, and database across multiple keys unless your deployment tooling requires that shape.\n\n### Redis Sentinel\n\n```python\napp.config.from_mapping(\n    CACHE_TYPE=\"RedisSentinelCache\",\n    CACHE_KEY_PREFIX=\"myapp:\",\n    CACHE_REDIS_SENTINELS=[\n        (\"redis-sentinel-1\", 26379),\n        (\"redis-sentinel-2\", 26379),\n    ],\n    CACHE_REDIS_SENTINEL_MASTER=\"mymaster\",\n    CACHE_REDIS_PASSWORD=\"secret\",\n    CACHE_REDIS_DB=0,\n    CACHE_OPTIONS={\"socket_timeout\": 2},\n)\n```\n\n### SASL Memcached\n\n```python\napp.config.from_mapping(\n    CACHE_TYPE=\"SASLMemcachedCache\",\n    CACHE_MEMCACHED_SERVERS=[\"memcached-1:11211\", \"memcached-2:11211\"],\n    CACHE_MEMCACHED_USERNAME=\"cache-user\",\n    CACHE_MEMCACHED_PASSWORD=\"cache-pass\",\n    CACHE_KEY_PREFIX=\"myapp:\",\n)\n```\n\nIf you need client-specific Memcached tuning, the docs note that plain `MemcachedCache` does not automatically pass `CACHE_OPTIONS` through to the client. Set those options on the underlying client after initialization if required.\n\n## Core Usage\n\n### Use the cache object directly\n\n```python\nfrom flask_caching import Cache\n\ncache = Cache()\n\ndef get_profile(user_id: int) -> dict:\n    key = f\"user-profile:{user_id}\"\n    cached = cache.get(key)\n    if cached is not None:\n        return cached\n\n    profile = load_profile_from_db(user_id)\n    cache.set(key, profile, timeout=300)\n    return profile\n```\n\nUseful methods include `get`, `set`, `add`, `delete`, `delete_many`, `has`, and `clear`.\n\n### Cache view responses with `@cache.cached`\n\n```python\nfrom flask import Flask, jsonify, request\nfrom flask_caching import Cache\n\napp = Flask(__name__)\napp.config[\"CACHE_TYPE\"] = \"SimpleCache\"\ncache = Cache(app)\n\n@app.get(\"/items\")\n@cache.cached(timeout=60, query_string=True, source_check=True)\ndef list_items():\n    return jsonify(fetch_items(request.args))\n```\n\nKey points:\n\n- Default cache keys are based on `request.path`.\n- Set `query_string=True` when query params change the response.\n- `source_check=True` makes the decorated function's source part of the cache key, which helps when code changes but the URL does not.\n- Put `@cache.cached(...)` below Flask's route decorator and directly above the function.\n\n### Build a custom cache key for POST or body-sensitive routes\n\n```python\nimport hashlib\nimport json\n\nfrom flask import request\n\ndef make_post_cache_key() -> str:\n    payload = request.get_json(silent=True) or {}\n    raw = json.dumps(payload, sort_keys=True)\n    digest = hashlib.sha256(raw.encode(\"utf-8\")).hexdigest()\n    return f\"search:{digest}\"\n\n@app.post(\"/search\")\n@cache.cached(timeout=30, make_cache_key=make_post_cache_key)\ndef search():\n    return run_search()\n```\n\n### Memoize helper functions with `@cache.memoize`\n\nUse `memoize()` when function arguments should be part of the cache key.\n\n```python\n@cache.memoize(timeout=300)\ndef permission_check(user_id: int, role_id: str) -> bool:\n    return expensive_permission_lookup(user_id, role_id)\n```\n\n### Ignore non-semantic arguments\n\nIf a function receives objects that should not affect the cache key, ignore them explicitly.\n\n```python\n@cache.memoize(timeout=300, args_to_ignore=[\"db_session\"])\ndef load_report(report_id: str, db_session) -> dict:\n    return build_report(report_id, db_session)\n```\n\n### Avoid caching bad responses\n\nUse `response_filter` when you do not want to keep failures in cache.\n\n```python\nfrom flask import Response\n\ndef should_cache(response: Response) -> bool:\n    return response.status_code < 500\n\n@app.get(\"/dashboard\")\n@cache.cached(timeout=120, response_filter=should_cache)\ndef dashboard():\n    return render_dashboard()\n```\n\n### Force refreshes on demand\n\nUse `forced_update` when a call should refresh the cached value even if it has not expired yet.\n\n```python\ndef refresh_requested() -> bool:\n    return False\n\n@cache.memoize(timeout=900, forced_update=refresh_requested)\ndef load_catalog() -> dict:\n    return fetch_catalog()\n```\n\n## Invalidation And Template Fragments\n\n### Delete memoized entries\n\n```python\n@cache.memoize(timeout=300)\ndef user_has_role(user_id: int, role: str) -> bool:\n    return query_role(user_id, role)\n\ncache.delete_memoized(user_has_role)\ncache.delete_memoized(user_has_role, 42, \"admin\")\n```\n\nRules that matter:\n\n- Passing only the function clears all memoized variants.\n- Passing arguments clears only the matching cache entry.\n- For class methods, include the class as the first argument when deleting memoized values.\n\n### Cache Jinja fragments\n\n```jinja\n{% cache 300, \"sidebar\", current_user.id %}\n  {{ render_sidebar() }}\n{% endcache %}\n```\n\nTo invalidate that fragment from Python:\n\n```python\nfrom flask_caching import make_template_fragment_key\n\nkey = make_template_fragment_key(\"sidebar\", vary_on=[current_user.id])\ncache.delete(key)\n```\n\n## Common Pitfalls\n\n### `SimpleCache` is process-local\n\nIt does not share state across Gunicorn workers, uWSGI workers, or multiple containers. Use Redis or Memcached for shared caches.\n\n### Default view keys ignore query parameters\n\n`@cache.cached` uses `request.path` by default. If `/items?page=1` and `/items?page=2` return different data, set `query_string=True` or build a custom key.\n\n### `cached()` outside a request context still needs a stable `key_prefix`\n\nIf you decorate a helper with `cached()` and keep the default key behavior, Flask-Caching still expects request-path-based keys.\n\n```python\n@cache.cached(timeout=60, key_prefix=\"expensive:all-comments\")\ndef get_all_comments():\n    return load_comments()\n```\n\n### Decorator order matters\n\nUse:\n\n```python\n@app.get(\"/\")\n@cache.cached(timeout=60)\ndef index():\n    ...\n```\n\nDo not reverse the decorators.\n\n### `cache_none=True` is usually the wrong tradeoff\n\nThe API docs warn that enabling it can return incorrect `None` results under concurrency. Prefer explicit sentinel values or a different cache design.\n\n### Mutable objects in memoized arguments are risky\n\nMemoization keys depend on argument values and representations. Mutable objects or unstable `repr()` output make cache hits and invalidation unpredictable.\n\n### `cache.clear()` can be broader than expected\n\nThe docs warn that some backends do not support a clean scoped clear, and Redis-backed clears without a prefix can flush the whole configured database. Always set `CACHE_KEY_PREFIX` for shared backends.\n\n## Version-Sensitive Notes For `2.3.1`\n\n- The version used here `2.3.1` matches the current PyPI project page and GitHub release history.\n- PyPI metadata for `2.3.1` lists `Python >=3.8`.\n- The Read the Docs usage pages describe the current 2.x API surface, but the published changelog page currently stops at `2.1.0`. For 2.2.x and 2.3.x provenance, verify PyPI and GitHub releases instead of relying on the changelog page alone.\n- `2.0.0` removed support for the old lowercase backend aliases such as `simple`, and aligned `FileSystemCache` behavior with `cachelib.FileSystemCache`. Old on-disk cache files from pre-2.0 deployments should not be assumed compatible.\n- `2.1.0` added official Flask 3 support in the published changelog, so `2.3.1` is part of the maintained Flask 3-compatible 2.x line.\n- If you are migrating very old code or `Flask-Cache` snippets, re-check backend names, config keys, and invalidation behavior instead of copying legacy examples directly.\n\n## Recommended Agent Workflow\n\n1. Configure the cache backend explicitly in Flask config, including a safe `CACHE_KEY_PREFIX` for shared backends.\n2. Use `memoize()` for argument-sensitive helpers and `cached()` for route responses.\n3. Decide cache keys deliberately for query params, POST bodies, tenant IDs, and auth-sensitive output.\n4. Add invalidation where source data changes by using `delete`, `delete_many`, `delete_memoized`, or fragment-key deletion.\n5. Avoid `SimpleCache` in multi-worker production deployments.\n\n## Official Sources\n\n- Documentation root: https://flask-caching.readthedocs.io/en/latest/\n- Changelog: https://flask-caching.readthedocs.io/en/latest/changelog.html\n- PyPI project: https://pypi.org/project/Flask-Caching/\n- Source repository: https://github.com/pallets-eco/flask-caching\n- Releases: https://github.com/pallets-eco/flask-caching/releases\n"
  },
  {
    "path": "content/flask/docs/celery-helper/python/DOC.md",
    "content": "---\nname: celery-helper\ndescription: \"Flask-Celery-Helper 1.1.0 guide for maintaining legacy Flask app-factory integrations with Celery\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,celery,background-jobs,legacy,redis,worker\"\n---\n\n# Flask-Celery-Helper for Flask Apps\n\n## Compatibility And Scope\n\nThe released `1.1.0` PyPI page lists these tested versions:\n\n- Python `2.6`, `2.7`, `3.3`, `3.4`\n- Flask `0.10.1`\n- Celery `3.1.11`\n- Redis `2.9.1`\n\nTreat that as the real support envelope for this doc. Do not assume compatibility with Flask 2.x or 3.x, Celery 5.x, or modern Python.\n\nIf you are starting a new Flask project, prefer plain Celery setup from current Celery docs instead of adding this extension.\n\n## Install\n\nPin the package and keep the rest of the stack consistent with the old support window:\n\n```bash\npython -m pip install \"Flask-Celery-Helper==1.1.0\"\n```\n\nFor a legacy environment that follows the package's documented test matrix, pin Celery and Flask explicitly as well:\n\n```bash\npython -m pip install \\\n  \"Flask-Celery-Helper==1.1.0\" \\\n  \"Flask==0.10.1\" \\\n  \"celery==3.1.11\"\n```\n\nIf you use the Redis-backed `single_instance` flow from the release examples, install the matching Redis helper too:\n\n```bash\npython -m pip install \"Flask-Redis-Helper\"\n```\n\n## Minimal Setup\n\nThe basic release example configures the broker on the Flask app, constructs the extension, and exposes the Celery app as `example.celery` for the worker process:\n\n```python\nfrom flask import Flask\nfrom flask.ext.celery import Celery\n\napp = Flask(\"example\")\napp.config[\"CELERY_BROKER_URL\"] = \"redis://localhost\"\napp.config[\"CELERY_RESULT_BACKEND\"] = \"redis://localhost\"\n\ncelery = Celery(app)\n\n@celery.task()\ndef add_together(a, b):\n    return a + b\n\nif __name__ == \"__main__\":\n    result = add_together.delay(23, 42)\n    print(result.get())\n```\n\nRun the worker against the Celery object, not just the Flask app module:\n\n```bash\ncelery -A example.celery worker\npython example.py\n```\n\n## App Factory Setup\n\nThe main reason to keep this package is `init_app()` support for older factory layouts.\n\n`extensions.py`\n\n```python\nfrom flask.ext.celery import Celery\n\ncelery = Celery()\n```\n\n`application.py`\n\n```python\nfrom flask import Flask\n\nfrom extensions import celery\n\ndef create_app():\n    app = Flask(__name__)\n    app.config[\"CELERY_IMPORTS\"] = (\"tasks.add_together\",)\n    app.config[\"CELERY_BROKER_URL\"] = \"redis://localhost\"\n    app.config[\"CELERY_RESULT_BACKEND\"] = \"redis://localhost\"\n    celery.init_app(app)\n    return app\n```\n\n`tasks.py`\n\n```python\nfrom extensions import celery\n\n@celery.task()\ndef add_together(a, b):\n    return a + b\n```\n\n`manage.py`\n\n```python\nfrom application import create_app\n\napp = create_app()\n```\n\nWorker startup still needs a module path that resolves to the initialized Celery object in your project. The PyPI example shows the Celery app living on `example.celery`; adapt that pattern to your own module layout and verify it before automating worker commands.\n\n## Configuration And Secrets\n\nThis extension reads Celery settings from Flask config. The release examples use:\n\n- `CELERY_BROKER_URL`\n- `CELERY_RESULT_BACKEND`\n- `CELERY_IMPORTS`\n\nExample:\n\n```python\napp.config.update(\n    CELERY_BROKER_URL=\"redis://localhost/0\",\n    CELERY_RESULT_BACKEND=\"redis://localhost/0\",\n    CELERY_IMPORTS=(\"tasks.email\", \"tasks.reports\"),\n)\n```\n\nAuth is delegated to the broker and result-backend URLs, not to `Flask-Celery-Helper` itself. Put credentials in connection URLs and load them from environment or config files outside source control:\n\n```python\nimport os\n\napp.config[\"CELERY_BROKER_URL\"] = os.environ[\"CELERY_BROKER_URL\"]\napp.config[\"CELERY_RESULT_BACKEND\"] = os.environ.get(\"CELERY_RESULT_BACKEND\", \"\")\n```\n\nTypical legacy connection strings:\n\n- Redis: `redis://:password@host:6379/0`\n- RabbitMQ / AMQP: `amqp://user:password@host:5672//`\n\nVersion note:\n\n- `1.1.0` changed the package so `CELERY_RESULT_BACKEND` is no longer mandatory.\n- In practice, if your code calls `AsyncResult.get()` or expects stored results, you still need a working result backend.\n\n## Core Usage\n\n### Queue a task\n\n```python\ntask = add_together.delay(23, 42)\n```\n\n### Wait for a result\n\n```python\nvalue = task.get(timeout=10)\n```\n\n### Register task modules in factory apps\n\nIf your project creates Celery before importing task modules, set `CELERY_IMPORTS` so the worker sees those tasks when it starts:\n\n```python\napp.config[\"CELERY_IMPORTS\"] = (\n    \"tasks.add_together\",\n    \"tasks.cleanup\",\n)\n```\n\nWithout that, factory-style apps often start a worker that does not know about your tasks yet.\n\n## `single_instance` Locking\n\nThe package ships a `single_instance` decorator for deduplicating overlapping task runs.\n\nPyPI's release example uses Redis plus `Flask-Redis-Helper`:\n\n```python\nimport time\nfrom flask import Flask\nfrom flask.ext.celery import Celery, single_instance\nfrom flask.ext.redis import Redis\n\napp = Flask(\"example\")\napp.config[\"REDIS_URL\"] = \"redis://localhost\"\napp.config[\"CELERY_BROKER_URL\"] = \"redis://localhost\"\napp.config[\"CELERY_RESULT_BACKEND\"] = \"redis://localhost\"\n\ncelery = Celery(app)\nRedis(app)\n\n@celery.task(bind=True)\n@single_instance\ndef sleep_one_second(a, b):\n    time.sleep(1)\n    return a + b\n```\n\nThe `1.1.0` changelog says `single_instance` gained SQLite, MySQL, and PostgreSQL support in addition to Redis. The release page does not include a full non-Redis example, so validate locking behavior in your exact backend before relying on it for correctness.\n\n## Common Pitfalls\n\n- This package is from 2014. Treat it as legacy maintenance tooling, not a current Flask recommendation.\n- The released examples use the old `flask.ext.celery` namespace. That is an old Flask extension import style and is a strong signal that the package targets old Flask versions.\n- Do not mix this guide with modern Celery 5.x or modern Flask 3.x tutorials. The API assumptions are different enough that copy-paste code is likely to fail.\n- In factory apps, initialize the Flask app before starting the worker and make sure the worker imports the actual Celery object.\n- `CELERY_RESULT_BACKEND` may be optional for fire-and-forget tasks, but result retrieval with `.get()` still needs a backend.\n- `CELERY_IMPORTS` matters for worker startup in older factory layouts. Missing task imports usually show up as unregistered-task failures at runtime.\n- `single_instance` is not a substitute for broader distributed-systems guarantees. Use it as a task dedupe helper, not as your only concurrency control.\n\n## Version-Sensitive Notes\n\n- `1.1.0` is the last published PyPI release shown on the project page.\n- The `1.1.0` changelog includes:\n  - Windows support\n  - `CELERY_RESULT_BACKEND` no longer mandatory\n  - `single_instance` support for SQLite, MySQL, and PostgreSQL in addition to Redis\n  - a breaking move of `CELERY_LOCK`\n- The docs URL is the repository root on GitHub, which is not version-locked to `1.1.0`. For package-matched behavior, anchor your code decisions to the `1.1.0` PyPI release page first.\n- Current Celery documentation still says Flask integration packages are \"not needed\". That is the modern direction; use this package only when you have an inherited codebase that already depends on it.\n\n## Source URLs\n\n- PyPI project page: `https://pypi.org/project/Flask-Celery-Helper/`\n- Official repository: `https://github.com/Robpol86/Flask-Celery-Helper`\n- Current Celery docs: `https://docs.celeryq.dev/en/latest/getting-started/introduction.html`\n"
  },
  {
    "path": "content/flask/docs/cors/python/DOC.md",
    "content": "---\nname: cors\ndescription: \"Flask-CORS guide for Python Flask apps, selective CORS policies, and credentialed browser requests\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,flask,cors,http,web,security\"\n---\n\n# flask-cors Python Package Guide\n\n## What It Is\n\n`flask-cors` adds Cross-Origin Resource Sharing headers to Flask responses so browser apps on one origin can call a Flask app on another origin.\n\n- PyPI package: `flask-cors`\n- Import path: `flask_cors`\n- Main APIs: `CORS` for app or blueprint setup, `cross_origin` for route-level overrides\n- Version covered here: `6.0.2`\n- PyPI requirement for this release: Python `>=3.9`\n\nUse it only when a browser must make cross-origin requests. It does not replace authentication, authorization, or CSRF protection.\n\n## Install\n\n```bash\npip install flask-cors==6.0.2\n```\n\nIf the project already pins Flask and related middleware, keep the package version aligned with the lockfile instead of upgrading ad hoc.\n\n## Minimal Setup\n\nEnable CORS for the whole Flask app:\n\n```python\nfrom flask import Flask, jsonify\nfrom flask_cors import CORS\n\napp = Flask(__name__)\nCORS(app)\n\n@app.get(\"/ping\")\ndef ping():\n    return jsonify(ok=True)\n```\n\nThis is convenient for local development, but it is usually too broad for production APIs because it allows every origin on every route by default.\n\n## Restrict CORS To API Routes\n\nPrefer a scoped policy for API paths:\n\n```python\nfrom flask import Flask\nfrom flask_cors import CORS\n\napp = Flask(__name__)\n\nCORS(\n    app,\n    resources={\n        r\"/api/*\": {\n            \"origins\": [\n                \"https://app.example.com\",\n                \"https://admin.example.com\",\n            ],\n            \"methods\": [\"GET\", \"POST\", \"PATCH\", \"DELETE\"],\n            \"allow_headers\": [\"Content-Type\", \"Authorization\"],\n        }\n    },\n)\n```\n\nThe official configuration docs say resource regexes are sorted longest-first before matching, so the most specific pattern should win.\n\n## Route-Level Control With `cross_origin`\n\nUse the decorator when only a few routes need cross-origin access:\n\n```python\nfrom flask import Flask, jsonify\nfrom flask_cors import cross_origin\n\napp = Flask(__name__)\n\n@app.get(\"/public\")\n@cross_origin(origins=\"*\")\ndef public():\n    return jsonify(public=True)\n\n@app.post(\"/api/token\")\n@cross_origin(\n    origins=[\"https://app.example.com\"],\n    methods=[\"POST\"],\n    allow_headers=[\"Content-Type\", \"Authorization\"],\n)\ndef issue_token():\n    return jsonify(token=\"example\")\n```\n\nDecorator kwargs override the broader app-level defaults for that route.\n\n## App Factory And Config Keys\n\n`flask-cors` also reads Flask config keys prefixed with `CORS_`, which is useful in app-factory setups:\n\n```python\nfrom flask import Flask\nfrom flask_cors import CORS\n\ndef create_app():\n    app = Flask(__name__)\n    app.config.update(\n        CORS_ORIGINS=[\"https://app.example.com\"],\n        CORS_RESOURCES={r\"/api/*\": {\"origins\": [\"https://app.example.com\"]}},\n        CORS_ALLOW_HEADERS=[\"Content-Type\", \"Authorization\"],\n        CORS_METHODS=[\"GET\", \"POST\", \"PATCH\", \"DELETE\"],\n        CORS_SUPPORTS_CREDENTIALS=True,\n        CORS_MAX_AGE=600,\n        CORS_VARY_HEADER=True,\n    )\n    CORS(app)\n    return app\n```\n\nThe documented precedence order is:\n\n1. Resource-level settings\n2. Keyword arguments passed to `CORS(...)` or `@cross_origin(...)`\n3. App config keys such as `CORS_ORIGINS`\n4. Package defaults\n\nCommon options that matter in real apps:\n\n- `origins`: allowed origin string, list, or regex\n- `resources`: route-regex to options mapping\n- `methods`: methods advertised on preflight responses\n- `allow_headers`: request headers accepted during preflight\n- `expose_headers`: response headers readable from browser code\n- `supports_credentials`: allow cookies or auth-bearing cross-origin requests\n- `max_age`: cache successful preflight responses\n- `send_wildcard`: send `*` instead of echoing the caller origin when `origins=\"*\"`\n- `vary_header`: keep `Vary: Origin` when origin handling is dynamic\n- `allow_private_network`: control the `Access-Control-Allow-Private-Network` response header\n\n## Blueprints\n\nYou can attach CORS to a blueprint instead of the whole app:\n\n```python\nfrom flask import Blueprint\nfrom flask_cors import CORS\n\napi = Blueprint(\"api\", __name__, url_prefix=\"/api\")\nCORS(api, origins=[\"https://app.example.com\"])\n```\n\nRegister the blueprint on the Flask app as usual.\n\n## Credentials, Cookies, And Auth\n\nIf the frontend sends cookies or other credentials, use explicit origins and enable credentials:\n\n```python\nfrom flask import Flask\nfrom flask_cors import CORS\n\napp = Flask(__name__)\n\nCORS(\n    app,\n    resources={r\"/api/*\": {\"origins\": [\"https://app.example.com\"]}},\n    supports_credentials=True,\n)\n```\n\nImportant constraints:\n\n- Do not combine `supports_credentials=True` with `origins=\"*\"`. The official API docs explicitly disallow it.\n- The browser client must also opt in to credentials mode.\n- CORS only controls browser access to responses. It does not implement login, token validation, or CSRF defense.\n- If cookie-based auth crosses origins, verify Flask session cookie settings and CSRF protections together with the CORS policy.\n\n## Preflight-Friendly JSON APIs\n\nBrowsers preflight requests that use JSON, custom headers, or non-simple methods. A common setup for API routes is:\n\n```python\nfrom flask import Flask\nfrom flask_cors import CORS\n\napp = Flask(__name__)\n\nCORS(\n    app,\n    resources={r\"/api/*\": {\"origins\": [\"https://app.example.com\"]}},\n    allow_headers=[\"Content-Type\", \"Authorization\"],\n    methods=[\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n    max_age=600,\n)\n```\n\nIf a browser reports a CORS error on a JSON request, check the exact path, request method, and `allow_headers` first. Flask route failures often surface as generic browser CORS errors.\n\n## Common Pitfalls\n\n- Install name and import name differ: install `flask-cors`, import `flask_cors`.\n- Origins must match scheme, host, and port exactly.\n- `CORS(app)` is easy to overuse. Prefer scoped `resources` or route decorators in production.\n- Dynamic origin behavior should usually keep `vary_header=True` so shared caches do not reuse the wrong response.\n- If a frontend sends `Authorization` or JSON, missing `allow_headers` is a common reason for failed preflights.\n- If you use overlapping regexes in `resources`, keep the specific ones longer and test them explicitly.\n- A backend `404`, `405`, or `500` can look like a CORS problem in the browser. Reproduce with `curl` before changing the policy.\n\n## Version-Sensitive Notes For 6.0.2\n\n- PyPI currently lists `6.0.2` as the latest release and requires Python `>=3.9`.\n- The current official docs are served from `https://flask-cors.corydolphin.com/en/latest/`. The older Read the Docs URL still resolves, but the custom domain is the canonical docs root advertised on PyPI.\n- The maintainer release notes for `6.0.1` mention a fix for incorrect regex-length sorting. If you rely on multiple overlapping `resources` patterns, prefer `6.0.1+` behavior and avoid older examples that assume different match ordering.\n- The maintainer release notes for `6.0.0` mention security fixes. Treat older third-party snippets carefully if they assume pre-`6.x` defaults.\n- The public docs are not obviously version-pinned per package release. When a behavior matters for production security, verify it against the exact installed version instead of assuming the `latest` docs describe `6.0.2` perfectly.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/flask-cors/\n- Version-specific PyPI page: https://pypi.org/project/flask-cors/6.0.2/\n- Canonical docs root: https://flask-cors.corydolphin.com/en/latest/\n- API docs: https://flask-cors.corydolphin.com/en/latest/api.html\n- Configuration docs: https://flask-cors.corydolphin.com/en/latest/configuration.html\n- Maintainer release notes: https://github.com/corydolphin/flask-cors/releases\n"
  },
  {
    "path": "content/flask/docs/dance/python/DOC.md",
    "content": "---\nname: dance\ndescription: \"Flask-Dance 7.1.0 guide for OAuth and social login flows in Flask applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,flask-dance,oauth,oauth2,oauth1,authentication,social-login\"\n---\n\n# Flask-Dance for Flask Apps\n\n## Install\n\nPin the package version your app expects:\n\n```bash\npython -m pip install \"Flask-Dance==7.1.0\"\n```\n\nIf you want the built-in SQLAlchemy token storage helper, install the extra:\n\n```bash\npython -m pip install \"Flask-Dance[sqla]==7.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Flask-Dance==7.1.0\"\npoetry add \"Flask-Dance==7.1.0\"\n```\n\n## Minimal Setup With A Built-In Provider\n\nUse an app factory, load secrets before initializing the extension, then register the provider blueprint.\n\n```python\nimport os\n\nfrom flask import Flask, redirect, url_for\nfrom flask_dance.contrib.github import github, make_github_blueprint\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = os.environ[\"FLASK_SECRET_KEY\"]\n\n    github_bp = make_github_blueprint(\n        client_id=os.environ[\"GITHUB_OAUTH_CLIENT_ID\"],\n        client_secret=os.environ[\"GITHUB_OAUTH_CLIENT_SECRET\"],\n        redirect_to=\"github_done\",\n    )\n    app.register_blueprint(github_bp, url_prefix=\"/login\")\n\n    @app.get(\"/\")\n    def index():\n        return '<a href=\"/login/github\">Sign in with GitHub</a>'\n\n    @app.get(\"/github\")\n    def github_done():\n        if not github.authorized:\n            return redirect(url_for(\"github.login\"))\n\n        response = github.get(\"/user\")\n        response.raise_for_status()\n        profile = response.json()\n        return {\"login\": profile[\"login\"], \"id\": profile[\"id\"]}\n\n    return app\n```\n\nImportant setup rules:\n\n- Set Flask `SECRET_KEY`; Flask-Dance uses the Flask session unless you provide another token storage backend.\n- Register the blueprint on the app before the first request.\n- The login route comes from the blueprint name and `url_prefix`. With the GitHub provider above, the login URL is `/login/github`.\n- The callback route must be reachable at the exact URL you registered with the provider.\n\n## Provider Configuration\n\nBuilt-in `make_*_blueprint()` helpers usually accept:\n\n- `client_id`\n- `client_secret`\n- `scope`\n- `redirect_to`\n- `login_url`\n- `authorized_url`\n- `storage`\n\nSeveral built-in providers also support reading credentials from Flask config when you omit them explicitly. Common keys follow the provider naming pattern, for example:\n\n- `GITHUB_OAUTH_CLIENT_ID`\n- `GITHUB_OAUTH_CLIENT_SECRET`\n- `GOOGLE_OAUTH_CLIENT_ID`\n- `GOOGLE_OAUTH_CLIENT_SECRET`\n\nThat makes config-driven factories straightforward:\n\n```python\nfrom flask import Flask\nfrom flask_dance.contrib.google import make_google_blueprint\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        SECRET_KEY=\"replace-me\",\n        GOOGLE_OAUTH_CLIENT_ID=\"...\",\n        GOOGLE_OAUTH_CLIENT_SECRET=\"...\",\n    )\n\n    google_bp = make_google_blueprint(\n        scope=[\n            \"openid\",\n            \"https://www.googleapis.com/auth/userinfo.email\",\n        ],\n        redirect_to=\"auth.google_done\",\n    )\n    app.register_blueprint(google_bp, url_prefix=\"/login\")\n    return app\n```\n\nProvider modules live under `flask_dance.contrib`. Prefer the built-in helper for a supported provider before writing a custom OAuth flow by hand.\n\n## Custom Provider Blueprint\n\nFor a provider without a built-in helper, use `OAuth2ConsumerBlueprint` directly:\n\n```python\nfrom flask import Flask\nfrom flask_dance.consumer import OAuth2ConsumerBlueprint\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = \"replace-me\"\n\n    example_bp = OAuth2ConsumerBlueprint(\n        \"example\",\n        __name__,\n        client_id=\"client-id\",\n        client_secret=\"client-secret\",\n        base_url=\"https://api.example.com/\",\n        authorization_url=\"https://example.com/oauth/authorize\",\n        token_url=\"https://example.com/oauth/token\",\n    )\n    app.register_blueprint(example_bp, url_prefix=\"/login\")\n    return app\n```\n\nUse this path when the provider is standards-compliant OAuth but Flask-Dance does not already ship a `contrib` module for it.\n\n## Token Storage And Persistence\n\nThe default storage keeps tokens in the signed Flask session cookie. That is acceptable for simple demos, but it is usually the wrong choice for production apps because:\n\n- tokens disappear when the session is cleared\n- one browser session does not map cleanly to multiple linked OAuth accounts\n- storing access tokens in client cookies makes rotation and revocation harder\n\nThe docs provide multiple storage backends:\n\n- `SessionStorage`: Flask session-backed storage\n- `SQLAlchemyStorage`: database-backed storage\n- `MemoryStorage`: in-memory storage, useful in tests\n- `NullStorage`: disables persistence\n\nFor production apps, prefer `SQLAlchemyStorage`:\n\n```python\nfrom flask import Flask\nfrom flask_dance.consumer.storage.sqla import OAuthConsumerMixin, SQLAlchemyStorage\nfrom flask_dance.contrib.github import make_github_blueprint\nfrom flask_login import current_user\nfrom flask_sqlalchemy import SQLAlchemy\n\ndb = SQLAlchemy()\n\nclass OAuth(OAuthConsumerMixin, db.Model):\n    __tablename__ = \"oauth\"\n\n    user_id = db.Column(db.Integer, db.ForeignKey(\"user.id\"))\n    user = db.relationship(\"User\")\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        SECRET_KEY=\"replace-me\",\n        SQLALCHEMY_DATABASE_URI=\"sqlite:///app.db\",\n    )\n    db.init_app(app)\n\n    github_bp = make_github_blueprint(\n        storage=SQLAlchemyStorage(OAuth, db.session, user=current_user),\n    )\n    app.register_blueprint(github_bp, url_prefix=\"/login\")\n    return app\n```\n\nIf you use a database-backed storage, create the tables before starting auth flows or the callback exchange will fail when Flask-Dance tries to save the token.\n\n## Multi-User Account Linking\n\nFlask-Dance has specific guidance for apps where users log into your app first and then link external providers. Combine it with Flask-Login and a persistent token store.\n\nUseful pattern:\n\n- require a local logged-in user before starting the provider flow\n- store tokens per application user, not just per browser session\n- use `flask_dance.consumer.storage.sqla` with `current_user`\n- use the `@oauth_authorized` signal to attach provider identity metadata to the local user record\n\nIf your app supports connecting multiple GitHub or Google accounts, model that explicitly in your own database instead of assuming one token per provider name.\n\n## Signals And Custom Auth Handling\n\nFlask-Dance emits signals around the OAuth flow. The important ones are:\n\n- `oauth_before_login`\n- `oauth_authorized`\n- `oauth_error`\n\nTypical use cases:\n\n- enrich or normalize provider profile data after authorization\n- create or link a local user\n- reject or redirect when provider auth fails\n- audit provider authorization events\n\nExample:\n\n```python\nfrom flask import redirect, url_for\nfrom flask_dance.consumer import oauth_authorized, oauth_error\n\n@oauth_authorized.connect\ndef github_logged_in(blueprint, token):\n    if blueprint.name != \"github\":\n        return None\n\n    response = blueprint.session.get(\"/user\")\n    response.raise_for_status()\n    profile = response.json()\n    link_user_account(profile, token)\n    return False\n\n@oauth_error.connect\ndef github_error(blueprint, message, response, error, error_description, error_uri):\n    if blueprint.name == \"github\":\n        return redirect(url_for(\"login_failed\"))\n    return None\n```\n\nIn `7.1.0`, signal handlers can return a Flask response from `oauth_error`, and Flask-Dance will respect it. If you previously relied on side effects only, review those handlers before upgrading.\n\nReturning `False` from `oauth_authorized` tells Flask-Dance not to save the token automatically. Use that when you want your signal handler to decide whether and how the token should be stored.\n\n## Logout And Revocation\n\nLogging out of your Flask app is not the same as revoking the provider token. Clear both pieces when appropriate:\n\n```python\nfrom flask import current_app, redirect, url_for\nfrom flask_dance.contrib.github import github\nfrom flask_login import logout_user\n\n@app.post(\"/logout\")\ndef logout():\n    if github.authorized:\n        github.post(\n            f\"/applications/{current_app.config['GITHUB_OAUTH_CLIENT_ID']}/token\",\n            auth=(\n                current_app.config[\"GITHUB_OAUTH_CLIENT_ID\"],\n                current_app.config[\"GITHUB_OAUTH_CLIENT_SECRET\"],\n            ),\n            json={\"access_token\": github.token[\"access_token\"]},\n        )\n\n    del github.token\n    logout_user()\n    return redirect(url_for(\"index\"))\n```\n\nPractical rule:\n\n- revoke provider tokens when the provider supports it and your app owns that lifecycle\n- always clear local session state\n- if you use database-backed storage, remove the stored token row as part of logout or unlink\n\n## Reverse Proxy And Callback URLs\n\nOAuth callbacks break easily when Flask sees the wrong scheme or host behind a reverse proxy. If your app runs behind Nginx, a load balancer, or a platform proxy, configure Flask/Werkzeug to trust the forwarded headers you actually use.\n\nCommon production fix:\n\n```python\nfrom werkzeug.middleware.proxy_fix import ProxyFix\n\napp.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)\n```\n\nWithout that, Flask-Dance may generate `http://...` callback URLs while your provider is configured for `https://...`, which causes redirect URI mismatch errors.\n\n## Testing OAuth Flows\n\nThe testing docs cover several useful patterns:\n\n- `MemoryStorage` for simple in-memory token tests\n- `NullStorage` when you want auth behavior without persistence\n- `requests_mock` to stub provider HTTP calls\n- a provided pytest fixture for isolating OAuth state\n\nExample:\n\n```python\nimport requests_mock\nfrom flask import Flask\nfrom flask_dance.contrib.github import github, make_github_blueprint\nfrom flask_dance.consumer.storage import MemoryStorage\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = \"testing\"\n\n    github_bp = make_github_blueprint(\n        client_id=\"test-client-id\",\n        client_secret=\"test-client-secret\",\n        storage=MemoryStorage({\"access_token\": \"fake-token\"}),\n    )\n    app.register_blueprint(github_bp, url_prefix=\"/login\")\n\n    @app.get(\"/me\")\n    def me():\n        response = github.get(\"/user\")\n        response.raise_for_status()\n        return response.json()\n\n    return app\n\ndef test_me(client):\n    with requests_mock.Mocker() as mocker:\n        mocker.get(\n            \"https://api.github.com/user\",\n            json={\"login\": \"octocat\", \"id\": 1},\n        )\n\n        response = client.get(\"/me\")\n        assert response.status_code == 200\n        assert response.json[\"login\"] == \"octocat\"\n```\n\nWhen testing, avoid making the real OAuth redirect round-trip unless you are doing an end-to-end browser test. Most application logic can be covered by seeding token storage and mocking the provider API response.\n\n## Common Pitfalls\n\n- Do not hard-code provider secrets in source files. Load them from environment or a secret manager.\n- Package name and import path differ: `Flask-Dance` vs `flask_dance`.\n- Register the callback URL with the provider exactly as Flask-Dance generates it, including scheme, host, prefix, and trailing path pieces.\n- Session-backed token storage is easy to start with but weak for multi-user apps and account-linking flows.\n- If you connect `oauth_authorized`, remember that returning `False` disables automatic token persistence.\n- If you use Flask-Login, require a current user before account-linking routes or you may attach the provider token to the wrong local session.\n- If the provider requires extra scopes, request them up front. Missing scopes often only surface later when the first API request fails.\n- Old blog posts may still show providers or flows that changed in `7.x`, especially around Twitter support and PKCE-related behavior.\n\n## Version-Sensitive Notes For 7.1.0\n\n- `7.1.0` changes signal handling so a response returned from an `oauth_error` signal handler is used directly.\n- `7.1.0` also fixes Azure auto-refresh token behavior for short-lived access tokens.\n- In `7.0.0`, the built-in Twitter provider was removed because the API is no longer broadly accessible. Do not copy older `make_twitter_blueprint()` examples from pre-7.0 articles.\n- In `7.0.0`, PKCE support was added. If you are integrating with a provider that expects PKCE, prefer current `7.x` docs and examples over older snippets.\n\n## Official Sources Used\n\n- Docs root: `https://flask-dance.readthedocs.io/en/latest/`\n- Providers: `https://flask-dance.readthedocs.io/en/latest/providers.html`\n- Storages: `https://flask-dance.readthedocs.io/en/latest/storages.html`\n- Multi-user: `https://flask-dance.readthedocs.io/en/latest/multi-user.html`\n- Signals: `https://flask-dance.readthedocs.io/en/latest/signals.html`\n- Logout: `https://flask-dance.readthedocs.io/en/latest/logout.html`\n- Testing: `https://flask-dance.readthedocs.io/en/latest/testing.html`\n- PyPI: `https://pypi.org/project/flask-dance/`\n- Changelog: `https://github.com/singingwolfboy/flask-dance/blob/main/CHANGELOG.rst`\n"
  },
  {
    "path": "content/flask/docs/jwt-extended/python/DOC.md",
    "content": "---\nname: jwt-extended\ndescription: \"Flask-JWT-Extended 4.7.1 guide for JWT authentication in Flask APIs and browser apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.7.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,jwt,authentication,authorization,cookies,api\"\n---\n\n# Flask-JWT-Extended Python Guide\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"flask-jwt-extended==4.7.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"flask-jwt-extended==4.7.1\"\npoetry add \"flask-jwt-extended==4.7.1\"\n```\n\nYou also need Flask itself:\n\n```bash\npython -m pip install \"Flask>=3,<4\"\n```\n\n## Minimal Header-Based API Auth\n\nFor API clients, start with bearer tokens in the `Authorization` header. Set `JWT_SECRET_KEY`, initialize `JWTManager`, issue an access token only after real credential verification, and protect routes with `@jwt_required()`.\n\n```python\nfrom datetime import timedelta\nimport os\n\nfrom flask import Flask, jsonify, request\nfrom flask_jwt_extended import (\n    JWTManager,\n    create_access_token,\n    get_jwt_identity,\n    jwt_required,\n)\n\napp = Flask(__name__)\napp.config[\"JWT_SECRET_KEY\"] = os.environ[\"JWT_SECRET_KEY\"]\napp.config[\"JWT_ACCESS_TOKEN_EXPIRES\"] = timedelta(hours=1)\n\njwt = JWTManager(app)\n\n@app.post(\"/login\")\ndef login():\n    data = request.get_json() or {}\n    username = data.get(\"username\")\n    password = data.get(\"password\")\n\n    if not username or password != \"correct-password\":\n        return jsonify(msg=\"Bad username or password\"), 401\n\n    access_token = create_access_token(identity=username)\n    return jsonify(access_token=access_token)\n\n@app.get(\"/me\")\n@jwt_required()\ndef me():\n    return jsonify(user=get_jwt_identity())\n```\n\nClients call the protected route with:\n\n```http\nAuthorization: Bearer <access_token>\n```\n\n## App Factory Setup\n\nFor real projects, keep the extension unbound until app creation:\n\n```python\nimport os\n\nfrom flask import Flask\nfrom flask_jwt_extended import JWTManager\n\njwt = JWTManager()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"JWT_SECRET_KEY\"] = os.environ[\"JWT_SECRET_KEY\"]\n    jwt.init_app(app)\n    return app\n```\n\nThis avoids binding extension state at import time and makes testing easier.\n\n## Refresh Tokens\n\nUse refresh tokens for long-lived sessions. In 4.x, the refresh endpoint should use `@jwt_required(refresh=True)` rather than old 3.x decorators.\n\n```python\nfrom flask_jwt_extended import create_refresh_token\n\n@app.post(\"/login\")\ndef login():\n    data = request.get_json() or {}\n    username = data.get(\"username\")\n\n    access_token = create_access_token(identity=username)\n    refresh_token = create_refresh_token(identity=username)\n    return jsonify(\n        access_token=access_token,\n        refresh_token=refresh_token,\n    )\n\n@app.post(\"/refresh\")\n@jwt_required(refresh=True)\ndef refresh():\n    identity = get_jwt_identity()\n    return jsonify(access_token=create_access_token(identity=identity))\n```\n\nKeep access tokens short-lived. Refresh tokens should have tighter storage rules and a clear revocation story.\n\n## Cookie-Based Auth For Browser Apps\n\nIf your frontend is a browser app instead of an API client, store JWTs in cookies and keep CSRF protection enabled.\n\n```python\nfrom flask_jwt_extended import set_access_cookies, unset_jwt_cookies\n\napp.config.update(\n    JWT_TOKEN_LOCATION=[\"cookies\"],\n    JWT_COOKIE_SECURE=True,\n    JWT_COOKIE_CSRF_PROTECT=True,\n    JWT_COOKIE_SAMESITE=\"Lax\",\n)\n\n@app.post(\"/token/auth\")\ndef cookie_login():\n    access_token = create_access_token(identity=\"user-123\")\n    response = jsonify(msg=\"login successful\")\n    set_access_cookies(response, access_token)\n    return response\n\n@app.post(\"/logout\")\ndef logout():\n    response = jsonify(msg=\"logout successful\")\n    unset_jwt_cookies(response)\n    return response\n```\n\nUse cookie mode when the browser should automatically send the token. When you do that:\n\n- serve over HTTPS in production\n- keep CSRF protection on\n- make `SameSite`, domain, and secure-cookie settings explicit for your deployment\n\nThe docs include both explicit refresh-token routes and implicit cookie-refresh patterns. Prefer explicit refresh endpoints unless you have a strong reason to hide refresh mechanics in response hooks.\n\n## Loading The Current User\n\nIf protected routes need a real user object instead of just the JWT identity value, register a user lookup callback and then access `current_user`.\n\n```python\nfrom flask_jwt_extended import current_user\n\n@jwt.user_lookup_loader\ndef load_user(jwt_header, jwt_payload):\n    user_id = jwt_payload[\"sub\"]\n    return User.query.get(user_id)\n\n@app.get(\"/profile\")\n@jwt_required()\ndef profile():\n    return jsonify(\n        id=current_user.id,\n        email=current_user.email,\n    )\n```\n\n`User` is your own model or repository layer. This keeps the token small while still letting route handlers work with application-level user records.\n\n## Revocation, Logout, And Blocklists\n\nFor logout, compromised credentials, or administrative invalidation, register a blocklist callback and store revoked token `jti` values in a shared persistent store such as Redis or a database.\n\n```python\nfrom flask_jwt_extended import get_jwt\n\n@jwt.token_in_blocklist_loader\ndef is_token_revoked(jwt_header, jwt_payload):\n    return redis_client.sismember(\"jwt_blocklist\", jwt_payload[\"jti\"])\n\n@app.delete(\"/logout\")\n@jwt_required()\ndef revoke_current_token():\n    jti = get_jwt()[\"jti\"]\n    redis_client.sadd(\"jwt_blocklist\", jti)\n    return jsonify(msg=\"token revoked\")\n```\n\n`redis_client` is your own Redis connection or adapter.\n\nDo not use a process-local Python set for this in production. Revocation state must survive restarts and be shared across workers.\n\n## Configuration Checklist\n\nMost apps should review these settings explicitly:\n\n- `JWT_SECRET_KEY`: signing secret for JWTs; keep it out of source control and stable across instances\n- `JWT_ACCESS_TOKEN_EXPIRES`: short lifetime for access tokens\n- `JWT_REFRESH_TOKEN_EXPIRES`: separate lifetime for refresh tokens\n- `JWT_TOKEN_LOCATION`: choose header mode for APIs or cookie mode for browser flows\n- `JWT_COOKIE_SECURE`: `True` in production when using cookies\n- `JWT_COOKIE_CSRF_PROTECT`: keep enabled for cookie-based auth\n- `JWT_IDENTITY_CLAIM`: defaults to `sub` in 4.x\n\nPractical rules:\n\n- Use a dedicated JWT secret instead of hard-coding values in the app module.\n- Treat JWT contents as signed, not encrypted. Do not put secrets or unnecessary PII in claims.\n- Keep token payloads small; every authenticated request carries them back to the server.\n\n## Common Pitfalls\n\n- Search results still surface the old `3.0.0_release` docs. Those pages are not reliable for 4.7.1 code.\n- The package name is `flask-jwt-extended`, but imports are from `flask_jwt_extended`.\n- `@jwt_required()` is the 4.x decorator. Old 3.x helpers like `@jwt_refresh_token_required` should not be copied forward.\n- `get_jwt()` replaces older raw-JWT helper patterns from pre-4.x examples.\n- `current_user` is not automatic; it depends on a configured user lookup callback.\n- Cookie mode requires CSRF handling and correct cookie settings. Disabling CSRF to make a browser flow \"work\" is usually the wrong fix.\n- Revocation requires shared persistent storage. In-memory revocation breaks as soon as you run multiple workers or restart the process.\n- Rotating `JWT_SECRET_KEY` invalidates outstanding tokens. Plan key changes deliberately.\n\n## Version-Sensitive Notes For 4.7.1\n\nAs of March 12, 2026, the stable docs and PyPI both align on `4.7.1`.\n\nImportant 4.x behavior changes from the official upgrade guide:\n\n- JWT payload structure changed in 4.x.\n- The default identity claim moved to `sub`.\n- Custom claims are flattened into the top-level payload instead of living under a nested claim bucket.\n- Several callback names and signatures changed between 3.x and 4.x.\n\nIf you are updating older code, read the 4.x upgrade guide before reusing decorators, callbacks, claim access patterns, or token-inspection helpers from blog posts and issue comments.\n"
  },
  {
    "path": "content/flask/docs/limiter/python/DOC.md",
    "content": "---\nname: limiter\ndescription: \"Flask-Limiter package guide for Python Flask rate limiting, storage backends, CLI inspection, and 429 handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask-limiter,flask,python,rate-limiting,redis,limits\"\n---\n\n# Flask-Limiter Python Package Guide\n\n## What It Is\n\n`Flask-Limiter` adds request rate limiting to Flask apps. It supports:\n\n- default limits applied to many routes\n- route-specific limits\n- shared buckets across multiple routes\n- application-wide limits\n- per-method limits\n- meta limits for repeated breaches\n- pluggable storage backends via `limits`\n\nThis entry is for `Flask-Limiter==4.1.1`, the current stable release on PyPI and the version tracked by the stable docs.\n\n## Installation\n\nBase install:\n\n```bash\npip install Flask-Limiter==4.1.1\n```\n\nCommon extras:\n\n```bash\npip install \"Flask-Limiter[redis]==4.1.1\"\npip install \"Flask-Limiter[valkey]==4.1.1\"\npip install \"Flask-Limiter[cli]==4.1.1\"\n```\n\nNotes:\n\n- Use a shared backend such as Redis or Valkey in production.\n- `memory://` is fine for local development and tests, not for multi-process or multi-instance deployments.\n- The `cli` extra is separate in `4.1.x`; it is no longer bundled into every install.\n\n## Minimal Setup\n\nConstructor-first initialization:\n\n```python\nfrom flask import Flask\nfrom flask_limiter import Limiter\nfrom flask_limiter.util import get_remote_address\n\napp = Flask(__name__)\n\nlimiter = Limiter(\n    key_func=get_remote_address,\n    app=app,\n    default_limits=[\"200 per day\", \"50 per hour\"],\n    storage_uri=\"memory://\",\n)\n\n@app.get(\"/slow\")\n@limiter.limit(\"1 per day\")\ndef slow() -> str:\n    return \"slow\"\n\n@app.get(\"/medium\")\n@limiter.limit(\"1/second\", override_defaults=False)\ndef medium() -> str:\n    return \"medium\"\n\n@app.get(\"/health\")\n@limiter.exempt\ndef health() -> str:\n    return \"ok\"\n```\n\nBehavior:\n\n- Route decorators override defaults unless `override_defaults=False`.\n- `@limiter.exempt` skips default and application limits for that endpoint.\n- `get_remote_address()` uses the request remote address, so proxy configuration matters.\n\n## App Factory Setup\n\nUse `init_app()` in app-factory projects:\n\n```python\nfrom flask import Flask\nfrom flask_limiter import Limiter\nfrom flask_limiter.util import get_remote_address\n\nlimiter = Limiter(key_func=get_remote_address, default_limits=[\"100/minute\"])\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"RATELIMIT_STORAGE_URI\"] = \"redis://localhost:6379/0\"\n    app.config[\"RATELIMIT_HEADERS_ENABLED\"] = True\n    limiter.init_app(app)\n    return app\n```\n\nConstructor arguments win over equivalent Flask config values, so avoid setting the same option in both places unless that precedence is intentional.\n\n## Production Storage Setup\n\nUse a shared backend for real deployments:\n\n```python\nfrom flask import Flask\nfrom flask_limiter import Limiter\nfrom flask_limiter.util import get_remote_address\n\napp = Flask(__name__)\napp.config.update(\n    RATELIMIT_STORAGE_URI=\"redis://localhost:6379/0\",\n    RATELIMIT_STRATEGY=\"fixed-window\",\n    RATELIMIT_HEADERS_ENABLED=True,\n)\n\nlimiter = Limiter(\n    key_func=get_remote_address,\n    app=app,\n    default_limits=[\"100/minute\"],\n    application_limits=[\"1000/hour\"],\n    meta_limits=[\"20/hour\"],\n)\n```\n\nPractical choices:\n\n- `fixed-window`: simplest and lowest overhead.\n- `moving-window`: stricter behavior, more backend work.\n- `sliding-window-counter`: approximation with lower cost than a full moving window.\n\n## Core Usage Patterns\n\nPer-route limit:\n\n```python\n@app.post(\"/login\")\n@limiter.limit(\"5/minute\")\ndef login():\n    ...\n```\n\nKeep defaults and add a tighter route limit:\n\n```python\n@app.post(\"/checkout\")\n@limiter.limit(\"10/minute\", override_defaults=False)\ndef checkout():\n    ...\n```\n\nPer-method limits:\n\n```python\n@app.route(\"/items\", methods=[\"GET\", \"POST\"])\n@limiter.limit(\"20/minute\", methods=[\"POST\"], per_method=True)\ndef items():\n    ...\n```\n\nShared bucket across routes:\n\n```python\nwrite_limit = limiter.shared_limit(\"100/hour\", scope=\"writes\")\n\n@app.post(\"/posts\")\n@write_limit\ndef create_post():\n    ...\n\n@app.post(\"/comments\")\n@write_limit\ndef create_comment():\n    ...\n```\n\nWeighted requests:\n\n```python\nfrom flask import request\n\n@app.post(\"/batch\")\n@limiter.limit(\"100/hour\", cost=lambda: len(request.json.get(\"items\", [])) or 1)\ndef batch():\n    ...\n```\n\nUse `cost` only when one request can represent materially different backend load.\n\n## Identity, Auth, And Proxies\n\n`Flask-Limiter` does not authenticate users. Your app decides identity, then `key_func` decides the bucket key.\n\nAuthenticated-user buckets:\n\n```python\nfrom flask_login import current_user\nfrom flask_limiter.util import get_remote_address\n\ndef rate_limit_key() -> str:\n    if current_user.is_authenticated:\n        return f\"user:{current_user.get_id()}\"\n    return get_remote_address()\n```\n\nProxy-safe setup:\n\n```python\nfrom werkzeug.middleware.proxy_fix import ProxyFix\n\napp.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)\n```\n\nImportant:\n\n- If you are behind a load balancer or reverse proxy, configure proxy handling before relying on `get_remote_address()`.\n- Without proxy fixups, all clients may collapse into the proxy IP and share one rate-limit bucket.\n- If you have multi-tenant auth, key on tenant or account identifiers instead of raw IPs.\n\n## 429 Handling\n\nCustom JSON response:\n\n```python\nfrom flask import jsonify\nfrom flask_limiter.errors import RateLimitExceeded\n\n@app.errorhandler(429)\ndef ratelimit_handler(error: RateLimitExceeded):\n    response = error.get_response()\n    if response is not None:\n        return response\n    return jsonify(error=\"rate_limit_exceeded\", detail=error.description), 429\n```\n\nIf you use `on_breach`, keep the `429` error handler compatible with the embedded response by checking `error.get_response()` first.\n\n## Useful Configuration Keys\n\nHigh-signal Flask config keys for most projects:\n\n- `RATELIMIT_ENABLED`: global on/off switch.\n- `RATELIMIT_STORAGE_URI`: backend connection string such as `redis://...`.\n- `RATELIMIT_STRATEGY`: `fixed-window`, `moving-window`, or `sliding-window-counter`.\n- `RATELIMIT_DEFAULT`: default route limits.\n- `RATELIMIT_APPLICATION`: app-wide shared limits.\n- `RATELIMIT_META`: meta limits for repeated breaches.\n- `RATELIMIT_HEADERS_ENABLED`: emits rate-limit response headers.\n- `RATELIMIT_FAIL_ON_FIRST_BREACH`: stop evaluating additional limits after the first breach.\n- `RATELIMIT_KEY_PREFIX`: namespace keys when multiple apps share one backend.\n- `RATELIMIT_REQUEST_IDENTIFIER`: customize how requests are identified for some strategies and logging.\n\nUse either constructor kwargs or config-first initialization consistently. Mixing both is valid, but it becomes harder to reason about precedence.\n\n## CLI And Debugging\n\nInstall the CLI extra if you want the Flask CLI integration:\n\n```bash\npip install \"Flask-Limiter[cli]==4.1.1\"\n```\n\nUseful commands:\n\n```bash\nflask limiter config\nflask limiter limits\n```\n\nUse them to verify:\n\n- the active backend and strategy\n- default, application, and route limits actually registered\n- whether your app factory or environment-specific config loaded the values you expected\n\n## Common Pitfalls\n\n- Using `memory://` in production. Counters stay local to one process.\n- Relying on IP-based keys behind a proxy without `ProxyFix` or equivalent trusted-proxy setup.\n- Forgetting that route decorators override defaults by default.\n- Treating `Flask-Limiter` as an auth system. It only consumes request identity; it does not establish it.\n- Swallowing backend failures without understanding the effect. If the backend is unavailable and you enable fallback or error swallowing, you may silently weaken protection.\n- Copying older blog posts that still assume Python `3.8` or bundled CLI dependencies.\n\n## Version-Sensitive Notes For 4.x\n\n- `4.1.1` is the current stable release and matches the stable docs.\n- `4.1.0` split extras so `cli` is installed separately; if you upgraded from older guides, add `[cli]` explicitly.\n- `4.0.0` dropped support for Python `<3.10`, Flask `<2`, and Werkzeug `<2`.\n- `4.0.0` also renamed the old `RATELIMIT_ENABLED` config key from the earlier `RATELIMIT_ENABLE` spelling.\n- The stable docs are appropriate for `4.1.1`, but older `3.x` setups may differ in Python support, extras, and some config details.\n\n## Official Sources\n\n- Stable docs: https://flask-limiter.readthedocs.io/en/stable/\n- Quick start and initialization: https://flask-limiter.readthedocs.io/en/stable/\n- Configuration: https://flask-limiter.readthedocs.io/en/stable/configuration.html\n- Recipes and proxy guidance: https://flask-limiter.readthedocs.io/en/stable/recipes.html\n- CLI: https://flask-limiter.readthedocs.io/en/stable/cli.html\n- Changelog: https://flask-limiter.readthedocs.io/en/stable/changelog.html\n- PyPI package page: https://pypi.org/project/flask-limiter/\n- PyPI version metadata JSON: https://pypi.org/pypi/Flask-Limiter/4.1.1/json\n"
  },
  {
    "path": "content/flask/docs/login/python/DOC.md",
    "content": "---\nname: login\ndescription: \"Flask-Login guide for user loading, login state, remember cookies, and route protection in Flask apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,flask-login,authentication,session,login,remember-cookie\"\n---\n\n# Flask-Login for Flask Apps\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Flask-Login==0.6.3\"\n```\n\nPyPI metadata for `0.6.3` requires:\n\n- `Flask >=1.0.4`\n- `Werkzeug >=1.0.1`\n\n`0.6.3` specifically adds compatibility with Flask 3 and Werkzeug 3.\n\n## Minimal Setup\n\n```python\nfrom flask import Flask, redirect, url_for\nfrom flask_login import LoginManager, UserMixin, current_user, login_required\n\napp = Flask(__name__)\napp.config[\"SECRET_KEY\"] = \"replace-me\"\n\nlogin_manager = LoginManager()\nlogin_manager.login_view = \"login\"\nlogin_manager.init_app(app)\n\nclass User(UserMixin):\n    def __init__(self, user_id: str, email: str) -> None:\n        self.id = user_id\n        self.email = email\n\nUSERS = {\n    \"1\": User(\"1\", \"user@example.com\"),\n}\n\n@login_manager.user_loader\ndef load_user(user_id: str):\n    return USERS.get(user_id)\n\n@app.get(\"/\")\ndef index():\n    if current_user.is_authenticated:\n        return f\"Hello, {current_user.email}\"\n    return redirect(url_for(\"login\"))\n\n@app.get(\"/settings\")\n@login_required\ndef settings():\n    return \"protected\"\n```\n\nImportant contract for your user class:\n\n- `is_authenticated`\n- `is_active`\n- `is_anonymous`\n- `get_id()`\n\nIf a user should not be allowed to sign in, make `is_active` return `False`.\n\n## Login And Logout Flow\n\nYou validate credentials yourself, then call `login_user()`:\n\n```python\nfrom flask import abort, redirect, render_template, request, url_for\nfrom flask_login import login_required, login_user, logout_user\n\ndef is_safe_redirect_target(target: str | None) -> bool:\n    return not target or target.startswith(\"/\")\n\n@app.route(\"/login\", methods=[\"GET\", \"POST\"])\ndef login():\n    if request.method == \"GET\":\n        return render_template(\"login.html\")\n\n    email = request.form[\"email\"]\n    password = request.form[\"password\"]\n    remember = request.form.get(\"remember\") == \"on\"\n\n    user = authenticate(email, password)\n    if user is None:\n        abort(401)\n\n    login_user(user, remember=remember)\n\n    next_url = request.args.get(\"next\")\n    if not is_safe_redirect_target(next_url):\n        abort(400)\n\n    return redirect(next_url or url_for(\"index\"))\n\n@app.post(\"/logout\")\n@login_required\ndef logout():\n    logout_user()\n    return redirect(url_for(\"index\"))\n```\n\nDo not blindly redirect to `request.args[\"next\"]`. Validate it first or you create an open redirect.\n\nIf you want Flask-Login to keep the target URL in the session rather than the query string, set:\n\n```python\napp.config[\"USE_SESSION_FOR_NEXT\"] = True\n```\n\n## Request Loading And API Behavior\n\n### Session-backed login\n\n`user_loader` is the normal path for browser sessions. It receives the string returned by `get_id()` and must return the matching user object or `None`.\n\nReturning `None` matters: if the user no longer exists, Flask-Login removes the invalid ID from the session.\n\n### Request-based login\n\nFor request-authenticated endpoints, use `request_loader`:\n\n```python\nimport base64\nfrom flask import request\n\n@login_manager.request_loader\ndef load_user_from_request(request):\n    api_key = request.args.get(\"api_key\")\n    if api_key:\n        user = lookup_user_by_api_key(api_key)\n        if user:\n            return user\n\n    auth_header = request.headers.get(\"Authorization\")\n    if auth_header and auth_header.startswith(\"Basic \"):\n        encoded = auth_header.removeprefix(\"Basic \")\n        try:\n            decoded = base64.b64decode(encoded).decode()\n        except Exception:\n            return None\n        return lookup_user_by_api_key(decoded)\n\n    return None\n```\n\n`header_loader` still exists in `0.6.3`, but the docs mark it deprecated. Prefer `request_loader` for new code.\n\n### Unauthorized responses\n\nIf you set `login_view`, unauthorized browser requests redirect to that view. That is usually wrong for APIs, so add `unauthorized_handler`:\n\n```python\nfrom http import HTTPStatus\nfrom flask import jsonify, redirect, request, url_for\n\n@login_manager.unauthorized_handler\ndef unauthorized():\n    if request.blueprint == \"api\":\n        return jsonify(error=\"authentication required\"), HTTPStatus.UNAUTHORIZED\n    return redirect(url_for(\"login\"))\n```\n\nIf your app has different auth entry points per blueprint, use `login_manager.blueprint_login_views` instead of forcing one global login route.\n\n## Fresh Logins For Sensitive Actions\n\nRemembered sessions are not always \"fresh\". Use `@fresh_login_required` when a user must re-authenticate before a sensitive action:\n\n```python\nfrom flask_login import confirm_login, fresh_login_required, login_user\n\nlogin_manager.refresh_view = \"accounts.reauthenticate\"\nlogin_manager.needs_refresh_message = (\n    \"Please reauthenticate before changing sensitive settings.\"\n)\nlogin_manager.needs_refresh_message_category = \"info\"\n\n@app.post(\"/account/reauth\")\ndef reauth():\n    user = authenticate_again(...)\n    if user is None:\n        return {\"error\": \"bad credentials\"}, 401\n    confirm_login()\n    return {\"ok\": True}\n\n@app.get(\"/account/security\")\n@fresh_login_required\ndef account_security():\n    return \"fresh session required\"\n```\n\nUse this for actions such as email changes, MFA setup, or billing changes.\n\n## Remember-Me And Cookie Configuration\n\n`login_user(..., remember=True)` issues a persistent remember cookie. Important settings from the `0.6.3` docs:\n\n- `REMEMBER_COOKIE_NAME`\n- `REMEMBER_COOKIE_DURATION`\n- `REMEMBER_COOKIE_DOMAIN`\n- `REMEMBER_COOKIE_PATH`\n- `REMEMBER_COOKIE_SECURE`\n- `REMEMBER_COOKIE_HTTPONLY`\n- `REMEMBER_COOKIE_REFRESH_EACH_REQUEST`\n- `REMEMBER_COOKIE_SAMESITE`\n\nExample:\n\n```python\nfrom datetime import timedelta\n\napp.config.update(\n    REMEMBER_COOKIE_DURATION=timedelta(days=14),\n    REMEMBER_COOKIE_SECURE=True,\n    REMEMBER_COOKIE_HTTPONLY=True,\n    REMEMBER_COOKIE_SAMESITE=\"Lax\",\n    REMEMBER_COOKIE_REFRESH_EACH_REQUEST=False,\n)\n```\n\nOperational notes:\n\n- `REMEMBER_COOKIE_SECURE` should be `True` in production behind HTTPS.\n- `REMEMBER_COOKIE_HTTPONLY` is `True` by default and should usually stay that way.\n- `REMEMBER_COOKIE_REFRESH_EACH_REQUEST=True` extends the lifetime on every request; leave it off unless you explicitly want sliding expiration.\n\n## Session Protection\n\nFlask-Login can bind a session to a client fingerprint based on IP address and user agent:\n\n```python\nlogin_manager.session_protection = \"strong\"\n```\n\nModes in `0.6.3`:\n\n- `\"basic\"`: identifier changes mark the session non-fresh\n- `None`: disables session protection\n\nThe docs say the default is `\"basic\"`. You can also configure this via `app.config[\"SESSION_PROTECTION\"]`.\n\nBe careful with `\"strong\"` behind proxies, mobile networks, or other environments where IP/user-agent characteristics shift often.\n\n## API Requests Without Writing A Session Cookie\n\nIf you authenticate via `request_loader`, you may not want Flask to write a session cookie for API calls. The official docs recommend a custom session interface keyed off `user_loaded_from_request`:\n\n```python\nfrom flask import g\nfrom flask.sessions import SecureCookieSessionInterface\nfrom flask_login import user_loaded_from_request\n\n@user_loaded_from_request.connect\ndef mark_login_via_request(app, user=None):\n    g.login_via_request = True\n\nclass APISessionInterface(SecureCookieSessionInterface):\n    def save_session(self, *args, **kwargs):\n        if g.get(\"login_via_request\"):\n            return\n        return super().save_session(*args, **kwargs)\n\napp.session_interface = APISessionInterface()\n```\n\nUse this when request-authenticated API traffic should stay stateless.\n\n## Testing\n\nFor test code, use the built-in `FlaskLoginClient` instead of manually building login session state:\n\n```python\nfrom flask_login import FlaskLoginClient\n\napp.test_client_class = FlaskLoginClient\n\ndef test_settings_page(app, user):\n    with app.test_client(user=user, fresh_login=True) as client:\n        response = client.get(\"/settings\")\n        assert response.status_code == 200\n```\n\nTwo details from the docs matter:\n\n- Pass `user=` as a keyword argument, not a positional argument.\n- If session protection is enabled, test-client requests may become non-fresh in `\"basic\"` mode or fail in `\"strong\"` mode. Disable session protection in tests if needed.\n\n`LOGIN_DISABLED` still exists in `0.6.3` and can bypass login checks in tests, but it is not a good primary testing strategy when you want realistic auth behavior.\n\n## Common Pitfalls\n\n- Missing `SECRET_KEY`: session-backed auth will not work correctly without it.\n- Returning non-string IDs: keep `get_id()` string-based.\n- Forgetting `user_loader`: `current_user` cannot be restored from the session without it.\n- Using `@login_required` on JSON routes without `unauthorized_handler`: you get HTML redirects instead of `401`.\n- Treating Flask-Login as a full auth system: it does not hash passwords, register users, or handle permissions.\n- Using deprecated `header_loader` in new code: prefer `request_loader`.\n- Copying examples from `latest`: the `latest` docs are `0.7.0`, not `0.6.3`.\n\n## Version-Sensitive Notes\n\n- `0.6.3` is the package version covered here and is the release that adds Flask 3 / Werkzeug 3 compatibility.\n- `0.6.2` already warned that `header_loader` is deprecated and that `request_loader` should replace it.\n- The current `0.7.0` changelog removes `LOGIN_DISABLED` and previously deprecated code. If you rely on deprecated paths in `0.6.3`, expect upgrade cleanup.\n- When behavior and docs disagree, prefer the version-pinned `0.6.3` docs and the package's changelog over `latest`.\n\n## Official Sources\n\n- Version-pinned docs: https://flask-login.readthedocs.io/en/0.6.3/\n- Latest docs root: https://flask-login.readthedocs.io/en/latest/\n- PyPI release page: https://pypi.org/project/Flask-Login/0.6.3/\n- PyPI JSON metadata: https://pypi.org/pypi/Flask-Login/0.6.3/json\n- Source repository: https://github.com/maxcountryman/flask-login\n- Changelog: https://github.com/maxcountryman/flask-login/blob/main/CHANGES.md\n"
  },
  {
    "path": "content/flask/docs/mail/python/DOC.md",
    "content": "---\nname: mail\ndescription: \"Flask-Mail extension guide for SMTP email sending, attachments, testing, and bulk delivery in Flask apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,mail,email,smtp,testing,attachments,python\"\n---\n\n# Flask-Mail Python Guide\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Flask-Mail==0.10.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Flask-Mail==0.10.0\"\npoetry add \"Flask-Mail==0.10.0\"\n```\n\nFlask-Mail depends on SMTP access. It does not provision an email service for you. You still need credentials and server settings from your mail provider or relay.\n\n## Initialize In A Flask App\n\nLoad config before calling `Mail(app)` or `mail.init_app(app)`.\n\n```python\nimport os\n\nfrom flask import Flask\nfrom flask_mail import Mail\n\nmail = Mail()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        MAIL_SERVER=os.environ[\"MAIL_SERVER\"],\n        MAIL_PORT=int(os.getenv(\"MAIL_PORT\", \"587\")),\n        MAIL_USE_TLS=os.getenv(\"MAIL_USE_TLS\", \"true\").lower() == \"true\",\n        MAIL_USE_SSL=os.getenv(\"MAIL_USE_SSL\", \"false\").lower() == \"true\",\n        MAIL_USERNAME=os.getenv(\"MAIL_USERNAME\"),\n        MAIL_PASSWORD=os.getenv(\"MAIL_PASSWORD\"),\n        MAIL_DEFAULT_SENDER=os.environ[\"MAIL_DEFAULT_SENDER\"],\n    )\n\n    mail.init_app(app)\n    return app\n```\n\nImportant setup rules:\n\n- Configure the app before `mail.init_app(app)`. Flask-Mail reads mail settings during initialization.\n- With the extension-factory pattern (`mail = Mail()` then `init_app()`), mail sending uses Flask's application context. Push `app.app_context()` for CLI scripts, background jobs, or one-off tasks outside requests.\n- `MAIL_DEFAULT_SENDER` avoids repeating `sender=` on every message. If you do not set it, pass `sender=` explicitly when constructing a message.\n\n## Core Sending Pattern\n\nUse `Message` for the envelope and body, then send it through the configured `Mail` instance.\n\n```python\nfrom flask import Blueprint, jsonify\nfrom flask_mail import Message\n\nbp = Blueprint(\"mail_demo\", __name__)\n\n@bp.post(\"/send-welcome\")\ndef send_welcome():\n    msg = Message(\n        subject=\"Welcome\",\n        recipients=[\"user@example.com\"],\n        body=\"Thanks for signing up.\",\n        html=\"<p>Thanks for signing up.</p>\",\n        reply_to=\"support@example.com\",\n    )\n\n    mail.send(msg)\n    return jsonify(sent=True)\n```\n\nCommon `Message(...)` arguments you will actually use:\n\n- `subject`\n- `recipients`\n- `body`\n- `html`\n- `sender`\n- `cc`\n- `bcc`\n- `reply_to`\n- `extra_headers`\n\nUseful details from the official docs:\n\n- `recipients` is a list; you can also call `msg.add_recipient(\"other@example.com\")`.\n- If `sender` is a two-item tuple such as `(\"Support\", \"support@example.com\")`, Flask-Mail formats it as a display name plus address.\n- `mail.send_message(...)` is a convenience wrapper around `Message(...)` plus `mail.send(...)`.\n\n## Attachments\n\nAttach bytes from a file-like object or other in-memory content:\n\n```python\nfrom flask import current_app\nfrom flask_mail import Message\n\ndef send_report() -> None:\n    msg = Message(\n        subject=\"Daily report\",\n        recipients=[\"ops@example.com\"],\n        body=\"Attached.\",\n    )\n\n    with current_app.open_resource(\"reports/daily.csv\") as fp:\n        msg.attach(\"daily.csv\", \"text/csv\", fp.read())\n\n    mail.send(msg)\n```\n\nNotes:\n\n- `msg.attach(filename, content_type, data)` is the direct API.\n- In `0.10.0`, attachment content type is detected from `filename` and `data` if you do not provide one, and attachment data may not be `None`.\n- Set `MAIL_ASCII_ATTACHMENTS=True` if your relay mishandles UTF-8 attachment filenames.\n\n## Bulk Email\n\nFor many messages in one job, reuse a connection:\n\n```python\nfrom flask_mail import Message\n\ndef send_batch(users: list[dict[str, str]]) -> None:\n    with mail.connect() as conn:\n        for user in users:\n            msg = Message(\n                subject=f\"Hello, {user['name']}\",\n                recipients=[user[\"email\"]],\n                body=\"Your account update is ready.\",\n            )\n            conn.send(msg)\n```\n\nSet `MAIL_MAX_EMAILS` if your SMTP provider limits how many messages can be sent on one connection before reconnecting.\n\n## Testing And Suppressed Delivery\n\nFlask-Mail is usable in tests without sending real mail.\n\n```python\nfrom flask import Flask\nfrom flask_mail import Mail\n\nmail = Mail()\n\ndef test_mail_capture():\n    app = Flask(__name__)\n    app.config.update(\n        TESTING=True,\n        MAIL_DEFAULT_SENDER=\"noreply@example.com\",\n    )\n    mail.init_app(app)\n\n    with app.app_context():\n        with mail.record_messages() as outbox:\n            mail.send_message(\n                subject=\"Testing\",\n                recipients=[\"dev@example.com\"],\n                body=\"hello\",\n            )\n\n        assert len(outbox) == 1\n        assert outbox[0].subject == \"Testing\"\n```\n\nKey behavior:\n\n- `TESTING=True` suppresses actual sending.\n- `MAIL_SUPPRESS_SEND=True` does the same outside test mode.\n- `mail.record_messages()` captures the `Message` objects that would have been dispatched.\n- The `email_dispatched` signal still fires even when sending is suppressed.\n\n## Configuration And Auth\n\nThe core config keys from the official docs are:\n\n- `MAIL_SERVER`: SMTP hostname, default `localhost`\n- `MAIL_PORT`: SMTP port, default `25`\n- `MAIL_USE_TLS`: enable STARTTLS\n- `MAIL_USE_SSL`: enable implicit TLS\n- `MAIL_DEBUG`: mail transport debug logging, defaults to `app.debug`\n- `MAIL_USERNAME`\n- `MAIL_PASSWORD`\n- `MAIL_DEFAULT_SENDER`\n- `MAIL_MAX_EMAILS`\n- `MAIL_SUPPRESS_SEND`: defaults to `app.testing`\n- `MAIL_ASCII_ATTACHMENTS`\n\nPractical guidance:\n\n- Keep SMTP credentials in environment variables or your secret manager, not in code.\n- Match `MAIL_PORT`, `MAIL_USE_TLS`, and `MAIL_USE_SSL` to your provider's documented SMTP settings.\n- If you are using a provider account with app passwords, API-generated SMTP passwords, or a relay username separate from your mailbox address, store exactly the provider-issued value in `MAIL_PASSWORD`.\n- If your background worker or CLI command sends email outside a request, create an app and push `with app.app_context():` before calling `mail.send(...)`.\n\n## Signals And Observability\n\nFlask-Mail exposes an `email_dispatched` signal for logging, tests, or metrics.\n\n```python\nfrom flask_mail import email_dispatched\n\ndef log_message(app, message):\n    app.logger.info(\"mail subject=%s to=%s\", message.subject, message.recipients)\n\nemail_dispatched.connect(log_message)\n```\n\nIn `0.10.0`, the signal behavior changed so the current Flask app is the sender and the `Message` object is passed as the `message` argument.\n\n## Common Pitfalls\n\n- If you initialize `Mail` before loading config, the extension will not pick up the SMTP settings you expected.\n- If `TESTING=True`, mail is suppressed. This often looks like a configuration failure when you are manually checking delivery.\n- If you omit both `sender=` and `MAIL_DEFAULT_SENDER`, your message setup is incomplete.\n- Header injection protection is strict. Newlines in subject, sender, or recipient fields raise `BadHeaderError`.\n- Flask-Mail sends through SMTP. If your provider requires a REST API instead of SMTP, use that provider's API client instead of forcing Flask-Mail into the wrong transport model.\n- When using `mail = Mail()` plus `init_app()`, background jobs and scripts need an application context.\n\n## Version-Sensitive Notes For 0.10.0\n\n- `0.10.0` is the latest PyPI release as of March 12, 2026.\n- `0.10.0` drops support for Python earlier than 3.8.\n- `flask_mail.__version__` is deprecated in `0.10.0`. Use `importlib.metadata.version(\"flask-mail\")` if you need the installed package version.\n- The deprecated `is_bad_headers` helper is flagged for removal in the next version, so do not build new code around it.\n- `Attachment.data` may not be `None` in `0.10.0`.\n- `Attachment.content_type` is now inferred when possible from the filename and data.\n- The upstream repository moved from the historical `mattupstate/flask-mail` location to `pallets-eco/flask-mail`. Use the Pallets-Eco repository and the Read the Docs site as canonical sources.\n"
  },
  {
    "path": "content/flask/docs/marshmallow/python/DOC.md",
    "content": "---\nname: marshmallow\ndescription: \"flask-marshmallow 1.4.0 package guide for Flask-aware Marshmallow schemas, URL fields, file validation, and SQLAlchemy integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,marshmallow,serialization,validation,sqlalchemy,uploads\"\n---\n\n# flask-marshmallow Python Package Guide\n\n## Install\n\nPin the package version the project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"flask-marshmallow==1.4.0\"\n```\n\nFor ORM-backed schemas, install the SQLAlchemy packages explicitly too:\n\n```bash\npip install \"flask-marshmallow==1.4.0\" Flask-SQLAlchemy marshmallow-sqlalchemy\n```\n\nIf you are upgrading an older app, check the changelog before assuming compatibility with old `marshmallow` or Flask versions.\n\n## Initialize In An App Factory\n\nUse the normal Flask extension pattern:\n\n```python\nfrom flask import Flask\nfrom flask_marshmallow import Marshmallow\n\nma = Marshmallow()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"API_TITLE\"] = \"Example API\"\n\n    ma.init_app(app)\n    return app\n```\n\nWhat `ma` exposes:\n\n- `ma.Schema` for your base schema class\n- standard marshmallow fields through the extension\n- Flask-specific fields such as `URLFor`, `AbsoluteURLFor`, `Hyperlinks`, and `Config`\n- SQLAlchemy schema classes when the SQLAlchemy integration packages are installed\n\n## Core Schema Usage\n\nUse `ma.Schema` like a normal marshmallow schema, then add Flask-specific fields when you need URLs or config-backed values.\n\n```python\nfrom flask import Flask\nfrom flask_marshmallow import Marshmallow\nfrom marshmallow import fields\n\nma = Marshmallow()\napp = Flask(__name__)\nma.init_app(app)\n\nclass UserSchema(ma.Schema):\n    id = fields.Int(dump_only=True)\n    email = fields.Email(required=True)\n    profile_url = ma.URLFor(\"user_detail\", values={\"user_id\": \"<id>\"})\n    _links = ma.Hyperlinks(\n        {\n            \"self\": ma.URLFor(\"user_detail\", values={\"user_id\": \"<id>\"}),\n            \"collection\": ma.URLFor(\"user_list\"),\n        }\n    )\n\nuser_schema = UserSchema()\n```\n\nIn a view:\n\n```python\n@app.get(\"/users\")\ndef user_list():\n    users = [{\"id\": 1, \"email\": \"a@example.com\"}]\n    return {\"items\": user_schema.dump(users, many=True)}\n\n@app.get(\"/users/<int:user_id>\")\ndef user_detail(user_id: int):\n    return user_schema.dump({\"id\": user_id, \"email\": \"a@example.com\"})\n```\n\nPractical notes:\n\n- URL fields build Flask endpoints with `url_for`, so the endpoint name must match an actual route.\n- Route parameters belong in `values={...}` and can reference object attributes with placeholders such as `\"<id>\"`.\n- If you serialize outside a request handler, create a request context first:\n\n```python\nwith app.test_request_context():\n    payload = user_schema.dump({\"id\": 1, \"email\": \"a@example.com\"})\n```\n\n## SQLAlchemy Integration\n\nIf you use `Flask-SQLAlchemy`, initialize the database extension before `Marshmallow`.\n\n```python\nfrom flask import Flask\nfrom flask_marshmallow import Marshmallow\nfrom flask_sqlalchemy import SQLAlchemy\n\ndb = SQLAlchemy()\nma = Marshmallow()\n\nclass Author(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    name = db.Column(db.String(120), nullable=False)\n\nclass AuthorSchema(ma.SQLAlchemyAutoSchema):\n    class Meta:\n        model = Author\n        load_instance = True\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SQLALCHEMY_DATABASE_URI\"] = \"sqlite:///app.db\"\n\n    db.init_app(app)\n    ma.init_app(app)\n    return app\n```\n\nUse this pattern when you want schema generation from Flask-SQLAlchemy models. `flask-marshmallow` does not replace query planning or relationship loading; keep eager-loading and N+1 concerns explicit in your model and query code.\n\n## File Upload Validation\n\nThe package includes a `File` field plus validators in `flask_marshmallow.validate`.\n\n```python\nfrom flask import request\nfrom flask_marshmallow import Marshmallow\nfrom flask_marshmallow.validate import FileSize, FileType\n\nma = Marshmallow()\n\nclass UploadSchema(ma.Schema):\n    image = ma.File(\n        required=True,\n        validate=[\n            FileType([\".png\", \".jpg\", \".jpeg\"]),\n            FileSize(max=\"5 MiB\"),\n        ],\n    )\n\ndef validate_upload():\n    return UploadSchema().load({\"image\": request.files[\"image\"]})\n```\n\nUse file validation with `request.files` objects, not JSON payloads.\n\n## Config And Auth\n\n`flask-marshmallow` can expose Flask config values through schemas, but it is not an auth library.\n\n```python\nclass AppInfoSchema(ma.Schema):\n    api_title = ma.Config(\"API_TITLE\")\n```\n\nImportant behavior:\n\n- `Config` reads from `app.config` during serialization.\n- Missing config keys raise `ValueError`.\n- Do not serialize secrets such as API keys, signing keys, or OAuth client secrets.\n- For authentication and authorization, use Flask itself or a dedicated auth extension; `flask-marshmallow` only handles serialization and validation concerns.\n\n## Common Pitfalls\n\n- Forgetting `ma.init_app(app)`: schemas and Flask-aware fields will not be wired to the application.\n- Using URL fields for endpoints that are not registered: dumps fail when Flask cannot build the route.\n- Serializing URL fields outside a request context: create a test request context for background tasks or tests.\n- Expecting SQLAlchemy helpers without `Flask-SQLAlchemy` and `marshmallow-sqlalchemy`: install both packages when you need model-backed schemas.\n- Reading missing config keys with `ma.Config`: this raises `ValueError` instead of returning `None`.\n- Validating uploads from JSON request bodies: file validators operate on uploaded file objects from `request.files`.\n- Copying old examples that use removed legacy schema helpers: prefer `SQLAlchemySchema` and `SQLAlchemyAutoSchema`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.4.0`, which matches the version used here and the current upstream docs and PyPI release line as checked on 2026-03-12.\n- The official changelog says `1.4.0` adds support for `Flask-SQLAlchemy 3`.\n- The official changelog says `1.3.0` adds support for `marshmallow 4`; do not assume that compatibility if your app is pinned below `1.3.0`.\n- The official changelog says `1.2.0` adds support for `Flask 3.0` and `webargs 8`.\n- Since `1.0.0`, the package no longer exposes `flask_marshmallow.__version__`; use `importlib.metadata.version(\"flask-marshmallow\")` if you need the installed package version at runtime.\n\n## Official Sources\n\n- Docs root: `https://flask-marshmallow.readthedocs.io/en/latest/`\n- Changelog: `https://flask-marshmallow.readthedocs.io/en/latest/changelog.html`\n- PyPI project: `https://pypi.org/project/flask-marshmallow/`\n- Repository: `https://github.com/marshmallow-code/flask-marshmallow`\n"
  },
  {
    "path": "content/flask/docs/migrate/python/DOC.md",
    "content": "---\nname: migrate\ndescription: \"Flask-Migrate package guide for Python: Alembic-powered schema migrations for Flask-SQLAlchemy applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,sqlalchemy,alembic,migrations,database\"\n---\n\n# Flask-Migrate Python Package Guide\n\n## Golden Rule\n\nUse `Flask-Migrate` as the Flask CLI integration for Alembic. `flask db migrate` only generates a revision file; review that file, then run `flask db upgrade` to apply the change.\n\n## What It Does\n\n`Flask-Migrate` connects Alembic to Flask's CLI so your app can:\n\n- create a migrations repository\n- autogenerate migration scripts from SQLAlchemy metadata changes\n- upgrade, downgrade, stamp, inspect, and merge revisions\n- support app factories and Flask-SQLAlchemy multiple binds\n\nIt is normally used with `Flask-SQLAlchemy` and an initialized `SQLAlchemy` object.\n\n## Install\n\nPin the package version when you need behavior that matches this doc:\n\n```bash\npip install Flask-Migrate==4.1.0\n```\n\nTypical stack:\n\n```bash\npip install Flask Flask-SQLAlchemy Alembic Flask-Migrate==4.1.0\n```\n\nPyPI metadata for `4.1.0` declares `Requires: Python >=3.6`, but the practical floor in a real app can be higher because Flask, Flask-SQLAlchemy, SQLAlchemy, and your database driver may require newer Python versions.\n\n## Minimal Setup\n\nApplication factories are the safest default for new Flask apps:\n\n```python\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_migrate import Migrate\n\ndb = SQLAlchemy()\nmigrate = Migrate()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        SQLALCHEMY_DATABASE_URI=\"postgresql+psycopg://user:pass@localhost/app\",\n        SQLALCHEMY_TRACK_MODIFICATIONS=False,\n    )\n\n    db.init_app(app)\n    migrate.init_app(app, db)\n\n    return app\n\nclass User(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    email = db.Column(db.String(255), unique=True, nullable=False)\n```\n\nIf you do not use an app factory, constructing `Migrate(app, db)` directly is also supported:\n\n```python\nmigrate = Migrate(app, db)\n```\n\nMake sure the Flask CLI imports all models before migration commands run. If metadata is incomplete, autogenerate will miss tables or columns.\n\n## First Migration Workflow\n\nFor a module that exposes `app`:\n\n```bash\nflask --app app db init\nflask --app app db migrate -m \"create user table\"\nflask --app app db upgrade\n```\n\nFor an app factory:\n\n```bash\nflask --app 'myapp:create_app()' db upgrade\n```\n\nEquivalent environment-variable style from the official docs:\n\n```bash\nexport FLASK_APP=app.py\nflask db migrate -m \"add last_login to user\"\nflask db upgrade\n```\n\nCommit the generated `migrations/` directory. Alembic revision history belongs in source control.\n\n## Core Commands\n\n| Command | Use |\n| --- | --- |\n| `flask db init` | Create the Alembic migrations repository. |\n| `flask db migrate -m \"msg\"` | Autogenerate a new revision from detected model changes. |\n| `flask db upgrade [revision]` | Apply migrations up to a target revision, usually `head`. |\n| `flask db downgrade [-1\\|revision]` | Roll back one or more revisions. |\n| `flask db check` | Exit non-zero when autogenerate would produce a new migration; useful in CI. |\n| `flask db current` | Show the current database revision. |\n| `flask db history` | Show revision history. |\n| `flask db heads` | Show current head revisions. |\n| `flask db stamp <revision>` | Mark a revision without running migrations. |\n| `flask db merge` | Merge divergent heads. |\n| `flask db revision` | Create an empty or manually edited revision. |\n\n`flask db migrate` uses Alembic autogenerate, so treat the output as a draft and inspect it before applying it.\n\n## Configuration\n\n### `Migrate` options\n\nPass Alembic autogenerate options to `Migrate()` or `init_app()`:\n\n```python\nmigrate = Migrate(\n    app,\n    db,\n    directory=\"migrations\",\n    compare_type=True,\n    render_as_batch=True,\n)\n```\n\nImportant `4.x` defaults from the official docs:\n\n- `compare_type=True` is enabled by default, so type changes are detected automatically.\n- `render_as_batch=True` is enabled by default, which improves SQLite schema migrations by using batch mode.\n\n### Custom CLI group or migration directory\n\n```python\nMigrate(app, db, directory=\"db-migrations\", command=\"schema\")\n```\n\nThen run:\n\n```bash\nflask schema upgrade\n```\n\nYou can also override the directory with the `FLASK_DB_DIRECTORY` environment variable.\n\n### Alembic config callbacks\n\nUse `@migrate.configure` to modify the Alembic config object before commands run:\n\n```python\nfrom flask_migrate import Migrate\n\nmigrate = Migrate()\n\n@migrate.configure\ndef configure_alembic(config):\n    config.set_main_option(\"compare_type\", \"true\")\n    return config\n```\n\nThis is the hook for environment-driven config changes. If multiple callbacks are registered, their execution order is not guaranteed.\n\n## Multiple Databases And Custom Arguments\n\nFor Flask-SQLAlchemy binds, initialize the repository in multi-db mode from the start:\n\n```bash\nflask --app app db init --multidb\n```\n\nCustom Alembic arguments are passed with `-x` and can be consumed inside migration scripts:\n\n```bash\nflask --app app db upgrade -x tenant=acme\n```\n\nThe official docs note that all `flask db` commands accept `-x` arguments in the current `4.x` line. Read them from Alembic's context helpers inside your revision scripts instead of assuming Flask request globals exist.\n\n## Config And Secrets\n\n`Flask-Migrate` has no package-specific authentication layer. Database access comes from your Flask and SQLAlchemy configuration, typically by mapping environment variables into `SQLALCHEMY_DATABASE_URI` or related engine settings:\n\n```python\nimport os\n\napp.config[\"SQLALCHEMY_DATABASE_URI\"] = os.environ[\"DATABASE_URL\"]\n```\n\nTreat migration commands as privileged operations because they run with full schema-changing database credentials.\n\n## Common Pitfalls\n\n- `flask db migrate` creates a revision file but does not change the database until `flask db upgrade` runs.\n- Alembic autogenerate detects many schema changes, but it does not reliably infer table renames, column renames, or anonymously named constraints.\n- Review generated scripts before applying them, especially for data migrations, server defaults, and engine-specific DDL.\n- Import all models before running CLI commands or Alembic will compare incomplete metadata.\n- Use `flask db merge` for multiple heads instead of manually editing revision identifiers.\n- Batch mode makes SQLite development workflows smoother, but production behavior on PostgreSQL or MySQL can still differ.\n\n## Version-Sensitive Notes For `4.1.0`\n\n- PyPI currently lists `4.1.0` as the latest release for `flask-migrate`.\n- The maintainer changelog for `4.1.0` is short: it updates support for current Python and dependency versions, without documenting a new CLI surface.\n- `4.0.6` added `-x` support across all `db` commands and `--purge` support for `flask db stamp`.\n- `4.0.2` added `flask db check`, which is useful as a CI guard for missing migrations.\n- `4.0.0` changed defaults by enabling `compare_type=True` and `render_as_batch=True`.\n- The official Read the Docs site uses a rolling `/latest/` URL, so examples there can drift ahead of older pinned releases. For version-specific behavior, check the changelog alongside the docs.\n\n## Official Sources\n\n- Docs index: https://flask-migrate.readthedocs.io/en/latest/\n- Commands reference: https://flask-migrate.readthedocs.io/en/latest/#command-reference\n- PyPI package page: https://pypi.org/project/flask-migrate/\n- Maintainer changelog: https://raw.githubusercontent.com/miguelgrinberg/Flask-Migrate/main/CHANGES.md\n- Repository: https://github.com/miguelgrinberg/Flask-Migrate\n"
  },
  {
    "path": "content/flask/docs/opentelemetry/python/DOC.md",
    "content": "---\nname: opentelemetry\ndescription: \"OpenTelemetry Flask instrumentation for tracing Flask request handling, hooks, header capture, and OTLP export setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,opentelemetry,otel,tracing,observability,otlp\"\n---\n\n# OpenTelemetry Flask Instrumentation\n\n## Golden Rule\n\nConfigure a tracer provider and exporter first, then instrument the Flask app exactly once with `FlaskInstrumentor().instrument_app(app)`. Set `service.name` explicitly. Do not mix programmatic `instrument_app(app)` with separate global `FlaskInstrumentor().instrument()` patching on the same app object.\n\n## Install\n\nFor explicit in-app instrumentation:\n\n```bash\npython -m pip install \"Flask>=1.0\" \\\n  \"opentelemetry-instrumentation-flask==0.61b0\" \\\n  opentelemetry-sdk \\\n  opentelemetry-exporter-otlp-proto-http\n```\n\nFor zero-code or bootstrap-driven instrumentation:\n\n```bash\npython -m pip install \"Flask>=1.0\" opentelemetry-distro\nopentelemetry-bootstrap -a install\n```\n\nNotes:\n\n- `opentelemetry-instrumentation-flask` is a contrib instrumentation package, not the full SDK.\n- Keep OpenTelemetry packages on the same release train where practical. This package depends on matching contrib instrumentation components internally.\n- PyPI marks `0.61b0` as a beta pre-release. Pin if you need reproducible behavior.\n\n## Manual Setup For A Flask App\n\nThis is the safest pattern when you control app startup and want predictable instrumentation:\n\n```python\nfrom flask import Flask\n\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.instrumentation.flask import FlaskInstrumentor\nfrom opentelemetry.sdk.resources import SERVICE_NAME, Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\napp = Flask(__name__)\n\nresource = Resource.create(\n    {\n        SERVICE_NAME: \"orders-api\",\n    }\n)\n\ntrace_provider = TracerProvider(resource=resource)\ntrace_provider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(endpoint=\"http://localhost:4318/v1/traces\")\n    )\n)\ntrace.set_tracer_provider(trace_provider)\n\nFlaskInstrumentor().instrument_app(app, tracer_provider=trace_provider)\n\n@app.get(\"/healthz\")\ndef healthz():\n    return {\"ok\": True}\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\nWhat this package adds for Flask:\n\n- server spans around incoming requests\n- span names based on the Flask URL rule\n- `http.route` populated from the matched Flask route\n- request/response hooks for custom span attributes\n- optional SQLCommenter context enrichment for instrumented database stacks\n\n## Core Usage\n\n### Exclude noisy routes\n\nUse this for health checks, metrics endpoints, and other low-value traffic:\n\n```python\nFlaskInstrumentor().instrument_app(\n    app,\n    excluded_urls=\"healthz,metrics,/static/.*\",\n)\n```\n\nEquivalent environment variable:\n\n```bash\nexport OTEL_PYTHON_FLASK_EXCLUDED_URLS=\"healthz,metrics,/static/.*\"\n```\n\nYou can also use `OTEL_PYTHON_EXCLUDED_URLS` to apply exclusions across all Python instrumentations.\n\n### Add request and response hooks\n\nHooks let you attach app-specific attributes without manually managing spans:\n\n```python\nfrom opentelemetry.trace import Span\n\ndef request_hook(span: Span, environ) -> None:\n    if span and span.is_recording():\n        tenant_id = environ.get(\"HTTP_X_TENANT_ID\")\n        if tenant_id:\n            span.set_attribute(\"app.tenant_id\", tenant_id)\n\ndef response_hook(span: Span, status: str, response_headers) -> None:\n    if span and span.is_recording():\n        span.set_attribute(\"app.http_status_line\", status)\n\nFlaskInstrumentor().instrument_app(\n    app,\n    request_hook=request_hook,\n    response_hook=response_hook,\n)\n```\n\n### Capture selected headers\n\n```bash\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=\"x-request-id,user-agent\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=\"content-type\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=\".*session.*,set-cookie,authorization\"\n```\n\nImportant:\n\n- request header names are case-insensitive\n- response header names are case-insensitive\n- captured header attributes use normalized lowercase names with `-` changed to `_`\n- the header capture environment variable names are still experimental upstream\n\n### Enable SQLCommenter when you also instrument your DB stack\n\n```python\nFlaskInstrumentor().instrument_app(\n    app,\n    enable_commenter=True,\n    commenter_options={\n        \"controller\": False,\n    },\n)\n```\n\nThis only helps if your database driver or ORM instrumentation also supports SQLCommenter. Flask instrumentation enriches that downstream SQL comment with framework, route, and controller metadata.\n\n### Uninstrument in tests or app reinitialization code\n\n```python\nFlaskInstrumentor().uninstrument_app(app)\n```\n\nThis restores the original WSGI app wrapper and removes the registered Flask hooks. It is useful in test suites that reuse or rebuild the same app object.\n\n## Zero-Code Instrumentation\n\nIf you want automatic instrumentation around a Flask process without editing startup code:\n\n```bash\npython -m pip install \"Flask>=1.0\" opentelemetry-distro\nopentelemetry-bootstrap -a install\n\nexport OTEL_SERVICE_NAME=orders-api\nopentelemetry-instrument \\\n  --traces_exporter console \\\n  --metrics_exporter none \\\n  --logs_exporter none \\\n  python app.py\n```\n\nNotes:\n\n- `opentelemetry-bootstrap -a install` installs default and detected instrumentation packages for the current environment.\n- `opentelemetry-instrument` defaults to OTLP exporters unless you override exporters explicitly.\n- If you need to suppress Flask instrumentation in a larger auto-instrumented process, use `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=flask`.\n\n## Configuration And OTLP Auth\n\nOpenTelemetry backends usually need three things from you:\n\n1. A stable service identity\n2. An exporter endpoint\n3. Auth headers or collector-side auth\n\nCommon environment variables:\n\n```bash\nexport OTEL_SERVICE_NAME=orders-api\nexport OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=prod,service.namespace=payments\nexport OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>,x-tenant-id=acme\"\n```\n\nKey points:\n\n- `service.name` defaults to `unknown_service` if you do not set it, so set `OTEL_SERVICE_NAME` or create a `Resource` in code.\n- `OTEL_RESOURCE_ATTRIBUTES` is the usual place for deployment environment and other resource metadata.\n- The agent configuration docs map `exporter_otlp_endpoint` to `OTEL_EXPORTER_OTLP_ENDPOINT`.\n- Upstream docs note default collector endpoints of `0.0.0.0:4317` for gRPC and `0.0.0.0:4318` for HTTP when you do not override them.\n- `OTEL_EXPORTER_OTLP_HEADERS` is commonly required for vendor backends that expect API keys or bearer tokens.\n\n## Common Pitfalls\n\n- Do not expect this package to create spans in your backend by itself. You still need an SDK and exporter or zero-code distro setup.\n- Do not instrument the same app twice. The source warns if an app is already instrumented.\n- Prefer `instrument_app(app)` in normal Flask application code. `FlaskInstrumentor().instrument()` patches `flask.Flask` globally.\n- Set `OTEL_SERVICE_NAME` or an explicit `Resource`. Otherwise your service appears as `unknown_service`.\n- Be conservative with header capture. Capturing `.*` can leak secrets and produce high-cardinality attributes.\n- If you enable SQLCommenter, also enable it in the database instrumentation you actually use; Flask alone is not enough.\n- Excluded URL patterns are regexes matched against the request URL. Test them before using broad patterns in production.\n\n## Version-Sensitive Notes\n\n- `0.61b0` is the current PyPI release for this package as of March 12, 2026, and it is still a beta pre-release.\n- This release requires Python 3.9+.\n- The package metadata exposes an `instruments` extra that pulls in `flask >= 1.0`.\n- The package entry point name for disable-lists is `flask`, which is why `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=flask` works.\n- The header-capture environment variables are explicitly marked experimental in the upstream docs and may change across future contrib releases.\n"
  },
  {
    "path": "content/flask/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Flask 3.1.3 package guide for building and testing Python web applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"flask,python,web,wsgi,jinja,werkzeug\"\n---\n\n# Flask Python Package Guide\n\n## Install\n\nFlask 3.1.3 requires Python 3.9+.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"Flask==3.1.3\"\n```\n\nUseful extras:\n\n```bash\npip install \"Flask[dotenv]==3.1.3\"\npip install \"Flask[async]==3.1.3\"\n```\n\n- `dotenv` adds `.env` / `.flaskenv` loading support for the `flask` CLI.\n- `async` enables `async def` views and other async request hooks.\n\n## Minimal App\n\n```python\nfrom flask import Flask\n\napp = Flask(__name__)\n\n@app.get(\"/\")\ndef healthcheck():\n    return {\"ok\": True}\n```\n\nRun it with the CLI:\n\n```bash\nflask --app app run --debug\n```\n\nImportant:\n\n- Do not name your module `flask.py`; it conflicts with the package import.\n- Use `--app` unless your entry file is named `app.py` or `wsgi.py`.\n- Use `--debug` at startup rather than trying to flip `DEBUG` later in code.\n- The built-in server is for development only, not production.\n\n## Recommended App Factory Layout\n\nFor any non-trivial project, prefer an application factory and blueprints. This makes testing easier and avoids binding extension state too early.\n\n`myapp/__init__.py`\n\n```python\nfrom flask import Flask\n\ndef create_app(test_config: dict | None = None) -> Flask:\n    app = Flask(__name__, instance_relative_config=True)\n\n    app.config.from_mapping(\n        SECRET_KEY=\"dev-only-change-me\",\n        DATABASE_URL=\"sqlite:///app.db\",\n    )\n\n    if test_config:\n        app.config.update(test_config)\n    else:\n        app.config.from_prefixed_env()\n\n    from .views import bp\n    app.register_blueprint(bp)\n\n    return app\n```\n\n`myapp/views.py`\n\n```python\nfrom flask import Blueprint, current_app, jsonify\n\nbp = Blueprint(\"main\", __name__)\n\n@bp.get(\"/\")\ndef index():\n    return jsonify(\n        app_name=current_app.name,\n        debug=current_app.debug,\n    )\n```\n\nRun a factory app:\n\n```bash\nflask --app myapp:create_app run --debug\n```\n\nFlask will auto-detect a factory named `create_app` or `make_app`.\n\n## Core Request and Response Patterns\n\n### Route methods and path params\n\n```python\nfrom flask import Flask, abort, jsonify, request\n\napp = Flask(__name__)\n\n@app.get(\"/users/<int:user_id>\")\ndef get_user(user_id: int):\n    verbose = request.args.get(\"verbose\") == \"1\"\n\n    user = {\"id\": user_id, \"name\": \"Ada\"}\n    if not user:\n        abort(404)\n\n    if verbose:\n        user[\"debug\"] = {\"remote_addr\": request.remote_addr}\n\n    return jsonify(user)\n\n@app.post(\"/users\")\ndef create_user():\n    payload = request.get_json(force=False, silent=False)\n    if not payload or \"name\" not in payload:\n        abort(400)\n\n    return jsonify(id=123, name=payload[\"name\"]), 201\n```\n\nUse:\n\n- `request.args` for query parameters\n- `request.form` for HTML form fields\n- `request.files` for uploads\n- `request.get_json()` for JSON request bodies\n- `jsonify(...)` or dict return values for JSON responses\n- `abort(status_code)` for simple HTTP errors\n\n### Templates and static assets\n\n```python\nfrom flask import Flask, render_template\n\napp = Flask(__name__)\n\n@app.get(\"/hello/<name>\")\ndef hello(name: str):\n    return render_template(\"hello.html\", name=name)\n```\n\n- Templates live under `templates/`\n- Static files live under `static/`\n- `__name__` on the `Flask(...)` app tells Flask where to find those resources\n\n### Sessions\n\n```python\nfrom flask import Flask, redirect, session, url_for\n\napp = Flask(__name__)\napp.config[\"SECRET_KEY\"] = \"replace-in-production\"\n\n@app.post(\"/login\")\ndef login():\n    session[\"user_id\"] = 42\n    session.permanent = True\n    return redirect(url_for(\"me\"))\n\n@app.get(\"/me\")\ndef me():\n    return {\"user_id\": session.get(\"user_id\")}\n```\n\nFlask's built-in session uses a signed cookie, not a server-side session store. Keep session payloads small and non-sensitive.\n\n## Configuration and Secrets\n\nFlask configuration lives on `app.config`, which behaves like a dict.\n\n```python\napp.config.update(\n    TESTING=False,\n    SECRET_KEY=\"replace-me\",\n    TRUSTED_HOSTS=[\"example.com\", \".example.com\"],\n    MAX_CONTENT_LENGTH=16 * 1024 * 1024,\n    SESSION_COOKIE_SECURE=True,\n    SESSION_COOKIE_SAMESITE=\"Lax\",\n)\n```\n\nPrefer loading environment-driven config in the factory:\n\n```python\ndef create_app():\n    app = Flask(__name__)\n    app.config.from_prefixed_env()\n    return app\n```\n\nWith the default `FLASK_` prefix:\n\n```bash\nexport FLASK_SECRET_KEY=\"$(python -c 'import secrets; print(secrets.token_hex())')\"\nexport FLASK_MAIL_ENABLED=false\nflask --app myapp:create_app run --debug\n```\n\nKey config to know in 3.1.x:\n\n- `SECRET_KEY`: required for sessions, flash messages, and many extensions.\n- `SECRET_KEY_FALLBACKS`: lets you rotate signing keys without immediately invalidating active sessions.\n- `TRUSTED_HOSTS`: validates the incoming host header during routing. Use this instead of assuming `SERVER_NAME` will restrict hosts.\n- `MAX_CONTENT_LENGTH`: caps request body size.\n- `MAX_FORM_MEMORY_SIZE` and `MAX_FORM_PARTS`: new in 3.1 for multipart form limits.\n- `SESSION_COOKIE_SECURE`: send cookies only over HTTPS.\n- `SESSION_COOKIE_SAMESITE`: usually `\"Lax\"` unless cross-site behavior is required.\n- `SESSION_COOKIE_PARTITIONED`: new in 3.1 for embedded third-party cookie scenarios; enabling it also requires secure cookies.\n- `TESTING`: enable in tests so exceptions propagate and extensions switch into test-friendly behavior.\n\nAuth note:\n\n- Flask does not ship with a full authentication system.\n- Store auth provider secrets in config or environment, not inline in code.\n\n## Testing\n\nThe official docs recommend `pytest` and Flask's built-in test client / CLI runner.\n\n`tests/conftest.py`\n\n```python\nimport pytest\n\nfrom myapp import create_app\n\n@pytest.fixture()\ndef app():\n    app = create_app({\"TESTING\": True, \"SECRET_KEY\": \"test-secret\"})\n    yield app\n\n@pytest.fixture()\ndef client(app):\n    return app.test_client()\n\n@pytest.fixture()\ndef runner(app):\n    return app.test_cli_runner()\n```\n\n`tests/test_app.py`\n\n```python\nfrom flask import session\n\ndef test_index(client):\n    response = client.get(\"/\")\n    assert response.status_code == 200\n\ndef test_redirect_chain(client):\n    response = client.get(\"/logout\", follow_redirects=True)\n    assert response.status_code == 200\n    assert response.history\n\ndef test_modify_session(client):\n    with client.session_transaction() as sess:\n        sess[\"user_id\"] = 1\n\n    response = client.get(\"/me\")\n    assert response.json[\"user_id\"] == 1\n\ndef test_context_access(client):\n    with client:\n        client.post(\"/login\")\n        assert session[\"user_id\"] == 42\n```\n\nUseful testing primitives:\n\n- `app.test_client()` for HTTP requests without a live server\n- `follow_redirects=True` to assert on final redirected responses\n- `client.session_transaction()` to seed or inspect session state\n- `app.test_cli_runner()` for `@app.cli.command(...)` tests\n- `with app.app_context():` when testing code that needs `current_app`, database bindings, or extension state\n\n## Async Support\n\nFlask 3.1.3 supports async views and async request hooks if installed with the `async` extra.\n\n```python\nfrom flask import Flask, jsonify\n\napp = Flask(__name__)\n\n@app.get(\"/aggregate\")\nasync def aggregate():\n    result = await fetch_remote_data()\n    return jsonify(result)\n```\n\nImportant limitations:\n\n- Flask remains a WSGI framework.\n- One worker still handles one request/response cycle.\n- Async helps with concurrent IO inside a view, not with serving more requests per worker.\n- Do not spawn background tasks with `asyncio.create_task()` from a view; unfinished tasks are cancelled when the async view completes.\n\nIf most of your stack is async-first, or you need websockets and long-lived async workloads, an ASGI-native framework may be a better fit.\n\n## Deployment\n\nDo not deploy the development server.\n\nUse a production WSGI server or managed platform, for example:\n\n- Gunicorn\n- Waitress\n- mod_wsgi\n- uWSGI\n- gevent-based hosting\n\nCommon production concerns:\n\n- terminate TLS before Flask or at the reverse proxy\n- set `TRUSTED_HOSTS`\n- set secure cookie flags\n- configure body/form limits\n- if behind a proxy, configure proxy handling correctly before trusting forwarded headers\n\n## Common Pitfalls\n\n- Module named `flask.py`: breaks imports.\n- Missing `SECRET_KEY`: sessions and flash messages will not work correctly.\n- Late debug changes: `DEBUG` may behave inconsistently if changed after startup; use `flask --debug`.\n- Using `SERVER_NAME` as host protection: in 3.1 it no longer restricts requests to that domain; use `TRUSTED_HOSTS`.\n- Large uploads with no limits: set `MAX_CONTENT_LENGTH`, and for multipart forms also set `MAX_FORM_MEMORY_SIZE` and `MAX_FORM_PARTS`.\n- Assuming Flask sessions are encrypted server-side: they are signed cookies by default, so don't store secrets or large blobs in them.\n- Binding extensions directly inside module import paths: prefer `extension = Extension()` and `extension.init_app(app)` in the factory.\n- Copying old blog posts that use `FLASK_ENV` or `app.env`: those were removed in Flask 2.3.\n- Relying on `flask.__version__`: deprecated since 3.0. Use `importlib.metadata.version(\"flask\")`.\n\n## Version-Sensitive Notes for 3.1.3\n\n- `3.1.3` is the current PyPI release as of 2026-03-11.\n- `3.1.3` is a security-fix release and should not otherwise change behavior relative to the latest feature release.\n- `3.1.2` fixed async `stream_with_context` behavior and corrected session state when using `follow_redirects` in tests.\n- `3.1.1` fixed signing key selection order when `SECRET_KEY_FALLBACKS` is enabled.\n- `3.1.0` added `SECRET_KEY_FALLBACKS`, `TRUSTED_HOSTS`, `MAX_FORM_MEMORY_SIZE`, `MAX_FORM_PARTS`, and `SESSION_COOKIE_PARTITIONED`.\n- `3.1.0` also changed `SERVER_NAME` behavior so it no longer restricts incoming requests to that domain.\n\n## Official Sources\n\n- Flask installation: `https://flask.palletsprojects.com/en/stable/installation/`\n- Flask quickstart: `https://flask.palletsprojects.com/en/stable/quickstart/`\n- Flask configuration: `https://flask.palletsprojects.com/en/stable/config/`\n- Flask testing: `https://flask.palletsprojects.com/en/stable/testing/`\n- Flask async support: `https://flask.palletsprojects.com/en/stable/async-await/`\n- Flask application factories: `https://flask.palletsprojects.com/en/stable/patterns/appfactories/`\n- Flask deployment: `https://flask.palletsprojects.com/en/stable/deploying/`\n- Flask changelog: `https://flask.palletsprojects.com/en/stable/changes/`\n- Flask release page: `https://github.com/pallets/flask/releases/tag/3.1.3`\n- PyPI package: `https://pypi.org/project/Flask/`\n"
  },
  {
    "path": "content/flask/docs/restful/python/DOC.md",
    "content": "---\nname: restful\ndescription: \"Flask-RESTful package guide for building REST APIs on top of Flask\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.10\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"flask,rest,api,python,flask-restful\"\n---\n\n# Flask-RESTful Python Package Guide\n\n## What It Is\n\n`flask-restful` is a lightweight Flask extension for class-based REST resources, routing, request parsing, output marshalling, and API-specific error handling.\n\nUse it when a Flask codebase already wants Flask-style control over routing and app setup, but needs a cleaner resource layer than plain `@app.route` handlers.\n\n## Install\n\n```bash\npip install flask-restful\n```\n\nPin the version if the project depends on behavior from this release:\n\n```bash\npip install \"flask-restful==0.3.10\"\n```\n\n## Minimal Setup\n\n```python\nfrom flask import Flask\nfrom flask_restful import Api, Resource\n\napp = Flask(__name__)\napi = Api(app)\n\nclass Health(Resource):\n    def get(self):\n        return {\"status\": \"ok\"}\n\napi.add_resource(Health, \"/health\")\n\nif __name__ == \"__main__\":\n    app.run()\n```\n\nNotes:\n\n- `Resource` methods map to HTTP verbs (`get`, `post`, `put`, `delete`, and so on).\n- `Api.add_resource()` wires one resource to one or more URL rules.\n- Resource methods can return `data`, `(data, status_code)`, or `(data, status_code, headers)`.\n\n## Core Usage\n\n### Resource Routing And Named Endpoints\n\nUse named endpoints when you plan to generate links with `fields.Url`.\n\n```python\nfrom flask import Flask, request\nfrom flask_restful import Api, Resource, abort, fields, marshal_with\n\napp = Flask(__name__)\napi = Api(app)\n\nTODOS = {\n    1: {\"task\": \"ship docs\"},\n}\n\ntodo_fields = {\n    \"id\": fields.Integer,\n    \"task\": fields.String,\n    \"uri\": fields.Url(\"todo_item\", absolute=True),\n}\n\nclass TodoList(Resource):\n    def post(self):\n        payload = request.get_json() or {}\n        task = payload.get(\"task\")\n        if not task:\n            abort(400, message=\"task is required\")\n\n        todo_id = max(TODOS, default=0) + 1\n        TODOS[todo_id] = {\"task\": task}\n        return {\"id\": todo_id, **TODOS[todo_id]}, 201\n\nclass TodoItem(Resource):\n    @marshal_with(todo_fields)\n    def get(self, todo_id):\n        todo = TODOS.get(todo_id)\n        if todo is None:\n            abort(404, message=f\"todo {todo_id} does not exist\")\n        return {\"id\": todo_id, **todo}\n\napi.add_resource(TodoList, \"/todos\")\napi.add_resource(TodoItem, \"/todos/<int:todo_id>\", endpoint=\"todo_item\")\n```\n\n### Blueprints And App Factories\n\nFor larger apps, attach the API to a Flask blueprint and register that blueprint in your app factory.\n\n```python\nfrom flask import Blueprint, Flask\nfrom flask_restful import Api, Resource\n\napi_bp = Blueprint(\"api\", __name__, url_prefix=\"/api\")\napi = Api(api_bp)\n\nclass Ping(Resource):\n    def get(self):\n        return {\"ping\": \"pong\"}\n\napi.add_resource(Ping, \"/ping\")\n\ndef create_app():\n    app = Flask(__name__)\n    app.register_blueprint(api_bp)\n    return app\n```\n\nThe upstream guide explicitly shows blueprint registration as sufficient here; you do not need an extra `Api.init_app()` call when the `Api` is bound to the blueprint and the blueprint is registered on the app.\n\n### Output Marshalling\n\n`fields` and `marshal_with` are the built-in way to control response shape.\n\n```python\nfrom flask_restful import Resource, fields, marshal_with\n\nuser_fields = {\n    \"id\": fields.Integer,\n    \"username\": fields.String,\n    \"email\": fields.String,\n    \"links\": fields.Nested({\n        \"self\": fields.Url(\"user_detail\", absolute=True),\n    }),\n}\n\nclass UserDetail(Resource):\n    @marshal_with(user_fields)\n    def get(self, user_id):\n        return get_user(user_id)\n```\n\nUseful built-ins from the official docs:\n\n- `fields.String`, `fields.Integer`, `fields.Boolean`\n- `fields.DateTime`\n- `fields.Url` for relative or absolute URLs\n- `fields.Nested` and `fields.List` for nested response shapes\n\n## Input Validation\n\nFor new code, prefer normal Flask request handling plus a dedicated validation library such as Marshmallow or Pydantic.\n\n`reqparse` still works in `0.3.10`, but the official docs mark it as deprecated and say it is slated for removal in `2.0`.\n\nLegacy `reqparse` example:\n\n```python\nfrom flask_restful import Resource, reqparse\n\nparser = reqparse.RequestParser(bundle_errors=True)\nparser.add_argument(\"task\", type=str, required=True, location=\"json\")\nparser.add_argument(\"priority\", type=int, choices=range(1, 6), location=\"json\")\n\nclass TodoCreate(Resource):\n    def post(self):\n        args = parser.parse_args(strict=True)\n        return {\"task\": args[\"task\"], \"priority\": args.get(\"priority\", 1)}, 201\n```\n\nPractical notes:\n\n- `bundle_errors=True` returns all parser validation errors at once.\n- `app.config[\"BUNDLE_ERRORS\"] = True` makes that behavior global.\n- `strict=True` rejects unexpected request arguments.\n- The `help` parameter on arguments lets you customize validation messages.\n\n## Config And Auth\n\n### JSON Output Configuration\n\nFlask-RESTful uses Python's standard-library `json` module by default, not `flask.json`.\n\nYou can configure its serializer behavior through `RESTFUL_JSON`:\n\n```python\nclass Config:\n    RESTFUL_JSON = {\n        \"indent\": 2,\n        \"sort_keys\": False,\n    }\n```\n\nIn debug mode, Flask-RESTful will add pretty-print defaults unless you set them explicitly.\n\nIf your app depends on Flask's custom JSON behavior, replace the default representation with your own `@api.representation(\"application/json\")` function.\n\n### Authentication Hooks\n\nFlask-RESTful does not ship its own auth system. The official extension point is resource decorators.\n\n```python\nfrom functools import wraps\nfrom flask_restful import Resource, abort\n\ndef require_token(fn):\n    @wraps(fn)\n    def wrapper(*args, **kwargs):\n        token = extract_bearer_token()\n        if not is_valid_token(token):\n            abort(401, message=\"authentication required\")\n        return fn(*args, **kwargs)\n    return wrapper\n\nclass ProtectedResource(Resource):\n    method_decorators = [require_token]\n\n    def get(self):\n        return {\"ok\": True}\n```\n\nYou can also set `method_decorators` as a dict, such as `{\"get\": [cache_decorator]}`, to apply behavior only to selected HTTP methods.\n\n### API Error Handling\n\nTwo package-specific hooks matter in real services:\n\n- `Api(app, catch_all_404s=True)` lets Flask-RESTful format 404s as API errors instead of leaving them to default Flask HTML handling.\n- `Api(app, errors=errors)` lets you map exception names to response payloads and status codes.\n\nExample:\n\n```python\nfrom werkzeug.exceptions import HTTPException\n\nclass UserAlreadyExists(HTTPException):\n    pass\n\nerrors = {\n    \"UserAlreadyExists\": {\n        \"message\": \"A user with that username already exists.\",\n        \"status\": 409,\n    },\n}\n```\n\nIf you use the `errors=` mapping, the official docs note that custom exceptions must inherit from `HTTPException`.\n\n## Common Pitfalls\n\n- `reqparse` is legacy. Do not build new long-term API validation layers around it unless you are intentionally maintaining an older Flask-RESTful codebase.\n- The docs site is partly stale around installation details. An older installation page still lists Python `2.7` and `3.4` to `3.7`, while the `0.3.10` changelog adds Flask `2.3` compatibility and PyPI ships a `py2.py3` wheel. Verify your exact Python and Flask combination in CI.\n- `app.run(debug=True)` is only for local development. The official quickstart warns against using debug mode in production.\n- If `fields.Url` generates the wrong link, check the endpoint name passed to `add_resource(...)`.\n- If you expect Flask's JSON provider behavior, remember Flask-RESTful defaults to the standard `json` module.\n- If your API returns HTML 404 pages instead of JSON, check `catch_all_404s=True`.\n- If custom exceptions do not pick up your `errors=` mapping, make sure they derive from `werkzeug.exceptions.HTTPException`.\n\n## Version-Sensitive Notes For 0.3.10\n\n- PyPI lists `0.3.10` as released on `2023-05-21`.\n- The official changelog entry for `0.3.10` is small and specifically calls out compatibility with Flask `2.3`.\n- The official request parsing docs still describe `reqparse`, but also mark it deprecated in favor of better input/output packages.\n- The Read the Docs site identifies itself as `0.3.10` in the latest docs root, but some deeper pages still resolve under older or `master` URLs. Prefer `https://flask-restful.readthedocs.io/en/latest/` as the canonical docs root when linking or crawling.\n\n## Official Sources\n\n- Docs root: https://flask-restful.readthedocs.io/en/latest/\n- Quickstart: https://flask-restful.readthedocs.io/en/latest/quickstart.html\n- Request parsing: https://flask-restful.readthedocs.io/en/latest/reqparse.html\n- Output fields: https://flask-restful.readthedocs.io/en/latest/fields.html\n- Extending Flask-RESTful: https://flask-restful.readthedocs.io/en/latest/extending.html\n- Intermediate usage: https://flask-restful.readthedocs.io/en/latest/intermediate-usage.html\n- PyPI package: https://pypi.org/project/Flask-RESTful/\n- Source repository: https://github.com/flask-restful/flask-restful\n- Changelog: https://github.com/flask-restful/flask-restful/blob/master/CHANGES.md\n"
  },
  {
    "path": "content/flask/docs/restx/python/DOC.md",
    "content": "---\nname: restx\ndescription: \"Flask-RESTX package guide for Python REST APIs with namespaces, validation, and Swagger UI\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask-restx,flask,rest,api,swagger,openapi\"\n---\n\n# Flask-RESTX Python Package Guide\n\n## What It Is\n\n`flask-restx` is a Flask extension for class-based REST APIs with:\n\n- `Resource` handlers for HTTP verbs\n- `Namespace` composition for larger projects\n- model definitions plus response marshalling\n- request payload validation\n- generated Swagger UI and `swagger.json`\n- documented error handlers and auth metadata\n\nFor `1.3.2`, treat it as a stable Flask extension for Python `3.9+`. The current `1.3.x` line is also the compatibility boundary for modern Flask `3.x`.\n\n## Install\n\n```bash\npip install \"flask-restx==1.3.2\"\n```\n\nTypical setup for a new project:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"flask>=2\" \"flask-restx==1.3.2\"\n```\n\nIf you need a reproducible lockfile, pin both Flask and Flask-RESTX together. Upstream notes that `>=1.3.0` is the line that supports Flask `>=2.0.0`, including Flask `3.x`.\n\n## Minimal Setup\n\nUse `Api(app)` for a small app or `Api().init_app(app)` for an app factory.\n\n```python\nfrom flask import Flask\nfrom flask_restx import Api, Resource, fields\n\napp = Flask(__name__)\napp.config[\"RESTX_VALIDATE\"] = True\n\napi = Api(\n    app,\n    version=\"1.0\",\n    title=\"Todo API\",\n    description=\"Small example API\",\n    doc=\"/docs\",\n)\n\nns = api.namespace(\"todos\", path=\"/todos\", description=\"Todo operations\")\n\ntodo_input = api.model(\n    \"TodoInput\",\n    {\n        \"title\": fields.String(required=True, description=\"Short task title\"),\n        \"done\": fields.Boolean(required=True, description=\"Completion flag\"),\n    },\n)\n\ntodo_model = api.inherit(\n    \"Todo\",\n    todo_input,\n    {\n        \"id\": fields.Integer(readonly=True, description=\"Server-assigned ID\"),\n    },\n)\n\nTODOS = [{\"id\": 1, \"title\": \"Ship docs\", \"done\": False}]\n\n@ns.route(\"/\")\nclass TodoList(Resource):\n    @ns.marshal_list_with(todo_model)\n    def get(self):\n        return TODOS\n\n    @ns.expect(todo_input, validate=True)\n    @ns.marshal_with(todo_model, code=201)\n    def post(self):\n        payload = api.payload\n        item = {\n            \"id\": len(TODOS) + 1,\n            \"title\": payload[\"title\"],\n            \"done\": payload[\"done\"],\n        }\n        TODOS.append(item)\n        return item, 201\n\n@ns.route(\"/<int:todo_id>\")\n@ns.response(404, \"Todo not found\")\nclass TodoItem(Resource):\n    @ns.marshal_with(todo_model)\n    def get(self, todo_id):\n        for item in TODOS:\n            if item[\"id\"] == todo_id:\n                return item\n        api.abort(404, f\"Todo {todo_id} not found\")\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\nImportant behavior:\n\n- Swagger UI is served from `/docs` here; by default it is served from the API root.\n- Flask-RESTX also exposes the generated schema through `api.__schema__`.\n- `api.payload` gives you the parsed JSON body after `@api.expect(...)`.\n\n## App Factory and Blueprints\n\nUse `Api()` plus `init_app()` when the Flask app is created later:\n\n```python\nfrom flask import Flask\nfrom flask_restx import Api\n\napi = Api(\n    version=\"1.0\",\n    title=\"Example API\",\n    description=\"Factory-based app\",\n    doc=\"/docs\",\n)\n\ndef create_app():\n    app = Flask(__name__)\n    api.init_app(app)\n    return app\n```\n\nFor larger services, mount the API on a blueprint:\n\n```python\nfrom flask import Blueprint\nfrom flask_restx import Api\n\napi_bp = Blueprint(\"api\", __name__, url_prefix=\"/api/v1\")\napi = Api(\n    api_bp,\n    title=\"Service API\",\n    version=\"1.0\",\n    description=\"Versioned API\",\n    doc=\"/docs\",\n)\n```\n\nThen register the blueprint:\n\n```python\napp.register_blueprint(api_bp)\n```\n\nWhen using blueprints:\n\n- `url_for()` endpoint names are prefixed with the blueprint name, for example `url_for(\"api.some_endpoint\")`\n- registering the blueprint is enough; you do not also call `api.init_app(app)`\n\n## Organizing Larger APIs\n\nThe upstream scaling guide uses one namespace module per surface and adds each namespace to a shared `Api`:\n\n```python\nfrom flask_restx import Api\n\nfrom .users import api as users_ns\nfrom .projects import api as projects_ns\n\napi = Api(title=\"My API\", version=\"1.0\", description=\"Service API\")\napi.add_namespace(users_ns, path=\"/users\")\napi.add_namespace(projects_ns, path=\"/projects\")\n```\n\nThis is the default pattern to use when the API grows beyond one file or when you need multiple versioned blueprints.\n\n## Core Usage Patterns\n\n### Models and marshalling\n\nUse `api.model()`, `api.inherit()`, `@marshal_with()`, and `@marshal_list_with()` to keep response shapes explicit and documented.\n\n```python\nproject_model = api.model(\n    \"Project\",\n    {\n        \"id\": fields.Integer(required=True),\n        \"name\": fields.String(required=True),\n        \"owner_name\": fields.String(attribute=\"owner.display_name\"),\n        \"url\": fields.Url(\"project_detail\", absolute=True),\n    },\n)\n```\n\nUseful details:\n\n- only declared fields are serialized\n- `attribute=` remaps object attributes or dict keys\n- `fields.Nested(...)` and `fields.List(fields.Nested(...))` document structured output\n- `fields.Url(...)` builds URLs from endpoint names\n- `ordered=True` on `Api`, `Namespace`, or `marshal()` preserves field order\n\n### Request validation\n\nFor JSON request bodies, prefer model-based validation:\n\n```python\ncreate_user = api.model(\n    \"CreateUser\",\n    {\n        \"email\": fields.String(required=True),\n        \"active\": fields.Boolean(required=True),\n    },\n)\n\n@ns.route(\"/users\")\nclass UserList(Resource):\n    @ns.expect(create_user, validate=True)\n    def post(self):\n        payload = api.payload\n        return payload, 201\n```\n\nValidation can be enabled in three places:\n\n- per endpoint with `@api.expect(model, validate=True)`\n- globally with `app.config[\"RESTX_VALIDATE\"] = True`\n- globally with `Api(..., validate=True)`\n\n### `reqparse` still exists, but treat it as legacy\n\nOfficial docs mark the request-parser system as deprecated and say it is maintained only until `2.0`. Keep it for older codebases, query/header/file parsing, or very small forms, but do not build new large validation flows around it.\n\n```python\nfrom flask_restx import reqparse\n\nparser = reqparse.RequestParser(bundle_errors=True)\nparser.add_argument(\"page\", type=int, location=\"args\")\nparser.add_argument(\"picture\", location=\"files\")\n```\n\nIf you keep using `reqparse`:\n\n- `strict=True` on `parse_args()` rejects unknown inputs\n- `BUNDLE_ERRORS = True` returns all parser errors instead of only the first one\n- if `location=[\"headers\", ...]` is used, header names must match title case\n\n## Docs, Auth, and Configuration\n\nFlask-RESTX generates Swagger UI plus a `swagger.json`-style schema from routes, models, decorators, and namespaces.\n\nDocument auth schemes with `authorizations` and `security`:\n\n```python\nauthorizations = {\n    \"apikey\": {\n        \"type\": \"apiKey\",\n        \"in\": \"header\",\n        \"name\": \"X-API-Key\",\n    }\n}\n\napi = Api(\n    app,\n    authorizations=authorizations,\n    security=\"apikey\",\n    doc=\"/docs\",\n)\n```\n\nPer-method overrides:\n\n```python\n@ns.route(\"/private\")\nclass PrivateResource(Resource):\n    @ns.doc(security=\"apikey\")\n    def get(self):\n        return {\"ok\": True}\n\n@ns.route(\"/public\")\nclass PublicResource(Resource):\n    @ns.doc(security=[])\n    def get(self):\n        return {\"ok\": True}\n```\n\nImportant caveat: these settings document security for Swagger UI, but they do not enforce authentication. You still need Flask auth middleware, decorators, or request checks.\n\nConfiguration keys worth checking before production rollout:\n\n- `RESTX_JSON`\n- `RESTX_VALIDATE`\n- `RESTX_MASK_HEADER`\n- `RESTX_MASK_SWAGGER`\n- `RESTX_INCLUDE_ALL_MODELS`\n- `BUNDLE_ERRORS`\n- `ERROR_404_HELP`\n- `SWAGGER_VALIDATOR_URL`\n- `SWAGGER_UI_DOC_EXPANSION`\n- `SWAGGER_UI_OPERATION_ID`\n- `SWAGGER_UI_REQUEST_DURATION`\n- `SWAGGER_UI_OAUTH_APP_NAME`\n- `SWAGGER_UI_OAUTH_CLIENT_ID`\n- `SWAGGER_UI_OAUTH_REALM`\n- `SWAGGER_SUPPORTED_SUBMIT_METHODS`\n\nDisable the built-in docs UI with:\n\n```python\napi = Api(app, doc=False)\n```\n\n## Error Handling\n\nWerkzeug `HTTPException` instances are serialized automatically. Use `@api.errorhandler` or namespace-level handlers when you need a structured API error shape.\n\n```python\nfrom werkzeug.exceptions import BadRequest\n\n@api.errorhandler(BadRequest)\ndef handle_bad_request(error):\n    return {\"message\": str(error), \"code\": \"bad_request\"}, 400\n```\n\nUseful behavior:\n\n- `api.abort(code, message, extra=\"value\")` adds extra keys to the response\n- namespace-level handlers override API-level handlers\n- `ERROR_INCLUDE_MESSAGE = False` removes the default `message` field\n\n## Common Pitfalls\n\n### The root endpoint is reserved early\n\nInitializing `Api` registers `/` even if you move Swagger UI to another path. If your app needs `/` for something else, register that route before creating `Api`, or mount the API on a blueprint/prefix.\n\n### Swagger docs are Swagger/OpenAPI 2-era, not OpenAPI 3-native\n\nThe official docs and generated schema use Swagger terminology such as `securityDefinitions` and `swagger.json`. If a tool expects OpenAPI 3 features directly, verify compatibility before generating clients from the schema.\n\n### `reqparse` is deprecated\n\nDo not start new complex validation layers with `reqparse`. Prefer model-based docs/validation plus a dedicated validation library if your payload rules are non-trivial.\n\n### Docs auth is documentation, not enforcement\n\n`authorizations`, `security`, and Swagger UI settings only describe auth to humans and tooling. They do not check headers or users for you.\n\n### The docs site version label is stale\n\nAs of `2026-03-12`, the official Read the Docs pages under `https://flask-restx.readthedocs.io/en/latest/` still render a `1.1.1.dev` title even though PyPI lists `1.3.2` as the latest release. Use PyPI and GitHub releases as the authoritative version source, and treat the docs site as a rolling usage guide.\n\n## Version-Sensitive Notes for `1.3.2`\n\nFor the requested version used here `1.3.2`:\n\n- PyPI shows `1.3.2` as the latest release on `2025-09-23`\n- Python requirement is still `>=3.9`\n- the `1.3.x` line remains the boundary for Flask `3.x` support\n\nOfficial `1.3.2` release notes add important detail beyond the older `1.3.0` compatibility jump:\n\n- fixes for Flask `3.1.0` test changes\n- migration away from `jsonschema.RefResolver` to the newer `referencing` library\n- a fix for nullable `fields.Nested` input validation\n- a thread lock around first-time schema construction\n\nIf you are upgrading older code:\n\n- jumping from `1.2.0` to `1.3.x` is the important compatibility step for Flask `3.x`\n- jumping from `1.3.0` to `1.3.2` is mostly about bug fixes and runtime/schema robustness\n\n## Migration Notes\n\nIf the codebase still uses Flask-RESTPlus, the official quickstart says Flask-RESTX kept API compatibility and the normal migration is:\n\n- replace `flask_restplus` imports with `flask_restx`\n- rename config keys from `RESTPLUS_...` to `RESTX_...`\n- retest validation, error responses, and generated docs\n\n## Official Sources\n\n- Docs root: https://flask-restx.readthedocs.io/en/latest/\n- Quick start: https://flask-restx.readthedocs.io/en/latest/quickstart.html\n- Swagger docs: https://flask-restx.readthedocs.io/en/latest/swagger.html\n- Request parsing: https://flask-restx.readthedocs.io/en/latest/parsing.html\n- Error handling: https://flask-restx.readthedocs.io/en/latest/errors.html\n- Configuration: https://flask-restx.readthedocs.io/en/latest/configuration.html\n- Scaling patterns: https://flask-restx.readthedocs.io/en/latest/scaling.html\n- PyPI package: https://pypi.org/project/flask-restx/\n- GitHub repo: https://github.com/python-restx/flask-restx\n- GitHub releases: https://github.com/python-restx/flask-restx/releases\n"
  },
  {
    "path": "content/flask/docs/security-too/python/DOC.md",
    "content": "---\nname: security-too\ndescription: \"Flask-Security-Too package guide for Flask authentication, authorization, registration, and MFA\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.7.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,authentication,authorization,security,roles,mfa\"\n---\n\n# Flask-Security-Too Python Package Guide\n\n## What It Is\n\n`Flask-Security-Too` is the maintainer docs and PyPI line for the Flask extension that handles:\n\n- session login/logout\n- JSON and token-based authentication\n- role and permission checks\n- registration, email confirmation, password reset, password change, and email change\n- optional unified sign-in, MFA, WebAuthn/passkeys, and social login flows\n\nNaming matters:\n\n- Upstream docs now install with `Flask-Security`\n- Import root stays `flask_security`\n\nAs of **March 12, 2026**, the stable docs and PyPI both point at `5.7.1`.\n\n## Version And Source Notes\n\n- Package covered: `flask-security-too==5.7.1`\n- Docs root: `https://flask-security-too.readthedocs.io/en/stable/`\n- Registry URL: `https://pypi.org/project/flask-security-too/`\n- Python requirement on PyPI: `>=3.10`\n- The official quickstart still centers the SQLAlchemy integration and the `fsqla_v3` model mixins.\n\n## Install\n\nThe upstream docs now show the preferred package name:\n\n```bash\npip install \"Flask-Security[fsqla,common]==5.7.1\"\n```\n\nIf your lockfile or dependency list still uses the older package name, keep the import path the same:\n\n```bash\npip install \"Flask-Security-Too[fsqla,common]==5.7.1\"\n```\n\nCommon companion packages:\n\n```bash\npip install \"Flask-SQLAlchemy>=3,<4\"\npip install \"Flask-WTF>=1.1\"\n```\n\nNotes:\n\n- `fsqla` enables the Flask-SQLAlchemy datastore helpers and model mixins.\n- `common` pulls in the password-hashing support used by the default setup.\n- `5.7.1` is on the argon2-default line, so do not assume older bcrypt-only deployments will behave the same without migration planning.\n\n## Minimal Setup\n\nThis is the fastest correct starting point for a server-rendered Flask app with API endpoints.\n\n```python\nimport os\n\nfrom flask import Flask, jsonify\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_security import (\n    Security,\n    SQLAlchemyUserDatastore,\n    auth_required,\n    current_user,\n    hash_password,\n    roles_required,\n)\nfrom flask_security.models import fsqla_v3 as fsqla\n\napp = Flask(__name__)\napp.config.update(\n    SECRET_KEY=os.environ[\"SECRET_KEY\"],\n    SECURITY_PASSWORD_SALT=os.environ[\"SECURITY_PASSWORD_SALT\"],\n    SQLALCHEMY_DATABASE_URI=\"sqlite:///app.db\",\n    SQLALCHEMY_TRACK_MODIFICATIONS=False,\n    SESSION_COOKIE_HTTPONLY=True,\n    SESSION_COOKIE_SAMESITE=\"Lax\",\n    REMEMBER_COOKIE_HTTPONLY=True,\n    REMEMBER_COOKIE_SAMESITE=\"Lax\",\n)\n\ndb = SQLAlchemy(app)\nfsqla.FsModels.set_db_info(db)\n\nclass Role(db.Model, fsqla.FsRoleMixin):\n    pass\n\nclass User(db.Model, fsqla.FsUserMixin):\n    pass\n\nuser_datastore = SQLAlchemyUserDatastore(db, User, Role)\nsecurity = Security(app, user_datastore)\n\n@app.get(\"/api/me\")\n@auth_required(\"session\", \"token\")\ndef me():\n    return jsonify(\n        id=current_user.id,\n        email=current_user.email,\n        active=current_user.active,\n    )\n\n@app.get(\"/admin\")\n@auth_required(\"session\", \"token\")\n@roles_required(\"admin\")\ndef admin():\n    return {\"ok\": True}\n\nwith app.app_context():\n    db.create_all()\n    if not user_datastore.find_user(email=\"admin@example.com\"):\n        user_datastore.create_user(\n            email=\"admin@example.com\",\n            password=hash_password(\"change-me-now\"),\n        )\n        db.session.commit()\n```\n\nRules to keep:\n\n- Set `SECRET_KEY` and `SECURITY_PASSWORD_SALT` from environment or secret storage.\n- Call `fsqla.FsModels.set_db_info(db)` before declaring `User` and `Role`.\n- Use `hash_password()` when creating users.\n- Prefer `@auth_required(...)` over raw Flask-Login decorators on protected routes.\n- Turn on `SESSION_COOKIE_SECURE` and `REMEMBER_COOKIE_SECURE` in production behind HTTPS.\n\n## Required Model Contract\n\nIf you use the built-in SQLAlchemy mixins, most fields come for free. If you customize models, keep these requirements.\n\nUser model:\n\n- primary key\n- `email` for the default identity flows\n- `password`\n- `active`\n- `fs_uniquifier`\n- relationship to roles\n\nRole model:\n\n- primary key\n- `name`\n- `description`\n\nIf you use permission decorators, roles also need a `permissions` field.\n\n`fs_uniquifier` is not optional boilerplate. It is used for session identity and token invalidation. Rotating it logs users out. If you want auth tokens to survive password changes, add `fs_token_uniquifier` and let Flask-Security use that for token generation.\n\n## Core Auth Patterns\n\n### Protect routes with Flask-Security decorators\n\n```python\nfrom flask_security import auth_required, current_user, permissions_required\n\n@app.get(\"/reports\")\n@auth_required(\"token\", \"session\")\n@permissions_required(\"report-read\")\ndef list_reports():\n    return {\"email\": current_user.email}\n```\n\nUse these decorators first:\n\n- `auth_required()`\n- `auth_token_required()`\n- `http_auth_required()`\n- `roles_required()` / `roles_accepted()`\n- `permissions_required()` / `permissions_accepted()`\n\nDo not use Flask-Login's `@login_required` as your primary protection layer here. You bypass Flask-Security's auth-method handling, freshness checks, and CSRF behavior.\n\n### JSON login and token auth\n\n`5.7.1` still supports mixed browser/API apps. By default, `SECURITY_API_ENABLED_METHODS` includes `session`, `token`, and `basic`.\n\nRequest a token from the login endpoint:\n\n```bash\ncurl -X POST \"http://localhost:5000/login?include_auth_token\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json\" \\\n  -d '{\"email\":\"admin@example.com\",\"password\":\"change-me-now\"}'\n```\n\nUse the returned token on protected endpoints:\n\n```bash\ncurl \"http://localhost:5000/api/me\" \\\n  -H \"Authentication-Token: <token>\"\n```\n\n## Configuration That Usually Matters First\n\n```python\napp.config.update(\n    SECRET_KEY=os.environ[\"SECRET_KEY\"],\n    SECURITY_PASSWORD_SALT=os.environ[\"SECURITY_PASSWORD_SALT\"],\n    SECURITY_PASSWORD_HASH=\"argon2\",\n    SECURITY_API_ENABLED_METHODS=[\"session\", \"token\", \"basic\"],\n    SECURITY_TOKEN_MAX_AGE=3600,\n    SECURITY_RETURN_GENERIC_RESPONSES=True,\n    SECURITY_EMAIL_VALIDATOR_ARGS={\"check_deliverability\": False},\n    SECURITY_REGISTERABLE=True,\n    SECURITY_CONFIRMABLE=True,\n    SECURITY_RECOVERABLE=True,\n    SECURITY_CHANGEABLE=True,\n    SECURITY_CHANGE_EMAIL=True,\n)\n```\n\nWhy these are the high-value knobs:\n\n- `SECURITY_PASSWORD_SALT` is required for the default password/token behavior.\n- `SECURITY_PASSWORD_HASH=\"argon2\"` makes migrations explicit in code and tests.\n- `SECURITY_TOKEN_MAX_AGE` prevents indefinitely valid auth tokens.\n- `SECURITY_RETURN_GENERIC_RESPONSES=True` reduces user-enumeration leakage on auth endpoints.\n- `SECURITY_REGISTERABLE`, `SECURITY_CONFIRMABLE`, `SECURITY_RECOVERABLE`, `SECURITY_CHANGEABLE`, and `SECURITY_CHANGE_EMAIL` control the common account-management flows.\n- `SECURITY_EMAIL_VALIDATOR_ARGS={\"check_deliverability\": False}` is useful in tests or seeded local environments.\n\nIf you enable mail-driven flows, wire up your Flask mail extension and sender settings before testing signup, confirmation, or recovery.\n\n## CSRF, Sessions, And API Clients\n\nThe official mixed-app pattern is:\n\n```python\nimport flask_wtf\n\napp.config[\"WTF_CSRF_CHECK_DEFAULT\"] = False\napp.config[\"SECURITY_CSRF_PROTECT_MECHANISMS\"] = [\"session\", \"basic\"]\nflask_wtf.CSRFProtect(app)\n```\n\nPractical rules:\n\n- Keep CSRF enabled for browser session flows.\n- Send the CSRF token header on JSON requests that still rely on the session cookie.\n- Do not expect token-auth requests to need the same CSRF treatment as session-cookie requests.\n- Put `@auth_required(...)` on endpoints that need Flask-Security to enforce the right mechanism.\n\n## Optional Feature Areas\n\nOnce the base login flow works, the upstream docs support these higher-level features:\n\n- registration and confirmation flows\n- email and username identity flows\n- password reset and password change\n- unified sign-in and newer register-form behavior\n- two-factor auth, passkeys/WebAuthn, and recovery codes\n- OAuth/social login integrations\n\nEnable one feature family at a time and test the generated views or JSON responses before combining several of them.\n\n## Common Pitfalls\n\n- Confusing install name and import name. Install may be `Flask-Security` or `Flask-Security-Too`; the import stays `flask_security`.\n- Forgetting `SECRET_KEY` or `SECURITY_PASSWORD_SALT`.\n- Protecting routes with Flask-Login decorators instead of Flask-Security decorators.\n- Creating custom models without `fs_uniquifier`.\n- Adding permission checks without a `permissions` field on roles.\n- Copying old bcrypt-era setup notes into an argon2-default deployment.\n- Overriding `Security.render_json` and assuming it returns a string; `5.7.1` changed that contract to return a `dict`.\n\n## Version-Sensitive Notes For `5.7.1`\n\n- `5.7.1` requires Python `>=3.10` according to PyPI metadata.\n- `5.7.1` changed `Security.render_json` to return a `dict` instead of a serialized string. Update custom subclasses and tests that assert the old behavior.\n- The maintainer quickstart now shows `Flask-Security[fsqla,common]` as the preferred install name, even though this guide tracks the `flask-security-too` PyPI package.\n- If you are upgrading from older `5.4.x` or earlier guidance, review the argon2 default, token freshness behavior, and newer registration/account-flow settings before reusing old snippets.\n\n## Official Sources Used\n\n- `https://flask-security-too.readthedocs.io/en/stable/`\n- `https://flask-security-too.readthedocs.io/en/stable/quickstart.html`\n- `https://flask-security-too.readthedocs.io/en/stable/configuration.html`\n- `https://flask-security-too.readthedocs.io/en/stable/patterns.html`\n- `https://flask-security-too.readthedocs.io/en/stable/models.html`\n- `https://flask-security-too.readthedocs.io/en/stable/features.html`\n- `https://flask-security-too.readthedocs.io/en/stable/changelog.html`\n- `https://pypi.org/project/flask-security-too/`\n"
  },
  {
    "path": "content/flask/docs/smorest/python/DOC.md",
    "content": "---\nname: smorest\ndescription: \"flask-smorest package guide for Python with Flask setup, Blueprint patterns, OpenAPI config, pagination, ETag, auth boundaries, and version-sensitive notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.46.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask-smorest,flask,marshmallow,openapi,rest,python\"\n---\n\n# flask-smorest Python Package Guide\n\n## What It Is\n\n`flask-smorest` is a Flask extension for building JSON REST APIs with:\n\n- Marshmallow-based request parsing and validation\n- Marshmallow-based response serialization\n- generated OpenAPI documentation\n- optional pagination helpers\n- optional ETag helpers for conditional requests\n\nThe main objects you use are:\n\n- `Api` to bind the extension to a Flask app\n- `Blueprint` to group routes and attach request and response metadata\n- decorators such as `@blp.arguments`, `@blp.response`, `@blp.paginate`, and `@blp.etag`\n- `abort(...)` for consistent JSON HTTP errors\n\n## Version Covered\n\n- Package: `flask-smorest`\n- Ecosystem: `pypi`\n- Import: `from flask_smorest import Api, Blueprint, abort`\n- Version covered: `0.46.2`\n- Python requirement: `>=3.9`\n- Registry URL: `https://pypi.org/project/flask-smorest/`\n- Docs root used for this guide: `https://flask-smorest.readthedocs.io/en/latest/`\n\nThe official docs root and PyPI both identify `0.46.2` as the current documented release.\n\n## Install\n\nPin the package version when you need behavior that matches this guide.\n\n```bash\npython -m pip install \"flask-smorest==0.46.2\"\n```\n\nFor current releases, assume a modern Flask stack:\n\n- `flask-smorest 0.46.2` requires Python `>=3.9`\n- `0.43.0` raised the floor to `Flask>=3.0.2` and `Werkzeug>=3.0.1`\n- `0.46.0` dropped marshmallow `<3.24.1`\n- `0.46.1` added marshmallow 4 support\n- `0.46.2` added Flask async support\n\n## Minimal Setup\n\n`flask-smorest` expects a Flask app, Marshmallow schemas, and routes organized around a `Blueprint`.\n\n```python\nfrom flask import Flask\nfrom flask.views import MethodView\nimport marshmallow as ma\nfrom flask_smorest import Api, Blueprint, abort\n\nclass ItemSchema(ma.Schema):\n    id = ma.fields.Int(dump_only=True)\n    name = ma.fields.Str(required=True)\n\nclass ItemQuerySchema(ma.Schema):\n    name = ma.fields.Str()\n\nITEMS = [\n    {\"id\": 1, \"name\": \"hammer\"},\n    {\"id\": 2, \"name\": \"nails\"},\n]\n\nblp = Blueprint(\n    \"items\",\n    __name__,\n    url_prefix=\"/items\",\n    description=\"Operations on items\",\n)\n\n@blp.route(\"/\")\nclass ItemsResource(MethodView):\n    @blp.arguments(ItemQuerySchema, location=\"query\")\n    @blp.response(200, ItemSchema(many=True))\n    def get(self, query_args):\n        if \"name\" not in query_args:\n            return ITEMS\n        return [item for item in ITEMS if item[\"name\"] == query_args[\"name\"]]\n\n    @blp.arguments(ItemSchema)\n    @blp.response(201, ItemSchema)\n    def post(self, item_data):\n        item = {\"id\": len(ITEMS) + 1, **item_data}\n        ITEMS.append(item)\n        return item\n\n@blp.route(\"/<int:item_id>\")\nclass ItemByIdResource(MethodView):\n    @blp.response(200, ItemSchema)\n    def get(self, item_id):\n        for item in ITEMS:\n            if item[\"id\"] == item_id:\n                return item\n        abort(404, message=\"Item not found\")\n\ndef create_app():\n    app = Flask(__name__)\n    app.config.update(\n        API_TITLE=\"Example API\",\n        API_VERSION=\"v1\",\n        OPENAPI_VERSION=\"3.0.2\",\n    )\n\n    api = Api(app)\n    api.register_blueprint(blp)\n    return app\n\napp = create_app()\n```\n\n## App Factory Pattern\n\nIf your project uses Flask's app factory pattern, initialize lazily:\n\n```python\nfrom flask import Flask\nfrom flask_smorest import Api\n\napi = Api()\n\ndef create_app():\n    app = Flask(__name__)\n    app.config.update(\n        API_TITLE=\"Example API\",\n        API_VERSION=\"v1\",\n        OPENAPI_VERSION=\"3.0.2\",\n    )\n    api.init_app(app)\n    api.register_blueprint(blp)\n    return app\n```\n\nUse `api.init_app(app)` when extension setup happens before the Flask app exists.\n\n## Core Usage Patterns\n\n### Parse Request Data With `@arguments`\n\n`@blp.arguments(...)` deserializes request data with a Marshmallow schema and injects the validated data into the view.\n\n```python\n@blp.arguments(ItemSchema)\ndef post(self, item_data):\n    ...\n```\n\nImportant defaults:\n\n- default location is `\"json\"`\n- validated data is passed as one positional `dict`\n- use `location=\"query\"` for query parameters\n- use `as_kwargs=True` if you want keyword arguments instead of one `dict`\n\n```python\n@blp.arguments(ItemQuerySchema, location=\"query\", as_kwargs=True)\ndef get(self, **filters):\n    ...\n```\n\nAllowed locations include `json`, `query`, `path`, `form`, `headers`, `cookies`, `files`, and `json_or_form`.\n\nYou can stack `@arguments(...)` decorators, but the order matters because it controls the order of injected parameters.\n\n### Control Unknown-Field Behavior Explicitly\n\nFor JSON and other nested body payloads, marshmallow's schema-level `Meta.unknown` setting is the reliable place to define whether unknown fields are rejected, excluded, or included.\n\n```python\nimport marshmallow as ma\n\nclass BaseSchema(ma.Schema):\n    class Meta:\n        unknown = ma.EXCLUDE\n```\n\nFor non-body locations such as query parameters, `flask-smorest` already uses `unknown=EXCLUDE` by default through its webargs integration.\n\n### Serialize Responses With `@response`\n\nUse `@blp.response(status_code, schema)` to keep return values and OpenAPI docs aligned.\n\n```python\n@blp.response(200, ItemSchema)\ndef get(self, item_id):\n    return load_item(item_id)\n\n@blp.response(204)\ndef delete(self, item_id):\n    delete_item(item_id)\n```\n\nUse `many=True` when returning lists:\n\n```python\n@blp.response(200, ItemSchema(many=True))\ndef get(self):\n    return list_items()\n```\n\nIf the view returns a real Flask or Werkzeug `Response`, `flask-smorest` leaves it unchanged and only uses the decorator for documentation.\n\nAvoid returning tuples with a different status code than the one documented by `@blp.response(...)`; it works at runtime, but it makes the generated OpenAPI spec inaccurate.\n\n### Document Alternative Flows\n\n`@blp.response(...)` should describe the normal success path. Use `@blp.alt_response(...)` for non-primary flows you still want in the spec.\n\n```python\n@blp.alt_response(401, description=\"Unauthorized\")\n@blp.alt_response(404, description=\"Item not found\")\n```\n\n### Use `abort(...)` For JSON Error Payloads\n\n`flask_smorest.abort(...)` raises an HTTP error and lets you attach structured details.\n\n```python\nabort(400, message=\"Invalid state transition\")\nabort(404, message=\"Item not found\")\n```\n\nValidation errors from request parsing also flow through the JSON error handler.\n\n## OpenAPI And Documentation Config\n\nYou must provide these settings, either through `app.config` or `Api(..., spec_kwargs=...)`:\n\n- `API_TITLE`\n- `API_VERSION`\n- `OPENAPI_VERSION`\n\nThe docs pages can also be served directly from the app:\n\n```python\napp.config.update(\n    API_TITLE=\"Example API\",\n    API_VERSION=\"v1\",\n    OPENAPI_VERSION=\"3.0.2\",\n    OPENAPI_URL_PREFIX=\"/docs\",\n    OPENAPI_JSON_PATH=\"openapi.json\",\n    OPENAPI_SWAGGER_UI_PATH=\"/swagger-ui\",\n    OPENAPI_SWAGGER_UI_URL=\"https://cdn.jsdelivr.net/npm/swagger-ui-dist/\",\n)\n```\n\nUseful notes:\n\n- `OPENAPI_URL_PREFIX` enables serving docs from the Flask app\n- `OPENAPI_JSON_PATH` controls the JSON spec route below that prefix\n- ReDoc, Swagger UI, and RapiDoc are supported if you set both a path and a script URL\n- `app.config` overrides overlapping `spec_kwargs`\n- `API_SPEC_OPTIONS` adds or overrides root OpenAPI document fields\n\nTo export the generated spec during deployment:\n\n```bash\nflask openapi print --format=json\nflask openapi write --format=json openapi.json\n```\n\nIf one Flask app hosts multiple APIs, `Api(config_prefix=\"V1_\")` lets each `Api` instance read a separate configuration namespace.\n\n### Custom OpenAPI Mappings\n\nIf your API uses custom Flask path converters or custom Marshmallow fields, register them before documenting routes and schemas:\n\n```python\napi.register_converter(MyConverter, converter_to_schema)\napi.register_field(MyField, \"string\", \"custom-format\")\n```\n\n## Auth And Security Boundaries\n\n`flask-smorest` does not implement authentication or authorization for you. Handle auth with your normal Flask stack, such as:\n\n- request hooks\n- custom decorators\n- Flask-Login\n- JWT or API-key middleware\n\nThen keep the generated spec honest:\n\n- document `401` and `403` with `@blp.alt_response(...)`\n- use `@blp.doc(...)` when the generated operation documentation needs extra auth metadata\n- use `api.spec.components...` when you need extra top-level OpenAPI components\n\nTreat auth as an application concern, not a `flask-smorest` feature.\n\n## Pagination\n\n`@blp.paginate()` helps standardize paged list endpoints.\n\n### Pagination In The View\n\n```python\n@blp.route(\"/\")\nclass ItemsResource(MethodView):\n    @blp.response(200, ItemSchema(many=True))\n    @blp.paginate()\n    def get(self, pagination_parameters):\n        pagination_parameters.item_count = len(ITEMS)\n        return ITEMS[\n            pagination_parameters.first_item:pagination_parameters.last_item\n        ]\n```\n\nDefault pagination parameters are effectively:\n\n```python\n{\"page\": 1, \"page_size\": 10, \"max_page_size\": 100}\n```\n\nWhen pagination is enabled, responses include an `X-Pagination` header with counts and page navigation data unless you customize or disable that behavior on the blueprint class.\n\n### Post-Pagination With A Pager\n\nIf the view returns a lazy collection or query object, pass a pager class to `@blp.paginate(...)` and let the decorator slice after the view returns.\n\n## ETag Support\n\n`@blp.etag` enables conditional request support, but mutation protection is not fully automatic.\n\n```python\n@blp.route(\"/<int:item_id>\")\n@blp.etag\nclass ItemByIdResource(MethodView):\n    @blp.response(200, ItemSchema)\n    def get(self, item_id):\n        return load_item(item_id)\n\n    @blp.arguments(ItemSchema)\n    @blp.response(200, ItemSchema)\n    def put(self, item_data, item_id):\n        item = load_item(item_id)\n        blp.check_etag(item, ItemSchema)\n        item.update(item_data)\n        return item\n```\n\nImportant behavior:\n\n- `ETAG_DISABLED` disables ETag support globally\n- GET and HEAD responses can derive ETags from serialized response data\n- PUT, PATCH, and DELETE handlers must call `blp.check_etag(...)` themselves\n- if you forget `check_etag(...)`, `flask-smorest` warns at runtime\n- `blp.set_etag(...)` lets you compute ETags from arbitrary data instead of the response schema\n\n## Common Pitfalls\n\n- Missing `API_TITLE`, `API_VERSION`, or `OPENAPI_VERSION` breaks or weakens spec generation.\n- `@blp.arguments(...)` defaults to JSON body parsing. Query parameters need `location=\"query\"`.\n- `@blp.arguments(...)` passes one positional `dict` unless you opt into `as_kwargs=True`.\n- Stacked `@blp.arguments(...)` decorators inject parameters in decorator order.\n- For nested body schemas, configure unknown-field handling on the schema `Meta`; changing parser defaults does not propagate cleanly into nested schemas.\n- Returning a tuple with a different status code than the one documented by `@blp.response(...)` creates doc and runtime drift.\n- Returning a real `Response` bypasses schema dumping and the decorator's status-code behavior.\n- `@blp.etag` does not automatically enforce lost-update protection on writes; you still need `blp.check_etag(...)`.\n- Custom converters and custom Marshmallow fields should be registered before routes and schemas are documented.\n- The OpenAPI UI is not served unless you configure both the base prefix and the selected UI path and script URL.\n- Multipart requests with mixed body locations are not documented correctly; do not stack more than one request-body location on the same view.\n\n## Version-Sensitive Notes\n\n- `0.46.2` adds Flask async support. If you adopt async view functions, validate the behavior in your actual Flask deployment stack because most upstream examples are still synchronous.\n- `0.46.1` adds marshmallow 4 support.\n- `0.46.0` relies on marshmallow for schema ordering and drops marshmallow versions earlier than `3.24.1`.\n- `0.45.0` removed `flask_smorest.__version__`. If you need the installed package version at runtime, use `importlib.metadata.version(\"flask-smorest\")`.\n- `0.45.0` also officially supports Python 3.13 and drops Python 3.8.\n- `0.43.0` raised the minimum supported Flask and Werkzeug versions to `3.0.2` and `3.0.1`.\n\n## Official Sources\n\n- Docs root: `https://flask-smorest.readthedocs.io/en/latest/`\n- Quickstart: `https://flask-smorest.readthedocs.io/en/latest/quickstart.html`\n- Arguments guide: `https://flask-smorest.readthedocs.io/en/latest/arguments.html`\n- Response guide: `https://flask-smorest.readthedocs.io/en/latest/response.html`\n- Pagination guide: `https://flask-smorest.readthedocs.io/en/latest/pagination.html`\n- ETag guide: `https://flask-smorest.readthedocs.io/en/latest/etag.html`\n- OpenAPI guide: `https://flask-smorest.readthedocs.io/en/latest/openapi.html`\n- API reference: `https://flask-smorest.readthedocs.io/en/latest/api_reference.html`\n- Changelog: `https://flask-smorest.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/flask-smorest/`\n- Repository: `https://github.com/marshmallow-code/flask-smorest`\n"
  },
  {
    "path": "content/flask/docs/socketio/python/DOC.md",
    "content": "---\nname: socketio\ndescription: \"Flask-SocketIO package guide for Flask realtime apps, event handlers, rooms, auth, testing, and deployment\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.6.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask-socketio,flask,socketio,websocket,realtime,rooms,auth,gunicorn\"\n---\n\n# Flask-SocketIO Python Package Guide\n\n## What It Is\n\n`Flask-SocketIO` adds a Socket.IO server to a Flask application. Use it when you want Flask request and session integration plus realtime events, rooms, broadcasts, acknowledgements, and compatibility with Socket.IO clients.\n\nIf you do not need Flask integration, use `python-socketio` directly. If you are building a new ASGI-native app, compare it with FastAPI or Starlette plus the lower-level Socket.IO server.\n\n## Install\n\nPin the package version when you need the documented behavior exactly:\n\n```bash\npython -m pip install \"Flask-SocketIO==5.6.1\"\n```\n\nPick an async model deliberately instead of letting dependency auto-detection surprise you:\n\n```bash\n# Threaded worker with WebSocket support\npython -m pip install \"Flask-SocketIO==5.6.1\" simple-websocket gunicorn\n\n# gevent\npython -m pip install \"Flask-SocketIO==5.6.1\" gevent gevent-websocket gunicorn\n\n# eventlet\npython -m pip install \"Flask-SocketIO==5.6.1\" eventlet gunicorn\n```\n\nPractical guidance:\n\n- `threading` plus `simple-websocket` is the safest default when your app or dependencies do not tolerate green threads.\n- `gevent` is the preferred green-thread option in current upstream guidance.\n- `eventlet` still works, but upstream now calls out that it is not actively maintained.\n- If more than one async backend is installed, set `async_mode` explicitly so upgrades do not silently switch runtimes.\n\n## Initialize It Correctly\n\nUse an extension-style singleton and start the app with `socketio.run(app)` in local or simple deployments.\n\n```python\nfrom flask import Flask\nfrom flask_socketio import SocketIO\n\nsocketio = SocketIO(\n    cors_allowed_origins=[\"https://app.example.com\"],\n    async_mode=\"threading\",\n    logger=True,\n    engineio_logger=False,\n)\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = \"replace-me\"\n    socketio.init_app(app, manage_session=True)\n    return app\n\napp = create_app()\n\nif __name__ == \"__main__\":\n    socketio.run(app, debug=True)\n```\n\nImportant setup rules:\n\n- Set `SECRET_KEY` before initializing the extension if you rely on Flask sessions.\n- Prefer `socketio.init_app(app)` in app-factory projects.\n- Use `socketio.run(app)` instead of `flask run`; the Flask CLI server does not provide production WebSocket support for this package.\n- Keep `path=\"socket.io\"` unless your reverse proxy or client uses a custom Engine.IO path.\n\n## Core Event Patterns\n\n### Connect, authenticate, join rooms, and acknowledge work\n\n```python\nfrom flask import request, session\nfrom flask_socketio import emit, join_room\n\n@socketio.on(\"connect\")\ndef on_connect(auth):\n    user_id = session.get(\"user_id\")\n    token = (auth or {}).get(\"token\")\n\n    if not user_id and token != \"dev-token\":\n        return False\n\n    personal_room = f\"user:{user_id or request.sid}\"\n    join_room(personal_room)\n    emit(\"connected\", {\"sid\": request.sid, \"room\": personal_room})\n\n@socketio.on(\"chat:send\")\ndef on_chat_send(data):\n    room = data[\"room\"]\n    body = data[\"body\"]\n    emit(\"chat:message\", {\"body\": body}, to=room)\n    return {\"ok\": True}\n```\n\nWhat matters:\n\n- `connect(auth)` receives the optional auth payload sent by modern Socket.IO clients.\n- Returning `False` from `connect` rejects the connection.\n- `request.sid` is the connection id and the built-in personal room for that client.\n- Returning a value from a handler sends an acknowledgement payload to the client callback.\n- Use `to=room` for room broadcasts; omit it when replying only on the current namespace.\n\n### Emit outside a handler\n\nInside an event handler, use `emit()` or `send()`. Outside the event context, call methods on the `socketio` instance.\n\n```python\nfrom flask import request\n\n@socketio.on(\"jobs:start\")\ndef start_job(data):\n    room = request.sid\n    socketio.start_background_task(run_job, room, data)\n    return {\"started\": True}\n\ndef run_job(room: str, data: dict) -> None:\n    socketio.sleep(2)\n    socketio.emit(\"jobs:done\", {\"input\": data, \"result\": \"ok\"}, to=room)\n```\n\nUse `socketio.start_background_task()` and `socketio.sleep()` instead of raw thread or greenlet primitives. They adapt to the selected async backend.\n\n### Rooms and namespaces\n\n- Use `join_room()`, `leave_room()`, and `close_room()` for room lifecycle.\n- Keep room names application-defined and deterministic, such as `project:123` or `user:42`.\n- Only create custom namespaces when you need separate event surfaces or auth rules. Rooms are enough for most multitenant realtime features.\n\n## Config, Session, And Auth\n\nThe most important `SocketIO()` and `init_app()` options in real projects are:\n\n- `async_mode`: `threading`, `eventlet`, `gevent`, or `gevent_uwsgi`.\n- `cors_allowed_origins`: same-origin is the default; use an explicit allow-list in production.\n- `message_queue`: required for multi-process or multi-host broadcasting.\n- `logger` and `engineio_logger`: turn these on when debugging handshakes, transport upgrades, or disconnects.\n\n### Session semantics are not the same as HTTP\n\n- the Socket.IO side starts from the session state that existed when the connection was created\n- if a Socket.IO handler mutates `session`, later Socket.IO events see that change\n- normal Flask routes do not automatically see those Socket.IO-only mutations\n\nIf you use server-side sessions and avoid mutating the session inside Socket.IO handlers, later HTTP-side session updates can still be visible to Socket.IO handlers.\n\n### Auth patterns that work\n\nUse one of these patterns:\n\n- authenticate over normal Flask HTTP routes first, then read `session` or `current_user` in Socket.IO handlers\n- send an `auth` dictionary during the connection handshake and validate it in `connect`\n\nDo not use Flask route decorators such as `login_required` directly on Socket.IO event handlers. If you need handler-level enforcement, write a small decorator that checks `current_user.is_authenticated` and calls `disconnect()` when the client is unauthorized.\n\n## Deployment And Scaling\n\n### Embedded server\n\nFor local development or simple deployments:\n\n```python\nsocketio.run(app)\n```\n\nIf `eventlet` or `gevent` is installed, `socketio.run(app)` uses a production-capable server for that backend. Without them, it falls back to Flask's development server.\n\n### Gunicorn\n\nCurrent upstream deployment examples include:\n\n```bash\ngunicorn --worker-class eventlet -w 1 module:app\ngunicorn -k gevent -w 1 module:app\ngunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 module:app\ngunicorn -w 1 --threads 100 module:app\n```\n\nPractical guidance:\n\n- Keep Gunicorn at `-w 1` for a single Flask-SocketIO process; Gunicorn's normal load balancing is not compatible with Socket.IO's stickiness requirements.\n- Use the threaded worker plus `simple-websocket` when green threads are a poor fit.\n- Use `gevent-websocket` only when you specifically want Gunicorn plus gevent-based WebSocket handling.\n\n### Multiple workers or hosts\n\nHorizontal scaling needs both:\n\n- sticky sessions at the load balancer\n- a message queue such as Redis, RabbitMQ, or Kafka\n\nTypical Redis setup:\n\n```python\nsocketio = SocketIO(\n    app,\n    cors_allowed_origins=[\"https://app.example.com\"],\n    message_queue=\"redis://\",\n)\n```\n\nIf you use `eventlet` or `gevent` together with a queue client, patch early in process startup so queue I/O cooperates with the async runtime:\n\n```python\n# eventlet\nimport eventlet\neventlet.monkey_patch()\n```\n\n```python\n# gevent\nfrom gevent import monkey\nmonkey.patch_all()\n```\n\nApply monkey patching before imports that open sockets or initialize queue clients.\n\n## Testing\n\nUse the built-in Socket.IO test client. Pass Flask's test client when you need cookies or Flask session state to carry into the Socket.IO connection.\n\n```python\nfrom flask import Flask\nfrom flask_socketio import SocketIO\n\nsocketio = SocketIO()\n\ndef create_app():\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = \"test-secret\"\n    socketio.init_app(app)\n    return app\n\ndef test_ping_roundtrip():\n    app = create_app()\n\n    @socketio.on(\"ping\")\n    def handle_ping(data):\n        return {\"pong\": data[\"value\"]}\n\n    flask_client = app.test_client()\n    socket_client = socketio.test_client(app, flask_test_client=flask_client)\n\n    assert socket_client.is_connected()\n    assert socket_client.emit(\"ping\", {\"value\": 1}, callback=True) == {\"pong\": 1}\n    socket_client.disconnect()\n```\n\nUse `socketio.test_client()` instead of spinning up a real server for normal handler tests.\n\n## Common Pitfalls\n\n- `flask run` works for plain Flask routes, not for a production Flask-SocketIO server.\n- Installing multiple async backends without setting `async_mode` can change behavior between environments.\n- Running multiple Gunicorn workers without a message queue and sticky sessions causes missed broadcasts and broken rooms.\n- Emitting from background jobs or external workers requires the `socketio` object plus a configured `message_queue`; context-local `emit()` only works inside an event handler.\n- Cross-origin failures are often just missing `cors_allowed_origins` or a proxy that does not forward WebSocket upgrade headers.\n- Mixing blocking code with `eventlet` or `gevent` can stall the whole process. Use `threading` when your code or libraries are not green-thread-friendly.\n\n## Version-Sensitive Notes For 5.6.1\n\n- `5.6.1` is in the Flask-SocketIO `5.x` line and uses the newer Socket.IO / Engine.IO protocol generation documented in the upstream version-compatibility table. Pair it with modern JavaScript Socket.IO clients, not old `2.x` clients.\n- Upgrading from Flask-SocketIO `4.x` is not drop-in. The upstream upgrade guide calls out protocol and behavior changes, including explicit namespace connection behavior in newer Socket.IO clients.\n- The official docs root is `latest`, not a patch-pinned docs tree. For `5.6.1`, use the PyPI version plus the upgrade notes together when checking older examples from blogs or issue threads.\n- Current maintainer docs and PyPI metadata both require Python `3.8+`. Older `5.x` examples written for Python `3.6` or `3.7` are stale for `5.6.1`.\n\n## Official Sources\n\n- Docs root: https://flask-socketio.readthedocs.io/en/latest/\n- Introduction and version compatibility: https://flask-socketio.readthedocs.io/en/latest/intro.html\n- Getting started: https://flask-socketio.readthedocs.io/en/latest/getting_started.html\n- Implementation notes: https://flask-socketio.readthedocs.io/en/latest/implementation_notes.html\n- Deployment: https://flask-socketio.readthedocs.io/en/latest/deployment.html\n- API reference: https://flask-socketio.readthedocs.io/en/latest/api.html\n- Upgrade notes: https://flask-socketio.readthedocs.io/en/latest/upgrading.html\n- PyPI: https://pypi.org/project/Flask-SocketIO/\n- Repository: https://github.com/miguelgrinberg/Flask-SocketIO\n"
  },
  {
    "path": "content/flask/docs/sqlalchemy/python/DOC.md",
    "content": "---\nname: sqlalchemy\ndescription: \"Flask-SQLAlchemy extension guide for integrating SQLAlchemy 2.x with Flask applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,sqlalchemy,orm,database,python,web\"\n---\n\n# Flask-SQLAlchemy Python Guide\n\n## Install\n\nInstall the extension at the pinned version your project expects:\n\n```bash\npython -m pip install \"flask-sqlalchemy==3.1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"flask-sqlalchemy==3.1.1\"\npoetry add \"flask-sqlalchemy==3.1.1\"\n```\n\nFor schema migrations, add Alembic or Flask-Migrate separately. `db.create_all()` is useful for quickstarts, tests, and throwaway prototypes, but it is not a replacement for migrations in a real app.\n\n## Recommended App Factory Setup\n\nConfigure the app before calling `db.init_app(app)`. Flask-SQLAlchemy reads engine configuration during initialization and does not re-read it later.\n\n```python\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column\n\nclass Base(DeclarativeBase):\n    pass\n\ndb = SQLAlchemy(model_class=Base)\n\nclass User(db.Model):\n    id: Mapped[int] = mapped_column(primary_key=True)\n    username: Mapped[str] = mapped_column(unique=True)\n\ndef create_app() -> Flask:\n    app = Flask(__name__, instance_relative_config=True)\n    app.config.from_mapping(\n        SQLALCHEMY_DATABASE_URI=\"sqlite:///app.db\",\n        SQLALCHEMY_ENGINE_OPTIONS={\"pool_pre_ping\": True},\n    )\n\n    db.init_app(app)\n\n    with app.app_context():\n        db.create_all()\n\n    return app\n```\n\nImportant setup rules:\n\n- Define `db = SQLAlchemy(...)` once at module scope, then call `db.init_app(app)` inside the app factory.\n- Import or define all models before `db.create_all()` so SQLAlchemy knows which tables exist.\n- Prefer `model_class=Base` with SQLAlchemy 2.x typed mappings instead of older untyped model patterns.\n- Keep the database URL in config or environment variables, not inline in reusable library code.\n\n## Configuration\n\nAt least one of these must be configured before `init_app`:\n\n- `SQLALCHEMY_DATABASE_URI`\n- `SQLALCHEMY_BINDS`\n\nCommon config keys:\n\n- `SQLALCHEMY_DATABASE_URI`: default bind URL\n- `SQLALCHEMY_BINDS`: named extra engines for multi-database apps\n- `SQLALCHEMY_ENGINE_OPTIONS`: default `create_engine()` options for the default bind\n- `SQLALCHEMY_ECHO`: log SQLAlchemy statements for debugging\n- `SQLALCHEMY_RECORD_QUERIES`: enable query recording for inspection helpers\n- `SQLALCHEMY_TRACK_MODIFICATIONS`: enables model change signals\n\nExample environment-driven setup:\n\n```python\nimport os\n\napp.config[\"SQLALCHEMY_DATABASE_URI\"] = os.environ[\"DATABASE_URL\"]\napp.config[\"SQLALCHEMY_ENGINE_OPTIONS\"] = {\n    \"pool_pre_ping\": True,\n    \"pool_recycle\": 1800,\n}\napp.config[\"SQLALCHEMY_ECHO\"] = os.getenv(\"SQLALCHEMY_ECHO\", \"\").lower() == \"true\"\n```\n\nSQLite note:\n\n- `sqlite:///project.db` is relative to the Flask instance path, not necessarily the current working directory.\n\n## Models\n\nUse typed SQLAlchemy 2.x models. Flask-SQLAlchemy exposes `db.Model`, `db.session`, and helper metadata, but mapped columns and relationships are still standard SQLAlchemy.\n\n```python\nfrom __future__ import annotations\n\nfrom sqlalchemy import ForeignKey, String\nfrom sqlalchemy.orm import Mapped, mapped_column, relationship\n\nclass Author(db.Model):\n    id: Mapped[int] = mapped_column(primary_key=True)\n    name: Mapped[str] = mapped_column(String(120), unique=True)\n    books: Mapped[list[\"Book\"]] = relationship(back_populates=\"author\")\n\nclass Book(db.Model):\n    id: Mapped[int] = mapped_column(primary_key=True)\n    title: Mapped[str] = mapped_column(String(200))\n    author_id: Mapped[int] = mapped_column(ForeignKey(\"author.id\"))\n    author: Mapped[Author] = relationship(back_populates=\"books\")\n```\n\nUse `db.create_all()` only for initial table creation in simple setups:\n\n```python\nwith app.app_context():\n    db.create_all()\n```\n\nIt will not alter existing tables to match later model changes. Use migrations for that.\n\n## Core Query and Session Patterns\n\nFor new code, prefer `select()` and `db.session.execute()` / `db.session.scalars()` over the legacy query interface.\n\nInsert and commit:\n\n```python\nauthor = Author(name=\"Octavia Butler\")\ndb.session.add(author)\ndb.session.commit()\n```\n\nSelect rows:\n\n```python\nfrom sqlalchemy import select\n\nstmt = select(Author).order_by(Author.name)\nauthors = db.session.scalars(stmt).all()\n```\n\nFetch one row or fail with a 404 in a Flask view:\n\n```python\nfrom flask import Blueprint\n\nbp = Blueprint(\"authors\", __name__)\n\n@bp.get(\"/authors/<int:author_id>\")\ndef get_author(author_id: int):\n    author = db.get_or_404(Author, author_id)\n    return {\"id\": author.id, \"name\": author.name}\n```\n\nRun a filtered scalar query and fail with 404:\n\n```python\nfrom sqlalchemy import select\n\nstmt = select(Author).where(Author.name == \"Octavia Butler\")\nauthor = db.one_or_404(stmt)\n```\n\nPagination:\n\n```python\nfrom sqlalchemy import select\n\npage = db.paginate(\n    select(Book).order_by(Book.title),\n    page=1,\n    per_page=20,\n    max_per_page=100,\n)\n\nfor book in page.items:\n    print(book.title)\n```\n\n`db.paginate()` is meant for request-driven list views and can read `page` and `per_page` from request args when called in a Flask request context.\n\n## Application Context Rules\n\nAccess to `db.session`, `db.engine`, and model queries requires an active Flask application context.\n\nTypical cases that need a context:\n\n- request handlers\n- CLI commands registered with Flask\n- startup or bootstrap code\n- tests\n\nManual context usage:\n\n```python\napp = create_app()\n\nwith app.app_context():\n    user_count = db.session.scalar(db.select(db.func.count()).select_from(User))\n```\n\nWithout a context, Flask-SQLAlchemy raises `RuntimeError: Working outside of application context.` Keep session work inside request handlers, CLI commands, or explicit `with app.app_context():` blocks.\n\nFor tests, create a real app fixture and push a context only around the test or fixture scope that needs DB access. Do not keep one global context alive for the entire test suite unless you understand the cleanup tradeoffs.\n\n## Multiple Databases With Binds\n\nUse binds when a model belongs to a different database than the default bind.\n\n```python\napp.config[\"SQLALCHEMY_DATABASE_URI\"] = \"postgresql+psycopg://app:secret@localhost/main\"\napp.config[\"SQLALCHEMY_BINDS\"] = {\n    \"meta\": \"sqlite:////tmp/meta.db\",\n    \"audit\": {\n        \"url\": \"postgresql+psycopg://app:secret@localhost/audit\",\n        \"pool_recycle\": 1200,\n    },\n}\n```\n\nBind a model to one of those engines:\n\n```python\nclass AuditLog(db.Model):\n    __bind_key__ = \"audit\"\n\n    id: Mapped[int] = mapped_column(primary_key=True)\n    event: Mapped[str]\n```\n\nImportant:\n\n- The bind key is attached when the model or table is defined.\n- Changing `__bind_key__` after definition does not move an existing table to a new engine.\n- Use `db.create_all(bind_key=\"audit\")` or `db.create_all()` inside an app context if you need Flask-SQLAlchemy to create tables for bound engines in simple setups.\n\n## Working With Raw SQL\n\nDrop to standard SQLAlchemy APIs when you need raw SQL or engine-level work:\n\n```python\nfrom sqlalchemy import text\n\nwith db.engine.begin() as conn:\n    conn.execute(text(\"INSERT INTO user (username) VALUES (:username)\"), {\"username\": \"ada\"})\n```\n\nUse `db.session` for ORM unit-of-work behavior. Use `db.engine` or `db.engines[\"bind_name\"]` for connection-level operations that should bypass the ORM session.\n\n## Common Pitfalls\n\n- Do not call `db.session`, `db.engine`, or query helpers outside an app context.\n- Do not set `SQLALCHEMY_DATABASE_URI`, binds, or engine options after `db.init_app(app)` and expect them to be picked up.\n- Do not rely on `db.create_all()` for schema migrations after your tables already exist.\n- Do not keep using `Model.query` or `session.query()` for new code just because older Flask examples still do.\n- Do not forget to import model modules before `db.create_all()` or your tables may not be registered.\n- Do not assume a SQLite URL is relative to the repo root; in Flask it is usually relative to the app instance path.\n- Do not mutate a model's `__bind_key__` after class creation and expect routing to change.\n\n## Version-Sensitive Notes\n\n- `3.1.0` adds the `model_class` parameter so you can provide your own SQLAlchemy 2.x declarative base and use fully typed mappings.\n- `3.1.0` also raises the minimum SQLAlchemy version to `2.0.16` and drops Python 3.7 support.\n- `3.0` changed session scoping to the current app context instead of thread-local behavior and removed the old default in-memory SQLite engine. New apps must configure a database URI or binds explicitly.\n- `3.1.1` deprecates the `__version__` attribute. Use `importlib.metadata.version(\"flask-sqlalchemy\")` if code needs the installed package version.\n- The stable Pallets changelog already shows a `3.1.2` entry, but PyPI and GitHub releases still show `3.1.1` as the latest published version on March 12, 2026. Do not assume `3.1.2` fixes are installed unless your environment proves it.\n\n## Current Official Sources\n\n- Docs root: `https://flask-sqlalchemy.palletsprojects.com/en/stable/`\n- Quickstart: `https://flask-sqlalchemy.palletsprojects.com/en/stable/quickstart/`\n- Config: `https://flask-sqlalchemy.palletsprojects.com/en/stable/config/`\n- Models: `https://flask-sqlalchemy.palletsprojects.com/en/stable/models/`\n- Queries: `https://flask-sqlalchemy.palletsprojects.com/en/stable/queries/`\n- Binds: `https://flask-sqlalchemy.palletsprojects.com/en/stable/binds/`\n- Contexts: `https://flask-sqlalchemy.palletsprojects.com/en/stable/contexts/`\n- Changelog: `https://flask-sqlalchemy.palletsprojects.com/en/stable/changes/`\n- PyPI: `https://pypi.org/project/flask-sqlalchemy/`\n"
  },
  {
    "path": "content/flask/docs/testing/python/DOC.md",
    "content": "---\nname: testing\ndescription: \"Flask-Testing 0.8.1 guide for unittest-style Flask application tests and live server tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,flask-testing,testing,unittest,test-client,live-server\"\n---\n\n# Flask-Testing for Flask Apps\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Flask-Testing==0.8.1\"\n```\n\nIf you use template/context/flashed-message assertions, make sure Flask signals are available. Those helpers require `blinker` to be importable.\n\n## Minimal `TestCase` Setup\n\n`TestCase` expects you to implement `create_app()` and return a configured Flask app.\n\n```python\nfrom flask import Flask, flash, jsonify, redirect, render_template, url_for\nfrom flask_testing import TestCase\n\nclass ViewTests(TestCase):\n    def create_app(self) -> Flask:\n        app = Flask(__name__)\n        app.config.update(\n            TESTING=True,\n            SECRET_KEY=\"test-secret\",\n            SERVER_NAME=\"localhost\",\n        )\n\n        @app.get(\"/\")\n        def index():\n            flash(\"ready\")\n            return render_template(\"index.html\", name=\"Ada\")\n\n        @app.get(\"/api\")\n        def api():\n            return jsonify(ok=True)\n\n        @app.get(\"/go\")\n        def go():\n            return redirect(url_for(\"index\"))\n\n        return app\n\n    def test_index(self) -> None:\n        response = self.client.get(\"/\")\n\n        self.assert200(response)\n        self.assert_template_used(\"index.html\")\n        self.assert_context(\"name\", \"Ada\")\n        self.assert_message_flashed(\"ready\")\n\n    def test_json(self) -> None:\n        response = self.client.get(\"/api\")\n\n        self.assert200(response)\n        assert response.json == {\"ok\": True}\n\n    def test_redirect(self) -> None:\n        response = self.client.get(\"/go\")\n\n        self.assert_redirects(response, url_for(\"index\"))\n```\n\nWhat `TestCase` gives you:\n\n- `self.app`: the Flask app returned by `create_app()`\n- `self.client`: the Flask test client\n- a pushed request context around each test method\n- a custom response class with a `response.json` convenience property\n- Flask-aware assertions such as `assert200`, `assert_template_used`, `assert_context`, and `assert_redirects`\n\nIn normal use, define `setUp()` and `tearDown()` like plain `unittest.TestCase` methods. You do not call `super().setUp()` or `super().tearDown()` for Flask-Testing's internal setup.\n\n## Core Assertions And Helpers\n\nCommon helpers from `TestCase`:\n\n- `assert200`, `assert404`, `assertStatus`\n- `assertRedirects` / `assert_redirects`\n- `assertTemplateUsed` / `assert_template_used`\n- `assertContext` / `assert_context`\n- `getContextVariable` / `get_context_variable`\n- `assertMessageFlashed` / `assert_message_flashed`\n\nThe package keeps both camelCase and snake_case aliases. Match the style already used in the codebase you are editing.\n\n### Template and context assertions\n\nThese helpers rely on Flask's template-rendered signal. If signals are unavailable, Flask-Testing raises a runtime error instead of silently passing.\n\nIf you want template assertions without paying template-render cost, set:\n\n```python\nclass FastTemplateTests(TestCase):\n    render_templates = False\n```\n\nWith `render_templates = False`, template rendering is skipped for the test case, so the response body from `render_template(...)` is not useful for HTML assertions. Use template/context assertions instead.\n\n### Redirect assertions\n\n`assert_redirects(response, location)` compares both the status code and the target URL. For `0.8.1`, the maintained source accepts these redirect status codes:\n\n- `301`\n- `302`\n- `303`\n- `305`\n- `307`\n\nPitfall:\n\n- `308` is not accepted by `assertRedirects()` in `0.8.1`, even though newer Flask and Werkzeug code may emit it.\n\nIf your app uses relative redirect locations, set `SERVER_NAME` in the test config so URL normalization stays predictable.\n\n## App Factory And Config Patterns\n\nKeep the app factory explicit and set testing config inside `create_app()`:\n\n```python\nfrom flask import Flask\nfrom flask_testing import TestCase\n\nclass MyTests(TestCase):\n    def create_app(self) -> Flask:\n        app = Flask(__name__)\n        app.config.update(\n            TESTING=True,\n            SECRET_KEY=\"test-secret\",\n            SQLALCHEMY_DATABASE_URI=\"sqlite://\",\n            WTF_CSRF_ENABLED=False,\n        )\n        return app\n```\n\nImportant config that frequently matters in tests:\n\n- `TESTING=True`: enables Flask testing behavior and better error propagation\n- `SECRET_KEY`: required for sessions and flashed messages\n- `SERVER_NAME`: helps with `url_for(..., _external=True)` and redirect assertions\n- extension-specific test settings such as `SQLALCHEMY_DATABASE_URI`, `MAIL_SUPPRESS_SEND`, or `WTF_CSRF_ENABLED`\n\nPitfall:\n\n- Older docs show patterns like `TESTING = True` or `SQLALCHEMY_DATABASE_URI = \"sqlite://\"` as class attributes. Flask-Testing does not automatically merge those into `app.config`; your `create_app()` implementation must do that itself, or your app factory must explicitly read from the test case object.\n\n## Database Setup Pattern\n\nThe official docs include a Flask-SQLAlchemy example. The practical pattern is:\n\n```python\nfrom flask_testing import TestCase\n\nfrom myapp import create_app, db\n\nclass DatabaseTests(TestCase):\n    def create_app(self):\n        app = create_app()\n        app.config.update(\n            TESTING=True,\n            SQLALCHEMY_DATABASE_URI=\"sqlite://\",\n        )\n        return app\n\n    def setUp(self):\n        db.create_all()\n\n    def tearDown(self):\n        db.session.remove()\n        db.drop_all()\n```\n\nUse a disposable database per test class or per test run. `self.client` requests execute real Flask request teardown behavior, so extension sessions may be removed between requests just like in the app itself.\n\n## Live Server Tests\n\nUse `LiveServerTestCase` when you need a real HTTP server instead of Flask's in-process test client. This is the path for browser-driven tests, external callbacks, or anything that must talk to an actual socket.\n\n```python\nfrom flask import Flask\nfrom flask_testing import LiveServerTestCase\nfrom urllib.request import urlopen\n\nclass LiveTests(LiveServerTestCase):\n    LIVESERVER_PORT = 0\n    LIVESERVER_TIMEOUT = 10\n\n    def create_app(self) -> Flask:\n        app = Flask(__name__)\n        app.config[\"TESTING\"] = True\n\n        @app.get(\"/\")\n        def index():\n            return \"ok\"\n\n        return app\n\n    def test_server_is_reachable(self) -> None:\n        response = urlopen(self.get_server_url())\n        assert response.status == 200\n```\n\nKey behavior:\n\n- `LIVESERVER_PORT = 0` asks the OS for a free port, which is safer for parallel runs\n- `get_server_url()` returns the actual base URL to call\n- `LIVESERVER_TIMEOUT` controls how long startup waits before failing\n- the live server runs in a separate process, so share test state through a real database or other externalized state, not in-memory globals\n\n## Common Pitfalls\n\n- Use `from flask_testing import TestCase`, not the legacy `flask.ext.testing` import path.\n- The docs site is stale; always cross-check version-sensitive behavior against PyPI and the maintainer repository.\n- Signal-based assertions require Flask signals. If they fail with a runtime error, check whether `blinker` is available in the environment.\n- `assertRedirects()` in `0.8.1` does not treat HTTP `308` as valid.\n- `render_templates = False` is good for speed but bad for asserting rendered HTML output.\n- `LiveServerTestCase` is not the same as Flask's test client; requests go through a real socket and process boundary.\n- Twill-related helpers in the old docs are effectively legacy paths. Prefer modern browser or HTTP tooling instead.\n\n## Version-Sensitive Notes\n\n- Public docs and changelog pages lag behind the `0.8.1` package published on PyPI.\n- The GitHub release UI is also behind PyPI for this package, so use PyPI for the latest published package version and GitHub source for exact helper behavior.\n- Flask-Testing is still centered on `unittest`. If the project is already strongly pytest-native, plain Flask fixtures or a pytest-focused plugin may fit better than wrapping everything in `TestCase`.\n"
  },
  {
    "path": "content/flask/docs/wtf/python/DOC.md",
    "content": "---\nname: wtf\ndescription: \"Flask-WTF form handling, CSRF protection, file uploads, and reCAPTCHA for Flask applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flask,flask-wtf,wtforms,forms,csrf,file-upload,recaptcha\"\n---\n\n# Flask-WTF Python Package Guide\n\n## Install\n\nPin the package to the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Flask-WTF==1.2.2\"\n```\n\nIf you use WTForms email validation, install the published extra:\n\n```bash\npython -m pip install \"Flask-WTF[email]==1.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Flask-WTF==1.2.2\"\npoetry add \"Flask-WTF==1.2.2\"\n```\n\n## Initialize In A Flask App\n\nUse Flask-WTF with an application factory and a real secret key. CSRF uses Flask's `SECRET_KEY` unless you set `WTF_CSRF_SECRET_KEY`.\n\n```python\nfrom flask import Flask\nfrom flask_wtf.csrf import CSRFProtect\n\ncsrf = CSRFProtect()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config.from_mapping(\n        SECRET_KEY=\"replace-in-production\",\n    )\n\n    csrf.init_app(app)\n\n    return app\n```\n\nImportant:\n\n- Any view that uses `FlaskForm` already gets CSRF handling for that form.\n- Register `CSRFProtect` when you also need to protect non-form POST/PUT/PATCH/DELETE endpoints or JavaScript requests.\n- Do not disable CSRF globally unless you have a narrow, explicit reason.\n\n## Define And Validate Forms\n\nImport fields and validators from `wtforms`, not from `flask_wtf`.\n\n```python\nfrom flask import Blueprint, redirect, render_template, url_for\nfrom flask_wtf import FlaskForm\nfrom wtforms import PasswordField, StringField, SubmitField\nfrom wtforms.validators import DataRequired, Email, Length\n\nbp = Blueprint(\"auth\", __name__)\n\nclass LoginForm(FlaskForm):\n    email = StringField(\"Email\", validators=[DataRequired(), Email()])\n    password = PasswordField(\"Password\", validators=[DataRequired(), Length(min=8)])\n    submit = SubmitField(\"Sign in\")\n\n@bp.route(\"/login\", methods=[\"GET\", \"POST\"])\ndef login():\n    form = LoginForm()\n\n    if form.validate_on_submit():\n        email = form.email.data\n        return redirect(url_for(\"auth.success\", email=email))\n\n    return render_template(\"login.html\", form=form)\n```\n\n`validate_on_submit()` is the common path. It is equivalent to checking that the request was submitted with a mutating HTTP method and then running `validate()`.\n\n## Render Forms In Templates\n\nRender the hidden CSRF field or use `hidden_tag()` to render all hidden fields in one place.\n\n```html\n<form method=\"post\" action=\"{{ url_for('auth.login') }}\">\n  {{ form.hidden_tag() }}\n\n  <div>\n    {{ form.email.label }}\n    {{ form.email() }}\n    {% for error in form.email.errors %}\n      <p>{{ error }}</p>\n    {% endfor %}\n  </div>\n\n  <div>\n    {{ form.password.label }}\n    {{ form.password() }}\n    {% for error in form.password.errors %}\n      <p>{{ error }}</p>\n    {% endfor %}\n  </div>\n\n  {{ form.submit() }}\n</form>\n```\n\nIf you forget the hidden CSRF field, `validate_on_submit()` will fail even though the form otherwise looks correct.\n\n## File Uploads\n\nUse Flask-WTF's file helpers instead of plain WTForms file fields when you want Flask-aware `FileStorage` handling and validators.\n\n```python\nfrom pathlib import Path\n\nfrom flask import Blueprint, current_app, redirect, render_template, url_for\nfrom flask_wtf import FlaskForm\nfrom flask_wtf.file import FileAllowed, FileField, FileRequired\nfrom werkzeug.utils import secure_filename\nfrom wtforms import SubmitField\n\nbp = Blueprint(\"uploads\", __name__)\n\nclass UploadForm(FlaskForm):\n    photo = FileField(\n        \"Photo\",\n        validators=[\n            FileRequired(),\n            FileAllowed([\"jpg\", \"jpeg\", \"png\", \"webp\"], \"Images only.\"),\n        ],\n    )\n    submit = SubmitField(\"Upload\")\n\n@bp.route(\"/upload\", methods=[\"GET\", \"POST\"])\ndef upload():\n    form = UploadForm()\n\n    if form.validate_on_submit():\n        storage = form.photo.data\n        filename = secure_filename(storage.filename)\n        destination = Path(current_app.instance_path) / \"uploads\" / filename\n        destination.parent.mkdir(parents=True, exist_ok=True)\n        storage.save(destination)\n        return redirect(url_for(\"uploads.upload\"))\n\n    return render_template(\"upload.html\", form=form)\n```\n\nTemplate requirement:\n\n```html\n<form method=\"post\" enctype=\"multipart/form-data\">\n  {{ form.hidden_tag() }}\n  {{ form.photo() }}\n  {{ form.submit() }}\n</form>\n```\n\nNotes:\n\n- `enctype=\"multipart/form-data\"` is required or `request.files` will be empty.\n- If you manually instantiate a form with explicit request data, combine `request.files` and `request.form`; otherwise file fields will not populate.\n- `MultipleFileField` is available in the 1.2.x line when you need multiple uploads.\n- `FileRequired`, `FileAllowed`, and `FileSize` work with both single and multiple file fields in 1.2.x.\n\n## Global CSRF Protection For HTML And JavaScript Requests\n\nIf you submit requests outside a `FlaskForm`, protect them with `CSRFProtect` and send the token explicitly.\n\nServer setup:\n\n```python\nfrom flask import Flask, jsonify\nfrom flask_wtf.csrf import CSRFError, CSRFProtect\n\ncsrf = CSRFProtect()\n\ndef create_app() -> Flask:\n    app = Flask(__name__)\n    app.config[\"SECRET_KEY\"] = \"replace-in-production\"\n    csrf.init_app(app)\n\n    @app.errorhandler(CSRFError)\n    def handle_csrf_error(e):\n        return jsonify(error=\"csrf_failed\", reason=e.description), 400\n\n    return app\n```\n\nTemplate or page script for JavaScript requests:\n\n```html\n<script>\n  axios.defaults.headers.common[\"X-CSRFToken\"] = \"{{ csrf_token() }}\";\n</script>\n```\n\nRelevant defaults in 1.2.x:\n\n- `WTF_CSRF_ENABLED=True`\n- `WTF_CSRF_CHECK_DEFAULT=True`\n- `WTF_CSRF_METHODS={\"POST\", \"PUT\", \"PATCH\", \"DELETE\"}`\n- `WTF_CSRF_FIELD_NAME=\"csrf_token\"`\n- `WTF_CSRF_HEADERS=[\"X-CSRFToken\", \"X-CSRF-Token\"]`\n- `WTF_CSRF_TIME_LIMIT=3600`\n\nUse `WTF_CSRF_SECRET_KEY` if you want CSRF signing separated from your app `SECRET_KEY`.\n\n## Configuration\n\nCommon config you will actually use:\n\n```python\napp.config.update(\n    SECRET_KEY=\"replace-in-production\",\n    WTF_CSRF_SECRET_KEY=\"separate-csrf-key-if-needed\",\n    WTF_CSRF_TIME_LIMIT=3600,\n)\n```\n\nUseful rules:\n\n- `SECRET_KEY` is mandatory for normal form CSRF protection.\n- `WTF_CSRF_SECRET_KEY` is optional and overrides the signing key for CSRF tokens only.\n- `WTF_CSRF_CHECK_DEFAULT=False` is only for special flows where you call `csrf.protect()` selectively, such as preprocessing OAuth callbacks.\n- `WTF_CSRF_TIME_LIMIT=None` keeps a token valid for the life of the session.\n- CSRF failures are logged to the `flask_wtf.csrf` logger at `INFO`; configure logging if you want to see them.\n\n## Recaptcha\n\nFlask-WTF ships a `RecaptchaField` for server-side validation and widget rendering.\n\n```python\nfrom flask_wtf import FlaskForm, RecaptchaField\nfrom wtforms import SubmitField\n\nclass SignupForm(FlaskForm):\n    recaptcha = RecaptchaField()\n    submit = SubmitField(\"Create account\")\n```\n\nRequired config:\n\n```python\napp.config.update(\n    RECAPTCHA_PUBLIC_KEY=\"...\",\n    RECAPTCHA_PRIVATE_KEY=\"...\",\n)\n```\n\nThe config surface also includes `RECAPTCHA_PARAMETERS`, `RECAPTCHA_DATA_ATTRS`, `RECAPTCHA_SCRIPT`, `RECAPTCHA_DIV_CLASS`, and `RECAPTCHA_VERIFY_SERVER`, which matters if you need alternative captcha services or custom rendering.\n\n## Testing\n\nIf you are testing code that instantiates a form outside an active request, pass `formdata=None` explicitly so Flask-WTF does not try to read `request.form` and `request.files`.\n\nFor unit tests around CSRF-protected flows:\n\n- prefer Flask's test client for end-to-end form submissions\n- disable CSRF per-form with `meta={\"csrf\": False}` only in narrow test cases that are not exercising CSRF behavior\n- when you need the token directly, the API docs note that the signed token is available in `g.csrf_token` and the raw token in `session[\"csrf_token\"]` during testing\n\n## Common Pitfalls\n\n- Forgetting `SECRET_KEY` or setting it too late. CSRF and session-backed forms rely on it.\n- Forgetting `{{ form.hidden_tag() }}` or `{{ form.csrf_token }}` in the template.\n- Assuming Flask-WTF handles JSON APIs automatically. For JavaScript and non-form endpoints, register `CSRFProtect` and send the header token.\n- Disabling `WTF_CSRF_ENABLED` globally instead of exempting a narrow route or blueprint.\n- Importing fields from `flask_wtf` instead of `wtforms`.\n- Forgetting `multipart/form-data` for upload forms.\n- Passing only `request.form` when manually constructing an upload form.\n- Caching HTML pages longer than `WTF_CSRF_TIME_LIMIT`, which can surface expired-token errors from stale pages.\n- Expecting Flask-WTF to handle authentication. It handles forms, validation, CSRF, uploads, and reCAPTCHA, not login/session policy by itself.\n\n## Version-Sensitive Notes For 1.2.x\n\n- GitHub releases and PyPI both show `Flask-WTF 1.2.2` on October 24, 2024.\n- `1.2.2` moved the project to the `pallets-eco` GitHub organization.\n- `1.2.2` dropped Python 3.8 support and added Python 3.13 support; PyPI now lists `Requires: Python >=3.9`.\n- `1.2.1` fixed a bug where file validators could mutate file field content.\n- `1.2.0` added `MultipleFileField`, and the file validators (`FileRequired`, `FileAllowed`, `FileSize`) now support multiple files.\n- The versioned `1.2.x` docs are the right reference target for this package line. The floating `stable/latest` docs are fine for browsing but less precise for package-pinned work.\n- The Read the Docs changelog page is incomplete for the latest `1.2.x` releases, so use GitHub releases and PyPI when you need exact `1.2.1` / `1.2.2` release details.\n\n## Official Sources\n\n- Docs root: https://flask-wtf.readthedocs.io/en/1.2.x/\n- Installation: https://flask-wtf.readthedocs.io/en/latest/install/\n- Quickstart: https://flask-wtf.readthedocs.io/en/1.2.x/quickstart/\n- Forms guide: https://flask-wtf.readthedocs.io/en/1.2.x/form/\n- CSRF guide: https://flask-wtf.readthedocs.io/en/1.2.x/csrf/\n- Configuration: https://flask-wtf.readthedocs.io/en/1.2.x/config/\n- API reference: https://flask-wtf.readthedocs.io/en/1.2.x/api/\n- Changelog: https://flask-wtf.readthedocs.io/en/1.2.x/changes/\n- PyPI: https://pypi.org/project/Flask-WTF/\n- Source: https://github.com/pallets-eco/flask-wtf\n- Releases: https://github.com/pallets-eco/flask-wtf/releases\n"
  },
  {
    "path": "content/flax/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Flax for Python on JAX with NNX modules, Linen interop, training, randomness, and checkpointing guidance\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flax,jax,nnx,linen,deep-learning,neural-networks\"\n---\n\n# Flax Python Package Guide\n\n## Golden Rule\n\nUse `from flax import nnx` for new Flax code, keep `from flax import linen as nn` only for existing Linen-style projects, and treat JAX installation as a separate platform decision. `flax==0.12.5` is the current PyPI release as of March 12, 2026, but GPU and TPU projects should install the correct JAX build first instead of assuming the default `pip install flax` path is enough.\n\n## Install\n\nFor CPU-only local development:\n\n```bash\npython -m pip install \"flax==0.12.5\"\n```\n\nFor projects that train models, checkpoint state, or follow the official tutorials, install companion libraries explicitly:\n\n```bash\npython -m pip install \"flax==0.12.5\" optax orbax-checkpoint\n```\n\nImportant install note:\n\n- `flax` depends on JAX, but accelerator-specific JAX installation is not a Flax concern. For CUDA, ROCm, or TPU environments, install the correct JAX build first using the JAX installation matrix, then install `flax`.\n\n## Choose The Right API Surface\n\n### NNX for new code\n\nUse NNX when you are starting fresh. NNX modules are Python objects that hold state directly, work with `nnx.Module`, and use explicit RNG containers like `nnx.Rngs(...)`.\n\n### Linen for existing codebases\n\nUse Linen when the project already relies on `init/apply`, `@nn.compact`, `TrainState`, or older tutorials. Linen is still supported, but the main docs site now prioritizes NNX and keeps Linen material in the legacy docs site plus the NNX bridge guide.\n\n## Initialize A Model With NNX\n\nNNX modules create parameter state at construction time:\n\n```python\nimport jax.numpy as jnp\nfrom flax import nnx\n\nclass MLP(nnx.Module):\n    def __init__(self, din: int, hidden: int, dout: int, *, rngs: nnx.Rngs):\n        self.linear1 = nnx.Linear(din, hidden, rngs=rngs)\n        self.linear2 = nnx.Linear(hidden, dout, rngs=rngs)\n\n    def __call__(self, x):\n        x = self.linear1(x)\n        x = nnx.relu(x)\n        return self.linear2(x)\n\nmodel = MLP(din=784, hidden=256, dout=10, rngs=nnx.Rngs(0))\nbatch = jnp.ones((32, 784))\nlogits = model(batch)\nprint(logits.shape)\n```\n\nWhat changes compared with Linen:\n\n- NNX does not start from `variables = model.init(...)`\n- The model instance already owns parameter state\n- You mutate or update stateful objects through NNX transforms and utilities instead of passing a variables tree into `apply`\n\n## Training With Optax\n\n`optax` is the standard optimizer library used in Flax examples. In NNX, attach the optimizer to the model and update parameters through gradients:\n\n```python\nimport jax.numpy as jnp\nimport optax\nfrom flax import nnx\n\nclass Regressor(nnx.Module):\n    def __init__(self, *, rngs: nnx.Rngs):\n        self.linear = nnx.Linear(4, 1, rngs=rngs)\n\n    def __call__(self, x):\n        return self.linear(x)\n\nmodel = Regressor(rngs=nnx.Rngs(0))\noptimizer = nnx.Optimizer(model, optax.adam(1e-3), wrt=nnx.Param)\n\n@nnx.jit\ndef train_step(model, optimizer, x, y):\n    def loss_fn(model):\n        preds = model(x)\n        return jnp.mean((preds - y) ** 2)\n\n    loss, grads = nnx.value_and_grad(loss_fn)(model)\n    optimizer.update(model, grads)\n    return loss\n\nx = jnp.ones((8, 4))\ny = jnp.ones((8, 1))\nloss = train_step(model, optimizer, x, y)\nprint(loss)\n```\n\nUse `flax.training.train_state.TrainState` only when you are staying in Linen-style training loops.\n\n## Randomness And Configuration\n\nFlax is a local library, so there is no service authentication step. The important runtime configuration is how you manage JAX and RNG state.\n\nNamed RNG streams are the normal NNX pattern:\n\n```python\nimport jax.numpy as jnp\nfrom flax import nnx\n\ndropout = nnx.Dropout(rate=0.5)\nrngs = nnx.Rngs(params=0, dropout=1)\n\noutput = dropout(jnp.ones((4, 4)), rngs=rngs)\n```\n\nPractical rules:\n\n- Use separate named streams such as `params`, `dropout`, and any data-augmentation stream your code needs.\n- Do not silently reuse the same RNG stream everywhere. Reused dropout keys are a common source of suspiciously deterministic behavior.\n- When batching or vectorizing stochastic code, follow the randomness guide and fork streams instead of manually juggling raw JAX keys everywhere.\n- Install JAX for the correct platform before debugging Flax errors. Many apparent Flax failures are really mismatched `jax` or `jaxlib` installs.\n\n## Checkpointing\n\nThe current Flax docs point to Orbax for checkpointing. For NNX modules, save and restore state objects, then update the live module:\n\n```python\nfrom flax import nnx\nimport orbax.checkpoint as ocp\n\nstate = nnx.state(model)\ncheckpointer = ocp.StandardCheckpointer()\ncheckpointer.save(\"/tmp/flax-demo\", state, force=True)\n\nabstract_model = nnx.eval_shape(lambda: Regressor(rngs=nnx.Rngs(0)))\nabstract_state = nnx.state(abstract_model)\nrestored_state = checkpointer.restore(\"/tmp/flax-demo\", abstract_state)\nnnx.update(model, restored_state)\n```\n\nCheckpointing rules that matter:\n\n- Prefer Orbax APIs from current docs instead of older `flax.training.checkpoints` examples.\n- Restore against an abstract target tree when shapes or sharding matter.\n- Keep checkpoint structure stable across refactors or write explicit migration code.\n\n## Linen Interop And Migration\n\nIf you are migrating an existing Linen project, use the NNX bridge guide instead of rewriting everything at once.\n\nUseful mental model:\n\n- Linen: functional `init/apply`, variables collections, `@nn.compact`\n- NNX: object-style modules with explicit state and RNG containers\n- Bridge tools exist so you can convert or wrap pieces gradually instead of doing a flag day rewrite\n\nWhen reading external examples:\n\n- If the example imports `from flax import linen as nn`, it is not written in the current NNX style\n- If the example uses `TrainState`, `model.init`, or `variables[\"params\"]`, it is a Linen example\n- Do not paste Linen examples into an NNX training loop without translating the state model\n\n## Common Pitfalls\n\n- Treating `flax` as a standalone deep-learning runtime. Flax sits on top of JAX, so the JAX install and backend still determine whether code runs on CPU, GPU, or TPU.\n- Mixing NNX and Linen idioms in the same function without understanding the bridge boundary.\n- Assuming tutorial dependencies are bundled with `flax`. Training and checkpoint examples commonly also need `optax`, `orbax-checkpoint`, and dataset libraries.\n- Copying older blog posts that still target pre-NNX Flax APIs.\n- Restoring checkpoints directly into a changed model structure without checking shapes, names, or collection layout.\n\n## Version-Sensitive Notes For 0.12.5\n\n- PyPI lists `flax 0.12.5` as the latest release and marks `Requires: Python >=3.11`.\n- The latest docs site is now NNX-first, while legacy Linen docs live at `flax-linen.readthedocs.io`.\n- The PyPI project description still contains older prose that says Flax works on Python 3.8 or later. For `0.12.5`, trust the PyPI package metadata instead of the stale prose.\n- If you are starting from an older Flax tutorial, verify whether it predates the NNX transition before copying module and training patterns.\n\n## Official Links\n\n- NNX docs root: `https://flax.readthedocs.io/en/latest/`\n- NNX basics and tutorials: `https://flax.readthedocs.io/en/latest/basics.html`\n- Randomness guide: `https://flax.readthedocs.io/en/latest/guides/randomness.html`\n- Checkpointing guide: `https://flax.readthedocs.io/en/latest/guides/checkpointing.html`\n- NNX bridge guide: `https://flax.readthedocs.io/en/latest/guides/bridge_guide.html`\n- NNX optimizer reference: `https://flax.readthedocs.io/en/latest/api_reference/flax.nnx/training/optimizer.html`\n- Legacy Linen docs: `https://flax-linen.readthedocs.io/en/latest/`\n- PyPI package: `https://pypi.org/project/flax/`\n"
  },
  {
    "path": "content/flit-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"flit-core Python build backend for packaging projects with pyproject.toml and PEP 517\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.12.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"flit-core,python,packaging,pyproject,pep517,build-backend,pypi\"\n---\n\n# flit-core Python Package Guide\n\n## Golden Rule\n\n`flit-core` is the build backend, not the full `flit` CLI. Configure it in `pyproject.toml` with `build-backend = \"flit_core.buildapi\"` and let a frontend such as `pip` or `python -m build` call it. If you need commands like `flit init`, `flit build`, or `flit publish`, install `flit`, not only `flit-core`.\n\n## Install\n\nFor a locked environment:\n\n```bash\npython -m pip install \"flit-core==3.12.0\"\n```\n\nMost projects should declare it in `pyproject.toml` as a build dependency instead of importing it directly at runtime:\n\n```toml\n[build-system]\nrequires = [\"flit_core >=3.11,<4\"]\nbuild-backend = \"flit_core.buildapi\"\n```\n\nUse an exact pin like `flit_core==3.12.0` only when your project or CI needs full reproducibility.\n\n## Minimal Setup\n\nFor new projects on Flit 3.x, prefer PEP 621 metadata in `[project]`:\n\n```toml\n[build-system]\nrequires = [\"flit_core >=3.11,<4\"]\nbuild-backend = \"flit_core.buildapi\"\n\n[project]\nname = \"demo-pkg\"\nauthors = [{name = \"Example Maintainer\", email = \"dev@example.com\"}]\nreadme = \"README.md\"\nlicense = {file = \"LICENSE\"}\nrequires-python = \">=3.9\"\ndynamic = [\"version\", \"description\"]\n\n[project.urls]\nHome = \"https://example.com/demo-pkg\"\n```\n\nThen expose the version and module docstring from your import package:\n\n```python\n\"\"\"Short package description used by Flit.\"\"\"\n\n__version__ = \"0.1.0\"\n```\n\nBy default, Flit derives the importable module name from the project name, replacing hyphens with underscores.\n\n## Core Usage\n\n### Build a wheel and sdist\n\nAfter the project is configured, build artifacts with a frontend:\n\n```bash\npython -m pip install build\npython -m build\n```\n\nThis uses `flit_core.buildapi` from your `pyproject.toml`.\n\n### Package layout\n\nFlit supports a simple top-level module or a package directory. A common layout is:\n\n```text\npyproject.toml\nREADME.md\nLICENSE\nsrc/\n  demo_pkg/\n    __init__.py\n```\n\nIf your import package name does not match the normalized project name, set it explicitly:\n\n```toml\n[tool.flit.module]\nname = \"demo_pkg\"\n```\n\n### Console scripts\n\nDeclare CLI entry points with standard `[project.scripts]` metadata:\n\n```toml\n[project.scripts]\ndemo-pkg = \"demo_pkg.cli:main\"\n```\n\n### Source distributions\n\nIf you need extra files in the sdist or want to exclude generated files, configure them explicitly:\n\n```toml\n[tool.flit.sdist]\ninclude = [\"tests/\", \"docs/\"]\nexclude = [\"docs/_build/\"]\n```\n\nThis matters because `flit-core` itself is just the backend. Some workflows that use the `flit` CLI add VCS-tracked files by default, but direct backend builds do not.\n\n## Configuration Notes\n\n- Prefer `[project]` metadata for new work. Flit 3.x still recognizes the older `[tool.flit.metadata]` style, but it is legacy.\n- `dynamic = [\"version\", \"description\"]` reads `__version__` and the module docstring from your package.\n- `requires-python`, dependencies, optional dependencies, entry points, and URLs belong in standard PEP 621 metadata under `[project]`.\n- Reproducible build timestamps can be controlled with `SOURCE_DATE_EPOCH`.\n- `flit-core` has no authentication flow of its own. Package publishing credentials apply to tools such as `flit publish` or `twine`, not to the backend configuration shown here.\n\n## Common Pitfalls\n\n- Installing `flit-core` does not install the `flit` CLI.\n- Use `build-backend = \"flit_core.buildapi\"`. The older `flit.buildapi` backend name is deprecated in the 3.x line.\n- Do not assume the project name and import package are identical. Hyphens are normalized to underscores, and some projects need an explicit `[tool.flit.module]`.\n- If you rely on non-code files in source distributions, configure `[tool.flit.sdist]` instead of assuming they will be discovered automatically.\n- Old blog posts often show `[tool.flit.metadata]` examples. They still work in `flit-core` 3.x, but they are the wrong starting point for new projects.\n- `flit-core` is a build-time dependency. It usually should not appear in your application imports or runtime requirements.\n\n## Version-Sensitive Notes For 3.12.0\n\n- The stable Flit docs are versioned for `3.12.0`, so `https://flit.pypa.io/en/stable/` is the correct canonical doc root for this package version.\n- Flit `3.12` adds support for SPDX license expressions with `AND` and `OR`, and it accepts an annotated assignment such as `__version__: str = \"0.1.0\"` for dynamic version loading.\n- Flit `3.11` added support for PEP 639 license expressions and `license-files`, so examples using those fields require at least `flit_core >=3.11`.\n- Flit `3.10` deprecated the old `flit.buildapi` backend path. For 3.12 projects, use `flit_core.buildapi` only.\n- The old metadata format is still accepted in the 3.x series, but the docs state it is removed in `flit_core` 4.0. If you want an easy future upgrade path, stay on `[project]` now.\n\n## Bootstrap And Advanced Packaging Notes\n\n- If you are bootstrapping packaging tooling itself, Flit documents `python -m flit_core.wheel` as the low-level way to build a wheel for Flit without having `flit` installed already.\n- For normal project packaging, prefer standard build frontends and keep `flit-core` behind the PEP 517 interface.\n\n## Official Sources\n\n- Flit stable docs: `https://flit.pypa.io/en/stable/`\n- Flit `pyproject.toml` reference: `https://flit.pypa.io/en/stable/pyproject_toml.html`\n- Flit bootstrap notes: `https://flit.pypa.io/en/stable/bootstrap.html`\n- Flit history: `https://flit.pypa.io/en/stable/history.html`\n- Flit reproducible builds: `https://flit.pypa.io/en/stable/reproducible.html`\n- PyPI package page: `https://pypi.org/project/flit-core/`\n"
  },
  {
    "path": "content/folium/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Folium Python package for building Leaflet-based interactive maps, layers, GeoJSON overlays, choropleths, and map plugins\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.20.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"folium,maps,leaflet,geojson,visualization,gis\"\n---\n\n# Folium Python Package Guide\n\n## Golden Rule\n\nUse `folium` when you need to generate interactive Leaflet maps from Python and deliver them as HTML. Treat the Python object as a map builder, not a GIS engine: prepare your data first, then use Folium to render tiles, markers, GeoJSON, choropleths, and plugins into a notebook or saved HTML file.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"folium==0.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"folium==0.20.0\"\npoetry add \"folium==0.20.0\"\nconda install -c conda-forge folium\n```\n\nUpstream getting-started docs list these automatic dependencies for the base install:\n\n- `branca`\n- `jinja2`\n- `numpy`\n- `requests`\n\nPyPI also publishes a `testing` extra for contributor or package-maintainer workflows.\n\n## Initialize And Render A Map\n\nFolium maps are HTML/JavaScript artifacts. In notebooks, display the map object directly. In scripts or web backends, save the output to HTML.\n\n```python\nimport folium\n\nm = folium.Map(\n    location=(45.5236, -122.6750),\n    zoom_start=12,\n    control_scale=True,\n)\n\nfolium.Marker(\n    location=(45.528, -122.68),\n    tooltip=\"Downtown\",\n    popup=\"Portland\",\n).add_to(m)\n\nm.save(\"map.html\")\n```\n\nKey defaults and behaviors:\n\n- `location` is latitude, longitude.\n- The default basemap is `OpenStreetMap`.\n- The rendered output is not visible in an untrusted Jupyter notebook until the notebook is trusted.\n- `LayerControl` should be added after the layers it controls.\n\n## Core Usage\n\n### Create a map with a different tile provider\n\nFolium 0.20.0 supports built-in provider names and `xyzservices` tile providers. If you pass a custom tile URL, also pass attribution with `attr`.\n\n```python\nimport folium\n\nm = folium.Map(\n    location=(37.7749, -122.4194),\n    zoom_start=11,\n    tiles=\"CartoDB Positron\",\n)\n\nfolium.TileLayer(\n    tiles=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\n    attr=\"&copy; OpenStreetMap contributors\",\n    name=\"OSM\",\n).add_to(m)\n\nfolium.LayerControl().add_to(m)\n```\n\nIf you need a map with no basemap, start with `tiles=None` and add your own layers later.\n\n### Group layers and toggle them\n\n```python\nimport folium\n\nm = folium.Map((0, 0), zoom_start=3)\n\ncities = folium.FeatureGroup(name=\"Cities\").add_to(m)\nroutes = folium.FeatureGroup(name=\"Routes\").add_to(m)\n\nfolium.Marker((51.5072, -0.1276), tooltip=\"London\").add_to(cities)\nfolium.Marker((48.8566, 2.3522), tooltip=\"Paris\").add_to(cities)\n\nfolium.PolyLine(\n    locations=[(51.5072, -0.1276), (48.8566, 2.3522)],\n    color=\"blue\",\n    weight=3,\n).add_to(routes)\n\nfolium.LayerControl(collapsed=False).add_to(m)\n```\n\nUse `FeatureGroup` for logical toggles. If the layer should appear in the control, keep `control=True` and add the control last.\n\n### Add GeoJSON with styling and tooltips\n\n`folium.GeoJson` is the main entry point for polygon, line, and point feature overlays.\n\n```python\nimport folium\n\ngeojson = {\n    \"type\": \"FeatureCollection\",\n    \"features\": [\n        {\n            \"type\": \"Feature\",\n            \"properties\": {\"name\": \"Area A\", \"value\": 10},\n            \"geometry\": {\n                \"type\": \"Polygon\",\n                \"coordinates\": [[\n                    [-122.53, 45.52],\n                    [-122.53, 45.55],\n                    [-122.48, 45.55],\n                    [-122.48, 45.52],\n                    [-122.53, 45.52],\n                ]],\n            },\n        }\n    ],\n}\n\nm = folium.Map(location=(45.53, -122.50), zoom_start=13)\n\nfolium.GeoJson(\n    geojson,\n    name=\"Areas\",\n    style_function=lambda feature: {\n        \"fillColor\": \"#2a9d8f\",\n        \"color\": \"#1d3557\",\n        \"weight\": 2,\n        \"fillOpacity\": 0.5,\n    },\n    highlight_function=lambda feature: {\n        \"weight\": 4,\n        \"fillOpacity\": 0.8,\n    },\n    tooltip=folium.GeoJsonTooltip(fields=[\"name\", \"value\"]),\n    zoom_on_click=True,\n).add_to(m)\n\nfolium.LayerControl().add_to(m)\n```\n\nPrefer `GeoJson` when you want full styling control, hover highlighting, popups/tooltips, or click-to-zoom behavior.\n\n### Build a choropleth from tabular data\n\n`folium.Choropleth` is the fast path for coloring features from a data table. The most common mistake is using the wrong `key_on` expression for your GeoJSON properties or IDs.\n\n```python\nimport folium\nimport pandas as pd\n\ngeojson = {\n    \"type\": \"FeatureCollection\",\n    \"features\": [\n        {\n            \"type\": \"Feature\",\n            \"id\": \"A\",\n            \"properties\": {\"name\": \"Area A\"},\n            \"geometry\": {\n                \"type\": \"Polygon\",\n                \"coordinates\": [[\n                    [-122.53, 45.52],\n                    [-122.53, 45.55],\n                    [-122.48, 45.55],\n                    [-122.48, 45.52],\n                    [-122.53, 45.52],\n                ]],\n            },\n        },\n        {\n            \"type\": \"Feature\",\n            \"id\": \"B\",\n            \"properties\": {\"name\": \"Area B\"},\n            \"geometry\": {\n                \"type\": \"Polygon\",\n                \"coordinates\": [[\n                    [-122.48, 45.52],\n                    [-122.48, 45.55],\n                    [-122.43, 45.55],\n                    [-122.43, 45.52],\n                    [-122.48, 45.52],\n                ]],\n            },\n        },\n    ],\n}\n\ndata = pd.DataFrame(\n    [\n        {\"region_id\": \"A\", \"score\": 10},\n        {\"region_id\": \"B\", \"score\": 25},\n    ]\n)\n\nm = folium.Map(location=(45.53, -122.48), zoom_start=13)\n\nfolium.Choropleth(\n    geo_data=geojson,\n    data=data,\n    columns=[\"region_id\", \"score\"],\n    key_on=\"feature.id\",\n    fill_color=\"YlGnBu\",\n    fill_opacity=0.7,\n    line_opacity=0.2,\n    legend_name=\"Score\",\n    highlight=True,\n).add_to(m)\n```\n\nUseful options from the upstream guide:\n\n- `bins` when the default color scaling is not appropriate\n- `nan_fill_color` and `nan_fill_opacity` for missing values\n- `name` and `show` if the choropleth should participate in `LayerControl`\n\n### Cluster many markers\n\nFor dense point data, use `folium.plugins.MarkerCluster` instead of adding hundreds of plain markers directly to the map.\n\n```python\nimport folium\nfrom folium.plugins import MarkerCluster\n\nm = folium.Map(location=(44, -73), zoom_start=5)\ncluster = MarkerCluster(name=\"Sites\").add_to(m)\n\npoints = [\n    (40.67, -73.94, \"Brooklyn\"),\n    (44.67, -73.94, \"Vermont\"),\n    (44.67, -71.94, \"New Hampshire\"),\n]\n\nfor lat, lon, label in points:\n    folium.Marker((lat, lon), popup=label, tooltip=label).add_to(cluster)\n\nfolium.LayerControl().add_to(m)\n```\n\n### Search GeoJSON or grouped features\n\nThe `Search` plugin can search `GeoJson`, `TopoJson`, `FeatureGroup`, or `MarkerCluster` layers. Set `search_label` to a property that actually exists in the target layer.\n\n```python\nimport folium\nfrom folium.plugins import Search\n\ngeojson = {\n    \"type\": \"FeatureCollection\",\n    \"features\": [\n        {\n            \"type\": \"Feature\",\n            \"properties\": {\"name\": \"Central Park\"},\n            \"geometry\": {\"type\": \"Point\", \"coordinates\": [-73.9654, 40.7829]},\n        }\n    ],\n}\n\nm = folium.Map(location=(40.78, -73.97), zoom_start=13)\n\nplaces = folium.GeoJson(\n    geojson,\n    name=\"Places\",\n    tooltip=folium.GeoJsonTooltip(fields=[\"name\"]),\n).add_to(m)\n\nSearch(\n    layer=places,\n    search_label=\"name\",\n    placeholder=\"Search places\",\n    collapsed=False,\n).add_to(m)\n```\n\n## Configuration And Integration Notes\n\n### Notebooks\n\n- Display the map object directly in Jupyter: `m`\n- If the map area stays blank, trust the notebook first\n- Save with `m.save(\"map.html\")` when you need a portable artifact outside the notebook\n\n### Flask, Django, and other server-rendered apps\n\nFolium generates HTML with linked JavaScript and CSS resources. Common patterns are:\n\n- generate a full standalone file with `m.save(...)`\n- embed `m.get_root().render()` into a server-rendered template\n- write the HTML to object storage or a temp file if another service will host it\n\nBecause Folium emits browser code, it is usually simpler to generate maps on the server and let the browser render them than to treat Folium as an API you call from frontend JavaScript.\n\n### Tile providers and API keys\n\nFolium itself has no package-level authentication, but some third-party tile or geocoding providers do. Practical rules:\n\n- if you pass a custom tile URL, set `attr` explicitly\n- if a plugin provider needs credentials, pass them in the provider-specific options the plugin accepts\n- keep provider tokens outside source control and inject them from environment variables\n\nExample with an environment variable inside a tile URL template:\n\n```python\nimport os\nimport folium\n\ntile_token = os.environ[\"MAP_TILE_TOKEN\"]\n\nm = folium.Map(\n    location=(37.7749, -122.4194),\n    zoom_start=11,\n    tiles=f\"https://tiles.example.com/{{z}}/{{x}}/{{y}}.png?token={tile_token}\",\n    attr=\"Example Maps\",\n)\n```\n\n### Custom JS and CSS resources\n\nClasses that inherit from Folium's JS/CSS mixin can load custom resources. Use this when your deployment needs a private CDN or a patched asset URL.\n\n```python\nimport folium\n\nm = folium.Map()\nm.add_css_link(\n    \"bootstrap_css\",\n    \"https://example.com/bootstrap/400.5.0/css/bootstrap.min.css\",\n)\n```\n\n## Common Pitfalls\n\n- Folium expects latitude, longitude order for `location`; GeoJSON coordinate arrays stay longitude, latitude.\n- The map object is only a renderer. If your data needs joins, projections, cleaning, or aggregation, do that before building the map.\n- Blank notebook output usually means the notebook is not trusted or required assets were blocked.\n- `LayerControl` must be added after the layers you want it to control.\n- Custom tile URLs need attribution via `attr`, and provider terms can require API keys or usage limits.\n- `Choropleth` joins fail quietly when `columns` and `key_on` do not line up with GeoJSON identifiers.\n- Large GeoJSON payloads can make notebook output or saved HTML files heavy. For large point sets, prefer clustering; for large polygons, simplify the geometry before rendering.\n- Search only works against the properties exposed by the target layer. If `search_label` does not exist, the UI appears but results will be wrong or empty.\n\n## Version-Sensitive Notes For 0.20.0\n\n- As of March 12, 2026, PyPI still lists `0.20.0` as the latest Folium release, published on June 16, 2025.\n- The official docs root and API reference are aligned to `0.20.0`, so the version used here and upstream version match for this session.\n- PyPI now requires Python `>=3.9`; older project environments pinned to Python 3.8 need an older Folium release.\n- The upstream `v0.20.0` release notes are short, so treat the docs and API reference as the authoritative source for behavior rather than relying on release-note summaries alone.\n\n## Official Sources\n\n- Folium docs root: `https://python-visualization.github.io/folium/latest/`\n- Folium getting started: `https://python-visualization.github.io/folium/latest/getting_started.html`\n- Folium API reference: `https://python-visualization.github.io/folium/latest/reference.html`\n- Folium user guide: `https://python-visualization.github.io/folium/latest/user_guide.html`\n- Folium choropleth guide: `https://python-visualization.github.io/folium/latest/user_guide/geojson/choropleth.html`\n- Folium MarkerCluster guide: `https://python-visualization.github.io/folium/latest/user_guide/plugins/marker_cluster.html`\n- Folium Search guide: `https://python-visualization.github.io/folium/latest/user_guide/plugins/search.html`\n- Folium custom tiles guide: `https://python-visualization.github.io/folium/latest/advanced_guide/custom_tiles.html`\n- Folium JS/CSS customization guide: `https://python-visualization.github.io/folium/latest/advanced_guide/customize_javascript_and_css.html`\n- PyPI package page: `https://pypi.org/project/folium/`\n- GitHub release notes for `v0.20.0`: `https://github.com/python-visualization/folium/releases/tag/v0.20.0`\n"
  },
  {
    "path": "content/fpdf2/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"fpdf2 package guide for Python PDF generation with setup, fonts, layout defaults, and output handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.8.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"fpdf2,pdf,python,fonts,unicode,html\"\n---\n\n# fpdf2 Python Package Guide\n\n## Golden Rule\n\nInstall `fpdf2`, but import from `fpdf`:\n\n```bash\npython -m pip install \"fpdf2==2.8.7\"\n```\n\n```python\nfrom fpdf import FPDF\n```\n\nCreate a fresh `FPDF` instance per document, call `add_page()`, set a font before writing text, and use `bytes(pdf.output())` when you need the PDF in memory for an HTTP response or file upload.\n\n## Install\n\n### pip\n\n```bash\npython -m pip install \"fpdf2==2.8.7\"\n```\n\n### uv\n\n```bash\nuv add \"fpdf2==2.8.7\"\n```\n\n### Poetry\n\n```bash\npoetry add \"fpdf2==2.8.7\"\n```\n\nIf you are migrating from older PyFPDF-era code, verify the environment only has `fpdf2` installed. The modern package name is `fpdf2`, but the import path remains `fpdf`.\n\n## Initialize A Document\n\n`FPDF()` defaults to portrait, millimeters, and A4. Start by creating a document, enabling automatic page breaks, adding a page, and choosing a font:\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF()\npdf.set_auto_page_break(auto=True, margin=15)\npdf.add_page()\npdf.set_font(\"Helvetica\", size=12)\n\npdf.cell(text=\"Hello from fpdf2\")\npdf.ln(10)\npdf.multi_cell(text=\"This PDF was generated from Python.\")\n\npdf.output(\"hello.pdf\")\n```\n\nUseful constructor overrides:\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF(\n    orientation=\"landscape\",\n    unit=\"pt\",\n    format=(612, 792),\n)\n```\n\n- `orientation`: `\"portrait\"` or `\"landscape\"`\n- `unit`: `\"pt\"`, `\"mm\"`, `\"cm\"`, or `\"in\"`\n- `format`: named page size such as `\"A4\"` or a `(width, height)` tuple\n\n## Core Usage\n\n### Draw text and simple layout\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF()\npdf.add_page()\npdf.set_font(\"Helvetica\", size=12)\n\npdf.cell(text=\"Invoice #1234\", new_x=\"LMARGIN\", new_y=\"NEXT\")\npdf.set_font_size(10)\npdf.multi_cell(\n    text=\"Generated with fpdf2. Use multi_cell for wrapped paragraphs instead of trying to pack long text into cell().\"\n)\n\npdf.output(\"invoice.pdf\")\n```\n\n`cell()` is best for single-line content. `multi_cell()` is the normal choice for wrapped paragraphs or user-provided text.\n\n### Use a Unicode font for non-Latin text\n\nBuilt-in PDF core fonts cover Latin text, but not arbitrary Unicode. Register a `.ttf`, `.otf`, `.ttc`, or `.otc` font file before writing multilingual text:\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF()\npdf.add_page()\n\npdf.add_font(\"DejaVuSans\", fname=\"fonts/DejaVuSans.ttf\")\npdf.set_font(\"DejaVuSans\", size=14)\npdf.multi_cell(text=\"Hello, world\\\\nGreek: Γειά σου\\\\nArabic: مرحبا\\\\nChinese: 你好\")\n\npdf.output(\"unicode.pdf\")\n```\n\nIf you only set a core font such as `Helvetica`, `Times`, or `Courier`, non-Latin characters will fail or render incorrectly.\n\n### Insert images\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF()\npdf.add_page()\npdf.set_font(\"Helvetica\", size=12)\npdf.cell(text=\"Chart output\", new_x=\"LMARGIN\", new_y=\"NEXT\")\npdf.image(\"artifacts/chart.png\", x=10, y=25, w=120)\npdf.output(\"report.pdf\")\n```\n\nPass either `w` or `h` and let `fpdf2` preserve aspect ratio unless you intentionally want to distort the image.\n\n### Write basic HTML fragments\n\n`write_html()` is useful for simple rich text, lists, links, and tables generated by your app:\n\n```python\nfrom fpdf import FPDF\n\npdf = FPDF()\npdf.add_page()\npdf.set_font(\"Helvetica\", size=11)\npdf.write_html(\n    \"\"\"\n    <h1>Status</h1>\n    <p><b>Build:</b> green</p>\n    <ul>\n      <li>PDF generated with <a href=\"https://py-pdf.github.io/fpdf2/\">fpdf2</a></li>\n      <li>HTML support is intentionally limited</li>\n    </ul>\n    \"\"\"\n)\npdf.output(\"html.pdf\")\n```\n\nUse this for controlled snippets, not as a full HTML-to-PDF browser engine.\n\n### Return PDF bytes from a web API\n\n`output()` returns a `bytearray` when you do not pass a filename. Convert it to `bytes` for frameworks that expect immutable byte strings:\n\n```python\nfrom flask import Response\nfrom fpdf import FPDF\n\ndef download_pdf() -> Response:\n    pdf = FPDF()\n    pdf.add_page()\n    pdf.set_font(\"Helvetica\", size=12)\n    pdf.cell(text=\"Generated on demand\")\n\n    payload = bytes(pdf.output())\n    return Response(\n        payload,\n        mimetype=\"application/pdf\",\n        headers={\"Content-Disposition\": \"inline; filename=example.pdf\"},\n    )\n```\n\n## Configuration Notes\n\n### Fonts and file paths\n\n- `add_font()` expects a font file that your process can read at runtime.\n- As of `2.8.6`, `fpdf2` supports `.woff` and `.woff2` in addition to `.ttf`, `.otf`, `.ttc`, and `.otc`.\n- Keep font files in a stable application path and reference them with absolute or application-root-relative paths in production.\n\n### Page geometry and breaks\n\n- `set_auto_page_break(auto=True, margin=15)` is the safest default for text-heavy reports.\n- `set_margins(left, top, right)` controls content bounds across the document.\n- For custom sizes such as labels or receipts, pass an explicit `(width, height)` tuple to `format`.\n\n### Output lifecycle\n\n- `pdf.output(\"file.pdf\")` writes to disk.\n- `pdf.output()` returns the document as a `bytearray`.\n- The API docs warn that content cannot be added after `output()` finalizes the document. Build the whole document first, then export once.\n\n## Common Pitfalls\n\n- Package name and import name differ. Install `fpdf2`, import from `fpdf`.\n- Always call `add_page()` before writing visible content.\n- Always set a font before calling `cell()`, `multi_cell()`, or `write_html()`.\n- Core fonts are not a substitute for Unicode fonts. Use `add_font()` for multilingual output or symbols outside Latin coverage.\n- `write_html()` is intentionally limited. It is not a browser engine and will not match arbitrary CSS-heavy templates.\n- Reuse patterns from old `pyfpdf` examples carefully. Some deprecated compatibility parameters were removed in `2.8.5`.\n- Generate a new `FPDF` object per document or request. Mutating and reusing an already-output document object is error-prone.\n\n## Version-Sensitive Notes For 2.8.x\n\n- `2.8.5` removed remaining traces of deprecated parameters from APIs and docs. If older examples pass `dest=` to `output()` or `uni=` to `add_font()`, update them.\n- `2.8.6` added support for `.woff` and `.woff2` fonts, plus improvements around transforms and text regions.\n- `2.8.7` is a bugfix release. If you depend on image metadata internals or type-checking behavior, prefer `2.8.7` examples over early `2.8.x` blog posts.\n\n## Official Sources Used\n\n- Docs root: `https://py-pdf.github.io/fpdf2/`\n- Tutorial: `https://py-pdf.github.io/fpdf2/Tutorial.html`\n- Text styling and Unicode fonts: `https://py-pdf.github.io/fpdf2/TextStyling.html`\n- Output API reference: `https://py-pdf.github.io/fpdf2/fpdf/fpdf.html`\n- Web API usage guide: `https://py-pdf.github.io/fpdf2/UsageInWebAPI.html`\n- Project history and compatibility context: `https://py-pdf.github.io/fpdf2/History.html`\n- Changelog: `https://py-pdf.github.io/fpdf2/Changelog.html`\n- PyPI release page: `https://pypi.org/project/fpdf2/`\n"
  },
  {
    "path": "content/freezegun/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"freezegun package guide for Python tests that freeze, tick, and move time deterministically\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.5\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"freezegun,python,testing,time,mocking,datetime,pytest,unittest\"\n---\n\n# freezegun Python Package Guide\n\n## Golden Rule\n\nUse `freezegun` to freeze time inside tests, not in production code. Prefer freezing the smallest scope that makes the assertion deterministic, and use explicit timestamps instead of relying on whatever the current clock happens to be.\n\nAs of March 11, 2026, the version used here `1.5.5` still matches the current PyPI release.\n\n## Install\n\n```bash\npython -m pip install \"freezegun==1.5.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"freezegun==1.5.5\"\npoetry add \"freezegun==1.5.5\"\n```\n\n`freezegun` uses `python-dateutil` under the hood for string parsing, so readable date strings work, but ISO-style strings are safer in test code.\n\n## What It Freezes\n\nOnce `freeze_time(...)` is active, Freezegun freezes these common clock reads:\n\n- `datetime.datetime.now()`\n- `datetime.datetime.utcnow()`\n- `datetime.date.today()`\n- `time.time()`\n- `time.localtime()`\n- `time.gmtime()`\n- `time.strftime()`\n- `time.monotonic()`\n- `time.perf_counter()`\n\n`time.monotonic()` and `time.perf_counter()` are frozen for relative changes, not meaningful absolute values.\n\n## Core Usage\n\n### Decorator\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09 12:00:00\")\ndef test_invoice_timestamp() -> None:\n    assert datetime.now() == datetime(2025, 8, 9, 12, 0, 0)\n```\n\n### Context manager\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\ndef test_context_manager() -> None:\n    with freeze_time(\"2025-08-09\"):\n        assert datetime.now() == datetime(2025, 8, 9, 0, 0, 0)\n```\n\n### Raw start/stop for setup-heavy tests\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\ndef test_manual_lifecycle() -> None:\n    freezer = freeze_time(\"2025-08-09 15:30:00\")\n    freezer.start()\n    try:\n        assert datetime.now() == datetime(2025, 8, 9, 15, 30, 0)\n    finally:\n        freezer.stop()\n```\n\n## Common Test Patterns\n\n### `unittest.TestCase`\n\nClass decoration freezes time for test methods and the test case setup and teardown path:\n\n```python\nimport datetime\nimport unittest\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"1999-12-31 23:59:59\")\nclass BillingTests(unittest.TestCase):\n    def test_cutoff(self) -> None:\n        self.assertEqual(\n            datetime.datetime.now(),\n            datetime.datetime(1999, 12, 31, 23, 59, 59),\n        )\n```\n\n### Passing the freezer object into the test\n\nUse `as_arg=True` or `as_kwarg=...` when the test needs to move time after entering the frozen scope:\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09\", as_arg=True)\ndef test_time_travel(frozen_time) -> None:\n    assert datetime.now() == datetime(2025, 8, 9)\n    frozen_time.move_to(\"2025-08-10\")\n    assert datetime.now() == datetime(2025, 8, 10)\n```\n\n### Supplying the target time dynamically\n\n`freeze_time(...)` accepts strings, `date`, `datetime`, callables, and generators that yield datetimes:\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\ndef dynamic_now() -> datetime:\n    return datetime(2025, 8, 9, 18, 45, 0)\n\ndef test_dynamic_source() -> None:\n    with freeze_time(dynamic_now):\n        assert datetime.now() == datetime(2025, 8, 9, 18, 45, 0)\n```\n\n## Time Control Options\n\n### `tick=True`\n\nUse this when time should start from a known instant but continue advancing:\n\n```python\nfrom datetime import datetime\nimport time\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09 12:00:00\", tick=True)\ndef test_tick_mode() -> None:\n    start = datetime.now()\n    time.sleep(0.01)\n    assert datetime.now() > start\n```\n\n### `auto_tick_seconds=...`\n\nUse this when every clock read should move forward by a fixed amount:\n\n```python\nfrom datetime import datetime, timedelta\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09 12:00:00\", auto_tick_seconds=15)\ndef test_auto_increment() -> None:\n    first = datetime.now()\n    second = datetime.now()\n    assert second == first + timedelta(seconds=15)\n```\n\n### Manual `.tick(...)`\n\nUse the freezer object when the test needs precise control:\n\n```python\nfrom datetime import datetime, timedelta\n\nfrom freezegun import freeze_time\n\ndef test_manual_tick() -> None:\n    with freeze_time(\"2025-08-09 12:00:00\") as frozen_time:\n        frozen_time.tick(delta=timedelta(minutes=5))\n        assert datetime.now() == datetime(2025, 8, 9, 12, 5, 0)\n```\n\n### `.move_to(...)`\n\nJump directly to another date or timestamp:\n\n```python\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\ndef test_move_to() -> None:\n    with freeze_time(\"2025-08-09 12:00:00\") as frozen_time:\n        frozen_time.move_to(\"2025-08-10 09:30:00\")\n        assert datetime.now() == datetime(2025, 8, 10, 9, 30, 0)\n```\n\n### `tz_offset=...`\n\nUse `tz_offset` when the test cares about local time relative to UTC:\n\n```python\nfrom datetime import date, datetime, timedelta\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09 03:00:00\", tz_offset=-4)\ndef test_local_and_utc() -> None:\n    assert datetime.utcnow() == datetime(2025, 8, 9, 3, 0, 0)\n    assert datetime.now() == datetime(2025, 8, 8, 23, 0, 0)\n    assert date.today() == date(2025, 8, 8)\n\n@freeze_time(\"2025-08-09 03:00:00\", tz_offset=-timedelta(hours=3, minutes=30))\ndef test_timedelta_offset() -> None:\n    assert datetime.now() == datetime(2025, 8, 8, 23, 30, 0)\n```\n\n## Asyncio\n\n`freezegun` also freezes `time.monotonic()`, which can break `asyncio.sleep()` and related scheduling if you do nothing else. For async tests, pass `real_asyncio=True` so the event loop still sees real monotonic time.\n\n```python\nimport asyncio\nfrom datetime import datetime\n\nfrom freezegun import freeze_time\n\n@freeze_time(\"2025-08-09 12:00:00\", real_asyncio=True)\nasync def test_async_sleep() -> None:\n    await asyncio.sleep(0.01)\n    assert datetime.now() == datetime(2025, 8, 9, 12, 0, 0)\n```\n\n## Ignore Lists And Global Configuration\n\nIgnore a package for one frozen scope:\n\n```python\nfrom freezegun import freeze_time\n\nwith freeze_time(\"2025-08-09\", ignore=[\"threading\"]):\n    pass\n```\n\nSet a new default ignore list globally:\n\n```python\nimport freezegun\n\nfreezegun.configure(default_ignore_list=[\"threading\", \"tensorflow\"])\n```\n\nExtend the built-in ignore list instead of replacing it:\n\n```python\nimport freezegun\n\nfreezegun.configure(extend_ignore_list=[\"tensorflow\"])\n```\n\nThe built-in defaults shown in the maintainer docs include modules such as `threading`, `selenium`, `_pytest.terminal.`, and `_pytest.runner.`.\n\n## Common Pitfalls\n\n- Default argument values are evaluated before Freezegun starts. If a function uses `default=date.today()` or similar, freezing time later will not change that captured value.\n- `auto_tick_seconds` overrides `tick`. If both are set, Freezegun ignores `tick`.\n- Generator inputs are consumable. Reusing the same generator across multiple `freeze_time(...)` calls can end in `StopIteration`.\n- The arbitrary-class decorator form may not work in every case. It is most reliable on test functions and `unittest.TestCase` classes.\n- If your test or framework depends on the event loop clock, use `real_asyncio=True`.\n- Overriding `default_ignore_list` replaces the defaults. Use `extend_ignore_list` if you only want to add entries.\n- Prefer explicit timestamps in assertions. Natural-language date strings are convenient, but ISO timestamps are less ambiguous in tests and agent-written code.\n\n## Version-Sensitive Notes\n\n- The version used here `1.5.5` matches the current PyPI release on March 11, 2026, so no version drift was found during review.\n- Freezegun's maintained documentation is README-based. The GitHub README and the PyPI long description are effectively the canonical docs, so check those before trusting older blog posts.\n- The current API documented by the maintainer includes `tick`, `auto_tick_seconds`, `move_to`, `as_arg`, `as_kwarg`, and `real_asyncio`. Older examples often omit the async guidance.\n- PyPI shows the `1.5.5` release was published on August 9, 2025. If you need behavior identical to this guide, pin `freezegun==1.5.5`.\n\n## Official Sources\n\n- GitHub README: `https://github.com/spulec/freezegun`\n- PyPI project page: `https://pypi.org/project/freezegun/`\n- PyPI JSON metadata: `https://pypi.org/pypi/freezegun/json`\n"
  },
  {
    "path": "content/frozenlist/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"frozenlist package guide for Python projects that need a MutableSequence which can be frozen and hashed\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"frozenlist,python,collections,mutable-sequence,aio-libs\"\n---\n\n# frozenlist Python Package Guide\n\n## Golden Rule\n\nUse `frozenlist.FrozenList` when you need normal list-style mutation during setup and an immutable, hashable sequence afterward. The public API is intentionally small: `FrozenList` implements `collections.abc.MutableSequence`, `freeze()` makes it immutable, and hashing only works after the instance is frozen.\n\n## Install\n\n`frozenlist 1.8.0` requires Python 3.9 or newer.\n\n```bash\npython -m pip install \"frozenlist==1.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"frozenlist==1.8.0\"\npoetry add \"frozenlist==1.8.0\"\n```\n\nMost projects should use the published wheels from PyPI. If you are building the package from a source checkout, the 1.8.0 changelog documents `--config-settings=pure-python=true` for explicitly requesting a pure-Python build.\n\n## Imports, Environment Variables, And Setup\n\nThere is no auth step, client object, or required runtime environment variable. Import the class directly:\n\n```python\nfrom frozenlist import FrozenList\n```\n\nFor normal app code, that is all the setup you need.\n\n## Build A List, Then Freeze It\n\n`FrozenList` starts mutable. Use normal `MutableSequence` operations first, then freeze it once the contents are final:\n\n```python\nfrom frozenlist import FrozenList\n\nsteps = FrozenList([\"parse\"])\nsteps.append(\"validate\")\nsteps.extend([\"enrich\", \"serialize\"])\nsteps.insert(1, \"normalize\")\n\nassert not steps.frozen\n\nsteps.freeze()\n\nassert steps.frozen\nprint(steps[0])       # \"parse\"\nprint(len(steps))     # 5\nprint(list(steps))    # ['parse', 'normalize', 'validate', 'enrich', 'serialize']\n```\n\nAfter `freeze()`, mutating operations raise `RuntimeError`.\n\n## Use A FrozenList As A Cache Key Or Dict Key\n\n`FrozenList` becomes hashable only after freezing. Hashing an unfrozen instance raises `RuntimeError`.\n\n```python\nfrom frozenlist import FrozenList\n\nenabled_features = FrozenList([\"search\", \"audit\"])\n\nenabled_features.freeze()\n\ncache = {enabled_features: \"compiled-config\"}\nprint(cache[enabled_features])\nprint(hash(enabled_features))\n```\n\nThis is the main reason to choose `FrozenList` instead of a plain list.\n\n## Make A New Editable Copy\n\n`freeze()` is one-way. If you need to keep editing, build a new `FrozenList` from the current items instead of trying to thaw the existing one:\n\n```python\nfrom frozenlist import FrozenList\n\nbase = FrozenList([\"read\", \"write\"])\nbase.freeze()\n\neditable = FrozenList(base)\neditable.append(\"admin\")\neditable.freeze()\n```\n\n## Type Hints\n\n`FrozenList` supports generic type syntax on Python 3.9+:\n\n```python\nfrom frozenlist import FrozenList\n\nnames: FrozenList[str] = FrozenList([\"alice\", \"bob\"])\nnames.freeze()\n```\n\n## Version Notes For 1.8.0\n\n- PyPI lists `1.8.0` as the current release and requires Python 3.9+.\n- The public runtime API remains the same small surface shown in the maintainer docs: `FrozenList`, `.frozen`, and `.freeze()`, plus standard `MutableSequence` behavior.\n- `1.7.0` added `copy.deepcopy()` support for `FrozenList`, so that behavior is available in `1.8.0`.\n- `1.8.0` changelog entries are packaging-focused. They add CPython 3.14 wheel builds and document `--config-settings=pure-python=true` for explicitly requesting a pure-Python build from source.\n\n## Common Pitfalls\n\n- Do not call `hash()` before `freeze()`. Upstream documents this as a `RuntimeError`.\n- Do not expect `freeze()` to be reversible. The docs expose no unfreeze API.\n- Do all list edits before freezing. Once frozen, methods like `append()`, `extend()`, item assignment, and deletion stop working.\n- `FrozenList` is list-like, not tuple-like. If you need a built-in immutable sequence and do not need staged mutation, a plain `tuple` may be simpler.\n- Build-only knobs like `FROZENLIST_CYTHON_TRACING` and `--config-settings=with-cython-tracing=true` are for debugging or packaging workflows, not normal runtime use.\n\n## Official Sources\n\n- Maintainer docs: https://frozenlist.aio-libs.org/en/latest/\n- Changelog: https://frozenlist.aio-libs.org/en/latest/changes.html\n- PyPI project page: https://pypi.org/project/frozenlist/\n"
  },
  {
    "path": "content/fsspec/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"fsspec package guide for Python - unified filesystem access across local, cloud, HTTP, and archive backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"fsspec,filesystem,storage,python,io\"\n---\n\n# fsspec Python Package Guide\n\n## Golden Rule\n\nUse `fsspec` as the filesystem abstraction layer, then install the protocol-specific backend you actually need. `fsspec` itself provides the interface and common helpers; cloud backends such as S3, GCS, and Azure usually come from companion packages like `s3fs`, `gcsfs`, and `adlfs`.\n\n## Install\n\n```bash\npip install fsspec==2026.2.0\n```\n\nCommon extras and companion installs:\n\n```bash\n# HTTP support helpers\npip install \"fsspec[http]==2026.2.0\"\n\n# S3 protocol\npip install \"fsspec[s3]==2026.2.0\"\n\n# GCS protocol\npip install \"fsspec[gcs]==2026.2.0\"\n\n# Azure Data Lake / Blob protocol\npip install \"fsspec[abfs]==2026.2.0\"\n```\n\nPractical rule:\n\n- `pip install fsspec` is enough for local files, in-memory filesystems, archives, and some built-in adapters.\n- Remote protocols often need extra dependencies. If `protocol not known` or an import error appears, install the matching extra or backend package first.\n\n## Core Mental Model\n\nThe main entry points are:\n\n- `fsspec.filesystem(protocol, **storage_options)` to create a filesystem instance.\n- `fsspec.open(url, mode=\"rb\", **storage_options)` for a single file handle.\n- `fsspec.open_files(urls, mode=\"rb\", **storage_options)` for many files.\n- `fsspec.url_to_fs(url, **storage_options)` when you need both the filesystem object and the normalized path.\n- `fsspec.get_mapper(url, **storage_options)` when a library expects a mutable-mapping interface instead of raw file handles.\n\nMinimal local example:\n\n```python\nimport fsspec\n\nwith fsspec.open(\"data/example.txt\", \"rt\", encoding=\"utf-8\") as f:\n    text = f.read()\n\nprint(text)\n```\n\nFilesystem object example:\n\n```python\nimport fsspec\n\nfs = fsspec.filesystem(\"file\")\n\nprint(fs.exists(\"data/example.txt\"))\nprint(fs.ls(\"data\"))\n\nwith fs.open(\"data/example.txt\", \"rt\", encoding=\"utf-8\") as f:\n    print(f.readline())\n```\n\n## Protocol Setup\n\n### Local, archive, and memory backends\n\nThese are the safest defaults for generic code:\n\n```python\nimport fsspec\n\nlocal_fs = fsspec.filesystem(\"file\")\nmemory_fs = fsspec.filesystem(\"memory\")\nzip_fs = fsspec.filesystem(\"zip\", fo=\"archive.zip\")\n```\n\n### HTTP and HTTPS\n\n`HTTPFileSystem` is built into `fsspec` and supports read-oriented access:\n\n```python\nimport fsspec\n\nwith fsspec.open(\"https://example.com/data.json\", \"rt\") as f:\n    body = f.read()\n```\n\nFor custom headers, auth tokens, timeouts, or block sizing, pass them as storage options:\n\n```python\nimport fsspec\n\nfs = fsspec.filesystem(\n    \"https\",\n    headers={\"Authorization\": \"Bearer TOKEN\"},\n    block_size=5 * 2**20,\n)\n\nwith fs.open(\"https://example.com/data.json\", \"rb\") as f:\n    payload = f.read()\n```\n\n### Cloud backends\n\nBackends such as S3, GCS, and Azure are not implemented by `fsspec` alone. Install the matching backend and pass backend-specific options through `storage_options`:\n\n```python\nimport fsspec\n\nfs = fsspec.filesystem(\n    \"s3\",\n    anon=False,\n    key=\"AWS_ACCESS_KEY_ID\",\n    secret=\"AWS_SECRET_ACCESS_KEY\",\n)\n\nwith fs.open(\"s3://my-bucket/path/data.parquet\", \"rb\") as f:\n    chunk = f.read(1024)\n```\n\nIf a library already has credentials in environment variables or provider config files, prefer that instead of hard-coding secrets in code.\n\n## Common Usage Patterns\n\n### Open many files at once\n\n```python\nimport fsspec\n\nfiles = fsspec.open_files(\"logs/part-*.json\", mode=\"rt\")\n\nfor of in files:\n    with of as f:\n        print(f.readline())\n```\n\n### Resolve a URL into filesystem plus path\n\n```python\nimport fsspec\n\nfs, path = fsspec.url_to_fs(\"s3://my-bucket/table/date=2026-03-11/file.parquet\")\nprint(type(fs).__name__, path)\n```\n\nUse this when downstream code wants `fs` and `path` separately.\n\n### Expose object storage as a key-value store\n\n```python\nimport fsspec\n\nmapper = fsspec.get_mapper(\"memory://cache\")\nmapper[\"example\"] = b\"hello\"\nprint(mapper[\"example\"])\n```\n\nThis pattern is common with Zarr and similar libraries.\n\n### Work with chained URLs\n\n`fsspec` supports compound URLs for cases like archives on remote stores:\n\n```python\nimport fsspec\n\nwith fsspec.open(\n    \"zip://data.csv::simplecache::https://example.com/archive.zip\",\n    \"rt\",\n) as f:\n    print(f.readline())\n```\n\nThe chained-protocol syntax is powerful but brittle. Keep each protocol's options explicit and test the exact URL form you ship.\n\n## Config and Authentication\n\n`fsspec` can read protocol configuration from config files and environment variables, then merge that with options passed directly in code.\n\nUseful rules:\n\n- Direct kwargs on `filesystem()` and `open()` win for the current call.\n- Protocol-specific credentials usually belong to the backend package, not to `fsspec` itself.\n- Prefer provider-native environment variables or shared credentials files for production secrets.\n\nExample with explicit storage options:\n\n```python\nimport fsspec\n\nstorage_options = {\n    \"anon\": False,\n    \"client_kwargs\": {\"region_name\": \"us-west-2\"},\n}\n\nwith fsspec.open(\n    \"s3://my-bucket/dataset.csv\",\n    \"rt\",\n    **storage_options,\n) as f:\n    print(f.readline())\n```\n\nThe official features docs also describe config discovery under an `fsspec` config directory plus `FSSPEC_<protocol>` style environment variables. That section is useful, but the current docs use inconsistent variable naming for the config-directory override, so verify the exact env var against your installed version before automating around it.\n\n## Integration Notes\n\n### Pandas and PyArrow\n\nMany libraries already accept `fsspec` URLs and `storage_options` directly:\n\n```python\nimport pandas as pd\n\ndf = pd.read_csv(\n    \"https://example.com/data.csv\",\n    storage_options={},\n)\n```\n\nFor object stores, pass the same storage options you would pass to `fsspec.open()`.\n\n### Instance caching\n\nFilesystem instances are often cached by protocol and arguments. This is convenient, but it can surprise tests and short-lived scripts.\n\nIf you need a fresh instance, pass:\n\n```python\nimport fsspec\n\nfs = fsspec.filesystem(\"file\", skip_instance_cache=True)\n```\n\n## Common Pitfalls\n\n- `fsspec` is not a full cloud SDK. Installing `fsspec` alone does not give you S3, GCS, or Azure support.\n- Use text mode explicitly. `fsspec.open()` defaults to binary-style patterns in many examples, so use `\"rt\"` plus `encoding=\"utf-8\"` when you want decoded text.\n- Always use context managers. `OpenFile` objects delay opening until `with ... as f:`.\n- URL chaining is easy to get wrong. Validate protocol order and storage options with a real integration test.\n- Listing caches can become stale on changing backends. If results look wrong after writes or deletes, invalidate caches or create a fresh filesystem instance.\n- Not every backend supports the same operations or transaction semantics. Check the backend's own docs before assuming rename, append, glob, async, or write guarantees.\n\n## Version-Sensitive Notes\n\n- PyPI shows `fsspec` `2026.2.0` as the current package version covered here.\n- PyPI requires Python `>=3.10` for this release family.\n- The official docs URL supplied for this session points to the Read the Docs `latest` build, but that site is currently rendered from a `2025.12.0+` development snapshot. Treat it as the canonical usage guide for stable APIs, but double-check version-sensitive behavior against the installed `2026.2.0` package when relying on newly added kwargs, async behavior, or config details.\n- The upstream changelog notes that Python 3.9 support was dropped in the `2025.12.0` line. Do not assume Python 3.9 compatibility for `2026.2.0`.\n\n## Official Sources\n\n- Docs root: https://filesystem-spec.readthedocs.io/en/latest/\n- Usage guide: https://filesystem-spec.readthedocs.io/en/latest/usage.html\n- Features guide: https://filesystem-spec.readthedocs.io/en/latest/features.html\n- Async docs: https://filesystem-spec.readthedocs.io/en/latest/async.html\n- API reference: https://filesystem-spec.readthedocs.io/en/latest/api.html\n- Changelog: https://filesystem-spec.readthedocs.io/en/latest/changelog.html\n- PyPI package: https://pypi.org/project/fsspec/\n"
  },
  {
    "path": "content/gatsby/docs/gatsby/javascript/DOC.md",
    "content": "---\nname: gatsby\ndescription: \"Gatsby JavaScript guide for creating React-based static sites with file routes, GraphQL data queries, plugins, images, and build-time page generation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.16.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"gatsby,javascript,react,graphql,ssg,meta-framework\"\n---\n\n# Gatsby JavaScript Guide\n\n## Golden Rule\n\nFor `gatsby@5.16.1`, treat Gatsby as a React framework with build-time data loading:\n\n- put URL-based pages in `src/pages/`\n- configure site metadata and plugins in `gatsby-config.js`\n- use `gatsby-node.js` for build-time APIs such as `createPages`\n- use page queries only in page components and templates\n- use `useStaticQuery()` for shared components that are not pages\n- use `Link` for internal navigation and `Head` for document metadata\n\nThere is no Gatsby client to initialize and no framework-level auth step. Setup is package installation, config files, plugins, environment variables, and React components.\n\n## Install\n\nFor a new site, use Gatsby's project initializer:\n\n```bash\nnpm init gatsby\ncd my-site\nnpm run develop\n```\n\nTo add Gatsby to an existing JavaScript project:\n\n```bash\nnpm install gatsby@5.16.1 react react-dom\n```\n\nAdd the standard scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"develop\": \"gatsby develop\",\n    \"build\": \"gatsby build\",\n    \"serve\": \"gatsby serve\",\n    \"clean\": \"gatsby clean\"\n  }\n}\n```\n\n## Minimal Project Setup\n\nCreate the core files:\n\n```text\ngatsby-config.js\nsrc/pages/index.js\nsrc/pages/about.js\n```\n\n`gatsby-config.js`:\n\n```js\nrequire('dotenv').config({\n  path: `.env.${process.env.NODE_ENV}`,\n})\n\nmodule.exports = {\n  siteMetadata: {\n    title: 'My Gatsby Site',\n    siteUrl: process.env.GATSBY_SITE_URL || 'http://localhost:8000',\n  },\n  plugins: [],\n}\n```\n\n`src/pages/index.js`:\n\n```js\nimport * as React from 'react'\nimport { Link, graphql } from 'gatsby'\n\nexport default function HomePage({ data }) {\n  return (\n    <main>\n      <h1>{data.site.siteMetadata.title}</h1>\n      <p>Welcome to Gatsby.</p>\n      <Link to=\"/about/\">About</Link>\n    </main>\n  )\n}\n\nexport const query = graphql`\n  query HomePageQuery {\n    site {\n      siteMetadata {\n        title\n      }\n    }\n  }\n`\n\nexport function Head() {\n  return (\n    <>\n      <title>Home</title>\n      <meta name=\"description\" content=\"Homepage for my Gatsby site\" />\n    </>\n  )\n}\n```\n\n`src/pages/about.js`:\n\n```js\nimport * as React from 'react'\nimport { Link } from 'gatsby'\n\nexport default function AboutPage() {\n  return (\n    <main>\n      <h1>About</h1>\n      <p>This page is created automatically from its file path.</p>\n      <Link to=\"/\">Back home</Link>\n    </main>\n  )\n}\n```\n\nRun local development:\n\n```bash\nnpm run develop\n```\n\nDuring development, Gatsby exposes GraphiQL at `http://localhost:8000/___graphql` so you can inspect the schema and test queries.\n\n## Environment Variables\n\nGatsby supports environment-specific `.env.*` files, but browser-exposed variables must be prefixed with `GATSBY_`.\n\n`.env.development`:\n\n```dotenv\nCMS_API_TOKEN=secret-build-token\nGATSBY_SITE_URL=http://localhost:8000\nGATSBY_PUBLIC_API_BASE=https://api.example.com\n```\n\nLoad variables in Node-side Gatsby files such as `gatsby-config.js` or `gatsby-node.js`:\n\n```js\nrequire('dotenv').config({\n  path: `.env.${process.env.NODE_ENV}`,\n})\n\nconsole.log(process.env.CMS_API_TOKEN)\nconsole.log(process.env.GATSBY_SITE_URL)\n```\n\nUse only `GATSBY_` variables in browser-rendered React code:\n\n```js\nimport * as React from 'react'\n\nexport default function SettingsPage() {\n  return <pre>{process.env.GATSBY_PUBLIC_API_BASE}</pre>\n}\n```\n\nIf a variable is not prefixed with `GATSBY_`, do not expect it to be available in page components or other client-side code.\n\n## Query Data In Pages\n\nPage components can export a GraphQL page query. Gatsby injects the result into the component as the `data` prop.\n\n```js\nimport * as React from 'react'\nimport { graphql } from 'gatsby'\n\nexport default function SiteInfoPage({ data }) {\n  const { title, siteUrl } = data.site.siteMetadata\n\n  return (\n    <main>\n      <h1>{title}</h1>\n      <p>{siteUrl}</p>\n    </main>\n  )\n}\n\nexport const query = graphql`\n  query SiteInfoPageQuery {\n    site {\n      siteMetadata {\n        title\n        siteUrl\n      }\n    }\n  }\n`\n```\n\nUse page queries in:\n\n- files under `src/pages/`\n- page template components used by `createPage()`\n\nDo not put page queries in shared UI components. Gatsby only runs them for page components and templates.\n\n## Query Shared Data With `useStaticQuery`\n\nFor headers, footers, nav, and other shared components, use `useStaticQuery()`.\n\n`src/components/site-header.js`:\n\n```js\nimport * as React from 'react'\nimport { graphql, Link, useStaticQuery } from 'gatsby'\n\nexport default function SiteHeader() {\n  const data = useStaticQuery(graphql`\n    query SiteHeaderQuery {\n      site {\n        siteMetadata {\n          title\n        }\n      }\n    }\n  `)\n\n  return (\n    <header>\n      <Link to=\"/\">{data.site.siteMetadata.title}</Link>\n    </header>\n  )\n}\n```\n\nUse this pattern when the query is static and reused across multiple pages.\n\n## Add Optimized Images\n\nFor Gatsby image optimization, install the image plugin and its Sharp dependencies:\n\n```bash\nnpm install gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp\n```\n\nEnable them in `gatsby-config.js`:\n\n```js\nrequire('dotenv').config({\n  path: `.env.${process.env.NODE_ENV}`,\n})\n\nmodule.exports = {\n  siteMetadata: {\n    title: 'My Gatsby Site',\n    siteUrl: process.env.GATSBY_SITE_URL || 'http://localhost:8000',\n  },\n  plugins: [\n    'gatsby-plugin-image',\n    'gatsby-plugin-sharp',\n    'gatsby-transformer-sharp',\n  ],\n}\n```\n\nUse `StaticImage` for straightforward images referenced directly from a component:\n\n```js\nimport * as React from 'react'\nimport { StaticImage } from 'gatsby-plugin-image'\n\nexport default function AboutPage() {\n  return (\n    <main>\n      <h1>About</h1>\n      <StaticImage\n        src=\"../images/team.jpg\"\n        alt=\"Team working together\"\n        width={720}\n        placeholder=\"blurred\"\n      />\n    </main>\n  )\n}\n```\n\nIf you need GraphQL-driven image data, use `GatsbyImage` with a file query instead. For simple local assets, `StaticImage` is the fastest path.\n\n## Create Pages Programmatically\n\nUse `gatsby-node.js` when routes depend on build-time data rather than the file system alone.\n\n`gatsby-node.js`:\n\n```js\nexports.createPages = async ({ actions }) => {\n  const { createPage } = actions\n\n  const docsPages = [\n    { slug: '/docs/getting-started/', title: 'Getting Started' },\n    { slug: '/docs/deploying/', title: 'Deploying' },\n  ]\n\n  docsPages.forEach((page) => {\n    createPage({\n      path: page.slug,\n      component: require.resolve('./src/templates/doc-page.js'),\n      context: {\n        title: page.title,\n      },\n    })\n  })\n}\n```\n\n`src/templates/doc-page.js`:\n\n```js\nimport * as React from 'react'\n\nexport default function DocPage({ pageContext }) {\n  return (\n    <main>\n      <h1>{pageContext.title}</h1>\n      <p>This page was created with Gatsby's Node API.</p>\n    </main>\n  )\n}\n```\n\nUse `context` for small route-specific values you need in the generated page. For larger content datasets, create the page from sourced data and query that data in the template.\n\n## Common Commands\n\n```bash\nnpm run develop\nnpm run build\nnpm run serve\nnpm run clean\n```\n\n- `develop` starts the local dev server\n- `build` creates the production site\n- `serve` serves the built output locally\n- `clean` removes Gatsby caches and generated artifacts\n\n`gatsby clean` is useful when schema changes, plugin changes, or stale caches cause confusing local failures.\n\n## Common Pitfalls\n\n- Use `Link` from `gatsby` for internal links. Use a normal `<a>` for external URLs.\n- Keep secrets in unprefixed variables and access them only in Node-side Gatsby files.\n- Prefix browser-exposed variables with `GATSBY_`, or they will not be available in client code.\n- Keep page queries in page components and templates only; use `useStaticQuery()` elsewhere.\n- Add the Sharp companion plugins when using `gatsby-plugin-image`, or image processing will not work.\n- Prefer the built-in `Head` export for page metadata rather than older third-party head-management patterns.\n\n## Version Notes\n\nThis guide targets `gatsby@5.16.1` and uses the current Gatsby v5 conventions documented by the maintainer docs: file-based pages in `src/pages/`, `Head` exports for metadata, `Link` for internal routing, GraphQL page queries, `useStaticQuery()` for shared components, and the Gatsby Image plugin stack for optimized images.\n"
  },
  {
    "path": "content/gemini/docs/deep-research/javascript/DOC.md",
    "content": "---\nname: deep-research\ndescription: \"Gemini Deep Research API via the Interactions endpoint for autonomous multi-step research with structured reports\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.33.0\"\n  revision: 2\n  updated-on: \"2026-03-09\"\n  source: community\n  tags: \"gemini,google,deep-research,research,interactions,agent\"\n---\n\n# Gemini Deep Research API (JavaScript/TypeScript)\n\nThe Deep Research API lets you run Google's autonomous research agent\nprogrammatically. It performs multi-step web research and returns structured\nmarkdown reports. This uses the **Interactions API** — the recommended way to\ninteract with Gemini models and agents.\n\n## Official References\n\n- [Interactions API Guide](https://ai.google.dev/gemini-api/docs/interactions)\n- [Deep Research Agent Guide](https://ai.google.dev/gemini-api/docs/deep-research)\n\n## Key Concepts\n\n- **Interactions API**: Unified interface for Gemini models and agents, with server-side state management\n- **Asynchronous**: Create a background interaction, then poll for completion (typically 5–15 minutes)\n- **Agent model**: `deep-research-pro-preview-12-2025` (the only available agent as of March 2026)\n- **SDK**: `@google/genai` >= 1.33.0 wraps the Interactions API natively\n- **Output**: Markdown report with citations and structured sections\n\n## Installation\n\n```bash\nnpm install @google/genai\n```\n\n## Authentication\n\nSet `GEMINI_API_KEY` environment variable — the SDK picks it up automatically.\n\n```typescript\n// Or pass directly\nimport { GoogleGenAI } from \"@google/genai\";\nconst client = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });\n```\n\n## Quick Start\n\n```typescript\nimport { GoogleGenAI } from \"@google/genai\";\n\nconst client = new GoogleGenAI({});\n\n// Start background research\nconst initialInteraction = await client.interactions.create({\n  agent: \"deep-research-pro-preview-12-2025\",\n  input: \"Research the current state of AI in disaster relief operations.\",\n  background: true,\n});\n\n// Poll for results\nwhile (true) {\n  const interaction = await client.interactions.get(initialInteraction.id);\n  if (interaction.status === \"completed\") {\n    console.log(interaction.outputs[interaction.outputs.length - 1].text);\n    break;\n  } else if ([\"failed\", \"cancelled\"].includes(interaction.status)) {\n    console.log(`Failed: ${interaction.status}`);\n    break;\n  }\n  await new Promise((resolve) => setTimeout(resolve, 10000));\n}\n```\n\n## Complete Example with Error Handling\n\n```typescript\nimport { GoogleGenAI } from \"@google/genai\";\nimport fs from \"fs/promises\";\n\nconst client = new GoogleGenAI({});\n\nasync function deepResearch(query: string, timeoutMinutes = 60): Promise<string> {\n  // Start background research\n  const initialInteraction = await client.interactions.create({\n    agent: \"deep-research-pro-preview-12-2025\",\n    input: query,\n    background: true,\n  });\n  console.log(`Research started: ${initialInteraction.id}`);\n\n  // Poll for completion\n  const deadline = Date.now() + timeoutMinutes * 60 * 1000;\n\n  while (Date.now() < deadline) {\n    await new Promise((r) => setTimeout(r, 10_000));\n\n    try {\n      const interaction = await client.interactions.get(initialInteraction.id);\n\n      if (interaction.status === \"completed\") {\n        const outputs = interaction.outputs;\n        if (outputs && outputs.length > 0) {\n          return outputs[outputs.length - 1].text;\n        }\n        return \"No content in response\";\n      }\n\n      if ([\"failed\", \"cancelled\"].includes(interaction.status)) {\n        throw new Error(`Research ${interaction.status}`);\n      }\n    } catch (e: any) {\n      // Retry on transient errors, throw on fatal\n      if (e.message?.includes(\"Research failed\") || e.message?.includes(\"Research cancelled\")) {\n        throw e;\n      }\n      console.warn(`Poll error (retrying): ${e.message}`);\n    }\n  }\n\n  throw new Error(`Research timed out after ${timeoutMinutes} minutes`);\n}\n\n// Usage\nconst report = await deepResearch(\"Current state of AI in disaster relief operations\");\nawait fs.writeFile(\"report.md\", report);\nconsole.log(\"Report saved.\");\n```\n\n## Optional: Generate a Research Plan First\n\nFor higher quality results, generate a structured research plan before\nsending to Deep Research:\n\n```typescript\nconst planInteraction = await client.interactions.create({\n  model: \"gemini-2.5-pro\",\n  input: `Create a detailed research plan for: \"${topic}\". Break it into key areas and questions.`,\n});\nconst plan = planInteraction.outputs[planInteraction.outputs.length - 1].text;\n\n// Pass the refined plan to Deep Research\nconst report = await deepResearch(`Execute the following research plan:\\n\\n${plan}`);\n```\n\n## Stateful Conversations with Deep Research\n\nThe Interactions API supports server-side conversation state. You can\nchain interactions using `previousInteractionId`:\n\n```typescript\n// First research task\nconst interaction1 = await client.interactions.create({\n  agent: \"deep-research-pro-preview-12-2025\",\n  input: \"Research quantum computing breakthroughs in 2026.\",\n  background: true,\n});\n// ... poll until complete ...\n\n// Follow-up referencing previous context\nconst interaction2 = await client.interactions.create({\n  agent: \"deep-research-pro-preview-12-2025\",\n  input: \"Now compare these breakthroughs with classical computing limitations.\",\n  background: true,\n  previousInteractionId: interaction1.id,\n});\n```\n\n## Parameters\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `input` | string | Yes | The research query or topic |\n| `agent` | string | Yes | Must be `deep-research-pro-preview-12-2025` |\n| `background` | boolean | Yes | Set to `true` for async execution |\n| `previousInteractionId` | string | No | Chain to a previous interaction for context |\n\n## Status Values\n\n| Status | Meaning |\n|--------|---------|\n| `in_progress` | Agent is still researching |\n| `completed` | Report is ready in `outputs[last].text` |\n| `failed` | Research failed — check error |\n| `cancelled` | Research was cancelled |\n\n## Tips and Gotchas\n\n- **Long-running**: Expect 5–15 minutes per research task. Max research time is 60 minutes.\n- **No streaming**: Deep Research does not support streaming. You must poll via `client.interactions.get()`.\n- **Rate limits**: The Interactions API has separate rate limits from `generateContent`. Expect lower throughput.\n- **Report quality**: The agent performs real web searches. More specific queries produce better reports.\n- **Plan first**: For best results, generate a research plan with a standard model first, then pass it to Deep Research.\n- **Agent name**: As of March 2026, the only available agent is `deep-research-pro-preview-12-2025`.\n- **Audio inputs not supported**: The Deep Research agent does not accept audio inputs.\n- **Output is markdown**: Reports come back as structured markdown with headers, bullet points, and citations.\n- **Google Search is built-in**: The agent uses Google Search by default. Grounding restrictions apply to results.\n\n## Migration from Raw REST\n\nIf you previously used raw REST calls to `https://generativelanguage.googleapis.com/v1beta/interactions`,\nthe SDK is now the recommended approach. The `client.interactions.create()` and\n`client.interactions.get()` methods handle authentication, serialization, and\nerror handling automatically.\n"
  },
  {
    "path": "content/gemini/docs/deep-research/python/DOC.md",
    "content": "---\nname: deep-research\ndescription: \"Gemini Deep Research API via the Interactions endpoint for autonomous multi-step research with structured reports\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.55.0\"\n  revision: 2\n  updated-on: \"2026-03-09\"\n  source: community\n  tags: \"gemini,google,deep-research,research,interactions,agent\"\n---\n\n# Gemini Deep Research API (Python)\n\nThe Deep Research API lets you run Google's autonomous research agent\nprogrammatically. It performs multi-step web research and returns structured\nmarkdown reports. This uses the **Interactions API** — the recommended way to\ninteract with Gemini models and agents.\n\n## Official References\n\n- [Interactions API Guide](https://ai.google.dev/gemini-api/docs/interactions)\n- [Deep Research Agent Guide](https://ai.google.dev/gemini-api/docs/deep-research)\n\n## Key Concepts\n\n- **Interactions API**: Unified interface for Gemini models and agents, with server-side state management\n- **Asynchronous**: Create a background interaction, then poll for completion (typically 5–15 minutes)\n- **Agent model**: `deep-research-pro-preview-12-2025` (the only available agent as of March 2026)\n- **SDK**: `google-genai` >= 1.55.0 wraps the Interactions API natively\n- **Output**: Markdown report with citations and structured sections\n\n## Installation\n\n```bash\npip install -U google-genai\n```\n\n**Important**: The package is `google-genai`, NOT the deprecated `google-generativeai`.\n\n## Authentication\n\nSet `GEMINI_API_KEY` environment variable — the SDK picks it up automatically.\n\n```python\nimport os\nos.environ[\"GEMINI_API_KEY\"] = \"your-api-key\"\n```\n\n## Quick Start\n\n```python\nimport time\nfrom google import genai\n\nclient = genai.Client()\n\n# Start background research\ninteraction = client.interactions.create(\n    agent=\"deep-research-pro-preview-12-2025\",\n    input=\"Research the current state of AI in disaster relief operations.\",\n    background=True,\n)\n\n# Poll for results\nwhile True:\n    interaction = client.interactions.get(interaction.id)\n    if interaction.status == \"completed\":\n        print(interaction.outputs[-1].text)\n        break\n    elif interaction.status == \"failed\":\n        print(f\"Failed: {interaction.error}\")\n        break\n    time.sleep(10)\n```\n\n## Complete Example with Error Handling\n\n```python\nimport time\nfrom pathlib import Path\nfrom google import genai\n\nclient = genai.Client()\n\n\ndef deep_research(query: str, timeout_minutes: int = 60) -> str:\n    \"\"\"Run Gemini Deep Research and return the markdown report.\"\"\"\n    # Start background research\n    interaction = client.interactions.create(\n        agent=\"deep-research-pro-preview-12-2025\",\n        input=query,\n        background=True,\n    )\n    print(f\"Research started: {interaction.id}\")\n\n    # Poll for completion\n    deadline = time.time() + timeout_minutes * 60\n\n    while time.time() < deadline:\n        time.sleep(10)\n\n        try:\n            interaction = client.interactions.get(interaction.id)\n        except Exception as e:\n            print(f\"Poll error (retrying): {e}\")\n            continue\n\n        if interaction.status == \"completed\":\n            if interaction.outputs:\n                return interaction.outputs[-1].text\n            return \"No content in response\"\n\n        if interaction.status in (\"failed\", \"cancelled\"):\n            raise RuntimeError(f\"Research {interaction.status}: {interaction.error}\")\n\n    raise TimeoutError(f\"Research timed out after {timeout_minutes} minutes\")\n\n\n# Usage\nreport = deep_research(\"Current state of AI in disaster relief operations\")\nPath(\"report.md\").write_text(report)\nprint(\"Report saved.\")\n```\n\n## Optional: Generate a Research Plan First\n\nFor higher quality results, generate a structured research plan before\nsending to Deep Research:\n\n```python\nfrom google import genai\n\nclient = genai.Client()\n\n# Generate plan using a standard model\nplan_interaction = client.interactions.create(\n    model=\"gemini-2.5-pro\",\n    input=f'Create a detailed research plan for: \"{topic}\". '\n          \"Break it into key areas and questions. Be concise but comprehensive.\",\n)\nplan = plan_interaction.outputs[-1].text\n\n# Pass the refined plan to Deep Research\nreport = deep_research(f\"Execute the following research plan:\\n\\n{plan}\")\n```\n\n## Stateful Conversations with Deep Research\n\nThe Interactions API supports server-side conversation state. You can\nchain interactions using `previous_interaction_id`:\n\n```python\n# First research task\ninteraction1 = client.interactions.create(\n    agent=\"deep-research-pro-preview-12-2025\",\n    input=\"Research quantum computing breakthroughs in 2026.\",\n    background=True,\n)\n# ... poll until complete ...\n\n# Follow-up referencing previous context\ninteraction2 = client.interactions.create(\n    agent=\"deep-research-pro-preview-12-2025\",\n    input=\"Now compare these breakthroughs with classical computing limitations.\",\n    background=True,\n    previous_interaction_id=interaction1.id,\n)\n```\n\n## Parameters\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `input` | string | Yes | The research query or topic |\n| `agent` | string | Yes | Must be `deep-research-pro-preview-12-2025` |\n| `background` | boolean | Yes | Set to `True` for async execution |\n| `previous_interaction_id` | string | No | Chain to a previous interaction for context |\n\n## Status Values\n\n| Status | Meaning |\n|--------|---------|\n| `in_progress` | Agent is still researching |\n| `completed` | Report is ready in `outputs[-1].text` |\n| `failed` | Research failed — check `error` field |\n| `cancelled` | Research was cancelled |\n\n## Tips and Gotchas\n\n- **Long-running**: Expect 5–15 minutes per research task. Max research time is 60 minutes.\n- **No streaming**: Deep Research does not support streaming. You must poll via `client.interactions.get()`.\n- **Rate limits**: The Interactions API has separate rate limits from `generateContent`. Expect lower throughput.\n- **Report quality**: The agent performs real web searches. More specific queries produce better reports.\n- **Plan first**: For best results, generate a research plan with a standard model first, then pass it to Deep Research.\n- **Agent name**: As of March 2026, the only available agent is `deep-research-pro-preview-12-2025`.\n- **Audio inputs not supported**: The Deep Research agent does not accept audio inputs.\n- **Output is markdown**: Reports come back as structured markdown with headers, bullet points, and citations.\n- **Google Search is built-in**: The agent uses Google Search by default. Grounding restrictions apply to results.\n\n## Migration from Raw REST\n\nIf you previously used raw REST calls to `https://generativelanguage.googleapis.com/v1beta/interactions`,\nthe SDK is now the recommended approach. The `client.interactions.create()` and\n`client.interactions.get()` methods handle authentication, serialization, and\nerror handling automatically.\n"
  },
  {
    "path": "content/gemini/docs/genai/javascript/DOC.md",
    "content": "---\nname: genai\ndescription: \"Google Gemini GenAI SDK for multimodal LLM interactions, image generation (Nano Banana), and video generation in JavaScript/TypeScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.43.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"gemini,google,genai,llm,multimodal,nano banana,imagen,image generation,veo,video generation\"\n---\n\n# Gemini API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Gemini API coding expert. Help me with writing code using the Gemini\nAPI calling the official libraries and SDKs.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://googleapis.github.io/js-genai/\n\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Google Gen AI SDK to call the Gemini models, which is the\nstandard library for all Gemini API interactions. Do not use legacy libraries\nand SDKs.\n\n- **Library Name:** Google Gen AI SDK\n- **NPM Package:** `@google/genai`\n- **Legacy Libraries**: (`@google/generative-ai`) are deprecated\n\n**Installation:**\n\n- **Incorrect:** `npm install @google/generative-ai`\n- **Incorrect:** `npm install @google-ai/generativelanguage`\n- **Correct:** `npm install @google/genai`\n\n**APIs and Usage:**\n\n- **Incorrect:** `const { GenerativeModel } =\n    require('@google/generative-ai')` -> **Correct:** `import { GoogleGenAI }\n    from '@google/genai'`\n- **Incorrect:** `const model = genai.getGenerativeModel(...)` -> **Correct:**\n    `const ai = new GoogleGenAI({apiKey: \"...\"})`\n- **Incorrect:** `await model.generateContent(...)` -> **Correct:** `await\n    ai.models.generateContent(...)`\n- **Incorrect:** `await model.generateContentStream(...)` -> **Correct:**\n    `await ai.models.generateContentStream(...)`\n- **Incorrect:** `const generationConfig = { ... }` -> **Correct:** Pass\n    configuration directly: `config: { safetySettings: [...] }`\n- **Incorrect** `GoogleGenerativeAI`\n- **Incorrect** `google.generativeai`\n- **Incorrect** `models.create`\n- **Incorrect** `ai.models.create`\n- **Incorrect** `models.getGenerativeModel`\n- **Incorrect** `ai.models.getModel`\n- **Incorrect** `ai.models['model_name']`\n- **Incorrect** `generationConfig`\n- **Incorrect** `GoogleGenAIError` -> **Correct** `ApiError`\n- **Incorrect** `GenerateContentResult` -> **Correct**\n    `GenerateContentResponse`.\n- **Incorrect** `GenerateContentRequest` -> **Correct**\n    `GenerateContentParameters`\n\n## Initialization and API key\n\nThe `@google/genai` library requires creating a `GoogleGenAI` instance for all\nAPI calls.\n\n- Always use `const ai = new GoogleGenAI({})` to create an instance.\n- Set the `GEMINI_API_KEY` environment variable, which will be picked up\n    automatically in Node.js environments.\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\n\n// Uses the GEMINI_API_KEY environment variable if apiKey not specified\nconst ai = new GoogleGenAI({});\n\n// Or pass the API key directly\n// const ai = new GoogleGenAI({apiKey: process.env.GEMINI_API_KEY});\n```\n\n## Models\n\n- By default, use the following models as of March 2026:\n    - **General Text & Multimodal Tasks:** `gemini-2.5-flash`\n    - **Coding and Complex Reasoning Tasks:** `gemini-2.5-pro`\n    - **Image Generation Tasks:** `imagen-4.0-fast-generate-001`,\n        `imagen-4.0-generate-001` or `imagen-4.0-ultra-generate-001`\n    - **Image Editing Tasks:** `gemini-2.5-flash-image-preview`\n    - **Video Generation Tasks:** `veo-3.0-fast-generate-preview` or\n        `veo-3.0-generate-preview`.\n\n- It is also acceptable to use the following model if explicitly requested by\n    the user:\n    - **Gemini 2.0 Series**: `gemini-2.0-flash`, `gemini-2.0-pro`\n\n- Do not use the following deprecated models (or their variants like\n    `gemini-1.5-flash-latest`):\n    - **Prohibited:** `gemini-1.5-flash`\n    - **Prohibited:** `gemini-1.5-pro`\n    - **Prohibited:** `gemini-pro`\n\n## Basic Inference (Text Generation)\n\nHere's how to generate a response from a text prompt.\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\n\nconst ai = new GoogleGenAI({}); // Assumes GEMINI_API_KEY is set\n\nasync function run() {\n  const response = await ai.models.generateContent({\n    model: 'gemini-2.5-flash',\n    contents: 'why is the sky blue?',\n  });\n\n  console.log(response.text); // output is often markdown\n}\n\nrun();\n```\n\nMultimodal inputs are supported by passing file data in the `contents` array.\n\n```javascript\nimport { GoogleGenAI, Part } from '@google/genai';\nimport * as fs from 'fs';\n\nconst ai = new GoogleGenAI({});\n\n// Converts local file information to a Part object.\nfunction fileToGenerativePart(path, mimeType): Part {\n  return {\n    inlineData: {\n      data: Buffer.from(fs.readFileSync(path)).toString(\"base64\"),\n      mimeType\n    },\n  };\n}\n\nasync function run() {\n    const imagePart = fileToGenerativePart(\"path/to/image.jpg\", \"image/jpeg\");\n\n    const response = await ai.models.generateContent({\n        model: 'gemini-2.5-flash',\n        contents: [imagePart, \"explain that image\"],\n    });\n\n    console.log(response.text); // The output often is markdown\n}\n\nrun();\n```\n\nYou can use this approach to pass a variety of data types (images, audio, video,\npdf). For PDF, use `application/pdf` as `mimeType`.\n\nFor larger files, use `ai.files.upload`:\n\n```javascript\nimport { GoogleGenAI, createPartFromUri, createUserContent } from '@google/genai';\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const f = await ai.files.upload({\n        file: 'path/to/sample.mp3',\n        config:{mimeType: 'audio/mp3'},\n    });\n\n    const response = await ai.models.generateContent({\n        model: 'gemini-2.5-flash',\n         contents: createUserContent([\n          createPartFromUri(f.uri, f.mimeType),\n          \"Describe this audio clip\"\n        ])\n    });\n\n    console.log(response.text);\n}\n\nrun();\n```\n\nYou can delete files after use like this:\n\n```javascript\nconst myFile = await ai.files.upload({file: 'path/to/sample.mp3', mimeType: 'audio/mp3'});\nawait ai.files.delete({name: myFile.name});\n```\n\n## Additional Capabilities and Configurations\n\nBelow are examples of advanced configurations.\n\n### Thinking\n\nGemini 2.5 series models support thinking, which is on by default for\n`gemini-2.5-flash`. It can be adjusted by using `thinking_budget` setting.\nSetting it to zero turns thinking off, and will reduce latency.\n\n```javascript\nimport { GoogleGenAI } from \"@google/genai\";\n\nconst ai = new GoogleGenAI({});\n\nasync function main() {\n  const response = await ai.models.generateContent({\n    model: \"gemini-2.5-pro\",\n    contents: \"Provide a list of 3 famous physicists and their key contributions\",\n    config: {\n      thinkingConfig: {\n        thinkingBudget: 1024,\n        // Turn off thinking:\n        // thinkingBudget: 0\n        // Turn on dynamic thinking:\n        // thinkingBudget: -1\n      },\n    },\n  });\n\n  console.log(response.text);\n}\n\nmain();\n```\n\nIMPORTANT NOTES:\n\n- Minimum thinking budget for `gemini-2.5-pro` is `128` and thinking can not\n    be turned off for that model.\n- No models (apart from Gemini 2.5 series) support thinking or thinking\n    budgets APIs. Do not try to adjust thinking budgets other models (such as\n    `gemini-2.0-flash` or `gemini-2.0-pro`) otherwise it will cause syntax\n    errors.\n\n### System instructions\n\nUse system instructions to guide the model's behavior.\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\n\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const response = await ai.models.generateContent({\n        model: 'gemini-2.5-flash',\n        contents: \"Hello.\",\n        config: {\n            systemInstruction: \"You are a pirate\",\n        }\n    });\n    console.log(response.text);\n}\nrun();\n```\n\n### Hyperparameters\n\nYou can also set `temperature` or `maxOutputTokens` within the `config` object.\n**Avoid** setting `maxOutputTokens`, `topP`, `topK` unless explicitly requested\nby the user.\n\n### Safety configurations\n\nAvoid setting safety configurations unless explicitly requested by the user. If\nexplicitly asked for by the user, here is a sample API:\n\n```javascript\nimport { GoogleGenAI, HarmCategory, HarmBlockThreshold, Part } from '@google/genai';\nimport * as fs from 'fs';\n\nconst ai = new GoogleGenAI({});\n\nfunction fileToGenerativePart(path, mimeType): Part {\n  return {\n    inlineData: {\n      data: Buffer.from(fs.readFileSync(path)).toString(\"base64\"),\n      mimeType\n    },\n  };\n}\n\nasync function run() {\n    const img = fileToGenerativePart(\"/path/to/img.jpg\", \"image/jpeg\");\n    const response = await ai.models.generateContent({\n        model: \"gemini-2.5-flash\",\n        contents: ['Do these look store-bought or homemade?', img],\n        config: {\n            safetySettings: [\n                {\n                    category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,\n                    threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n                },\n            ]\n        }\n    });\n    console.log(response.text);\n}\nrun();\n```\n\n### Streaming\n\nIt is possible to stream responses to reduce user perceived latency:\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n  const responseStream = await ai.models.generateContentStream({\n    model: \"gemini-2.5-flash\",\n    contents: [\"Explain how AI works\"],\n  });\n\n  for await (const chunk of responseStream) {\n    process.stdout.write(chunk.text);\n  }\n  console.log(); // for a final newline\n}\nrun();\n```\n\n### Chat\n\nFor multi-turn conversations, use the `chats` service to maintain conversation\nhistory.\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\n\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const chat = ai.chats.create({model: \"gemini-2.5-flash\"});\n\n    let response = await chat.sendMessage({message:\"I have 2 dogs in my house.\"});\n    console.log(response.text);\n\n    response = await chat.sendMessage({message: \"How many paws are in my house?\"});\n    console.log(response.text);\n\n    const history = await chat.getHistory();\n    for (const message of history) {\n        console.log(`role - ${message.role}: ${message.parts[0].text}`);\n    }\n}\nrun();\n``` It is also possible to use streaming with Chat:\n\n```javascript\n    const chat = ai.chats.create({model: \"gemini-2.5-flash\"});\n    const stream = await chat.sendMessageStream({message:\"I have 2 dogs in my house.\"});\n    for await (const chunk of stream) {\n      console.log(chunk.text);\n      console.log(\"_\".repeat(80));\n    }\n```\n\nNote: ai.chats.create({model}) returns `Chat` under `@google/genai` which tracks\nthe session.\n\n### Structured outputs\n\nAsk the model to return a response in JSON format.\n\nThe recommended way is to configure a `responseSchema` for the expected output.\n\nSee the available types below that can be used in the `responseSchema`.\n\n```javascript\nexport enum Type {\n  /**\n   * Not specified, should not be used.\n   */\n  TYPE_UNSPECIFIED = 'TYPE_UNSPECIFIED',\n  /**\n   * OpenAPI string type\n   */\n  STRING = 'STRING',\n  /**\n   * OpenAPI number type\n   */\n  NUMBER = 'NUMBER',\n  /**\n   * OpenAPI integer type\n   */\n  INTEGER = 'INTEGER',\n  /**\n   * OpenAPI boolean type\n   */\n  BOOLEAN = 'BOOLEAN',\n  /**\n   * OpenAPI array type\n   */\n  ARRAY = 'ARRAY',\n  /**\n   * OpenAPI object type\n   */\n  OBJECT = 'OBJECT',\n  /**\n   * Null type\n   */\n  NULL = 'NULL',\n}\n```\n\n`Type.OBJECT` cannot be empty; it must contain other properties.\n\n```javascript\nimport { GoogleGenAI, Type } from \"@google/genai\";\n\nconst ai = new GoogleGenAI({});\nconst response = await ai.models.generateContent({\n   model: \"gemini-2.5-flash\",\n   contents: \"List a few popular cookie recipes, and include the amounts of ingredients.\",\n   config: {\n     responseMimeType: \"application/json\",\n     responseSchema: {\n        type: Type.ARRAY,\n        items: {\n          type: Type.OBJECT,\n          properties: {\n            recipeName: {\n              type: Type.STRING,\n              description: 'The name of the recipe.',\n            },\n            ingredients: {\n              type: Type.ARRAY,\n              items: {\n                type: Type.STRING,\n              },\n              description: 'The ingredients for the recipe.',\n            },\n          },\n          propertyOrdering: [\"recipeName\", \"ingredients\"],\n        },\n      },\n   },\n});\n\nlet jsonStr = response.text.trim();\n```\n\nThe `jsonStr` might look like this:\n\n```javascript\n[\n  {\n    \"recipeName\": \"Chocolate Chip Cookies\",\n    \"ingredients\": [\n      \"1 cup (2 sticks) unsalted butter, softened\",\n      \"3/4 cup granulated sugar\",\n      \"3/4 cup packed brown sugar\",\n      \"1 teaspoon vanilla extract\",\n      \"2 large eggs\",\n      \"2 1/4 cups all-purpose flour\",\n      \"1 teaspoon baking soda\",\n      \"1 teaspoon salt\",\n      \"2 cups chocolate chips\"\n    ]\n  },\n  ...\n]\n```\n\n#### Function Calling (Tools)\n\nYou can provide the model with tools (functions) it can use to bring in external\ninformation to answer a question or act on a request outside the model.\n\n```javascript\nimport {GoogleGenAI, FunctionDeclaration, Type} from '@google/genai';\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const controlLightDeclaration = {\n        name: 'controlLight',\n        parameters: {\n          type: Type.OBJECT,\n          description: 'Set brightness and color temperature of a light.',\n          properties: {\n            brightness: { type: Type.NUMBER, description: 'Light level from 0 to 100.' },\n            colorTemperature: { type: Type.STRING, description: '`daylight`, `cool`, or `warm`.'},\n          },\n          required: ['brightness', 'colorTemperature'],\n        },\n    };\n\n    const response = await ai.models.generateContent({\n        model: 'gemini-2.5-flash',\n        contents: 'Dim the lights so the room feels cozy and warm.',\n        config: {\n            tools: [{functionDeclarations: [controlLightDeclaration]}]\n        }\n    });\n\n    if (response.functionCalls) {\n        console.log(response.functionCalls);\n        // In a real app, you would execute the function and send the result back.\n    }\n}\nrun();\n```\n\n### Generate Images\n\nHere's how to generate images using the Imagen models.\n\n```javascript\nimport { GoogleGenAI } from \"@google/genai\";\n\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const response = await ai.models.generateImages({\n        model: 'imagen-4.0-fast-generate-001',\n        prompt: 'A friendly robot holding a red skateboard, minimalist vector art',\n        config: {\n          numberOfImages: 1, // 1 to 4 (always 1 for the ultra model)\n          outputMimeType: 'image/jpeg',\n          aspectRatio: '1:1', // \"1:1\", \"3:4\", \"4:3\", \"9:16\", or \"16:9\"\n        },\n    });\n\n    const base64ImageBytes = response.generatedImages[0].image.imageBytes;\n    // This can be used directly in an <img> src attribute\n    const imageUrl = `data:image/jpeg;base64,${base64ImageBytes}`;\n    console.log(imageUrl);\n}\nrun();\n```\n\nNote: Do not include negativePrompts in config, it's not supported.\n\n### Edit Images\n\nEditing images is better done using the Gemini native image generation model.\nConfigs are not supported in this model (except modality).\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\n\nconst ai = new GoogleGenAI({});\n\nconst response = await ai.models.generateContent({\n  model: 'gemini-2.5-flash-image-preview',\n  contents: [imagePart, 'koala eating a nano banana']\n});\nfor (const part of response.candidates[0].content.parts) {\n  if (part.inlineData) {\n    const base64ImageBytes: string = part.inlineData.data;\n    const imageUrl = `data:image/png;base64,${base64ImageBytes}`;\n  }\n}\n```\n\n### Generate Videos\n\nHere's how to generate videos using the Veo models. Usage of Veo can be costly,\nso after generating code for it, give user a heads up to check pricing for Veo.\n\n```javascript\nimport { GoogleGenAI } from \"@google/genai\";\nimport { createWriteStream } from \"fs\";\nimport { Readable } from \"stream\";\n\nconst ai = new GoogleGenAI({});\n\nasync function main() {\n  let operation = await ai.models.generateVideos({\n    model: \"veo-3.0-fast-generate-preview\",\n    prompt: \"Panning wide shot of a calico kitten sleeping in the sunshine\",\n    config: {\n      personGeneration: \"dont_allow\",\n      aspectRatio: \"16:9\",\n    },\n  });\n\n  while (!operation.done) {\n    await new Promise((resolve) => setTimeout(resolve, 10000));\n    operation = await ai.operations.getVideosOperation({\n      operation: operation,\n    });\n  }\n\n  operation.response?.generatedVideos?.forEach(async (generatedVideo, n) => {\n    const resp = await fetch(`${generatedVideo.video?.uri}&key=GEMINI_API_KEY`); // append your API key\n    const writer = createWriteStream(`video${n}.mp4`);\n    Readable.fromWeb(resp.body).pipe(writer);\n  });\n}\n\nmain();\n```\n\n### Search Grounding\n\nGoogle Search can be used as a tool for grounding queries that with up to date\ninformation from the web.\n\n```javascript\nimport { GoogleGenAI } from \"@google/genai\";\n\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const response = await ai.models.generateContent({\n       model: \"gemini-2.5-flash\",\n       contents: \"Who won the latest F1 race?\",\n       config: {\n         tools: [{googleSearch: {}}],\n       },\n    });\n\n    console.log(\"Response:\", response.text);\n\n    // Extract and display grounding URLs\n    const searchChunks = response.candidates?.[0]?.groundingMetadata?.groundingChunks;\n    if (searchChunks) {\n        const urls = searchChunks.map(chunk => chunk.web.uri);\n        console.log(\"Sources:\", urls);\n    }\n}\nrun();\n```\n\n### Content and Part Hierarchy\n\nWhile the simpler API call is often sufficient, you may run into scenarios where\nyou need to work directly with the underlying `Content` and `Part` objects for\nmore explicit control. These are the fundamental building blocks of the\n`generateContent` API.\n\nFor instance, the following simple API call:\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const response = await ai.models.generateContent({\n        model: \"gemini-2.5-flash\",\n        contents: \"How does AI work?\",\n    });\n    console.log(response.text);\n}\nrun();\n```\n\nis effectively a shorthand for this more explicit structure:\n\n```javascript\nimport { GoogleGenAI } from '@google/genai';\nconst ai = new GoogleGenAI({});\n\nasync function run() {\n    const response = await ai.models.generateContent({\n        model: \"gemini-2.5-flash\",\n        contents: [\n            { role: \"user\", parts: [{ text: \"How does AI work?\" }] },\n        ],\n    });\n    console.log(response.text);\n}\nrun();\n```\n\n## API Errors\n\n`ApiError` from `@google/genai` extends from EcmaScript `Error` and has\n`message`, `name` fields in addition to `status` (HTTP Code).\n\n## Other APIs\n\nThe list of APIs and capabilities above are not comprehensive. If users ask you\nto generate code for a capability not provided above, refer them to\nhttps://googleapis.github.io/js-genai/.\n\n## Useful Links\n\n- Documentation: ai.google.dev/gemini-api/docs\n- API Keys and Authentication: ai.google.dev/gemini-api/docs/api-key\n- Models: ai.google.dev/models\n- API Pricing: ai.google.dev/pricing\n- Rate Limits: ai.google.dev/rate-limits\n"
  },
  {
    "path": "content/gemini/docs/genai/python/DOC.md",
    "content": "---\nname: genai\ndescription: \"Google Gemini GenAI SDK for multimodal LLM interactions, image generation (Nano Banana), and video generation in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.56.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"gemini,google,genai,llm,multimodal,nano banana,imagen,image generation,veo,video generation\"\n---\n\n# Gemini API Coding Guidelines (Python)\n\nYou are a Gemini API coding expert. Help me with writing code using the Gemini\nAPI calling the official libraries and SDKs.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://ai.google.dev/gemini-api/docs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Google GenAI SDK to call the Gemini models, which became the\nstandard library for all Gemini API interactions as of 2025. Do not use legacy\nlibraries and SDKs.\n\n- **Library Name:** Google GenAI SDK\n- **Python Package:** `google-genai`\n- **Legacy Library**: (`google-generativeai`) is deprecated.\n\n**Installation:**\n\n- **Incorrect:** `pip install google-generativeai`\n- **Incorrect:** `pip install google-ai-generativelanguage`\n- **Correct:** `pip install google-genai`\n\n**APIs and Usage:**\n\n- **Incorrect:** `import google.generativeai as genai`-> **Correct:** `from\n    google import genai`\n- **Incorrect:** `from google.ai import generativelanguage_v1`  ->\n    **Correct:** `from google import genai`\n- **Incorrect:** `from google.generativeai` -> **Correct:** `from google\n    import genai`\n- **Incorrect:** `from google.generativeai import types` -> **Correct:** `from\n    google.genai import types`\n- **Incorrect:** `import google.generativeai as genai` -> **Correct:** `from\n    google import genai`\n- **Incorrect:** `genai.configure(api_key=...)` -> **Correct:** `client =\n    genai.Client(api_key=\"...\")`\n- **Incorrect:** `model = genai.GenerativeModel(...)`\n- **Incorrect:** `model.generate_content(...)` -> **Correct:**\n    `client.models.generate_content(...)`\n- **Incorrect:** `response = model.generate_content(..., stream=True)` ->\n    **Correct:** `client.models.generate_content_stream(...)`\n- **Incorrect:** `genai.GenerationConfig(...)` -> **Correct:**\n    `types.GenerateContentConfig(...)`\n- **Incorrect:** `safety_settings={...}` -> **Correct:** Use `safety_settings`\n    inside a `GenerateContentConfig` object.\n- **Incorrect:** `from google.api_core.exceptions import GoogleAPIError` ->\n    **Correct:** `from google.genai.errors import APIError`\n- **Incorrect:** `types.ResponseModality.TEXT`\n\n## Initialization and API key\n\nThe `google-genai` library requires creating a client object for all API calls.\n\n- Always use `client = genai.Client()` to create a client object.\n- Set `GEMINI_API_KEY` environment variable, which will be picked up\n    automatically.\n\n## Models\n\n- By default, use the following models as of March 2026:\n    - **General Text & Multimodal Tasks:** `gemini-2.5-flash`\n    - **Coding and Complex Reasoning Tasks:** `gemini-2.5-pro`\n    - **Image Generation Tasks:** `imagen-4.0-fast-generate-001`,\n        `imagen-4.0-generate-001` or `imagen-4.0-ultra-generate-001`\n    - **Image Editing Tasks:** `gemini-2.5-flash-image-preview`\n    - **Video Generation Tasks:** `veo-3.0-fast-generate-preview` or\n        `veo-3.0-generate-preview`.\n\n- It is also acceptable to use following models if explicitly requested by the\n    user:\n    - **Gemini 2.0 Series**: `gemini-2.0-flash`, `gemini-2.0-pro`\n\n- Do not use the following deprecated models (or their variants like\n    `gemini-1.5-flash-latest`):\n    - **Prohibited:** `gemini-1.5-flash`\n    - **Prohibited:** `gemini-1.5-pro`\n    - **Prohibited:** `gemini-pro`\n\n## Basic Inference (Text Generation)\n\nHere's how to generate a response from a text prompt.\n\n```python\nfrom google import genai\n\nclient = genai.Client()\n\nresponse = client.models.generate_content(\n  model='gemini-2.5-flash',\n  contents='why is the sky blue?',\n)\n\nprint(response.text) # output is often markdown\n```\n\nMultimodal inputs are supported by passing a PIL-Image in the `contents` list:\n\n```python\nfrom google import genai\nfrom PIL import Image\n\nclient = genai.Client()\n\nimage = Image.open(img_path)\n\nresponse = client.models.generate_content(\n  model='gemini-2.5-flash',\n  contents=[image, \"explain that image\"],\n)\n\nprint(response.text) # The output often is markdown\n```\n\nYou can also use `Part.from_bytes` type to pass a variety of data types (images,\naudio, video, pdf).\n\n```python\nfrom google.genai import types\n\n  with open('path/to/small-sample.jpg', 'rb') as f:\n    image_bytes = f.read()\n\n  response = client.models.generate_content(\n    model='gemini-2.5-flash',\n    contents=[\n      types.Part.from_bytes(\n        data=image_bytes,\n        mime_type='image/jpeg',\n      ),\n      'Caption this image.'\n    ]\n  )\n\n  print(response.text)\n```\n\nFor larger files, use `client.files.upload`:\n\n```python\nf = client.files.upload(file=img_path)\n\nresponse = client.models.generate_content(\n    model='gemini-2.5-flash',\n    contents=[f, \"can you describe this image?\"]\n)\n```\n\nYou can delete files after use like this:\n\n```python\nmyfile = client.files.upload(file='path/to/sample.mp3')\nclient.files.delete(name=myfile.name)\n```\n\n## Additional Capabilities and Configurations\n\nBelow are examples of advanced configurations.\n\n### Thinking\n\nGemini 2.5 series models support thinking, which is on by default for\n`gemini-2.5-flash`. It can be adjusted by using `thinking_budget` setting.\nSetting it to zero turns thinking off, and will reduce latency.\n\n```python\nfrom google import genai\nfrom google.genai import types\n\nclient = genai.Client()\n\nclient.models.generate_content(\n  model='gemini-2.5-flash',\n  contents=\"What is AI?\",\n  config=types.GenerateContentConfig(\n    thinking_config=types.ThinkingConfig(\n      thinking_budget=0\n    )\n  )\n)\n```\n\nIMPORTANT NOTES:\n\n- Minimum thinking budget for `gemini-2.5-pro` is `128` and thinking can not\n    be turned off for that model.\n- No models (apart from Gemini 2.5 series) support thinking or thinking\n    budgets APIs. Do not try to adjust thinking budgets other models (such as\n    `gemini-2.0-flash` or `gemini-2.0-pro`) otherwise it will cause syntax\n    errors.\n\n### System instructions\n\nUse system instructions to guide model's behavior.\n\n```python\nfrom google import genai\nfrom google.genai import types\n\nclient = genai.Client()\n\nconfig = types.GenerateContentConfig(\n    system_instruction=\"You are a pirate\",\n)\n\nresponse = client.models.generate_content(\n    model='gemini-2.5-flash',\n    contents='Tell me a pirate joke',\n    config=config,\n)\n\nprint(response.text)\n```\n\n### Hyperparameters\n\nYou can also set `temperature` or `max_output_tokens` within\n`types.GenerateContentConfig`\n**Avoid** setting `max_output_tokens`, `topP`, `topK` unless explicitly\nrequested by the user.\n\n### Safety configurations\n\nAvoid setting safety configurations unless explicitly requested by the user. If\nexplicitly asked for by the user, here is a sample API:\n\n```python\nfrom google import genai\nfrom google.genai import types\n\nclient = genai.Client()\n\nimg = Image.open(\"/path/to/img\")\nresponse = client.models.generate_content(\n    model=\"gemini-2.0-flash\",\n    contents=['Do these look store-bought or homemade?', img],\n    config=types.GenerateContentConfig(\n      safety_settings=[\n        types.SafetySetting(\n            category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,\n            threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n        ),\n      ]\n    )\n)\n\nprint(response.text)\n```\n\n### Streaming\n\nIt is possible to stream responses to reduce user perceived latency:\n\n```python\nfrom google import genai\n\nclient = genai.Client()\n\nresponse = client.models.generate_content_stream(\n    model=\"gemini-2.5-flash\",\n    contents=[\"Explain how AI works\"]\n)\nfor chunk in response:\n    print(chunk.text, end=\"\")\n```\n\n### Chat\n\nFor multi-turn conversations, use the `chats` service to maintain conversation\nhistory.\n\n```python\nfrom google import genai\n\nclient = genai.Client()\nchat = client.chats.create(model=\"gemini-2.5-flash\")\n\nresponse = chat.send_message(\"I have 2 dogs in my house.\")\nprint(response.text)\n\nresponse = chat.send_message(\"How many paws are in my house?\")\nprint(response.text)\n\nfor message in chat.get_history():\n    print(f'role - {message.role}',end=\": \")\n    print(message.parts[0].text)\n```\n\n### Structured outputs\n\nUse structured outputs to force the model to return a response that conforms to\na specific Pydantic schema.\n\n```python\nfrom google import genai\nfrom google.genai import types\nfrom pydantic import BaseModel\n\nclient = genai.Client()\n\n# Define the desired output structure using Pydantic\nclass Recipe(BaseModel):\n    recipe_name: str\n    description: str\n    ingredients: list[str]\n    steps: list[str]\n\n# Request the model to populate the schema\nresponse = client.models.generate_content(\n    model='gemini-2.5-flash',\n    contents=\"Provide a classic recipe for chocolate chip cookies.\",\n    config=types.GenerateContentConfig(\n        response_mime_type=\"application/json\",\n        response_schema=Recipe,\n    ),\n)\n\n# The response.text will be a valid JSON string matching the Recipe schema\nprint(response.text)\n```\n\n#### Function Calling (Tools)\n\nYou can provide the model with tools (functions) it can use to bring in external\ninformation to answer a question or act on a request outside the model.\n\n```python\nfrom google import genai\nfrom google.genai import types\n\nclient = genai.Client()\n\n# Define a function that the model can call (to access external information)\ndef get_current_weather(city: str) -> str:\n    \"\"\"Returns the current weather in a given city. For this example, it's hardcoded.\"\"\"\n    if \"boston\" in city.lower():\n        return \"The weather in Boston is 15°C and sunny.\"\n    else:\n        return f\"Weather data for {city} is not available.\"\n\n# Make the function available to the model as a tool\nresponse = client.models.generate_content(\n  model='gemini-2.5-flash',\n  contents=\"What is the weather like in Boston?\",\n  config=types.GenerateContentConfig(\n      tools=[get_current_weather]\n  ),\n)\n# The model may respond with a request to call the function\nif response.function_calls:\n    print(\"Function calls requested by the model:\")\n    for function_call in response.function_calls:\n        print(f\"- Function: {function_call.name}\")\n        print(f\"- Args: {dict(function_call.args)}\")\nelse:\n    print(\"The model responded directly:\")\n    print(response.text)\n```\n\n### Generate Images\n\nHere's how to generate images using the Imagen models. Start with the fast model\nas it should cover most use-cases, and move to the more standard or the ultra\nmodels for advanced use-cases.\n\n```python\nfrom google import genai\nfrom PIL import Image\nfrom io import BytesIO\n\nclient = genai.Client()\n\nresult = client.models.generate_images(\n    model='imagen-4.0-fast-generate-001',\n    prompt=\"Image of a cat\",\n    config=dict(\n        number_of_images=1, # 1 to 4 (always 1 for the ultra model)\n        output_mime_type=\"image/jpeg\",\n        person_generation=\"ALLOW_ADULT\", # 'ALLOW_ALL' (but not in Europe/Mena), 'DONT_ALLOW' or 'ALLOW_ADULT'\n        aspect_ratio=\"1:1\", # \"1:1\", \"3:4\", \"4:3\", \"9:16\", or \"16:9\"\n    )\n)\n\nfor generated_image in result.generated_images:\n   image = Image.open(BytesIO(generated_image.image.image_bytes))\n```\n\n### Edit images\n\nEditing images is better done using the Gemini native image generation model,\nand it is recommended to use chat mode. Configs are not supported in this model\n(except modality).\n\n```python\nfrom google import genai\nfrom PIL import Image\nfrom io import BytesIO\n\nclient = genai.Client()\n\nprompt = \"\"\"\n  Create a picture of my cat eating a nano-banana in a fancy restaurant under the gemini constellation\n\"\"\"\nimage = PIL.Image.open('/path/to/image.png')\n\n# Create the chat\nchat = client.chats.create(model=\"gemini-2.5-flash-image-preview\")\n# Send the image and ask for it to be edited\nresponse = chat.send_message([prompt, image])\n\n# Get the text and the image generated\nfor i, part in enumerate(response.candidates[0].content.parts):\n  if part.text is not None:\n    print(part.text)\n  elif part.inline_data is not None:\n    image = Image.open(BytesIO(part.inline_data.data))\n    image.save(f\"generated_image_{i}.png\") # Multiple images can be generated\n\n# Continue iterating\nchat.send_message(\"Can you make it a bananas foster?\")\n```\n\n### Generate Videos\n\nHere's how to generate videos using the Veo models. Usage of Veo can be costly,\nso after generating code for it, give user a heads up to check pricing for Veo.\nStart with the fast model since the result quality is usually sufficient, and\nswap to the larger model if needed.\n\n```python\nimport time\nfrom google import genai\nfrom google.genai import types\nfrom PIL import Image\n\nclient = genai.Client()\n\nPIL_image = Image.open(\"path/to/image.png\") # Optional\n\noperation = client.models.generate_videos(\n    model=\"veo-3.0-fast-generate-preview\",\n    prompt=\"Panning wide shot of a calico kitten sleeping in the sunshine\",\n    image = PIL_image,\n    config=types.GenerateVideosConfig(\n        person_generation=\"dont_allow\",  # \"dont_allow\" or \"allow_adult\"\n        aspect_ratio=\"16:9\",  # \"16:9\" or \"9:16\"\n        number_of_videos=1, # supported value is 1-4, use 1 by default\n        duration_seconds=8, # supported value is 5-8\n    ),\n)\n\nwhile not operation.done:\n    time.sleep(20)\n    operation = client.operations.get(operation)\n\nfor n, generated_video in enumerate(operation.response.generated_videos):\n    client.files.download(file=generated_video.video) # just file=, no need for path= as it doesn't save yet\n    generated_video.video.save(f\"video{n}.mp4\")  # saves the video\n\n```\n\n### Search Grounding\n\nGoogle Search can be used as a tool for grounding queries that with up to date\ninformation from the web.\n\n**Correct**\n\n```python\nfrom google import genai\n\nclient = genai.Client()\n\nresponse = client.models.generate_content(\n    model='gemini-2.5-flash',\n    contents=\"What was the score of the latest Olympique Lyonnais game?\",\n    config={\"tools\": [{\"google_search\": {}}]},\n)\n\n# Response\nprint(f\"Response:\\n {response.text}\")\n# Search details\nprint(f\"Search Query: {response.candidates[0].grounding_metadata.web_search_queries}\")\n# Urls used for grounding\nprint(f\"Search Pages: {', '.join([site.web.title for site in response.candidates[0].grounding_metadata.grounding_chunks])}\")\n```\n\nThe output `response.text` will likely not be in JSON format, do not attempt to\nparse it as JSON.\n\n### Content and Part Hierarchy\n\nWhile the simpler API call is often sufficient, you may run into scenarios where\nyou need to work directly with the underlying `Content` and `Part` objects for\nmore explicit control. These are the fundamental building blocks of the\n`generate_content` API.\n\nFor instance, the following simple API call:\n\n```python\nfrom google import genai\n\nclient = genai.Client()\n\nresponse = client.models.generate_content(\n    model=\"gemini-2.5-flash\",\n    contents=\"How does AI work?\"\n)\nprint(response.text)\n```\n\nis effectively a shorthand for this more explicit structure:\n\n```python\nfrom google import genai\nfrom google.genai import types\n\nclient = genai.Client()\n\nresponse = client.models.generate_content(\n    model=\"gemini-2.5-flash\",\n    contents=[\n      types.Content(role=\"user\", parts=[types.Part.from_text(text=\"How does AI work?\")]),\n    ]\n)\nprint(response.text)\n```\n\n## Other APIs\n\nThe list of APIs and capabilities above are not comprehensive. If users ask you\nto generate code for a capability not provided above, refer them to\nai.google.dev/gemini-api/docs.\n\n## Useful Links\n\n- Documentation: ai.google.dev/gemini-api/docs\n- API Keys and Authentication: ai.google.dev/gemini-api/docs/api-key\n- Models: ai.google.dev/models\n- API Pricing: ai.google.dev/pricing\n- Rate Limits: ai.google.dev/rate-limits"
  },
  {
    "path": "content/gensim/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Gensim package guide for Python with corpus setup, embeddings, topic models, downloader usage, and 4.4.0 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"gensim,python,nlp,embeddings,word2vec,lda,topic-modeling\"\n---\n\n# Gensim Python Package Guide\n\n## What It Is\n\n`gensim` is a Python library for topic modeling, document indexing, similarity retrieval, and vector-space NLP workflows. It is most commonly used for:\n\n- streaming text corpora through memory-efficient training pipelines\n- building dictionaries and bag-of-words corpora\n- training or loading embedding models such as `Word2Vec`, `FastText`, and `Doc2Vec`\n- topic modeling with `LdaModel`\n- loading pre-trained datasets and vectors with `gensim.downloader`\n\nUse it when a project needs classical NLP pipelines, embedding training, similarity search, or topic models without moving immediately to transformer tooling.\n\n## Install\n\nPin the package version if you need behavior that matches this guide:\n\n```bash\npython -m pip install \"gensim==4.4.0\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"gensim==4.4.0\"\n```\n\nRuntime notes:\n\n- `gensim` depends on `numpy`, `scipy`, and `smart_open`.\n- Large-model performance depends heavily on the NumPy/BLAS stack available in your environment.\n- `4.4.0` raises the floor to Python `3.9+` and adds compatibility updates for newer NumPy releases.\n\n## Golden Rules\n\n- Feed training code tokenized sentences or streamed corpora, not one giant in-memory string.\n- Use `Dictionary` plus `doc2bow()` for bag-of-words / topic-model pipelines.\n- Query word vectors through `model.wv`, not the full training model object.\n- Save trained artifacts with `.save()` and reload them with the class-specific `.load()`.\n- When porting old examples, expect `gensim 4.x` naming changes such as `vector_size`, `epochs`, `index_to_key`, and `key_to_index`.\n\n## Core Workflow\n\nThe common `gensim` pipeline is:\n\n1. tokenize documents into lists of strings\n2. build a `Dictionary`\n3. convert documents to bag-of-words with `doc2bow()`\n4. train a model such as TF-IDF, LSI, or LDA\n5. persist the model and dictionary for reuse\n\n### Dictionary And Bag-Of-Words Setup\n\n```python\nfrom gensim.corpora import Dictionary\n\ndocuments = [\n    [\"human\", \"interface\", \"computer\"],\n    [\"survey\", \"user\", \"computer\", \"system\", \"response\", \"time\"],\n    [\"graph\", \"minors\", \"trees\"],\n]\n\ndictionary = Dictionary(documents)\ndictionary.filter_extremes(no_below=1, no_above=0.8)\n\nbow_corpus = [dictionary.doc2bow(doc) for doc in documents]\n\nprint(dictionary.token2id)\nprint(bow_corpus[0])\n```\n\nUse this representation when you want classic vector-space models, topic models, or similarity indexes.\n\n### Topic Modeling With LDA\n\n```python\nfrom gensim.corpora import Dictionary\nfrom gensim.models import LdaModel\n\ntexts = [\n    [\"bank\", \"loan\", \"credit\", \"money\"],\n    [\"river\", \"bank\", \"water\", \"flood\"],\n    [\"loan\", \"interest\", \"debt\", \"credit\"],\n]\n\ndictionary = Dictionary(texts)\ncorpus = [dictionary.doc2bow(text) for text in texts]\n\nlda = LdaModel(\n    corpus=corpus,\n    id2word=dictionary,\n    num_topics=2,\n    passes=20,\n    random_state=42,\n)\n\nfor topic_id, topic in lda.print_topics():\n    print(topic_id, topic)\n\ndoc_topics = lda.get_document_topics(corpus[0])\nprint(doc_topics)\n```\n\nPractical notes:\n\n- pass `id2word=dictionary` so topic output uses tokens instead of raw ids\n- set `random_state` when you need repeatable output in tests or docs\n- increase `passes` and train on a real corpus before evaluating topic quality\n\n### Training Word2Vec\n\n```python\nfrom gensim.models import Word2Vec\n\nsentences = [\n    [\"human\", \"interface\", \"computer\"],\n    [\"survey\", \"user\", \"computer\", \"system\"],\n    [\"graph\", \"trees\", \"minors\"],\n    [\"human\", \"system\", \"response\"],\n]\n\nmodel = Word2Vec(\n    sentences=sentences,\n    vector_size=100,\n    window=5,\n    min_count=1,\n    workers=1,\n    epochs=20,\n)\n\nprint(model.wv.most_similar(\"computer\", topn=3))\nprint(model.wv[\"human\"][:5])\n```\n\nImportant API shape:\n\n- use `vector_size`, not the old `size`\n- use `epochs`, not the old `iter`\n- similarity lookup lives on `model.wv`\n\n### Loading Pretrained Assets With `gensim.downloader`\n\n```python\nimport gensim.downloader as api\n\navailable = api.info()\nprint(\"glove-wiki-gigaword-50\" in available[\"models\"])\n\nvectors = api.load(\"glove-wiki-gigaword-50\")\nprint(vectors.most_similar(\"cat\", topn=5))\n```\n\nUse the downloader when you need a quick public baseline model or toy dataset. It is convenient for experiments, tests, and reproducing tutorial code.\n\n## Similarity And Transform Pipelines\n\nFor document similarity, combine a corpus transform with a similarity index:\n\n```python\nfrom gensim.corpora import Dictionary\nfrom gensim.models import TfidfModel\nfrom gensim.similarities import MatrixSimilarity\n\ntexts = [\n    [\"apple\", \"banana\", \"fruit\"],\n    [\"dog\", \"cat\", \"pet\"],\n    [\"apple\", \"orange\", \"fruit\"],\n]\n\ndictionary = Dictionary(texts)\ncorpus = [dictionary.doc2bow(text) for text in texts]\n\ntfidf = TfidfModel(corpus)\nindex = MatrixSimilarity(tfidf[corpus], num_features=len(dictionary))\n\nquery_bow = dictionary.doc2bow([\"apple\", \"fruit\"])\nscores = index[tfidf[query_bow]]\nprint(list(enumerate(scores)))\n```\n\nThis pattern is useful when you need lightweight semantic retrieval without adding a vector database.\n\n## Persistence\n\nPersist both the model and the vocabulary objects you need for inference:\n\n```python\nfrom gensim.corpora import Dictionary\nfrom gensim.models import Word2Vec\n\nsentences = [[\"hello\", \"world\"], [\"hello\", \"gensim\"]]\n\ndictionary = Dictionary(sentences)\nmodel = Word2Vec(sentences=sentences, min_count=1)\n\ndictionary.save(\"dictionary.gensim\")\nmodel.save(\"word2vec.model\")\n\nloaded_dictionary = Dictionary.load(\"dictionary.gensim\")\nloaded_model = Word2Vec.load(\"word2vec.model\")\n\nprint(loaded_dictionary.token2id)\nprint(loaded_model.wv.most_similar(\"hello\"))\n```\n\nLarge-array loading note:\n\n- `SaveLoad.load(..., mmap=\"r\")` can memory-map large arrays for sharing between processes.\n- Memory mapping does not work for compressed files such as `.gz` or `.bz2`.\n\n## Configuration And Environment\n\n### Downloader Cache Location\n\n`gensim.downloader` stores downloaded assets under `~/gensim-data` by default. Override that location with `GENSIM_DATA_DIR` before importing or downloading models:\n\n```bash\nexport GENSIM_DATA_DIR=/srv/shared/gensim-data\n```\n\nYou can inspect downloader metadata from the command line:\n\n```bash\npython -m gensim.downloader --info\npython -m gensim.downloader --download glove-wiki-gigaword-50\n```\n\n### Authentication\n\n`gensim` itself has no package-level authentication or API key flow.\n\nPractical implication:\n\n- public downloader assets require no auth\n- local filesystem workflows require no auth\n- if you open remote objects through `smart_open`-backed URLs such as S3, configure those storage credentials through the underlying provider tooling in your runtime environment\n\n## Common Pitfalls\n\n### Mixing Up Training Models And Keyed Vectors\n\nUse the right object for the job:\n\n- `Word2Vec`, `FastText`, and `Doc2Vec` are training-capable model classes\n- `KeyedVectors` is the light-weight structure for querying vectors\n\nIf you load vectors from `load_word2vec_format()` or the downloader, you usually get queryable vectors, not a fully trainable model.\n\n### Porting Pre-4.x Examples Without Translating Names\n\nOld blog posts often use removed or renamed APIs. Common replacements in `gensim 4.x`:\n\n- `size` -> `vector_size`\n- `iter` -> `epochs`\n- `model.wv.vocab` -> `model.wv.key_to_index` and vector attributes via `get_vecattr()`\n- `model.wv.index2word` -> `model.wv.index_to_key`\n- direct similarity methods on the training model -> `model.wv.<method>`\n\nIf copied code references `vocab`, `index2word`, or `size`, translate it before debugging anything else.\n\n### Forgetting To Stream Large Corpora\n\nMany `gensim` APIs accept iterables. Use that to your advantage for large datasets:\n\n- prefer generators or corpus iterators over building giant intermediate lists\n- save reusable corpora in `MmCorpus` or another serialized format when training repeatedly\n- keep tokenization outside the training loop so retraining is deterministic\n\n### Treating The Docs Site Version As The Exact Package Version\n\nAt the time of this guide:\n\n- package metadata and release tags point to `4.4.0`\n- the docs site header still shows `4.3.3`\n\nDo not assume that page chrome is the authoritative package version. When behavior matters, cross-check PyPI metadata and the `4.4.0` release page.\n\n## Version-Sensitive Notes For 4.4.0\n\n- `4.4.0` is the package version on PyPI for this entry.\n- Upstream `4.4.0` release notes call out support for NumPy `2.0`.\n- PyPI metadata for `4.4.0` requires Python `>=3.9`.\n- The upstream repository describes `gensim` as being in stable maintenance mode, so expect incremental fixes more often than major new surfaces.\n\n## Official Sources Used\n\n- Docs root: `https://radimrehurek.com/gensim/`\n- API reference: `https://radimrehurek.com/gensim/apiref.html`\n- Word2Vec tutorial: `https://radimrehurek.com/gensim/auto_examples/tutorials/run_word2vec.html`\n- Topics and transformations tutorial: `https://radimrehurek.com/gensim/auto_examples/core/run_topics_and_transformations.html`\n- Downloader how-to: `https://radimrehurek.com/gensim/auto_examples/howtos/run_downloader_api.html`\n- `4.4.0` release page: `https://github.com/piskvorky/gensim/releases/tag/4.4.0`\n- Package registry: `https://pypi.org/project/gensim/`\n"
  },
  {
    "path": "content/geopandas/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"GeoPandas package guide for Python geospatial dataframes, CRS workflows, spatial joins, GeoParquet, and PostGIS\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"geopandas,geospatial,gis,shapely,pyogrio,geoparquet,postgis\"\n---\n\n# GeoPandas Python Package Guide\n\n## Golden Rule\n\nUse `import geopandas as gpd`, keep the active geometry column and CRS explicit, and reproject before any distance- or area-based operation. GeoPandas operations are planar: `set_crs()` assigns CRS metadata, while `to_crs()` transforms coordinates.\n\n## Install\n\nThe official install guide recommends `conda-forge` when compiled geospatial dependencies are hard to resolve manually.\n\n### pip\n\n```bash\npython -m pip install \"geopandas==1.1.3\"\n```\n\n### conda-forge\n\n```bash\nconda install -c conda-forge geopandas\n```\n\n### Useful extras\n\n```bash\npython -m pip install \"geopandas[all]==1.1.3\"\n```\n\nCurrent stable install docs list these core dependency floors:\n\n- `numpy >= 1.24`\n- `pandas >= 2.2`\n- `pyproj >= 3.7.0`\n- `shapely >= 2.1.0`\n- `pyogrio >= 0.8.0`\n- `packaging`\n\nOptional extras matter for common workflows:\n\n- `pyarrow` for faster `pyogrio` IO and Parquet\n- `sqlalchemy`, `psycopg` or `psycopg2`, and `GeoAlchemy2` for PostGIS\n- `matplotlib` for `plot()`\n- `folium`, `mapclassify`, and `matplotlib` for `explore()`\n\n## Initialize Geometry\n\nCreate a `GeoDataFrame` from tabular lon/lat data with an explicit CRS:\n\n```python\nimport geopandas as gpd\nimport pandas as pd\n\ndf = pd.DataFrame(\n    {\n        \"city\": [\"San Francisco\", \"New York\"],\n        \"lon\": [-122.4194, -73.9857],\n        \"lat\": [37.7749, 40.7484],\n    }\n)\n\ngdf = gpd.GeoDataFrame(\n    df,\n    geometry=gpd.points_from_xy(df[\"lon\"], df[\"lat\"]),\n    crs=\"EPSG:4326\",\n)\n\nprint(gdf.crs)\nprint(gdf.geometry.name)\n```\n\nGeoPandas can keep multiple geometry columns, but spatial methods operate on the active geometry column. Use `set_geometry(...)` if you need to switch.\n\n## Core Workflows\n\n### Read vector data\n\n`read_file()` is the main entry point for files, URLs, and GDAL-backed data sources:\n\n```python\nimport geopandas as gpd\n\ngdf = gpd.read_file(\n    \"data/neighborhoods.gpkg\",\n    layer=\"neighborhoods\",\n    columns=[\"name\", \"borough\", \"geometry\"],\n)\n\nsubset = gpd.read_file(\n    \"data/neighborhoods.gpkg\",\n    bbox=(-74.1, 40.68, -73.85, 40.88),\n)\n```\n\nFor larger datasets, use Arrow-backed reads when `pyarrow` is installed:\n\n```python\nfast = gpd.read_file(\"data/neighborhoods.gpkg\", use_arrow=True)\n```\n\nNotes:\n\n- Since GeoPandas 1.0, the default read/write engine is `pyogrio`, not Fiona.\n- With the `pyogrio` engine, `bbox=` must already be in the dataset CRS.\n- `gpd.list_layers(...)` is available when `pyogrio` is installed.\n- `read_file()` returns a plain `pandas.DataFrame` when the source has no geometry column.\n\n### CRS assignment and reprojection\n\nAssign a CRS only when coordinates are already in that CRS. Reproject before buffering, measuring distance, or nearest-neighbor work:\n\n```python\nimport geopandas as gpd\n\ngdf = gdf.set_crs(\"EPSG:4326\")\ngdf_projected = gdf.to_crs(gdf.estimate_utm_crs())\n```\n\nUse `allow_override=True` with `set_crs()` only when you are fixing bad metadata. It does not move coordinates.\n\n### Spatial joins\n\n`sjoin()` combines rows by spatial predicate, while `sjoin_nearest()` finds nearest matches:\n\n```python\nparcels = parcels.to_crs(parcels.estimate_utm_crs())\nschools = schools.to_crs(parcels.crs)\n\nintersections = parcels.sjoin(\n    schools[[\"school_id\", \"geometry\"]],\n    how=\"left\",\n    predicate=\"intersects\",\n)\n\nnearest = parcels.sjoin_nearest(\n    schools[[\"school_id\", \"geometry\"]],\n    how=\"left\",\n    max_distance=500,\n    distance_col=\"distance_m\",\n)\n```\n\nImportant behavior:\n\n- Valid predicates depend on the spatial index backend; inspect `left_df.sindex.valid_query_predicates`.\n- `predicate=\"dwithin\"` requires a `distance=` argument.\n- `sjoin_nearest()` distances are in CRS units. Using a geographic CRS such as `EPSG:4326` gives inaccurate distance results.\n- Multiple equidistant nearest geometries produce multiple output rows.\n\n### Overlay and clip-style geometry operations\n\nUse `overlay()` when you need geometric set operations between two layers:\n\n```python\nresult = gpd.overlay(\n    parcels,\n    flood_zones,\n    how=\"intersection\",\n    keep_geom_type=True,\n)\n```\n\nNotes:\n\n- `overlay()` expects uniform geometry types per input layer.\n- The default `keep_geom_type=True` drops result geometries that do not match the left-hand geometry type and emits a warning. Set `keep_geom_type=False` if you need those rows.\n- `make_valid=True` is the default and repairs invalid inputs before overlay. Set `make_valid=False` if you would rather fail fast.\n\n### GeoParquet and other columnar formats\n\nGeoPandas reads and writes Parquet and Feather through Arrow-backed paths:\n\n```python\ngdf.to_parquet(\n    \"out/places.parquet\",\n    compression=\"zstd\",\n)\n\nround_tripped = gpd.read_parquet(\"out/places.parquet\")\n```\n\nUseful notes:\n\n- `to_parquet()` supports both WKB encoding and experimental GeoArrow-based native geometry encoding.\n- GeoParquet 1.1 support landed in GeoPandas 1.0 and is still new enough that older tutorials may miss it.\n\n### PostGIS\n\nRead from and write to PostGIS through SQLAlchemy engines or connections:\n\n```python\nfrom sqlalchemy import create_engine\nimport geopandas as gpd\n\nengine = create_engine(\"postgresql+psycopg://user:pass@host:5432/geodb\")\n\nroads = gpd.read_postgis(\n    \"SELECT road_id, geom FROM roads\",\n    engine,\n    geom_col=\"geom\",\n)\n\nroads.to_postgis(\n    \"roads_copy\",\n    engine,\n    if_exists=\"replace\",\n    index=False,\n)\n```\n\n`read_postgis()` expects the geometry column to contain WKB values. `to_postgis()` requires SQLAlchemy, a PostgreSQL driver, and GeoAlchemy2.\n\n## Configuration And Backend Notes\n\nGeoPandas does not define package-level authentication of its own. From the official IO APIs, auth is delegated to the file, database, or cloud backend you use.\n\nPractical configuration points:\n\n- Set `PYOGRIO_USE_ARROW=1` to enable Arrow transfers by default for supported `pyogrio` reads and writes.\n- Put PostGIS credentials in the SQLAlchemy URL, connection settings, or your secret manager.\n- When you pass GDAL-backed file paths or URLs to `read_file()`, backend-specific access rules come from the underlying driver stack rather than GeoPandas itself.\n\n## Common Pitfalls\n\n### Confusing `set_crs()` with `to_crs()`\n\n- `set_crs()` assigns metadata to existing coordinates.\n- `to_crs()` transforms coordinates into a new CRS.\n\nIf you use `set_crs()` when you meant `to_crs()`, every downstream spatial result will be wrong.\n\n### Measuring in a geographic CRS\n\nDistance, area, and nearest-neighbor operations are planar. Reproject first when you need meters or other projected units.\n\n### Assuming old Fiona or PyGEOS behavior\n\nMany blog posts still describe pre-1.0 behavior. Since 1.0:\n\n- `pyogrio` is the default IO engine\n- Shapely 2 is required\n- support for PyGEOS and `rtree`-based spatial indexing was removed\n- `geopandas.datasets` was removed\n\n### Losing geometries in overlay results\n\nIf `overlay()` appears to \"drop\" rows, check whether `keep_geom_type=True` filtered out line or point results that came from polygon inputs.\n\n### Forgetting the active geometry column\n\nIf a frame has multiple geometry columns, `plot`, `sjoin`, `overlay`, `to_crs`, and other geometry-aware methods use the active one. Switch it explicitly with `set_geometry(...)`.\n\n## Version-Sensitive Notes For 1.1.x\n\n- `1.1.3` includes fixes for pandas 3.0 copy-on-write behavior, `GeoSeries.value_counts()`, `GeoSeries.fillna()`, `overlay(..., identity)`, and NA handling in `from_wkt` / `from_wkb`.\n- `1.1.2` fixed several regressions, including some `read_file()`, `to_file()`, and `read_parquet()` failures with complex Arrow types.\n- Stable install docs now show dependency floors that are stricter than older 0.x and early 1.0 tutorials. If examples mention PyGEOS, `rtree`, or Fiona-as-default, they are outdated for 1.1.3.\n"
  },
  {
    "path": "content/geopy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"geopy Python package guide for geocoding, reverse geocoding, distance calculations, adapters, and rate limiting\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"geopy,python,geocoding,reverse-geocoding,location,distance,nominatim\"\n---\n\n# geopy Python Package Guide\n\n## Golden Rule\n\nUse `geopy` as a client library for third-party geocoding services, not as a service or dataset by itself. Pick the specific geocoder class your project uses, pass its credentials and request options explicitly, set a real `user_agent` for `Nominatim`, and rate-limit any batch traffic to stay within the provider's terms and quotas.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"geopy==2.4.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"geopy==2.4.1\"\npoetry add \"geopy==2.4.1\"\n```\n\nFor the async adapter:\n\n```bash\npython -m pip install \"geopy[aiohttp]==2.4.1\"\n```\n\n## Setup And Initialization\n\n`geopy` exposes many provider-specific geocoder classes through `geopy.geocoders`. Start with the concrete service you actually use.\n\n### Nominatim\n\n`Nominatim` is the most common example in code snippets, but it requires a custom `user_agent`. In geopy 2.x, using the default or a sample user agent raises `geopy.exc.ConfigurationError`.\n\n```python\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(\n    user_agent=\"my-app/1.0 (contact@example.com)\",\n    timeout=10,\n)\n```\n\n### API-key geocoder\n\nCredentials are not global to `geopy`; they belong to the provider class.\n\n```python\nimport os\nfrom geopy.geocoders import GoogleV3\n\ngeocoder = GoogleV3(\n    api_key=os.environ[\"GOOGLE_MAPS_API_KEY\"],\n    timeout=10,\n)\n```\n\n## Core Usage\n\n### Geocode an address\n\n`geocode()` usually returns `None`, a single `Location`, or a list of `Location` objects when `exactly_one=False`.\n\n```python\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(user_agent=\"my-app/1.0\")\n\nlocation = geocoder.geocode(\n    \"1600 Amphitheatre Parkway, Mountain View, CA\",\n    exactly_one=True,\n    addressdetails=True,\n    language=\"en\",\n)\n\nif location is None:\n    raise LookupError(\"Address not found\")\n\nprint(location.address)\nprint(location.latitude, location.longitude)\nprint(location.raw)\n```\n\n### Reverse geocode coordinates\n\n```python\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(user_agent=\"my-app/1.0\")\n\nlocation = geocoder.reverse(\n    (37.4221, -122.0841),\n    exactly_one=True,\n    language=\"en\",\n)\n\nif location:\n    print(location.address)\n```\n\n### Request multiple matches\n\n```python\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(user_agent=\"my-app/1.0\")\n\nmatches = geocoder.geocode(\"Springfield\", exactly_one=False, limit=5) or []\n\nfor item in matches:\n    print(item.address, item.latitude, item.longitude)\n```\n\n### Compute distances\n\n`geopy.distance.distance(...)` currently uses the geodesic algorithm by default. Use `great_circle(...)` only when that approximation is acceptable.\n\n```python\nfrom geopy.distance import distance, geodesic, great_circle\n\nnewport_ri = (41.49008, -71.312796)\ncleveland_oh = (41.499498, -81.695391)\n\nprint(distance(newport_ri, cleveland_oh).km)\nprint(geodesic(newport_ri, cleveland_oh).miles)\nprint(great_circle(newport_ri, cleveland_oh).miles)\n```\n\n## Configuration And Request Defaults\n\nUse constructor arguments for per-instance defaults and method kwargs for per-call overrides.\n\nCommon constructor parameters across geocoders:\n\n- `timeout`: seconds before `GeocoderTimedOut`; the global default is `1`\n- `user_agent`: HTTP user agent string; mandatory for `Nominatim`\n- `proxies`: proxy mapping\n- `ssl_context`: custom SSL context\n- `adapter_factory`: choose the HTTP adapter implementation\n- `domain` and `scheme`: override provider endpoint details when the class supports them\n\nYou can set defaults once through `geopy.geocoders.options`:\n\n```python\nimport geopy.geocoders\nfrom geopy.geocoders import Nominatim\n\ngeopy.geocoders.options.default_user_agent = \"my-app/1.0\"\ngeopy.geocoders.options.default_timeout = 7\n\ngeocoder = Nominatim()\n```\n\nIn 2.x, service-specific request parameters generally belong on `geocode(...)` or `reverse(...)`, not on the geocoder constructor.\n\n## Async Usage\n\nAsync geocoding uses `AioHTTPAdapter` and `async with`. Install the `aiohttp` extra first.\n\n```python\nimport asyncio\n\nfrom geopy.adapters import AioHTTPAdapter\nfrom geopy.geocoders import Nominatim\n\nasync def main() -> None:\n    async with Nominatim(\n        user_agent=\"my-app/1.0\",\n        adapter_factory=AioHTTPAdapter,\n    ) as geocoder:\n        location = await geocoder.geocode(\"Berlin\")\n        if location:\n            print(location.address)\n\nasyncio.run(main())\n```\n\n## Rate Limiting And Batch Work\n\nRespect the provider's usage policy. `RateLimiter` and `AsyncRateLimiter` are the normal way to slow down repeated lookups and retry `GeocoderServiceError` failures.\n\n### Synchronous rate limiting\n\n```python\nfrom geopy.extra.rate_limiter import RateLimiter\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(user_agent=\"my-app/1.0\")\ngeocode = RateLimiter(\n    geocoder.geocode,\n    min_delay_seconds=1,\n    max_retries=2,\n    error_wait_seconds=5,\n)\n\nfor query in [\"Paris\", \"Berlin\", \"Tokyo\"]:\n    location = geocode(query)\n    print(location.address if location else None)\n```\n\n### Asynchronous rate limiting\n\n```python\nimport asyncio\n\nfrom geopy.adapters import AioHTTPAdapter\nfrom geopy.extra.rate_limiter import AsyncRateLimiter\nfrom geopy.geocoders import Nominatim\n\nasync def main() -> None:\n    async with Nominatim(\n        user_agent=\"my-app/1.0\",\n        adapter_factory=AioHTTPAdapter,\n    ) as geocoder:\n        geocode = AsyncRateLimiter(geocoder.geocode, min_delay_seconds=1)\n        results = await asyncio.gather(*(geocode(q) for q in [\"Paris\", \"Berlin\", \"Tokyo\"]))\n        for location in results:\n            print(location.address if location else None)\n\nasyncio.run(main())\n```\n\n## Exceptions And Failure Handling\n\nUseful exceptions from `geopy.exc` to handle explicitly:\n\n- `GeocoderTimedOut`: request exceeded the configured timeout\n- `GeocoderUnavailable`: provider could not be reached\n- `GeocoderServiceError`: service-side error class retried by the rate limiters\n- `GeocoderQueryError`: bad input or invalid request shape\n- `ConfigurationError`: invalid client configuration, including invalid `Nominatim` user agents\n\nMinimal pattern:\n\n```python\nfrom geopy.exc import GeocoderServiceError, GeocoderTimedOut\nfrom geopy.geocoders import Nominatim\n\ngeocoder = Nominatim(user_agent=\"my-app/1.0\", timeout=10)\n\ntry:\n    location = geocoder.geocode(\"Lisbon\")\nexcept GeocoderTimedOut:\n    location = None\nexcept GeocoderServiceError as exc:\n    raise RuntimeError(f\"geocoding failed: {exc}\") from exc\n```\n\n## Common Pitfalls\n\n- `geopy` does not give you geocoding data by itself. You must choose a real provider such as `Nominatim`, `GoogleV3`, `OpenMapQuest`, or `GeoNames`.\n- Do not use `Nominatim()` without a real `user_agent`.\n- Do not batch large jobs without rate limiting and provider-specific ToS review.\n- `geocode()` can return `None`; guard before reading `.latitude`, `.longitude`, or `.raw`.\n- In 2.x, most service-specific arguments must be passed as keyword arguments, not positional arguments.\n- The default timeout is very short (`1` second). Raise it for real network conditions.\n- `timeout=None` disables timeouts in 2.x; it does not restore the default timeout.\n- Distance calculations ignore altitude and raise `ValueError` for points with different altitudes.\n- Many old blog posts still use pre-2.0 imports or constructor signatures. Prefer the current class import from `geopy.geocoders`.\n\n## Version-Sensitive Notes For geopy 2.4.1\n\n- `2.4.1` is in the 2.x line documented at the stable docs root and changelog.\n- Async support, adapters, `AsyncRateLimiter`, and the `geopy[aiohttp]` extra were introduced in `2.0`.\n- `RequestsAdapter` is the default adapter when `requests` is installed; otherwise geopy falls back to `URLLibAdapter`.\n- Since `2.0`, `Nominatim` rejects default or sample user agents with `ConfigurationError`.\n- Since `2.0`, service-specific request parameters belong on `geocode(...)` and `reverse(...)`, not on geocoder constructors.\n- Since `2.0`, `geopy.distance.vincenty` is gone; use `geopy.distance.geodesic`.\n- Old module paths such as `geopy.geocoders.osm.Nominatim` and `geopy.geocoders.googlev3.GoogleV3` remain only for compatibility and are slated for removal in geopy `3`.\n- `2.3.0` dropped Python `3.5` and `3.6`; `2.4.0` added Python `3.12` support.\n\n## Current Links\n\n- Official docs: `https://geopy.readthedocs.io/en/stable/`\n- Changelog: `https://geopy.readthedocs.io/en/stable/changelog_2xx.html`\n- Package registry: `https://pypi.org/project/geopy/`\n"
  },
  {
    "path": "content/gevent/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"gevent package guide for Python covering greenlets, monkey patching, pools, queues, DNS, and WSGI serving\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.9.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"gevent,greenlet,python,concurrency,networking,event-loop\"\n---\n\n# gevent Python Package Guide\n\n## What It Is\n\n`gevent` is a coroutine-based networking library that uses `greenlet` to provide a mostly synchronous Python API on top of `libev` or `libuv`. Use it for I/O-bound concurrency, cooperative servers, and adapting blocking-looking code into greenlet-friendly workflows.\n\nThis guide targets the PyPI release `25.9.1`. The official docs host currently renders development docs (`25.9.2.dev0`, and some pages such as `gevent.queue` show `25.8.3.dev0`), so treat `docs.gevent.org` as current upstream reference instead of a version-pinned snapshot.\n\n## Installation\n\n```bash\npython -m pip install gevent==25.9.1\n```\n\n`25.9.1` requires Python `>=3.9`.\n\nUseful extras published on PyPI:\n\n- `recommended`: default choice when you want the usual optional runtime helpers\n- `monitor`: monitoring/debugging dependencies\n- `dnspython`: alternate DNS resolver support\n- `docs` and `test`: only for documentation or gevent development workflows\n\n```bash\npython -m pip install \"gevent[recommended]==25.9.1\"\n```\n\nIf no compatible wheel is available for your platform, `pip` falls back to a source build.\n\n## Pick An Integration Style\n\n### Use gevent APIs directly\n\nThis is the safest model when you control the code path and can use gevent-native modules explicitly.\n\n```python\nimport gevent\n\ndef work(label, delay):\n    gevent.sleep(delay)\n    return f\"{label} finished\"\n\njobs = [\n    gevent.spawn(work, \"a\", 0.2),\n    gevent.spawn(work, \"b\", 0.1),\n]\n\ngevent.joinall(jobs, raise_error=True)\nresults = [job.value for job in jobs]\nprint(results)\n```\n\nPractical rules:\n\n- Use `gevent.sleep()` to yield cooperatively.\n- `gevent.sleep(0)` yields to runnable greenlets, but repeated zero-sleeps can still delay I/O-heavy work for a short period.\n- Use `gevent.joinall(..., raise_error=True)` or inspect `greenlet.exception`; spawned greenlets keep exceptions on the greenlet object.\n\n### Monkey patch the standard library\n\nUse monkey patching when you need existing stdlib-style networking code to become cooperative.\n\n```python\nfrom gevent import monkey\n\nmonkey.patch_all()\n\nimport gevent\nfrom urllib.request import urlopen\n\ndef fetch(url):\n    with urlopen(url, timeout=5) as response:\n        return response.read()\n\njobs = [\n    gevent.spawn(fetch, \"https://example.com\"),\n    gevent.spawn(fetch, \"https://example.org\"),\n]\n\ngevent.joinall(jobs, raise_error=True)\npayloads = [job.value for job in jobs]\n```\n\nUpstream guidance is strict here:\n\n- Call `monkey.patch_all()` as early as possible in the main module.\n- Patch on the main thread while the process is still single-threaded.\n- Late patching can leave some modules on blocking sockets or other incompatible primitives.\n- Some frameworks patch for you; verify that before adding a second patch layer.\n\n## Core Usage Patterns\n\n### Bound concurrency with `Pool`\n\n```python\nfrom gevent import joinall, sleep\nfrom gevent.pool import Pool\n\npool = Pool(10)\n\ndef fetch_one(item):\n    sleep(0.1)\n    return item * 2\n\njobs = [pool.spawn(fetch_one, item) for item in range(100)]\njoinall(jobs, raise_error=True)\nvalues = [job.value for job in jobs]\n```\n\nUse a pool when you need backpressure instead of spawning an unbounded number of greenlets.\n\n### Coordinate work with `gevent.queue`\n\nIn `25.9.1`, `gevent.queue.Queue` is the joinable queue type. `JoinableQueue` remains as a backward-compatibility alias, and `SimpleQueue` is the lightweight queue without `join()` and `task_done()`.\n\n```python\nimport gevent\nfrom gevent.queue import Queue\n\nqueue = Queue()\n\ndef producer():\n    for item in range(5):\n        queue.put(item)\n    queue.put(None)\n\ndef consumer():\n    seen = []\n    while True:\n        item = queue.get()\n        if item is None:\n            queue.task_done()\n            break\n        seen.append(item)\n        queue.task_done()\n    return seen\n\nprod = gevent.spawn(producer)\ncons = gevent.spawn(consumer)\n\ngevent.joinall([prod], raise_error=True)\nqueue.join()\ngevent.joinall([cons], raise_error=True)\nprint(cons.value)\n```\n\n### Timeouts\n\n```python\nimport gevent\n\nwith gevent.Timeout(2, TimeoutError(\"operation timed out\")):\n    gevent.sleep(3)\n```\n\nWrap risky operations so one blocked greenlet does not stall the overall workflow indefinitely.\n\n### WSGI serving with `gevent.pywsgi`\n\n```python\nfrom gevent.pywsgi import WSGIServer\n\ndef app(environ, start_response):\n    body = b\"ok\\n\"\n    start_response(\n        \"200 OK\",\n        [\n            (\"Content-Type\", \"text/plain\"),\n            (\"Content-Length\", str(len(body))),\n        ],\n    )\n    return [body]\n\nWSGIServer((\"127.0.0.1\", 8080), app).serve_forever()\n```\n\n`gevent.pywsgi.WSGIServer` is the standard gevent-hosted WSGI entrypoint.\n\n## Configuration And Environment\n\n`gevent` has no auth model of its own. Configuration is about loop selection, DNS behavior, monitoring, file-object strategy, and related runtime controls.\n\nIf you set options in code, do it before importing modules that initialize the hub or start using sockets.\n\n```python\nfrom gevent import config\n\nconfig.loop = \"libuv\"\nconfig.resolver = [\"thread\", \"dnspython\"]\nconfig.monitor_thread = True\nconfig.max_blocking_time = 0.5\n```\n\nUseful environment variables:\n\n```bash\nexport GEVENT_LOOP=libuv\nexport GEVENT_RESOLVER=thread\nexport GEVENT_MONITOR_THREAD_ENABLE=1\nexport GEVENT_MAX_BLOCKING_TIME=0.5\nexport GEVENT_MONITOR_PRINT_BLOCKING_REPORTS=1\n```\n\nPractical notes:\n\n- On Windows, the loop default is `libuv`; on other platforms, the default preference is `libev` first.\n- The default resolver preference is `thread`, then `dnspython`, then `ares`, then `block`.\n- `GEVENT_RESOLVER_NAMESERVERS` accepts IP addresses only; invalid values can hang resolver backends such as `dnspython`.\n- `GEVENT_MONITOR_THREAD_ENABLE=1` starts a native monitoring thread that reports blocked hubs.\n- `GEVENT_MONITOR_PRINT_BLOCKING_REPORTS` was added in `25.4.1`; it defaults to `True` when monitoring is enabled.\n\n## Common Pitfalls\n\n- Late monkey patching: patch before importing modules that create sockets, locks, selectors, subprocess helpers, or threads.\n- CPU-bound work: greenlets do not give CPU parallelism. Use processes or native extensions for CPU-heavy jobs.\n- Hidden blocking calls: unpatched C extensions, file APIs, or third-party libraries can still block the hub.\n- Queue internals: after the `25.4.1` queue rename, rely on documented queue APIs like `put`, `get`, `task_done`, and `join`, not internal attributes.\n- Version drift: `docs.gevent.org` tracks current development state, so confirm version-sensitive behavior against the installed release.\n- Interpreter mode: free-threaded CPython 3.13/3.14 builds are not supported by gevent even though the package can build there.\n- Platform assumptions: Windows support is best-effort and upstream does not recommend it for production.\n\n## Version-Sensitive Notes For `25.9.1`\n\n- PyPI marks `25.9.1` as the latest release and shows its release date as September 17, 2025.\n- `25.9.1` fixes a `TypeError` in the C extensions when putting items into a full `SimpleQueue`. If you are stuck on `25.4.1` through `25.8.x`, upstream lists `PURE_PYTHON=1` or `GEVENT_PURE_PYTHON=1` as a workaround.\n- `25.4.1` changed queue behavior in ways that matter for porting code: `Queue` became the joinable queue type, `SimpleQueue` became the simple queue type, and `patch_all()` started patching stdlib `queue.Queue`, `PriorityQueue`, and `LifoQueue` by default. Upstream explicitly notes that this solved a known `urllib3` deadlock.\n- `25.4.1` also added `GEVENT_MONITOR_PRINT_BLOCKING_REPORTS`, which is useful when enabling monitor-thread diagnostics in long-running services.\n- `25.5.1` updated the bundled `libuv` and raised wheel baselines to newer OS versions, including Linux kernel `3.10` with `glibc 2.17`, macOS `11`, Windows `10`, and FreeBSD `12`.\n- `25.8.1` says Python `3.9` support is expected to be removed soon. For new services, prefer Python `3.10+` unless you are pinned by project constraints.\n\n## Official Sources Used\n\n- API landing page: https://www.gevent.org/api/\n- Docs root: https://docs.gevent.org/\n- Common functions API: https://docs.gevent.org/api/gevent.html\n- Monkey patching API: https://docs.gevent.org/api/gevent.monkey.html\n- Queue API: https://docs.gevent.org/api/gevent.queue.html\n- Configuration guide: https://docs.gevent.org/configuration.html\n- Changelog: https://docs.gevent.org/changelog.html\n- PyPI release page: https://pypi.org/project/gevent/25.9.1/\n"
  },
  {
    "path": "content/github/docs/octokit/DOC.md",
    "content": "---\nname: octokit\ndescription: \"Official GitHub SDK for JavaScript providing REST API, GraphQL API, authentication, and App support via Octokit packages.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.0.5\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"github,octokit,rest,graphql,api\"\n---\n\n# GitHub Octokit.js SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Octokit packages from GitHub.** The main `octokit` package is recommended for most use cases as it includes REST API, GraphQL API, authentication, App support, and recommended plugins out of the box.\n\n**Never use deprecated or unofficial GitHub API libraries.**\n\nTo view available Octokit packages and their details:\n```bash\nnpm view octokit\nnpm view @octokit/core\nnpm view @octokit/rest\nnpm view @octokit/graphql\n```\n\n## 2. Installation\n\n```bash\nnpm install octokit\n# Or: yarn add octokit\n# Or: pnpm add octokit\n```\n\nFor specific components, use `@octokit/rest`, `@octokit/graphql`, or `@octokit/core`.\n\n**Environment Variables:**\n```bash\n# Personal Access Token (classic or fine-grained)\nGITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx\n\n# For GitHub Apps\nGITHUB_APP_ID=123456\nGITHUB_PRIVATE_KEY=\"-----BEGIN RSA PRIVATE KEY-----\\n...\"\nGITHUB_INSTALLATION_ID=789012\n\n# For OAuth Apps\nGITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxx\nGITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx\n\n# GitHub Enterprise Server (optional)\nGITHUB_API_URL=https://github.mycompany.com/api/v3\n```\n\n## 3. Initialization\n\n### Basic Authentication with Personal Access Token\n```javascript\nimport { Octokit } from \"octokit\";\n\n// Using environment variable\nconst octokit = new Octokit({\n  auth: process.env.GITHUB_TOKEN\n});\n\n// Or explicit token\nconst octokit = new Octokit({\n  auth: \"ghp_xxxxxxxxxxxxxxxxxxxx\"\n});\n```\n\n### Unauthenticated Requests\n```javascript\nimport { Octokit } from \"octokit\";\n\n// Lower rate limits (60 requests/hour)\nconst octokit = new Octokit();\n```\n\n### GitHub App Authentication\n```javascript\nimport { Octokit } from \"octokit\";\nimport { createAppAuth } from \"@octokit/auth-app\";\n\nconst octokit = new Octokit({\n  authStrategy: createAppAuth,\n  auth: {\n    appId: process.env.GITHUB_APP_ID,\n    privateKey: process.env.GITHUB_PRIVATE_KEY,\n    installationId: process.env.GITHUB_INSTALLATION_ID\n  }\n});\n```\n\n### OAuth App Authentication\n```javascript\nimport { Octokit } from \"octokit\";\nimport { createOAuthAppAuth } from \"@octokit/auth-oauth-app\";\n\nconst octokit = new Octokit({\n  authStrategy: createOAuthAppAuth,\n  auth: {\n    clientId: process.env.GITHUB_CLIENT_ID,\n    clientSecret: process.env.GITHUB_CLIENT_SECRET\n  }\n});\n```\n\n### GitHub Actions Authentication\n```javascript\nimport { Octokit } from \"octokit\";\n\n// In GitHub Actions, use the built-in token\nconst octokit = new Octokit({\n  auth: process.env.GITHUB_TOKEN // Available in all workflows\n});\n```\n\n### GitHub Enterprise Server\n```javascript\nimport { Octokit } from \"octokit\";\n\nconst octokit = new Octokit({\n  auth: process.env.GITHUB_TOKEN,\n  baseUrl: \"https://github.mycompany.com/api/v3\"\n});\n```\n\n## 4. Core API Surfaces\n\n### Repositories\n\n**Minimal Example - Get Repository:**\n```javascript\nconst { data: repo } = await octokit.rest.repos.get({\n  owner: \"octokit\",\n  repo: \"rest.js\"\n});\n```\n\n**Advanced Example - Create Repository:**\n```javascript\nconst { data: newRepo } = await octokit.rest.repos.createForAuthenticatedUser({\n  name: \"my-new-repo\",\n  description: \"Created via Octokit\",\n  private: false,\n  auto_init: true,\n  gitignore_template: \"Node\",\n  license_template: \"mit\",\n  homepage: \"https://example.com\",\n  has_issues: true,\n  has_projects: true,\n  has_wiki: true\n});\n```\n\n**List User Repositories:**\n\nTo view available methods and parameters:\n```bash\nnpm view @octokit/plugin-rest-endpoint-methods\n```\n\n```javascript\nconst { data: repos } = await octokit.rest.repos.listForAuthenticatedUser({\n  sort: \"updated\",\n  direction: \"desc\",\n  per_page: 100\n});\n```\n\n**Update Repository:**\n```javascript\nconst { data: updated } = await octokit.rest.repos.update({\n  owner: \"username\",\n  repo: \"repo-name\",\n  description: \"New description\",\n  homepage: \"https://newsite.com\",\n  has_issues: false\n});\n```\n\n### Issues\n\n**Minimal Example - List Issues:**\n\nFor CLI alternative: `gh issue list --repo owner/repo`\n\n```javascript\nconst { data: issues } = await octokit.rest.issues.listForRepo({\n  owner: \"facebook\",\n  repo: \"react\"\n});\n```\n\n**Advanced Example - Create Issue with Labels:**\n```javascript\nconst { data: issue } = await octokit.rest.issues.create({\n  owner: \"owner\",\n  repo: \"repo\",\n  title: \"Bug: Application crashes on startup\",\n  body: `## Description\nDetailed description of the issue...\n\n## Steps to Reproduce\n1. Step 1\n2. Step 2\n\n## Expected Behavior\nWhat should happen\n\n## Actual Behavior\nWhat actually happens`,\n  labels: [\"bug\", \"high-priority\"],\n  assignees: [\"username1\", \"username2\"],\n  milestone: 1\n});\n```\n\n**Update Issue:**\n```javascript\nconst { data: updated } = await octokit.rest.issues.update({\n  owner: \"owner\",\n  repo: \"repo\",\n  issue_number: 123,\n  state: \"closed\",\n  state_reason: \"completed\",\n  labels: [\"resolved\"]\n});\n```\n\n**Add Comment:**\n```javascript\nconst { data: comment } = await octokit.rest.issues.createComment({\n  owner: \"owner\",\n  repo: \"repo\",\n  issue_number: 123,\n  body: \"Thanks for reporting! This has been fixed in v2.0.0\"\n});\n```\n\n### Pull Requests\n\n**Minimal Example - List Pull Requests:**\n\nFor CLI alternative: `gh pr list --repo owner/repo --state open`\n\n```javascript\nconst { data: pulls } = await octokit.rest.pulls.list({\n  owner: \"microsoft\",\n  repo: \"vscode\",\n  state: \"open\"\n});\n```\n\n**Advanced Example - Create Pull Request:**\n```javascript\nconst { data: pr } = await octokit.rest.pulls.create({\n  owner: \"owner\",\n  repo: \"repo\",\n  title: \"Add new feature\",\n  head: \"feature-branch\",\n  base: \"main\",\n  body: \"Detailed description of changes in this pull request.\",\n  maintainer_can_modify: true,\n  draft: false\n});\n```\n\n**Get Pull Request Files:**\n```javascript\nconst { data: files } = await octokit.rest.pulls.listFiles({\n  owner: \"owner\",\n  repo: \"repo\",\n  pull_number: 123\n});\n```\n\n**Merge Pull Request:**\n```javascript\nconst { data: merge } = await octokit.rest.pulls.merge({\n  owner: \"owner\",\n  repo: \"repo\",\n  pull_number: 123,\n  commit_title: \"Merge PR #123: Add new feature\",\n  commit_message: \"Additional details about the merge\",\n  merge_method: \"squash\" // or \"merge\" or \"rebase\"\n});\n```\n\n**Request Reviewers:**\n```javascript\nawait octokit.rest.pulls.requestReviewers({\n  owner: \"owner\",\n  repo: \"repo\",\n  pull_number: 123,\n  reviewers: [\"reviewer1\", \"reviewer2\"],\n  team_reviewers: [\"team-slug\"]\n});\n```\n\n### Commits\n\n**Minimal Example - Get Commit:**\n```javascript\nconst { data: commit } = await octokit.rest.repos.getCommit({\n  owner: \"owner\",\n  repo: \"repo\",\n  ref: \"abc123\"\n});\n```\n\n**Advanced Example - List Commits with Filtering:**\n```javascript\nconst { data: commits } = await octokit.rest.repos.listCommits({\n  owner: \"owner\",\n  repo: \"repo\",\n  sha: \"main\",\n  path: \"src/index.js\",\n  author: \"username\",\n  since: \"2025-01-01T00:00:00Z\",\n  until: \"2025-12-31T23:59:59Z\",\n  per_page: 100\n});\n```\n\n**Compare Commits:**\n```javascript\nconst { data: comparison } = await octokit.rest.repos.compareCommits({\n  owner: \"owner\",\n  repo: \"repo\",\n  base: \"main\",\n  head: \"feature-branch\"\n});\n```\n\n### Branches\n\n**List Branches:**\n\nFor CLI alternative: `gh api repos/owner/repo/branches` or `git branch -r`\n\n```javascript\nconst { data: branches } = await octokit.rest.repos.listBranches({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n```\n\n**Get Branch:**\n```javascript\nconst { data: branch } = await octokit.rest.repos.getBranch({\n  owner: \"owner\",\n  repo: \"repo\",\n  branch: \"main\"\n});\n```\n\n**Create Branch (via Git References):**\n```javascript\n// First, get the SHA of the source branch\nconst { data: refData } = await octokit.rest.git.getRef({\n  owner: \"owner\",\n  repo: \"repo\",\n  ref: \"heads/main\"\n});\n\n// Create new branch from that SHA\nawait octokit.rest.git.createRef({\n  owner: \"owner\",\n  repo: \"repo\",\n  ref: \"refs/heads/new-feature\",\n  sha: refData.object.sha\n});\n```\n\n### Files and Content\n\n**Minimal Example - Get File Content:**\n```javascript\nconst { data: file } = await octokit.rest.repos.getContent({\n  owner: \"owner\",\n  repo: \"repo\",\n  path: \"README.md\"\n});\n\n// Decode base64 content\nconst content = Buffer.from(file.content, \"base64\").toString(\"utf8\");\nconsole.log(content);\n```\n\n**Advanced Example - Create or Update File:**\n```javascript\n// Get current file to retrieve SHA (required for updates)\nlet sha;\ntry {\n  const { data: existing } = await octokit.rest.repos.getContent({\n    owner: \"owner\",\n    repo: \"repo\",\n    path: \"config.json\"\n  });\n  sha = existing.sha;\n} catch (error) {\n  // File doesn't exist, will create new\n}\n\nconst content = JSON.stringify({ version: \"2.0.0\" }, null, 2);\nconst { data: result } = await octokit.rest.repos.createOrUpdateFileContents({\n  owner: \"owner\",\n  repo: \"repo\",\n  path: \"config.json\",\n  message: \"Update config version to 2.0.0\",\n  content: Buffer.from(content).toString(\"base64\"),\n  sha: sha, // Required for updates, omit for new files\n  branch: \"main\",\n  committer: {\n    name: \"Bot Name\",\n    email: \"bot@example.com\"\n  },\n  author: {\n    name: \"Author Name\",\n    email: \"author@example.com\"\n  }\n});\n\nconsole.log(`File updated: ${result.content.html_url}`);\n```\n\n**Delete File:**\n```javascript\n// Get file SHA first\nconst { data: file } = await octokit.rest.repos.getContent({\n  owner: \"owner\",\n  repo: \"repo\",\n  path: \"file-to-delete.txt\"\n});\n\nawait octokit.rest.repos.deleteFile({\n  owner: \"owner\",\n  repo: \"repo\",\n  path: \"file-to-delete.txt\",\n  message: \"Remove obsolete file\",\n  sha: file.sha,\n  branch: \"main\"\n});\n```\n\n### Releases\n\n**Minimal Example - List Releases:**\n\nFor CLI alternative: `gh release list --repo owner/repo`\n\n```javascript\nconst { data: releases } = await octokit.rest.repos.listReleases({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n```\n\n**Advanced Example - Create Release:**\n```javascript\nconst { data: release } = await octokit.rest.repos.createRelease({\n  owner: \"owner\",\n  repo: \"repo\",\n  tag_name: \"v2.0.0\",\n  name: \"Version 2.0.0\",\n  body: \"Release notes and changelog content here.\",\n  draft: false,\n  prerelease: false,\n  generate_release_notes: false,\n  target_commitish: \"main\"\n});\n\n```\n\n**Get Latest Release:**\n\nFor CLI alternative: `gh release view --repo owner/repo`\n\n```javascript\nconst { data: latest } = await octokit.rest.repos.getLatestRelease({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n```\n\n### Gists\n\n**Minimal Example - Create Gist:**\n```javascript\nconst { data: gist } = await octokit.rest.gists.create({\n  files: {\n    \"hello.js\": {\n      content: \"console.log('Hello World');\"\n    }\n  },\n  description: \"Hello World example\",\n  public: true\n});\n\n```\n\n**Advanced Example - Multi-file Gist:**\n```javascript\nconst { data: gist } = await octokit.rest.gists.create({\n  files: {\n    \"package.json\": {\n      content: JSON.stringify({\n        name: \"example\",\n        version: \"1.0.0\"\n      }, null, 2)\n    },\n    \"index.js\": {\n      content: \"const express = require('express');\\n// App code here\"\n    },\n    \"README.md\": {\n      content: \"# Example Project\\n\\nDescription here\"\n    }\n  },\n  description: \"Full project example\",\n  public: false\n});\n```\n\n### Search\n\n**Search Repositories:**\n```javascript\nconst { data: results } = await octokit.rest.search.repos({\n  q: \"language:javascript stars:>1000 created:>2024-01-01\",\n  sort: \"stars\",\n  order: \"desc\",\n  per_page: 30\n});\n```\n\n**Search Issues and Pull Requests:**\n```javascript\nconst { data: results } = await octokit.rest.search.issuesAndPullRequests({\n  q: \"type:pr repo:facebook/react is:open label:bug\",\n  sort: \"created\",\n  order: \"desc\"\n});\n```\n\n**Search Code:**\n```javascript\nconst { data: results } = await octokit.rest.search.code({\n  q: \"import Octokit from octokit language:javascript\",\n  per_page: 50\n});\n```\n\n**Search Users:**\n```javascript\nconst { data: results } = await octokit.rest.search.users({\n  q: \"followers:>1000 location:London\",\n  per_page: 20\n});\n```\n\n### Users and Organizations\n\n**Get Authenticated User:**\n\nFor CLI alternative: `gh api user`\n\n```javascript\nconst { data: user } = await octokit.rest.users.getAuthenticated();\n```\n\n**Get User by Username:**\n\nFor CLI alternative: `gh api users/username`\n\n```javascript\nconst { data: user } = await octokit.rest.users.getByUsername({\n  username: \"torvalds\"\n});\n```\n\n**List Organization Repositories:**\n\nFor CLI alternative: `gh repo list org-name`\n\n```javascript\nconst { data: repos } = await octokit.rest.repos.listForOrg({\n  org: \"github\",\n  type: \"public\",\n  sort: \"updated\",\n  per_page: 100\n});\n```\n\n**List Organization Members:**\n\nFor CLI alternative: `gh api orgs/org-name/members`\n\n```javascript\nconst { data: members } = await octokit.rest.orgs.listMembers({\n  org: \"github\",\n  per_page: 100\n});\n```\n\n### Webhooks\n\n**List Repository Webhooks:**\n\nFor CLI alternative: `gh api repos/owner/repo/hooks`\n\n```javascript\nconst { data: hooks } = await octokit.rest.repos.listWebhooks({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n```\n\n**Create Webhook:**\n```javascript\nconst { data: hook } = await octokit.rest.repos.createWebhook({\n  owner: \"owner\",\n  repo: \"repo\",\n  name: \"web\",\n  active: true,\n  events: [\"push\", \"pull_request\", \"issues\"],\n  config: {\n    url: \"https://example.com/webhook\",\n    content_type: \"json\",\n    secret: process.env.WEBHOOK_SECRET,\n    insecure_ssl: \"0\"\n  }\n});\n```\n\n### GraphQL API\n\n**Minimal Example - Simple Query:**\n```javascript\nconst { repository } = await octokit.graphql(`\n  query {\n    repository(owner: \"octokit\", name: \"graphql.js\") {\n      name\n      description\n      stargazerCount\n    }\n  }\n`);\n```\n\n**Advanced Example - Query with Variables:**\n```javascript\nconst query = `\n  query($owner: String!, $repo: String!, $issueCount: Int!) {\n    repository(owner: $owner, name: $repo) {\n      name\n      issues(last: $issueCount, states: OPEN) {\n        edges {\n          node {\n            number\n            title\n            author {\n              login\n            }\n            createdAt\n            labels(first: 5) {\n              nodes {\n                name\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n`;\n\nconst { repository } = await octokit.graphql(query, {\n  owner: \"facebook\",\n  repo: \"react\",\n  issueCount: 10\n});\n```\n\n**GraphQL Mutation Example:**\n```javascript\nconst mutation = `\n  mutation($repositoryId: ID!, $issueTitle: String!, $issueBody: String!) {\n    createIssue(input: {\n      repositoryId: $repositoryId,\n      title: $issueTitle,\n      body: $issueBody\n    }) {\n      issue {\n        number\n        url\n      }\n    }\n  }\n`;\n\n// First get repository ID\nconst { repository } = await octokit.graphql(`\n  query($owner: String!, $name: String!) {\n    repository(owner: $owner, name: $name) {\n      id\n    }\n  }\n`, {\n  owner: \"owner\",\n  name: \"repo\"\n});\n\n// Create issue\nconst result = await octokit.graphql(mutation, {\n  repositoryId: repository.id,\n  issueTitle: \"New issue via GraphQL\",\n  issueBody: \"Issue body content\"\n});\n```\n\n## 5. Advanced Features\n\n### Pagination\n\n**Automatic Pagination - Get All Results:**\n```javascript\n// Get all issues (auto-handles pagination)\nconst allIssues = await octokit.paginate(\n  octokit.rest.issues.listForRepo,\n  {\n    owner: \"facebook\",\n    repo: \"react\",\n    state: \"all\",\n    per_page: 100\n  }\n);\n```\n\n**Iterator-based Pagination:**\n```javascript\n// Process results as they come\nfor await (const response of octokit.paginate.iterator(\n  octokit.rest.repos.listForOrg,\n  {\n    org: \"github\",\n    per_page: 100\n  }\n)) {\n  // response.data contains up to 100 items\n  // Process each batch here\n}\n```\n\n**Custom Page Limit:**\n```javascript\n// Get only first 500 items across pages\nconst limitedResults = await octokit.paginate(\n  octokit.rest.issues.listForRepo,\n  {\n    owner: \"owner\",\n    repo: \"repo\",\n    per_page: 100\n  },\n  (response, done) => {\n    if (response.data.length >= 500) {\n      done();\n    }\n    return response.data;\n  }\n);\n```\n\n### Error Handling\n\n**Comprehensive Error Handling:**\n```javascript\nimport { RequestError } from \"@octokit/request-error\";\n\ntry {\n  const { data } = await octokit.rest.repos.get({\n    owner: \"owner\",\n    repo: \"nonexistent\"\n  });\n} catch (error) {\n  if (error instanceof RequestError) {\n    console.error(`Error ${error.status}: ${error.message}`);\n\n    // Check specific error codes\n    if (error.status === 404) {\n      console.error(\"Repository not found\");\n    } else if (error.status === 403) {\n      if (error.response.headers[\"x-ratelimit-remaining\"] === \"0\") {\n        console.error(\"Rate limit exceeded\");\n        const resetTime = new Date(\n          error.response.headers[\"x-ratelimit-reset\"] * 1000\n        );\n        console.error(`Rate limit resets at ${resetTime}`);\n      } else {\n        console.error(\"Forbidden - check permissions\");\n      }\n    } else if (error.status === 401) {\n      console.error(\"Unauthorized - check authentication token\");\n    } else if (error.status >= 500) {\n      console.error(\"GitHub server error - retry later\");\n    }\n\n    // Log additional error details\n    console.error(\"Request ID:\", error.response.headers[\"x-github-request-id\"]);\n  } else {\n    console.error(\"Unexpected error:\", error);\n  }\n}\n```\n\n### Rate Limiting with Throttle Plugin\n\n**Setup:**\n```bash\nnpm install @octokit/plugin-throttling\n```\n\n**Implementation:**\n```javascript\nimport { Octokit } from \"@octokit/core\";\nimport { throttling } from \"@octokit/plugin-throttling\";\n\nconst MyOctokit = Octokit.plugin(throttling);\n\nconst octokit = new MyOctokit({\n  auth: process.env.GITHUB_TOKEN,\n  throttle: {\n    onRateLimit: (retryAfter, options, octokit, retryCount) => {\n      octokit.log.warn(\n        `Request quota exhausted for request ${options.method} ${options.url}`\n      );\n\n      // Retry first 3 times\n      if (retryCount < 3) {\n        octokit.log.info(`Retrying after ${retryAfter} seconds!`);\n        return true;\n      }\n    },\n    onSecondaryRateLimit: (retryAfter, options, octokit, retryCount) => {\n      octokit.log.warn(\n        `SecondaryRateLimit detected for request ${options.method} ${options.url}`\n      );\n\n      // Always retry on secondary rate limit\n      if (retryCount < 5) {\n        octokit.log.info(`Retrying after ${retryAfter} seconds!`);\n        return true;\n      }\n    }\n  }\n});\n```\n\n### Retry Plugin\n\n**Setup:**\n```bash\nnpm install @octokit/plugin-retry\n```\n\n**Implementation:**\n```javascript\nimport { Octokit } from \"@octokit/core\";\nimport { retry } from \"@octokit/plugin-retry\";\n\nconst MyOctokit = Octokit.plugin(retry);\n\nconst octokit = new MyOctokit({\n  auth: process.env.GITHUB_TOKEN\n});\n\n// Automatic retries on 500 errors (up to 3 times)\nconst { data } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n\n// Manual retry configuration\nconst { data: issues } = await octokit.rest.issues.listForRepo({\n  owner: \"owner\",\n  repo: \"repo\",\n  request: {\n    retries: 5,\n    retryAfter: 3 // seconds\n  }\n});\n```\n\n### Custom Request Options\n\n**Timeouts:**\n```javascript\nconst { data } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\",\n  request: {\n    timeout: 10000 // 10 seconds\n  }\n});\n```\n\n**Custom Headers:**\n```javascript\nconst { data } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\",\n  headers: {\n    \"X-GitHub-Api-Version\": \"2022-11-28\"\n  }\n});\n```\n\n**Signal for Abort:**\n```javascript\nconst controller = new AbortController();\n\nsetTimeout(() => controller.abort(), 5000); // Abort after 5s\n\ntry {\n  const { data } = await octokit.rest.repos.get({\n    owner: \"owner\",\n    repo: \"repo\",\n    request: {\n      signal: controller.signal\n    }\n  });\n} catch (error) {\n  if (error.name === \"AbortError\") {\n    console.log(\"Request was aborted\");\n  }\n}\n```\n\n## 6. TypeScript Usage\n\n### Basic TypeScript Setup\n\n**tsconfig.json Configuration:**\n```json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node16\",\n    \"module\": \"node16\",\n    \"target\": \"ES2022\",\n    \"lib\": [\"ES2022\"]\n  }\n}\n```\n\n### Type-Safe API Calls\n\n**Import Types:**\n```typescript\nimport { Octokit } from \"octokit\";\nimport type { RestEndpointMethodTypes } from \"@octokit/plugin-rest-endpoint-methods\";\n\n// Type for a specific endpoint\ntype GetRepoResponse = RestEndpointMethodTypes[\"repos\"][\"get\"][\"response\"];\ntype GetRepoParams = RestEndpointMethodTypes[\"repos\"][\"get\"][\"parameters\"];\n\nconst octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });\n\nconst params: GetRepoParams = {\n  owner: \"octokit\",\n  repo: \"rest.js\"\n};\n\nconst response: GetRepoResponse = await octokit.rest.repos.get(params);\nconst repo = response.data;\n```\n\n**Generic Response Types:**\n```typescript\nimport type { Endpoints } from \"@octokit/types\";\n\ntype IssuesListResponse = Endpoints[\"GET /repos/{owner}/{repo}/issues\"][\"response\"];\ntype Issue = Endpoints[\"GET /repos/{owner}/{repo}/issues\"][\"response\"][\"data\"][number];\n\nconst issues: IssuesListResponse = await octokit.rest.issues.listForRepo({\n  owner: \"facebook\",\n  repo: \"react\"\n});\n\nconst firstIssue: Issue = issues.data[0];\n```\n\n**Custom Type-Safe Wrapper:**\n```typescript\ninterface GitHubService {\n  getRepository(owner: string, repo: string): Promise<Repository>;\n  createIssue(params: CreateIssueParams): Promise<Issue>;\n}\n\ninterface Repository {\n  name: string;\n  description: string;\n  stars: number;\n  url: string;\n}\n\ninterface CreateIssueParams {\n  owner: string;\n  repo: string;\n  title: string;\n  body: string;\n  labels?: string[];\n}\n\ninterface Issue {\n  number: number;\n  title: string;\n  url: string;\n}\n\nclass GitHubClient implements GitHubService {\n  constructor(private octokit: Octokit) {}\n\n  async getRepository(owner: string, repo: string): Promise<Repository> {\n    const { data } = await this.octokit.rest.repos.get({ owner, repo });\n\n    return {\n      name: data.name,\n      description: data.description || \"\",\n      stars: data.stargazers_count,\n      url: data.html_url\n    };\n  }\n\n  async createIssue(params: CreateIssueParams): Promise<Issue> {\n    const { data } = await this.octokit.rest.issues.create({\n      owner: params.owner,\n      repo: params.repo,\n      title: params.title,\n      body: params.body,\n      labels: params.labels\n    });\n\n    return {\n      number: data.number,\n      title: data.title,\n      url: data.html_url\n    };\n  }\n}\n\n// Usage\nconst client = new GitHubClient(octokit);\nconst repo = await client.getRepository(\"facebook\", \"react\");\n```\n\n### GraphQL TypeScript\n\n```typescript\nimport { Octokit } from \"octokit\";\n\ninterface RepositoryQuery {\n  repository: {\n    name: string;\n    stargazerCount: number;\n    issues: {\n      totalCount: number;\n      nodes: Array<{\n        number: number;\n        title: string;\n        author: {\n          login: string;\n        } | null;\n      }>;\n    };\n  };\n}\n\nconst octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });\n\nconst result: RepositoryQuery = await octokit.graphql(`\n  query($owner: String!, $repo: String!) {\n    repository(owner: $owner, name: $repo) {\n      name\n      stargazerCount\n      issues(last: 5, states: OPEN) {\n        totalCount\n        nodes {\n          number\n          title\n          author {\n            login\n          }\n        }\n      }\n    }\n  }\n`, {\n  owner: \"facebook\",\n  repo: \"react\"\n});\n```\n\n## 7. Best Practices\n\n### Authentication and Security\n\n**Never Hardcode Tokens:**\n```javascript\n// BAD - Never do this\nconst octokit = new Octokit({ auth: \"ghp_actualtoken123\" });\n\n// GOOD - Use environment variables\nconst octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });\n```\n\n**Use Fine-Grained Tokens:**\nFine-grained personal access tokens provide more granular permissions and are repository-scoped. Use them instead of classic tokens when possible.\n\n**Rotate Tokens Regularly:**\nImplement a token rotation strategy, especially for long-running applications.\n\n**Use GitHub Apps for Production:**\nGitHub Apps provide better security, higher rate limits, and better audit trails than personal access tokens.\n\n### Rate Limiting Strategy\n\n**Check Rate Limit Status:**\n```javascript\nconst { data: rateLimit } = await octokit.rest.rateLimit.get();\n\nconsole.log(`Remaining: ${rateLimit.rate.remaining}/${rateLimit.rate.limit}`);\nconsole.log(`Resets at: ${new Date(rateLimit.rate.reset * 1000)}`);\n\n// Check specific resource limits\nconsole.log(`Search limit: ${rateLimit.resources.search.remaining}`);\nconsole.log(`GraphQL limit: ${rateLimit.resources.graphql.remaining}`);\n```\n\n**Implement Backoff Strategy:**\n```javascript\nasync function makeRequestWithBackoff(fn, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn();\n    } catch (error) {\n      if (error.status === 403 && error.response.headers[\"x-ratelimit-remaining\"] === \"0\") {\n        const resetTime = parseInt(error.response.headers[\"x-ratelimit-reset\"]) * 1000;\n        const waitTime = resetTime - Date.now();\n\n        if (i < maxRetries - 1) {\n          console.log(`Rate limited. Waiting ${waitTime}ms...`);\n          await new Promise(resolve => setTimeout(resolve, waitTime));\n          continue;\n        }\n      }\n      throw error;\n    }\n  }\n}\n```\n\n**Use Conditional Requests:**\n```javascript\n// First request\nconst { data, headers } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n\nconst etag = headers.etag;\n\n// Later request - only downloads if changed\nconst { status, data: newData } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\",\n  headers: {\n    \"If-None-Match\": etag\n  }\n});\n\nif (status === 304) {\n  console.log(\"No changes - use cached data\");\n} else {\n  console.log(\"Data changed - use new data\");\n}\n```\n\n### Error Recovery\n\n**Implement Retry Logic:**\n```javascript\nasync function retryRequest(fn, maxRetries = 3, delay = 1000) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn();\n    } catch (error) {\n      const isLastRetry = i === maxRetries - 1;\n      const shouldRetry = error.status >= 500 || error.status === 429;\n\n      if (!shouldRetry || isLastRetry) {\n        throw error;\n      }\n\n      const backoffDelay = delay * Math.pow(2, i);\n      console.log(`Retry ${i + 1}/${maxRetries} after ${backoffDelay}ms`);\n      await new Promise(resolve => setTimeout(resolve, backoffDelay));\n    }\n  }\n}\n\n// Usage\nconst data = await retryRequest(\n  () => octokit.rest.repos.get({ owner: \"owner\", repo: \"repo\" })\n);\n```\n\n### Performance Optimization\n\n**Use GraphQL for Complex Queries:**\n```javascript\n// BAD - Multiple REST requests\nconst { data: repo } = await octokit.rest.repos.get({ owner, repo });\nconst { data: issues } = await octokit.rest.issues.listForRepo({ owner, repo });\nconst { data: pulls } = await octokit.rest.pulls.list({ owner, repo });\n\n// GOOD - Single GraphQL request\nconst result = await octokit.graphql(`\n  query($owner: String!, $repo: String!) {\n    repository(owner: $owner, name: $repo) {\n      name\n      description\n      issues(last: 10, states: OPEN) {\n        totalCount\n        nodes { number title }\n      }\n      pullRequests(last: 10, states: OPEN) {\n        totalCount\n        nodes { number title }\n      }\n    }\n  }\n`, { owner, repo });\n```\n\n**Batch Operations:**\n```javascript\n// Process items in batches to avoid overwhelming the API\nasync function processBatch(items, batchSize, handler) {\n  for (let i = 0; i < items.length; i += batchSize) {\n    const batch = items.slice(i, i + batchSize);\n    await Promise.all(batch.map(handler));\n\n    // Brief pause between batches\n    if (i + batchSize < items.length) {\n      await new Promise(resolve => setTimeout(resolve, 1000));\n    }\n  }\n}\n\n// Usage\nawait processBatch(\n  repositories,\n  10,\n  async (repo) => {\n    const { data } = await octokit.rest.repos.get({\n      owner: repo.owner,\n      repo: repo.name\n    });\n    // Process repo data\n  }\n);\n```\n\n### Data Validation\n\n**Validate Input:**\n```javascript\nfunction validateRepoParams(owner, repo) {\n  if (!owner || typeof owner !== \"string\" || owner.trim() === \"\") {\n    throw new Error(\"Invalid owner parameter\");\n  }\n  if (!repo || typeof repo !== \"string\" || repo.trim() === \"\") {\n    throw new Error(\"Invalid repo parameter\");\n  }\n  if (!/^[a-zA-Z0-9-_.]+$/.test(owner)) {\n    throw new Error(\"Owner contains invalid characters\");\n  }\n  if (!/^[a-zA-Z0-9-_.]+$/.test(repo)) {\n    throw new Error(\"Repo contains invalid characters\");\n  }\n}\n\n// Usage\nvalidateRepoParams(userInput.owner, userInput.repo);\nconst { data } = await octokit.rest.repos.get({\n  owner: userInput.owner,\n  repo: userInput.repo\n});\n```\n\n**Sanitize Output:**\n```javascript\nfunction sanitizeIssue(issue) {\n  return {\n    number: issue.number,\n    title: issue.title.trim(),\n    body: issue.body?.trim() || \"\",\n    state: issue.state,\n    createdAt: new Date(issue.created_at),\n    author: issue.user?.login || \"unknown\"\n  };\n}\n```\n\n## 8. Production Checklist\n\n### Version Pinning\n```json\n{\n  \"dependencies\": {\n    \"octokit\": \"3.1.2\"\n  }\n}\n```\n\nPin exact versions (no `^` or `~`) to prevent unexpected breaking changes.\n\n### Robust Error Handling\n```javascript\n// Production-ready request wrapper\nasync function safeRequest(requestFn) {\n  try {\n    const { data } = await requestFn();\n    return { success: true, data, error: null };\n  } catch (error) {\n    console.error(\"GitHub API Error:\", {\n      status: error.status,\n      message: error.message,\n      requestId: error.response?.headers?.[\"x-github-request-id\"],\n      timestamp: new Date().toISOString()\n    });\n\n    return {\n      success: false,\n      data: null,\n      error: {\n        code: error.status,\n        message: error.message,\n        retryable: error.status >= 500 || error.status === 429\n      }\n    };\n  }\n}\n\n// Usage\nconst result = await safeRequest(\n  () => octokit.rest.repos.get({ owner: \"owner\", repo: \"repo\" })\n);\n\nif (result.success) {\n  console.log(result.data);\n} else {\n  console.error(\"Request failed:\", result.error);\n  if (result.error.retryable) {\n    // Implement retry logic\n  }\n}\n```\n\n### Environment Configuration\n```javascript\n// config.js\nexport const config = {\n  github: {\n    token: process.env.GITHUB_TOKEN,\n    baseUrl: process.env.GITHUB_API_URL || \"https://api.github.com\",\n    timeout: parseInt(process.env.GITHUB_TIMEOUT || \"30000\"),\n    userAgent: `${process.env.APP_NAME}/${process.env.APP_VERSION}`\n  }\n};\n\n// Validate configuration on startup\nfunction validateConfig() {\n  if (!config.github.token) {\n    throw new Error(\"GITHUB_TOKEN environment variable is required\");\n  }\n  if (config.github.timeout < 1000 || config.github.timeout > 60000) {\n    throw new Error(\"GITHUB_TIMEOUT must be between 1000 and 60000\");\n  }\n}\n\nvalidateConfig();\n\nexport const octokit = new Octokit({\n  auth: config.github.token,\n  baseUrl: config.github.baseUrl,\n  userAgent: config.github.userAgent,\n  request: {\n    timeout: config.github.timeout\n  }\n});\n```\n\n### Logging and Monitoring\n```javascript\nimport { Octokit } from \"@octokit/core\";\n\nclass LoggingOctokit extends Octokit {\n  constructor(options) {\n    super(options);\n\n    this.hook.before(\"request\", async (options) => {\n      console.log(`[GitHub API] ${options.method} ${options.url}`, {\n        timestamp: new Date().toISOString()\n      });\n    });\n\n    this.hook.after(\"request\", async (response, options) => {\n      console.log(`[GitHub API] ${options.method} ${options.url} - ${response.status}`, {\n        rateLimit: response.headers[\"x-ratelimit-remaining\"],\n        timestamp: new Date().toISOString()\n      });\n    });\n\n    this.hook.error(\"request\", async (error, options) => {\n      console.error(`[GitHub API] ${options.method} ${options.url} - ERROR`, {\n        status: error.status,\n        message: error.message,\n        requestId: error.response?.headers?.[\"x-github-request-id\"],\n        timestamp: new Date().toISOString()\n      });\n      throw error;\n    });\n  }\n}\n\nconst octokit = new LoggingOctokit({ auth: process.env.GITHUB_TOKEN });\n```\n\n### Validate Structured Output\n```javascript\nfunction validateRepository(data) {\n  const required = [\"id\", \"name\", \"full_name\", \"owner\", \"html_url\"];\n  for (const field of required) {\n    if (!(field in data)) {\n      throw new Error(`Missing required field: ${field}`);\n    }\n  }\n  return data;\n}\n\nconst { data } = await octokit.rest.repos.get({ owner, repo });\nconst validatedRepo = validateRepository(data);\n```\n\n### Avoid Preview/Unstable APIs\n```javascript\n// BAD - Using preview API\nconst { data } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\",\n  mediaType: {\n    previews: [\"mercy\"] // Preview API\n  }\n});\n\n// GOOD - Use stable APIs only\nconst { data } = await octokit.rest.repos.get({\n  owner: \"owner\",\n  repo: \"repo\"\n});\n```\n\n### Health Checks\n```javascript\nasync function healthCheck() {\n  try {\n    const { data: rateLimit } = await octokit.rest.rateLimit.get();\n    const remaining = rateLimit.rate.remaining;\n\n    return {\n      healthy: remaining > 100,\n      rateLimit: {\n        remaining,\n        limit: rateLimit.rate.limit,\n        reset: new Date(rateLimit.rate.reset * 1000)\n      }\n    };\n  } catch (error) {\n    return {\n      healthy: false,\n      error: error.message\n    };\n  }\n}\n\n// Run periodically\nsetInterval(async () => {\n  const health = await healthCheck();\n  if (!health.healthy) {\n    console.warn(\"GitHub API health check failed\", health);\n  }\n}, 60000); // Every minute\n```\n\n### Testing Strategy\n```javascript\n// Mock Octokit for tests\nimport { jest } from \"@jest/globals\";\n\nconst mockOctokit = {\n  rest: {\n    repos: {\n      get: jest.fn().mockResolvedValue({\n        data: {\n          id: 1,\n          name: \"test-repo\",\n          full_name: \"owner/test-repo\",\n          owner: { login: \"owner\" },\n          html_url: \"https://github.com/owner/test-repo\"\n        }\n      })\n    }\n  }\n};\n\n// Test\ntest(\"getRepository returns formatted data\", async () => {\n  const client = new GitHubClient(mockOctokit);\n  const repo = await client.getRepository(\"owner\", \"test-repo\");\n\n  expect(repo.name).toBe(\"test-repo\");\n  expect(mockOctokit.rest.repos.get).toHaveBeenCalledWith({\n    owner: \"owner\",\n    repo: \"test-repo\"\n  });\n});\n```\n\n### Graceful Degradation\n```javascript\nasync function getRepoWithFallback(owner, repo) {\n  try {\n    const { data } = await octokit.rest.repos.get({ owner, repo });\n    return data;\n  } catch (error) {\n    if (error.status === 404) {\n      console.warn(`Repository ${owner}/${repo} not found`);\n      return null;\n    }\n    if (error.status === 403) {\n      console.warn(\"Rate limited - using cached data\");\n      return getCachedRepo(owner, repo);\n    }\n    throw error; // Re-throw unexpected errors\n  }\n}\n```\n"
  },
  {
    "path": "content/github3-py/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"github3.py package guide for Python - GitHub API client patterns for tokens, repositories, issues, and pagination\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"github,api,rest,automation,python\"\n---\n\n# github3.py Python Package Guide\n\n## Golden Rule\n\nInstall `github3.py`, import it as `github3`, and authenticate with a token for GitHub.com work.\n\n```bash\npip install github3.py==4.0.1\n```\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\n```\n\nThe package name is `github3.py`, but the import name is `github3`.\n\n## Installation\n\n### pip\n\n```bash\npip install github3.py\n```\n\n### Pin the documented version\n\n```bash\npip install github3.py==4.0.1\n```\n\n### Poetry\n\n```bash\npoetry add github3.py@4.0.1\n```\n\n### uv\n\n```bash\nuv add github3.py==4.0.1\n```\n\n## Authentication And Setup\n\nFor GitHub.com automation, put a personal access token or GitHub App installation token in an environment variable and pass it to `github3.login`.\n\n```bash\nexport GITHUB_TOKEN=\"ghp_your_token\"\n```\n\n```python\nimport os\nimport github3\n\ntoken = os.environ[\"GITHUB_TOKEN\"]\ngh = github3.login(token=token)\nviewer = gh.me()\nprint(viewer.login)\n```\n\n### Recommended token setup\n\n- Use a fine-grained personal access token when you only need a user-scoped script.\n- Use a GitHub App installation token for automation that should avoid personal credentials.\n- Scope the token to the repositories and permissions the script actually needs.\n\n### Enterprise note\n\n`github3.py` also documents GitHub Enterprise support. If you are targeting GitHub Enterprise Server, verify the base URL and enterprise-specific login flow in the upstream docs before writing code.\n\n## Core Usage\n\n### Get a repository object\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\nrepo = gh.repository(\"owner\", \"repo-name\")\n\nprint(repo.full_name)\nprint(repo.clone_url)\n```\n\n### Create an issue\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\nrepo = gh.repository(\"owner\", \"repo-name\")\n\nissue = repo.create_issue(\n    title=\"Bug report from automation\",\n    body=\"Created by github3.py\"\n)\n\nprint(issue.html_url)\n```\n\n### Read an existing issue\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\nissue = gh.issue(\"owner\", \"repo-name\", 1)\n\nprint(issue.title)\nprint(issue.state)\n```\n\n### Create a gist\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\ngist = gh.create_gist(\n    description=\"Example gist\",\n    files={\"hello.py\": {\"content\": \"print('hello')\\n\"}},\n    public=False,\n)\n\nprint(gist.html_url)\n```\n\n## Pagination And Iteration\n\nMany collection-returning methods are lazy iterators over paginated GitHub API responses. Iterate them directly instead of forcing everything into memory.\n\n```python\nimport os\nimport github3\n\ngh = github3.login(token=os.environ[\"GITHUB_TOKEN\"])\n\nfor repo in gh.repositories():\n    print(repo.full_name)\n```\n\nUse iterator limits when you only need a small sample, and keep pagination behavior in mind for orgs or users with many repositories, issues, or pull requests.\n\n## Configuration Patterns\n\n### Minimal env-driven helper\n\n```python\nimport os\nimport github3\n\ndef get_github() -> github3.GitHub:\n    token = os.environ[\"GITHUB_TOKEN\"]\n    return github3.login(token=token)\n```\n\n### Check the authenticated user early\n\n```python\ngh = get_github()\nme = gh.me()\n\nif me is None:\n    raise RuntimeError(\"Authentication failed\")\n```\n\nThis is a useful early sanity check before mutating repositories or issues.\n\n## Common Pitfalls\n\n### Package name vs import name\n\nInstall `github3.py`, but write `import github3`.\n\n### Do not rely on username/password auth for GitHub.com\n\nSome upstream docs and examples still show `github3.login(username=..., password=...)`. The library exposes that API, but GitHub removed password authentication for the REST API on August 13, 2021. For GitHub.com, use a token instead.\n\n### Treat iterators as paginated network calls\n\nObjects returned from list-style methods usually fetch pages on demand. Repeated iteration can trigger repeated API traffic and rate-limit consumption.\n\n### Expect permission-dependent behavior\n\nMissing scopes or repository permissions commonly show up as `403` responses or empty-looking result sets. Check token permissions before debugging method names.\n\n### Verify object methods against the right object type\n\n`github3.py` has separate methods on the top-level `GitHub` session object and on resource objects like `Repository`, `Issue`, and `Gist`. Fetch the right object first, then call the method on that object.\n\n## Version-Sensitive Notes\n\n- The package version covered here is `4.0.1`, matching the PyPI release page.\n- The canonical documentation root is `https://github3.readthedocs.io/en/latest/`. The source URL `https://github3py.readthedocs.io/en/latest/` appears to be stale or non-canonical.\n- PyPI currently declares Python `>=3.7` for `4.0.1`.\n- Upstream docs are useful but not fully aligned with modern GitHub.com auth guidance. Prefer token-based examples in new code even if older docs show password parameters.\n\n## Official Sources\n\n- Docs root: https://github3.readthedocs.io/en/latest/\n- Quickstart/auth examples: https://github3.readthedocs.io/en/latest/examples/authentication.html\n- README usage examples: https://github.com/sigmavirus24/github3.py\n- PyPI package page: https://pypi.org/project/github3.py/\n- GitHub authentication change notice: https://github.blog/changelog/2021-08-12-git-password-authentication-is-shutting-down/\n"
  },
  {
    "path": "content/glob/docs/glob/javascript/DOC.md",
    "content": "---\nname: glob\ndescription: \"JavaScript guide for `glob`, covering async and sync filesystem matching, `cwd` and `ignore` usage, `Path` results, and Windows-specific pattern rules.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"13.0.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"glob,javascript,node,filesystem,patterns\"\n---\n\n# glob Guide for JavaScript\n\n## Golden Rule\n\nInstall `glob`, not `node-glob`, write glob expressions with forward slashes, and choose the result shape you want up front:\n\n- strings from `glob()`, `globSync()`, `globIterate()`, and `globStream()`\n- `Path` objects from `withFileTypes: true`\n\n`glob@13.0.6` is a Node.js filesystem utility. It does not use authentication, does not require a client object, and does not have package-specific environment variables. The package declares support for Node `18 || 20 || >=22`.\n\n## Install\n\n```bash\nnpm install glob@13.0.6\n```\n\n## Imports and Initialization\n\n### ECMAScript modules\n\n```js\nimport {\n  Glob,\n  escape,\n  glob,\n  globIterate,\n  globSync,\n  hasMagic,\n} from 'glob';\n```\n\n### CommonJS\n\n```js\nconst {\n  Glob,\n  escape,\n  glob,\n  globIterate,\n  globSync,\n  hasMagic,\n} = require('glob');\n```\n\nThere is no service client to initialize. Import the helpers you need and call them directly.\n\n## Common Workflows\n\n### Find matching files asynchronously\n\n`glob()` resolves to an array of matches. For relative patterns, results are relative to `cwd` unless you set `absolute: true`.\n\n```js\nimport { glob } from 'glob';\n\nconst files = await glob('src/**/*.js', {\n  cwd: process.cwd(),\n  ignore: ['**/node_modules/**', '**/dist/**'],\n  nodir: true,\n  absolute: true,\n});\n\nconsole.log(files);\n```\n\n### Match multiple patterns\n\nPass a string array when you want to search several patterns in one call.\n\n```js\nimport { glob } from 'glob';\n\nconst assets = await glob([\n  'public/**/*.{png,jpg,jpeg,svg}',\n  'src/**/*.{png,jpg,jpeg,svg}',\n], {\n  cwd: process.cwd(),\n  nodir: true,\n});\n\nconsole.log(assets);\n```\n\n### Stop a long walk with `AbortSignal`\n\n```js\nimport { glob } from 'glob';\n\nconst styles = await glob('**/*.css', {\n  cwd: process.cwd(),\n  signal: AbortSignal.timeout(250),\n});\n\nconsole.log(styles);\n```\n\n### Iterate without building a full result array\n\nUse `globIterate()` when you want to process matches as they are discovered.\n\n```js\nimport { globIterate } from 'glob';\n\nfor await (const file of globIterate('logs/**/*.log', {\n  cwd: process.cwd(),\n  nodir: true,\n})) {\n  console.log(file);\n}\n```\n\nUse `globSync()` for short scripts and startup work where blocking I/O is acceptable.\n\n```js\nimport { globSync } from 'glob';\n\nconst configFiles = globSync('packages/*/package.json', {\n  cwd: process.cwd(),\n  nodir: true,\n});\n\nconsole.log(configFiles);\n```\n\n### Return rich `Path` objects\n\nSet `withFileTypes: true` to get `Path` objects instead of strings. Add `stat: true` when you need fields such as `mtimeMs` or `mode`.\n\n```js\nimport { glob } from 'glob';\n\nconst entries = await glob('packages/*', {\n  cwd: process.cwd(),\n  withFileTypes: true,\n  stat: true,\n});\n\nfor (const entry of entries) {\n  console.log({\n    name: entry.name,\n    fullpath: entry.fullpath(),\n    isDirectory: entry.isDirectory(),\n    modifiedMs: entry.mtimeMs,\n  });\n}\n```\n\nDo not combine `withFileTypes: true` with `absolute: true`. If you need an absolute path from a `Path` result, call `entry.fullpath()`.\n\n### Reuse caches across related searches\n\nConstruct a `Glob` instance when you need to search the same tree repeatedly. You can pass an existing `Glob` object as the options argument to reuse its settings and caches.\n\n```js\nimport { Glob } from 'glob';\n\nconst base = new Glob('packages/*/src/**/*.ts', {\n  cwd: process.cwd(),\n  ignore: ['**/node_modules/**'],\n  nodir: true,\n});\n\nconst sourceFiles = await base.walk();\nconst testFiles = await new Glob('packages/*/test/**/*.ts', base).walk();\n\nconsole.log({ sourceFiles, testFiles });\n```\n\n### Treat user input as a literal filename\n\nUse `escape()` when a user-supplied string should match literally instead of being interpreted as a glob pattern. Use `hasMagic()` to decide whether a pattern contains glob metacharacters.\n\n```js\nimport { escape, glob, hasMagic } from 'glob';\n\nconst input = process.argv[2];\nconst pattern = hasMagic(input) ? input : escape(input);\n\nconst matches = await glob(pattern, {\n  cwd: process.cwd(),\n  nodir: true,\n});\n\nconsole.log(matches);\n```\n\nBrace expansion is not treated as “magic” by `hasMagic()` unless you pass `magicalBraces: true`.\n\n## Pattern Rules and Pitfalls\n\n- Use `/` in glob expressions on every platform. In patterns, `\\` is an escape character, not a path separator.\n- If you must pass a Windows-style pattern built with `path.join()` or `path.resolve()`, set `windowsPathsNoEscape: true`. In that mode, literal glob metacharacters such as `*` and `?` cannot be escaped.\n- Use the `ignore` option for exclusions. Leading `!pattern` negation and `#comment` handling were removed in v6.\n- `ignore` patterns always run in `dot:true` mode. To exclude a directory and everything below it, use a pattern like `node_modules/**`.\n- `matchBase: true` makes a pattern with no slash, such as `*.js`, behave like `**/*.js`.\n- `nodir: true` removes directories from results. To match only directories, end the pattern with `/`.\n- `root` only changes how absolute patterns beginning with `/` are resolved. It does not sandbox traversal, and a pattern containing `..` can still walk outside that root.\n- `follow: true` makes `**` follow symlinked directories, which can introduce duplicates and slow traversal.\n\n## Version Notes\n\n### No bundled CLI in v13\n\nAs of `glob` v13, the CLI moved to a separate package:\n\n```bash\nnpm install glob-bin\n```\n\nUse `glob` for library code and install `glob-bin` separately only when you need a command-line interface.\n\n### Windows behavior\n\nOn Windows, always write glob expressions with forward slashes. For example, use `src/**/*.js`, not `src\\**\\*.js`.\n\nIf you set `posix: true` on Windows, returned string paths use `/` separators and absolute results are returned in UNC form such as `//?/C:/path/to/file`.\n"
  },
  {
    "path": "content/google/docs/access-context-manager/python/DOC.md",
    "content": "---\nname: access-context-manager\ndescription: \"Google Cloud Access Context Manager Python client for access policies, access levels, service perimeters, and GCP user access bindings\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,python,access-context-manager,vpc-service-controls,access-levels,service-perimeters\"\n---\n\n# Google Cloud Access Context Manager Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-access-context-manager` for Access Context Manager policy data in Python, authenticate with Application Default Credentials (ADC), and keep one policy on one API track. Google publishes both `v1` and `v1alpha` surfaces, but the official RPC docs warn not to mix `v1` and `v1alpha` calls in the same access policy.\n\nThis package is still published on PyPI as `0.3.0` with an alpha classifier, so pin the version you expect and verify request fields against the current Google docs before changing production perimeters.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-access-context-manager==0.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-access-context-manager==0.3.0\"\npoetry add \"google-cloud-access-context-manager==0.3.0\"\n```\n\n## Authentication And Setup\n\nBefore writing code:\n\n1. Enable the Access Context Manager API.\n2. Make sure the caller can edit the organization policy. Google documents `roles/accesscontextmanager.policyEditor` for common setup flows.\n3. Use ADC locally with `gcloud auth application-default login`, or use an attached service account in Google Cloud.\n4. Work with organization and policy resource names, not bare IDs.\n\nLocal setup:\n\n```bash\ngcloud services enable accesscontextmanager.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_ORGANIZATION=\"123456789012\"\nexport ACCESS_POLICY_ID=\"9522\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful resource name formats:\n\n- organization: `organizations/{organization_id}`\n- access policy: `accessPolicies/{policy_id}`\n- access level: `accessPolicies/{policy_id}/accessLevels/{level_id}`\n- service perimeter: `accessPolicies/{policy_id}/servicePerimeters/{perimeter_id}`\n- GCP user access binding: `organizations/{organization_id}/gcpUserAccessBindings/{binding_id}`\n\n## Imports And Client Initialization\n\nUse the generated Python client surface:\n\n```python\nfrom google.cloud import accesscontextmanager_v1\n\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n```\n\nIf you are comparing this package with the lower-level Google API reference, the generated protobuf and RPC namespace is documented under `google.identity.accesscontextmanager.v1`.\n\n## Core Usage\n\n### List access policies in an organization\n\nEach organization has one access policy. Start here if you only know the organization ID.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\norganization_id = os.environ[\"GOOGLE_CLOUD_ORGANIZATION\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\nfor policy in client.list_access_policies(\n    request={\"parent\": f\"organizations/{organization_id}\"}\n):\n    print(policy.name, policy.title, policy.etag)\n```\n\n### Get one access policy\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\npolicy = client.get_access_policy(\n    request={\"name\": f\"accessPolicies/{policy_id}\"}\n)\n\nprint(policy.name)\nprint(policy.parent)\nprint(policy.title)\nprint(policy.etag)\n```\n\n### List and inspect access levels\n\n`accessLevels.list` is the practical way to discover existing policy rules. Use `CEL` format only if you need the expression form instead of the original basic/custom representation.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\nparent = f\"accessPolicies/{policy_id}\"\n\nfor level in client.list_access_levels(\n    request={\n        \"parent\": parent,\n        \"access_level_format\": accesscontextmanager_v1.LevelFormat.AS_DEFINED,\n    }\n):\n    print(level.name, level.title)\n```\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nlevel_name = f\"accessPolicies/{policy_id}/accessLevels/device_trusted\"\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\nlevel = client.get_access_level(\n    request={\n        \"name\": level_name,\n        \"access_level_format\": accesscontextmanager_v1.LevelFormat.AS_DEFINED,\n    }\n)\n\nprint(level.name)\nprint(level.title)\nprint(level.description)\n```\n\n### Create a basic access level\n\nAccess level names are immutable after creation. The level ID must start with a letter and then use only alphanumeric characters or `_`.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nparent = f\"accessPolicies/{policy_id}\"\nlevel_name = f\"{parent}/accessLevels/device_trusted\"\n\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\ncondition = accesscontextmanager_v1.Condition(\n    members=[\"user:alice@example.com\"],\n    regions=[\"US\"],\n    ip_subnetworks=[\"203.0.113.0/24\"],\n)\n\naccess_level = accesscontextmanager_v1.AccessLevel(\n    name=level_name,\n    title=\"device_trusted\",\n    description=\"Allow approved US traffic from the corp subnet\",\n    basic=accesscontextmanager_v1.BasicLevel(\n        conditions=[condition],\n        combining_function=accesscontextmanager_v1.ConditionCombiningFunction.AND,\n    ),\n)\n\noperation = client.create_access_level(\n    request={\n        \"parent\": parent,\n        \"access_level\": access_level,\n    }\n)\n\ncreated = operation.result(timeout=300)\nprint(created.name)\n```\n\nIf you prefer bulk replacement for policy-as-code workflows, the API also exposes `replaceAll` for access levels and accepts an optional policy `etag`.\n\n### List service perimeters\n\nService perimeter resources live under the access policy, not under projects.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\nfor perimeter in client.list_service_perimeters(\n    request={\"parent\": f\"accessPolicies/{policy_id}\"}\n):\n    print(perimeter.name, perimeter.title, perimeter.perimeter_type)\n```\n\n### Commit dry-run service perimeter specs\n\n`CommitServicePerimeters` copies each perimeter's `spec` into `status` when `use_explicit_dry_run_spec` is true. Pass the current policy `etag` when you want optimistic concurrency.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\npolicy_id = os.environ[\"ACCESS_POLICY_ID\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\npolicy_name = f\"accessPolicies/{policy_id}\"\n\npolicy = client.get_access_policy(request={\"name\": policy_name})\n\noperation = client.commit_service_perimeters(\n    request={\n        \"parent\": policy.name,\n        \"etag\": policy.etag,\n    }\n)\n\nresponse = operation.result(timeout=300)\n\nfor perimeter in response.service_perimeters:\n    print(perimeter.name)\n```\n\n### List organization-level GCP user access bindings\n\nUse these when you need Context-Aware Access restrictions for Cloud Console and Google Cloud APIs at the organization level.\n\n```python\nimport os\n\nfrom google.cloud import accesscontextmanager_v1\n\norganization_id = os.environ[\"GOOGLE_CLOUD_ORGANIZATION\"]\nclient = accesscontextmanager_v1.AccessContextManagerClient()\n\nfor binding in client.list_gcp_user_access_bindings(\n    request={\"parent\": f\"organizations/{organization_id}\"}\n):\n    print(binding.name, binding.group_key, list(binding.access_levels))\n```\n\nImportant binding constraints from the official API reference:\n\n- `groupKey` is the Google Group ID, not the group email address or alias.\n- `accessLevels` supports exactly one access level, not multiple.\n- create and patch operations can finish before the new restriction is fully deployed to all affected users.\n\n## Common Pitfalls\n\n- Do not mix `v1` and `v1alpha` mutations in the same access policy. Google explicitly warns that mixed usage can make a policy hard or impossible to update safely.\n- Access Context Manager is organization-scoped. Most calls use `organizations/{org_id}` or `accessPolicies/{policy_id}`, not project IDs alone.\n- Access level and service perimeter names are immutable after creation. Pick stable IDs early.\n- Access level conditions are strict. `members` supports users and service accounts, but not groups. Group-based enforcement belongs in `GcpUserAccessBinding`.\n- For service perimeters, resources use project numbers like `projects/{project_number}`, not project IDs.\n- Mutating calls are long-running operations. Wait for `.result()` before reading back the resource or chaining dependent operations.\n- Service perimeter propagation is not instant. Google documents that perimeter changes can take up to 30 minutes to take effect.\n- `use_explicit_dry_run_spec` must be true before you rely on `spec` for dry-run perimeter testing and later commit it.\n\n## Official Links\n\n- PyPI package: `https://pypi.org/project/google-cloud-access-context-manager/`\n- Maintainer repo: `https://github.com/googleapis/python-access-context-manager`\n- Generated docs root: `https://googleapis.dev/python/accesscontextmanager/latest/`\n- Access Context Manager RPC overview: `https://docs.cloud.google.com/access-context-manager/docs/reference/rpc`\n- `google.identity.accesscontextmanager.v1` RPC package: `https://docs.cloud.google.com/access-context-manager/docs/reference/rpc/google.identity.accesscontextmanager.v1`\n- Access policies REST resource: `https://docs.cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies`\n- Access levels REST resource: `https://docs.cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies.accessLevels`\n- Service perimeters REST resource: `https://docs.cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies.servicePerimeters`\n- GCP user access bindings REST resource: `https://docs.cloud.google.com/access-context-manager/docs/reference/rest/v1/organizations.gcpUserAccessBindings`\n- Manage access levels guide: `https://docs.cloud.google.com/access-context-manager/docs/manage-access-levels`\n- Manage service perimeters guide: `https://docs.cloud.google.com/vpc-service-controls/docs/manage-service-perimeters`\n"
  },
  {
    "path": "content/google/docs/aiplatform/javascript/DOC.md",
    "content": "---\nname: aiplatform\ndescription: \"Google Cloud Vertex AI Node.js client for managing Vertex AI resources and calling deployed prediction endpoints\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,vertex-ai,aiplatform,prediction,ml,javascript,nodejs\"\n---\n\n# `@google-cloud/aiplatform` JavaScript Package Guide\n\nUse `@google-cloud/aiplatform` when your Node.js app needs Vertex AI control-plane clients such as endpoints and models, or when it needs to send online prediction requests to an already deployed Vertex AI endpoint.\n\nThis package is a generated Google Cloud client library. Most application code should start with the stable `v1` clients and only use `v1beta1` when the maintainer docs for the feature you need are explicitly beta-only.\n\n## Golden Rule\n\n- Use the `v1` namespace unless the official page for your target method is explicitly beta-only.\n- Authenticate with Google Cloud Application Default Credentials (ADC), not API keys.\n- Set the client `apiEndpoint` to the same region as your Vertex AI resources, for example `us-central1-aiplatform.googleapis.com`.\n- Pass full Vertex AI resource names such as `projects/PROJECT_ID/locations/LOCATION/endpoints/ENDPOINT_ID`.\n- Convert prediction payloads with `helpers.toValue(...)` before calling `predict()`.\n\nThis guide covers `6.5.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/aiplatform@6.5.0\n```\n\n## Authentication And Setup\n\nTypical prerequisites:\n\n1. A Google Cloud project with Vertex AI enabled.\n2. Credentials with permission to read Vertex AI resources or call predictions.\n3. A regional Vertex AI location such as `us-central1`.\n4. An existing endpoint if your app is only sending predictions.\n\nEnable the Vertex AI API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable aiplatform.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nPrefer attached service-account credentials on Google Cloud over shipping JSON key files.\n\n## Initialize Clients\n\nCommonJS:\n\n```javascript\nconst {v1, helpers} = require('@google-cloud/aiplatform');\n\nfunction getVertexApiEndpoint(location = 'us-central1') {\n  return `${location}-aiplatform.googleapis.com`;\n}\n\nfunction createVertexClients(location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1') {\n  const clientOptions = {\n    apiEndpoint: getVertexApiEndpoint(location),\n  };\n\n  return {\n    endpointClient: new v1.EndpointServiceClient(clientOptions),\n    modelClient: new v1.ModelServiceClient(clientOptions),\n    predictionClient: new v1.PredictionServiceClient(clientOptions),\n    helpers,\n  };\n}\n```\n\nES modules:\n\n```javascript\nimport {v1, helpers} from '@google-cloud/aiplatform';\n\nfunction getVertexApiEndpoint(location = 'us-central1') {\n  return `${location}-aiplatform.googleapis.com`;\n}\n\nfunction createVertexClients(location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1') {\n  const clientOptions = {\n    apiEndpoint: getVertexApiEndpoint(location),\n  };\n\n  return {\n    endpointClient: new v1.EndpointServiceClient(clientOptions),\n    modelClient: new v1.ModelServiceClient(clientOptions),\n    predictionClient: new v1.PredictionServiceClient(clientOptions),\n    helpers,\n  };\n}\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/aiplatform');\n\nconst location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1';\n\nconst endpointClient = new v1.EndpointServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n  apiEndpoint: `${location}-aiplatform.googleapis.com`,\n});\n```\n\n## Core Workflows\n\n### List Endpoints In A Region\n\nUse the regional parent resource and async iteration so pagination stays simple:\n\n```javascript\nconst {v1} = require('@google-cloud/aiplatform');\n\nasync function listEndpoints(projectId, location = 'us-central1') {\n  const client = new v1.EndpointServiceClient({\n    apiEndpoint: `${location}-aiplatform.googleapis.com`,\n  });\n\n  const parent = `projects/${projectId}/locations/${location}`;\n  const endpoints = [];\n\n  for await (const endpoint of client.listEndpointsAsync({parent})) {\n    endpoints.push({\n      name: endpoint.name,\n      displayName: endpoint.displayName,\n    });\n  }\n\n  return endpoints;\n}\n```\n\nReuse the returned `name` field from this call instead of rebuilding endpoint resource names later.\n\n### Read One Endpoint\n\n`getEndpoint()` expects the full resource name:\n\n```javascript\nconst {v1} = require('@google-cloud/aiplatform');\n\nasync function getEndpoint(endpointName, location = 'us-central1') {\n  const client = new v1.EndpointServiceClient({\n    apiEndpoint: `${location}-aiplatform.googleapis.com`,\n  });\n\n  const [endpoint] = await client.getEndpoint({\n    name: endpointName,\n  });\n\n  return endpoint;\n}\n```\n\nExample endpoint name:\n\n```text\nprojects/my-project/locations/us-central1/endpoints/1234567890123456789\n```\n\n### Send An Online Prediction Request\n\n`predict()` sends requests to an existing deployed endpoint. Convert each instance and any parameters with `helpers.toValue(...)` so the request matches the protobuf `Value` fields used by the API.\n\n```javascript\nconst {v1, helpers} = require('@google-cloud/aiplatform');\n\nasync function predictText(endpointName, text, location = 'us-central1') {\n  const client = new v1.PredictionServiceClient({\n    apiEndpoint: `${location}-aiplatform.googleapis.com`,\n  });\n\n  const instances = [\n    helpers.toValue({\n      content: text,\n    }),\n  ];\n\n  const [response] = await client.predict({\n    endpoint: endpointName,\n    instances,\n  });\n\n  return response.predictions;\n}\n\npredictText(\n  'projects/my-project/locations/us-central1/endpoints/1234567890123456789',\n  'This support experience was excellent.'\n).then(predictions => {\n  console.dir(predictions, {depth: null});\n});\n```\n\nThe instance shape is model-specific. The API will not infer the correct schema from the endpoint name alone.\n\nIf your deployed model expects additional prediction parameters, convert those too:\n\n```javascript\nconst parameters = helpers.toValue({\n  confidenceThreshold: 0.5,\n  maxPredictions: 5,\n});\n\nconst [response] = await client.predict({\n  endpoint: endpointName,\n  instances,\n  parameters,\n});\n```\n\n### List Models In A Region\n\nUse `ModelServiceClient` when you need to inspect available models before choosing one to deploy or reference elsewhere.\n\n```javascript\nconst {v1} = require('@google-cloud/aiplatform');\n\nasync function listModels(projectId, location = 'us-central1') {\n  const client = new v1.ModelServiceClient({\n    apiEndpoint: `${location}-aiplatform.googleapis.com`,\n  });\n\n  const parent = `projects/${projectId}/locations/${location}`;\n  const models = [];\n\n  for await (const model of client.listModelsAsync({parent})) {\n    models.push({\n      name: model.name,\n      displayName: model.displayName,\n    });\n  }\n\n  return models;\n}\n```\n\n## Practical Notes\n\n- Vertex AI is regional. Keep `apiEndpoint`, resource names, storage, and any deployed endpoint IDs in the same region.\n- Reuse client instances instead of creating a new gRPC client for every request.\n- Reuse the resource `name` returned by the API instead of stitching strings together in multiple places.\n- Many mutating Vertex AI methods return long-running operations. Wait for the returned operation before assuming the resource is ready.\n- Start with `v1` unless the official method page you need is only documented in `v1beta1`.\n\n## Common Pitfalls\n\n- `gcloud auth login` is not enough for local Node.js code. Use `gcloud auth application-default login` so ADC works.\n- Do not use API keys with this package. Use ADC, user credentials, or a service account.\n- A bare endpoint ID is not enough for most requests. Pass the full endpoint resource name.\n- A client pointed at `us-central1-aiplatform.googleapis.com` will not behave correctly if you pass a resource from another region.\n- `predict()` does not take arbitrary plain JavaScript objects for protobuf `Value` fields. Convert request data with `helpers.toValue(...)`.\n- Do not mix stable `v1` snippets with `v1beta1` snippets unless the maintainer docs for the exact feature say you should.\n\n## Official Sources\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/aiplatform/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/aiplatform`\n- ADC setup for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Vertex AI sample index: `https://cloud.google.com/vertex-ai/docs/samples`\n- Vertex AI locations: `https://cloud.google.com/vertex-ai/docs/general/locations`\n"
  },
  {
    "path": "content/google/docs/aiplatform/python/DOC.md",
    "content": "---\nname: aiplatform\ndescription: \"Google Cloud Vertex AI Python SDK and client library for training, pipelines, prediction, and Vertex AI resource management\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.141.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,vertex-ai,ml,genai,pipelines,prediction\"\n---\n\n# Google Cloud Vertex AI Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-aiplatform` for Vertex AI work in Python, authenticate with Application Default Credentials (ADC), and call `aiplatform.init(...)` once before creating jobs or resources.\n\nPrefer the high-level SDK first:\n\n- `from google.cloud import aiplatform` for most Vertex AI workflows\n- `from google.cloud import aiplatform_v1` or `from google.cloud.aiplatform import gapic` when you need lower-level API coverage\n- `import vertexai.preview` only for preview-only surfaces\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-aiplatform==1.141.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-aiplatform==1.141.0\"\npoetry add \"google-cloud-aiplatform==1.141.0\"\n```\n\nPyPI also publishes extras for common workflows. The most useful ones for agents are:\n\n```bash\npython -m pip install \"google-cloud-aiplatform[pipelines]==1.141.0\"\npython -m pip install \"google-cloud-aiplatform[prediction]==1.141.0\"\npython -m pip install \"google-cloud-aiplatform[full]==1.141.0\"\n```\n\nIf you are not sure which extra you need, start with the base package and only add extras when the upstream docs or import errors require them.\n\n## Project And Auth Setup\n\nVertex AI expects a Google Cloud project, the Vertex AI API enabled, and ADC available to the process.\n\nEnable the API:\n\n```bash\ngcloud services enable aiplatform.googleapis.com\n```\n\nFor local development, create ADC with your user account:\n\n```bash\ngcloud auth application-default login\n```\n\nFor production on Google Cloud, prefer an attached service account over a downloaded key file.\n\nIf you must use a service account key locally, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_CLOUD_STAGING_BUCKET=\"gs://your-staging-bucket\"\n```\n\n## Initialize The SDK\n\nInitialize once near process startup and reuse that configuration:\n\n```python\nimport os\n\nfrom google.cloud import aiplatform\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nSTAGING_BUCKET = os.getenv(\"GOOGLE_CLOUD_STAGING_BUCKET\")\n\naiplatform.init(\n    project=PROJECT_ID,\n    location=LOCATION,\n    staging_bucket=STAGING_BUCKET,\n)\n```\n\nWhy this matters:\n\n- `project` and `location` determine where resources are created and looked up\n- `staging_bucket` is reused by pipelines, training jobs, and other artifact-producing workflows\n- any default service account, network, or CMEK settings should be set before creating resources\n\n## Core Usage Patterns\n\n### Reference an existing endpoint and send predictions\n\nUse the resource-name constructor when the endpoint already exists:\n\n```python\nfrom google.cloud import aiplatform\n\nendpoint = aiplatform.Endpoint(\n    \"projects/PROJECT_ID/locations/us-central1/endpoints/ENDPOINT_ID\"\n)\n\nprediction = endpoint.predict(\n    instances=[\n        [6.4, 3.1, 5.5, 1.8],\n        [5.1, 3.5, 1.4, 0.2],\n    ]\n)\n\nprint(prediction.predictions)\n```\n\nThe instance shape must match the schema of the deployed model. Agents should not invent request bodies here.\n\n### Submit a pipeline job\n\n```python\nfrom google.cloud import aiplatform\n\njob = aiplatform.PipelineJob(\n    display_name=\"daily-train\",\n    template_path=\"gs://my-bucket/pipelines/train.yaml\",\n    pipeline_root=\"gs://my-bucket/pipeline-root\",\n    parameter_values={\n        \"project\": \"your-project-id\",\n        \"location\": \"us-central1\",\n    },\n    enable_caching=True,\n)\n\njob.run(sync=True)\n```\n\nUse `sync=False` if your app should submit and return immediately, then poll job state later.\n\n### Track experiment params and metrics\n\n```python\nfrom google.cloud import aiplatform\n\naiplatform.init(\n    project=\"your-project-id\",\n    location=\"us-central1\",\n    experiment=\"baseline-experiment\",\n)\n\nwith aiplatform.start_run(\"xgboost-baseline\"):\n    aiplatform.log_params({\"learning_rate\": 0.1, \"max_depth\": 6})\n    aiplatform.log_metrics({\"accuracy\": 0.94, \"f1\": 0.91})\n```\n\n### Drop to lower-level clients when needed\n\nUse the lower-level API clients when the high-level wrapper has not exposed a new field or resource yet:\n\n```python\nfrom google.cloud import aiplatform_v1\n\njob_client = aiplatform_v1.JobServiceClient()\nmodel_client = aiplatform_v1.ModelServiceClient()\n```\n\nThis package also exposes GAPIC clients through `google.cloud.aiplatform.gapic`, but most application code should start with the higher-level `aiplatform` module first.\n\n## Config Notes For Agents\n\n- Vertex AI is regional. Keep `location`, storage buckets, endpoints, and resource names aligned.\n- Initialize once per process instead of scattering different `aiplatform.init(...)` calls across modules.\n- Many helpers accept explicit `credentials`, `project`, `location`, `network`, `service_account`, or `encryption_spec_key_name` overrides. Prefer explicit overrides only when one job needs behavior different from the process default.\n- Long-running operations are common. Use `sync=True` when your code depends on the result immediately, or keep the returned resource/job object and poll state explicitly.\n- Preview features may require `vertexai.preview` imports and can change faster than the stable `aiplatform` surface.\n\n## Common Pitfalls\n\n- `gcloud auth login` is not enough for local SDK code. Use `gcloud auth application-default login` so ADC works in Python.\n- Do not hard-code service account key files into repos or container images. Prefer attached identities on GCP.\n- The package contains multiple namespaces. `google.cloud.aiplatform` is the normal entry point; do not mix random snippets from `aiplatform_v1beta1`, `gapic`, and `vertexai.preview` unless you know why.\n- Region mismatches cause many confusing failures. A pipeline in `us-central1` with a bucket or endpoint in another region is a common source of errors.\n- Pipeline and training examples often assume a staging bucket already exists. If `staging_bucket` is missing, artifact-heavy workflows usually fail later than you expect.\n- Endpoint prediction payloads are model-specific. The SDK will not infer your instance schema from the endpoint resource name.\n- Many online examples still use older generative APIs in this package. Check the deprecation note below before copying them.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-aiplatform 1.141.0` with `Python >=3.9`.\n- Some Google-hosted reference pages and search snippets lag the actual PyPI package version. Treat PyPI as the source of truth for package-version metadata and the Vertex AI docs/reference pages as the source of truth for behavior and examples.\n- Google has deprecated several generative AI modules in this package, including `vertexai.generative_models`, `vertexai.language_models`, `vertexai.vision_models`, `vertexai.tuning`, and `vertexai.caching`. The official deprecation page says they were deprecated on June 24, 2025 and are scheduled for removal on June 24, 2026.\n- For new Gemini and generative AI application code, prefer the `google-genai` SDK and avoid starting fresh work on those deprecated `vertexai.*` generative modules.\n\n## Official Sources Used\n\n- PyPI package page: `https://pypi.org/project/google-cloud-aiplatform/`\n- PyPI JSON metadata: `https://pypi.org/pypi/google-cloud-aiplatform/json`\n- Vertex AI Python reference root: `https://docs.cloud.google.com/python/docs/reference/aiplatform/latest`\n- Vertex AI install guide: `https://cloud.google.com/vertex-ai/docs/start/install-sdk`\n- Vertex AI authentication guide: `https://cloud.google.com/vertex-ai/docs/authentication`\n- Vertex AI Python SDK guide: `https://cloud.google.com/vertex-ai/docs/python-sdk/use-vertex-ai-python-sdk`\n- Generative SDK deprecation notice: `https://cloud.google.com/vertex-ai/generative-ai/docs/deprecations/genai-vertexai-sdk`\n- Official repository: `https://github.com/googleapis/python-aiplatform`\n"
  },
  {
    "path": "content/google/docs/alloydb/python/DOC.md",
    "content": "---\nname: alloydb\ndescription: \"google-cloud-alloydb Python package guide for managing AlloyDB clusters, instances, backups, users, and admin SQL through the AlloyDB Admin API\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,alloydb,gcp,database,postgresql,admin\"\n---\n\n# google-cloud-alloydb Python Package Guide\n\n## What This Package Is For\n\n`google-cloud-alloydb` is the generated Python client library for the AlloyDB Admin API.\n\nUse it when your code needs to:\n\n- list or inspect AlloyDB clusters, instances, backups, users, databases, and operations\n- create, update, or delete AlloyDB resources through Google Cloud APIs\n- fetch instance connection metadata with `get_connection_info`\n- run administrative SQL with `execute_sql`\n\nDo not use this package as your normal PostgreSQL application driver. It is the control-plane SDK. For application connections to an AlloyDB instance, use the separate `google-cloud-alloydb-connector` package together with a driver such as `pg8000` or `asyncpg`.\n\nThe import surface is:\n\n```python\nfrom google.cloud import alloydb_v1\n```\n\n## Version-Sensitive Notes\n\n- This entry keeps `0.8.0` in frontmatter because that was the version used here provided for review.\n- Public upstream sources checked on 2026-03-12 did not verify a public `0.8.0` release. PyPI currently shows `0.7.0`.\n- The hosted Google Cloud reference also lags PyPI: the `latest` changelog still tops out at `0.6.0`.\n- Treat the docs root as the canonical API reference, but verify the exact installed package version before pinning dependencies or depending on release-specific behavior.\n- PyPI metadata says the package supports Python `>=3.7`.\n\n## Install\n\nUse the public package name from PyPI:\n\n```bash\npip install google-cloud-alloydb\n```\n\nPin only after checking what your index actually serves:\n\n```bash\npip install \"google-cloud-alloydb==0.7.0\"\n```\n\nIf your project genuinely depends on a private or mirrored `0.8.0`, confirm that in your artifact registry before copying the pin above.\n\n## Authentication And Environment Setup\n\nThis library uses Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud init\ngcloud services enable alloydb.googleapis.com\ngcloud auth application-default login\n```\n\nService account based auth:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\n```\n\nPractical permission guidance:\n\n- for admin operations, start with `roles/alloydb.admin`\n- to create a cluster, Google Cloud also requires `compute.networks.list`; the docs call out `roles/compute.networkUser` as the least-privilege way to get that permission\n- cluster creation also depends on private services access and other AlloyDB networking prerequisites already being configured in the target project and region\n\n## Initialize A Client\n\nUse the GA `v1` surface unless you specifically need a method that only exists on a preview surface:\n\n```python\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\n```\n\nPrefer full resource names in requests:\n\n```python\nproject = \"my-project\"\nregion = \"us-central1\"\ncluster = \"my-cluster\"\ninstance = \"my-primary\"\n\nlocation_name = f\"projects/{project}/locations/{region}\"\ncluster_name = f\"{location_name}/clusters/{cluster}\"\ninstance_name = f\"{cluster_name}/instances/{instance}\"\n```\n\nMost request fields expect these full resource names, not short IDs.\n\n## Core Read Workflows\n\n### List Clusters\n\n```python\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\nrequest = alloydb_v1.ListClustersRequest(\n    parent=\"projects/my-project/locations/us-central1\"\n)\n\nfor cluster in client.list_clusters(request=request):\n    print(cluster.name, cluster.state)\n```\n\n`list_*` methods return pagers. Iterate directly unless you need custom page-token handling.\n\n### List Instances In A Cluster\n\n```python\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\nrequest = alloydb_v1.ListInstancesRequest(\n    parent=\"projects/my-project/locations/us-central1/clusters/my-cluster\"\n)\n\nfor instance in client.list_instances(request=request):\n    print(instance.name, instance.instance_type, instance.state)\n```\n\n### Fetch Connection Metadata\n\nUse `get_connection_info` when you need admin-plane connection details for an instance:\n\n```python\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\nrequest = alloydb_v1.GetConnectionInfoRequest(\n    parent=(\n        \"projects/my-project/locations/us-central1/\"\n        \"clusters/my-cluster/instances/my-primary\"\n    )\n)\n\ninfo = client.get_connection_info(request=request)\nprint(info)\n```\n\n### Run Administrative SQL\n\n`execute_sql` is for controlled admin tasks, not for normal application query traffic.\n\n```python\nimport os\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\nrequest = alloydb_v1.ExecuteSqlRequest(\n    instance=(\n        \"projects/my-project/locations/us-central1/\"\n        \"clusters/my-cluster/instances/my-primary\"\n    ),\n    database=\"postgres\",\n    user=\"postgres\",\n    password=os.environ[\"ALLOYDB_DB_PASSWORD\"],\n    sql_statement=\"SELECT current_database();\",\n)\n\nresponse = client.execute_sql(request=request)\nprint(response)\n```\n\n`database` and `user` are plain database identifiers, not resource paths.\n\n## Mutating Operations\n\nCreate, update, and delete calls typically return long-running operations. Wait on `.result()` before assuming the resource is ready.\n\n```python\nimport uuid\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient()\nrequest = alloydb_v1.CreateClusterRequest(\n    parent=\"projects/my-project/locations/us-central1\",\n    cluster_id=\"dev-cluster\",\n    cluster=alloydb_v1.Cluster(\n        display_name=\"dev-cluster\",\n        # Fill in the required network, initial user, and config fields.\n    ),\n    request_id=str(uuid.uuid4()),\n)\n\noperation = client.create_cluster(request=request)\ncreated_cluster = operation.result(timeout=1800)\nprint(created_cluster.name)\n```\n\nUse a `request_id` on mutating calls when your caller might retry after a timeout or transport failure.\n\n## Configuration Notes\n\n### Endpoints\n\nIf your environment requires an endpoint override, pass `client_options` explicitly:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import alloydb_v1\n\nclient = alloydb_v1.AlloyDBAdminClient(\n    client_options=ClientOptions(api_endpoint=\"YOUR_ALLOYDB_ENDPOINT\")\n)\n```\n\n### Async Usage\n\nIf your service is already async, use `AlloyDBAdminAsyncClient` instead of pushing the sync client through thread executors.\n\n### Logging\n\nThe PyPI package page documents environment-based logging for Google client libraries:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.alloydb_v1\n```\n\nOnly enable this in environments where you are comfortable with RPC metadata appearing in logs.\n\n## Common Pitfalls\n\n- `google-cloud-alloydb` manages AlloyDB resources; it is not your regular Postgres connection library.\n- Use full resource names like `projects/.../locations/.../clusters/...`, not bare IDs.\n- Expect long-running operations for provisioning and destructive changes.\n- `execute_sql` needs database credentials; it does not replace connection pooling or ordinary query execution.\n- Cluster creation also depends on private networking prerequisites outside this Python package.\n- Google-hosted reference pages can lag PyPI releases, so check both the installed version and the reference docs before relying on version-specific behavior.\n- If you need app-level connections, use `google-cloud-alloydb-connector` with `pg8000` or `asyncpg` instead of trying to route runtime traffic through the admin client.\n\n## Official Sources\n\n- Google Cloud AlloyDB Python reference root: https://cloud.google.com/python/docs/reference/alloydb/latest\n- AlloyDB changelog: https://cloud.google.com/python/docs/reference/alloydb/latest/changelog\n- `AlloyDBAdminClient` reference: https://cloud.google.com/python/docs/reference/alloydb/latest/google.cloud.alloydb_v1.services.alloy_d_b_admin.AlloyDBAdminClient\n- AlloyDB cluster creation guide: https://cloud.google.com/alloydb/docs/cluster-create\n- Google Cloud client-library authentication guide: https://cloud.google.com/docs/authentication/client-libraries\n- PyPI package page: https://pypi.org/project/google-cloud-alloydb/\n- AlloyDB Python Connector package page: https://pypi.org/project/google-cloud-alloydb-connector/\n"
  },
  {
    "path": "content/google/docs/api-core/python/DOC.md",
    "content": "---\nname: api-core\ndescription: \"google-api-core Python package guide for shared Google client helpers such as auth handoff, client options, retries, exceptions, pagination, and long-running operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.30.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,python,auth,retry,pagination,long-running-operations\"\n---\n\n# google-api-core Python Package Guide\n\n## Golden Rule\n\nUse `google-api-core` as shared infrastructure behind a real Google client library, not as a standalone SDK. Install the service-specific package you actually need, import helpers from `google.api_core`, and prefer Application Default Credentials (ADC) or an explicit credentials object over file-path shortcuts in `ClientOptions`.\n\n## When To Use It\n\n`google-api-core` provides the common behavior used by generated Google clients:\n\n- auth handoff into client constructors\n- `ClientOptions` for endpoint, mTLS, scopes, quota project, API key, and universe domain\n- retry helpers and retry predicates\n- normalized exception classes\n- iterator wrappers for paginated APIs\n- long-running operation futures\n\nIf you need service methods, install the service package too. For example, use `google-cloud-secret-manager`, `google-cloud-pubsub`, or `google-cloud-bigquery` for actual API calls.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-api-core==2.30.0\"\n```\n\nUseful extras from PyPI:\n\n```bash\npython -m pip install \"google-api-core[grpc]==2.30.0\"\npython -m pip install \"google-api-core[async-rest]==2.30.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-api-core==2.30.0\"\npoetry add \"google-api-core==2.30.0\"\n```\n\nNotes:\n\n- `grpc` is relevant when the client library uses gRPC transports.\n- `async-rest` is relevant for async REST transports in newer generated clients.\n- Many Google packages pull `google-api-core` transitively, but explicit pinning is useful when your project depends on retry, paging, or operation behavior.\n\n## Authentication And Setup\n\nThe official auth guide for `google-api-core` expects the same Google Cloud patterns used by generated clients:\n\n1. On Google Cloud runtimes, ADC usually works automatically.\n2. For local development, use `gcloud auth application-default login`.\n3. Outside Google Cloud, use a service account credential object or set `GOOGLE_APPLICATION_CREDENTIALS`.\n\nMinimal local setup:\n\n```bash\ngcloud auth application-default login\n```\n\nService-account setup:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nExplicit credentials object:\n\n```python\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\",\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n```\n\nGenerated clients normally accept either no credentials argument, which triggers ADC, or `credentials=...`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import secretmanager_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\",\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n\nclient = secretmanager_v1.SecretManagerServiceClient(\n    credentials=credentials,\n    client_options=ClientOptions(quota_project_id=\"billing-project\"),\n)\n```\n\n## ClientOptions\n\n`ClientOptions` is the main configuration object shared across Google generated clients.\n\nTypical uses:\n\n- `api_endpoint`: regional endpoint, private service endpoint, emulator-style host when supported\n- `quota_project_id`: charge quota and billing to a different project\n- `scopes`: override OAuth scopes when the client supports it\n- `api_key`: only for APIs that explicitly support API keys\n- `client_cert_source` or `client_encrypted_cert_source`: mTLS client certificate configuration\n- `universe_domain`: non-default Google universe domain when the service supports it\n\nExample:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import secretmanager_v1\n\nclient = secretmanager_v1.SecretManagerServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=\"secretmanager.googleapis.com\",\n        quota_project_id=\"billing-project\",\n        universe_domain=\"googleapis.com\",\n    )\n)\n```\n\nImportant behavior:\n\n- `api_endpoint` wins if both `api_endpoint` and `universe_domain` are set.\n- `credentials_file` exists today but is deprecated and will be removed in the next major `google-api-core` release.\n- `credentials_file` and `api_key` are mutually exclusive.\n- `client_cert_source` and `client_encrypted_cert_source` are mutually exclusive.\n\n## Core Usage Patterns\n\n### Pass retry, timeout, and metadata on RPCs\n\nMost GAPIC methods accept `retry=`, `timeout=`, and `metadata=` keyword arguments.\n\n```python\nfrom google.api_core import exceptions, retry\nfrom google.cloud import secretmanager_v1\n\nclient = secretmanager_v1.SecretManagerServiceClient()\n\nrpc_retry = retry.Retry(\n    predicate=retry.if_exception_type(\n        exceptions.TooManyRequests,\n        exceptions.ServiceUnavailable,\n        exceptions.DeadlineExceeded,\n    ),\n    initial=1.0,\n    maximum=30.0,\n    multiplier=2.0,\n    timeout=120.0,\n)\n\nresponse = client.access_secret_version(\n    request={\"name\": \"projects/my-project/secrets/my-secret/versions/latest\"},\n    retry=rpc_retry,\n    timeout=10.0,\n    metadata=[(\"x-goog-user-project\", \"billing-project\")],\n)\n```\n\nUse `timeout` for per-call timing. Use `retry.timeout` for total retry budget. In current docs, `deadline` still works for backward compatibility, but it is deprecated in favor of `timeout`.\n\n### Catch normalized Google API exceptions\n\nGenerated clients convert transport-specific errors into `google.api_core.exceptions.*` types.\n\n```python\nfrom google.api_core import exceptions\n\ntry:\n    response = client.access_secret_version(\n        request={\"name\": secret_version_name},\n        retry=rpc_retry,\n        timeout=10.0,\n    )\nexcept exceptions.NotFound:\n    print(\"Secret version does not exist\")\nexcept exceptions.PermissionDenied:\n    print(\"Caller does not have the required IAM permission\")\nexcept exceptions.ResourceExhausted:\n    print(\"Quota or rate limit exceeded\")\nexcept exceptions.GoogleAPICallError as exc:\n    print(f\"Unexpected Google API failure: {exc}\")\n```\n\n`RetryError` is separate: it means the retry policy exhausted its budget while the underlying exception kept matching the retry predicate.\n\n### Work with pagers\n\nList methods in generated clients often return pager objects backed by `google.api_core.page_iterator`.\n\n```python\nfrom google.cloud import secretmanager_v1\n\nclient = secretmanager_v1.SecretManagerServiceClient()\npager = client.list_secrets(request={\"parent\": \"projects/my-project\"})\n\nfor secret in pager:\n    print(secret.name)\n```\n\nIf you need page-level handling instead of item-level iteration:\n\n```python\nfor page in pager.pages:\n    print(\"page start\")\n    for secret in page:\n        print(secret.name)\n```\n\nNotes:\n\n- Iteration is lazy; additional RPCs happen as pages are consumed.\n- The core library exposes both HTTP and gRPC iterator implementations. Generated clients usually hide those details behind pager objects.\n\n### Wait for long-running operations\n\nOperations returned by Google clients are wrapped as `google.api_core.operation.Operation` or async equivalents.\n\n```python\noperation = client.some_long_running_method(request={...})\n\nresult = operation.result(timeout=300)\nprint(result)\n\nif operation.metadata is not None:\n    print(operation.metadata)\n```\n\nUseful operation methods:\n\n- `result(timeout=...)`\n- `done()`\n- `cancel()`\n- `exception()`\n- `add_done_callback(...)`\n\nPolling behavior is controlled by a retry-style polling configuration internally. For current releases, prefer the `polling` argument over the older `retry` argument when you are working directly with `google.api_core.operation.Operation`.\n\n### Async retry helpers\n\nFor async clients and async transports, use `google.api_core.retry_async.AsyncRetry` instead of the sync `Retry` helper:\n\n```python\nfrom google.api_core import exceptions, retry_async\n\nasync_retry = retry_async.AsyncRetry(\n    predicate=retry_async.if_exception_type(\n        exceptions.TooManyRequests,\n        exceptions.ServiceUnavailable,\n    ),\n    timeout=60.0,\n)\n```\n\nIf a generated async client already has default retry behavior, pass your own `retry=` only when you need different backoff or failure handling.\n\n## Common Pitfalls\n\n- `google-api-core` does not expose product-specific methods. You still need the real service client package.\n- The pip package name is `google-api-core`, but the import path is `google.api_core`.\n- Do not assume API keys work for every Google API. Many Google Cloud clients require OAuth credentials or service-account credentials.\n- Avoid `ClientOptions(credentials_file=...)` in new code. Current docs mark it deprecated; prefer ADC or an explicit credentials object.\n- `retry.timeout` is not the same as per-request `timeout`. The first controls total retry budget; the second controls a single RPC attempt.\n- Pagers are lazy. Calling `list(pager)` can trigger many requests and load every item into memory.\n- Regional and private endpoints are service-specific. Only set `api_endpoint` when the service documentation tells you what host to use.\n- `universe_domain` must match the credentials' universe domain. Do not set it casually.\n\n## Version-Sensitive Notes For 2.30.0\n\n- As of March 12, 2026, the version used here `2.30.0` matches the current PyPI release.\n- The official docs root is a `latest` URL, not a version-pinned documentation tree. Use PyPI and the changelog to validate version-specific behavior.\n- The official changelog for `2.30.0` records two notable changes: Python `>=3.9` is now required, and the minimum supported `protobuf` version is `4.25.8`.\n- The `2.25.2` changelog marks `ClientOptions.credentials_file` as deprecated. Do not build new patterns around it even though the parameter still exists in current docs.\n- `google-api-core` remains stable at the package level, but retry defaults, transport support, and generated-client behavior can still shift across Google service packages. Check the service package docs when behavior seems inconsistent.\n"
  },
  {
    "path": "content/google/docs/api-gateway/python/DOC.md",
    "content": "---\nname: api-gateway\ndescription: \"Google Cloud API Gateway Python client for managing APIs, API configs, gateways, and rollouts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,api-gateway,api-management,openapi,gateway\"\n---\n\n# google-cloud-api-gateway Python Package Guide\n\n## What This Package Is For\n\n`google-cloud-api-gateway` is the official Python client for the API Gateway control plane. Use it to create and manage:\n\n- APIs\n- API configs\n- Gateways\n- gateway rollouts from one config to another\n\nThe main import surface is:\n\n```python\nfrom google.cloud import apigateway_v1\n```\n\nThis package manages API Gateway resources. It does not send end-user traffic through your deployed gateway for you. Your application still calls the deployed `https://...gateway.dev` URL like any other HTTPS API.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-api-gateway 1.14.0` as the current package release on March 13, 2026.\n- The generated client reference for the current line exposes both `ApiGatewayServiceClient` and `ApiGatewayServiceAsyncClient`.\n- The package changelog for the current line notes two recent behavior changes that matter in real projects:\n  - `1.13.0` added Python 3.14 support.\n  - `1.13.0` deprecated the `credentials_file` argument. Prefer Application Default Credentials or pass an explicit `credentials=` object instead.\n- API Gateway product docs added OpenAPI 3.0 support on November 12, 2025. Older tutorials that say API Gateway only accepts OpenAPI 2.0 are outdated.\n\n## Install\n\nPin the package when you need reproducible generated-client behavior:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-api-gateway==1.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-api-gateway==1.14.0\"\npoetry add \"google-cloud-api-gateway==1.14.0\"\n```\n\n## Authentication And Setup\n\nThis library uses Google Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud services enable apigateway.googleapis.com\ngcloud services enable servicemanagement.googleapis.com\ngcloud services enable servicecontrol.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport API_ID=\"orders-api\"\nexport API_CONFIG_ID=\"orders-config-v1\"\nexport GATEWAY_ID=\"orders-gateway\"\nexport OPENAPI_SPEC_PATH=\"openapi.yaml\"\nexport GATEWAY_SERVICE_ACCOUNT=\"gateway-invoker@my-project.iam.gserviceaccount.com\"\n```\n\nService account credentials when you explicitly need file-based auth:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/abs/path/service-account.json\"\n```\n\nImportant setup details from the product docs:\n\n- The identity creating or updating an API config or gateway needs `iam.serviceAccounts.actAs` on the gateway service account. Google documents this through the Service Account User role (`roles/iam.serviceAccountUser`).\n- The gateway service account itself needs permission to invoke your backend, for example `roles/run.invoker` for Cloud Run.\n- APIs and API configs live under `locations/global`, but gateways are regional resources.\n- Gateways can only host one API config at a time.\n\n## Initialize A Client\n\n```python\nimport google.auth\nfrom google.cloud import apigateway_v1\n\ncredentials, project_id = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\n\nclient = apigateway_v1.ApiGatewayServiceClient(credentials=credentials)\nprint(project_id)\n```\n\nIf you do not need to inspect the resolved project, ADC-only initialization is enough:\n\n```python\nfrom google.cloud import apigateway_v1\n\nclient = apigateway_v1.ApiGatewayServiceClient()\n```\n\n## Resource Names And Parents\n\nUse the helper methods instead of hand-building resource names:\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\napi_id = os.environ[\"API_ID\"]\nconfig_id = os.environ[\"API_CONFIG_ID\"]\ngateway_id = os.environ[\"GATEWAY_ID\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\n\nglobal_parent = client.common_location_path(project_id, \"global\")\nregional_parent = client.common_location_path(project_id, location)\n\napi_name = client.api_path(project_id, api_id)\napi_config_name = client.api_config_path(project_id, api_id, config_id)\ngateway_name = client.gateway_path(project_id, location, gateway_id)\n```\n\nUse `global_parent` for `create_api(...)` and `regional_parent` for `create_gateway(...)`.\n\n## List Existing Resources\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\nglobal_parent = client.common_location_path(project_id, \"global\")\nregional_parent = client.common_location_path(project_id, location)\n\nfor api in client.list_apis(parent=global_parent):\n    print(\"API:\", api.name, api.display_name)\n\nfor gateway in client.list_gateways(parent=regional_parent):\n    print(\"Gateway:\", gateway.name, gateway.default_hostname, gateway.state.name)\n```\n\nThe list methods return pagers, so iterate over them directly.\n\n## Create An API\n\nAPI IDs must be lowercase letters, numbers, or dashes, cannot start with a dash, and cannot contain underscores.\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napi_id = os.environ[\"API_ID\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\nglobal_parent = client.common_location_path(project_id, \"global\")\n\noperation = client.create_api(\n    parent=global_parent,\n    api_id=api_id,\n    api=apigateway_v1.Api(\n        display_name=\"Orders API\",\n    ),\n)\n\ncreated_api = operation.result(timeout=300)\nprint(created_api.name)\n```\n\nIf you omit `managed_service`, the API resource automatically creates a managed service in the same project.\n\n## Create An API Config From An OpenAPI Document\n\nAPI config creation is the step that uploads your OpenAPI file and associates the gateway service account used for backend authentication.\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napi_id = os.environ[\"API_ID\"]\nconfig_id = os.environ[\"API_CONFIG_ID\"]\nspec_path = Path(os.environ[\"OPENAPI_SPEC_PATH\"])\ngateway_service_account = os.environ[\"GATEWAY_SERVICE_ACCOUNT\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\napi_parent = client.api_path(project_id, api_id)\n\nopenapi_bytes = spec_path.read_bytes()\n\noperation = client.create_api_config(\n    parent=api_parent,\n    api_config_id=config_id,\n    api_config=apigateway_v1.ApiConfig(\n        display_name=\"Orders API config v1\",\n        gateway_service_account=gateway_service_account,\n        openapi_documents=[\n            apigateway_v1.ApiConfig.OpenApiDocument(\n                document=apigateway_v1.ApiConfig.File(\n                    path=spec_path.name,\n                    contents=openapi_bytes,\n                )\n            )\n        ],\n    ),\n)\n\ncreated_config = operation.result(timeout=900)\nprint(created_config.name)\nprint(created_config.service_config_id)\n```\n\nImportant details:\n\n- Pass raw bytes with `Path(...).read_bytes()`.\n- `openapi_documents` and `grpc_services` are mutually exclusive on `ApiConfig`.\n- Product docs warn that only one API config can be created at a time for the same API.\n- API config IDs use the same character rules as API IDs.\n\n## Deploy A Config To A Gateway\n\nGateway IDs have a stricter length limit than API and config IDs. Product docs say they must be 49 characters or fewer, lowercase letters, numbers, or dashes, and no underscores.\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\napi_id = os.environ[\"API_ID\"]\nconfig_id = os.environ[\"API_CONFIG_ID\"]\ngateway_id = os.environ[\"GATEWAY_ID\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\nregional_parent = client.common_location_path(project_id, location)\napi_config_name = client.api_config_path(project_id, api_id, config_id)\n\noperation = client.create_gateway(\n    parent=regional_parent,\n    gateway_id=gateway_id,\n    gateway=apigateway_v1.Gateway(\n        display_name=\"Orders gateway\",\n        api_config=api_config_name,\n    ),\n)\n\ngateway = operation.result(timeout=900)\nprint(gateway.name)\nprint(gateway.default_hostname)\nprint(gateway.state.name)\n```\n\nAfter the operation finishes, send traffic to:\n\n```text\nhttps://<default_hostname>\n```\n\nThe product docs describe the deployed hostname shape as `https://GATEWAY_ID-HASH.REGION_CODE.gateway.dev`.\n\n## Fetch One Gateway And Use Its Hostname\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ngateway_id = os.environ[\"GATEWAY_ID\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\ngateway_name = client.gateway_path(project_id, location, gateway_id)\n\ngateway = client.get_gateway(name=gateway_name)\nprint(gateway.default_hostname)\nprint(gateway.api_config)\nprint(gateway.state.name)\n```\n\n`default_hostname` is the easiest value to hand to callers or smoke tests.\n\n## Roll A Gateway Forward To A New Config\n\nYou do not edit the OpenAPI document in place. Upload a new API config, then point the gateway at that new config.\n\n```python\nimport os\n\nfrom google.cloud import apigateway_v1\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\napi_id = os.environ[\"API_ID\"]\ngateway_id = os.environ[\"GATEWAY_ID\"]\nnew_config_id = \"orders-config-v2\"\n\nclient = apigateway_v1.ApiGatewayServiceClient()\n\ngateway_name = client.gateway_path(project_id, location, gateway_id)\nnew_config_name = client.api_config_path(project_id, api_id, new_config_id)\n\noperation = client.update_gateway(\n    gateway=apigateway_v1.Gateway(\n        name=gateway_name,\n        api_config=new_config_name,\n    ),\n    update_mask=field_mask_pb2.FieldMask(paths=[\"api_config\"]),\n)\n\nupdated_gateway = operation.result(timeout=900)\nprint(updated_gateway.api_config)\nprint(updated_gateway.state.name)\n```\n\nThe product docs call this a zero-downtime update model, but they also note that some requests can still hit the old config while the new one is propagating.\n\n## Delete Resources In The Safe Order\n\nDelete the gateway first if it is using the config you want to remove.\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\napi_id = os.environ[\"API_ID\"]\nconfig_id = os.environ[\"API_CONFIG_ID\"]\ngateway_id = os.environ[\"GATEWAY_ID\"]\n\nclient = apigateway_v1.ApiGatewayServiceClient()\n\ngateway_name = client.gateway_path(project_id, location, gateway_id)\napi_config_name = client.api_config_path(project_id, api_id, config_id)\napi_name = client.api_path(project_id, api_id)\n\nclient.delete_gateway(name=gateway_name).result(timeout=900)\nclient.delete_api_config(name=api_config_name).result(timeout=900)\nclient.delete_api(name=api_name).result(timeout=900)\n```\n\nIf a gateway still points at an API config, product docs say deleting that config will fail until you either deploy a different config or delete the gateway.\n\n## Async Usage\n\nIf your application is already asyncio-based, use the async client:\n\n```python\nimport os\nfrom google.cloud import apigateway_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = apigateway_v1.ApiGatewayServiceAsyncClient()\nglobal_parent = client.common_location_path(project_id, \"global\")\n\nasync def list_apis() -> None:\n    async for api in client.list_apis(parent=global_parent):\n        print(api.name)\n```\n\n## Common Pitfalls\n\n- Do not treat this package as a runtime API caller. It manages API Gateway resources, not end-user calls through the gateway.\n- Keep the resource hierarchy straight: APIs and configs are global; gateways are regional.\n- Do not try to mutate an existing API config to change the uploaded spec. Product docs say config updates are limited to labels and display name. Upload a new config, then update the gateway.\n- Wait for long-running operations with `.result()` before assuming the resource is ready.\n- Use a gateway service account with the minimum backend permissions needed, and make sure the operator creating the config can act as that service account.\n- API Gateway does not support proxying to other Google Cloud APIs such as `*.googleapis.com`; Google documents those requests as failing with `401` because API Gateway uses ID tokens while Google APIs expect access tokens.\n- If you enable Google client-library logging, treat those logs as sensitive. The package docs warn that log output can contain sensitive information.\n- If your environment has mTLS client certificates configured, the generated client can switch endpoints based on `GOOGLE_API_USE_MTLS_ENDPOINT` and `GOOGLE_API_USE_CLIENT_CERTIFICATE`. Set `client_options.api_endpoint` explicitly if you need deterministic endpoint selection.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-api-gateway/\n- Python client overview: https://docs.cloud.google.com/python/docs/reference/apigateway/latest\n- Python client reference: https://docs.cloud.google.com/python/docs/reference/apigateway/latest/google.cloud.apigateway_v1.services.api_gateway_service.ApiGatewayServiceClient\n- API type reference: https://docs.cloud.google.com/python/docs/reference/apigateway/latest/google.cloud.apigateway_v1.types.Api\n- API config type reference: https://docs.cloud.google.com/python/docs/reference/apigateway/latest/google.cloud.apigateway_v1.types.ApiConfig\n- Gateway type reference: https://docs.cloud.google.com/python/docs/reference/apigateway/latest/google.cloud.apigateway_v1.types.Gateway\n- Package changelog: https://docs.cloud.google.com/python/docs/reference/apigateway/latest/changelog\n- API Gateway development environment: https://cloud.google.com/api-gateway/docs/configure-dev-env\n- Creating an API: https://cloud.google.com/api-gateway/docs/creating-api\n- Creating an API config: https://cloud.google.com/api-gateway/docs/creating-api-config\n- Deploying an API to a gateway: https://cloud.google.com/api-gateway/docs/deploying-api\n- API Gateway deployment model: https://cloud.google.com/api-gateway/docs/deployment-model\n- Securing backend services: https://cloud.google.com/api-gateway/docs/securing-backend-services\n- API Gateway release notes: https://cloud.google.com/api-gateway/docs/release-notes\n"
  },
  {
    "path": "content/google/docs/api-python-client/python/DOC.md",
    "content": "---\nname: api-python-client\ndescription: \"Google API Python client for discovery-based access to Google APIs with API key, OAuth 2.0, and service account authentication\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.192.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-api,googleapiclient,discovery,oauth,service-account,rest\"\n---\n\n# Google API Python Client\n\n## Golden Rule\n\nUse `google-api-python-client` when you need the generic discovery-based client for Google APIs such as Drive, Sheets, Calendar, Gmail, YouTube, or Books. Install `google-api-python-client`, import `googleapiclient`, and pair it with the modern `google-auth` stack rather than older `oauth2client` examples.\n\nThis library is complete and in maintenance mode. Expect incremental updates and new API discovery documents, not a radically changing client model. For many Google Cloud products, prefer a service-specific client library when Google publishes one.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-api-python-client==2.192.0\"\n```\n\nFor current auth flows, install the companion auth packages used by the maintainers:\n\n```bash\npython -m pip install \\\n  \"google-auth>=2\" \\\n  \"google-auth-httplib2>=0.2.0\" \\\n  \"google-auth-oauthlib>=1.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add google-api-python-client google-auth google-auth-httplib2 google-auth-oauthlib\npoetry add google-api-python-client google-auth google-auth-httplib2 google-auth-oauthlib\n```\n\n## Authentication Strategy\n\nChoose auth based on the API and the data you need:\n\n- `developerKey=` for APIs that explicitly allow API-key access\n- OAuth 2.0 user credentials for Drive, Gmail, Calendar, YouTube, and other user-scoped data\n- Service account credentials for server-to-server access where the target API supports them\n\nDo not assume every Google API supports every auth mode. Service-specific docs still decide what is allowed.\n\nEnvironment variables commonly used with this package:\n\n```bash\nexport GOOGLE_API_KEY=\"...\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n## Initialize A Service\n\nThe main entry point is `googleapiclient.discovery.build()`:\n\n```python\nfrom googleapiclient.discovery import build\n\nservice = build(\n    \"drive\",\n    \"v3\",\n    credentials=credentials,\n)\n```\n\nKey points:\n\n- The first argument is the discovery API name, such as `\"drive\"` or `\"sheets\"`.\n- The second argument is the API version, such as `\"v3\"` or `\"v4\"`.\n- Calls are synchronous and usually end with `.execute()`.\n- If you use a private API or a custom discovery document URL, pass `static_discovery=False`.\n\n## Core Usage\n\n### API key example\n\nUse an API key only when the target API supports it. The Books API is a simple example:\n\n```python\nimport os\n\nfrom googleapiclient.discovery import build\nfrom googleapiclient.errors import HttpError\n\nservice = build(\"books\", \"v1\", developerKey=os.environ[\"GOOGLE_API_KEY\"])\n\ntry:\n    response = service.volumes().list(q=\"python\", maxResults=5).execute()\n    for item in response.get(\"items\", []):\n        volume = item.get(\"volumeInfo\", {})\n        print(volume.get(\"title\"))\nexcept HttpError as err:\n    print(err.status_code, err.error_details)\nfinally:\n    service.close()\n```\n\n### OAuth installed-app example\n\nUse OAuth for user data. The current maintainer docs recommend the `google-auth-oauthlib` flow:\n\n```python\nfrom google_auth_oauthlib.flow import InstalledAppFlow\nfrom googleapiclient.discovery import build\n\nSCOPES = [\"https://www.googleapis.com/auth/drive.metadata.readonly\"]\n\nflow = InstalledAppFlow.from_client_secrets_file(\n    \"client_secret.json\",\n    SCOPES,\n)\ncredentials = flow.run_local_server(port=0)\n\nservice = build(\"drive\", \"v3\", credentials=credentials)\n\ntry:\n    response = service.files().list(\n        pageSize=10,\n        fields=\"files(id,name,mimeType)\",\n    ).execute()\n    for file in response.get(\"files\", []):\n        print(file[\"id\"], file[\"name\"], file[\"mimeType\"])\nfinally:\n    service.close()\n```\n\n### Service account example\n\nUse service accounts for server-side access where the API supports them:\n\n```python\nfrom google.oauth2 import service_account\nfrom googleapiclient.discovery import build\n\nSCOPES = [\"https://www.googleapis.com/auth/calendar.readonly\"]\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\",\n    scopes=SCOPES,\n)\n\nservice = build(\"calendar\", \"v3\", credentials=credentials)\n\ntry:\n    response = service.calendarList().list().execute()\n    for item in response.get(\"items\", []):\n        print(item[\"id\"], item.get(\"summary\"))\nfinally:\n    service.close()\n```\n\nIf you need Google Workspace domain-wide delegation, call `credentials.with_subject(\"user@example.com\")` after loading the service account.\n\n### Read data from an API\n\nMost requests follow the same pattern:\n\n```python\nservice = build(\"sheets\", \"v4\", credentials=credentials)\n\ntry:\n    result = service.spreadsheets().values().get(\n        spreadsheetId=spreadsheet_id,\n        range=\"Sheet1!A1:C10\",\n    ).execute()\n    rows = result.get(\"values\", [])\nfinally:\n    service.close()\n```\n\n### Pagination\n\nMany list operations are paginated. Use the resource helper's `list_next()` method:\n\n```python\nfiles = []\nrequest = service.files().list(\n    pageSize=100,\n    fields=\"nextPageToken, files(id,name)\",\n)\n\nwhile request is not None:\n    response = request.execute()\n    files.extend(response.get(\"files\", []))\n    request = service.files().list_next(request, response)\n```\n\n### Resumable uploads\n\nUse `MediaFileUpload` with `resumable=True` for larger uploads:\n\n```python\nfrom googleapiclient.http import MediaFileUpload\n\nmedia = MediaFileUpload(\n    \"report.pdf\",\n    mimetype=\"application/pdf\",\n    resumable=True,\n)\n\nrequest = service.files().create(\n    body={\"name\": \"report.pdf\"},\n    media_body=media,\n    fields=\"id,name\",\n)\n\nresponse = None\nwhile response is None:\n    status, response = request.next_chunk()\n    if status is not None:\n        print(f\"Uploaded {int(status.progress() * 100)}%\")\n\nprint(response[\"id\"], response[\"name\"])\n```\n\n### Error handling\n\nGoogle API request failures raise `HttpError`:\n\n```python\nfrom googleapiclient.errors import HttpError\n\ntry:\n    response = service.files().list(pageSize=10).execute()\nexcept HttpError as err:\n    print(err.status_code)\n    print(err.error_details)\n```\n\n## Configuration Notes\n\n- `developerKey=` is for API key auth. `credentials=` is for OAuth or service-account auth.\n- Scope mismatches often show up as `403` errors. Verify the exact scopes required by the target API.\n- Discovery API name and version are unrelated to the package version. You still need values like `\"drive\"` and `\"v3\"`.\n- Static discovery artifacts are bundled with current `2.x` releases. When you build against a custom discovery URL or private API, disable static discovery explicitly.\n- `cache_discovery` is a legacy discovery-cache setting. Do not rely on older examples that expect file-cache behavior from the `oauth2client` era.\n\n## Common Pitfalls\n\n- The package name and import name differ: install `google-api-python-client`, import `googleapiclient`.\n- `oauth2client` is deprecated. Start new code with `google-auth`, `google-auth-httplib2`, and `google-auth-oauthlib`.\n- `httplib2.Http()` instances are not thread-safe. Give each thread its own HTTP instance if you customize transport.\n- Not every API supports API keys, and not every API supports service accounts. Check the product-specific auth rules before choosing a credential type.\n- Service accounts do not automatically see a user's Drive, Gmail, or Calendar data. You usually need explicit sharing or domain-wide delegation.\n- For many Google Cloud services, the generic discovery client is not the preferred library. If a service-specific client exists, use that unless you specifically need the discovery-based REST surface.\n\n## Version-Sensitive Notes For 2.192.0\n\n- PyPI lists `2.192.0` as the latest release, published on March 5, 2026.\n- The maintainer README states that this library is complete and in maintenance mode, so expect stability more than major new client abstractions.\n- Current maintainer guidance uses the `google-auth` family for credentials. Older `oauth2client`-era snippets still exist in historical blog posts and some generated docs, but they should not be your starting point for new code.\n\n## Official Sources\n\n- Docs root: https://googleapis.github.io/google-api-python-client/docs/\n- Getting started: https://googleapis.github.io/google-api-python-client/docs/start.html\n- OAuth guide: https://googleapis.github.io/google-api-python-client/docs/oauth.html\n- PyPI package: https://pypi.org/project/google-api-python-client/\n- Maintainer README: https://github.com/googleapis/google-api-python-client\n"
  },
  {
    "path": "content/google/docs/appengine-admin/python/DOC.md",
    "content": "---\nname: appengine-admin\ndescription: \"Google Cloud App Engine Admin Python client for managing applications, services, versions, traffic splits, and deployments\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,app-engine,appengine,google-cloud,deployment,traffic-splitting,python\"\n---\n\n# Google Cloud App Engine Admin Python Client\n\n## What This Package Is For\n\n`google-cloud-appengine-admin` is the generated control-plane client for App Engine Admin API operations in Python.\n\nUse it when your code needs to:\n\n- inspect the App Engine application attached to a project\n- list services and versions\n- deploy a new version from a Cloud Storage artifact\n- change service traffic splitting\n- manage other admin resources exposed by the App Engine Admin API\n\nThis package manages App Engine resources. It does not replace the runtime behavior of the app you deploy.\n\nThe main import surface is:\n\n```python\nfrom google.cloud import appengine_admin_v1\n```\n\n## Install\n\nPin the version you want to reason about:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-appengine-admin==1.16.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-appengine-admin==1.16.0\"\npoetry add \"google-cloud-appengine-admin==1.16.0\"\n```\n\n## Authentication And Setup\n\nUse Google Cloud Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account credentials when you need them explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nApp Engine resource names are project-scoped. The patterns you will use most often are:\n\n- application: `apps/{project_id}`\n- service: `apps/{project_id}/services/{service_id}`\n- version parent: `apps/{project_id}/services/{service_id}`\n- version: `apps/{project_id}/services/{service_id}/versions/{version_id}`\n\n## Initialize Clients\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\n\napplications_client = appengine_admin_v1.ApplicationsClient()\nservices_client = appengine_admin_v1.ServicesClient()\nversions_client = appengine_admin_v1.VersionsClient()\n```\n\nCreate the App Engine application once if the project does not already have one:\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napplications_client = appengine_admin_v1.ApplicationsClient()\n\noperation = applications_client.create_application(\n    request=appengine_admin_v1.CreateApplicationRequest(\n        application=appengine_admin_v1.Application(\n            id=project_id,\n            location_id=\"us-central\",\n        )\n    )\n)\n\napplication = operation.result()\nprint(application.name)\n```\n\nImportant:\n\n- `location_id` is the App Engine location for the application.\n- The App Engine Admin REST docs state that the location choice cannot be changed later.\n\n## Inspect The Current Application\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\n\napplications_client = appengine_admin_v1.ApplicationsClient()\napplication = applications_client.get_application(name=app_name)\n\nprint(application.name)\nprint(application.location_id)\nprint(application.default_hostname)\nprint(application.serving_status)\n```\n\n`default_hostname` is useful when you need the project's default `*.appspot.com` hostname.\n\n## List Services And Versions\n\nList services:\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\n\nservices_client = appengine_admin_v1.ServicesClient()\n\nfor service in services_client.list_services(parent=app_name):\n    print(service.name)\n    if service.split.allocations:\n        print(dict(service.split.allocations))\n```\n\nList versions for a service:\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\nservice_name = f\"{app_name}/services/default\"\nversions_client = appengine_admin_v1.VersionsClient()\n\nfor version in versions_client.list_versions(parent=service_name):\n    print(version.name, version.id, version.serving_status)\n```\n\nFetch one version:\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\nversion_name = f\"{app_name}/services/default/versions/v20260313\"\nversions_client = appengine_admin_v1.VersionsClient()\n\nversion = versions_client.get_version(name=version_name)\nprint(version.name)\nprint(version.serving_status)\n```\n\n## Deploy A Version From Cloud Storage\n\n`create_version()` is a long-running operation. Wait for `.result()` before assuming the version is ready.\n\nThe App Engine types expose `Deployment.zip.source_url`, and the REST docs describe that source as a Cloud Storage URL for a zip file.\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\nservice_name = f\"{app_name}/services/default\"\nversions_client = appengine_admin_v1.VersionsClient()\n\noperation = versions_client.create_version(\n    request=appengine_admin_v1.CreateVersionRequest(\n        parent=service_name,\n        version=appengine_admin_v1.Version(\n            id=\"v20260313\",\n            deployment=appengine_admin_v1.Deployment(\n                zip=appengine_admin_v1.ZipInfo(\n                    source_url=\"https://storage.googleapis.com/my-app-deploys/app-v20260313.zip\"\n                )\n            ),\n        ),\n    )\n)\n\ncreated = operation.result()\nprint(created.name)\n```\n\nUse this pattern when your deployment artifact is already staged in Cloud Storage and you want Python code to drive the admin API directly.\n\n## Split Traffic Between Versions\n\nUpdating a service is also a long-running operation. Patch only the `split` field so the request stays narrow and predictable.\n\n```python\nimport os\n\nfrom google.cloud import appengine_admin_v1\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\napp_name = f\"apps/{project_id}\"\nservice_name = f\"{app_name}/services/default\"\nservices_client = appengine_admin_v1.ServicesClient()\n\noperation = services_client.update_service(\n    request=appengine_admin_v1.UpdateServiceRequest(\n        name=service_name,\n        service=appengine_admin_v1.Service(\n            name=service_name,\n            split=appengine_admin_v1.TrafficSplit(\n                shard_by=appengine_admin_v1.TrafficSplit.ShardBy.IP,\n                allocations={\n                    \"v20260301\": 0.9,\n                    \"v20260313\": 0.1,\n                },\n            ),\n        ),\n        update_mask=field_mask_pb2.FieldMask(paths=[\"split\"]),\n        migrate_traffic=False,\n    )\n)\n\nupdated = operation.result()\nprint(dict(updated.split.allocations))\n```\n\nPractical guidance:\n\n- `allocations` is a mapping of version id to traffic fraction.\n- `shard_by` controls how requests are split. The generated types expose values such as `IP`.\n- If you use `migrate_traffic=True`, treat that as a deliberate deployment action and wait for the operation to finish.\n\n## Common Pitfalls\n\n- This is an admin client, not a local deployment tool. It manages App Engine resources after you authenticate and provide the right resource names.\n- The package documentation is hosted under `latest` generated reference pages, while your project may be pinned to `1.16.0`. Keep your lockfile authoritative when debugging behavior differences.\n- Create and update calls often return long-running operations. Call `.result()` before reading follow-up state.\n- Application, service, and version names are full resource names, not bare ids. Build strings like `apps/{project}/services/{service}` explicitly.\n- The application location is a one-time choice. Do not automate `create_application()` casually in shared projects.\n- `create_version()` expects a deployment definition. The verified source shape in the upstream types is a `Deployment` with fields such as `zip.source_url`; do not assume the client uploads a local directory for you.\n\n## Version-Sensitive Notes\n\n- This guide is pinned to PyPI package version `1.16.0`.\n- The official Python reference for this library is published as `latest` rather than a version-pinned `1.16.0` tree, so new generated methods or fields can appear in the hosted docs before your application upgrades.\n\n## Official Sources\n\n- PyPI: `https://pypi.org/project/google-cloud-appengine-admin/`\n- Package docs root: `https://docs.cloud.google.com/python/docs/reference/appengine/latest`\n- `ApplicationsClient`: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.services.applications.ApplicationsClient`\n- `ServicesClient`: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.services.services.ServicesClient`\n- `VersionsClient`: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.services.versions.VersionsClient`\n- `Application` type: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.types.Application`\n- `Version` type: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.types.Version`\n- `Deployment` type: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.types.Deployment`\n- `ZipInfo` type: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.types.ZipInfo`\n- `TrafficSplit` type: `https://docs.cloud.google.com/python/docs/reference/appengine/latest/google.cloud.appengine_admin_v1.types.TrafficSplit`\n- App Engine Admin REST `apps.create`: `https://cloud.google.com/appengine/docs/admin-api/reference/rest/v1/apps`\n- App Engine Admin REST `apps.services.patch`: `https://cloud.google.com/appengine/docs/admin-api/reference/rest/v1/apps.services`\n- ADC setup: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/appengine-logging/python/DOC.md",
    "content": "---\nname: appengine-logging\ndescription: \"google-cloud-appengine-logging package guide for Python code that models App Engine request-log messages\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,appengine,logging,cloud-logging,protobuf,python\"\n---\n\n# google-cloud-appengine-logging Python Package Guide\n\n## What It Is\n\n`google-cloud-appengine-logging` is the Python package for the App Engine logging protobuf types under `google.appengine.logging.v1`.\n\nIn practice, this package is useful when your code needs to model or inspect App Engine request-log data as typed Python messages:\n\n- `RequestLog`\n- `LogLine`\n- `SourceLocation`\n- `SourceReference`\n\nThis is not the package you use to write normal application logs from an App Engine service. Google documents that App Engine already emits request logs automatically, and for app logs it recommends Cloud Logging integration or structured `stdout` / `stderr`.\n\nThis guide covers `1.8.0`.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-appengine-logging==1.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-appengine-logging==1.8.0\"\npoetry add \"google-cloud-appengine-logging==1.8.0\"\n```\n\nPyPI lists support for Python 3.7 and newer.\n\n## Authentication And Environment\n\nYou do not need credentials or Google Cloud environment variables just to construct or inspect these protobuf messages.\n\nIf you are reading real App Engine logs from Google Cloud, Google says to use one of these paths:\n\n- call the Cloud Logging API through a client library\n- call the Cloud Logging REST API directly\n- export logs through a sink such as Pub/Sub\n\nFor those flows, use normal Google Cloud auth:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nOr with a service account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\n## Import The Message Types\n\n```python\nfrom google.cloud.appengine_logging_v1.types import (\n    LogLine,\n    RequestLog,\n    SourceLocation,\n    SourceReference,\n)\n```\n\nThe published Python reference for this package currently surfaces these generated message types rather than a higher-level logging client.\n\n## Build A `RequestLog`\n\nUse `RequestLog` when you need a typed representation of one App Engine request and its child app log lines.\n\n```python\nfrom datetime import datetime, timezone\n\nfrom google.cloud.appengine_logging_v1.types import (\n    LogLine,\n    RequestLog,\n    SourceLocation,\n    SourceReference,\n)\nfrom google.protobuf.duration_pb2 import Duration\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\nstarted = Timestamp()\nstarted.FromDatetime(datetime.now(timezone.utc))\n\nlatency = Duration(seconds=0, nanos=125_000_000)\n\nrequest_log = RequestLog(\n    app_id=\"my-project-id\",\n    module_id=\"default\",\n    version_id=\"20260313t120000\",\n    request_id=\"67d2d4b100ff7e0b9b0d6b1d0001735a\",\n    method=\"GET\",\n    resource=\"/healthz\",\n    http_version=\"HTTP/1.1\",\n    status=200,\n    host=\"my-project.uc.r.appspot.com\",\n    trace_id=\"105445aa7843bc8bf206b120001000\",\n    trace_sampled=True,\n    start_time=started,\n    latency=latency,\n    line=[\n        LogLine(\n            log_message=\"health check passed\",\n            source_location=SourceLocation(\n                file=\"main.py\",\n                line=17,\n                function_name=\"healthz\",\n            ),\n        )\n    ],\n    source_reference=[\n        SourceReference(\n            repository=\"https://github.com/example/my-app\",\n            revision_id=\"abc123def456\",\n        )\n    ],\n)\n\nprint(request_log.status)\nprint(request_log.line[0].log_message)\n```\n\nFields worth knowing from the official schema:\n\n- `RequestLog` includes request metadata such as `method`, `resource`, `status`, `latency`, `host`, `trace_id`, and repeated `line`\n- `LogLine` includes `time`, `severity`, `log_message`, and `source_location`\n- `SourceLocation` includes `file`, `line`, and `function_name`\n- `SourceReference` includes `repository` and `revision_id`\n\n## Read App Log Lines From A Request\n\nEach `RequestLog` can contain child application log lines in `line`.\n\n```python\nfrom google.cloud.appengine_logging_v1.types import RequestLog\n\n\ndef summarize_request(log: RequestLog) -> dict[str, object]:\n    return {\n        \"request_id\": log.request_id,\n        \"path\": log.resource,\n        \"status\": log.status,\n        \"trace_id\": log.trace_id,\n        \"messages\": [entry.log_message for entry in log.line],\n    }\n```\n\nIf you need source-aware output, use `source_location` when it is present:\n\n```python\nfor entry in request_log.line:\n    location = entry.source_location\n    print(f\"{location.file}:{location.line} {entry.log_message}\")\n```\n\n## What To Use For Real App Engine Logging\n\nUse this package for typed App Engine request-log data.\n\nDo not use it as your primary logging integration for an App Engine app. Google’s App Engine logging docs say:\n\n- request logs are created automatically\n- app logs should be written through Cloud Logging integration or structured `stdout` / `stderr`\n- programmatic log reads should go through Cloud Logging client libraries, REST, or an export sink\n\nFor most App Engine services, that means:\n\n- write logs with `google-cloud-logging` or structured `stdout`\n- read live logs with Cloud Logging\n- use `google-cloud-appengine-logging` only if you specifically need the App Engine request-log message schema in Python\n\n## Common Pitfalls\n\n- Package name and import path differ. Install `google-cloud-appengine-logging`, import from `google.cloud.appengine_logging_v1.types`.\n- Do not add this package expecting it to replace `google-cloud-logging`. They solve different problems.\n- Do not try to write App Engine request logs yourself. App Engine creates them automatically.\n- If you need to fetch real logs from Google Cloud, this package is only one part of the workflow. You still need a log-reading path such as Cloud Logging or a sink export.\n- The Google Python reference pages for this package lag the current PyPI release in some places. Use PyPI for exact version pinning and the protobuf reference pages for field names.\n\n## Official Links\n\n- PyPI: https://pypi.org/project/google-cloud-appengine-logging/\n- Maintainer package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-appengine-logging\n- Python reference root: https://cloud.google.com/python/docs/reference/appenginelogging/latest\n- Python `types` package reference: https://cloud.google.com/python/docs/reference/appenginelogging/latest/google.cloud.appengine_logging_v1.types\n- App Engine logging guide: https://cloud.google.com/appengine/docs/standard/writing-application-logs\n- Cloud Logging RPC schema for `google.appengine.logging.v1`: https://docs.cloud.google.com/logging/docs/reference/v2/rpc/google.appengine.logging.v1\n- REST `RequestLog` schema: https://docs.cloud.google.com/logging/docs/reference/v1beta3/rest/v1beta3/RequestLog\n"
  },
  {
    "path": "content/google/docs/artifact-registry/python/DOC.md",
    "content": "---\nname: artifact-registry\ndescription: \"Google Cloud Artifact Registry Python client for repository management, package metadata, tags, and version operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.20.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,gcp,artifact-registry,packages,python,registry,google-cloud\"\n---\n\n# Google Cloud Artifact Registry Python Client\n\n## Golden Rule\n\nUse `google-cloud-artifact-registry` when you need to manage Artifact Registry resources from Python code. Import it as `from google.cloud import artifactregistry_v1`, authenticate with Application Default Credentials (ADC), and build resource names with the client helper methods instead of string-concatenating them by hand.\n\nThis package is the Artifact Registry control-plane client. If your job is configuring `pip`, `twine`, or keyring-based auth for private Python package publishing and installs, use the Artifact Registry Python package product docs for that workflow; this SDK is for repository, package, version, tag, rule, file, and attachment APIs.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-artifact-registry==1.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-artifact-registry==1.20.0\"\npoetry add \"google-cloud-artifact-registry==1.20.0\"\n```\n\n## Authentication And Setup\n\nBefore you create a client:\n\n1. Enable the Artifact Registry API in the target Google Cloud project.\n2. Use an identity with the Artifact Registry IAM permissions your operation needs.\n3. Prefer ADC over embedding service-account keys in code.\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nBasic client setup:\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\n```\n\nIf your environment does not make the project obvious, keep the project ID explicit in resource names:\n\n```python\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\n```\n\nService-account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n### Endpoint And Client Options\n\nThe client constructor accepts `credentials`, `transport`, and `client_options`. Use `client_options` when you need a specific API endpoint:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient(\n    client_options=ClientOptions(api_endpoint=\"artifactregistry.googleapis.com\")\n)\n```\n\nThe package also supports structured logging configuration through the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable, for example:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.artifactregistry_v1\n```\n\n## Core Usage\n\n### Build Resource Names With Helpers\n\nArtifact Registry methods expect fully qualified resource names. Use the helper methods exposed on the client:\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\n\nrepository_name = client.repository_path(\n    project=\"my-project\",\n    location=\"us-central1\",\n    repository=\"python-internal\",\n)\n\npackage_name = client.package_path(\n    project=\"my-project\",\n    location=\"us-central1\",\n    repository=\"python-internal\",\n    package=\"my-package\",\n)\n\npython_package_name = client.python_package_path(\n    project=\"my-project\",\n    location=\"us-central1\",\n    repository=\"python-internal\",\n    python_package=\"my-package\",\n)\n```\n\nThese helpers prevent common mistakes around location-scoped names such as `projects/{project}/locations/{location}/repositories/{repository}`.\n\n### List Repositories In A Location\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nfor repo in client.list_repositories(parent=parent):\n    print(repo.name, repo.format_, repo.mode, repo.registry_uri)\n```\n\nThe `Repository` type exposes repository `format_` and `mode`, including standard, remote, and virtual repository modes.\n\n### Create A Standard Python Repository\n\n`create_repository` is a long-running operation, so wait for the result:\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nrepository = artifactregistry_v1.Repository(\n    format_=artifactregistry_v1.Repository.Format.PYTHON,\n    mode=artifactregistry_v1.Repository.Mode.STANDARD_REPOSITORY,\n    description=\"Internal Python packages\",\n)\n\noperation = client.create_repository(\n    parent=parent,\n    repository_id=\"python-internal\",\n    repository=repository,\n)\n\ncreated = operation.result()\nprint(created.name)\nprint(created.registry_uri)\n```\n\nUse the returned `registry_uri` when wiring clients or publishing tools to the repository endpoint.\n\n### List Packages And Python Package Metadata\n\nUse `list_packages()` for general package inventory and `list_python_packages()` when you want Python-specific package resources:\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\nrepository = client.repository_path(\"my-project\", \"us-central1\", \"python-internal\")\n\nfor pkg in client.list_packages(parent=repository):\n    print(pkg.name)\n\nfor py_pkg in client.list_python_packages(parent=repository):\n    print(py_pkg.name)\n```\n\n### Inspect Versions And Tags\n\nVersions and tags use package-scoped parent resources:\n\n```python\nfrom google.cloud import artifactregistry_v1\n\nclient = artifactregistry_v1.ArtifactRegistryClient()\npackage_name = client.package_path(\n    project=\"my-project\",\n    location=\"us-central1\",\n    repository=\"python-internal\",\n    package=\"my-package\",\n)\n\nfor version in client.list_versions(parent=package_name):\n    print(version.name)\n\nfor tag in client.list_tags(parent=package_name):\n    print(tag.name, tag.version)\n```\n\nThis is the right surface when you need metadata, retention tooling, or promotion logic around stored artifacts.\n\n## Common Pitfalls\n\n- Do not confuse this SDK with the Artifact Registry `pip` and `twine` setup guides. Publishing or installing Python packages from private repositories usually needs product-doc auth steps in addition to, or instead of, this client library.\n- Resource names are always fully qualified and location-scoped. Prefer `repository_path()`, `package_path()`, `python_package_path()`, `tag_path()`, and `version_path()` helpers.\n- `create_repository`, `update_repository`, and similar mutating methods can return long-running operations. Call `.result()` before assuming the change is usable.\n- Artifact Registry is regional or multi-regional. A wrong `location` in the resource name is a common reason for confusing `NotFound` and permission errors.\n- IAM matters at both the project and repository levels. Failing auth often means the identity lacks Artifact Registry permissions, not that the SDK call shape is wrong.\n- If you override endpoints or transports, keep them aligned with the resource location and the rest of your Google Cloud environment.\n\n## Version-Sensitive Notes\n\n- PyPI lists `1.20.0` as the current package version covered here.\n- The main client reference resolves on the `latest` docs track and showed `ArtifactRegistryClient (1.20.0)` when validated on March 12, 2026.\n- Some adjacent generated reference pages under the same docs root were still indexed at `1.19.0` on March 12, 2026. If a type page looks behind the client page or PyPI, trust the package version on PyPI and re-check the docs version selector before copying details.\n- PyPI lists support for Python `>=3.7`; if your project is on an older interpreter, upgrade Python before trying to pin this release line.\n\n## Official Sources\n\n- Python client reference root: `https://docs.cloud.google.com/python/docs/reference/artifactregistry/latest`\n- `ArtifactRegistryClient` reference: `https://docs.cloud.google.com/python/docs/reference/artifactregistry/latest/google.cloud.artifactregistry_v1.services.artifact_registry.ArtifactRegistryClient`\n- Client changelog: `https://docs.cloud.google.com/python/docs/reference/artifactregistry/latest/changelog`\n- Artifact Registry Python package product docs: `https://docs.cloud.google.com/artifact-registry/docs/python`\n- PyPI package page: `https://pypi.org/project/google-cloud-artifact-registry/`\n"
  },
  {
    "path": "content/google/docs/asset/javascript/DOC.md",
    "content": "---\nname: asset\ndescription: \"@google-cloud/asset JavaScript package guide with ADC setup, asset inventory search/list patterns, and export workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,cloud-asset-inventory,javascript,nodejs,iam,inventory,search,export\"\n---\n\n# `@google-cloud/asset` JavaScript Package Guide\n\nUse `@google-cloud/asset` when your Node.js code needs to inventory Google Cloud resources, search resources across a project, folder, or organization, or export Cloud Asset Inventory snapshots for reporting.\n\n## Golden Rule\n\n- Import the generated client from the `v1` namespace.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Pass full resource names like `projects/...`, `folders/...`, and `organizations/...`.\n- Use `searchAllResourcesAsync()` for targeted lookups and `listAssetsAsync()` for inventory-style reads.\n- Use `exportAssets()` for large or scheduled snapshots instead of trying to dump broad inventories client-side.\n\nThis guide covers `6.3.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/asset@6.3.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the Cloud Asset API in the project your application uses to call the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable cloudasset.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nBefore calling the API, make sure:\n\n1. The Cloud Asset API is enabled.\n2. The caller has access to the project, folder, or organization being queried.\n3. The scope string is a full resource name, not a bare ID.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/asset');\n\nconst client = new v1.AssetServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/asset';\n\nconst client = new v1.AssetServiceClient();\n```\n\nWith an explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/asset');\n\nconst client = new v1.AssetServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Resource Scopes You Reuse Constantly\n\nUse the fully qualified form expected by the API:\n\n- Project scope: `projects/my-project-id`\n- Folder scope: `folders/1234567890`\n- Organization scope: `organizations/1234567890`\n\nUse `parent` for snapshot and export methods such as `listAssets()` and `exportAssets()`. Use `scope` for search methods such as `searchAllResources()`.\n\n## Core Workflows\n\n### List Assets For A Snapshot\n\nUse `listAssetsAsync()` when you need a structured inventory for a bounded scope.\n\n```javascript\nconst {v1} = require('@google-cloud/asset');\n\nconst client = new v1.AssetServiceClient();\n\nasync function listBucketAssets() {\n  const request = {\n    parent: 'projects/my-project-id',\n    assetTypes: ['storage.googleapis.com/Bucket'],\n    contentType: 'RESOURCE',\n    pageSize: 100,\n  };\n\n  for await (const asset of client.listAssetsAsync(request)) {\n    console.log({\n      name: asset.name,\n      assetType: asset.assetType,\n    });\n  }\n}\n\nlistBucketAssets().catch(console.error);\n```\n\nUse `readTime` when you need a point-in-time snapshot instead of the latest view.\n\n### Search Resources Across A Scope\n\nUse `searchAllResourcesAsync()` when you know roughly what you want and do not want to walk the entire inventory.\n\n```javascript\nconst {v1} = require('@google-cloud/asset');\n\nconst client = new v1.AssetServiceClient();\n\nasync function searchComputeInstances() {\n  const request = {\n    scope: 'projects/my-project-id',\n    query: 'displayName:prod',\n    assetTypes: ['compute.googleapis.com/Instance'],\n    pageSize: 50,\n  };\n\n  for await (const resource of client.searchAllResourcesAsync(request)) {\n    console.log({\n      name: resource.name,\n      assetType: resource.assetType,\n    });\n  }\n}\n\nsearchComputeInstances().catch(console.error);\n```\n\nUse `searchAllIamPolicies()` when the task is policy-oriented rather than resource-oriented.\n\n### Export Assets To Cloud Storage\n\nUse `exportAssets()` for scheduled reporting or broad inventory snapshots. It is a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/asset');\n\nconst client = new v1.AssetServiceClient();\n\nasync function exportBucketAssets() {\n  const request = {\n    parent: 'projects/my-project-id',\n    assetTypes: ['storage.googleapis.com/Bucket'],\n    contentType: 'RESOURCE',\n    outputConfig: {\n      gcsDestination: {\n        uri: 'gs://my-bucket/exports/asset-snapshot.json',\n      },\n    },\n  };\n\n  const [operation] = await client.exportAssets(request);\n  const [response] = await operation.promise();\n\n  console.log(response.readTime);\n}\n\nexportBucketAssets().catch(console.error);\n```\n\nUse a BigQuery destination when downstream code will query asset snapshots with SQL instead of reading raw export files.\n\n## Version And Namespace Notes\n\nThis package exposes versioned namespaces. For normal application code:\n\n- Prefer `v1` unless you are maintaining code that already depends on a beta namespace.\n- Keep request field names in JavaScript `camelCase`, even when the product docs describe proto fields with snake case.\n\n## Important Pitfalls\n\n- Passing a bare project ID where the API expects `projects/PROJECT_ID`.\n- Using `parent` and `scope` interchangeably. Snapshot/export methods use `parent`; search methods use `scope`.\n- Expecting organization-wide searches to behave like project-scoped reads. Broader scopes need broader IAM and are slower.\n- Treating empty results as a request-shape problem before checking API enablement, IAM, and scope.\n- Assuming an export finished before awaiting `operation.promise()`.\n- Using `listAssets()` for large-scale dumps that are better handled by `exportAssets()`.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/asset/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/asset`\n- Cloud Asset Inventory docs: `https://cloud.google.com/asset-inventory/docs`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/asset/python/DOC.md",
    "content": "---\nname: asset\ndescription: \"google-cloud-asset package guide for Python with ADC setup, asset inventory search/list patterns, and export workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,gcp,cloud-asset-inventory,python,iam,inventory,search,export\"\n---\n\n# google-cloud-asset Python Package Guide\n\n## What It Is\n\n`google-cloud-asset` is the official Python client for Google Cloud Asset Inventory.\n\nUse it when code needs to:\n\n- inventory resources under a project, folder, or organization\n- search resources or IAM policies across a scope\n- export snapshots to Cloud Storage or BigQuery\n- analyze IAM access relationships\n\nFor Python code, import from `google.cloud.asset_v1`.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-asset==4.2.0\"\n```\n\nIf you manage dependencies with `uv` or Poetry, pin the same version there.\n\n## Authentication And Setup\n\nThe client library uses Application Default Credentials by default. For local development, the standard flow is:\n\n```bash\ngcloud auth application-default login\n```\n\nBefore calling the API, make sure:\n\n- Cloud Asset API is enabled in the target project\n- the caller has access to the project, folder, or organization being queried\n- the scope strings you pass use full resource names such as `projects/my-project`, `folders/1234567890`, or `organizations/1234567890`\n\n## Initialize A Client\n\n```python\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceClient()\n```\n\nIf you need a custom endpoint or mTLS behavior, pass `client_options`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceClient(\n    client_options=ClientOptions(api_endpoint=\"cloudasset.googleapis.com\"),\n)\n```\n\nThe generated client also accepts explicit `credentials=` and `transport=` arguments when ADC is not the right fit.\n\n## Core Usage\n\n### List Assets For An Inventory Snapshot\n\nUse `list_assets` when you want a structured inventory for a project, folder, or organization.\n\n```python\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceClient()\n\nrequest = asset_v1.ListAssetsRequest(\n    parent=\"projects/my-project-id\",\n    asset_types=[\"storage.googleapis.com/Bucket\"],\n    content_type=asset_v1.ContentType.RESOURCE,\n    page_size=100,\n)\n\npager = client.list_assets(request=request)\n\nfor asset in pager:\n    print(asset.name)\n    print(asset.asset_type)\n```\n\nUse `read_time` when you need a point-in-time snapshot instead of the latest view.\n\n### Search Resources Across A Scope\n\nUse `search_all_resources` when you know roughly what you want and need filtered lookup instead of a full inventory walk.\n\n```python\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceClient()\n\nrequest = asset_v1.SearchAllResourcesRequest(\n    scope=\"projects/my-project-id\",\n    query='displayName:prod',\n    asset_types=[\"compute.googleapis.com/Instance\"],\n    page_size=50,\n)\n\npager = client.search_all_resources(request=request)\n\nfor resource in pager:\n    print(resource.name)\n    print(resource.asset_type)\n```\n\nUse `search_all_iam_policies` when the task is policy-oriented rather than resource-oriented.\n\n### Export Large Inventories\n\nUse `export_assets` for scheduled reporting or large inventories. It is a long-running operation.\n\n```python\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceClient()\n\nrequest = asset_v1.ExportAssetsRequest(\n    parent=\"projects/my-project-id\",\n    asset_types=[\"storage.googleapis.com/Bucket\"],\n    output_config={\n        \"gcs_destination\": {\n            \"uri\": \"gs://my-bucket/asset-export.json\",\n        }\n    },\n)\n\noperation = client.export_assets(request=request)\nresult = operation.result(timeout=300)\n\nprint(result.read_time)\n```\n\nUse a BigQuery destination when downstream code will query or join asset data instead of reading raw JSON snapshots.\n\n### Async Client\n\nIf the application is already async, use `AssetServiceAsyncClient` directly.\n\n```python\nfrom google.cloud import asset_v1\n\nclient = asset_v1.AssetServiceAsyncClient()\n\nasync def main() -> None:\n    request = asset_v1.SearchAllResourcesRequest(\n        scope=\"projects/my-project-id\",\n        asset_types=[\"compute.googleapis.com/Instance\"],\n    )\n    pager = client.search_all_resources(request=request)\n    async for resource in pager:\n        print(resource.name)\n```\n\n## Config And Auth Notes\n\n- Prefer ADC in local development and attached service accounts or Workload Identity in deployed environments.\n- `parent` and `scope` are not plain project IDs. They must be fully qualified resource names.\n- Keep the queried scope as narrow as possible. Organization-wide searches are slower and need broader IAM.\n- The generated GAPIC methods accept either a `request=` object or flattened fields. If you pass `request=...`, do not also pass method-specific flattened arguments.\n\n## Common Pitfalls\n\n### Empty Or Partial Results Usually Mean IAM Or Scope Problems\n\n`search_all_resources` and `list_assets` only return what the caller can see. If results look incomplete, verify:\n\n- the resource scope string\n- whether the API is enabled\n- whether the caller has the relevant Cloud Asset Inventory permissions for that scope\n\n### `list_assets` Is Not The Best Tool For Very Large Dumps\n\nThe official reference warns that `list_assets` might not meet performance requirements for large-scale exports. Use `export_assets` when you need broad snapshots.\n\n### Rolling Reference Docs Can Lag The Exact Package Version\n\nPyPI shows `4.2.0` as the package release, but the rolling Google Cloud Python reference pages visited on March 12, 2026 still surfaced `4.1.0` in page chrome. Treat the reference pages as the canonical API family docs, but verify installed-client behavior if you are debugging a version-pinned environment.\n\n### Prefer Resource Search For Targeted Queries\n\nIf you only need specific resources, `search_all_resources` is usually simpler than scanning `list_assets` and filtering client-side.\n\n## Official Source URLs\n\n- PyPI package page: `https://pypi.org/project/google-cloud-asset/4.2.0/`\n- PyPI release JSON: `https://pypi.org/pypi/google-cloud-asset/4.2.0/json`\n- Package docs URL: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-asset`\n- Google Cloud Python reference root: `https://cloud.google.com/python/docs/reference/cloudasset/latest`\n- `AssetServiceClient` reference: `https://cloud.google.com/python/docs/reference/cloudasset/latest/google.cloud.asset_v1.services.asset_service.AssetServiceClient`\n- `ListAssets` reference: `https://cloud.google.com/python/docs/reference/cloudasset/latest/google.cloud.asset_v1.services.asset_service.AssetServiceClient#google_cloud_asset_v1_services_asset_service_AssetServiceClient_list_assets`\n- `SearchAllResources` reference: `https://cloud.google.com/python/docs/reference/cloudasset/latest/google.cloud.asset_v1.services.asset_service.AssetServiceClient#google_cloud_asset_v1_services_asset_service_AssetServiceClient_search_all_resources`\n- `ExportAssets` reference: `https://cloud.google.com/python/docs/reference/cloudasset/latest/google.cloud.asset_v1.services.asset_service.AssetServiceClient#google_cloud_asset_v1_services_asset_service_AssetServiceClient_export_assets`\n- ADC guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/assured-workloads/python/DOC.md",
    "content": "---\nname: assured-workloads\ndescription: \"Google Cloud Assured Workloads Python client for workload creation, compliance operations, and violation management\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,assured-workloads,compliance,folders,violations,python\"\n---\n\n# Google Cloud Assured Workloads Python Client\n\n## Golden Rule\n\nUse `google-cloud-assured-workloads` with `from google.cloud import assuredworkloads_v1`, authenticate with Application Default Credentials (ADC), and build requests with full resource names such as `organizations/123456789012/locations/us-central1`. Prefer the GA `assuredworkloads_v1` surface unless you have a verified reason to use the beta namespace.\n\nThis client is useful only after the Assured Workloads product prerequisites already exist: an organization, an allowed Assured Workloads location, the Assured Workloads API, and the IAM roles needed for the operation you are calling.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-assured-workloads==2.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-assured-workloads==2.2.0\"\npoetry add \"google-cloud-assured-workloads==2.2.0\"\n```\n\nPyPI publishes `2.2.0` for Python `>=3.7`.\n\n## Authentication And Setup\n\nUse ADC unless you have a hard requirement to load credentials explicitly.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_ORGANIZATION=\"123456789012\"\nexport ASSURED_WORKLOADS_LOCATION=\"us-central1\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nIf you manage service enablement with `gcloud`, the Assured Workloads API service name is `assuredworkloads.googleapis.com`.\n\nPractical permission notes from the product docs:\n\n- `roles/assuredworkloads.reader` is enough for read-only workload and violation access.\n- `roles/assuredworkloads.editor` or `roles/assuredworkloads.admin` is required for changes such as restriction updates or violation acknowledgement.\n- Creating workloads also commonly requires organization-level visibility such as `roles/resourcemanager.organizationViewer`.\n\n## Initialize The Client\n\nThe generated client supports the global endpoint and regional endpoints. For location-bound workloads, prefer an endpoint that matches the workload location.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import assuredworkloads_v1\n\norganization_id = os.environ[\"GOOGLE_CLOUD_ORGANIZATION\"]\nlocation = os.getenv(\"ASSURED_WORKLOADS_LOCATION\", \"us-central1\")\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-assuredworkloads.googleapis.com\"\n    )\n)\n\nparent = f\"organizations/{organization_id}/locations/{location}\"\n```\n\nIf you want default ADC behavior with the global endpoint, `assuredworkloads_v1.AssuredWorkloadsServiceClient()` also works.\n\nExplicit credentials example:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import assuredworkloads_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient(\n    credentials=credentials,\n    client_options=ClientOptions(\n        api_endpoint=\"us-central1-assuredworkloads.googleapis.com\"\n    ),\n)\n```\n\n## Core Workflows\n\n### List workloads in a location\n\n```python\nimport os\n\nfrom google.cloud import assuredworkloads_v1\n\norganization_id = os.environ[\"GOOGLE_CLOUD_ORGANIZATION\"]\nlocation = os.getenv(\"ASSURED_WORKLOADS_LOCATION\", \"us-central1\")\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\nparent = f\"organizations/{organization_id}/locations/{location}\"\n\nfor workload in client.list_workloads(parent=parent):\n    print(workload.name)\n    print(workload.display_name)\n    print(workload.compliance_regime)\n```\n\n### Get one workload\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\n\nworkload_name = (\n    \"organizations/123456789012/locations/us-central1/workloads/WORKLOAD_ID\"\n)\n\nworkload = client.get_workload(name=workload_name)\nprint(workload.name)\nprint(workload.display_name)\nprint(workload.etag)\n```\n\n### Create a workload\n\n`create_workload()` returns a long-running operation. Wait for `result()` before assuming the folder and related resources exist.\n\n```python\nimport os\n\nfrom google.cloud import assuredworkloads_v1\n\norganization_id = os.environ[\"GOOGLE_CLOUD_ORGANIZATION\"]\nlocation = os.getenv(\"ASSURED_WORKLOADS_LOCATION\", \"us-central1\")\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\nparent = f\"organizations/{organization_id}/locations/{location}\"\n\nworkload = assuredworkloads_v1.Workload(\n    display_name=\"aw-prod-us\",\n    compliance_regime=assuredworkloads_v1.Workload.ComplianceRegime.US_REGIONAL_ACCESS,\n    billing_account=\"billingAccounts/012345-567890-ABCDEF\",\n    labels={\n        \"env\": \"prod\",\n        \"team\": \"platform\",\n    },\n)\n\noperation = client.create_workload(parent=parent, workload=workload)\ncreated = operation.result(timeout=1800)\n\nprint(created.name)\nprint(created.resources)\n```\n\nIf you need Google Cloud resources created with specific names, supply `resource_settings` on the workload:\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nworkload = assuredworkloads_v1.Workload(\n    display_name=\"aw-prod-us\",\n    compliance_regime=assuredworkloads_v1.Workload.ComplianceRegime.US_REGIONAL_ACCESS,\n    resource_settings=[\n        assuredworkloads_v1.Workload.ResourceSettings(\n            resource_type=assuredworkloads_v1.Workload.ResourceInfo.ResourceType.CONSUMER_FOLDER,\n            display_name=\"aw-prod-us-folder\",\n        ),\n        assuredworkloads_v1.Workload.ResourceSettings(\n            resource_type=assuredworkloads_v1.Workload.ResourceInfo.ResourceType.ENCRYPTION_KEYS_PROJECT,\n            resource_id=\"aw-prod-us-kms\",\n            display_name=\"aw-prod-us-kms\",\n        ),\n    ],\n)\n```\n\nFor folder resources, the API docs mark `resource_id` as output only. Set `display_name` and let the service create the folder identifier.\n\n### Update workload metadata\n\nUse an update mask so you only change the fields you intend to patch.\n\n```python\nfrom google.cloud import assuredworkloads_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\nworkload_name = (\n    \"organizations/123456789012/locations/us-central1/workloads/WORKLOAD_ID\"\n)\n\nworkload = client.get_workload(name=workload_name)\nworkload.labels[\"cost-center\"] = \"sec-001\"\n\nupdated = client.update_workload(\n    workload=workload,\n    update_mask=FieldMask(paths=[\"labels\"]),\n)\n\nprint(updated.labels)\n```\n\nRefetch the workload before updating if another system might have changed it, because the API uses `etag` for optimistic concurrency.\n\n### List and inspect violations\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\nworkload_name = (\n    \"organizations/123456789012/locations/us-central1/workloads/WORKLOAD_ID\"\n)\n\nfor violation in client.list_violations(parent=workload_name):\n    print(violation.name)\n    print(violation.state)\n```\n\nFetch one violation when you need the full remediation details:\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\n\nviolation_name = (\n    \"organizations/123456789012/locations/us-central1/\"\n    \"workloads/WORKLOAD_ID/violations/VIOLATION_ID\"\n)\n\nviolation = client.get_violation(name=violation_name)\nprint(violation.name)\nprint(violation.description)\n\nfor command in violation.remediation.instructions.gcloud.gcloud_commands:\n    print(command)\n```\n\n### Acknowledge a violation\n\nUse this only after recording the remediation or risk acceptance your process requires.\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\n\nviolation_name = (\n    \"organizations/123456789012/locations/us-central1/\"\n    \"workloads/WORKLOAD_ID/violations/VIOLATION_ID\"\n)\n\nclient.acknowledge_violation(\n    request=assuredworkloads_v1.AcknowledgeViolationRequest(\n        name=violation_name,\n        comment=\"Reviewed by platform security on 2026-03-13\",\n    )\n)\n```\n\n### Restrict allowed resources to compliant products\n\nThe Python client method is `restrict_allowed_resources()`. In product and REST docs, the operation is still described as restricting allowed services.\n\n```python\nfrom google.cloud import assuredworkloads_v1\n\nclient = assuredworkloads_v1.AssuredWorkloadsServiceClient()\nworkload_name = (\n    \"organizations/123456789012/locations/us-central1/workloads/WORKLOAD_ID\"\n)\n\nclient.restrict_allowed_resources(\n    request=assuredworkloads_v1.RestrictAllowedResourcesRequest(\n        name=workload_name,\n        restriction_type=assuredworkloads_v1.RestrictAllowedResourcesRequest.RestrictionType.ALLOW_COMPLIANT_RESOURCES,\n    )\n)\n```\n\nTo remove the restriction later, use `ALLOW_ALL_GCP_RESOURCES`.\n\n## Important Pitfalls\n\n- This is an organization-scoped product. Supplying only a project ID is not enough; most calls want organization, location, workload, or violation resource names.\n- Do not assume the global endpoint is always the right choice. The Assured Workloads docs publish regional endpoints, and the generated Python docs note that regional endpoints may be required.\n- `create_workload()` and `delete_workload()` are long-running operations. Wait for `.result()` and handle timeouts explicitly.\n- `labels` is the only field the v1 client documents as filterable in `list_workloads()`. Do not assume general-purpose search syntax.\n- `KMSSettings` is deprecated in the Workload type docs. Prefer `resource_settings` for keys, keyrings, folders, and related resources.\n- `CONSUMER_PROJECT` in `ResourceSettings` is deprecated for create requests. Use `CONSUMER_FOLDER` and other current resource types instead.\n- The package also ships `assuredworkloads_v1beta1`. Some product REST methods appear outside the GA Python v1 client surface. If you need a capability that is present in REST docs but missing from `AssuredWorkloadsServiceClient`, verify whether it is beta-only before you write wrappers around a nonexistent client method.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-assured-workloads/2.2.0/\n- Python client reference root: https://cloud.google.com/python/docs/reference/assuredworkloads/latest\n- `AssuredWorkloadsServiceClient` reference: https://cloud.google.com/python/docs/reference/assuredworkloads/latest/google.cloud.assuredworkloads_v1.services.assured_workloads_service.AssuredWorkloadsServiceClient\n- `Workload` type reference: https://cloud.google.com/python/docs/reference/assuredworkloads/latest/google.cloud.assuredworkloads_v1.types.Workload\n- `RestrictAllowedResourcesRequest` type reference: https://cloud.google.com/python/docs/reference/assuredworkloads/latest/google.cloud.assuredworkloads_v1.types.RestrictAllowedResourcesRequest\n- REST reference and regional endpoints: https://cloud.google.com/assured-workloads/docs/reference/rest\n- Assured Workloads roles and permissions: https://cloud.google.com/assured-workloads/docs/access-control\n- Assured Workloads folders and supported products guidance: https://cloud.google.com/assured-workloads/docs/create-folder\n"
  },
  {
    "path": "content/google/docs/auth/python/DOC.md",
    "content": "---\nname: auth\ndescription: \"Google authentication library for Python covering ADC, service accounts, workload identity federation, impersonation, ID tokens, and authenticated transports\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.49.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-auth,authentication,oauth2,adc,service-account,workload-identity,id-token\"\n---\n\n# Google Auth Python Library\n\n## Golden Rule\n\nUse `google-auth` for Google credential objects and authenticated transports in Python. Prefer Application Default Credentials (ADC) first, prefer short-lived credentials over private key files, and use `google-auth-oauthlib` for browser-based OAuth consent flows because `google-auth` does not perform that login flow by itself.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-auth==2.49.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-auth==2.49.0\"\npoetry add \"google-auth==2.49.0\"\n```\n\nIf you are writing higher-level Google Cloud client code, you usually also install the specific client library you need, such as `google-cloud-storage` or `google-cloud-bigquery`. `google-auth` is the shared authentication layer underneath those libraries.\n\n## Authentication And Setup\n\n### Use ADC for the common case\n\n`google.auth.default()` is the standard entry point. In practice it commonly resolves credentials from:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. Local Application Default Credentials created by `gcloud auth application-default login`\n3. An attached service account on Google Cloud runtimes\n4. External account configuration for workload identity federation\n\nFor direct HTTP calls, pair ADC with `AuthorizedSession`:\n\n```python\nimport google.auth\nfrom google.auth.transport.requests import AuthorizedSession\n\nSCOPES = [\"https://www.googleapis.com/auth/cloud-platform\"]\n\ncredentials, project_id = google.auth.default(scopes=SCOPES)\nsession = AuthorizedSession(credentials)\n\nresponse = session.get(\n    \"https://storage.googleapis.com/storage/v1/b\",\n    params={\"project\": project_id},\n    timeout=30,\n)\nresponse.raise_for_status()\n\nfor bucket in response.json().get(\"items\", []):\n    print(bucket[\"name\"])\n```\n\nNotes:\n\n- `project_id` may be `None`; do not assume ADC always discovers one.\n- Pass scopes explicitly when you are using raw transports instead of a higher-level client library.\n- `AuthorizedSession` refreshes access tokens automatically, but you still need to set request timeouts yourself.\n\n### Refresh a token explicitly\n\nRefresh manually when you need the current bearer token value:\n\n```python\nimport google.auth\nfrom google.auth.transport.requests import Request\n\ncredentials, _ = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\ncredentials.refresh(Request())\n\nprint(credentials.token)\n```\n\n## Core Credential Flows\n\n### Service account credentials\n\nUse a service account key file only when ADC, workload identity federation, or impersonation is not viable.\n\n```python\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\",\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n\ncredentials = credentials.with_quota_project(\"billing-project-id\")\n```\n\nFor Google Workspace domain-wide delegation:\n\n```python\ndelegated = credentials.with_subject(\"user@example.com\")\n```\n\nImportant points:\n\n- Keep private key files out of source control.\n- Prefer deriving copies with `with_scopes(...)`, `with_quota_project(...)`, and `with_subject(...)` instead of mutating shared state.\n- Domain-wide delegation only works when the Workspace admin has explicitly authorized the service account.\n\n### Authorized user credentials\n\nIf an OAuth flow has already produced an authorized-user JSON file, load it with `google.oauth2.credentials`:\n\n```python\nfrom google.auth.transport.requests import AuthorizedSession\nfrom google.oauth2.credentials import Credentials\n\ncredentials = Credentials.from_authorized_user_file(\n    \"authorized-user.json\",\n    scopes=[\"openid\", \"https://www.googleapis.com/auth/userinfo.email\"],\n)\n\nsession = AuthorizedSession(credentials)\nresponse = session.get(\n    \"https://openidconnect.googleapis.com/v1/userinfo\",\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json()[\"email\"])\n```\n\n`google-auth` can use these credentials, but it does not run the browser login flow that creates them.\n\n### Workload identity federation and external account configs\n\nFor AWS, Azure, or OIDC federation into Google Cloud, load the external account config instead of distributing service account keys:\n\n```python\nimport google.auth\n\ncredentials, project_id = google.auth.load_credentials_from_file(\n    \"wif-config.json\",\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n```\n\nThe official docs call the generic credential-loading helpers security-sensitive. Validate any externally supplied credential JSON before using it, and prefer config files generated by Google Cloud tooling rather than user-uploaded files.\n\n### Service account impersonation\n\nUse impersonation when one trusted credential should mint short-lived credentials for another service account:\n\n```python\nimport google.auth\nfrom google.auth import impersonated_credentials\n\nsource_credentials, _ = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\n\ntarget_credentials = impersonated_credentials.Credentials(\n    source_credentials=source_credentials,\n    target_principal=\"sa-name@project-id.iam.gserviceaccount.com\",\n    target_scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n    lifetime=300,\n)\n```\n\nThis is usually safer than distributing long-lived key files.\n\n### Fetch ID tokens for Cloud Run or IAP\n\nUse ID tokens, not OAuth access tokens, when the target expects an audience-bound identity token:\n\n```python\nfrom google.auth.transport.requests import Request\nfrom google.oauth2 import id_token\n\naudience = \"https://my-service-abc-uc.a.run.app\"\ntoken = id_token.fetch_id_token(Request(), audience)\nprint(token)\n```\n\nRule of thumb:\n\n- Google APIs usually expect OAuth access tokens.\n- Cloud Run, IAP, and similar identity-aware endpoints often expect ID tokens with the correct audience.\n\n## Direct HTTP Usage\n\n`AuthorizedSession` is the practical default when you need raw HTTP instead of a higher-level Google client library:\n\n```python\nfrom google.auth.transport.requests import AuthorizedSession\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\",\n    scopes=[\"https://www.googleapis.com/auth/devstorage.read_only\"],\n)\n\nsession = AuthorizedSession(credentials)\nresponse = session.get(\n    \"https://storage.googleapis.com/storage/v1/b/my-bucket/o\",\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n```\n\nOther transports exist, including `google.auth.transport.urllib3` and gRPC helpers, but `requests`-based `AuthorizedSession` is usually the fastest path for agent-written code.\n\n## Configuration Notes\n\n- `GOOGLE_APPLICATION_CREDENTIALS` points ADC at a credential file when you need to override the default environment.\n- `scopes` matter for raw REST usage and some service account flows; many higher-level Google client libraries set defaults for you.\n- `quota_project_id` is important when billing or quota should be charged to a different project than the resource project.\n- Metadata server availability affects ADC behavior on GCE, GKE, and Cloud Run.\n- Always pass `timeout=` on HTTP requests; auth helpers do not define your network timeout policy.\n\n## Common Pitfalls\n\n### Package name and import names differ\n\nInstall `google-auth`, but import from `google.auth` and `google.oauth2`.\n\n### `google-auth` is not the browser OAuth flow\n\nIf your code needs to open a browser, redirect a user, or complete an OAuth consent screen, use `google-auth-oauthlib` together with `google-auth`.\n\n### ADC can resolve an unexpected identity\n\n`google.auth.default()` may choose local CLI credentials, an attached runtime service account, or a workload identity config depending on the environment. If the wrong account is being used, inspect the resolved credential source before debugging the API call itself.\n\n### `project_id` may be missing\n\nAuthentication can succeed even when no project ID is returned. Pass project IDs explicitly when the downstream API requires them.\n\n### Access tokens and ID tokens are not interchangeable\n\nIf you get audience or issuer errors, verify whether the target service expects an ID token instead of a bearer access token.\n\n### Credential files are sensitive configuration\n\nThe official docs explicitly warn against blindly trusting externally supplied credential configuration files. Do not accept uploaded JSON credentials across a trust boundary without validation.\n\n## Version-Sensitive Notes\n\n### Hosted documentation lags the package release\n\nAs of 2026-03-12, PyPI has `2.49.0`, while the official `googleapis.dev` API docs still render as `2.47.0` and the Read the Docs user guide renders as `2.38.0`. If a symbol or parameter seems missing from the hosted docs, check the installed package in your environment before assuming the API is unavailable.\n\n### Python 3.8 is the minimum supported version on PyPI\n\nIf you are pinned to Python `3.7`, you need an older `google-auth` release line.\n\n## Official Sources\n\n- PyPI: `https://pypi.org/project/google-auth/`\n- API docs root: `https://googleapis.dev/python/google-auth/latest/`\n- User guide: `https://google-auth.readthedocs.io/en/latest/user-guide.html`\n- Core API reference: `https://googleapis.dev/python/google-auth/latest/reference/google.auth.html`\n- Requests transport reference: `https://googleapis.dev/python/google-auth/latest/reference/google.auth.transport.requests.html`\n- Service account reference: `https://googleapis.dev/python/google-auth/latest/reference/google.oauth2.service_account.html`\n- Impersonation reference: `https://googleapis.dev/python/google-auth/latest/reference/google.auth.impersonated_credentials.html`\n- ID token reference: `https://googleapis.dev/python/google-auth/latest/reference/google.oauth2.id_token.html`\n- Repository: `https://github.com/googleapis/google-auth-library-python`\n"
  },
  {
    "path": "content/google/docs/auth-httplib2/python/DOC.md",
    "content": "---\nname: auth-httplib2\ndescription: \"google-auth-httplib2 package guide for Python projects that still need httplib2-backed authenticated Google API requests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-auth,httplib2,google-api-python-client,authentication,http\"\n---\n\n# google-auth-httplib2 Python Package Guide\n\n## Golden Rule\n\nUse `google-auth-httplib2` only when you must attach modern `google-auth` credentials to code that already depends on `httplib2`, especially legacy `google-api-python-client` integrations. The maintainer docs explicitly say this library is no longer maintained and that new usage should prefer the transport layers provided by `google-auth`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-auth-httplib2==0.3.0\"\n```\n\nIf you are also using the discovery-based Google API client:\n\n```bash\npython -m pip install \"google-api-python-client>=2\"\n```\n\nImport names do not match the package slug:\n\n- Install `google-auth-httplib2`\n- Import `google_auth_httplib2`\n\n## Authentication And Setup\n\nFor the common case, use Application Default Credentials (ADC). Locally, that usually means one of these:\n\n```bash\ngcloud auth application-default login\n```\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nIf your code needs a project id for raw REST calls, keep it explicit:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nChoose scopes for the API you are calling. For example:\n\n```python\nSCOPES = [\"https://www.googleapis.com/auth/devstorage.read_only\"]\n```\n\n## Core Usage\n\n### Wrap an `httplib2.Http` instance with ADC credentials\n\nUse `AuthorizedHttp` when you already have `httplib2`-based code and need bearer-token handling plus automatic refresh on auth failures.\n\n```python\nimport json\nimport os\nfrom urllib.parse import urlencode\n\nimport google.auth\nimport google_auth_httplib2\nimport httplib2\n\nSCOPES = [\"https://www.googleapis.com/auth/devstorage.read_only\"]\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\ncredentials, _ = google.auth.default(scopes=SCOPES)\n\nhttp = httplib2.Http(timeout=30)\nauthed_http = google_auth_httplib2.AuthorizedHttp(credentials, http=http)\n\ntry:\n    uri = \"https://storage.googleapis.com/storage/v1/b?\" + urlencode(\n        {\"project\": PROJECT_ID}\n    )\n    response, content = authed_http.request(uri, method=\"GET\")\n\n    if response.status != 200:\n        raise RuntimeError(f\"Request failed: {response.status} {content!r}\")\n\n    for bucket in json.loads(content).get(\"items\", []):\n        print(bucket[\"name\"])\nfinally:\n    authed_http.close()\n```\n\nPractical notes:\n\n- `AuthorizedHttp` behaves like `httplib2.Http`, so existing `request(...)` call patterns usually carry over.\n- The wrapper refreshes credentials and retries when it sees auth refresh status codes; the default retry limit is `2`.\n- Set network timeouts on the underlying `httplib2.Http(...)` or via `authed_http.timeout`.\n\n### Initialize with an explicit service account file\n\nUse this when ADC is not the right fit for the process:\n\n```python\nimport os\n\nimport google_auth_httplib2\nimport httplib2\nfrom google.oauth2 import service_account\n\nSCOPES = [\"https://www.googleapis.com/auth/drive.metadata.readonly\"]\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"],\n    scopes=SCOPES,\n)\n\nauthed_http = google_auth_httplib2.AuthorizedHttp(\n    credentials,\n    http=httplib2.Http(timeout=30),\n)\n```\n\n### Use it with `google-api-python-client`\n\nThis is the main reason to keep `google-auth-httplib2` around in modern codebases.\n\n```python\nimport google.auth\nimport google_auth_httplib2\nimport httplib2\nfrom googleapiclient.discovery import build\n\nSCOPES = [\"https://www.googleapis.com/auth/drive.metadata.readonly\"]\n\ncredentials, _ = google.auth.default(scopes=SCOPES)\nauthed_http = google_auth_httplib2.AuthorizedHttp(\n    credentials,\n    http=httplib2.Http(timeout=30),\n)\n\nservice = build(\"drive\", \"v3\", http=authed_http)\n\ntry:\n    response = service.files().list(\n        pageSize=10,\n        fields=\"files(id,name,mimeType)\",\n    ).execute()\n    for file in response.get(\"files\", []):\n        print(file[\"id\"], file[\"name\"], file[\"mimeType\"])\nfinally:\n    service.close()\n```\n\n### Refresh credentials manually\n\nUse `Request` only when you need to refresh a credential object directly. If you already use `AuthorizedHttp`, you normally do not need this.\n\n```python\nimport google.auth\nimport google_auth_httplib2\nimport httplib2\n\nSCOPES = [\"https://www.googleapis.com/auth/cloud-platform\"]\n\ncredentials, _ = google.auth.default(scopes=SCOPES)\nrequest = google_auth_httplib2.Request(httplib2.Http(timeout=30))\ncredentials.refresh(request)\n\nprint(credentials.token)\n```\n\n## Configuration Notes\n\n- `google.auth.default(scopes=...)` is the standard way to get credentials for `AuthorizedHttp`.\n- ADC checks `GOOGLE_APPLICATION_CREDENTIALS`, local ADC created by `gcloud auth application-default login`, then attached runtime credentials on Google Cloud.\n- `AuthorizedHttp` can wrap your own preconfigured `httplib2.Http` object if you already rely on custom proxy, certificate, cache, or redirect settings.\n- `google-api-python-client` keeps HTTP connections open by default. Close the service object when done.\n\n## Common Pitfalls\n\n- Do not start new code with `google-auth-httplib2` unless you are forced to stay on `httplib2`. For new transports, use `google-auth` integrations such as `google.auth.transport.requests`.\n- `httplib2.Http()` objects are not thread-safe. If you use `google-api-python-client` from multiple threads, create a separate `httplib2.Http()` or `AuthorizedHttp` per thread or per request.\n- `google_auth_httplib2.Request(...).__call__(..., timeout=...)` ignores the per-call `timeout` argument because `httplib2` ignores it. Set the timeout when you construct `httplib2.Http(timeout=30)` instead.\n- `google.auth.default()` can return credentials with no discovered project id. Pass the project explicitly when the API call needs one.\n- The package name and import name differ: install `google-auth-httplib2`, import `google_auth_httplib2`.\n\n## Version-Sensitive Notes For 0.3.0\n\n- PyPI lists `0.3.0` as the current release, uploaded on December 15, 2025.\n- The `0.3.0` changelog entry adds Python 3.14 support. It does not introduce a new transport model or a broader maintenance commitment.\n- The `0.2.1` changelog tightened compatibility to `google-auth >=1.32.0,<3.0.0`, `httplib2 >=0.19.0,<1.0.0`, and Python `>=3.7`.\n- The original GitHub repository is archived and still points users to the generated docs, which matches the package's \"migration helper for existing httplib2 users\" status rather than an actively evolving library.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/googleapis/google-auth-library-python-httplib2`\n- Package docs root: `https://googleapis.dev/python/google-auth-httplib2/latest/`\n- API reference: `https://googleapis.dev/python/google-auth-httplib2/latest/google_auth_httplib2.html`\n- Changelog: `https://googleapis.dev/python/google-auth-httplib2/latest/CHANGELOG.html`\n- PyPI: `https://pypi.org/project/google-auth-httplib2/`\n- Google API client getting started: `https://googleapis.github.io/google-api-python-client/docs/start.html`\n- Google API client thread safety: `https://googleapis.github.io/google-api-python-client/docs/thread_safety.html`\n- ADC overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/automl/python/DOC.md",
    "content": "---\nname: automl\ndescription: \"Google Cloud AutoML Python client for legacy dataset, training, prediction, and AutoML Tables workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.18.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,automl,vertex-ai,ml,prediction,python\"\n---\n\n# Google Cloud AutoML Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-automl` only for maintaining existing Cloud AutoML integrations. Google now points new AutoML work at Vertex AI and the `google-cloud-aiplatform` package. For code that still depends on this package, use Application Default Credentials (ADC), enable `automl.googleapis.com`, and set a regional AutoML endpoint on every client.\n\nThe package exposes two namespaces you will actually use:\n\n- `google.cloud.automl_v1` for datasets, models, operations, and prediction\n- `google.cloud.automl_v1beta1` for legacy AutoML Tables helpers such as `TablesClient`\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-automl==2.18.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-automl==2.18.1\"\npoetry add \"google-cloud-automl==2.18.1\"\n```\n\n## Project And Authentication Setup\n\nEnable the AutoML API in the Google Cloud project you will call:\n\n```bash\ngcloud services enable automl.googleapis.com\n```\n\nFor local development, create ADC with the Google Cloud CLI:\n\n```bash\ngcloud auth application-default login\n```\n\nIf you must use a service account key outside Google Cloud, point ADC at the file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport AUTOML_DATASET_ID=\"1234567890123456789\"\nexport AUTOML_MODEL_ID=\"9876543210987654321\"\n```\n\n`google-cloud-automl` is regional. The client reference explicitly warns that you may need to specify regional endpoints when creating the service client. Keep the `location`, resource names, and `api_endpoint` aligned.\n\n## Initialize The Clients\n\nCreate one shared set of clients near process startup and reuse them:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import automl_v1\nfrom google.cloud import automl_v1beta1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient_options = ClientOptions(api_endpoint=f\"{LOCATION}-automl.googleapis.com\")\n\nautoml_client = automl_v1.AutoMlClient(client_options=client_options)\nprediction_client = automl_v1.PredictionServiceClient(\n    client_options=client_options\n)\n\n# Only needed for legacy AutoML Tables workflows.\ntables_client = automl_v1beta1.TablesClient(client_options=client_options)\n\nlocation_path = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\ndataset_name = (\n    f\"projects/{PROJECT_ID}/locations/{LOCATION}/datasets/\"\n    f\"{os.environ['AUTOML_DATASET_ID']}\"\n)\nmodel_name = (\n    f\"projects/{PROJECT_ID}/locations/{LOCATION}/models/\"\n    f\"{os.environ['AUTOML_MODEL_ID']}\"\n)\n```\n\n## Common Workflows\n\n### List Existing Datasets\n\nUse `filter` only when you want a specific dataset family. Remove it to list everything in the location.\n\n```python\nfrom google.cloud import automl_v1\n\nrequest = automl_v1.ListDatasetsRequest(\n    parent=location_path,\n    filter=\"translation_dataset_metadata:*\",\n)\n\nfor dataset in automl_client.list_datasets(request=request):\n    print(dataset.name, dataset.display_name)\n```\n\n### Import Training Data From Cloud Storage\n\nThe input file format is modality-specific. For example, text classification CSVs and image import CSVs follow different schemas in the product docs.\n\n```python\nfrom google.cloud import automl_v1\n\ngcs_uri = \"gs://your-bucket/training.csv\"\n\ninput_config = automl_v1.InputConfig(\n    gcs_source=automl_v1.GcsSource(input_uris=[gcs_uri])\n)\n\noperation = automl_client.import_data(\n    request=automl_v1.ImportDataRequest(\n        name=dataset_name,\n        input_config=input_config,\n    )\n)\n\noperation.result(timeout=1800)\nprint(\"Import finished\")\n```\n\n### Train A Text Classification Model\n\nModel creation is a long-running operation. Keep the returned model name and reuse it for prediction.\n\n```python\nfrom google.cloud import automl_v1\n\ndataset_id = os.environ[\"AUTOML_DATASET_ID\"]\n\nmodel = automl_v1.Model(\n    display_name=\"support-ticket-router\",\n    dataset_id=dataset_id,\n    text_classification_model_metadata=automl_v1.TextClassificationModelMetadata(),\n)\n\noperation = automl_client.create_model(\n    request=automl_v1.CreateModelRequest(\n        parent=location_path,\n        model=model,\n    )\n)\n\nmodel = operation.result(timeout=7200)\nprint(model.name)\n```\n\nThe metadata field changes by problem type. Do not copy `TextClassificationModelMetadata` into image, video, or translation code paths.\n\n### Run Online Text Prediction\n\nThis is the exact request shape for inline text prediction:\n\n```python\nfrom google.cloud import automl_v1\n\npayload = automl_v1.ExamplePayload(\n    text_snippet=automl_v1.TextSnippet(\n        content=\"Please cancel my subscription and refund the latest invoice.\",\n        mime_type=\"text/plain\",\n    )\n)\n\nresponse = prediction_client.predict(\n    request=automl_v1.PredictRequest(\n        name=model_name,\n        payload=payload,\n    )\n)\n\nfor annotation in response.payload:\n    print(annotation.display_name)\n    print(annotation.classification.score)\n```\n\n### Run Online Image Prediction\n\nFor image classification or object detection, send image bytes inside `ExamplePayload.Image`:\n\n```python\nfrom google.cloud import automl_v1\n\nwith open(\"image.jpg\", \"rb\") as fh:\n    image_bytes = fh.read()\n\npayload = automl_v1.ExamplePayload(\n    image=automl_v1.Image(image_bytes=image_bytes)\n)\n\nresponse = prediction_client.predict(\n    request=automl_v1.PredictRequest(\n        name=model_name,\n        payload=payload,\n    )\n)\n\nfor annotation in response.payload:\n    print(annotation)\n```\n\nThe structure of each returned annotation depends on the model type. Classification models return scores; detection models also return bounding boxes.\n\n### Use The Legacy AutoML Tables Helper\n\n`TablesClient` is still under `automl_v1beta1`, and the latest reference says `us-central1` is the only supported location for tables helpers.\n\n```python\nfrom google.cloud import automl_v1beta1\n\ntable_dataset_name = (\n    f\"projects/{PROJECT_ID}/locations/us-central1/datasets/\"\n    f\"{os.environ['AUTOML_DATASET_ID']}\"\n)\n\nrequest = automl_v1beta1.ListTableSpecsRequest(parent=table_dataset_name)\n\nfor table_spec in tables_client.list_table_specs(request=request):\n    print(table_spec.name, table_spec.time_column_spec_id)\n```\n\nIf you are maintaining AutoML Tables code, keep the namespace consistent. Do not mix `automl_v1beta1.TablesClient` requests with `automl_v1` request types in the same call.\n\n## Common Pitfalls\n\n- `gcloud auth login` is not enough for local Python code. Use `gcloud auth application-default login` so ADC resolves correctly.\n- The resource location and the client endpoint must match. A `us-central1` dataset with an `eu-automl.googleapis.com` endpoint is a common failure mode.\n- Long-running operations are normal for import and training. Always call `.result(...)` or poll the operation instead of assuming the work finished after the initial RPC returns.\n- `dataset_name` is a full resource name, while some request bodies use a plain `dataset_id`. Do not swap them.\n- The input format for `import_data` is product-specific. Check the product guide for the exact CSV or JSONL shape before uploading files.\n- AutoML Tables helpers are still beta-namespace APIs. Keep them in `automl_v1beta1` and default to `us-central1`.\n- This package is a legacy surface. Before starting new code, verify that the specific AutoML product you need has not already moved to Vertex AI or reached end-of-support.\n\n## Version-Sensitive Notes For `2.18.1`\n\n- PyPI currently lists `google-cloud-automl 2.18.1` and `Requires: Python >=3.7`.\n- The PyPI project description says the AutoML API client library is now available from Vertex AI and recommends the Vertex AI SDK (`google-cloud-aiplatform`) for the new AutoML features.\n- On March 13, 2026, the latest generated Python reference root was live, but some individual client pages such as `PredictionServiceClient` and `TablesClient` were still rendered under `2.17.0` URLs. Use PyPI for package-version metadata and the generated client pages for method signatures.\n- Google has already shut down several legacy AutoML product families outside Vertex AI, including AutoML Vision, AutoML Video Intelligence, AutoML Tables, and AutoML Natural Language. Check the deprecations page before reviving an older integration.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/google-cloud-automl/`\n- Python reference root: `https://cloud.google.com/python/docs/reference/automl/latest`\n- `AutoMlClient` reference: `https://cloud.google.com/python/docs/reference/automl/latest/google.cloud.automl_v1.services.auto_ml.AutoMlClient`\n- `PredictionServiceClient` reference: `https://cloud.google.com/python/docs/reference/automl/latest/google.cloud.automl_v1.services.prediction_service.PredictionServiceClient`\n- `TablesClient` reference: `https://cloud.google.com/python/docs/reference/automl/latest/google.cloud.automl_v1beta1.services.tables.TablesClient`\n- AutoML quickstart setup: `https://cloud.google.com/automl/docs/quickstarts`\n- ADC local setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Vertex AI deprecations and shut down page: `https://cloud.google.com/vertex-ai/docs/deprecations`\n"
  },
  {
    "path": "content/google/docs/batch/python/DOC.md",
    "content": "---\nname: batch\ndescription: \"Google Cloud Batch Python client library for submitting, inspecting, and managing batch jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.20.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,batch,jobs,compute,scheduler\"\n---\n\n# Google Cloud Batch Python Client\n\n## Golden Rule\n\nUse `google-cloud-batch` with `from google.cloud import batch_v1`, authenticate with Application Default Credentials (ADC), and treat Batch as a regional control plane over Compute Engine resources. Most real failures come from missing IAM, unsupported region choice, or VM/network/service-account configuration in the job definition, not from the Python client itself.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-batch==0.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-batch==0.20.0\"\npoetry add \"google-cloud-batch==0.20.0\"\n```\n\n## Authentication And Setup\n\nBefore writing code:\n\n1. Enable the Google Cloud Batch API on the target project.\n2. Make sure billing is enabled for the project.\n3. Pick a supported Batch region and keep using that same region in resource names.\n4. Confirm the caller can create Batch jobs and act as the job's VM service account.\n\nFor local development, use ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nThen construct the client normally:\n\n```python\nfrom google.cloud import batch_v1\n\nclient = batch_v1.BatchServiceClient()\n```\n\nIf you must use a service account key file, set the standard ADC environment variable before creating the client:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nPractical auth notes:\n\n- `gcloud auth login` is not enough for this library by itself; the Python client uses ADC.\n- On Google Cloud runtimes, prefer attached service accounts or workload identity over long-lived key files.\n- If your organization has removed the default VPC network or restricts images and service accounts with org policies, your job spec must set compatible networking and identity explicitly.\n\n## Core Usage\n\n### Submit a basic script job\n\nThis is the smallest practical job shape: one task group, one runnable script, fixed compute, Cloud Logging enabled.\n\n```python\nfrom google.cloud import batch_v1\n\ndef create_script_job(project_id: str, region: str, job_id: str) -> batch_v1.Job:\n    client = batch_v1.BatchServiceClient()\n\n    runnable = batch_v1.Runnable()\n    runnable.script = batch_v1.Runnable.Script()\n    runnable.script.text = (\n        \"echo Hello from task ${BATCH_TASK_INDEX}/${BATCH_TASK_COUNT}; \"\n        \"sleep 5\"\n    )\n\n    resources = batch_v1.ComputeResource()\n    resources.cpu_milli = 2000\n    resources.memory_mib = 512\n\n    task = batch_v1.TaskSpec()\n    task.runnables = [runnable]\n    task.compute_resource = resources\n    task.max_retry_count = 2\n    task.max_run_duration = \"3600s\"\n\n    group = batch_v1.TaskGroup()\n    group.task_count = 4\n    group.task_spec = task\n\n    instance_policy = batch_v1.AllocationPolicy.InstancePolicy()\n    instance_policy.machine_type = \"e2-standard-4\"\n\n    instance = batch_v1.AllocationPolicy.InstancePolicyOrTemplate()\n    instance.policy = instance_policy\n\n    allocation_policy = batch_v1.AllocationPolicy()\n    allocation_policy.instances = [instance]\n\n    job = batch_v1.Job()\n    job.task_groups = [group]\n    job.allocation_policy = allocation_policy\n    job.labels = {\"env\": \"dev\"}\n\n    job.logs_policy = batch_v1.LogsPolicy()\n    job.logs_policy.destination = batch_v1.LogsPolicy.Destination.CLOUD_LOGGING\n\n    request = batch_v1.CreateJobRequest()\n    request.parent = f\"projects/{project_id}/locations/{region}\"\n    request.job_id = job_id\n    request.job = job\n\n    return client.create_job(request=request)\n\ncreated = create_script_job(\n    project_id=\"my-project\",\n    region=\"us-central1\",\n    job_id=\"example-job-001\",\n)\n\nprint(created.name)\n```\n\nNotes:\n\n- `job_id` must be unique within the project and region.\n- The parent resource is always `projects/{project}/locations/{region}`.\n- The task runtime gets useful built-in environment variables such as `BATCH_TASK_INDEX`, `BATCH_TASK_COUNT`, `BATCH_HOSTS_FILE`, and `BATCH_TASK_RETRY_ATTEMPT`.\n\n### Run a container instead of an inline script\n\nReplace the runnable setup when your workload is already packaged as a container image:\n\n```python\nfrom google.cloud import batch_v1\n\nrunnable = batch_v1.Runnable()\nrunnable.container = batch_v1.Runnable.Container()\nrunnable.container.image_uri = \"us-docker.pkg.dev/cloudrun/container/hello\"\nrunnable.container.entrypoint = \"/bin/sh\"\nrunnable.container.commands = [\"-c\", \"python -V && echo batch container started\"]\n```\n\nKeep the rest of the job structure the same.\n\n### Inspect, list, cancel, or delete jobs\n\n```python\nfrom google.cloud import batch_v1\n\nclient = batch_v1.BatchServiceClient()\njob_name = \"projects/my-project/locations/us-central1/jobs/example-job-001\"\nparent = \"projects/my-project/locations/us-central1\"\n\njob = client.get_job(name=job_name)\nprint(job.status.state)\n\nfor item in client.list_jobs(parent=parent):\n    print(item.name, item.status.state)\n\ncancel_op = client.cancel_job(name=job_name)\ncancel_op.result()\n\ndelete_op = client.delete_job(name=job_name)\ndelete_op.result()\n```\n\n`cancel_job()` and `delete_job()` return long-running operations, so wait for them instead of assuming the state changed immediately.\n\n### Task groups and tasks\n\n`list_tasks()` needs the task group resource name, not just the job name. If you need per-task inspection, keep the task group name returned by the created job or the later job lookup and pass that full resource path to `list_tasks(parent=...)`.\n\n## Configuration Notes\n\n### Service account and permissions\n\nBatch jobs run on VMs, so there are usually two identities involved:\n\n- the caller creating the job\n- the service account attached to the job's VMs\n\nThe official setup docs call out two common requirements:\n\n- the caller needs permission to create jobs\n- the caller needs permission to act as the job service account\n\nIf you need a non-default VM service account, set it in the job's allocation policy rather than relying on ambient defaults.\n\n### Region and endpoint handling\n\nBatch is regional. Keep these aligned:\n\n- the `parent` location in `create_job()` and `list_jobs()`\n- the fully-qualified job name in `get_job()`, `cancel_job()`, and `delete_job()`\n- the product region where Batch is supported\n\nThe generated client also supports endpoint overrides through `client_options.api_endpoint`. This matters for custom endpoint selection and mTLS behavior.\n\n### Logging\n\nFor job output, send logs to Cloud Logging with `job.logs_policy.destination = CLOUD_LOGGING`.\n\nFor SDK-internal Python logging, Google's generated clients support the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable. Example:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\n## Common Pitfalls\n\n- Package name and import path differ: install `google-cloud-batch`, import `batch_v1`.\n- Do not confuse CLI credentials with ADC. If local auth works in `gcloud` but fails in Python, run `gcloud auth application-default login`.\n- Batch is regional. A valid project with the wrong region string still fails.\n- A job can be syntactically valid but still fail at runtime because the VM service account, network, subnet, or image permissions are wrong.\n- If your project no longer has a usable default network, the simplest examples from the docs are not enough; add explicit networking or an instance template.\n- `create_job()` returns the job resource immediately, not proof that all tasks succeeded. Check job state and logs afterward.\n- `cancel_job()` and `delete_job()` are operations; wait for them.\n- The generated clients warn against using the client object as a context manager if the transport is shared elsewhere, because exiting closes the transport.\n\n## Version-Sensitive Notes For 0.20.0\n\n- PyPI and the official changelog both show `0.20.0` as the current release line covered here as of `2026-03-12`.\n- The `0.20.0` changelog notes auto-enabled mTLS support when a supported client certificate is present. If endpoint behavior changes unexpectedly, check `GOOGLE_API_USE_MTLS_ENDPOINT`, `GOOGLE_API_USE_CLIENT_CERTIFICATE`, and any explicit `client_options.api_endpoint` override.\n- The `0.19.0` release added new provisioning-model support. If you are adapting older 2025 examples around instance provisioning, confirm the current Batch fields and enums in the latest API reference.\n- PyPI still marks this package as beta, so generated client details can change faster than long-established Google Cloud libraries. Prefer the current reference and changelog over blog posts.\n"
  },
  {
    "path": "content/google/docs/beyondcorp/python/DOC.md",
    "content": "---\nname: beyondcorp\ndescription: \"google-cloud-beyondcorp package guide for Python: package split, ADC auth, service clients, resource names, and operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"google-cloud,beyondcorp,python,gcp,iam,zero-trust\"\n---\n\n# google-cloud-beyondcorp Python Package Guide\n\n## What This Entry Covers\n\nThis entry is pinned to the package version used here `google-cloud-beyondcorp==3.0.0`.\n\n## Canonical Docs For Real Work\n\nUse the service-specific official docs that match the BeyondCorp surface you are calling:\n\n- AppConnections: `https://cloud.google.com/python/docs/reference/beyondcorp-appconnections/latest`\n- AppConnectors: `https://cloud.google.com/python/docs/reference/beyondcorp-appconnectors/latest`\n- AppGateways: `https://cloud.google.com/python/docs/reference/beyondcorp-appgateways/latest`\n- ClientConnectorServices: `https://cloud.google.com/python/docs/reference/beyondcorp-clientconnectorservices/latest`\n- ClientGateways: `https://cloud.google.com/python/docs/reference/beyondcorp-clientgateways/latest`\n\nIf the project already depends on the old umbrella package, keep the dependency pinned and verify the exact imports in that codebase before changing anything.\n\n## Version-Sensitive Note\n\nAn older package reference pointed at `google-cloud-beyondcorp==3.0.0`, but Google Cloud's current official Python docs no longer use a single `beyondcorp/latest` reference as the primary navigation surface. For new code, pick the specific BeyondCorp service first, then use that service's generated client library docs.\n\nThat means agents should not assume:\n\n- one package contains every BeyondCorp client\n- the umbrella docs URL is the canonical current reference\n- examples from one BeyondCorp service page apply to the others unchanged\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-beyondcorp==3.0.0\"\n```\n\nFor new code, install the service-specific client package that matches the API you actually need. Typical packages are:\n\n```bash\npython -m pip install google-cloud-beyondcorp-appconnections\npython -m pip install google-cloud-beyondcorp-appconnectors\npython -m pip install google-cloud-beyondcorp-appgateways\npython -m pip install google-cloud-beyondcorp-clientconnectorservices\npython -m pip install google-cloud-beyondcorp-clientgateways\n```\n\n## Authentication And Setup\n\nThese clients follow the normal Google Cloud Python authentication model:\n\n1. Enable the relevant BeyondCorp API in the target Google Cloud project.\n2. Use Application Default Credentials.\n3. Run locally with user ADC or in production with a service account.\n4. Grant IAM roles on the project and BeyondCorp resources before debugging client code.\n\nFor local development, the common pattern is:\n\n```bash\ngcloud auth application-default login\n```\n\nThen set the project and location you will target:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\n## Choosing The Right Client\n\nPick the client by resource family, not by the old umbrella package name:\n\n- Use AppConnections when working with application connection resources.\n- Use AppConnectors when managing connector resources.\n- Use AppGateways when managing application gateways.\n- Use ClientConnectorServices for connector services exposed to clients.\n- Use ClientGateways for client gateway resources.\n\nIf you are not sure which service you need, start from the resource names already present in the project or Terraform config. The resource collection usually tells you which client page to open.\n\n## Quick Start\n\nThis example uses the AppConnections client because it is one of the current official BeyondCorp Python references.\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n\nfor app_connection in client.list_app_connections(parent=parent):\n    print(app_connection.name)\n```\n\nUse the same overall pattern for the other BeyondCorp services:\n\n- import the matching generated module\n- create the service client\n- build the `projects/{project}/locations/{location}` parent path\n- call the list/get/create/update/delete method for that service\n\n## Core Usage Patterns\n\n### Resource Names Are Fully Qualified\n\nMost methods expect resource names like:\n\n```text\nprojects/PROJECT_ID/locations/LOCATION_ID/RESOURCE_COLLECTION/RESOURCE_ID\n```\n\nDo not pass a bare ID when the method expects a fully qualified resource name.\n\n### Many Mutating Calls Use Long-Running Operations\n\nCreate, update, and delete operations in Google Cloud generated clients often return long-running operations. Wait for completion instead of assuming the initial RPC means the resource is ready.\n\n```python\noperation = client.create_app_connection(request=request)\nresult = operation.result(timeout=300)\nprint(result.name)\n```\n\n### Regional Endpoints Matter\n\nThe official BeyondCorp service docs note that some clients may require a regional endpoint. If you get endpoint or location mismatch errors, construct the client with `client_options` and use the region-specific endpoint documented for that service.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient(\n    client_options=ClientOptions(api_endpoint=\"REGIONAL_ENDPOINT\")\n)\n```\n\nCheck the service-specific docs page before hardcoding an endpoint string.\n\n## Common Pitfalls\n\n- The docs URL is not the best current reference. Start from the service-specific docs roots above.\n- Package names, import names, and client class names are not identical. Verify the generated import on the exact official page you are using.\n- ADC may exist locally but still fail because the account lacks the required BeyondCorp IAM permissions.\n- Location is part of the resource path. `us-central1` resources and `global` resources are not interchangeable.\n- Generated clients use request objects or keyword arguments with exact field names. Do not invent field names from REST examples or older blog posts.\n- For create or update flows, wait on the operation result before reading the resource back or using it in dependent calls.\n\n## Practical Workflow For Agents\n\n1. Confirm whether the codebase is pinned to `google-cloud-beyondcorp==3.0.0` or already uses one of the split packages.\n2. Identify the exact BeyondCorp resource type the code needs.\n3. Open the matching official service reference, not the old umbrella landing page.\n4. Copy the generated client import, parent/resource path helpers, and request field names from that page.\n5. Use ADC and verify IAM before treating `PermissionDenied` or `NotFound` as code bugs.\n\n## Official Links\n\n- Queue package page: `https://pypi.org/project/google-cloud-beyondcorp/`\n- Docs URL: `https://cloud.google.com/python/docs/reference/beyondcorp/latest`\n- AppConnections reference: `https://cloud.google.com/python/docs/reference/beyondcorp-appconnections/latest`\n- AppConnectors reference: `https://cloud.google.com/python/docs/reference/beyondcorp-appconnectors/latest`\n- AppGateways reference: `https://cloud.google.com/python/docs/reference/beyondcorp-appgateways/latest`\n- ClientConnectorServices reference: `https://cloud.google.com/python/docs/reference/beyondcorp-clientconnectorservices/latest`\n- ClientGateways reference: `https://cloud.google.com/python/docs/reference/beyondcorp-clientgateways/latest`\n"
  },
  {
    "path": "content/google/docs/beyondcorp-appconnections/python/DOC.md",
    "content": "---\nname: beyondcorp-appconnections\ndescription: \"Google Cloud BeyondCorp AppConnections Python client guide with ADC setup, AppConnectionsServiceClient usage, long-running operations, and regional resource pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,beyondcorp,appconnections,python,gcp,adc,zero-trust\"\n---\n\n# google-cloud-beyondcorp-appconnections Python Package Guide\n\n## What This Package Is\n\n`google-cloud-beyondcorp-appconnections` is the official Google Cloud Python client for the BeyondCorp Enterprise AppConnections API.\n\nUse it when Python code needs to:\n\n- list or inspect AppConnection resources\n- create, update, or delete AppConnections\n- resolve which AppConnections are associated with a connector\n- wait for BeyondCorp AppConnections long-running operations to finish\n\nThe install name and import path differ:\n\n```bash\npython -m pip install google-cloud-beyondcorp-appconnections\n```\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n```\n\n## Version-Sensitive Notes\n\nThis guide started from version used here `0.6.0`. Official sources checked on `2026-03-12` show partial version drift:\n\n- PyPI lists `0.6.0` as the current published package version.\n- The rolling Google Cloud Python reference and changelog pages still render `0.5.0` content under `latest`.\n\nPractical implication:\n\n- pin installs to `0.6.0` if you need the package version used here\n- use the generated `v1` client surface shown in the official docs, but treat the docs site as slightly behind the wheel published on PyPI\n- if you need a field or transport behavior added very recently, verify it against the installed package instead of assuming the `latest` docs already reflect `0.6.0`\n\nUseful upstream change markers visible in the official changelog:\n\n- REST transport support was added before `0.6.0`\n- opt-in library logging was added before `0.6.0`\n- the docs-visible `0.5.0` release added Python `3.14` support\n\n## Install\n\nPin the package version explicitly:\n\n```bash\npython -m pip install \"google-cloud-beyondcorp-appconnections==0.6.0\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"google-cloud-beyondcorp-appconnections==0.6.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Required Setup\n\nBefore you call the client:\n\n1. Enable the BeyondCorp Enterprise API in the target project.\n2. Ensure the project already has the connector and gateway resources your AppConnection will reference.\n3. Authenticate with Application Default Credentials.\n4. Grant the caller IAM permissions for the relevant BeyondCorp resources.\n\nEnable the API:\n\n```bash\ngcloud services enable beyondcorp.googleapis.com\n```\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nService account credentials via environment variable:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful environment variables for examples:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport APPCONNECTION_ID=\"my-app-connection\"\nexport CONNECTOR_ID=\"my-app-connector\"\nexport GATEWAY_ID=\"my-app-gateway\"\n```\n\n## Client Creation\n\nDefault gRPC client:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceAsyncClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nREST transport:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient(transport=\"rest\")\n```\n\nRegional endpoint override:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=\"us-central1-beyondcorp.googleapis.com\"\n    )\n)\n```\n\nUse a regional endpoint if the product docs or runtime errors indicate the default endpoint does not match the resource location you are targeting.\n\n## Resource Naming\n\nThe generated client expects fully qualified resource names.\n\nCommon formats:\n\n- location parent: `projects/{project}/locations/{location}`\n- app connection: `projects/{project}/locations/{location}/appConnections/{app_connection}`\n- app connector: `projects/{project}/locations/{location}/appConnectors/{app_connector}`\n- app gateway: `projects/{project}/locations/{location}/appGateways/{app_gateway}`\n\nYou can build them manually or use client helpers when available:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n\nparent = f\"projects/my-project/locations/us-central1\"\nname = client.app_connection_path(\"my-project\", \"us-central1\", \"my-app-connection\")\n```\n\n## Core Usage\n\n### List AppConnections\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\n\ndef list_app_connections() -> None:\n    project_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    location = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\n    client = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n\n    for app_connection in client.list_app_connections(request={\"parent\": parent}):\n        print(app_connection.name, app_connection.display_name)\n```\n\n`list_app_connections(...)` returns a pager. Iterate over it directly.\n\n### Get One AppConnection\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\n\ndef get_app_connection(app_connection_id: str):\n    project_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    location = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\n    client = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n    name = client.app_connection_path(project_id, location, app_connection_id)\n    return client.get_app_connection(request={\"name\": name})\n\napp_connection = get_app_connection(os.environ[\"APPCONNECTION_ID\"])\nprint(app_connection.name)\nprint(app_connection.application_endpoint)\n```\n\n### Create An AppConnection\n\nCreating an AppConnection usually requires:\n\n- an existing AppConnector resource\n- an application endpoint reachable through that connector\n- optionally an AppGateway resource depending on the traffic pattern you are implementing\n\nCreate calls return a long-running operation:\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\n\ndef create_app_connection():\n    project_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    location = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n    app_connection_id = os.environ[\"APPCONNECTION_ID\"]\n    connector_id = os.environ[\"CONNECTOR_ID\"]\n    gateway_id = os.environ[\"GATEWAY_ID\"]\n\n    client = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n\n    app_connection = beyondcorp_appconnections_v1.AppConnection(\n        display_name=\"Example AppConnection\",\n        type_=\"TCP_PROXY\",\n        application_endpoint=beyondcorp_appconnections_v1.AppConnection.ApplicationEndpoint(\n            host=\"internal.example.local\",\n            port=443,\n        ),\n        connectors=[\n            f\"projects/{project_id}/locations/{location}/appConnectors/{connector_id}\"\n        ],\n        gateway=f\"projects/{project_id}/locations/{location}/appGateways/{gateway_id}\",\n    )\n\n    operation = client.create_app_connection(\n        request={\n            \"parent\": parent,\n            \"app_connection_id\": app_connection_id,\n            \"app_connection\": app_connection,\n        }\n    )\n\n    created = operation.result(timeout=600)\n    return created\n```\n\nThe exact resource combination depends on your BeyondCorp deployment. Start from the product docs for AppConnections and AppConnectors, then mirror the resource names already present in the project.\n\n### Update Mutable Fields\n\nThe generated reference documents these fields as mutable for update:\n\n- `labels`\n- `display_name`\n- `application_endpoint`\n- `connectors`\n\nUse an update mask:\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\nfrom google.protobuf import field_mask_pb2\n\ndef update_display_name(app_connection_id: str, new_display_name: str):\n    project_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    location = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\n    client = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n    name = client.app_connection_path(project_id, location, app_connection_id)\n\n    app_connection = beyondcorp_appconnections_v1.AppConnection(\n        name=name,\n        display_name=new_display_name,\n    )\n\n    operation = client.update_app_connection(\n        request={\n            \"app_connection\": app_connection,\n            \"update_mask\": field_mask_pb2.FieldMask(paths=[\"display_name\"]),\n        }\n    )\n\n    return operation.result(timeout=600)\n```\n\n### Delete An AppConnection\n\n```python\nimport os\n\nfrom google.cloud import beyondcorp_appconnections_v1\n\ndef delete_app_connection(app_connection_id: str) -> None:\n    project_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    location = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\n    client = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n    name = client.app_connection_path(project_id, location, app_connection_id)\n\n    operation = client.delete_app_connection(request={\"name\": name})\n    operation.result(timeout=600)\n```\n\n## Configuration Notes\n\n### Authentication Model\n\nThis client follows standard Google Cloud client-library auth:\n\n- local development usually uses user ADC from `gcloud auth application-default login`\n- production usually uses a service account attached to the runtime\n- raw access tokens are rarely needed directly in application code\n\nIf the credential is valid but the call still fails, check IAM on the BeyondCorp resources before changing code.\n\n### Logging\n\nThe library supports opt-in Python logging through the Google client-library logging environment variable:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google.cloud.beyondcorp_appconnections_v1\"\n```\n\nThis is useful when you need to inspect request flow or retry behavior without rewriting application logging.\n\n### Transport Choice\n\n- prefer default gRPC unless you have an environment-specific reason to use REST\n- if you switch to REST for compatibility or debugging, keep the same request objects and resource names\n\n## Common Pitfalls\n\n### Package Name, Import Name, And Client Name Differ\n\nInstall:\n\n```bash\npip install google-cloud-beyondcorp-appconnections\n```\n\nImport and client:\n\n```python\nfrom google.cloud import beyondcorp_appconnections_v1\n\nclient = beyondcorp_appconnections_v1.AppConnectionsServiceClient()\n```\n\nDo not invent imports such as `google_cloud_beyondcorp_appconnections`.\n\n### The Docs Site Lags PyPI For This Package\n\nAs of `2026-03-12`, PyPI shows `0.6.0`, while the official `latest` docs pages still render `0.5.0`. If you depend on a recently added field, check the installed package or repository source before assuming the docs page is current.\n\n### Use Full Resource Names\n\nMethods such as `get_app_connection`, `update_app_connection`, and `delete_app_connection` expect full resource names, not bare IDs.\n\n### Mutating Calls Return Long-Running Operations\n\nCreate, update, and delete calls do not complete synchronously. Always wait on `operation.result(...)` before treating the resource as ready or removed.\n\n### AppConnections Depend On Other BeyondCorp Resources\n\nCreating an AppConnection is not a standalone action. If the project does not already have the referenced AppConnector or AppGateway, the client call can fail even when the Python request shape is correct.\n\n### Region And Endpoint Must Match\n\nDo not mix `us-central1` resources with an endpoint or parent path intended for a different region. If you see `NotFound` or endpoint mismatch errors, verify:\n\n- the resource location in the fully qualified name\n- the `parent` location\n- any explicit `api_endpoint` override\n\n## Practical Workflow For Agents\n\n1. Confirm the project already has the required BeyondCorp resources and APIs enabled.\n2. Pin `google-cloud-beyondcorp-appconnections==0.6.0` unless the codebase is intentionally on another version.\n3. Use ADC first, then debug IAM and resource existence before changing request shapes.\n4. Copy import paths, client class names, and mutable-field rules from the generated reference, not from generic REST examples.\n5. Wait for long-running operations to finish before issuing dependent reads or updates.\n\n## Official Sources Used\n\n- PyPI project page: `https://pypi.org/project/google-cloud-beyondcorp-appconnections/`\n- Google Cloud Python reference root: `https://docs.cloud.google.com/python/docs/reference/beyondcorpappconnections/latest`\n- `AppConnectionsServiceClient` reference: `https://cloud.google.com/python/docs/reference/beyondcorpappconnections/latest/google.cloud.beyondcorp_appconnections_v1.services.app_connections_service.AppConnectionsServiceClient`\n- `AppConnection` reference: `https://cloud.google.com/python/docs/reference/beyondcorpappconnections/latest/google.cloud.beyondcorp_appconnections_v1.types.AppConnection`\n- changelog: `https://docs.cloud.google.com/python/docs/reference/beyondcorpappconnections/latest/changelog`\n- Google Cloud authentication guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- BeyondCorp Enterprise AppConnections product guide: `https://cloud.google.com/beyondcorp-enterprise/docs/appconnections-app-connectors`\n- official repository package root: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnections`\n"
  },
  {
    "path": "content/google/docs/bigquery/javascript/DOC.md",
    "content": "---\nname: bigquery\ndescription: \"BigQuery API JavaScript/TypeScript coding guidelines using the official Node.js client library\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.1.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"google,bigquery,data-warehouse,sql,analytics\"\n---\n\n# BigQuery API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a BigQuery API coding expert. Help me with writing code using the BigQuery API and the official Node.js client library.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://cloud.google.com/nodejs/docs/reference/bigquery/latest\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Google Cloud BigQuery Node.js client library for all BigQuery API interactions. Do not use unofficial or deprecated libraries.\n\n- **Library Name:** Google Cloud BigQuery Node.js Client\n- **NPM Package:** `@google-cloud/bigquery`\n- **Current Version:** 8.1.1\n- **Do NOT use:** `bigquery` (deprecated standalone package)\n- **Do NOT use:** Any unofficial BigQuery wrappers\n\n**Installation:**\n\n```bash\nnpm install @google-cloud/bigquery\n```\n\n**Correct Import:**\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n```\n\nor with ES6 modules:\n\n```javascript\nimport {BigQuery} from '@google-cloud/bigquery';\n```\n\n**Incorrect patterns to avoid:**\n- `const bigquery = require('bigquery')` - Wrong package\n- `import BigQuery from '@google-cloud/bigquery'` - Wrong import syntax (missing curly braces)\n- Using any package other than `@google-cloud/bigquery`\n\n## Installation and Setup\n\n### Install the package\n\n```bash\nnpm install @google-cloud/bigquery\n```\n\n### Authentication\n\nBigQuery requires authentication. The client library uses Application Default Credentials (ADC).\n\n**Set up authentication using one of these methods:**\n\n**Option 1: Service Account Key File (Recommended for local development)**\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/your/service-account-key.json\"\n```\n\n**Option 2: Application Default Credentials (Recommended for production)**\n\nWhen running on Google Cloud (Cloud Functions, Cloud Run, GKE, etc.), authentication happens automatically.\n\n**Option 3: Explicit credentials in code**\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n\nconst bigquery = new BigQuery({\n  projectId: 'your-project-id',\n  keyFilename: '/path/to/service-account-key.json'\n});\n```\n\n### Environment Variables\n\n```javascript\n// Set these environment variables\nprocess.env.GOOGLE_APPLICATION_CREDENTIALS = '/path/to/service-account-key.json';\nprocess.env.GOOGLE_CLOUD_PROJECT = 'your-project-id';\n```\n\n## Initialization\n\n### Basic Client Initialization\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n\n// Uses GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_CLOUD_PROJECT env vars\nconst bigquery = new BigQuery();\n```\n\n### Client with Explicit Project ID\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n\nconst bigquery = new BigQuery({\n  projectId: 'your-project-id'\n});\n```\n\n### Client with Explicit Credentials\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n\nconst bigquery = new BigQuery({\n  projectId: 'your-project-id',\n  keyFilename: '/path/to/service-account-key.json'\n});\n```\n\n### Client with Location\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\n\nconst bigquery = new BigQuery({\n  projectId: 'your-project-id',\n  location: 'US' // or 'EU', 'us-central1', etc.\n});\n```\n\n## Working with Datasets\n\n### Create a Dataset\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createDataset() {\n  const datasetId = 'my_new_dataset';\n\n  const [dataset] = await bigquery.createDataset(datasetId);\n  console.log(`Dataset ${dataset.id} created.`);\n}\n\ncreateDataset();\n```\n\n### Create Dataset with Location\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createDatasetWithLocation() {\n  const datasetId = 'my_new_dataset';\n\n  const options = {\n    location: 'US'\n  };\n\n  const [dataset] = await bigquery.createDataset(datasetId, options);\n  console.log(`Dataset ${dataset.id} created in ${dataset.location}.`);\n}\n\ncreateDatasetWithLocation();\n```\n\n### List Datasets\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function listDatasets() {\n  const [datasets] = await bigquery.getDatasets();\n\n  console.log('Datasets:');\n  datasets.forEach(dataset => console.log(dataset.id));\n}\n\nlistDatasets();\n```\n\n### Get Dataset Reference\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nconst dataset = bigquery.dataset('my_dataset');\n```\n\n### Check if Dataset Exists\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function datasetExists() {\n  const dataset = bigquery.dataset('my_dataset');\n  const [exists] = await dataset.exists();\n  console.log(`Dataset exists: ${exists}`);\n}\n\ndatasetExists();\n```\n\n### Delete a Dataset\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function deleteDataset() {\n  const datasetId = 'my_dataset';\n\n  await bigquery.dataset(datasetId).delete({force: true}); // force deletes all tables\n  console.log(`Dataset ${datasetId} deleted.`);\n}\n\ndeleteDataset();\n```\n\n## Working with Tables\n\n### Create a Table\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createTable() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const schema = [\n    {name: 'name', type: 'STRING', mode: 'REQUIRED'},\n    {name: 'age', type: 'INTEGER', mode: 'NULLABLE'},\n    {name: 'email', type: 'STRING', mode: 'NULLABLE'}\n  ];\n\n  const [table] = await bigquery\n    .dataset(datasetId)\n    .createTable(tableId, {schema: schema});\n\n  console.log(`Table ${table.id} created.`);\n}\n\ncreateTable();\n```\n\n### Create Table with Advanced Schema\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createTableWithAdvancedSchema() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_advanced_table';\n\n  const schema = [\n    {name: 'id', type: 'INTEGER', mode: 'REQUIRED'},\n    {name: 'name', type: 'STRING', mode: 'REQUIRED'},\n    {name: 'timestamp', type: 'TIMESTAMP', mode: 'REQUIRED'},\n    {name: 'scores', type: 'FLOAT', mode: 'REPEATED'}, // Array field\n    {\n      name: 'address',\n      type: 'RECORD', // Nested/struct field\n      mode: 'NULLABLE',\n      fields: [\n        {name: 'street', type: 'STRING'},\n        {name: 'city', type: 'STRING'},\n        {name: 'zipcode', type: 'STRING'}\n      ]\n    }\n  ];\n\n  const options = {\n    schema: schema,\n    location: 'US',\n    timePartitioning: {\n      type: 'DAY',\n      field: 'timestamp'\n    }\n  };\n\n  const [table] = await bigquery\n    .dataset(datasetId)\n    .createTable(tableId, options);\n\n  console.log(`Table ${table.id} created with partitioning.`);\n}\n\ncreateTableWithAdvancedSchema();\n```\n\n### List Tables\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function listTables() {\n  const datasetId = 'my_dataset';\n\n  const [tables] = await bigquery.dataset(datasetId).getTables();\n\n  console.log('Tables:');\n  tables.forEach(table => console.log(table.id));\n}\n\nlistTables();\n```\n\n### Get Table Metadata\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function getTableMetadata() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const table = bigquery.dataset(datasetId).table(tableId);\n  const [metadata] = await table.getMetadata();\n\n  console.log('Table metadata:');\n  console.log(`Schema: ${JSON.stringify(metadata.schema.fields)}`);\n  console.log(`Num rows: ${metadata.numRows}`);\n  console.log(`Num bytes: ${metadata.numBytes}`);\n  console.log(`Created: ${metadata.creationTime}`);\n}\n\ngetTableMetadata();\n```\n\n### Get Table Reference\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nconst table = bigquery.dataset('my_dataset').table('my_table');\n```\n\n### Check if Table Exists\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function tableExists() {\n  const table = bigquery.dataset('my_dataset').table('my_table');\n  const [exists] = await table.exists();\n  console.log(`Table exists: ${exists}`);\n}\n\ntableExists();\n```\n\n### Delete a Table\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function deleteTable() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  await bigquery.dataset(datasetId).table(tableId).delete();\n  console.log(`Table ${tableId} deleted.`);\n}\n\ndeleteTable();\n```\n\n### Copy a Table\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function copyTable() {\n  const srcDatasetId = 'my_dataset';\n  const srcTableId = 'my_source_table';\n  const destDatasetId = 'my_dataset';\n  const destTableId = 'my_destination_table';\n\n  const srcTable = bigquery.dataset(srcDatasetId).table(srcTableId);\n  const destTable = bigquery.dataset(destDatasetId).table(destTableId);\n\n  const [job] = await srcTable.copy(destTable);\n\n  console.log(`Job ${job.id} completed. Table copied.`);\n}\n\ncopyTable();\n```\n\n## Querying Data\n\n### Simple Query\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryData() {\n  const query = `\n    SELECT name, age\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE age > 25\n    ORDER BY age DESC\n    LIMIT 10\n  `;\n\n  const [rows] = await bigquery.query(query);\n\n  console.log('Rows:');\n  rows.forEach(row => console.log(`${row.name}: ${row.age}`));\n}\n\nqueryData();\n```\n\n### Query with Location\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithLocation() {\n  const query = 'SELECT name FROM `my-project.my_dataset.my_table` LIMIT 10';\n\n  const options = {\n    query: query,\n    location: 'US'\n  };\n\n  const [rows] = await bigquery.query(options);\n\n  rows.forEach(row => console.log(row.name));\n}\n\nqueryWithLocation();\n```\n\n### Query Public Dataset\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryPublicDataset() {\n  const query = `\n    SELECT name, SUM(number) as total\n    FROM \\`bigquery-public-data.usa_names.usa_1910_2013\\`\n    WHERE state = 'TX'\n    GROUP BY name, state\n    ORDER BY total DESC\n    LIMIT 10\n  `;\n\n  const [rows] = await bigquery.query(query);\n\n  console.log('Top 10 names in Texas:');\n  rows.forEach(row => console.log(`${row.name}: ${row.total}`));\n}\n\nqueryPublicDataset();\n```\n\n### Query with Parameters (Parameterized Query)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithParameters() {\n  const query = `\n    SELECT name, age\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE age > @min_age\n      AND name LIKE @name_pattern\n    LIMIT @limit\n  `;\n\n  const options = {\n    query: query,\n    params: {\n      min_age: 25,\n      name_pattern: 'John%',\n      limit: 10\n    }\n  };\n\n  const [rows] = await bigquery.query(options);\n\n  rows.forEach(row => console.log(`${row.name}: ${row.age}`));\n}\n\nqueryWithParameters();\n```\n\n### Query with Typed Parameters\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithTypedParameters() {\n  const query = `\n    SELECT name, timestamp\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE timestamp > @start_date\n      AND status IN UNNEST(@statuses)\n  `;\n\n  const options = {\n    query: query,\n    params: {\n      start_date: '2024-01-01',\n      statuses: ['active', 'pending']\n    },\n    types: {\n      start_date: 'DATE',\n      statuses: ['STRING']\n    }\n  };\n\n  const [rows] = await bigquery.query(options);\n\n  rows.forEach(row => console.log(row));\n}\n\nqueryWithTypedParameters();\n```\n\n### Query with Job Configuration\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithJobConfig() {\n  const query = 'SELECT * FROM `my-project.my_dataset.my_table` LIMIT 100';\n\n  const options = {\n    query: query,\n    location: 'US',\n    useLegacySql: false, // Use Standard SQL (default)\n    useQueryCache: true,\n    maximumBytesBilled: '1000000' // Set query cost limit\n  };\n\n  const [job] = await bigquery.createQueryJob(options);\n  console.log(`Job ${job.id} started.`);\n\n  const [rows] = await job.getQueryResults();\n  console.log(`Rows: ${rows.length}`);\n}\n\nqueryWithJobConfig();\n```\n\n### Dry Run Query (Estimate Query Cost)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function dryRunQuery() {\n  const query = 'SELECT * FROM `my-project.my_dataset.my_table`';\n\n  const options = {\n    query: query,\n    dryRun: true\n  };\n\n  const [job] = await bigquery.createQueryJob(options);\n\n  console.log('Query would process:');\n  console.log(`${job.metadata.statistics.totalBytesProcessed} bytes`);\n}\n\ndryRunQuery();\n```\n\n### Check Query Job Status\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function checkJobStatus() {\n  const query = 'SELECT * FROM `my-project.my_dataset.large_table`';\n\n  const [job] = await bigquery.createQueryJob({query: query});\n\n  console.log(`Job ${job.id} started.`);\n\n  // Wait for job to complete\n  const [rows] = await job.getQueryResults();\n\n  // Get job metadata\n  const [metadata] = await job.getMetadata();\n\n  console.log('Job statistics:');\n  console.log(`State: ${metadata.status.state}`);\n  console.log(`Bytes processed: ${metadata.statistics.totalBytesProcessed}`);\n  console.log(`Rows: ${rows.length}`);\n}\n\ncheckJobStatus();\n```\n\n## Inserting Data\n\n### Streaming Insert (Single Row)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function insertSingleRow() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const row = {\n    name: 'John Doe',\n    age: 30,\n    email: 'john@example.com'\n  };\n\n  await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .insert(row);\n\n  console.log('Row inserted successfully.');\n}\n\ninsertSingleRow();\n```\n\n### Streaming Insert (Multiple Rows)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function insertMultipleRows() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const rows = [\n    {name: 'Tom Smith', age: 28, email: 'tom@example.com'},\n    {name: 'Jane Doe', age: 32, email: 'jane@example.com'},\n    {name: 'Bob Johnson', age: 45, email: 'bob@example.com'}\n  ];\n\n  await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .insert(rows);\n\n  console.log(`Inserted ${rows.length} rows successfully.`);\n}\n\ninsertMultipleRows();\n```\n\n### Streaming Insert with Options\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function insertWithOptions() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const rows = [\n    {name: 'Alice', age: 25, email: 'alice@example.com'},\n    {name: 'Charlie', age: 35, email: 'charlie@example.com'}\n  ];\n\n  const options = {\n    skipInvalidRows: true, // Skip rows with errors\n    ignoreUnknownValues: true, // Ignore fields not in schema\n    raw: false // Use field names, not raw API format\n  };\n\n  await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .insert(rows, options);\n\n  console.log('Rows inserted with options.');\n}\n\ninsertWithOptions();\n```\n\n### Streaming Insert with Error Handling\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function insertWithErrorHandling() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const rows = [\n    {name: 'Valid User', age: 30, email: 'valid@example.com'},\n    {name: 'Invalid User', age: 'not a number', email: 'invalid@example.com'}\n  ];\n\n  try {\n    await bigquery\n      .dataset(datasetId)\n      .table(tableId)\n      .insert(rows);\n\n    console.log('All rows inserted successfully.');\n  } catch (error) {\n    if (error.name === 'PartialFailureError') {\n      console.error('Some rows failed to insert:');\n      error.errors.forEach((err, index) => {\n        console.error(`Row ${index}:`, err.errors);\n      });\n    } else {\n      console.error('Insert error:', error);\n    }\n  }\n}\n\ninsertWithErrorHandling();\n```\n\n## Loading Data from Files\n\n### Load Data from Local CSV File\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function loadCSVFromFile() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n  const filename = '/path/to/file.csv';\n\n  const metadata = {\n    sourceFormat: 'CSV',\n    skipLeadingRows: 1, // Skip header row\n    autodetect: true, // Auto-detect schema\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .load(filename, metadata);\n\n  console.log(`Job ${job.id} completed. Data loaded.`);\n}\n\nloadCSVFromFile();\n```\n\n### Load Data from Cloud Storage (CSV)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function loadCSVFromGCS() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const metadata = {\n    sourceFormat: 'CSV',\n    skipLeadingRows: 1,\n    schema: {\n      fields: [\n        {name: 'name', type: 'STRING'},\n        {name: 'age', type: 'INTEGER'},\n        {name: 'email', type: 'STRING'}\n      ]\n    },\n    location: 'US',\n    writeDisposition: 'WRITE_TRUNCATE' // Overwrite table\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .load('gs://my-bucket/data.csv', metadata);\n\n  console.log(`Job ${job.id} completed.`);\n\n  const errors = job.status.errors;\n  if (errors && errors.length > 0) {\n    throw errors;\n  }\n}\n\nloadCSVFromGCS();\n```\n\n### Load Data from Cloud Storage (JSON)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function loadJSONFromGCS() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const metadata = {\n    sourceFormat: 'NEWLINE_DELIMITED_JSON',\n    autodetect: true,\n    location: 'US',\n    writeDisposition: 'WRITE_APPEND' // Append to table\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .load('gs://my-bucket/data.json', metadata);\n\n  console.log(`Job ${job.id} completed. JSON data loaded.`);\n}\n\nloadJSONFromGCS();\n```\n\n### Load Data from Multiple Files\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function loadFromMultipleFiles() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const metadata = {\n    sourceFormat: 'CSV',\n    skipLeadingRows: 1,\n    autodetect: true,\n    location: 'US'\n  };\n\n  const sourceUris = [\n    'gs://my-bucket/data1.csv',\n    'gs://my-bucket/data2.csv',\n    'gs://my-bucket/data3.csv'\n  ];\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .load(sourceUris, metadata);\n\n  console.log(`Job ${job.id} completed. Multiple files loaded.`);\n}\n\nloadFromMultipleFiles();\n```\n\n### Load Data from Cloud Storage (Parquet)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function loadParquetFromGCS() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const metadata = {\n    sourceFormat: 'PARQUET',\n    location: 'US',\n    writeDisposition: 'WRITE_TRUNCATE'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .load('gs://my-bucket/data.parquet', metadata);\n\n  console.log('Parquet data loaded successfully.');\n}\n\nloadParquetFromGCS();\n```\n\n### Load with createLoadJob\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createLoadJobExample() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const metadata = {\n    sourceFormat: 'CSV',\n    skipLeadingRows: 1,\n    schema: {\n      fields: [\n        {name: 'id', type: 'INTEGER'},\n        {name: 'name', type: 'STRING'},\n        {name: 'value', type: 'FLOAT'}\n      ]\n    },\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .createLoadJob('gs://my-bucket/file.csv', metadata);\n\n  console.log(`Load job ${job.id} started.`);\n\n  // Wait for job to complete\n  const [completedJob] = await job.promise();\n\n  console.log(`Job ${completedJob.id} completed.`);\n}\n\ncreateLoadJobExample();\n```\n\n## Exporting Data\n\n### Export Table to Cloud Storage (CSV)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst {Storage} = require('@google-cloud/storage');\n\nconst bigquery = new BigQuery();\nconst storage = new Storage();\n\nasync function exportTableToGCS() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n  const bucketName = 'my-bucket';\n  const filename = 'export.csv';\n\n  const destination = storage.bucket(bucketName).file(filename);\n\n  const options = {\n    format: 'CSV',\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .extract(destination, options);\n\n  console.log(`Job ${job.id} completed. Table exported to ${filename}.`);\n}\n\nexportTableToGCS();\n```\n\n### Export Table to Cloud Storage (JSON)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst {Storage} = require('@google-cloud/storage');\n\nconst bigquery = new BigQuery();\nconst storage = new Storage();\n\nasync function exportTableToJSON() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n  const bucketName = 'my-bucket';\n  const filename = 'export.json';\n\n  const destination = storage.bucket(bucketName).file(filename);\n\n  const options = {\n    format: 'JSON',\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .extract(destination, options);\n\n  console.log('Table exported to JSON.');\n}\n\nexportTableToJSON();\n```\n\n### Export Table with Compression\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst {Storage} = require('@google-cloud/storage');\n\nconst bigquery = new BigQuery();\nconst storage = new Storage();\n\nasync function exportTableCompressed() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n  const bucketName = 'my-bucket';\n  const filename = 'export.csv.gz';\n\n  const destination = storage.bucket(bucketName).file(filename);\n\n  const options = {\n    format: 'CSV',\n    gzip: true,\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .extract(destination, options);\n\n  console.log('Table exported with gzip compression.');\n}\n\nexportTableCompressed();\n```\n\n### Export to Multiple Files\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst {Storage} = require('@google-cloud/storage');\n\nconst bigquery = new BigQuery();\nconst storage = new Storage();\n\nasync function exportToMultipleFiles() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_large_table';\n  const bucketName = 'my-bucket';\n\n  // Use wildcard to split into multiple files\n  const destination = storage.bucket(bucketName).file('export-*.csv');\n\n  const options = {\n    format: 'CSV',\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .extract(destination, options);\n\n  console.log('Table exported to multiple files.');\n}\n\nexportToMultipleFiles();\n```\n\n### Export with createExtractJob\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst {Storage} = require('@google-cloud/storage');\n\nconst bigquery = new BigQuery();\nconst storage = new Storage();\n\nasync function createExtractJobExample() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n  const bucketName = 'my-bucket';\n  const filename = 'extract.csv';\n\n  const destination = storage.bucket(bucketName).file(filename);\n\n  const options = {\n    format: 'CSV',\n    printHeader: true,\n    location: 'US'\n  };\n\n  const [job] = await bigquery\n    .dataset(datasetId)\n    .table(tableId)\n    .createExtractJob(destination, options);\n\n  console.log(`Extract job ${job.id} started.`);\n\n  const [completedJob] = await job.promise();\n  console.log(`Job ${completedJob.id} completed.`);\n}\n\ncreateExtractJobExample();\n```\n\n## DML Operations (INSERT, UPDATE, DELETE)\n\n### INSERT with DML\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function insertWithDML() {\n  const query = `\n    INSERT INTO \\`my-project.my_dataset.my_table\\` (name, age, email)\n    VALUES\n      ('Alice', 25, 'alice@example.com'),\n      ('Bob', 30, 'bob@example.com'),\n      ('Charlie', 35, 'charlie@example.com')\n  `;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Rows inserted via DML.');\n}\n\ninsertWithDML();\n```\n\n### UPDATE with DML\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function updateWithDML() {\n  const query = `\n    UPDATE \\`my-project.my_dataset.my_table\\`\n    SET age = age + 1\n    WHERE name = 'Alice'\n  `;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Rows updated via DML.');\n}\n\nupdateWithDML();\n```\n\n### DELETE with DML\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function deleteWithDML() {\n  const query = `\n    DELETE FROM \\`my-project.my_dataset.my_table\\`\n    WHERE age < 18\n  `;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Rows deleted via DML.');\n}\n\ndeleteWithDML();\n```\n\n### MERGE (Upsert) with DML\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function mergeWithDML() {\n  const query = `\n    MERGE \\`my-project.my_dataset.target_table\\` T\n    USING \\`my-project.my_dataset.source_table\\` S\n    ON T.id = S.id\n    WHEN MATCHED THEN\n      UPDATE SET T.name = S.name, T.age = S.age\n    WHEN NOT MATCHED THEN\n      INSERT (id, name, age) VALUES (S.id, S.name, S.age)\n  `;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Merge operation completed.');\n}\n\nmergeWithDML();\n```\n\n### TRUNCATE Table\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function truncateTable() {\n  const query = `TRUNCATE TABLE \\`my-project.my_dataset.my_table\\``;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Table truncated.');\n}\n\ntruncateTable();\n```\n\n## Advanced Query Patterns\n\n### Create Table As Select (CTAS)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createTableAsSelect() {\n  const query = `\n    CREATE OR REPLACE TABLE \\`my-project.my_dataset.new_table\\` AS\n    SELECT name, age\n    FROM \\`my-project.my_dataset.source_table\\`\n    WHERE age > 25\n  `;\n\n  const [job] = await bigquery.createQueryJob({\n    query: query,\n    location: 'US'\n  });\n\n  await job.getQueryResults();\n  console.log('Table created from query.');\n}\n\ncreateTableAsSelect();\n```\n\n### Query with Common Table Expressions (CTEs)\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithCTE() {\n  const query = `\n    WITH filtered_data AS (\n      SELECT name, age, email\n      FROM \\`my-project.my_dataset.my_table\\`\n      WHERE age > 25\n    ),\n    aggregated_data AS (\n      SELECT COUNT(*) as total\n      FROM filtered_data\n    )\n    SELECT * FROM aggregated_data\n  `;\n\n  const [rows] = await bigquery.query(query);\n\n  rows.forEach(row => console.log(row));\n}\n\nqueryWithCTE();\n```\n\n### Query with Window Functions\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithWindowFunctions() {\n  const query = `\n    SELECT\n      name,\n      age,\n      ROW_NUMBER() OVER (ORDER BY age DESC) as rank,\n      AVG(age) OVER () as avg_age\n    FROM \\`my-project.my_dataset.my_table\\`\n    ORDER BY rank\n    LIMIT 10\n  `;\n\n  const [rows] = await bigquery.query(query);\n\n  rows.forEach(row => {\n    console.log(`${row.rank}. ${row.name} (${row.age}) - Avg: ${row.avg_age}`);\n  });\n}\n\nqueryWithWindowFunctions();\n```\n\n### Query with Arrays and Structs\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryArraysAndStructs() {\n  const query = `\n    SELECT\n      name,\n      scores,\n      ARRAY_LENGTH(scores) as num_scores,\n      address.city,\n      address.zipcode\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE 90 IN UNNEST(scores)\n  `;\n\n  const [rows] = await bigquery.query(query);\n\n  rows.forEach(row => console.log(row));\n}\n\nqueryArraysAndStructs();\n```\n\n## Pagination and Iterating Results\n\n### Paginate Query Results\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function paginateResults() {\n  const query = 'SELECT * FROM `my-project.my_dataset.large_table`';\n\n  const options = {\n    query: query,\n    maxResults: 100 // Page size\n  };\n\n  const [job] = await bigquery.createQueryJob(options);\n\n  let pageToken = null;\n  let pageCount = 0;\n\n  do {\n    const [rows, nextQuery, apiResponse] = await job.getQueryResults({\n      pageToken: pageToken,\n      maxResults: 100\n    });\n\n    pageCount++;\n    console.log(`Page ${pageCount}: ${rows.length} rows`);\n\n    rows.forEach(row => {\n      // Process each row\n      console.log(row);\n    });\n\n    pageToken = apiResponse.pageToken;\n  } while (pageToken);\n\n  console.log(`Total pages: ${pageCount}`);\n}\n\npaginateResults();\n```\n\n### Stream Query Results\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function streamQueryResults() {\n  const query = 'SELECT * FROM `my-project.my_dataset.large_table`';\n\n  const [job] = await bigquery.createQueryJob({query: query});\n\n  return new Promise((resolve, reject) => {\n    let rowCount = 0;\n\n    job.getQueryResultsStream()\n      .on('data', row => {\n        rowCount++;\n        console.log(row);\n      })\n      .on('error', reject)\n      .on('end', () => {\n        console.log(`Processed ${rowCount} rows`);\n        resolve();\n      });\n  });\n}\n\nstreamQueryResults();\n```\n\n## Working with Views\n\n### Create a View\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function createView() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_view';\n\n  const query = `\n    SELECT name, age\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE age > 25\n  `;\n\n  const options = {\n    view: query,\n    location: 'US'\n  };\n\n  const [view] = await bigquery\n    .dataset(datasetId)\n    .createTable(tableId, options);\n\n  console.log(`View ${view.id} created.`);\n}\n\ncreateView();\n```\n\n### Update a View\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function updateView() {\n  const datasetId = 'my_dataset';\n  const viewId = 'my_view';\n\n  const newQuery = `\n    SELECT name, age, email\n    FROM \\`my-project.my_dataset.my_table\\`\n    WHERE age > 30\n  `;\n\n  const table = bigquery.dataset(datasetId).table(viewId);\n\n  await table.setMetadata({\n    view: newQuery\n  });\n\n  console.log('View updated.');\n}\n\nupdateView();\n```\n\n## Error Handling\n\n### Complete Error Handling Example\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function queryWithErrorHandling() {\n  const query = 'SELECT * FROM `my-project.my_dataset.my_table` LIMIT 10';\n\n  try {\n    const [rows] = await bigquery.query({\n      query: query,\n      location: 'US'\n    });\n\n    console.log(`Query returned ${rows.length} rows`);\n    rows.forEach(row => console.log(row));\n\n  } catch (error) {\n    console.error('Error occurred:');\n    console.error(`Message: ${error.message}`);\n\n    if (error.code) {\n      console.error(`Error code: ${error.code}`);\n    }\n\n    if (error.errors) {\n      console.error('Detailed errors:');\n      error.errors.forEach(err => console.error(err));\n    }\n  }\n}\n\nqueryWithErrorHandling();\n```\n\n### Handle Partial Insert Errors\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function handlePartialInsertErrors() {\n  const datasetId = 'my_dataset';\n  const tableId = 'my_table';\n\n  const rows = [\n    {name: 'Valid', age: 25},\n    {name: 'Invalid', age: 'not a number'},\n    {name: 'Another Valid', age: 30}\n  ];\n\n  try {\n    await bigquery\n      .dataset(datasetId)\n      .table(tableId)\n      .insert(rows);\n\n    console.log('All rows inserted successfully.');\n  } catch (error) {\n    if (error.name === 'PartialFailureError') {\n      console.log('Some rows were inserted, but some failed:');\n\n      error.errors.forEach((rowError, index) => {\n        console.log(`Row ${index} errors:`);\n        rowError.errors.forEach(err => {\n          console.log(`  - ${err.reason}: ${err.message}`);\n        });\n      });\n    } else {\n      console.error('Complete failure:', error.message);\n    }\n  }\n}\n\nhandlePartialInsertErrors();\n```\n\n## Working with Jobs\n\n### List Recent Jobs\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function listJobs() {\n  const [jobs] = await bigquery.getJobs({\n    maxResults: 10,\n    allUsers: false\n  });\n\n  console.log('Recent jobs:');\n  jobs.forEach(job => {\n    console.log(`${job.id} - ${job.metadata.status.state}`);\n  });\n}\n\nlistJobs();\n```\n\n### Get Job Details\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function getJobDetails(jobId) {\n  const job = bigquery.job(jobId);\n  const [metadata] = await job.getMetadata();\n\n  console.log('Job details:');\n  console.log(`ID: ${metadata.id}`);\n  console.log(`State: ${metadata.status.state}`);\n  console.log(`Created: ${metadata.statistics.creationTime}`);\n  console.log(`Started: ${metadata.statistics.startTime}`);\n  console.log(`Ended: ${metadata.statistics.endTime}`);\n\n  if (metadata.statistics.query) {\n    console.log(`Bytes processed: ${metadata.statistics.query.totalBytesProcessed}`);\n  }\n}\n\ngetJobDetails('your-job-id');\n```\n\n### Cancel a Job\n\n```javascript\nconst {BigQuery} = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function cancelJob(jobId) {\n  const job = bigquery.job(jobId);\n\n  await job.cancel();\n  console.log(`Job ${jobId} cancelled.`);\n}\n\ncancelJob('your-job-id');\n```\n\n## Important Notes\n\n### Streaming Insert Limitations\n\n- Streaming inserts are available immediately for querying but may take up to 90 minutes to become available for copy, export, or DML operations\n- Tables with data in the streaming buffer cannot be updated or deleted using UPDATE/DELETE DML statements\n- Use batch loading for large data volumes to reduce costs\n\n### DML Quotas\n\n- Maximum 1,000 DML statements per table per day\n- Use batch operations when possible to stay within quota limits\n\n### Query Costs\n\n- Queries are billed based on bytes processed\n- Use `dryRun: true` to estimate query costs before running\n- Use partitioned tables and clustering to reduce query costs\n- Set `maximumBytesBilled` to prevent accidentally expensive queries\n\n### Data Types\n\nAvailable BigQuery data types:\n- **Numeric**: INTEGER (INT64), NUMERIC, BIGNUMERIC, FLOAT (FLOAT64)\n- **String**: STRING, BYTES\n- **Date/Time**: DATE, DATETIME, TIME, TIMESTAMP\n- **Boolean**: BOOLEAN (BOOL)\n- **Complex**: ARRAY, STRUCT (RECORD), GEOGRAPHY, JSON\n\n### Best Practices\n\n- Always specify location for datasets and queries to avoid cross-region data transfer costs\n- Use parameterized queries to improve query caching and prevent SQL injection\n- Use batch loading instead of streaming for large data volumes\n- Enable query cache when possible to reduce costs\n- Use partitioned and clustered tables for better query performance\n- Set timeouts and cost limits for queries in production\n- Handle errors gracefully, especially for streaming inserts\n\n## Useful Links\n\n- Official Documentation: https://cloud.google.com/bigquery/docs\n- Node.js Client Reference: https://cloud.google.com/nodejs/docs/reference/bigquery/latest\n- BigQuery Pricing: https://cloud.google.com/bigquery/pricing\n- SQL Reference: https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax\n- Quotas and Limits: https://cloud.google.com/bigquery/quotas\n"
  },
  {
    "path": "content/google/docs/bigquery/python/DOC.md",
    "content": "---\nname: bigquery\ndescription: \"Google Cloud BigQuery Python client for queries, table loads, and dataset setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.40.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,bigquery,google-cloud,gcp,sql,analytics,data-warehouse,python\"\n---\n\n# google-cloud-bigquery Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-bigquery` package with `from google.cloud import bigquery`, and authenticate with Google Cloud Application Default Credentials (ADC).\n\nFor predictable behavior, pass `project=` explicitly and set `location=` when your datasets or jobs are region-specific. BigQuery client code should not rely on API keys.\n\n## Install\n\nPin the package version you want to reason about:\n\n```bash\npython -m pip install \"google-cloud-bigquery==3.40.1\"\n```\n\nIf you want pandas helpers such as `to_dataframe()` and `load_table_from_dataframe()`:\n\n```bash\npython -m pip install \"google-cloud-bigquery[pandas]==3.40.1\"\n```\n\nOther common package managers:\n\n```bash\nuv add \"google-cloud-bigquery==3.40.1\"\npoetry add \"google-cloud-bigquery==3.40.1\"\n```\n\n## Authentication And Setup\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nPractical setup notes:\n\n- Use ADC for local development, CI, and deployed Google Cloud workloads when possible.\n- `GOOGLE_CLOUD_PROJECT` helps when project discovery is ambiguous or missing.\n- Pick a `location` such as `US`, `EU`, or a regional location that matches the datasets and jobs you intend to use.\n\n## Initialize A Client\n\nTypical client initialization:\n\n```python\nimport os\n\nfrom google.cloud import bigquery\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = bigquery.Client(\n    project=project_id,\n    location=\"US\",\n)\n```\n\nExplicit service account credentials:\n\n```python\nfrom google.cloud import bigquery\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = bigquery.Client(\n    project=\"your-project-id\",\n    credentials=credentials,\n    location=\"US\",\n)\n```\n\n## Common Workflows\n\n### Run A Parameterized Query\n\nUse `QueryJobConfig` and query parameters instead of string interpolation.\n\n```python\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\nsql = \"\"\"\nSELECT name, SUM(number) AS total\nFROM `bigquery-public-data.usa_names.usa_1910_2013`\nWHERE state = @state\nGROUP BY name\nORDER BY total DESC\nLIMIT @limit\n\"\"\"\n\njob_config = bigquery.QueryJobConfig(\n    query_parameters=[\n        bigquery.ScalarQueryParameter(\"state\", \"STRING\", \"TX\"),\n        bigquery.ScalarQueryParameter(\"limit\", \"INT64\", 10),\n    ]\n)\n\nquery_job = client.query(sql, job_config=job_config)\n\nfor row in query_job.result():\n    print(row.name, row.total)\n```\n\nBigQuery uses standard SQL by default. Only set `use_legacy_sql=True` when you intentionally need legacy SQL behavior.\n\n### Read Query Results Into A DataFrame\n\nInstall the pandas extra first, then convert the result iterator:\n\n```python\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\nsql = \"\"\"\nSELECT name, state, year, number\nFROM `bigquery-public-data.usa_names.usa_1910_2013`\nWHERE state = 'CA'\nLIMIT 100\n\"\"\"\n\nrows = client.query(sql).result()\ndf = rows.to_dataframe()\n\nprint(df.head())\n```\n\n### Create A Dataset And Table\n\nCreate the dataset in the same location you plan to query and load.\n\n```python\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\ndataset = bigquery.Dataset(\"your-project-id.analytics\")\ndataset.location = \"US\"\nclient.create_dataset(dataset)\n\nschema = [\n    bigquery.SchemaField(\"user_id\", \"STRING\", mode=\"REQUIRED\"),\n    bigquery.SchemaField(\"amount_cents\", \"INT64\"),\n    bigquery.SchemaField(\"event_ts\", \"TIMESTAMP\"),\n]\n\ntable = bigquery.Table(\"your-project-id.analytics.events\", schema=schema)\nclient.create_table(table)\n```\n\n### Load A CSV File From Cloud Storage\n\nUse this for normal batch ingestion from `gs://...` objects.\n\n```python\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\njob_config = bigquery.LoadJobConfig(\n    source_format=bigquery.SourceFormat.CSV,\n    skip_leading_rows=1,\n    autodetect=True,\n    write_disposition=bigquery.WriteDisposition.WRITE_APPEND,\n)\n\nload_job = client.load_table_from_uri(\n    \"gs://my-bucket/orders.csv\",\n    \"your-project-id.analytics.orders\",\n    job_config=job_config,\n)\n\nload_job.result()\ntable = client.get_table(\"your-project-id.analytics.orders\")\nprint(table.num_rows)\n```\n\n### Load A pandas DataFrame\n\nUse this when your data already exists in memory as a DataFrame.\n\n```python\nimport pandas as pd\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\ndf = pd.DataFrame(\n    [\n        {\"user_id\": \"u_1\", \"amount_cents\": 4999},\n        {\"user_id\": \"u_2\", \"amount_cents\": 1299},\n    ]\n)\n\njob_config = bigquery.LoadJobConfig(\n    write_disposition=bigquery.WriteDisposition.WRITE_TRUNCATE,\n)\n\nload_job = client.load_table_from_dataframe(\n    df,\n    \"your-project-id.analytics.daily_revenue\",\n    job_config=job_config,\n)\n\nload_job.result()\n```\n\n### Insert JSON Rows\n\nUse `insert_rows_json()` when you need row-oriented inserts from application code and you want per-row error details.\n\n```python\nfrom google.cloud import bigquery\n\nclient = bigquery.Client(project=\"your-project-id\", location=\"US\")\n\nrows = [\n    {\n        \"user_id\": \"u_1\",\n        \"amount_cents\": 4999,\n        \"event_ts\": \"2026-03-12T12:00:00Z\",\n    },\n    {\n        \"user_id\": \"u_2\",\n        \"amount_cents\": 1299,\n        \"event_ts\": \"2026-03-12T12:05:00Z\",\n    },\n]\n\nerrors = client.insert_rows_json(\n    \"your-project-id.analytics.events\",\n    rows,\n)\n\nif errors:\n    raise RuntimeError(errors)\n```\n\n## Important Notes\n\n### Authentication Is Credential-Based, Not API-Key-Based\n\nFor normal Python client usage, use ADC or explicit service account credentials. Do not build BigQuery client initialization around API keys.\n\n### Project Discovery Can Be Missing\n\nIf your code runs in local scripts, CI, or mixed-cloud environments, do not assume the project ID will always be inferred. Pass `project=` explicitly when correctness matters.\n\n### Location Mismatches Cause Job Errors\n\nQueries, loads, and table operations must use the same BigQuery location as the datasets they touch. If your dataset is in `EU`, do not create the client or run the job with `location=\"US\"`.\n\n### Check Insert Errors Explicitly\n\n`insert_rows_json()` returns a list of row-level errors. Treat a non-empty return value as a failed write path.\n\n### Prefer Parameterized Queries\n\nUse `ScalarQueryParameter`, `ArrayQueryParameter`, and related query parameter helpers instead of building SQL with untrusted strings.\n\n## Version Notes\n\n- This guide targets `google-cloud-bigquery==3.40.1`.\n- The maintained BigQuery Python reference for the `latest` line and the PyPI package page both pointed to `3.40.1` when this guide was updated.\n- If you are upgrading older `2.x` code, check the official `3.0.0` migration guide before reusing deprecated patterns.\n\n## Official Source URLs\n\n- `https://cloud.google.com/python/docs/reference/bigquery/latest`\n- `https://cloud.google.com/python/docs/reference/bigquery/latest/google.cloud.bigquery.client.Client`\n- `https://cloud.google.com/python/docs/reference/bigquery/latest/3.0.0_migration_guide`\n- `https://cloud.google.com/python/docs/reference/bigquery/latest/changelog`\n- `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- `https://pypi.org/project/google-cloud-bigquery/`\n"
  },
  {
    "path": "content/google/docs/bigquery-connection/python/DOC.md",
    "content": "---\nname: bigquery-connection\ndescription: \"Google Cloud BigQuery Connection Python client for creating and managing external connections\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.20.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,bigquery,connection,gcp,cloud-sql,iam,federated-query,python\"\n---\n\n# Google Cloud BigQuery Connection Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-bigquery-connection` package with `from google.cloud import bigquery_connection_v1`, and authenticate with Application Default Credentials (ADC).\n\nThis client manages BigQuery connection resources. A connection is regional, has exactly one backend-specific configuration such as `cloud_resource` or `cloud_sql`, and is addressed as `projects/PROJECT_ID/locations/LOCATION/connections/CONNECTION_ID`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-bigquery-connection==1.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-bigquery-connection==1.20.0\"\npoetry add \"google-cloud-bigquery-connection==1.20.0\"\n```\n\nPyPI lists `1.20.0` as supporting Python 3.7 and later.\n\n## Authentication And Setup\n\nEnable the API once per project:\n\n```bash\ngcloud services enable bigqueryconnection.googleapis.com\n```\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport BIGQUERY_LOCATION=\"US\"\n```\n\nService account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport BIGQUERY_LOCATION=\"US\"\n```\n\nPractical setup notes:\n\n- Use ADC rather than API keys.\n- The package uses the BigQuery Connection API service `bigqueryconnection.googleapis.com`.\n- Connections are regional. Use a location such as `US`, `EU`, or a specific region that matches the connection type you are creating.\n- To manage connections, Google documents `roles/bigquery.connectionAdmin`. To use an existing connection in queries, Google documents `roles/bigquery.connectionUser`.\n\n## Initialize The Client\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nparent = client.common_location_path(project_id, location)\n```\n\nUse one reusable `ConnectionServiceClient` for normal application code instead of recreating it for every request.\n\n## Common Workflows\n\n### Create A Cloud Resource Connection\n\nCloud resource connections create a Google-managed service account. Grant that service account access to the target Google Cloud resource after creation.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nparent = client.common_location_path(project_id, location)\n\nconnection = bigquery_connection_v1.Connection(\n    friendly_name=\"analytics-gcs-connection\",\n    description=\"Used by BigQuery jobs that need Google Cloud resource access\",\n    cloud_resource=bigquery_connection_v1.CloudResourceProperties(),\n)\n\nrequest = bigquery_connection_v1.CreateConnectionRequest(\n    parent=parent,\n    connection_id=\"analytics_gcs_connection\",\n    connection=connection,\n)\n\ncreated = client.create_connection(request=request)\n\nprint(created.name)\nprint(created.cloud_resource.service_account_id)\n```\n\nTypical next step: grant `created.cloud_resource.service_account_id` the IAM role it needs on the bucket, object table source, or other Google Cloud resource.\n\n### Create A Cloud SQL Connection\n\nUse a Cloud SQL connection when BigQuery needs stored credentials for Cloud SQL federation. The instance ID is the Cloud SQL connection name in `PROJECT:REGION:INSTANCE` form.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1 as bq_connection\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\ncloud_sql = bq_connection.CloudSqlProperties(\n    instance_id=os.environ[\"CLOUD_SQL_INSTANCE_ID\"],\n    database=os.environ[\"CLOUD_SQL_DATABASE\"],\n    type_=bq_connection.CloudSqlProperties.DatabaseType.MYSQL,\n    credential=bq_connection.CloudSqlCredential(\n        username=os.environ[\"CLOUD_SQL_USERNAME\"],\n        password=os.environ[\"CLOUD_SQL_PASSWORD\"],\n    ),\n)\n\nclient = bq_connection.ConnectionServiceClient()\nparent = client.common_location_path(project_id, location)\n\nrequest = bq_connection.CreateConnectionRequest(\n    parent=parent,\n    connection_id=\"orders_mysql\",\n    connection=bq_connection.Connection(\n        friendly_name=\"orders-mysql\",\n        description=\"BigQuery federation into Cloud SQL for MySQL\",\n        cloud_sql=cloud_sql,\n    ),\n)\n\ncreated = client.create_connection(request=request)\nprint(created.name)\n```\n\nThe Python type docs expose `MYSQL` and `POSTGRES` as `CloudSqlProperties.DatabaseType` values. Keep database credentials in environment variables or a secret manager, not in source control.\n\n### List Connections In A Project And Location\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nparent = client.common_location_path(project_id, location)\n\nrequest = bigquery_connection_v1.ListConnectionsRequest(\n    parent=parent,\n    page_size=100,\n)\n\nfor connection in client.list_connections(request=request):\n    print(connection.name)\n    print(connection.friendly_name)\n    print(connection.has_credential)\n```\n\n`has_credential` is useful when you need to confirm whether a credential-backed connection such as Cloud SQL has stored credentials.\n\n### Get Connection Metadata\n\n`get_connection()` returns metadata, but Google’s samples explicitly note that credential secrets are not returned.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconnection_id = os.environ[\"BIGQUERY_CONNECTION_ID\"]\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nname = client.connection_path(project_id, location, connection_id)\n\nconnection = client.get_connection(name=name)\n\nprint(connection.name)\nprint(connection.friendly_name)\nprint(connection.description)\n\nif connection.cloud_sql:\n    print(connection.cloud_sql.instance_id)\n    print(connection.cloud_sql.database)\n```\n\n### Update Friendly Name Or Description\n\nUse a field mask so you only update the metadata you intend to change.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconnection_id = os.environ[\"BIGQUERY_CONNECTION_ID\"]\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nname = client.connection_path(project_id, location, connection_id)\n\nconnection = client.get_connection(name=name)\nconnection.friendly_name = \"analytics-prod\"\nconnection.description = \"Used by scheduled BigQuery jobs\"\n\nupdated = client.update_connection(\n    request=bigquery_connection_v1.UpdateConnectionRequest(\n        connection=connection,\n        update_mask=field_mask_pb2.FieldMask(\n            paths=[\"friendly_name\", \"description\"]\n        ),\n    )\n)\n\nprint(updated.name)\nprint(updated.friendly_name)\n```\n\nGoogle’s manage-connections guide warns that updating connection properties resets the credential. For Cloud SQL connections, do not modify backend properties casually; if you must change credential-bearing properties, be ready to set credentials again.\n\n### Inspect IAM Bindings On A Connection\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\nfrom google.iam.v1 import iam_policy_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconnection_id = os.environ[\"BIGQUERY_CONNECTION_ID\"]\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nresource = client.connection_path(project_id, location, connection_id)\n\npolicy = client.get_iam_policy(\n    request=iam_policy_pb2.GetIamPolicyRequest(resource=resource)\n)\n\nfor binding in policy.bindings:\n    print(binding.role, list(binding.members))\n```\n\nUse this to confirm which principals currently have `roles/bigquery.connectionUser` or `roles/bigquery.connectionAdmin` on the connection resource.\n\n### Delete A Connection\n\nDeleting a connection also deletes its associated credential.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_connection_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconnection_id = os.environ[\"BIGQUERY_CONNECTION_ID\"]\n\nclient = bigquery_connection_v1.ConnectionServiceClient()\nname = client.connection_path(project_id, location, connection_id)\n\nclient.delete_connection(name=name)\nprint(f\"Deleted {name}\")\n```\n\n## Common Pitfalls\n\n- Do not use API keys. This client is designed around ADC and IAM credentials.\n- Do not treat connections as global. Listing, getting, and creating all require the correct location.\n- `Connection` uses backend-specific fields such as `cloud_resource` and `cloud_sql`; set the one you actually need instead of trying to combine multiple backends in one connection.\n- `get_connection()` does not return stored credential secrets. If your code expects to read back a password, it is using the API incorrectly.\n- Google documents that updating connection properties resets credentials. Limit updates to `friendly_name` and `description` unless you intentionally want to change backend settings and re-supply credentials.\n- A Cloud resource connection is not usable by itself until you grant the generated service account access to the external Google Cloud resource.\n- BigQuery connection IAM is separate from access to the underlying system. A user may be allowed to use a connection but still fail if the connection’s service account lacks access to the target resource.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-bigquery-connection/\n- Python client reference: https://cloud.google.com/python/docs/reference/bigqueryconnection/latest\n- `ConnectionServiceClient` reference: https://cloud.google.com/python/docs/reference/bigqueryconnection/latest/google.cloud.bigquery_connection_v1.services.connection_service.ConnectionServiceClient\n- `Connection` type reference: https://cloud.google.com/python/docs/reference/bigqueryconnection/latest/google.cloud.bigquery_connection_v1.types.Connection\n- `CloudSqlProperties` type reference: https://cloud.google.com/python/docs/reference/bigqueryconnection/latest/google.cloud.bigquery_connection_v1.types.CloudSqlProperties\n- BigQuery connections overview: https://cloud.google.com/bigquery/docs/connections-api-intro\n- Manage connections: https://cloud.google.com/bigquery/docs/working-with-connections\n- Create a Cloud resource connection sample: https://docs.cloud.google.com/bigquery/docs/samples/bigqueryconnection-connectionservice-connection-create\n- Create a Cloud SQL connection sample: https://docs.cloud.google.com/bigquery/docs/samples/bigqueryconnection-create-connection\n- List connections sample: https://docs.cloud.google.com/bigquery/docs/samples/bigqueryconnection-connectionservice-connections-list\n- Get connection metadata sample: https://docs.cloud.google.com/bigquery/docs/samples/bigqueryconnection-connectionservice-connection-get\n"
  },
  {
    "path": "content/google/docs/bigquery-datatransfer/python/DOC.md",
    "content": "---\nname: bigquery-datatransfer\ndescription: \"Google Cloud BigQuery Data Transfer Service Python client for scheduled queries, managed transfers, and transfer run operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.21.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,bigquery,data-transfer,gcp,scheduled-query,cloud-storage,python\"\n---\n\n# google-cloud-bigquery-datatransfer Python Package Guide\n\n## What This Package Is\n\n`google-cloud-bigquery-datatransfer` is the official Python client for the BigQuery Data Transfer Service. Use it when your application needs to:\n\n- create scheduled queries\n- create recurring transfers from supported sources such as Cloud Storage\n- inspect transfer configs and transfer runs\n- start manual backfills for an existing transfer\n\nThe client does not move data out of BigQuery. It manages transfer configurations and runs that load data into BigQuery.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-bigquery-datatransfer==3.21.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-bigquery-datatransfer==3.21.0\"\npoetry add \"google-cloud-bigquery-datatransfer==3.21.0\"\n```\n\nUpstream package metadata currently lists Python `>=3.7`.\n\n## Authentication And Setup\n\nBefore using the client:\n\n- enable billing on the project\n- enable BigQuery and BigQuery Data Transfer Service\n- create the destination BigQuery dataset\n- configure Application Default Credentials (ADC)\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nPractical IAM guidance from the product docs:\n\n- Google recommends `roles/bigquery.admin` for users who create transfers because it includes the common BigQuery Data Transfer and dataset permissions.\n- Scheduled queries and dataset copies run using the transfer owner credentials unless you set `service_account_name`.\n- Most other data sources rely on the BigQuery Data Transfer Service agent to create jobs and write into the destination dataset.\n\n## Initialize A Client\n\nUse the explicit `bigquery_datatransfer_v1` namespace in new code:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_datatransfer_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = \"us\"\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n```\n\nIf you need to pass credentials explicitly:\n\n```python\nfrom google.cloud import bigquery_datatransfer_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient(credentials=credentials)\n```\n\n## Common Workflows\n\n### List Available Data Sources\n\nData source ids such as `scheduled_query` and `google_cloud_storage` are product-defined. Query them instead of guessing.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_datatransfer_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\n\nfor source in client.list_data_sources(parent=f\"projects/{project_id}\"):\n    print(source.data_source_id, source.display_name)\n```\n\n### Create A Scheduled Query\n\nThis is the most common automation workflow for BigQuery-native jobs.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_datatransfer_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndataset_id = \"analytics\"\nservice_account_name = \"scheduler@your-project-id.iam.gserviceaccount.com\"\n\nquery_string = \"\"\"\nSELECT\n  CURRENT_TIMESTAMP() AS current_time,\n  @run_time AS intended_run_time,\n  @run_date AS intended_run_date,\n  COUNT(*) AS row_count\nFROM `your-project-id.analytics.events`\n\"\"\"\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\n\ntransfer_config = bigquery_datatransfer_v1.TransferConfig(\n    destination_dataset_id=dataset_id,\n    display_name=\"Daily event summary\",\n    data_source_id=\"scheduled_query\",\n    params={\n        \"query\": query_string,\n        \"destination_table_name_template\": \"daily_summary_{run_date}\",\n        \"write_disposition\": \"WRITE_TRUNCATE\",\n        \"partitioning_field\": \"\",\n    },\n    schedule=\"every 24 hours\",\n)\n\ncreated = client.create_transfer_config(\n    request=bigquery_datatransfer_v1.CreateTransferConfigRequest(\n        parent=f\"projects/{project_id}\",\n        transfer_config=transfer_config,\n        service_account_name=service_account_name,\n    )\n)\n\nprint(created.name)\n```\n\nNotes:\n\n- The scheduled query sample uses a project-scoped `parent` rather than a location-scoped one.\n- The query can reference the built-in `@run_time` and `@run_date` parameters.\n- Omit `service_account_name` if the scheduled query should run as the caller represented by your ADC credentials.\n\n### Create A Cloud Storage Transfer\n\nUse the `google_cloud_storage` data source when you want recurring load jobs from `gs://` objects.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_datatransfer_v1\nfrom google.protobuf import struct_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = \"us\"\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nparams = struct_pb2.Struct()\nparams.update(\n    {\n        \"data_path_template\": \"gs://my-bucket/orders/*.csv\",\n        \"destination_table_name_template\": \"orders_{run_date}\",\n        \"file_format\": \"CSV\",\n        \"skip_leading_rows\": \"1\",\n    }\n)\n\ntransfer_config = bigquery_datatransfer_v1.TransferConfig(\n    destination_dataset_id=\"analytics\",\n    display_name=\"Cloud Storage orders import\",\n    data_source_id=\"google_cloud_storage\",\n    params=params,\n    schedule=\"every 24 hours\",\n)\n\ncreated = client.create_transfer_config(\n    request=bigquery_datatransfer_v1.CreateTransferConfigRequest(\n        parent=parent,\n        transfer_config=transfer_config,\n    )\n)\n\nprint(created.name)\n```\n\nUse the location-scoped `projects/{project}/locations/{location}` parent format shown in the official transfer-management samples.\n\n### Inspect Transfer Configs And Runs\n\nUse location-scoped resource names for config and run operations.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_datatransfer_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = \"us\"\ntransfer_config_id = \"abcd1234-0000-1111-2222-efgh5678\"\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\nconfig_name = f\"{parent}/transferConfigs/{transfer_config_id}\"\n\nfor config in client.list_transfer_configs(parent=parent):\n    print(config.name, config.data_source_id, config.schedule)\n\nconfig = client.get_transfer_config(name=config_name)\nprint(config.display_name, config.destination_dataset_id, config.disabled)\n\nfor run in client.list_transfer_runs(parent=config_name):\n    print(run.name, run.run_time)\n```\n\n### Start A Manual Backfill\n\nUse `start_manual_transfer_runs()` for missed dates or historical reprocessing.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud.bigquery_datatransfer_v1 import (\n    DataTransferServiceClient,\n    StartManualTransferRunsRequest,\n)\n\nclient = DataTransferServiceClient()\ntransfer_config_name = \"projects/1234/locations/us/transferConfigs/abcd\"\n\nnow = datetime.now(timezone.utc)\nstart_time = now - timedelta(days=5)\nend_time = now - timedelta(days=2)\n\n# Some data sources, such as scheduled_query, only support daily runs.\n# Truncate to midnight UTC before requesting a time range.\nstart_time = datetime(\n    start_time.year, start_time.month, start_time.day, tzinfo=timezone.utc\n)\nend_time = datetime(end_time.year, end_time.month, end_time.day, tzinfo=timezone.utc)\n\nrequest = StartManualTransferRunsRequest(\n    parent=transfer_config_name,\n    requested_time_range=StartManualTransferRunsRequest.TimeRange(\n        start_time=start_time,\n        end_time=end_time,\n    ),\n)\n\nresponse = client.start_manual_transfer_runs(request=request)\n\nfor run in response.runs:\n    print(run.name, run.run_time)\n```\n\n### Update Metadata Or Switch To A Service Account\n\n`update_transfer_config()` is partial-update only. Always pass an update mask.\n\n```python\nfrom google.cloud import bigquery_datatransfer_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\ntransfer_config_name = \"projects/1234/locations/us/transferConfigs/abcd\"\n\nupdated = client.update_transfer_config(\n    request={\n        \"transfer_config\": bigquery_datatransfer_v1.TransferConfig(\n            name=transfer_config_name,\n            display_name=\"Nightly orders sync\",\n        ),\n        \"update_mask\": FieldMask(paths=[\"display_name\"]),\n    }\n)\n\nprint(updated.display_name)\n```\n\nSwitch credentials for a supported data source:\n\n```python\nfrom google.cloud import bigquery_datatransfer_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\n\nupdated = client.update_transfer_config(\n    request={\n        \"transfer_config\": bigquery_datatransfer_v1.TransferConfig(\n            name=\"projects/1234/locations/us/transferConfigs/abcd\",\n        ),\n        \"update_mask\": FieldMask(paths=[\"service_account_name\"]),\n        \"service_account_name\": \"scheduler@your-project-id.iam.gserviceaccount.com\",\n    }\n)\n\nprint(updated.name)\n```\n\n### Delete A Transfer Config\n\n```python\nfrom google.cloud import bigquery_datatransfer_v1\n\nclient = bigquery_datatransfer_v1.DataTransferServiceClient()\ntransfer_config_name = \"projects/1234/locations/us/transferConfigs/abcd\"\n\nclient.delete_transfer_config(name=transfer_config_name)\n```\n\n## Important Pitfalls\n\n- Do not assume every transfer uses the same credential model. Scheduled queries and dataset copies run with user or explicit service-account credentials, while most other sources rely on the BigQuery Data Transfer Service agent.\n- Do not remove the service agent dataset permissions that BigQuery Data Transfer Service adds for non-scheduled-query transfers. Google documents `roles/bigquery.dataEditor` on the destination dataset as required for the service agent to write data.\n- `start_manual_transfer_runs()` is the current backfill API. The older `schedule_transfer_runs()` API is deprecated.\n- Disabling a transfer stops future scheduled runs and also blocks new backfills until you re-enable it.\n- Starting on **March 17, 2026**, Google documents additional dataset IAM requirements for transfer creators and updaters: `bigquery.datasets.getIamPolicy` and `bigquery.datasets.setIamPolicy`.\n- Data source parameters are source-specific. Use `list_data_sources()` and the product docs for the exact `params` keys supported by a given `data_source_id`.\n\n## Version Notes\n\n- PyPI currently lists `3.21.0` as the package version published on January 9, 2026.\n- The Google Cloud Python reference pages currently expose the latest library reference under the 3.20.0 documentation tree even though PyPI lists package version 3.21.0.\n- The package changelog shows `scheduleOptionsV2` support was added in `3.16.0`. Prefer the plain `schedule` string unless you specifically need newer schedule configuration fields from the generated types.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-bigquery-datatransfer/\n- Maintainer package docs: https://cloud.google.com/python/docs/reference/bigquerydatatransfer/latest\n- Maintainer package source: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datatransfer\n- BigQuery Data Transfer Service overview: https://cloud.google.com/bigquery/docs/dts-introduction\n- Enable the BigQuery Data Transfer Service: https://cloud.google.com/bigquery/docs/enable-transfer-service\n- Authorize accounts for data transfer: https://cloud.google.com/bigquery/docs/dts-authentication-authorization\n- Manage transfers: https://cloud.google.com/bigquery/docs/working-with-transfers\n- Scheduling queries: https://cloud.google.com/bigquery/docs/scheduling-queries\n- Create a scheduled query with a service account: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-create-scheduled-query-with-service-account\n- Create a Cloud Storage transfer: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-create-cloudstorage-transfer\n- Start manual transfer runs: https://cloud.google.com/python/docs/reference/bigquerydatatransfer/latest/google.cloud.bigquery_datatransfer_v1.services.data_transfer_service.DataTransferServiceClient#google_cloud_bigquery_datatransfer_v1_services_data_transfer_service_DataTransferServiceClient_start_manual_transfer_runs\n- Get a transfer configuration: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-get-config-info\n- List transfer configurations: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-list-configs\n- List transfer runs: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-get-run-history\n- Update a transfer configuration: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-update-config\n- Update transfer configuration credentials: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-update-credentials\n- Delete a transfer configuration: https://cloud.google.com/bigquery/docs/samples/bigquerydatatransfer-delete-transfer\n"
  },
  {
    "path": "content/google/docs/bigquery-migration/python/DOC.md",
    "content": "---\nname: bigquery-migration\ndescription: \"Google Cloud BigQuery Migration Python client for batch SQL translation workflows and interactive query translation\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,bigquery,migration,google-cloud,gcp,sql,translation,python\"\n---\n\n# google-cloud-bigquery-migration Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-bigquery-migration` package with Google Cloud credentials.\n\nIn practice, the Python surface is split:\n\n- `google.cloud.bigquery_migration_v2.MigrationServiceClient` for migration workflows such as batch SQL translation jobs\n- `google.cloud.bigquery_migration_v2alpha.SqlTranslationServiceClient` for direct `translate_query()` calls\n\nAuthenticate with Application Default Credentials (ADC), keep the `project` and `location` explicit in resource names, and use Cloud Storage paths for batch translation inputs and outputs.\n\n## Install\n\nPin the package version you want to reason about:\n\n```bash\npython -m pip install \"google-cloud-bigquery-migration==0.13.0\"\n```\n\nOther common package managers:\n\n```bash\nuv add \"google-cloud-bigquery-migration==0.13.0\"\npoetry add \"google-cloud-bigquery-migration==0.13.0\"\n```\n\nPyPI lists support for Python 3.7 and newer, including Python 3.14.\n\n## Authentication And Setup\n\nEnable the API, authenticate locally, and set the project you want the client to use:\n\n```bash\ngcloud services enable bigquerymigration.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport BIGQUERY_MIGRATION_LOCATION=\"us\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport BIGQUERY_MIGRATION_LOCATION=\"us\"\n```\n\nPractical setup notes:\n\n- BigQuery Migration resources are location-scoped, so build parents like `projects/PROJECT_ID/locations/us`.\n- Batch translation expects Cloud Storage source and target directories such as `gs://my-bucket/input/` and `gs://my-bucket/output/`.\n- The API requires Google Cloud OAuth credentials with the `cloud-platform` scope. Do not use API keys for this client.\n\n## Initialize Clients\n\n```python\nimport os\n\nfrom google.cloud import bigquery_migration_v2\nfrom google.cloud import bigquery_migration_v2alpha\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"BIGQUERY_MIGRATION_LOCATION\", \"us\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nworkflow_client = bigquery_migration_v2.MigrationServiceClient()\ntranslation_client = bigquery_migration_v2alpha.SqlTranslationServiceClient()\n```\n\nIf your environment requires a regional or custom endpoint, the generated client docs say to pass `client_options={\"api_endpoint\": ...}` when constructing the client.\n\n## Common Workflows\n\n### Create A Batch SQL Translation Workflow\n\nThis follows the official Python sample shape for a Teradata-to-BigQuery batch translation job:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_migration_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"BIGQUERY_MIGRATION_LOCATION\", \"us\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = bigquery_migration_v2.MigrationServiceClient()\n\nsource_dialect = bigquery_migration_v2.Dialect()\nsource_dialect.teradata_dialect = bigquery_migration_v2.TeradataDialect(\n    mode=bigquery_migration_v2.TeradataDialect.Mode.SQL\n)\n\ntarget_dialect = bigquery_migration_v2.Dialect()\ntarget_dialect.bigquery_dialect = bigquery_migration_v2.BigQueryDialect()\n\ntranslation_config = bigquery_migration_v2.TranslationConfigDetails(\n    gcs_source_path=\"gs://my-bucket/teradata/input/\",\n    gcs_target_path=\"gs://my-bucket/teradata/output/\",\n    source_dialect=source_dialect,\n    target_dialect=target_dialect,\n)\n\nmigration_task = bigquery_migration_v2.MigrationTask(\n    type_=\"Translation_Teradata2BQ\",\n    translation_config_details=translation_config,\n)\n\nworkflow = bigquery_migration_v2.MigrationWorkflow(\n    display_name=\"teradata-batch-translation\",\n)\nworkflow.tasks[\"translation-task\"] = migration_task\n\nrequest = bigquery_migration_v2.CreateMigrationWorkflowRequest(\n    parent=parent,\n    migration_workflow=workflow,\n)\n\nresponse = client.create_migration_workflow(request=request)\n\nprint(response.name)\nprint(response.display_name)\nprint(response.state)\n```\n\nThe product docs list batch translation task types for Redshift, HiveQL, Impala, Spark SQL, Azure Synapse, BigQuery, Greenplum, Db2, Netezza, MySQL, Oracle, PostgreSQL, Presto or Trino, Snowflake, SQLite, SQL Server, Teradata, and Vertica. Change the task `type_` and source dialect fields to match the source system you are migrating from.\n\n### Start And Inspect A Workflow\n\nCreating a workflow and starting a workflow are separate operations in the API. The start call is valid for workflows in `DRAFT` or `RUNNING`.\n\n```python\nfrom google.cloud import bigquery_migration_v2\n\nclient = bigquery_migration_v2.MigrationServiceClient()\nworkflow_name = \"projects/your-project-id/locations/us/workflows/12345678\"\n\nclient.start_migration_workflow(name=workflow_name)\n\ncurrent = client.get_migration_workflow(name=workflow_name)\nprint(current.name)\nprint(current.state)\n\nfor workflow in client.list_migration_workflows(parent=\"projects/your-project-id/locations/us\"):\n    print(workflow.name, workflow.display_name, workflow.state)\n```\n\n### List Subtasks After A Workflow Starts\n\nSubtasks are useful when you need per-task progress or error inspection:\n\n```python\nfrom google.cloud import bigquery_migration_v2\n\nclient = bigquery_migration_v2.MigrationServiceClient()\nworkflow_name = \"projects/your-project-id/locations/us/workflows/12345678\"\n\nfor subtask in client.list_migration_subtasks(parent=workflow_name):\n    print(subtask.name, subtask.task_id, subtask.type_, subtask.state)\n```\n\nIf you only want subtasks for one task inside the workflow, the request supports filters such as `migration_task = \"task_id\"`.\n\n### Translate A Single Query Interactively\n\nUse the v2alpha SQL translation client when you want a direct string-to-string translation call instead of a Cloud Storage-backed batch workflow:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_migration_v2alpha\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"BIGQUERY_MIGRATION_LOCATION\", \"us\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = bigquery_migration_v2alpha.SqlTranslationServiceClient()\n\nrequest = bigquery_migration_v2alpha.TranslateQueryRequest(\n    parent=parent,\n    source_dialect=bigquery_migration_v2alpha.TranslateQueryRequest.SqlTranslationSourceDialect.TERADATA,\n    query=\"SELECT TOP 5 * FROM sales;\",\n)\n\nresponse = client.translate_query(request=request)\n\nprint(response.translation_job)\nprint(response.translated_query)\nprint(len(response.warnings), len(response.errors))\n```\n\nThe current `TranslateQueryRequest` reference only documents `TERADATA` as the interactive `source_dialect` enum value.\n\n## Common Pitfalls\n\n- Do not mix the workflow client and the direct translation client. Batch workflows live under `bigquery_migration_v2`; direct `translate_query()` lives under `bigquery_migration_v2alpha`.\n- Do not omit the location segment in `parent` or workflow names. The API examples use `projects/PROJECT_ID/locations/LOCATION`.\n- Do not pass local filesystem paths for batch translation. Batch jobs use Cloud Storage URIs.\n- Do not assume `create_migration_workflow()` also starts execution. Use `start_migration_workflow()` when you need to move a draft workflow into `RUNNING`.\n- Do not hardcode API keys or custom auth headers. Use ADC or an explicit Google credentials object.\n- The generated Python docs note that some calls may require regional endpoints. If requests fail because of endpoint routing, set `client_options.api_endpoint` instead of changing resource-name formats.\n- The product docs note that translated output can reference helper UDFs in the public `bqutil` dataset. That is useful for initial translation, but Google explicitly warns against relying on `bqutil` directly for production workloads.\n\n## Version-Sensitive Notes For 0.13.0\n\n- PyPI shows `google-cloud-bigquery-migration 0.13.0` released on January 9, 2026.\n- The current Python reference still documents the two-surface model: workflow management in `v2`, direct query translation in `v2alpha`.\n- The latest published changelog page for this package currently stops at `0.12.0`, where Google added Python 3.14 support and deprecated the `credentials_file` argument. Prefer ADC or `credentials=` over older credentials-file shortcuts.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-bigquery-migration/\n- BigQuery Migration API client libraries page: https://docs.cloud.google.com/bigquery/docs/reference/migration\n- BigQuery Migration product docs for translation jobs: https://docs.cloud.google.com/bigquery/docs/api-sql-translator\n- Python `MigrationServiceClient` reference: https://cloud.google.com/python/docs/reference/bigquerymigration/latest/google.cloud.bigquery_migration_v2.services.migration_service.MigrationServiceClient\n- Python `SqlTranslationServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/bigquerymigration/latest/google.cloud.bigquery_migration_v2alpha.services.sql_translation_service.SqlTranslationServiceClient\n- Python `TranslateQueryRequest` reference: https://cloud.google.com/python/docs/reference/bigquerymigration/latest/google.cloud.bigquery_migration_v2alpha.types.TranslateQueryRequest\n- Python `TranslateQueryResponse` reference: https://cloud.google.com/python/docs/reference/bigquerymigration/latest/google.cloud.bigquery_migration_v2alpha.types.TranslateQueryResponse\n- Python package changelog: https://docs.cloud.google.com/python/docs/reference/bigquerymigration/latest/changelog\n- BigQuery Migration RPC reference: https://docs.cloud.google.com/bigquery/docs/reference/migration/rpc\n"
  },
  {
    "path": "content/google/docs/bigquery-reservation/python/DOC.md",
    "content": "---\nname: bigquery-reservation\ndescription: \"Google Cloud BigQuery Reservation Python client for reservation admin, assignments, and capacity commitments\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.22.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,bigquery,reservations,capacity-commitments,slots,python\"\n---\n\n# google-cloud-bigquery-reservation Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-bigquery-reservation` with `from google.cloud import bigquery_reservation_v1`, authenticate with Google Cloud Application Default Credentials (ADC), and build full location or reservation resource names instead of hand-assembling partial IDs.\n\nThis package is for BigQuery reservation administration: reservations, assignments, capacity commitments, and related control-plane operations. It is not the package you use to run SQL queries; that is `google-cloud-bigquery`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-bigquery-reservation==1.22.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-bigquery-reservation==1.22.0\"\npoetry add \"google-cloud-bigquery-reservation==1.22.0\"\n```\n\n## Authentication And Setup\n\nEnable the Reservation API and set up ADC before writing code:\n\n```bash\ngcloud services enable bigqueryreservation.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"admin-project-id\"\nexport BIGQUERY_LOCATION=\"US\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/abs/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"admin-project-id\"\nexport BIGQUERY_LOCATION=\"US\"\n```\n\nPractical setup notes:\n\n- Reservations and capacity commitments are regional or multi-regional resources. Use the same location consistently in your client calls and resource names.\n- The caller needs BigQuery Reservation Admin style permissions on the admin project, and assignment operations also depend on permissions over the assignee project, folder, or organization.\n- For most local and deployed Google Cloud workloads, ADC is the intended credential flow.\n\n## Initialize A Client\n\nUse one `ReservationServiceClient` and derive parent paths from helper methods:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\nlocation_path = client.common_location_path(project_id, location)\n```\n\nExplicit service account credentials:\n\n```python\nfrom google.cloud import bigquery_reservation_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/abs/path/service-account.json\"\n)\n\nclient = bigquery_reservation_v1.ReservationServiceClient(\n    credentials=credentials,\n)\n```\n\n## Common Workflows\n\n### Inspect Current Reservations And Commitments\n\nList reservations and capacity commitments before changing anything:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\nparent = client.common_location_path(project_id, location)\n\nprint(\"Reservations:\")\nfor reservation in client.list_reservations(parent=parent):\n    print(\n        reservation.name,\n        reservation.edition.name,\n        reservation.slot_capacity,\n        reservation.ignore_idle_slots,\n    )\n\nprint(\"Capacity commitments:\")\nfor commitment in client.list_capacity_commitments(parent=parent):\n    print(\n        commitment.name,\n        commitment.plan.name,\n        commitment.slot_count,\n        commitment.edition.name,\n        commitment.state.name,\n    )\n```\n\n### Create A Reservation\n\nCreate the reservation in the admin project and location where you manage slots:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\nparent = client.common_location_path(project_id, location)\n\nreservation = bigquery_reservation_v1.Reservation(\n    edition=bigquery_reservation_v1.Edition.STANDARD,\n    slot_capacity=100,\n    ignore_idle_slots=False,\n)\n\ncreated = client.create_reservation(\n    parent=parent,\n    reservation=reservation,\n    reservation_id=\"analytics-prod\",\n)\n\nprint(created.name)\n```\n\nUse a stable `reservation_id`; the full resource name will look like `projects/admin-project-id/locations/US/reservations/analytics-prod`.\n\n### Assign A Project To A Reservation\n\nAssignments attach a project, folder, or organization assignee to a reservation for a specific job type:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nadmin_project = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconsumer_project = \"consumer-project-id\"\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\nparent = client.reservation_path(admin_project, location, \"analytics-prod\")\n\nassignment = bigquery_reservation_v1.Assignment(\n    assignee=f\"projects/{consumer_project}\",\n    job_type=bigquery_reservation_v1.Assignment.JobType.QUERY,\n)\n\ncreated = client.create_assignment(\n    parent=parent,\n    assignment=assignment,\n)\n\nprint(created.name)\n```\n\nCommon assignee forms are:\n\n- `projects/PROJECT_ID`\n- `folders/FOLDER_NUMBER`\n- `organizations/ORGANIZATION_NUMBER`\n\n### Find Effective Assignments For A Project\n\nUse `search_all_assignments()` when you need to understand what a project currently inherits in one location:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nconsumer_project = \"consumer-project-id\"\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\n\nfor assignment in client.search_all_assignments(\n    parent=f\"projects/-/locations/{location}\",\n    query=f\"assignee=projects/{consumer_project}\",\n):\n    print(assignment.name, assignment.job_type.name)\n```\n\nThis is the practical way to debug whether a project is using the reservation you expect.\n\n### Move An Assignment To A Different Reservation\n\nMove the assignment by name when you need to repoint an existing workload:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nadmin_project = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\nassignment_name = (\n    f\"projects/{admin_project}/locations/{location}/reservations/\"\n    \"analytics-prod/assignments/123456789\"\n)\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\n\nmoved = client.move_assignment(\n    name=assignment_name,\n    destination_id=\"analytics-batch\",\n)\n\nprint(moved.name)\n```\n\n`destination_id` is the target reservation ID in the same admin project and location.\n\n### Purchase A Capacity Commitment\n\nCapacity commitments are the slot commitments that back reservations:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\nparent = client.common_location_path(project_id, location)\n\ncommitment = bigquery_reservation_v1.CapacityCommitment(\n    slot_count=100,\n    plan=bigquery_reservation_v1.CapacityCommitment.CommitmentPlan.FLEX,\n    edition=bigquery_reservation_v1.Edition.STANDARD,\n)\n\ncreated = client.create_capacity_commitment(\n    parent=parent,\n    capacity_commitment=commitment,\n)\n\nprint(created.name, created.state.name)\n```\n\nUse the commitment plan that matches your billing and lifecycle requirements. Flex commitments are the shortest-lived option; annual and multi-year commitments have longer lock-in and renewal behavior.\n\n### Update Reservation Capacity\n\nUpdate only the fields you intend to change by passing a field mask:\n\n```python\nimport os\n\nfrom google.cloud import bigquery_reservation_v1\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"BIGQUERY_LOCATION\", \"US\")\n\nclient = bigquery_reservation_v1.ReservationServiceClient()\n\nreservation = bigquery_reservation_v1.Reservation(\n    name=client.reservation_path(project_id, location, \"analytics-prod\"),\n    slot_capacity=200,\n)\n\nupdated = client.update_reservation(\n    reservation=reservation,\n    update_mask=field_mask_pb2.FieldMask(paths=[\"slot_capacity\"]),\n)\n\nprint(updated.name, updated.slot_capacity)\n```\n\n## Common Pitfalls\n\n### Reservation admin is a separate API surface\n\nEnable `bigqueryreservation.googleapis.com` explicitly. BigQuery query access alone does not enable reservation administration.\n\n### Resource names must be complete\n\nUse helper methods like `common_location_path()` and `reservation_path()` instead of passing bare location names or reservation IDs to methods that expect full resource names.\n\n### Assignment rules are strict\n\nA given assignee can only have one assignment per job type in one location. If a project inherits assignments from multiple levels, the more specific resource wins.\n\n### Assignment changes are not always immediate for billing\n\nGoogle's reservation docs note that after creating or updating an assignment, you should allow roughly five minutes before expecting workloads to be billed and scheduled according to the new assignment.\n\n### Capacity commitments are location-bound\n\nCommitments are regional resources. You cannot move them between locations, and deletion rules depend on the commitment plan and state.\n\n### Reservation capacity and autoscaling settings interact\n\nThe Reservation API exposes `slot_capacity`, `ignore_idle_slots`, `autoscale`, `max_slots`, and `scaling_mode`. If you use autoscaling or slot upper bounds, follow the Reservation type docs carefully because some fields are mutually constrained.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-bigquery-reservation 1.22.0`, released on January 9, 2026.\n- The hosted Google Cloud Python reference is the authoritative API surface, but generated pages and changelog pages can lag each other. Confirm the version you have installed when copying signatures from hosted docs.\n- PyPI classifies this release for Python `>=3.7` and includes current classifiers through Python 3.14.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-bigquery-reservation/\n- Maintainer package docs: https://cloud.google.com/python/docs/reference/bigqueryreservation/latest\n- `ReservationServiceClient` reference: https://cloud.google.com/python/docs/reference/bigqueryreservation/latest/google.cloud.bigquery_reservation_v1.services.reservation_service.ReservationServiceClient\n- Reservation type reference: https://cloud.google.com/python/docs/reference/bigqueryreservation/latest/google.cloud.bigquery_reservation_v1.types.Reservation\n- CapacityCommitment type reference: https://cloud.google.com/python/docs/reference/bigqueryreservation/latest/google.cloud.bigquery_reservation_v1.types.CapacityCommitment\n- BigQuery Reservations introduction: https://cloud.google.com/bigquery/docs/reservations-intro\n- Get started with Reservations: https://cloud.google.com/bigquery/docs/reservations-get-started\n- Use Reservations with assignments: https://cloud.google.com/bigquery/docs/reservations-workload-management\n- ADC overview: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/bigquery-storage/python/DOC.md",
    "content": "---\nname: bigquery-storage\ndescription: \"Google Cloud BigQuery Storage Python client for high-throughput table reads, Arrow/DataFrame downloads, and Storage Write API appends\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.36.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,bigquery,bigquery-storage,google-cloud,gcp,python,analytics,storage-api\"\n---\n\n# google-cloud-bigquery-storage Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-bigquery-storage` with Google Cloud Application Default Credentials (ADC). This package is the Python client for the BigQuery Storage Read API and Storage Write API.\n\nFor application code, be explicit about:\n\n- the project used to create read or write clients\n- the full table resource name\n- whether you want Avro or Arrow reads\n- whether write semantics can be at-least-once or must be exactly-once\n\n## Install\n\nPin the package version you want to reason about:\n\n```bash\npython -m pip install \"google-cloud-bigquery-storage==2.36.2\"\n```\n\nInstall extras when you need the higher-level helpers:\n\n```bash\npython -m pip install \"google-cloud-bigquery-storage[fastavro,pyarrow,pandas]==2.36.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-bigquery-storage==2.36.2\"\npoetry add \"google-cloud-bigquery-storage==2.36.2\"\n```\n\nUse these extras intentionally:\n\n- `fastavro`: required for `ReadRowsStream.rows()` and `ReadRowsStream.to_dataframe()` on Avro data\n- `pyarrow`: required for Arrow reads and Arrow-based appends\n- `pandas`: required for DataFrame helpers\n\n## Authentication And Setup\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nPrerequisites:\n\n- enable the BigQuery Storage API for the project\n- use credentials with permission to read or write the target BigQuery table\n- keep `GOOGLE_CLOUD_PROJECT` set when project discovery is ambiguous\n\n## Initialize Clients\n\n```python\nimport os\n\nfrom google.cloud import bigquery_storage_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nread_client = bigquery_storage_v1.BigQueryReadClient()\nwrite_client = bigquery_storage_v1.BigQueryWriteClient()\n```\n\nThe package name and import names differ:\n\n- install: `google-cloud-bigquery-storage`\n- import: `google.cloud.bigquery_storage_v1`\n\n## Common Read Workflows\n\n### Read rows with a filtered read session\n\nThis is the core Storage Read API flow: create a read session, pick a stream, and iterate decoded rows.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_storage_v1\nfrom google.cloud.bigquery_storage_v1 import types\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ntable = (\n    \"projects/bigquery-public-data/datasets/usa_names/tables/usa_1910_current\"\n)\n\nclient = bigquery_storage_v1.BigQueryReadClient()\n\nrequested_session = types.ReadSession()\nrequested_session.table = table\nrequested_session.data_format = types.DataFormat.AVRO\nrequested_session.read_options.selected_fields = [\"name\", \"number\", \"state\"]\nrequested_session.read_options.row_restriction = 'state = \"WA\"'\n\nsession = client.create_read_session(\n    parent=f\"projects/{project_id}\",\n    read_session=requested_session,\n    max_stream_count=1,\n)\n\nreader = client.read_rows(session.streams[0].name)\n\nfor row in reader.rows(session):\n    print(row[\"name\"], row[\"number\"], row[\"state\"])\n```\n\nPractical notes:\n\n- `parent` is the project that creates the read session; it does not have to match the project that owns the table.\n- `selected_fields` and `row_restriction` reduce the amount of data scanned over the wire.\n- if you omit `max_stream_count`, the service chooses the number of streams for you.\n\n### Convert a stream to Arrow\n\nUse Arrow when your next step is pandas, PyArrow, or another columnar pipeline.\n\n```python\nimport os\n\nfrom google.cloud import bigquery_storage_v1\nfrom google.cloud.bigquery_storage_v1 import types\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ntable = (\n    \"projects/bigquery-public-data/datasets/usa_names/tables/usa_1910_current\"\n)\n\nclient = bigquery_storage_v1.BigQueryReadClient()\n\nrequested_session = types.ReadSession()\nrequested_session.table = table\nrequested_session.data_format = types.DataFormat.ARROW\n\nsession = client.create_read_session(\n    parent=f\"projects/{project_id}\",\n    read_session=requested_session,\n    max_stream_count=1,\n)\n\nreader = client.read_rows(session.streams[0].name)\narrow_table = reader.to_arrow(session)\n\nprint(arrow_table.schema)\nprint(arrow_table.to_pydict())\n```\n\n`to_arrow()` requires an Arrow read session and `pyarrow` to be installed.\n\n### Download a DataFrame through `google-cloud-bigquery`\n\nIf you already use the BigQuery client, this package can accelerate DataFrame downloads by supplying the BigQuery Storage transport.\n\n```python\nimport os\n\nfrom google.cloud import bigquery\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = bigquery.Client(project=project_id)\nrows = client.list_rows(\"bigquery-public-data.samples.shakespeare\")\ndf = rows.to_dataframe(create_bqstorage_client=True)\n\nprint(df.head())\n```\n\nFor this workflow, install both:\n\n```bash\npython -m pip install \"google-cloud-bigquery\" \"google-cloud-bigquery-storage[fastavro,pandas]==2.36.2\"\n```\n\n## Common Write Workflow\n\n### Append Arrow batches to the default stream\n\nThe default stream is the simplest way to append data. Google documents it as the right choice when your application only needs at-least-once delivery semantics.\n\n```python\nimport os\n\nimport pyarrow\nfrom google.cloud import bigquery_storage_v1\nfrom google.cloud.bigquery_storage_v1 import types\nfrom google.cloud.bigquery_storage_v1.writer import AppendRowsStream\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndataset_id = \"analytics\"\ntable_id = \"events\"\n\nwrite_client = bigquery_storage_v1.BigQueryWriteClient()\n\narrow_table = pyarrow.table(\n    {\n        \"user_id\": [\"u_1\", \"u_2\"],\n        \"amount_cents\": [4999, 1299],\n    }\n)\n\nrequest_template = types.AppendRowsRequest()\nrequest_template.write_stream = (\n    f\"projects/{project_id}/datasets/{dataset_id}/tables/{table_id}/_default\"\n)\nrequest_template.arrow_rows.writer_schema.serialized_schema = (\n    arrow_table.schema.serialize().to_pybytes()\n)\n\nappend_rows_stream = AppendRowsStream(write_client, request_template)\n\nrequest = types.AppendRowsRequest()\nrequest.arrow_rows.rows.serialized_record_batch = (\n    arrow_table.to_batches()[0].serialize().to_pybytes()\n)\n\nresponse = append_rows_stream.send(request).result()\nprint(response.append_result)\n```\n\nUse this pattern when your table schema already exists and your source data is easy to express as Arrow. For exactly-once writes, Google documents committed streams with offsets, and for atomic batch loads it documents pending streams followed by `FinalizeWriteStream` and `BatchCommitWriteStreams`.\n\n## Common Pitfalls\n\n- Do not use API keys. Google Cloud client libraries expect ADC or explicit Google credentials.\n- Do not confuse the package name with the import path. Import from `google.cloud.bigquery_storage_v1`.\n- If you use `row_restriction`, pass the `session` object into `rows(session)`, `to_arrow(session)`, or `to_dataframe(session)`. The docs call this out because empty streams can otherwise fail when they cannot infer the schema.\n- `rows()` and `to_dataframe()` on `ReadRowsStream` depend on `fastavro`; `to_arrow()` depends on Arrow format plus `pyarrow`.\n- The default write stream is at-least-once. If your retry behavior cannot tolerate duplicates, use committed streams with offsets instead of `_default`.\n- Storage Write API appends are schema-sensitive. Keep the Arrow schema or protobuf schema aligned with the BigQuery table schema before sending batches.\n\n## Version-Sensitive Notes\n\n- The `2.36.2` changelog entry fixes `to_dataframe()` missing the first page of results. If you see truncated DataFrame downloads on an older `2.36.x` build, upgrade to `2.36.2`.\n- The upstream changelog notes Python `3.14` support starting in `2.34.0`, and PyPI classifiers for `2.36.2` include Python `3.14`.\n\n## Official Sources\n\n- PyPI: `https://pypi.org/project/google-cloud-bigquery-storage/`\n- Python reference root: `https://docs.cloud.google.com/python/docs/reference/bigquerystorage/latest`\n- `BigQueryReadClient` reference: `https://docs.cloud.google.com/python/docs/reference/bigquerystorage/latest/google.cloud.bigquery_storage_v1.client.BigQueryReadClient`\n- `ReadRowsStream` reference: `https://docs.cloud.google.com/python/docs/reference/bigquerystorage/latest/google.cloud.bigquery_storage_v1.reader.ReadRowsStream`\n- BigQuery Storage quickstart sample: `https://docs.cloud.google.com/bigquery/docs/samples/bigquerystorage-quickstart`\n- BigQuery DataFrame sample with Storage API: `https://docs.cloud.google.com/bigquery/docs/samples/bigquery-pandas-public-data`\n- Storage Write API streaming guide: `https://cloud.google.com/bigquery/docs/write-api-streaming`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/bigquerystorage/latest/changelog`\n- ADC setup: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/bigtable/javascript/DOC.md",
    "content": "---\nname: bigtable\ndescription: \"Google Cloud Bigtable Node.js client for ADC auth, table admin, row reads and writes, and emulator-backed local development\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,bigtable,google-cloud,gcp,nosql,database,javascript,nodejs\"\n---\n\n# Google Cloud Bigtable Node.js Client\n\n## Golden Rule\n\nUse `@google-cloud/bigtable` with Google Cloud authentication, and open an existing instance before you debug row logic.\n\nIn most applications, the Cloud Bigtable instance already exists and your Node.js code works with tables and rows inside that instance. Keep `projectId`, `instanceId`, and `tableId` explicit in local development so you do not accidentally point at the wrong project.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/bigtable@6.5.0\n```\n\nIf you use `pnpm` or `yarn`, install the same package version there.\n\nBefore running code, make sure all of the following are true:\n\n- the target Google Cloud project exists\n- the Cloud Bigtable API is enabled\n- the caller has IAM access to the instance and tables\n- the Bigtable instance already exists\n- the table and column families already exist unless your code is creating them\n\n## Authentication And Project Setup\n\nFor local development, use Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\nexport BIGTABLE_INSTANCE_ID=\"my-instance\"\nexport BIGTABLE_TABLE_ID=\"my-table\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\nexport BIGTABLE_INSTANCE_ID=\"my-instance\"\nexport BIGTABLE_TABLE_ID=\"my-table\"\n```\n\n`GOOGLE_APPLICATION_CREDENTIALS` and ADC are standard Google auth inputs. `BIGTABLE_INSTANCE_ID` and `BIGTABLE_TABLE_ID` are app-level environment variables used by the examples in this guide.\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\n## Initialize A Client\n\nImport the package as:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n```\n\nBasic setup with an explicit project:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nconst instance = bigtable.instance(process.env.BIGTABLE_INSTANCE_ID);\nconst table = instance.table(process.env.BIGTABLE_TABLE_ID);\n```\n\nIf your runtime already resolves the correct project and credentials, `new Bigtable()` is usually enough:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable();\nconst instance = bigtable.instance('my-instance');\nconst table = instance.table('my-table');\n```\n\nWith an explicit key file:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable({\n  projectId: 'my-gcp-project',\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\n## Create A Table\n\nIf the instance exists but the table does not, create the table and its column families from the instance handle:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nconst instance = bigtable.instance(process.env.BIGTABLE_INSTANCE_ID);\nconst tableId = process.env.BIGTABLE_TABLE_ID;\n\nasync function ensureTable() {\n  const table = instance.table(tableId);\n  const [exists] = await table.exists();\n\n  if (!exists) {\n    await instance.createTable(tableId, {\n      families: ['profile', 'stats'],\n    });\n  }\n}\n\nensureTable().catch(console.error);\n```\n\nThis creates the table inside an existing instance. Instance and cluster provisioning are separate infrastructure steps.\n\n## Write Rows\n\nInsert rows with a row key and `data` grouped by column family:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable();\nconst table = bigtable\n  .instance(process.env.BIGTABLE_INSTANCE_ID)\n  .table(process.env.BIGTABLE_TABLE_ID);\n\nasync function writeUsers() {\n  await table.insert([\n    {\n      key: 'user#1001',\n      data: {\n        profile: {\n          name: 'Ada Lovelace',\n          email: 'ada@example.com',\n        },\n        stats: {\n          visits: '1',\n        },\n      },\n    },\n    {\n      key: 'user#1002',\n      data: {\n        profile: {\n          name: 'Grace Hopper',\n          email: 'grace@example.com',\n        },\n        stats: {\n          visits: '5',\n        },\n      },\n    },\n  ]);\n}\n\nwriteUsers().catch(console.error);\n```\n\nBigtable stores cell values as bytes. If you need typed numbers, JSON, or timestamps, serialize and deserialize them consistently in your application.\n\n## Read Rows\n\nRead a single row by key:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable();\nconst table = bigtable\n  .instance(process.env.BIGTABLE_INSTANCE_ID)\n  .table(process.env.BIGTABLE_TABLE_ID);\n\nasync function readUser() {\n  const [row] = await table.row('user#1001').get();\n\n  if (!row) {\n    console.log('Row not found');\n    return;\n  }\n\n  const name = row.data.profile.name[0].value.toString();\n  const email = row.data.profile.email[0].value.toString();\n\n  console.log({\n    id: row.id,\n    name,\n    email,\n  });\n}\n\nreadUser().catch(console.error);\n```\n\nStream rows when you want to scan a table without loading everything into memory at once:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable();\nconst table = bigtable\n  .instance(process.env.BIGTABLE_INSTANCE_ID)\n  .table(process.env.BIGTABLE_TABLE_ID);\n\nasync function listRows() {\n  await new Promise((resolve, reject) => {\n    table\n      .createReadStream()\n      .on('error', reject)\n      .on('data', row => {\n        console.log(row.id);\n      })\n      .on('end', resolve);\n  });\n}\n\nlistRows().catch(console.error);\n```\n\nThe returned row shape matters:\n\n- `row.id` is the row key\n- `row.data[family][qualifier]` is an array of cells\n- `row.data[family][qualifier][0].value` is a `Buffer`, so decode it before logging or parsing\n\n## Delete Data\n\nDelete a single row:\n\n```javascript\nconst {Bigtable} = require('@google-cloud/bigtable');\n\nconst bigtable = new Bigtable();\nconst table = bigtable\n  .instance(process.env.BIGTABLE_INSTANCE_ID)\n  .table(process.env.BIGTABLE_TABLE_ID);\n\nasync function deleteUser() {\n  await table.row('user#1002').delete();\n}\n\ndeleteUser().catch(console.error);\n```\n\nDelete the whole table only when you really intend to remove schema and data together:\n\n```javascript\nasync function deleteTable() {\n  await table.delete();\n}\n```\n\n## Emulator\n\nFor local integration tests, use the official Bigtable emulator:\n\n```bash\ngcloud beta emulators bigtable start --host-port=localhost:8086\nexport BIGTABLE_EMULATOR_HOST=localhost:8086\n```\n\nImportant emulator behavior from the official docs:\n\n- it is in-memory only and does not persist data across runs\n- it does not support a secure connection\n- it does not provide admin APIs for creating or managing instances and clusters\n- once `BIGTABLE_EMULATOR_HOST` is set, the client library connects to the emulator automatically\n\nUnset `BIGTABLE_EMULATOR_HOST` after tests so production code does not accidentally point at the emulator.\n\n## Common Pitfalls\n\n- The package is a server-side Node.js client. Do not mix it with browser-only Firebase or web SDK setup.\n- `instance.table('name')` only gives you a handle. It does not prove the table already exists.\n- Bigtable stores rows in sorted row-key order. Avoid production row-key schemes that send sequential traffic to the same tablet range.\n- Row data comes back as cell-version arrays with `Buffer` values. Decode the `Buffer` and choose which version you want.\n- Missing column families are a common cause of first-run write failures.\n- If `BIGTABLE_EMULATOR_HOST` is still set in your shell or CI job, the client talks to the emulator instead of the real service.\n\n## Version Notes For 6.5.0\n\n- This guide targets `@google-cloud/bigtable` `6.5.0`.\n- Use the current Google Cloud Node.js reference when copying admin or row APIs into new code, especially if you are adapting older blog posts or answers.\n\n## Official Sources\n\n- Bigtable Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/bigtable/latest`\n- Google Cloud ADC guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Bigtable emulator guide: `https://cloud.google.com/bigtable/docs/emulator`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/bigtable`\n"
  },
  {
    "path": "content/google/docs/bigtable/python/DOC.md",
    "content": "---\nname: bigtable\ndescription: \"Google Cloud Bigtable Python client library for ADC auth, classic admin/data access, async data workflows, and emulator-backed testing\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.35.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,bigtable,google-cloud,gcp,nosql,grpc\"\n---\n\n# Google Cloud Bigtable Python Client Library\n\n## Golden Rule\n\nInstall `google-cloud-bigtable`, authenticate with Application Default Credentials (ADC), and pick one client surface before writing code:\n\n- `google.cloud.bigtable` for the classic synchronous client and admin/table helpers\n- `google.cloud.bigtable.data` for the newer async data-plane client\n\nThe official Bigtable Python docs explicitly note that the async data client is focused on data reads and writes. Table creation and other admin operations still use the regular synchronous admin client.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-bigtable==2.35.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-bigtable==2.35.0\"\npoetry add \"google-cloud-bigtable==2.35.0\"\n```\n\n## Authentication And Setup\n\nBefore using the client library, make sure all of the following are true:\n\n- The target Google Cloud project exists\n- Billing is enabled\n- The Cloud Bigtable API is enabled\n- The caller has IAM permissions for the instance and tables\n- The instance, table, and column family already exist unless your code is explicitly creating them\n\nFor local development, the normal path is ADC with the Google Cloud CLI:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\n```\n\nBasic classic client setup:\n\n```python\nfrom google.cloud import bigtable\n\nclient = bigtable.Client(project=\"my-gcp-project\", admin=False)\ninstance = client.instance(\"my-instance\")\ntable = instance.table(\"my-table\")\n```\n\nBasic async data client setup:\n\n```python\nfrom google.cloud import bigtable\n\nclient = bigtable.data.BigtableDataClientAsync(project=\"my-gcp-project\")\ntable = client.get_table(\"my-instance\", \"my-table\")\n```\n\nPass `project` explicitly unless you have already verified that project discovery is correct in the runtime. Bigtable failures are often caused by pointing at the wrong project or instance rather than by bad row logic.\n\n## Choose The Client Surface First\n\n### Classic synchronous client\n\nUse `google.cloud.bigtable` when you need:\n\n- synchronous request flow\n- table creation or schema/admin helpers\n- compatibility with older examples that use `Client`, `Instance`, `Table`, and `DirectRow`\n\n### Async data client\n\nUse `google.cloud.bigtable.data` when you need:\n\n- an async application flow\n- the newer data-plane API for row reads and writes\n- bulk mutation and streaming reads in an asyncio codebase\n\nThe official docs and PyPI page both warn against dropping the async client into an otherwise synchronous codebase just to use a newer API surface.\n\n## Core Usage\n\n### Create a table with the classic admin client\n\nThe official hello-world sample creates tables with the regular admin client, not the async data client:\n\n```python\nfrom google.cloud import bigtable\nfrom google.cloud.bigtable import column_family\n\nproject_id = \"my-gcp-project\"\ninstance_id = \"my-instance\"\ntable_id = \"my-table\"\n\nclient = bigtable.Client(project=project_id, admin=True)\ninstance = client.instance(instance_id)\ntable = instance.table(table_id)\n\ncolumn_families = {\n    b\"cf1\": column_family.MaxVersionsGCRule(2),\n}\n\nif not table.exists():\n    table.create(column_families=column_families)\n```\n\n### Write and read a row with the classic synchronous API\n\n```python\nimport datetime\n\nfrom google.cloud import bigtable\nfrom google.cloud.bigtable import row_filters\n\nproject_id = \"my-gcp-project\"\ninstance_id = \"my-instance\"\ntable_id = \"my-table\"\ncolumn_family_id = b\"cf1\"\ncolumn = b\"status\"\n\nclient = bigtable.Client(project=project_id, admin=False)\ntable = client.instance(instance_id).table(table_id)\n\nrow = table.direct_row(b\"device#123\")\nrow.set_cell(\n    column_family_id,\n    column,\n    b\"ok\",\n    timestamp=datetime.datetime.utcnow(),\n)\ntable.mutate_rows([row])\n\nstored = table.read_row(\n    b\"device#123\",\n    row_filters.CellsColumnLimitFilter(1),\n)\n\nif stored is not None:\n    cell = stored.cells[column_family_id.decode(\"utf-8\")][column][0]\n    print(cell.value.decode(\"utf-8\"))\n```\n\n### Write and read rows with the async data client\n\n```python\nimport asyncio\n\nfrom google.cloud import bigtable\n\nproject_id = \"my-gcp-project\"\ninstance_id = \"my-instance\"\ntable_id = \"my-table\"\ncolumn_family_id = b\"cf1\"\ncolumn = b\"status\"\n\nasync def main() -> None:\n    client = bigtable.data.BigtableDataClientAsync(project=project_id)\n    table = client.get_table(instance_id, table_id)\n\n    mutation = bigtable.data.RowMutationEntry(\n        b\"device#123\",\n        bigtable.data.SetCell(column_family_id, column, b\"ok\"),\n    )\n    await table.bulk_mutate_rows([mutation])\n\n    row_filter = bigtable.data.row_filters.CellsColumnLimitFilter(1)\n    row = await table.read_row(b\"device#123\", row_filter=row_filter)\n\n    if row is not None:\n        print(row.cells[0].value.decode(\"utf-8\"))\n\nasyncio.run(main())\n```\n\n### Scan rows with the async data client\n\n```python\nimport asyncio\n\nfrom google.cloud import bigtable\n\nasync def main() -> None:\n    client = bigtable.data.BigtableDataClientAsync(project=\"my-gcp-project\")\n    table = client.get_table(\"my-instance\", \"my-table\")\n    query = bigtable.data.ReadRowsQuery(\n        row_filter=bigtable.data.row_filters.CellsColumnLimitFilter(1),\n    )\n\n    async for row in await table.read_rows_stream(query):\n        print(row.row_key)\n\nasyncio.run(main())\n```\n\n## Emulator\n\nFor local integration tests, use the official Bigtable emulator:\n\n```bash\ngcloud beta emulators bigtable start --host-port=localhost:8086\nexport BIGTABLE_EMULATOR_HOST=localhost:8086\n```\n\nImportant emulator behavior from the official docs:\n\n- it is in-memory only and does not persist data across runs\n- it does not support a secure connection\n- it does not provide admin APIs for creating or managing instances and clusters\n- once `BIGTABLE_EMULATOR_HOST` is set, the client library connects to the emulator automatically\n\nUnset `BIGTABLE_EMULATOR_HOST` after tests so production code does not accidentally point at the emulator.\n\n## Common Pitfalls\n\n- The package name is `google-cloud-bigtable`, but the common import is `from google.cloud import bigtable`.\n- Do not mix classic `Client` / `Table` examples with `bigtable.data` examples unless you deliberately adapt imports, row types, and method names.\n- The async client is not a general replacement for synchronous code. Google explicitly recommends using it only in an async codebase.\n- Table creation is an admin operation. The async data client does not replace the regular admin client for that workflow.\n- Bigtable rows are stored in sorted row-key order. The official sample warns that sequential numeric row keys are fine for demos but can create poor production distribution and hotspotting.\n- Data examples assume the instance, table, and column family already exist. Missing schema is a common cause of first-run failures.\n- If `BIGTABLE_EMULATOR_HOST` is left set in a shell or CI job, the library will connect to the local emulator instead of the real service.\n\n## Version-Sensitive Notes For 2.35.0\n\n- As of `2026-03-12`, PyPI and the official Google Cloud Bigtable Python reference both align on `2.35.0` as the current package release.\n- The official docs still call out `v2.23.0` as the introduction of `BigtableDataClientAsync` under `google.cloud.bigtable.data`. Older examples written before that release often show only the classic client surface.\n- PyPI lists the package requirement as `Python >= 3.7`.\n- If you are adapting older blog posts or Stack Overflow answers, verify whether they predate the newer `google.cloud.bigtable.data` API before copying method names into current code.\n\n## Official Sources\n\n- Bigtable Python reference root: `https://cloud.google.com/python/docs/reference/bigtable/latest`\n- Bigtable Python hello-world sample: `https://cloud.google.com/bigtable/docs/samples-python-hello`\n- Google Cloud ADC guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Bigtable emulator guide: `https://cloud.google.com/bigtable/docs/emulator`\n- PyPI package page: `https://pypi.org/project/google-cloud-bigtable/`\n"
  },
  {
    "path": "content/google/docs/billing/javascript/DOC.md",
    "content": "---\nname: billing\ndescription: \"Google Cloud Billing Node.js client for billing accounts, project billing links, and Cloud Catalog SKU metadata\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-billing,google-cloud,gcp,billing,cloud-catalog,pricing,javascript,nodejs\"\n---\n\n# `@google-cloud/billing` JavaScript Package Guide\n\nUse `@google-cloud/billing` when your Node.js code needs to discover billing accounts, read or change the billing account linked to a project, or query published Cloud Catalog service and SKU metadata.\n\n## Golden Rule\n\nUse this package for Cloud Billing control-plane operations and catalog metadata, not for invoice analysis, budget enforcement, or BigQuery billing export queries.\n\n- Import the generated clients from the `v1` namespace.\n- Use `v1.CloudBillingClient` for billing accounts and project billing links.\n- Use `v1.CloudCatalogClient` for services, SKUs, and published price metadata.\n- Authenticate with Application Default Credentials (ADC), not API keys.\n- Pass full resource names like `projects/PROJECT_ID`, `billingAccounts/...`, and `services/...`.\n\nThis guide covers `5.1.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/billing@5.1.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the Cloud Billing API in the project that will call the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable cloudbilling.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target project already exists.\n2. The Cloud Billing API is enabled for the caller project.\n3. The caller has permission to view billing accounts or change project billing links.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst billingClient = new v1.CloudBillingClient();\nconst catalogClient = new v1.CloudCatalogClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/billing';\n\nconst billingClient = new v1.CloudBillingClient();\nconst catalogClient = new v1.CloudCatalogClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst billingClient = new v1.CloudBillingClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### List Billing Accounts\n\nUse this to discover billing account resource names for later requests.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function listBillingAccounts() {\n  const accounts = [];\n\n  for await (const account of client.listBillingAccountsAsync({})) {\n    accounts.push({\n      name: account.name,\n      displayName: account.displayName,\n      open: account.open,\n    });\n  }\n\n  return accounts;\n}\n```\n\nBilling account resource names look like `billingAccounts/000000-000000-000000`.\n\n### Read A Project's Billing State\n\n`getProjectBillingInfo()` expects a project resource name, not a bare project ID.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function getProjectBillingState(projectId) {\n  const [info] = await client.getProjectBillingInfo({\n    name: `projects/${projectId}`,\n  });\n\n  return {\n    projectId: info.projectId,\n    billingEnabled: info.billingEnabled,\n    billingAccountName: info.billingAccountName || null,\n  };\n}\n```\n\n### Link A Project To A Billing Account\n\nUse `updateProjectBillingInfo()` to attach a project to a billing account.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function linkProjectBilling(projectId, billingAccountName) {\n  const [info] = await client.updateProjectBillingInfo({\n    name: `projects/${projectId}`,\n    projectBillingInfo: {\n      billingAccountName,\n    },\n  });\n\n  return info;\n}\n\nlinkProjectBilling(\n  'my-project-id',\n  'billingAccounts/000000-000000-000000'\n).catch(console.error);\n```\n\n### Disable Billing For A Project\n\nTo unlink a billing account from a project, send an empty billing account name.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function disableProjectBilling(projectId) {\n  const [info] = await client.updateProjectBillingInfo({\n    name: `projects/${projectId}`,\n    projectBillingInfo: {\n      billingAccountName: '',\n    },\n  });\n\n  return info;\n}\n```\n\n### List Projects Linked To A Billing Account\n\nUse this when you need billing inventory for one billing account.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function listProjectsOnBillingAccount(billingAccountName) {\n  const projects = [];\n\n  for await (const info of client.listProjectBillingInfoAsync({\n    name: billingAccountName,\n  })) {\n    projects.push({\n      projectId: info.projectId,\n      billingEnabled: info.billingEnabled,\n      billingAccountName: info.billingAccountName,\n    });\n  }\n\n  return projects;\n}\n```\n\n### List Billable Services\n\n`CloudCatalogClient` exposes published Cloud Catalog metadata.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudCatalogClient();\n\nasync function listServices() {\n  const services = [];\n\n  for await (const service of client.listServicesAsync({})) {\n    services.push({\n      name: service.name,\n      displayName: service.displayName,\n    });\n  }\n\n  return services;\n}\n```\n\nService resource names look like `services/6F81-5844-456A`.\n\n### List SKUs For A Service\n\nUse this when you need published SKU metadata for one Google Cloud service.\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudCatalogClient();\n\nasync function listSkusForService(serviceName) {\n  const skus = [];\n\n  for await (const sku of client.listSkusAsync({\n    parent: serviceName,\n  })) {\n    skus.push({\n      name: sku.name,\n      description: sku.description,\n      resourceFamily: sku.category?.resourceFamily,\n      usageType: sku.category?.usageType,\n    });\n  }\n\n  return skus;\n}\n\nlistSkusForService('services/6F81-5844-456A').catch(console.error);\n```\n\nTreat catalog results as published SKU metadata, not as live usage or invoice data.\n\n## Request Configuration\n\nGenerated Google Cloud Node.js clients follow the usual GAPIC request pattern:\n\n- Unary methods take a request object and optional call options.\n- List methods expose async iterators like `listBillingAccountsAsync()` and `listSkusAsync()`.\n- Resource names are strings like `projects/my-project-id`, `billingAccounts/...`, and `services/...`.\n\nExample with an explicit timeout:\n\n```javascript\nconst {v1} = require('@google-cloud/billing');\n\nconst client = new v1.CloudBillingClient();\n\nasync function getProjectBillingState(projectId) {\n  const [info] = await client.getProjectBillingInfo(\n    {name: `projects/${projectId}`},\n    {timeout: 30000}\n  );\n\n  return info;\n}\n```\n\n## Configuration And Debugging Notes\n\n- ADC is the default credential flow. Avoid hard-coding credentials into application code.\n- Set `GOOGLE_APPLICATION_CREDENTIALS` only when you intentionally want file-based service account credentials.\n- Reuse long-lived clients in app code instead of constructing a new client for every request.\n- Cache catalog lookups when you repeatedly read services or SKUs. Catalog responses can be large.\n\n## Common Pitfalls\n\n- The package is `@google-cloud/billing`, but the generated clients live under the `v1` namespace.\n- `CloudBillingClient` and `CloudCatalogClient` are separate surfaces. Project billing methods are not on the catalog client, and SKU methods are not on the billing client.\n- `getProjectBillingInfo()` and `updateProjectBillingInfo()` require `projects/PROJECT_ID`, not just `PROJECT_ID`.\n- `listProjectBillingInfoAsync()` takes a billing account resource like `billingAccounts/...`, not a project resource.\n- Disabling billing uses `updateProjectBillingInfo()` with an empty `billingAccountName`; there is no separate delete method.\n- Cloud Catalog metadata is useful for published pricing context, but it is not a substitute for usage export, invoice reconciliation, or budget enforcement.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/billing/latest`\n- Cloud Billing product docs: `https://cloud.google.com/billing/docs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Local ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/billing`\n"
  },
  {
    "path": "content/google/docs/billing/python/DOC.md",
    "content": "---\nname: billing\ndescription: \"Google Cloud Billing Python client for billing accounts, project billing links, and Cloud Catalog SKU metadata\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.18.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-billing,google-cloud,gcp,billing,cloud-catalog,pricing,python\"\n---\n\n# google-cloud-billing Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-billing` for control-plane billing operations and catalog metadata, not for invoice analysis or budget management.\n\n- Import from `google.cloud import billing_v1`.\n- Use `CloudBillingClient` for billing accounts and project billing links.\n- Use `CloudCatalogClient` for services, SKUs, and price metadata.\n- Prefer Application Default Credentials (ADC) unless your runtime already manages credentials another way.\n\n## Version Notes\n\n- The version used here for this package was `1.18.0`. That matches the current PyPI package version shown on March 12, 2026.\n- Google's `latest` reference pages for some `billing_v1` classes still display `1.17.0` in their headers. Treat the reference site as the authoritative API surface, but confirm your installed version when exact generated signatures matter.\n- This package covers Cloud Billing account/project linkage and Cloud Catalog data. If you need budgets, BigQuery billing export analysis, or invoices, you need adjacent Google Cloud services or separate libraries.\n\n## Installation\n\nInstall the package directly:\n\n```bash\npython -m pip install google-cloud-billing\n```\n\nPin the package when your project already uses a lockfile or needs reproducible CI:\n\n```bash\npython -m pip install \"google-cloud-billing==1.18.0\"\n```\n\nWith `uv`:\n\n```bash\nuv add google-cloud-billing\n```\n\nWith Poetry:\n\n```bash\npoetry add google-cloud-billing\n```\n\n## Authentication And Setup\n\nPrefer ADC for local development and deployed workloads.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nService-account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/abs/path/service-account.json\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project exists and has billing enabled where required.\n2. The Cloud Billing API is enabled for the project that will call the API.\n3. The caller has the right IAM permissions to view billing accounts or update project billing links.\n\nMinimal initialization:\n\n```python\nfrom google.cloud import billing_v1\n\nbilling_client = billing_v1.CloudBillingClient()\ncatalog_client = billing_v1.CloudCatalogClient()\n```\n\nExplicit credentials:\n\n```python\nfrom google.cloud import billing_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/abs/path/service-account.json\"\n)\n\nclient = billing_v1.CloudBillingClient(credentials=credentials)\n```\n\nAsync variants also exist if your app already uses async Google client patterns:\n\n- `billing_v1.CloudBillingAsyncClient`\n- `billing_v1.CloudCatalogAsyncClient`\n\n## Core Usage\n\n### List Billing Accounts\n\nUse this to discover the billing account resource names your code will reuse later.\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\nfor account in client.list_billing_accounts():\n    print(account.name, account.display_name, account.open)\n```\n\nResource names look like `billingAccounts/000000-000000-000000`.\n\n### Read A Project's Billing State\n\n`get_project_billing_info()` expects a project resource name, not a bare project ID.\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\nproject_name = \"projects/my-project-id\"\ninfo = client.get_project_billing_info(name=project_name)\n\nprint(info.name)\nprint(info.project_id)\nprint(info.billing_account_name)\nprint(info.billing_enabled)\n```\n\nUse this before linking or unlinking a billing account.\n\n### Link Or Unlink A Project Billing Account\n\nTo attach a project to a billing account:\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\nupdated = client.update_project_billing_info(\n    name=\"projects/my-project-id\",\n    project_billing_info=billing_v1.ProjectBillingInfo(\n        billing_account_name=\"billingAccounts/000000-000000-000000\",\n    ),\n)\n\nprint(updated.billing_account_name)\nprint(updated.billing_enabled)\n```\n\nTo disable billing for a project, send an empty billing account name:\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\nupdated = client.update_project_billing_info(\n    name=\"projects/my-project-id\",\n    project_billing_info=billing_v1.ProjectBillingInfo(\n        billing_account_name=\"\",\n    ),\n)\n```\n\n### List Projects Linked To A Billing Account\n\nUse this when you need inventory for one billing account.\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\nbilling_account_name = \"billingAccounts/000000-000000-000000\"\n\nfor project in client.list_project_billing_info(name=billing_account_name):\n    print(project.project_id, project.billing_enabled)\n```\n\n### List Billable Services\n\n`CloudCatalogClient` exposes published Cloud Catalog metadata.\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudCatalogClient()\n\nfor service in client.list_services():\n    print(service.name, service.display_name)\n```\n\nService names look like `services/6F81-5844-456A`.\n\n### List SKUs For A Service\n\nThis is the common path for pricing metadata lookup.\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudCatalogClient()\n\nservice_name = \"services/6F81-5844-456A\"\n\nfor sku in client.list_skus(parent=service_name):\n    print(sku.name)\n    print(sku.description)\n    print(sku.category.resource_family)\n```\n\nIf you need the price metadata effective for a specific window, use the request object and pass `start_time` and `end_time`.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudCatalogClient()\n\nend_time = datetime.now(timezone.utc)\nstart_time = end_time - timedelta(days=30)\n\nrequest = billing_v1.ListSkusRequest(\n    parent=\"services/6F81-5844-456A\",\n    start_time=start_time,\n    end_time=end_time,\n)\n\nfor sku in client.list_skus(request=request):\n    print(sku.name)\n```\n\nTreat catalog data as published SKU metadata, not as live usage or invoice data.\n\n## Request Configuration\n\nGenerated Google Cloud clients follow the standard GAPIC pattern:\n\n- Most methods accept `retry`, `timeout`, and `metadata` keyword arguments.\n- List methods return pagers, so direct iteration is the normal path.\n- Resource names are strings like `projects/my-project-id`, `billingAccounts/...`, and `services/...`.\n\nExample with an explicit timeout:\n\n```python\nfrom google.cloud import billing_v1\n\nclient = billing_v1.CloudBillingClient()\n\ninfo = client.get_project_billing_info(\n    name=\"projects/my-project-id\",\n    timeout=30,\n)\n```\n\n## Configuration And Debugging Notes\n\n- ADC is the default credential flow. Avoid hard-coding credentials into application code.\n- Set `GOOGLE_APPLICATION_CREDENTIALS` only when you intentionally want file-based service-account credentials.\n- The package README documents environment-based logging control through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`. Use `google` or a narrower namespace when debugging client-library RPC behavior.\n- Reuse long-lived clients in app code instead of creating a new client for every request.\n\n## Common Pitfalls\n\n- The package installs as `google-cloud-billing`, but the import path is `google.cloud.billing_v1`.\n- `CloudBillingClient` and `CloudCatalogClient` are separate surfaces. Project billing methods are not on the catalog client, and SKU methods are not on the billing client.\n- `get_project_billing_info()` and `update_project_billing_info()` require `projects/PROJECT_ID`, not just `PROJECT_ID`.\n- `list_project_billing_info()` takes a billing account resource like `billingAccounts/...`, not a project resource.\n- Cloud Catalog results can be large. Cache service and SKU lookups if you call them repeatedly.\n- Do not use catalog prices as a substitute for usage export, invoice reconciliation, or budget enforcement.\n- Be careful with context-manager patterns around generated transports. Shared transports can be closed unexpectedly if you wrap clients in short-lived `with` blocks.\n\n## Version-Sensitive Notes\n\n- This guide targets PyPI version `1.18.0`.\n- The package README and PyPI metadata are already on `1.18.0`, but some Google Cloud reference pages still render `1.17.0` in class headings as of March 12, 2026. If you hit a signature mismatch, inspect your installed package with `python -m pip show google-cloud-billing` and prefer the generated docs for your exact version when available.\n- Older links may still point to `.../python/docs/reference/billing/latest`. Prefer the `cloudbilling` path for current references.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/google-cloud-billing/`\n- Package README in the official monorepo: `https://raw.githubusercontent.com/googleapis/google-cloud-python/main/packages/google-cloud-billing/README.rst`\n- Repository package directory: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing`\n- Cloud Billing Python reference root: `https://cloud.google.com/python/docs/reference/cloudbilling/latest`\n- `CloudBillingClient` reference: `https://cloud.google.com/python/docs/reference/cloudbilling/latest/google.cloud.billing_v1.services.cloud_billing.CloudBillingClient`\n- `CloudCatalogClient` reference: `https://cloud.google.com/python/docs/reference/cloudbilling/latest/google.cloud.billing_v1.services.cloud_catalog.CloudCatalogClient`\n- `ListSkusRequest` reference: `https://cloud.google.com/python/docs/reference/cloudbilling/latest/google.cloud.billing_v1.types.ListSkusRequest`\n- ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n"
  },
  {
    "path": "content/google/docs/binary-authorization/python/DOC.md",
    "content": "---\nname: binary-authorization\ndescription: \"google-cloud-binary-authorization package guide for Python covering ADC setup, project policy reads, attestor lookups, and system-policy workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,binary-authorization,gke,cloud-run,attestations,supply-chain,python\"\n---\n\n# google-cloud-binary-authorization Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-binary-authorization` for Binary Authorization control-plane access from Python, import it as `from google.cloud import binaryauthorization_v1`, and authenticate with Application Default Credentials (ADC).\n\nThis package is for managing and reading Binary Authorization resources such as project policies, system policies, and attestors. It is not the end-to-end image-signing workflow by itself: attestors point at user-owned Grafeas notes, and attestation validation expects an attestation occurrence plus the image URI being checked.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-binary-authorization==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-binary-authorization==1.15.0\"\npoetry add \"google-cloud-binary-authorization==1.15.0\"\n```\n\nPyPI lists support for Python `>=3.7`.\n\n## Authentication And Setup\n\nBefore creating a client:\n\n1. Enable Binary Authorization in the target Google Cloud project.\n2. Use an identity with Binary Authorization IAM permissions on the project you are managing.\n3. Prefer ADC over embedding credentials in code.\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nService-account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n\n# Optional generated-client logging\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google.cloud.binaryauthorization_v1\"\n```\n\n## Imports And Client Initialization\n\nThe package exposes separate clients for management, system policy, and attestation validation:\n\n```python\nimport os\n\nfrom google.cloud import binaryauthorization_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nmanagement_client = binaryauthorization_v1.BinauthzManagementServiceV1Client()\nsystem_policy_client = binaryauthorization_v1.SystemPolicyV1Client()\nvalidation_client = binaryauthorization_v1.ValidationHelperV1Client()\n```\n\nIf you need explicit credentials instead of ADC:\n\n```python\nfrom google.oauth2 import service_account\nfrom google.cloud import binaryauthorization_v1\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nmanagement_client = binaryauthorization_v1.BinauthzManagementServiceV1Client(\n    credentials=credentials,\n)\n```\n\n## Resource Names\n\nThe generated clients expect fully qualified resource names. The ones you use most often are:\n\n- project policy: `projects/{project}/policy`\n- attestor parent: `projects/{project}`\n- attestor: `projects/{project}/attestors/{attestor}`\n- system policy: `locations/{location}/policy`\n\nKeep these strings explicit in your code. Passing short IDs instead of canonical names is a common cause of `InvalidArgument` and `NotFound` errors.\n\n## Core Workflows\n\n### Read The Project Policy\n\nUse `get_policy()` to inspect the Binary Authorization policy attached to one project:\n\n```python\nfrom google.cloud import binaryauthorization_v1\n\nclient = binaryauthorization_v1.BinauthzManagementServiceV1Client()\npolicy_name = f\"projects/{project_id}/policy\"\n\npolicy = client.get_policy(\n    request=binaryauthorization_v1.GetPolicyRequest(\n        name=policy_name,\n    )\n)\n\nprint(policy.name)\nprint(policy.default_admission_rule)\n```\n\nThis is the safest first call when you want to confirm auth, permissions, and the current policy shape before changing anything.\n\n### List Attestors In A Project\n\nAttestors are project-scoped resources:\n\n```python\nfrom google.cloud import binaryauthorization_v1\n\nclient = binaryauthorization_v1.BinauthzManagementServiceV1Client()\nparent = f\"projects/{project_id}\"\n\nfor attestor in client.list_attestors(\n    request=binaryauthorization_v1.ListAttestorsRequest(parent=parent)\n):\n    print(attestor.name)\n    print(attestor.description)\n```\n\nThe pager yields `Attestor` resources directly. Reuse the same client instead of recreating it inside tight loops.\n\n### Read One Attestor\n\nUse the fully qualified attestor name:\n\n```python\nfrom google.cloud import binaryauthorization_v1\n\nclient = binaryauthorization_v1.BinauthzManagementServiceV1Client()\nattestor_name = f\"projects/{project_id}/attestors/{attestor_id}\"\n\nattestor = client.get_attestor(\n    request=binaryauthorization_v1.GetAttestorRequest(\n        name=attestor_name,\n    )\n)\n\nprint(attestor.name)\nprint(attestor.user_owned_grafeas_note.note_reference)\n```\n\nFor user-owned attestors, the important linkage is `user_owned_grafeas_note.note_reference`. That note must already exist in Artifact Analysis / Grafeas.\n\n### Create An Attestor\n\nCreate attestors with a project parent, an `attestor_id`, and an `Attestor` message. The `Attestor` type includes a `user_owned_grafeas_note` that carries the note reference and public keys.\n\n```python\nfrom google.cloud import binaryauthorization_v1\n\nclient = binaryauthorization_v1.BinauthzManagementServiceV1Client()\nparent = f\"projects/{project_id}\"\n\nattestor = binaryauthorization_v1.Attestor(\n    description=\"CI attestor\",\n    user_owned_grafeas_note=binaryauthorization_v1.UserOwnedGrafeasNote(\n        note_reference=f\"projects/{project_id}/notes/{note_id}\",\n    ),\n)\n\noperation = client.create_attestor(\n    request=binaryauthorization_v1.CreateAttestorRequest(\n        parent=parent,\n        attestor_id=attestor_id,\n        attestor=attestor,\n    )\n)\n\ncreated = operation.result()\nprint(created.name)\n```\n\nFor a real attestor, populate the `public_keys` on `UserOwnedGrafeasNote` with the keys your signer uses. Keep the note resource and key material aligned with the attestation workflow your platform already uses.\n\n### Read The System Policy\n\nSystem policy is location-scoped rather than project-scoped:\n\n```python\nfrom google.cloud import binaryauthorization_v1\n\nclient = binaryauthorization_v1.SystemPolicyV1Client()\nname = f\"locations/{location}/policy\"\n\nsystem_policy = client.get_system_policy(\n    request=binaryauthorization_v1.GetSystemPolicyRequest(name=name)\n)\n\nprint(system_policy.name)\n```\n\nUse this when you need to inspect Google-managed defaults that apply alongside your project policy.\n\n### Validate An Attestation Occurrence\n\n`ValidationHelperV1Client` exposes `validate_attestation_occurrence()`. The request takes:\n\n- `attestor`: `projects/{project}/attestors/{attestor}`\n- `attestation`: the attestation occurrence to verify\n- `gcr_image_uri`: the container image URI being checked\n\nUse this helper when you already have an attestation occurrence object and need Binary Authorization to verify that it matches the attestor and image URI.\n\n## Updating Policy Safely\n\n`BinauthzManagementServiceV1Client` also exposes `update_policy()`, `create_attestor()`, `update_attestor()`, and delete operations. In practice:\n\n- read the current policy with `get_policy()` first\n- modify only the fields you intend to change\n- send the updated policy back with `update_policy()`\n- avoid generating policy resources from scratch unless you control every field being written\n\nThat keeps automation from accidentally replacing admission rules or cluster/image allowlists you did not intend to touch.\n\n## Common Pitfalls\n\n- Do not confuse project policy and system policy resource names. Project policy uses `projects/{project}/policy`; system policy uses `locations/{location}/policy`.\n- Attestors are not standalone signing identities. They are Binary Authorization resources that reference user-owned Grafeas notes and key material.\n- `validate_attestation_occurrence()` is not a shortcut for creating attestations. You still need an actual attestation occurrence from your signing pipeline.\n- This package manages Binary Authorization resources; it does not build images, sign artifacts, or create Grafeas notes for you.\n- ADC problems and IAM problems look similar. Verify both authentication and Binary Authorization permissions before debugging request shapes.\n- Generated Google clients accept canonical resource names, not partial IDs. Build the full `projects/...` or `locations/...` path explicitly.\n\n## Version Notes\n\n- This guide covers PyPI package version `1.15.0`.\n- The Google Cloud Python reference root and the `ValidationHelperV1Client` page were current for `1.15.0` when checked on `2026-03-13`.\n- PyPI lists the package under the Google-maintained `google-cloud-binary-authorization` name. Use that exact package name when pinning dependencies.\n\n## Official Sources\n\n- Python client reference root: `https://cloud.google.com/python/docs/reference/binaryauthorization/latest`\n- `ValidationHelperV1Client` reference: `https://cloud.google.com/python/docs/reference/binaryauthorization/latest/google.cloud.binaryauthorization_v1.services.validation_helper_v1.ValidationHelperV1Client`\n- Python package summary classes: `https://cloud.google.com/python/docs/reference/binaryauthorization/latest/summary_class`\n- Python package summary methods: `https://cloud.google.com/python/docs/reference/binaryauthorization/latest/summary_method`\n- RPC reference (`Policy`, `Attestor`, `UserOwnedGrafeasNote`, request types): `https://cloud.google.com/binary-authorization/docs/reference/rpc/google.cloud.binaryauthorization.v1beta1`\n- RPC reference (`SystemPolicy`): `https://cloud.google.com/binary-authorization/docs/reference/rpc/google.cloud.binaryauthorization.v1`\n- Google Cloud ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- PyPI package page: `https://pypi.org/project/google-cloud-binary-authorization/`\n"
  },
  {
    "path": "content/google/docs/build/python/DOC.md",
    "content": "---\nname: build\ndescription: \"Google Cloud Build Python client for submitting builds, inspecting status, approving gated builds, and managing build triggers\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.35.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,cloud-build,cicd,builds,triggers,gcp,python\"\n---\n\n# google-cloud-build Python Package Guide\n\nUse `google-cloud-build` for Cloud Build control-plane automation in Python: submit builds, inspect build state, approve gated builds, and manage triggers.\n\nImport surface:\n\n```python\nfrom google.cloud.devtools import cloudbuild_v1\n```\n\n## Golden Rule\n\n- Install the official client and import `cloudbuild_v1` from `google.cloud.devtools`.\n- Authenticate with Application Default Credentials (ADC), not hard-coded OAuth tokens.\n- Pick `global` or a regional location deliberately and keep your `parent` resource name consistent with that choice.\n- Treat `create_build` as a long-running operation and wait for `operation.result()` before assuming the build finished.\n- If you set a user-specified service account on a build or trigger, also send logs to Cloud Logging or a user-owned bucket. Cloud Build does not let that service-account mode use the default logs bucket.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-build==3.35.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-build==3.35.0\"\npoetry add \"google-cloud-build==3.35.0\"\n```\n\n## Authentication And Setup\n\nEnable the API and authenticate with ADC:\n\n```bash\ngcloud services enable cloudbuild.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"   # or \"global\"\n```\n\nIf you need file-based service account credentials instead of the local ADC login flow:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nMinimal client setup:\n\n```python\nimport os\n\nfrom google.cloud.devtools import cloudbuild_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = cloudbuild_v1.CloudBuildClient()\n```\n\nCloud Build supports both `global` and regional resources. If your build config uses regional private pools, regional repositories, or regional triggers, keep the build location aligned with those resources and use the matching regional Cloud Build endpoint in environments where endpoint selection matters.\n\n## Submit A Build\n\nThis example submits a Docker build from a source archive already stored in Cloud Storage. `StorageSource.object_` is the archive object key inside the bucket.\n\n```python\nimport os\n\nfrom google.cloud.devtools import cloudbuild_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = cloudbuild_v1.CloudBuildClient()\nimage_uri = f\"{location}-docker.pkg.dev/{project_id}/apps/web:latest\"\n\nbuild = cloudbuild_v1.Build(\n    steps=[\n        cloudbuild_v1.BuildStep(\n            name=\"gcr.io/cloud-builders/docker\",\n            args=[\"build\", \"-t\", image_uri, \".\"],\n        ),\n    ],\n    images=[image_uri],\n    source=cloudbuild_v1.Source(\n        storage_source=cloudbuild_v1.StorageSource(\n            bucket=\"my-source-bucket\",\n            object_=\"source/app.tar.gz\",\n        )\n    ),\n    options=cloudbuild_v1.BuildOptions(\n        logging=cloudbuild_v1.BuildOptions.LoggingMode.CLOUD_LOGGING_ONLY,\n    ),\n)\n\noperation = client.create_build(parent=parent, build=build)\nresult = operation.result()\n\nprint(result.id)\nprint(result.status)\nprint(result.log_url)\n```\n\nUse inline `Build.steps` when your automation already knows the build steps. If you need Cloud Build to read `cloudbuild.yaml`, create or run a trigger instead of assuming `create_build` will discover that file automatically.\n\n## Inspect Build Status\n\nList recent builds for a project:\n\n```python\nimport os\n\nfrom google.cloud.devtools import cloudbuild_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nclient = cloudbuild_v1.CloudBuildClient()\n\nfor build in client.list_builds(project_id=project_id):\n    print(build.id, build.status, build.create_time)\n```\n\nFetch one build by ID:\n\n```python\nimport os\n\nfrom google.cloud.devtools import cloudbuild_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nbuild_id = \"your-build-id\"\n\nclient = cloudbuild_v1.CloudBuildClient()\nbuild = client.get_build(project_id=project_id, id=build_id)\n\nprint(build.status)\nprint(build.log_url)\nprint(build.images)\n```\n\nIf a build fails and you want Cloud Build to rerun it with the same configuration, the same client exposes `retry_build(project_id=..., id=...)`.\n\n## Approve A Pending Build\n\nWhen a trigger or build config requires approval, use `approve_build` with an `ApprovalResult`.\n\n```python\nimport os\n\nfrom google.cloud.devtools import cloudbuild_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nbuild_id = \"your-build-id\"\n\nclient = cloudbuild_v1.CloudBuildClient()\n\napproved = client.approve_build(\n    project_id=project_id,\n    id=build_id,\n    approval_result=cloudbuild_v1.ApprovalResult(\n        decision=cloudbuild_v1.ApprovalResult.Decision.APPROVED,\n        comment=\"Approved by release automation\",\n    ),\n)\n\nprint(approved.status)\n```\n\nRejecting a build uses the same call with `Decision.REJECTED`.\n\n## Build Triggers\n\nThe same client manages trigger resources:\n\n- `create_build_trigger(...)`\n- `list_build_triggers(...)`\n- `get_build_trigger(...)`\n- `update_build_trigger(...)`\n- `delete_build_trigger(...)`\n- `run_build_trigger(...)`\n\nUse triggers when you want Cloud Build to watch a repository event or reuse a stored build definition such as `cloudbuild.yaml`. Keep trigger location aligned with the repository or private pool location when the product docs call that out.\n\n## Secrets And Service Accounts\n\nCloud Build supports Secret Manager-backed environment variables in build steps, but there are two easy ways to get this wrong:\n\n- Secret values must be wired through the build config using `availableSecrets` plus `secretEnv`; they are not injected automatically just because the build service account can access Secret Manager.\n- When you reference a secret from a `bash` command in the build config, use `$$VAR_NAME` so Cloud Build substitutes the secret at execution time instead of your shell expanding it early.\n\nService account rules that matter in practice:\n\n- If you set `service_account` on a build or trigger, also set a supported log destination. The default logs bucket is not allowed with user-specified service accounts.\n- Be careful granting Secret Manager access to legacy Cloud Build service accounts on trigger-based builds. Google’s Secret Manager guide calls out that anyone who can run that trigger would inherit the secret access available to the trigger’s service account.\n\n## Common Pitfalls\n\n- `global` and regional resources are not interchangeable. A mismatched `parent` like `projects/x/locations/global` versus `projects/x/locations/us-central1` is a common cause of confusing `NotFound` and permission failures.\n- `create_build` returns a long-running operation. If later code depends on the image or artifact existing, wait for `operation.result()`.\n- `StorageSource.object_` is the object key in Cloud Storage, not a local filesystem path.\n- Build steps run inside builder containers such as `gcr.io/cloud-builders/docker`. Installing `google-cloud-build` locally does not give your build step images extra tools.\n- `approve_build` only works for builds that are actually waiting on approval. Read the build first if your automation is unsure about current state.\n\n## Version Notes\n\n- PyPI currently lists `google-cloud-build 3.35.0`.\n- The generated Python reference pages for `CloudBuildClient`, `Build`, `BuildStep`, `Source`, and `StorageSource` also render under the `3.35.0` docs tree.\n- The generated changelog page still stops at `3.34.0`, so use the class reference pages and PyPI as the source of truth for the current 3.35.0 client surface.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-build/\n- Maintainer package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-build\n- Python reference root: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest\n- `CloudBuildClient` reference: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest/google.cloud.devtools.cloudbuild_v1.services.cloud_build.CloudBuildClient\n- `Build` reference: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest/google.cloud.devtools.cloudbuild_v1.types.Build\n- `BuildStep` reference: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest/google.cloud.devtools.cloudbuild_v1.types.BuildStep\n- `Source` reference: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest/google.cloud.devtools.cloudbuild_v1.types.Source\n- `StorageSource` reference: https://docs.cloud.google.com/python/docs/reference/cloudbuild/latest/google.cloud.devtools.cloudbuild_v1.types.StorageSource\n- Configure regional endpoints and locations: https://cloud.google.com/build/docs/locations\n- Use secrets from Secret Manager: https://cloud.google.com/build/docs/securing-builds/use-secrets\n"
  },
  {
    "path": "content/google/docs/certificate-manager/python/DOC.md",
    "content": "---\nname: certificate-manager\ndescription: \"Google Cloud Certificate Manager Python client for DNS authorizations, managed and self-managed certificates, and certificate maps\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,certificate-manager,tls,ssl,load-balancing,dns,python\"\n---\n\n# google-cloud-certificate-manager Python Package Guide\n\nUse `google-cloud-certificate-manager` for Python code that manages Certificate Manager resources in Google Cloud: DNS authorizations, Google-managed certificates, self-managed certificates, certificate maps, and certificate map entries.\n\n## Golden Rule\n\n- Install and import the official client: `from google.cloud import certificate_manager_v1`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass explicit credentials.\n- Keep the resource location explicit. The common Certificate Manager workflows in the official docs use `locations/global`.\n- Treat create, update, and delete calls as long-running operations and wait on `operation.result()`.\n- For Google-managed certificates, create the DNS authorization first and publish the returned CNAME record before expecting issuance to complete.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-certificate-manager==1.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-certificate-manager==1.12.0\"\npoetry add \"google-cloud-certificate-manager==1.12.0\"\n```\n\nPyPI currently lists Python `>=3.7` for this package.\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nIf you must use a service-account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nBefore calling the API:\n\n1. Enable Certificate Manager on the target project.\n2. Make sure the credential has permission to manage Certificate Manager resources in that project.\n3. Decide which location you are targeting. The examples below use `global`, which matches the common product documentation flows for certificates, DNS authorizations, and certificate maps.\n\n## Initialize The Client\n\nBasic client initialization with ADC:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n```\n\nExplicit credentials also work:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\nfrom google.oauth2 import service_account\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nclient = certificate_manager_v1.CertificateManagerClient(credentials=credentials)\n```\n\n## Core Usage\n\n### List certificates\n\nList methods return pagers, so normal iteration handles pagination:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n\nfor certificate in client.list_certificates(request={\"parent\": parent}):\n    print(certificate.name)\n```\n\n### Create a DNS authorization\n\nCertificate Manager returns the DNS record you must publish for domain control validation:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n\noperation = client.create_dns_authorization(\n    request={\n        \"parent\": parent,\n        \"dns_authorization_id\": \"example-com-auth\",\n        \"dns_authorization\": {\n            \"domain\": \"example.com\",\n        },\n    }\n)\n\ndns_authorization = operation.result(timeout=600)\nrecord = dns_authorization.dns_resource_record\n\nprint(\"Create this DNS record before requesting a managed certificate:\")\nprint(record.name)\nprint(record.type_)\nprint(record.data)\n```\n\nThe product docs describe this record as the CNAME you add to your DNS zone for authorization.\n\n### Create a Google-managed certificate\n\nAfter the DNS authorization exists and its CNAME record is published, create the managed certificate and reference the authorization resource name:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n\ndns_authorization_name = (\n    f\"{parent}/dnsAuthorizations/example-com-auth\"\n)\n\noperation = client.create_certificate(\n    request={\n        \"parent\": parent,\n        \"certificate_id\": \"example-com-cert\",\n        \"certificate\": {\n            \"managed\": {\n                \"domains\": [\"example.com\"],\n                \"dns_authorizations\": [dns_authorization_name],\n            }\n        },\n    }\n)\n\ncertificate = operation.result(timeout=600)\nprint(certificate.name)\n```\n\nCertificate creation is asynchronous. The resource can exist before Google finishes provisioning and attaching the certificate material, so plan for DNS propagation and issuance time.\n\n### Upload a self-managed certificate\n\nSelf-managed certificates use PEM content, not a `.p12` or other binary bundle:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n\nwith open(\"fullchain.pem\", \"r\", encoding=\"utf-8\") as cert_file:\n    pem_certificate = cert_file.read()\n\nwith open(\"privkey.pem\", \"r\", encoding=\"utf-8\") as key_file:\n    pem_private_key = key_file.read()\n\noperation = client.create_certificate(\n    request={\n        \"parent\": parent,\n        \"certificate_id\": \"self-managed-cert\",\n        \"certificate\": {\n            \"self_managed\": {\n                \"pem_certificate\": pem_certificate,\n                \"pem_private_key\": pem_private_key,\n            }\n        },\n    }\n)\n\ncertificate = operation.result(timeout=600)\nprint(certificate.name)\n```\n\n### Create a certificate map and map entry\n\nCertificate maps let you bind hostnames to certificates for supported load-balancing integrations:\n\n```python\nimport os\n\nfrom google.cloud import certificate_manager_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = certificate_manager_v1.CertificateManagerClient()\n\nmap_operation = client.create_certificate_map(\n    request={\n        \"parent\": parent,\n        \"certificate_map_id\": \"edge-map\",\n        \"certificate_map\": {},\n    }\n)\ncertificate_map = map_operation.result(timeout=600)\n\ncertificate_name = f\"{parent}/certificates/example-com-cert\"\n\nentry_operation = client.create_certificate_map_entry(\n    request={\n        \"parent\": certificate_map.name,\n        \"certificate_map_entry_id\": \"example-com\",\n        \"certificate_map_entry\": {\n            \"hostname\": \"example.com\",\n            \"certificates\": [certificate_name],\n        },\n    }\n)\nentry = entry_operation.result(timeout=600)\nprint(entry.name)\n```\n\n## Common Pitfalls\n\n- `create_*`, `update_*`, and `delete_*` methods return long-running operations. If you skip `operation.result()`, your script will usually exit before the server-side work finishes.\n- The DNS authorization step gives you the authoritative CNAME record to publish. Do not guess the record name or value.\n- Google-managed certificate issuance depends on the DNS authorization record being published and propagated.\n- Self-managed certificate uploads require PEM text in `pem_certificate` and `pem_private_key`.\n- The package uses the import path `google.cloud.certificate_manager_v1`, even though the PyPI package name is `google-cloud-certificate-manager`.\n- Certificate map entries are created under the certificate map resource name, not directly under the location parent.\n- The product docs note that you must remove certificate map entries and detach the map from target proxies before deleting a certificate map.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-certificate-manager 1.12.0`.\n- The generated Python client reference for `CertificateManagerClient` is already published under the `1.12.0` docs path.\n- Some generated type pages under the `latest` docs root still render older version labels such as `1.11.0`. When that happens, prefer the current package version on PyPI and the current client-method reference pages for method names and request shapes.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-certificate-manager/\n- Maintainer package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-certificate-manager\n- Python reference root: https://cloud.google.com/python/docs/reference/certificate-manager/latest\n- `CertificateManagerClient` reference: https://cloud.google.com/python/docs/reference/certificate-manager/latest/google.cloud.certificate_manager_v1.services.certificate_manager.CertificateManagerClient\n- `DnsAuthorization` reference: https://cloud.google.com/python/docs/reference/certificate-manager/latest/google.cloud.certificate_manager_v1.types.DnsAuthorization\n- `DnsAuthorization.DnsResourceRecord` reference: https://cloud.google.com/python/docs/reference/certificate-manager/latest/google.cloud.certificate_manager_v1.types.DnsAuthorization.DnsResourceRecord\n- Certificate Manager API reference: https://cloud.google.com/certificate-manager/docs/reference/certificate-manager/rpc/google.cloud.certificatemanager.v1\n- Create and deploy Google-managed certificates: https://cloud.google.com/certificate-manager/docs/deploy-google-managed-dns-auth\n- Create and deploy self-managed certificates: https://cloud.google.com/certificate-manager/docs/deploy-self-managed-dns-auth\n- Manage certificate maps: https://cloud.google.com/certificate-manager/docs/maps\n"
  },
  {
    "path": "content/google/docs/channel/python/DOC.md",
    "content": "---\nname: channel\ndescription: \"Google Cloud Channel Python client for reseller customer management, SKU discovery, offers, and entitlements\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.26.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,cloud-channel,reseller,subscriptions,customers,entitlements,python\"\n---\n\n# google-cloud-channel Python Package Guide\n\n## What It Is\n\n`google-cloud-channel` is the official Python client for the Google Cloud Channel API. It is for reseller flows: managing customers, browsing purchasable SKUs and offers, and inspecting entitlements under a reseller account.\n\nUse this package when your integration already has Cloud Channel reseller access and you need to call resource paths such as `accounts/{account_id}` and `accounts/{account_id}/customers/{customer_id}` from Python.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-channel==1.26.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-channel==1.26.0\"\npoetry add \"google-cloud-channel==1.26.0\"\n```\n\nPyPI currently lists `Requires: Python >=3.7`.\n\n## Authentication And Setup\n\nUse Google Application Default Credentials (ADC). For local development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_ACCOUNT_ID=\"1234567890\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_ACCOUNT_ID=\"1234567890\"\n```\n\nImportant setup notes:\n\n- Most requests need your reseller account resource in the form `accounts/{account_id}`.\n- Customer-scoped requests use names such as `accounts/{account_id}/customers/{customer_id}`.\n- Install `google-auth` separately only when you need to work with credential objects directly; the Cloud Channel client uses ADC underneath.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import channel_v1\n\nACCOUNT_ID = os.environ[\"GOOGLE_CLOUD_ACCOUNT_ID\"]\nACCOUNT_NAME = f\"accounts/{ACCOUNT_ID}\"\n\nclient = channel_v1.CloudChannelServiceClient()\n```\n\nIf you need to override the endpoint or mTLS behavior, the generated client supports standard Google API client options and environment variables such as `GOOGLE_API_USE_MTLS_ENDPOINT` and `GOOGLE_API_USE_CLIENT_CERTIFICATE`.\n\n## Core Workflows\n\n### List Customers\n\n```python\nimport os\n\nfrom google.cloud import channel_v1\n\naccount_name = f\"accounts/{os.environ['GOOGLE_CLOUD_ACCOUNT_ID']}\"\nclient = channel_v1.CloudChannelServiceClient()\n\nrequest = channel_v1.ListCustomersRequest(parent=account_name)\n\nfor customer in client.list_customers(request=request):\n    print(customer.name, customer.org_display_name)\n```\n\n### Get One Customer\n\n```python\nfrom google.cloud import channel_v1\n\nclient = channel_v1.CloudChannelServiceClient()\n\nrequest = channel_v1.GetCustomerRequest(\n    name=\"accounts/1234567890/customers/C012abcde\"\n)\n\ncustomer = client.get_customer(request=request)\nprint(customer.org_display_name)\n```\n\n### Create A Customer\n\n`create_customer` requires `Customer.org_display_name`, `Customer.org_postal_address`, and one of `Customer.domain` or `Customer.cloud_identity_id`.\n\n```python\nimport os\n\nfrom google.cloud import channel_v1\nfrom google.type.postal_address_pb2 import PostalAddress\n\naccount_name = f\"accounts/{os.environ['GOOGLE_CLOUD_ACCOUNT_ID']}\"\nclient = channel_v1.CloudChannelServiceClient()\n\nrequest = channel_v1.CreateCustomerRequest(\n    parent=account_name,\n    customer=channel_v1.Customer(\n        org_display_name=\"Example Resold Customer\",\n        domain=\"example.com\",\n        org_postal_address=PostalAddress(\n            region_code=\"US\",\n            postal_code=\"94043\",\n            administrative_area=\"CA\",\n            locality=\"Mountain View\",\n            address_lines=[\"1600 Amphitheatre Parkway\"],\n        ),\n    ),\n)\n\ncustomer = client.create_customer(request=request)\nprint(customer.name)\n```\n\n### List Purchasable SKUs For A Customer\n\nUse the full customer resource name, not just the account id.\n\n```python\nfrom google.cloud import channel_v1\n\nclient = channel_v1.CloudChannelServiceClient()\n\nrequest = channel_v1.ListPurchasableSkusRequest(\n    customer=\"accounts/1234567890/customers/C012abcde\"\n)\n\nfor sku in client.list_purchasable_skus(request=request):\n    print(sku.name)\n```\n\n### List Entitlements For A Customer\n\n```python\nfrom google.cloud import channel_v1\n\nclient = channel_v1.CloudChannelServiceClient()\n\nrequest = channel_v1.ListEntitlementsRequest(\n    parent=\"accounts/1234567890/customers/C012abcde\"\n)\n\nfor entitlement in client.list_entitlements(request=request):\n    print(entitlement.name)\n```\n\n## Async Usage\n\nThe package also exposes `CloudChannelServiceAsyncClient` with the same resource-name patterns and request types:\n\n```python\nimport asyncio\nimport os\n\nfrom google.cloud import channel_v1\n\n\nasync def main() -> None:\n    client = channel_v1.CloudChannelServiceAsyncClient()\n    request = channel_v1.ListCustomersRequest(\n        parent=f\"accounts/{os.environ['GOOGLE_CLOUD_ACCOUNT_ID']}\"\n    )\n\n    async for customer in client.list_customers(request=request):\n        print(customer.name)\n\n\nasyncio.run(main())\n```\n\n## Common Pitfalls\n\n- Install `google-cloud-channel`, but import from `google.cloud import channel_v1`.\n- Do not pass bare ids where the API expects full resource names. Use `accounts/{account_id}` and `accounts/{account_id}/customers/{customer_id}` exactly.\n- `create_customer` is stricter than older blog posts imply: the generated request docs require an org display name, an org postal address, and either a domain or a Cloud Identity id.\n- `list_purchasable_skus` uses the customer resource name. It does not accept only an account-level parent.\n- The package README on PyPI says the report service module was deprecated in `1.20.0`; for reporting flows, use the Cloud Channel Reports API package instead of adding new dependencies on the deprecated report service module here.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `1.26.0`, but the generated reference pages under the current `latest` docs tree still display `1.25.0` in page chrome. If you are debugging a behavior difference, trust your installed package version first and then confirm the generated surface in the reference docs.\n- The current package metadata on PyPI requires Python `>=3.7`.\n\n## Official Sources\n\n- PyPI: `https://pypi.org/project/google-cloud-channel/`\n- Package docs root: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest`\n- `CloudChannelServiceClient` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.services.cloud_channel_service.CloudChannelServiceClient`\n- `ListCustomersRequest` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.types.ListCustomersRequest`\n- `CreateCustomerRequest` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.types.CreateCustomerRequest`\n- `Customer` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.types.Customer`\n- `ListPurchasableSkusRequest` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.types.ListPurchasableSkusRequest`\n- `ListEntitlementsRequest` reference: `https://docs.cloud.google.com/python/docs/reference/cloudchannel/latest/google.cloud.channel_v1.types.ListEntitlementsRequest`\n- API overview: `https://cloud.google.com/channel/docs/reference/rest`\n- ADC setup: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/compute/javascript/DOC.md",
    "content": "---\nname: compute\ndescription: \"Google Cloud Compute Engine Node.js client for listing, inspecting, and managing VM resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-compute,gcp,google-cloud,compute-engine,vm,javascript,nodejs\"\n---\n\n# `@google-cloud/compute` JavaScript Package Guide\n\nUse `@google-cloud/compute` when your Node.js app needs to inspect or manage Compute Engine resources such as VM instances, images, networks, disks, and the operations returned by mutating calls.\n\nThis package is organized as resource-specific generated clients. For most instance workflows, use `v1.InstancesClient`, `v1.ImagesClient`, and the matching operations client for the resource scope.\n\nThis guide covers `6.8.0`.\n\n## Install\n\n```bash\nnpm install @google-cloud/compute@6.8.0\n```\n\n## Authentication And Setup\n\nTypical prerequisites:\n\n1. A Google Cloud project ID.\n2. The Compute Engine API enabled for that project.\n3. Credentials with permission to read or mutate the target Compute Engine resources.\n4. The correct zone, region, or global scope for the API you are calling.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable compute.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n## Initialize Clients\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst instancesClient = new v1.InstancesClient();\nconst imagesClient = new v1.ImagesClient();\nconst zoneOperationsClient = new v1.ZoneOperationsClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/compute';\n\nconst instancesClient = new v1.InstancesClient();\nconst imagesClient = new v1.ImagesClient();\nconst zoneOperationsClient = new v1.ZoneOperationsClient();\n```\n\nWith explicit project ID and credential file:\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst instancesClient = new v1.InstancesClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nUse the client that matches the resource scope:\n\n- `v1.InstancesClient` for zonal VM instance operations.\n- `v1.ImagesClient` for image and image-family lookups.\n- `v1.ZoneOperationsClient` for zonal operations returned by instance mutations.\n- `v1.RegionOperationsClient` or `v1.GlobalOperationsClient` when the API you called returns a regional or global operation instead.\n\n## Core Workflows\n\n### List Instances In A Zone\n\nUse the async iterator so the client handles pagination.\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst client = new v1.InstancesClient();\n\nasync function listInstances(projectId, zone) {\n  const instances = [];\n\n  for await (const instance of client.listAsync({\n    project: projectId,\n    zone,\n  })) {\n    instances.push({\n      name: instance.name,\n      status: instance.status,\n      machineType: instance.machineType,\n    });\n  }\n\n  return instances;\n}\n```\n\n### Get One Instance\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst client = new v1.InstancesClient();\n\nasync function getInstance(projectId, zone, instanceName) {\n  const [instance] = await client.get({\n    project: projectId,\n    zone,\n    instance: instanceName,\n  });\n\n  return instance;\n}\n```\n\n### Resolve An Image Family Before Creating A VM\n\nUse an image family lookup instead of hard-coding a specific image self link.\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst client = new v1.ImagesClient();\n\nasync function getDebianImage() {\n  const [image] = await client.getFromFamily({\n    project: 'debian-cloud',\n    family: 'debian-12',\n  });\n\n  return image.selfLink;\n}\n```\n\n### Wait For A Zonal Operation\n\nCompute Engine mutation methods usually return an operation resource. Wait for it before assuming the change completed.\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst operationsClient = new v1.ZoneOperationsClient();\n\nasync function waitForZonalOperation(projectId, zone, operationName) {\n  while (true) {\n    const [operation] = await operationsClient.wait({\n      project: projectId,\n      zone,\n      operation: operationName,\n    });\n\n    const errors = operation.error?.errors ?? [];\n    if (errors.length > 0) {\n      throw new Error(\n        errors.map(entry => entry.message || entry.code).join('; ')\n      );\n    }\n\n    if (operation.status === 'DONE') {\n      return operation;\n    }\n\n    operationName = operation.name;\n  }\n}\n```\n\n### Start Or Stop An Instance\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst client = new v1.InstancesClient();\n\nasync function startInstance(projectId, zone, instanceName) {\n  const [operation] = await client.start({\n    project: projectId,\n    zone,\n    instance: instanceName,\n  });\n\n  return waitForZonalOperation(projectId, zone, operation.name);\n}\n\nasync function stopInstance(projectId, zone, instanceName) {\n  const [operation] = await client.stop({\n    project: projectId,\n    zone,\n    instance: instanceName,\n  });\n\n  return waitForZonalOperation(projectId, zone, operation.name);\n}\n```\n\n### Create A Small Debian VM\n\nThis is the minimal pattern for creating a VM from an image family lookup.\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst imagesClient = new v1.ImagesClient();\nconst instancesClient = new v1.InstancesClient();\n\nasync function createInstance(projectId, zone, instanceName) {\n  const [image] = await imagesClient.getFromFamily({\n    project: 'debian-cloud',\n    family: 'debian-12',\n  });\n\n  const [operation] = await instancesClient.insert({\n    project: projectId,\n    zone,\n    instanceResource: {\n      name: instanceName,\n      machineType: `zones/${zone}/machineTypes/e2-micro`,\n      disks: [\n        {\n          boot: true,\n          autoDelete: true,\n          initializeParams: {\n            sourceImage: image.selfLink,\n          },\n        },\n      ],\n      networkInterfaces: [\n        {\n          name: 'global/networks/default',\n        },\n      ],\n    },\n  });\n\n  return waitForZonalOperation(projectId, zone, operation.name);\n}\n```\n\n### Delete An Instance\n\n```javascript\nconst {v1} = require('@google-cloud/compute');\n\nconst client = new v1.InstancesClient();\n\nasync function deleteInstance(projectId, zone, instanceName) {\n  const [operation] = await client.delete({\n    project: projectId,\n    zone,\n    instance: instanceName,\n  });\n\n  return waitForZonalOperation(projectId, zone, operation.name);\n}\n```\n\n## Practical Notes\n\n- Prefer environment variables or app configuration for `project`, `zone`, and `region` instead of hard-coding them inside helpers.\n- Use full Compute Engine resource paths where the API expects them, such as `zones/us-central1-a/machineTypes/e2-micro` and `global/networks/default`.\n- Keep the operations client aligned with the resource scope. Instance methods return zonal operations, but other APIs may return regional or global operations.\n- Create clients after `fork()` if your app uses child processes.\n\n## Common Pitfalls\n\n- `@google-cloud/compute` is the package name, but the code uses resource-specific clients from the `v1` namespace.\n- Mutating methods such as `insert`, `delete`, `start`, and `stop` do not mean the resource is ready when the first promise resolves. Wait for the returned operation.\n- A zone like `us-central1-a` is not interchangeable with a region like `us-central1`. Use the scope required by the method you are calling.\n- Many request fields expect Compute Engine resource names, not shorthand values.\n- If your code runs on Google Cloud, prefer attached service-account credentials through ADC instead of shipping JSON key files.\n\n## Official Sources\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/compute/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/compute`\n- ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Compute Engine sample index: `https://cloud.google.com/compute/docs/samples`\n"
  },
  {
    "path": "content/google/docs/compute/python/DOC.md",
    "content": "---\nname: compute\ndescription: \"Python package guide for google-cloud-compute, the Google Cloud Compute Engine client library\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.45.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-compute,gcp,google-cloud,compute-engine,vm,python\"\n---\n\n# google-cloud-compute Python Package Guide\n\n`google-cloud-compute` is the generated Python client for Google Cloud Compute Engine.\nInstall the package from PyPI, import `compute_v1`, authenticate with Application Default Credentials (ADC), and use the resource-specific client for the thing you are managing.\n\n```python\nfrom google.cloud import compute_v1\n```\n\n## Install\n\n```bash\npip install google-cloud-compute==1.45.0\n```\n\nUse the PyPI package name in dependency files and the `google.cloud.compute_v1` import path in code.\n\nPyPI currently lists:\n\n- Package version: `1.45.0`\n- Python requirement: `>=3.7`\n\n## Setup And Authentication\n\nTypical prerequisites:\n\n- a Google Cloud project ID\n- the Compute Engine API enabled for that project\n- credentials with the required IAM permissions\n- the correct zone, region, or resource scope for the API you are calling\n\nFor local development, the standard path is ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\nFor automation, use a service account key only when ADC from the runtime environment is not available:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nExplicit credentials also work:\n\n```python\nfrom google.cloud import compute_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\ninstances = compute_v1.InstancesClient(credentials=credentials)\n```\n\n## Client Model\n\nThis library is organized as generated clients by resource family. Common ones include:\n\n- `InstancesClient`\n- `ImagesClient`\n- `FirewallsClient`\n- `NetworksClient`\n- `SubnetworksClient`\n- `DisksClient`\n- `ZoneOperationsClient`\n- `RegionOperationsClient`\n- `GlobalOperationsClient`\n\nCommon rules that matter in practice:\n\n- Use the client that matches the resource scope: zonal, regional, or global.\n- Read methods usually return response objects or pagers.\n- Mutating methods such as `insert()`, `delete()`, `start()`, and `stop()` usually return an extended operation that you must wait on.\n- The generated methods accept either flattened keyword arguments or a `request=` object. Do not mix both in the same call.\n\n## Basic Read Operations\n\nList instances in a zone:\n\n```python\nimport os\nfrom google.cloud import compute_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\ninstances = compute_v1.InstancesClient()\n\nfor vm in instances.list(project=project_id, zone=zone):\n    print(vm.name, vm.status)\n```\n\nFetch one instance:\n\n```python\nimport os\nfrom google.cloud import compute_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\ninstances = compute_v1.InstancesClient()\nvm = instances.get(project=project_id, zone=zone, instance=\"example-vm\")\n\nprint(vm.name)\nprint(vm.machine_type)\nprint(vm.status)\n```\n\nResolve an image family before instance creation:\n\n```python\nfrom google.cloud import compute_v1\n\nimages = compute_v1.ImagesClient()\nimage = images.get_from_family(project=\"debian-cloud\", family=\"debian-12\")\n\nprint(image.self_link)\n```\n\n## Waiting For Mutating Operations\n\nCompute Engine mutations are long-running operations. The official samples use `google.api_core.extended_operation.ExtendedOperation` and wait on `result()`.\n\n```python\nfrom google.api_core.extended_operation import ExtendedOperation\n\ndef wait_for_extended_operation(\n    operation: ExtendedOperation, *, verbose_name: str, timeout: int = 600\n):\n    result = operation.result(timeout=timeout)\n\n    if operation.error_code:\n        raise RuntimeError(\n            f\"{verbose_name} failed with code {operation.error_code}: \"\n            f\"{operation.error_message}\"\n        )\n\n    for warning in operation.warnings or []:\n        print(f\"{verbose_name} warning: {warning.code}: {warning.message}\")\n\n    return result\n```\n\nStart, stop, and delete all follow the same pattern:\n\n```python\nstop_op = instances.stop(project=project_id, zone=zone, instance=\"example-vm\")\nwait_for_extended_operation(stop_op, verbose_name=\"stop instance\")\n\nstart_op = instances.start(project=project_id, zone=zone, instance=\"example-vm\")\nwait_for_extended_operation(start_op, verbose_name=\"start instance\")\n\ndelete_op = instances.delete(project=project_id, zone=zone, instance=\"example-vm\")\nwait_for_extended_operation(delete_op, verbose_name=\"delete instance\")\n```\n\n## Creating An Instance\n\nThe official Compute sample uses `ImagesClient.get_from_family()` to find a boot image, builds a `compute_v1.Instance`, then calls `InstancesClient.insert()`.\n\n```python\nimport os\nfrom google.cloud import compute_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\ninstance_name = \"example-vm\"\n\nimages = compute_v1.ImagesClient()\nsource_image = images.get_from_family(\n    project=\"debian-cloud\",\n    family=\"debian-12\",\n)\n\ndisk = compute_v1.AttachedDisk()\ndisk.boot = True\ndisk.auto_delete = True\ndisk.initialize_params = compute_v1.AttachedDiskInitializeParams(\n    source_image=source_image.self_link,\n)\n\nnetwork_interface = compute_v1.NetworkInterface()\nnetwork_interface.name = \"global/networks/default\"\n\ninstance = compute_v1.Instance()\ninstance.name = instance_name\ninstance.machine_type = f\"zones/{zone}/machineTypes/e2-micro\"\ninstance.disks = [disk]\ninstance.network_interfaces = [network_interface]\n\ninstances = compute_v1.InstancesClient()\noperation = instances.insert(\n    project=project_id,\n    zone=zone,\n    instance_resource=instance,\n)\n\nwait_for_extended_operation(operation, verbose_name=\"create instance\")\n```\n\n## Configuration Patterns\n\n- Prefer environment variables or configuration files for `project`, `zone`, and `region`; avoid hard-coding them in library helpers.\n- Use the `request=` object style when the method has many optional fields or when you need request flags such as filters or partial-success behavior.\n- If you need custom client options, pass them to the client constructor rather than patching transport internals.\n- Create clients after `os.fork()`. The official multiprocessing guidance says to instantiate client objects in the child process, not before forking.\n\n## Common Pitfalls\n\n- `google-cloud-compute` is the package name, but the import is `from google.cloud import compute_v1`.\n- Zonal, regional, and global resources are handled by different clients and different operation services. Use the wrong scope and the request fails.\n- Many fields need Compute Engine resource paths, not shorthand names. Common examples are `zones/us-central1-a/machineTypes/e2-micro`, `global/networks/default`, and full image `self_link` values.\n- Mutating calls are not complete when the initial method returns. Wait for the operation result and check `error_code`, `error_message`, and warnings.\n- List methods return pagers. Iterate them directly instead of assuming a single page.\n- The generated clients are large enough that JetBrains IDEs may need a larger maximum IntelliSense file size to fully index the stubs.\n\n## Version-Sensitive Notes\n\nAs of `2026-03-12`, the official sources are not fully aligned:\n\n- PyPI lists `google-cloud-compute 1.45.0`.\n- The Google Cloud Python reference root and changelog pages still show `1.41.0`.\n\nTreat `1.45.0` as the package version for dependency management, but verify any newly added methods or fields against the version of the Google-hosted reference you are reading. The docs URL in this entry is a moving `latest` page, not a version-pinned reference tree.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/google-cloud-compute/\n- Google Cloud Python reference root: https://cloud.google.com/python/docs/reference/compute/latest\n- `InstancesClient` reference: https://cloud.google.com/python/docs/reference/compute/latest/google.cloud.compute_v1.services.instances.InstancesClient\n- Multiprocessing guidance: https://cloud.google.com/python/docs/reference/compute/latest/multiprocessing\n- Compute instance creation sample: https://cloud.google.com/compute/docs/samples/compute-instances-create\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- Changelog: https://cloud.google.com/python/docs/reference/compute/latest/changelog\n"
  },
  {
    "path": "content/google/docs/config-connector/python/DOC.md",
    "content": "---\nname: config-connector\ndescription: \"Google Config Connector guide for Python teams using GKE, Workload Identity, Config Connector CRDs, and GKE add-on automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,config-connector,gke,kubernetes,python,infrastructure\"\n---\n\n# Config Connector Guide For Python Teams\n\n## What This Is\n\nConfig Connector is a Kubernetes add-on for managing Google Cloud resources through Kubernetes custom resources.\n\nImportant inference from Google's current public docs: treat `google-cloud-config-connector` as product packaging metadata, not as a normal Python application SDK with resource clients. The documented interfaces are:\n\n- the Config Connector operator and CRDs\n- `kubectl` and Kubernetes manifests\n- the GKE Cluster Manager API surface for enabling the Config Connector add-on\n\nIf you are writing Python automation, the practical split is:\n\n- use `google-cloud-container` to inspect or enable the GKE add-on from Python\n- use Config Connector YAML manifests for the actual Google Cloud resources you want to manage\n\n## Version Note\n\nThe current Google documentation for Config Connector is a rolling \"latest\" product doc set, not a version-pinned Python API reference. The upstream source repository currently shows much newer releases than `1.0.0`, so do not assume the live docs describe the exact behavior of an old package pin. If your environment needs reproducibility, pin the Config Connector release bundle you install on the cluster.\n\n## Authentication And Environment\n\nConfig Connector on GKE should use Workload Identity Federation for GKE. For Python code that talks to the GKE API, use Application Default Credentials (ADC).\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GKE_LOCATION=\"us-central1\"\nexport GKE_CLUSTER=\"my-cluster\"\n```\n\nService account credential file fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GKE_LOCATION=\"us-central1\"\nexport GKE_CLUSTER=\"my-cluster\"\n```\n\nADC looks for credentials in this order:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. credentials created by `gcloud auth application-default login`\n3. the attached service account from the metadata server\n\n## Enable The GKE Add-On From Python\n\nIf you want Python code to inspect or enable the Config Connector add-on on an existing GKE Standard cluster, use `google-cloud-container`.\n\nInstall the client library:\n\n```bash\npython -m pip install google-cloud-container\n```\n\nInspect the cluster and current add-on state:\n\n```python\nimport os\n\nfrom google.cloud import container_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GKE_LOCATION\"]\ncluster_id = os.environ[\"GKE_CLUSTER\"]\n\nclient = container_v1.ClusterManagerClient()\nname = f\"projects/{project_id}/locations/{location}/clusters/{cluster_id}\"\n\ncluster = client.get_cluster(name=name)\nprint(cluster.name)\nprint(cluster.addons_config.config_connector_config.enabled)\n```\n\nEnable the add-on:\n\n```python\nimport os\n\nfrom google.cloud import container_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GKE_LOCATION\"]\ncluster_id = os.environ[\"GKE_CLUSTER\"]\n\nclient = container_v1.ClusterManagerClient()\nname = f\"projects/{project_id}/locations/{location}/clusters/{cluster_id}\"\n\noperation = client.set_addons_config(\n    name=name,\n    addons_config=container_v1.AddonsConfig(\n        config_connector_config=container_v1.ConfigConnectorConfig(\n            enabled=True,\n        ),\n    ),\n)\n\nprint(operation.name)\n```\n\nUse this only for the GKE add-on. Google's product docs still describe actual Config Connector resource management through YAML and `kubectl`, not through a Python resource client.\n\n## Recommended Installation Path\n\nFor most use cases, Google recommends manual installation in namespaced mode. It is more scalable than cluster mode and provides better permission isolation. The GKE add-on is only available on GKE Standard clusters and is often behind the latest Config Connector version by up to 12 months or more.\n\nMinimum cluster prerequisites from the installation docs:\n\n- a GKE cluster where Config Connector is not already installed\n- Workload Identity enabled\n- Kubernetes Engine Monitoring enabled\n- `kubectl` configured for the cluster\n\nExample setup:\n\n```bash\nexport PROJECT_ID=\"your-project-id\"\nexport CLUSTER_NAME=\"your-cluster\"\nexport LOCATION=\"us-central1\"\nexport NAMESPACE=\"config-connector\"\nexport NAMESPACE_GSA=\"config-connector\"\n\ngcloud container clusters get-credentials \"$CLUSTER_NAME\" \\\n  --location \"$LOCATION\" \\\n  --project \"$PROJECT_ID\"\n\ngcloud storage cp gs://configconnector-operator/latest/release-bundle.tar.gz release-bundle.tar.gz\ntar zxvf release-bundle.tar.gz\nkubectl apply -f operator-system/configconnector-operator.yaml\n```\n\nCreate the operator configuration in namespaced mode:\n\n```yaml\n# configconnector.yaml\napiVersion: core.cnrm.cloud.google.com/v1beta1\nkind: ConfigConnector\nmetadata:\n  name: configconnector.core.cnrm.cloud.google.com\nspec:\n  mode: namespaced\n  stateIntoSpec: Absent\n```\n\n```bash\nkubectl apply -f configconnector.yaml\n```\n\nCreate a namespace-specific IAM identity and bind it to Config Connector:\n\n```bash\nkubectl create namespace \"$NAMESPACE\"\n\ngcloud iam service-accounts create \"$NAMESPACE_GSA\" --project \"$PROJECT_ID\"\n\ngcloud projects add-iam-policy-binding \"$PROJECT_ID\" \\\n  --member=\"serviceAccount:${NAMESPACE_GSA}@${PROJECT_ID}.iam.gserviceaccount.com\" \\\n  --role=\"roles/editor\"\n\ngcloud iam service-accounts add-iam-policy-binding \\\n  \"${NAMESPACE_GSA}@${PROJECT_ID}.iam.gserviceaccount.com\" \\\n  --member=\"serviceAccount:${PROJECT_ID}.svc.id.goog[cnrm-system/cnrm-controller-manager-${NAMESPACE}]\" \\\n  --role=\"roles/iam.workloadIdentityUser\"\n```\n\nFor real deployments, replace the broad `roles/editor` example with the narrow roles your managed resources actually require.\n\nCreate the namespace context that tells Config Connector which Google service account to use:\n\n```yaml\n# configconnectorcontext.yaml\napiVersion: core.cnrm.cloud.google.com/v1beta1\nkind: ConfigConnectorContext\nmetadata:\n  name: configconnectorcontext.core.cnrm.cloud.google.com\n  namespace: config-connector\nspec:\n  googleServiceAccount: \"config-connector@your-project-id.iam.gserviceaccount.com\"\n  stateIntoSpec: Absent\n```\n\n```bash\nkubectl apply -f configconnectorcontext.yaml\nkubectl wait -n cnrm-system \\\n  --for=condition=Ready pod \\\n  -l cnrm.cloud.google.com/component=cnrm-controller-manager \\\n  -l cnrm.cloud.google.com/scoped-namespace=\"$NAMESPACE\"\n```\n\n## Choose Where Resources Are Created\n\nConfig Connector can determine the target project from annotations on the Kubernetes namespace. The namespace annotation is used only when the resource itself does not already specify where it should be created.\n\nProject-scoped namespace:\n\n```bash\nkubectl annotate namespace \"$NAMESPACE\" \\\n  cnrm.cloud.google.com/project-id=\"$PROJECT_ID\"\n\nkubectl config set-context --current --namespace \"$NAMESPACE\"\n```\n\nIf you need deterministic behavior in shared clusters, prefer setting the project both on the namespace and explicitly in the resource when the resource kind supports it.\n\n## Core Workflow\n\n### Enable a Google API\n\n```yaml\n# enable-pubsub.yaml\napiVersion: serviceusage.cnrm.cloud.google.com/v1beta1\nkind: Service\nmetadata:\n  name: pubsub.googleapis.com\nspec:\n  projectRef:\n    external: projects/your-project-id\n```\n\n```bash\nkubectl apply -f enable-pubsub.yaml\n```\n\n### Create a resource\n\n```yaml\n# pubsub-topic.yaml\napiVersion: pubsub.cnrm.cloud.google.com/v1beta1\nkind: PubSubTopic\nmetadata:\n  annotations:\n    cnrm.cloud.google.com/project-id: your-project-id\n  labels:\n    environment: dev\n  name: example-topic\n```\n\n```bash\nkubectl apply -f pubsub-topic.yaml\nkubectl wait --for=condition=READY pubsubtopics example-topic\nkubectl describe pubsubtopics example-topic\n```\n\n### Update a resource\n\nEdit the manifest and run `kubectl apply -f pubsub-topic.yaml` again. Config Connector reconciles the live Google Cloud resource toward the new desired state.\n\n### Acquire an existing resource with `resourceID`\n\nUse `resourceID` when the Kubernetes object name should differ from the Google Cloud resource ID, or when you need to acquire an existing resource. The field is optional but immutable after apply.\n\n```yaml\napiVersion: pubsub.cnrm.cloud.google.com/v1beta1\nkind: PubSubTopic\nmetadata:\n  name: pubsub-topic-sample\nspec:\n  resourceID: pubsub-topic-id\n```\n\n### Keep a cloud resource when deleting the Kubernetes object\n\nBy default, deleting a Config Connector resource deletes the corresponding Google Cloud resource too. Use `cnrm.cloud.google.com/deletion-policy: \"abandon\"` when you want Kubernetes to stop managing the resource but keep the cloud object.\n\n```yaml\nmetadata:\n  annotations:\n    cnrm.cloud.google.com/deletion-policy: \"abandon\"\n```\n\n## Secrets\n\nConfig Connector can read Kubernetes Secrets for sensitive fields such as passwords and access keys. Keep the Secret in the same namespace as the resource that references it.\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: secret-1\nstringData:\n  password: change-me\n```\n\nApply the Secret before applying the resource that references it:\n\n```bash\nkubectl apply -f example-secret.yaml\n```\n\nIf the referenced Secret does not exist, Config Connector emits `DependencyNotFound` or `DependencyInvalid` events.\n\n## Common Pitfalls\n\n- Do not look for a normal Python resource client in this package. The supported day-to-day interface is CRDs plus `kubectl`.\n- Prefer manual namespaced installation for new deployments unless you explicitly want the GKE add-on trade-offs.\n- Do not use the GKE add-on on Autopilot; Google documents it as GKE Standard only.\n- The GKE add-on can lag the latest Config Connector release significantly. If you need newer CRDs or tighter version control, install manually.\n- `resourceID` is immutable after apply. Choose it deliberately.\n- Namespace annotations affect default project selection. Be explicit when project targeting must never drift.\n- By default, deleting the Kubernetes object deletes the Google Cloud resource. Use `deletion-policy: \"abandon\"` when that is not what you want.\n- Some resources have extra annotations beyond the generic ones. Check the reference page for the specific resource kind before relying on deletion or cleanup behavior.\n- If a resource references a Secret, keep that Secret in the same namespace.\n\n## Official Sources\n\n- Config Connector overview: `https://docs.cloud.google.com/config-connector/docs/overview`\n- Choosing an installation type: `https://docs.cloud.google.com/config-connector/docs/concepts/installation-types`\n- Manual installation: `https://docs.cloud.google.com/config-connector/docs/how-to/install-manually`\n- Getting started: `https://docs.cloud.google.com/config-connector/docs/how-to/getting-started`\n- Namespaces and Google Cloud projects: `https://docs.cloud.google.com/config-connector/docs/concepts/namespaces-and-projects`\n- `resourceID` behavior: `https://docs.cloud.google.com/config-connector/docs/how-to/managing-resources-with-resource-ids`\n- Secrets: `https://docs.cloud.google.com/config-connector/docs/how-to/secrets`\n- Annotations: `https://docs.cloud.google.com/config-connector/docs/reference/annotations`\n- GKE Python client docs: `https://docs.cloud.google.com/python/docs/reference/container/latest`\n- `ClusterManagerClient.get_cluster`: `https://docs.cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.services.cluster_manager.ClusterManagerClient`\n- `ClusterManagerClient.set_addons_config`: `https://docs.cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.services.cluster_manager.ClusterManagerClient`\n- `ConfigConnectorConfig`: `https://docs.cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.types.ConfigConnectorConfig`\n- ADC overview: `https://docs.cloud.google.com/docs/authentication/application-default-credentials`\n- Source repository: `https://github.com/GoogleCloudPlatform/k8s-config-connector`\n"
  },
  {
    "path": "content/google/docs/contact-center-insights/javascript/DOC.md",
    "content": "---\nname: contact-center-insights\ndescription: \"Google Cloud Contact Center Insights Node.js client for settings, conversation upload, analysis, and issue model workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,contact-center-insights,ccai,conversation-analysis,javascript,nodejs\"\n---\n\n# `@google-cloud/contact-center-insights` JavaScript Package Guide\n\nUse `@google-cloud/contact-center-insights` when your Node.js code needs to manage Contact Center Insights settings, upload or create conversations, run analyses, and work with deployed issue models.\n\n## Golden Rule\n\n- Import the generated client from the `v1` namespace.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Pass full resource names like `projects/PROJECT_ID/locations/LOCATION/...`.\n- Use `uploadConversation()` for audio files that need transcription or redaction.\n- Use `createConversation()` when you already have a transcript and do not need transcription or redaction.\n- Await long-running operations with `operation.promise()` before reading results.\n\nThis guide covers `4.1.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/contact-center-insights@4.1.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the Contact Center Insights API in the project your application uses to call the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\ngcloud services enable contactcenterinsights.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nBefore calling the API, make sure:\n\n1. The Contact Center Insights API is enabled.\n2. The caller has permission to read and write Contact Center Insights resources in the target project and location.\n3. Any Cloud Storage URIs you pass are accessible to the calling identity.\n4. Your code consistently uses one location string such as `us-central1` when building resource names.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/contact-center-insights';\n\nconst client = new v1.ContactCenterInsightsClient();\n```\n\nWith an explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Resource Names You Reuse Constantly\n\nBuild these once and pass them through your app:\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1';\n\nconst parent = `projects/${projectId}/locations/${location}`;\nconst settingsName = `${parent}/settings`;\nconst conversationName = `${parent}/conversations/my-conversation-id`;\nconst issueModelName = `${parent}/issueModels/my-issue-model-id`;\n```\n\n## Core Workflows\n\n### Read Location Settings\n\nUse `getSettings()` to inspect the default language, speech config, redaction config, and automatic analysis behavior for one location.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function getLocationSettings(projectId, location) {\n  const [settings] = await client.getSettings({\n    name: `projects/${projectId}/locations/${location}/settings`,\n  });\n\n  return {\n    name: settings.name,\n    languageCode: settings.languageCode,\n    conversationTtl: settings.conversationTtl,\n    analysisConfig: settings.analysisConfig,\n  };\n}\n```\n\n### Update Default Settings With A Field Mask\n\nUse `updateSettings()` with a field mask so you only change the settings you intend to change.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function enableAutomaticUploadAnalysis(projectId, location) {\n  const name = `projects/${projectId}/locations/${location}/settings`;\n\n  const [settings] = await client.updateSettings({\n    settings: {\n      name,\n      languageCode: 'en-US',\n      analysisConfig: {\n        uploadConversationAnalysisPercentage: 100,\n      },\n    },\n    updateMask: {\n      paths: [\n        'language_code',\n        'analysis_config.upload_conversation_analysis_percentage',\n      ],\n    },\n  });\n\n  return settings;\n}\n```\n\n### Create A Transcript-Only Conversation\n\nUse `createConversation()` when the transcript already exists in Cloud Storage. This path does not perform audio transcription or redaction.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function createTranscriptConversation(projectId, location) {\n  const [conversation] = await client.createConversation({\n    parent: `projects/${projectId}/locations/${location}`,\n    conversationId: 'chat-001',\n    conversation: {\n      medium: 'CHAT',\n      languageCode: 'en-US',\n      dataSource: {\n        gcsSource: {\n          transcriptUri: 'gs://my-contact-center-data/transcripts/chat-001.json',\n        },\n      },\n      labels: {\n        channel: 'support',\n      },\n    },\n  });\n\n  return conversation.name;\n}\n```\n\n### Upload An Audio Conversation\n\nUse `uploadConversation()` when you are starting from audio in Cloud Storage and want Contact Center Insights to process it as a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function uploadPhoneCall(projectId, location) {\n  const [operation] = await client.uploadConversation({\n    parent: `projects/${projectId}/locations/${location}`,\n    conversationId: 'call-001',\n    conversation: {\n      medium: 'PHONE_CALL',\n      languageCode: 'en-US',\n      dataSource: {\n        gcsSource: {\n          audioUri: 'gs://my-contact-center-data/audio/call-001.wav',\n        },\n      },\n      callMetadata: {\n        agentChannel: 1,\n        customerChannel: 2,\n      },\n    },\n  });\n\n  await operation.promise();\n}\n```\n\nIf you use stereo call recordings, set `agentChannel` and `customerChannel` so the conversation is analyzed against the correct speaker channels.\n\n### List Conversations In One Location\n\nUse `listConversationsAsync()` for inventory-style reads and filter in your own code unless you already have a precise server-side filter.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function listConversationNames(projectId, location) {\n  const names = [];\n\n  for await (const conversation of client.listConversationsAsync({\n    parent: `projects/${projectId}/locations/${location}`,\n    pageSize: 50,\n  })) {\n    names.push(conversation.name);\n  }\n\n  return names;\n}\n```\n\n### Run An On-Demand Analysis For One Conversation\n\nUse `createAnalysis()` when you want explicit control over which annotators run for a conversation.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function analyzeConversation(projectId, location, conversationId) {\n  const [operation] = await client.createAnalysis({\n    parent: `projects/${projectId}/locations/${location}/conversations/${conversationId}`,\n    analysis: {\n      annotatorSelector: {\n        runEntityAnnotator: true,\n        runIssueModelAnnotator: true,\n        runSentimentAnnotator: true,\n        runSummarizationAnnotator: true,\n      },\n    },\n  });\n\n  const [analysis] = await operation.promise();\n  return analysis.name;\n}\n```\n\n`runIssueModelAnnotator` only has effect when an issue model is already deployed in that location.\n\n### List Analyses For A Conversation\n\nUse `listAnalysesAsync()` when you need to inspect completed analysis resources for one conversation.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function listAnalysisNames(projectId, location, conversationId) {\n  const names = [];\n\n  for await (const analysis of client.listAnalysesAsync({\n    parent: `projects/${projectId}/locations/${location}/conversations/${conversationId}`,\n  })) {\n    names.push(analysis.name);\n  }\n\n  return names;\n}\n```\n\n### Deploy An Existing Issue Model\n\nAn issue model must be deployed before issue-model-based analysis can use it.\n\n```javascript\nconst {v1} = require('@google-cloud/contact-center-insights');\n\nconst client = new v1.ContactCenterInsightsClient();\n\nasync function deployIssueModel(projectId, location, issueModelId) {\n  const [operation] = await client.deployIssueModel({\n    name: `projects/${projectId}/locations/${location}/issueModels/${issueModelId}`,\n  });\n\n  await operation.promise();\n}\n```\n\n## Version And Namespace Notes\n\n- Prefer `v1` unless you are intentionally maintaining code against another versioned namespace.\n- Request objects use JavaScript `camelCase` field names such as `languageCode` and `conversationTtl`.\n- Field masks use proto field paths such as `language_code` and `analysis_config.upload_conversation_analysis_percentage`.\n\n## Important Pitfalls\n\n- Passing a bare project ID where the API expects `projects/.../locations/...` resource names.\n- Using `createConversation()` for audio uploads that need transcription or redaction. Use `uploadConversation()` instead.\n- Forgetting to await `operation.promise()` on upload, analysis, or issue model deployment.\n- Enabling the issue model annotator before a model is deployed.\n- Omitting speaker channel metadata for multi-channel phone audio.\n- Mixing locations across settings, conversations, issue models, and Cloud Storage inputs in the same workflow.\n\n## Official Sources\n\n- Maintainer package docs: `https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-contactcenterinsights`\n- Node.js client reference root: `https://cloud.google.com/nodejs/docs/reference/contact-center-insights/latest`\n- Product documentation: `https://cloud.google.com/contact-center/insights/docs`\n- Authentication with ADC: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- npm registry: `https://www.npmjs.com/package/@google-cloud/contact-center-insights`\n"
  },
  {
    "path": "content/google/docs/container/javascript/DOC.md",
    "content": "---\nname: container\ndescription: \"Google Kubernetes Engine Node.js client guide with ADC setup, ClusterManagerClient usage, operation polling, and resource-name pitfalls\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.7.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gke,kubernetes,container,gcp,adc,javascript,nodejs\"\n---\n\n# `@google-cloud/container` JavaScript Package Guide\n\nUse `@google-cloud/container` when your Node.js code needs to call the Google Kubernetes Engine control-plane API to list, inspect, create, update, or delete clusters and related resources such as node pools.\n\nDo not use this package for normal Kubernetes object access inside a cluster. For Pods, Deployments, Services, and other Kubernetes resources, get cluster credentials first and then use `kubectl` or a Kubernetes client library.\n\n## Golden Rule\n\n- Import the generated client from the `v1` namespace for stable automation.\n- Authenticate with Application Default Credentials (ADC), not API keys.\n- Pass fully qualified resource names like `projects/PROJECT_ID/locations/LOCATION`.\n- Treat cluster create, update, and delete calls as asynchronous operations and poll `getOperation`.\n- Use a separate Kubernetes client after you need to manage workload objects inside the cluster.\n\nThis guide covers `6.7.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/container@6.7.0\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nEnable the Kubernetes Engine API in the project that will call the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable container.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project already exists.\n2. The Kubernetes Engine API is enabled.\n3. The caller has permission to manage GKE clusters in the target project.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/container';\n\nconst client = new v1.ClusterManagerClient();\n```\n\nWith explicit project ID and service account file:\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Resource Names\n\nBuild resource names explicitly in new code:\n\n- parent location: `projects/PROJECT_ID/locations/LOCATION`\n- cluster name: `projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_ID`\n- operation name: `projects/PROJECT_ID/locations/LOCATION/operations/OPERATION_ID`\n\n`LOCATION` can be a region such as `us-central1` or a zone such as `us-central1-a`, depending on whether the cluster is regional or zonal.\n\nPrefer `parent` and `name` request fields over older request shapes that pass `projectId`, `zone`, or `clusterId` separately.\n\n## Core Workflows\n\n### List Clusters In A Location\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function listClusters(projectId, location) {\n  const parent = `projects/${projectId}/locations/${location}`;\n  const [response] = await client.listClusters({parent});\n  return response.clusters ?? [];\n}\n\nasync function main() {\n  const clusters = await listClusters('my-project', 'us-central1');\n\n  for (const cluster of clusters) {\n    console.log(cluster.name, cluster.endpoint);\n  }\n}\n\nmain().catch(console.error);\n```\n\n### Get One Cluster\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function getCluster(projectId, location, clusterId) {\n  const name = `projects/${projectId}/locations/${location}/clusters/${clusterId}`;\n  const [cluster] = await client.getCluster({name});\n  return cluster;\n}\n\nasync function main() {\n  const cluster = await getCluster('my-project', 'us-central1', 'primary');\n  console.log(cluster.name);\n  console.log(cluster.endpoint);\n  console.log(cluster.currentMasterVersion);\n}\n\nmain().catch(console.error);\n```\n\n### Inspect Available Control-Plane Versions\n\nUse `getServerConfig` before hard-coding a Kubernetes version into automation:\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function getServerConfig(projectId, location) {\n  const [config] = await client.getServerConfig({\n    name: `projects/${projectId}/locations/${location}`,\n  });\n\n  return config;\n}\n\nasync function main() {\n  const config = await getServerConfig('my-project', 'us-central1');\n  console.log(config.defaultClusterVersion);\n  console.log((config.validMasterVersions ?? []).slice(0, 5));\n}\n\nmain().catch(console.error);\n```\n\n### Create A Cluster\n\n`createCluster` returns a GKE operation resource. It does not block until the cluster is ready.\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function createCluster(projectId, location, clusterId) {\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  const [operation] = await client.createCluster({\n    parent,\n    cluster: {\n      name: clusterId,\n      initialNodeCount: 1,\n      nodeConfig: {\n        machineType: 'e2-standard-4',\n      },\n    },\n  });\n\n  return operation.name;\n}\n```\n\nReal production clusters usually need more configuration than this minimal request, such as networking, release channels, workload identity, autoscaling, or private-cluster settings.\n\n### Poll A Returned Operation\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function waitForOperation(operationName, pollMs = 10000) {\n  while (true) {\n    const [operation] = await client.getOperation({name: operationName});\n    const done = operation.status === 'DONE' || operation.status === 3;\n\n    if (done) {\n      return operation;\n    }\n\n    await new Promise(resolve => setTimeout(resolve, pollMs));\n  }\n}\n```\n\nStore the `operation.name` returned by `createCluster`, `updateCluster`, `deleteCluster`, or node-pool methods, then poll it until the status is done.\n\n### Delete A Cluster\n\n```javascript\nconst {v1} = require('@google-cloud/container');\n\nconst client = new v1.ClusterManagerClient();\n\nasync function deleteCluster(projectId, location, clusterId) {\n  const name = `projects/${projectId}/locations/${location}/clusters/${clusterId}`;\n  const [operation] = await client.deleteCluster({name});\n  return operation.name;\n}\n```\n\n## Access The Kubernetes API After Control-Plane Calls\n\nAfter the cluster exists, use `gcloud` to fetch credentials for `kubectl` or a Kubernetes client:\n\n```bash\ngcloud container clusters get-credentials my-cluster \\\n  --location us-central1 \\\n  --project my-project-id\n```\n\nThis package manages GKE resources through Google Cloud APIs. It does not replace a Kubernetes client for in-cluster workload resources.\n\n## Common Pitfalls\n\n- Confusing GKE control-plane calls with Kubernetes API calls for workload objects.\n- Mixing regional and zonal locations when building resource names.\n- Assuming `createCluster` or `deleteCluster` completes before the returned operation finishes.\n- Copying older examples that use deprecated `projectId`, `zone`, or `clusterId` request fields.\n- Hard-coding cluster versions instead of checking `getServerConfig` first.\n- Reaching for beta namespaces before confirming that the GA `v1` client is missing a required field.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/container/latest`\n- Authentication with ADC: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- GKE REST reference: `https://cloud.google.com/kubernetes-engine/docs/reference/rest`\n- Cluster access with `kubectl`: `https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/container`\n"
  },
  {
    "path": "content/google/docs/container/python/DOC.md",
    "content": "---\nname: container\ndescription: \"Google Kubernetes Engine Python client guide with ADC setup, ClusterManagerClient usage, operation polling, and location/name pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.63.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,gke,kubernetes,container,gcp,adc\"\n---\n\n# google-cloud-container Python Package Guide\n\n## What This Package Is\n\n`google-cloud-container` is the official Google Cloud Python client for the Google Kubernetes Engine control-plane API.\n\nUse it when Python code needs to:\n\n- list, inspect, create, update, or delete GKE clusters\n- manage node pools and server config\n- poll GKE operations from application code\n\nDo not use this package for normal Kubernetes object access inside a cluster. For Deployments, Services, Pods, and other Kubernetes resources, use the Kubernetes Python client against the cluster endpoint after you obtain cluster credentials.\n\n## Version Note\n\nThis guide covers package version `2.63.0`, which PyPI lists as the latest visible release as of `2026-03-12`.\n\nOfficial upstream sources checked on `2026-03-12` do not fully agree on package freshness:\n\n- PyPI lists `2.63.0` as the latest release\n- the Google Cloud Python docs overview page under `latest` currently renders the package as `2.62.0`\n- the `latest` docs changelog page currently stops at `2.61.0`\n\nPractical implication:\n\n- the examples below are grounded in the current GA `container_v1` client surface\n- if you depend on a field added very recently, verify it against the installed wheel, not just the rolling docs site\n- treat the docs site as slightly lagging behind the published PyPI package for this library\n\nOfficial sources used for this guide:\n\n- Docs root: `https://cloud.google.com/python/docs/reference/container/latest`\n- Cluster manager reference: `https://cloud.google.com/python/docs/reference/container/latest/google.cloud.container_v1.services.cluster_manager.ClusterManagerClient`\n- Changelog: `https://cloud.google.com/python/docs/reference/container/latest/changelog`\n- Authentication: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Registry: `https://pypi.org/project/google-cloud-container/`\n\n## Install\n\nInstall the library:\n\n```bash\npython -m pip install google-cloud-container\n```\n\nIf you want the current upstream release that was visible on that date:\n\n```bash\npython -m pip install \"google-cloud-container==2.63.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Required Setup\n\nBefore calling the client, Google’s package docs and authentication docs require the usual Google Cloud setup:\n\n1. Select or create a Google Cloud project.\n2. Enable billing for the project.\n3. Enable the Kubernetes Engine API.\n4. Set up Application Default Credentials.\n\nEnable the API:\n\n```bash\ngcloud services enable container.googleapis.com\n```\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nService account credentials via environment variable:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nYour credential needs permission to call GKE cluster-management APIs in the target project.\n\n## Imports And Client Creation\n\nUse the GA surface by default:\n\n```python\nfrom google.cloud import container_v1\n\nclient = container_v1.ClusterManagerClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import container_v1\n\nclient = container_v1.ClusterManagerAsyncClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import container_v1\n\nclient = container_v1.ClusterManagerClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nREST transport instead of gRPC:\n\n```python\nfrom google.cloud import container_v1\n\nclient = container_v1.ClusterManagerClient(transport=\"rest\")\n```\n\nUse `container_v1beta1` only if you intentionally need beta-only fields. For stable automation, prefer `container_v1`.\n\n## Resource Naming\n\nThe current generated client expects fully qualified resource names.\n\nUse these formats:\n\n- parent location: `projects/{project_id}/locations/{location}`\n- cluster name: `projects/{project_id}/locations/{location}/clusters/{cluster_id}`\n- operation name: `projects/{project_id}/locations/{location}/operations/{operation_id}`\n\n`location` can be a region such as `us-central1` or a zone such as `us-central1-a`, depending on whether the cluster is regional or zonal.\n\nImportant compatibility note:\n\n- older request shapes used separate `project_id`, `zone`, and `cluster_id` fields\n- the current reference marks those older fields as deprecated in favor of `parent` and `name`\n\nFor new code, always build `parent` and `name` explicitly.\n\n## Core Usage\n\n### List Clusters In A Location\n\n```python\nfrom google.cloud import container_v1\n\ndef list_clusters(project_id: str, location: str) -> list[container_v1.Cluster]:\n    client = container_v1.ClusterManagerClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n    response = client.list_clusters(request={\"parent\": parent})\n    return list(response.clusters)\n\nfor cluster in list_clusters(\"my-project\", \"us-central1\"):\n    print(cluster.name, cluster.endpoint)\n```\n\n`list_clusters` returns a `ListClustersResponse`, not a pager object. Read `response.clusters` directly.\n\n### Get One Cluster\n\n```python\nfrom google.cloud import container_v1\n\ndef get_cluster(project_id: str, location: str, cluster_id: str) -> container_v1.Cluster:\n    client = container_v1.ClusterManagerClient()\n    name = f\"projects/{project_id}/locations/{location}/clusters/{cluster_id}\"\n    return client.get_cluster(request={\"name\": name})\n\ncluster = get_cluster(\"my-project\", \"us-central1\", \"primary\")\nprint(cluster.name)\nprint(cluster.endpoint)\nprint(cluster.current_master_version)\n```\n\n### Inspect Available Control-Plane Versions\n\nUse `get_server_config` before hard-coding Kubernetes versions in automation:\n\n```python\nfrom google.cloud import container_v1\n\ndef get_server_config(project_id: str, location: str) -> container_v1.ServerConfig:\n    client = container_v1.ClusterManagerClient()\n    name = f\"projects/{project_id}/locations/{location}\"\n    return client.get_server_config(request={\"name\": name})\n\nconfig = get_server_config(\"my-project\", \"us-central1\")\nprint(config.default_cluster_version)\nprint(list(config.valid_master_versions)[:5])\n```\n\n### Create A Cluster\n\n`create_cluster` returns a GKE operation resource. It does not block until the cluster is ready.\n\n```python\nfrom google.cloud import container_v1\n\ndef create_cluster(project_id: str, location: str, cluster_id: str) -> str:\n    client = container_v1.ClusterManagerClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n\n    operation = client.create_cluster(\n        request={\n            \"parent\": parent,\n            \"cluster\": container_v1.Cluster(\n                name=cluster_id,\n                initial_node_count=1,\n                node_config=container_v1.NodeConfig(\n                    machine_type=\"e2-standard-4\",\n                ),\n            ),\n        }\n    )\n    return operation.name\n```\n\nReal production cluster creation usually needs more than the minimal example above, such as networking, release channel, workload identity, autoscaling, or private-cluster settings. Start with the minimal request shape, then add product-specific cluster configuration deliberately.\n\n### Poll A Long-Running Operation\n\n```python\nimport time\n\nfrom google.cloud import container_v1\n\ndef wait_for_operation(operation_name: str, poll_seconds: int = 10) -> container_v1.Operation:\n    client = container_v1.ClusterManagerClient()\n\n    while True:\n        operation = client.get_operation(request={\"name\": operation_name})\n        if operation.status == container_v1.Operation.Status.DONE:\n            return operation\n        time.sleep(poll_seconds)\n```\n\nIf you need to cancel an operation, the same client also exposes `cancel_operation`.\n\n### Delete A Cluster\n\n```python\nfrom google.cloud import container_v1\n\ndef delete_cluster(project_id: str, location: str, cluster_id: str) -> str:\n    client = container_v1.ClusterManagerClient()\n    name = f\"projects/{project_id}/locations/{location}/clusters/{cluster_id}\"\n    operation = client.delete_cluster(request={\"name\": name})\n    return operation.name\n```\n\n## Authentication And Configuration Notes\n\n### ADC Is The Default\n\nThis client is designed around Application Default Credentials. In practice, the safest patterns are:\n\n- local development: `gcloud auth application-default login`\n- deployed workloads on Google Cloud: attach a service account and let ADC discover it\n- external workloads: point `GOOGLE_APPLICATION_CREDENTIALS` at a service account key only when workload identity federation is not available\n\n### Endpoint Overrides\n\nThe generated client constructor accepts `client_options=` if you need to override the API endpoint for a specialized environment:\n\n```python\nfrom google.cloud import container_v1\nfrom google.api_core.client_options import ClientOptions\n\nclient = container_v1.ClusterManagerClient(\n    client_options=ClientOptions(\n        api_endpoint=\"container.googleapis.com\",\n    )\n)\n```\n\nFor normal public Google Cloud usage, the default endpoint is the right choice.\n\n### Logging\n\nThe PyPI package page documents standard Google client-library logging support through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`.\n\nExample:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.container_v1\n```\n\n## Common Pitfalls\n\n### Confusing GKE Control-Plane Calls With Kubernetes API Calls\n\n`google-cloud-container` manages clusters and node pools through Google Cloud APIs. It does not replace the Kubernetes client for in-cluster resource CRUD.\n\n### Using Deprecated Request Fields\n\nIf you copy old examples that pass `project_id`, `zone`, or `cluster_id` separately, you can end up mixing old and new request shapes. Prefer the current `parent` and `name` fields everywhere.\n\n### Forgetting To Poll Operations\n\nCluster creation, updates, and deletes are asynchronous. Treat the returned `Operation` as a long-running status object and poll `get_operation` until it is done.\n\n### Mixing Zonal And Regional Names\n\nUse the exact location where the cluster lives. A regional cluster name such as `projects/my-project/locations/us-central1/clusters/my-cluster` is different from a zonal cluster name under `us-central1-a`.\n\n### Assuming `latest` Docs Match Installed Code\n\nFor this package, PyPI currently shows `2.63.0`, the docs overview page shows `2.62.0`, and the published changelog page stops at `2.61.0`. If a method or field appears new, verify it against the installed package before relying on it in generated code.\n\n### Reaching For `container_v1beta1` Without A Reason\n\nThe beta surface exists, but GA automation should start on `container_v1`. Only switch to `container_v1beta1` when you have confirmed that the needed field or method is not available in GA.\n\n## Practical Defaults For Agents\n\n- Import `from google.cloud import container_v1`.\n- Build resource names explicitly with `projects/.../locations/...`.\n- Use `ClusterManagerClient()` with ADC.\n- Treat create, update, and delete calls as asynchronous and poll `get_operation`.\n- Use the Kubernetes Python client separately for workload objects inside the cluster.\n"
  },
  {
    "path": "content/google/docs/core/python/DOC.md",
    "content": "---\nname: core\ndescription: \"google-cloud-core package guide for Python with ADC setup, project resolution, client base classes, and version-aware notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.5.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-core,gcp,google-cloud,auth,adc,project,client\"\n---\n\n# google-cloud-core Python Package Guide\n\n## What It Is\n\n`google-cloud-core` is the shared foundation package used by Google Cloud Python client libraries. It provides common client base classes, project and credential discovery behavior, and shared configuration conventions. It is not a product SDK by itself.\n\nUse a service package for actual API work:\n\n- `google-cloud-storage`\n- `google-cloud-bigquery`\n- `google-cloud-pubsub`\n\nInstall `google-cloud-core` directly when you are debugging dependency issues, building thin wrappers around Google Cloud clients, or working with the common `Client` / `ClientWithProject` base behavior.\n\n## Install\n\nPin the version you actually want to reason about:\n\n```bash\npython -m pip install google-cloud-core==2.5.0\n```\n\nIn most application code you should install the service-specific client instead and let it pull in `google-cloud-core` transitively.\n\n## Core API Surface\n\nThe package surface that matters most in real code:\n\n- `google.cloud.client.Client`: shared base client with credential loading, optional custom HTTP transport, and `client_options`\n- `google.cloud.client.ClientWithProject`: `Client` plus explicit or inferred project handling\n- `google.cloud.environment_vars`: constants for shared Google Cloud client environment variables\n\nPractical rule:\n\n- Use `Client` when you need to inspect or reuse base auth / transport behavior.\n- Use `ClientWithProject` when your code must carry a project id explicitly.\n- Use a service client for actual API methods.\n\n## Authentication And Project Setup\n\n`google-cloud-core` follows Google Cloud Application Default Credentials (ADC). For reliable automation:\n\n1. Use ADC for local development and managed runtime environments.\n2. Pass `project=` explicitly when project selection must be deterministic.\n3. Pass explicit `credentials=` in tests, CLIs, and wrappers when ambient machine state is unreliable.\n\n### Local ADC\n\n```bash\ngcloud auth application-default login\n```\n\n### Service Account Credentials File\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n### Explicit Credentials In Code\n\n```python\nfrom google.cloud.client import ClientWithProject\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = ClientWithProject(\n    project=\"my-gcp-project\",\n    credentials=credentials,\n)\n\nprint(client.project)\n```\n\nThe official configuration docs list `GOOGLE_CLOUD_PROJECT` as the environment-variable override for default project detection. Prefer passing `project=` directly when behavior must not depend on the shell or runtime environment.\n\n## Core Usage\n\n### Inspect Base Credential Resolution\n\n```python\nfrom google.cloud.client import Client\n\nclient = Client()\n\nprint(type(client._credentials).__name__)\nclient.close()\n```\n\nThis is useful for debugging what a larger Google Cloud Python stack will pick up from ADC, workload identity, or local developer credentials.\n\n### Carry Project Context Explicitly\n\n```python\nfrom google.cloud.client import ClientWithProject\n\nclient = ClientWithProject(project=\"my-gcp-project\")\n\nprint(client.project)\nclient.close()\n```\n\nUse this when your wrapper or test helper should not rely on inferred project discovery.\n\n### Supply A Custom HTTP Session\n\nIf you pass `_http`, it should already be an authenticated session with a `request()` method.\n\n```python\nfrom google.auth.transport.requests import AuthorizedSession\nfrom google.cloud.client import Client\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\nsession = AuthorizedSession(credentials)\n\nclient = Client(_http=session)\n\ntry:\n    response = client._http.request(\"GET\", \"https://example.com\")\nfinally:\n    client.close()\n```\n\nPitfall:\n\n- When `_http` is supplied, you are responsible for giving the client a ready-to-use session. Do not assume `credentials=` will also be applied to that custom transport.\n\n### Use `client_options` For Endpoint Overrides\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud.client import Client\n\nclient = Client(\n    client_options=ClientOptions(\n        api_endpoint=\"https://example.googleapis.com\"\n    )\n)\n\nclient.close()\n```\n\nThis matters most for libraries built on top of `google-cloud-core`; whether a particular option is honored depends on the concrete service client.\n\n## Configuration And Environment Variables\n\nThe current official config docs highlight these shared settings:\n\n- `GOOGLE_APPLICATION_CREDENTIALS`: credentials file path for ADC\n- `GOOGLE_CLOUD_PROJECT`: override the default project id\n- `GOOGLE_CLOUD_DISABLE_GRPC`: disables gRPC in dual-transport libraries that honor it\n\nImport the shared constant names if you need them programmatically:\n\n```python\nfrom google.cloud import environment_vars\n\nprint(environment_vars.CREDENTIALS)\nprint(environment_vars.PROJECT)\nprint(environment_vars.DISABLE_GRPC)\n```\n\nPractical guidance:\n\n- Prefer explicit `project=` over relying on `GOOGLE_CLOUD_PROJECT`.\n- Prefer explicit credentials in automation over ambient ADC state.\n- Treat transport-related environment variables as service-library specific; confirm behavior in the service client's own docs before relying on them.\n\n## Common Pitfalls\n\n- Do not treat `google-cloud-core` as a service SDK. It does not give you product methods like bucket, dataset, or subscription operations.\n- Do not anchor new work to older `googleapis.dev` examples alone. The current canonical docs are under `docs.cloud.google.com`.\n- Do not depend on project inference in tests if the project matters. Pass `project=` explicitly.\n- Do not pass a custom `_http` object unless it is already authenticated and implements the expected request interface.\n- Do not assume every Google Cloud Python package honors the same environment variables or transport toggles in the same way. Confirm service-specific behavior upstream.\n\n## Version-Sensitive Notes\n\n- The upstream changelog for `2.5.0` notes Python `3.14` support. If you are validating interpreter compatibility, use `2.5.0` or newer as the baseline for Python 3.14 environments.\n- The upstream changelog for `2.4.2` notes that `Client` passes `client_options.api_key` to the auth library. If you depend on API-key-based configuration, make sure you are not reasoning from older `2.4.1` behavior.\n- The canonical reference docs currently serve `latest` rather than a version-pinned `2.5.0` tree. Keep your lockfile authoritative if you are debugging a project pinned to an older transitive dependency set.\n\n## Official Sources\n\n- Docs root: `https://docs.cloud.google.com/python/docs/reference/google-cloud-core/latest`\n- `Client` reference: `https://docs.cloud.google.com/python/docs/reference/google-cloud-core/latest/google.cloud.client.Client`\n- `ClientWithProject` reference: `https://docs.cloud.google.com/python/docs/reference/google-cloud-core/latest/google.cloud.client.ClientWithProject`\n- Configuration guide: `https://cloud.google.com/python/docs/reference/google-cloud-core/latest/config`\n- Changelog: `https://cloud.google.com/python/docs/reference/google-cloud-core/latest/changelog`\n- PyPI: `https://pypi.org/project/google-cloud-core/`\n- ADC setup: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/data-fusion/python/DOC.md",
    "content": "---\nname: data-fusion\ndescription: \"Google Cloud Data Fusion Python client for instance lifecycle management and version discovery\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,data-fusion,gcp,etl,instances,python\"\n---\n\n# Google Cloud Data Fusion Python Client\n\n## Golden Rule\n\nUse `google-cloud-data-fusion` with `from google.cloud import data_fusion_v1` when you need to create, inspect, update, restart, or delete Cloud Data Fusion instances from Python.\n\nThis package is the control-plane client for Data Fusion instances and available versions. The generated `DataFusionClient` methods cover instance lifecycle and version discovery, not pipeline authoring inside the Data Fusion Studio UI.\n\n## Install\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-data-fusion==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-data-fusion==1.15.0\"\npoetry add \"google-cloud-data-fusion==1.15.0\"\n```\n\nPyPI lists `Python >=3.7` for this package.\n\n## Authentication And Environment\n\nThis client uses Google Cloud credentials, not an API key.\n\nFor local development, create Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nIf you must use a service account key outside Google Cloud, point ADC at the file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUseful environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATA_FUSION_LOCATION=\"us-central1\"\nexport DATA_FUSION_INSTANCE_ID=\"analytics-dev\"\nexport DATA_FUSION_NETWORK=\"projects/your-project-id/global/networks/default\"\n```\n\n`DATA_FUSION_NETWORK` is a full VPC resource name. Keep the project and location consistent across all requests.\n\n## Initialize The Client\n\n```python\nimport os\n\nfrom google.cloud import data_fusion_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"DATA_FUSION_LOCATION\", \"us-central1\")\nINSTANCE_ID = os.getenv(\"DATA_FUSION_INSTANCE_ID\", \"analytics-dev\")\n\nclient = data_fusion_v1.DataFusionClient()\nparent = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\ninstance_name = f\"{parent}/instances/{INSTANCE_ID}\"\n```\n\nIf your application already has explicit Google credentials loaded, you can pass them with the normal generated-client `credentials=` argument when constructing `DataFusionClient()`.\n\n## Core Workflows\n\n### List available Data Fusion versions\n\nUse `list_available_versions()` before creating an instance so you do not hard-code an old runtime version.\n\n```python\nfrom google.cloud import data_fusion_v1\n\nclient = data_fusion_v1.DataFusionClient()\nparent = \"projects/your-project-id/locations/us-central1\"\n\nversions = list(client.list_available_versions(parent=parent))\nfor version in versions:\n    print(version.version_number)\n```\n\n### Create an instance\n\nInstance creation is a long-running operation. Pick the version first, then wait for `.result()`.\n\n```python\nimport os\n\nfrom google.cloud import data_fusion_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"DATA_FUSION_LOCATION\", \"us-central1\")\nINSTANCE_ID = os.getenv(\"DATA_FUSION_INSTANCE_ID\", \"analytics-dev\")\nNETWORK = os.environ[\"DATA_FUSION_NETWORK\"]\n\nclient = data_fusion_v1.DataFusionClient()\nparent = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\n\navailable_versions = list(client.list_available_versions(parent=parent))\nselected_version = available_versions[0].version_number\n\ninstance = data_fusion_v1.Instance(\n    display_name=\"Analytics Dev\",\n    type_=data_fusion_v1.Instance.Type.BASIC,\n    version=selected_version,\n    network_config=data_fusion_v1.NetworkConfig(\n        network=NETWORK,\n    ),\n    labels={\"env\": \"dev\"},\n)\n\nrequest = data_fusion_v1.CreateInstanceRequest(\n    parent=parent,\n    instance_id=INSTANCE_ID,\n    instance=instance,\n)\n\noperation = client.create_instance(request=request)\ncreated = operation.result(timeout=3600)\n\nprint(created.name)\nprint(created.version)\n```\n\nThe `Instance` type also exposes fields for options such as private instance settings, accelerators, and CMEK-related configuration. Add those only when your environment requires them.\n\n### Get or list instances\n\n```python\nfrom google.cloud import data_fusion_v1\n\nclient = data_fusion_v1.DataFusionClient()\nparent = \"projects/your-project-id/locations/us-central1\"\nname = f\"{parent}/instances/analytics-dev\"\n\ninstance = client.get_instance(name=name)\nprint(instance.name, instance.state, instance.version)\n\nfor item in client.list_instances(parent=parent):\n    print(item.name, item.state, item.version)\n```\n\n### Patch an instance\n\nUse `update_instance()` with a field mask. The instance `name` identifies which resource to patch.\n\n```python\nfrom google.cloud import data_fusion_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = data_fusion_v1.DataFusionClient()\n\ninstance = data_fusion_v1.Instance(\n    name=(\n        \"projects/your-project-id/locations/us-central1/\"\n        \"instances/analytics-dev\"\n    ),\n    display_name=\"Analytics Dev Updated\",\n    labels={\"env\": \"dev\", \"team\": \"data-platform\"},\n)\n\nrequest = data_fusion_v1.UpdateInstanceRequest(\n    instance=instance,\n    update_mask=FieldMask(paths=[\"display_name\", \"labels\"]),\n)\n\nupdated = client.update_instance(request=request).result(timeout=3600)\nprint(updated.display_name)\n```\n\n### Restart or delete an instance\n\nBoth operations are long-running.\n\n```python\nfrom google.cloud import data_fusion_v1\n\nclient = data_fusion_v1.DataFusionClient()\nname = \"projects/your-project-id/locations/us-central1/instances/analytics-dev\"\n\nclient.restart_instance(name=name).result(timeout=3600)\nclient.delete_instance(name=name).result(timeout=3600)\n```\n\n## Practical Notes\n\n- Package name and import path differ: install `google-cloud-data-fusion`, import `data_fusion_v1`.\n- Resource names are regional: `projects/{project}/locations/{location}/instances/{instance}`.\n- `instance_id` is the stable resource ID. `display_name` is only a label for humans.\n- `create_instance`, `update_instance`, `restart_instance`, and `delete_instance` return long-running operations. Do not assume the change is finished until `.result()` completes.\n- Use `list_available_versions()` before provisioning instead of copying a version string from an old article or console screenshot.\n- If your task is pipeline design, namespace management, or Studio interaction, this package is not the main API surface. Start with the Data Fusion product docs for that workflow.\n\n## Version Notes For 1.15.0\n\n- PyPI and the generated Python reference both show `1.15.0` as the current library version covered here as of March 13, 2026.\n- The upstream changelog for `1.15.0` is a routine generated-library release; check the current reference if you are adapting examples from older `1.13.x` or `1.14.x` posts.\n\n## Official Sources Used\n\n- PyPI package page: `https://pypi.org/project/google-cloud-data-fusion/`\n- PyPI JSON metadata: `https://pypi.org/pypi/google-cloud-data-fusion/json`\n- Generated package reference and README: `https://googleapis.dev/python/datafusion/latest/`\n- `DataFusionClient` reference: `https://googleapis.dev/python/datafusion/latest/data_fusion_v1/services.html#module-data_fusion_v1.services.data_fusion`\n- `Instance` type reference: `https://googleapis.dev/python/datafusion/latest/data_fusion_v1/types.html#data_fusion_v1.types.Instance`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Cloud Data Fusion create-instance guide: `https://cloud.google.com/data-fusion/docs/how-to/create-instance`\n- Changelog: `https://googleapis.dev/python/datafusion/latest/changelog.html`\n"
  },
  {
    "path": "content/google/docs/datacatalog/javascript/DOC.md",
    "content": "---\nname: datacatalog\ndescription: \"Google Cloud Data Catalog Node.js client for catalog search, entry lookup, entry metadata, tags, and policy-tag client selection\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,datacatalog,metadata,governance,tags,bigquery,javascript,nodejs\"\n---\n\n# `@google-cloud/datacatalog` JavaScript Package Guide\n\nUse `@google-cloud/datacatalog` when your Node.js app needs to search Google Cloud Data Catalog, look up known assets, read entry metadata, or attach tags from an existing tag template.\n\n## Golden Rule\n\nUse the official Google-maintained package and import the generated clients from the `v1` namespace.\n\n- Use `v1.DataCatalogClient` for entries, entry groups, tag templates, tags, search, and lookup.\n- Use `v1.PolicyTagManagerClient` for taxonomies and policy tags.\n- Authenticate with Application Default Credentials (ADC), not API keys.\n- Pass full resource names such as `projects/PROJECT/locations/LOCATION/entryGroups/.../entries/...` when an API expects `name` or `parent`.\n\nThis guide covers `5.2.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/datacatalog@5.2.1\n```\n\n## Authentication And Setup\n\nEnable the API in the project that will call Data Catalog:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable datacatalog.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The Data Catalog API is enabled for the caller project.\n2. The caller has IAM permissions to search metadata, read entries, and manage tags or tag templates.\n3. Your code uses the correct regional resource names for tag templates and custom entries.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst dataCatalogClient = new v1.DataCatalogClient();\nconst policyTagClient = new v1.PolicyTagManagerClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/datacatalog';\n\nconst dataCatalogClient = new v1.DataCatalogClient();\nconst policyTagClient = new v1.PolicyTagManagerClient();\n```\n\nWith an explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst dataCatalogClient = new v1.DataCatalogClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Search Catalog Assets\n\nUse `searchCatalogAsync()` when you know search terms but do not already have the entry resource name.\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst client = new v1.DataCatalogClient();\n\nasync function searchCatalog(projectId) {\n  const request = {\n    scope: {\n      includeProjectIds: [projectId],\n    },\n    query: 'type=entry name:orders',\n    pageSize: 20,\n  };\n\n  for await (const result of client.searchCatalogAsync(request)) {\n    console.log(result.relativeResourceName);\n    console.log(result.linkedResource);\n    console.log(result.searchResultSubtype);\n  }\n}\n\nsearchCatalog(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\nKeep the query narrow when you can. `scope.includeProjectIds` is the usual starting point for project-level searches.\n\n### Look Up A Known Asset\n\nIf you already know the underlying Google Cloud resource, use `lookupEntry()` instead of search.\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst client = new v1.DataCatalogClient();\n\nasync function lookupBigQueryTable(projectId, datasetId, tableId) {\n  const linkedResource =\n    `//bigquery.googleapis.com/projects/${projectId}` +\n    `/datasets/${datasetId}/tables/${tableId}`;\n\n  const [entry] = await client.lookupEntry({\n    linkedResource,\n  });\n\n  console.log(entry.name);\n  console.log(entry.type);\n  console.log(entry.fullyQualifiedName);\n}\n```\n\nOnly set one lookup identifier per request: `linkedResource`, `sqlResource`, or `fullyQualifiedName`.\n\n### Read An Entry And List Its Tags\n\nSearch results are intentionally lightweight. Fetch the full entry when you need schema or metadata, then list tags separately.\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst client = new v1.DataCatalogClient();\n\nasync function readEntryAndTags(entryName) {\n  const [entry] = await client.getEntry({\n    name: entryName,\n  });\n\n  console.log(entry.displayName);\n  console.log(entry.schema?.columns ?? []);\n\n  for await (const tag of client.listTagsAsync({\n    parent: entry.name,\n  })) {\n    console.log(tag.name, tag.template);\n  }\n}\n\nreadEntryAndTags(\n  'projects/my-project/locations/us/entryGroups/@bigquery/entries/orders'\n).catch(console.error);\n```\n\nUse this pattern when a search hit is only a starting point and you need the actual entry contents.\n\n### Attach A Tag From An Existing Tag Template\n\nCreate the tag template first, then attach a tag to the entry with `createTag()`.\n\n```javascript\nconst {v1} = require('@google-cloud/datacatalog');\n\nconst client = new v1.DataCatalogClient();\n\nasync function attachGovernanceTag({\n  projectId,\n  location,\n  tagTemplateId,\n  entryName,\n}) {\n  const [createdTag] = await client.createTag({\n    parent: entryName,\n    tag: {\n      template: client.tagTemplatePath(projectId, location, tagTemplateId),\n      fields: {\n        owner: {\n          stringValue: 'data-platform',\n        },\n        contains_pii: {\n          boolValue: true,\n        },\n      },\n    },\n  });\n\n  console.log(createdTag.name);\n}\n```\n\nThe tag template and the target entry must belong to the same organization.\n\n## Client Selection Notes\n\nUse the right client for the job:\n\n- `v1.DataCatalogClient`: search, lookup, entries, tags, tag templates, entry groups.\n- `v1.PolicyTagManagerClient`: taxonomies and policy tags for column-level governance.\n\nDo not try to manage policy tags through `DataCatalogClient`.\n\n## Common Pitfalls\n\n- Import from `@google-cloud/datacatalog` and then use `.v1`; do not invent package-local import paths.\n- `searchCatalogAsync()` is for discovery. Follow it with `getEntry()` or `lookupEntry()` when you need the full record.\n- `lookupEntry()` uses a oneof request shape; set only one of `linkedResource`, `sqlResource`, or `fullyQualifiedName`.\n- Policy tags use `v1.PolicyTagManagerClient`, not `v1.DataCatalogClient`.\n- Do not hard-code `us-central1` for templates or custom entries unless that is the real location for your metadata.\n- `createTag()` uses a full tag-template resource name; build it with `client.tagTemplatePath(...)` instead of concatenating strings by hand.\n- If ADC is pointed at the wrong project or service account, catalog search may succeed in one environment and fail in another because metadata visibility is IAM-scoped.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/datacatalog` `5.2.1`.\n- The examples use the generated `v1` clients and async-iterator methods shown in the maintained Node.js reference.\n\n## Official URLs\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/datacatalog/latest`\n- Package README in the Google Cloud Node.js monorepo: `https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-datacatalog`\n- Auth setup for ADC: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Data Catalog code samples: `https://cloud.google.com/data-catalog/docs/samples`\n- Search sample: `https://cloud.google.com/data-catalog/docs/samples/data-catalog-search-assets`\n- Quickstart sample: `https://cloud.google.com/data-catalog/docs/samples/data-catalog-quickstart`\n- Data Catalog release notes: `https://cloud.google.com/data-catalog/docs/release-notes`\n"
  },
  {
    "path": "content/google/docs/datacatalog/python/DOC.md",
    "content": "---\nname: datacatalog\ndescription: \"google-cloud-datacatalog package guide for Python legacy Data Catalog integrations and migration work\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,google-cloud-datacatalog,data-catalog,metadata,governance\"\n---\n\n# google-cloud-datacatalog Python Package Guide\n\n## Status\n\n`google-cloud-datacatalog` is the Google-maintained Python client for Google Cloud Data Catalog.\n\nUse this package only for legacy maintenance or migration work. Google Cloud's generated client reference marks `DataCatalogClient` as deprecated in favor of Dataplex Catalog, and the Data Catalog release notes announced a shutdown date of January 30, 2026. As of March 12, 2026, the Python package `3.29.0` and its reference docs are still published, but new integrations should target Dataplex Catalog unless you have a specific legacy requirement.\n\n## Install\n\n```bash\npip install google-cloud-datacatalog==3.29.0\n```\n\n```bash\nuv add google-cloud-datacatalog==3.29.0\n```\n\n```bash\npoetry add google-cloud-datacatalog==3.29.0\n```\n\n## Authentication And Setup\n\nThe client uses Application Default Credentials (ADC). For local development, the usual order is:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS` pointing at a service-account key JSON file.\n2. `gcloud auth application-default login` for user credentials.\n3. Attached service-account credentials when running on Google Cloud.\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/abs/path/service-account.json\"\n```\n\n```python\nfrom google.cloud import datacatalog_v1\n\nclient = datacatalog_v1.DataCatalogClient()\n```\n\nNotes:\n\n- Prefer ADC or an explicit `credentials=` object. The library changelog deprecates the older `credentials_file` client argument in recent releases.\n- Keep the Data Catalog API enabled in the target project if you are maintaining an existing deployment.\n- If you are migrating away from Data Catalog, validate service availability first instead of assuming the legacy API is still enabled everywhere.\n\n## Core Client Types\n\n```python\nfrom google.cloud import datacatalog_v1\n\ncatalog_client = datacatalog_v1.DataCatalogClient()\ncatalog_async_client = datacatalog_v1.DataCatalogAsyncClient()\npolicy_tag_client = datacatalog_v1.PolicyTagManagerClient()\nserialization_client = datacatalog_v1.PolicyTagManagerSerializationClient()\n```\n\nUse them for different surfaces:\n\n- `DataCatalogClient`: entries, entry groups, tag templates, tags, search, lookup.\n- `PolicyTagManagerClient`: taxonomies and policy tags for column-level governance.\n- `PolicyTagManagerSerializationClient`: import or export entire taxonomies.\n\nPolicy tags are not managed through `DataCatalogClient`, which is a common source of agent mistakes.\n\n## Common Usage\n\n### Search Catalog Assets\n\n`search_catalog` is the main discovery call. It returns a pager.\n\n```python\nfrom google.cloud import datacatalog_v1\n\nproject_id = \"my-project\"\n\nclient = datacatalog_v1.DataCatalogClient()\nscope = datacatalog_v1.SearchCatalogRequest.Scope()\nscope.include_project_ids.append(project_id)\n\nrequest = datacatalog_v1.SearchCatalogRequest(\n    scope=scope,\n    query=\"type=entry name:orders\",\n    page_size=20,\n)\n\nfor result in client.search_catalog(request=request):\n    print(result.relative_resource_name)\n    print(result.linked_resource)\n    print(result.search_result_subtype)\n```\n\nUse search when you know keywords, asset type, columns, tags, or business terms but do not already have the entry name.\n\n### Look Up A Known Asset\n\nIf you already know the underlying Google Cloud resource, `lookup_entry` is usually more reliable than search.\n\n```python\nfrom google.cloud import datacatalog_v1\n\nproject_id = \"my-project\"\ndataset_id = \"analytics\"\ntable_id = \"orders\"\n\nclient = datacatalog_v1.DataCatalogClient()\nlinked_resource = (\n    f\"//bigquery.googleapis.com/projects/{project_id}\"\n    f\"/datasets/{dataset_id}/tables/{table_id}\"\n)\n\nentry = client.lookup_entry(\n    request=datacatalog_v1.LookupEntryRequest(\n        linked_resource=linked_resource,\n    )\n)\n\nprint(entry.name)\nprint(entry.type_)\nprint(entry.fully_qualified_name)\n```\n\nUse `lookup_entry` when you have one of the supported identifiers:\n\n- `linked_resource` for a concrete resource URI such as BigQuery or Pub/Sub.\n- `sql_resource` for SQL resources.\n- `fully_qualified_name` for supported systems.\n\nOnly set one of those fields in the request.\n\n### Read An Entry And Its Tags\n\nSearch results are intentionally lightweight. Fetch the entry when you need the full record, then list tags separately.\n\n```python\nfrom google.cloud import datacatalog_v1\n\nclient = datacatalog_v1.DataCatalogClient()\nentry_name = \"projects/my-project/locations/us/entryGroups/@bigquery/entries/orders\"\n\nentry = client.get_entry(request={\"name\": entry_name})\nprint(entry.display_name)\nprint(entry.schema.columns)\n\nfor tag in client.list_tags(request={\"parent\": entry.name}):\n    print(tag.name, tag.template)\n```\n\n### Attach A Tag From An Existing Tag Template\n\nThis is the common metadata-enrichment flow after you already created the tag template in the same project and organization.\n\n```python\nfrom google.cloud import datacatalog_v1\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\ntag_template_id = \"governance_template\"\nentry_name = \"projects/my-project/locations/us/entryGroups/@bigquery/entries/orders\"\n\nclient = datacatalog_v1.DataCatalogClient()\n\ntag = datacatalog_v1.Tag()\ntag.template = client.tag_template_path(project_id, location, tag_template_id)\ntag.fields[\"owner\"].string_value = \"data-platform\"\ntag.fields[\"contains_pii\"].bool_value = True\n\ncreated = client.create_tag(\n    request=datacatalog_v1.CreateTagRequest(\n        parent=entry_name,\n        tag=tag,\n    )\n)\n\nprint(created.name)\n```\n\nImportant constraint: the entry and the tag template must belong to the same organization.\n\n## Configuration Notes\n\n### Credentials\n\nIf you need explicit credentials instead of ADC, pass a credentials object:\n\n```python\nfrom google.cloud import datacatalog_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/abs/path/service-account.json\"\n)\n\nclient = datacatalog_v1.DataCatalogClient(credentials=credentials)\n```\n\n### Endpoints And Client Options\n\nMost legacy integrations use the default endpoint and do not need custom transport settings.\n\nIf you must override the endpoint:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import datacatalog_v1\n\nclient = datacatalog_v1.DataCatalogClient(\n    client_options=ClientOptions(api_endpoint=\"datacatalog.googleapis.com\")\n)\n```\n\nOnly override `api_endpoint` when the product documentation for your exact workload requires it.\n\n## Common Pitfalls\n\n- The import name is `datacatalog_v1`, not `google_cloud_datacatalog`.\n- Treat Data Catalog as a legacy surface. For new metadata catalog work, use Dataplex Catalog.\n- `search_catalog` does not guarantee full recall. Use it for discovery, then follow up with `get_entry`, `lookup_entry`, or targeted reads.\n- `lookup_entry` uses a oneof request shape. Set only one of `linked_resource`, `sql_resource`, or `fully_qualified_name`.\n- The official quickstart and tag-template samples often use `us-central1`. Do not hard-code that location unless your resources or templates actually live there.\n- `create_tag` requires the tag template and the target entry to be in the same organization.\n- Policy tags use `PolicyTagManagerClient`, not `DataCatalogClient`.\n- If you copied older client-construction examples that pass `credentials_file=...`, update them to ADC or explicit `credentials=...`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `3.29.0` as the current package version for `google-cloud-datacatalog`.\n- The published changelog for recent releases shows Python 3.14 support added in `3.28.0`.\n- The same changelog deprecates the `credentials_file` argument in favor of `credentials`.\n- The `3.26.0` changelog explicitly marks the Data Catalog service as deprecated.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/google-cloud-datacatalog/`\n- PyPI metadata JSON: `https://pypi.org/pypi/google-cloud-datacatalog/json`\n- Python client reference root: `https://cloud.google.com/python/docs/reference/datacatalog/latest`\n- `DataCatalogClient` reference: `https://cloud.google.com/python/docs/reference/datacatalog/latest/google.cloud.datacatalog_v1.services.data_catalog.DataCatalogClient`\n- Library changelog: `https://cloud.google.com/python/docs/reference/datacatalog/latest/changelog`\n- Data Catalog search sample: `https://cloud.google.com/data-catalog/docs/samples/data-catalog-search-assets`\n- Data Catalog quickstart sample: `https://cloud.google.com/data-catalog/docs/samples/data-catalog-quickstart`\n- ADC guide: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Data Catalog release notes: `https://cloud.google.com/data-catalog/docs/release-notes`\n"
  },
  {
    "path": "content/google/docs/dataflow/javascript/DOC.md",
    "content": "---\nname: dataflow\ndescription: \"Google Cloud Dataflow Node.js client for inspecting jobs and launching classic or Flex templates\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,dataflow,templates,apache-beam,javascript,nodejs\"\n---\n\n# `@google-cloud/dataflow` JavaScript Package Guide\n\nUse `@google-cloud/dataflow` when your Node.js code needs the Dataflow service API: list jobs, inspect a job, read job messages or metrics, or launch classic and Flex templates.\n\n## Golden Rule\n\n- Use the official `@google-cloud/dataflow` package.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Pass `location` on every request instead of relying on defaults.\n- Treat this package as a Dataflow control-plane client. Author pipelines or build templates with Beam or other supported tooling first, then use this library to launch or manage them.\n- Keep every template path and temp location in Cloud Storage as a `gs://...` URI.\n\nThis guide covers `4.1.1`.\n\n## Install\n\n```bash\nnpm install @google-cloud/dataflow@4.1.1\n```\n\n## Authentication And Setup\n\nEnable the API and authenticate with ADC:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport DATAFLOW_REGION=\"us-central1\"\nexport DATAFLOW_TEMP_LOCATION=\"gs://my-bucket/dataflow/temp\"\n\ngcloud auth application-default login\ngcloud config set project \"$GOOGLE_CLOUD_PROJECT\"\ngcloud services enable dataflow.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nIf you are using a service account JSON file locally:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport DATAFLOW_REGION=\"us-central1\"\nexport DATAFLOW_TEMP_LOCATION=\"gs://my-bucket/dataflow/temp\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project already exists.\n2. The Dataflow API is enabled in that project.\n3. The runtime identity can launch Dataflow jobs and read any `gs://` objects referenced by templates.\n4. A Cloud Storage bucket exists for temporary files, staging files, or template specs.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.DATAFLOW_REGION || 'us-central1';\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client();\nconst messagesClient = new v1beta3.MessagesV1Beta3Client();\nconst metricsClient = new v1beta3.MetricsV1Beta3Client();\nconst templatesClient = new v1beta3.TemplatesServiceClient();\nconst flexTemplatesClient = new v1beta3.FlexTemplatesServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1beta3} from '@google-cloud/dataflow';\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client();\n```\n\nIf ADC is already configured, you usually do not need to pass `keyFilename`. When you do want to pin a credentials file explicitly, pass it in the client options:\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client({\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\n## Core Workflows\n\n### List Jobs In A Region\n\n`listJobsAsync()` is the easiest way to iterate through job summaries.\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client();\n\nasync function listJobs(projectId, location) {\n  for await (const job of jobsClient.listJobsAsync({projectId, location})) {\n    console.log({\n      id: job.id,\n      name: job.name,\n      state: job.currentState,\n      type: job.type,\n    });\n  }\n}\n```\n\nUse `getJob()` when you need the full job record. `listJobs()` returns summaries.\n\n### Get A Single Job\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client();\n\nasync function getJob(projectId, location, jobId) {\n  const [job] = await jobsClient.getJob({\n    projectId,\n    location,\n    jobId,\n  });\n\n  console.log({\n    id: job.id,\n    name: job.name,\n    currentState: job.currentState,\n    createTime: job.createTime,\n  });\n\n  return job;\n}\n```\n\n### Launch A Classic Template\n\nClassic template launches use `TemplatesServiceClient` with a GCS template path such as `gs://dataflow-templates/latest/Word_Count`.\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst templatesClient = new v1beta3.TemplatesServiceClient();\n\nasync function launchClassicTemplate(projectId, location) {\n  const [response] = await templatesClient.launchTemplate({\n    projectId,\n    location,\n    gcsPath: 'gs://dataflow-templates/latest/Word_Count',\n    launchParameters: {\n      jobName: `wordcount-${Date.now()}`,\n      parameters: {\n        inputFile: 'gs://dataflow-samples/shakespeare/kinglear.txt',\n        output: 'gs://my-bucket/output/wordcount',\n      },\n      environment: {\n        tempLocation: process.env.DATAFLOW_TEMP_LOCATION,\n      },\n    },\n    validateOnly: true,\n  });\n\n  return response;\n}\n```\n\nStart with `validateOnly: true` to validate the launch request without creating a job. Set it to `false` after the parameters and environment are correct.\n\n### Launch A Flex Template\n\nFlex template launches use `FlexTemplatesServiceClient` and a template spec stored in Cloud Storage.\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst flexTemplatesClient = new v1beta3.FlexTemplatesServiceClient();\n\nasync function launchFlexTemplate(projectId, location) {\n  const [response] = await flexTemplatesClient.launchFlexTemplate({\n    projectId,\n    location,\n    launchParameter: {\n      jobName: `orders-etl-${Date.now()}`,\n      containerSpecGcsPath: 'gs://my-bucket/dataflow/flex/orders-spec.json',\n      parameters: {\n        inputSubscription: 'projects/my-project-id/subscriptions/orders-sub',\n        outputTableSpec: 'my-project-id:analytics.orders',\n      },\n      environment: {\n        tempLocation: process.env.DATAFLOW_TEMP_LOCATION,\n      },\n    },\n    validateOnly: false,\n  });\n\n  return response;\n}\n```\n\nUse a real template spec path generated for your Flex Template. Local files are not valid for `containerSpecGcsPath`.\n\n### Read Job Messages And Metrics\n\nUse `MessagesV1Beta3Client` for logs and `MetricsV1Beta3Client` for metrics snapshots.\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst messagesClient = new v1beta3.MessagesV1Beta3Client();\nconst metricsClient = new v1beta3.MetricsV1Beta3Client();\n\nasync function inspectJob(projectId, location, jobId) {\n  for await (const message of messagesClient.listJobMessagesAsync({\n    projectId,\n    location,\n    jobId,\n  })) {\n    console.log(message.messageText);\n  }\n\n  const [metrics] = await metricsClient.getJobMetrics({\n    projectId,\n    location,\n    jobId,\n  });\n\n  for (const metric of metrics.metrics || []) {\n    console.log(metric.name?.name, metric.scalar);\n  }\n}\n```\n\n### Drain Or Cancel A Job\n\n`updateJob()` is for job state changes, not general job edits.\n\n```javascript\nconst {v1beta3} = require('@google-cloud/dataflow');\n\nconst jobsClient = new v1beta3.JobsV1Beta3Client();\n\nasync function drainJob(projectId, location, jobId) {\n  const [job] = await jobsClient.updateJob({\n    projectId,\n    location,\n    jobId,\n    job: {\n      requestedState: 'JOB_STATE_DRAINED',\n    },\n  });\n\n  return job;\n}\n```\n\nUse `JOB_STATE_CANCELLED` when you want cancellation instead of a drain request.\n\n## Common Pitfalls\n\n- Do not omit `location`. Explicit regional requests are safer than relying on defaults.\n- Do not pass local filesystem paths where the API expects `gs://` URIs.\n- Do not treat `listJobs()` output as the full job record; call `getJob()` for complete details.\n- Do not expect `updateJob()` to patch arbitrary fields. It is used for job state transitions.\n- Do not use this package as a replacement for Apache Beam or a template build process.\n- Do not use API keys. Use ADC or service account credentials.\n\n## Official Sources Used\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/dataflow/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/dataflow`\n- Dataflow authentication with ADC: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Dataflow template launch REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.templates/launch`\n- Dataflow Flex Template launch REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.flexTemplates/launch`\n- Dataflow jobs REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.jobs`\n- Dataflow metrics REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.jobs/getMetrics`\n- Dataflow messages REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.jobs.messages/list`\n"
  },
  {
    "path": "content/google/docs/dataflow/python/DOC.md",
    "content": "---\nname: dataflow\ndescription: \"Google Cloud Dataflow Python guide for the legacy google-cloud-dataflow package row and the current Dataflow client split\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,dataflow,gcp,apache-beam,pipelines,templates\"\n---\n\n# Google Cloud Dataflow Python Guide\n\n## Golden Rule\n\nTreat `google-cloud-dataflow==2.5.0` as a legacy package row, not the modern Python 3 SDK for Google Cloud Dataflow.\n\nAs of March 12, 2026:\n\n- PyPI still lists `google-cloud-dataflow 2.5.0`, released on June 27, 2018, with `Requires: Python >=2.7, <3.0`.\n- The official Python reference at `https://cloud.google.com/python/docs/reference/dataflow/latest` is for the separate `google-cloud-dataflow-client` package, not for `google-cloud-dataflow`.\n- Google Cloud's current pipeline quickstart for Python uses `apache-beam[gcp]` to submit Beam pipelines to the Dataflow service.\n\nIf you are writing new Python 3 code:\n\n- Use `apache-beam[gcp]` to author and run Dataflow pipelines.\n- Use `google-cloud-dataflow-client` only when you need the Dataflow control-plane API for jobs, templates, metrics, messages, or snapshots.\n- Do not install `google-cloud-dataflow` unless you are intentionally maintaining a legacy Python 2 codebase pinned to that distribution.\n\n## Package Split And Upstream Drift\n\n- Version used here: `2.5.0`\n- Registry URL: `https://pypi.org/project/google-cloud-dataflow/`\n- Docs URL: `https://cloud.google.com/python/docs/reference/dataflow/latest`\n\nThose URLs do not describe the same published distribution:\n\n- `google-cloud-dataflow` is the old PyPI package row tracked here.\n- `google-cloud-dataflow-client` is the current generated Python client library documented at the Google Cloud reference URL.\n- `apache-beam[gcp]` is the modern package used to build and submit Python pipelines to Dataflow.\n\nThis entry is therefore a resolution guide first: it tells agents which package to use for which task before showing code.\n\n## Install\n\n### Legacy Compatibility Only\n\nOnly use this if the project is explicitly pinned to the old `google-cloud-dataflow` package and can still run under Python 2:\n\n```bash\npython2 -m pip install \"google-cloud-dataflow==2.5.0\"\n```\n\nThis is usually the wrong choice for current code.\n\n### Authoring And Running Dataflow Pipelines\n\nUse Apache Beam with Google Cloud extras:\n\n```bash\npython -m pip install \"apache-beam[gcp]\"\n```\n\n### Calling The Dataflow Service API\n\nUse the current generated client library:\n\n```bash\npython -m pip install \"google-cloud-dataflow-client\"\n```\n\nThe current Google Cloud Python reference page identifies `google-cloud-dataflow-client 0.11.0` as the latest published client library.\n\n## Auth And Project Setup\n\nFor modern Python 3 usage, follow normal Google Cloud authentication and project setup:\n\n1. Enable billing and the Dataflow API on the target Google Cloud project.\n2. Authenticate with Application Default Credentials (ADC).\n3. Choose a region up front.\n4. Create a GCS bucket for staging and temporary files.\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project MY_PROJECT_ID\n```\n\nService account based auth:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor Beam jobs, you will usually also need:\n\n```bash\nexport DATAFLOW_REGION=\"us-central1\"\nexport DATAFLOW_STAGING_LOCATION=\"gs://my-bucket/dataflow/staging\"\nexport DATAFLOW_TEMP_LOCATION=\"gs://my-bucket/dataflow/temp\"\n```\n\n## Which API Surface To Use\n\n### Use `apache-beam[gcp]` when you need to run a pipeline\n\nTypical tasks:\n\n- ETL or batch transforms\n- streaming pipelines\n- writing to BigQuery, Pub/Sub, GCS, or other Beam connectors\n- local testing before running on Dataflow\n\nMinimal pipeline options for a Dataflow run:\n\n```python\nfrom apache_beam.options.pipeline_options import PipelineOptions\n\noptions = PipelineOptions(\n    runner=\"DataflowRunner\",\n    project=\"my-project-id\",\n    region=\"us-central1\",\n    temp_location=\"gs://my-bucket/dataflow/temp\",\n    staging_location=\"gs://my-bucket/dataflow/staging\",\n    job_name=\"wordcount-20260312\",\n)\n```\n\nThe Dataflow quickstart and pipeline options docs make `apache-beam[gcp]` the authoritative starting point for new Python pipeline code.\n\n### Use `google-cloud-dataflow-client` when you need to manage jobs or templates\n\nTypical tasks:\n\n- list or inspect running jobs\n- launch classic templates or flex templates\n- fetch job messages or metrics\n- create snapshots or drain/cancel jobs through the API\n\nImport path:\n\n```python\nfrom google.cloud import dataflow_v1beta3\n```\n\n## Core Usage With `google-cloud-dataflow-client`\n\n### Create A Jobs Client\n\nThe generated docs recommend using regional endpoints for service calls. Keep the request `location` aligned with the region where the job runs.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataflow_v1beta3\n\nREGION = \"us-central1\"\nREGIONAL_ENDPOINT = \"YOUR_REGIONAL_DATAFLOW_ENDPOINT\"\n\nclient = dataflow_v1beta3.JobsV1Beta3Client(\n    client_options=ClientOptions(api_endpoint=REGIONAL_ENDPOINT)\n)\n```\n\n### List Jobs\n\n`list_jobs` returns job summaries. Use `get_job` when you need the full job record.\n\n```python\nfrom google.cloud import dataflow_v1beta3\n\nclient = dataflow_v1beta3.JobsV1Beta3Client()\n\nrequest = dataflow_v1beta3.ListJobsRequest(\n    project_id=\"my-project-id\",\n    location=\"us-central1\",\n)\n\nfor job in client.list_jobs(request=request):\n    print(job)\n```\n\n### Get A Single Job\n\n```python\nfrom google.cloud import dataflow_v1beta3\n\nclient = dataflow_v1beta3.JobsV1Beta3Client()\n\nrequest = dataflow_v1beta3.GetJobRequest(\n    project_id=\"my-project-id\",\n    location=\"us-central1\",\n    job_id=\"2026-03-12_10_00_00-1234567890123456789\",\n)\n\njob = client.get_job(request=request)\nprint(job)\n```\n\n### Launch A Classic Template\n\nThe template launch request takes a regional `location`, a GCS template path, launch parameters, and optional runtime environment values such as `temp_location` and `service_account_email`.\n\n```python\nfrom google.cloud import dataflow_v1beta3\n\nclient = dataflow_v1beta3.TemplatesServiceClient()\n\nrequest = dataflow_v1beta3.LaunchTemplateRequest(\n    project_id=\"my-project-id\",\n    location=\"us-central1\",\n    gcs_path=\"gs://dataflow-templates/latest/Word_Count\",\n    launch_parameters=dataflow_v1beta3.LaunchTemplateParameters(\n        job_name=\"wordcount-template-run\",\n        parameters={\n            \"inputFile\": \"gs://dataflow-samples/shakespeare/kinglear.txt\",\n            \"output\": \"gs://my-bucket/output/wordcount\",\n        },\n        environment=dataflow_v1beta3.RuntimeEnvironment(\n            temp_location=\"gs://my-bucket/dataflow/temp\",\n            service_account_email=\"dataflow-runner@my-project-id.iam.gserviceaccount.com\",\n        ),\n    ),\n    validate_only=False,\n)\n\nresponse = client.launch_template(request=request)\nprint(response)\n```\n\nSet `validate_only=True` first if you want the API to validate the request without launching a job.\n\n## Config Notes For Beam Pipelines\n\nWhen the task is \"run this pipeline on Dataflow\", the configuration that usually matters most is on the Beam side:\n\n- `runner=\"DataflowRunner\"`\n- `project`\n- `region`\n- `temp_location`\n- `staging_location`\n- `job_name`\n\nUseful optional flags to remember for Beam-based runs:\n\n- `save_main_session=True` when worker imports depend on local module state\n- `setup_file` or `requirements_file` when workers need extra dependencies\n- `service_account_email` when jobs must run under a non-default identity\n- `subnetwork`, `network`, and worker machine options for private networking or sizing\n\n## Common Pitfalls\n\n- Installing the wrong package is the biggest failure mode here. `google-cloud-dataflow` is not the current Python 3 client library.\n- The legacy `google-cloud-dataflow` package is Python 2 only. For Python 3 projects, it is the wrong dependency.\n- The docs URL in the queue points to `google-cloud-dataflow-client`, whose import path is `google.cloud.dataflow_v1beta3`. Do not assume the import name matches the old PyPI package name.\n- The generated client docs repeatedly recommend regional endpoints. Do not mix a regional `location` with the wrong service endpoint.\n- Template launch requests expect GCS paths such as `gs://...`; local filesystem paths will not work for `gcs_path` or `temp_location`.\n- `projects.templates.launch` without a regional `location` defaults to `us-central1`; Google recommends the regional `projects.locations.templates.launch` form instead.\n- `list_jobs` returns summaries and its `view` selector is deprecated. Call `get_job` if you need full details.\n- `update_job` only updates job state. Do not treat it as a general patch endpoint.\n- The Dataflow API docs warn not to send confidential information in raw string fields unless the transport itself is protected.\n\n## Version-Sensitive Notes\n\n- The frontmatter version for this entry remains `2.5.0` because that is the legacy PyPI package this guide covers.\n- As of March 12, 2026, `google-cloud-dataflow 2.5.0` is still the latest release on PyPI for that legacy package, and it still requires Python `<3.0`.\n- As of March 12, 2026, the Google Cloud Python reference page reports `google-cloud-dataflow-client 0.11.0` as the latest generated client library.\n- If you are curating or debugging a modern Dataflow Python project, treat the package split explicitly:\n  - pipeline authoring: `apache-beam[gcp]`\n  - service management API: `google-cloud-dataflow-client`\n  - legacy compatibility only: `google-cloud-dataflow==2.5.0`\n\n## Official Sources Used\n\n- PyPI legacy package: `https://pypi.org/project/google-cloud-dataflow/`\n- Google Cloud Python reference root: `https://cloud.google.com/python/docs/reference/dataflow/latest`\n- Dataflow client package page: `https://pypi.org/project/google-cloud-dataflow-client/`\n- Dataflow Python guide and quickstart: `https://cloud.google.com/dataflow/docs/guides/installing-beam-sdk`\n- Dataflow pipeline options: `https://cloud.google.com/dataflow/docs/guides/setting-pipeline-options`\n- Dataflow authentication: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Jobs client reference: `https://cloud.google.com/python/docs/reference/dataflow/latest/google.cloud.dataflow_v1beta3.services.jobs_v1_beta3.JobsV1Beta3Client`\n- Templates service reference: `https://cloud.google.com/python/docs/reference/dataflow/latest/google.cloud.dataflow_v1beta3.services.templates_service.TemplatesServiceClient`\n- Launch template request reference: `https://cloud.google.com/python/docs/reference/dataflow/latest/google.cloud.dataflow_v1beta3.types.LaunchTemplateRequest`\n- Dataflow template launch REST docs: `https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.templates/launch`\n"
  },
  {
    "path": "content/google/docs/dataform/python/DOC.md",
    "content": "---\nname: dataform\ndescription: \"Google Cloud Dataform Python client for repositories, workspaces, compilation results, and workflow invocations\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,dataform,bigquery,gcp,sql,workflow,python\"\n---\n\n# Google Cloud Dataform Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-dataform` package with `from google.cloud import dataform_v1`, and authenticate with Google Cloud credentials through Application Default Credentials (ADC) unless you have a reason to pass explicit credentials.\n\nFor new code, prefer the stable `dataform_v1` namespace. The package also publishes `dataform_v1beta1`, but the stable `v1` surface is the better default when the reference docs cover the feature you need.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-dataform==0.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dataform==0.9.0\"\npoetry add \"google-cloud-dataform==0.9.0\"\n```\n\n## Authentication And Setup\n\nThe Dataform client library uses normal Google Cloud credentials, not API keys.\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport DATAFORM_REPOSITORY=\"analytics\"\nexport DATAFORM_WORKSPACE=\"dev\"\n```\n\nService account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport DATAFORM_REPOSITORY=\"analytics\"\nexport DATAFORM_WORKSPACE=\"dev\"\n```\n\nBasic client initialization with ADC:\n\n```python\nimport os\n\nfrom google.cloud import dataform_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nREPOSITORY = os.environ[\"DATAFORM_REPOSITORY\"]\nWORKSPACE = os.environ[\"DATAFORM_WORKSPACE\"]\n\nclient = dataform_v1.DataformClient()\n\nlocation_name = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\nrepository_name = f\"{location_name}/repositories/{REPOSITORY}\"\nworkspace_name = f\"{repository_name}/workspaces/{WORKSPACE}\"\n```\n\nExplicit service account credentials:\n\n```python\nfrom google.cloud import dataform_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = dataform_v1.DataformClient(credentials=credentials)\n```\n\n## Common Workflows\n\n### List repositories in a location\n\nDataform resources are regional. Start from `projects/{project}/locations/{location}` when listing repositories:\n\n```python\nimport os\n\nfrom google.cloud import dataform_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = dataform_v1.DataformClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor repository in client.list_repositories(request={\"parent\": parent}):\n    print(repository.name)\n```\n\n### Get a workspace\n\nUse the full resource name for workspace reads:\n\n```python\nimport os\n\nfrom google.cloud import dataform_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nrepository_id = os.environ[\"DATAFORM_REPOSITORY\"]\nworkspace_id = os.environ[\"DATAFORM_WORKSPACE\"]\n\nclient = dataform_v1.DataformClient()\nworkspace_name = (\n    f\"projects/{project_id}/locations/{location}\"\n    f\"/repositories/{repository_id}/workspaces/{workspace_id}\"\n)\n\nworkspace = client.get_workspace(request={\"name\": workspace_name})\nprint(workspace.name)\n```\n\n### Create a compilation result\n\n`CompilationResult` can compile from a workspace, a Git commit-ish, or a release config. For an ad hoc run from your current workspace, set `workspace`:\n\n```python\nimport os\n\nfrom google.cloud import dataform_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nrepository_id = os.environ[\"DATAFORM_REPOSITORY\"]\nworkspace_id = os.environ[\"DATAFORM_WORKSPACE\"]\n\nclient = dataform_v1.DataformClient()\nrepository_name = f\"projects/{project_id}/locations/{location}/repositories/{repository_id}\"\nworkspace_name = f\"{repository_name}/workspaces/{workspace_id}\"\n\ncompilation_result = client.create_compilation_result(\n    request={\n        \"parent\": repository_name,\n        \"compilation_result\": {\n            \"workspace\": workspace_name,\n        },\n    }\n)\n\nprint(compilation_result.name)\n```\n\nCompile from a Git reference instead:\n\n```python\ncompilation_result = client.create_compilation_result(\n    request={\n        \"parent\": repository_name,\n        \"compilation_result\": {\n            \"git_commitish\": \"main\",\n        },\n    }\n)\n```\n\n### Inspect actions in a compilation result\n\nUse `query_compilation_result_actions` before you trigger execution so you can see what the compilation produced:\n\n```python\nresponse = client.query_compilation_result_actions(\n    request={\"name\": compilation_result.name}\n)\n\nfor action in response.compilation_result_actions:\n    target = action.target\n    if target:\n        print(target.database, target.schema, target.name)\n```\n\n### Start a workflow invocation from a compilation result\n\nUse a `WorkflowInvocation` when you want Dataform to run the compiled actions. `invocation_config` lets you scope execution by tags or targets.\n\n```python\nworkflow_invocation = client.create_workflow_invocation(\n    request={\n        \"parent\": repository_name,\n        \"workflow_invocation\": {\n            \"compilation_result\": compilation_result.name,\n            \"invocation_config\": {\n                \"included_tags\": [\"daily\"],\n                \"transitive_dependencies_included\": True,\n            },\n        },\n    }\n)\n\nprint(workflow_invocation.name)\n```\n\nTo target a specific action instead of tags, pass `included_targets`:\n\n```python\nworkflow_invocation = client.create_workflow_invocation(\n    request={\n        \"parent\": repository_name,\n        \"workflow_invocation\": {\n            \"compilation_result\": compilation_result.name,\n            \"invocation_config\": {\n                \"included_targets\": [\n                    {\n                        \"database\": \"YOUR_PROJECT_ID\",\n                        \"schema\": \"analytics\",\n                        \"name\": \"daily_revenue\",\n                    }\n                ],\n                \"transitive_dependencies_included\": True,\n            },\n        },\n    }\n)\n```\n\n### Poll a workflow invocation\n\nUse `get_workflow_invocation` for the current state:\n\n```python\nfrom google.cloud import dataform_v1\n\nclient = dataform_v1.DataformClient()\n\ncurrent = client.get_workflow_invocation(\n    request={\"name\": workflow_invocation.name}\n)\n\nprint(current.name)\nprint(current.state.name)\n```\n\nPoll that same call in your own retry loop until the state reaches the terminal value your application expects.\n\n### Inspect per-action execution status\n\nAfter a workflow starts, query the invocation actions instead of the compilation actions:\n\n```python\nresponse = client.query_workflow_invocation_actions(\n    request={\"name\": workflow_invocation.name}\n)\n\nfor action in response.workflow_invocation_actions:\n    target = action.target\n    name = target.name if target else \"<unknown>\"\n    print(name, action.state.name)\n```\n\n### Cancel a running workflow invocation\n\n```python\nclient.cancel_workflow_invocation(\n    request={\"name\": workflow_invocation.name}\n)\n```\n\n## Common Pitfalls\n\n- Install `google-cloud-dataform`, but import from `google.cloud import dataform_v1`.\n- Keep `project`, `location`, repository, workspace, compilation result, and workflow invocation names aligned. Dataform resource names are region-scoped under `projects/{project}/locations/{location}`.\n- `query_compilation_result_actions` shows what a compilation produced. `query_workflow_invocation_actions` shows execution state after you start a workflow.\n- If you want an ad hoc run from current workspace contents, create a fresh `CompilationResult` first and invoke that result. Do not expect a workflow invocation to compile your workspace implicitly.\n- Use `included_tags` or `included_targets` in `InvocationConfig` when you do not want to run everything in the compilation result.\n\n## Version Notes\n\nAs of March 13, 2026, PyPI lists `google-cloud-dataform 0.9.0`, but the generated Google Cloud Python reference pages still show older page-level version labels and the published changelog lags further behind. Use PyPI as the package-version source of truth, and use the `dataform_v1` reference pages for method names and request shapes.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-dataform/\n- Python client library overview: https://cloud.google.com/python/docs/reference/dataform/latest\n- `DataformClient` reference: https://cloud.google.com/python/docs/reference/dataform/latest/google.cloud.dataform_v1.services.dataform.DataformClient\n- `CompilationResult` type: https://cloud.google.com/python/docs/reference/dataform/latest/google.cloud.dataform_v1.types.CompilationResult\n- `WorkflowInvocation` type: https://cloud.google.com/python/docs/reference/dataform/latest/google.cloud.dataform_v1.types.WorkflowInvocation\n- `QueryCompilationResultActionsResponse` type: https://cloud.google.com/python/docs/reference/dataform/latest/google.cloud.dataform_v1.types.QueryCompilationResultActionsResponse\n- `QueryWorkflowInvocationActionsResponse` type: https://cloud.google.com/python/docs/reference/dataform/latest/google.cloud.dataform_v1.types.QueryWorkflowInvocationActionsResponse\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- Changelog: https://cloud.google.com/python/docs/reference/dataform/latest/changelog\n"
  },
  {
    "path": "content/google/docs/dataplex/python/DOC.md",
    "content": "---\nname: dataplex\ndescription: \"Google Cloud Dataplex Python client for lake management, catalog lookups, and data scans\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,dataplex,gcp,python,data-governance,data-quality,catalog\"\n---\n\n# Google Cloud Dataplex Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-dataplex` client with Google Cloud authentication.\n\nFor most Python code, the important clients are:\n\n- `dataplex_v1.DataplexServiceClient` for lakes, zones, assets, tasks, and environments\n- `dataplex_v1.DataScanServiceClient` for data profile and data quality scans\n- `dataplex_v1.CatalogServiceClient` for catalog entry lookup and search\n\nDataplex uses Google Cloud credentials, not API keys.\n\n## Install\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-dataplex==2.16.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dataplex==2.16.0\"\npoetry add \"google-cloud-dataplex==2.16.0\"\n```\n\n## Authentication And Setup\n\nEnable Dataplex for the target project and authenticate with Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\ngcloud services enable dataplex.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATAPLEX_LOCATION=\"us-central1\"\n```\n\nIf you need to use a service account key file explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATAPLEX_LOCATION=\"us-central1\"\n```\n\nIf your workflow scans BigQuery tables or catalogs Cloud Storage data, those resources must already exist and be accessible to the caller.\n\n## Initialize Clients\n\nCreate clients once and reuse them:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"DATAPLEX_LOCATION\", \"us-central1\")\n\ndataplex_client = dataplex_v1.DataplexServiceClient()\nscan_client = dataplex_v1.DataScanServiceClient()\ncatalog_client = dataplex_v1.CatalogServiceClient()\n```\n\nIf you need explicit credentials:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nscan_client = dataplex_v1.DataScanServiceClient(credentials=credentials)\n```\n\n## Core Workflows\n\n### List Or Create Lakes\n\nList lakes in one project and location:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"DATAPLEX_LOCATION\", \"us-central1\")\n\nclient = dataplex_v1.DataplexServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor lake in client.list_lakes(parent=parent):\n    print(lake.name, lake.display_name)\n```\n\nCreate a lake:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"DATAPLEX_LOCATION\", \"us-central1\")\n\nclient = dataplex_v1.DataplexServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\noperation = client.create_lake(\n    parent=parent,\n    lake_id=\"analytics-lake\",\n    lake=dataplex_v1.Lake(\n        display_name=\"Analytics Lake\",\n    ),\n)\n\nlake = operation.result(timeout=900)\nprint(lake.name)\n```\n\n`create_lake` is a long-running operation. Wait on `operation.result()` before assuming the lake exists.\n\n### Create And Run A Data Quality Scan\n\nThis example creates a scan against a BigQuery table using the full resource name format documented for `DataSource.resource`:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"DATAPLEX_LOCATION\", \"us-central1\")\ndataset_id = \"analytics\"\ntable_id = \"customers\"\n\nclient = dataplex_v1.DataScanServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nscan = dataplex_v1.DataScan(\n    data=dataplex_v1.DataSource(\n        resource=(\n            f\"//bigquery.googleapis.com/projects/{project_id}\"\n            f\"/datasets/{dataset_id}/tables/{table_id}\"\n        )\n    ),\n    data_quality_spec=dataplex_v1.DataQualitySpec(\n        rules=[\n            dataplex_v1.DataQualityRule(\n                name=\"customer-id-not-null\",\n                dimension=\"COMPLETENESS\",\n                column=\"customer_id\",\n                non_null_expectation=dataplex_v1.DataQualityRule.NonNullExpectation(),\n            ),\n            dataplex_v1.DataQualityRule(\n                name=\"email-format\",\n                dimension=\"VALIDITY\",\n                column=\"email\",\n                ignore_null=True,\n                regex_expectation=dataplex_v1.DataQualityRule.RegexExpectation(\n                    regex=r\"^[^@]+@[^@]+\\.[^@]+$\"\n                ),\n            ),\n        ],\n        sampling_percent=100.0,\n        catalog_publishing_enabled=True,\n    ),\n)\n\noperation = client.create_data_scan(\n    parent=parent,\n    data_scan_id=\"customers-dq\",\n    data_scan=scan,\n)\n\ncreated_scan = operation.result(timeout=900)\nprint(created_scan.name)\n```\n\nIf you do not configure an execution trigger, Dataplex defaults the scan to on-demand execution. Start it explicitly with `run_data_scan`:\n\n```python\nrun_response = client.run_data_scan(name=created_scan.name)\nprint(run_response.job.name)\n```\n\nFetch the job with the full view to inspect the latest result:\n\n```python\njob = client.get_data_scan_job(\n    request=dataplex_v1.GetDataScanJobRequest(\n        name=run_response.job.name,\n        view=dataplex_v1.GetDataScanJobRequest.DataScanJobView.FULL,\n    )\n)\n\nprint(job.state)\nprint(job.data_quality_result.passed)\nprint(job.data_quality_result.score)\n```\n\n### Search The Catalog Or Read One Entry\n\nSearch entries visible from a project:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = dataplex_v1.CatalogServiceClient()\n\nrequest = dataplex_v1.SearchEntriesRequest(\n    page_size=100,\n    name=f\"projects/{project_id}/locations/global\",\n    scope=f\"projects/{project_id}\",\n    query='name:\"customers\"',\n)\n\nfor result in client.search_entries(request=request):\n    print(result.dataplex_entry.name)\n```\n\nRead one known entry and request the `FULL` view:\n\n```python\nimport os\n\nfrom google.cloud import dataplex_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"DATAPLEX_LOCATION\", \"us-central1\")\nentry_group_id = \"example-group\"\nentry_id = \"example-entry\"\n\nclient = dataplex_v1.CatalogServiceClient()\n\nentry = client.get_entry(\n    request=dataplex_v1.GetEntryRequest(\n        name=(\n            f\"projects/{project_id}/locations/{location}\"\n            f\"/entryGroups/{entry_group_id}/entries/{entry_id}\"\n        ),\n        view=dataplex_v1.EntryView.FULL,\n    )\n)\n\nprint(entry.name)\n```\n\nUse `get_entry` when you want Dataplex-side access checks. Use `lookup_entry` when you need source-system permission checks instead.\n\n## Common Pitfalls\n\n- Do not use API keys. Dataplex Python clients expect Google credentials.\n- `create_lake` and `create_data_scan` are long-running operations. Wait on `.result()` before using the created resource.\n- `DataScan.ExecutionSpec` defaults to on-demand execution. If you do not configure a trigger, call `run_data_scan()` yourself.\n- `DataQualitySpec.rules` is required and must contain at least one rule.\n- `DataSource` is a one-of. Set either `entity` or `resource`, not both.\n- `SearchEntriesRequest.name` uses `projects/{project}/locations/global`, while many other Dataplex resources are regional.\n- `get_entry` and `lookup_entry` are not interchangeable. The official samples and reference docs distinguish Dataplex permission checks from source-system permission checks.\n- If you use a client as a context manager, leaving the `with` block closes its underlying transport.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-dataplex 2.16.0` as the current package version for this guide.\n- The hosted `latest` reference pages are version-skewed on some Dataplex subpages and may still show `2.15.0` or older headings. Use PyPI for package version pinning, and use the reference docs for method names, request types, and resource formats.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-dataplex/\n- Python client overview: https://cloud.google.com/python/docs/reference/dataplex/latest\n- Dataplex Python reference root: https://docs.cloud.google.com/python/docs/reference/dataplex/latest\n- `DataplexServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.services.dataplex_service.DataplexServiceClient\n- `DataScanServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.services.data_scan_service.DataScanServiceClient\n- `CatalogServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.services.catalog_service.CatalogServiceClient\n- `DataSource` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.types.DataSource\n- `DataQualityRule` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.types.DataQualityRule\n- `DataQualitySpec` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.types.DataQualitySpec\n- `DataScan.ExecutionSpec` reference: https://docs.cloud.google.com/python/docs/reference/dataplex/latest/google.cloud.dataplex_v1.types.DataScan.ExecutionSpec\n- Catalog search sample: https://docs.cloud.google.com/dataplex/docs/samples/dataplex-search-entries\n- Catalog get-entry sample: https://docs.cloud.google.com/dataplex/docs/samples/dataplex-get-entry\n- Data profiling and data scan samples: https://docs.cloud.google.com/dataplex/docs/use-data-profiling\n- Create-lake guide: https://docs.cloud.google.com/dataplex/docs/create-lake\n"
  },
  {
    "path": "content/google/docs/dataproc/javascript/DOC.md",
    "content": "---\nname: dataproc\ndescription: \"Google Cloud Dataproc Node.js client for regional cluster management and job submission\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,dataproc,spark,hadoop,javascript,nodejs\"\n---\n\n# `@google-cloud/dataproc` JavaScript Package Guide\n\nUse `@google-cloud/dataproc` when your Node.js code needs to create or inspect Dataproc clusters and submit jobs to an existing cluster.\n\n## Golden Rule\n\n- Use the official `@google-cloud/dataproc` package.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Treat Dataproc as a regional API. Set `apiEndpoint` to the same region you pass in requests, for example `us-central1-dataproc.googleapis.com`.\n- Put your Spark or PySpark entrypoint in Cloud Storage before submission. The client library does not upload local files for you.\n- Wait for `operation.promise()` on mutating methods before assuming the resource is ready.\n\nThis guide covers `6.3.0`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/dataproc@6.3.0\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials.\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\ngcloud services enable dataproc.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATAPROC_REGION=\"us-central1\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATAPROC_REGION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project already exists.\n2. The Dataproc API is enabled in that project.\n3. The calling identity can manage Dataproc resources and read any `gs://` paths referenced by jobs.\n\n## Initialize The Clients\n\nThe package exposes multiple service clients under `v1`. The most common ones for cluster-backed workflows are `ClusterControllerClient` and `JobControllerClient`.\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nfunction getDataprocEndpoint(region) {\n  return `${region}-dataproc.googleapis.com`;\n}\n\nfunction createDataprocClients(region) {\n  const clientOptions = {\n    apiEndpoint: getDataprocEndpoint(region),\n  };\n\n  return {\n    clusterClient: new v1.ClusterControllerClient(clientOptions),\n    jobClient: new v1.JobControllerClient(clientOptions),\n  };\n}\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/dataproc';\n\nconst clusterClient = new v1.ClusterControllerClient({\n  apiEndpoint: 'us-central1-dataproc.googleapis.com',\n});\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nconst client = new v1.JobControllerClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n  apiEndpoint: 'us-central1-dataproc.googleapis.com',\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Request Shape Notes\n\n- Cluster and job methods commonly take `projectId` and `region` as top-level request fields.\n- Cluster names such as `analytics-dev` are short IDs, not full resource names.\n- Job payloads usually point at code or dependencies stored in Cloud Storage, for example `gs://your-bucket/jobs/main.py`.\n- For resource names that are fully qualified, Dataproc uses the `projects/{project}/regions/{region}/...` pattern.\n\n## Core Workflows\n\n### List Existing Clusters\n\nUse the regional endpoint that matches the `region` request field.\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nasync function listClusters(projectId, region) {\n  const client = new v1.ClusterControllerClient({\n    apiEndpoint: `${region}-dataproc.googleapis.com`,\n  });\n\n  for await (const cluster of client.listClustersAsync({projectId, region})) {\n    console.log(cluster.clusterName, cluster.status?.state);\n  }\n}\n```\n\n### Create A Cluster\n\nCluster creation is a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nasync function createCluster(projectId, region) {\n  const client = new v1.ClusterControllerClient({\n    apiEndpoint: `${region}-dataproc.googleapis.com`,\n  });\n\n  const cluster = {\n    clusterName: 'analytics-dev',\n    config: {\n      gceClusterConfig: {\n        zoneUri: 'us-central1-a',\n      },\n      masterConfig: {\n        numInstances: 1,\n        machineTypeUri: 'e2-standard-4',\n      },\n      workerConfig: {\n        numInstances: 2,\n        machineTypeUri: 'e2-standard-4',\n      },\n    },\n  };\n\n  const [operation] = await client.createCluster({\n    projectId,\n    region,\n    cluster,\n  });\n\n  const [createdCluster] = await operation.promise();\n  console.log(createdCluster.clusterUuid);\n  return createdCluster;\n}\n```\n\n### Submit A PySpark Job To An Existing Cluster\n\nUse `JobControllerClient` after the target cluster is ready.\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nasync function submitPySparkJob(projectId, region, clusterName) {\n  const client = new v1.JobControllerClient({\n    apiEndpoint: `${region}-dataproc.googleapis.com`,\n  });\n\n  const job = {\n    placement: {\n      clusterName,\n    },\n    pysparkJob: {\n      mainPythonFileUri: 'gs://your-bucket/jobs/main.py',\n      args: ['--date', '2026-03-13'],\n    },\n  };\n\n  const [operation] = await client.submitJobAsOperation({\n    projectId,\n    region,\n    job,\n  });\n\n  const [submittedJob] = await operation.promise();\n  console.log(submittedJob.reference?.jobId);\n  console.log(submittedJob.driverOutputResourceUri);\n  return submittedJob;\n}\n```\n\nUse `submitJob()` instead when you want the `Job` resource back immediately and plan to poll status yourself.\n\n### Read Job Status\n\nFetch the job again with its `jobId` if you need to inspect state after submission.\n\n```javascript\nconst {v1} = require('@google-cloud/dataproc');\n\nasync function getJob(projectId, region, jobId) {\n  const client = new v1.JobControllerClient({\n    apiEndpoint: `${region}-dataproc.googleapis.com`,\n  });\n\n  const [job] = await client.getJob({\n    projectId,\n    region,\n    jobId,\n  });\n\n  console.log(job.status?.state);\n  return job;\n}\n```\n\n## Common Pitfalls\n\n- Install and import are not the same shape. Install `@google-cloud/dataproc`, then import `{v1}` from the package.\n- Do not mix regions. Keep `apiEndpoint`, `region`, cluster placement, and any zonal settings aligned.\n- Do not pass local file paths such as `./main.py` in job definitions. Upload code to Cloud Storage first and use `gs://...` URIs.\n- Create, update, and delete cluster calls are long-running operations. Wait for `operation.promise()` before using the resource.\n- Job submission requires an existing cluster. Create the cluster and wait for completion before submitting work to it.\n- Some configuration fields depend on the Dataproc image version, machine family, and region. If a field is accepted by the client but rejected by the API, re-check the Dataproc product docs for that runtime and region.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/dataproc/latest`\n- Dataproc product documentation: `https://cloud.google.com/dataproc/docs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/dataproc`\n"
  },
  {
    "path": "content/google/docs/dataproc/python/DOC.md",
    "content": "---\nname: dataproc\ndescription: \"Google Cloud Dataproc Python client for cluster management, job submission, and serverless batch workloads\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.25.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,dataproc,gcp,python,spark,hadoop,serverless\"\n---\n\n# Google Cloud Dataproc Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-dataproc` client library and treat Dataproc as a regional API surface. Install `google-cloud-dataproc`, authenticate with Application Default Credentials (ADC), and create clients with a regional endpoint such as `us-central1-dataproc.googleapis.com:443`.\n\nAs of March 12, 2026, PyPI lists `google-cloud-dataproc 5.25.0`. The `latest` reference site is still version-skewed across individual pages, so use PyPI for package-version truth and the reference docs for API shape.\n\n## Install\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-dataproc==5.25.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dataproc==5.25.0\"\npoetry add \"google-cloud-dataproc==5.25.0\"\n```\n\nDataproc jobs usually reference code and data in Google Cloud Storage, so many projects also install `google-cloud-storage` separately when they need to upload artifacts before submission.\n\n## Authentication And Setup\n\nDataproc uses Google Cloud credentials, not API keys.\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\ngcloud services enable dataproc.googleapis.com\n```\n\nService account setup for CI or servers:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\nexport GOOGLE_CLOUD_PROJECT=your-project-id\nexport DATAPROC_REGION=us-central1\n```\n\nPrefer workload identity or an attached service account in production instead of long-lived JSON keys.\n\n## Initialize Clients\n\nThe package exposes multiple service clients. For most coding tasks, the important ones are:\n\n- `ClusterControllerClient` for cluster lifecycle\n- `JobControllerClient` for jobs that run on an existing cluster\n- `BatchControllerClient` for Dataproc Serverless batches\n\nCreate them with a regional endpoint:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataproc_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nREGION = os.getenv(\"DATAPROC_REGION\", \"us-central1\")\n\ndef regional_client_options(region: str) -> ClientOptions:\n    return ClientOptions(api_endpoint=f\"{region}-dataproc.googleapis.com:443\")\n\ncluster_client = dataproc_v1.ClusterControllerClient(\n    client_options=regional_client_options(REGION)\n)\njob_client = dataproc_v1.JobControllerClient(\n    client_options=regional_client_options(REGION)\n)\nbatch_client = dataproc_v1.BatchControllerClient(\n    client_options=regional_client_options(REGION)\n)\n```\n\nIf you need explicit credentials:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataproc_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = dataproc_v1.JobControllerClient(\n    credentials=credentials,\n    client_options=ClientOptions(\n        api_endpoint=\"us-central1-dataproc.googleapis.com:443\"\n    ),\n)\n```\n\n## Core Usage Patterns\n\n### 1. Create Or List Clusters\n\nUse `ClusterControllerClient` when you manage classic Dataproc clusters yourself.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataproc_v1\n\nregion = \"us-central1\"\nproject_id = \"your-project-id\"\n\ncluster_client = dataproc_v1.ClusterControllerClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{region}-dataproc.googleapis.com:443\"\n    )\n)\n\ncluster = {\n    \"cluster_name\": \"analytics-dev\",\n    \"config\": {\n        \"gce_cluster_config\": {\n            \"zone_uri\": \"us-central1-a\",\n        },\n        \"master_config\": {\n            \"num_instances\": 1,\n            \"machine_type_uri\": \"e2-standard-4\",\n        },\n        \"worker_config\": {\n            \"num_instances\": 2,\n            \"machine_type_uri\": \"e2-standard-4\",\n        },\n    },\n}\n\noperation = cluster_client.create_cluster(\n    request={\n        \"project_id\": project_id,\n        \"region\": region,\n        \"cluster\": cluster,\n    }\n)\n\ncreated_cluster = operation.result(timeout=1800)\nprint(created_cluster.cluster_uuid)\n\nfor item in cluster_client.list_clusters(\n    request={\"project_id\": project_id, \"region\": region}\n):\n    print(item.cluster_name, item.status.state)\n```\n\nUse `.result()` on long-running operations. `create_cluster`, `update_cluster`, and `delete_cluster` do not complete immediately.\n\n### 2. Submit A Job To An Existing Cluster\n\nUse `JobControllerClient` when you already have a cluster and want to run a Spark, PySpark, Hive, or Hadoop job on it.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataproc_v1\n\nregion = \"us-central1\"\nproject_id = \"your-project-id\"\ncluster_name = \"analytics-dev\"\n\njob_client = dataproc_v1.JobControllerClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{region}-dataproc.googleapis.com:443\"\n    )\n)\n\njob = {\n    \"placement\": {\n        \"cluster_name\": cluster_name,\n    },\n    \"pyspark_job\": {\n        \"main_python_file_uri\": \"gs://your-bucket/jobs/main.py\",\n        \"args\": [\"--date\", \"2026-03-12\"],\n    },\n}\n\noperation = job_client.submit_job_as_operation(\n    request={\n        \"project_id\": project_id,\n        \"region\": region,\n        \"job\": job,\n    }\n)\n\nsubmitted_job = operation.result(timeout=1800)\nprint(submitted_job.reference.job_id)\nprint(submitted_job.driver_output_resource_uri)\n```\n\nUse `submit_job()` if you want the `Job` resource back immediately and will poll status yourself. Use `submit_job_as_operation()` when you want the operation flow.\n\n### 3. Run A Dataproc Serverless Batch\n\nUse `BatchControllerClient` for Dataproc Serverless. This is a separate API surface from jobs on a long-lived cluster.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dataproc_v1\n\nregion = \"us-central1\"\nproject_id = \"your-project-id\"\n\nbatch_client = dataproc_v1.BatchControllerClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{region}-dataproc.googleapis.com:443\"\n    )\n)\n\nbatch = {\n    \"pyspark_batch\": {\n        \"main_python_file_uri\": \"gs://your-bucket/jobs/etl.py\",\n        \"args\": [\"--env\", \"dev\"],\n    },\n    \"runtime_config\": {\n        \"version\": \"2.2\",\n        \"properties\": {\n            \"spark.executor.instances\": \"2\",\n        },\n    },\n    \"environment_config\": {\n        \"execution_config\": {\n            \"service_account\": \"dataproc-runner@your-project-id.iam.gserviceaccount.com\",\n            \"subnetwork_uri\": (\n                \"projects/your-project-id/regions/us-central1/subnetworks/default\"\n            ),\n        },\n    },\n}\n\noperation = batch_client.create_batch(\n    request={\n        \"parent\": f\"projects/{project_id}/regions/{region}\",\n        \"batch\": batch,\n        \"batch_id\": \"daily-etl-20260312\",\n        \"request_id\": \"c1d9b0b1-2b4e-4a47-a03d-9b6d5d118df8\",\n    }\n)\n\ncreated_batch = operation.result(timeout=1800)\nprint(created_batch.name)\nprint(created_batch.state)\n```\n\nThe `request_id` field is worth setting when retries are possible. It helps make create requests safer to replay after transport failures.\n\n### 4. Poll Or Enumerate Existing Batches\n\n```python\nparent = f\"projects/{project_id}/regions/{region}\"\n\nfor batch in batch_client.list_batches(request={\"parent\": parent}):\n    print(batch.name, batch.state)\n```\n\n## Configuration Notes\n\n- Dataproc is region-scoped. Keep `region`, `parent`, and the endpoint aligned.\n- GCS URIs such as `gs://bucket/path/file.py` are common in request payloads. Local file paths are not uploaded automatically.\n- Many request parameters can be passed as typed protobuf objects or plain Python dictionaries. Dictionaries are usually faster for agents to assemble correctly.\n- Client methods accept retry and timeout options through `google-api-core` if you need stricter operational behavior.\n\n## Common Pitfalls\n\n- Install name and import name differ. Use `pip install google-cloud-dataproc`, then `from google.cloud import dataproc_v1`.\n- Do not use the global endpoint by accident. The reference docs explicitly call out regional endpoints for Dataproc clients.\n- Do not mix cluster jobs and serverless batches. `JobControllerClient` targets an existing cluster; `BatchControllerClient` targets Dataproc Serverless.\n- Long-running operations are common. Call `.result()` or store the operation name and poll deliberately.\n- The package does not upload your local code. Put scripts, jars, and dependency archives in GCS first.\n- `latest` reference pages are not perfectly version-synchronized. Cross-check version-sensitive behavior against PyPI and the Dataproc changelog before copying snippets blindly.\n- Some batch and cluster features are region- or image-version-sensitive. If a field looks valid in the reference docs but the API rejects it, confirm the Dataproc image/runtime version and region support.\n\n## Version-Sensitive Notes For 5.25.0\n\n- PyPI shows `5.25.0` as the current package version, released on February 19, 2026.\n- The official changelog for the `latest` docs includes 5.25.0 changes, including `ClusterType` support for zero-scale clusters.\n- Individual API reference pages under the `latest` docs root still show older page-version labels on some services. Treat the package version and the page heading as separate signals.\n\n## Official Sources\n\n- Dataproc Python reference: `https://cloud.google.com/python/docs/reference/dataproc/latest`\n- Dataproc changelog: `https://cloud.google.com/python/docs/reference/dataproc/latest/changelog`\n- `ClusterControllerClient` reference: `https://cloud.google.com/python/docs/reference/dataproc/latest/google.cloud.dataproc_v1.services.cluster_controller.ClusterControllerClient`\n- `JobControllerClient` reference: `https://cloud.google.com/python/docs/reference/dataproc/latest/google.cloud.dataproc_v1.services.job_controller.JobControllerClient`\n- `BatchControllerClient` reference: `https://cloud.google.com/python/docs/reference/dataproc/latest/google.cloud.dataproc_v1.services.batch_controller.BatchControllerClient`\n- Google Cloud ADC guide: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- PyPI project page: `https://pypi.org/project/google-cloud-dataproc/`\n"
  },
  {
    "path": "content/google/docs/dataproc-metastore/python/DOC.md",
    "content": "---\nname: dataproc-metastore\ndescription: \"Google Cloud Dataproc Metastore Python client for managing metastore services, imports, backups, restores, and metadata queries\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.21.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,dataproc,metastore,hive,python\"\n---\n\n# google-cloud-dataproc-metastore Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-dataproc-metastore` client with Google Cloud credentials.\n\nThis package is the control-plane SDK for Dataproc Metastore. Use it to create and manage metastore services, run metadata imports, query metadata, and manage backups. It is not a Hive or SQL client for talking directly to your metastore endpoint.\n\nThe import surface is:\n\n```python\nfrom google.cloud import metastore_v1\n```\n\n## Install\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-dataproc-metastore==1.21.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dataproc-metastore==1.21.0\"\npoetry add \"google-cloud-dataproc-metastore==1.21.0\"\n```\n\nPyPI currently lists `1.21.0` and publishes this package for Python `>=3.7`.\n\n## Authentication And Setup\n\nThe client library uses Application Default Credentials (ADC), not API keys.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\ngcloud services enable metastore.googleapis.com\n```\n\nService account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport METASTORE_REGION=\"us-central1\"\n```\n\nPrefer workload identity or an attached service account in deployed environments instead of long-lived JSON keys.\n\n## Initialize A Client\n\nThe default endpoint is `metastore.googleapis.com`, so a plain client is usually enough:\n\n```python\nimport os\n\nfrom google.cloud import metastore_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nREGION = os.getenv(\"METASTORE_REGION\", \"us-central1\")\n\nclient = metastore_v1.DataprocMetastoreClient()\nlocation_name = f\"projects/{PROJECT_ID}/locations/{REGION}\"\n```\n\nIf you need explicit credentials:\n\n```python\nfrom google.cloud import metastore_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = metastore_v1.DataprocMetastoreClient(credentials=credentials)\n```\n\nMost methods use full resource names:\n\n```python\nservice_name = (\n    f\"projects/{PROJECT_ID}/locations/{REGION}/services/my-metastore\"\n)\n```\n\n## Core Workflows\n\n### List Existing Metastore Services\n\n`list_services()` returns a pager. Iterate over it directly:\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\nparent = \"projects/your-project/locations/us-central1\"\n\nfor service in client.list_services(request={\"parent\": parent}):\n    print(service.name, service.state, service.endpoint_uri)\n```\n\n### Create A Metastore Service\n\nCreate calls return a long-running operation. Wait for `.result()` before using the service.\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\nparent = \"projects/your-project/locations/us-central1\"\n\nservice = metastore_v1.Service(\n    network=\"projects/your-project/global/networks/default\",\n    port=9083,\n    tier=metastore_v1.Service.Tier.DEVELOPER,\n    hive_metastore_config=metastore_v1.Service.HiveMetastoreConfig(\n        version=metastore_v1.Service.HiveMetastoreConfig.Version.V3_1_2\n    ),\n)\n\noperation = client.create_service(\n    request=metastore_v1.CreateServiceRequest(\n        parent=parent,\n        service_id=\"dev-metastore\",\n        service=service,\n    )\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\nprint(created.endpoint_uri)\n```\n\nThe `network` field expects a full VPC resource name such as `projects/{project}/global/networks/{network}`. The service documentation also notes that all subnet IP ranges in that network must be RFC 1918 ranges.\n\n### Import Metadata From A Database Dump In Cloud Storage\n\nUse a metadata import when you already have a supported database dump in Cloud Storage and want to load it into a Dataproc Metastore service.\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\nservice_name = (\n    \"projects/your-project/locations/us-central1/services/dev-metastore\"\n)\n\nmetadata_import = metastore_v1.MetadataImport(\n    database_dump=metastore_v1.MetadataImport.DatabaseDump(\n        database_type=metastore_v1.MetadataImport.DatabaseDump.DatabaseType.MYSQL,\n        gcs_uri=\"gs://your-bucket/metastore/hive.sql\",\n    )\n)\n\noperation = client.create_metadata_import(\n    request=metastore_v1.CreateMetadataImportRequest(\n        parent=service_name,\n        metadata_import_id=\"bootstrap-import\",\n        metadata_import=metadata_import,\n    )\n)\n\nresult = operation.result(timeout=1800)\nprint(result.name)\nprint(result.state)\n```\n\nThe database dump source is a Cloud Storage URI. The generated types expose MySQL and PostgreSQL dump types.\n\n### Query Metastore Metadata\n\n`query_metadata()` lets you send a metadata query against a running metastore service:\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\n\nresponse = client.query_metadata(\n    request=metastore_v1.QueryMetadataRequest(\n        service=(\n            \"projects/your-project/locations/us-central1/services/dev-metastore\"\n        ),\n        query=\"SHOW DATABASES\",\n    )\n)\n\nprint(response.result_manifest)\nprint(response.result_uri)\n```\n\nThe response includes a `result_manifest` and a `result_uri` for the query output.\n\n### Create A Backup And Restore From It\n\nBackup creation is also a long-running operation:\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\nservice_name = (\n    \"projects/your-project/locations/us-central1/services/dev-metastore\"\n)\n\noperation = client.create_backup(\n    request=metastore_v1.CreateBackupRequest(\n        parent=service_name,\n        backup_id=\"nightly-backup-20260313\",\n        backup=metastore_v1.Backup(),\n    )\n)\n\nbackup = operation.result(timeout=1800)\nprint(backup.name)\nprint(backup.state)\n```\n\nRestore a service from a backup by passing the backup resource name:\n\n```python\nfrom google.cloud import metastore_v1\n\nclient = metastore_v1.DataprocMetastoreClient()\n\noperation = client.restore_service(\n    request=metastore_v1.RestoreServiceRequest(\n        service=(\n            \"projects/your-project/locations/us-central1/services/dev-metastore\"\n        ),\n        backup=(\n            \"projects/your-project/locations/us-central1/\"\n            \"services/dev-metastore/backups/nightly-backup-20260313\"\n        ),\n    )\n)\n\nrestored = operation.result(timeout=1800)\nprint(restored.name)\nprint(restored.state)\n```\n\nThe generated `Backup` type notes that backups are supported only for Dataproc Metastore services running supported Hive Metastore versions.\n\n## Configuration Notes\n\n- Use full resource names in requests instead of short IDs.\n- Create, import, backup, restore, update, and delete operations are long-running operations.\n- If your code is async, use `metastore_v1.DataprocMetastoreAsyncClient`.\n- `QueryMetadataRequest.query` is the metadata query string; treat it as service input, not a safe place to interpolate untrusted text.\n\n## Common Pitfalls\n\n- Do not try to authenticate with API keys. This package expects Google Cloud credentials.\n- Do not confuse the admin SDK with direct Hive access. The library manages services and admin operations.\n- Do not pass a bare network name like `default`; `Service.network` expects the full VPC resource path.\n- Do not assume service creation is instant. Wait on the returned operation before using the service endpoint.\n- Do not point metadata imports at local files. `MetadataImport.DatabaseDump.gcs_uri` must reference Cloud Storage.\n- Do not assume every Hive Metastore version supports backup. Check the service version when you depend on backup workflows.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-dataproc-metastore/\n- Python client reference root: https://cloud.google.com/python/docs/reference/metastore/latest\n- `DataprocMetastoreClient` reference: https://cloud.google.com/python/docs/reference/metastore/latest/google.cloud.metastore_v1.services.dataproc_metastore_service.DataprocMetastoreClient\n- Package source tree: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc-metastore\n- Generated types source: https://raw.githubusercontent.com/googleapis/google-cloud-python/main/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/types/metastore.py\n- Google Cloud client-library authentication guide: https://cloud.google.com/docs/authentication/client-libraries\n"
  },
  {
    "path": "content/google/docs/datastore/javascript/DOC.md",
    "content": "---\nname: datastore\ndescription: \"Google Cloud Datastore Node.js client for entities, keys, queries, transactions, and emulator-based local development\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,datastore,firestore-datastore-mode,nosql,query,transaction\"\n---\n\n# Google Cloud Datastore Node.js Client\n\n## Golden Rule\n\nUse the official `@google-cloud/datastore` package and import it as:\n\n```javascript\nconst {Datastore, PropertyFilter} = require('@google-cloud/datastore');\n```\n\nor:\n\n```javascript\nimport {Datastore, PropertyFilter} from '@google-cloud/datastore';\n```\n\nAuthenticate with Application Default Credentials (ADC), not API keys. This guide targets `@google-cloud/datastore` `10.1.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/datastore@10.1.0\n```\n\nIf this is a fresh Google Cloud project, make sure Datastore mode is enabled for the project before debugging client code.\n\n## Authentication And Project Setup\n\nFor local development, sign in with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\n```\n\nFor service-account-based environments, point `GOOGLE_APPLICATION_CREDENTIALS` at the JSON key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\n## Initialize A Client\n\nBasic client:\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nWith an explicit key file:\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore({\n  projectId: 'your-gcp-project',\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf `projectId` is omitted, the client usually discovers it from ADC or the environment.\n\n## Create And Save Entities\n\nUse `datastore.key()` to build a key, then call `save()` with `{key, data}`:\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore();\n\nasync function createTask() {\n  const taskKey = datastore.key(['Task', 'sample-task']);\n\n  const entity = {\n    key: taskKey,\n    data: {\n      title: 'Ship docs',\n      done: false,\n      createdAt: new Date(),\n      description: 'Write the public package guide',\n    },\n    excludeFromIndexes: ['description'],\n  };\n\n  await datastore.save(entity);\n}\n\ncreateTask().catch(console.error);\n```\n\n`save()` is the simplest create-or-update path. If you need stricter semantics, use `insert()` when the entity must not already exist or `update()` when it must already exist.\n\n## Fetch, Update, And Delete Entities\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore();\n\nasync function updateTask() {\n  const taskKey = datastore.key(['Task', 'sample-task']);\n  const [task] = await datastore.get(taskKey);\n\n  if (!task) {\n    return;\n  }\n\n  task.done = true;\n  await datastore.save(task);\n}\n\nasync function deleteTask() {\n  const taskKey = datastore.key(['Task', 'sample-task']);\n  await datastore.delete(taskKey);\n}\n```\n\nFor bulk reads and writes, pass arrays to `get()`, `save()`, or `delete()` instead of looping one network call at a time.\n\n## Query Entities\n\nUse `createQuery()` and `PropertyFilter` for property predicates:\n\n```javascript\nconst {Datastore, PropertyFilter} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore();\n\nasync function listOpenTasks() {\n  const query = datastore\n    .createQuery('Task')\n    .filter(new PropertyFilter('done', '=', false))\n    .order('createdAt')\n    .limit(20);\n\n  const [tasks] = await datastore.runQuery(query);\n\n  for (const task of tasks) {\n    console.log(task.title, task.done);\n  }\n}\n```\n\nIf you need strong consistency for a query, use an ancestor query with `hasAncestor(parentKey)` instead of a global query.\n\n## Bulk Operations\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore();\n\nasync function saveManyTasks() {\n  const entities = [\n    {\n      key: datastore.key(['Task', 'task-1']),\n      data: {title: 'One', done: false},\n    },\n    {\n      key: datastore.key(['Task', 'task-2']),\n      data: {title: 'Two', done: false},\n    },\n  ];\n\n  await datastore.save(entities);\n\n  const [tasks] = await datastore.get(entities.map(entity => entity.key));\n  console.log(tasks.length);\n}\n```\n\nThis is simpler than a transaction when you do not need read-modify-write logic between operations.\n\n## Transactions\n\nUse a transaction for read-modify-write workflows that must commit atomically:\n\n```javascript\nconst {Datastore} = require('@google-cloud/datastore');\n\nconst datastore = new Datastore();\n\nasync function completeTask(taskId) {\n  const transaction = datastore.transaction();\n  const taskKey = datastore.key(['Task', taskId]);\n\n  await transaction.run();\n\n  try {\n    const [task] = await transaction.get(taskKey);\n\n    if (!task) {\n      throw new Error('Task not found');\n    }\n\n    task.done = true;\n    transaction.save(task);\n\n    await transaction.commit();\n  } catch (err) {\n    await transaction.rollback();\n    throw err;\n  }\n}\n```\n\n## Local Emulator\n\nStart the Datastore emulator with `gcloud`, then export the environment variables it prints:\n\n```bash\ngcloud beta emulators datastore start --project=demo-project\neval \"$(gcloud beta emulators datastore env-init)\"\n```\n\nThe important environment variables are `DATASTORE_EMULATOR_HOST` and `DATASTORE_PROJECT_ID`. Once they are set, `new Datastore()` talks to the emulator instead of production.\n\n## Common Pitfalls\n\n- Do not use API keys. Use ADC, user credentials, or a service account.\n- `save()` upserts. Use `insert()` or `update()` when you need create-only or update-only behavior.\n- Large strings and blobs should usually be excluded from indexes with `excludeFromIndexes`, or writes can fail and indexing cost increases.\n- If a query returns a missing-index error, create the composite index in `index.yaml` and deploy it with `gcloud datastore indexes create index.yaml`.\n- Ancestor queries are strongly consistent; global non-ancestor queries are not.\n- If you rebuild a fetched entity into a plain object, keep its key when you call `save()` again.\n- If emulator variables are still exported in your shell, the client keeps talking to the local emulator until you unset them.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/datastore` `10.1.0`.\n- Prefer the current `PropertyFilter` query pattern from the maintained Node.js reference instead of older examples that rely on overloaded string filter signatures.\n\n## Official URLs\n\n- Docs root: `https://cloud.google.com/nodejs/docs/reference/datastore/latest`\n- Auth setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Datastore emulator: `https://cloud.google.com/datastore/docs/tools/datastore-emulator`\n- Datastore indexes: `https://cloud.google.com/datastore/docs/tools/indexconfig`\n- npm package: `https://www.npmjs.com/package/@google-cloud/datastore`\n"
  },
  {
    "path": "content/google/docs/datastore/python/DOC.md",
    "content": "---\nname: datastore\ndescription: \"Google Cloud Datastore Python client library for entities, keys, queries, batches, and transactions\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.23.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,datastore,firestore-datastore-mode,nosql,query,transaction\"\n---\n\n# Google Cloud Datastore Python Client Library\n\n## Golden Rule\n\nUse the official `google-cloud-datastore` package and import it as:\n\n```python\nfrom google.cloud import datastore\n```\n\nAuthenticate with Application Default Credentials (ADC), not API keys. As of 2026-03-12, PyPI lists `google-cloud-datastore 2.23.0`, but Google Cloud reference subpages under the `latest` docs path still render page versions such as `2.21.0` and `2.22.0`. The examples below stay on the current maintained client surface that is documented in those official references and published on PyPI.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-datastore==2.23.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-datastore==2.23.0\"\npoetry add \"google-cloud-datastore==2.23.0\"\n```\n\nIf this is a fresh Google Cloud project, enable billing and the Datastore API before debugging client code.\n\n## Authentication And Project Setup\n\nFor local development, use ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nFor service-account-based environments, point `GOOGLE_APPLICATION_CREDENTIALS` at the JSON key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nThe client can usually infer the current project from ADC or environment, but pass `project=` explicitly when your runtime cannot resolve it reliably.\n\nUseful environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nOptional library logging can be enabled with:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\n## Initialize A Client\n\nBasic client:\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(project=\"your-gcp-project\")\n```\n\nWith namespace and non-default database:\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(\n    project=\"your-gcp-project\",\n    namespace=\"tenant-a\",\n    database=\"customer-db\",\n)\n```\n\nWith explicit credentials:\n\n```python\nfrom google.cloud import datastore\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = datastore.Client(\n    project=\"your-gcp-project\",\n    credentials=credentials,\n)\n```\n\n## Core Usage\n\n### Create keys and entities\n\nUse an incomplete key to let Datastore allocate an ID when you call `put()`. Use `exclude_from_indexes` for long text or fields you do not query on.\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(project=\"your-gcp-project\")\n\ntask_key = client.key(\"Task\")\ntask = datastore.Entity(\n    key=task_key,\n    exclude_from_indexes=(\"description\",),\n)\ntask.update(\n    {\n        \"title\": \"Ship docs\",\n        \"description\": \"Long text that should not be indexed\",\n        \"done\": False,\n        \"priority\": 3,\n    }\n)\n\nclient.put(task)\n```\n\n### Fetch, update, and delete entities\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(project=\"your-gcp-project\")\ntask_key = client.key(\"Task\", 123456789)\n\ntask = client.get(task_key)\nif task is not None:\n    task[\"done\"] = True\n    client.put(task)\n\nclient.delete(task_key)\n```\n\nFor bulk operations, use `get_multi()`, `put_multi()`, and `delete_multi()` instead of looping one network call at a time.\n\n### Query entities\n\nUse `PropertyFilter` with `Query.add_filter()` for property-based predicates.\n\n```python\nfrom google.cloud import datastore\nfrom google.cloud.datastore.query import PropertyFilter\n\nclient = datastore.Client(project=\"your-gcp-project\")\nancestor = client.key(\"Account\", \"acct-1\")\n\nquery = client.query(\n    kind=\"Task\",\n    ancestor=ancestor,\n    order=[\"priority\"],\n)\nquery.add_filter(filter=PropertyFilter(\"done\", \"=\", False))\n\nfor entity in query.fetch(limit=20):\n    print(entity[\"title\"], entity.get(\"priority\"))\n```\n\nIf you need key-based filtering, use `Query.key_filter()`. For composite predicates, use the query filter helpers documented in `google.cloud.datastore.query`.\n\n### Batch writes\n\nUse a batch when you want to send multiple mutations together without transaction semantics:\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(project=\"your-gcp-project\")\n\ntask_key = client.key(\"Task\", 1)\naudit_key = client.key(\"AuditLog\", 1)\n\ntask = datastore.Entity(key=task_key)\ntask.update({\"done\": True})\n\naudit = datastore.Entity(key=audit_key)\naudit.update({\"message\": \"Task completed\"})\n\nwith client.batch() as batch:\n    batch.put(task)\n    batch.put(audit)\n```\n\n### Transactions\n\nUse a transaction for read-modify-write workflows that must commit atomically:\n\n```python\nfrom google.cloud import datastore\n\nclient = datastore.Client(project=\"your-gcp-project\")\ncounter_key = client.key(\"Counter\", \"default\")\n\nwith client.transaction():\n    counter = client.get(counter_key)\n    if counter is None:\n        counter = datastore.Entity(key=counter_key)\n        counter[\"value\"] = 0\n\n    counter[\"value\"] += 1\n    client.put(counter)\n```\n\nInside a transaction, reads and writes use the active transaction automatically unless you override the `transaction=` argument explicitly.\n\n## Local Emulator\n\nGoogle documents two related emulator paths:\n\n- Firestore emulator in Datastore mode: `gcloud emulators firestore start --database-mode=datastore-mode`\n- Legacy Datastore emulator: `gcloud beta emulators datastore start`\n\nWhen using the Datastore emulator, export the environment variables emitted by `gcloud` before starting your app. The official docs call out these variables:\n\n- `DATASTORE_DATASET`\n- `DATASTORE_EMULATOR_HOST`\n- `DATASTORE_EMULATOR_HOST_PATH`\n- `DATASTORE_HOST`\n- `DATASTORE_PROJECT_ID`\n\nOnce those are set, `datastore.Client()` will talk to the emulator instead of production.\n\n## Common Pitfalls\n\n- Do not use API keys. The client expects ADC, user credentials, or service-account credentials.\n- Do not guess the import path. Use `from google.cloud import datastore`.\n- `exclude_from_indexes` matters. Large or unneeded indexed fields can fail writes or increase index cost.\n- `eventual=True` is only for eventually consistent reads and cannot be combined with a transaction or `read_time`.\n- Ancestor queries are strongly consistent; global non-ancestor queries are not.\n- `client.put()` writes the entity state you give it. Fetch first if you need a safe read-modify-write update.\n- Namespace and database are part of identity. If reads unexpectedly return nothing, verify `project`, `namespace`, and `database` all match the stored entity.\n- Old blog posts often use pre-2.x patterns or older filter APIs. Prefer the `PropertyFilter`-based query examples from the official reference.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `2.23.0`.\n- The Google Cloud Python reference URL is still the correct canonical docs root, but some Datastore reference pages under `latest` currently display page versions like `2.21.0` or `2.22.0`. Treat that as docs-site version drift, not a reason to downgrade the package automatically.\n- If you are migrating old code from `google-cloud-datastore 1.x`, read the official upgrade guide first. The 2.0 migration changed several client and query patterns.\n- If your project uses Firestore in Datastore mode rather than legacy Cloud Datastore, keep emulator and operational docs aligned with that mode when testing locally.\n\n## Official URLs\n\n- Docs root: `https://cloud.google.com/python/docs/reference/datastore/latest`\n- Client reference: `https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.client.Client`\n- Query reference: `https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.query.Query`\n- Filter reference: `https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.query.PropertyFilter`\n- Upgrade guide: `https://cloud.google.com/python/docs/reference/datastore/latest/upgrading`\n- Auth setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Emulator docs: `https://cloud.google.com/datastore/docs/emulator`\n- PyPI: `https://pypi.org/project/google-cloud-datastore/`\n"
  },
  {
    "path": "content/google/docs/datastream/python/DOC.md",
    "content": "---\nname: datastream\ndescription: \"Google Cloud Datastream Python client for regional connection profiles, stream creation, discovery, and stream lifecycle management\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,datastream,gcp,cdc,bigquery,cloud-storage,python\"\n---\n\n# Google Cloud Datastream Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-datastream` package with the generated `google.cloud.datastream_v1` client, and always point the client at the Datastream region you are working in.\n\nDatastream is regional. The client reference explicitly notes that you should use regional endpoints such as `us-central1-datastream.googleapis.com`, and your stream plus its source and destination connection profiles must live in the same location.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-datastream==1.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-datastream==1.17.0\"\npoetry add \"google-cloud-datastream==1.17.0\"\n```\n\n## Prerequisites And Authentication\n\nEnable Datastream in the target Google Cloud project, then authenticate with Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATASTREAM_LOCATION=\"us-central1\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport DATASTREAM_LOCATION=\"us-central1\"\n```\n\nIf you are running on Google Cloud, prefer the attached service account or workload identity instead of shipping key files.\n\n## Initialize A Regional Client\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import datastream_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"DATASTREAM_LOCATION\"]\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = datastream_v1.DatastreamClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-datastream.googleapis.com:443\"\n    )\n)\n```\n\nUse the helper methods when you need full resource names:\n\n```python\nsource_profile_name = client.connection_profile_path(\n    project_id, location, \"mysql-source\"\n)\nstream_name = client.stream_path(project_id, location, \"mysql-to-bq\")\n```\n\n## List Existing Connection Profiles And Streams\n\n```python\nfor profile in client.list_connection_profiles(parent=parent):\n    print(profile.name, profile.display_name)\n\nfor stream in client.list_streams(parent=parent):\n    print(stream.name, stream.state)\n```\n\n## Fetch Static IPs For Public Source Connectivity\n\nIf your source database is reachable over public IP and you plan to use Datastream static service IP connectivity, fetch the region's allowlist addresses first:\n\n```python\nresponse = client.fetch_static_ips(name=parent)\n\nfor ip in response.static_ips:\n    print(ip)\n```\n\n## Create A Source Connection Profile\n\nThis example creates a MySQL source profile with static service IP connectivity:\n\n```python\nimport os\n\nfrom google.cloud import datastream_v1\n\noperation = client.create_connection_profile(\n    parent=parent,\n    connection_profile_id=\"mysql-source\",\n    connection_profile=datastream_v1.ConnectionProfile(\n        display_name=\"mysql-source\",\n        mysql_profile=datastream_v1.MysqlProfile(\n            hostname=os.environ[\"MYSQL_HOST\"],\n            port=3306,\n            username=os.environ[\"MYSQL_USER\"],\n            password=os.environ[\"MYSQL_PASSWORD\"],\n        ),\n        static_service_ip_connectivity=datastream_v1.StaticServiceIpConnectivity(),\n    ),\n)\n\nsource_profile = operation.result()\nprint(source_profile.name)\n```\n\nCreate methods return long-running operations. Wait on `.result()` before using the created resource name in later calls.\n\n## Create A Destination Connection Profile\n\nBigQuery destination profile:\n\n```python\nfrom google.cloud import datastream_v1\n\noperation = client.create_connection_profile(\n    parent=parent,\n    connection_profile_id=\"bq-destination\",\n    connection_profile=datastream_v1.ConnectionProfile(\n        display_name=\"bq-destination\",\n        bigquery_profile=datastream_v1.BigQueryProfile(),\n    ),\n)\n\nbq_profile = operation.result()\nprint(bq_profile.name)\n```\n\nCloud Storage destination profile:\n\n```python\nfrom google.cloud import datastream_v1\n\noperation = client.create_connection_profile(\n    parent=parent,\n    connection_profile_id=\"gcs-destination\",\n    connection_profile=datastream_v1.ConnectionProfile(\n        display_name=\"gcs-destination\",\n        gcs_profile=datastream_v1.GcsProfile(\n            bucket=\"my-datastream-bucket\",\n            root_path=\"/datastream\",\n        ),\n    ),\n)\n\ngcs_profile = operation.result()\nprint(gcs_profile.name)\n```\n\n## Create A Stream To BigQuery\n\n```python\nfrom google.cloud import datastream_v1\nfrom google.protobuf import duration_pb2\n\nstream = datastream_v1.Stream(\n    display_name=\"mysql-to-bq\",\n    source_config=datastream_v1.SourceConfig(\n        source_connection_profile=source_profile.name,\n        mysql_source_config=datastream_v1.MysqlSourceConfig(\n            include_objects=datastream_v1.MysqlRdbms(\n                mysql_databases=[\n                    datastream_v1.MysqlDatabase(\n                        database=\"app\",\n                        mysql_tables=[\n                            datastream_v1.MysqlTable(table=\"customers\"),\n                            datastream_v1.MysqlTable(table=\"orders\"),\n                        ],\n                    )\n                ]\n            )\n        ),\n    ),\n    destination_config=datastream_v1.DestinationConfig(\n        destination_connection_profile=bq_profile.name,\n        bigquery_destination_config=datastream_v1.BigQueryDestinationConfig(\n            single_target_dataset=datastream_v1.BigQueryDestinationConfig.SingleTargetDataset(\n                dataset_id=\"your-project-id:raw_cdc\",\n            ),\n            append_only=datastream_v1.BigQueryDestinationConfig.AppendOnly(),\n            data_freshness=duration_pb2.Duration(seconds=900),\n        ),\n    ),\n    backfill_all=datastream_v1.Stream.BackfillAllStrategy(),\n)\n\noperation = client.create_stream(\n    parent=parent,\n    stream_id=\"mysql-to-bq\",\n    stream=stream,\n)\n\ncreated_stream = operation.result()\nprint(created_stream.name)\n```\n\nUse `append_only` when you want a pure change log in BigQuery. If you omit it, Datastream uses merge semantics where possible, but tables without primary keys still behave as append-only.\n\n## Stream To Cloud Storage Instead\n\nSwap the destination section when you want files in Cloud Storage instead of BigQuery:\n\n```python\nfrom google.cloud import datastream_v1\nfrom google.protobuf import duration_pb2\n\ndestination_config = datastream_v1.DestinationConfig(\n    destination_connection_profile=gcs_profile.name,\n    gcs_destination_config=datastream_v1.GcsDestinationConfig(\n        path=\"/cdc-files\",\n        file_rotation_mb=200,\n        file_rotation_interval=duration_pb2.Duration(seconds=60),\n        avro_file_format=datastream_v1.AvroFileFormat(),\n    ),\n)\n```\n\n`GcsDestinationConfig.path` and `GcsProfile.root_path` are bucket-internal prefixes. Use slash-prefixed paths such as `\"/datastream\"` or `\"/cdc-files\"`.\n\n## Pause Or Resume A Stream\n\nNormal lifecycle changes use `update_stream()` with a field mask:\n\n```python\nfrom google.cloud import datastream_v1\nfrom google.protobuf import field_mask_pb2\n\npause_operation = client.update_stream(\n    stream=datastream_v1.Stream(\n        name=created_stream.name,\n        state=datastream_v1.Stream.State.PAUSED,\n    ),\n    update_mask=field_mask_pb2.FieldMask(paths=[\"state\"]),\n)\npause_operation.result()\n\nresume_operation = client.update_stream(\n    stream=datastream_v1.Stream(\n        name=created_stream.name,\n        state=datastream_v1.Stream.State.RUNNING,\n    ),\n    update_mask=field_mask_pb2.FieldMask(paths=[\"state\"]),\n)\nresume_operation.result()\n```\n\nUse `run_stream()` only when you need non-default recovery or a specific CDC start position. For normal start, pause, and resume operations, update the stream state instead.\n\n## Discover Source Objects Before You Create A Stream\n\nUse discovery when you want the source schema as Datastream sees it before you lock in `include_objects` or `exclude_objects`:\n\n```python\nfrom google.cloud import datastream_v1\n\nresponse = client.discover_connection_profile(\n    request=datastream_v1.DiscoverConnectionProfileRequest(\n        parent=parent,\n        connection_profile_name=source_profile.name,\n    )\n)\n\nprint(response)\n```\n\nThe response shape depends on the source profile type. For relational sources, inspect the returned database and table objects and then build a narrower `MysqlSourceConfig`, `OracleSourceConfig`, or `PostgresqlSourceConfig` for the actual stream.\n\n## Practical Pitfalls\n\n- Keep the client endpoint, stream location, and connection profile location aligned. Datastream resources are regional, not global.\n- Wait for every create, update, or delete operation to finish. Most control-plane methods return long-running operations.\n- For retryable create and update paths, pass a `request_id` if you need server-side deduplication of repeated requests.\n- Use `fetch_static_ips()` before opening source database firewalls for static public connectivity.\n- Prefer ADC and attached service accounts. Only use `GOOGLE_APPLICATION_CREDENTIALS` as a fallback when ADC is not already available.\n"
  },
  {
    "path": "content/google/docs/debug-agent/javascript/DOC.md",
    "content": "---\nname: debug-agent\ndescription: \"Google Cloud Debugger Node.js agent for bootstrapping snapshot and logpoint debugging with a single start() call\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,cloud-debugger,debug-agent,gcp,javascript,nodejs,observability\"\n---\n\n# `@google-cloud/debug-agent` JavaScript Package Guide\n\nUse `@google-cloud/debug-agent` when a Node.js service should register itself with Google Cloud Debugger so you can set snapshot or logpoints from Google Cloud without attaching a local debugger to the process.\n\n## Golden Rule\n\n- Call `require('@google-cloud/debug-agent').start()` at the very top of the process entrypoint.\n- Start the agent before loading Express, Koa, Fastify, or your own application modules.\n- Use Google Cloud credentials through Application Default Credentials (ADC) or `GOOGLE_APPLICATION_CREDENTIALS`.\n- Set `GOOGLE_CLOUD_PROJECT` when the runtime does not already provide the project ID.\n- Enable `allowExpressions: true` only when you need evaluated watch expressions.\n\nThis guide covers `9.0.1`.\n\n## Install\n\nPin the package version you want your app to target:\n\n```bash\nnpm install @google-cloud/debug-agent@9.0.1\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials, not an API key.\n\nEnable the Cloud Debugger API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable clouddebugger.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimum setup:\n\n1. Enable the Cloud Debugger API in the target project.\n2. Grant the runtime identity the Cloud Debugger Agent role: `roles/clouddebugger.agent`.\n3. Make sure the process can resolve the same project you intend to debug.\n\nIf you run on Google Cloud managed compute, the default service account can be used as long as it has the required IAM role.\n\n## Initialize The Agent\n\nThis package is a process-wide bootstrap agent. You initialize it once with `start()` and then load the rest of your app.\n\nCommonJS bootstrap:\n\n```javascript\nrequire('@google-cloud/debug-agent').start();\n\nrequire('./server');\n```\n\nIf you need evaluated watch expressions:\n\n```javascript\nrequire('@google-cloud/debug-agent').start({\n  allowExpressions: true,\n});\n\nrequire('./server');\n```\n\n## Common Workflows\n\n### Bootstrap An Express Service\n\nPut the debugger agent on the first line of the entrypoint:\n\n```javascript\nrequire('@google-cloud/debug-agent').start();\n\nconst express = require('express');\n\nconst app = express();\n\napp.get('/healthz', (_req, res) => {\n  res.json({ok: true});\n});\n\nconst port = Number(process.env.PORT || 8080);\napp.listen(port, () => {\n  console.log(`listening on ${port}`);\n});\n```\n\n### Start With Explicit Environment Variables\n\nUse environment variables when you want the startup command itself to make the project and credential source obvious:\n\n```bash\nGOOGLE_CLOUD_PROJECT=\"my-project-id\" \\\nGOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\" \\\nnode index.js\n```\n\n### Enable Expression Evaluation Deliberately\n\nExpression evaluation is opt-in:\n\n```javascript\nrequire('@google-cloud/debug-agent').start({\n  allowExpressions: true,\n});\n```\n\nIf you do not need evaluated expressions, leave this off and use plain snapshot breakpoints or logpoints.\n\n## Important Pitfalls\n\n### Loading The Agent Too Late\n\nDo not load the agent after your framework or app modules are already required.\n\nBad:\n\n```javascript\nconst express = require('express');\n\nrequire('@google-cloud/debug-agent').start();\n```\n\nGood:\n\n```javascript\nrequire('@google-cloud/debug-agent').start();\n\nconst express = require('express');\n```\n\n### Expecting A Request Client\n\n`@google-cloud/debug-agent` does not expose a normal per-request client object. The public integration point is the startup call:\n\n```javascript\nrequire('@google-cloud/debug-agent').start();\n```\n\nAfter that, breakpoint management happens in Google Cloud Debugger rather than through application code.\n\n### Missing Project Or IAM Configuration\n\nIf the debug target does not show up, check these first:\n\n- `GOOGLE_CLOUD_PROJECT` points at the correct project when you are not on a managed Google Cloud runtime.\n- The Cloud Debugger API is enabled.\n- The running identity has `roles/clouddebugger.agent`.\n- The process can authenticate with ADC or `GOOGLE_APPLICATION_CREDENTIALS`.\n\n## Practical Notes\n\n- Keep the debugger initialization in a tiny bootstrap file if your main application entrypoint is already crowded.\n- Call `start()` once per process.\n- If you deploy transpiled output, place breakpoints against the files that actually ship with the running service.\n"
  },
  {
    "path": "content/google/docs/deploy/python/DOC.md",
    "content": "---\nname: deploy\ndescription: \"Google Cloud Deploy Python client for listing delivery pipelines and targets, inspecting releases and rollouts, and driving approval or promotion flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,cloud-deploy,gcp,cicd,deployments,rollouts,adc,python\"\n---\n\n# google-cloud-deploy Python Package Guide\n\nUse `google-cloud-deploy` for Python automation around Google Cloud Deploy control-plane resources: delivery pipelines, targets, releases, rollouts, rollout approvals, promotions, and canary advancement.\n\nImport surface:\n\n```python\nfrom google.cloud import deploy_v1\n```\n\n## Golden Rule\n\n- Install and import the official client: `from google.cloud import deploy_v1`.\n- Authenticate with Application Default Credentials (ADC), not ad hoc API-key patterns.\n- Treat Cloud Deploy resource names as regional: `projects/{project}/locations/{location}/...`.\n- Use generated path helpers such as `release_path(...)` and `rollout_path(...)` instead of hand-building resource strings.\n- Read current release or rollout state before approving, promoting, or advancing it.\n- Wait for long-running operations with `operation.result(...)` when later steps depend on completion.\n\n## Version Covered\n\n- Package: `google-cloud-deploy`\n- Ecosystem: `pypi`\n- Version: `2.9.0`\n- Python requirement from PyPI: `>=3.7`\n- Registry: https://pypi.org/project/google-cloud-deploy/\n- Canonical package docs URL from the task input: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-deploy\n- Python reference root used for method shapes: https://docs.cloud.google.com/python/docs/reference/clouddeploy/latest\n\nVersion drift note:\n\n- PyPI lists `2.9.0` as the current package version.\n- The generated Python reference root also renders `google-cloud-deploy 2.9.0`.\n- Some generated subpages, including the changelog and some class pages, still display `2.7.1`.\n- Practical rule: use PyPI for package-version truth, and use the generated reference pages for client classes, request types, and helper methods.\n\n## Install\n\nPin the package version you want the agent to target:\n\n```bash\npython -m pip install google-cloud-deploy==2.9.0\n```\n\nIf you only need the latest published build:\n\n```bash\npython -m pip install google-cloud-deploy\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials through ADC.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud services enable clouddeploy.googleapis.com\n```\n\nService account credentials:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nMinimum setup:\n\n1. Enable the Cloud Deploy API in the target project.\n2. Make sure ADC resolves to the principal you expect.\n3. Grant the IAM role that matches the action being automated.\n4. Keep the project, location, delivery pipeline, release, and rollout names in the same region.\n\nCommon documented Cloud Deploy roles:\n\n- `roles/clouddeploy.admin`\n- `roles/clouddeploy.operator`\n- `roles/clouddeploy.releaser`\n- `roles/clouddeploy.approver`\n\nIf your automation promotes or approves rollouts, validate both Cloud Deploy IAM and the downstream runtime permissions needed by the actual target environment.\n\n## Initialize The Client\n\nStandard sync client:\n\n```python\nfrom google.cloud import deploy_v1\n\nclient = deploy_v1.CloudDeployClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import deploy_v1\n\nclient = deploy_v1.CloudDeployAsyncClient()\n```\n\nThe generated client also supports `transport` and `client_options` when you need REST transport or custom endpoint behavior:\n\n```python\nfrom google.cloud import deploy_v1\n\nclient = deploy_v1.CloudDeployClient(\n    transport=\"rest\",\n)\n```\n\n## Resource Names And Regional Scope\n\nCloud Deploy is regional. Delivery pipelines, targets, releases, and rollouts all live under a location-qualified resource name.\n\nPrefer generated helpers:\n\n```python\nfrom google.cloud import deploy_v1\n\nclient = deploy_v1.CloudDeployClient()\n\npipeline_name = client.delivery_pipeline_path(\n    \"my-project\",\n    \"us-central1\",\n    \"web-app\",\n)\ntarget_name = client.target_path(\n    \"my-project\",\n    \"us-central1\",\n    \"staging\",\n)\nrelease_name = client.release_path(\n    \"my-project\",\n    \"us-central1\",\n    \"web-app\",\n    \"release-20260312\",\n)\nrollout_name = client.rollout_path(\n    \"my-project\",\n    \"us-central1\",\n    \"web-app\",\n    \"release-20260312\",\n    \"release-20260312-to-staging\",\n)\n```\n\nThis is safer than concatenating strings and helps avoid cross-region `NotFound` and permission errors.\n\n## Core Usage\n\n### List Delivery Pipelines\n\n```python\nfrom google.cloud import deploy_v1\n\ndef list_delivery_pipelines(project_id: str, location: str) -> list[str]:\n    client = deploy_v1.CloudDeployClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n\n    return [\n        pipeline.name\n        for pipeline in client.list_delivery_pipelines(\n            request={\"parent\": parent}\n        )\n    ]\n```\n\n### List Targets\n\n```python\nfrom google.cloud import deploy_v1\n\ndef list_targets(project_id: str, location: str) -> list[str]:\n    client = deploy_v1.CloudDeployClient()\n    parent = f\"projects/{project_id}/locations/{location}\"\n\n    return [\n        target.name\n        for target in client.list_targets(\n            request={\"parent\": parent}\n        )\n    ]\n```\n\n### List Releases For A Pipeline\n\n```python\nfrom google.cloud import deploy_v1\n\ndef list_releases(project_id: str, location: str, pipeline_id: str) -> list[str]:\n    client = deploy_v1.CloudDeployClient()\n    parent = client.delivery_pipeline_path(project_id, location, pipeline_id)\n\n    return [\n        release.name\n        for release in client.list_releases(\n            request={\"parent\": parent}\n        )\n    ]\n```\n\n### Read Release And Rollout State Before Acting\n\nUse this before promotion, approval, or canary advancement so automation branches on actual state instead of assuming the rollout is ready.\n\n```python\nfrom google.cloud import deploy_v1\n\ndef get_release_and_rollout(\n    project_id: str,\n    location: str,\n    pipeline_id: str,\n    release_id: str,\n    rollout_id: str,\n):\n    client = deploy_v1.CloudDeployClient()\n\n    release_name = client.release_path(\n        project_id,\n        location,\n        pipeline_id,\n        release_id,\n    )\n    rollout_name = client.rollout_path(\n        project_id,\n        location,\n        pipeline_id,\n        release_id,\n        rollout_id,\n    )\n\n    release = client.get_release(request={\"name\": release_name})\n    rollout = client.get_rollout(request={\"name\": rollout_name})\n    return release, rollout\n```\n\n### Create A Release\n\n`create_release` is usually the most version-sensitive write path. The official request type still centers on three fields:\n\n- `parent`: delivery pipeline resource name\n- `release_id`: release identifier\n- `release`: `deploy_v1.Release` payload\n\n```python\nfrom google.cloud import deploy_v1\n\ndef create_release(project_id: str, location: str, pipeline_id: str, release_id: str):\n    client = deploy_v1.CloudDeployClient()\n    parent = client.delivery_pipeline_path(project_id, location, pipeline_id)\n\n    release = deploy_v1.Release(\n        description=\"Created from Python automation\",\n    )\n\n    operation = client.create_release(\n        request={\n            \"parent\": parent,\n            \"release_id\": release_id,\n            \"release\": release,\n        }\n    )\n    return operation.result(timeout=900)\n```\n\nThe current `Release` reference includes fields such as `skaffold_config_path`, `skaffold_version`, `build_artifacts`, `target_artifacts`, and `deploy_parameters`. Which fields you actually need depends on how the delivery pipeline and render source are configured, so verify the installed client version's `Release` schema before generating release bodies.\n\n### Approve A Rollout\n\nUse `approve_rollout` only when the rollout is paused for approval.\n\n```python\nfrom google.cloud import deploy_v1\n\ndef approve_rollout(\n    project_id: str,\n    location: str,\n    pipeline_id: str,\n    release_id: str,\n    rollout_id: str,\n) -> None:\n    client = deploy_v1.CloudDeployClient()\n    rollout_name = client.rollout_path(\n        project_id,\n        location,\n        pipeline_id,\n        release_id,\n        rollout_id,\n    )\n\n    operation = client.approve_rollout(\n        request={\n            \"name\": rollout_name,\n            \"approved\": True,\n        }\n    )\n    operation.result(timeout=600)\n```\n\n### Promote A Release\n\nUse `promote_release` to move an existing release forward in the delivery pipeline.\n\n```python\nfrom google.cloud import deploy_v1\n\ndef promote_release(\n    project_id: str,\n    location: str,\n    pipeline_id: str,\n    release_id: str,\n    target_id: str,\n    rollout_id: str,\n) -> None:\n    client = deploy_v1.CloudDeployClient()\n    release_name = client.release_path(\n        project_id,\n        location,\n        pipeline_id,\n        release_id,\n    )\n\n    operation = client.promote_release(\n        request={\n            \"name\": release_name,\n            \"target_id\": target_id,\n            \"rollout_id\": rollout_id,\n        }\n    )\n    operation.result(timeout=900)\n```\n\n### Advance A Canary Rollout Phase\n\nFor multi-phase rollouts, use `advance_rollout` with the phase identifier.\n\n```python\nfrom google.cloud import deploy_v1\n\ndef advance_rollout(\n    project_id: str,\n    location: str,\n    pipeline_id: str,\n    release_id: str,\n    rollout_id: str,\n    phase_id: str,\n) -> None:\n    client = deploy_v1.CloudDeployClient()\n    rollout_name = client.rollout_path(\n        project_id,\n        location,\n        pipeline_id,\n        release_id,\n        rollout_id,\n    )\n\n    operation = client.advance_rollout(\n        request={\n            \"name\": rollout_name,\n            \"phase_id\": phase_id,\n        }\n    )\n    operation.result(timeout=900)\n```\n\n## Configuration Notes\n\n- The generated client uses gRPC by default; use `transport=\"rest\"` only if your environment needs REST.\n- The list methods return pagers, so ordinary iteration handles pagination.\n- For library logging, the PyPI package page documents the standard Google client-library logging controls, including the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable.\n\n## Common Pitfalls\n\n- The repo URL from the task is a package source location, not the best day-to-day API reference. Use the generated Python reference for class names and request types.\n- The old docs path pattern `.../python/docs/reference/deploy/latest` is stale for this package. The canonical path is `.../python/docs/reference/clouddeploy/latest`.\n- Cloud Deploy is regional. A correct project with the wrong `location` still fails.\n- `approve_rollout`, `promote_release`, and `advance_rollout` are long-running operations; do not assume success until `operation.result(...)` returns.\n- Approval only works when the rollout is actually waiting for approval.\n- Promotion can fail if the release, pipeline, or target state no longer matches what your automation assumed.\n- Release creation depends on your pipeline configuration, Skaffold setup, render source, and artifacts. Do not generate a large `Release` body from memory alone.\n\n## Version-Sensitive Notes\n\n- This doc targets `2.9.0`, which is the package version currently published on PyPI.\n- The generated reference site is partially version-lagged: some subpages still render `2.7.1` even though the reference root and PyPI show `2.9.0`.\n- `CloudDeployClient` and `CloudDeployAsyncClient` are both present in the current reference.\n- Before using lesser-known request fields, confirm them against the installed client's generated types for `2.9.0` rather than relying on older blog posts or stale snippets.\n\n## Official Links\n\n- Package repo path: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-deploy`\n- PyPI: `https://pypi.org/project/google-cloud-deploy/`\n- Python reference root: `https://docs.cloud.google.com/python/docs/reference/clouddeploy/latest`\n- `CloudDeployClient` reference: `https://docs.cloud.google.com/python/docs/reference/clouddeploy/latest/google.cloud.deploy_v1.services.cloud_deploy.CloudDeployClient`\n- `Release` reference: `https://docs.cloud.google.com/python/docs/reference/clouddeploy/latest/google.cloud.deploy_v1.types.Release`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/clouddeploy/latest/changelog`\n- Cloud Deploy product docs: `https://cloud.google.com/deploy/docs`\n- Promote release guide: `https://cloud.google.com/deploy/docs/promote-release`\n- Approvals and promotions guide: `https://cloud.google.com/deploy/docs/approve-promote`\n"
  },
  {
    "path": "content/google/docs/dialogflow/javascript/DOC.md",
    "content": "---\nname: dialogflow\ndescription: \"Google Cloud Dialogflow ES Node.js client for sessions, intents, contexts, entities, and agent operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,dialogflow,dialogflow-es,gcp,nlp,chatbot,javascript,nodejs\"\n---\n\n# `@google-cloud/dialogflow` JavaScript Package Guide\n\nUse `@google-cloud/dialogflow` for Dialogflow ES integrations in Node.js: detect intent for a session, inspect contexts, and manage agent resources such as intents and entities.\n\n## Golden Rule\n\n- Use the `v2` namespace for Dialogflow ES examples.\n- Use Google Cloud credentials through Application Default Credentials (ADC), not API keys.\n- Do not mix Dialogflow CX examples into this package. Dialogflow CX uses a different API surface.\n- For regional agents, keep both the `apiEndpoint` and every resource name in the same location.\n- Reuse one stable `sessionId` for a single end-user conversation so contexts can carry across turns.\n\nThis guide covers `7.5.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/dialogflow@7.5.0\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable Dialogflow in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable dialogflow.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport DIALOGFLOW_LOCATION=\"global\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport DIALOGFLOW_LOCATION=\"global\"\n```\n\nPractical setup notes:\n\n1. The project must have Dialogflow enabled.\n2. The resolved credential must have Dialogflow permissions in that project.\n3. For regional agents, set `DIALOGFLOW_LOCATION` to the agent region such as `us-central1`.\n4. Prefer attached service accounts or impersonation over long-lived JSON key files when you control the runtime environment.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v2: dialogflow} = require('@google-cloud/dialogflow');\n\nfunction getDialogflowEndpoint(location = 'global') {\n  return location === 'global'\n    ? 'dialogflow.googleapis.com'\n    : `${location}-dialogflow.googleapis.com`;\n}\n\nfunction createSessionsClient(location = 'global') {\n  if (location === 'global') {\n    return new dialogflow.SessionsClient();\n  }\n\n  return new dialogflow.SessionsClient({\n    apiEndpoint: getDialogflowEndpoint(location),\n  });\n}\n```\n\nES modules:\n\n```javascript\nimport {v2 as dialogflow} from '@google-cloud/dialogflow';\n\nfunction getDialogflowEndpoint(location = 'global') {\n  return location === 'global'\n    ? 'dialogflow.googleapis.com'\n    : `${location}-dialogflow.googleapis.com`;\n}\n\nfunction createSessionsClient(location = 'global') {\n  if (location === 'global') {\n    return new dialogflow.SessionsClient();\n  }\n\n  return new dialogflow.SessionsClient({\n    apiEndpoint: getDialogflowEndpoint(location),\n  });\n}\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v2: dialogflow} = require('@google-cloud/dialogflow');\n\nconst client = new dialogflow.SessionsClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Resource Name Helpers\n\nDialogflow ES uses different resource formats for global and regional agents. Build them consistently:\n\n```javascript\nfunction getAgentName(projectId, location = 'global') {\n  return location === 'global'\n    ? `projects/${projectId}/agent`\n    : `projects/${projectId}/locations/${location}/agent`;\n}\n\nfunction getSessionName(projectId, sessionId, location = 'global') {\n  return location === 'global'\n    ? `projects/${projectId}/agent/sessions/${sessionId}`\n    : `projects/${projectId}/locations/${location}/agent/sessions/${sessionId}`;\n}\n```\n\nUse the same location for all related resources in a request flow.\n\n## Core Workflows\n\n### Detect Intent From Text\n\nThis is the main runtime flow for text chat.\n\n```javascript\nconst {v2: dialogflow} = require('@google-cloud/dialogflow');\n\nfunction getDialogflowEndpoint(location = 'global') {\n  return location === 'global'\n    ? 'dialogflow.googleapis.com'\n    : `${location}-dialogflow.googleapis.com`;\n}\n\nfunction createSessionsClient(location = 'global') {\n  if (location === 'global') {\n    return new dialogflow.SessionsClient();\n  }\n\n  return new dialogflow.SessionsClient({\n    apiEndpoint: getDialogflowEndpoint(location),\n  });\n}\n\nfunction getSessionName(projectId, sessionId, location = 'global') {\n  return location === 'global'\n    ? `projects/${projectId}/agent/sessions/${sessionId}`\n    : `projects/${projectId}/locations/${location}/agent/sessions/${sessionId}`;\n}\n\nasync function detectIntentFromText({\n  projectId,\n  sessionId,\n  text,\n  languageCode = 'en-US',\n  location = 'global',\n}) {\n  const client = createSessionsClient(location);\n  const session = getSessionName(projectId, sessionId, location);\n\n  const [response] = await client.detectIntent({\n    session,\n    queryInput: {\n      text: {\n        text,\n        languageCode,\n      },\n    },\n  });\n\n  const result = response.queryResult;\n\n  return {\n    intent: result.intent?.displayName ?? null,\n    confidence: result.intentDetectionConfidence ?? 0,\n    fulfillmentText: result.fulfillmentText ?? '',\n    parameters: result.parameters,\n  };\n}\n\nasync function main() {\n  const response = await detectIntentFromText({\n    projectId: process.env.GOOGLE_CLOUD_PROJECT,\n    sessionId: 'web-demo-session',\n    text: 'Book a table for two tonight',\n    languageCode: 'en-US',\n    location: process.env.DIALOGFLOW_LOCATION || 'global',\n  });\n\n  console.log(response);\n}\n\nmain().catch(console.error);\n```\n\nUse one stable `sessionId` per conversation. If every turn uses a new session ID, Dialogflow cannot reuse context from earlier turns.\n\n### Trigger An Intent With An Event\n\nUse an event input when your application needs to start a flow explicitly instead of matching end-user text.\n\n```javascript\nconst {v2: dialogflow} = require('@google-cloud/dialogflow');\n\nfunction getDialogflowEndpoint(location = 'global') {\n  return location === 'global'\n    ? 'dialogflow.googleapis.com'\n    : `${location}-dialogflow.googleapis.com`;\n}\n\nfunction createSessionsClient(location = 'global') {\n  if (location === 'global') {\n    return new dialogflow.SessionsClient();\n  }\n\n  return new dialogflow.SessionsClient({\n    apiEndpoint: getDialogflowEndpoint(location),\n  });\n}\n\nfunction getSessionName(projectId, sessionId, location = 'global') {\n  return location === 'global'\n    ? `projects/${projectId}/agent/sessions/${sessionId}`\n    : `projects/${projectId}/locations/${location}/agent/sessions/${sessionId}`;\n}\n\nasync function detectIntentFromEvent({\n  projectId,\n  sessionId,\n  eventName,\n  languageCode = 'en-US',\n  location = 'global',\n}) {\n  const client = createSessionsClient(location);\n  const session = getSessionName(projectId, sessionId, location);\n\n  const [response] = await client.detectIntent({\n    session,\n    queryInput: {\n      event: {\n        name: eventName,\n        languageCode,\n      },\n    },\n  });\n\n  return response.queryResult;\n}\n```\n\n### List Active Contexts For A Session\n\nContexts show what Dialogflow is carrying forward between turns.\n\n```javascript\nconst {v2: dialogflow} = require('@google-cloud/dialogflow');\n\nfunction getDialogflowEndpoint(location = 'global') {\n  return location === 'global'\n    ? 'dialogflow.googleapis.com'\n    : `${location}-dialogflow.googleapis.com`;\n}\n\nfunction createContextsClient(location = 'global') {\n  if (location === 'global') {\n    return new dialogflow.ContextsClient();\n  }\n\n  return new dialogflow.ContextsClient({\n    apiEndpoint: getDialogflowEndpoint(location),\n  });\n}\n\nfunction getSessionName(projectId, sessionId, location = 'global') {\n  return location === 'global'\n    ? `projects/${projectId}/agent/sessions/${sessionId}`\n    : `projects/${projectId}/locations/${location}/agent/sessions/${sessionId}`;\n}\n\nasync function listActiveContexts({projectId, sessionId, location = 'global'}) {\n  const client = createContextsClient(location);\n  const parent = getSessionName(projectId, sessionId, location);\n  const [contexts] = await client.listContexts({parent});\n\n  return contexts.map(context => ({\n    name: context.name,\n    lifespanCount: context.lifespanCount,\n    parameters: context.parameters,\n  }));\n}\n```\n\n## Other Common Operations\n\nUse these clients when you move beyond runtime session handling:\n\n- `IntentsClient` for listing, creating, updating, and deleting intents\n- `EntityTypesClient` for custom entities and synonyms\n- `AgentsClient` for agent metadata and supported languages\n- `KnowledgeBasesClient` and `DocumentsClient` for knowledge connectors\n- `SessionEntityTypesClient` for per-session entity overrides\n\nKeep the endpoint and resource-name location aligned for those clients too.\n\n## Important Pitfalls\n\n- Dialogflow ES vs CX: this package targets Dialogflow ES. Do not copy Dialogflow CX code into an ES integration.\n- Global vs regional mismatch: for a regional agent, changing only the endpoint or only the resource name is a common cause of `NOT_FOUND` and routing failures.\n- Credentials: use ADC or service-account credentials. Dialogflow requests are not authenticated with a simple API key.\n- Session scoping: reuse a session within one conversation, but do not share one session ID across unrelated users.\n- Language code: pass a `languageCode` that matches the agent's default language or an enabled language.\n- Response handling: `fulfillmentText` can be empty. If the reply seems incomplete, inspect other `queryResult` fields such as contexts, parameters, and rich response messages.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/dialogflow` version `7.5.0`.\n- The maintainer reference URL for this package is a rolling `latest` docs tree. If your project pins a materially older or newer package version, verify request fields and helper names against the installed package and the matching reference pages.\n\n## Official Sources\n\n- `https://cloud.google.com/nodejs/docs/reference/dialogflow/latest`\n- `https://cloud.google.com/dialogflow/es/docs/how/detect-intent-text`\n- `https://cloud.google.com/dialogflow/es/docs/how/region`\n- `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- `https://www.npmjs.com/package/@google-cloud/dialogflow`\n"
  },
  {
    "path": "content/google/docs/dialogflow/python/DOC.md",
    "content": "---\nname: dialogflow\ndescription: \"Google Cloud Dialogflow ES Python client library for sessions, intents, contexts, and agent management\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.46.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,dialogflow,dialogflow-es,gcp,chatbot,conversation,nlp\"\n---\n\n# Google Cloud Dialogflow Python Client\n\n## Golden Rule\n\nUse `google-cloud-dialogflow` for Dialogflow ES work in Python, and treat the official Google Cloud reference as the source of truth for client classes and request shapes.\n\n- Use Application Default Credentials (ADC) instead of hardcoding credentials in code.\n- Do not mix Dialogflow CX examples into this package. This package documents the Dialogflow ES / `dialogflow_v2` surface.\n- If your agent is regional, set both the API endpoint and the session resource path to the same location.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-dialogflow==2.46.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dialogflow==2.46.0\"\npoetry add \"google-cloud-dialogflow==2.46.0\"\n```\n\n## Authentication And Setup\n\nFor local development, prefer ADC with the Google Cloud CLI:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project-id\"\nexport DIALOGFLOW_LOCATION=\"global\"\n```\n\nIf you must use a service account key file, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project-id\"\n```\n\nPractical notes:\n\n- The Google Cloud project must have Dialogflow enabled and the caller must have Dialogflow permissions.\n- For regional agents, set `DIALOGFLOW_LOCATION` to the region where the agent lives, for example `us-central1`.\n- Prefer attached service accounts or impersonation over long-lived JSON key files when you control the runtime environment.\n\n## Initialize A Sessions Client\n\nUse the default global endpoint unless your agent is regional:\n\n```python\nimport os\nfrom typing import Sequence\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dialogflow\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"DIALOGFLOW_LOCATION\", \"global\")\n\ndef make_sessions_client(location: str) -> dialogflow.SessionsClient:\n    if location == \"global\":\n        return dialogflow.SessionsClient()\n\n    return dialogflow.SessionsClient(\n        client_options=ClientOptions(\n            api_endpoint=f\"{location}-dialogflow.googleapis.com:443\"\n        )\n    )\n\ndef build_session_name(\n    client: dialogflow.SessionsClient, project_id: str, session_id: str, location: str\n) -> str:\n    if location == \"global\":\n        return client.session_path(project_id, session_id)\n\n    return f\"projects/{project_id}/locations/{location}/agent/sessions/{session_id}\"\n```\n\nIf ADC is not available in the current process, you can initialize directly from a service account file:\n\n```python\nfrom google.cloud import dialogflow\n\nclient = dialogflow.SessionsClient.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n```\n\n## Core Usage: Detect Intent From Text\n\nThis is the core request flow from the official text detect-intent sample, with regional endpoint handling added:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dialogflow\n\ndef detect_intent_texts(\n    project_id: str,\n    session_id: str,\n    texts: Sequence[str],\n    language_code: str = \"en-US\",\n    location: str = \"global\",\n) -> None:\n    client_options = None\n    if location != \"global\":\n        client_options = ClientOptions(\n            api_endpoint=f\"{location}-dialogflow.googleapis.com:443\"\n        )\n\n    session_client = dialogflow.SessionsClient(client_options=client_options)\n\n    if location == \"global\":\n        session = session_client.session_path(project_id, session_id)\n    else:\n        session = (\n            f\"projects/{project_id}/locations/{location}/agent/sessions/{session_id}\"\n        )\n\n    for text in texts:\n        text_input = dialogflow.TextInput(text=text, language_code=language_code)\n        query_input = dialogflow.QueryInput(text=text_input)\n\n        response = session_client.detect_intent(\n            request={\"session\": session, \"query_input\": query_input}\n        )\n\n        result = response.query_result\n        matched_intent = result.intent.display_name if result.intent else \"<no match>\"\n\n        print(f\"user: {text}\")\n        print(f\"intent: {matched_intent}\")\n        print(f\"confidence: {result.intent_detection_confidence:.3f}\")\n        print(f\"reply: {result.fulfillment_text}\")\n        print(\"---\")\n\ndetect_intent_texts(\n    project_id=os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n    session_id=\"web-demo-session\",\n    texts=[\"hello\", \"book a table for two tonight\"],\n    language_code=\"en-US\",\n    location=os.getenv(\"DIALOGFLOW_LOCATION\", \"global\"),\n)\n```\n\nUse one stable `session_id` per end-user conversation so Dialogflow can reuse context across turns.\n\n## Other Common Operations\n\nReach for these clients for the next layer of work:\n\n- `IntentsClient`: create, update, list, and delete intents\n- `ContextsClient`: inspect or clear active contexts for a session\n- `EntityTypesClient`: manage custom entities and synonyms\n- `AgentsClient`: inspect agent settings and supported languages\n- `KnowledgeBasesClient` and `DocumentsClient`: manage knowledge connectors\n\nThe package reference root lists these services and their request/response types under `google.cloud.dialogflow_v2`.\n\n## Configuration Notes\n\n### Regional agents\n\nRegional Dialogflow ES agents require both of these changes:\n\n- API endpoint: `\"{location}-dialogflow.googleapis.com:443\"`\n- Session resource: `projects/{project}/locations/{location}/agent/sessions/{session}`\n\nChanging only one of them is a common cause of `NOT_FOUND` and routing errors.\n\n### Logging\n\nThe library supports opt-in standard logging. Set a logging scope before import or process startup:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nTreat client logs as sensitive. Request metadata and payload details may not be appropriate for production logs.\n\n## Common Pitfalls\n\n- Dialogflow ES vs CX: this package is for Dialogflow ES. CX examples and resource names do not map cleanly here.\n- Global vs regional mismatch: if the agent is regional, do not keep using the default global endpoint.\n- Post-fork gRPC clients: create client instances after `os.fork()` or worker process start. Do not share a pre-fork client across processes.\n- Session handling: reuse a session ID for one conversation, but do not share one session ID across unrelated users.\n- Empty `fulfillment_text`: some agents rely more on rich response messages, output contexts, or intent parameters than on a single text reply.\n- Explicit close behavior: using the client as a context manager closes the underlying transport. Do not do that if the transport is shared elsewhere in the process.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-dialogflow 2.46.0`, which is the version tracked in this doc.\n- As of `2026-03-12`, Google Cloud reference pages under the `latest` docs tree still show `2.45.0` in page titles and the published changelog.\n- Use PyPI as the authoritative package-release source for pinning, and use the Google Cloud `latest` reference tree for current API shapes until Google publishes a clearly version-aligned `2.46.0` reference set.\n\n## Official Sources\n\n- `https://cloud.google.com/python/docs/reference/dialogflow/latest`\n- `https://cloud.google.com/python/docs/reference/dialogflow/latest/google.cloud.dialogflow_v2.services.sessions.SessionsClient`\n- `https://cloud.google.com/python/docs/reference/dialogflow/latest/changelog`\n- `https://cloud.google.com/dialogflow/es/docs/how/detect-intent-text`\n- `https://cloud.google.com/dialogflow/es/docs/how/region`\n- `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- `https://pypi.org/project/google-cloud-dialogflow/`\n"
  },
  {
    "path": "content/google/docs/discoveryengine/javascript/DOC.md",
    "content": "---\nname: discoveryengine\ndescription: \"Google Cloud Discovery Engine Node.js client for search, answer generation, and document inspection\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.5.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,discoveryengine,vertex-ai-search,agent-builder,search,rag,javascript,nodejs\"\n---\n\n# `@google-cloud/discoveryengine` JavaScript Package Guide\n\nUse `@google-cloud/discoveryengine` when your Node.js code needs to query a Discovery Engine data store, generate grounded answers over indexed content, or inspect indexed documents.\n\n## Golden Rule\n\n- Use the GA `v1` clients from `@google-cloud/discoveryengine`.\n- Enable `discoveryengine.googleapis.com` in the Google Cloud project that owns the data store.\n- Authenticate with Application Default Credentials (ADC) unless you have a specific reason to pass a credential file directly.\n- Set a regional `apiEndpoint` when your Discovery Engine resources are not in `global`.\n- Reuse full resource names for `servingConfig`, `branch`, and `session` instead of rebuilding them differently in each call.\n\nThis guide covers `2.5.3`.\n\n## Install\n\nPin the package version your app should target:\n\n```bash\nnpm install @google-cloud/discoveryengine@2.5.3\n```\n\n## Authentication And Setup\n\nBefore making API calls, make sure all of the following are true:\n\n1. You have a Google Cloud project.\n2. Billing is enabled for that project.\n3. The Discovery Engine API is enabled.\n4. ADC is configured for the identity your app runs as.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable discoveryengine.googleapis.com \\\n  --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\nexport DISCOVERY_ENGINE_DATA_STORE_ID=\"my-data-store\"\nexport DISCOVERY_ENGINE_SERVING_CONFIG=\"default_serving_config\"\nexport DISCOVERY_ENGINE_BRANCH=\"default_branch\"\n```\n\nIf you must use a service account key outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account instead of shipping JSON keys.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/discoveryengine');\n\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\nconst dataStoreId = process.env.DISCOVERY_ENGINE_DATA_STORE_ID;\nconst servingConfigId =\n  process.env.DISCOVERY_ENGINE_SERVING_CONFIG ?? 'default_serving_config';\nconst branchId = process.env.DISCOVERY_ENGINE_BRANCH ?? 'default_branch';\n\nconst clientOptions = {\n  projectId,\n  ...(location === 'global'\n    ? {}\n    : {apiEndpoint: `${location}-discoveryengine.googleapis.com`}),\n};\n\nconst searchClient = new v1.SearchServiceClient(clientOptions);\nconst answerClient = new v1.ConversationalSearchServiceClient(clientOptions);\nconst documentClient = new v1.DocumentServiceClient(clientOptions);\n\nconst servingConfig = searchClient.servingConfigPath(\n  projectId,\n  location,\n  dataStoreId,\n  servingConfigId\n);\n\nconst branch = documentClient.branchPath(\n  projectId,\n  location,\n  dataStoreId,\n  branchId\n);\n\nconst session = answerClient.sessionPath(projectId, location, dataStoreId, '-');\n```\n\nIf you want to pass a credential file explicitly, add `keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS` to `clientOptions`.\n\nFor non-global locations, keep the resource names and `apiEndpoint` aligned with the same region.\n\n## Core Workflows\n\n### Search Indexed Content\n\nUse `search()` when you want ranked matching documents.\n\n```javascript\nconst {v1} = require('@google-cloud/discoveryengine');\n\nconst searchClient = new v1.SearchServiceClient();\n\nasync function searchDocuments(servingConfig, branch, query) {\n  const [response] = await searchClient.search({\n    servingConfig,\n    branch,\n    query,\n    pageSize: 5,\n  });\n\n  for (const result of response.results ?? []) {\n    const document = result.document;\n    const title = document?.derivedStructData?.title ?? document?.name;\n    console.log(document?.id, title);\n  }\n}\n```\n\nKeep `servingConfig` as the fully qualified resource name returned by the client helper or the console. The reference docs allow both data-store-based and engine-based serving config resource names; use one form consistently.\n\n### Generate An Answer\n\nUse `answerQuery()` when you want a synthesized answer grounded in retrieved content instead of raw ranked results.\n\n```javascript\nconst {v1} = require('@google-cloud/discoveryengine');\n\nconst answerClient = new v1.ConversationalSearchServiceClient();\n\nasync function answerQuestion(servingConfig, session, question, userPseudoId) {\n  const [response] = await answerClient.answerQuery({\n    servingConfig,\n    query: {\n      text: question,\n    },\n    session,\n    userPseudoId,\n    answerGenerationSpec: {\n      includeCitations: true,\n      ignoreAdversarialQuery: true,\n      ignoreNonAnswerSeekingQuery: true,\n      modelSpec: {\n        modelVersion: 'stable',\n      },\n    },\n  });\n\n  console.log(response.answer?.answerText ?? '');\n}\n```\n\nUse a stable `userPseudoId` per visitor or device. If you want the service to create a session automatically, pass the wildcard session resource with `-` as the session ID.\n\n### Inspect Indexed Documents\n\nUse `listDocumentsAsync()` when search results look wrong and you want to confirm what is actually indexed in the branch.\n\n```javascript\nconst {v1} = require('@google-cloud/discoveryengine');\n\nconst documentClient = new v1.DocumentServiceClient();\n\nasync function listIndexedDocuments(branch, limit = 20) {\n  let count = 0;\n\n  for await (const document of documentClient.listDocumentsAsync({\n    parent: branch,\n  })) {\n    console.log(document.name);\n\n    count += 1;\n    if (count >= limit) {\n      break;\n    }\n  }\n}\n```\n\nThe generated client also exposes document-path helpers, which are safer than hand-assembling resource names when you later add `getDocument()`, imports, or cleanup code.\n\n## Common Pitfalls\n\n- `search()` and `answerQuery()` are different APIs. Use `search()` for ranked retrieval and `answerQuery()` for generated answers.\n- Set `apiEndpoint` for non-`global` locations. Mismatched endpoints and resource locations are a common source of `NOT_FOUND` and routing errors.\n- Keep `userPseudoId` stable. Do not send a fixed placeholder for every visitor.\n- `searchLite()` is a separate path intended for public website search with API keys. It is not the default path for normal IAM- or OAuth-backed application access.\n- The request docs accept both engine-based and data-store-based serving config resource names. Do not mix those forms accidentally in the same integration.\n- Reuse long-lived client instances instead of creating a new client on every request.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/discoveryengine@2.5.3`.\n- The examples here use the GA `v1` namespace.\n- If you are following older Discovery Engine material, check whether it uses earlier product branding or preview namespaces before copying code into a current project.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/discoveryengine/latest`\n- Search client reference: `https://cloud.google.com/nodejs/docs/reference/discoveryengine/latest/discoveryengine/v1.searchserviceclient`\n- Conversational search client reference: `https://cloud.google.com/nodejs/docs/reference/discoveryengine/latest/discoveryengine/v1.conversationalsearchserviceclient`\n- Document client reference: `https://cloud.google.com/nodejs/docs/reference/discoveryengine/latest/discoveryengine/v1.documentserviceclient`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Maintainer package source: `https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-discoveryengine`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/discoveryengine`\n"
  },
  {
    "path": "content/google/docs/discoveryengine/python/DOC.md",
    "content": "---\nname: discoveryengine\ndescription: \"Google Cloud Discovery Engine Python client for search, answer generation, and document operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,discoveryengine,vertex-ai-search,agent-builder,search,rag,recommendations\"\n---\n\n# Google Cloud Discovery Engine Python Client\n\n## Install And Prerequisites\n\nGoogle's own package quickstart still expects the standard Google Cloud setup before client code will work:\n\n1. Select or create a Google Cloud project.\n2. Enable billing for that project.\n3. Enable the Discovery Engine API.\n4. Set up authentication.\n\nThen install the client in an isolated environment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-discoveryengine==0.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-discoveryengine==0.17.0\"\npoetry add \"google-cloud-discoveryengine==0.17.0\"\n```\n\n## Authentication And Endpoint Setup\n\nGoogle Cloud client libraries use Application Default Credentials (ADC). For local development, Google recommends setting up ADC with your user credentials or service account impersonation via the `gcloud` CLI. For production, attach a service account to the runtime instead of baking JSON keys into the app.\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\nexport DISCOVERY_ENGINE_DATA_STORE_ID=\"my-data-store\"\n```\n\nUse a regional endpoint when your resources are not in `global`. The generated Discovery Engine client snippets explicitly warn that you may need to specify regional endpoints when creating the service client.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import discoveryengine_v1 as discoveryengine\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nDATA_STORE_ID = os.environ[\"DISCOVERY_ENGINE_DATA_STORE_ID\"]\n\nclient_options = None\nif LOCATION != \"global\":\n    client_options = ClientOptions(\n        api_endpoint=f\"{LOCATION}-discoveryengine.googleapis.com\"\n    )\n\nsearch_client = discoveryengine.SearchServiceClient(client_options=client_options)\ndocument_client = discoveryengine.DocumentServiceClient(client_options=client_options)\nanswer_client = discoveryengine.ConversationalSearchServiceClient(\n    client_options=client_options\n)\n\nserving_config = search_client.serving_config_path(\n    project=PROJECT_ID,\n    location=LOCATION,\n    data_store=DATA_STORE_ID,\n    serving_config=\"default_serving_config\",\n)\n\nbranch = document_client.branch_path(\n    project=PROJECT_ID,\n    location=LOCATION,\n    data_store=DATA_STORE_ID,\n    branch=\"default_branch\",\n)\n```\n\n## Core Search\n\n`SearchServiceClient.search()` is the default entry point when you need ranked search results from an indexed data store.\n\n```python\nfrom google.cloud import discoveryengine_v1 as discoveryengine\n\nrequest = discoveryengine.SearchRequest(\n    serving_config=serving_config,\n    query=\"refund policy\",\n    page_size=5,\n)\n\npager = search_client.search(request=request)\n\nfor result in pager:\n    document = result.document\n    title = document.derived_struct_data.get(\"title\")\n    print(document.id, title or document.name)\n```\n\nUseful notes from the reference docs:\n\n- `SearchRequest.serving_config` accepts either an engine serving config or a data store serving config.\n- Leaving `branch` empty searches the default branch; otherwise use a branch resource name such as `default_branch`.\n- `page_size` limits depend on the indexed data type, so do not assume every corpus supports large pages.\n- The returned pager handles additional pages for you when you iterate it.\n\n### API key-only search\n\n`SearchServiceClient.search_lite()` exists, but the reference docs restrict it to public website search and explicitly recommend normal `search()` with OAuth/IAM checks for better security. Treat `search_lite()` as a narrow onboarding path, not the default for private or enterprise content.\n\n## Answer Generation\n\nUse `ConversationalSearchServiceClient.answer_query()` when you need synthesized answers over retrieved content instead of raw ranked results.\n\n```python\nfrom google.cloud import discoveryengine_v1 as discoveryengine\n\nsession = answer_client.session_path(\n    project=PROJECT_ID,\n    location=LOCATION,\n    data_store=DATA_STORE_ID,\n    session=\"-\",\n)\n\nrequest = discoveryengine.AnswerQueryRequest(\n    serving_config=serving_config,\n    query=discoveryengine.Query(text=\"Summarize the return policy.\"),\n    session=session,\n    user_pseudo_id=\"user-123\",\n    answer_generation_spec=discoveryengine.AnswerQueryRequest.AnswerGenerationSpec(\n        include_citations=True,\n        ignore_adversarial_query=True,\n        ignore_non_answer_seeking_query=True,\n        model_spec=discoveryengine.AnswerQueryRequest.AnswerGenerationSpec.ModelSpec(\n            model_version=\"stable\"\n        ),\n    ),\n)\n\nresponse = answer_client.answer_query(request=request)\nprint(response.answer.answer_text)\n```\n\nImportant behavior from the request docs:\n\n- `session` is optional. If you want auto-session mode, Google documents `-` as a wildcard session ID and the service will generate a session for you.\n- `stream_answer_query()` is available if you need streamed answer output.\n- `user_pseudo_id` should be stable per visitor/device and should not be a fixed placeholder like `unknown_visitor`.\n\n## Inspect Documents\n\nWhen search results are unexpectedly empty, inspect the indexed content before debugging query logic.\n\n```python\npager = document_client.list_documents(request={\"parent\": branch})\n\nfor document in pager:\n    print(document.name)\n```\n\nUseful helpers from `DocumentServiceClient`:\n\n- `branch_path(project, location, data_store, branch)`\n- `document_path(project, location, data_store, branch, document)`\n\nThese helpers are safer than hand-assembling resource names when you are writing validation, ingestion, or cleanup tools.\n\n## Configuration And Operational Notes\n\n- Prefer ADC over manually loading credentials into every client constructor. The auth docs say client libraries automatically check ADC and use those credentials.\n- In production, attach a service account to the workload instead of distributing long-lived JSON keys.\n- Keep `project`, `location`, `data_store`, `branch`, and `serving_config` in environment or typed config. Most `INVALID_ARGUMENT` and `NOT_FOUND` failures come from a wrong resource path, not a broken query.\n- If you need request-level logging while debugging, PyPI documents the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable. `export GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google` enables default debug logging for Google client libraries.\n\n## Common Pitfalls\n\n- Hosted docs are currently inconsistent across pages. Do not assume every `latest` page reflects the same package build.\n- Set `client_options.api_endpoint` for non-`global` locations. The generated client snippets repeat this warning across search, document, and conversational clients.\n- Search and answer generation are separate APIs. `search()` returns ranked results; `answer_query()` generates synthesized responses over retrieved content.\n- Be consistent about resource naming. Request types accept both engine-based and data-store-based serving configs, while many helper methods generate data-store-based paths.\n- Older examples may use preview modules or older product branding such as Generative AI App Builder. Prefer `discoveryengine_v1` and current resource names unless you have a documented reason to use preview APIs.\n- `search_lite()` supports API keys only for public website search. It is not a general replacement for OAuth/IAM-backed search.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-discoveryengine 0.17.0`, released on February 12, 2026.\n- The official reference changelog page still reports `0.16.0 (latest)` and was last updated on December 18, 2025.\n- The hosted reference is in a mixed rollout state:\n  - `SearchServiceClient` renders as `0.17.0`.\n  - `ConversationalSearchServiceClient` and `SearchRequest` render as `0.16.0`.\n  - `DocumentServiceClient` still renders as `0.15.0`.\n- If you are using a very new symbol from the installed package, confirm it exists locally with Python introspection or your editor's type stubs instead of trusting a single hosted page.\n\n## Official Sources\n\n- Python reference root: `https://cloud.google.com/python/docs/reference/discoveryengine/latest`\n- Search client reference: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/google.cloud.discoveryengine_v1.services.search_service.SearchServiceClient`\n- Search request reference: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/google.cloud.discoveryengine_v1.types.SearchRequest`\n- Conversational search client reference: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/google.cloud.discoveryengine_v1.services.conversational_search_service.ConversationalSearchServiceClient`\n- Answer query request reference: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/google.cloud.discoveryengine_v1.types.AnswerQueryRequest`\n- Document service reference: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/google.cloud.discoveryengine_v1.services.document_service.DocumentServiceClient`\n- Discovery Engine changelog: `https://cloud.google.com/python/docs/reference/discoveryengine/latest/changelog`\n- Google Cloud authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- PyPI package page: `https://pypi.org/project/google-cloud-discoveryengine/`\n"
  },
  {
    "path": "content/google/docs/dlp/javascript/DOC.md",
    "content": "---\nname: dlp\ndescription: \"@google-cloud/dlp Node.js client for Sensitive Data Protection inspection, de-identification, jobs, and image redaction\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,dlp,sensitive-data-protection,pii,redaction,javascript\"\n---\n\n# Google Cloud Sensitive Data Protection Node.js Client\n\n`@google-cloud/dlp` is the official Node.js client for Google Cloud Sensitive Data Protection, the product formerly called Cloud DLP. The package and API surface still use DLP naming such as `DlpServiceClient`, `inspectContent`, and `createDlpJob`.\n\n## Golden Rule\n\nUse `@google-cloud/dlp` with Application Default Credentials (ADC), enable `dlp.googleapis.com` in the target project, and build requests around a location-qualified `parent` resource: `projects/PROJECT_ID/locations/LOCATION`.\n\nFor new Node.js code, use the package's `v2` namespace:\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n```\n\n```javascript\nimport {v2} from '@google-cloud/dlp'\n\nconst client = new v2.DlpServiceClient()\n```\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/dlp@6.5.0\n```\n\n## Authentication And Project Setup\n\nEnable the API and configure ADC before making calls:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\ngcloud services enable dlp.googleapis.com --project=\"$GOOGLE_CLOUD_PROJECT\"\n```\n\nIf you must use a service account key file outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account instead of distributing key files.\n\nBefore you write application code, make sure all of the following are true:\n\n- `GOOGLE_CLOUD_PROJECT` points at the project that has the DLP API enabled.\n- `GOOGLE_CLOUD_LOCATION` is set to `global` unless you intentionally use a regional location.\n- Templates, job triggers, and jobs use the same location as the `parent` resource you pass.\n- Inline text goes in `item`, while raw bytes such as images go in `byteItem`.\n\n## Initialize A Client\n\nBasic client construction:\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n```\n\nWith explicit project, key file, or endpoint settings:\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n  apiEndpoint: process.env.GOOGLE_CLOUD_DLP_ENDPOINT,\n})\n```\n\nCreate the client once and reuse it across requests instead of constructing a new client for every scan.\n\n## Build The `parent` Resource Once\n\nMost calls require the same `parent` string:\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT\nconst location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global'\nconst parent = `projects/${projectId}/locations/${location}`\n```\n\nIf you omit the location segment, the request is not valid.\n\n## Inspect Inline Text\n\nUse `inspectContent()` for text or small payloads that are already in memory.\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n\nasync function inspectText() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global'\n  const parent = `projects/${projectId}/locations/${location}`\n\n  const [response] = await client.inspectContent({\n    parent,\n    item: {\n      value: 'Contact alice@example.com or call 415-555-0100.',\n    },\n    inspectConfig: {\n      infoTypes: [\n        {name: 'EMAIL_ADDRESS'},\n        {name: 'PHONE_NUMBER'},\n      ],\n      includeQuote: true,\n      minLikelihood: 'POSSIBLE',\n    },\n  })\n\n  for (const finding of response.result?.findings ?? []) {\n    console.log(finding.infoType?.name, finding.quote)\n  }\n}\n\ninspectText().catch(console.error)\n```\n\nSet `includeQuote` only when downstream code actually needs the matched text. If you only need counts or metadata, leave it off so the response carries less sensitive data.\n\n## De-Identify Text\n\nUse `deidentifyContent()` when you want the service to transform sensitive values instead of only reporting them.\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n\nasync function deidentifyText() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global'\n  const parent = `projects/${projectId}/locations/${location}`\n\n  const [response] = await client.deidentifyContent({\n    parent,\n    item: {\n      value: 'Contact alice@example.com or call 415-555-0100.',\n    },\n    inspectConfig: {\n      infoTypes: [\n        {name: 'EMAIL_ADDRESS'},\n        {name: 'PHONE_NUMBER'},\n      ],\n    },\n    deidentifyConfig: {\n      infoTypeTransformations: {\n        transformations: [\n          {\n            primitiveTransformation: {\n              replaceWithInfoTypeConfig: {},\n            },\n          },\n        ],\n      },\n    },\n  })\n\n  console.log(response.item?.value)\n}\n\ndeidentifyText().catch(console.error)\n```\n\nThat sample replaces findings with their info type labels such as `EMAIL_ADDRESS` and `PHONE_NUMBER`. For production masking or tokenization, swap in the transformation you actually need and keep the inspect configuration aligned with it.\n\n## Redact Sensitive Data From Images\n\nUse `redactImage()` when the input is an image file that may contain text or other sensitive content.\n\n```javascript\nconst fs = require('node:fs')\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n\nasync function redactImage() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global'\n  const parent = `projects/${projectId}/locations/${location}`\n\n  const [response] = await client.redactImage({\n    parent,\n    byteItem: {\n      type: 'IMAGE',\n      data: fs.readFileSync('document.png'),\n    },\n    inspectConfig: {\n      infoTypes: [{name: 'EMAIL_ADDRESS'}],\n    },\n    imageRedactionConfigs: [\n      {\n        infoType: {name: 'EMAIL_ADDRESS'},\n      },\n    ],\n  })\n\n  fs.writeFileSync('document-redacted.png', response.redactedImage)\n}\n\nredactImage().catch(console.error)\n```\n\nFor image work, `byteItem` holds the raw file bytes and `imageRedactionConfigs` tells the service which findings to cover in the output image.\n\n## Use Jobs For Storage-Backed Scans\n\nDo not send large files through `inspectContent()`. For Cloud Storage and BigQuery workloads, create a DLP job instead.\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n\nasync function createInspectJob() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global'\n  const parent = `projects/${projectId}/locations/${location}`\n\n  const [job] = await client.createDlpJob({\n    parent,\n    inspectJob: {\n      inspectConfig: {\n        infoTypes: [{name: 'EMAIL_ADDRESS'}],\n        minLikelihood: 'POSSIBLE',\n        includeQuote: true,\n      },\n      storageConfig: {\n        cloudStorageOptions: {\n          fileSet: {\n            url: 'gs://your-bucket/input/*.txt',\n          },\n        },\n      },\n    },\n  })\n\n  console.log(job.name)\n}\n\ncreateInspectJob().catch(console.error)\n```\n\nPoll the created job later:\n\n```javascript\nconst {v2} = require('@google-cloud/dlp')\n\nconst client = new v2.DlpServiceClient()\n\nasync function getJob(jobName) {\n  const [job] = await client.getDlpJob({name: jobName})\n  console.log(job.state)\n}\n\ngetJob('projects/your-gcp-project/locations/global/dlpJobs/i-1234567890').catch(console.error)\n```\n\nUse templates and job triggers when the same inspect or de-identify configuration needs to run repeatedly. Keep the template location, trigger location, and job location aligned.\n\n## Common Pitfalls\n\n- Missing ADC is the most common failure mode. Start with `gcloud auth application-default login` for local development.\n- A valid credential is not enough if `dlp.googleapis.com` is disabled in the project tied to those credentials.\n- Always pass a full `parent` such as `projects/my-project/locations/global`. `projects/my-project` is not enough.\n- In Node.js request objects, use camelCase fields such as `inspectConfig`, `deidentifyConfig`, `includeQuote`, and `imageRedactionConfigs`.\n- Use `inspectContent()` for inline data already in memory, and use `createDlpJob()` for storage-backed scans.\n- Keep locations consistent across parents, templates, job triggers, and jobs.\n- Prefer built-in info types first. Add custom detectors only when the built-in detectors do not cover your data.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/dlp` `6.5.0`.\n- The maintainer reference lives under a rolling `latest` URL, so re-check the docs before copying examples into a project pinned to a different package version.\n- Older examples may show top-level imports or different request object shapes. For new code, keep the `v2.DlpServiceClient` namespace and camelCase request fields consistent.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/dlp/latest`\n- Sensitive Data Protection documentation: `https://cloud.google.com/sensitive-data-protection/docs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/dlp`\n"
  },
  {
    "path": "content/google/docs/dlp/python/DOC.md",
    "content": "---\nname: dlp\ndescription: \"google-cloud-dlp Python client for Cloud Sensitive Data Protection inspection, de-identification, re-identification, jobs, and image redaction\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.34.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-dlp,google cloud,dlp,sensitive data protection,pii,python\"\n---\n\n# google-cloud-dlp Python Package Guide\n\n`google-cloud-dlp` is the official Python client for Google Cloud Sensitive Data Protection (the DLP API). Use it to inspect text or structured data for info types, de-identify or re-identify content, redact images, and run long-running DLP jobs against sources such as Cloud Storage and BigQuery.\n\nThis guide is scoped to package version `3.34.0`. The docs URL points at the rolling `latest` reference. As of the official docs page on 2026-03-12, `latest` also resolves to `3.34.0`, but you should still check the changelog before copying older or newer samples.\n\n## Install\n\n```bash\npip install google-cloud-dlp==3.34.0\n```\n\nIf you are not pinning yet:\n\n```bash\npip install google-cloud-dlp\n```\n\nWith `uv`:\n\n```bash\nuv add google-cloud-dlp==3.34.0\n```\n\n## Authentication And Setup\n\nThe client uses Google Application Default Credentials (ADC). For local development, the most common setup is:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nIf you need explicit credentials from a service account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nIn deployed environments, prefer attached service accounts and default credentials instead of long-lived key files.\n\nBefore calling the client, make sure:\n\n- Enable the DLP API in the target project.\n- Build resource parents as `projects/PROJECT_ID/locations/LOCATION`.\n- Use `global` for common content inspection calls unless the workload must stay in a specific region.\n- Keep templates, job triggers, and jobs in the same location you reference in `parent`.\n- If you must override the endpoint, pass `client_options` when creating the client.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import dlp_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = dlp_v2.DlpServiceClient()\n```\n\nFor a regional or custom endpoint:\n\n```python\nimport os\n\nfrom google.cloud import dlp_v2\n\nclient = dlp_v2.DlpServiceClient(\n    client_options={\"api_endpoint\": os.environ[\"GOOGLE_CLOUD_DLP_ENDPOINT\"]}\n)\n```\n\nIf you need explicit credentials handling, build credentials with `google.auth` and pass them into the client constructor. In most codebases, ADC is the correct default.\n\n## Core Usage\n\n### Inspect Text For Sensitive Data\n\nUse `inspect_content` for inline text or other small payloads already in memory.\n\n```python\nfrom google.cloud import dlp_v2\n\nclient = dlp_v2.DlpServiceClient()\nparent = \"projects/my-project/locations/global\"\n\nrequest = {\n    \"parent\": parent,\n    \"item\": {\"value\": \"Contact alice@example.com or call 415-555-0100.\"},\n    \"inspect_config\": {\n        \"info_types\": [\n            {\"name\": \"EMAIL_ADDRESS\"},\n            {\"name\": \"PHONE_NUMBER\"},\n        ],\n        \"include_quote\": True,\n        \"min_likelihood\": dlp_v2.Likelihood.POSSIBLE,\n    },\n}\n\nresponse = client.inspect_content(request=request)\n\nfor finding in response.result.findings:\n    print(finding.info_type.name, finding.quote)\n```\n\nSet `include_quote` only when your downstream logic needs the matched text. If you only need counts or metadata, leave it off to reduce exposure of raw sensitive values.\n\n### De-Identify Text\n\nUse `deidentify_content` when you want the service to transform or mask findings instead of just reporting them.\n\n```python\nfrom google.cloud import dlp_v2\n\nclient = dlp_v2.DlpServiceClient()\nparent = \"projects/my-project/locations/global\"\n\nrequest = {\n    \"parent\": parent,\n    \"item\": {\"value\": \"Send the report to alice@example.com.\"},\n    \"inspect_config\": {\n        \"info_types\": [{\"name\": \"EMAIL_ADDRESS\"}],\n    },\n    \"deidentify_config\": {\n        \"info_type_transformations\": {\n            \"transformations\": [\n                {\n                    \"primitive_transformation\": {\n                        \"replace_with_info_type_config\": {}\n                    }\n                }\n            ]\n        }\n    },\n}\n\nresponse = client.deidentify_content(request=request)\nprint(response.item.value)\n```\n\nCommon alternatives are masking, character replacement, date shifting, bucketing, and crypto transforms. For structured transformation rules, keep the request in a dedicated helper so your inspect and de-identify configs stay consistent.\n\n### Re-Identify Previously Transformed Content\n\nUse `reidentify_content` when you previously applied a reversible transformation such as crypto-based tokenization and need to restore the original value.\n\n```python\ntransformed_value = \"TOKEN(3b6d...)\"\noriginal_inspect_config = {\n    \"info_types\": [{\"name\": \"PHONE_NUMBER\"}],\n}\noriginal_reidentify_config = {\n    # Use the same reversible transform family and key material\n    # that produced the tokenized value in the first place.\n}\n\nrequest = {\n    \"parent\": parent,\n    \"item\": {\"value\": transformed_value},\n    \"inspect_config\": original_inspect_config,\n    \"reidentify_config\": original_reidentify_config,\n}\n\nresponse = client.reidentify_content(request=request)\nprint(response.item.value)\n```\n\nKeep the inspect and crypto settings aligned with the original de-identification flow. Re-identification will fail or return unusable output if the transform configuration does not match.\n\n### Redact Sensitive Data From Images\n\nUse `redact_image` for image bytes that may contain faces, text, or embedded sensitive data.\n\n```python\nfrom google.cloud import dlp_v2\n\nclient = dlp_v2.DlpServiceClient()\nparent = \"projects/my-project/locations/global\"\n\nwith open(\"document.png\", \"rb\") as fh:\n    image_bytes = fh.read()\n\nrequest = {\n    \"parent\": parent,\n    \"byte_item\": {\n        \"type_\": dlp_v2.ByteContentItem.BytesType.IMAGE,\n        \"data\": image_bytes,\n    },\n    \"inspect_config\": {\n        \"info_types\": [{\"name\": \"EMAIL_ADDRESS\"}],\n    },\n    \"image_redaction_configs\": [\n        {\"info_type\": {\"name\": \"EMAIL_ADDRESS\"}}\n    ],\n}\n\nresponse = client.redact_image(request=request)\n\nwith open(\"document-redacted.png\", \"wb\") as fh:\n    fh.write(response.redacted_image)\n```\n\n### Async Client\n\nThe async client mirrors the sync surface and is useful when DLP is part of an async service:\n\n```python\nfrom google.cloud import dlp_v2\n\nasync_client = dlp_v2.DlpServiceAsyncClient()\nresponse = await async_client.inspect_content(request=request)\n```\n\n### Templates, Triggers, And Jobs\n\nFor repeated or large-scale workloads:\n\n- Use `create_inspect_template` and `update_inspect_template` to store reusable inspection rules.\n- Use `create_deidentify_template` for repeatable transformation configs.\n- Use `create_job_trigger` when you need scheduled or recurring scans.\n- Use `create_dlp_job` for longer-running scans against storage systems instead of sending large payloads with `inspect_content`.\n\nThe general pattern is:\n\n1. Create a template with the inspect or de-identify rules you want to reuse.\n2. Reference that template from a job or trigger.\n3. Poll job state with `get_dlp_job` or `list_dlp_jobs`.\n\n## Configuration Notes\n\n- `parent` is required on almost every call and must include a location.\n- `item` is for inline content already in memory.\n- `byte_item` is for raw bytes such as image content.\n- Storage scans use storage/job configuration objects instead of `item`.\n- Request dictionaries map to protobuf field names, and you can swap them for generated request objects when you want type-checked construction.\n- If a Python field name ends with `_`, that usually means the proto field name would otherwise collide with a Python keyword.\n\n## Common Pitfalls\n\n- Do not treat DLP as a generic regex engine. Prefer built-in info types and a deliberate `inspect_config`; add custom detectors only when the built-ins are not enough.\n- Do not use `inspect_content` for large files or repository-scale scans. Use DLP jobs for Cloud Storage and BigQuery workloads.\n- Do not forget the location segment in resource names. `projects/my-project` is not enough; use `projects/my-project/locations/global` or a regional location.\n- Do not mix locations for templates, job triggers, and jobs. Keep the `parent` location consistent across related resources.\n- Do not assume findings include the original matched text. Set `include_quote` explicitly when your downstream logic needs it.\n- Do not rely on static JSON key files if ADC from attached service accounts is available in the runtime environment.\n\n## Version-Sensitive Notes For `3.34.0`\n\nThe official docs root currently lists `3.34.0` as the latest published Python package reference. The changelog entry for `3.34.0` is dated `2026-01-27`.\n\n- `3.34.0` is not called out as a breaking release in the official changelog.\n- The changelog notes Python `3.14` support in this release series.\n- This release also includes routine dependency and documentation updates. If your environment pins older `protobuf` or related Google client libraries tightly, compare the changelog before upgrading.\n- The docs URL is the rolling `latest` branch. Re-check it if you revisit this package later because `latest` will move after `3.34.0`.\n\nIf your project is pinned to `3.34.0`, prefer:\n\n- request dictionaries passed as `request={...}` or the generated request types for each method\n- checking the changelog before copying setup or transport details from older blog posts\n- validating method arguments against the reference for the specific client class you are using\n\n## Official Sources\n\n- Python client reference: https://cloud.google.com/python/docs/reference/dlp/latest\n- `DlpServiceClient` reference: https://cloud.google.com/python/docs/reference/dlp/latest/google.cloud.dlp_v2.services.dlp_service.DlpServiceClient\n- Changelog: https://cloud.google.com/python/docs/reference/dlp/latest/changelog\n- PyPI package page: https://pypi.org/project/google-cloud-dlp/\n- Google Cloud authentication overview for ADC: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/dns/python/DOC.md",
    "content": "---\nname: dns\ndescription: \"Google Cloud DNS Python client for managed zones, record sets, and transactional DNS changes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.36.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,dns,gcp,networking,python\"\n---\n\n# Google Cloud DNS Python Client\n\n## Golden Rule\n\nUse `google-cloud-dns` with Application Default Credentials (ADC), pass `project=` explicitly when your environment can see more than one Google Cloud project, and treat DNS updates as transactional changes rather than in-place record edits.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-dns==0.36.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-dns==0.36.0\"\npoetry add \"google-cloud-dns==0.36.0\"\n```\n\n## Authentication And Project Setup\n\nThis library uses Google Cloud credentials, not API keys.\n\nPreferred auth order:\n\n1. Local development: `gcloud auth application-default login`\n2. Google Cloud runtime with an attached service account or workload identity\n3. `GOOGLE_APPLICATION_CREDENTIALS` pointing at a service-account key only when the first two are not available\n\nTypical setup for local development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nCloud DNS prerequisites the docs call out:\n\n- Enable the Cloud DNS API on the target project.\n- Enable billing on the project.\n- Grant DNS permissions such as `roles/dns.admin` for write operations.\n\nThe product docs also note narrower permissions for record and zone operations, including `dns.managedZones.*`, `dns.resourceRecordSets.*`, and `dns.changes.*`.\n\n## Initialize The Client\n\nBasic client:\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\n```\n\nExplicit service-account credentials:\n\n```python\nfrom google.cloud import dns\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = dns.Client(\n    project=\"your-project-id\",\n    credentials=credentials,\n)\n```\n\nCustom endpoint override when you need to set `api_endpoint` through `client_options`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import dns\n\nclient = dns.Client(\n    project=\"your-project-id\",\n    client_options=ClientOptions(api_endpoint=\"https://dns.googleapis.com\"),\n)\n```\n\nThe `Client` reference documents `project`, `credentials`, and `client_options` as the main public configuration knobs. `_http` exists, but the reference marks it as private.\n\n## Core Usage\n\n### List managed zones\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\n\nfor zone in client.list_zones():\n    print(zone.name, zone.dns_name)\n```\n\n### Create or bind a managed-zone handle\n\n`client.zone(...)` constructs a `ManagedZone` object bound to the client. If you omit `dns_name`, later `create()` calls fail.\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\n\nzone = client.zone(\n    \"example-com\",\n    dns_name=\"example.com.\",\n    description=\"Public zone for example.com\",\n)\n```\n\nFetch current server state when you need it:\n\n```python\nzone.reload()\nprint(zone.name_servers)\n```\n\n### Create a public managed zone\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\n\nzone = client.zone(\n    \"example-com\",\n    dns_name=\"example.com.\",\n    description=\"Public zone for example.com\",\n)\nzone.create()\n```\n\n### List record sets in a zone\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\nzone = client.zone(\"example-com\")\n\nfor record_set in zone.list_resource_record_sets():\n    print(record_set.name, record_set.record_type, record_set.ttl, record_set.rrdatas)\n```\n\n### Add a record with a change set\n\nThe client models record updates through `Changes`, which bundle additions and deletions and are submitted with `create()`.\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\nzone = client.zone(\"example-com\")\n\nrecord = zone.resource_record_set(\n    \"www.example.com.\",\n    \"A\",\n    300,\n    [\"203.0.113.10\"],\n)\n\nchange = zone.changes()\nchange.add_record_set(record)\nchange.create()\n```\n\n### Replace an existing record\n\nCloud DNS updates are not patch-style mutations on an existing record object. Replace a record by deleting the old record set and adding the new one in the same change.\n\n```python\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\nzone = client.zone(\"example-com\")\n\ncurrent = zone.resource_record_set(\n    \"www.example.com.\",\n    \"A\",\n    300,\n    [\"203.0.113.10\"],\n)\nreplacement = zone.resource_record_set(\n    \"www.example.com.\",\n    \"A\",\n    60,\n    [\"203.0.113.25\"],\n)\n\nchange = zone.changes()\nchange.delete_record_set(current)\nchange.add_record_set(replacement)\nchange.create()\n```\n\n### Poll for change completion\n\n```python\nimport time\n\nfrom google.cloud import dns\n\nclient = dns.Client(project=\"your-project-id\")\nzone = client.zone(\"example-com\")\n\nchange = zone.changes()\nchange.add_record_set(\n    zone.resource_record_set(\n        \"api.example.com.\",\n        \"A\",\n        60,\n        [\"203.0.113.40\"],\n    )\n)\nchange.create()\n\nwhile True:\n    change.reload()\n    if change.status == \"done\":\n        break\n    time.sleep(2)\n```\n\n## Configuration Notes\n\n- Prefer passing `project=` explicitly in scripts and automation. The client falls back to the default inferred environment, which is easy to misread in shared ADC setups.\n- Use fully qualified DNS names with trailing dots where Cloud DNS expects them, such as `example.com.` or `www.example.com.`.\n- `client.list_zones()` and `zone.list_resource_record_sets()` return iterators. Use iterator paging rather than manually carrying `page_token` unless you have a specific reason.\n- The reference exposes a small synchronous surface around `Client`, `ManagedZone`, `Changes`, and `ResourceRecordSet`.\n\n## Common Pitfalls\n\n- `client.zone(\"name\")` creates a local zone handle. It does not fetch remote state until you call methods such as `reload()`, `create()`, or listing methods.\n- `zone.create()` needs `dns_name`. If you only constructed the handle with a zone name, creation fails.\n- Do not assume you can update a record by mutating a local `ResourceRecordSet` object. Submit a `Changes` request.\n- Cloud DNS automatically manages apex `NS` and `SOA` records for public zones. The product docs say those records cannot be deleted through the API.\n- User ADC against the wrong active project is a common cause of confusing permission or not-found errors.\n- For private, forwarding, peering, and other advanced zone types, verify the product docs before assuming the high-level Python client exposes a first-class helper for the exact workflow you need. This is an inference from the current reference coverage.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.36.0` as the latest release for `google-cloud-dns`.\n- The Cloud Python docs root at `https://cloud.google.com/python/docs/reference/dns/latest` is the correct canonical reference entry point, but the current module and class pages under `latest` still render as `0.35.1`.\n- Because of that upstream docs drift, validate method signatures against the live reference pages before relying on stale blog posts or old snippets.\n- If you need package-specific release deltas for `0.36.0`, check the source repository history in addition to the reference pages, because the rendered API docs lag the current PyPI release.\n\n## Official Sources\n\n- Python reference root: https://cloud.google.com/python/docs/reference/dns/latest\n- `Client` reference: https://docs.cloud.google.com/python/docs/reference/dns/latest/google.cloud.dns.client.Client\n- `ManagedZone` reference: https://docs.cloud.google.com/python/docs/reference/dns/latest/google.cloud.dns.zone.ManagedZone\n- `Changes` reference: https://docs.cloud.google.com/python/docs/reference/dns/latest/google.cloud.dns.changes.Changes\n- Cloud DNS zone operations: https://docs.cloud.google.com/dns/docs/zones\n- Cloud DNS record-set operations: https://docs.cloud.google.com/dns/docs/records\n- Cloud DNS IAM roles: https://docs.cloud.google.com/iam/docs/roles-permissions/dns\n- PyPI package page: https://pypi.org/project/google-cloud-dns/\n- Source repository: https://github.com/googleapis/python-dns\n"
  },
  {
    "path": "content/google/docs/documentai/javascript/DOC.md",
    "content": "---\nname: documentai\ndescription: \"Google Cloud Document AI Node.js client for ADC auth, regional processor calls, local document parsing, and GCS batch processing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,documentai,gcp,ocr,forms,javascript,nodejs\"\n---\n\n# `@google-cloud/documentai` JavaScript Package Guide\n\nUse `@google-cloud/documentai` when your Node.js app needs to send PDFs or image files to a Google Cloud Document AI processor and read OCR or structured extraction results such as entities, form fields, tables, and page text.\n\n## Golden Rule\n\n- Authenticate with Google Cloud Application Default Credentials (ADC), not an API key.\n- Set the client `apiEndpoint` to the same region as the processor, usually `us-documentai.googleapis.com` or `eu-documentai.googleapis.com`.\n- Pass the full processor or processor-version resource name, not only the processor ID.\n- Use `processDocument()` for one document at a time and `batchProcessDocuments()` when the input and output live in Cloud Storage.\n- Send a MIME type that matches the real file, such as `application/pdf`, `image/png`, `image/jpeg`, or `image/tiff`.\n\nThis guide covers `9.5.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/documentai@9.5.0\n```\n\n## Authentication And Project Setup\n\nBefore making requests, make sure all of the following are true:\n\n1. You have a Google Cloud project.\n2. Billing is enabled for that project.\n3. The Document AI API is enabled.\n4. You already have a processor in the region your app will call.\n5. ADC is configured for the identity your app will run as.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable documentai.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us\"\n```\n\nIf you must use a service account key file outside Google Cloud:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nPrefer attached service-account credentials on Google Cloud over distributing JSON key files.\n\n## Initialize The Client\n\nDocument AI is regional. Build the endpoint from the processor location and reuse the client instead of constructing a new client for every request.\n\n```javascript\nconst {v1} = require('@google-cloud/documentai');\n\nfunction createDocumentAiClient(location = process.env.GOOGLE_CLOUD_LOCATION || 'us') {\n  return new v1.DocumentProcessorServiceClient({\n    apiEndpoint: `${location}-documentai.googleapis.com`,\n  });\n}\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/documentai');\n\nconst location = process.env.GOOGLE_CLOUD_LOCATION || 'us';\n\nconst client = new v1.DocumentProcessorServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n  apiEndpoint: `${location}-documentai.googleapis.com`,\n});\n```\n\n## Process One Local Document\n\nUse `processDocument()` for synchronous processing of one document at a time.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v1} = require('@google-cloud/documentai');\n\nasync function processLocalDocument({\n  projectId = process.env.GOOGLE_CLOUD_PROJECT,\n  location = process.env.GOOGLE_CLOUD_LOCATION || 'us',\n  processorId,\n  filePath,\n  mimeType = 'application/pdf',\n}) {\n  const client = new v1.DocumentProcessorServiceClient({\n    apiEndpoint: `${location}-documentai.googleapis.com`,\n  });\n\n  const name = `projects/${projectId}/locations/${location}/processors/${processorId}`;\n  const fileBytes = await fs.readFile(filePath);\n\n  const [result] = await client.processDocument({\n    name,\n    rawDocument: {\n      content: Buffer.from(fileBytes).toString('base64'),\n      mimeType,\n    },\n  });\n\n  const document = result.document;\n\n  console.log(document?.text ?? '');\n\n  for (const entity of document?.entities ?? []) {\n    console.log(entity.type, entity.mentionText, entity.confidence);\n  }\n\n  return document;\n}\n\nprocessLocalDocument({\n  processorId: '1234567890abcdef',\n  filePath: 'invoice.pdf',\n}).catch(console.error);\n```\n\n`document.text` holds the full extracted text. The structured fields you get back depend on the processor type, so inspect `document.entities`, `document.pages`, `document.pages?.[0]?.formFields`, and `document.pages?.[0]?.tables` only when that processor is expected to produce them.\n\n## Call A Specific Processor Version\n\nIf your application must pin an explicitly deployed processor version, pass the processor-version resource name instead of the processor resource name.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v1} = require('@google-cloud/documentai');\n\nasync function processWithProcessorVersion({\n  projectId = process.env.GOOGLE_CLOUD_PROJECT,\n  location = process.env.GOOGLE_CLOUD_LOCATION || 'us',\n  processorId,\n  processorVersionId,\n  filePath,\n  mimeType = 'application/pdf',\n}) {\n  const client = new v1.DocumentProcessorServiceClient({\n    apiEndpoint: `${location}-documentai.googleapis.com`,\n  });\n\n  const name = `projects/${projectId}/locations/${location}/processors/${processorId}/processorVersions/${processorVersionId}`;\n  const fileBytes = await fs.readFile(filePath);\n\n  const [result] = await client.processDocument({\n    name,\n    rawDocument: {\n      content: Buffer.from(fileBytes).toString('base64'),\n      mimeType,\n    },\n  });\n\n  return result.document;\n}\n```\n\nUse this pattern when the processor has multiple deployed versions and your code must stay pinned to one of them.\n\n## Batch Process Documents From Cloud Storage\n\nUse `batchProcessDocuments()` for larger jobs or when your input and output are already in Cloud Storage. This is a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/documentai');\n\nasync function batchProcessDocuments({\n  projectId = process.env.GOOGLE_CLOUD_PROJECT,\n  location = process.env.GOOGLE_CLOUD_LOCATION || 'us',\n  processorId,\n  inputUri,\n  outputUri,\n  mimeType = 'application/pdf',\n}) {\n  const client = new v1.DocumentProcessorServiceClient({\n    apiEndpoint: `${location}-documentai.googleapis.com`,\n  });\n\n  const name = `projects/${projectId}/locations/${location}/processors/${processorId}`;\n\n  const [operation] = await client.batchProcessDocuments({\n    name,\n    inputDocuments: {\n      gcsDocuments: {\n        documents: [\n          {\n            gcsUri: inputUri,\n            mimeType,\n          },\n        ],\n      },\n    },\n    documentOutputConfig: {\n      gcsOutputConfig: {\n        gcsUri: outputUri,\n      },\n    },\n  });\n\n  await operation.promise();\n  console.log('Batch processing complete');\n}\n\nbatchProcessDocuments({\n  processorId: '1234567890abcdef',\n  inputUri: 'gs://my-input-bucket/forms/form-001.pdf',\n  outputUri: 'gs://my-output-bucket/documentai-results/',\n}).catch(console.error);\n```\n\nImportant behavior:\n\n- The long-running operation completes when processing is done, but the parsed documents are written to the GCS output prefix you provide.\n- Your calling identity needs Cloud Storage access for both the input and output buckets.\n- Do not expect the parsed JSON results to come back inline in the API response.\n\n## List Processors In A Region\n\nUse `listProcessors()` when the app needs to discover existing processors instead of hardcoding one.\n\n```javascript\nconst {v1} = require('@google-cloud/documentai');\n\nasync function listProcessors(\n  projectId = process.env.GOOGLE_CLOUD_PROJECT,\n  location = process.env.GOOGLE_CLOUD_LOCATION || 'us'\n) {\n  const client = new v1.DocumentProcessorServiceClient({\n    apiEndpoint: `${location}-documentai.googleapis.com`,\n  });\n\n  const parent = `projects/${projectId}/locations/${location}`;\n  const [processors] = await client.listProcessors({parent});\n\n  return processors.map(processor => ({\n    name: processor.name,\n    displayName: processor.displayName,\n    type: processor.type,\n  }));\n}\n```\n\nReuse the returned `name` values from list calls if you want to avoid rebuilding resource names manually later.\n\n## Common Pitfalls\n\n- Region mismatch: a processor in `us` will not work if the client endpoint points at `eu-documentai.googleapis.com`.\n- Wrong `name` field: `processDocument()` expects the full processor or processor-version resource name, not only `processorId`.\n- Wrong MIME type: keep the request `mimeType` aligned with the real file format.\n- Batch output assumptions: `batchProcessDocuments()` writes results to Cloud Storage; it does not return parsed documents inline.\n- Missing Storage permissions: GCS-backed workflows need bucket access in addition to Document AI permissions.\n- Per-request client creation: create the client once and reuse it in hot paths.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/documentai` version `9.5.0`.\n- The maintainer reference URL is a rolling `latest` docs tree. If your project pins a materially older or newer package version, verify request fields and helper names against the installed package and the matching reference pages.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/documentai/latest`\n- Document processing client-library guide: `https://cloud.google.com/document-ai/docs/process-documents-client-libraries`\n- Process document sample: `https://cloud.google.com/document-ai/docs/samples/documentai-process-document`\n- Batch process sample: `https://cloud.google.com/document-ai/docs/samples/documentai-batch-process-document`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/documentai`\n"
  },
  {
    "path": "content/google/docs/documentai/python/DOC.md",
    "content": "---\nname: documentai\ndescription: \"Google Cloud Document AI client for Python with ADC auth, regional endpoints, processor workflows, and batch GCS processing\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,documentai,ocr,gcp,python,client\"\n---\n\n# google-cloud-documentai Python Package Guide\n\n## What It Is\n\n`google-cloud-documentai` is the official Google Cloud client library for Document AI in Python. Use it when you need to:\n\n- send PDFs or images to a Document AI processor\n- extract text, entities, form fields, tables, and page layout\n- batch-process files from Google Cloud Storage\n- manage processor discovery and processor-version resource names from Python\n\nThis package is only the client. Your code still needs:\n\n- a Google Cloud project\n- a Document AI processor in the correct region\n- Application Default Credentials or another supported Google auth flow\n\n## Version Covered\n\n- Ecosystem: `pypi`\n- Package: `google-cloud-documentai`\n- Version covered: `3.11.0`\n- Import path used in this doc: `from google.cloud import documentai`\n- Docs URL: `https://cloud.google.com/python/docs/reference/documentai/latest`\n- Stable versioned reference used for this entry: `https://cloud.google.com/python/docs/reference/documentai/3.11.0`\n- Registry URL: `https://pypi.org/project/google-cloud-documentai/`\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-documentai==3.11.0\"\n```\n\nFor local development, use Application Default Credentials:\n\n```bash\ngcloud auth application-default login\n```\n\nFor a service-account key outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n```\n\n## Required Setup\n\nDocument AI is regional. Before writing code, confirm all of these line up:\n\n- `project_id`\n- `location`, usually `us` or `eu`\n- `processor_id`\n- the processor resource name or processor-version resource name you will call\n- a MIME type that matches the actual file, such as `application/pdf`, `image/png`, `image/jpeg`, or `image/tiff`\n\nThe client endpoint must match the processor location:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import documentai\n\nlocation = \"us\"\n\nclient = documentai.DocumentProcessorServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-documentai.googleapis.com\"\n    )\n)\n```\n\nIf the processor is in `eu`, use `eu-documentai.googleapis.com`.\n\n## Quick Start: Process One Local Document\n\nUse `process_document` for synchronous processing of one document at a time.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import documentai\n\nproject_id = \"my-project\"\nlocation = \"us\"\nprocessor_id = \"1234567890abcdef\"\nfile_path = \"invoice.pdf\"\nmime_type = \"application/pdf\"\n\nclient = documentai.DocumentProcessorServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-documentai.googleapis.com\"\n    )\n)\n\nname = client.processor_path(project_id, location, processor_id)\n\nwith open(file_path, \"rb\") as fh:\n    request = documentai.ProcessRequest(\n        name=name,\n        raw_document=documentai.RawDocument(\n            content=fh.read(),\n            mime_type=mime_type,\n        ),\n    )\n\nresult = client.process_document(request=request)\ndocument = result.document\n\nprint(document.text)\n\nfor entity in document.entities:\n    print(entity.type_, entity.mention_text, entity.confidence)\n```\n\nUse `document.text` for full OCR output. For structured extraction, inspect `document.entities`, `document.pages`, `document.pages[n].form_fields`, and `document.pages[n].tables`.\n\n## When To Call A Processor Version\n\nSome workflows need a specific processor version instead of the default processor target. In that case, pass the processor-version resource name as `name`.\n\n```python\nprocessor_version_name = (\n    f\"projects/{project_id}/locations/{location}/\"\n    f\"processors/{processor_id}/processorVersions/{processor_version_id}\"\n)\n\nrequest = documentai.ProcessRequest(\n    name=processor_version_name,\n    raw_document=documentai.RawDocument(\n        content=file_bytes,\n        mime_type=\"application/pdf\",\n    ),\n)\n```\n\nUse this pattern when the processor has multiple deployed versions and your application must pin one explicitly.\n\n## Batch Processing From Google Cloud Storage\n\nUse `batch_process_documents` for larger jobs or when the input and output already live in GCS. This is a long-running operation.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import documentai\n\nproject_id = \"my-project\"\nlocation = \"us\"\nprocessor_id = \"1234567890abcdef\"\n\ngcs_input_uri = \"gs://my-input-bucket/forms/form-001.pdf\"\ngcs_output_uri = \"gs://my-output-bucket/documentai-results/\"\n\nclient = documentai.DocumentProcessorServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-documentai.googleapis.com\"\n    )\n)\n\nname = client.processor_path(project_id, location, processor_id)\n\ngcs_document = documentai.GcsDocument(\n    gcs_uri=gcs_input_uri,\n    mime_type=\"application/pdf\",\n)\n\nrequest = documentai.BatchProcessRequest(\n    name=name,\n    input_documents=documentai.BatchDocumentsInputConfig(\n        gcs_documents=documentai.GcsDocuments(documents=[gcs_document])\n    ),\n    document_output_config=documentai.DocumentOutputConfig(\n        gcs_output_config=documentai.DocumentOutputConfig.GcsOutputConfig(\n            gcs_uri=gcs_output_uri\n        )\n    ),\n)\n\noperation = client.batch_process_documents(request=request)\noperation.result(timeout=900)\n\nprint(\"Batch processing complete\")\n```\n\nImportant behavior:\n\n- the response does not return parsed documents inline\n- Document AI writes JSON output files under the GCS prefix you provide\n- your app must read those output objects afterward if it needs the structured results\n\n## Listing Processors\n\nUse `list_processors` when the app needs to discover an existing processor rather than hardcode one.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import documentai\n\nproject_id = \"my-project\"\nlocation = \"us\"\n\nclient = documentai.DocumentProcessorServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-documentai.googleapis.com\"\n    )\n)\n\nparent = client.common_location_path(project_id, location)\n\nfor processor in client.list_processors(parent=parent):\n    print(processor.name)\n    print(processor.display_name)\n    print(processor.type_)\n```\n\nIf you create processors programmatically, first list processor types in the same region and use the returned type name for creation.\n\n## Auth And Configuration\n\n### Preferred Auth\n\nUse Application Default Credentials unless you have a specific reason not to.\n\nCommon patterns:\n\n- local development: `gcloud auth application-default login`\n- Google Cloud runtime: attach a service account to the workload\n- non-Google runtime: set `GOOGLE_APPLICATION_CREDENTIALS`\n\nDo not embed service-account JSON in source code.\n\n### Endpoint Selection\n\nAlways set the endpoint from `location`:\n\n```python\napi_endpoint = f\"{location}-documentai.googleapis.com\"\n```\n\nThe processor resource name and the endpoint must point to the same region.\n\n### Timeouts And Retries\n\nEvery RPC accepts the standard Google API Core call options:\n\n```python\nresult = client.process_document(\n    request=request,\n    timeout=120,\n)\n```\n\nUse explicit `timeout` values for large documents or slow networks. Only override retries when you have a concrete failure mode to address.\n\n## Common Pitfalls\n\n- Region mismatch: `us` processor plus `eu-documentai.googleapis.com` fails.\n- Wrong resource name: `name` must be the full processor or processor-version resource, not just the processor ID.\n- Wrong MIME type: Document AI validates the actual file type.\n- Batch output assumptions: `batch_process_documents` writes results to GCS; it does not hand back parsed JSON in memory.\n- Stale examples: older 2.x snippets may not match the 3.x request shapes.\n- Rolling docs drift: the source URL uses Google Cloud's `latest` reference, which can lag behind the current PyPI package version.\n\n## Version-Sensitive Notes\n\n- PyPI shows `3.11.0` as the current release for `google-cloud-documentai`.\n- Use the versioned reference at `https://cloud.google.com/python/docs/reference/documentai/3.11.0` when you need a stable package-specific API surface.\n- The official upgrading guide for `3.0.0` documents breaking request and method changes from older releases. If you are adapting 2.x code, review that guide before copying request construction verbatim.\n- Google Cloud product guides sometimes use `from google.cloud import documentai_v1` while other samples use `from google.cloud import documentai`. Both refer to the v1 client surface; keep the import style consistent within one codebase.\n\n## Official Sources Used\n\n- Google Cloud Python reference, versioned: `https://cloud.google.com/python/docs/reference/documentai/3.11.0`\n- Google Cloud Python reference, rolling: `https://cloud.google.com/python/docs/reference/documentai/latest`\n- Changelog: `https://cloud.google.com/python/docs/reference/documentai/3.11.0/changelog`\n- Upgrading guide: `https://cloud.google.com/python/docs/reference/documentai/3.11.0/upgrading`\n- Client-library processing guide: `https://cloud.google.com/document-ai/docs/process-documents-client-libraries`\n- Batch processing sample: `https://cloud.google.com/document-ai/docs/samples/documentai-batch-process-document`\n- ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- PyPI package page: `https://pypi.org/project/google-cloud-documentai/`\n"
  },
  {
    "path": "content/google/docs/error-reporting/javascript/DOC.md",
    "content": "---\nname: error-reporting\ndescription: \"Google Cloud Error Reporting Node.js client for reporting handled exceptions and request failures from JavaScript services\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,error-reporting,observability,exceptions,javascript,nodejs\"\n---\n\n# `@google-cloud/error-reporting` JavaScript Package Guide\n\nUse `@google-cloud/error-reporting` when a Node.js service needs to send handled exceptions or request-scoped failures to Google Cloud Error Reporting.\n\nIf your runtime already forwards uncaught exceptions into Google Cloud automatically, use this package for handled errors or custom service grouping instead of reporting the same crash path twice.\n\n## Golden Rule\n\n- Create one process-wide `ErrorReporting` client.\n- Set `serviceContext.service` to a stable service name.\n- Set `serviceContext.version` from a deploy identifier such as a release tag or git SHA.\n- Use Application Default Credentials (ADC) or `GOOGLE_APPLICATION_CREDENTIALS`.\n- Report real `Error` objects so the event includes a JavaScript stack trace.\n- Pass the HTTP request when reporting request failures so Error Reporting can attach request context.\n\nThis guide covers `3.0.5`.\n\n## Install\n\n```bash\nnpm install @google-cloud/error-reporting@3.0.5\n```\n\n## Authentication And Setup\n\nBefore sending events:\n\n1. Enable the Error Reporting API in the target project.\n2. Run with credentials that can write error events.\n3. Decide the `service` and `version` values you want to appear in Google Cloud.\n\nEnable the API in the project that will receive the events:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable clouderrorreporting.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nIf you must use a service account key file explicitly:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nIn production on Google Cloud, prefer an attached service account or workload identity over distributing long-lived JSON keys.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {ErrorReporting} = require('@google-cloud/error-reporting');\n\nconst errors = new ErrorReporting({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  serviceContext: {\n    service: 'checkout-api',\n    version: process.env.K_REVISION || process.env.APP_VERSION || 'dev',\n  },\n});\n```\n\nES modules:\n\n```javascript\nimport {ErrorReporting} from '@google-cloud/error-reporting';\n\nconst errors = new ErrorReporting({\n  serviceContext: {\n    service: 'checkout-api',\n    version: process.env.K_REVISION || process.env.APP_VERSION || 'dev',\n  },\n});\n```\n\nIf project detection is wrong outside Google Cloud, pass `projectId` explicitly or set `GOOGLE_CLOUD_PROJECT`.\n\n## Core Workflows\n\n### Report A Caught Exception\n\nReport the original `Error` and then decide whether your code should rethrow it:\n\n```javascript\nconst {ErrorReporting} = require('@google-cloud/error-reporting');\n\nconst errors = new ErrorReporting({\n  serviceContext: {\n    service: 'billing-worker',\n    version: process.env.APP_VERSION || 'dev',\n  },\n});\n\nasync function chargeCustomer(customer) {\n  try {\n    await billingClient.charge(customer);\n  } catch (error) {\n    errors.report(error);\n    throw error;\n  }\n}\n```\n\n### Report A Handled Background Error\n\nIf you want an Error Reporting event for a failure your code handles locally, create an `Error` so the event includes a stack trace:\n\n```javascript\nconst {ErrorReporting} = require('@google-cloud/error-reporting');\n\nconst errors = new ErrorReporting({\n  serviceContext: {\n    service: 'job-runner',\n    version: process.env.APP_VERSION || 'dev',\n  },\n});\n\nasync function processJob(job) {\n  try {\n    await runJob(job);\n  } catch (cause) {\n    const error = cause instanceof Error\n      ? cause\n      : new Error(`job ${job.id} failed: ${String(cause)}`);\n\n    errors.report(error);\n    return {ok: false};\n  }\n}\n```\n\n### Report An Express Request Failure With HTTP Context\n\nPass the current `req` object so Error Reporting can associate the event with the request URL, method, referrer, and user agent.\n\n```javascript\nconst express = require('express');\nconst {ErrorReporting} = require('@google-cloud/error-reporting');\n\nconst app = express();\nconst errors = new ErrorReporting({\n  serviceContext: {\n    service: 'frontend',\n    version: process.env.K_REVISION || 'dev',\n  },\n});\n\napp.get('/checkout', async (req, res, next) => {\n  try {\n    await runCheckout(req.query.cartId);\n    res.json({ok: true});\n  } catch (error) {\n    next(error);\n  }\n});\n\napp.use((error, req, res, next) => {\n  errors.report(error, req);\n  res.status(500).json({error: 'internal'});\n});\n```\n\nPut the error-handling middleware after your routes so it only runs for actual request failures.\n\n## Common Pitfalls\n\n- Do not rotate `serviceContext.service` on every deploy; keep the service name stable and move release information into `serviceContext.version`.\n- Do not rely on implicit project detection everywhere; set `GOOGLE_CLOUD_PROJECT` or `projectId` when running outside Google Cloud.\n- Do not report arbitrary plain objects when you can report an `Error`; Error Reporting groups JavaScript events best when the stack trace comes from `error.stack`.\n- Do not double-report the same uncaught exception path if your Google Cloud runtime already surfaces it automatically.\n- Do not place Express error middleware before routes; the request context example only works when the handler runs after routing.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/error-reporting` version `3.0.5`.\n- Error Reporting groups events using service context, so `serviceContext.service` and `serviceContext.version` are part of the setup, not optional polish.\n- The underlying Error Reporting API expects a stack trace or an explicit report location. In JavaScript, reporting real `Error` instances is the safest path.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/error-reporting/latest`\n- Google Cloud Error Reporting product docs: `https://cloud.google.com/error-reporting/`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/error-reporting`\n"
  },
  {
    "path": "content/google/docs/error-reporting/python/DOC.md",
    "content": "---\nname: error-reporting\ndescription: \"Google Cloud Error Reporting Python client library for reporting handled exceptions and custom error events\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,error-reporting,observability,exceptions,logging\"\n---\n\n# Google Cloud Error Reporting Python Client\n\n## Golden Rule\n\nUse `google-cloud-error-reporting` for Python code that needs to report handled exceptions or custom error events into Google Cloud Error Reporting.\n\n- PyPI package: `google-cloud-error-reporting`\n- Common import: `from google.cloud import error_reporting`\n- Covered version: `1.14.0`\n\nIf your app already runs on managed Google Cloud platforms that automatically surface uncaught exceptions, do not add this client just to duplicate those same unhandled errors. Use the library when you need explicit reporting, custom grouping metadata, or reporting from environments that are not auto-integrated.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-error-reporting==1.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-error-reporting==1.14.0\"\npoetry add \"google-cloud-error-reporting==1.14.0\"\n```\n\n## Project Setup And Auth\n\nBefore the client can send events:\n\n1. Enable the Error Reporting API for the target Google Cloud project.\n2. Use credentials that can write error events, typically `roles/errorreporting.writer`.\n3. Prefer Application Default Credentials (ADC).\n\nLocal development with user credentials:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nService account based setup:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nThe client will usually infer the project from ADC. Set `GOOGLE_CLOUD_PROJECT` or pass `project=` if the runtime cannot infer it correctly.\n\n## Initialize The Client\n\nMinimal setup:\n\n```python\nfrom google.cloud import error_reporting\n\nclient = error_reporting.Client()\n```\n\nExplicit project and service grouping:\n\n```python\nfrom google.cloud import error_reporting\n\nclient = error_reporting.Client(\n    project=\"my-project\",\n    service=\"checkout-api\",\n    version=\"2026.03.12\",\n)\n```\n\n`service` and `version` affect how errors are grouped and displayed in Error Reporting. Set them intentionally for services with multiple deploys or components.\n\n## Core Usage\n\n### Report the current exception\n\nUse `report_exception()` inside an `except` block:\n\n```python\nfrom google.cloud import error_reporting\n\nclient = error_reporting.Client(service=\"checkout-api\", version=\"2026.03.12\")\n\ntry:\n    1 / 0\nexcept ZeroDivisionError:\n    client.report_exception()\n    raise\n```\n\n### Report a handled error message\n\nUse `report()` when you want an Error Reporting event without re-raising:\n\n```python\nfrom google.cloud import error_reporting\n\nclient = error_reporting.Client(service=\"worker\")\n\ntry:\n    process_job()\nexcept TimeoutError as exc:\n    client.report(f\"job processing timed out: {exc}\")\n```\n\n### Attach user context\n\nBoth reporting methods support a `user` identifier. Use a stable internal identifier, not raw secrets:\n\n```python\ntry:\n    charge_customer(customer)\nexcept Exception:\n    client.report_exception(user=customer.id)\n    raise\n```\n\n## Flask Request Context\n\nFor Flask apps, use the helper that converts the current request into the HTTP context Error Reporting expects:\n\n```python\nfrom flask import Flask, request\nfrom google.cloud import error_reporting\nfrom google.cloud.error_reporting import build_flask_context\n\napp = Flask(__name__)\nclient = error_reporting.Client(service=\"frontend\")\n\n@app.post(\"/checkout\")\ndef checkout():\n    try:\n        run_checkout(request.json)\n        return {\"ok\": True}\n    except Exception:\n        client.report_exception(\n            http_context=build_flask_context(request),\n            user=request.headers.get(\"X-User-Id\"),\n        )\n        raise\n```\n\nIf you are not using Flask, provide the HTTP metadata expected by the library rather than trying to fake a Flask request object.\n\n## Multiprocessing\n\nThe library has dedicated multiprocessing guidance because clients created before `fork()` are a bad fit for worker processes. Create the client in each worker after process startup:\n\n```python\nfrom multiprocessing import Pool\nfrom google.cloud import error_reporting\n\nclient = None\n\ndef init_worker():\n    global client\n    client = error_reporting.Client(service=\"batch-worker\")\n\ndef handle_job(job):\n    try:\n        process_job(job)\n    except Exception:\n        client.report_exception()\n        raise\n\nwith Pool(initializer=init_worker) as pool:\n    pool.map(handle_job, jobs)\n```\n\nDo not construct one global client in the parent process and share it across forked workers.\n\n## Common Pitfalls\n\n- Package and import names differ: install `google-cloud-error-reporting`, import `google.cloud.error_reporting`.\n- Enabling the library is not enough by itself. The target project still needs the Error Reporting API enabled and a credential with write access.\n- If `Client()` reports to the wrong project, pass `project=` explicitly or set `GOOGLE_CLOUD_PROJECT`.\n- `report_exception()` should run inside an active exception handler. Use `report()` for handled, non-exception events.\n- Set `service` and `version` deliberately. If you omit them, grouping in the Error Reporting UI is less useful for multi-service systems.\n- On Cloud Run, App Engine, and similar managed environments, uncaught exceptions may already appear through integrated logging. Avoid double-reporting the same failure path.\n- In multiprocess workers, initialize the client after the worker starts.\n\n## Version-Sensitive Notes\n\n- PyPI lists `1.14.0` as the current package release used for this doc.\n- The Google reference site is published under a `latest` docs root, so use PyPI for exact package-version pinning and release verification.\n- Older search results for this package referenced stale version information. As of `2026-03-12`, the earlier version reference `1.14.0` matches the live PyPI package page.\n\n## Official Links\n\n- Python client reference: https://cloud.google.com/python/docs/reference/clouderrorreporting/latest\n- Usage guide: https://cloud.google.com/python/docs/reference/clouderrorreporting/latest/usage\n- API reference for `Client`: https://cloud.google.com/python/docs/reference/clouderrorreporting/latest/google.cloud.error_reporting.client.Client\n- Multiprocessing guidance: https://cloud.google.com/python/docs/reference/clouderrorreporting/latest/multiprocessing\n- Product setup guide: https://cloud.google.com/error-reporting/docs/setup/python\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- PyPI: https://pypi.org/project/google-cloud-error-reporting/\n"
  },
  {
    "path": "content/google/docs/essential-contacts/python/DOC.md",
    "content": "---\nname: essential-contacts\ndescription: \"Google Cloud Essential Contacts Python client for managing billing, security, legal, and technical notification contacts on organizations, folders, and projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,essential-contacts,contacts,notifications,python\"\n---\n\n# Google Cloud Essential Contacts Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-essential-contacts` with `from google.cloud import essential_contacts_v1`, authenticate with Application Default Credentials (ADC), and pass full Google Cloud resource names such as `projects/my-project-id`, `folders/123456789012`, or `organizations/123456789012`.\n\nThis library manages the contact records Google Cloud services use for billing, legal, product update, security, suspension, and technical notifications. It does not replace service-specific alerting systems such as Cloud Monitoring notification channels.\n\n## Install\n\nPin the package version if you want your environment to match this guide exactly:\n\n```bash\npython -m pip install \"google-cloud-essential-contacts==1.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-essential-contacts==1.12.0\"\npoetry add \"google-cloud-essential-contacts==1.12.0\"\n```\n\nPyPI lists Python `>=3.7` for `1.12.0`.\n\n## Authentication And Setup\n\nRecommended local setup:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID\n```\n\nIf you must provide a service account key explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/abs/path/service-account.json\nexport GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID\n```\n\nThe caller also needs IAM permissions to read or manage Essential Contacts on the target organization, folder, or project.\n\n## Initialize The Client\n\nUse a project, folder, or organization resource name as the parent:\n\n```python\nimport os\n\nfrom google.cloud import essential_contacts_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nparent = f\"projects/{project_id}\"\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n```\n\nExplicit credentials:\n\n```python\nimport os\n\nfrom google.cloud import essential_contacts_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nclient = essential_contacts_v1.EssentialContactsServiceClient(\n    credentials=credentials,\n)\n```\n\nIf your application is already async, the package also exposes `EssentialContactsServiceAsyncClient`.\n\n## Core Usage\n\n### Create A Contact\n\n`language_tag` is required. Notification subscriptions use the `NotificationCategory` enum.\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\nparent = \"projects/my-project-id\"\n\ncreated = client.create_contact(\n    request=essential_contacts_v1.CreateContactRequest(\n        parent=parent,\n        contact=essential_contacts_v1.Contact(\n            email=\"sre@example.com\",\n            language_tag=\"en-US\",\n            notification_category_subscriptions=[\n                essential_contacts_v1.NotificationCategory.SECURITY,\n                essential_contacts_v1.NotificationCategory.TECHNICAL,\n                essential_contacts_v1.NotificationCategory.TECHNICAL_INCIDENTS,\n            ],\n        ),\n    )\n)\n\nprint(created.name)\n```\n\nCommon categories include `BILLING`, `LEGAL`, `PRODUCT_UPDATES`, `SECURITY`, `SUSPENSION`, `TECHNICAL`, and `TECHNICAL_INCIDENTS`.\n\n### List Contacts Defined Directly On One Resource\n\n`list_contacts()` only returns contacts attached to that exact project, folder, or organization.\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\nfor contact in client.list_contacts(parent=\"projects/my-project-id\"):\n    print(contact.name)\n    print(contact.email)\n    print(list(contact.notification_category_subscriptions))\n```\n\n### Compute Effective Contacts For A Category\n\n`compute_contacts()` includes inherited contacts from parent folders and organizations. Use it when you need to know who will actually receive a notification.\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\npager = client.compute_contacts(\n    request=essential_contacts_v1.ComputeContactsRequest(\n        parent=\"projects/my-project-id\",\n        notification_categories=[\n            essential_contacts_v1.NotificationCategory.SECURITY,\n            essential_contacts_v1.NotificationCategory.TECHNICAL_INCIDENTS,\n        ],\n    )\n)\n\nfor contact in pager:\n    print(contact.name, contact.email)\n```\n\n### Read One Contact\n\nUse the contact resource name returned from `create_contact()` or `list_contacts()`:\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\ncontact = client.get_contact(\n    request=essential_contacts_v1.GetContactRequest(\n        name=\"projects/my-project-id/contacts/CONTACT_ID\"\n    )\n)\n\nprint(contact.email)\nprint(contact.language_tag)\n```\n\n### Update Notification Categories Or Language\n\nUse a protobuf `FieldMask`. The email address is immutable and cannot be updated.\n\n```python\nfrom google.cloud import essential_contacts_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\nupdated = client.update_contact(\n    request=essential_contacts_v1.UpdateContactRequest(\n        contact=essential_contacts_v1.Contact(\n            name=\"projects/my-project-id/contacts/CONTACT_ID\",\n            email=\"sre@example.com\",\n            language_tag=\"ja\",\n            notification_category_subscriptions=[\n                essential_contacts_v1.NotificationCategory.SECURITY,\n                essential_contacts_v1.NotificationCategory.PRODUCT_UPDATES,\n            ],\n        ),\n        update_mask=FieldMask(\n            paths=[\n                \"language_tag\",\n                \"notification_category_subscriptions\",\n            ]\n        ),\n    )\n)\n\nprint(updated.language_tag)\n```\n\n### Send A Test Message\n\nUse this to verify that the selected contacts for one category can receive an Essential Contacts message.\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\nclient.send_test_message(\n    request=essential_contacts_v1.SendTestMessageRequest(\n        contacts=[\n            \"projects/my-project-id/contacts/CONTACT_ID\",\n        ],\n        resource=\"projects/my-project-id\",\n        notification_category=essential_contacts_v1.NotificationCategory.SECURITY,\n    )\n)\n```\n\n### Delete A Contact\n\n```python\nfrom google.cloud import essential_contacts_v1\n\nclient = essential_contacts_v1.EssentialContactsServiceClient()\n\nclient.delete_contact(\n    request=essential_contacts_v1.DeleteContactRequest(\n        name=\"projects/my-project-id/contacts/CONTACT_ID\"\n    )\n)\n```\n\n## Important Pitfalls\n\n- Use full resource names everywhere. `my-project-id` is not enough when the API expects `projects/my-project-id`.\n- `list_contacts()` and `compute_contacts()` answer different questions. `list_contacts()` is direct attachments only; `compute_contacts()` includes inherited contacts from parent folders and organizations.\n- `email` cannot be changed after a contact is created. Create a new contact and delete the old one if the mailbox changes.\n- `update_contact()` does not infer changed fields. Pass an explicit `FieldMask` or your update can silently omit fields you expected to change.\n- `language_tag` must be one of the supported contact languages. If a notification is not available in that language, Google sends the message in English.\n- `TECHNICAL_INCIDENTS` is more specific than `TECHNICAL`. If you subscribe contacts to both, incident notifications are sent to the `TECHNICAL_INCIDENTS` contacts instead of the general technical contacts.\n- Use group addresses or team aliases where possible. The product docs recommend stable team-owned addresses so personnel changes do not break notification routing.\n\n## Official Sources\n\n- Maintainer package docs: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-essential-contacts\n- Package README: https://raw.githubusercontent.com/googleapis/google-cloud-python/main/packages/google-cloud-essential-contacts/README.rst\n- Python reference: https://cloud.google.com/python/docs/reference/essentialcontacts/latest/google.cloud.essential_contacts_v1.services.essential_contacts_service.EssentialContactsServiceClient\n- Product guide: https://cloud.google.com/resource-manager/docs/managing-notification-contacts\n- ADC overview: https://cloud.google.com/docs/authentication/application-default-credentials\n- PyPI package page: https://pypi.org/project/google-cloud-essential-contacts/\n"
  },
  {
    "path": "content/google/docs/eventarc/python/DOC.md",
    "content": "---\nname: eventarc\ndescription: \"Google Cloud Eventarc Python client for managing triggers, providers, channels, Google API sources, message buses, and pipelines\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.19.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,eventarc,google-cloud,events,cloudevents,cloud-run,pubsub\"\n---\n\n# Google Cloud Eventarc Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-eventarc` to manage Eventarc resources from Python. This package is the control-plane client for Eventarc resources such as triggers, providers, channels, message buses, pipelines, and Google API sources. It is not the library that receives HTTP events in your Cloud Run service, and it is not the publishing client for custom events; Google publishes `google-cloud-eventarc-publishing` separately for publishing flows.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-eventarc==1.19.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-eventarc==1.19.0\"\npoetry add \"google-cloud-eventarc==1.19.0\"\n```\n\n## Authentication And Setup\n\nEventarc clients use Application Default Credentials (ADC). Prefer these credential sources in this order:\n\n1. Local development: `gcloud auth application-default login`\n2. Google Cloud runtimes with an attached service account or workload identity\n3. `GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json` only when you cannot use the first two\n\nProject prerequisites agents commonly miss:\n\n- Enable the Eventarc API before creating or listing resources.\n- Use the same `location` as the resources you are routing events from or to; providers and triggers are location-scoped.\n- Make sure the caller can manage Eventarc resources and impersonate the service account used by the trigger when needed.\n- For Cloud Run destinations, the trigger's service account typically needs `roles/eventarc.eventReceiver`, and the destination service may need `roles/run.invoker` when it requires authenticated invocation.\n- Avoid default service accounts for production setups unless you have reviewed the permissions explicitly.\n\nIf you must use a key file locally:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n## Initialize A Client\n\nGenerated client snippets warn that some environments may require specifying a regional API endpoint. Start with the default client, and set `client_options` if your environment or upstream guidance requires a location-specific endpoint.\n\n```python\nfrom google.cloud import eventarc_v1\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = eventarc_v1.EventarcClient()\n```\n\nIf you need custom endpoint selection:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import eventarc_v1\n\nclient = eventarc_v1.EventarcClient(\n    client_options=ClientOptions(\n        api_endpoint=\"YOUR_EVENTARC_ENDPOINT\"\n    )\n)\n```\n\n## Core Usage\n\n### List providers for a location\n\nProvider discovery is the safest way to confirm which event sources and filters are valid in a given region.\n\n```python\nfrom google.cloud import eventarc_v1\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = eventarc_v1.EventarcClient()\n\nfor provider in client.list_providers(parent=parent):\n    print(provider.name)\n```\n\nUse the provider metadata in the official docs or `gcloud eventarc providers describe ...` when you need the exact filtering attributes for a specific event type.\n\n### Create a trigger that sends Cloud Storage events to Cloud Run\n\nTrigger creation is a long-running operation, so wait for `.result()` instead of assuming the resource is ready immediately.\n\n```python\nfrom google.cloud import eventarc_v1\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = eventarc_v1.EventarcClient()\n\ntrigger = eventarc_v1.Trigger(\n    service_account=\"eventarc-trigger@my-project.iam.gserviceaccount.com\",\n    destination=eventarc_v1.Destination(\n        cloud_run=eventarc_v1.CloudRun(\n            service=\"image-handler\",\n            region=location,\n            path=\"/events\",\n        )\n    ),\n    event_filters=[\n        eventarc_v1.EventFilter(\n            attribute=\"type\",\n            value=\"google.cloud.storage.object.v1.finalized\",\n        ),\n        eventarc_v1.EventFilter(\n            attribute=\"bucket\",\n            value=\"my-upload-bucket\",\n        ),\n    ],\n)\n\noperation = client.create_trigger(\n    parent=parent,\n    trigger=trigger,\n    trigger_id=\"storage-object-finalized\",\n)\n\ncreated = operation.result(timeout=300)\nprint(created.name)\n```\n\nNotes:\n\n- Every trigger must include an event filter for the `type` attribute.\n- The valid additional filters depend on the provider and event type.\n- Eventarc propagation is not instant; the product docs note that new triggers can take up to about two minutes to become active.\n\n### List existing triggers\n\n`list_triggers()` returns a pager, so iterate directly over it.\n\n```python\nfrom google.cloud import eventarc_v1\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = eventarc_v1.EventarcClient()\n\nfor trigger in client.list_triggers(parent=parent):\n    print(trigger.name)\n    print(trigger.service_account)\n```\n\n### Delete a trigger\n\nDelete operations are also long-running:\n\n```python\nfrom google.cloud import eventarc_v1\n\nclient = eventarc_v1.EventarcClient()\n\nname = \"projects/my-project/locations/us-central1/triggers/storage-object-finalized\"\noperation = client.delete_trigger(name=name)\noperation.result(timeout=300)\n```\n\n## Working With Advanced Resources\n\nThe same client also exposes methods for Eventarc Advanced resources such as channels, channel connections, message buses, pipelines, enrollments, and Google API sources. The request pattern is the same:\n\n- build the resource name under `projects/{project}/locations/{location}/...`\n- create the resource object from `eventarc_v1`\n- call the matching `create_*`, `update_*`, `get_*`, `list_*`, or `delete_*` method\n- wait on long-running operations with `.result()`\n\nIf you are writing code against these newer surfaces, check the `1.18.x` and `1.19.x` changelog entries first because several fields for Google API sources, Eventarc triggers, and Python version support were updated recently.\n\n## Configuration Notes\n\n- Resource names are location-scoped. Keep a single `location` variable and build all `parent` and `name` strings from it.\n- Use explicit project IDs in resource names rather than relying on ambient defaults when automation spans multiple projects.\n- Logging can be enabled with the standard Google client logging controls, including `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`.\n- Prefer passing an explicit `credentials=` object only when ADC is not viable. The changelog notes that the older `credentials_file` argument is deprecated.\n\n## Common Pitfalls\n\n- This package manages Eventarc resources. It does not replace your Cloud Run, GKE, or HTTP application code that actually receives delivered CloudEvents.\n- Do not guess event filters. Event types and supported filtering attributes vary by provider and location.\n- `type` is mandatory on every trigger, and Eventarc does not let you change the event filter type after the trigger is created.\n- Long-running operations still need propagation time after `.result()` returns; allow for eventual consistency in tests and automation.\n- Path-pattern matching is not generally available for all trigger types; the type docs mark it as only supported for GCFv1 triggers.\n- `Trigger.retry_policy` is version-sensitive and only applies to Cloud Run destinations.\n- If you provide your own Pub/Sub topic for transport, Eventarc will not delete that topic when the trigger is deleted.\n- IAM failures are often split across two identities: the caller creating the trigger and the service account attached to the trigger itself.\n\n## Version-Sensitive Notes For 1.19.0\n\n- PyPI and the official Google Cloud reference both show `1.19.0` as the current package version on March 12, 2026.\n- The `1.19.0` changelog adds Python 3.14 support.\n- The `1.18.0` changelog added wider `GoogleApiSource` flags and trigger retry policy support, so examples written against older `1.17.x` docs may miss newer fields.\n- The `1.17.0` changelog deprecates `credentials_file`; prefer ADC or an explicit `credentials=` object.\n\n## Official Sources\n\n- Python client reference: `https://cloud.google.com/python/docs/reference/eventarc/latest`\n- `EventarcClient` reference: `https://cloud.google.com/python/docs/reference/eventarc/latest/google.cloud.eventarc_v1.services.eventarc.EventarcClient`\n- Package changelog: `https://cloud.google.com/python/docs/reference/eventarc/latest/changelog`\n- Eventarc create-trigger guidance: `https://cloud.google.com/eventarc/docs/creating-triggers`\n- Eventarc IAM guidance: `https://cloud.google.com/eventarc/docs/roles-permissions`\n- ADC guidance: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- PyPI package page: `https://pypi.org/project/google-cloud-eventarc/`\n"
  },
  {
    "path": "content/google/docs/filestore/python/DOC.md",
    "content": "---\nname: filestore\ndescription: \"google-cloud-filestore package guide for Python with ADC setup, instance administration, backups, and restore operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,filestore,gcp,nfs,storage,python,admin\"\n---\n\n# google-cloud-filestore Python Package Guide\n\n`google-cloud-filestore` is the official Google Cloud Python client for the Filestore control plane.\n\nUse it to create, inspect, back up, restore, and delete Filestore resources. Do not use it for file I/O against the mounted NFS share itself.\n\nPrimary import:\n\n```python\nfrom google.cloud import filestore_v1\n```\n\n## Golden Rule\n\n- Use `google-cloud-filestore` for Filestore administration.\n- Use Application Default Credentials (ADC) for normal authentication.\n- Treat create, delete, backup, and restore calls as long-running operations.\n- Use the generated resource-name helpers such as `instance_path()` and `backup_path()` instead of concatenating `projects/...` strings by hand.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-filestore==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-filestore==1.15.0\"\npoetry add \"google-cloud-filestore==1.15.0\"\n```\n\nPyPI currently lists Python `>=3.7` for this package.\n\n## Authentication And Setup\n\nEnable the Filestore API and set up ADC before creating a client:\n\n```bash\ngcloud services enable file.googleapis.com\ngcloud auth application-default login\ngcloud config set project MY_PROJECT_ID\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"MY_PROJECT_ID\"\n```\n\nFor production on Google Cloud, prefer attached service accounts or workload identity over shipping key files with your app.\n\n## Initialize The Client\n\nDefault client with ADC:\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\n```\n\nExplicit credentials object:\n\n```python\nfrom google.cloud import filestore_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = filestore_v1.CloudFilestoreManagerClient(credentials=credentials)\n```\n\nUseful resource helpers:\n\n```python\nproject_id = \"my-project\"\nzone = \"us-central1-b\"\ninstance_id = \"filestore-dev\"\n\ninstance_name = client.instance_path(project_id, zone, instance_id)\nbackup_name = client.backup_path(project_id, \"us-central1\", \"filestore-dev-backup\")\n```\n\n## Core Workflow\n\n### List instances\n\n`list_instances()` returns a pager:\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\nparent = \"projects/my-project/locations/us-central1-b\"\n\nfor instance in client.list_instances(request={\"parent\": parent}):\n    print(instance.name)\n    print(instance.tier.name)\n    print(instance.state.name)\n```\n\n### Get one instance\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\nname = client.instance_path(\"my-project\", \"us-central1-b\", \"filestore-dev\")\n\ninstance = client.get_instance(request={\"name\": name})\n\nprint(instance.name)\nprint(instance.description)\nprint(instance.file_shares)\nprint(instance.networks)\nprint(instance.state.name)\n```\n\n### Create an instance\n\nCreating an instance requires a service tier, at least one file share, and at least one network config. `capacity_gb` must be at least `1024`.\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\nproject_id = \"my-project\"\nzone = \"us-central1-b\"\n\ninstance = filestore_v1.Instance(\n    tier=filestore_v1.Instance.Tier.BASIC_HDD,\n    description=\"Development Filestore instance\",\n    file_shares=[\n        filestore_v1.FileShareConfig(\n            name=\"vol1\",\n            capacity_gb=1024,\n        )\n    ],\n    networks=[\n        filestore_v1.NetworkConfig(\n            network=\"default\",\n            modes=[filestore_v1.NetworkConfig.AddressMode.MODE_IPV4],\n        )\n    ],\n)\n\noperation = client.create_instance(\n    request={\n        \"parent\": f\"projects/{project_id}/locations/{zone}\",\n        \"instance_id\": \"filestore-dev\",\n        \"instance\": instance,\n    }\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\nprint(created.state.name)\n```\n\nThe `network` field accepts either the bare VPC network name such as `default` or the full path `projects/{project_number}/global/networks/{network}`.\n\n### Create a backup\n\nBackups are separate resources. The backup request points at the source instance and the file share name to capture.\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\nproject_id = \"my-project\"\ninstance_zone = \"us-central1-b\"\nbackup_location = \"us-central1\"\n\nsource_instance = client.instance_path(project_id, instance_zone, \"filestore-dev\")\n\nbackup = filestore_v1.Backup(\n    source_instance=source_instance,\n    source_file_share=\"vol1\",\n    description=\"Nightly backup\",\n)\n\noperation = client.create_backup(\n    request={\n        \"parent\": f\"projects/{project_id}/locations/{backup_location}\",\n        \"backup_id\": \"filestore-dev-backup\",\n        \"backup\": backup,\n    }\n)\n\ncreated_backup = operation.result(timeout=1800)\nprint(created_backup.name)\nprint(created_backup.state.name)\n```\n\n### Restore an instance from a backup\n\n`restore_instance()` restores one file share on an existing instance from a backup resource.\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\n\ninstance_name = client.instance_path(\"my-project\", \"us-central1-b\", \"filestore-dev\")\nbackup_name = client.backup_path(\"my-project\", \"us-central1\", \"filestore-dev-backup\")\n\noperation = client.restore_instance(\n    request={\n        \"name\": instance_name,\n        \"file_share\": \"vol1\",\n        \"source_backup\": backup_name,\n    }\n)\n\nrestored = operation.result(timeout=1800)\nprint(restored.name)\nprint(restored.state.name)\n```\n\n### Delete an instance\n\nDelete is also a long-running operation:\n\n```python\nfrom google.cloud import filestore_v1\n\nclient = filestore_v1.CloudFilestoreManagerClient()\nname = client.instance_path(\"my-project\", \"us-central1-b\", \"filestore-dev\")\n\noperation = client.delete_instance(request={\"name\": name})\noperation.result(timeout=1800)\n```\n\n## Common Pitfalls\n\n- This package manages Filestore resources. It does not mount the exported NFS share or perform filesystem reads and writes for you.\n- Do not assume mutating methods finish immediately. Wait for `operation.result()` before reading follow-up state.\n- Do not omit `file_shares` or `networks` on create. They are required parts of the instance definition.\n- `FileShareConfig.capacity_gb` has a minimum of `1024`.\n- `NetworkConfig.network` is the VPC network name or full network resource path, not a subnet name.\n- Use the correct location type for the resource you are creating. Instance examples commonly use zonal locations like `us-central1-b`, while backup resource names use their own `locations/{location}` path.\n\n## Version Notes For 1.15.0\n\n- This guide is pinned to `google-cloud-filestore==1.15.0`.\n- The official changelog lists `1.15.0` on January 8, 2026.\n- The generated Python reference for this package documents `CloudFilestoreManagerClient`, `Instance`, `FileShareConfig`, `NetworkConfig`, `Backup`, and `RestoreInstanceRequest`, which are the main surfaces used here.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-filestore/\n- Package docs on GitHub: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-filestore\n- Python reference root: https://docs.cloud.google.com/python/docs/reference/file/latest\n- Client reference: https://docs.cloud.google.com/python/docs/reference/file/latest/google.cloud.filestore_v1.services.cloud_filestore_manager.CloudFilestoreManagerClient\n- `FileShareConfig` reference: https://docs.cloud.google.com/python/docs/reference/file/latest/google.cloud.filestore_v1.types.FileShareConfig\n- `NetworkConfig` reference: https://docs.cloud.google.com/python/docs/reference/file/latest/google.cloud.filestore_v1.types.NetworkConfig\n- `Backup` reference: https://docs.cloud.google.com/python/docs/reference/file/latest/google.cloud.filestore_v1.types.Backup\n- `RestoreInstanceRequest` reference: https://docs.cloud.google.com/python/docs/reference/file/latest/google.cloud.filestore_v1.types.RestoreInstanceRequest\n- Filestore create-instance docs: https://cloud.google.com/filestore/docs/create-instances\n- Filestore create-backup docs: https://cloud.google.com/filestore/docs/backup-restore/create-instance-backups\n- Google Cloud ADC docs: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/firestore/javascript/DOC.md",
    "content": "---\nname: firestore\ndescription: \"Google Cloud Firestore Node.js client for document reads, queries, transactions, batched writes, and emulator-backed local development\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,firestore,gcp,nosql,database,javascript,nodejs\"\n---\n\n# Google Cloud Firestore Node.js Client\n\n## Golden Rule\n\nUse the official `@google-cloud/firestore` server SDK with Google Cloud authentication.\n\nPrefer Application Default Credentials (ADC) for local development and deployed workloads. Use a service account key file only when ADC or workload identity is not available.\n\nUse this package for server-side Node.js code. Do not copy Firebase Web SDK setup into backend code that uses `@google-cloud/firestore`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/firestore@8.3.0\n```\n\nIf your project does not already have Firestore enabled, create the Firestore database for the target Google Cloud project before debugging client code.\n\n## Authentication And Project Setup\n\nFor local development, sign in with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nFor service-account-based environments, point `GOOGLE_APPLICATION_CREDENTIALS` at the JSON key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\n## Initialize A Client\n\nImport the package as:\n\n```javascript\nconst {Firestore, FieldValue} = require('@google-cloud/firestore');\n```\n\nBasic client:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nIf the environment already provides project and credentials, `new Firestore()` is usually enough:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n```\n\nWith an explicit key file:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore({\n  projectId: 'your-project-id',\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nPass `projectId` explicitly when your shell, local tooling, or CI environment makes project discovery ambiguous.\n\n## Create And Update Documents\n\nCreate or replace a document with `set()`:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\nconst cityRef = db.collection('cities').doc('SF');\n\nasync function createCity() {\n  await cityRef.set({\n    name: 'San Francisco',\n    state: 'CA',\n    country: 'USA',\n    capital: false,\n    population: 860000,\n  });\n}\n\ncreateCity().catch(console.error);\n```\n\nMerge a partial update into an existing document with `set(..., {merge: true})`:\n\n```javascript\nasync function mergeCityFields() {\n  await cityRef.set(\n    {\n      nickname: 'SF',\n      regions: ['west_coast', 'norcal'],\n    },\n    {merge: true}\n  );\n}\n```\n\nAdd a document with an auto-generated ID:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function addCity() {\n  const docRef = await db.collection('cities').add({\n    name: 'Los Angeles',\n    state: 'CA',\n    country: 'USA',\n  });\n\n  console.log(docRef.id);\n}\n\naddCity().catch(console.error);\n```\n\nUse sentinel values such as `increment()`, `serverTimestamp()`, and `arrayUnion()` in updates:\n\n```javascript\nconst {Firestore, FieldValue} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\nconst cityRef = db.collection('cities').doc('SF');\n\nasync function updateCity() {\n  await cityRef.update({\n    population: FieldValue.increment(1),\n    updatedAt: FieldValue.serverTimestamp(),\n    tags: FieldValue.arrayUnion('coastal'),\n  });\n}\n\nupdateCity().catch(console.error);\n```\n\n## Read Documents And Run Queries\n\nFetch a single document:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function readCity() {\n  const snapshot = await db.collection('cities').doc('SF').get();\n\n  if (!snapshot.exists) {\n    console.log('Document not found');\n    return;\n  }\n\n  console.log(snapshot.id, snapshot.data());\n}\n\nreadCity().catch(console.error);\n```\n\nRun a simple query and iterate the results:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function listCaliforniaCities() {\n  const snapshot = await db\n    .collection('cities')\n    .where('state', '==', 'CA')\n    .orderBy('population', 'desc')\n    .limit(10)\n    .get();\n\n  for (const doc of snapshot.docs) {\n    console.log(doc.id, doc.data());\n  }\n}\n\nlistCaliforniaCities().catch(console.error);\n```\n\nQuery a collection group when the same subcollection exists under many parents:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function listMuseums() {\n  const snapshot = await db\n    .collectionGroup('landmarks')\n    .where('type', '==', 'museum')\n    .get();\n\n  for (const doc of snapshot.docs) {\n    console.log(doc.ref.path, doc.data());\n  }\n}\n\nlistMuseums().catch(console.error);\n```\n\n## Transactions\n\nUse a transaction for read-modify-write logic that must commit atomically:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\nconst cityRef = db.collection('cities').doc('SF');\n\nasync function incrementPopulation() {\n  const nextPopulation = await db.runTransaction(async transaction => {\n    const snapshot = await transaction.get(cityRef);\n\n    if (!snapshot.exists) {\n      throw new Error('City document does not exist');\n    }\n\n    const current = snapshot.get('population') || 0;\n    const updated = current + 1;\n\n    transaction.update(cityRef, {population: updated});\n    return updated;\n  });\n\n  console.log(nextPopulation);\n}\n\nincrementPopulation().catch(console.error);\n```\n\n## Batched Writes\n\nUse a batch when you need multiple writes committed together and the write set does not depend on reading documents inside the same operation:\n\n```javascript\nconst {Firestore, FieldValue} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function commitBatch() {\n  const batch = db.batch();\n  const sfRef = db.collection('cities').doc('SF');\n  const nycRef = db.collection('cities').doc('NYC');\n  const laRef = db.collection('cities').doc('LA');\n\n  batch.set(sfRef, {name: 'San Francisco'}, {merge: true});\n  batch.update(nycRef, {population: FieldValue.increment(1)});\n  batch.delete(laRef);\n\n  await batch.commit();\n}\n\ncommitBatch().catch(console.error);\n```\n\n## BulkWriter For High-Volume Non-Transactional Writes\n\nUse `bulkWriter()` when throughput matters more than atomic multi-document behavior:\n\n```javascript\nconst {Firestore, FieldValue} = require('@google-cloud/firestore');\n\nconst db = new Firestore();\n\nasync function writeManyDocuments() {\n  const bulkWriter = db.bulkWriter();\n  const sfRef = db.collection('cities').doc('SF');\n  const nycRef = db.collection('cities').doc('NYC');\n\n  bulkWriter.set(sfRef, {name: 'San Francisco'}, {merge: true});\n  bulkWriter.update(nycRef, {population: FieldValue.increment(1)});\n\n  await bulkWriter.close();\n}\n\nwriteManyDocuments().catch(console.error);\n```\n\n## Emulator Setup\n\nStart the Firestore emulator with the Google Cloud CLI:\n\n```bash\ngcloud emulators firestore start --host-port=127.0.0.1:8080\n```\n\nIn the shell where you run your app or tests, point the client at the emulator:\n\n```bash\nexport FIRESTORE_EMULATOR_HOST=\"127.0.0.1:8080\"\nexport GOOGLE_CLOUD_PROJECT=\"demo-project\"\n```\n\nThen initialize the client normally:\n\n```javascript\nconst {Firestore} = require('@google-cloud/firestore');\n\nconst db = new Firestore({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || 'demo-project',\n});\n```\n\nThe emulator is useful for local integration tests, but it does not replace production checks for indexes, quotas, IAM, or other managed-service behavior.\n\n## Configuration Notes\n\n- Pass `projectId` explicitly when your environment is ambiguous.\n- Use `set(..., {merge: true})` for partial upserts. Use `update()` only when the document must already exist.\n- Use a transaction for read-modify-write logic.\n- Use a batch for grouped writes that do not depend on reads.\n- Use `bulkWriter()` for high-throughput writes when atomicity is not required.\n- Keep emulator environment variables out of production shells and CI jobs.\n\n## Common Pitfalls\n\n- Do not use API keys or custom auth headers. Use ADC, user credentials, or a service account.\n- Do not confuse `collection()` and `doc()` handles with network reads. Firestore only fetches data when you call methods like `get()`.\n- Do not call `update()` on a document that may not exist.\n- Do not treat a write batch as a transaction.\n- Do not treat `BulkWriter` as atomic.\n- Compound and ordered queries can require composite indexes. Follow the index creation link in the Firestore error message when a query fails.\n- Keep emulator-only configuration out of production environments.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/firestore` `8.3.0`.\n- Prefer the current Node.js client reference and Firestore sample code when older articles show legacy client patterns or Firebase-specific setup.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest`\n- `Firestore` class reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest/firestore/firestore`\n- `Query` class reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest/firestore/query`\n- `DocumentReference` class reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest/firestore/documentreference`\n- `WriteBatch` class reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest/firestore/writebatch`\n- `BulkWriter` class reference: `https://cloud.google.com/nodejs/docs/reference/firestore/latest/firestore/bulkwriter`\n- Firestore code samples index: `https://cloud.google.com/firestore/docs/samples`\n- Authentication guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Firestore emulator guide: `https://cloud.google.com/firestore/native/docs/emulator`\n- npm package: `https://www.npmjs.com/package/@google-cloud/firestore`\n"
  },
  {
    "path": "content/google/docs/firestore/python/DOC.md",
    "content": "---\nname: firestore\ndescription: \"Google Cloud Firestore Python client for document reads, queries, transactions, batched writes, and emulator-backed tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.24.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,firestore,gcp,nosql,database,python,async\"\n---\n\n# google-cloud-firestore Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-firestore` client with Google Cloud authentication.\n\nPrefer Application Default Credentials (ADC) for local development and deployed workloads. Use a service account key file only when ADC or workload identity is not available.\n\n## Install\n\n```bash\npip install google-cloud-firestore\n```\n\nPin the version if you need the exact package line covered here:\n\n```bash\npip install \"google-cloud-firestore==2.24.0\"\n```\n\nOther common package managers:\n\n```bash\nuv add google-cloud-firestore\npoetry add google-cloud-firestore\n```\n\n## Authentication And Setup\n\n1. Enable Firestore for the target Google Cloud project.\n2. For local development, authenticate with ADC.\n3. For deployed workloads, prefer workload identity or an attached service account.\n4. Set the project explicitly when your environment does not already provide one.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\n## Initialize A Client\n\nSynchronous client:\n\n```python\nfrom google.cloud import firestore\n\ndb = firestore.Client(project=\"your-project-id\")\n```\n\nAsynchronous client:\n\n```python\nfrom google.cloud import firestore\n\nadb = firestore.AsyncClient(project=\"your-project-id\")\n```\n\nExplicit credentials:\n\n```python\nfrom google.cloud import firestore\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\ndb = firestore.Client(\n    project=\"your-project-id\",\n    credentials=credentials,\n    database=\"(default)\",\n)\n```\n\nImportant client note: the current official `Client` reference explicitly says `_http` is not accepted because Firestore requires the gRPC transport.\n\n## Core Usage\n\n### Create Or Replace A Document\n\n```python\nfrom google.cloud import firestore\n\ndb = firestore.Client()\ncity_ref = db.collection(\"cities\").document(\"SF\")\n\ncity_ref.set(\n    {\n        \"name\": \"San Francisco\",\n        \"state\": \"CA\",\n        \"country\": \"USA\",\n        \"capital\": False,\n        \"population\": 860000,\n    }\n)\n```\n\n### Merge Into An Existing Document\n\n```python\ncity_ref.set({\"nickname\": \"San Fran\"}, merge=True)\n```\n\n### Add A Document With An Auto-Generated ID\n\n```python\ndoc_ref, write_result = db.collection(\"cities\").add(\n    {\"name\": \"Tokyo\", \"country\": \"Japan\"}\n)\n\nprint(doc_ref.id)\nprint(write_result.update_time)\n```\n\n### Read One Document\n\n```python\nsnapshot = city_ref.get()\n\nif snapshot.exists:\n    print(snapshot.to_dict())\n```\n\n### Query A Collection\n\nPrefer the current `FieldFilter` style. Older positional `where(\"field\", \"==\", value)` snippets still exist in blog posts and old answers, but the official current samples use `where(filter=...)`.\n\n```python\nfrom google.cloud import firestore\nfrom google.cloud.firestore_v1.base_query import FieldFilter\n\ndb = firestore.Client()\n\nquery = (\n    db.collection(\"cities\")\n    .where(filter=FieldFilter(\"state\", \"==\", \"CA\"))\n    .order_by(\"population\", direction=firestore.Query.DESCENDING)\n    .limit(10)\n)\n\nfor snapshot in query.stream():\n    print(snapshot.id, snapshot.to_dict())\n```\n\nThe query reference notes that `stream()` is usually preferred over `get()`.\n\n### Update Nested Fields And Atomic Values\n\n```python\nfrom google.cloud import firestore\n\ncity_ref.update(\n    {\n        \"population\": firestore.Increment(1),\n        \"regions\": firestore.ArrayUnion([\"west_coast\"]),\n        \"last_updated\": firestore.SERVER_TIMESTAMP,\n        \"stats.visits\": firestore.Increment(1),\n    }\n)\n```\n\n### Batched Writes\n\nUse a batch when you already know the write set and do not need read-before-write logic.\n\n```python\nbatch = db.batch()\n\nsf_ref = db.collection(\"cities\").document(\"SF\")\nla_ref = db.collection(\"cities\").document(\"LA\")\n\nbatch.set(sf_ref, {\"name\": \"San Francisco\", \"state\": \"CA\"})\nbatch.update(la_ref, {\"population\": 3900000})\nbatch.commit()\n```\n\n### Transactions\n\nUse a transaction when writes depend on currently stored values.\n\n```python\nfrom google.cloud import firestore\n\ndb = firestore.Client()\ntransaction = db.transaction()\ncounter_ref = db.collection(\"counters\").document(\"pageviews\")\n\n@firestore.transactional\ndef increment_counter(transaction, ref):\n    snapshot = ref.get(transaction=transaction)\n    current = snapshot.get(\"value\") or 0\n    transaction.update(ref, {\"value\": current + 1})\n\nincrement_counter(transaction, counter_ref)\n```\n\n### BulkWriter For High-Volume Non-Transactional Writes\n\nUse `bulk_writer()` when throughput matters more than atomic multi-document behavior.\n\n```python\nfrom google.cloud import firestore\n\ndb = firestore.Client()\nbulk = db.bulk_writer()\n\nsf_ref = db.collection(\"cities\").document(\"SF\")\nnyc_ref = db.collection(\"cities\").document(\"NYC\")\n\nbulk.set(sf_ref, {\"name\": \"San Francisco\"})\nbulk.update(nyc_ref, {\"population\": firestore.Increment(1)})\nbulk.flush()\nbulk.close()\n```\n\n## Emulator Setup\n\nFor local tests, point the client at the Firestore emulator:\n\n```bash\nexport FIRESTORE_EMULATOR_HOST=\"127.0.0.1:8080\"\nexport GOOGLE_CLOUD_PROJECT=\"demo-project\"\n```\n\nThis is useful for integration tests, but it is not a full production-equivalence check. Google documents differences around transactions, index handling, and cleanup behavior.\n\n## Configuration Notes\n\n- Pass `project=` explicitly when your environment is ambiguous.\n- Pass `database=\"(default)\"` unless you intentionally use a named Firestore database.\n- For async code, use `firestore.AsyncClient` instead of wrapping the sync client in thread pools.\n- In multiprocessing code, create Firestore clients after `os.fork()`, not before.\n\n## Common Pitfalls\n\n- Do not invent custom auth headers or API-key flows. Firestore Python expects Google credentials.\n- Do not pass `_http` into the client. The official client reference says Firestore does not accept it.\n- Do not treat a batch like a transaction. If the write depends on a prior read, use a transaction.\n- Do not treat `BulkWriter` like a transaction. It improves throughput, not atomicity.\n- Prefer `query.stream()` for iteration-heavy reads.\n- Prefer `FieldFilter`-based query examples in new code.\n- Keep emulator-only settings out of production environments.\n- If copied examples reference `v1beta1` or other legacy surfaces, reconcile them against the current 2.x docs before using them.\n\n## Version-Sensitive Notes\n\n### Current Upstream State\n\n- Version used here for this session: `2.24.0`\n- PyPI official package page observed on 2026-03-12: `2.24.0`\n- PyPI release date observed on 2026-03-12: `2026-03-06`\n- Firestore Python reference docs root observed on 2026-03-12: `2.23.0 (latest)`\n\n### Relevant 2.x Migration History\n\nThe official upgrade guide for `2.0.0` is still relevant when you run into old examples:\n\n- `v1beta1` and older legacy surfaces were removed.\n- generated GAPIC methods follow the modern request-or-flattened-kwargs style\n- older query snippets often predate the current `FieldFilter` examples\n\n## Official Sources Used\n\n- PyPI package page: https://pypi.org/project/google-cloud-firestore/\n- Firestore Python reference docs root: https://cloud.google.com/python/docs/reference/firestore/latest\n- Firestore `Client` reference: https://cloud.google.com/python/docs/reference/firestore/latest/google.cloud.firestore_v1.client.Client\n- Firestore `Query` reference: https://cloud.google.com/python/docs/reference/firestore/latest/google.cloud.firestore_v1.query.Query\n- Firestore `BulkWriter` reference: https://cloud.google.com/python/docs/reference/firestore/latest/google.cloud.firestore_v1.bulk_writer.BulkWriter\n- Firestore code samples index: https://cloud.google.com/firestore/docs/samples\n- Firestore query sample using `FieldFilter`: https://cloud.google.com/firestore/docs/samples/firestore-query-filter-compound-multi-eq\n- Firestore batch write sample: https://cloud.google.com/firestore/docs/samples/firestore-data-batch-writes\n- Firestore transaction sample: https://cloud.google.com/firestore/docs/samples/firestore-transaction-document-update-conditional\n- Google Cloud ADC guide: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- Firestore emulator guide: https://cloud.google.com/firestore/native/docs/emulator\n- Firestore Python changelog: https://cloud.google.com/python/docs/reference/firestore/latest/changelog\n- Firestore Python upgrade guide: https://cloud.google.com/python/docs/reference/firestore/latest/upgrading\n"
  },
  {
    "path": "content/google/docs/functions/javascript/DOC.md",
    "content": "---\nname: functions\ndescription: \"Google Cloud Functions Node.js client for listing, inspecting, deploying, updating, and deleting Cloud Functions resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,cloud-functions,gcp,functions,serverless,javascript,nodejs\"\n---\n\n# `@google-cloud/functions` JavaScript Package Guide\n\nUse `@google-cloud/functions` when your Node.js code needs the Cloud Functions control-plane API: list deployed functions, inspect configuration, discover runtimes, deploy changes, generate source upload URLs, and delete functions. Prefer the `v2` client for current 2nd gen workflows. Use `v1` only when you are intentionally working with legacy 1st gen functions or the v1-only `callFunction()` API.\n\nThis package manages Cloud Functions resources. It is not the package you use inside a function handler.\n\nThis guide covers `4.2.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/functions@4.2.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nTypical prerequisites:\n\n1. A Google Cloud project.\n2. Cloud Functions API enabled in that project.\n3. Credentials with permission to manage functions in the target project and region.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable cloudfunctions.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n```\n\nIf you must use a service account key file explicitly:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nFor production on Google Cloud, prefer an attached service account instead of shipping key files.\n\n## Initialize The Clients\n\nUse `v2.FunctionServiceClient` for current deployments and admin workflows:\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nUse `v1.CloudFunctionsServiceClient` only for legacy 1st gen-specific workflows:\n\n```javascript\nconst {v1} = require('@google-cloud/functions');\n\nconst legacyClient = new v1.CloudFunctionsServiceClient();\n```\n\nFor the examples below, build resource names explicitly:\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst region = process.env.GOOGLE_CLOUD_REGION || 'us-central1';\n\nconst parent = `projects/${projectId}/locations/${region}`;\nconst functionName = `${parent}/functions/hello-function`;\n```\n\n## Core Workflows\n\n### List Functions In A Region\n\nUse the async iterator to avoid manual page handling.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function listFunctions(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  for await (const fn of client.listFunctionsAsync({parent})) {\n    console.log({\n      name: fn.name,\n      state: fn.state,\n      environment: fn.environment,\n      url: fn.serviceConfig?.uri || fn.url || null,\n    });\n  }\n}\n```\n\n### Read One Function\n\n`getFunction()` expects the full resource name, not just the function ID.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function getFunction(projectId, region, functionId) {\n  const name = `projects/${projectId}/locations/${region}/functions/${functionId}`;\n  const [fn] = await client.getFunction({name});\n  return fn;\n}\n```\n\n### List Supported Runtimes\n\nUse this instead of hard-coding runtime strings when you generate deployment config.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function listRuntimes(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  for await (const runtime of client.listRuntimesAsync({parent})) {\n    console.log({\n      name: runtime.name,\n      displayName: runtime.displayName,\n      environment: runtime.environment,\n      stage: runtime.stage,\n    });\n  }\n}\n```\n\n### Update A Function With A Field Mask\n\n`updateFunction()` is a long-running operation. Wait for `operation.promise()`. Use an update mask so you only change the fields you intend to change.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function updateFunctionEnv(projectId, region, functionId) {\n  const name = `projects/${projectId}/locations/${region}/functions/${functionId}`;\n  const [fn] = await client.getFunction({name});\n\n  fn.serviceConfig = {\n    ...fn.serviceConfig,\n    environmentVariables: {\n      ...(fn.serviceConfig?.environmentVariables ?? {}),\n      APP_ENV: 'prod',\n    },\n    maxInstanceCount: 5,\n  };\n\n  const [operation] = await client.updateFunction({\n    function: fn,\n    updateMask: {\n      paths: [\n        'service_config.environment_variables',\n        'service_config.max_instance_count',\n      ],\n    },\n  });\n\n  const [updated] = await operation.promise();\n  return updated;\n}\n```\n\n### Create A Function From Source Already In Cloud Storage\n\nFor `storageSource`, the object must be a gzipped archive (`.tar.gz`) in Cloud Storage.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function createFunctionFromGcs(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  const [operation] = await client.createFunction({\n    parent,\n    functionId: 'hello-function',\n    function: {\n      buildConfig: {\n        runtime: 'nodejs22',\n        entryPoint: 'helloHttp',\n        source: {\n          storageSource: {\n            bucket: 'my-source-bucket',\n            object: 'hello-function.tar.gz',\n          },\n        },\n      },\n      serviceConfig: {\n        availableMemory: '512M',\n        timeoutSeconds: 60,\n        environmentVariables: {\n          APP_ENV: 'prod',\n        },\n      },\n    },\n  });\n\n  const [created] = await operation.promise();\n  console.log(created.name);\n  console.log(created.serviceConfig?.uri || created.url || null);\n  return created;\n}\n```\n\n### Generate A Signed Upload URL For Local Source\n\nUse `generateUploadUrl()` when your source bundle is local. The upload target expects a zip archive, not a `.tar.gz` file. After upload, use the returned `storageSource` when you call `createFunction()` or `updateFunction()`.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function uploadLocalSource(projectId, region, zipPath) {\n  const parent = `projects/${projectId}/locations/${region}`;\n  const [upload] = await client.generateUploadUrl({parent});\n\n  const body = await fs.readFile(zipPath);\n  const response = await fetch(upload.uploadUrl, {\n    method: 'PUT',\n    headers: {\n      'Content-Type': 'application/zip',\n    },\n    body,\n  });\n\n  if (!response.ok) {\n    throw new Error(`Upload failed: ${response.status} ${response.statusText}`);\n  }\n\n  return upload.storageSource;\n}\n```\n\nUse the returned storage source in a later create request:\n\n```javascript\nconst storageSource = await uploadLocalSource(\n  process.env.GOOGLE_CLOUD_PROJECT,\n  process.env.GOOGLE_CLOUD_REGION || 'us-central1',\n  './function-source.zip'\n);\n\nconst [operation] = await client.createFunction({\n  parent,\n  functionId: 'hello-function',\n  function: {\n    buildConfig: {\n      runtime: 'nodejs22',\n      entryPoint: 'helloHttp',\n      source: {\n        storageSource,\n      },\n    },\n    serviceConfig: {\n      timeoutSeconds: 60,\n    },\n  },\n});\n\nawait operation.promise();\n```\n\n### Delete A Function\n\nDelete is also a long-running operation.\n\n```javascript\nconst {v2} = require('@google-cloud/functions');\n\nconst client = new v2.FunctionServiceClient();\n\nasync function deleteFunction(projectId, region, functionId) {\n  const name = `projects/${projectId}/locations/${region}/functions/${functionId}`;\n  const [operation] = await client.deleteFunction({name});\n  await operation.promise();\n}\n```\n\n## Legacy `v1` Surface\n\nUse `v1` only when you are working with 1st gen functions or the legacy synchronous invoke API.\n\n### Call A 1st Gen Function Directly\n\n`callFunction()` is part of the v1 surface. Do not use this for normal HTTP-triggered 2nd gen functions. For deployed HTTP endpoints, send a normal HTTP request to the function URL instead.\n\n```javascript\nconst {v1} = require('@google-cloud/functions');\n\nconst client = new v1.CloudFunctionsServiceClient();\n\nasync function callFirstGenFunction(projectId, region, functionId, payload) {\n  const name = `projects/${projectId}/locations/${region}/functions/${functionId}`;\n\n  const [response] = await client.callFunction({\n    name,\n    data: JSON.stringify(payload),\n  });\n\n  if (response.error) {\n    throw new Error(response.error);\n  }\n\n  return response.result;\n}\n```\n\n## Configuration Notes\n\n- Keep `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_REGION` in configuration instead of scattering literal strings through deployment code.\n- `buildConfig` controls build-time settings such as runtime, entry point, worker pool, and source location.\n- `serviceConfig` controls execution-side settings such as memory, timeout, instance counts, service account, ingress, and secrets.\n- Mutating methods like `createFunction()`, `updateFunction()`, and `deleteFunction()` return long-running operations. Wait for `operation.promise()` before assuming the change is complete.\n- The signed upload URL flow and the Cloud Storage archive flow use different archive formats: signed upload uses a zip file, while `storageSource.object` in Cloud Storage must be a `.tar.gz` archive.\n\n## Common Pitfalls\n\n- The package name is `@google-cloud/functions`, but the main clients live under versioned namespaces: `v2.FunctionServiceClient` and `v1.CloudFunctionsServiceClient`.\n- This is an admin SDK. It manages Cloud Functions resources; it does not replace plain HTTP requests to a deployed function URL.\n- For `getFunction()`, `updateFunction()`, and `deleteFunction()`, use a full resource name like `projects/.../locations/.../functions/...`.\n- `updateFunction()` without an explicit field mask can update more than you intended.\n- `generateUploadUrl()` returns a signed URL for a zip upload. That upload request should not include an `Authorization` header.\n- `listFunctionsAsync()` and `listRuntimesAsync()` are usually the simplest way to iterate through pages.\n- `callFunction()` is a v1-only workflow for legacy 1st gen usage, not a general-purpose invoke method for 2nd gen HTTP functions.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/functions` `4.2.1`.\n- The package exposes both `v1` and `v2` clients under one npm package. Prefer `v2` for current 2nd gen management code and keep `v1` only for intentional 1st gen compatibility.\n- Cloud Functions runtime names change over time. Use `listRuntimesAsync()` when you need a current supported runtime list instead of hard-coding old runtime values.\n\n## Official Sources\n\n- Node.js client reference root: `https://cloud.google.com/nodejs/docs/reference/functions/latest`\n- Cloud Functions v2 REST reference: `https://cloud.google.com/functions/docs/reference/rest/v2/projects.locations.functions`\n- Cloud Functions v1 REST reference: `https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions`\n- Application Default Credentials overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- ADC search order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/functions`\n"
  },
  {
    "path": "content/google/docs/functions/python/DOC.md",
    "content": "---\nname: functions\ndescription: \"Google Cloud Functions Python client for managing and deploying 1st gen and 2nd gen Cloud Functions resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.22.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,functions,cloud-functions,gcp,serverless\"\n---\n\n# Google Cloud Functions Python Client\n\nUse `google-cloud-functions` when you need the Google Cloud control-plane client for Cloud Functions from Python: list functions, inspect config, discover runtimes, deploy updates, and manage IAM. Prefer `functions_v2` for current 2nd gen workflows. Use `functions_v1` only when you are intentionally working with legacy 1st gen functions or the v1-only `call_function` API.\n\n```python\nfrom google.cloud import functions_v2\n```\n\n## What This Package Is For\n\nThis package is an admin SDK, not a runtime helper for function handler code.\n\nUse it to:\n\n- list and inspect deployed functions\n- create, update, and delete functions\n- discover supported runtimes\n- manage IAM and deployment metadata\n- generate signed upload or download URLs for source bundles\n\nDo not use it to call an HTTP-triggered function URL. For that, send a normal HTTP request to the deployed endpoint. The one direct invocation helper in this package, `call_function`, is part of the v1 client surface for legacy 1st gen functions.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-functions==1.22.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-functions==1.22.0\"\npoetry add \"google-cloud-functions==1.22.0\"\n```\n\n## Setup And Authentication\n\nTypical prerequisites:\n\n- a Google Cloud project with billing enabled\n- the Cloud Functions API enabled\n- IAM permissions for the functions and locations you need to manage\n- a chosen region such as `us-central1`\n\nThe client uses Application Default Credentials (ADC). For local development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n```\n\nIf you must use a credential file explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n```\n\nFor production on Google Cloud, prefer an attached service account instead of shipping key files. ADC checks, in order, `GOOGLE_APPLICATION_CREDENTIALS`, the local ADC file created by `gcloud auth application-default login`, then the attached service account from the metadata server.\n\nExplicit credentials also work:\n\n```python\nfrom google.cloud import functions_v2\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = functions_v2.FunctionServiceClient(credentials=credentials)\n```\n\n## Client Structure\n\nThe package exposes both generations:\n\n- `functions_v2.FunctionServiceClient`: preferred for current deployments and admin workflows\n- `functions_v2.FunctionServiceAsyncClient`: async variant\n- `functions_v1.CloudFunctionsServiceClient`: legacy 1st gen surface, including `call_function`\n\nImportant behavior:\n\n- Most mutating methods return a long-running operation. Call `operation.result(...)` and wait.\n- Resource names are usually full paths like `projects/my-project/locations/us-central1/functions/my-fn`.\n- The client has helper builders such as `common_location_path()` and `function_path()`.\n- Use either flattened arguments or `request=...`, not both in the same call.\n\n## Core Usage\n\n### Create a v2 client and location parent\n\n```python\nimport os\nfrom google.cloud import functions_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nregion = os.environ.get(\"GOOGLE_CLOUD_REGION\", \"us-central1\")\n\nclient = functions_v2.FunctionServiceClient()\nparent = client.common_location_path(project_id, region)\n```\n\n### List functions in a region\n\n```python\nfor fn in client.list_functions(parent=parent):\n    uri = fn.service_config.uri if fn.service_config else None\n    print(fn.name, fn.environment, fn.state, uri)\n```\n\n### Get one function by resource name\n\n```python\nfunction_name = client.function_path(project_id, region, \"hello-function\")\nfn = client.get_function(name=function_name)\n\nprint(fn.name)\nprint(fn.build_config.runtime)\nprint(fn.service_config.service_account_email)\nprint(fn.service_config.uri)\n```\n\n### Discover supported runtimes\n\nUse this instead of hard-coding a runtime string when you are generating deploy code:\n\n```python\nfor runtime in client.list_runtimes(parent=parent):\n    print(runtime.name, runtime.environment, runtime.stage)\n```\n\n### Update a deployed function safely\n\n`update_function` accepts a `FieldMask`. Use it. Without a mask, the request updates all fields present on the function object.\n\n```python\nfrom google.cloud import functions_v2\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nfunction_name = client.function_path(project_id, region, \"hello-function\")\nfn = client.get_function(name=function_name)\n\nfn.service_config.environment_variables[\"APP_ENV\"] = \"prod\"\nfn.service_config.max_instance_count = 5\n\noperation = client.update_function(\n    request=functions_v2.UpdateFunctionRequest(\n        function=fn,\n        update_mask=FieldMask(\n            paths=[\n                \"service_config.environment_variables\",\n                \"service_config.max_instance_count\",\n            ]\n        ),\n    )\n)\n\nupdated = operation.result(timeout=1800)\nprint(updated.update_time)\n```\n\n### Create a function from source already in Cloud Storage\n\nFor `StorageSource`, the referenced object is a gzipped archive (`.tar.gz`), not a local source tree.\n\n```python\nfrom google.cloud import functions_v2\n\nfunction_id = \"hello-function\"\n\nfunction = functions_v2.Function(\n    build_config=functions_v2.BuildConfig(\n        runtime=\"python312\",\n        entry_point=\"hello_http\",\n        source=functions_v2.Source(\n            storage_source=functions_v2.StorageSource(\n                bucket=\"my-source-bucket\",\n                object_=\"hello-function.tar.gz\",\n            )\n        ),\n    ),\n    service_config=functions_v2.ServiceConfig(\n        available_memory=\"512M\",\n        timeout_seconds=60,\n        environment_variables={\"APP_ENV\": \"prod\"},\n    ),\n)\n\noperation = client.create_function(\n    parent=parent,\n    function_id=function_id,\n    function=function,\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\nprint(created.service_config.uri)\n```\n\n### Generate an upload URL for local source packaging\n\nIf your source bundle is local instead of already in Cloud Storage, generate a signed upload URL first:\n\n```python\nupload = client.generate_upload_url(parent=parent)\nprint(upload.upload_url)\n```\n\nImportant constraints from the official docs:\n\n- upload a zip file to the signed URL\n- send `content-type: application/zip`\n- do not send an `Authorization` header with that upload request\n\nAfter the upload completes, use the returned upload URL in the create or update flow.\n\n### Delete a function\n\n```python\nfunction_name = client.function_path(project_id, region, \"hello-function\")\noperation = client.delete_function(name=function_name)\noperation.result(timeout=1800)\n```\n\n## Legacy V1 Surface\n\nUse `functions_v1` only if you need the 1st gen API shape:\n\n```python\nfrom google.cloud import functions_v1\n\nclient = functions_v1.CloudFunctionsServiceClient()\n```\n\nReasons to stay on v1:\n\n- you are managing existing 1st gen functions\n- you need `call_function`\n- you are working with older deployment fields or migration flows\n\nDo not mix v1 and v2 request objects in the same workflow. Pick the surface that matches the deployed function generation.\n\n## Configuration Notes\n\n- Keep `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_REGION` in config, not inline strings.\n- If you accept customer-supplied credential JSON or files, review Google’s security guidance before loading them directly.\n- `service_config` controls execution-side settings such as memory, timeout, instance counts, service account, ingress, and secret environment variables.\n- `build_config` controls build-time concerns such as runtime, entry point, source location, worker pool, and build-time environment variables.\n- 2nd gen functions are backed by Cloud Run service configuration. Expect important fields such as the deployed URI to live under `service_config`.\n- If you enable library logging, Google’s client library logging can be activated with `GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google`.\n\n## Common Pitfalls\n\n- The package name is `google-cloud-functions`, but the main imports are `google.cloud.functions_v2` and `google.cloud.functions_v1`.\n- This library manages Cloud Functions resources. It does not replace plain HTTP requests to a deployed function URL.\n- For `get`, `update`, and `delete`, use full resource names like `projects/.../locations/.../functions/...`, not just `my-function`.\n- `update_function` without a `FieldMask` updates everything present in the request object.\n- `generate_upload_url()` is for a signed upload flow; the upload request must not include an `Authorization` header.\n- `StorageSource.object_` expects a `.tar.gz` archive in Cloud Storage, while the signed upload URL flow expects a zip upload.\n- Long-running operations are the normal path for create, update, and delete. Do not assume the resource is ready until `operation.result()` returns.\n- If your code forks processes, create client instances after `os.fork()` or after `multiprocessing` starts the child process.\n- 2nd gen and 1st gen fields are different enough that copying old blog examples blindly usually fails.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `1.22.0` as the latest release, published on January 15, 2026.\n- As of March 12, 2026, some Google Cloud docs pages still show `1.21.0` as the latest on overview or changelog pages even though the class reference pages and PyPI already expose `1.22.0`. Trust PyPI and the class pages over the lagging overview when pinning the package version.\n- The changelog page for `latest` currently tops out at `1.21.0`, where Google notes Python 3.14 support and deprecates the `credentials_file` argument.\n- The `BuildConfig.docker_registry` field is effectively Artifact Registry only for 2nd gen. The docs mark `CONTAINER_REGISTRY` as deprecated as of March 2025.\n- `ServiceConfig.security_level` only matters for 1st gen HTTP-triggered functions. 2nd gen functions are HTTPS-only.\n\n## Official Sources\n\n- Python reference root: https://cloud.google.com/python/docs/reference/cloudfunctions/latest\n- v2 client reference: https://docs.cloud.google.com/python/docs/reference/cloudfunctions/latest/google.cloud.functions_v2.services.function_service.FunctionServiceClient\n- v2 type reference: https://docs.cloud.google.com/python/docs/reference/cloudfunctions/latest/google.cloud.functions_v2.types.Function\n- REST reference: https://cloud.google.com/functions/docs/reference/rest/v2/projects.locations.functions\n- Authentication: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- ADC search order: https://cloud.google.com/docs/authentication/application-default-credentials\n- PyPI package page: https://pypi.org/project/google-cloud-functions/\n"
  },
  {
    "path": "content/google/docs/generativeai/python/DOC.md",
    "content": "---\nname: generativeai\ndescription: \"Legacy Google Gemini API Python SDK (`google-generativeai`) for text generation, chat, files, embeddings, and basic tool use\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.6\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,gemini,generative-ai,llm,python,pypi,legacy\"\n---\n\n# google-generativeai Python Package Guide\n\n## Golden Rule\n\n`google-generativeai` is the legacy Gemini Python SDK. Keep using it only when a project is already pinned to it. For new work, migrate to `google-genai`.\n\n- Package covered here: `google-generativeai==0.8.6`\n- Import path: `import google.generativeai as genai`\n- Python requirement on PyPI: `>=3.9`\n- Lifecycle status as of March 12, 2026: support ended on November 30, 2025, the package is marked inactive on PyPI, and the upstream repo was archived on December 16, 2025\n\n## Install\n\n```bash\npip install \"google-generativeai==0.8.6\"\n```\n\nIf you are starting a new integration, install `google-genai` instead. The public Gemini docs now default to the new SDK.\n\n## Auth And Setup\n\nCreate an API key in Google AI Studio, then configure the SDK before creating models.\n\n```bash\nexport GEMINI_API_KEY=\"your-api-key\"\n```\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n```\n\nNotes:\n\n- Google’s key guide says Gemini API libraries can pick up `GEMINI_API_KEY` or `GOOGLE_API_KEY`; if both are set, `GOOGLE_API_KEY` takes precedence.\n- For this legacy package, prefer calling `genai.configure(...)` explicitly so the active key is unambiguous.\n- Keep the API key server-side only. Google’s API key guide warns against exposing Gemini API keys in browser code.\n\n## Core Text Generation\n\nThe legacy SDK does not use a top-level client object. You create a `GenerativeModel` and call methods on it directly.\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nmodel = genai.GenerativeModel(\"gemini-2.0-flash\")\nresponse = model.generate_content(\"Tell me a story in 300 words.\")\nprint(response.text)\n```\n\nUse `response.text` for the common case.\n\n## Configure Generation\n\nAttach generation settings when you create the model, or pass them into calls as needed.\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nmodel = genai.GenerativeModel(\n    \"gemini-2.0-flash\",\n    system_instruction=\"You are a terse assistant for production incident summaries.\",\n    generation_config=genai.GenerationConfig(\n        temperature=0.2,\n        top_p=0.95,\n        top_k=40,\n        max_output_tokens=512,\n        stop_sequences=[\"\\n\\n\"],\n    ),\n)\n\nresponse = model.generate_content(\"Summarize this incident: ...\")\nprint(response.text)\n```\n\nCommon knobs:\n\n- `temperature`, `top_p`, `top_k` for sampling behavior\n- `max_output_tokens` to cap output size\n- `stop_sequences` to stop on delimiters\n- `system_instruction` for persistent model behavior\n\n## Structured JSON Output\n\n`google-generativeai` supports schema-constrained JSON output through `GenerationConfig`.\n\n```python\nimport os\nimport typing_extensions as typing\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nclass CountryInfo(typing.TypedDict):\n    name: str\n    capital: str\n    population: int\n\nmodel = genai.GenerativeModel(\"gemini-1.5-flash\")\nresponse = model.generate_content(\n    \"Give me information about Japan.\",\n    generation_config=genai.GenerationConfig(\n        response_mime_type=\"application/json\",\n        response_schema=CountryInfo,\n    ),\n)\n\nprint(response.text)\n```\n\nThis legacy SDK generally leaves you with JSON text to parse yourself. The newer `google-genai` SDK adds stronger typed parsing helpers such as `response.parsed`.\n\n## Multi-Turn Chat\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nmodel = genai.GenerativeModel(\"gemini-2.0-flash\")\nchat = model.start_chat()\n\nprint(chat.send_message(\"Tell me a story in 100 words.\").text)\nprint(chat.send_message(\"What happened after that?\").text)\n```\n\nUse chat objects when conversation state should remain server-managed across turns. For one-off tasks, plain `generate_content(...)` is simpler.\n\n## Function Calling\n\nAutomatic function calling in the legacy SDK is chat-only. New-SDK examples that pass tools directly to `client.models.generate_content(...)` do not translate 1:1.\n\n```python\nimport google.generativeai as genai\n\ndef get_current_weather(city: str) -> str:\n    return \"23C\"\n\nmodel = genai.GenerativeModel(\n    model_name=\"gemini-2.0-flash\",\n    tools=[get_current_weather],\n)\n\nchat = model.start_chat(enable_automatic_function_calling=True)\nresponse = chat.send_message(\"What is the weather in San Francisco?\")\nprint(response.text)\n```\n\nIf you need the current tool surface from Google’s latest docs, migrate instead of trying to backport new `google-genai` examples to this package.\n\n## Files And Multimodal Prompts\n\nThe legacy package exposes file helpers at module level.\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nuploaded = genai.upload_file(path=\"notes.txt\")\n\nmodel = genai.GenerativeModel(\"gemini-2.0-flash\")\nresponse = model.generate_content([\n    \"Summarize this file in 5 bullets.\",\n    uploaded,\n])\n\nprint(response.text)\n```\n\nRelated helpers:\n\n- `genai.list_files()`\n- `genai.get_file(name=...)`\n- `genai.delete_file(name=...)`\n\n## Token Counting And Embeddings\n\nCount tokens before large prompts:\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nmodel = genai.GenerativeModel(\"gemini-2.0-flash\")\ncount = model.count_tokens(\"The quick brown fox jumps over the lazy dog.\")\nprint(count)\n```\n\nCreate embeddings with the top-level helper:\n\n```python\nimport os\nimport google.generativeai as genai\n\ngenai.configure(api_key=os.environ[\"GEMINI_API_KEY\"])\n\nembedding = genai.embed_content(\n    model=\"models/gemini-embedding-001\",\n    content=\"Hello world\",\n)\n\nprint(embedding)\n```\n\n## Safety Settings\n\nFor basic safety overrides, pass a `safety_settings` mapping to `generate_content(...)`.\n\n```python\nresponse = model.generate_content(\n    \"say something bad\",\n    safety_settings={\n        \"HATE\": \"BLOCK_ONLY_HIGH\",\n        \"HARASSMENT\": \"BLOCK_ONLY_HIGH\",\n    },\n)\n```\n\nKeep the settings close to the specific call unless the whole model instance should share the same policy.\n\n## Common Pitfalls\n\n- Do not import `from google import genai` in code that is supposed to use this package. That import is for the newer `google-genai` SDK.\n- The current Gemini docs mostly show new-SDK examples. Translate them carefully: `client.models.generate_content(...)` becomes `GenerativeModel(...).generate_content(...)`, and `client.chats.create(...)` becomes `model.start_chat()`.\n- Legacy automatic function calling is only supported through `start_chat(enable_automatic_function_calling=True)`.\n- Support for this SDK ended on November 30, 2025. Do not expect new Gemini features or active maintenance.\n- The repository was archived on December 16, 2025. Treat bug reports and stale examples accordingly.\n- The official Gemini libraries page says legacy libraries do not provide access to recent features such as Live API and Veo.\n- Model names are server-side. Some newer model IDs may still work, but new SDK-only features and new helper types will not appear in this package.\n- The old SDK typically returns raw text or lower-level response objects. If you need parsed JSON objects, richer config types, or a stable client abstraction, migrate.\n\n## Version-Sensitive Notes\n\n- PyPI shows `0.8.6` as the latest and final published release, uploaded on December 16, 2025.\n- PyPI also marks the project as `Development Status :: 7 - Inactive`.\n- The current Google docs treat `google-generativeai` as a legacy library and recommend `google-genai` for all new Gemini work.\n- If your project is pinned below `0.8.6`, prefer exact-version installs and avoid copying examples written for `google-genai` without translating the client model, chat, file, and config APIs.\n- If you need Live API, Veo, typed parsed responses, or the maintained client abstraction, migrate to `google-genai` instead of upgrading within this legacy line.\n\n## Official Sources\n\n- Gemini API docs: https://ai.google.dev/gemini-api/docs\n- Gemini API libraries page: https://ai.google.dev/gemini-api/docs/libraries\n- Migration guide: https://ai.google.dev/gemini-api/docs/migrate\n- Gemini API key guide: https://ai.google.dev/gemini-api/docs/api-key\n- PyPI package page for `0.8.6`: https://pypi.org/project/google-generativeai/0.8.6/\n- Current PyPI project page: https://pypi.org/project/google-generativeai/\n- Archived upstream repository: https://github.com/google-gemini/deprecated-generative-ai-python\n"
  },
  {
    "path": "content/google/docs/gke-backup/python/DOC.md",
    "content": "---\nname: gke-backup\ndescription: \"Google Cloud Backup for GKE Python client for backup plans, on-demand backups, restore plans, and restores\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gke,backup,restore,kubernetes,gcp,adc\"\n---\n\n# Google Cloud Backup for GKE Python Client\n\n## What This Package Is\n\n`google-cloud-gke-backup` is the generated Python client for the Backup for GKE control-plane API.\n\nUse it when Python code needs to:\n\n- create and list backup plans\n- start on-demand backups from a backup plan\n- create restore plans\n- start restores from existing backups\n\nThis package manages Backup for GKE resources. It does not talk to the Kubernetes API server inside your cluster.\n\n## Version Note\n\nThis guide covers package version `0.7.0`.\n\nAs of `2026-03-13`, upstream sources are slightly out of sync:\n\n- PyPI lists `google-cloud-gke-backup 0.7.0`\n- the Cloud Python reference under `/latest/` still renders as `latest (0.6.0)`\n\nThe examples below use the current GA `gke_backup_v1` client surface shown in the generated reference. If you depend on a field added very recently, verify it against your installed wheel as well as the rolling docs site.\n\nOfficial sources used for this guide:\n\n- `https://pypi.org/project/google-cloud-gke-backup/`\n- `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-backup`\n- `https://cloud.google.com/python/docs/reference/gkebackup/latest`\n- `https://cloud.google.com/python/docs/reference/gkebackup/latest/google.cloud.gke_backup_v1.services.backup_for_gke.BackupForGKEClient`\n- `https://cloud.google.com/python/docs/reference/gkebackup/latest/google.cloud.gke_backup_v1.types.BackupPlan`\n- `https://cloud.google.com/python/docs/reference/gkebackup/latest/google.cloud.gke_backup_v1.types.RestorePlan`\n- `https://cloud.google.com/python/docs/reference/gkebackup/latest/google.cloud.gke_backup_v1.types.RestoreConfig`\n- `https://cloud.google.com/kubernetes-engine/docs/add-on/backup-for-gke/how-to/get-started-kubectl`\n- `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n\n## Install\n\nInstall the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-gke-backup==0.7.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-gke-backup==0.7.0\"\npoetry add \"google-cloud-gke-backup==0.7.0\"\n```\n\n## Required Setup\n\nBefore using the client:\n\n1. Enable Backup for GKE in the target Google Cloud project.\n2. Make sure the calling identity has permission to manage Backup for GKE resources.\n3. Configure Application Default Credentials (ADC).\n\nEnable the API:\n\n```bash\ngcloud services enable gkebackup.googleapis.com\n```\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_BACKUP_LOCATION=\"us-central1\"\nexport GOOGLE_CLOUD_GKE_CLUSTER_LOCATION=\"us-central1-a\"\nexport GOOGLE_CLOUD_GKE_CLUSTER=\"primary\"\n```\n\nService account credentials via environment variable:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUse a zonal value such as `us-central1-a` for `GOOGLE_CLOUD_GKE_CLUSTER_LOCATION` when the source cluster is zonal. Use a regional value such as `us-central1` when the cluster is regional.\n\n## Imports And Client Creation\n\n```python\nimport os\n\nfrom google.cloud import gke_backup_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nbackup_location = os.environ[\"GOOGLE_CLOUD_BACKUP_LOCATION\"]\ncluster_location = os.environ[\"GOOGLE_CLOUD_GKE_CLUSTER_LOCATION\"]\ncluster_id = os.environ[\"GOOGLE_CLOUD_GKE_CLUSTER\"]\n\nbackup_parent = f\"projects/{project_id}/locations/{backup_location}\"\ncluster_name = (\n    f\"projects/{project_id}/locations/{cluster_location}/clusters/{cluster_id}\"\n)\n\nclient = gke_backup_v1.BackupForGKEClient()\n```\n\n## Resource Naming\n\nThe generated client expects fully qualified resource names.\n\nUse these formats:\n\n- backup location parent: `projects/{project_id}/locations/{backup_location}`\n- cluster name: `projects/{project_id}/locations/{cluster_location}/clusters/{cluster_id}`\n- backup plan name: `projects/{project_id}/locations/{backup_location}/backupPlans/{backup_plan_id}`\n- backup name: `projects/{project_id}/locations/{backup_location}/backupPlans/{backup_plan_id}/backups/{backup_id}`\n- restore plan name: `projects/{project_id}/locations/{backup_location}/restorePlans/{restore_plan_id}`\n\nImportant location pitfall:\n\n- the backup plan lives under the Backup for GKE location\n- the protected cluster resource can be regional or zonal\n- do not assume the plan parent and the cluster location use the same string\n\n## Core Usage\n\n### List backup plans\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\n\nfor plan in client.list_backup_plans(parent=backup_parent):\n    print(plan.name)\n    print(plan.cluster)\n```\n\n### Create a backup plan\n\nThis example creates a daily backup plan that covers all namespaces and includes persistent volume data and Secrets.\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\n\nbackup_plan = gke_backup_v1.BackupPlan(\n    cluster=cluster_name,\n    retention_policy=gke_backup_v1.BackupPlan.RetentionPolicy(\n        backup_retain_days=7,\n    ),\n    backup_schedule=gke_backup_v1.BackupPlan.Schedule(\n        cron_schedule=\"0 3 * * *\",\n    ),\n    backup_config=gke_backup_v1.BackupPlan.BackupConfig(\n        all_namespaces=True,\n        include_volume_data=True,\n        include_secrets=True,\n    ),\n)\n\noperation = client.create_backup_plan(\n    parent=backup_parent,\n    backup_plan=backup_plan,\n    backup_plan_id=\"daily-plan\",\n)\n\ncreated_plan = operation.result()\nprint(created_plan.name)\n```\n\n`create_backup_plan()` returns a long-running operation. Call `.result()` before assuming the plan exists.\n\n### Start an on-demand backup\n\nAn on-demand backup is created under an existing backup plan. The plan controls scope and retention, so the `Backup` request body can stay minimal.\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\nbackup_plan_name = (\n    f\"{backup_parent}/backupPlans/daily-plan\"\n)\n\noperation = client.create_backup(\n    parent=backup_plan_name,\n    backup=gke_backup_v1.Backup(),\n    backup_id=\"before-upgrade-20260313\",\n)\n\nbackup = operation.result()\nprint(backup.name)\n```\n\n### List backups for a plan\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\nbackup_plan_name = (\n    f\"{backup_parent}/backupPlans/daily-plan\"\n)\n\nfor backup in client.list_backups(parent=backup_plan_name):\n    print(backup.name)\n    print(backup.state)\n```\n\n### Create a restore plan\n\nThe restore plan points at a backup plan and describes how namespaced resources and volume data should be restored into a target cluster.\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\ntarget_cluster_name = (\n    f\"projects/{project_id}/locations/{cluster_location}/clusters/restore-target\"\n)\n\nrestore_plan = gke_backup_v1.RestorePlan(\n    backup_plan=f\"{backup_parent}/backupPlans/daily-plan\",\n    cluster=target_cluster_name,\n    restore_config=gke_backup_v1.RestoreConfig(\n        all_namespaces=True,\n        namespaced_resource_restore_mode=(\n            gke_backup_v1.RestoreConfig.NamespacedResourceRestoreMode\n            .MERGE_SKIP_ON_CONFLICT\n        ),\n        volume_data_restore_policy=(\n            gke_backup_v1.RestoreConfig.VolumeDataRestorePolicy\n            .RESTORE_VOLUME_DATA_FROM_BACKUP\n        ),\n    ),\n)\n\noperation = client.create_restore_plan(\n    parent=backup_parent,\n    restore_plan=restore_plan,\n    restore_plan_id=\"default-restore-plan\",\n)\n\ncreated_restore_plan = operation.result()\nprint(created_restore_plan.name)\n```\n\n### Start a restore from a backup\n\n```python\nfrom google.cloud import gke_backup_v1\n\nclient = gke_backup_v1.BackupForGKEClient()\nrestore_plan_name = (\n    f\"{backup_parent}/restorePlans/default-restore-plan\"\n)\nbackup_name = (\n    f\"{backup_parent}/backupPlans/daily-plan/backups/before-upgrade-20260313\"\n)\n\noperation = client.create_restore(\n    parent=restore_plan_name,\n    restore=gke_backup_v1.Restore(\n        backup=backup_name,\n    ),\n    restore_id=\"restore-20260313\",\n)\n\nrestore = operation.result()\nprint(restore.name)\n```\n\n## Important Pitfalls\n\n### Long-running operations\n\nCreate and restore calls return long-running operations. Wait for `.result()` before using the new resource in later calls.\n\n### Backup scope is a oneof\n\n`BackupPlan.BackupConfig` treats resource scope as a oneof. Pick exactly one of these:\n\n- `all_namespaces`\n- `selected_namespaces`\n- `selected_applications`\n\nDo not set more than one in the same request.\n\n### Restore config requires an explicit namespaced-resource mode\n\n`RestoreConfig.namespaced_resource_restore_mode` is required. Set it deliberately instead of relying on defaults.\n\n### Be explicit about volume restoration\n\n`RestoreConfig.volume_data_restore_policy` controls whether persistent volume data is restored from backup data or left alone. Set it explicitly for restore automation so behavior is obvious from code review.\n\n### Prefer ADC over custom credential plumbing\n\nUse ADC with `BackupForGKEClient()` for the common case. For local development, `gcloud auth application-default login` is the normal setup path. For non-interactive environments, set `GOOGLE_APPLICATION_CREDENTIALS` to a service account key only when you actually need file-based credentials.\n"
  },
  {
    "path": "content/google/docs/gke-connect-gateway/python/DOC.md",
    "content": "---\nname: gke-connect-gateway\ndescription: \"Google Cloud GKE Connect Gateway Python client for generating kubeconfig access to registered fleet memberships\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gke,fleet,connect-gateway,kubernetes,adc\"\n---\n\n# google-cloud-gke-connect-gateway Python Package Guide\n\n## What This Package Does\n\n`google-cloud-gke-connect-gateway` is the Python client for the GKE Connect Gateway control API.\n\nUse it when Python code needs to generate a Connect Gateway `kubeconfig` for an existing fleet membership so your app, job runner, or automation can call `kubectl` or other Kubernetes clients against a registered cluster.\n\nThis package does not create clusters, register memberships, or manage Kubernetes resources directly. Its core job is to call `GatewayControlClient.generate_credentials(...)` for a membership you already have access to.\n\n## Version Note\n\nThis guide covers package version `0.12.0`, which PyPI lists as the current release uploaded on `2026-01-15`.\n\nThe rolling Google Cloud Python reference site currently lags behind PyPI for this package:\n\n- PyPI shows `0.12.0`\n- the `latest` Python client reference currently renders `GatewayControlClient` as `0.11.0`\n- the `latest` changelog page currently goes through `0.11.0`\n\nThe current documented surface is still the same practical one for new code:\n\n- use `google.cloud.gkeconnect.gateway_v1`\n- use `GatewayControlClient`\n- call `generate_credentials`\n- expect REST transport, not gRPC\n\nGoogle's changelog also records two important recent breaking changes that still affect current usage:\n\n- `0.9.0` removed the nonfunctional `GatewayService` surface and replaced it with `GatewayControl`\n- `0.10.0` removed gRPC-based async support and switched the default transport to `rest`\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-gke-connect-gateway==0.12.0\"\n```\n\nPyPI currently lists support for Python `>=3.7`, including Python `3.14`.\n\n## Required Setup\n\nBefore using the client, the target cluster must already be registered to a fleet membership and Connect Gateway must be enabled for the project.\n\nEnable the required APIs:\n\n```bash\nexport PROJECT_ID=\"your-project-id\"\n\ngcloud services enable --project=\"${PROJECT_ID}\" \\\n  connectgateway.googleapis.com \\\n  gkeconnect.googleapis.com \\\n  gkehub.googleapis.com \\\n  cloudresourcemanager.googleapis.com\n```\n\nAuthenticate with Application Default Credentials for local development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"${PROJECT_ID}\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"${PROJECT_ID}\"\n```\n\nThe calling principal needs both:\n\n- `roles/gkehub.viewer` so it can retrieve membership kubeconfigs\n- one of `roles/gkehub.gatewayReader`, `roles/gkehub.gatewayEditor`, or `roles/gkehub.gatewayAdmin` to use Connect Gateway\n\nIf your workflow needs `kubectl exec`, `kubectl attach`, `kubectl cp`, or `kubectl port-forward`, Google’s product docs call out an extra requirement:\n\n- the IAM permission `gkehub.gateway.stream`, which is included in `roles/gkehub.gatewayAdmin`\n- matching Kubernetes RBAC permissions on the target cluster\n\n## Membership Names\n\n`generate_credentials` requires the full fleet membership resource name, not just the cluster name.\n\nUse this format:\n\n```text\nprojects/{project_id}/locations/global/memberships/{membership_id}\n```\n\nIf you do not already know the membership ID, Google’s product docs recommend discovering it with:\n\n```bash\ngcloud container fleet memberships list\n```\n\n## Initialize The Client\n\nDefault client with ADC:\n\n```python\nfrom google.cloud.gkeconnect import gateway_v1\n\nclient = gateway_v1.GatewayControlClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud.gkeconnect import gateway_v1\n\nclient = gateway_v1.GatewayControlClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nBe explicit about REST if you want the transport choice in code:\n\n```python\nfrom google.cloud.gkeconnect import gateway_v1\n\nclient = gateway_v1.GatewayControlClient(transport=\"rest\")\n```\n\n## Core Workflow\n\n### Generate A Kubeconfig For A Fleet Membership\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud.gkeconnect import gateway_v1\n\nPROJECT_ID = \"your-project-id\"\nMEMBERSHIP_ID = \"your-membership\"\nMEMBERSHIP_NAME = (\n    f\"projects/{PROJECT_ID}/locations/global/memberships/{MEMBERSHIP_ID}\"\n)\n\nclient = gateway_v1.GatewayControlClient()\n\nrequest = gateway_v1.GenerateCredentialsRequest(\n    name=MEMBERSHIP_NAME,\n)\n\nresponse = client.generate_credentials(request=request)\n\nkubeconfig_path = Path(\"connect-gateway-kubeconfig.yaml\")\nkubeconfig_path.write_bytes(response.kubeconfig)\n\nprint(f\"Gateway endpoint: {response.endpoint}\")\nprint(f\"Wrote kubeconfig to {kubeconfig_path.resolve()}\")\n```\n\n`GenerateCredentialsResponse` contains:\n\n- `kubeconfig`: a full serialized YAML kubeconfig as bytes\n- `endpoint`: the generated cluster URI exposed through Connect Gateway\n\n### Use The Returned Kubeconfig With kubectl\n\n```bash\nKUBECONFIG=./connect-gateway-kubeconfig.yaml kubectl get namespaces\n```\n\nOr from Python:\n\n```python\nimport subprocess\nfrom pathlib import Path\n\nkubeconfig_path = Path(\"connect-gateway-kubeconfig.yaml\")\n\nsubprocess.run(\n    [\"kubectl\", \"--kubeconfig\", str(kubeconfig_path), \"get\", \"namespaces\"],\n    check=True,\n)\n```\n\n### Set A Default Namespace In The Generated Context\n\nIf you want the generated kubeconfig context to default to a namespace, set `kubernetes_namespace` on the request:\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud.gkeconnect import gateway_v1\n\nmembership_name = \"projects/your-project-id/locations/global/memberships/your-membership\"\n\nclient = gateway_v1.GatewayControlClient()\n\nrequest = gateway_v1.GenerateCredentialsRequest(\n    name=membership_name,\n    kubernetes_namespace=\"production\",\n)\n\nresponse = client.generate_credentials(request=request)\nPath(\"connect-gateway-prod.yaml\").write_bytes(response.kubeconfig)\n```\n\n### Generate A Windows-Specific Kubeconfig\n\nThe request type exposes an `operating_system` field for kubeconfigs that need Windows-specific behavior:\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud.gkeconnect import gateway_v1\n\nmembership_name = \"projects/your-project-id/locations/global/memberships/your-membership\"\n\nclient = gateway_v1.GatewayControlClient()\n\nrequest = gateway_v1.GenerateCredentialsRequest(\n    name=membership_name,\n    operating_system=(\n        gateway_v1.GenerateCredentialsRequest.OperatingSystem.OPERATING_SYSTEM_WINDOWS\n    ),\n)\n\nresponse = client.generate_credentials(request=request)\nPath(\"connect-gateway-windows.yaml\").write_bytes(response.kubeconfig)\n```\n\n### Force Connect Agent-Based Transport\n\nFor cluster types that can use more than one underlying transport, the request also supports `force_use_agent=True`:\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud.gkeconnect import gateway_v1\n\nmembership_name = \"projects/your-project-id/locations/global/memberships/your-membership\"\n\nclient = gateway_v1.GatewayControlClient()\n\nrequest = gateway_v1.GenerateCredentialsRequest(\n    name=membership_name,\n    force_use_agent=True,\n)\n\nresponse = client.generate_credentials(request=request)\nPath(\"connect-gateway-agent.yaml\").write_bytes(response.kubeconfig)\n```\n\nUse this only when you intentionally want Connect Agent transport and the agent is installed on the cluster. The request reference says leaving it unset is equivalent to `False`.\n\n## Important Pitfalls\n\n- This library is for generating access credentials, not for listing or registering memberships. Membership discovery and fleet administration are separate APIs and tools.\n- Pass the full membership resource name. A bare cluster name is not enough.\n- Write `response.kubeconfig` as bytes. It is already a complete serialized kubeconfig payload.\n- New code should use `gateway_v1.GatewayControlClient`. The old `GatewayService` surface was removed.\n- Do not plan around an async client in the current line. Google’s `0.10.0` changelog explicitly says the async client was removed when gRPC support was dropped.\n- `kubectl exec`, `attach`, `cp`, and `port-forward` need more than basic gateway access. Google’s product docs require `gkehub.gateway.stream` and matching Kubernetes RBAC.\n- If access fails even though the Google Cloud IAM roles look correct, check cluster-side RBAC next. Connect Gateway authorization is layered on top of Kubernetes authorization.\n\n## When To Use This Package Instead Of gcloud\n\nIf you only need an interactive one-off kubeconfig, `gcloud container fleet memberships get-credentials` is usually simpler.\n\nUse `google-cloud-gke-connect-gateway` when you need the same workflow inside Python code, such as:\n\n- CI/CD jobs that generate short-lived kubeconfig files on demand\n- internal automation that targets fleet memberships by name\n- services that need to hand a generated kubeconfig to `kubectl` or another Kubernetes client process\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-gke-connect-gateway/\n- Python client reference root: https://docs.cloud.google.com/python/docs/reference/connectgateway/latest\n- `GatewayControlClient` reference: https://docs.cloud.google.com/python/docs/reference/connectgateway/latest/google.cloud.gkeconnect.gateway_v1.services.gateway_control.GatewayControlClient\n- Changelog: https://docs.cloud.google.com/python/docs/reference/connectgateway/latest/changelog\n- Connect Gateway setup guide: https://cloud.google.com/kubernetes-engine/enterprise/multicluster-management/gateway/setup\n- Connect Gateway usage guide: https://cloud.google.com/kubernetes-engine/enterprise/multicluster-management/gateway/using\n- GKE Hub IAM roles: https://cloud.google.com/iam/docs/roles-permissions/gkehub\n- Application Default Credentials: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/gke-hub/python/DOC.md",
    "content": "---\nname: gke-hub\ndescription: \"Google Cloud GKE Hub Python client for fleet memberships and features with ADC setup, location-aware resource names, and long-running operation handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.21.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gke-hub,fleet,anthos,gke,adc\"\n---\n\n# google-cloud-gke-hub Python Package Guide\n\n## What This Package Is\n\n`google-cloud-gke-hub` is the official Google Cloud Python client for the GKE Hub / Fleet control-plane API.\n\nUse it when Python code needs to:\n\n- list, inspect, create, update, or delete fleet memberships\n- list or inspect fleet features\n- automate fleet registration flows around GKE Hub resources\n\nDo not use this package to manage Kubernetes objects inside a cluster. For Deployments, Services, Pods, and other Kubernetes resources, use the Kubernetes API after you have cluster credentials.\n\nThe API surface is centered on two resource types:\n\n- `Membership`: a registered cluster in a fleet\n- `Feature`: a fleet-level capability such as config or multi-cluster integrations\n\n## Version Note\n\nThis guide targets package version `1.21.0`.\n\nAs of `2026-03-13`, upstream sources do not line up perfectly:\n\n- PyPI shows `1.22.0` as the newest release, published on `2026-03-12`\n- the current `latest` Python reference page still labels `GkeHubClient` as `1.20.0`\n- the current `latest` changelog page reaches `1.19.0`\n\nPractical implication:\n\n- the examples below stick to the stable `google.cloud.gkehub_v1` surface that is present in the current reference docs\n- if you are pinned to `1.21.0`, keep your installed wheel authoritative when a docs page shows an older version badge\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-gke-hub==1.21.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-gke-hub==1.21.0\"\npoetry add \"google-cloud-gke-hub==1.21.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Required Setup\n\nThe package quickstart requires the usual Google Cloud setup:\n\n1. Select or create a Google Cloud project.\n2. Enable billing.\n3. Enable GKE Hub.\n4. Set up Application Default Credentials.\n\nFor cluster-registration workflows, Google’s fleet prerequisites also call out the companion APIs commonly needed around Hub membership setup:\n\n```bash\ngcloud services enable \\\n  --project=\"${GOOGLE_CLOUD_PROJECT}\" \\\n  container.googleapis.com \\\n  gkeconnect.googleapis.com \\\n  gkehub.googleapis.com \\\n  cloudresourcemanager.googleapis.com\n```\n\nIf you plan to enable fleet Workload Identity, also enable:\n\n```bash\ngcloud services enable \\\n  --project=\"${GOOGLE_CLOUD_PROJECT}\" \\\n  iam.googleapis.com\n```\n\nLocal ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nService account credentials file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n## Environment And Client Initialization\n\nExample shell setup:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-fleet-host-project\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n\nexport GKE_CLUSTER_PROJECT=\"my-fleet-host-project\"\nexport GKE_CLUSTER_LOCATION=\"us-central1\"\nexport GKE_CLUSTER_NAME=\"primary\"\n```\n\nBasic client setup:\n\n```python\nimport os\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nmembership_location = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\n\nclient = gkehub_v1.GkeHubClient()\nparent = client.common_location_path(project_id, membership_location)\nall_memberships_parent = client.common_location_path(project_id, \"-\")\nfeatures_parent = client.common_location_path(project_id, \"global\")\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import gkehub_v1\n\nclient = gkehub_v1.GkeHubClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nAsync client:\n\n```python\nfrom google.cloud import gkehub_v1\n\nclient = gkehub_v1.GkeHubAsyncClient()\n```\n\n## Resource Naming And Locations\n\nUse the helper methods on `GkeHubClient` instead of hand-building resource names when you can:\n\n- membership name: `client.membership_path(project, location, membership)`\n- feature name: `client.feature_path(project, location, feature)`\n- parent location: `client.common_location_path(project, location)`\n\nImportant location rules from the current reference docs:\n\n- memberships are available in `global` and regional locations\n- features are only available in `global`\n- `list_memberships(parent=\"projects/*/locations/-\")` lists memberships across all regions for a project\n\nFor GKE-on-Google-Cloud memberships, the cluster reference must use the full Container API resource link format:\n\n```text\n//container.googleapis.com/projects/PROJECT_ID/locations/CLUSTER_LOCATION/clusters/CLUSTER_NAME\n```\n\n## Core Usage\n\n### List memberships\n\nUse `locations/-` when you want all memberships in the project, regardless of membership location.\n\n```python\nimport os\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = gkehub_v1.GkeHubClient()\nparent = client.common_location_path(project_id, \"-\")\n\nfor membership in client.list_memberships(parent=parent):\n    print(membership.name)\n    print(membership.state.code)\n```\n\n### Get one membership\n\n```python\nimport os\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nmembership_location = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nmembership_id = \"primary\"\n\nclient = gkehub_v1.GkeHubClient()\nname = client.membership_path(project_id, membership_location, membership_id)\nmembership = client.get_membership(name=name)\n\nprint(membership.name)\nprint(membership.unique_id)\nprint(membership.endpoint.google_managed)\n```\n\n### Create a membership for a GKE cluster\n\nMembership creation is a long-running operation. Wait on `.result()` before assuming the membership exists.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nmembership_location = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\ncluster_project = os.getenv(\"GKE_CLUSTER_PROJECT\", project_id)\ncluster_location = os.environ[\"GKE_CLUSTER_LOCATION\"]\ncluster_name = os.environ[\"GKE_CLUSTER_NAME\"]\n\nclient = gkehub_v1.GkeHubClient()\nparent = client.common_location_path(project_id, membership_location)\nmembership_id = \"primary\"\n\ncluster_resource_link = (\n    f\"//container.googleapis.com/projects/{cluster_project}\"\n    f\"/locations/{cluster_location}/clusters/{cluster_name}\"\n)\n\nmembership = gkehub_v1.Membership(\n    labels={\"env\": \"dev\"},\n    endpoint=gkehub_v1.MembershipEndpoint(\n        gke_cluster=gkehub_v1.GkeCluster(\n            resource_link=cluster_resource_link,\n        )\n    ),\n)\n\noperation = client.create_membership(\n    request=gkehub_v1.CreateMembershipRequest(\n        parent=parent,\n        membership_id=membership_id,\n        resource=membership,\n        request_id=str(uuid.uuid4()),\n    )\n)\n\ncreated = operation.result()\nprint(created.name)\n```\n\n### Update membership labels\n\n`update_membership` requires a `FieldMask`. Only the masked fields are applied.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import gkehub_v1\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nmembership_location = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nmembership_id = \"primary\"\n\nclient = gkehub_v1.GkeHubClient()\nname = client.membership_path(project_id, membership_location, membership_id)\nmembership = client.get_membership(name=name)\n\nmembership.labels[\"team\"] = \"platform\"\n\noperation = client.update_membership(\n    request=gkehub_v1.UpdateMembershipRequest(\n        name=name,\n        resource=membership,\n        update_mask=field_mask_pb2.FieldMask(paths=[\"labels\"]),\n        request_id=str(uuid.uuid4()),\n    )\n)\n\nupdated = operation.result()\nprint(updated.labels)\n```\n\n### List and inspect features\n\nFeatures are global resources, so use `locations/global`.\n\n```python\nimport os\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = gkehub_v1.GkeHubClient()\nparent = client.common_location_path(project_id, \"global\")\n\nfor feature in client.list_features(parent=parent):\n    print(feature.name)\n    print(feature.labels)\n```\n\n```python\nimport os\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nfeature_id = \"configmanagement\"\n\nclient = gkehub_v1.GkeHubClient()\nname = client.feature_path(project_id, \"global\", feature_id)\nfeature = client.get_feature(name=name)\n\nprint(feature.name)\nprint(feature.resource_state.state)\n```\n\n### Delete a membership\n\nDeletion is also a long-running operation. If the membership still has subresources, the request can fail unless you intentionally set `force=True`.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import gkehub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nmembership_location = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nmembership_id = \"primary\"\n\nclient = gkehub_v1.GkeHubClient()\nname = client.membership_path(project_id, membership_location, membership_id)\n\noperation = client.delete_membership(\n    request=gkehub_v1.DeleteMembershipRequest(\n        name=name,\n        request_id=str(uuid.uuid4()),\n    )\n)\n\noperation.result()\nprint(\"Deleted\")\n```\n\n## Connect Agent And Generated Manifests\n\nThe client exposes `generate_connect_manifest()`, but the current reference docs explicitly say this method is used internally by Google-provided libraries and that most clients should not need to call it directly.\n\nIf you do need generated manifests:\n\n- `GenerateConnectManifestResponse.manifest` returns an ordered list of Kubernetes resources to apply\n- membership `kubernetes_resource.membership_resources` and `connect_resources` are only populated in the `Membership` returned from a successful `create_membership` or `update_membership` long-running operation\n- normal `get_membership()` and `list_memberships()` responses do not include those manifest payloads\n\n## Common Pitfalls\n\n- Do not use this package as a Kubernetes client. It manages fleet control-plane resources, not in-cluster objects.\n- Do not assume every GKE Hub resource is global. Features are global; memberships can be global or regional.\n- Do not assume a mutation is complete until you call `.result()` on the returned operation.\n- Do not build GKE cluster links from just the cluster name. Use the full `//container.googleapis.com/projects/.../locations/.../clusters/...` resource link.\n- Do not update memberships without an explicit `FieldMask`. The request contract is patch-style, and masked fields that you omit from `resource` are removed.\n- Prefer `request_id` for create, update, and delete calls so retries do not duplicate operations.\n- If you are automating around existing GKE registrations, remember that GKE clusters registered with `gcloud` are managed in the cluster’s own region; product docs also note that you cannot move a membership to a different location without unregistering and registering again.\n- Treat the rolling docs site as slightly behind PyPI for this package right now. The published wheel version and the installed client surface are the reliable source of truth for version pinning.\n\n## Optional Debug Logging\n\nGoogle’s package docs support opt-in environment-based logging:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nOr configure logging in code:\n\n```python\nimport logging\n\nbase_logger = logging.getLogger(\"google\")\nbase_logger.addHandler(logging.StreamHandler())\nbase_logger.setLevel(logging.DEBUG)\n```\n\nBe careful: the package docs note that RPC logs can contain sensitive information.\n\n## Official Sources\n\n- Python client overview: https://docs.cloud.google.com/python/docs/reference/gkehub/latest\n- `GkeHubClient` reference: https://docs.cloud.google.com/python/docs/reference/gkehub/latest/google.cloud.gkehub_v1.services.gke_hub.GkeHubClient\n- Package types: https://docs.cloud.google.com/python/docs/reference/gkehub/latest/google.cloud.gkehub_v1.types\n- GKE Hub RPC reference: https://cloud.google.com/kubernetes-engine/fleet-management/docs/reference/rpc/google.cloud.gkehub.v1\n- Fleet prerequisites: https://cloud.google.com/kubernetes-engine/fleet-management/docs/before-you-begin\n- Fleet creation overview: https://cloud.google.com/kubernetes-engine/enterprise/multicluster-management/fleet-creation\n- ADC setup: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- ADC search order: https://cloud.google.com/docs/authentication/application-default-credentials\n- PyPI package: https://pypi.org/project/google-cloud-gke-hub/\n"
  },
  {
    "path": "content/google/docs/gke-multicloud/python/DOC.md",
    "content": "---\nname: gke-multicloud\ndescription: \"Google Cloud GKE Multi-Cloud Python client for attached clusters and legacy AWS or Azure control-plane workflows with ADC, regional endpoints, token generation, and deprecation notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gke,multicloud,anthos,kubernetes,attached-clusters,aws,azure,adc\"\n---\n\n# google-cloud-gke-multicloud Python Package Guide\n\n## What This Package Is\n\n`google-cloud-gke-multicloud` is the official Google Cloud Python client for the GKE Multi-Cloud control-plane API.\n\nUse it when Python code needs to:\n\n- manage GKE attached clusters from Google Cloud\n- read cluster metadata from the Multi-Cloud API\n- generate short-lived access tokens for managed clusters\n- import an existing Fleet membership as an attached-cluster resource\n\nDo not use this package to manage Kubernetes objects like Deployments, Services, or Pods. Use `kubectl` or the Kubernetes Python client against the cluster API after you obtain cluster access.\n\n## Version Note\n\nThis guide covers package version `0.8.0`, which PyPI lists as the current release as of `2026-03-13`.\n\nThe upstream docs are slightly inconsistent right now:\n\n- PyPI lists `0.8.0`, uploaded on `2026-01-15`\n- the reference overview page under `latest` exposes `0.8.0`\n- many generated service and type pages under `latest` still render as `0.7.0`\n- the published changelog page currently stops at `0.7.0`\n\nPractical implication:\n\n- the import path and client surface below are current for the `google.cloud.gke_multicloud_v1` package\n- if you depend on a field added very recently, verify it against the installed wheel, not only the rolling docs pages\n\n## Install\n\nInstall the package:\n\n```bash\npython -m pip install \"google-cloud-gke-multicloud==0.8.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Required Setup\n\nThe package quickstart and product docs require the usual Google Cloud setup:\n\n1. Create or select a Google Cloud project.\n2. Enable billing.\n3. Enable the GKE Multi-Cloud API and related services.\n4. Configure Application Default Credentials.\n\nCommon environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-west1\"\n\n# Optional when you are not using local ADC or an attached service account.\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nEnable the APIs that the AWS, Azure, and attached-cluster setup docs all call out:\n\n```bash\ngcloud services enable gkemulticloud.googleapis.com\ngcloud services enable gkeconnect.googleapis.com\ngcloud services enable gkehub.googleapis.com\ngcloud services enable connectgateway.googleapis.com\ngcloud services enable cloudresourcemanager.googleapis.com\ngcloud services enable anthos.googleapis.com\ngcloud services enable logging.googleapis.com\ngcloud services enable monitoring.googleapis.com\ngcloud services enable opsconfigmonitoring.googleapis.com\ngcloud services enable kubernetesmetadata.googleapis.com\n```\n\nFor local development, set up ADC with your user account:\n\n```bash\ngcloud auth application-default login\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nGoogle’s ADC docs explicitly recommend user ADC or service account impersonation before long-lived key files.\n\n## Regional Endpoints And Client Creation\n\nThis API is regional. The generated Python samples say the clients may require regional endpoints, and in practice you should set `client_options.api_endpoint` explicitly to the Google Cloud administrative region you are using.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.environ[\"GOOGLE_CLOUD_LOCATION\"]  # example: us-west1\n\nclient_options = ClientOptions(\n    api_endpoint=f\"{LOCATION}-gkemulticloud.googleapis.com\"\n)\n\nattached_client = gke_multicloud_v1.AttachedClustersClient(\n    client_options=client_options\n)\naws_client = gke_multicloud_v1.AwsClustersClient(\n    client_options=client_options\n)\nazure_client = gke_multicloud_v1.AzureClustersClient(\n    client_options=client_options\n)\n```\n\nExplicit credential file instead of ambient ADC:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nclient = gke_multicloud_v1.AttachedClustersClient.from_service_account_file(\n    \"/absolute/path/service-account.json\",\n    client_options=ClientOptions(api_endpoint=\"us-west1-gkemulticloud.googleapis.com\"),\n)\n```\n\n## Resource Names\n\nThe client expects fully qualified resource names.\n\nUse these patterns:\n\n- location: `projects/{project_id}/locations/{location}`\n- attached cluster: `projects/{project_id}/locations/{location}/attachedClusters/{cluster_id}`\n- attached server config: `projects/{project_id}/locations/{location}/attachedServerConfig`\n- AWS cluster: `projects/{project_id}/locations/{location}/awsClusters/{cluster_id}`\n- AWS server config: `projects/{project_id}/locations/{location}/awsServerConfig`\n- Azure cluster: `projects/{project_id}/locations/{location}/azureClusters/{cluster_id}`\n- Azure client: `projects/{project_id}/locations/{location}/azureClients/{client_id}`\n- Azure server config: `projects/{project_id}/locations/{location}/azureServerConfig`\n- Fleet membership to import: `projects/{project_id}/locations/{location}/memberships/{membership_id}`\n\nThe `location` here is the Google Cloud administrative region for the API, not the Kubernetes cluster’s own zone.\n\n## Attached Clusters: Current Path\n\nFor new automation, use the attached-cluster surface. The product docs for GKE on AWS and GKE on Azure are already in maintenance mode and both products will no longer be supported on `March 17, 2027`.\n\n### Get supported attached-cluster platform versions\n\nUse `get_attached_server_config` before hard-coding a `platform_version`:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nname = f\"projects/{project_id}/locations/{location}/attachedServerConfig\"\nconfig = client.get_attached_server_config(name=name)\n\nfor version in config.valid_versions:\n    if getattr(version, \"enabled\", False):\n        print(version.version)\n```\n\n### List attached clusters in one location\n\n`list_attached_clusters` returns a pager:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor cluster in client.list_attached_clusters(parent=parent):\n    print(cluster.name)\n    print(cluster.platform_version)\n    print(cluster.distribution)\n    print(cluster.state)\n```\n\n### Get one attached cluster\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ncluster_id = \"example-attached-cluster\"\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nname = f\"projects/{project_id}/locations/{location}/attachedClusters/{cluster_id}\"\ncluster = client.get_attached_cluster(name=name)\n\nprint(cluster.name)\nprint(cluster.kubernetes_version)\nprint(cluster.fleet.membership)\n```\n\n### Generate the install manifest for a cluster you want to attach\n\nThis returns the YAML manifest you apply to the target cluster.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nattached_cluster_id = \"my-existing-cluster\"\nplatform_version = \"1.32.0-gke.1000\"\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nrequest = gke_multicloud_v1.GenerateAttachedClusterInstallManifestRequest(\n    parent=f\"projects/{project_id}/locations/{location}\",\n    attached_cluster_id=attached_cluster_id,\n    platform_version=platform_version,\n)\n\nresponse = client.generate_attached_cluster_install_manifest(request=request)\nprint(response.manifest)\n```\n\nImportant detail from the REST docs:\n\n- when you are generating a manifest for importing an existing membership, `attached_cluster_id` must be the membership id\n\n### Import an existing Fleet membership as an attached cluster\n\n`import_attached_cluster` is a long-running operation. Wait for `operation.result()`.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nmembership_id = \"my-existing-cluster\"\nplatform_version = \"1.32.0-gke.1000\"\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nrequest = gke_multicloud_v1.ImportAttachedClusterRequest(\n    parent=f\"projects/{project_id}/locations/{location}\",\n    fleet_membership=(\n        f\"projects/{project_id}/locations/{location}/memberships/{membership_id}\"\n    ),\n    platform_version=platform_version,\n    distribution=\"generic\",  # one of: generic, eks, aks\n)\n\noperation = client.import_attached_cluster(request=request)\ncluster = operation.result()\n\nprint(cluster.name)\n```\n\nIf you want the API to check the request without importing the cluster yet, set `validate_only=True` on the same request first.\n\n### Generate an attached-cluster agent token\n\nThis is the advanced flow for cluster agents, not normal human access to the Kubernetes API.\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ncluster_id = \"example-attached-cluster\"\n\nclient = gke_multicloud_v1.AttachedClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nrequest = gke_multicloud_v1.GenerateAttachedClusterAgentTokenRequest(\n    attached_cluster=(\n        f\"projects/{project_id}/locations/{location}/attachedClusters/{cluster_id}\"\n    ),\n    subject_token=\"external-subject-token\",\n    subject_token_type=\"urn:ietf:params:oauth:token-type:jwt\",\n    version=\"1\",\n)\n\nresponse = client.generate_attached_cluster_agent_token(request=request)\n\nprint(response.access_token)\nprint(response.expires_in)\nprint(response.token_type)\n```\n\n## Legacy AWS And Azure Surfaces\n\nThe library still exposes AWS and Azure clients, but Google’s product docs say both GKE on AWS and GKE on Azure are already in maintenance mode and will no longer be supported on `March 17, 2027`.\n\nUse these surfaces for existing environments you still operate today, not for new long-term platform work.\n\nThe REST reference also marks `getAwsServerConfig` and `getAzureServerConfig` as deprecated.\n\n### Inspect supported AWS versions and regions\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = gke_multicloud_v1.AwsClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nname = f\"projects/{project_id}/locations/{location}/awsServerConfig\"\nconfig = client.get_aws_server_config(name=name)\n\nprint(config.supported_aws_regions)\nfor version in config.valid_versions:\n    if getattr(version, \"enabled\", False):\n        print(version.version)\n```\n\n### List and read AWS clusters\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ncluster_id = \"legacy-aws-cluster\"\n\nclient = gke_multicloud_v1.AwsClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nparent = f\"projects/{project_id}/locations/{location}\"\nfor cluster in client.list_aws_clusters(parent=parent):\n    print(cluster.name)\n\nname = f\"projects/{project_id}/locations/{location}/awsClusters/{cluster_id}\"\ncluster = client.get_aws_cluster(name=name)\nprint(cluster.aws_region)\nprint(cluster.endpoint)\n```\n\n### Generate a Kubernetes API token for an AWS cluster\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ncluster_id = \"legacy-aws-cluster\"\n\nclient = gke_multicloud_v1.AwsClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nrequest = gke_multicloud_v1.GenerateAwsAccessTokenRequest(\n    aws_cluster=f\"projects/{project_id}/locations/{location}/awsClusters/{cluster_id}\"\n)\n\nresponse = client.generate_aws_access_token(request=request)\nprint(response.access_token)\nprint(response.expiration_time)\n```\n\n### Inspect supported Azure versions and regions\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = gke_multicloud_v1.AzureClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nname = f\"projects/{project_id}/locations/{location}/azureServerConfig\"\nconfig = client.get_azure_server_config(name=name)\n\nprint(config.supported_azure_regions)\nfor version in config.valid_versions:\n    if getattr(version, \"enabled\", False):\n        print(version.version)\n```\n\n### List Azure clients and clusters\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = gke_multicloud_v1.AzureClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor azure_client in client.list_azure_clients(parent=parent):\n    print(azure_client.name)\n\nfor cluster in client.list_azure_clusters(parent=parent):\n    print(cluster.name)\n```\n\n### Generate a Kubernetes API token for an Azure cluster\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import gke_multicloud_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\ncluster_id = \"legacy-azure-cluster\"\n\nclient = gke_multicloud_v1.AzureClustersClient(\n    client_options=ClientOptions(\n        api_endpoint=f\"{location}-gkemulticloud.googleapis.com\"\n    )\n)\n\nrequest = gke_multicloud_v1.GenerateAzureAccessTokenRequest(\n    azure_cluster=(\n        f\"projects/{project_id}/locations/{location}/azureClusters/{cluster_id}\"\n    )\n)\n\nresponse = client.generate_azure_access_token(request=request)\nprint(response.access_token)\nprint(response.expiration_time)\n```\n\n## Common Pitfalls\n\n- Do not omit `client_options.api_endpoint`. This API is regional and the generated samples explicitly warn that regional endpoints may be required.\n- Do not confuse the Google Cloud administrative `location` with the cluster’s cloud-provider region or zone.\n- Do not manage Kubernetes workloads through this package. Its job is the Google control plane, not the Kubernetes resource API.\n- Do not hard-code `platform_version` or Kubernetes versions without reading the matching server-config resource first.\n- Do not assume AWS or Azure methods are a safe foundation for new platform work. Google has already put both products in maintenance mode and scheduled shutdown for `March 17, 2027`.\n- Prefer ADC or service account impersonation over long-lived key files.\n- Avoid older examples that pass `credentials_file=` into generated clients. The upstream changelog notes that argument was deprecated.\n\n## Version-Sensitive Notes\n\n- The `0.7.0` changelog marks the GKE-on-AWS and GKE-on-Azure protos as deprecated to discourage new usage as those services turn down.\n- The product docs state that both GKE on AWS and GKE on Azure will no longer be supported on `March 17, 2027`, and recommend migrating to GKE or another Kubernetes distribution. For continued Google Cloud integration, the deprecation pages explicitly point users to GKE attached clusters.\n- The Multi-Cloud reference docs are generated from the API surface and may lag the latest wheel on PyPI. Keep your installed package version authoritative when you debug field-level differences.\n\n## Official Sources\n\n- Docs overview: `https://docs.cloud.google.com/python/docs/reference/gkemulticloud/latest`\n- AttachedClustersClient reference: `https://docs.cloud.google.com/python/docs/reference/gkemulticloud/latest/google.cloud.gke_multicloud_v1.services.attached_clusters.AttachedClustersClient`\n- Package classes summary: `https://docs.cloud.google.com/python/docs/reference/gkemulticloud/latest/summary_class`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/gkemulticloud/latest/changelog`\n- PyPI: `https://pypi.org/project/google-cloud-gke-multicloud/`\n- ADC overview: `https://docs.cloud.google.com/docs/authentication/provide-credentials-adc`\n- ADC local development: `https://docs.cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- GKE on AWS setup: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/aws/how-to/configure-cloud-sdk`\n- GKE on Azure setup: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/azure/how-to/configure-cloud-sdk`\n- Attached cluster prerequisites: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/attached/generic/reference/cluster-prerequisites`\n- Attached server config REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations/getAttachedServerConfig`\n- Generate attached install manifest REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations/generateAttachedClusterInstallManifest`\n- Import attached cluster REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations.attachedClusters/import`\n- Generate attached cluster agent token REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations.attachedClusters/generateAttachedClusterAgentToken`\n- AWS clusters REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations.awsClusters`\n- Generate AWS access token REST reference: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations.awsClusters/generateAwsAccessToken`\n- Get AWS server config REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations/getAwsServerConfig`\n- Generate Azure access token REST reference: `https://cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations.azureClusters/generateAzureAccessToken`\n- Get Azure server config REST reference: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/reference/rest/v1/projects.locations/getAzureServerConfig`\n- GKE on AWS deprecation announcement: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/aws/deprecations/deprecation-announcement`\n- GKE on Azure deprecation announcement: `https://docs.cloud.google.com/kubernetes-engine/multi-cloud/docs/azure/deprecations/deprecation-announcement`\n"
  },
  {
    "path": "content/google/docs/gsuiteaddons/python/DOC.md",
    "content": "---\nname: gsuiteaddons\ndescription: \"Google Workspace Add-ons Python client for managing add-on deployments, authorization metadata, and developer-mode installs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,workspace,addons,gmail,calendar,docs,python\"\n---\n\n# Google Workspace Add-ons Python Client\n\n## Golden Rule\n\nUse `google-cloud-gsuiteaddons` to manage Google Workspace add-on deployments from Python. This package is for deployment lifecycle operations such as `create_deployment`, `replace_deployment`, `install_deployment`, and `get_authorization`; it does not build your card UI or replace the Google Workspace manifest docs.\n\nAs of March 13, 2026, PyPI lists `google-cloud-gsuiteaddons 0.4.0`. The current Python reference pages still show `0.3.18` in page chrome, so use PyPI for the published package version and the reference pages for the client methods and message types.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-gsuiteaddons==0.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-gsuiteaddons==0.4.0\"\npoetry add \"google-cloud-gsuiteaddons==0.4.0\"\n```\n\n## Prerequisites\n\nBefore calling the API, make sure you have:\n\n- A Google Cloud project that owns the add-on deployment\n- The Google Workspace Add-ons API enabled for that project\n- A valid Workspace add-on manifest for your host app and runtime\n- The Google Workspace Marketplace SDK enabled as well if you are deploying an HTTP add-on\n\nThe client library manages deployments against that existing project setup. It does not generate the manifest for you.\n\n## Authentication And Environment\n\nGoogle client libraries use Application Default Credentials (ADC) by default.\n\nFor local development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nIf you must use a service account key locally:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOptional client-library debug logging:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google\"\n```\n\n## Initialize The Client\n\nMost code only needs the default client:\n\n```python\nimport os\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\nproject_name = f\"projects/{project_id}\"\n```\n\nIf you need explicit credentials instead of ADC:\n\n```python\nfrom google.cloud import gsuiteaddons_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\nclient = gsuiteaddons_v1.GSuiteAddOnsClient(credentials=credentials)\n```\n\n## Get Authorization Metadata\n\n`get_authorization` returns the authorization metadata Google created for the project, including the service account email and OAuth client ID used by the add-on. This is especially useful for alternate runtimes that validate Google-signed tokens on your HTTP endpoint.\n\n```python\nimport os\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\n\nauthorization = client.get_authorization(\n    request={\"name\": f\"projects/{project_id}/authorization\"}\n)\n\nprint(authorization.service_account_email)\nprint(authorization.oauth_client_id)\n```\n\n## List And Inspect Deployments\n\nList the deployments that already exist under a project:\n\n```python\nimport os\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\n\nfor deployment in client.list_deployments(\n    request={\"parent\": f\"projects/{project_id}\"}\n):\n    print(deployment.name)\n    print(deployment.oauth_scopes)\n```\n\nFetch one deployment by resource name:\n\n```python\nimport os\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndeployment_id = \"my-add-on\"\n\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\ndeployment = client.get_deployment(\n    request={\"name\": f\"projects/{project_id}/deployments/{deployment_id}\"}\n)\n\nprint(deployment.name)\nprint(deployment.etag)\n```\n\n## Create Or Replace A Deployment\n\nThe Python client accepts deployment data that matches the `Deployment` message. In practice, the easiest approach is to build a deployment dict from the Workspace add-on manifest you already maintain, then send it with `create_deployment` or `replace_deployment`.\n\n```python\nimport json\nimport os\nfrom pathlib import Path\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndeployment_id = \"my-add-on\"\n\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\n\n# deployment.json should use the Deployment schema for this API.\ndeployment_manifest = json.loads(Path(\"deployment.json\").read_text())\n\ncreated = client.create_deployment(\n    request={\n        \"parent\": f\"projects/{project_id}\",\n        \"deployment_id\": deployment_id,\n        \"deployment\": deployment_manifest,\n    }\n)\n\nupdated = client.replace_deployment(\n    request={\n        \"deployment\": {\n            **deployment_manifest,\n            \"name\": f\"projects/{project_id}/deployments/{deployment_id}\",\n        }\n    }\n)\n\nprint(created.name)\nprint(updated.name)\n```\n\nFor HTTP add-ons, the manifest still needs the correct `http_options` and host-app sections from the Google Workspace add-ons manifest docs. Keep those definitions in sync with the runtime you actually deploy.\n\n## Install In Developer Mode And Check Status\n\n`install_deployment` installs an add-on deployment for the current user in developer mode so they can test it. `get_install_status` uses a different resource name: append `/installStatus` to the deployment resource.\n\n```python\nimport os\n\nfrom google.cloud import gsuiteaddons_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndeployment_id = \"my-add-on\"\ndeployment_name = f\"projects/{project_id}/deployments/{deployment_id}\"\n\nclient = gsuiteaddons_v1.GSuiteAddOnsClient()\n\nclient.install_deployment(request={\"name\": deployment_name})\n\ninstall_status = client.get_install_status(\n    request={\"name\": f\"{deployment_name}/installStatus\"}\n)\n\nprint(install_status.installed)\n```\n\nTo remove the developer-mode install:\n\n```python\nclient.uninstall_deployment(request={\"name\": deployment_name})\n```\n\n## Delete A Deployment\n\nDelete the deployment when you no longer need it:\n\n```python\nclient.delete_deployment(request={\"name\": deployment_name})\n```\n\n## Common Pitfalls\n\n- This package manages the deployment API. It does not replace the Google Workspace add-on manifest docs, card-service docs, or your HTTP endpoint implementation.\n- `install_deployment` and `uninstall_deployment` use the deployment resource name, but `get_install_status` uses `projects/{project}/deployments/{deployment}/installStatus`.\n- The generated Python reference includes a generic note about regional endpoints, but the product REST docs document the Google Workspace Add-ons API under the global `gsuiteaddons.googleapis.com` service.\n- If you are using alternate runtimes, keep the `authorization_header` behavior in your manifest aligned with what your backend actually validates. The product docs describe `SYSTEM_ID_TOKEN`, `USER_ID_TOKEN`, and `NONE`.\n- The reference changelog notes that the generated `credentials_file` constructor argument is deprecated. Prefer ADC or explicit `credentials=...`.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `0.4.0` for `google-cloud-gsuiteaddons`.\n- The maintainer reference root and changelog currently stop at `0.3.18`, so there is an upstream version-display lag between the package registry and the generated docs site.\n- The public API surface in the current reference includes the main deployment-management methods: `create_deployment`, `delete_deployment`, `get_authorization`, `get_deployment`, `get_install_status`, `install_deployment`, `list_deployments`, `replace_deployment`, and `uninstall_deployment`.\n\n## Official Sources Used For This Doc\n\n- PyPI package page: `https://pypi.org/project/google-cloud-gsuiteaddons/`\n- Python reference root: `https://cloud.google.com/python/docs/reference/gsuiteaddons/latest`\n- `GSuiteAddOnsClient` reference: `https://cloud.google.com/python/docs/reference/gsuiteaddons/latest/google.cloud.gsuiteaddons_v1.services.g_suite_add_ons.GSuiteAddOnsClient`\n- Changelog: `https://cloud.google.com/python/docs/reference/gsuiteaddons/latest/changelog`\n- Google Workspace Add-ons API overview: `https://developers.google.com/workspace/add-ons/guides/workspace-addons-api`\n- Alternate runtimes guide: `https://developers.google.com/workspace/add-ons/guides/alternate-runtimes`\n- REST `projects.deployments` resource: `https://developers.google.com/workspace/add-ons/reference/rest/v1/projects.deployments`\n- REST `projects.getAuthorization` reference: `https://developers.google.com/workspace/add-ons/reference/rest/v1/projects/getAuthorization`\n"
  },
  {
    "path": "content/google/docs/iam/javascript/DOC.md",
    "content": "---\nname: iam\ndescription: \"Google Cloud IAM Node.js client for service account admin, short-lived credentials, and deny policies\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,iam,gcp,service-accounts,credentials,deny-policies,javascript,nodejs\"\n---\n\n# `@google-cloud/iam` JavaScript Package Guide\n\nUse `@google-cloud/iam` when your Node.js code needs to manage service accounts, mint short-lived credentials for service account impersonation, sign blobs or JWTs, or manage IAM deny policies.\n\n## Golden Rule\n\n- Import the generated clients from `@google-cloud/iam` version namespaces: `v1.IAMClient`, `v1.IAMCredentialsClient`, and `v2.PoliciesClient`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass a credential file directly.\n- Prefer `IAMCredentialsClient` for access tokens, ID tokens, and signing flows instead of creating long-lived service account keys.\n- Use the wildcard resource form `projects/-/serviceAccounts/<email-or-unique-id>` for IAM Credentials requests.\n- For deny policies, URL-encode the attachment point and wait for the long-running operation to finish before assuming the policy exists.\n\nThis guide covers `2.3.1`.\n\n## Install\n\nPin the package version your app or agent should target:\n\n```bash\nnpm install @google-cloud/iam@2.3.1\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials, not API keys.\n\nEnable the APIs you plan to call:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable iam.googleapis.com iamcredentials.googleapis.com \\\n  --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nCommon role requirements depend on the workflow:\n\n- `roles/iam.serviceAccountAdmin` for creating and managing service accounts\n- `roles/iam.serviceAccountTokenCreator` on the target service account for `generateAccessToken`, `generateIdToken`, `signBlob`, and `signJwt`\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1, v2} = require('@google-cloud/iam');\n\nconst iamAdminClient = new v1.IAMClient();\nconst iamCredentialsClient = new v1.IAMCredentialsClient();\nconst policiesClient = new v2.PoliciesClient();\n```\n\nES modules:\n\n```javascript\nimport {v1, v2} from '@google-cloud/iam';\n\nconst iamAdminClient = new v1.IAMClient();\nconst iamCredentialsClient = new v1.IAMCredentialsClient();\nconst policiesClient = new v2.PoliciesClient();\n```\n\nWith explicit project ID and credential file:\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Create A Service Account\n\nUse `v1.IAMClient` for service account admin operations.\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMClient();\n\nasync function createServiceAccount(projectId, accountId) {\n  const [serviceAccount] = await client.createServiceAccount({\n    name: `projects/${projectId}`,\n    accountId,\n    serviceAccount: {\n      displayName: 'Automation runner',\n      description: 'Service account used by deployment jobs',\n    },\n  });\n\n  return serviceAccount;\n}\n```\n\n### List Service Accounts In A Project\n\nUse the async iterator when you want the client to handle pagination for you.\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMClient();\n\nasync function listServiceAccounts(projectId) {\n  const serviceAccounts = [];\n\n  for await (const serviceAccount of client.listServiceAccountsAsync({\n    name: `projects/${projectId}`,\n  })) {\n    serviceAccounts.push({\n      name: serviceAccount.name,\n      email: serviceAccount.email,\n      disabled: serviceAccount.disabled,\n    });\n  }\n\n  return serviceAccounts;\n}\n```\n\n### Generate A Short-Lived Access Token\n\nUse `IAMCredentialsClient` for impersonation flows. At least one OAuth scope is required.\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMCredentialsClient();\n\nasync function generateAccessToken(serviceAccountEmail) {\n  const [response] = await client.generateAccessToken({\n    name: `projects/-/serviceAccounts/${serviceAccountEmail}`,\n    scope: ['https://www.googleapis.com/auth/cloud-platform'],\n  });\n\n  return {\n    accessToken: response.accessToken,\n    expireTime: response.expireTime,\n  };\n}\n```\n\n### Generate An ID Token\n\nUse this when a downstream service expects an OpenID Connect token for a specific audience.\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMCredentialsClient();\n\nasync function generateIdToken(serviceAccountEmail, audience) {\n  const [response] = await client.generateIdToken({\n    name: `projects/-/serviceAccounts/${serviceAccountEmail}`,\n    audience,\n    includeEmail: true,\n  });\n\n  return response.token;\n}\n```\n\n### Sign A JWT\n\nUse `signJwt` when you need the service account to sign a JWT payload without exporting a private key.\n\n```javascript\nconst {v1} = require('@google-cloud/iam');\n\nconst client = new v1.IAMCredentialsClient();\n\nasync function signJwt(serviceAccountEmail) {\n  const payload = JSON.stringify({\n    iss: serviceAccountEmail,\n    sub: serviceAccountEmail,\n    aud: 'https://example.com',\n  });\n\n  const [response] = await client.signJwt({\n    name: `projects/-/serviceAccounts/${serviceAccountEmail}`,\n    payload,\n  });\n\n  return response.signedJwt;\n}\n```\n\n### Create A Deny Policy On A Project\n\nDeny policies use the IAM v2 client and a URL-encoded attachment point.\n\n```javascript\nconst {v2} = require('@google-cloud/iam');\n\nconst client = new v2.PoliciesClient();\n\nasync function createProjectDenyPolicy(projectId) {\n  const attachmentPoint = encodeURIComponent(\n    `cloudresourcemanager.googleapis.com/projects/${projectId}`\n  );\n\n  const [operation] = await client.createPolicy({\n    parent: `policies/${attachmentPoint}/denypolicies`,\n    policyId: 'deny-project-delete',\n    policy: {\n      displayName: 'Restrict project deletion',\n      rules: [\n        {\n          denyRule: {\n            deniedPrincipals: ['principalSet://goog/public:all'],\n            deniedPermissions: [\n              'cloudresourcemanager.googleapis.com/projects.delete',\n            ],\n            exceptionPrincipals: [\n              `principal://iam.googleapis.com/projects/-/serviceAccounts/admin@${projectId}.iam.gserviceaccount.com`,\n            ],\n          },\n        },\n      ],\n    },\n  });\n\n  const [policy] = await operation.promise();\n  return policy.name;\n}\n```\n\n### List Deny Policies Attached To A Project\n\n```javascript\nconst {v2} = require('@google-cloud/iam');\n\nconst client = new v2.PoliciesClient();\n\nasync function listProjectDenyPolicies(projectId) {\n  const attachmentPoint = encodeURIComponent(\n    `cloudresourcemanager.googleapis.com/projects/${projectId}`\n  );\n\n  const policies = [];\n\n  for await (const policy of client.listPoliciesAsync({\n    parent: `policies/${attachmentPoint}/denypolicies`,\n  })) {\n    policies.push({\n      name: policy.name,\n      displayName: policy.displayName,\n    });\n  }\n\n  return policies;\n}\n```\n\n## Common Pitfalls\n\n- `IAMClient` and `IAMCredentialsClient` solve different problems. Use `IAMClient` for service account admin, and `IAMCredentialsClient` for impersonation and signing.\n- `generateAccessToken` requires at least one OAuth scope. An empty `scope` list fails.\n- IAM Credentials resource names commonly use `projects/-/serviceAccounts/...`; do not replace `-` with a project ID unless the specific method documentation says to.\n- Long-lived service account keys are not the default path. Prefer short-lived access tokens, ID tokens, or signing APIs when possible.\n- Deny policy parents must use the encoded attachment-point format `policies/{attachment_point}/denypolicies`.\n- Create, update, and delete deny policy operations are long-running operations. Wait for `operation.promise()` before using the result.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/iam/latest`\n- IAM Admin client reference: `https://cloud.google.com/nodejs/docs/reference/iam/latest/iam-admin/v1.iamclient`\n- IAM Credentials client reference: `https://cloud.google.com/nodejs/docs/reference/iam/latest/iam-credentials/v1.iamcredentialsclient`\n- IAM v2 Policies client reference: `https://cloud.google.com/nodejs/docs/reference/iam/latest/iam-v2/policiesclient`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Create short-lived credentials: `https://cloud.google.com/iam/docs/create-short-lived-credentials-direct`\n- Create deny policy sample: `https://cloud.google.com/iam/docs/samples/iam-create-deny-policy`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/iam`\n"
  },
  {
    "path": "content/google/docs/iam/python/DOC.md",
    "content": "---\nname: iam\ndescription: \"Google Cloud IAM Python client library for service account admin, short-lived credentials, and deny policies\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.21.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,iam,python,service-accounts,credentials,deny-policies\"\n---\n\n# Google Cloud IAM Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-iam` for Google Cloud IAM Admin, IAM Credentials, and IAM v2 deny-policy operations, but do not treat it as the entire Google Cloud auth stack. In practice this package exposes three main client surfaces:\n\n- `google.cloud.iam_admin_v1` for service accounts, keys, and custom roles\n- `google.cloud.iam_credentials_v1` for short-lived access tokens, ID tokens, and signing\n- `google.cloud.iam_v2` for deny policies\n\nFor authentication, prefer Application Default Credentials (ADC). For credential minting and request signing, prefer `IAMCredentialsClient` over the deprecated signing methods on `IAMClient`.\n\n## Install\n\n```bash\npython -m pip install --upgrade google-cloud-iam\n```\n\nCommon alternatives:\n\n```bash\nuv add google-cloud-iam\npoetry add google-cloud-iam\n```\n\n## Authentication And Setup\n\nGoogle Cloud client libraries use Application Default Credentials. For local development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nFor non-interactive workloads, point ADC at a service account key file only when you actually need a key-based flow:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nBasic imports:\n\n```python\nfrom google.cloud import iam_admin_v1\nfrom google.cloud import iam_credentials_v1\nfrom google.cloud import iam_v2\n```\n\nBasic client initialization:\n\n```python\nfrom google.cloud import iam_admin_v1\n\nclient = iam_admin_v1.IAMClient()\n```\n\nYou can also use the generated helper constructors if you need to pin a credential file directly:\n\n```python\nfrom google.cloud import iam_credentials_v1\n\nclient = iam_credentials_v1.IAMCredentialsClient.from_service_account_json(\n    \"/path/to/service-account.json\"\n)\n```\n\n## Core Usage\n\n### Manage service accounts with `IAMClient`\n\nCreate a service account:\n\n```python\nfrom google.cloud import iam_admin_v1\n\nproject_id = \"your-project-id\"\nclient = iam_admin_v1.IAMClient()\n\nrequest = iam_admin_v1.CreateServiceAccountRequest(\n    name=f\"projects/{project_id}\",\n    account_id=\"automation-runner\",\n    service_account=iam_admin_v1.ServiceAccount(\n        display_name=\"Automation runner\",\n        description=\"Service account used by deployment jobs\",\n    ),\n)\n\nservice_account = client.create_service_account(request=request)\nprint(service_account.email)\n```\n\nList service accounts in a project:\n\n```python\nfrom google.cloud import iam_admin_v1\n\nproject_id = \"your-project-id\"\nclient = iam_admin_v1.IAMClient()\n\npager = client.list_service_accounts(\n    request=iam_admin_v1.ListServiceAccountsRequest(\n        name=f\"projects/{project_id}\",\n    )\n)\n\nfor service_account in pager:\n    print(service_account.name, service_account.email)\n```\n\nPatch only selected fields with an update mask:\n\n```python\nfrom google.cloud import iam_admin_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = iam_admin_v1.IAMClient()\n\nservice_account = iam_admin_v1.ServiceAccount(\n    name=\"projects/your-project-id/serviceAccounts/automation-runner@your-project-id.iam.gserviceaccount.com\",\n    display_name=\"Automation runner v2\",\n)\n\nupdated = client.patch_service_account(\n    request=iam_admin_v1.PatchServiceAccountRequest(\n        service_account=service_account,\n        update_mask=FieldMask(paths=[\"display_name\"]),\n    )\n)\n\nprint(updated.display_name)\n```\n\n`create_service_account_key` still exists, but treat long-lived key creation as an exception. Prefer short-lived tokens or signing via `IAMCredentialsClient` when you can.\n\n### Generate short-lived credentials with `IAMCredentialsClient`\n\nGenerate an OAuth access token for a target service account:\n\n```python\nfrom google.cloud import iam_credentials_v1\nfrom google.protobuf.duration_pb2 import Duration\n\nservice_account_email = \"target-sa@your-project-id.iam.gserviceaccount.com\"\nclient = iam_credentials_v1.IAMCredentialsClient()\n\nrequest = iam_credentials_v1.GenerateAccessTokenRequest(\n    name=f\"projects/-/serviceAccounts/{service_account_email}\",\n    scope=[\"https://www.googleapis.com/auth/cloud-platform\"],\n    lifetime=Duration(seconds=900),\n)\n\nresponse = client.generate_access_token(request=request)\nprint(response.access_token)\nprint(response.expire_time)\n```\n\nGenerate an ID token for Cloud Run or another audience-bound service:\n\n```python\nfrom google.cloud import iam_credentials_v1\n\nservice_account_email = \"target-sa@your-project-id.iam.gserviceaccount.com\"\nclient = iam_credentials_v1.IAMCredentialsClient()\n\nrequest = iam_credentials_v1.GenerateIdTokenRequest(\n    name=f\"projects/-/serviceAccounts/{service_account_email}\",\n    audience=\"https://your-service-xyz.a.run.app\",\n    include_email=True,\n)\n\nresponse = client.generate_id_token(request=request)\nprint(response.token)\n```\n\nSign a JWT payload with the target service account:\n\n```python\nimport json\nfrom google.cloud import iam_credentials_v1\n\nservice_account_email = \"target-sa@your-project-id.iam.gserviceaccount.com\"\nclient = iam_credentials_v1.IAMCredentialsClient()\n\npayload = json.dumps(\n    {\n        \"iss\": service_account_email,\n        \"sub\": service_account_email,\n        \"aud\": \"https://example.com\",\n    }\n)\n\nresponse = client.sign_jwt(\n    request=iam_credentials_v1.SignJwtRequest(\n        name=f\"projects/-/serviceAccounts/{service_account_email}\",\n        payload=payload,\n    )\n)\n\nprint(response.signed_jwt)\n```\n\nFor impersonation flows, the caller needs `roles/iam.serviceAccountTokenCreator` on the target service account. The direct credential-creation guide also documents that access tokens default to one hour and can be extended to twelve hours only when the org policy for lifetime extension allows it.\n\n### Manage deny policies with `PoliciesClient`\n\nCreate a deny policy attached to a project:\n\n```python\nfrom urllib.parse import quote\n\nfrom google.cloud import iam_v2\nfrom google.cloud.iam_v2 import types\n\nproject_id = \"your-project-id\"\nclient = iam_v2.PoliciesClient()\n\nattachment_point = quote(\n    f\"cloudresourcemanager.googleapis.com/projects/{project_id}\",\n    safe=\"\",\n)\n\nrequest = types.CreatePolicyRequest(\n    parent=f\"policies/{attachment_point}/denypolicies\",\n    policy=types.Policy(\n        display_name=\"Restrict project deletion\",\n        rules=[\n            types.PolicyRule(\n                deny_rule=types.DenyRule(\n                    denied_principals=[\"principalSet://goog/public:all\"],\n                    denied_permissions=[\n                        \"cloudresourcemanager.googleapis.com/projects.delete\"\n                    ],\n                    exception_principals=[\n                        \"principal://iam.googleapis.com/projects/-/serviceAccounts/admin@your-project-id.iam.gserviceaccount.com\"\n                    ],\n                )\n            )\n        ],\n    ),\n    policy_id=\"deny-project-delete\",\n)\n\noperation = client.create_policy(request=request)\npolicy = operation.result()\nprint(policy.name)\n```\n\nList attached deny policies:\n\n```python\nfrom urllib.parse import quote\n\nfrom google.cloud import iam_v2\n\nproject_id = \"your-project-id\"\nclient = iam_v2.PoliciesClient()\n\nattachment_point = quote(\n    f\"cloudresourcemanager.googleapis.com/projects/{project_id}\",\n    safe=\"\",\n)\n\nfor policy in client.list_policies(\n    request={\"parent\": f\"policies/{attachment_point}/denypolicies\"}\n):\n    print(policy.name, policy.display_name)\n```\n\n`list_policies` is for discovery. Fetch the specific policy with `get_policy` before assuming you have the full rule contents.\n\n## Configuration Notes\n\n- The generated clients accept `client_options`, including `api_endpoint`, and document the standard Google mTLS environment variables `GOOGLE_API_USE_MTLS_ENDPOINT` and `GOOGLE_API_USE_CLIENT_CERTIFICATE`.\n- The docs also mention `universe_domain` support on client construction. Most projects should leave this alone unless they already run in a non-default Google Cloud universe.\n- The PyPI page documents standard `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` support for Google client library logging if you need request-level diagnostics.\n\n## Common Pitfalls\n\n- Do not use `IAMClient.sign_blob` or `IAMClient.sign_jwt` for new code. The generated docs mark them deprecated and point you to `IAMCredentialsClient`.\n- `IAMCredentialsClient` resource names commonly use the wildcard form `projects/-/serviceAccounts/<email-or-unique-id>`. Do not assume a concrete project segment is interchangeable in every flow.\n- `generate_access_token` requires at least one OAuth scope. Missing scopes is a common source of confusing permission errors.\n- Do not create service account keys unless a downstream system truly requires a private key file. Short-lived access tokens, ID tokens, or signing APIs are usually safer.\n- Deny policy attachment points must be URL-encoded under `policies/{attachment_point}/denypolicies`; passing an unescaped resource name will fail.\n- The IAM deny-policy API uses long-running operations for create, update, and delete. Wait on `operation.result()` before assuming the change is active.\n- If you use a client as a context manager, do not share its transport with other clients unless you intend to close that shared transport on exit.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-iam 2.21.0`, which matches the version used here for this session.\n- The rolling docs root is correct for current reference lookup, but some generated class pages can lag slightly in the version stamp. During this session the main docs root and IAM Admin/IAM Credentials pages showed `2.21.0`, while the IAM v2 `PoliciesClient` page still displayed `2.20.0`.\n- The package changelog shows API-key support plumbing added in the 2.x line, but Google Cloud IAM coding flows in the official docs still center on ADC, service accounts, and delegated IAM permissions. Treat API keys as an edge configuration detail, not the default auth path.\n- Deny policies are still the IAM v2 surface in this package. Older blog posts often cover only IAM Admin or IAM Credentials and omit deny-policy attachment-point requirements.\n\n## Official Sources\n\n- Google Cloud Python reference: `https://cloud.google.com/python/docs/reference/iam/latest`\n- IAM Admin client reference: `https://cloud.google.com/python/docs/reference/iam/latest/google.cloud.iam_admin_v1.services.iam.IAMClient`\n- IAM Credentials client reference: `https://cloud.google.com/python/docs/reference/iam/latest/google.cloud.iam_credentials_v1.services.iam_credentials.IAMCredentialsClient`\n- IAM v2 Policies client reference: `https://cloud.google.com/python/docs/reference/iam/latest/google.cloud.iam_v2.services.policies.PoliciesClient`\n- Google Cloud client-library auth guide: `https://cloud.google.com/docs/authentication/client-libraries`\n- IAM short-lived credentials guide: `https://cloud.google.com/iam/docs/create-short-lived-credentials-direct`\n- IAM deny policy sample: `https://cloud.google.com/iam/docs/samples/iam-create-deny-policy`\n- PyPI package page: `https://pypi.org/project/google-cloud-iam/`\n"
  },
  {
    "path": "content/google/docs/iap/python/DOC.md",
    "content": "---\nname: iap\ndescription: \"Google Cloud Identity-Aware Proxy Python client for managing IAP settings, programmatic access allowlists, and tunnel destination groups\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.19.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,cloud,iap,identity-aware-proxy,python,auth\"\n---\n\n# Google Cloud IAP Python Client\n\n## Golden Rule\n\nUse `google-cloud-iap` to manage IAP configuration from Python: `IapSettings`, programmatic access allowlists, and IAP TCP forwarding tunnel destination groups.\n\nDo not build new automation around `IdentityAwareProxyOAuthServiceClient` for custom OAuth brand or client creation. Google documents the IAP OAuth 2.0 Admin APIs as deprecated as of January 22, 2025. For requests to an IAP-protected application, mint an ID token with `google-auth`; this package is the admin client, not the runtime caller for protected apps.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-iap==1.19.0\" requests\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-iap==1.19.0\" requests\npoetry add \"google-cloud-iap==1.19.0\" requests\n```\n\nThe maintained package docs list Python 3.7+ support for this client version.\n\n## Authentication And Setup\n\nGoogle Cloud client libraries use Application Default Credentials (ADC). For local development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nFor service-account-based automation:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nUseful environment variables for examples in this guide:\n\n```bash\nexport IAP_RESOURCE=\"projects/123456789/iap_web/compute/services/my-backend-service\"\nexport IAP_PROGRAMMATIC_CLIENT_ID=\"1234567890-abc123def456.apps.googleusercontent.com\"\nexport IAP_PROTECTED_URL=\"https://my-service-uc.a.run.app\"\n```\n\nResource name patterns you will actually need:\n\n- App Engine app: `projects/PROJECT_ID/iap_web/appengine-PROJECT_ID`\n- App Engine service version: `projects/PROJECT_ID/iap_web/appengine-PROJECT_ID/services/SERVICE_ID/versions/VERSION_ID`\n- Global external Application Load Balancer or backend service: `projects/PROJECT_NUMBER/iap_web/compute/services/BACKEND_SERVICE_NAME`\n- Regional Cloud Run behind IAP: `projects/PROJECT_NUMBER/iap_web/cloud_run-REGION/services/SERVICE_NAME`\n- IAP TCP forwarding tunnel groups parent: `projects/PROJECT_NUMBER/iap_tunnel/locations/-`\n\n## Client Initialization\n\n```python\nfrom google.cloud import iap_v1\n\nadmin_client = iap_v1.IdentityAwareProxyAdminServiceClient()\n```\n\nIf you need an explicit credential file instead of ADC:\n\n```python\nfrom google.cloud import iap_v1\n\nadmin_client = iap_v1.IdentityAwareProxyAdminServiceClient.from_service_account_json(\n    \"/path/to/service-account.json\"\n)\n```\n\n## Common Workflows\n\n### Read the current IAP settings\n\n```python\nimport os\n\nfrom google.cloud import iap_v1\n\nresource_name = os.environ[\"IAP_RESOURCE\"]\nclient = iap_v1.IdentityAwareProxyAdminServiceClient()\n\nsettings = client.get_iap_settings(name=resource_name)\n\nprint(settings.name)\nprint(settings.access_settings.oauth_settings.programmatic_clients)\nprint(settings.access_settings.allowed_domains_settings.enable)\n```\n\nUse `get_iap_settings` first and inspect the returned document before patching anything. The admin API is resource-specific, so the `name` string must match the exact IAP-protected resource you are managing.\n\n### Allowlist an OAuth client for programmatic access\n\nWhen an IAP-protected app uses the Google-managed OAuth client, programmatic access requires allowlisting another OAuth 2.0 client ID in IAP settings.\n\n```python\nimport os\n\nfrom google.cloud import iap_v1\n\nresource_name = os.environ[\"IAP_RESOURCE\"]\nclient_id = os.environ[\"IAP_PROGRAMMATIC_CLIENT_ID\"]\n\nclient = iap_v1.IdentityAwareProxyAdminServiceClient()\nsettings = client.get_iap_settings(name=resource_name)\n\nprogrammatic_clients = settings.access_settings.oauth_settings.programmatic_clients\nif client_id not in programmatic_clients:\n    programmatic_clients.append(client_id)\n\nupdated = client.update_iap_settings(\n    request=iap_v1.UpdateIapSettingsRequest(iap_settings=settings)\n)\n\nprint(updated.access_settings.oauth_settings.programmatic_clients)\n```\n\nImportant behavior: `update_iap_settings` replaces the settings document unless you send an `update_mask`. If multiple automation paths touch IAP settings, do a read-modify-write against the latest state and use a narrow update mask when you need partial updates.\n\n### Call an IAP-protected application from Python\n\nFor runtime requests to an IAP-protected endpoint, send an ID token in the `Authorization` header. The audience is the OAuth client ID that protects the app.\n\n```python\nimport os\n\nimport requests\nfrom google.auth.transport.requests import Request\nfrom google.oauth2 import id_token\n\naudience = os.environ[\"IAP_PROGRAMMATIC_CLIENT_ID\"]\nurl = os.environ[\"IAP_PROTECTED_URL\"]\n\ntoken = id_token.fetch_id_token(Request(), audience)\n\nresponse = requests.get(\n    url,\n    headers={\"Authorization\": f\"Bearer {token}\"},\n    timeout=30,\n)\nresponse.raise_for_status()\n\nprint(response.text)\n```\n\nIf the app is configured to accept a service-account-signed JWT instead, Google documents `Proxy-Authorization: Bearer SIGNED_JWT` as the alternate header. The common Cloud Run and HTTPS load balancer case is an ID token in `Authorization`.\n\n### List or create IAP TCP forwarding tunnel destination groups\n\nUse tunnel destination groups when you manage IAP TCP forwarding destinations through the API.\n\n```python\nimport os\n\nfrom google.cloud import iap_v1\n\nproject_number = os.environ[\"GOOGLE_CLOUD_PROJECT_NUMBER\"]\nparent = f\"projects/{project_number}/iap_tunnel/locations/-\"\n\nclient = iap_v1.IdentityAwareProxyAdminServiceClient()\n\ngroup = client.create_tunnel_dest_group(\n    parent=parent,\n    tunnel_dest_group_id=\"corp-egress\",\n    tunnel_dest_group=iap_v1.TunnelDestGroup(\n        cidrs=[\"10.10.0.0/16\"],\n        fqdns=[\"db.internal.example.com\"],\n    ),\n)\n\nprint(group.name)\n\nfor existing in client.list_tunnel_dest_groups(parent=parent):\n    print(existing.name, list(existing.cidrs), list(existing.fqdns))\n```\n\nTunnel destination groups are part of the admin service, but they are separate from `IapSettings`. Product docs also note that you cannot use the `IapSettings` API to configure resources accessed with IAP TCP forwarding.\n\n## Common Pitfalls\n\n- Do not confuse project ID and project number. IAP resource names for Compute Engine and Cloud Run commonly use project number, while App Engine paths use project ID.\n- Do not send an OAuth access token to an IAP-protected app. Programmatic access expects an ID token or, in some configurations, a signed JWT.\n- Do not assume the package is the right tool for end-user login flows. Browser sign-in and OAuth consent are separate from this admin client.\n- Do not overwrite IAP settings blindly. `update_iap_settings` can replace fields you did not intend to change.\n- Do not start new code on the deprecated IAP OAuth Admin API. The generated Python surface still exists, but Google documents the API as deprecated for custom OAuth client management.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-iap 1.19.0`, and the maintained Python reference pages are available under the `latest` IAP client docs.\n- Inference from the official sources: the `IdentityAwareProxyOAuthServiceClient` classes remain in the generated library, but new production workflows should treat them as legacy because the IAP OAuth 2.0 Admin APIs are deprecated.\n- If you only need browser access to an IAP-protected app, prefer the default Google-managed OAuth client. You only need programmatic client allowlisting when non-browser callers must reach the protected endpoint.\n\n## Official Sources\n\n- Python package reference root: https://cloud.google.com/python/docs/reference/iap/latest\n- `google.cloud.iap_v1.services.identity_aware_proxy_admin_service.IdentityAwareProxyAdminServiceClient`: https://cloud.google.com/python/docs/reference/iap/latest/google.cloud.iap_v1.services.identity_aware_proxy_admin_service.IdentityAwareProxyAdminServiceClient\n- `google.cloud.iap_v1.services.identity_aware_proxy_o_auth_service.IdentityAwareProxyOAuthServiceClient`: https://cloud.google.com/python/docs/reference/iap/latest/google.cloud.iap_v1.services.identity_aware_proxy_o_auth_service.IdentityAwareProxyOAuthServiceClient\n- Programmatic access for IAP-secured resources: https://cloud.google.com/iap/docs/authentication-howto\n- IAP custom OAuth configuration and deprecation notice: https://cloud.google.com/iap/docs/custom-oauth-configuration\n- PyPI package page: https://pypi.org/project/google-cloud-iap/\n"
  },
  {
    "path": "content/google/docs/ids/python/DOC.md",
    "content": "---\nname: ids\ndescription: \"google-cloud-ids package guide for Python covering ADC setup, Cloud IDS endpoint lifecycle, and packet mirroring prerequisites\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,cloud-ids,ids,security,packet-mirroring,network,python\"\n---\n\n# google-cloud-ids Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-ids` to manage Cloud IDS endpoints from Python, and use Google Cloud Application Default Credentials (ADC) unless you have a concrete reason to inject credentials manually.\n\nThis package manages the Cloud IDS endpoint resource itself. Traffic is not inspected until you attach a Packet Mirroring policy to the endpoint's forwarding rule.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-ids==1.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-ids==1.12.0\"\npoetry add \"google-cloud-ids==1.12.0\"\n```\n\n## Authentication And Prerequisites\n\nBefore creating endpoints:\n\n1. Enable Cloud IDS for the Google Cloud project.\n2. Enable the Service Networking API and configure private services access for the VPC that will host the endpoint.\n3. Grant the caller Cloud IDS permissions such as `roles/ids.admin` for create/delete flows or `roles/ids.viewer` for read-only access.\n4. Grant `roles/compute.packetMirroringUser` if the same operator will attach a Packet Mirroring policy to the endpoint.\n5. Authenticate with ADC for local development or with an attached service account in deployed environments.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1-a\"\nexport GOOGLE_CLOUD_NETWORK=\"projects/your-project-id/global/networks/my-vpc\"\nexport GOOGLE_CLOUD_IDS_ENDPOINT_ID=\"prod-inspection\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUse a full VPC network resource name in code. The generated `Endpoint.network` field expects the fully qualified network URL.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import ids_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]  # Zonal location, for example us-central1-a\nnetwork = os.environ[\"GOOGLE_CLOUD_NETWORK\"]\nendpoint_id = os.environ[\"GOOGLE_CLOUD_IDS_ENDPOINT_ID\"]\n\nclient = ids_v1.IDSClient()\nparent = client.common_location_path(project_id, location)\nendpoint_name = client.endpoint_path(project_id, location, endpoint_id)\n```\n\nIf your environment requires a non-default API endpoint, pass `client_options` when creating the client:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import ids_v1\n\nclient = ids_v1.IDSClient(\n    client_options=ClientOptions(\n        api_endpoint=os.environ[\"GOOGLE_CLOUD_IDS_API_ENDPOINT\"]\n    )\n)\n```\n\nExplicit credentials are also supported:\n\n```python\nfrom google.cloud import ids_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = ids_v1.IDSClient(credentials=credentials)\n```\n\n## Core Workflow\n\n### Create An Endpoint\n\nCreating an endpoint is a long-running operation. Wait for `operation.result()` before using the endpoint in later steps.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import ids_v1\n\nclient = ids_v1.IDSClient()\nparent = client.common_location_path(\n    os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n    os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n)\n\nendpoint = ids_v1.Endpoint(\n    network=os.environ[\"GOOGLE_CLOUD_NETWORK\"],\n    severity=ids_v1.Endpoint.Severity.HIGH,\n    description=\"Inspect mirrored traffic for production subnets\",\n    traffic_logs=True,\n    labels={\"env\": \"prod\"},\n)\n\noperation = client.create_endpoint(\n    request=ids_v1.CreateEndpointRequest(\n        parent=parent,\n        endpoint_id=os.environ[\"GOOGLE_CLOUD_IDS_ENDPOINT_ID\"],\n        endpoint=endpoint,\n        request_id=str(uuid.uuid4()),\n    )\n)\n\ncreated = operation.result(timeout=1800)\n\nprint(created.name)\nprint(created.endpoint_forwarding_rule)\nprint(created.endpoint_ip)\nprint(created.state)\n```\n\nImportant request details:\n\n- `endpoint_id` must start with a lowercase letter, can include lowercase letters, digits, and hyphens, and cannot end with a hyphen.\n- `severity` accepts Cloud IDS alerting levels such as `INFORMATIONAL`, `LOW`, `MEDIUM`, `HIGH`, and `CRITICAL`.\n- `traffic_logs=True` enables logs for the endpoint.\n\n### Get One Endpoint\n\n```python\nimport os\n\nfrom google.cloud import ids_v1\n\nclient = ids_v1.IDSClient()\nname = client.endpoint_path(\n    os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n    os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    os.environ[\"GOOGLE_CLOUD_IDS_ENDPOINT_ID\"],\n)\n\nendpoint = client.get_endpoint(name=name)\n\nprint(endpoint.name)\nprint(endpoint.state)\nprint(endpoint.endpoint_forwarding_rule)\n```\n\n### List Endpoints In A Location\n\n```python\nimport os\n\nfrom google.cloud import ids_v1\n\nclient = ids_v1.IDSClient()\nparent = client.common_location_path(\n    os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n    os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n)\n\nfor endpoint in client.list_endpoints(\n    request=ids_v1.ListEndpointsRequest(parent=parent)\n):\n    print(endpoint.name, endpoint.state, endpoint.severity)\n```\n\n### Attach Packet Mirroring To The Endpoint\n\nThe endpoint does not inspect traffic by itself. After creation, use the returned `endpoint_forwarding_rule` as the packet-mirroring collector.\n\n```python\ncollector_ilb = created.endpoint_forwarding_rule\nprint(collector_ilb)\n```\n\nExample `gcloud` workflow using that forwarding rule:\n\n```bash\ngcloud compute packet-mirrorings create ids-mirror \\\n  --project=\"$GOOGLE_CLOUD_PROJECT\" \\\n  --region=\"us-central1\" \\\n  --network=\"my-vpc\" \\\n  --collector-ilb=\"projects/your-project-id/regions/us-central1/forwardingRules/...\" \\\n  --mirrored-subnets=\"my-subnet\"\n```\n\nKeep the packet-mirroring policy and mirrored subnets in the same region as the IDS endpoint.\n\n### Delete An Endpoint\n\nDelete endpoints you no longer need. Google Cloud product docs note that an endpoint keeps incurring charges until you delete it.\n\n```python\nimport os\n\nfrom google.cloud import ids_v1\n\nclient = ids_v1.IDSClient()\nname = client.endpoint_path(\n    os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n    os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    os.environ[\"GOOGLE_CLOUD_IDS_ENDPOINT_ID\"],\n)\n\noperation = client.delete_endpoint(name=name)\noperation.result(timeout=1800)\n```\n\n## Common Pitfalls\n\n- Creating the endpoint is only half of the setup. You still need Packet Mirroring before traffic is inspected.\n- Cloud IDS endpoint creation depends on VPC setup outside this package. If private services access or Service Networking is missing, the create call will fail even though your Python code is correct.\n- Cloud IDS endpoints are zonal resources such as `us-central1-a`, while packet-mirroring policies are regional. Keep the mirrored subnets in the same region as the endpoint.\n- `create_endpoint` and `delete_endpoint` are long-running operations. Do not assume the resource is ready or gone until `operation.result()` completes.\n- Use a fully qualified network resource name like `projects/PROJECT_ID/global/networks/VPC_NAME` instead of a short network name.\n- Plan capacity per endpoint. Cloud IDS documentation recommends one endpoint per region and one endpoint for each 5 Gbps of peak traffic.\n\n## Official Sources\n\n- Google Cloud IDS Python reference: https://cloud.google.com/python/docs/reference/ids/latest\n- `IDSClient` reference: https://docs.cloud.google.com/python/docs/reference/ids/latest/google.cloud.ids_v1.services.ids.IDSClient\n- `Endpoint` reference: https://docs.cloud.google.com/python/docs/reference/ids/latest/google.cloud.ids_v1.types.Endpoint\n- Cloud IDS best practice: https://cloud.google.com/intrusion-detection-system/docs/best-practice\n- Create and configure endpoints: https://cloud.google.com/intrusion-detection-system/docs/configuring-ids\n- Cloud IDS overview: https://cloud.google.com/intrusion-detection-system/docs/overview\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- PyPI package page: https://pypi.org/project/google-cloud-ids/\n"
  },
  {
    "path": "content/google/docs/iot/python/DOC.md",
    "content": "---\nname: iot\ndescription: \"Legacy Google Cloud IoT Core Python client library for maintaining existing device manager code and resource models\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,iot,cloudiot,devices,pubsub,legacy\"\n---\n\n# Google Cloud IoT Python Client Library\n\n## Golden Rule\n\n`google-cloud-iot` is a legacy client for Google Cloud IoT Core. The official repository is archived, and the upstream README says Cloud IoT Core was retired in August 2023. Use this package only to read, maintain, or migrate older codebases. Do not choose it for new systems. When you do touch existing code, import `from google.cloud import iot_v1`, authenticate with Application Default Credentials (ADC), and pass request objects or request dicts to client methods.\n\n## Install\n\nPin the exact version your legacy project expects:\n\n```bash\npython -m pip install \"google-cloud-iot==2.9.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-iot==2.9.2\"\npoetry add \"google-cloud-iot==2.9.2\"\n```\n\nPractical note: there have been no new releases after `2.9.2`, so treat newer Python runtimes as unvalidated unless your own test matrix proves otherwise.\n\n## Authentication And Setup\n\nThe client uses Google authentication plumbing, so use ADC first:\n\n1. Local development: `gcloud auth application-default login`\n2. Google Cloud runtime with an attached service account\n3. `GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json` only when the first two are not possible\n\nBasic setup:\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\n\nparent = \"projects/my-project/locations/us-central1\"\nregistry_name = f\"{parent}/registries/my-registry\"\ndevice_name = f\"{registry_name}/devices/device-1\"\n```\n\nIf legacy code needs a non-default endpoint or transport settings, use the generated GAPIC knobs such as `client_options` and `transport`. Keep that configuration explicit in tests because this package is old and no longer evolving.\n\n## Core Usage\n\nThese examples are for maintaining old code and understanding the current 2.x request shapes. They are not a recommendation to build new Cloud IoT Core workflows.\n\n### List registries in a location\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nfor registry in client.list_device_registries(request={\"parent\": parent}):\n    print(registry.id)\n```\n\n### List devices in a registry\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\nregistry_name = \"projects/my-project/locations/us-central1/registries/my-registry\"\n\nfor device in client.list_devices(request={\"parent\": registry_name}):\n    print(device.id, device.num_id)\n```\n\n### Read one device and its config history\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\ndevice_name = \"projects/my-project/locations/us-central1/registries/my-registry/devices/device-1\"\n\ndevice = client.get_device(request={\"name\": device_name})\nprint(device.id)\n\nfor version in client.list_device_config_versions(request={\"name\": device_name}):\n    print(version.version, version.cloud_update_time)\n```\n\n### Update persistent cloud-to-device config\n\nUse `modify_cloud_to_device_config` when the device should fetch a versioned config payload later.\n\n```python\nimport json\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\ndevice_name = \"projects/my-project/locations/us-central1/registries/my-registry/devices/device-1\"\n\npayload = json.dumps({\"sampling_interval_s\": 60}).encode(\"utf-8\")\n\nconfig = client.modify_cloud_to_device_config(\n    request={\n        \"name\": device_name,\n        \"binary_data\": payload,\n    }\n)\n\nprint(config.version)\n```\n\n### Send an immediate command\n\nUse `send_command_to_device` for transient commands rather than durable config.\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\ndevice_name = \"projects/my-project/locations/us-central1/registries/my-registry/devices/device-1\"\n\nclient.send_command_to_device(\n    request={\n        \"name\": device_name,\n        \"binary_data\": b\"reboot\",\n        \"subfolder\": \"ops\",\n    }\n)\n```\n\n### Create or inspect registry definitions in legacy code\n\nRegistry objects usually wire Pub/Sub topics for telemetry and state:\n\n```python\nfrom google.cloud import iot_v1\n\nclient = iot_v1.DeviceManagerClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nregistry = {\n    \"id\": \"my-registry\",\n    \"event_notification_configs\": [\n        {\n            \"pubsub_topic_name\": \"projects/my-project/topics/device-events\",\n        }\n    ],\n    \"state_notification_config\": {\n        \"pubsub_topic_name\": \"projects/my-project/topics/device-state\",\n    },\n}\n\ncreated = client.create_device_registry(\n    request={\n        \"parent\": parent,\n        \"device_registry\": registry,\n    }\n)\n\nprint(created.name)\n```\n\n## Configuration And Data Model Notes\n\n- Resource names are full paths, not short IDs. Use strings like `projects/.../locations/.../registries/.../devices/...`.\n- `DeviceManagerClient` is the main service client. Most legacy code only touches this one client.\n- Device credentials use `DeviceCredential` and `PublicKeyCredential`; there is no API-key-style auth for devices.\n- Registry routing is Pub/Sub-based. Event and state topics must already exist, and the relevant Google-managed service identities need permission to publish.\n- `binary_data` fields are bytes. Encode JSON manually with `json.dumps(...).encode(\"utf-8\")`.\n- The generated 2.x client accepts either strongly typed request objects or plain request dicts. Request dicts are usually simpler for maintenance work.\n\n## Common Pitfalls\n\n- The service is retired. Official reference pages still exist, but live Cloud IoT Core workflows are no longer a valid choice for new Google Cloud systems.\n- The repo is archived, so do not expect bugfixes, new features, or updated Python-version classifiers.\n- Older blog posts often show 1.x positional-call patterns. The 2.x client follows GAPIC request-object style instead.\n- Device, registry, and location strings are easy to mix up. Most method failures in old code come from malformed resource names.\n- `modify_cloud_to_device_config` stores durable config versions; `send_command_to_device` is for immediate commands. They are not interchangeable.\n- Pub/Sub topic wiring is registry-level configuration. If legacy code creates registries, missing topics or IAM permissions will break event/state delivery.\n\n## Version-Sensitive Notes\n\n- Official PyPI metadata and the Google Cloud Python reference both show `2.9.2` as the current published package version as of `2026-03-12`.\n- The important upgrade boundary is `2.0.0`. If you are maintaining pre-2.x code, check the upstream migration guide before translating older samples.\n- Upstream metadata still advertises `>=3.7`, but the archived package has no active release train for modern Python versions. Verify `3.12+` behavior in your own environment before depending on it.\n\n## Official Sources\n\n- Reference docs: `https://cloud.google.com/python/docs/reference/cloudiot/latest`\n- Main client reference: `https://cloud.google.com/python/docs/reference/cloudiot/latest/google.cloud.iot_v1.services.device_manager.DeviceManagerClient`\n- Migration guide: `https://cloud.google.com/python/docs/reference/cloudiot/latest/migration`\n- ADC guide: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- GitHub repo and archived README: `https://github.com/googleapis/python-iot`\n- PyPI package page: `https://pypi.org/project/google-cloud-iot/`\n"
  },
  {
    "path": "content/google/docs/kms/javascript/DOC.md",
    "content": "---\nname: kms\ndescription: \"Google Cloud KMS Node.js client for key rings, crypto keys, IAM-aware setup, and symmetric encrypt/decrypt workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,kms,cloud-kms,encryption,gcp,javascript,nodejs,adc\"\n---\n\n# `@google-cloud/kms` JavaScript Package Guide\n\nUse `@google-cloud/kms` when your Node.js code needs to create key rings, create crypto keys, inspect key metadata and versions, and encrypt or decrypt application data with Google Cloud KMS.\n\n## Golden Rule\n\n- Import `KeyManagementServiceClient` from `@google-cloud/kms`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass a credential file directly.\n- Most methods expect fully qualified resource names, not short IDs.\n- `encrypt()` and `decrypt()` are for symmetric keys whose purpose is `ENCRYPT_DECRYPT`.\n- Treat ciphertext as bytes. Base64-encode it yourself before storing it in JSON, text columns, or message payloads.\n\nThis guide covers `5.4.0`.\n\n## Install\n\nPin the package version your app or agent should target:\n\n```bash\nnpm install @google-cloud/kms@5.4.0\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials, not API keys.\n\nEnable the Cloud KMS API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable cloudkms.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_CLOUD_KMS_KEY_RING=\"app-secrets\"\nexport GOOGLE_CLOUD_KMS_KEY=\"primary\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_CLOUD_KMS_KEY_RING=\"app-secrets\"\nexport GOOGLE_CLOUD_KMS_KEY=\"primary\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nTypical permissions:\n\n- symmetric encrypt/decrypt: `roles/cloudkms.cryptoKeyEncrypterDecrypter`\n- metadata reads and listings: `roles/cloudkms.viewer`\n- key and key ring administration: `roles/cloudkms.admin` or narrower resource-specific roles\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {KeyManagementServiceClient} from '@google-cloud/kms';\n\nconst client = new KeyManagementServiceClient();\n```\n\nWith explicit project ID and credential file:\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Resource Names\n\nCloud KMS methods expect fully qualified resource names.\n\nCommon patterns:\n\n- location parent: `projects/{project}/locations/{location}`\n- key ring: `projects/{project}/locations/{location}/keyRings/{keyRing}`\n- crypto key: `projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{cryptoKey}`\n- crypto key version: `projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{cryptoKey}/cryptoKeyVersions/{version}`\n\nPrefer the path helpers on the client instead of building deep paths manually:\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nconst keyRingName = client.keyRingPath('my-project', 'us-central1', 'app-secrets');\nconst cryptoKeyName = client.cryptoKeyPath(\n  'my-project',\n  'us-central1',\n  'app-secrets',\n  'primary'\n);\n```\n\n## Core Workflows\n\n### Create A Key Ring\n\nKey rings are location-scoped containers for crypto keys.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function createKeyRing(projectId, locationId, keyRingId) {\n  const parent = client.locationPath(projectId, locationId);\n\n  const [keyRing] = await client.createKeyRing({\n    parent,\n    keyRingId,\n    keyRing: {},\n  });\n\n  return keyRing;\n}\n\ncreateKeyRing('my-project', 'us-central1', 'app-secrets').catch(console.error);\n```\n\n### Create A Symmetric Crypto Key\n\nUse `ENCRYPT_DECRYPT` with `GOOGLE_SYMMETRIC_ENCRYPTION` for standard symmetric encryption workflows.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function createCryptoKey(projectId, locationId, keyRingId, cryptoKeyId) {\n  const parent = client.keyRingPath(projectId, locationId, keyRingId);\n\n  const [cryptoKey] = await client.createCryptoKey({\n    parent,\n    cryptoKeyId,\n    cryptoKey: {\n      purpose: 'ENCRYPT_DECRYPT',\n      versionTemplate: {\n        algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION',\n      },\n    },\n  });\n\n  return cryptoKey;\n}\n\ncreateCryptoKey('my-project', 'us-central1', 'app-secrets', 'primary').catch(\n  console.error\n);\n```\n\nFor production keys, add rotation policy, labels, protection level, import settings, or HSM and EKM configuration deliberately instead of copying a minimal example unchanged.\n\n### Encrypt Data With A Symmetric Key\n\n`encrypt()` expects the crypto key resource name, not a crypto key version name.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function encryptText(projectId, locationId, keyRingId, cryptoKeyId, text) {\n  const name = client.cryptoKeyPath(\n    projectId,\n    locationId,\n    keyRingId,\n    cryptoKeyId\n  );\n\n  const [response] = await client.encrypt({\n    name,\n    plaintext: Buffer.from(text, 'utf8'),\n  });\n\n  return response.ciphertext.toString('base64');\n}\n\nencryptText('my-project', 'us-central1', 'app-secrets', 'primary', 'secret payload')\n  .then(console.log)\n  .catch(console.error);\n```\n\n### Decrypt Data\n\nIf you serialized ciphertext to text, convert it back to bytes before calling `decrypt()`.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function decryptText(\n  projectId,\n  locationId,\n  keyRingId,\n  cryptoKeyId,\n  ciphertextBase64\n) {\n  const name = client.cryptoKeyPath(\n    projectId,\n    locationId,\n    keyRingId,\n    cryptoKeyId\n  );\n\n  const [response] = await client.decrypt({\n    name,\n    ciphertext: Buffer.from(ciphertextBase64, 'base64'),\n  });\n\n  return response.plaintext.toString('utf8');\n}\n\ndecryptText(\n  'my-project',\n  'us-central1',\n  'app-secrets',\n  'primary',\n  process.env.CIPHERTEXT_BASE64\n)\n  .then(console.log)\n  .catch(console.error);\n```\n\n### Inspect One Crypto Key\n\nUse this to confirm the key name, purpose, and current primary version.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function getCryptoKey(projectId, locationId, keyRingId, cryptoKeyId) {\n  const name = client.cryptoKeyPath(\n    projectId,\n    locationId,\n    keyRingId,\n    cryptoKeyId\n  );\n\n  const [cryptoKey] = await client.getCryptoKey({name});\n\n  return {\n    name: cryptoKey.name,\n    purpose: cryptoKey.purpose,\n    primaryVersion: cryptoKey.primary?.name,\n  };\n}\n\ngetCryptoKey('my-project', 'us-central1', 'app-secrets', 'primary')\n  .then(console.log)\n  .catch(console.error);\n```\n\n### List Crypto Key Versions\n\nUse this when troubleshooting disabled, pending-destruction, or destroyed versions.\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function listCryptoKeyVersions(projectId, locationId, keyRingId, cryptoKeyId) {\n  const parent = client.cryptoKeyPath(\n    projectId,\n    locationId,\n    keyRingId,\n    cryptoKeyId\n  );\n\n  const [versions] = await client.listCryptoKeyVersions({parent});\n\n  return versions.map((version) => ({\n    name: version.name,\n    state: version.state,\n  }));\n}\n\nlistCryptoKeyVersions('my-project', 'us-central1', 'app-secrets', 'primary')\n  .then(console.log)\n  .catch(console.error);\n```\n\n### List Key Rings In A Location\n\n```javascript\nconst {KeyManagementServiceClient} = require('@google-cloud/kms');\n\nconst client = new KeyManagementServiceClient();\n\nasync function listKeyRings(projectId, locationId) {\n  const parent = client.locationPath(projectId, locationId);\n  const [keyRings] = await client.listKeyRings({parent});\n\n  return keyRings.map((keyRing) => keyRing.name);\n}\n\nlistKeyRings('my-project', 'us-central1').then(console.log).catch(console.error);\n```\n\n## Configuration Notes\n\n- Prefer ADC from the runtime environment over distributing service account JSON files.\n- Prefer path helpers such as `locationPath()`, `keyRingPath()`, and `cryptoKeyPath()` over hand-built strings.\n- Add rotation, HSM, EKM, labels, and import settings intentionally. The minimal examples here create software-backed defaults unless you specify otherwise.\n- The API also supports CRC32C integrity fields on encrypt and decrypt requests and responses. Use them when request or response integrity matters.\n\n## Common Pitfalls\n\n- The package name is `@google-cloud/kms`, and the main client for common workflows is `KeyManagementServiceClient`.\n- `encrypt()` and `decrypt()` are for symmetric keys. Asymmetric workflows use different operations such as signing, asymmetric decrypt, and public-key retrieval.\n- Most methods require full resource names, not just the key ring ID or crypto key ID.\n- `PermissionDenied`, `NotFound`, and `FailedPrecondition` often mean IAM, API enablement, key state, or location mismatches rather than a bad client call.\n- Disabled or destroyed key versions cannot be used for new cryptographic operations.\n- The maintainer reference URL uses `latest`, so confirm release-specific behavior against the installed package when you depend on something very recent.\n\n## Version-Sensitive Notes For `5.4.0`\n\n- This guide targets `@google-cloud/kms` version `5.4.0`.\n- The maintainer Node.js reference is a rolling `latest` URL rather than a frozen `5.4.0` snapshot.\n- If you need release-specific behavior, verify it against the installed package and the package release history before depending on it.\n\n## Official Sources\n\n- Node.js package reference: `https://cloud.google.com/nodejs/docs/reference/kms/latest`\n- Cloud KMS product docs: `https://cloud.google.com/kms/docs`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/kms`\n- Package source: `https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-kms`\n"
  },
  {
    "path": "content/google/docs/kms/python/DOC.md",
    "content": "---\nname: kms\ndescription: \"Google Cloud KMS Python client for key rings, crypto keys, IAM-aware setup, and symmetric encrypt/decrypt workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,kms,cloud-kms,encryption,gcp,adc\"\n---\n\n# Google Cloud KMS Python Client\n\nUse `google-cloud-kms` for Cloud KMS automation from Python. Install the PyPI package, authenticate with Application Default Credentials (ADC), import `kms_v1`, and work with fully qualified resource names for key rings, crypto keys, and crypto key versions.\n\n```python\nfrom google.cloud import kms_v1\n```\n\n## Version Note\n\nThis entry is written against package version `3.11.0`, which PyPI lists as the current visible release as of `2026-03-12`.\n\nOfficial upstream pages do not fully agree on freshness:\n\n- PyPI lists `3.11.0`\n- the `KeyManagementServiceClient` reference page renders `3.11.0`\n- the docs overview page and changelog under `latest` still render `3.7.0` as the latest visible version\n\nPractical implication:\n\n- the examples below use the current `kms_v1` client surface\n- if you need a field or method added very recently, confirm it against the installed wheel and the class reference page, not only the overview page\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-kms==3.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-kms==3.11.0\"\npoetry add \"google-cloud-kms==3.11.0\"\n```\n\nPyPI currently declares Python `>=3.7` for this package.\n\n## Setup And Authentication\n\nBefore writing code:\n\n1. Select the Google Cloud project that owns the KMS resources.\n2. Enable the Cloud KMS API.\n3. Authenticate with ADC.\n4. Make sure the principal has the right IAM role on the project, key ring, or key.\n\nEnable the API:\n\n```bash\ngcloud services enable cloudkms.googleapis.com\n```\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nIf you must use a service account key file locally:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nTypical permissions:\n\n- symmetric encrypt/decrypt: `roles/cloudkms.cryptoKeyEncrypterDecrypter`\n- metadata reads and listings: `roles/cloudkms.viewer`\n- key and key ring administration: `roles/cloudkms.admin` or narrower resource-specific roles\n\n## Client Creation\n\nDefault client with ADC:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceAsyncClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nREST transport instead of gRPC:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient(transport=\"rest\")\n```\n\nCustom endpoint:\n\n```python\nfrom google.cloud import kms_v1\nfrom google.api_core.client_options import ClientOptions\n\nclient = kms_v1.KeyManagementServiceClient(\n    client_options=ClientOptions(api_endpoint=\"cloudkms.googleapis.com\")\n)\n```\n\n## Resource Names\n\nCloud KMS methods expect fully qualified resource names.\n\nCommon patterns:\n\n- location parent: `projects/{project}/locations/{location}`\n- key ring: `projects/{project}/locations/{location}/keyRings/{key_ring}`\n- crypto key: `projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}`\n- crypto key version: `projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}/cryptoKeyVersions/{version}`\n\nPrefer the helper methods on the client instead of building deep paths manually:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\n\nkey_ring_name = client.key_ring_path(\"my-project\", \"us-central1\", \"app-secrets\")\ncrypto_key_name = client.crypto_key_path(\n    \"my-project\",\n    \"us-central1\",\n    \"app-secrets\",\n    \"primary\",\n)\n```\n\n## Core Usage\n\n### List Key Rings In A Location\n\n```python\nimport os\nfrom google.cloud import kms_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = kms_v1.KeyManagementServiceClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor key_ring in client.list_key_rings(request={\"parent\": parent}):\n    print(key_ring.name)\n```\n\n### Inspect One Crypto Key\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nname = client.crypto_key_path(\"my-project\", \"us-central1\", \"app-secrets\", \"primary\")\n\ncrypto_key = client.get_crypto_key(request={\"name\": name})\n\nprint(crypto_key.name)\nprint(crypto_key.primary.name if crypto_key.primary else \"no primary version\")\nprint(crypto_key.purpose.name)\n```\n\n`crypto_key.primary` tells you which key version will be used by operations such as symmetric encrypt unless you explicitly target a version elsewhere.\n\n### List Crypto Key Versions\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nparent = client.crypto_key_path(\"my-project\", \"us-central1\", \"app-secrets\", \"primary\")\n\nfor version in client.list_crypto_key_versions(request={\"parent\": parent}):\n    print(version.name, version.state.name)\n```\n\nUse this when troubleshooting disabled, pending-destruction, or destroyed versions.\n\n### Encrypt Data With A Symmetric Key\n\n`encrypt()` expects a symmetric key whose purpose is `ENCRYPT_DECRYPT`.\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nname = client.crypto_key_path(\"my-project\", \"us-central1\", \"app-secrets\", \"primary\")\n\nplaintext = b\"secret payload\"\nresponse = client.encrypt(\n    request={\n        \"name\": name,\n        \"plaintext\": plaintext,\n    }\n)\n\nciphertext = response.ciphertext\nprint(len(ciphertext))\n```\n\n### Decrypt Data\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nname = client.crypto_key_path(\"my-project\", \"us-central1\", \"app-secrets\", \"primary\")\n\ndecrypt_response = client.decrypt(\n    request={\n        \"name\": name,\n        \"ciphertext\": ciphertext,\n    }\n)\n\nprint(decrypt_response.plaintext.decode(\"utf-8\"))\n```\n\nIf you store ciphertext in JSON, a database text column, or another text-only channel, base64-encode it yourself before serialization and decode it back to `bytes` before calling `decrypt()`.\n\n### Create A Key Ring\n\nInfrastructure code often creates key rings once and reuses them for many keys:\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nkey_ring = client.create_key_ring(\n    request={\n        \"parent\": parent,\n        \"key_ring_id\": \"app-secrets\",\n        \"key_ring\": kms_v1.KeyRing(),\n    }\n)\n\nprint(key_ring.name)\n```\n\n### Create A Symmetric Crypto Key\n\n```python\nfrom google.cloud import kms_v1\n\nclient = kms_v1.KeyManagementServiceClient()\nparent = client.key_ring_path(\"my-project\", \"us-central1\", \"app-secrets\")\n\ncrypto_key = client.create_crypto_key(\n    request={\n        \"parent\": parent,\n        \"crypto_key_id\": \"primary\",\n        \"crypto_key\": kms_v1.CryptoKey(\n            purpose=kms_v1.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT,\n            version_template=kms_v1.CryptoKeyVersionTemplate(\n                algorithm=(\n                    kms_v1.CryptoKeyVersion.CryptoKeyVersionAlgorithm\n                    .GOOGLE_SYMMETRIC_ENCRYPTION\n                )\n            ),\n        ),\n    }\n)\n\nprint(crypto_key.name)\n```\n\nFor production keys, add rotation policy, labels, protection level, import settings, or HSM/EKM configuration deliberately instead of copying a minimal example unchanged.\n\n## Configuration Notes\n\n- Prefer ADC from the runtime environment over distributing service account JSON files.\n- Pass transport or endpoint overrides through the client constructor rather than patching internals.\n- If you need library logging, Google’s package docs document the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable. Use a logger scope starting with `google`, such as `google.cloud.kms_v1`.\n- The generated client also exposes path parser helpers such as `parse_crypto_key_path(...)` when you need to decompose a full resource name.\n\n## Integrity Checks And Data Handling\n\nThe KMS API supports CRC32C integrity fields on encrypt and decrypt requests and responses, including:\n\n- `plaintext_crc32c`\n- `ciphertext_crc32c`\n- `verified_plaintext_crc32c`\n- `verified_ciphertext_crc32c`\n\nUse those fields when request/response integrity matters, especially for high-assurance systems or when payloads move through intermediaries. The generated reference documents these fields on the encrypt and decrypt request/response types.\n\n## Common Pitfalls\n\n- The package name is `google-cloud-kms`, but the import surface for new code is `google.cloud.kms_v1`.\n- `encrypt()` and `decrypt()` are for symmetric keys. Asymmetric keys use different methods such as `asymmetric_sign`, `asymmetric_decrypt`, and public-key retrieval.\n- Most methods require full resource names, not short IDs.\n- `PermissionDenied`, `NotFound`, and `FailedPrecondition` often mean IAM, API enablement, key state, or location mismatches rather than a bad client call.\n- Disabled or destroyed key versions cannot be used for new crypto operations.\n- Older examples may import `from google.cloud import kms`; prefer `kms_v1` for current code.\n- The rolling docs overview currently lags PyPI for this package. Verify very recent behavior against the installed package and the class reference page.\n\n## Version-Sensitive Notes\n\n- The official changelog marks `3.0.0` as a breaking release to support `protobuf 5.x`.\n- The same changelog notes async REST transport support in the 3.x line, so transport behavior can differ from older 2.x examples.\n- On `2026-03-12`, PyPI and the class reference page show `3.11.0`, but the docs overview and changelog pages under `latest` still render `3.7.0`. Treat that as docs-site lag, not as evidence that `3.11.0` is unpublished.\n\n## Official Sources Used\n\n- `https://pypi.org/project/google-cloud-kms/`\n- `https://cloud.google.com/python/docs/reference/cloudkms/latest`\n- `https://docs.cloud.google.com/python/docs/reference/cloudkms/latest/google.cloud.kms_v1.services.key_management_service.KeyManagementServiceClient`\n- `https://cloud.google.com/python/docs/reference/cloudkms/latest/changelog`\n- `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms`\n"
  },
  {
    "path": "content/google/docs/language/javascript/DOC.md",
    "content": "---\nname: language\ndescription: \"Google Cloud Natural Language Node.js client for sentiment, entity, moderation, and text classification workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,natural-language,nlp,sentiment,entities,moderation,text-classification\"\n---\n\n# Google Cloud Natural Language Node.js Client\n\n## Golden Rule\n\nUse the official `@google-cloud/language` package with Application Default Credentials (ADC), and choose one API namespace per code path. For new code, prefer the `v2` namespace for sentiment, entities, moderation, classification, and combined `annotateText` requests.\n\nUse one of these import patterns:\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n```\n\n```javascript\nimport {v2} from '@google-cloud/language';\n\nconst client = new v2.LanguageServiceClient();\n```\n\nOlder examples often use the package's top-level `LanguageServiceClient`, which typically targets older API shapes. Keep the client namespace and the request fields consistent throughout the file.\n\n## Install\n\nPin the version your app expects:\n\n```bash\nnpm install @google-cloud/language@7.2.1\n```\n\n## Authentication And Project Setup\n\nFor local development, authenticate ADC with the Google Cloud CLI:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\ngcloud services enable language.googleapis.com --project=\"$GOOGLE_CLOUD_PROJECT\"\n```\n\nIf you must use a service account key locally or outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\n## Initialize A Client\n\nBasic client construction:\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n```\n\nWith explicit project and key file settings:\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC already resolves both credentials and project ID in your runtime, you can usually omit constructor options.\n\n## Core Request Shape\n\nMost requests start with a `document` object. Supply either inline `content` or a Cloud Storage URI with `gcsContentUri`.\n\n```javascript\nconst document = {\n  content: 'Google Cloud Natural Language can score sentiment and extract entities.',\n  type: 'PLAIN_TEXT',\n  languageCode: 'en',\n};\n```\n\nFor large inputs already stored in Cloud Storage:\n\n```javascript\nconst document = {\n  gcsContentUri: 'gs://your-bucket/input/article.txt',\n  type: 'PLAIN_TEXT',\n  languageCode: 'en',\n};\n```\n\nUse `encodingType: 'UTF8'` when you need stable offsets for mentions or syntax-related data.\n\n## Analyze Sentiment\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n\nasync function analyzeSentiment() {\n  const document = {\n    content: 'The launch went well and customers were happy with the result.',\n    type: 'PLAIN_TEXT',\n    languageCode: 'en',\n  };\n\n  const [response] = await client.analyzeSentiment({\n    document,\n    encodingType: 'UTF8',\n  });\n\n  console.log(response.documentSentiment?.score);\n  console.log(response.documentSentiment?.magnitude);\n}\n\nanalyzeSentiment().catch(console.error);\n```\n\n## Analyze Entities\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n\nasync function analyzeEntities() {\n  const document = {\n    content: 'Google Cloud opened a new office in Seattle.',\n    type: 'PLAIN_TEXT',\n    languageCode: 'en',\n  };\n\n  const [response] = await client.analyzeEntities({\n    document,\n    encodingType: 'UTF8',\n  });\n\n  for (const entity of response.entities ?? []) {\n    console.log(entity.name, entity.salience);\n  }\n}\n\nanalyzeEntities().catch(console.error);\n```\n\n## Combine Features With `annotateText`\n\nUse `annotateText` when you want one request that bundles the supported `v2` features.\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n\nasync function annotateText() {\n  const document = {\n    content: 'Google Cloud\\'s update improved moderation and sentiment reporting for long-form content.',\n    type: 'PLAIN_TEXT',\n    languageCode: 'en',\n  };\n\n  const [response] = await client.annotateText({\n    document,\n    features: {\n      extractEntities: true,\n      extractDocumentSentiment: true,\n      classifyText: true,\n      moderateText: true,\n    },\n    encodingType: 'UTF8',\n  });\n\n  console.log(response.documentSentiment?.score);\n  console.log((response.entities ?? []).map((entity) => entity.name));\n  console.log((response.categories ?? []).map((category) => category.name));\n  console.log((response.moderationCategories ?? []).map((category) => category.name));\n}\n\nannotateText().catch(console.error);\n```\n\n## Classify Text\n\nText classification is for longer document-style content. The product docs require at least 20 words.\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n\nasync function classifyText() {\n  const document = {\n    content: 'This article explains how machine learning models are trained, evaluated, deployed, monitored, and improved across business analytics and product engineering workflows.',\n    type: 'PLAIN_TEXT',\n    languageCode: 'en',\n  };\n\n  const [response] = await client.classifyText({document});\n\n  for (const category of response.categories ?? []) {\n    console.log(category.name, category.confidence);\n  }\n}\n\nclassifyText().catch(console.error);\n```\n\nFor large documents already in Cloud Storage, switch the `document` source to `gcsContentUri` instead of reading the whole body into memory.\n\n## Moderate Text\n\nUse `moderateText` when you want the Natural Language API to score text against moderation categories.\n\n```javascript\nconst language = require('@google-cloud/language').v2;\n\nconst client = new language.LanguageServiceClient();\n\nasync function moderateText() {\n  const document = {\n    content: 'Example text to score against moderation categories.',\n    type: 'PLAIN_TEXT',\n    languageCode: 'en',\n  };\n\n  const [response] = await client.moderateText({document});\n\n  for (const category of response.moderationCategories ?? []) {\n    console.log(category.name, category.confidence);\n  }\n}\n\nmoderateText().catch(console.error);\n```\n\n## Namespace Choice: `v2` vs Older Samples\n\nThe maintained `v2` guide surface centers on these methods:\n\n- `analyzeEntities`\n- `analyzeSentiment`\n- `annotateText`\n- `classifyText`\n- `moderateText`\n\nIf you are reviving an older integration that depends on syntax analysis or other older request shapes, verify those calls against the older reference before copying top-level `LanguageServiceClient` examples into new code.\n\n## Common Pitfalls\n\n- Do not use API keys with this client. Use ADC, user credentials, or a service account.\n- Set exactly one document source: inline `content` or `gcsContentUri`.\n- Keep the namespace consistent. Do not mix `require('@google-cloud/language').v2` examples with older top-level client samples in the same file.\n- In Node.js request objects, use camelCase fields such as `languageCode`, `gcsContentUri`, and `encodingType`.\n- `classifyText` is for longer document-style content, not short snippets.\n- If `language.googleapis.com` is not enabled in the target project, authentication can succeed while API calls still fail.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/language` `7.2.1`.\n- The maintainer Node.js reference uses a `latest` URL rather than a version-pinned `7.2.1` page.\n- Older search results often land on pre-`v2` examples. Match your import path and method names to the API namespace you intentionally chose.\n\n## Official Sources\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/language/latest`\n- Natural Language product docs: `https://cloud.google.com/natural-language/docs`\n- Sentiment guide: `https://cloud.google.com/natural-language/docs/analyzing-sentiment`\n- Entity analysis guide: `https://cloud.google.com/natural-language/docs/analyzing-entities`\n- Text classification guide: `https://cloud.google.com/natural-language/docs/classifying-text`\n- Text moderation guide: `https://cloud.google.com/natural-language/docs/moderating-text`\n- ADC setup for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC for production workloads: `https://cloud.google.com/docs/authentication/set-up-adc-attached-service-account`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/language`\n"
  },
  {
    "path": "content/google/docs/language/python/DOC.md",
    "content": "---\nname: language\ndescription: \"Google Cloud Natural Language Python client library for sentiment, entity, moderation, and text classification workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.19.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,natural-language,nlp,sentiment,entities,moderation,text-classification\"\n---\n\n# Google Cloud Natural Language Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-language` package with Application Default Credentials (ADC), and pick one API namespace per code path. For new code, `language_v2` is the clearest default for sentiment, entities, moderation, classification, and combined `annotate_text` requests. Older examples may still use `language_v1` or `language_v1beta2`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-language==2.19.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-language==2.19.0\"\npoetry add \"google-cloud-language==2.19.0\"\n```\n\n## Authentication And Setup\n\nFor local development, authenticate ADC with the Google Cloud CLI:\n\n```bash\ngcloud auth application-default login\n```\n\nFor deployed workloads on Google Cloud, prefer an attached user-managed service account instead of shipping key files.\n\nIf you must use a service account key locally or outside Google Cloud, point ADC at the file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nThe client picks credentials up automatically:\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\n```\n\nFor explicit credentials or a custom endpoint, pass `credentials=` and `client_options=`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import language_v2\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\n\nclient = language_v2.LanguageServiceClient(\n    credentials=credentials,\n    client_options=ClientOptions(api_endpoint=\"language.googleapis.com\"),\n)\n```\n\n## Core Request Shape\n\nMost calls start with a `Document`. In Python, the field is `type_`, not `type`, and you must supply either inline `content` or `gcs_content_uri`.\n\n```python\nfrom google.cloud import language_v2\n\ndocument = language_v2.Document(\n    content=\"Google Cloud Natural Language can score sentiment and extract entities.\",\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n    language_code=\"en\",\n)\n```\n\nUse `EncodingType.UTF8` unless you have a specific reason to map offsets differently.\n\n## Core Usage\n\n### Analyze Sentiment\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\ndocument = language_v2.Document(\n    content=\"The launch went well and customers were happy with the result.\",\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n    language_code=\"en\",\n)\n\nresponse = client.analyze_sentiment(\n    request={\n        \"document\": document,\n        \"encoding_type\": language_v2.EncodingType.UTF8,\n    }\n)\n\nprint(response.document_sentiment.score)\nprint(response.document_sentiment.magnitude)\n```\n\n### Analyze Entities\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\ndocument = language_v2.Document(\n    content=\"Google Cloud opened a new office in Seattle.\",\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n)\n\nresponse = client.analyze_entities(\n    request={\n        \"document\": document,\n        \"encoding_type\": language_v2.EncodingType.UTF8,\n    }\n)\n\nfor entity in response.entities:\n    print(entity.name, entity.type_.name, entity.salience)\n```\n\n### Combine Features With `annotate_text`\n\nUse `annotate_text` when you want one request that bundles the supported v2 features.\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\ndocument = language_v2.Document(\n    content=\"Google Cloud's update improved moderation and sentiment reporting.\",\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n)\nfeatures = language_v2.AnnotateTextRequest.Features(\n    extract_entities=True,\n    extract_document_sentiment=True,\n    classify_text=True,\n    moderate_text=True,\n)\n\nresponse = client.annotate_text(\n    request={\n        \"document\": document,\n        \"features\": features,\n        \"encoding_type\": language_v2.EncodingType.UTF8,\n    }\n)\n\nprint(response.document_sentiment.score)\nprint([entity.name for entity in response.entities])\n```\n\n### Classify Text\n\nClassification is for longer document-style content. The product docs require at least 20 words of text.\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\ndocument = language_v2.Document(\n    content=(\n        \"This article explains how machine learning models are trained, evaluated, \"\n        \"and deployed in production systems for business analytics teams.\"\n    ),\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n)\n\nresponse = client.classify_text(request={\"document\": document})\n\nfor category in response.categories:\n    print(category.name, category.confidence)\n```\n\nFor large documents already in Cloud Storage, use `gcs_content_uri` instead of loading the full body into memory.\n\n## Moderation\n\nUse `moderate_text` or `annotate_text(..., moderate_text=True)` for safety-style classification of harmful content categories:\n\n```python\nfrom google.cloud import language_v2\n\nclient = language_v2.LanguageServiceClient()\ndocument = language_v2.Document(\n    content=\"Example text to score against moderation categories.\",\n    type_=language_v2.Document.Type.PLAIN_TEXT,\n)\n\nresponse = client.moderate_text(request={\"document\": document})\n\nfor category in response.moderation_categories:\n    print(category.name, category.confidence)\n```\n\n## Namespace Choice: `language_v2` vs `language_v1`\n\nThe current latest reference for `language_v2.LanguageServiceClient` exposes these main methods:\n\n- `analyze_entities`\n- `analyze_sentiment`\n- `annotate_text`\n- `classify_text`\n- `moderate_text`\n\nIf you need syntax analysis or entity-sentiment analysis because an older codebase depends on them, check the `language_v1` or `language_v1beta2` namespaces and keep the request/response types from that namespace consistent throughout the file.\n\n## Common Pitfalls\n\n- `Document.type_` is the Python field name. Copying REST examples that use `type` will fail.\n- Set exactly one document source: inline `content` or `gcs_content_uri`.\n- Prefer ADC over embedding service-account JSON in code. Use `gcloud auth application-default login` locally and attached service accounts in production.\n- Google Cloud docs mix product guides and API reference pages. Use the product docs for behavioral limits, and the Python reference for exact class and field names.\n- Older examples often import `language_v1`. Do not mix `language_v1.Document` with a `language_v2.LanguageServiceClient`.\n- `classify_text` is not for short snippets. If the text is too short, classification quality will be poor and requests may be rejected.\n- Use UTF-8 encoding offsets unless your downstream consumer explicitly expects a different encoding.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-language 2.19.0`.\n- The API reference pages are current for `2.19.0`, but the changelog page under the same docs root still tops out at `2.18.0`. Validate behavior against both the reference and the product docs when investigating recent changes.\n- The package still ships multiple namespaces (`language_v1`, `language_v1beta2`, `language_v2`), so many search results point at older samples. Match your imports to the namespace you intentionally chose.\n- The client constructor still accepts several convenience arguments, but the changelog notes deprecations around `credentials_file`; prefer explicit `credentials=` for new code.\n\n## Official Sources\n\n- Python reference root: `https://cloud.google.com/python/docs/reference/language/latest`\n- `language_v2.LanguageServiceClient`: `https://cloud.google.com/python/docs/reference/language/latest/google.cloud.language_v2.services.language_service.LanguageServiceClient`\n- `Document` type: `https://cloud.google.com/python/docs/reference/language/latest/google.cloud.language_v2.types.Document`\n- Changelog: `https://cloud.google.com/python/docs/reference/language/latest/changelog`\n- ADC setup for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC for production workloads: `https://cloud.google.com/docs/authentication/set-up-adc-attached-service-account`\n- Natural Language product docs: `https://cloud.google.com/natural-language/docs`\n- Sentiment guide: `https://cloud.google.com/natural-language/docs/analyzing-sentiment`\n- Classification guide: `https://cloud.google.com/natural-language/docs/classifying-text`\n- PyPI package page: `https://pypi.org/project/google-cloud-language/`\n"
  },
  {
    "path": "content/google/docs/life-sciences/python/DOC.md",
    "content": "---\nname: life-sciences\ndescription: \"Google Cloud Life Sciences Python client for legacy pipeline submission and operation inspection\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,life-sciences,genomics,pipelines,batch,migration\"\n---\n\n# Google Cloud Life Sciences Python Client\n\n## Golden Rule\n\nUse `google-cloud-life-sciences` with `from google.cloud import lifesciences_v2beta` only for existing codebases that still reference Cloud Life Sciences. Google deprecated Cloud Life Sciences on July 17, 2023 and shut the service down on July 8, 2025. For new workflow execution, Google directs users to Cloud Batch instead.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-life-sciences==0.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-life-sciences==0.11.0\"\npoetry add \"google-cloud-life-sciences==0.11.0\"\n```\n\nThe package name and import path differ:\n\n```python\nfrom google.cloud import lifesciences_v2beta\n```\n\n## Authentication And Setup\n\nUse Application Default Credentials (ADC) unless you already have an explicit `google.auth.credentials.Credentials` object.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nService account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nMinimal client setup:\n\n```python\nfrom google.cloud import lifesciences_v2beta\n\nclient = lifesciences_v2beta.WorkflowsServiceV2BetaClient()\n```\n\nImportant setup details from the official docs:\n\n- Cloud Life Sciences required billing on the target Google Cloud project.\n- Running a pipeline required permission to call the workflow API and permission to act as the VM service account used by the pipeline.\n- The Python client follows normal Google client behavior for endpoint overrides through `client_options.api_endpoint` and for credential injection through the `credentials=` argument.\n\n## Core Workflow\n\n### List available metadata locations\n\nThe `parent` on Life Sciences requests is a metadata location such as `projects/PROJECT_ID/locations/us-central1`. It is separate from the Compute Engine region or zone where VMs run.\n\n```python\nfrom google.cloud import lifesciences_v2beta\n\nproject_id = \"YOUR_PROJECT_ID\"\nclient = lifesciences_v2beta.WorkflowsServiceV2BetaClient()\n\nfor location in client.list_locations(\n    request={\"name\": f\"projects/{project_id}\"}\n):\n    print(location.location_id, location.name)\n```\n\nUse this when you are reading legacy configs and need to confirm which Life Sciences locations a project used.\n\n### Build and submit a legacy pipeline request\n\nThis is the core API surface of the package: `run_pipeline()` on `WorkflowsServiceV2BetaClient`.\n\n```python\nfrom google.cloud import lifesciences_v2beta\n\nproject_id = \"YOUR_PROJECT_ID\"\nmetadata_location = \"us-central1\"\nvm_region = \"us-central1\"\nservice_account_email = \"pipeline-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com\"\n\nclient = lifesciences_v2beta.WorkflowsServiceV2BetaClient()\n\nrequest = lifesciences_v2beta.RunPipelineRequest(\n    parent=f\"projects/{project_id}/locations/{metadata_location}\",\n    pipeline=lifesciences_v2beta.Pipeline(\n        actions=[\n            lifesciences_v2beta.Action(\n                image_uri=\"bash\",\n                commands=[\"-c\", \"echo hello from Cloud Life Sciences\"],\n            )\n        ],\n        resources=lifesciences_v2beta.Resources(\n            regions=[vm_region],\n            virtual_machine=lifesciences_v2beta.VirtualMachine(\n                machine_type=\"e2-standard-4\",\n                boot_disk_size_gb=30,\n                service_account=lifesciences_v2beta.ServiceAccount(\n                    email=service_account_email,\n                ),\n            ),\n        ),\n    ),\n    labels={\"env\": \"legacy\"},\n)\n\noperation = client.run_pipeline(request=request)\n\n# Cloud Life Sciences returned a long-running operation.\noperation.result(timeout=3600)\n```\n\nPractical notes:\n\n- `parent` identifies the Life Sciences metadata location, not the VM placement.\n- VM placement lives under `pipeline.resources.regions` or `pipeline.resources.zones`.\n- `run_pipeline()` returns a long-running operation, not a completed pipeline result payload.\n\n### Inspect or list operations\n\nIf you already have an operation resource name from logs or an existing system, use the operations helpers on the same client.\n\n```python\nfrom google.cloud import lifesciences_v2beta\n\nproject_id = \"YOUR_PROJECT_ID\"\nmetadata_location = \"us-central1\"\noperation_name = (\n    \"projects/YOUR_PROJECT_ID/locations/us-central1/operations/OPERATION_ID\"\n)\n\nclient = lifesciences_v2beta.WorkflowsServiceV2BetaClient()\n\noperation = client.get_operation(request={\"name\": operation_name})\nprint(\"done:\", operation.done)\n\nfor item in client.list_operations(\n    request={\n        \"name\": f\"projects/{project_id}/locations/{metadata_location}\",\n        \"filter\": \"done = false\",\n    }\n):\n    print(item.name, item.done)\n```\n\n### Cancel an in-flight operation\n\n```python\nfrom google.cloud import lifesciences_v2beta\n\noperation_name = (\n    \"projects/YOUR_PROJECT_ID/locations/us-central1/operations/OPERATION_ID\"\n)\n\nclient = lifesciences_v2beta.WorkflowsServiceV2BetaClient()\nclient.cancel_operation(request={\"name\": operation_name})\n```\n\nCancellation is best-effort. Check the operation state afterward instead of assuming the pipeline stopped immediately.\n\n## Logging\n\nThe generated library supports structured SDK logging through the standard Google client logging scope environment variable:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nUse this for client-level request and retry diagnostics while you are untangling legacy integrations.\n\n## Common Pitfalls\n\n- Install `google-cloud-life-sciences`, but import `lifesciences_v2beta`.\n- Do not plan new production workflows on this package. Google says Cloud Life Sciences became unavailable on July 8, 2025.\n- `parent` and `pipeline.resources.regions` or `zones` are different concepts. The first is a Life Sciences control-plane location; the second controls where compute runs.\n- The troubleshooting guide calls out both workflow-runner access and `iam.serviceAccounts.actAs` style permission on the VM service account.\n- `run_pipeline()` is asynchronous. If you only create the operation and never inspect it, you do not know whether the pipeline actually succeeded.\n- Older examples may still pass `credentials_file=` to the client constructor. The `0.10.0` changelog deprecates that argument; use ADC or pass a `Credentials` object with `credentials=...` instead.\n- The generated client warns against using the client as a context manager when the transport is shared elsewhere, because exiting the context closes the transport.\n\n## Version-Sensitive Notes For 0.11.0\n\n- PyPI shows `0.11.0` as the current package release covered here.\n- The `0.11.0` changelog adds Python 3.14 support and drops Python 3.8 support.\n- The `0.11.0` changelog also notes auto-enabled mTLS support. If endpoint selection changes unexpectedly, check `GOOGLE_API_USE_MTLS_ENDPOINT`, `GOOGLE_API_USE_CLIENT_CERTIFICATE`, and any explicit `client_options.api_endpoint` override.\n- The package is still marked beta on PyPI, so treat old blog posts and pre-shutdown examples as historical references, not current platform guidance.\n\n## Migration Direction\n\nGoogle's migration guide says to move Cloud Life Sciences workloads to Cloud Batch. The main conceptual mapping is:\n\n- Life Sciences pipeline submission maps to Batch job creation.\n- Life Sciences actions map to Batch runnables.\n- Life Sciences VM resource settings map to Batch allocation policy and task compute resources.\n- Existing workflow engines such as Cromwell, dsub, Nextflow, and Snakemake have product-specific migration guidance in the official Batch migration docs.\n\nIf you are writing new code, start with `google-cloud-batch` instead of this package.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-life-sciences/\n- Python reference root: https://docs.cloud.google.com/python/docs/reference/lifesciences/latest\n- `WorkflowsServiceV2BetaClient` reference: https://docs.cloud.google.com/python/docs/reference/lifesciences/latest/google.cloud.lifesciences_v2beta.services.workflows_service_v2_beta.WorkflowsServiceV2BetaClient\n- Python client changelog: https://docs.cloud.google.com/python/docs/reference/lifesciences/latest/changelog\n- Cloud Life Sciences release notes: https://cloud.google.com/life-sciences/docs/release-notes\n- Cloud Life Sciences locations: https://cloud.google.com/life-sciences/docs/locations\n- Troubleshooting guide: https://cloud.google.com/life-sciences/docs/troubleshooting\n- Migration guide to Cloud Batch: https://cloud.google.com/batch/docs/migrate-to-batch-from-cloud-life-sciences\n"
  },
  {
    "path": "content/google/docs/logging/javascript/DOC.md",
    "content": "---\nname: logging\ndescription: \"Google Cloud Logging Node.js client for writing structured log entries, reading logs back, and configuring project-scoped logging with ADC\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"11.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,google,gcp,logging,cloud-logging,observability,javascript,nodejs\"\n---\n\n# `@google-cloud/logging` JavaScript Package Guide\n\nUse `@google-cloud/logging` when your Node.js code needs to write log entries to Google Cloud Logging directly, attach structured metadata, or read recent entries back from a project.\n\n## Golden Rule\n\n- Import `Logging` from `@google-cloud/logging`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass `projectId` or `keyFilename` explicitly.\n- Treat `logging.log(name)` as a handle for a named log, then create entries with `log.entry(...)` and send them with `await log.write(...)`.\n- Prefer structured JSON payloads for application logs so entries are easier to filter in Logs Explorer.\n- Keep log writing asynchronous and await it before process shutdown.\n\nThis guide covers `11.2.1`.\n\n## Install\n\nPin the package version if you want behavior to match this guide exactly:\n\n```bash\nnpm install @google-cloud/logging@11.2.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nEnable the Cloud Logging API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable logging.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud auth application-default login\ngcloud config set project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nBefore you write code, make sure:\n\n1. The Cloud Logging API is enabled in the project.\n2. The credential resolves to the principal you expect.\n3. That principal has permission for the logging operations you need.\n\nCommon IAM roles:\n\n- `roles/logging.logWriter` to write log entries\n- `roles/logging.viewer` to read log entries\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nES modules:\n\n```javascript\nimport {Logging} from '@google-cloud/logging';\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nWith an explicit key file:\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Write A Simple Text Entry\n\nCreate a named log handle, build an entry, then write it.\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function writeStartupLog() {\n  const log = logging.log('application');\n\n  const entry = log.entry(\n    {\n      resource: {type: 'global'},\n      severity: 'INFO',\n    },\n    'service started'\n  );\n\n  await log.write(entry);\n}\n\nwriteStartupLog().catch(console.error);\n```\n\nUse a simple log name such as `application` or `worker`. In Cloud Logging, that becomes a project-scoped log such as `projects/PROJECT_ID/logs/application`.\n\n### Write A Structured JSON Entry\n\nUse an object payload when you want queryable fields in Logs Explorer.\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function writeOrderLog(orderId) {\n  const log = logging.log('application');\n\n  const entry = log.entry(\n    {\n      resource: {type: 'global'},\n      severity: 'NOTICE',\n      labels: {\n        service: 'checkout',\n        env: process.env.NODE_ENV || 'development',\n      },\n    },\n    {\n      event: 'order.created',\n      orderId,\n      source: 'api',\n    }\n  );\n\n  await log.write(entry);\n}\n```\n\nStructured payloads are easier to filter than plain strings because the fields are preserved as JSON.\n\n### Attach Request Metadata To Error Logs\n\nCloud Logging entries can include request metadata such as method, URL, and status code.\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function writeRequestErrorLog(error, request) {\n  const log = logging.log('application');\n\n  const entry = log.entry(\n    {\n      resource: {type: 'global'},\n      severity: 'ERROR',\n      httpRequest: {\n        requestMethod: request.method,\n        requestUrl: request.url,\n        status: 500,\n        userAgent: request.headers['user-agent'],\n        remoteIp: request.ip,\n      },\n      labels: {\n        service: 'checkout',\n      },\n    },\n    {\n      message: 'request failed',\n      error: error.message,\n      path: request.url,\n    }\n  );\n\n  await log.write(entry);\n}\n```\n\nIf you want stack traces or other fields preserved reliably, serialize them into the payload explicitly instead of relying on JavaScript `Error` object inspection.\n\n### Write Multiple Entries In One Call\n\n`log.write()` accepts either one entry or an array of entries.\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function writeBatch() {\n  const log = logging.log('worker');\n\n  const entries = [\n    log.entry({resource: {type: 'global'}, severity: 'INFO'}, 'job started'),\n    log.entry(\n      {resource: {type: 'global'}, severity: 'NOTICE'},\n      {event: 'job.finished', rowsProcessed: 128}\n    ),\n  ];\n\n  await log.write(entries);\n}\n```\n\nThis is useful when your code already has multiple related entries ready to send together.\n\n### Read Recent Entries\n\nUse the top-level `Logging` client for project-scoped reads.\n\n```javascript\nconst {Logging} = require('@google-cloud/logging');\n\nconst logging = new Logging({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function readRecentErrors(projectId) {\n  const [entries] = await logging.getEntries({\n    filter: [\n      `logName=\"projects/${projectId}/logs/application\"`,\n      'severity>=ERROR',\n    ].join(' AND '),\n    orderBy: 'timestamp desc',\n    pageSize: 20,\n  });\n\n  for (const entry of entries) {\n    console.log(entry.metadata.timestamp, entry.metadata.severity, entry.data);\n  }\n}\n\nreadRecentErrors(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\nStart with a simple filter first, then add more clauses once you confirm entries are present.\n\n## Configuration Notes\n\n### Pass `projectId` Explicitly When The Target Project Matters\n\nThe client can usually discover the project from ADC, but explicit `projectId` is safer when:\n\n- local shells and CI may point at different Google Cloud projects\n- the runtime project is not the same project where you want the logs written\n- you are building filters that depend on exact project-qualified log names\n\n### Set The Resource Explicitly Outside Managed Google Cloud Runtimes\n\nFor local development and generic servers, `resource: {type: 'global'}` is the safest starting point.\n\n```javascript\nconst entry = logging.log('application').entry(\n  {\n    resource: {type: 'global'},\n    severity: 'INFO',\n  },\n  {message: 'background job heartbeat'}\n);\n```\n\nIf your application runs on a Google Cloud runtime that supplies richer monitored resource metadata, the platform can associate entries more specifically.\n\n## Common Pitfalls\n\n- Do not use API keys; this client expects Google Cloud credentials.\n- Do not forget to `await log.write(...)` in short-lived scripts or request handlers.\n- Do not assume `logging.log(name)` sends anything by itself. It only returns a handle for later writes.\n- Do not mix up plain-string payloads and structured-object payloads when you intend to query fields later.\n- When reading entries, build filters with the full project-qualified log name such as `projects/PROJECT_ID/logs/application`.\n- Keep local and CI environments explicit about `GOOGLE_CLOUD_PROJECT` so logs do not land in the wrong project.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/logging` version `11.2.1`.\n- The Node.js reference site uses the `/latest` selector, so pin the npm version in your app if exact behavior matters.\n- Use `Logging` as the main entry point for direct log reads and writes in Node.js code.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/logging/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/logging`\n- Cloud Logging setup for Node.js: `https://cloud.google.com/logging/docs/setup/nodejs`\n- Application Default Credentials overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n"
  },
  {
    "path": "content/google/docs/logging/python/DOC.md",
    "content": "---\nname: logging\ndescription: \"google-cloud-logging package guide for Python with ADC setup, stdlib integration, direct API usage, and 3.x version notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.14.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-logging,google-cloud,logging,gcp,observability,python\"\n---\n\n# google-cloud-logging Python Package Guide\n\n## What It Is\n\n`google-cloud-logging` is the official Python client for Google Cloud Logging.\n\nUse it in two main ways:\n\n- integrate Cloud Logging with Python's standard `logging` module\n- call the Cloud Logging API directly to write, read, and manage log entries\n\nFor most application code, start with standard-library integration. Use the direct client APIs when you need explicit control over log names, labels, resources, batching, or entry retrieval.\n\n## Version Covered\n\n- Ecosystem: `pypi`\n- Package: `google-cloud-logging`\n- Version covered: `3.14.0`\n- Import path: `google.cloud.logging`\n- Registry: `https://pypi.org/project/google-cloud-logging/`\n- Docs root used for this guide: `https://cloud.google.com/python/docs/reference/logging/latest`\n\nVersion drift to know about:\n\n- The version used here for this entry is `3.14.0`.\n- PyPI lists `3.14.0` as the current package release.\n- As of March 12, 2026, the Google Cloud `latest` reference selector and changelog pages still top out at `3.13.0`.\n- Inference from those sources: the practical `3.x` API surface used here remains valid for `3.14.0`, but the Cloud docs are not fully version-pinned to that exact package release. Do not assume a method is new in `3.14.0` unless you verify it in release notes or package metadata.\n\n## Install\n\nPin the package when you need to match the version used here exactly:\n\n```bash\npython -m pip install google-cloud-logging==3.14.0\n```\n\nThe package name and import path differ:\n\n```python\nimport google.cloud.logging\n```\n\nPyPI metadata for `3.14.0` declares `Requires-Python >=3.7`.\n\n## Authentication And Project Setup\n\nBefore writing logs, you need:\n\n1. a Google Cloud project\n2. the Cloud Logging API enabled\n3. Application Default Credentials (ADC)\n\nFor local development, use the standard Google Cloud ADC flow:\n\n```bash\ngcloud auth application-default login\n```\n\nADC search order matters when auth fails:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. the local ADC file created by `gcloud auth application-default login`\n3. the attached service account from the metadata server\n\nIf you must use a service account key locally:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nWhen the code runs on Google Cloud, prefer an attached service account instead of a key file. The runtime identity needs permission to write logs, typically:\n\n- `roles/logging.logWriter`\n\n## Standard Library Integration\n\nThis is the default path for application logging.\n\n```python\nimport logging\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\nclient.setup_logging()\n\nlogging.info(\"service started\")\nlogging.warning(\"cache miss\", extra={\"json_fields\": {\"key\": \"user:123\"}})\n\nclient.close()\n```\n\nWhat `client.setup_logging()` does:\n\n- attaches a Cloud Logging handler to the root logger\n- by default captures logs at `INFO` level and above\n- picks a handler based on the current runtime environment\n\nRuntime behavior to know:\n\n- in managed Google Cloud environments, the library may choose `StructuredLogHandler`\n- in other environments, it commonly uses `CloudLoggingHandler`\n\nIf you need predictable behavior, configure the handler directly.\n\n### Manual `CloudLoggingHandler`\n\nUse this when you want API-backed delivery from the Python logging stack.\n\n```python\nimport logging\nimport google.cloud.logging\nfrom google.cloud.logging_v2.handlers import CloudLoggingHandler\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\nhandler = CloudLoggingHandler(client, name=\"application\")\n\nlogger = logging.getLogger(\"myapp\")\nlogger.setLevel(logging.INFO)\nlogger.addHandler(handler)\nlogger.propagate = False\n\nlogger.error(\"payment failed\")\n\nclient.close()\n```\n\nImportant details:\n\n- `CloudLoggingHandler` writes through the Cloud Logging API\n- the default transport is `BackgroundThreadTransport`\n- use `SyncTransport` only when you need synchronous writes and accept the latency cost\n\n### Manual `StructuredLogHandler`\n\nUse this when the runtime already captures stdout or stderr and turns JSON lines into Cloud Logging entries.\n\n```python\nimport logging\nfrom google.cloud.logging_v2.handlers.structured_log import StructuredLogHandler\n\nhandler = StructuredLogHandler()\n\nlogger = logging.getLogger(\"myapp\")\nlogger.setLevel(logging.INFO)\nlogger.addHandler(handler)\nlogger.propagate = False\n\nlogger.info(\n    \"user signed in\",\n    extra={\"json_fields\": {\"user_id\": \"123\", \"plan\": \"pro\"}},\n)\n```\n\n`StructuredLogHandler` emits structured JSON to standard output. It does not use the transport classes used by `CloudLoggingHandler`.\n\n### Adding Cloud Logging Metadata Through `extra`\n\nThe stdlib integration supports Cloud Logging fields through `extra=`.\n\n```python\nimport logging\n\nlogging.info(\n    \"request completed\",\n    extra={\n        \"labels\": {\"component\": \"billing\", \"region\": \"us-central1\"},\n        \"json_fields\": {\"order_id\": \"ord-123\", \"amount_cents\": 4999},\n        \"trace\": \"projects/my-project-id/traces/0123456789abcdef\",\n        \"http_request\": {\"requestMethod\": \"POST\", \"requestUrl\": \"/checkout\"},\n    },\n)\n```\n\nUseful fields supported by the official docs include:\n\n- `labels`\n- `trace`\n- `span_id`\n- `trace_sampled`\n- `http_request`\n- `source_location`\n- `resource`\n- `json_fields`\n\nValues you pass explicitly through `extra` override auto-detected metadata.\n\n## Direct API Usage\n\nUse the direct client APIs when you want to control the log name or work with entries yourself instead of routing through `logging`.\n\n### Create A Client And Logger\n\n```python\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\nlogger = client.logger(\"application\")\n```\n\nIf you need HTTP instead of gRPC:\n\n```python\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(\n    project=\"my-project-id\",\n    _use_grpc=False,\n)\n```\n\n### Write Text And Structured Entries\n\n```python\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\nlogger = client.logger(\"application\")\n\nlogger.log_text(\"plain text entry\", severity=\"INFO\")\n\nlogger.log_struct(\n    {\n        \"message\": \"structured entry\",\n        \"job\": \"daily-sync\",\n        \"success\": True,\n        \"items_processed\": 42,\n    },\n    severity=\"INFO\",\n    labels={\"component\": \"sync-worker\"},\n)\n\nclient.close()\n```\n\n`Logger.log()` can infer the entry type from the payload. Use `log_text()` and `log_struct()` when you want the entry type to be explicit.\n\n### Batch Writes\n\nBatching reduces per-entry network overhead.\n\n```python\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\nlogger = client.logger(\"application\")\n\nwith logger.batch() as batch:\n    batch.log_text(\"batch start\")\n    batch.log_struct({\"step\": \"transform\", \"rows\": 128})\n    batch.log_text(\"batch done\", severity=\"NOTICE\")\n\nclient.close()\n```\n\n### Read Back Entries\n\n```python\nimport google.cloud.logging\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\n\nfor entry in client.list_entries(\n    filter_='logName=\"projects/my-project-id/logs/application\"',\n    order_by=\"DESCENDING\",\n    max_results=20,\n):\n    print(type(entry).__name__, entry.severity, entry.timestamp)\n```\n\nThe client applies a 24-hour filter by default unless you override it.\n\n## Resource And Label Control\n\nThe library usually infers the monitored resource from the runtime environment.\n\nIf you need to set a specific resource:\n\n```python\nimport google.cloud.logging\nfrom google.cloud.logging_v2.resource import Resource\n\nclient = google.cloud.logging.Client(project=\"my-project-id\")\n\nresource = Resource(\n    type=\"global\",\n    labels={},\n)\n\nlogger = client.logger(\n    \"application\",\n    labels={\"service\": \"billing\"},\n    resource=resource,\n)\n```\n\nThis matters most in local development, hybrid environments, or custom runtimes where resource detection may fall back to `global`.\n\n## Web Framework Integration\n\nThe official integration can enrich entries with `trace`, `span_id`, `trace_sampled`, and `http_request` for supported frameworks such as Flask and Django.\n\nIf trace correlation matters:\n\n- configure logging before constructing the Flask app\n- add the documented middleware for Django\n- let framework integration populate request metadata unless you need to override fields manually\n\n## Common Pitfalls\n\n- Install with `pip install google-cloud-logging`, but import `google.cloud.logging`.\n- `client.setup_logging()` changes the root logger. If the app already has logging config, decide whether to use the root logger or attach a handler to a specific logger.\n- `setup_logging()` defaults to `INFO`. Lower the threshold explicitly if you need `DEBUG`.\n- `BackgroundThreadTransport` is asynchronous. In short-lived scripts, call `client.close()` before exit so buffered logs flush.\n- If logs are missing on Google Cloud, check the runtime service account and project selection before debugging the handler.\n- If local auth behaves unexpectedly, inspect the ADC search order before changing code.\n- `json_fields` and `log_struct()` payloads must be JSON- or protobuf-struct-serializable.\n- `CloudLoggingHandler` and `StructuredLogHandler` solve different transport problems. Do not attach both to the same logger unless duplicate output is intentional.\n\n## Version-Sensitive Notes\n\nFor current `3.x` projects:\n\n- Prefer `CloudLoggingHandler` or `StructuredLogHandler`. Older product-specific handlers such as `AppEngineHandler` and `ContainerEngineHandler` were deprecated in the `3.0.0` migration.\n- The `3.0.0` upgrade also changed resource-detection behavior and expanded structured logging support, so older `2.x` examples are not always the best reference.\n- Because the Google Cloud `latest` docs lag the current PyPI release as of March 12, 2026, keep examples anchored to documented `3.x` methods and verify any release-specific additions separately.\n\nPractical upgrade takeaway:\n\n- if upgrading from `2.x`, replace older environment-specific handlers\n- retest log formatting, metadata enrichment, and resource attribution after the upgrade\n- for projects pinned close to `3.14.0`, treat the Cloud docs as the API reference and PyPI as the authoritative package-version signal\n\n## Recommended Workflow For Agents\n\n1. Set up ADC first and confirm the target project ID.\n2. Start with `client.setup_logging()` unless the app already has strict logging configuration.\n3. Use `CloudLoggingHandler` when you want direct API delivery from Python.\n4. Use `StructuredLogHandler` when the platform already ingests stdout JSON.\n5. Switch to direct `client.logger(...).log_*()` calls only when you need named logs, batching, reads, or explicit resources.\n6. If the project is pinned to a specific `3.x` release, verify docs drift before assuming a feature is tied to that exact patch or minor version.\n\n## Official Sources\n\n- Cloud Logging Python docs: `https://cloud.google.com/python/docs/reference/logging/latest`\n- Standard library integration: `https://cloud.google.com/python/docs/reference/logging/latest/std-lib-integration`\n- Direct library usage: `https://cloud.google.com/python/docs/reference/logging/latest/direct-lib-usage`\n- Logger reference: `https://cloud.google.com/python/docs/reference/logging/latest/logger`\n- Changelog: `https://cloud.google.com/python/docs/reference/logging/latest/changelog`\n- Cloud Logging setup guide: `https://cloud.google.com/logging/docs/setup/python`\n- ADC setup for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC search order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- 3.0.0 migration guide: `https://cloud.google.com/python/docs/reference/logging/3.3.0/upgrading`\n- PyPI package page: `https://pypi.org/project/google-cloud-logging/`\n"
  },
  {
    "path": "content/google/docs/managed-identities/python/DOC.md",
    "content": "---\nname: managed-identities\ndescription: \"Google Cloud Managed Identities Python client for Managed Microsoft AD domains, authorized networks, delegated admin passwords, and trust management\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,managed-identities,active-directory,microsoft-ad,python,trusts\"\n---\n\n# Google Cloud Managed Identities Python Client\n\n## Golden Rule\n\nUse `google-cloud-managed-identities` with `from google.cloud import managedidentities_v1`, and treat it as a control-plane client for Managed Service for Microsoft Active Directory. The package handles domain lifecycle, delegated admin password reset, and trust operations. Network connectivity, DNS forwarding, firewall rules, and domain join steps still come from the product setup docs.\n\nPrefer Application Default Credentials (ADC) for authentication. For local development, use `gcloud auth application-default login`. On Google Cloud, prefer an attached service account over key files.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-managed-identities==1.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-managed-identities==1.14.0\"\npoetry add \"google-cloud-managed-identities==1.14.0\"\n```\n\nPyPI metadata for `1.14.0` currently declares `Requires: Python >=3.7`.\n\n## Authentication And Prerequisites\n\nBefore the client code works, Google Cloud product setup still matters:\n\n- Enable the Managed Microsoft AD, Cloud DNS, and Compute Engine APIs.\n- For domain creation, the quickstart calls out `roles/managedidentities.admin` and `roles/compute.networkUser`.\n- Use a VPC network resource name in the form `projects/PROJECT_ID/global/networks/VPC_NETWORK_NAME`.\n- Pick a reserved CIDR range that does not overlap with existing subnets in the authorized networks.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport MANAGED_IDENTITIES_DOMAIN_FQDN=\"ad.example.com\"\nexport MANAGED_IDENTITIES_AUTHORIZED_NETWORK=\"projects/your-project-id/global/networks/shared-vpc\"\nexport MANAGED_IDENTITIES_RESERVED_IP_RANGE=\"172.16.0.0/24\"\nexport MANAGED_IDENTITIES_REGION=\"us-central1\"\nexport MANAGED_IDENTITIES_ADMIN=\"setupadmin\"\n```\n\nKey-file based ADC only when you need it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n## Client Initialization\n\nManaged Identities resources are global. The parent is always `projects/{project_id}/locations/global`, while the deployment region goes inside the domain resource's `locations` field.\n\n```python\nimport os\n\nfrom google.cloud import managedidentities_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndomain_fqdn = os.environ[\"MANAGED_IDENTITIES_DOMAIN_FQDN\"]\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\n\nparent = f\"projects/{project_id}/locations/global\"\ndomain_name = f\"{parent}/domains/{domain_fqdn}\"\n```\n\n## Core Workflows\n\n### Create a domain\n\n```python\nimport os\n\nfrom google.cloud import managedidentities_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndomain_fqdn = os.environ[\"MANAGED_IDENTITIES_DOMAIN_FQDN\"]\nauthorized_network = os.environ[\"MANAGED_IDENTITIES_AUTHORIZED_NETWORK\"]\nreserved_ip_range = os.environ[\"MANAGED_IDENTITIES_RESERVED_IP_RANGE\"]\nregion = os.environ[\"MANAGED_IDENTITIES_REGION\"]\nadmin = os.getenv(\"MANAGED_IDENTITIES_ADMIN\", \"setupadmin\")\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\nparent = f\"projects/{project_id}/locations/global\"\n\nrequest = managedidentities_v1.CreateMicrosoftAdDomainRequest(\n    parent=parent,\n    domain_name=domain_fqdn,\n    domain=managedidentities_v1.Domain(\n        reserved_ip_range=reserved_ip_range,\n        locations=[region],\n        authorized_networks=[authorized_network],\n        admin=admin,\n    ),\n)\n\noperation = client.create_microsoft_ad_domain(request=request)\ndomain = operation.result(timeout=3600)\n\nprint(domain.name)\nprint(domain.fqdn)\nprint(domain.state)\n```\n\nUse one region at initial creation time. The product quickstart says a new domain is created in only one region, and the operation can take up to 60 minutes.\n\n### Get one domain or list domains\n\n```python\nfrom google.cloud import managedidentities_v1\n\nproject_id = \"your-project-id\"\ndomain_fqdn = \"ad.example.com\"\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\nparent = f\"projects/{project_id}/locations/global\"\ndomain_name = f\"{parent}/domains/{domain_fqdn}\"\n\ndomain = client.get_domain(name=domain_name)\nprint(domain.fqdn, domain.state)\n\npager = client.list_domains(\n    request=managedidentities_v1.ListDomainsRequest(\n        parent=parent,\n        filter=f'Domain.fqdn=\"{domain_fqdn}\"',\n    )\n)\n\nfor item in pager:\n    print(item.name, item.fqdn, item.state)\n```\n\n### Update authorized networks\n\n`update_domain` only supports `labels`, `locations`, and `authorized_networks`. Use a field mask so the client updates exactly the field you intend.\n\n```python\nfrom google.cloud import managedidentities_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nproject_id = \"your-project-id\"\ndomain_fqdn = \"ad.example.com\"\nauthorized_networks = [\n    \"projects/your-project-id/global/networks/shared-vpc\",\n    \"projects/your-project-id/global/networks/secondary-vpc\",\n]\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\ndomain_name = f\"projects/{project_id}/locations/global/domains/{domain_fqdn}\"\n\noperation = client.update_domain(\n    domain=managedidentities_v1.Domain(\n        name=domain_name,\n        authorized_networks=authorized_networks,\n    ),\n    update_mask=FieldMask(paths=[\"authorized_networks\"]),\n)\n\nupdated_domain = operation.result(timeout=1800)\nprint(updated_domain.authorized_networks)\n```\n\n### Reset the delegated administrator password\n\nManaged Microsoft AD creates a delegated administrator account when you create a domain. By default the username is `setupadmin`, unless you provide a custom `admin` field during creation.\n\n```python\nfrom google.cloud import managedidentities_v1\n\nproject_id = \"your-project-id\"\ndomain_fqdn = \"ad.example.com\"\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\ndomain_name = f\"projects/{project_id}/locations/global/domains/{domain_fqdn}\"\n\nresponse = client.reset_admin_password(name=domain_name)\n\nprint(response.password)\n```\n\nThis returns a newly generated random password. The existing password cannot be retrieved, only reset, so store the new value immediately in your secret manager.\n\n### Create and validate a forest trust\n\nFor on-premises trusts, the product documentation says Managed Microsoft AD supports forest trusts and does not support external, realm, or shortcut trusts. Some generated client snippets still show `EXTERNAL` placeholders; replace those with `FOREST`.\n\n```python\nimport os\n\nfrom google.cloud import managedidentities_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ndomain_fqdn = os.environ[\"MANAGED_IDENTITIES_DOMAIN_FQDN\"]\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\ndomain_name = f\"projects/{project_id}/locations/global/domains/{domain_fqdn}\"\n\ntrust = managedidentities_v1.Trust(\n    target_domain_name=\"corp.example.com\",\n    trust_type=managedidentities_v1.Trust.TrustType.FOREST,\n    trust_direction=managedidentities_v1.Trust.TrustDirection.BIDIRECTIONAL,\n    target_dns_ip_addresses=[\"10.10.0.10\", \"10.10.0.11\"],\n    trust_handshake_secret=os.environ[\"MANAGED_IDENTITIES_TRUST_SECRET\"],\n)\n\noperation = client.attach_trust(\n    request=managedidentities_v1.AttachTrustRequest(\n        name=domain_name,\n        trust=trust,\n    )\n)\ndomain = operation.result(timeout=900)\n\nvalidation = client.validate_trust(\n    request=managedidentities_v1.ValidateTrustRequest(\n        name=domain_name,\n        trust=trust,\n    )\n)\nvalidated_domain = validation.result(timeout=600)\n\nfor item in validated_domain.trusts:\n    print(item.target_domain_name, item.state, item.state_description)\n```\n\n`validate_trust` checks that the target domain is reachable and can accept the trust. It does not replace the product prerequisites around Cloud VPN or Interconnect, DNS forwarding, and firewall ports.\n\n### Reconfigure trust DNS servers\n\nIf the remote domain's DNS IPs change, use `reconfigure_trust`:\n\n```python\nfrom google.cloud import managedidentities_v1\n\nproject_id = \"your-project-id\"\ndomain_fqdn = \"ad.example.com\"\n\nclient = managedidentities_v1.ManagedIdentitiesServiceClient()\ndomain_name = f\"projects/{project_id}/locations/global/domains/{domain_fqdn}\"\n\noperation = client.reconfigure_trust(\n    request=managedidentities_v1.ReconfigureTrustRequest(\n        name=domain_name,\n        target_domain_name=\"corp.example.com\",\n        target_dns_ip_addresses=[\"10.20.0.10\", \"10.20.0.11\"],\n    )\n)\n\ndomain = operation.result(timeout=900)\nprint(domain.name)\n```\n\n## Pitfalls\n\n- `parent` is always `projects/{project_id}/locations/global`. Do not put `us-central1` or another region in the resource name.\n- `domain_name` on create is the FQDN, while later read and update calls use the full resource name `projects/{project_id}/locations/global/domains/{domain_fqdn}`.\n- `reserved_ip_range` must be `/24` or larger, unique, and non-overlapping with existing subnets in the authorized networks.\n- Authorized networks must be full VPC resource names, not plain network names. The product docs say a domain supports up to 5 authorized networks.\n- Domain creation is a long-running operation that can take up to 60 minutes. Trust creation can take up to 10 minutes before the trust reaches `CONNECTED`.\n- The trust handshake secret is required when creating the trust and is not stored by the service. Keep your own copy.\n- `update_domain` is not a generic patch endpoint. Only `labels`, `locations`, and `authorized_networks` are supported in the update mask.\n- Resetting the delegated administrator password replaces the old password. You cannot read the old one back later.\n\n## Version Notes\n\n- PyPI lists `google-cloud-managed-identities 1.14.0` released on January 15, 2026.\n- As of March 13, 2026, Google's hosted Python reference pages for this package still label `latest` as `1.13.0`. The request and resource shapes above are taken from those latest reference pages plus the current product docs. If you depend on `1.14.0`-specific behavior, check the release history before assuming the hosted reference has caught up.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-managed-identities/\n- Maintainer package source: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-managed-identities\n- Python client reference root: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest\n- Package class summary: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/summary_class\n- CreateMicrosoftAdDomainRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.CreateMicrosoftAdDomainRequest\n- ListDomainsRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.ListDomainsRequest\n- UpdateDomainRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.UpdateDomainRequest\n- ResetAdminPasswordRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.ResetAdminPasswordRequest\n- ReconfigureTrustRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.ReconfigureTrustRequest\n- ValidateTrustRequest: https://docs.cloud.google.com/python/docs/reference/managedidentities/latest/google.cloud.managedidentities_v1.types.ValidateTrustRequest\n- Managed Microsoft AD create domain quickstart: https://cloud.google.com/managed-microsoft-ad/docs/create-domain\n- Managed Microsoft AD authorized networks: https://cloud.google.com/managed-microsoft-ad/docs/managing-authorized-networks\n- Managed Microsoft AD delegated administrator account: https://docs.cloud.google.com/managed-microsoft-ad/docs/how-to-use-delegated-admin\n- Managed Microsoft AD create trust: https://cloud.google.com/managed-microsoft-ad/docs/create-trust\n- Managed Microsoft AD manage trusts: https://docs.cloud.google.com/managed-microsoft-ad/docs/manage-trusts\n- ADC setup: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- `gcloud auth application-default login`: https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login\n"
  },
  {
    "path": "content/google/docs/media-translation/javascript/DOC.md",
    "content": "---\nname: media-translation\ndescription: \"Google Cloud Media Translation Node.js client for bidirectional streaming speech translation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-media-translation,google-cloud,media-translation,translation,speech,streaming,gcp,javascript,nodejs\"\n---\n\n# `@google-cloud/media-translation` JavaScript Package Guide\n\nUse `@google-cloud/media-translation` when your Node.js app needs Google Cloud Media Translation for bidirectional streaming speech translation. This package is narrow by design: it is for live audio translation streams, not for general text translation or batch document translation.\n\nIf you need text translation, glossaries, or document translation, use `@google-cloud/translate` instead.\n\n## Golden Rule\n\n- Use the `v1beta1` client surface for this package.\n- Authenticate with Google Cloud Application Default Credentials (ADC), not an API key.\n- Send one config message first, then send audio chunks in later messages.\n- Make `audioEncoding` and `sampleRateHertz` match the actual bytes you stream.\n- Treat `streamingTranslateSpeech()` as an event-driven bidirectional stream.\n\nThis guide covers `5.2.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/media-translation@5.2.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the Media Translation API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable mediatranslation.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nIf you need to use a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nPrefer attached service-account credentials on Google Cloud over shipping JSON key files.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1beta1} = require('@google-cloud/media-translation');\n\nconst client = new v1beta1.SpeechTranslationServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1beta1} from '@google-cloud/media-translation';\n\nconst client = new v1beta1.SpeechTranslationServiceClient();\n```\n\nIf you need to override the default endpoint or pass explicit credentials, provide standard client options when constructing the client:\n\n```javascript\nconst {v1beta1} = require('@google-cloud/media-translation');\n\nconst client = new v1beta1.SpeechTranslationServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n  apiEndpoint: 'mediatranslation.googleapis.com',\n});\n```\n\n## Core Workflow: Stream Audio And Read Translations\n\n`streamingTranslateSpeech()` is the main API call. The request stream has one important rule:\n\n- The first message must contain `streamingConfig` and no audio bytes.\n- All later messages must contain `audioContent` and no config.\n\nThis example streams raw 16 kHz mono PCM (`LINEAR16`) from a local file and logs both interim recognition text and translated text when those fields are present in the response stream:\n\n```javascript\nconst fs = require('node:fs');\nconst {v1beta1} = require('@google-cloud/media-translation');\n\nfunction translateAudioFile(filePath) {\n  const client = new v1beta1.SpeechTranslationServiceClient();\n\n  const stream = client\n    .streamingTranslateSpeech()\n    .on('error', err => {\n      console.error('Media Translation stream error:', err.message);\n    })\n    .on('data', response => {\n      if (response.error) {\n        console.error('API error:', response.error.message);\n        return;\n      }\n\n      const result = response.result;\n      if (!result) {\n        return;\n      }\n\n      const status = result.isFinal ? 'final' : 'interim';\n\n      if (result.recognitionResult?.text) {\n        console.log(`[${status}] transcript: ${result.recognitionResult.text}`);\n      }\n\n      if (result.textTranslationResult?.translation) {\n        console.log(\n          `[${status}] translation: ${result.textTranslationResult.translation}`\n        );\n      }\n    })\n    .on('end', () => {\n      console.log('Translation stream finished');\n    });\n\n  stream.write({\n    streamingConfig: {\n      audioConfig: {\n        audioEncoding: 'LINEAR16',\n        sampleRateHertz: 16000,\n      },\n      sourceLanguageCode: 'en-US',\n      targetLanguageCode: 'es-ES',\n      singleUtterance: false,\n    },\n  });\n\n  fs.createReadStream(filePath, {highWaterMark: 4096})\n    .on('data', chunk => {\n      stream.write({audioContent: chunk});\n    })\n    .on('end', () => {\n      stream.end();\n    })\n    .on('error', err => {\n      stream.destroy(err);\n    });\n\n  return stream;\n}\n\ntranslateAudioFile('./speech.raw');\n```\n\nAdjust these fields to match your real stream:\n\n- `audioEncoding`: must match the bytes you actually send\n- `sampleRateHertz`: must match the source stream sample rate\n- `sourceLanguageCode`: BCP-47 language tag for the spoken input\n- `targetLanguageCode`: BCP-47 language tag for translated output\n- `singleUtterance`: set `true` if the server should stop after one utterance\n\n## Response Handling Notes\n\nThis API is a bidirectional stream, so the normal usage pattern is event-based rather than `const [response] = await ...`.\n\nThe response stream can contain:\n\n- `response.error` for request-level failures\n- `response.result.recognitionResult.text` for recognized speech text\n- `response.result.textTranslationResult.translation` for translated text\n- `response.result.isFinal` to distinguish interim from final results\n\nIf your app only needs the translated output, ignore `recognitionResult` and read `textTranslationResult.translation`.\n\n## Common Pitfalls\n\n- Do not send audio bytes in the first request. Start with `streamingConfig` only.\n- Do not resend `streamingConfig` after the first message. Later writes should only include `audioContent`.\n- `audioContent` is raw bytes. Do not base64-encode it.\n- Do not stream a WAV or other container format unless the bytes and config match what the API expects.\n- Bad `audioEncoding` or `sampleRateHertz` values usually show up as poor transcripts, poor translations, or request failures.\n- This package is for streaming speech translation. It is not the right client for general text translation workflows.\n- The package surface is beta-oriented (`v1beta1`), so check the maintainer reference before upgrading across package versions.\n\n## Version Notes For 5.2.1\n\n- This guide targets `@google-cloud/media-translation` version `5.2.1`.\n- The practical client surface is the `v1beta1` namespace.\n- The core integration pattern is still `streamingTranslateSpeech()` with a config-first request stream.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/media-translation/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/media-translation`\n- Media Translation product docs: `https://cloud.google.com/media-translation/docs`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/media-translation/python/DOC.md",
    "content": "---\nname: media-translation\ndescription: \"Google Cloud Media Translation Python client for bidirectional streaming speech translation\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-media-translation,google-cloud,translation,speech,streaming,gcp,python\"\n---\n\n# Google Cloud Media Translation Python Package Guide\n\nUse `google-cloud-media-translation` when you need Google Cloud's Media Translation API from Python. This package is narrow by design: the Python surface is the `mediatranslation_v1beta1` client for bidirectional streaming speech translation, not a general text-translation SDK.\n\nIf you need text translation, glossaries, document translation, or batch translation jobs, use `google-cloud-translate` instead.\n\n## Install\n\nPin the package version if you want behavior to match this guide:\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-media-translation==0.13.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-media-translation==0.13.0\"\npoetry add \"google-cloud-media-translation==0.13.0\"\n```\n\nPyPI currently classifies the package as Beta and publishes the client under the `v1beta1` namespace.\n\n## Authentication And Environment\n\nGoogle Cloud client libraries use Application Default Credentials (ADC). For local development, the practical options are:\n\n```bash\ngcloud auth application-default login\n```\n\nOr point the client at a service account JSON file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nUse a principal that can call Media Translation in the target Google Cloud project. Prefer ADC or attached service accounts over hard-coding credentials in Python.\n\n## Initialize The Client\n\n```python\nfrom google.cloud import mediatranslation_v1beta1 as media_translation\n\nclient = media_translation.SpeechTranslationServiceClient()\n```\n\nThe default endpoint is `mediatranslation.googleapis.com:443`. If your environment needs custom endpoint selection or mTLS behavior, pass `client_options` when you construct the client.\n\n## Core Workflow: Stream Audio And Read Translations\n\n`streaming_translate_speech()` is the main API call. The request stream has one important rule:\n\n- The first message must contain `streaming_config` and no audio bytes.\n- All later messages must contain `audio_content` and no config.\n\nThis example streams raw 16 kHz mono PCM (`LINEAR16`) from a local file and prints interim and final translated text:\n\n```python\nfrom typing import Iterator\n\nfrom google.cloud import mediatranslation_v1beta1 as media_translation\n\n\ndef request_stream(\n    audio_path: str,\n) -> Iterator[media_translation.StreamingTranslateSpeechRequest]:\n    yield media_translation.StreamingTranslateSpeechRequest(\n        streaming_config=media_translation.StreamingTranslateSpeechConfig(\n            audio_config=media_translation.AudioConfig(\n                audio_encoding=media_translation.AudioEncoding.LINEAR16,\n                sample_rate_hertz=16000,\n            ),\n            source_language_code=\"en-US\",\n            target_language_code=\"es-ES\",\n            single_utterance=False,\n        )\n    )\n\n    with open(audio_path, \"rb\") as audio_file:\n        while chunk := audio_file.read(4096):\n            yield media_translation.StreamingTranslateSpeechRequest(\n                audio_content=chunk\n            )\n\n\ndef translate_stream(audio_path: str) -> None:\n    client = media_translation.SpeechTranslationServiceClient()\n    responses = client.streaming_translate_speech(\n        requests=request_stream(audio_path)\n    )\n\n    for response in responses:\n        event = response.WhichOneof(\"streaming_response\")\n\n        if event == \"error\":\n            raise RuntimeError(\n                f\"Media Translation error {response.error.code}: \"\n                f\"{response.error.message}\"\n            )\n\n        if event == \"result\":\n            result = response.result\n            status = \"final\" if result.is_final else \"interim\"\n            message_type = result.WhichOneof(\"message_type\")\n\n            if message_type == \"text_translation_result\":\n                print(\n                    f\"[{status}] \"\n                    f\"{result.text_translation_result.translation}\"\n                )\n            elif message_type == \"recognition_result\":\n                print(f\"[{status}] {result.recognition_result.text}\")\n\n\ntranslate_stream(\"speech.raw\")\n```\n\nAdjust these fields for your real stream:\n\n- `audio_encoding`: use an encoding that matches the actual audio bytes you send\n- `sample_rate_hertz`: match the source stream's sample rate\n- `source_language_code`: BCP-47 language tag for the spoken input\n- `target_language_code`: BCP-47 language tag for the translation output\n- `single_utterance`: set `True` if you want the server to stop after one utterance\n\n## Async Client\n\nIf the rest of your app is async, use the async client with the same request messages:\n\n```python\nfrom google.cloud import mediatranslation_v1beta1 as media_translation\n\nclient = media_translation.SpeechTranslationServiceAsyncClient()\n```\n\nThe streaming request structure stays the same; only the client call pattern changes.\n\n## Common Pitfalls\n\n- Do not send audio bytes in the first request. The API expects config first, then audio chunks.\n- Do not keep resending `streaming_config` after the first message. Subsequent messages should only carry `audio_content`.\n- `audio_content` is raw bytes. Do not base64-encode it.\n- Make sure `audio_encoding` and `sample_rate_hertz` match the real stream. A mismatched config is a common cause of bad transcripts or request failures.\n- This package is not a replacement for `google-cloud-translate`. The Media Translation client is specifically for streaming speech translation.\n- The package is still a beta client surface (`mediatranslation_v1beta1`), so keep an eye on release notes before upgrading across minor versions.\n\n## Version Notes For 0.13.0\n\n- PyPI lists `0.13.0` as the current package version for this guide.\n- The import surface remains `google.cloud.mediatranslation_v1beta1`.\n- PyPI classifiers currently advertise support for Python 3.7 through 3.14.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-media-translation/\n- Maintainer README: https://raw.githubusercontent.com/googleapis/google-cloud-python/main/packages/google-cloud-media-translation/README.rst\n- Python reference index: https://cloud.google.com/python/docs/reference/mediatranslation/latest\n- Client reference: https://cloud.google.com/python/docs/reference/mediatranslation/latest/google.cloud.mediatranslation_v1beta1.services.speech_translation_service.SpeechTranslationServiceClient\n- Type reference: https://cloud.google.com/python/docs/reference/mediatranslation/latest/google.cloud.mediatranslation_v1beta1.types.StreamingTranslateSpeechResponse\n- ADC overview: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/memcache/javascript/DOC.md",
    "content": "---\nname: memcache\ndescription: \"Google Cloud Memorystore for Memcached Node.js admin client for listing, creating, updating, and deleting Memcached instances\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,memorystore,memcached,javascript,nodejs,admin-sdk\"\n---\n\n# `@google-cloud/memcache` JavaScript Package Guide\n\nUse `@google-cloud/memcache` when your Node.js code needs the Google Cloud Memorystore for Memcached control plane: list instances, inspect configuration, create an instance, update metadata, stage and apply Memcached parameter changes, reschedule maintenance, and delete an instance.\n\nThis package manages Memorystore resources. It is not the Memcached protocol client you use for key/value commands such as `get`, `set`, `delete`, `incr`, or CAS operations against the cache itself.\n\n## Golden Rule\n\n- Use `@google-cloud/memcache` for Memorystore administration, not Memcached data-plane traffic.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Build full resource names as `projects/{project}/locations/{region}` and `projects/{project}/locations/{region}/instances/{instance}`.\n- Treat create, update, parameter, maintenance, and delete calls as long-running operations and wait for `operation.promise()`.\n- Use a separate Memcached client package for application traffic after the instance exists.\n\nThis guide covers `4.2.1`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/memcache@4.2.1\n```\n\nIf your app also needs to talk Memcached protocol to the running cache, install a separate Memcached client package too.\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials.\n\nTypical prerequisites:\n\n1. A Google Cloud project.\n2. The Memorystore for Memcached API enabled in that project.\n3. A caller identity with permission to view or manage Memcached instances.\n4. A VPC network ready for the instance.\n5. Private services access configured for that network before you create the instance.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n\ngcloud services enable memcache.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n```\n\nIf you must use a service account key file explicitly:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nFor production on Google Cloud, prefer an attached service account instead of shipping key files.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/memcache';\n\nconst client = new v1.CloudMemcacheClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nReuse client instances in long-lived processes instead of constructing a new client for every request.\n\n## Resource Names\n\nUse these resource formats consistently:\n\n- Region parent: `projects/PROJECT_ID/locations/REGION`\n- Instance name: `projects/PROJECT_ID/locations/REGION/instances/INSTANCE_ID`\n- Network path for creation: `projects/PROJECT_ID/global/networks/NETWORK_NAME`\n\nFor listing across all available regions, Google documents `projects/PROJECT_ID/locations/-` as the `parent`.\n\n## Core Workflows\n\n### List Instances In A Region\n\nUse the async iterator form so pagination stays automatic.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function listInstances(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  for await (const instance of client.listInstancesAsync({parent})) {\n    console.log({\n      name: instance.name,\n      displayName: instance.displayName,\n      state: instance.state,\n      nodeCount: instance.nodeCount,\n      discoveryEndpoint: instance.discoveryEndpoint,\n    });\n  }\n}\n```\n\nTo aggregate across every available region, use `projects/PROJECT_ID/locations/-` as `parent`.\n\n### Get One Instance\n\nUse the full resource name, not only the short instance ID.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function getInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n  const [instance] = await client.getInstance({name});\n\n  console.log({\n    name: instance.name,\n    displayName: instance.displayName,\n    authorizedNetwork: instance.authorizedNetwork,\n    discoveryEndpoint: instance.discoveryEndpoint,\n    labels: instance.labels,\n    maintenancePolicy: instance.maintenancePolicy,\n    maintenanceSchedule: instance.maintenanceSchedule,\n    memcacheNodes: instance.memcacheNodes,\n    memcacheVersion: instance.memcacheVersion,\n    nodeConfig: instance.nodeConfig,\n    nodeCount: instance.nodeCount,\n    state: instance.state,\n  });\n\n  return instance;\n}\n```\n\n### Create A Basic Instance\n\n`createInstance()` is a long-running operation. Wait for completion before using the instance.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function createInstance(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  const [operation] = await client.createInstance({\n    parent,\n    instanceId: 'cache-prod',\n    instance: {\n      displayName: 'Primary cache',\n      authorizedNetwork: `projects/${projectId}/global/networks/default`,\n      nodeCount: 3,\n      nodeConfig: {\n        cpuCount: 2,\n        memorySizeMb: 4096,\n      },\n      labels: {\n        env: 'prod',\n      },\n    },\n  });\n\n  const [instance] = await operation.promise();\n  console.log(instance.name, instance.discoveryEndpoint);\n  return instance;\n}\n```\n\nChoose these fields deliberately during creation:\n\n- `instanceId` must be 1 to 40 characters, use lowercase letters, numbers, and hyphens, start with a letter, and end with a letter or number.\n- `authorizedNetwork` should point at the VPC network that will reach the cache.\n- `nodeCount` and `nodeConfig` are required for provisioning.\n- `labels` are useful for environment and ownership metadata.\n\n### Update Instance Metadata\n\nUse a field mask so you only change the fields you intend to change.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function renameInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.updateInstance({\n    updateMask: {\n      paths: ['display_name'],\n    },\n    instance: {\n      name,\n      displayName: 'Cache production',\n    },\n  });\n\n  const [instance] = await operation.promise();\n  return instance;\n}\n```\n\n### Stage Memcached Parameter Changes\n\n`updateParameters()` stages parameter changes. It does not apply them to the running nodes by itself.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function stageParameters(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.updateParameters({\n    name,\n    updateMask: {\n      paths: ['params'],\n    },\n    parameters: {\n      params: {\n        'max-item-size': '1048576',\n        lru_crawler: 'yes',\n      },\n    },\n  });\n\n  await operation.promise();\n}\n```\n\n### Apply Staged Parameters\n\nApply the current staged parameter set when you are ready for the operational change.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function applyParameters(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.applyParameters({name});\n  await operation.promise();\n}\n```\n\nApplying updated parameters can flush cache data on affected nodes. Treat this as an operational change, not a harmless metadata edit.\n\n### Reschedule Maintenance\n\nUse `rescheduleMaintenance()` when you need to move a scheduled maintenance event.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function rescheduleMaintenance(projectId, region, instanceId) {\n  const instance = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n  const scheduleTime = new Date('2026-03-20T03:00:00Z');\n\n  const [operation] = await client.rescheduleMaintenance({\n    instance,\n    rescheduleType: 'SPECIFIC_TIME',\n    scheduleTime: {\n      seconds: Math.floor(scheduleTime.getTime() / 1000),\n    },\n  });\n\n  await operation.promise();\n}\n```\n\n### Delete An Instance\n\nDelete is also a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/memcache');\n\nconst client = new v1.CloudMemcacheClient();\n\nasync function deleteInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.deleteInstance({name});\n  await operation.promise();\n}\n```\n\n## Using A Memcached Data Client\n\nUse the admin SDK to provision the Memorystore instance and inspect connection details. Use a separate Memcached protocol client for actual cache operations.\n\nTypical flow:\n\n1. Create or inspect the instance with `@google-cloud/memcache`.\n2. Read `instance.discoveryEndpoint` or the node addresses from `instance.memcacheNodes`.\n3. Configure your Memcached client to connect to those endpoints.\n\nIf generated code starts calling `client.get()` or `client.set()` on `CloudMemcacheClient`, it is using the wrong API surface.\n\n## Operations And Request Patterns\n\n- List methods use async iterators such as `listInstancesAsync()` so the client can handle pagination.\n- Unary reads like `getInstance()` return a tuple where the first element is the resource.\n- Mutating methods such as `createInstance()`, `updateInstance()`, `updateParameters()`, `applyParameters()`, `rescheduleMaintenance()`, and `deleteInstance()` return long-running operations.\n- Reuse client instances in long-lived processes instead of creating a new client for every request.\n- Prefer explicit request objects with `parent`, `name`, `instanceId`, `instance`, `parameters`, `updateMask`, and maintenance fields rather than partially flattened arguments.\n\n## Common Pitfalls\n\n- The package is an admin SDK. It does not expose Memcached commands such as `get`, `set`, `delete`, or CAS operations.\n- `parent` is `projects/{project}/locations/{region}`. Instance operations usually need a full `name` ending in `/instances/{instance}`.\n- Do not assume an operation finished just because the initial method returned. Wait for `await operation.promise()`.\n- `updateParameters()` stages config only; `applyParameters()` is the step that restarts affected nodes to pick up staged values.\n- Applying parameter updates can flush cache contents on affected nodes.\n- Instance creation can fail even with correct IAM if private services access is not configured on the selected VPC network.\n- `authorizedNetwork` should be a full VPC resource path such as `projects/PROJECT_ID/global/networks/default`.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/memcache/latest`\n- Memorystore for Memcached product docs: `https://cloud.google.com/memorystore/docs/memcached`\n- Configure Memcached parameters: `https://cloud.google.com/memorystore/docs/memcached/configure-memcached`\n- Connect to a Memcached instance: `https://cloud.google.com/memorystore/docs/memcached/establish-connection`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC overview and search order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/memcache`\n"
  },
  {
    "path": "content/google/docs/memcache/python/DOC.md",
    "content": "---\nname: memcache\ndescription: \"google-cloud-memcache package guide for Python with ADC setup, instance lifecycle operations, and docs-version drift notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,memorystore,memcached,gcp,python,admin\"\n---\n\n# google-cloud-memcache Python Package Guide\n\n## What This Package Is\n\n`google-cloud-memcache` is the official Google Cloud Python client library for the Memorystore for Memcached admin API.\n\nUse it when your code needs to:\n\n- create Memcached instances\n- list or inspect instances\n- update instance metadata or staged Memcached parameters\n- apply staged parameter changes\n- reschedule maintenance\n- delete instances\n\nDo not use this package for Memcached key/value traffic. After the instance exists, your application talks to the cache through a normal Memcached protocol client and the instance's discovery or node endpoints.\n\nPrimary import:\n\n```python\nfrom google.cloud import memcache_v1\n```\n\nLegacy surface also exists:\n\n```python\nfrom google.cloud import memcache_v1beta2\n```\n\nPrefer `memcache_v1` for new code.\n\n## Version Note\n\nThis entry is pinned to the version used here `1.14.0`, and that version is confirmed by the official PyPI project page as the current release published on January 15, 2026.\n\nGoogle's current `latest` Python reference pages for this library are lagging or internally inconsistent:\n\n- the package landing page and several `memcache_v1` pages are still labeled `1.13.0`\n- some deeper generated pages still render as `1.12.2`\n\nThe API surface in this guide is based on the current official `latest` reference pages plus the official PyPI package page for `1.14.0`. Where those sources disagree on displayed doc version labels, this guide favors the validated package version from PyPI and treats the reference-site version labels as documentation lag.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-memcache==1.14.0\"\n```\n\nUnpinned install:\n\n```bash\npython -m pip install google-cloud-memcache\n```\n\nWith `uv`:\n\n```bash\nuv add google-cloud-memcache\n```\n\nWith Poetry:\n\n```bash\npoetry add google-cloud-memcache\n```\n\nThe official PyPI page currently lists support for Python `>=3.7`.\n\n## Setup And Authentication\n\nBefore calling the client, you need:\n\n- a Google Cloud project with billing enabled\n- the Memorystore for Memcached API enabled\n- Application Default Credentials (ADC)\n- a VPC network that can host the instance\n- private services access configured for that network\n\nEnable the API:\n\n```bash\ngcloud services enable memcache.googleapis.com\n```\n\nSet up ADC for local development:\n\n```bash\ngcloud auth application-default login\n```\n\nIf you need service account impersonation for local work:\n\n```bash\ngcloud auth application-default login \\\n  --impersonate-service-account=SERVICE_ACCOUNT_EMAIL\n```\n\nIf you must point ADC at a credential file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\n```\n\nGoogle's auth docs still recommend attached service accounts for production workloads on Google Cloud rather than shipping service account keys with your code.\n\n## Client Creation\n\nDefault client with ADC:\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheAsyncClient()\n```\n\nExplicit credentials object:\n\n```python\nfrom google.cloud import memcache_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = memcache_v1.CloudMemcacheClient(credentials=credentials)\n```\n\nThe generated reference examples warn that some environments may need explicit `client_options` endpoint configuration. Start with the default client and only add `client_options` when your environment actually requires it.\n\n## Resource Naming\n\nMemcached instances are regional resources:\n\n```python\nproject_id = \"my-project\"\nregion = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{region}\"\ninstance_name = f\"{parent}/instances/cache-prod\"\n```\n\nThe reference docs also document `projects/{project}/locations/-` for listing across all regions.\n\n## Core Workflow\n\n### List instances\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\n\nfor instance in client.list_instances(\n    request={\"parent\": \"projects/my-project/locations/us-central1\"}\n):\n    print(instance.name, instance.state.name)\n```\n\n`list_instances()` returns a pager. Iterate over it directly.\n\n### Get one instance\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\n\ninstance = client.get_instance(\n    request={\n        \"name\": \"projects/my-project/locations/us-central1/instances/cache-prod\"\n    }\n)\n\nprint(instance.discovery_endpoint)\nprint(instance.memcache_nodes)\nprint(instance.maintenance_schedule)\n```\n\nUseful fields from `Instance`:\n\n- `authorized_network`\n- `discovery_endpoint`\n- `labels`\n- `maintenance_policy`\n- `maintenance_schedule`\n- `memcache_nodes`\n- `memcache_version`\n- `node_config`\n- `node_count`\n- `state`\n\n### Create an instance\n\n`create_instance()` is a long-running operation. Wait for `operation.result()` before assuming the instance is usable.\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\nparent = \"projects/my-project/locations/us-central1\"\n\ninstance = memcache_v1.Instance(\n    display_name=\"Primary cache\",\n    authorized_network=\"projects/my-project/global/networks/default\",\n    node_count=3,\n    node_config=memcache_v1.Instance.NodeConfig(\n        cpu_count=2,\n        memory_size_mb=4096,\n    ),\n    labels={\"env\": \"prod\"},\n)\n\noperation = client.create_instance(\n    request={\n        \"parent\": parent,\n        \"instance_id\": \"cache-prod\",\n        \"instance\": instance,\n    }\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\nprint(created.discovery_endpoint)\n```\n\nPractical constraints from the official docs:\n\n- `instance_id` must be 1 to 40 characters\n- it must use lowercase letters, numbers, and hyphens\n- it must start with a letter\n- it must end with a letter or number\n- `node_count` and `node_config` are required\n- `authorized_network` should point at the VPC network meant to reach the cache\n\nThe product docs also note that a private services access connection must exist for the selected network before instance creation succeeds.\n\n### Update instance metadata\n\nUse a field mask. Do not assume the whole resource is safely patchable.\n\n```python\nfrom google.cloud import memcache_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = memcache_v1.CloudMemcacheClient()\n\npatch = memcache_v1.Instance(\n    name=\"projects/my-project/locations/us-central1/instances/cache-prod\",\n    display_name=\"Cache production\",\n)\n\noperation = client.update_instance(\n    request={\n        \"update_mask\": FieldMask(paths=[\"display_name\"]),\n        \"instance\": patch,\n    }\n)\n\nupdated = operation.result(timeout=1800)\nprint(updated.display_name)\n```\n\n### Stage Memcached parameter changes\n\n`update_parameters()` stages parameter changes. It does not apply them to nodes by itself.\n\n```python\nfrom google.cloud import memcache_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = memcache_v1.CloudMemcacheClient()\n\noperation = client.update_parameters(\n    request={\n        \"name\": \"projects/my-project/locations/us-central1/instances/cache-prod\",\n        \"update_mask\": FieldMask(paths=[\"params\"]),\n        \"parameters\": memcache_v1.MemcacheParameters(\n            params={\n                \"max-item-size\": \"1048576\",\n                \"lru_crawler\": \"yes\",\n            }\n        ),\n    }\n)\n\noperation.result(timeout=1800)\n```\n\n### Apply staged parameters\n\nThe generated client docs state that `ApplyParameters` restarts the specified nodes so they pick up the current staged parameter set.\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\n\noperation = client.apply_parameters(\n    request={\n        \"name\": \"projects/my-project/locations/us-central1/instances/cache-prod\"\n    }\n)\n\noperation.result(timeout=1800)\n```\n\nThe product docs warn that applying parameter updates can flush cache data on affected nodes. Treat this as an operational change, not a harmless metadata edit.\n\n### Reschedule maintenance\n\nThe reference types include `RescheduleMaintenanceRequest`, `MaintenancePolicy`, and `MaintenanceSchedule`.\n\n```python\nfrom datetime import datetime, timezone\n\nfrom google.cloud import memcache_v1\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\nclient = memcache_v1.CloudMemcacheClient()\n\nschedule_time = Timestamp()\nschedule_time.FromDatetime(datetime(2026, 3, 20, 3, 0, tzinfo=timezone.utc))\n\noperation = client.reschedule_maintenance(\n    request={\n        \"instance\": \"projects/my-project/locations/us-central1/instances/cache-prod\",\n        \"reschedule_type\": (\n            memcache_v1.RescheduleMaintenanceRequest.RescheduleType.SPECIFIC_TIME\n        ),\n        \"schedule_time\": schedule_time,\n    }\n)\n\noperation.result(timeout=1800)\n```\n\n### Delete an instance\n\n```python\nfrom google.cloud import memcache_v1\n\nclient = memcache_v1.CloudMemcacheClient()\n\noperation = client.delete_instance(\n    request={\n        \"name\": \"projects/my-project/locations/us-central1/instances/cache-prod\"\n    }\n)\n\noperation.result(timeout=1800)\n```\n\n## Connecting Your Application To The Cache\n\nThis package stops at the admin API.\n\nTypical split:\n\n1. Use `google-cloud-memcache` to provision or inspect the Memorystore instance.\n2. Read `discovery_endpoint` or node addresses from the returned `Instance`.\n3. Configure a real Memcached client in your application to talk to those endpoints.\n\nIf generated code starts calling `client.get()` or `client.set()` on `CloudMemcacheClient`, it is using the wrong API surface.\n\n## Logging\n\nThe official PyPI package page documents optional structured logging support through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`.\n\nExample:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nUse that only when you explicitly want Google client library debug logging, and treat emitted RPC metadata as potentially sensitive.\n\n## Common Pitfalls\n\n### Using the admin client as a Memcached data client\n\nThis package manages instances. It does not implement Memcached `get`, `set`, `delete`, or CAS operations.\n\n### Missing private services access\n\nCreating an instance can fail even with correct IAM if the target VPC network does not already have private services access configured.\n\n### Forgetting to wait on long-running operations\n\n`create_instance()`, `update_instance()`, `update_parameters()`, `apply_parameters()`, `reschedule_maintenance()`, and `delete_instance()` are not immediate state changes.\n\n### Assuming parameter updates are harmless\n\nThe product docs explicitly warn that applying updated parameters can flush cache data on affected nodes.\n\n### Blindly trusting `latest` doc version labels\n\nFor this package on March 12, 2026, the official reference pages lag the official PyPI release. Pin generated install commands to `1.14.0`, but validate method availability against the current reference pages when you rely on newly added features.\n\n## Official Source URLs\n\n- `https://cloud.google.com/python/docs/reference/memcache/latest`\n- `https://cloud.google.com/python/docs/reference/memcache/latest/google.cloud.memcache_v1.services.cloud_memcache.CloudMemcacheClient`\n- `https://cloud.google.com/python/docs/reference/memcache/latest/google.cloud.memcache_v1.types.Instance`\n- `https://cloud.google.com/python/docs/reference/memcache/latest/google.cloud.memcache_v1.types`\n- `https://cloud.google.com/memorystore/docs/memcached`\n- `https://cloud.google.com/memorystore/docs/memcached/configure-memcached`\n- `https://cloud.google.com/memorystore/docs/memcached/establish-connection`\n- `https://cloud.google.com/docs/authentication/client-libraries`\n- `https://cloud.google.com/docs/authentication/application-default-credentials`\n- `https://pypi.org/project/google-cloud-memcache/`\n"
  },
  {
    "path": "content/google/docs/migrationcenter/python/DOC.md",
    "content": "---\nname: migrationcenter\ndescription: \"Google Cloud Migration Center Python client for asset inventory reads, group management, and import jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,migrationcenter,migration,inventory,discovery,python\"\n---\n\n# Google Cloud Migration Center Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-migrationcenter` package with `from google.cloud import migrationcenter_v1`, and authenticate with Google Cloud credentials instead of API keys or custom bearer-token code.\n\nMigration Center resources are location-scoped. Before you automate against this API, enable Migration Center for the project and choose the location that will store your discovery data. The product docs say that location cannot be changed later.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-migrationcenter==0.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-migrationcenter==0.3.0\"\npoetry add \"google-cloud-migrationcenter==0.3.0\"\n```\n\nPyPI for `0.3.0` lists Python `>=3.7`.\n\n## Authentication And Setup\n\n1. Enable the Migration Center API for the Google Cloud project.\n2. Activate Migration Center for the project and pick the location you will use.\n3. Use Application Default Credentials (ADC) for local development and deployed workloads.\n4. Set the project ID and location explicitly when your environment does not already provide them.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import migrationcenter_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nPARENT = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\n\nclient = migrationcenter_v1.MigrationCenterClient()\n```\n\nThe generated client reference notes that some Google APIs support regional endpoints through `client_options`. For Migration Center, the resource name you pass in `parent` or `name` is the main location control you need in normal code.\n\n## Core Workflows\n\n### List assets\n\n```python\nimport os\n\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\nparent = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/locations/{os.environ['GOOGLE_CLOUD_LOCATION']}\"\n\npager = client.list_assets(\n    request={\n        \"parent\": parent,\n        \"page_size\": 100,\n    }\n)\n\nfor asset in pager:\n    print(asset.name)\n```\n\n`list_assets()` returns a pager. Iterate over it directly unless you have a reason to manage page tokens yourself.\n\n### Get one asset\n\n```python\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\n\nasset = client.get_asset(\n    request={\n        \"name\": \"projects/your-project-id/locations/us-central1/assets/1234567890\",\n    }\n)\n\nprint(asset.name)\nprint(asset.display_name)\n```\n\n### Create a group and add assets to it\n\nGroups are lightweight containers in Migration Center. The REST resource only exposes server-managed fields, so creating a group uses an empty `group` body plus your chosen `group_id`.\n\n```python\nimport os\n\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\nparent = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/locations/{os.environ['GOOGLE_CLOUD_LOCATION']}\"\n\ncreate_operation = client.create_group(\n    request={\n        \"parent\": parent,\n        \"group_id\": \"wave-1\",\n        \"group\": migrationcenter_v1.Group(),\n    }\n)\ngroup = create_operation.result()\n\nadd_operation = client.add_assets_to_group(\n    request={\n        \"group\": group.name,\n        \"assets\": [\n            \"projects/your-project-id/locations/us-central1/assets/1234567890\",\n            \"projects/your-project-id/locations/us-central1/assets/9876543210\",\n        ],\n    }\n)\nadd_operation.result()\n```\n\nRemove assets later with the symmetric call:\n\n```python\nclient.remove_assets_from_group(\n    request={\n        \"group\": \"projects/your-project-id/locations/us-central1/groups/wave-1\",\n        \"assets\": [\n            \"projects/your-project-id/locations/us-central1/assets/1234567890\",\n        ],\n    }\n).result()\n```\n\n### Create an upload source and import job\n\nAn import job points at a source. For file-based imports, create a source with `SOURCE_TYPE_UPLOAD` first.\n\n```python\nimport os\n\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\nparent = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/locations/{os.environ['GOOGLE_CLOUD_LOCATION']}\"\n\nsource_operation = client.create_source(\n    request={\n        \"parent\": parent,\n        \"source_id\": \"rvtools-upload\",\n        \"source\": migrationcenter_v1.Source(\n            type_=migrationcenter_v1.Source.SourceType.SOURCE_TYPE_UPLOAD\n        ),\n    }\n)\nsource = source_operation.result()\n\njob_operation = client.create_import_job(\n    request={\n        \"parent\": parent,\n        \"import_job_id\": \"rvtools-import-001\",\n        \"import_job\": migrationcenter_v1.ImportJob(\n            display_name=\"rvtools-import-001\",\n            asset_source=source.name,\n        ),\n    }\n)\nimport_job = job_operation.result()\n```\n\n### Create an import data file\n\nUse `create_import_data_file()` to ask Migration Center for a signed upload target. The official type reference documents the signed URI, the required headers, and the expiration time.\n\n```python\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\n\ndata_file = client.create_import_data_file(\n    request={\n        \"parent\": \"projects/your-project-id/locations/us-central1/importJobs/rvtools-import-001\",\n        \"import_data_file\": {\n            \"display_name\": \"rvtools.xlsx\",\n            \"format\": migrationcenter_v1.ImportJobFormat.IMPORT_JOB_FORMAT_RVTOOLS_XLSX,\n        },\n    }\n)\n\nprint(data_file.name)\nprint(data_file.upload_file_info.signed_uri)\nprint(dict(data_file.upload_file_info.headers))\n```\n\nInference from the official `UploadFileInfo` reference: the Python client stops after it gives you the signed upload URL and headers, so the file transfer itself is a normal HTTPS upload outside this SDK.\n\n```python\nfrom pathlib import Path\n\nimport requests\n\npayload = Path(\"rvtools.xlsx\").read_bytes()\n\nresponse = requests.put(\n    data_file.upload_file_info.signed_uri,\n    data=payload,\n    headers=dict(data_file.upload_file_info.headers),\n    timeout=300,\n)\nresponse.raise_for_status()\n```\n\n### Validate and run an import job\n\n```python\nfrom google.cloud import migrationcenter_v1\n\nclient = migrationcenter_v1.MigrationCenterClient()\nname = \"projects/your-project-id/locations/us-central1/importJobs/rvtools-import-001\"\n\nclient.validate_import_job(request={\"name\": name}).result()\nclient.run_import_job(request={\"name\": name}).result()\n```\n\nBoth methods return long-running operations. Wait for `.result()` before you assume the request completed successfully.\n\n## Configuration Notes\n\n- Migration Center uses location-qualified resource names everywhere: `projects/{project}/locations/{location}/...`.\n- The product setup flow requires you to choose a Migration Center location up front. The product docs say you cannot change it later for that project.\n- Use ADC for routine code. Avoid inventing API-key authentication or passing raw bearer tokens into generated clients.\n- `create_group()`, `create_source()`, `create_import_job()`, `add_assets_to_group()`, `remove_assets_from_group()`, `validate_import_job()`, and `run_import_job()` are long-running operations.\n\n## Common Pitfalls\n\n- Do not omit the location in resource names. `projects/{project}/assets/...` is wrong for this API.\n- Do not assume groups carry custom metadata. In the REST reference, `Group` only exposes server-managed fields such as `name`, `createTime`, and `updateTime`.\n- Do not assume the SDK uploads import files for you. `create_import_data_file()` only returns `upload_file_info`; your code still needs to upload the file bytes to the signed URI.\n- Keep `group_id`, `source_id`, and `import_job_id` RFC 1034 compatible: lowercase letters, digits, and hyphens, starting with a letter and ending with a letter or digit.\n- Use the supported import format enum that matches your file. The REST reference lists `RVTOOLS_XLSX`, `RISC_XLSX`, and `STRATOZONE_CSV`.\n\n## Version Notes\n\n- This guide is pinned to `google-cloud-migrationcenter==0.3.0`.\n- The hosted Python reference is published under a `latest` path, so verify the package version if your project depends on behavior added after `0.3.0`.\n- The package is still in the `0.x` series, so treat minor-version upgrades as potentially meaningful changes instead of assuming strict long-term stability.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-migrationcenter/0.3.0/\n- Maintainer package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-migrationcenter\n- Python client reference: https://docs.cloud.google.com/python/docs/reference/migrationcenter/latest/google.cloud.migrationcenter_v1.services.migration_center.MigrationCenterClient\n- Get started with Migration Center: https://cloud.google.com/migration-center/docs/get-started\n- Group REST resource and create method: https://cloud.google.com/migration-center/docs/reference/rest/v1/projects.locations.groups/create\n- Source REST resource and create method: https://cloud.google.com/migration-center/docs/reference/rest/v1/projects.locations.sources/create\n- Import job REST resource and create method: https://cloud.google.com/migration-center/docs/reference/rest/v1/projects.locations.importJobs/create\n- Import data file REST resource and create method: https://cloud.google.com/migration-center/docs/reference/rest/v1/projects.locations.importJobs.importDataFiles/create\n"
  },
  {
    "path": "content/google/docs/monitoring/javascript/DOC.md",
    "content": "---\nname: monitoring\ndescription: \"Google Cloud Monitoring Node.js client for reading metrics, writing custom metrics, and inspecting alerting resources\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,monitoring,observability,metrics,alerting,javascript,nodejs\"\n---\n\n# `@google-cloud/monitoring` JavaScript Package Guide\n\nUse `@google-cloud/monitoring` when your Node.js code needs to read Cloud Monitoring time series, write custom metrics, inspect alert policies, or work with notification channel configuration.\n\n## Golden Rule\n\n- Import the generated `v3` service clients from `@google-cloud/monitoring`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass `projectId` or `keyFilename` explicitly.\n- Most project-scoped requests use `projects/{projectId}` as the `name` or `parent` value.\n- Start metric reads with a known metric type and a small time window; Monitoring filters are strict and often return no data instead of a helpful error.\n- For custom metrics, keep the metric type, value type, metric kind, and monitored resource labels consistent across writes.\n\nThis guide covers `5.3.1`.\n\n## Install\n\nPin the version if you want behavior to match this guide exactly:\n\n```bash\nnpm install @google-cloud/monitoring@5.3.1\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials, not API keys.\n\nEnable Cloud Monitoring in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable monitoring.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud auth application-default login\ngcloud config set project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nBefore you write code, make sure:\n\n1. The Monitoring API is enabled in the project.\n2. The credential resolves to the principal you expect.\n3. That principal has permission for the specific Monitoring operations you want to perform.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst metricClient = new monitoring.v3.MetricServiceClient();\nconst alertClient = new monitoring.v3.AlertPolicyServiceClient();\nconst channelClient = new monitoring.v3.NotificationChannelServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v3} from '@google-cloud/monitoring';\n\nconst metricClient = new v3.MetricServiceClient();\nconst alertClient = new v3.AlertPolicyServiceClient();\nconst channelClient = new v3.NotificationChannelServiceClient();\n```\n\nWith explicit project ID and credential file:\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst metricClient = new monitoring.v3.MetricServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Read Time Series Data\n\nUse `MetricServiceClient` for metric reads.\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst client = new monitoring.v3.MetricServiceClient();\n\nasync function listCpuUtilization(projectId) {\n  const nowSeconds = Math.floor(Date.now() / 1000);\n\n  const [timeSeries] = await client.listTimeSeries({\n    name: `projects/${projectId}`,\n    filter:\n      'metric.type = \"compute.googleapis.com/instance/cpu/utilization\"',\n    interval: {\n      startTime: {seconds: nowSeconds - 10 * 60},\n      endTime: {seconds: nowSeconds},\n    },\n  });\n\n  for (const series of timeSeries) {\n    console.log(series.metric?.type);\n    console.log(series.resource?.type);\n    console.log(series.metric?.labels);\n    console.log(series.resource?.labels);\n  }\n}\n\nlistCpuUtilization(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\nNotes:\n\n- `name` is usually `projects/{projectId}`.\n- `filter` must use Cloud Monitoring filter syntax exactly.\n- If you only need series metadata, use the headers-only view to reduce response size.\n\n### Write A Custom Metric\n\nCloud Monitoring creates the custom metric descriptor automatically on first write if the metric type is new.\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst client = new monitoring.v3.MetricServiceClient();\n\nasync function writeCustomMetric(projectId) {\n  const nowSeconds = Math.floor(Date.now() / 1000);\n\n  await client.createTimeSeries({\n    name: `projects/${projectId}`,\n    timeSeries: [\n      {\n        metric: {\n          type: 'custom.googleapis.com/myapp/request_latency_ms',\n          labels: {\n            endpoint: '/healthz',\n          },\n        },\n        resource: {\n          type: 'global',\n          labels: {\n            project_id: projectId,\n          },\n        },\n        points: [\n          {\n            interval: {\n              endTime: {seconds: nowSeconds},\n            },\n            value: {\n              doubleValue: 123.4,\n            },\n          },\n        ],\n      },\n    ],\n  });\n}\n\nwriteCustomMetric(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\nKeep the first successful write stable, because later writes must match the metric's established type and resource model.\n\n### List Alert Policies\n\nUse `AlertPolicyServiceClient` to inspect or manage alerting rules.\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst client = new monitoring.v3.AlertPolicyServiceClient();\n\nasync function listAlertPolicies(projectId) {\n  const [policies] = await client.listAlertPolicies({\n    name: `projects/${projectId}`,\n  });\n\n  for (const policy of policies) {\n    console.log(policy.name, policy.displayName, policy.enabled);\n  }\n}\n\nlistAlertPolicies(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\nThis is a good first step before attempting updates, because it shows the exact resource names and the current policy structure in your project.\n\n### Inspect Notification Channel Types\n\nBefore creating a notification channel, inspect the descriptors for the channel type you want so you know which labels are required.\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst client = new monitoring.v3.NotificationChannelServiceClient();\n\nasync function listChannelDescriptors(projectId) {\n  const [descriptors] = await client.listNotificationChannelDescriptors({\n    name: `projects/${projectId}`,\n  });\n\n  for (const descriptor of descriptors) {\n    console.log(descriptor.type, descriptor.displayName);\n  }\n}\n\nlistChannelDescriptors(process.env.GOOGLE_CLOUD_PROJECT).catch(console.error);\n```\n\n## Configuration Notes\n\n### Pass Credentials Explicitly Only When Needed\n\nGenerated clients can take `projectId` and `keyFilename`, but in most Google Cloud environments ADC is simpler and safer.\n\n```javascript\nconst monitoring = require('@google-cloud/monitoring');\n\nconst client = new monitoring.v3.MetricServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\n### Resource Names Matter\n\nMany Monitoring methods require fully qualified project or resource names. The common starting points are:\n\n- project name: `projects/PROJECT_ID`\n- alert policy name: `projects/PROJECT_ID/alertPolicies/POLICY_ID`\n- notification channel name: `projects/PROJECT_ID/notificationChannels/CHANNEL_ID`\n\n### Keep Filters Simple First\n\nWhen `listTimeSeries()` returns no data, the most common causes are:\n\n- the metric type is wrong\n- the resource labels do not match the series you are querying\n- the interval is too narrow or outside the retention window\n\nStart with only `metric.type = \"...\"`, confirm that it returns data, then add additional clauses.\n\n## Common Pitfalls\n\n- Install `@google-cloud/monitoring`, then import the generated `v3` clients from that package.\n- Do not assume a custom metric write can omit monitored resource labels. Even `global` metrics need `project_id`.\n- Keep the value type stable. If the first writes establish a metric as `double`, later integer or string values fail.\n- `listTimeSeries()` is strict about filters and time windows; an empty result often means the request matched nothing, not that the client is broken.\n- The docs root uses `/latest`, which moves. Pin the package version in your app and in any internal runbooks that depend on exact behavior.\n"
  },
  {
    "path": "content/google/docs/monitoring/python/DOC.md",
    "content": "---\nname: monitoring\ndescription: \"Google Cloud Monitoring Python client library for metrics, alerting, uptime checks, and SLO automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.29.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,monitoring,observability,metrics,alerting,slo\"\n---\n\n# Google Cloud Monitoring Python Client Library\n\n## Golden Rule\n\nUse the official `google-cloud-monitoring` package with `from google.cloud import monitoring_v3`, and authenticate with Application Default Credentials (ADC).\n\nFor `2.29.1`, prefer the generated `*ServiceClient` classes such as `MetricServiceClient`, `AlertPolicyServiceClient`, and `NotificationChannelServiceClient`. Avoid old blog posts that import `google.cloud.monitoring` or use `monitoring.Client()` unless you are intentionally maintaining legacy code.\n\n## Install\n\nPin the package version if you want behavior to match this document exactly:\n\n```bash\npython -m pip install \"google-cloud-monitoring==2.29.1\"\n```\n\nIf you want the optional dataframe helper from `monitoring_v3.query.Query`, install `pandas` too:\n\n```bash\npython -m pip install \"google-cloud-monitoring==2.29.1\" pandas\n```\n\n## Authentication And Project Setup\n\nThis library uses Google Cloud credentials, not API keys.\n\nFor local development, the usual path is:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID\n```\n\nFor service-to-service or production workloads, attach a service account to the runtime or set:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json\nexport GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID\n```\n\nYou also need the Cloud Monitoring API enabled in the target project.\n\n## Initialize Clients\n\nMost work starts with a fully qualified project resource name:\n\n```python\nfrom google.cloud import monitoring_v3\n\nproject_id = \"your-project-id\"\nproject_name = monitoring_v3.MetricServiceClient.common_project_path(project_id)\n\nmetric_client = monitoring_v3.MetricServiceClient()\nalert_client = monitoring_v3.AlertPolicyServiceClient()\nchannel_client = monitoring_v3.NotificationChannelServiceClient()\nuptime_client = monitoring_v3.UptimeCheckServiceClient()\nservice_client = monitoring_v3.ServiceMonitoringServiceClient()\nquery_client = monitoring_v3.QueryServiceClient()\n```\n\nUse the client matching the API surface you need:\n\n- `MetricServiceClient`: read and write metrics/time series, descriptors, groups\n- `AlertPolicyServiceClient`: alert policies\n- `NotificationChannelServiceClient`: email, Pub/Sub, webhook, PagerDuty, and other channel config\n- `UptimeCheckServiceClient`: uptime checks and configs\n- `ServiceMonitoringServiceClient`: services and SLOs\n- `QueryServiceClient`: Monitoring Query Language (MQL) time-series queries\n\n## Core Usage\n\n### Read time series with `MetricServiceClient`\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import monitoring_v3\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\nproject_id = \"your-project-id\"\nclient = monitoring_v3.MetricServiceClient()\nproject_name = client.common_project_path(project_id)\n\nend = Timestamp()\nend.FromDatetime(datetime.now(tz=timezone.utc))\n\nstart = Timestamp()\nstart.FromDatetime(datetime.now(tz=timezone.utc) - timedelta(minutes=10))\n\ninterval = monitoring_v3.TimeInterval(\n    {\n        \"end_time\": end,\n        \"start_time\": start,\n    }\n)\n\nresults = client.list_time_series(\n    request={\n        \"name\": project_name,\n        \"filter\": 'metric.type = \"compute.googleapis.com/instance/cpu/utilization\"',\n        \"interval\": interval,\n        \"view\": monitoring_v3.ListTimeSeriesRequest.TimeSeriesView.FULL,\n    }\n)\n\nfor series in results:\n    print(series.metric.type)\n    print(series.resource.type)\n    print(series.metric.labels)\n    print(series.resource.labels)\n```\n\nNotes:\n\n- `name` is usually `projects/{project_id}`.\n- `filter` must match Cloud Monitoring filter syntax exactly; a wrong metric type or resource label returns no data rather than a helpful error.\n- Use `HEADERS` view if you only need metadata and want to reduce payload size.\n\n### Write a custom metric with `create_time_series`\n\n```python\nimport time\n\nfrom google.cloud import monitoring_v3\n\nproject_id = \"your-project-id\"\nclient = monitoring_v3.MetricServiceClient()\nproject_name = client.common_project_path(project_id)\n\nseries = monitoring_v3.TimeSeries()\nseries.metric.type = \"custom.googleapis.com/myapp/request_latency_ms\"\nseries.metric.labels[\"endpoint\"] = \"/healthz\"\nseries.resource.type = \"global\"\nseries.resource.labels[\"project_id\"] = project_id\n\nnow = time.time()\nseconds = int(now)\nnanos = int((now - seconds) * 1_000_000_000)\n\npoint = series.points.add()\npoint.value.double_value = 123.4\npoint.interval.end_time.seconds = seconds\npoint.interval.end_time.nanos = nanos\n\nclient.create_time_series(name=project_name, time_series=[series])\n```\n\nNotes:\n\n- The metric descriptor for a custom metric is created automatically on first write if the metric type is new.\n- Your metric kind and value type are inferred from the first writes. Be consistent so later writes do not fail with type mismatches.\n- The monitored resource must match the labels required by that resource type. `global` is a simple starting point for app-level custom metrics.\n\n### Use the query helper for simple aggregations\n\n```python\nfrom google.cloud import monitoring_v3\nfrom google.cloud.monitoring_v3.query import Query\n\nproject_id = \"your-project-id\"\nmetric_client = monitoring_v3.MetricServiceClient()\n\nquery = Query(\n    metric_client,\n    project=project_id,\n    metric_type=\"compute.googleapis.com/instance/cpu/utilization\",\n    minutes=30,\n)\n\nquery = query.select_resources(resource_type=\"gce_instance\").align(\n    monitoring_v3.Aggregation.Aligner.ALIGN_MEAN,\n    minutes=5,\n)\n\nfor time_series in query:\n    print(time_series.metric.labels, len(time_series.points))\n```\n\nIf you call `query.as_dataframe()`, install `pandas` first.\n\n### List alert policies\n\n```python\nfrom google.cloud import monitoring_v3\n\nproject_id = \"your-project-id\"\nclient = monitoring_v3.AlertPolicyServiceClient()\nproject_name = client.common_project_path(project_id)\n\nfor policy in client.list_alert_policies(request={\"name\": project_name}):\n    print(policy.name, policy.display_name, policy.enabled)\n```\n\nBefore creating notification channels, inspect the descriptor for the channel type you want so you know which labels are required:\n\n```python\nfrom google.cloud import monitoring_v3\n\nproject_id = \"your-project-id\"\nclient = monitoring_v3.NotificationChannelServiceClient()\nproject_name = client.common_project_path(project_id)\n\nfor descriptor in client.list_notification_channel_descriptors(name=project_name):\n    print(descriptor.type, descriptor.display_name)\n```\n\n## Configuration, Retries, And Runtime Behavior\n\n### Explicit credentials or project\n\nIf ADC is not enough, pass explicit credentials:\n\n```python\nfrom google.cloud import monitoring_v3\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = monitoring_v3.MetricServiceClient(credentials=credentials)\n```\n\nMost constructors also accept `client_options`, which is where you override the API endpoint or universe domain when you need non-default routing:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import monitoring_v3\n\nclient = monitoring_v3.MetricServiceClient(\n    client_options=ClientOptions(api_endpoint=\"monitoring.googleapis.com\")\n)\n```\n\n### Retry and timeout control\n\nRPC methods accept `retry=` and `timeout=` parameters. Use them when a polling loop or a high-volume metrics pipeline needs predictable behavior:\n\n```python\nresults = client.list_time_series(\n    request=request,\n    timeout=30,\n)\n```\n\n### Library logging\n\nGoogle's Python client libraries support environment-based logging configuration. For debugging client behavior, set a Google logging scope before starting the process:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.monitoring_v3\n```\n\n### Multiprocessing\n\nGoogle's generated docs call out a multiprocessing caveat: when you use `multiprocessing` with the gRPC transport, create client instances after `os.fork()`.\n\n## Common Pitfalls\n\n- Package name and import path differ. Install `google-cloud-monitoring`, but import `monitoring_v3`.\n- Modern code should use service clients, not the older `monitoring.Client()` examples you may find on historical release pages or blogs.\n- Many methods want full resource names such as `projects/{project_id}` or `projects/{project_id}/alertPolicies/{policy_id}`. Use the path helper methods on the client when available.\n- `QueryServiceClient` and the `query.Query` helper are for Monitoring Query Language. Google has deprecated MQL for new dashboard and alert creation, so prefer PromQL for new query authoring where the product surface supports it.\n- Writing custom metrics fails if the monitored resource labels are incomplete or if later points change value type or metric kind.\n- `list_time_series` filter strings are strict. Start with a known metric type from the console or `list_metric_descriptors` output before adding more clauses.\n- `query.as_dataframe()` needs `pandas`; it is not bundled by default with this package.\n- In long-running ingestion jobs, do not assume the docs alias `/latest` stays pinned to `2.29.1`. Store the package version separately.\n\n## Version-Sensitive Notes For `2.29.1`\n\n- The official docs and PyPI both show `2.29.1` as the current package version on 2026-03-12.\n- The upstream changelog lists `2.29.1` on 2026-02-05 as a bugfix release for mypy-related errors.\n- The changelog for `2.29.0` notes automatic mTLS enablement when the runtime provides the required certificates and Google APIs use the default host. If endpoint selection matters in your environment, set `client_options` and the related Google API endpoint environment variables explicitly instead of relying on defaults.\n- The docs root in Google Cloud uses `/latest`, which is a moving alias. Treat the package version in frontmatter as the actual pin, not the URL path.\n"
  },
  {
    "path": "content/google/docs/network-connectivity/python/DOC.md",
    "content": "---\nname: network-connectivity\ndescription: \"Google Cloud Network Connectivity Python client for Network Connectivity Center hubs, spokes, route tables, and related control-plane APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,google-cloud,network-connectivity,networking,ncc,python\"\n---\n\n# google-cloud-network-connectivity Python Package Guide\n\n## What This Package Is\n\n`google-cloud-network-connectivity` is the official Google Cloud Python client for the Network Connectivity API. For Network Connectivity Center automation, the main entry point is `google.cloud.networkconnectivity_v1.HubServiceClient`, which manages hubs, spokes, route tables, and related long-running operations.\n\nThe package also includes other v1 services such as Internal Range, Policy Based Routing, Data Transfer, and Cross Network Automation. This guide stays focused on the hub-and-spoke workflows that Google documents most directly for Network Connectivity Center.\n\n## Version Note\n\nThis guide covers package version `2.13.0`, which PyPI lists as the latest release as of `2026-03-13`.\n\nGoogle's docs are slightly uneven right now:\n\n- the PyPI page lists `2.13.0`\n- the reference docs `latest` selector and changelog selector include `2.13.0`\n- some individual class pages still render `2.11.0` in the page heading\n\nThe examples below use the current GA `networkconnectivity_v1` surface and method signatures from the live reference docs.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-network-connectivity==2.13.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Authentication And Prerequisites\n\nBefore using the client:\n\n1. Choose the Google Cloud project that owns the hub or spoke resources.\n2. Enable billing for that project.\n3. Enable the Network Connectivity API.\n4. Configure Application Default Credentials (ADC).\n\nEnable the API:\n\n```bash\ngcloud services enable networkconnectivity.googleapis.com\n```\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nGoogle recommends user ADC or attached service accounts first. Use a downloaded service account key only if you cannot use those safer options.\n\n## Client Initialization\n\nDefault client using ADC:\n\n```python\nimport os\n\nfrom google.cloud import networkconnectivity_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = networkconnectivity_v1.HubServiceClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nCustom endpoint override:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient(\n    client_options=ClientOptions(api_endpoint=os.environ[\"GOOGLE_API_ENDPOINT\"])\n)\n```\n\nThe generated client accepts `client_options.api_endpoint`, and Google's autogenerated snippets note that some deployments may require specifying regional endpoints explicitly.\n\n## Resource Naming\n\nUse fully qualified resource names:\n\n- hub parent: `projects/{project_id}/locations/global`\n- hub name: `projects/{project_id}/locations/global/hubs/{hub_id}`\n- spoke parent for VPC spokes: `projects/{project_id}/locations/global`\n- spoke parent for hybrid spokes: `projects/{project_id}/locations/{region}`\n- spoke name: `projects/{project_id}/locations/{location}/spokes/{spoke_id}`\n\nHelper methods on `HubServiceClient` are useful for names you already know:\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient()\n\nhub_name = client.hub_path(\"my-project\", \"my-hub\")\nspoke_name = client.spoke_path(\"my-project\", \"global\", \"my-vpc-spoke\")\nglobal_parent = client.common_location_path(\"my-project\", \"global\")\n```\n\nFor a VPC spoke, the linked network is identified by a network URI such as `projects/my-project/global/networks/my-network`.\n\n## Core Usage\n\n### List hubs in a project\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\ndef list_hubs(project_id: str) -> list[networkconnectivity_v1.Hub]:\n    client = networkconnectivity_v1.HubServiceClient()\n    parent = client.common_location_path(project_id, \"global\")\n    return list(client.list_hubs(parent=parent))\n\nfor hub in list_hubs(\"my-project\"):\n    print(hub.name, hub.state)\n```\n\n### Create a hub\n\n`create_hub()` is a long-running operation. Wait for `.result()` before assuming the hub exists.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\ndef create_hub(project_id: str, hub_id: str) -> networkconnectivity_v1.Hub:\n    client = networkconnectivity_v1.HubServiceClient()\n    parent = client.common_location_path(project_id, \"global\")\n\n    operation = client.create_hub(\n        parent=parent,\n        hub_id=hub_id,\n        hub=networkconnectivity_v1.Hub(\n            description=\"Shared connectivity hub\",\n            labels={\"env\": \"dev\"},\n        ),\n    )\n    return operation.result(timeout=300)\n\nhub = create_hub(\"my-project\", \"my-hub\")\nprint(hub.name)\n```\n\n### Get and update a hub\n\n`update_hub()` only documents updates to the hub description and labels. Pass an explicit field mask.\n\n```python\nfrom google.cloud import networkconnectivity_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = networkconnectivity_v1.HubServiceClient()\nhub_name = client.hub_path(\"my-project\", \"my-hub\")\n\nhub = client.get_hub(name=hub_name)\nprint(hub.description)\n\noperation = client.update_hub(\n    hub=networkconnectivity_v1.Hub(\n        name=hub_name,\n        description=\"Production connectivity hub\",\n        labels={\"env\": \"prod\", \"team\": \"networking\"},\n    ),\n    update_mask=FieldMask(paths=[\"description\", \"labels\"]),\n)\n\nupdated_hub = operation.result(timeout=300)\nprint(updated_hub.labels)\n```\n\n### Create a VPC spoke\n\nVPC spokes are global. A spoke must reference a hub and set exactly one linked backing resource. For a VPC spoke, that backing resource is `linked_vpc_network`.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\ndef create_vpc_spoke(\n    spoke_project_id: str,\n    hub_project_id: str,\n    hub_id: str,\n    spoke_id: str,\n    network_name: str,\n) -> networkconnectivity_v1.Spoke:\n    client = networkconnectivity_v1.HubServiceClient()\n    parent = client.common_location_path(spoke_project_id, \"global\")\n    hub_name = client.hub_path(hub_project_id, hub_id)\n\n    operation = client.create_spoke(\n        parent=parent,\n        spoke_id=spoke_id,\n        spoke=networkconnectivity_v1.Spoke(\n            hub=hub_name,\n            description=\"Attach a VPC network to the hub\",\n            linked_vpc_network=networkconnectivity_v1.LinkedVpcNetwork(\n                uri=f\"projects/{spoke_project_id}/global/networks/{network_name}\"\n            ),\n        ),\n    )\n    return operation.result(timeout=300)\n\nspoke = create_vpc_spoke(\n    spoke_project_id=\"my-project\",\n    hub_project_id=\"my-project\",\n    hub_id=\"my-hub\",\n    spoke_id=\"my-vpc-spoke\",\n    network_name=\"prod-network\",\n)\nprint(spoke.name, spoke.state)\n```\n\n### List and inspect spokes\n\nFor VPC spokes, list under `global`. For regional spoke types such as VPN, VLAN attachment, or router appliance spokes, list under the resource's region.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient()\n\nfor spoke in client.list_spokes(\n    parent=client.common_location_path(\"my-project\", \"global\")\n):\n    print(spoke.name, spoke.spoke_type, spoke.state)\n\nspoke_name = client.spoke_path(\"my-project\", \"global\", \"my-vpc-spoke\")\nspoke = client.get_spoke(name=spoke_name)\nprint(spoke.hub)\nprint(spoke.linked_vpc_network.uri)\n```\n\n### List all spokes attached to a hub\n\nUse `list_hub_spokes()` when you need the hub-centric view across projects, including spokes that were proposed but not yet accepted.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient()\nhub_name = client.hub_path(\"hub-project\", \"shared-hub\")\n\nfor item in client.list_hub_spokes(name=hub_name):\n    print(item)\n```\n\n### Accept a proposed spoke from another project\n\nWhen the spoke project and the hub project differ, the hub administrator must accept the proposal before the spoke becomes active.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient()\n\nhub_name = client.hub_path(\"hub-project\", \"shared-hub\")\nspoke_uri = client.spoke_path(\"spoke-project\", \"global\", \"proposed-vpc-spoke\")\n\noperation = client.accept_hub_spoke(\n    name=hub_name,\n    spoke_uri=spoke_uri,\n)\n\nresponse = operation.result(timeout=300)\nprint(response)\n```\n\n### Delete a spoke and hub\n\nDeletes are also long-running operations.\n\n```python\nfrom google.cloud import networkconnectivity_v1\n\nclient = networkconnectivity_v1.HubServiceClient()\n\nspoke_name = client.spoke_path(\"my-project\", \"global\", \"my-vpc-spoke\")\nclient.delete_spoke(name=spoke_name).result(timeout=300)\n\nhub_name = client.hub_path(\"my-project\", \"my-hub\")\nclient.delete_hub(name=hub_name).result(timeout=300)\n```\n\n## Important Pitfalls\n\n- Hubs are global resources. Product docs also call out that VPC spokes are global, while hybrid spokes must be created in the same region as the underlying VPN tunnel, VLAN attachment, or router appliance resource.\n- `create_spoke()` requires exactly one linked backing resource. The current client docs explicitly list `linked_vpn_tunnels`, `linked_interconnect_attachments`, `linked_router_appliance_instances`, or `linked_vpc_network`.\n- Do not ignore the operation objects returned by create, update, accept, reject, and delete methods. Call `.result()` and set a timeout that matches your environment.\n- Use `update_mask` for updates. The hub update method is documented for description and label changes; omitting the mask can overwrite more than you intend.\n- Cross-project VPC spoke workflows are not fully automatic. A proposed spoke can exist before the hub administrator accepts it, so `list_hub_spokes()` and `accept_hub_spoke()` matter in real automation.\n- The docs site is not perfectly version-aligned for this package right now. If you depend on a field that looks new, verify it against the installed wheel and the current reference page for that class or method.\n"
  },
  {
    "path": "content/google/docs/network-management/python/DOC.md",
    "content": "---\nname: network-management\ndescription: \"google-cloud-network-management package guide for Python covering Connectivity Tests and VPC Flow Logs configuration with the Network Management API\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.32.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,google-cloud-network-management,gcp,network-management,connectivity-tests,vpc-flow-logs,python\"\n---\n\n# google-cloud-network-management Python Package Guide\n\n`google-cloud-network-management` is the official Google Cloud Python client for the Network Management API. The package's main v1 entry points are:\n\n- `network_management_v1.ReachabilityServiceClient` for Connectivity Tests\n- `network_management_v1.VpcFlowLogsServiceClient` for project-level VPC Flow Logs configs\n- `network_management_v1.OrganizationVpcFlowLogsServiceClient` for organization-level VPC Flow Logs configs\n\n## Version Note\n\nThis guide covers `google-cloud-network-management==1.32.0`, which PyPI and the current Google Cloud Python reference pages list as the latest release on `2026-03-13`.\n\nGoogle's hosted reference is slightly uneven right now:\n\n- the package root and client-class pages show `1.32.0`\n- some type pages still render older headings such as `1.29.0` or `1.30.0`\n\nUse `1.32.0` for dependency pinning, and rely on the latest client method pages for request shapes and signatures.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-network-management==1.32.0\"\n```\n\nPyPI currently declares `Requires: Python >=3.7`.\n\n## Authentication And Prerequisites\n\nBefore calling the client:\n\n1. Choose the Google Cloud project or organization you are targeting.\n2. Enable the Network Management API.\n3. Grant the caller IAM permissions for the resources the test or flow logs config will inspect or modify.\n4. Configure Application Default Credentials (ADC).\n\nEnable the API:\n\n```bash\ngcloud services enable networkmanagement.googleapis.com\n```\n\nLocal development with user ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nGoogle recommends ADC from your local user, attached service account, or workload identity before falling back to a downloaded key file.\n\n## Client Initialization\n\nDefault clients use ADC automatically:\n\n```python\nimport os\n\nfrom google.cloud import network_management_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nPARENT = f\"projects/{PROJECT_ID}/locations/global\"\n\nreachability = network_management_v1.ReachabilityServiceClient()\nflow_logs = network_management_v1.VpcFlowLogsServiceClient()\n```\n\nIf you need to authenticate from a specific service account file:\n\n```python\nfrom google.cloud import network_management_v1\n\nreachability = network_management_v1.ReachabilityServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nUseful resource name patterns:\n\n- Connectivity Tests parent: `projects/{project_id}/locations/global`\n- Connectivity Test name: `projects/{project_id}/locations/global/connectivityTests/{test_id}`\n- Project VPC Flow Logs config name: `projects/{project_id}/locations/global/vpcFlowLogsConfigs/{config_id}`\n- Organization VPC Flow Logs config parent: `organizations/{organization_id}/locations/global`\n\n## Connectivity Tests\n\nConnectivity Tests are managed through `ReachabilityServiceClient`. Create, update, and rerun operations are long-running operations, so wait for `operation.result()` before assuming the resource or analysis is ready.\n\n### Create a connectivity test\n\nThis example checks TCP reachability from one VM IP to another endpoint inside a GCP VPC network:\n\n```python\nfrom google.cloud import network_management_v1\n\n\ndef create_connectivity_test(\n    project_id: str,\n    test_id: str,\n    network_name: str,\n    source_ip: str,\n    destination_ip: str,\n) -> network_management_v1.ConnectivityTest:\n    client = network_management_v1.ReachabilityServiceClient()\n    parent = f\"projects/{project_id}/locations/global\"\n    network_uri = f\"projects/{project_id}/global/networks/{network_name}\"\n\n    operation = client.create_connectivity_test(\n        parent=parent,\n        test_id=test_id,\n        resource=network_management_v1.ConnectivityTest(\n            description=\"HTTPS connectivity check\",\n            source=network_management_v1.Endpoint(\n                ip_address=source_ip,\n                project_id=project_id,\n                network=network_uri,\n                network_type=network_management_v1.Endpoint.NetworkType.GCP_NETWORK,\n            ),\n            destination=network_management_v1.Endpoint(\n                ip_address=destination_ip,\n                project_id=project_id,\n                network=network_uri,\n                port=443,\n            ),\n            protocol=\"TCP\",\n        ),\n    )\n    return operation.result(timeout=300)\n\n\ntest = create_connectivity_test(\n    project_id=\"my-project\",\n    test_id=\"https-to-private-service\",\n    network_name=\"prod-network\",\n    source_ip=\"10.10.0.10\",\n    destination_ip=\"10.20.0.15\",\n)\n\nif (\n    test.reachability_details.result\n    == network_management_v1.ReachabilityDetails.Result.REACHABLE\n):\n    print(\"Reachable\")\nelse:\n    print(test.reachability_details.result)\n```\n\nImportant endpoint fields from the generated types:\n\n- `ip_address` is the IP to test from or to\n- `project_id` is useful when the endpoint belongs to Google Cloud resources\n- `network` is the full network URI such as `projects/my-project/global/networks/prod-network`\n- `port` applies to the destination endpoint\n- `protocol` accepts values such as `TCP`, `UDP`, `ICMP`, `ESP`, `AH`, `SCTP`, and `IPIP`\n\n### List, get, and rerun tests\n\n```python\nfrom google.cloud import network_management_v1\n\nclient = network_management_v1.ReachabilityServiceClient()\nparent = \"projects/my-project/locations/global\"\ntest_name = client.connectivity_test_path(\"my-project\", \"https-to-private-service\")\n\nfor test in client.list_connectivity_tests(parent=parent):\n    print(test.name, test.reachability_details.result)\n\ncurrent = client.get_connectivity_test(name=test_name)\nprint(current.description)\n\nrerun_operation = client.rerun_connectivity_test(\n    request=network_management_v1.RerunConnectivityTestRequest(name=test_name)\n)\nrerun_result = rerun_operation.result(timeout=300)\nprint(rerun_result.reachability_details.result)\n```\n\nUse `rerun_connectivity_test()` after route, firewall, or load balancer changes when you want fresh analysis without creating a new test resource.\n\n## VPC Flow Logs Configs\n\nUse `VpcFlowLogsServiceClient` to create and manage project-level VPC Flow Logs configs through the Network Management API. These resources are also global, even when the target subnet or tunnel is regional.\n\n### Create a VPC Flow Logs config for a subnet\n\n```python\nfrom google.cloud import network_management_v1\n\n\ndef create_subnet_flow_logs_config(\n    project_id: str,\n    region: str,\n    subnet_name: str,\n    config_id: str,\n) -> network_management_v1.VpcFlowLogsConfig:\n    client = network_management_v1.VpcFlowLogsServiceClient()\n    parent = f\"projects/{project_id}/locations/global\"\n    subnet = f\"projects/{project_id}/regions/{region}/subnetworks/{subnet_name}\"\n\n    operation = client.create_vpc_flow_logs_config(\n        parent=parent,\n        vpc_flow_logs_config_id=config_id,\n        vpc_flow_logs_config=network_management_v1.VpcFlowLogsConfig(\n            subnet=subnet,\n            aggregation_interval=(\n                network_management_v1.VpcFlowLogsConfig.AggregationInterval.INTERVAL_10_MIN\n            ),\n            flow_sampling=0.7,\n            metadata=(\n                network_management_v1.VpcFlowLogsConfig.Metadata.INCLUDE_ALL_METADATA\n            ),\n        ),\n    )\n    return operation.result(timeout=300)\n\n\nconfig = create_subnet_flow_logs_config(\n    project_id=\"my-project\",\n    region=\"us-central1\",\n    subnet_name=\"app-subnet\",\n    config_id=\"app-subnet-flow-logs\",\n)\nprint(config.name)\n```\n\nSet exactly one target resource in the config:\n\n- `subnet`\n- `network`\n- `interconnect_attachment`\n- `vpn_tunnel`\n\n### Update and inspect flow logs configs\n\n```python\nfrom google.cloud import network_management_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = network_management_v1.VpcFlowLogsServiceClient()\nparent = \"projects/my-project/locations/global\"\nsubnet = \"projects/my-project/regions/us-central1/subnetworks/app-subnet\"\nconfig_name = client.vpc_flow_logs_config_path(\n    \"my-project\",\n    \"global\",\n    \"app-subnet-flow-logs\",\n)\n\nupdate_operation = client.update_vpc_flow_logs_config(\n    vpc_flow_logs_config=network_management_v1.VpcFlowLogsConfig(\n        name=config_name,\n        subnet=subnet,\n        aggregation_interval=(\n            network_management_v1.VpcFlowLogsConfig.AggregationInterval.INTERVAL_5_SEC\n        ),\n        flow_sampling=1.0,\n        metadata=(\n            network_management_v1.VpcFlowLogsConfig.Metadata.EXCLUDE_ALL_METADATA\n        ),\n    ),\n    update_mask=FieldMask(\n        paths=[\"aggregation_interval\", \"flow_sampling\", \"metadata\"]\n    ),\n)\nupdated = update_operation.result(timeout=300)\nprint(updated.aggregation_interval, updated.flow_sampling)\n\nfor config in client.list_vpc_flow_logs_configs(parent=parent):\n    print(config.name)\n\nloaded = client.get_vpc_flow_logs_config(name=config_name)\nprint(loaded.name)\n```\n\n### Show the effective flow logs configs for a resource\n\nNetwork Management API-managed configs do not toggle the older Compute Engine subnet `enableFlowLogs` flag. Use `show_effective_flow_logs_configs()` when you need to see which configs actually apply to a subnet, network, interconnect attachment, or VPN tunnel.\n\n```python\nfrom google.cloud import network_management_v1\n\nclient = network_management_v1.VpcFlowLogsServiceClient()\n\nrequest = network_management_v1.ShowEffectiveFlowLogsConfigsRequest(\n    parent=\"projects/my-project/locations/global\",\n    resource=\"projects/my-project/regions/us-central1/subnetworks/app-subnet\",\n)\n\nfor effective in client.show_effective_flow_logs_configs(request=request):\n    print(effective)\n```\n\n## Organization-Level Flow Logs\n\nIf you manage VPC Flow Logs centrally, use `OrganizationVpcFlowLogsServiceClient` with an organization parent such as `organizations/123456789/locations/global`. The org-level service supports the same general create, list, get, update, and delete pattern as the project-level service, plus organization-scoped settings such as `cross_project_metadata`.\n\nThe permissions are different from project-level configs. Google documents `roles/networkmanagement.admin` as the role that can create, update, and delete VPC Flow Logs configs at the relevant scope.\n\n## Debug Logging\n\nThe package supports environment-based structured logging through the Google client libraries:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google.cloud.network_management_v1\"\n```\n\nUse this only in controlled environments; Google notes that client-library debug logging may include sensitive information.\n\n## Common Pitfalls\n\n- Import the module as `from google.cloud import network_management_v1`; the package name and import path are different.\n- Connectivity Tests and VPC Flow Logs configs are created under `locations/global`, even if the resource you are testing or configuring lives in a region.\n- Connectivity test results are only as specific as the endpoints you provide. In GCP or Shared VPC environments, include `project_id` and the full `network` URI instead of only an IP address.\n- `create_connectivity_test()`, `rerun_connectivity_test()`, `create_vpc_flow_logs_config()`, and `update_vpc_flow_logs_config()` are long-running operations. Wait for `result()` before reading the returned resource.\n- `VpcFlowLogsConfig` target resources are a oneof. Set only one of `network`, `subnet`, `interconnect_attachment`, or `vpn_tunnel`.\n- For project-level flow logs configs, `cross_project_metadata` is not valid. Google documents that field as organization-level only.\n- Creating or updating a VPC Flow Logs config with the same effective settings as an existing config on the same target resource fails, even if the config name or description differs.\n- If a connectivity test comes back `AMBIGUOUS` or `UNDETERMINED`, check whether the endpoint definition is incomplete, the referenced resource is unsupported, or the caller lacks permissions to inspect part of the path.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/google-cloud-network-management/\n- Google Cloud Python package reference: https://cloud.google.com/python/docs/reference/networkmanagement/latest\n- `ReachabilityServiceClient` reference: https://cloud.google.com/python/docs/reference/networkmanagement/latest/google.cloud.network_management_v1.services.reachability_service.ReachabilityServiceClient\n- `VpcFlowLogsServiceClient` reference: https://cloud.google.com/python/docs/reference/networkmanagement/latest/google.cloud.network_management_v1.services.vpc_flow_logs_service.VpcFlowLogsServiceClient\n- Connectivity Tests overview: https://cloud.google.com/network-intelligence-center/docs/connectivity-tests/concepts/overview\n- Connectivity Tests how-to: https://cloud.google.com/network-intelligence-center/docs/connectivity-tests/how-to/running-connectivity-tests\n- VPC Flow Logs config overview: https://cloud.google.com/vpc/docs/network-management-api\n- VPC Flow Logs config how-to: https://cloud.google.com/vpc/docs/using-flow-logs\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n"
  },
  {
    "path": "content/google/docs/network-security/python/DOC.md",
    "content": "---\nname: network-security\ndescription: \"Google Cloud Network Security Python client for address groups and TLS policy resources in the Network Security API\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,google-cloud,network-security,tls,mtls,address-groups,python\"\n---\n\n# google-cloud-network-security Python Package Guide\n\n## What This Package Is\n\n`google-cloud-network-security` is the official Google Cloud Python client for the Network Security API.\n\nFor Python automation, the package is split across a few service clients:\n\n- `network_security_v1.NetworkSecurityClient` for resources such as `ClientTlsPolicy`, `ServerTlsPolicy`, and `AuthorizationPolicy`\n- `network_security_v1.AddressGroupServiceClient` for project-scoped address groups\n- `network_security_v1.OrganizationAddressGroupServiceClient` for organization-scoped address groups\n\nThese resources are configuration objects. Creating them in this package does not attach them to a backend service, target HTTPS proxy, or firewall policy by itself.\n\n## Version Note\n\nThis guide covers package version `0.11.0`, which PyPI lists for `google-cloud-network-security`.\n\nGoogle's live Python reference currently has some Network Security class pages that still render `0.10.0` in the heading even under the `latest` selector. The resource names and method families below are taken from the current official reference docs, but you should expect the docs site to lag the PyPI patch version slightly.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-network-security==0.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-network-security==0.11.0\"\npoetry add \"google-cloud-network-security==0.11.0\"\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nBefore calling the API:\n\n1. Select the Google Cloud project or organization that owns the Network Security resources.\n2. Enable billing for the project.\n3. Enable the Network Security API.\n4. Configure Application Default Credentials (ADC).\n\nEnable the API:\n\n```bash\ngcloud services enable networksecurity.googleapis.com\n```\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nThe examples below use `global`, which matches the common location pattern in the Network Security resource names documented by Google.\n\n## Initialize Clients\n\nUse ADC unless you have a concrete reason to inject credentials yourself:\n\n```python\nimport os\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nnetwork_client = network_security_v1.NetworkSecurityClient()\naddress_group_client = network_security_v1.AddressGroupServiceClient()\n```\n\nExplicit service-account credentials also work:\n\n```python\nimport os\n\nfrom google.cloud import network_security_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nnetwork_client = network_security_v1.NetworkSecurityClient(credentials=credentials)\naddress_group_client = network_security_v1.AddressGroupServiceClient(\n    credentials=credentials\n)\n```\n\nIf your environment requires a custom endpoint, pass `client_options`:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import network_security_v1\n\nendpoint = os.environ[\"GOOGLE_API_ENDPOINT\"]\n\nnetwork_client = network_security_v1.NetworkSecurityClient(\n    client_options=ClientOptions(api_endpoint=endpoint)\n)\n```\n\n## Core Workflows\n\n### List authorization policies\n\nUse the main Network Security client for policy resources:\n\n```python\nimport os\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = network_security_v1.NetworkSecurityClient()\n\nfor policy in client.list_authorization_policies(parent=parent):\n    print(policy.name)\n```\n\n`AuthorizationPolicy` controls how a server authorizes incoming connections, but the policy does not affect traffic until it is attached to a target HTTPS proxy or endpoint config selector.\n\n### Create an address group and add items\n\nAddress groups are managed by `AddressGroupServiceClient`, not by `NetworkSecurityClient`.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = network_security_v1.AddressGroupServiceClient()\n\noperation = client.create_address_group(\n    request=network_security_v1.CreateAddressGroupRequest(\n        parent=parent,\n        address_group_id=\"corp-ipv4\",\n        address_group=network_security_v1.AddressGroup(\n            description=\"Corporate office egress ranges\",\n            type_=network_security_v1.AddressGroup.Type.IPV4,\n            capacity=100,\n            items=[\"203.0.113.0/24\"],\n            labels={\"env\": \"prod\"},\n        ),\n        request_id=str(uuid.uuid4()),\n    )\n)\n\naddress_group = operation.result(timeout=600)\nprint(address_group.name)\n```\n\nAdd more items later:\n\n```python\nimport uuid\n\nfrom google.cloud import network_security_v1\n\nclient = network_security_v1.AddressGroupServiceClient()\n\noperation = client.add_address_group_items(\n    request=network_security_v1.AddAddressGroupItemsRequest(\n        address_group=\"projects/your-project-id/locations/global/addressGroups/corp-ipv4\",\n        items=[\"198.51.100.0/24\", \"192.0.2.15\"],\n        request_id=str(uuid.uuid4()),\n    )\n)\n\nupdated = operation.result(timeout=600)\nprint(updated.items)\n```\n\nList address groups in a project:\n\n```python\nimport os\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = network_security_v1.AddressGroupServiceClient()\n\nfor group in client.list_address_groups(parent=parent):\n    print(group.name, group.type_, group.capacity)\n```\n\n### See what still references an address group\n\nThis is useful before delete or migration work:\n\n```python\nfrom google.cloud import network_security_v1\n\nclient = network_security_v1.AddressGroupServiceClient()\n\nfor ref in client.list_address_group_references(\n    address_group=\"projects/your-project-id/locations/global/addressGroups/corp-ipv4\"\n):\n    print(ref)\n```\n\n### Create a client TLS policy for backend TLS\n\n`ClientTlsPolicy` defines how a client authenticates connections to backends. The resource itself does nothing until it is attached to a backend service.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = network_security_v1.NetworkSecurityClient()\n\noperation = client.create_client_tls_policy(\n    request={\n        \"parent\": parent,\n        \"client_tls_policy_id\": \"backend-tls\",\n        \"client_tls_policy\": {\n            \"description\": \"Validate backend certificates for secure.example.internal\",\n            \"sni\": \"secure.example.internal\",\n            \"server_validation_ca\": [\n                {\"ca_cert_path\": \"/etc/ssl/certs/backend-root-ca.pem\"}\n            ],\n            \"labels\": {\"env\": \"prod\"},\n        },\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\npolicy = operation.result(timeout=600)\nprint(policy.name)\n```\n\nIf `server_validation_ca` is empty, the client does not validate the backend server certificate.\n\n### Create a server TLS policy\n\n`ServerTlsPolicy` defines how a server authenticates incoming connections. The resource does not affect traffic until it is attached to a target HTTPS proxy or endpoint config selector.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import network_security_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = network_security_v1.NetworkSecurityClient()\n\noperation = client.create_server_tls_policy(\n    request={\n        \"parent\": parent,\n        \"server_tls_policy_id\": \"frontend-tls\",\n        \"server_tls_policy\": {\n            \"description\": \"Terminate TLS for the frontend proxy\",\n            \"server_certificate\": {\n                \"local_filepath\": {\n                    \"certificate_path\": \"/etc/tls/tls.crt\",\n                    \"private_key_path\": \"/etc/tls/tls.key\",\n                }\n            },\n            \"labels\": {\"env\": \"prod\"},\n        },\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\npolicy = operation.result(timeout=600)\nprint(policy.name)\n```\n\nFor mixed plaintext and mTLS rollouts, the resource supports `allow_open` and `mtls_policy`, but `allow_open` cannot be combined with `server_certificate`.\n\n## Common Pitfalls\n\n- Use the right client for the resource. Address groups are managed by `AddressGroupServiceClient`; TLS and authorization policy resources use `NetworkSecurityClient`.\n- Do not assume these resources are active immediately after creation. They are configuration objects that still need to be attached by the relevant Google Cloud product surface.\n- Treat create, update, add-items, clone-items, and delete calls as long-running operations and wait on `operation.result()`.\n- Set a `request_id` on mutating calls when you may retry. The API documents request deduplication behavior for at least 60 minutes.\n- `AddressGroup.capacity` is required at create time. Plan capacity before the group is used broadly in policy references.\n- `ClientTlsPolicy.server_validation_ca` matters. If you omit it, the client does not validate the backend server certificate.\n- `ServerTlsPolicy.allow_open` is a permissive migration mode. Do not combine it with `server_certificate`; the reference docs explicitly mark that combination unsupported.\n- Listing address-group references before deletion can save time. Policies or firewall configuration that still point at the group will block cleanup.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-network-security/\n- Python client overview: https://cloud.google.com/python/docs/reference/networksecurity/latest\n- Network Security client reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1.services.network_security\n- Address group service reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1.services.address_group_service\n- AddressGroup type reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1.types.AddressGroup\n- AddAddressGroupItemsRequest reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1.types.AddAddressGroupItemsRequest\n- ServerTlsPolicy type reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1.types.ServerTlsPolicy\n- ClientTlsPolicy type reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1alpha1.types.ClientTlsPolicy\n- ValidationCA type reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1alpha1.types.ValidationCA\n- CertificateProvider type reference: https://docs.cloud.google.com/python/docs/reference/networksecurity/latest/google.cloud.network_security_v1alpha1.types.CertificateProvider\n"
  },
  {
    "path": "content/google/docs/network-services/python/DOC.md",
    "content": "---\nname: network-services\ndescription: \"Google Cloud Network Services Python client for gateways, HTTP routes, meshes, and Wasm plugins\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,google-cloud,network-services,networking,load-balancing,mesh,wasm,python\"\n---\n\n# google-cloud-network-services Python Package Guide\n\nUse `google-cloud-network-services` for Python code that manages Google Cloud Network Services resources such as gateways, routes, meshes, service bindings, and Wasm plugins. The main entry point is `google.cloud.network_services_v1.NetworkServicesClient`.\n\n## Version Note\n\nThis guide covers package version `0.8.0`, which PyPI lists as the current release as of `2026-03-13`.\n\nGoogle's Python reference pages for this library currently lag behind PyPI:\n\n- the PyPI package page lists `0.8.0`\n- the live `latest` reference pages for `NetworkServicesClient`, `HttpRoute`, and `WasmPlugin` still render `0.7.0`\n- the `Gateway` type page still renders `0.6.0`\n\nThe examples below stay on the documented `network_services_v1` client methods and message fields shown in the live reference docs.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-network-services==0.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-network-services==0.8.0\"\npoetry add \"google-cloud-network-services==0.8.0\"\n```\n\nPyPI currently declares Python `>=3.7`.\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nBefore calling the API:\n\n1. Enable the Network Services API for the target project.\n2. Make sure the credential can manage Network Services resources in that project.\n3. Decide which location your resources use. Gateways are location-scoped. Several route and Wasm plugin examples in the reference docs use `global`.\n\nEnable the API:\n\n```bash\ngcloud services enable networkservices.googleapis.com\n```\n\nTypical local development setup with Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nIf you must use a service-account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\n```\n\nGoogle's ADC setup docs recommend attached service accounts or service account impersonation before downloading long-lived key files.\n\n## Initialize The Client\n\nBasic client initialization with ADC:\n\n```python\nimport os\n\nfrom google.cloud import network_services_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\n\nclient = network_services_v1.NetworkServicesClient()\n```\n\nExplicit service-account file:\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient.from_service_account_json(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nCustom endpoint override:\n\n```python\nimport os\n\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient(\n    client_options=ClientOptions(api_endpoint=os.environ[\"GOOGLE_API_ENDPOINT\"])\n)\n```\n\nThe generated client supports `client_options.api_endpoint` if you need to target a non-default endpoint.\n\n## Resource Names\n\nUse fully qualified names instead of assembling strings ad hoc:\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\n\ngateway_name = client.gateway_path(\"my-project\", \"global\", \"my-gateway\")\nhttp_route_name = client.http_route_path(\"my-project\", \"global\", \"my-route\")\nwasm_plugin_name = client.wasm_plugin_path(\"my-project\", \"global\", \"header-normalizer\")\nparent = client.common_location_path(\"my-project\", \"global\")\n```\n\nThat keeps request code consistent with the documented patterns:\n\n- gateway parent: `projects/{project}/locations/{location}`\n- gateway name: `projects/{project}/locations/{location}/gateways/{gateway}`\n- HTTP route name: `projects/{project}/locations/global/httpRoutes/{http_route}`\n- Wasm plugin name: `projects/{project}/locations/global/wasmPlugins/{wasm_plugin}`\n\n## Core Usage\n\n### List gateways\n\nList methods return pagers, so normal iteration handles pagination:\n\n```python\nimport os\n\nfrom google.cloud import network_services_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\n\nclient = network_services_v1.NetworkServicesClient()\nparent = client.common_location_path(project_id, location)\n\nfor gateway in client.list_gateways(parent=parent):\n    print(gateway.name, gateway.type_.name, list(gateway.ports))\n```\n\n### Create a gateway\n\n`create_gateway()` is a long-running operation. Wait on `.result()` before using the resource.\n\n```python\nimport os\n\nfrom google.cloud import network_services_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\n\nclient = network_services_v1.NetworkServicesClient()\nparent = client.common_location_path(project_id, location)\n\noperation = client.create_gateway(\n    parent=parent,\n    gateway_id=\"mesh-gateway\",\n    gateway=network_services_v1.Gateway(\n        description=\"Gateway for mesh traffic\",\n        type_=network_services_v1.Gateway.Type.OPEN_MESH,\n        ports=[80, 443],\n        addresses=[\"10.0.0.15\"],\n        scope=\"prod-mesh\",\n        labels={\"env\": \"dev\"},\n    ),\n)\n\ngateway = operation.result(timeout=600)\nprint(gateway.name)\n```\n\n### Get and update a gateway\n\nUse an explicit field mask when updating mutable fields.\n\n```python\nfrom google.cloud import network_services_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = network_services_v1.NetworkServicesClient()\ngateway_name = client.gateway_path(\"my-project\", \"global\", \"mesh-gateway\")\n\ngateway = client.get_gateway(name=gateway_name)\nprint(gateway.description, gateway.labels)\n\noperation = client.update_gateway(\n    gateway=network_services_v1.Gateway(\n        name=gateway_name,\n        description=\"Updated mesh gateway description\",\n        labels={\"env\": \"prod\", \"team\": \"networking\"},\n    ),\n    update_mask=FieldMask(paths=[\"description\", \"labels\"]),\n)\n\nupdated_gateway = operation.result(timeout=600)\nprint(updated_gateway.labels)\n```\n\n### Delete a gateway\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\ngateway_name = client.gateway_path(\"my-project\", \"global\", \"mesh-gateway\")\n\noperation = client.delete_gateway(name=gateway_name)\noperation.result(timeout=600)\n```\n\n### List and inspect HTTP routes\n\nThe reference docs use the global location for HTTP routes. Listing returns route resources directly; `get_http_route()` fetches one by resource name.\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\nparent = client.common_location_path(\"my-project\", \"global\")\n\nfor route in client.list_http_routes(parent=parent):\n    print(route.name)\n    print(\"hostnames:\", list(route.hostnames))\n    print(\"gateways:\", list(route.gateways))\n\nroute_name = client.http_route_path(\"my-project\", \"global\", \"my-route\")\nroute = client.get_http_route(name=route_name)\nprint(route.name, list(route.hostnames))\n```\n\n### Create and inspect a Wasm plugin\n\nWasm plugin creation is also a long-running operation. The `versions` map holds one or more named plugin versions, and `main_version_id` selects the default version.\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\nparent = client.common_location_path(\"my-project\", \"global\")\n\noperation = client.create_wasm_plugin(\n    parent=parent,\n    wasm_plugin_id=\"header-normalizer\",\n    wasm_plugin=network_services_v1.WasmPlugin(\n        description=\"Normalize request headers before routing\",\n        main_version_id=\"v1\",\n        versions={\n            \"v1\": network_services_v1.WasmPlugin.VersionDetails(\n                image_uri=(\n                    \"us-docker.pkg.dev/my-project/wasm-plugins/\"\n                    \"header-normalizer:1.0.0\"\n                ),\n                plugin_config_data=b'{\\\"header\\\":\\\"x-trace-id\\\"}',\n            )\n        },\n        labels={\"env\": \"dev\"},\n    ),\n)\n\nplugin = operation.result(timeout=600)\nprint(plugin.name)\n```\n\nFetch the full plugin definition, including version details:\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\nplugin_name = client.wasm_plugin_path(\"my-project\", \"global\", \"header-normalizer\")\n\nplugin = client.get_wasm_plugin(\n    request=network_services_v1.GetWasmPluginRequest(\n        name=plugin_name,\n        view=network_services_v1.WasmPluginView.WASM_PLUGIN_VIEW_FULL,\n    )\n)\n\nprint(plugin.main_version_id)\nprint(sorted(plugin.versions.keys()))\n```\n\nList plugin versions:\n\n```python\nfrom google.cloud import network_services_v1\n\nclient = network_services_v1.NetworkServicesClient()\nplugin_name = client.wasm_plugin_path(\"my-project\", \"global\", \"header-normalizer\")\n\nfor version in client.list_wasm_plugin_versions(parent=plugin_name):\n    print(version.name)\n```\n\n## Common Pitfalls\n\n- Treat `create_*`, `update_*`, and `delete_*` calls as long-running operations. Read the returned resource only after `operation.result()` completes.\n- Keep location explicit. Gateways are location-scoped, while the reference docs for HTTP routes and Wasm plugins use `projects/{project}/locations/global/...`.\n- Build resource names with helper methods such as `gateway_path()` and `http_route_path()` instead of manual string concatenation.\n- `Gateway` creation needs the resource `type_` and at least one listening port. The `SECURE_WEB_GATEWAY` variant has additional constraints documented on the `Gateway` type, including a single port and specific networking and TLS fields.\n- `HttpRoute.hostnames` must stay unique within the mesh or gateway scope where the route is attached.\n- `get_wasm_plugin()` does not return full version details unless you request `WASM_PLUGIN_VIEW_FULL`.\n"
  },
  {
    "path": "content/google/docs/notebooks/javascript/DOC.md",
    "content": "---\nname: notebooks\ndescription: \"Google Cloud Notebooks Node.js client for classic notebook instances, managed runtimes, and Workbench instances\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,notebooks,vertex-ai-workbench,jupyter,javascript,nodejs\"\n---\n\n# `@google-cloud/notebooks` JavaScript Package Guide\n\nUse `@google-cloud/notebooks` when your Node.js code needs to manage Google Cloud notebook resources instead of opening the notebook UI manually.\n\nThis package exposes multiple client surfaces under one npm package:\n\n- `v1.NotebookServiceClient` for classic notebook instances and related execution and schedule resources\n- `v1.ManagedNotebookServiceClient` for managed notebook runtimes\n- `v2.NotebookServiceClient` for Workbench notebook instances\n\n## Golden Rule\n\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Pick the client that matches the resource model you are managing.\n- Build resource names explicitly as `projects/{project}/locations/{location}/...`.\n- Treat create, start, stop, and delete calls as long-running operations and wait for `operation.promise()`.\n- Keep classic `v1`, managed-runtime `v1`, and Workbench `v2` flows separate in your code.\n\nThis guide covers `4.2.1`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/notebooks@4.2.1\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials.\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project already exists.\n2. Billing and the relevant Notebooks or Workbench APIs are enabled for that project.\n3. The calling identity can view or manage notebook resources in the target location.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v1, v2} = require('@google-cloud/notebooks');\n\nconst classicClient = new v1.NotebookServiceClient();\nconst runtimeClient = new v1.ManagedNotebookServiceClient();\nconst workbenchClient = new v2.NotebookServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1, v2} from '@google-cloud/notebooks';\n\nconst classicClient = new v1.NotebookServiceClient();\nconst runtimeClient = new v1.ManagedNotebookServiceClient();\nconst workbenchClient = new v2.NotebookServiceClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.NotebookServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Resource Names\n\nBuild names directly in code so you do not mix resource types:\n\n- parent location: `projects/PROJECT_ID/locations/LOCATION`\n- classic instance: `projects/PROJECT_ID/locations/LOCATION/instances/INSTANCE_ID`\n- managed runtime: `projects/PROJECT_ID/locations/LOCATION/runtimes/RUNTIME_ID`\n- Workbench instance: `projects/PROJECT_ID/locations/LOCATION/instances/INSTANCE_ID`\n\nUse `parent` when listing or creating resources and full `name` values when getting, starting, stopping, or deleting them.\n\n## Choose The Right Client\n\n### `v1.NotebookServiceClient`\n\nUse this for classic notebook instances and related execution or schedule workflows.\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.NotebookServiceClient();\n\nasync function listClassicInstances(projectId, location) {\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  for await (const instance of client.listInstancesAsync({parent})) {\n    console.log(instance.name, instance.state);\n  }\n}\n```\n\nCommon operations on this surface include `listInstancesAsync()`, `getInstance()`, `createInstance()`, `deleteInstance()`, `startInstance()`, `stopInstance()`, plus execution and schedule management methods.\n\n### `v1.ManagedNotebookServiceClient`\n\nUse this for managed notebook runtimes.\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.ManagedNotebookServiceClient();\n\nasync function listRuntimes(projectId, location) {\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  for await (const runtime of client.listRuntimesAsync({parent})) {\n    console.log(runtime.name, runtime.healthState);\n  }\n}\n```\n\nCommon operations on this surface include `listRuntimesAsync()`, `getRuntime()`, `createRuntime()`, `deleteRuntime()`, `startRuntime()`, and `stopRuntime()`.\n\n### `v2.NotebookServiceClient`\n\nUse this for Workbench notebook instances.\n\n```javascript\nconst {v2} = require('@google-cloud/notebooks');\n\nconst client = new v2.NotebookServiceClient();\n\nasync function listWorkbenchInstances(projectId, location) {\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  for await (const instance of client.listInstancesAsync({parent})) {\n    console.log(instance.name, instance.state);\n  }\n}\n```\n\nUse this surface when you are managing Workbench instances instead of classic v1 notebook instances.\n\n## Core Workflows\n\n### Get One Instance By Resource Name\n\nUse the full resource name, not only the short instance ID.\n\n```javascript\nconst {v2} = require('@google-cloud/notebooks');\n\nconst client = new v2.NotebookServiceClient();\n\nasync function getWorkbenchInstance(projectId, location, instanceId) {\n  const name = `projects/${projectId}/locations/${location}/instances/${instanceId}`;\n  const [instance] = await client.getInstance({name});\n  return instance;\n}\n```\n\n### Start And Stop A Classic Instance\n\nMutating methods return a long-running operation. Wait for it before reading the resource again.\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.NotebookServiceClient();\n\nasync function restartClassicInstance(projectId, location, instanceId) {\n  const name = `projects/${projectId}/locations/${location}/instances/${instanceId}`;\n\n  const [stopOperation] = await client.stopInstance({name});\n  await stopOperation.promise();\n\n  const [startOperation] = await client.startInstance({name});\n  await startOperation.promise();\n}\n```\n\n### Create A Classic Instance\n\nFor classic `v1`, send `parent`, `instanceId`, and an `instance` object, then wait for the operation to finish.\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.NotebookServiceClient();\n\nasync function createClassicInstance(projectId, location) {\n  const [operation] = await client.createInstance({\n    parent: `projects/${projectId}/locations/${location}`,\n    instanceId: 'my-notebook',\n    instance: {\n      vmImage: {\n        imageName: 'tf-latest-cpu',\n        project: 'deeplearning-platform-release',\n      },\n      machineType: 'e2-standard-4',\n    },\n  });\n\n  const [instance] = await operation.promise();\n  return instance;\n}\n```\n\nIf you are creating Workbench resources with `v2`, use the `v2.Instance` schema instead of reusing the classic `v1` instance shape.\n\n### Read One Managed Runtime\n\nManaged runtimes are a different resource type, so use `ManagedNotebookServiceClient` and a `/runtimes/` name.\n\n```javascript\nconst {v1} = require('@google-cloud/notebooks');\n\nconst client = new v1.ManagedNotebookServiceClient();\n\nasync function getRuntime(projectId, location, runtimeId) {\n  const name = `projects/${projectId}/locations/${location}/runtimes/${runtimeId}`;\n  const [runtime] = await client.getRuntime({name});\n  return runtime;\n}\n```\n\n## Operations And Pagination\n\n- Prefer async iterators such as `listInstancesAsync()` and `listRuntimesAsync()` so the client handles pagination for you.\n- Create, delete, start, and stop calls are long-running operations. Call `await operation.promise()` before assuming the change completed.\n- Use request objects for create and update flows. They are clearer than relying on positional or partially flattened arguments.\n- Reuse client instances in long-lived processes instead of creating a new client for every request.\n\n## Common Pitfalls\n\n- The npm package is `@google-cloud/notebooks`, but the main clients live under versioned namespaces like `v1` and `v2`.\n- Do not mix classic notebook instances, managed runtimes, and Workbench instances in the same request flow.\n- `parent` is always `projects/{project}/locations/{location}`. Individual operations usually want a full `name`.\n- Managed runtime resource names end in `/runtimes/{runtime}`; notebook instance resource names end in `/instances/{instance}`.\n- Local Google Cloud auth for client libraries uses `gcloud auth application-default login`, not only `gcloud auth login`.\n- Creation and lifecycle methods are asynchronous. If you skip `operation.promise()`, follow-up reads can race with the control plane.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/notebooks` `4.2.1`.\n- The package includes multiple service surfaces under one npm package. Choose the namespace and client class first, then write resource-specific code around that surface.\n- Workbench `v2` instance creation uses a different schema than classic `v1` instance creation, so do not copy a classic `instance` payload into `v2` code.\n\n## Official Sources\n\n- Node.js client reference root: `https://cloud.google.com/nodejs/docs/reference/notebooks/latest`\n- Application Default Credentials overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC search order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/notebooks`\n"
  },
  {
    "path": "content/google/docs/notebooks/python/DOC.md",
    "content": "---\nname: notebooks\ndescription: \"Google Cloud Notebooks Python client library for notebook instances, managed runtimes, and Workbench instances\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,notebooks,jupyter,workbench,ml\"\n---\n\n# Google Cloud Notebooks Python Client\n\n## Golden Rule\n\nUse `google-cloud-notebooks` for Google Cloud notebook instance automation, authenticate with Application Default Credentials (ADC), and pick the client surface that matches the resource you are managing:\n\n- `notebooks_v1.NotebookServiceClient`: classic AI Platform notebook instances, executions, schedules\n- `notebooks_v1.ManagedNotebookServiceClient`: managed notebook runtimes\n- `notebooks_v2.NotebookServiceClient`: Workbench notebook instances\n\nAs of March 12, 2026, PyPI lists `google-cloud-notebooks 1.15.0`. The Google-hosted `latest` reference pages are current enough to use, but some generated subpages still display older minor versions, so pin package versions from PyPI rather than from the page chrome.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-notebooks==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-notebooks==1.15.0\"\npoetry add \"google-cloud-notebooks==1.15.0\"\n```\n\n## Authentication And Project Setup\n\nThe official quick start says you must:\n\n1. Select or create a Google Cloud project.\n2. Enable billing for the project.\n3. Enable AI Platform Notebooks for the project.\n4. Set up authentication.\n\nUse ADC so the same code works locally and on Google Cloud:\n\n```bash\ngcloud auth application-default login\n```\n\nFor production on Google Cloud, prefer an attached service account with the least-privileged IAM roles instead of distributing service account keys.\n\nIf you must use a credentials file explicitly, set:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/credentials.json\"\n```\n\n## Choose The Right Client\n\n### `notebooks_v1.NotebookServiceClient`\n\nUse this for classic notebook instances and related resources such as executions and schedules.\n\n```python\nfrom google.cloud import notebooks_v1\n\nclient = notebooks_v1.NotebookServiceClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nfor instance in client.list_instances(parent=parent):\n    print(instance.name, instance.state.name)\n```\n\nKey operations:\n\n- `list_instances`, `get_instance`\n- `create_instance`, `delete_instance`\n- `start_instance`, `stop_instance`\n- `create_execution`, `list_executions`\n- `create_schedule`, `list_schedules`\n\nThe generated client docs require `parent` in the form `projects/{project_id}/locations/{location}`. `create_instance` returns a long-running operation.\n\n### `notebooks_v1.ManagedNotebookServiceClient`\n\nUse this for managed notebook runtimes.\n\n```python\nfrom google.cloud import notebooks_v1\n\nclient = notebooks_v1.ManagedNotebookServiceClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nfor runtime in client.list_runtimes(parent=parent):\n    print(runtime.name, runtime.health_state.name)\n```\n\nUseful operations:\n\n- `list_runtimes`, `get_runtime`\n- `create_runtime`, `delete_runtime`\n- `start_runtime`, `stop_runtime`\n- IAM helpers such as `get_iam_policy` and `set_iam_policy`\n\nThe generated docs explicitly note that `get_runtime` expects a regional location rather than a zonal endpoint.\n\n### `notebooks_v2.NotebookServiceClient`\n\nUse this for Workbench notebook instances.\n\n```python\nfrom google.cloud import notebooks_v2\n\nclient = notebooks_v2.NotebookServiceClient()\nparent = \"projects/my-project/locations/us-central1\"\n\nfor instance in client.list_instances(parent=parent):\n    print(instance.name, instance.state.name)\n```\n\nUseful operations:\n\n- `list_instances`, `get_instance`\n- `create_instance`, `delete_instance`\n- `check_instance_upgradability`\n\nThe v2 generated sample shows `Instance.gce_setup.vm_image.name` and `Instance.gce_setup.vm_image.project` when building a creation request, which is a good hint that Workbench instance creation uses a different schema than classic v1 instances.\n\n## Common Request Patterns\n\n### Get one instance by resource name\n\n```python\nfrom google.cloud import notebooks_v2\n\nclient = notebooks_v2.NotebookServiceClient()\nname = \"projects/my-project/locations/us-central1/instances/my-instance\"\n\ninstance = client.get_instance(name=name)\nprint(instance.name)\n```\n\n### Start and stop a classic v1 instance\n\n```python\nfrom google.cloud import notebooks_v1\n\nclient = notebooks_v1.NotebookServiceClient()\nname = \"projects/my-project/locations/us-central1/instances/my-instance\"\n\nclient.start_instance(name=name).result()\nclient.stop_instance(name=name).result()\n```\n\n### Create a classic v1 instance\n\nThe generated docs show the minimum shape: set a VM image, set a machine type, send `parent`, `instance_id`, and `instance`, then wait on the operation.\n\n```python\nfrom google.cloud import notebooks_v1\n\nclient = notebooks_v1.NotebookServiceClient()\n\ninstance = notebooks_v1.Instance()\ninstance.vm_image.image_name = \"tf-latest-cpu\"\ninstance.vm_image.project = \"deeplearning-platform-release\"\ninstance.machine_type = \"e2-standard-4\"\n\noperation = client.create_instance(\n    parent=\"projects/my-project/locations/us-central1\",\n    instance_id=\"my-notebook\",\n    instance=instance,\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\n```\n\n### Create a managed runtime\n\n`create_runtime` is also a long-running operation. The request must include `parent`, `runtime_id`, and a populated `Runtime`.\n\n```python\nfrom google.cloud import notebooks_v1\n\nclient = notebooks_v1.ManagedNotebookServiceClient()\n\nruntime = notebooks_v1.Runtime()\n\noperation = client.create_runtime(\n    parent=\"projects/my-project/locations/us-central1\",\n    runtime_id=\"my-runtime\",\n    runtime=runtime,\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\n```\n\nIn real code, fill the required runtime configuration fields from the `Runtime` schema before sending the request.\n\n## Operations, Timeouts, And Endpoints\n\n- Most create, delete, start, and stop methods return `google.api_core.operation.Operation`. Call `.result()` and budget for long timeouts.\n- The generated samples repeatedly warn that you might need to specify a regional API endpoint with `client_options` for your location.\n- If you are looping over many resources, prefer pager-returning methods such as `list_instances` and `list_runtimes` instead of manually managing page tokens.\n- Use request objects when the method has many optional fields; flattened keyword arguments are convenient for small calls but easier to misuse in larger create/update flows.\n\n## Common Pitfalls\n\n- Do not mix the three service surfaces. `notebooks_v1.NotebookServiceClient`, `notebooks_v1.ManagedNotebookServiceClient`, and `notebooks_v2.NotebookServiceClient` manage different resource models.\n- Resource names are location-scoped. Build `parent` as `projects/{project}/locations/{location}` and full resource names as `projects/{project}/locations/{location}/instances/{instance}` or `.../runtimes/{runtime}`.\n- `get_runtime` in the managed-runtime client expects a regional location. Zonal resource naming and regional endpoints are easy to confuse.\n- Creation calls are not synchronous. Agents often forget to wait on the returned long-running operation before reading the new resource.\n- ADC and `gcloud auth login` are not the same thing. Local client-library auth should use `gcloud auth application-default login` when you want user credentials for ADC.\n- Prefer attached service accounts in Google Cloud environments. Service account keys are a fallback, not the default.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `1.15.0`, uploaded on January 15, 2026.\n- The official Google Cloud reference root still points at `latest`, but some generated package pages under that tree show older minor versions in their titles. Treat the reference tree as authoritative for API shapes, and PyPI as authoritative for `metadata.versions`.\n- PyPI says the package supports Python `>=3.7`, including `3.14`. If your project has already dropped Python 3.7 or 3.8, that is your application policy, not a library requirement from this package.\n"
  },
  {
    "path": "content/google/docs/optimization/python/DOC.md",
    "content": "---\nname: optimization\ndescription: \"Google Cloud Optimization Python client for Route Optimization API requests, validation-only solves, and batch jobs backed by Cloud Storage\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,route-optimization,fleet-routing,logistics,gcp,python\"\n---\n\n# Google Cloud Optimization Python Package Guide\n\n## Golden Rule\n\nUse the official `google-cloud-optimization` package with OAuth-based Google credentials.\n\n- Install: `google-cloud-optimization`\n- Import: `from google.cloud import optimization_v1`\n- Main client: `optimization_v1.FleetRoutingClient`\n- Main calls: `optimize_tours()` for interactive requests and `batch_optimize_tours()` for GCS-backed async jobs\n\nThe package name still says \"Cloud Optimization\", but the product docs and service endpoint are now under the Route Optimization API at `routeoptimization.googleapis.com`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-optimization==1.13.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-optimization==1.13.0\"\npoetry add \"google-cloud-optimization==1.13.0\"\n```\n\nPyPI currently lists Python `>=3.7`.\n\n## Authentication And Setup\n\nBefore you call the client:\n\n1. Create or choose a Google Cloud project.\n2. Enable billing for that project.\n3. Enable the Route Optimization API.\n4. Authenticate with OAuth-based credentials.\n\nApplication Default Credentials (ADC) are the normal path:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nThe API requires the OAuth scope `https://www.googleapis.com/auth/cloud-platform`.\n\nImportant IAM permissions:\n\n- `routeoptimization.locations.use` for `optimize_tours`\n- `routeoptimization.operations.create` for `batch_optimize_tours`\n\n## Initialize A Client\n\nWith ADC:\n\n```python\nimport os\n\nfrom google.cloud import optimization_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nparent = f\"projects/{project_id}\"\n\nclient = optimization_v1.FleetRoutingClient()\n```\n\nThe `parent` can be either:\n\n- `projects/PROJECT_ID`\n- `projects/PROJECT_ID/locations/LOCATION_ID`\n\nIf you omit the location, the service chooses a region automatically.\n\nExplicit credentials object:\n\n```python\nimport os\n\nfrom google.cloud import optimization_v1\nfrom google.oauth2 import service_account\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"],\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n\nclient = optimization_v1.FleetRoutingClient(credentials=credentials)\nparent = f\"projects/{project_id}\"\n```\n\n## Core Workflow\n\n### Solve A Small Request Synchronously\n\nFor a normal application request, build an `OptimizeToursRequest` and call `optimize_tours()`.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import optimization_v1\n\n\ndef ts(dt: datetime) -> dict:\n    return {\"seconds\": int(dt.astimezone(timezone.utc).timestamp())}\n\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nclient = optimization_v1.FleetRoutingClient()\nparent = f\"projects/{project_id}\"\n\nroute_start = datetime(2026, 3, 13, 15, 0, tzinfo=timezone.utc)\nroute_end = route_start + timedelta(hours=8)\n\nrequest = optimization_v1.OptimizeToursRequest(\n    parent=parent,\n    timeout={\"seconds\": 10},\n    model={\n        \"global_start_time\": ts(route_start),\n        \"global_end_time\": ts(route_end),\n        \"shipments\": [\n            {\n                \"label\": \"order-1001\",\n                \"pickups\": [\n                    {\n                        \"arrival_location\": {\n                            \"latitude\": 37.7955,\n                            \"longitude\": -122.3937,\n                        },\n                        \"duration\": {\"seconds\": 300},\n                        \"time_windows\": [\n                            {\n                                \"start_time\": ts(route_start + timedelta(minutes=15)),\n                                \"end_time\": ts(route_start + timedelta(hours=2)),\n                            }\n                        ],\n                    }\n                ],\n                \"deliveries\": [\n                    {\n                        \"arrival_location\": {\n                            \"latitude\": 37.7658,\n                            \"longitude\": -122.4036,\n                        },\n                        \"duration\": {\"seconds\": 300},\n                        \"time_windows\": [\n                            {\n                                \"start_time\": ts(route_start + timedelta(hours=1)),\n                                \"end_time\": ts(route_start + timedelta(hours=4)),\n                            }\n                        ],\n                    }\n                ],\n                \"penalty_cost\": 100.0,\n            }\n        ],\n        \"vehicles\": [\n            {\n                \"label\": \"van-1\",\n                \"start_location\": {\n                    \"latitude\": 37.7749,\n                    \"longitude\": -122.4194,\n                },\n                \"end_location\": {\n                    \"latitude\": 37.7749,\n                    \"longitude\": -122.4194,\n                },\n                \"cost_per_hour\": 27.0,\n                \"start_time_windows\": [\n                    {\n                        \"start_time\": ts(route_start),\n                        \"end_time\": ts(route_start + timedelta(minutes=30)),\n                    }\n                ],\n                \"end_time_windows\": [\n                    {\n                        \"start_time\": ts(route_start + timedelta(hours=3)),\n                        \"end_time\": ts(route_end),\n                    }\n                ],\n            }\n        ],\n    },\n    consider_road_traffic=True,\n    populate_transition_polylines=True,\n)\n\nresponse = client.optimize_tours(request=request)\n\nprint(\"total_cost:\", response.metrics.total_cost)\n\nfor route_index, route in enumerate(response.routes):\n    print(f\"route {route_index}\")\n    for visit in route.visits:\n        visit_kind = \"pickup\" if visit.is_pickup else \"delivery\"\n        print(\n            visit_kind,\n            \"shipment_index=\",\n            visit.shipment_index,\n            \"visit_request_index=\",\n            visit.visit_request_index,\n            \"start_time=\",\n            visit.start_time,\n        )\n\nfor skipped in response.skipped_shipments:\n    print(\"skipped shipment index:\", skipped.index)\n```\n\nPractical notes:\n\n- `ShipmentModel` is the core payload: shipments, vehicles, and global time bounds.\n- `penalty_cost` lets the solver skip a shipment instead of forcing an impossible route.\n- `response.metrics.total_cost` is the current field to read; `response.total_cost` is deprecated.\n\n### Validate A Request Before Solving\n\nUse `VALIDATE_ONLY` when you want schema and constraint feedback without running a full solve.\n\n```python\nvalidation_request = optimization_v1.OptimizeToursRequest(\n    parent=request.parent,\n    timeout=request.timeout,\n    model=request.model,\n    solving_mode=optimization_v1.OptimizeToursRequest.SolvingMode.VALIDATE_ONLY,\n    max_validation_errors=100,\n)\n\nvalidation_response = client.optimize_tours(request=validation_request)\n\nfor error in validation_response.validation_errors:\n    print(error)\n```\n\nThis is the safest way to catch bad time windows, impossible constraints, or malformed data before moving the request into production traffic. Validation-only requests are also not billed according to the product billing docs.\n\n### Run A Batch Job From Cloud Storage\n\nUse `batch_optimize_tours()` when you have multiple models, large request bodies, or you want results written back to GCS.\n\n```python\nimport os\n\nfrom google.cloud import optimization_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nparent = f\"projects/{project_id}\"\n\nclient = optimization_v1.FleetRoutingClient()\n\nrequest = optimization_v1.BatchOptimizeToursRequest(\n    parent=parent,\n    model_configs=[\n        optimization_v1.AsyncModelConfig(\n            display_name=\"daily-planning-2026-03-13\",\n            input_config=optimization_v1.InputConfig(\n                gcs_source={\"uri\": \"gs://my-bucket/route-inputs/model-001.json\"},\n                data_format=optimization_v1.DataFormat.JSON,\n            ),\n            output_config=optimization_v1.OutputConfig(\n                gcs_destination={\"uri\": \"gs://my-bucket/route-outputs/model-001/\"},\n                data_format=optimization_v1.DataFormat.JSON,\n            ),\n        )\n    ],\n)\n\noperation = client.batch_optimize_tours(request=request)\nresponse = operation.result(timeout=1800)\n\nprint(response)\n```\n\nBatch constraints that matter:\n\n- Each input file must contain one `OptimizeToursRequest`.\n- Each output file contains one `OptimizeToursResponse`.\n- The input and output files must be under the same project.\n- This call returns a long-running operation, so plan for polling or waiting on `operation.result()`.\n\n## Common Pitfalls\n\n- Do not use API-key-only patterns from other Google Maps services here. The official Route Optimization setup requires OAuth credentials, and the Python client is built around Google auth credentials.\n- Keep all visit and vehicle time windows inside `ShipmentModel.global_start_time` and `global_end_time`.\n- Time windows in the same repeated field must be disjoint and in increasing order.\n- Visit-request time windows constrain arrival time. The visit duration can extend past the end of that window.\n- Keep protobuf timestamps and durations at whole-second precision. The reference docs require `nanos` unset or `0`.\n- Use `populate_transition_polylines`, not the deprecated `populate_travel_step_polylines`.\n- If you set `use_geodesic_distances=True`, you must also set `geodesic_meters_per_second`.\n- Do not read `response.total_cost` in new code; use `response.metrics.total_cost`.\n\n## Version Notes\n\n- PyPI lists `google-cloud-optimization 1.13.0`.\n- Parts of the Python reference site still render `latest` pages as `1.12.0`, while newer request-type pages already show `1.13.0`.\n- For package pinning, prefer PyPI. For API fields and method shapes, use the current reference URLs under the `latest` docs path.\n\n## Optional Debug Logging\n\nThe PyPI package docs describe environment-based logging through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`.\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.optimization_v1\n```\n\nThat enables default structured logging for this library without changing application code.\n\n## Official Sources\n\n- Python client reference root: https://cloud.google.com/python/docs/reference/optimization/latest\n- FleetRoutingClient reference: https://cloud.google.com/python/docs/reference/optimization/latest/google.cloud.optimization_v1.services.fleet_routing.FleetRoutingClient\n- OptimizeToursRequest reference: https://cloud.google.com/python/docs/reference/optimization/latest/google.cloud.optimization_v1.types.OptimizeToursRequest\n- BatchOptimizeToursRequest reference: https://cloud.google.com/python/docs/reference/optimization/latest/google.cloud.optimization_v1.types.BatchOptimizeToursRequest\n- OptimizeToursResponse reference: https://cloud.google.com/python/docs/reference/optimization/latest/google.cloud.optimization_v1.types.OptimizeToursResponse\n- Route Optimization setup guide: https://developers.google.com/maps/documentation/route-optimization/cloud-setup\n- Route Optimization overview: https://developers.google.com/maps/documentation/route-optimization/overview\n- Route Optimization REST reference root: https://developers.google.com/maps/documentation/route-optimization/reference/rest\n- `projects.optimizeTours` REST method: https://developers.google.com/maps/documentation/route-optimization/reference/rest/v1/projects/optimizeTours\n- `projects.batchOptimizeTours` REST method: https://developers.google.com/maps/documentation/route-optimization/reference/rest/v1/projects/batchOptimizeTours\n- First-request guide: https://developers.google.com/maps/documentation/route-optimization/construct-request\n- PyPI package page: https://pypi.org/project/google-cloud-optimization/\n"
  },
  {
    "path": "content/google/docs/orchestration-airflow/python/DOC.md",
    "content": "---\nname: orchestration-airflow\ndescription: \"Google Cloud Composer Python client for managing environments, image versions, Airflow CLI commands, and snapshots\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.19.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,composer,airflow,gcp,orchestration\"\n---\n\n# Google Cloud Composer Python Client\n\nUse `google-cloud-orchestration-airflow` when you need the Cloud Composer control-plane API from Python: discover environments, inspect image versions, create or patch environments, run Airflow CLI commands, and save or load snapshots.\n\n```python\nfrom google.cloud.orchestration.airflow import service_v1\n```\n\nThis package is for managing Composer environments. It is not the package you import inside DAG code.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-orchestration-airflow==1.19.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-orchestration-airflow==1.19.0\"\npoetry add \"google-cloud-orchestration-airflow==1.19.0\"\n```\n\nPyPI publishes this client for Python 3.7+.\n\n## Setup And Authentication\n\nTypical prerequisites:\n\n- a Google Cloud project\n- the Cloud Composer API enabled\n- a Composer environment region such as `us-central1`\n- Application Default Credentials (ADC) or another Google-authenticated runtime\n\nEnable auth locally:\n\n```bash\ngcloud auth application-default login\ngcloud services enable composer.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport COMPOSER_ENVIRONMENT=\"my-composer-env\"\nexport COMPOSER_SERVICE_ACCOUNT=\"composer-runtime@my-project.iam.gserviceaccount.com\"\n```\n\nIf you must use a credential file explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nExplicit credentials also work:\n\n```python\nfrom google.cloud.orchestration.airflow import service_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = service_v1.EnvironmentsClient(credentials=credentials)\n```\n\n## Client Initialization\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\n\nclient = service_v1.EnvironmentsClient()\nparent = client.common_location_path(project_id, location)\nenvironment_name = client.environment_path(project_id, location, environment_id)\n```\n\nUseful generated clients:\n\n- `service_v1.EnvironmentsClient`: main environment lifecycle and Airflow command operations\n- `service_v1.ImageVersionsClient`: list usable Composer image versions for a region\n- `service_v1.EnvironmentsAsyncClient` and `service_v1.ImageVersionsAsyncClient`: async variants\n\nMost mutating operations return a long-running operation. Wait on `operation.result(...)` before assuming the environment is ready.\n\n## Core Workflow\n\n### List environments in a region\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = service_v1.EnvironmentsClient()\nparent = client.common_location_path(project_id, location)\n\nfor env in client.list_environments(parent=parent):\n    airflow_uri = env.config.airflow_uri if env.config else None\n    print(env.name, env.state, airflow_uri)\n```\n\n### Get one environment\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\n\nclient = service_v1.EnvironmentsClient()\nenvironment_name = client.environment_path(project_id, location, environment_id)\n\nenv = client.get_environment(name=environment_name)\n\nprint(env.name)\nprint(env.state)\nprint(env.config.dag_gcs_prefix)\nprint(env.config.airflow_uri)\nprint(env.config.software_config.image_version)\n```\n\n### Discover valid image versions before creating an environment\n\nDo not hard-code a Composer image string that you found in an old blog post. List image versions in the target region first, then pick one from the API response.\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = service_v1.ImageVersionsClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor version in client.list_image_versions(parent=parent):\n    print(version.image_version_id)\n    print(\"  supports Python:\", \", \".join(version.supported_python_versions))\n    print(\"  release date:\", version.release_date)\n```\n\nCloud Composer ties the environment Python version to the selected image version. After an environment is created, you cannot switch it to a different minor Python version.\n\n### Create an environment\n\nUse an explicit service account and an explicit image version. Cloud Composer product docs note that new environments created on or after April 13, 2025 no longer default to the Compute Engine default service account.\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\nservice_account = os.environ[\"COMPOSER_SERVICE_ACCOUNT\"]\n\nclient = service_v1.EnvironmentsClient()\nparent = client.common_location_path(project_id, location)\nenvironment_name = client.environment_path(project_id, location, environment_id)\n\nenvironment = service_v1.Environment(\n    name=environment_name,\n    config=service_v1.EnvironmentConfig(\n        environment_size=service_v1.EnvironmentConfig.EnvironmentSize.ENVIRONMENT_SIZE_SMALL,\n        software_config=service_v1.SoftwareConfig(\n            image_version=\"composer-3-airflow-2.10.5-build.9\",\n            env_variables={\"APP_ENV\": \"prod\"},\n            pypi_packages={\"pendulum\": \"==3.0.0\"},\n        ),\n        node_config=service_v1.NodeConfig(\n            service_account=service_account,\n        ),\n    ),\n    labels={\"team\": \"data-platform\"},\n)\n\noperation = client.create_environment(\n    parent=parent,\n    environment=environment,\n)\n\ncreated = operation.result(timeout=60 * 60)\nprint(created.name)\nprint(created.config.airflow_uri)\n```\n\nUse an image version returned by `list_image_versions` for your region. The example image above is only a shape example from the official docs, not a promise that it is still the newest image in every region.\n\n### Patch environment configuration with `update_mask`\n\n`update_environment` is a partial update API. Use a field mask and patch only the fields you intend to change.\n\nExample: add or update one PyPI package in the environment:\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\n\nclient = service_v1.EnvironmentsClient()\nenvironment_name = client.environment_path(project_id, location, environment_id)\n\npatch = service_v1.Environment(\n    name=environment_name,\n    config=service_v1.EnvironmentConfig(\n        software_config=service_v1.SoftwareConfig(\n            pypi_packages={\"dbt-bigquery\": \"==1.9.1\"},\n        )\n    ),\n)\n\noperation = client.update_environment(\n    request=service_v1.UpdateEnvironmentRequest(\n        name=environment_name,\n        environment=patch,\n        update_mask=FieldMask(\n            paths=[\"config.softwareConfig.pypiPackages.dbt-bigquery\"]\n        ),\n    )\n)\n\nupdated = operation.result(timeout=60 * 60)\nprint(updated.config.software_config.pypi_packages[\"dbt-bigquery\"])\n```\n\nThe product docs call out that only one update type is supported per request. Keep patches narrow.\n\n### Run an Airflow CLI command and poll output\n\nThis is useful for targeted operational automation such as triggering a DAG or checking dags, pools, or variables without opening the UI.\n\n```python\nimport os\nimport time\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\n\nclient = service_v1.EnvironmentsClient()\nenvironment_name = client.environment_path(project_id, location, environment_id)\n\nstarted = client.execute_airflow_command(\n    request=service_v1.ExecuteAirflowCommandRequest(\n        environment=environment_name,\n        command=\"dags\",\n        subcommand=\"trigger\",\n        parameters=[\"example_bash_operator\"],\n    )\n)\n\nif started.error:\n    raise RuntimeError(started.error)\n\nnext_line_number = 0\n\nwhile True:\n    polled = client.poll_airflow_command(\n        request=service_v1.PollAirflowCommandRequest(\n            environment=environment_name,\n            execution_id=started.execution_id,\n            pod=started.pod,\n            pod_namespace=started.pod_namespace,\n            next_line_number=next_line_number,\n        )\n    )\n\n    for line in polled.output:\n        print(line.content, end=\"\")\n        next_line_number = max(next_line_number, line.line_number + 1)\n\n    if polled.output_end:\n        if polled.exit_info.error:\n            raise RuntimeError(polled.exit_info.error)\n        if polled.exit_info.exit_code != 0:\n            raise RuntimeError(\n                f\"Airflow command failed with exit code {polled.exit_info.exit_code}\"\n            )\n        break\n\n    time.sleep(2)\n```\n\nCloud Composer product docs warn that CLI execution can run Python code available to Airflow components on behalf of the environment service account. For high-volume DAG triggering and automation, prefer the stable Airflow REST API or `gcloud composer environments run` when that is a better fit for your operational model.\n\n### Save and load a snapshot\n\nSnapshots are the API-supported way to back up and restore environment state.\n\n```python\nimport os\n\nfrom google.cloud.orchestration.airflow import service_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nenvironment_id = os.environ[\"COMPOSER_ENVIRONMENT\"]\n\nclient = service_v1.EnvironmentsClient()\nenvironment_name = client.environment_path(project_id, location, environment_id)\n\nsave_operation = client.save_snapshot(\n    request=service_v1.SaveSnapshotRequest(\n        environment=environment_name,\n        snapshot_location=\"gs://my-snapshot-bucket/composer-backups\",\n    )\n)\n\nsaved = save_operation.result(timeout=60 * 60)\nprint(saved.snapshot_path)\n\nload_operation = client.load_snapshot(\n    request=service_v1.LoadSnapshotRequest(\n        environment=environment_name,\n        snapshot_path=saved.snapshot_path,\n    )\n)\n\nload_operation.result(timeout=60 * 60)\n```\n\n## Pitfalls And Practical Notes\n\n- This package manages Composer environments. It does not replace the Airflow runtime libraries used inside DAGs.\n- Use `list_image_versions` before `create_environment`; image availability and supported Python versions are regional and change over time.\n- Treat image version choice as part of environment design. Composer docs say you cannot change an existing environment to a different minor Python version later.\n- Always wait for long-running operations from create, update, delete, save, and load flows.\n- Use `update_mask` paths exactly. Generated Python field names are snake_case, but the field mask paths for Composer config updates use the API field names shown in the product docs, such as `config.softwareConfig.pypiPackages.<package-name>`.\n- Keep `execute_airflow_command` for targeted admin automation. The product docs explicitly caution that this route can execute Python code on behalf of the environment service account.\n\n## Official Sources\n\n- Python client reference root: https://cloud.google.com/python/docs/reference/composer/latest\n- PyPI package: https://pypi.org/project/google-cloud-orchestration-airflow/\n- `EnvironmentsClient` reference: https://cloud.google.com/python/docs/reference/composer/latest/google.cloud.orchestration.airflow.service_v1.services.environments.EnvironmentsClient\n- `ImageVersionsClient` reference: https://cloud.google.com/python/docs/reference/composer/latest/google.cloud.orchestration.airflow.service_v1.services.image_versions.ImageVersionsClient\n- Environment creation guide: https://cloud.google.com/composer/docs/composer-3/create-environments\n- Airflow CLI command guide: https://cloud.google.com/composer/docs/composer-3/access-airflow-cli\n- Snapshot guide: https://cloud.google.com/composer/docs/composer-3/save-load-snapshots\n- Environment image versions guide: https://cloud.google.com/composer/docs/composer-3/concepts/versioning/composer-versions\n- ADC guide: https://cloud.google.com/docs/authentication/provide-credentials-adc\n"
  },
  {
    "path": "content/google/docs/os-config/python/DOC.md",
    "content": "---\nname: os-config\ndescription: \"Google Cloud OS Config Python client for VM Manager inventory, vulnerability reports, patch jobs, patch deployments, and OS policy assignments\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.23.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-os-config,gcp,google-cloud,vm-manager,os-config,patching,inventory,python\"\n---\n\n# google-cloud-os-config Python Package Guide\n\nUse `google-cloud-os-config` for Python code that reads VM Manager inventory and vulnerability data, runs patch jobs, manages patch deployments, and works with OS policy assignments in Google Cloud.\n\n## Golden Rule\n\n- Install `google-cloud-os-config`, then import `osconfig_v1` from `google.cloud`.\n- Use Application Default Credentials (ADC) or explicit service-account credentials. This library does not use API keys.\n- Use the right client for the resource scope:\n  - `OsConfigServiceClient` for project-level patch jobs and patch deployments\n  - `OsConfigZonalServiceClient` for zonal inventory, vulnerability reports, and OS policy assignments\n- Use the generated path helpers when you need full resource names.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-os-config==1.23.0\"\n```\n\n## Setup And Authentication\n\nBefore using the client library:\n\n1. Enable the OS Config API for the target project.\n2. Set up VM Manager for the Compute Engine VMs you want to inspect or patch.\n3. Authenticate with ADC locally or attach a service account in Google Cloud.\n\nLocal development with ADC:\n\n```bash\ngcloud services enable osconfig.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\nService account file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\n## Initialize The Clients\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nservice_client = osconfig_v1.OsConfigServiceClient()\nzonal_client = osconfig_v1.OsConfigZonalServiceClient()\n\nproject_parent = f\"projects/{project_id}\"\nzone_parent = f\"projects/{project_id}/locations/{zone}\"\n```\n\nWith explicit credentials:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nservice_client = osconfig_v1.OsConfigServiceClient(credentials=credentials)\nzonal_client = osconfig_v1.OsConfigZonalServiceClient(credentials=credentials)\n```\n\n## Read VM Inventory\n\nInventory data is zonal. The request parent format is:\n\n```text\nprojects/{project}/locations/{zone}\n```\n\nList inventory records for every VM in a zone:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = osconfig_v1.OsConfigZonalServiceClient()\n\nfor inventory in client.list_inventories(\n    request={\"parent\": f\"projects/{project_id}/locations/{zone}\"}\n):\n    print(inventory.name)\n    print(inventory.os_info)\n```\n\nFetch one inventory resource when you already know the instance segment:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\ninstance = \"instance-id-or-name\"\n\nclient = osconfig_v1.OsConfigZonalServiceClient()\nname = client.inventory_path(project_id, zone, instance)\n\ninventory = client.get_inventory(request={\"name\": name})\nprint(inventory.name)\nprint(inventory.os_info)\n```\n\n## Read Vulnerability Reports\n\nVulnerability reports are also zonal and follow the same parent shape as inventories.\n\nList the reports available in a zone:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = osconfig_v1.OsConfigZonalServiceClient()\n\nfor report in client.list_vulnerability_reports(\n    request={\"parent\": f\"projects/{project_id}/locations/{zone}\"}\n):\n    print(report.name)\n```\n\nGet one report by resource name:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\ninstance = \"instance-id-or-name\"\n\nclient = osconfig_v1.OsConfigZonalServiceClient()\nname = client.vulnerability_report_path(project_id, zone, instance)\n\nreport = client.get_vulnerability_report(request={\"name\": name})\nprint(report.name)\n```\n\n## Run A Patch Job\n\nPatch jobs use the project-level service client. The request parent format is:\n\n```text\nprojects/{project}\n```\n\nStart with a dry run so you can confirm the instance filter matches the VMs you expect:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = osconfig_v1.OsConfigServiceClient()\n\npatch_job = client.execute_patch_job(\n    request={\n        \"parent\": f\"projects/{project_id}\",\n        \"description\": \"Preview the next web patch run\",\n        \"instance_filter\": {\n            \"zones\": [zone],\n            \"instance_name_prefixes\": [\"web-\"],\n        },\n        \"dry_run\": True,\n    }\n)\n\nprint(patch_job.name)\nprint(patch_job.state)\n```\n\nInspect the VM-level results for that job:\n\n```python\nfor detail in client.list_patch_job_instance_details(\n    request={\"parent\": patch_job.name}\n):\n    print(detail.name, detail.state)\n```\n\nFetch the current job state again later:\n\n```python\ncurrent = client.get_patch_job(request={\"name\": patch_job.name})\nprint(current.state)\n```\n\nRun a one-off patch against a specific instance resource:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\ninstance_name = \"vm-1\"\n\nclient = osconfig_v1.OsConfigServiceClient()\n\npatch_job = client.execute_patch_job(\n    request={\n        \"parent\": f\"projects/{project_id}\",\n        \"description\": \"Patch one VM now\",\n        \"instance_filter\": {\n            \"instances\": [f\"zones/{zone}/instances/{instance_name}\"],\n        },\n    }\n)\n\nprint(patch_job.name)\n```\n\n## Patch Deployments And OS Policy Assignments\n\nThe same package also exposes:\n\n- `create_patch_deployment`, `get_patch_deployment`, `list_patch_deployments`, `pause_patch_deployment`, `resume_patch_deployment`, and `delete_patch_deployment` on `OsConfigServiceClient`\n- `create_os_policy_assignment`, `update_os_policy_assignment`, `get_os_policy_assignment`, `list_os_policy_assignments`, `delete_os_policy_assignment`, and report methods on `OsConfigZonalServiceClient`\n\nImportant behavior differences:\n\n- Patch deployments are scheduled resources. Patch jobs are immediate executions.\n- OS policy assignment create, update, and delete methods return long-running operations. Wait for `operation.result()` before assuming rollout is finished.\n\nList current OS policy assignments in a zone:\n\n```python\nimport os\n\nfrom google.cloud import osconfig_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nzone = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = osconfig_v1.OsConfigZonalServiceClient()\n\nfor assignment in client.list_os_policy_assignments(\n    request={\"parent\": f\"projects/{project_id}/locations/{zone}\"}\n):\n    print(assignment.name)\n```\n\n## Common Pitfalls\n\n- The package name is `google-cloud-os-config`, but the import is `from google.cloud import osconfig_v1`.\n- Inventory, vulnerability, and OS policy assignment methods are zonal. Patch jobs and patch deployments are project-level. Using the wrong parent format causes `InvalidArgument` or `NotFound` errors.\n- Inventory and vulnerability data only exist for VMs that are set up for VM Manager / OS Config.\n- Use `dry_run=True` on patch jobs first. It is the safest way to verify the instance filter before patching production VMs.\n- `execute_patch_job()` returns a `PatchJob`, not a long-running operation. Re-read it with `get_patch_job()` or inspect `list_patch_job_instance_details()` for progress.\n- `create_os_policy_assignment()` and `update_os_policy_assignment()` do use long-running operations. Wait on `operation.result()`.\n- If your app uses multiprocessing, create client objects after `os.fork()`, not before.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/google-cloud-os-config/\n- GitHub package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-os-config\n- Google Cloud Python reference root: https://cloud.google.com/python/docs/reference/osconfig/latest\n- `OsConfigServiceClient` reference: https://cloud.google.com/python/docs/reference/osconfig/latest/google.cloud.osconfig_v1.services.os_config_service.OsConfigServiceClient\n- `OsConfigZonalServiceClient` reference: https://cloud.google.com/python/docs/reference/osconfig/latest/google.cloud.osconfig_v1.services.os_config_zonal_service.OsConfigZonalServiceClient\n- VM Manager setup: https://cloud.google.com/compute/vm-manager/docs/setup\n- Patch jobs overview: https://cloud.google.com/compute/vm-manager/docs/patch\n- Multiprocessing note: https://cloud.google.com/python/docs/reference/osconfig/latest/multiprocessing\n"
  },
  {
    "path": "content/google/docs/os-login/python/DOC.md",
    "content": "---\nname: os-login\ndescription: \"Google Cloud OS Login Python client library for login profiles, POSIX accounts, and SSH public key management\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.19.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,os-login,ssh,compute-engine,iam,linux\"\n---\n\n# Google Cloud OS Login Python Client\n\n## Golden Rule\n\nUse `google-cloud-os-login` with `from google.cloud import oslogin_v1`, authenticate with Application Default Credentials (ADC), and treat this library as the control plane for OS Login profile data and SSH keys. It does not enable OS Login on Compute Engine VMs by itself.\n\nBefore these API calls matter, you still need:\n\n- the OS Login API enabled in the target Google Cloud project\n- OS Login enabled for the VM or project metadata\n- IAM roles that let the caller use OS Login, typically `roles/compute.osLogin` or `roles/compute.osAdminLogin`\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-os-login==2.19.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-os-login==2.19.0\"\npoetry add \"google-cloud-os-login==2.19.0\"\n```\n\nPyPI currently lists Python `>=3.7`.\n\n## Authentication And Setup\n\nGoogle Cloud client libraries use ADC. For local development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport OSLOGIN_USER=\"users/USER_ID\"\n```\n\nIf you need a key-based flow, point ADC at a service account file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nBasic imports and client setup:\n\n```python\nimport os\n\nfrom google.cloud import oslogin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nuser_name = os.environ[\"OSLOGIN_USER\"]  # format: users/{user}\n\nclient = oslogin_v1.OsLoginServiceClient()\n```\n\nIf you need to pin credentials explicitly:\n\n```python\nfrom google.cloud import oslogin_v1\n\nclient = oslogin_v1.OsLoginServiceClient.from_service_account_json(\n    \"service-account.json\"\n)\n```\n\n## Core Workflow\n\n### Read a login profile\n\n`get_login_profile` returns the caller's or target user's POSIX accounts and SSH public keys. Pass the project ID when you want the profile resolved in a specific project context.\n\n```python\nimport os\n\nfrom google.cloud import oslogin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nuser_name = os.environ[\"OSLOGIN_USER\"]\n\nclient = oslogin_v1.OsLoginServiceClient()\nprofile = client.get_login_profile(\n    request=oslogin_v1.GetLoginProfileRequest(\n        name=user_name,\n        project_id=project_id,\n    )\n)\n\nprint(\"profile:\", profile.name)\n\nfor account in profile.posix_accounts:\n    print(\n        account.username,\n        account.uid,\n        account.home_directory,\n        account.primary,\n    )\n\nfor ssh_key in profile.ssh_public_keys.values():\n    print(ssh_key.fingerprint, ssh_key.expiration_time_usec)\n```\n\nUse this first when your code needs the current Linux username, UID, or existing key fingerprints before making changes.\n\n### Import an SSH public key and let OS Login create default POSIX account info if needed\n\n`import_ssh_public_key` is the practical entry point for first-time setup. The reference docs note that default POSIX account information is set when no username and UID already exist in the login profile.\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom google.cloud import oslogin_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nuser_name = os.environ[\"OSLOGIN_USER\"]\npublic_key_text = Path.home().joinpath(\".ssh\", \"id_ed25519.pub\").read_text().strip()\n\nclient = oslogin_v1.OsLoginServiceClient()\nclient.import_ssh_public_key(\n    request=oslogin_v1.ImportSshPublicKeyRequest(\n        parent=user_name,\n        project_id=project_id,\n        ssh_public_key=oslogin_v1.SshPublicKey(\n            key=public_key_text,\n        ),\n    )\n)\n\nprofile = client.get_login_profile(\n    request=oslogin_v1.GetLoginProfileRequest(\n        name=user_name,\n        project_id=project_id,\n    )\n)\n\nprint(\"imported fingerprints:\")\nfor ssh_key in profile.ssh_public_keys.values():\n    print(ssh_key.fingerprint)\n```\n\n### Create an SSH public key with an explicit expiration\n\nUse `create_ssh_public_key` when you want to set the key metadata directly.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\nfrom pathlib import Path\n\nfrom google.cloud import oslogin_v1\n\nuser_name = os.environ[\"OSLOGIN_USER\"]\npublic_key_text = Path.home().joinpath(\".ssh\", \"id_ed25519.pub\").read_text().strip()\nexpires_at = datetime.now(timezone.utc) + timedelta(days=7)\n\nclient = oslogin_v1.OsLoginServiceClient()\ncreated_key = client.create_ssh_public_key(\n    request=oslogin_v1.CreateSshPublicKeyRequest(\n        parent=user_name,\n        ssh_public_key=oslogin_v1.SshPublicKey(\n            key=public_key_text,\n            expiration_time_usec=int(expires_at.timestamp() * 1_000_000),\n        ),\n    )\n)\n\nprint(created_key.name)\nprint(created_key.fingerprint)\n```\n\n### Fetch one SSH public key by resource name\n\nThe key resource name comes back from `create_ssh_public_key`, or you can read it from the `ssh_public_keys` map in a login profile.\n\n```python\nimport os\n\nfrom google.cloud import oslogin_v1\n\nkey_name = os.environ[\"OSLOGIN_SSH_KEY_NAME\"]\n\nclient = oslogin_v1.OsLoginServiceClient()\nssh_key = client.get_ssh_public_key(\n    request=oslogin_v1.GetSshPublicKeyRequest(name=key_name)\n)\n\nprint(ssh_key.name)\nprint(ssh_key.fingerprint)\nprint(ssh_key.key)\n```\n\n### Extend or change SSH key metadata\n\n`update_ssh_public_key` uses patch semantics, so pass an update mask for the fields you are changing.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import oslogin_v1\nfrom google.protobuf import field_mask_pb2\n\nkey_name = os.environ[\"OSLOGIN_SSH_KEY_NAME\"]\nexpires_at = datetime.now(timezone.utc) + timedelta(days=30)\n\nclient = oslogin_v1.OsLoginServiceClient()\nupdated_key = client.update_ssh_public_key(\n    request=oslogin_v1.UpdateSshPublicKeyRequest(\n        ssh_public_key=oslogin_v1.SshPublicKey(\n            name=key_name,\n            expiration_time_usec=int(expires_at.timestamp() * 1_000_000),\n        ),\n        update_mask=field_mask_pb2.FieldMask(paths=[\"expiration_time_usec\"]),\n    )\n)\n\nprint(updated_key.name)\nprint(updated_key.expiration_time_usec)\n```\n\n### Delete an SSH public key\n\n```python\nimport os\n\nfrom google.cloud import oslogin_v1\n\nkey_name = os.environ[\"OSLOGIN_SSH_KEY_NAME\"]\n\nclient = oslogin_v1.OsLoginServiceClient()\nclient.delete_ssh_public_key(\n    request=oslogin_v1.DeleteSshPublicKeyRequest(name=key_name)\n)\n```\n\n### Delete a POSIX account\n\nThis removes the POSIX account resource for a specific user.\n\n```python\nimport os\n\nfrom google.cloud import oslogin_v1\n\nposix_account_name = os.environ[\"OSLOGIN_POSIX_ACCOUNT_NAME\"]\n\nclient = oslogin_v1.OsLoginServiceClient()\nclient.delete_posix_account(\n    request=oslogin_v1.DeletePosixAccountRequest(name=posix_account_name)\n)\n```\n\n## Configuration Notes\n\n- Use the package name `google-cloud-os-login`, but import from `google.cloud.oslogin_v1`.\n- The generated clients accept either flattened parameters or a `request=` object. Use `request=` consistently once the call has more than one field.\n- The `project_id` parameter on `get_login_profile` and `import_ssh_public_key` is optional in the client surface, but it matters when your app works across projects and needs OS Login state evaluated in a specific project.\n- `expiration_time_usec` is expressed in microseconds since the Unix epoch, not seconds.\n- Create client instances after `os.fork()` if your application uses multiprocessing. Google Cloud generated clients are not intended to be shared across fork boundaries.\n\n## Common Pitfalls\n\n- Enabling the API is not enough. OS Login also has to be enabled on the Compute Engine project or instance metadata, or the VM still uses metadata-based SSH keys.\n- This package manages OS Login data; it does not open SSH connections or configure guest OS settings for you.\n- The most common import mistake is installing `google-cloud-os-login` and then trying to import `google.cloud.os_login`. The correct import is `from google.cloud import oslogin_v1`.\n- `update_ssh_public_key` is patch-based. If you omit `update_mask`, your code is not expressing which field should change.\n- Key deletion uses the SSH key resource name, not the raw public key text or fingerprint by itself.\n- Some OS Login methods documented in the Compute Engine REST API are v1beta-only. The stable Python client surface here is `oslogin_v1`, so do not assume every REST method has a matching stable Python wrapper.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-os-login 2.19.0`.\n- The current Google Cloud Python reference pages for `oslogin_v1` also show `2.19.0`.\n- If you are copying older snippets, prefer request-object examples like the ones above. That matches the current generated client docs and avoids ambiguity when optional fields are added.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-os-login/\n- Python client reference root: https://cloud.google.com/python/docs/reference/oslogin/latest\n- `OsLoginServiceClient` reference: https://cloud.google.com/python/docs/reference/oslogin/latest/google.cloud.oslogin_v1.services.os_login_service.OsLoginServiceClient\n- Library overview and auth notes: https://cloud.google.com/python/docs/reference/oslogin/latest\n- Set up OS Login on Compute Engine: https://cloud.google.com/compute/docs/oslogin/set-up-oslogin\n- Manage OS Login in an organization: https://cloud.google.com/compute/docs/oslogin/manage-oslogin-in-an-org\n"
  },
  {
    "path": "content/google/docs/phishing-protection/python/DOC.md",
    "content": "---\nname: phishing-protection\ndescription: \"google-cloud-phishing-protection Python package guide for reporting suspected phishing URLs with ADC-based auth\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,phishing-protection,security,safe-browsing,python\"\n---\n\n# google-cloud-phishing-protection Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-phishing-protection` with Application Default Credentials (ADC), import the `phishingprotection_v1beta1` namespace, and treat `report_phishing` as an asynchronous submission step rather than a verdict API.\n\nThe generated Python reference for this package exposes one service namespace, `v1beta1`, and one practical RPC, `report_phishing(...)`.\n\n## Install\n\nPin the version if you want behavior aligned with this entry:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-phishing-protection==1.16.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-phishing-protection==1.16.0\"\npoetry add \"google-cloud-phishing-protection==1.16.0\"\n```\n\nPyPI currently lists Python `>=3.7` support for this package.\n\n## Required Setup\n\nGoogle's package docs say you must do all of the following before calling the client:\n\n1. Select or create a Google Cloud project.\n2. Enable billing for that project.\n3. Enable the Phishing Protection API.\n4. Set up authentication.\n\n## Authentication\n\n### Preferred: Application Default Credentials\n\nLocal development:\n\n```bash\ngcloud auth application-default login\n```\n\nThe client library will then pick up credentials automatically:\n\n```python\nfrom google.cloud import phishingprotection_v1beta1\n\nclient = phishingprotection_v1beta1.PhishingProtectionServiceV1Beta1Client()\n```\n\n### Service Account Or Workload Identity\n\nIf your runtime is outside Google Cloud, Google recommends ADC-compatible credentials rather than hard-coding keys in application code.\n\nService account key file fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n```python\nfrom google.cloud import phishingprotection_v1beta1\n\nclient = phishingprotection_v1beta1.PhishingProtectionServiceV1Beta1Client()\n```\n\nThe class also exposes `from_service_account_file(...)`, but the standard `GOOGLE_APPLICATION_CREDENTIALS` flow is usually the simpler choice.\n\n## Core Workflow: Report A Suspected Phishing URL\n\nThe request takes exactly two required fields:\n\n- `parent`: must be `projects/{project_number}`\n- `uri`: the URL to submit for analysis\n\nMinimal synchronous example:\n\n```python\nfrom google.cloud import phishingprotection_v1beta1\n\ndef report_phishing_uri(project_number: str, uri: str) -> None:\n    client = phishingprotection_v1beta1.PhishingProtectionServiceV1Beta1Client()\n\n    request = phishingprotection_v1beta1.ReportPhishingRequest(\n        parent=f\"projects/{project_number}\",\n        uri=uri,\n    )\n\n    client.report_phishing(request=request)\n    print(f\"Submitted {uri} for phishing review\")\n```\n\nThe same call using the client helper that builds a fully-qualified project path:\n\n```python\nfrom google.cloud import phishingprotection_v1beta1\n\nclient = phishingprotection_v1beta1.PhishingProtectionServiceV1Beta1Client()\nparent = client.common_project_path(\"123456789012\")\n\nclient.report_phishing(\n    request=phishingprotection_v1beta1.ReportPhishingRequest(\n        parent=parent,\n        uri=\"https://example-phish.test/login\",\n    )\n)\n```\n\nThe response type is `ReportPhishingResponse`, but the docs describe it as an empty response. The useful outcome of the submission is not returned inline. The service docs say that, after review, results appear in the Cloud Security Command Center findings dashboard for Phishing Protection.\n\n## Async Client\n\nUse the async client only if the rest of your application already uses `asyncio`:\n\n```python\nimport asyncio\n\nfrom google.cloud import phishingprotection_v1beta1\n\nasync def main() -> None:\n    client = phishingprotection_v1beta1.PhishingProtectionServiceV1Beta1AsyncClient()\n\n    request = phishingprotection_v1beta1.ReportPhishingRequest(\n        parent=\"projects/123456789012\",\n        uri=\"https://example-phish.test/login\",\n    )\n\n    await client.report_phishing(request=request)\n    print(\"Submission queued\")\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n- The client supports `client_options` if you need to override endpoint behavior.\n- The generated client also exposes mTLS-related behavior controlled by Google client environment settings. In `1.16.0`, the changelog notes automatic mTLS enablement when supported certificates are detected.\n- The package uses standard Python `logging`. Google warns that logs can contain sensitive information, are not handled by default, and should not be treated as a stable contract.\n\n## Common Pitfalls\n\n- `parent` requires a numeric project resource path like `projects/123456789012`, not a project ID like `projects/my-project`.\n- Do not expect a phishing verdict in the RPC response. The Python docs describe `ReportPhishingResponse` as empty, and the method docs route the result to Security Command Center findings after review.\n- This package currently documents only the `phishingprotection_v1beta1` namespace. If you are looking for a `v1` module, it is not the surface exposed by the official Python reference today.\n- When you call `report_phishing`, pass either a `request=` object or flattened keyword arguments like `parent=` and `uri=`. Do not mix both styles in the same call.\n- Avoid the deprecated `credentials_file` constructor argument. The `1.15.0` changelog explicitly deprecated it.\n- The generated client can be used as a context manager, but the class docs warn that exiting the `with` block closes the underlying transport. Do not use that pattern if the transport is shared.\n\n## Version Notes For `1.16.0`\n\n- PyPI lists `1.16.0` as the current package version, released on January 15, 2026.\n- The official changelog lists `1.16.0` on January 9, 2026 and notes two changes: automatic mTLS enablement when supported certificates are detected, and generated checks for Python and dependency versions.\n- On March 13, 2026, the package landing page and changelog both show `1.16.0`, but the deep class reference pages still render `1.15.0` in their page header. The callable surface for `report_phishing`, `common_project_path`, and the request types is still the relevant current reference, but pin dependencies to `1.16.0`.\n\n## Official Sources\n\n- Python package overview: `https://cloud.google.com/python/docs/reference/phishingprotection/latest`\n- Python API summary: `https://cloud.google.com/python/docs/reference/phishingprotection/latest/summary_overview`\n- Python client class docs: `https://cloud.google.com/python/docs/reference/phishingprotection/latest/google.cloud.phishingprotection_v1beta1.services.phishing_protection_service_v1_beta1.PhishingProtectionServiceV1Beta1Client`\n- Python methods summary: `https://cloud.google.com/python/docs/reference/phishingprotection/latest/summary_method`\n- Python changelog: `https://cloud.google.com/python/docs/reference/phishingprotection/latest/changelog`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- ADC behavior and lookup order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- PyPI package page: `https://pypi.org/project/google-cloud-phishing-protection/`\n"
  },
  {
    "path": "content/google/docs/policy-troubleshooter/python/DOC.md",
    "content": "---\nname: policy-troubleshooter\ndescription: \"google-cloud-policy-troubleshooter Python package guide for IAM access checks with ADC setup and troubleshoot_iam_policy examples\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,iam,policy-troubleshooter,policy-intelligence,python,access\"\n---\n\n# google-cloud-policy-troubleshooter Python Package Guide\n\n## What It Is\n\n`google-cloud-policy-troubleshooter` is the Google-maintained Python client for the `policytroubleshooter_v1` IAM checker surface.\n\nUse it when code needs to answer one question reliably:\n\n- does a specific principal have a specific IAM permission on a specific Google Cloud resource?\n\nThe package exposes one main client, `IamCheckerClient`, and one main RPC, `troubleshoot_iam_policy`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-policy-troubleshooter==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-policy-troubleshooter==1.15.0\"\npoetry add \"google-cloud-policy-troubleshooter==1.15.0\"\n```\n\nPyPI lists support for Python 3.7 and newer for this release line.\n\n## Authentication And Setup\n\nBefore making requests:\n\n1. Enable the IAM Policy Troubleshooter API in the project that will send the request.\n2. Authenticate with Application Default Credentials (ADC).\n3. Make sure the caller can view the policies involved in the check. Google documents `roles/iam.securityReviewer` as the baseline role for troubleshooting principal access.\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport TROUBLESHOOT_PRINCIPAL=\"alice@example.com\"\nexport TROUBLESHOOT_RESOURCE=\"//cloudresourcemanager.googleapis.com/projects/${GOOGLE_CLOUD_PROJECT}\"\nexport TROUBLESHOOT_PERMISSION=\"resourcemanager.projects.get\"\n```\n\nIf you need to point ADC at a credential file explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nImportant request inputs:\n\n- `principal`: an email-form Google Account or service account identity\n- `full_resource_name`: the full resource name, not a bare project ID\n- `permission`: an IAM permission that is valid for that resource type\n\n## Imports And Client Initialization\n\n```python\nfrom google.cloud import policytroubleshooter_v1\n\nclient = policytroubleshooter_v1.IamCheckerClient()\n```\n\nIf you need to construct the client from a service account file directly:\n\n```python\nfrom google.cloud import policytroubleshooter_v1\n\nclient = policytroubleshooter_v1.IamCheckerClient.from_service_account_json(\n    \"/absolute/path/service-account.json\"\n)\n```\n\n## Core Usage\n\n### Troubleshoot one IAM permission check\n\n```python\nimport os\n\nfrom google.cloud import policytroubleshooter_v1\n\nclient = policytroubleshooter_v1.IamCheckerClient()\n\nrequest = policytroubleshooter_v1.TroubleshootIamPolicyRequest(\n    access_tuple=policytroubleshooter_v1.AccessTuple(\n        principal=os.environ[\"TROUBLESHOOT_PRINCIPAL\"],\n        full_resource_name=os.environ[\"TROUBLESHOOT_RESOURCE\"],\n        permission=os.environ[\"TROUBLESHOOT_PERMISSION\"],\n    )\n)\n\nresponse = client.troubleshoot_iam_policy(request=request)\n\nprint(\"overall access:\", response.access)\n\nfor explained_policy in response.explained_policies:\n    print(\"policy resource:\", explained_policy.full_resource_name)\n    print(\"policy access:\", explained_policy.access)\n    print(\"policy relevance:\", explained_policy.relevance)\n\n    for binding in explained_policy.binding_explanations:\n        print(\"  role:\", binding.role)\n        print(\"  binding access:\", binding.access)\n        print(\"  role contains permission:\", binding.role_permission)\n        print(\"  binding relevance:\", binding.relevance)\n\n        for member, annotated in binding.memberships.items():\n            print(\"   \", member, annotated.membership)\n\nif response.errors:\n    for error in response.errors:\n        print(\"error:\", error.code, error.message)\n```\n\nThe important response fields are:\n\n- `response.access`: overall result for the requested principal/resource/permission tuple\n- `response.explained_policies`: each evaluated IAM policy, including inherited policies\n- `response.errors`: general troubleshooting errors returned with the response\n\n### Async client\n\nUse the async client if the rest of your application is already async:\n\n```python\nimport asyncio\nimport os\n\nfrom google.cloud import policytroubleshooter_v1\n\n\nasync def main() -> None:\n    client = policytroubleshooter_v1.IamCheckerAsyncClient()\n\n    request = policytroubleshooter_v1.TroubleshootIamPolicyRequest(\n        access_tuple=policytroubleshooter_v1.AccessTuple(\n            principal=os.environ[\"TROUBLESHOOT_PRINCIPAL\"],\n            full_resource_name=os.environ[\"TROUBLESHOOT_RESOURCE\"],\n            permission=os.environ[\"TROUBLESHOOT_PERMISSION\"],\n        )\n    )\n\n    response = await client.troubleshoot_iam_policy(request=request)\n    print(response.access)\n\n\nasyncio.run(main())\n```\n\n## How To Read The Result\n\nPolicy Troubleshooter evaluates all relevant IAM policies it can see, including inherited policies from higher levels of the resource hierarchy.\n\nIn practice:\n\n- a granted project-level role can explain access to resources under that project\n- missing viewer permissions for the caller can cause omitted policy details or limited explanations\n- bindings are evaluated independently, so `binding_explanations` are the fastest place to see which role or membership actually changed the outcome\n\n## Common Pitfalls\n\n### `full_resource_name` must be a full resource name\n\nDo not pass plain IDs such as `my-project` or `123456789012`. Use names like:\n\n```text\n//cloudresourcemanager.googleapis.com/projects/my-project\n```\n\n### The permission must apply to the resource type\n\nGoogle's product docs note that the request fails if the permission cannot be used on the resource in the request. For example, troubleshooting a Compute Engine permission against a GKE cluster resource is invalid.\n\n### Caller visibility affects the explanation quality\n\nTroubleshooter only explains the policies and custom roles that the caller is allowed to inspect. If the caller cannot view a relevant policy, parts of the result can be omitted or effectively unknown. `roles/iam.securityReviewer` is the documented baseline for troubleshooting principal access.\n\n### Pub/Sub allow policies are a known limitation\n\nThe product documentation says Policy Troubleshooter does not evaluate allow policies set directly on Pub/Sub resources. For Pub/Sub, troubleshoot the parent project first, then review the resource-level allow policy separately.\n\n### The rolling reference docs lag PyPI for this package\n\nPyPI lists `1.15.0`, but the Google Cloud Python reference pages visited on March 13, 2026 still show `1.14.0` as the latest published reference set. Treat the reference pages as the canonical API shape for `policytroubleshooter_v1`, but check PyPI for the current installable package version.\n\n## Official Source URLs\n\n- PyPI package page: `https://pypi.org/project/google-cloud-policy-troubleshooter/1.15.0/`\n- Maintainer package directory: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-policy-troubleshooter`\n- Google Cloud Python reference root: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest`\n- `IamCheckerClient` reference: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest/google.cloud.policytroubleshooter_v1.services.iam_checker.IamCheckerClient`\n- `TroubleshootIamPolicyRequest` reference: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest/google.cloud.policytroubleshooter_v1.types.TroubleshootIamPolicyRequest`\n- `AccessTuple` reference: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest/google.cloud.policytroubleshooter_v1.types.AccessTuple`\n- `BindingExplanation` reference: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest/google.cloud.policytroubleshooter_v1.types.BindingExplanation`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/policytroubleshooter/latest/changelog`\n- Policy Troubleshooter product guide: `https://docs.cloud.google.com/policy-intelligence/docs/troubleshoot-access`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/private-ca/python/DOC.md",
    "content": "---\nname: private-ca\ndescription: \"Google Cloud Private CA Python client for CA pools, private certificate authorities, certificate templates, issuance, and revocation\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,private-ca,pki,tls,x509,certificates,python\"\n---\n\n# google-cloud-private-ca Python Package Guide\n\nUse `google-cloud-private-ca` for Python code that manages Google Cloud Certificate Authority Service resources: CA pools, certificate authorities, certificate templates, issued certificates, and certificate revocation.\n\n## Golden Rule\n\n- Install and import the official client: `import google.cloud.security.privateca_v1 as privateca_v1`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass an explicit credential object.\n- Keep resource locations consistent. CA pools, certificate authorities, templates, and certificates are location-scoped, and certificate templates must be in the same location as the certificate.\n- Treat create, enable, disable, restore, and delete operations on CA pools, certificate authorities, and certificate templates as long-running operations and wait on `operation.result()`.\n- Prefer CSR-based issuance when the private key should stay outside Google Cloud. `create_certificate()` returns the issued leaf certificate plus the PEM chain.\n\nThis guide covers `1.17.0`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-private-ca==1.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-private-ca==1.17.0\"\npoetry add \"google-cloud-private-ca==1.17.0\"\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nIf you must use a service-account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nBefore calling the API:\n\n1. Enable Certificate Authority Service in the target project.\n2. Decide which region you are using. Requests must stay consistent with the CA pool location.\n3. Grant the narrowest IAM role that matches the operation.\n\nCommon IAM roles from the product docs:\n\n- `roles/privateca.admin` for full administration\n- `roles/privateca.caManager` for creating and updating CA pools, certificate authorities, templates, and revocations\n- `roles/privateca.certificateManager` for requesting certificates and reading them back\n- `roles/privateca.certificateRequester` for certificate requests only\n- `roles/privateca.templateUser` to use a certificate template during issuance\n- `roles/privateca.auditor` for read-only inspection\n\n## Initialize The Client\n\nBasic client initialization with ADC:\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\nlocation_path = client.common_location_path(project_id, location)\n```\n\nIf you need to pass an explicit credential object, prefer `credentials=` instead of older `credentials_file`-style configuration:\n\n```python\nimport os\n\nfrom google.cloud.security import privateca_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nclient = privateca_v1.CertificateAuthorityServiceClient(credentials=credentials)\n```\n\nUseful helper paths:\n\n```python\nca_pool_path = client.ca_pool_path(project_id, location, \"my-pool\")\nca_path = client.certificate_authority_path(project_id, location, \"my-pool\", \"root-ca\")\ncertificate_path = client.certificate_path(project_id, location, \"my-pool\", \"leaf-cert\")\ntemplate_path = f\"projects/{project_id}/locations/{location}/certificateTemplates/web-server\"\n```\n\n## Core Usage\n\n### Create a CA pool\n\nCA pools group issuance policy, IAM policy, and the certificate authorities that issue from that pool.\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\n\nca_pool = privateca_v1.CaPool(\n    tier=privateca_v1.CaPool.Tier.ENTERPRISE,\n)\n\noperation = client.create_ca_pool(\n    request=privateca_v1.CreateCaPoolRequest(\n        parent=client.common_location_path(project_id, location),\n        ca_pool_id=\"my-pool\",\n        ca_pool=ca_pool,\n    )\n)\n\ncreated_pool = operation.result(timeout=600)\nprint(created_pool.name)\n```\n\n### Create a root certificate authority\n\nThe official sample creates a self-signed root CA under the pool:\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\nfrom google.protobuf import duration_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\n\ncertificate_authority = privateca_v1.CertificateAuthority(\n    type_=privateca_v1.CertificateAuthority.Type.SELF_SIGNED,\n    key_spec=privateca_v1.CertificateAuthority.KeyVersionSpec(\n        algorithm=privateca_v1.CertificateAuthority.SignHashAlgorithm.RSA_PKCS1_4096_SHA256,\n    ),\n    config=privateca_v1.CertificateConfig(\n        subject_config=privateca_v1.CertificateConfig.SubjectConfig(\n            subject=privateca_v1.Subject(\n                common_name=\"Example Root CA\",\n                organization=\"Example Corp\",\n            )\n        ),\n        x509_config=privateca_v1.X509Parameters(\n            key_usage=privateca_v1.KeyUsage(\n                base_key_usage=privateca_v1.KeyUsage.KeyUsageOptions(\n                    cert_sign=True,\n                    crl_sign=True,\n                )\n            ),\n            ca_options=privateca_v1.X509Parameters.CaOptions(is_ca=True),\n        ),\n    ),\n    lifetime=duration_pb2.Duration(seconds=10 * 365 * 24 * 60 * 60),\n)\n\noperation = client.create_certificate_authority(\n    request=privateca_v1.CreateCertificateAuthorityRequest(\n        parent=client.ca_pool_path(project_id, location, \"my-pool\"),\n        certificate_authority_id=\"root-ca\",\n        certificate_authority=certificate_authority,\n    )\n)\n\ncreated_ca = operation.result(timeout=1800)\nprint(created_ca.name, created_ca.state)\n```\n\n### Enable the CA before issuing certificates\n\nCreating the CA and having an enabled CA are separate steps in the product docs and samples:\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\nca_name = client.certificate_authority_path(project_id, location, \"my-pool\", \"root-ca\")\n\noperation = client.enable_certificate_authority(\n    request=privateca_v1.EnableCertificateAuthorityRequest(name=ca_name)\n)\noperation.result(timeout=600)\n\nca = client.get_certificate_authority(request={\"name\": ca_name})\nprint(ca.state)\n```\n\n### Create a certificate template\n\nTemplates are reusable policy fragments. If you attach one during issuance, the caller needs `roles/privateca.templateUser`.\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\nfrom google.type import expr_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\n\ncertificate_template = privateca_v1.CertificateTemplate(\n    predefined_values=privateca_v1.X509Parameters(\n        key_usage=privateca_v1.KeyUsage(\n            base_key_usage=privateca_v1.KeyUsage.KeyUsageOptions(\n                digital_signature=True,\n                key_encipherment=True,\n            ),\n            extended_key_usage=privateca_v1.KeyUsage.ExtendedKeyUsageOptions(\n                server_auth=True,\n            ),\n        ),\n        ca_options=privateca_v1.X509Parameters.CaOptions(is_ca=False),\n    ),\n    identity_constraints=privateca_v1.CertificateIdentityConstraints(\n        cel_expression=expr_pb2.Expr(\n            expression=\"subject_alt_names.all(san, san.type == DNS)\"\n        ),\n        allow_subject_passthrough=False,\n        allow_subject_alt_names_passthrough=False,\n    ),\n)\n\noperation = client.create_certificate_template(\n    request=privateca_v1.CreateCertificateTemplateRequest(\n        parent=client.common_location_path(project_id, location),\n        certificate_template_id=\"web-server\",\n        certificate_template=certificate_template,\n    )\n)\n\ntemplate = operation.result(timeout=600)\nprint(template.name)\n```\n\n### Issue a certificate from a PEM CSR\n\nThis is the most practical flow when your workload or CA tooling generates the private key locally and only sends the CSR to Private CA.\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\nfrom google.protobuf import duration_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\n\nwith open(\"server.csr.pem\", \"r\", encoding=\"utf-8\") as fh:\n    pem_csr = fh.read()\n\ncertificate = privateca_v1.Certificate(\n    pem_csr=pem_csr,\n    lifetime=duration_pb2.Duration(seconds=30 * 24 * 60 * 60),\n    certificate_template=(\n        f\"projects/{project_id}/locations/{location}/certificateTemplates/web-server\"\n    ),\n)\n\nissued = client.create_certificate(\n    request=privateca_v1.CreateCertificateRequest(\n        parent=client.ca_pool_path(project_id, location, \"my-pool\"),\n        certificate_id=\"web-20260313\",\n        certificate=certificate,\n        issuing_certificate_authority_id=\"root-ca\",\n    )\n)\n\nprint(issued.name)\nprint(issued.pem_certificate)\nfor pem in issued.pem_certificate_chain:\n    print(pem)\n```\n\nImportant response fields:\n\n- `pem_certificate`: the issued leaf certificate\n- `pem_certificate_chain`: issuer-to-root verification chain from the API reference\n- `issuer_certificate_authority`: the CA resource name that signed the certificate\n- `certificate_description`: parsed X.509 details such as SANs, serial number, and validity timestamps\n\n### List certificates in a CA pool\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\nparent = client.ca_pool_path(project_id, location, \"my-pool\")\n\nfor certificate in client.list_certificates(parent=parent):\n    print(certificate.name)\n```\n\n### Revoke a certificate\n\nRevocation updates the certificate metadata immediately. The product docs note that a new CRL is typically created within 15 minutes after revocation.\n\n```python\nimport os\n\nimport google.cloud.security.privateca_v1 as privateca_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = privateca_v1.CertificateAuthorityServiceClient()\n\ncertificate_name = client.certificate_path(\n    project_id,\n    location,\n    \"my-pool\",\n    \"web-20260313\",\n)\n\nrevoked = client.revoke_certificate(\n    request=privateca_v1.RevokeCertificateRequest(\n        name=certificate_name,\n        reason=privateca_v1.RevocationReason.PRIVILEGE_WITHDRAWN,\n    )\n)\n\nprint(revoked.name)\nprint(revoked.revocation_details.revocation_state)\n```\n\n## Common Pitfalls\n\n- Creating a CA is not the same as having an enabled CA. Follow the enable step before trying to issue certificates.\n- Keep `location` aligned across the CA pool, issuing CA, certificate, and certificate template. Templates must be in the same location as the certificate.\n- `roles/privateca.certificateRequester` can create certificates but cannot read them back. If your code expects the returned certificate body or needs list/get access later, use a broader role such as `roles/privateca.certificateManager`.\n- After a certificate is created, the product docs say you cannot delete it or reuse the certificate name.\n- `create_certificate()` returns a `Certificate` directly, but many administrative methods return long-running operations. Do not assume the same response pattern across methods.\n- The published Python reference pages currently lag PyPI by one patch release. Check both PyPI and the Google reference pages when you care about a version-specific behavior change.\n\n## Version-Sensitive Notes\n\n- PyPI shows `google-cloud-private-ca 1.17.0` released on January 15, 2026.\n- The published `latest` Python reference pages currently show `1.16.0`.\n- The official changelog for the published reference notes that `credentials_file` is deprecated. Prefer ADC or pass an explicit `credentials=` object.\n- The same changelog stream documents opt-in debug logging support. If you need RPC logging, set `GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google`, but treat those logs as potentially sensitive.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-private-ca/\n- Python reference root: https://docs.cloud.google.com/python/docs/reference/privateca/latest\n- Changelog: https://docs.cloud.google.com/python/docs/reference/privateca/latest/changelog\n- Client reference: https://docs.cloud.google.com/python/docs/reference/privateca/latest/google.cloud.security.privateca_v1.services.certificate_authority_service.CertificateAuthorityServiceClient\n- `Certificate` type reference: https://docs.cloud.google.com/python/docs/reference/privateca/latest/google.cloud.security.privateca_v1.types.Certificate\n- Create a CA pool sample: https://cloud.google.com/certificate-authority-service/docs/samples/privateca-create-ca-pool\n- Create a root CA sample: https://cloud.google.com/certificate-authority-service/docs/samples/privateca-create-ca\n- Enable a CA sample: https://docs.cloud.google.com/certificate-authority-service/docs/samples/privateca-enable-ca\n- Create a certificate template sample: https://docs.cloud.google.com/certificate-authority-service/docs/samples/privateca-create-certificate-template\n- Issue a certificate from CSR sample: https://docs.cloud.google.com/certificate-authority-service/docs/samples/privateca-create-certificate-csr\n- Request certificates guide: https://cloud.google.com/certificate-authority-service/docs/requesting-certificates\n- Revoke certificate sample: https://docs.cloud.google.com/certificate-authority-service/docs/samples/privateca-revoke-certificate\n- Revoke certificates guide: https://docs.cloud.google.com/certificate-authority-service/docs/revoking-certificates\n- IAM roles and permissions: https://docs.cloud.google.com/certificate-authority-service/docs/access-control\n- ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n"
  },
  {
    "path": "content/google/docs/private-catalog/python/DOC.md",
    "content": "---\nname: private-catalog\ndescription: \"Google Cloud Private Catalog Python client for listing Service Catalog catalogs, products, and versions shared to a project, folder, or organization\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,service-catalog,private-catalog,python,marketplace\"\n---\n\n# Google Cloud Private Catalog Python Client\n\n## Golden Rule\n\nUse `google-cloud-private-catalog` to browse the Service Catalog content that is visible to a resource context such as a project, folder, or organization.\n\nInstall `google-cloud-private-catalog`, import `privatecatalog_v1beta1`, authenticate with Application Default Credentials (ADC), and scope every search to the correct `resource`. This library is the consumer-side browse API. Admin tasks such as creating or sharing catalogs are covered by the Service Catalog product docs, not by this client.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-private-catalog==0.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-private-catalog==0.11.0\"\npoetry add \"google-cloud-private-catalog==0.11.0\"\n```\n\nPyPI lists Python `>=3.7` for this release line.\n\n## Authentication And Setup\n\nBefore you call the API:\n\n1. Enable and configure Service Catalog or Private Catalog for the organization that owns the shared catalogs.\n2. Make sure the catalog is shared to the target project, folder, or organization you plan to search against.\n3. Use an identity that can view that shared target. The current product docs describe the Catalog Consumer role as the common choice for end users.\n4. Prefer ADC over embedding service account keys in application code.\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nThe `resource` argument is what scopes visibility. The generated request types document these formats:\n\n- `projects/PROJECT_ID`\n- `folders/FOLDER_NUMBER`\n- `organizations/ORG_NUMBER`\n\nIf the catalog is not shared to that exact resource, the search calls usually return an empty result set.\n\n## Initialize A Client\n\nBasic client setup with ADC:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\nresource = \"projects/my-project\"\n```\n\nExplicit credentials:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient(credentials=credentials)\nresource = \"projects/my-project\"\n```\n\n## Core Usage\n\n### List Catalogs Shared To A Resource\n\nUse `search_catalogs` to discover which catalogs are visible to a project, folder, or organization:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\nrequest = privatecatalog_v1beta1.SearchCatalogsRequest(\n    resource=\"projects/my-project\",\n)\n\nfor catalog in client.search_catalogs(request=request):\n    print(catalog.name)\n    print(catalog.display_name)\n```\n\nTo narrow the result to one known catalog name, use the documented `name=` query form:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\ncatalog_name = client.catalog_path(catalog=\"my-catalog\")\n\nrequest = privatecatalog_v1beta1.SearchCatalogsRequest(\n    resource=\"projects/my-project\",\n    query=f\"name={catalog_name}\",\n)\n\ncatalog = next(iter(client.search_catalogs(request=request)), None)\nif catalog is not None:\n    print(catalog.name, catalog.display_name)\n```\n\n### List Products In A Catalog\n\n`search_products` is scoped by both the shared `resource` and a catalog-relative query:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\ncatalog_name = \"catalogs/my-catalog\"\n\nrequest = privatecatalog_v1beta1.SearchProductsRequest(\n    resource=\"projects/my-project\",\n    query=f\"parent={catalog_name}\",\n)\n\nfor product in client.search_products(request=request):\n    print(product.name)\n    print(product.display_name)\n    print(product.asset_type)\n    print(product.icon_uri)\n```\n\nTo fetch one specific product, use the documented `name=` query form:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\nproduct_name = \"catalogs/my-catalog/products/my-product\"\n\nrequest = privatecatalog_v1beta1.SearchProductsRequest(\n    resource=\"projects/my-project\",\n    query=f\"name={product_name}\",\n)\n\nproduct = next(iter(client.search_products(request=request)), None)\nif product is not None:\n    print(product.name, product.asset_type)\n```\n\nThe current product reference documents these `asset_type` values:\n\n- `google.deploymentmanager.Template`\n- `google.cloudprivatecatalog.ListingOnly`\n- `google.cloudprivatecatalog.Terraform`\n\n### List Versions For A Product\n\nUse the product resource name as the `parent=` filter when browsing versions:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\nproduct_name = \"catalogs/my-catalog/products/my-product\"\n\nrequest = privatecatalog_v1beta1.SearchVersionsRequest(\n    resource=\"projects/my-project\",\n    query=f\"parent={product_name}\",\n)\n\nfor version in client.search_versions(request=request):\n    print(version.name)\n    print(version.description)\n    print(version.asset)\n```\n\nTo fetch a single version directly:\n\n```python\nfrom google.cloud import privatecatalog_v1beta1\n\nclient = privatecatalog_v1beta1.PrivateCatalogClient()\nversion_name = client.version_path(\n    catalog=\"my-catalog\",\n    product=\"my-product\",\n    version=\"v1\",\n)\n\nrequest = privatecatalog_v1beta1.SearchVersionsRequest(\n    resource=\"projects/my-project\",\n    query=f\"name={version_name}\",\n)\n\nversion = next(iter(client.search_versions(request=request)), None)\nif version is not None:\n    print(version.name)\n    print(version.asset)\n```\n\nThe `Version` type exposes the validated deployment payload in `asset`. For Terraform-based products, `asset_references` identifies any referenced modules or files that belong to that version.\n\n## Common Pitfalls\n\n- Product naming is inconsistent across surfaces. The product docs live under Service Catalog, but the Python package, import path, and API names still use Private Catalog and `privatecatalog_v1beta1`.\n- The browse API is visibility-scoped. A wrong `resource` string is a common reason for empty results.\n- Use only the documented query forms:\n  - `search_catalogs`: `name=catalogs/{catalog}`\n  - `search_products`: `parent=catalogs/{catalog}` or `name=catalogs/{catalog}/products/{product}`\n  - `search_versions`: `parent=catalogs/{catalog}/products/{product}` or `name=catalogs/{catalog}/products/{product}/versions/{version}`\n- This client browses catalogs, products, and versions. It is not the admin SDK for creating catalogs or sharing them with target resources.\n- The import path is `from google.cloud import privatecatalog_v1beta1`, not `private_catalog` or `service_catalog`.\n- The library is still on a beta API surface. Pin the package version if you need stable behavior across environments.\n\n## Version-Sensitive Notes\n\n- PyPI publishes `google-cloud-private-catalog 0.11.0`, which is the package version covered here.\n- The current Python reference pages under the `latest` docs track still render `0.10.0` on the generated client and type pages. Use PyPI to decide what version to pin, and use the reference pages for request shapes, helper methods, and response fields.\n- The package remains on the `privatecatalog_v1beta1` import path and the PyPI classifiers still mark it as beta. Treat upgrade notes carefully if you are moving between minor releases.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/google-cloud-private-catalog/`\n- Maintainer package directory: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-private-catalog`\n- Python client reference root: `https://cloud.google.com/python/docs/reference/cloudprivatecatalog/latest`\n- `PrivateCatalogClient` reference: `https://cloud.google.com/python/docs/reference/cloudprivatecatalog/latest/google.cloud.privatecatalog_v1beta1.services.private_catalog.PrivateCatalogClient`\n- `SearchCatalogsRequest` reference: `https://cloud.google.com/python/docs/reference/cloudprivatecatalog/latest/google.cloud.privatecatalog_v1beta1.types.SearchCatalogsRequest`\n- `SearchProductsRequest` reference: `https://cloud.google.com/python/docs/reference/cloudprivatecatalog/latest/google.cloud.privatecatalog_v1beta1.types.SearchProductsRequest`\n- `SearchVersionsRequest` reference: `https://cloud.google.com/python/docs/reference/cloudprivatecatalog/latest/google.cloud.privatecatalog_v1beta1.types.SearchVersionsRequest`\n- Service Catalog access control: `https://cloud.google.com/service-catalog/docs/access-control`\n- Service Catalog configuration overview: `https://cloud.google.com/service-catalog/docs/set-service-catalog`\n"
  },
  {
    "path": "content/google/docs/profiler/javascript/DOC.md",
    "content": "---\nname: profiler\ndescription: \"Google Cloud Profiler Node.js agent for starting continuous application profiling from a Node process\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,profiler,performance,observability,javascript,nodejs\"\n---\n\n# `@google-cloud/profiler` JavaScript Package Guide\n\nUse `@google-cloud/profiler` when you want a Node.js process to publish profiling data to Google Cloud Profiler. This package is a startup hook, not a request-scoped client: you configure it once with `start()`, then let it run for the life of the process.\n\n## Golden Rule\n\n- Start the profiler once, as early as practical in process startup.\n- Use Application Default Credentials (ADC) unless you need to pass a project ID or key file explicitly.\n- Set a stable `serviceContext.service` value so profiles for the same service stay grouped together.\n- Set `serviceContext.version` from your deployment version so you can compare releases.\n- Treat profiler startup as optional application infrastructure: log failures, then decide whether the app should continue.\n\nThis guide covers `6.0.4`.\n\n## Install\n\n```bash\nnpm install @google-cloud/profiler@6.0.4\n```\n\n## Prerequisites\n\nBefore starting the agent, make sure the Google Cloud side is ready:\n\n1. Enable the Cloud Profiler API for the target project.\n2. Run the process with credentials that can create profiler profiles.\n3. Decide the service name and version you want to appear in Google Cloud.\n\nEnable the API:\n\n```bash\ngcloud services enable cloudprofiler.googleapis.com \\\n  --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud authentication, not an API key.\n\nFor local development with Application Default Credentials:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nIn production on Google Cloud, prefer an attached service account or workload identity instead of distributing long-lived JSON keys.\n\n## Initialize The Profiler\n\nThe package is typically loaded near the top of your entry file and started before the rest of the app begins serving traffic.\n\n### Minimal Startup Example\n\n```javascript\nconst profiler = require('@google-cloud/profiler');\n\nasync function start() {\n  try {\n    await profiler.start({\n      projectId: process.env.GOOGLE_CLOUD_PROJECT,\n      serviceContext: {\n        service: 'orders-api',\n        version: process.env.K_REVISION || process.env.APP_VERSION || 'dev',\n      },\n    });\n  } catch (error) {\n    console.error('Failed to start Google Cloud Profiler', error);\n  }\n\n  require('./server');\n}\n\nstart();\n```\n\n### Start With An Explicit Key File\n\nUse this when you are not relying on ADC discovery.\n\n```javascript\nconst profiler = require('@google-cloud/profiler');\n\nasync function start() {\n  await profiler.start({\n    projectId: process.env.GOOGLE_CLOUD_PROJECT,\n    keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n    serviceContext: {\n      service: 'orders-api',\n      version: '1.2.3',\n    },\n  });\n}\n\nstart().catch(console.error);\n```\n\n## Common Workflows\n\n### Start Profiling In An HTTP Server Entry Point\n\nInitialize the profiler before creating the HTTP listener.\n\n```javascript\nconst profiler = require('@google-cloud/profiler');\nconst express = require('express');\n\nasync function main() {\n  try {\n    await profiler.start({\n      projectId: process.env.GOOGLE_CLOUD_PROJECT,\n      serviceContext: {\n        service: 'checkout-api',\n        version: process.env.APP_VERSION || 'dev',\n      },\n    });\n  } catch (error) {\n    console.error('Profiler startup failed', error);\n  }\n\n  const app = express();\n\n  app.get('/healthz', (req, res) => {\n    res.send('ok');\n  });\n\n  app.listen(8080, () => {\n    console.log('Listening on :8080');\n  });\n}\n\nmain().catch(console.error);\n```\n\n### Use Stable Service Naming Across Deployments\n\nKeep the service name stable and vary the version by release.\n\n```javascript\nconst profiler = require('@google-cloud/profiler');\n\nasync function startProfiler() {\n  await profiler.start({\n    serviceContext: {\n      service: 'billing-worker',\n      version: process.env.GIT_SHA || 'local-dev',\n    },\n  });\n}\n```\n\nThis keeps profiles for `billing-worker` grouped together while still separating release versions.\n\n### Disable Time Profiling\n\nIf your environment or policy requires turning off time profiling, pass `disableTime` in the startup config.\n\n```javascript\nconst profiler = require('@google-cloud/profiler');\n\nasync function startProfiler() {\n  await profiler.start({\n    serviceContext: {\n      service: 'payments-api',\n      version: '2026-03-13',\n    },\n    disableTime: true,\n  });\n}\n```\n\n## Common Pitfalls\n\n- Do not start the profiler late in your app lifecycle if you want startup behavior included in profiles.\n- Do not change `serviceContext.service` on every deploy; use `serviceContext.version` for release separation instead.\n- Do not commit service account JSON files into your repository.\n- Do not assume project detection always works outside Google Cloud; set `GOOGLE_CLOUD_PROJECT` or `projectId` when needed.\n- Do not skip Cloud Profiler API enablement or IAM setup when startup fails with permission or API errors.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/profiler` version `6.0.4`.\n- The Node.js package is configured through the top-level `start()` call rather than by constructing a long-lived client instance.\n- The package documentation examples use `serviceContext` to identify the profiled service.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/profiler/latest`\n- Cloud Profiler product docs: `https://cloud.google.com/profiler/docs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/profiler`\n"
  },
  {
    "path": "content/google/docs/public-ca/python/DOC.md",
    "content": "---\nname: public-ca\ndescription: \"Google Cloud Public CA Python client for creating ACME external account binding keys\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,cloud,public-ca,certificate-manager,acme,tls,eab\"\n---\n\n# Google Cloud Public CA Python Client\n\n## What It Is\n\n`google-cloud-public-ca` is a narrow client library for Google Cloud Public CA. In `0.3.9`, the Python surface is `google.cloud.security.publicca_v1beta1`, and the main operation is creating an ACME external account binding (EAB) secret for a Google Cloud project.\n\nUse this package when you need to mint the EAB key ID and HMAC that an ACME client such as Certbot uses to register an ACME account with Google Public CA. Certificate issuance, renewal, and challenge handling still happen through the ACME client, not through this Python package.\n\n## Install\n\nPin the version you are actually using:\n\n```bash\npython -m pip install \"google-cloud-public-ca==0.3.9\"\n```\n\n`0.3.9` is published on PyPI as `google-cloud-public-ca`. Newer Google reference docs now describe later releases under `google-cloud-security-publicca`, so keep your lockfile authoritative if your project is pinned to `0.3.9`.\n\n## Prerequisites\n\nBefore calling the client:\n\n1. Create or select a Google Cloud project.\n2. Enable billing on that project.\n3. Enable the Public CA API.\n4. Grant the caller the `roles/publicca.externalAccountKeyCreator` IAM role.\n5. Set up Application Default Credentials (ADC) or pass explicit credentials.\n\nEnable the API:\n\n```bash\ngcloud services enable publicca.googleapis.com\n```\n\nGrant the IAM role:\n\n```bash\ngcloud projects add-iam-policy-binding PROJECT_ID \\\n  --member=\"user:you@example.com\" \\\n  --role=\"roles/publicca.externalAccountKeyCreator\"\n```\n\nSet up local ADC for development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"PROJECT_ID\"\n```\n\nOr point ADC at a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"PROJECT_ID\"\n```\n\n## Client Initialization\n\nWith ADC, the client can usually be created without passing credentials explicitly:\n\n```python\nfrom google.cloud.security import publicca_v1beta1\n\nclient = publicca_v1beta1.PublicCertificateAuthorityServiceClient()\n```\n\nIf you need deterministic credentials in a script or test, pass them directly:\n\n```python\nfrom google.cloud.security import publicca_v1beta1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\n\nclient = publicca_v1beta1.PublicCertificateAuthorityServiceClient(\n    credentials=credentials,\n)\n```\n\n## Create An External Account Binding Key\n\nIn `0.3.9`, the practical workflow is creating an EAB secret for the `global` location and then passing that secret to an ACME client.\n\n```python\nimport os\n\nfrom google.cloud.security import publicca_v1beta1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nparent = f\"projects/{project_id}/locations/global\"\n\nclient = publicca_v1beta1.PublicCertificateAuthorityServiceClient()\n\nresponse = client.create_external_account_key(\n    request=publicca_v1beta1.CreateExternalAccountKeyRequest(\n        parent=parent,\n        external_account_key=publicca_v1beta1.ExternalAccountKey(),\n    )\n)\n\neab_kid = response.key_id\neab_hmac_key = response.b64_mac_key.decode(\"ascii\")\n\nprint(\"EAB key ID:\", eab_kid)\nprint(\"EAB HMAC key:\", eab_hmac_key)\n\nclient.transport.close()\n```\n\nImportant details from the API surface:\n\n- `parent` must be `projects/PROJECT_ID/locations/global`.\n- `external_account_key` is required on the request, but the server currently ignores any fields you set on it. Pass an empty `ExternalAccountKey()`.\n- `response.b64_mac_key` is already a base64url-encoded HMAC value returned as `bytes`. Decode it to text before passing it to an ACME client.\n\n## Use The EAB Secret With Certbot\n\nGoogle documents Public CA as an ACME service. After you create the EAB secret, register an ACME account against the production directory:\n\n```bash\ncertbot register \\\n  --email \"admin@example.com\" \\\n  --no-eff-email \\\n  --server \"https://dv.acme-v02.api.pki.goog/directory\" \\\n  --eab-kid \"$EAB_KID\" \\\n  --eab-hmac-key \"$EAB_HMAC_KEY\"\n```\n\nThen request a certificate through normal ACME flows. For example, a manual DNS challenge:\n\n```bash\ncertbot certonly \\\n  --manual \\\n  --preferred-challenges \"dns-01\" \\\n  --server \"https://dv.acme-v02.api.pki.goog/directory\" \\\n  --domains \"example.com,*.example.com\"\n```\n\nGoogle also documents a staging ACME directory for testing:\n\n```text\nhttps://dv.acme-v02.test-api.pki.goog/directory\n```\n\n## Common Pitfalls\n\n- Do not use `publicca_v1` imports with `0.3.9`. That surface was added in `0.3.10`; `0.3.9` uses `publicca_v1beta1`.\n- Do not expect this package to request or renew certificates directly. It only creates EAB keys; your ACME client handles registration, challenges, issuance, renewal, and revocation.\n- Do not use anything except the `global` location for `parent`; the reference docs say only `global` is supported.\n- Do not re-encode `response.b64_mac_key` with `base64.urlsafe_b64encode(...)`. The value is already base64url-encoded by the service.\n- Do not try to reuse an EAB secret across multiple ACME account registrations. Google documents each EAB secret as single-account and invalid after use.\n\n## Version-Sensitive Notes\n\n- `0.3.9` is the last version covered by the original PyPI package name `google-cloud-public-ca`.\n- The upstream changelog says `0.3.10` added `publicca v1` protos. If you are pinned to `0.3.9`, stay on `publicca_v1beta1`.\n- The upstream changelog for `0.3.9` excludes `google-auth` `2.24.0` and `2.25.0`. If dependency resolution pulls one of those versions, align with the library's published constraints instead of forcing them back in.\n- Google product docs say an unused EAB secret expires after 7 days, while the ACME account registered with that secret does not expire.\n\n## Official Sources\n\n- PyPI package `0.3.9`: `https://pypi.org/project/google-cloud-public-ca/`\n- Google Cloud Python reference root: `https://cloud.google.com/python/docs/reference/publicca/0.3.0`\n- `publicca_v1beta1` service package reference: `https://cloud.google.com/python/docs/reference/publicca/0.3.8/google.cloud.security.publicca_v1beta1.services.public_certificate_authority_service`\n- `ExternalAccountKey` reference: `https://cloud.google.com/python/docs/reference/publicca/0.3.9/google.cloud.security.publicca_v1beta1.types.ExternalAccountKey`\n- Current changelog: `https://docs.cloud.google.com/python/docs/reference/publicca/latest/changelog`\n- Public CA overview: `https://docs.cloud.google.com/certificate-manager/docs/public-ca`\n- Public CA ACME tutorial: `https://docs.cloud.google.com/certificate-manager/docs/public-ca-tutorial`\n- ADC overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/pubsub/javascript/DOC.md",
    "content": "---\nname: pubsub\ndescription: \"Google Cloud Pub/Sub Node.js client for creating topics and subscriptions, publishing messages, consuming messages, and using the local emulator\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,google,gcp,pubsub,messaging,events,javascript,nodejs\"\n---\n\n# `@google-cloud/pubsub` JavaScript Package Guide\n\nUse `@google-cloud/pubsub` in Node.js code that needs to create topics and subscriptions, publish messages, and consume them with a streaming subscriber.\n\n## Golden Rule\n\n- Import `PubSub` from `@google-cloud/pubsub`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass credentials explicitly.\n- Publish message bodies as `Buffer` data.\n- Treat subscriber handlers as idempotent. Pub/Sub delivery is at-least-once by default, so a message can be delivered more than once.\n- Acknowledge messages only after durable processing succeeds.\n\nThis guide covers `5.3.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/pubsub@5.3.0\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nEnable the Pub/Sub API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable pubsub.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimum setup:\n\n1. Create or choose a Google Cloud project.\n2. Enable the Pub/Sub API.\n3. Authenticate with ADC.\n4. Grant the runtime identity permission to publish to the topic or consume from the subscription it uses.\n\nCommon IAM roles:\n\n- `roles/pubsub.publisher` for publishing messages\n- `roles/pubsub.subscriber` for consuming and acknowledging messages\n- `roles/pubsub.editor` for creating and managing topics and subscriptions\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nES modules:\n\n```javascript\nimport {PubSub} from '@google-cloud/pubsub';\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n```\n\nWith an explicit key file:\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Create A Topic And Subscription\n\nCreate the topic first, then create a subscription attached to it.\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function ensureTopicAndSubscription(topicName, subscriptionName) {\n  const [topic] = await pubsub.createTopic(topicName);\n  const [subscription] = await topic.createSubscription(subscriptionName);\n\n  return {\n    topicName: topic.name,\n    subscriptionName: subscription.name,\n  };\n}\n```\n\nIf the topic or subscription may already exist, call `pubsub.topic(topicName)` and `pubsub.subscription(subscriptionName)` to get handles, and handle `AlreadyExists` errors when creating resources.\n\n### Publish A Message\n\nUse `publishMessage()` for new code. Encode structured payloads yourself before publishing.\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nasync function publishOrderCreated(topicName, order) {\n  const topic = pubsub.topic(topicName);\n\n  const messageId = await topic.publishMessage({\n    data: Buffer.from(JSON.stringify(order), 'utf8'),\n    attributes: {\n      eventType: 'order.created',\n      source: 'checkout',\n    },\n  });\n\n  return messageId;\n}\n```\n\nNotes:\n\n- `data` should be a `Buffer`.\n- Message attributes are string key/value pairs.\n- `publishMessage()` resolves to the Pub/Sub message ID.\n\n### Subscribe With A Streaming Message Handler\n\nUse the high-level `Subscription` event interface for the common async worker pattern.\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n});\n\nfunction listenForMessages(subscriptionName) {\n  const subscription = pubsub.subscription(subscriptionName, {\n    flowControl: {\n      maxMessages: 10,\n    },\n  });\n\n  subscription.on('message', message => {\n    try {\n      const body = message.data.toString('utf8');\n      console.log('message id:', message.id);\n      console.log('body:', body);\n      console.log('attributes:', message.attributes);\n\n      message.ack();\n    } catch (error) {\n      message.nack();\n    }\n  });\n\n  subscription.on('error', error => {\n    console.error('subscriber error:', error);\n  });\n\n  return subscription;\n}\n```\n\nNotes:\n\n- `message.data` is binary data. Decode it yourself.\n- Call `message.ack()` only after your application has finished the work that must not be repeated.\n- Call `message.nack()` for retryable failures.\n- The streaming subscriber keeps the process alive until you remove listeners or call `subscription.close()`.\n\n### Use The Emulator For Local Development\n\nStart the Pub/Sub emulator with the Google Cloud CLI:\n\n```bash\ngcloud beta emulators pubsub start\n$(gcloud beta emulators pubsub env-init)\nexport PUBSUB_PROJECT_ID=\"local-project\"\n```\n\nCreate the client against the emulator:\n\n```javascript\nconst {PubSub} = require('@google-cloud/pubsub');\n\nconst pubsub = new PubSub({\n  projectId: process.env.PUBSUB_PROJECT_ID || 'local-project',\n});\n\nasync function seedEmulator() {\n  const topicName = 'demo-topic';\n  const subscriptionName = 'demo-subscription';\n\n  const [topic] = await pubsub.createTopic(topicName);\n  await topic.createSubscription(subscriptionName);\n\n  await topic.publishMessage({\n    data: Buffer.from('hello emulator', 'utf8'),\n  });\n}\n```\n\nWhen `PUBSUB_EMULATOR_HOST` is set, the client connects to the emulator instead of the managed Pub/Sub service.\n\n## Common Pitfalls\n\n- Do not pass a plain string as the message body. Use `Buffer.from(...)`.\n- Do not acknowledge a message before your durable side effects complete.\n- Do not assume a message will only be delivered once. Keep handlers idempotent.\n- Do not confuse handle creation with resource creation. `pubsub.topic(name)` and `pubsub.subscription(name)` return local handles; they do not create server-side resources.\n- Do not rely on emulator behavior for production semantics.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/pubsub` version `5.3.0`.\n- Current Node.js reference material uses `publishMessage()` for publishing. Prefer that method for new code.\n- The high-level JavaScript package uses `PubSub` as the main entry point for both publisher and subscriber workflows.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/pubsub/latest`\n- `PubSub` class reference: `https://cloud.google.com/nodejs/docs/reference/pubsub/latest/pubsub/pubsub`\n- `Topic` class reference: `https://cloud.google.com/nodejs/docs/reference/pubsub/latest/pubsub/topic`\n- `Subscription` class reference: `https://cloud.google.com/nodejs/docs/reference/pubsub/latest/pubsub/subscription`\n- Authentication guide: `https://cloud.google.com/pubsub/docs/authentication`\n- Emulator guide: `https://cloud.google.com/pubsub/docs/emulator`\n"
  },
  {
    "path": "content/google/docs/pubsub/python/DOC.md",
    "content": "---\nname: pubsub\ndescription: \"Google Cloud Pub/Sub Python client library for publishing, subscribing, and local emulator workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.35.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,gcp,pubsub,messaging,events,queues\"\n---\n\n# Google Cloud Pub/Sub Python Client\n\n## Golden Rule\n\nUse `google-cloud-pubsub` for Pub/Sub work in Python, authenticate with Application Default Credentials (ADC), and write subscriber handlers as idempotent code. Pub/Sub delivery is at-least-once by default, so duplicate deliveries are normal unless you explicitly enable exactly-once delivery on the subscription.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-pubsub==2.35.0\"\n```\n\nIf you need the migration helper for older pre-2.0 code:\n\n```bash\npython -m pip install \"google-cloud-pubsub[libcst]==2.35.0\"\n```\n\n## Auth And Setup\n\nPub/Sub client libraries use ADC.\n\nLocal development with user credentials:\n\n```bash\ngcloud init\ngcloud auth application-default login\ngcloud auth application-default set-quota-project YOUR_PROJECT_ID\n```\n\nService account JSON:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nMinimum Google Cloud setup:\n\n1. Create or choose a project.\n2. Enable the Pub/Sub API.\n3. Authenticate with ADC.\n4. Grant the runtime identity Pub/Sub permissions for the topics and subscriptions it uses.\n\n## Initialize Clients\n\n```python\nimport os\nfrom google.cloud import pubsub_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\npublisher = pubsub_v1.PublisherClient()\nsubscriber = pubsub_v1.SubscriberClient()\n\ntopic_path = publisher.topic_path(project_id, \"orders\")\nsubscription_path = subscriber.subscription_path(project_id, \"orders-worker\")\n```\n\nUse `PublisherClient` for topic and publish operations, and `SubscriberClient` for subscription and pull operations.\n\n## Create Topics And Subscriptions\n\nMost generated API methods in the 2.x client accept either a `request={...}` object or flattened keyword arguments. Do not mix both styles in the same call.\n\n```python\nfrom google.api_core.exceptions import AlreadyExists\nfrom google.cloud import pubsub_v1\n\npublisher = pubsub_v1.PublisherClient()\nsubscriber = pubsub_v1.SubscriberClient()\n\ntopic_path = publisher.topic_path(\"my-project\", \"orders\")\nsubscription_path = subscriber.subscription_path(\"my-project\", \"orders-worker\")\n\ntry:\n    publisher.create_topic(request={\"name\": topic_path})\nexcept AlreadyExists:\n    pass\n\ntry:\n    subscriber.create_subscription(\n        request={\n            \"name\": subscription_path,\n            \"topic\": topic_path,\n        }\n    )\nexcept AlreadyExists:\n    pass\n```\n\n## Publish Messages\n\n`publish()` is one of the handwritten methods whose convenient signature stayed stable across the 2.x line. It takes a topic path, raw bytes payload, and optional string attributes.\n\n```python\nimport json\nfrom google.cloud import pubsub_v1\n\npublisher = pubsub_v1.PublisherClient(\n    batch_settings=pubsub_v1.types.BatchSettings(\n        max_bytes=1_000_000,\n        max_latency=0.01,\n        max_messages=100,\n    )\n)\n\ntopic_path = publisher.topic_path(\"my-project\", \"orders\")\n\npayload = json.dumps({\"order_id\": \"123\", \"status\": \"created\"}).encode(\"utf-8\")\nfuture = publisher.publish(\n    topic_path,\n    payload,\n    event_type=\"order.created\",\n    source=\"checkout\",\n)\n\nmessage_id = future.result()\nprint(message_id)\n\n# Flush outstanding publishes before process shutdown.\npublisher.stop()\n```\n\nNotes:\n\n- `data` must be `bytes`, not `str`.\n- Message attributes are strings.\n- Default batch settings are `max_bytes=1_000_000`, `max_latency=0.01`, and `max_messages=100`.\n- If you enable ordered delivery, publish with `ordering_key=...` and call `resume_publish(topic_path, ordering_key)` after a recoverable publish failure for that key.\n\n## Subscribe With A Streaming Callback\n\nUse `subscribe()` for the common async consumer pattern:\n\n```python\nfrom concurrent.futures import TimeoutError\nfrom google.cloud import pubsub_v1\n\nsubscriber = pubsub_v1.SubscriberClient()\nsubscription_path = subscriber.subscription_path(\"my-project\", \"orders-worker\")\n\nflow_control = pubsub_v1.types.FlowControl(\n    max_messages=100,\n    max_bytes=10 * 1024 * 1024,\n)\n\ndef callback(message: pubsub_v1.subscriber.message.Message) -> None:\n    try:\n        body = message.data.decode(\"utf-8\")\n        print(body, dict(message.attributes), message.delivery_attempt)\n        message.ack()\n    except Exception:\n        message.nack()\n\nstreaming_pull_future = subscriber.subscribe(\n    subscription_path,\n    callback=callback,\n    flow_control=flow_control,\n    await_callbacks_on_shutdown=True,\n)\n\nwith subscriber:\n    try:\n        streaming_pull_future.result(timeout=30)\n    except TimeoutError:\n        streaming_pull_future.cancel()\n        streaming_pull_future.result()\n```\n\nNotes:\n\n- Default subscriber flow control is `max_messages=1000`, `max_bytes=100 MiB`, `max_lease_duration=3600`.\n- `message.data` is always `bytes`; decode it yourself.\n- `message.delivery_attempt` is only populated when the subscription has a dead-letter policy.\n- Use `ack()` only after durable processing succeeds.\n- Use `nack()` for retryable failures.\n\n## Exactly-Once Delivery\n\nDefault Pub/Sub acknowledgements are best effort. The client docs explicitly warn that your handler should remain idempotent because messages may be delivered more than once.\n\nIf the subscription has exactly-once delivery enabled, use `ack_with_response()` when you need acknowledgement success tracking:\n\n```python\nack_future = message.ack_with_response()\nack_future.result()\n```\n\nWithout exactly-once delivery, `ack_with_response()` still returns success immediately, but re-delivery is still possible.\n\n## Emulator For Local Tests\n\nStart the local Pub/Sub emulator through the Google Cloud CLI:\n\n```bash\ngcloud beta emulators pubsub start\n$(gcloud beta emulators pubsub env-init)\nexport PUBSUB_PROJECT_ID=\"local-project\"\n```\n\nThe Python client automatically uses `PUBSUB_EMULATOR_HOST` when it is set.\n\nExample against the emulator:\n\n```python\nfrom google.cloud import pubsub_v1\n\nproject_id = \"local-project\"\npublisher = pubsub_v1.PublisherClient()\nsubscriber = pubsub_v1.SubscriberClient()\n\ntopic_path = publisher.topic_path(project_id, \"demo\")\nsubscription_path = subscriber.subscription_path(project_id, \"demo-sub\")\n\npublisher.create_topic(request={\"name\": topic_path})\nsubscriber.create_subscription(request={\"name\": subscription_path, \"topic\": topic_path})\npublisher.publish(topic_path, b\"hello emulator\").result()\n```\n\n## Common Pitfalls\n\n- Do not pass a text string to `publish()`. Encode to bytes first.\n- Do not mix `request={...}` with flattened keyword arguments on the same generated API call.\n- Do not create `SubscriberClient` path helpers with the publisher client. In the 2.x line, `subscription_path()` lives on `SubscriberClient`.\n- Do not assume a successful `ack()` means the message can never be re-delivered. Keep handlers idempotent.\n- Do not let the process exit with pending publish futures. Wait on futures and call `publisher.stop()`.\n- Do not share client instances across forked processes. Create clients after `os.fork()` or inside each worker process.\n- Do not rely on emulator behavior for production semantics. Google documents that the emulator may be incomplete or differ from the real service.\n\n## Version-Sensitive Notes\n\n- `2.35.0` is the latest PyPI release as of March 12, 2026.\n- PyPI requires Python `>=3.9`. The archived Google repository notes that `2.34.0` was the last release supporting Python 3.7 and 3.8.\n- The official 2.0 migration guide still matters when reading older examples: most generated client methods moved to request-object style, while `publish()` and `subscribe()` largely kept their higher-level signatures.\n- In the 2.x API, `request` and flattened keyword arguments are mutually exclusive on generated methods.\n- Google archived the standalone `googleapis/python-pubsub` repository in March 2026 and points maintainers to the `google-cloud-python` monorepo. Prefer the Google Cloud docs site and PyPI metadata over old repository examples when they conflict.\n\n## Official Sources\n\n- Client library reference: `https://cloud.google.com/python/docs/reference/pubsub/latest`\n- Publisher client reference: `https://cloud.google.com/python/docs/reference/pubsub/latest/google.cloud.pubsub_v1.publisher.client.Client`\n- Subscriber client reference: `https://cloud.google.com/python/docs/reference/pubsub/latest/google.cloud.pubsub_v1.subscriber.client.Client`\n- Migration guide: `https://cloud.google.com/python/docs/reference/pubsub/latest/upgrading`\n- Multiprocessing note: `https://cloud.google.com/python/docs/reference/pubsub/latest/multiprocessing`\n- Auth guide: `https://cloud.google.com/pubsub/docs/authentication`\n- Emulator guide: `https://cloud.google.com/pubsub/docs/emulator`\n- Package registry: `https://pypi.org/project/google-cloud-pubsub/`\n"
  },
  {
    "path": "content/google/docs/rapidmigrationassessment/python/DOC.md",
    "content": "---\nname: rapidmigrationassessment\ndescription: \"Google Cloud Rapid Migration Assessment Python client for collector lifecycle management and project annotations\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,rapidmigrationassessment,migration,collector,python\"\n---\n\n# Google Cloud Rapid Migration Assessment Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-rapidmigrationassessment` package with `from google.cloud import rapidmigrationassessment_v1`, and authenticate with Google Cloud Application Default Credentials (ADC).\n\nThis client manages Rapid Migration Assessment control-plane resources such as collectors and annotations. It does not replace the product-side workflow for deploying and running the actual discovery client.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-rapidmigrationassessment==0.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-rapidmigrationassessment==0.3.0\"\npoetry add \"google-cloud-rapidmigrationassessment==0.3.0\"\n```\n\nPyPI for `0.3.0` lists Python `>=3.7`.\n\n## Authentication And Setup\n\nBefore you call the API:\n\n1. Enable Migration Center and the Rapid Migration Assessment API for the target Google Cloud project.\n2. Choose the Google Cloud location where the Migration Center data lives.\n3. Use ADC for local development, CI, and deployed workloads.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nThe product IAM docs list Rapid Migration Assessment roles such as `roles/rma.admin`, `roles/rma.runner`, and `roles/rma.viewer`. For setup and collector management, the broader Migration Center roles and prerequisite permissions in the product docs still matter.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import rapidmigrationassessment_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nPARENT = f\"projects/{PROJECT_ID}/locations/{LOCATION}\"\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\n```\n\nUse fully qualified resource names throughout the API:\n\n- Parent: `projects/{project}/locations/{location}`\n- Collector: `projects/{project}/locations/{location}/collectors/{collector}`\n- Annotation: `projects/{project}/locations/{location}/annotations/{annotation}`\n\n## Common Workflows\n\n### List collectors\n\n```python\nimport os\n\nfrom google.cloud import rapidmigrationassessment_v1\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\nparent = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/locations/{os.environ['GOOGLE_CLOUD_LOCATION']}\"\n\npager = client.list_collectors(\n    request={\n        \"parent\": parent,\n        \"page_size\": 50,\n    }\n)\n\nfor collector in pager:\n    print(collector.name, collector.state.name)\n```\n\n`list_collectors()` returns a pager. Iterate over it directly unless you need manual page-token handling.\n\n### Create a collector\n\n`create_collector()` is a long-running operation. Wait for `.result()` before assuming the collector exists.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import rapidmigrationassessment_v1\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\nparent = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/locations/{os.environ['GOOGLE_CLOUD_LOCATION']}\"\n\noperation = client.create_collector(\n    request={\n        \"parent\": parent,\n        \"collector_id\": \"rma-collector-01\",\n        \"collector\": rapidmigrationassessment_v1.Collector(\n            display_name=\"rma-collector-01\",\n            description=\"Primary VMware assessment collector\",\n            expected_asset_count=250,\n            collection_days=14,\n            labels={\"env\": \"prod\", \"wave\": \"1\"},\n        ),\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\ncollector = operation.result()\n\nprint(collector.name)\nprint(collector.state.name)\nprint(collector.service_account)\nprint(collector.eula_uri)\n```\n\nPractical note: the REST resource marks fields such as `guest_os_scan`, `vsphere_scan`, `bucket`, `client_version`, and `state` as output only. Do not try to send those in your create body.\n\n### Get one collector\n\n```python\nfrom google.cloud import rapidmigrationassessment_v1\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\n\ncollector = client.get_collector(\n    request={\n        \"name\": \"projects/your-project-id/locations/us-central1/collectors/rma-collector-01\",\n    }\n)\n\nprint(collector.name)\nprint(collector.display_name)\nprint(collector.state.name)\n```\n\n### Register, pause, and resume a collector\n\nThese lifecycle methods return long-running operations.\n\n```python\nimport uuid\n\nfrom google.cloud import rapidmigrationassessment_v1\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\nname = \"projects/your-project-id/locations/us-central1/collectors/rma-collector-01\"\n\nclient.register_collector(\n    request={\n        \"name\": name,\n        \"request_id\": str(uuid.uuid4()),\n    }\n).result()\n\nclient.pause_collector(\n    request={\n        \"name\": name,\n        \"request_id\": str(uuid.uuid4()),\n    }\n).result()\n\nclient.resume_collector(\n    request={\n        \"name\": name,\n        \"request_id\": str(uuid.uuid4()),\n    }\n).result()\n```\n\nUse a fresh UUID `request_id` on mutating requests when you want retry-safe deduplication.\n\n### Update mutable collector fields\n\nUse `update_mask` so the API only changes the fields you intend to change.\n\n```python\nimport uuid\n\nfrom google.cloud import rapidmigrationassessment_v1\nfrom google.protobuf import field_mask_pb2\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\n\ncollector = rapidmigrationassessment_v1.Collector(\n    name=\"projects/your-project-id/locations/us-central1/collectors/rma-collector-01\",\n    display_name=\"rma-collector-prod\",\n    description=\"Collector for the production VMware estate\",\n    labels={\"env\": \"prod\", \"owner\": \"platform\"},\n    collection_days=21,\n)\n\noperation = client.update_collector(\n    request={\n        \"collector\": collector,\n        \"update_mask\": field_mask_pb2.FieldMask(\n            paths=[\"display_name\", \"description\", \"labels\", \"collection_days\"]\n        ),\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\nupdated = operation.result()\nprint(updated.display_name)\nprint(updated.collection_days)\n```\n\n### Delete a collector\n\n```python\nimport uuid\n\nfrom google.cloud import rapidmigrationassessment_v1\n\nclient = rapidmigrationassessment_v1.RapidMigrationAssessmentClient()\n\nclient.delete_collector(\n    request={\n        \"name\": \"projects/your-project-id/locations/us-central1/collectors/rma-collector-01\",\n        \"request_id\": str(uuid.uuid4()),\n    }\n).result()\n```\n\n## Configuration Notes And Pitfalls\n\n- Resource names are location-scoped. If `parent` or `name` points at the wrong location, the API will not find your collectors.\n- Mutating methods such as `create_collector()`, `register_collector()`, `pause_collector()`, `resume_collector()`, `update_collector()`, and `delete_collector()` return long-running operations. Call `.result()` before you depend on the side effect.\n- Use `update_mask` on updates. Sending a partial `Collector` without a mask is not the safe default.\n- Generated Google Cloud Python clients can emit structured logging if you set `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`, for example `google`. Treat that as opt-in because logs can still include operational metadata.\n- As of 2026-03-13, PyPI lists `google-cloud-rapidmigrationassessment 0.3.0`, while the public Google Cloud Python reference pages visible for this library are labeled with older generated doc versions. Pin the package version you install instead of assuming the reference page label matches PyPI.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-rapidmigrationassessment/\n- Python client reference root: https://cloud.google.com/python/docs/reference/rapidmigrationassessment/latest\n- `RapidMigrationAssessmentClient` reference: https://cloud.google.com/python/docs/reference/rapidmigrationassessment/latest/google.cloud.rapidmigrationassessment_v1.services.rapid_migration_assessment.RapidMigrationAssessmentClient\n- `Collector` type reference: https://cloud.google.com/python/docs/reference/rapidmigrationassessment/latest/google.cloud.rapidmigrationassessment_v1.types.Collector\n- Product IAM and permissions: https://cloud.google.com/migration-center/docs/rapidmigrationassessment/iam-permissions\n- REST collector resource: https://cloud.google.com/migration-center/docs/rapidmigrationassessment/reference/rest/v1/projects.locations.collectors\n- REST create collector method: https://cloud.google.com/migration-center/docs/rapidmigrationassessment/reference/rest/v1/projects.locations.collectors/create\n- REST annotations resource: https://cloud.google.com/migration-center/docs/rapidmigrationassessment/reference/rest/v1/projects.locations.annotations\n- Changelog: https://cloud.google.com/python/docs/reference/rapidmigrationassessment/latest/changelog\n"
  },
  {
    "path": "content/google/docs/recaptcha-enterprise/javascript/DOC.md",
    "content": "---\nname: recaptcha-enterprise\ndescription: \"Google Cloud reCAPTCHA Enterprise Node.js client for backend assessments, annotations, keys, and key metrics\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,recaptcha-enterprise,security,fraud-detection,javascript,nodejs\"\n---\n\n# `@google-cloud/recaptcha-enterprise` JavaScript Package Guide\n\nUse `@google-cloud/recaptcha-enterprise` in backend Node.js code to create reCAPTCHA Enterprise assessments, send fraud annotations, manage keys, and read key metrics.\n\n## Golden Rule\n\nUse this package only on trusted server-side code. Your frontend should obtain a reCAPTCHA token and send it to your backend, and your backend should call `createAssessment()`.\n\n- Import the client from the `v1` namespace.\n- Authenticate with Application Default Credentials (ADC) or a service account.\n- Enable billing and `recaptchaenterprise.googleapis.com` before debugging library code.\n- Pass full resource names such as `projects/PROJECT_ID` and `projects/PROJECT_ID/keys/KEY_ID`.\n- Prefer `v1` over older `v1beta1` examples.\n\nThis guide covers `6.4.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/recaptcha-enterprise@6.4.0\n```\n\n## Authentication And Setup\n\nBefore calling the API, the product docs say you need to:\n\n1. Create or choose a Google Cloud project.\n2. Enable billing.\n3. Enable the reCAPTCHA Enterprise API.\n4. Create a reCAPTCHA Enterprise key for your site or app.\n5. Set up credentials for the backend that will call the API.\n\nFor website assessments, the product docs also call out the `reCAPTCHA Enterprise Agent` role, `roles/recaptchaenterprise.agent`, and recommend creating assessments only on your backend.\n\nEnable the API in the caller project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable recaptchaenterprise.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport RECAPTCHA_SITE_KEY=\"your-site-key\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport RECAPTCHA_SITE_KEY=\"your-site-key\"\n```\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/recaptcha-enterprise';\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Create An Assessment\n\nThis is the main backend flow for website score-based or checkbox integrations. Your frontend obtains a token and sends it to your server, and your server creates the assessment.\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n\nasync function createAssessment({\n  projectId = process.env.GOOGLE_CLOUD_PROJECT,\n  siteKey = process.env.RECAPTCHA_SITE_KEY,\n  token,\n  expectedAction,\n  userIpAddress,\n  userAgent,\n}) {\n  const [response] = await client.createAssessment({\n    parent: `projects/${projectId}`,\n    assessment: {\n      event: {\n        siteKey,\n        token,\n        expectedAction,\n        userIpAddress,\n        userAgent,\n      },\n    },\n  });\n\n  if (!response.tokenProperties?.valid) {\n    throw new Error('reCAPTCHA token was rejected');\n  }\n\n  if (response.tokenProperties.action !== expectedAction) {\n    throw new Error(\n      `Action mismatch: expected ${expectedAction}, got ${response.tokenProperties.action}`\n    );\n  }\n\n  return {\n    assessmentName: response.name,\n    score: response.riskAnalysis?.score ?? null,\n    reasons: response.riskAnalysis?.reasons ?? [],\n  };\n}\n```\n\nImportant fields from the response:\n\n- `response.tokenProperties.valid` tells you whether the token was accepted.\n- `response.tokenProperties.action` must match your expected action in action-based flows.\n- `response.riskAnalysis.score` is the risk score you use for allow, challenge, or block decisions.\n- `response.riskAnalysis.reasons` contains classifier reasons for higher-risk outcomes.\n- `response.name` is the assessment resource name you reuse later for annotation.\n\n### Annotate An Assessment\n\nIf you later learn whether the interaction was legitimate or fraudulent, send that result back with `annotateAssessment()`. The product docs say this improves site-specific model performance over time.\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n\nasync function annotateFraudulentAssessment(assessmentName) {\n  await client.annotateAssessment({\n    name: assessmentName,\n    annotation: 'FRAUDULENT',\n    reasons: ['FAILED_TWO_FACTOR'],\n  });\n}\n```\n\nStore and reuse the full `response.name` returned by `createAssessment()` so you can pass it directly as `assessmentName`.\n\n### Create A Score-Based Website Key\n\nIf you manage reCAPTCHA Enterprise keys programmatically, create a web key with `createKey()`:\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n\nasync function createScoreKey(domainName) {\n  const [key] = await client.createKey({\n    parent: `projects/${process.env.GOOGLE_CLOUD_PROJECT}`,\n    key: {\n      displayName: 'primary-web-key',\n      webSettings: {\n        allowedDomains: [domainName],\n        allowAmpTraffic: false,\n        integrationType: 'SCORE',\n      },\n    },\n  });\n\n  return key.name;\n}\n```\n\nThe returned `key.name` looks like `projects/PROJECT_ID/keys/KEY_ID`. Persist that full resource name instead of rebuilding it later.\n\n### Get An Existing Key\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n\nasync function getKey() {\n  const [key] = await client.getKey({\n    name: 'projects/PROJECT_ID/keys/KEY_ID',\n  });\n\n  return key;\n}\n```\n\n### Get Metrics For A Key\n\nUse `getMetrics()` to inspect key performance. The metrics resource name is the key resource name with `/metrics` appended.\n\n```javascript\nconst {v1} = require('@google-cloud/recaptcha-enterprise');\n\nconst client = new v1.RecaptchaEnterpriseServiceClient();\n\nasync function getKeyMetrics(keyName) {\n  const [metrics] = await client.getMetrics({\n    name: `${keyName}/metrics`,\n  });\n\n  return {\n    scoreMetrics: metrics.scoreMetrics ?? [],\n    challengeMetrics: metrics.challengeMetrics ?? [],\n  };\n}\n```\n\nUse `scoreMetrics` for score-based keys and `challengeMetrics` for challenge-style keys.\n\n## Common Pitfalls\n\n- Create assessments only on your backend. The product docs explicitly warn against creating them in the browser because attackers can forge those requests.\n- Tokens are single-use and expire after two minutes. If the user retries later, obtain a fresh token on the client.\n- Always verify `response.tokenProperties.action === expectedAction` for action-based flows.\n- Keep the assessment resource name returned by `createAssessment()`. You need it for `annotateAssessment()`.\n- Enable billing before debugging library code. Assessment calls stop once you exhaust the free monthly quota and do not have billing enabled.\n- Reuse a client instance instead of constructing a new one for every request path.\n- This package is for server-side API calls. It does not render widgets or mint browser tokens for you.\n\n## Version-Sensitive Notes\n\n- This guide covers `@google-cloud/recaptcha-enterprise` version `6.4.0`.\n- Older examples may still show `v1beta1`; prefer the `v1` surface for new work.\n- Keep your installed package version pinned when you copy request shapes into long-lived services.\n\n## Official Sources\n\n- npm package: `https://www.npmjs.com/package/@google-cloud/recaptcha-enterprise`\n- Node.js client library reference root: `https://cloud.google.com/nodejs/docs/reference/recaptcha-enterprise/latest`\n- Product docs: `https://cloud.google.com/recaptcha/docs/create-assessment-website`\n- Product samples:\n  - `https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-create-assessment`\n  - `https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-annotate-assessment`\n  - `https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-create-site-key`\n  - `https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-get-metrics-site-key`\n- Auth docs:\n  - `https://cloud.google.com/docs/authentication/application-default-credentials`\n  - `https://docs.cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/recaptcha-enterprise/python/DOC.md",
    "content": "---\nname: recaptcha-enterprise\ndescription: \"Google Cloud reCAPTCHA Enterprise Python client for assessments, key management, and metrics\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.30.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,recaptcha-enterprise,security,fraud-detection\"\n---\n\n# Google Cloud reCAPTCHA Enterprise Python Client\n\n## Golden Rule\n\nUse `google-cloud-recaptcha-enterprise` for Python integrations with reCAPTCHA Enterprise, create assessments on your backend, and prefer the `v1` API surface over older `v1beta1` examples.\n\nThe package version validated for this doc is `1.30.0` from PyPI. The official import path is:\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n```\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-recaptcha-enterprise==1.30.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-recaptcha-enterprise==1.30.0\"\npoetry add \"google-cloud-recaptcha-enterprise==1.30.0\"\n```\n\n## Required Setup\n\nBefore the client works, Google’s product docs say you must:\n\n1. Select or create a Google Cloud project.\n2. Enable billing.\n3. Enable the reCAPTCHA Enterprise API.\n4. Set up authentication.\n\nFor website assessments, the product docs also call out the `reCAPTCHA Enterprise Agent` role (`roles/recaptchaenterprise.agent`) and recommend creating assessments only on your backend.\n\n## Authentication\n\n### Preferred: Application Default Credentials\n\nOn local development machines, use ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nAt runtime, the library follows normal ADC lookup order. The most common inputs are:\n\n- `GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json`\n- Local ADC created by `gcloud auth application-default login`\n- An attached service account when running on Google Cloud\n\nBasic client creation:\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\nclient = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\n```\n\n### Service Account File\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\nclient = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\n```\n\n### API Key for Python Client Libraries\n\nThe reCAPTCHA product docs explicitly say Python client libraries can use API keys or Workload Identity Federation outside Google Cloud. Google API Core exposes API-key auth through `ClientOptions`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import recaptchaenterprise_v1\n\nclient = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient(\n    client_options=ClientOptions(api_key=\"YOUR_API_KEY\")\n)\n```\n\nUse ADC or Workload Identity Federation for server-side production systems when possible. If you do use an API key, restrict it.\n\n## Create An Assessment\n\nThis is the core flow for score-based or checkbox website integrations:\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\ndef create_assessment(\n    project_id: str,\n    site_key: str,\n    token: str,\n    expected_action: str,\n    user_ip_address: str,\n    user_agent: str,\n    ja3: str | None = None,\n):\n    client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\n\n    event = recaptchaenterprise_v1.Event(\n        site_key=site_key,\n        token=token,\n        expected_action=expected_action,\n        user_ip_address=user_ip_address,\n        user_agent=user_agent,\n        ja3=ja3 or \"\",\n    )\n    assessment = recaptchaenterprise_v1.Assessment(event=event)\n    request = recaptchaenterprise_v1.CreateAssessmentRequest(\n        parent=f\"projects/{project_id}\",\n        assessment=assessment,\n    )\n\n    response = client.create_assessment(request=request)\n\n    if not response.token_properties.valid:\n        invalid_reason = response.token_properties.invalid_reason.name\n        raise ValueError(f\"Invalid token: {invalid_reason}\")\n\n    if response.token_properties.action != expected_action:\n        raise ValueError(\n            f\"Action mismatch: expected {expected_action}, \"\n            f\"got {response.token_properties.action}\"\n        )\n\n    return {\n        \"assessment_name\": response.name,\n        \"score\": response.risk_analysis.score,\n        \"reasons\": [reason.name for reason in response.risk_analysis.reasons],\n    }\n```\n\nImportant fields from the response:\n\n- `response.token_properties.valid`: whether the token was accepted\n- `response.token_properties.action`: must match your expected action for action-based integrations\n- `response.risk_analysis.score`: risk score used for your allow/challenge/block logic\n- `response.risk_analysis.reasons`: classifier reasons that explain higher-risk outcomes\n- `response.name`: assessment resource name, reused later for annotation\n\n## Annotate Assessments\n\nIf you later learn whether an interaction was legitimate or fraudulent, send that feedback back to reCAPTCHA. Product docs say this improves site-specific model performance over time.\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\ndef annotate_fraudulent_assessment(project_id: str, assessment_id: str) -> None:\n    client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\n\n    request = recaptchaenterprise_v1.AnnotateAssessmentRequest(\n        name=f\"projects/{project_id}/assessments/{assessment_id}\",\n        annotation=recaptchaenterprise_v1.AnnotateAssessmentRequest.Annotation.FRAUDULENT,\n        reasons=[\n            recaptchaenterprise_v1.AnnotateAssessmentRequest.Reason.FAILED_TWO_FACTOR,\n        ],\n    )\n\n    client.annotate_assessment(request=request)\n```\n\nIf you stored the full assessment resource name from `create_assessment`, you can pass that directly as `name` instead of rebuilding it.\n\n## Key Management\n\n### Create a score-based website key\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\ndef create_score_key(project_id: str, domain_name: str) -> str:\n    client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\n\n    web_settings = recaptchaenterprise_v1.WebKeySettings(\n        allowed_domains=[domain_name],\n        allow_amp_traffic=False,\n        integration_type=recaptchaenterprise_v1.WebKeySettings.IntegrationType.SCORE,\n    )\n    key = recaptchaenterprise_v1.Key(\n        display_name=\"primary-web-key\",\n        web_settings=web_settings,\n    )\n\n    response = client.create_key(\n        request=recaptchaenterprise_v1.CreateKeyRequest(\n            parent=f\"projects/{project_id}\",\n            key=key,\n        )\n    )\n    return response.name\n```\n\n### Get an existing key\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\nclient = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\nkey = client.get_key(name=\"projects/PROJECT_ID/keys/KEY_ID\")\n```\n\n### Fetch metrics for a key\n\n```python\nfrom google.cloud import recaptchaenterprise_v1\n\nclient = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()\nmetrics = client.get_metrics(name=\"projects/PROJECT_ID/keys/KEY_ID/metrics\")\n\nfor day_metric in metrics.score_metrics:\n    print(day_metric.overall_metrics.score_buckets)\n```\n\nUse `metrics.score_metrics` for score-based keys and `metrics.challenge_metrics` for checkbox-style challenge keys.\n\n## Async Client\n\nThe generated async surface is available if your app already uses `asyncio`:\n\n```python\nimport asyncio\nfrom google.cloud import recaptchaenterprise_v1\n\nasync def main() -> None:\n    client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceAsyncClient()\n    metrics = await client.get_metrics(\n        name=\"projects/PROJECT_ID/keys/KEY_ID/metrics\"\n    )\n    print(metrics.name)\n\nasyncio.run(main())\n```\n\n## Common Pitfalls\n\n- Create assessments only on your backend. Google’s product docs explicitly warn against creating them in the browser because attackers can forge those requests.\n- Tokens are single-use and expire after two minutes. If the frontend action is retried later, obtain a fresh token.\n- Always verify `response.token_properties.action == expected_action` for action-based flows. A mismatch is a fraud signal.\n- Pass extra context such as `userAgent`, `userIpAddress`, and TLS fingerprints (`ja3` or `ja4`) when available. Google’s docs recommend them to improve detection quality.\n- Keep and reuse the assessment resource name. You need it for later annotation.\n- Enable billing before debugging library code. Assessment calls stop once you exhaust the free monthly quota and do not have billing enabled.\n- Reuse clients instead of creating a new client object for every request path in hot code.\n- Prefer the `v1` API. Product docs explicitly recommend migrating away from `v1beta1` for newer features.\n\n## Version-Sensitive Notes\n\n- PyPI shows `1.30.0` as the current release for this package, published on January 15, 2026.\n- The generated Google Cloud reference site is authoritative for API surface shape, but its `latest` class pages can lag in the visible version label. Validate the installed package version against PyPI when version precision matters.\n- The current package still targets Python `>=3.7`, but for new projects you should align with a currently supported Python runtime in your deployment environment.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-recaptcha-enterprise/\n- Client library reference root: https://cloud.google.com/python/docs/reference/recaptchaenterprise/latest/index.html\n- Client class reference: https://cloud.google.com/python/docs/reference/recaptchaenterprise/latest/google.cloud.recaptchaenterprise_v1.services.recaptcha_enterprise_service.RecaptchaEnterpriseServiceClient\n- Product docs: https://cloud.google.com/recaptcha/docs/create-assessment-website\n- Product samples:\n  - https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-create-assessment\n  - https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-annotate-assessment\n  - https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-create-site-key\n  - https://cloud.google.com/recaptcha/docs/samples/recaptcha-enterprise-get-metrics-site-key\n- Auth docs:\n  - https://cloud.google.com/docs/authentication/application-default-credentials\n  - https://docs.cloud.google.com/docs/authentication/provide-credentials-adc\n  - https://googleapis.dev/python/google-api-core/latest/client_options.html\n"
  },
  {
    "path": "content/google/docs/recommendations-ai/python/DOC.md",
    "content": "---\nname: recommendations-ai\ndescription: \"Google Cloud Recommendations AI Python client for catalog ingestion, recommendation prediction, and user event logging\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,recommendations-ai,recommendationengine,ecommerce,personalization\"\n---\n\n# Google Cloud Recommendations AI Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-recommendations-ai` package, authenticate with Application Default Credentials (ADC), and build requests against the `recommendationengine_v1beta1` namespace.\n\nThe package is still generated around the Recommendations AI `v1beta1` API surface, so the safest path is to stick to the documented service clients:\n\n- `CatalogServiceClient` for catalog items\n- `PredictionServiceClient` for recommendation calls\n- `UserEventServiceClient` for event ingestion\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-recommendations-ai==0.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-recommendations-ai==0.12.0\"\npoetry add \"google-cloud-recommendations-ai==0.12.0\"\n```\n\n## Authentication And Setup\n\nBefore client code works, Google says you need to:\n\n1. Select or create a Google Cloud project.\n2. Enable billing.\n3. Enable Recommendations AI.\n4. Set up authentication.\n\nFor local development, use ADC with `gcloud`:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\nexport GOOGLE_CLOUD_CATALOG=\"default_catalog\"\nexport GOOGLE_CLOUD_EVENT_STORE=\"default_event_store\"\nexport RECOMMENDATIONS_PLACEMENT=\"home_page\"\n```\n\nIf you must use a service account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nFor production on Google Cloud, prefer attaching a service account to the workload instead of shipping JSON keys.\n\n## Initialize Clients And Resource Names\n\nMost request failures come from malformed resource names. Use the helper methods on the generated clients instead of hand-assembling long strings.\n\n```python\nimport os\n\nfrom google.cloud import recommendationengine_v1beta1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.getenv(\"GOOGLE_CLOUD_LOCATION\", \"global\")\nCATALOG_ID = os.getenv(\"GOOGLE_CLOUD_CATALOG\", \"default_catalog\")\nEVENT_STORE_ID = os.getenv(\"GOOGLE_CLOUD_EVENT_STORE\", \"default_event_store\")\nPLACEMENT_ID = os.getenv(\"RECOMMENDATIONS_PLACEMENT\", \"home_page\")\n\ncatalog_client = recommendationengine_v1beta1.CatalogServiceClient()\nprediction_client = recommendationengine_v1beta1.PredictionServiceClient()\nuser_event_client = recommendationengine_v1beta1.UserEventServiceClient()\n\ncatalog_name = catalog_client.catalog_path(PROJECT_ID, LOCATION, CATALOG_ID)\nevent_store_name = user_event_client.event_store_path(\n    PROJECT_ID,\n    LOCATION,\n    CATALOG_ID,\n    EVENT_STORE_ID,\n)\nplacement_name = prediction_client.placement_path(\n    PROJECT_ID,\n    LOCATION,\n    CATALOG_ID,\n    EVENT_STORE_ID,\n    PLACEMENT_ID,\n)\n```\n\nImportant formats from the reference:\n\n- Catalog: `projects/*/locations/global/catalogs/default_catalog`\n- Event store: `projects/*/locations/global/catalogs/default_catalog/eventStores/default_event_store`\n- Placement: `projects/*/locations/global/catalogs/default_catalog/eventStores/default_event_store/placements/*`\n\n## Create Or Import Catalog Items\n\n### Create one catalog item\n\n`CatalogItem.id`, `CatalogItem.category_hierarchies`, and `CatalogItem.title` are required.\n\n```python\nfrom google.cloud import recommendationengine_v1beta1\n\ncatalog_item = recommendationengine_v1beta1.CatalogItem(\n    id=\"sku-123\",\n    title=\"Trail Runner 2\",\n    category_hierarchies=[\n        recommendationengine_v1beta1.CatalogItem.CategoryHierarchy(\n            categories=[\"Shoes\", \"Running\"]\n        )\n    ],\n    description=\"Neutral daily running shoe\",\n)\n\ncreated = catalog_client.create_catalog_item(\n    parent=catalog_name,\n    catalog_item=catalog_item,\n)\n\nprint(created.id)\n```\n\n### Bulk import catalog items\n\n`import_catalog_items()` is the normal bulk-ingestion path. The official docs say it may run synchronously, does not support partial updates, and creates missing items.\n\nFor small batches, use the inline source:\n\n```python\nfrom google.cloud import recommendationengine_v1beta1\n\nitems = [\n    recommendationengine_v1beta1.CatalogItem(\n        id=\"sku-123\",\n        title=\"Trail Runner 2\",\n        category_hierarchies=[\n            recommendationengine_v1beta1.CatalogItem.CategoryHierarchy(\n                categories=[\"Shoes\", \"Running\"]\n            )\n        ],\n    ),\n    recommendationengine_v1beta1.CatalogItem(\n        id=\"sku-456\",\n        title=\"Daily Trainer\",\n        category_hierarchies=[\n            recommendationengine_v1beta1.CatalogItem.CategoryHierarchy(\n                categories=[\"Shoes\", \"Training\"]\n            )\n        ],\n    ),\n]\n\noperation = catalog_client.import_catalog_items(\n    request=recommendationengine_v1beta1.ImportCatalogItemsRequest(\n        parent=catalog_name,\n        input_config=recommendationengine_v1beta1.InputConfig(\n            catalog_inline_source=recommendationengine_v1beta1.CatalogInlineSource(\n                catalog_items=items\n            )\n        ),\n    )\n)\n\nresponse = operation.result()\nprint(response)\n```\n\nThe generated references document the inline source as a list of catalog items and recommend keeping it to about 10,000 items max. For larger feeds, move the input source to GCS instead of sending everything inline.\n\n### List catalog items\n\n`list_catalog_items()` returns a pager:\n\n```python\npager = catalog_client.list_catalog_items(parent=catalog_name)\n\nfor item in pager:\n    print(item.id, item.title)\n```\n\n## Request Recommendations\n\n`PredictionServiceClient.predict()` takes a placement and a contextual `UserEvent`. The response is pageable, so iterating the result automatically handles additional pages.\n\n```python\nfrom google.cloud import recommendationengine_v1beta1\n\nresponse = prediction_client.predict(\n    request=recommendationengine_v1beta1.PredictRequest(\n        name=placement_name,\n        user_event=recommendationengine_v1beta1.UserEvent(\n            event_type=\"home-page-view\",\n            user_info=recommendationengine_v1beta1.UserInfo(\n                visitor_id=\"visitor-123\"\n            ),\n        ),\n    )\n)\n\nfor result in response:\n    print(result.id)\n```\n\nDefault placement IDs documented in the Python reference include:\n\n- `home_page`\n- `product_detail`\n- `shopping_cart`\n- `recently_viewed_default`\n\nUse `home_page` when you want generic \"recommended for you\" output. Use the other placements only when your event context actually matches that page or flow.\n\n## Write And Inspect User Events\n\nPredictions are better when you keep writing real user behavior back to the event store. The reference docs also note that the inline `user_event` you send to `predict()` is not written to the event logs, so you still need a separate `write_user_event()` call for logging and training data.\n\n```python\nfrom google.cloud import recommendationengine_v1beta1\n\nlogged_event = recommendationengine_v1beta1.UserEvent(\n    event_type=\"home-page-view\",\n    user_info=recommendationengine_v1beta1.UserInfo(\n        visitor_id=\"visitor-123\"\n    ),\n)\n\nwritten = user_event_client.write_user_event(\n    parent=event_store_name,\n    user_event=logged_event,\n)\n\nprint(written.event_type)\n```\n\nTo inspect what was recorded:\n\n```python\npager = user_event_client.list_user_events(parent=event_store_name)\n\nfor event in pager:\n    print(event.event_type)\n```\n\nFor historical backfills, use `import_user_events()`. The official docs say existing events are skipped and the method is intended for backfilling old data, not normal real-time logging.\n\n## Endpoint And Client Options\n\nThe generated client docs repeatedly warn that you may need to specify a regional endpoint when creating the client. When Google tells you to do that for your deployment, pass it through `ClientOptions`.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import recommendationengine_v1beta1\n\nclient = recommendationengine_v1beta1.PredictionServiceClient(\n    client_options=ClientOptions(api_endpoint=\"YOUR_ENDPOINT\")\n)\n```\n\nThe same client docs also note:\n\n- `api_endpoint` overrides the default endpoint\n- `universe_domain` can override the default `googleapis.com` universe\n- `universe_domain` is not supported for mTLS\n\n## Common Pitfalls\n\n- Do not call `collect_user_event()` from normal server code. The reference docs say it exists only for the Recommendations AI JavaScript pixel.\n- Do not assume `predict()` logs behavior. It does not; log a separate user event if you want the interaction stored.\n- Keep using resource helper methods for catalog, event store, and placement names. Most `NOT_FOUND` and `INVALID_ARGUMENT` failures are path mistakes.\n- `CatalogItem.category_hierarchies` is required. A title and ID alone are not enough.\n- `import_catalog_items()` is not a patch API. The docs explicitly say partial updates are not supported there; use `update_catalog_item()` when you need patch-style changes.\n- Treat the pager return types as lazy iterators. Extra RPCs happen as you iterate.\n- If you share transports across clients, do not casually wrap one client in `with ...:` and then reuse the others. The generated docs warn that exiting the context manager closes the transport.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `google-cloud-recommendations-ai 0.12.0`, released on January 15, 2026.\n- The hosted Python docs are in a mixed rollout state:\n  - `PredictionServiceClient` renders as `0.12.0`\n  - `CatalogServiceClient` renders as `0.11.0`\n  - `UserEventServiceClient` renders as `0.11.0`\n  - the hosted changelog still stops at `0.11.0`\n- When the installed package and hosted reference disagree, use PyPI for the package version you pin and the class reference pages for the request and response shapes you are actually calling.\n\n## Official Sources\n\n- Python client library overview: `https://cloud.google.com/python/docs/reference/recommendationengine/latest`\n- Package README in `google-cloud-python`: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-recommendations-ai`\n- PyPI package page: `https://pypi.org/project/google-cloud-recommendations-ai/`\n- Google Cloud auth for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- `CatalogServiceClient` reference: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/google.cloud.recommendationengine_v1beta1.services.catalog_service.CatalogServiceClient`\n- `CatalogItem` reference: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/google.cloud.recommendationengine_v1beta1.types.CatalogItem`\n- `PredictionServiceClient` reference: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/google.cloud.recommendationengine_v1beta1.services.prediction_service.PredictionServiceClient`\n- `UserEventServiceClient` reference: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/google.cloud.recommendationengine_v1beta1.services.user_event_service.UserEventServiceClient`\n- `UserEvent` reference: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/google.cloud.recommendationengine_v1beta1.types.UserEvent`\n- Hosted changelog: `https://cloud.google.com/python/docs/reference/recommendationengine/latest/changelog`\n"
  },
  {
    "path": "content/google/docs/recommender/python/DOC.md",
    "content": "---\nname: recommender\ndescription: \"Google Cloud Recommender Python client for listing recommendations and insights and updating their state\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.20.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,recommender,active-assist,gcp,optimization,python\"\n---\n\n# Google Cloud Recommender Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-recommender` package with Application Default Credentials (ADC), and treat Recommender as a metadata and workflow API:\n\n- Recommender lists recommendations and insights.\n- Recommender state changes require the current `etag`.\n- Applying a recommendation is usually a separate product-specific API call against the resource named in the recommendation content.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-recommender==2.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-recommender==2.20.0\"\npoetry add \"google-cloud-recommender==2.20.0\"\n```\n\nPyPI currently lists support for Python 3.7 and newer.\n\n## Authentication And Setup\n\nBefore calling the API:\n\n1. Enable the Recommender API for the target Google Cloud project.\n2. Authenticate with ADC.\n3. Choose the exact recommender ID, insight type ID, and location for the product you are targeting.\n\nLocal ADC setup:\n\n```bash\ngcloud services enable recommender.googleapis.com\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT_NUMBER=\"123456789012\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1-a\"\nexport GOOGLE_CLOUD_RECOMMENDER_ID=\"google.compute.instance.MachineTypeRecommender\"\nexport GOOGLE_CLOUD_INSIGHT_TYPE_ID=\"google.compute.instance.IdleResourceInsight\"\n```\n\nService account fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT_NUMBER=\"123456789012\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1-a\"\n```\n\nNotes:\n\n- For API requests, Google documents that you can use a project ID or project number, and recommends the project number.\n- Location and recommender or insight type are required for the GA API flow.\n- Recommender IDs and supported locations vary by product. Verify them against the Recommenders and Insight types tables before copying an example.\n- Required IAM permissions also vary by recommender and insight type. Check the product tables before assuming a broad viewer or editor role is enough.\n\n## Initialize A Client\n\nDefault client with ADC:\n\n```python\nfrom google.cloud import recommender_v1\n\nclient = recommender_v1.RecommenderClient()\n```\n\nExplicit service account credentials:\n\n```python\nfrom google.cloud import recommender_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = recommender_v1.RecommenderClient(credentials=credentials)\n```\n\nBuild a project-scoped recommender resource name:\n\n```python\nimport os\n\nfrom google.cloud import recommender_v1\n\nclient = recommender_v1.RecommenderClient()\n\nparent = client.recommender_path(\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT_NUMBER\"],\n    location=os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    recommender=os.environ[\"GOOGLE_CLOUD_RECOMMENDER_ID\"],\n)\n```\n\nFor non-project scopes such as folders, organizations, or billing accounts, pass the fully qualified `parent` or `name` string in one of the formats accepted by the request type docs.\n\n## Core Workflow\n\n### List active recommendations\n\n`list_recommendations()` returns a pager. The common filter is `stateInfo.state = ACTIVE`.\n\n```python\nimport os\n\nfrom google.cloud import recommender_v1\n\nclient = recommender_v1.RecommenderClient()\nparent = client.recommender_path(\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT_NUMBER\"],\n    location=os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    recommender=os.environ[\"GOOGLE_CLOUD_RECOMMENDER_ID\"],\n)\n\nfor recommendation in client.list_recommendations(\n    parent=parent,\n    filter=\"stateInfo.state = ACTIVE\",\n):\n    print(recommendation.name)\n    print(recommendation.description)\n    print(recommendation.recommender_subtype)\n    print(recommendation.etag)\n    print(\"---\")\n```\n\nSupported filter fields for recommendations are documented as:\n\n- `stateInfo.state`\n- `recommenderSubtype`\n- `priority`\n- `targetResources`\n\n### Fetch one recommendation and inspect the suggested operations\n\nThe recommendation tells you what to change. The actual change is usually not performed through the Recommender client itself.\n\n```python\nimport os\n\nfrom google.cloud import recommender_v1\n\nclient = recommender_v1.RecommenderClient()\nrecommendation_name = client.recommendation_path(\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT_NUMBER\"],\n    location=os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    recommender=os.environ[\"GOOGLE_CLOUD_RECOMMENDER_ID\"],\n    recommendation=\"RECOMMENDATION_ID\",\n)\nrecommendation = client.get_recommendation(name=recommendation_name)\n\nprint(recommendation.description)\n\nfor group in recommendation.content.operation_groups:\n    for operation in group.operations:\n        print(\"action:\", operation.action)\n        print(\"resource:\", operation.resource)\n        print(\"path:\", operation.path)\n        print(\"value:\", operation.value)\n        print(\"---\")\n```\n\nUse the `resource` and operation details to decide which product-specific API call you need to make next. For example, a Compute Engine sizing recommendation is applied with Compute Engine tooling, not by mutating the resource through `google-cloud-recommender`.\n\n### Claim a recommendation before applying it\n\nClaiming marks the recommendation as in progress and prevents Recommender from refreshing its content while you work on it.\n\n```python\nclaimed = client.mark_recommendation_claimed(\n    name=recommendation.name,\n    etag=recommendation.etag,\n    state_metadata={\"actor\": \"ops-bot\", \"ticket\": \"chg-12345\"},\n)\n```\n\n### Mark it succeeded, failed, or dismissed\n\nAfter you apply the real resource change, update the recommendation state with the latest returned `etag`:\n\n```python\nsucceeded = client.mark_recommendation_succeeded(\n    name=claimed.name,\n    etag=claimed.etag,\n    state_metadata={\"actor\": \"ops-bot\", \"ticket\": \"chg-12345\"},\n)\n```\n\nIf your rollout fails:\n\n```python\nfailed = client.mark_recommendation_failed(\n    name=claimed.name,\n    etag=claimed.etag,\n    state_metadata={\"actor\": \"ops-bot\", \"ticket\": \"chg-12345\"},\n)\n```\n\nIf you want to stop seeing a recommendation without applying it:\n\n```python\ndismissed = client.mark_recommendation_dismissed(\n    request=recommender_v1.MarkRecommendationDismissedRequest(\n        name=recommendation.name,\n        etag=recommendation.etag,\n    )\n)\n```\n\nFor recommendation state metadata, the generated client docs note that keys and values are validated. Keep keys simple, lowercase, and short.\n\n## Insights Workflow\n\n### List active insights\n\nInsights are separate resources. Some insights are linked to recommendations, and some are useful on their own.\n\n```python\nimport os\n\nfrom google.cloud import recommender_v1\n\nclient = recommender_v1.RecommenderClient()\nparent = client.insight_type_path(\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT_NUMBER\"],\n    location=os.environ[\"GOOGLE_CLOUD_LOCATION\"],\n    insight_type=os.environ[\"GOOGLE_CLOUD_INSIGHT_TYPE_ID\"],\n)\n\nfor insight in client.list_insights(\n    parent=parent,\n    filter=\"stateInfo.state = ACTIVE\",\n):\n    print(insight.name)\n    print(insight.description)\n    print(insight.category)\n    print(insight.severity)\n    for reference in insight.associated_recommendations:\n        print(\"recommendation:\", reference.recommendation)\n    print(\"---\")\n```\n\nSupported filter fields for insights are documented as:\n\n- `stateInfo.state`\n- `insightSubtype`\n- `severity`\n- `targetResources`\n\n### Mark an insight accepted\n\nUse this when you acted on the insight directly, or when you want to record that the finding has been handled.\n\n```python\naccepted = client.mark_insight_accepted(\n    name=insight.name,\n    etag=insight.etag,\n    state_metadata={\"actor\": \"ops-bot\", \"ticket\": \"chg-12345\"},\n)\n```\n\nAccepted insights become immutable. Product docs also note that insights associated with a recommendation become accepted when the recommendation is marked `CLAIMED`, `SUCCEEDED`, or `FAILED`.\n\n## Configuration And Debugging Notes\n\n- Prefer ADC or an explicit `credentials=` object. The Recommender changelog notes that `credentials_file` is deprecated.\n- If you need SDK debug logs, set `GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google` or a narrower Google module scope before instantiating the client.\n- The Python package exposes both `recommender_v1` and `recommender_v1beta1`. Prefer `recommender_v1` unless you specifically need a beta-only surface.\n\n## Common Pitfalls\n\n- Do not assume one global recommender. Every call needs the right recommender ID or insight type ID and the right location for that product.\n- Do not drop the `etag`. State-change methods require the current fingerprint for optimistic locking.\n- Do not assume marking a recommendation `SUCCEEDED` applies the infrastructure change for you. You still have to call the relevant Google Cloud service API or use the console or `gcloud`.\n- Do not invent your own filter fields. Recommender and insight list filters only support the documented fields.\n- Do not assume the helper methods cover every resource hierarchy. Project helpers are convenient, but request docs also allow folder, organization, and billing-account resource names.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `google-cloud-recommender 2.20.0`.\n- The hosted reference pages under the latest docs tree are slightly inconsistent: some generated subpages still display older version labels, so check PyPI and the official changelog when you need the exact released package version.\n- The Recommender changelog shows that `2.19.0` deprecated `credentials_file`, so prefer ADC or explicit credential objects in new code.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-recommender/\n- Python client reference root: https://cloud.google.com/python/docs/reference/recommender/latest\n- `RecommenderClient` reference: https://docs.cloud.google.com/python/docs/reference/recommender/latest/google.cloud.recommender_v1.services.recommender.RecommenderClient\n- `Recommendation` type reference: https://docs.cloud.google.com/python/docs/reference/recommender/latest/google.cloud.recommender_v1.types.Recommendation\n- `Insight` type reference: https://docs.cloud.google.com/python/docs/reference/recommender/latest/google.cloud.recommender_v1.types.Insight\n- `ListRecommendationsRequest` reference: https://docs.cloud.google.com/python/docs/reference/recommender/latest/google.cloud.recommender_v1.types.ListRecommendationsRequest\n- `ListInsightsRequest` reference: https://docs.cloud.google.com/python/docs/reference/recommender/latest/google.cloud.recommender_v1.types.ListInsightsRequest\n- Recommender API usage guide: https://docs.cloud.google.com/recommender/docs/use-api\n- Insights API usage guide: https://docs.cloud.google.com/recommender/docs/insights/use-api\n- Recommender concepts: https://docs.cloud.google.com/recommender/docs/key-concepts\n- Insight concepts: https://docs.cloud.google.com/recommender/docs/insights/using-insights\n- Insight types table: https://docs.cloud.google.com/recommender/docs/insights/insight-types\n- Recommenders table: https://docs.cloud.google.com/recommender/docs/recommenders\n- Changelog: https://docs.cloud.google.com/python/docs/reference/recommender/latest/changelog\n"
  },
  {
    "path": "content/google/docs/redis/javascript/DOC.md",
    "content": "---\nname: redis\ndescription: \"Google Cloud Memorystore for Redis Node.js admin client for listing, creating, updating, exporting, importing, and deleting Redis instances\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,memorystore,redis,javascript,nodejs,admin-sdk\"\n---\n\n# `@google-cloud/redis` JavaScript Package Guide\n\nUse `@google-cloud/redis` when your Node.js code needs the Google Cloud Memorystore for Redis control plane: list instances, inspect configuration, create or update instances, export or import RDB files, retrieve the AUTH string, fail over a standard instance, and delete instances.\n\nThis package manages Memorystore resources. It is not the Redis protocol client you use for `GET`, `SET`, pub/sub, pipelines, or Lua commands against the Redis endpoint itself.\n\n## Golden Rule\n\n- Use `@google-cloud/redis` for Memorystore administration, not application data-plane commands.\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Build full resource names as `projects/{project}/locations/{region}` and `projects/{project}/locations/{region}/instances/{instance}`.\n- Treat create, update, export, import, failover, maintenance, upgrade, and delete calls as long-running operations and wait for `operation.promise()`.\n- Use a separate Redis client package for application traffic to the running Redis endpoint.\n\nThis guide covers `5.2.1`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/redis@5.2.1\n```\n\nIf your app also needs to talk Redis protocol to the instance endpoint, install a separate Redis client too:\n\n```bash\nnpm install @google-cloud/redis@5.2.1 redis\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials.\n\nTypical prerequisites:\n\n1. A Google Cloud project.\n2. The Memorystore for Redis API enabled in that project.\n3. A caller identity with permission to view or manage Redis instances in the target region.\n4. A VPC network ready if you are creating private Redis instances.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n\ngcloud services enable redis.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\n```\n\nIf you must use a service account key file explicitly:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_REGION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nFor production on Google Cloud, prefer an attached service account instead of shipping key files.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/redis';\n\nconst client = new v1.CloudRedisClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nBuild resource names once and reuse them:\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst region = process.env.GOOGLE_CLOUD_REGION || 'us-central1';\nconst instanceId = 'cache-dev';\n\nconst parent = `projects/${projectId}/locations/${region}`;\nconst name = `${parent}/instances/${instanceId}`;\n```\n\n## Core Workflows\n\n### List Instances In A Region\n\nUse the async iterator for normal listing flows.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function listInstances(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  for await (const instance of client.listInstancesAsync({parent})) {\n    console.log({\n      name: instance.name,\n      tier: instance.tier,\n      host: instance.host,\n      port: instance.port,\n      state: instance.state,\n      redisVersion: instance.redisVersion,\n      readEndpoint: instance.readEndpoint || null,\n      readEndpointPort: instance.readEndpointPort || null,\n    });\n  }\n}\n```\n\nTo aggregate across every available region, use `projects/PROJECT_ID/locations/-` as `parent`.\n\n### Get One Instance\n\nUse a full resource name, not only the short instance ID.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function getInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n  const [instance] = await client.getInstance({name});\n\n  console.log({\n    name: instance.name,\n    displayName: instance.displayName,\n    host: instance.host,\n    port: instance.port,\n    memorySizeGb: instance.memorySizeGb,\n    redisVersion: instance.redisVersion,\n    authorizedNetwork: instance.authorizedNetwork,\n    persistenceIamIdentity: instance.persistenceIamIdentity,\n  });\n\n  return instance;\n}\n```\n\n### Create A Basic Instance\n\n`createInstance()` is a long-running operation. Wait for completion before using the endpoint.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function createBasicInstance(projectId, region) {\n  const parent = `projects/${projectId}/locations/${region}`;\n\n  const [operation] = await client.createInstance({\n    parent,\n    instanceId: 'cache-dev',\n    instance: {\n      tier: 'BASIC',\n      memorySizeGb: 1,\n      authorizedNetwork: `projects/${projectId}/global/networks/default`,\n      redisVersion: 'REDIS_7_0',\n    },\n  });\n\n  const [instance] = await operation.promise();\n  console.log(instance.name, instance.host, instance.port);\n  return instance;\n}\n```\n\nCommon fields to choose deliberately during creation:\n\n- `tier` such as `BASIC` or `STANDARD_HA`\n- `memorySizeGb`\n- `authorizedNetwork`\n- `redisVersion`\n- `connectMode`\n- `transitEncryptionMode`\n- `readReplicasMode`, `replicaCount`, and `secondaryIpRange` when you use read replicas\n\n### Update An Instance With A Field Mask\n\nUse an update mask so you only change the fields you intend to change.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function renameInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.updateInstance({\n    updateMask: {\n      paths: ['display_name'],\n    },\n    instance: {\n      name,\n      displayName: 'cache-dev-updated',\n    },\n  });\n\n  const [instance] = await operation.promise();\n  return instance;\n}\n```\n\n### Export An Instance To Cloud Storage\n\nExport uses a long-running operation and writes an RDB snapshot to Cloud Storage.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function exportInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.exportInstance({\n    name,\n    outputConfig: {\n      gcsDestination: {\n        uri: 'gs://my-backups/redis/cache-dev.rdb',\n      },\n    },\n  });\n\n  await operation.promise();\n}\n```\n\n### Import An RDB Snapshot From Cloud Storage\n\nImport replaces the instance contents with the imported snapshot.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function importInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.importInstance({\n    name,\n    inputConfig: {\n      gcsSource: {\n        uri: 'gs://my-backups/redis/cache-dev.rdb',\n      },\n    },\n  });\n\n  await operation.promise();\n}\n```\n\n### Retrieve The AUTH String\n\nIf AUTH is enabled, fetch the current AUTH string from the admin API instead of assuming it is stored elsewhere.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function getAuthString(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n  const [response] = await client.getInstanceAuthString({name});\n  return response.authString;\n}\n```\n\n### Delete An Instance\n\nDelete is also a long-running operation.\n\n```javascript\nconst {v1} = require('@google-cloud/redis');\n\nconst client = new v1.CloudRedisClient();\n\nasync function deleteInstance(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n\n  const [operation] = await client.deleteInstance({name});\n  await operation.promise();\n}\n```\n\n## Using A Redis Data Client\n\nUse the admin SDK to discover the endpoint and configuration. Use a separate Redis client package for actual Redis commands.\n\n```javascript\nconst {createClient} = require('redis');\nconst {v1} = require('@google-cloud/redis');\n\nconst admin = new v1.CloudRedisClient();\n\nasync function connectForCommands(projectId, region, instanceId) {\n  const name = `projects/${projectId}/locations/${region}/instances/${instanceId}`;\n  const [instance] = await admin.getInstance({name});\n\n  const redis = createClient({\n    socket: {\n      host: instance.host,\n      port: instance.port,\n    },\n  });\n\n  await redis.connect();\n  console.log(await redis.ping());\n  return redis;\n}\n```\n\nIf you enable AUTH or TLS on the Memorystore instance, configure the Redis protocol client to match that instance before connecting.\n\n## Operations And Request Patterns\n\n- List methods expose async iterators such as `listInstancesAsync()` so the client can handle pagination for you.\n- Unary reads like `getInstance()` return a tuple where the first element is the resource.\n- Mutating methods such as `createInstance()`, `updateInstance()`, `exportInstance()`, `importInstance()`, and `deleteInstance()` return long-running operations.\n- Reuse client instances in long-lived processes instead of creating a new client for every request.\n- Use request objects with `parent`, `name`, `instanceId`, `instance`, and `updateMask` rather than assembling partially flattened arguments.\n\nOther important instance admin methods on this client include `failoverInstance()`, `rescheduleMaintenance()`, and `upgradeInstance()`. Treat them the same way: send a request object and wait for `operation.promise()`.\n\n## Common Pitfalls\n\n- The package is an admin SDK. It does not expose Redis commands like `get`, `set`, or pipelines.\n- `parent` is always `projects/{project}/locations/{region}`. Instance operations usually need a full `name` ending in `/instances/{instance}`.\n- Do not assume an operation finished just because the initial method returned. Wait for `await operation.promise()`.\n- Use an explicit field mask for `updateInstance()` or you risk sending an incomplete update.\n- `authorizedNetwork` must be a full VPC resource path such as `projects/PROJECT_ID/global/networks/default`.\n- Export and import require Cloud Storage access in addition to Memorystore permissions. Check `instance.persistenceIamIdentity` when troubleshooting bucket permissions.\n- `readEndpoint` is a read-only endpoint for eligible standard-tier topologies. Writes still go to the primary `host` and `port`.\n- If you aggregate listings with `projects/PROJECT_ID/locations/-`, the response can include unreachable regions. Handle that in operational tooling.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/redis` `5.2.1`.\n- The package is the Node.js admin client for the Memorystore control plane. Keep application Redis traffic in a separate Redis client package.\n- Current Memorystore instance fields include Redis 7.x-compatible values such as `REDIS_7_0` and `REDIS_7_2`; choose the version explicitly when you provision new instances.\n\n## Official Sources\n\n- Node.js client reference root: `https://cloud.google.com/nodejs/docs/reference/redis/latest`\n- Memorystore for Redis product docs: `https://cloud.google.com/memorystore/docs/redis`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC search order and overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/redis`\n"
  },
  {
    "path": "content/google/docs/redis/python/DOC.md",
    "content": "---\nname: redis\ndescription: \"google-cloud-redis package guide for Python with ADC setup, instance administration, long-running operations, and Memorystore-specific pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.20.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,memorystore,redis,gcp,python,admin-sdk\"\n---\n\n# google-cloud-redis Python Package Guide\n\n`google-cloud-redis` is the Python admin SDK for Google Cloud Memorystore for Redis. Use it for control-plane tasks such as listing instances, creating instances, updating configuration, exporting data, importing data, failing over, and deleting instances.\n\nIt is not the Redis protocol client you use inside application request paths. For reads, writes, pipelines, pub/sub, and Lua scripts against the Redis endpoint itself, use the separate `redis` package.\n\n## Golden Rule\n\n- Use `google-cloud-redis` for Memorystore administration.\n- Use Application Default Credentials (ADC) instead of hardcoded credentials whenever possible.\n- Treat create, update, export, import, failover, reschedule maintenance, upgrade, and delete calls as long-running operations.\n- Use the library path helpers to build resource names instead of concatenating `projects/...` strings by hand.\n- Use the separate `redis` package for application data-plane commands.\n\n## Install\n\nPin to the package version you intend to use:\n\n```bash\npython -m pip install google-cloud-redis==2.20.0\n```\n\nIf you also need to connect to the Redis endpoint from Python code, install `redis` separately:\n\n```bash\npython -m pip install google-cloud-redis==2.20.0 redis\n```\n\nPyPI currently lists Python `>=3.7` for this package. The official changelog also notes Python 3.14 support in the 2.19.0 line.\n\n## Authentication And Project Setup\n\nGoogle Cloud client libraries use ADC by default. For local development, the normal path is:\n\n```bash\ngcloud auth application-default login\ngcloud config set project MY_PROJECT_ID\ngcloud services enable redis.googleapis.com\n```\n\nIn Google Cloud runtimes, prefer attaching a service account to the workload instead of shipping JSON key files.\n\nIf you must use an explicit credential file, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/service-account.json\nexport GOOGLE_CLOUD_PROJECT=MY_PROJECT_ID\n```\n\nPractical notes:\n\n- The admin API is `redis.googleapis.com`.\n- Most requests need a project ID and region.\n- The region is part of the parent resource name: `projects/<project>/locations/<region>`.\n- Avoid baking credentials into code. Let ADC resolve them from the environment or runtime metadata server.\n\n## Initialize The Client\n\nStart with the synchronous client unless the rest of your codebase is already async:\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nproject_id = \"my-project\"\nregion = \"us-central1\"\n\nparent = client.common_location_path(project_id, region)\n\nfor instance in client.list_instances(request={\"parent\": parent}):\n    print(instance.name)\n    print(instance.host, instance.port)\n    print(instance.state.name)\n```\n\nUseful path helpers:\n\n- `client.common_location_path(project_id, region)`\n- `client.instance_path(project_id, region, instance_id)`\n\nIf you need a non-default endpoint or other transport configuration, pass `client_options` when constructing the client. The generated reference explicitly supports overriding `api_endpoint` that way.\n\n## Core Usage\n\n## List Instances\n\n`list_instances()` returns a pager. Iterate over it directly:\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nparent = client.common_location_path(\"my-project\", \"us-central1\")\n\nfor instance in client.list_instances(request={\"parent\": parent}):\n    print(instance.name)\n    print(instance.tier.name)\n    print(instance.redis_version)\n    print(instance.host, instance.port)\n```\n\n## Get One Instance\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-dev\")\n\ninstance = client.get_instance(request={\"name\": name})\n\nprint(instance.name)\nprint(instance.host)\nprint(instance.port)\nprint(instance.memory_size_gb)\nprint(instance.redis_version)\nprint(instance.authorized_network)\n```\n\n`Instance` exposes operationally useful fields including:\n\n- `host` and `port` for runtime client connections\n- `authorized_network`\n- `connect_mode`\n- `transit_encryption_mode`\n- `redis_version`\n- `read_endpoint` and `read_endpoint_port` when read replicas are available\n- `available_maintenance_versions`\n\n## Create An Instance\n\nCreate calls return a long-running operation. Wait for completion before using the instance.\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nproject_id = \"my-project\"\nregion = \"us-central1\"\n\ninstance = redis_v1.Instance(\n    tier=redis_v1.Instance.Tier.BASIC,\n    memory_size_gb=1,\n    authorized_network=f\"projects/{project_id}/global/networks/default\",\n    redis_version=\"REDIS_7_0\",\n)\n\noperation = client.create_instance(\n    request={\n        \"parent\": client.common_location_path(project_id, region),\n        \"instance_id\": \"cache-dev\",\n        \"instance\": instance,\n    }\n)\n\ncreated = operation.result(timeout=1800)\nprint(created.name)\nprint(created.host, created.port)\n```\n\nChoose these fields deliberately:\n\n- `tier`: `BASIC` vs `STANDARD_HA`\n- `memory_size_gb`\n- `authorized_network`\n- `redis_version`\n- `connect_mode`\n- `transit_encryption_mode`\n- `labels`, `display_name`, maintenance settings, and Redis config knobs for production instances\n\n## Update An Instance\n\nUse an update mask. Without it, partial updates are easy to get wrong.\n\n```python\nfrom google.cloud import redis_v1\nfrom google.protobuf import field_mask_pb2\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-dev\")\n\ninstance = redis_v1.Instance(\n    name=name,\n    display_name=\"cache-dev-updated\",\n)\n\noperation = client.update_instance(\n    request={\n        \"update_mask\": field_mask_pb2.FieldMask(paths=[\"display_name\"]),\n        \"instance\": instance,\n    }\n)\n\nupdated = operation.result(timeout=1800)\nprint(updated.display_name)\n```\n\n## Export And Import\n\nExport and import are also long-running operations and usually require Cloud Storage permissions in addition to Memorystore permissions.\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-prod\")\n\noperation = client.export_instance(\n    request={\n        \"name\": name,\n        \"output_config\": {\n            \"gcs_destination\": {\n                \"uri\": \"gs://my-backups/redis/cache-prod.rdb\",\n            }\n        },\n    }\n)\n\noperation.result(timeout=1800)\n```\n\nFor import, the structure is similar but uses `input_config`.\n\n## Fail Over And Maintenance Operations\n\nHigh-availability operational methods also return long-running operations:\n\n- `failover_instance()`\n- `reschedule_maintenance()`\n- `upgrade_instance()`\n\nExample:\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-prod\")\n\noperation = client.failover_instance(\n    request={\n        \"name\": name,\n        \"data_protection_mode\": (\n            redis_v1.FailoverInstanceRequest.DataProtectionMode.LIMITED_DATA_LOSS\n        ),\n    }\n)\n\noperation.result(timeout=1800)\n```\n\nUse failover only for instances and runbooks that are prepared for it.\n\n## Delete An Instance\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-dev\")\n\noperation = client.delete_instance(request={\"name\": name})\noperation.result(timeout=1800)\n```\n\n## Get The AUTH String\n\nIf AUTH is enabled, retrieve it from the admin API instead of assuming it is embedded in `get_instance()` output:\n\n```python\nfrom google.cloud import redis_v1\n\nclient = redis_v1.CloudRedisClient()\nname = client.instance_path(\"my-project\", \"us-central1\", \"cache-prod\")\n\nresponse = client.get_instance_auth_string(request={\"name\": name})\nprint(response.auth_string)\n```\n\n## Connect To The Redis Endpoint From Application Code\n\nUse the admin SDK to discover the connection endpoint, then use `redis` for actual Redis commands:\n\n```python\nfrom google.cloud import redis_v1\nimport redis\n\nadmin = redis_v1.CloudRedisClient()\nname = admin.instance_path(\"my-project\", \"us-central1\", \"cache-prod\")\ninstance = admin.get_instance(request={\"name\": name})\n\nr = redis.Redis(host=instance.host, port=instance.port, decode_responses=True)\nprint(r.ping())\n```\n\nThat split matters:\n\n- `google-cloud-redis` manages the Memorystore resource.\n- `redis` talks Redis protocol to the running instance.\n\n## Async Client\n\nIf your code is already async, the library exposes `CloudRedisAsyncClient` with the same request shapes:\n\n```python\nimport asyncio\nfrom google.cloud import redis_v1\n\nasync def main() -> None:\n    client = redis_v1.CloudRedisAsyncClient()\n    parent = client.common_location_path(\"my-project\", \"us-central1\")\n\n    async for instance in client.list_instances(request={\"parent\": parent}):\n        print(instance.name)\n\nasyncio.run(main())\n```\n\n## Configuration And Authentication Pitfalls\n\n- Do not confuse the package with `redis`. This library does not expose Redis data commands like `get`, `set`, or pipelines.\n- Use full resource names for `parent` and `name`. Path helpers are safer than manual string assembly.\n- Wait on `operation.result()` for every long-running call. A returned operation object does not mean the underlying change is finished.\n- Use an explicit update mask for `update_instance()`.\n- `authorized_network` expects a full VPC network resource path such as `projects/<project>/global/networks/<network>`.\n- Export and import need Cloud Storage access as well as Memorystore access. Instance metadata also exposes `persistence_iam_identity`, which matters when troubleshooting storage permissions.\n- `read_endpoint` is not the same thing as the primary write endpoint. Keep your runtime client routing aligned with the instance topology you actually provisioned.\n- The generated client can be used as a context manager, but doing so closes the underlying transport. Do not use `with CloudRedisClient()` if that transport will be shared elsewhere.\n- In multiprocessing scenarios, create the client after `os.fork()`, not before.\n\n## Version-Sensitive Notes\n\n- Frontmatter tracks `2.20.0` because that is the version used here and the current PyPI release.\n- Official upstream pages are not perfectly in sync on `2026-03-12`. PyPI lists `2.20.0`, some reference pages such as the `Instance` type page also show `2.20.0`, while the generated `CloudRedisClient` page and the official changelog page still show `2.19.0 (latest)`.\n- The official changelog records these recent changes:\n  - `2.20.0`: automatic mTLS enablement when Google API client certificates are available and the environment opts in, plus generated client updates around version handling\n  - `2.19.0`: Python 3.14 support and deprecation of the old `credentials_file` argument in generated clients\n  - `2.18.1`: protobuf 6.x compatibility\n  - `2.17.0`: opt-in debug logging support through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`\n- Because the public reference pages are mixed, verify the exact constructor arguments and generated helper behavior against the live reference if you are relying on very recent `2.20.x` behavior.\n\n## Official Sources Used For This Entry\n\n- Google Cloud Python reference root: `https://cloud.google.com/python/docs/reference/redis/latest`\n- `CloudRedisClient` reference: `https://cloud.google.com/python/docs/reference/redis/latest/google.cloud.redis_v1.services.cloud_redis.CloudRedisClient`\n- `Instance` reference: `https://cloud.google.com/python/docs/reference/redis/latest/google.cloud.redis_v1.types.Instance`\n- Google Cloud ADC overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- Google Cloud client library auth guidance: `https://cloud.google.com/docs/authentication/client-libraries`\n- Official changelog: `https://cloud.google.com/python/docs/reference/redis/latest/changelog`\n- PyPI package page: `https://pypi.org/project/google-cloud-redis/`\n"
  },
  {
    "path": "content/google/docs/resource-manager/python/DOC.md",
    "content": "---\nname: resource-manager\ndescription: \"Google Cloud Resource Manager Python client library for projects, folders, organizations, and tag bindings with ADC-based auth\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.16.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,gcp,google-cloud,resource-manager,projects,folders,organizations,tags,python\"\n---\n\n# Google Cloud Resource Manager Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-resource-manager` with `from google.cloud import resourcemanager_v3`, authenticate with Application Default Credentials (ADC), and pass full Google Cloud resource names instead of bare IDs. The package version is `1.16.0`, but the main client surface is still the `resourcemanager_v3` namespace.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-resource-manager==1.16.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-resource-manager==1.16.0\"\npoetry add \"google-cloud-resource-manager==1.16.0\"\n```\n\nFor local examples and most production workloads, you will also want the Google Cloud CLI available for ADC setup:\n\n```bash\ngcloud --version\n```\n\n## Authentication And Setup\n\nUse ADC unless you have a hard requirement to provide credentials explicitly.\n\nRecommended credential flow:\n\n1. Local development: `gcloud auth application-default login`\n2. Production on Google Cloud: attached service account or workload identity\n3. Only if you cannot use the first two: `GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json`\n\nLocal development setup:\n\n```bash\ngcloud auth application-default login\ngcloud services enable cloudresourcemanager.googleapis.com\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nExplicit credentials example:\n\n```python\nfrom google.cloud import resourcemanager_v3\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = resourcemanager_v3.ProjectsClient(credentials=credentials)\n```\n\nNotes:\n\n- Successful authentication is not enough by itself; the caller also needs the correct IAM permissions on the organization, folder, project, or tag resources it touches.\n- For local development, Google recommends user ADC or service account impersonation instead of downloading long-lived key files.\n- The Cloud Resource Manager API must be enabled on the project used for these calls.\n\n## Initialize Clients\n\nProjects are usually the starting point:\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nprojects = resourcemanager_v3.ProjectsClient()\n```\n\nOther surfaces in the same package:\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nfolders = resourcemanager_v3.FoldersClient()\norganizations = resourcemanager_v3.OrganizationsClient()\ntag_bindings = resourcemanager_v3.TagBindingsClient()\ntag_keys = resourcemanager_v3.TagKeysClient()\ntag_values = resourcemanager_v3.TagValuesClient()\n```\n\nAsync variants also exist, for example `ProjectsAsyncClient` and `TagBindingsAsyncClient`, if your codebase is already async.\n\n## Core Usage\n\n### Read a project\n\nUse a full resource name like `projects/my-project-id`:\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\nproject_name = resourcemanager_v3.ProjectsClient.common_project_path(\"my-project-id\")\n\nproject = client.get_project(name=project_name)\n\nprint(project.name)\nprint(project.project_id)\nprint(project.display_name)\nprint(project.state)\n```\n\n### Search projects when you do not know the exact parent\n\n`search_projects()` accepts a query language and is the practical starting point for discovery:\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\n\npager = client.search_projects(\n    request={\n        \"query\": \"parent.type:folder parent.id:123456789012 state:ACTIVE labels.env:prod\"\n    }\n)\n\nfor project in pager:\n    print(project.project_id, project.display_name)\n```\n\nUse `search_projects()` for ad hoc discovery. Use `list_projects()` only when you already know the parent container.\n\n### List projects under a folder or organization\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\n\nfor project in client.list_projects(request={\"parent\": \"folders/123456789012\"}):\n    print(project.project_id, project.display_name)\n```\n\n### Create a project\n\nProject creation is a long-running operation. Wait for `.result()` instead of assuming the project exists immediately.\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\n\noperation = client.create_project(\n    request={\n        \"project\": {\n            \"project_id\": \"example-project-123\",\n            \"display_name\": \"Example Project\",\n            \"parent\": \"folders/123456789012\",\n        }\n    }\n)\n\nproject = operation.result(timeout=300)\nprint(project.name)\n```\n\n### Move a project\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\n\noperation = client.move_project(\n    request={\n        \"name\": \"projects/my-project-id\",\n        \"destination_parent\": \"folders/987654321098\",\n    }\n)\n\nproject = operation.result(timeout=300)\nprint(project.parent)\n```\n\n### Delete and undelete a project\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.ProjectsClient()\n\ndelete_op = client.delete_project(name=\"projects/my-project-id\")\ndelete_op.result(timeout=300)\n\nundelete_op = client.undelete_project(name=\"projects/my-project-id\")\nundelete_op.result(timeout=300)\n```\n\n### Inspect effective tags on a project\n\nTag APIs use a different parent resource format than `ProjectsClient`. Use the double-slash URI-style resource name:\n\n```python\nfrom google.cloud import resourcemanager_v3\n\nclient = resourcemanager_v3.TagBindingsClient()\n\nfor tag in client.list_effective_tags(\n    parent=\"//cloudresourcemanager.googleapis.com/projects/123456789012\"\n):\n    print(tag.namespaced_tag_key, tag.namespaced_tag_value)\n```\n\n## Configuration Notes\n\n### Resource names are strict\n\nCommon forms:\n\n- Projects client methods: `projects/my-project-id`\n- Folder methods: `folders/123456789012`\n- Organization methods: `organizations/123456789012`\n- Tag binding parent values: `//cloudresourcemanager.googleapis.com/projects/123456789012`\n\nPassing a bare ID where the API expects a full resource name is a common cause of `InvalidArgument` errors.\n\n### Search and list are not interchangeable\n\n- `search_projects()` supports queries and is appropriate for discovery\n- `list_projects()` requires a known parent and is better for enumerating that container\n\nAgents often guess one when the other is required and end up debugging the wrong thing.\n\n### Long-running operations are normal\n\n`create_project()`, `move_project()`, `delete_project()`, `undelete_project()`, and some tag operations return long-running operations. Always wait on `.result()` and handle timeout, permission, and conflict errors explicitly.\n\n### Endpoint overrides are specialized\n\nThese clients accept `client_options`, including custom `api_endpoint`. Leave the default endpoint alone unless you are working with mTLS, Private Service Connect, or a specialized Google Cloud environment.\n\n### SDK logging is opt-in\n\nGoogle's Python client libraries support environment-based logging configuration. If you need transport-level visibility while debugging:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nThat is useful for auth and request debugging, but do not leave verbose logging enabled by default in production.\n\n## Common Pitfalls\n\n- Do not import `google.cloud.resource_manager`; use `google.cloud.resourcemanager_v3`.\n- Do not assume the package version and API namespace match. This package is `1.16.0`, but the API surface is still `v3`.\n- Do not pass bare project IDs where a full resource name is required.\n- Do not reuse the `projects/...` format for tag-binding parents; tag APIs use the `//cloudresourcemanager.googleapis.com/...` form.\n- Do not assume successful ADC means the operation is authorized. Most failures here are IAM or org-policy issues, not client-construction bugs.\n- Do not fire-and-forget project create, move, delete, or undelete calls. They are long-running operations.\n- Do not reach for service account key files first in local development when user ADC or impersonation will work.\n\n## Version-Sensitive Notes\n\n- PyPI lists `1.16.0` for `google-cloud-resource-manager` as of March 12, 2026.\n- The canonical reference pages for clients such as `ProjectsClient` and `TagBindingsClient` show the `1.16.0` library surface.\n- The docs root and changelog navigation still show `1.15.0` in some places. Treat that as documentation-site lag, not as proof that `1.16.0` is unsupported.\n- The package still exposes the `resourcemanager_v3` namespace. Do not rewrite imports or sample code to a hypothetical `v1_16` or `v4` namespace based on the package version.\n\n## Official Source URLs Used\n\n- PyPI package: `https://pypi.org/project/google-cloud-resource-manager/`\n- Google Cloud reference root: `https://cloud.google.com/python/docs/reference/cloudresourcemanager/latest`\n- `ProjectsClient` reference: `https://cloud.google.com/python/docs/reference/cloudresourcemanager/latest/google.cloud.resourcemanager_v3.services.projects.ProjectsClient`\n- `TagBindingsClient` reference: `https://cloud.google.com/python/docs/reference/cloudresourcemanager/latest/google.cloud.resourcemanager_v3.services.tag_bindings.TagBindingsClient`\n- Changelog: `https://cloud.google.com/python/docs/reference/cloudresourcemanager/latest/changelog`\n- ADC overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- ADC local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Repository path: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-resource-manager`\n"
  },
  {
    "path": "content/google/docs/resource-settings/python/DOC.md",
    "content": "---\nname: resource-settings\ndescription: \"Deprecated Google Cloud Resource Settings Python client library for inspecting legacy setting metadata and request shapes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,resource-settings,python,deprecated,settings,resource-manager\"\n---\n\n# Google Cloud Resource Settings Python Client Library\n\n## Golden Rule\n\nDo not start new integrations with `google-cloud-resource-settings`. Google still publishes the Python package on PyPI, but Google Cloud lists Resource Settings as deprecated on November 7, 2023 and shut down on October 1, 2024. Use this package only when you need to read or replace older code that already depended on Resource Settings.\n\nThe generated Python import path is:\n\n```python\nfrom google.cloud import resourcesettings_v1\n```\n\n## Install\n\nPin the package version your codebase expects:\n\n```bash\npython -m pip install \"google-cloud-resource-settings==1.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-resource-settings==1.12.0\"\npoetry add \"google-cloud-resource-settings==1.12.0\"\n```\n\nPyPI lists `Requires: Python >=3.7` for this package.\n\n## Authentication And Initialization\n\nThe generated client uses Application Default Credentials (ADC). Historically, Resource Settings calls required the `https://www.googleapis.com/auth/cloud-platform` scope.\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nBasic client initialization:\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient()\n```\n\nExplicit credentials:\n\n```python\nfrom google.cloud import resourcesettings_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient(credentials=credentials)\n```\n\nBecause the service is shut down, successful client initialization does not mean live API calls will succeed.\n\n## Resource Names And Value Types\n\nThe v1 Python types expect full resource names:\n\n- parent resource: `projects/{project_number}`, `projects/{project_id}`, `folders/{folder_id}`, or `organizations/{organization_id}`\n- setting name: `projects/{project_number}/settings/{setting_name}` or the equivalent folder or organization form\n\nThe documented value shapes are:\n\n- `boolean_value`\n- `string_value`\n- `string_set_value`\n- `enum_value`\n\n`Value` is a protobuf `oneof`, so only one of those fields can be set at a time.\n\nThe library also exposes `SettingView` values:\n\n- `SETTING_VIEW_BASIC`\n- `SETTING_VIEW_EFFECTIVE_VALUE`\n- `SETTING_VIEW_LOCAL_VALUE`\n\nIf you do not set a view, the docs say the API defaults to `SETTING_VIEW_BASIC`.\n\n## Historical Client Surface\n\nThese examples are useful when auditing or replacing older integrations. They show the generated request shapes that the package documents, but live calls should be treated as legacy-only because the service shut down on October 1, 2024.\n\n### List settings available on a resource\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient()\n\npager = client.list_settings(\n    request={\n        \"parent\": \"projects/my-project-id\",\n        \"view\": resourcesettings_v1.SettingView.SETTING_VIEW_BASIC,\n    }\n)\n\nfor setting in pager:\n    print(setting.name)\n    print(setting.metadata.display_name)\n    print(setting.metadata.data_type.name)\n    print(setting.metadata.read_only)\n```\n\n### Get one setting and read its effective value\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient()\n\nsetting = client.get_setting(\n    request={\n        \"name\": \"projects/my-project-id/settings/example.setting\",\n        \"view\": resourcesettings_v1.SettingView.SETTING_VIEW_EFFECTIVE_VALUE,\n    }\n)\n\nprint(setting.name)\nprint(setting.effective_value)\n```\n\n### Get one setting and inspect its local value\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient()\n\nsetting = client.get_setting(\n    request={\n        \"name\": \"projects/my-project-id/settings/example.setting\",\n        \"view\": resourcesettings_v1.SettingView.SETTING_VIEW_LOCAL_VALUE,\n    }\n)\n\nprint(setting.local_value)\nprint(setting.etag)\n```\n\n### Update a setting value with the documented v1 request types\n\nThe v1 docs say `update_setting` takes a full `Setting` object and uses `etag` for optimistic concurrency.\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nclient = resourcesettings_v1.ResourceSettingsServiceClient()\nsetting_name = \"projects/my-project-id/settings/example.setting\"\n\ncurrent = client.get_setting(\n    request={\n        \"name\": setting_name,\n        \"view\": resourcesettings_v1.SettingView.SETTING_VIEW_LOCAL_VALUE,\n    }\n)\n\nupdated = client.update_setting(\n    request={\n        \"setting\": resourcesettings_v1.Setting(\n            name=current.name,\n            local_value=resourcesettings_v1.Value(boolean_value=True),\n            etag=current.etag,\n        )\n    }\n)\n\nprint(updated.name)\nprint(updated.local_value)\nprint(updated.etag)\n```\n\n### Build other value shapes\n\n```python\nfrom google.cloud import resourcesettings_v1\n\nstring_value = resourcesettings_v1.Value(string_value=\"example\")\n\nstring_set_value = resourcesettings_v1.Value(\n    string_set_value=resourcesettings_v1.Value.StringSet(\n        values=[\"alpha\", \"beta\"]\n    )\n)\n\nenum_value = resourcesettings_v1.Value(\n    enum_value=resourcesettings_v1.Value.EnumValue(value=\"ENUM_MEMBER\")\n)\n```\n\n## Common Pitfalls\n\n- Package name and import path differ: install `google-cloud-resource-settings`, import `resourcesettings_v1`.\n- The package is newer than the service. `1.12.0` was released in February 2025, after the service shutdown on October 1, 2024, so package freshness does not mean the backend is still available.\n- Use full resource names, not bare IDs. `projects/my-project-id/settings/example.setting` is valid; `example.setting` is not.\n- `get_setting()` and `list_settings()` default to basic metadata unless you request `SETTING_VIEW_EFFECTIVE_VALUE` or `SETTING_VIEW_LOCAL_VALUE`.\n- `update_setting()` is documented as a full overwrite and checks `etag`. Reusing a stale `etag` can cause an optimistic-concurrency failure.\n- `Value` is a oneof. Setting both `boolean_value` and `string_value` on the same object will not do what you expect.\n- The docs mark `page_size` and `page_token` as unused on `ListSettingsRequest`.\n- The type docs say a string set supports at most 50 entries and each string can be at most 200 characters.\n\n## Version-Sensitive Notes\n\n- `1.12.0` adds REST interceptors and selective GAPIC generation support. It does not restore service availability.\n- `1.11.0` adds opt-in debug logging support.\n- `1.10.0` adds Python 3.13 support.\n- `1.9.4` is where Google added the deprecation and shutdown notice to the package changelog.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/google-cloud-resource-settings/`\n- Python client docs root: `https://googleapis.dev/python/resourcesettings/latest/`\n- Python v1 types reference: `https://googleapis.dev/python/resourcesettings/latest/resourcesettings_v1/types_.html`\n- Package changelog: `https://googleapis.dev/python/resourcesettings/latest/CHANGELOG.html`\n- Resource Manager deprecations: `https://cloud.google.com/resource-manager/docs/deprecations`\n- Resource Settings RPC reference: `https://developers.google.com/resource-settings/docs/reference/rpc/google.cloud.resourcesettings.v1alpha1`\n"
  },
  {
    "path": "content/google/docs/resumable-media/python/DOC.md",
    "content": "---\nname: resumable-media\ndescription: \"Google low-level Python library for resumable uploads and media downloads over requests\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,resumable-media,uploads,downloads,requests,google-auth,http,streaming\"\n---\n\n# Google Resumable Media Python Library\n\n## Golden Rule\n\nUse `google-resumable-media` only when you need low-level control over upload or download HTTP flows. It is not a Google service client, it does not discover resources for you, and it does not build service-specific upload or media URLs.\n\nFor synchronous Python code, use the documented `google.resumable_media.requests` surface with a `google.auth.transport.requests.AuthorizedSession`.\n\nOne versioning caveat matters immediately: the official docs URL redirects to a rendered reference site that still labels `latest` as `2.4.1`, while PyPI and the official changelog show `2.8.0` as the current release. Use the rendered docs for class and method shape, then use PyPI and the changelog for post-`2.4.1` release facts.\n\n## Install\n\nFor the documented sync transport:\n\n```bash\npython -m pip install \"google-resumable-media[requests]==2.8.0\" google-auth\n```\n\nIf you are pinning without extras:\n\n```bash\npython -m pip install \"google-resumable-media==2.8.0\" requests google-auth\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-resumable-media==2.8.0\"\npoetry add \"google-resumable-media==2.8.0\"\n```\n\nPyPI also advertises an `aiohttp` extra:\n\n```bash\npython -m pip install \"google-resumable-media[aiohttp]==2.8.0\"\n```\n\nTreat async support as experimental and version-sensitive. The published reference pages in the official docs only document the `requests` transport.\n\n## Authentication And Transport Setup\n\nThe official docs assume `requests` as the transport and `google-auth` for authenticated HTTP traffic. A normal Google API setup looks like this:\n\n```python\nfrom google.auth import default\nfrom google.auth.transport.requests import AuthorizedSession\n\nSCOPES = (\"https://www.googleapis.com/auth/devstorage.read_write\",)\n\ncredentials, _ = default(scopes=SCOPES)\ntransport = AuthorizedSession(credentials)\n```\n\nPractical rules:\n\n- Choose scopes for the API you are actually calling.\n- Build the upload URL or media URL for the target API yourself.\n- Keep auth and URL construction in the calling code; this package only handles transfer mechanics.\n\n## Core Usage\n\n### Simple upload\n\nUse `SimpleUpload` when the API accepts the full media body in a single request and there is no metadata part.\n\n```python\nfrom google.resumable_media.requests import SimpleUpload\n\nupload_url = (\n    \"https://www.googleapis.com/upload/storage/v1/b/my-bucket/o\"\n    \"?uploadType=media&name=hello.txt\"\n)\n\nupload = SimpleUpload(upload_url)\nresponse = upload.transmit(\n    transport,\n    b\"hello world\",\n    \"text/plain\",\n)\nresponse.raise_for_status()\n```\n\n### Multipart upload\n\nUse `MultipartUpload` when the API expects metadata plus content in one request.\n\nThe official class reference documents:\n\n- `MultipartUpload(upload_url, headers=None, checksum=None)`\n- `transmit(transport, data, metadata, content_type, timeout=(61, 60))`\n\n```python\nfrom google.resumable_media.requests import MultipartUpload\n\nupload_url = \"https://example.googleapis.com/upload/path?uploadType=multipart\"\nmetadata = {\"name\": \"example.json\"}\ndata = b'{\"hello\": \"world\"}'\n\nupload = MultipartUpload(upload_url)\nresponse = upload.transmit(\n    transport,\n    data,\n    metadata,\n    \"application/json\",\n)\nresponse.raise_for_status()\n```\n\n### Resumable upload\n\nUse `ResumableUpload` for large payloads, flaky networks, or cases where you need upload state to survive more than one HTTP request.\n\nThe official class reference documents:\n\n- `ResumableUpload(upload_url, chunk_size, checksum=None, headers=None)`\n- `initiate(transport, stream, metadata, content_type, total_bytes=None, stream_final=True, timeout=(61, 60))`\n- `recover(transport)`\n- `transmit_next_chunk(transport, timeout=(61, 60))`\n\n```python\nimport io\n\nfrom google.resumable_media.requests import ResumableUpload\n\npayload = b\"x\" * (8 * 1024 * 1024)\nstream = io.BytesIO(payload)\nupload_url = (\n    \"https://www.googleapis.com/upload/storage/v1/b/my-bucket/o\"\n    \"?uploadType=resumable&name=example.bin\"\n)\n\nupload = ResumableUpload(upload_url, chunk_size=1024 * 1024)\nresponse = upload.initiate(\n    transport,\n    stream,\n    metadata={\"name\": \"example.bin\"},\n    content_type=\"application/octet-stream\",\n    total_bytes=len(payload),\n)\nresponse.raise_for_status()\n\nwhile not upload.finished:\n    response = upload.transmit_next_chunk(transport)\n    response.raise_for_status()\n```\n\nCall `recover(transport)` when the process boundary or network boundary is uncertain and you need to re-check the server-side upload state before sending more data.\n\n### Chunked download\n\nUse `ChunkedDownload` when the object is large, you do not want to buffer it all in memory, or you need ranged/chunked progress.\n\nThe official docs call out chunked downloads for very large objects or objects of unknown size and document:\n\n- `ChunkedDownload(media_url, chunk_size, stream, start=0, end=None, headers=None)`\n- `consume_next_chunk(transport, timeout=(61, 60))`\n\n```python\nfrom google.resumable_media.requests import ChunkedDownload\n\nmedia_url = (\n    \"https://www.googleapis.com/download/storage/v1/b/\"\n    \"my-bucket/o/example.bin?alt=media\"\n)\n\nwith open(\"example.bin\", \"wb\") as fh:\n    download = ChunkedDownload(\n        media_url,\n        chunk_size=50 * 1024 * 1024,\n        stream=fh,\n    )\n\n    while not download.finished:\n        response = download.consume_next_chunk(transport)\n        response.raise_for_status()\n```\n\n### One-shot raw download\n\nUse `RawDownload` when you want a single request and the raw `requests.Response` content path.\n\nThe official class reference documents:\n\n- `RawDownload(media_url, stream=None, start=None, end=None, headers=None, checksum='md5')`\n- `consume(transport, timeout=(61, 60))`\n\n```python\nfrom google.resumable_media.requests import RawDownload\n\ndownload = RawDownload(\n    \"https://www.googleapis.com/download/storage/v1/b/\"\n    \"my-bucket/o/example.bin?alt=media\"\n)\nresponse = download.consume(transport)\nresponse.raise_for_status()\n\npayload = response.content\n```\n\n## Configuration Notes\n\n### Timeouts\n\nThe published sync reference uses `timeout=(61, 60)` on `transmit`, `initiate`, `transmit_next_chunk`, `consume_next_chunk`, and `consume`. Pass `timeout=` explicitly when your environment needs different connect or read behavior.\n\n### Checksums\n\nThe published constructors expose checksum controls on upload and raw-download helpers:\n\n- `MultipartUpload(..., checksum=None)`\n- `ResumableUpload(..., checksum=None)`\n- `RawDownload(..., checksum='md5')`\n\nThe overview docs also say chunked downloads usually do not return a checksum, and even if they do, it is not validated during chunked transfer. If you need integrity validation for chunked downloads, validate after reassembling the full payload.\n\n### URL construction\n\nThis package does not derive API-specific paths for you. Your caller code must provide the right URL shape, such as:\n\n- `uploadType=media` for simple uploads\n- `uploadType=multipart` for metadata + media uploads\n- `uploadType=resumable` for resumable upload sessions\n- `alt=media` for media downloads on APIs that use that query parameter\n\n## Common Pitfalls\n\n- Install name and import name differ. You install `google-resumable-media`, but the documented sync imports come from `google.resumable_media.requests`.\n- This package is a transfer helper, not a product client. It will not list buckets, resolve object paths, or infer service endpoints.\n- The official published reference is stale on version labeling. As of March 12, 2026, the rendered `latest` docs still show `2.4.1`, so use the changelog and PyPI for `2.7.x` and `2.8.0` release facts.\n- The docs only clearly cover the `requests` surface. Do not assume sync examples translate directly to async code.\n- Chunked downloads do not automatically give you end-to-end checksum validation for the whole object.\n\n## Version-Sensitive Notes For 2.8.0\n\nFrom the official changelog and PyPI metadata:\n\n- `2.8.0` adds support for Python `3.13` and `3.14`.\n- `2.7.2` fixes retry offset calculation for ranged reads.\n- `2.7.1` adds a partial-response data check.\n- `2.7.0` adds Python `3.12` support and brotli support.\n- PyPI still lists the package requirement as Python `>=3.7`.\n\nPractical implications:\n\n- If you run Python `3.13` or `3.14`, use at least `2.8.0`.\n- If you rely on ranged-read retries, pin at least `2.7.2`.\n- If examples from the rendered docs conflict with newer behavior, prefer the changelog for post-`2.4.1` release notes and PyPI for release/version metadata.\n\n## Official Sources Used\n\n- Docs root from package metadata: https://googleapis.dev/python/google-resumable-media/latest/\n- Canonical rendered docs root: https://docs.cloud.google.com/python/docs/reference/google-resumable-media/latest\n- ResumableUpload reference: https://docs.cloud.google.com/python/docs/reference/google-resumable-media/latest/google.resumable_media.requests.ResumableUpload\n- MultipartUpload reference: https://docs.cloud.google.com/python/docs/reference/google-resumable-media/latest/google.resumable_media.requests.MultipartUpload\n- ChunkedDownload reference: https://docs.cloud.google.com/python/docs/reference/google-resumable-media/latest/google.resumable_media.requests.ChunkedDownload\n- RawDownload reference: https://docs.cloud.google.com/python/docs/reference/google-resumable-media/latest/google.resumable_media.requests.RawDownload\n- PyPI package page: https://pypi.org/project/google-resumable-media/\n- Archived upstream repository: https://github.com/googleapis/google-resumable-media-python\n- Upstream changelog: https://github.com/googleapis/google-resumable-media-python/blob/main/CHANGELOG.md\n"
  },
  {
    "path": "content/google/docs/retail/javascript/DOC.md",
    "content": "---\nname: retail\ndescription: \"Google Cloud Retail Node.js client for catalog import, search, predictions, and user event logging\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,retail,ecommerce,search,recommendations,javascript\"\n---\n\n# Google Cloud Retail Node.js Client\n\n## Golden Rule\n\nUse `@google-cloud/retail` with Application Default Credentials (ADC), enable `retail.googleapis.com` in the Google Cloud project that owns your catalog, and build against the GA `v2` client surface for product import, search, predictions, and user events.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/retail@4.3.0\n```\n\n## Authentication And Project Setup\n\nBefore making API calls, make sure all of the following are true:\n\n1. You have a Google Cloud project.\n2. Billing is enabled for that project.\n3. Cloud Retail is enabled for that project.\n4. ADC is configured for the identity your app runs as.\n\nEnable the API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\ngcloud services enable retail.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development, the standard ADC flow is:\n\n```bash\ngcloud auth application-default login\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"global\"\nexport GOOGLE_CLOUD_CATALOG=\"default_catalog\"\nexport GOOGLE_CLOUD_BRANCH=\"default_branch\"\nexport RETAIL_SEARCH_SERVING_CONFIG=\"default_serving_config\"\nexport RETAIL_RECOMMENDATION_SERVING_CONFIG=\"default_recommendation_config\"\n```\n\nIf you must use a service account key outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account instead of shipping JSON keys.\n\n## Initialize Clients\n\nThe package exports versioned namespaces. For the current GA surface:\n\n```javascript\nconst retail = require('@google-cloud/retail').v2;\n\nconst clientOptions = {\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n};\n\nconst productClient = new retail.ProductServiceClient(clientOptions);\nconst searchClient = new retail.SearchServiceClient(clientOptions);\nconst predictionClient = new retail.PredictionServiceClient(clientOptions);\nconst userEventClient = new retail.UserEventServiceClient(clientOptions);\n```\n\nIf you need to pass a key file explicitly, add `keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS` to `clientOptions`.\n\nCreate clients once and reuse them across requests.\n\n## Resource Names You Reuse Constantly\n\nRetail requests usually need fully qualified resource names, not your internal IDs.\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\nconst catalog = process.env.GOOGLE_CLOUD_CATALOG ?? 'default_catalog';\nconst branch = process.env.GOOGLE_CLOUD_BRANCH ?? 'default_branch';\nconst searchServingConfig =\n  process.env.RETAIL_SEARCH_SERVING_CONFIG ?? 'default_serving_config';\nconst recommendationServingConfig =\n  process.env.RETAIL_RECOMMENDATION_SERVING_CONFIG ??\n  'default_recommendation_config';\n\nconst catalogName = `projects/${projectId}/locations/${location}/catalogs/${catalog}`;\nconst branchName = `${catalogName}/branches/${branch}`;\nconst searchPlacement = `${catalogName}/servingConfigs/${searchServingConfig}`;\nconst recommendationPlacement =\n  `${catalogName}/servingConfigs/${recommendationServingConfig}`;\n```\n\nThe resource forms you use most often are:\n\n- Catalog: `projects/PROJECT_ID/locations/global/catalogs/default_catalog`\n- Branch: `projects/PROJECT_ID/locations/global/catalogs/default_catalog/branches/default_branch`\n- Serving config: `projects/PROJECT_ID/locations/global/catalogs/default_catalog/servingConfigs/default_serving_config`\n\nPersist the `name` values the API returns when you can instead of rebuilding them by hand.\n\n## Search Products\n\n`search()` is the main retrieval API. Pass a `placement`, and send a stable `visitorId` from your own app rather than a random placeholder.\n\n```javascript\nconst retail = require('@google-cloud/retail').v2;\n\nconst searchClient = new retail.SearchServiceClient();\n\nasync function searchProducts() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\n  const catalog = process.env.GOOGLE_CLOUD_CATALOG ?? 'default_catalog';\n  const branch = process.env.GOOGLE_CLOUD_BRANCH ?? 'default_branch';\n  const servingConfig =\n    process.env.RETAIL_SEARCH_SERVING_CONFIG ?? 'default_serving_config';\n\n  const catalogName = `projects/${projectId}/locations/${location}/catalogs/${catalog}`;\n  const branchName = `${catalogName}/branches/${branch}`;\n  const placement = `${catalogName}/servingConfigs/${servingConfig}`;\n\n  const [response] = await searchClient.search({\n    placement,\n    branch: branchName,\n    query: 'running shoes',\n    visitorId: 'anon-session-7d6b4d3c',\n    pageSize: 10,\n  });\n\n  for (const result of response.results ?? []) {\n    console.log(result.product?.id, result.product?.title);\n  }\n}\n\nsearchProducts().catch(console.error);\n```\n\nUse a branch explicitly when you want search results scoped to `default_branch` or another non-default branch.\n\n## Import Products\n\n`importProducts()` is the normal bulk-ingestion path. The request parent is the branch resource.\n\n```javascript\nconst retail = require('@google-cloud/retail').v2;\n\nconst productClient = new retail.ProductServiceClient();\n\nasync function importProducts() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\n  const catalog = process.env.GOOGLE_CLOUD_CATALOG ?? 'default_catalog';\n  const branch = process.env.GOOGLE_CLOUD_BRANCH ?? 'default_branch';\n\n  const parent = `projects/${projectId}/locations/${location}/catalogs/${catalog}/branches/${branch}`;\n\n  const [operation] = await productClient.importProducts({\n    parent,\n    inputConfig: {\n      productInlineSource: {\n        products: [\n          {\n            id: 'sku-123',\n            title: 'Trail Runner 2',\n            categories: ['Shoes', 'Running'],\n          },\n          {\n            id: 'sku-456',\n            title: 'Daily Trainer',\n            categories: ['Shoes', 'Training'],\n          },\n        ],\n      },\n    },\n  });\n\n  const [response] = await operation.promise();\n  console.log(response);\n}\n\nimportProducts().catch(console.error);\n```\n\nInline source is fine for small examples. For large feeds, move the import source to Cloud Storage instead of putting the whole catalog in the request body.\n\n## Get Recommendations\n\nUse `predict()` to request recommendation results for a visitor and page context.\n\n```javascript\nconst retail = require('@google-cloud/retail').v2;\n\nconst predictionClient = new retail.PredictionServiceClient();\n\nasync function getRecommendations() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\n  const catalog = process.env.GOOGLE_CLOUD_CATALOG ?? 'default_catalog';\n  const servingConfig =\n    process.env.RETAIL_RECOMMENDATION_SERVING_CONFIG ??\n    'default_recommendation_config';\n\n  const placement =\n    `projects/${projectId}/locations/${location}/catalogs/${catalog}/` +\n    `servingConfigs/${servingConfig}`;\n\n  const [response] = await predictionClient.predict({\n    placement,\n    userEvent: {\n      eventType: 'detail-page-view',\n      visitorId: 'anon-session-7d6b4d3c',\n    },\n    pageSize: 10,\n  });\n\n  for (const result of response.results ?? []) {\n    console.log(result.id);\n  }\n}\n\ngetRecommendations().catch(console.error);\n```\n\nSend a realistic `userEvent` that matches the page or flow where you request recommendations.\n\n## Write User Events\n\nUse `writeUserEvent()` for real-time search, click, and page-view signals.\n\n```javascript\nconst retail = require('@google-cloud/retail').v2;\n\nconst userEventClient = new retail.UserEventServiceClient();\n\nasync function writeSearchEvent() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n  const location = process.env.GOOGLE_CLOUD_LOCATION ?? 'global';\n  const catalog = process.env.GOOGLE_CLOUD_CATALOG ?? 'default_catalog';\n\n  const parent = `projects/${projectId}/locations/${location}/catalogs/${catalog}`;\n\n  const [userEvent] = await userEventClient.writeUserEvent({\n    parent,\n    userEvent: {\n      eventType: 'search',\n      visitorId: 'anon-session-7d6b4d3c',\n      searchQuery: 'running shoes',\n    },\n  });\n\n  console.log(userEvent.eventType, userEvent.visitorId);\n}\n\nwriteSearchEvent().catch(console.error);\n```\n\nPersist the same visitor identifier across search, recommendation, and conversion flows so Retail can connect those events.\n\n## Common Pitfalls\n\n- Do not pass internal IDs where the API expects full resource names like `projects/.../locations/.../catalogs/...`.\n- Do not mix up request scopes: `importProducts()` uses a branch parent, while `writeUserEvent()` uses a catalog parent.\n- Do not omit `visitorId` in search and recommendation flows if you want useful attribution and personalization.\n- Do not assume the inline `userEvent` in `predict()` replaces explicit event logging; write the event separately when you need it stored.\n- Do not create a new client per request. Reuse long-lived client instances.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/retail@4.3.0`.\n- Older Retail examples may still show legacy placement-style resource names. Prefer `servingConfigs/*` when you build new request paths.\n- If you need query-completion or autocomplete features, check the generated Node.js reference for the exact namespace exposed by your installed version before you commit that code path.\n\n## Official Sources\n\n- Maintainer package docs: https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-retail\n- Node.js reference root: https://cloud.google.com/nodejs/docs/reference/retail/latest\n- npm package page: https://www.npmjs.com/package/@google-cloud/retail\n- ADC overview: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- Local ADC setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n"
  },
  {
    "path": "content/google/docs/retail/python/DOC.md",
    "content": "---\nname: retail\ndescription: \"Google Cloud Retail Python client for catalog import, search, recommendations, user events, and autocomplete\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,retail,ecommerce,search,recommendations\"\n---\n\n# Google Cloud Retail Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-retail` package with Application Default Credentials (ADC), and prefer the GA `retail_v2` namespace unless a feature is only surfaced in `retail_v2beta`.\n\nAs of March 12, 2026, PyPI lists `google-cloud-retail 2.9.0`, but Google's `latest` Python reference and changelog still show `2.7.0`. Treat the docs site as the API shape reference, but pin installs from PyPI and call out the drift in reviews.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-retail==2.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-retail==2.9.0\"\npoetry add \"google-cloud-retail==2.9.0\"\n```\n\n## Authentication And Setup\n\nThis client library uses Google Cloud authentication, so the normal setup is:\n\n1. Create or select a Google Cloud project.\n2. Enable billing.\n3. Enable the Retail API for that project.\n4. Configure ADC for local development or attach a service account in production.\n\n### Local development\n\nGoogle's ADC guidance says the best local option is your user credentials:\n\n```bash\ngcloud auth application-default login\n```\n\nGoogle also documents that ADC checks credentials in this order:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. A local ADC file created by `gcloud auth application-default login`\n3. The attached service account from the metadata server\n\n### Production on Google Cloud\n\nFor production workloads running on Google Cloud, Google recommends an attached user-managed service account rather than baking keys into the app.\n\n### Service account key fallback\n\nOnly use a service account key if you cannot use user credentials, service account impersonation, or an attached service account:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\n## Import Surface\n\nGA and generated helpers live under `retail_v2`:\n\n```python\nfrom google.cloud import retail_v2\n```\n\nThe docs overview also exposes `retail_v2alpha` and `retail_v2beta`. In practice:\n\n- Use `retail_v2` for product import, search, recommendations, and user events.\n- Check `retail_v2beta` when you need autocomplete and the GA page for `CompletionServiceClient` is missing or stale.\n\n## Resource Names You Will Reuse\n\nMost requests fail because of bad resource names rather than bad Python syntax. Build them explicitly:\n\n```python\nfrom google.cloud import retail_v2\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\nbranch = \"default_branch\"\nserving_config = \"default_serving_config\"\n\nsearch_client = retail_v2.SearchServiceClient()\n\nbranch_name = search_client.branch_path(project_id, location, catalog, branch)\nserving_config_name = search_client.serving_config_path(\n    project_id,\n    location,\n    catalog,\n    serving_config,\n)\ncatalog_name = f\"projects/{project_id}/locations/{location}/catalogs/{catalog}\"\n```\n\nUseful formats from the official docs:\n\n- Search placement: `projects/*/locations/global/catalogs/default_catalog/servingConfigs/default_serving_config`\n- Legacy search placement: `projects/*/locations/global/catalogs/default_catalog/placements/default_search`\n- Branch: `projects/*/locations/global/catalogs/default_catalog/branches/default_branch`\n- Catalog: `projects/*/locations/global/catalogs/default_catalog`\n\n## Search Products\n\n`SearchRequest` requires a `placement`. `visitor_id` is effectively mandatory for real applications if you want search quality and later event correlation.\n\n```python\nfrom google.cloud import retail_v2\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\nbranch = \"default_branch\"\nserving_config = \"default_serving_config\"\n\nclient = retail_v2.SearchServiceClient()\n\nrequest = retail_v2.SearchRequest(\n    placement=client.serving_config_path(\n        project_id,\n        location,\n        catalog,\n        serving_config,\n    ),\n    branch=client.branch_path(project_id, location, catalog, branch),\n    query=\"running shoes\",\n    visitor_id=\"anon-session-7d6b4d3c\",\n)\n\nresults = client.search(request=request)\n\nfor result in results:\n    product = result.product\n    print(product.id, product.title)\n```\n\nVersion-sensitive behavior from the reference:\n\n- If `query` is empty, Retail treats the call as category browsing.\n- `search()` returns a pager and automatically resolves additional pages while you iterate.\n- `placements/*` still works, but `servingConfigs/*` is the recommended resource.\n\n## Import Or Update Products\n\n`import_products()` is the normal bulk-ingestion API. The request parent is the branch resource, and the operation can create missing products.\n\n```python\nfrom google.cloud import retail_v2\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\nbranch = \"default_branch\"\n\nclient = retail_v2.ProductServiceClient()\nparent = client.branch_path(project_id, location, catalog, branch)\n\nproducts = [\n    retail_v2.Product(\n        id=\"sku-123\",\n        title=\"Trail Runner 2\",\n        categories=[\"Shoes\", \"Running\"],\n    ),\n    retail_v2.Product(\n        id=\"sku-456\",\n        title=\"Daily Trainer\",\n        categories=[\"Shoes\", \"Training\"],\n    ),\n]\n\ninput_config = retail_v2.ProductInputConfig(\n    product_inline_source=retail_v2.ProductInlineSource(products=products)\n)\n\noperation = client.import_products(\n    request=retail_v2.ImportProductsRequest(\n        parent=parent,\n        input_config=input_config,\n    )\n)\n\nresponse = operation.result()\nprint(response)\n```\n\nImportant request behavior from the official docs:\n\n- `parent` must look like `projects/.../locations/global/catalogs/default_catalog/branches/default_branch`\n- `reconciliation_mode` defaults to incremental\n- If you set `update_mask`, missing products are not created\n- `notification_pubsub_topic` is only supported with `FULL` reconciliation\n\n## Get Recommendations\n\nRecommendations are served through `PredictionServiceClient.predict()`. The official `PredictRequest` docs say `placement` can be either a `servingConfigs/*` resource or the legacy `placements/*` form, with `servingConfigs/*` preferred.\n\n```python\nfrom google.cloud import retail_v2\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\n\nclient = retail_v2.PredictionServiceClient()\n\nrequest = retail_v2.PredictRequest(\n    placement=(\n        f\"projects/{project_id}/locations/{location}/\"\n        f\"catalogs/{catalog}/servingConfigs/default_recommendation_config\"\n    ),\n    user_event=retail_v2.UserEvent(\n        event_type=\"detail-page-view\",\n        visitor_id=\"anon-session-7d6b4d3c\",\n    ),\n    page_size=10,\n)\n\nresponse = client.predict(request=request)\n\nfor prediction in response.results:\n    print(prediction.id)\n```\n\nThe request docs also warn that the inline `user_event` in `PredictRequest` is not written to Retail's event logs. If you need logging and training data, send a separate `write_user_event()` call too.\n\n## Record User Events\n\nUse `UserEventServiceClient.write_user_event()` for real-time clickstream or behavioral signals.\n\n```python\nfrom google.cloud import retail_v2\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\n\nclient = retail_v2.UserEventServiceClient()\nparent = f\"projects/{project_id}/locations/{location}/catalogs/{catalog}\"\n\nresponse = client.write_user_event(\n    request=retail_v2.WriteUserEventRequest(\n        parent=parent,\n        user_event=retail_v2.UserEvent(\n            event_type=\"search\",\n            visitor_id=\"anon-session-7d6b4d3c\",\n            search_query=\"running shoes\",\n        ),\n    )\n)\n\nprint(response)\n```\n\nPractical notes from the official request docs:\n\n- `parent` is the catalog resource, not the branch\n- `user_event` is required\n- `write_async=True` can return success before the event is fully written; silent failures then show up in Cloud Logging\n\n## Autocomplete\n\nThe package overview lists completion support in the Retail family, and `CompleteQueryRequest` is documented in the reference. The directly indexed `CompletionServiceClient` page currently resolves under `retail_v2beta`, so verify the namespace in your installed version before committing autocomplete code.\n\n```python\nfrom google.cloud import retail_v2beta\n\nproject_id = \"my-project\"\nlocation = \"global\"\ncatalog = \"default_catalog\"\n\nclient = retail_v2beta.CompletionServiceClient()\n\nresponse = client.complete_query(\n    request=retail_v2beta.CompleteQueryRequest(\n        catalog=f\"projects/{project_id}/locations/{location}/catalogs/{catalog}\",\n        query=\"run\",\n        visitor_id=\"anon-session-7d6b4d3c\",\n    )\n)\n\nprint(response)\n```\n\nThe documented request shape matters:\n\n- `catalog` is required\n- `query` is required and limited to 255 characters\n- `visitor_id` is recommended, must be UTF-8, and has a 128-character limit\n- Completion is only available when Retail Search is enabled\n\n## Logging And Debugging\n\nThe PyPI package page documents built-in Python logging support for Google client libraries.\n\nEnvironment-based logging:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nCode-based logging:\n\n```python\nimport logging\n\nbase_logger = logging.getLogger(\"google\")\nbase_logger.addHandler(logging.StreamHandler())\nbase_logger.setLevel(logging.DEBUG)\n```\n\nThe package notes also say logging is not configured by default and may include sensitive information.\n\n## Common Pitfalls\n\n- Do not invent resource names. Use helper methods like `branch_path()` and `serving_config_path()` where available.\n- Do not omit `visitor_id`. Search, recommendations, and autocomplete all rely on it for useful personalization and event attribution.\n- Do not assume `PredictRequest.user_event` writes an event log entry. It does not.\n- Do not mix up parent scopes:\n  - product import uses a branch parent\n  - user-event writes use a catalog parent\n  - search uses `placement` plus an optional branch\n- Do not trust the docs site version label as the package version. The reference currently says `2.7.0 (latest)` while PyPI serves `2.9.0`.\n- Do not default to service account keys in production when an attached service account is available.\n\n## Version-Sensitive Notes\n\n- PyPI shows `google-cloud-retail 2.9.0`, released on January 29, 2026.\n- The canonical Google Python reference root redirects to `https://docs.cloud.google.com/python/docs/reference/retail/latest`, but its visible `latest` label and changelog still stop at `2.7.0` as of March 12, 2026.\n- The generated client reference pages used here were last updated on October 30, 2025, while the Google Cloud authentication pages were updated on March 11, 2026.\n- Completion/autocomplete documentation currently appears split: the package overview exposes completion under Retail V2, while the directly indexed `CompletionServiceClient` page resolves under `retail_v2beta`.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-retail/\n- Python reference root: https://cloud.google.com/python/docs/reference/retail/latest\n- Changelog: https://cloud.google.com/python/docs/reference/retail/latest/changelog\n- Search client: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.services.search_service.SearchServiceClient\n- Search request: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.types.SearchRequest\n- Product client: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.services.product_service.ProductServiceClient\n- Import products request: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.types.ImportProductsRequest\n- Prediction client: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.services.prediction_service.PredictionServiceClient\n- Predict request: https://docs.cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.types.PredictRequest\n- User event client: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.services.user_event_service.UserEventServiceClient\n- Write user event request: https://docs.cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.types.WriteUserEventRequest\n- Complete query request: https://cloud.google.com/python/docs/reference/retail/latest/google.cloud.retail_v2.types.CompleteQueryRequest\n- ADC overview: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- ADC local development: https://docs.cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- ADC search order: https://cloud.google.com/docs/authentication/application-default-credentials\n"
  },
  {
    "path": "content/google/docs/run/javascript/DOC.md",
    "content": "---\nname: run\ndescription: \"Google Cloud Run Node.js client for managing services, jobs, executions, and tasks\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,cloud-run,serverless,jobs,javascript,nodejs\"\n---\n\n# `@google-cloud/run` JavaScript Package Guide\n\nUse `@google-cloud/run` when your Node.js code needs to manage Cloud Run resources through the Cloud Run Admin API.\n\n- Use this package for control-plane automation such as creating services, creating jobs, running jobs, and inspecting executions.\n- Do not use this package to send HTTP requests to a deployed Cloud Run service URL. For runtime requests, call the service URL with your normal HTTP client.\n\n## Golden Rule\n\n- Authenticate with Application Default Credentials (ADC), not an API key.\n- Use the `v2` clients for normal Cloud Run automation in Node.js.\n- Build full resource names as `projects/{project}/locations/{location}/...`.\n- Treat create, update, delete, and run calls as long-running operations and wait for `operation.promise()`.\n- Use `ServicesClient` and `JobsClient` to mutate resources, then use `ExecutionsClient` and `TasksClient` to inspect what happened.\n\nThis guide covers `3.2.0`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/run@3.2.0\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials.\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud services enable run.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nFor a service account JSON key file when you explicitly need one:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nTypical prerequisites:\n\n1. The target Google Cloud project already exists.\n2. The Cloud Run API is enabled for that project.\n3. The calling identity can manage Cloud Run resources in the target project and region.\n4. Any container image you reference already exists in Artifact Registry or another supported registry.\n\n## Initialize The Clients\n\nCommonJS:\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst servicesClient = new v2.ServicesClient();\nconst jobsClient = new v2.JobsClient();\nconst executionsClient = new v2.ExecutionsClient();\nconst tasksClient = new v2.TasksClient();\n```\n\nES modules:\n\n```javascript\nimport {v2} from '@google-cloud/run';\n\nconst servicesClient = new v2.ServicesClient();\nconst jobsClient = new v2.JobsClient();\nconst executionsClient = new v2.ExecutionsClient();\nconst tasksClient = new v2.TasksClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst client = new v2.ServicesClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`.\n\n## Resource Names\n\nBuild resource names explicitly in code:\n\n- parent location: `projects/PROJECT_ID/locations/LOCATION`\n- service: `projects/PROJECT_ID/locations/LOCATION/services/SERVICE_ID`\n- job: `projects/PROJECT_ID/locations/LOCATION/jobs/JOB_ID`\n- execution: `projects/PROJECT_ID/locations/LOCATION/jobs/JOB_ID/executions/EXECUTION_ID`\n- task: `projects/PROJECT_ID/locations/LOCATION/jobs/JOB_ID/executions/EXECUTION_ID/tasks/TASK_ID`\n\nUse `parent` when listing or creating resources and full `name` values when getting, updating, deleting, or running a specific resource.\n\n## Client Surface\n\nFor most Node.js automation, these are the main clients to reach for:\n\n- `v2.ServicesClient` for service CRUD\n- `v2.JobsClient` for job CRUD and `runJob()`\n- `v2.ExecutionsClient` for listing and fetching job executions\n- `v2.TasksClient` for listing and fetching tasks inside an execution\n\n## Core Workflows\n\n### List And Get Services\n\nUse the location parent for listing and the full service name for lookups.\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst client = new v2.ServicesClient();\n\nasync function listAndGetService(projectId, location, serviceId) {\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  for await (const service of client.listServicesAsync({parent})) {\n    console.log(service.name);\n  }\n\n  const name = `projects/${projectId}/locations/${location}/services/${serviceId}`;\n  const [service] = await client.getService({name});\n  return service;\n}\n```\n\n### Create A Service\n\nSend `parent`, `serviceId`, and a `service` object, then wait for the long-running operation to finish.\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst client = new v2.ServicesClient();\n\nasync function createService(projectId, location) {\n  const [operation] = await client.createService({\n    parent: `projects/${projectId}/locations/${location}`,\n    serviceId: 'hello-service',\n    service: {\n      template: {\n        serviceAccount: 'runtime-sa@my-project.iam.gserviceaccount.com',\n        containers: [\n          {\n            image: 'us-docker.pkg.dev/my-project/apps/hello:latest',\n            env: [\n              {name: 'NODE_ENV', value: 'production'},\n            ],\n          },\n        ],\n      },\n    },\n  });\n\n  const [service] = await operation.promise();\n  return service;\n}\n```\n\n### Create And Run A Job\n\nCloud Run jobs are separate resources. Create the job first, then call `runJob()` on the created job name.\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst client = new v2.JobsClient();\n\nasync function createAndRunJob(projectId, location) {\n  const [createOperation] = await client.createJob({\n    parent: `projects/${projectId}/locations/${location}`,\n    jobId: 'daily-job',\n    job: {\n      template: {\n        taskCount: 1,\n        parallelism: 1,\n        template: {\n          serviceAccount: 'runtime-sa@my-project.iam.gserviceaccount.com',\n          containers: [\n            {\n              image: 'us-docker.pkg.dev/my-project/batch/worker:latest',\n              args: ['--mode', 'daily'],\n              env: [\n                {name: 'APP_ENV', value: 'prod'},\n              ],\n            },\n          ],\n          timeout: {\n            seconds: 1800,\n          },\n        },\n      },\n    },\n  });\n\n  const [job] = await createOperation.promise();\n\n  const [runOperation] = await client.runJob({\n    name: job.name,\n  });\n\n  const [execution] = await runOperation.promise();\n  return execution;\n}\n```\n\n### Inspect Executions And Tasks\n\nUse the execution and task clients after a job run instead of trying to infer execution state from the job object.\n\n```javascript\nconst {v2} = require('@google-cloud/run');\n\nconst executionsClient = new v2.ExecutionsClient();\nconst tasksClient = new v2.TasksClient();\n\nasync function inspectJobRun(projectId, location, jobId) {\n  const jobName = `projects/${projectId}/locations/${location}/jobs/${jobId}`;\n  const executionParent = `${jobName}/executions`;\n\n  for await (const execution of executionsClient.listExecutionsAsync({\n    parent: executionParent,\n  })) {\n    console.log('execution:', execution.name);\n  }\n}\n\nasync function listTasksForExecution(executionName) {\n  for await (const task of tasksClient.listTasksAsync({\n    parent: executionName,\n  })) {\n    console.log('task:', task.name);\n  }\n}\n```\n\n## Configuration Notes\n\n- Keep project ID and region explicit in your code so you do not mutate the wrong environment.\n- Cloud Run resource names are regional. A job or service name for `us-central1` does not resolve in `europe-west1`.\n- Mutating calls are asynchronous. Wait for `operation.promise()` before reading the resource again or assuming the change is complete.\n- For partial updates, send an `updateMask` that matches the fields you intend to change.\n- Use the service client for services and the job client for jobs; executions and tasks are follow-on resources created by a job run.\n\n## Common Pitfalls\n\n- This package manages Cloud Run resources; it does not replace the runtime contract inside your container.\n- Do not use API keys. Use ADC for local development, CI, and Google Cloud runtimes.\n- Do not pass only a short resource ID to `getService()`, `getJob()`, or similar methods. Use the full resource name.\n- Do not assume create, update, delete, or run methods finish synchronously.\n- Do not mix service URLs with service resource names. A deployed HTTPS URL is not the same thing as `projects/.../services/...`.\n- If you update only part of a resource, do not omit the field mask.\n\n## Official Sources\n\n- Node.js client reference root: `https://cloud.google.com/nodejs/docs/reference/run/latest`\n- Application Default Credentials overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- ADC search order: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/run`\n"
  },
  {
    "path": "content/google/docs/run/python/DOC.md",
    "content": "---\nname: run\ndescription: \"Google Cloud Run Python client library for managing services, jobs, executions, tasks, revisions, and worker pools\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,cloud-run,serverless,containers,jobs,google-cloud\"\n---\n\n# Google Cloud Run Python Client\n\n## Golden Rule\n\nUse `google-cloud-run` for Cloud Run control-plane automation in Python.\n\n- This package manages Cloud Run resources such as services, jobs, executions, tasks, revisions, and worker pools.\n- It does not replace the Cloud Run runtime contract inside your container. Your deployed app still needs to listen on the expected port and handle requests normally.\n- Authenticate with Application Default Credentials (ADC). For local development, use `gcloud auth application-default login` or set `GOOGLE_APPLICATION_CREDENTIALS` to a service account key file if you explicitly need file-based credentials.\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-run==0.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-run==0.15.0\"\npoetry add \"google-cloud-run==0.15.0\"\n```\n\n## Authentication And Setup\n\nCloud Run uses Google Cloud authentication, so start with ADC instead of hand-rolling tokens.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nService account key file when needed:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nBasic client setup:\n\n```python\nimport os\nfrom google.cloud import run_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nservices_client = run_v2.ServicesClient()\njobs_client = run_v2.JobsClient()\n```\n\nIf you need a custom endpoint or universe domain, pass `client_options` when creating the client. The generated clients expose `api_endpoint` and `universe_domain` settings through `client_options`.\n\n## Client Surface\n\nThe package is organized around API-specific clients:\n\n- `ServicesClient` / `ServicesAsyncClient`\n- `JobsClient` / `JobsAsyncClient`\n- `ExecutionsClient`\n- `TasksClient`\n- `RevisionsClient`\n- `WorkerPoolsClient`\n- `BuildsClient`\n\nUse `ServicesClient` for service CRUD, `JobsClient` for job CRUD and job execution, and the other clients when you need to inspect the resources created by those operations.\n\n## Core Usage\n\n### List and fetch services\n\n```python\nimport os\nfrom google.cloud import run_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = run_v2.ServicesClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nfor service in client.list_services(parent=parent):\n    print(service.name, list(service.urls))\n\nservice_name = client.service_path(project_id, location, \"hello-service\")\nservice = client.get_service(name=service_name)\nprint(service.name)\nprint(list(service.urls))\n```\n\n### Create a service\n\nCloud Run mutations are long-running operations. Call `.result()` before assuming the resource exists.\n\n```python\nimport os\nfrom google.cloud import run_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = run_v2.ServicesClient()\n\nservice = run_v2.Service(\n    template=run_v2.RevisionTemplate(\n        service_account=\"runtime-sa@my-project.iam.gserviceaccount.com\",\n        containers=[\n            run_v2.Container(\n                image=\"us-docker.pkg.dev/cloudrun/container/hello\",\n                env=[run_v2.EnvVar(name=\"APP_ENV\", value=\"prod\")],\n            )\n        ],\n    )\n)\n\noperation = client.create_service(\n    parent=parent,\n    service=service,\n    service_id=\"hello-service\",\n)\n\ncreated = operation.result()\nprint(created.name)\nprint(list(created.urls))\n```\n\n### Update a service with an update mask\n\nPatch updates need a `FieldMask`. Only the paths in the update mask are applied.\n\n```python\nimport os\nfrom google.cloud import run_v2\nfrom google.protobuf import field_mask_pb2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = run_v2.ServicesClient()\nservice_name = client.service_path(project_id, location, \"hello-service\")\nservice = client.get_service(name=service_name)\n\nservice.template.containers[0].env.append(\n    run_v2.EnvVar(name=\"FEATURE_FLAG\", value=\"on\")\n)\n\nupdate_mask = field_mask_pb2.FieldMask(paths=[\"template.containers\"])\nupdated = client.update_service(\n    service=service,\n    update_mask=update_mask,\n).result()\n\nprint(updated.name)\n```\n\n### Create and run a job\n\nJobs also return long-running operations. `run_job()` returns an operation whose result is an `Execution`.\n\n```python\nimport os\nfrom google.cloud import run_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\nparent = f\"projects/{project_id}/locations/{location}\"\n\nclient = run_v2.JobsClient()\n\njob = run_v2.Job(\n    template=run_v2.ExecutionTemplate(\n        task_count=1,\n        template=run_v2.TaskTemplate(\n            service_account=\"runtime-sa@my-project.iam.gserviceaccount.com\",\n            containers=[\n                run_v2.Container(\n                    image=\"us-docker.pkg.dev/my-project/batch/worker:latest\",\n                    args=[\"--mode\", \"daily\"],\n                    env=[run_v2.EnvVar(name=\"APP_ENV\", value=\"prod\")],\n                )\n            ],\n        ),\n    )\n)\n\ncreated = client.create_job(\n    parent=parent,\n    job=job,\n    job_id=\"daily-job\",\n).result()\n\nexecution = client.run_job(name=created.name).result()\nprint(execution.name)\n```\n\n### Inspect executions and tasks\n\nUse the follow-on clients instead of trying to infer execution state from the original job resource.\n\n```python\nfrom google.cloud import run_v2\n\nexecutions = run_v2.ExecutionsClient()\ntasks = run_v2.TasksClient()\n\njob_name = \"projects/my-project/locations/us-central1/jobs/daily-job\"\nexecution_parent = f\"{job_name}/executions\"\n\nfor execution in executions.list_executions(parent=execution_parent):\n    print(execution.name)\n\ntask_parent = f\"{job_name}/executions/my-execution\"\nfor task in tasks.list_tasks(parent=task_parent):\n    print(task.name)\n```\n\n## Async Usage\n\nIf the rest of your application is already async, use the async variants rather than wrapping sync clients in thread pools.\n\n```python\nimport os\nfrom google.cloud import run_v2\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = run_v2.ServicesAsyncClient()\nparent = f\"projects/{project_id}/locations/{location}\"\n\nasync def list_services() -> None:\n    async for service in client.list_services(parent=parent):\n        print(service.name)\n```\n\n## Configuration Notes\n\n- Resource names follow the usual Google Cloud pattern, such as `projects/{project}/locations/{location}/services/{service}` and `projects/{project}/locations/{location}/jobs/{job}`.\n- Prefer the client helper methods like `service_path()` and `job_path()` when you need a resource name string.\n- The generated clients support `client_options`, `credentials`, `transport`, and custom retry/timeout values. Use those instead of patching transport internals.\n- For local or CI automation, export `GOOGLE_CLOUD_PROJECT` and the location you deploy into so your scripts do not silently mutate the wrong region.\n\n## Common Pitfalls\n\n- This package manages Cloud Run resources; it does not deploy source code directly for you. You still need a container image or another supported deployment artifact in the resource template.\n- Always wait on long-running operations with `.result()`. Create, update, delete, and run calls do not complete synchronously.\n- Do not mix regions. A service or job name built for `us-central1` will not resolve in `europe-west1`.\n- Use an update mask for partial updates. Without it, agents often assume a mutated local object automatically patches server-side state.\n- ADC is the normal auth path. Hard-coded access tokens and checked-in service account keys are the wrong default.\n- If you override job execution arguments or environment variables, verify the container names and override fields against the generated request types before sending the request.\n- The client surface includes worker-pool APIs. Do not assume worker pools exist in every project or region your code targets.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI and the generated reference both show `google-cloud-run 0.15.0`.\n- The published changelog page under the `latest` docs root currently lists entries through `0.14.0`, so release-note coverage appears to lag the package version. If you need exact `0.15.0` change details, double-check PyPI release history or the package repository before assuming the changelog page is complete.\n- The generated changelog records notable recent behavior changes:\n  - `0.14.0` added automatic mTLS enablement when a client certificate is available and mTLS is not explicitly disabled.\n  - `0.12.0` deprecated the `credentials_file` helper argument in client constructors.\n  - `0.11.0` included breaking changes around worker pools and build worker pools.\n\n## Official Sources\n\n- Cloud Run Python reference root: `https://cloud.google.com/python/docs/reference/run/latest`\n- Services client reference: `https://cloud.google.com/python/docs/reference/run/latest/google.cloud.run_v2.services.services.ServicesClient`\n- Jobs client reference: `https://cloud.google.com/python/docs/reference/run/latest/google.cloud.run_v2.services.jobs.JobsClient`\n- Changelog: `https://cloud.google.com/python/docs/reference/run/latest/changelog`\n- PyPI package page: `https://pypi.org/project/google-cloud-run/`\n- Google Cloud ADC guide: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/scheduler/javascript/DOC.md",
    "content": "---\nname: scheduler\ndescription: \"Google Cloud Scheduler Node.js client for creating and managing scheduled HTTP, Pub/Sub, and App Engine jobs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,scheduler,gcp,cron,jobs,http,pubsub,app-engine\"\n---\n\n# Google Cloud Scheduler Node.js Client\n\n## What This Package Is\n\n`@google-cloud/scheduler` is the official Node.js client for Google Cloud Scheduler.\n\nUse it when your application needs to create or manage scheduled jobs that deliver work to exactly one of these target types:\n\n- HTTP endpoints\n- Pub/Sub topics\n- App Engine HTTP handlers\n\nFor most integrations, the main job of this package is control-plane work: create the job, update the schedule, inspect state, and trigger administrative operations such as pause, resume, run, or delete.\n\nThis guide targets `@google-cloud/scheduler` version `5.3.1`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\nnpm install @google-cloud/scheduler@5.3.1\n```\n\nCommon alternatives:\n\n```bash\npnpm add @google-cloud/scheduler@5.3.1\nyarn add @google-cloud/scheduler@5.3.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key. For local development, the standard setup is Application Default Credentials (ADC):\n\n```bash\ngcloud services enable cloudscheduler.googleapis.com\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nIf you need to point ADC at a service account key file locally:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\nThere are two separate auth concerns in a real Scheduler integration:\n\n1. Your Node.js code must authenticate to the Cloud Scheduler API.\n2. Cloud Scheduler may need to authenticate from the scheduled job to the target service.\n\n## Initialize The Client\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nconst client = new v1.CloudSchedulerClient();\n\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = 'us-central1';\nconst parent = `projects/${projectId}/locations/${location}`;\nconst jobName = `${parent}/jobs/daily-report`;\n```\n\nUse explicit resource names unless you already rely on helper methods elsewhere in your codebase.\n\n## Create An HTTP Job\n\nHTTP jobs are the common case for Cloud Run, custom HTTPS services, and internal webhooks.\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nasync function createDailyReportJob({\n  projectId,\n  location,\n  jobId,\n  url,\n  serviceAccountEmail,\n}) {\n  const client = new v1.CloudSchedulerClient();\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  const [job] = await client.createJob({\n    parent,\n    job: {\n      name: `${parent}/jobs/${jobId}`,\n      description: 'Call the daily report endpoint every morning',\n      schedule: '0 9 * * *',\n      timeZone: 'Etc/UTC',\n      httpTarget: {\n        uri: url,\n        httpMethod: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: Buffer.from(\n          JSON.stringify({reportType: 'daily'})\n        ),\n        oidcToken: {\n          serviceAccountEmail,\n          audience: url,\n        },\n      },\n      retryConfig: {\n        retryCount: 3,\n        minBackoffDuration: {seconds: 30},\n        maxBackoffDuration: {seconds: 300},\n        maxDoublings: 5,\n      },\n      attemptDeadline: {seconds: 180},\n    },\n  });\n\n  return job;\n}\n```\n\nUse `oidcToken` when the target validates a Google-signed OIDC identity token, including Cloud Run and many custom HTTPS backends.\n\nFor protected Cloud Run services, grant the Scheduler job's service account permission to invoke the service before you create the job:\n\n```bash\ngcloud run services add-iam-policy-binding SERVICE_NAME \\\n  --region=us-central1 \\\n  --member=\"serviceAccount:SCHEDULER_INVOKER@YOUR_PROJECT_ID.iam.gserviceaccount.com\" \\\n  --role=\"roles/run.invoker\"\n```\n\nUse `oauthToken` instead of `oidcToken` when the target is a Google API on `*.googleapis.com` that expects an OAuth access token.\n\n## Create A Pub/Sub Job\n\nUse a Pub/Sub target when the scheduled action should publish work for downstream consumers instead of invoking an HTTP service directly.\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nasync function createPubSubJob({projectId, location, jobId, topicId}) {\n  const client = new v1.CloudSchedulerClient();\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  const [job] = await client.createJob({\n    parent,\n    job: {\n      name: `${parent}/jobs/${jobId}`,\n      schedule: '0 * * * *',\n      timeZone: 'Etc/UTC',\n      pubsubTarget: {\n        topicName: `projects/${projectId}/topics/${topicId}`,\n        data: Buffer.from(JSON.stringify({task: 'refresh-cache'})),\n        attributes: {\n          source: 'cloud-scheduler',\n        },\n      },\n    },\n  });\n\n  return job;\n}\n```\n\nThe Pub/Sub topic must be in the same project as the Cloud Scheduler job.\n\n## Create An App Engine Job\n\nUse an App Engine target only when you actually want App Engine routing behavior.\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nasync function createAppEngineJob({projectId, location, jobId}) {\n  const client = new v1.CloudSchedulerClient();\n  const parent = `projects/${projectId}/locations/${location}`;\n\n  const [job] = await client.createJob({\n    parent,\n    job: {\n      name: `${parent}/jobs/${jobId}`,\n      schedule: '0 3 * * *',\n      timeZone: 'Etc/UTC',\n      appEngineHttpTarget: {\n        relativeUri: '/tasks/cleanup',\n        httpMethod: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: Buffer.from(JSON.stringify({action: 'cleanup'})),\n      },\n    },\n  });\n\n  return job;\n}\n```\n\n## Read, List, And Update Jobs\n\nUse `getJob()` for one job, `listJobs()` for a location, and `updateJob()` with a field mask for partial changes.\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nasync function inspectAndReschedule({projectId, location, jobId}) {\n  const client = new v1.CloudSchedulerClient();\n  const parent = `projects/${projectId}/locations/${location}`;\n  const name = `${parent}/jobs/${jobId}`;\n\n  const [job] = await client.getJob({name});\n  console.log(job.state, job.schedule);\n\n  const [jobs] = await client.listJobs({\n    parent,\n    pageSize: 100,\n  });\n\n  for (const item of jobs) {\n    console.log(item.name, item.state);\n  }\n\n  const [updatedJob] = await client.updateJob({\n    job: {\n      name,\n      schedule: '30 9 * * *',\n      timeZone: 'America/Los_Angeles',\n    },\n    updateMask: {\n      paths: ['schedule', 'time_zone'],\n    },\n  });\n\n  return updatedJob;\n}\n```\n\nImportant update behavior:\n\n- `listJobs()` is paginated, and `pageSize` has a documented maximum of `500`.\n- `updateJob()` is a partial update. Use `updateMask`; do not rely on omitted fields being preserved by accident.\n- If an update fails, the job can enter `UPDATE_FAILED`. Retry `updateJob()` until it succeeds.\n\n## Pause, Resume, Run, And Delete\n\nThese operations are direct administrative RPCs on an existing job resource.\n\n```javascript\nconst {v1} = require('@google-cloud/scheduler');\n\nasync function manageJob({projectId, location, jobId}) {\n  const client = new v1.CloudSchedulerClient();\n  const name = `projects/${projectId}/locations/${location}/jobs/${jobId}`;\n\n  await client.pauseJob({name});\n  await client.resumeJob({name});\n  await client.runJob({name});\n  await client.deleteJob({name});\n}\n```\n\nOperational behavior to remember:\n\n- `pauseJob()` applies to an enabled job.\n- `resumeJob()` applies to a paused job.\n- `runJob()` forces an immediate execution and is not a dry run.\n\n## Target Authentication Rules\n\nFor HTTP job targets:\n\n- Use `oidcToken` for services that expect an OIDC identity token.\n- Use `oauthToken` when the target is a Google API on `*.googleapis.com`.\n- The service account configured in `oidcToken` or `oauthToken` must belong to the same project as the job.\n- If you set `oidcToken` or `oauthToken`, Cloud Scheduler overrides any `Authorization` header you put in `httpTarget.headers`.\n\nFor Cloud Run and other protected backends, grant the configured service account permission on the receiving service before scheduling the job.\n\n## Retry, Deadline, And Scheduling Semantics\n\nImportant runtime behavior from the Cloud Scheduler RPC and product docs:\n\n- Cloud Scheduler does not allow two outstanding executions of the same job at the same time.\n- If one execution is still running when the next schedule time arrives, the next execution is delayed.\n- `retryCount: 0` means failures are not retried before the next scheduled time.\n- For HTTP targets, `attemptDeadline` must be between 15 seconds and 30 minutes.\n- For Pub/Sub targets, `attemptDeadline` is ignored.\n\n## Common Pitfalls\n\n- HTTP request bodies are valid only for `POST`, `PUT`, or `PATCH`.\n- If you send a body and omit `Content-Type`, Cloud Scheduler defaults it to `application/octet-stream`.\n- Cloud Scheduler computes or overwrites several HTTP headers, including `Host`, `Content-Length`, `User-Agent`, and `X-CloudScheduler-*`.\n- Total HTTP header size must stay under `80 KB`.\n- `appEngineHttpTarget.relativeUri` must start with `/`.\n- `PATCH` and `OPTIONS` are not allowed for `appEngineHttpTarget`.\n- Always set `timeZone` intentionally. Do not rely on local machine timezone assumptions.\n- Prefer request objects such as `client.createJob({parent, job})` and `client.updateJob({job, updateMask})` over handwritten wrappers that hide the actual API shape.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/scheduler` version `5.3.1`.\n- The maintainer reference URL uses `latest`. If you depend on a recently added field or behavior, compare the generated reference with the package version installed in your project.\n\n## Official Sources\n\n- Node.js client reference: https://cloud.google.com/nodejs/docs/reference/scheduler/latest\n- Cloud Scheduler setup: https://cloud.google.com/scheduler/docs/setup\n- Cloud Scheduler authentication: https://cloud.google.com/scheduler/docs/authentication\n- Secure cron jobs with HTTP targets: https://cloud.google.com/scheduler/docs/http-target-auth\n- Cloud Scheduler RPC reference: https://cloud.google.com/scheduler/docs/reference/rpc/google.cloud.scheduler.v1\n- npm package page: https://www.npmjs.com/package/@google-cloud/scheduler\n"
  },
  {
    "path": "content/google/docs/scheduler/python/DOC.md",
    "content": "---\nname: scheduler\ndescription: \"Google Cloud Scheduler Python client for creating and managing scheduled HTTP, Pub/Sub, and App Engine jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.18.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,scheduler,gcp,cron,jobs,http,pubsub,app-engine\"\n---\n\n# google-cloud-scheduler Python Package Guide\n\n## What This Package Is\n\n`google-cloud-scheduler` is the official Python client library for Google Cloud Scheduler.\n\nUse it when your Python code needs to create or manage scheduled jobs that deliver work to exactly one of these target types:\n\n- HTTP endpoints\n- Pub/Sub topics\n- App Engine HTTP handlers\n\nThe generated client gives you sync and async clients for the Cloud Scheduler API, plus typed request and resource objects such as `Job`, `HttpTarget`, `PubsubTarget`, `RetryConfig`, and `OidcToken`.\n\n## Install\n\nThe maintainer README and PyPI package page currently publish `2.18.0`.\n\n```bash\npip install google-cloud-scheduler==2.18.0\n```\n\nUnpinned install:\n\n```bash\npip install google-cloud-scheduler\n```\n\nWith `uv`:\n\n```bash\nuv add google-cloud-scheduler\n```\n\nThe package metadata in the maintainer repo lists `Python >= 3.7`.\n\n## Setup And Authentication\n\nBefore the client works, you need a Google Cloud project with Cloud Scheduler enabled and Application Default Credentials (ADC) configured for the code that calls the API.\n\nEnable the API:\n\n```bash\ngcloud services enable cloudscheduler.googleapis.com\n```\n\nSet up local ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nIf you need ADC backed by service account impersonation:\n\n```bash\ngcloud auth application-default login \\\n  --impersonate-service-account=SERVICE_ACCT_EMAIL\n```\n\nOn Google Cloud runtimes, prefer workload-attached service accounts and let ADC resolve credentials automatically.\n\n## Imports And Client Creation\n\n```python\nfrom google.cloud import scheduler_v1\n\nclient = scheduler_v1.CloudSchedulerClient()\n```\n\nAsync client:\n\n```python\nfrom google.cloud import scheduler_v1\n\nclient = scheduler_v1.CloudSchedulerAsyncClient()\n```\n\nBuild resource names explicitly:\n\n```python\nproject_id = \"my-project\"\nlocation_id = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location_id}\"\njob_name = f\"{parent}/jobs/daily-report\"\n```\n\n## Core Pattern: Create An HTTP Job\n\nHTTP jobs are the common case for Cloud Run, custom HTTPS services, and internal webhooks.\n\n```python\nfrom google.cloud import scheduler_v1\nfrom google.protobuf.duration_pb2 import Duration\n\nclient = scheduler_v1.CloudSchedulerClient()\n\nproject_id = \"my-project\"\nlocation_id = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location_id}\"\n\njob = scheduler_v1.Job(\n    name=f\"{parent}/jobs/daily-report\",\n    description=\"Call the daily report endpoint every morning\",\n    schedule=\"0 9 * * *\",\n    time_zone=\"Etc/UTC\",\n    http_target=scheduler_v1.HttpTarget(\n        uri=\"https://reports-abc123-uc.a.run.app/run\",\n        http_method=scheduler_v1.HttpMethod.POST,\n        headers={\"Content-Type\": \"application/json\"},\n        body=b'{\"source\":\"cloud-scheduler\"}',\n        oidc_token=scheduler_v1.OidcToken(\n            service_account_email=\"scheduler-invoker@my-project.iam.gserviceaccount.com\",\n            audience=\"https://reports-abc123-uc.a.run.app/run\",\n        ),\n    ),\n    retry_config=scheduler_v1.RetryConfig(\n        retry_count=3,\n        min_backoff_duration=Duration(seconds=10),\n        max_backoff_duration=Duration(seconds=300),\n        max_doublings=5,\n    ),\n    attempt_deadline=Duration(seconds=180),\n)\n\ncreated = client.create_job(request={\"parent\": parent, \"job\": job})\nprint(created.name)\n```\n\nUse `oidc_token` for services that validate OpenID Connect identity tokens, including Cloud Run and most custom HTTPS targets.\n\n## Pub/Sub Job Example\n\nUse a Pub/Sub target when the scheduled action should enqueue work rather than invoke an HTTP service directly.\n\n```python\nimport json\n\nfrom google.cloud import scheduler_v1\n\nclient = scheduler_v1.CloudSchedulerClient()\n\nproject_id = \"my-project\"\nlocation_id = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location_id}\"\n\njob = scheduler_v1.Job(\n    name=f\"{parent}/jobs/hourly-refresh\",\n    schedule=\"0 * * * *\",\n    time_zone=\"Etc/UTC\",\n    pubsub_target=scheduler_v1.PubsubTarget(\n        topic_name=f\"projects/{project_id}/topics/hourly-jobs\",\n        data=json.dumps({\"task\": \"refresh-cache\"}).encode(\"utf-8\"),\n        attributes={\"source\": \"cloud-scheduler\"},\n    ),\n)\n\nclient.create_job(request={\"parent\": parent, \"job\": job})\n```\n\nThe RPC reference states that the Pub/Sub topic must be in the same project as the Cloud Scheduler job.\n\n## App Engine Job Example\n\nUse an App Engine target only when you actually want App Engine routing behavior.\n\n```python\nfrom google.cloud import scheduler_v1\n\nclient = scheduler_v1.CloudSchedulerClient()\n\nproject_id = \"my-project\"\nlocation_id = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location_id}\"\n\njob = scheduler_v1.Job(\n    name=f\"{parent}/jobs/app-engine-cleanup\",\n    schedule=\"0 3 * * *\",\n    time_zone=\"Etc/UTC\",\n    app_engine_http_target=scheduler_v1.AppEngineHttpTarget(\n        relative_uri=\"/tasks/cleanup\",\n        http_method=scheduler_v1.HttpMethod.POST,\n        headers={\"Content-Type\": \"application/json\"},\n        body=b'{\"action\":\"cleanup\"}',\n    ),\n)\n\nclient.create_job(request={\"parent\": parent, \"job\": job})\n```\n\n## Read, List, And Update Jobs\n\n```python\nfrom google.cloud import scheduler_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = scheduler_v1.CloudSchedulerClient()\n\njob_name = \"projects/my-project/locations/us-central1/jobs/daily-report\"\n\njob = client.get_job(request={\"name\": job_name})\nprint(job.state.name)\nprint(job.schedule)\n\nparent = \"projects/my-project/locations/us-central1\"\nfor item in client.list_jobs(request={\"parent\": parent, \"page_size\": 100}):\n    print(item.name, item.state.name)\n\npatch = scheduler_v1.Job(\n    name=job_name,\n    schedule=\"30 9 * * *\",\n    time_zone=\"America/Los_Angeles\",\n)\n\nmask = FieldMask(paths=[\"schedule\", \"time_zone\"])\nupdated = client.update_job(request={\"job\": patch, \"update_mask\": mask})\nprint(updated.schedule)\n```\n\nImportant update behavior from the generated reference:\n\n- `list_jobs` is paginated and `page_size` has a documented maximum of `500`.\n- `update_job` is a partial update. Use `FieldMask`; do not assume omitted fields are preserved safely by accident.\n- If an update fails, the job can enter `UPDATE_FAILED`. Retry `update_job` until it succeeds.\n\n## Pause, Resume, Run, And Delete\n\n```python\nfrom google.cloud import scheduler_v1\n\nclient = scheduler_v1.CloudSchedulerClient()\njob_name = \"projects/my-project/locations/us-central1/jobs/daily-report\"\n\nclient.pause_job(request={\"name\": job_name})\nclient.resume_job(request={\"name\": job_name})\nclient.run_job(request={\"name\": job_name})\nclient.delete_job(request={\"name\": job_name})\n```\n\nOperational behavior to remember:\n\n- `pause_job` applies to an enabled job.\n- `resume_job` applies to a paused job.\n- `run_job` forces an immediate execution and is not a dry run.\n\n## Target Authentication Rules\n\nThere are two separate auth problems:\n\n1. Your Python code must authenticate to the Cloud Scheduler API.\n2. Cloud Scheduler may need to authenticate from the job to the target service.\n\nFor the first, use ADC.\n\nFor HTTP job targets:\n\n- Use `oidc_token` for services that expect an OIDC identity token.\n- Use `oauth_token` when the target is a Google API on `*.googleapis.com`.\n- The service account configured in `oidc_token` or `oauth_token` must belong to the same project as the job.\n- If you set `oidc_token` or `oauth_token`, Cloud Scheduler overrides any `Authorization` header you put in `http_target.headers`.\n\nFor Cloud Run or another protected backend, grant the service account permission to invoke the target before you schedule the job.\n\n## Retry, Deadline, And Scheduling Semantics\n\nImportant runtime behavior from the RPC and generated reference docs:\n\n- Cloud Scheduler does not allow two outstanding executions of the same job at the same time.\n- If one execution is still running when the next schedule time arrives, the next execution is delayed.\n- `retry_count=0` means failures are not retried before the next scheduled time.\n- For HTTP targets, `attempt_deadline` must be between 15 seconds and 30 minutes.\n- For Pub/Sub targets, `attempt_deadline` is ignored.\n\n## Common Pitfalls\n\n- HTTP request bodies are valid only for `POST`, `PUT`, or `PATCH`.\n- If you send a body and omit `Content-Type`, Cloud Scheduler defaults it to `application/octet-stream`.\n- Cloud Scheduler computes or overwrites several HTTP headers, including `Host`, `Content-Length`, `User-Agent`, and `X-CloudScheduler-*`.\n- Total HTTP header size must stay under 80 KB.\n- `AppEngineHttpTarget` requires `relative_uri` to start with `/`.\n- `PATCH` and `OPTIONS` are not allowed for `AppEngineHttpTarget`.\n- Always set `time_zone` intentionally. Do not rely on local machine timezone assumptions.\n- Prefer explicit `request={...}` calls or typed request objects. That matches the generated library surface and is less brittle than positional-argument examples copied from old posts.\n\n## Version-Sensitive Notes\n\n- This guide covers package version `2.18.0`, which is the version currently shown on PyPI and in the maintainer package README.\n- The docs URL for this package points at the maintainer repo directory on GitHub. That repo is useful for install metadata and package-level release context, but operational API details are clearer in the generated Python reference and Cloud Scheduler product docs.\n- As of `2026-03-12`, Google’s generated `latest` reference pages appear to mix `2.17.0` and `2.18.0` labels across pages. When that happens, trust the installed package version in your environment and the actual generated method signatures over stale page chrome.\n\n## Official Sources\n\n- Maintainer package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-scheduler\n- Maintainer README: https://raw.githubusercontent.com/googleapis/google-cloud-python/main/packages/google-cloud-scheduler/README.rst\n- Python client reference: https://docs.cloud.google.com/python/docs/reference/cloudscheduler/latest\n- Cloud Scheduler setup: https://docs.cloud.google.com/scheduler/docs/setup\n- Cloud Scheduler authentication: https://docs.cloud.google.com/scheduler/docs/authentication\n- Secure cron jobs with HTTP targets: https://docs.cloud.google.com/scheduler/docs/http-target-auth\n- RPC reference: https://docs.cloud.google.com/scheduler/docs/reference/rpc/google.cloud.scheduler.v1\n- PyPI package page: https://pypi.org/project/google-cloud-scheduler/\n"
  },
  {
    "path": "content/google/docs/secret-manager/javascript/DOC.md",
    "content": "---\nname: secret-manager\ndescription: \"Google Cloud Secret Manager Node.js client for creating secrets, adding versions, accessing payloads, and managing secret version state\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,secret-manager,gcp,secrets,iam,javascript,nodejs\"\n---\n\n# `@google-cloud/secret-manager` JavaScript Package Guide\n\nUse `@google-cloud/secret-manager` in Node.js code that needs to create secrets, add immutable secret versions, read secret payloads, list secrets, and manage secret version state in Google Cloud Secret Manager.\n\n## Golden Rule\n\n- Import `SecretManagerServiceClient` from `@google-cloud/secret-manager`.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass credentials explicitly.\n- Secret values live in **secret versions**. Rotation means adding a new version, not editing an existing one.\n- Use an explicit version number when rollout control matters. `latest` always resolves to the newest created version.\n- Treat secret payloads as bytes and avoid logging plaintext secrets.\n- For regional secrets, keep the resource name and `apiEndpoint` in the same region.\n\nThis guide covers `6.1.1`.\n\n## Install\n\nPin the package version you want your app or agent to target:\n\n```bash\nnpm install @google-cloud/secret-manager@6.1.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nEnable the API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable secretmanager.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimum setup:\n\n1. Enable Secret Manager API in the target project.\n2. Make sure the credential resolves to the principal you expect.\n3. Grant the narrowest IAM role that matches the operation.\n\nCommon IAM roles:\n\n- `roles/secretmanager.secretAccessor` for reading secret payloads\n- `roles/secretmanager.secretVersionAdder` for adding versions to an existing secret\n- `roles/secretmanager.secretVersionManager` for enabling, disabling, listing, and destroying versions\n- `roles/secretmanager.admin` for creating and fully managing secrets\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {SecretManagerServiceClient} from '@google-cloud/secret-manager';\n\nconst client = new SecretManagerServiceClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Create A Secret\n\nCreate the secret container first. The secret value itself is stored in a secret version.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function createSecret(projectId, secretId) {\n  const [secret] = await client.createSecret({\n    parent: `projects/${projectId}`,\n    secretId,\n    secret: {\n      replication: {\n        automatic: {},\n      },\n    },\n  });\n\n  return secret.name;\n}\n```\n\nChoose the replication policy deliberately when you create the secret.\n\n### Add A Secret Version\n\nAdding a version is the normal way to rotate a secret value.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function addSecretVersion(projectId, secretId, value) {\n  const [version] = await client.addSecretVersion({\n    parent: `projects/${projectId}/secrets/${secretId}`,\n    payload: {\n      data: Buffer.from(value, 'utf8'),\n    },\n  });\n\n  return version.name;\n}\n```\n\n### Access A Secret Version\n\nUse a fixed version number when you need stable, reviewable configuration.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function accessSecretValue(projectId, secretId, versionId = 'latest') {\n  const [version] = await client.accessSecretVersion({\n    name: `projects/${projectId}/secrets/${secretId}/versions/${versionId}`,\n  });\n\n  const data = version.payload && version.payload.data;\n  if (!data) {\n    throw new Error('Secret payload is empty');\n  }\n\n  return data.toString('utf8');\n}\n```\n\n### Read Metadata Without Reading The Secret Value\n\nUse metadata methods when you do not need the plaintext payload.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function getSecretMetadata(projectId, secretId) {\n  const [secret] = await client.getSecret({\n    name: `projects/${projectId}/secrets/${secretId}`,\n  });\n\n  return secret;\n}\n\nasync function getSecretVersionMetadata(projectId, secretId, versionId) {\n  const [version] = await client.getSecretVersion({\n    name: `projects/${projectId}/secrets/${secretId}/versions/${versionId}`,\n  });\n\n  return version;\n}\n```\n\n### List Secrets\n\nUse the async iterator form when you want straightforward pagination.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function listSecretNames(projectId) {\n  const names = [];\n\n  for await (const secret of client.listSecretsAsync({\n    parent: `projects/${projectId}`,\n  })) {\n    names.push(secret.name);\n  }\n\n  return names;\n}\n```\n\n### Disable, Enable, Or Destroy A Secret Version\n\nDisable a version to block reads without permanently deleting it.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst client = new SecretManagerServiceClient();\n\nasync function disableSecretVersion(projectId, secretId, versionId) {\n  const [version] = await client.disableSecretVersion({\n    name: `projects/${projectId}/secrets/${secretId}/versions/${versionId}`,\n  });\n\n  return version.name;\n}\n\nasync function enableSecretVersion(projectId, secretId, versionId) {\n  const [version] = await client.enableSecretVersion({\n    name: `projects/${projectId}/secrets/${secretId}/versions/${versionId}`,\n  });\n\n  return version.name;\n}\n\nasync function destroySecretVersion(projectId, secretId, versionId) {\n  const [version] = await client.destroySecretVersion({\n    name: `projects/${projectId}/secrets/${secretId}/versions/${versionId}`,\n  });\n\n  return version.name;\n}\n```\n\nUse `destroySecretVersion` only when you intend permanent destruction.\n\n## Regional Secrets And Endpoints\n\nRegional secrets use location-qualified resource names and a regional API endpoint.\n\n```javascript\nconst {SecretManagerServiceClient} = require('@google-cloud/secret-manager');\n\nconst location = 'us-east1';\n\nconst client = new SecretManagerServiceClient({\n  apiEndpoint: `secretmanager.${location}.rep.googleapis.com`,\n});\n\nconst secretName = `projects/my-project/locations/${location}/secrets/my-secret`;\nconst versionName = `${secretName}/versions/latest`;\n```\n\nKeep the resource-name format and the endpoint in sync. Mixing a regional endpoint with global resource names is a common cause of `NotFound` and routing errors.\n\n## Common Pitfalls\n\n- A valid credential is not enough if the principal lacks Secret Manager IAM permissions on the project or secret.\n- `latest` points to the newest created version, not necessarily the exact version you intended to roll out.\n- Secret payloads are bytes. Convert outbound values with `Buffer.from(...)` and decode reads with `toString('utf8')`.\n- `accessSecretVersion` returns sensitive material. Prefer `getSecret` or `getSecretVersion` when you only need metadata.\n- Rotation means `addSecretVersion`, not mutation of an existing version.\n- Regional secrets require both regional resource names and the matching regional endpoint.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/secret-manager/latest`\n- Secret Manager product docs: `https://cloud.google.com/secret-manager/docs`\n- Secret Manager authentication docs: `https://cloud.google.com/secret-manager/docs/authentication`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Create secret sample: `https://cloud.google.com/secret-manager/docs/samples/secretmanager-create-secret`\n- Add secret version sample: `https://cloud.google.com/secret-manager/docs/samples/secretmanager-add-secret-version`\n- Access secret version sample: `https://cloud.google.com/secret-manager/docs/samples/secretmanager-access-secret-version`\n- Regional secret sample: `https://cloud.google.com/secret-manager/docs/samples/secretmanager-create-regional-secret`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/secret-manager`\n"
  },
  {
    "path": "content/google/docs/secret-manager/python/DOC.md",
    "content": "---\nname: secret-manager\ndescription: \"Google Cloud Secret Manager Python client for creating secrets, adding versions, accessing payloads, and managing version state\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.26.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,secret-manager,gcp,secrets,iam,adc,python\"\n---\n\n# google-cloud-secret-manager Python Package Guide\n\nUse `google-cloud-secret-manager` for Python code that needs to create secrets, add secret versions, read secret payloads, list secrets, and manage secret version state in Google Cloud Secret Manager.\n\n## Golden Rule\n\n- Install and import the official client: `from google.cloud import secretmanager`.\n- Prefer Application Default Credentials (ADC). For local development, use `gcloud auth application-default login` or set `GOOGLE_APPLICATION_CREDENTIALS`.\n- Secret values are immutable per version. To rotate a secret, add a new version instead of editing an existing one.\n- Use an explicit version number when rollout control matters. `latest` is convenient, but it always resolves to the newest created version.\n- Treat the secret payload as bytes and avoid logging plaintext secrets.\n\n## Version Covered\n\n- Package: `google-cloud-secret-manager`\n- Ecosystem: `pypi`\n- Version: `2.26.0`\n- Python requirement from PyPI: `>=3.7`\n- Registry: https://pypi.org/project/google-cloud-secret-manager/\n- Docs root used for this guide: https://docs.cloud.google.com/python/docs/reference/secretmanager/latest\n\n## Install\n\nPin the package version you want the agent to target:\n\n```bash\npython -m pip install google-cloud-secret-manager==2.26.0\n```\n\nIf you verify payload integrity with CRC32C checksums, install `google-crc32c` too:\n\n```bash\npython -m pip install google-crc32c\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not API keys.\n\nFor local development:\n\n```bash\ngcloud auth application-default login\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nMinimum setup:\n\n1. Enable the Secret Manager API in the target Google Cloud project.\n2. Make sure ADC resolves to the principal you expect.\n3. Grant the narrowest IAM role that matches the operation.\n\nCommon IAM roles from the product docs:\n\n- `roles/secretmanager.secretAccessor` for reading secret payloads\n- `roles/secretmanager.secretVersionAdder` for adding versions to an existing secret\n- `roles/secretmanager.secretVersionManager` for enabling, disabling, listing, and destroying versions\n- `roles/secretmanager.admin` for creating and fully managing secrets\n\nOn Compute Engine and GKE, Secret Manager client-library auth also depends on the underlying runtime having the `cloud-platform` access scope when metadata-based credentials are used.\n\n## Initialize The Client\n\nThe standard sync client picks up ADC automatically:\n\n```python\nfrom google.cloud import secretmanager\n\nclient = secretmanager.SecretManagerServiceClient()\n```\n\nThe generated reference also exposes `client_options` and `transport` when you need non-default behavior:\n\n```python\nfrom google.cloud import secretmanager\n\nclient = secretmanager.SecretManagerServiceClient(\n    transport=\"rest\",\n)\n```\n\nUse the helper methods for resource names instead of concatenating strings by hand:\n\n```python\nfrom google.cloud import secretmanager\n\nclient = secretmanager.SecretManagerServiceClient()\n\nsecret_name = client.secret_path(\"my-project\", \"db-password\")\nversion_name = client.secret_version_path(\"my-project\", \"db-password\", \"latest\")\n```\n\n## Core Usage\n\n### Create A Secret\n\nA secret is the metadata container. The actual secret bytes live in secret versions.\n\n```python\nfrom google.cloud import secretmanager\n\ndef create_secret(project_id: str, secret_id: str) -> str:\n    client = secretmanager.SecretManagerServiceClient()\n    parent = f\"projects/{project_id}\"\n\n    secret = client.create_secret(\n        request={\n            \"parent\": parent,\n            \"secret_id\": secret_id,\n            \"secret\": {\n                \"replication\": {\n                    \"automatic\": {},\n                }\n            },\n        }\n    )\n    return secret.name\n```\n\nKeep the replication policy intentional. The docs note that replication configuration is immutable after creation.\n\n### Add A Secret Version\n\nRotating a secret means adding a new version.\n\n```python\nfrom google.cloud import secretmanager\nimport google_crc32c\n\ndef add_secret_version(project_id: str, secret_id: str, value: str) -> str:\n    client = secretmanager.SecretManagerServiceClient()\n    parent = client.secret_path(project_id, secret_id)\n\n    payload = value.encode(\"utf-8\")\n    checksum = google_crc32c.Checksum()\n    checksum.update(payload)\n\n    version = client.add_secret_version(\n        request={\n            \"parent\": parent,\n            \"payload\": {\n                \"data\": payload,\n                \"data_crc32c\": int(checksum.hexdigest(), 16),\n            },\n        }\n    )\n    return version.name\n```\n\n`payload.data` must be bytes. The CRC32C value is optional, but Google samples recommend it when integrity matters.\n\n### Access A Secret Version\n\nUse a fixed version number when you want stable, reviewable configuration.\n\n```python\nfrom google.cloud import secretmanager\nimport google_crc32c\n\ndef access_secret_value(\n    project_id: str,\n    secret_id: str,\n    version_id: str = \"latest\",\n) -> str:\n    client = secretmanager.SecretManagerServiceClient()\n    name = client.secret_version_path(project_id, secret_id, version_id)\n\n    response = client.access_secret_version(request={\"name\": name})\n\n    checksum = google_crc32c.Checksum()\n    checksum.update(response.payload.data)\n    if response.payload.data_crc32c != int(checksum.hexdigest(), 16):\n        raise ValueError(\"Secret payload checksum verification failed\")\n\n    return response.payload.data.decode(\"utf-8\")\n```\n\nUse `get_secret` or `get_secret_version` when you only need metadata and not the secret payload itself.\n\n### List Secrets\n\nList methods return pagers, so normal iteration handles pagination:\n\n```python\nfrom google.cloud import secretmanager\n\ndef list_secret_names(project_id: str) -> list[str]:\n    client = secretmanager.SecretManagerServiceClient()\n    parent = f\"projects/{project_id}\"\n    return [secret.name for secret in client.list_secrets(request={\"parent\": parent})]\n```\n\n### Disable, Enable, Or Destroy A Secret Version\n\nDisable a version to block access without deleting it:\n\n```python\nfrom google.cloud import secretmanager\n\ndef disable_secret_version(project_id: str, secret_id: str, version_id: str) -> str:\n    client = secretmanager.SecretManagerServiceClient()\n    name = client.secret_version_path(project_id, secret_id, version_id)\n    version = client.disable_secret_version(request={\"name\": name})\n    return version.name\n```\n\nUse `enable_secret_version` to restore access later. Use `destroy_secret_version` only when you intend permanent destruction.\n\n## Regional Secrets And Endpoints\n\nSecret Manager supports regional resources as well as the usual project-scoped global resource names.\n\nRegional secrets use location-qualified resource names:\n\n- Global: `projects/{project}/secrets/{secret}`\n- Regional: `projects/{project}/locations/{location}/secrets/{secret}`\n\nFor regional secrets, point the client at the regional endpoint:\n\n```python\nfrom google.cloud import secretmanager_v1\n\nlocation_id = \"us-east1\"\n\nclient = secretmanager_v1.SecretManagerServiceClient(\n    client_options={\n        \"api_endpoint\": f\"secretmanager.{location_id}.rep.googleapis.com\",\n    }\n)\n```\n\nKeep the resource-name format and the endpoint in sync. Mixing a regional endpoint with global resource names is a common source of `NotFound` and routing errors.\n\n## Common Pitfalls\n\n- A valid credential is not enough if the principal lacks Secret Manager IAM permissions on the project or secret.\n- `latest` points to the newest created version, not the newest enabled version you intended to roll out.\n- The import path is `from google.cloud import secretmanager`, while the generated reference often shows fully qualified modules under `secretmanager_v1`.\n- Secret payloads are bytes. Encode before upload and decode after access.\n- `access_secret_version` returns sensitive material. Prefer metadata-only methods if you do not need the plaintext.\n- Secret rotation is version creation. Do not design code around in-place mutation of an existing version.\n- Regional secrets require both regional resource names and the correct regional endpoint.\n\n## Version-Sensitive Notes For `2.26.0`\n\n- The official PyPI package page and Google Cloud Python reference both showed `2.26.0` on `2026-03-12`.\n- PyPI declares `Requires: Python >=3.7`, so older runtimes are out of scope for this package version.\n- The active repository is the `googleapis/google-cloud-python` monorepo package directory, not the archived single-package repository some older search results still reference.\n- Google Cloud docs currently use the `docs.cloud.google.com` host as the canonical docs surface. Older `cloud.google.com/...` reference URLs commonly redirect there.\n\n## Official Sources\n\n- Google Cloud Secret Manager Python reference: https://docs.cloud.google.com/python/docs/reference/secretmanager/latest\n- `SecretManagerServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/secretmanager/latest/google.cloud.secretmanager_v1.services.secret_manager_service.SecretManagerServiceClient\n- Secret Manager product docs: https://docs.cloud.google.com/secret-manager/docs\n- Secret Manager access a secret version sample: https://docs.cloud.google.com/secret-manager/docs/samples/secretmanager-access-secret-version\n- Secret Manager regional secret sample: https://docs.cloud.google.com/secret-manager/docs/samples/secretmanager-create-regional-secret\n- Authentication for client libraries: https://docs.cloud.google.com/docs/authentication/client-libraries\n- `google-cloud-secret-manager` PyPI page: https://pypi.org/project/google-cloud-secret-manager/\n- Monorepo package directory: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-secret-manager\n- Changelog: https://github.com/googleapis/google-cloud-python/blob/main/packages/google-cloud-secret-manager/CHANGELOG.md\n"
  },
  {
    "path": "content/google/docs/security-center/javascript/DOC.md",
    "content": "---\nname: security-center\ndescription: \"Google Cloud Security Command Center Node.js client for listing findings, managing sources, and handling SCC resource names correctly\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,security-command-center,security-center,findings,@google-cloud/security-center,javascript,nodejs\"\n---\n\n# `@google-cloud/security-center` JavaScript Package Guide\n\n## Golden Rule\n\nUse `@google-cloud/security-center` with Application Default Credentials (ADC), build requests with full Security Command Center resource names, and keep the client namespace aligned with the resource format your code already uses.\n\nFor most established integrations, that means `v1.SecurityCenterClient` with names like `organizations/ORG_ID/sources/SOURCE_ID`. If your existing SCC resources are location-scoped and include `/locations/LOCATION`, keep that path shape and use the matching versioned client surface instead of rewriting names by hand.\n\nThis guide covers `9.2.1`.\n\n## Install\n\n```bash\nnpm install @google-cloud/security-center@9.2.1\n```\n\n## Authentication And Setup\n\nBefore you create the client:\n\n1. Make sure the calling identity can access Security Command Center in the organization, folder, or project scope you plan to query.\n2. Configure ADC for local development or attach a service account in Google Cloud.\n3. Keep the resource scope you query separate from the project you use for credentials and API enablement.\n\nIf you are setting up a new environment, enable the API in the project that owns the client credentials:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable securitycenter.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ORGANIZATION=\"123456789\"\n```\n\nIf you must use a service account key outside Google Cloud:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_ORGANIZATION=\"123456789\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n`GOOGLE_CLOUD_PROJECT` is not a substitute for your SCC organization ID. Most SCC request paths use the organization, folder, or project resource you are inspecting.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1} = require('@google-cloud/security-center');\n\nconst client = new v1.SecurityCenterClient();\n```\n\nES modules:\n\n```javascript\nimport {v1} from '@google-cloud/security-center';\n\nconst client = new v1.SecurityCenterClient();\n```\n\nIf you need to pass credentials explicitly:\n\n```javascript\nconst {v1} = require('@google-cloud/security-center');\n\nconst client = new v1.SecurityCenterClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Resource Names You Reuse Constantly\n\nThe package expects canonical SCC resource names, not bare numeric IDs.\n\n- Organization parent: `organizations/ORG_ID`\n- Aggregate findings parent: `organizations/ORG_ID/sources/-`\n- One source: `organizations/ORG_ID/sources/SOURCE_ID`\n- One finding: `organizations/ORG_ID/sources/SOURCE_ID/findings/FINDING_ID`\n\nSome SCC methods also accept folder-scoped or project-scoped parents, but the same rule applies: pass the full resource name that matches the API method you are calling.\n\n## Core Workflows\n\n### List Findings Across All Sources In An Organization\n\nUse the aggregate source form `sources/-` when you want findings from every source in one organization.\n\n```javascript\nconst {v1} = require('@google-cloud/security-center');\n\nconst client = new v1.SecurityCenterClient();\n\nasync function listFindings(organizationId) {\n  const [results] = await client.listFindings({\n    parent: `organizations/${organizationId}/sources/-`,\n    pageSize: 20,\n  });\n\n  for (const result of results) {\n    const finding = result.finding;\n    if (!finding) continue;\n\n    console.log({\n      name: finding.name,\n      category: finding.category,\n      state: finding.state,\n      eventTime: finding.eventTime,\n    });\n  }\n}\n\nlistFindings(process.env.GOOGLE_CLOUD_ORGANIZATION).catch(console.error);\n```\n\nStart with an unfiltered read like this to confirm that authentication, IAM, and resource naming are correct before adding SCC filter expressions.\n\n### Create A Custom Source\n\nCreate a source when you need a stable SCC source for findings that come from your own scanners or internal controls.\n\n```javascript\nconst {v1} = require('@google-cloud/security-center');\n\nconst client = new v1.SecurityCenterClient();\n\nasync function createSource(organizationId) {\n  const [source] = await client.createSource({\n    parent: `organizations/${organizationId}`,\n    source: {\n      displayName: 'internal-security-controls',\n      description: 'Findings imported from internal security checks.',\n    },\n  });\n\n  console.log(source.name);\n  return source.name;\n}\n\ncreateSource(process.env.GOOGLE_CLOUD_ORGANIZATION).catch(console.error);\n```\n\nPersist the returned `source.name`. Later SCC calls are easier and safer when you reuse the canonical name instead of rebuilding it from IDs.\n\n### List Sources\n\nList sources first when you are inheriting an existing SCC setup and need the exact source names already present in the organization.\n\n```javascript\nconst {v1} = require('@google-cloud/security-center');\n\nconst client = new v1.SecurityCenterClient();\n\nasync function listSources(organizationId) {\n  const [sources] = await client.listSources({\n    parent: `organizations/${organizationId}`,\n  });\n\n  for (const source of sources) {\n    console.log({\n      name: source.name,\n      displayName: source.displayName,\n      description: source.description,\n    });\n  }\n}\n\nlistSources(process.env.GOOGLE_CLOUD_ORGANIZATION).catch(console.error);\n```\n\n## Version And Namespace Notes\n\nThis package uses versioned namespaces. For practical integration work:\n\n- Prefer `v1` when your existing SCC names look like `organizations/.../sources/...`.\n- Keep location-aware names such as `.../locations/LOCATION` on the matching versioned client surface instead of trying to reuse `v1` request objects.\n- Avoid beta namespaces unless the codebase you are maintaining already depends on them.\n\n## Important Pitfalls\n\n- Using a bare organization ID or source ID where the API expects a full `name` or `parent` resource string.\n- Treating `GOOGLE_CLOUD_PROJECT` as the SCC resource scope. Many SCC requests are organization-scoped instead.\n- Debugging request payloads before verifying ADC and IAM. Authentication and permissions usually fail earlier than request shape.\n- Rebuilding source names by hand after creation instead of storing the returned `source.name`.\n- Mixing resource formats across namespaces, especially when location-scoped names appear in an existing codebase.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/security-center/latest`\n- Security Command Center product docs: `https://cloud.google.com/security-command-center/docs`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/security-center`\n- Source repository package directory: `https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-security-center`\n"
  },
  {
    "path": "content/google/docs/securitycenter/python/DOC.md",
    "content": "---\nname: securitycenter\ndescription: \"google-cloud-securitycenter package guide for Python covering ADC setup, v1/v2 clients, findings workflows, and endpoint/version caveats\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.42.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,security-command-center,security-center,findings,google-cloud-securitycenter,python\"\n---\n\n# google-cloud-securitycenter Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-securitycenter` for Security Command Center API access from Python, and authenticate with Application Default Credentials (ADC) unless you have a strong reason to inject explicit credentials.\n\nThis package exposes multiple generated client surfaces under different modules, most commonly `google.cloud.securitycenter_v1` and `google.cloud.securitycenter_v2`. Choose the module that matches the API resource names and request shapes your project is already using.\n\n## Version Notes\n\nThe version used here for this session is `1.42.0`.\n\nGoogle's package reference landing page is current for the package, but some deep class-reference pages still render with `1.41.0` in the page header. Treat the package version in this entry as authoritative for dependency pinning, and use the latest class docs for signatures and request types.\n\nThe package includes several API namespaces (`v1`, `v1beta1`, `v1p1beta1`, `v2`). For new work, prefer `v1` or `v2` unless you are matching an older codebase or a feature that only exists in a beta namespace.\n\n## Install\n\nPin the version when you need behavior aligned with this entry:\n\n```bash\npython -m pip install \"google-cloud-securitycenter==1.42.0\"\n```\n\nIf your environment does not already have Google auth tooling available, install the Cloud SDK separately so local ADC setup is straightforward.\n\n## Authentication And Setup\n\nSecurity Command Center clients use Google auth and gRPC transports by default. The standard setup is:\n\n1. Enable the Security Command Center API for the Google Cloud project or organization you are targeting.\n2. Grant the calling identity the required Security Command Center IAM roles.\n3. Provide ADC locally with `gcloud auth application-default login`, or in deployed environments with an attached service account / workload identity.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimal client creation:\n\n```python\nfrom google.cloud import securitycenter_v1\n\nclient = securitycenter_v1.SecurityCenterClient()\n```\n\nIf you need a non-default endpoint, pass `client_options`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import securitycenter_v1\n\nclient = securitycenter_v1.SecurityCenterClient(\n    client_options=ClientOptions(api_endpoint=\"securitycenter.googleapis.com\")\n)\n```\n\nUse a region-specific endpoint only when your Security Command Center setup requires it. The generated client docs explicitly support overriding `api_endpoint` through `client_options`.\n\n## Choose The API Module\n\nUse this rule of thumb:\n\n- `securitycenter_v1`: safest default for established findings and source-management flows.\n- `securitycenter_v2`: use when your workflow is location-aware and the resource names include `/locations/{location}`.\n- `securitycenter_v1beta1` or `securitycenter_v1p1beta1`: only use when you are maintaining existing beta-based code or need an API surface not yet promoted.\n\nThe biggest practical difference is the resource path shape:\n\n- `v1` commonly uses `organizations/{organization}/sources/{source}`.\n- `v2` commonly uses `organizations/{organization}/sources/{source}/locations/{location}`.\n\nDo not mix request objects and resource names across modules.\n\n## Core Usage\n\n### List Findings With `v1`\n\n`list_findings` is a common read path. In `v1`, the `parent` is typically a source resource such as `organizations/123456789/sources/-`.\n\n```python\nfrom google.cloud import securitycenter_v1\n\nclient = securitycenter_v1.SecurityCenterClient()\n\nrequest = securitycenter_v1.ListFindingsRequest(\n    parent=\"organizations/123456789/sources/-\",\n)\n\nfor finding_result in client.list_findings(request=request):\n    finding = finding_result.finding\n    print(finding.name)\n    print(finding.category)\n```\n\nNotes:\n\n- `sources/-` is the aggregate form when you want findings across all sources in the organization.\n- The iterator is paged for you; iterate directly over the result unless you need manual page control.\n- Add a server-side `filter` only when you know the exact Security Command Center filter syntax you need.\n\n### Get One Finding\n\n```python\nfrom google.cloud import securitycenter_v1\n\nclient = securitycenter_v1.SecurityCenterClient()\n\nfinding = client.get_finding(\n    request=securitycenter_v1.GetFindingRequest(\n        name=(\n            \"organizations/123456789/sources/12345/\"\n            \"findings/finding-id\"\n        )\n    )\n)\n\nprint(finding.name)\nprint(finding.state)\n```\n\nUse `get_finding` when you already have a canonical finding resource name and need the current server state before updating or triaging it.\n\n### List Findings With `v2`\n\nIf your deployment and existing resource names are location-scoped, use `securitycenter_v2` instead:\n\n```python\nfrom google.cloud import securitycenter_v2\n\nclient = securitycenter_v2.SecurityCenterClient()\n\nrequest = securitycenter_v2.ListFindingsRequest(\n    parent=\"organizations/123456789/sources/-/locations/us\",\n)\n\nfor finding_result in client.list_findings(request=request):\n    print(finding_result.finding.name)\n```\n\nDo not silently downgrade a location-scoped resource name to `v1`; keep the client version aligned with the resource path.\n\n### Async Client\n\nUse the async client only when the rest of the application is already async:\n\n```python\nimport asyncio\n\nfrom google.cloud import securitycenter_v1\n\nasync def main() -> None:\n    client = securitycenter_v1.SecurityCenterAsyncClient()\n    request = securitycenter_v1.ListFindingsRequest(\n        parent=\"organizations/123456789/sources/-\",\n    )\n\n    async for finding_result in client.list_findings(request=request):\n        print(finding_result.finding.name)\n\nasyncio.run(main())\n```\n\nThe async surface mirrors the sync API closely. Reuse the same module-selection rules (`v1` vs `v2`) for async code.\n\n## Resource Naming Patterns\n\nExpect to work with full resource names, not short IDs. The most common shapes are:\n\n```text\norganizations/{organization}/sources/{source}\norganizations/{organization}/sources/{source}/findings/{finding}\norganizations/{organization}/sources/{source}/locations/{location}\norganizations/{organization}/sources/{source}/locations/{location}/findings/{finding}\n```\n\nIf you only have numeric IDs, build the full resource name before calling the client. Most generated request types expect canonical names, not separate `organization_id` and `finding_id` fields.\n\n## Configuration Notes\n\n- Reuse client instances when possible. The generated clients manage transports and channels internally, so recreating them per call is unnecessary overhead.\n- Prefer explicit request objects such as `ListFindingsRequest(...)` over positional parameters. That makes version/module mismatches easier to catch.\n- The default transport is gRPC. Stay on the default unless your environment has a concrete reason to force REST transport.\n- Timeout and retry behavior comes from `google-api-core`; override only for known latency or idempotency needs.\n\n## Common Pitfalls\n\n- Importing the wrong module. `securitycenter_v1` and `securitycenter_v2` are both valid, but their request types and resource paths are not interchangeable.\n- Using the wrong parent format. `v1` examples typically omit `/locations/...`; `v2` examples include it.\n- Forgetting ADC. A plain `SecurityCenterClient()` call will fail if the environment is not authenticated.\n- Passing partial IDs instead of full resource names. Most methods want canonical `name` or `parent` strings.\n- Assuming every blog post matches the current generated client. For this package, older examples often use beta modules or stale page versions.\n- Ignoring IAM. Authentication alone is not enough; the caller also needs the right Security Command Center permissions on the organization, folder, or project scope involved.\n\n## Practical Workflow For Agents\n\nWhen writing or editing code against this package:\n\n1. Confirm whether the codebase is using `securitycenter_v1` or `securitycenter_v2`.\n2. Confirm whether existing resource names contain `/locations/{location}`.\n3. Set up ADC first and verify access before debugging request shapes.\n4. Start with `list_findings` or `get_finding` to prove connectivity and permissions.\n5. Only then add write or triage operations, using request classes from the same module as the read path.\n\n## Official Sources\n\n- Package reference landing page: `https://cloud.google.com/python/docs/reference/securitycenter/latest`\n- API class docs (`v1`): `https://cloud.google.com/python/docs/reference/securitycenter/latest/google.cloud.securitycenter_v1.services.security_center.SecurityCenterClient`\n- API class docs (`v2`): `https://cloud.google.com/python/docs/reference/securitycenter/latest/google.cloud.securitycenter_v2.services.security_center.SecurityCenterClient`\n- Async client docs: `https://cloud.google.com/python/docs/reference/securitycenter/latest/google.cloud.securitycenter_v1.services.security_center.SecurityCenterAsyncClient`\n- Google Cloud auth / ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Source repository package directory: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycenter`\n- PyPI package page: `https://pypi.org/project/google-cloud-securitycenter/`\n"
  },
  {
    "path": "content/google/docs/service-control/python/DOC.md",
    "content": "---\nname: service-control\ndescription: \"Google Cloud Service Control Python client guide for admission checks, telemetry reporting, and quota allocation\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.18.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,service-control,service-infrastructure,quota,telemetry\"\n---\n\n# google-cloud-service-control Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-service-control` when you are integrating a managed service with Google Service Infrastructure as a service producer. The main import is:\n\n```python\nfrom google.cloud import servicecontrol_v1\n```\n\nFor most code, the package surfaces that matter are:\n\n- `servicecontrol_v1.ServiceControllerClient` for `check(...)` and `report(...)`\n- `servicecontrol_v1.QuotaControllerClient` for `allocate_quota(...)`\n\nThis package is not a general Google Cloud application SDK. It is for service producers that already have a managed service and service config in Service Management.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-service-control==1.18.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-service-control==1.18.0\"\npoetry add \"google-cloud-service-control==1.18.0\"\n```\n\n## Authentication And Prerequisites\n\nThis library uses Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-producer-project-id\"\nexport SERVICE_NAME=\"example-api.endpoints.your-producer-project-id.cloud.goog\"\nexport CONSUMER_ID=\"project:consumer-project-id\"\n```\n\nService account credentials:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/abs/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-producer-project-id\"\nexport SERVICE_NAME=\"example-api.endpoints.your-producer-project-id.cloud.goog\"\nexport CONSUMER_ID=\"project:consumer-project-id\"\n```\n\nBefore these calls work, confirm:\n\n- the producer project already owns a managed service in Service Management\n- the caller has permission to call Service Control, typically `roles/servicemanagement.serviceController`\n- the service config already defines the monitored resources, metrics, logs, or quota rules you reference in requests\n\n`consumer_id` is required on operations. Common forms are:\n\n- `project:consumer-project-id`\n- `project_number:123456789012`\n- another producer-supported consumer identifier from your service config\n\n## Initialize Clients\n\n```python\nimport google.auth\nfrom google.cloud import servicecontrol_v1\n\nSCOPES = [\"https://www.googleapis.com/auth/cloud-platform\"]\n\ncredentials, project_id = google.auth.default(scopes=SCOPES)\n\nservice_client = servicecontrol_v1.ServiceControllerClient(credentials=credentials)\nquota_client = servicecontrol_v1.QuotaControllerClient(credentials=credentials)\n\nprint(project_id)\n```\n\nIf your code already uses `asyncio`, the package also exposes `ServiceControllerAsyncClient` and `QuotaControllerAsyncClient`.\n\n## Resource Naming\n\nThe methods here expect your managed service name, not just a project ID:\n\n```python\nimport os\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nconsumer_id = os.environ[\"CONSUMER_ID\"]\n```\n\nTypical values:\n\n- `SERVICE_NAME=\"example-api.endpoints.my-project.cloud.goog\"`\n- `CONSUMER_ID=\"project:consumer-project-id\"`\n\nWhen you are working with the active config, using `service_config_id=\"latest\"` is the practical default.\n\n## Check Before Serving A Request\n\nCall `check(...)` before executing protected work. Service Control evaluates the operation against your managed service config and returns any admission errors in `check_errors`.\n\n```python\nimport os\nimport uuid\nfrom datetime import datetime, timezone\n\nfrom google.cloud import servicecontrol_v1\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nconsumer_id = os.environ[\"CONSUMER_ID\"]\n\nnow = Timestamp()\nnow.FromDatetime(datetime.now(timezone.utc))\n\noperation_id = str(uuid.uuid4())\n\nclient = servicecontrol_v1.ServiceControllerClient()\nresponse = client.check(\n    request=servicecontrol_v1.CheckRequest(\n        service_name=service_name,\n        service_config_id=\"latest\",\n        operation=servicecontrol_v1.Operation(\n            operation_id=operation_id,\n            operation_name=\"google.example.library.v1.LibraryService.ListShelves\",\n            consumer_id=consumer_id,\n            start_time=now,\n            labels={\n                \"cloud.googleapis.com/location\": \"us-central1\",\n            },\n        ),\n    )\n)\n\nif response.check_errors:\n    for error in response.check_errors:\n        print(error.code.name, error.subject, error.detail)\n    raise PermissionError(\"Service Control check failed\")\n```\n\nPractical guidance:\n\n- reuse the same `operation_id` later in `report(...)` for the same request\n- use request objects when you need nested protobuf messages; it is easier to keep the field names correct\n- `check(...)` results are intended to be cached. The product docs recommend a cache entry TTL of 60 seconds and note that policy changes can take about a minute to propagate\n\n## Report After The Operation Finishes\n\nCall `report(...)` after the work completes so Service Infrastructure can ingest logs and metrics for the operation. `end_time` is required on the reported operation.\n\n```python\nimport os\nimport uuid\nfrom datetime import datetime, timezone\n\nfrom google.cloud import servicecontrol_v1\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nconsumer_id = os.environ[\"CONSUMER_ID\"]\n\nstart_time = Timestamp()\nstart_time.FromDatetime(datetime.now(timezone.utc))\n\nend_time = Timestamp()\nend_time.FromDatetime(datetime.now(timezone.utc))\n\noperation_id = str(uuid.uuid4())  # Generate once in your request path and reuse it in check() and report().\n\nclient = servicecontrol_v1.ServiceControllerClient()\nresponse = client.report(\n    request=servicecontrol_v1.ReportRequest(\n        service_name=service_name,\n        service_config_id=\"latest\",\n        operations=[\n            servicecontrol_v1.Operation(\n                operation_id=operation_id,\n                operation_name=\"google.example.library.v1.LibraryService.ListShelves\",\n                consumer_id=consumer_id,\n                start_time=start_time,\n                end_time=end_time,\n                labels={\n                    \"cloud.googleapis.com/location\": \"us-central1\",\n                },\n            )\n        ],\n    )\n)\n\nif response.report_errors:\n    for error in response.report_errors:\n        print(error.operation_id, error.status.message)\n```\n\nImportant limits from the Service Control docs:\n\n- batch report calls for up to 5 seconds before sending to reduce RPC overhead\n- keep each report request at or below 1 MB\n- inspect `report_errors`; the RPC can succeed while individual operations still fail validation\n\n## Allocate Quota Before Execution\n\nUse `allocate_quota(...)` when your service config defines quota rules and the request should reserve or verify capacity before executing.\n\n```python\nimport os\nimport uuid\n\nfrom google.cloud import servicecontrol_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nconsumer_id = os.environ[\"CONSUMER_ID\"]\n\nclient = servicecontrol_v1.QuotaControllerClient()\nresponse = client.allocate_quota(\n    request=servicecontrol_v1.AllocateQuotaRequest(\n        service_name=service_name,\n        service_config_id=\"latest\",\n        allocate_operation=servicecontrol_v1.QuotaOperation(\n            operation_id=str(uuid.uuid4()),\n            consumer_id=consumer_id,\n            method_name=\"google.example.library.v1.LibraryService.ListShelves\",\n            quota_mode=servicecontrol_v1.QuotaOperation.QuotaMode.NORMAL,\n        ),\n    )\n)\n\nif response.allocate_errors:\n    for error in response.allocate_errors:\n        print(error.code.name, error.subject, error.detail)\n    raise RuntimeError(\"Quota allocation failed\")\n```\n\nUse `QuotaMode.CHECK_ONLY` when you want to verify quota without consuming it.\n\n## Configuration Notes\n\n- The default endpoint for this package is `servicecontrol.googleapis.com`.\n- The generated clients support per-call `retry`, `timeout`, and `metadata` arguments through Google API Core. Use them explicitly in CI jobs or request paths with hard deadlines.\n- The package supports the standard Google client logging hook through `GOOGLE_SDK_PYTHON_LOGGING_SCOPE`.\n\nExample:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.servicecontrol_v1\n```\n\n## Common Pitfalls\n\n- Package name and import path differ: install `google-cloud-service-control`, import `servicecontrol_v1`.\n- `check(...)` is for admission control before work runs; `report(...)` is for telemetry after work completes. Do not swap them.\n- `report(...)` requires `end_time` on each operation.\n- `check(...)`, `report(...)`, and `allocate_quota(...)` all operate on your managed service name. A bare project ID is not enough.\n- Quota allocation only makes sense if the referenced method or quota metrics exist in the deployed service config.\n- Service Control has its own producer-project quota. The product quota page documents 6,000,000 quota units per minute by default, and each `check`, `report`, or `allocateQuota` call consumes one unit.\n- Do not hard-code long-lived service account key files into app code. Prefer ADC on Google Cloud runtimes or a managed secret path outside the repo.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `google-cloud-service-control 1.18.0`; pin that if you want reproducible generated-client behavior.\n- The Python reference pages under `latest` are the right source for request and response field shapes, but Google Cloud reference pages can lag or mix generated version labels. Use PyPI for the installed package version you lock and the reference docs for API shape.\n- This package is a generated client library. Minor releases commonly update generated protobuf and transport surfaces without changing the core workflow shown above.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/google-cloud-service-control/`\n- Package docs root: `https://docs.cloud.google.com/python/docs/reference/servicecontrol/latest`\n- `ServiceControllerClient` reference: `https://docs.cloud.google.com/python/docs/reference/servicecontrol/latest/google.cloud.servicecontrol_v1.services.service_controller.ServiceControllerClient`\n- `QuotaControllerClient` reference: `https://docs.cloud.google.com/python/docs/reference/servicecontrol/latest/google.cloud.servicecontrol_v1.services.quota_controller.QuotaControllerClient`\n- Access control: `https://cloud.google.com/service-infrastructure/docs/access-control`\n- Checking request status: `https://cloud.google.com/service-infrastructure/docs/checking-api-status`\n- Reporting metrics: `https://cloud.google.com/service-infrastructure/docs/reporting-metrics`\n- Service Control quotas: `https://cloud.google.com/service-infrastructure/docs/service-control/reference/limits`\n- REST reference for `services.check`: `https://cloud.google.com/service-infrastructure/docs/service-control/reference/rest/v1/services/check`\n- REST reference for `services.report`: `https://cloud.google.com/service-infrastructure/docs/service-control/reference/rest/v1/services/report`\n- REST reference for `services.allocateQuota`: `https://cloud.google.com/service-infrastructure/docs/service-control/reference/rest/v1/services/allocateQuota`\n- Repository package root: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-control`\n"
  },
  {
    "path": "content/google/docs/service-directory/python/DOC.md",
    "content": "---\nname: service-directory\ndescription: \"Google Cloud Service Directory Python client for registering namespaces, services, and endpoints and resolving them at runtime\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.16.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,service-directory,service-discovery,dns,python\"\n---\n\n# Google Cloud Service Directory Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-service-directory` with `from google.cloud import servicedirectory_v1`, authenticate with Application Default Credentials (ADC), and keep registration calls separate from runtime lookups:\n\n- `RegistrationServiceClient` for namespaces, services, endpoints, updates, and deletes\n- `LookupServiceClient` for `resolve_service()` during service discovery\n\nThe main resource hierarchy is:\n\n- `projects/{project}/locations/{location}/namespaces/{namespace}`\n- `projects/{project}/locations/{location}/namespaces/{namespace}/services/{service}`\n- `projects/{project}/locations/{location}/namespaces/{namespace}/services/{service}/endpoints/{endpoint}`\n\n## Version-Sensitive Notes\n\nPin `google-cloud-service-directory==1.16.0` when you want the package version covered here. PyPI lists `1.16.0` as the current release and requires Python 3.7 or newer.\n\nThe generated Cloud Python reference currently lags the PyPI release metadata: the package changelog page currently tops out at `1.15.0`. Use PyPI for installable package version tracking and the Cloud Python reference for method names, request types, and field behavior.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-service-directory==1.16.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-service-directory==1.16.0\"\npoetry add \"google-cloud-service-directory==1.16.0\"\n```\n\n## Authentication And Setup\n\nThis library uses Google Cloud ADC by default.\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud services enable servicedirectory.googleapis.com\n\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-east1\"\nexport SERVICE_DIRECTORY_NAMESPACE=\"backend\"\nexport SERVICE_DIRECTORY_SERVICE=\"payments\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-east1\"\n```\n\nImportant setup points:\n\n- A namespace belongs to one region and cannot span multiple regions.\n- Services remain globally resolvable, but Google recommends choosing a region close to your services and clients.\n- The calling identity needs Service Directory permissions on the target project. If you set `Endpoint.network`, it also needs `servicedirectory.networks.attach` on that VPC network.\n\n## Initialize Clients\n\n```python\nimport os\n\nfrom google.cloud import servicedirectory_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nnamespace_id = os.environ[\"SERVICE_DIRECTORY_NAMESPACE\"]\nservice_id = os.environ[\"SERVICE_DIRECTORY_SERVICE\"]\n\nregistration = servicedirectory_v1.RegistrationServiceClient()\nlookup = servicedirectory_v1.LookupServiceClient()\n\nlocation_name = f\"projects/{project_id}/locations/{location}\"\nnamespace_name = registration.namespace_path(project_id, location, namespace_id)\nservice_name = registration.service_path(\n    project_id,\n    location,\n    namespace_id,\n    service_id,\n)\n```\n\nExplicit credentials:\n\n```python\nfrom google.cloud import servicedirectory_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nregistration = servicedirectory_v1.RegistrationServiceClient(\n    credentials=credentials\n)\n```\n\n## Core Workflow\n\n### Create a namespace\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nclient = servicedirectory_v1.RegistrationServiceClient()\n\nnamespace = servicedirectory_v1.Namespace(\n    name=client.namespace_path(\"your-project-id\", \"us-east1\", \"backend\"),\n    labels={\"env\": \"dev\"},\n)\n\ncreated = client.create_namespace(\n    parent=\"projects/your-project-id/locations/us-east1\",\n    namespace=namespace,\n    namespace_id=\"backend\",\n)\n\nprint(created.name)\n```\n\n### Create a service\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nclient = servicedirectory_v1.RegistrationServiceClient()\nnamespace_name = client.namespace_path(\"your-project-id\", \"us-east1\", \"backend\")\n\nservice = servicedirectory_v1.Service(\n    name=client.service_path(\"your-project-id\", \"us-east1\", \"backend\", \"payments\"),\n    annotations={\"protocol\": \"grpc\", \"owner\": \"checkout\"},\n)\n\ncreated = client.create_service(\n    parent=namespace_name,\n    service=service,\n    service_id=\"payments\",\n)\n\nprint(created.name)\n```\n\n### Create an endpoint\n\nRegister concrete backends under the service. `address` is an IP address and `port` is an integer.\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nclient = servicedirectory_v1.RegistrationServiceClient()\nservice_name = client.service_path(\"your-project-id\", \"us-east1\", \"backend\", \"payments\")\n\nendpoint = servicedirectory_v1.Endpoint(\n    name=client.endpoint_path(\n        \"your-project-id\",\n        \"us-east1\",\n        \"backend\",\n        \"payments\",\n        \"payments-1\",\n    ),\n    address=\"10.10.0.15\",\n    port=8443,\n    annotations={\"version\": \"v1\", \"zone\": \"us-east1-b\"},\n)\n\ncreated = client.create_endpoint(\n    parent=service_name,\n    endpoint=endpoint,\n    endpoint_id=\"payments-1\",\n)\n\nprint(created.name, created.address, created.port)\n```\n\nIf you want to attach the endpoint to a VPC network, set `network` to the full network resource using the project number, not the project ID:\n\n```python\nendpoint = servicedirectory_v1.Endpoint(\n    address=\"10.10.0.15\",\n    port=8443,\n    network=\"projects/123456789012/locations/global/networks/default\",\n)\n```\n\n### Resolve a service at runtime\n\nUse `LookupServiceClient.resolve_service()` for discovery. That is the lookup API intended to return the service and its endpoints.\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nlookup = servicedirectory_v1.LookupServiceClient()\n\nresponse = lookup.resolve_service(\n    request=servicedirectory_v1.ResolveServiceRequest(\n        name=\"projects/your-project-id/locations/us-east1/namespaces/backend/services/payments\"\n    )\n)\n\nprint(response.service.name)\n\nfor endpoint in response.service.endpoints:\n    print(endpoint.name, endpoint.address, endpoint.port, dict(endpoint.annotations))\n```\n\n### List endpoints with a filter\n\n`list_endpoints()` accepts a filter expression. The reference docs include examples such as `annotations.owner=sre` and `port>8080`.\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nclient = servicedirectory_v1.RegistrationServiceClient()\n\npager = client.list_endpoints(\n    request=servicedirectory_v1.ListEndpointsRequest(\n        parent=\"projects/your-project-id/locations/us-east1/namespaces/backend/services/payments\",\n        filter=\"annotations.version=v1 OR port=8443\",\n    )\n)\n\nfor endpoint in pager:\n    print(endpoint.name, endpoint.address, endpoint.port)\n```\n\n### Update labels or annotations\n\nUse a field mask so the API only changes the fields you intend to modify.\n\n```python\nfrom google.cloud import servicedirectory_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = servicedirectory_v1.RegistrationServiceClient()\n\nupdated_service = client.update_service(\n    service=servicedirectory_v1.Service(\n        name=\"projects/your-project-id/locations/us-east1/namespaces/backend/services/payments\",\n        annotations={\n            \"protocol\": \"grpc\",\n            \"owner\": \"checkout\",\n            \"stage\": \"prod\",\n        },\n    ),\n    update_mask=FieldMask(paths=[\"annotations\"]),\n)\n\nprint(updated_service.annotations)\n```\n\nUpdating namespace labels uses the same pattern:\n\n```python\nupdated_namespace = client.update_namespace(\n    namespace=servicedirectory_v1.Namespace(\n        name=\"projects/your-project-id/locations/us-east1/namespaces/backend\",\n        labels={\"env\": \"prod\"},\n    ),\n    update_mask=FieldMask(paths=[\"labels\"]),\n)\n```\n\n### Delete a namespace\n\nDeleting a namespace also deletes every service and endpoint inside it.\n\n```python\nfrom google.cloud import servicedirectory_v1\n\nclient = servicedirectory_v1.RegistrationServiceClient()\n\nclient.delete_namespace(\n    name=\"projects/your-project-id/locations/us-east1/namespaces/backend\"\n)\n```\n\nIf you only want to remove one service or one endpoint, use `delete_service()` or `delete_endpoint()` instead.\n\n## Common Pitfalls\n\n- Use `resolve_service()` for discovery. `get_service()` and `get_endpoint()` are administrative reads, not the main service-resolution path.\n- Namespace IDs and service IDs follow DNS label style rules. Keep them lowercase and avoid trying to use arbitrary display names as IDs.\n- `Endpoint.address` is only the IP address. Do not pass `host:port`, a URL, or bracketed IPv6 plus port.\n- `Endpoint.network` is immutable after creation and must use the full VPC resource path with the project number.\n- Service annotations are capped at 2000 total characters. Endpoint annotations are capped at 512 total characters. Namespace labels follow Google Cloud label limits.\n- Deleting a namespace is recursive. If you attached a DNS zone to that namespace, deleting it causes those lookups to start returning `NXDOMAIN`.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-service-directory/\n- Python client reference root: https://cloud.google.com/python/docs/reference/servicedirectory/latest\n- `RegistrationServiceClient` reference: https://cloud.google.com/python/docs/reference/servicedirectory/latest/google.cloud.servicedirectory_v1.services.registration_service.RegistrationServiceClient\n- `LookupServiceClient` reference: https://cloud.google.com/python/docs/reference/servicedirectory/latest/google.cloud.servicedirectory_v1.services.lookup_service.LookupServiceClient\n- Service Directory configuration guide: https://cloud.google.com/service-directory/docs/configuring-service-directory\n- Service Directory authentication guide: https://cloud.google.com/service-directory/docs/authentication\n- ADC guide: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- Package changelog page: https://docs.cloud.google.com/python/docs/reference/servicedirectory/latest/changelog\n"
  },
  {
    "path": "content/google/docs/service-management/python/DOC.md",
    "content": "---\nname: service-management\ndescription: \"Google Cloud Service Management Python client guide for managing services, configs, and rollouts\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,gcp,service-management,api-management,endpoints,long-running-operations\"\n---\n\n# google-cloud-service-management Python Package Guide\n\n## What This Package Is For\n\n`google-cloud-service-management` is the official Python client for Google Cloud Service Management. Use it when Python code needs to:\n\n- create, fetch, list, or delete managed services\n- submit new service configs\n- inspect config revisions and rollouts\n- validate config source before rollout\n\nThe main import surface is:\n\n```python\nfrom google.cloud import servicemanagement_v1\n```\n\nFor asyncio code, the package also exposes `ServiceManagerAsyncClient`.\n\n## Version-Sensitive Notes\n\n- The initial package metadata version `1.15.0` matches the official PyPI release for this package as verified on March 12, 2026.\n- Prefer the Google Cloud Python reference for API shape and request types, and PyPI for installable package version and Python compatibility.\n- The docs URL points at the monorepo package directory on GitHub. That repo path is useful for repository context, but the generated Cloud Python reference is the better coding-time source for client methods, request objects, and changelog entries.\n\n## Install\n\nPin the package when you need reproducible generated-client behavior:\n\n```bash\npip install \"google-cloud-service-management==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-service-management==1.15.0\"\npoetry add \"google-cloud-service-management==1.15.0\"\n```\n\n## Authentication And Setup\n\nThis library uses Google Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-producer-project-id\"\nexport SERVICE_NAME=\"example-api.endpoints.your-producer-project-id.cloud.goog\"\n```\n\nService account credentials:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/abs/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-producer-project-id\"\nexport SERVICE_NAME=\"example-api.endpoints.your-producer-project-id.cloud.goog\"\n```\n\nImportant setup points:\n\n- `SERVICE_NAME` is the managed service name, not just the project ID.\n- The calling identity needs Service Management permissions in the producer project.\n- If you run on Cloud Run, GKE, GCE, or another Google Cloud runtime, prefer the attached workload or service account over key files.\n\n## Initialize A Client\n\n```python\nfrom google.cloud import servicemanagement_v1\n\nclient = servicemanagement_v1.ServiceManagerClient()\n```\n\nIf you need explicit credentials or project discovery:\n\n```python\nimport google.auth\nfrom google.cloud import servicemanagement_v1\n\ncredentials, project_id = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\n\nclient = servicemanagement_v1.ServiceManagerClient(credentials=credentials)\nprint(project_id)\n```\n\nIf you must override the endpoint, use `client_options`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import servicemanagement_v1\n\nclient = servicemanagement_v1.ServiceManagerClient(\n    client_options=ClientOptions(\n        api_endpoint=\"servicemanagement.googleapis.com\"\n    )\n)\n```\n\n## Resource Naming\n\nMost operations use the managed service name directly:\n\n```python\nimport os\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nservice_name = os.environ[\"SERVICE_NAME\"]\n```\n\nTypical values look like:\n\n- `example-api.endpoints.my-project.cloud.goog`\n- another verified managed service name owned by the producer project\n\nConfig IDs and rollout IDs are returned by the API and are used in later calls such as `get_service_config(...)` and `get_service_rollout(...)`.\n\n## List Managed Services\n\n`list_services()` returns a pager. Iterate over it directly.\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\n\nfor service in client.list_services(producer_project_id=project_id):\n    print(service.service_name, service.producer_project_id)\n```\n\n## Get One Managed Service\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\nservice = client.get_service(service_name=service_name)\n\nprint(service.service_name)\nprint(service.producer_project_id)\n```\n\n## Create A Managed Service\n\nCreating or deleting a service returns a long-running operation. Wait for `.result()` before assuming the change is visible.\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nservice_name = os.environ[\"SERVICE_NAME\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\noperation = client.create_service(\n    request=servicemanagement_v1.CreateServiceRequest(\n        service=servicemanagement_v1.ManagedService(\n            service_name=service_name,\n            producer_project_id=project_id,\n        )\n    )\n)\n\ncreated = operation.result(timeout=300)\nprint(created.service_name)\n```\n\n## Validate And Submit Config Source\n\nWhen you are pushing a new service configuration, the most practical flow is:\n\n1. build a `ConfigSource` from your YAML or OpenAPI files\n2. call `generate_config_report(...)` if you want diagnostics before rollout\n3. call `submit_config_source(...)` to create a new config revision\n\nExample submission:\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nyaml_bytes = Path(\"openapi/service.yaml\").read_bytes()\n\nclient = servicemanagement_v1.ServiceManagerClient()\noperation = client.submit_config_source(\n    request=servicemanagement_v1.SubmitConfigSourceRequest(\n        service_name=service_name,\n        config_source=servicemanagement_v1.ConfigSource(\n            files=[\n                {\n                    \"file_path\": \"openapi/service.yaml\",\n                    \"file_contents\": yaml_bytes,\n                }\n            ]\n        ),\n    )\n)\n\nconfig = operation.result(timeout=300)\nprint(config.id)\n```\n\nImportant details:\n\n- `file_contents` must be bytes. Use `Path(...).read_bytes()`, not a Python string.\n- `submit_config_source(...)` is also a long-running operation.\n- Prefer request objects when there are multiple nested fields or when you need version-stable clarity.\n\n## Inspect Config Revisions\n\nUse `list_service_configs(...)` when you need the config IDs created by previous submissions:\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\n\nfor config in client.list_service_configs(service_name=service_name):\n    print(config.id, config.title)\n```\n\nFetch one specific config when you already have the config ID:\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nconfig_id = \"2026-03-12r0\"\n\nclient = servicemanagement_v1.ServiceManagerClient()\nconfig = client.get_service_config(\n    service_name=service_name,\n    config_id=config_id,\n)\n\nprint(config.id)\nprint(config.name)\n```\n\n## Inspect Rollouts\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\n\nfor rollout in client.list_service_rollouts(service_name=service_name):\n    print(rollout.rollout_id, rollout.status)\n```\n\nUse `get_service_rollout(...)` when you need one rollout by ID:\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\nrollout_id = \"current\"\n\nclient = servicemanagement_v1.ServiceManagerClient()\nrollout = client.get_service_rollout(\n    service_name=service_name,\n    rollout_id=rollout_id,\n)\n\nprint(rollout.rollout_id)\nprint(rollout.status)\n```\n\n## Delete A Managed Service\n\n```python\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nservice_name = os.environ[\"SERVICE_NAME\"]\n\nclient = servicemanagement_v1.ServiceManagerClient()\noperation = client.delete_service(service_name=service_name)\noperation.result(timeout=300)\n```\n\n## Async Client\n\nFor asyncio code, use `ServiceManagerAsyncClient`:\n\n```python\nimport asyncio\nimport os\n\nfrom google.cloud import servicemanagement_v1\n\nasync def main() -> None:\n    service_name = os.environ[\"SERVICE_NAME\"]\n    client = servicemanagement_v1.ServiceManagerAsyncClient()\n    service = await client.get_service(service_name=service_name)\n    print(service.service_name)\n\nasyncio.run(main())\n```\n\n## Common Pitfalls\n\n- Confusing the package name with the import path. Use `from google.cloud import servicemanagement_v1`.\n- Passing a project ID where the API expects a managed service name.\n- Forgetting that mutating calls return long-running operations.\n- Passing text instead of bytes for config file contents.\n- Treating this package like a runtime gateway SDK. It manages service definitions, configs, and rollouts; it does not proxy or serve application traffic.\n\n## Official Sources\n\n- Google Cloud Python reference: https://cloud.google.com/python/docs/reference/servicemanagement/latest\n- `ServiceManagerClient` reference: https://cloud.google.com/python/docs/reference/servicemanagement/latest/google.cloud.servicemanagement_v1.services.service_manager.ServiceManagerClient\n- Changelog: https://cloud.google.com/python/docs/reference/servicemanagement/latest/changelog\n- ADC setup: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- PyPI package page: https://pypi.org/project/google-cloud-service-management/\n- Docs URL provided for this package: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-management\n"
  },
  {
    "path": "content/google/docs/service-usage/python/DOC.md",
    "content": "---\nname: service-usage\ndescription: \"Google Cloud Service Usage Python client library for listing, enabling, and disabling Google APIs and services\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,service-usage,api-enablement,iam,operations\"\n---\n\n# Google Cloud Service Usage Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-service-usage` with `from google.cloud import service_usage_v1`, authenticate with Application Default Credentials (ADC), and pass full resource names like `projects/PROJECT_NUMBER/services/SERVICE_NAME`. The mutating methods return long-running operations, so do not treat `enable_service`, `batch_enable_services`, or `disable_service` as immediate.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-service-usage==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-service-usage==1.15.0\"\npoetry add \"google-cloud-service-usage==1.15.0\"\n```\n\n## Authentication And Setup\n\nThis client library uses ADC. Prefer these credential sources:\n\n1. Local development: `gcloud auth application-default login`\n2. Google Cloud runtime with an attached service account or workload identity\n3. `GOOGLE_APPLICATION_CREDENTIALS` only when you cannot use the first two\n\nTypical local setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nThe caller usually needs a role such as `roles/serviceusage.serviceUsageAdmin` on the target project to enable or disable APIs.\n\nBasic client initialization:\n\n```python\nfrom google.cloud import service_usage_v1\n\nclient = service_usage_v1.ServiceUsageClient()\n```\n\nAsync initialization:\n\n```python\nfrom google.cloud import service_usage_v1\n\nclient = service_usage_v1.ServiceUsageAsyncClient()\n```\n\n## Core Usage\n\n### Resource names\n\nThe library expects Service Usage resource names, not just service IDs:\n\n- Project parent: `projects/PROJECT_NUMBER`\n- Service name: `projects/PROJECT_NUMBER/services/SERVICE_NAME`\n\nExample service IDs:\n\n- `bigquery.googleapis.com`\n- `run.googleapis.com`\n- `serviceusage.googleapis.com`\n\n### Check one service\n\nUse `get_service` when you know the exact service:\n\n```python\nfrom google.cloud import service_usage_v1\n\nproject_number = \"123456789012\"\nservice_id = \"bigquery.googleapis.com\"\n\nclient = service_usage_v1.ServiceUsageClient()\nservice = client.get_service(\n    request=service_usage_v1.GetServiceRequest(\n        name=f\"projects/{project_number}/services/{service_id}\",\n    )\n)\n\nprint(service.name)\nprint(service.state.name)\n```\n\n### List enabled services\n\nUse `filter=\"state:ENABLED\"` to avoid iterating over every known service:\n\n```python\nfrom google.cloud import service_usage_v1\n\nproject_number = \"123456789012\"\nclient = service_usage_v1.ServiceUsageClient()\n\npager = client.list_services(\n    request=service_usage_v1.ListServicesRequest(\n        parent=f\"projects/{project_number}\",\n        filter=\"state:ENABLED\",\n    )\n)\n\nfor service in pager:\n    print(service.config.name, service.state.name)\n```\n\n### Enable one service\n\n`enable_service` returns a long-running operation. Wait for completion before assuming the API is usable:\n\n```python\nfrom google.cloud import service_usage_v1\n\nproject_number = \"123456789012\"\nservice_id = \"bigquery.googleapis.com\"\n\nclient = service_usage_v1.ServiceUsageClient()\noperation = client.enable_service(\n    request=service_usage_v1.EnableServiceRequest(\n        name=f\"projects/{project_number}/services/{service_id}\",\n    )\n)\n\nresponse = operation.result(timeout=300)\nprint(response.name, response.state.name)\n```\n\n### Enable several services in one call\n\n`batch_enable_services` is the fastest path when bootstrapping a project, but the API only allows up to 20 services per request:\n\n```python\nfrom google.cloud import service_usage_v1\n\nproject_number = \"123456789012\"\nservice_ids = [\n    \"serviceusage.googleapis.com\",\n    \"iam.googleapis.com\",\n    \"run.googleapis.com\",\n]\n\nclient = service_usage_v1.ServiceUsageClient()\noperation = client.batch_enable_services(\n    request=service_usage_v1.BatchEnableServicesRequest(\n        parent=f\"projects/{project_number}\",\n        service_ids=service_ids,\n    )\n)\n\noperation.result(timeout=600)\n```\n\n### Disable a service\n\nDisabling can fail when other enabled services depend on the target service. Only set `disable_dependent_services=True` when you intend that cascade:\n\n```python\nfrom google.cloud import service_usage_v1\n\nproject_number = \"123456789012\"\nservice_id = \"run.googleapis.com\"\n\nclient = service_usage_v1.ServiceUsageClient()\noperation = client.disable_service(\n    request=service_usage_v1.DisableServiceRequest(\n        name=f\"projects/{project_number}/services/{service_id}\",\n        disable_dependent_services=False,\n    )\n)\n\nresponse = operation.result(timeout=300)\nprint(response.name, response.state.name)\n```\n\n## Configuration Notes\n\n- If your automation only needs to inspect current state, prefer `get_service`, `batch_get_services`, or `list_services` over mutation calls.\n- The library also exposes `ServiceUsageAsyncClient` if your app already uses `asyncio`, but the API surface is the same as the sync client.\n- The generated clients support the normal Google API Core retry and timeout parameters on each method. Use them explicitly in automation that runs under CI time limits.\n- The package supports optional debug logging through the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable. Example:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google.cloud.service_usage_v1\n```\n\n## Common Pitfalls\n\n- Package name and import path differ: install `google-cloud-service-usage`, import `service_usage_v1`.\n- Use the project number in resource names when possible. The official examples use `projects/123456789012`, not a bare project ID.\n- `enable_service`, `batch_enable_services`, and `disable_service` are long-running operations. Call `.result()` and handle timeouts.\n- `batch_enable_services` accepts at most 20 services per request.\n- Service enable/disable requests are quota-limited. The product docs call out a default mutate quota of 2 QPS, so bulk project bootstrap code should throttle and retry.\n- `disable_service` can fail unless you set `disable_dependent_services=True` for dependent APIs.\n- Enabling or disabling APIs fails with permission errors unless the caller has the required Service Usage IAM role on the target project.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `1.15.0`, but some Google Cloud Python reference pages indexed under `latest` still render slightly older generated versions. Use PyPI for the package version you pin, and use the reference pages for current request and response shapes.\n- This package is the generated Python client for the Service Usage API. Minor releases often refresh generated surfaces and dependencies without changing the basic client workflow shown above.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/google-cloud-service-usage/`\n- Package docs root: `https://cloud.google.com/python/docs/reference/service-usage/latest`\n- ServiceUsageClient reference: `https://cloud.google.com/python/docs/reference/serviceusage/latest/google.cloud.service_usage_v1.services.service_usage.ServiceUsageClient`\n- Service enable/disable guide: `https://cloud.google.com/service-usage/docs/enable-disable`\n- Service Usage IAM roles: `https://cloud.google.com/service-usage/docs/access-control`\n- Repository package root: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-usage`\n"
  },
  {
    "path": "content/google/docs/shell/python/DOC.md",
    "content": "---\nname: shell\ndescription: \"Google Cloud Shell Python client for starting environments, managing SSH keys, and authorizing gcloud access\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,cloud-shell,gcp,ssh,shell,remote-development\"\n---\n\n# Google Cloud Shell Python Client\n\n## What It Is\n\n`google-cloud-shell` is the Python client for the Cloud Shell API. Use it to inspect a user's Cloud Shell environment, start it, add or remove SSH public keys, and send OAuth credentials into the running environment so `gcloud` is already authorized.\n\nThis package does not run shell commands for you. The API gives you environment metadata such as `web_host`, `ssh_username`, `ssh_host`, and `ssh_port`; you still connect with your own SSH or web client.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-shell==1.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-shell==1.14.0\"\npoetry add \"google-cloud-shell==1.14.0\"\n```\n\nThe current Google Cloud library docs and PyPI metadata list Python 3.7+ support, including Python 3.14.\n\n## Authentication And Setup\n\nCloud Shell uses Application Default Credentials (ADC). For local development, sign in with `gcloud`:\n\n```bash\ngcloud auth application-default login\n```\n\nOptional environment variables:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/to/credentials.json\"\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nNotes:\n\n- `GOOGLE_APPLICATION_CREDENTIALS` lets ADC load a credential file explicitly.\n- Google recommends avoiding long-lived service account keys when possible.\n- `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` enables the default Google client-library log handler.\n\nCloud Shell environment names are user-scoped, not project-scoped. The default environment is typically:\n\n```text\nusers/me/environments/default\n```\n\n## Initialize The Client\n\n```python\nfrom google.cloud import shell_v1\n\nclient = shell_v1.CloudShellServiceClient()\nenvironment_name = client.environment_path(\"me\", \"default\")\n```\n\nIf you need explicit credentials:\n\n```python\nimport google.auth\nfrom google.cloud import shell_v1\n\ncredentials, _ = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\n\nclient = shell_v1.CloudShellServiceClient(credentials=credentials)\nenvironment_name = client.environment_path(\"me\", \"default\")\n```\n\n## Common Workflows\n\n### Get the current environment\n\n```python\nfrom google.cloud import shell_v1\n\nclient = shell_v1.CloudShellServiceClient()\nenvironment_name = client.environment_path(\"me\", \"default\")\n\nenvironment = client.get_environment(request={\"name\": environment_name})\n\nprint(environment.name)\nprint(environment.state)\nprint(environment.web_host)\nprint(environment.ssh_username)\nprint(environment.ssh_host)\nprint(environment.ssh_port)\n```\n\nThe returned `Environment` includes the SSH and WSS connection targets for the running environment, plus the currently registered public keys.\n\n### Start the environment and pre-authorize `gcloud`\n\n`start_environment` is a long-running operation. Wait on `.result()` before using the connection fields.\n\n```python\nfrom pathlib import Path\n\nimport google.auth\nfrom google.auth.transport.requests import Request\nfrom google.cloud import shell_v1\n\ncredentials, _ = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\ncredentials.refresh(Request())\n\nclient = shell_v1.CloudShellServiceClient(credentials=credentials)\nenvironment_name = client.environment_path(\"me\", \"default\")\npublic_key = Path.home().joinpath(\".ssh/id_rsa.pub\").read_text().strip()\n\noperation = client.start_environment(\n    request={\n        \"name\": environment_name,\n        \"access_token\": credentials.token,\n        \"public_keys\": [public_key],\n    }\n)\n\nresponse = operation.result(timeout=300)\nenvironment = response.environment\n\nprint(environment.web_host)\nprint(environment.ssh_username)\nprint(environment.ssh_host)\nprint(environment.ssh_port)\n```\n\n`access_token` is optional, but if you pass a valid token the environment is pre-authenticated so the user can run `gcloud` commands without logging in again inside Cloud Shell.\n\n### Connect over SSH after startup\n\nAfter `start_environment` completes, connect with the private key that matches one of the environment's public keys:\n\n```bash\nssh -p \"${SSH_PORT}\" \"${SSH_USER}@${SSH_HOST}\"\n```\n\nIn Python, the values come from the `Environment` returned by `get_environment()` or `start_environment()`:\n\n```python\nssh_user = environment.ssh_username\nssh_host = environment.ssh_host\nssh_port = environment.ssh_port\n```\n\n### Add a public key later\n\nUse `add_public_key` when the environment already exists and you need to allow another SSH keypair.\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud import shell_v1\n\nclient = shell_v1.CloudShellServiceClient()\nenvironment_name = client.environment_path(\"me\", \"default\")\npublic_key = Path.home().joinpath(\".ssh/id_rsa.pub\").read_text().strip()\n\noperation = client.add_public_key(\n    request={\n        \"environment\": environment_name,\n        \"key\": public_key,\n    }\n)\n\nresponse = operation.result(timeout=60)\nprint(response.key)\n```\n\nSupported key formats in the request docs are `ssh-dss`, `ssh-rsa`, and the `ecdsa-sha2-*` variants.\n\n### Remove a public key\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud import shell_v1\n\nclient = shell_v1.CloudShellServiceClient()\nenvironment_name = client.environment_path(\"me\", \"default\")\npublic_key = Path.home().joinpath(\".ssh/id_rsa.pub\").read_text().strip()\n\noperation = client.remove_public_key(\n    request={\n        \"environment\": environment_name,\n        \"key\": public_key,\n    }\n)\n\noperation.result(timeout=60)\n```\n\n### Refresh Cloud Shell authorization without restarting it\n\nIf the environment is already running, use `authorize_environment` to push a fresh OAuth token instead of starting it again.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nimport google.auth\nfrom google.auth.transport.requests import Request\nfrom google.cloud import shell_v1\nfrom google.protobuf import timestamp_pb2\n\ncredentials, _ = google.auth.default(\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"]\n)\ncredentials.refresh(Request())\n\nexpire_time = timestamp_pb2.Timestamp()\nexpire_time.FromDatetime(\n    datetime.now(timezone.utc) + timedelta(minutes=55)\n)\n\nclient = shell_v1.CloudShellServiceClient(credentials=credentials)\nenvironment_name = client.environment_path(\"me\", \"default\")\n\noperation = client.authorize_environment(\n    request={\n        \"name\": environment_name,\n        \"access_token\": credentials.token,\n        \"expire_time\": expire_time,\n    }\n)\n\noperation.result(timeout=60)\n```\n\nThe REST reference documents `id_token` as an additional optional field if your workflow also needs to send an ID token into the environment.\n\n## Important Pitfalls\n\n- Cloud Shell resource names are user-based, such as `users/me/environments/default`. Do not expect a `project=` argument on the client methods.\n- `start_environment`, `add_public_key`, `remove_public_key`, and `authorize_environment` all return long-running operations. Wait for `.result()` before assuming the change is ready.\n- SSH access only works if the private key on your machine matches one of the environment's registered public keys.\n- The API surface is intentionally small: get, start, authorize, add key, remove key. Use the returned SSH or WSS coordinates to connect; do not expect a \"run command\" RPC in this client.\n- Google Cloud ADC docs say service account keys are a security risk and are not recommended. Prefer user ADC locally or other non-key ADC flows when possible.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `google-cloud-shell 1.14.0`, released on January 15, 2026.\n- The current Google Cloud reference and changelog pages still label the latest reference content as `1.13.0`. Treat the public API surface above as current, but verify changelog-level details carefully if you depend on behavior introduced after `1.13.0`.\n- The upstream changelog for `1.13.0` adds Python 3.14 support and deprecates the `credentials_file` argument. Prefer ADC or an explicit `credentials=` object.\n- The upstream changelog for `1.12.0` adds REST interceptors that can read metadata.\n- The upstream changelog for `1.7.0` enables the `\"rest\"` transport. If you need the HTTP/JSON transport explicitly, pass `transport=\"rest\"` when creating the client.\n\n## Official Sources\n\n- Docs root: `https://docs.cloud.google.com/python/docs/reference/cloudshell/latest`\n- Client reference: `https://docs.cloud.google.com/python/docs/reference/cloudshell/latest/google.cloud.shell_v1.services.cloud_shell_service.CloudShellServiceClient`\n- `StartEnvironmentRequest`: `https://docs.cloud.google.com/python/docs/reference/cloudshell/latest/google.cloud.shell_v1.types.StartEnvironmentRequest`\n- `Environment` type: `https://docs.cloud.google.com/python/docs/reference/cloudshell/latest/google.cloud.shell_v1.types.Environment`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/cloudshell/latest/changelog`\n- Cloud Shell REST API: `https://cloud.google.com/shell/docs/reference/rest`\n- `users.environments.start`: `https://cloud.google.com/shell/docs/reference/rest/v1/users.environments/start`\n- `users.environments.authorize`: `https://docs.cloud.google.com/shell/docs/reference/rest/v1/users.environments/authorize`\n- ADC overview: `https://docs.cloud.google.com/docs/authentication/application-default-credentials`\n- PyPI: `https://pypi.org/project/google-cloud-shell/`\n"
  },
  {
    "path": "content/google/docs/source-context/python/DOC.md",
    "content": "---\nname: source-context\ndescription: \"google-cloud-source-context message types for describing Git, Gerrit, Cloud Repo, and Cloud Workspace source revisions in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,source-context,gcp,protobuf,git,gerrit\"\n---\n\n# google-cloud-source-context Python Package Guide\n\n## What It Is\n\n`google-cloud-source-context` provides the generated Python message types for Google Source Context v1.\n\nThe current official reference pages for this package are centered on `google.cloud.source_context_v1.types`, including:\n\n- `SourceContext`\n- `ExtendedSourceContext`\n- `GitSourceContext`\n- `GerritSourceContext`\n- `CloudRepoSourceContext`\n- `CloudWorkspaceSourceContext`\n- `RepoId`\n- `ProjectRepoId`\n\nUse this package when another Google API or protobuf message expects a `SourceContext` or `ExtendedSourceContext`. For standalone usage, you usually just construct these message objects and pass them into another request.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-source-context==1.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-source-context==1.9.0\"\npoetry add \"google-cloud-source-context==1.9.0\"\n```\n\n## Authentication And Environment\n\nConstructing `SourceContext` messages does not require credentials and this package does not need its own client initialization.\n\nIf you pass these messages to another Google Cloud client, that client typically uses Application Default Credentials (ADC):\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nPractical note:\n\n- The message classes in this package do not read these environment variables directly.\n- `GOOGLE_APPLICATION_CREDENTIALS` and `GOOGLE_CLOUD_PROJECT` matter for the downstream Google Cloud client you pair with these types.\n\n## Imports And Initialization\n\nImport the message types directly and instantiate them. There is no separate `SourceContextClient` shown in the current official package reference.\n\n```python\nfrom google.cloud.source_context_v1.types import (\n    AliasContext,\n    CloudRepoSourceContext,\n    CloudWorkspaceId,\n    CloudWorkspaceSourceContext,\n    ExtendedSourceContext,\n    GerritSourceContext,\n    GitSourceContext,\n    ProjectRepoId,\n    RepoId,\n    SourceContext,\n)\n```\n\n## Core Usage\n\n### Describe A Git Commit\n\n`GitSourceContext` is the most direct option when you know the repository URL and the exact commit hash.\n\n```python\nfrom google.cloud.source_context_v1.types import GitSourceContext, SourceContext\n\nsource_context = SourceContext(\n    git=GitSourceContext(\n        url=\"https://github.com/example/service.git\",\n        revision_id=\"4f3a1c6b7d8e9f00112233445566778899aabbcc\",\n    )\n)\n\nprint(source_context.git.url)\nprint(source_context.git.revision_id)\n```\n\nThe official type docs describe `GitSourceContext.url` and `GitSourceContext.revision_id` as required fields.\n\n### Describe A Cloud Source Repositories Revision\n\nUse `CloudRepoSourceContext` when the source lives in a Google-hosted repository identified by project and repo name.\n\n```python\nfrom google.cloud.source_context_v1.types import (\n    CloudRepoSourceContext,\n    ProjectRepoId,\n    RepoId,\n    SourceContext,\n)\n\nsource_context = SourceContext(\n    cloud_repo=CloudRepoSourceContext(\n        repo_id=RepoId(\n            project_repo_id=ProjectRepoId(\n                project_id=\"my-gcp-project\",\n                repo_name=\"backend\",\n            )\n        ),\n        revision_id=\"4f3a1c6b7d8e9f00112233445566778899aabbcc\",\n    )\n)\n\nprint(source_context.cloud_repo.repo_id.project_repo_id.project_id)\nprint(source_context.cloud_repo.revision_id)\n```\n\nIf you want to point at a branch or tag instead of a fixed commit, use `alias_name` or `alias_context` on `CloudRepoSourceContext`.\n\n### Describe A Gerrit Revision\n\nUse `GerritSourceContext` when the revision comes from a Gerrit host and project.\n\n```python\nfrom google.cloud.source_context_v1.types import GerritSourceContext, SourceContext\n\nsource_context = SourceContext(\n    gerrit=GerritSourceContext(\n        host_uri=\"https://gerrit-review.googlesource.com\",\n        gerrit_project=\"my-team/service\",\n        revision_id=\"4f3a1c6b7d8e9f00112233445566778899aabbcc\",\n    )\n)\n\nprint(source_context.gerrit.host_uri)\nprint(source_context.gerrit.gerrit_project)\nprint(source_context.gerrit.revision_id)\n```\n\n### Describe A Cloud Workspace Snapshot\n\nUse `CloudWorkspaceSourceContext` when the source reference is a Cloud Workspace snapshot instead of a repo revision.\n\n```python\nfrom google.cloud.source_context_v1.types import (\n    CloudWorkspaceId,\n    CloudWorkspaceSourceContext,\n    ProjectRepoId,\n    RepoId,\n    SourceContext,\n)\n\nsource_context = SourceContext(\n    cloud_workspace=CloudWorkspaceSourceContext(\n        workspace_id=CloudWorkspaceId(\n            repo_id=RepoId(\n                project_repo_id=ProjectRepoId(\n                    project_id=\"my-gcp-project\",\n                    repo_name=\"backend\",\n                )\n            ),\n            name=\"alice-feature-workspace\",\n        ),\n        snapshot_id=\"snapshot-123\",\n    )\n)\n\nprint(source_context.cloud_workspace.workspace_id.name)\nprint(source_context.cloud_workspace.snapshot_id)\n```\n\nThe official docs note that an empty `snapshot_id` means \"the most recent snapshot.\"\n\n### Attach Labels With `ExtendedSourceContext`\n\nUse `ExtendedSourceContext` when you need the base source reference plus extra labels.\n\n```python\nfrom google.cloud.source_context_v1.types import (\n    ExtendedSourceContext,\n    GitSourceContext,\n    SourceContext,\n)\n\nextended = ExtendedSourceContext(\n    context=SourceContext(\n        git=GitSourceContext(\n            url=\"https://github.com/example/service.git\",\n            revision_id=\"4f3a1c6b7d8e9f00112233445566778899aabbcc\",\n        )\n    ),\n    labels={\n        \"component\": \"api\",\n        \"deploy_env\": \"prod\",\n    },\n)\n\nprint(extended.context.git.url)\nprint(extended.labels[\"component\"])\n```\n\n## Common Patterns\n\n### Use A Branch Or Tag Alias\n\nIf the upstream API accepts a movable reference instead of a fixed revision, use `AliasContext`.\n\n```python\nfrom google.cloud.source_context_v1.types import (\n    AliasContext,\n    CloudRepoSourceContext,\n    ProjectRepoId,\n    RepoId,\n    SourceContext,\n)\n\nsource_context = SourceContext(\n    cloud_repo=CloudRepoSourceContext(\n        repo_id=RepoId(\n            project_repo_id=ProjectRepoId(\n                project_id=\"my-gcp-project\",\n                repo_name=\"backend\",\n            )\n        ),\n        alias_context=AliasContext(alias_name=\"main\"),\n    )\n)\n\nprint(source_context.cloud_repo.alias_context.alias_name)\n```\n\nUse a fixed `revision_id` when reproducibility matters more than following the current branch head.\n\n### Pass The Message Into Another Request\n\nThis package is usually consumed indirectly. When a downstream Google client library exposes a field typed as `SourceContext` or `ExtendedSourceContext`, build the message here first and pass that typed object into the request instead of assembling an ad hoc dict payload.\n\n## Common Pitfalls\n\n- `SourceContext` is a oneof wrapper. Set only one of `cloud_repo`, `cloud_workspace`, `gerrit`, or `git`.\n- `CloudRepoSourceContext` and `GerritSourceContext` also use oneof fields for the revision selector. `revision_id`, `alias_name`, and `alias_context` are alternatives, not additive fields.\n- `GitSourceContext` expects the exact repository URL and commit hash. It does not resolve branches for you.\n- `ProjectRepoId.repo_name` may be empty for the default repo, so do not assume it is always populated.\n- `CloudWorkspaceSourceContext.snapshot_id` is optional; the official docs say an empty value means the most recent snapshot.\n- This package models source references. It does not clone repositories, fetch commits, or provide a standalone repository service client.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `1.9.0` as the package version for `google-cloud-source-context`.\n- The official changelog entry for `1.9.0` notes mTLS auto-enablement support when a client certificate is available and generated GAPIC updates around Python and dependency version checks.\n- The official changelog entry for `1.8.0` adds Python 3.14 support. If you are standardizing on Python 3.14, use `1.8.0` or newer.\n- The current docs site serves the package reference under the `latest` tree, while PyPI is the authoritative source for the exact package version you install.\n\n## Official Sources\n\n- Package docs overview: `https://cloud.google.com/python/docs/reference/source/latest/summary_overview`\n- Type reference index: `https://docs.cloud.google.com/python/docs/reference/source/latest/google.cloud.source_context_v1.types`\n- Changelog: `https://cloud.google.com/python/docs/reference/source/latest/changelog`\n- PyPI: `https://pypi.org/project/google-cloud-source-context/`\n- Maintainer repository: `https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-source-context`\n- ADC setup: `https://cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/spanner/javascript/DOC.md",
    "content": "---\nname: spanner\ndescription: \"Google Cloud Spanner Node.js client for SQL queries, mutations, read-write transactions, schema updates, and emulator-based local development\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.6.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,spanner,database,sql,gcp,transactions,nodejs\"\n---\n\n# `@google-cloud/spanner` JavaScript Package Guide\n\nUse `@google-cloud/spanner` when you need to query Cloud Spanner with SQL, apply mutations, run read-write transactions, and manage schema from Node.js.\n\n## Golden Rule\n\n- Import `Spanner` from `@google-cloud/spanner` and create one long-lived client per process.\n- Authenticate with Application Default Credentials (ADC), not API keys.\n- Reuse `Instance` and `Database` handles instead of recreating them for every query.\n- Use parameterized SQL for dynamic values.\n- Close `Database` handles when your app shuts down or a short-lived script finishes so sessions are released cleanly.\n\nThis guide covers `8.6.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/spanner@8.6.0\n```\n\n## Authentication And Environment\n\nEnable the API in the Google Cloud project you want to use:\n\n```bash\ngcloud services enable spanner.googleapis.com\n```\n\nFor local development with your user credentials:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nFor deployed workloads, prefer attached service accounts. If you need to point ADC at a key file locally or in CI:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nUseful app-level variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport SPANNER_INSTANCE_ID=\"your-instance-id\"\nexport SPANNER_DATABASE_ID=\"your-database-id\"\n```\n\nThis guide assumes the instance and database already exist.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst instanceId = process.env.SPANNER_INSTANCE_ID;\nconst databaseId = process.env.SPANNER_DATABASE_ID;\n\nconst spanner = new Spanner({projectId});\nconst instance = spanner.instance(instanceId);\nconst database = instance.database(databaseId);\n```\n\nES modules:\n\n```javascript\nimport {Spanner} from '@google-cloud/spanner';\n\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst instanceId = process.env.SPANNER_INSTANCE_ID;\nconst databaseId = process.env.SPANNER_DATABASE_ID;\n\nconst spanner = new Spanner({projectId});\nconst instance = spanner.instance(instanceId);\nconst database = instance.database(databaseId);\n```\n\nIf you use the handle in a short-lived script, release sessions when you are done:\n\n```javascript\ntry {\n  const [rows] = await database.run({sql: 'SELECT 1'});\n  console.log(rows.length);\n} finally {\n  await database.close();\n}\n```\n\n## Common Workflows\n\n### Run A SQL Query\n\nUse `database.run()` for straightforward query execution:\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n\nasync function listSingers() {\n  const [rows] = await database.run({\n    sql: `\n      SELECT SingerId, FirstName, LastName\n      FROM Singers\n      ORDER BY SingerId\n    `,\n  });\n\n  return rows.map(row => row.toJSON());\n}\n\ntry {\n  const singers = await listSingers();\n  console.log(singers);\n} finally {\n  await database.close();\n}\n```\n\n### Use Parameters Instead Of String Interpolation\n\nPass dynamic values in `params`. For integer values, use `Spanner.int(...)` when you need an exact Spanner `INT64` value.\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n\nasync function getAlbumsForSinger(singerId) {\n  const [rows] = await database.run({\n    sql: `\n      SELECT SingerId, AlbumId, AlbumTitle\n      FROM Albums\n      WHERE SingerId = @singerId\n      ORDER BY AlbumId\n    `,\n    params: {\n      singerId: Spanner.int(singerId),\n    },\n  });\n\n  return rows.map(row => row.toJSON());\n}\n```\n\n### Insert Rows With Mutations\n\nUse table mutations when you want to write whole rows without DML:\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n\nasync function insertSingers() {\n  await database.table('Singers').insert([\n    {\n      SingerId: Spanner.int(1),\n      FirstName: 'Ada',\n      LastName: 'Lovelace',\n    },\n    {\n      SingerId: Spanner.int(2),\n      FirstName: 'Grace',\n      LastName: 'Hopper',\n    },\n  ]);\n}\n```\n\nFor idempotent writes, use `upsert()` instead of `insert()`.\n\n### Run DML In A Read-Write Transaction\n\nUse a transaction when multiple statements must commit atomically:\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n\nasync function increaseBudget(singerId, delta) {\n  const [transaction] = await database.getTransaction();\n\n  try {\n    const [rowCount] = await transaction.runUpdate({\n      sql: `\n        UPDATE Albums\n        SET MarketingBudget = MarketingBudget + @delta\n        WHERE SingerId = @singerId\n      `,\n      params: {\n        delta: Spanner.int(delta),\n        singerId: Spanner.int(singerId),\n      },\n    });\n\n    await transaction.commit();\n    return rowCount;\n  } catch (error) {\n    await transaction.rollback();\n    throw error;\n  }\n}\n```\n\nUse transactions for read-write units of work. For simple row inserts, updates, or deletes that already map cleanly to mutations, table mutation helpers are often simpler.\n\n### Update Schema\n\nSchema changes return a long-running operation. Wait for it to finish before issuing dependent queries or writes.\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n\nasync function createSingersTable() {\n  const [operation] = await database.updateSchema([\n    `CREATE TABLE Singers (\n      SingerId INT64 NOT NULL,\n      FirstName STRING(1024),\n      LastName STRING(1024)\n    ) PRIMARY KEY (SingerId)`,\n  ]);\n\n  await operation.promise();\n}\n```\n\n## Emulator Setup\n\nFor local development or tests, start the Spanner emulator and point the client at it:\n\n```bash\ngcloud emulators spanner start\nexport SPANNER_EMULATOR_HOST=\"localhost:9010\"\nexport GOOGLE_CLOUD_PROJECT=\"test-project\"\nexport SPANNER_INSTANCE_ID=\"test-instance\"\nexport SPANNER_DATABASE_ID=\"test-database\"\n```\n\nCreate the instance and database your app expects:\n\n```bash\ngcloud spanner instances create test-instance \\\n  --config=emulator-config \\\n  --description=\"Spanner emulator\" \\\n  --nodes=1\n\ngcloud spanner databases create test-database --instance=test-instance\n```\n\nThen initialize the client the same way as production code:\n\n```javascript\nconst {Spanner} = require('@google-cloud/spanner');\n\nconst spanner = new Spanner({projectId: process.env.GOOGLE_CLOUD_PROJECT});\nconst database = spanner\n  .instance(process.env.SPANNER_INSTANCE_ID)\n  .database(process.env.SPANNER_DATABASE_ID);\n```\n\nWhen `SPANNER_EMULATOR_HOST` is set, the client connects to the emulator instead of the production service.\n\n## Common Pitfalls\n\n- Do not use API keys. Cloud Spanner client libraries use ADC and IAM credentials.\n- Reuse `Spanner`, `Instance`, and `Database` handles instead of constructing new ones for every request.\n- Close `database` handles in scripts, workers, and tests so session resources are released.\n- Do not build SQL with string interpolation for user input. Use `params`.\n- JavaScript numbers do not safely represent every `INT64` value. Use `Spanner.int(...)` for exact integer parameters and mutation values when precision matters.\n- Schema updates are asynchronous. Wait for `operation.promise()` before assuming the new schema is ready.\n- The emulator is useful for local development, but it does not replace validation against a real Cloud Spanner instance for IAM, quotas, and production behavior.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/spanner` `8.6.0`.\n- Pin the npm dependency if your application depends on behavior from this exact release while the online reference stays on the `latest` docs root.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/spanner/latest`\n- Cloud Spanner product docs: `https://cloud.google.com/spanner/docs`\n- Cloud Spanner Node.js quickstart: `https://cloud.google.com/spanner/docs/getting-started/nodejs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Local ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Spanner emulator: `https://cloud.google.com/spanner/docs/emulator`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/spanner`\n"
  },
  {
    "path": "content/google/docs/spanner/python/DOC.md",
    "content": "---\nname: spanner\ndescription: \"Google Cloud Spanner Python client library for sessions, SQL reads, transactions, DML, and emulator-backed local development\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.63.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,spanner,database,sql,gcp,transactions\"\n---\n\n# Google Cloud Spanner Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-spanner` package and authenticate with Application Default Credentials (ADC). Structure code around one long-lived `spanner.Client`, then derive `Instance` and `Database` handles from it.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-spanner==3.63.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-spanner==3.63.0\"\npoetry add \"google-cloud-spanner==3.63.0\"\n```\n\n## Authentication And Environment\n\nEnable the API once per Google Cloud project:\n\n```bash\ngcloud services enable spanner.googleapis.com\n```\n\nFor local development with your user credentials:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nFor deployed workloads, prefer attached service accounts. If you must use a key locally or in CI, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nA simple app-level environment setup:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\nexport SPANNER_INSTANCE_ID=\"your-instance-id\"\nexport SPANNER_DATABASE_ID=\"your-database-id\"\n```\n\n## Initialize The Client\n\nCreate one reusable client, then derive instance and database handles:\n\n```python\nimport os\n\nfrom google.cloud import spanner\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\ninstance_id = os.environ[\"SPANNER_INSTANCE_ID\"]\ndatabase_id = os.environ[\"SPANNER_DATABASE_ID\"]\n\nclient = spanner.Client(project=project_id)\ninstance = client.instance(instance_id)\ndatabase = instance.database(database_id)\n```\n\nNotes:\n\n- `Client` is gRPC-based. The official client docs explicitly note that no `_http` transport argument is accepted.\n- Reuse the same `Client` instead of creating one per request.\n- `Database` uses a session pool under the hood. The default is a `BurstyPool`; tune `pool=` only if you understand your concurrency and session lifecycle needs.\n\n## Core Usage\n\n### Read rows with a snapshot\n\nUse `database.snapshot()` for consistent read-only work:\n\n```python\nfrom google.cloud import spanner\n\nclient = spanner.Client(project=\"your-project-id\")\ndatabase = client.instance(\"my-instance\").database(\"my-database\")\n\nwith database.snapshot() as snapshot:\n    results = snapshot.execute_sql(\n        \"\"\"\n        SELECT SingerId, FirstName, LastName\n        FROM Singers\n        ORDER BY SingerId\n        \"\"\"\n    )\n    for row in results:\n        print(row)\n```\n\nKey point:\n\n- `Snapshot` is for reads. Do not try to mutate data from it.\n\n### Insert or update rows with a batch\n\nUse `database.batch()` for straightforward mutations:\n\n```python\nfrom google.cloud import spanner\n\nclient = spanner.Client(project=\"your-project-id\")\ndatabase = client.instance(\"my-instance\").database(\"my-database\")\n\nwith database.batch() as batch:\n    batch.insert(\n        table=\"Singers\",\n        columns=(\"SingerId\", \"FirstName\", \"LastName\"),\n        values=[\n            (1, \"Marc\", \"Richards\"),\n            (2, \"Catalina\", \"Smith\"),\n        ],\n    )\n```\n\nUseful mutation methods include `insert`, `update`, `insert_or_update`, `replace`, and `delete`.\n\n### Use a read-write transaction\n\nUse `run_in_transaction()` when multiple reads and writes must commit atomically:\n\n```python\nfrom google.cloud import spanner\n\nclient = spanner.Client(project=\"your-project-id\")\ndatabase = client.instance(\"my-instance\").database(\"my-database\")\n\ndef transfer_budget(transaction, singer_id, delta):\n    row = transaction.execute_sql(\n        \"\"\"\n        SELECT MarketingBudget\n        FROM Albums\n        WHERE SingerId = @singer_id\n        \"\"\",\n        params={\"singer_id\": singer_id},\n        param_types={\"singer_id\": spanner.param_types.INT64},\n    ).one()\n\n    new_budget = row[0] + delta\n\n    transaction.execute_update(\n        \"\"\"\n        UPDATE Albums\n        SET MarketingBudget = @budget\n        WHERE SingerId = @singer_id\n        \"\"\",\n        params={\"budget\": new_budget, \"singer_id\": singer_id},\n        param_types={\n            \"budget\": spanner.param_types.INT64,\n            \"singer_id\": spanner.param_types.INT64,\n        },\n    )\n\ndatabase.run_in_transaction(transfer_budget, singer_id=1, delta=5000)\n```\n\nUse `execute_update()` for DML inside transactions. For large standalone DML operations, check whether `execute_partitioned_dml()` is the better fit for your workload.\n\n### Parameterized SQL\n\nDo not format values directly into SQL strings. Use parameters and Spanner types:\n\n```python\nfrom google.cloud import spanner\n\nwith database.snapshot() as snapshot:\n    rows = snapshot.execute_sql(\n        \"\"\"\n        SELECT SingerId, FirstName\n        FROM Singers\n        WHERE LastName = @last_name\n        \"\"\",\n        params={\"last_name\": \"Richards\"},\n        param_types={\"last_name\": spanner.param_types.STRING},\n    )\n    for row in rows:\n        print(row)\n```\n\n## DB-API 2.0 Mode\n\nThis package also ships `google.cloud.spanner_dbapi`, a PEP 249 wrapper that is useful when you need a familiar DB-API cursor/connection interface.\n\n```python\nfrom google.cloud import spanner_dbapi\n\nconn = spanner_dbapi.connect(\n    \"my-instance\",\n    \"my-database\",\n    project=\"your-project-id\",\n)\n\nwith conn.cursor() as cursor:\n    cursor.execute(\n        \"SELECT SingerId, FirstName FROM Singers WHERE SingerId = %s\",\n        (1,),\n    )\n    print(cursor.fetchall())\n\nconn.close()\n```\n\nUse the DB-API layer when a framework expects DB-API semantics. Use `google.cloud.spanner` directly when you want native Spanner transaction and snapshot APIs.\n\n## Emulator Setup\n\nFor local or test environments, start the emulator and point the client at it:\n\n```bash\ngcloud emulators spanner start\nexport SPANNER_EMULATOR_HOST=\"localhost:9010\"\n```\n\nThen create the instance and database your tests expect:\n\n```bash\ngcloud spanner instances create test-instance \\\n  --config=emulator-config \\\n  --description=\"Spanner emulator\" \\\n  --nodes=1\n\ngcloud spanner databases create test-database --instance=test-instance\n```\n\nThe library detects `SPANNER_EMULATOR_HOST`. When you configure the client manually, use anonymous credentials against the emulator:\n\n```python\nfrom google.auth.credentials import AnonymousCredentials\nfrom google.cloud import spanner\n\nclient = spanner.Client(\n    project=\"test-project\",\n    credentials=AnonymousCredentials(),\n)\ndatabase = client.instance(\"test-instance\").database(\"test-database\")\n```\n\n## Common Pitfalls\n\n- Do not use API keys. Cloud Spanner client authentication is based on ADC and IAM credentials.\n- Do not create a fresh `spanner.Client()` for every query or HTTP request.\n- `snapshot()` is read-only. Use `batch()` or `run_in_transaction()` for writes.\n- Always parameterize SQL and provide `param_types`; agents often forget the type mapping and then produce invalid examples.\n- The emulator is not production-equivalent. Validate IAM, quotas, leader routing, and latency-sensitive behavior against real Cloud Spanner before release.\n- If you need custom routing or metrics behavior, check constructor flags like `route_to_leader_enabled`, `directed_read_options`, `disable_builtin_metrics`, and `resource_exhausted_behavior` in the current client reference instead of guessing names from older blog posts.\n- If you use the DB-API wrapper, keep in mind that not every third-party ORM assumption maps cleanly onto Spanner semantics.\n\n## Version-Sensitive Notes\n\n- PyPI lists `3.63.0` as the current package version for this package.\n- The Google Cloud `latest` reference root is usable for `3.63.0`, but rendered pages are not perfectly in sync: the changelog includes `3.63.0`, while some class pages under `latest` still show older minor-version badges.\n- Because the docs root is `latest`, prefer the package version from PyPI when pinning dependencies and use the reference site for API shape, constructor flags, and examples.\n\n## Official Sources\n\n- Reference root: `https://docs.cloud.google.com/python/docs/reference/spanner/latest`\n- Client usage guide: `https://docs.cloud.google.com/python/docs/reference/spanner/latest/client-usage`\n- Client class reference: `https://cloud.google.com/python/docs/reference/spanner/latest/google.cloud.spanner_v1.client.Client`\n- Database class reference: `https://cloud.google.com/python/docs/reference/spanner/latest/google.cloud.spanner_v1.database.Database`\n- Changelog: `https://cloud.google.com/python/docs/reference/spanner/latest/changelog`\n- Getting started: `https://docs.cloud.google.com/spanner/docs/getting-started/python`\n- Emulator guide: `https://docs.cloud.google.com/spanner/docs/emulator`\n- PyPI package page: `https://pypi.org/project/google-cloud-spanner/`\n- Upstream repository: `https://github.com/googleapis/python-spanner`\n"
  },
  {
    "path": "content/google/docs/speech/javascript/DOC.md",
    "content": "---\nname: speech\ndescription: \"Google Cloud Speech-to-Text Node.js client library for v1 and v2 transcription workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,speech,speech-to-text,transcription,audio,javascript,nodejs\"\n---\n\n# `@google-cloud/speech` JavaScript Package Guide\n\nUse `@google-cloud/speech` in Node.js code that needs Google Cloud Speech-to-Text. The package ships multiple API surfaces, so decide up front whether your code is using the classic `v1` client or the newer `v2` client.\n\n## Golden Rule\n\n- Choose `v1` or `v2` explicitly in your imports and keep the request types consistent with that choice.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass credentials explicitly.\n- Use `v1.recognize()` for short synchronous requests, `v1.longRunningRecognize()` for longer Cloud Storage jobs, and `v1.streamingRecognize()` for live or chunked audio streams.\n- Use `v2` for new integrations that need recognizers, auto-decoding, or batch workflows.\n- For `v2`, always set the `recognizer` resource name; the `_` recognizer is the usual one-off path.\n- Prefer `gs://...` inputs for longer audio instead of sending large local payloads.\n\nThis guide covers `7.3.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/speech@7.3.0\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable speech.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimum setup:\n\n1. Enable the Speech-to-Text API in the target project.\n2. Make sure the credential resolves to the project and principal you expect.\n3. Set `GOOGLE_CLOUD_PROJECT` for `v2` code so recognizer resource names are easy to build.\n\n## Choose The Right Surface\n\n### Use `v1` when\n\n- you already have code built around `audio` plus `config` request objects\n- you need classic synchronous, long-running, or streaming recognition samples\n- you are maintaining an older integration and want the smallest change set\n\n### Use `v2` when\n\n- you are building a new integration\n- you want `autoDecodingConfig`\n- you need recognizer resources or batch recognition workflows\n- you need regional endpoints and recognizer locations to line up explicitly\n\nDo not mix `v1` request shapes with a `v2` client, or vice versa.\n\n## Initialize The Client\n\n### `v1` client\n\nCommonJS:\n\n```javascript\nconst {v1: speech} = require('@google-cloud/speech');\n\nconst client = new speech.SpeechClient();\n```\n\nES modules:\n\n```javascript\nimport {v1 as speech} from '@google-cloud/speech';\n\nconst client = new speech.SpeechClient();\n```\n\n### `v2` client\n\nCommonJS:\n\n```javascript\nconst {v2: speechV2} = require('@google-cloud/speech');\n\nconst client = new speechV2.SpeechClient();\n```\n\nES modules:\n\n```javascript\nimport {v2 as speechV2} from '@google-cloud/speech';\n\nconst client = new speechV2.SpeechClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v2: speechV2} = require('@google-cloud/speech');\n\nconst client = new speechV2.SpeechClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### `v1`: Transcribe A Short Local File\n\nUse `recognize()` for short request-response jobs. For raw PCM input, make sure the encoding and sample rate match the source audio.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v1: speech} = require('@google-cloud/speech');\n\nconst client = new speech.SpeechClient();\n\nasync function recognizeFile(filePath) {\n  const content = await fs.readFile(filePath);\n\n  const [response] = await client.recognize({\n    audio: {content},\n    config: {\n      encoding: 'LINEAR16',\n      sampleRateHertz: 16000,\n      languageCode: 'en-US',\n      enableAutomaticPunctuation: true,\n    },\n  });\n\n  for (const result of response.results ?? []) {\n    const alternative = result.alternatives?.[0];\n    if (alternative) {\n      console.log(alternative.transcript);\n    }\n  }\n\n  return response;\n}\n\nrecognizeFile('./audio.raw').catch(console.error);\n```\n\n### `v1`: Transcribe Longer Audio From Cloud Storage\n\nUse `longRunningRecognize()` when the source audio is already in Cloud Storage or the job should run asynchronously.\n\n```javascript\nconst {v1: speech} = require('@google-cloud/speech');\n\nconst client = new speech.SpeechClient();\n\nasync function recognizeFromGcs(uri) {\n  const [operation] = await client.longRunningRecognize({\n    audio: {uri},\n    config: {\n      languageCode: 'en-US',\n      enableAutomaticPunctuation: true,\n    },\n  });\n\n  const [response] = await operation.promise();\n\n  for (const result of response.results ?? []) {\n    const alternative = result.alternatives?.[0];\n    if (alternative) {\n      console.log(alternative.transcript);\n    }\n  }\n\n  return response;\n}\n\nrecognizeFromGcs('gs://my-bucket/audio.flac').catch(console.error);\n```\n\n### `v1`: Stream Chunked Audio\n\nUse `streamingRecognize()` for microphone-style or chunked audio flows. The stream must match the config you send.\n\n```javascript\nconst fs = require('node:fs');\nconst {v1: speech} = require('@google-cloud/speech');\n\nconst client = new speech.SpeechClient();\n\nfunction streamAudio(filePath) {\n  const recognizeStream = client\n    .streamingRecognize({\n      config: {\n        encoding: 'LINEAR16',\n        sampleRateHertz: 16000,\n        languageCode: 'en-US',\n      },\n      interimResults: true,\n    })\n    .on('error', console.error)\n    .on('data', data => {\n      const transcript = data.results?.[0]?.alternatives?.[0]?.transcript;\n      if (transcript) {\n        console.log(transcript);\n      }\n    });\n\n  fs.createReadStream(filePath).pipe(recognizeStream);\n  return recognizeStream;\n}\n\nstreamAudio('./audio.raw');\n```\n\nIf you start from a WAV, MP3, or other containerized file instead of raw chunks, prefer `recognize()` or `longRunningRecognize()` unless you decode the stream first.\n\n### `v2`: Recognize A Local File With Auto-Decoding\n\nThis is the cleanest `v2` quickstart. The `_` recognizer avoids creating a dedicated recognizer resource for one-off requests.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v2: speechV2} = require('@google-cloud/speech');\n\nconst client = new speechV2.SpeechClient();\n\nasync function recognizeV2(filePath) {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n  const content = await fs.readFile(filePath);\n\n  const [response] = await client.recognize({\n    recognizer: `projects/${projectId}/locations/global/recognizers/_`,\n    config: {\n      autoDecodingConfig: {},\n      languageCodes: ['en-US'],\n      model: 'short',\n    },\n    content,\n  });\n\n  for (const result of response.results ?? []) {\n    const alternative = result.alternatives?.[0];\n    if (alternative) {\n      console.log(alternative.transcript);\n    }\n  }\n\n  return response;\n}\n\nrecognizeV2('./audio.wav').catch(console.error);\n```\n\n### `v2`: Batch Recognize Audio From Cloud Storage\n\nUse `batchRecognize()` for asynchronous `v2` processing from Cloud Storage. Write results to Cloud Storage when another system needs to read the output later.\n\n```javascript\nconst {v2: speechV2} = require('@google-cloud/speech');\n\nconst client = new speechV2.SpeechClient();\n\nasync function batchRecognizeToGcs(audioUri, outputUri) {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT;\n\n  const [operation] = await client.batchRecognize({\n    recognizer: `projects/${projectId}/locations/global/recognizers/_`,\n    config: {\n      autoDecodingConfig: {},\n      languageCodes: ['en-US'],\n      model: 'long',\n    },\n    files: [{uri: audioUri}],\n    recognitionOutputConfig: {\n      gcsOutputConfig: {\n        uri: outputUri,\n      },\n    },\n  });\n\n  await operation.promise();\n}\n\nbatchRecognizeToGcs(\n  'gs://my-bucket/audio.wav',\n  'gs://my-bucket/transcripts/'\n).catch(console.error);\n```\n\n## Regional Endpoints For `v2`\n\nIf you need a regional endpoint, keep the API endpoint and recognizer location aligned.\n\n```javascript\nconst {v2: speechV2} = require('@google-cloud/speech');\n\nconst client = new speechV2.SpeechClient({\n  apiEndpoint: 'us-speech.googleapis.com',\n});\n\nconst recognizer = `projects/${process.env.GOOGLE_CLOUD_PROJECT}/locations/us/recognizers/_`;\n```\n\nDo not pair `us-speech.googleapis.com` with `locations/global`.\n\n## Response Handling\n\nThe common shapes are:\n\n```javascript\nconst [response] = await client.recognize(request);\n```\n\nand for long-running operations:\n\n```javascript\nconst [operation] = await client.longRunningRecognize(request);\nconst [response] = await operation.promise();\n```\n\nor in `v2`:\n\n```javascript\nconst [operation] = await client.batchRecognize(request);\nconst [response] = await operation.promise();\n```\n\nFor transcript text, most flows read `response.results` and then the first alternative from each result.\n\n## Common Pitfalls\n\n- The package exports multiple surfaces. Be explicit with `v1` or `v2` imports instead of mixing examples.\n- `v2` requests need a `recognizer` field. `GOOGLE_CLOUD_PROJECT` is usually the easiest way to build that path.\n- `streamingRecognize()` expects chunked audio that matches the request config. Do not pipe arbitrary file formats into it and expect automatic decoding.\n- `recognize()` is the synchronous path. Move longer jobs to `longRunningRecognize()` or `batchRecognize()` instead of forcing large inline payloads.\n- Regional `v2` endpoints and recognizer locations must match.\n- This client uses Google Cloud credentials, not an API key.\n- The package also includes `v1p1beta1`. Use it only when you specifically need that surface; do not choose it by default for new code.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/speech/latest`\n- Speech-to-Text client library quickstart: `https://cloud.google.com/speech-to-text/docs/transcribe-client-libraries`\n- Speech-to-Text migration guide: `https://cloud.google.com/speech-to-text/docs/migration`\n- Application Default Credentials: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/speech`\n"
  },
  {
    "path": "content/google/docs/speech/python/DOC.md",
    "content": "---\nname: speech\ndescription: \"Google Cloud Speech-to-Text Python client library for v1 and v2 transcription workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.37.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,speech,speech-to-text,transcription,audio,cloud\"\n---\n\n# Google Cloud Speech-to-Text Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-speech` for Google Cloud Speech-to-Text in Python, and decide up front whether your code is using the classic v1 surface or the newer v2 surface.\n\n- v1 uses `from google.cloud import speech` and is the shortest path for existing samples and legacy request shapes.\n- v2 uses `from google.cloud.speech_v2 import SpeechClient` and adds recognizers, auto-decoding, batch workflows, regionalization, and newer model options.\n\nDo not mix v1 and v2 message types in the same request path.\n\n## Install\n\nPin the package version if you want behavior to match this doc:\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-speech==2.37.0\"\n```\n\nYou also need the Speech-to-Text API enabled in the target project:\n\n```bash\ngcloud services enable speech.googleapis.com\n```\n\n## Auth And Project Setup\n\nGoogle Cloud client libraries use Application Default Credentials (ADC).\n\nADC checks credentials in this order:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. Credentials created by `gcloud auth application-default login`\n3. The attached service account from the metadata server on Google Cloud\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID\n```\n\nIf you must point to a credential file explicitly:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/credentials.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nPrefer attached service accounts in production on Google Cloud. Google documents raw service account keys as a security risk; use them only when you cannot use attached identities or federation.\n\n## Choose The Right Surface\n\n### Use v1 when\n\n- you already have working code based on `speech.RecognitionAudio` and `speech.RecognitionConfig`\n- you need existing synchronous, long-running, or streaming samples with the classic API shape\n- you are maintaining older integrations and want minimal changes\n\n### Use v2 when\n\n- you are building a new integration\n- you want `AutoDetectDecodingConfig`\n- you need recognizer resources, batch recognition, newer model selection, or regional routing\n- you are migrating toward the current product direction\n\nGoogle's migration guide is explicit that moving from v1 to v2 is not automatic.\n\n## Initialize Clients\n\n### v1\n\n```python\nfrom google.cloud import speech\n\nclient = speech.SpeechClient()\n```\n\n### v2\n\n```python\nfrom google.cloud.speech_v2 import SpeechClient\n\nclient = SpeechClient()\n```\n\n### Regional endpoint override\n\nIf you need US or EU data residency, use a matching endpoint and location:\n\n```python\nfrom google.api_core import client_options\nfrom google.cloud.speech_v2 import SpeechClient\n\noptions = client_options.ClientOptions(api_endpoint=\"us-speech.googleapis.com\")\nclient = SpeechClient(client_options=options)\n```\n\nUse matching resource paths such as `locations/us` or `locations/eu` when you override the endpoint.\n\n## Core Usage\n\n### v1: transcribe a short local file\n\nUse this for the classic synchronous flow. Google documents local synchronous requests as limited to short audio, and the product docs call out a 60 second and 10 MB limit for local content.\n\n```python\nfrom google.cloud import speech\n\ndef transcribe_file(audio_file: str) -> speech.RecognizeResponse:\n    client = speech.SpeechClient()\n\n    with open(audio_file, \"rb\") as f:\n        audio_content = f.read()\n\n    audio = speech.RecognitionAudio(content=audio_content)\n    config = speech.RecognitionConfig(\n        encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,\n        sample_rate_hertz=16000,\n        language_code=\"en-US\",\n    )\n\n    response = client.recognize(config=config, audio=audio)\n\n    for result in response.results:\n        print(result.alternatives[0].transcript)\n\n    return response\n```\n\n### v1: transcribe long audio from Cloud Storage\n\nUse a long-running operation for files that exceed the short synchronous path.\n\n```python\nfrom google.cloud import speech\n\ndef transcribe_gcs(gcs_uri: str) -> speech.LongRunningRecognizeResponse:\n    client = speech.SpeechClient()\n\n    audio = speech.RecognitionAudio(uri=gcs_uri)\n    config = speech.RecognitionConfig(\n        encoding=speech.RecognitionConfig.AudioEncoding.FLAC,\n        sample_rate_hertz=44100,\n        language_code=\"en-US\",\n    )\n\n    operation = client.long_running_recognize(config=config, audio=audio)\n    response = operation.result(timeout=600)\n\n    for result in response.results:\n        print(result.alternatives[0].transcript)\n\n    return response\n```\n\n### v1: stream audio incrementally\n\nFor microphone or chunked file input, use `streaming_recognize` with a generator of `StreamingRecognizeRequest` messages.\n\n```python\nfrom google.cloud import speech\nfrom typing import Iterable\n\ndef stream_chunks(chunks: Iterable[bytes]):\n    client = speech.SpeechClient()\n    config = speech.RecognitionConfig(\n        encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,\n        sample_rate_hertz=16000,\n        language_code=\"en-US\",\n    )\n    streaming_config = speech.StreamingRecognitionConfig(config=config, interim_results=True)\n\n    def requests():\n        for chunk in chunks:\n            yield speech.StreamingRecognizeRequest(audio_content=chunk)\n\n    responses = client.streaming_recognize(\n        config=streaming_config,\n        requests=requests(),\n    )\n    for response in responses:\n        for result in response.results:\n            print(result.is_final, result.alternatives[0].transcript)\n```\n\n### v2: recognize a local file with auto-decoding\n\nThis is the cleanest v2 quickstart. The sample path uses the implicit recognizer `_`, which avoids creating a recognizer resource for one-off requests.\n\n```python\nimport os\n\nfrom google.cloud.speech_v2 import SpeechClient\nfrom google.cloud.speech_v2.types import cloud_speech\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\ndef recognize_v2(audio_file: str) -> cloud_speech.RecognizeResponse:\n    with open(audio_file, \"rb\") as f:\n        audio_content = f.read()\n\n    client = SpeechClient()\n\n    config = cloud_speech.RecognitionConfig(\n        auto_decoding_config=cloud_speech.AutoDetectDecodingConfig(),\n        language_codes=[\"en-US\"],\n        model=\"short\",\n    )\n\n    request = cloud_speech.RecognizeRequest(\n        recognizer=f\"projects/{PROJECT_ID}/locations/global/recognizers/_\",\n        config=config,\n        content=audio_content,\n    )\n\n    response = client.recognize(request=request)\n\n    for result in response.results:\n        print(result.alternatives[0].transcript)\n\n    return response\n```\n\n### v2: batch recognition for long files in Cloud Storage\n\nUse this when the audio is longer than one minute or you want asynchronous processing. Google documents v2 batch recognition as Cloud Storage based, with an upper limit of 480 minutes.\n\n```python\nimport os\n\nfrom google.cloud.speech_v2 import SpeechClient\nfrom google.cloud.speech_v2.types import cloud_speech\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n\ndef batch_recognize_v2(audio_uri: str) -> cloud_speech.BatchRecognizeResults:\n    client = SpeechClient()\n\n    config = cloud_speech.RecognitionConfig(\n        auto_decoding_config=cloud_speech.AutoDetectDecodingConfig(),\n        language_codes=[\"en-US\"],\n        model=\"long\",\n    )\n\n    request = cloud_speech.BatchRecognizeRequest(\n        recognizer=f\"projects/{PROJECT_ID}/locations/global/recognizers/_\",\n        config=config,\n        files=[cloud_speech.BatchRecognizeFileMetadata(uri=audio_uri)],\n        recognition_output_config=cloud_speech.RecognitionOutputConfig(\n            inline_response_config=cloud_speech.InlineOutputConfig(),\n        ),\n    )\n\n    operation = client.batch_recognize(request=request)\n    response = operation.result(timeout=1200)\n\n    for result in response.results[audio_uri].transcript.results:\n        print(result.alternatives[0].transcript)\n\n    return response.results[audio_uri].transcript\n```\n\n## Config And Accuracy Controls\n\n### Basic language and model selection\n\n- v1 uses `language_code=\"en-US\"` and optional `model=\"video\"` or similar model strings\n- v2 uses `language_codes=[\"en-US\"]` and model names such as `short` or `long`\n\n### Adaptation and phrase hints\n\nThe package includes adaptation clients and types for custom phrase sets and classes. Use them when domain-specific terms are being transcribed incorrectly.\n\n- v1 and v1p1beta1 expose adaptation resources and request types\n- v2 also supports phrase sets, custom classes, recognizers, and custom prompt config in the library surface\n\nStart simple before creating reusable resources:\n\n- add explicit language codes\n- choose the right model\n- use Cloud Storage for long audio instead of forcing large local payloads\n- add phrase hints or adaptation resources only after you confirm baseline accuracy is not enough\n\n## Async Usage\n\nThe library also exposes async clients:\n\n- `google.cloud.speech_v1.services.speech.SpeechAsyncClient`\n- `google.cloud.speech_v2.services.speech.SpeechAsyncClient`\n\nUse those when your application is already async and you want to avoid blocking request handlers on long-running calls.\n\n## Logging And Debugging\n\nYou can enable structured library logging without changing code:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\nUseful narrower scopes include `google.cloud.speech_v2` and `google.auth`.\n\n## Common Pitfalls\n\n- Do not assume `from google.cloud import speech` is v2. It is the classic v1 import path.\n- Do not mix v1 message classes with v2 clients. `speech.RecognitionAudio` is not valid for `speech_v2.SpeechClient`.\n- For v2, do not forget the `recognizer` field. Most examples use `projects/{project}/locations/{location}/recognizers/_`.\n- For regional endpoints, keep endpoint and resource location aligned. `us-speech.googleapis.com` should pair with `locations/us`, not `locations/global`.\n- Local synchronous transcription is for short audio only. For anything larger, move to Cloud Storage plus `long_running_recognize` or `batch_recognize`.\n- `GOOGLE_CLOUD_PROJECT` matters in v2 because recognizer resource names include the project.\n- Do not hard-code service account key files into the repo. Prefer ADC via `gcloud auth application-default login` locally and attached service accounts in production.\n- The package includes v1p1beta1. Use it only when you specifically need that surface; do not choose it by default for new code.\n\n## Version-Sensitive Notes For 2.37.0\n\n- PyPI lists `2.37.0` as the latest release, published on February 27, 2026.\n- The package still ships v1, v1p1beta1, and v2 surfaces together, so import path choice is a real compatibility decision.\n- The docs changelog page currently shows entries through `2.36.0`, so PyPI is the more reliable source for the exact latest package version.\n- The published changelog notes that `credentials_file` was deprecated in `2.34.0`. Prefer ADC or explicit `credentials=` objects instead of depending on file-path constructor arguments.\n- The published changelog for `2.35.0` notes automatic mTLS enablement when supported certificates are detected. If endpoint behavior looks unexpected in secured environments, inspect client options and the `GOOGLE_API_USE_MTLS_ENDPOINT` setting.\n- The published changelog for `2.36.0` includes speaker diarization documentation updates and new prompt-related configuration support. Re-check request fields before copying older snippets from blogs or answers written before late 2025.\n\n## Official Sources\n\n- Python reference: `https://docs.cloud.google.com/python/docs/reference/speech/latest`\n- PyPI package page: `https://pypi.org/project/google-cloud-speech/`\n- Client library quickstart and samples: `https://docs.cloud.google.com/speech-to-text/docs/quickstarts/transcribe-client-libraries`\n- v1 migration guide: `https://docs.cloud.google.com/speech-to-text/docs/migration`\n- ADC guide: `https://docs.cloud.google.com/docs/authentication/application-default-credentials`\n"
  },
  {
    "path": "content/google/docs/storage/javascript/DOC.md",
    "content": "---\nname: storage\ndescription: \"Google Cloud Storage Node.js client for working with buckets, objects, metadata, streams, and signed URLs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.19.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,cloud-storage,storage,buckets,objects,javascript,nodejs\"\n---\n\n# `@google-cloud/storage` JavaScript Package Guide\n\nUse `@google-cloud/storage` in Node.js code that needs to create buckets, upload and download objects, list files, manage metadata, stream data, or generate signed URLs for Google Cloud Storage.\n\n## Golden Rule\n\n- Use the official `@google-cloud/storage` client, not raw HTTP calls, for normal application code.\n- Prefer Application Default Credentials (ADC) unless you have a clear reason to pass credentials explicitly.\n- Think in terms of `Storage` → `Bucket` → `File` objects.\n- Use `bucket.upload()` when the source is already on disk, and `file.save()` or streams when the content already lives in memory or arrives incrementally.\n- Prefer signed URLs for temporary external access instead of making objects public.\n- Keep bucket names globally unique and treat object names as the stable key inside a bucket.\n\nThis guide covers `7.19.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/storage@7.19.0\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nIn production on Google Cloud, prefer an attached service account or workload identity over long-lived key files.\n\nMinimum setup:\n\n1. Authenticate with ADC or a service account.\n2. Set `GOOGLE_CLOUD_PROJECT` when the project is not detected automatically.\n3. Make sure the credential has the bucket and object permissions your workflow needs.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n```\n\nES modules:\n\n```javascript\nimport {Storage} from '@google-cloud/storage';\n\nconst storage = new Storage();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nReference a bucket and file once, then reuse those handles:\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\nconst bucket = storage.bucket('my-bucket');\nconst file = bucket.file('reports/2026-03-13.json');\n```\n\n## Core Workflows\n\n### Create A Bucket\n\nBucket names are globally unique across Cloud Storage.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function createBucket(bucketName) {\n  const [bucket] = await storage.createBucket(bucketName, {\n    location: 'US',\n    storageClass: 'STANDARD',\n  });\n\n  console.log(bucket.name);\n}\n\ncreateBucket('my-unique-bucket-name').catch(console.error);\n```\n\n### Upload A Local File\n\nUse `bucket.upload()` when the source file already exists on disk.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function uploadLocalFile(bucketName, localPath, destination) {\n  await storage.bucket(bucketName).upload(localPath, {\n    destination,\n  });\n}\n\nuploadLocalFile(\n  'my-bucket',\n  './invoices/march.csv',\n  'imports/2026-03/march.csv'\n).catch(console.error);\n```\n\n### Upload Text Or JSON From Memory\n\nUse `file.save()` when your app already has the content in memory.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function saveJson(bucketName, fileName, payload) {\n  await storage\n    .bucket(bucketName)\n    .file(fileName)\n    .save(JSON.stringify(payload), {\n      resumable: false,\n      metadata: {\n        contentType: 'application/json',\n      },\n    });\n}\n\nsaveJson('my-bucket', 'exports/run.json', {ok: true}).catch(console.error);\n```\n\n### Download An Object To Disk\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function downloadFile(bucketName, fileName, destination) {\n  await storage.bucket(bucketName).file(fileName).download({\n    destination,\n  });\n}\n\ndownloadFile('my-bucket', 'exports/run.json', './run.json').catch(console.error);\n```\n\n### List Objects Under A Prefix\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function listFiles(bucketName, prefix) {\n  const [files] = await storage.bucket(bucketName).getFiles({prefix});\n\n  for (const file of files) {\n    console.log(file.name);\n  }\n}\n\nlistFiles('my-bucket', 'imports/').catch(console.error);\n```\n\n### Stream Uploads And Downloads\n\nUse streams when the payload is large or already arrives as a stream.\n\n```javascript\nconst fs = require('node:fs');\nconst {pipeline} = require('node:stream/promises');\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function uploadWithStreams(bucketName, localPath, destination) {\n  await pipeline(\n    fs.createReadStream(localPath),\n    storage.bucket(bucketName).file(destination).createWriteStream()\n  );\n}\n\nasync function downloadWithStreams(bucketName, fileName, localPath) {\n  await pipeline(\n    storage.bucket(bucketName).file(fileName).createReadStream(),\n    fs.createWriteStream(localPath)\n  );\n}\n```\n\n### Read And Update Metadata\n\nUse `getMetadata()` to inspect the object and `setMetadata()` to update fields such as cache control or custom metadata.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function updateMetadata(bucketName, fileName) {\n  const file = storage.bucket(bucketName).file(fileName);\n\n  const [before] = await file.getMetadata();\n  console.log(before.contentType);\n\n  await file.setMetadata({\n    cacheControl: 'public, max-age=3600',\n    metadata: {\n      source: 'api',\n      jobId: 'job-1234',\n    },\n  });\n}\n\nupdateMetadata('my-bucket', 'assets/logo.png').catch(console.error);\n```\n\n### Copy, Rename, And Delete Objects\n\nUse `copy()` to duplicate an object, `move()` to rename it, and `delete()` to remove it.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function reorganizeObject(bucketName) {\n  const bucket = storage.bucket(bucketName);\n  const source = bucket.file('incoming/report.csv');\n\n  await source.copy(bucket.file('archive/report.csv'));\n  await source.move('processed/report.csv');\n  await bucket.file('processed/old-report.csv').delete();\n}\n\nreorganizeObject('my-bucket').catch(console.error);\n```\n\n### Generate A V4 Signed URL\n\nUse signed URLs when another client should read or upload a specific object without using your server credentials directly.\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function generateReadUrl(bucketName, fileName) {\n  const [url] = await storage.bucket(bucketName).file(fileName).getSignedUrl({\n    version: 'v4',\n    action: 'read',\n    expires: Date.now() + 15 * 60 * 1000,\n  });\n\n  console.log(url);\n}\n\ngenerateReadUrl('my-bucket', 'exports/run.json').catch(console.error);\n```\n\n## Practical Notes\n\n- `new Storage()` usually works when ADC is configured; pass `projectId` explicitly when project detection is ambiguous.\n- `bucket.upload()` is the simplest path for local files, but streams are a better fit for request bodies, large files, and background pipelines.\n- `file.save()` is convenient for smaller strings and buffers that you already have in memory.\n- Signed URL generation depends on credentials that can sign requests; service-account based credentials are the straightforward choice for server-side signing.\n- Prefer IAM and signed URLs over object ACL-style sharing patterns in new code.\n\n## Minimal End-To-End Example\n\n```javascript\nconst {Storage} = require('@google-cloud/storage');\n\nconst storage = new Storage();\n\nasync function main() {\n  const bucket = storage.bucket(process.env.BUCKET_NAME);\n\n  await bucket.file('hello.txt').save('hello world\\n', {\n    resumable: false,\n  });\n\n  const [files] = await bucket.getFiles({prefix: 'hello'});\n  for (const file of files) {\n    console.log(file.name);\n  }\n\n  const [url] = await bucket.file('hello.txt').getSignedUrl({\n    version: 'v4',\n    action: 'read',\n    expires: Date.now() + 5 * 60 * 1000,\n  });\n\n  console.log(url);\n}\n\nmain().catch(console.error);\n```\n"
  },
  {
    "path": "content/google/docs/storage/python/DOC.md",
    "content": "---\nname: storage\ndescription: \"Google Cloud Storage Python client library for buckets, blobs, transfers, and signed URLs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,cloud,storage,gcs,bucket,blob,signed-url\"\n---\n\n# Google Cloud Storage Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-storage` package with `from google.cloud import storage`, and prefer Application Default Credentials (ADC) for normal client setup. For write paths, add generation preconditions such as `if_generation_match=0` so retries stay safe and idempotent.\n\nThis package covers the main Cloud Storage Python client. Some newer control-plane features live in adjacent Google Cloud packages and product docs, so do not assume every Storage feature lands in `google-cloud-storage`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"google-cloud-storage==3.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-storage==3.9.0\"\npoetry add \"google-cloud-storage==3.9.0\"\n```\n\nUseful extras from PyPI:\n\n```bash\npython -m pip install \"google-cloud-storage[tracing]==3.9.0\"\npython -m pip install \"google-cloud-storage[grpc]==3.9.0\"\n```\n\nUse `tracing` when you want OpenTelemetry integration. Use `grpc` only when you actually need the gRPC-based async/client surfaces documented in the upstream changelog.\n\n## Authentication And Setup\n\nEnable the Cloud Storage API in the target Google Cloud project, then choose one of the standard auth flows.\n\n### Local development with ADC\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\n```\n\n### Service account credentials\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\n```\n\n### Explicit credentials object\n\n```python\nfrom google.cloud import storage\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\n\nclient = storage.Client(\n    project=\"YOUR_PROJECT_ID\",\n    credentials=credentials,\n)\n```\n\n### API key support\n\n`storage.Client` accepts `api_key=...`, but that is not the normal path for authenticated bucket and object management. Treat ADC or service-account credentials as the default for production code, and do not mix `api_key` with `credentials`.\n\n## Core Workflow\n\n### Create a client, bucket, and blob handle\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"reports/summary.json\")\n```\n\nCreating a bucket:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-new-bucket\")\nbucket.storage_class = \"STANDARD\"\nnew_bucket = client.create_bucket(bucket, location=\"US\")\n\nprint(new_bucket.name)\n```\n\n### Upload data\n\nSimple string upload:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"notes/hello.txt\")\n\nblob.upload_from_string(\"hello world\", content_type=\"text/plain\")\n```\n\nCreate-only upload with a generation precondition:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"uploads/report.csv\")\n\nblob.upload_from_filename(\n    \"report.csv\",\n    if_generation_match=0,\n    checksum=\"auto\",\n)\n```\n\nUse `if_generation_match=0` when the object must not already exist. That enables conditional retry behavior and prevents duplicate writes during retried uploads.\n\n### Download data\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"uploads/report.csv\")\n\ntext = blob.download_as_text()\ndata = blob.download_as_bytes()\nblob.download_to_filename(\"report.csv\")\n```\n\n### List objects\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\n\nfor blob in client.list_blobs(\"my-bucket\", prefix=\"uploads/2026/\"):\n    print(blob.name, blob.size)\n```\n\nPseudo-directory style listing:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\niterator = client.list_blobs(\n    \"my-bucket\",\n    prefix=\"uploads/\",\n    delimiter=\"/\",\n)\n\nfor page in iterator.pages:\n    for subdir in page.prefixes:\n        print(\"prefix:\", subdir)\n    for blob in page:\n        print(\"blob:\", blob.name)\n```\n\n### Delete or replace safely\n\nIf you need optimistic concurrency, reload the blob first and pass a generation precondition:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"uploads/report.csv\")\nblob.reload()\n\nblob.delete(if_generation_match=blob.generation)\n```\n\nThe same pattern applies to overwrite flows: read the current generation, then write with `if_generation_match=<current_generation>`.\n\n## Signed URLs\n\nGenerate a short-lived V4 signed URL for downloads:\n\n```python\nfrom datetime import timedelta\n\nfrom google.cloud import storage\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\nblob = bucket.blob(\"private/report.csv\")\n\nurl = blob.generate_signed_url(\n    version=\"v4\",\n    expiration=timedelta(minutes=15),\n    method=\"GET\",\n)\n\nprint(url)\n```\n\nPractical caveats:\n\n- Signed URLs target Cloud Storage XML API style endpoints, even when the rest of your app uses the JSON API or the Python client library.\n- URL signing needs signing-capable credentials. Many default runtime credentials can access Storage but cannot sign URLs directly.\n\n## Parallel Transfers\n\nFor bulk uploads or downloads, use `transfer_manager` instead of writing your own thread/process orchestration:\n\n```python\nfrom pathlib import Path\n\nfrom google.cloud import storage\nfrom google.cloud.storage import transfer_manager\n\nclient = storage.Client(project=\"YOUR_PROJECT_ID\")\nbucket = client.bucket(\"my-bucket\")\n\nresults = transfer_manager.upload_many_from_filenames(\n    bucket,\n    [str(path) for path in Path(\"dist\").glob(\"*.json\")],\n    source_directory=\".\",\n    blob_name_prefix=\"artifacts/\",\n    max_workers=8,\n)\n\nfor result in results:\n    if isinstance(result, Exception):\n        raise result\n```\n\nUse this for many medium-sized files. For a single large file, a resumable upload through `upload_from_filename()` is usually enough.\n\n## Custom Endpoints And Tests\n\nIf you point the client at a custom endpoint for tests or local emulation, be explicit about auth behavior:\n\n```python\nfrom google.cloud import storage\n\nclient = storage.Client(\n    project=\"test-project\",\n    client_options={\"api_endpoint\": \"http://localhost:4443\"},\n    use_auth_w_custom_endpoint=False,\n)\n```\n\nWithout `use_auth_w_custom_endpoint=False`, the client still assumes authentication on custom endpoints.\n\n## Configuration Notes\n\n- Set `project=` explicitly when your local ADC context and the target billing project are not the same.\n- For Requester Pays buckets, set `bucket.user_project = \"BILLING_PROJECT_ID\"` before the operation so the request is billed correctly.\n- Keep credentials out of source control. Use ADC locally and secret-managed service account credentials in CI or production.\n- Prefer `checksum=\"auto\"` unless you have a specific reason to disable checksums.\n\n## Common Pitfalls\n\n- Do not omit generation preconditions on important writes. Retrying a non-conditional upload can create correctness bugs.\n- `download_as_text()` decodes content; use `download_as_bytes()` for binary data.\n- Range downloads do not support checksum verification in the same way full-object downloads do. Validate integrity at the application layer if partial reads matter.\n- `api_key` and `credentials` are mutually exclusive on `storage.Client`.\n- Signed URL support and Storage data access are different capabilities. A credential that can read or write objects may still fail to sign.\n- Some \"folder\", managed-folder, or storage-control features are documented elsewhere in Google Cloud and may require a different client package.\n- Custom endpoints still try to authenticate unless you disable that behavior explicitly.\n\n## Version-Sensitive Notes For 3.9.0\n\n- PyPI and the latest reference docs both pointed to `3.9.0` on March 12, 2026.\n- The `3.x` line changed several behaviors compared with `2.x`, especially around retries, checksum defaults, exception classes, and some upload/download edge cases. If you are migrating old code, read the changelog before assuming old retry or exception behavior still applies.\n- In `3.x`, uploads and downloads moved toward safer defaults: checksum handling now defaults to `auto`, and conditional retry support matters more for safe writes.\n- `3.1.0` added `api_key` support to `storage.Client`; if you see older examples claiming the client only accepts OAuth-style credentials, those examples are outdated.\n- The `3.9.0` changelog includes async gRPC and zonal-bucket related additions. Those are advanced surfaces; standard sync `Client` / `Bucket` / `Blob` code remains the baseline for most agents.\n\n## Official Sources\n\n- Python reference root: `https://docs.cloud.google.com/python/docs/reference/storage/latest`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/storage/latest/changelog`\n- Client API: `https://docs.cloud.google.com/python/docs/reference/storage/latest/google.cloud.storage.client.Client`\n- Blob API: `https://docs.cloud.google.com/python/docs/reference/storage/latest/google.cloud.storage.blob.Blob`\n- Transfer manager API: `https://docs.cloud.google.com/python/docs/reference/storage/latest/google.cloud.storage.transfer_manager`\n- Authentication guide: `https://docs.cloud.google.com/storage/docs/authentication`\n- Request preconditions guide: `https://docs.cloud.google.com/storage/docs/request-preconditions`\n- Signed URLs guide: `https://docs.cloud.google.com/storage/docs/access-control/signed-urls`\n- PyPI package page: `https://pypi.org/project/google-cloud-storage/`\n- GitHub repository: `https://github.com/googleapis/python-storage`\n"
  },
  {
    "path": "content/google/docs/talent/javascript/DOC.md",
    "content": "---\nname: talent\ndescription: \"Google Cloud Talent Solution Node.js client for companies, jobs, search, and query completion\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,talent,jobs,recruiting,search,javascript\"\n---\n\n# Google Cloud Talent Solution Node.js Client\n\n## Golden Rule\n\nUse `@google-cloud/talent` with Application Default Credentials (ADC), enable `jobs.googleapis.com` in the Google Cloud project that owns your Talent Solution resources, and use the GA `v4` client surface unless you have a documented reason to target a different namespace.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/talent@7.1.1\n```\n\n## Authentication And Project Setup\n\nBefore making API calls, make sure all of the following are true:\n\n1. You have a Google Cloud project.\n2. Billing is enabled for that project.\n3. Cloud Talent Solution is enabled for that project.\n4. ADC is configured for the identity your app runs as.\n\nEnable the API:\n\n```bash\ngcloud services enable jobs.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development, the normal ADC flow is:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\nexport TALENT_TENANT_ID=\"your-tenant-id\"\n```\n\nIf you must use a service account key outside Google Cloud:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\nexport TALENT_TENANT_ID=\"your-tenant-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account instead of distributing key files.\n\n## Initialize Clients\n\nThe package exposes versioned namespaces. For the current GA surface:\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst companyClient = new v4.CompanyServiceClient();\nconst jobClient = new v4.JobServiceClient();\nconst completionClient = new v4.CompletionClient();\n```\n\nIf you need to pass project or key settings explicitly:\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst clientOptions = {\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n};\n\nconst companyClient = new v4.CompanyServiceClient(clientOptions);\nconst jobClient = new v4.JobServiceClient(clientOptions);\n```\n\nCreate clients once and reuse them across requests.\n\n## Resource Names You Reuse Constantly\n\nCloud Talent Solution request bodies often need fully qualified resource names, not just your own IDs.\n\nThe most common parent forms are:\n\n- Project-scoped parent: `projects/PROJECT_ID`\n- Tenant-scoped parent: `projects/PROJECT_ID/tenants/TENANT_ID`\n\nThe examples below use a tenant-scoped parent because it is the safer default for multi-tenant integrations:\n\n```javascript\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT;\nconst tenantId = process.env.TALENT_TENANT_ID;\n\nconst parent = `projects/${projectId}/tenants/${tenantId}`;\n```\n\nWhen the API returns a resource `name`, persist and reuse that value instead of rebuilding it by hand.\n\n## Create A Company\n\nCreate the employer record first, then reference that returned company name when you create jobs:\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst companyClient = new v4.CompanyServiceClient();\n\nasync function createCompany() {\n  const parent = `projects/${process.env.GOOGLE_CLOUD_PROJECT}/tenants/${process.env.TALENT_TENANT_ID}`;\n\n  const [company] = await companyClient.createCompany({\n    parent,\n    company: {\n      displayName: 'Example, Inc.',\n      externalId: 'example-inc',\n      headquartersAddress: '1600 Amphitheatre Parkway, Mountain View, CA 94043',\n      careerSiteUri: 'https://example.com/careers',\n    },\n  });\n\n  console.log(company.name);\n  return company.name;\n}\n\ncreateCompany().catch(console.error);\n```\n\nUse your own stable `externalId` so you can map the Talent Solution company back to your internal system.\n\n## Create A Job\n\nJobs reference the full company resource name returned by `createCompany`:\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst jobClient = new v4.JobServiceClient();\n\nasync function createJob(companyName) {\n  const parent = `projects/${process.env.GOOGLE_CLOUD_PROJECT}/tenants/${process.env.TALENT_TENANT_ID}`;\n\n  const [job] = await jobClient.createJob({\n    parent,\n    job: {\n      company: companyName,\n      requisitionId: 'req-1001',\n      title: 'Senior Software Engineer',\n      description: 'Build search and matching features for recruiting workflows.',\n      addresses: ['New York, NY'],\n      languageCode: 'en-US',\n      applicationInfo: {\n        uris: ['https://example.com/jobs/req-1001'],\n      },\n    },\n  });\n\n  console.log(job.name);\n  return job;\n}\n```\n\nKeep `requisitionId` stable on your side. That is usually the simplest way to reconcile jobs between Talent Solution and your own database.\n\n## Search Jobs\n\n`searchJobs()` is the main retrieval API. Include `requestMetadata` on every search request so Talent Solution can attribute the request correctly.\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst jobClient = new v4.JobServiceClient();\n\nasync function searchJobs() {\n  const parent = `projects/${process.env.GOOGLE_CLOUD_PROJECT}/tenants/${process.env.TALENT_TENANT_ID}`;\n\n  const [response] = await jobClient.searchJobs({\n    parent,\n    requestMetadata: {\n      domain: 'jobs.example.com',\n      sessionId: 'session-123',\n      userId: 'user-42',\n    },\n    searchMode: 'JOB_SEARCH',\n    enableBroadening: true,\n    jobQuery: {\n      query: 'software engineer',\n      locationFilters: [\n        {\n          address: 'New York, NY',\n        },\n      ],\n    },\n    pageSize: 10,\n  });\n\n  for (const match of response.matchingJobs ?? []) {\n    console.log(match.job?.name, match.job?.title);\n  }\n}\n\nsearchJobs().catch(console.error);\n```\n\nUse stable identifiers in `requestMetadata` from your own app instead of random placeholders in production traffic.\n\n## Query Completion\n\nUse `completeQuery()` for typeahead suggestions in your job search UI:\n\n```javascript\nconst {v4} = require('@google-cloud/talent');\n\nconst completionClient = new v4.CompletionClient();\n\nasync function completeQuery() {\n  const parent = `projects/${process.env.GOOGLE_CLOUD_PROJECT}/tenants/${process.env.TALENT_TENANT_ID}`;\n\n  const [response] = await completionClient.completeQuery({\n    parent,\n    query: 'softw',\n    languageCodes: ['en-US'],\n    pageSize: 5,\n  });\n\n  for (const result of response.completionResults ?? []) {\n    console.log(result.suggestion);\n  }\n}\n\ncompleteQuery().catch(console.error);\n```\n\n## Common Pitfalls\n\n- Do not use API keys for this library. Use ADC, user credentials, or a service account.\n- Pass full resource names such as `projects/.../tenants/.../companies/...`, not just your internal IDs.\n- Reuse returned `name` fields from API responses instead of reconstructing them.\n- Always send `requestMetadata` with `searchJobs()`; it is part of the normal search request shape.\n- Reuse client instances instead of creating a new gRPC client for every request.\n\n## Useful Links\n\n- Node.js reference: `https://cloud.google.com/nodejs/docs/reference/talent/latest`\n- Package page: `https://www.npmjs.com/package/@google-cloud/talent`\n- ADC overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Local ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n"
  },
  {
    "path": "content/google/docs/tasks/javascript/DOC.md",
    "content": "---\nname: tasks\ndescription: \"Google Cloud Tasks Node.js client library for creating and managing HTTP and App Engine tasks\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,cloud-tasks,queues,jobs,http\"\n---\n\n# Google Cloud Tasks Node.js Client\n\n## Golden Rule\n\nUse `@google-cloud/tasks` with Application Default Credentials (ADC) unless you have a strong reason to construct credentials manually. For real integrations, treat queue location, IAM, and request authentication as part of the API contract, not as afterthoughts.\n\nThis guide targets `@google-cloud/tasks` version `6.2.1`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\nnpm install @google-cloud/tasks@6.2.1\n```\n\nCommon alternatives:\n\n```bash\npnpm add @google-cloud/tasks@6.2.1\nyarn add @google-cloud/tasks@6.2.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key. For local development, the standard path is:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nIf the queue does not exist yet, create it before you enqueue work:\n\n```bash\ngcloud tasks queues create default --location=us-central1\n```\n\nIf you must use a service account key file locally, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account and let ADC resolve credentials automatically.\n\nMinimal IAM to enqueue authenticated HTTP tasks is usually:\n\n- `roles/cloudtasks.enqueuer` on the queue or project for the caller creating tasks\n- `roles/iam.serviceAccountUser` on the service account attached to the task when you use `oidcToken` or `oauthToken`\n- A target-service role on the receiving service, such as Cloud Run invocation permission, for the service account that will sign the outbound token\n\nQueue administration uses broader roles such as `roles/cloudtasks.queueAdmin` or `roles/cloudtasks.admin`.\n\n## Initialize The Client\n\nMost code only needs a default client:\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nconst client = new v2.CloudTasksClient();\nconst queueName = client.queuePath('my-project', 'us-central1', 'default');\n```\n\nWith an explicit key file:\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nconst client = new v2.CloudTasksClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf ADC is already configured, you usually do not need `keyFilename`. The generated client also accepts options such as `apiEndpoint` when you need a non-default endpoint or explicit transport behavior.\n\n## Create A Basic HTTP Task\n\nThis is the common pattern for pushing JSON work to an HTTP handler:\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nasync function enqueueHttpJsonTask({\n  projectId,\n  location,\n  queueId,\n  url,\n  payload,\n  delaySeconds = 0,\n}) {\n  const client = new v2.CloudTasksClient();\n  const parent = client.queuePath(projectId, location, queueId);\n\n  const task = {\n    httpRequest: {\n      httpMethod: 'POST',\n      url,\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: Buffer.from(JSON.stringify(payload)).toString('base64'),\n    },\n  };\n\n  if (delaySeconds > 0) {\n    task.scheduleTime = {\n      seconds: Math.floor(Date.now() / 1000) + delaySeconds,\n    };\n  }\n\n  const [response] = await client.createTask({parent, task});\n  return response.name;\n}\n\nenqueueHttpJsonTask({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  location: 'us-central1',\n  queueId: 'default',\n  url: 'https://example.com/tasks/process',\n  payload: {jobId: 'job-123', action: 'sync'},\n  delaySeconds: 30,\n}).catch(console.error);\n```\n\n`httpRequest.body` is a bytes field, so encode JSON or text payloads before sending them. Use an explicit `task.name` only when you need deduplication or idempotency:\n\n```javascript\ntask.name = client.taskPath(projectId, location, queueId, 'job-123');\n```\n\nExplicit task IDs add an extra lookup and should not use sequential prefixes such as timestamps or incrementing integers.\n\n## Create An Authenticated HTTP Task\n\nFor Cloud Run, Cloud Functions, or your own HTTPS handler protected by IAM, attach an OIDC token:\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nasync function enqueueOidcTask({\n  projectId,\n  location,\n  queueId,\n  url,\n  serviceAccountEmail,\n  payload,\n}) {\n  const client = new v2.CloudTasksClient();\n  const parent = client.queuePath(projectId, location, queueId);\n\n  const task = {\n    httpRequest: {\n      httpMethod: 'POST',\n      url,\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: Buffer.from(JSON.stringify(payload)).toString('base64'),\n      oidcToken: {\n        serviceAccountEmail,\n        audience: url,\n      },\n    },\n  };\n\n  const [response] = await client.createTask({parent, task});\n  return response.name;\n}\n```\n\nUse `oidcToken` for handlers that validate Google-signed ID tokens. Use `oauthToken` only when the target expects an OAuth access token for Google APIs such as `*.googleapis.com`.\n\n## App Engine Tasks\n\nUse `appEngineHttpRequest` only when the target really is an App Engine service. For Cloud Run or arbitrary HTTPS endpoints, use `httpRequest`.\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nasync function enqueueAppEngineTask() {\n  const client = new v2.CloudTasksClient();\n  const parent = client.queuePath('my-project', 'us-central1', 'default');\n\n  const task = {\n    appEngineHttpRequest: {\n      httpMethod: 'POST',\n      relativeUri: '/tasks/process',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: Buffer.from(JSON.stringify({job: 'sync'})).toString('base64'),\n    },\n  };\n\n  const [response] = await client.createTask({parent, task});\n  return response.name;\n}\n```\n\n## Inspect And Manage Queues\n\nQueue operations you will use most often:\n\n```javascript\nconst {v2} = require('@google-cloud/tasks');\n\nasync function inspectQueue() {\n  const client = new v2.CloudTasksClient();\n  const queueName = client.queuePath('my-project', 'us-central1', 'default');\n\n  const [queue] = await client.getQueue({name: queueName});\n  console.log(queue.rateLimits);\n\n  const [tasks] = await client.listTasks({\n    parent: queueName,\n    responseView: 'FULL',\n  });\n\n  for (const task of tasks) {\n    console.log(task.name, task.scheduleTime);\n  }\n\n  await client.pauseQueue({name: queueName});\n  await client.resumeQueue({name: queueName});\n}\n```\n\nUseful methods on `CloudTasksClient` include:\n\n- `createQueue`, `getQueue`, `listQueues`, `updateQueue`\n- `pauseQueue`, `resumeQueue`, `purgeQueue`, `deleteQueue`\n- `createTask`, `getTask`, `listTasks`, `deleteTask`, `runTask`\n\n`runTask` is for manual execution or debugging of a task now. It is not a replacement for normal dispatch configuration.\n\n## Configuration Notes\n\n- Queue names are regional. The path is always `projects/{project}/locations/{location}/queues/{queue}`.\n- Create the queue before enqueuing work. `createTask()` does not auto-create missing queues.\n- Queue-level throttling and retry behavior live on the queue, not on the individual `createTask()` call.\n- Task payload size is capped at `100KB`.\n- If you need to inspect task payloads or headers, request `responseView: 'FULL'`; the default view is lighter.\n- For JSON or text bodies, base64-encode the payload before assigning `httpRequest.body` or `appEngineHttpRequest.body`.\n\n## Common Pitfalls\n\n- Do not confuse Cloud Tasks with Pub/Sub. Cloud Tasks is for controlled dispatch to a specific handler with per-queue retry and rate settings.\n- Do not omit the location when building queue paths. Region mismatch is a common cause of `NOT_FOUND`.\n- If you use `oidcToken` or `oauthToken`, the caller creating the task needs permission to act as the signing service account, and the target service must also trust that account.\n- Do not use `appEngineHttpRequest` for Cloud Run or arbitrary HTTPS endpoints.\n- `purgeQueue()` is destructive and can take time to propagate. Use it only on an isolated queue.\n- Avoid sequential explicit task IDs. Cloud Tasks expects IDs to be distributed well enough to avoid hot spots.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/tasks` version `6.2.1`.\n- Keep the `v2.CloudTasksClient` namespace and JavaScript `camelCase` request fields shown here for current code.\n- If your project pins a materially different package version, verify helper names and request shapes against the installed package and the matching reference pages.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/tasks/latest`\n- Cloud Tasks product docs: `https://cloud.google.com/tasks/docs`\n- Create HTTP target tasks guide: `https://cloud.google.com/tasks/docs/creating-http-target-tasks`\n- Application Default Credentials setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- IAM roles for Cloud Tasks: `https://cloud.google.com/iam/docs/roles-permissions/cloudtasks`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/tasks`\n"
  },
  {
    "path": "content/google/docs/tasks/python/DOC.md",
    "content": "---\nname: tasks\ndescription: \"Google Cloud Tasks Python client library for creating and managing HTTP and App Engine tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.21.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,cloud-tasks,queues,async,jobs,http\"\n---\n\n# Google Cloud Tasks Python Client\n\n## Golden Rule\n\nUse `google-cloud-tasks` for Python and authenticate with Application Default Credentials (ADC) unless you have a strong reason to construct credentials manually. For application handlers, treat queue location, IAM, and request authentication as part of the API contract, not deployment details.\n\nAs of March 12, 2026, PyPI lists `google-cloud-tasks 2.21.0`, which matches the version used here for this session.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-tasks==2.21.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-tasks==2.21.0\"\npoetry add \"google-cloud-tasks==2.21.0\"\n```\n\n## Authentication And Setup\n\nCloud Tasks client libraries are meant to run with Google Cloud credentials, not anonymous requests. For local development, the standard path is:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nIf you must use a service account key file locally, point ADC at it:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nMinimal IAM to enqueue HTTP tasks is usually:\n\n- `roles/cloudtasks.enqueuer` on the queue or project for the caller creating tasks\n- `roles/iam.serviceAccountUser` on the service account attached to the task when you use `oidc_token` or `oauth_token`\n- A target-service role on the receiving service, such as Cloud Run invocation permission, for the service account that will sign the outbound token\n\nQueue administration uses broader roles such as `roles/cloudtasks.queueAdmin` or `roles/cloudtasks.admin`.\n\n## Initialize The Client\n\nMost code only needs a default client:\n\n```python\nfrom google.cloud import tasks_v2\n\nclient = tasks_v2.CloudTasksClient()\nqueue_name = client.queue_path(\"my-project\", \"us-central1\", \"default\")\n```\n\nFor async code:\n\n```python\nfrom google.cloud import tasks_v2\n\nclient = tasks_v2.CloudTasksAsyncClient()\nqueue_name = client.queue_path(\"my-project\", \"us-central1\", \"default\")\n```\n\nIf you need explicit credentials instead of ADC:\n\n```python\nfrom google.cloud import tasks_v2\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\nclient = tasks_v2.CloudTasksClient(credentials=credentials)\n```\n\nThe generated client also supports `client_options`, including explicit `api_endpoint`, if you need non-default endpoint or mTLS behavior.\n\n## Create A Basic HTTP Task\n\nThis is the common pattern for pushing JSON work to an HTTP handler:\n\n```python\nimport datetime\nimport json\n\nfrom google.cloud import tasks_v2\nfrom google.protobuf import timestamp_pb2\n\ndef enqueue_http_json_task(\n    project_id: str,\n    location: str,\n    queue_id: str,\n    url: str,\n    payload: dict,\n) -> str:\n    client = tasks_v2.CloudTasksClient()\n    parent = client.queue_path(project_id, location, queue_id)\n\n    task = tasks_v2.Task(\n        http_request=tasks_v2.HttpRequest(\n            http_method=tasks_v2.HttpMethod.POST,\n            url=url,\n            headers={\"Content-Type\": \"application/json\"},\n            body=json.dumps(payload).encode(),\n        )\n    )\n\n    schedule_time = timestamp_pb2.Timestamp()\n    schedule_time.FromDatetime(\n        datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=30)\n    )\n    task.schedule_time = schedule_time\n\n    response = client.create_task(\n        request={\"parent\": parent, \"task\": task}\n    )\n    return response.name\n```\n\nUse an explicit `task.name` only when you need deduplication or idempotency. The API docs note that explicit task IDs introduce an extra lookup, can increase latency, and sequential prefixes increase storage hot-spotting. If a task with the same ID was recently deleted or executed, deduplication may still reject the create request.\n\n## Create An Authenticated HTTP Task\n\nFor Cloud Run, Cloud Functions, or your own HTTPS handler protected by IAM, attach an OIDC token:\n\n```python\nimport json\n\nfrom google.cloud import tasks_v2\n\ndef enqueue_oidc_task(\n    project_id: str,\n    location: str,\n    queue_id: str,\n    url: str,\n    service_account_email: str,\n    payload: dict,\n) -> str:\n    client = tasks_v2.CloudTasksClient()\n    parent = client.queue_path(project_id, location, queue_id)\n\n    task = tasks_v2.Task(\n        http_request=tasks_v2.HttpRequest(\n            http_method=tasks_v2.HttpMethod.POST,\n            url=url,\n            headers={\"Content-Type\": \"application/json\"},\n            body=json.dumps(payload).encode(),\n            oidc_token=tasks_v2.OidcToken(\n                service_account_email=service_account_email,\n                audience=url,\n            ),\n        )\n    )\n\n    response = client.create_task(request={\"parent\": parent, \"task\": task})\n    return response.name\n```\n\nUse `oidc_token` for handlers that validate Google-signed ID tokens. Use `oauth_token` only when the target expects an OAuth access token for Google APIs such as `*.googleapis.com`.\n\n## App Engine Tasks\n\nCloud Tasks also supports App Engine targets through `app_engine_http_request`. Prefer that field only when the target really is an App Engine service. For Cloud Run or arbitrary HTTPS endpoints, use `http_request`.\n\n```python\nfrom google.cloud import tasks_v2\n\nclient = tasks_v2.CloudTasksClient()\nparent = client.queue_path(\"my-project\", \"us-central1\", \"default\")\n\ntask = tasks_v2.Task(\n    app_engine_http_request=tasks_v2.AppEngineHttpRequest(\n        http_method=tasks_v2.HttpMethod.POST,\n        relative_uri=\"/tasks/process\",\n        body=b'{\\\"job\\\": \\\"sync\\\"}',\n        headers={\"Content-Type\": \"application/json\"},\n    )\n)\n\nresponse = client.create_task(request={\"parent\": parent, \"task\": task})\n```\n\n## Inspect And Manage Queues\n\nQueue operations you will use most often:\n\n```python\nfrom google.cloud import tasks_v2\n\nclient = tasks_v2.CloudTasksClient()\nqueue_name = client.queue_path(\"my-project\", \"us-central1\", \"default\")\n\nqueue = client.get_queue(name=queue_name)\nprint(queue.rate_limits)\n\nfor task in client.list_tasks(\n    request={\"parent\": queue_name, \"response_view\": tasks_v2.Task.View.FULL}\n):\n    print(task.name, task.schedule_time)\n\nclient.pause_queue(name=queue_name)\nclient.resume_queue(name=queue_name)\nclient.purge_queue(name=queue_name)\n```\n\nUseful methods on `CloudTasksClient` include:\n\n- `create_queue`, `get_queue`, `list_queues`, `update_queue`\n- `pause_queue`, `resume_queue`, `purge_queue`, `delete_queue`\n- `create_task`, `get_task`, `list_tasks`, `delete_task`, `run_task`\n\n`run_task` is for manual execution/testing of a task now. It is not a replacement for normal dispatch configuration.\n\n## Configuration Notes\n\n- Queue names are regional. The path is always `projects/{project}/locations/{location}/queues/{queue}`.\n- Create the queue before enqueuing work. `create_task` does not auto-create missing queues.\n- Queue-level throttling and retry behavior live on the queue, not the individual `create_task` call.\n- Task payload size is capped at `100KB`.\n- Queue creation docs note that tasks can live in a queue for up to `31 days`, so Cloud Tasks is not a long-term durable archive.\n- If you need to inspect task payloads or headers, request `response_view=FULL`; the default view is lighter.\n\n## Common Pitfalls\n\n- Do not confuse Cloud Tasks with Pub/Sub. Cloud Tasks is for controlled dispatch to a specific handler with per-queue retry and rate settings.\n- Do not omit the location when building queue paths. Region mismatch is a common cause of `NOT_FOUND`.\n- If you use OIDC or OAuth tokens, the caller creating the task needs permission to act as the signing service account, and the target service must also trust that account.\n- `purge_queue` is destructive and takes time to propagate. Do not call it in tests unless the queue is isolated.\n- `delete_queue` is also slow to clear fully. The Python client reference says deletion can take up to `7 days`, and a queue with the same name cannot be recreated until deletion finishes.\n- The Python library does not cover every REST surface. The product docs explicitly call out `BufferTask` as not supported in client libraries, so use the REST API directly if you need that endpoint.\n- There is no \"update task\" workflow for mutating an existing enqueued task. In practice you usually create a replacement task and delete the old one if it has not executed yet.\n- Avoid sequential explicit task IDs such as timestamps or incrementing integers. The client reference warns they can increase latency and error rates because the backend expects roughly uniform distribution.\n\n## Version-Sensitive Notes\n\n- `2.21.0` is the current PyPI release for this package as of March 12, 2026.\n- The upstream changelog for `2.21.0` notes automatic mTLS enablement when supported client certificates are detected. If your environment has unexpected client certs, pin `client_options` or your Google API mTLS environment variables deliberately instead of relying on defaults.\n- The changelog for `2.20.0` deprecated the generated `credentials_file` constructor argument. Prefer ADC, `credentials=...`, or explicit `service_account.Credentials.from_service_account_file(...)`.\n- The generated reference pages still contain some stale-looking older version labels in page chrome. Use PyPI as the source of truth for the published package version and use the reference docs for API surface and examples.\n\n## Official Sources Used For This Doc\n\n- PyPI package page: `https://pypi.org/project/google-cloud-tasks/`\n- Python reference root: `https://docs.cloud.google.com/python/docs/reference/cloudtasks/latest`\n- CloudTasksClient reference: `https://docs.cloud.google.com/python/docs/reference/cloudtasks/latest/google.cloud.tasks_v2.services.cloud_tasks.CloudTasksClient`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/cloudtasks/latest/changelog`\n- Create HTTP target tasks guide: `https://cloud.google.com/tasks/docs/creating-http-target-tasks`\n- ADC local development guide: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- IAM roles for Cloud Tasks: `https://cloud.google.com/iam/docs/roles-permissions/cloudtasks`\n"
  },
  {
    "path": "content/google/docs/tpu/python/DOC.md",
    "content": "---\nname: tpu\ndescription: \"Google Cloud TPU Python client for provisioning TPU nodes, queued resources, accelerator discovery, and node lifecycle operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.25.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,cloud,tpu,gcp,python,ml,infrastructure,queued-resources\"\n---\n\n# Google Cloud TPU Python Client\n\n## What This Package Is\n\n`google-cloud-tpu` is the Python client for the Cloud TPU control plane. Use it to discover available TPU configurations, create and delete TPU nodes, inspect node state, and work with queued resources.\n\nThis package does not train or run JAX, PyTorch, or TensorFlow workloads by itself. It provisions Cloud TPU resources; your framework code runs on the TPU VM after the resource exists.\n\nUse the v2 client for new code:\n\n```python\nfrom google.cloud import tpu_v2\n```\n\nThe package also still ships `tpu_v1` and `tpu_v2alpha1`. Keep `tpu_v1` only for older code that still depends on its API shapes.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-tpu==1.25.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-tpu==1.25.0\"\npoetry add \"google-cloud-tpu==1.25.0\"\n```\n\nPyPI currently lists Python `>=3.7` for `1.25.0`.\n\n## Prerequisites\n\nBefore calling this library, Google’s Cloud TPU setup guide requires you to:\n\n- enable billing on the project\n- enable the Cloud TPU API: `tpu.googleapis.com`\n- have quota in the zone where you want to create TPUs\n- use credentials with the required TPU permissions\n\nMinimal setup with `gcloud`:\n\n```bash\ngcloud services enable tpu.googleapis.com\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\nFor automation outside a Google Cloud runtime:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\nexport GOOGLE_CLOUD_ZONE=\"us-central1-a\"\n```\n\nImportant scope note:\n\n- This client is for the Cloud TPU API.\n- Google’s current TPU product docs note that Ironwood / TPU7x uses GKE instead of the Cloud TPU API.\n\n## Authentication And Client Setup\n\nApplication Default Credentials (ADC) are the normal path. ADC looks for credentials in this order:\n\n1. `GOOGLE_APPLICATION_CREDENTIALS`\n2. local ADC created by `gcloud auth application-default login`\n3. the attached service account on Google Cloud\n\nBasic client setup:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]  # Example: us-central1-a\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n```\n\nIf you need explicit credentials:\n\n```python\nimport os\n\nfrom google.auth import default\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\ncredentials, _ = default()\nclient = tpu_v2.TpuClient(credentials=credentials)\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n```\n\n## Core Workflow\n\n### Discover valid accelerator types and runtime versions\n\nDo this first instead of hard-coding values copied from old blog posts:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n\nprint(\"Accelerator types:\")\nfor accelerator in client.list_accelerator_types(parent=parent):\n    print(accelerator.name, accelerator.type_)\n\nprint(\"Runtime versions:\")\nfor runtime in client.list_runtime_versions(parent=parent):\n    print(runtime)\n```\n\nThe returned values are what you should feed into node creation.\n\n### Create a TPU node\n\n`tpu_v2.Node` requires `runtime_version`. For a simple single-node example:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n\nnode = tpu_v2.Node(\n    accelerator_type=\"v2-8\",\n    runtime_version=\"tpu-ubuntu2204-base\",\n    network_config=tpu_v2.NetworkConfig(\n        enable_external_ips=True,\n    ),\n    tags=[\"ml\"],\n    labels={\"env\": \"dev\"},\n)\n\noperation = client.create_node(\n    parent=parent,\n    node_id=\"example-v2-8\",\n    node=node,\n)\n\ncreated = operation.result()\nprint(created.name)\nprint(created.state)\n```\n\nPractical notes:\n\n- `create_node()` returns a long-running operation. Wait on `operation.result()` before assuming the TPU exists.\n- If you set `enable_external_ips=False`, Google documents that the selected network or subnetwork must have Private Google Access enabled.\n- The library examples warn that some environments may need an explicit `client_options.api_endpoint` override; use that only if your environment requires a non-default endpoint.\n\n### Get and list nodes\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\nnode_name = client.node_path(PROJECT_ID, ZONE, \"example-v2-8\")\n\nnode = client.get_node(name=node_name)\nprint(node.name)\nprint(node.state)\nprint(node.health_description)\n\nfor item in client.list_nodes(parent=parent):\n    print(item.name, item.state)\n```\n\n### Stop, start, and delete a node\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nnode_name = client.node_path(PROJECT_ID, ZONE, \"example-v2-8\")\n\nclient.stop_node(name=node_name).result()\nclient.start_node(name=node_name).result()\nclient.delete_node(name=node_name).result()\n```\n\nImportant behavior:\n\n- `stop_node()` in v2 is only available for single TPU nodes.\n- `delete_node()` also returns a long-running operation. Wait for completion before recreating the same name.\n\n### Update mutable node fields\n\nThe v2 client only supports updating these node fields through `update_node()`:\n\n- `description`\n- `tags`\n- `labels`\n- `metadata`\n- `network_config.enable_external_ips`\n\nExample:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nnode_name = client.node_path(PROJECT_ID, ZONE, \"example-v2-8\")\n\nnode = tpu_v2.Node(\n    name=node_name,\n    labels={\"env\": \"staging\", \"owner\": \"ml-platform\"},\n)\n\noperation = client.update_node(\n    node=node,\n    update_mask=FieldMask(paths=[\"labels\"]),\n)\n\nupdated = operation.result()\nprint(updated.labels)\n```\n\n## Queued Resources\n\nGoogle’s Cloud TPU setup guide recommends queued resources as a best practice when you want capacity to arrive when it becomes available instead of failing immediately.\n\nCreate a Spot queued resource:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n\nqueued_resource = tpu_v2.QueuedResource(\n    tpu=tpu_v2.QueuedResource.Tpu(\n        node_spec=[\n            tpu_v2.QueuedResource.Tpu.NodeSpec(\n                parent=parent,\n                node_id=\"queued-node-1\",\n                node=tpu_v2.Node(\n                    accelerator_type=\"v5litepod-8\",\n                    runtime_version=\"v2-alpha-tpuv5-lite\",\n                    network_config=tpu_v2.NetworkConfig(\n                        enable_external_ips=True,\n                    ),\n                ),\n            )\n        ]\n    ),\n    spot=tpu_v2.QueuedResource.Spot(),\n)\n\noperation = client.create_queued_resource(\n    parent=parent,\n    queued_resource_id=\"queued-demo\",\n    queued_resource=queued_resource,\n)\n\ncreated = operation.result()\nprint(created.name)\nprint(created.state)\n```\n\nInspect and list queued resources:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n\nqueued_name = client.queued_resource_path(PROJECT_ID, ZONE, \"queued-demo\")\n\nqueued = client.get_queued_resource(name=queued_name)\nprint(queued.name)\nprint(queued.state)\n\nfor item in client.list_queued_resources(parent=parent):\n    print(item.name, item.state)\n```\n\nDelete a queued resource:\n\n```python\nimport os\n\nfrom google.cloud import tpu_v2\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v2.TpuClient()\nqueued_name = client.queued_resource_path(PROJECT_ID, ZONE, \"queued-demo\")\n\nclient.delete_queued_resource(name=queued_name).result()\n```\n\nQueued-resource caveats that matter in practice:\n\n- `QueuedResource` has oneof fields. Pick one tier such as `spot` or `guaranteed`; do not set multiple tiers at once.\n- For a single queued node, set `node_id`. The docs say multislice requests should populate `multislice_params` instead.\n- Reservation-backed requests use `reservation_name` in the format `projects/{project}/locations/{zone}/reservations/{reservation}`.\n\n## Legacy v1 API\n\nThe package still ships `tpu_v1`, but its request model is older. The main difference that trips people up is that v1 node creation uses `tensorflow_version`, not `runtime_version`.\n\n```python\nimport os\n\nfrom google.cloud import tpu_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_ZONE\"]\n\nclient = tpu_v1.TpuClient()\nparent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\n\nnode = tpu_v1.Node(\n    accelerator_type=\"v2-8\",\n    tensorflow_version=\"YOUR_TENSORFLOW_VERSION\",\n)\n\noperation = client.create_node(\n    parent=parent,\n    node_id=\"legacy-v1-node\",\n    node=node,\n)\n\ncreated = operation.result()\nprint(created.name)\n```\n\nOnly stay on v1 if your existing code or resource model already depends on it.\n\n## Common Pitfalls\n\n- The package name is `google-cloud-tpu`, but the import you usually want is `from google.cloud import tpu_v2`.\n- This library manages TPU resources. It does not replace the framework-specific setup you do after the TPU VM is provisioned.\n- Do not assume an old accelerator type or runtime version still exists in your target zone. Call `list_accelerator_types()` and `list_runtime_versions()` first.\n- Wait for long-running operations to finish before using or deleting a resource.\n- In v2, `stop_node()` only works for single TPU nodes.\n- In v2, `update_node()` only supports a narrow set of mutable fields. Do not expect accelerator type or runtime version changes through `update_node()`.\n- `QueuedResource` uses oneof fields for both the resource definition and the request tier. Setting conflicting fields will clear earlier values.\n- If you disable external IPs, your network path must satisfy the Private Google Access requirement documented on `NetworkConfig`.\n- ADC is the standard auth path. Avoid service account keys unless you actually need them.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `google-cloud-tpu 1.25.0`.\n- The current reference pages for the client surface are serving `1.25.0`, but the public changelog page still lists `1.24.0` as its latest entry as of March 13, 2026.\n- The upstream changelog for `1.24.0` adds Python 3.14 support and deprecates the `credentials_file` argument. If you are updating older code, prefer `credentials=` or ADC instead of new `credentials_file` usage.\n- The upstream changelog shows TPU v2 support landed in `1.6.0`. If you are maintaining very old environments pinned below that, the v2 examples in this guide do not apply.\n\n## Official Sources\n\n- Cloud TPU Python reference root: `https://cloud.google.com/python/docs/reference/tpu/latest`\n- `tpu_v2.TpuClient` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v2.services.tpu.TpuClient`\n- `tpu_v2.Node` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v2.types.Node`\n- `tpu_v2.NetworkConfig` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v2.types.NetworkConfig`\n- `tpu_v2.QueuedResource` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v2.types.QueuedResource`\n- `QueuedResource.Tpu.NodeSpec` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v2.types.QueuedResource.Tpu.NodeSpec`\n- `tpu_v1.Node` reference: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/google.cloud.tpu_v1.types.Node`\n- Cloud TPU environment setup: `https://docs.cloud.google.com/tpu/docs/quick-starts`\n- Queued resources guide: `https://docs.cloud.google.com/tpu/docs/queued-resources`\n- ADC overview: `https://cloud.google.com/docs/authentication/application-default-credentials`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Changelog: `https://docs.cloud.google.com/python/docs/reference/tpu/latest/changelog`\n- PyPI: `https://pypi.org/project/google-cloud-tpu/`\n"
  },
  {
    "path": "content/google/docs/trace/python/DOC.md",
    "content": "---\nname: trace\ndescription: \"Google Cloud Trace Python client library for reading traces with trace_v1 and writing spans with trace_v2\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.18.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,cloud-trace,trace,tracing,observability,gcp\"\n---\n\n# Google Cloud Trace Python Client Library\n\n## Golden Rule\n\nUse `google-cloud-trace` when you need direct Cloud Trace API access from Python.\n\n- Import `trace_v1` to list, read, and patch traces.\n- Import `trace_v2` to create or batch-write spans.\n- If you need application instrumentation rather than low-level API calls, Google recommends OpenTelemetry for Cloud Trace instrumentation.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-trace==1.18.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-trace==1.18.0\"\npoetry add \"google-cloud-trace==1.18.0\"\n```\n\nIf you use explicit service-account credentials in code, install the auth helper too:\n\n```bash\npython -m pip install \"google-auth\"\n```\n\n## Authentication And Setup\n\nCloud Trace client libraries use Application Default Credentials (ADC).\n\nLocal development:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\n```\n\nService-account file flow:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-project-id\"\n```\n\nIn Google Cloud runtimes, prefer an attached service account over a downloaded key file.\n\nBefore sending or reading trace data, make sure:\n\n1. The Cloud Trace API is enabled in the target project.\n2. The caller has the right IAM role.\n3. `GOOGLE_CLOUD_PROJECT` or the explicit project argument matches the project that owns the traces.\n\nUseful IAM roles from the Cloud Trace IAM docs:\n\n- `roles/cloudtrace.user`: read trace data\n- `roles/cloudtrace.agent`: write spans\n- `roles/cloudtrace.admin`: full administrative access\n\n## Client Initialization\n\n### Read traces with `trace_v1`\n\n```python\nfrom google.cloud import trace_v1\n\nclient = trace_v1.TraceServiceClient()\nproject_id = \"your-project-id\"\n```\n\n`trace_v1.TraceServiceClient` is the client for `list_traces`, `get_trace`, and `patch_traces`.\n\n### Write spans with `trace_v2`\n\n```python\nfrom google.cloud import trace_v2\n\nclient = trace_v2.TraceServiceClient()\nproject_name = \"projects/your-project-id\"\n```\n\n`trace_v2.TraceServiceClient` is the client for `batch_write_spans` and `create_span`.\n\n### Explicit credentials\n\n```python\nfrom google.cloud import trace_v2\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = trace_v2.TraceServiceClient(credentials=credentials)\n```\n\n## Core Usage\n\n### Write spans with `batch_write_spans`\n\nUse `batch_write_spans` for normal ingest. It accepts a parent resource name in the form `projects/{project_id}` and a list of spans.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import trace_v2\nfrom google.cloud.trace_v2.types import Span\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\ndef to_timestamp(value: datetime) -> Timestamp:\n    ts = Timestamp()\n    ts.FromDatetime(value)\n    return ts\n\nproject_id = \"your-project-id\"\ntrace_id = \"0123456789abcdef0123456789abcdef\"\nspan_id = \"0123456789abcdef\"\n\nnow = datetime.now(timezone.utc)\nend = now + timedelta(milliseconds=150)\n\nspan = Span(\n    name=f\"projects/{project_id}/traces/{trace_id}/spans/{span_id}\",\n    span_id=span_id,\n    display_name={\"value\": \"process-order\"},\n    start_time=to_timestamp(now),\n    end_time=to_timestamp(end),\n)\n\nclient = trace_v2.TraceServiceClient()\nclient.batch_write_spans(\n    name=f\"projects/{project_id}\",\n    spans=[span],\n)\n```\n\nUse `create_span` only when you really want a single-span RPC. For regular ingestion, batch writes reduce request overhead.\n\n### List traces with `trace_v1`\n\n`trace_v1` reads traces by project id, not by `projects/{project_id}` resource name.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nfrom google.cloud import trace_v1\nfrom google.protobuf.timestamp_pb2 import Timestamp\n\ndef to_timestamp(value: datetime) -> Timestamp:\n    ts = Timestamp()\n    ts.FromDatetime(value)\n    return ts\n\nclient = trace_v1.TraceServiceClient()\nproject_id = \"your-project-id\"\n\nend = datetime.now(timezone.utc)\nstart = end - timedelta(hours=1)\n\nfor trace in client.list_traces(\n    project_id=project_id,\n    view=trace_v1.ListTracesRequest.ViewType.MINIMAL,\n    page_size=20,\n    start_time=to_timestamp(start),\n    end_time=to_timestamp(end),\n):\n    print(trace.project_id, trace.trace_id)\n```\n\nUse a larger view only when you need more than IDs:\n\n- `MINIMAL`: cheapest listing\n- `ROOTSPAN`: include root-span data\n- `COMPLETE`: include full span details\n\n### Get one trace\n\n```python\nfrom google.cloud import trace_v1\n\nclient = trace_v1.TraceServiceClient()\n\ntrace = client.get_trace(\n    project_id=\"your-project-id\",\n    trace_id=\"0123456789abcdef0123456789abcdef\",\n)\n\nprint(trace.project_id)\nprint(trace.trace_id)\nprint(len(trace.spans))\n```\n\n## Configuration Notes\n\n- `trace_v1` and `trace_v2` are separate generated clients. Pick the client by operation, not by package name.\n- ADC is the default path. Only pass explicit credentials when your runtime cannot provide ADC cleanly.\n- If your runtime does not infer the project automatically, pass the project id explicitly and keep `GOOGLE_CLOUD_PROJECT` aligned with it.\n- The generated clients support `client_options` if you need to override the API endpoint or other transport options.\n- For library debug logging, Google client libraries support the `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` environment variable.\n- `trace_v1` also exposes `patch_traces` for updating trace resources, but new write flows should usually be modeled as v2 span writes.\n\n## Common Pitfalls\n\n- Do not import `trace`; the Python package exposes `trace_v1` and `trace_v2`.\n- Do not use the v2 client for reads. `trace_v2` is for writing spans, while `trace_v1` is where `list_traces` and `get_trace` live.\n- Do not mix resource formats. `trace_v2` methods use names like `projects/my-project`, while `trace_v1` request methods use `project_id=\"my-project\"`.\n- For `batch_write_spans`, every span still needs a fully qualified span `name` such as `projects/{project_id}/traces/{trace_id}/spans/{span_id}`.\n- If you are instrumenting an app or service rather than calling the Trace API directly, prefer OpenTelemetry. This package is the low-level client, not the main instrumentation path.\n- In production, prefer attached service accounts over JSON key files.\n- Some generated reference pages can lag the newest release label. Validate package version against PyPI if a `latest` doc page and a generated class page disagree.\n\n## Version-Sensitive Notes For `1.18.0`\n\n- The version used here `1.18.0` matches the current PyPI release as of March 12, 2026.\n- The canonical Google Python docs family for this package is `cloudtrace`, not the older `trace` path variant.\n- The top-level `latest` reference resolves to `1.18.0`, but some generated class pages can still display `1.17.0`. Treat PyPI as the release authority when there is a temporary docs-generation mismatch.\n- PyPI still declares `Requires: Python >=3.7`, but Python 3.7 and 3.8 are upstream-EOL interpreters. If you are choosing a new runtime, use a currently supported Python version even though the wheel metadata remains broad.\n\n## Official Sources\n\n- Python reference root: `https://cloud.google.com/python/docs/reference/cloudtrace/latest`\n- `trace_v1` service docs: `https://cloud.google.com/python/docs/reference/cloudtrace/latest/google.cloud.trace_v1.services.trace_service.TraceServiceClient`\n- `trace_v2` service docs: `https://cloud.google.com/python/docs/reference/cloudtrace/latest/google.cloud.trace_v2.services.trace_service.TraceServiceClient`\n- Python instrumentation guidance: `https://cloud.google.com/trace/docs/setup/python-ot`\n- Authentication: `https://cloud.google.com/docs/authentication/client-libraries`\n- ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Cloud Trace IAM: `https://cloud.google.com/trace/docs/iam`\n- PyPI package: `https://pypi.org/project/google-cloud-trace/`\n"
  },
  {
    "path": "content/google/docs/trace-agent/javascript/DOC.md",
    "content": "---\nname: trace-agent\ndescription: \"Google Cloud Trace Node.js agent for starting automatic tracing early in process startup and adding manual spans when needed\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,trace,distributed-tracing,observability,javascript,nodejs\"\n---\n\n# `@google-cloud/trace-agent` JavaScript Package Guide\n\nUse `@google-cloud/trace-agent` when you want a Node.js service to send trace data to Google Cloud Trace. This package is a startup agent, not a request-scoped client: you initialize it once at process startup, before loading the rest of the app, and then let automatic instrumentation collect traces for supported modules.\n\n## Golden Rule\n\n- Start the agent exactly once, as early as possible in the process.\n- Load it before `express`, database drivers, HTTP clients, or other modules you want auto-instrumented.\n- Use Application Default Credentials (ADC) unless you need to pass `projectId` or `keyFilename` explicitly.\n- Keep project selection explicit in local development so traces do not go to the wrong project.\n- Use manual spans only for work the agent will not capture automatically.\n\nThis guide covers `8.0.0`.\n\n## Install\n\n```bash\nnpm install @google-cloud/trace-agent@8.0.0\n```\n\n## Prerequisites\n\nBefore starting the agent:\n\n1. Enable the Cloud Trace API in the target project.\n2. Run the process with credentials that can write trace data.\n3. Decide which Google Cloud project should receive traces.\n\nEnable the API:\n\n```bash\ngcloud services enable cloudtrace.googleapis.com \\\n  --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\n## Authentication And Setup\n\nThis package uses Google Cloud credentials, not an API key.\n\nFor local development with Application Default Credentials:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GCLOUD_PROJECT=\"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GCLOUD_PROJECT=\"$GOOGLE_CLOUD_PROJECT\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nIn production on Google Cloud, prefer an attached service account or workload identity instead of distributing JSON key files.\n\n## Initialize The Agent\n\nThe agent must start before the rest of the app is loaded so it can patch supported modules during `require()`.\n\n### Minimal Startup Example\n\n```javascript\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n});\n\nrequire('./server');\n```\n\n### Start With An Explicit Key File\n\nUse this when you are not relying on ADC discovery.\n\n```javascript\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n\nrequire('./server');\n```\n\n### Use A Dedicated Bootstrap File\n\nKeeping tracing in its own startup module makes it easier to guarantee load order.\n\n```javascript\n// tracing.js\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n});\n```\n\n```javascript\n// index.js\nrequire('./tracing');\nrequire('./server');\n```\n\n## Common Workflows\n\n### Start Tracing Before An Express App\n\nInitialize the agent before `express` is loaded.\n\n```javascript\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n});\n\nconst express = require('express');\n\nconst app = express();\n\napp.get('/healthz', (req, res) => {\n  res.send('ok');\n});\n\napp.listen(8080, () => {\n  console.log('Listening on :8080');\n});\n```\n\n### Add A Manual Root Span For Background Work\n\nUse manual spans for work that does not already sit inside an incoming traced request.\n\n```javascript\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n});\n\nconst tracer = traceAgent.get();\n\nfunction rebuildSearchIndex(doWork) {\n  return tracer.runInRootSpan({name: 'rebuild-search-index'}, rootSpan => {\n    try {\n      rootSpan.addLabel('job.name', 'rebuild-search-index');\n      return doWork();\n    } finally {\n      rootSpan.endSpan();\n    }\n  });\n}\n```\n\n### Add Child Spans Inside A Traced Operation\n\nUse child spans to break a larger operation into smaller timed sections.\n\n```javascript\nconst traceAgent = require('@google-cloud/trace-agent');\n\ntraceAgent.start({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT,\n});\n\nconst tracer = traceAgent.get();\n\nfunction handleOrder(validateCart, chargeCustomer) {\n  return tracer.runInRootSpan({name: 'handle-order'}, rootSpan => {\n    try {\n      const validationSpan = tracer.createChildSpan({name: 'validate-cart'});\n      try {\n        validateCart();\n      } finally {\n        validationSpan.endSpan();\n      }\n\n      const chargeSpan = tracer.createChildSpan({name: 'charge-customer'});\n      try {\n        chargeCustomer();\n      } finally {\n        chargeSpan.endSpan();\n      }\n    } finally {\n      rootSpan.endSpan();\n    }\n  });\n}\n```\n\n## Common Pitfalls\n\n- Do not call `start()` after loading `express`, database drivers, or HTTP client libraries you expect the agent to patch.\n- Do not initialize the agent more than once in the same process.\n- Do not rely on implicit project detection in local development if you have access to multiple Google Cloud projects.\n- Do not commit service account JSON files into the repository.\n- Do not treat this package like a normal instantiated client; the primary entry point is the top-level `start()` call.\n\n## Version-Sensitive Notes\n\n- This guide targets `@google-cloud/trace-agent` version `8.0.0`.\n- The package is configured through `start(...)` at process startup rather than by constructing a long-lived client instance.\n- Manual instrumentation in this package uses the singleton tracer obtained from `require('@google-cloud/trace-agent').get()`.\n\n## Official Sources\n\n- Maintainer README: `https://github.com/googleapis/cloud-trace-nodejs#readme`\n- Google Cloud authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/trace-agent`\n"
  },
  {
    "path": "content/google/docs/translate/javascript/DOC.md",
    "content": "---\nname: translate\ndescription: \"Official Google Cloud Translation Node.js client library with Basic v2 and Advanced v3 setup, auth, and translation patterns\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud-translate,gcp,translation,i18n,javascript,nodejs,google-cloud\"\n---\n\n# google-cloud-translate JavaScript Package Guide\n\nUse `@google-cloud/translate` for the official Google Cloud Translation client library in Node.js. The package includes two distinct surfaces:\n\n- `require('@google-cloud/translate').v2` for Basic edition\n- `require('@google-cloud/translate').v3` for Advanced edition\n\nUse Basic v2 for simple text translation, language detection, and supported-language lookup. Use Advanced v3 when you need the current Translation API feature set such as regional resources or glossaries.\n\n## Install\n\nInstall the package directly:\n\n```bash\nnpm install @google-cloud/translate@9.3.0\n```\n\nWith Yarn:\n\n```bash\nyarn add @google-cloud/translate@9.3.0\n```\n\nWith pnpm:\n\n```bash\npnpm add @google-cloud/translate@9.3.0\n```\n\n## Choose The Right Client\n\n### Use Basic edition v2 when you need:\n\n- simple text translation\n- language detection\n- supported-language lookup\n- compatibility with older Basic edition code\n\nImport it as:\n\n```js\nconst {v2} = require('@google-cloud/translate')\nconst {Translate} = v2\n```\n\n### Use Advanced edition v3 when you need:\n\n- glossaries\n- document translation\n- batch translation jobs\n- regional resources and custom models\n\nImport it as:\n\n```js\nconst {v3} = require('@google-cloud/translate')\nconst {TranslationServiceClient} = v3\n```\n\n## Setup And Authentication\n\nBefore making requests:\n\n1. Create or select a Google Cloud project.\n2. Enable billing on that project.\n3. Enable the Cloud Translation API.\n4. Authenticate with Application Default Credentials (ADC) or a service account key.\n\nLocal ADC flow:\n\n```bash\ngcloud auth application-default login\n```\n\nService account credentials:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nIf you are provisioning the API in setup scripts, the service name is:\n\n```bash\ngcloud services enable translate.googleapis.com\n```\n\nDefault to ADC unless you have a reason to pass credentials explicitly.\n\n## Basic v2 Quick Start\n\nTranslate a plain string:\n\n```js\nconst {v2} = require('@google-cloud/translate')\n\nconst {Translate} = v2\nconst translate = new Translate()\n\nasync function main() {\n  const [translation] = await translate.translate('Hello, world!', 'es')\n  console.log(translation)\n}\n\nmain().catch(console.error)\n```\n\nDetect language:\n\n```js\nconst {v2} = require('@google-cloud/translate')\n\nconst {Translate} = v2\nconst translate = new Translate()\n\nasync function main() {\n  let [detections] = await translate.detect('Bonjour tout le monde')\n  detections = Array.isArray(detections) ? detections : [detections]\n\n  for (const detection of detections) {\n    console.log(detection.language, detection.confidence)\n  }\n}\n\nmain().catch(console.error)\n```\n\nList supported languages:\n\n```js\nconst {v2} = require('@google-cloud/translate')\n\nconst {Translate} = v2\nconst translate = new Translate()\n\nasync function main() {\n  const [languages] = await translate.getLanguages()\n\n  for (const language of languages.slice(0, 5)) {\n    console.log(language.code, language.name)\n  }\n}\n\nmain().catch(console.error)\n```\n\n## Advanced v3 Quick Start\n\nEvery v3 request needs a `parent` resource:\n\n```js\nconst projectId = process.env.GOOGLE_CLOUD_PROJECT\nconst parent = `projects/${projectId}/locations/global`\n```\n\nTranslate text:\n\n```js\nconst {v3} = require('@google-cloud/translate')\n\nconst {TranslationServiceClient} = v3\nconst client = new TranslationServiceClient()\n\nasync function main() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const parent = `projects/${projectId}/locations/global`\n\n  const [response] = await client.translateText({\n    parent,\n    contents: ['Hello, world!'],\n    mimeType: 'text/plain',\n    targetLanguageCode: 'es',\n  })\n\n  for (const translation of response.translations) {\n    console.log(translation.translatedText)\n  }\n}\n\nmain().catch(console.error)\n```\n\nDetect language:\n\n```js\nconst {v3} = require('@google-cloud/translate')\n\nconst {TranslationServiceClient} = v3\nconst client = new TranslationServiceClient()\n\nasync function main() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const parent = `projects/${projectId}/locations/global`\n\n  const [response] = await client.detectLanguage({\n    parent,\n    content: 'Hallo Welt',\n    mimeType: 'text/plain',\n  })\n\n  for (const language of response.languages) {\n    console.log(language.languageCode, language.confidence)\n  }\n}\n\nmain().catch(console.error)\n```\n\nGet supported languages:\n\n```js\nconst {v3} = require('@google-cloud/translate')\n\nconst {TranslationServiceClient} = v3\nconst client = new TranslationServiceClient()\n\nasync function main() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const parent = `projects/${projectId}/locations/global`\n\n  const [response] = await client.getSupportedLanguages({\n    parent,\n    displayLanguageCode: 'en',\n  })\n\n  for (const language of response.languages.slice(0, 5)) {\n    console.log(language.languageCode, language.displayName)\n  }\n}\n\nmain().catch(console.error)\n```\n\n## Regional Resources And Endpoints\n\nStart with `locations/global` unless you are using a regional resource such as a glossary or custom model.\n\nGlossary example:\n\n```js\nconst {v3} = require('@google-cloud/translate')\n\nconst {TranslationServiceClient} = v3\n\nasync function main() {\n  const projectId = process.env.GOOGLE_CLOUD_PROJECT\n  const location = 'us-central1'\n  const parent = `projects/${projectId}/locations/${location}`\n  const glossary = `projects/${projectId}/locations/${location}/glossaries/my-glossary`\n\n  const client = new TranslationServiceClient({\n    apiEndpoint: 'us-central1-translate.googleapis.com',\n  })\n\n  const [response] = await client.translateText({\n    parent,\n    contents: ['Product name: Example Cloud'],\n    mimeType: 'text/plain',\n    targetLanguageCode: 'fr',\n    glossaryConfig: {glossary},\n  })\n\n  console.log(response.glossaryTranslations[0].translatedText)\n}\n\nmain().catch(console.error)\n```\n\nKeep the endpoint, `parent`, glossary path, and any model path in the same location.\n\n## Credentials Configuration\n\nIf you need to pass options explicitly, both clients accept constructor options:\n\n```js\nconst {v2, v3} = require('@google-cloud/translate')\n\nconst basicClient = new v2.Translate({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n})\n\nconst advancedClient = new v3.TranslationServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n})\n```\n\nUse constructor options only when ADC is not enough for your runtime.\n\n## Common Pitfalls\n\n- Do not mix `v2` and `v3` imports. They expose different classes and different request and response shapes.\n- For v3, always provide `parent` in the form `projects/PROJECT_ID/locations/LOCATION`.\n- In Node.js v3 requests, use camelCase field names such as `mimeType` and `targetLanguageCode`.\n- `translateText()` takes `contents` as an array, even when you are translating a single string.\n- Use `mimeType: 'text/plain'` for plain strings and `mimeType: 'text/html'` only when you are sending HTML content.\n- Do not mix `locations/global` with regional glossaries or custom models. The request location and resource location must match.\n- The maintainer reference URL uses `latest`, so it is not a frozen `9.3.0` snapshot.\n\n## Version-Sensitive Notes For 9.3.0\n\n- This guide targets `@google-cloud/translate` version `9.3.0`.\n- The maintainer Node.js reference is still the right entry point, but it is a `latest` URL rather than a version-pinned `9.3.0` page.\n- If you need release-specific behavior, verify it against the npm package page or the package changelog before depending on it.\n\n## Official Sources\n\n- Node.js package reference: `https://cloud.google.com/nodejs/docs/reference/translate/latest`\n- Translation Basic edition Node.js guide: `https://cloud.google.com/translate/docs/reference/libraries/v2/nodejs`\n- Translation Advanced text translation guide: `https://cloud.google.com/translate/docs/advanced/translating-text-v3`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/translate`\n"
  },
  {
    "path": "content/google/docs/translate/python/DOC.md",
    "content": "---\nname: translate\ndescription: \"Official Google Cloud Translation client library for Python with Basic v2 and Advanced v3 setup, auth, and translation patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.24.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud-translate,gcp,translation,i18n,python,google-cloud\"\n---\n\n# google-cloud-translate Python Package Guide\n\nUse `google-cloud-translate` for the official Google Cloud Translation client library in Python. The package includes two distinct surfaces:\n\n- `google.cloud.translate_v2` for Basic edition\n- `google.cloud.translate_v3` for Advanced edition\n\nFor new code, prefer Advanced edition v3 unless you specifically need the older Basic edition API shape.\n\n## Install\n\nInstall the package directly:\n\n```bash\npython -m pip install \"google-cloud-translate==3.24.0\"\n```\n\nWith `uv`:\n\n```bash\nuv add google-cloud-translate==3.24.0\n```\n\nWith Poetry:\n\n```bash\npoetry add google-cloud-translate==3.24.0\n```\n\n## Choose The Right Client\n\n### Use Basic edition v2 when you need:\n\n- simple text translation\n- language detection\n- supported-language lookup\n- compatibility with older Basic edition code\n\nImport it as:\n\n```python\nfrom google.cloud import translate_v2 as translate\n```\n\n### Use Advanced edition v3 when you need:\n\n- glossaries\n- document translation\n- batch translation jobs\n- regional resources and custom models\n- the current Google Cloud Translation feature set\n\nImport it as:\n\n```python\nfrom google.cloud import translate_v3\n```\n\n## Setup And Authentication\n\nBefore making requests:\n\n1. Create or select a Google Cloud project.\n2. Enable billing on that project.\n3. Enable the Cloud Translation API.\n4. Authenticate with Application Default Credentials (ADC) or explicit service account credentials.\n\nLocal ADC flow:\n\n```bash\ngcloud auth application-default login\n```\n\nService account credentials:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nIf you are provisioning the API in setup scripts, the service name is:\n\n```bash\ngcloud services enable translate.googleapis.com\n```\n\nDefault to ADC unless you have a reason to inject credentials manually.\n\n## Basic v2 Quick Start\n\n```python\nfrom google.cloud import translate_v2 as translate\n\nclient = translate.Client()\n\nresult = client.translate(\n    \"Hello, world!\",\n    target_language=\"es\",\n)\n\nprint(result[\"translatedText\"])\nprint(result.get(\"detectedSourceLanguage\"))\n```\n\nDetect language:\n\n```python\nfrom google.cloud import translate_v2 as translate\n\nclient = translate.Client()\nresult = client.detect_language(\"Bonjour tout le monde\")\n\nprint(result[\"language\"], result[\"confidence\"])\n```\n\nList supported languages:\n\n```python\nfrom google.cloud import translate_v2 as translate\n\nclient = translate.Client()\nlanguages = client.get_languages(target_language=\"en\")\n\nfor language in languages[:5]:\n    print(language[\"language\"], language[\"name\"])\n```\n\n## Advanced v3 Quick Start\n\nEvery v3 request needs a `parent` resource:\n\n```python\nproject_id = \"my-project\"\nparent = f\"projects/{project_id}/locations/global\"\n```\n\nTranslate text:\n\n```python\nfrom google.cloud import translate_v3\n\nproject_id = \"my-project\"\nparent = f\"projects/{project_id}/locations/global\"\n\nclient = translate_v3.TranslationServiceClient()\n\nresponse = client.translate_text(\n    request={\n        \"parent\": parent,\n        \"contents\": [\"Hello, world!\"],\n        \"mime_type\": \"text/plain\",\n        \"target_language_code\": \"es\",\n    }\n)\n\nfor translation in response.translations:\n    print(translation.translated_text)\n```\n\nDetect language:\n\n```python\nfrom google.cloud import translate_v3\n\nproject_id = \"my-project\"\nparent = f\"projects/{project_id}/locations/global\"\n\nclient = translate_v3.TranslationServiceClient()\n\nresponse = client.detect_language(\n    request={\n        \"parent\": parent,\n        \"content\": \"Hallo Welt\",\n        \"mime_type\": \"text/plain\",\n    }\n)\n\nfor language in response.languages:\n    print(language.language_code, language.confidence)\n```\n\nGet supported languages:\n\n```python\nfrom google.cloud import translate_v3\n\nproject_id = \"my-project\"\nparent = f\"projects/{project_id}/locations/global\"\n\nclient = translate_v3.TranslationServiceClient()\n\nresponse = client.get_supported_languages(\n    request={\n        \"parent\": parent,\n        \"display_language_code\": \"en\",\n    }\n)\n\nfor language in response.languages[:5]:\n    print(language.language_code, language.display_name)\n```\n\n## Regional Resources And Endpoints\n\nStart with `locations/global` unless you are using a regional resource such as a glossary or custom model.\n\nGlossary example:\n\n```python\nfrom google.cloud import translate_v3\n\nproject_id = \"my-project\"\nlocation = \"us-central1\"\nparent = f\"projects/{project_id}/locations/{location}\"\nglossary = (\n    f\"projects/{project_id}/locations/{location}/glossaries/my-glossary\"\n)\n\nclient = translate_v3.TranslationServiceClient()\n\nresponse = client.translate_text(\n    request={\n        \"parent\": parent,\n        \"contents\": [\"Product name: Example Cloud\"],\n        \"mime_type\": \"text/plain\",\n        \"target_language_code\": \"fr\",\n        \"glossary_config\": {\"glossary\": glossary},\n    }\n)\n\nprint(response.glossary_translations[0].translated_text)\n```\n\nIf you need a regional endpoint, pass `client_options`:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import translate_v3\n\nclient = translate_v3.TranslationServiceClient(\n    client_options=ClientOptions(\n        api_endpoint=\"us-central1-translate.googleapis.com\"\n    )\n)\n```\n\nKeep the endpoint, `parent`, glossary path, and model path in the same location.\n\n## Credentials Configuration\n\nExplicit credentials object:\n\n```python\nfrom google.cloud import translate_v3\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"/path/to/service-account.json\"\n)\n\nclient = translate_v3.TranslationServiceClient(credentials=credentials)\n```\n\nYou can also use the async client in async applications:\n\n```python\nfrom google.cloud.translate_v3.services.translation_service import (\n    TranslationServiceAsyncClient,\n)\n\nclient = TranslationServiceAsyncClient()\n```\n\n## Common Pitfalls\n\n- Do not import `translate_v2` and `translate_v3` interchangeably. They are different APIs with different request and response shapes.\n- For v3, always provide `parent` in the form `projects/PROJECT_ID/locations/LOCATION`.\n- Use `mime_type=\"text/plain\"` for plain strings and `mime_type=\"text/html\"` only when you are sending HTML content.\n- Do not mix `locations/global` with regional glossaries or custom models. The request location and resource location must match.\n- The docs URL uses `latest`, so it is not a frozen `3.24.0` snapshot. Treat it as the current 3.x reference and verify anything version-sensitive against PyPI or the changelog.\n- Prefer `credentials=` or ADC. The changelog marks `credentials_file` as deprecated starting in `3.22.0`.\n- Be careful when copying older pre-3.x examples. Current 3.x docs consistently use request objects or keyword arguments rather than positional request fields.\n\n## Version-Sensitive Notes For 3.24.0\n\n- PyPI currently lists `3.24.0` as the latest release for `google-cloud-translate`.\n- The official Python reference page is still the right entry point, but it is a `latest` URL rather than a version-pinned `3.24.0` page.\n- The upstream changelog notes that from `3.22.0`, `credentials_file` is deprecated and `api_audience` support was added.\n- The upstream changelog also notes that from `3.14.0`, the client can auto-select the mTLS endpoint when `GOOGLE_API_USE_CLIENT_CERTIFICATE=true` and a client certificate source is available.\n- If you only need simple text translation, v2 remains available in the same package. For new build-out on Google Cloud, prefer v3 first and drop to v2 only when you intentionally need the Basic edition surface.\n\n## Official Sources\n\n- Python package reference: `https://cloud.google.com/python/docs/reference/translate/latest`\n- Translation Basic edition Python guide: `https://cloud.google.com/translate/docs/reference/libraries/v2/python`\n- Translation Advanced text translation guide: `https://cloud.google.com/translate/docs/advanced/translating-text-v3`\n- PyPI package page: `https://pypi.org/project/google-cloud-translate/`\n- Upstream changelog: `https://github.com/googleapis/google-cloud-python/blob/main/packages/google-cloud-translate/CHANGELOG.md`\n"
  },
  {
    "path": "content/google/docs/vertexai/javascript/DOC.md",
    "content": "---\nname: vertexai\ndescription: \"Google Cloud Vertex AI Node.js client for Gemini text generation, streaming, chat, multimodal prompts, and tool calling\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,vertex-ai,vertexai,gemini,generative-ai,javascript,nodejs\"\n---\n\n# `@google-cloud/vertexai` JavaScript Package Guide\n\nUse `@google-cloud/vertexai` when your Node.js app needs to call Gemini models through Vertex AI on Google Cloud.\n\nThis package is for Vertex AI generative model requests. It uses Google Cloud authentication and regional Vertex AI setup, not API-key-only Gemini API flows.\n\n## Golden Rule\n\n- Authenticate with Google Cloud Application Default Credentials (ADC) or a service account.\n- Create the client with the correct `project` and `location`.\n- Use `vertexAI.getGenerativeModel(...)` for normal model access.\n- Use `vertexAI.preview.getGenerativeModel(...)` only when the feature or model is documented as preview.\n- Build prompts with `contents`, `role`, and `parts` objects instead of ad hoc request shapes.\n\nThis guide covers `1.10.0`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/vertexai@1.10.0\n```\n\n## Authentication And Setup\n\nTypical prerequisites:\n\n1. A Google Cloud project with Vertex AI enabled.\n2. Credentials that can call Vertex AI.\n3. A supported Vertex AI region such as `us-central1`.\n4. A model name that is available in that region.\n\nEnable the Vertex AI API:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable aiplatform.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nIf you must use a service account key file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nPrefer attached service-account credentials on Google Cloud over shipping JSON key files.\n\n## Initialize The Client\n\nES modules:\n\n```javascript\nimport {VertexAI, HarmCategory, HarmBlockThreshold} from '@google-cloud/vertexai';\n\nconst project = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1';\n\nif (!project) {\n  throw new Error('Set GOOGLE_CLOUD_PROJECT before creating VertexAI');\n}\n\nconst vertexAI = new VertexAI({project, location});\n\nconst generativeModel = vertexAI.getGenerativeModel({\n  model: 'gemini-1.5-flash',\n  generationConfig: {\n    maxOutputTokens: 512,\n    temperature: 0.2,\n  },\n  safetySettings: [\n    {\n      category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,\n      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,\n    },\n  ],\n  systemInstruction: {\n    role: 'system',\n    parts: [{text: 'You write concise, production-ready summaries.'}],\n  },\n});\n```\n\nCommonJS:\n\n```javascript\nconst {VertexAI, HarmCategory, HarmBlockThreshold} = require('@google-cloud/vertexai');\n\nconst project = process.env.GOOGLE_CLOUD_PROJECT;\nconst location = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1';\n\nconst vertexAI = new VertexAI({project, location});\n\nconst generativeModel = vertexAI.getGenerativeModel({\n  model: 'gemini-1.5-flash',\n  generationConfig: {\n    maxOutputTokens: 512,\n    temperature: 0.2,\n  },\n  safetySettings: [\n    {\n      category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,\n      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,\n    },\n  ],\n});\n```\n\nSmall helper for extracting generated text:\n\n```javascript\nfunction getText(response) {\n  return (\n    response.candidates?.[0]?.content?.parts\n      ?.map(part => part.text || '')\n      .join('') || ''\n  );\n}\n```\n\n## Core Workflows\n\n### Generate Text\n\nUse a `contents` array with a `user` message.\n\n```javascript\nimport {VertexAI} from '@google-cloud/vertexai';\n\nconst vertexAI = new VertexAI({\n  project: process.env.GOOGLE_CLOUD_PROJECT,\n  location: process.env.GOOGLE_CLOUD_LOCATION || 'us-central1',\n});\n\nconst model = vertexAI.getGenerativeModel({model: 'gemini-1.5-flash'});\n\nfunction getText(response) {\n  return (\n    response.candidates?.[0]?.content?.parts\n      ?.map(part => part.text || '')\n      .join('') || ''\n  );\n}\n\nasync function generateSummary() {\n  const result = await model.generateContent({\n    contents: [\n      {\n        role: 'user',\n        parts: [{text: 'Summarize the causes of HTTP 429 errors in three bullets.'}],\n      },\n    ],\n  });\n\n  return getText(result.response);\n}\n```\n\n### Stream Output\n\nUse `generateContentStream()` when you want tokens as they arrive.\n\n```javascript\nimport {VertexAI} from '@google-cloud/vertexai';\n\nconst vertexAI = new VertexAI({\n  project: process.env.GOOGLE_CLOUD_PROJECT,\n  location: process.env.GOOGLE_CLOUD_LOCATION || 'us-central1',\n});\n\nconst model = vertexAI.getGenerativeModel({model: 'gemini-1.5-flash'});\n\nasync function streamAnswer() {\n  const streamingResult = await model.generateContentStream({\n    contents: [\n      {\n        role: 'user',\n        parts: [{text: 'Write a short incident update for a database failover.'}],\n      },\n    ],\n  });\n\n  for await (const item of streamingResult.stream) {\n    const chunk = item.candidates?.[0]?.content?.parts?.[0]?.text || '';\n    process.stdout.write(chunk);\n  }\n\n  const aggregatedResponse = await streamingResult.response;\n  return aggregatedResponse;\n}\n```\n\n### Start A Multi-Turn Chat\n\nUse `startChat()` when the same conversation needs multiple turns.\n\n```javascript\nimport {VertexAI} from '@google-cloud/vertexai';\n\nconst vertexAI = new VertexAI({\n  project: process.env.GOOGLE_CLOUD_PROJECT,\n  location: process.env.GOOGLE_CLOUD_LOCATION || 'us-central1',\n});\n\nconst model = vertexAI.getGenerativeModel({model: 'gemini-1.5-flash'});\n\nfunction getText(response) {\n  return (\n    response.candidates?.[0]?.content?.parts\n      ?.map(part => part.text || '')\n      .join('') || ''\n  );\n}\n\nasync function runChat() {\n  const chat = model.startChat({\n    history: [\n      {\n        role: 'user',\n        parts: [{text: 'My app is a task tracker for small teams.'}],\n      },\n      {\n        role: 'model',\n        parts: [{text: 'Got it. I will keep suggestions focused on task tracking.'}],\n      },\n    ],\n  });\n\n  const result = await chat.sendMessage('Suggest three onboarding emails.');\n  return getText(result.response);\n}\n```\n\n### Send A Multimodal Prompt\n\nFor image inputs, pass a text part plus a file reference. Include the correct MIME type.\n\n```javascript\nimport {VertexAI} from '@google-cloud/vertexai';\n\nconst vertexAI = new VertexAI({\n  project: process.env.GOOGLE_CLOUD_PROJECT,\n  location: process.env.GOOGLE_CLOUD_LOCATION || 'us-central1',\n});\n\nconst model = vertexAI.getGenerativeModel({model: 'gemini-1.5-flash'});\n\nasync function describeImage() {\n  const result = await model.generateContent({\n    contents: [\n      {\n        role: 'user',\n        parts: [\n          {text: 'Describe this image for an accessibility alt tag.'},\n          {\n            fileData: {\n              fileUri: 'gs://cloud-samples-data/generative-ai/image/scones.jpg',\n              mimeType: 'image/jpeg',\n            },\n          },\n        ],\n      },\n    ],\n  });\n\n  return result.response.candidates?.[0]?.content?.parts?.[0]?.text || '';\n}\n```\n\n### Define Tool Calls\n\nWhen a model feature is only documented as preview, create the model from `vertexAI.preview`.\n\n```javascript\nimport {VertexAI, FunctionDeclarationSchemaType} from '@google-cloud/vertexai';\n\nconst vertexAI = new VertexAI({\n  project: process.env.GOOGLE_CLOUD_PROJECT,\n  location: process.env.GOOGLE_CLOUD_LOCATION || 'us-central1',\n});\n\nconst weatherTools = [\n  {\n    functionDeclarations: [\n      {\n        name: 'get_current_weather',\n        description: 'Get the current weather in a given city',\n        parameters: {\n          type: FunctionDeclarationSchemaType.OBJECT,\n          properties: {\n            location: {\n              type: FunctionDeclarationSchemaType.STRING,\n              description: 'City and region, for example Boston, MA',\n            },\n            unit: {\n              type: FunctionDeclarationSchemaType.STRING,\n              enum: ['celsius', 'fahrenheit'],\n            },\n          },\n          required: ['location'],\n        },\n      },\n    ],\n  },\n];\n\nconst model = vertexAI.preview.getGenerativeModel({\n  model: 'gemini-1.5-pro',\n  tools: weatherTools,\n});\n\nasync function requestWeatherToolCall() {\n  const result = await model.generateContent({\n    contents: [\n      {\n        role: 'user',\n        parts: [{text: 'What is the weather in Boston right now?'}],\n      },\n    ],\n  });\n\n  const parts = result.response.candidates?.[0]?.content?.parts || [];\n  const toolCall = parts.find(part => part.functionCall)?.functionCall;\n\n  return toolCall;\n}\n```\n\nThe SDK surfaces the requested function call. Your application still needs to execute the tool and decide how to continue the conversation.\n\n## Practical Notes\n\n- Vertex AI is regional. Keep the client `location`, model availability, and any related Cloud resources in the same region.\n- Reuse `VertexAI` and model instances instead of creating a new client for every request.\n- Keep prompts in the documented `contents` format so text-only and multimodal requests stay consistent.\n- Use `generateContentStream()` for interactive output and `generateContent()` for single-response workflows.\n- Keep `systemInstruction`, `generationConfig`, and `safetySettings` on the model definition when they should apply to every request.\n\n## Common Pitfalls\n\n- `gcloud auth login` is not enough for local Node.js code. Use `gcloud auth application-default login` so ADC works.\n- Do not expect `GEMINI_API_KEY` or `GOOGLE_API_KEY` to authenticate this package. Use Google Cloud credentials.\n- Do not omit `location` when your project uses regional Vertex AI resources.\n- Do not assume every model or feature is GA. If the official docs show a preview-only path, use `vertexAI.preview` for that integration.\n- Multimodal requests need correctly typed parts such as `fileData` with a matching `mimeType`.\n- Generated text is nested under `response.candidates[0].content.parts`; extract it deliberately instead of assuming a flat `text` field.\n\n## Official Sources\n\n- Node.js reference root: `https://cloud.google.com/nodejs/docs/reference/vertexai/latest`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/vertexai`\n- ADC setup for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Vertex AI locations: `https://cloud.google.com/vertex-ai/docs/general/locations`\n"
  },
  {
    "path": "content/google/docs/video-intelligence/javascript/DOC.md",
    "content": "---\nname: video-intelligence\ndescription: \"Google Cloud Video Intelligence Node.js client for asynchronous video annotation from Cloud Storage or in-memory bytes\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,gcp,video-intelligence,video,annotation,javascript,nodejs\"\n---\n\n# `@google-cloud/video-intelligence` JavaScript Package Guide\n\nUse `@google-cloud/video-intelligence` in Node.js code that needs to analyze video with Google Cloud Video Intelligence, including label detection, shot-change detection, text detection, object tracking, and speech transcription.\n\n## Golden Rule\n\n- Import the GA client from the `v1` namespace.\n- Use Application Default Credentials (ADC) unless you have a specific reason to pass credentials explicitly.\n- Treat `annotateVideo()` as an asynchronous long-running operation and wait on `operation.promise()`.\n- Prefer `inputUri` with a `gs://...` object for normal workloads; use `inputContent` only for smaller inputs you can safely hold in memory.\n- Only read response sections that match the features you requested.\n- Use `outputUri` when another system should consume the results later or when the response payload can be large.\n\nThis guide covers `6.2.1`.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/video-intelligence@6.2.1\n```\n\n## Authentication And Setup\n\nThis client uses Google Cloud credentials, not an API key.\n\nEnable the API in the target project:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\ngcloud services enable videointelligence.googleapis.com --project \"$GOOGLE_CLOUD_PROJECT\"\n```\n\nFor local development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\n```\n\nFor a service account JSON file:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-project-id\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nMinimum setup:\n\n1. Enable the Video Intelligence API in the target project.\n2. Make sure the credential resolves to the project and principal you expect.\n3. Store source videos in Cloud Storage when they are too large to load comfortably into memory.\n\n## Initialize The Client\n\nCommonJS:\n\n```javascript\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n```\n\nES modules:\n\n```javascript\nimport {v1 as videoIntelligence} from '@google-cloud/video-intelligence';\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n```\n\nWith explicit project ID and key file:\n\n```javascript\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nIf you already authenticated with `gcloud auth application-default login`, you usually do not need `keyFilename`.\n\n## Core Workflows\n\n### Detect Labels From Cloud Storage\n\nUse `inputUri` for production-style jobs so the client does not need to hold the video bytes in memory.\n\n```javascript\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n\nasync function detectLabels(inputUri) {\n  const [operation] = await client.annotateVideo({\n    inputUri,\n    features: ['LABEL_DETECTION'],\n  });\n\n  const [response] = await operation.promise();\n  const result = response.annotationResults?.[0];\n\n  for (const annotation of result?.segmentLabelAnnotations ?? []) {\n    console.log(annotation.entity?.description);\n  }\n}\n\ndetectLabels('gs://my-bucket/example.mp4').catch(console.error);\n```\n\n### Detect Shot Changes From A Local File\n\nUse `inputContent` for smaller files or test fixtures.\n\n```javascript\nconst fs = require('node:fs/promises');\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n\nasync function detectShots(filePath) {\n  const inputContent = await fs.readFile(filePath);\n\n  const [operation] = await client.annotateVideo({\n    inputContent,\n    features: ['SHOT_CHANGE_DETECTION'],\n  });\n\n  const [response] = await operation.promise();\n  const result = response.annotationResults?.[0];\n\n  for (const shot of result?.shotAnnotations ?? []) {\n    const startSeconds =\n      Number(shot.startTimeOffset?.seconds ?? 0) +\n      Number(shot.startTimeOffset?.nanos ?? 0) / 1e9;\n    const endSeconds =\n      Number(shot.endTimeOffset?.seconds ?? 0) +\n      Number(shot.endTimeOffset?.nanos ?? 0) / 1e9;\n\n    console.log(`${startSeconds.toFixed(2)}s -> ${endSeconds.toFixed(2)}s`);\n  }\n}\n\ndetectShots('./sample.mp4').catch(console.error);\n```\n\n### Transcribe Speech\n\nSpeech transcription needs `videoContext.speechTranscriptionConfig` in addition to the feature flag.\n\n```javascript\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n\nasync function transcribeVideo(inputUri) {\n  const [operation] = await client.annotateVideo({\n    inputUri,\n    features: ['SPEECH_TRANSCRIPTION'],\n    videoContext: {\n      speechTranscriptionConfig: {\n        languageCode: 'en-US',\n        enableAutomaticPunctuation: true,\n      },\n    },\n  });\n\n  const [response] = await operation.promise();\n  const result = response.annotationResults?.[0];\n\n  for (const transcription of result?.speechTranscriptions ?? []) {\n    for (const alternative of transcription.alternatives ?? []) {\n      console.log(alternative.transcript);\n    }\n  }\n}\n\ntranscribeVideo('gs://my-bucket/example.mp4').catch(console.error);\n```\n\n### Write Results To Cloud Storage\n\nSet `outputUri` when you want downstream systems to read the result JSON from Cloud Storage.\n\n```javascript\nconst {v1: videoIntelligence} = require('@google-cloud/video-intelligence');\n\nconst client = new videoIntelligence.VideoIntelligenceServiceClient();\n\nasync function annotateToGcs(inputUri, outputUri) {\n  const [operation] = await client.annotateVideo({\n    inputUri,\n    outputUri,\n    features: ['TEXT_DETECTION'],\n  });\n\n  await operation.promise();\n}\n\nannotateToGcs(\n  'gs://my-bucket/example.mp4',\n  'gs://my-bucket/results/example.json'\n).catch(console.error);\n```\n\n## Response Handling\n\nThe common shape is:\n\n```javascript\nconst [operation] = await client.annotateVideo(request);\nconst [response] = await operation.promise();\nconst result = response.annotationResults?.[0];\n```\n\nThen inspect only the sections for the features you requested, for example:\n\n- `segmentLabelAnnotations`\n- `shotAnnotations`\n- `textAnnotations`\n- `speechTranscriptions`\n- `objectAnnotations`\n- `explicitAnnotation`\n\nDo not assume every section is present. The result is sparse and feature-dependent.\n\n## Common Pitfalls\n\n- `annotateVideo()` is not a synchronous request-response method. It returns a long-running operation.\n- `inputContent` reads the entire file into memory. Use `inputUri` for larger videos.\n- The response only fills fields for the features you requested. Guard property access accordingly.\n- `annotationResults` is an array. Most single-input flows read `annotationResults[0]`.\n- Product examples and generated references may show beta namespaces for preview-era features. Keep the import, request types, and result handling in the same namespace family instead of mixing `v1` with `v1p*beta*` snippets.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/video-intelligence/latest`\n- Video Intelligence product docs: `https://cloud.google.com/video-intelligence/docs`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/video-intelligence`\n"
  },
  {
    "path": "content/google/docs/videointelligence/python/DOC.md",
    "content": "---\nname: videointelligence\ndescription: \"Google Cloud Video Intelligence Python client for asynchronous video annotation and analysis\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.18.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,videointelligence,video,annotation\"\n---\n\n# Google Cloud Video Intelligence Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-videointelligence` package with Application Default Credentials (ADC). The main RPC, `annotate_video()`, starts a long-running operation, so plan for `operation.result(...)` or an `output_uri` in Cloud Storage.\n\n## Install\n\nPin the version if your project is already locked to the older release line:\n\n```bash\npython -m pip install \"google-cloud-videointelligence==2.18.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-videointelligence==2.18.0\"\npoetry add \"google-cloud-videointelligence==2.18.0\"\n```\n\n## Authentication And Setup\n\nBefore you create a client:\n\n1. Select a Google Cloud project.\n2. Enable the Video Intelligence API.\n3. Configure ADC.\n\nEnable the API:\n\n```bash\ngcloud services enable videointelligence.googleapis.com\n```\n\nFor local development, Google's recommended ADC flow is:\n\n```bash\ngcloud auth application-default login\n```\n\nFor non-interactive environments, point ADC at a service account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nIf the API is disabled or ADC is missing, requests fail before annotation starts.\n\n## Initialize The Client\n\nBasic client creation:\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\nclient = videointelligence.VideoIntelligenceServiceClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\nclient = videointelligence.VideoIntelligenceServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nCustom endpoint or standard client options:\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import videointelligence_v1 as videointelligence\n\nclient = videointelligence.VideoIntelligenceServiceClient(\n    client_options=ClientOptions(api_endpoint=\"videointelligence.googleapis.com\")\n)\n```\n\nShort-lived script using a context manager:\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\nwith videointelligence.VideoIntelligenceServiceClient() as client:\n    ...\n```\n\nUse the context-manager form only when you want the client closed at the end of the block. The generated client docs warn that exiting the block closes the underlying transport, which can break other clients sharing it.\n\n## Core Usage\n\n### Label Detection From Google Cloud Storage\n\nUse `input_uri` for normal production workflows so the client does not need to hold the full video in memory.\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\ndef detect_labels(gcs_uri: str) -> None:\n    client = videointelligence.VideoIntelligenceServiceClient()\n\n    operation = client.annotate_video(\n        request={\n            \"input_uri\": gcs_uri,\n            \"features\": [videointelligence.Feature.LABEL_DETECTION],\n        }\n    )\n\n    response = operation.result(timeout=600)\n    result = response.annotation_results[0]\n\n    for annotation in result.segment_label_annotations:\n        print(annotation.entity.description)\n\ndetect_labels(\"gs://cloud-samples-data/video/cat.mp4\")\n```\n\n### Speech Transcription\n\nFeature-specific behavior is configured through `VideoContext`.\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\ndef transcribe_video(gcs_uri: str) -> None:\n    client = videointelligence.VideoIntelligenceServiceClient()\n\n    config = videointelligence.SpeechTranscriptionConfig(\n        language_code=\"en-US\",\n        enable_automatic_punctuation=True,\n    )\n    context = videointelligence.VideoContext(\n        speech_transcription_config=config,\n    )\n\n    operation = client.annotate_video(\n        request={\n            \"input_uri\": gcs_uri,\n            \"features\": [videointelligence.Feature.SPEECH_TRANSCRIPTION],\n            \"video_context\": context,\n        }\n    )\n\n    result = operation.result(timeout=1800).annotation_results[0]\n\n    for transcription in result.speech_transcriptions:\n        for alternative in transcription.alternatives:\n            print(alternative.transcript)\n```\n\n### Local Bytes For Small Inputs\n\n`input_content` is useful for tests or smaller files. Prefer `input_uri` for large videos.\n\n```python\nfrom google.cloud import videointelligence_v1 as videointelligence\n\ndef detect_shots(path: str) -> None:\n    client = videointelligence.VideoIntelligenceServiceClient()\n\n    with open(path, \"rb\") as fh:\n        content = fh.read()\n\n    operation = client.annotate_video(\n        request={\n            \"input_content\": content,\n            \"features\": [videointelligence.Feature.SHOT_CHANGE_DETECTION],\n        }\n    )\n\n    result = operation.result(timeout=600).annotation_results[0]\n\n    for shot in result.shot_annotations:\n        start = shot.start_time_offset.total_seconds()\n        end = shot.end_time_offset.total_seconds()\n        print(f\"{start:.2f}s -> {end:.2f}s\")\n```\n\n### Persist Results To Cloud Storage\n\nFor longer jobs or larger outputs, write results to GCS:\n\n```python\noperation = client.annotate_video(\n    request={\n        \"input_uri\": \"gs://my-bucket/video.mp4\",\n        \"output_uri\": \"gs://my-bucket/results/video-analysis.json\",\n        \"features\": [videointelligence.Feature.TEXT_DETECTION],\n    }\n)\n```\n\n## Response Handling\n\nThe common shape is:\n\n```python\nresponse = operation.result(timeout=600)\nresult = response.annotation_results[0]\n```\n\nThen inspect only the sections for the features you requested, for example:\n\n- `segment_label_annotations`\n- `shot_annotations`\n- `text_annotations`\n- `speech_transcriptions`\n- `explicit_annotation`\n- `object_annotations`\n\nDo not assume every section is populated. The result is sparse and feature-dependent.\n\n## Configuration Notes\n\n- ADC is the default auth path. Avoid hard-coding credentials in source.\n- `client_options` works for endpoint overrides and standard Google client configuration.\n- `timeout` on `operation.result(...)` is a local wait timeout, not the API's processing limit.\n- Use `output_uri` when another system will consume results later or when the response can be large.\n\n## Common Pitfalls\n\n### Treating `annotate_video()` as synchronous\n\nThe RPC returns a long-running operation. Always wait for it or write output to GCS.\n\n### Sending large videos as `input_content`\n\nThis loads the file into process memory. Production jobs should usually use `input_uri`.\n\n### Parsing fields for features you did not request\n\nOnly the result sections for requested features are populated. Guard your access accordingly.\n\n### Closing shared transports accidentally\n\n`with VideoIntelligenceServiceClient() as client:` closes the transport when the block exits. Do not use that pattern if the transport is shared elsewhere.\n\n### Mixing GA and beta namespaces\n\nThe stable client in this package is `videointelligence_v1`. Some Google docs and samples for preview or older features use beta namespaces such as `videointelligence_v1p3beta1`; those request and response types are not interchangeable with the GA client.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI lists `2.18.0` for `google-cloud-videointelligence`.\n- The Google Cloud Python `/latest/changelog` page still tops out at `2.17.0`, so verify the newest patch-level release on PyPI or the repository when you need exact release-history detail.\n- Product quickstarts sometimes show `from google.cloud import videointelligence`, while the generated Python reference is organized under `videointelligence_v1`. This guide uses `videointelligence_v1 as videointelligence` so the client, enums, and reference docs line up exactly.\n\n## Official Sources\n\n- PyPI: `https://pypi.org/project/google-cloud-videointelligence/`\n- Python reference root: `https://cloud.google.com/python/docs/reference/videointelligence/latest`\n- Client reference: `https://cloud.google.com/python/docs/reference/videointelligence/latest/google.cloud.videointelligence_v1.services.video_intelligence_service.VideoIntelligenceServiceClient`\n- Product quickstart: `https://cloud.google.com/video-intelligence/docs/quickstart-client-libraries`\n- Label sample: `https://cloud.google.com/video-intelligence/docs/samples/video-analyze-labels-gcs`\n- ADC setup: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n"
  },
  {
    "path": "content/google/docs/vision/javascript/DOC.md",
    "content": "---\nname: vision\ndescription: \"Google Cloud Vision Node.js client for image annotation, OCR, and async batch annotation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.3.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,vision,gcp,ocr,images,javascript\"\n---\n\n# Google Cloud Vision Node.js Client\n\n## Golden Rule\n\nUse `@google-cloud/vision` with Application Default Credentials (ADC), enable `vision.googleapis.com` in the same Google Cloud project, and reuse a single `ImageAnnotatorClient` for normal request traffic.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install @google-cloud/vision@5.3.4\n```\n\n## Authentication And Project Setup\n\nBefore making API calls, make sure all of the following are true:\n\n1. You have a Google Cloud project.\n2. Billing is enabled for that project.\n3. The Cloud Vision API is enabled.\n4. ADC is configured for the identity your app will run as.\n\nEnable the API:\n\n```bash\ngcloud services enable vision.googleapis.com\n```\n\nFor local development, the standard ADC flow is:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\n```\n\nIf you must use a service account key file outside Google Cloud:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-gcp-project\"\n```\n\nOn Cloud Run, GKE, Cloud Functions, and other Google Cloud runtimes, prefer the attached service account instead of distributing key files.\n\n## Initialize The Client\n\nThe package exposes `ImageAnnotatorClient` from the module namespace:\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n```\n\nIf you need to set the project or key file explicitly:\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient({\n  projectId: process.env.GOOGLE_CLOUD_PROJECT,\n  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,\n});\n```\n\nCreate the client once and reuse it across requests instead of constructing a new client per image.\n\n## Detect Labels From A Local File\n\nUse the convenience helper when you have a local image path:\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n\nasync function detectLabels(fileName) {\n  const [result] = await client.labelDetection(fileName);\n\n  if (result.error?.message) {\n    throw new Error(result.error.message);\n  }\n\n  for (const label of result.labelAnnotations ?? []) {\n    console.log(label.description, label.score);\n  }\n}\n\ndetectLabels('image.jpg').catch(console.error);\n```\n\nThe same helper also accepts a Cloud Storage URI such as `gs://my-bucket/image.jpg`.\n\n## OCR: Short Text vs Document OCR\n\nUse `textDetection` for short or sparse text in images, and `documentTextDetection` for scanned pages, dense text, or structured OCR.\n\n### Short Text\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n\nasync function detectText(fileName) {\n  const [result] = await client.textDetection(fileName);\n\n  if (result.error?.message) {\n    throw new Error(result.error.message);\n  }\n\n  const primaryText = result.textAnnotations?.[0]?.description ?? '';\n  console.log(primaryText);\n}\n\ndetectText('sign.jpg').catch(console.error);\n```\n\n### Dense Document OCR\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n\nasync function detectDocumentText(fileName) {\n  const [result] = await client.documentTextDetection(fileName);\n\n  if (result.error?.message) {\n    throw new Error(result.error.message);\n  }\n\n  console.log(result.fullTextAnnotation?.text ?? '');\n}\n\ndetectDocumentText('document.png').catch(console.error);\n```\n\n## Combine Multiple Features In One Request\n\nUse `batchAnnotateImages` when you want multiple feature passes over the same image in one request.\n\n```javascript\nconst fs = require('node:fs');\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n\nasync function annotateImage(fileName) {\n  const [response] = await client.batchAnnotateImages({\n    requests: [\n      {\n        image: {content: fs.readFileSync(fileName)},\n        features: [\n          {type: 'LABEL_DETECTION'},\n          {type: 'IMAGE_PROPERTIES'},\n        ],\n      },\n    ],\n  });\n\n  const annotated = response.responses?.[0];\n\n  if (annotated?.error?.message) {\n    throw new Error(annotated.error.message);\n  }\n\n  for (const label of annotated?.labelAnnotations ?? []) {\n    console.log(label.description, label.score);\n  }\n\n  const colors = annotated?.imagePropertiesAnnotation?.dominantColors?.colors ?? [];\n  console.log('Dominant colors:', colors.length);\n}\n\nannotateImage('image.jpg').catch(console.error);\n```\n\nInspect the per-image response entry for errors. A successful transport response does not guarantee every annotation inside the batch succeeded.\n\n## Async Batch Annotation With Cloud Storage Output\n\nFor larger image batches or workflows that should write results to Cloud Storage, use `asyncBatchAnnotateImages`.\n\n```javascript\nconst vision = require('@google-cloud/vision');\n\nconst client = new vision.ImageAnnotatorClient();\n\nasync function runAsyncBatch() {\n  const [operation] = await client.asyncBatchAnnotateImages({\n    requests: [\n      {\n        image: {\n          source: {\n            imageUri: 'gs://your-bucket/input/image-1.jpg',\n          },\n        },\n        features: [{type: 'LABEL_DETECTION'}],\n      },\n    ],\n    outputConfig: {\n      gcsDestination: {\n        uri: 'gs://your-bucket/output/',\n      },\n      batchSize: 2,\n    },\n  });\n\n  const [result] = await operation.promise();\n  console.log(result.outputConfig.gcsDestination.uri);\n}\n\nrunAsyncBatch().catch(console.error);\n```\n\nThe calling identity needs Cloud Storage permissions for both the input and output buckets.\n\n## Common Pitfalls\n\n- Missing ADC is the most common failure mode. Start with `gcloud auth application-default login` for local development.\n- A valid credential is not enough if `vision.googleapis.com` is disabled in the project tied to those credentials.\n- `textDetection` and `documentTextDetection` are not interchangeable. Prefer the document variant for dense OCR and scanned pages.\n- Batch APIs can return per-image failures inside `response.responses`. Check `error.message` on each response entry, not just the top-level promise.\n- `gs://...` inputs and outputs require Cloud Storage IAM permissions in addition to Vision API access.\n- Reuse one `ImageAnnotatorClient` in hot paths instead of creating a new client for every request.\n\n## Official Sources\n\n- Node.js client reference: `https://cloud.google.com/nodejs/docs/reference/vision/latest`\n- Vision product documentation: `https://cloud.google.com/vision/docs`\n- Label detection guide: `https://cloud.google.com/vision/docs/detect-labels-image-client-libraries`\n- OCR guide: `https://cloud.google.com/vision/docs/ocr`\n- Dense document OCR guide: `https://cloud.google.com/vision/docs/detecting-fulltext`\n- Async batch annotation sample: `https://cloud.google.com/vision/docs/samples/vision-async-batch-annotate-images`\n- Authentication for client libraries: `https://cloud.google.com/docs/authentication/client-libraries`\n- Set up ADC for local development: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- npm package page: `https://www.npmjs.com/package/@google-cloud/vision`\n"
  },
  {
    "path": "content/google/docs/vision/python/DOC.md",
    "content": "---\nname: vision\ndescription: \"google-cloud-vision package guide for Python Cloud Vision API clients\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.12.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google-cloud,vision,gcp,ocr,images,python\"\n---\n\n# google-cloud-vision Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-vision` with Application Default Credentials (ADC), enable `vision.googleapis.com` in the same Google Cloud project, and reuse a single `ImageAnnotatorClient` for normal request traffic.\n\n## Install\n\n```bash\npip install google-cloud-vision==3.12.1\n```\n\nUse `pip install --upgrade google-cloud-vision` only when you explicitly want the newest release instead of the pinned version used here.\n\n## Setup And Authentication\n\nYou need all of the following before API calls will succeed:\n\n1. A Google Cloud project.\n2. Billing enabled for that project.\n3. The Cloud Vision API enabled.\n4. ADC configured for the identity your code will run as.\n\nEnable the API:\n\n```bash\ngcloud services enable vision.googleapis.com\n```\n\nFor local development, the standard ADC flow is:\n\n```bash\ngcloud auth application-default login\n```\n\nIf you are not running on Google Cloud and must use a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nProduction code on Google Cloud should usually rely on the runtime's attached service account instead of shipping key files.\n\n## Initialize The Client\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n```\n\nThe client uses ADC automatically. Create it once and reuse it for multiple requests instead of constructing a new client per image.\n\nIf you need a non-default endpoint or networking config, pass `client_options`:\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient(\n    client_options={\"api_endpoint\": \"vision.googleapis.com\"}\n)\n```\n\n## Core Usage\n\n### Detect Labels From A Cloud Storage Object\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n\nimage = vision.Image()\nimage.source.image_uri = \"gs://cloud-samples-data/vision/label/wakeupcat.jpg\"\n\nresponse = client.label_detection(image=image)\n\nif response.error.message:\n    raise RuntimeError(response.error.message)\n\nfor label in response.label_annotations:\n    print(label.description, label.score)\n```\n\n### Detect Labels From Local Image Bytes\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n\nwith open(\"image.jpg\", \"rb\") as fh:\n    image = vision.Image(content=fh.read())\n\nresponse = client.label_detection(image=image)\n\nif response.error.message:\n    raise RuntimeError(response.error.message)\n\nfor label in response.label_annotations:\n    print(label.description)\n```\n\n### OCR For Documents And Dense Text\n\nUse `document_text_detection` for scanned pages, forms, and multi-block OCR. It returns the richer `full_text_annotation` tree.\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n\nwith open(\"document.png\", \"rb\") as fh:\n    image = vision.Image(content=fh.read())\n\nresponse = client.document_text_detection(image=image)\n\nif response.error.message:\n    raise RuntimeError(response.error.message)\n\nprint(response.full_text_annotation.text)\n```\n\n### Combine Multiple Features In One Request\n\nUse `batch_annotate_images` when you want multiple feature passes over the same image and a single request/response envelope.\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n\nwith open(\"image.jpg\", \"rb\") as fh:\n    image = vision.Image(content=fh.read())\n\nrequest = vision.AnnotateImageRequest(\n    image=image,\n    features=[\n        vision.Feature(type_=vision.Feature.Type.LABEL_DETECTION),\n        vision.Feature(type_=vision.Feature.Type.IMAGE_PROPERTIES),\n    ],\n)\n\nresponse = client.batch_annotate_images(requests=[request])\nannotated = response.responses[0]\n\nif annotated.error.message:\n    raise RuntimeError(annotated.error.message)\n\nfor label in annotated.label_annotations:\n    print(label.description)\n```\n\n### Large Async Jobs With Cloud Storage Input And Output\n\nFor many images, or when you want results written back to Cloud Storage, use `async_batch_annotate_images`.\n\n```python\nfrom google.cloud import vision\n\nclient = vision.ImageAnnotatorClient()\n\nsource = {\"image_uri\": \"gs://your-bucket/input/image.jpg\"}\nimage = {\"source\": source}\nfeatures = [{\"type_\": vision.Feature.Type.LABEL_DETECTION}]\nrequests = [{\"image\": image, \"features\": features}]\n\noutput_config = {\n    \"gcs_destination\": {\"uri\": \"gs://your-bucket/output/\"},\n    \"batch_size\": 2,\n}\n\noperation = client.async_batch_annotate_images(\n    requests=requests,\n    output_config=output_config,\n)\n\nresult = operation.result(timeout=300)\nprint(result.output_config.gcs_destination.uri)\n```\n\nFor PDFs and TIFFs, use file-oriented methods such as `batch_annotate_files` or `async_batch_annotate_files` instead of image-only methods.\n\n## Configuration Notes\n\n- ADC resolution order matters. Local shells, IDEs, CI jobs, and deployed workloads can each pick up different identities.\n- If you read from or write to `gs://...` URIs, the calling identity also needs the relevant Cloud Storage IAM permissions in addition to Vision API access.\n- The generated reference uses `google.cloud.vision_v1` service namespaces, but normal application imports commonly use `from google.cloud import vision`.\n- Prefer typed request objects and enums for long-lived code. Ad-hoc dict payloads work, but they are easier to get wrong when fields are renamed or nested.\n\n## Common Pitfalls\n\n- Missing ADC is the most common failure mode. `DefaultCredentialsError` usually means you have not run `gcloud auth application-default login`, have the wrong environment variable, or are using credentials from the wrong project.\n- API enablement and credentials must point at the same project. A valid credential alone is not enough if `vision.googleapis.com` is disabled there.\n- `text_detection` and `document_text_detection` are not interchangeable. Prefer the document variant for dense OCR and scanned documents.\n- Per-image failures are returned inside batch responses. Always inspect `response.error.message` or `annotated.error.message`, not just transport success.\n- Cloud Storage input and output require bucket permissions. Vision access does not grant read or write access to `gs://` paths automatically.\n- Reusing the client matters in hot paths. Creating a new client for every request adds avoidable overhead.\n\n## Version-Sensitive Notes For `3.12.1`\n\n- PyPI lists `3.12.1` as the package version covered by this entry.\n- On `2026-03-12`, the official `latest` Python reference pages were also serving `3.12.1`, so the version used here and the current reference root were aligned.\n- On `2026-03-12`, the official Vision Python changelog page still topped out at `3.12.0`. If you need the exact delta from `3.12.0` to `3.12.1`, check the PyPI release page and repository history in addition to the generated changelog.\n\n## Official Sources\n\n- Python reference root: `https://cloud.google.com/python/docs/reference/vision/latest`\n- `ImageAnnotatorClient` reference: `https://cloud.google.com/python/docs/reference/vision/latest/google.cloud.vision_v1.services.image_annotator.ImageAnnotatorClient`\n- Label detection quickstart: `https://cloud.google.com/vision/docs/detect-labels-image-client-libraries`\n- OCR guide: `https://cloud.google.com/vision/docs/detecting-fulltext`\n- Async batch sample: `https://cloud.google.com/vision/docs/samples/vision-async-batch-annotate-images`\n- ADC overview: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Local ADC setup: `https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment`\n- Package registry: `https://pypi.org/project/google-cloud-vision/`\n"
  },
  {
    "path": "content/google/docs/vm-migration/python/DOC.md",
    "content": "---\nname: vm-migration\ndescription: \"Google Cloud VM Migration Python client for target projects, sources, migrating VMs, and clone or cutover jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,gcp,vm-migration,migrate-to-virtual-machines,compute,python\"\n---\n\n# Google Cloud VM Migration Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-vm-migration` package with `from google.cloud import vmmigration_v1`, and authenticate with Application Default Credentials (ADC).\n\nThis API is location-scoped and follows the Migrate to Virtual Machines lifecycle: configure the host project and source, onboard a VM, replicate it, then create clone or cutover jobs and finalize the migration. The Python client is not a shortcut around product setup such as enabling services, installing a Migrate Connector for VMware or VMware Engine, or configuring target details for the VM you plan to migrate.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-vm-migration==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-vm-migration==1.15.0\"\npoetry add \"google-cloud-vm-migration==1.15.0\"\n```\n\nThe official package page for `1.15.0` lists Python `>=3.7`.\n\n## Authentication And Setup\n\nBefore you use the client:\n\n- choose a host project for Migrate to Virtual Machines\n- enable the required services on that host project: `vmmigration.googleapis.com`, `servicemanagement.googleapis.com`, `servicecontrol.googleapis.com`, `iam.googleapis.com`, `cloudresourcemanager.googleapis.com`, and `compute.googleapis.com`\n- grant an IAM role that matches the work: `roles/vmmigration.viewer` for read-only access or `roles/vmmigration.admin` for migration operations\n- prepare at least one migration source\n- if you are migrating from VMware or VMware Engine, install a Migrate Connector in each Google Cloud region you plan to use\n\nLocal ADC setup:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"your-host-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport VM_MIGRATION_SOURCE_ID=\"my-source\"\nexport VM_MIGRATING_VM_ID=\"my-source-vm\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"your-host-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nOptional SDK logging:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google.cloud.vmmigration_v1\"\n```\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import vmmigration_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nLOCATION = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nSOURCE_ID = os.environ[\"VM_MIGRATION_SOURCE_ID\"]\nMIGRATING_VM_ID = os.environ[\"VM_MIGRATING_VM_ID\"]\n\nclient = vmmigration_v1.VmMigrationClient()\n\nparent = client.common_location_path(PROJECT_ID, LOCATION)\nsource_name = client.source_path(PROJECT_ID, LOCATION, SOURCE_ID)\nmigrating_vm_name = client.migrating_vm_path(\n    PROJECT_ID,\n    LOCATION,\n    SOURCE_ID,\n    MIGRATING_VM_ID,\n)\n```\n\nUse the path helpers instead of hard-coding resource names. Most methods expect one of these location-scoped names.\n\n## Core Workflows\n\n### List or add target projects\n\nUse target projects when the migrated Compute Engine VM should land somewhere other than the host project.\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nparent = client.common_location_path(\"your-host-project\", \"us-central1\")\n\nfor target in client.list_target_projects(request={\"parent\": parent}):\n    print(target.name, target.project)\n```\n\nCreate one:\n\n```python\nimport uuid\n\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nparent = client.common_location_path(\"your-host-project\", \"us-central1\")\n\noperation = client.create_target_project(\n    request={\n        \"parent\": parent,\n        \"target_project_id\": \"prod-target\",\n        \"target_project\": vmmigration_v1.TargetProject(\n            project=\"my-compute-project\",\n            description=\"Primary Compute Engine target project\",\n        ),\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\ntarget = operation.result()\nprint(target.name)\nprint(target.project)\n```\n\n### List sources and inspect one source\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nparent = client.common_location_path(\"your-host-project\", \"us-central1\")\n\nfor source in client.list_sources(request={\"parent\": parent, \"page_size\": 50}):\n    print(source.name)\n```\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nsource_name = client.source_path(\"your-host-project\", \"us-central1\", \"my-source\")\n\nsource = client.get_source(request={\"name\": source_name})\nprint(source.name)\nprint(source.description)\n```\n\n### List migrating VMs under a source\n\n`list_migrating_vms()` is scoped to a source, not directly to the location.\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nsource_name = client.source_path(\"your-host-project\", \"us-central1\", \"my-source\")\n\nfor vm in client.list_migrating_vms(\n    request={\n        \"parent\": source_name,\n        \"view\": vmmigration_v1.MigratingVmView.MIGRATING_VM_VIEW_BASIC,\n    }\n):\n    print(vm.name, vm.state)\n```\n\nFetch one VM with the fuller view:\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nmigrating_vm_name = client.migrating_vm_path(\n    \"your-host-project\",\n    \"us-central1\",\n    \"my-source\",\n    \"my-source-vm\",\n)\n\nvm = client.get_migrating_vm(\n    request={\n        \"name\": migrating_vm_name,\n        \"view\": vmmigration_v1.MigratingVmView.MIGRATING_VM_VIEW_FULL,\n    }\n)\n\nprint(vm.name)\nprint(vm.state)\n```\n\n### Start, pause, or resume replication\n\nThese methods act on an existing migrating VM resource.\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nmigrating_vm_name = client.migrating_vm_path(\n    \"your-host-project\",\n    \"us-central1\",\n    \"my-source\",\n    \"my-source-vm\",\n)\n\nclient.start_migration(request={\"name\": migrating_vm_name})\nclient.pause_migration(request={\"name\": migrating_vm_name})\nclient.resume_migration(request={\"name\": migrating_vm_name})\n```\n\nThe product docs say replication runs every two hours by default unless you change the replication policy in the migration target details.\n\n### Create a clone job\n\nClone jobs are the usual test phase before cutover. Wait for the long-running operation to finish.\n\n```python\nimport uuid\n\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nmigrating_vm_name = client.migrating_vm_path(\n    \"your-host-project\",\n    \"us-central1\",\n    \"my-source\",\n    \"my-source-vm\",\n)\n\noperation = client.create_clone_job(\n    request={\n        \"parent\": migrating_vm_name,\n        \"clone_job_id\": \"test-clone-001\",\n        \"clone_job\": vmmigration_v1.CloneJob(),\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\nclone_job = operation.result()\nprint(clone_job.name)\n```\n\nList prior clone jobs:\n\n```python\nfor clone_job in client.list_clone_jobs(request={\"parent\": migrating_vm_name}):\n    print(clone_job.name, clone_job.state)\n```\n\n### Create a cutover job and then finalize\n\nUse cutover only when you are ready to stop the source VM and perform the final sync.\n\n```python\nimport uuid\n\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nmigrating_vm_name = client.migrating_vm_path(\n    \"your-host-project\",\n    \"us-central1\",\n    \"my-source\",\n    \"my-source-vm\",\n)\n\noperation = client.create_cutover_job(\n    request={\n        \"parent\": migrating_vm_name,\n        \"cutover_job_id\": \"cutover-001\",\n        \"cutover_job\": vmmigration_v1.CutoverJob(),\n        \"request_id\": str(uuid.uuid4()),\n    }\n)\n\ncutover_job = operation.result()\nprint(cutover_job.name)\n```\n\nAfter the VM reaches cutover state, finalize the migration:\n\n```python\nfrom google.cloud import vmmigration_v1\n\nclient = vmmigration_v1.VmMigrationClient()\nmigrating_vm_name = client.migrating_vm_path(\n    \"your-host-project\",\n    \"us-central1\",\n    \"my-source\",\n    \"my-source-vm\",\n)\n\nclient.finalize_migration(request={\"name\": migrating_vm_name})\n```\n\n## Common Pitfalls\n\n- The package name is `google-cloud-vm-migration`, but the import path is `from google.cloud import vmmigration_v1`.\n- Resources are region-scoped. Use the same location that you used when you prepared the source and, for VMware-based sources, the connector.\n- If you migrate VMware or VMware Engine workloads to multiple regions, Google requires a separate Migrate Connector per region.\n- Clone and cutover jobs depend on target details already being configured for the migrating VM. If target project, zone, machine settings, or licensing are still incomplete, the job can fail even though the API call itself is correct.\n- Mutating calls such as `create_target_project()`, `create_clone_job()`, and `create_cutover_job()` return long-running operations. Call `.result()` before assuming the change is complete.\n- Use `request_id` on mutating calls so retries stay idempotent.\n- The product docs cap in-progress migrations at 200 per host project and region, excluding migrations already in finalize.\n- Finalize deletes replication data and other migration resources, but it does not delete Compute Engine instances or test-clone resources you already created.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-vm-migration 1.15.0` released on January 15, 2026.\n- As of March 13, 2026, Google Cloud's `latest` Python reference pages for this library still show mixed generated page versions such as `1.14.0`, `1.13.0`, and `1.12.x`. The v1 surface used above is still the current maintainer reference, but expect page headers in the docs to lag the package release.\n\n## Official Sources\n\n- Python client library overview: https://cloud.google.com/python/docs/reference/vmmigration/latest\n- `VmMigrationClient` reference: https://docs.cloud.google.com/python/docs/reference/vmmigration/latest/google.cloud.vmmigration_v1.services.vm_migration.VmMigrationClient\n- Target project types: https://cloud.google.com/python/docs/reference/vmmigration/latest/google.cloud.vmmigration_v1.types.TargetProject\n- Enable services and IAM roles: https://docs.cloud.google.com/migrate/virtual-machines/docs/5.0/get-started/enable-services\n- VMware source and per-region connector guidance: https://docs.cloud.google.com/migrate/virtual-machines/docs/5.0/migrate/create-a-vmware-source\n- Migration lifecycle, replication interval, clone, cutover, and finalize behavior: https://docs.cloud.google.com/migrate/virtual-machines/docs/5.0/migrate/migrating-vms\n- Finalize behavior reference: https://cloud.google.com/migrate/virtual-machines/docs/5.0/discover/lifecycle\n- PyPI package and release history: https://pypi.org/project/google-cloud-vm-migration/\n"
  },
  {
    "path": "content/google/docs/vmwareengine/python/DOC.md",
    "content": "---\nname: vmwareengine\ndescription: \"Python package guide for google-cloud-vmwareengine, the Google Cloud VMware Engine client library\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,vmware-engine,gcp,virtualization,private-cloud,python\"\n---\n\n# google-cloud-vmwareengine Python Package Guide\n\n`google-cloud-vmwareengine` is the official Python client for Google Cloud VMware Engine.\nInstall the package from PyPI, authenticate with Application Default Credentials (ADC), import `vmwareengine_v1`, and use `VmwareEngineClient` for VMware Engine resources and long-running operations.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-vmwareengine==1.10.0\"\n```\n\nOther common package managers:\n\n```bash\nuv add \"google-cloud-vmwareengine==1.10.0\"\npoetry add \"google-cloud-vmwareengine==1.10.0\"\n```\n\nPyPI lists `1.10.0` as the current release and `Python >=3.7` as the package requirement.\n\n## Prerequisites\n\nBefore creating or modifying VMware Engine resources, make sure you have:\n\n- a Google Cloud project with billing enabled\n- the VMware Engine API enabled\n- enough VMware Engine node quota for the region you want to use\n- IAM permissions for the VMware Engine resources you will manage\n- a non-overlapping management CIDR block for each private cloud\n\nThe product docs say each private cloud must start with at least three nodes, and the vSphere/vSAN management CIDR must use a prefix between `/24` and `/20`.\n\n## Authentication And Environment\n\nFor local development, use ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_VMWAREENGINE_ZONE=\"us-central1-a\"\nexport GOOGLE_CLOUD_VMWAREENGINE_NETWORK_LOCATION=\"global\"\n```\n\nIf you cannot use user credentials, point ADC at a service account key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/service-account.json\"\n```\n\nPrefer attached service accounts or service account impersonation over long-lived key files when your runtime supports them.\n\n## Initialize A Client\n\n```python\nimport os\n\nfrom google.cloud import vmwareengine_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_VMWAREENGINE_ZONE\"]  # example: us-central1-a\nNETWORK_LOCATION = os.getenv(\"GOOGLE_CLOUD_VMWAREENGINE_NETWORK_LOCATION\", \"global\")\n\nclient = vmwareengine_v1.VmwareEngineClient()\n```\n\nExplicit credentials also work:\n\n```python\nimport os\n\nfrom google.cloud import vmwareengine_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nclient = vmwareengine_v1.VmwareEngineClient(credentials=credentials)\n```\n\n## Common Workflows\n\n### List available locations\n\n```python\nfrom google.cloud import vmwareengine_v1\nfrom google.cloud.location.locations_pb2 import ListLocationsRequest\n\nclient = vmwareengine_v1.VmwareEngineClient()\nrequest = ListLocationsRequest(name=f\"projects/{PROJECT_ID}\")\n\nfor location in client.list_locations(request=request):\n    print(location.name)\n```\n\n### List VMware Engine networks\n\nUse `global` for Standard VMware Engine networks. Older legacy-network flows use a regional parent instead.\n\n```python\nfrom google.cloud import vmwareengine_v1\n\nclient = vmwareengine_v1.VmwareEngineClient()\n\nfor network in client.list_vmware_engine_networks(\n    parent=f\"projects/{PROJECT_ID}/locations/{NETWORK_LOCATION}\"\n):\n    print(network.name)\n```\n\nThe returned `network.name` is the resource name you pass into private-cloud creation.\n\n### Create a private cloud\n\nPrivate-cloud creation is a long-running operation. The official sample notes that it may take over an hour.\n\n```python\nimport os\n\nfrom google.cloud import vmwareengine_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_VMWAREENGINE_ZONE\"]  # example: us-central1-a\nNETWORK_NAME = os.environ[\"GOOGLE_CLOUD_VMWAREENGINE_NETWORK\"]\n\nPRIVATE_CLOUD_ID = \"example-private-cloud\"\nCLUSTER_ID = \"management-cluster-1\"\nMANAGEMENT_CIDR = \"192.168.0.0/24\"\nNODE_COUNT = 3\n\nrequest = vmwareengine_v1.CreatePrivateCloudRequest()\nrequest.parent = f\"projects/{PROJECT_ID}/locations/{ZONE}\"\nrequest.private_cloud_id = PRIVATE_CLOUD_ID\nrequest.private_cloud = vmwareengine_v1.PrivateCloud()\n\nrequest.private_cloud.management_cluster = (\n    vmwareengine_v1.PrivateCloud.ManagementCluster()\n)\nrequest.private_cloud.management_cluster.cluster_id = CLUSTER_ID\n\nnode_config = vmwareengine_v1.NodeTypeConfig()\nnode_config.node_count = NODE_COUNT\n\n# The official sample notes that standard-72 is the supported node type here.\nrequest.private_cloud.management_cluster.node_type_configs = {\n    \"standard-72\": node_config\n}\n\nrequest.private_cloud.network_config = vmwareengine_v1.NetworkConfig()\nrequest.private_cloud.network_config.vmware_engine_network = NETWORK_NAME\nrequest.private_cloud.network_config.management_cidr = MANAGEMENT_CIDR\n\nclient = vmwareengine_v1.VmwareEngineClient()\noperation = client.create_private_cloud(request=request)\nprivate_cloud = operation.result(timeout=7200)\n\nprint(private_cloud.name)\n```\n\n`GOOGLE_CLOUD_VMWAREENGINE_NETWORK` must be the full resource name of an existing VMware Engine network, for example the `.name` you got from `list_vmware_engine_networks(...)`.\n\n### List clusters in a private cloud\n\n```python\nfrom google.cloud import vmwareengine_v1\n\nPROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nZONE = os.environ[\"GOOGLE_CLOUD_VMWAREENGINE_ZONE\"]\nPRIVATE_CLOUD_ID = \"example-private-cloud\"\n\nclient = vmwareengine_v1.VmwareEngineClient()\n\nfor cluster in client.list_clusters(\n    parent=(\n        f\"projects/{PROJECT_ID}/locations/{ZONE}/privateClouds/{PRIVATE_CLOUD_ID}\"\n    )\n):\n    print(cluster.name)\n```\n\n### Re-check a long-running operation by name\n\nIf you persist the operation name from a prior response, you can fetch it again later:\n\n```python\nfrom google.cloud import vmwareengine_v1\nfrom google.longrunning.operations_pb2 import GetOperationRequest\n\noperation_name = \"projects/my-project/locations/us-central1/operations/operation-id\"\n\nclient = vmwareengine_v1.VmwareEngineClient()\nrequest = GetOperationRequest(name=operation_name)\noperation = client.get_operation(request=request)\n\nprint(operation.name)\nprint(operation.done)\n```\n\n## Common Pitfalls\n\n- The PyPI package name is `google-cloud-vmwareengine`, but the import is `from google.cloud import vmwareengine_v1`.\n- Private clouds are zonal resources such as `us-central1-a`; network resources may use a different location scope. Standard VMware Engine network docs use `locations/global`.\n- Your management CIDR must not overlap with on-prem, VPC, or planned workload subnets, and you cannot change that range later without deleting the private cloud.\n- Private-cloud creation is not immediate. Wait for the returned operation instead of assuming the resource exists as soon as `create_private_cloud()` returns.\n- Newer projects use Standard VMware Engine networks. Google’s current product docs describe Standard networks under `global`, while some Python samples still demonstrate legacy-network flows for older projects.\n- This client uses gRPC. Google’s multiprocessing guidance says to create client instances after `os.fork()` in child processes, not before.\n\n## Version-Sensitive Notes\n\nAs of `2026-03-13`, the package and hosted reference pages are not fully aligned:\n\n- PyPI lists `google-cloud-vmwareengine 1.10.0`.\n- The hosted `latest` reference pages and changelog still show version labels from `1.9.0` or earlier on some pages.\n\nTreat `1.10.0` as the dependency version to install, but verify newly added methods or fields against the exact hosted page you are reading if you run into a mismatch.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/google-cloud-vmwareengine/\n- Google Cloud Python reference root: https://cloud.google.com/python/docs/reference/vmwareengine/latest\n- `VmwareEngineClient` reference: https://cloud.google.com/python/docs/reference/vmwareengine/latest/google.cloud.vmwareengine_v1.services.vmware_engine.VmwareEngineClient\n- Changelog: https://cloud.google.com/python/docs/reference/vmwareengine/latest/changelog\n- Multiprocessing guidance: https://cloud.google.com/python/docs/reference/vmwareengine/latest/multiprocessing\n- ADC local setup: https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment\n- VMware Engine API access and quota: https://cloud.google.com/vmware-engine/docs/quickstart-prerequisites\n- VMware Engine networking requirements: https://cloud.google.com/vmware-engine/docs/quickstart-networking-requirements\n- List locations sample: https://cloud.google.com/vmware-engine/docs/samples/vmwareengine-list-locations\n- List networks sample: https://cloud.google.com/vmware-engine/docs/samples/vmwareengine-list-networks\n- Create private cloud sample: https://cloud.google.com/vmware-engine/docs/samples/vmwareengine-create-private-cloud\n- List clusters sample: https://cloud.google.com/vmware-engine/docs/samples/vmwareengine-list-clusters\n- Get operation sample: https://cloud.google.com/vmware-engine/docs/samples/vmwareengine-get-operation\n- Standard VMware Engine network guide: https://cloud.google.com/vmware-engine/docs/networking/howto-create-vmware-engine-network\n"
  },
  {
    "path": "content/google/docs/vpc-access/python/DOC.md",
    "content": "---\nname: vpc-access\ndescription: \"Google Cloud Serverless VPC Access Python client for creating, listing, inspecting, and deleting VPC connectors\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,gcp,google-cloud,vpc-access,serverless-vpc-access,networking,python\"\n---\n\n# google-cloud-vpc-access Python Package Guide\n\n## What This Package Is\n\n`google-cloud-vpc-access` is the official Python client for the Serverless VPC Access API. Use it to manage connector resources that let App Engine, Cloud Functions, and Cloud Run reach resources on a VPC network.\n\nThis package manages the connector itself. It does not deploy or reconfigure your Cloud Run, Cloud Functions, or App Engine services to use that connector.\n\n## Version Note\n\nThis guide targets `google-cloud-vpc-access==1.15.0`, which PyPI lists as the current release as of `2026-03-13`.\n\nImport path:\n\n```python\nfrom google.cloud import vpcaccess_v1\n```\n\nPyPI currently lists `Python >=3.7`.\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-vpc-access==1.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-vpc-access==1.15.0\"\npoetry add \"google-cloud-vpc-access==1.15.0\"\n```\n\n## Authentication And Prerequisites\n\nBefore creating connectors:\n\n1. Choose the Google Cloud project that will own the connector.\n2. Enable billing for that project.\n3. Enable the Serverless VPC Access API.\n4. Configure Application Default Credentials (ADC).\n\nEnable the API:\n\n```bash\ngcloud services enable vpcaccess.googleapis.com\n```\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\nexport GOOGLE_CLOUD_NETWORK=\"default\"\nexport GOOGLE_CLOUD_SUBNET=\"serverless-subnet\"\n```\n\nService account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nUse a regional location such as `us-central1`. Product docs note that the connector region must match the region of the serverless service that will use it.\n\nIf you are connecting Cloud Run and Direct VPC egress satisfies your requirements, Google recommends Direct VPC egress instead of a connector. Use this package when you specifically need Serverless VPC Access connectors.\n\n## Client Initialization\n\nDefault client with ADC:\n\n```python\nfrom google.cloud import vpcaccess_v1\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\n```\n\nExplicit service account file:\n\n```python\nfrom google.cloud import vpcaccess_v1\n\nclient = vpcaccess_v1.VpcAccessServiceClient.from_service_account_file(\n    \"/absolute/path/service-account.json\"\n)\n```\n\nUseful resource helpers:\n\n```python\nfrom google.cloud import vpcaccess_v1\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\n\nparent = client.common_location_path(\"my-project\", \"us-central1\")\nconnector_name = client.connector_path(\"my-project\", \"us-central1\", \"orders-vpc\")\n```\n\nConnector resource names use:\n\n- parent: `projects/{project_id}/locations/{region}`\n- connector: `projects/{project_id}/locations/{region}/connectors/{connector_id}`\n\n## Core Usage\n\n### List connectors in a region\n\n```python\nimport os\n\nfrom google.cloud import vpcaccess_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\nparent = client.common_location_path(project_id, location)\n\nfor connector in client.list_connectors(parent=parent):\n    state = vpcaccess_v1.Connector.State(connector.state).name\n    print(connector.name, state)\n```\n\n### Create a connector on an existing subnet\n\nUse this when you already created a dedicated subnet for the connector.\n\n```python\nimport os\n\nfrom google.cloud import vpcaccess_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nnetwork = os.environ[\"GOOGLE_CLOUD_NETWORK\"]\nsubnet = os.environ[\"GOOGLE_CLOUD_SUBNET\"]\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\nparent = client.common_location_path(project_id, location)\n\noperation = client.create_connector(\n    parent=parent,\n    connector_id=\"orders-vpc\",\n    connector=vpcaccess_v1.Connector(\n        network=network,\n        subnet=vpcaccess_v1.Connector.Subnet(name=subnet),\n        machine_type=\"e2-micro\",\n        min_instances=2,\n        max_instances=3,\n    ),\n)\n\nconnector = operation.result(timeout=1800)\nprint(connector.name)\n```\n\n### Create a connector and let Google create a new `/28` subnet\n\nUse this when you want Google Cloud to create the connector subnet from an unused CIDR range.\n\n```python\nimport os\n\nfrom google.cloud import vpcaccess_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\nnetwork = os.environ[\"GOOGLE_CLOUD_NETWORK\"]\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\nparent = client.common_location_path(project_id, location)\n\noperation = client.create_connector(\n    parent=parent,\n    connector_id=\"orders-vpc\",\n    connector=vpcaccess_v1.Connector(\n        network=network,\n        ip_cidr_range=\"10.8.0.0/28\",\n        machine_type=\"e2-micro\",\n        min_instances=2,\n        max_instances=3,\n    ),\n)\n\nconnector = operation.result(timeout=1800)\nprint(connector.name)\n```\n\n### Get one connector and inspect status\n\n`get_connector()` is the simplest way to confirm the final connector state after creation.\n\n```python\nimport os\n\nfrom google.cloud import vpcaccess_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\nname = client.connector_path(project_id, location, \"orders-vpc\")\n\nconnector = client.get_connector(name=name)\n\nprint(connector.name)\nprint(vpcaccess_v1.Connector.State(connector.state).name)\nprint(list(connector.connected_projects))\n```\n\nThe connector is ready to use when its state is `READY`.\n\n### Delete a connector\n\nDelete is also a long-running operation.\n\n```python\nimport os\n\nfrom google.cloud import vpcaccess_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ[\"GOOGLE_CLOUD_LOCATION\"]\n\nclient = vpcaccess_v1.VpcAccessServiceClient()\nname = client.connector_path(project_id, location, \"orders-vpc\")\n\noperation = client.delete_connector(name=name)\noperation.result(timeout=1800)\nprint(f\"Deleted {name}\")\n```\n\n## Operational Notes\n\n- The client surface is intentionally small: `create_connector()`, `list_connectors()`, `get_connector()`, and `delete_connector()` are the main operations.\n- Create and delete both return long-running operations. Wait for `.result()` before assuming the connector exists or is gone.\n- Connector states include `READY`, `CREATING`, `DELETING`, `ERROR`, and `UPDATING`.\n- `connected_projects` is output-only and is useful for checking which projects still rely on a connector before cleanup.\n\n## Common Pitfalls\n\n- Connector names must follow Compute Engine naming rules, must be less than 21 characters long, and hyphens count as two characters.\n- The connector region must match the region of the serverless resource that will use it.\n- A connector subnet must stay `/28`. If you let Google create the subnet, choose an unused `/28` CIDR range that does not conflict with existing routes.\n- Product docs note that if the connector scales up to its configured maximum number of instances, it does not scale back down automatically.\n- Before deleting a connector, remove it from any Cloud Run, Cloud Functions, or App Engine resources that still use it.\n- If you create a connector in a service project that targets a Shared VPC network in a host project, Google requires the subnet to exist first and requires additional firewall rules for connector traffic.\n\n## Optional Logging\n\nGoogle's PyPI docs describe an environment-variable-based logging switch for Google client libraries:\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=\"google.cloud.vpcaccess_v1\"\n```\n\nThat enables default structured logging for this library without changing application code.\n\n## Official Sources\n\n- Python client reference root: https://cloud.google.com/python/docs/reference/vpcaccess/latest\n- `VpcAccessServiceClient` reference: https://docs.cloud.google.com/python/docs/reference/vpcaccess/latest/google.cloud.vpcaccess_v1.services.vpc_access_service.VpcAccessServiceClient\n- `Connector` type reference: https://docs.cloud.google.com/python/docs/reference/vpcaccess/latest/google.cloud.vpcaccess_v1.types.Connector\n- PyPI package page: https://pypi.org/project/google-cloud-vpc-access/\n- Serverless VPC Access product guide: https://cloud.google.com/vpc/docs/configure-serverless-vpc-access\n- Cloud Run connectors guide: https://cloud.google.com/run/docs/configuring/vpc-connectors\n- Cloud Run Direct VPC egress guide: https://cloud.google.com/run/docs/configuring/vpc-direct-vpc\n"
  },
  {
    "path": "content/google/docs/webrisk/python/DOC.md",
    "content": "---\nname: webrisk\ndescription: \"Google Cloud Web Risk Python client for URI lookups, hash-prefix lookups, threat-list diff updates, and submission of suspected phishing URLs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.20.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,webrisk,safebrowsing,security,malware,phishing,python\"\n---\n\n# Google Cloud Web Risk Python Client\n\n## Golden Rule\n\nUse the official `google-cloud-webrisk` package with `from google.cloud import webrisk_v1`, authenticate with Application Default Credentials (ADC), and choose the API surface that matches your design:\n\n- `search_uris()` for direct server-side URL checks\n- `compute_threat_list_diff()` plus `search_hashes()` only if you are maintaining a local threat database\n- `create_submission()` only for the submission workflow, and only when your project is allowlisted for it\n\nPrefer the `v1` client unless you have a specific reason to target older beta surfaces.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"google-cloud-webrisk==1.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-webrisk==1.20.0\"\npoetry add \"google-cloud-webrisk==1.20.0\"\n```\n\nPrerequisites:\n\n- a Google Cloud project with billing enabled\n- the Web Risk API enabled for that project\n- credentials that can call Google Cloud APIs\n\n## Authentication And Setup\n\nFor local development, Google recommends ADC:\n\n```bash\ngcloud auth application-default login\n```\n\nFor service-account based setups, point ADC at the key file:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\n```\n\nThe client library uses the standard Cloud Platform OAuth scope. If you create credentials explicitly, include that scope:\n\n```python\nfrom google.cloud import webrisk_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\",\n    scopes=[\"https://www.googleapis.com/auth/cloud-platform\"],\n)\n\nclient = webrisk_v1.WebRiskServiceClient(credentials=credentials)\n```\n\nDefault client initialization with ADC:\n\n```python\nfrom google.cloud import webrisk_v1\n\nclient = webrisk_v1.WebRiskServiceClient()\n```\n\nReuse the client for multiple requests instead of constructing one per URL.\n\n## Lookup API: Check A URL Directly\n\nUse `search_uris()` when you want Google to do the lookup remotely and return a positive match, if any. The product docs note that the Lookup API takes one URL per request and the URL does not need to be canonicalized first.\n\n```python\nfrom google.cloud import webrisk_v1\n\nTHREAT_TYPES = [\n    webrisk_v1.ThreatType.MALWARE,\n    webrisk_v1.ThreatType.SOCIAL_ENGINEERING,\n    webrisk_v1.ThreatType.UNWANTED_SOFTWARE,\n    webrisk_v1.ThreatType.SOCIAL_ENGINEERING_EXTENDED_COVERAGE,\n]\n\nclient = webrisk_v1.WebRiskServiceClient()\n\nresponse = client.search_uris(\n    uri=\"https://example.com\",\n    threat_types=THREAT_TYPES,\n)\n\nif response.threat and response.threat.threat_types:\n    print(\"Matched threat types:\", response.threat.threat_types)\n    print(\"Cache positive result until:\", response.threat.expire_time)\nelse:\n    print(\"No threat match\")\n```\n\nUse the returned `expire_time` as the positive-cache TTL. If there is no match, the response is empty.\n\n## Update API: Maintain A Local Threat Database\n\nUse the Update API when you need privacy-preserving checks or high-volume local lookups. This flow is more work than `search_uris()`:\n\n1. fetch diffs with `compute_threat_list_diff()`\n2. apply additions and removals to your local store\n3. hash URL expressions locally and look up matching full hashes with `search_hashes()`\n4. persist the returned version token per threat type\n\nMinimal diff request:\n\n```python\nfrom google.cloud import webrisk_v1\n\nclient = webrisk_v1.WebRiskServiceClient()\n\nconstraints = webrisk_v1.ComputeThreatListDiffRequest.Constraints(\n    max_diff_entries=1 << 10,\n    max_database_entries=1 << 20,\n    supported_compressions=[\n        webrisk_v1.CompressionType.RAW,\n        webrisk_v1.CompressionType.RICE,\n    ],\n)\n\nresponse = client.compute_threat_list_diff(\n    threat_type=webrisk_v1.ThreatType.MALWARE,\n    version_token=b\"\",\n    constraints=constraints,\n)\n\nprint(\"Response type:\", response.response_type)\nprint(\"Next token:\", response.new_version_token)\nprint(\"Recommended next diff:\", response.recommended_next_diff)\n\nif response.checksum and response.checksum.sha256:\n    print(\"SHA256 checksum:\", response.checksum.sha256.hex())\n```\n\nPractical notes from the API reference:\n\n- `version_token` is an opaque byte string. Store it exactly as returned and send it back on the next diff request for the same threat type.\n- `max_diff_entries` and `max_database_entries` must be powers of two between `2**10` and `2**20`.\n- `recommended_next_diff` is the server-side backoff hint for your next update request.\n- When the response type indicates a reset, rebuild the local state from the returned data instead of trying to apply it as an incremental patch.\n\n### Confirm A Full Hash After A Local Prefix Match\n\n`search_hashes()` is for a hash prefix you already derived from your local Update API pipeline. It is not a shortcut for passing raw URLs.\n\n```python\nfrom google.cloud import webrisk_v1\n\nclient = webrisk_v1.WebRiskServiceClient()\n\nresponse = client.search_hashes(\n    hash_prefix=bytes.fromhex(\"00112233\"),\n    threat_types=[\n        webrisk_v1.ThreatType.MALWARE,\n        webrisk_v1.ThreatType.SOCIAL_ENGINEERING,\n    ],\n)\n\nfor threat_hash in response.threats:\n    print(\"Full hash:\", threat_hash.hash_.hex())\n    print(\"Threat types:\", threat_hash.threat_types)\n    print(\"Cache until:\", threat_hash.expire_time)\n\nprint(\"Negative cache until:\", response.negative_expire_time)\n```\n\nIf you are implementing the full Update API flow, the product docs also require URL canonicalization, generation of suffix and prefix expressions, and SHA-256 hashing before you ever call `search_hashes()`.\n\n## Submission API: Report A Suspected Phishing URL\n\nThe Python client exposes `create_submission()`. The maintainer reference says this method is for URIs suspected of containing phishing content. The product REST reference also notes that submitting malicious URLs is an Early Access feature and your project must be allowlisted first.\n\n`parent` uses the project number, not the project ID:\n\n```python\nfrom google.cloud import webrisk_v1\n\nclient = webrisk_v1.WebRiskServiceClient()\n\nsubmission = webrisk_v1.Submission(\n    uri=\"https://example.invalid/login\",\n)\n\nresponse = client.create_submission(\n    parent=\"projects/123456789012\",\n    submission=submission,\n)\n\nprint(response)\n```\n\nDo not build your normal URL-check path around submissions. Use it only when you are explicitly reporting content and your project is enabled for that workflow.\n\n## Endpoint And Transport Notes\n\n`WebRiskServiceClient` accepts standard Google API `client_options`, including a custom `api_endpoint`. This matters if you need to force an endpoint instead of relying on the library's endpoint and mTLS environment detection.\n\n```python\nfrom google.api_core.client_options import ClientOptions\nfrom google.cloud import webrisk_v1\n\nclient = webrisk_v1.WebRiskServiceClient(\n    client_options=ClientOptions(api_endpoint=\"webrisk.googleapis.com\")\n)\n```\n\nAdvanced environment variables used by Google API clients:\n\n```bash\nexport GOOGLE_API_USE_MTLS_ENDPOINT=\"never\"\nexport GOOGLE_API_USE_CLIENT_CERTIFICATE=\"false\"\n```\n\nOnly set those when you actually need to control endpoint selection or mTLS behavior.\n\n## Common Pitfalls\n\n- Install `google-cloud-webrisk`, but import from `google.cloud import webrisk_v1`.\n- `search_uris()` and `search_hashes()` solve different problems. Do not hash a raw URL and treat that as a replacement for the full Update API pipeline.\n- The library does not manage your local threat database for you. If you use `compute_threat_list_diff()`, you must store version tokens, apply resets and diffs, and verify checksums yourself.\n- Cache lifetimes matter. Positive URI and hash matches include expiration times, and hash lookups also return `negative_expire_time` for safe negative caching.\n- The submission workflow is gated. If `create_submission()` is central to your integration, confirm project allowlisting before you depend on it.\n\n## Version-Sensitive Notes\n\n- This guide targets `google-cloud-webrisk==1.20.0`.\n- The official changelog entry for `1.20.0` notes automatic mTLS enablement when a client certificate is available and the relevant environment settings request it. If endpoint selection changes unexpectedly after an upgrade, set `client_options.api_endpoint` explicitly and review the `GOOGLE_API_USE_MTLS_ENDPOINT` and `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variables.\n\n## Official Sources\n\n- Python client reference root: https://cloud.google.com/python/docs/reference/webrisk/latest\n- `WebRiskServiceClient` reference: https://cloud.google.com/python/docs/reference/webrisk/latest/google.cloud.webrisk_v1.services.web_risk_service.WebRiskServiceClient\n- Web Risk Lookup API guide: https://cloud.google.com/web-risk/docs/lookup-api\n- Web Risk Update API guide: https://cloud.google.com/web-risk/docs/update-api\n- Web Risk REST reference: https://cloud.google.com/web-risk/docs/reference/rest\n- Web Risk RPC reference: https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1\n- Google Cloud ADC overview: https://cloud.google.com/docs/authentication/provide-credentials-adc\n- `gcloud auth application-default login`: https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login\n- Package page: https://pypi.org/project/google-cloud-webrisk/\n- Changelog: https://cloud.google.com/python/docs/reference/webrisk/latest/changelog\n"
  },
  {
    "path": "content/google/docs/websecurityscanner/python/DOC.md",
    "content": "---\nname: websecurityscanner\ndescription: \"google-cloud-websecurityscanner package guide for Python covering ADC setup, scan configs, scan runs, findings, and authenticated-scan caveats\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.19.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google-cloud,web-security-scanner,security-command-center,vulnerability-scanning,google-cloud-websecurityscanner,python\"\n---\n\n# google-cloud-websecurityscanner Python Package Guide\n\n## Golden Rule\n\nUse `google-cloud-websecurityscanner` with `from google.cloud import websecurityscanner_v1`, authenticate with Application Default Credentials (ADC), and model your code around the package's persistent resource flow:\n\n1. create or update a `ScanConfig`\n2. start a `ScanRun`\n3. poll the run state\n4. read findings and finding-type stats\n\nThis client is for the current Web Security Scanner API surface. The current Google Cloud product docs describe custom scans as part of Security Command Center, so make sure the target project has the required product/API enablement before you debug Python code.\n\n## Version Notes\n\nThis guide is written for PyPI package version `1.19.0`.\n\nGoogle's package landing page is current, but some deep generated-reference pages still render older package versions such as `1.17.2` or `1.18.0` in the page header. Use `1.19.0` for dependency pinning, and use the latest reference pages for method names, request types, and field names.\n\n## Install\n\n```bash\npython -m pip install \"google-cloud-websecurityscanner==1.19.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-websecurityscanner==1.19.0\"\npoetry add \"google-cloud-websecurityscanner==1.19.0\"\n```\n\n## Authentication And Setup\n\nBefore calling the client:\n\n1. enable the target Google Cloud project for Web Security Scanner / Security Command Center as required by your scan workflow\n2. grant the calling identity permission to manage scan configs and runs\n3. authenticate locally with ADC, or use a runtime-attached service account in production\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\ngcloud config set project YOUR_PROJECT_ID\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nService-account key fallback:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"YOUR_PROJECT_ID\"\n```\n\nMinimal client initialization:\n\n```python\nimport os\n\nfrom google.cloud import websecurityscanner_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nproject_name = f\"projects/{project_id}\"\n\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n```\n\nExplicit credentials object:\n\n```python\nimport os\n\nfrom google.cloud import websecurityscanner_v1\nfrom google.oauth2 import service_account\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nproject_name = f\"projects/{project_id}\"\n\ncredentials = service_account.Credentials.from_service_account_file(\n    os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n)\n\nclient = websecurityscanner_v1.WebSecurityScannerClient(credentials=credentials)\n```\n\n## Core Workflow\n\n### List Existing Scan Configs\n\n```python\nimport os\n\nfrom google.cloud import websecurityscanner_v1\n\nproject_name = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}\"\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nrequest = websecurityscanner_v1.ListScanConfigsRequest(parent=project_name)\n\nfor scan_config in client.list_scan_configs(request=request):\n    print(scan_config.name, scan_config.display_name)\n```\n\n### Create A Scan Config\n\nThe minimum useful config is a display name plus one or more starting URLs.\n\n```python\nimport os\n\nfrom google.cloud import websecurityscanner_v1\n\nproject_name = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}\"\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nscan_config = websecurityscanner_v1.ScanConfig(\n    display_name=\"staging-weekly-scan\",\n    starting_urls=[\"https://staging.example.com/\"],\n    max_qps=15,\n)\n\ncreated = client.create_scan_config(\n    request=websecurityscanner_v1.CreateScanConfigRequest(\n        parent=project_name,\n        scan_config=scan_config,\n    )\n)\n\nprint(created.name)\n```\n\nUseful fields from the `ScanConfig` type:\n\n- `starting_urls`: required scan entry points\n- `max_qps`: crawler request rate\n- `blacklist_patterns`: URL patterns to exclude\n- `ignore_http_status_errors`: whether non-2xx/3xx responses should fail the scan less aggressively\n- `static_ip_scan`: preview feature for static-IP custom scans\n\n### Start A Scan Run And Poll Until Completion\n\nGoogle's product docs note that a scan can stay queued for a while and might take hours before it starts, so poll for state instead of assuming immediate execution.\n\n```python\nimport os\nimport time\n\nfrom google.cloud import websecurityscanner_v1\n\nproject_name = f\"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}\"\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nscan_config = next(\n    client.list_scan_configs(\n        request=websecurityscanner_v1.ListScanConfigsRequest(parent=project_name)\n    )\n)\n\nscan_run = client.start_scan_run(\n    request=websecurityscanner_v1.StartScanRunRequest(\n        name=scan_config.name,\n    )\n)\n\nwhile True:\n    current = client.get_scan_run(request={\"name\": scan_run.name})\n    state = current.execution_state\n    print(current.name, state)\n\n    if state in (\n        websecurityscanner_v1.ScanRun.ExecutionState.FINISHED,\n        websecurityscanner_v1.ScanRun.ExecutionState.ERROR,\n        websecurityscanner_v1.ScanRun.ExecutionState.KILLED,\n    ):\n        break\n\n    time.sleep(30)\n```\n\nIf you need to stop a run early:\n\n```python\nclient.stop_scan_run(request={\"name\": scan_run.name})\n```\n\n### Read Findings And Finding-Type Stats\n\n`list_findings` gives you the findings attached to a run. `list_finding_type_stats` is the fastest way to summarize the run by finding type.\n\n```python\nfrom google.cloud import websecurityscanner_v1\n\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nfor finding in client.list_findings(request={\"parent\": scan_run.name}):\n    print(finding.name)\n```\n\n```python\nfrom google.cloud import websecurityscanner_v1\n\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nfor stat in client.list_finding_type_stats(request={\"parent\": scan_run.name}):\n    print(stat.finding_type, stat.finding_count)\n```\n\nIf you already have a finding resource name and want the full record:\n\n```python\nfinding = client.get_finding(\n    request={\"name\": \"projects/PROJECT_ID/scanConfigs/SCAN_CONFIG_ID/scanRuns/RUN_ID/findings/FINDING_ID\"}\n)\n\nprint(finding.name)\n```\n\n### Update A Scan Config\n\nUse `update_scan_config` with a field mask. Changes outside the `FieldMask.paths` list are ignored.\n\n```python\nfrom google.cloud import websecurityscanner_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nclient = websecurityscanner_v1.WebSecurityScannerClient()\n\nscan_config = client.get_scan_config(request={\"name\": created.name})\nscan_config.max_qps = 5\nscan_config.ignore_http_status_errors = True\n\nupdated = client.update_scan_config(\n    request=websecurityscanner_v1.UpdateScanConfigRequest(\n        scan_config=scan_config,\n        update_mask=FieldMask(\n            paths=[\"max_qps\", \"ignore_http_status_errors\"]\n        ),\n    )\n)\n\nprint(updated.max_qps, updated.ignore_http_status_errors)\n```\n\n## Target Authentication Options\n\nGoogle's product docs describe these target-app authentication modes for scan configs:\n\n- custom account login with `username`, `password`, and `login_url`\n- Google account login with `username` and `password`\n- Identity-Aware Proxy (IAP) by granting the Web Security Scanner service account access to the protected application\n\nPractical guidance from the product docs:\n\n- Prefer IAP when possible for authenticated applications. Google documents it as the more reliable option.\n- Google account authentication does not support two-factor authentication.\n- Custom-account form auth breaks easily on complex HTML forms, custom JavaScript login flows, anti-bot / DDoS protection, or pages that do not set an auth cookie after login.\n- Static-IP custom scans are more limited than standard custom scans. The current docs say they are preview-only, support public Compute Engine and GKE targets, do not support App Engine, and only work with no authentication or Google-account authentication.\n\n## Important Pitfalls\n\n- Custom scans target public URLs or public IPs. The current product docs say standard custom scans only support public IPv4 hosts, not internal-only services.\n- Scans can create or modify server-side state. Use a staging environment or disposable test accounts when forms trigger writes.\n- More exclusion patterns are not always better. Google documents a hard limit of 100 blacklist patterns and recommends avoiding more than about 10 different scans before cleanup because excessive configs slow the system down.\n- Do not assume a started run is actively scanning right away. A scan may sit queued for a while before it begins.\n- If your target is behind a firewall, allowlisting depends on the scan mode. Standard custom scans and static-IP custom scans use different source IP guidance.\n- Reuse the client instead of recreating it per request. The generated client manages its own transport.\n\n## Practical Workflow For Agents\n\nWhen generating code against this package:\n\n1. set up ADC and `GOOGLE_CLOUD_PROJECT` first\n2. list existing scan configs before creating duplicates\n3. create or update a `ScanConfig`\n4. start a run and poll `get_scan_run`\n5. read findings from the run resource, then summarize with `list_finding_type_stats`\n6. stop the run explicitly if your automation no longer needs it\n\n## Official Sources\n\n- Package reference landing page: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest`\n- `WebSecurityScannerClient` reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.services.web_security_scanner.WebSecurityScannerClient`\n- `ScanConfig` type reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.types.ScanConfig`\n- `CreateScanConfigRequest` type reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.types.CreateScanConfigRequest`\n- `StartScanRunRequest` type reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.types.StartScanRunRequest`\n- `ListFindingsRequest` type reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.types.ListFindingsRequest`\n- `ScanRun` type reference: `https://cloud.google.com/python/docs/reference/websecurityscanner/latest/google.cloud.websecurityscanner_v1.types.ScanRun`\n- Authentication with ADC: `https://cloud.google.com/docs/authentication/provide-credentials-adc`\n- Web Security Scanner custom scans guide: `https://cloud.google.com/security-command-center/docs/how-to-web-security-scanner-custom-scans`\n- Scan with user credentials: `https://cloud.google.com/security-command-center/docs/how-to-use-web-security-scanner-scan-with-user-credentials`\n- IAP setup for Web Security Scanner: `https://cloud.google.com/security-command-center/docs/how-to-web-security-scanner-scan-with-iap`\n- PyPI package page: `https://pypi.org/project/google-cloud-websecurityscanner/`\n"
  },
  {
    "path": "content/google/docs/workflows/python/DOC.md",
    "content": "---\nname: workflows\ndescription: \"Google Cloud Workflows Python client for creating workflows, managing revisions, and starting executions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.20.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"google,google-cloud,workflows,orchestration,serverless,python\"\n---\n\n# Google Cloud Workflows Python Client\n\n## Golden Rule\n\nUse `google-cloud-workflows` for the Workflows control plane in Python:\n\n- `from google.cloud import workflows_v1` to create, list, update, and delete workflows\n- `from google.cloud.workflows import executions_v1` to start executions and inspect their status\n\nThis package manages deployed workflow resources and execution records. It does not replace the workflow definition language itself; you still provide workflow source as YAML or JSON text in `Workflow.source_contents`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"google-cloud-workflows==1.20.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"google-cloud-workflows==1.20.0\"\npoetry add \"google-cloud-workflows==1.20.0\"\n```\n\n## Authentication And Setup\n\nBefore using the client:\n\n- select a Google Cloud project\n- enable billing\n- enable the Cloud Workflows API\n- authenticate with Application Default Credentials (ADC)\n\nLocal development with ADC:\n\n```bash\ngcloud auth application-default login\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nService account file when you explicitly need one:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/service-account.json\"\nexport GOOGLE_CLOUD_PROJECT=\"my-project\"\nexport GOOGLE_CLOUD_LOCATION=\"us-central1\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\nfrom google.cloud.workflows import executions_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nworkflows_client = workflows_v1.WorkflowsClient()\nexecutions_client = executions_v1.ExecutionsClient()\n\nparent = workflows_client.common_location_path(project_id, location)\n```\n\nIf you need explicit credentials:\n\n```python\nfrom google.cloud import workflows_v1\nfrom google.cloud.workflows import executions_v1\nfrom google.oauth2 import service_account\n\ncredentials = service_account.Credentials.from_service_account_file(\n    \"service-account.json\"\n)\n\nworkflows_client = workflows_v1.WorkflowsClient(credentials=credentials)\nexecutions_client = executions_v1.ExecutionsClient(credentials=credentials)\n```\n\n## Client Surface\n\nThe package is split across two service families:\n\n- `workflows_v1.WorkflowsClient`: create, get, list, update, delete workflows, and list revisions\n- `executions_v1.ExecutionsClient`: create, get, list, and cancel executions for a workflow\n\nImportant behavior from the generated API:\n\n- workflow create, update, and delete calls return long-running operations; wait on `.result()`\n- execution creation is not a long-running operation; it returns an `Execution` resource immediately\n- `Execution.argument` is a JSON string with a 32 KB limit\n- `Workflow.source_contents` has a 128 KB limit\n- updating `service_account` or `source_contents` creates a new workflow revision\n\n## Core Workflow\n\n### Create a workflow from inline source\n\n`source_contents` is the workflow definition you want Cloud Workflows to run. Keep it as a raw YAML string.\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = workflows_v1.WorkflowsClient()\nparent = client.common_location_path(project_id, location)\n\nworkflow = workflows_v1.Workflow(\n    description=\"Echo input back to the caller\",\n    source_contents=\"\"\"main:\n  params: [args]\n  steps:\n    - return_output:\n        return: ${args}\n\"\"\",\n    service_account=f\"workflow-sa@{project_id}.iam.gserviceaccount.com\",\n    user_env_vars={\"APP_ENV\": \"dev\"},\n)\n\noperation = client.create_workflow(\n    parent=parent,\n    workflow=workflow,\n    workflow_id=\"echo-workflow\",\n)\n\ncreated = operation.result(timeout=600)\nprint(created.name)\nprint(created.revision_id)\n```\n\n### List and fetch workflows\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = workflows_v1.WorkflowsClient()\nparent = client.common_location_path(project_id, location)\n\nfor workflow in client.list_workflows(parent=parent):\n    print(workflow.name, workflow.state.name, workflow.revision_id)\n\nworkflow_name = client.workflow_path(project_id, location, \"echo-workflow\")\nworkflow = client.get_workflow(name=workflow_name)\n\nprint(workflow.description)\nprint(workflow.service_account)\nprint(workflow.user_env_vars)\n```\n\n### Update only specific fields\n\nUse `FieldMask` instead of sending a whole replacement update.\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\nfrom google.protobuf.field_mask_pb2 import FieldMask\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = workflows_v1.WorkflowsClient()\nworkflow_name = client.workflow_path(project_id, location, \"echo-workflow\")\nworkflow = client.get_workflow(name=workflow_name)\n\nworkflow.description = \"Echo input and keep production env vars\"\nworkflow.user_env_vars[\"APP_ENV\"] = \"prod\"\n\noperation = client.update_workflow(\n    request=workflows_v1.UpdateWorkflowRequest(\n        workflow=workflow,\n        update_mask=FieldMask(paths=[\"description\", \"user_env_vars\"]),\n    )\n)\n\nupdated = operation.result(timeout=600)\nprint(updated.revision_id)\nprint(updated.user_env_vars)\n```\n\n### List workflow revisions\n\nIf you are debugging deployment drift, inspect the revision history instead of guessing which definition executed.\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = workflows_v1.WorkflowsClient()\nworkflow_name = client.workflow_path(project_id, location, \"echo-workflow\")\n\nfor revision in client.list_workflow_revisions(name=workflow_name):\n    print(revision.revision_id, revision.revision_create_time)\n```\n\n### Start an execution with a JSON argument\n\nPass execution input as a JSON string, not a Python dict.\n\n```python\nimport json\nimport os\n\nfrom google.cloud import workflows_v1\nfrom google.cloud.workflows import executions_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nworkflow_name = workflows_v1.WorkflowsClient.workflow_path(\n    project_id,\n    location,\n    \"echo-workflow\",\n)\n\nclient = executions_v1.ExecutionsClient()\n\nexecution = executions_v1.Execution(\n    argument=json.dumps({\"message\": \"hello from python\"}),\n)\n\ncreated = client.create_execution(\n    parent=workflow_name,\n    execution=execution,\n)\n\nprint(created.name)\nprint(created.state.name)\nprint(created.workflow_revision_id)\n```\n\n### Poll until the execution finishes\n\n```python\nimport json\nimport time\n\nfrom google.cloud.workflows import executions_v1\nfrom google.cloud.workflows.executions_v1.types import executions\n\nclient = executions_v1.ExecutionsClient()\nexecution_name = \"projects/my-project/locations/us-central1/workflows/echo-workflow/executions/my-execution\"\n\nwhile True:\n    current = client.get_execution(name=execution_name)\n    print(current.state.name)\n\n    if current.state != executions.Execution.State.ACTIVE:\n        break\n\n    time.sleep(2)\n\nif current.state == executions.Execution.State.SUCCEEDED:\n    print(json.loads(current.result))\nelse:\n    print(current.error)\n```\n\n### List executions for one workflow\n\n`list_executions` defaults to the BASIC view, which is enough for names, timestamps, state, and revision IDs.\n\n```python\nfrom google.cloud.workflows import executions_v1\n\nclient = executions_v1.ExecutionsClient()\nworkflow_name = \"projects/my-project/locations/us-central1/workflows/echo-workflow\"\n\nfor execution in client.list_executions(parent=workflow_name):\n    print(\n        execution.name,\n        execution.state.name,\n        execution.workflow_revision_id,\n        execution.start_time,\n    )\n```\n\n### Cancel an in-flight execution\n\n```python\nfrom google.cloud.workflows import executions_v1\n\nclient = executions_v1.ExecutionsClient()\nexecution_name = \"projects/my-project/locations/us-central1/workflows/echo-workflow/executions/my-execution\"\n\ncancelled = client.cancel_execution(name=execution_name)\nprint(cancelled.state.name)\n```\n\n### Delete a workflow\n\n```python\nimport os\n\nfrom google.cloud import workflows_v1\n\nproject_id = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\nlocation = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"us-central1\")\n\nclient = workflows_v1.WorkflowsClient()\nworkflow_name = client.workflow_path(project_id, location, \"echo-workflow\")\n\noperation = client.delete_workflow(name=workflow_name)\noperation.result(timeout=600)\n```\n\n## Common Pitfalls\n\n- Do not pass a Python dict directly to `Execution.argument`; serialize it with `json.dumps(...)`.\n- Do not treat workflow mutations as synchronous. `create_workflow`, `update_workflow`, and `delete_workflow` all return long-running operations.\n- Use `FieldMask` for updates. If `update_mask` is omitted, the API treats the request as a full workflow update.\n- `list_executions` defaults to the BASIC view. If you need payload fields such as `result` or `error` in list output, request the FULL view explicitly.\n- Keep `source_contents` small enough to fit the documented 128 KB limit.\n- Changing `source_contents` or `service_account` creates a new workflow revision. If behavior changed after a deploy, inspect `revision_id` and `workflow_revision_id`.\n- `user_env_vars` keys cannot start with `GOOGLE` or `WORKFLOWS`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `google-cloud-workflows 1.20.0` as the current package release for this guide.\n- The generated `latest` Python reference pages still render as `1.19.0` in the page title, even though PyPI shows `1.20.0`. Use the package version from PyPI for pinning, and use the latest reference pages for current API surface details.\n- The package exposes both `v1` and `v1beta` modules. Prefer the `v1` clients shown above unless you specifically need beta-only behavior documented upstream.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/google-cloud-workflows/\n- Python client overview: https://docs.cloud.google.com/python/docs/reference/workflows/latest\n- `WorkflowsClient` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows_v1.services.workflows.WorkflowsClient\n- `Workflow` type reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows_v1.types.Workflow\n- `UpdateWorkflowRequest` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows_v1.types.UpdateWorkflowRequest\n- `ListWorkflowRevisionsRequest` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows_v1.types.ListWorkflowRevisionsRequest\n- `ExecutionsClient` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows.executions_v1.services.executions.ExecutionsClient\n- `Execution` type reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows.executions_v1.types.Execution\n- `CreateExecutionRequest` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows.executions_v1.types.CreateExecutionRequest\n- `ListExecutionsRequest` reference: https://docs.cloud.google.com/python/docs/reference/workflows/latest/google.cloud.workflows.executions_v1.types.ListExecutionsRequest\n"
  },
  {
    "path": "content/googleapis-common-protos/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"googleapis-common-protos package guide for Python generated Google API protobuf modules\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.73.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"google,protobuf,grpc,googleapis,proto\"\n---\n\n# googleapis-common-protos Python Package Guide\n\n## What This Package Is\n\n`googleapis-common-protos` installs generated Python protobuf modules for common Google API definitions. In practice, it gives you imports such as:\n\n- `google.api.*_pb2`\n- `google.rpc.*_pb2`\n- `google.type.*_pb2`\n- `google.longrunning.operations_pb2`\n\nUse it when your code, generated stubs, or another dependency needs those message definitions at runtime.\n\nThis package is not a service client. It does not make HTTP requests, open gRPC channels, or authenticate with Google services by itself.\n\n## Install\n\nPin to the version this entry covers:\n\n```bash\npip install googleapis-common-protos==1.73.0\n```\n\nIf your dependency graph expects the optional gRPC extra exposed on PyPI:\n\n```bash\npip install \"googleapis-common-protos[grpc]==1.73.0\"\n```\n\nAlternative package managers:\n\n```bash\npoetry add googleapis-common-protos==1.73.0\nuv add googleapis-common-protos==1.73.0\n```\n\n## Python Support\n\nThe `1.73.0` PyPI release requires Python `>=3.7`.\n\n## Initialize And Import\n\nThere is no package-specific initialization step. Import the generated modules directly and instantiate protobuf messages as needed.\n\n```python\nfrom google.rpc import status_pb2\nfrom google.type import date_pb2\n\nstatus = status_pb2.Status(code=3, message=\"invalid request\")\nbirthday = date_pb2.Date(year=2026, month=3, day=12)\n```\n\n## Core Usage\n\n### Build structured error details\n\n`google.rpc.status_pb2` and `google.rpc.error_details_pb2` are common when you need gRPC-style or Google API error payloads.\n\n```python\nfrom google.protobuf import any_pb2\nfrom google.rpc import error_details_pb2, status_pb2\n\nbad_request = error_details_pb2.BadRequest()\nviolation = bad_request.field_violations.add()\nviolation.field = \"user.email\"\nviolation.description = \"must be a valid email address\"\n\ndetail = any_pb2.Any()\ndetail.Pack(bad_request)\n\nstatus = status_pb2.Status(\n    code=3,  # INVALID_ARGUMENT\n    message=\"request validation failed\",\n)\nstatus.details.append(detail)\n```\n\n### Work with long-running operation messages\n\nSome Google APIs expose long-running operations through `google.longrunning.operations_pb2`.\n\n```python\nfrom google.longrunning import operations_pb2\n\noperation = operations_pb2.Operation(\n    name=\"operations/1234567890\",\n    done=False,\n)\n```\n\n### Use common Google API message types\n\nThe package also provides generated modules under namespaces such as `google.api` and `google.type`.\n\n```python\nfrom google.api import httpbody_pb2\nfrom google.type import decimal_pb2\n\nbody = httpbody_pb2.HttpBody(\n    content_type=\"application/json\",\n    data=b'{\"ok\": true}',\n)\n\nprice = decimal_pb2.Decimal(value=\"19.99\")\n```\n\n## Config And Auth\n\n### Authentication\n\nYou do not need credentials to import these modules or construct protobuf messages.\n\nAuthentication belongs to the higher-level code that uses these messages, for example:\n\n- a `google-cloud-*` client library\n- a gRPC client or server\n- a REST layer that serializes these messages\n\nIf you are only creating or parsing protobuf messages from this package, Google Cloud project setup, billing, and Application Default Credentials are not part of the package setup.\n\n### Logging\n\nPyPI documents the standard Google Python SDK logging hook. If you need Google library logging in the same process, set `GOOGLE_SDK_PYTHON_LOGGING_SCOPE` to a valid logger scope such as `google`, or configure Python logging manually.\n\n```bash\nexport GOOGLE_SDK_PYTHON_LOGGING_SCOPE=google\n```\n\n## Common Pitfalls\n\n### Install name is not the import name\n\nInstall:\n\n```bash\npip install googleapis-common-protos\n```\n\nImport from the generated namespaces:\n\n```python\nfrom google.rpc import status_pb2\nfrom google.type import date_pb2\n```\n\nDo not write:\n\n```python\nimport googleapis_common_protos\n```\n\n### `protobuf` and `googleapis-common-protos` solve different import errors\n\n`protobuf` provides the core runtime and well-known types under `google.protobuf.*`.\n\n`googleapis-common-protos` provides generated Google API modules such as `google.rpc.*`, `google.type.*`, and `google.api.*`.\n\nIf the failing import is `google.protobuf.timestamp_pb2`, fix `protobuf`.\nIf the failing import is `google.rpc.status_pb2` or `google.type.date_pb2`, fix `googleapis-common-protos`.\n\n### Installing the wheel does not replace local `.proto` sources for `protoc`\n\nThe official `api-common-protos` guidance is explicit about this: if you compile your own protos and import files like `google/type/color.proto`, you still need local access to those `.proto` files during code generation.\n\nUse `googleapis-common-protos` so you do not have to ship your own generated Python classes for these common definitions. Do not assume it removes the need for proto include paths when running `protoc`.\n\n### Do not treat this like a Google client-library quickstart\n\nThe PyPI page includes standard Google client-library guidance around credentials and logging, but this package itself is only generated proto modules. For message construction and parsing alone, there is no package-specific network setup.\n\n## Version-Sensitive Notes\n\n- The version used here `1.73.0` matches the current PyPI latest release as of March 12, 2026.\n- PyPI lists `Requires: Python >=3.7` for `1.73.0`.\n- The docs URL, `https://github.com/googleapis/python-api-common-protos`, is still official but the repository is archived and points maintainers to the `google-cloud-python/packages/googleapis-common-protos` location.\n- The older `googleapis/api-common-protos` repository is also archived and warns that its protos can be outdated. For canonical proto definitions, prefer `googleapis/googleapis`.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/googleapis-common-protos/`\n- PyPI version page: `https://pypi.org/project/googleapis-common-protos/1.73.0/`\n- Archived repository URL: `https://github.com/googleapis/python-api-common-protos`\n- Archived proto packaging guidance: `https://github.com/googleapis/api-common-protos`\n- Canonical Google API proto source tree: `https://github.com/googleapis/googleapis`\n"
  },
  {
    "path": "content/got/docs/got/javascript/DOC.md",
    "content": "---\nname: got\ndescription: \"Got HTTP client for Node.js with promise and stream APIs, JSON helpers, retries, hooks, pagination, and optional HTTP/2 support\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"14.6.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"got,http,http2,node,javascript,requests\"\n---\n\n# Got Guide for Node.js HTTP Requests\n\n## What It Is\n\n`got` is an HTTP client for Node.js with:\n\n- promise-based requests\n- stream-based requests\n- built-in retries and timeout controls\n- hooks for request lifecycle changes\n- pagination helpers\n- optional HTTP/2 support\n\nUse it when you want a Node-only HTTP client with more control than `fetch`, especially for retries, hooks, streaming, and per-request options.\n\n## Install\n\n`got` 14.x is native ESM and the published package metadata requires Node.js 20 or newer.\n\n```bash\nnpm install got@14.6.6\n```\n\nIf your app is not already using ESM, opt in with `\"type\": \"module\"` in `package.json` or use `.mjs` files.\n\n```json\n{\n  \"type\": \"module\"\n}\n```\n\nImport `got` with a default ESM import:\n\n```javascript\nimport got from 'got';\n```\n\n`got` no longer provides a CommonJS export for `require()`.\n\n## Environment and Initialization\n\nFor APIs that need a base URL and bearer token, keep those values in environment variables.\n\n```bash\nexport API_BASE_URL=\"https://api.example.com/v1/\"\nexport API_TOKEN=\"your-api-token\"\nexport REQUEST_TIMEOUT_MS=\"10000\"\n```\n\nCreate a shared client with `got.extend()` so your app reuses defaults for headers, timeouts, and retries.\n\n```javascript\nimport got from 'got';\n\nexport const api = got.extend({\n  prefixUrl: process.env.API_BASE_URL,\n  headers: {\n    authorization: `Bearer ${process.env.API_TOKEN}`,\n    accept: 'application/json',\n  },\n  timeout: {\n    request: Number(process.env.REQUEST_TIMEOUT_MS ?? 10000),\n  },\n  retry: {\n    limit: 2,\n  },\n});\n```\n\nImportant detail: when you use `prefixUrl`, pass request paths like `'users/me'`, not `'/users/me'`.\n\n## Common Workflows\n\n### GET JSON with query parameters\n\nUse `searchParams` for the query string and `.json()` to parse the response body as JSON.\n\n```javascript\nimport { api } from './client.js';\n\nconst issues = await api.get('issues', {\n  searchParams: {\n    state: 'open',\n    limit: 20,\n  },\n}).json();\n\nconsole.log(issues);\n```\n\n`searchParams` replaces any query string already present in the URL.\n\n### POST a JSON body\n\nUse the `json` option to send JSON. If `content-type` is not set, `got` sets it to `application/json`.\n\n```javascript\nimport { api } from './client.js';\n\nconst message = await api.post('messages', {\n  json: {\n    role: 'user',\n    content: 'Hello from got',\n  },\n}).json();\n\nconsole.log(message.id);\n```\n\nThe `json` option only controls the outgoing request body. To parse a JSON response, call `.json()` or set `responseType: 'json'`.\n\n### Send a form-encoded request\n\nUse `form` for `application/x-www-form-urlencoded` requests such as OAuth token exchanges.\n\n```javascript\nimport got from 'got';\n\nconst tokenResponse = await got.post('https://auth.example.com/oauth/token', {\n  form: {\n    grant_type: 'client_credentials',\n    client_id: process.env.CLIENT_ID,\n    client_secret: process.env.CLIENT_SECRET,\n  },\n}).json();\n\nconsole.log(tokenResponse.access_token);\n```\n\n### Inspect the full response\n\nIf you need status code, headers, or the raw text body, await the request directly instead of calling `.json()`.\n\n```javascript\nimport got from 'got';\n\nconst response = await got('https://api.example.com/health');\n\nconsole.log(response.statusCode);\nconsole.log(response.headers['content-type']);\nconsole.log(response.body);\n```\n\n### Handle non-2xx responses yourself\n\nBy default, `got` throws `HTTPError` for unsuccessful HTTP responses. Disable that with `throwHttpErrors: false` when your app expects statuses such as `404` or `409`.\n\n```javascript\nimport { api } from './client.js';\n\nconst response = await api.get('users/missing', {\n  throwHttpErrors: false,\n});\n\nif (response.statusCode === 404) {\n  console.log('User not found');\n} else {\n  console.log(response.body);\n}\n```\n\n### Set timeouts, retries, and cancellation\n\n`got` supports a full request timeout or per-phase timeout values. Retries are enabled by default.\n\n```javascript\nimport { api } from './client.js';\n\nconst abortController = new AbortController();\n\nsetTimeout(() => {\n  abortController.abort();\n}, 200);\n\ntry {\n  const report = await api.get('reports/daily', {\n    signal: abortController.signal,\n    timeout: {\n      request: 5000,\n    },\n    retry: {\n      limit: 0,\n    },\n  }).json();\n\n  console.log(report);\n} catch (error) {\n  console.error(error.name);\n}\n```\n\nUse `retry: {limit: 0}` when you need single-attempt behavior.\n\n### Download a file with progress events\n\nUse the stream API for large downloads.\n\n```javascript\nimport { createWriteStream } from 'node:fs';\nimport { pipeline } from 'node:stream/promises';\nimport got from 'got';\n\nconst download = got.stream('https://downloads.example.com/archive.zip')\n  .on('downloadProgress', ({ percent, transferred, total }) => {\n    console.log({\n      percent,\n      transferred,\n      total,\n    });\n  });\n\nawait pipeline(download, createWriteStream('archive.zip'));\n```\n\nIf the server does not send `content-length`, the progress event has `total: undefined`.\n\n### Paginate through an API\n\nUse `got.paginate()` or `got.paginate.all()` when the API returns a collection across multiple pages.\n\n```javascript\nimport got from 'got';\n\nconst items = await got.paginate.all('https://api.example.com/items', {\n  searchParams: {\n    limit: 100,\n    offset: 0,\n  },\n  pagination: {\n    transform: (response) => JSON.parse(response.body).items,\n    paginate: ({ response, currentItems }) => {\n      const previous = response.request.options.searchParams;\n      const limit = Number(previous.get('limit') ?? 100);\n      const offset = Number(previous.get('offset') ?? 0);\n\n      if (currentItems.length < limit) {\n        return false;\n      }\n\n      return {\n        searchParams: {\n          limit,\n          offset: offset + limit,\n        },\n      };\n    },\n    countLimit: 500,\n  },\n});\n\nconsole.log(items.length);\n```\n\nUse `got.paginate()` when you want an async iterator instead of collecting everything into one array.\n\n### Add request hooks\n\nHooks run during the request lifecycle and are useful for auth, logging, and request shaping.\n\n```javascript\nimport got from 'got';\n\nconst api = got.extend({\n  prefixUrl: process.env.API_BASE_URL,\n  hooks: {\n    beforeRequest: [\n      (options) => {\n        options.headers.authorization = `Bearer ${process.env.API_TOKEN}`;\n      },\n    ],\n  },\n});\n\nconst response = await api.get('users/me');\nconsole.log(response.statusCode);\n```\n\nInside `beforeRequest`, changing `options.json` or `options.form` does not change the final request body. If you need to rewrite the payload there, update `options.body` and any related headers instead.\n\n### Enable HTTP/2 when the server supports it\n\nSet `http2: true` to allow `got` to negotiate HTTP/1.1 or HTTP/2 through ALPN.\n\n```javascript\nimport got from 'got';\n\nconst response = await got('https://nghttp2.org/httpbin/anything', {\n  http2: true,\n}).json();\n\nconsole.log(response.headers);\n```\n\n## Important Pitfalls\n\n- `got` 14.x is ESM-only. `require('got')` is not supported.\n- The published package metadata for the 14.x line requires Node.js 20 or newer.\n- `json` serializes the request body only. It does not automatically parse the response.\n- `prefixUrl` and leading slashes do not mix. Use `'users/me'`, not `'/users/me'`.\n- `searchParams` overrides the query string already present in `url`.\n- Retries are enabled by default. Turn them off explicitly when retrying would be unsafe.\n- If you set `cookieJar`, `options.headers.cookie` is overridden.\n- `dnsCache` is intended for many requests to public hostnames; the maintainer docs say to keep it disabled for internal names such as `localhost` or `database.local`.\n\n## Version Notes\n\n- This entry targets `got@14.6.6`.\n- The maintainer docs for the current 14.x line document promise requests, streams, pagination, retries, hooks, and optional HTTP/2 support under the same package entrypoint: `import got from 'got'`.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/sindresorhus/got\n- Maintainer README: https://github.com/sindresorhus/got/blob/main/readme.md\n- Options reference: https://github.com/sindresorhus/got/blob/main/documentation/2-options.md\n- Streams reference: https://github.com/sindresorhus/got/blob/main/documentation/3-streams.md\n- Pagination reference: https://github.com/sindresorhus/got/blob/main/documentation/4-pagination.md\n- Timeout reference: https://github.com/sindresorhus/got/blob/main/documentation/6-timeout.md\n- Retry reference: https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md\n- Hooks reference: https://github.com/sindresorhus/got/blob/main/documentation/9-hooks.md\n- npm package: https://www.npmjs.com/package/got\n"
  },
  {
    "path": "content/gql/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"gql GraphQL client for Python with HTTP and websocket transports, schema introspection, and subscriptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"gql,graphql,python,http,websocket,subscriptions\"\n---\n\n# gql for Python\n\n`gql` is a Python GraphQL client built around two pieces:\n\n- `gql(...)` parses a GraphQL document string.\n- `Client(...)` executes that document through a transport such as HTTP or WebSocket.\n\nVersion `4.0.0` requires Python `>=3.8.1` and keeps transport dependencies optional, so install the extra that matches the transport you plan to use.\n\n## Install\n\nInstall only the transport dependencies you need:\n\n```bash\npython -m pip install \"gql[aiohttp]\"\npython -m pip install \"gql[requests]\"\npython -m pip install \"gql[httpx]\"\npython -m pip install \"gql[websockets]\"\n```\n\nOr install everything:\n\n```bash\npython -m pip install \"gql[all]\"\n```\n\nTypical environment variables:\n\n```bash\nexport GRAPHQL_URL=\"https://api.example.com/graphql\"\nexport GRAPHQL_WS_URL=\"wss://api.example.com/graphql\"\nexport GRAPHQL_TOKEN=\"your-token\"\n```\n\n## Async HTTP workflow\n\n`AIOHTTPTransport` is the common choice in async applications. Pass auth and any custom headers directly to the transport.\n\n```python\nimport asyncio\nimport os\n\nfrom gql import Client, gql\nfrom gql.transport.aiohttp import AIOHTTPTransport\n\n\nasync def main() -> None:\n    transport = AIOHTTPTransport(\n        url=os.environ[\"GRAPHQL_URL\"],\n        headers={\"Authorization\": f\"Bearer {os.environ['GRAPHQL_TOKEN']}\"},\n    )\n\n    client = Client(\n        transport=transport,\n        fetch_schema_from_transport=True,\n    )\n\n    query = gql(\n        \"\"\"\n        query GetViewer {\n          viewer {\n            id\n            login\n          }\n        }\n        \"\"\"\n    )\n\n    async with client as session:\n        result = await session.execute(query)\n        print(result[\"viewer\"][\"id\"])\n        print(result[\"viewer\"][\"login\"])\n\n\nasyncio.run(main())\n```\n\nUse `fetch_schema_from_transport=True` when the server allows introspection and you want local query validation. If your API disables introspection, leave it off and execute requests without schema fetching.\n\n## Sync HTTP workflow\n\nFor normal synchronous scripts, use a sync transport such as `RequestsHTTPTransport` and keep the session open with `with client as session:` when sending multiple operations.\n\n```python\nimport os\n\nfrom gql import Client, gql\nfrom gql.transport.requests import RequestsHTTPTransport\n\n\ntransport = RequestsHTTPTransport(\n    url=os.environ[\"GRAPHQL_URL\"],\n    headers={\"Authorization\": f\"Bearer {os.environ['GRAPHQL_TOKEN']}\"},\n    timeout=30,\n    retries=3,\n)\n\nclient = Client(\n    transport=transport,\n    fetch_schema_from_transport=True,\n)\n\nquery = gql(\n    \"\"\"\n    query GetViewer {\n      viewer {\n        id\n        login\n      }\n    }\n    \"\"\"\n)\n\nwith client as session:\n    result = session.execute(query)\n    print(result[\"viewer\"][\"login\"])\n```\n\n`client.execute(query)` also exists as a convenience wrapper, but the explicit session form is easier to reuse across multiple requests.\n\n## Read GraphQL errors and extensions\n\nBy default, `execute(...)` returns only the GraphQL `data` object. If the server returns GraphQL errors, `gql` raises `TransportQueryError`.\n\nUse `get_execution_result=True` when you need the full `ExecutionResult`, including `extensions`:\n\n```python\nfrom gql.transport.exceptions import TransportQueryError\n\n\nasync with client as session:\n    try:\n        execution_result = await session.execute(\n            query,\n            get_execution_result=True,\n        )\n    except TransportQueryError as exc:\n        print(exc.errors)\n        print(exc.data)\n    else:\n        print(execution_result.data)\n        print(execution_result.extensions)\n```\n\nThis is the right pattern when your API uses GraphQL `extensions` for tracing, rate-limit metadata, or other out-of-band fields.\n\n## Subscribe over WebSocket\n\nUse `WebsocketsTransport` for GraphQL subscriptions. Some servers authenticate with HTTP headers, while others expect auth in the `connection_init` payload, exposed here as `init_payload`.\n\n```python\nimport asyncio\nimport os\n\nfrom gql import Client, gql\nfrom gql.transport.websockets import WebsocketsTransport\n\n\nasync def main() -> None:\n    transport = WebsocketsTransport(\n        url=os.environ[\"GRAPHQL_WS_URL\"],\n        headers={\"Authorization\": f\"Bearer {os.environ['GRAPHQL_TOKEN']}\"},\n        init_payload={\"Authorization\": f\"Bearer {os.environ['GRAPHQL_TOKEN']}\"},\n    )\n\n    client = Client(transport=transport)\n\n    subscription = gql(\n        \"\"\"\n        subscription OnMessageAdded {\n          messageAdded {\n            id\n            body\n          }\n        }\n        \"\"\"\n    )\n\n    async with client as session:\n        async for event in session.subscribe(subscription):\n            print(event[\"messageAdded\"][\"id\"])\n            print(event[\"messageAdded\"][\"body\"])\n\n\nasyncio.run(main())\n```\n\nIf your server only accepts one auth mechanism, remove the other. The package supports connection parameters such as `ack_timeout`, `keep_alive_timeout`, `ping_interval`, and `pong_timeout` when you need to tune long-lived subscriptions.\n\n## Custom scalars and local parsing\n\nIf you have a schema available and need custom scalar or enum handling, enable variable serialization and result parsing on the client:\n\n```python\nclient = Client(\n    transport=transport,\n    fetch_schema_from_transport=True,\n    serialize_variables=True,\n    parse_results=True,\n)\n```\n\nThese options are only useful when `gql` has schema information, either from `fetch_schema_from_transport=True`, a provided `schema=...`, or a provided `introspection=...`.\n\n## Common pitfalls\n\n- Install the right extra for your transport. `gql` itself does not vendor `aiohttp`, `requests`, `httpx`, or `websockets`.\n- If an asyncio event loop is already running, do not call the sync convenience APIs such as `client.execute(...)` or `client.subscribe(...)`. Use `async with client as session:` and `await session.execute(...)` instead.\n- `fetch_schema_from_transport=True` depends on GraphQL introspection. It will fail against servers that disable introspection.\n- `execute(...)` returns `data` by default and raises `TransportQueryError` for GraphQL errors. Ask for `get_execution_result=True` when you need `extensions`.\n- WebSocket auth is server-specific. Some APIs require headers, some require `init_payload`, and some require both.\n- Reuse a client session for multiple operations instead of creating a new connection per request.\n"
  },
  {
    "path": "content/gradio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Gradio Python package for building web UIs, chat apps, and MCP-enabled demos around Python functions\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"gradio,python,ui,chatbot,ml,fastapi,mcp\"\n---\n\n# Gradio Python Package Guide\n\n## Golden Rule\n\nUse `gradio` as the UI layer around ordinary Python callables, import it as `import gradio as gr`, and pick the highest-level abstraction that fits the app:\n\n- `gr.Interface(...)` for one function with clear inputs and outputs\n- `gr.ChatInterface(...)` for chatbot-style apps\n- `gr.Blocks()` when you need custom layout, multiple events, shared state, or tighter control over queuing and launch behavior\n\nFor Gradio 6.x, assume launch-time settings now belong on `.launch()` instead of the `Blocks` constructor, and do not rely on old `/predict` or `/chat` API endpoint names unless you set `api_name` explicitly.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"gradio==6.9.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"gradio==6.9.0\"\npoetry add \"gradio==6.9.0\"\n```\n\nOptional extras:\n\n```bash\npython -m pip install \"gradio[mcp]==6.9.0\"\npython -m pip install \"gradio[oauth]==6.9.0\"\n```\n\nUse the `mcp` extra if you want `.launch(mcp_server=True)` support without manually resolving MCP dependencies.\n\n## Fast Start\n\n### `Interface` for a single function\n\nUse `Interface` when one Python function maps neatly to inputs and outputs:\n\n```python\nimport gradio as gr\n\ndef classify_text(text: str) -> str:\n    if \"error\" in text.lower():\n        return \"negative\"\n    return \"positive\"\n\ndemo = gr.Interface(\n    fn=classify_text,\n    inputs=gr.Textbox(label=\"Text\"),\n    outputs=gr.Label(label=\"Prediction\"),\n    title=\"Simple classifier\",\n)\n\nif __name__ == \"__main__\":\n    demo.launch()\n```\n\n`fn` parameters line up with the input components in order, and the return value must match the output components you declared.\n\n### `Blocks` for custom layouts and events\n\nUse `Blocks` once you need multiple components, custom layout, or event wiring:\n\n```python\nimport gradio as gr\n\ndef reverse_text(text: str) -> str:\n    return text[::-1]\n\nwith gr.Blocks() as demo:\n    gr.Markdown(\"## Reverse text\")\n    with gr.Row():\n        inp = gr.Textbox(label=\"Input\")\n        out = gr.Textbox(label=\"Output\")\n    run = gr.Button(\"Reverse\")\n    run.click(reverse_text, inputs=inp, outputs=out)\n\nif __name__ == \"__main__\":\n    demo.launch(theme=\"soft\")\n```\n\nIn Gradio 6.x, app-level settings such as `theme`, `css`, and related launch behavior should be treated as launch concerns, not old `Blocks(...)` constructor-era behavior from 5.x examples.\n\n### `ChatInterface` for chatbot UIs\n\n`ChatInterface` expects a function shaped like `fn(message, history, ...)`. The current history format is a list of OpenAI-style message dictionaries with `role` and `content`.\n\n```python\nimport gradio as gr\n\ndef respond(message: str, history: list[dict]) -> str:\n    turns = len([item for item in history if item[\"role\"] == \"assistant\"])\n    return f\"Turn {turns + 1}: you said {message!r}\"\n\ndemo = gr.ChatInterface(\n    fn=respond,\n    title=\"Echo bot\",\n    save_history=True,\n)\n\nif __name__ == \"__main__\":\n    demo.launch()\n```\n\n`save_history=True` stores chat history in the browser's local storage, which is convenient for demos but worth remembering if the app handles sensitive conversations.\n\nStreaming is just a generator:\n\n```python\nimport time\nimport gradio as gr\n\ndef slow_echo(message: str, history: list[dict]):\n    for index in range(len(message)):\n        time.sleep(0.05)\n        yield f\"You typed: {message[:index + 1]}\"\n\ngr.ChatInterface(slow_echo).launch()\n```\n\nIf you enable `multimodal=True`, the first parameter is no longer a plain string. It becomes a dictionary with `\"text\"` and `\"files\"` keys:\n\n```python\nimport gradio as gr\n\ndef count_uploads(message: dict, history: list[dict]) -> str:\n    return f\"text={message['text']!r}, files={len(message['files'])}\"\n\ndemo = gr.ChatInterface(\n    fn=count_uploads,\n    multimodal=True,\n    textbox=gr.MultimodalTextbox(file_count=\"multiple\", file_types=[\"image\"]),\n)\n\ndemo.launch()\n```\n\n## Launch, Hosting, And Environment\n\n`launch()` is where Gradio runtime behavior is controlled.\n\nLocal-network access:\n\n```python\ndemo.launch(server_name=\"0.0.0.0\", server_port=8000)\n```\n\nEquivalent environment variables:\n\n```bash\nexport GRADIO_SERVER_NAME=\"0.0.0.0\"\nexport GRADIO_SERVER_PORT=8000\n```\n\nUseful environment variables:\n\n- `GRADIO_SERVER_NAME`: defaults to `127.0.0.1`; set to `0.0.0.0` for LAN/container access\n- `GRADIO_SERVER_PORT`: defaults to `7860`\n- `GRADIO_ROOT_PATH`: use when deployed behind a reverse proxy or non-root mount path\n- `GRADIO_ALLOWED_PATHS` and `GRADIO_BLOCKED_PATHS`: comma-separated absolute paths controlling what Gradio may serve\n- `GRADIO_SSR_MODE`: enables server-side rendering; Gradio docs note SSR requires Node 20+\n- `GRADIO_ANALYTICS_ENABLED`: opt out of telemetry if your environment requires it\n- `GRADIO_DEBUG=1`: keeps the main thread alive for easier debugging in notebook-style environments\n\nIf you need HTTPS locally, `launch()` also accepts `ssl_keyfile` and `ssl_certfile`.\n\n## Authentication, Sharing, And Reverse Proxies\n\n### Built-in auth\n\nFor a quick password gate:\n\n```python\ndemo.launch(auth=(\"admin\", \"pass1234\"))\n```\n\nOr provide a validation callback:\n\n```python\ndef check_login(username: str, password: str) -> bool:\n    return username == password\n\ndemo.launch(auth=check_login)\n```\n\nThis is convenient but basic. The official guide calls out that it is not a substitute for stronger controls such as MFA, rate limiting, or account lockout.\n\n### Share links\n\n```python\ndemo.launch(share=True)\n```\n\nGradio share links are proxied public URLs for your local app. The official docs state that Gradio’s share servers do not store app data and that share links expire after 1 week.\n\n### Mount inside FastAPI\n\nIf your application already uses FastAPI, mount a Gradio app instead of running a separate server:\n\n```python\nfrom fastapi import FastAPI\nimport gradio as gr\n\napp = FastAPI()\n\ndef greet(name: str) -> str:\n    return f\"Hello {name}\"\n\ndemo = gr.Interface(greet, \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, demo, path=\"/gradio\")\n```\n\nImportant mount options:\n\n- `root_path`: required when a reverse proxy strips the public prefix before forwarding requests\n- `auth`: basic username/password auth for the mounted app\n- `auth_dependency`: use this instead of `auth` when you already have external auth in FastAPI or OAuth middleware\n- `allowed_paths` and `blocked_paths`: absolute file-system paths controlling what mounted apps may serve\n- `ssr_mode=True`: enables server-side rendering and requires Node 20+\n\nFor external auth:\n\n```python\nfrom fastapi import FastAPI, Request\nimport gradio as gr\n\ndef current_user(request: Request) -> str | None:\n    user = getattr(request.state, \"user\", None)\n    return getattr(user, \"id\", None)\n\napp = FastAPI()\ndemo = gr.Interface(lambda text: text.upper(), \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, demo, path=\"/gradio\", auth_dependency=current_user)\n```\n\n## Queues, API Exposure, And Performance\n\nEvery Gradio event listener has a queue. By default, each listener processes one request at a time.\n\nUse per-listener concurrency when a function can safely run more than one request in parallel:\n\n```python\nimport gradio as gr\n\ndef generate(prompt: str) -> str:\n    return f\"generated: {prompt}\"\n\nwith gr.Blocks() as demo:\n    prompt = gr.Textbox()\n    output = gr.Textbox()\n    button = gr.Button(\"Run\")\n    button.click(generate, prompt, output, concurrency_limit=4)\n\ndemo.queue(default_concurrency_limit=2, max_size=32)\ndemo.launch()\n```\n\nKey rules:\n\n- `concurrency_limit=None` removes the limit for that event listener\n- `concurrency_id=\"gpu_queue\"` lets multiple listeners share the same queue and concurrency budget\n- `demo.queue(max_size=...)` caps queued events and fails fast when the queue is full\n- `api_open=True` on `Blocks.queue()` allows direct backend REST routes to skip the queue; only use this intentionally\n\n## File Access And Output Handling\n\nGradio can serve files back to the browser, which makes file exposure settings important.\n\nPrefer explicit allowlists:\n\n```python\ndemo.launch(\n    allowed_paths=[\"/srv/gradio/public-assets\"],\n    blocked_paths=[\"/srv/gradio/public-assets/secrets\"],\n)\n```\n\nRules that matter:\n\n- `allowed_paths` and `blocked_paths` must be absolute paths\n- `blocked_paths` takes precedence over `allowed_paths`\n- exposing a directory means all files inside it and its subdirectories can be reachable by app users\n- `GRADIO_TEMP_DIR` controls where temporary files are stored\n- `max_file_size` can enforce upload limits when you mount a Gradio app or configure launch options\n\n## MCP Support\n\nGradio 6.9.0 can expose documented functions as MCP tools.\n\nMinimal MCP server:\n\n```python\nimport gradio as gr\n\ndef letter_counter(word: str, letter: str) -> int:\n    \"\"\"Count how many times a letter appears in a word.\"\"\"\n    return word.lower().count(letter.lower())\n\ndemo = gr.Interface(\n    fn=letter_counter,\n    inputs=[gr.Textbox(\"strawberry\"), gr.Textbox(\"r\")],\n    outputs=gr.Number(),\n    api_name=\"predict\",\n)\n\ndemo.launch(mcp_server=True)\n```\n\nPractical notes:\n\n- install with `gradio[mcp]`\n- Gradio uses your function docstring and type hints to describe the tool\n- the MCP endpoint is served under `/gradio_api/mcp/`\n- `GRADIO_MCP_SERVER=True` can enable MCP mode via environment variable instead of code\n\n## Common Pitfalls\n\n- Do not copy Gradio 5.x launch snippets blindly. Gradio 6 moved or renamed several parameters.\n- Do not assume chat APIs still default to `/chat` or `/predict`. In 6.x, `Interface` and `ChatInterface` use the function name as the default API route unless you set `api_name`.\n- If `multimodal=True`, your chat function’s first argument must accept a dictionary, not a string.\n- If your app is behind a reverse proxy and file URLs break, set `root_path` explicitly.\n- If users cannot see uploaded or generated files, check `allowed_paths`, `blocked_paths`, and temp-directory behavior before debugging component code.\n- Built-in `auth` is a convenience gate, not a full security layer.\n- If you enable SSR without Node 20+, rendering will fail.\n- `api_open=True` can bypass queue limits; that is useful for some internal systems and surprising in public deployments.\n- If you expose directories with `allowed_paths`, you are exposing every file under those directories unless a matching blocked path overrides them.\n\n## Version-Sensitive Notes For 6.9.0\n\n- PyPI lists `gradio 6.9.0` as the latest release on March 12, 2026, with Python `>=3.10`.\n- The official Gradio 6 migration guide says Gradio 6 is the actively maintained major line and recommends upgrading through `gradio==5.50` first if you need deprecation warnings before a 6.x migration.\n- `show_api` in launch/event listeners is replaced by `footer_links` and `api_visibility`.\n- Old `Blocks(...)` constructor-era app settings moved to `launch()`.\n- `Interface` and `ChatInterface` now default API names to the Python function name, which matters if external callers depend on the old endpoint paths.\n"
  },
  {
    "path": "content/graphene/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Graphene GraphQL framework for Python with schema types, queries, mutations, context passing, and subscriptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"graphene,graphql,python,schema,mutation,subscription\"\n---\n\n# Graphene for Python\n\n`graphene` is a Python library for defining a GraphQL schema in Python and executing GraphQL operations against it. In Graphene 3, the core workflow is:\n\n1. define `graphene.ObjectType` classes for your schema\n2. create a `graphene.Schema`\n3. execute queries or mutations with `schema.execute()` or `await schema.execute_async()`\n4. expose that schema through your web framework or GraphQL server integration\n\nGraphene itself is the schema and execution layer. It does not provide HTTP routing, authentication, or deployment primitives.\n\n## Install\n\nInstall the package directly:\n\n```bash\npip install graphene==3.4.3\n```\n\nGraphene installs its GraphQL runtime dependencies automatically.\n\nIf you need framework integrations, add those separately. The Graphene project documents companion packages such as `graphene-django` and `graphene-sqlalchemy`.\n\n## Configuration and request context\n\nGraphene does not require environment variables, API keys, or client initialization.\n\nIn a real app, you usually keep app-specific settings in your own environment and pass request-scoped values into Graphene through `context_value`.\n\nExample application environment:\n\n```bash\nexport DATABASE_URL=\"postgresql://app:secret@localhost:5432/app\"\nexport APP_ENV=\"development\"\n```\n\nThose values are for your app or framework, not for Graphene itself.\n\nTo make request state available to resolvers, use `graphene.Context` or pass any object as `context_value`:\n\n```python\nfrom graphene import Context\n\ncontext = Context(\n    request_id=\"req_123\",\n    current_user={\"id\": \"u_1\", \"email\": \"ada@example.com\"},\n)\n```\n\nResolvers can then read `info.context.request_id`, `info.context.current_user`, or any other attributes you put there.\n\n## Define a schema\n\nUse `graphene.ObjectType` classes for root query types and object types returned by fields.\n\n```python\nimport graphene\n\n\nclass User(graphene.ObjectType):\n    id = graphene.ID(required=True)\n    email = graphene.String(required=True)\n\n\nclass Query(graphene.ObjectType):\n    hello = graphene.String(name=graphene.String(default_value=\"world\"))\n    user = graphene.Field(User, id=graphene.ID(required=True))\n\n    def resolve_hello(root, info, name):\n        return f\"Hello, {name}!\"\n\n    def resolve_user(root, info, id):\n        if info.context.current_user[\"id\"] != id:\n            return None\n\n        return {\"id\": id, \"email\": info.context.current_user[\"email\"]}\n\n\nschema = graphene.Schema(query=Query)\n```\n\nImportant behavior:\n\n- Define resolvers with the `resolve_<field_name>` naming pattern.\n- Graphene maps Python `snake_case` field names to GraphQL `camelCase` by default.\n- If you do not write a resolver, Graphene's default resolver reads matching attributes or dictionary keys from the returned object.\n\n## Execute a query\n\n`Schema.execute()` runs a GraphQL operation synchronously and returns an `ExecutionResult` with `.data` and `.errors`.\n\n```python\nfrom graphene import Context\n\n\nquery = \"\"\"\nquery GetUser($id: ID!, $name: String!) {\n  hello(name: $name)\n  user(id: $id) {\n    id\n    email\n  }\n}\n\"\"\"\n\nresult = schema.execute(\n    query,\n    variable_values={\"id\": \"u_1\", \"name\": \"Ada\"},\n    context_value=Context(\n        request_id=\"req_123\",\n        current_user={\"id\": \"u_1\", \"email\": \"ada@example.com\"},\n    ),\n)\n\nif result.errors:\n    raise RuntimeError(result.errors)\n\nprint(result.data)\n```\n\nExpected result shape:\n\n```python\n{\n    \"hello\": \"Hello, Ada!\",\n    \"user\": {\n        \"id\": \"u_1\",\n        \"email\": \"ada@example.com\",\n    },\n}\n```\n\n## Add mutations\n\nDefine mutations by subclassing `graphene.Mutation`, declaring an inner `Arguments` class, and mounting the mutation with `.Field()` on a root mutation type.\n\n```python\nimport graphene\n\n\nclass User(graphene.ObjectType):\n    id = graphene.ID(required=True)\n    email = graphene.String(required=True)\n\n\nclass CreateUser(graphene.Mutation):\n    class Arguments:\n        email = graphene.String(required=True)\n\n    ok = graphene.Boolean(required=True)\n    user = graphene.Field(User)\n\n    def mutate(root, info, email):\n        user = {\"id\": \"u_2\", \"email\": email}\n        return CreateUser(ok=True, user=user)\n\n\nclass Query(graphene.ObjectType):\n    health = graphene.String()\n\n    def resolve_health(root, info):\n        return \"ok\"\n\n\nclass Mutation(graphene.ObjectType):\n    create_user = CreateUser.Field()\n\n\nschema = graphene.Schema(query=Query, mutation=Mutation)\n\nresult = schema.execute(\n    \"\"\"\n    mutation CreateUser($email: String!) {\n      createUser(email: $email) {\n        ok\n        user {\n          id\n          email\n        }\n      }\n    }\n    \"\"\",\n    variable_values={\"email\": \"new@example.com\"},\n)\n\nif result.errors:\n    raise RuntimeError(result.errors)\n\nprint(result.data[\"createUser\"][\"user\"][\"email\"])\n```\n\nTwo common patterns are supported:\n\n- return fields directly from the mutation class, as shown above\n- set `Output = SomeObjectType` if you want the mutation to return an existing Graphene object type directly\n\nEvery mutation class must define `mutate(...)`.\n\n## Async execution\n\nUse `await schema.execute_async(...)` when your integration is async or when resolvers depend on async work.\n\n```python\nimport graphene\n\n\nclass Query(graphene.ObjectType):\n    hello = graphene.String()\n\n    async def resolve_hello(root, info):\n        return \"Hello from async Graphene\"\n\n\nschema = graphene.Schema(query=Query)\n\nresult = await schema.execute_async(\"{ hello }\")\n\nif result.errors:\n    raise RuntimeError(result.errors)\n\nprint(result.data[\"hello\"])\n```\n\nThe async API is the same shape as `execute()`, but it uses GraphQL-core's async execution path.\n\n## Subscriptions\n\nGraphene 3 supports subscriptions through `Schema.subscribe(...)`. Define a root subscription type and add `subscribe_<field_name>` methods that yield values.\n\n```python\nimport asyncio\nimport graphene\n\n\nclass Query(graphene.ObjectType):\n    health = graphene.String()\n\n    def resolve_health(root, info):\n        return \"ok\"\n\n\nclass Subscription(graphene.ObjectType):\n    count_upwards = graphene.Field(graphene.Int, limit=graphene.Int(required=True))\n\n    async def subscribe_count_upwards(root, info, limit):\n        for count in range(1, limit + 1):\n            yield count\n            await asyncio.sleep(0)\n\n\nschema = graphene.Schema(query=Query, subscription=Subscription)\n\nstream = await schema.subscribe(\n    \"subscription CountUpwards($limit: Int!) { countUpwards(limit: $limit) }\",\n    variable_values={\"limit\": 3},\n)\n\nif getattr(stream, \"errors\", None):\n    raise RuntimeError(stream.errors)\n\nasync for item in stream:\n    print(item.data[\"countUpwards\"])\n```\n\nIf the subscription query fails parsing or validation, `schema.subscribe()` returns an `ExecutionResult` with errors instead of a stream.\n\n## Schema output and introspection\n\nGraphene exposes a few useful schema-level helpers:\n\n```python\nprint(schema)\nintrospection = schema.introspect()\nuser_type = schema.User\n```\n\nUse these when you need the generated SDL, introspection output, or access to a type already registered in the schema.\n\n## Common pitfalls\n\n- `query=` is not optional in practice. A schema without a query root cannot execute queries.\n- Field names are camel-cased on the GraphQL side by default, so `create_user` becomes `createUser` and `count_upwards` becomes `countUpwards`.\n- If you need to keep GraphQL names in `snake_case`, build the schema with `graphene.Schema(..., auto_camelcase=False)`.\n- Graphene is not an HTTP server. Mount the schema inside Django, Starlette, Flask, or another integration layer yourself.\n- Use `context_value` to pass request-scoped auth, dataloaders, and services to resolvers. Graphene does not implement auth for you.\n\n## Minimal starting point\n\nThis is the smallest useful Graphene application shape for a Python service:\n\n```python\nimport graphene\nfrom graphene import Context\n\n\nclass Query(graphene.ObjectType):\n    hello = graphene.String(name=graphene.String(default_value=\"world\"))\n\n    def resolve_hello(root, info, name):\n        return f\"Hello, {name}!\"\n\n\nschema = graphene.Schema(query=Query)\n\nresult = schema.execute(\n    \"query SayHello($name: String!) { hello(name: $name) }\",\n    variable_values={\"name\": \"Ada\"},\n    context_value=Context(request_id=\"req_123\"),\n)\n\nif result.errors:\n    raise RuntimeError(result.errors)\n\nprint(result.data[\"hello\"])\n```\n\nOnce that works, add a mutation root, request context, and your framework-specific HTTP integration.\n"
  },
  {
    "path": "content/great-expectations/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Great Expectations Python package guide for GX Core data validation workflows with Data Contexts, Expectations, Validation Definitions, and Checkpoints\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"great-expectations,gx,data-quality,validation,expectations,checkpoints,pandas,spark\"\n---\n\n# Great Expectations Python Package Guide\n\n## Golden Rule\n\nUse `great_expectations` as `import great_expectations as gx`, and be explicit about the Data Context mode you want. A large share of GX confusion comes from `gx.get_context()` returning a different context than you expected because it found an existing File Data Context in the current directory or under `GX_HOME`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"great_expectations==1.14.0\"\n```\n\nIf you use pandas examples, install pandas in the same environment:\n\n```bash\npython -m pip install \"pandas>=2\"\n```\n\nRepresentative optional extras from the official docs and PyPI metadata:\n\n```bash\npython -m pip install \"great_expectations[gcp]==1.14.0\"\npython -m pip install \"great_expectations[aws_secrets]==1.14.0\"\npython -m pip install \"great_expectations[spark]==1.14.0\"\n```\n\nNotes:\n\n- GX supports Python `3.10` through `3.13`.\n- PyPI metadata normalizes some extras with hyphens while docs examples sometimes use underscores. If pip rejects one spelling, use the PyPI-normalized spelling shown on the package page.\n\n## Choose A Data Context\n\nGX has three important context modes:\n\n- `file`: persistent config and metadata on disk; use this for reusable suites, checkpoints, and Data Docs\n- `ephemeral`: in-memory only; use this for notebooks, experiments, and one-off validations\n- `cloud`: GX Cloud-backed context using cloud credentials\n\nThe official `get_context()` behavior matters:\n\n- no arguments: returns an existing `FileDataContext` if GX finds one in the current directory tree, otherwise returns an `EphemeralDataContext`\n- `mode=\"file\"`: requires or scaffolds a File Data Context\n- `mode=\"ephemeral\"`: always returns a fresh in-memory context\n- `mode=\"cloud\"`: returns a `CloudDataContext`\n\nTypical setup:\n\n```python\nimport great_expectations as gx\n\n# Persistent local project config\nfile_context = gx.get_context(mode=\"file\", project_root_dir=\".\")\n\n# One-off exploration\nephemeral_context = gx.get_context(mode=\"ephemeral\")\n\n# GX Cloud\ncloud_context = gx.get_context(mode=\"cloud\")\n```\n\n## Core Usage\n\n### Fast in-memory validation with a DataFrame\n\nUse this for notebooks, ETL debugging, and test-time validation where you do not need persisted metadata:\n\n```python\nimport great_expectations as gx\nimport pandas as pd\n\ndf = pd.read_csv(\"orders.csv\")\n\ncontext = gx.get_context(mode=\"ephemeral\")\ndata_source = context.data_sources.add_pandas(\"pandas\")\ndata_asset = data_source.add_dataframe_asset(name=\"orders_df\")\nbatch_definition = data_asset.add_batch_definition_whole_dataframe(\"default\")\nbatch = batch_definition.get_batch(batch_parameters={\"dataframe\": df})\n\nexpectation = gx.expectations.ExpectColumnValuesToBeBetween(\n    column=\"total_amount\",\n    min_value=0,\n    severity=\"warning\",\n)\n\nvalidation_result = batch.validate(expectation)\nprint(validation_result)\n```\n\nKey detail: dataframe-backed assets do not persist the dataframe itself. You must pass the actual dataframe at runtime with `batch_parameters={\"dataframe\": df}`.\n\n### Persist a reusable suite, validation definition, and checkpoint\n\nUse a File Data Context when you want rerunnable validation artifacts:\n\n```python\nimport great_expectations as gx\n\ncontext = gx.get_context(mode=\"file\", project_root_dir=\".\")\n\nconnection_string = \"postgresql+psycopg2://user:password@host/dbname\"\ndata_source = context.data_sources.add_postgres(\n    \"warehouse\",\n    connection_string=connection_string,\n)\ndata_asset = data_source.add_table_asset(name=\"orders\", table_name=\"orders\")\nbatch_definition = data_asset.add_batch_definition_whole_table(\"all_rows\")\n\nsuite = gx.ExpectationSuite(name=\"orders_suite\")\nsuite.add_expectation(\n    gx.expectations.ExpectColumnValuesToNotBeNull(\n        column=\"order_id\",\n        severity=\"critical\",\n    )\n)\nsuite.add_expectation(\n    gx.expectations.ExpectColumnValuesToBeBetween(\n        column=\"total_amount\",\n        min_value=0,\n        severity=\"warning\",\n    )\n)\nsuite = context.suites.add_or_update(suite)\n\nvalidation_definition = gx.ValidationDefinition(\n    name=\"orders_validation\",\n    data=batch_definition,\n    suite=suite,\n)\nvalidation_definition = context.validation_definitions.add_or_update(\n    validation_definition\n)\n\ncheckpoint = gx.Checkpoint(\n    name=\"orders_checkpoint\",\n    validation_definitions=[validation_definition],\n)\ncheckpoint = context.checkpoints.add_or_update(checkpoint)\n\ncheckpoint_result = checkpoint.run()\nprint(checkpoint_result.describe())\n```\n\nWhy this matters:\n\n- `ExpectationSuite` groups expectations\n- `ValidationDefinition` binds a suite to a specific batch definition\n- `Checkpoint` is the production-oriented entry point for running one or more validation definitions\n\nIf you only need ad hoc validation, `batch.validate(expectation)` or `batch.validate(suite)` is simpler. Use checkpoints when you need repeatability and post-validation actions.\n\n### Re-running persisted objects\n\nWhen a script may be run more than once, prefer `add_or_update(...)` instead of `add(...)` for suites, validation definitions, and checkpoints. The official factories support both, but `add(...)` will fail if the named object already exists.\n\n## Configuration And Credentials\n\n### File Data Context configuration\n\nA File Data Context stores GX configuration on disk in a project config rooted around `great_expectations.yml`. GX looks for it in:\n\n1. the path in `GX_HOME`\n2. the current directory\n3. parent directories of the current directory\n\nThat lookup order is why implicit `gx.get_context()` calls can attach to the wrong project.\n\nUseful patterns:\n\n```bash\nexport GX_HOME=\"/absolute/path/to/gx-project\"\n```\n\n```python\ncontext = gx.get_context(mode=\"file\", project_root_dir=\"/absolute/path/to/project\")\n```\n\nGX also supports `runtime_environment` overrides when you need to inject config values at runtime instead of hard-coding them into project files.\n\n### Secret management\n\nGX Core supports:\n\n- environment variables\n- `config_variables.yml`\n- AWS Secrets Manager\n- Google Cloud Secret Manager\n- Azure Key Vault\n\nOfficial docs examples for secret-manager support use extras such as:\n\n```bash\npython -m pip install \"great_expectations[aws_secrets]\"\npython -m pip install \"great_expectations[gcp]\"\n```\n\nPractical guidance:\n\n- keep raw passwords, tokens, and connection strings out of `great_expectations.yml`\n- store stable references in `config_variables.yml` and resolve the sensitive value via environment variables or a supported secret manager\n- prefer runtime environment variables in CI/CD and containerized jobs\n\n### GX Cloud authentication\n\nGX Cloud uses these environment variables:\n\n```bash\nexport GX_CLOUD_ACCESS_TOKEN=\"<user_access_token>\"\nexport GX_CLOUD_ORGANIZATION_ID=\"<organization_id>\"\nexport GX_CLOUD_WORKSPACE_ID=\"<workspace_id>\"\n```\n\nThen create the context with:\n\n```python\nimport great_expectations as gx\n\ncontext = gx.get_context(mode=\"cloud\")\n```\n\nGX Cloud also ships with a built-in `pandas_default` datasource, so simple CSV reads can start immediately:\n\n```python\nbatch = context.data_sources.pandas_default.read_csv(\"https://example.com/data.csv\")\n```\n\n## Common Pitfalls\n\n- `gx.get_context()` is environment-sensitive. If a nearby File Data Context exists, GX will use it instead of creating an Ephemeral context.\n- `mode=\"ephemeral\"` does not persist suites, checkpoints, or other metadata after the Python process exits.\n- DataFrame assets still need runtime `batch_parameters`. Defining the datasource, asset, and batch definition does not save the dataframe itself.\n- Checkpoints should be added to the context before running them. The API documents `CheckpointNotAddedError` and `CheckpointNotFreshError` if you modify or run unmanaged checkpoint objects incorrectly.\n- Batch parameter keys depend on the batch definition. A whole-dataframe batch definition expects `{\"dataframe\": df}`; whole-table definitions typically need no batch parameters.\n- The package is not officially Windows-supported in the compatibility reference. Mac and Linux are the supported operating systems.\n- Many third-party examples still use pre-1.0 or 0.18 APIs. Do not copy those patterns into a 1.x project.\n\n## Version-Sensitive Notes\n\n- This doc is pinned to version used here `1.14.0`, which PyPI lists as released on `2026-03-04`.\n- PyPI already lists `1.15.0` as the latest release on `2026-03-11`, so check release drift before copying exact method names into a newly created project.\n- The docs URL `https://docs.greatexpectations.io/docs/reference/` is not a stable package guide. During validation on `2026-03-12`, it resolved to a version-drifting API landing page, while guide pages were on `1.15.0` and some API pages still showed `1.14.0` or `1.11.3`.\n- When the docs disagree, trust the page's own version banner plus the PyPI release history, and keep 0.18 content out of 1.x work unless you are explicitly maintaining a legacy deployment.\n- The compatibility reference says GX supports library versions `>=1.0`, and that `0.18` reached end of life on `2025-10-01`.\n\n## Source URLs\n\n- Docs home: https://docs.greatexpectations.io/docs/\n- Try GX Core: https://docs.greatexpectations.io/docs/core/introduction/try_gx/\n- Create a Data Context: https://docs.greatexpectations.io/docs/core/set_up_a_gx_environment/create_a_data_context/\n- `get_context()` API reference: https://docs.greatexpectations.io/docs/reference/api/data_context/data_context/context_factory/\n- Pandas dataframe workflow: https://docs.greatexpectations.io/docs/core/connect_to_data/dataframes/\n- ValidationDefinition API reference: https://docs.greatexpectations.io/docs/reference/api/validationdefinition_class/\n- Checkpoint API reference: https://docs.greatexpectations.io/docs/reference/api/checkpoint_class/\n- Compatibility reference: https://docs.greatexpectations.io/docs/help/compatibility_reference\n- GX Cloud Python connection guide: https://docs.greatexpectations.io/docs/cloud/connect/connect_python/\n- Secrets managers guide: https://docs.greatexpectations.io/docs/core/configure_project_settings/access_secrets_managers/\n- PyPI package page: https://pypi.org/project/great-expectations/\n- GitHub repository: https://github.com/great-expectations/great_expectations\n"
  },
  {
    "path": "content/groq/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Groq Python SDK for chat completions, streaming, async clients, and audio transcription\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"groq,llm,inference,chat,streaming,audio\"\n---\n\n# groq Python Package Guide\n\n## When To Use\n\nUse `groq` when you want the official Groq Python SDK for server-side text generation, streaming chat completions, async calls, and speech-to-text requests.\n\nThis entry is pinned to package version `1.1.1`.\n\n## Install\n\nInstall the pinned version when you need this exact SDK surface:\n\n```bash\npip install groq==1.1.1\n```\n\nIf you are not pinning strictly, install the latest compatible release for the project and then confirm the API surface against the installed version:\n\n```bash\npip install groq\n```\n\n## Authentication And Setup\n\nGroq uses an API key. In Python, the SDK reads `GROQ_API_KEY` from the environment if you do not pass `api_key` explicitly.\n\n```bash\nexport GROQ_API_KEY=\"your-api-key\"\n```\n\n```python\nimport os\n\nfrom groq import Groq\n\nclient = Groq(\n    api_key=os.environ[\"GROQ_API_KEY\"],\n)\n```\n\nThis also works:\n\n```python\nfrom groq import Groq\n\nclient = Groq()\n```\n\nThat implicit style depends on `GROQ_API_KEY` already being set in the environment.\n\n## Core Usage\n\n### Chat Completions\n\n`groq` `1.1.1` uses the `client.chat.completions.create(...)` pattern.\n\n```python\nfrom groq import Groq\n\nclient = Groq()\n\ncompletion = client.chat.completions.create(\n    model=\"your-model-id\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are a concise assistant.\"},\n        {\"role\": \"user\", \"content\": \"Summarize the benefits of HTTP keep-alive.\"},\n    ],\n)\n\nprint(completion.choices[0].message.content)\n```\n\nResponse objects are typed models rather than plain dictionaries. Access fields with attributes such as `completion.choices[0].message.content`. If you need plain data for logging or serialization, use the model helpers shown in the upstream README, such as `to_json()` and `to_dict()`.\n\n### Streaming\n\nSet `stream=True` and iterate over the chunks:\n\n```python\nfrom groq import Groq\n\nclient = Groq()\n\nstream = client.chat.completions.create(\n    model=\"your-model-id\",\n    messages=[\n        {\"role\": \"user\", \"content\": \"Count from 1 to 5.\"},\n    ],\n    stream=True,\n)\n\nfor chunk in stream:\n    delta = chunk.choices[0].delta.content or \"\"\n    if delta:\n        print(delta, end=\"\", flush=True)\nprint()\n```\n\n### Async Client\n\nUse `AsyncGroq` inside async code:\n\n```python\nimport asyncio\n\nfrom groq import AsyncGroq\n\nclient = AsyncGroq()\n\nasync def main() -> None:\n    completion = await client.chat.completions.create(\n        model=\"your-model-id\",\n        messages=[\n            {\"role\": \"user\", \"content\": \"Give me three commit message tips.\"},\n        ],\n    )\n    print(completion.choices[0].message.content)\n\nasyncio.run(main())\n```\n\nDo not `await` the synchronous `Groq` client, and do not call `AsyncGroq` from sync code without an event loop.\n\n### Audio Transcription\n\nThe SDK also supports speech-to-text requests:\n\n```python\nfrom pathlib import Path\n\nfrom groq import Groq\n\nclient = Groq()\n\ntranscription = client.audio.transcriptions.create(\n    file=Path(\"speech.wav\"),\n    model=\"whisper-large-v3-turbo\",\n)\n\nprint(transcription.text)\n```\n\nFor translation instead of transcription, use `client.audio.translations.create(...)`.\n\n## Configuration And Reliability\n\n### Timeout And Retries\n\nThe client supports request timeout and retry configuration:\n\n```python\nfrom groq import Groq\n\nclient = Groq(\n    timeout=20.0,\n    max_retries=2,\n)\n```\n\nAccording to the upstream SDK README, retries are enabled by default for connection problems, HTTP `408`, `409`, `429`, and `>=500` responses. Set `max_retries=0` if you need strict single-attempt behavior.\n\n### Error Handling\n\nHandle Groq SDK exceptions explicitly when you need reliable control flow:\n\n```python\nfrom groq import APIConnectionError, APIStatusError, Groq\n\nclient = Groq()\n\ntry:\n    client.chat.completions.create(\n        model=\"your-model-id\",\n        messages=[{\"role\": \"user\", \"content\": \"Ping\"}],\n    )\nexcept APIConnectionError as exc:\n    print(f\"Connection error: {exc}\")\nexcept APIStatusError as exc:\n    print(f\"Status {exc.status_code}: {exc.response}\")\n```\n\nThe SDK README also documents specific subclasses such as `RateLimitError`.\n\n## Common Pitfalls\n\n- `groq` is the package name and the import namespace. Use `from groq import Groq`, not `import groq as client`.\n- The SDK version and the available hosted models are separate concerns. Verify current model IDs in Groq Console docs before hard-coding them.\n- Some Groq docs pages still show older setup text. For package `1.1.1`, rely on package metadata and the SDK repo for Python compatibility: `>=3.8`.\n- Responses are typed objects, not raw dictionaries. Attribute access is the default path.\n- Streaming chunks can contain empty deltas. Guard against `None` or empty strings before concatenating output.\n- If you rely on implicit environment loading, missing `GROQ_API_KEY` failures can be delayed until runtime. In deployed code, `os.environ[\"GROQ_API_KEY\"]` is usually the safer setup.\n- Default retries can mask whether a failure was transient. For debugging or idempotency-sensitive workflows, set `max_retries=0`.\n\n## Version-Sensitive Notes For `1.1.1`\n\n- This doc is intentionally pinned to version used here `1.1.1`.\n- The package surface verified from official sources includes sync and async clients, chat completions, streaming, audio transcriptions, translations, typed responses, retries, and timeout configuration.\n- Groq Console docs describe the live platform and can drift ahead of a pinned SDK release. If an example from the console does not match installed code, confirm the local SDK version first.\n- The docs landing page currently contains older Python-version wording in places. The maintained SDK metadata and README indicate Python `3.8+` for this package line.\n\n## Official Sources Used\n\n- Groq Python libraries doc: `https://console.groq.com/docs/libraries`\n- Groq quickstart: `https://console.groq.com/docs/quickstart`\n- PyPI package page: `https://pypi.org/project/groq/`\n- Groq Python SDK repository: `https://github.com/groq/groq-python`\n"
  },
  {
    "path": "content/grpcio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"gRPC Python runtime package for generated stubs, clients, servers, TLS credentials, metadata, retries, and AsyncIO APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.78.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"grpcio,grpc,rpc,protobuf,http2,asyncio\"\n---\n\n# grpcio Python Package Guide\n\nUse `grpcio` when you need to run Python gRPC clients or servers. The installed package is `grpcio`, but the runtime import is `grpc`.\n\n## Golden Rule\n\n- Install `grpcio` for the runtime and `grpcio-tools` only when you need to generate Python code from `.proto` files.\n- Prefer `grpc.secure_channel(...)` in real deployments. Reserve `grpc.insecure_channel(...)` for local development, trusted internal networks, or tests.\n- Keep the generated `_pb2.py` and `_pb2_grpc.py` files checked in or regenerated in CI. They are part of your application contract, not transient artifacts.\n\n## Install\n\nRuntime only:\n\n```bash\npython -m pip install grpcio==1.78.0\n```\n\nRuntime plus code generation:\n\n```bash\npython -m pip install grpcio==1.78.0 grpcio-tools\n```\n\nVerify the runtime version in code:\n\n```python\nimport grpc\n\nprint(grpc.__version__)\n```\n\n## What `grpcio` Gives You\n\n- Channel creation: `grpc.insecure_channel(...)`, `grpc.secure_channel(...)`\n- Server creation: `grpc.server(...)`\n- TLS and call credentials helpers such as `grpc.ssl_channel_credentials(...)` and `grpc.composite_channel_credentials(...)`\n- Interceptors via `grpc.intercept_channel(...)`\n- AsyncIO client and server APIs under `grpc.aio`\n\nIf you use protocol buffers, your usual workflow is:\n\n1. Define the service in a `.proto`.\n2. Generate Python files.\n3. Build a server by subclassing the generated `*Servicer`.\n4. Build clients from the generated `*Stub`.\n\n## Generate Python Code From `.proto`\n\nThe Python basics guide uses `grpcio-tools` to generate the protobuf module and the gRPC module:\n\n```bash\npython -m grpc_tools.protoc \\\n  -I./protos \\\n  --python_out=. \\\n  --pyi_out=. \\\n  --grpc_python_out=. \\\n  ./protos/helloworld.proto\n```\n\nThis produces:\n\n- `helloworld_pb2.py`: protobuf messages and descriptors\n- `helloworld_pb2_grpc.py`: gRPC-specific client and server helpers\n\nThe generated gRPC module imports the protobuf module, so both files need to stay importable together.\n\n## Core Sync Usage\n\n### Minimal server\n\n```python\nfrom concurrent import futures\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nclass Greeter(helloworld_pb2_grpc.GreeterServicer):\n    def SayHello(self, request, context):\n        return helloworld_pb2.HelloReply(message=f\"Hello, {request.name}\")\n\ndef serve() -> None:\n    server = grpc.server(\n        futures.ThreadPoolExecutor(max_workers=10),\n        options=[\n            (\"grpc.keepalive_time_ms\", 60_000),\n            (\"grpc.keepalive_timeout_ms\", 20_000),\n        ],\n        maximum_concurrent_rpcs=1000,\n    )\n    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)\n    server.add_insecure_port(\"[::]:50051\")\n    server.start()\n    server.wait_for_termination()\n\nif __name__ == \"__main__\":\n    serve()\n```\n\n### Minimal client\n\n```python\nimport json\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nservice_config = json.dumps(\n    {\n        \"methodConfig\": [\n            {\n                \"name\": [{\"service\": \"helloworld.Greeter\"}],\n                \"timeout\": \"5s\",\n                \"waitForReady\": True,\n            }\n        ]\n    }\n)\n\nchannel = grpc.insecure_channel(\n    \"dns:///localhost:50051\",\n    options=[(\"grpc.service_config\", service_config)],\n)\nstub = helloworld_pb2_grpc.GreeterStub(channel)\n\ntry:\n    reply = stub.SayHello(\n        helloworld_pb2.HelloRequest(name=\"Ada\"),\n        timeout=5,\n        metadata=((\"x-request-id\", \"req-123\"),),\n        wait_for_ready=True,\n    )\n    print(reply.message)\nexcept grpc.RpcError as exc:\n    print(exc.code(), exc.details())\n```\n\n## Streaming RPC Shapes\n\nThe Python basics tutorial maps the four RPC shapes like this:\n\n- Unary-unary: return one response object.\n- Unary-stream: `yield` zero or more response objects.\n- Stream-unary: accept a request iterator and return one response object.\n- Stream-stream: accept a request iterator and `yield` responses as they become available.\n\nExample server-streaming handler:\n\n```python\ndef ListFeatures(self, request, context):\n    for feature in self._lookup(request):\n        yield feature\n```\n\nExample client-streaming handler:\n\n```python\ndef RecordRoute(self, request_iterator, context):\n    count = sum(1 for _ in request_iterator)\n    return route_pb2.RouteSummary(point_count=count)\n```\n\n## AsyncIO API\n\nUse `grpc.aio` when the surrounding application is already built on AsyncIO. The official AsyncIO docs call this API stable, but also note an important caveat: gRPC AsyncIO objects may only be used on the thread where they were created.\n\n### Async client\n\n```python\nimport asyncio\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nasync def main() -> None:\n    async with grpc.aio.insecure_channel(\"localhost:50051\") as channel:\n        stub = helloworld_pb2_grpc.GreeterStub(channel)\n\n        try:\n            reply = await stub.SayHello(\n                helloworld_pb2.HelloRequest(name=\"Ada\"),\n                timeout=5,\n                metadata=((\"x-request-id\", \"req-123\"),),\n            )\n            print(reply.message)\n        except grpc.aio.AioRpcError as exc:\n            print(exc.code(), exc.details())\n\nasyncio.run(main())\n```\n\n### Async server\n\n```python\nimport asyncio\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\nclass Greeter(helloworld_pb2_grpc.GreeterServicer):\n    async def SayHello(self, request, context):\n        return helloworld_pb2.HelloReply(message=f\"Hello, {request.name}\")\n\nasync def serve() -> None:\n    server = grpc.aio.server(\n        options=[(\"grpc.keepalive_time_ms\", 60_000)],\n        maximum_concurrent_rpcs=1000,\n    )\n    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)\n    server.add_insecure_port(\"[::]:50051\")\n    await server.start()\n    await server.wait_for_termination()\n\nasyncio.run(serve())\n```\n\nAsync streaming rules that matter in real code:\n\n- Do not share `grpc.aio` channels, calls, or server objects across threads.\n- On AsyncIO streaming calls, read operations must be serialized and write operations must be serialized.\n- Do not mix the iterator API with explicit `read()` / `write()` calls on the same RPC.\n\n## Auth, TLS, and Metadata\n\n### TLS channel\n\n```python\nimport grpc\n\nwith open(\"ca.pem\", \"rb\") as fh:\n    root_certs = fh.read()\n\nchannel_credentials = grpc.ssl_channel_credentials(root_certificates=root_certs)\nchannel = grpc.secure_channel(\"api.example.com:443\", channel_credentials)\n```\n\n### TLS plus bearer token call credentials\n\n```python\nimport grpc\n\nchannel_credentials = grpc.ssl_channel_credentials()\ncall_credentials = grpc.access_token_call_credentials(\"YOUR_ACCESS_TOKEN\")\ncredentials = grpc.composite_channel_credentials(\n    channel_credentials,\n    call_credentials,\n)\n\nchannel = grpc.secure_channel(\"api.example.com:443\", credentials)\n```\n\nOther credential helpers worth knowing:\n\n- `grpc.metadata_call_credentials(...)`: build call credentials from a metadata plugin\n- `grpc.composite_call_credentials(...)`: combine multiple call credentials\n- `grpc.ssl_server_credentials(...)`: TLS on the server side\n- `grpc.local_channel_credentials(...)` and `grpc.local_server_credentials(...)`: local-only credentials for localhost or UDS testing\n\nImportant auth notes:\n\n- The auth guide warns that Google credentials should only be sent to Google services.\n- Local channel credentials are useful for tests because they allow call credentials without `insecure_channel`, but local TCP is still not encrypted. UDS is the safer local transport.\n- Metadata keys must be ASCII and must not start with `grpc-`.\n- Metadata values can be ASCII or binary. Servers may cap request headers; the metadata guide suggests assuming about 8 KiB by default.\n\nPer-call metadata example:\n\n```python\nreply = stub.SayHello(\n    helloworld_pb2.HelloRequest(name=\"Ada\"),\n    metadata=(\n        (\"authorization\", \"Bearer YOUR_ACCESS_TOKEN\"),\n        (\"x-request-id\", \"req-123\"),\n    ),\n)\n```\n\n## Service Config, Retries, and Keepalive\n\n`grpcio` exposes channel and server configuration through `options=[(\"key\", value), ...]`. The Python API docs point to gRPC core channel arguments, and the service-config guide documents the JSON model used for client-side behavior.\n\nUseful channel args:\n\n- `grpc.service_config`: default service config as JSON\n- `grpc.keepalive_time_ms`\n- `grpc.keepalive_timeout_ms`\n- `grpc.keepalive_permit_without_calls`\n- `grpc.max_receive_message_length`\n- `grpc.max_send_message_length`\n\nExample with service config:\n\n```python\nimport json\nimport grpc\n\nservice_config = json.dumps(\n    {\n        \"loadBalancingConfig\": [{\"round_robin\": {}}],\n        \"methodConfig\": [\n            {\n                \"name\": [{\"service\": \"helloworld.Greeter\"}],\n                \"timeout\": \"5s\",\n                \"waitForReady\": True,\n                \"retryPolicy\": {\n                    \"maxAttempts\": 4,\n                    \"initialBackoff\": \"0.1s\",\n                    \"maxBackoff\": \"1s\",\n                    \"backoffMultiplier\": 2,\n                    \"retryableStatusCodes\": [\"UNAVAILABLE\"],\n                },\n            }\n        ],\n    }\n)\n\nchannel = grpc.insecure_channel(\n    \"dns:///greeter.internal:50051\",\n    options=[(\"grpc.service_config\", service_config)],\n)\n```\n\nBehavior to remember:\n\n- Service config can control load balancing, wait-for-ready, timeouts, retries, hedging, and health checking.\n- Retries are enabled by default, but there is no default retry policy. Without one, you only get transparent retries for narrowly defined low-level failures.\n- Once response headers arrive, the RPC is committed and gRPC will not retry it.\n- Keepalive should be coordinated with the service owner. The keepalive guide warns against enabling keepalive without active calls and against setting client keepalive much below one minute.\n- If a server dislikes your keepalive settings, it can send `GOAWAY` with debug data `too_many_pings`.\n\n## Interceptors\n\nUse interceptors when you need a reusable cross-cutting layer for auth headers, tracing, logging, or client-side retries that sit above the generated stubs.\n\nSync client interceptors wrap a channel:\n\n```python\nchannel = grpc.intercept_channel(base_channel, my_interceptor)\nstub = helloworld_pb2_grpc.GreeterStub(channel)\n```\n\nFor AsyncIO, pass interceptors directly to `grpc.aio.insecure_channel(...)` or `grpc.aio.secure_channel(...)`.\n\n## Error Handling\n\nFor sync code, non-OK RPCs surface as `grpc.RpcError`.\n\n```python\ntry:\n    reply = stub.SayHello(helloworld_pb2.HelloRequest(name=\"Ada\"), timeout=5)\nexcept grpc.RpcError as exc:\n    if exc.code() is grpc.StatusCode.UNAVAILABLE:\n        ...\n```\n\nFor AsyncIO, await calls can raise `grpc.aio.AioRpcError`.\n\nOn the server side, use the `context` object to read deadlines and set status details, codes, and trailing metadata when you need to return a structured failure.\n\n## Common Pitfalls\n\n- `pip install grpcio`, but `import grpc`.\n- `grpcio` does not generate code by itself. Use `grpcio-tools` and commit or regenerate the `_pb2.py` / `_pb2_grpc.py` pair.\n- Generated import paths matter. If your project needs package-prefixed generated imports, use the custom `-Ipackage=...` form shown in the basics tutorial.\n- Do not send OAuth or Google-issued tokens to arbitrary non-Google endpoints.\n- Do not assume `local_channel_credentials()` means encrypted localhost traffic. Local TCP is checked for locality, not encrypted.\n- Do not overuse keepalive on short unary RPCs.\n- Do not share AsyncIO gRPC objects across threads.\n- Do not mix `async for call` with manual `call.read()` / `call.write()` on the same async streaming RPC.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to PyPI package version `1.78.0`, released on February 6, 2026.\n- The docs URL currently redirects to the canonical Python API site serving `gRPC Python Docs v1.78.1`.\n- The PyPI project notes that gRPC patch versions are not guaranteed to stay aligned across all languages in the monorepo, so do not assume the latest GitHub patch tag exists on PyPI for Python.\n- If you are debugging generated-code mismatches, compare the checked-in generated files, the installed `grpc.__version__`, and the docs version shown on `grpc.github.io`.\n\n## Official Sources\n\n- Python API landing page: https://grpc.io/docs/languages/python/api/\n- Canonical Python API docs: https://grpc.github.io/grpc/python/\n- Python basics tutorial: https://grpc.io/docs/languages/python/basics/\n- Python generated-code reference: https://grpc.io/docs/languages/python/generated-code/\n- Auth guide: https://grpc.io/docs/guides/auth/\n- Metadata guide: https://grpc.io/docs/guides/metadata/\n- Retry guide: https://grpc.io/docs/guides/retry/\n- Keepalive guide: https://grpc.io/docs/guides/keepalive/\n- Service config guide: https://grpc.io/docs/guides/service-config/\n- PyPI package page: https://pypi.org/project/grpcio/\n"
  },
  {
    "path": "content/grpcio/docs/status/python/DOC.md",
    "content": "---\nname: status\ndescription: \"grpcio-status package guide for sending and decoding structured google.rpc.status.Status errors in Python gRPC applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.78.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"grpcio-status,grpc,python,status,errors,protobuf\"\n---\n\n# grpcio-status Python Package Guide\n\nUse `grpcio-status` when you need structured gRPC errors in Python instead of plain status strings. The PyPI package is `grpcio-status`, and the import you use in code is `from grpc_status import rpc_status`.\n\n## Golden Rule\n\n- Use `grpcio-status` only for non-OK RPC failures that need structured error details.\n- Build a `google.rpc.status_pb2.Status`, then convert it with `rpc_status.to_status(...)` before aborting the RPC.\n- On the client, decode rich error metadata with `rpc_status.from_call(...)` or `await rpc_status.aio.from_call(...)` instead of parsing trailing metadata yourself.\n\n## Install\n\nIf you want the status-mapping helpers and the gRPC runtime in the same environment, install matching versions:\n\n```bash\npython -m pip install \"grpcio==1.78.0\" \"grpcio-status==1.78.0\"\n```\n\nIf your environment already pins `grpcio`, install just the helper package:\n\n```bash\npython -m pip install \"grpcio-status==1.78.0\"\n```\n\n`grpcio-status` works with protobuf message types from `google.rpc`, so your app also needs generated protobuf support available in the environment. In most setups, pip resolves the needed packages automatically.\n\n## What The Package Does\n\n`grpcio-status` is a small bridge between:\n\n- gRPC transport status values such as `grpc.StatusCode.INVALID_ARGUMENT`\n- `google.rpc.status.Status` protobuf messages\n- trailing metadata under the `grpc-status-details-bin` key\n\nIt does not create channels, authenticate requests, or generate stubs. Use `grpcio` for runtime channels and servers, and `grpcio-tools` if you need to generate `_pb2.py` and `_pb2_grpc.py` files from `.proto` definitions.\n\n## Initialization And Auth\n\n`grpcio-status` has no package-specific authentication and no required environment variables.\n\nChannel credentials, TLS configuration, and per-request auth metadata still belong to `grpcio`. A practical pattern is to keep the target address in an environment variable and initialize the gRPC client normally:\n\n```bash\nexport GRPC_TARGET=localhost:50051\n```\n\n```python\nimport os\n\nimport grpc\n\ntarget = os.environ.get(\"GRPC_TARGET\", \"localhost:50051\")\nchannel = grpc.insecure_channel(target)\n```\n\nFor production traffic, switch to `grpc.secure_channel(...)` and your normal credential setup.\n\n## Return Rich Errors From A Server\n\nThe server-side flow is:\n\n1. Create one or more structured detail messages.\n2. Pack each detail into `google.protobuf.any_pb2.Any`.\n3. Build a `google.rpc.status_pb2.Status` with a non-OK code.\n4. Abort the RPC with `context.abort_with_status(rpc_status.to_status(...))`.\n\nExample using `google.rpc.error_details_pb2.BadRequest`:\n\n```python\nfrom google.protobuf.any_pb2 import Any\nfrom google.rpc import error_details_pb2, status_pb2\nfrom grpc_status import rpc_status\nimport grpc\n\n\ndef abort_invalid_email(context) -> None:\n    bad_request = error_details_pb2.BadRequest()\n    violation = bad_request.field_violations.add()\n    violation.field = \"email\"\n    violation.description = \"must be a valid email address\"\n\n    detail = Any()\n    detail.Pack(bad_request)\n\n    rich_status = status_pb2.Status(\n        code=grpc.StatusCode.INVALID_ARGUMENT.value[0],\n        message=\"request validation failed\",\n        details=[detail],\n    )\n\n    context.abort_with_status(rpc_status.to_status(rich_status))\n```\n\nIf you already have generated service code, call that helper from your servicer method:\n\n```python\nclass UsersService(users_pb2_grpc.UsersServicer):\n    def CreateUser(self, request, context):\n        if \"@\" not in request.email:\n            abort_invalid_email(context)\n\n        return users_pb2.CreateUserResponse(user_id=\"usr_123\")\n```\n\n## Decode Rich Errors On A Sync Client\n\n`rpc_status.from_call(call)` reads the trailing metadata from a completed `grpc.Call` and returns a `google.rpc.status_pb2.Status` message when the server sent one.\n\n```python\nimport os\n\nimport grpc\nfrom google.rpc import error_details_pb2\nfrom grpc_status import rpc_status\n\nimport users_pb2\nimport users_pb2_grpc\n\n\ntarget = os.environ.get(\"GRPC_TARGET\", \"localhost:50051\")\n\nwith grpc.insecure_channel(target) as channel:\n    stub = users_pb2_grpc.UsersStub(channel)\n\n    try:\n        stub.CreateUser(\n            users_pb2.CreateUserRequest(email=\"not-an-email\"),\n            timeout=5,\n        )\n    except grpc.RpcError as exc:\n        rich_status = rpc_status.from_call(exc)\n\n        if rich_status is None:\n            print(exc.code(), exc.details())\n            raise\n\n        print(rich_status.code, rich_status.message)\n\n        for detail in rich_status.details:\n            bad_request = error_details_pb2.BadRequest()\n            if detail.Unpack(bad_request):\n                for violation in bad_request.field_violations:\n                    print(violation.field, violation.description)\n```\n\n`rich_status.code` is the integer protobuf code. If you also need the Python gRPC enum, use `exc.code()` from the original exception.\n\n## Decode Rich Errors On An AsyncIO Client\n\nFor AsyncIO calls, keep a reference to the `grpc.aio` call object. The async helper expects the call, not the caught `grpc.aio.AioRpcError` snapshot:\n\n```python\nimport asyncio\nimport os\n\nimport grpc\nfrom google.rpc import error_details_pb2\nfrom grpc_status import rpc_status\n\nimport users_pb2\nimport users_pb2_grpc\n\n\nasync def main() -> None:\n    target = os.environ.get(\"GRPC_TARGET\", \"localhost:50051\")\n\n    async with grpc.aio.insecure_channel(target) as channel:\n        stub = users_pb2_grpc.UsersStub(channel)\n        call = stub.CreateUser(\n            users_pb2.CreateUserRequest(email=\"not-an-email\"),\n            timeout=5,\n        )\n\n        try:\n            await call\n        except grpc.aio.AioRpcError as exc:\n            rich_status = await rpc_status.aio.from_call(call)\n\n            if rich_status is None:\n                print(exc.code(), exc.details())\n                raise\n\n            print(rich_status.code, rich_status.message)\n\n            for detail in rich_status.details:\n                error_info = error_details_pb2.ErrorInfo()\n                if detail.Unpack(error_info):\n                    print(error_info.reason, error_info.domain)\n\n\nasyncio.run(main())\n```\n\n## Common Pitfalls\n\n- `grpcio-status` is not a full error-handling framework. It only maps between gRPC status data and `google.rpc.status.Status` messages.\n- `rpc_status.to_status(...)` is for non-OK termination paths. Do not build an `OK` status and abort the RPC with it.\n- `rpc_status.from_call(...)` returns `None` when the server did not send rich status metadata.\n- `rpc_status.from_call(...)` and `rpc_status.aio.from_call(...)` can raise `ValueError` if the protobuf status code or message does not match the transport-level gRPC code or details.\n- Do not hand-roll the `grpc-status-details-bin` metadata value. Use `rpc_status.to_status(...)` on the server and `from_call(...)` on the client.\n- Keep your generated protobuf types aligned with the detail messages you unpack. If the server packs `BadRequest`, the client needs `error_details_pb2.BadRequest` available to decode it.\n\n## Version Notes\n\n- This entry covers PyPI package version `1.78.0`.\n- The package API shown here is small and centered on `grpc_status.rpc_status.to_status`, `grpc_status.rpc_status.from_call`, and `grpc_status.rpc_status.aio.from_call`.\n- The helper APIs are documented by gRPC Python as experimental, so check the hosted Python API docs if you are upgrading across gRPC releases.\n\n## Official Sources\n\n- gRPC Python landing page: https://grpc.io/docs/languages/python/\n- gRPC error handling guide: https://grpc.io/docs/guides/error/\n- gRPC status codes guide: https://grpc.io/docs/guides/status-codes/\n- Hosted gRPC Python API docs: https://grpc.github.io/grpc/python/\n- PyPI package page: https://pypi.org/project/grpcio-status/\n"
  },
  {
    "path": "content/grpcio/docs/tools/python/DOC.md",
    "content": "---\nname: tools\ndescription: \"grpcio-tools package guide for generating Python protobuf modules and gRPC stubs from .proto files\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.78.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"grpcio-tools,grpc,protobuf,protoc,python,codegen\"\n---\n\n# grpcio-tools Python Package Guide\n\nUse `grpcio-tools` to compile `.proto` files into Python protobuf message modules and gRPC service stubs. The PyPI package name is `grpcio-tools`, but the command module you run is `grpc_tools`.\n\n## Golden Rule\n\n- Use `grpcio-tools` for code generation, not as the gRPC runtime.\n- Generate all Python outputs from the same command: `--python_out`, `--pyi_out`, and `--grpc_python_out`.\n- Install the runtime packages separately in any environment that imports the generated files: `protobuf` for `*_pb2.py` and `grpcio` for `*_pb2_grpc.py`.\n\n## Install\n\nCode generation only:\n\n```bash\npython -m pip install \"grpcio-tools==1.78.0\"\n```\n\nRuntime dependencies for applications that import generated code:\n\n```bash\npython -m pip install \"protobuf\" \"grpcio==1.78.0\"\n```\n\nIf one environment both generates and runs the code, install all three:\n\n```bash\npython -m pip install \"protobuf\" \"grpcio==1.78.0\" \"grpcio-tools==1.78.0\"\n```\n\n## Initialization And Auth\n\n`grpcio-tools` is a local compiler wrapper around `protoc` and the Python gRPC plugin. It does not create a client, does not open network connections, and has no package-specific authentication or environment-variable setup.\n\nAuthentication and channel setup belong to the generated gRPC client or server you run with `grpcio`.\n\n## Minimal `.proto` File\n\n```proto\nsyntax = \"proto3\";\n\npackage helloworld;\n\nservice Greeter {\n  rpc SayHello(HelloRequest) returns (HelloReply) {}\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage HelloReply {\n  string message = 1;\n}\n```\n\nSave this as `protos/helloworld.proto`.\n\n## Generate Python Code\n\nSet an explicit proto root and output directory so the generated imports stay predictable:\n\n```bash\nexport PROTO_ROOT=./protos\nexport PY_OUT=./src\n\npython -m grpc_tools.protoc \\\n  -I\"$PROTO_ROOT\" \\\n  --python_out=\"$PY_OUT\" \\\n  --pyi_out=\"$PY_OUT\" \\\n  --grpc_python_out=\"$PY_OUT\" \\\n  \"$PROTO_ROOT/helloworld.proto\"\n```\n\nThis writes:\n\n- `src/helloworld_pb2.py` for protobuf messages and descriptors\n- `src/helloworld_pb2.pyi` for typing information\n- `src/helloworld_pb2_grpc.py` for the gRPC stub, servicer base class, and server registration helper\n\n## Use The Generated Files\n\nAfter generation, import the message module and the gRPC helper module together:\n\n```python\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n```\n\nThe gRPC helper module imports the protobuf module, so both files need to stay importable on the same Python module path.\n\n## Minimal Server\n\nThis requires `grpcio` in the runtime environment.\n\n```python\nfrom concurrent import futures\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\n\nclass Greeter(helloworld_pb2_grpc.GreeterServicer):\n    def SayHello(self, request, context):\n        return helloworld_pb2.HelloReply(message=f\"Hello, {request.name}\")\n\n\ndef serve() -> None:\n    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))\n    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)\n    server.add_insecure_port(\"[::]:50051\")\n    server.start()\n    server.wait_for_termination()\n\n\nif __name__ == \"__main__\":\n    serve()\n```\n\n## Minimal Client\n\nUse an environment variable for the target address so the client can move between local development and deployed environments without code changes:\n\n```bash\nexport GREETER_ADDR=localhost:50051\n```\n\n```python\nimport os\n\nimport grpc\n\nimport helloworld_pb2\nimport helloworld_pb2_grpc\n\n\ntarget = os.environ.get(\"GREETER_ADDR\", \"localhost:50051\")\n\nwith grpc.insecure_channel(target) as channel:\n    stub = helloworld_pb2_grpc.GreeterStub(channel)\n    reply = stub.SayHello(helloworld_pb2.HelloRequest(name=\"Ada\"))\n    print(reply.message)\n```\n\nFor production traffic, switch to `grpc.secure_channel(...)` and the credential helpers documented in the gRPC auth guide.\n\n## Common Pitfalls\n\n- `pip install grpcio-tools`, but run `python -m grpc_tools.protoc`.\n- `grpcio-tools` does not run RPC clients or servers by itself. Generated `*_pb2_grpc.py` files expect the `grpcio` runtime.\n- `*_pb2.py` and `*_pb2_grpc.py` are a pair. If one moves or lands in a different import root, the generated imports break.\n- Output paths matter. Run generation from a stable working directory and keep `-I` and the output directories aligned with your Python package layout.\n- If your project needs package-prefixed generated imports, use the custom `-Ipackage=...` mapping documented in the Python basics tutorial instead of patching the generated files manually.\n\n## Version Notes\n\n- This entry covers PyPI package version `1.78.0`.\n- The gRPC documentation site and the PyPI package page can move on different patch cadences. If you are debugging generated-code differences, compare the installed package version with the version shown in the hosted Python docs.\n\n## Official Sources\n\n- gRPC Python landing page: https://grpc.io/docs/languages/python/\n- gRPC Python basics tutorial: https://grpc.io/docs/languages/python/basics/\n- gRPC Python generated-code reference: https://grpc.io/docs/languages/python/generated-code/\n- gRPC Python API landing page: https://grpc.io/docs/languages/python/api/\n- Canonical hosted Python API docs: https://grpc.github.io/grpc/python/\n- PyPI package page: https://pypi.org/project/grpcio-tools/\n"
  },
  {
    "path": "content/guidance/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"guidance package guide for Python - constrained generation and structured outputs across local and hosted LLM backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"guidance,llm,prompting,structured-output,openai,transformers,llamacpp\"\n---\n\n# guidance Python Package Guide\n\n## What It Is\n\n`guidance` is a Python library for constrained generation with LLMs. It gives you a common interface for:\n\n- local Hugging Face models through `guidance.models.Transformers`\n- local GGUF models through `guidance.models.LlamaCpp`\n- hosted models through `guidance.models.OpenAI`\n\nUse it when you need structured output, token-level constraints, selectable branches, or reusable prompt programs instead of plain string prompting.\n\n## Version Covered\n\n- Ecosystem: `pypi`\n- Package: `guidance`\n- Version: `0.3.1`\n- Python requirement: `>=3.10`\n- Docs root used for coding guidance: `https://guidance.readthedocs.io/en/latest/`\n\n## Install\n\nInstall the base package:\n\n```bash\npip install guidance==0.3.1\n```\n\nInstall the backend extras you actually use:\n\n```bash\npip install \"guidance[transformers]\"\npip install \"guidance[llamacpp]\"\npip install \"guidance[openai]\"\n```\n\nIf you want everything the project exposes as optional extras:\n\n```bash\npip install \"guidance[all]\"\n```\n\n## Backend Setup\n\nChoose one backend first. Most runtime issues come from mixing examples from different backends.\n\n### Transformers\n\nUse this for local or self-hosted Hugging Face causal language models.\n\n```python\nfrom guidance.models import Transformers\n\nlm = Transformers(\"microsoft/Phi-4-mini-instruct\")\n```\n\nThe constructor also accepts loaded `transformers` model and tokenizer objects when you need custom loading behavior.\n\n### LlamaCpp\n\nUse this for local GGUF models through `llama.cpp`.\n\n```python\nfrom guidance.models import LlamaCpp\n\nlm = LlamaCpp(model=\"models/phi-4-mini-instruct-q4.gguf\")\n```\n\n### OpenAI\n\nUse this when you want hosted OpenAI models.\n\n```python\nimport os\nfrom guidance.models import OpenAI\n\nlm = OpenAI(\n    \"gpt-4o-mini\",\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n```\n\nIf you need a proxy or compatible endpoint, pass `base_url`. If you need org scoping, pass `organization`.\n\n```python\nimport os\nfrom guidance.models import OpenAI\n\nlm = OpenAI(\n    \"gpt-4o-mini\",\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n    base_url=os.getenv(\"OPENAI_BASE_URL\"),\n    organization=os.getenv(\"OPENAI_ORGANIZATION\"),\n)\n```\n\n## Core Usage\n\n### Minimal chat with a constrained choice\n\n```python\nfrom guidance import assistant, select, system, user\nfrom guidance.models import Transformers\n\nlm = Transformers(\"microsoft/Phi-4-mini-instruct\")\n\nresult = (\n    lm\n    + system()\n    + \"You are a classifier. Reply with the selected label only.\"\n    + user()\n    + \"Classify the sentiment of: guidance makes structured output easier.\"\n    + assistant()\n    + select([\"positive\", \"negative\"], name=\"sentiment\")\n)\n\nprint(result[\"sentiment\"])\n```\n\nUse `select()` when the output must be one of a fixed set of strings.\n\n### Free-form generation with capture\n\n```python\nfrom guidance import gen\nfrom guidance.models import Transformers\n\nlm = Transformers(\"microsoft/Phi-4-mini-instruct\")\nresult = lm + \"Write a short release note:\\n\" + gen(name=\"note\", max_tokens=60)\n\nprint(result[\"note\"])\n```\n\nUse `gen(name=...)` when you want to capture generated text into a named field.\n\n### Structured JSON generation\n\n```python\nfrom guidance import json as gen_json\nfrom guidance.models import OpenAI\n\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"language\": {\"type\": \"string\"},\n        \"score\": {\"type\": \"integer\", \"minimum\": 0, \"maximum\": 10},\n    },\n    \"required\": [\"language\", \"score\"],\n}\n\nlm = OpenAI(\"gpt-4o-mini\", api_key=\"...\")\nresult = lm + \"Return a rating for Python as JSON.\\n\" + gen_json(\n    name=\"rating\",\n    schema=schema,\n)\n\nprint(result[\"rating\"])\n```\n\nUse `guidance.json()` when you need schema-constrained JSON instead of post-processing raw text.\n\n### Reusable prompt programs\n\n```python\nimport guidance\nfrom guidance import gen\nfrom guidance.models import Transformers\n\n@guidance(stateless=True)\ndef summarize(lm, text):\n    lm += f\"Summarize this in one sentence:\\n{text}\\nSummary: \"\n    lm += gen(name=\"summary\", max_tokens=50)\n    return lm\n\nlm = Transformers(\"microsoft/Phi-4-mini-instruct\")\nresult = lm + summarize(\"Guidance composes prompts as immutable model states.\")\n\nprint(result[\"summary\"])\n```\n\nUse `@guidance` functions when you want reusable prompt fragments or higher-level prompt programs.\n\n## Config And Auth\n\n### OpenAI credentials\n\nThe common setup is:\n\n```bash\nexport OPENAI_API_KEY=your_api_key\n```\n\nOptional settings:\n\n```bash\nexport OPENAI_BASE_URL=https://your-proxy-or-compatible-endpoint/v1\nexport OPENAI_ORGANIZATION=org_xxx\n```\n\n### Local model files\n\n- `Transformers` needs a compatible Hugging Face model id or loaded model/tokenizer objects.\n- `LlamaCpp` needs a local GGUF model file path.\n- Local backends avoid API keys but still need model weights present on disk.\n\n## Common Pitfalls\n\n- Install the right extra. `pip install guidance` alone does not guarantee the backend integration dependencies you need.\n- Backend capabilities differ. The project docs explicitly note that `LlamaCpp` and `Transformers` support the full set of Guidance features, while `OpenAI` support is currently limited to JSON generation.\n- Treat results as returned model state. Capture the returned object and then read named variables from it, for example `result[\"sentiment\"]` or `result[\"rating\"]`.\n- `guidance.json()` only supports a subset of JSON Schema keywords. The documented supported set includes `enum`, `format`, `maximum`, `minimum`, `maxItems`, `minItems`, `properties`, `required`, `type`, and related object/array structure.\n- When using `gen(..., tools=...)`, the API docs require `max_tokens`, and `regex`/`stop` constraints are not supported in the same call.\n- The docs site contains some older notebook material. Prefer the generated API pages plus the current intro tutorial when notebook examples disagree.\n\n## Version-Sensitive Notes For 0.3.1\n\n- PyPI confirms `0.3.1` as the package version covered here.\n- The upstream docs site is published as `latest`, not a pinned `0.3.1` doc set, so verify signatures against the current API pages if you are debugging version-specific behavior.\n- The GitHub releases page exposes `0.3.0` notes publicly, but a matching `0.3.1` release note was not surfaced on that date. For exact behavioral deltas, confirm against the package source or release history before assuming a new API surface.\n- PyPI metadata for `0.3.1` requires Python `>=3.10`.\n\n## Official Sources\n\n- GitHub repository: https://github.com/guidance-ai/guidance\n- ReadTheDocs docs root: https://guidance.readthedocs.io/en/latest/\n- PyPI package page: https://pypi.org/project/guidance/\n"
  },
  {
    "path": "content/gunicorn/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Gunicorn package guide for Python - production WSGI server setup, configuration, and deployment notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.1.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"gunicorn,python,wsgi,server,deployment\"\n---\n\n# Gunicorn Python Package Guide\n\n## What It Is\n\n`gunicorn` is the standard production process manager and HTTP server for Python WSGI apps on Unix-like systems. Use it to run Flask, Django, Pyramid, or any other WSGI callable behind a reverse proxy such as Nginx.\n\nImportant source note: older docs links may point to `https://docs.gunicorn.org/en/stable/`, but current official docs are published at `https://gunicorn.org/`. The old `docs.gunicorn.org` stable pages still render `23.0.0` content, while the new `gunicorn.org` site documents current `25.x` features. Prefer `gunicorn.org` for active work and treat the old stable site as legacy reference material.\n\n## Install\n\nPython compatibility needs a quick check before rollout because current upstream sources do not agree exactly:\n\n- the official install page currently says Python `3.12+`\n- PyPI classifiers for `25.1.0` list Python `3.10` through `3.13`\n\nFor agent work, do not hard-code an older minimum without checking the target deployment environment.\n\n```bash\npip install gunicorn==25.1.0\n```\n\nIf you need optional worker implementations or utilities, install the matching extras instead of assuming they are bundled:\n\n```bash\npip install \"gunicorn[gevent]==25.1.0\"\npip install \"gunicorn[eventlet]==25.1.0\"\npip install \"gunicorn[gthread]==25.1.0\"\npip install \"gunicorn[tornado]==25.1.0\"\npip install \"gunicorn[setproctitle]==25.1.0\"\n```\n\nCurrent install docs mark `eventlet` as deprecated and scheduled for removal in `26.0`.\n\n## Quick Start\n\nMinimal WSGI app:\n\n```python\ndef app(environ, start_response):\n    body = b\"ok\"\n    start_response(\"200 OK\", [\n        (\"Content-Type\", \"text/plain\"),\n        (\"Content-Length\", str(len(body))),\n    ])\n    return [body]\n```\n\nRun it:\n\n```bash\ngunicorn app:app\n```\n\nCommon forms:\n\n```bash\n# Bind explicitly instead of relying on the default 127.0.0.1:8000\ngunicorn --bind 0.0.0.0:8000 app:app\n\n# Django\ngunicorn mysite.wsgi\n\n# ASGI on current Gunicorn docs\ngunicorn app:app --worker-class asgi\n```\n\nThe current quickstart shows `gunicorn app:app` for WSGI and `gunicorn app:app --worker-class asgi` for ASGI.\n\n## Recommended Production Setup\n\nUse a reverse proxy in front of Gunicorn for TLS termination, request buffering, static files, and connection handling. The official deployment guide strongly recommends Nginx or a similar proxy in front of Gunicorn.\n\nTypical startup command:\n\n```bash\ngunicorn \\\n  --bind 127.0.0.1:8000 \\\n  --workers 3 \\\n  --access-logfile - \\\n  --error-logfile - \\\n  mysite.wsgi:application\n```\n\nWorker count is workload-dependent. The official quickstart suggests starting around `(2 x num_cores) + 1` and then measuring under real load.\n\n## Configuration\n\nCurrent official configuration order is, from lower to higher precedence:\n\n- environment variables for supported settings\n- framework-specific config (mainly Paste Deploy)\n- a Python config file, commonly `gunicorn.conf.py`\n- `GUNICORN_CMD_ARGS`\n- CLI flags such as `--bind`, `--workers`, `--worker-class`\n\nExample `gunicorn.conf.py`:\n\n```python\nbind = \"127.0.0.1:8000\"\nworkers = 3\nworker_class = \"sync\"\naccesslog = \"-\"\nerrorlog = \"-\"\ngraceful_timeout = 30\ntimeout = 30\nkeepalive = 2\n```\n\nUseful startup forms:\n\n```bash\ngunicorn -c gunicorn.conf.py mysite.wsgi:application\nGUNICORN_CMD_ARGS=\"--bind=0.0.0.0:8000 --workers=4\" gunicorn mysite.wsgi:application\ngunicorn --check-config mysite.wsgi:application\ngunicorn --print-config mysite.wsgi:application\n```\n\nHigh-signal settings to know:\n\n- `bind`: listen address. Default is `127.0.0.1:8000`, or `0.0.0.0:$PORT` if `PORT` is set.\n- `workers`: process count. More workers increase concurrency but also memory use.\n- `worker_class`: `sync` by default. Async or threaded classes require the right extra/dependency set.\n- `threads`: if you set `threads > 1` with `sync`, Gunicorn switches to `gthread`.\n- `timeout`: hard-kill quiet workers after N seconds.\n- `graceful_timeout`: how long a worker gets to finish during restart before forced exit.\n- `max_requests` and `max_requests_jitter`: recycle workers to mitigate slow memory growth.\n- `preload_app`: loads the app before forking. Good for copy-on-write memory savings, but unsafe if your app opens connections or performs per-process setup at import time.\n- `reload`: development-only auto-reload. Do not combine it with `preload_app` for production assumptions.\n- `worker_connections`: important for async and ASGI workers; use this instead of `threads` when the worker model is connection-oriented.\n\n## Worker Class Guidance\n\nUse the simplest worker model that matches the app:\n\n- `sync`: default for normal WSGI apps doing short blocking work.\n- `gthread`: straightforward way to increase concurrency for blocking I/O without adopting greenlets.\n- `gevent` or `eventlet`: cooperative workers that need compatible libraries and monkey-patching discipline.\n- `tornado`: specialized integration if the app stack already depends on Tornado.\n- `asgi`: first-class worker in the current official docs for FastAPI, Starlette, Quart, and other ASGI apps.\n\n## Reverse Proxy And Trust Settings\n\nGunicorn usually sits behind Nginx, HAProxy, or a platform load balancer. In that setup, the important trust boundary is forwarded headers.\n\n- `secure_scheme_headers` defines which proxy headers imply HTTPS to Gunicorn.\n- `forwarded_allow_ips` controls which proxy IPs are allowed to set those forwarded headers.\n- The deployment guide warns that if you expose Gunicorn directly to the internet, clients can spoof `X-Forwarded-*` headers. Only trust forwarded headers from your actual proxy layer.\n\nTypical proxy header for correct scheme handling:\n\n```nginx\nproxy_set_header X-Forwarded-Proto $scheme;\n```\n\nIf your framework needs help reconstructing the original scheme/host, use its proxy middleware rather than guessing. The official deployment docs explicitly call out Werkzeug's `ProxyFix` for Flask-style stacks.\n\nGunicorn does not provide application auth. Handle authentication and authorization in the app or at the reverse proxy, not in Gunicorn config.\n\n## Logging And Operations\n\nFor containers and systemd, write logs to stdout/stderr:\n\n```bash\ngunicorn \\\n  --access-logfile - \\\n  --error-logfile - \\\n  mysite.wsgi:application\n```\n\nOther practical settings:\n\n- `capture_output = True` forwards application stdout/stderr into Gunicorn error logs.\n- `reuse_port = True` can help certain multi-process deployment patterns, but only enable it when you understand the kernel and load-balancer behavior.\n- `worker_tmp_dir` should point at a fast local filesystem if heartbeat blocking becomes an issue; the settings docs warn that disk-backed temp dirs can stall workers.\n- `raw_env` or `--env KEY=value` can inject runtime environment variables for the app process.\n\n## Common Pitfalls\n\n- Do not rely on the previous old `docs.gunicorn.org/en/stable/` URL for `25.x` behavior; use `gunicorn.org`.\n- Binding to `0.0.0.0` is fine inside a container or private host, but you still usually want a reverse proxy or platform ingress in front.\n- Too many workers can reduce throughput by causing CPU contention and excessive memory use.\n- `sync` workers ignore persistent connections; the settings reference notes that `keepalive` does not affect `sync` workers.\n- `preload_app` can break apps that create DB pools, event loops, or other per-process state during import.\n- Greenlet-based worker classes often need compatible drivers and monkey-patching before imports. If you are not already committed to that model, start with `sync` or `gthread`.\n- If you use PROXY protocol, also restrict `--proxy-allow-from`; do not accept PROXY headers from arbitrary clients unless the service is isolated behind a trusted load balancer.\n- Windows is not the target platform. Gunicorn is designed for Unix-like process semantics.\n\n## Version-Sensitive Notes For `25.1.0`\n\n- PyPI lists `25.1.0` as released on `2026-02-13`.\n- Current official docs document first-class ASGI support, HTTP/2 settings, and dirty-arbiter features in `25.x`.\n- The old `docs.gunicorn.org/en/stable/` pages are stale relative to `25.1.0`; use them only when you need legacy reference context.\n- Current upstream Python-version statements are inconsistent across sources, so verify interpreter support against the deployment target before pinning runtime requirements.\n\n## Official Sources\n\n- Docs root: https://gunicorn.org/\n- Install: https://gunicorn.org/install/\n- Quickstart: https://gunicorn.org/quickstart/\n- Configuration overview: https://gunicorn.org/configure/\n- Settings reference: https://gunicorn.org/reference/settings/\n- Deployment guidance: https://gunicorn.org/deploy/\n- ASGI worker guide: https://gunicorn.org/asgi/\n- PyPI package page: https://pypi.org/project/gunicorn/\n"
  },
  {
    "path": "content/h11/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"h11 package guide for Python - sans-I/O HTTP/1.1 protocol state machine\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.16.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"h11,http,http1.1,protocol,sans-io,networking\"\n---\n\n# h11 Python Package Guide\n\n## Golden Rule\n\nUse `h11` when you need to parse or serialize raw HTTP/1.1 on top of your own transport layer.\n\n`h11` is a low-level, bring-your-own-I/O state machine. It does not open sockets, perform TLS, retry requests, manage connection pools, follow redirects, or implement cookies and auth for you.\n\nIf you need a normal HTTP client or server framework, use something higher level and treat `h11` as an internal protocol layer.\n\n## Install\n\n```bash\npip install h11==0.16.0\n```\n\n```bash\npoetry add h11==0.16.0\n```\n\n```bash\nuv add h11==0.16.0\n```\n\n## Core Model\n\n`h11` turns HTTP/1.1 bytes into typed events and turns typed events back into bytes.\n\n```python\nimport h11\n\nconn = h11.Connection(our_role=h11.CLIENT)\n```\n\nYou drive it with four operations:\n\n1. Read bytes from your socket, stream, or async transport.\n2. Feed them into `conn.receive_data(...)`.\n3. Pull parsed events with `conn.next_event()`.\n4. Build outgoing events and serialize them with `conn.send(...)`.\n\nImportant event types:\n\n- `Request`\n- `Response`\n- `InformationalResponse`\n- `Data`\n- `EndOfMessage`\n- `ConnectionClosed`\n\nImportant sentinels and states:\n\n- `NEED_DATA`: read more bytes before calling `next_event()` again\n- `PAUSED`: stop reading until your application advances the connection cycle\n- `IDLE`, `SEND_BODY`, `SEND_RESPONSE`, `DONE`, `MUST_CLOSE`\n\n## Initialize And Configure\n\nThe main constructor accepts your role and an optional receive-buffer limit:\n\n```python\nimport h11\n\nconn = h11.Connection(\n    our_role=h11.SERVER,\n    max_incomplete_event_size=16 * 1024,\n)\n```\n\n`max_incomplete_event_size` limits how much incomplete request-line/response-line and header data h11 buffers before failing. Increase it only if you expect unusually large headers, because larger values reduce protection against slowloris-style or otherwise malformed input.\n\n## Minimal HTTPS Request\n\nThis follows the upstream \"getting started\" flow, but as a compact script.\n\n```python\nimport socket\nimport ssl\n\nimport h11\n\nctx = ssl.create_default_context()\nsock = ctx.wrap_socket(\n    socket.create_connection((\"httpbin.org\", 443)),\n    server_hostname=\"httpbin.org\",\n)\n\nconn = h11.Connection(our_role=h11.CLIENT)\n\nsock.sendall(\n    conn.send(\n        h11.Request(\n            method=\"GET\",\n            target=\"/get\",\n            headers=[\n                (\"Host\", \"httpbin.org\"),\n                (\"User-Agent\", \"context-hub-example/1.0\"),\n                (\"Accept\", \"application/json\"),\n            ],\n        )\n    )\n)\nsock.sendall(conn.send(h11.EndOfMessage()))\n\nstatus_code = None\nheaders = {}\nbody = bytearray()\n\nwhile True:\n    data = sock.recv(8192)\n    conn.receive_data(data)\n\n    while True:\n        event = conn.next_event()\n\n        if event is h11.NEED_DATA:\n            break\n\n        if isinstance(event, h11.Response):\n            status_code = event.status_code\n            headers = {\n                name.decode(\"ascii\"): value.decode(\"ascii\")\n                for name, value in event.headers\n            }\n        elif isinstance(event, h11.Data):\n            body.extend(event.data)\n        elif isinstance(event, h11.EndOfMessage):\n            sock.close()\n            print(status_code)\n            print(headers[\"content-type\"])\n            print(body.decode(\"utf-8\"))\n            raise SystemExit\n        elif isinstance(event, h11.ConnectionClosed):\n            raise RuntimeError(\"peer closed before EndOfMessage\")\n\n    if data == b\"\":\n        raise RuntimeError(\"unexpected EOF\")\n```\n\n## Sending Request Or Response Bodies\n\nWhen you send a body, emit one or more `Data(...)` events and always finish with `EndOfMessage()`.\n\n```python\nimport h11\n\nconn = h11.Connection(our_role=h11.SERVER)\npayload = b\"hello\"\n\nraw_bytes = b\"\".join(\n    [\n        conn.send(\n            h11.Response(\n                status_code=200,\n                headers=[\n                    (\"Content-Length\", str(len(payload))),\n                    (\"Content-Type\", \"text/plain; charset=utf-8\"),\n                ],\n            )\n        ),\n        conn.send(h11.Data(data=payload)),\n        conn.send(h11.EndOfMessage()),\n    ]\n)\n```\n\nIf you forget framing headers such as `Content-Length` when they are required, h11 will raise a `LocalProtocolError` when you try to send body data.\n\n## Keep-Alive And Connection Reuse\n\n`h11` models one HTTP request/response exchange at a time. Reuse the same TCP connection only after both sides are done:\n\n```python\nif conn.our_state is h11.DONE and conn.their_state is h11.DONE:\n    conn.start_next_cycle()\n```\n\n`start_next_cycle()` resets both sides to `IDLE`. If you call it before both sides reach `DONE`, h11 raises `LocalProtocolError`.\n\n## Auth And Higher-Level Configuration\n\n`h11` has no auth subsystem. Authentication is just headers you construct yourself:\n\n```python\nheaders = [\n    (\"Host\", \"api.example.com\"),\n    (\"Authorization\", f\"Bearer {token}\"),\n    (\"Accept\", \"application/json\"),\n]\n```\n\nYou are responsible for all higher-level behavior around h11:\n\n- TCP or Unix socket setup\n- TLS contexts and certificate verification\n- timeouts and cancellation\n- retries and reconnects\n- connection pooling\n- proxy handling\n- redirects\n- compression/decompression\n- cookie jars and session state\n\n## Common Pitfalls\n\n### `h11` is not an HTTP client library\n\nDo not expect `h11` to behave like `requests`, `httpx`, or `urllib3`. It only understands protocol events and framing.\n\n### Always send `EndOfMessage()`\n\nEven when h11 serializes it as `b\"\"`, your application should still send the `EndOfMessage()` event so the state machine stays correct.\n\n### Drain `next_event()` until `NEED_DATA` or `PAUSED`\n\nOne read from the network can yield multiple events. Do not assume a single `recv()` call maps to a single HTTP event.\n\n### Call `receive_data(b\"\")` on EOF\n\nEOF is meaningful input to h11. Feed `b\"\"` when the transport closes so it can emit `ConnectionClosed` or finish parsing EOF-terminated cases correctly.\n\n### HTTP/1.1 requests need exactly one `Host` header\n\nCreating a `Request` with HTTP/1.1 and no `Host` header raises `LocalProtocolError`. Multiple `Host` headers are also invalid.\n\n### Header names and values are normalized\n\nWhen constructing events, h11 accepts ASCII strings or bytes-like values, normalizes header names to lowercase bytes internally, and validates whitespace and illegal characters. When reading events back, response/request headers are exposed as bytes pairs.\n\n### Write failures must poison the state machine\n\nIf `conn.send(...)` produced bytes but your transport failed before they were actually sent, call `conn.send_failed()` and stop reusing that `Connection`.\n\n### Upgrades and tunneling need a handoff\n\nIf you implement `Upgrade` or `CONNECT`, expect `PAUSED` and protocol-switch states such as `MIGHT_SWITCH_PROTOCOL`. At that point you must hand the transport and any trailing bytes to the next protocol layer yourself.\n\n## Version-Sensitive Notes For `0.16.0`\n\n- This entry targets `h11==0.16.0`.\n- The docs URL points at `/latest/`, which currently renders `0.16.0+dev` docs. For package-accurate behavior, use `https://h11.readthedocs.io/en/v0.16.0/`.\n- `0.16.0` added a security fix that rejects certain malformed `Transfer-Encoding: chunked` bodies that were previously accepted, closing a request-smuggling risk in some proxy or load-balancer deployments.\n- `0.15.0`, which is included in the upgrade path to `0.16.0`, rejects absurdly large `Content-Length` values earlier instead of attempting full integer parsing.\n- Current maintainer docs and PyPI metadata both describe `h11` as requiring Python `3.8+`.\n\n## Official Sources Used\n\n- `https://h11.readthedocs.io/en/latest/`\n- `https://h11.readthedocs.io/en/v0.16.0/`\n- `https://h11.readthedocs.io/en/stable/basic-usage.html`\n- `https://h11.readthedocs.io/en/stable/api.html`\n- `https://h11.readthedocs.io/en/v0.16.0/changes.html`\n- `https://pypi.org/project/h11/`\n"
  },
  {
    "path": "content/h3/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"h3 Python package for hexagonal geospatial indexing, traversal, and polygon coverage\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"h3,geospatial,gis,hexagonal-grid,geojson,uber\"\n---\n\n# h3 Python Package Guide\n\n## Golden Rule\n\nUse `h3` for local geospatial indexing and polygon-to-cell coverage, and keep the coordinate conventions straight: core point and boundary APIs use `(lat, lng)`, while GeoJSON-style `__geo_interface__` objects use `(lng, lat)`. For most Python code, stick with the default string API from `import h3` unless you have a measured reason to switch to an integer or NumPy-oriented API.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"h3==4.4.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"h3==4.4.2\"\npoetry add \"h3==4.4.2\"\n```\n\nOptional extra for NumPy-oriented work:\n\n```bash\npython -m pip install \"h3[numpy]==4.4.2\"\n```\n\nIf you use conda instead of PyPI, the upstream docs point to `conda-forge` as the package source:\n\n```bash\nconda config --add channels conda-forge\nconda install h3-py\n```\n\n## Initialization And API Choice\n\nThe default import uses the string-oriented API:\n\n```python\nimport h3\n\nprint(h3.versions())\n```\n\n`h3.versions()` returns both the Python wrapper version and the wrapped C library version. Upstream guarantees that the Python and C versions match on major and minor (`X.Y`) even if the patch versions differ.\n\n`h3-py` exposes multiple APIs with the same function names but different input and output types:\n\n- `import h3` or `import h3.api.basic_str as h3`: default, human-readable hex strings\n- `import h3.api.basic_int as h3`: Python integers instead of strings\n- `import h3.api.numpy_int as h3`: NumPy-friendly integer arrays\n- `import h3.api.memview_int as h3`: memoryview-oriented API for lower-overhead bulk work\n\nChoose one API per module and stay consistent. If your project stores H3 indexes as strings in JSON, databases, or logs, the default API is usually the right choice.\n\n## Core Usage\n\n### Convert a point to a cell and back\n\n```python\nimport h3\n\nlat, lng = 37.769377, -122.388903\ncell = h3.latlng_to_cell(lat, lng, 9)\n\nprint(cell)                    # '89283082e73ffff'\nprint(h3.get_resolution(cell)) # 9\nprint(h3.cell_to_latlng(cell)) # (lat, lng)\nprint(h3.cell_to_boundary(cell))\n```\n\nUse these functions as your baseline:\n\n- `latlng_to_cell(lat, lng, res)`: point to cell\n- `cell_to_latlng(cell)`: cell center\n- `cell_to_boundary(cell)`: boundary vertices as `(lat, lng)` tuples\n- `cell_area(cell, unit=\"km^2\")` and `average_hexagon_area(res, unit=\"km^2\")`: area calculations\n\n### Traverse the grid\n\n```python\nimport h3\n\norigin = h3.latlng_to_cell(37.769377, -122.388903, 9)\n\nneighbors = h3.grid_disk(origin, 2)\nring = h3.grid_ring(origin, 1)\n\nprint(len(neighbors))\nprint(h3.are_neighbor_cells(origin, ring[0]))\n```\n\nUseful traversal functions:\n\n- `grid_disk(cell, k)`: all cells within grid distance `<= k`\n- `grid_ring(cell, k)`: cells at exactly distance `k`\n- `grid_distance(a, b)`: number of grid steps between cells\n- `grid_path_cells(start, end)`: ordered minimum-length path\n\n`grid_disk`, `grid_ring`, and several hierarchy helpers return unordered collections. Do not write code that depends on a stable iteration order unless the function explicitly documents ordered output.\n\n### Move up and down the hierarchy\n\n```python\nimport h3\n\ncell = h3.latlng_to_cell(37.769377, -122.388903, 9)\nparent = h3.cell_to_parent(cell, 7)\nchildren = h3.cell_to_children(parent, 9)\n\ncompacted = h3.compact_cells(children)\nexpanded = h3.uncompact_cells(compacted, 9)\n```\n\nHierarchy helpers that come up often:\n\n- `cell_to_parent(cell, res)`\n- `cell_to_children(cell, res)`\n- `cell_to_children_size(cell, res)`\n- `compact_cells(cells)` / `uncompact_cells(cells, res)`\n\n### Cover a polygon with cells\n\nFor GeoJSON-like objects, use `geo_to_cells`. Geo objects use `(lng, lat)` coordinate order.\n\n```python\nimport h3\n\npolygon = {\n    \"type\": \"Polygon\",\n    \"coordinates\": [[\n        (-122.4089866999972145, 37.813318999983238),\n        (-122.3805436999997056, 37.7866302000007224),\n        (-122.3544736999993603, 37.7198061999978478),\n        (-122.5123436999983966, 37.7076131999975672),\n        (-122.5247187000021967, 37.7835871999971715),\n        (-122.4798767000009008, 37.8151571999998453),\n        (-122.4089866999972145, 37.813318999983238),\n    ]],\n}\n\ncells = h3.geo_to_cells(polygon, res=9)\nshape = h3.cells_to_h3shape(cells)\ngeojson = h3.cells_to_geo(cells)\n```\n\nIf you want the explicit polygon classes, use `LatLngPoly` and `LatLngMultiPoly`, which expect `(lat, lng)` points:\n\n```python\nimport h3\n\npoly = h3.LatLngPoly(\n    [\n        (37.804, -122.412),\n        (37.778, -122.507),\n        (37.733, -122.501),\n    ]\n)\n\ncells = h3.h3shape_to_cells(poly, res=7)\n```\n\nInteroperability functions:\n\n- `geo_to_h3shape(geo)` / `h3shape_to_geo(shape)`\n- `geo_to_cells(geo, res)` / `cells_to_geo(cells, tight=False)`\n- `h3shape_to_cells(shape, res)` / `cells_to_h3shape(cells, tight=False)`\n- `polygon_to_cells(...)`: alias for `h3shape_to_cells(...)`\n\n## Configuration And Environment\n\nThere is no API key, network configuration, or service endpoint to set. The configuration choices that matter in practice are:\n\n- Index representation: string API vs integer/NumPy APIs\n- Coordinate convention: `(lat, lng)` for core H3 functions and `LatLngPoly`, `(lng, lat)` for GeoJSON-like objects\n- Coordinate reference system: convert projected data to WGS84 / EPSG:4326 before calling `geo_to_cells`\n\nFor GeoPandas or Shapely workflows, make sure the geometry is in latitude/longitude degrees before passing it into `h3`. Upstream explicitly warns that projected CRS values like EPSG:2263 will produce incorrect results.\n\n## Common Pitfalls\n\n- `import h3` is the default string API, not the integer API. If another part of the code expects `uint64`-like integers, import `h3.api.basic_int` or `h3.api.numpy_int` explicitly.\n- `latlng_to_cell()` and `cell_to_boundary()` use `(lat, lng)`, but GeoJSON and `__geo_interface__` use `(lng, lat)`. This mismatch is the easiest way to generate wrong cells.\n- `cell_to_children()`, `grid_disk()`, `grid_ring()`, and `compact_cells()` work with unordered collections. Sort only if your application truly needs deterministic output.\n- `geo_to_cells()` fills cells whose centroids are contained in the polygon. If you need alternate containment semantics, use `h3shape_to_cells_experimental()` or `polygon_to_cells_experimental()` and check the current containment-mode options in the upstream API reference.\n- `cells_to_h3shape()` and `cells_to_geo()` assume a valid cell set. Mixed resolutions and duplicate cells are a common source of downstream errors.\n- Shapely or GeoPandas objects may be compatible through `__geo_interface__`, but their CRS is your responsibility. Reproject first.\n- If you exchange H3 indexes across services, normalize them early. Mixing string IDs and integer IDs in the same code path creates subtle bugs.\n\n## Version-Sensitive Notes For 4.4.2\n\n- PyPI currently lists `4.4.2` as the latest stable release for `h3`, published on January 29, 2026.\n- `4.4.2` is a bugfix release. The changelog notes an error check fix in `cellsToLinkedMultiPolygon`, which matters if you convert cell sets back into polygons.\n- The `4.4.0` changelog added `is_valid_index`, `get_index_digit`, `construct_cell`, and `deconstruct_cell`, plus several new concrete error classes such as `H3IndexInvalidError`.\n- `polygon_to_cells` is a `4.1.x` alias for `h3shape_to_cells`. Older snippets may still use earlier v4 beta names or the v3-era shape API.\n- `polygon_to_cells_experimental` and `h3shape_to_cells_experimental` arrived in `4.2.0`; do not assume they exist in older `4.1.x` environments.\n- The v4 line changed function names and introduced the newer error system. If you are upgrading old code or copying blog posts written for `3.x`, verify every function name against the current quick reference.\n- Upstream has already published `4.5.0` alpha releases as of February 2026, including a future Python minimum of `3.10`. That does not apply to stable `4.4.2`, but it is relevant if you track pre-releases.\n\n## Official Sources\n\n- Docs root: https://uber.github.io/h3-py/\n- API quick reference: https://uber.github.io/h3-py/api_quick.html\n- API comparison: https://uber.github.io/h3-py/api_comparison.html\n- Polygon tutorial: https://uber.github.io/h3-py/polygon_tutorial.html\n- Changelog: https://uber.github.io/h3-py/_changelog.html\n- PyPI: https://pypi.org/project/h3/\n"
  },
  {
    "path": "content/hamilton/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hamilton PyPI package guide for the legacy 0.1.0 mechanics GUI package\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"hamilton,python,mechanics,gui,legacy,pydy\"\n---\n\n# Hamilton Python Package Guide\n\n## Golden Rule\n\nDo not assume `pip install hamilton` gives you the modern Apache Hamilton DAG framework.\n\nThe PyPI package named `Hamilton` is a separate legacy project published at version `0.1.0` on August 9, 2013. Its maintainer-provided description presents it as a GUI application for determining and solving Hamilton equations, with a workflow centered on launching `GUI-Hamilton.py` from Spyder. If you actually need the modern dataflow framework, use the official `sf-hamilton` package instead.\n\n## What This Package Actually Is\n\nUpstream describes `Hamilton` as a Python application for determining and solving Hamilton equations. The published instructions are oriented around:\n\n- installing scientific Python dependencies manually\n- unpacking the source archive\n- running `python setup.py install`\n- opening `GUI-Hamilton.py` in Spyder and pressing `F5`\n\nThis is not documented as a conventional library-first package with a stable import API.\n\n## Install\n\nPrefer a disposable virtual environment or container. The published package is old enough that modern Python compatibility is uncertain.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip setuptools wheel\npython -m pip install \"Hamilton==0.1.0\"\n```\n\nIf installation from PyPI fails because the package expects an older scientific stack, inspect the source archive instead of forcing it into a modern production environment.\n\n```bash\npython -m pip download \"Hamilton==0.1.0\"\ntar -xf Hamilton-0.1.0.tar.gz\ncd Hamilton-0.1.0\npython setup.py install\n```\n\n## Documented Dependencies\n\nThe maintainer-provided PyPI description names these prerequisites:\n\n- `Qt`\n- `SIP`\n- `PyQt`\n- `Sympy`\n- `Numpy`\n- `Scipy`\n- `Matplotlib`\n- `Control`\n- `Slycot`\n\nTreat that dependency list as historical guidance, not a modern lockfile. Some package names, binary wheels, and Python-version support have changed since 2013.\n\n## Initialize And Run\n\nThe only documented startup flow is GUI-based:\n\n```bash\npython GUI-Hamilton.py\n```\n\nIf the installed package does not place `GUI-Hamilton.py` on your path, inspect the unpacked source tree or installed files under `site-packages` to find the entry script.\n\nBecause the upstream instructions explicitly reference Spyder, expect an interactive desktop workflow rather than a headless server or importable SDK workflow.\n\n## Core Usage Expectations\n\nThere is no maintainer-published API reference for functions, classes, or a supported `import hamilton` surface.\n\nFor coding-agent work, the practical approach is:\n\n1. Confirm that `Hamilton` is really the intended dependency and not `sf-hamilton`.\n2. Inspect the installed files or unpacked source archive before writing code against it.\n3. Treat it as a legacy GUI/scientific application unless your project already has working examples.\n4. Avoid inventing module names, CLI flags, or object APIs that are not visible in the source tree you installed.\n\n## Configuration\n\nThe official package page does not document environment variables, auth, network configuration, or a structured config file format.\n\nAssume:\n\n- no authentication model\n- local desktop execution\n- configuration, if any, is embedded in the GUI flow or source files\n\nIf you need reproducible automation, inspect the source directly and wrap only the parts you can verify.\n\n## Common Pitfalls\n\n- `pip install hamilton` is easy to confuse with the modern Apache Hamilton project. They are different packages.\n- The package is old and may not install cleanly on current Python versions or current Qt bindings.\n- Upstream docs are minimal and do not define a stable Python import API.\n- The published instructions use `setup.py` and Spyder-era tooling, which is a strong sign that the package predates modern packaging norms.\n- Scientific dependencies such as `slycot` can be hard to build on clean machines without platform-specific system libraries.\n- The package name is capitalized on PyPI (`Hamilton`), but import paths and script names should be verified from the installed files instead of guessed.\n\n## Version-Sensitive Notes\n\n- The only release shown on PyPI is `0.1.0`.\n- The previous docs URL (`http://pypi.python.org/pypi/Hamilton/`) is a legacy PyPI page, not a maintained documentation site.\n- As of March 12, 2026, the current PyPI project page still points to the same legacy `0.1.0` release with a 2013 description.\n- If your real goal is the actively maintained Hamilton framework, the official package is `sf-hamilton`, and the official install docs say to install that package rather than `hamilton`.\n\n## If You Actually Need Apache Hamilton\n\nUse the official modern package instead:\n\n```bash\npython -m pip install \"sf-hamilton[visualization]\"\n```\n\nOfficial docs for that separate project:\n\n- `https://pypi.org/project/sf-hamilton/`\n- `https://hamilton.apache.org/get-started/install/`\n\nDo not mix examples or imports between `Hamilton==0.1.0` and `sf-hamilton`.\n"
  },
  {
    "path": "content/hatch/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hatch Python project manager for environments, builds, publishing, and versioning\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.16.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"hatch,python,packaging,pyproject,build,publish,virtualenv\"\n---\n\n# Hatch Python Package Guide\n\n## Golden Rule\n\nUse `hatch` as a project-level CLI for Python packaging workflows, but use `hatchling` as the build backend in `pyproject.toml`. Most project configuration lives under `tool.hatch` in `pyproject.toml`; if you also create `hatch.toml`, its top-level settings override the `pyproject.toml` equivalents.\n\n## Install\n\nPin the CLI version if your project or automation depends on specific Hatch behavior:\n\n```bash\npython -m pip install \"hatch==1.16.5\"\n```\n\nCommon tool-install alternatives:\n\n```bash\npipx install \"hatch==1.16.5\"\nuv tool install \"hatch==1.16.5\"\n```\n\nVerify the installed CLI:\n\n```bash\nhatch --version\n```\n\nThe official install page for the `1.16` docs stream still shows `1.16.4` in its sample verification output. For this guide, treat PyPI `1.16.5` as the package version of record.\n\n## Initialize Or Adopt A Project\n\nCreate a new project from Hatch's template:\n\n```bash\nhatch new awesome-app\ncd awesome-app\n```\n\nInitialize Hatch metadata in an existing project instead:\n\n```bash\nhatch new --init\n```\n\nFor package builds, make sure your `pyproject.toml` uses Hatchling:\n\n```toml\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n```\n\nMinimal project setup with dynamic versioning and a default dev environment:\n\n```toml\n[project]\nname = \"awesome-app\"\ndynamic = [\"version\"]\ndependencies = [\n  \"httpx>=0.28\",\n]\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.version]\npath = \"src/awesome_app/__about__.py\"\n\n[tool.hatch.envs.default]\npython = \"3.12\"\ndependencies = [\n  \"pytest\",\n  \"ruff\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = \"pytest\"\nlint = \"ruff check .\"\nfmt = \"ruff format .\"\n```\n\nVersion file example:\n\n```python\n# src/awesome_app/__about__.py\n__version__ = \"0.1.0\"\n```\n\n## Core Usage\n\n### Work with environments\n\nIf you define no environments, Hatch automatically provides a `default` environment. Create or refresh environments explicitly when you want deterministic setup in CI or local tooling:\n\n```bash\nhatch env create\nhatch env show\n```\n\nRun commands inside the default environment:\n\n```bash\nhatch run python -V\nhatch run test\nhatch run lint\n```\n\nTarget a named environment when you have more than one:\n\n```bash\nhatch run lint:check\nhatch run test.py311:pytest\n```\n\nOpen a shell in the default environment:\n\n```bash\nhatch shell\n```\n\n### Use tool-only or matrix environments\n\nDetached environments are useful for linting, docs, or other tooling that should not install your package:\n\n```toml\n[tool.hatch.envs.lint]\ndetached = true\ndependencies = [\n  \"ruff\",\n]\n\n[tool.hatch.envs.lint.scripts]\ncheck = \"ruff check .\"\n```\n\nIf you want an environment to exist without installing the project itself, set:\n\n```toml\nskip-install = true\n```\n\nFor multi-version testing, define a matrix:\n\n```toml\n[tool.hatch.envs.test]\ndependencies = [\"pytest\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.10\", \"3.11\", \"3.12\"]\n```\n\nThen run a specific matrix environment such as `hatch run test.py311:pytest`.\n\n### Build artifacts\n\nBuild both wheel and source distribution:\n\n```bash\nhatch build\n```\n\nBuild only one target:\n\n```bash\nhatch build -t wheel\nhatch build -t sdist\n```\n\nArtifacts are written to `dist/` by default.\n\n### Manage versions\n\nShow the current project version:\n\n```bash\nhatch version\n```\n\nBump semver-style versions:\n\n```bash\nhatch version patch\nhatch version minor\nhatch version major\n```\n\nSet an explicit version:\n\n```bash\nhatch version 1.2.3\n```\n\nBy default, Hatch's code version source expects a `__version__ = \"...\"` assignment. If your version lives elsewhere or uses a different format, configure a different source or regex under `tool.hatch.version`.\n\n## Config And Auth\n\n### Where configuration lives\n\nPreferred project config location:\n\n- `pyproject.toml` under `tool.hatch`\n\nOptional override location:\n\n- `hatch.toml`\n\n`hatch.toml` uses top-level keys rather than the `tool.hatch` prefix and takes precedence over equivalent `pyproject.toml` settings. Keep one source of truth when possible; mixing both files is a common cause of confusion.\n\n### Choose the environment installer\n\nHatch supports `pip` and `uv` for environment installation. To make `uv` the project default:\n\n```toml\n[tool.hatch.envs.default]\ninstaller = \"uv\"\n```\n\nUse this only when your team machines or CI images have a compatible `uv` available.\n\n### Configure publishing targets\n\nRepository configuration belongs in Hatch's user config, not in committed project metadata. Example:\n\n```toml\n# ~/.config/hatch/config.toml\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n```\n\nPublish to TestPyPI with environment variables:\n\n```bash\nexport HATCH_INDEX_REPO=test\nexport HATCH_INDEX_USER=__token__\nexport HATCH_INDEX_AUTH=pypi-xxxxxxxxxxxxxxxx\n\nhatch build\nhatch publish\n```\n\nUseful publishing flags and environment variables:\n\n- `--repo` / `HATCH_INDEX_REPO`\n- `--user` / `HATCH_INDEX_USER`\n- `--auth` / `HATCH_INDEX_AUTH`\n- `--ca-cert` / `HATCH_INDEX_CA_CERT`\n- `--client-cert` / `HATCH_INDEX_CLIENT_CERT`\n- `--client-key` / `HATCH_INDEX_CLIENT_KEY`\n\n`hatch publish` uploads built `.whl` and `.tar.gz` artifacts from `dist/` by default. Build first so the upload step is explicit and reproducible.\n\n## Common Pitfalls\n\n- Installing `hatch` does not replace the need for `hatchling` in `[build-system]`. The CLI package and the build backend serve different roles.\n- If both `pyproject.toml` and `hatch.toml` define the same Hatch settings, `hatch.toml` wins. This can make local behavior differ from CI unexpectedly.\n- `hatch version` only works cleanly when the configured version source matches the file layout in your repository.\n- `detached = true` and `skip-install = true` are useful for tooling environments, but they also mean your package code is not installed there. Do not run package-import tests in those envs unless that is intentional.\n- `hatch publish` does not infer alternate repositories unless you pass `--repo` or set `HATCH_INDEX_REPO`.\n- Matrix environment names are generated from the matrix values. Check `hatch env show` before hard-coding names in scripts or CI.\n\n## Version-Sensitive Notes For 1.16.x\n\n- The official docs are versioned by `MAJOR.MINOR` rather than exact patch number. For `hatch 1.16.5`, the matching docs family is `https://hatch.pypa.io/1.16/`, while `latest` currently points at the same `1.16` stream.\n- The `1.16.0` release added workspaces, dependency groups, and SBOM support, and dropped Python 3.9 support. If you are upgrading from `1.15.x` or earlier, confirm your Python baseline and project layout assumptions before copying old config.\n- The official install page currently includes stale `1.16.4` verification text even though PyPI lists `1.16.5`. Prefer PyPI for the exact package version and the docs site for behavior and configuration.\n\n## Official Links\n\n- Docs root: https://hatch.pypa.io/latest/\n- Versioned docs: https://hatch.pypa.io/1.16/\n- Install guide: https://hatch.pypa.io/1.16/install/\n- Environment overview: https://hatch.pypa.io/1.16/config/environment/overview/\n- Build configuration: https://hatch.pypa.io/1.16/config/build/\n- Versioning: https://hatch.pypa.io/1.16/version/\n- Publishing: https://hatch.pypa.io/1.16/publish/\n- PyPI package: https://pypi.org/project/hatch/1.16.5/\n"
  },
  {
    "path": "content/hatchling/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hatchling build backend for Python packages, covering pyproject.toml setup, build targets, version sources, and hooks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,packaging,build-backend,pep517,pyproject,hatchling\"\n---\n\n# Hatchling Python Package Guide\n\n## Golden Rule\n\nUse `hatchling` as your PEP 517 build backend in `pyproject.toml`, not as a runtime dependency. Put project metadata in `[project]`, put build behavior in `[tool.hatch.build...]`, and let a frontend like `pip`, `python -m build`, or `hatch build` drive the build.\n\n## Install\n\nIn most projects, do not manually import or run `hatchling`. Declare it in `[build-system]` and let the build frontend install it in an isolated build environment.\n\nMinimal setup:\n\n```toml\n[build-system]\nrequires = [\"hatchling>=1.29.0\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"acme-widget\"\nversion = \"0.1.0\"\ndescription = \"Example package\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\ndependencies = [\n  \"httpx>=0.27\",\n]\n```\n\nUseful local tools:\n\n```bash\npython -m pip install --upgrade build\npython -m pip install \"hatchling==1.29.0\"\n```\n\nUse `build` when you want `python -m build`; the frontend is separate from Hatchling itself.\n\n## Initialize A Package\n\nA practical `src/` layout looks like this:\n\n```text\npyproject.toml\nREADME.md\nsrc/\n  acme_widget/\n    __init__.py\n```\n\nMinimal `pyproject.toml` for a `src/` layout:\n\n```toml\n[build-system]\nrequires = [\"hatchling>=1.29.0\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"acme-widget\"\nversion = \"0.1.0\"\ndescription = \"Example package\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/acme_widget\"]\n```\n\n`packages = [\"src/acme_widget\"]` tells the wheel target what package to ship and rewrites the installed path to `acme_widget`.\n\n## Core Usage\n\n### Build distributions\n\nHatchling is a backend. Common frontend commands are:\n\n```bash\n# Build sdist + wheel\npython -m build\n\n# Build only a wheel\npython -m build --wheel\n\n# Build only an sdist\npython -m build --sdist\n\n# Install the local project through pip\npython -m pip install .\n\n# If you use Hatch as the frontend\nhatch build\n```\n\n### Use standard project metadata\n\nHatchling uses PEP 621 project metadata from `[project]`:\n\n```toml\n[project]\nname = \"acme-widget\"\nversion = \"0.1.0\"\ndescription = \"Example package\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\ndependencies = [\"httpx>=0.27\"]\n\n[project.optional-dependencies]\ndev = [\"pytest>=8\", \"ruff>=0.11\"]\n\n[project.scripts]\nacme-widget = \"acme_widget.cli:main\"\n```\n\nKeep package metadata here unless the field is explicitly dynamic.\n\n### Control what goes into the wheel and sdist\n\nGlobal build settings live under `[tool.hatch.build]`. Target-specific settings live under `[tool.hatch.build.targets.<target>]`.\n\nExample:\n\n```toml\n[tool.hatch.build]\ninclude = [\n  \"/src\",\n  \"/README.md\",\n  \"/LICENSE\",\n]\nartifacts = [\n  \"build/*.json\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/acme_widget\"]\nonly-packages = true\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n  \"/src\",\n  \"/tests\",\n  \"/README.md\",\n  \"/LICENSE\",\n  \"/pyproject.toml\",\n]\n```\n\nPractical rules:\n\n- `wheel` should usually contain only importable package contents plus explicitly selected data.\n- `sdist` should usually contain source, tests, docs needed for build, and packaging metadata.\n- `only-packages = true` removes non-package files from the wheel unless you force-include them.\n- `artifacts` are for files generated during the build or otherwise included outside normal VCS-style selection.\n\n### Dynamic versioning\n\nIf you do not want a static version in `[project]`, declare it as dynamic and configure `[tool.hatch.version]`.\n\nRegex source, using the default `__version__` pattern:\n\n```toml\n[project]\nname = \"acme-widget\"\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"src/acme_widget/__about__.py\"\n```\n\n```python\n# src/acme_widget/__about__.py\n__version__ = \"0.1.0\"\n```\n\nOther built-in sources worth knowing:\n\n- `source = \"code\"` loads a Python file and evaluates an expression, defaulting to `__version__`\n- `source = \"env\"` reads the version from an environment variable\n- `hatch-vcs` is the main third-party option when versioning should come from Git tags\n\nIf you use `source = \"code\"` with a `src/` layout and the file imports your own package modules, you may need absolute imports plus `search-paths = [\"src\"]`.\n\n### Build hooks\n\nBuild hooks run around each selected build target and can modify build data before or after the build.\n\nCustom hooks normally live in `hatch_build.py`:\n\n```toml\n[tool.hatch.build.targets.wheel.hooks.custom]\n```\n\n```python\nfrom hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\nclass CustomBuildHook(BuildHookInterface):\n    def initialize(self, version, build_data):\n        build_data[\"artifacts\"].append(\"build/generated/schema.json\")\n```\n\nUseful facts:\n\n- Global build hooks run before target-specific hooks.\n- Hooks can influence build data such as `artifacts` and forced inclusions.\n- If you need a hook dependency or a third-party hook plugin, add it to `[build-system].requires`.\n\n### Metadata hooks\n\nMetadata hooks modify project metadata after Hatchling loads it. This is useful when fields like dependencies or the readme must be rewritten at build time.\n\nCustom metadata hooks also default to `hatch_build.py`:\n\n```toml\n[tool.hatch.metadata.hooks.custom]\n```\n\n```python\nfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\nclass CustomMetadataHook(MetadataHookInterface):\n    def update(self, metadata):\n        metadata[\"keywords\"] = [\"acme\", \"widget\"]\n```\n\n### Write the version into a file during builds\n\nIf your runtime code needs a version file generated at build time, use the built-in version build hook:\n\n```toml\n[project]\nname = \"acme-widget\"\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"src/acme_widget/__about__.py\"\n\n[tool.hatch.build.hooks.version]\npath = \"src/acme_widget/_version.py\"\n```\n\nThat hook writes the resolved project version into the target file during the build.\n\n## Configuration And Environment\n\nThere is no authentication model for Hatchling itself.\n\nConfiguration lives in `pyproject.toml`. Environment-sensitive behavior mainly appears in these cases:\n\n- `source = \"env\"` versioning reads the version from an environment variable\n- build frontends create isolated environments from `[build-system].requires`\n- `HATCH_METADATA_CLASSIFIERS_NO_VERIFY` disables trove-classifier verification if you need to bypass that check\n\nIf a build depends on local plugins, dynamic metadata, or custom hooks, treat `[build-system].requires` as the complete build-time dependency set.\n\n## Common Pitfalls\n\n- Do not confuse Hatchling with the full `hatch` CLI. `hatchling` is the backend; `hatch` is an optional frontend and project manager.\n- Do not put package metadata like `dependencies`, entry points, or `requires-python` under `[tool.hatch.build]`; those belong under `[project]`.\n- If you set `dynamic = [\"version\"]`, you must also configure a version source. Otherwise the build will not know how to resolve the version.\n- If Hatchling cannot determine what the wheel should include, define `packages`, `only-include`, `include`, or `force-include` explicitly. Recent Hatchling versions are stricter here and fail instead of guessing silently.\n- `only-packages = true` is convenient, but it will drop top-level files that are not part of a Python package. Add explicit inclusion for package data or generated assets you still need.\n- `artifacts` are not affected by `exclude`. If you need to exclude a subset of artifact matches, use more precise patterns or explicit negation.\n- `skip-excluded-dirs = true` can speed up builds, but it may prevent discovery under directories you later expected Hatchling to inspect. Use it carefully in repos with generated files or unusual layouts.\n- If you use the `code` version source, relative imports inside the loaded file are a common failure mode. Prefer absolute imports and set `search-paths` when needed.\n- Hook plugins and metadata plugins are build-time dependencies. If they are missing from `[build-system].requires`, the build can fail only in isolated CI builds while appearing to work locally.\n\n## Version-Sensitive Notes For 1.29.0\n\n- As of March 12, 2026, PyPI lists `hatchling 1.29.0` and requires Python `>=3.10`.\n- `1.28.0` dropped Python 3.9 support and added the `sbom-files` option plus `sbom_files` build data for the `wheel` target. If your build still assumes Python 3.9, you must stay on an older release.\n- `1.27.0` updated the default core metadata version to `2.4`.\n- `1.26.0` changed `license-files` to the newer array-of-glob-patterns form and added `HATCH_METADATA_CLASSIFIERS_NO_VERIFY`.\n- PyPI marks `1.26.0`, `1.26.1`, and `1.26.2` as yanked. Do not copy pins to those versions from stale lockfiles or blog posts; use `1.26.3+`.\n\n## Official Sources\n\n- Docs root: `https://hatch.pypa.io/latest/`\n- Build configuration: `https://hatch.pypa.io/latest/config/build/`\n- Project metadata: `https://hatch.pypa.io/latest/config/metadata/`\n- Wheel builder: `https://hatch.pypa.io/latest/plugins/builder/wheel/`\n- Source distribution builder: `https://hatch.pypa.io/latest/plugins/builder/sdist/`\n- Versioning: `https://hatch.pypa.io/latest/version/`\n- Version source plugins: `https://hatch.pypa.io/latest/plugins/version-source/reference/`\n- Build hook plugins: `https://hatch.pypa.io/latest/plugins/build-hook/reference/`\n- Metadata hook plugins: `https://hatch.pypa.io/latest/plugins/metadata-hook/reference/`\n- Hatchling release history: `https://hatch.pypa.io/dev/history/hatchling/`\n- PyPI package page: `https://pypi.org/project/hatchling/`\n"
  },
  {
    "path": "content/haystack-ai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Haystack AI Python framework for modular RAG pipelines, agents, custom components, and integrations\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.25.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"haystack,rag,agents,llm,pipelines,retrieval\"\n---\n\n# Haystack AI Python Package Guide\n\n## Golden Rule\n\nUse `haystack-ai` 2.x for new Haystack work, not the legacy `farm-haystack` package. Build applications as explicit pipelines of components, keep secrets in environment variables via Haystack `Secret`s, and treat the core package as the orchestration layer while adding integration packages only when a component or backend actually requires them.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"haystack-ai==2.25.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv pip install \"haystack-ai==2.25.2\"\nuv add \"haystack-ai==2.25.2\"\nconda config --add channels conda-forge/label/haystack-ai_rc\nconda install haystack-ai\n```\n\nImportant install notes:\n\n- Do not keep `farm-haystack` and `haystack-ai` in the same environment. The official installation guide says mixed installs can fail in obscure ways.\n- Base installation is intentionally lightweight. Some components need optional Python dependencies, and Haystack will raise an `ImportError` telling you what to install.\n- Many external providers and backends are documented as Haystack integrations. The API reference separates the core `haystack-ai` package from integrations distributed as separate packages.\n\nIf you need to clean up a mixed 1.x and 2.x environment:\n\n```bash\npython -m pip uninstall -y farm-haystack haystack-ai\npython -m pip install \"haystack-ai==2.25.2\"\n```\n\n## Core Concepts\n\n### Pipelines\n\nHaystack pipelines are directed multigraphs of components. The practical flow is:\n\n1. Create a `Pipeline()`\n2. Add components with `add_component()`\n3. Wire them with `connect()`\n4. Execute with `run()`\n\nConnections are validated before runtime, which helps catch type and socket mismatches early.\n\n### Documents and Retrievers\n\n`Document` is the basic unit of retrieved context. For local experiments, the simplest setup is `InMemoryDocumentStore` plus `InMemoryBM25Retriever`.\n\n### ChatMessage\n\nFor chat-oriented generators and agents, use `ChatMessage.from_user(...)`, `from_system(...)`, `from_assistant(...)`, and `from_tool(...)`. Current docs treat those factory methods as the standard way to create messages.\n\n### Secrets\n\nUse `from haystack.utils import Secret` and prefer `Secret.from_env_var(...)` for API keys. Environment-variable secrets serialize safely because Haystack stores the variable name, not the raw secret value.\n\n## Minimal RAG Pipeline\n\nThis is the current official-style \"first app\" pattern for Haystack 2.25: load documents, retrieve them, build a chat prompt, and send the messages to a chat generator.\n\n```python\nfrom haystack import Document, Pipeline\nfrom haystack.components.builders.chat_prompt_builder import ChatPromptBuilder\nfrom haystack.components.generators.chat import OpenAIChatGenerator\nfrom haystack.components.retrievers.in_memory import InMemoryBM25Retriever\nfrom haystack.dataclasses import ChatMessage\nfrom haystack.document_stores.in_memory import InMemoryDocumentStore\nfrom haystack.utils import Secret\n\ndocument_store = InMemoryDocumentStore()\ndocument_store.write_documents(\n    [\n        Document(content=\"My name is Jean and I live in Paris.\"),\n        Document(content=\"My name is Mark and I live in Berlin.\"),\n        Document(content=\"My name is Giorgio and I live in Rome.\"),\n    ]\n)\n\nprompt_template = [\n    ChatMessage.from_system(\"You are a helpful assistant.\"),\n    ChatMessage.from_user(\n        \"Given these documents, answer the question.\\n\"\n        \"Documents:\\n{% for doc in documents %}{{ doc.content }}\\n{% endfor %}\\n\"\n        \"Question: {{question}}\\n\"\n        \"Answer:\"\n    ),\n]\n\nprompt_builder = ChatPromptBuilder(\n    template=prompt_template,\n    required_variables={\"documents\", \"question\"},\n)\nretriever = InMemoryBM25Retriever(document_store=document_store)\nllm = OpenAIChatGenerator(api_key=Secret.from_env_var(\"OPENAI_API_KEY\"))\n\nrag_pipeline = Pipeline()\nrag_pipeline.add_component(\"retriever\", retriever)\nrag_pipeline.add_component(\"prompt_builder\", prompt_builder)\nrag_pipeline.add_component(\"llm\", llm)\n\nrag_pipeline.connect(\"retriever\", \"prompt_builder.documents\")\nrag_pipeline.connect(\"prompt_builder\", \"llm.messages\")\n\nquestion = \"Who lives in Paris?\"\nresult = rag_pipeline.run(\n    {\n        \"retriever\": {\"query\": question},\n        \"prompt_builder\": {\"question\": question},\n    }\n)\n\nprint(result[\"llm\"][\"replies\"][0].text)\n```\n\nPractical notes:\n\n- `InMemoryDocumentStore` is recommended for experiments, not production.\n- `InMemoryBM25Retriever` is keyword-based. For semantic retrieval, switch to an embedding-based path and the corresponding dependencies or integrations.\n- `OpenAIChatGenerator` consumes `messages`, not raw prompt strings.\n\n## Configuration And Auth\n\n### Environment variables\n\nFor OpenAI-backed examples, export the API key before running your script:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nThen construct the component with a Haystack secret:\n\n```python\nfrom haystack.components.generators.chat import OpenAIChatGenerator\nfrom haystack.utils import Secret\n\nllm = OpenAIChatGenerator(api_key=Secret.from_env_var(\"OPENAI_API_KEY\"))\n```\n\n### When to use `Secret.from_token(...)`\n\nUse `Secret.from_token(...)` only for short-lived experiments. Token-based secrets cannot be serialized, so any pipeline containing them cannot be safely dumped to YAML.\n\n### Serialization\n\nPipelines are serializable, and current Haystack docs describe YAML as the built-in format.\n\n```python\nyaml_text = rag_pipeline.dumps()\n\n# Later\nrestored = Pipeline.loads(yaml_text)\n```\n\nIf you expect to save and reload a pipeline, prefer environment-variable secrets and keep non-serializable runtime objects out of component init parameters.\n\n## Custom Components\n\nUse `@component` for custom logic you want to insert into a pipeline. Output names must match the dictionary returned by `run()`.\n\n```python\nfrom haystack import component\n\n@component\nclass WelcomeTextGenerator:\n    @component.output_types(welcome_text=str, note=str)\n    def run(self, name: str):\n        return {\n            \"welcome_text\": f\"Hello {name}, welcome to Haystack!\".upper(),\n            \"note\": \"welcome message is ready\",\n        }\n```\n\nThis is the standard extension point when the built-in components do not exactly match your workflow.\n\n## Agents And Tools\n\nCurrent Haystack 2.25 docs treat agents as compositions of:\n\n- a chat generator that supports tool calling\n- tools such as `Tool`, `ComponentTool`, or `PipelineTool`\n- optionally `ToolInvoker` when you want tool execution as part of a pipeline graph\n\nFor simple tool-calling agents, the `Agent` component is the highest-level entry point. For explicit orchestration, use a normal `Pipeline` and wire a generator, router, tool invoker, and state-handling components yourself.\n\n## Common Pitfalls\n\n- Mixing `farm-haystack` and `haystack-ai` in one environment is a real source of broken imports and obscure runtime behavior.\n- `InMemoryDocumentStore` is not a production document store. Replace it before shipping anything that needs persistence, scale, or multi-process access.\n- Missing optional dependencies are expected with the minimal install. Read the `ImportError` and install the named dependency or integration package instead of debugging the component itself.\n- Chat-based components work with `ChatMessage` objects. If you pass raw strings where `messages` are expected, the pipeline wiring will not match the component inputs.\n- Use `ChatMessage.from_user(...)` and the other factory methods rather than inventing your own message dict format.\n- Secret handling affects serialization. `Secret.from_token(...)` is convenient, but it prevents safe pipeline dumping.\n- If tracing libraries such as OpenTelemetry or Datadog are present and you do not want auto tracing, set `HAYSTACK_AUTO_TRACE_ENABLED=false` before import.\n\n## Version-Sensitive Notes For 2.25.2\n\n- PyPI currently lists `haystack-ai 2.25.2` as the latest stable release, released on March 5, 2026.\n- The official API reference root currently defaults to version `2.25` and also shows a separate `2.26-unstable` track. Keep examples aligned to the 2.25 docs when working against `2.25.2`.\n- The docs explicitly separate the core `haystack-ai` API from integrations distributed as separate packages. If you find older examples assuming everything ships in one install, re-check the current integration docs.\n- Current tooling docs include `PipelineTool` as the direct way to wrap a pipeline for tool calling. Prefer current tool APIs over older blog posts that describe more manual wrapping patterns.\n"
  },
  {
    "path": "content/holoviews/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"HoloViews package guide for Python projects using the official HoloViews docs and reference gallery\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.22.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"holoviews,holoviz,python,visualization,plotting,jupyter,bokeh,matplotlib,plotly\"\n---\n\n# HoloViews Python Package Guide\n\n## Golden Rule\n\nUse `holoviews` as a backend-agnostic plotting layer, activate a backend explicitly with `hv.extension(...)`, and prefer the `recommended` extra unless you intentionally want a minimal install. For `1.22.1`, treat `https://holoviews.org/` as the docs root and `https://holoviews.org/reference/` as the fastest way to look up concrete element and backend examples.\n\n## Install\n\nThe official install guide distinguishes between a minimal install and the recommended install with plotting dependencies.\n\nRecommended for most agent work:\n\n```bash\npython -m pip install \"holoviews[recommended]==1.22.1\"\n```\n\nMinimal package only:\n\n```bash\npython -m pip install \"holoviews==1.22.1\"\n```\n\nConda also has first-party guidance:\n\n```bash\nconda install -c conda-forge \"holoviews=1.22.1\"\n```\n\nUse the `recommended` extra when you expect notebook rendering, widgets, or the common Bokeh/Matplotlib/Plotly plotting stack to work without additional package chasing.\n\n## Initialize And Choose A Backend\n\nHoloViews objects are not displayable until a plotting extension is loaded. In notebooks, make backend selection explicit instead of relying on defaults:\n\n```python\nimport numpy as np\nimport holoviews as hv\n\nhv.extension(\"bokeh\")\n\nxs = np.linspace(0, 2 * np.pi, 200)\ncurve = hv.Curve((xs, np.sin(xs)), kdims=\"x\", vdims=\"y\")\ncurve\n```\n\nSupported backends in the official docs are `bokeh`, `matplotlib`, and `plotly`:\n\n```python\nhv.extension(\"matplotlib\")\nhv.extension(\"plotly\")\n```\n\nPractical guidance:\n\n- Use `bokeh` for interactive notebook exploration and most examples in the docs.\n- Use `matplotlib` when you need static image output or tighter Matplotlib ecosystem integration.\n- Use `plotly` when you need Plotly-native interactivity, but verify backend-specific options against the reference gallery.\n\n## Core Usage\n\n### Build elements from arrays or dataframes\n\n```python\nimport pandas as pd\nimport holoviews as hv\n\nhv.extension(\"bokeh\")\n\ndf = pd.DataFrame(\n    {\n        \"x\": [1, 2, 3, 4],\n        \"y\": [2.5, 3.0, 2.2, 4.1],\n        \"label\": [\"a\", \"b\", \"c\", \"d\"],\n    }\n)\n\npoints = hv.Points(df, kdims=[\"x\", \"y\"], vdims=[\"label\"])\npoints\n```\n\nCore object families agents will use most often:\n\n- Elements such as `Curve`, `Scatter`, `Points`, `Image`, `Bars`, and `HeatMap`\n- Containers such as `Overlay`, `Layout`, `HoloMap`, and `DynamicMap`\n- `Dataset` as the common wrapper when you want consistent dimension metadata and conversion between element types\n\n### Compose plots declaratively\n\nUse `*` for overlays and `+` for layouts:\n\n```python\nline = hv.Curve(df, kdims=\"x\", vdims=\"y\").opts(line_width=3, color=\"black\")\nmarkers = hv.Scatter(df, kdims=\"x\", vdims=\"y\").opts(size=8, color=\"tomato\")\n\noverlay = line * markers\nlayout = overlay + points\n```\n\n### Customize with `.opts(...)`\n\nThe user guide recommends the `.opts(...)` method for per-object customization:\n\n```python\nfrom holoviews import opts\n\nstyled = overlay.opts(\n    opts.Curve(width=700, height=350, tools=[\"hover\"]),\n    opts.Scatter(size=10),\n)\n```\n\nIf you want shared defaults for a notebook or module, set them once:\n\n```python\nopts.defaults(\n    opts.Curve(width=700, height=350),\n    opts.Scatter(size=8),\n)\n```\n\n### Use `DynamicMap` for callable, parameter-driven plots\n\n`DynamicMap` is the core HoloViews abstraction for plots generated on demand:\n\n```python\nimport numpy as np\nimport holoviews as hv\n\nhv.extension(\"bokeh\")\n\ndef sine_curve(phase):\n    xs = np.linspace(0, 2 * np.pi, 200)\n    return hv.Curve((xs, np.sin(xs + phase)))\n\ndmap = hv.DynamicMap(sine_curve, kdims=[\"phase\"]).redim.values(\n    phase=[0.0, 0.5, 1.0, 1.5]\n)\n```\n\nUse `DynamicMap` when the plot should respond to widgets, streams, or deferred computation. If you only need a finite set of precomputed states, a `HoloMap` is usually simpler to save and debug.\n\n## Export And Embedding\n\nUse `hv.save(...)` for files:\n\n```python\nhv.save(overlay, \"plot.html\")\nhv.save(overlay, \"plot.png\", backend=\"matplotlib\")\n```\n\nPractical export rules:\n\n- HTML export is the most reliable default for interactive Bokeh output.\n- For static PNG/SVG workflows, prefer the `matplotlib` backend unless you have already validated the target format with another backend.\n- Saving uses the active or specified backend, so mismatched backend assumptions are a common cause of export failures.\n\n## Configuration And Runtime Notes\n\n- Authentication: none. `holoviews` is a local plotting library, not a remote API client.\n- Notebook setup matters more than credentials: install the plotting dependencies you actually need and load a backend before display.\n- The official docs note that `DynamicMap` relies on a running Python process, so fully interactive behavior is available in live notebook or app contexts, not in static HTML alone.\n- If you are building a richer dashboard or widget-driven app, HoloViews often pairs with Panel. Keep that as a separate dependency decision instead of assuming `holoviews` alone provides app serving.\n\n## Common Pitfalls\n\n- Installing plain `holoviews` and then expecting rich plotting backends to work. Use `holoviews[recommended]` unless you intentionally manage dependencies yourself.\n- Forgetting `hv.extension(\"bokeh\")` or another explicit backend before display.\n- Assuming `.opts(...)` settings are backend-neutral. Many options are shared, but some tools, hooks, and styling flags are backend-specific.\n- Treating `DynamicMap` like a static object. Interactive updates depend on a live kernel or app session.\n- Exporting with the wrong backend. If `hv.save(...)` fails or produces the wrong format, specify `backend=...` explicitly.\n- Copying older examples that rely on implicit Matplotlib defaults, notebook magics, or old streamz integrations without checking the release notes first.\n\n## Version-Sensitive Notes For 1.22.1\n\n- PyPI lists `1.22.1` as the current stable release for `holoviews`.\n- The `1.22` release line adds Narwhals-based dataframe compatibility, which broadens support for Polars and DuckDB-backed workflows. That matters when agents are adapting examples written for pandas-only inputs.\n- The `1.21` release raised the minimum supported Python version to `3.10`.\n- The `1.21` release also deprecated the `streamz` interface, autoloading the RC file, IPython magic, and relying on Matplotlib as the default backend for `hv.extension`; the release notes say these are planned for removal in `1.23.0`.\n\n## Official Sources Used\n\n- Docs root: `https://holoviews.org/`\n- Install guide: `https://holoviews.org/install.html`\n- Getting started: `https://holoviews.org/getting_started/Introduction.html`\n- Customizing plots: `https://holoviews.org/user_guide/Customizing_Plots.html`\n- Live data: `https://holoviews.org/user_guide/Live_Data.html`\n- Exporting: `https://holoviews.org/user_guide/Exporting_and_Archiving.html`\n- Release notes: `https://holoviews.org/releases.html`\n- Reference gallery: `https://holoviews.org/reference/`\n- PyPI: `https://pypi.org/project/holoviews/`\n"
  },
  {
    "path": "content/html5lib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"html5lib package guide for Python HTML5 parsing, tree building, and serialization\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"html5lib,html,parser,dom,serialization\"\n---\n\n# html5lib Python Package Guide\n\n## Golden Rule\n\nUse `html5lib` when you need browser-style HTML5 parsing and error recovery, not strict XML parsing. Pass bytes when you want encoding sniffing to match real HTML input, and choose the tree builder explicitly if downstream code expects stdlib ElementTree, `xml.dom.minidom`, or `lxml`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"html5lib==1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"html5lib==1.1\"\npoetry add \"html5lib==1.1\"\n```\n\nOptional parser tree support:\n\n```bash\npython -m pip install lxml\n```\n\n`html5lib` can build trees for:\n\n- `etree` (default; stdlib ElementTree)\n- `dom` (`xml.dom.minidom`)\n- `lxml` (`lxml.etree`, if `lxml` is installed)\n\n## Core Usage\n\n### Parse a full HTML document\n\nUse `html5lib.parse()` for whole documents. The return type depends on the tree builder.\n\n```python\nimport html5lib\n\ndocument = html5lib.parse(\n    b\"<html><head><title>demo</title></head><body><p>Hello\",\n    treebuilder=\"etree\",\n)\n\nroot = document.getroot()\nprint(root.tag)\n```\n\nThe parser accepts:\n\n- a string filename\n- a file-like object\n- a text string\n- raw bytes\n\n### Parse an HTML fragment\n\nUse `parseFragment()` when the input is a snippet instead of a complete document. Set `container` to the element context the fragment belongs in.\n\n```python\nimport html5lib\n\nfragment = html5lib.parseFragment(\n    \"<tr><td>cell</td></tr>\",\n    container=\"table\",\n    treebuilder=\"dom\",\n)\n\nprint(fragment.childNodes[0].toxml())\n```\n\n### Choose the right tree builder\n\nIf your code already expects a particular tree API, set `treebuilder` up front instead of converting later.\n\n```python\nimport html5lib\n\netree_doc = html5lib.parse(\"<p>stdlib tree</p>\", treebuilder=\"etree\")\ndom_doc = html5lib.parse(\"<p>minidom tree</p>\", treebuilder=\"dom\")\nlxml_doc = html5lib.parse(\"<p>lxml tree</p>\", treebuilder=\"lxml\")\n```\n\nThe project README notes that the `lxml` tree builder is not supported on PyPy because of segfault risk.\n\n### Disable XHTML namespaces when tag matching should stay simple\n\nBy default, HTML namespace handling is enabled. If your code compares plain tag names like `\"div\"` instead of fully qualified XHTML tags, turn it off.\n\n```python\nimport html5lib\n\ndocument = html5lib.parse(\n    \"<div><p>hello</p></div>\",\n    treebuilder=\"etree\",\n    namespaceHTMLElements=False,\n)\n\nroot = document.getroot()\nprint(root.tag)  # html instead of {http://www.w3.org/1999/xhtml}html\n```\n\n### Serialize parsed content back to HTML\n\nUse `serialize()` to emit normalized HTML from a tree walker.\n\n```python\nimport html5lib\nfrom html5lib.serializer import serialize\nfrom html5lib.treewalkers import getTreeWalker\n\ndocument = html5lib.parse(\"<p class=test>Hello</p>\", treebuilder=\"etree\")\nwalker = getTreeWalker(\"etree\")\n\nhtml = serialize(\n    walker(document),\n    omit_optional_tags=False,\n    quote_attr_values=\"always\",\n)\n\nprint(html)\n```\n\n## Setup And Configuration Notes\n\n`html5lib` does not use network authentication or API credentials. The important configuration choices are parser and serializer behavior:\n\n- `treebuilder`: choose `etree`, `dom`, or `lxml` based on the object model your code consumes\n- `namespaceHTMLElements`: leave enabled when you want XHTML-aware trees; disable it for simpler tag-name matching\n- `container` in `parseFragment()`: set the surrounding HTML element so fragment parsing follows the right insertion rules\n- serializer options such as `omit_optional_tags` and `quote_attr_values`: control how normalized output is emitted\n\nIf you are parsing content from HTTP responses, prefer `response.content` bytes over decoded text when you want `html5lib` to apply its own HTML encoding detection.\n\n## Common Pitfalls\n\n- The docs URL points at `https://html5lib.readthedocs.io/en/latest/`, which is currently `1.2-dev`. For released `1.1` behavior, use `https://html5lib.readthedocs.io/en/stable/`.\n- The default `etree` output uses XHTML namespaces. Plain `element.tag == \"div\"` checks often fail unless you pass `namespaceHTMLElements=False` or handle namespace-qualified tags.\n- `parseFragment()` is not interchangeable with `parse()`. Use fragments for snippets and set `container` when table/list/form insertion rules matter.\n- `html5lib` repairs malformed markup. That is the point of the library, but it also means output structure and serialization may differ from the raw input.\n- The optional `lxml` tree builder requires `lxml` to be installed separately.\n- The deprecated `html5lib.filters.sanitizer` module should not be used for new work.\n\n## Version-Sensitive Notes\n\n- PyPI still lists `html5lib 1.1` as the latest released package.\n- The official `latest` Read the Docs site is ahead of the release and identifies itself as `1.2-dev`, so examples there can drift from the published wheel.\n- The stable changelog page still labels the `1.1` section as `UNRELEASED`, even though PyPI shows the `1.1` release was published in June 2020. Treat PyPI and the stable API docs as the authoritative release references for package-version guidance.\n- PyPI metadata for `1.1` still declares an old broad `Requires-Python` range (`>=2.7`, excluding Python `3.0` through `3.4`). If you need a formally supported modern-Python compatibility statement, verify against your target interpreter in CI instead of assuming the old metadata reflects current maintainer support policy.\n\n## Official Sources\n\n- Stable docs: `https://html5lib.readthedocs.io/en/stable/`\n- Latest docs branch: `https://html5lib.readthedocs.io/en/latest/`\n- API module docs: `https://html5lib.readthedocs.io/en/latest/html5lib.html`\n- Changelog: `https://html5lib.readthedocs.io/en/latest/changes.html`\n- PyPI: `https://pypi.org/project/html5lib/`\n- PyPI JSON metadata: `https://pypi.org/pypi/html5lib/json`\n- Repository: `https://github.com/html5lib/html5lib-python`\n"
  },
  {
    "path": "content/httpcore/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"httpcore package guide for Python - low-level sync and async HTTP transport, pooling, streaming, and proxy support\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.9\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"httpcore,http,http2,asyncio,trio,networking,proxy,transport\"\n---\n\n# httpcore Python Package Guide\n\n## What It Is\n\n`httpcore` is Encode's low-level HTTP transport library. Use it when you need direct control over connection pooling, sync or async request execution, streaming bodies, proxy configuration, SSL contexts, or transport-level retries.\n\nDo not reach for `httpcore` if you want a batteries-included client. It deliberately does not handle redirects, cookies, auth helpers, JSON helpers, multipart abstractions, or environment-based defaults. If you need those higher-level features, use `httpx` instead.\n\n## Installation\n\nBase install for HTTP/1.1:\n\n```bash\npython -m pip install \"httpcore==1.0.9\"\n```\n\nOptional extras from the maintainer docs:\n\n```bash\n# Async support on asyncio.\npython -m pip install \"httpcore[asyncio]==1.0.9\"\n\n# Async support on trio.\npython -m pip install \"httpcore[trio]==1.0.9\"\n\n# HTTP/2 support.\npython -m pip install \"httpcore[http2]==1.0.9\"\n\n# SOCKS proxy support.\npython -m pip install \"httpcore[socks]==1.0.9\"\n```\n\nYou can combine extras:\n\n```bash\npython -m pip install \"httpcore[asyncio,http2,socks]==1.0.9\"\n```\n\n## Choose The Right Entry Point\n\n- `httpcore.request(...)`: one-shot synchronous request helper. Fine for scripts or tests.\n- `httpcore.stream(...)`: one-shot synchronous streaming response helper.\n- `httpcore.ConnectionPool(...)`: the default choice for reusable synchronous transport.\n- `httpcore.AsyncConnectionPool(...)`: the async transport for `asyncio` or `trio`.\n\nIn real code, prefer a pool over repeated top-level `request()` calls. That is where `httpcore` actually gives you connection reuse and transport-level configuration.\n\n## Quick Start\n\n### One synchronous request\n\n```python\nimport httpcore\n\nresponse = httpcore.request(\"GET\", \"https://www.example.com/\")\n\nprint(response)\nprint(response.status)\nprint(response.headers)\nprint(response.content)\n```\n\n`response.headers` is low-level header data, not a rich mapping object. Expect raw header pairs and decode or normalize them yourself if your code expects higher-level client behavior.\n\n### Reuse a synchronous connection pool\n\n```python\nimport httpcore\n\nwith httpcore.ConnectionPool() as pool:\n    response = pool.request(\n        \"GET\",\n        \"https://api.example.com/items\",\n        headers={\"Accept\": \"application/json\"},\n    )\n    print(response.status)\n    print(response.content)\n```\n\n### Reuse an asynchronous connection pool\n\nInstall either `httpcore[asyncio]` or `httpcore[trio]` first.\n\n```python\nimport asyncio\nimport httpcore\n\nasync def main() -> None:\n    async with httpcore.AsyncConnectionPool() as pool:\n        response = await pool.request(\n            \"GET\",\n            \"https://api.example.com/items\",\n            headers={\"Accept\": \"application/json\"},\n        )\n        print(response.status)\n        print(await response.aread())\n\nasyncio.run(main())\n```\n\n## Request Model\n\nThe request surface is deliberately small:\n\n- `method`: `str` or `bytes`\n- `url`: `str`, `bytes`, or `httpcore.URL`\n- `headers`: dict or list of header tuples\n- `content`: `bytes` or an iterator of `bytes`\n- `extensions`: a dict for transport-level options such as timeouts or tracing\n\nSynchronous POST example:\n\n```python\nimport json\n\nimport httpcore\n\npayload = {\"name\": \"example\", \"enabled\": True}\n\nwith httpcore.ConnectionPool() as pool:\n    response = pool.request(\n        \"POST\",\n        \"https://api.example.com/items\",\n        headers={\n            \"Accept\": \"application/json\",\n            \"Content-Type\": \"application/json\",\n            \"Authorization\": \"Bearer TOKEN\",\n        },\n        content=json.dumps(payload).encode(\"utf-8\"),\n    )\n    print(response.status)\n    print(response.content)\n```\n\nHeader keys and values may be strings or bytes. If you pass strings, keep them ASCII-only. For non-ASCII values, encode explicitly and pass bytes.\n\nFor async requests with a body, pass either `bytes` or an async iterable yielding byte chunks.\n\n## Streaming Responses\n\nUse streaming when the response body may be large or when you want backpressure instead of buffering the whole body in memory.\n\n### One-shot streaming\n\n```python\nimport httpcore\n\nwith httpcore.stream(\"GET\", \"https://example.com/large-download\") as response:\n    with open(\"download.bin\", \"wb\") as output:\n        for chunk in response.iter_stream():\n            output.write(chunk)\n```\n\n### Streaming through a pool\n\n```python\nimport httpcore\n\nwith httpcore.ConnectionPool() as pool:\n    with pool.stream(\"GET\", \"https://example.com/large-download\") as response:\n        with open(\"download.bin\", \"ab\") as output:\n            for chunk in response.iter_stream():\n                output.write(chunk)\n```\n\n### Async streaming\n\n```python\nimport asyncio\nimport httpcore\nfrom pathlib import Path\n\nasync def main() -> None:\n    path = Path(\"download.bin\")\n    async with httpcore.AsyncConnectionPool() as pool:\n        async with pool.stream(\"GET\", \"https://example.com/large-download\") as response:\n            with path.open(\"ab\") as output:\n                async for chunk in response.aiter_stream():\n                    output.write(chunk)\n\nasyncio.run(main())\n```\n\n`stream()` is also the safest cleanup pattern because the context manager guarantees the response is closed even if your processing exits early.\n\n## Connection Pool Configuration\n\nThe most important pool knobs are:\n\n- `max_connections`: upper bound on concurrent open connections\n- `max_keepalive_connections`: upper bound on idle reusable connections\n- `keepalive_expiry`: idle keep-alive lifetime in seconds\n- `http1` / `http2`: allowed protocol versions\n- `retries`: connection-establishment retries\n- `local_address`: bind to a local IP or force IPv4/IPv6 family\n- `uds`: connect through a Unix domain socket instead of TCP\n- `socket_options`: socket options applied when establishing TCP connections\n\nExample:\n\n```python\nimport httpcore\n\nwith httpcore.ConnectionPool(\n    max_connections=50,\n    max_keepalive_connections=20,\n    keepalive_expiry=30.0,\n    retries=2,\n    http1=True,\n    http2=False,\n) as pool:\n    response = pool.request(\"GET\", \"https://example.com/health\")\n    print(response.status)\n```\n\nPractical guidance:\n\n- Start with the defaults unless you have a real concurrency bottleneck.\n- Increase `max_connections` only when you expect actual concurrent work.\n- If you see `PoolTimeout`, either your pool is too small or responses are not being closed quickly enough.\n- Use `local_address=\"0.0.0.0\"` or `\"::\"` when you need to force IPv4 or IPv6 source addressing.\n- Use `uds=\"/path/to/socket.sock\"` only for services that explicitly expose an HTTP-over-UDS endpoint.\n\n## HTTP/2\n\nHTTP/2 support is optional and disabled by default.\n\n1. Install the extra:\n\n```bash\npython -m pip install \"httpcore[http2]==1.0.9\"\n```\n\n2. Enable it on the pool:\n\n```python\nimport httpcore\n\nwith httpcore.ConnectionPool(http2=True) as pool:\n    response = pool.request(\"GET\", \"https://example.com/\")\n    print(response.http_version)\n```\n\nKeep `http1=True` unless you specifically need to disable HTTP/1.1 fallback.\n\n## Proxies\n\n`httpcore` supports HTTP proxies, HTTPS proxies, and SOCKS proxies.\n\n### HTTP proxy\n\n```python\nimport httpcore\n\nproxy = httpcore.Proxy(\"http://127.0.0.1:8080/\")\n\nwith httpcore.ConnectionPool(proxy=proxy) as pool:\n    response = pool.request(\"GET\", \"https://example.com/\")\n    print(response.status)\n```\n\n### Proxy authentication\n\n```python\nimport httpcore\n\nproxy = httpcore.Proxy(\n    url=\"http://127.0.0.1:8080/\",\n    auth=(\"username\", \"password\"),\n)\n\nwith httpcore.ConnectionPool(proxy=proxy) as pool:\n    response = pool.request(\"GET\", \"https://example.com/\")\n    print(response.status)\n```\n\n### HTTPS proxy with custom TLS configuration\n\n```python\nimport ssl\n\nimport httpcore\n\nproxy_ssl_context = ssl.create_default_context(cafile=\"/path/to/proxy-ca.pem\")\nproxy = httpcore.Proxy(\n    url=\"https://proxy.internal:8443/\",\n    ssl_context=proxy_ssl_context,\n)\n\nwith httpcore.ConnectionPool(proxy=proxy) as pool:\n    response = pool.request(\"GET\", \"https://example.com/\")\n    print(response.status)\n```\n\n### SOCKS proxy\n\nInstall the extra first:\n\n```bash\npython -m pip install \"httpcore[socks]==1.0.9\"\n```\n\nThen configure the proxy URL:\n\n```python\nimport httpcore\n\nproxy = httpcore.Proxy(\"socks5://127.0.0.1:1080\")\n\nwith httpcore.ConnectionPool(proxy=proxy) as pool:\n    response = pool.request(\"GET\", \"https://example.com/\")\n    print(response.status)\n```\n\n## SSL, Certificates, And mTLS\n\nPass an `ssl.SSLContext` when you need custom CA bundles, stricter verification settings, or client certificates.\n\n```python\nimport ssl\n\nimport httpcore\n\nssl_context = ssl.create_default_context(cafile=\"/path/to/internal-ca.pem\")\n\nwith httpcore.ConnectionPool(ssl_context=ssl_context) as pool:\n    response = pool.request(\"GET\", \"https://internal.example.com/\")\n    print(response.status)\n```\n\nMutual TLS:\n\n```python\nimport ssl\n\nimport httpcore\n\nssl_context = ssl.create_default_context()\nssl_context.load_cert_chain(\"client-cert.pem\", \"client-key.pem\")\n\nwith httpcore.ConnectionPool(ssl_context=ssl_context) as pool:\n    response = pool.request(\"GET\", \"https://mtls.example.com/\")\n    print(response.status)\n```\n\n## Auth And Headers\n\n`httpcore` does not implement auth workflows for you. There are no session objects, auth plugins, cookie jars, or automatic token refresh hooks.\n\nIn practice you add headers directly:\n\n```python\nimport httpcore\n\nheaders = {\n    \"Authorization\": \"Bearer TOKEN\",\n    \"Accept\": \"application/json\",\n    \"User-Agent\": \"my-service/1.0\",\n}\n\nwith httpcore.ConnectionPool() as pool:\n    response = pool.request(\n        \"GET\",\n        \"https://api.example.com/private\",\n        headers=headers,\n    )\n    print(response.status)\n```\n\nIf your code needs auth choreography, cookie persistence, or redirect policy, `httpx` is usually the better layer.\n\n## Timeouts And Other Extensions\n\nThe `extensions` dict is where `httpcore` exposes transport-level controls.\n\n### Timeout extension\n\n```python\nimport httpcore\n\ntimeouts = {\n    \"connect\": 5.0,\n    \"read\": 10.0,\n    \"write\": 10.0,\n    \"pool\": 5.0,\n}\n\nwith httpcore.ConnectionPool() as pool:\n    response = pool.request(\n        \"GET\",\n        \"https://api.example.com/items\",\n        extensions={\"timeout\": timeouts},\n    )\n    print(response.status)\n```\n\n### Trace extension\n\nUse tracing when you need to debug DNS, connect, TLS, or pool behavior.\n\n```python\nimport httpcore\n\ndef trace(event_name, info) -> None:\n    print(event_name, info)\n\nresponse = httpcore.request(\n    \"GET\",\n    \"https://www.example.com/\",\n    extensions={\"trace\": trace},\n)\n```\n\nFor broader debug output, the maintainer docs also show standard-library logging against the `httpcore` logger namespace.\n\n## Exceptions You Will Actually Handle\n\nThe official exception tree is small and useful:\n\n- `httpcore.TimeoutException`\n  - `httpcore.PoolTimeout`\n  - `httpcore.ConnectTimeout`\n  - `httpcore.ReadTimeout`\n  - `httpcore.WriteTimeout`\n- `httpcore.NetworkError`\n  - `httpcore.ConnectError`\n  - `httpcore.ReadError`\n  - `httpcore.WriteError`\n- `httpcore.ProtocolError`\n  - `httpcore.RemoteProtocolError`\n  - `httpcore.LocalProtocolError`\n- `httpcore.ProxyError`\n- `httpcore.UnsupportedProtocol`\n\nTypical handling:\n\n```python\nimport httpcore\n\ntry:\n    with httpcore.ConnectionPool() as pool:\n        response = pool.request(\n            \"GET\",\n            \"https://example.com/\",\n            extensions={\n                \"timeout\": {\n                    \"connect\": 2.0,\n                    \"read\": 5.0,\n                    \"write\": 5.0,\n                    \"pool\": 1.0,\n                }\n            },\n        )\n        print(response.status)\nexcept httpcore.ConnectTimeout:\n    print(\"Connection attempt timed out\")\nexcept httpcore.PoolTimeout:\n    print(\"Pool exhausted before a connection became available\")\nexcept httpcore.ReadTimeout:\n    print(\"Response body was too slow\")\nexcept httpcore.RemoteProtocolError as exc:\n    print(f\"Upstream sent an invalid HTTP response: {exc}\")\nexcept httpcore.ProxyError as exc:\n    print(f\"Proxy negotiation failed: {exc}\")\n```\n\n## Common Pitfalls\n\n- Do not expect `requests` or `httpx` ergonomics. `httpcore` is a transport layer, not a general-purpose user client.\n- Install extras explicitly. `asyncio`, `trio`, HTTP/2, and SOCKS support are not all available from the base install.\n- Use `AsyncConnectionPool` only from async code and only after installing the right async extra.\n- Close what you open. Long-lived pools should be context-managed or explicitly closed, and streaming responses must be consumed or closed.\n- Expect low-level header handling. Response headers are raw tuples, not a case-insensitive mapping with convenience helpers.\n- Remember that top-level `request()` is convenience only. Repeated calls lose the connection reuse that makes `httpcore` valuable.\n- Set timeouts yourself. The extension-based timeout model is explicit; if you want higher-level timeout policy, wrap `httpcore` in your own helper.\n- Use bytes for non-ASCII header values. String header values are ASCII-only.\n\n## Version-Sensitive Notes For 1.0.9\n\n- This guide targets `httpcore==1.0.9`, which is also the current latest PyPI release as of March 12, 2026.\n- `1.0.9` shipped on April 24, 2025 and updated the `h11` dependency to address `GHSA-vqfr-h8mv-ghfj`.\n- `1.0.8` fixed an `AttributeError` when importing on Python 3.14. If you are supporting Python 3.14, stay on at least `1.0.8`.\n- `1.0.7` added direct `proxy=` support on `ConnectionPool()` and `AsyncConnectionPool()`. If you are pinned below `1.0.7`, re-check proxy examples before copying them.\n- Since `1.0.0`, async support has been optional and must be enabled with `httpcore[asyncio]` or `httpcore[trio]`.\n- The maintainer docs site is rolling `1.0.x` documentation rather than a version-pinned snapshot, so release notes are the authority for point-release-specific changes.\n\n## Official Sources\n\n- Docs root: https://www.encode.io/httpcore/\n- Quickstart: https://www.encode.io/httpcore/quickstart/\n- Connection pools: https://www.encode.io/httpcore/connection-pools/\n- Async support: https://www.encode.io/httpcore/async/\n- Proxies: https://www.encode.io/httpcore/proxies/\n- HTTP/2: https://www.encode.io/httpcore/http2/\n- Extensions: https://www.encode.io/httpcore/extensions/\n- Exceptions: https://www.encode.io/httpcore/exceptions/\n- Logging: https://www.encode.io/httpcore/logging/\n- PyPI: https://pypi.org/project/httpcore/\n- Source repository: https://github.com/encode/httpcore\n- Releases: https://github.com/encode/httpcore/releases\n"
  },
  {
    "path": "content/httplib2/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"httplib2 HTTP client for Python with request, authentication, caching, proxy, and TLS configuration examples\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.31.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"httplib2,http,https,client,cache,proxy,python\"\n---\n\n# httplib2 Python Package Guide\n\n## Golden Rule\n\nUse `httplib2.Http` as the main client and build requests through `Http.request(...)`.\n\nThe maintainer docs on Read the Docs still render as `httplib2 0.4 documentation`, but PyPI currently publishes `0.31.2`. For current version notes, check the repository `README.md` and `CHANGELOG` alongside the API docs.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"httplib2==0.31.2\"\n```\n\nExample environment variables used in the snippets below:\n\n```bash\nexport API_BASE_URL=\"https://api.example.com\"\nexport API_USERNAME=\"alice\"\nexport API_PASSWORD=\"secret\"\nexport HTTPLIB2_CA_CERTS=\"/etc/ssl/certs/ca-certificates.crt\"\nexport HTTPS_PROXY=\"http://proxy.example:8080\"\nexport NO_PROXY=\"localhost,127.0.0.1,.internal.example\"\n```\n\n`HTTPLIB2_CA_CERTS` is supported by current releases for custom CA bundles. Proxy settings are picked up from the environment by default.\n\n## Initialize A Client\n\nCreate one `Http` instance and reuse it across requests so connection pooling and caching can work for you:\n\n```python\nimport os\nimport httplib2\n\nhttp = httplib2.Http(\n    cache=\".cache/httplib2\",\n    timeout=20,\n    ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"),\n)\n```\n\nIf you need to ignore proxy environment variables for a specific client, pass `proxy_info=None`:\n\n```python\nimport httplib2\n\nhttp = httplib2.Http(proxy_info=None, timeout=20)\n```\n\n## Make Requests\n\n### GET JSON\n\n`request()` returns `(response, content)`. `content` is bytes in current releases, so decode it before loading JSON.\n\n```python\nimport json\nimport os\nimport httplib2\n\nhttp = httplib2.Http(\n    cache=\".cache/httplib2\",\n    timeout=20,\n    ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"),\n)\n\nresponse, content = http.request(\n    f\"{os.environ['API_BASE_URL']}/v1/widgets\",\n    method=\"GET\",\n    headers={\n        \"accept\": \"application/json\",\n        \"user-agent\": \"my-app/1.0\",\n    },\n)\n\nif response.status != 200:\n    raise RuntimeError(f\"request failed: {response.status} {response.reason}\")\n\npayload = json.loads(content.decode(\"utf-8\"))\nprint(payload)\n```\n\n### POST JSON\n\n```python\nimport json\nimport os\nimport httplib2\n\nhttp = httplib2.Http(timeout=20, ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"))\n\nbody = json.dumps(\n    {\n        \"name\": \"widget-1\",\n        \"enabled\": True,\n    }\n)\n\nresponse, content = http.request(\n    f\"{os.environ['API_BASE_URL']}/v1/widgets\",\n    method=\"POST\",\n    body=body,\n    headers={\n        \"content-type\": \"application/json\",\n        \"accept\": \"application/json\",\n    },\n)\n\nif response.status not in (200, 201):\n    raise RuntimeError(f\"create failed: {response.status} {response.reason}\")\n\ncreated = json.loads(content.decode(\"utf-8\"))\nprint(created[\"id\"])\n```\n\n### Send Form Data\n\n```python\nimport urllib.parse\nimport os\nimport httplib2\n\nhttp = httplib2.Http(timeout=20, ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"))\n\nform_body = urllib.parse.urlencode(\n    {\n        \"grant_type\": \"client_credentials\",\n        \"scope\": \"read:widgets\",\n    }\n)\n\nresponse, content = http.request(\n    f\"{os.environ['API_BASE_URL']}/oauth/token\",\n    method=\"POST\",\n    body=form_body,\n    headers={\"content-type\": \"application/x-www-form-urlencoded\"},\n)\n```\n\n## Authentication\n\n### Basic Auth\n\nUse `add_credentials()` before calling protected endpoints:\n\n```python\nimport os\nimport httplib2\n\nhttp = httplib2.Http(timeout=20, ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"))\nhttp.add_credentials(\n    os.environ[\"API_USERNAME\"],\n    os.environ[\"API_PASSWORD\"],\n)\n\nresponse, content = http.request(\n    f\"{os.environ['API_BASE_URL']}/private/profile\",\n    method=\"GET\",\n    headers={\"accept\": \"application/json\"},\n)\n```\n\n### Client Certificates\n\nFor mTLS-style endpoints, register the certificate and key for the target domain:\n\n```python\nimport os\nimport httplib2\n\nhttp = httplib2.Http(timeout=20, ca_certs=os.getenv(\"HTTPLIB2_CA_CERTS\"))\nhttp.add_certificate(\n    \"/path/to/client-key.pem\",\n    \"/path/to/client-cert.pem\",\n    \"api.example.com\",\n)\n\nresponse, content = http.request(\n    \"https://api.example.com/secure/health\",\n    method=\"GET\",\n)\n```\n\n## Caching, Redirects, And TLS\n\n### File-based caching\n\nPassing a cache directory stores cache entries on disk:\n\n```python\nimport httplib2\n\nhttp = httplib2.Http(cache=\".cache/httplib2\", timeout=20)\nresponse, content = http.request(\"https://api.example.com/v1/widgets\", \"GET\")\n\nif getattr(response, \"fromcache\", False):\n    print(\"served from cache\")\n```\n\n### Redirect behavior\n\n`httplib2` follows redirects for `GET` and `HEAD` by default. If you need redirect handling for other methods, enable it explicitly:\n\n```python\nimport httplib2\n\nhttp = httplib2.Http(follow_all_redirects=True, timeout=20)\nresponse, content = http.request(\n    \"https://api.example.com/legacy-endpoint\",\n    method=\"POST\",\n    body=\"x=1\",\n    headers={\"content-type\": \"application/x-www-form-urlencoded\"},\n)\n```\n\nKeep the default `forward_authorization_headers=False` unless you fully trust redirect targets.\n\n### TLS validation\n\nLeave certificate validation enabled in production. If your environment uses a private CA, point `ca_certs` or `HTTPLIB2_CA_CERTS` at the bundle that should be trusted.\n\n```python\nimport os\nimport httplib2\n\nhttp = httplib2.Http(\n    timeout=20,\n    ca_certs=os.environ[\"HTTPLIB2_CA_CERTS\"],\n)\n```\n\n## Common Pitfalls\n\n- `Http.request()` expects an absolute URI. Relative URLs raise `RelativeURIError`.\n- `content` is bytes in current releases. Decode it before calling `json.loads(...)` or string operations.\n- `httplib2` reads proxy settings from the environment by default. If that is breaking local development or internal calls, create the client with `proxy_info=None`.\n- Redirects are not blanket-enabled for every method. If your API returns `307` or `308` for `POST` or `PUT`, set `follow_all_redirects=True` deliberately.\n- `forward_authorization_headers` is off by default for safety. Do not switch it on unless you are certain redirected requests should carry credentials.\n- `force_exception_to_status_code=True` changes transport and SSL failures into synthetic response objects instead of raising exceptions. If you enable it, always inspect `response.status` before assuming the request succeeded.\n\n## Version-Sensitive Notes For 0.31.x\n\n- PyPI currently lists `httplib2 0.31.2` as the latest release.\n- The maintainer changelog explicitly says not to use `0.31.1`.\n- The changelog for `0.30.0` says support changed to Python 3.7+ only, but the current PyPI metadata still shows `Requires: Python >=3.6`. Treat Python 3.7+ as the safer baseline for `0.31.x`.\n- `0.30.1` notes a fix for SOCKS proxy support that was broken in `0.30.0`.\n- The `HTTPLIB2_CA_CERTS` environment variable support is documented in the `0.31.0` changelog, which is useful when system trust stores are not enough for your environment.\n\n## Official Sources\n\n- Maintainer docs root: https://httplib2.readthedocs.io/en/latest/\n- API reference: https://httplib2.readthedocs.io/en/latest/libhttplib2.html\n- Authentication guide: https://httplib2.readthedocs.io/en/latest/authentication.html\n- Caching guide: https://httplib2.readthedocs.io/en/latest/caching.html\n- Repository README: https://github.com/httplib2/httplib2/blob/master/README.md\n- Repository changelog: https://github.com/httplib2/httplib2/blob/master/CHANGELOG\n- PyPI project page: https://pypi.org/project/httplib2/\n"
  },
  {
    "path": "content/httptools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"httptools package guide for Python HTTP/1.1 request parsing and URL parsing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"httptools,http,http1,url-parser,async,python\"\n---\n\n# httptools Python Package Guide\n\n## What It Is\n\n`httptools` is a low-level Python binding around Node's `llhttp` parser. Use it when you need incremental HTTP/1.1 request parsing or fast URL parsing inside server, proxy, or framework code.\n\nUse something higher-level if you need an HTTP client, ASGI/WSGI framework, TLS handling, retries, cookies, or authentication helpers. `httptools` only parses bytes and calls your callbacks.\n\n## Installation\n\n```bash\npip install httptools\n```\n\nPin the documented version when behavior or wheel availability matters:\n\n```bash\npip install \"httptools==0.7.1\"\n```\n\nWith Poetry:\n\n```bash\npoetry add httptools\n```\n\nWith uv:\n\n```bash\nuv add httptools\n```\n\n## Core Setup\n\n`HttpRequestParser` takes a protocol-like object. The parser calls methods on that object as it sees request data. The official README shows these callback names:\n\n- `on_message_begin()`\n- `on_url(url: bytes)`\n- `on_header(name: bytes, value: bytes)`\n- `on_headers_complete()`\n- `on_body(body: bytes)`\n- `on_message_complete()`\n\nAny of these methods can be omitted if you do not need them.\n\n```python\nimport httptools\n\nclass RequestProtocol:\n    def __init__(self) -> None:\n        self.url = b\"\"\n        self.headers = []\n        self.body_parts = []\n\n    def on_url(self, url: bytes) -> None:\n        self.url = url\n\n    def on_header(self, name: bytes, value: bytes) -> None:\n        self.headers.append((name, value))\n\n    def on_body(self, body: bytes) -> None:\n        self.body_parts.append(body)\n\n    def on_message_complete(self) -> None:\n        body = b\"\".join(self.body_parts)\n        print(\"url =\", self.url.decode(\"ascii\", errors=\"replace\"))\n        print(\"headers =\", [(k.decode(), v.decode()) for k, v in self.headers])\n        print(\"body =\", body.decode(\"utf-8\", errors=\"replace\"))\n\nprotocol = RequestProtocol()\nparser = httptools.HttpRequestParser(protocol)\n\nparser.feed_data(\n    b\"POST /users?id=1 HTTP/1.1\\r\\n\"\n    b\"Host: example.com\\r\\n\"\n    b\"Content-Type: application/json\\r\\n\"\n    b\"Content-Length: 17\\r\\n\"\n    b\"\\r\\n\"\n    b'{\\\"name\\\":\\\"alice\\\"}'\n)\n```\n\n## Incremental Parsing\n\nThe parser is designed for chunked input. Feed it bytes exactly as you receive them from the socket or transport:\n\n```python\nimport httptools\n\nclass Protocol:\n    def on_message_begin(self) -> None:\n        self.body = bytearray()\n\n    def on_body(self, body: bytes) -> None:\n        self.body.extend(body)\n\n    def on_message_complete(self) -> None:\n        print(\"complete body:\", bytes(self.body))\n\nparser = httptools.HttpRequestParser(Protocol())\n\nfor chunk in [\n    b\"POST /upload HTTP/1.1\\r\\nHost: example.com\\r\\nContent-L\",\n    b\"ength: 11\\r\\n\\r\\nhello \",\n    b\"world\",\n]:\n    parser.feed_data(chunk)\n```\n\nWrap `feed_data()` in `try/except httptools.HttpParserError` if you need to reject malformed requests cleanly:\n\n```python\nimport httptools\n\nparser = httptools.HttpRequestParser(object())\n\ntry:\n    parser.feed_data(b\"broken request\")\nexcept httptools.HttpParserError as exc:\n    print(f\"parse failed: {exc}\")\n```\n\n## URL Parsing\n\n`parse_url()` is useful when you need the path, query string, host, or port without building your own splitter. It returns a parsed URL object whose string-like fields are bytes.\n\n```python\nimport httptools\n\nparsed = httptools.parse_url(b\"/users/list?active=1\")\n\nprint(parsed.path)   # b\"/users/list\"\nprint(parsed.query)  # b\"active=1\"\n```\n\nFor absolute URLs:\n\n```python\nimport httptools\n\nparsed = httptools.parse_url(b\"http://example.com:8080/users?id=1\")\n\nprint(parsed.schema)  # b\"http\"\nprint(parsed.host)    # b\"example.com\"\nprint(parsed.port)    # 8080\nprint(parsed.path)    # b\"/users\"\nprint(parsed.query)   # b\"id=1\"\n```\n\n## Configuration And Auth\n\n`httptools` has no authentication, session, retry, or transport configuration layer.\n\nThe practical configuration surface is:\n\n- the callback methods you implement on the protocol object\n- how you buffer partial request state between callbacks\n- how your server or transport layer handles sockets, TLS, backpressure, and connection lifecycles\n\nIf you need request routing, middleware, header normalization, or response generation, pair `httptools` with a higher-level server stack instead of trying to add those concerns inside the parser callbacks.\n\n## Common Pitfalls\n\n- Pass `bytes` to `feed_data()`, not `str`.\n- Callback arguments such as URL parts, header names, and header values are `bytes`; decode them explicitly when your application needs text.\n- Treat parser callbacks as streaming events. Do not assume the request body arrives in one `on_body()` call.\n- Keep request state on a per-connection or per-request object. Reset or replace it after `on_message_complete()`.\n- Handle parser failures explicitly with `httptools.HttpParserError` if malformed input should become a `400` or connection close in your server.\n- `httptools` is for HTTP/1.x parsing. It is not an HTTP client and it does not implement HTTP/2 or HTTP/3.\n\n## Version-Sensitive Notes\n\n- PyPI shows `0.7.1` as the current package version and requires Python `>=3.8`.\n- The `v0.7.1` release added Python 3.14 wheels and fixed Python 3.13 free-threaded wheel builds.\n- The `v0.7.0` release added wheels for Python 3.13 free-threaded, Windows ARM64, and macOS arm64.\n- If your environment does not have a compatible wheel for the target runtime and platform, `pip` may need to build from source. Check the PyPI files list for the version you are deploying.\n\n## Official Sources\n\n- GitHub repository and README: https://github.com/MagicStack/httptools\n- PyPI package page: https://pypi.org/project/httptools/\n- GitHub release `v0.7.1`: https://github.com/MagicStack/httptools/releases/tag/v0.7.1\n- GitHub release `v0.7.0`: https://github.com/MagicStack/httptools/releases/tag/v0.7.0\n"
  },
  {
    "path": "content/httpx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"HTTPX package guide for Python with sync and async clients, auth, transports, and 0.28.1 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"httpx,http,client,async,python,requests\"\n---\n\n# HTTPX Python Package Guide\n\n## When To Use HTTPX\n\nUse `httpx` when Python code needs:\n\n- a modern HTTP client with both sync and async APIs\n- connection pooling, timeouts, streaming, redirects, cookies, and auth\n- HTTP/2 support\n- transport adapters for testing WSGI or ASGI apps in-process\n\n`httpx` is the maintained successor-style choice when you want a `requests`-like API plus async support and more explicit client configuration.\n\n## Install\n\n```bash\npip install httpx==0.28.1\n```\n\nCommon optional extras from the official package metadata:\n\n```bash\npip install \"httpx[http2]==0.28.1\"\npip install \"httpx[socks]==0.28.1\"\npip install \"httpx[brotli]==0.28.1\"\npip install \"httpx[zstd]==0.28.1\"\n```\n\nVersion-sensitive runtime note:\n\n- PyPI metadata for `0.28.1` declares `Requires-Python >=3.8`.\n- The current docs homepage now says Python `3.9+`.\n- Treat the homepage as the latest upstream docs, not a strict guarantee for `0.28.1`. If you are pinned to `0.28.x`, prefer the package metadata and the `0.28.0` / `0.28.1` release notes for behavior changes.\n\n## Golden Rules\n\n- Prefer `httpx.Client()` or `httpx.AsyncClient()` for anything beyond a single one-off request.\n- Reuse one client instead of creating a new client inside a hot loop.\n- Call `response.raise_for_status()` when non-2xx responses should fail the workflow.\n- Redirects are **not** followed unless you set `follow_redirects=True`.\n- For `0.28.x`, use `proxy=` or `mounts=`. The old `proxies=` argument was removed.\n- For app testing and in-process calls, use `WSGITransport` or `ASGITransport`. The old `app=` shortcut was removed.\n\n## Basic Sync Usage\n\n```python\nimport httpx\n\nwith httpx.Client(\n    base_url=\"https://api.example.com\",\n    headers={\"Accept\": \"application/json\"},\n    params={\"api_version\": \"2026-01-01\"},\n    timeout=httpx.Timeout(10.0, connect=5.0),\n    follow_redirects=True,\n) as client:\n    response = client.get(\"/items\", params={\"limit\": 20})\n    response.raise_for_status()\n    items = response.json()\n    print(items)\n```\n\nUseful client behavior:\n\n- `base_url` lets you use relative paths like `\"/items\"`.\n- Client-level headers, query params, and cookies merge with request-level values.\n- A client keeps connections open and reuses them across requests.\n\n## Sending JSON, Form Data, and Files\n\n```python\nimport httpx\n\npayload = {\"name\": \"example\", \"enabled\": True}\n\nwith httpx.Client() as client:\n    response = client.post(\"https://api.example.com/items\", json=payload)\n    response.raise_for_status()\n```\n\n```python\nimport httpx\n\nwith open(\"report.csv\", \"rb\") as f:\n    files = {\"file\": (\"report.csv\", f, \"text/csv\")}\n    response = httpx.post(\"https://api.example.com/upload\", files=files)\n    response.raise_for_status()\n```\n\nUse the request body arguments deliberately:\n\n- `json=` for JSON bodies\n- `data=` for HTML form data\n- `files=` for multipart uploads\n- `content=` for raw bytes or text when you need full control\n\n## Async Usage\n\n```python\nimport asyncio\nimport httpx\n\nasync def main() -> None:\n    async with httpx.AsyncClient(\n        base_url=\"https://api.example.com\",\n        timeout=httpx.Timeout(10.0, connect=5.0),\n    ) as client:\n        response = await client.get(\"/items\")\n        response.raise_for_status()\n        print(response.json())\n\nasyncio.run(main())\n```\n\nFor streaming responses:\n\n```python\nimport asyncio\nimport httpx\n\nasync def download(url: str, output_path: str) -> None:\n    async with httpx.AsyncClient() as client:\n        async with client.stream(\"GET\", url) as response:\n            response.raise_for_status()\n            with open(output_path, \"wb\") as f:\n                async for chunk in response.aiter_bytes():\n                    f.write(chunk)\n\nasyncio.run(download(\"https://example.com/large.bin\", \"large.bin\"))\n```\n\nAsync pitfalls:\n\n- Keep one long-lived `AsyncClient` where possible.\n- Do not instantiate clients repeatedly inside request handlers unless that is the intended lifecycle.\n- If you use manual streaming mode, you must eventually call `Response.aclose()`.\n\n## Authentication\n\nBasic auth:\n\n```python\nimport httpx\n\nresponse = httpx.get(\n    \"https://api.example.com/me\",\n    auth=(\"username\", \"password\"),\n)\nresponse.raise_for_status()\n```\n\nClient-scoped auth:\n\n```python\nimport httpx\n\nwith httpx.Client(\n    base_url=\"https://api.example.com\",\n    auth=(\"username\", \"password\"),\n) as client:\n    response = client.get(\"/me\")\n    response.raise_for_status()\n```\n\nUpstream auth options to know about:\n\n- Basic auth via a `(username, password)` tuple\n- `httpx.DigestAuth(...)`\n- `httpx.NetRCAuth()` for local `.netrc` credentials\n- custom auth flows by subclassing `httpx.Auth`\n\nFor bearer tokens or API keys, set a header on the client:\n\n```python\nimport httpx\n\ntoken = \"YOUR_TOKEN\"\n\nwith httpx.Client(\n    base_url=\"https://api.example.com\",\n    headers={\"Authorization\": f\"Bearer {token}\"},\n) as client:\n    response = client.get(\"/me\")\n    response.raise_for_status()\n```\n\n## Timeouts, Limits, and Retries\n\nHTTPX enforces timeouts by default. Configure them explicitly for production code.\n\n```python\nimport httpx\n\ntimeout = httpx.Timeout(10.0, connect=2.0, read=20.0, write=20.0, pool=5.0)\nlimits = httpx.Limits(max_connections=100, max_keepalive_connections=20)\n\nwith httpx.Client(timeout=timeout, limits=limits) as client:\n    response = client.get(\"https://api.example.com/health\")\n    response.raise_for_status()\n```\n\nNotes:\n\n- The docs describe HTTPX timeouts as inactivity timeouts, not a single total request deadline.\n- Resource limits matter for high-concurrency code and async services.\n- HTTPX does not provide the same built-in retry layer you may know from `urllib3`; implement retries at your application boundary or transport layer when needed.\n\n## Proxies and Environment Variables\n\nExplicit proxy:\n\n```python\nimport httpx\n\nwith httpx.Client(proxy=\"http://localhost:8030\") as client:\n    response = client.get(\"https://example.com\")\n    response.raise_for_status()\n```\n\nEnvironment-driven proxy behavior is enabled by default via `trust_env=True`. Officially documented variables include:\n\n- `HTTP_PROXY`\n- `HTTPS_PROXY`\n- `ALL_PROXY`\n- `NO_PROXY`\n- `SSL_CERT_FILE`\n- `SSL_CERT_DIR`\n\nDisable environment-derived proxy and certificate settings when you need deterministic behavior:\n\n```python\nimport httpx\n\nwith httpx.Client(trust_env=False) as client:\n    response = client.get(\"https://example.com\")\n    response.raise_for_status()\n```\n\n## SSL / TLS Configuration\n\nFor `0.28.x`, the release notes deprecate string-style `verify=` and the `cert=` shortcut. Prefer an explicit `ssl.SSLContext`.\n\n```python\nimport ssl\nimport certifi\nimport httpx\n\nctx = ssl.create_default_context(cafile=certifi.where())\n\nwith httpx.Client(verify=ctx) as client:\n    response = client.get(\"https://example.com\")\n    response.raise_for_status()\n```\n\nIf you want system certificate stores on newer Python environments, the official SSL docs recommend `truststore`:\n\n```python\nimport ssl\nimport httpx\nimport truststore\n\nctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n\nwith httpx.Client(verify=ctx) as client:\n    response = client.get(\"https://example.com\")\n    response.raise_for_status()\n```\n\n## HTTP/2\n\nInstall the extra and enable it on the client:\n\n```python\nimport httpx\n\nwith httpx.Client(http2=True) as client:\n    response = client.get(\"https://example.com\")\n    print(response.http_version)\n```\n\n`http2=True` is not enough unless the `http2` extra is installed.\n\n## Transports and In-Process App Calls\n\nFor tests and in-process service integration, use the transport APIs directly:\n\n```python\nimport httpx\nfrom starlette.applications import Starlette\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import Route\n\nasync def homepage(request):\n    return JSONResponse({\"ok\": True})\n\napp = Starlette(routes=[Route(\"/\", homepage)])\ntransport = httpx.ASGITransport(app=app)\n\nasync def main() -> None:\n    async with httpx.AsyncClient(transport=transport, base_url=\"http://testserver\") as client:\n        response = await client.get(\"/\")\n        response.raise_for_status()\n        print(response.json())\n```\n\nUse this pattern for `0.28.1`. The deprecated `app=` shortcut was removed in `0.28.0`.\n\n## Error Handling\n\n`httpx.HTTPError` is the broad top-level exception. The most useful subclasses in normal application code are:\n\n- `httpx.HTTPStatusError` for `raise_for_status()` failures\n- `httpx.RequestError` for transport-level failures\n- `httpx.TimeoutException` and subclasses for timeout failures\n\n```python\nimport httpx\n\ntry:\n    response = httpx.get(\"https://api.example.com/items\", timeout=5.0)\n    response.raise_for_status()\nexcept httpx.HTTPStatusError as exc:\n    print(\"Bad status:\", exc.response.status_code)\nexcept httpx.TimeoutException:\n    print(\"Request timed out\")\nexcept httpx.RequestError as exc:\n    print(\"Transport error:\", exc)\n```\n\n## Requests Compatibility Notes\n\nHTTPX is intentionally similar to `requests`, but not identical:\n\n- Redirects are off by default.\n- `response.url` is an `httpx.URL` object, not a plain string.\n- Cookies should normally live on the client, not be passed ad hoc on individual request calls.\n- Streaming uses `Client.stream(...)` / `AsyncClient.stream(...)` instead of the exact `requests` interface.\n\nIf you are porting code from `requests`, check the compatibility guide before assuming every edge-case matches exactly.\n\n## Version-Sensitive Notes For 0.28.1\n\n- `0.28.0` removed the deprecated `proxies` argument. Use `proxy=` for a single proxy or `mounts=` for per-scheme routing.\n- `0.28.0` removed the deprecated `app` argument. Use `WSGITransport` or `ASGITransport`.\n- `0.28.0` deprecated string-style `verify=` and the `cert=` argument. Prefer `ssl.SSLContext`.\n- `0.28.0` changed JSON request body serialization to a more compact representation.\n- `0.28.1` fixed a bug involving `verify=False` together with client-side certificates.\n\n## Official Sources\n\n- Docs root: `https://www.python-httpx.org/`\n- Quickstart: `https://www.python-httpx.org/quickstart/`\n- Clients: `https://www.python-httpx.org/advanced/clients/`\n- Authentication: `https://www.python-httpx.org/advanced/authentication/`\n- Timeouts: `https://www.python-httpx.org/advanced/timeouts/`\n- Resource limits: `https://www.python-httpx.org/advanced/resource-limits/`\n- Proxies: `https://www.python-httpx.org/advanced/proxies/`\n- SSL: `https://www.python-httpx.org/advanced/ssl/`\n- Environment variables: `https://www.python-httpx.org/environment_variables/`\n- Async support: `https://www.python-httpx.org/async/`\n- HTTP/2: `https://www.python-httpx.org/http2/`\n- Requests compatibility: `https://www.python-httpx.org/compatibility/`\n- Exceptions: `https://www.python-httpx.org/exceptions/`\n- Transports: `https://www.python-httpx.org/advanced/transports/`\n- PyPI package metadata: `https://pypi.org/project/httpx/0.28.1/`\n- Releases: `https://github.com/encode/httpx/releases/tag/0.28.0`\n- Releases: `https://github.com/encode/httpx/releases/tag/0.28.1`\n"
  },
  {
    "path": "content/hubspot/docs/crm/javascript/DOC.md",
    "content": "---\nname: crm\ndescription: \"HubSpot Node.js SDK for managing CRM contacts, companies, deals, and marketing automation via the HubSpot API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"13.4.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"hubspot,crm,marketing,contacts,automation\"\n---\n\n# HubSpot JavaScript/Node.js SDK Coding Guidelines\n\nYou are a HubSpot API coding expert. Help me write code using the HubSpot API with the official Node.js SDK.\n\nOfficial SDK documentation and code samples:\nhttps://developers.hubspot.com/docs/api/overview\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official HubSpot Node.js SDK (`@hubspot/api-client`), which is the standard library for all HubSpot API interactions. Do not use deprecated or unofficial packages.\n\n- **Library Name:** HubSpot Node.js SDK\n- **NPM Package:** `@hubspot/api-client`\n- **Current Version:** 13.4.0\n- **Deprecated Packages:** `hubspot`, `hubspot-api`, `@hubspot/integrations-framework-actions` (do not use these)\n\n**Installation:**\n\n- **Correct:** `npm install @hubspot/api-client`\n- **Incorrect:** `npm install hubspot` or `npm install hubspot-api`\n\n**APIs and Usage:**\n\n- **Correct:** `const hubspot = require('@hubspot/api-client')`\n- **Correct:** `const hubspotClient = new hubspot.Client({ accessToken: token })`\n- **Correct:** `await hubspotClient.crm.contacts.basicApi.create(...)`\n- **Incorrect:** `HubspotClient` or `HubspotAPI`\n- **Incorrect:** Legacy v2 API endpoints\n\n## Installation\n\nInstall the SDK via npm:\n\n```bash\nnpm install @hubspot/api-client\n```\n\nFor TypeScript projects, the SDK includes built-in type definitions.\n\n## Authentication\n\nHubSpot API uses access tokens for authentication. There are three types of access tokens:\n\n1. **Private App Access Tokens** (recommended for server-side integrations)\n2. **OAuth Access Tokens** (for public apps and integrations)\n3. **Legacy API Keys** (deprecated, will be revoked November 19, 2025)\n\n### Environment Variable Configuration\n\nSet your access token as an environment variable:\n\n```bash\n# .env file\nHUBSPOT_ACCESS_TOKEN=your_access_token_here\n```\n\n**Creating a Private App:**\n\n1. Navigate to Settings > Integrations > Private Apps in your HubSpot account\n2. Click \"Create private app\"\n3. Configure the required scopes (permissions)\n4. Click \"Create app\" and copy the access token\n\n## Initialization\n\n### Basic Initialization\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\n\n// Initialize with access token from environment variable\nconst hubspotClient = new hubspot.Client({\n  accessToken: process.env.HUBSPOT_ACCESS_TOKEN\n});\n```\n\n### Initialization with OAuth\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\n\nconst hubspotClient = new hubspot.Client({\n  accessToken: 'YOUR_OAUTH_ACCESS_TOKEN'\n});\n\n// Refresh token when needed\nhubspotClient.setAccessToken('NEW_ACCESS_TOKEN');\n```\n\n### Initialization with Rate Limiting Options\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\n\nconst hubspotClient = new hubspot.Client({\n  accessToken: process.env.HUBSPOT_ACCESS_TOKEN,\n  limiterOptions: {\n    maxConcurrent: 5,\n    minTime: 100\n  }\n});\n```\n\n## CRM API - Contacts\n\n### Create a Contact\n\n**Basic Example:**\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\nconst hubspotClient = new hubspot.Client({ accessToken: process.env.HUBSPOT_ACCESS_TOKEN });\n\nasync function createContact() {\n  const contactObj = {\n    properties: {\n      email: 'example@company.com',\n      firstname: 'John',\n      lastname: 'Doe',\n      phone: '555-0100',\n      company: 'Example Company',\n      website: 'example.com'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.create(contactObj);\n    console.log('Contact created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating contact:', error.message);\n  }\n}\n\ncreateContact();\n```\n\n**Advanced Example with Custom Properties:**\n\n```javascript\nasync function createContactAdvanced() {\n  const contactObj = {\n    properties: {\n      email: 'jane@example.com',\n      firstname: 'Jane',\n      lastname: 'Smith',\n      phone: '555-0200',\n      company: 'Tech Corp',\n      jobtitle: 'Software Engineer',\n      lifecyclestage: 'lead',\n      hs_lead_status: 'NEW',\n      // Custom properties\n      custom_field: 'custom_value',\n      industry: 'Technology'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.create(contactObj);\n    console.log('Contact created with ID:', apiResponse.id);\n    console.log('Properties:', apiResponse.properties);\n    return apiResponse;\n  } catch (error) {\n    if (error.statusCode === 409) {\n      console.error('Contact with this email already exists');\n    } else {\n      console.error('Error creating contact:', error.message);\n    }\n  }\n}\n```\n\n### Get a Contact\n\n**By ID:**\n\n```javascript\nasync function getContact(contactId) {\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.getById(\n      contactId,\n      ['email', 'firstname', 'lastname', 'phone', 'company'] // properties to return\n    );\n    console.log('Contact:', apiResponse.properties);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching contact:', error.message);\n  }\n}\n```\n\n**By Email:**\n\n```javascript\nasync function getContactByEmail(email) {\n  const filter = { propertyName: 'email', operator: 'EQ', value: email };\n  const filterGroup = { filters: [filter] };\n  const sort = JSON.stringify({ propertyName: 'createdate', direction: 'DESCENDING' });\n  const properties = ['email', 'firstname', 'lastname'];\n  const limit = 1;\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.searchApi.doSearch({\n      filterGroups: [filterGroup],\n      sorts: [sort],\n      properties,\n      limit\n    });\n\n    if (apiResponse.total > 0) {\n      return apiResponse.results[0];\n    }\n    return null;\n  } catch (error) {\n    console.error('Error searching contact:', error.message);\n  }\n}\n```\n\n### Update a Contact\n\n```javascript\nasync function updateContact(contactId) {\n  const properties = {\n    firstname: 'Updated Name',\n    phone: '555-9999',\n    lifecyclestage: 'opportunity'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.update(\n      contactId,\n      { properties }\n    );\n    console.log('Contact updated:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error updating contact:', error.message);\n  }\n}\n```\n\n### List Contacts\n\n**Basic Pagination:**\n\n```javascript\nasync function listContacts() {\n  const limit = 10;\n  const properties = ['email', 'firstname', 'lastname', 'company'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.getPage(\n      limit,\n      undefined, // after (for pagination)\n      properties\n    );\n\n    console.log(`Found ${apiResponse.results.length} contacts`);\n    apiResponse.results.forEach(contact => {\n      console.log(`${contact.properties.firstname} ${contact.properties.lastname}`);\n    });\n\n    return apiResponse;\n  } catch (error) {\n    console.error('Error listing contacts:', error.message);\n  }\n}\n```\n\n**Get All Contacts (with pagination handling):**\n\n```javascript\nasync function getAllContacts() {\n  const allContacts = [];\n  let after = undefined;\n  const limit = 100;\n\n  try {\n    do {\n      const apiResponse = await hubspotClient.crm.contacts.basicApi.getPage(\n        limit,\n        after,\n        ['email', 'firstname', 'lastname']\n      );\n\n      allContacts.push(...apiResponse.results);\n      after = apiResponse.paging?.next?.after;\n\n    } while (after);\n\n    console.log(`Total contacts retrieved: ${allContacts.length}`);\n    return allContacts;\n  } catch (error) {\n    console.error('Error getting all contacts:', error.message);\n  }\n}\n```\n\n### Delete a Contact\n\n```javascript\nasync function deleteContact(contactId) {\n  try {\n    await hubspotClient.crm.contacts.basicApi.archive(contactId);\n    console.log('Contact deleted:', contactId);\n  } catch (error) {\n    console.error('Error deleting contact:', error.message);\n  }\n}\n```\n\n## CRM API - Companies\n\n### Create a Company\n\n```javascript\nasync function createCompany() {\n  const companyObj = {\n    properties: {\n      name: 'Example Company',\n      domain: 'example.com',\n      city: 'San Francisco',\n      state: 'California',\n      industry: 'Technology',\n      phone: '555-0100',\n      numberofemployees: '50',\n      description: 'A technology company'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.companies.basicApi.create(companyObj);\n    console.log('Company created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating company:', error.message);\n  }\n}\n```\n\n### Get a Company\n\n```javascript\nasync function getCompany(companyId) {\n  const properties = ['name', 'domain', 'city', 'industry', 'phone'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.companies.basicApi.getById(\n      companyId,\n      properties\n    );\n    console.log('Company:', apiResponse.properties);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching company:', error.message);\n  }\n}\n```\n\n### Update a Company\n\n```javascript\nasync function updateCompany(companyId) {\n  const properties = {\n    name: 'Updated Company Name',\n    numberofemployees: '100',\n    annualrevenue: '1000000'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.companies.basicApi.update(\n      companyId,\n      { properties }\n    );\n    console.log('Company updated:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error updating company:', error.message);\n  }\n}\n```\n\n### List Companies\n\n```javascript\nasync function listCompanies() {\n  const limit = 10;\n  const properties = ['name', 'domain', 'city', 'industry'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.companies.basicApi.getPage(\n      limit,\n      undefined,\n      properties\n    );\n\n    console.log(`Found ${apiResponse.results.length} companies`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error listing companies:', error.message);\n  }\n}\n```\n\n## CRM API - Deals\n\n### Create a Deal\n\n```javascript\nasync function createDeal() {\n  const dealObj = {\n    properties: {\n      dealname: 'New Deal',\n      dealstage: 'appointmentscheduled',\n      amount: '10000',\n      closedate: '2025-12-31',\n      pipeline: 'default',\n      hubspot_owner_id: '12345'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.deals.basicApi.create(dealObj);\n    console.log('Deal created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating deal:', error.message);\n  }\n}\n```\n\n### Get a Deal\n\n```javascript\nasync function getDeal(dealId) {\n  const properties = ['dealname', 'dealstage', 'amount', 'closedate'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.deals.basicApi.getById(\n      dealId,\n      properties\n    );\n    console.log('Deal:', apiResponse.properties);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching deal:', error.message);\n  }\n}\n```\n\n### Update a Deal\n\n```javascript\nasync function updateDeal(dealId) {\n  const properties = {\n    dealstage: 'closedwon',\n    amount: '15000',\n    closedate: '2025-11-30'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.deals.basicApi.update(\n      dealId,\n      { properties }\n    );\n    console.log('Deal updated:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error updating deal:', error.message);\n  }\n}\n```\n\n### List Deals\n\n```javascript\nasync function listDeals() {\n  const limit = 10;\n  const properties = ['dealname', 'dealstage', 'amount'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.deals.basicApi.getPage(\n      limit,\n      undefined,\n      properties\n    );\n\n    console.log(`Found ${apiResponse.results.length} deals`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error listing deals:', error.message);\n  }\n}\n```\n\n## CRM API - Tickets\n\n### Create a Ticket\n\n```javascript\nasync function createTicket() {\n  const ticketObj = {\n    properties: {\n      subject: 'Customer Support Request',\n      content: 'Customer needs help with product setup',\n      hs_pipeline: '0',\n      hs_pipeline_stage: '1',\n      hs_ticket_priority: 'HIGH',\n      hubspot_owner_id: '12345'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.tickets.basicApi.create(ticketObj);\n    console.log('Ticket created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating ticket:', error.message);\n  }\n}\n```\n\n### Get a Ticket\n\n```javascript\nasync function getTicket(ticketId) {\n  const properties = ['subject', 'content', 'hs_pipeline_stage', 'hs_ticket_priority'];\n\n  try {\n    const apiResponse = await hubspotClient.crm.tickets.basicApi.getById(\n      ticketId,\n      properties\n    );\n    console.log('Ticket:', apiResponse.properties);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching ticket:', error.message);\n  }\n}\n```\n\n### Update a Ticket\n\n```javascript\nasync function updateTicket(ticketId) {\n  const properties = {\n    hs_pipeline_stage: '4', // Closed\n    hs_ticket_priority: 'LOW'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.tickets.basicApi.update(\n      ticketId,\n      { properties }\n    );\n    console.log('Ticket updated:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error updating ticket:', error.message);\n  }\n}\n```\n\n## CRM API - Associations\n\nAssociations link objects together (e.g., contacts to companies, deals to contacts).\n\n### Create Association\n\n**Associate Contact with Company:**\n\n```javascript\nasync function associateContactWithCompany(contactId, companyId) {\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.associationsApi.create(\n      contactId,\n      'companies',\n      companyId,\n      'contact_to_company'\n    );\n    console.log('Association created');\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating association:', error.message);\n  }\n}\n```\n\n**Associate Deal with Contact:**\n\n```javascript\nasync function associateDealWithContact(dealId, contactId) {\n  try {\n    const apiResponse = await hubspotClient.crm.deals.associationsApi.create(\n      dealId,\n      'contacts',\n      contactId,\n      'deal_to_contact'\n    );\n    console.log('Association created');\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating association:', error.message);\n  }\n}\n```\n\n### Get Associations\n\n```javascript\nasync function getContactAssociations(contactId) {\n  try {\n    const companies = await hubspotClient.crm.contacts.associationsApi.getAll(\n      contactId,\n      'companies'\n    );\n\n    const deals = await hubspotClient.crm.contacts.associationsApi.getAll(\n      contactId,\n      'deals'\n    );\n\n    console.log('Associated companies:', companies.results);\n    console.log('Associated deals:', deals.results);\n\n    return { companies, deals };\n  } catch (error) {\n    console.error('Error fetching associations:', error.message);\n  }\n}\n```\n\n### Remove Association\n\n```javascript\nasync function removeAssociation(contactId, companyId) {\n  try {\n    await hubspotClient.crm.contacts.associationsApi.archive(\n      contactId,\n      'companies',\n      companyId,\n      'contact_to_company'\n    );\n    console.log('Association removed');\n  } catch (error) {\n    console.error('Error removing association:', error.message);\n  }\n}\n```\n\n## CRM API - Batch Operations\n\nBatch operations allow you to create, update, or read up to 100 records in a single API call.\n\n### Batch Create Contacts\n\n```javascript\nasync function batchCreateContacts() {\n  const batchInputs = {\n    inputs: [\n      {\n        properties: {\n          email: 'contact1@example.com',\n          firstname: 'Contact',\n          lastname: 'One'\n        }\n      },\n      {\n        properties: {\n          email: 'contact2@example.com',\n          firstname: 'Contact',\n          lastname: 'Two'\n        }\n      },\n      {\n        properties: {\n          email: 'contact3@example.com',\n          firstname: 'Contact',\n          lastname: 'Three'\n        }\n      }\n    ]\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.batchApi.create(batchInputs);\n    console.log(`Created ${apiResponse.results.length} contacts`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error batch creating contacts:', error.message);\n  }\n}\n```\n\n### Batch Update Contacts\n\n```javascript\nasync function batchUpdateContacts(contactIds) {\n  const batchInputs = {\n    inputs: contactIds.map(id => ({\n      id: id,\n      properties: {\n        lifecyclestage: 'customer',\n        hs_lead_status: 'CONNECTED'\n      }\n    }))\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.batchApi.update(batchInputs);\n    console.log(`Updated ${apiResponse.results.length} contacts`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error batch updating contacts:', error.message);\n  }\n}\n```\n\n### Batch Read Contacts\n\n```javascript\nasync function batchReadContacts(contactIds) {\n  const batchInputs = {\n    properties: ['email', 'firstname', 'lastname', 'phone'],\n    inputs: contactIds.map(id => ({ id }))\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.batchApi.read(batchInputs);\n    console.log(`Retrieved ${apiResponse.results.length} contacts`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error batch reading contacts:', error.message);\n  }\n}\n```\n\n### Batch Upsert Contacts\n\n```javascript\nasync function batchUpsertContacts() {\n  const batchInputs = {\n    inputs: [\n      {\n        properties: {\n          email: 'existing@example.com',\n          firstname: 'Updated',\n          lastname: 'Name'\n        },\n        idProperty: 'email'\n      },\n      {\n        properties: {\n          email: 'new@example.com',\n          firstname: 'New',\n          lastname: 'Contact'\n        },\n        idProperty: 'email'\n      }\n    ]\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.batchApi.upsert(batchInputs);\n    console.log(`Upserted ${apiResponse.results.length} contacts`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error batch upserting contacts:', error.message);\n  }\n}\n```\n\n## CRM API - Search\n\nThe Search API allows you to filter, sort, and search across CRM objects.\n\n### Basic Search\n\n```javascript\nasync function searchContacts() {\n  const filter = {\n    propertyName: 'lifecyclestage',\n    operator: 'EQ',\n    value: 'lead'\n  };\n\n  const filterGroup = {\n    filters: [filter]\n  };\n\n  const searchRequest = {\n    filterGroups: [filterGroup],\n    properties: ['email', 'firstname', 'lastname', 'lifecyclestage'],\n    limit: 10\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.searchApi.doSearch(searchRequest);\n    console.log(`Found ${apiResponse.total} contacts`);\n    console.log(`Returned ${apiResponse.results.length} results`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error searching contacts:', error.message);\n  }\n}\n```\n\n### Advanced Search with Multiple Filters\n\n```javascript\nasync function advancedSearchContacts() {\n  const searchRequest = {\n    filterGroups: [\n      {\n        filters: [\n          {\n            propertyName: 'lifecyclestage',\n            operator: 'EQ',\n            value: 'lead'\n          },\n          {\n            propertyName: 'createdate',\n            operator: 'GTE',\n            value: '2025-01-01'\n          }\n        ]\n      }\n    ],\n    sorts: [\n      {\n        propertyName: 'createdate',\n        direction: 'DESCENDING'\n      }\n    ],\n    properties: ['email', 'firstname', 'lastname', 'createdate', 'lifecyclestage'],\n    limit: 100,\n    after: 0\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.searchApi.doSearch(searchRequest);\n    console.log(`Found ${apiResponse.total} matching contacts`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error searching contacts:', error.message);\n  }\n}\n```\n\n### Search with Association Filters\n\n```javascript\nasync function searchContactsByCompany(companyId) {\n  const searchRequest = {\n    filterGroups: [\n      {\n        filters: [\n          {\n            propertyName: 'associations.company',\n            operator: 'EQ',\n            value: companyId\n          }\n        ]\n      }\n    ],\n    properties: ['email', 'firstname', 'lastname'],\n    limit: 100\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.searchApi.doSearch(searchRequest);\n    console.log(`Found ${apiResponse.results.length} contacts for company`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error searching contacts by company:', error.message);\n  }\n}\n```\n\n### Search Operators\n\nAvailable operators for search filters:\n\n- `EQ` - Equal to\n- `NEQ` - Not equal to\n- `LT` - Less than\n- `LTE` - Less than or equal to\n- `GT` - Greater than\n- `GTE` - Greater than or equal to\n- `IN` - In list of values\n- `NOT_IN` - Not in list of values\n- `HAS_PROPERTY` - Has property value set\n- `NOT_HAS_PROPERTY` - Does not have property value set\n- `CONTAINS_TOKEN` - Contains token (for text)\n- `NOT_CONTAINS_TOKEN` - Does not contain token\n\n## CRM API - Properties\n\n### Get All Contact Properties\n\n```javascript\nasync function getAllContactProperties() {\n  try {\n    const apiResponse = await hubspotClient.crm.properties.coreApi.getAll('contacts');\n    console.log(`Found ${apiResponse.results.length} contact properties`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching contact properties:', error.message);\n  }\n}\n```\n\n### Create Custom Property\n\n```javascript\nasync function createCustomProperty() {\n  const propertyObj = {\n    name: 'favorite_color',\n    label: 'Favorite Color',\n    type: 'string',\n    fieldType: 'text',\n    groupName: 'contactinformation',\n    description: 'The contact\\'s favorite color',\n    options: []\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.properties.coreApi.create(\n      'contacts',\n      propertyObj\n    );\n    console.log('Custom property created:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating custom property:', error.message);\n  }\n}\n```\n\n### Create Dropdown Property\n\n```javascript\nasync function createDropdownProperty() {\n  const propertyObj = {\n    name: 'customer_tier',\n    label: 'Customer Tier',\n    type: 'enumeration',\n    fieldType: 'select',\n    groupName: 'contactinformation',\n    options: [\n      { label: 'Bronze', value: 'bronze', displayOrder: 0 },\n      { label: 'Silver', value: 'silver', displayOrder: 1 },\n      { label: 'Gold', value: 'gold', displayOrder: 2 },\n      { label: 'Platinum', value: 'platinum', displayOrder: 3 }\n    ]\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.properties.coreApi.create(\n      'contacts',\n      propertyObj\n    );\n    console.log('Dropdown property created:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating dropdown property:', error.message);\n  }\n}\n```\n\n### Update Property\n\n```javascript\nasync function updateProperty(propertyName) {\n  const propertyUpdate = {\n    label: 'Updated Label',\n    description: 'Updated description'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.properties.coreApi.update(\n      'contacts',\n      propertyName,\n      propertyUpdate\n    );\n    console.log('Property updated:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error updating property:', error.message);\n  }\n}\n```\n\n## Marketing API - Emails\n\n### Get All Marketing Emails\n\n```javascript\nasync function getMarketingEmails() {\n  try {\n    const apiResponse = await hubspotClient.marketing.emails.emailsApi.getPage();\n    console.log(`Found ${apiResponse.results.length} marketing emails`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching marketing emails:', error.message);\n  }\n}\n```\n\n### Get Email by ID\n\n```javascript\nasync function getMarketingEmail(emailId) {\n  try {\n    const apiResponse = await hubspotClient.marketing.emails.emailsApi.getById(emailId);\n    console.log('Email:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching marketing email:', error.message);\n  }\n}\n```\n\n## Marketing API - Forms\n\n### Get All Forms\n\n```javascript\nasync function getAllForms() {\n  try {\n    const apiResponse = await hubspotClient.marketing.forms.formsApi.getPage();\n    console.log(`Found ${apiResponse.results.length} forms`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching forms:', error.message);\n  }\n}\n```\n\n### Get Form by ID\n\n```javascript\nasync function getForm(formId) {\n  try {\n    const apiResponse = await hubspotClient.marketing.forms.formsApi.getById(formId);\n    console.log('Form:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching form:', error.message);\n  }\n}\n```\n\n### Submit Form Data\n\n```javascript\nasync function submitFormData(formGuid, portalId) {\n  const formData = {\n    fields: [\n      {\n        name: 'email',\n        value: 'test@example.com'\n      },\n      {\n        name: 'firstname',\n        value: 'John'\n      },\n      {\n        name: 'lastname',\n        value: 'Doe'\n      }\n    ],\n    context: {\n      pageUri: 'https://example.com/contact',\n      pageName: 'Contact Us'\n    }\n  };\n\n  try {\n    const axios = require('axios');\n    const response = await axios.post(\n      `https://api.hsforms.com/submissions/v3/integration/submit/${portalId}/${formGuid}`,\n      formData\n    );\n    console.log('Form submitted successfully');\n    return response.data;\n  } catch (error) {\n    console.error('Error submitting form:', error.message);\n  }\n}\n```\n\n## Events API - Timeline Events\n\n### Create Timeline Event Type\n\n```javascript\nasync function createTimelineEventType() {\n  const eventTypeObj = {\n    name: 'Custom Event',\n    applicationId: 12345, // Your app ID\n    objectType: 'CONTACT',\n    headerTemplate: '{{eventTitle}}',\n    detailTemplate: '{{eventDescription}}'\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.timeline.eventsApi.createEventType(\n      eventTypeObj\n    );\n    console.log('Timeline event type created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating timeline event type:', error.message);\n  }\n}\n```\n\n### Create Timeline Event\n\n```javascript\nasync function createTimelineEvent(eventTypeId, objectId) {\n  const eventData = {\n    eventTypeId: eventTypeId,\n    objectId: objectId,\n    extraData: {\n      eventTitle: 'Purchase Completed',\n      eventDescription: 'Customer completed a purchase of $99.99'\n    },\n    timestamp: new Date().toISOString()\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.timeline.eventsApi.create(eventData);\n    console.log('Timeline event created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating timeline event:', error.message);\n  }\n}\n```\n\n## Automation API - Workflows\n\n### Get All Workflows\n\n```javascript\nasync function getAllWorkflows() {\n  try {\n    const axios = require('axios');\n    const response = await axios.get(\n      'https://api.hubapi.com/automation/v3/workflows',\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`\n        }\n      }\n    );\n    console.log(`Found ${response.data.workflows.length} workflows`);\n    return response.data;\n  } catch (error) {\n    console.error('Error fetching workflows:', error.message);\n  }\n}\n```\n\n### Get Workflow by ID\n\n```javascript\nasync function getWorkflow(workflowId) {\n  try {\n    const axios = require('axios');\n    const response = await axios.get(\n      `https://api.hubapi.com/automation/v3/workflows/${workflowId}`,\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`\n        }\n      }\n    );\n    console.log('Workflow:', response.data.name);\n    return response.data;\n  } catch (error) {\n    console.error('Error fetching workflow:', error.message);\n  }\n}\n```\n\n### Enroll Contact in Workflow\n\n```javascript\nasync function enrollContactInWorkflow(workflowId, contactEmail) {\n  try {\n    const axios = require('axios');\n    const response = await axios.post(\n      `https://api.hubapi.com/automation/v2/workflows/${workflowId}/enrollments/contacts/${contactEmail}`,\n      {},\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`,\n          'Content-Type': 'application/json'\n        }\n      }\n    );\n    console.log('Contact enrolled in workflow');\n    return response.data;\n  } catch (error) {\n    console.error('Error enrolling contact in workflow:', error.message);\n  }\n}\n```\n\n## Webhooks API\n\n### Create Webhook Subscription\n\n```javascript\nasync function createWebhookSubscription() {\n  const subscriptionObj = {\n    eventType: 'contact.creation',\n    propertyName: undefined,\n    active: true\n  };\n\n  try {\n    const apiResponse = await hubspotClient.webhooks.subscriptionsApi.create(\n      12345, // Your app ID\n      subscriptionObj\n    );\n    console.log('Webhook subscription created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating webhook subscription:', error.message);\n  }\n}\n```\n\n### Get All Webhook Subscriptions\n\n```javascript\nasync function getWebhookSubscriptions(appId) {\n  try {\n    const apiResponse = await hubspotClient.webhooks.subscriptionsApi.getAll(appId);\n    console.log(`Found ${apiResponse.results.length} webhook subscriptions`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching webhook subscriptions:', error.message);\n  }\n}\n```\n\n### Delete Webhook Subscription\n\n```javascript\nasync function deleteWebhookSubscription(appId, subscriptionId) {\n  try {\n    await hubspotClient.webhooks.subscriptionsApi.archive(appId, subscriptionId);\n    console.log('Webhook subscription deleted');\n  } catch (error) {\n    console.error('Error deleting webhook subscription:', error.message);\n  }\n}\n```\n\n## Lists API\n\n### Get All Lists\n\n```javascript\nasync function getAllLists() {\n  try {\n    const axios = require('axios');\n    const response = await axios.get(\n      'https://api.hubapi.com/contacts/v1/lists',\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`\n        },\n        params: {\n          count: 100,\n          offset: 0\n        }\n      }\n    );\n    console.log(`Found ${response.data.lists.length} lists`);\n    return response.data;\n  } catch (error) {\n    console.error('Error fetching lists:', error.message);\n  }\n}\n```\n\n### Add Contact to List\n\n```javascript\nasync function addContactToList(listId, contactId) {\n  try {\n    const axios = require('axios');\n    const response = await axios.post(\n      `https://api.hubapi.com/contacts/v1/lists/${listId}/add`,\n      {\n        vids: [contactId]\n      },\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`,\n          'Content-Type': 'application/json'\n        }\n      }\n    );\n    console.log('Contact added to list');\n    return response.data;\n  } catch (error) {\n    console.error('Error adding contact to list:', error.message);\n  }\n}\n```\n\n### Remove Contact from List\n\n```javascript\nasync function removeContactFromList(listId, contactId) {\n  try {\n    const axios = require('axios');\n    const response = await axios.post(\n      `https://api.hubapi.com/contacts/v1/lists/${listId}/remove`,\n      {\n        vids: [contactId]\n      },\n      {\n        headers: {\n          Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`,\n          'Content-Type': 'application/json'\n        }\n      }\n    );\n    console.log('Contact removed from list');\n    return response.data;\n  } catch (error) {\n    console.error('Error removing contact from list:', error.message);\n  }\n}\n```\n\n## Owners API\n\n### Get All Owners\n\n```javascript\nasync function getAllOwners() {\n  try {\n    const apiResponse = await hubspotClient.crm.owners.ownersApi.getPage();\n    console.log(`Found ${apiResponse.results.length} owners`);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching owners:', error.message);\n  }\n}\n```\n\n### Get Owner by ID\n\n```javascript\nasync function getOwner(ownerId) {\n  try {\n    const apiResponse = await hubspotClient.crm.owners.ownersApi.getById(ownerId);\n    console.log('Owner:', apiResponse.email);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error fetching owner:', error.message);\n  }\n}\n```\n\n## Error Handling\n\n### Comprehensive Error Handling\n\n```javascript\nasync function handleApiCall() {\n  try {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.getById('12345');\n    return apiResponse;\n  } catch (error) {\n    if (error.statusCode === 401) {\n      console.error('Authentication failed - check your access token');\n    } else if (error.statusCode === 404) {\n      console.error('Resource not found');\n    } else if (error.statusCode === 409) {\n      console.error('Conflict - resource already exists');\n    } else if (error.statusCode === 429) {\n      console.error('Rate limit exceeded - wait before retrying');\n    } else if (error.statusCode >= 500) {\n      console.error('HubSpot server error - try again later');\n    } else {\n      console.error('API error:', error.message);\n    }\n    throw error;\n  }\n}\n```\n\n### Retry Logic\n\n```javascript\nasync function apiCallWithRetry(apiCall, maxRetries = 3) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await apiCall();\n    } catch (error) {\n      if (error.statusCode === 429 && attempt < maxRetries) {\n        const retryAfter = error.response?.headers['retry-after'] || 1;\n        console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);\n        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n      } else {\n        throw error;\n      }\n    }\n  }\n}\n\n// Usage\nawait apiCallWithRetry(() =>\n  hubspotClient.crm.contacts.basicApi.getById('12345')\n);\n```\n\n## Rate Limits\n\nHubSpot API has the following rate limits:\n\n- **Private Apps:** 100 requests per 10 seconds per account\n- **OAuth Apps:** 100 requests per 10 seconds per app per account\n- **Search API:** 5 requests per second, 1000 requests per day (per account)\n- **Batch API:** 100 objects per request, same rate limits as standard endpoints\n\nThe SDK automatically handles rate limiting with the `limiterOptions` configuration.\n\n## Pagination\n\nMost list endpoints return paginated results. Use the `after` parameter for pagination:\n\n```javascript\nasync function paginateThroughContacts() {\n  let after = undefined;\n  let allContacts = [];\n\n  do {\n    const apiResponse = await hubspotClient.crm.contacts.basicApi.getPage(\n      100,\n      after,\n      ['email', 'firstname', 'lastname']\n    );\n\n    allContacts.push(...apiResponse.results);\n    after = apiResponse.paging?.next?.after;\n\n  } while (after);\n\n  return allContacts;\n}\n```\n\n## OAuth Implementation\n\n### Initialize OAuth Provider\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\n\nconst hubspotClient = new hubspot.Client({\n  clientId: process.env.HUBSPOT_CLIENT_ID,\n  clientSecret: process.env.HUBSPOT_CLIENT_SECRET,\n  redirectUri: 'https://yourapp.com/oauth-callback'\n});\n```\n\n### Get Authorization URL\n\n```javascript\nfunction getAuthorizationUrl() {\n  const authUrl = hubspotClient.oauth.getAuthorizationUrl(\n    process.env.HUBSPOT_CLIENT_ID,\n    process.env.REDIRECT_URI,\n    'contacts crm.objects.contacts.read'\n  );\n  return authUrl;\n}\n```\n\n### Exchange Authorization Code for Tokens\n\n```javascript\nasync function getTokens(authorizationCode) {\n  try {\n    const tokenResponse = await hubspotClient.oauth.tokensApi.create(\n      'authorization_code',\n      authorizationCode,\n      process.env.REDIRECT_URI,\n      process.env.HUBSPOT_CLIENT_ID,\n      process.env.HUBSPOT_CLIENT_SECRET\n    );\n\n    return {\n      accessToken: tokenResponse.accessToken,\n      refreshToken: tokenResponse.refreshToken,\n      expiresIn: tokenResponse.expiresIn\n    };\n  } catch (error) {\n    console.error('Error exchanging code for tokens:', error.message);\n  }\n}\n```\n\n### Refresh Access Token\n\n```javascript\nasync function refreshAccessToken(refreshToken) {\n  try {\n    const tokenResponse = await hubspotClient.oauth.tokensApi.create(\n      'refresh_token',\n      undefined,\n      undefined,\n      process.env.HUBSPOT_CLIENT_ID,\n      process.env.HUBSPOT_CLIENT_SECRET,\n      refreshToken\n    );\n\n    return {\n      accessToken: tokenResponse.accessToken,\n      refreshToken: tokenResponse.refreshToken,\n      expiresIn: tokenResponse.expiresIn\n    };\n  } catch (error) {\n    console.error('Error refreshing token:', error.message);\n  }\n}\n```\n\n## Custom Objects\n\n### Create Custom Object Schema\n\n```javascript\nasync function createCustomObjectSchema() {\n  const schemaObj = {\n    name: 'cars',\n    labels: {\n      singular: 'Car',\n      plural: 'Cars'\n    },\n    primaryDisplayProperty: 'model',\n    requiredProperties: ['model', 'make'],\n    searchableProperties: ['model', 'make', 'year'],\n    properties: [\n      {\n        name: 'model',\n        label: 'Model',\n        type: 'string',\n        fieldType: 'text'\n      },\n      {\n        name: 'make',\n        label: 'Make',\n        type: 'string',\n        fieldType: 'text'\n      },\n      {\n        name: 'year',\n        label: 'Year',\n        type: 'number',\n        fieldType: 'number'\n      }\n    ]\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.schemas.coreApi.create(schemaObj);\n    console.log('Custom object schema created:', apiResponse.name);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating custom object schema:', error.message);\n  }\n}\n```\n\n### Create Custom Object Instance\n\n```javascript\nasync function createCustomObject(objectType) {\n  const objectData = {\n    properties: {\n      model: 'Model 3',\n      make: 'Tesla',\n      year: '2024'\n    }\n  };\n\n  try {\n    const apiResponse = await hubspotClient.crm.objects.basicApi.create(\n      objectType,\n      objectData\n    );\n    console.log('Custom object created:', apiResponse.id);\n    return apiResponse;\n  } catch (error) {\n    console.error('Error creating custom object:', error.message);\n  }\n}\n```\n\n## Complete Example Application\n\nHere's a complete example that demonstrates multiple API operations:\n\n```javascript\nconst hubspot = require('@hubspot/api-client');\nrequire('dotenv').config();\n\nconst hubspotClient = new hubspot.Client({\n  accessToken: process.env.HUBSPOT_ACCESS_TOKEN\n});\n\nasync function main() {\n  try {\n    // Create a contact\n    console.log('Creating contact...');\n    const newContact = await hubspotClient.crm.contacts.basicApi.create({\n      properties: {\n        email: 'john.doe@example.com',\n        firstname: 'John',\n        lastname: 'Doe',\n        phone: '555-0100',\n        company: 'Example Corp'\n      }\n    });\n    console.log(`Contact created with ID: ${newContact.id}`);\n\n    // Create a company\n    console.log('\\nCreating company...');\n    const newCompany = await hubspotClient.crm.companies.basicApi.create({\n      properties: {\n        name: 'Example Corp',\n        domain: 'example.com',\n        city: 'San Francisco',\n        industry: 'Technology'\n      }\n    });\n    console.log(`Company created with ID: ${newCompany.id}`);\n\n    // Associate contact with company\n    console.log('\\nAssociating contact with company...');\n    await hubspotClient.crm.contacts.associationsApi.create(\n      newContact.id,\n      'companies',\n      newCompany.id,\n      'contact_to_company'\n    );\n    console.log('Association created successfully');\n\n    // Create a deal\n    console.log('\\nCreating deal...');\n    const newDeal = await hubspotClient.crm.deals.basicApi.create({\n      properties: {\n        dealname: 'Example Deal',\n        dealstage: 'appointmentscheduled',\n        amount: '10000',\n        closedate: '2025-12-31'\n      }\n    });\n    console.log(`Deal created with ID: ${newDeal.id}`);\n\n    // Associate deal with contact\n    console.log('\\nAssociating deal with contact...');\n    await hubspotClient.crm.deals.associationsApi.create(\n      newDeal.id,\n      'contacts',\n      newContact.id,\n      'deal_to_contact'\n    );\n    console.log('Deal associated with contact');\n\n    // Search for contacts\n    console.log('\\nSearching for leads...');\n    const searchResults = await hubspotClient.crm.contacts.searchApi.doSearch({\n      filterGroups: [\n        {\n          filters: [\n            {\n              propertyName: 'email',\n              operator: 'CONTAINS_TOKEN',\n              value: 'example.com'\n            }\n          ]\n        }\n      ],\n      properties: ['email', 'firstname', 'lastname', 'company'],\n      limit: 10\n    });\n    console.log(`Found ${searchResults.total} contacts`);\n\n    // List all owners\n    console.log('\\nFetching owners...');\n    const owners = await hubspotClient.crm.owners.ownersApi.getPage();\n    console.log(`Found ${owners.results.length} owners`);\n\n    console.log('\\nAll operations completed successfully!');\n  } catch (error) {\n    console.error('Error:', error.message);\n    if (error.body) {\n      console.error('Error details:', JSON.stringify(error.body, null, 2));\n    }\n  }\n}\n\nmain();\n```\n\n## TypeScript Support\n\nThe SDK includes full TypeScript definitions:\n\n```typescript\nimport { Client } from '@hubspot/api-client';\n\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_ACCESS_TOKEN\n});\n\ninterface ContactProperties {\n  email: string;\n  firstname: string;\n  lastname: string;\n  phone?: string;\n}\n\nasync function createContact(props: ContactProperties) {\n  const apiResponse = await hubspotClient.crm.contacts.basicApi.create({\n    properties: props\n  });\n  return apiResponse;\n}\n```\n\n## Environment Variables Template\n\n```bash\n# .env file\nHUBSPOT_ACCESS_TOKEN=your_private_app_access_token\nHUBSPOT_CLIENT_ID=your_client_id\nHUBSPOT_CLIENT_SECRET=your_client_secret\nREDIRECT_URI=https://yourapp.com/oauth-callback\n```\n\n## API Scopes\n\nWhen creating a private app or OAuth app, configure the following scopes based on your needs:\n\n**CRM:**\n- `crm.objects.contacts.read` / `crm.objects.contacts.write`\n- `crm.objects.companies.read` / `crm.objects.companies.write`\n- `crm.objects.deals.read` / `crm.objects.deals.write`\n- `crm.objects.owners.read`\n- `crm.schemas.contacts.read` / `crm.schemas.contacts.write`\n\n**Marketing:**\n- `forms` - Read and write forms\n- `content` - Read and write marketing emails\n\n**Automation:**\n- `automation` - Access to workflows\n\n**Timeline:**\n- `timeline` - Create timeline events\n\n## Migration from Legacy API Keys\n\nIf you're using legacy API keys (deprecated), migrate to private apps:\n\n**Old (Deprecated):**\n```javascript\n// DON'T USE THIS\nconst hapikey = 'your-api-key';\n```\n\n**New (Correct):**\n```javascript\nconst hubspotClient = new hubspot.Client({\n  accessToken: process.env.HUBSPOT_ACCESS_TOKEN\n});\n```\n\nLegacy API keys will be revoked on November 19, 2025.\n"
  },
  {
    "path": "content/hubspot/docs/crm/python/DOC.md",
    "content": "---\nname: crm\ndescription: \"HubSpot Python SDK for managing CRM contacts, companies, deals, and marketing automation via the HubSpot API.\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.0.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"hubspot,crm,marketing,contacts,automation\"\n---\n\n# HubSpot Python SDK Coding Guidelines\n\nYou are a HubSpot API coding expert. Help me write code using the HubSpot API with the official Python SDK.\n\nOfficial SDK documentation and code samples:\nhttps://developers.hubspot.com/docs/api/overview\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official HubSpot Python SDK (`hubspot-api-client`), which is the standard library for all HubSpot API interactions. Do not use deprecated or unofficial packages.\n\n- **Library Name:** HubSpot Python SDK\n- **PyPI Package:** `hubspot-api-client`\n- **Current Version:** 12.0.0\n- **Deprecated Packages:** `hubspot-python`, `hubspot3` (do not use these)\n\n**Installation:**\n\n- **Correct:** `pip install hubspot-api-client`\n- **Incorrect:** `pip install hubspot-python` or `pip install hubspot3`\n\n**APIs and Usage:**\n\n- **Correct:** `from hubspot import HubSpot`\n- **Correct:** `api_client = HubSpot(access_token=token)`\n- **Correct:** `api_client.crm.contacts.basic_api.create(...)`\n- **Incorrect:** `HubspotClient` or `HubspotAPI`\n- **Incorrect:** Legacy v2 API endpoints\n- **Incorrect:** Using `hapikey` (removed after v5.1.0)\n\n## Installation\n\nInstall the SDK via pip:\n\n```bash\npip install hubspot-api-client\n```\n\nThe SDK requires Python 3.9 or higher.\n\nFor development with additional dependencies:\n\n```bash\npip install hubspot-api-client[dev]\n```\n\n## Authentication\n\nHubSpot API uses access tokens for authentication. There are three types of access tokens:\n\n1. **Private App Access Tokens** (recommended for server-side integrations)\n2. **OAuth Access Tokens** (for public apps and integrations)\n3. **Legacy API Keys** (deprecated, will be revoked November 19, 2025)\n\n### Environment Variable Configuration\n\nSet your access token as an environment variable:\n\n```bash\n# .env file\nHUBSPOT_ACCESS_TOKEN=your_access_token_here\n```\n\n**Creating a Private App:**\n\n1. Navigate to Settings > Integrations > Private Apps in your HubSpot account\n2. Click \"Create private app\"\n3. Configure the required scopes (permissions)\n4. Click \"Create app\" and copy the access token\n\n## Initialization\n\n### Basic Initialization\n\n```python\nfrom hubspot import HubSpot\nimport os\n\n# Initialize with access token from environment variable\napi_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))\n```\n\n### Initialization with OAuth\n\n```python\nfrom hubspot import HubSpot\n\napi_client = HubSpot(access_token='YOUR_OAUTH_ACCESS_TOKEN')\n\n# Update token when refreshed\napi_client.access_token = 'NEW_ACCESS_TOKEN'\n```\n\n### Alternative Initialization Methods\n\n```python\nfrom hubspot import HubSpot\n\n# Option 1: Set token during initialization\napi_client = HubSpot(access_token='your_access_token')\n\n# Option 2: Set token after initialization\napi_client = HubSpot()\napi_client.access_token = 'your_access_token'\n\n# Option 3: Using Client.create method\nimport hubspot\napi_client = hubspot.Client.create(access_token='your_access_token')\n```\n\n## CRM API - Contacts\n\n### Create a Contact\n\n**Basic Example:**\n\n```python\nfrom hubspot import HubSpot\nfrom hubspot.crm.contacts import SimplePublicObjectInputForCreate, ApiException\nimport os\n\napi_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))\n\ndef create_contact():\n    properties = {\n        \"email\": \"example@company.com\",\n        \"firstname\": \"John\",\n        \"lastname\": \"Doe\",\n        \"phone\": \"555-0100\",\n        \"company\": \"Example Company\",\n        \"website\": \"example.com\"\n    }\n\n    simple_public_object_input_for_create = SimplePublicObjectInputForCreate(\n        properties=properties\n    )\n\n    try:\n        api_response = api_client.crm.contacts.basic_api.create(\n            simple_public_object_input_for_create=simple_public_object_input_for_create\n        )\n        print(f\"Contact created with ID: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating contact: {e}\")\n\ncreate_contact()\n```\n\n**Advanced Example with Custom Properties:**\n\n```python\nfrom hubspot.crm.contacts import SimplePublicObjectInputForCreate, ApiException\n\ndef create_contact_advanced():\n    properties = {\n        \"email\": \"jane@example.com\",\n        \"firstname\": \"Jane\",\n        \"lastname\": \"Smith\",\n        \"phone\": \"555-0200\",\n        \"company\": \"Tech Corp\",\n        \"jobtitle\": \"Software Engineer\",\n        \"lifecyclestage\": \"lead\",\n        \"hs_lead_status\": \"NEW\",\n        # Custom properties\n        \"custom_field\": \"custom_value\",\n        \"industry\": \"Technology\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)\n\n    try:\n        api_response = api_client.crm.contacts.basic_api.create(\n            simple_public_object_input_for_create=simple_public_object_input\n        )\n        print(f\"Contact created with ID: {api_response.id}\")\n        print(f\"Properties: {api_response.properties}\")\n        return api_response\n    except ApiException as e:\n        if e.status == 409:\n            print(\"Contact with this email already exists\")\n        else:\n            print(f\"Exception when creating contact: {e}\")\n\ncreate_contact_advanced()\n```\n\n### Get a Contact\n\n**By ID:**\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef get_contact(contact_id):\n    properties = [\"email\", \"firstname\", \"lastname\", \"phone\", \"company\"]\n\n    try:\n        api_response = api_client.crm.contacts.basic_api.get_by_id(\n            contact_id=contact_id,\n            properties=properties\n        )\n        print(f\"Contact: {api_response.properties}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching contact: {e}\")\n\nget_contact(\"12345\")\n```\n\n**By Email:**\n\n```python\nfrom hubspot.crm.contacts import PublicObjectSearchRequest, ApiException\n\ndef get_contact_by_email(email):\n    filter_obj = {\n        \"propertyName\": \"email\",\n        \"operator\": \"EQ\",\n        \"value\": email\n    }\n\n    filter_group = {\n        \"filters\": [filter_obj]\n    }\n\n    sort = {\n        \"propertyName\": \"createdate\",\n        \"direction\": \"DESCENDING\"\n    }\n\n    public_object_search_request = PublicObjectSearchRequest(\n        filter_groups=[filter_group],\n        sorts=[sort],\n        properties=[\"email\", \"firstname\", \"lastname\"],\n        limit=1\n    )\n\n    try:\n        api_response = api_client.crm.contacts.search_api.do_search(\n            public_object_search_request=public_object_search_request\n        )\n\n        if api_response.total > 0:\n            return api_response.results[0]\n        return None\n    except ApiException as e:\n        print(f\"Exception when searching contact: {e}\")\n\nget_contact_by_email(\"example@company.com\")\n```\n\n### Update a Contact\n\n```python\nfrom hubspot.crm.contacts import SimplePublicObjectInput, ApiException\n\ndef update_contact(contact_id):\n    properties = {\n        \"firstname\": \"Updated Name\",\n        \"phone\": \"555-9999\",\n        \"lifecyclestage\": \"opportunity\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInput(properties=properties)\n\n    try:\n        api_response = api_client.crm.contacts.basic_api.update(\n            contact_id=contact_id,\n            simple_public_object_input=simple_public_object_input\n        )\n        print(f\"Contact updated: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when updating contact: {e}\")\n\nupdate_contact(\"12345\")\n```\n\n### List Contacts\n\n**Basic Pagination:**\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef list_contacts():\n    limit = 10\n    properties = [\"email\", \"firstname\", \"lastname\", \"company\"]\n\n    try:\n        api_response = api_client.crm.contacts.basic_api.get_page(\n            limit=limit,\n            properties=properties\n        )\n\n        print(f\"Found {len(api_response.results)} contacts\")\n        for contact in api_response.results:\n            print(f\"{contact.properties.get('firstname')} {contact.properties.get('lastname')}\")\n\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when listing contacts: {e}\")\n\nlist_contacts()\n```\n\n**Get All Contacts (with pagination handling):**\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef get_all_contacts():\n    all_contacts = []\n    after = None\n    limit = 100\n    properties = [\"email\", \"firstname\", \"lastname\"]\n\n    try:\n        while True:\n            api_response = api_client.crm.contacts.basic_api.get_page(\n                limit=limit,\n                after=after,\n                properties=properties\n            )\n\n            all_contacts.extend(api_response.results)\n\n            if api_response.paging and api_response.paging.next:\n                after = api_response.paging.next.after\n            else:\n                break\n\n        print(f\"Total contacts retrieved: {len(all_contacts)}\")\n        return all_contacts\n    except ApiException as e:\n        print(f\"Exception when getting all contacts: {e}\")\n\nget_all_contacts()\n```\n\n**Using get_all method:**\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef get_all_contacts_simple():\n    try:\n        # The get_all method handles pagination automatically\n        all_contacts = api_client.crm.contacts.get_all()\n        print(f\"Total contacts: {len(all_contacts)}\")\n        return all_contacts\n    except ApiException as e:\n        print(f\"Exception when getting all contacts: {e}\")\n\nget_all_contacts_simple()\n```\n\n### Delete a Contact\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef delete_contact(contact_id):\n    try:\n        api_client.crm.contacts.basic_api.archive(contact_id=contact_id)\n        print(f\"Contact deleted: {contact_id}\")\n    except ApiException as e:\n        print(f\"Exception when deleting contact: {e}\")\n\ndelete_contact(\"12345\")\n```\n\n## CRM API - Companies\n\n### Create a Company\n\n```python\nfrom hubspot.crm.companies import SimplePublicObjectInputForCreate, ApiException\n\ndef create_company():\n    properties = {\n        \"name\": \"Example Company\",\n        \"domain\": \"example.com\",\n        \"city\": \"San Francisco\",\n        \"state\": \"California\",\n        \"industry\": \"Technology\",\n        \"phone\": \"555-0100\",\n        \"numberofemployees\": \"50\",\n        \"description\": \"A technology company\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)\n\n    try:\n        api_response = api_client.crm.companies.basic_api.create(\n            simple_public_object_input_for_create=simple_public_object_input\n        )\n        print(f\"Company created with ID: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating company: {e}\")\n\ncreate_company()\n```\n\n### Get a Company\n\n```python\nfrom hubspot.crm.companies import ApiException\n\ndef get_company(company_id):\n    properties = [\"name\", \"domain\", \"city\", \"industry\", \"phone\"]\n\n    try:\n        api_response = api_client.crm.companies.basic_api.get_by_id(\n            company_id=company_id,\n            properties=properties\n        )\n        print(f\"Company: {api_response.properties}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching company: {e}\")\n\nget_company(\"12345\")\n```\n\n### Update a Company\n\n```python\nfrom hubspot.crm.companies import SimplePublicObjectInput, ApiException\n\ndef update_company(company_id):\n    properties = {\n        \"name\": \"Updated Company Name\",\n        \"numberofemployees\": \"100\",\n        \"annualrevenue\": \"1000000\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInput(properties=properties)\n\n    try:\n        api_response = api_client.crm.companies.basic_api.update(\n            company_id=company_id,\n            simple_public_object_input=simple_public_object_input\n        )\n        print(f\"Company updated: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when updating company: {e}\")\n\nupdate_company(\"12345\")\n```\n\n### List Companies\n\n```python\nfrom hubspot.crm.companies import ApiException\n\ndef list_companies():\n    limit = 10\n    properties = [\"name\", \"domain\", \"city\", \"industry\"]\n\n    try:\n        api_response = api_client.crm.companies.basic_api.get_page(\n            limit=limit,\n            properties=properties\n        )\n\n        print(f\"Found {len(api_response.results)} companies\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when listing companies: {e}\")\n\nlist_companies()\n```\n\n## CRM API - Deals\n\n### Create a Deal\n\n```python\nfrom hubspot.crm.deals import SimplePublicObjectInputForCreate, ApiException\n\ndef create_deal():\n    properties = {\n        \"dealname\": \"New Deal\",\n        \"dealstage\": \"appointmentscheduled\",\n        \"amount\": \"10000\",\n        \"closedate\": \"2025-12-31\",\n        \"pipeline\": \"default\",\n        \"hubspot_owner_id\": \"12345\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)\n\n    try:\n        api_response = api_client.crm.deals.basic_api.create(\n            simple_public_object_input_for_create=simple_public_object_input\n        )\n        print(f\"Deal created with ID: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating deal: {e}\")\n\ncreate_deal()\n```\n\n### Get a Deal\n\n```python\nfrom hubspot.crm.deals import ApiException\n\ndef get_deal(deal_id):\n    properties = [\"dealname\", \"dealstage\", \"amount\", \"closedate\"]\n\n    try:\n        api_response = api_client.crm.deals.basic_api.get_by_id(\n            deal_id=deal_id,\n            properties=properties\n        )\n        print(f\"Deal: {api_response.properties}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching deal: {e}\")\n\nget_deal(\"12345\")\n```\n\n### Update a Deal\n\n```python\nfrom hubspot.crm.deals import SimplePublicObjectInput, ApiException\n\ndef update_deal(deal_id):\n    properties = {\n        \"dealstage\": \"closedwon\",\n        \"amount\": \"15000\",\n        \"closedate\": \"2025-11-30\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInput(properties=properties)\n\n    try:\n        api_response = api_client.crm.deals.basic_api.update(\n            deal_id=deal_id,\n            simple_public_object_input=simple_public_object_input\n        )\n        print(f\"Deal updated: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when updating deal: {e}\")\n\nupdate_deal(\"12345\")\n```\n\n### List Deals\n\n```python\nfrom hubspot.crm.deals import ApiException\n\ndef list_deals():\n    limit = 10\n    properties = [\"dealname\", \"dealstage\", \"amount\"]\n\n    try:\n        api_response = api_client.crm.deals.basic_api.get_page(\n            limit=limit,\n            properties=properties\n        )\n\n        print(f\"Found {len(api_response.results)} deals\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when listing deals: {e}\")\n\nlist_deals()\n```\n\n## CRM API - Tickets\n\n### Create a Ticket\n\n```python\nfrom hubspot.crm.tickets import SimplePublicObjectInputForCreate, ApiException\n\ndef create_ticket():\n    properties = {\n        \"subject\": \"Customer Support Request\",\n        \"content\": \"Customer needs help with product setup\",\n        \"hs_pipeline\": \"0\",\n        \"hs_pipeline_stage\": \"1\",\n        \"hs_ticket_priority\": \"HIGH\",\n        \"hubspot_owner_id\": \"12345\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)\n\n    try:\n        api_response = api_client.crm.tickets.basic_api.create(\n            simple_public_object_input_for_create=simple_public_object_input\n        )\n        print(f\"Ticket created with ID: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating ticket: {e}\")\n\ncreate_ticket()\n```\n\n### Get a Ticket\n\n```python\nfrom hubspot.crm.tickets import ApiException\n\ndef get_ticket(ticket_id):\n    properties = [\"subject\", \"content\", \"hs_pipeline_stage\", \"hs_ticket_priority\"]\n\n    try:\n        api_response = api_client.crm.tickets.basic_api.get_by_id(\n            ticket_id=ticket_id,\n            properties=properties\n        )\n        print(f\"Ticket: {api_response.properties}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching ticket: {e}\")\n\nget_ticket(\"12345\")\n```\n\n### Update a Ticket\n\n```python\nfrom hubspot.crm.tickets import SimplePublicObjectInput, ApiException\n\ndef update_ticket(ticket_id):\n    properties = {\n        \"hs_pipeline_stage\": \"4\",  # Closed\n        \"hs_ticket_priority\": \"LOW\"\n    }\n\n    simple_public_object_input = SimplePublicObjectInput(properties=properties)\n\n    try:\n        api_response = api_client.crm.tickets.basic_api.update(\n            ticket_id=ticket_id,\n            simple_public_object_input=simple_public_object_input\n        )\n        print(f\"Ticket updated: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when updating ticket: {e}\")\n\nupdate_ticket(\"12345\")\n```\n\n## CRM API - Associations\n\nAssociations link objects together (e.g., contacts to companies, deals to contacts).\n\n### Create Association\n\n**Associate Contact with Company:**\n\n```python\nfrom hubspot.crm.associations import ApiException\n\ndef associate_contact_with_company(contact_id, company_id):\n    try:\n        api_response = api_client.crm.contacts.associations_api.create(\n            contact_id=contact_id,\n            to_object_type=\"companies\",\n            to_object_id=company_id,\n            association_type=\"contact_to_company\"\n        )\n        print(\"Association created\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating association: {e}\")\n\nassociate_contact_with_company(\"12345\", \"67890\")\n```\n\n**Associate Deal with Contact:**\n\n```python\nfrom hubspot.crm.associations import ApiException\n\ndef associate_deal_with_contact(deal_id, contact_id):\n    try:\n        api_response = api_client.crm.deals.associations_api.create(\n            deal_id=deal_id,\n            to_object_type=\"contacts\",\n            to_object_id=contact_id,\n            association_type=\"deal_to_contact\"\n        )\n        print(\"Association created\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating association: {e}\")\n\nassociate_deal_with_contact(\"12345\", \"67890\")\n```\n\n### Get Associations\n\n```python\nfrom hubspot.crm.associations import ApiException\n\ndef get_contact_associations(contact_id):\n    try:\n        # Get associated companies\n        companies = api_client.crm.contacts.associations_api.get_all(\n            contact_id=contact_id,\n            to_object_type=\"companies\"\n        )\n\n        # Get associated deals\n        deals = api_client.crm.contacts.associations_api.get_all(\n            contact_id=contact_id,\n            to_object_type=\"deals\"\n        )\n\n        print(f\"Associated companies: {companies.results}\")\n        print(f\"Associated deals: {deals.results}\")\n\n        return {\"companies\": companies, \"deals\": deals}\n    except ApiException as e:\n        print(f\"Exception when fetching associations: {e}\")\n\nget_contact_associations(\"12345\")\n```\n\n### Remove Association\n\n```python\nfrom hubspot.crm.associations import ApiException\n\ndef remove_association(contact_id, company_id):\n    try:\n        api_client.crm.contacts.associations_api.archive(\n            contact_id=contact_id,\n            to_object_type=\"companies\",\n            to_object_id=company_id,\n            association_type=\"contact_to_company\"\n        )\n        print(\"Association removed\")\n    except ApiException as e:\n        print(f\"Exception when removing association: {e}\")\n\nremove_association(\"12345\", \"67890\")\n```\n\n## CRM API - Batch Operations\n\nBatch operations allow you to create, update, or read up to 100 records in a single API call.\n\n### Batch Create Contacts\n\n```python\nfrom hubspot.crm.contacts import BatchInputSimplePublicObjectInputForCreate, SimplePublicObjectInputForCreate, ApiException\n\ndef batch_create_contacts():\n    inputs = [\n        SimplePublicObjectInputForCreate(\n            properties={\n                \"email\": \"contact1@example.com\",\n                \"firstname\": \"Contact\",\n                \"lastname\": \"One\"\n            }\n        ),\n        SimplePublicObjectInputForCreate(\n            properties={\n                \"email\": \"contact2@example.com\",\n                \"firstname\": \"Contact\",\n                \"lastname\": \"Two\"\n            }\n        ),\n        SimplePublicObjectInputForCreate(\n            properties={\n                \"email\": \"contact3@example.com\",\n                \"firstname\": \"Contact\",\n                \"lastname\": \"Three\"\n            }\n        )\n    ]\n\n    batch_input = BatchInputSimplePublicObjectInputForCreate(inputs=inputs)\n\n    try:\n        api_response = api_client.crm.contacts.batch_api.create(\n            batch_input_simple_public_object_input_for_create=batch_input\n        )\n        print(f\"Created {len(api_response.results)} contacts\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when batch creating contacts: {e}\")\n\nbatch_create_contacts()\n```\n\n### Batch Update Contacts\n\n```python\nfrom hubspot.crm.contacts import BatchInputSimplePublicObjectBatchInput, SimplePublicObjectBatchInput, ApiException\n\ndef batch_update_contacts(contact_ids):\n    inputs = []\n    for contact_id in contact_ids:\n        inputs.append(\n            SimplePublicObjectBatchInput(\n                id=contact_id,\n                properties={\n                    \"lifecyclestage\": \"customer\",\n                    \"hs_lead_status\": \"CONNECTED\"\n                }\n            )\n        )\n\n    batch_input = BatchInputSimplePublicObjectBatchInput(inputs=inputs)\n\n    try:\n        api_response = api_client.crm.contacts.batch_api.update(\n            batch_input_simple_public_object_batch_input=batch_input\n        )\n        print(f\"Updated {len(api_response.results)} contacts\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when batch updating contacts: {e}\")\n\nbatch_update_contacts([\"12345\", \"67890\", \"11111\"])\n```\n\n### Batch Read Contacts\n\n```python\nfrom hubspot.crm.contacts import BatchReadInputSimplePublicObjectId, SimplePublicObjectId, ApiException\n\ndef batch_read_contacts(contact_ids):\n    inputs = [SimplePublicObjectId(id=contact_id) for contact_id in contact_ids]\n\n    batch_input = BatchReadInputSimplePublicObjectId(\n        properties=[\"email\", \"firstname\", \"lastname\", \"phone\"],\n        inputs=inputs\n    )\n\n    try:\n        api_response = api_client.crm.contacts.batch_api.read(\n            batch_read_input_simple_public_object_id=batch_input\n        )\n        print(f\"Retrieved {len(api_response.results)} contacts\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when batch reading contacts: {e}\")\n\nbatch_read_contacts([\"12345\", \"67890\", \"11111\"])\n```\n\n### Batch Upsert Contacts\n\n```python\nfrom hubspot.crm.contacts import BatchInputSimplePublicObjectInputForCreate, SimplePublicObjectInputForCreate, ApiException\n\ndef batch_upsert_contacts():\n    inputs = [\n        SimplePublicObjectInputForCreate(\n            properties={\n                \"email\": \"existing@example.com\",\n                \"firstname\": \"Updated\",\n                \"lastname\": \"Name\"\n            },\n            id_property=\"email\"\n        ),\n        SimplePublicObjectInputForCreate(\n            properties={\n                \"email\": \"new@example.com\",\n                \"firstname\": \"New\",\n                \"lastname\": \"Contact\"\n            },\n            id_property=\"email\"\n        )\n    ]\n\n    batch_input = BatchInputSimplePublicObjectInputForCreate(inputs=inputs)\n\n    try:\n        api_response = api_client.crm.contacts.batch_api.upsert(\n            batch_input_simple_public_object_input_for_create=batch_input\n        )\n        print(f\"Upserted {len(api_response.results)} contacts\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when batch upserting contacts: {e}\")\n\nbatch_upsert_contacts()\n```\n\n## CRM API - Search\n\nThe Search API allows you to filter, sort, and search across CRM objects.\n\n### Basic Search\n\n```python\nfrom hubspot.crm.contacts import PublicObjectSearchRequest, ApiException\n\ndef search_contacts():\n    filter_obj = {\n        \"propertyName\": \"lifecyclestage\",\n        \"operator\": \"EQ\",\n        \"value\": \"lead\"\n    }\n\n    filter_group = {\n        \"filters\": [filter_obj]\n    }\n\n    public_object_search_request = PublicObjectSearchRequest(\n        filter_groups=[filter_group],\n        properties=[\"email\", \"firstname\", \"lastname\", \"lifecyclestage\"],\n        limit=10\n    )\n\n    try:\n        api_response = api_client.crm.contacts.search_api.do_search(\n            public_object_search_request=public_object_search_request\n        )\n        print(f\"Found {api_response.total} contacts\")\n        print(f\"Returned {len(api_response.results)} results\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when searching contacts: {e}\")\n\nsearch_contacts()\n```\n\n### Advanced Search with Multiple Filters\n\n```python\nfrom hubspot.crm.contacts import PublicObjectSearchRequest, ApiException\n\ndef advanced_search_contacts():\n    filter_group = {\n        \"filters\": [\n            {\n                \"propertyName\": \"lifecyclestage\",\n                \"operator\": \"EQ\",\n                \"value\": \"lead\"\n            },\n            {\n                \"propertyName\": \"createdate\",\n                \"operator\": \"GTE\",\n                \"value\": \"2025-01-01\"\n            }\n        ]\n    }\n\n    sort = {\n        \"propertyName\": \"createdate\",\n        \"direction\": \"DESCENDING\"\n    }\n\n    public_object_search_request = PublicObjectSearchRequest(\n        filter_groups=[filter_group],\n        sorts=[sort],\n        properties=[\"email\", \"firstname\", \"lastname\", \"createdate\", \"lifecyclestage\"],\n        limit=100,\n        after=0\n    )\n\n    try:\n        api_response = api_client.crm.contacts.search_api.do_search(\n            public_object_search_request=public_object_search_request\n        )\n        print(f\"Found {api_response.total} matching contacts\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when searching contacts: {e}\")\n\nadvanced_search_contacts()\n```\n\n### Search with Association Filters\n\n```python\nfrom hubspot.crm.contacts import PublicObjectSearchRequest, ApiException\n\ndef search_contacts_by_company(company_id):\n    filter_obj = {\n        \"propertyName\": \"associations.company\",\n        \"operator\": \"EQ\",\n        \"value\": company_id\n    }\n\n    filter_group = {\n        \"filters\": [filter_obj]\n    }\n\n    public_object_search_request = PublicObjectSearchRequest(\n        filter_groups=[filter_group],\n        properties=[\"email\", \"firstname\", \"lastname\"],\n        limit=100\n    )\n\n    try:\n        api_response = api_client.crm.contacts.search_api.do_search(\n            public_object_search_request=public_object_search_request\n        )\n        print(f\"Found {len(api_response.results)} contacts for company\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when searching contacts by company: {e}\")\n\nsearch_contacts_by_company(\"12345\")\n```\n\n### Search Operators\n\nAvailable operators for search filters:\n\n- `EQ` - Equal to\n- `NEQ` - Not equal to\n- `LT` - Less than\n- `LTE` - Less than or equal to\n- `GT` - Greater than\n- `GTE` - Greater than or equal to\n- `IN` - In list of values\n- `NOT_IN` - Not in list of values\n- `HAS_PROPERTY` - Has property value set\n- `NOT_HAS_PROPERTY` - Does not have property value set\n- `CONTAINS_TOKEN` - Contains token (for text)\n- `NOT_CONTAINS_TOKEN` - Does not contain token\n\n## CRM API - Properties\n\n### Get All Contact Properties\n\n```python\nfrom hubspot.crm.properties import ApiException\n\ndef get_all_contact_properties():\n    try:\n        api_response = api_client.crm.properties.core_api.get_all(\n            object_type=\"contacts\"\n        )\n        print(f\"Found {len(api_response.results)} contact properties\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching contact properties: {e}\")\n\nget_all_contact_properties()\n```\n\n### Create Custom Property\n\n```python\nfrom hubspot.crm.properties import PropertyCreate, ApiException\n\ndef create_custom_property():\n    property_create = PropertyCreate(\n        name=\"favorite_color\",\n        label=\"Favorite Color\",\n        type=\"string\",\n        field_type=\"text\",\n        group_name=\"contactinformation\",\n        description=\"The contact's favorite color\"\n    )\n\n    try:\n        api_response = api_client.crm.properties.core_api.create(\n            object_type=\"contacts\",\n            property_create=property_create\n        )\n        print(f\"Custom property created: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating custom property: {e}\")\n\ncreate_custom_property()\n```\n\n### Create Dropdown Property\n\n```python\nfrom hubspot.crm.properties import PropertyCreate, OptionInput, ApiException\n\ndef create_dropdown_property():\n    options = [\n        OptionInput(label=\"Bronze\", value=\"bronze\", display_order=0),\n        OptionInput(label=\"Silver\", value=\"silver\", display_order=1),\n        OptionInput(label=\"Gold\", value=\"gold\", display_order=2),\n        OptionInput(label=\"Platinum\", value=\"platinum\", display_order=3)\n    ]\n\n    property_create = PropertyCreate(\n        name=\"customer_tier\",\n        label=\"Customer Tier\",\n        type=\"enumeration\",\n        field_type=\"select\",\n        group_name=\"contactinformation\",\n        options=options\n    )\n\n    try:\n        api_response = api_client.crm.properties.core_api.create(\n            object_type=\"contacts\",\n            property_create=property_create\n        )\n        print(f\"Dropdown property created: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating dropdown property: {e}\")\n\ncreate_dropdown_property()\n```\n\n### Update Property\n\n```python\nfrom hubspot.crm.properties import PropertyUpdate, ApiException\n\ndef update_property(property_name):\n    property_update = PropertyUpdate(\n        label=\"Updated Label\",\n        description=\"Updated description\"\n    )\n\n    try:\n        api_response = api_client.crm.properties.core_api.update(\n            object_type=\"contacts\",\n            property_name=property_name,\n            property_update=property_update\n        )\n        print(f\"Property updated: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when updating property: {e}\")\n\nupdate_property(\"favorite_color\")\n```\n\n## Marketing API - Emails\n\n### Get All Marketing Emails\n\n```python\nfrom hubspot.marketing.emails import ApiException\n\ndef get_marketing_emails():\n    try:\n        api_response = api_client.marketing.emails.emails_api.get_page()\n        print(f\"Found {len(api_response.results)} marketing emails\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching marketing emails: {e}\")\n\nget_marketing_emails()\n```\n\n### Get Email by ID\n\n```python\nfrom hubspot.marketing.emails import ApiException\n\ndef get_marketing_email(email_id):\n    try:\n        api_response = api_client.marketing.emails.emails_api.get_by_id(\n            email_id=email_id\n        )\n        print(f\"Email: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching marketing email: {e}\")\n\nget_marketing_email(\"12345\")\n```\n\n## Marketing API - Forms\n\n### Get All Forms\n\n```python\nfrom hubspot.marketing.forms import ApiException\n\ndef get_all_forms():\n    try:\n        api_response = api_client.marketing.forms.forms_api.get_page()\n        print(f\"Found {len(api_response.results)} forms\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching forms: {e}\")\n\nget_all_forms()\n```\n\n### Get Form by ID\n\n```python\nfrom hubspot.marketing.forms import ApiException\n\ndef get_form(form_id):\n    try:\n        api_response = api_client.marketing.forms.forms_api.get_by_id(\n            form_id=form_id\n        )\n        print(f\"Form: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching form: {e}\")\n\nget_form(\"12345\")\n```\n\n### Submit Form Data\n\n```python\nimport requests\n\ndef submit_form_data(form_guid, portal_id):\n    form_data = {\n        \"fields\": [\n            {\n                \"name\": \"email\",\n                \"value\": \"test@example.com\"\n            },\n            {\n                \"name\": \"firstname\",\n                \"value\": \"John\"\n            },\n            {\n                \"name\": \"lastname\",\n                \"value\": \"Doe\"\n            }\n        ],\n        \"context\": {\n            \"pageUri\": \"https://example.com/contact\",\n            \"pageName\": \"Contact Us\"\n        }\n    }\n\n    try:\n        response = requests.post(\n            f\"https://api.hsforms.com/submissions/v3/integration/submit/{portal_id}/{form_guid}\",\n            json=form_data\n        )\n        response.raise_for_status()\n        print(\"Form submitted successfully\")\n        return response.json()\n    except requests.exceptions.RequestException as e:\n        print(f\"Error submitting form: {e}\")\n\nsubmit_form_data(\"form-guid-here\", \"12345\")\n```\n\n## Events API - Timeline Events\n\n### Create Timeline Event\n\n```python\nimport requests\nimport os\n\ndef create_timeline_event(event_type_id, object_id):\n    event_data = {\n        \"eventTypeId\": event_type_id,\n        \"objectId\": object_id,\n        \"extraData\": {\n            \"eventTitle\": \"Purchase Completed\",\n            \"eventDescription\": \"Customer completed a purchase of $99.99\"\n        },\n        \"timestamp\": \"2025-11-07T12:00:00Z\"\n    }\n\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\",\n        \"Content-Type\": \"application/json\"\n    }\n\n    try:\n        response = requests.post(\n            \"https://api.hubapi.com/crm/v3/timeline/events\",\n            json=event_data,\n            headers=headers\n        )\n        response.raise_for_status()\n        print(f\"Timeline event created: {response.json()['id']}\")\n        return response.json()\n    except requests.exceptions.RequestException as e:\n        print(f\"Error creating timeline event: {e}\")\n\ncreate_timeline_event(\"event_type_id_here\", \"12345\")\n```\n\n## Automation API - Workflows\n\n### Get All Workflows\n\n```python\nimport requests\nimport os\n\ndef get_all_workflows():\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\"\n    }\n\n    try:\n        response = requests.get(\n            \"https://api.hubapi.com/automation/v3/workflows\",\n            headers=headers\n        )\n        response.raise_for_status()\n        workflows = response.json()['workflows']\n        print(f\"Found {len(workflows)} workflows\")\n        return workflows\n    except requests.exceptions.RequestException as e:\n        print(f\"Error fetching workflows: {e}\")\n\nget_all_workflows()\n```\n\n### Get Workflow by ID\n\n```python\nimport requests\nimport os\n\ndef get_workflow(workflow_id):\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\"\n    }\n\n    try:\n        response = requests.get(\n            f\"https://api.hubapi.com/automation/v3/workflows/{workflow_id}\",\n            headers=headers\n        )\n        response.raise_for_status()\n        workflow = response.json()\n        print(f\"Workflow: {workflow['name']}\")\n        return workflow\n    except requests.exceptions.RequestException as e:\n        print(f\"Error fetching workflow: {e}\")\n\nget_workflow(\"12345\")\n```\n\n### Enroll Contact in Workflow\n\n```python\nimport requests\nimport os\n\ndef enroll_contact_in_workflow(workflow_id, contact_email):\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\",\n        \"Content-Type\": \"application/json\"\n    }\n\n    try:\n        response = requests.post(\n            f\"https://api.hubapi.com/automation/v2/workflows/{workflow_id}/enrollments/contacts/{contact_email}\",\n            headers=headers,\n            json={}\n        )\n        response.raise_for_status()\n        print(\"Contact enrolled in workflow\")\n        return response.json()\n    except requests.exceptions.RequestException as e:\n        print(f\"Error enrolling contact in workflow: {e}\")\n\nenroll_contact_in_workflow(\"12345\", \"contact@example.com\")\n```\n\n## Webhooks API\n\n### Create Webhook Subscription\n\n```python\nfrom hubspot.webhooks import SubscriptionCreateRequest, ApiException\n\ndef create_webhook_subscription(app_id):\n    subscription_create = SubscriptionCreateRequest(\n        event_type=\"contact.creation\",\n        active=True\n    )\n\n    try:\n        api_response = api_client.webhooks.subscriptions_api.create(\n            app_id=app_id,\n            subscription_create_request=subscription_create\n        )\n        print(f\"Webhook subscription created: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating webhook subscription: {e}\")\n\ncreate_webhook_subscription(12345)\n```\n\n### Get All Webhook Subscriptions\n\n```python\nfrom hubspot.webhooks import ApiException\n\ndef get_webhook_subscriptions(app_id):\n    try:\n        api_response = api_client.webhooks.subscriptions_api.get_all(\n            app_id=app_id\n        )\n        print(f\"Found {len(api_response.results)} webhook subscriptions\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching webhook subscriptions: {e}\")\n\nget_webhook_subscriptions(12345)\n```\n\n### Delete Webhook Subscription\n\n```python\nfrom hubspot.webhooks import ApiException\n\ndef delete_webhook_subscription(app_id, subscription_id):\n    try:\n        api_client.webhooks.subscriptions_api.archive(\n            subscription_id=subscription_id,\n            app_id=app_id\n        )\n        print(\"Webhook subscription deleted\")\n    except ApiException as e:\n        print(f\"Exception when deleting webhook subscription: {e}\")\n\ndelete_webhook_subscription(12345, 67890)\n```\n\n## Lists API\n\n### Get All Lists\n\n```python\nimport requests\nimport os\n\ndef get_all_lists():\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\"\n    }\n\n    params = {\n        \"count\": 100,\n        \"offset\": 0\n    }\n\n    try:\n        response = requests.get(\n            \"https://api.hubapi.com/contacts/v1/lists\",\n            headers=headers,\n            params=params\n        )\n        response.raise_for_status()\n        lists = response.json()['lists']\n        print(f\"Found {len(lists)} lists\")\n        return lists\n    except requests.exceptions.RequestException as e:\n        print(f\"Error fetching lists: {e}\")\n\nget_all_lists()\n```\n\n### Add Contact to List\n\n```python\nimport requests\nimport os\n\ndef add_contact_to_list(list_id, contact_id):\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\",\n        \"Content-Type\": \"application/json\"\n    }\n\n    data = {\n        \"vids\": [contact_id]\n    }\n\n    try:\n        response = requests.post(\n            f\"https://api.hubapi.com/contacts/v1/lists/{list_id}/add\",\n            headers=headers,\n            json=data\n        )\n        response.raise_for_status()\n        print(\"Contact added to list\")\n        return response.json()\n    except requests.exceptions.RequestException as e:\n        print(f\"Error adding contact to list: {e}\")\n\nadd_contact_to_list(123, 456)\n```\n\n### Remove Contact from List\n\n```python\nimport requests\nimport os\n\ndef remove_contact_from_list(list_id, contact_id):\n    headers = {\n        \"Authorization\": f\"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}\",\n        \"Content-Type\": \"application/json\"\n    }\n\n    data = {\n        \"vids\": [contact_id]\n    }\n\n    try:\n        response = requests.post(\n            f\"https://api.hubapi.com/contacts/v1/lists/{list_id}/remove\",\n            headers=headers,\n            json=data\n        )\n        response.raise_for_status()\n        print(\"Contact removed from list\")\n        return response.json()\n    except requests.exceptions.RequestException as e:\n        print(f\"Error removing contact from list: {e}\")\n\nremove_contact_from_list(123, 456)\n```\n\n## Owners API\n\n### Get All Owners\n\n```python\nfrom hubspot.crm.owners import ApiException\n\ndef get_all_owners():\n    try:\n        api_response = api_client.crm.owners.owners_api.get_page()\n        print(f\"Found {len(api_response.results)} owners\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching owners: {e}\")\n\nget_all_owners()\n```\n\n### Get Owner by ID\n\n```python\nfrom hubspot.crm.owners import ApiException\n\ndef get_owner(owner_id):\n    try:\n        api_response = api_client.crm.owners.owners_api.get_by_id(\n            owner_id=owner_id\n        )\n        print(f\"Owner: {api_response.email}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when fetching owner: {e}\")\n\nget_owner(\"12345\")\n```\n\n## Error Handling\n\n### Comprehensive Error Handling\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef handle_api_call():\n    try:\n        api_response = api_client.crm.contacts.basic_api.get_by_id(\n            contact_id=\"12345\"\n        )\n        return api_response\n    except ApiException as e:\n        if e.status == 401:\n            print(\"Authentication failed - check your access token\")\n        elif e.status == 404:\n            print(\"Resource not found\")\n        elif e.status == 409:\n            print(\"Conflict - resource already exists\")\n        elif e.status == 429:\n            print(\"Rate limit exceeded - wait before retrying\")\n        elif e.status >= 500:\n            print(\"HubSpot server error - try again later\")\n        else:\n            print(f\"API error: {e}\")\n        raise\n\nhandle_api_call()\n```\n\n### Retry Logic\n\n```python\nimport time\nfrom hubspot.crm.contacts import ApiException\n\ndef api_call_with_retry(api_call, max_retries=3):\n    for attempt in range(1, max_retries + 1):\n        try:\n            return api_call()\n        except ApiException as e:\n            if e.status == 429 and attempt < max_retries:\n                retry_after = int(e.headers.get('Retry-After', 1))\n                print(f\"Rate limited. Retrying after {retry_after} seconds...\")\n                time.sleep(retry_after)\n            else:\n                raise\n\n# Usage\nresult = api_call_with_retry(\n    lambda: api_client.crm.contacts.basic_api.get_by_id(contact_id=\"12345\")\n)\n```\n\n## Rate Limits\n\nHubSpot API has the following rate limits:\n\n- **Private Apps:** 100 requests per 10 seconds per account\n- **OAuth Apps:** 100 requests per 10 seconds per app per account\n- **Search API:** 5 requests per second, 1000 requests per day (per account)\n- **Batch API:** 100 objects per request, same rate limits as standard endpoints\n\nMonitor rate limit headers in responses:\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef check_rate_limits():\n    try:\n        api_response = api_client.crm.contacts.basic_api.get_page(limit=1)\n\n        # Rate limit information is in the response headers\n        # These are typically accessed via the underlying HTTP client\n        print(\"Request successful\")\n        return api_response\n    except ApiException as e:\n        if e.status == 429:\n            print(\"Rate limit exceeded\")\n            print(f\"Retry after: {e.headers.get('Retry-After')} seconds\")\n\ncheck_rate_limits()\n```\n\n## Pagination\n\nMost list endpoints return paginated results. Use the `after` parameter for pagination:\n\n```python\nfrom hubspot.crm.contacts import ApiException\n\ndef paginate_through_contacts():\n    after = None\n    all_contacts = []\n\n    while True:\n        try:\n            api_response = api_client.crm.contacts.basic_api.get_page(\n                limit=100,\n                after=after,\n                properties=[\"email\", \"firstname\", \"lastname\"]\n            )\n\n            all_contacts.extend(api_response.results)\n\n            if api_response.paging and api_response.paging.next:\n                after = api_response.paging.next.after\n            else:\n                break\n        except ApiException as e:\n            print(f\"Exception during pagination: {e}\")\n            break\n\n    return all_contacts\n\nall_contacts = paginate_through_contacts()\nprint(f\"Total contacts: {len(all_contacts)}\")\n```\n\n## OAuth Implementation\n\n### Initialize OAuth Provider\n\n```python\nfrom hubspot import HubSpot\nimport os\n\napi_client = HubSpot(\n    access_token=None,  # Will be set after OAuth flow\n    client_id=os.getenv('HUBSPOT_CLIENT_ID'),\n    client_secret=os.getenv('HUBSPOT_CLIENT_SECRET'),\n    redirect_uri='https://yourapp.com/oauth-callback'\n)\n```\n\n### Get Authorization URL\n\n```python\nimport os\n\ndef get_authorization_url():\n    scopes = ['contacts', 'crm.objects.contacts.read']\n\n    auth_url = (\n        f\"https://app.hubspot.com/oauth/authorize\"\n        f\"?client_id={os.getenv('HUBSPOT_CLIENT_ID')}\"\n        f\"&redirect_uri={os.getenv('REDIRECT_URI')}\"\n        f\"&scope={' '.join(scopes)}\"\n    )\n\n    return auth_url\n\nprint(get_authorization_url())\n```\n\n### Exchange Authorization Code for Tokens\n\n```python\nfrom hubspot.auth.oauth import ApiException\n\ndef get_tokens(authorization_code):\n    try:\n        token_response = api_client.auth.oauth.tokens_api.create(\n            grant_type='authorization_code',\n            code=authorization_code,\n            redirect_uri=os.getenv('REDIRECT_URI'),\n            client_id=os.getenv('HUBSPOT_CLIENT_ID'),\n            client_secret=os.getenv('HUBSPOT_CLIENT_SECRET')\n        )\n\n        return {\n            \"access_token\": token_response.access_token,\n            \"refresh_token\": token_response.refresh_token,\n            \"expires_in\": token_response.expires_in\n        }\n    except ApiException as e:\n        print(f\"Error exchanging code for tokens: {e}\")\n\ntokens = get_tokens(\"authorization_code_here\")\n```\n\n### Refresh Access Token\n\n```python\nfrom hubspot.auth.oauth import ApiException\nimport os\n\ndef refresh_access_token(refresh_token):\n    try:\n        token_response = api_client.auth.oauth.tokens_api.create(\n            grant_type='refresh_token',\n            redirect_uri=None,\n            refresh_token=refresh_token,\n            client_id=os.getenv('HUBSPOT_CLIENT_ID'),\n            client_secret=os.getenv('HUBSPOT_CLIENT_SECRET')\n        )\n\n        return {\n            \"access_token\": token_response.access_token,\n            \"refresh_token\": token_response.refresh_token,\n            \"expires_in\": token_response.expires_in\n        }\n    except ApiException as e:\n        print(f\"Error refreshing token: {e}\")\n\nnew_tokens = refresh_access_token(\"refresh_token_here\")\n```\n\n## Custom Objects\n\n### Create Custom Object Schema\n\n```python\nfrom hubspot.crm.schemas import ObjectSchemaEgg, ObjectTypePropertyCreate, ApiException\n\ndef create_custom_object_schema():\n    properties = [\n        ObjectTypePropertyCreate(\n            name=\"model\",\n            label=\"Model\",\n            type=\"string\",\n            field_type=\"text\"\n        ),\n        ObjectTypePropertyCreate(\n            name=\"make\",\n            label=\"Make\",\n            type=\"string\",\n            field_type=\"text\"\n        ),\n        ObjectTypePropertyCreate(\n            name=\"year\",\n            label=\"Year\",\n            type=\"number\",\n            field_type=\"number\"\n        )\n    ]\n\n    schema_egg = ObjectSchemaEgg(\n        name=\"cars\",\n        labels={\n            \"singular\": \"Car\",\n            \"plural\": \"Cars\"\n        },\n        primary_display_property=\"model\",\n        required_properties=[\"model\", \"make\"],\n        searchable_properties=[\"model\", \"make\", \"year\"],\n        properties=properties\n    )\n\n    try:\n        api_response = api_client.crm.schemas.core_api.create(\n            object_schema_egg=schema_egg\n        )\n        print(f\"Custom object schema created: {api_response.name}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating custom object schema: {e}\")\n\ncreate_custom_object_schema()\n```\n\n### Create Custom Object Instance\n\n```python\nfrom hubspot.crm.objects import SimplePublicObjectInputForCreate, ApiException\n\ndef create_custom_object(object_type):\n    object_data = SimplePublicObjectInputForCreate(\n        properties={\n            \"model\": \"Model 3\",\n            \"make\": \"Tesla\",\n            \"year\": \"2024\"\n        }\n    )\n\n    try:\n        api_response = api_client.crm.objects.basic_api.create(\n            object_type=object_type,\n            simple_public_object_input_for_create=object_data\n        )\n        print(f\"Custom object created: {api_response.id}\")\n        return api_response\n    except ApiException as e:\n        print(f\"Exception when creating custom object: {e}\")\n\ncreate_custom_object(\"cars\")\n```\n\n## Complete Example Application\n\nHere's a complete example that demonstrates multiple API operations:\n\n```python\nfrom hubspot import HubSpot\nfrom hubspot.crm.contacts import SimplePublicObjectInputForCreate, PublicObjectSearchRequest\nfrom hubspot.crm.companies import SimplePublicObjectInputForCreate as CompanyInput\nfrom hubspot.crm.deals import SimplePublicObjectInputForCreate as DealInput\nfrom hubspot.crm.contacts import ApiException\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\napi_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))\n\ndef main():\n    try:\n        # Create a contact\n        print(\"Creating contact...\")\n        new_contact = api_client.crm.contacts.basic_api.create(\n            simple_public_object_input_for_create=SimplePublicObjectInputForCreate(\n                properties={\n                    \"email\": \"john.doe@example.com\",\n                    \"firstname\": \"John\",\n                    \"lastname\": \"Doe\",\n                    \"phone\": \"555-0100\",\n                    \"company\": \"Example Corp\"\n                }\n            )\n        )\n        print(f\"Contact created with ID: {new_contact.id}\")\n\n        # Create a company\n        print(\"\\nCreating company...\")\n        new_company = api_client.crm.companies.basic_api.create(\n            simple_public_object_input_for_create=CompanyInput(\n                properties={\n                    \"name\": \"Example Corp\",\n                    \"domain\": \"example.com\",\n                    \"city\": \"San Francisco\",\n                    \"industry\": \"Technology\"\n                }\n            )\n        )\n        print(f\"Company created with ID: {new_company.id}\")\n\n        # Associate contact with company\n        print(\"\\nAssociating contact with company...\")\n        api_client.crm.contacts.associations_api.create(\n            contact_id=new_contact.id,\n            to_object_type=\"companies\",\n            to_object_id=new_company.id,\n            association_type=\"contact_to_company\"\n        )\n        print(\"Association created successfully\")\n\n        # Create a deal\n        print(\"\\nCreating deal...\")\n        new_deal = api_client.crm.deals.basic_api.create(\n            simple_public_object_input_for_create=DealInput(\n                properties={\n                    \"dealname\": \"Example Deal\",\n                    \"dealstage\": \"appointmentscheduled\",\n                    \"amount\": \"10000\",\n                    \"closedate\": \"2025-12-31\"\n                }\n            )\n        )\n        print(f\"Deal created with ID: {new_deal.id}\")\n\n        # Associate deal with contact\n        print(\"\\nAssociating deal with contact...\")\n        api_client.crm.deals.associations_api.create(\n            deal_id=new_deal.id,\n            to_object_type=\"contacts\",\n            to_object_id=new_contact.id,\n            association_type=\"deal_to_contact\"\n        )\n        print(\"Deal associated with contact\")\n\n        # Search for contacts\n        print(\"\\nSearching for leads...\")\n        search_results = api_client.crm.contacts.search_api.do_search(\n            public_object_search_request=PublicObjectSearchRequest(\n                filter_groups=[\n                    {\n                        \"filters\": [\n                            {\n                                \"propertyName\": \"email\",\n                                \"operator\": \"CONTAINS_TOKEN\",\n                                \"value\": \"example.com\"\n                            }\n                        ]\n                    }\n                ],\n                properties=[\"email\", \"firstname\", \"lastname\", \"company\"],\n                limit=10\n            )\n        )\n        print(f\"Found {search_results.total} contacts\")\n\n        # List all owners\n        print(\"\\nFetching owners...\")\n        owners = api_client.crm.owners.owners_api.get_page()\n        print(f\"Found {len(owners.results)} owners\")\n\n        print(\"\\nAll operations completed successfully!\")\n\n    except ApiException as e:\n        print(f\"Error: {e}\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## Environment Variables Template\n\n```bash\n# .env file\nHUBSPOT_ACCESS_TOKEN=your_private_app_access_token\nHUBSPOT_CLIENT_ID=your_client_id\nHUBSPOT_CLIENT_SECRET=your_client_secret\nREDIRECT_URI=https://yourapp.com/oauth-callback\n```\n\n## API Scopes\n\nWhen creating a private app or OAuth app, configure the following scopes based on your needs:\n\n**CRM:**\n- `crm.objects.contacts.read` / `crm.objects.contacts.write`\n- `crm.objects.companies.read` / `crm.objects.companies.write`\n- `crm.objects.deals.read` / `crm.objects.deals.write`\n- `crm.objects.owners.read`\n- `crm.schemas.contacts.read` / `crm.schemas.contacts.write`\n\n**Marketing:**\n- `forms` - Read and write forms\n- `content` - Read and write marketing emails\n\n**Automation:**\n- `automation` - Access to workflows\n\n**Timeline:**\n- `timeline` - Create timeline events\n\n## Migration from Legacy API Keys\n\nIf you're using legacy API keys (deprecated), migrate to private apps:\n\n**Old (Deprecated):**\n```python\n# DON'T USE THIS - hapikey is no longer supported\napi_client = HubSpot(api_key='your-api-key')  # Removed after v5.1.0\n```\n\n**New (Correct):**\n```python\napi_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))\n```\n\nLegacy API keys will be revoked on November 19, 2025.\n"
  },
  {
    "path": "content/huey/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Huey Python task queue guide for background jobs, scheduling, retries, and Django integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"huey,python,task-queue,background-jobs,scheduling,redis,django\"\n---\n\n# Huey Python Package Guide\n\n## Golden Rule\n\nUse one shared `Huey` instance per queue, make sure the consumer imports every decorated task before it starts working, and run a real consumer process outside tests. Most production deployments should use a Redis-backed queue; the main \"configuration\" surface in Huey is backend and consumer setup, not application-level auth.\n\n## Install\n\nCore install:\n\n```bash\npython -m pip install \"huey==2.6.0\"\n```\n\nIf you are using Redis, install the backend extra so the Redis client dependency is present:\n\n```bash\npython -m pip install \"huey[backends]==2.6.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"huey==2.6.0\"\npoetry add \"huey==2.6.0\"\n```\n\nNotes:\n\n- `RedisHuey` is the default recommendation for real async workloads.\n- `SqliteHuey` is simpler operationally and can be good for smaller single-host deployments.\n- `FileHuey` and `MemoryHuey` are mainly useful for local development and tests.\n\n## Initialize A Queue\n\nMinimal Redis-backed setup:\n\n```python\nimport os\n\nfrom huey import RedisHuey, crontab\n\nhuey = RedisHuey(\n    \"my-app\",\n    url=os.getenv(\"REDIS_URL\", \"redis://localhost:6379/0\"),\n    results=True,\n    store_none=False,\n    utc=True,\n)\n\n@huey.task(retries=3, retry_delay=60)\ndef send_email(recipient: str, subject: str) -> None:\n    print(f\"Sending {subject} to {recipient}\")\n\n@huey.periodic_task(crontab(minute=\"0\", hour=\"3\"))\ndef run_nightly_cleanup() -> None:\n    print(\"nightly cleanup\")\n```\n\nQueue layout matters. A common pattern is:\n\n```python\n# myapp/queue.py\nimport os\n\nfrom huey import RedisHuey\n\nhuey = RedisHuey(\"my-app\", url=os.getenv(\"REDIS_URL\", \"redis://localhost:6379/0\"))\n\n# Import task modules so the consumer sees every decorated task.\nfrom myapp import tasks  # noqa: F401\n```\n\nIf the consumer starts without importing a task module, the task can be enqueued but the worker may not know how to execute it.\n\n## Run The Consumer\n\nPoint the consumer at the import path for your `Huey` instance:\n\n```bash\nhuey_consumer.py myapp.queue.huey\n```\n\nUseful options:\n\n```bash\nhuey_consumer.py myapp.queue.huey -w 4 -k thread\nhuey_consumer.py myapp.queue.huey -w 4 -k process\nhuey_consumer.py myapp.queue.huey -w 100 -k greenlet\nhuey_consumer.py myapp.queue.huey --no-periodic\n```\n\nChoose worker type by workload:\n\n- `thread`: good default for mixed I/O-bound tasks\n- `process`: use for CPU-bound work, but not on Windows\n- `greenlet`: only for I/O-heavy tasks after `gevent.monkey.patch_all()`\n\nPeriodic task scheduling happens inside the consumer. If you run multiple consumers for the same queue, typically only one should handle periodic scheduling and the rest should start with `--no-periodic`.\n\n## Core Usage\n\n### Enqueue a task and wait for the result\n\nCalling a decorated function enqueues it and returns a `Result` handle:\n\n```python\nresult = send_email(\"ops@example.com\", \"daily report\")\n\n# Block for up to 10 seconds waiting for the worker.\nresult.get(blocking=True, timeout=10)\n```\n\nIf the task raises an exception, `.get()` raises a `TaskException`.\n\n### Schedule work for later\n\n```python\nfrom datetime import datetime, timedelta\n\neta = datetime.utcnow() + timedelta(minutes=10)\nresult = send_email.schedule((\"ops@example.com\", \"later\"), eta=eta)\n```\n\nUse `delay` when relative timing is easier than an absolute ETA:\n\n```python\nresult = send_email.schedule((\"ops@example.com\", \"retry soon\"), delay=60)\n```\n\n### Retry from inside a task\n\nUse decorator-level retries for common cases:\n\n```python\n@huey.task(retries=5, retry_delay=30)\ndef fetch_webhook(url: str) -> dict:\n    ...\n```\n\nRaise `RetryTask` when the retry decision depends on runtime state:\n\n```python\nfrom huey import RetryTask\n\n@huey.task()\ndef sync_remote_order(order_id: str) -> None:\n    if not upstream_is_ready(order_id):\n        raise RetryTask(delay=60)\n```\n\n### Prevent overlapping jobs\n\nUse a lock for singleton-style work:\n\n```python\nfrom huey import lock_task\n\n@huey.periodic_task(crontab(minute=\"*/5\"))\n@lock_task(\"rebuild-search-index\")\ndef rebuild_search_index() -> None:\n    ...\n```\n\n### Signals\n\nHuey exposes signals such as task completion, errors, retries, locks, and enqueue events. Use them for instrumentation or cleanup hooks:\n\n```python\nfrom huey import SIGNAL_ERROR\n\n@huey.signal(SIGNAL_ERROR)\ndef on_task_error(signal, task, exc=None):\n    print(\"task failed\", task, exc)\n```\n\n## Backend Configuration And Connection Details\n\nHuey does not have a package-level auth system. The main operational config is how your queue backend is connected and how the consumer is tuned.\n\n### Redis-backed queues\n\nRedis is the primary production backend. A Redis URL can embed auth and database selection:\n\n```python\nimport os\n\nfrom huey import RedisHuey\n\nhuey = RedisHuey(\n    \"my-app\",\n    url=os.environ[\"REDIS_URL\"],  # e.g. redis://:password@redis.internal:6379/0\n    results=True,\n)\n```\n\nUseful variants:\n\n- `RedisHuey`: standard Redis queue\n- `PriorityRedisHuey`: priority queue support; requires Redis 5.0+\n- `RedisExpireHuey`: expiring result store\n- `PriorityRedisExpireHuey`: priorities plus expiring results\n\nUse an expiring result store when many callers never read task results and you do not want result keys to accumulate indefinitely.\n\n### SQLite-backed queues\n\nFor a single machine or smaller workloads:\n\n```python\nfrom huey import SqliteHuey\n\nhuey = SqliteHuey(\"my-app\", filename=\"huey.db\")\n```\n\nThis avoids Redis as an operational dependency, but it is not the right choice for horizontally scaled workers on multiple hosts.\n\n### Immediate mode\n\nImmediate mode executes tasks synchronously in the caller instead of queueing them:\n\n```python\nhuey.immediate = True\n```\n\nThis is useful in tests and sometimes in local development. Do not confuse it with running a real background queue.\n\n## Django Integration\n\nUse `huey.contrib.djhuey` when you are in a Django project. Configure Huey in `settings.py`:\n\n```python\nimport os\n\nHUEY = {\n    \"huey_class\": \"huey.RedisHuey\",\n    \"name\": \"my-django-app\",\n    \"results\": True,\n    \"store_none\": False,\n    \"url\": os.getenv(\"REDIS_URL\", \"redis://localhost:6379/0\"),\n    \"immediate\": False,\n    \"consumer\": {\n        \"workers\": 4,\n        \"worker_type\": \"thread\",\n    },\n}\n```\n\nDecorators from `djhuey` handle connection management around task execution:\n\n```python\nfrom huey.contrib.djhuey import db_task, on_commit_task\n\n@db_task()\ndef recalculate_user_stats(user_id: int) -> None:\n    ...\n\n@on_commit_task()\ndef send_order_confirmation(order_id: int) -> None:\n    ...\n```\n\nWhy these matter:\n\n- `db_task()` closes Django database connections around task execution\n- `on_commit_task()` waits until the outer transaction commits before enqueueing\n\nThat second point is important whenever a task depends on rows written in the request that queued it.\n\nRun the Django consumer with:\n\n```bash\npython manage.py run_huey\n```\n\nCommon Django surprise:\n\n- When Django `DEBUG` is on, many teams intentionally run Huey in immediate mode during development. That is convenient, but it hides real async behavior, retries, and worker-import issues.\n\n## Testing\n\nFor unit tests, immediate mode or local execution is usually easier than spinning up workers:\n\n```python\ndef test_send_email_runs_inline():\n    huey.immediate = True\n    send_email(\"ops@example.com\", \"subject\")\n```\n\nFor pure function tests, `call_local()` runs the task body without enqueueing:\n\n```python\nsend_email.call_local(\"ops@example.com\", \"subject\")\n```\n\nReset queue state between tests when sharing a backend.\n\n## Common Pitfalls\n\n- The consumer must import the modules that define your tasks. Missing imports look like \"task enqueued but never handled\".\n- `results=False` means no persistent task results. Also, return values of `None` are not stored unless `store_none=True`.\n- Reading a result normally consumes it. Use `preserve=True` if you need to read it more than once.\n- Periodic tasks do not preserve return values the same way normal tasks do. Push important outputs to your own datastore instead of relying on task return values.\n- Use aware or consistently interpreted times. Huey stores timestamps in UTC internally; mismatched local time assumptions can shift scheduled jobs.\n- `greenlet` workers need proper monkey-patching and are not a drop-in replacement for CPU-bound work.\n- `SIGTERM` can interrupt in-flight work abruptly. Graceful shutdown handling and signal hooks matter if you need to requeue or audit interrupted tasks.\n- If you upgrade from very old Huey versions, do not mix workers with old serialized tasks still sitting in the queue until you confirm serialization compatibility.\n\n## Version-Sensitive Notes For 2.6.0\n\n- PyPI currently lists `2.6.0` as the latest `huey` release as of March 12, 2026, so the version used here is still current.\n- The 2.6.0 release itself is mostly packaging and release-process maintenance. The operational features most agents care about were added earlier in the 2.5.x line and are present in 2.6.0.\n- `on_commit_task()` landed in the 2.5 series. If older internal docs do not mention it, prefer it over enqueueing tasks inside open Django transactions.\n- `SIGNAL_ENQUEUED` also arrived in the 2.5 series. Use it if you need enqueue-side instrumentation.\n- If you are upgrading from pre-2.0 code, watch for old names like `always_eager` and `result_store`; Huey 2.x uses `immediate` and `results`, and 2.0 changed task serialization in a way that can matter for live queues.\n\n## Official Sources\n\n- Docs root: `https://huey.readthedocs.io/en/stable/`\n- API reference: `https://huey.readthedocs.io/en/latest/api.html`\n- Django integration: `https://huey.readthedocs.io/en/latest/django.html`\n- Consumer guide: `https://huey.readthedocs.io/en/latest/consumer.html`\n- Signals guide: `https://huey.readthedocs.io/en/latest/signals.html`\n- Registry: `https://pypi.org/project/huey/`\n- Repository: `https://github.com/coleifer/huey`\n"
  },
  {
    "path": "content/huggingface/docs/hub/python/DOC.md",
    "content": "---\nname: package\ndescription: \"huggingface-hub for Python: authenticate, download files and snapshots, query Hub repos, and upload models, datasets, or Spaces\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"huggingface-hub,huggingface,hub,models,datasets,spaces,ml\"\n---\n\n# huggingface-hub Python Package Guide\n\n## What It Is\n\n`huggingface-hub` is the official Python client for the Hugging Face Hub. Use it to:\n\n- authenticate with a user access token\n- download individual files or full repository snapshots\n- inspect models, datasets, Spaces, and repo metadata through `HfApi`\n- upload files, folders, or commits to Hub repositories\n- access Hub content through an `fsspec` filesystem interface\n\nFor Python code, the main imports come from `huggingface_hub`, while the install name on PyPI is `huggingface-hub`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"huggingface-hub==1.6.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"huggingface-hub==1.6.0\"\npoetry add \"huggingface-hub==1.6.0\"\n```\n\nUseful extras documented by Hugging Face and PyPI metadata:\n\n```bash\npython -m pip install \"huggingface-hub[mcp]==1.6.0\"\npython -m pip install \"huggingface-hub[torch]==1.6.0\"\npython -m pip install \"huggingface-hub[hf-xet]==1.6.0\"\n```\n\n## Imports At A Glance\n\n```python\nfrom huggingface_hub import (\n    HfApi,\n    HfFileSystem,\n    hf_hub_download,\n    login,\n    model_info,\n    repo_exists,\n    snapshot_download,\n    upload_file,\n    upload_folder,\n)\n```\n\n## Authentication And Setup\n\n### Preferred auth paths\n\nUse a Hugging Face user access token. The package supports:\n\n1. `hf auth login` from the CLI\n2. `login()` in Python\n3. `HF_TOKEN` in the environment for headless or CI usage\n\nCLI login:\n\n```bash\nhf auth login\n```\n\nHeadless environment setup:\n\n```bash\nexport HF_TOKEN=\"hf_your_token\"\n```\n\nProgrammatic login:\n\n```python\nfrom huggingface_hub import login\n\nlogin(token=\"hf_your_token\")\n```\n\nNotebook-specific helpers are available:\n\n```python\nfrom huggingface_hub import interpreter_login, notebook_login\n\n# Use in a notebook environment\nnotebook_login()\n\n# Use when automatic notebook detection is unreliable\ninterpreter_login()\n```\n\nImportant auth notes:\n\n- `login()` rejects organization tokens. Use a personal user token.\n- `HF_TOKEN` overrides the token stored on disk.\n- Public downloads often work without a token, but private or gated repos require one.\n- When code must work for models, datasets, or Spaces, pass `repo_type=\"dataset\"` or `repo_type=\"space\"` explicitly instead of assuming the default model repo type.\n\n## Core Usage\n\n### Download one file into the local cache\n\n`hf_hub_download()` is the normal path when you need one file and want a stable local cache path back:\n\n```python\nfrom huggingface_hub import hf_hub_download\n\nweights_path = hf_hub_download(\n    repo_id=\"google/flan-t5-small\",\n    filename=\"config.json\",\n    revision=\"main\",\n)\n\nprint(weights_path)\n```\n\nFor reproducible builds, pin `revision` to a full commit hash instead of a moving branch name.\n\nUse `repo_type` for non-model repos:\n\n```python\nfrom huggingface_hub import hf_hub_download\n\ndataset_file = hf_hub_download(\n    repo_id=\"datasets-org/my-dataset\",\n    filename=\"README.md\",\n    repo_type=\"dataset\",\n    revision=\"main\",\n)\n```\n\n### Download a full snapshot\n\nUse `snapshot_download()` when a task needs multiple files from the same repo:\n\n```python\nfrom huggingface_hub import snapshot_download\n\nrepo_dir = snapshot_download(\n    repo_id=\"google/flan-t5-small\",\n    allow_patterns=[\"*.json\", \"*.safetensors\", \"tokenizer.*\"],\n    revision=\"main\",\n)\n\nprint(repo_dir)\n```\n\nPattern filters are the main way to avoid pulling an entire repository when only a few assets are needed.\n\nIf you want a working copy in a project directory instead of the central cache:\n\n```python\nfrom huggingface_hub import snapshot_download\n\nsnapshot_download(\n    repo_id=\"google/flan-t5-small\",\n    local_dir=\"artifacts/flan-t5-small\",\n    revision=\"main\",\n)\n```\n\nUse `local_dir` only when you really want a mirrored folder in your workspace. The docs note that this mode manages its own lightweight cache under that folder and is less optimized than the main cache system.\n\n### Search and inspect the Hub with `HfApi`\n\n`HfApi` is the main Python interface for Hub operations beyond simple download helpers:\n\n```python\nfrom huggingface_hub import HfApi\n\napi = HfApi()\n\nmodels = api.list_models(search=\"sentence-transformers\", limit=5)\nfor model in models:\n    print(model.id)\n```\n\nInspect one repository:\n\n```python\nfrom huggingface_hub import HfApi\n\napi = HfApi()\ninfo = api.model_info(\"google/flan-t5-small\")\n\nprint(info.id)\nprint(info.sha)\nprint(info.private)\n```\n\nCheck existence before generating code that assumes a repo is present:\n\n```python\nfrom huggingface_hub import repo_exists\n\nprint(repo_exists(\"google/flan-t5-small\"))\nprint(repo_exists(\"my-org/private-dataset\", repo_type=\"dataset\", token=\"hf_...\"))\n```\n\n### Create a repo and upload content\n\nCreate the target repo first:\n\n```python\nfrom huggingface_hub import HfApi\n\napi = HfApi(token=\"hf_your_token\")\n\napi.create_repo(\n    repo_id=\"your-username/demo-model\",\n    exist_ok=True,\n)\n```\n\nUpload one file:\n\n```python\nfrom huggingface_hub import upload_file\n\nupload_file(\n    path_or_fileobj=\"README.md\",\n    path_in_repo=\"README.md\",\n    repo_id=\"your-username/demo-model\",\n    commit_message=\"Add README\",\n    token=\"hf_your_token\",\n)\n```\n\nUpload a whole folder:\n\n```python\nfrom huggingface_hub import upload_folder\n\nupload_folder(\n    folder_path=\"dist/model-artifacts\",\n    repo_id=\"your-username/demo-model\",\n    allow_patterns=[\"*.json\", \"*.safetensors\", \"*.md\"],\n    commit_message=\"Upload model artifacts\",\n    token=\"hf_your_token\",\n)\n```\n\nFor datasets or Spaces, add `repo_type=\"dataset\"` or `repo_type=\"space\"`.\n\n### Access Hub content through `HfFileSystem`\n\n`HfFileSystem` gives you an `fsspec` filesystem for Hub repos:\n\n```python\nfrom huggingface_hub import HfFileSystem\n\nfs = HfFileSystem(token=\"hf_your_token\")\n\nprint(fs.ls(\"datasets/openai/gsm8k\"))\n\nwith fs.open(\"datasets/openai/gsm8k/README.md\", \"r\") as f:\n    print(f.read(200))\n```\n\nUse it when a library already expects an `fsspec` filesystem. The docs explicitly note that `HfFileSystem` adds extra overhead, so use `HfApi` methods directly when you do not need filesystem semantics.\n\n## Configuration And Environment\n\nThe most useful environment variables for generated code and CI are:\n\n- `HF_TOKEN`: access token used by the client; overrides the stored token\n- `HF_HOME`: root directory for token and cache state\n- `HF_HUB_CACHE`: override the repo cache directory\n- `HF_HUB_OFFLINE=1`: disable HTTP calls and rely on cached files only\n- `HF_HUB_DISABLE_IMPLICIT_TOKEN=1`: do not automatically send the stored token on read operations\n- `HF_DEBUG=1`: emit debug logs and cURL-equivalent request traces\n\nExample CI setup:\n\n```bash\nexport HF_TOKEN=\"hf_your_token\"\nexport HF_HOME=\"$PWD/.hf\"\nexport HF_HUB_CACHE=\"$PWD/.hf/hub\"\n```\n\nPython usage with an explicit cache directory:\n\n```python\nfrom huggingface_hub import hf_hub_download\n\npath = hf_hub_download(\n    repo_id=\"google/flan-t5-small\",\n    filename=\"config.json\",\n    cache_dir=\".hf-cache\",\n)\n```\n\n## Common Pitfalls\n\n- Install name and import name differ: install `huggingface-hub`, import `huggingface_hub`.\n- Default repo type is a model repo. Set `repo_type` for datasets and Spaces.\n- Do not rely on moving branches like `main` when reproducibility matters. Pin `revision` to a commit hash.\n- `hf_hub_download()` returns a cached file path; it does not copy the file into your project unless you do that yourself.\n- `snapshot_download(local_dir=...)` creates a local mirror, not just a cache entry. Use it intentionally.\n- Public reads can work anonymously, but gated or private repos will fail without a valid token.\n- `login()` only accepts personal account tokens, not organization tokens.\n- `HfFileSystem` is convenient but slower than direct `HfApi` calls for simple metadata or file operations.\n- In offline mode, code that expects fresh metadata or remote existence checks will fail unless the artifacts are already cached locally.\n\n## Version-Sensitive Notes For 1.6.0\n\n- PyPI lists `huggingface-hub 1.6.0` released on March 6, 2026.\n- The current docs root publishes `main v1.6.0`, so the primary Hugging Face docs are aligned with the package version for this session.\n- The v1.x line requires Python 3.9+.\n- The v1.0 migration notes still matter in `1.6.0`: the library switched to `httpx`, the `Repository` class was removed, `use_auth_token` was removed in favor of `token`, and several cache-constant internals moved or were removed.\n- If you need code that spans both `0.x` and `1.x`, prefer `huggingface_hub.HfHubHttpError` for shared exception handling because it maps cleanly across the backend switch.\n- The `1.6.0` release adds CLI commands for discussions, webhooks, dataset parquet and SQL export, repo duplication, and bucket support in `HfFileSystem`. These are useful if your automation shells out to `hf` alongside the Python API.\n\n## Official Sources\n\n- Docs home: `https://huggingface.co/docs/huggingface_hub/`\n- Installation: `https://huggingface.co/docs/huggingface_hub/en/installation`\n- Quickstart: `https://huggingface.co/docs/huggingface_hub/en/quick-start`\n- Authentication: `https://huggingface.co/docs/huggingface_hub/en/package_reference/authentication`\n- File download: `https://huggingface.co/docs/huggingface_hub/en/package_reference/file_download`\n- Environment variables: `https://huggingface.co/docs/huggingface_hub/en/package_reference/environment_variables`\n- `HfApi` reference: `https://huggingface.co/docs/huggingface_hub/en/package_reference/hf_api`\n- `HfFileSystem` reference: `https://huggingface.co/docs/huggingface_hub/en/package_reference/hf_file_system`\n- Migration notes: `https://huggingface.co/docs/huggingface_hub/en/concepts/migration`\n- PyPI: `https://pypi.org/project/huggingface-hub/`\n- GitHub release `v1.6.0`: `https://github.com/huggingface/huggingface_hub/releases/tag/v1.6.0`\n"
  },
  {
    "path": "content/huggingface/docs/transformers/DOC.md",
    "content": "---\nname: transformers\ndescription: \"Transformers.js coding guidelines for running ML models in the browser or Node.js\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.7.6\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"huggingface,transformers,ml,inference,models\"\n---\n\n# Transformers.js Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Transformers.js expert. Help me with writing code using the Transformers.js library for running machine learning models directly in the browser or Node.js.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official documentation and examples here:\nhttps://huggingface.co/docs/transformers.js/\n\n## Golden Rule: Use the Correct and Current Package\n\nAlways use the official Transformers.js package `@huggingface/transformers` for all machine learning inference tasks. This is the standard library for running transformer models in JavaScript environments.\n\n- **Library Name:** Transformers.js\n- **NPM Package:** `@huggingface/transformers`\n- **Current Version:** 3.5.2\n\n**Installation:**\n\n- **Correct:** `npm i @huggingface/transformers`\n- **Browser CDN:** `https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.5.2`\n\n**Main APIs and Usage:**\n\n- **Correct:** `import { pipeline } from '@huggingface/transformers'`\n- **Correct:** `const pipe = await pipeline('task-name')`\n- **Correct:** `const result = await pipe(input)` \n\n## Installation and Setup\n\n### Browser Installation\n\nFor browser environments, you can use either NPM or CDN:\n\n**NPM Installation:**\n```bash\nnpm i @huggingface/transformers\n```\n\n**CDN Installation:**\n```html\n<script type=\"module\">\n    import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.4';\n</script>\n```\n\n\n### Node.js Installation\n\nFor Node.js environments, install via NPM and configure your project:\n\n**ESM (Recommended):**\nTo indicate that your project uses ECMAScript modules, you need to add `\"type\": \"module\"` to your `package.json`:\n\n```json\n{\n  //...\n  \"type\": \"module\",\n  //...\n}\n```\n\n**CommonJS:**\nUse dynamic imports for Transformers.js\n\nFollowing that, let's import Transformers.js and define the `MyClassificationPipeline` class. Since Transformers.js is an ESM module, we will need to dynamically import the library using the [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) function:\n\n```javascript\nclass MyClassificationPipeline {\n  static task = 'text-classification';\n  static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n  static instance = null;\n\n  static async getInstance(progress_callback = null) {\n    if (this.instance === null) {\n      // Dynamically import the Transformers.js library\n      let { pipeline, env } = await import('@huggingface/transformers');\n\n      // NOTE: Uncomment this to change the cache directory\n      // env.cacheDir = './.cache';\n\n      this.instance = pipeline(this.task, this.model, { progress_callback });\n    }\n\n    return this.instance;\n  }\n}\n```\n\n## Basic Inference (Text Processing)\n\nThe `pipeline()` function is the easiest way to use pretrained models:\n\n```javascript\nimport { pipeline } from '@huggingface/transformers';\n\nconst classifier = await pipeline('sentiment-analysis');\n```\n\n**Text Classification Example:**\n\n```javascript\nconst result = await classifier('I love transformers!');\n// [{'label': 'POSITIVE', 'score': 0.9998}]\n```\n\n\n**Multiple Inputs:**\n\n```javascript\nconst result = await classifier(['I love transformers!', 'I hate transformers!']);\n// [{'label': 'POSITIVE', 'score': 0.9998}, {'label': 'NEGATIVE', 'score': 0.9982}]\n```\n\n**Custom Models:**\n```javascript\nconst reviewer = await pipeline('sentiment-analysis', 'Xenova/bert-base-multilingual-uncased-sentiment');\n\nconst result = await reviewer('The Shawshank Redemption is a true masterpiece of cinema.');\n// [{label: '5 stars', score: 0.8167929649353027}]\n```\n\n## Multimodal Input Support\n\nTransformers.js supports various input types including images, audio, and video:\n\n**Image Processing:**\n\nBy default, when running in the browser, the model will be run on your CPU (via WASM). If you would like\nto run the model on your GPU (via WebGPU), you can do this by setting `device: 'webgpu'`, for example:\n```javascript\n// Run the model on WebGPU\nconst pipe = await pipeline('sentiment-analysis', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english', {\n  device: 'webgpu',\n});\n```\n\nFor more information, check out the [WebGPU guide](https://huggingface.co/docs/transformers.js/guides/webgpu).\n\n\n\nIn resource-constrained environments, such as web browsers, it is advisable to use a quantized version of\nthe model to lower bandwidth and optimize performance. This can be achieved by adjusting the `dtype` option,\nwhich allows you to select the appropriate data type for your model. While the available options may vary\ndepending on the specific model, typical choices include `\"fp32\"` (default for WebGPU), `\"fp16\"`, `\"q8\"`\n(default for WASM), and `\"q4\"`. For more information, check out the [quantization guide](https://huggingface.co/docs/transformers.js/guides/dtypes).\n```javascript\n// Run the model at 4-bit quantization\nconst pipe = await pipeline('sentiment-analysis', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english', {\n  dtype: 'q4',\n});\n```\n\n**Audio Processing (ASR):**\n\n\n\n## Device Configuration\n\n### WebGPU Acceleration\n\nFor GPU acceleration in browsers, use the `device: 'webgpu'` option: \n\n**WebGPU Usage Example:** \n\n### Device Options\n\nAvailable device options include:\n- `'cpu'` - CPU execution (default for Node.js)\n- `'wasm'` - WebAssembly execution (default for browsers)  \n- `'webgpu'` - GPU acceleration (browsers with WebGPU support)\n- `'webnn'` - Web Neural Network API acceleration \n\n## Quantization and Data Types\n\n### Basic Quantization\n\nUse the `dtype` parameter to control model precision and size: \n\n**Available dtypes:**\n- `\"fp32\"` - Full precision (default for WebGPU)\n- `\"fp16\"` - Half precision\n- `\"q8\"` - 8-bit quantization (default for WASM)\n- `\"q4\"` - 4-bit quantization (smallest size) \n\n**Basic Quantization Example:** \n\n### Per-Module Quantization\n\nFor complex models, you can specify different quantization levels per module: \n\n## Environment Configuration\n\n### Global Settings\n\nConfigure Transformers.js behavior using the `env` object: \n\n**Common Configuration Options:**\n\n- **Remote Models:** `env.allowRemoteModels = false`\n- **Local Model Path:** `env.localModelPath = '/path/to/models/'`\n- **Cache Directory:** `env.cacheDir = '/path/to/cache/'` \n\n### Node.js Specific Settings\n\nFor Node.js applications, you can customize caching and model loading: \n\n**Default Cache Location:**\n- Node.js: `node_modules/@huggingface/transformers/.cache/`\n- Models are organized by author/model-name subdirectories\n- Each model contains config.json, tokenizer files, and ONNX weights in an `onnx/` subfolder \n\n## Pipeline Options and Generation Parameters\n\n### Loading Options\n\nControl how models are loaded with PretrainedOptions: \n\n**Model Revision:** \n\n**Available Options:**\n```javascript\nconst pipe = await pipeline('task-name', 'model-name', {\n  device: 'webgpu',           // 'cpu', 'wasm', 'webgpu', 'webnn'\n  dtype: 'q8',                // 'fp32', 'fp16', 'q8', 'q4'\n  progress_callback: (info) => console.log(info),  // Track download progress\n  revision: 'main',           // Specific model revision/branch\n});\n```\n\n### Generation Parameters\n\nFor text generation models, use GenerationConfig options: \n\n**Common Generation Options:**\n```javascript\nconst result = await generator(prompt, {\n  max_new_tokens: 50,        // Maximum tokens to generate\n  temperature: 0.9,          // Randomness (0.0 = deterministic, 1.0+ = creative)\n  do_sample: true,           // Enable sampling (required for temperature/top_k)\n  top_k: 50,                 // Consider only top K tokens\n  repetition_penalty: 2.0,   // Penalize repetition\n  no_repeat_ngram_size: 3,   // Prevent n-gram repetition\n});\n```\n\n### Feature Extraction Options\n\nFor embedding models, specify pooling and normalization:\n\n```javascript\nconst embeddings = await extractor(texts, {\n  pooling: 'mean',           // 'mean', 'max', 'cls'\n  normalize: true            // L2 normalization for similarity tasks\n});\n\n// Convert tensor to array\nconst embeddingArray = embeddings.tolist();\n``` \n\n### Streaming Output\n\nEnable streaming for real-time text generation: \n\n## Translation and Multilingual Models\n\n### Available Translation Models\n\nTransformers.js supports several translation model families on Hugging Face Hub:\n\n**OPUS-MT Models (Recommended for Lightweight Use):**\n- Lightweight, fast translation models from the Marian framework\n- Trained on OPUS multilingual data by Helsinki-NLP\n- Available as Xenova-converted ONNX models for browser compatibility\n- Examples: `Xenova/opus-mt-en-es`, `Xenova/opus-mt-en-fr`, `Xenova/opus-mt-ja-en`\n- Best for: Single language-pair translation, browser applications, fast inference\n\n**NLLB (No Language Left Behind):**\n- Meta's multilingual model supporting 200+ languages\n- Models: `Xenova/nllb-200-distilled-600M` (and larger variants)\n- Requires more resources but supports many language pairs\n- Best for: Multi-language support, low-resource languages\n\n**mBART Models:**\n- Facebook's multilingual translation models\n- Good for document-level translation\n\n### Translation Usage\n\nFor translation tasks, specify source and target languages: \n\n**Language Code Format:**\n- OPUS-MT models: Often work with simple language codes\n- NLLB models: Use codes like `eng_Latn`, `spa_Latn`, `fra_Latn`, etc.\n- Check model card on Hugging Face for supported language codes\n\n**Important Notes:**\n- OPUS-MT models are typically single-direction (e.g., EN→ES only)\n- For bi-directional translation, you need two separate OPUS-MT models\n- NLLB models support multiple directions but are much larger\n- Translation quality and speed vary significantly between model families \n\n## Supported Tasks\n\n### Natural Language Processing\n\nMain NLP tasks include:\n- Text Classification (`text-classification` or `sentiment-analysis`)\n- Question Answering (`question-answering`)\n- Text Generation (`text-generation`)\n- Translation (`translation`)\n- Summarization (`summarization`)\n- Token Classification (`token-classification` or `ner`)\n- Fill Mask (`fill-mask`)\n- Zero-Shot Classification (`zero-shot-classification`)\n- Feature Extraction (`feature-extraction`) \n\n**Recommended Models by Task:**\n\n- **Sentiment Analysis:** `Xenova/distilbert-base-uncased-finetuned-sst-2-english` (fast, accurate)\n- **Text Generation:** `Xenova/gpt2` (lightweight), `onnx-community/Qwen2.5-Coder-0.5B-Instruct` (code/chat)\n- **Feature Extraction:** `Xenova/all-MiniLM-L6-v2` (384-dim embeddings, fast)\n- **Translation:** `Xenova/opus-mt-*` series (lightweight, language-specific)\n- **Question Answering:** `Xenova/distilbert-base-cased-distilled-squad` \n\n### Computer Vision\n\nVision tasks include:\n- Image Classification (`image-classification`)\n- Object Detection (`object-detection`)\n- Image Segmentation (`image-segmentation`)\n- Depth Estimation (`depth-estimation`)\n- Background Removal (`background-removal`)\n- Image-to-Image (`image-to-image`)\n- Image Feature Extraction (`image-feature-extraction`) \n\n### Audio Processing\n\nAudio tasks include:\n- Automatic Speech Recognition (`automatic-speech-recognition`)\n- Audio Classification (`audio-classification`)\n- Text-to-Speech (`text-to-speech` or `text-to-audio`)  \n\n### Multimodal\n\nMultimodal tasks include:\n- Document Question Answering (`document-question-answering`)\n- Image-to-Text (`image-to-text`)\n- Zero-Shot Image Classification (`zero-shot-image-classification`)\n- Zero-Shot Audio Classification (`zero-shot-audio-classification`)\n- Zero-Shot Object Detection (`zero-shot-object-detection`) \n\n## Framework Integration\n\n### Node.js Server Example\n\nCreate a basic HTTP server with Transformers.js: \n\nUse the singleton pattern for efficient model loading:\n\n## Error Handling and Best Practices\n\n### General Best Practices\n\n- Always await pipeline creation and inference calls\n- Use lazy loading patterns (singleton pattern) for efficient model loading\n- Enable WebGPU when available for better performance in browsers\n- Choose appropriate quantization levels based on your requirements\n- Cache models locally for production applications\n\n### Singleton Pattern for Model Loading\n\nUse the singleton pattern to load models once and reuse them across requests:\n\n```javascript\nclass MyPipeline {\n  static task = 'sentiment-analysis';\n  static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n  static instance = null;\n\n  static async getInstance(progress_callback = null) {\n    if (this.instance === null) {\n      const { pipeline, env } = await import('@huggingface/transformers');\n\n      // Configure environment if needed\n      // env.cacheDir = './.cache';\n\n      this.instance = await pipeline(this.task, this.model, { progress_callback });\n    }\n    return this.instance;\n  }\n}\n```\n\n### Model Loading Warnings\n\nWhen loading models, you may see dtype warnings in the console:\n\n```\ndtype not specified for \"model\". Using the default dtype (fp32) for this device (cpu).\n```\n\nThese are informational warnings and can be safely ignored. To suppress them, explicitly specify the dtype:\n\n```javascript\nconst pipe = await pipeline('task-name', 'model-name', {\n  dtype: 'q8'  // or 'fp32', 'fp16', 'q4', etc.\n});\n```\n\n### Common Issues and Solutions\n\n**Model Cache Issues:**\n- If a model fails to load with \"Protobuf parsing failed\" errors, the cached model may be corrupted\n- Clear the cache directory (default: `node_modules/@huggingface/transformers/.cache/`)\n- Consider using a different model or switching to a lighter variant\n\n**Translation Models:**\n- Large translation models (600M+ parameters) may be too heavy for browser environments\n- Prefer lightweight OPUS-MT models for single language pairs\n- NLLB models require significant memory and may time out in resource-constrained environments\n\n**Response Structure:**\n- Different pipelines return different response structures\n- Sentiment analysis: `[{label: 'POSITIVE', score: 0.99}]`\n- Translation: `[{translation_text: 'Hola mundo'}]`\n- Feature extraction: Returns tensor objects, use `.tolist()` to convert to arrays\n- Question answering: `{answer: 'text', score: 0.95}`\n- Text generation: `[{generated_text: 'text'}]`\n\n## Model Conversion\n\nTo use custom models, convert them to ONNX format:\n\nThe conversion script supports quantization:\n\n## Useful Links\n\n- Documentation: https://huggingface.co/docs/transformers.js\n- NPM Package: https://www.npmjs.com/package/@huggingface/transformers\n- GitHub Repository: https://github.com/huggingface/transformers.js\n- Model Hub (transformers.js compatible): https://huggingface.co/models?library=transformers.js\n- Examples and Templates: https://github.com/huggingface/transformers.js-examples\n\n## Notes\n\nThis is a comprehensive guide for using Transformers.js in JavaScript applications. The library is designed to be functionally equivalent to Hugging Face's Python transformers library but optimized for JavaScript environments. It supports running inference in browsers, Node.js, and web workers using ONNX Runtime for optimal performance.\n\nKey advantages include:\n- No server required for inference\n- Support for quantized models for better performance\n- WebGPU acceleration when available\n- Comprehensive task coverage across NLP, computer vision, and audio\n- Easy integration with existing JavaScript applications\n\n### Citations\n\n```markdown\nTo install via [NPM](https://www.npmjs.com/package/@huggingface/transformers), run:\n```bash\nnpm i @huggingface/transformers\n```\n```\n\n```markdown\nAlternatively, you can use it in vanilla JS, without any bundler, by using a CDN or static hosting. For example, using [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), you can import the library with:\n```html\n<script type=\"module\">\n    import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.5.2';\n</script>\n```\n```\n\n```markdown\nBy default, when running in the browser, the model will be run on your CPU (via WASM). If you would like\nto run the model on your GPU (via WebGPU), you can do this by setting `device: 'webgpu'`, for example:\n```javascript\n// Run the model on WebGPU\nconst pipe = await pipeline('sentiment-analysis', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english', {\n  device: 'webgpu',\n});\n```\n\nFor more information, check out the [WebGPU guide](https://huggingface.co/docs/transformers.js/guides/webgpu).\n\n> [!WARNING]\n> The WebGPU API is still experimental in many browsers, so if you run into any issues,\n> please file a [bug report](https://github.com/huggingface/transformers.js/issues/new?title=%5BWebGPU%5D%20Error%20running%20MODEL_ID_GOES_HERE&assignees=&labels=bug,webgpu&projects=&template=1_bug-report.yml).\n\nIn resource-constrained environments, such as web browsers, it is advisable to use a quantized version of\nthe model to lower bandwidth and optimize performance. This can be achieved by adjusting the `dtype` option,\nwhich allows you to select the appropriate data type for your model. While the available options may vary\ndepending on the specific model, typical choices include `\"fp32\"` (default for WebGPU), `\"fp16\"`, `\"q8\"`\n(default for WASM), and `\"q4\"`. For more information, check out the [quantization guide](https://huggingface.co/docs/transformers.js/guides/dtypes).\n```javascript\n// Run the model at 4-bit quantization\nconst pipe = await pipeline('sentiment-analysis', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english', {\n  dtype: 'q4',\n});\n```\n```\n\n```markdown\n```javascript\nimport { env } from '@huggingface/transformers';\n\n// Specify a custom location for models (defaults to '/models/').\nenv.localModelPath = '/path/to/models/';\n\n// Disable the loading of remote models from the Hugging Face Hub:\nenv.allowRemoteModels = false;\n\n// Set location of .wasm files. Defaults to use a CDN.\nenv.backends.onnx.wasm.wasmPaths = '/path/to/files/';\n```\n```\n\n```markdown\n```bash\npython -m scripts.convert --quantize --model_id <model_name_or_path>\n```\n\nFor example, convert and quantize [bert-base-uncased](https://huggingface.co/bert-base-uncased) using:\n```bash\npython -m scripts.convert --quantize --model_id bert-base-uncased\n```\n\n```\n\n```markdown\nThis will save the following files to `./models/`:\n\n```\nbert-base-uncased/\n├── config.json\n├── tokenizer.json\n├── tokenizer_config.json\n└── onnx/\n    ├── model.onnx\n    └── model_quantized.onnx\n```\n```\n\n```markdown\nTo indicate that your project uses ECMAScript modules, you need to add `\"type\": \"module\"` to your `package.json`:\n\n```json\n{\n  ...\n  \"type\": \"module\",\n  ...\n}\n```\n```\n\n```markdown\nclass MyClassificationPipeline {\n  static task = 'text-classification';\n  static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n  static instance = null;\n\n  static async getInstance(progress_callback = null) {\n    if (this.instance === null) {\n      // NOTE: Uncomment this to change the cache directory\n      // env.cacheDir = './.cache';\n\n      this.instance = pipeline(this.task, this.model, { progress_callback });\n    }\n\n    return this.instance;\n  }\n}\n```\n```\n\n```markdown\nFollowing that, let's import Transformers.js and define the `MyClassificationPipeline` class. Since Transformers.js is an ESM module, we will need to dynamically import the library using the [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) function:\n\n```javascript\nclass MyClassificationPipeline {\n  static task = 'text-classification';\n  static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n  static instance = null;\n\n  static async getInstance(progress_callback = null) {\n    if (this.instance === null) {\n      // Dynamically import the Transformers.js library\n      let { pipeline, env } = await import('@huggingface/transformers');\n\n      // NOTE: Uncomment this to change the cache directory\n      // env.cacheDir = './.cache';\n\n      this.instance = pipeline(this.task, this.model, { progress_callback });\n    }\n\n    return this.instance;\n  }\n}\n```\n```\n\n```markdown\n// Define the HTTP server\nconst server = http.createServer();\nconst hostname = '127.0.0.1';\nconst port = 3000;\n\n// Listen for requests made to the server\nserver.on('request', async (req, res) => {\n  // Parse the request URL\n  const parsedUrl = url.parse(req.url);\n\n  // Extract the query parameters\n  const { text } = querystring.parse(parsedUrl.query);\n\n  // Set the response headers\n  res.setHeader('Content-Type', 'application/json');\n\n  let response;\n  if (parsedUrl.pathname === '/classify' && text) {\n    const classifier = await MyClassificationPipeline.getInstance();\n    response = await classifier(text);\n    res.statusCode = 200;\n  } else {\n    response = { 'error': 'Bad request' }\n    res.statusCode = 400;\n  }\n\n  // Send the JSON response\n  res.end(JSON.stringify(response));\n});\n\nserver.listen(port, hostname, () => {\n  console.log(`Server running at http://${hostname}:${port}/`);\n});\n\n```\n```\n\n```markdown\n### Model caching\n\nBy default, the first time you run the application, it will download the model files and cache them on your file system (in `./node_modules/@huggingface/transformers/.cache/`). All subsequent requests will then use this model. You can change the location of the cache by setting `env.cacheDir`. For example, to cache the model in the `.cache` directory in the current working directory, you can add:\n\n```javascript\nenv.cacheDir = './.cache';\n```\n\n### Use local models\n\nIf you want to use local model files, you can set `env.localModelPath` as follows:\n\n```javascript\n// Specify a custom location for models (defaults to '/models/').\nenv.localModelPath = '/path/to/models/';\n```\n\nYou can also disable loading of remote models by setting `env.allowRemoteModels` to `false`:\n\n```javascript\n// Disable the loading of remote models from the Hugging Face Hub:\nenv.allowRemoteModels = false;\n```\n\n```markdown\n```javascript\nimport { pipeline } from '@huggingface/transformers';\n\nconst classifier = await pipeline('sentiment-analysis');\n```\n\n```\n\n```markdown\n```javascript\nconst result = await classifier('I love transformers!');\n// [{'label': 'POSITIVE', 'score': 0.9998}]\n```\n```\n\n```markdown\n```javascript\nconst result = await classifier(['I love transformers!', 'I hate transformers!']);\n// [{'label': 'POSITIVE', 'score': 0.9998}, {'label': 'NEGATIVE', 'score': 0.9982}]\n```\n```\n\n```markdown\n```javascript\nconst reviewer = await pipeline('sentiment-analysis', 'Xenova/bert-base-multilingual-uncased-sentiment');\n\nconst result = await reviewer('The Shawshank Redemption is a true masterpiece of cinema.');\n// [{label: '5 stars', score: 0.8167929649353027}]\n```\n```\n\n```markdown\n// Create a pipeline for Automatic Speech Recognition\nconst transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-small.en');\n\n// Transcribe an audio file, loaded from a URL.\nconst result = await transcriber('https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac');\n// {text: ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'}\n```\n```\n\n```markdown\n// Create a pipeline for feature extraction, using the full-precision model (fp32)\nconst pipe = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', {\n    dtype: \"fp32\",\n});\n```\nCheck out the section on [quantization](./guides/dtypes) to learn more.\n```\n\n```markdown\n```javascript\nconst transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-tiny.en', {\n    revision: 'output_attentions',\n});\n```\n```\n\n```markdown\n// Create a pipeline for translation\nconst translator = await pipeline('translation', 'Xenova/nllb-200-distilled-600M');\n\n// Translate from English to Greek\nconst result = await translator('I like to walk my dog.', {\n    src_lang: 'eng_Latn',\n    tgt_lang: 'ell_Grek'\n});\n// [ { translation_text: 'Μου αρέσει να περπατάω το σκυλί μου.' } ]\n\n// Translate back to English\nconst result2 = await translator(result[0].translation_text, {\n    src_lang: 'ell_Grek',\n    tgt_lang: 'eng_Latn'\n});\n// [ { translation_text: 'I like to walk my dog.' } ]\n```\n```\n\n```markdown\n```javascript\n// Create a pipeline for text2text-generation\nconst poet = await pipeline('text2text-generation', 'Xenova/LaMini-Flan-T5-783M');\nconst result = await poet('Write me a love poem about cheese.', {\n    max_new_tokens: 200,\n    temperature: 0.9,\n    repetition_penalty: 2.0,\n    no_repeat_ngram_size: 3,\n});\n```\n```\n\n```markdown\nSome pipelines such as `text-generation` or `automatic-speech-recognition` support streaming output. This is achieved using the `TextStreamer` class. For example, when using a chat model like `Qwen2.5-Coder-0.5B-Instruct`, you can specify a callback function that will be called with each generated token text (if unset, new tokens will be printed to the console).\n\n```js\nimport { pipeline, TextStreamer } from \"@huggingface/transformers\";\n\n// Create a text generation pipeline\nconst generator = await pipeline(\n  \"text-generation\",\n  \"onnx-community/Qwen2.5-Coder-0.5B-Instruct\",\n  { dtype: \"q4\" },\n);\n\n// Define the list of messages\nconst messages = [\n  { role: \"system\", content: \"You are a helpful assistant.\" },\n  { role: \"user\", content:  \"Write a quick sort algorithm.\" },\n];\n\n// Create text streamer\nconst streamer = new TextStreamer(generator.tokenizer, {\n  skip_prompt: true,\n  // Optionally, do something with the text (e.g., write to a textbox)\n  // callback_function: (text) => { /* Do something with text */ },\n})\n\n// Generate a response\nconst result = await generator(messages, { max_new_tokens: 512, do_sample: false, streamer });\n```\n```\n\n```markdown\n```js\nimport { pipeline } from \"@huggingface/transformers\";\n\n// Create a feature-extraction pipeline\nconst extractor = await pipeline(\n  \"feature-extraction\",\n  \"mixedbread-ai/mxbai-embed-xsmall-v1\",\n  { device: \"webgpu\" },\n);\n\n// Compute embeddings\nconst texts = [\"Hello world!\", \"This is an example sentence.\"];\nconst embeddings = await extractor(texts, { pooling: \"mean\", normalize: true });\nconsole.log(embeddings.tolist());\n// [\n//   [-0.016986183822155, 0.03228696808218956, -0.0013630966423079371, ... ],\n//   [0.09050482511520386, 0.07207386940717697, 0.05762749910354614, ... ],\n// ]\n```\n```\n\n```markdown\nBefore Transformers.js v3, we used the `quantized` option to specify whether to use a quantized (q8) or full-precision (fp32) variant of the model by setting `quantized` to `true` or `false`, respectively. Now, we've added the ability to select from a much larger list with the `dtype` parameter.\n\nThe list of available quantizations depends on the model, but some common ones are: full-precision (`\"fp32\"`), half-precision (`\"fp16\"`), 8-bit (`\"q8\"`, `\"int8\"`, `\"uint8\"`), and 4-bit (`\"q4\"`, `\"bnb4\"`, `\"q4f16\"`).\n\n```\n\n```markdown\n```js\nimport { pipeline } from \"@huggingface/transformers\";\n\n// Create a text generation pipeline\nconst generator = await pipeline(\n  \"text-generation\",\n  \"onnx-community/Qwen2.5-0.5B-Instruct\",\n  { dtype: \"q4\", device: \"webgpu\" },\n);\n\n// Define the list of messages\nconst messages = [\n  { role: \"system\", content: \"You are a helpful assistant.\" },\n  { role: \"user\", content: \"Tell me a funny joke.\" },\n];\n\n// Generate a response\nconst output = await generator(messages, { max_new_tokens: 128 });\nconsole.log(output[0].generated_text.at(-1).content);\n```\n```\n\n```markdown\nSome encoder-decoder models, like Whisper or Florence-2, are extremely sensitive to quantization settings: especially of the encoder. For this reason, we added the ability to select per-module dtypes, which can be done by providing a mapping from module name to dtype.\n\n**Example:** Run Florence-2 on WebGPU ([demo](https://v2.scrimba.com/s0pdm485fo))\n\n```js\nimport { Florence2ForConditionalGeneration } from \"@huggingface/transformers\";\n\nconst model = await Florence2ForConditionalGeneration.from_pretrained(\n  \"onnx-community/Florence-2-base-ft\",\n  {\n    dtype: {\n      embed_tokens: \"fp16\",\n      vision_encoder: \"fp16\",\n      encoder_model: \"q4\",\n      decoder_model_merged: \"q4\",\n    },\n    device: \"webgpu\",\n  },\n);\n```\n```\n\n```javascript\n * **Example:** Disable remote models.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.allowRemoteModels = false;\n * ```\n * \n * **Example:** Set local model path.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.localModelPath = '/path/to/local/models/';\n * ```\n * \n * **Example:** Set cache directory.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.cacheDir = '/path/to/cache/directory/';\n * ```\n * \n * @module env\n */\n```\n\n```text\n| Task                     | ID | Description | Supported? |\n|--------------------------|----|-------------|------------|\n| [Fill-Mask](https://huggingface.co/tasks/fill-mask)                     | `fill-mask`   | Masking some of the words in a sentence and predicting which words should replace those masks. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.FillMaskPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=fill-mask&library=transformers.js) |\n| [Question Answering](https://huggingface.co/tasks/question-answering)   | `question-answering`   | Retrieve the answer to a question from a given text. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.QuestionAnsweringPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=question-answering&library=transformers.js) |\n| [Sentence Similarity](https://huggingface.co/tasks/sentence-similarity) | `sentence-similarity`  | Determining how similar two texts are. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.FeatureExtractionPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=sentence-similarity&library=transformers.js) |\n| [Summarization](https://huggingface.co/tasks/summarization)             |  `summarization`  | Producing a shorter version of a document while preserving its important information. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.SummarizationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=summarization&library=transformers.js) |\n| [Table Question Answering](https://huggingface.co/tasks/table-question-answering) |  `table-question-answering`  | Answering a question about information from a given table. | ❌ |\n| [Text Classification](https://huggingface.co/tasks/text-classification)      | `text-classification` or `sentiment-analysis`  | Assigning a label or class to a given text. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.TextClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=text-classification&library=transformers.js) |\n| [Text Generation](https://huggingface.co/tasks/text-generation#completion-generation-models)          | `text-generation`  | Producing new text by predicting the next word in a sequence. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.TextGenerationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=text-generation&library=transformers.js) |\n| [Text-to-text Generation](https://huggingface.co/tasks/text-generation#text-to-text-generation-models)  | `text2text-generation`  | Converting one text sequence into another text sequence. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.Text2TextGenerationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=text2text-generation&library=transformers.js) |\n| [Token Classification](https://huggingface.co/tasks/token-classification)     | `token-classification` or `ner`  | Assigning a label to each token in a text. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.TokenClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=token-classification&library=transformers.js) |\n| [Translation](https://huggingface.co/tasks/translation)              |  `translation`  | Converting text from one language to another. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.TranslationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=translation&library=transformers.js) |\n| [Zero-Shot Classification](https://huggingface.co/tasks/zero-shot-classification) | `zero-shot-classification`  | Classifying text into classes that are unseen during training.  | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ZeroShotClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=zero-shot-classification&library=transformers.js) |\n| [Feature Extraction](https://huggingface.co/tasks/feature-extraction)         |  `feature-extraction`  | Transforming raw data into numerical features that can be processed while preserving the information in the original dataset. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.FeatureExtractionPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=feature-extraction&library=transformers.js) |\n```\n\n```text\n| Task                     | ID | Description | Supported? |\n|--------------------------|----|-------------|------------|\n| [Background Removal](https://huggingface.co/tasks/image-segmentation#background-removal)       | `background-removal`   | Isolating the main subject of an image by removing or making the background transparent. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.BackgroundRemovalPipeline)<br>[(models)](https://huggingface.co/models?other=background-removal&library=transformers.js) |\n| [Depth Estimation](https://huggingface.co/tasks/depth-estimation)         |  `depth-estimation`  | Predicting the depth of objects present in an image. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.DepthEstimationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=depth-estimation&library=transformers.js) |\n| [Image Classification](https://huggingface.co/tasks/image-classification)                | `image-classification`   | Assigning a label or class to an entire image. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ImageClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=image-classification&library=transformers.js) |\n| [Image Segmentation](https://huggingface.co/tasks/image-segmentation)       | `image-segmentation`   | Divides an image into segments where each pixel is mapped to an object. This task has multiple variants such as instance segmentation, panoptic segmentation and semantic segmentation. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ImageSegmentationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=image-segmentation&library=transformers.js) |\n| [Image-to-Image](https://huggingface.co/tasks/image-to-image)      |  `image-to-image` | Transforming a source image to match the characteristics of a target image or a target image domain. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ImageToImagePipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=image-to-image&library=transformers.js) |\n| [Mask Generation](https://huggingface.co/tasks/mask-generation)            |  `mask-generation`  | Generate masks for the objects in an image. | ❌ |\n| [Object Detection](https://huggingface.co/tasks/object-detection)            | `object-detection`   | Identify objects of certain defined classes within an image. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ObjectDetectionPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=object-detection&library=transformers.js) |\n| [Video Classification](https://huggingface.co/tasks/video-classification) |  n/a  | Assigning a label or class to an entire video. | ❌ |\n| [Unconditional Image Generation](https://huggingface.co/tasks/unconditional-image-generation)      |  n/a   | Generating images with no condition in any context (like a prompt text or another image). | ❌ |\n| [Image Feature Extraction](https://huggingface.co/tasks/image-feature-extraction)         |  `image-feature-extraction`  | Transforming raw data into numerical features that can be processed while preserving the information in the original image. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ImageFeatureExtractionPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=image-feature-extraction&library=transformers.js) |\n```\n\n```text\n| Task                     | ID | Description | Supported? |\n|--------------------------|----|-------------|------------|\n| [Audio Classification](https://huggingface.co/tasks/audio-classification)         |  `audio-classification`  | Assigning a label or class to a given audio. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.AudioClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=audio-classification&library=transformers.js) |\n| [Audio-to-Audio](https://huggingface.co/tasks/audio-to-audio)         |  n/a  | Generating audio from an input audio source. | ❌ |\n| [Automatic Speech Recognition](https://huggingface.co/tasks/automatic-speech-recognition)         | `automatic-speech-recognition`  | Transcribing a given audio into text. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.AutomaticSpeechRecognitionPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition&library=transformers.js) |\n| [Text-to-Speech](https://huggingface.co/tasks/text-to-speech)         | `text-to-speech` or `text-to-audio` | Generating natural-sounding speech given text input. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.TextToAudioPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=text-to-audio&library=transformers.js) |\n```\n\n```text\n| Task                     | ID | Description | Supported? |\n|--------------------------|----|-------------|------------|\n| [Document Question Answering](https://huggingface.co/tasks/document-question-answering)         | `document-question-answering`  | Answering questions on document images. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.DocumentQuestionAnsweringPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=document-question-answering&library=transformers.js) |\n| [Image-to-Text](https://huggingface.co/tasks/image-to-text)         |  `image-to-text`  | Output text from a given image. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ImageToTextPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=image-to-text&library=transformers.js) |\n| [Text-to-Image](https://huggingface.co/tasks/text-to-image)         |  `text-to-image`  | Generates images from input text.  | ❌ |\n| [Visual Question Answering](https://huggingface.co/tasks/visual-question-answering)         |  `visual-question-answering`  | Answering open-ended questions based on an image. | ❌ |\n| [Zero-Shot Audio Classification](https://huggingface.co/learn/audio-course/chapter4/classification_models#zero-shot-audio-classification) | `zero-shot-audio-classification`  | Classifying audios into classes that are unseen during training. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ZeroShotAudioClassificationPipeline)<br>[(models)](https://huggingface.co/models?other=zero-shot-audio-classification&library=transformers.js) |\n| [Zero-Shot Image Classification](https://huggingface.co/tasks/zero-shot-image-classification) | `zero-shot-image-classification`  | Classifying images into classes that are unseen during training. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ZeroShotImageClassificationPipeline)<br>[(models)](https://huggingface.co/models?pipeline_tag=zero-shot-image-classification&library=transformers.js) |\n| [Zero-Shot Object Detection](https://huggingface.co/tasks/zero-shot-object-detection) | `zero-shot-object-detection`  | Identify objects of classes that are unseen during training. | ✅ [(docs)](https://huggingface.co/docs/transformers.js/api/pipelines#module_pipelines.ZeroShotObjectDetectionPipeline)<br>[(models)](https://huggingface.co/models?other=zero-shot-object-detection&library=transformers.js) |\n```\n"
  },
  {
    "path": "content/humanfriendly/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"humanfriendly package guide for Python text, terminal, and parsing utilities\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"humanfriendly,python,cli,terminal,formatting,utilities\"\n---\n\n# humanfriendly Python Package Guide\n\n## Golden Rule\n\nUse the official `humanfriendly` package when you need to parse or format human-readable values in Python. There is no client object, authentication flow, or service configuration: import the functions you need and call them directly.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"humanfriendly==10.0\"\n```\n\nIf you rely on ANSI styling on older Windows terminals, install `colorama` as well; the docs say `humanfriendly` will use it automatically when available:\n\n```bash\npython -m pip install \"humanfriendly==10.0\" colorama\n```\n\n## Initialization\n\nThere is no package-level initialization. Import the helpers you need:\n\n```python\nimport os\n\nfrom humanfriendly import (\n    InvalidSize,\n    InvalidTimespan,\n    coerce_boolean,\n    format_size,\n    format_timespan,\n    parse_path,\n    parse_size,\n    parse_timespan,\n)\n```\n\n## Common Workflows\n\n### Parse and format file sizes\n\nBy default `format_size()` and `parse_size()` use decimal units for ambiguous symbols like `KB` and `GB`. Pass `binary=True` when you want base-2 behavior for ambiguous units.\n\n```python\nfrom humanfriendly import InvalidSize, format_size, parse_size\n\nquota_bytes = parse_size(\"1.5 GB\")\ncache_bytes = parse_size(\"1 GiB\")\nlegacy_bytes = parse_size(\"1 GB\", binary=True)\n\nprint(quota_bytes)                 # 1500000000\nprint(cache_bytes)                 # 1073741824\nprint(legacy_bytes)                # 1073741824\nprint(format_size(cache_bytes))    # 1.07 GB\nprint(format_size(cache_bytes, binary=True))  # 1 GiB\n\ntry:\n    parse_size(\"5 Z\")\nexcept InvalidSize as exc:\n    print(f\"Invalid size: {exc}\")\n```\n\n### Parse timespans from flags, config, or user input\n\n`parse_timespan()` is meant for concise human input like `5m` or `1h`, not as an exact inverse of `format_timespan()`.\n\n```python\nfrom humanfriendly import InvalidTimespan, format_timespan, parse_timespan\n\npoll_interval = parse_timespan(\"2.5m\")\nprint(poll_interval)                    # 150.0\nprint(format_timespan(poll_interval))   # 2 minutes and 30 seconds\nprint(format_timespan(93784))           # 1 day, 2 hours and 3 minutes\n\ntry:\n    parse_timespan(\"1 age\")\nexcept InvalidTimespan as exc:\n    print(f\"Invalid timespan: {exc}\")\n```\n\n### Parse environment variables and path-like input\n\n`coerce_boolean()` is useful for strict env var parsing. `parse_path()` expands `~`, environment variables, and then returns an absolute path.\n\n```python\nimport os\n\nfrom humanfriendly import coerce_boolean, parse_path\n\ndebug_enabled = coerce_boolean(os.getenv(\"DEBUG\", \"false\"))\nlog_path = parse_path(os.getenv(\"APP_LOG_PATH\", \"~/logs/$USER/app.log\"))\n\nprint(debug_enabled)\nprint(log_path)\n```\n\nAccepted string booleans are `1`, `yes`, `true`, `on`, `0`, `no`, `false`, and `off`. Unknown strings raise `ValueError`, which is useful when you want configuration mistakes to fail fast.\n\n### Measure work or rate-limit a loop\n\n`Timer` instances stringify to a human-readable elapsed time. Resumable timers also work as context managers and expose `sleep()` for loop pacing.\n\n```python\nimport time\n\nfrom humanfriendly import Timer\n\nwith Timer(resumable=True) as timer:\n    time.sleep(1.2)\n    print(f\"Finished first step in {timer}\")\n\nfor item in range(3):\n    with Timer() as iteration_timer:\n        time.sleep(0.2)\n        print(f\"Processed {item} in {iteration_timer}\")\n\n    # Keep the loop at roughly one iteration per second.\n    Timer().sleep(1)\n```\n\nIf you want the timer to pause and resume across multiple `with` blocks, keep one resumable timer instance:\n\n```python\nimport time\n\nfrom humanfriendly import Timer\n\ntimer = Timer(resumable=True)\n\nwith timer:\n    time.sleep(0.5)\n\nwith timer:\n    time.sleep(0.5)\n\nprint(timer.elapsed_time)\nprint(timer.rounded)\n```\n\n### Prompt for input or a constrained choice\n\nUse the prompts helpers for simple terminal programs. `prompt_for_choice()` accepts a numeric selection or a unique substring of an option.\n\n```python\nfrom humanfriendly.prompts import prompt_for_choice, prompt_for_confirmation, prompt_for_input\n\nsize_text = prompt_for_input(\"Enter cache size\", default=\"512 MB\")\nregion = prompt_for_choice([\"us-east-1\", \"us-west-2\", \"eu-west-1\"], default=\"us-east-1\")\nconfirmed = prompt_for_confirmation(\"Apply settings?\", default=True)\n\nprint(size_text, region, confirmed)\n```\n\nIf standard input is not connected to a terminal, `prompt_for_input()` returns its `default` instead of blocking for input. `prompt_for_choice()` raises `ValueError` when given an empty list and skips prompting entirely when only one choice is available.\n\n### Render terminal-safe output, styles, and tables\n\nUse the terminal and table helpers when you want readable CLI output without building formatting code yourself.\n\n```python\nfrom humanfriendly.tables import format_smart_table\nfrom humanfriendly.terminal import ansi_wrap, message, output\n\nrows = [\n    [\"worker-a\", \"ready\", \"1.2 GB\"],\n    [\"worker-b\", \"draining\", \"850 MB\"],\n]\n\ntable = format_smart_table(rows, column_names=[\"Worker\", \"Status\", \"Memory\"])\n\noutput(ansi_wrap(\"Cluster summary\", color=\"green\", bold=True))\noutput(table)\nmessage(\"Wrote report to %s\", \"/tmp/report.txt\")\n```\n\nFor long blocking calls where you want terminal feedback, use `AutomaticSpinner` as a context manager:\n\n```python\nimport time\n\nfrom humanfriendly import AutomaticSpinner\n\nwith AutomaticSpinner(label=\"Waiting for subprocess\"):\n    time.sleep(3)\n```\n\n## Command-Line Interface\n\nThe package also installs a `humanfriendly` command. The official docs list these common options:\n\n```bash\nhumanfriendly --format-size 1500000000\nhumanfriendly --format-size 1500000000 --binary\nhumanfriendly --parse-size \"1.5 GB\"\nhumanfriendly --format-timespan 93784\nhumanfriendly --parse-length \"15.3cm\"\nhumanfriendly --format-table < data.txt\nhumanfriendly --demo\n```\n\n`--demo` is the quickest way to verify whether ANSI styling works in the current terminal.\n\n## Common Pitfalls\n\n- `KB`, `MB`, and `GB` default to decimal units. Use `binary=True` or explicit `KiB`/`MiB`/`GiB` when you need base-2 semantics.\n- `parse_timespan()` is optimized for short human input like `5m` and `1h`; do not treat it as an exact round-trip pair with `format_timespan()`.\n- `coerce_boolean()` is strict for strings. Values outside the documented true/false set raise `ValueError`.\n- `prompt_for_choice()` is terminal-oriented. In non-interactive environments, pass defaults explicitly or avoid prompting code paths.\n- ANSI color support on Windows may depend on native Windows 10 support or `colorama`.\n\n## Version Notes For 10.0\n\n- The Read the Docs site and PyPI project both document `humanfriendly 10.0`; PyPI’s latest release is still `10.0`.\n- The docs for 10.0 say the package is tested on Python 2.7, Python 3.5+, and PyPy 2.7. For new code, prefer Python 3, but do not assume the project has newer Python-specific documentation than what the 10.0 docs describe.\n- The 10.0 changelog notes a Windows `pyreadline` compatibility fix for Python 3.9+, updates to the Python 3 examples in the readme, and removal of the legacy `humanfriendly.compat.unittest` alias. If you maintain older code that imports that alias, it needs to change.\n\n## Official Sources\n\n- Documentation index: https://humanfriendly.readthedocs.io/en/latest/\n- Readme and CLI overview: https://humanfriendly.readthedocs.io/en/latest/readme.html\n- API reference: https://humanfriendly.readthedocs.io/en/latest/api.html\n- Changelog: https://humanfriendly.readthedocs.io/en/latest/changelog.html\n- PyPI package page: https://pypi.org/project/humanfriendly/\n"
  },
  {
    "path": "content/humanize/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"humanize Python package for turning numbers, sizes, dates, times, and lists into human-readable strings\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"humanize,python,formatting,i18n,time,filesize,numbers\"\n---\n\n# humanize Python Package Guide\n\n## Golden Rule\n\nUse `humanize` only for presentation. It turns values into user-facing strings like `1.2 million`, `an hour ago`, or `976.6 KiB`; it is not a parsing library and its output is locale-sensitive once translations are activated.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"humanize==4.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"humanize==4.15.0\"\npoetry add \"humanize==4.15.0\"\n```\n\nThe package has no runtime service credentials or API setup. PyPI lists only a `tests` extra.\n\n## Initialize\n\nMost projects only need a plain import:\n\n```python\nimport humanize\n```\n\nFor deterministic examples in tests or generated content, pass explicit values rather than calling `datetime.now()` inside the formatter code.\n\n## Core Usage\n\n### Numbers\n\nUse the top-level helpers for commas, short words, AP-style small numbers, and SI prefixes:\n\n```python\nimport humanize\n\nprint(humanize.intcomma(1_234_567.25))     # 1,234,567.25\nprint(humanize.intword(1_200_000_000))     # 1.2 billion\nprint(humanize.apnumber(7))                # seven\nprint(humanize.metric(1500, \"V\"))          # 1.50 kV\nprint(humanize.scientific(500))            # scientific notation string\n```\n\nNotes:\n\n- `intcomma()` and `intword()` accept `int`, `float`, and numeric strings.\n- If the value is not parseable, these helpers return `str(value)` instead of raising, so validate inputs before using the result in program logic.\n- In `4.15.0`, `intword()` gained locale-aware decimal separator support.\n\n### Dates and relative time\n\n`humanize` is most useful for display labels, activity feeds, and summaries:\n\n```python\nfrom datetime import datetime, timedelta, timezone\nimport humanize\n\nnow = datetime.now(timezone.utc)\n\nprint(humanize.naturalday(now))                            # today\nprint(humanize.naturaldate(now - timedelta(days=400)))     # includes year when far away\nprint(humanize.naturaldelta(timedelta(seconds=1001)))      # 16 minutes\nprint(humanize.naturaltime(now - timedelta(hours=2)))      # 2 hours ago\nprint(humanize.precisedelta(timedelta(days=2, seconds=33)))\n```\n\nUse `when=` when you need stable output relative to a fixed reference time:\n\n```python\nfrom datetime import datetime, timezone\nimport humanize\n\nreference = datetime(2026, 3, 12, 12, 0, tzinfo=timezone.utc)\ntarget = datetime(2026, 3, 12, 14, 30, tzinfo=timezone.utc)\n\nprint(humanize.naturaltime(target, when=reference))  # 2 hours from now\n```\n\nImportant behavior:\n\n- `naturaltime()` accepts a `datetime`, `timedelta`, or a numeric seconds value.\n- The `future=` flag is ignored for `datetime` and `timedelta`; tense is derived from the value relative to `when` or the current local time.\n- `months=True` uses 30.5-day month fuzziness between years.\n- `minimum_unit` is useful when sub-second output matters. `naturaldelta()` and `naturaltime()` support `seconds`, `milliseconds`, and `microseconds`.\n\n### Filesizes\n\nUse `naturalsize()` for decimal, binary, or GNU-style units:\n\n```python\nimport humanize\n\nprint(humanize.naturalsize(1_000_000))                 # 1.0 MB\nprint(humanize.naturalsize(1_000_000, binary=True))    # 976.6 KiB\nprint(humanize.naturalsize(1_000_000, gnu=True))       # 976.6K\n```\n\nDefault output uses decimal suffixes (`kB`, `MB`). Set `binary=True` for IEC units (`KiB`, `MiB`) when you need powers-of-two semantics.\n\n### Lists\n\n`natural_list()` is useful for UI text and error messages:\n\n```python\nfrom humanize import natural_list\n\nprint(natural_list([\"one\", \"two\", \"three\"]))  # one, two and three\n```\n\n### Localization\n\nTranslations are mutable library state. Activate a locale before formatting, then deactivate when you are done if the rest of the process should stay in English:\n\n```python\nimport humanize\n\nhumanize.i18n.activate(\"fr_FR\")\n\nprint(humanize.intcomma(12345))\nprint(humanize.intword(1234000))\n\nhumanize.i18n.deactivate()\n```\n\nUseful helpers:\n\n```python\nimport humanize\n\nhumanize.i18n.activate(\"fr_FR\")\nprint(humanize.i18n.decimal_separator())\nprint(humanize.i18n.thousands_separator())\nhumanize.i18n.deactivate()\n```\n\nIf `activate()` cannot find translation files, it raises `FileNotFoundError`. You can pass `path=` to load translations from a custom locale directory.\n\n## Configuration And Auth\n\nThere is no auth model, service endpoint, or environment-variable configuration. The main configuration surface is localization behavior:\n\n- Default behavior is effectively English.\n- `humanize.i18n.activate(locale)` switches the active translation for the current process context used by `humanize`.\n- `activate(None)` and locales starting with `en` behave like deactivation.\n- Custom translation bundles can be loaded with `humanize.i18n.activate(locale, path=\"/path/to/locales\")`.\n\n## Common Pitfalls\n\n- Do not store or compare `humanize` output as canonical data. Keep raw numbers, datetimes, and byte counts separately.\n- `naturaltime()` output depends on the current clock unless you pass `when=`.\n- Timezone handling is yours. Pass timezone-aware datetimes if your application mixes zones.\n- `intcomma()` and `intword()` may return the original value as a string for invalid inputs instead of failing loudly.\n- `precisedelta()` can round or promote units; review output before using it in strict UX copy.\n- Locale activation is shared state. In long-running apps, avoid flipping locales globally in ways that can leak across requests or concurrent tasks.\n\n## Version-Sensitive Notes\n\n- `4.15.0` adds locale support for the decimal separator in `intword()`.\n- `4.15.0` fixes `naturaldelta()` rounding to the nearest sensible unit and fixes `intword()` plural handling.\n- `4.14.0` dropped Python 3.9 support, which is why current PyPI metadata requires Python `>=3.10`.\n- The docs URL `https://python-humanize.readthedocs.io/en/latest/` still resolves, but PyPI and the repository point to `https://humanize.readthedocs.io/en/latest/` as the canonical docs root.\n\n## Official Links\n\n- Documentation: `https://humanize.readthedocs.io/en/latest/`\n- PyPI: `https://pypi.org/project/humanize/`\n- Repository: `https://github.com/python-humanize/humanize`\n- Releases: `https://github.com/python-humanize/humanize/releases`\n"
  },
  {
    "path": "content/hvplot/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"hvPlot plotting API for pandas, xarray, polars, DuckDB, and related Python data objects\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"hvplot,holoviz,plotting,pandas,xarray,polars,bokeh,panel\"\n---\n\n# hvPlot Python Package Guide\n\n## Golden Rule\n\nUse `hvplot` as a high-level plotting layer on top of HoloViews, and import the accessor module for the data type you actually use before calling `.hvplot(...)`. The default rendering backend is Bokeh; if you need Matplotlib or Plotly, set it explicitly with `hvplot.extension(...)` near process startup.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"hvplot==0.12.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"hvplot==0.12.2\"\npoetry add \"hvplot==0.12.2\"\n```\n\nNotes:\n\n- `hvplot` is the plotting layer. Install the data-library packages you actually plot, such as `pandas`, `xarray`, `polars`, `duckdb`, `ibis`, or `intake`.\n- Basic Bokeh-backed plotting works with the package install above. If you switch to a different backend or build richer apps, make sure the rest of that stack is installed and initialized.\n\n## Initialize\n\n### Pandas or Polars accessors\n\nImport the adapter module once, then use the `.hvplot` accessor on the object:\n\n```python\nimport pandas as pd\nimport hvplot.pandas\n\ndf = pd.DataFrame(\n    {\n        \"x\": [1, 2, 3, 4],\n        \"y\": [3, 1, 4, 2],\n        \"group\": [\"a\", \"a\", \"b\", \"b\"],\n    }\n)\n\nplot = df.hvplot.line(x=\"x\", y=\"y\", by=\"group\", title=\"Series by group\")\n```\n\n```python\nimport polars as pl\nimport hvplot.polars\n\ndf = pl.DataFrame({\"x\": [1, 2, 3], \"y\": [2, 4, 1]})\nplot = df.hvplot.scatter(x=\"x\", y=\"y\")\n```\n\n### Xarray accessor\n\n```python\nimport xarray as xr\nimport hvplot.xarray\n\nda = xr.DataArray(\n    [[1, 2, 3], [4, 5, 6]],\n    dims=(\"row\", \"col\"),\n    coords={\"row\": [\"a\", \"b\"], \"col\": [0, 1, 2]},\n)\n\nplot = da.hvplot.image(x=\"col\", y=\"row\")\n```\n\n### Explicit object API\n\nUse `hvPlot(...)` when you want the plotting helper without relying on an accessor import:\n\n```python\nimport pandas as pd\nfrom hvplot import hvPlot\n\ndf = pd.DataFrame({\"x\": [1, 2, 3], \"y\": [3, 1, 2]})\n\nplot = hvPlot(df).scatter(x=\"x\", y=\"y\")\n```\n\n## Backend And Display Setup\n\nThe default backend is Bokeh. Set a different backend before generating plots if your environment expects Matplotlib or Plotly:\n\n```python\nimport hvplot\n\nhvplot.extension(\"bokeh\")\n# hvplot.extension(\"matplotlib\")\n# hvplot.extension(\"plotly\")\n```\n\nFor notebook and app-style workflows, initialize Panel early when you expect widgets or servable views:\n\n```python\nimport panel as pn\nimport hvplot\n\npn.extension()\nhvplot.extension(\"bokeh\")\n```\n\nIf you want pandas-style `.plot(...)` calls to route through hvPlot, configure the pandas plotting backend:\n\n```python\nimport pandas as pd\nimport hvplot.pandas\n\npd.options.plotting.backend = \"hvplot\"\n```\n\nUse that mode for common plots, not as a guarantee of full pandas plotting API compatibility.\n\n## Core Usage\n\n### Common chart types\n\n```python\nimport pandas as pd\nimport hvplot.pandas\n\ndf = pd.DataFrame(\n    {\n        \"time\": [1, 2, 3, 4],\n        \"value\": [5, 3, 6, 8],\n        \"category\": [\"a\", \"a\", \"b\", \"b\"],\n    }\n)\n\nline = df.hvplot.line(x=\"time\", y=\"value\")\nscatter = df.hvplot.scatter(x=\"time\", y=\"value\", by=\"category\")\nhist = df.hvplot.hist(y=\"value\", bins=10)\n```\n\n### Grouping, faceting, and layout\n\n```python\nimport pandas as pd\nimport hvplot.pandas\n\ndf = pd.DataFrame(\n    {\n        \"x\": [1, 2, 3, 1, 2, 3],\n        \"y\": [3, 1, 4, 5, 2, 6],\n        \"species\": [\"adelie\", \"adelie\", \"adelie\", \"chinstrap\", \"chinstrap\", \"chinstrap\"],\n        \"island\": [\"Torgersen\", \"Torgersen\", \"Biscoe\", \"Dream\", \"Dream\", \"Dream\"],\n    }\n)\n\nplot = df.hvplot.scatter(\n    x=\"x\",\n    y=\"y\",\n    groupby=\"species\",\n    by=\"island\",\n    responsive=True,\n)\n```\n\n### Interactive pipeline\n\n`interactive` lets you build reactive data pipelines that stay linked to widgets:\n\n```python\nimport pandas as pd\nimport panel as pn\nimport hvplot.pandas\n\ndf = pd.DataFrame(\n    {\n        \"x\": [1, 2, 3, 4],\n        \"y\": [3, 2, 4, 5],\n        \"kind\": [\"a\", \"a\", \"b\", \"b\"],\n    }\n)\n\nselector = pn.widgets.Select(name=\"Kind\", options=[\"a\", \"b\"], value=\"a\")\nidf = df.interactive()\n\nview = idf[idf.kind == selector].hvplot.line(x=\"x\", y=\"y\")\n```\n\nThis is most useful in a live notebook or a Panel app, not in static markdown output.\n\n### Explorer UI\n\nUse `explorer(...)` when you want a quick visual exploration surface instead of hand-writing the plot config:\n\n```python\nimport pandas as pd\nfrom hvplot import explorer\n\ndf = pd.DataFrame(\n    {\n        \"x\": [1, 2, 3, 4],\n        \"y\": [4, 1, 3, 2],\n        \"group\": [\"a\", \"a\", \"b\", \"b\"],\n    }\n)\n\nui = explorer(df)\n```\n\nIf you are running a script or app, serve it explicitly:\n\n```python\nui.servable()\n```\n\n### Save or show outside a notebook\n\nFor script-driven output, prefer saving HTML artifacts:\n\n```python\nimport pandas as pd\nimport hvplot\nimport hvplot.pandas\n\ndf = pd.DataFrame({\"x\": [1, 2, 3], \"y\": [3, 1, 2]})\nplot = df.hvplot.line(x=\"x\", y=\"y\")\n\nhvplot.save(plot, \"plot.html\")\n```\n\nUse `hvplot.show(plot)` or a Panel server only when you need a live rendered view.\n\n## Configuration Notes\n\n- `hvplot` itself does not handle service authentication. Credentials belong to the data-source layer you are plotting from, such as DuckDB connections, Ibis backends, cloud warehouse clients, or remote filesystems.\n- Backend selection is process-global enough that it should be treated as startup configuration. Set it once near import time instead of switching backends mid-request.\n- For reusable dashboards, prefer a Panel app or saved HTML over relying on implicit notebook display hooks.\n\n## Common Pitfalls\n\n- `import hvplot` alone does not register `.hvplot` on pandas, xarray, polars, DuckDB, or other supported objects. Import the matching adapter module first.\n- The pandas plotting backend mode is intentionally not a full emulation of pandas plotting. It covers common cases, but not every pandas `.plot(...)` feature or edge case.\n- `interactive()` and `explorer()` create live widget-driven objects. They will not behave like plain static images in logs, CI output, or markdown rendering.\n- If a notebook cell shows nothing useful, check that you initialized the frontend extensions and that the backend you selected is available in that environment.\n- `hvplot` can plot many data libraries, but the data adapter and the underlying package still need to be installed. Support is not magical just because `hvplot` itself imports cleanly.\n\n## Version-Sensitive Notes For 0.12.2\n\n- `0.12.2` is the current PyPI release and requires Python `>=3.10`.\n- The `0.12.x` line dropped Python 3.9 support starting with `0.12.0`, so upgrade your runtime before pinning this version.\n- `0.12.2` includes fixes for DuckDB support and Pandas 3.0 compatibility. If your project mixes `hvplot` with newer pandas or DuckDB releases, prefer `0.12.2` or later in the `0.12.x` line.\n\n## Official Sources\n\n- Docs root: https://hvplot.holoviz.org/\n- User guide: https://hvplot.holoviz.org/getting_started/index.html\n- Supported data libraries: https://hvplot.holoviz.org/ref/data_libraries.html\n- Plotting extensions and backends: https://hvplot.holoviz.org/ref/plotting_extensions/index.html\n- Interactive guide: https://hvplot.holoviz.org/user_guide/Interactive.html\n- Explorer guide: https://hvplot.holoviz.org/user_guide/Explorer.html\n- Viewing and exporting: https://hvplot.holoviz.org/user_guide/Viewing.html\n- Release notes: https://hvplot.holoviz.org/releases.html\n- PyPI: https://pypi.org/project/hvplot/\n- GitHub releases: https://github.com/holoviz/hvplot/releases\n"
  },
  {
    "path": "content/hydra-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hydra configuration framework for Python apps with composable configs, structured configs, overrides, and multirun\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"hydra,configuration,cli,omegaconf,experiments,python\"\n---\n\n# Hydra Python Package Guide\n\n## Golden Rule\n\nUse `hydra-core` `1.3.2` with an explicit `version_base` and a deliberate config layout. In Hydra 1.3, the most common breakages come from implicit defaults: omitted `version_base`, unexpected working-directory changes, and confusion about where Hydra looks for configs. Prefer `@hydra.main(version_base=None, config_path=\"conf\", config_name=\"config\")` for normal app entrypoints, and use the Compose API only for notebooks, tests, or embedded flows.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"hydra-core==1.3.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"hydra-core==1.3.2\"\npoetry add \"hydra-core==1.3.2\"\n```\n\nVersion-sensitive note:\n\n- The Hydra `1.3` docs page lists Python `3.6-3.11` for the series, but the `1.3.2` release notes explicitly dropped Python `3.6`. For `1.3.2`, use Python `3.7-3.11`.\n\n## Initialize With YAML Config Files\n\nHydra works best when your application has a primary config plus optional config groups.\n\nExample layout:\n\n```text\nmy_app/\n  app.py\n  conf/\n    config.yaml\n    db/\n      sqlite.yaml\n      postgres.yaml\n```\n\nPrimary config:\n\n```yaml\n# conf/config.yaml\ndefaults:\n  - db: sqlite\n  - _self_\n\napp_name: demo\ndebug: false\n```\n\nConfig group options:\n\n```yaml\n# conf/db/sqlite.yaml\ndriver: sqlite\npath: /tmp/demo.db\n```\n\n```yaml\n# conf/db/postgres.yaml\ndriver: postgresql\nhost: localhost\nport: 5432\nuser: app\ndatabase: demo\n```\n\nApplication entrypoint:\n\n```python\nimport hydra\nfrom omegaconf import DictConfig, OmegaConf\n\n@hydra.main(version_base=None, config_path=\"conf\", config_name=\"config\")\ndef main(cfg: DictConfig) -> None:\n    print(OmegaConf.to_yaml(cfg))\n\nif __name__ == \"__main__\":\n    main()\n```\n\nRun with the default config:\n\n```bash\npython app.py\n```\n\nOverride from the command line:\n\n```bash\npython app.py db=postgres debug=true\n```\n\nRun multiple jobs:\n\n```bash\npython app.py --multirun db=sqlite,postgres\n```\n\n## Structured Configs With `ConfigStore`\n\nUse structured configs when you want dataclass-backed config validation and editor-friendly types.\n\n```python\nfrom dataclasses import dataclass, field\n\nimport hydra\nfrom hydra.core.config_store import ConfigStore\n\n@dataclass\nclass DBConfig:\n    driver: str = \"sqlite\"\n    path: str = \"/tmp/demo.db\"\n\n@dataclass\nclass AppConfig:\n    app_name: str = \"demo\"\n    debug: bool = False\n    db: DBConfig = field(default_factory=DBConfig)\n\ncs = ConfigStore.instance()\ncs.store(name=\"config\", node=AppConfig)\n\n@hydra.main(version_base=None, config_name=\"config\")\ndef main(cfg: AppConfig) -> None:\n    print(cfg.db.driver)\n\nif __name__ == \"__main__\":\n    main()\n```\n\nUse structured configs when:\n\n- you want type-checked defaults\n- you need a Python-native config schema\n- you want to register multiple named configs or config groups in code\n\nUse YAML config files when:\n\n- non-Python users need to edit config\n- you want config files to live next to deployment assets\n- the project already relies on Hydra defaults lists and file-based overrides\n\n## Compose API For Tests, Notebooks, And Embedded Use\n\nThe Compose API is useful when `@hydra.main()` is not practical, such as unit tests, Jupyter notebooks, or libraries embedding Hydra config composition.\n\n```python\nfrom hydra import compose, initialize\nfrom omegaconf import OmegaConf\n\nwith initialize(version_base=None, config_path=\"conf\"):\n    cfg = compose(config_name=\"config\", overrides=[\"db=postgres\", \"debug=true\"])\n\nprint(OmegaConf.to_yaml(cfg))\n```\n\nPrefer `@hydra.main()` for normal command-line apps. The Hydra docs warn that the Compose API does not provide the full `@hydra.main()` feature set such as shell tab completion, multirun, working-directory management, and some logging integration.\n\nIf your configs live in an importable Python module instead of a path relative to the caller, use `initialize_config_module()` or a `pkg://...` config path. Hydra `1.3.2` specifically added support for non-relative module paths in `config_path`, for example:\n\n```python\nimport hydra\n\n@hydra.main(version_base=None, config_path=\"pkg://my_app.conf\", config_name=\"config\")\ndef main(cfg):\n    ...\n```\n\n## Instantiate Python Objects From Config\n\nHydra can construct objects directly from config using `_target_`.\n\nConfig:\n\n```yaml\ntrainer:\n  _target_: my_app.training.Trainer\n  epochs: 10\n  lr: 0.001\n```\n\nPython:\n\n```python\nimport hydra\nfrom hydra.utils import instantiate\nfrom omegaconf import DictConfig\n\n@hydra.main(version_base=None, config_path=\"conf\", config_name=\"config\")\ndef main(cfg: DictConfig) -> None:\n    trainer = instantiate(cfg.trainer)\n    trainer.run()\n```\n\nThis pattern is common in ML and experiment codebases. It keeps object wiring in config instead of hardcoding class selection in Python.\n\n## Config, Secrets, And Runtime Behavior\n\nHydra does not handle service authentication. It only composes configuration. Treat credentials as application concerns and keep them out of committed config files.\n\nPractical guidance:\n\n- Keep secrets in environment variables, a secret manager, or local untracked overrides.\n- Do not commit real credentials into `conf/*.yaml`.\n- Pass environment-derived values into your app after Hydra composes the config, or inject them at runtime with command-line overrides.\n\nHydra-specific runtime behavior to configure explicitly:\n\n- `version_base`: set this on every `@hydra.main()` and `initialize()` call\n- `hydra.job.chdir`: decide whether each run should change into Hydra's output directory\n- `hydra.run.dir` and `hydra.sweep.dir`: set these if your project needs deterministic output locations\n- `hydra.searchpath`: use this only in the primary config when you need Hydra to search additional config sources\n\nExample working-directory configuration:\n\n```yaml\nhydra:\n  job:\n    chdir: false\n  run:\n    dir: outputs/${now:%Y-%m-%d}/${now:%H-%M-%S}\n```\n\nIn Hydra 1.2+, `version_base=None` implies the newer defaults, including `hydra.job.chdir=False`. If you depend on the older behavior that changes into the run directory, set `hydra.job.chdir=true` explicitly instead of relying on legacy defaults.\n\n## Debugging And Common CLI Helpers\n\nUseful commands when a config is not composing the way you expect:\n\n```bash\npython app.py --cfg job\npython app.py --cfg hydra\npython app.py --info searchpath\npython app.py --resolve --cfg job\n```\n\nWhen you need the full Python traceback instead of Hydra's shorter error formatting:\n\n```bash\nHYDRA_FULL_ERROR=1 python app.py\n```\n\n## Common Pitfalls\n\n- Omitting `version_base`. Hydra will warn, and default behavior can change across releases.\n- Omitting `_self_` in a defaults list when composition order matters. Hydra 1.1+ changed defaults-list composition behavior.\n- Using the Compose API in place of `@hydra.main()` for a normal CLI app. You lose important Hydra runtime behavior.\n- Forgetting that config search path issues are often the real cause of \"config not found\" failures. Check `--info searchpath`.\n- Setting `hydra.searchpath` outside the primary config. Hydra documents that this must be configured in the primary config.\n- Assuming Hydra will manage credentials. It will not; that logic belongs in your application.\n- Relying on the process working directory without checking `hydra.job.chdir`.\n- Decorating a `@hydra.main()` function without preserving `__wrapped__`. Hydra's docs require `@functools.wraps` on custom decorators so it can locate the config path correctly.\n\n## Version-Sensitive Notes For `1.3.2`\n\n- Pin documentation links to `https://hydra.cc/docs/1.3/...` instead of the unversioned docs root when targeting `hydra-core==1.3.2`.\n- Hydra `1.3.2` dropped Python `3.6`.\n- Hydra `1.3.2` added support for non-relative module paths in `config_path`, which makes packaged config modules easier to use.\n- Hydra `1.3.2` added `hydra.utils.get_object` for resolving a dotted path without instantiating it.\n- The `1.3` docs line is stable but not actively maintained; if a project is migrating beyond `1.3.x`, re-check the \"Next\" or newer versioned docs before copying behavior assumptions.\n\n## Official Sources\n\n- Docs root: `https://hydra.cc/docs/1.3/intro/`\n- Compose API: `https://hydra.cc/docs/1.3/advanced/compose_api/`\n- Search path: `https://hydra.cc/docs/1.3/advanced/search_path/`\n- Instantiate objects: `https://hydra.cc/docs/1.3/advanced/instantiate_objects/overview/`\n- Structured configs: `https://hydra.cc/docs/1.3/tutorials/structured_config/intro/`\n- `version_base` upgrade note: `https://hydra.cc/docs/1.3/upgrades/version_base/`\n- Working-directory behavior: `https://hydra.cc/docs/1.3/upgrades/1.1_to_1.2/changes_to_job_working_dir/`\n- Decorator guidance: `https://hydra.cc/docs/1.3/advanced/decorating_main/`\n- PyPI registry page: `https://pypi.org/project/hydra-core/`\n- `1.3.2` release notes: `https://github.com/facebookresearch/hydra/releases/tag/v1.3.2`\n"
  },
  {
    "path": "content/hypothesis/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hypothesis property-based testing library for Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.151.9\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"hypothesis,property-based-testing,testing,pytest,fuzzing,python\"\n---\n\n# Hypothesis Python Package Guide\n\n## Golden Rule\n\nUse Hypothesis to generate inputs and state transitions that exercise properties of your code, not to hard-code a long list of example test cases. Start with `pytest`, add `@given(...)`, and only tune settings when the default search becomes too slow or too strict for your test.\n\n## Install\n\nBasic install:\n\n```bash\npython -m pip install \"hypothesis==6.151.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"hypothesis==6.151.9\"\npoetry add \"hypothesis==6.151.9\"\n```\n\nUseful extras from the official docs:\n\n```bash\npython -m pip install \"hypothesis[pytest]==6.151.9\"\npython -m pip install \"hypothesis[cli]==6.151.9\"\npython -m pip install \"hypothesis[numpy,pandas]==6.151.9\"\npython -m pip install \"hypothesis[django]==6.151.9\"\n```\n\n- `pytest` extra: install the pytest integration\n- `cli` extra: install `hypothesis write`\n- domain extras such as `numpy`, `pandas`, and `django`: install first-party extension support\n\n## Minimal Setup\n\nHypothesis works with both `pytest` and `unittest`, but the common path is `pytest`.\n\n```python\nfrom hypothesis import given, strategies as st\n\n@given(st.lists(st.integers()))\ndef test_reverse_round_trip(xs: list[int]) -> None:\n    assert list(reversed(list(reversed(xs)))) == xs\n```\n\nRun the test with:\n\n```bash\npytest\n```\n\nWhat Hypothesis does for you:\n\n- generates many valid inputs from the strategy\n- shrinks failures to a smaller counterexample\n- stores failing examples in its local example database so they are retried first later\n\n## Core Usage Patterns\n\n### Basic strategies\n\nUse `hypothesis.strategies` (`st`) to describe the space of inputs you want:\n\n```python\nfrom hypothesis import given, strategies as st\n\n@given(\n    st.dictionaries(\n        keys=st.text(min_size=1, max_size=20),\n        values=st.integers(min_value=0, max_value=100),\n        max_size=20,\n    )\n)\ndef test_total_is_never_negative(counts: dict[str, int]) -> None:\n    assert sum(counts.values()) >= 0\n```\n\nCommon strategy building blocks:\n\n- `st.integers()`, `st.floats()`, `st.text()`, `st.binary()`, `st.booleans()`\n- `st.lists(...)`, `st.sets(...)`, `st.dictionaries(...)`, `st.tuples(...)`\n- `st.none() | st.text()` or `st.one_of(...)` for alternatives\n- `st.sampled_from(...)` for finite enums\n\n### Build domain objects\n\nUse `st.builds(...)` when your test targets constructors, dataclasses, or value objects:\n\n```python\nfrom dataclasses import dataclass\n\nfrom hypothesis import given, strategies as st\n\n@dataclass\nclass User:\n    id: int\n    name: str\n    is_admin: bool = False\n\nuser_strategy = st.builds(\n    User,\n    id=st.integers(min_value=1),\n    name=st.text(min_size=1, max_size=50),\n)\n\n@given(user_strategy)\ndef test_user_name_is_never_empty(user: User) -> None:\n    assert user.name\n```\n\n### Use `from_type()` and `register_type_strategy()` for typed APIs\n\nIf your code already uses type annotations, `st.from_type(...)` can infer strategies for many annotated types. For project-specific classes, register a strategy once and reuse it:\n\n```python\nfrom hypothesis.strategies import register_type_strategy\n\nregister_type_strategy(User, user_strategy)\n```\n\nThat lets later tests use `st.from_type(User)` without repeating the constructor logic.\n\n### Use `st.data()` when later draws depend on earlier values\n\nWhen you need dependent generation, draw values inside the test instead of encoding everything into one large strategy:\n\n```python\nfrom hypothesis import given, strategies as st\n\n@given(st.data())\ndef test_pop_reduces_length(data) -> None:\n    items = data.draw(st.lists(st.integers(), min_size=1, max_size=20))\n    index = data.draw(st.integers(min_value=0, max_value=len(items) - 1))\n    before = len(items)\n    items.pop(index)\n    assert len(items) == before - 1\n```\n\n## Configuration And Test Runner Integration\n\nHypothesis has no API credentials or service authentication. The main configuration surface is settings and runner integration.\n\nPer-test settings:\n\n```python\nfrom hypothesis import given, settings, strategies as st\n\n@settings(max_examples=200, deadline=None)\n@given(st.lists(st.integers(), max_size=200))\ndef test_sort_is_idempotent(xs: list[int]) -> None:\n    assert sorted(sorted(xs)) == sorted(xs)\n```\n\nSettings you will tune most often:\n\n- `max_examples`: how many generated examples to try\n- `deadline`: per-example execution deadline in milliseconds, or `None`\n- `derandomize`: deterministic generation, useful for CI profiles\n- `database`: where Hypothesis stores examples, or `None` to disable persistence\n- `suppress_health_check`: narrow opt-out for specific health checks when justified\n\nProject-wide profiles:\n\n```python\nfrom hypothesis import HealthCheck, settings\n\nsettings.register_profile(\n    \"ci\",\n    max_examples=500,\n    derandomize=True,\n    suppress_health_check=[HealthCheck.too_slow],\n)\n\nsettings.load_profile(\"ci\")\n```\n\nYou can also select a profile with the environment variable:\n\n```bash\nexport HYPOTHESIS_PROFILE=ci\npytest\n```\n\nUseful pytest flags from the official integration docs:\n\n```bash\npytest --hypothesis-profile=ci\npytest --hypothesis-show-statistics\npytest --hypothesis-verbosity=verbose\npytest --hypothesis-seed=12345\n```\n\n## Examples, Seeds, And Failure Reproduction\n\nUse the built-in reproduction tools before inventing your own debug harness.\n\n### Add explicit examples\n\n`@example(...)` forces specific inputs to run before generated cases:\n\n```python\nfrom hypothesis import example, given, strategies as st\n\n@example([])\n@example([0])\n@given(st.lists(st.integers()))\ndef test_reversed_twice_is_original(xs: list[int]) -> None:\n    assert list(reversed(list(reversed(xs)))) == xs\n```\n\n### Pin a deterministic seed\n\n`@seed(...)` or `--hypothesis-seed=...` is useful when you want a repeatable run while investigating a flaky or performance-sensitive test:\n\n```python\nfrom hypothesis import given, seed, strategies as st\n\n@seed(20260311)\n@given(st.text())\ndef test_text_round_trip(s: str) -> None:\n    assert s.encode(\"utf-8\").decode(\"utf-8\") == s\n```\n\n### Replay an exact failure\n\nHypothesis can emit `@reproduce_failure(...)` for a failing example. This is for short-lived local debugging only.\n\n- It is tied to the exact Hypothesis version that generated it.\n- It can stop working after an upgrade, downgrade, or even if internal encoding changes.\n- Do not keep it in long-lived committed tests.\n\n## Stateful Testing\n\nFor APIs with sequences of operations, use `RuleBasedStateMachine` instead of squeezing the whole workflow into one example:\n\n```python\nfrom hypothesis import strategies as st\nfrom hypothesis.stateful import RuleBasedStateMachine, invariant, rule\n\nclass SetMachine(RuleBasedStateMachine):\n    def __init__(self) -> None:\n        super().__init__()\n        self.items: set[int] = set()\n\n    @rule(x=st.integers())\n    def add_item(self, x: int) -> None:\n        self.items.add(x)\n\n    @invariant()\n    def contents_match_python_set_rules(self) -> None:\n        assert len(self.items) == len(set(self.items))\n\nTestSetMachine = SetMachine.TestCase\n```\n\nUse this for caches, queues, parsers, protocol clients, and CRUD APIs where bugs only appear after a sequence of actions.\n\n## CLI Ghostwriter\n\nIf you have the `cli` extra installed, Hypothesis can generate starter tests:\n\n```bash\nhypothesis write your_module.your_function\n```\n\nUse ghostwriter as scaffolding, not as the final test design. You still need to decide the actual invariants and edge cases that matter for your code.\n\n## Common Pitfalls\n\n- Avoid heavy use of `assume(...)` or `.filter(...)`. They can make generation inefficient and trigger health checks or unsatisfiable tests.\n- Do not hide real bugs by broadly suppressing health checks. Suppress only the specific check you understand.\n- Keep tests deterministic apart from Hypothesis input generation. Time, global state, randomness, filesystem races, and network calls are common sources of flaky failures.\n- Prefer properties over implementation snapshots. Hypothesis is strongest when you assert invariants, round-trips, ordering rules, idempotence, or equivalence between implementations.\n- Remember that the example database persists local failures. If behavior changes unexpectedly between runs, check whether `.hypothesis/` is replaying a previously found case.\n- Install the right extra for framework-specific helpers such as NumPy, pandas, or Django support.\n\n## Version-Sensitive Notes For 6.151.9\n\n- The official PyPI release and the docs currently align on `6.151.9`.\n- `hypothesis` now requires Python `>=3.10`; older project interpreters need an older Hypothesis release.\n- `@reproduce_failure(...)` is intentionally version-specific and should not be treated as a stable fixture format.\n- The built-in profile mechanism and `HYPOTHESIS_PROFILE` environment variable are the preferred way to keep local and CI settings aligned without hard-coding settings in every test.\n\n## Official Sources\n\n- Docs root: https://hypothesis.readthedocs.io/en/latest/\n- Quickstart: https://hypothesis.readthedocs.io/en/latest/quickstart.html\n- API reference: https://hypothesis.readthedocs.io/en/latest/reference/api.html\n- Strategies reference: https://hypothesis.readthedocs.io/en/latest/reference/strategies.html\n- Pytest integration and CLI: https://hypothesis.readthedocs.io/en/latest/integrations.html\n- First-party extensions: https://hypothesis.readthedocs.io/en/latest/extensions.html\n- Settings tutorial: https://hypothesis.readthedocs.io/en/latest/tutorial/settings.html\n- Flaky failures: https://hypothesis.readthedocs.io/en/latest/tutorial/flaky.html\n- Package registry: https://pypi.org/project/hypothesis/\n"
  },
  {
    "path": "content/identify/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"identify package guide for classifying files into tags in Python tooling\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.17\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"identify,python,files,pre-commit,automation\"\n---\n\n# identify Python Package Guide\n\n`identify` is a small utility package for classifying files into tags such as language, text or binary, executable state, and filesystem type. Use it when your tooling needs `pre-commit`-style file typing inside Python code.\n\nIt is a local helper library, not a network client:\n\n- Environment variables: none\n- Authentication: none\n- Client initialization: none\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"identify==2.6.17\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"identify==2.6.17\"\npoetry add \"identify==2.6.17\"\n```\n\nImport the package like this:\n\n```python\nfrom identify import identify\n```\n\n## Core API\n\nThe two helpers you will usually need are:\n\n- `identify.tags_from_path(path)` for a real filesystem path\n- `identify.tags_from_filename(filename)` when you only know the name\n\nBoth return a Python `set[str]` of tags.\n\n## Tag A Real File Or Directory\n\nUse `tags_from_path()` when the path already exists on disk.\n\n```python\nfrom identify import identify\n\ntags = identify.tags_from_path(\"src/app.py\")\n\nif {\"file\", \"text\", \"python\"} <= tags:\n    print(\"run Python-specific checks\")\n```\n\nThis is the right helper when file mode, symlinks, directories, or shebang-based detection matter.\n\n## Tag A Filename Before Writing It\n\nUse `tags_from_filename()` when you only have a file name, such as for generated outputs or archive entries.\n\n```python\nfrom identify import identify\n\ntags = identify.tags_from_filename(\"generated_config.py\")\n\nif \"python\" in tags:\n    print(\"generate Python-oriented content\")\n```\n\nThis only uses the filename. It cannot inspect file contents, executable bits, or symlink state.\n\n## Filter Files In A Repository Walk\n\n`identify` works well as a lightweight filter before linting, formatting, or custom analysis.\n\n```python\nfrom pathlib import Path\n\nfrom identify import identify\n\n\npython_files: list[Path] = []\n\nfor path in Path(\".\").rglob(\"*\"):\n    tags = identify.tags_from_path(str(path))\n    if {\"file\", \"text\", \"python\"} <= tags:\n        python_files.append(path)\n\nfor path in python_files:\n    print(path)\n```\n\nIf your tool only wants regular files, check for the `\"file\"` tag explicitly instead of assuming everything returned from a directory walk is a normal file.\n\n## Use Tags As Capability Checks\n\nTreat the returned set as a collection of capabilities or attributes.\n\n```python\nfrom identify import identify\n\ntags = identify.tags_from_path(\"scripts/release\")\n\nif \"executable\" in tags:\n    print(\"this path can be run directly\")\n\nif \"text\" in tags:\n    print(\"safe to process as text\")\n```\n\nMembership tests such as `\"python\" in tags` or subset checks such as `{\"file\", \"text\"} <= tags` are the practical way to consume the API.\n\n## Common Pitfalls\n\n- Use `tags_from_path()` for files that already exist and `tags_from_filename()` for names only.\n- Do not expect `tags_from_filename()` to infer executable or shebang-derived tags.\n- The return value is a set. Do not rely on tag ordering.\n- When working with `pathlib.Path`, pass `str(path)` if the surrounding code expects plain string paths.\n- Check for `\"file\"` when your logic should exclude directories, symlinks, or other filesystem entries.\n\n## When To Reach For identify\n\nUse `identify` when you need file classification as a library dependency inside Python automation. If you only need a fixed glob like `*.py`, plain path matching is simpler. `identify` becomes useful when filename rules are not enough and your tool needs the same kind of path tagging that `pre-commit` uses.\n"
  },
  {
    "path": "content/idna/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"idna package guide for Python - IDNA 2008 and UTS #46 domain handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"idna,dns,unicode,domain,punycode,internationalization\"\n---\n\n# idna Python Package Guide\n\n## Golden Rule\n\nUse the third-party `idna` package when you need IDNA 2008 or UTS #46 behavior. Do not assume Python's built-in `encodings.idna` codec is equivalent; upstream documents that as the older IDNA 2003 implementation.\n\n## Installation\n\nInstall the package:\n\n```bash\npython -m pip install idna\n```\n\nPin the documented version when behavior needs to match this entry exactly:\n\n```bash\npython -m pip install \"idna==3.11\"\n```\n\nAlternative package managers:\n\n```bash\nuv add idna==3.11\n```\n\n```bash\npoetry add idna==3.11\n```\n\nPyPI lists `idna` `3.11` as supporting Python `>=3.8`.\n\n## Setup\n\nThere is no service initialization, network client, or authentication step. Setup is just importing the module and deciding which conversion mode fits your input:\n\n- `idna.encode()` / `idna.decode()` for full domains\n- `idna.alabel()` / `idna.ulabel()` for single labels\n- `uts46=True` when you need browser-style compatibility mapping on user input before IDNA conversion\n\n## Core Usage\n\n### Convert a full domain\n\n```python\nimport idna\n\nascii_domain = idna.encode(\"ドメイン.テスト\")\nprint(ascii_domain)  # b'xn--eckwd4c7c.xn--zckzah'\n\nunicode_domain = idna.decode(ascii_domain)\nprint(unicode_domain)  # ドメイン.テスト\n```\n\n`encode()` returns `bytes`. `decode()` returns `str`.\n\n### Convert a single label\n\nUse label helpers when you already split the hostname or only need one component:\n\n```python\nimport idna\n\nlabel = idna.alabel(\"测试\")\nprint(label)  # b'xn--0zwm56d'\n\nunicode_label = idna.ulabel(label)\nprint(unicode_label)  # 测试\n```\n\n### Normalize user input with UTS #46\n\nPure IDNA 2008 is strict. Real user input often needs compatibility mapping first:\n\n```python\nimport idna\n\ntry:\n    idna.encode(\"Königsgäßchen\")\nexcept idna.InvalidCodepoint as exc:\n    print(exc)\n\nnormalized = idna.encode(\"Königsgäßchen\", uts46=True)\nprint(normalized)  # b'xn--knigsgchen-b4a3dun'\n```\n\nUse `uts46=True` when accepting domains from forms, CLIs, or copied text. Skip it if your input is already normalized and you want strict IDNA 2008 validation.\n\n### Use the codec interface\n\nIf you need codec-style integration, upstream exposes `idna.codec` and the `idna2008` codec:\n\n```python\nimport idna.codec\n\nwire_value = \"домен.испытание\".encode(\"idna2008\")\nprint(wire_value)\n\ntext_value = wire_value.decode(\"idna2008\")\nprint(text_value)\n```\n\n### Validate and normalize for application code\n\n```python\nimport idna\n\ndef normalize_domain(value: str) -> str:\n    try:\n        return idna.encode(value, uts46=True).decode(\"ascii\")\n    except idna.IDNAError as exc:\n        raise ValueError(f\"invalid internationalized domain: {value!r}\") from exc\n```\n\nThis is a common boundary pattern when your application stores hostnames as ASCII but accepts Unicode input.\n\n## Config And Auth\n\nThere is no API key, credential flow, or external service configuration.\n\nThe runtime choices that matter are:\n\n- Whether to use strict IDNA 2008 processing or `uts46=True`\n- Whether to process whole domains or individual labels\n- Whether downstream code expects `bytes` or ASCII `str`\n- Whether legacy migration code still passes `transitional=True`\n\nIn `3.11`, upstream notes that Unicode `16.0.0` removed transitional processing from UTS #46. That means `transitional=True` no longer changes results in current behavior. Treat it as legacy compatibility noise, not an active tuning knob.\n\n## Error Handling\n\nCatch `idna.IDNAError` for generic conversion failures. Upstream also documents more specific exceptions:\n\n- `idna.IDNABidiError` for invalid bidirectional labels\n- `idna.InvalidCodepoint` for disallowed characters\n- `idna.InvalidCodepointContext` for context-sensitive code point failures\n\nPrefer converting these into application-level validation errors instead of letting raw exceptions surface to users.\n\n## Common Pitfalls\n\n- `idna.encode()` returns `bytes`, not text. Call `.decode(\"ascii\")` if the rest of your code expects `str`.\n- Python's built-in `encodings.idna` codec is older IDNA 2003 behavior, not a drop-in replacement for this package.\n- `uts46=True` is a compatibility-mapping step for user input. It is not the same as strict validation.\n- `transitional=True` is effectively obsolete in `3.11` because Unicode `16.0.0` removed transitional processing from UTS #46.\n- Emoji domains and other labels outside the IDNA rules are rejected on purpose.\n- Process domains as dot-separated labels. If you already split them, use `alabel()` / `ulabel()` instead of repeatedly rejoining.\n- Do not rely on very old blog posts that say `idna` supports Python `3.6` or `3.7`; `3.11` requires Python `>=3.8`.\n- If you handle untrusted input, stay on modern releases. Upstream's `3.7` release fixed a crafted-input performance issue in `encode()`.\n\n## Version-Sensitive Notes\n\n- This doc covers `idna` `3.11`, released on `2025-10-12`.\n- The version used here `3.11` matches the current PyPI package version shown on the official project page as of `2026-03-12`.\n- Upstream's `v3.11` release switched the generated tables back to Unicode `16.0.0`, which changes some UTS #46 compatibility behavior compared with `3.10`.\n- The `v3.11` release also notes support for Python `3.14`.\n- `3.10` had temporarily reverted to Unicode `15.1.0`; if you are diffing behavior between `3.10` and `3.11`, check UTS #46 mapping outcomes rather than assuming they are identical.\n\n## Official Sources\n\n- Repository and README: `https://github.com/kjd/idna`\n- PyPI release page for `3.11`: `https://pypi.org/project/idna/3.11/`\n- Releases index: `https://github.com/kjd/idna/releases`\n- `v3.11` release note: `https://github.com/kjd/idna/releases/tag/v3.11`\n"
  },
  {
    "path": "content/imageio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"imageio package guide for Python: read and write images, videos, volumes, and scientific formats with the v3 API and optional plugins\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.37.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"imageio,images,video,numpy,io,tiff,gif,scientific-imaging\"\n---\n\n# imageio Python Package Guide\n\n## Golden Rule\n\nUse the v3 API unless you are intentionally maintaining older code:\n\n- Prefer `import imageio.v3 as iio`\n- Use plugin extras for the formats you actually need\n- Use `imageio.v2` only for legacy code that still relies on the older reader/writer behavior\n\n`imageio` is a NumPy-first IO layer for images, videos, volumetric data, and many scientific file formats. The package is lightweight by default and picks up broader format support through optional plugins.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"imageio==2.37.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"imageio==2.37.3\"\npoetry add \"imageio==2.37.3\"\n```\n\nOptional extras matter in practice because format support is plugin-driven:\n\n```bash\npython -m pip install \"imageio[pyav]==2.37.3\"\npython -m pip install \"imageio[ffmpeg]==2.37.3\"\npython -m pip install \"imageio[tifffile]==2.37.3\"\npython -m pip install \"imageio[full]==2.37.3\"\n```\n\nPractical guidance:\n\n- Use `pyav` for modern video decoding/encoding work when possible.\n- Use `ffmpeg` when you need the legacy ffmpeg plugin, webcam helpers, or existing ffmpeg-based examples.\n- Use `tifffile` for TIFF-heavy scientific workflows.\n- Use `full` only when you explicitly want broad optional dependency coverage.\n\nVerify what your environment installed:\n\n```bash\npython -c \"import imageio; print(imageio.__version__)\"\n```\n\n## Initialize And Choose An API\n\nPreferred import:\n\n```python\nimport imageio.v3 as iio\n```\n\nLegacy compatibility import:\n\n```python\nimport imageio.v2 as iio\n```\n\nMental model:\n\n- `imageio.v3` is the current high-level API.\n- `imageio.v2` exposes the older API surface and wraps many calls through the v3 backend.\n- Most common code paths start with `iio.imread(...)`, `iio.imwrite(...)`, `iio.imiter(...)`, `iio.improps(...)`, or `iio.immeta(...)`.\n\n## Core Usage\n\n### Read a single image into a NumPy array\n\n```python\nimport imageio.v3 as iio\n\nimage = iio.imread(\"photo.png\")\nprint(image.shape, image.dtype)\n```\n\n`imread()` returns an `ndarray`. For a normal RGB image, expect a shape like `(height, width, 3)`.\n\n### Write an array to disk\n\n```python\nimport imageio.v3 as iio\nimport numpy as np\n\nimage = np.zeros((128, 128, 3), dtype=np.uint8)\nimage[:, :, 0] = 255\n\niio.imwrite(\"red.png\", image)\n```\n\nWhen writing to bytes or file-like objects, pass an explicit extension so imageio can pick the correct backend:\n\n```python\nimport imageio.v3 as iio\n\npayload = iio.imwrite(\"<bytes>\", image, extension=\".png\")\n```\n\n### Iterate video or multi-frame data without loading everything at once\n\nUse `imiter()` for frame-by-frame processing:\n\n```python\nimport imageio.v3 as iio\n\nfor frame in iio.imiter(\"clip.mp4\", plugin=\"pyav\"):\n    print(frame.shape)\n```\n\nThis is usually the safer default for large videos, animated GIFs, and stacks because it avoids loading every frame into memory at once.\n\n### Inspect standardized properties and raw metadata\n\n```python\nimport imageio.v3 as iio\n\nprops = iio.improps(\"photo.jpg\")\nmeta = iio.immeta(\"photo.jpg\")\n\nprint(props.shape)\nprint(props.dtype)\nprint(meta)\n```\n\nUse `improps()` when you want a stable, plugin-independent summary. Use `immeta()` when you need format-specific metadata from the backend.\n\n### Work with sample assets, URLs, zip paths, and bytes\n\n`imageio` accepts more than ordinary filesystem paths:\n\n```python\nimport imageio.v3 as iio\n\nsample = iio.imread(\"imageio:chelsea.png\")\nremote = iio.imread(\"https://github.com/imageio/imageio-binaries/raw/master/images/chelsea.png\")\n```\n\nIn-memory streams also work:\n\n```python\nfrom io import BytesIO\nimport imageio.v3 as iio\n\nwith open(\"photo.jpg\", \"rb\") as f:\n    raw = f.read()\n\nimage = iio.imread(BytesIO(raw), extension=\".jpg\")\n```\n\nIf you are pulling protected URLs or data from custom transports, fetch the bytes yourself with your HTTP client and then pass a file object or `BytesIO` to imageio.\n\n### Use `imopen()` when you need explicit plugin control\n\n`imopen()` is the lower-level entry point when the one-shot helpers are too limiting:\n\n```python\nimport imageio.v3 as iio\n\nwith iio.imopen(\"clip.mp4\", \"r\", plugin=\"pyav\") as resource:\n    frame0 = resource.read(index=0)\n    props = resource.properties(index=0)\n    print(frame0.shape, props.shape)\n```\n\nReach for `imopen()` when you need:\n\n- an explicitly chosen plugin\n- repeated reads or writes through one opened resource\n- lower-level access to backend-specific behavior\n\n## Configuration And Environment\n\nThere is no auth model built into `imageio`. Configuration is mostly about plugin choice, transport constraints, and environment variables.\n\nImportant environment variables from the upstream docs:\n\n- `IMAGEIO_FORMAT_ORDER`: overrides plugin priority for a format, for example `\".tiff -TIFF +FEI\"`\n- `IMAGEIO_NO_INTERNET=1`: disables internet access, including automatic fetching of example images and remote resources\n- `IMAGEIO_REQUEST_TIMEOUT=5.0`: changes the timeout for reading remote resources over the network\n\nPractical setup guidance:\n\n- In CI or sandboxed environments, set `IMAGEIO_NO_INTERNET=1` if tests must not reach the network.\n- If backend auto-detection picks the wrong plugin, pass `plugin=\"...\"` explicitly instead of relying on global ordering.\n- For remote resources behind auth, proxies, signed URLs, or custom headers, do the network request outside imageio and pass the resulting bytes or stream.\n\n## Common Pitfalls\n\n- `imageio.v2` and `imageio.v3` are not interchangeable. New code should not mix both styles casually.\n- Optional backends are not installed automatically. A missing plugin dependency often shows up as a runtime read/write failure for only one format family.\n- For writes to `<bytes>` or arbitrary file-like objects, pass `extension=\".png\"` or similar so backend selection is deterministic.\n- `imiter()` is usually better than `imread()` for large multi-frame resources. Loading every frame eagerly can consume a lot of memory.\n- `immeta()` returns backend-specific metadata and can vary by plugin. Use `improps()` when you need a normalized shape/dtype summary.\n- Remote URL support is convenient for public resources, not a full HTTP client abstraction.\n- Some example pages still use `imageio:chelsea.png` sample assets or public GitHub URLs. Those patterns are fine for tests and demos, but production code should use your own asset source explicitly.\n\n## Version-Sensitive Notes For 2.37.3\n\n- `2.37.3` is the current version on PyPI as of `2026-03-12`, released on `2026-03-09`.\n- The stable docs home and PyPI metadata now target Python `>=3.10`.\n- The installation page in the stable docs still says `imageio` supports Python `3.5+`, which is stale relative to the current package metadata. Trust PyPI metadata and the current package configuration when deciding compatibility.\n- The v2 API remains available, but the upstream docs treat it as a compatibility layer around the newer v3 machinery. Prefer `imageio.v3` in new code.\n- The upstream user API docs explicitly point older `imageio.imread(...)` and similar patterns toward `imageio.v2` for backward-compatible behavior. If you are fixing an old codebase, importing `imageio.v2 as imageio` is often the least disruptive migration step before a fuller v3 rewrite.\n\n## Official Sources\n\n- Docs root: https://imageio.readthedocs.io/en/stable/\n- Installation: https://imageio.readthedocs.io/en/stable/getting_started/installation.html\n- Core v3 API: https://imageio.readthedocs.io/en/stable/reference/core_v3.html\n- User API and v2/v3 migration notes: https://imageio.readthedocs.io/en/stable/reference/userapi.html\n- Fancy sources and `BytesIO` examples: https://imageio.readthedocs.io/en/stable/examples.html#read-from-fancy-sources\n- Package metadata: https://pypi.org/project/imageio/\n- Repository: https://github.com/imageio/imageio\n"
  },
  {
    "path": "content/importlib-metadata/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Backport of importlib.metadata for reading installed distribution metadata and entry points in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.7.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,packaging,metadata,entry-points,importlib\"\n---\n\n# importlib-metadata Python Package Guide\n\nUse `importlib-metadata` when you need the backport of `importlib.metadata`, want a consistent metadata API across Python versions, or are migrating older `pkg_resources` metadata code.\n\n## Golden Rule\n\n- The PyPI package name is `importlib-metadata`, but the import name is `importlib_metadata`.\n- The library works on installed distribution metadata, not arbitrary import names.\n- On Python versions where the standard library is sufficient, prefer `from importlib import metadata`.\n- Install the backport when you need features or behavior newer than the stdlib copy bundled with the interpreter.\n- Query distribution names such as `importlib-metadata`, `wheel`, or `PyYAML`, not import package names such as `importlib_metadata`, `wheel`, or `yaml`.\n\n## Version Scope\n\n- Package covered here: `importlib-metadata==8.7.1`\n- Version used here: `8.7.1`\n- Release date for `8.7.1`: `2025-12-21`\n- Python requirement on PyPI: `>=3.9`\n- Docs drift note: the source URL `https://importlib-metadata.readthedocs.io/en/latest/` is a moving target and rendered `8.7.2.dev1+gd8a7576de` on `2026-03-12`; use the official `stable` pages for `8.7.1`-anchored behavior.\n\nThe examples below stay on APIs available in `8.7.1`.\n\n## Install\n\n```bash\npip install importlib-metadata==8.7.1\n```\n\nIf you only need the backport on interpreters where the stdlib copy is older than the behavior you want, use an environment marker in project metadata:\n\n```toml\ndependencies = [\n  \"importlib-metadata>=8.7.1; python_version < '3.10'\",\n]\n```\n\nIf you need one pinned behavior across all supported interpreters, install it unconditionally and use the compatibility import shown below.\n\n## Setup and Import Pattern\n\nThere is no auth, network setup, or environment-variable configuration. The package reads metadata from distributions that are installed in the current Python environment and discoverable on `sys.path`.\n\n### Backport-only import\n\n```python\nfrom importlib_metadata import (\n    PackageNotFoundError,\n    distribution,\n    entry_points,\n    files,\n    metadata,\n    packages_distributions,\n    requires,\n    version,\n)\n```\n\n### Cross-version compatibility import\n\nUse this when the same codebase may run with either the stdlib module or the backport:\n\n```python\ntry:\n    from importlib import metadata as importlib_metadata\nexcept ImportError:\n    import importlib_metadata\n```\n\nThen call everything through `importlib_metadata`:\n\n```python\nwheel_version = importlib_metadata.version(\"wheel\")\n```\n\nThis follows the upstream recommendation: start with the stdlib docs for usage, but substitute `importlib_metadata` for `importlib.metadata` when using the backport.\n\n## Core Usage\n\n### Get the installed version of a distribution\n\n```python\nfrom importlib_metadata import PackageNotFoundError, version\n\ndef get_dist_version(dist_name: str) -> str | None:\n    try:\n        return version(dist_name)\n    except PackageNotFoundError:\n        return None\n\nprint(get_dist_version(\"pip\"))\n```\n\nUse the distribution name from packaging metadata. That is not always the same as the import name used in Python code.\n\n### Read package metadata\n\n```python\nfrom importlib_metadata import metadata, requires\n\ndist_meta = metadata(\"setuptools\")\n\nprint(dist_meta[\"Name\"])\nprint(dist_meta[\"Summary\"])\nprint(dist_meta.json[\"requires_python\"])\nprint(requires(\"setuptools\") or [])\n```\n\n`metadata()` returns message-style package metadata, and `.json` exposes a JSON-compatible view of the same data. `requires()` returns dependency requirement strings or `None`.\n\n### Discover entry points\n\nModern code should use the selectable `entry_points()` API:\n\n```python\nfrom importlib_metadata import entry_points\n\nconsole_scripts = entry_points(group=\"console_scripts\")\n\nfor ep in console_scripts:\n    if ep.name == \"uvicorn\":\n        print(ep.value)\n```\n\nYou can also filter by both group and name:\n\n```python\nfrom importlib_metadata import entry_points\n\nmatches = entry_points(group=\"pytest11\", name=\"pytest_cov\")\n\nfor ep in matches:\n    plugin = ep.load()\n    print(plugin)\n```\n\nDo not write new code assuming `entry_points()` returns a dict keyed by group. In modern `importlib_metadata`, it returns an `EntryPoints` collection.\n\n### Inspect installed files\n\n```python\nfrom importlib_metadata import files\n\ndist_files = files(\"wheel\")\nif dist_files is not None:\n    for path in dist_files:\n        if path.name == \"METADATA\":\n            print(path.locate())\n```\n\nUse this when you need the installed file list or an on-disk path for a distribution artifact.\n\n### Work with a `Distribution` object\n\n```python\nfrom importlib_metadata import distribution\n\ndist = distribution(\"wheel\")\n\nprint(dist.version)\nprint(dist.metadata[\"Name\"])\n\nif getattr(dist, \"origin\", None) is not None:\n    print(dist.origin.url)\n```\n\nUse `distribution()` when you want one object that exposes `version`, `metadata`, `files`, and related properties together.\n\n### Map import packages to owning distributions\n\n```python\nfrom importlib_metadata import packages_distributions\n\nmapping = packages_distributions()\n\nprint(mapping.get(\"yaml\"))\nprint(mapping.get(\"google\"))\n```\n\nThis is the official way to answer \"which installed distribution provides this import package?\".\n\n## Environment and Runtime Notes\n\n- The package only sees distributions installed in the interpreter environment that is currently running your code.\n- In virtualenv-heavy tooling, run the lookup inside the target environment instead of the system interpreter.\n- It works with discoverable `dist-info` or `egg-info` metadata and primarily targets packages installed by standard PyPA tooling.\n- By default it reads from file system and zip-based distributions visible on `sys.path`.\n- There are no environment variables, credentials, or service endpoints to configure.\n\n## Common Pitfalls\n\n- Package name and import name differ: install `importlib-metadata`, import `importlib_metadata`.\n- Distribution names and import package names are not 1:1. Use `packages_distributions()` when you only know the import name.\n- `version()`, `metadata()`, `files()`, and `requires()` raise `PackageNotFoundError` when the distribution is not installed.\n- `files()` can return `None` if the installed distribution metadata does not expose a file list. Guard before iterating.\n- Namespace packages may map to multiple distributions, and some editable installs do not supply complete top-level name metadata.\n- `importlib_metadata` is not a `pkg_resources` working-set manager. It does not support multi-version installs or `require()` semantics.\n- Entry points are not automatically validated the way `pkg_resources.iter_entry_points()` behaved. Access a property such as `ep.name` or call `ep.load()` to force real use.\n- `EntryPoint.load()` does not verify that declared extras are installed.\n- Do not write new code against the old dict-like `entry_points()` behavior. Use `entry_points(group=...)` or `.select(...)`.\n\n## Version-Sensitive Notes\n\n- `8.7.1` includes fixes for FastPath behavior under fork-multiprocessing. If metadata discovery behaves strangely only after a fork, do not copy pre-`8.7.1` workarounds blindly.\n- `8.7.0` changed `.metadata()` and `Distribution.metadata` so they can return `None` when a metadata directory exists but no metadata file is present. Guard if you inspect broken or partially installed distributions.\n- `importlib_metadata 7.0` roughly corresponds to the copy merged into Python `3.13`, `6.5` to `3.12`, `4.13` to `3.11`, `4.6` to `3.10`, and `1.4` to `3.8`. If you are debugging version drift between stdlib and backport behavior, check that mapping first.\n- The backport can be ahead of the stdlib copy that ships with a given interpreter. If you need one consistent feature set across Python versions, standardize on the compatibility import pattern above.\n- The official docs homepage points readers at the Python standard library documentation for general usage. That is correct, but remember the import path changes between stdlib (`importlib.metadata`) and the backport (`importlib_metadata`).\n\n## Recommended Agent Workflow\n\n1. Confirm whether the target project should use the stdlib module or the backport.\n2. Use distribution names for lookups unless you explicitly map from imports with `packages_distributions()`.\n3. Wrap metadata lookups in `PackageNotFoundError` handling when the target distribution may be optional.\n4. Guard `files()` and, for `8.7.0+`, be prepared for `metadata()` to be absent on malformed installs.\n5. Prefer `entry_points(group=..., name=...)` selection style instead of older compatibility patterns.\n6. If you are migrating from `pkg_resources`, plan replacement for working-set behavior separately. `importlib_metadata` only covers metadata discovery.\n\n## Official Sources\n\n- Stable docs root: https://importlib-metadata.readthedocs.io/en/stable/\n- Migration guide: https://importlib-metadata.readthedocs.io/en/stable/migration.html\n- Release history: https://importlib-metadata.readthedocs.io/en/stable/history.html\n- Python stdlib reference: https://docs.python.org/3/library/importlib.metadata.html\n- PyPI project page: https://pypi.org/project/importlib-metadata/8.7.1/\n"
  },
  {
    "path": "content/importlib-resources/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"importlib-resources package guide for Python projects reading package data with the Traversable API\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.5.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"python,resources,importlib,packaging,files\"\n---\n\n# importlib-resources Python Package Guide\n\n## Golden Rule\n\nUse `importlib_resources.files()` as the default API for package data. Treat resources as package contents, not as paths computed from `__file__`.\n\nThis package has:\n\n- No environment variables\n- No client object or initialization step\n- A different import name than its PyPI name: install `importlib-resources`, import `importlib_resources`\n\n## Install\n\n`importlib-resources 6.5.2` requires Python 3.9 or newer.\n\n```bash\npython -m pip install \"importlib-resources==6.5.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"importlib-resources==6.5.2\"\npoetry add \"importlib-resources==6.5.2\"\n```\n\nIf your project only targets a recent CPython and does not need the backport package, you can often use the stdlib module instead:\n\n```python\nfrom importlib.resources import files, as_file\n```\n\nFor code that should use the PyPI package explicitly:\n\n```python\nfrom importlib_resources import files, as_file\n```\n\n## Basic Pattern\n\nAssume this package layout:\n\n```text\nmyapp/\n  data/\n    defaults.json\n    schema.sql\n```\n\nRead a text resource:\n\n```python\nfrom importlib_resources import files\n\ndefaults = files(\"myapp.data\").joinpath(\"defaults.json\").read_text(encoding=\"utf-8\")\nprint(defaults)\n```\n\nRead bytes:\n\n```python\nfrom importlib_resources import files\n\npayload = files(\"myapp.data\").joinpath(\"schema.sql\").read_bytes()\n```\n\nUse an imported module instead of a string if that is clearer in your app:\n\n```python\nimport myapp.data\nfrom importlib_resources import files\n\ndefaults_path = files(myapp.data).joinpath(\"defaults.json\")\n```\n\n## When You Need A Real Filesystem Path\n\nResources may come from a wheel, a zip import, or another loader-backed source. If another API needs an actual `pathlib.Path`, wrap the resource with `as_file()`.\n\n```python\nfrom importlib_resources import as_file, files\n\nresource = files(\"myapp.data\").joinpath(\"schema.sql\")\n\nwith as_file(resource) as schema_path:\n    with schema_path.open(\"r\", encoding=\"utf-8\") as fh:\n        sql = fh.read()\n```\n\nThis is the direct replacement for older code that expected `pkg_resources.resource_filename()`.\n\n## Directory Traversal\n\n`files()` returns a `Traversable` object, so you can inspect package contents without assuming a normal on-disk directory.\n\n```python\nfrom importlib_resources import files\n\nroot = files(\"myapp.data\")\n\nfor entry in root.iterdir():\n    kind = \"dir\" if entry.is_dir() else \"file\"\n    print(entry.name, kind)\n```\n\nCheck for a specific resource before reading it:\n\n```python\nfrom importlib_resources import files\n\nconfig = files(\"myapp.data\").joinpath(\"defaults.json\")\n\nif config.is_file():\n    settings_text = config.read_text(encoding=\"utf-8\")\n```\n\n## Legacy Helper Functions\n\nThe package still exposes convenience helpers such as `read_text()`, `read_binary()`, `open_text()`, and `open_binary()`, but new code is usually clearer with `files()`.\n\n```python\nfrom importlib_resources import read_text\n\ndefaults = read_text(\"myapp.data\", \"defaults.json\", encoding=\"utf-8\")\n```\n\nFor anything more complex than a single file read, switch back to `files()` and `Traversable`.\n\n## Migration From `pkg_resources`\n\nIf you are replacing `setuptools.pkg_resources`, use these patterns:\n\n- `pkg_resources.resource_filename(pkg, name)` -> `with as_file(files(pkg).joinpath(name)) as path:`\n- `pkg_resources.resource_stream(pkg, name)` -> `files(pkg).joinpath(name).open(\"rb\")`\n- `pkg_resources.resource_string(pkg, name)` -> `files(pkg).joinpath(name).read_bytes()`\n- `pkg_resources.resource_listdir(pkg, subdir)` -> `[entry.name for entry in files(pkg).joinpath(subdir).iterdir()]`\n\nExample:\n\n```python\nfrom importlib_resources import as_file, files\n\ntemplate = files(\"myapp.data\").joinpath(\"templates\", \"report.html\")\n\nwith as_file(template) as path:\n    render_report(path)\n```\n\n## Namespace Packages\n\nNamespace packages are supported. The important restriction is that two distributions contributing to the same namespace must not publish resources with the same name in the same virtual location.\n\nKeep namespace resource names unique across distributions or resource lookups become unsupported.\n\n## Version-Sensitive Notes\n\n- `6.5.2` is a `6.x` release line that requires Python 3.9+.\n- The maintainers document `6.0` as the backport line aligned with Python 3.13 behavior.\n- The stdlib `anchor` rename and omitted-anchor behavior were added later in CPython; the Python docs call out `importlib_resources >= 5.10` as the compatible interface for older interpreters.\n\nFor portable application code, pass the anchor explicitly:\n\n```python\nfrom importlib_resources import files\n\nconfig = files(\"myapp.data\").joinpath(\"defaults.json\")\n```\n\nThat avoids relying on caller inference if some environments still use the stdlib module on Python versions before 3.12.\n\n## Common Pitfalls\n\n- Install name and import name differ: `pip install importlib-resources`, but `import importlib_resources`.\n- Do not build paths with `Path(__file__).parent / ...` for package data you intend to ship in wheels.\n- Use `as_file()` only when another API truly needs a real path. For direct reads, prefer `read_text()`, `read_bytes()`, or `open()`.\n- Do not assume resources live on a normal filesystem. `Traversable` is the supported abstraction.\n- If you maintain a namespace package, avoid same-named resources across namespace portions.\n\n## Official Sources\n\n- Maintainer docs: https://importlib-resources.readthedocs.io/en/latest/\n- Using the package: https://importlib-resources.readthedocs.io/en/latest/using.html\n- Migration guide: https://importlib-resources.readthedocs.io/en/latest/migration.html\n- Release history: https://importlib-resources.readthedocs.io/en/latest/history.html\n- PyPI package page: https://pypi.org/project/importlib-resources/6.5.2/\n- Python stdlib reference: https://docs.python.org/3/library/importlib.resources.html\n"
  },
  {
    "path": "content/influxdb-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"InfluxDB Python client for writing, querying, and managing InfluxDB 2.x from Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.50.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"influxdb,time-series,flux,python,database,observability\"\n---\n\n# influxdb-client Python Package Guide\n\n## Golden Rule\n\nUse `influxdb-client` for InfluxDB 2.x and Flux-based workflows. The package import is `influxdb_client`, not `influxdb`.\n\nAs of March 12, 2026, PyPI lists `influxdb-client 1.50.0`, which matches the version used here. Upstream describes this package as the Python client for InfluxDB 2.x and Flux. If you are targeting InfluxDB 3.x, use the official v3 client instead. If you are maintaining old `influxdb-python` code, do not assume the APIs are backwards compatible.\n\n## Install\n\nBase install:\n\n```bash\npython -m pip install \"influxdb-client==1.50.0\"\n```\n\nRecommended install with faster datetime parsing:\n\n```bash\npython -m pip install \"influxdb-client[ciso]==1.50.0\"\n```\n\nAsync support:\n\n```bash\npython -m pip install \"influxdb-client[async]==1.50.0\"\n```\n\nIf you plan to use pandas-heavy paths, install pandas separately and keep the `ciso` extra enabled when possible.\n\n## Required Connection Settings\n\nFor most InfluxDB 2.x and Cloud setups you need:\n\n- `url`: base URL such as `http://localhost:8086` or your Cloud URL\n- `token`: API token\n- `org`: default organization for writes and queries\n- `bucket`: target bucket for writes\n\nEnvironment variables supported by `from_env_properties()`:\n\n```bash\nexport INFLUXDB_V2_URL=\"http://localhost:8086\"\nexport INFLUXDB_V2_TOKEN=\"your-token\"\nexport INFLUXDB_V2_ORG=\"your-org\"\nexport INFLUXDB_V2_TIMEOUT=\"10000\"\n```\n\nFor local development, a `.env` file plus `python-dotenv` is enough:\n\n```env\nINFLUXDB_V2_URL=http://localhost:8086\nINFLUXDB_V2_TOKEN=your-token\nINFLUXDB_V2_ORG=your-org\nINFLUXDB_V2_BUCKET=telemetry\n```\n\n## Initialize The Client\n\nThe safest default for scripts and request/response handlers is a context manager plus synchronous writes:\n\n```python\nimport os\n\nfrom dotenv import load_dotenv\nfrom influxdb_client import InfluxDBClient\nfrom influxdb_client.client.write_api import SYNCHRONOUS\n\nload_dotenv()\n\nurl = os.environ[\"INFLUXDB_V2_URL\"]\ntoken = os.environ[\"INFLUXDB_V2_TOKEN\"]\norg = os.environ[\"INFLUXDB_V2_ORG\"]\nbucket = os.environ[\"INFLUXDB_V2_BUCKET\"]\n\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    write_api = client.write_api(write_options=SYNCHRONOUS)\n    query_api = client.query_api()\n```\n\nIf you already store connection settings in an INI, TOML, or JSON config file:\n\n```python\nfrom influxdb_client import InfluxDBClient\n\nclient = InfluxDBClient.from_config_file(\"influxdb.ini\")\n```\n\nOr load directly from the `INFLUXDB_V2_*` environment variables:\n\n```python\nfrom influxdb_client import InfluxDBClient\n\nclient = InfluxDBClient.from_env_properties()\n```\n\nMinimal INI example:\n\n```ini\n[influx2]\nurl = http://localhost:8086\norg = my-org\ntoken = my-token\ntimeout = 10000\nverify_ssl = true\n```\n\n## Core Usage\n\n### Write points\n\nUse `Point` objects or line protocol. `Point` is usually clearer and safer for agents.\n\n```python\nfrom influxdb_client import InfluxDBClient, Point\nfrom influxdb_client.client.write_api import SYNCHRONOUS\n\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    write_api = client.write_api(write_options=SYNCHRONOUS)\n\n    point = (\n        Point(\"cpu\")\n        .tag(\"host\", \"web-1\")\n        .field(\"usage_idle\", 91.2)\n    )\n\n    write_api.write(bucket=bucket, record=point)\n```\n\nThe client also accepts line protocol strings, dict-like records, dataclasses, named tuples, pandas DataFrames, and lists of those record types.\n\n### Query with Flux\n\nThis client is built around Flux queries:\n\n```python\nfrom influxdb_client import InfluxDBClient\n\nquery = f'''\nfrom(bucket: \"{bucket}\")\n  |> range(start: -1h)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n  |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n'''\n\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    tables = client.query_api().query(query=query)\n\n    for table in tables:\n        for record in table.records:\n            print(record.get_time(), record.values[\"_value\"])\n```\n\n### Stream query results\n\nFor large result sets, prefer `query_stream()` so you do not materialize everything in memory:\n\n```python\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    records = client.query_api().query_stream(\n        f'from(bucket: \"{bucket}\") |> range(start: -10m)'\n    )\n\n    for record in records:\n        print(record[\"_time\"], record[\"_value\"])\n\n    records.close()\n```\n\n### Query into pandas\n\nIf the workflow is analytical rather than service-oriented, use the DataFrame helpers:\n\n```python\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    df = client.query_api().query_data_frame(\n        f'from(bucket: \"{bucket}\") |> range(start: -1d)'\n    )\n    print(df.head())\n```\n\n### Check connectivity and health\n\nUse a quick readiness check before failing deeper in your code:\n\n```python\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    if not client.ping():\n        raise RuntimeError(\"InfluxDB is not reachable\")\n```\n\n### Delete data\n\nDelete operations go through `delete_api()` and require an explicit time range plus predicate:\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nwith InfluxDBClient(url=url, token=token, org=org) as client:\n    stop = datetime.now(timezone.utc)\n    start = stop - timedelta(hours=1)\n\n    client.delete_api().delete(\n        start=start,\n        stop=stop,\n        predicate='_measurement=\"cpu\"',\n        bucket=bucket,\n        org=org,\n    )\n```\n\n## Async Usage\n\nUse the async client only if the surrounding app is already async:\n\n```python\nimport asyncio\n\nfrom influxdb_client import Point\nfrom influxdb_client.client.influxdb_client_async import InfluxDBClientAsync\n\nasync def main() -> None:\n    async with InfluxDBClientAsync(url=url, token=token, org=org) as client:\n        await client.write_api().write(\n            bucket=bucket,\n            record=Point(\"cpu\").tag(\"host\", \"web-1\").field(\"usage_idle\", 91.2),\n        )\n\n        records = await client.query_api().query_stream(\n            f'from(bucket: \"{bucket}\") |> range(start: -10m)'\n        )\n        async for record in records:\n            print(record[\"_time\"], record[\"_value\"])\n\nasyncio.run(main())\n```\n\n## Config And Auth Notes\n\nToken auth is the preferred option for InfluxDB 2.x and Cloud.\n\nThe client also supports:\n\n- username/password\n- HTTP Basic auth\n\nThe `auth_basic` config flag is specifically for InfluxDB 1.8.x setups that are fronted by a reverse proxy using Basic auth.\n\nUseful config keys from the upstream client config support:\n\n- `timeout`: socket timeout in milliseconds\n- `verify_ssl`: disable only for controlled local/testing cases\n- `ssl_ca_cert`: custom CA bundle\n- `cert_file` and `cert_key_file`: mTLS client certificates\n- `connection_pool_maxsize`: useful for high-concurrency services\n- `profilers`: Flux profiler configuration\n\nIf you use environment-based config, the supported names start with `INFLUXDB_V2_...`, including `INFLUXDB_V2_URL`, `INFLUXDB_V2_TOKEN`, `INFLUXDB_V2_ORG`, `INFLUXDB_V2_TIMEOUT`, and `INFLUXDB_V2_AUTH_BASIC`.\n\n## Common Pitfalls\n\n- The package name is `influxdb-client`, but the import is `influxdb_client`.\n- `WriteApi` defaults to batching. In short-lived scripts, tests, lambdas, or request handlers, use `SYNCHRONOUS` or explicitly close the batching writer so data is flushed.\n- If you do use batching writes, keep the writer as a long-lived singleton and register callbacks if you need to observe background write failures.\n- This client is for InfluxDB 2.x and Flux-centric flows. Do not use it as the default choice for new InfluxDB 3.x work.\n- The API is not backwards compatible with the old `influxdb-python` client. Migration usually requires changing imports, auth setup, and query shapes.\n- InfluxDB 1.8 compatibility uses `/api/v2/query` and `/api/v2/write`; Flux must be enabled on the server for query compatibility.\n- Python `datetime` does not preserve nanosecond precision. If you need nanosecond timestamps, use pandas timestamps and the related upstream nanosecond-precision guidance.\n- Base install works, but upstream recommends `ciso8601` for much faster date parsing.\n- Outside batching writes, the client does not apply a general retry policy by default. Set `retries=` on `InfluxDBClient` if your service needs explicit HTTP retry behavior.\n\n## Version-Sensitive Notes\n\n- Version used here: `1.50.0`\n- Live PyPI version on March 12, 2026: `1.50.0`\n- PyPI release date for `1.50.0`: January 23, 2026\n- Python support declared on PyPI for this release: `>=3.7`\n- The upstream changelog entry for `1.50.0` is a packaging/build change, not a documented application-level API shift, so current 1.4x usage patterns in the official docs still apply to 1.50.0.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/influxdb-client/\n- README: https://github.com/influxdata/influxdb-client-python/blob/master/README.md\n- Product docs: https://docs.influxdata.com/influxdb/v2/api-guide/client-libraries/python/\n- API reference: https://influxdb-client.readthedocs.io/en/stable/\n- Changelog: https://github.com/influxdata/influxdb-client-python/blob/master/CHANGELOG.md\n"
  },
  {
    "path": "content/iniconfig/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"iniconfig package guide for parsing INI-style config files in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"python,ini,config,parser,iniconfig\"\n---\n\n# iniconfig Python Package Guide\n\n## Install\n\n`iniconfig 2.3.0` requires Python 3.10 or newer.\n\n```bash\npython -m pip install \"iniconfig==2.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"iniconfig==2.3.0\"\npoetry add \"iniconfig==2.3.0\"\n```\n\n`iniconfig` is a local parser library. There are no environment variables, network credentials, or service initialization steps.\n\n## Import And Parse A File\n\nUse `IniConfig.parse()` for new code on `2.3.0`. It is the new classmethod added in `2.3.0`, and its defaults are the safer ones for normal INI parsing.\n\n```python\nfrom pathlib import Path\n\nfrom iniconfig import IniConfig\n\nconfig_path = Path(\"pytest.ini\")\nini = IniConfig.parse(config_path)\n```\n\nIf the file is not UTF-8, pass an explicit encoding:\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig.parse(\"settings.ini\", encoding=\"latin-1\")\n```\n\n## Read Sections And Keys\n\nSection values are strings. Access a section first, then its keys:\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig.parse(\"settings.ini\")\n\ndb = ini[\"database\"]\nhost = db[\"host\"]\nport = int(db[\"port\"])\ndebug = ini[\"app\"].get(\"debug\", \"false\").lower() == \"true\"\n```\n\nFor optional sections or keys, use `.get()` instead of direct indexing:\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig.parse(\"settings.ini\")\n\nserver = ini.get(\"server\")\ntimeout = server.get(\"timeout\", \"30\") if server is not None else \"30\"\n```\n\n## Parse Config Text In Memory\n\nPass `data=` when the config content is already in memory. Keep the `path` argument meaningful so parse errors mention a useful filename.\n\n```python\nfrom iniconfig import IniConfig\n\nraw = \"\"\"\n[tool]\nname = demo\nenabled = true\n\"\"\"\n\nini = IniConfig.parse(\"inline.ini\", data=raw)\nname = ini[\"tool\"][\"name\"]\nenabled = ini[\"tool\"][\"enabled\"] == \"true\"\n```\n\n## Inspect File Order And Line Numbers\n\n`iniconfig` preserves section and key order, and exposes line numbers for parsed entries.\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig.parse(\"settings.ini\")\n\nfor section in ini:\n    print(section.name, ini.lineof(section.name))\n    for key, value in section.items():\n        print(\" \", key, value, section.lineof(key))\n```\n\nThat is useful when you want to surface validation errors back to a user with a stable file location.\n\n## Error Handling\n\nInvalid syntax and duplicate sections raise `ParseError`.\n\n```python\nfrom iniconfig import IniConfig, ParseError\n\ntry:\n    ini = IniConfig.parse(\"settings.ini\")\nexcept ParseError as exc:\n    print(f\"Could not parse {exc}\")\n```\n\n## Important Behavior In 2.3.0\n\n`IniConfig.parse()` and the `IniConfig(...)` constructor do not use the same defaults.\n\nFor new code, prefer `IniConfig.parse()`:\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig.parse(\"settings.ini\")\n```\n\nUse the constructor only when you intentionally need to control its legacy-compatible defaults:\n\n```python\nfrom iniconfig import IniConfig\n\nini = IniConfig(\n    \"settings.ini\",\n    strip_inline_comments=False,\n    strip_section_whitespace=False,\n)\n```\n\nThe practical difference is that `IniConfig.parse()` defaults `strip_inline_comments=True`, while the constructor keeps `strip_inline_comments=False` for backward compatibility. If you move older code to `parse()`, re-check any values that intentionally included inline `#` or `;` text.\n\n## Common Pitfalls\n\n- `iniconfig` does not coerce types for you. Convert strings to `int`, `bool`, or other application types after reading them.\n- Direct indexing like `ini[\"section\"][\"key\"]` raises when the section or key is missing. Use `.get()` when the config is optional.\n- Keep the `path` argument accurate when parsing in-memory data; it is used in parse error reporting.\n- Be deliberate about inline comments when migrating older code. `IniConfig.parse()` strips them by default in `2.3.0`.\n\n## Version Notes For 2.3.0\n\n- `2.3.0` requires Python `>=3.10`.\n- `2.3.0` adds `IniConfig.parse(path, data=None, encoding=\"utf-8\")`.\n- `2.3.0` also adds the `strip_inline_comments` and `strip_section_whitespace` constructor arguments. The constructor keeps the older inline-comment behavior by default; `parse()` opts into comment stripping by default.\n\n## Official Sources\n\n- GitHub repository: https://github.com/pytest-dev/iniconfig\n- README and usage examples: https://github.com/pytest-dev/iniconfig/blob/main/README.rst\n- Source API (`IniConfig`, `SectionWrapper`, `ParseError`): https://github.com/pytest-dev/iniconfig/blob/main/src/iniconfig/__init__.py\n- Package metadata and Python requirement: https://github.com/pytest-dev/iniconfig/blob/main/pyproject.toml\n- `2.3.0` release notes: https://github.com/pytest-dev/iniconfig/releases/tag/v2.3.0\n- PyPI package page: https://pypi.org/project/iniconfig/\n"
  },
  {
    "path": "content/instructor/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"instructor package guide for Python: structured outputs, validation-driven retries, streaming partials, and provider client patching for LLM apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"instructor,llm,structured-outputs,pydantic,openai,anthropic,gemini,validation\"\n---\n\n# instructor Python Package Guide\n\n## What It Does\n\n`instructor` wraps provider SDK clients so you can ask for structured outputs as Pydantic models instead of manually parsing JSON or tool-call payloads yourself. In practice, that means:\n\n- define a `BaseModel`\n- patch or construct a provider client with `instructor`\n- pass `response_model=...` on generation calls\n- get back validated Python objects\n\nIt is most useful when you need reliable extraction, classification, routing, or multi-step agent code that should fail on schema violations instead of silently accepting malformed model output.\n\n## Version Scope\n\n- Package: `instructor`\n- Language: `python`\n- Frontmatter version: `1.14.5`\n- Docs root: `https://python.useinstructor.com/`\n- Registry: `https://pypi.org/project/instructor/`\n\nImportant version note: the current docs site is not pinned to `1.14.5` and already includes newer migration guidance for `v2` and the newer `from_provider(...)` setup flow. For code that must match `1.14.5`, prefer the stable provider-specific wrappers such as `from_openai(...)` unless you have verified the newer helper exists in the installed version.\n\n## Installation\n\nInstall `instructor` plus the SDK for the model provider you are actually calling.\n\n```bash\npython -m pip install \"instructor==1.14.5\" openai\n```\n\n```bash\nuv add \"instructor==1.14.5\" openai\n```\n\n```bash\npoetry add \"instructor==1.14.5\" openai\n```\n\nCommon provider packages:\n\n- OpenAI-style examples: `openai`\n- Anthropic: `anthropic`\n- Google Gemini: use the provider package shown in the current maintainer docs for the integration you need\n\nIf a project already pins a provider SDK, keep that version aligned with the project lockfile rather than copying a random blog example.\n\n## Core Mental Model\n\n`instructor` does not replace the provider SDK. It augments it.\n\n1. Create the normal provider client.\n2. Wrap it with `instructor`.\n3. Pass a Pydantic model as `response_model`.\n4. Receive a validated model instance instead of raw text.\n\nThat also means authentication, base URLs, organization or project IDs, timeouts, and transport settings still come from the underlying provider SDK.\n\n## Initialization And Auth\n\n### OpenAI sync client\n\n```python\nimport os\n\nimport instructor\nfrom openai import OpenAI\n\nclient = instructor.from_openai(\n    OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n)\n```\n\n### OpenAI async client\n\n```python\nimport os\nimport asyncio\n\nimport instructor\nfrom openai import AsyncOpenAI\n\nasync def main() -> None:\n    client = instructor.from_openai(\n        AsyncOpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n    )\n\n    # Use the patched async client exactly where you would normally make a request.\n    print(client)\n\nasyncio.run(main())\n```\n\n### Other providers\n\nThe docs also cover provider-specific wrappers and newer generic provider setup flows. The safe rule is:\n\n- authenticate the provider client exactly as that provider SDK expects\n- then wrap that client with the `instructor` integration documented for that provider\n\n`instructor` does not introduce a separate universal auth environment variable.\n\n## Basic Structured Output\n\n```python\nimport os\n\nimport instructor\nfrom openai import OpenAI\nfrom pydantic import BaseModel\n\nclass UserInfo(BaseModel):\n    name: str\n    age: int\n\nclient = instructor.from_openai(\n    OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n)\n\nuser = client.chat.completions.create(\n    model=\"gpt-4.1-mini\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Jane Doe is 34 years old.\",\n        }\n    ],\n    response_model=UserInfo,\n)\n\nprint(user)\nprint(user.name)\nprint(user.age)\n```\n\nThe return value is the validated `UserInfo` instance, not a JSON string you still need to parse.\n\n## Lists And Repeated Objects\n\nWhen the task is “extract many records,” use the iterable helper instead of asking for free-form JSON and then trying to coerce it afterward.\n\n```python\nimport os\n\nimport instructor\nfrom openai import OpenAI\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n    name: str\n    age: int\n\nclient = instructor.from_openai(\n    OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n)\n\npeople = client.chat.completions.create_iterable(\n    model=\"gpt-4.1-mini\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Extract Jane Doe, 34, and Bob Smith, 41.\",\n        }\n    ],\n    response_model=Person,\n)\n\nfor person in people:\n    print(person)\n```\n\nPrefer `create_iterable(...)` when you want repeated model instances, progressive consumption, or a cleaner control flow than “ask for a list and hope the JSON is perfect.”\n\n## Streaming Partial Structured Output\n\nUse partial streaming when you want progressive model state before the final object is complete. Make fields optional or provide defaults so intermediate partials can validate.\n\n```python\nimport os\n\nimport instructor\nfrom openai import OpenAI\nfrom pydantic import BaseModel\n\nclass TicketDraft(BaseModel):\n    title: str | None = None\n    summary: str | None = None\n    priority: str | None = None\n\nclient = instructor.from_openai(\n    OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n)\n\nfor partial in client.chat.completions.create_partial(\n    model=\"gpt-4.1-mini\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Draft a bug ticket for a flaky login timeout issue.\",\n        }\n    ],\n    response_model=TicketDraft,\n):\n    print(partial)\n```\n\nUse this for streaming UIs or long extraction jobs where waiting for one final object would hurt latency or user feedback.\n\n## Validation And Retries\n\nValidation is the main reason to use `instructor`. Put real constraints in the model and let the wrapper retry when the provider returns something that does not satisfy the schema.\n\n```python\nimport os\n\nimport instructor\nfrom openai import OpenAI\nfrom pydantic import BaseModel, field_validator\n\nclass Customer(BaseModel):\n    email: str\n    age: int\n\n    @field_validator(\"age\")\n    @classmethod\n    def age_must_be_positive(cls, value: int) -> int:\n        if value <= 0:\n            raise ValueError(\"age must be positive\")\n        return value\n\nclient = instructor.from_openai(\n    OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n)\n\ncustomer = client.chat.completions.create(\n    model=\"gpt-4.1-mini\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Extract the customer profile from: Sam, age 27, sam@example.com\",\n        }\n    ],\n    response_model=Customer,\n    max_retries=3,\n)\n```\n\nPractical guidance:\n\n- keep validators focused on business constraints that matter\n- use retries sparingly because each retry adds cost and latency\n- prefer clear field names and descriptions so the model has a better chance of satisfying the schema on the first attempt\n\n## Raw Completion Access\n\nIf you need both the validated object and the raw provider response for logging, token accounting, or finish-reason debugging, use the maintainer-documented helper that returns structured output together with the completion payload.\n\nTreat this as the debugging and observability path. For normal application code, the plain structured-return flow is simpler.\n\n## Configuration Notes\n\nThe main configuration surface lives on the underlying provider SDK client:\n\n- API keys and auth\n- custom base URLs\n- organization or project identifiers\n- timeout and retry transport settings\n- HTTP client or proxy settings\n\nThe main configuration surface on `instructor` itself is how you request structure:\n\n- `response_model=...`\n- streaming helpers such as partial or iterable output\n- validation-driven retry count\n- provider-specific integration or mode choices from the docs\n\nWhen a project uses Azure OpenAI, OpenRouter, LiteLLM, local gateways, or other OpenAI-compatible endpoints, configure those details on the provider client first and then wrap that configured client.\n\n## Common Pitfalls\n\n### Forgetting the provider SDK dependency\n\n`instructor` is not a standalone LLM transport. Installing only `instructor` is not enough for real requests.\n\n### Treating auth as an Instructor concern\n\nSet auth on `OpenAI(...)`, `Anthropic(...)`, or the provider client you use. `instructor` wraps the client; it does not replace provider authentication.\n\n### Writing overly strict partial models\n\n`create_partial(...)` emits incomplete intermediate states. If every field is required, partial streaming will be brittle. Make partial fields optional or defaulted.\n\n### Assuming every docs example matches `1.14.5`\n\nThe docs site currently includes newer `v2` migration content and `from_provider(...)` examples. For `1.14.5`, stay with the provider-specific wrappers unless you have confirmed otherwise in your installed package.\n\n### Using retries without thinking about cost\n\nValidation retries improve correctness, but they also create extra model calls. Keep retry counts small for hot paths.\n\n### Falling back to raw JSON parsing anyway\n\nIf you are already using `response_model`, let Pydantic own validation. Do not ask the model for JSON strings and then write fragile post-processing unless you need a provider feature that the wrapper cannot express.\n\n## Version-Sensitive Notes\n\n- The version used here for this package is `1.14.5`.\n- The maintainer docs root is newer than that version and already references migration guidance for `v2`.\n- For compatibility-focused work on `1.14.5`, favor the documented `from_openai(...)` style and the `chat.completions.create(...)` family shown in the main getting-started flow.\n- If you want to use the newer `from_provider(...)` helper, OpenAI Responses API integrations, or recently added provider abstractions, verify them against the installed package version first.\n\n## Official Sources\n\n- Docs root: https://python.useinstructor.com/\n- Getting started: https://python.useinstructor.com/getting-started/\n- Patching and provider setup: https://python.useinstructor.com/concepts/patching/\n- Validation and retry concepts: https://python.useinstructor.com/concepts/validation/\n- Hooks and observability: https://python.useinstructor.com/concepts/hooks/\n- Registry: https://pypi.org/project/instructor/\n"
  },
  {
    "path": "content/intercom/docs/messaging/javascript/DOC.md",
    "content": "---\nname: messaging\ndescription: \"Intercom JavaScript SDK for customer messaging and chat support\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.4.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"intercom,messaging,customer,chat,support\"\n---\n\n# Intercom JavaScript SDK (v6.4.0)\n\n## Golden Rule\n\n**ALWAYS use `intercom-client` version 6.4.0 or later.**\n\n```bash\nnpm install intercom-client\n```\n\n**DO NOT use these deprecated or unofficial packages:**\n- `intercom.io` (deprecated)\n- `@ludovicbret/intercom-client` (community fork)\n- Any package not named exactly `intercom-client`\n\nThe official Intercom TypeScript/JavaScript SDK is `intercom-client`, maintained by Intercom at https://github.com/intercom/intercom-node\n\n## Installation\n\n```bash\nnpm install intercom-client\n```\n\nFor TypeScript projects, types are included in the package.\n\n**Environment Setup:**\n\n```bash\n# .env file\nINTERCOM_ACCESS_TOKEN=your_access_token_here\n```\n\n**Loading environment variables:**\n\n```javascript\n// Using dotenv\nimport 'dotenv/config';\n// or\nrequire('dotenv').config();\n```\n\n## Initialization\n\n**Basic Client Setup:**\n\n```javascript\nimport { IntercomClient } from 'intercom-client';\n\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN\n});\n```\n\n**TypeScript with explicit typing:**\n\n```typescript\nimport { IntercomClient, Intercom } from 'intercom-client';\n\nconst client: IntercomClient = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN\n});\n```\n\n**With custom configuration:**\n\n```javascript\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  timeoutInSeconds: 120, // Default is 60\n  maxRetries: 3, // Default is 2\n});\n```\n\n**API Version Selection:**\n\n```javascript\n// Use specific API version\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  apiVersion: '2.11', // Default is latest stable (2.11)\n});\n```\n\n## Core API Surfaces\n\n### Contacts\n\nContacts represent users, leads, and visitors in Intercom. They are the primary entities for customer communication.\n\n**Create a contact:**\n\n```javascript\nconst contact = await client.contacts.create({\n  email: '[email protected]',\n  name: 'John Doe',\n  phone: '+1234567890',\n  role: 'user', // 'user' or 'lead'\n});\n\nconsole.log(contact.id);\n```\n\n**Create with custom attributes:**\n\n```javascript\nconst contact = await client.contacts.create({\n  email: '[email protected]',\n  name: 'Jane Smith',\n  role: 'user',\n  custom_attributes: {\n    plan: 'premium',\n    signup_date: '2025-01-15',\n    total_spend: 599.99,\n    active: true,\n  },\n});\n```\n\n**Retrieve a contact:**\n\n```javascript\nconst contact = await client.contacts.find({\n  id: '65f9a5e4f5e5b40001234567',\n});\n\nconsole.log(contact.email, contact.name);\n```\n\n**Update a contact:**\n\n```javascript\nconst updated = await client.contacts.update({\n  id: '65f9a5e4f5e5b40001234567',\n  name: 'John Updated',\n  custom_attributes: {\n    plan: 'enterprise',\n  },\n});\n```\n\n**Search contacts:**\n\n```javascript\nconst results = await client.contacts.search({\n  query: {\n    field: 'email',\n    operator: '=',\n    value: '[email protected]',\n  },\n});\n\nfor (const contact of results.data) {\n  console.log(contact.name, contact.email);\n}\n```\n\n**Search with filters:**\n\n```javascript\nconst results = await client.contacts.search({\n  query: {\n    operator: 'AND',\n    value: [\n      {\n        field: 'role',\n        operator: '=',\n        value: 'user',\n      },\n      {\n        field: 'created_at',\n        operator: '>',\n        value: 1704067200, // Unix timestamp\n      },\n    ],\n  },\n  pagination: {\n    per_page: 50,\n  },\n});\n```\n\n**List all contacts:**\n\n```javascript\nconst response = await client.contacts.list({\n  per_page: 150,\n});\n\n// Iterate through paginated results\nfor await (const contact of response) {\n  console.log(contact.email);\n}\n```\n\n**Delete a contact:**\n\n```javascript\nawait client.contacts.delete({\n  id: '65f9a5e4f5e5b40001234567',\n});\n```\n\n**Archive a contact:**\n\n```javascript\nconst archived = await client.contacts.archive({\n  id: '65f9a5e4f5e5b40001234567',\n});\n```\n\n**Unarchive a contact:**\n\n```javascript\nconst unarchived = await client.contacts.unarchive({\n  id: '65f9a5e4f5e5b40001234567',\n});\n```\n\n**Merge contacts:**\n\n```javascript\nconst merged = await client.contacts.merge({\n  from: '65f9a5e4f5e5b40001234567',\n  into: '65f9a5e4f5e5b40009876543',\n});\n```\n\n### Companies\n\nCompanies group contacts together by organization. They're useful for B2B use cases.\n\n**Create a company:**\n\n```javascript\nconst company = await client.companies.create({\n  company_id: 'company_123',\n  name: 'Acme Corporation',\n  website: 'https://acme.com',\n  industry: 'Technology',\n  size: 500,\n  custom_attributes: {\n    plan_level: 'enterprise',\n    mrr: 50000,\n  },\n});\n```\n\n**Retrieve a company:**\n\n```javascript\nconst company = await client.companies.find({\n  company_id: 'company_123',\n});\n```\n\n**Update a company:**\n\n```javascript\nconst updated = await client.companies.update({\n  company_id: 'company_123',\n  name: 'Acme Corp',\n  size: 600,\n  custom_attributes: {\n    mrr: 60000,\n  },\n});\n```\n\n**List companies:**\n\n```javascript\nconst response = await client.companies.list({\n  per_page: 50,\n});\n\nfor await (const company of response) {\n  console.log(company.name, company.company_id);\n}\n```\n\n**Attach contact to company:**\n\n```javascript\nawait client.contacts.update({\n  id: '65f9a5e4f5e5b40001234567',\n  companies: [\n    {\n      company_id: 'company_123',\n    },\n  ],\n});\n```\n\n**List company contacts:**\n\n```javascript\nconst contacts = await client.companies.listContacts({\n  company_id: 'company_123',\n});\n\nfor await (const contact of contacts) {\n  console.log(contact.email);\n}\n```\n\n**Delete a company:**\n\n```javascript\nawait client.companies.delete({\n  company_id: 'company_123',\n});\n```\n\n### Conversations\n\nConversations are threads of communication between contacts and your team.\n\n**Create a conversation:**\n\n```javascript\nconst conversation = await client.conversations.create({\n  from: {\n    type: 'user',\n    id: '65f9a5e4f5e5b40001234567',\n  },\n  body: 'Hello, I need help with my account.',\n});\n\nconsole.log(conversation.id);\n```\n\n**Create conversation with user:**\n\n```javascript\nconst conversation = await client.conversations.createConversation({\n  userId: '65f9a5e4f5e5b40001234567',\n  body: 'I have a question about billing.',\n});\n```\n\n**Retrieve a conversation:**\n\n```javascript\nconst conversation = await client.conversations.find({\n  id: '123456',\n});\n\nconsole.log(conversation.state); // 'open', 'closed', 'snoozed'\n```\n\n**Reply to conversation as admin:**\n\n```javascript\nconst reply = await client.conversations.reply({\n  id: '123456',\n  message_type: 'comment',\n  type: 'admin',\n  admin_id: '987654',\n  body: 'Thanks for reaching out! How can I help?',\n});\n```\n\n**Reply with attachment:**\n\n```javascript\nconst reply = await client.conversations.reply({\n  id: '123456',\n  message_type: 'comment',\n  type: 'admin',\n  admin_id: '987654',\n  body: 'Here is the document you requested.',\n  attachment_urls: [\n    'https://example.com/document.pdf',\n  ],\n});\n```\n\n**Reply as user:**\n\n```javascript\nconst reply = await client.conversations.reply({\n  id: '123456',\n  message_type: 'comment',\n  type: 'user',\n  user_id: '65f9a5e4f5e5b40001234567',\n  body: 'Thank you for your help!',\n});\n```\n\n**Search conversations:**\n\n```javascript\nconst results = await client.conversations.search({\n  query: {\n    field: 'state',\n    operator: '=',\n    value: 'open',\n  },\n  pagination: {\n    per_page: 50,\n  },\n});\n\nfor (const conv of results.conversations) {\n  console.log(conv.id, conv.created_at);\n}\n```\n\n**Search with multiple filters:**\n\n```javascript\nconst results = await client.conversations.search({\n  query: {\n    operator: 'AND',\n    value: [\n      {\n        field: 'state',\n        operator: '=',\n        value: 'open',\n      },\n      {\n        field: 'updated_at',\n        operator: '>',\n        value: 1704067200,\n      },\n    ],\n  },\n  sort: {\n    field: 'updated_at',\n    order: 'descending',\n  },\n});\n```\n\n**List conversations:**\n\n```javascript\nconst response = await client.conversations.list();\n\nfor await (const conversation of response) {\n  console.log(conversation.id, conversation.state);\n}\n```\n\n**Close a conversation:**\n\n```javascript\nconst closed = await client.conversations.close({\n  id: '123456',\n  type: 'admin',\n  admin_id: '987654',\n});\n```\n\n**Open a conversation:**\n\n```javascript\nconst opened = await client.conversations.open({\n  id: '123456',\n  type: 'admin',\n  admin_id: '987654',\n});\n```\n\n**Snooze a conversation:**\n\n```javascript\nconst snoozed = await client.conversations.snooze({\n  id: '123456',\n  type: 'admin',\n  admin_id: '987654',\n  snoozed_until: 1704153600, // Unix timestamp\n});\n```\n\n**Assign conversation to admin:**\n\n```javascript\nconst assigned = await client.conversations.assign({\n  id: '123456',\n  type: 'admin',\n  admin_id: '987654',\n  assignee_id: '111222',\n});\n```\n\n**Assign to team:**\n\n```javascript\nconst assigned = await client.conversations.assign({\n  id: '123456',\n  type: 'admin',\n  admin_id: '987654',\n  assignee_id: '333444',\n  assignment_type: 'team',\n});\n```\n\n**Convert conversation to ticket:**\n\n```javascript\nconst ticket = await client.conversations.convertToTicket({\n  id: '123456',\n  ticket_type_id: '100',\n});\n```\n\n**Add tag to conversation:**\n\n```javascript\nawait client.conversations.attachTag({\n  conversationId: '123456',\n  id: 'tag_789',\n  adminId: '987654',\n});\n```\n\n**Remove tag from conversation:**\n\n```javascript\nawait client.conversations.detachTag({\n  conversationId: '123456',\n  id: 'tag_789',\n  adminId: '987654',\n});\n```\n\n### Messages\n\nSend messages to contacts via Intercom.\n\n**Send a message to contact:**\n\n```javascript\nconst message = await client.messages.create({\n  message_type: 'email',\n  from: {\n    type: 'admin',\n    id: '987654',\n  },\n  to: {\n    type: 'user',\n    id: '65f9a5e4f5e5b40001234567',\n  },\n  subject: 'Welcome to our platform',\n  body: 'Thanks for signing up! Here are some tips to get started.',\n});\n```\n\n**Send message by email:**\n\n```javascript\nconst message = await client.messages.create({\n  message_type: 'email',\n  from: {\n    type: 'admin',\n    id: '987654',\n  },\n  to: {\n    type: 'user',\n    email: '[email protected]',\n  },\n  subject: 'Your monthly report',\n  body: 'Here is your activity summary for January.',\n});\n```\n\n**Send in-app message:**\n\n```javascript\nconst message = await client.messages.create({\n  message_type: 'inapp',\n  from: {\n    type: 'admin',\n    id: '987654',\n  },\n  to: {\n    type: 'user',\n    id: '65f9a5e4f5e5b40001234567',\n  },\n  body: 'Check out our new features!',\n});\n```\n\n**Send message with custom data:**\n\n```javascript\nconst message = await client.messages.create({\n  message_type: 'email',\n  from: {\n    type: 'admin',\n    id: '987654',\n  },\n  to: {\n    type: 'user',\n    id: '65f9a5e4f5e5b40001234567',\n  },\n  subject: 'Order confirmation',\n  body: 'Your order has been confirmed.',\n  template: 'plain',\n  create_conversation_without_contact_reply: false,\n});\n```\n\n### Data Events\n\nTrack user behavior and custom events.\n\n**Submit a data event:**\n\n```javascript\nawait client.events.create({\n  event_name: 'purchased_item',\n  created_at: Math.floor(Date.now() / 1000),\n  user_id: '65f9a5e4f5e5b40001234567',\n  metadata: {\n    item_name: 'Premium Plan',\n    item_price: 99.99,\n    currency: 'USD',\n    quantity: 1,\n  },\n});\n```\n\n**Event with email identifier:**\n\n```javascript\nawait client.events.create({\n  event_name: 'signed_up',\n  created_at: Math.floor(Date.now() / 1000),\n  email: '[email protected]',\n  metadata: {\n    source: 'landing_page',\n    campaign: 'winter_2025',\n  },\n});\n```\n\n**Complex event metadata:**\n\n```javascript\nawait client.events.create({\n  event_name: 'completed_onboarding',\n  created_at: Math.floor(Date.now() / 1000),\n  user_id: '65f9a5e4f5e5b40001234567',\n  metadata: {\n    steps_completed: 5,\n    time_taken_seconds: 320,\n    skipped_steps: ['profile_picture'],\n    completion_rate: 0.95,\n    device: 'mobile',\n  },\n});\n```\n\n**List events for user:**\n\n```javascript\nconst events = await client.events.list({\n  type: 'user',\n  user_id: '65f9a5e4f5e5b40001234567',\n});\n\nfor (const event of events.events) {\n  console.log(event.event_name, event.created_at);\n}\n```\n\n**Event summaries:**\n\n```javascript\nconst summary = await client.events.summaries({\n  user_id: '65f9a5e4f5e5b40001234567',\n  event_name: 'purchased_item',\n});\n\nconsole.log(summary.count, summary.first, summary.last);\n```\n\n### Tags\n\nOrganize and categorize contacts, companies, and conversations.\n\n**Create a tag:**\n\n```javascript\nconst tag = await client.tags.create({\n  name: 'VIP Customer',\n});\n\nconsole.log(tag.id);\n```\n\n**Retrieve a tag:**\n\n```javascript\nconst tag = await client.tags.find({\n  id: 'tag_789',\n});\n```\n\n**List all tags:**\n\n```javascript\nconst tags = await client.tags.list();\n\nfor (const tag of tags.data) {\n  console.log(tag.name, tag.id);\n}\n```\n\n**Tag a contact:**\n\n```javascript\nawait client.contacts.tag({\n  contactId: '65f9a5e4f5e5b40001234567',\n  id: 'tag_789',\n});\n```\n\n**Tag a company:**\n\n```javascript\nawait client.companies.tag({\n  companyId: 'company_123',\n  id: 'tag_789',\n});\n```\n\n**Untag a contact:**\n\n```javascript\nawait client.contacts.untag({\n  contactId: '65f9a5e4f5e5b40001234567',\n  id: 'tag_789',\n});\n```\n\n**Delete a tag:**\n\n```javascript\nawait client.tags.delete({\n  id: 'tag_789',\n});\n```\n\n### Data Attributes\n\nDefine custom attributes for contacts and companies.\n\n**Create a contact attribute:**\n\n```javascript\nconst attribute = await client.dataAttributes.create({\n  name: 'subscription_tier',\n  model: 'contact',\n  data_type: 'string',\n  options: ['free', 'pro', 'enterprise'],\n  description: 'Customer subscription level',\n});\n```\n\n**Create a company attribute:**\n\n```javascript\nconst attribute = await client.dataAttributes.create({\n  name: 'annual_revenue',\n  model: 'company',\n  data_type: 'float',\n  description: 'Company annual revenue in USD',\n});\n```\n\n**Create boolean attribute:**\n\n```javascript\nconst attribute = await client.dataAttributes.create({\n  name: 'is_beta_tester',\n  model: 'contact',\n  data_type: 'boolean',\n  description: 'Whether user is enrolled in beta program',\n});\n```\n\n**Create date attribute:**\n\n```javascript\nconst attribute = await client.dataAttributes.create({\n  name: 'trial_end_date',\n  model: 'contact',\n  data_type: 'date',\n  description: 'Date when trial period ends',\n});\n```\n\n**List data attributes:**\n\n```javascript\nconst attributes = await client.dataAttributes.list({\n  model: 'contact',\n});\n\nfor (const attr of attributes.data) {\n  console.log(attr.name, attr.data_type);\n}\n```\n\n**Update an attribute:**\n\n```javascript\nconst updated = await client.dataAttributes.update({\n  id: 'attr_123',\n  description: 'Updated description',\n  options: ['free', 'pro', 'enterprise', 'custom'],\n});\n```\n\n### Notes\n\nAdd notes to contacts and companies for internal reference.\n\n**Create a note for contact:**\n\n```javascript\nconst note = await client.notes.create({\n  contact_id: '65f9a5e4f5e5b40001234567',\n  admin_id: '987654',\n  body: 'Customer requested custom integration. Follow up next week.',\n});\n```\n\n**Create a note for company:**\n\n```javascript\nconst note = await client.notes.create({\n  company_id: 'company_123',\n  admin_id: '987654',\n  body: 'Contract renewal coming up in Q2 2025.',\n});\n```\n\n**Retrieve a note:**\n\n```javascript\nconst note = await client.notes.find({\n  id: 'note_456',\n});\n```\n\n**List notes for contact:**\n\n```javascript\nconst notes = await client.contacts.listNotes({\n  id: '65f9a5e4f5e5b40001234567',\n});\n\nfor (const note of notes.data) {\n  console.log(note.body, note.created_at);\n}\n```\n\n### Segments\n\nQuery and retrieve segments (groups of contacts).\n\n**List all segments:**\n\n```javascript\nconst segments = await client.segments.list();\n\nfor (const segment of segments.segments) {\n  console.log(segment.name, segment.count);\n}\n```\n\n**Retrieve a segment:**\n\n```javascript\nconst segment = await client.segments.find({\n  id: 'segment_999',\n});\n\nconsole.log(segment.name, segment.person_type);\n```\n\n**List contacts in segment:**\n\n```javascript\nconst contacts = await client.segments.listContacts({\n  id: 'segment_999',\n});\n\nfor await (const contact of contacts) {\n  console.log(contact.email);\n}\n```\n\n### Tickets\n\nManage customer support tickets.\n\n**Create a ticket:**\n\n```javascript\nconst ticket = await client.tickets.create({\n  contact_id: '65f9a5e4f5e5b40001234567',\n  ticket_type_id: '100',\n  contacts: [\n    {\n      id: '65f9a5e4f5e5b40001234567',\n    },\n  ],\n  ticket_attributes: {\n    _default_title_: 'Payment issue',\n    _default_description_: 'Customer unable to process payment',\n  },\n});\n```\n\n**Retrieve a ticket:**\n\n```javascript\nconst ticket = await client.tickets.find({\n  id: 'ticket_888',\n});\n\nconsole.log(ticket.ticket_state);\n```\n\n**Update a ticket:**\n\n```javascript\nconst updated = await client.tickets.update({\n  id: 'ticket_888',\n  ticket_attributes: {\n    _default_title_: 'Payment issue - RESOLVED',\n  },\n  ticket_state: 'submitted',\n});\n```\n\n**Reply to ticket:**\n\n```javascript\nconst reply = await client.tickets.reply({\n  id: 'ticket_888',\n  admin_id: '987654',\n  message_type: 'comment',\n  body: 'Issue has been resolved. Payment processed successfully.',\n});\n```\n\n**Search tickets:**\n\n```javascript\nconst results = await client.tickets.search({\n  query: {\n    field: 'ticket_state',\n    operator: '=',\n    value: 'submitted',\n  },\n});\n\nfor (const ticket of results.tickets) {\n  console.log(ticket.id, ticket.ticket_attributes);\n}\n```\n\n### Admins\n\nManage admin users and teams.\n\n**List all admins:**\n\n```javascript\nconst admins = await client.admins.list();\n\nfor (const admin of admins.admins) {\n  console.log(admin.name, admin.email);\n}\n```\n\n**Retrieve an admin:**\n\n```javascript\nconst admin = await client.admins.find({\n  id: '987654',\n});\n\nconsole.log(admin.name, admin.away_mode_enabled);\n```\n\n**Retrieve current admin:**\n\n```javascript\nconst me = await client.admins.me();\n\nconsole.log(me.name, me.email);\n```\n\n**Set away mode:**\n\n```javascript\nconst updated = await client.admins.setAwayMode({\n  admin_id: '987654',\n  away_mode_enabled: true,\n  away_mode_reassign: true,\n});\n```\n\n**List teams:**\n\n```javascript\nconst teams = await client.teams.list();\n\nfor (const team of teams.teams) {\n  console.log(team.name, team.id);\n}\n```\n\n**Retrieve a team:**\n\n```javascript\nconst team = await client.teams.find({\n  id: '333444',\n});\n```\n\n### Articles\n\nManage help center articles.\n\n**Create an article:**\n\n```javascript\nconst article = await client.articles.create({\n  title: 'Getting Started Guide',\n  description: 'Learn how to use our platform',\n  body: '<h1>Welcome</h1><p>This guide will help you get started...</p>',\n  author_id: 987654,\n  state: 'published',\n});\n```\n\n**Retrieve an article:**\n\n```javascript\nconst article = await client.articles.find({\n  id: 'article_555',\n});\n```\n\n**Update an article:**\n\n```javascript\nconst updated = await client.articles.update({\n  id: 'article_555',\n  title: 'Getting Started Guide (Updated)',\n  body: '<h1>Welcome</h1><p>This updated guide...</p>',\n});\n```\n\n**List articles:**\n\n```javascript\nconst response = await client.articles.list({\n  per_page: 50,\n});\n\nfor await (const article of response) {\n  console.log(article.title, article.state);\n}\n```\n\n**Delete an article:**\n\n```javascript\nawait client.articles.delete({\n  id: 'article_555',\n});\n```\n\n### Subscription Types\n\nManage subscription preferences for contacts.\n\n**List subscription types:**\n\n```javascript\nconst types = await client.subscriptionTypes.list();\n\nfor (const type of types.data) {\n  console.log(type.id, type.content_type);\n}\n```\n\n**Subscribe contact:**\n\n```javascript\nawait client.contacts.subscribe({\n  id: '65f9a5e4f5e5b40001234567',\n  subscription_type_id: 'sub_123',\n});\n```\n\n**Unsubscribe contact:**\n\n```javascript\nawait client.contacts.unsubscribe({\n  id: '65f9a5e4f5e5b40001234567',\n  subscription_type_id: 'sub_123',\n});\n```\n\n## Error Handling\n\n**Basic error handling:**\n\n```javascript\nimport { IntercomError } from 'intercom-client';\n\ntry {\n  const contact = await client.contacts.find({ id: 'invalid_id' });\n} catch (err) {\n  if (err instanceof IntercomError) {\n    console.error('Status:', err.statusCode);\n    console.error('Message:', err.message);\n    console.error('Body:', err.body);\n  }\n}\n```\n\n**Handle specific error codes:**\n\n```javascript\ntry {\n  await client.contacts.create({ email: '[email protected]' });\n} catch (err) {\n  if (err instanceof IntercomError) {\n    switch (err.statusCode) {\n      case 400:\n        console.error('Bad request:', err.message);\n        break;\n      case 401:\n        console.error('Unauthorized - check your token');\n        break;\n      case 404:\n        console.error('Resource not found');\n        break;\n      case 429:\n        console.error('Rate limit exceeded');\n        break;\n      default:\n        console.error('Error:', err.message);\n    }\n  }\n}\n```\n\n**Retry on rate limit:**\n\n```javascript\nasync function createContactWithRetry(data, maxRetries = 3) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await client.contacts.create(data);\n    } catch (err) {\n      if (err instanceof IntercomError && err.statusCode === 429) {\n        if (attempt < maxRetries) {\n          const delay = Math.pow(2, attempt) * 1000;\n          console.log(`Rate limited, retrying in ${delay}ms...`);\n          await new Promise(resolve => setTimeout(resolve, delay));\n          continue;\n        }\n      }\n      throw err;\n    }\n  }\n}\n```\n\n## Pagination\n\n**Auto-pagination with for-await:**\n\n```javascript\nconst response = await client.contacts.list();\n\nfor await (const contact of response) {\n  console.log(contact.email);\n  // Automatically fetches next page when needed\n}\n```\n\n**Manual pagination:**\n\n```javascript\nlet hasMore = true;\nlet startingAfter = null;\n\nwhile (hasMore) {\n  const response = await client.contacts.list({\n    per_page: 50,\n    starting_after: startingAfter,\n  });\n\n  for (const contact of response.data) {\n    console.log(contact.email);\n  }\n\n  hasMore = response.pages && response.pages.next;\n  startingAfter = response.pages?.next?.starting_after;\n}\n```\n\n**Get all pages at once:**\n\n```javascript\nconst allContacts = [];\nconst response = await client.contacts.list();\n\nfor await (const contact of response) {\n  allContacts.push(contact);\n}\n\nconsole.log(`Total contacts: ${allContacts.length}`);\n```\n\n## Advanced Features\n\n**Custom headers:**\n\n```javascript\nconst contact = await client.contacts.create(\n  {\n    email: '[email protected]',\n    name: 'Test User',\n  },\n  {\n    headers: {\n      'X-Custom-Header': 'custom-value',\n    },\n  }\n);\n```\n\n**Request timeout:**\n\n```javascript\nconst contact = await client.contacts.find(\n  { id: '65f9a5e4f5e5b40001234567' },\n  {\n    timeoutInSeconds: 30,\n  }\n);\n```\n\n**Abort requests:**\n\n```javascript\nconst controller = new AbortController();\n\n// Cancel after 5 seconds\nsetTimeout(() => controller.abort(), 5000);\n\ntry {\n  const contact = await client.contacts.create(\n    {\n      email: '[email protected]',\n    },\n    {\n      abortSignal: controller.signal,\n    }\n  );\n} catch (err) {\n  if (err.name === 'AbortError') {\n    console.log('Request was aborted');\n  }\n}\n```\n\n**Access raw response:**\n\n```javascript\nconst response = await client.contacts\n  .withRawResponse()\n  .find({ id: '65f9a5e4f5e5b40001234567' });\n\nconsole.log('Status:', response.statusCode);\nconsole.log('Headers:', response.headers);\nconsole.log('Body:', response.body);\n```\n\n**Disable automatic retries:**\n\n```javascript\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  maxRetries: 0, // Disable retries\n});\n```\n\n**Custom retry configuration:**\n\n```javascript\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  maxRetries: 5,\n  timeoutInSeconds: 90,\n});\n```\n\n## Type Definitions\n\n**Using request types:**\n\n```typescript\nimport { Intercom } from 'intercom-client';\n\nconst createRequest: Intercom.ContactCreateRequest = {\n  email: '[email protected]',\n  name: 'Jane Doe',\n  role: 'user',\n  custom_attributes: {\n    plan: 'premium',\n  },\n};\n\nconst contact = await client.contacts.create(createRequest);\n```\n\n**Using response types:**\n\n```typescript\nimport { Intercom } from 'intercom-client';\n\nconst contact: Intercom.Contact = await client.contacts.find({\n  id: '65f9a5e4f5e5b40001234567',\n});\n\nconsole.log(contact.email, contact.created_at);\n```\n\n**Conversation types:**\n\n```typescript\nimport { Intercom } from 'intercom-client';\n\nconst conversation: Intercom.Conversation = await client.conversations.find({\n  id: '123456',\n});\n\nconst state: Intercom.ConversationState = conversation.state;\n// 'open' | 'closed' | 'snoozed'\n```\n\n**Event metadata typing:**\n\n```typescript\ninterface PurchaseMetadata {\n  item_name: string;\n  item_price: number;\n  currency: string;\n  quantity: number;\n}\n\nawait client.events.create({\n  event_name: 'purchased_item',\n  created_at: Math.floor(Date.now() / 1000),\n  user_id: '65f9a5e4f5e5b40001234567',\n  metadata: {\n    item_name: 'Premium Plan',\n    item_price: 99.99,\n    currency: 'USD',\n    quantity: 1,\n  } as PurchaseMetadata,\n});\n```\n\n## Webhooks\n\n**Verify webhook signature:**\n\n```javascript\nimport crypto from 'crypto';\n\nfunction verifyWebhook(body, signature, secret) {\n  const hash = crypto\n    .createHmac('sha256', secret)\n    .update(body)\n    .digest('hex');\n\n  return signature === hash;\n}\n\n// Express example\napp.post('/webhooks/intercom', (req, res) => {\n  const signature = req.headers['x-hub-signature'];\n  const isValid = verifyWebhook(\n    JSON.stringify(req.body),\n    signature,\n    process.env.INTERCOM_WEBHOOK_SECRET\n  );\n\n  if (!isValid) {\n    return res.status(401).send('Invalid signature');\n  }\n\n  const event = req.body;\n  console.log('Webhook event:', event.topic);\n\n  res.sendStatus(200);\n});\n```\n\n**Handle webhook events:**\n\n```javascript\napp.post('/webhooks/intercom', (req, res) => {\n  const { topic, data } = req.body;\n\n  switch (topic) {\n    case 'contact.created':\n      console.log('New contact:', data.item.email);\n      break;\n\n    case 'conversation.user.created':\n      console.log('New conversation:', data.item.id);\n      break;\n\n    case 'conversation.admin.replied':\n      console.log('Admin replied to:', data.item.id);\n      break;\n\n    case 'user.tag.created':\n      console.log('User tagged:', data.item.user.email);\n      break;\n\n    default:\n      console.log('Unknown event:', topic);\n  }\n\n  res.sendStatus(200);\n});\n```\n\n## Rate Limiting\n\nIntercom enforces rate limits on API requests. The SDK handles retries automatically.\n\n**Default retry behavior:**\n\n```javascript\n// SDK automatically retries on 429 (rate limit) responses\n// with exponential backoff (2 retries by default)\n\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  maxRetries: 2, // Default\n});\n```\n\n**Rate limit headers:**\n\n```javascript\nconst response = await client.contacts\n  .withRawResponse()\n  .list();\n\nconsole.log('Rate limit:', response.headers['x-ratelimit-limit']);\nconsole.log('Remaining:', response.headers['x-ratelimit-remaining']);\nconsole.log('Reset:', response.headers['x-ratelimit-reset']);\n```\n\n**Handle rate limits manually:**\n\n```javascript\nasync function makeRequestWithBackoff(requestFn, maxRetries = 5) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await requestFn();\n    } catch (err) {\n      if (err instanceof IntercomError && err.statusCode === 429) {\n        const resetHeader = err.headers?.['x-ratelimit-reset'];\n        const resetTime = resetHeader ? parseInt(resetHeader) * 1000 : null;\n\n        if (resetTime && i < maxRetries - 1) {\n          const waitTime = Math.max(resetTime - Date.now(), 0);\n          console.log(`Rate limited. Waiting ${waitTime}ms...`);\n          await new Promise(resolve => setTimeout(resolve, waitTime));\n          continue;\n        }\n      }\n      throw err;\n    }\n  }\n}\n\n// Usage\nawait makeRequestWithBackoff(() =>\n  client.contacts.create({ email: '[email protected]' })\n);\n```\n\n## Bulk Operations\n\n**Bulk create contacts:**\n\n```javascript\nconst contacts = [\n  { email: '[email protected]', name: 'User 1' },\n  { email: '[email protected]', name: 'User 2' },\n  { email: '[email protected]', name: 'User 3' },\n];\n\nconst results = await Promise.all(\n  contacts.map(data => client.contacts.create(data))\n);\n\nconsole.log(`Created ${results.length} contacts`);\n```\n\n**Bulk update with error handling:**\n\n```javascript\nconst updates = [\n  { id: '1', name: 'Updated 1' },\n  { id: '2', name: 'Updated 2' },\n  { id: '3', name: 'Updated 3' },\n];\n\nconst results = await Promise.allSettled(\n  updates.map(data => client.contacts.update(data))\n);\n\nconst succeeded = results.filter(r => r.status === 'fulfilled').length;\nconst failed = results.filter(r => r.status === 'rejected').length;\n\nconsole.log(`Success: ${succeeded}, Failed: ${failed}`);\n```\n\n**Rate-limited bulk operations:**\n\n```javascript\nasync function bulkOperationWithRateLimit(items, operation, requestsPerSecond = 5) {\n  const results = [];\n  const delay = 1000 / requestsPerSecond;\n\n  for (const item of items) {\n    try {\n      const result = await operation(item);\n      results.push({ success: true, data: result });\n    } catch (err) {\n      results.push({ success: false, error: err });\n    }\n\n    await new Promise(resolve => setTimeout(resolve, delay));\n  }\n\n  return results;\n}\n\n// Usage\nconst contactData = [\n  { email: '[email protected]', name: 'User 1' },\n  { email: '[email protected]', name: 'User 2' },\n  // ... more contacts\n];\n\nconst results = await bulkOperationWithRateLimit(\n  contactData,\n  data => client.contacts.create(data),\n  5 // 5 requests per second\n);\n```\n\n## Environment-Specific Configuration\n\n**Development:**\n\n```javascript\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  timeoutInSeconds: 30,\n  maxRetries: 1,\n});\n```\n\n**Production:**\n\n```javascript\nconst client = new IntercomClient({\n  token: process.env.INTERCOM_ACCESS_TOKEN,\n  timeoutInSeconds: 120,\n  maxRetries: 3,\n});\n```\n\n**Testing with mock:**\n\n```javascript\n// For testing, you can inject a custom httpx client\nimport { IntercomClient } from 'intercom-client';\n\nconst mockClient = new IntercomClient({\n  token: 'test_token',\n  // Use mock HTTP client for tests\n});\n```\n\n## Complete Examples\n\n**User onboarding workflow:**\n\n```javascript\nasync function onboardUser(email, name, plan) {\n  try {\n    // Create contact\n    const contact = await client.contacts.create({\n      email,\n      name,\n      role: 'user',\n      custom_attributes: {\n        plan,\n        signup_date: new Date().toISOString(),\n      },\n    });\n\n    // Track signup event\n    await client.events.create({\n      event_name: 'signed_up',\n      created_at: Math.floor(Date.now() / 1000),\n      user_id: contact.id,\n      metadata: {\n        plan,\n        source: 'web',\n      },\n    });\n\n    // Tag as new user\n    const newUserTag = await client.tags.create({\n      name: 'New User',\n    });\n\n    await client.contacts.tag({\n      contactId: contact.id,\n      id: newUserTag.id,\n    });\n\n    // Send welcome message\n    await client.messages.create({\n      message_type: 'email',\n      from: {\n        type: 'admin',\n        id: process.env.ADMIN_ID,\n      },\n      to: {\n        type: 'user',\n        id: contact.id,\n      },\n      subject: 'Welcome to our platform!',\n      body: `Hi ${name}, thanks for signing up!`,\n    });\n\n    console.log('User onboarded successfully:', contact.id);\n    return contact;\n  } catch (err) {\n    console.error('Onboarding failed:', err);\n    throw err;\n  }\n}\n```\n\n**Customer support workflow:**\n\n```javascript\nasync function handleSupportRequest(userId, subject, message) {\n  try {\n    // Create conversation\n    const conversation = await client.conversations.create({\n      from: {\n        type: 'user',\n        id: userId,\n      },\n      body: message,\n    });\n\n    // Assign to team\n    await client.conversations.assign({\n      id: conversation.id,\n      type: 'admin',\n      admin_id: process.env.ADMIN_ID,\n      assignee_id: process.env.SUPPORT_TEAM_ID,\n      assignment_type: 'team',\n    });\n\n    // Add priority tag if urgent\n    if (subject.toLowerCase().includes('urgent')) {\n      const urgentTag = await client.tags.create({\n        name: 'Urgent',\n      });\n\n      await client.conversations.attachTag({\n        conversationId: conversation.id,\n        id: urgentTag.id,\n        adminId: process.env.ADMIN_ID,\n      });\n    }\n\n    // Track support event\n    await client.events.create({\n      event_name: 'support_request_created',\n      created_at: Math.floor(Date.now() / 1000),\n      user_id: userId,\n      metadata: {\n        conversation_id: conversation.id,\n        subject,\n        urgent: subject.toLowerCase().includes('urgent'),\n      },\n    });\n\n    return conversation;\n  } catch (err) {\n    console.error('Support request failed:', err);\n    throw err;\n  }\n}\n```\n\n**Company and contact management:**\n\n```javascript\nasync function addContactToCompany(contactEmail, companyId) {\n  try {\n    // Find or create contact\n    let contact;\n    try {\n      const searchResults = await client.contacts.search({\n        query: {\n          field: 'email',\n          operator: '=',\n          value: contactEmail,\n        },\n      });\n      contact = searchResults.data[0];\n    } catch (err) {\n      contact = await client.contacts.create({\n        email: contactEmail,\n        role: 'user',\n      });\n    }\n\n    // Attach to company\n    await client.contacts.update({\n      id: contact.id,\n      companies: [\n        {\n          company_id: companyId,\n        },\n      ],\n    });\n\n    // Get company details\n    const company = await client.companies.find({\n      company_id: companyId,\n    });\n\n    console.log(`Added ${contactEmail} to ${company.name}`);\n\n    return { contact, company };\n  } catch (err) {\n    console.error('Failed to add contact to company:', err);\n    throw err;\n  }\n}\n```\n\n**Analytics and reporting:**\n\n```javascript\nasync function generateUserReport(userId) {\n  try {\n    // Get user details\n    const contact = await client.contacts.find({ id: userId });\n\n    // Get user events\n    const events = await client.events.list({\n      type: 'user',\n      user_id: userId,\n    });\n\n    // Get conversations\n    const conversations = await client.conversations.search({\n      query: {\n        field: 'contact_ids',\n        operator: '=',\n        value: userId,\n      },\n    });\n\n    // Get notes\n    const notes = await client.contacts.listNotes({ id: userId });\n\n    const report = {\n      contact: {\n        email: contact.email,\n        name: contact.name,\n        created_at: contact.created_at,\n        custom_attributes: contact.custom_attributes,\n      },\n      events: events.events.map(e => ({\n        name: e.event_name,\n        created_at: e.created_at,\n        metadata: e.metadata,\n      })),\n      conversations: {\n        total: conversations.total_count,\n        open: conversations.conversations.filter(c => c.state === 'open').length,\n        closed: conversations.conversations.filter(c => c.state === 'closed').length,\n      },\n      notes: notes.data.map(n => ({\n        body: n.body,\n        created_at: n.created_at,\n      })),\n    };\n\n    return report;\n  } catch (err) {\n    console.error('Report generation failed:', err);\n    throw err;\n  }\n}\n```\n"
  },
  {
    "path": "content/intercom/docs/messaging/python/DOC.md",
    "content": "---\nname: messaging\ndescription: \"Intercom Python SDK for customer messaging and chat support\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"intercom,messaging,customer,chat,support\"\n---\n\n# Intercom Python SDK (v4.0.0)\n\n## Golden Rule\n\n**ALWAYS use `python-intercom` version 4.0.0 or later.**\n\n```bash\npip install python-intercom\n```\n\n**DO NOT use these deprecated or unofficial packages:**\n- `intercom-python-2` (community fork)\n- Old versions of `python-intercom` < 4.0.0 (different API structure)\n\nThe official Intercom Python SDK is `python-intercom`, maintained by Intercom at https://github.com/intercom/python-intercom\n\n## Installation\n\n```bash\npip install python-intercom\n```\n\nFor Poetry projects:\n\n```bash\npoetry add python-intercom\n```\n\n**Environment Setup:**\n\n```bash\n# .env file\nINTERCOM_ACCESS_TOKEN=your_access_token_here\n```\n\n**Loading environment variables:**\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ntoken = os.getenv('INTERCOM_ACCESS_TOKEN')\n```\n\n## Initialization\n\n**Basic Client Setup:**\n\n```python\nfrom intercom import Intercom\n\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN')\n)\n```\n\n**With custom configuration:**\n\n```python\nfrom intercom import Intercom\n\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    timeout=120,  # Default is 60 seconds\n    max_retries=3,  # Default is 2\n)\n```\n\n**Async Client:**\n\n```python\nfrom intercom import AsyncIntercom\nimport asyncio\n\nasync def main():\n    client = AsyncIntercom(\n        token=os.getenv('INTERCOM_ACCESS_TOKEN')\n    )\n\n    contact = await client.contacts.find(id='65f9a5e4f5e5b40001234567')\n    print(contact.email)\n\nasyncio.run(main())\n```\n\n**API Version Selection:**\n\n```python\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    api_version='2.11',  # Default is latest stable\n)\n```\n\n## Core API Surfaces\n\n### Contacts\n\nContacts represent users, leads, and visitors in Intercom. They are the primary entities for customer communication.\n\n**Create a contact:**\n\n```python\ncontact = client.contacts.create(\n    email='[email protected]',\n    name='John Doe',\n    phone='+1234567890',\n    role='user',  # 'user' or 'lead'\n)\n\nprint(contact.id)\n```\n\n**Create with custom attributes:**\n\n```python\ncontact = client.contacts.create(\n    email='[email protected]',\n    name='Jane Smith',\n    role='user',\n    custom_attributes={\n        'plan': 'premium',\n        'signup_date': '2025-01-15',\n        'total_spend': 599.99,\n        'active': True,\n    }\n)\n```\n\n**Retrieve a contact:**\n\n```python\ncontact = client.contacts.find(id='65f9a5e4f5e5b40001234567')\n\nprint(contact.email, contact.name)\n```\n\n**Update a contact:**\n\n```python\nupdated = client.contacts.update(\n    id='65f9a5e4f5e5b40001234567',\n    name='John Updated',\n    custom_attributes={\n        'plan': 'enterprise',\n    }\n)\n```\n\n**Search contacts:**\n\n```python\nresults = client.contacts.search(\n    query={\n        'field': 'email',\n        'operator': '=',\n        'value': '[email protected]',\n    }\n)\n\nfor contact in results.data:\n    print(contact.name, contact.email)\n```\n\n**Search with filters:**\n\n```python\nresults = client.contacts.search(\n    query={\n        'operator': 'AND',\n        'value': [\n            {\n                'field': 'role',\n                'operator': '=',\n                'value': 'user',\n            },\n            {\n                'field': 'created_at',\n                'operator': '>',\n                'value': 1704067200,  # Unix timestamp\n            },\n        ],\n    },\n    pagination={\n        'per_page': 50,\n    }\n)\n```\n\n**List all contacts:**\n\n```python\nresponse = client.contacts.list(per_page=150)\n\n# Iterate through paginated results\nfor contact in response:\n    print(contact.email)\n```\n\n**Delete a contact:**\n\n```python\nclient.contacts.delete(id='65f9a5e4f5e5b40001234567')\n```\n\n**Archive a contact:**\n\n```python\narchived = client.contacts.archive(id='65f9a5e4f5e5b40001234567')\n```\n\n**Unarchive a contact:**\n\n```python\nunarchived = client.contacts.unarchive(id='65f9a5e4f5e5b40001234567')\n```\n\n**Merge contacts:**\n\n```python\nmerged = client.contacts.merge(\n    from_='65f9a5e4f5e5b40001234567',\n    into='65f9a5e4f5e5b40009876543'\n)\n```\n\n### Companies\n\nCompanies group contacts together by organization. They're useful for B2B use cases.\n\n**Create a company:**\n\n```python\ncompany = client.companies.create(\n    company_id='company_123',\n    name='Acme Corporation',\n    website='https://acme.com',\n    industry='Technology',\n    size=500,\n    custom_attributes={\n        'plan_level': 'enterprise',\n        'mrr': 50000,\n    }\n)\n```\n\n**Retrieve a company:**\n\n```python\ncompany = client.companies.find(company_id='company_123')\n```\n\n**Update a company:**\n\n```python\nupdated = client.companies.update(\n    company_id='company_123',\n    name='Acme Corp',\n    size=600,\n    custom_attributes={\n        'mrr': 60000,\n    }\n)\n```\n\n**List companies:**\n\n```python\nresponse = client.companies.list(per_page=50)\n\nfor company in response:\n    print(company.name, company.company_id)\n```\n\n**Attach contact to company:**\n\n```python\nclient.contacts.update(\n    id='65f9a5e4f5e5b40001234567',\n    companies=[\n        {\n            'company_id': 'company_123',\n        }\n    ]\n)\n```\n\n**List company contacts:**\n\n```python\ncontacts = client.companies.list_contacts(company_id='company_123')\n\nfor contact in contacts:\n    print(contact.email)\n```\n\n**Delete a company:**\n\n```python\nclient.companies.delete(company_id='company_123')\n```\n\n### Conversations\n\nConversations are threads of communication between contacts and your team.\n\n**Create a conversation:**\n\n```python\nconversation = client.conversations.create(\n    from_={\n        'type': 'user',\n        'id': '65f9a5e4f5e5b40001234567',\n    },\n    body='Hello, I need help with my account.'\n)\n\nprint(conversation.id)\n```\n\n**Create conversation with user:**\n\n```python\nconversation = client.conversations.create_conversation(\n    user_id='65f9a5e4f5e5b40001234567',\n    body='I have a question about billing.'\n)\n```\n\n**Retrieve a conversation:**\n\n```python\nconversation = client.conversations.find(id='123456')\n\nprint(conversation.state)  # 'open', 'closed', 'snoozed'\n```\n\n**Reply to conversation as admin:**\n\n```python\nreply = client.conversations.reply(\n    id='123456',\n    message_type='comment',\n    type='admin',\n    admin_id='987654',\n    body='Thanks for reaching out! How can I help?'\n)\n```\n\n**Reply with attachment:**\n\n```python\nreply = client.conversations.reply(\n    id='123456',\n    message_type='comment',\n    type='admin',\n    admin_id='987654',\n    body='Here is the document you requested.',\n    attachment_urls=[\n        'https://example.com/document.pdf',\n    ]\n)\n```\n\n**Reply as user:**\n\n```python\nreply = client.conversations.reply(\n    id='123456',\n    message_type='comment',\n    type='user',\n    user_id='65f9a5e4f5e5b40001234567',\n    body='Thank you for your help!'\n)\n```\n\n**Search conversations:**\n\n```python\nresults = client.conversations.search(\n    query={\n        'field': 'state',\n        'operator': '=',\n        'value': 'open',\n    },\n    pagination={\n        'per_page': 50,\n    }\n)\n\nfor conv in results.conversations:\n    print(conv.id, conv.created_at)\n```\n\n**Search with multiple filters:**\n\n```python\nresults = client.conversations.search(\n    query={\n        'operator': 'AND',\n        'value': [\n            {\n                'field': 'state',\n                'operator': '=',\n                'value': 'open',\n            },\n            {\n                'field': 'updated_at',\n                'operator': '>',\n                'value': 1704067200,\n            },\n        ],\n    },\n    sort={\n        'field': 'updated_at',\n        'order': 'descending',\n    }\n)\n```\n\n**List conversations:**\n\n```python\nresponse = client.conversations.list()\n\nfor conversation in response:\n    print(conversation.id, conversation.state)\n```\n\n**Close a conversation:**\n\n```python\nclosed = client.conversations.close(\n    id='123456',\n    type='admin',\n    admin_id='987654'\n)\n```\n\n**Open a conversation:**\n\n```python\nopened = client.conversations.open(\n    id='123456',\n    type='admin',\n    admin_id='987654'\n)\n```\n\n**Snooze a conversation:**\n\n```python\nsnoozed = client.conversations.snooze(\n    id='123456',\n    type='admin',\n    admin_id='987654',\n    snoozed_until=1704153600  # Unix timestamp\n)\n```\n\n**Assign conversation to admin:**\n\n```python\nassigned = client.conversations.assign(\n    id='123456',\n    type='admin',\n    admin_id='987654',\n    assignee_id='111222'\n)\n```\n\n**Assign to team:**\n\n```python\nassigned = client.conversations.assign(\n    id='123456',\n    type='admin',\n    admin_id='987654',\n    assignee_id='333444',\n    assignment_type='team'\n)\n```\n\n**Convert conversation to ticket:**\n\n```python\nticket = client.conversations.convert_to_ticket(\n    id='123456',\n    ticket_type_id='100'\n)\n```\n\n**Add tag to conversation:**\n\n```python\nclient.conversations.attach_tag(\n    conversation_id='123456',\n    id='tag_789',\n    admin_id='987654'\n)\n```\n\n**Remove tag from conversation:**\n\n```python\nclient.conversations.detach_tag(\n    conversation_id='123456',\n    id='tag_789',\n    admin_id='987654'\n)\n```\n\n### Messages\n\nSend messages to contacts via Intercom.\n\n**Send a message to contact:**\n\n```python\nmessage = client.messages.create(\n    message_type='email',\n    from_={\n        'type': 'admin',\n        'id': '987654',\n    },\n    to={\n        'type': 'user',\n        'id': '65f9a5e4f5e5b40001234567',\n    },\n    subject='Welcome to our platform',\n    body='Thanks for signing up! Here are some tips to get started.'\n)\n```\n\n**Send message by email:**\n\n```python\nmessage = client.messages.create(\n    message_type='email',\n    from_={\n        'type': 'admin',\n        'id': '987654',\n    },\n    to={\n        'type': 'user',\n        'email': '[email protected]',\n    },\n    subject='Your monthly report',\n    body='Here is your activity summary for January.'\n)\n```\n\n**Send in-app message:**\n\n```python\nmessage = client.messages.create(\n    message_type='inapp',\n    from_={\n        'type': 'admin',\n        'id': '987654',\n    },\n    to={\n        'type': 'user',\n        'id': '65f9a5e4f5e5b40001234567',\n    },\n    body='Check out our new features!'\n)\n```\n\n**Send message with custom data:**\n\n```python\nmessage = client.messages.create(\n    message_type='email',\n    from_={\n        'type': 'admin',\n        'id': '987654',\n    },\n    to={\n        'type': 'user',\n        'id': '65f9a5e4f5e5b40001234567',\n    },\n    subject='Order confirmation',\n    body='Your order has been confirmed.',\n    template='plain',\n    create_conversation_without_contact_reply=False\n)\n```\n\n### Data Events\n\nTrack user behavior and custom events.\n\n**Submit a data event:**\n\n```python\nimport time\n\nclient.events.create(\n    event_name='purchased_item',\n    created_at=int(time.time()),\n    user_id='65f9a5e4f5e5b40001234567',\n    metadata={\n        'item_name': 'Premium Plan',\n        'item_price': 99.99,\n        'currency': 'USD',\n        'quantity': 1,\n    }\n)\n```\n\n**Event with email identifier:**\n\n```python\nclient.events.create(\n    event_name='signed_up',\n    created_at=int(time.time()),\n    email='[email protected]',\n    metadata={\n        'source': 'landing_page',\n        'campaign': 'winter_2025',\n    }\n)\n```\n\n**Complex event metadata:**\n\n```python\nclient.events.create(\n    event_name='completed_onboarding',\n    created_at=int(time.time()),\n    user_id='65f9a5e4f5e5b40001234567',\n    metadata={\n        'steps_completed': 5,\n        'time_taken_seconds': 320,\n        'skipped_steps': ['profile_picture'],\n        'completion_rate': 0.95,\n        'device': 'mobile',\n    }\n)\n```\n\n**List events for user:**\n\n```python\nevents = client.events.list(\n    type='user',\n    user_id='65f9a5e4f5e5b40001234567'\n)\n\nfor event in events.events:\n    print(event.event_name, event.created_at)\n```\n\n**Event summaries:**\n\n```python\nsummary = client.events.summaries(\n    user_id='65f9a5e4f5e5b40001234567',\n    event_name='purchased_item'\n)\n\nprint(summary.count, summary.first, summary.last)\n```\n\n### Tags\n\nOrganize and categorize contacts, companies, and conversations.\n\n**Create a tag:**\n\n```python\ntag = client.tags.create(name='VIP Customer')\n\nprint(tag.id)\n```\n\n**Retrieve a tag:**\n\n```python\ntag = client.tags.find(id='tag_789')\n```\n\n**List all tags:**\n\n```python\ntags = client.tags.list()\n\nfor tag in tags.data:\n    print(tag.name, tag.id)\n```\n\n**Tag a contact:**\n\n```python\nclient.contacts.tag(\n    contact_id='65f9a5e4f5e5b40001234567',\n    id='tag_789'\n)\n```\n\n**Tag a company:**\n\n```python\nclient.companies.tag(\n    company_id='company_123',\n    id='tag_789'\n)\n```\n\n**Untag a contact:**\n\n```python\nclient.contacts.untag(\n    contact_id='65f9a5e4f5e5b40001234567',\n    id='tag_789'\n)\n```\n\n**Delete a tag:**\n\n```python\nclient.tags.delete(id='tag_789')\n```\n\n### Data Attributes\n\nDefine custom attributes for contacts and companies.\n\n**Create a contact attribute:**\n\n```python\nattribute = client.data_attributes.create(\n    name='subscription_tier',\n    model='contact',\n    data_type='string',\n    options=['free', 'pro', 'enterprise'],\n    description='Customer subscription level'\n)\n```\n\n**Create a company attribute:**\n\n```python\nattribute = client.data_attributes.create(\n    name='annual_revenue',\n    model='company',\n    data_type='float',\n    description='Company annual revenue in USD'\n)\n```\n\n**Create boolean attribute:**\n\n```python\nattribute = client.data_attributes.create(\n    name='is_beta_tester',\n    model='contact',\n    data_type='boolean',\n    description='Whether user is enrolled in beta program'\n)\n```\n\n**Create date attribute:**\n\n```python\nattribute = client.data_attributes.create(\n    name='trial_end_date',\n    model='contact',\n    data_type='date',\n    description='Date when trial period ends'\n)\n```\n\n**List data attributes:**\n\n```python\nattributes = client.data_attributes.list(model='contact')\n\nfor attr in attributes.data:\n    print(attr.name, attr.data_type)\n```\n\n**Update an attribute:**\n\n```python\nupdated = client.data_attributes.update(\n    id='attr_123',\n    description='Updated description',\n    options=['free', 'pro', 'enterprise', 'custom']\n)\n```\n\n### Notes\n\nAdd notes to contacts and companies for internal reference.\n\n**Create a note for contact:**\n\n```python\nnote = client.notes.create(\n    contact_id='65f9a5e4f5e5b40001234567',\n    admin_id='987654',\n    body='Customer requested custom integration. Follow up next week.'\n)\n```\n\n**Create a note for company:**\n\n```python\nnote = client.notes.create(\n    company_id='company_123',\n    admin_id='987654',\n    body='Contract renewal coming up in Q2 2025.'\n)\n```\n\n**Retrieve a note:**\n\n```python\nnote = client.notes.find(id='note_456')\n```\n\n**List notes for contact:**\n\n```python\nnotes = client.contacts.list_notes(id='65f9a5e4f5e5b40001234567')\n\nfor note in notes.data:\n    print(note.body, note.created_at)\n```\n\n### Segments\n\nQuery and retrieve segments (groups of contacts).\n\n**List all segments:**\n\n```python\nsegments = client.segments.list()\n\nfor segment in segments.segments:\n    print(segment.name, segment.count)\n```\n\n**Retrieve a segment:**\n\n```python\nsegment = client.segments.find(id='segment_999')\n\nprint(segment.name, segment.person_type)\n```\n\n**List contacts in segment:**\n\n```python\ncontacts = client.segments.list_contacts(id='segment_999')\n\nfor contact in contacts:\n    print(contact.email)\n```\n\n### Tickets\n\nManage customer support tickets.\n\n**Create a ticket:**\n\n```python\nticket = client.tickets.create(\n    contact_id='65f9a5e4f5e5b40001234567',\n    ticket_type_id='100',\n    contacts=[\n        {\n            'id': '65f9a5e4f5e5b40001234567',\n        }\n    ],\n    ticket_attributes={\n        '_default_title_': 'Payment issue',\n        '_default_description_': 'Customer unable to process payment',\n    }\n)\n```\n\n**Retrieve a ticket:**\n\n```python\nticket = client.tickets.find(id='ticket_888')\n\nprint(ticket.ticket_state)\n```\n\n**Update a ticket:**\n\n```python\nupdated = client.tickets.update(\n    id='ticket_888',\n    ticket_attributes={\n        '_default_title_': 'Payment issue - RESOLVED',\n    },\n    ticket_state='submitted'\n)\n```\n\n**Reply to ticket:**\n\n```python\nreply = client.tickets.reply(\n    id='ticket_888',\n    admin_id='987654',\n    message_type='comment',\n    body='Issue has been resolved. Payment processed successfully.'\n)\n```\n\n**Search tickets:**\n\n```python\nresults = client.tickets.search(\n    query={\n        'field': 'ticket_state',\n        'operator': '=',\n        'value': 'submitted',\n    }\n)\n\nfor ticket in results.tickets:\n    print(ticket.id, ticket.ticket_attributes)\n```\n\n### Admins\n\nManage admin users and teams.\n\n**List all admins:**\n\n```python\nadmins = client.admins.list()\n\nfor admin in admins.admins:\n    print(admin.name, admin.email)\n```\n\n**Retrieve an admin:**\n\n```python\nadmin = client.admins.find(id='987654')\n\nprint(admin.name, admin.away_mode_enabled)\n```\n\n**Retrieve current admin:**\n\n```python\nme = client.admins.me()\n\nprint(me.name, me.email)\n```\n\n**Set away mode:**\n\n```python\nupdated = client.admins.set_away_mode(\n    admin_id='987654',\n    away_mode_enabled=True,\n    away_mode_reassign=True\n)\n```\n\n**List teams:**\n\n```python\nteams = client.teams.list()\n\nfor team in teams.teams:\n    print(team.name, team.id)\n```\n\n**Retrieve a team:**\n\n```python\nteam = client.teams.find(id='333444')\n```\n\n### Articles\n\nManage help center articles.\n\n**Create an article:**\n\n```python\narticle = client.articles.create(\n    title='Getting Started Guide',\n    description='Learn how to use our platform',\n    body='<h1>Welcome</h1><p>This guide will help you get started...</p>',\n    author_id=987654,\n    state='published'\n)\n```\n\n**Retrieve an article:**\n\n```python\narticle = client.articles.find(id='article_555')\n```\n\n**Update an article:**\n\n```python\nupdated = client.articles.update(\n    id='article_555',\n    title='Getting Started Guide (Updated)',\n    body='<h1>Welcome</h1><p>This updated guide...</p>'\n)\n```\n\n**List articles:**\n\n```python\nresponse = client.articles.list(per_page=50)\n\nfor article in response:\n    print(article.title, article.state)\n```\n\n**Delete an article:**\n\n```python\nclient.articles.delete(id='article_555')\n```\n\n### Subscription Types\n\nManage subscription preferences for contacts.\n\n**List subscription types:**\n\n```python\ntypes = client.subscription_types.list()\n\nfor sub_type in types.data:\n    print(sub_type.id, sub_type.content_type)\n```\n\n**Subscribe contact:**\n\n```python\nclient.contacts.subscribe(\n    id='65f9a5e4f5e5b40001234567',\n    subscription_type_id='sub_123'\n)\n```\n\n**Unsubscribe contact:**\n\n```python\nclient.contacts.unsubscribe(\n    id='65f9a5e4f5e5b40001234567',\n    subscription_type_id='sub_123'\n)\n```\n\n## Error Handling\n\n**Basic error handling:**\n\n```python\nfrom intercom import ApiError\n\ntry:\n    contact = client.contacts.find(id='invalid_id')\nexcept ApiError as e:\n    print(f'Status: {e.status_code}')\n    print(f'Message: {e.message}')\n    print(f'Body: {e.body}')\n```\n\n**Handle specific error codes:**\n\n```python\ntry:\n    client.contacts.create(email='[email protected]')\nexcept ApiError as e:\n    if e.status_code == 400:\n        print('Bad request:', e.message)\n    elif e.status_code == 401:\n        print('Unauthorized - check your token')\n    elif e.status_code == 404:\n        print('Resource not found')\n    elif e.status_code == 429:\n        print('Rate limit exceeded')\n    else:\n        print('Error:', e.message)\n```\n\n**Retry on rate limit:**\n\n```python\nimport time\nfrom intercom import ApiError\n\ndef create_contact_with_retry(data, max_retries=3):\n    for attempt in range(1, max_retries + 1):\n        try:\n            return client.contacts.create(**data)\n        except ApiError as e:\n            if e.status_code == 429 and attempt < max_retries:\n                delay = 2 ** attempt\n                print(f'Rate limited, retrying in {delay}s...')\n                time.sleep(delay)\n                continue\n            raise\n```\n\n## Pagination\n\n**Auto-pagination with iterator:**\n\n```python\nresponse = client.contacts.list()\n\nfor contact in response:\n    print(contact.email)\n    # Automatically fetches next page when needed\n```\n\n**Manual pagination:**\n\n```python\nhas_more = True\nstarting_after = None\n\nwhile has_more:\n    response = client.contacts.list(\n        per_page=50,\n        starting_after=starting_after\n    )\n\n    for contact in response.data:\n        print(contact.email)\n\n    has_more = response.pages and response.pages.next\n    starting_after = response.pages.next.starting_after if has_more else None\n```\n\n**Get all pages at once:**\n\n```python\nall_contacts = []\nresponse = client.contacts.list()\n\nfor contact in response:\n    all_contacts.append(contact)\n\nprint(f'Total contacts: {len(all_contacts)}')\n```\n\n## Async Client\n\n**Basic async usage:**\n\n```python\nimport asyncio\nfrom intercom import AsyncIntercom\n\nasync def main():\n    client = AsyncIntercom(\n        token=os.getenv('INTERCOM_ACCESS_TOKEN')\n    )\n\n    contact = await client.contacts.find(id='65f9a5e4f5e5b40001234567')\n    print(contact.email)\n\n    await client.close()\n\nasyncio.run(main())\n```\n\n**Async context manager:**\n\n```python\nasync def main():\n    async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:\n        contact = await client.contacts.create(\n            email='[email protected]',\n            name='Async User'\n        )\n        print(contact.id)\n\nasyncio.run(main())\n```\n\n**Concurrent operations:**\n\n```python\nasync def create_multiple_contacts():\n    async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:\n        tasks = [\n            client.contacts.create(email=f'user{i}@example.com', name=f'User {i}')\n            for i in range(10)\n        ]\n\n        contacts = await asyncio.gather(*tasks)\n\n        for contact in contacts:\n            print(contact.email)\n\nasyncio.run(create_multiple_contacts())\n```\n\n**Async pagination:**\n\n```python\nasync def list_all_contacts():\n    async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:\n        response = await client.contacts.list()\n\n        async for contact in response:\n            print(contact.email)\n\nasyncio.run(list_all_contacts())\n```\n\n## Advanced Features\n\n**Custom headers:**\n\n```python\ncontact = client.contacts.create(\n    email='[email protected]',\n    name='Test User',\n    headers={\n        'X-Custom-Header': 'custom-value',\n    }\n)\n```\n\n**Request timeout:**\n\n```python\ncontact = client.contacts.find(\n    id='65f9a5e4f5e5b40001234567',\n    timeout=30\n)\n```\n\n**Disable automatic retries:**\n\n```python\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    max_retries=0  # Disable retries\n)\n```\n\n**Custom retry configuration:**\n\n```python\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    max_retries=5,\n    timeout=90\n)\n```\n\n## Webhooks\n\n**Verify webhook signature:**\n\n```python\nimport hmac\nimport hashlib\n\ndef verify_webhook(body, signature, secret):\n    computed_hash = hmac.new(\n        secret.encode('utf-8'),\n        body.encode('utf-8'),\n        hashlib.sha256\n    ).hexdigest()\n\n    return signature == computed_hash\n\n# Flask example\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/webhooks/intercom', methods=['POST'])\ndef webhook():\n    signature = request.headers.get('X-Hub-Signature')\n    body = request.get_data(as_text=True)\n\n    is_valid = verify_webhook(\n        body,\n        signature,\n        os.getenv('INTERCOM_WEBHOOK_SECRET')\n    )\n\n    if not is_valid:\n        return jsonify({'error': 'Invalid signature'}), 401\n\n    event = request.json\n    print(f'Webhook event: {event[\"topic\"]}')\n\n    return jsonify({'status': 'ok'})\n```\n\n**Handle webhook events:**\n\n```python\n@app.route('/webhooks/intercom', methods=['POST'])\ndef webhook():\n    event = request.json\n    topic = event.get('topic')\n    data = event.get('data')\n\n    if topic == 'contact.created':\n        print(f'New contact: {data[\"item\"][\"email\"]}')\n\n    elif topic == 'conversation.user.created':\n        print(f'New conversation: {data[\"item\"][\"id\"]}')\n\n    elif topic == 'conversation.admin.replied':\n        print(f'Admin replied to: {data[\"item\"][\"id\"]}')\n\n    elif topic == 'user.tag.created':\n        print(f'User tagged: {data[\"item\"][\"user\"][\"email\"]}')\n\n    else:\n        print(f'Unknown event: {topic}')\n\n    return jsonify({'status': 'ok'})\n```\n\n**Django webhook handler:**\n\n```python\nfrom django.http import JsonResponse\nfrom django.views.decorators.csrf import csrf_exempt\nimport json\n\n@csrf_exempt\ndef intercom_webhook(request):\n    if request.method == 'POST':\n        signature = request.headers.get('X-Hub-Signature')\n        body = request.body.decode('utf-8')\n\n        is_valid = verify_webhook(\n            body,\n            signature,\n            os.getenv('INTERCOM_WEBHOOK_SECRET')\n        )\n\n        if not is_valid:\n            return JsonResponse({'error': 'Invalid signature'}, status=401)\n\n        event = json.loads(body)\n        topic = event.get('topic')\n\n        # Handle event\n        print(f'Event: {topic}')\n\n        return JsonResponse({'status': 'ok'})\n\n    return JsonResponse({'error': 'Method not allowed'}, status=405)\n```\n\n## Rate Limiting\n\nIntercom enforces rate limits on API requests. The SDK handles retries automatically.\n\n**Default retry behavior:**\n\n```python\n# SDK automatically retries on 429 (rate limit) responses\n# with exponential backoff (2 retries by default)\n\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    max_retries=2  # Default\n)\n```\n\n**Handle rate limits manually:**\n\n```python\nimport time\nfrom intercom import ApiError\n\ndef make_request_with_backoff(request_fn, max_retries=5):\n    for i in range(max_retries):\n        try:\n            return request_fn()\n        except ApiError as e:\n            if e.status_code == 429:\n                if i < max_retries - 1:\n                    wait_time = 2 ** i\n                    print(f'Rate limited. Waiting {wait_time}s...')\n                    time.sleep(wait_time)\n                    continue\n            raise\n\n# Usage\ncontact = make_request_with_backoff(\n    lambda: client.contacts.create(email='[email protected]')\n)\n```\n\n## Bulk Operations\n\n**Bulk create contacts:**\n\n```python\ncontacts_data = [\n    {'email': '[email protected]', 'name': 'User 1'},\n    {'email': '[email protected]', 'name': 'User 2'},\n    {'email': '[email protected]', 'name': 'User 3'},\n]\n\nresults = []\nfor data in contacts_data:\n    try:\n        contact = client.contacts.create(**data)\n        results.append({'success': True, 'data': contact})\n    except ApiError as e:\n        results.append({'success': False, 'error': str(e)})\n\nsucceeded = sum(1 for r in results if r['success'])\nprint(f'Created {succeeded} contacts')\n```\n\n**Bulk update with concurrency (async):**\n\n```python\nimport asyncio\nfrom intercom import AsyncIntercom, ApiError\n\nasync def bulk_update_contacts(updates):\n    async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:\n        tasks = [\n            client.contacts.update(**data)\n            for data in updates\n        ]\n\n        results = await asyncio.gather(*tasks, return_exceptions=True)\n\n        succeeded = sum(1 for r in results if not isinstance(r, Exception))\n        failed = len(results) - succeeded\n\n        print(f'Success: {succeeded}, Failed: {failed}')\n        return results\n\n# Usage\nupdates = [\n    {'id': '1', 'name': 'Updated 1'},\n    {'id': '2', 'name': 'Updated 2'},\n    {'id': '3', 'name': 'Updated 3'},\n]\n\nasyncio.run(bulk_update_contacts(updates))\n```\n\n**Rate-limited bulk operations:**\n\n```python\nimport time\n\ndef bulk_operation_with_rate_limit(items, operation, requests_per_second=5):\n    results = []\n    delay = 1.0 / requests_per_second\n\n    for item in items:\n        try:\n            result = operation(item)\n            results.append({'success': True, 'data': result})\n        except ApiError as e:\n            results.append({'success': False, 'error': str(e)})\n\n        time.sleep(delay)\n\n    return results\n\n# Usage\ncontact_data = [\n    {'email': '[email protected]', 'name': 'User 1'},\n    {'email': '[email protected]', 'name': 'User 2'},\n]\n\nresults = bulk_operation_with_rate_limit(\n    contact_data,\n    lambda data: client.contacts.create(**data),\n    requests_per_second=5\n)\n```\n\n## Environment-Specific Configuration\n\n**Development:**\n\n```python\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    timeout=30,\n    max_retries=1\n)\n```\n\n**Production:**\n\n```python\nclient = Intercom(\n    token=os.getenv('INTERCOM_ACCESS_TOKEN'),\n    timeout=120,\n    max_retries=3\n)\n```\n\n**Testing with mock:**\n\n```python\nfrom unittest.mock import Mock\n\n# Mock client for testing\nmock_client = Mock(spec=Intercom)\nmock_client.contacts.create.return_value = Mock(\n    id='test_id',\n    email='[email protected]',\n    name='Test User'\n)\n```\n\n## Complete Examples\n\n**User onboarding workflow:**\n\n```python\nimport time\nfrom intercom import ApiError\n\ndef onboard_user(email, name, plan):\n    try:\n        # Create contact\n        contact = client.contacts.create(\n            email=email,\n            name=name,\n            role='user',\n            custom_attributes={\n                'plan': plan,\n                'signup_date': time.strftime('%Y-%m-%d'),\n            }\n        )\n\n        # Track signup event\n        client.events.create(\n            event_name='signed_up',\n            created_at=int(time.time()),\n            user_id=contact.id,\n            metadata={\n                'plan': plan,\n                'source': 'web',\n            }\n        )\n\n        # Tag as new user\n        new_user_tag = client.tags.create(name='New User')\n        client.contacts.tag(\n            contact_id=contact.id,\n            id=new_user_tag.id\n        )\n\n        # Send welcome message\n        client.messages.create(\n            message_type='email',\n            from_={\n                'type': 'admin',\n                'id': os.getenv('ADMIN_ID'),\n            },\n            to={\n                'type': 'user',\n                'id': contact.id,\n            },\n            subject='Welcome to our platform!',\n            body=f'Hi {name}, thanks for signing up!'\n        )\n\n        print(f'User onboarded successfully: {contact.id}')\n        return contact\n\n    except ApiError as e:\n        print(f'Onboarding failed: {e}')\n        raise\n```\n\n**Customer support workflow:**\n\n```python\ndef handle_support_request(user_id, subject, message):\n    try:\n        # Create conversation\n        conversation = client.conversations.create(\n            from_={\n                'type': 'user',\n                'id': user_id,\n            },\n            body=message\n        )\n\n        # Assign to team\n        client.conversations.assign(\n            id=conversation.id,\n            type='admin',\n            admin_id=os.getenv('ADMIN_ID'),\n            assignee_id=os.getenv('SUPPORT_TEAM_ID'),\n            assignment_type='team'\n        )\n\n        # Add priority tag if urgent\n        if 'urgent' in subject.lower():\n            urgent_tag = client.tags.create(name='Urgent')\n            client.conversations.attach_tag(\n                conversation_id=conversation.id,\n                id=urgent_tag.id,\n                admin_id=os.getenv('ADMIN_ID')\n            )\n\n        # Track support event\n        client.events.create(\n            event_name='support_request_created',\n            created_at=int(time.time()),\n            user_id=user_id,\n            metadata={\n                'conversation_id': conversation.id,\n                'subject': subject,\n                'urgent': 'urgent' in subject.lower(),\n            }\n        )\n\n        return conversation\n\n    except ApiError as e:\n        print(f'Support request failed: {e}')\n        raise\n```\n\n**Company and contact management:**\n\n```python\ndef add_contact_to_company(contact_email, company_id):\n    try:\n        # Find or create contact\n        try:\n            search_results = client.contacts.search(\n                query={\n                    'field': 'email',\n                    'operator': '=',\n                    'value': contact_email,\n                }\n            )\n            contact = search_results.data[0]\n        except (ApiError, IndexError):\n            contact = client.contacts.create(\n                email=contact_email,\n                role='user'\n            )\n\n        # Attach to company\n        client.contacts.update(\n            id=contact.id,\n            companies=[\n                {\n                    'company_id': company_id,\n                }\n            ]\n        )\n\n        # Get company details\n        company = client.companies.find(company_id=company_id)\n\n        print(f'Added {contact_email} to {company.name}')\n\n        return {'contact': contact, 'company': company}\n\n    except ApiError as e:\n        print(f'Failed to add contact to company: {e}')\n        raise\n```\n\n**Analytics and reporting:**\n\n```python\ndef generate_user_report(user_id):\n    try:\n        # Get user details\n        contact = client.contacts.find(id=user_id)\n\n        # Get user events\n        events = client.events.list(\n            type='user',\n            user_id=user_id\n        )\n\n        # Get conversations\n        conversations = client.conversations.search(\n            query={\n                'field': 'contact_ids',\n                'operator': '=',\n                'value': user_id,\n            }\n        )\n\n        # Get notes\n        notes = client.contacts.list_notes(id=user_id)\n\n        report = {\n            'contact': {\n                'email': contact.email,\n                'name': contact.name,\n                'created_at': contact.created_at,\n                'custom_attributes': contact.custom_attributes,\n            },\n            'events': [\n                {\n                    'name': e.event_name,\n                    'created_at': e.created_at,\n                    'metadata': e.metadata,\n                }\n                for e in events.events\n            ],\n            'conversations': {\n                'total': conversations.total_count,\n                'open': sum(1 for c in conversations.conversations if c.state == 'open'),\n                'closed': sum(1 for c in conversations.conversations if c.state == 'closed'),\n            },\n            'notes': [\n                {\n                    'body': n.body,\n                    'created_at': n.created_at,\n                }\n                for n in notes.data\n            ],\n        }\n\n        return report\n\n    except ApiError as e:\n        print(f'Report generation failed: {e}')\n        raise\n```\n\n**Async batch processing:**\n\n```python\nimport asyncio\nfrom intercom import AsyncIntercom\n\nasync def process_contacts_batch(contact_ids):\n    async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:\n        # Fetch all contacts concurrently\n        tasks = [client.contacts.find(id=contact_id) for contact_id in contact_ids]\n        contacts = await asyncio.gather(*tasks, return_exceptions=True)\n\n        # Process successful results\n        valid_contacts = [c for c in contacts if not isinstance(c, Exception)]\n\n        # Update contacts concurrently\n        update_tasks = [\n            client.contacts.update(\n                id=contact.id,\n                custom_attributes={'last_processed': int(time.time())}\n            )\n            for contact in valid_contacts\n        ]\n\n        results = await asyncio.gather(*update_tasks, return_exceptions=True)\n\n        succeeded = sum(1 for r in results if not isinstance(r, Exception))\n        print(f'Processed {succeeded}/{len(contact_ids)} contacts')\n\n        return results\n\n# Usage\ncontact_ids = ['id1', 'id2', 'id3', 'id4', 'id5']\nasyncio.run(process_contacts_batch(contact_ids))\n```\n"
  },
  {
    "path": "content/intercom-python/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Legacy intercom-python package for Intercom API access; treat as an unfinished 2015 package and prefer the maintained python-intercom SDK for new code\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"intercom,crm,customer-support,api,legacy\"\n---\n\n# intercom-python Python Package Guide\n\n## Golden Rule\n\nTreat `intercom-python==1.0.6` as a legacy package, not a current Intercom SDK. The live PyPI project still says it is \"not official\" and \"Not yet done!!!!!\", and the docs URL points at Intercom's maintained `python-intercom` repository, which is a different package entirely. For new code, use `python-intercom`; only touch `intercom-python` when an existing environment is already pinned to it.\n\n## Install\n\nIf a project is already pinned to the legacy package, install that exact version and inspect it locally before writing code against it:\n\n```bash\npython -m pip install \"intercom-python==1.0.6\"\n```\n\nThe maintained Intercom SDK is a different package:\n\n```bash\npython -m pip install \"python-intercom==5.0.1\"\n```\n\n## Reality Check Before You Code\n\nThere are no reliable maintainer-published docs for the runtime API of `intercom-python==1.0.6` beyond the PyPI stub, so do not invent imports or method names. Inspect the installed package first:\n\n```bash\npython - <<'PY'\nimport importlib\n\nfor name in (\"intercom\", \"intercom_python\"):\n    try:\n        module = importlib.import_module(name)\n        public = [item for item in dir(module) if not item.startswith(\"_\")]\n        print(name, module.__file__)\n        print(public[:50])\n    except Exception as exc:\n        print(name, \"IMPORT_FAILED\", exc)\nPY\n```\n\nThen inspect the actual code surface:\n\n```bash\npython - <<'PY'\nimport inspect\nimport importlib\n\nmodule = importlib.import_module(\"intercom\")\nprint(inspect.getsource(module))\nPY\n```\n\nIf the import name is different in your environment, adjust the second snippet to match what the first one discovered.\n\n## Safer Setup For New Code\n\nIf you are not forced to keep `intercom-python`, migrate to Intercom's maintained SDK instead. The current maintainer docs show this initialization pattern:\n\n```python\nimport os\nfrom intercom import Intercom\n\nclient = Intercom(token=os.environ[\"INTERCOM_ACCESS_TOKEN\"])\n```\n\nAuthentication notes from Intercom's current REST docs:\n\n- Use a bearer token in the `Authorization` header\n- The default API hostname is `https://api.intercom.io`\n- Region-specific hosts also exist for EU and AU workspaces, so confirm the workspace region before hard-coding URLs\n\n## Core Usage Guidance\n\nFor `intercom-python==1.0.6` itself, use this workflow instead of assuming a modern SDK shape:\n\n1. Install the exact pinned version.\n2. Discover the real import path and exported symbols locally.\n3. Check whether the package wraps HTTP requests directly or expects raw `requests` usage around it.\n4. Verify every endpoint against current Intercom REST docs before using it in production.\n\nFor maintained integrations, prefer `python-intercom` and use the official namespace-based client methods documented in the repo reference and README.\n\n## Configuration And Auth\n\n`intercom-python` is old enough that its auth behavior cannot be trusted without local inspection. Before using it, verify all of the following in the installed code:\n\n- Whether it expects an access token, basic auth, or some older Intercom credential format\n- Whether it hard-codes `https://api.intercom.io` or allows region-specific base URLs\n- Whether it sets request timeouts, retries, or pagination helpers\n- Whether it depends on deprecated Intercom API paths\n\nFor the maintained SDK, keep the token in `INTERCOM_ACCESS_TOKEN` and let the client handle the `Authorization: Bearer ...` header.\n\n## Common Pitfalls\n\n- `intercom-python` and `python-intercom` are different packages. Do not mix their install commands or examples.\n- The docs URL currently points to the maintained `python-intercom` repo, not the legacy `intercom-python` package being curated here.\n- PyPI shows `intercom-python` as an unfinished package last released in 2015. That is a strong signal to avoid it for greenfield work.\n- Old Intercom examples on blogs or gists may target deprecated authentication or endpoint behavior. Check the current REST docs before sending live requests.\n- Intercom has region-specific API hosts. If you drop to raw HTTP, use the correct workspace region instead of assuming the US hostname.\n- Do not assume async support, retries, or pagination helpers in `intercom-python`; verify them in the installed source.\n\n## Version-Sensitive Notes\n\n- `intercom-python 1.0.6` appears to be the latest and only practically relevant release of this legacy package on PyPI.\n- Intercom's maintained package is `python-intercom 5.0.1`, released on `2026-01-30`, with current docs in `intercom/python-intercom`.\n- The maintained SDK docs say `python-intercom` requires Python `>=3.8`. `intercom-python` predates that by a decade and may reflect Python 2 / early Python 3 assumptions.\n\n## Official Sources Used\n\n- PyPI package page for `intercom-python`: `https://pypi.org/project/intercom-python/`\n- PyPI package page for Intercom's maintained SDK: `https://pypi.org/project/python-intercom/`\n- Maintained SDK repository: `https://github.com/intercom/python-intercom`\n- Intercom REST API auth and base URL docs: `https://developers.intercom.com/docs/references/2.13/rest-api/api.intercom.io/admins`\n"
  },
  {
    "path": "content/invoke/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Invoke Python task execution library for defining CLI tasks and running local shell commands\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.2.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"invoke,python,cli,tasks,automation,shell\"\n---\n\n# Invoke Python Package Guide\n\n## Golden Rule\n\nUse `invoke` as a Python-native task runner: define tasks with `@task`, let `inv` discover the collection, and run subprocesses through the provided `Context`. If a task shells out, prefer `c.run(...)` over hand-rolled `subprocess` code unless you need behavior Invoke does not expose.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"invoke==2.2.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"invoke==2.2.1\"\npoetry add \"invoke==2.2.1\"\n```\n\nIf you only need the CLI for local automation, a standard virtualenv install is enough:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"invoke==2.2.1\"\n```\n\n## Initialize A Task Collection\n\nInvoke looks for a task collection starting from the current working directory and walking upward. The usual entry point is a `tasks.py` file.\n\nMinimal example:\n\n```python\nfrom invoke import task\n\n@task\ndef test(c):\n    c.run(\"pytest -q\")\n\n@task\ndef lint(c):\n    c.run(\"ruff check .\")\n```\n\nUseful first commands:\n\n```bash\ninv --list\ninv test\ninv lint\n```\n\nIf `inv --list` shows no tasks, check that:\n\n- you are running from the intended project directory\n- the collection file is named `tasks.py` or explicitly configured\n- the module imports cleanly without import-time errors\n\n## Define Parameterized Tasks\n\nTask arguments become CLI flags automatically. Keep the first parameter as the Invoke context object.\n\n```python\nfrom invoke import task\n\n@task(help={\"name\": \"Person or environment name\"})\ndef greet(c, name=\"world\", loud=False):\n    message = f\"hello, {name}\"\n    if loud:\n        message = message.upper()\n    print(message)\n```\n\nRun it like this:\n\n```bash\ninv greet\ninv greet --name codex\ninv greet --name staging --loud\n```\n\nPractical notes:\n\n- Write task docstrings and `help={...}` metadata if you want `inv --help <task>` to be useful.\n- Boolean parameters become flags; use explicit parameter names instead of overloaded positional parsing.\n- Keep task bodies small and compose shared logic in normal Python functions.\n\n## Run Shell Commands From Tasks\n\n`Context.run` is the core API for local command execution. By default, a non-zero exit code raises `UnexpectedExit`.\n\n```python\nfrom invoke import task\n\n@task\ndef check(c):\n    result = c.run(\"pytest -q\", hide=True, warn=True)\n    print(\"ok:\", result.ok)\n    print(\"exit:\", result.exited)\n    print(result.stdout)\n```\n\nCommon options agents usually need:\n\n- `warn=True`: return a `Result` instead of raising on non-zero exit\n- `hide=True`: capture output instead of echoing directly\n- `pty=True`: allocate a pseudo-terminal for interactive or color-sensitive commands\n- `env={...}`: add or override subprocess environment variables\n\nExample with environment overrides:\n\n```python\nfrom invoke import task\n\n@task\ndef integration(c):\n    c.run(\n        \"pytest tests/integration -q\",\n        env={\"APP_ENV\": \"test\", \"CHUB_TELEMETRY\": \"0\"},\n    )\n```\n\nUse `pty=True` for commands that behave differently without a TTY:\n\n```python\nfrom invoke import task\n\n@task\ndef deploy(c):\n    c.run(\"python manage.py migrate\", pty=True)\n```\n\n## Organize Larger Collections\n\nWhen `tasks.py` grows, move tasks into modules and expose a `Collection`.\n\n```python\nfrom invoke import Collection, task\n\n@task\ndef test(c):\n    c.run(\"pytest -q\")\n\n@task\ndef docs(c):\n    c.run(\"mkdocs build\")\n\nns = Collection(test, docs)\n```\n\nThis keeps your task surface stable while letting you split implementation details across files.\n\n## Configuration And Environment\n\nInvoke supports configuration files in multiple formats, including:\n\n- `invoke.yaml`\n- `invoke.yml`\n- `invoke.json`\n- `invoke.py`\n- `pyproject.toml` under `[tool.invoke]` in Invoke `2.1+`\n\n`pyproject.toml` example:\n\n```toml\n[tool.invoke.run]\necho = true\nwarn = true\n\n[tool.invoke.tasks]\ndedupe = true\n```\n\nEnvironment variables can override config values with the `INVOKE_` prefix. For example:\n\n```bash\nexport INVOKE_RUN_ECHO=1\nexport INVOKE_RUN_WARN=1\n```\n\nUse config for task-runner behavior, not service credentials. Invoke itself does not manage API authentication; if a task calls tools like `aws`, `gcloud`, or `docker`, those tools still need their own credentials and environment setup.\n\n## Sudo, Prompts, And Interactive Commands\n\nInvoke also exposes `c.sudo(...)` for privilege escalation. In non-interactive automation, password prompts are a common failure point. If a command expects interactive input, prefer one of these approaches:\n\n- run in an environment where passwordless sudo is already configured for the needed command\n- use `pty=True` when the target program requires a terminal\n- use Invoke watchers when you must respond to interactive prompts programmatically\n\nDo not hard-code real credentials into task files or checked-in config.\n\n## Common Pitfalls\n\n- The first argument to a task must be the context object. `@task def build(): ...` is wrong; use `def build(c): ...`.\n- `c.run(...)` raises on command failure unless you set `warn=True`.\n- `pty=True` changes I/O behavior. It is often necessary for interactive tools, but it can make output capture different from non-PTY execution.\n- Task discovery depends on the working directory. Running `inv` from the wrong directory is a frequent reason for \"No idea what task\" style errors.\n- `pyproject.toml` configuration only works in Invoke `2.1+`. Older 2.0.x setups need one of the legacy config file formats.\n- Invoke is for local or subprocess-driven automation. It is not Fabric; do not assume remote SSH execution APIs exist just because older blog posts mix the projects together.\n- Avoid putting secrets in `invoke.yaml` or `pyproject.toml`. Pass them via the environment or a secret manager and let downstream tools read them.\n\n## Version-Sensitive Notes\n\n- The version used here `2.2.1` matches the current PyPI release as of `2026-03-12`.\n- Invoke `2.0.0` dropped support for Python versions earlier than `3.6`. If you are stuck on Python `2.7` or `3.5`, you need the older `1.x` line instead of `2.x`.\n- Invoke `2.1.0` added support for reading configuration from `pyproject.toml`, which matters if you are migrating from ad hoc `invoke.yaml` files to modern project metadata.\n- Invoke `2.2.1` includes a fix for Python `3.14` compatibility around deprecated argument-inspection APIs. That matters if tasks or task loading fail on very new Python runtimes.\n\n## Official Sources\n\n- Project site: `https://www.pyinvoke.org/`\n- Documentation root: `https://docs.pyinvoke.org/en/latest/`\n- Getting started: `https://docs.pyinvoke.org/en/latest/getting-started.html`\n- Configuration: `https://docs.pyinvoke.org/en/latest/concepts/configuration.html`\n- Command execution: `https://docs.pyinvoke.org/en/latest/concepts/invoking-tasks.html`\n- Changelog: `https://www.pyinvoke.org/changelog.html`\n- PyPI: `https://pypi.org/project/invoke/`\n"
  },
  {
    "path": "content/ipykernel/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ipykernel package guide for registering Python environments as Jupyter kernels and embedding IPython kernels\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ipykernel,jupyter,ipython,kernel,notebook,python\"\n---\n\n# ipykernel Python Package Guide\n\n## Golden Rule\n\nUse `ipykernel` to make a specific Python environment available to Jupyter frontends, or to embed an IPython kernel inside a running Python process. Most projects should not call low-level `ipykernel` APIs directly in application code. The common path is:\n\n1. install `ipykernel` into the environment that should execute notebook code\n2. register that environment as a kernelspec\n3. let JupyterLab, Notebook, VS Code, or another frontend launch the kernel\n\nIf notebooks keep using the wrong interpreter, the problem is usually the kernelspec pointing at the wrong Python binary, not the notebook code itself.\n\n## Install\n\nInstall `ipykernel` in the exact environment you want notebook cells to run in:\n\n```bash\npython -m pip install \"ipykernel==7.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"ipykernel==7.2.0\"\npoetry add \"ipykernel==7.2.0\"\n```\n\nVerify the package version from that interpreter:\n\n```bash\npython -c \"import ipykernel; print(ipykernel.__version__)\"\n```\n\n`ipykernel` is only the kernel package. It does not replace the frontend. If the machine does not already have a notebook frontend, install one separately, such as JupyterLab or Notebook, in whichever environment will host the UI.\n\n## Register The Current Environment As A Jupyter Kernel\n\nThe usual setup command is:\n\n```bash\npython -m ipykernel install --user --name myenv --display-name \"Python (myenv)\"\n```\n\nWhat the flags mean:\n\n- `--user`: write the kernelspec into the current user's Jupyter data directory\n- `--name`: stable internal kernel name; this must be unique on the machine\n- `--display-name`: label shown in Jupyter frontends\n\nAfter installing, confirm Jupyter can see it:\n\n```bash\njupyter kernelspec list\n```\n\nIf you recreate the virtual environment later, rerun `python -m ipykernel install ...` so the kernelspec points at the new interpreter path.\n\n## Install A Kernel For A Different Jupyter Environment\n\nIt is common to keep the notebook frontend in one environment and the runtime kernel in another. In that case, run the kernel environment's Python with `--prefix` pointing at the frontend environment:\n\n```bash\n/path/to/kernel-env/bin/python -m ipykernel install \\\n  --prefix /path/to/jupyter-env \\\n  --name project-env \\\n  --display-name \"Python (project-env)\"\n```\n\nThis is the practical fix when:\n\n- JupyterLab is installed in a shared tooling environment\n- the project runtime lives in a separate `venv`, Conda env, or container image\n- VS Code or Notebook sees Jupyter but not the project interpreter\n\n## Edit Or Customize A Kernelspec\n\nIf you need to inspect or modify the generated kernelspec JSON before installing it permanently, the IPython install docs recommend this flow:\n\n```bash\nipython kernel install --prefix /tmp\n```\n\nThen edit the generated `kernel.json` under `/tmp/...` and install it with `jupyter kernelspec install`.\n\nTypical reasons to customize a kernelspec:\n\n- add environment variables for the kernel process\n- change the visible display name\n- ship a kernel into a shared Jupyter deployment path\n- pin a non-default interpreter location\n\nAvoid editing random files under Jupyter data directories by hand unless you know which kernelspec is active.\n\n## Programmatic Kernelspec Installation\n\nIf you are building tooling around environment bootstrap, `ipykernel.kernelspec.install(...)` exposes the same install path from Python.\n\n```python\nfrom ipykernel.kernelspec import install\n\ninstall(\n    user=True,\n    kernel_name=\"project-env\",\n    display_name=\"Python (project-env)\",\n    env={\"PYTHONUNBUFFERED\": \"1\"},\n)\n```\n\nUseful arguments in `7.2.0` include:\n\n- `user`, `prefix`: choose install destination\n- `kernel_name`, `display_name`: control stable ID vs UI label\n- `env`: inject environment variables into the kernel process\n- `frozen_modules`: control whether the generated kernelspec enables CPython frozen modules\n\nPrefer the CLI unless you are already writing automation in Python.\n\n## Embed A Kernel Inside A Running Process\n\n`embed_kernel()` starts an IPython kernel inside the current process so an external frontend can connect to it.\n\n```python\nfrom ipykernel.embed import embed_kernel\n\ndef main() -> None:\n    data = {\"message\": \"debug me\"}\n    embed_kernel(local_ns={\"data\": data})\n\nif __name__ == \"__main__\":\n    main()\n```\n\nUse this for debugging or interactive inspection of long-running processes, not for normal request handling. The `embed_kernel()` docs note that keyword arguments only affect the first embed call in a given process.\n\n## Connection Info And Runtime Introspection\n\nJupyter frontends launch kernels with a connection file that contains the transport, ports, and HMAC key. From inside a running kernel, you can inspect the active connection info:\n\n```python\nfrom ipykernel.connect import get_connection_info\n\ninfo = get_connection_info(unpack=True)\nprint(info[\"ip\"], info[\"shell_port\"])\n```\n\nUse this for debugging integration issues. Do not log or commit raw connection files or keys.\n\n## Configuration And Security Notes\n\n`ipykernel` does not use cloud-style API authentication. The important configuration surface is the Jupyter kernelspec and the connection file handed to the kernel process.\n\nPractical rules:\n\n- treat the kernelspec as the source of truth for which interpreter launches\n- use `--display-name` for human-readable labels and `--name` for stable automation-friendly IDs\n- use `env=` in the kernelspec only for non-secret defaults; prefer your normal secret-management path for credentials\n- treat the connection file as sensitive because it contains the HMAC signing key and open ports\n- let the frontend launch `ipykernel_launcher` with its generated `-f <connection-file>` argument instead of trying to hand-craft launch commands\n\nIf you are debugging kernel startup, inspect the active kernelspec before changing notebook code.\n\n## Common Pitfalls\n\n- Installing `ipykernel` into one environment does not automatically make another environment's Jupyter frontend use it. Register a kernelspec explicitly.\n- Recreating or moving a virtual environment leaves old kernelspecs behind. If notebooks suddenly start the wrong interpreter, delete or reinstall the stale kernelspec.\n- `--name` collisions overwrite the existing kernelspec for that internal name. Use stable, distinct names per environment.\n- `ipykernel` is not a full frontend stack. You may still need `jupyterlab`, `notebook`, or an editor integration.\n- Do not import low-level `ipykernel` internals just to run notebook code. Frontends start the kernel for you.\n- `embed_kernel()` can block the process waiting for a client connection, so do not drop it into normal production request paths.\n- If you are building a custom Jupyter integration, distinguish `ipykernel` from `jupyter_client`: the former runs the Python kernel, the latter manages client-side protocol connections.\n\n## Version-Sensitive Notes For 7.x\n\n- `ipykernel 7.0.0` introduced experimental subshell support and the changelog explicitly warns that downstream consumers could hit compatibility issues. If a toolchain is not ready for `7.x`, pin `<7` intentionally instead of mixing assumptions from old `6.x` material.\n- `ipykernel 7.2.0` updates the kernel protocol version advertised in the kernelspec to `5.5`.\n- `7.2.0` also switched the IOPub publisher socket to XPUB and upgraded `jupyter_client` to `8.8.0`, which matters mainly if you maintain tooling at the protocol or socket layer.\n- The `frozen_modules` kernelspec option exists in `7.x`; it can improve startup behavior on newer CPython builds, but it may interact badly with some debugging workflows for frozen stdlib modules.\n\nWhen copying older notebook setup instructions, check whether they were written for `6.x` because kernelspec details and protocol behavior changed in the `7.x` line.\n\n## Official Sources Used For This Guide\n\n- Stable docs: `https://ipykernel.readthedocs.io/en/stable/`\n- Changelog: `https://ipykernel.readthedocs.io/en/stable/changelog.html`\n- API reference: `https://ipykernel.readthedocs.io/en/stable/api/ipykernel.html`\n- IPython kernel install guide: `https://ipython.readthedocs.io/en/stable/install/kernel_install.html`\n- PyPI package page: `https://pypi.org/project/ipykernel/`\n"
  },
  {
    "path": "content/ipywidgets/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ipywidgets package guide for Python notebooks and JupyterLab with install, display, events, layouts, and ipywidgets 8 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.1.8\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ipywidgets,jupyter,notebook,jupyterlab,widgets,ui,traitlets\"\n---\n\n# ipywidgets Python Package Guide\n\n## Golden Rule\n\nUse `ipywidgets` in the kernel environment, then make sure the matching frontend support is installed where Jupyter itself runs. If a widget renders as plain text like `IntSlider(value=0)`, the Python package is present but the browser-side widget manager is missing, still loading, or enabled in the wrong environment.\n\n## Install\n\nMost projects only need the package in the active kernel environment:\n\n```bash\npython -m pip install \"ipywidgets==8.1.8\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"ipywidgets==8.1.8\"\npoetry add \"ipywidgets==8.1.8\"\nconda install -c conda-forge ipywidgets\n```\n\n### JupyterLab setup\n\nIf JupyterLab and the kernel use the same environment, installing `ipywidgets` is usually enough.\n\nIf they are split across environments:\n\n1. Install `jupyterlab_widgets` where JupyterLab runs.\n2. Install `ipywidgets` in each kernel environment that should display widgets.\n\nExample:\n\n```bash\nconda install -n base -c conda-forge jupyterlab_widgets\nconda install -n pyenv -c conda-forge ipywidgets\n```\n\nOfficial `ipywidgets` install docs still call out JupyterLab 3.x, but the current `jupyterlab_widgets` docs say the extension enables support in JupyterLab 3.x or 4.x.\n\n### Classic Notebook setup\n\nIf Notebook and the kernel use the same environment, `ipywidgets` usually pulls in the needed frontend pieces automatically.\n\nIf they are split:\n\n1. Install `widgetsnbextension` in the Notebook server environment.\n2. Install `ipywidgets` in each kernel environment.\n\nExample:\n\n```bash\nconda install -n base -c conda-forge widgetsnbextension\nconda install -n pyenv -c conda-forge ipywidgets\n```\n\nFor Notebook `5.2` or earlier, enable the extension manually:\n\n```bash\njupyter nbextension enable --py widgetsnbextension --sys-prefix\n```\n\n### Legacy JupyterLab 1 or 2\n\nFor JupyterLab 1.x or 2.x, you still need the lab extension and Node.js:\n\n```bash\njupyter labextension install @jupyter-widgets/jupyterlab-manager\n```\n\nDo not use this path for JupyterLab 3 or 4 unless you are doing extension development.\n\n## Quick Start\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nslider = widgets.IntSlider(\n    value=5,\n    min=0,\n    max=10,\n    step=1,\n    description=\"Count\",\n    continuous_update=False,\n)\n\ndisplay(slider)\n```\n\nWidgets display automatically when they are the last value in a cell, but `display(...)` is the safer pattern when composing multiple widgets.\n\n## Core Usage\n\n### Read and set widget state\n\nAll widgets expose synchronized trait values such as `value`, `description`, `disabled`, `layout`, and `style`.\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nslider = widgets.IntSlider(value=0, min=-5, max=5, description=\"X\")\ndisplay(slider)\n\nprint(slider.value)   # 0\nslider.value = 3\n```\n\n### Observe changes with traitlets\n\nUse `.observe(...)` for value-driven UI logic. The callback receives a `change` mapping with keys like `owner`, `old`, `new`, and `name`.\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nslider = widgets.IntSlider(description=\"Threshold\", continuous_update=False)\nlabel = widgets.Label(value=\"Threshold is 0\")\n\ndef handle_change(change):\n    label.value = f\"Threshold is {change['new']}\"\n\nslider.observe(handle_change, names=\"value\")\ndisplay(widgets.VBox([slider, label]))\n```\n\nFor expensive callbacks, set `continuous_update=False` on sliders or use `interact_manual` so you do not rerun heavy work on every drag event.\n\n### Button events and debug output\n\nIn JupyterLab, `print(...)` from widget callbacks is easy to lose. Route callback output through an `Output` widget.\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nbutton = widgets.Button(description=\"Run\", button_style=\"primary\", icon=\"play\")\nout = widgets.Output(layout={\"border\": \"1px solid #ddd\"})\n\n@out.capture(clear_output=True)\ndef run_clicked(_):\n    print(\"Button clicked\")\n\nbutton.on_click(run_clicked)\ndisplay(button, out)\n```\n\n### Build simple controls with `interact`\n\n`interact` is the quickest way to turn function parameters into widgets.\n\n```python\nfrom ipywidgets import interact, FloatSlider\n\ndef area(radius):\n    return 3.14159 * radius ** 2\n\ninteract(area, radius=FloatSlider(min=0, max=10, step=0.5, continuous_update=False))\n```\n\nUse `interact_manual(...)` when the callback is slow and should only run on demand.\n\n### Compose layouts and linked controls\n\nWidgets are regular objects, so build layouts explicitly with `VBox`, `HBox`, `GridBox`, `Tab`, `Accordion`, and `Stack`.\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nsource = widgets.IntSlider(description=\"Source\")\ntarget = widgets.IntText(description=\"Target\")\nwidgets.link((source, \"value\"), (target, \"value\"))\n\nui = widgets.VBox([\n    widgets.HTML(\"<b>Linked controls</b>\"),\n    widgets.HBox([source, target]),\n])\n\ndisplay(ui)\n```\n\nUse `widgets.jslink(...)` when you want the sync to happen in the browser without a kernel round-trip.\n\n### Separate controls from rendered output\n\n`interactive_output(...)` is useful when you want a custom layout instead of the default `interact` UI.\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nx = widgets.IntSlider(description=\"a\")\ny = widgets.IntSlider(description=\"b\")\n\ndef render(a, b):\n    print(f\"{a} + {b} = {a + b}\")\n\nout = widgets.interactive_output(render, {\"a\": x, \"b\": y})\ndisplay(widgets.HBox([widgets.VBox([x, y]), out]))\n```\n\n### File uploads in ipywidgets 8\n\n`FileUpload` in `8.x` returns uploaded files through `.value` as file objects with fields such as `name`, `type`, `size`, `last_modified`, and `content`.\n\n```python\nimport io\nimport ipywidgets as widgets\nimport pandas as pd\nfrom IPython.display import display\n\nuploader = widgets.FileUpload(accept=\".csv\", multiple=False)\ndisplay(uploader)\n\ndef handle_upload(change):\n    if not uploader.value:\n        return\n    uploaded = uploader.value[0]\n    df = pd.read_csv(io.BytesIO(uploaded.content))\n    print(uploaded.name, df.head())\n\nuploader.observe(handle_upload, names=\"value\")\n```\n\nTo convert back to the old name-to-bytes shape:\n\n```python\nfiles = {f.name: f.content.tobytes() for f in uploader.value}\n```\n\n## Configuration Notes\n\n- There is no API key or auth flow.\n- The important configuration boundary is environment placement:\n  - kernel environment needs `ipywidgets`\n  - JupyterLab environment may need `jupyterlab_widgets`\n  - classic Notebook environment may need `widgetsnbextension`\n- Browser support matters for some widgets. For example, date and time pickers rely on browser support for the underlying HTML inputs.\n- Displaying the same widget object multiple times creates multiple synchronized views of the same backend state.\n\n## Common Pitfalls\n\n- Seeing `IntSlider(value=0)` instead of a rendered control usually means the widget frontend is missing, disabled, or installed in the wrong environment.\n- Callback output often disappears unless you route it through `widgets.Output()` or write directly into other widgets like `HTML` or `Label`.\n- `FileUpload` stores uploaded content in memory and widget state can end up saved into the notebook. Avoid this for large or sensitive files.\n- `Accordion`, `Tab`, and `Stack` use `selected_index`, not `value`.\n- JupyterLab 1.x and 2.x still need a manual labextension install plus Node.js.\n- `continuous_update=True` can flood the kernel with events during slider drags. Turn it off for expensive work.\n\n## Version-Sensitive Notes For 8.1.8\n\n- `8.1.8` itself is a small release. The upstream release notes call out an update to `jupyterlab_widgets` metadata to indicate compatibility with JupyterLab 4.\n- `8.1.7` removed Python 3.8 in the release notes. Combined with the current PyPI classifiers, that makes Python `3.9+` the practical target for new work even though PyPI metadata still says `>=3.7`. This is an inference from the official sources.\n- In `8.x`, `FileUpload` changed substantially:\n  - `.value` is no longer the old name-to-content mapping\n  - `.data` and `.metadata` were removed\n- `description_tooltip` was deprecated in favor of `tooltip`.\n- Widget descriptions are sanitized on the client side. If you need HTML in `description`, set `description_allow_html=True` only for trusted content.\n- `Layout.overflow_x` and `Layout.overflow_y` were removed; use `overflow`.\n- `ipywidgets` no longer pulls in `notebook` transitively through `widgetsnbextension`. If your workflow needs classic Notebook, install `notebook` explicitly.\n\n## Official Sources\n\n- Stable docs: `https://ipywidgets.readthedocs.io/en/stable/`\n- Installation: `https://ipywidgets.readthedocs.io/en/stable/user_install.html`\n- Widget basics: `https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Basics.html`\n- Widget list: `https://ipywidgets.readthedocs.io/en/8.1.4/examples/Widget%20List.html`\n- Migration guide: `https://ipywidgets.readthedocs.io/en/8.1.4/user_migration_guides.html`\n- JupyterLab manager docs: `https://ipywidgets.readthedocs.io/en/latest/_static/typedoc/modules/_jupyter_widgets_jupyterlab_manager.html`\n- PyPI package page: `https://pypi.org/project/ipywidgets/`\n- GitHub releases: `https://github.com/jupyter-widgets/ipywidgets/releases`\n"
  },
  {
    "path": "content/isodate/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python ISO 8601 parsing and formatting helpers for dates, times, datetimes, durations, and time zones\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"isodate,python,iso8601,date,time,datetime,duration\"\n---\n\n# isodate Python Package Guide\n\n## Golden Rule\n\nUse `isodate` when you need ISO 8601 parsing and formatting with standard Python date/time types. It is a pure library package:\n\n- no environment variables\n- no API keys\n- no client initialization\n\nImport the parsing and formatting helpers directly in the module where you need them.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"isodate==0.7.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"isodate==0.7.2\"\npoetry add \"isodate==0.7.2\"\n```\n\n`isodate 0.7.2` requires Python 3.7 or newer.\n\n## Parse ISO 8601 Values\n\nUse the top-level helpers for the common parsing cases:\n\n```python\nimport isodate\n\ninvoice_date = isodate.parse_date(\"2026-03-13\")\ncutoff_time = isodate.parse_time(\"14:30:00Z\")\npublished_at = isodate.parse_datetime(\"2026-03-13T14:30:00+00:00\")\ntzinfo = isodate.parse_tzinfo(\"+05:30\")\n\nprint(invoice_date.year)\nprint(cutoff_time.tzinfo)\nprint(published_at.utcoffset())\nprint(tzinfo.utcoffset(None))\n```\n\n`parse_date`, `parse_time`, and `parse_datetime` return standard library `date`, `time`, and `datetime` objects. `parse_tzinfo` returns a `tzinfo` object for the offset portion of an ISO 8601 string.\n\n## Parse Durations\n\n`parse_duration()` returns either a `datetime.timedelta` or an `isodate.duration.Duration` depending on the input.\n\nIf the duration has only weeks, days, hours, minutes, or seconds, you usually get a `timedelta`:\n\n```python\nimport isodate\n\nduration = isodate.parse_duration(\"PT90M\")\n\nprint(type(duration).__name__)\nprint(duration.total_seconds())\n```\n\nIf the string includes years or months, use `Duration` semantics:\n\n```python\nimport isodate\n\nduration = isodate.parse_duration(\"P1Y2M3DT4H\")\n\nprint(type(duration).__name__)\nprint(duration.years)\nprint(duration.months)\nprint(duration.days)\n```\n\nVersion `0.7.2` also lets you force a `Duration` result even when a `timedelta` would be possible:\n\n```python\nimport isodate\n\nduration = isodate.parse_duration(\n    \"PT90M\",\n    as_timedelta_if_possible=False,\n)\n\nprint(type(duration).__name__)\n```\n\n## Work With `Duration`\n\nUse `Duration` when you need calendar-aware months or years.\n\n```python\nfrom datetime import date\n\nfrom isodate.duration import Duration\n\nrenewal_window = Duration(years=1, months=1, days=7)\nrenewal_date = date(2026, 1, 31) + renewal_window\n\nprint(renewal_date)\n```\n\nTo convert a `Duration` into a concrete `timedelta`, provide either a `start` or an `end` date:\n\n```python\nfrom datetime import date\n\nfrom isodate.duration import Duration\n\nduration = Duration(months=1, days=3)\ndelta = duration.totimedelta(start=date(2026, 1, 31))\n\nprint(delta.days)\n```\n\n`Duration.totimedelta()` raises `ValueError` if you pass neither `start` nor `end`, or if you pass both.\n\n## Format Python Values Back To ISO 8601\n\nUse the matching `*_isoformat` helpers when you need consistent ISO 8601 output:\n\n```python\nfrom datetime import date, datetime, time, timedelta, timezone\n\nimport isodate\nfrom isodate.duration import Duration\n\nprint(isodate.date_isoformat(date(2026, 3, 13)))\nprint(isodate.time_isoformat(time(14, 30, tzinfo=timezone.utc)))\nprint(isodate.datetime_isoformat(datetime(2026, 3, 13, 14, 30, tzinfo=timezone.utc)))\nprint(isodate.duration_isoformat(timedelta(hours=1, minutes=30)))\nprint(isodate.duration_isoformat(Duration(years=1, months=2, days=3)))\n```\n\nThe default formatting mode is the ISO 8601 expanded form.\n\n## Error Handling\n\nParsing failures raise `ISO8601Error`, which is a subclass of `ValueError`.\n\n```python\nimport isodate\nfrom isodate.isoerror import ISO8601Error\n\ntry:\n    isodate.parse_datetime(\"2026-03-13 14:30:00Z\")\nexcept ISO8601Error as exc:\n    print(f\"Invalid ISO 8601 value: {exc}\")\n```\n\n`parse_datetime()` expects the date-time separator to be `T`, not a space.\n\n## Important Pitfalls\n\n- If a parsed time string has no time zone information, `isodate` treats it as local time, not UTC.\n- Incomplete dates default to the first valid day. For example, a century-style date resolves to January 1 of the first year in that century.\n- Fractional seconds are cut down to microseconds; higher precision is not preserved.\n- `parse_duration()` switches between `timedelta` and `Duration` based on whether years or months are present unless you override `as_timedelta_if_possible`.\n- Negative `Duration` and `timedelta` handling is not fully supported yet.\n- The parser intentionally accepts some date/time combinations that are looser than strict ISO 8601. If you need strict validation, add your own checks around accepted input formats.\n- Alternative duration forms like `PYYYY-MM-DDThh:mm:ss` are supported, but the standard `PnYnMnDTnHnMnS` form is the safer default for application code.\n\n## Version-Sensitive Notes For 0.7.2\n\n- `0.7.2` no longer matches garbage characters at the end of parsed strings. Inputs that used to parse despite trailing junk now fail.\n- `0.7.2` adds the `as_timedelta_if_possible` control on `parse_duration()`.\n- `0.7.2` drops end-of-life Python versions and requires Python 3.7 or newer.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/gweis/isodate\n- README and package usage: https://github.com/gweis/isodate/blob/master/README.rst\n- PyPI project page: https://pypi.org/project/isodate/\n- PyPI package metadata JSON: https://pypi.org/pypi/isodate/json\n"
  },
  {
    "path": "content/isort/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"isort Python package guide for sorting imports from the CLI, pre-commit, editors, and Python code\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.0.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"isort,python,imports,formatting,linter,pre-commit\"\n---\n\n# isort Python Package Guide\n\n## Golden Rule\n\nUse `isort` to normalize Python import blocks, keep the configuration in the repository root, and make the config explicit enough that first-party modules are classified correctly. For `8.0.1`, trust PyPI metadata for runtime support and release versioning over older snippets on the docs site: PyPI says `isort` now requires Python `>=3.10`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"isort==8.0.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"isort==8.0.1\"\npoetry add --group dev \"isort==8.0.1\"\n```\n\nPyPI metadata for `8.0.1` lists only the `colors` extra:\n\n```bash\npython -m pip install \"isort[colors]==8.0.1\"\n```\n\nDo not rely on old docs examples that mention extras such as `requirements_deprecated_finder` or `pipfile_deprecated_finder`; those examples are from older documentation snapshots and do not match current PyPI metadata.\n\n## Setup And Configuration\n\n`isort` does not need authentication. The main setup task is making import classification deterministic.\n\nSupported config locations, in search order:\n\n1. `.isort.cfg`\n2. `pyproject.toml`\n3. `setup.cfg`\n4. `tox.ini`\n5. `.editorconfig`\n\nImportant behavior:\n\n- `isort` walks upward until it finds the nearest supported config file.\n- It stops at the first config file it finds.\n- It does not merge config files.\n- It does not leave a Git or Mercurial repository when searching.\n- Use `--settings-path` to force a config file or root.\n- Use `--show-config` when imports are being classified unexpectedly.\n\nFor most repos, prefer `pyproject.toml`:\n\n```toml\n[tool.isort]\nprofile = \"black\"\npy_version = 311\nsrc_paths = [\"src\", \"tests\"]\nknown_first_party = [\"my_package\"]\nskip_gitignore = true\nfilter_files = true\n```\n\nWhy these settings matter:\n\n- `profile = \"black\"` keeps wrapping compatible with Black.\n- `py_version` avoids stdlib classification drift across Python versions.\n- `src_paths` marks modules under those directories as first-party.\n- `known_first_party` is the escape hatch for packages not covered by `src_paths`.\n- `skip_gitignore = true` makes `isort` honor `.gitignore`, but it requires `git` to be installed.\n- `filter_files = true` matters when files are passed explicitly, which is common in pre-commit.\n\n## Core CLI Usage\n\nSort one or more files in place:\n\n```bash\nisort app.py package/__init__.py\n```\n\nSort a tree recursively:\n\n```bash\nisort .\n```\n\nPreview changes without writing:\n\n```bash\nisort . --diff\n```\n\nFail CI if imports would change:\n\n```bash\nisort . --check-only --diff\n```\n\nUse `--atomic` if you want `isort` to avoid writing changes that would introduce syntax errors:\n\n```bash\nisort --atomic .\n```\n\nUseful debugging commands:\n\n```bash\nisort . --show-config\nisort . --show-files\nisort . --verbose\n```\n\n## Python API Usage\n\n`isort` exposes a direct Python API when you need formatting inside generators, codemods, or editor tooling.\n\nSort code in memory:\n\n```python\nimport isort\n\nsource = \"\"\"\nimport requests\nimport os\nfrom my_package import api\n\"\"\"\n\nresult = isort.code(source, profile=\"black\")\nprint(result)\n```\n\nCheck code in memory without rewriting:\n\n```python\nimport isort\n\nif not isort.check_code(source, profile=\"black\"):\n    raise ValueError(\"Imports are not sorted\")\n```\n\nSort a file on disk:\n\n```python\nimport isort\n\nisort.file(\"app.py\", profile=\"black\")\n```\n\nDebug import placement:\n\n```python\nimport isort\n\nsection = isort.place_module(\"my_package\", known_first_party=[\"my_package\"])\nprint(section)\n```\n\nThe quick-start docs use convenience names like `isort.code`, `isort.check_code`, `isort.file`, and `isort.place_module`. The API reference also documents the underlying `sort_code_string`, `check_code_string`, `sort_file`, and related functions.\n\n## Pre-commit And Formatter Integration\n\nIf a repo uses Black, set the profile in config instead of only passing CLI flags. That keeps editor integrations, pre-commit, and local CLI runs aligned.\n\nExample `.pre-commit-config.yaml`:\n\n```yaml\nrepos:\n  - repo: https://github.com/PyCQA/isort\n    rev: 8.0.1\n    hooks:\n      - id: isort\n        args: [\"--filter-files\"]\n```\n\nNotes:\n\n- The official pre-commit docs page still shows older `5.x` revisions; pin the hook to the current tag your repo has standardized on.\n- The old `pre-commit/mirrors-isort` repository is deprecated. Use `PyCQA/isort` directly.\n- If your repo still uses `seed-isort-config`, remove it unless you have a very specific legacy reason. The official docs say modern `isort` placement logic made that helper unnecessary starting in `isort 5`.\n\n## Common Pitfalls\n\n### First-party imports are grouped as third-party\n\nUsually this means `src_paths`, `known_first_party`, `virtual_env`, or `conda_env` is not configured for the project layout. Check the resolved config first:\n\n```bash\nisort path/to/file.py --show-config\n```\n\n### Running from the wrong directory changes the chosen config\n\nConfig lookup is relative to the current directory for `isort .` and relative to the first explicit path when multiple paths are passed. If results vary between CI and local runs, compare working directories and use `--settings-path` if needed.\n\n### `.gitignore` is not respected\n\n`skip_gitignore` is off by default. Turn it on with `skip_gitignore = true` or `--skip-gitignore`, and make sure `git` is available in the environment.\n\n### Pre-commit still rewrites files you expected it to skip\n\nWhen pre-commit passes explicit file paths, add `filter_files = true` in config or `--filter-files` in hook args.\n\n### Standard library classification is wrong for the project target\n\nSet `py_version` to the project target instead of relying on the default union of Python 3 stdlib modules.\n\n### isort and Black keep fighting\n\nSet `profile = \"black\"` once in repo config. Do not try to hand-tune wrap settings unless the project has intentionally diverged from Black-compatible formatting.\n\n## Version-Sensitive Notes For 8.0.1\n\n- PyPI lists `8.0.1` as the latest release on February 28, 2026.\n- PyPI metadata for `8.0.1` requires Python `>=3.10`.\n- The docs home page still says `Python 3.7+`, which is stale for current releases.\n- The docs site still includes older pre-commit snippets such as `rev: 5.11.2` and older Black compatibility examples with `rev: 5.6.4`; update those revisions when copying examples.\n- The docs site still includes older optional-install examples that do not match current extras metadata on PyPI.\n- GitHub’s public release page appears behind the current PyPI version in some crawled views, so use PyPI as the canonical source for the package version and Python requirement.\n\n## Official Sources\n\n- Docs: `https://pycqa.github.io/isort/`\n- Config files: `https://pycqa.github.io/isort/docs/configuration/config_files.html`\n- Options: `https://pycqa.github.io/isort/docs/configuration/options.html`\n- Black compatibility: `https://pycqa.github.io/isort/docs/configuration/black_compatibility.html`\n- Pre-commit: `https://pycqa.github.io/isort/docs/configuration/pre-commit.html`\n- Python API quick start: `https://pycqa.github.io/isort/docs/quick_start/3.-api.html`\n- Python API reference: `https://pycqa.github.io/isort/reference/isort/api.html`\n- PyPI project page: `https://pypi.org/project/isort/`\n- PyPI JSON metadata: `https://pypi.org/pypi/isort/json`\n"
  },
  {
    "path": "content/itsdangerous/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Official itsdangerous package guide for Python token signing, URL-safe payloads, and expiring signatures\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.2.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"itsdangerous,pallets,python,signing,tokens,security\"\n---\n\n# itsdangerous Python Package Guide\n\n## What It Is\n\n`itsdangerous` signs data so you can send it through untrusted places such as URLs, cookies, or form fields and later verify that it was not modified.\n\nUse it for integrity and optional expiration. Do not use it for confidentiality: the payload is readable by the client unless you encrypt it separately.\n\n## Install\n\n```bash\npip install itsdangerous==2.2.0\n```\n\n- Package: `itsdangerous`\n- Version covered: `2.2.0`\n- Python requirement: `>=3.8`\n- Docs family: `2.2.x`\n\n## Choose The Right API\n\n| Need | API |\n| --- | --- |\n| Sign raw strings or bytes | `Signer` |\n| Sign structured Python data | `Serializer` |\n| Put signed data in URLs or cookies | `URLSafeSerializer` |\n| Add expiration to structured data | `URLSafeTimedSerializer` |\n| Add expiration to raw strings or bytes | `TimestampSigner` |\n\nIn most application code, start with `URLSafeSerializer` or `URLSafeTimedSerializer`.\n\n## Setup\n\nKeep the secret key outside source control and use a unique salt per token purpose.\n\n```python\nimport os\n\nfrom itsdangerous.url_safe import URLSafeTimedSerializer\n\nSECRET_KEY = os.environ[\"ITSDANGEROUS_SECRET_KEY\"]\n\nemail_tokens = URLSafeTimedSerializer(\n    secret_key=SECRET_KEY,\n    salt=\"email-confirm-v1\",\n)\n```\n\nGenerate a secret once and store it in your environment or secret manager:\n\n```bash\npython3 -c 'import os; print(os.urandom(32).hex())'\n```\n\n## Core Usage\n\n### Sign And Verify Structured Data\n\n```python\nfrom itsdangerous.exc import BadSignature\nfrom itsdangerous.url_safe import URLSafeSerializer\n\nserializer = URLSafeSerializer(\n    secret_key=\"replace-me-from-env\",\n    salt=\"invite-link-v1\",\n)\n\ntoken = serializer.dumps(\n    {\n        \"user_id\": 123,\n        \"role\": \"viewer\",\n    }\n)\n\nprint(token)\n\ntry:\n    payload = serializer.loads(token)\n    assert payload[\"user_id\"] == 123\nexcept BadSignature:\n    payload = None\n```\n\nNotes:\n\n- `dumps()` returns a signed string.\n- `loads()` verifies the signature before returning the payload.\n- The default serializer is JSON, so prefer JSON-compatible payloads.\n\n### URL-Safe Tokens With Expiration\n\nUse timed serializers for password reset links, email verification links, and one-click actions.\n\n```python\nfrom typing import Optional\n\nfrom itsdangerous.exc import BadSignature, SignatureExpired\nfrom itsdangerous.url_safe import URLSafeTimedSerializer\n\nserializer = URLSafeTimedSerializer(\n    secret_key=\"replace-me-from-env\",\n    salt=\"password-reset-v1\",\n)\n\ntoken = serializer.dumps({\"user_id\": 123})\n\ndef load_reset_token(token: str) -> Optional[int]:\n    try:\n        data = serializer.loads(token, max_age=3600)\n    except SignatureExpired:\n        return None\n    except BadSignature:\n        return None\n    else:\n        return int(data[\"user_id\"])\n```\n\nNotes:\n\n- `max_age` is in seconds.\n- Expired tokens raise `SignatureExpired`.\n- Other tampering or decode problems raise `BadSignature` or a subclass.\n\n### Raw Signing Without Serialization\n\nUse `Signer` when you already have the exact bytes or string you want to protect.\n\n```python\nfrom itsdangerous import Signer\nfrom itsdangerous.exc import BadSignature\n\nsigner = Signer(\"replace-me-from-env\", salt=\"download-token-v1\")\nsigned_value = signer.sign(\"user:123\")\n\ntry:\n    original = signer.unsign(signed_value).decode()\nexcept BadSignature:\n    original = None\n```\n\nUse `TimestampSigner` instead when the raw value should expire.\n\n## Config And Security Patterns\n\n### Secret Key\n\n- Use a long random secret.\n- Load it from environment variables or a secret manager.\n- Changing the secret invalidates existing tokens.\n- If the secret leaks, rotate it immediately and invalidate old tokens.\n\n### Salt Separation\n\nUse a different salt for each token purpose. Do not reuse one salt for unrelated actions.\n\nGood examples:\n\n- `email-confirm-v1`\n- `password-reset-v1`\n- `unsubscribe-link-v1`\n\nIf you sign the same payload for different actions with the same salt, a token issued for one action may be replayed in another context.\n\n### Key Rotation\n\n`itsdangerous` supports key rotation by accepting a list of keys, oldest to newest. The newest key signs new tokens, and all keys are tried for verification.\n\n```python\nfrom itsdangerous.url_safe import URLSafeTimedSerializer\n\nSECRET_KEYS = [\n    \"oldest-key\",\n    \"current-key\",\n    \"newest-key\",\n]\n\nserializer = URLSafeTimedSerializer(\n    secret_key=SECRET_KEYS,\n    salt=\"email-confirm-v1\",\n)\n```\n\nThis is the safest way to rotate secrets without invalidating every in-flight token immediately.\n\n### Upgrading Digest Settings\n\nIf you need to change signer parameters such as the digest method, use `fallback_signers` so older tokens still validate during rollout.\n\n```python\nimport hashlib\n\nfrom itsdangerous.serializer import Serializer\n\nserializer = Serializer(\n    secret_key=\"replace-me-from-env\",\n    signer_kwargs={\"digest_method\": hashlib.sha512},\n    fallback_signers=[{\"digest_method\": hashlib.sha1}],\n)\n```\n\nThis is for compatibility rollouts, not for secrecy.\n\n## Error Handling\n\nCommon exceptions:\n\n- `BadSignature`: signature does not validate.\n- `BadTimeSignature`: time-based signature is invalid.\n- `SignatureExpired`: token is validly signed but older than `max_age`.\n\nPattern:\n\n```python\nfrom itsdangerous.exc import BadSignature, SignatureExpired\n\ntry:\n    data = serializer.loads(token, max_age=3600)\nexcept SignatureExpired:\n    # Token was issued by you, but it is too old.\n    ...\nexcept BadSignature:\n    # Token was tampered with or is otherwise invalid.\n    ...\n```\n\nAvoid `loads_unsafe()` in production request handling. It skips signature verification and is only appropriate for tightly controlled debugging flows.\n\n## Common Pitfalls\n\n### Treating Signed Data As Encrypted\n\n`itsdangerous` signs data; it does not hide the data. Do not put secrets, API keys, or private user information in a token unless you encrypt first.\n\n### Reusing One Salt Everywhere\n\nSalt is meant to separate trust contexts. Reusing a generic salt such as `\"default\"` across many token types weakens that separation and makes cross-purpose replay easier.\n\n### Embedding The Secret Key In Code\n\nDo not hardcode the secret in application code, tests that ship to users, or committed config files.\n\n### Depending On `__version__`\n\nIn `2.2.0`, the `__version__` attribute is deprecated. Use feature detection or:\n\n```python\nfrom importlib.metadata import version\n\npackage_version = version(\"itsdangerous\")\n```\n\n### Using Removed JWS APIs\n\nOlder examples may reference `JSONWebSignatureSerializer` or `TimedJSONWebSignatureSerializer`. JWS support was deprecated in `2.0.0` and removed in `2.1.0`. Use a dedicated JWT or JWS library such as Authlib when you need standards-based tokens.\n\n### Assuming You Must Replace SHA-1 Immediately\n\nThe Pallets docs note that the default SHA-1 is used inside HMAC, where the collision concerns do not apply in the same way. If your environment still requires a different digest, configure it explicitly and plan compatibility with `fallback_signers`.\n\n## Version-Sensitive Notes For 2.2.0\n\n- `2.2.0` was released on `2024-04-16`.\n- Python `3.7` support was dropped in `2.2.0`; current requirement is Python `>=3.8`.\n- `__version__` is deprecated in `2.2.0`.\n- `Serializer` typing in `2.2.0` is more explicit for type checkers.\n- The changelog notes that FIPS builds may not expose the default `hashlib.sha1` in the same way at import time; if you run in FIPS-constrained environments, test token creation and verification explicitly.\n- Since `2.1.0`, JWS functionality is gone and `itsdangerous.json` should not be imported.\n\n## Practical Recommendations For Agents\n\n- Default to `URLSafeTimedSerializer` for emailed action links and other expiring user-facing tokens.\n- Use a purpose-specific salt and a stable payload schema such as `{\"user_id\": ..., \"action\": ...}`.\n- Treat token verification failures as normal control flow, not as crashes.\n- Prefer key rotation lists over forced global invalidation when you need secret rotation.\n- If you are integrating with Flask or another framework that already has a secret-key convention, reuse the framework secret-management pattern instead of inventing a second config path.\n\n## Official Sources\n\n- Documentation: `https://itsdangerous.palletsprojects.com/en/stable/`\n- Concepts: `https://itsdangerous.palletsprojects.com/en/stable/concepts/`\n- Serialization: `https://itsdangerous.palletsprojects.com/en/stable/serializer/`\n- URL-safe serialization: `https://itsdangerous.palletsprojects.com/en/stable/url_safe/`\n- Timed signing: `https://itsdangerous.palletsprojects.com/en/stable/timed/`\n- Signing: `https://itsdangerous.palletsprojects.com/en/stable/signer/`\n- Changelog: `https://itsdangerous.palletsprojects.com/en/stable/changes/`\n- PyPI release page: `https://pypi.org/project/itsdangerous/2.2.0/`\n"
  },
  {
    "path": "content/jax/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"JAX package guide for Python projects using transform-based array computing, autodiff, and accelerator backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"jax,python,autodiff,numpy,xla,gpu,tpu\"\n---\n\n# JAX Python Package Guide\n\n## Golden Rule\n\nUse `jax` together with the `jaxlib` build selected by the official installer path for your hardware. Write transformed code in terms of `jax.numpy`, `jax.lax`, and other JAX-aware APIs, not raw NumPy inside `jit`/`grad`/`vmap`.\n\n## Install\n\nJAX installs as two pieces:\n\n- `jax`: pure Python package\n- `jaxlib`: compiled backend/runtime package selected for your OS and accelerator\n\nFor most projects, let the official extras resolve the matching backend package.\n\n### CPU\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"jax==0.9.1\"\n```\n\n### NVIDIA GPU\n\nCUDA 13 wheels:\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"jax[cuda13]==0.9.1\"\n```\n\nCUDA 12 wheels:\n\n```bash\npython -m pip install \"jax[cuda12]==0.9.1\"\n```\n\nNotes:\n\n- JAX supports NVIDIA GPUs with SM `5.2+` on CUDA 12 and `7.5+` on CUDA 13.\n- For CUDA 13 on Linux, the NVIDIA driver must be `>= 580`.\n- Native Windows GPU is not supported; WSL2 GPU support is experimental.\n\n### Google Cloud TPU VM\n\n```bash\npython -m pip install \"jax[tpu]==0.9.1\"\n```\n\n### Other extras published on PyPI\n\nPyPI currently lists extras including `minimum-jaxlib`, `cpu`, `tpu`, `cuda`, `cuda12`, `cuda13`, `cuda12-local`, `cuda13-local`, `rocm`, `k8s`, and `xprof`.\n\n## Initialize And Verify The Backend\n\nJAX chooses the best available backend by default. Check what it actually initialized before assuming GPU or TPU execution:\n\n```python\nimport jax\nimport jax.numpy as jnp\n\nprint(jax.__version__)\nprint(jax.default_backend())\nprint(jax.devices())\n\nx = jnp.arange(5)\nprint(x)\n```\n\nIf you need to force CPU for reproducibility or debugging:\n\n```bash\nexport JAX_PLATFORMS=cpu\n```\n\nJAX has no package-level authentication. Any auth or IAM setup is handled by the surrounding platform, such as access to a Cloud TPU VM or cluster runtime, not by `jax` itself.\n\n## Core Usage\n\n### Array programming with `jax.numpy`\n\nUse `jax.numpy` as the default array API:\n\n```python\nimport jax.numpy as jnp\n\nx = jnp.linspace(0.0, 1.0, 5)\ny = jnp.sin(x) + 2 * x\nprint(y)\n```\n\n### Automatic differentiation with `jax.grad`\n\n```python\nimport jax\nimport jax.numpy as jnp\n\ndef loss(x):\n    return jnp.sum(jnp.log1p(jnp.exp(x)))\n\ngrad_loss = jax.grad(loss)\nprint(grad_loss(jnp.array([0.0, 1.0, 2.0])))\n```\n\n### JIT compilation with `jax.jit`\n\n```python\nimport jax\nimport jax.numpy as jnp\n\ndef normalize_rows(x):\n    x = x - x.mean(axis=0)\n    return x / x.std(axis=0)\n\nnormalize_rows_jit = jax.jit(normalize_rows)\n\nx = jnp.arange(12.0).reshape(4, 3)\nresult = normalize_rows_jit(x)\nprint(result.block_until_ready())\n```\n\nCall `block_until_ready()` when benchmarking or timing JAX code, because execution is asynchronous.\n\n### Vectorization with `jax.vmap`\n\n```python\nimport jax\nimport jax.numpy as jnp\n\ndef squared_norm(x):\n    return jnp.sum(x * x)\n\nbatched_squared_norm = jax.vmap(squared_norm)\n\nx = jnp.arange(12.0).reshape(4, 3)\nprint(batched_squared_norm(x))\n```\n\n### Random numbers use explicit keys\n\nJAX random state is explicit and stateless. Split keys instead of reusing them:\n\n```python\nfrom jax import random\n\nkey = random.key(0)\nkey1, key2 = random.split(key)\n\nsample_a = random.normal(key1, (2, 3))\nsample_b = random.normal(key2, (2, 3))\n```\n\n## Configuration\n\nJAX configuration can be set with environment variables before process start or with `jax.config.update(...)` early in Python startup.\n\n### Enable 64-bit types\n\nJAX defaults `jax_enable_x64` to `False`.\n\nEnvironment variable:\n\n```bash\nexport JAX_ENABLE_X64=True\n```\n\nRuntime config:\n\n```python\nimport jax\n\njax.config.update(\"jax_enable_x64\", True)\n```\n\n### Debug transformed code\n\nDisable JIT to debug Python behavior more directly:\n\n```bash\nexport JAX_DISABLE_JIT=True\n```\n\nRaise on NaNs:\n\n```bash\nexport JAX_DEBUG_NANS=True\n```\n\nUseful config options for practical debugging and ops work:\n\n- `JAX_PLATFORMS`: restrict backend initialization order, for example `cpu` or `cpu,tpu`\n- `JAX_COMPILATION_CACHE_DIR`: persistent compilation cache directory\n- `JAX_EXPLAIN_CACHE_MISSES`: log why JAX missed tracing or compilation caches\n\n## Common Pitfalls\n\n### JAX arrays are immutable\n\nThis fails:\n\n```python\nx = jnp.arange(5)\nx[0] = 10\n```\n\nUse indexed updates that return a new array:\n\n```python\nx = x.at[0].set(10)\n```\n\n### Do not call raw NumPy inside transformed JAX code\n\nThis is a common source of `TracerArrayConversionError`:\n\n```python\nimport numpy as np\nfrom jax import jit\n\n@jit\ndef f(x):\n    return np.sin(x)\n```\n\nUse `jax.numpy` inside transformed functions instead.\n\n### `jit` requires static output shapes\n\nBoolean masking that changes output size is incompatible with `jit`:\n\n```python\n@jax.jit\ndef positives(x):\n    return x[x > 0]\n```\n\nRewrite logic with shape-preserving operations such as `jnp.where(...)` when possible.\n\n### Python control flow on traced values fails\n\nThis often surfaces as `TracerBoolConversionError`:\n\n- `if traced_value: ...`\n- `min(x, 0)` or other non-JAX Python helpers inside `jit`\n\nUse `jnp.where`, `jax.lax.cond`, `jax.lax.scan`, or mark true configuration arguments as static with `static_argnums` or `static_argnames`.\n\n### Do not leak traced values through side effects\n\nAppending traced values to outer lists, mutating globals, or keeping references from inside `jit` can lead to `UnexpectedTracerError`. Return values explicitly from the transformed function instead.\n\n### Random keys must be split, not reused\n\nReusing a key is a logic bug. JAX exposes `KeyReuseError` and related docs because PRNG state is manual.\n\n### Backend assumptions are often wrong\n\nJAX will try to initialize all available platforms and defaults to GPU or TPU when possible, otherwise CPU. If your environment is fragile, set `JAX_PLATFORMS` explicitly and print `jax.default_backend()` / `jax.devices()` at process start.\n\n## Version-Sensitive Notes For `0.9.1`\n\n- As of March 12, 2026, PyPI lists `jax 0.9.1` as the latest release, published on March 2, 2026.\n- The docs URL `https://jax.readthedocs.io/en/latest/` redirects to the canonical docs root `https://docs.jax.dev/en/latest/`.\n- JAX `0.9.1` adds the debug config `jax_compilation_cache_check_contents`, which helps verify persistent compilation cache content consistency.\n- JAX `0.9.0` added `jax.thread_guard()` for detecting multi-thread device misuse in multi-controller JAX.\n- JAX `0.9.0` removed `jax_collectives_common_channel_id` and `jax_pmap_no_rank_reduction`.\n- JAX `0.9.0` deprecated `jax.numpy.fix()` in favor of `jax.numpy.trunc()`.\n\n## Official Sources\n\n- Docs root: https://docs.jax.dev/en/latest/\n- Installation: https://docs.jax.dev/en/latest/installation.html\n- Thinking in JAX: https://docs.jax.dev/en/latest/notebooks/thinking_in_jax.html\n- Configuration options: https://docs.jax.dev/en/latest/config_options.html\n- Errors: https://docs.jax.dev/en/latest/errors.html\n- Changelog: https://docs.jax.dev/en/latest/changelog.html\n- PyPI: https://pypi.org/project/jax/\n"
  },
  {
    "path": "content/jest/docs/jest/javascript/DOC.md",
    "content": "---\nname: jest\ndescription: \"Jest test runner for JavaScript projects, including configuration, async tests, mocks, snapshots, and CLI usage\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"30.3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"jest,testing,javascript,unit-testing,mocking,snapshots\"\n---\n\n# Jest for JavaScript\n\nJest runs JavaScript tests, provides `expect` assertions, includes mock helpers such as `jest.fn()` and `jest.spyOn()`, and supports snapshots and watch mode from the CLI.\n\nThis guide covers the common Node.js setup for `jest@30.3.0` and the extra step required for browser-like DOM tests.\n\n## Requirements\n\n- Node.js must satisfy Jest 30's engine range: `^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0`.\n- Install Jest as a development dependency.\n- No environment variables are required for normal local runs.\n- In CI, providers usually set `CI=true` automatically. Jest treats that as CI mode, so snapshot files are not written unless you also pass `-u` or `--updateSnapshot`.\n\n## Install and add a test script\n\n```bash\nnpm install --save-dev jest\n```\n\nAdd a `test` script in `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"test\": \"jest\"\n  }\n}\n```\n\nCheck the installed version:\n\n```bash\nnpx jest --version\n```\n\n## Write a first test\n\nJest finds tests in files such as `*.test.js`, `*.spec.js`, and files under `__tests__/`.\n\n`sum.js`\n\n```javascript\nfunction sum(a, b) {\n  return a + b;\n}\n\nmodule.exports = { sum };\n```\n\n`sum.test.js`\n\n```javascript\nconst { sum } = require('./sum');\n\ntest('adds two numbers', () => {\n  expect(sum(1, 2)).toBe(3);\n});\n```\n\nRun all tests:\n\n```bash\nnpm test\n```\n\nWhen passing extra flags through `npm test`, include `--` before the Jest flags:\n\n```bash\nnpm test -- --watch\n```\n\n## Add a config file\n\nJest supports config files such as `jest.config.js`, `jest.config.ts`, `jest.config.mjs`, `jest.config.cjs`, `jest.config.cts`, and `jest.config.json`.\n\nUse `jest.config.cjs` for a CommonJS config that still works when your `package.json` sets `\"type\": \"module\"`:\n\n```javascript\n/** @type {import('jest').Config} */\nmodule.exports = {\n  testEnvironment: 'node',\n  clearMocks: true,\n  setupFilesAfterEnv: ['<rootDir>/test/setup.js'],\n};\n```\n\n`test/setup.js`\n\n```javascript\nafterEach(() => {\n  jest.restoreAllMocks();\n});\n```\n\nNotes:\n\n- The default test environment in Jest 30 is Node (`jest-environment-node`).\n- `clearMocks: true` clears mock call state before each test.\n- `setupFilesAfterEnv` runs after the test framework is installed, so global helpers such as `afterEach` and `jest` are available there.\n- The examples in this guide use CommonJS test files and a CommonJS config. If your project uses ESM, switch the config to `jest.config.mjs` or keep the config in `jest.config.cjs` and update your test and module syntax accordingly.\n\n## Async tests\n\nUse `async` / `await`, or return a promise directly.\n\n`user-service.js`\n\n```javascript\nasync function loadUser(getUserById, id) {\n  return getUserById(id);\n}\n\nmodule.exports = { loadUser };\n```\n\n`user-service.test.js`\n\n```javascript\nconst { loadUser } = require('./user-service');\n\ntest('loads a user', async () => {\n  const getUserById = jest.fn().mockResolvedValue({\n    id: 42,\n    name: 'Ada',\n  });\n\n  await expect(loadUser(getUserById, 42)).resolves.toEqual({\n    id: 42,\n    name: 'Ada',\n  });\n\n  expect(getUserById).toHaveBeenCalledWith(42);\n});\n```\n\nFor rejected promises:\n\n```javascript\ntest('handles failures', async () => {\n  const getUserById = jest.fn().mockRejectedValue(new Error('timeout'));\n\n  await expect(loadUser(getUserById, 42)).rejects.toThrow('timeout');\n});\n```\n\n## Mocks and spies\n\nUse `jest.fn()` for stand-alone mocks and `jest.spyOn()` when you want to replace an existing method temporarily.\n\n```javascript\ntest('spies on Date.now', () => {\n  const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(1700000000000);\n\n  expect(Date.now()).toBe(1700000000000);\n\n  nowSpy.mockRestore();\n});\n```\n\nIf you use `jest.spyOn()`, restore the original implementation in the test itself or from a shared `afterEach` hook.\n\n## Snapshot tests\n\nSnapshots are useful for stable serialized output.\n\n```javascript\ntest('matches the saved order snapshot', () => {\n  expect({\n    id: 'ord_123',\n    total: 4200,\n    items: ['keyboard', 'cable'],\n  }).toMatchSnapshot();\n});\n```\n\nCreate or update snapshots:\n\n```bash\nnpm test -- -u\n```\n\nIn CI mode, Jest does not write snapshot files unless you explicitly pass `-u` or `--updateSnapshot`.\n\n## DOM tests with jsdom\n\nJest 30 defaults to the Node environment. If your tests use `window`, `document`, or other browser APIs, install the jsdom environment package and switch the environment.\n\n```bash\nnpm install --save-dev jest jest-environment-jsdom\n```\n\n`jest.config.cjs`\n\n```javascript\n/** @type {import('jest').Config} */\nmodule.exports = {\n  testEnvironment: 'jsdom',\n};\n```\n\n`dom.test.js`\n\n```javascript\ntest('renders a button label', () => {\n  document.body.innerHTML = '<button>Save</button>';\n\n  expect(document.querySelector('button').textContent).toBe('Save');\n});\n```\n\n## Useful CLI commands\n\nRun a single test file:\n\n```bash\nnpx jest sum.test.js\n```\n\nRun tests whose names match a pattern:\n\n```bash\nnpx jest -t \"adds two numbers\"\n```\n\nRun in watch mode:\n\n```bash\nnpx jest --watch\n```\n\nRun all tests and collect coverage:\n\n```bash\nnpx jest --coverage\n```\n\nRun tests serially in one process:\n\n```bash\nnpx jest --runInBand\n```\n\nUpdate snapshots:\n\n```bash\nnpx jest --updateSnapshot\n```\n\nRun tests related to changed source files:\n\n```bash\nnpx jest --findRelatedTests src/sum.js\n```\n\nShow the resolved version:\n\n```bash\nnpx jest --version\n```\n\n## Common pitfalls\n\n- Jest does not require environment variables for basic usage, but `CI=true` changes behavior by disabling interactive watch mode and preventing snapshot writes unless you pass `-u`.\n- `jest` includes the test runner and CLI, but DOM testing requires `jest-environment-jsdom` as a separate development dependency.\n- Keep your config file format aligned with your module system. `module.exports` configs belong in `jest.config.cjs`; ESM configs belong in `jest.config.mjs`.\n- `clearMocks` only clears mock usage data. If you replace real implementations with `jest.spyOn()` or manual mocks, restore them between tests.\n- If your project relies on TypeScript, JSX, or other non-Node syntax, add the matching transform toolchain for that syntax instead of assuming Jest will compile it automatically.\n\n## Official sources\n\n- Jest docs: https://jestjs.io/docs/api\n- Jest CLI docs: https://jestjs.io/docs/cli\n- Jest configuration docs: https://jestjs.io/docs/configuration\n- Jest async docs: https://jestjs.io/docs/asynchronous\n- Jest mock functions docs: https://jestjs.io/docs/mock-functions\n- Jest snapshot docs: https://jestjs.io/docs/snapshot-testing\n- npm package: https://www.npmjs.com/package/jest\n"
  },
  {
    "path": "content/jinja2/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Jinja2 package guide for Python templating, environment setup, and safe rendering\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.6\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"jinja2,templating,html,python,sandbox\"\n---\n\n# Jinja2 Python Package Guide\n\n## What It Is\n\n`Jinja2` is the Pallets template engine for Python. Use it when you need reusable text or HTML templates, template inheritance, macros, filters, tests, or sandboxed rendering.\n\n- Package: `Jinja2`\n- Import name: `jinja2`\n- Version covered: `3.1.6`\n- Docs family: `3.1.x`\n\n## Installation\n\nInstall the pinned package version when you need behavior aligned with this guide:\n\n```bash\npip install Jinja2==3.1.6\n```\n\n`MarkupSafe` is installed automatically. `Babel` is optional if you need template translation support.\n\n## Initialization And Setup\n\nFor real applications, create one `Environment` during app startup and reuse it. Avoid creating ad hoc `Template(...)` instances for application templates because that uses a shared anonymous environment.\n\n### Package-based templates\n\nUse `PackageLoader` when templates live inside an importable Python package:\n\n```python\nfrom jinja2 import Environment, PackageLoader, StrictUndefined, select_autoescape\n\nenv = Environment(\n    loader=PackageLoader(\"yourapp\"),\n    autoescape=select_autoescape([\"html\", \"htm\", \"xml\"]),\n    undefined=StrictUndefined,\n    trim_blocks=True,\n    lstrip_blocks=True,\n)\n```\n\n### Filesystem-based templates\n\nUse `FileSystemLoader` when templates live in a project directory:\n\n```python\nfrom jinja2 import Environment, FileSystemLoader, StrictUndefined, select_autoescape\n\nenv = Environment(\n    loader=FileSystemLoader(\"templates\"),\n    autoescape=select_autoescape([\"html\", \"htm\", \"xml\"]),\n    undefined=StrictUndefined,\n)\n```\n\n### String templates\n\nUse `from_string()` for short dynamic templates, tests, or generated content:\n\n```python\nfrom jinja2 import Environment, StrictUndefined\n\nenv = Environment(undefined=StrictUndefined)\ntemplate = env.from_string(\"Hello {{ name }}!\")\nprint(template.render(name=\"Ada\"))\n```\n\n## Core Usage\n\n### Render a template file\n\n```python\ntemplate = env.get_template(\"emails/welcome.html\")\nhtml = template.render(user={\"name\": \"Ada\"}, project_name=\"Sample Portal\")\n```\n\n### Inheritance and blocks\n\nJinja is strongest when you use a base template plus child templates:\n\n```jinja\n{# templates/base.html #}\n<!doctype html>\n<html>\n  <body>\n    {% block content %}{% endblock %}\n  </body>\n</html>\n```\n\n```jinja\n{# templates/home.html #}\n{% extends \"base.html\" %}\n\n{% block content %}\n  <h1>{{ title }}</h1>\n{% endblock %}\n```\n\n```python\nhtml = env.get_template(\"home.html\").render(title=\"Dashboard\")\n```\n\n### Includes, imports, and macros\n\nUse `include` for partial templates and `import` / `from ... import` for macro libraries:\n\n```jinja\n{# templates/forms.html #}\n{% macro input(name, value=\"\", type=\"text\") -%}\n  <input type=\"{{ type }}\" name=\"{{ name }}\" value=\"{{ value|e }}\">\n{%- endmacro %}\n```\n\n```jinja\n{% import \"forms.html\" as forms %}\n{{ forms.input(\"email\") }}\n```\n\nImportant context rule:\n\n- `include` gets the current context by default.\n- Imported templates do not get the current context by default because imports are cached.\n- Use `with context` explicitly if imported macros need access to current template variables.\n\n### Custom filters, tests, and globals\n\nRegister these on the environment before loading templates:\n\n```python\nfrom markupsafe import Markup\n\ndef initials(value: str) -> str:\n    return \"\".join(part[0].upper() for part in value.split() if part)\n\ndef is_even(value: int) -> bool:\n    return value % 2 == 0\n\nenv.filters[\"initials\"] = initials\nenv.tests[\"even\"] = is_even\nenv.globals[\"cdn_host\"] = \"https://cdn.example.com\"\n\ntemplate = env.from_string(\n    \"{{ user.name|initials }} {% if count is even %}even{% endif %}\"\n)\nprint(template.render(user={\"name\": \"Ada Lovelace\"}, count=4))\n```\n\nIf a filter or test needs environment or context data, use `pass_environment`, `pass_eval_context`, or `pass_context`.\n\n### Async rendering\n\nEnable async mode only if your template calls async functions or iterates async values:\n\n```python\nfrom jinja2 import Environment\n\nenv = Environment(enable_async=True)\ntemplate = env.from_string(\"Hello {{ awaitable_name() }}\")\n\nasync def awaitable_name():\n    return \"Ada\"\n\nresult = await template.render_async(awaitable_name=awaitable_name)\n```\n\nWith async enabled, Jinja compiles different code paths and `render_async()` / `generate_async()` become available.\n\n### Native Python types\n\nIf you want template output to be a Python value instead of always a string, use `NativeEnvironment`:\n\n```python\nfrom jinja2.nativetypes import NativeEnvironment\n\nenv = NativeEnvironment()\ntemplate = env.from_string(\"{{ x + y }}\")\nresult = template.render(x=4, y=2)\n\nassert result == 6\nassert isinstance(result, int)\n```\n\nThis is useful for config generation or lightweight expression evaluation, not just HTML rendering.\n\n## Configuration And Safety Notes\n\nJinja2 has no network authentication or service credentials. The main setup work is environment configuration.\n\n### Autoescaping\n\nDo not rely on defaults for HTML. Configure autoescaping explicitly:\n\n```python\nfrom jinja2 import Environment, select_autoescape\n\nenv = Environment(\n    autoescape=select_autoescape(\n        enabled_extensions=(\"html\", \"htm\", \"xml\"),\n        default_for_string=True,\n    )\n)\n```\n\nThe upstream API docs explicitly encourage configuring autoescape now instead of relying on the default behavior.\n\n### Undefined handling\n\nThe default undefined behavior can hide bugs because missing values often render as empty strings. Prefer:\n\n```python\nfrom jinja2 import StrictUndefined\n\nenv = Environment(undefined=StrictUndefined)\n```\n\n### Loader selection\n\n- `PackageLoader`: templates shipped inside a Python package\n- `FileSystemLoader`: templates from one or more directories\n- `DictLoader`: unit tests and small in-memory fixtures\n- `ChoiceLoader`: user override templates before default templates\n- `ModuleLoader`: precompiled templates\n\n### Caching and deployment\n\nUseful production options:\n\n- `cache_size`: in-memory template cache size, default `400`\n- `auto_reload`: leave enabled in development; disable if source files never change in production\n- `bytecode_cache`: add a `FileSystemBytecodeCache` or memcached-backed bytecode cache for repeated template compilation\n- `compile_templates()`: precompile templates for deployment-time packaging\n\n### Sandboxed rendering\n\nUse `SandboxedEnvironment` only when you intentionally need to execute untrusted templates, and still keep the threat model narrow:\n\n```python\nfrom jinja2.sandbox import SandboxedEnvironment\n\nenv = SandboxedEnvironment(undefined=StrictUndefined)\n```\n\nThe sandbox is not a complete security boundary. Upstream recommends passing only relevant data, avoiding objects with side-effecting methods, catching rendering errors, and using `ImmutableSandboxedEnvironment` if you must prevent template code from mutating lists and dicts.\n\n## Common Pitfalls\n\n### Autoescape is not universally on by default\n\nIf you render HTML without explicit autoescape configuration, you can create XSS problems or inconsistent escaping behavior.\n\n### Do not mutate an environment after templates are loaded\n\nThe API docs warn that modifying filters, tests, globals, or configuration after the first template load can cause surprising or undefined behavior.\n\n### `include` and `import` do not share context the same way\n\nThis is a frequent source of confusion:\n\n- included templates see current context by default\n- imported macro templates do not\n- `with context` changes that behavior and disables import caching\n\n### Default undefined values can hide missing data\n\nIf you do not set `StrictUndefined`, a typo such as `{{ user.nmae }}` may render as blank output instead of failing loudly.\n\n### Whitespace output can look wrong even when logic is correct\n\nBlock tags on their own lines can leave blank lines unless you enable `trim_blocks` and `lstrip_blocks`, or use `-%}` whitespace control in the template.\n\n### Sandbox is not a license to pass full application objects\n\nEven with `SandboxedEnvironment`, do not pass global state, ORM objects with side effects, or broad service objects. Restrict the data shape you expose.\n\n## Version-Sensitive Notes For 3.1.6\n\n- `3.1.6` is a security release. The official release notes say it fixes the `|attr` filter so it no longer bypasses environment attribute lookup, which matters for sandboxed environments.\n- `3.1.5` added more sandbox hardening and async-related fixes, including better handling for indirect `str.format` calls in sandboxed rendering and a correct `Environment.overlay(enable_async=...)` behavior.\n- `3.1.0` removed older deprecated APIs. For modern code:\n  - use `pass_context`, `pass_eval_context`, and `pass_environment` instead of the old `contextfilter` / `environmentfilter` style decorators\n  - import `Markup` and `escape` from `markupsafe`, not from `jinja2`\n  - treat autoescape and `with` as built-in behavior, not optional extensions\n- The current official docs for the `3.1.x` line say Jinja supports Python `3.7` and newer.\n\n## Official Sources\n\n- Docs root: https://jinja.palletsprojects.com/en/stable/\n- Introduction: https://jinja.palletsprojects.com/en/stable/intro/\n- API: https://jinja.palletsprojects.com/en/stable/api/\n- Template Designer Documentation: https://jinja.palletsprojects.com/en/stable/templates/\n- Sandbox: https://jinja.palletsprojects.com/en/stable/sandbox/\n- Native Python Types: https://jinja.palletsprojects.com/en/stable/nativetypes/\n- Changelog: https://jinja.palletsprojects.com/en/stable/changes/\n- PyPI package page: https://pypi.org/project/Jinja2/3.1.6/\n- Source repository: https://github.com/pallets/jinja\n- Release notes: https://github.com/pallets/jinja/releases/tag/3.1.6\n"
  },
  {
    "path": "content/jira/docs/issues/javascript/DOC.md",
    "content": "---\nname: issues\ndescription: \"Jira JavaScript/TypeScript SDK Coding Guidelines for writing code using the Jira API with official libraries and SDKs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"jira,issues,atlassian,project-management,agile\"\n---\n\n# Jira JavaScript/TypeScript SDK Coding Guidelines\n\nYou are a Jira API coding expert. Help me with writing code using the Jira API calling the official libraries and SDKs.\n\nYou can find the official Jira API documentation and code samples here:\nhttps://developer.atlassian.com/cloud/jira/platform/rest/v3/\nhttps://mrrefactoring.github.io/jira.js/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the jira.js library to interact with the Jira Cloud, Jira Agile, and Jira Service Desk REST APIs. This is the most comprehensive and actively maintained JavaScript/TypeScript wrapper for Jira APIs.\n\n- **Library Name:** jira.js\n- **NPM Package:** `jira.js`\n- **Minimum Node.js Version:** 20.0.0 or newer\n- **Legacy Libraries**: `jira-connector`, `jira-client`, and other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install jira.js`\n- **Correct:** `yarn add jira.js`\n- **Correct:** `pnpm add jira.js`\n\n**APIs and Usage:**\n\n- **Correct:** `import { Version3Client } from 'jira.js'`\n- **Correct:** `const client = new Version3Client({ host, authentication })`\n- **Correct:** `await client.issues.createIssue(...)`\n- **Correct:** `await client.issueSearch.searchForIssuesUsingJql(...)`\n- **Incorrect:** `JiraClient`, `JiraApi`, or `JiraConnector`\n- **Incorrect:** Using REST API endpoints directly without the SDK\n- **Incorrect:** Using deprecated v1 or v2 API versions\n\n## Authentication\n\nThe jira.js library supports multiple authentication methods. Always obtain API credentials from your Jira Cloud instance.\n\n### Basic Authentication (Recommended for Jira Cloud)\n\nGenerate an API token at: https://id.atlassian.com/manage-profile/security/api-tokens\n\n```javascript\nimport { Version3Client } from 'jira.js';\n\nconst client = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: 'your@email.com',\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n```\n\n### OAuth 2.0 Authentication\n\nOAuth 2.0 uses an access token obtained through the OAuth flow:\n\n```javascript\nimport { Version3Client } from 'jira.js';\n\nconst client = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    oauth2: {\n      accessToken: process.env.JIRA_ACCESS_TOKEN,\n    },\n  },\n});\n```\n\n### OAuth 1.0a Authentication (Legacy)\n\nFor Jira Server instances or legacy integrations:\n\n```javascript\nimport { Version3Client } from 'jira.js';\n\nconst client = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    oauth: {\n      consumerKey: process.env.JIRA_CONSUMER_KEY,\n      consumerSecret: process.env.JIRA_CONSUMER_SECRET,\n      accessToken: process.env.JIRA_ACCESS_TOKEN,\n      tokenSecret: process.env.JIRA_TOKEN_SECRET,\n    },\n  },\n});\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file in your project root:\n\n```bash\nJIRA_HOST=https://your-domain.atlassian.net\nJIRA_EMAIL=your@email.com\nJIRA_API_TOKEN=your_api_token_here\n```\n\nLoad environment variables in your code:\n\n```javascript\nimport 'dotenv/config';\nimport { Version3Client } from 'jira.js';\n\nconst client = new Version3Client({\n  host: process.env.JIRA_HOST,\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n```\n\n## Initialization\n\nCreate a client instance for all API interactions:\n\n```javascript\nimport { Version3Client } from 'jira.js';\n\n// Basic initialization\nconst client = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: 'your@email.com',\n      apiToken: 'your_api_token',\n    },\n  },\n});\n\n// With custom timeout and other options\nconst clientWithOptions = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: 'your@email.com',\n      apiToken: 'your_api_token',\n    },\n  },\n  timeout: 30000, // 30 seconds\n});\n```\n\n## Error Handling\n\nThe library provides two error types for comprehensive error handling:\n\n```javascript\nimport { Version3Client } from 'jira.js';\nimport { AxiosError } from 'axios';\n\nconst client = new Version3Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n\ntry {\n  const issue = await client.issues.getIssue({ issueIdOrKey: 'PROJECT-123' });\n  console.log(issue);\n} catch (error) {\n  if (error.name === 'HttpException') {\n    // Server errors with parsed details\n    console.error('HTTP Error:', error.statusCode, error.message);\n    console.error('Error details:', error.data);\n  } else if (error instanceof AxiosError) {\n    // Network or configuration errors\n    console.error('Network Error:', error.code, error.message);\n  } else {\n    console.error('Unexpected error:', error);\n  }\n}\n```\n\n## Core API Surfaces\n\n### Projects\n\n#### Get Project\n\n```javascript\n// Minimal example\nconst project = await client.projects.getProject({\n  projectIdOrKey: 'PROJ',\n});\n\nconsole.log(project.name);\nconsole.log(project.key);\nconsole.log(project.id);\n```\n\n#### Advanced: Get Project with Expanded Properties\n\n```javascript\n// Advanced example with expand options\nconst project = await client.projects.getProject({\n  projectIdOrKey: 'PROJ',\n  expand: 'description,lead,issueTypes,url,projectKeys',\n  properties: '*all',\n});\n\nconsole.log('Project Name:', project.name);\nconsole.log('Project Lead:', project.lead.displayName);\nconsole.log('Description:', project.description);\nconsole.log('Issue Types:', project.issueTypes);\n```\n\n#### Search Projects\n\n```javascript\n// Search for projects\nconst projects = await client.projects.searchProjects({\n  startAt: 0,\n  maxResults: 50,\n  orderBy: 'name',\n  query: 'development',\n});\n\nconsole.log('Total projects:', projects.total);\nprojects.values.forEach(project => {\n  console.log(`${project.key}: ${project.name}`);\n});\n```\n\n#### Create Project\n\n```javascript\n// Create a new project\nconst newProject = await client.projects.createProject({\n  key: 'NEWP',\n  name: 'New Project',\n  projectTypeKey: 'software',\n  projectTemplateKey: 'com.atlassian.jira-core-project-templates:jira-core-simplified-project-management',\n  description: 'This is a new project',\n  leadAccountId: '5b10a2844c20165700ede21g',\n});\n\nconsole.log('Created project:', newProject.key);\n```\n\n### Issues\n\n#### Create Issue\n\n```javascript\n// Minimal example\nconst issue = await client.issues.createIssue({\n  fields: {\n    project: {\n      key: 'PROJ',\n    },\n    summary: 'New issue from API',\n    issuetype: {\n      name: 'Task',\n    },\n  },\n});\n\nconsole.log('Created issue:', issue.key);\n```\n\n#### Advanced: Create Issue with All Fields\n\n```javascript\n// Advanced example with multiple fields\nconst issue = await client.issues.createIssue({\n  fields: {\n    project: {\n      key: 'PROJ',\n    },\n    summary: 'Implement user authentication',\n    description: {\n      type: 'doc',\n      version: 1,\n      content: [\n        {\n          type: 'paragraph',\n          content: [\n            {\n              type: 'text',\n              text: 'Need to implement OAuth 2.0 authentication for the API.',\n            },\n          ],\n        },\n      ],\n    },\n    issuetype: {\n      name: 'Story',\n    },\n    priority: {\n      name: 'High',\n    },\n    labels: ['security', 'authentication'],\n    assignee: {\n      accountId: '5b10a2844c20165700ede21g',\n    },\n    duedate: '2025-12-31',\n    customfield_10001: 'Custom field value',\n  },\n});\n\nconsole.log('Created issue:', issue.key, issue.id);\n```\n\n#### Get Issue\n\n```javascript\n// Get an issue with all fields\nconst issue = await client.issues.getIssue({\n  issueIdOrKey: 'PROJ-123',\n});\n\nconsole.log('Summary:', issue.fields.summary);\nconsole.log('Status:', issue.fields.status.name);\nconsole.log('Assignee:', issue.fields.assignee?.displayName);\n```\n\n#### Advanced: Get Issue with Specific Fields\n\n```javascript\n// Get specific fields and expand certain properties\nconst issue = await client.issues.getIssue({\n  issueIdOrKey: 'PROJ-123',\n  fields: ['summary', 'status', 'assignee', 'priority', 'created', 'updated'],\n  expand: 'changelog,renderedFields',\n});\n\nconsole.log('Issue:', issue.key);\nconsole.log('Summary:', issue.fields.summary);\nconsole.log('Created:', issue.fields.created);\nconsole.log('Change History:', issue.changelog);\n```\n\n#### Update Issue\n\n```javascript\n// Update issue fields\nawait client.issues.editIssue({\n  issueIdOrKey: 'PROJ-123',\n  fields: {\n    summary: 'Updated summary',\n    description: {\n      type: 'doc',\n      version: 1,\n      content: [\n        {\n          type: 'paragraph',\n          content: [\n            {\n              type: 'text',\n              text: 'Updated description',\n            },\n          ],\n        },\n      ],\n    },\n    priority: {\n      name: 'Critical',\n    },\n  },\n});\n\nconsole.log('Issue updated successfully');\n```\n\n#### Assign Issue\n\n```javascript\n// Assign issue to a user\nawait client.issues.assignIssue({\n  issueIdOrKey: 'PROJ-123',\n  accountId: '5b10a2844c20165700ede21g',\n});\n```\n\n#### Add Comment\n\n```javascript\n// Add a comment to an issue\nconst comment = await client.issueComments.addComment({\n  issueIdOrKey: 'PROJ-123',\n  body: {\n    type: 'doc',\n    version: 1,\n    content: [\n      {\n        type: 'paragraph',\n        content: [\n          {\n            type: 'text',\n            text: 'This is a comment from the API',\n          },\n        ],\n      },\n    ],\n  },\n});\n\nconsole.log('Comment added:', comment.id);\n```\n\n#### Transition Issue\n\n```javascript\n// Get available transitions\nconst transitions = await client.issues.getTransitions({\n  issueIdOrKey: 'PROJ-123',\n});\n\nconsole.log('Available transitions:');\ntransitions.transitions.forEach(t => {\n  console.log(`${t.id}: ${t.name}`);\n});\n\n// Transition issue to a new status\nawait client.issues.doTransition({\n  issueIdOrKey: 'PROJ-123',\n  transition: {\n    id: '21', // ID from getTransitions\n  },\n});\n\nconsole.log('Issue transitioned successfully');\n```\n\n#### Delete Issue\n\n```javascript\n// Delete an issue\nawait client.issues.deleteIssue({\n  issueIdOrKey: 'PROJ-123',\n  deleteSubtasks: 'true',\n});\n\nconsole.log('Issue deleted successfully');\n```\n\n### Issue Search\n\n#### Search with JQL (Jira Query Language)\n\n```javascript\n// Basic JQL search\nconst searchResults = await client.issueSearch.searchForIssuesUsingJql({\n  jql: 'project = PROJ AND status = \"In Progress\"',\n});\n\nconsole.log('Total issues:', searchResults.total);\nsearchResults.issues.forEach(issue => {\n  console.log(`${issue.key}: ${issue.fields.summary}`);\n});\n```\n\n#### Advanced: Search with Pagination and Sorting\n\n```javascript\n// Advanced search with pagination, sorting, and field selection\nconst searchResults = await client.issueSearch.searchForIssuesUsingJql({\n  jql: 'project = PROJ AND assignee = currentUser() ORDER BY created DESC',\n  startAt: 0,\n  maxResults: 50,\n  fields: ['summary', 'status', 'assignee', 'priority', 'created'],\n  expand: ['changelog'],\n});\n\nconsole.log(`Showing ${searchResults.issues.length} of ${searchResults.total} issues`);\n\nsearchResults.issues.forEach(issue => {\n  console.log(`${issue.key}: ${issue.fields.summary}`);\n  console.log(`  Status: ${issue.fields.status.name}`);\n  console.log(`  Priority: ${issue.fields.priority.name}`);\n  console.log(`  Created: ${issue.fields.created}`);\n});\n```\n\n#### Pagination Example\n\n```javascript\n// Fetch all issues with pagination\nasync function getAllIssues(jql) {\n  const allIssues = [];\n  let startAt = 0;\n  const maxResults = 100;\n  let total = 0;\n\n  do {\n    const searchResults = await client.issueSearch.searchForIssuesUsingJql({\n      jql,\n      startAt,\n      maxResults,\n    });\n\n    allIssues.push(...searchResults.issues);\n    total = searchResults.total;\n    startAt += maxResults;\n\n    console.log(`Fetched ${allIssues.length} of ${total} issues`);\n  } while (allIssues.length < total);\n\n  return allIssues;\n}\n\n// Usage\nconst allProjectIssues = await getAllIssues('project = PROJ');\nconsole.log('Total issues fetched:', allProjectIssues.length);\n```\n\n#### Complex JQL Queries\n\n```javascript\n// Complex JQL with multiple conditions\nconst jql = `\n  project = PROJ AND\n  status IN (\"To Do\", \"In Progress\") AND\n  priority IN (High, Critical) AND\n  assignee = currentUser() AND\n  created >= -30d\n  ORDER BY priority DESC, created ASC\n`;\n\nconst issues = await client.issueSearch.searchForIssuesUsingJql({\n  jql: jql.trim(),\n  maxResults: 100,\n});\n\nconsole.log('High priority issues:', issues.total);\n```\n\n### Agile - Boards\n\n#### Get All Boards\n\n```javascript\n// Minimal example\nimport { AgileClient } from 'jira.js';\n\nconst agileClient = new AgileClient({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n\nconst boards = await agileClient.board.getAllBoards();\n\nboards.values.forEach(board => {\n  console.log(`${board.id}: ${board.name} (${board.type})`);\n});\n```\n\n#### Advanced: Get Boards with Filters\n\n```javascript\n// Filter boards by project and type\nconst scrumBoards = await agileClient.board.getAllBoards({\n  projectKeyOrId: 'PROJ',\n  type: 'scrum',\n  startAt: 0,\n  maxResults: 50,\n});\n\nconsole.log('Scrum boards:');\nscrumBoards.values.forEach(board => {\n  console.log(`${board.id}: ${board.name}`);\n});\n```\n\n#### Get Board\n\n```javascript\n// Get a specific board\nconst board = await agileClient.board.getBoard({\n  boardId: 1,\n});\n\nconsole.log('Board name:', board.name);\nconsole.log('Board type:', board.type);\nconsole.log('Board location:', board.location);\n```\n\n#### Get Issues for Board\n\n```javascript\n// Get all issues on a board\nconst boardIssues = await agileClient.board.getIssuesForBoard({\n  boardId: 1,\n  startAt: 0,\n  maxResults: 50,\n  jql: 'status != Done',\n});\n\nconsole.log('Issues on board:', boardIssues.total);\nboardIssues.issues.forEach(issue => {\n  console.log(`${issue.key}: ${issue.fields.summary}`);\n});\n```\n\n### Agile - Sprints\n\n#### Create Sprint\n\n```javascript\n// Create a new sprint\nconst sprint = await agileClient.sprint.createSprint({\n  name: 'Sprint 23',\n  startDate: '2025-11-15T10:00:00.000Z',\n  endDate: '2025-11-29T18:00:00.000Z',\n  originBoardId: 1,\n  goal: 'Complete user authentication feature',\n});\n\nconsole.log('Created sprint:', sprint.id, sprint.name);\n```\n\n#### Advanced: Create Sprint with Minimal Fields\n\n```javascript\n// Create a future sprint (only name and board required)\nconst futureSprint = await agileClient.sprint.createSprint({\n  name: 'Q1 Sprint 1',\n  originBoardId: 1,\n});\n\nconsole.log('Created future sprint:', futureSprint.id);\n```\n\n#### Get Sprint\n\n```javascript\n// Get sprint details\nconst sprint = await agileClient.sprint.getSprint({\n  sprintId: 123,\n});\n\nconsole.log('Sprint:', sprint.name);\nconsole.log('State:', sprint.state);\nconsole.log('Start Date:', sprint.startDate);\nconsole.log('End Date:', sprint.endDate);\nconsole.log('Goal:', sprint.goal);\n```\n\n#### Update Sprint\n\n```javascript\n// Update sprint details\nawait agileClient.sprint.updateSprint({\n  sprintId: 123,\n  name: 'Updated Sprint Name',\n  goal: 'Updated sprint goal',\n  startDate: '2025-11-15T10:00:00.000Z',\n  endDate: '2025-11-29T18:00:00.000Z',\n  state: 'active',\n});\n\nconsole.log('Sprint updated successfully');\n```\n\n#### Get Issues for Sprint\n\n```javascript\n// Get all issues in a sprint\nconst sprintIssues = await agileClient.sprint.getIssuesForSprint({\n  sprintId: 123,\n  startAt: 0,\n  maxResults: 50,\n  jql: 'status != Done',\n});\n\nconsole.log('Issues in sprint:', sprintIssues.total);\nsprintIssues.issues.forEach(issue => {\n  console.log(`${issue.key}: ${issue.fields.summary}`);\n});\n```\n\n#### Move Issues to Sprint\n\n```javascript\n// Move issues to a sprint (max 50 issues per operation)\nawait agileClient.sprint.moveIssuesToSprintAndRank({\n  sprintId: 123,\n  issues: ['PROJ-123', 'PROJ-124', 'PROJ-125'],\n});\n\nconsole.log('Issues moved to sprint successfully');\n```\n\n#### Delete Sprint\n\n```javascript\n// Delete a sprint\nawait agileClient.sprint.deleteSprint({\n  sprintId: 123,\n});\n\nconsole.log('Sprint deleted successfully');\n```\n\n### Users\n\n#### Get Current User\n\n```javascript\n// Get currently authenticated user\nconst currentUser = await client.myself.getCurrentUser();\n\nconsole.log('User:', currentUser.displayName);\nconsole.log('Email:', currentUser.emailAddress);\nconsole.log('Account ID:', currentUser.accountId);\n```\n\n#### Find Users\n\n```javascript\n// Search for users by query\nconst users = await client.userSearch.findUsers({\n  query: 'john',\n  maxResults: 50,\n});\n\nusers.forEach(user => {\n  console.log(`${user.displayName} (${user.emailAddress})`);\n});\n```\n\n#### Get User\n\n```javascript\n// Get a specific user by account ID\nconst user = await client.users.getUser({\n  accountId: '5b10a2844c20165700ede21g',\n});\n\nconsole.log('User:', user.displayName);\nconsole.log('Active:', user.active);\n```\n\n### Filters\n\n#### Get Filters\n\n```javascript\n// Get all filters for the current user\nconst filters = await client.filters.getFavouriteFilters();\n\nfilters.forEach(filter => {\n  console.log(`${filter.id}: ${filter.name}`);\n  console.log(`  JQL: ${filter.jql}`);\n});\n```\n\n#### Create Filter\n\n```javascript\n// Create a new filter\nconst filter = await client.filters.createFilter({\n  name: 'My High Priority Issues',\n  description: 'All high priority issues assigned to me',\n  jql: 'assignee = currentUser() AND priority = High',\n  favourite: true,\n});\n\nconsole.log('Created filter:', filter.id, filter.name);\n```\n\n#### Get Filter\n\n```javascript\n// Get a specific filter\nconst filter = await client.filters.getFilter({\n  id: 10000,\n  expand: 'subscriptions,owner',\n});\n\nconsole.log('Filter:', filter.name);\nconsole.log('JQL:', filter.jql);\nconsole.log('Owner:', filter.owner.displayName);\n```\n\n#### Search with Filter\n\n```javascript\n// Execute a saved filter\nconst filterResults = await client.issueSearch.searchForIssuesUsingJql({\n  jql: `filter = ${filterId}`,\n  maxResults: 100,\n});\n\nconsole.log('Filter results:', filterResults.total);\n```\n\n### Workflows\n\n#### Get All Workflows\n\n```javascript\n// Get all workflows\nconst workflows = await client.workflows.getAllWorkflows({\n  workflowName: undefined,\n});\n\nworkflows.forEach(workflow => {\n  console.log(`${workflow.id}: ${workflow.name}`);\n});\n```\n\n#### Get Issue Transitions\n\n```javascript\n// Get available transitions for an issue\nconst transitions = await client.issues.getTransitions({\n  issueIdOrKey: 'PROJ-123',\n  expand: 'transitions.fields',\n});\n\nconsole.log('Available transitions:');\ntransitions.transitions.forEach(transition => {\n  console.log(`${transition.id}: ${transition.name}`);\n  console.log(`  To status: ${transition.to.name}`);\n});\n```\n\n### Custom Fields\n\n#### Get All Fields\n\n```javascript\n// Get all fields in Jira\nconst fields = await client.issueFields.getFields();\n\nfields.forEach(field => {\n  if (field.custom) {\n    console.log(`Custom Field: ${field.id} - ${field.name}`);\n  }\n});\n```\n\n#### Get Custom Field Options\n\n```javascript\n// Get options for a custom field\nconst customFieldId = 'customfield_10001';\nconst issue = await client.issues.getIssue({\n  issueIdOrKey: 'PROJ-123',\n  fields: [customFieldId],\n});\n\nconsole.log('Custom field value:', issue.fields[customFieldId]);\n```\n\n### Versions (Releases)\n\n#### Create Version\n\n```javascript\n// Create a new version/release\nconst version = await client.projectVersions.createVersion({\n  name: 'v1.2.0',\n  description: 'Q4 2025 Release',\n  projectId: 10000,\n  releaseDate: '2025-12-15',\n  archived: false,\n  released: false,\n});\n\nconsole.log('Created version:', version.id, version.name);\n```\n\n#### Get Version\n\n```javascript\n// Get a specific version\nconst version = await client.projectVersions.getVersion({\n  id: '10001',\n});\n\nconsole.log('Version:', version.name);\nconsole.log('Released:', version.released);\nconsole.log('Release Date:', version.releaseDate);\n```\n\n#### Update Version\n\n```javascript\n// Update a version\nawait client.projectVersions.updateVersion({\n  id: '10001',\n  name: 'v1.2.1',\n  description: 'Updated release',\n  released: true,\n  releaseDate: '2025-12-20',\n});\n```\n\n### Labels\n\n#### Add Labels to Issue\n\n```javascript\n// Add labels to an issue\nawait client.issues.editIssue({\n  issueIdOrKey: 'PROJ-123',\n  fields: {\n    labels: ['backend', 'api', 'urgent'],\n  },\n});\n\nconsole.log('Labels added successfully');\n```\n\n#### Get All Labels\n\n```javascript\n// Search for labels\nconst labels = await client.labels.getAllLabels({\n  startAt: 0,\n  maxResults: 1000,\n});\n\nconsole.log('Total labels:', labels.total);\nlabels.values.forEach(label => {\n  console.log(label);\n});\n```\n\n### Components\n\n#### Get Project Components\n\n```javascript\n// Get all components for a project\nconst components = await client.projectComponents.getProjectComponents({\n  projectIdOrKey: 'PROJ',\n});\n\ncomponents.forEach(component => {\n  console.log(`${component.id}: ${component.name}`);\n  console.log(`  Description: ${component.description}`);\n  console.log(`  Lead: ${component.lead?.displayName}`);\n});\n```\n\n#### Create Component\n\n```javascript\n// Create a new component\nconst component = await client.projectComponents.createComponent({\n  name: 'Frontend',\n  description: 'Frontend components and pages',\n  project: 'PROJ',\n  leadAccountId: '5b10a2844c20165700ede21g',\n});\n\nconsole.log('Created component:', component.id, component.name);\n```\n\n### Attachments\n\n#### Add Attachment\n\n```javascript\nimport fs from 'fs';\nimport FormData from 'form-data';\n\n// Add attachment to an issue\nconst formData = new FormData();\nformData.append('file', fs.createReadStream('/path/to/file.pdf'));\n\nconst attachments = await client.issueAttachments.addAttachment({\n  issueIdOrKey: 'PROJ-123',\n  attachment: formData,\n});\n\nconsole.log('Attachment added:', attachments[0].filename);\n```\n\n#### Get Attachment\n\n```javascript\n// Get attachment metadata\nconst issue = await client.issues.getIssue({\n  issueIdOrKey: 'PROJ-123',\n  fields: ['attachment'],\n});\n\nissue.fields.attachment.forEach(attachment => {\n  console.log(`${attachment.filename} - ${attachment.size} bytes`);\n  console.log(`  Download: ${attachment.content}`);\n});\n```\n\n### Webhooks\n\n#### Create Webhook\n\n```javascript\n// Create a webhook\nconst webhook = await client.webhooks.registerDynamicWebhooks({\n  url: 'https://your-domain.com/webhook',\n  webhooks: [\n    {\n      events: ['jira:issue_created', 'jira:issue_updated'],\n      jqlFilter: 'project = PROJ',\n    },\n  ],\n});\n\nconsole.log('Webhook created:', webhook);\n```\n\n#### Get Webhooks\n\n```javascript\n// Get all registered webhooks\nconst webhooks = await client.webhooks.getDynamicWebhooksForApp();\n\nwebhooks.forEach(webhook => {\n  console.log(`Webhook ${webhook.id}:`);\n  console.log(`  URL: ${webhook.url}`);\n  console.log(`  Events: ${webhook.events.join(', ')}`);\n});\n```\n\n### Permissions\n\n#### Get My Permissions\n\n```javascript\n// Get current user permissions\nconst permissions = await client.permissions.getMyPermissions({\n  projectKey: 'PROJ',\n});\n\nconsole.log('Permissions for project PROJ:');\nObject.entries(permissions.permissions).forEach(([key, permission]) => {\n  console.log(`${key}: ${permission.havePermission}`);\n});\n```\n\n#### Get Bulk Permissions\n\n```javascript\n// Get permissions for multiple projects\nconst bulkPermissions = await client.permissions.getBulkPermissions({\n  projectKey: ['PROJ1', 'PROJ2', 'PROJ3'],\n  permissions: ['BROWSE_PROJECTS', 'CREATE_ISSUES', 'EDIT_ISSUES'],\n});\n\nconsole.log('Bulk permissions:', bulkPermissions);\n```\n\n## API Client Optimization\n\n### Using Version 2 Client\n\nFor legacy Jira instances or when you need v2 endpoints:\n\n```javascript\nimport { Version2Client } from 'jira.js';\n\nconst v2Client = new Version2Client({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n```\n\n### Using Agile Client\n\nFor dedicated Agile/Scrum operations:\n\n```javascript\nimport { AgileClient } from 'jira.js';\n\nconst agileClient = new AgileClient({\n  host: 'https://your-domain.atlassian.net',\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n\n// Agile client provides specialized methods for boards, sprints, and backlogs\nconst boards = await agileClient.board.getAllBoards();\nconst sprints = await agileClient.sprint.getAllSprints({ boardId: 1 });\n```\n\n### Bundle Size Optimization\n\nImport only what you need to reduce bundle size:\n\n```javascript\n// Instead of importing the full client\nimport { Board } from 'jira.js/agile';\nimport { Issues } from 'jira.js/version3';\n\n// Use specific modules\nconst board = new Board({\n  host: 'https://your-domain.atlassian.net',\n  authentication: { /* ... */ },\n});\n```\n\n## Common Patterns\n\n### Batch Operations\n\n```javascript\n// Create multiple issues in batch\nasync function createMultipleIssues(issuesData) {\n  const promises = issuesData.map(issueData =>\n    client.issues.createIssue({\n      fields: issueData,\n    })\n  );\n\n  const results = await Promise.all(promises);\n  return results;\n}\n\n// Usage\nconst issues = await createMultipleIssues([\n  {\n    project: { key: 'PROJ' },\n    summary: 'Task 1',\n    issuetype: { name: 'Task' },\n  },\n  {\n    project: { key: 'PROJ' },\n    summary: 'Task 2',\n    issuetype: { name: 'Task' },\n  },\n]);\n\nconsole.log('Created issues:', issues.map(i => i.key));\n```\n\n### Rate Limiting\n\n```javascript\n// Implement rate limiting for bulk operations\nasync function rateLimitedOperation(items, operation, rateLimit = 10) {\n  const results = [];\n\n  for (let i = 0; i < items.length; i += rateLimit) {\n    const batch = items.slice(i, i + rateLimit);\n    const batchResults = await Promise.all(\n      batch.map(item => operation(item))\n    );\n    results.push(...batchResults);\n\n    // Wait before next batch (optional)\n    if (i + rateLimit < items.length) {\n      await new Promise(resolve => setTimeout(resolve, 1000));\n    }\n  }\n\n  return results;\n}\n```\n\n### Retry Logic\n\n```javascript\n// Implement retry logic for failed requests\nasync function withRetry(operation, maxRetries = 3, delay = 1000) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await operation();\n    } catch (error) {\n      if (attempt === maxRetries) throw error;\n\n      console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);\n      await new Promise(resolve => setTimeout(resolve, delay));\n      delay *= 2; // Exponential backoff\n    }\n  }\n}\n\n// Usage\nconst issue = await withRetry(() =>\n  client.issues.getIssue({ issueIdOrKey: 'PROJ-123' })\n);\n```\n\n## Complete Application Example\n\n```javascript\nimport 'dotenv/config';\nimport { Version3Client } from 'jira.js';\n\n// Initialize client\nconst client = new Version3Client({\n  host: process.env.JIRA_HOST,\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL,\n      apiToken: process.env.JIRA_API_TOKEN,\n    },\n  },\n});\n\nasync function main() {\n  try {\n    // Get current user\n    const user = await client.myself.getCurrentUser();\n    console.log(`Logged in as: ${user.displayName}`);\n\n    // Create a new issue\n    const newIssue = await client.issues.createIssue({\n      fields: {\n        project: { key: 'PROJ' },\n        summary: 'Implement new feature',\n        description: {\n          type: 'doc',\n          version: 1,\n          content: [\n            {\n              type: 'paragraph',\n              content: [\n                {\n                  type: 'text',\n                  text: 'This is a new feature request from the API',\n                },\n              ],\n            },\n          ],\n        },\n        issuetype: { name: 'Story' },\n        priority: { name: 'High' },\n      },\n    });\n\n    console.log(`Created issue: ${newIssue.key}`);\n\n    // Add a comment\n    await client.issueComments.addComment({\n      issueIdOrKey: newIssue.key,\n      body: {\n        type: 'doc',\n        version: 1,\n        content: [\n          {\n            type: 'paragraph',\n            content: [\n              {\n                type: 'text',\n                text: 'Starting work on this issue',\n              },\n            ],\n          },\n        ],\n      },\n    });\n\n    console.log('Comment added');\n\n    // Search for issues\n    const searchResults = await client.issueSearch.searchForIssuesUsingJql({\n      jql: 'project = PROJ AND status = \"To Do\" ORDER BY created DESC',\n      maxResults: 10,\n    });\n\n    console.log(`Found ${searchResults.total} issues`);\n    searchResults.issues.forEach(issue => {\n      console.log(`  ${issue.key}: ${issue.fields.summary}`);\n    });\n\n  } catch (error) {\n    console.error('Error:', error.message);\n    if (error.data) {\n      console.error('Error details:', error.data);\n    }\n  }\n}\n\nmain();\n```\n\n## TypeScript Support\n\njira.js is written in TypeScript and provides full type definitions:\n\n```typescript\nimport { Version3Client } from 'jira.js';\nimport type { Issue, IssueBean, SearchResults } from 'jira.js/out/version3/models';\n\nconst client = new Version3Client({\n  host: process.env.JIRA_HOST!,\n  authentication: {\n    basic: {\n      email: process.env.JIRA_EMAIL!,\n      apiToken: process.env.JIRA_API_TOKEN!,\n    },\n  },\n});\n\nasync function getIssues(projectKey: string): Promise<Issue[]> {\n  const results: SearchResults = await client.issueSearch.searchForIssuesUsingJql({\n    jql: `project = ${projectKey}`,\n    maxResults: 100,\n  });\n\n  return results.issues || [];\n}\n\nasync function createIssue(summary: string, projectKey: string): Promise<IssueBean> {\n  return await client.issues.createIssue({\n    fields: {\n      project: { key: projectKey },\n      summary,\n      issuetype: { name: 'Task' },\n    },\n  });\n}\n```\n\n## Common JQL Patterns\n\n```javascript\n// Issues assigned to current user\nconst jql1 = 'assignee = currentUser()';\n\n// Issues created in the last 7 days\nconst jql2 = 'created >= -7d';\n\n// High priority bugs not resolved\nconst jql3 = 'type = Bug AND priority = High AND status != Resolved';\n\n// Issues in specific sprint\nconst jql4 = 'sprint = 123';\n\n// Issues with specific labels\nconst jql5 = 'labels IN (urgent, critical)';\n\n// Issues due this week\nconst jql6 = 'duedate >= startOfWeek() AND duedate <= endOfWeek()';\n\n// Combining multiple conditions\nconst jql7 = `\n  project = PROJ AND\n  status IN (\"To Do\", \"In Progress\") AND\n  assignee IN (currentUser(), \"john.doe\") AND\n  created >= -30d\n  ORDER BY priority DESC, created ASC\n`;\n```\n\n## Response Format Examples\n\n### Issue Response\n\n```javascript\n{\n  \"id\": \"10002\",\n  \"key\": \"PROJ-123\",\n  \"self\": \"https://your-domain.atlassian.net/rest/api/3/issue/10002\",\n  \"fields\": {\n    \"summary\": \"Issue summary\",\n    \"description\": { /* ADF format */ },\n    \"status\": {\n      \"name\": \"In Progress\",\n      \"statusCategory\": { \"key\": \"indeterminate\" }\n    },\n    \"priority\": { \"name\": \"High\" },\n    \"assignee\": {\n      \"accountId\": \"5b10a2844c20165700ede21g\",\n      \"displayName\": \"John Doe\",\n      \"emailAddress\": \"john@example.com\"\n    },\n    \"created\": \"2025-11-01T10:00:00.000+0000\",\n    \"updated\": \"2025-11-07T15:30:00.000+0000\",\n    \"labels\": [\"backend\", \"api\"]\n  }\n}\n```\n\n### Search Results Response\n\n```javascript\n{\n  \"startAt\": 0,\n  \"maxResults\": 50,\n  \"total\": 127,\n  \"issues\": [\n    { /* issue object */ },\n    { /* issue object */ }\n  ]\n}\n```\n"
  },
  {
    "path": "content/jira/docs/issues/python/DOC.md",
    "content": "---\nname: issues\ndescription: \"Jira Python SDK Coding Guidelines for writing code using the Jira API with official libraries and SDKs\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.10.5\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"jira,issues,atlassian,project-management,agile\"\n---\n\n# Jira Python SDK Coding Guidelines\n\nYou are a Jira API coding expert. Help me with writing code using the Jira API calling the official libraries and SDKs.\n\nYou can find the official Jira API documentation and code samples here:\nhttps://jira.readthedocs.io/\nhttps://developer.atlassian.com/cloud/jira/platform/rest/v3/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the jira Python library to interact with the Jira Cloud, Jira Server, and Jira Data Center REST APIs. This is the most actively maintained and comprehensive Python wrapper for Jira APIs.\n\n- **Library Name:** jira\n- **PyPI Package:** `jira`\n- **Minimum Python Version:** 3.10 or newer\n- **Legacy Libraries**: `jira-python`, `atlassian-python-api` (different library), and other unofficial packages may have different APIs\n\n**Installation:**\n\n- **Correct:** `pip install jira`\n- **Correct:** `pip install jira[opt,cli,test]` (with optional dependencies)\n\n**APIs and Usage:**\n\n- **Correct:** `from jira import JIRA`\n- **Correct:** `jira = JIRA('https://your-domain.atlassian.net', basic_auth=('email', 'token'))`\n- **Correct:** `jira.search_issues('project = PROJ')`\n- **Incorrect:** Using REST API endpoints directly without the SDK\n- **Incorrect:** Using deprecated cookie-based authentication\n- **Incorrect:** Using username/password for Jira Cloud (use API tokens instead)\n\n## Authentication\n\nThe jira library supports multiple authentication methods. Choose the appropriate method based on your Jira instance type.\n\n### API Token Authentication (Recommended for Jira Cloud)\n\nGenerate an API token at: https://id.atlassian.com/manage-profile/security/api-tokens\n\n```python\nfrom jira import JIRA\n\n# Using basic_auth with email and API token\njira = JIRA(\n    server='https://your-domain.atlassian.net',\n    basic_auth=('your.email@example.com', 'your_api_token')\n)\n```\n\n### Personal Access Token (PAT) Authentication (Self-Hosted Jira)\n\nFor Jira Server/Data Center instances:\n\n```python\nfrom jira import JIRA\n\n# Using token_auth parameter\njira = JIRA(\n    server='https://jira.yourcompany.com',\n    token_auth='your_personal_access_token'\n)\n\n# Alternative: Using headers\nheaders = JIRA.DEFAULT_OPTIONS[\"headers\"].copy()\nheaders[\"Authorization\"] = f\"Bearer {personal_access_token}\"\n\njira = JIRA(\n    server='https://jira.yourcompany.com',\n    options={\"headers\": headers}\n)\n```\n\n### OAuth Authentication\n\nFor OAuth integrations:\n\n```python\nfrom jira import JIRA\n\noauth_dict = {\n    'access_token': 'your_access_token',\n    'access_token_secret': 'your_access_token_secret',\n    'consumer_key': 'your_consumer_key',\n    'key_cert': key_cert_data  # RSA private key data\n}\n\njira = JIRA(\n    server='https://your-domain.atlassian.net',\n    oauth=oauth_dict\n)\n```\n\n### Kerberos Authentication\n\nFor enterprise environments with Kerberos:\n\n```python\nfrom jira import JIRA\n\n# Basic Kerberos\njira = JIRA(server='https://jira.yourcompany.com', kerberos=True)\n\n# With options\njira = JIRA(\n    server='https://jira.yourcompany.com',\n    kerberos=True,\n    kerberos_options={'mutual_authentication': 'DISABLED'}\n)\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file or set environment variables:\n\n```bash\nJIRA_SERVER=https://your-domain.atlassian.net\nJIRA_EMAIL=your.email@example.com\nJIRA_API_TOKEN=your_api_token_here\n```\n\nLoad environment variables in your code:\n\n```python\nimport os\nfrom jira import JIRA\n\njira = JIRA(\n    server=os.environ['JIRA_SERVER'],\n    basic_auth=(os.environ['JIRA_EMAIL'], os.environ['JIRA_API_TOKEN'])\n)\n```\n\n## Initialization\n\nCreate a JIRA client instance for all API interactions:\n\n```python\nfrom jira import JIRA\n\n# Basic initialization\njira = JIRA(\n    server='https://your-domain.atlassian.net',\n    basic_auth=('your.email@example.com', 'your_api_token')\n)\n\n# With custom options\noptions = {\n    'server': 'https://your-domain.atlassian.net',\n    'verify': True,  # SSL certificate verification\n    'max_retries': 3,\n    'timeout': 30,\n}\n\njira = JIRA(\n    options=options,\n    basic_auth=('your.email@example.com', 'your_api_token')\n)\n```\n\n## Error Handling\n\nHandle exceptions for robust applications:\n\n```python\nfrom jira import JIRA, JIRAError\n\njira = JIRA(\n    server='https://your-domain.atlassian.net',\n    basic_auth=('your.email@example.com', 'your_api_token')\n)\n\ntry:\n    issue = jira.issue('PROJ-123')\n    print(f'Issue: {issue.key} - {issue.fields.summary}')\nexcept JIRAError as e:\n    if e.status_code == 404:\n        print('Issue not found')\n    elif e.status_code == 401:\n        print('Authentication failed')\n    elif e.status_code == 403:\n        print('Permission denied')\n    else:\n        print(f'Error: {e.status_code} - {e.text}')\nexcept Exception as e:\n    print(f'Unexpected error: {e}')\n```\n\n## Core API Surfaces\n\n### Projects\n\n#### Get Project\n\n```python\n# Minimal example\nproject = jira.project('PROJ')\n\nprint(project.key)\nprint(project.name)\nprint(project.lead.displayName)\n```\n\n#### Advanced: Get Project with All Details\n\n```python\n# Get project with all properties\nproject = jira.project('PROJ')\n\nprint('Project Key:', project.key)\nprint('Project Name:', project.name)\nprint('Project Lead:', project.lead.displayName)\nprint('Description:', project.raw.get('description', 'No description'))\nprint('Project Type:', project.projectTypeKey)\nprint('URL:', project.raw.get('url'))\n```\n\n#### Get All Projects\n\n```python\n# Get all projects\nprojects = jira.projects()\n\nfor project in projects:\n    print(f'{project.key}: {project.name}')\n```\n\n#### Get Project Components\n\n```python\n# Get components for a project\ncomponents = jira.project_components('PROJ')\n\nfor component in components:\n    print(f'{component.name}: {component.description}')\n    if component.lead:\n        print(f'  Lead: {component.lead.displayName}')\n```\n\n#### Get Project Versions\n\n```python\n# Get versions/releases for a project\nversions = jira.project_versions('PROJ')\n\nfor version in versions:\n    print(f'{version.name} - Released: {version.released}')\n    if hasattr(version, 'releaseDate'):\n        print(f'  Release Date: {version.releaseDate}')\n```\n\n### Issues\n\n#### Get Issue\n\n```python\n# Minimal example\nissue = jira.issue('PROJ-123')\n\nprint(issue.key)\nprint(issue.fields.summary)\nprint(issue.fields.status.name)\n```\n\n#### Advanced: Get Issue with Specific Fields\n\n```python\n# Get issue with expanded fields\nissue = jira.issue(\n    'PROJ-123',\n    fields='summary,status,assignee,reporter,created,updated,priority,labels',\n    expand='changelog,renderedFields'\n)\n\nprint('Key:', issue.key)\nprint('Summary:', issue.fields.summary)\nprint('Status:', issue.fields.status.name)\nprint('Priority:', issue.fields.priority.name)\nprint('Assignee:', issue.fields.assignee.displayName if issue.fields.assignee else 'Unassigned')\nprint('Reporter:', issue.fields.reporter.displayName)\nprint('Created:', issue.fields.created)\nprint('Updated:', issue.fields.updated)\nprint('Labels:', issue.fields.labels)\n\n# Access changelog\nif hasattr(issue, 'changelog'):\n    print('\\nChange History:')\n    for history in issue.changelog.histories:\n        print(f'  {history.created} by {history.author.displayName}')\n```\n\n#### Create Issue\n\n```python\n# Minimal example\nnew_issue = jira.create_issue(\n    project='PROJ',\n    summary='New issue from Python',\n    description='This is a test issue created via the API',\n    issuetype={'name': 'Task'}\n)\n\nprint(f'Created issue: {new_issue.key}')\n```\n\n#### Advanced: Create Issue with All Fields\n\n```python\n# Advanced example with multiple fields\nissue_dict = {\n    'project': {'key': 'PROJ'},\n    'summary': 'Implement user authentication',\n    'description': 'Need to implement OAuth 2.0 authentication for the API.\\n\\nAcceptance Criteria:\\n- Support OAuth 2.0\\n- Token refresh\\n- Secure storage',\n    'issuetype': {'name': 'Story'},\n    'priority': {'name': 'High'},\n    'labels': ['security', 'authentication', 'api'],\n    'components': [{'name': 'Backend'}],\n    'assignee': {'accountId': '5b10a2844c20165700ede21g'},\n    'duedate': '2025-12-31',\n    'customfield_10001': 'Custom field value',\n}\n\nnew_issue = jira.create_issue(fields=issue_dict)\n\nprint(f'Created issue: {new_issue.key} - {new_issue.fields.summary}')\n```\n\n#### Bulk Create Issues\n\n```python\n# Create multiple issues at once\nissue_list = [\n    {\n        'project': {'key': 'PROJ'},\n        'summary': 'First task',\n        'description': 'Description for first task',\n        'issuetype': {'name': 'Task'},\n    },\n    {\n        'project': {'key': 'PROJ'},\n        'summary': 'Second task',\n        'description': 'Description for second task',\n        'issuetype': {'name': 'Task'},\n        'priority': {'name': 'High'},\n    },\n]\n\nissues = jira.create_issues(field_list=issue_list)\n\nfor issue in issues:\n    print(f'Created: {issue[\"issue\"].key}')\n```\n\n#### Update Issue\n\n```python\n# Update issue fields\nissue = jira.issue('PROJ-123')\n\n# Method 1: Using update method\nissue.update(\n    summary='Updated summary',\n    description='Updated description',\n    priority={'name': 'Critical'}\n)\n\n# Method 2: Using fields parameter\nissue.update(fields={\n    'labels': ['updated', 'priority'],\n    'customfield_10001': 'New value'\n})\n\n# Method 3: Silent update (no notifications)\nissue.update(\n    notify=False,\n    description='Silent update - no emails sent'\n)\n\nprint('Issue updated successfully')\n```\n\n#### Assign Issue\n\n```python\n# Assign issue to a user\njira.assign_issue('PROJ-123', 'username')\n\n# Or use accountId\njira.assign_issue('PROJ-123', '5b10a2844c20165700ede21g')\n\n# Unassign issue\njira.assign_issue('PROJ-123', None)\n\nprint('Issue assigned successfully')\n```\n\n#### Delete Issue\n\n```python\n# Delete an issue\nissue = jira.issue('PROJ-123')\nissue.delete()\n\n# Delete with subtasks\nissue.delete(deleteSubtasks=True)\n\nprint('Issue deleted successfully')\n```\n\n### Issue Search\n\n#### Basic JQL Search\n\n```python\n# Search for issues in a project\nissues = jira.search_issues('project = PROJ')\n\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary}')\n```\n\n#### Advanced: Search with Pagination and Options\n\n```python\n# Advanced search with pagination and field selection\nissues = jira.search_issues(\n    jql_str='project = PROJ AND status = \"In Progress\" ORDER BY created DESC',\n    startAt=0,\n    maxResults=50,\n    fields='summary,status,assignee,priority,created',\n    expand='changelog'\n)\n\nprint(f'Total issues: {issues.total}')\nprint(f'Returned: {len(issues)}')\n\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary}')\n    print(f'  Status: {issue.fields.status.name}')\n    print(f'  Priority: {issue.fields.priority.name}')\n    print(f'  Created: {issue.fields.created}')\n```\n\n#### Pagination Example\n\n```python\n# Fetch all issues with pagination\ndef get_all_issues(jira, jql):\n    \"\"\"Fetch all issues matching JQL query with pagination\"\"\"\n    all_issues = []\n    start_at = 0\n    max_results = 100\n\n    while True:\n        issues = jira.search_issues(\n            jql_str=jql,\n            startAt=start_at,\n            maxResults=max_results\n        )\n\n        all_issues.extend(issues)\n\n        print(f'Fetched {len(all_issues)} of {issues.total} issues')\n\n        if len(issues) < max_results:\n            break\n\n        start_at += max_results\n\n    return all_issues\n\n# Usage\nall_project_issues = get_all_issues(jira, 'project = PROJ')\nprint(f'Total issues fetched: {len(all_project_issues)}')\n```\n\n#### Complex JQL Queries\n\n```python\n# Complex JQL with multiple conditions\njql = \"\"\"\n    project = PROJ AND\n    status IN (\"To Do\", \"In Progress\") AND\n    priority IN (High, Critical) AND\n    assignee = currentUser() AND\n    created >= -30d\n    ORDER BY priority DESC, created ASC\n\"\"\"\n\nissues = jira.search_issues(jql.strip(), maxResults=100)\n\nprint(f'High priority issues: {len(issues)}')\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary} ({issue.fields.priority.name})')\n```\n\n#### Common JQL Patterns\n\n```python\n# Issues assigned to current user\nissues = jira.search_issues('assignee = currentUser()')\n\n# Issues created in last 7 days\nissues = jira.search_issues('created >= -7d')\n\n# High priority unresolved bugs\nissues = jira.search_issues('type = Bug AND priority = High AND status != Resolved')\n\n# Issues in specific sprint\nissues = jira.search_issues('sprint = 123')\n\n# Issues with specific labels\nissues = jira.search_issues('labels IN (urgent, critical)')\n\n# Issues due this week\nissues = jira.search_issues('duedate >= startOfWeek() AND duedate <= endOfWeek()')\n\n# Combining multiple conditions\nissues = jira.search_issues(\n    'project = PROJ AND issuetype in (Story, Task) AND status = Open',\n    maxResults=50\n)\n```\n\n### Comments\n\n#### Get Comments\n\n```python\n# Get all comments for an issue\nissue = jira.issue('PROJ-123')\ncomments = issue.fields.comment.comments\n\nfor comment in comments:\n    print(f'{comment.author.displayName} at {comment.created}:')\n    print(f'  {comment.body}')\n```\n\n#### Get Specific Comment\n\n```python\n# Get a specific comment by ID\ncomment = jira.comment('PROJ-123', '10234')\n\nprint(f'Author: {comment.author.displayName}')\nprint(f'Created: {comment.created}')\nprint(f'Body: {comment.body}')\n```\n\n#### Add Comment\n\n```python\n# Add a simple comment\ncomment = jira.add_comment('PROJ-123', 'This is a new comment from the API')\n\nprint(f'Comment added: {comment.id}')\n```\n\n#### Advanced: Add Comment with Visibility\n\n```python\n# Add comment visible only to specific role\ncomment = jira.add_comment(\n    'PROJ-123',\n    'This is visible only to administrators',\n    visibility={'type': 'role', 'value': 'Administrators'}\n)\n\n# Add comment visible to specific group\ncomment = jira.add_comment(\n    'PROJ-123',\n    'This is visible only to developers',\n    visibility={'type': 'group', 'value': 'jira-developers'}\n)\n\nprint(f'Restricted comment added: {comment.id}')\n```\n\n#### Add Comment with Rich Text (ADF Format)\n\n```python\n# Add comment using Atlassian Document Format (ADF)\ncomment_adf = {\n    \"type\": \"doc\",\n    \"version\": 1,\n    \"content\": [\n        {\n            \"type\": \"paragraph\",\n            \"content\": [\n                {\n                    \"type\": \"text\",\n                    \"text\": \"This is a comment with \"\n                },\n                {\n                    \"type\": \"text\",\n                    \"text\": \"bold text\",\n                    \"marks\": [{\"type\": \"strong\"}]\n                }\n            ]\n        },\n        {\n            \"type\": \"codeBlock\",\n            \"content\": [\n                {\n                    \"type\": \"text\",\n                    \"text\": \"print('Hello, World!')\"\n                }\n            ]\n        }\n    ]\n}\n\ncomment = jira.add_comment('PROJ-123', comment_adf)\nprint(f'Rich text comment added: {comment.id}')\n```\n\n#### Update Comment\n\n```python\n# Update an existing comment\ncomment = jira.comment('PROJ-123', '10234')\n\ncomment.update(body='Updated comment text')\n\n# Silent update (no notifications)\ncomment.update(body='Quiet update', notify=False)\n\nprint('Comment updated successfully')\n```\n\n#### Delete Comment\n\n```python\n# Delete a comment\ncomment = jira.comment('PROJ-123', '10234')\ncomment.delete()\n\nprint('Comment deleted successfully')\n```\n\n### Transitions\n\n#### Get Available Transitions\n\n```python\n# Get all available transitions for an issue\ntransitions = jira.transitions('PROJ-123')\n\nprint('Available transitions:')\nfor transition in transitions:\n    print(f\"  {transition['id']}: {transition['name']} -> {transition['to']['name']}\")\n```\n\n#### Transition Issue\n\n```python\n# Transition issue to a new status\njira.transition_issue('PROJ-123', '21')  # Use transition ID\n\nprint('Issue transitioned successfully')\n```\n\n#### Advanced: Transition with Fields\n\n```python\n# Transition issue and set fields\njira.transition_issue(\n    'PROJ-123',\n    '5',  # Transition ID for \"Resolve Issue\"\n    assignee={'name': 'pm_user'},\n    resolution={'id': '3'},  # Fixed\n    comment='Issue resolved and tested'\n)\n\n# Alternative using fields parameter\njira.transition_issue(\n    'PROJ-123',\n    '5',\n    fields={\n        'assignee': {'name': 'qa_user'},\n        'resolution': {'name': 'Done'},\n        'customfield_10001': 'custom value'\n    }\n)\n\nprint('Issue transitioned with fields updated')\n```\n\n### Attachments\n\n#### Add Attachment\n\n```python\n# Add attachment from file path\njira.add_attachment(\n    issue='PROJ-123',\n    attachment='/path/to/file.pdf'\n)\n\nprint('Attachment added successfully')\n```\n\n#### Advanced: Add Multiple Attachments\n\n```python\n# Add multiple attachments\njira.add_attachment(\n    issue='PROJ-123',\n    attachment='/path/to/document.pdf',\n    filename='report.pdf'\n)\n\n# Add attachment from file object\nwith open('/path/to/file.txt', 'rb') as f:\n    jira.add_attachment(issue='PROJ-123', attachment=f, filename='data.txt')\n\n# Add multiple files\nattachments = ['/path/to/file1.txt', '/path/to/file2.pdf']\nfor attachment_path in attachments:\n    jira.add_attachment(issue='PROJ-123', attachment=attachment_path)\n\nprint('Multiple attachments added successfully')\n```\n\n#### Get Attachments\n\n```python\n# Get all attachments for an issue\nissue = jira.issue('PROJ-123')\n\nfor attachment in issue.fields.attachment:\n    print(f'Filename: {attachment.filename}')\n    print(f'Size: {attachment.size} bytes')\n    print(f'MIME Type: {attachment.mimeType}')\n    print(f'Created: {attachment.created}')\n    print(f'Download URL: {attachment.content}')\n    print()\n```\n\n#### Download Attachment\n\n```python\n# Download attachment content\nissue = jira.issue('PROJ-123')\n\nfor attachment in issue.fields.attachment:\n    # Get attachment content\n    content = attachment.get()\n\n    # Save to file\n    with open(attachment.filename, 'wb') as f:\n        f.write(content)\n\n    print(f'Downloaded: {attachment.filename}')\n```\n\n#### Delete Attachment\n\n```python\n# Delete an attachment by ID\njira.delete_attachment('10001')\n\nprint('Attachment deleted successfully')\n```\n\n### Agile - Boards\n\n#### Get All Boards\n\n```python\n# Get all boards\nboards = jira.boards()\n\nfor board in boards:\n    print(f'{board.id}: {board.name} ({board.type})')\n```\n\n#### Advanced: Get Boards with Filters\n\n```python\n# Get boards with specific parameters\nboards = jira.boards(\n    startAt=0,\n    maxResults=50,\n    type='scrum',  # or 'kanban'\n    name='Development',\n    projectKeyOrID='PROJ'\n)\n\nfor board in boards:\n    print(f'{board.id}: {board.name}')\n    print(f'  Type: {board.type}')\n    if hasattr(board, 'location'):\n        print(f'  Location: {board.location.name}')\n```\n\n#### Get Specific Board\n\n```python\n# Get a specific board by ID\nboard = jira.board(1)\n\nprint(f'Board: {board.name}')\nprint(f'Type: {board.type}')\nprint(f'Location: {board.location.name}')\n```\n\n#### Get Issues on Board\n\n```python\n# Get all issues on a board\nboard_id = 1\nissues = jira.search_issues(f'board = {board_id}')\n\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary}')\n```\n\n### Agile - Sprints\n\n#### Get Sprints for Board\n\n```python\n# Get all sprints for a board\nboard_id = 1\nsprints = jira.sprints(board_id)\n\nfor sprint in sprints:\n    print(f'{sprint.id}: {sprint.name}')\n    print(f'  State: {sprint.state}')\n    if hasattr(sprint, 'startDate'):\n        print(f'  Start: {sprint.startDate}')\n    if hasattr(sprint, 'endDate'):\n        print(f'  End: {sprint.endDate}')\n```\n\n#### Advanced: Get Sprints with Filters\n\n```python\n# Get sprints with specific state\nboard_id = 1\nsprints = jira.sprints(\n    board_id,\n    startAt=0,\n    maxResults=50,\n    state='active'  # 'active', 'closed', 'future'\n)\n\nfor sprint in sprints:\n    print(f'{sprint.name} - {sprint.state}')\n```\n\n#### Get Sprint\n\n```python\n# Get a specific sprint by ID\nsprint = jira.sprint(123)\n\nprint(f'Sprint: {sprint.name}')\nprint(f'State: {sprint.state}')\nprint(f'Start Date: {sprint.startDate}')\nprint(f'End Date: {sprint.endDate}')\nprint(f'Goal: {sprint.goal}')\n```\n\n#### Get Issues in Sprint\n\n```python\n# Get all issues in a sprint\nsprint_id = 123\nissues = jira.search_issues(f'sprint = {sprint_id}')\n\nprint(f'Issues in sprint: {len(issues)}')\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary}')\n    print(f'  Status: {issue.fields.status.name}')\n```\n\n#### Advanced: Get Sprint Issues with JQL\n\n```python\n# Get incomplete issues in active sprint\nsprint_id = 123\njql = f'sprint = {sprint_id} AND status != Done'\n\nissues = jira.search_issues(jql, maxResults=100)\n\nprint(f'Incomplete issues: {len(issues)}')\nfor issue in issues:\n    print(f'{issue.key}: {issue.fields.summary} ({issue.fields.status.name})')\n```\n\n### Users\n\n#### Get Current User\n\n```python\n# Get currently authenticated user\ncurrent_user = jira.current_user()\n\nprint(f'Username: {current_user}')\n```\n\n#### Search for Users\n\n```python\n# Search for users by username or email\nusers = jira.search_users(user='john')\n\nfor user in users:\n    print(f'{user.displayName} ({user.emailAddress})')\n    print(f'  Account ID: {user.accountId}')\n    print(f'  Active: {user.active}')\n```\n\n#### Advanced: Search Users with Filters\n\n```python\n# Search for users in a project\nusers = jira.search_users(\n    user='john',\n    startAt=0,\n    maxResults=50,\n    includeActive=True,\n    includeInactive=False\n)\n\nfor user in users:\n    print(f'{user.displayName} - {user.emailAddress}')\n```\n\n#### Search Assignable Users\n\n```python\n# Search for users who can be assigned to issues in a project\nusers = jira.search_assignable_users_for_projects(\n    username='',  # Empty string to get all\n    projectKeys='PROJ',\n    startAt=0,\n    maxResults=50\n)\n\nfor user in users:\n    print(f'{user.displayName} can be assigned to PROJ')\n```\n\n### Watchers\n\n#### Get Watchers\n\n```python\n# Get watchers for an issue\nissue = jira.issue('PROJ-123')\nwatchers = jira.watchers(issue)\n\nprint(f'Watch Count: {watchers.watchCount}')\nprint('Watchers:')\nfor watcher in watchers.watchers:\n    print(f'  {watcher.displayName}')\n```\n\n#### Add Watcher\n\n```python\n# Add a watcher to an issue\njira.add_watcher('PROJ-123', 'username')\n\n# Or use accountId\njira.add_watcher('PROJ-123', '5b10a2844c20165700ede21g')\n\nprint('Watcher added successfully')\n```\n\n#### Remove Watcher\n\n```python\n# Remove a watcher from an issue\njira.remove_watcher('PROJ-123', 'username')\n\nprint('Watcher removed successfully')\n```\n\n### Labels\n\n#### Get Issue Labels\n\n```python\n# Get labels for an issue\nissue = jira.issue('PROJ-123')\nlabels = issue.fields.labels\n\nprint('Labels:', labels)\n```\n\n#### Update Labels\n\n```python\n# Add labels to an issue\nissue = jira.issue('PROJ-123')\nissue.update(fields={'labels': ['backend', 'api', 'urgent']})\n\n# Append labels (preserve existing)\nexisting_labels = issue.fields.labels\nnew_labels = existing_labels + ['new-label']\nissue.update(fields={'labels': new_labels})\n\nprint('Labels updated successfully')\n```\n\n### Filters\n\n#### Get Favorite Filters\n\n```python\n# Get all favorite filters for current user\nfilters = jira.favourite_filters()\n\nfor f in filters:\n    print(f'{f.id}: {f.name}')\n    print(f'  JQL: {f.jql}')\n    print(f'  Owner: {f.owner.displayName}')\n```\n\n#### Get Filter\n\n```python\n# Get a specific filter by ID\nfilter_obj = jira.filter('10000')\n\nprint(f'Filter: {filter_obj.name}')\nprint(f'JQL: {filter_obj.jql}')\nprint(f'Owner: {filter_obj.owner.displayName}')\n```\n\n#### Search Using Filter\n\n```python\n# Execute a saved filter\nfilter_id = 10000\njql = f'filter = {filter_id}'\nissues = jira.search_issues(jql, maxResults=100)\n\nprint(f'Filter results: {len(issues)} issues')\n```\n\n### Versions (Releases)\n\n#### Create Version\n\n```python\n# Create a new version/release\nversion = jira.create_version(\n    name='v1.2.0',\n    project='PROJ',\n    description='Q4 2025 Release',\n    releaseDate='2025-12-15',\n    archived=False,\n    released=False\n)\n\nprint(f'Created version: {version.name} (ID: {version.id})')\n```\n\n#### Get Version\n\n```python\n# Get a specific version\nversion = jira.version('10001')\n\nprint(f'Version: {version.name}')\nprint(f'Released: {version.released}')\nif hasattr(version, 'releaseDate'):\n    print(f'Release Date: {version.releaseDate}')\n```\n\n#### Update Version\n\n```python\n# Update a version\nversion = jira.version('10001')\nversion.update(\n    name='v1.2.1',\n    description='Updated release',\n    released=True,\n    releaseDate='2025-12-20'\n)\n\nprint('Version updated successfully')\n```\n\n#### Delete Version\n\n```python\n# Delete a version\nversion = jira.version('10001')\nversion.delete()\n\nprint('Version deleted successfully')\n```\n\n### Components\n\n#### Create Component\n\n```python\n# Create a new component\ncomponent = jira.create_component(\n    name='Frontend',\n    project='PROJ',\n    description='Frontend components and pages',\n    leadAccountId='5b10a2844c20165700ede21g'\n)\n\nprint(f'Created component: {component.name} (ID: {component.id})')\n```\n\n#### Get Component\n\n```python\n# Get a specific component\ncomponent = jira.component('10000')\n\nprint(f'Component: {component.name}')\nprint(f'Description: {component.description}')\nif component.lead:\n    print(f'Lead: {component.lead.displayName}')\n```\n\n#### Update Component\n\n```python\n# Update a component\ncomponent = jira.component('10000')\ncomponent.update(\n    name='Updated Frontend',\n    description='Updated description'\n)\n\nprint('Component updated successfully')\n```\n\n### Workflows\n\n#### Get Workflows\n\n```python\n# Get all workflows (requires project admin permissions)\nworkflows = jira.workflows()\n\nfor workflow in workflows:\n    print(f'{workflow.name}')\n```\n\n### Custom Fields\n\n#### Get All Fields\n\n```python\n# Get all fields in Jira\nfields = jira.fields()\n\nprint('Custom Fields:')\nfor field in fields:\n    if field['custom']:\n        print(f\"{field['id']}: {field['name']}\")\n```\n\n#### Get Custom Field Value\n\n```python\n# Get custom field value from an issue\nissue = jira.issue('PROJ-123')\ncustom_field_id = 'customfield_10001'\n\nif hasattr(issue.fields, custom_field_id):\n    value = getattr(issue.fields, custom_field_id)\n    print(f'Custom field value: {value}')\n```\n\n#### Set Custom Field Value\n\n```python\n# Set custom field value\nissue = jira.issue('PROJ-123')\nissue.update(fields={'customfield_10001': 'New custom value'})\n\nprint('Custom field updated successfully')\n```\n\n### Permissions\n\n#### Get My Permissions\n\n```python\n# Get permissions for current user\npermissions = jira.my_permissions(projectKey='PROJ')\n\nprint('Permissions for project PROJ:')\nfor key, permission in permissions['permissions'].items():\n    if permission['havePermission']:\n        print(f'  {key}: Granted')\n```\n\n#### Check Specific Permission\n\n```python\n# Check if user has specific permission\npermissions = jira.my_permissions(\n    projectKey='PROJ',\n    permissions='CREATE_ISSUES,EDIT_ISSUES'\n)\n\ncan_create = permissions['permissions']['CREATE_ISSUES']['havePermission']\ncan_edit = permissions['permissions']['EDIT_ISSUES']['havePermission']\n\nprint(f'Can create issues: {can_create}')\nprint(f'Can edit issues: {can_edit}')\n```\n\n## Common Patterns\n\n### Batch Operations\n\n```python\n# Create multiple issues efficiently\ndef create_multiple_issues(jira, issues_data):\n    \"\"\"Create multiple issues using bulk operation\"\"\"\n    return jira.create_issues(field_list=issues_data)\n\n# Usage\nissues_data = [\n    {\n        'project': {'key': 'PROJ'},\n        'summary': f'Task {i}',\n        'issuetype': {'name': 'Task'},\n    }\n    for i in range(1, 11)\n]\n\ncreated_issues = create_multiple_issues(jira, issues_data)\n\nfor result in created_issues:\n    if 'issue' in result:\n        print(f\"Created: {result['issue'].key}\")\n    else:\n        print(f\"Error: {result['error']}\")\n```\n\n### Rate Limiting\n\n```python\nimport time\n\ndef rate_limited_operation(items, operation, rate_limit=10, delay=1):\n    \"\"\"Execute operations with rate limiting\"\"\"\n    results = []\n\n    for i, item in enumerate(items):\n        result = operation(item)\n        results.append(result)\n\n        # Add delay every rate_limit operations\n        if (i + 1) % rate_limit == 0 and i < len(items) - 1:\n            print(f'Processed {i + 1} items, waiting {delay}s...')\n            time.sleep(delay)\n\n    return results\n\n# Usage\ndef update_issue(issue_key):\n    issue = jira.issue(issue_key)\n    issue.update(fields={'labels': ['batch-updated']})\n    return issue_key\n\nissue_keys = ['PROJ-1', 'PROJ-2', 'PROJ-3', 'PROJ-4', 'PROJ-5']\nresults = rate_limited_operation(issue_keys, update_issue, rate_limit=2, delay=1)\n```\n\n### Retry Logic\n\n```python\nimport time\nfrom jira import JIRAError\n\ndef with_retry(operation, max_retries=3, delay=1):\n    \"\"\"Execute operation with retry logic\"\"\"\n    for attempt in range(1, max_retries + 1):\n        try:\n            return operation()\n        except JIRAError as e:\n            if attempt == max_retries:\n                raise\n\n            print(f'Attempt {attempt} failed: {e.text}')\n            print(f'Retrying in {delay}s...')\n            time.sleep(delay)\n            delay *= 2  # Exponential backoff\n\n# Usage\nissue = with_retry(lambda: jira.issue('PROJ-123'))\nprint(f'Retrieved: {issue.key}')\n```\n\n### Context Manager for Connection\n\n```python\nfrom contextlib import contextmanager\n\n@contextmanager\ndef jira_connection(server, email, api_token):\n    \"\"\"Context manager for Jira connection\"\"\"\n    jira = JIRA(\n        server=server,\n        basic_auth=(email, api_token)\n    )\n    try:\n        yield jira\n    finally:\n        jira.close()\n\n# Usage\nwith jira_connection(\n    'https://your-domain.atlassian.net',\n    'your@email.com',\n    'your_token'\n) as jira:\n    issues = jira.search_issues('project = PROJ', maxResults=10)\n    for issue in issues:\n        print(f'{issue.key}: {issue.fields.summary}')\n```\n\n## Complete Application Example\n\n```python\nimport os\nfrom jira import JIRA, JIRAError\n\ndef main():\n    # Initialize Jira client\n    jira = JIRA(\n        server=os.environ.get('JIRA_SERVER', 'https://your-domain.atlassian.net'),\n        basic_auth=(\n            os.environ.get('JIRA_EMAIL'),\n            os.environ.get('JIRA_API_TOKEN')\n        )\n    )\n\n    try:\n        # Get current user\n        current_user = jira.current_user()\n        print(f'Logged in as: {current_user}')\n\n        # Create a new issue\n        new_issue = jira.create_issue(\n            project='PROJ',\n            summary='Implement new feature',\n            description='This is a new feature request from the API',\n            issuetype={'name': 'Story'},\n            priority={'name': 'High'}\n        )\n\n        print(f'Created issue: {new_issue.key}')\n\n        # Add a comment\n        comment = jira.add_comment(\n            new_issue.key,\n            'Starting work on this issue'\n        )\n\n        print(f'Comment added: {comment.id}')\n\n        # Search for issues\n        jql = 'project = PROJ AND status = \"To Do\" ORDER BY created DESC'\n        issues = jira.search_issues(jql, maxResults=10)\n\n        print(f'\\nFound {issues.total} issues:')\n        for issue in issues:\n            print(f'  {issue.key}: {issue.fields.summary}')\n            print(f'    Status: {issue.fields.status.name}')\n            print(f'    Priority: {issue.fields.priority.name}')\n\n        # Get available transitions\n        transitions = jira.transitions(new_issue.key)\n        print(f'\\nAvailable transitions for {new_issue.key}:')\n        for t in transitions:\n            print(f\"  {t['id']}: {t['name']}\")\n\n    except JIRAError as e:\n        print(f'JIRA Error: {e.status_code} - {e.text}')\n    except Exception as e:\n        print(f'Error: {e}')\n    finally:\n        jira.close()\n\nif __name__ == '__main__':\n    main()\n```\n\n## Advanced Features\n\n### Custom JQL Functions\n\n```python\n# Use JQL functions for dynamic queries\nrecent_issues = jira.search_issues('created >= startOfWeek()')\nmy_overdue = jira.search_issues('assignee = currentUser() AND duedate < now()')\nunresolved_bugs = jira.search_issues('resolution = Unresolved AND type = Bug')\n```\n\n### Issue Links\n\n```python\n# Create issue link\njira.create_issue_link(\n    type='Blocks',\n    inwardIssue='PROJ-123',\n    outwardIssue='PROJ-124'\n)\n\n# Get issue links\nissue = jira.issue('PROJ-123')\nfor link in issue.fields.issuelinks:\n    if hasattr(link, 'outwardIssue'):\n        print(f'Blocks: {link.outwardIssue.key}')\n    if hasattr(link, 'inwardIssue'):\n        print(f'Blocked by: {link.inwardIssue.key}')\n```\n\n### Work Logs\n\n```python\n# Add work log to issue\nworklog = jira.add_worklog(\n    issue='PROJ-123',\n    timeSpent='2h 30m',\n    comment='Worked on implementation'\n)\n\n# Get work logs\nissue = jira.issue('PROJ-123')\nworklogs = jira.worklogs(issue)\n\nfor wl in worklogs:\n    print(f'{wl.author.displayName}: {wl.timeSpent}')\n```\n\n## Response Format Examples\n\n### Issue Object\n\n```python\n{\n    'key': 'PROJ-123',\n    'id': '10002',\n    'fields': {\n        'summary': 'Issue summary',\n        'description': 'Issue description',\n        'status': {'name': 'In Progress'},\n        'priority': {'name': 'High'},\n        'assignee': {\n            'displayName': 'John Doe',\n            'emailAddress': 'john@example.com',\n            'accountId': '5b10a2844c20165700ede21g'\n        },\n        'reporter': {'displayName': 'Jane Smith'},\n        'created': '2025-11-01T10:00:00.000+0000',\n        'updated': '2025-11-07T15:30:00.000+0000',\n        'labels': ['backend', 'api']\n    }\n}\n```\n\n### Search Results\n\n```python\n{\n    'startAt': 0,\n    'maxResults': 50,\n    'total': 127,\n    'issues': [<Issue object>, <Issue object>, ...]\n}\n```\n"
  },
  {
    "path": "content/jiter/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"jiter JSON parser for Python with partial parsing, duplicate-key detection, configurable float handling, and string-cache controls\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"jiter,json,python,pydantic,parser\"\n---\n\n# jiter Python Package Guide\n\n## Golden Rule\n\nUse `jiter` when you need fast JSON parsing in Python and you want features the standard `json` module does not provide directly, especially partial parsing, duplicate-key detection, and configurable float parsing.\n\nIf you are already using Pydantic for JSON parsing, the maintainer recommends relying on Pydantic's built-in JSON handling instead of calling `jiter` directly.\n\n## Install\n\n`jiter` 0.13.0 requires Python 3.9 or newer.\n\n```bash\npython -m pip install \"jiter==0.13.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"jiter==0.13.0\"\npoetry add \"jiter==0.13.0\"\n```\n\n## Initialization\n\nThere is no client object, authentication step, or required environment variable. Import the module and call `jiter.from_json(...)`.\n\n```python\nimport jiter\n```\n\n## Parse JSON\n\n`from_json` accepts JSON bytes and returns normal Python values such as `dict`, `list`, `str`, `int`, `float`, `bool`, and `None`.\n\n```python\nimport jiter\n\npayload = b'{\"name\":\"Ada\",\"active\":true,\"roles\":[\"admin\",\"editor\"]}'\ndata = jiter.from_json(payload)\n\nprint(data[\"name\"])\nprint(data[\"roles\"])\n```\n\nIf your JSON starts as a Python string, encode it first:\n\n```python\nimport jiter\n\ntext = '{\"count\": 3, \"ok\": true}'\ndata = jiter.from_json(text.encode(\"utf-8\"))\n```\n\nA practical file-loading pattern:\n\n```python\nimport jiter\nfrom pathlib import Path\n\nraw = Path(\"data.json\").read_bytes()\ndata = jiter.from_json(raw)\n```\n\n## Parse Incomplete JSON Streams\n\nUse `partial_mode` when you want the parser to return the valid prefix of an incomplete JSON payload instead of raising an error immediately.\n\n```python\nimport jiter\n\nchunk = b'[\"alpha\", \"beta\", \"gam'\nitems = jiter.from_json(chunk, partial_mode=True)\n\nprint(items)\n```\n\nFor object-shaped input, `jiter` returns the keys and values it could parse before the document became incomplete:\n\n```python\nimport jiter\n\nchunk = b'{\"name\":\"Ada\",\"team\":\"platf'\ndata = jiter.from_json(chunk, partial_mode=\"on\")\n\nprint(data)\n```\n\nUse this only when truncated input is expected, such as progressive network reads or partially generated model output. For normal request bodies or files, keep partial parsing off so malformed JSON fails fast.\n\n## Reject Duplicate Object Keys\n\nBy default, duplicate keys use the last value seen. Enable `catch_duplicate_keys` if you want `jiter` to raise instead.\n\n```python\nimport jiter\n\npayload = b'{\"role\":\"user\",\"role\":\"admin\"}'\n\ndata = jiter.from_json(payload)\nprint(data[\"role\"])  # \"admin\"\n```\n\n```python\nimport jiter\n\npayload = b'{\"role\":\"user\",\"role\":\"admin\"}'\n\ntry:\n    jiter.from_json(payload, catch_duplicate_keys=True)\nexcept ValueError as exc:\n    print(exc)\n```\n\nTurn this on for configuration files, security-sensitive payloads, or any input where duplicate keys should be treated as invalid.\n\n## Control How Numbers Are Returned\n\nThe default `float_mode` is `\"float\"`, which returns Python `float` values.\n\n```python\nimport jiter\n\ndata = jiter.from_json(b'{\"price\": 12.5}')\nprint(type(data[\"price\"]))\n```\n\nUse `float_mode=\"decimal\"` when you need `Decimal` objects for money or exact decimal arithmetic.\n\n```python\nfrom decimal import Decimal\nimport jiter\n\ndata = jiter.from_json(b'{\"price\": 12.5}', float_mode=\"decimal\")\n\nassert isinstance(data[\"price\"], Decimal)\n```\n\nUse `float_mode=\"lossless-float\"` when you need access to the original float representation before converting it yourself.\n\n```python\nimport jiter\n\ndata = jiter.from_json(b'{\"value\": 1.234567890123456789}', float_mode=\"lossless-float\")\nvalue = data[\"value\"]\n\nprint(type(value))\nprint(str(value))\nprint(float(value))\nprint(value.as_decimal())\n```\n\n## Manage The String Cache\n\n`jiter` can cache parsed strings. The default `cache_mode` is `\"all\"`.\n\nUse `cache_mode=\"keys\"` if you mainly want to reuse object keys, or `cache_mode=\"none\"` if you do not want string caching for a given parse.\n\n```python\nimport jiter\n\npayload = b'{\"user\":\"ada\",\"role\":\"admin\"}'\n\ndata = jiter.from_json(payload, cache_mode=\"keys\")\nprint(data)\n```\n\nYou can inspect and clear the process-wide cache:\n\n```python\nimport jiter\n\nprint(jiter.cache_usage())\njiter.cache_clear()\nprint(jiter.cache_usage())\n```\n\nIf you parse many unrelated documents with mostly unique strings, disabling caching for those calls can be simpler than carrying cache state for the whole process.\n\n## Handle Non-Standard Numbers\n\n`allow_inf_nan` defaults to `True`, which means non-standard JSON numbers such as `Infinity`, `-Infinity`, and `NaN` are accepted.\n\n```python\nimport jiter\n\ndata = jiter.from_json(b'{\"value\": NaN}')\nprint(data)\n```\n\nSet `allow_inf_nan=False` if you need stricter JSON parsing:\n\n```python\nimport jiter\n\ntry:\n    jiter.from_json(b'{\"value\": NaN}', allow_inf_nan=False)\nexcept ValueError as exc:\n    print(exc)\n```\n\n## Common Pitfalls\n\n- `jiter.from_json(...)` is documented around JSON bytes input. If you have a text string, encode it before parsing.\n- `partial_mode` is for intentionally incomplete input. Leaving it on for normal API requests can hide truncation bugs.\n- Duplicate keys do not raise by default; the last value wins unless you set `catch_duplicate_keys=True`.\n- `allow_inf_nan=True` is more permissive than strict JSON parsers. Disable it if interoperability matters.\n- If you only need standard JSON parsing and none of `jiter`'s extra controls, Python's built-in `json` module may be simpler.\n\n## Official Sources\n\n- GitHub repository: https://github.com/pydantic/jiter\n- PyPI project page: https://pypi.org/project/jiter/\n- API docs for `from_json`: https://docs.rs/jiter/latest/jiter/fn.from_json.html\n- API docs for `LosslessFloat`: https://docs.rs/jiter/latest/jiter/struct.LosslessFloat.html\n- API docs for `cache_usage`: https://docs.rs/jiter/latest/jiter/fn.cache_usage.html\n"
  },
  {
    "path": "content/jmespath/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"JMESPath Python package guide for querying JSON-like data with expressions, filters, functions, and custom options\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"jmespath,json,query,python,filtering\"\n---\n\n# jmespath Python Package Guide\n\n## Golden Rule\n\nUse `jmespath` when you need to query JSON-like Python data with a declarative expression instead of writing nested loops and conditionals by hand.\n\n- Import: `import jmespath`\n- Primary APIs: `jmespath.search()` and `jmespath.compile()`\n- Input shape: plain Python dict/list data, typically from `json.loads()` or API responses already decoded into Python objects\n- Network/auth: none. This package does not talk to a service or manage credentials; it only evaluates expressions against local data\n\n## Installation\n\n```bash\npip install jmespath==1.1.0\n```\n\nFor a floating install:\n\n```bash\npip install jmespath\n```\n\n## Initialization And Setup\n\nThere is no client object, auth flow, or global configuration step.\n\n```python\nimport jmespath\n```\n\nFor one-off queries, call `search()` directly:\n\n```python\nimport jmespath\n\ndata = {\n    \"foo\": {\n        \"bar\": [\n            {\"name\": \"one\"},\n            {\"name\": \"two\"},\n        ]\n    }\n}\n\nresult = jmespath.search(\"foo.bar[-1].name\", data)\nprint(result)  # \"two\"\n```\n\nFor repeated evaluation of the same expression, compile once and reuse it:\n\n```python\nimport jmespath\n\nexpression = jmespath.compile(\"foo.bar\")\n\nprint(expression.search({\"foo\": {\"bar\": \"baz\"}}))   # \"baz\"\nprint(expression.search({\"foo\": {\"bar\": \"qux\"}}))   # \"qux\"\n```\n\nUse `compile()` when the expression string is stable and you are applying it many times in a loop or across many records.\n\n## Core Usage\n\n### Basic field, index, and slice access\n\n```python\nimport jmespath\n\ndata = {\n    \"people\": [\n        {\"name\": \"Alice\", \"age\": 30},\n        {\"name\": \"Bob\", \"age\": 19},\n        {\"name\": \"Carol\", \"age\": 41},\n    ]\n}\n\nprint(jmespath.search(\"people[0].name\", data))   # \"Alice\"\nprint(jmespath.search(\"people[-1].name\", data))  # \"Carol\"\nprint(jmespath.search(\"people[:2].[name, age]\", data))\n```\n\n### Filters\n\nUse a filter projection when you need to keep only array items that match a predicate.\n\n```python\nimport jmespath\n\ndata = {\n    \"people\": [\n        {\"name\": \"Alice\", \"age\": 30},\n        {\"name\": \"Bob\", \"age\": 19},\n        {\"name\": \"Carol\", \"age\": 41},\n    ]\n}\n\nadults = jmespath.search(\"people[?age >= `21`].name\", data)\nprint(adults)  # [\"Alice\", \"Carol\"]\n```\n\nImportant syntax details:\n\n- Use backticks for JSON literals such as numbers, booleans, arrays, objects, and `null`\n- Use raw string literals inside single quotes for string comparisons, for example: `\"tags[?Key=='Name']\"`\n\n### Projections and pipes\n\nProjections are the main way to map over arrays.\n\n```python\nimport jmespath\n\ndata = {\n    \"reservations\": [\n        {\n            \"instances\": [\n                {\"type\": \"small\", \"state\": {\"name\": \"running\"}},\n                {\"type\": \"medium\", \"state\": {\"name\": \"stopped\"}},\n            ]\n        }\n    ]\n}\n\nstates = jmespath.search(\"reservations[].instances[].state.name\", data)\nprint(states)  # [\"running\", \"stopped\"]\n```\n\nUse a pipe when you want the output of one expression to become the input to the next step and you want to stop the current projection before continuing:\n\n```python\nimport jmespath\n\ndata = {\n    \"tags\": [\n        {\"Key\": \"Name\", \"Values\": [\"api-a\"]},\n        {\"Key\": \"Owner\", \"Values\": [\"platform\"]},\n    ]\n}\n\nname = jmespath.search(\"tags[?Key=='Name'] | [0].Values[]\", data)\nprint(name)  # \"api-a\"\n```\n\n### Multiselects and reshaping\n\nUse multiselect lists or hashes when you want to reshape the output into exactly the fields your code needs.\n\n```python\nimport jmespath\n\ndata = {\n    \"people\": [\n        {\"name\": \"Alice\", \"age\": 30, \"city\": \"LA\"},\n        {\"name\": \"Bob\", \"age\": 19, \"city\": \"NYC\"},\n    ]\n}\n\nrows = jmespath.search(\"people[].{name: name, age: age}\", data)\nprint(rows)\n```\n\n### Built-in functions\n\nJMESPath includes built-in functions such as `contains`, `length`, `sort`, `sort_by`, `to_number`, `keys`, and `values`.\n\n```python\nimport jmespath\n\ndata = {\n    \"items\": [\n        {\"name\": \"b\", \"price\": \"12\"},\n        {\"name\": \"a\", \"price\": \"7\"},\n        {\"name\": \"c\", \"price\": \"20\"},\n    ]\n}\n\nsorted_names = jmespath.search(\"sort_by(items, &to_number(price))[].name\", data)\nprint(sorted_names)  # [\"a\", \"b\", \"c\"]\n```\n\nUse `&expr` with functions like `sort_by`, `max_by`, and `min_by`. That `&` creates an expression reference; without it, the function call is wrong.\n\n## Configuration\n\n`jmespath.Options` controls evaluation behavior for the Python implementation.\n\n### Preserve key order in returned mappings\n\nIf you want multiselect-hash results as `OrderedDict` instead of plain `dict`, set `dict_cls`:\n\n```python\nimport collections\nimport jmespath\n\ndata = {\"foo\": {\"b\": \"first\", \"a\": \"second\"}}\n\nresult = jmespath.search(\n    \"{b: foo.b, a: foo.a}\",\n    data,\n    options=jmespath.Options(dict_cls=collections.OrderedDict),\n)\n\nprint(type(result))\n```\n\n### Custom functions\n\nThe Python implementation supports custom functions through `jmespath.functions.Functions` plus `jmespath.Options(custom_functions=...)`.\n\n```python\nimport jmespath\nfrom jmespath import functions\n\nclass CustomFunctions(functions.Functions):\n    @functions.signature({\"types\": [\"string\"]})\n    def _func_reverse(self, value):\n        return value[::-1]\n\noptions = jmespath.Options(custom_functions=CustomFunctions())\nresult = jmespath.search(\"reverse(name)\", {\"name\": \"jmespath\"}, options=options)\nprint(result)  # \"htapsemj\"\n```\n\nUpstream marks custom function support as experimental. Use it only when you control the execution environment and do not need cross-language portability.\n\n## Common Pitfalls\n\n### Missing values can disappear inside projections\n\nWhen a projected subexpression returns `null`, that element is omitted from the collected result. If you expect positional alignment with the source array, do not assume a one-to-one output length after a projection.\n\n### Quote identifiers that contain punctuation\n\nIf a key contains characters that are not valid in an unquoted identifier, quote it in the expression:\n\n```python\nimport jmespath\n\ndata = {\"headers\": {\"content-type\": \"application/json\"}}\nprint(jmespath.search('headers.\"content-type\"', data))\n```\n\n### Use the right literal syntax\n\n- String literal in the expression language: `'Name'`\n- Number / boolean / null / JSON literal: `` `21` ``, `` `true` ``, `` `null` ``\n\nIn Python source code, prefer double quotes around the whole expression when it already contains JMESPath single-quoted strings:\n\n```python\nexpr = \"tags[?Key=='Name']\"\n```\n\n### Object wildcards are not ordered\n\nJMESPath treats object values as unordered. If you need stable ordering, convert the data into an array before querying or sort the result explicitly.\n\n### Ordering comparisons are numeric in the spec\n\nFor filter expressions like `[?age > \\`20\\`]`, the ordering operators are defined for numbers. If the source value is a numeric string, convert it with `to_number(...)` before sorting or aggregating.\n\n### `compile()` does not validate your data shape\n\nCompiling an expression avoids reparsing the expression string; it does not guarantee that a later input document has the keys or types you expect. Validate the data contract separately when the payload schema is uncertain.\n\n## Version-Sensitive Notes For 1.1.0\n\n- PyPI shows `1.1.0` released on `2026-01-22`\n- PyPI lists Python requirement `>=3.9`\n- Older blog posts often describe very old Python compatibility or pre-1.x behavior; prefer the current PyPI page and `jmespath.org` language/spec pages when syntax details conflict\n- Custom functions remain implementation-specific and experimental in the Python package, even though the base JMESPath expression language is standardized\n\n## Recommended Agent Workflow\n\n1. Parse JSON into normal Python dict/list objects first.\n2. Start with `jmespath.search()` for a one-off expression.\n3. Switch to `jmespath.compile()` when reusing the same expression repeatedly.\n4. Use multiselects to shape the output your code needs instead of post-processing large nested results.\n5. Recheck filters, quoting, and numeric conversions before blaming the data source; most broken queries come from expression syntax mismatches, not from Python itself.\n\n## Official Sources\n\n- Docs root: https://jmespath.org/\n- Tutorial: https://jmespath.org/tutorial.html\n- Examples: https://jmespath.org/examples.html\n- Specification: https://jmespath.org/specification.html\n- PyPI package page: https://pypi.org/project/jmespath/\n- Upstream repository: https://github.com/jmespath/jmespath.py\n"
  },
  {
    "path": "content/joblib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Joblib Python package guide for caching, parallel loops, and object persistence\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"joblib,python,parallelism,caching,persistence,numpy\"\n---\n\n# Joblib Python Package Guide\n\n## Golden Rule\n\nUse `joblib` for three things: caching pure function results with `Memory`, running simple parallel loops with `Parallel` and `delayed`, and persisting large Python or NumPy-heavy objects with `dump` and `load`. Keep the default `loky` backend for generic Python work, prefer threads when the workload releases the GIL, and never `joblib.load()` data from an untrusted source.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"joblib==1.5.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"joblib==1.5.3\"\npoetry add \"joblib==1.5.3\"\n```\n\nUseful dependency notes from upstream:\n\n- `joblib` has no mandatory dependencies beyond Python.\n- `numpy` is optional but is a common companion and unlocks the main large-array optimizations described in the docs.\n- `lz4` is optional and makes `.lz4` compressed persistence available automatically.\n- `psutil` is optional and can help mitigate memory leaks in parallel worker processes.\n\n## Initialize And Setup\n\nThere is no auth or remote service setup. The main setup decision is where caches and temporary worker files should live.\n\nTypical imports:\n\n```python\nfrom joblib import Memory, Parallel, delayed, dump, load, parallel_config\n```\n\nTypical local cache setup:\n\n```python\nfrom pathlib import Path\nfrom joblib import Memory\n\ncache_dir = Path(\".cache/joblib\")\nmemory = Memory(cache_dir, verbose=0)\n```\n\nUse a cache directory that is safe to delete and not intended for manual editing. `Memory` stores pickled results on disk.\n\n## Core Usage\n\n### Cache expensive pure functions with `Memory`\n\nDecorate a function once and joblib will reuse the stored result for matching inputs:\n\n```python\nfrom pathlib import Path\nfrom joblib import Memory\n\nmemory = Memory(Path(\".cache/joblib\"), verbose=0)\n\n@memory.cache\ndef build_features(values: list[int]) -> list[int]:\n    print(\"computing\")\n    return [value * value for value in values]\n\nfirst = build_features([1, 2, 3])   # computes\nsecond = build_features([1, 2, 3])  # loads from cache\n```\n\nUse `ignore=[...]` for arguments that should not affect cache keys:\n\n```python\n@memory.cache(ignore=[\"debug\"])\ndef transform(data_path: str, debug: bool = False) -> str:\n    return data_path.upper()\n```\n\nUse cache validation when cached results expire based on time or external state:\n\n```python\nfrom joblib import Memory, expires_after\n\nmemory = Memory(\".cache/joblib\", verbose=0)\n\n@memory.cache(cache_validation_callback=expires_after(hours=1))\ndef fetch_snapshot() -> dict:\n    return {\"status\": \"ok\"}\n```\n\n### Run parallel loops with `Parallel` and `delayed`\n\nBasic process-based parallelism:\n\n```python\nfrom joblib import Parallel, delayed\n\ndef score_item(x: int) -> int:\n    return x * x\n\nresults = Parallel(n_jobs=-1)(\n    delayed(score_item)(x) for x in range(10)\n)\n```\n\nPrefer threads for I/O-heavy or native-code workloads that release the GIL:\n\n```python\nfrom joblib import Parallel, delayed\n\nresults = Parallel(n_jobs=8, prefer=\"threads\")(\n    delayed(score_item)(x) for x in range(100)\n)\n```\n\nIf you want results incrementally instead of materializing the whole list at once:\n\n```python\nfrom joblib import Parallel, delayed\n\nparallel = Parallel(n_jobs=4, return_as=\"generator\")\nfor result in parallel(delayed(score_item)(x) for x in range(20)):\n    print(result)\n```\n\n### Control backend defaults with `parallel_config`\n\nUse `parallel_config()` when the parallel call is buried inside another library or when you want a scoped override without hard-coding backend choices in reusable code:\n\n```python\nfrom joblib import Parallel, delayed, parallel_config\n\nwith parallel_config(\n    backend=\"loky\",\n    n_jobs=4,\n    inner_max_num_threads=1,\n    temp_folder=\"/tmp/joblib\",\n):\n    results = Parallel()(delayed(score_item)(x) for x in range(20))\n```\n\n`inner_max_num_threads` matters when NumPy, BLAS, or similar native libraries spawn their own thread pools inside each worker.\n\n### Persist Python objects with `dump` and `load`\n\nUse joblib persistence when pickled objects contain large arrays or when compressed storage is convenient:\n\n```python\nfrom joblib import dump, load\n\npayload = {\"weights\": [1, 2, 3], \"name\": \"model-a\"}\n\ndump(payload, \"artifacts/model.joblib\")\nrestored = load(\"artifacts/model.joblib\")\n```\n\nCompression is built in:\n\n```python\nfrom joblib import dump\n\ndump(payload, \"artifacts/model.joblib.gz\", compress=(\"gzip\", 3))\n```\n\nFor large NumPy payloads, the standard library `pickle` protocol 5 can also be a reasonable alternative on Python 3.8+ when you do not need joblib-specific features.\n\n## Configuration And Environment\n\nThere is no authentication layer. The configuration knobs that matter are local execution and filesystem behavior.\n\nImportant options and environment variables:\n\n- `n_jobs`: `-1` means \"use all CPUs\"; `1` disables parallelism and is the easiest debug mode.\n- `prefer=\"threads\"`: use this when the hot path mostly runs in native code or is I/O-bound.\n- `backend=\"loky\"`: default process backend; robust, but serialization overhead can dominate small tasks.\n- `temp_folder`: worker temp directory for memmapping with process-based backends.\n- `max_nbytes` and `mmap_mode`: control when large arrays are memory-mapped for worker sharing.\n- `JOBLIB_TEMP_FOLDER`: first-choice environment variable for process-worker temp files.\n- `TMPDIR`, `TMP`, `TEMP`: fallback temp directory controls used by the system temp folder.\n\n## Common Pitfalls\n\n- `joblib.load()` executes pickle-based deserialization. Do not load files from users, downloads, or any other untrusted source.\n- `Memory` is designed for pure functions. Caching instance methods is fragile because `self` becomes part of the cache key unless you deliberately ignore it.\n- Cache keys can invalidate after upgrading `joblib` or some third-party libraries because object hashing can change across versions.\n- `mmap_mode=\"r\"` returns read-only memmaps. `r+` and `w+` can mutate the on-disk cache and corrupt it; use `c` if you need copy-on-write semantics.\n- Close or delete memmap-backed results on Windows to avoid file-locking issues.\n- Default process workers serialize arguments and results. For tiny tasks, `Parallel` can be slower than a plain loop.\n- Nested native thread pools can cause severe oversubscription. Use `inner_max_num_threads` or reduce library thread counts when combining joblib with NumPy or BLAS-heavy code.\n- In reusable libraries, do not hard-code `backend=\"threading\"` or similar unless you truly must. Upstream recommends soft hints such as `prefer` and external overrides via `parallel_config()`.\n- `parallel_backend()` is in the deprecated section of the official docs; prefer `parallel_config()`.\n\n## Version-Sensitive Notes For 1.5.x\n\n- `joblib 1.5.3` on PyPI was released on 2025-12-15 and supports Python 3.9 through 3.13.\n- The 1.5.0 line dropped Python 3.8 support and added Python 3.13 free-threaded support.\n- `Memory` now auto-creates a `.gitignore` in its cache directory, and `1.5.3` specifically avoids overwriting an existing `.gitignore`.\n- `1.5.2` fixed collisions for temporary files in shared cache directories accessed concurrently on cluster filesystems.\n- `1.5.3` hardened evaluation of `pre_dispatch` expressions to avoid excessive memory allocation and crashes. Keep `pre_dispatch` values simple and numeric.\n- `1.5.3` also updated vendored `cloudpickle` to `3.1.2`, which matters if you serialize interactively defined abstractions on Python 3.14+.\n\n## Official Sources\n\n- Docs root: `https://joblib.readthedocs.io/en/stable/`\n- Install guide: `https://joblib.readthedocs.io/en/stable/installing.html`\n- Memory guide: `https://joblib.readthedocs.io/en/stable/memory.html`\n- Parallel guide: `https://joblib.readthedocs.io/en/stable/parallel.html`\n- Persistence guide: `https://joblib.readthedocs.io/en/stable/persistence.html`\n- Changelog / latest changes: `https://joblib.readthedocs.io/en/stable/developing.html#latest-changes`\n- PyPI package page: `https://pypi.org/project/joblib/`\n"
  },
  {
    "path": "content/jsonschema/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"jsonschema Python package guide for validating data with JSON Schema drafts, format checks, and explicit reference handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.26.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"jsonschema,json-schema,validation,python,schemas,referencing\"\n---\n\n# jsonschema Python Package Guide\n\n## Golden Rule\n\nUse `jsonschema` for JSON Schema validation in Python, declare the schema draft with `$schema`, and instantiate a draft-specific validator when you will validate repeatedly or need explicit control over formats and references. In `4.26.0`, new code should use `referencing.Registry` for `$ref` handling instead of the deprecated `RefResolver` APIs.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"jsonschema==4.26.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"jsonschema==4.26.0\"\npoetry add \"jsonschema==4.26.0\"\n```\n\nIf you need built-in format checkers with their optional dependencies, install an extra:\n\n```bash\npython -m pip install \"jsonschema[format]==4.26.0\"\npython -m pip install \"jsonschema[format-nongpl]==4.26.0\"\n```\n\nNotes:\n\n- `jsonschema` itself is a library, not a service client, so there is no auth setup.\n- The extras only install dependencies. They do not enable format validation by themselves.\n- If you need a CLI, the project recommends `check-jsonschema` instead of relying on the deprecated `jsonschema` CLI.\n\n## Initialize And Choose A Draft\n\nFor one-off checks, `validate()` is fine. For repeated validation, instantiate a validator once and reuse it.\n\nInclude `$schema` in schemas so the correct draft is selected:\n\n```python\nfrom jsonschema import validate\n\nschema = {\n    \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"name\": {\"type\": \"string\"},\n        \"age\": {\"type\": \"integer\", \"minimum\": 0},\n    },\n    \"required\": [\"name\"],\n    \"additionalProperties\": False,\n}\n\ninstance = {\"name\": \"Ada\", \"age\": 37}\n\nvalidate(instance=instance, schema=schema)\n```\n\nWhy prefer an explicit validator for real code:\n\n- `validate()` first checks that the schema itself is valid, which is useful but adds overhead.\n- Reusing a validator is simpler when you need `is_valid()`, `iter_errors()`, `registry=...`, or `format_checker=...`.\n\nExample:\n\n```python\nfrom jsonschema import Draft202012Validator\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"object\",\n    \"properties\": {\n        \"email\": {\"type\": \"string\", \"format\": \"email\"},\n    },\n    \"required\": [\"email\"],\n}\n\nDraft202012Validator.check_schema(schema)\n\nvalidator = Draft202012Validator(schema)\n\nassert validator.is_valid({\"email\": \"user@example.com\"})\nassert not validator.is_valid({\"email\": 42})\n```\n\n## Core Usage\n\n### Validate and raise on the first failure\n\n```python\nfrom jsonschema import Draft202012Validator\nfrom jsonschema.exceptions import ValidationError\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"array\",\n    \"items\": {\"type\": \"integer\"},\n    \"maxItems\": 3,\n}\n\nvalidator = Draft202012Validator(schema)\n\ntry:\n    validator.validate([1, 2, \"x\", 4])\nexcept ValidationError as exc:\n    print(exc.message)\n    print(exc.json_path)\n```\n\nUse `validate()` / `validator.validate()` when you want exception-driven control flow.\n\n### Collect every error instead of stopping at the first one\n\n```python\nfrom jsonschema import Draft202012Validator\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"array\",\n    \"items\": {\"enum\": [1, 2, 3]},\n    \"maxItems\": 2,\n}\n\nvalidator = Draft202012Validator(schema)\nerrors = sorted(validator.iter_errors([2, 3, 4]), key=lambda error: list(error.path))\n\nfor error in errors:\n    print(error.message, error.json_path)\n```\n\n`iter_errors()` is the right API for batch reporting, APIs that need field-level feedback, and tests that should assert on structured error data instead of string messages.\n\n### Inspect nested failures with `ErrorTree`\n\n```python\nfrom jsonschema import Draft202012Validator\nfrom jsonschema.exceptions import ErrorTree\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"array\",\n    \"items\": {\"type\": \"number\", \"enum\": [1, 2, 3]},\n    \"minItems\": 3,\n}\n\nvalidator = Draft202012Validator(schema)\ntree = ErrorTree(validator.iter_errors([\"spam\", 2]))\n\nprint(0 in tree)                     # True\nprint(sorted(tree[0].errors))        # ['enum', 'type']\nprint(\"minItems\" in tree.errors)     # True\n```\n\nUse `ErrorTree` when you need to answer questions like \"which field failed which keyword?\" without parsing human-readable messages.\n\n### Enable format validation explicitly\n\n`format` checks are informational by default. They only run if you pass a format checker.\n\n```python\nfrom jsonschema import Draft202012Validator\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"object\",\n    \"properties\": {\n        \"ip\": {\"type\": \"string\", \"format\": \"ipv4\"},\n    },\n    \"required\": [\"ip\"],\n}\n\nvalidator = Draft202012Validator(\n    schema,\n    format_checker=Draft202012Validator.FORMAT_CHECKER,\n)\n\nvalidator.validate({\"ip\": \"127.0.0.1\"})\n```\n\nIf format checks seem to be ignored, the missing piece is usually `format_checker=...`, not the schema.\n\n### Resolve `$ref` with an explicit registry\n\nNew code should use the `referencing` integration instead of deprecated resolver APIs:\n\n```python\nfrom jsonschema import Draft202012Validator\nfrom referencing import Registry\nfrom referencing.jsonschema import DRAFT202012\n\nregistry = Registry().with_resource(\n    \"urn:example:nonnegative-int\",\n    DRAFT202012.create_resource({\"type\": \"integer\", \"minimum\": 0}),\n)\n\nschema = {\n    \"$schema\": Draft202012Validator.META_SCHEMA[\"$id\"],\n    \"type\": \"object\",\n    \"properties\": {\n        \"count\": {\"$ref\": \"urn:example:nonnegative-int\"},\n    },\n    \"required\": [\"count\"],\n}\n\nvalidator = Draft202012Validator(schema, registry=registry)\nvalidator.validate({\"count\": 3})\n```\n\nThis is the safe default for local schema stores and app-controlled reference resolution. If you need custom lookup behavior, pass `Registry(retrieve=...)` with your own loader.\n\n### Extend a validator when you need custom behavior\n\nThe common example is filling defaults, which `jsonschema` does not do automatically:\n\n```python\nfrom jsonschema import Draft202012Validator, validators\n\ndef extend_with_default(validator_class):\n    validate_properties = validator_class.VALIDATORS[\"properties\"]\n\n    def set_defaults(validator, properties, instance, schema):\n        for property_name, subschema in properties.items():\n            if \"default\" in subschema and isinstance(instance, dict):\n                instance.setdefault(property_name, subschema[\"default\"])\n\n        yield from validate_properties(validator, properties, instance, schema)\n\n    return validators.extend(validator_class, {\"properties\": set_defaults})\n\nDefaultValidatingValidator = extend_with_default(Draft202012Validator)\n```\n\nUse this only when mutation is a deliberate application behavior. Validation alone will not apply defaults.\n\n## Configuration Notes\n\n- No auth is required. The important configuration is draft choice, format-checker behavior, and how `$ref` URIs are resolved.\n- Prefer explicit validator classes such as `Draft202012Validator` when the draft matters to correctness.\n- Call `Draft202012Validator.check_schema(schema)` in code paths that accept user- or config-supplied schemas.\n- When validating YAML or TOML, deserialize them first and pass the resulting Python objects into `jsonschema`.\n- Keep input data JSON-like. Behavior is not well-defined for data that cannot exist in JSON, such as mappings with non-string keys.\n\n## Common Pitfalls\n\n- Forgetting `$schema`. Without it, `validate()` chooses the latest released draft by default, which may not match an older schema.\n- Assuming `format` is enforced automatically. It is not.\n- Relying on exact error message wording or error ordering in tests. The project treats both as non-stable; assert on structured attributes like `path`, `schema_path`, `validator`, `validator_value`, or `json_path` instead.\n- Expecting `default` to mutate the instance. It does not unless you build a custom validator.\n- Using deprecated `RefResolver` patterns or depending on implicit remote reference fetching. Use an explicit `Registry` and retrieval function instead.\n- Treating YAML/TOML input as fully equivalent to JSON without normalization. Non-JSON constructs can make validation semantics ambiguous.\n- Mutating library-owned `ErrorTree` objects. `ErrorTree.__setitem__` is deprecated.\n\n## Version-Sensitive Notes For 4.26.0\n\n- PyPI lists `4.26.0` as the latest release as of March 12, 2026. It requires Python `>=3.10`.\n- The `4.26.0` release note is small: it reduces import time by delaying an `urllib.request` import. There are no new top-level validation APIs to adopt for this patch release.\n- The major reference-resolution shift happened in `4.18.0`: `RefResolver` was deprecated in favor of `referencing.Registry`, and automatic remote retrieval was called out as deprecated and security-sensitive.\n- Since `4.19.0`, importing the `Validator` protocol from the package root is deprecated. Prefer `jsonschema.protocols.Validator` in type-focused code.\n- Since `4.24.0`, Python 3.8 is no longer supported. For `4.26.0`, target Python 3.10+ only.\n"
  },
  {
    "path": "content/jsonschema-specifications/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python access to the official JSON Schema metaschemas and vocabularies as a referencing registry\"\nmetadata:\n  languages: \"python\"\n  versions: \"2025.9.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"jsonschema,json-schema,referencing,validation,metaschema\"\n---\n\n# jsonschema-specifications Python Package Guide\n\nUse `jsonschema-specifications` when you need runtime access to the official JSON Schema metaschemas and vocabularies from Python. The package exposes one main public object, `jsonschema_specifications.REGISTRY`, as a `referencing` schema registry.\n\n## Install\n\n```bash\npython -m pip install \"jsonschema-specifications==2025.9.1\"\n```\n\nIf you also want to validate instances or schemas, install `jsonschema` alongside it:\n\n```bash\npython -m pip install \"jsonschema-specifications==2025.9.1\" jsonschema\n```\n\nPyPI lists `2025.9.1` as requiring Python 3.9 or newer.\n\n## What This Package Exposes\n\nThere are no environment variables, API keys, or client objects to configure.\n\nImport the registry directly:\n\n```python\nfrom jsonschema_specifications import REGISTRY\n```\n\nThe 2025.9.1 API reference documents this object as `jsonschema_specifications.REGISTRY = <Registry (20 resources)>`.\n\n## Read An Official Metaschema\n\nUse `REGISTRY.contents(uri)` to fetch the JSON contents for a known schema URI:\n\n```python\nfrom jsonschema_specifications import REGISTRY\n\nDRAFT202012 = \"https://json-schema.org/draft/2020-12/schema\"\n\nmetaschema = REGISTRY.contents(DRAFT202012)\n\nprint(metaschema[\"$schema\"])\nprint(metaschema[\"$id\"])\nprint(metaschema[\"type\"])\n```\n\nUse the canonical JSON Schema URI for the draft you need. For example:\n\n- Draft 2020-12: `https://json-schema.org/draft/2020-12/schema`\n- Draft 2019-09: `https://json-schema.org/draft/2019-09/schema`\n- Draft 7: `http://json-schema.org/draft-07/schema#`\n\n## Validate Data With `jsonschema` Using The Official Registry\n\n`jsonschema` validators accept a keyword-only `registry=` argument. Pass `REGISTRY` when you want the validator to resolve against the official metaschemas explicitly:\n\n```python\nfrom jsonschema import Draft202012Validator\nfrom jsonschema_specifications import REGISTRY\n\nschema = {\n    \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"name\": {\"type\": \"string\"},\n        \"age\": {\"type\": \"integer\", \"minimum\": 0},\n    },\n    \"required\": [\"name\"],\n}\n\nvalidator = Draft202012Validator(schema, registry=REGISTRY)\n\nvalidator.validate({\"name\": \"Ada\", \"age\": 37})\n```\n\nIf you only use `jsonschema` for normal validation, its current validator classes already default to a registry with these official resources. Import `jsonschema-specifications` directly when you need to inspect, extend, or combine that registry yourself.\n\n## Add Your Own Schemas On Top Of The Official Registry\n\n`referencing.Registry` is immutable. Methods like `with_resource(...)` return a new registry, so keep the returned value.\n\nThis is the most useful pattern when your application has internal schemas that `$ref` the official drafts plus your own IDs:\n\n```python\nfrom jsonschema import Draft202012Validator\nfrom jsonschema_specifications import REGISTRY\nfrom referencing.jsonschema import DRAFT202012\n\naddress_schema = {\n    \"$id\": \"https://example.com/schemas/address\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"city\": {\"type\": \"string\"},\n        \"postal_code\": {\"type\": \"string\"},\n    },\n    \"required\": [\"city\", \"postal_code\"],\n}\n\nregistry = REGISTRY.with_resource(\n    address_schema[\"$id\"],\n    DRAFT202012.create_resource(address_schema),\n)\n\norder_schema = {\n    \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"shipping_address\": {\"$ref\": \"https://example.com/schemas/address\"},\n    },\n    \"required\": [\"shipping_address\"],\n}\n\nvalidator = Draft202012Validator(order_schema, registry=registry)\nvalidator.validate(\n    {\n        \"shipping_address\": {\n            \"city\": \"Paris\",\n            \"postal_code\": \"75001\",\n        }\n    }\n)\n```\n\n## Combine Registries\n\nIf you already have another `referencing.Registry`, merge it with the official JSON Schema resources instead of rebuilding everything manually:\n\n```python\nfrom jsonschema_specifications import REGISTRY as SPECIFICATIONS\nfrom referencing import Registry\nfrom referencing.jsonschema import DRAFT202012\n\ncustom = Registry().with_resource(\n    \"https://example.com/non-negative-integer\",\n    DRAFT202012.create_resource({\"type\": \"integer\", \"minimum\": 0}),\n)\n\nregistry = SPECIFICATIONS.combine(custom)\n\nprint(registry.contents(\"https://example.com/non-negative-integer\"))\n```\n\n## Common Pitfalls\n\n- This package does not validate JSON by itself. It provides the official schemas as data; use it together with `jsonschema` or other `referencing`-based tooling.\n- `REGISTRY` is immutable. `with_resource(...)`, `with_resources(...)`, and `combine(...)` return new registry objects.\n- `referencing.Registry` does not automatically fetch remote `$ref` targets. If your schemas depend on remote documents, configure retrieval explicitly in your own registry instead of assuming network access.\n- Use the correct canonical URI for the draft your schema declares in `$schema`. A mismatch between the draft URI and the validator class can produce confusing failures.\n\n## Version Notes For `2025.9.1`\n\n- PyPI shows `jsonschema-specifications 2025.9.1` was released on September 8, 2025.\n- PyPI lists Python 3.9+ support for this release.\n- The 2025.9.1 documentation describes `REGISTRY` as containing 20 official resources.\n\n## Official Sources\n\n- https://jsonschema-specifications.readthedocs.io/en/stable/\n- https://jsonschema-specifications.readthedocs.io/en/stable/api/\n- https://pypi.org/project/jsonschema-specifications/\n- https://python-jsonschema.readthedocs.io/en/stable/validate/\n- https://python-jsonschema.readthedocs.io/en/v4.18.6/referencing/\n- https://referencing.readthedocs.io/en/stable/api/\n"
  },
  {
    "path": "content/jupyter-server/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Jupyter Server package guide for Python with install, launch, authentication, configuration, and REST API usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"jupyter,jupyter-server,python,server,notebook,rest-api\"\n---\n\n# jupyter-server Python Package Guide\n\n## Golden Rule\n\nTreat `jupyter-server` as the backend web application and REST server behind Jupyter frontends, not as a notebook UI package and not as a small import-and-call helper library. Install it in the same environment as the kernels and server extensions you want to expose, start it with the `jupyter server` CLI, and configure it with `ServerApp` settings.\n\nIf you need a full browser UI for editing notebooks and files, install `jupyterlab` or `notebook` on top of Jupyter Server instead of expecting `jupyter-server` alone to replace those applications.\n\n## Install\n\nUse a virtual environment unless you intentionally manage Jupyter globally:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"jupyter-server==2.17.0\"\n```\n\nUseful sanity checks:\n\n```bash\njupyter server --help\njupyter --paths\npython -m pip show jupyter-server\n```\n\nIf you want to call the REST API from Python, install `requests` in the same environment:\n\n```bash\npython -m pip install requests\n```\n\n## Start And Reconnect To A Server\n\nStart a server in the current directory:\n\n```bash\njupyter server\n```\n\nStart without opening a browser and pin the root directory explicitly:\n\n```bash\njupyter server --no-browser --ServerApp.root_dir=\"$PWD\" --ServerApp.port=8888\n```\n\nList running servers and reconnect URLs:\n\n```bash\njupyter server list\n```\n\nBy default, Jupyter Server prints a URL containing an auth token. For local development, that tokenized URL is the normal way to connect from a browser or API client.\n\nThe server root is the current working directory unless you set `ServerApp.root_dir`, so launch from the directory you actually want exposed or set the root explicitly.\n\n## Configuration And Authentication\n\nGenerate a config file:\n\n```bash\nexport JUPYTER_CONFIG_DIR=\"$PWD/.jupyter\"\njupyter server --generate-config\n```\n\nImportant settings usually live in `jupyter_server_config.py` or `jupyter_server_config.json`.\n\nSettings agents and deployment scripts usually need to review:\n\n- `c.ServerApp.ip`\n- `c.ServerApp.port`\n- `c.ServerApp.open_browser`\n- `c.ServerApp.root_dir`\n- `c.ServerApp.base_url`\n- `c.ServerApp.token`\n- `c.ServerApp.password`\n- `c.ServerApp.certfile`\n- `c.ServerApp.keyfile`\n\nMinimal local configuration:\n\n```python\nc.ServerApp.ip = \"127.0.0.1\"\nc.ServerApp.port = 8888\nc.ServerApp.open_browser = False\nc.ServerApp.root_dir = \"/path/to/project\"\n```\n\n### Token and password behavior\n\nJupyter Server uses token authentication by default. The startup log shows a tokenized URL you can paste into a browser or use from an API client.\n\nSet a password interactively:\n\n```bash\njupyter server password\n```\n\nThat command writes password configuration to `jupyter_server_config.json`. In practice, JSON config values take precedence over the Python config file, so check both files if a password, token, or other setting seems to be ignored.\n\nTo generate a hashed password in Python:\n\n```python\nfrom jupyter_server.auth import passwd\n\nhashed = passwd(\"replace-me\")\nprint(hashed)\n```\n\nOnce you set a password, do not treat the server as safe for remote access unless TLS and network controls are also in place.\n\n### Remote single-user servers\n\nFor a remote server, you usually need all of:\n\n- `c.ServerApp.ip = \"0.0.0.0\"` or another deliberate bind address\n- an explicit token or password strategy\n- TLS via `certfile` and `keyfile` or a trusted reverse proxy in front of the server\n- `c.ServerApp.base_url` if the server is mounted under a subpath\n\nJupyter Server's public-server guidance is for a single-user server. If multiple users need separate sessions and isolation, use JupyterHub instead of exposing one shared Jupyter Server instance directly.\n\n## Call The REST API From Python\n\nFor scripts and agents, the cleanest way to automate Jupyter Server is usually the REST API.\n\nSet connection details from the running server output:\n\n```bash\nexport JUPYTER_SERVER_URL=\"http://127.0.0.1:8888\"\nexport JUPYTER_TOKEN=\"paste-the-token-from-jupyter-server-output\"\n```\n\n### List files at the server root\n\n```python\nimport os\n\nimport requests\n\nbase_url = os.environ[\"JUPYTER_SERVER_URL\"].rstrip(\"/\")\ntoken = os.environ[\"JUPYTER_TOKEN\"]\n\nsession = requests.Session()\nsession.headers.update({\"Authorization\": f\"token {token}\"})\n\nresponse = session.get(f\"{base_url}/api/contents\")\nresponse.raise_for_status()\n\nroot = response.json()\nfor entry in root[\"content\"]:\n    print(entry[\"path\"], entry[\"type\"])\n```\n\n### Create or overwrite a text file\n\n```python\nimport os\n\nimport requests\n\nbase_url = os.environ[\"JUPYTER_SERVER_URL\"].rstrip(\"/\")\ntoken = os.environ[\"JUPYTER_TOKEN\"]\n\nsession = requests.Session()\nsession.headers.update({\"Authorization\": f\"token {token}\"})\n\npayload = {\n    \"type\": \"file\",\n    \"format\": \"text\",\n    \"content\": \"hello from jupyter-server\\n\",\n}\n\nresponse = session.put(f\"{base_url}/api/contents/notes.txt\", json=payload)\nresponse.raise_for_status()\n\nprint(response.json()[\"path\"])\n```\n\nThose two calls cover a large share of automation work: connect with a token, inspect the exposed workspace, and write files through the Contents API instead of trying to drive a browser session.\n\n## Extensions And Server-Side Integrations\n\nIf you are writing custom handlers, auth helpers, or other server-side integrations, use `jupyter_server.*` imports and extension patterns rather than older `notebook.*` examples.\n\nCommon operational commands:\n\n```bash\njupyter server extension list\njupyter server extension enable my_extension\n```\n\nIf an extension package still documents old `NotebookApp` settings or old notebook-module imports, treat that guidance cautiously and check the current Jupyter Server developer docs before copying it into new code.\n\n## Common Pitfalls\n\n- Installing `jupyter-server` and expecting it to provide the full JupyterLab or Notebook user interface by itself.\n- Launching from the wrong directory and accidentally exposing the wrong files because `root_dir` was never set.\n- Copying old `NotebookApp` configuration or `notebook.*` imports into new Jupyter Server code.\n- Setting a password with `jupyter server password`, then editing only `jupyter_server_config.py` and wondering why the change does not apply.\n- Binding to a public interface without deliberate auth, TLS, and proxy configuration.\n- Treating one Jupyter Server process as a general multi-user deployment. For isolated multi-user access, use JupyterHub.\n\n## Version-Sensitive Notes For 2.17.0\n\n- This guide targets `jupyter-server 2.17.0`.\n- Prefer `ServerApp` configuration names in new automation and docs. Older `NotebookApp` examples are common in blogs and issue threads, but they are not the best source for current Jupyter Server setup.\n- If you are building extensions or auth integrations, favor current Jupyter Server developer docs over pre-2.x notebook-era examples.\n\n## Official Sources\n\n- Jupyter Server docs root: `https://jupyter-server.readthedocs.io/en/latest/`\n- Jupyter Server security docs: `https://jupyter-server.readthedocs.io/en/stable/operators/security.html`\n- Jupyter Server public-server docs: `https://jupyter-server.readthedocs.io/en/stable/operators/public-server.html`\n- Jupyter Server REST API docs: `https://jupyter-server.readthedocs.io/en/stable/developers/rest-api.html`\n- Jupyter Server developer docs: `https://jupyter-server.readthedocs.io/en/stable/developers/extensions.html`\n- Jupyter running docs: `https://docs.jupyter.org/en/latest/running.html`\n- PyPI package page: `https://pypi.org/project/jupyter-server/2.17.0/`\n"
  },
  {
    "path": "content/jupyterhub/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"JupyterHub package guide for Python with install, proxy setup, jupyterhub_config.py, authentication, spawners, and Hub API usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.4.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"jupyterhub,jupyter,python,multi-user,auth,spawner,proxy,notebooks\"\n---\n\n# jupyterhub Python Package Guide\n\n## Golden Rule\n\nTreat `jupyterhub` as a multi-user Jupyter application and service, not as a normal import-and-call Python library. Most real work happens through the `jupyterhub` CLI, a `jupyterhub_config.py` file, the proxy, the authenticator, the spawner, and the Hub REST API.\n\n## Install\n\nFor a basic local setup, install JupyterHub itself, a single-user UI such as JupyterLab, and the default proxy implementation:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"jupyterhub==5.4.3\" jupyterlab requests\nnpm install -g configurable-http-proxy\n```\n\nWhy these pieces matter:\n\n- `jupyterhub` runs the Hub service\n- `jupyterlab` gives spawned users a browser UI at `/lab`\n- `configurable-http-proxy` is the default proxy JupyterHub expects on `PATH`\n- `requests` is only needed if you want to call the Hub REST API from Python\n\nUseful sanity checks:\n\n```bash\njupyterhub --version\nconfigurable-http-proxy --version\npython -m pip show jupyterhub\npython -m pip show jupyterlab\n```\n\nIf `configurable-http-proxy` is missing, JupyterHub will not finish starting even if the Python package installed correctly.\n\n## Minimal Local Setup\n\nGenerate a starter config:\n\n```bash\nmkdir jupyterhub-demo\ncd jupyterhub-demo\njupyterhub --generate-config\n```\n\nFor a simple local test that does not require pre-created system users, use the built-in dummy authenticator plus the simple spawner:\n\n```python\n# jupyterhub_config.py\nimport os\n\nfrom jupyterhub.auth import DummyAuthenticator\nfrom jupyterhub.spawner import SimpleLocalProcessSpawner\n\n\nc.JupyterHub.bind_url = os.environ.get(\"JUPYTERHUB_BIND_URL\", \"http://127.0.0.1:8000\")\nc.JupyterHub.authenticator_class = DummyAuthenticator\nc.JupyterHub.spawner_class = SimpleLocalProcessSpawner\nc.Authenticator.allow_all = True\nc.DummyAuthenticator.password = os.environ.get(\"JUPYTERHUB_DUMMY_PASSWORD\", \"change-me\")\nc.Spawner.default_url = \"/lab\"\n```\n\nStart the Hub:\n\n```bash\nexport JUPYTERHUB_DUMMY_PASSWORD='dev-password'\njupyterhub -f jupyterhub_config.py\n```\n\nThen open `http://127.0.0.1:8000`, enter any username, and use the shared password from `JUPYTERHUB_DUMMY_PASSWORD`.\n\nThis setup is for local development only. `DummyAuthenticator` is intentionally weak and should not be used for a public or shared deployment.\n\n## Authentication, Users, And Admins\n\nJupyterHub 5 requires explicit access policy. For a real deployment, do not rely on a dummy login flow. Configure a real authenticator and decide who is allowed to sign in.\n\nMinimal allowlist example:\n\n```python\n# jupyterhub_config.py\nc.Authenticator.allowed_users = {\"alice\", \"bob\"}\nc.JupyterHub.admin_users = {\"alice\"}\n```\n\nImportant behavior:\n\n- `allowed_users` limits who can log in\n- `admin_users` grants admin privileges, but you should still define login policy explicitly\n- `allow_all = True` is convenient for local testing, not for production\n\nIf you need external identity providers or non-local user environments, install the relevant authenticator or spawner package separately and point JupyterHub at that class. JupyterHub core does not bundle every production integration.\n\n## Choose The User Interface\n\nJupyterHub launches single-user servers; the notebook UI comes from packages installed in the single-user environment.\n\nSend users to JupyterLab by default:\n\n```python\nc.Spawner.default_url = \"/lab\"\n```\n\nOr send them to the classic tree view:\n\n```python\nc.Spawner.default_url = \"/tree\"\n```\n\nIf you set `\"/lab\"` but the spawned environment does not have `jupyterlab` installed, users will authenticate successfully and still land on a broken or missing interface.\n\n## Hub API From Python\n\nJupyterHub exposes a REST API under `/hub/api`. For external scripts or services, authenticate with an API token and send the token in the `Authorization` header.\n\nEnvironment:\n\n```bash\nexport JUPYTERHUB_URL='http://127.0.0.1:8000'\nexport JUPYTERHUB_API_TOKEN='replace-with-a-real-token'\n```\n\nExample: list users and inspect one user record:\n\n```python\nimport os\n\nimport requests\n\n\nhub_url = os.environ[\"JUPYTERHUB_URL\"].rstrip(\"/\")\napi_token = os.environ[\"JUPYTERHUB_API_TOKEN\"]\n\nheaders = {\n    \"Authorization\": f\"token {api_token}\",\n}\n\nusers_response = requests.get(\n    f\"{hub_url}/hub/api/users\",\n    headers=headers,\n    timeout=30,\n)\nusers_response.raise_for_status()\nprint(users_response.json())\n\nuser_response = requests.get(\n    f\"{hub_url}/hub/api/users/alice\",\n    headers=headers,\n    timeout=30,\n)\nuser_response.raise_for_status()\nprint(user_response.json())\n```\n\nIf your Python code runs as a managed JupyterHub service, prefer the service-specific environment variables JupyterHub provides:\n\n```python\nimport os\n\nimport requests\n\n\napi_url = os.environ[\"JUPYTERHUB_API_URL\"].rstrip(\"/\")\napi_token = os.environ[\"JUPYTERHUB_API_TOKEN\"]\n\nresponse = requests.get(\n    f\"{api_url}/users\",\n    headers={\"Authorization\": f\"token {api_token}\"},\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n```\n\nThat pattern is the cleanest way to talk back to the Hub from an app or service that JupyterHub already manages.\n\n## Production-Leaning Configuration\n\nFor a more realistic starting point, move sensitive values into environment variables and persist the Hub database and cookie secret across restarts:\n\n```python\n# jupyterhub_config.py\nimport os\n\n\nc.JupyterHub.bind_url = os.environ.get(\"JUPYTERHUB_BIND_URL\", \"http://127.0.0.1:8000\")\nc.JupyterHub.cookie_secret_file = os.environ.get(\n    \"JUPYTERHUB_COOKIE_SECRET_FILE\",\n    \"jupyterhub_cookie_secret\",\n)\nc.JupyterHub.db_url = os.environ.get(\n    \"JUPYTERHUB_DB_URL\",\n    \"sqlite:///jupyterhub.sqlite\",\n)\nc.Authenticator.allowed_users = {\"alice\", \"bob\"}\nc.JupyterHub.admin_users = {\"alice\"}\nc.Spawner.default_url = \"/lab\"\n```\n\nExample environment:\n\n```bash\nexport JUPYTERHUB_BIND_URL='http://127.0.0.1:8000'\nexport JUPYTERHUB_COOKIE_SECRET_FILE='/srv/jupyterhub/jupyterhub_cookie_secret'\nexport JUPYTERHUB_DB_URL='sqlite:////srv/jupyterhub/jupyterhub.sqlite'\n```\n\nSQLite is fine for local development and small single-node installs. For production, confirm the database backend, reverse proxy, TLS, and authenticator choices against the deployment model you actually run.\n\n## Common Pitfalls\n\n- Installing `jupyterhub` without `configurable-http-proxy`. The Hub needs a working proxy command on `PATH` unless you deliberately replace the default proxy.\n- Using `DummyAuthenticator` outside local development. It is useful for testing, not for real authentication.\n- Forgetting JupyterHub 5 access policy changes. If you do not set `allow_all`, `allowed_users`, or another explicit allow rule, logins can fail even when the authenticator itself is working.\n- Assuming the Hub environment and the single-user environment are the same. If users should land in JupyterLab, the spawned environment needs `jupyterlab` installed.\n- Copying very old blog posts that configure only `ip` and `port`. Prefer `bind_url` in new setups.\n- Treating default local process spawning as a container or Kubernetes solution. For isolated user environments, install the correct spawner integration instead of forcing the local-process defaults.\n- Exposing JupyterHub on a public interface without deliberate auth and TLS configuration.\n\n## Version-Sensitive Notes For 5.4.3\n\n- JupyterHub 5 has stricter access defaults than older examples many agents still copy. Review `allow_all`, `allowed_users`, and related access-control settings before assuming a login flow is correct.\n- `5.4.3` is a patch release in the JupyterHub 5 line, so prioritize JupyterHub 5 documentation and examples over older 1.x or 2.x tutorials.\n- For new configuration, prefer `bind_url`-based examples and current authenticator/spawner guidance instead of outdated snippets that assume a simpler single-binary setup.\n\n## Official Sources\n\n- JupyterHub docs root: `https://jupyterhub.readthedocs.io/en/latest/`\n- PyPI package page: `https://pypi.org/project/jupyterhub/`\n"
  },
  {
    "path": "content/jupyterlab/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"JupyterLab package guide for Python projects using the JupyterLab 4.5.x application and extension workflow\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"jupyterlab,jupyter,notebook,python,ide,extensions\"\n---\n\n# JupyterLab Python Package Guide\n\n## Golden Rule\n\nTreat `jupyterlab` as a Python-installed web application built on `jupyter-server`, not as a normal import-and-call library. Install it in the same environment as the kernels and server extensions you need, launch it from the directory you want to expose, keep Jupyter Server authentication enabled unless another trusted auth layer is in front of it, and use prebuilt PyPI extensions instead of source builds.\n\n## Install\n\nPin the package version your environment expects:\n\n```bash\npython -m pip install \"jupyterlab==4.5.6\"\n```\n\nCommon environment-first workflow:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"jupyterlab==4.5.6\"\n```\n\nIf you use conda or mamba, install `jupyterlab` into the environment that will also hold the kernels and notebook dependencies:\n\n```bash\nmamba install -c conda-forge jupyterlab\n```\n\nInstall JupyterLab in the same environment as packages that must be importable from notebooks. A common failure mode is launching JupyterLab from one interpreter while the notebook kernel or extension package lives in another.\n\n## Start And Reconnect\n\nLaunch JupyterLab from the project directory you want to browse:\n\n```bash\njupyter lab\n```\n\nUseful variants:\n\n```bash\njupyter lab --notebook-dir \"$PWD\"\njupyter lab --preferred-dir \"$PWD\"\njupyter server list\n```\n\nOperational notes:\n\n- The initial terminal output includes a tokenized local URL when token auth is enabled.\n- `jupyter server list` is the quickest way to rediscover running servers and reconnect URLs.\n- JupyterLab workspaces are URL-based. Keep the workspace URL if you need to reopen the same layout later.\n\n## Core Workflow\n\n### Use the right environment and kernel\n\nJupyterLab only provides the UI and server shell. Your code executes in a kernel environment. If imports fail inside notebooks even though `jupyter lab` starts cleanly, verify which Python executable the kernel uses and install the package there.\n\n### Inspect where JupyterLab is reading and writing state\n\nThese commands help when settings, extensions, or workspaces do not behave as expected:\n\n```bash\njupyter lab path\njupyter --paths\n```\n\nImportant locations from the upstream docs:\n\n- Application directory: where the built frontend assets and staging data live. Override with `--app-dir` or `JUPYTERLAB_DIR`.\n- User settings directory: defaults under `~/.jupyter/lab/user-settings/`. Override with `JUPYTERLAB_SETTINGS_DIR`.\n- Workspaces directory: defaults under `~/.jupyter/lab/workspaces/`. Override with `JUPYTERLAB_WORKSPACES_DIR`.\n- `labconfig/page_config.json`: used to disable, defer, or otherwise tune frontend extensions.\n\n### Export or restore a workspace\n\nJupyterLab ships a workspace CLI so layout state can be captured or reapplied:\n\n```bash\njupyter lab workspaces export\njupyter lab workspaces import workspace.json\n```\n\nUse this in devcontainer, classroom, or remote-environment setups where a known sidebar and tab layout saves time.\n\n## Configuration And Authentication\n\nJupyterLab uses Jupyter Server for auth and transport. By default, a server with no password set requires a generated token in the URL or in an `Authorization: token ...` header.\n\nSet a password when you need a stable local login flow:\n\n```bash\njupyter server password\n```\n\nKey auth behavior from the upstream security docs:\n\n- If neither token nor password is set, the server is effectively open to whoever can reach it.\n- If you set a password, token auth is disabled by default.\n- Tokens should stay enabled for ad hoc local and remote-tunnel workflows unless you have another deliberate auth boundary.\n\nCommon server config lives in `jupyter_server_config.py` or `jupyter_server_config.json`. Typical settings agents need to review:\n\n- `ServerApp.root_dir`: what files the server can browse\n- `ServerApp.ip`: whether the server binds only to localhost or a broader interface\n- `ServerApp.open_browser`: whether a browser window opens automatically\n- TLS, reverse-proxy, and password settings when exposing a remote server\n\nIf you expose JupyterLab outside localhost, do it behind explicit network controls and authenticated access. Do not rely on obscurity or a copied token URL as your only protection.\n\n## Extensions\n\nFor JupyterLab 4.x, prefer prebuilt extensions distributed as Python packages on PyPI. The Extension Manager uses PyPI and `pip` by default in current stable docs, and it only shows packages marked with the PyPI classifier for prebuilt JupyterLab extensions.\n\nPractical workflow:\n\n1. Prefer the extension author's install instructions if they publish a Python package.\n2. Install the package into the same environment as JupyterLab.\n3. Restart JupyterLab and verify the extension appears.\n4. Use `jupyter labextension list` when debugging enablement or version mismatches.\n\nAdministrative controls worth knowing:\n\n- The Extension Manager can be disabled or switched to `readonly`.\n- Extension listings can be constrained with allowlist or blocklist URLs.\n- Frontend plugins and whole extensions can be disabled through `page_config.json`.\n\nAvoid older source-build guidance unless an extension explicitly requires it. Source extension installs pull in Node.js and a frontend rebuild path that most agent workflows do not want.\n\n## Common Pitfalls\n\n- Stable ReadTheDocs pages are currently labeled as JupyterLab `4.5.0` docs even though PyPI lists `4.5.6`. Treat the stable docs as the `4.5.x` reference and confirm patch-level drift on PyPI before assuming a bug is fixed or a behavior changed.\n- `jupyterlab` starting successfully does not prove notebook imports will work. Kernel environments and server environments are often different.\n- Editing the wrong directory is common. Check `jupyter lab path` before modifying settings, workspaces, or app assets.\n- Installing an extension package into a kernel-only environment will not make it available to the JupyterLab UI.\n- Extension names, Python package names, and frontend plugin IDs are not always the same string.\n- Remote servers should not bind to a public interface without deliberate password or token handling, TLS, and network controls.\n- If you suppress build checks or run with a shared app directory, make sure that is intentional. Otherwise you can hide broken extension state from yourself.\n\n## Version-Sensitive Notes\n\n- PyPI lists `jupyterlab 4.5.6` as the current package version covered by this doc.\n- The upstream stable docs still render as the `4.5.0` documentation branch. That is a documentation-label mismatch, not a reason to downgrade.\n- JupyterLab 4 changed extension discovery and management substantially versus older 3.x guidance; prefer 4.x docs and prebuilt-extension instructions.\n- The JupyterLab changelog notes JupyterLab 3 reached end of maintenance on May 15, 2024. Do not follow 3.x extension-install advice unless you are pinned to an old deployment.\n- If you are automating against UI behavior, check the 4.5 changelog first; terminal, debugger, and notebook interaction details changed during the 4.5 series.\n\n## Official Sources\n\n- JupyterLab docs: `https://jupyterlab.readthedocs.io/en/stable/`\n- Installation: `https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html`\n- Starting and workspace URLs: `https://jupyterlab.readthedocs.io/en/stable/getting_started/starting.html`\n- Directories and config paths: `https://jupyterlab.readthedocs.io/en/stable/user/directories.html`\n- Extension manager and listings: `https://jupyterlab.readthedocs.io/en/stable/user/extensions.html`\n- Changelog: `https://jupyterlab.readthedocs.io/en/stable/getting_started/changelog.html`\n- Jupyter Server security: `https://jupyter-server.readthedocs.io/en/stable/operators/security.html`\n- PyPI package page: `https://pypi.org/project/jupyterlab/`\n- PyPI JSON metadata: `https://pypi.org/pypi/jupyterlab/json`\n"
  },
  {
    "path": "content/kafka/docs/streaming/javascript/DOC.md",
    "content": "---\nname: streaming\ndescription: \"KafkaJS - Apache Kafka client for Node.js streaming and messaging\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.2.4\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"kafka,streaming,messaging,queue,events\"\n---\n\n# KafkaJS - Apache Kafka Client for Node.js\n\n## Golden Rule\n\n**ALWAYS use `kafkajs` version 2.2.4 or later.**\n\n```bash\nnpm install kafkajs\n```\n\n**DO NOT use:**\n- `kafka-node` (deprecated)\n- `no-kafka` (deprecated)\n- `node-rdkafka` (different use case - C++ binding)\n\nKafkaJS is the modern, pure JavaScript Apache Kafka client for Node.js. It provides a complete implementation of the Kafka protocol with support for producers, consumers, admin operations, and transactions.\n\n## Installation\n\n### Basic Installation\n\n```bash\nnpm install kafkajs\n```\n\n### With TypeScript\n\n```bash\nnpm install kafkajs\nnpm install --save-dev @types/node\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```bash\nKAFKA_BROKERS=localhost:9092\nKAFKA_CLIENT_ID=my-app\nKAFKA_USERNAME=your-username\nKAFKA_PASSWORD=your-password\n```\n\nLoad environment variables in your application:\n\n```javascript\nrequire('dotenv').config()\n\nconst brokers = process.env.KAFKA_BROKERS.split(',')\nconst clientId = process.env.KAFKA_CLIENT_ID\n```\n\n## Initialization\n\n### Basic Client\n\n```javascript\nconst { Kafka } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092']\n})\n```\n\n### With Environment Variables\n\n```javascript\nconst { Kafka } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: process.env.KAFKA_CLIENT_ID || 'my-app',\n  brokers: process.env.KAFKA_BROKERS.split(',') || ['localhost:9092']\n})\n```\n\n### With SSL/TLS\n\n```javascript\nconst fs = require('fs')\nconst { Kafka } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9093', 'kafka2:9093'],\n  ssl: {\n    rejectUnauthorized: false,\n    ca: [fs.readFileSync('/path/to/ca-cert', 'utf-8')],\n    key: fs.readFileSync('/path/to/client-key', 'utf-8'),\n    cert: fs.readFileSync('/path/to/client-cert', 'utf-8')\n  }\n})\n```\n\nFor basic SSL without custom certificates:\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9093'],\n  ssl: true\n})\n```\n\n### With SASL Authentication\n\n#### PLAIN\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092'],\n  sasl: {\n    mechanism: 'plain',\n    username: process.env.KAFKA_USERNAME,\n    password: process.env.KAFKA_PASSWORD\n  }\n})\n```\n\n#### SCRAM-SHA-256\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092'],\n  sasl: {\n    mechanism: 'scram-sha-256',\n    username: process.env.KAFKA_USERNAME,\n    password: process.env.KAFKA_PASSWORD\n  }\n})\n```\n\n#### SCRAM-SHA-512\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092'],\n  sasl: {\n    mechanism: 'scram-sha-512',\n    username: process.env.KAFKA_USERNAME,\n    password: process.env.KAFKA_PASSWORD\n  }\n})\n```\n\n#### AWS IAM\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092'],\n  sasl: {\n    mechanism: 'aws',\n    authorizationIdentity: 'AIDAIOSFODNN7EXAMPLE',\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n    sessionToken: process.env.AWS_SESSION_TOKEN // optional\n  }\n})\n```\n\n#### OAUTHBEARER\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092'],\n  sasl: {\n    mechanism: 'oauthbearer',\n    oauthBearerProvider: async () => {\n      const token = await getOAuthToken() // Your token fetching logic\n      return {\n        value: token\n      }\n    }\n  }\n})\n```\n\n### With SSL and SASL Combined\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9093'],\n  ssl: true,\n  sasl: {\n    mechanism: 'plain',\n    username: process.env.KAFKA_USERNAME,\n    password: process.env.KAFKA_PASSWORD\n  }\n})\n```\n\n### Connection Configuration Options\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['kafka1:9092', 'kafka2:9092'],\n  connectionTimeout: 1000,        // Time in ms to wait for successful connection\n  requestTimeout: 30000,          // Time in ms to wait for successful requests\n  enforceRequestTimeout: true,    // Enforce request timeout\n  retry: {\n    initialRetryTime: 300,        // Initial retry time in ms\n    retries: 5,                   // Max number of retries\n    maxRetryTime: 30000,          // Max retry time in ms\n    multiplier: 2,                // Exponential backoff multiplier\n    factor: 0.2                   // Randomization factor\n  }\n})\n```\n\n### Dynamic Broker Discovery\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: async () => {\n    // Fetch broker list dynamically\n    const response = await fetch('http://service-discovery/kafka-brokers')\n    const data = await response.json()\n    return data.brokers\n  }\n})\n```\n\n## Producer\n\n### Creating a Producer\n\n```javascript\nconst producer = kafka.producer()\n```\n\n### Producer Configuration Options\n\n```javascript\nconst producer = kafka.producer({\n  allowAutoTopicCreation: true,   // Allow auto topic creation\n  transactionTimeout: 60000,      // Transaction timeout in ms\n  idempotent: false,              // Enable idempotent producer\n  maxInFlightRequests: null,      // Max concurrent requests\n  metadataMaxAge: 300000          // Metadata refresh interval in ms\n})\n```\n\n### Connecting and Disconnecting\n\n```javascript\nawait producer.connect()\n// ... produce messages\nawait producer.disconnect()\n```\n\n### Sending Messages - Basic\n\n```javascript\nconst producer = kafka.producer()\nawait producer.connect()\n\nawait producer.send({\n  topic: 'my-topic',\n  messages: [\n    { value: 'Hello Kafka' }\n  ]\n})\n\nawait producer.disconnect()\n```\n\n### Sending Messages with Keys\n\n```javascript\nawait producer.send({\n  topic: 'user-events',\n  messages: [\n    { key: 'user-123', value: 'User logged in' },\n    { key: 'user-456', value: 'User logged out' }\n  ]\n})\n```\n\n### Sending Messages with Headers\n\n```javascript\nawait producer.send({\n  topic: 'my-topic',\n  messages: [\n    {\n      key: 'key1',\n      value: 'Hello World',\n      headers: {\n        'correlation-id': '2bfb68bb-893a-423b-a7fa-7b568cad5b67',\n        'user-id': 'user-123'\n      }\n    }\n  ]\n})\n```\n\n### Sending to Specific Partition\n\n```javascript\nawait producer.send({\n  topic: 'my-topic',\n  messages: [\n    {\n      partition: 0,\n      value: 'Message to partition 0'\n    }\n  ]\n})\n```\n\n### Sending with Timestamp\n\n```javascript\nawait producer.send({\n  topic: 'my-topic',\n  messages: [\n    {\n      value: 'Hello Kafka',\n      timestamp: Date.now()\n    }\n  ]\n})\n```\n\n### Sending Multiple Messages\n\n```javascript\nconst messages = [\n  { key: 'key1', value: 'Message 1' },\n  { key: 'key2', value: 'Message 2' },\n  { key: 'key3', value: 'Message 3' }\n]\n\nawait producer.send({\n  topic: 'my-topic',\n  messages: messages\n})\n```\n\n### Send with Acknowledgment Control\n\n```javascript\n// Wait for all in-sync replicas\nawait producer.send({\n  topic: 'my-topic',\n  messages: [{ value: 'Important message' }],\n  acks: -1  // -1 = all replicas, 0 = no acks, 1 = leader only\n})\n\n// No acknowledgment\nawait producer.send({\n  topic: 'my-topic',\n  messages: [{ value: 'Fire and forget' }],\n  acks: 0\n})\n\n// Leader acknowledgment only\nawait producer.send({\n  topic: 'my-topic',\n  messages: [{ value: 'Quick send' }],\n  acks: 1\n})\n```\n\n### Send with Timeout\n\n```javascript\nawait producer.send({\n  topic: 'my-topic',\n  messages: [{ value: 'Hello' }],\n  timeout: 5000  // Timeout in milliseconds\n})\n```\n\n### Send with Compression\n\n```javascript\nconst { CompressionTypes } = require('kafkajs')\n\nawait producer.send({\n  topic: 'my-topic',\n  compression: CompressionTypes.GZIP,\n  messages: [\n    { value: 'Compressed message 1' },\n    { value: 'Compressed message 2' }\n  ]\n})\n```\n\nAvailable compression types:\n- `CompressionTypes.None`\n- `CompressionTypes.GZIP`\n- `CompressionTypes.Snappy` (requires `kafkajs-snappy` package)\n- `CompressionTypes.LZ4` (requires `kafkajs-lz4` package)\n- `CompressionTypes.ZSTD` (requires `@kafkajs/zstd` package)\n\n### Batch Sending to Multiple Topics\n\n```javascript\nawait producer.sendBatch({\n  topicMessages: [\n    {\n      topic: 'topic-a',\n      messages: [\n        { key: 'key1', value: 'Message for topic A' }\n      ]\n    },\n    {\n      topic: 'topic-b',\n      messages: [\n        { key: 'key2', value: 'Message for topic B' }\n      ]\n    }\n  ]\n})\n```\n\n### Batch Sending with Compression\n\n```javascript\nconst { CompressionTypes } = require('kafkajs')\n\nawait producer.sendBatch({\n  compression: CompressionTypes.GZIP,\n  topicMessages: [\n    {\n      topic: 'topic-a',\n      messages: [{ value: 'Message A' }]\n    },\n    {\n      topic: 'topic-b',\n      messages: [{ value: 'Message B' }]\n    }\n  ]\n})\n```\n\n### Custom Partitioner\n\n```javascript\nconst MyPartitioner = () => {\n  return ({ topic, partitionMetadata, message }) => {\n    // Custom partitioning logic\n    const numPartitions = partitionMetadata.length\n    const partition = Math.abs(hashCode(message.key)) % numPartitions\n    return partition\n  }\n}\n\nconst producer = kafka.producer({\n  createPartitioner: MyPartitioner\n})\n\nfunction hashCode(str) {\n  let hash = 0\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i)\n    hash = ((hash << 5) - hash) + char\n    hash = hash & hash\n  }\n  return hash\n}\n```\n\n### Using Legacy Partitioner\n\n```javascript\nconst { Partitioners } = require('kafkajs')\n\nconst producer = kafka.producer({\n  createPartitioner: Partitioners.LegacyPartitioner\n})\n```\n\n### Sending JSON Data\n\n```javascript\nawait producer.send({\n  topic: 'user-events',\n  messages: [\n    {\n      key: 'user-123',\n      value: JSON.stringify({\n        userId: 'user-123',\n        action: 'login',\n        timestamp: Date.now()\n      })\n    }\n  ]\n})\n```\n\n### Error Handling\n\n```javascript\ntry {\n  await producer.send({\n    topic: 'my-topic',\n    messages: [{ value: 'Hello Kafka' }]\n  })\n} catch (error) {\n  console.error('Error sending message:', error)\n  // Handle specific errors\n  if (error.type === 'TOPIC_AUTHORIZATION_FAILED') {\n    console.error('Not authorized to produce to topic')\n  }\n}\n```\n\n## Consumer\n\n### Creating a Consumer\n\n```javascript\nconst consumer = kafka.consumer({ groupId: 'my-group' })\n```\n\n### Consumer Configuration Options\n\n```javascript\nconst consumer = kafka.consumer({\n  groupId: 'my-group',\n  sessionTimeout: 30000,          // Session timeout in ms\n  heartbeatInterval: 3000,        // Heartbeat interval in ms\n  maxBytesPerPartition: 1048576,  // Max bytes per partition (1MB)\n  maxBytes: 10485760,             // Max bytes per fetch (10MB)\n  maxWaitTimeInMs: 5000,          // Max wait time for fetch\n  retry: {\n    retries: 5\n  },\n  allowAutoTopicCreation: true,   // Allow auto topic creation\n  maxInFlightRequests: null,      // Max concurrent requests\n  readUncommitted: false,         // Read uncommitted messages\n  rackId: null                    // Enable follower fetching\n})\n```\n\n### Connecting and Subscribing\n\n```javascript\nconst consumer = kafka.consumer({ groupId: 'my-group' })\nawait consumer.connect()\nawait consumer.subscribe({ topics: ['my-topic'] })\n```\n\n### Subscribe to Multiple Topics\n\n```javascript\nawait consumer.subscribe({ topics: ['topic-a', 'topic-b', 'topic-c'] })\n```\n\n### Subscribe with Regex Pattern\n\n```javascript\nawait consumer.subscribe({ topics: [/topic-(eu|us)-.*/i] })\n```\n\n### Subscribe from Beginning\n\n```javascript\nawait consumer.subscribe({\n  topics: ['my-topic'],\n  fromBeginning: true\n})\n```\n\n### Consuming Messages - eachMessage\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    console.log({\n      topic: topic,\n      partition: partition,\n      offset: message.offset,\n      value: message.value.toString(),\n      key: message.key?.toString(),\n      headers: message.headers\n    })\n  }\n})\n```\n\n### Consuming with Heartbeat\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message, heartbeat }) => {\n    // For long-running processing\n    await processMessage(message)\n    await heartbeat()\n  }\n})\n```\n\n### Consuming with Pause/Resume\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message, pause }) => {\n    try {\n      await processMessage(message)\n    } catch (error) {\n      if (error.retryable) {\n        // Pause for 30 seconds on retryable error\n        const pausedConsumer = pause()\n        setTimeout(() => pausedConsumer.resume(), 30000)\n      }\n    }\n  }\n})\n```\n\n### Consuming JSON Messages\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    const data = JSON.parse(message.value.toString())\n    console.log('Received:', data)\n  }\n})\n```\n\n### Consuming Messages with Headers\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    const correlationId = message.headers['correlation-id']?.toString()\n    const userId = message.headers['user-id']?.toString()\n\n    console.log('Correlation ID:', correlationId)\n    console.log('User ID:', userId)\n    console.log('Message:', message.value.toString())\n  }\n})\n```\n\n### Batch Processing - eachBatch\n\n```javascript\nawait consumer.run({\n  eachBatch: async ({ batch, resolveOffset, heartbeat, isRunning, isStale }) => {\n    for (let message of batch.messages) {\n      if (!isRunning() || isStale()) break\n\n      console.log({\n        topic: batch.topic,\n        partition: batch.partition,\n        offset: message.offset,\n        value: message.value.toString()\n      })\n\n      resolveOffset(message.offset)\n      await heartbeat()\n    }\n  }\n})\n```\n\n### Batch Processing with Manual Commit\n\n```javascript\nawait consumer.run({\n  autoCommitInterval: null,\n  autoCommitThreshold: null,\n  eachBatch: async ({ batch, resolveOffset, commitOffsetsIfNecessary, heartbeat }) => {\n    for (let message of batch.messages) {\n      await processMessage(message)\n      resolveOffset(message.offset)\n    }\n\n    await commitOffsetsIfNecessary()\n    await heartbeat()\n  }\n})\n```\n\n### Batch Processing with Auto-Resolve\n\n```javascript\nawait consumer.run({\n  eachBatchAutoResolve: true,\n  eachBatch: async ({ batch, heartbeat }) => {\n    console.log(`Received batch of ${batch.messages.length} messages`)\n\n    for (let message of batch.messages) {\n      await processMessage(message)\n    }\n\n    await heartbeat()\n  }\n})\n```\n\n### Concurrent Processing by Partition\n\n```javascript\nawait consumer.run({\n  partitionsConsumedConcurrently: 3,\n  eachMessage: async ({ topic, partition, message }) => {\n    // This will process up to 3 partitions concurrently\n    // Messages within the same partition are still processed sequentially\n    await processMessage(message)\n  }\n})\n```\n\n### Manual Offset Management\n\n```javascript\nconst consumer = kafka.consumer({\n  groupId: 'my-group',\n  autoCommit: false\n})\n\nawait consumer.connect()\nawait consumer.subscribe({ topics: ['my-topic'] })\n\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    await processMessage(message)\n\n    // Manual commit\n    await consumer.commitOffsets([\n      {\n        topic: topic,\n        partition: partition,\n        offset: (parseInt(message.offset) + 1).toString()\n      }\n    ])\n  }\n})\n```\n\n### Auto Commit Configuration\n\n```javascript\nawait consumer.run({\n  autoCommit: true,\n  autoCommitInterval: 5000,      // Commit every 5 seconds\n  autoCommitThreshold: 100,      // Or after 100 messages\n  eachMessage: async ({ topic, partition, message }) => {\n    await processMessage(message)\n  }\n})\n```\n\n### Seek to Offset\n\n```javascript\n// Seek before running consumer\nawait consumer.subscribe({ topics: ['my-topic'] })\n\nconsumer.on(consumer.events.GROUP_JOIN, async ({ payload }) => {\n  // Seek to specific offset\n  consumer.seek({ topic: 'my-topic', partition: 0, offset: 12345 })\n})\n\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    console.log(`Offset: ${message.offset}`)\n  }\n})\n```\n\n### Seek to Beginning\n\n```javascript\nconsumer.on(consumer.events.GROUP_JOIN, async ({ payload }) => {\n  const { groupId } = payload\n  console.log(`Consumer ${groupId} joined`)\n\n  // Seek all partitions to beginning\n  const assignments = consumer.assignment()\n  for (const assignment of assignments) {\n    consumer.seek({\n      topic: assignment.topic,\n      partition: assignment.partition,\n      offset: '0'\n    })\n  }\n})\n```\n\n### Pause and Resume Consumption\n\n```javascript\n// Pause consumption\nconsumer.pause([{ topic: 'my-topic', partitions: [0, 1] }])\n\n// Resume after some time\nsetTimeout(() => {\n  consumer.resume([{ topic: 'my-topic', partitions: [0, 1] }])\n}, 60000)\n```\n\n### Error Handling\n\n```javascript\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    try {\n      await processMessage(message)\n    } catch (error) {\n      console.error('Error processing message:', error)\n      // Optionally: send to dead letter queue\n      await sendToDeadLetterQueue(topic, message, error)\n    }\n  }\n})\n```\n\n### Graceful Shutdown\n\n```javascript\nconst consumer = kafka.consumer({ groupId: 'my-group' })\n\nconst shutdown = async () => {\n  console.log('Shutting down consumer...')\n  await consumer.disconnect()\n  process.exit(0)\n}\n\nprocess.on('SIGINT', shutdown)\nprocess.on('SIGTERM', shutdown)\n\nawait consumer.connect()\nawait consumer.subscribe({ topics: ['my-topic'] })\n\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    await processMessage(message)\n  }\n})\n```\n\n## Admin Operations\n\n### Creating Admin Client\n\n```javascript\nconst admin = kafka.admin()\nawait admin.connect()\n```\n\n### List Topics\n\n```javascript\nconst topics = await admin.listTopics()\nconsole.log('Topics:', topics)\n```\n\n### Create Topic\n\n```javascript\nawait admin.createTopics({\n  topics: [\n    {\n      topic: 'my-topic',\n      numPartitions: 3,\n      replicationFactor: 2\n    }\n  ]\n})\n```\n\n### Create Topic with Configuration\n\n```javascript\nawait admin.createTopics({\n  topics: [\n    {\n      topic: 'my-topic',\n      numPartitions: 3,\n      replicationFactor: 2,\n      configEntries: [\n        { name: 'cleanup.policy', value: 'compact' },\n        { name: 'retention.ms', value: '86400000' }\n      ]\n    }\n  ]\n})\n```\n\n### Create Multiple Topics\n\n```javascript\nawait admin.createTopics({\n  topics: [\n    { topic: 'topic-a', numPartitions: 1 },\n    { topic: 'topic-b', numPartitions: 2 },\n    { topic: 'topic-c', numPartitions: 3 }\n  ]\n})\n```\n\n### Delete Topics\n\n```javascript\nawait admin.deleteTopics({\n  topics: ['topic-to-delete']\n})\n```\n\n### Fetch Topic Metadata\n\n```javascript\nconst metadata = await admin.fetchTopicMetadata({\n  topics: ['my-topic']\n})\n\nconsole.log('Topic metadata:', metadata)\n```\n\n### Fetch Topic Offsets\n\n```javascript\nconst offsets = await admin.fetchTopicOffsets('my-topic')\n\nconsole.log('Topic offsets:', offsets)\n// Output: [{ partition: 0, offset: '100', high: '100', low: '0' }]\n```\n\n### Fetch Offsets by Timestamp\n\n```javascript\nconst timestamp = Date.now() - 3600000 // 1 hour ago\n\nconst offsets = await admin.fetchTopicOffsetsByTimestamp('my-topic', timestamp)\nconsole.log('Offsets at timestamp:', offsets)\n```\n\n### Create Partitions\n\n```javascript\nawait admin.createPartitions({\n  topicPartitions: [\n    {\n      topic: 'my-topic',\n      count: 5  // New total partition count\n    }\n  ]\n})\n```\n\n### List Consumer Groups\n\n```javascript\nconst groups = await admin.listGroups()\nconsole.log('Consumer groups:', groups.groups)\n```\n\n### Describe Consumer Group\n\n```javascript\nconst group = await admin.describeGroups(['my-group'])\nconsole.log('Group details:', group)\n```\n\n### Fetch Consumer Group Offsets\n\n```javascript\nconst offsets = await admin.fetchOffsets({\n  groupId: 'my-group',\n  topics: ['my-topic']\n})\n\nconsole.log('Consumer group offsets:', offsets)\n```\n\n### Reset Consumer Group Offsets\n\n```javascript\n// Reset to earliest\nawait admin.resetOffsets({\n  groupId: 'my-group',\n  topic: 'my-topic',\n  earliest: true\n})\n\n// Reset to latest\nawait admin.resetOffsets({\n  groupId: 'my-group',\n  topic: 'my-topic'\n})\n```\n\n### Set Consumer Group Offsets\n\n```javascript\nawait admin.setOffsets({\n  groupId: 'my-group',\n  topic: 'my-topic',\n  partitions: [\n    { partition: 0, offset: '100' },\n    { partition: 1, offset: '200' }\n  ]\n})\n```\n\n### Delete Consumer Group\n\n```javascript\nawait admin.deleteGroups(['my-group'])\n```\n\n### Describe Cluster\n\n```javascript\nconst cluster = await admin.describeCluster()\n\nconsole.log('Cluster ID:', cluster.clusterId)\nconsole.log('Controller:', cluster.controller)\nconsole.log('Brokers:', cluster.brokers)\n```\n\n### Describe Configs\n\n```javascript\nconst configs = await admin.describeConfigs({\n  resources: [\n    {\n      type: 2, // TOPIC\n      name: 'my-topic'\n    }\n  ]\n})\n\nconsole.log('Topic configs:', configs)\n```\n\n### Alter Configs\n\n```javascript\nawait admin.alterConfigs({\n  resources: [\n    {\n      type: 2, // TOPIC\n      name: 'my-topic',\n      configEntries: [\n        { name: 'retention.ms', value: '604800000' }\n      ]\n    }\n  ]\n})\n```\n\n### Delete Topic Records\n\n```javascript\n// Delete records up to offset 100\nawait admin.deleteTopicRecords({\n  topic: 'my-topic',\n  partitions: [\n    { partition: 0, offset: '100' }\n  ]\n})\n```\n\n### Disconnect Admin\n\n```javascript\nawait admin.disconnect()\n```\n\n## Transactions\n\n### Creating Transactional Producer\n\n```javascript\nconst producer = kafka.producer({\n  transactionalId: 'my-transactional-producer',\n  maxInFlightRequests: 1,\n  idempotent: true\n})\n```\n\n### Basic Transaction\n\n```javascript\nawait producer.connect()\n\nconst transaction = await producer.transaction()\n\ntry {\n  await transaction.send({\n    topic: 'my-topic',\n    messages: [\n      { value: 'Message 1' },\n      { value: 'Message 2' }\n    ]\n  })\n\n  await transaction.commit()\n} catch (error) {\n  await transaction.abort()\n  throw error\n}\n```\n\n### Transaction with Multiple Topics\n\n```javascript\nconst transaction = await producer.transaction()\n\ntry {\n  await transaction.send({\n    topic: 'topic-a',\n    messages: [{ value: 'Message A' }]\n  })\n\n  await transaction.send({\n    topic: 'topic-b',\n    messages: [{ value: 'Message B' }]\n  })\n\n  await transaction.commit()\n} catch (error) {\n  await transaction.abort()\n}\n```\n\n### Transaction with sendOffsets\n\n```javascript\nconst consumer = kafka.consumer({ groupId: 'my-group' })\nawait consumer.connect()\nawait consumer.subscribe({ topics: ['input-topic'] })\n\nawait consumer.run({\n  eachMessage: async ({ topic, partition, message }) => {\n    const transaction = await producer.transaction()\n\n    try {\n      // Process and send to output topic\n      const outputMessage = processMessage(message)\n\n      await transaction.send({\n        topic: 'output-topic',\n        messages: [{ value: outputMessage }]\n      })\n\n      // Commit consumer offset atomically\n      await transaction.sendOffsets({\n        consumerGroupId: 'my-group',\n        topics: [\n          {\n            topic: topic,\n            partitions: [\n              {\n                partition: partition,\n                offset: (parseInt(message.offset) + 1).toString()\n              }\n            ]\n          }\n        ]\n      })\n\n      await transaction.commit()\n    } catch (error) {\n      await transaction.abort()\n      throw error\n    }\n  }\n})\n```\n\n## Logging\n\n### Setting Log Level\n\n```javascript\nconst { Kafka, logLevel } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  logLevel: logLevel.ERROR\n})\n```\n\nAvailable log levels:\n- `logLevel.NOTHING`\n- `logLevel.ERROR`\n- `logLevel.WARN`\n- `logLevel.INFO` (default)\n- `logLevel.DEBUG`\n\n### Custom Logger\n\n```javascript\nconst { Kafka, logLevel } = require('kafkajs')\n\nconst customLogger = () => {\n  return {\n    info: (message) => console.log(`[INFO] ${message.message}`),\n    error: (message) => console.error(`[ERROR] ${message.message}`),\n    warn: (message) => console.warn(`[WARN] ${message.message}`),\n    debug: (message) => console.debug(`[DEBUG] ${message.message}`)\n  }\n}\n\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  logLevel: logLevel.INFO,\n  logCreator: customLogger\n})\n```\n\n### Change Log Level at Runtime\n\n```javascript\nkafka.logger().setLogLevel(logLevel.DEBUG)\n```\n\n### Environment Variable for Logging\n\n```bash\nexport KAFKAJS_LOG_LEVEL=DEBUG\n```\n\n## Error Handling and Retries\n\n### Producer Retry Configuration\n\n```javascript\nconst producer = kafka.producer({\n  retry: {\n    initialRetryTime: 100,\n    retries: 8,\n    maxRetryTime: 30000,\n    multiplier: 2,\n    factor: 0.2\n  }\n})\n```\n\n### Consumer Retry Configuration\n\n```javascript\nconst consumer = kafka.consumer({\n  groupId: 'my-group',\n  retry: {\n    initialRetryTime: 100,\n    retries: 8\n  }\n})\n```\n\n### Custom Restart on Failure\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  retry: {\n    retries: 5\n  },\n  restartOnFailure: async (error) => {\n    console.error('Error occurred:', error)\n    // Return true to restart consumer, false to stop\n    return error.type !== 'FATAL_ERROR'\n  }\n})\n```\n\n## Advanced Configuration\n\n### Custom Socket Factory\n\n```javascript\nconst net = require('net')\nconst tls = require('tls')\n\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  socketFactory: ({ host, port, ssl, onConnect }) => {\n    const socket = ssl\n      ? tls.connect({ host, port, servername: host }, onConnect)\n      : net.connect({ host, port }, onConnect)\n\n    socket.setKeepAlive(true, 60000)\n    return socket\n  }\n})\n```\n\n### Rack Awareness for Follower Fetching\n\n```javascript\nconst consumer = kafka.consumer({\n  groupId: 'my-group',\n  rackId: 'us-east-1a'\n})\n```\n\n### Authentication Timeout\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  sasl: {\n    mechanism: 'plain',\n    username: process.env.KAFKA_USERNAME,\n    password: process.env.KAFKA_PASSWORD\n  },\n  authenticationTimeout: 10000\n})\n```\n\n### Reauthentication\n\n```javascript\nconst kafka = new Kafka({\n  clientId: 'my-app',\n  brokers: ['localhost:9092'],\n  sasl: {\n    mechanism: 'oauthbearer',\n    oauthBearerProvider: async () => ({ value: await getToken() })\n  },\n  reauthenticationThreshold: 10000\n})\n```\n\n## Events\n\n### Producer Events\n\n```javascript\nconst producer = kafka.producer()\n\nproducer.on(producer.events.CONNECT, () => {\n  console.log('Producer connected')\n})\n\nproducer.on(producer.events.DISCONNECT, () => {\n  console.log('Producer disconnected')\n})\n\nproducer.on(producer.events.REQUEST_TIMEOUT, ({ payload }) => {\n  console.log('Request timeout:', payload)\n})\n```\n\n### Consumer Events\n\n```javascript\nconst consumer = kafka.consumer({ groupId: 'my-group' })\n\nconsumer.on(consumer.events.GROUP_JOIN, ({ payload }) => {\n  console.log('Consumer joined group:', payload)\n})\n\nconsumer.on(consumer.events.CRASH, ({ payload }) => {\n  console.error('Consumer crashed:', payload.error)\n})\n\nconsumer.on(consumer.events.REBALANCING, ({ payload }) => {\n  console.log('Consumer rebalancing')\n})\n\nconsumer.on(consumer.events.STOP, () => {\n  console.log('Consumer stopped')\n})\n\nconsumer.on(consumer.events.CONNECT, () => {\n  console.log('Consumer connected')\n})\n\nconsumer.on(consumer.events.DISCONNECT, () => {\n  console.log('Consumer disconnected')\n})\n```\n\n## Complete Examples\n\n### Complete Producer Example\n\n```javascript\nconst { Kafka, CompressionTypes, logLevel } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'order-service',\n  brokers: [process.env.KAFKA_BROKER || 'localhost:9092'],\n  logLevel: logLevel.INFO,\n  retry: {\n    retries: 5\n  }\n})\n\nconst producer = kafka.producer({\n  allowAutoTopicCreation: false,\n  idempotent: true\n})\n\nasync function sendOrders() {\n  await producer.connect()\n\n  try {\n    const orders = [\n      { orderId: '123', amount: 99.99 },\n      { orderId: '124', amount: 149.99 }\n    ]\n\n    for (const order of orders) {\n      await producer.send({\n        topic: 'orders',\n        compression: CompressionTypes.GZIP,\n        messages: [\n          {\n            key: order.orderId,\n            value: JSON.stringify(order),\n            headers: {\n              'correlation-id': generateId(),\n              'timestamp': Date.now().toString()\n            }\n          }\n        ]\n      })\n\n      console.log(`Sent order ${order.orderId}`)\n    }\n  } catch (error) {\n    console.error('Error sending orders:', error)\n    throw error\n  } finally {\n    await producer.disconnect()\n  }\n}\n\nsendOrders().catch(console.error)\n\nfunction generateId() {\n  return Math.random().toString(36).substring(7)\n}\n```\n\n### Complete Consumer Example\n\n```javascript\nconst { Kafka, logLevel } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'order-processor',\n  brokers: [process.env.KAFKA_BROKER || 'localhost:9092'],\n  logLevel: logLevel.INFO\n})\n\nconst consumer = kafka.consumer({\n  groupId: 'order-processing-group',\n  sessionTimeout: 30000,\n  heartbeatInterval: 3000\n})\n\nasync function processOrders() {\n  await consumer.connect()\n  await consumer.subscribe({\n    topics: ['orders'],\n    fromBeginning: true\n  })\n\n  await consumer.run({\n    autoCommit: true,\n    autoCommitInterval: 5000,\n    eachMessage: async ({ topic, partition, message }) => {\n      const order = JSON.parse(message.value.toString())\n      const correlationId = message.headers['correlation-id']?.toString()\n\n      console.log(`Processing order ${order.orderId}`, {\n        partition,\n        offset: message.offset,\n        correlationId\n      })\n\n      try {\n        await processOrder(order)\n        console.log(`Order ${order.orderId} processed successfully`)\n      } catch (error) {\n        console.error(`Error processing order ${order.orderId}:`, error)\n        // Send to DLQ or handle error\n      }\n    }\n  })\n}\n\nasync function processOrder(order) {\n  // Simulate order processing\n  await new Promise(resolve => setTimeout(resolve, 100))\n}\n\nconst shutdown = async () => {\n  console.log('Shutting down...')\n  await consumer.disconnect()\n  process.exit(0)\n}\n\nprocess.on('SIGINT', shutdown)\nprocess.on('SIGTERM', shutdown)\n\nprocessOrders().catch(console.error)\n```\n\n### Complete Transaction Example\n\n```javascript\nconst { Kafka } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'transaction-app',\n  brokers: ['localhost:9092']\n})\n\nconst producer = kafka.producer({\n  transactionalId: 'my-transactional-id',\n  maxInFlightRequests: 1,\n  idempotent: true\n})\n\nconst consumer = kafka.consumer({\n  groupId: 'transaction-group'\n})\n\nasync function runTransactionalProcessing() {\n  await producer.connect()\n  await consumer.connect()\n\n  await consumer.subscribe({ topics: ['input-topic'] })\n\n  await consumer.run({\n    autoCommit: false,\n    eachMessage: async ({ topic, partition, message }) => {\n      const transaction = await producer.transaction()\n\n      try {\n        // Parse input message\n        const input = JSON.parse(message.value.toString())\n\n        // Process the message\n        const result = {\n          original: input,\n          processed: true,\n          timestamp: Date.now()\n        }\n\n        // Send to output topic\n        await transaction.send({\n          topic: 'output-topic',\n          messages: [\n            {\n              key: message.key,\n              value: JSON.stringify(result)\n            }\n          ]\n        })\n\n        // Commit offset atomically\n        await transaction.sendOffsets({\n          consumerGroupId: 'transaction-group',\n          topics: [\n            {\n              topic: topic,\n              partitions: [\n                {\n                  partition: partition,\n                  offset: (parseInt(message.offset) + 1).toString()\n                }\n              ]\n            }\n          ]\n        })\n\n        await transaction.commit()\n        console.log(`Processed message at offset ${message.offset}`)\n      } catch (error) {\n        console.error('Transaction failed:', error)\n        await transaction.abort()\n      }\n    }\n  })\n}\n\nrunTransactionalProcessing().catch(console.error)\n```\n\n### Complete Admin Example\n\n```javascript\nconst { Kafka } = require('kafkajs')\n\nconst kafka = new Kafka({\n  clientId: 'admin-client',\n  brokers: ['localhost:9092']\n})\n\nconst admin = kafka.admin()\n\nasync function manageTopics() {\n  await admin.connect()\n\n  try {\n    // List existing topics\n    const existingTopics = await admin.listTopics()\n    console.log('Existing topics:', existingTopics)\n\n    // Create new topic\n    const topicName = 'my-new-topic'\n\n    if (!existingTopics.includes(topicName)) {\n      await admin.createTopics({\n        topics: [\n          {\n            topic: topicName,\n            numPartitions: 3,\n            replicationFactor: 1,\n            configEntries: [\n              { name: 'retention.ms', value: '86400000' },\n              { name: 'cleanup.policy', value: 'delete' }\n            ]\n          }\n        ]\n      })\n      console.log(`Topic ${topicName} created`)\n    }\n\n    // Fetch metadata\n    const metadata = await admin.fetchTopicMetadata({\n      topics: [topicName]\n    })\n    console.log('Topic metadata:', JSON.stringify(metadata, null, 2))\n\n    // Fetch offsets\n    const offsets = await admin.fetchTopicOffsets(topicName)\n    console.log('Topic offsets:', offsets)\n\n    // List consumer groups\n    const groups = await admin.listGroups()\n    console.log('Consumer groups:', groups.groups)\n\n  } catch (error) {\n    console.error('Error managing topics:', error)\n  } finally {\n    await admin.disconnect()\n  }\n}\n\nmanageTopics().catch(console.error)\n```\n"
  },
  {
    "path": "content/kafka/docs/streaming/python/DOC.md",
    "content": "---\nname: streaming\ndescription: \"kafka-python - Apache Kafka client for Python streaming and messaging\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"kafka,streaming,messaging,queue,events\"\n---\n\n# kafka-python - Apache Kafka Client for Python\n\n## Golden Rule\n\n**ALWAYS use `kafka-python` version 2.0.2 or later.**\n\n```bash\npip install kafka-python\n```\n\n**DO NOT use:**\n- `pykafka` (different library)\n- `confluent-kafka` (different library - C-based client)\n- Outdated versions below 2.0.0\n\nkafka-python is a pure Python client for Apache Kafka with support for producers, consumers, and admin operations.\n\n## Installation\n\n### Basic Installation\n\n```bash\npip install kafka-python\n```\n\n### With UV\n\n```bash\nuv pip install kafka-python\n```\n\n### Adding to pyproject.toml\n\n```toml\n[project]\ndependencies = [\n    \"kafka-python>=2.0.2\"\n]\n```\n\n### With Optional Compression Support\n\n```bash\npip install kafka-python[snappy]\npip install kafka-python[lz4]\npip install kafka-python[zstd]\n```\n\nOr all compression codecs:\n\n```bash\npip install kafka-python[snappy,lz4,zstd]\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```bash\nKAFKA_BROKERS=localhost:9092\nKAFKA_USERNAME=your-username\nKAFKA_PASSWORD=your-password\nKAFKA_TOPIC=my-topic\nKAFKA_GROUP_ID=my-group\n```\n\nLoad environment variables in your application:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nbrokers = os.getenv('KAFKA_BROKERS', 'localhost:9092').split(',')\ntopic = os.getenv('KAFKA_TOPIC', 'my-topic')\ngroup_id = os.getenv('KAFKA_GROUP_ID', 'my-group')\n```\n\n## Initialization\n\n### Basic Producer\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n```\n\n### Basic Consumer\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer('my-topic',\n                        bootstrap_servers='localhost:9092',\n                        group_id='my-group')\n```\n\n### With Environment Variables\n\n```python\nimport os\nfrom kafka import KafkaProducer, KafkaConsumer\n\nproducer = KafkaProducer(\n    bootstrap_servers=os.getenv('KAFKA_BROKERS', 'localhost:9092').split(',')\n)\n\nconsumer = KafkaConsumer(\n    os.getenv('KAFKA_TOPIC', 'my-topic'),\n    bootstrap_servers=os.getenv('KAFKA_BROKERS', 'localhost:9092').split(','),\n    group_id=os.getenv('KAFKA_GROUP_ID', 'my-group')\n)\n```\n\n### With Multiple Brokers\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers=['kafka1:9092', 'kafka2:9092', 'kafka3:9092']\n)\n```\n\n## Producer\n\n### Creating a Producer with Configuration\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    client_id='my-producer',\n    acks='all',\n    retries=5,\n    max_in_flight_requests_per_connection=5\n)\n```\n\n### Producer with JSON Serialization\n\n```python\nimport json\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    value_serializer=lambda v: json.dumps(v).encode('utf-8')\n)\n```\n\n### Producer with Key and Value Serialization\n\n```python\nimport json\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    key_serializer=lambda k: k.encode('utf-8'),\n    value_serializer=lambda v: json.dumps(v).encode('utf-8')\n)\n```\n\n### Producer with Compression\n\n```python\nfrom kafka import KafkaProducer\n\n# GZIP compression\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    compression_type='gzip'\n)\n\n# Snappy compression\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    compression_type='snappy'\n)\n\n# LZ4 compression\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    compression_type='lz4'\n)\n\n# ZSTD compression\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    compression_type='zstd'\n)\n```\n\n### Producer Configuration Options\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers=['localhost:9092'],\n    client_id='my-app',\n    acks='all',                              # 0, 1, or 'all'\n    compression_type='gzip',                 # None, 'gzip', 'snappy', 'lz4', 'zstd'\n    retries=5,                               # Number of retries\n    batch_size=16384,                        # Batch size in bytes\n    linger_ms=10,                            # Wait time before sending\n    buffer_memory=33554432,                  # Total memory for buffering\n    max_block_ms=60000,                      # Max blocking time for send\n    max_request_size=1048576,                # Max request size\n    request_timeout_ms=30000,                # Request timeout\n    connections_max_idle_ms=540000,          # Close idle connections after\n    retry_backoff_ms=100,                    # Retry backoff time\n    max_in_flight_requests_per_connection=5, # Max concurrent requests\n    enable_idempotence=False,                # Idempotent producer\n    metadata_max_age_ms=300000               # Metadata refresh interval\n)\n```\n\n### Sending Messages - Basic\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\n# Send raw bytes\nfuture = producer.send('my-topic', b'Hello Kafka')\n\n# Wait for send to complete\nrecord_metadata = future.get(timeout=10)\nprint(f'Sent to partition {record_metadata.partition} at offset {record_metadata.offset}')\n```\n\n### Sending Messages with Key\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\nfuture = producer.send('my-topic', key=b'user-123', value=b'User logged in')\nrecord_metadata = future.get(timeout=10)\n```\n\n### Sending Messages with Partition\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\n# Send to specific partition\nfuture = producer.send('my-topic', value=b'Hello', partition=0)\nrecord_metadata = future.get(timeout=10)\n```\n\n### Sending Messages with Timestamp\n\n```python\nimport time\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\ntimestamp_ms = int(time.time() * 1000)\nfuture = producer.send('my-topic', value=b'Hello', timestamp_ms=timestamp_ms)\nrecord_metadata = future.get(timeout=10)\n```\n\n### Sending Messages with Headers\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\nheaders = [\n    ('correlation-id', b'12345'),\n    ('user-id', b'user-123')\n]\n\nfuture = producer.send('my-topic', value=b'Hello', headers=headers)\nrecord_metadata = future.get(timeout=10)\n```\n\n### Sending JSON Messages\n\n```python\nimport json\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='localhost:9092',\n    value_serializer=lambda v: json.dumps(v).encode('utf-8')\n)\n\ndata = {\n    'user_id': 'user-123',\n    'action': 'login',\n    'timestamp': 1234567890\n}\n\nfuture = producer.send('user-events', data)\nrecord_metadata = future.get(timeout=10)\n```\n\n### Sending with Key and Value Serialization\n\n```python\nimport json\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='localhost:9092',\n    key_serializer=lambda k: k.encode('utf-8'),\n    value_serializer=lambda v: json.dumps(v).encode('utf-8')\n)\n\nfuture = producer.send('my-topic', key='user-123', value={'action': 'login'})\nrecord_metadata = future.get(timeout=10)\n```\n\n### Async Send with Callback\n\n```python\nfrom kafka import KafkaProducer\nfrom kafka.errors import KafkaError\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\ndef on_send_success(record_metadata):\n    print(f'Sent to partition {record_metadata.partition} at offset {record_metadata.offset}')\n\ndef on_send_error(excp):\n    print(f'Error: {excp}')\n\nfuture = producer.send('my-topic', b'Hello Kafka')\nfuture.add_callback(on_send_success)\nfuture.add_errback(on_send_error)\n\n# Continue without blocking\n# Use flush() to wait for all messages\nproducer.flush()\n```\n\n### Flush Messages\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\nproducer.send('my-topic', b'Message 1')\nproducer.send('my-topic', b'Message 2')\nproducer.send('my-topic', b'Message 3')\n\n# Wait for all messages to be sent\nproducer.flush()\n```\n\n### Close Producer\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\nproducer.send('my-topic', b'Hello')\nproducer.flush()\nproducer.close()\n```\n\n### Error Handling\n\n```python\nfrom kafka import KafkaProducer\nfrom kafka.errors import KafkaError, KafkaTimeoutError\n\nproducer = KafkaProducer(bootstrap_servers='localhost:9092')\n\ntry:\n    future = producer.send('my-topic', b'Hello Kafka')\n    record_metadata = future.get(timeout=10)\n    print(f'Success: partition={record_metadata.partition}, offset={record_metadata.offset}')\nexcept KafkaTimeoutError:\n    print('Request timed out')\nexcept KafkaError as e:\n    print(f'Kafka error: {e}')\nexcept Exception as e:\n    print(f'Unexpected error: {e}')\nfinally:\n    producer.close()\n```\n\n## Consumer\n\n### Creating a Consumer\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n```\n\n### Consumer with Multiple Topics\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'topic-a', 'topic-b', 'topic-c',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n```\n\n### Consumer with Pattern Subscription\n\n```python\nimport re\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\n# Subscribe to topics matching pattern\nconsumer.subscribe(pattern='^awesome.*')\n```\n\n### Consumer Configuration Options\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers=['localhost:9092'],\n    client_id='my-consumer',\n    group_id='my-group',\n    auto_offset_reset='earliest',           # 'earliest' or 'latest'\n    enable_auto_commit=True,                # Auto commit offsets\n    auto_commit_interval_ms=5000,           # Auto commit interval\n    max_poll_records=500,                   # Max records per poll\n    max_poll_interval_ms=300000,            # Max poll interval\n    session_timeout_ms=10000,               # Session timeout\n    heartbeat_interval_ms=3000,             # Heartbeat interval\n    fetch_min_bytes=1,                      # Min fetch bytes\n    fetch_max_bytes=52428800,               # Max fetch bytes\n    fetch_max_wait_ms=500,                  # Max fetch wait time\n    max_partition_fetch_bytes=1048576,      # Max bytes per partition\n    request_timeout_ms=305000,              # Request timeout\n    connections_max_idle_ms=540000,         # Close idle connections\n    consumer_timeout_ms=None                # Stop iteration timeout\n)\n```\n\n### Consumer with JSON Deserialization\n\n```python\nimport json\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    value_deserializer=lambda m: json.loads(m.decode('utf-8'))\n)\n```\n\n### Consumer with Key and Value Deserialization\n\n```python\nimport json\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    key_deserializer=lambda k: k.decode('utf-8') if k else None,\n    value_deserializer=lambda v: json.loads(v.decode('utf-8'))\n)\n```\n\n### Consuming Messages - Basic Iteration\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\nfor message in consumer:\n    print(f'Topic: {message.topic}')\n    print(f'Partition: {message.partition}')\n    print(f'Offset: {message.offset}')\n    print(f'Key: {message.key}')\n    print(f'Value: {message.value}')\n    print(f'Timestamp: {message.timestamp}')\n    print(f'Headers: {message.headers}')\n```\n\n### Consuming from Beginning\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    auto_offset_reset='earliest',\n    enable_auto_commit=False\n)\n\nfor message in consumer:\n    print(message.value)\n```\n\n### Consuming with Timeout\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    consumer_timeout_ms=1000  # Stop iteration after 1 second of no messages\n)\n\nfor message in consumer:\n    print(message.value)\n\nprint('No more messages')\n```\n\n### Consuming JSON Messages\n\n```python\nimport json\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'user-events',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    value_deserializer=lambda m: json.loads(m.decode('utf-8'))\n)\n\nfor message in consumer:\n    data = message.value\n    print(f\"User: {data['user_id']}, Action: {data['action']}\")\n```\n\n### Consuming with Headers\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\nfor message in consumer:\n    # Headers is a list of tuples: [(key, value), ...]\n    headers_dict = {k: v.decode('utf-8') for k, v in message.headers} if message.headers else {}\n\n    correlation_id = headers_dict.get('correlation-id')\n    user_id = headers_dict.get('user-id')\n\n    print(f'Correlation ID: {correlation_id}')\n    print(f'User ID: {user_id}')\n    print(f'Message: {message.value}')\n```\n\n### Batch Consumption with poll()\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    enable_auto_commit=False\n)\n\nwhile True:\n    messages = consumer.poll(timeout_ms=1000, max_records=100)\n\n    for topic_partition, records in messages.items():\n        print(f'Received {len(records)} messages from {topic_partition}')\n\n        for record in records:\n            print(f'Offset: {record.offset}, Value: {record.value}')\n\n    # Commit offsets after processing\n    consumer.commit()\n```\n\n### Manual Partition Assignment\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(bootstrap_servers='localhost:9092')\n\n# Manually assign partitions\npartition = TopicPartition('my-topic', 0)\nconsumer.assign([partition])\n\nfor message in consumer:\n    print(message.value)\n```\n\n### Manual Offset Management\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    enable_auto_commit=False\n)\n\nfor message in consumer:\n    process_message(message)\n\n    # Manual commit\n    consumer.commit()\n```\n\n### Commit Specific Offsets\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition, OffsetAndMetadata\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    enable_auto_commit=False\n)\n\nfor message in consumer:\n    process_message(message)\n\n    # Commit specific offset\n    tp = TopicPartition(message.topic, message.partition)\n    offsets = {tp: OffsetAndMetadata(message.offset + 1, None)}\n    consumer.commit(offsets=offsets)\n```\n\n### Async Commit\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    enable_auto_commit=False\n)\n\ndef on_commit_complete(offsets, response):\n    if isinstance(response, Exception):\n        print(f'Commit failed: {response}')\n    else:\n        print(f'Commit successful: {offsets}')\n\nfor message in consumer:\n    process_message(message)\n    consumer.commit_async(callback=on_commit_complete)\n```\n\n### Seek to Offset\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\n# Seek to specific offset\npartition = TopicPartition('my-topic', 0)\nconsumer.seek(partition, 100)\n\nfor message in consumer:\n    print(f'Offset: {message.offset}')\n```\n\n### Seek to Beginning\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\n# Seek all assigned partitions to beginning\nconsumer.seek_to_beginning()\n\nfor message in consumer:\n    print(message.value)\n```\n\n### Seek to End\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\n# Seek all assigned partitions to end\nconsumer.seek_to_end()\n\nfor message in consumer:\n    print(message.value)\n```\n\n### Get Offset Information\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\npartition = TopicPartition('my-topic', 0)\n\n# Get current position\nposition = consumer.position(partition)\nprint(f'Current position: {position}')\n\n# Get committed offset\ncommitted = consumer.committed(partition)\nprint(f'Committed offset: {committed}')\n\n# Get beginning offset\nbeginning = consumer.beginning_offsets([partition])\nprint(f'Beginning offset: {beginning}')\n\n# Get end offset\nend = consumer.end_offsets([partition])\nprint(f'End offset: {end}')\n```\n\n### Pause and Resume\n\n```python\nfrom kafka import KafkaConsumer, TopicPartition\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\npartition = TopicPartition('my-topic', 0)\n\n# Pause consumption\nconsumer.pause(partition)\n\n# Check paused partitions\npaused = consumer.paused()\nprint(f'Paused partitions: {paused}')\n\n# Resume consumption\nconsumer.resume(partition)\n```\n\n### Get Topic and Partition Information\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(bootstrap_servers='localhost:9092')\n\n# List all topics\ntopics = consumer.topics()\nprint(f'Topics: {topics}')\n\n# Get partitions for a topic\npartitions = consumer.partitions_for_topic('my-topic')\nprint(f'Partitions: {partitions}')\n```\n\n### Close Consumer\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group'\n)\n\n# Process some messages\nfor message in consumer:\n    if should_stop:\n        break\n\n# Close consumer\nconsumer.close()\n```\n\n### Close with Auto Commit\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='localhost:9092',\n    group_id='my-group',\n    enable_auto_commit=False\n)\n\ntry:\n    for message in consumer:\n        process_message(message)\nfinally:\n    # Close and commit offsets\n    consumer.close(autocommit=True)\n```\n\n## Admin Operations\n\n### Creating Admin Client\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(\n    bootstrap_servers='localhost:9092',\n    client_id='admin-client'\n)\n```\n\n### List Topics\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ntopics = admin.list_topics()\nprint(f'Topics: {topics}')\n```\n\n### Create Topics\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import NewTopic\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ntopic = NewTopic(\n    name='my-new-topic',\n    num_partitions=3,\n    replication_factor=1\n)\n\nadmin.create_topics([topic])\n```\n\n### Create Topics with Configuration\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import NewTopic, ConfigResource, ConfigResourceType\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ntopic = NewTopic(\n    name='my-new-topic',\n    num_partitions=3,\n    replication_factor=1,\n    topic_configs={\n        'retention.ms': '86400000',\n        'cleanup.policy': 'delete'\n    }\n)\n\nadmin.create_topics([topic])\n```\n\n### Delete Topics\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\nadmin.delete_topics(['topic-to-delete'])\n```\n\n### Describe Topics\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\nmetadata = admin.describe_topics(['my-topic'])\nprint(metadata)\n```\n\n### Create Partitions\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import NewPartitions\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ntopic_partitions = {\n    'my-topic': NewPartitions(total_count=5)\n}\n\nadmin.create_partitions(topic_partitions)\n```\n\n### Describe Consumer Groups\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ngroups = admin.describe_consumer_groups(['my-group'])\nprint(groups)\n```\n\n### List Consumer Groups\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\ngroups = admin.list_consumer_groups()\nprint(groups)\n```\n\n### List Consumer Group Offsets\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import ConsumerGroupOffsets\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\noffsets = admin.list_consumer_group_offsets('my-group')\nprint(offsets)\n```\n\n### Delete Consumer Groups\n\n```python\nfrom kafka import KafkaAdminClient\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\nadmin.delete_consumer_groups(['my-group'])\n```\n\n### Describe Configs\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import ConfigResource, ConfigResourceType\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\nresource = ConfigResource(ConfigResourceType.TOPIC, 'my-topic')\nconfigs = admin.describe_configs([resource])\nprint(configs)\n```\n\n### Alter Configs\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import ConfigResource, ConfigResourceType\n\nadmin = KafkaAdminClient(bootstrap_servers='localhost:9092')\n\nresource = ConfigResource(\n    ConfigResourceType.TOPIC,\n    'my-topic',\n    configs={'retention.ms': '604800000'}\n)\n\nadmin.alter_configs([resource])\n```\n\n## Security and Authentication\n\n### SSL Configuration\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='kafka:9093',\n    security_protocol='SSL',\n    ssl_check_hostname=True,\n    ssl_cafile='/path/to/ca-cert',\n    ssl_certfile='/path/to/client-cert',\n    ssl_keyfile='/path/to/client-key'\n)\n```\n\n### SSL Consumer\n\n```python\nfrom kafka import KafkaConsumer\n\nconsumer = KafkaConsumer(\n    'my-topic',\n    bootstrap_servers='kafka:9093',\n    group_id='my-group',\n    security_protocol='SSL',\n    ssl_check_hostname=True,\n    ssl_cafile='/path/to/ca-cert',\n    ssl_certfile='/path/to/client-cert',\n    ssl_keyfile='/path/to/client-key'\n)\n```\n\n### SASL PLAIN Authentication\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='kafka:9092',\n    security_protocol='SASL_PLAINTEXT',\n    sasl_mechanism='PLAIN',\n    sasl_plain_username='username',\n    sasl_plain_password='password'\n)\n```\n\n### SASL SCRAM-SHA-256\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='kafka:9092',\n    security_protocol='SASL_SSL',\n    sasl_mechanism='SCRAM-SHA-256',\n    sasl_plain_username='username',\n    sasl_plain_password='password',\n    ssl_cafile='/path/to/ca-cert'\n)\n```\n\n### SASL SCRAM-SHA-512\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='kafka:9092',\n    security_protocol='SASL_SSL',\n    sasl_mechanism='SCRAM-SHA-512',\n    sasl_plain_username='username',\n    sasl_plain_password='password',\n    ssl_cafile='/path/to/ca-cert'\n)\n```\n\n### SSL with SASL\n\n```python\nfrom kafka import KafkaProducer\n\nproducer = KafkaProducer(\n    bootstrap_servers='kafka:9093',\n    security_protocol='SASL_SSL',\n    sasl_mechanism='PLAIN',\n    sasl_plain_username='username',\n    sasl_plain_password='password',\n    ssl_check_hostname=True,\n    ssl_cafile='/path/to/ca-cert'\n)\n```\n\n## Complete Examples\n\n### Complete Producer Example\n\n```python\nimport json\nimport time\nfrom kafka import KafkaProducer\nfrom kafka.errors import KafkaError\n\ndef create_producer():\n    return KafkaProducer(\n        bootstrap_servers=['localhost:9092'],\n        client_id='order-producer',\n        acks='all',\n        retries=5,\n        key_serializer=lambda k: k.encode('utf-8'),\n        value_serializer=lambda v: json.dumps(v).encode('utf-8'),\n        compression_type='gzip'\n    )\n\ndef send_order(producer, order):\n    try:\n        future = producer.send(\n            'orders',\n            key=order['order_id'],\n            value=order,\n            headers=[\n                ('correlation-id', str(time.time()).encode('utf-8')),\n                ('source', b'order-service')\n            ]\n        )\n\n        record_metadata = future.get(timeout=10)\n        print(f\"Order {order['order_id']} sent successfully\")\n        print(f\"  Partition: {record_metadata.partition}\")\n        print(f\"  Offset: {record_metadata.offset}\")\n        return True\n\n    except KafkaError as e:\n        print(f\"Failed to send order {order['order_id']}: {e}\")\n        return False\n\ndef main():\n    producer = create_producer()\n\n    try:\n        orders = [\n            {'order_id': 'order-001', 'amount': 99.99, 'customer': 'customer-123'},\n            {'order_id': 'order-002', 'amount': 149.99, 'customer': 'customer-456'},\n            {'order_id': 'order-003', 'amount': 79.99, 'customer': 'customer-789'}\n        ]\n\n        for order in orders:\n            send_order(producer, order)\n            time.sleep(0.1)\n\n        # Wait for all messages to be sent\n        producer.flush()\n        print(\"All orders sent successfully\")\n\n    except Exception as e:\n        print(f\"Error: {e}\")\n    finally:\n        producer.close()\n\nif __name__ == '__main__':\n    main()\n```\n\n### Complete Consumer Example\n\n```python\nimport json\nimport signal\nimport sys\nfrom kafka import KafkaConsumer\nfrom kafka.errors import KafkaError\n\nclass OrderConsumer:\n    def __init__(self):\n        self.consumer = KafkaConsumer(\n            'orders',\n            bootstrap_servers=['localhost:9092'],\n            group_id='order-processor',\n            client_id='order-consumer',\n            auto_offset_reset='earliest',\n            enable_auto_commit=False,\n            max_poll_records=100,\n            key_deserializer=lambda k: k.decode('utf-8') if k else None,\n            value_deserializer=lambda v: json.loads(v.decode('utf-8'))\n        )\n        self.running = True\n\n        # Handle graceful shutdown\n        signal.signal(signal.SIGINT, self.shutdown)\n        signal.signal(signal.SIGTERM, self.shutdown)\n\n    def shutdown(self, signum, frame):\n        print(\"\\nShutting down consumer...\")\n        self.running = False\n\n    def process_order(self, order):\n        print(f\"Processing order {order['order_id']}\")\n        print(f\"  Customer: {order['customer']}\")\n        print(f\"  Amount: ${order['amount']}\")\n        # Process the order here\n        return True\n\n    def run(self):\n        print(\"Starting order consumer...\")\n\n        try:\n            while self.running:\n                messages = self.consumer.poll(timeout_ms=1000, max_records=10)\n\n                for topic_partition, records in messages.items():\n                    for message in records:\n                        try:\n                            # Get headers\n                            headers = {k: v.decode('utf-8')\n                                     for k, v in message.headers} if message.headers else {}\n\n                            correlation_id = headers.get('correlation-id', 'unknown')\n\n                            print(f\"\\nReceived message (correlation-id: {correlation_id})\")\n                            print(f\"  Partition: {message.partition}\")\n                            print(f\"  Offset: {message.offset}\")\n\n                            # Process the order\n                            if self.process_order(message.value):\n                                print(f\"  Order {message.value['order_id']} processed successfully\")\n\n                        except Exception as e:\n                            print(f\"Error processing message: {e}\")\n\n                    # Commit after processing batch\n                    self.consumer.commit()\n\n        except KafkaError as e:\n            print(f\"Kafka error: {e}\")\n        finally:\n            self.consumer.close()\n            print(\"Consumer closed\")\n\nif __name__ == '__main__':\n    consumer = OrderConsumer()\n    consumer.run()\n```\n\n### Complete Admin Example\n\n```python\nfrom kafka import KafkaAdminClient\nfrom kafka.admin import NewTopic, ConfigResource, ConfigResourceType\nfrom kafka.errors import TopicAlreadyExistsError, KafkaError\n\ndef create_admin_client():\n    return KafkaAdminClient(\n        bootstrap_servers=['localhost:9092'],\n        client_id='admin-client'\n    )\n\ndef create_topic(admin, topic_name, num_partitions=3, replication_factor=1):\n    topic = NewTopic(\n        name=topic_name,\n        num_partitions=num_partitions,\n        replication_factor=replication_factor,\n        topic_configs={\n            'retention.ms': '86400000',  # 1 day\n            'cleanup.policy': 'delete',\n            'compression.type': 'gzip'\n        }\n    )\n\n    try:\n        admin.create_topics([topic], validate_only=False)\n        print(f\"Topic '{topic_name}' created successfully\")\n        return True\n    except TopicAlreadyExistsError:\n        print(f\"Topic '{topic_name}' already exists\")\n        return False\n    except KafkaError as e:\n        print(f\"Failed to create topic '{topic_name}': {e}\")\n        return False\n\ndef list_topics(admin):\n    topics = admin.list_topics()\n    print(f\"Available topics: {topics}\")\n    return topics\n\ndef describe_topic(admin, topic_name):\n    try:\n        metadata = admin.describe_topics([topic_name])\n        print(f\"\\nTopic '{topic_name}' details:\")\n        print(f\"  Metadata: {metadata}\")\n        return metadata\n    except KafkaError as e:\n        print(f\"Failed to describe topic '{topic_name}': {e}\")\n        return None\n\ndef delete_topic(admin, topic_name):\n    try:\n        admin.delete_topics([topic_name])\n        print(f\"Topic '{topic_name}' deleted successfully\")\n        return True\n    except KafkaError as e:\n        print(f\"Failed to delete topic '{topic_name}': {e}\")\n        return False\n\ndef list_consumer_groups(admin):\n    try:\n        groups = admin.list_consumer_groups()\n        print(f\"\\nConsumer groups:\")\n        for group in groups:\n            print(f\"  - {group}\")\n        return groups\n    except KafkaError as e:\n        print(f\"Failed to list consumer groups: {e}\")\n        return []\n\ndef describe_consumer_group(admin, group_id):\n    try:\n        groups = admin.describe_consumer_groups([group_id])\n        print(f\"\\nConsumer group '{group_id}' details:\")\n        for group in groups:\n            print(f\"  {group}\")\n        return groups\n    except KafkaError as e:\n        print(f\"Failed to describe consumer group '{group_id}': {e}\")\n        return None\n\ndef main():\n    admin = create_admin_client()\n\n    try:\n        # List existing topics\n        print(\"=== Listing Topics ===\")\n        list_topics(admin)\n\n        # Create new topic\n        print(\"\\n=== Creating Topic ===\")\n        create_topic(admin, 'orders', num_partitions=3, replication_factor=1)\n\n        # Describe topic\n        print(\"\\n=== Describing Topic ===\")\n        describe_topic(admin, 'orders')\n\n        # List consumer groups\n        print(\"\\n=== Listing Consumer Groups ===\")\n        list_consumer_groups(admin)\n\n    except Exception as e:\n        print(f\"Error: {e}\")\n    finally:\n        admin.close()\n\nif __name__ == '__main__':\n    main()\n```\n\n### Error Handling Example\n\n```python\nimport json\nimport time\nfrom kafka import KafkaProducer, KafkaConsumer\nfrom kafka.errors import (\n    KafkaError,\n    KafkaTimeoutError,\n    NoBrokersAvailable,\n    MessageSizeTooLargeError,\n    UnknownTopicOrPartitionError\n)\n\ndef resilient_producer():\n    max_retries = 3\n    retry_count = 0\n\n    while retry_count < max_retries:\n        try:\n            producer = KafkaProducer(\n                bootstrap_servers=['localhost:9092'],\n                value_serializer=lambda v: json.dumps(v).encode('utf-8'),\n                acks='all',\n                retries=5,\n                max_in_flight_requests_per_connection=1\n            )\n\n            data = {'message': 'Hello Kafka', 'timestamp': time.time()}\n\n            future = producer.send('my-topic', data)\n            record_metadata = future.get(timeout=10)\n\n            print(f\"Message sent successfully to partition {record_metadata.partition}\")\n            producer.close()\n            return True\n\n        except NoBrokersAvailable:\n            print(\"No brokers available. Retrying...\")\n            retry_count += 1\n            time.sleep(2)\n\n        except KafkaTimeoutError:\n            print(\"Request timed out. Retrying...\")\n            retry_count += 1\n            time.sleep(2)\n\n        except MessageSizeTooLargeError:\n            print(\"Message too large. Cannot retry.\")\n            return False\n\n        except UnknownTopicOrPartitionError:\n            print(\"Topic does not exist. Cannot retry.\")\n            return False\n\n        except KafkaError as e:\n            print(f\"Kafka error: {e}\")\n            retry_count += 1\n            time.sleep(2)\n\n    print(\"Max retries exceeded\")\n    return False\n\nif __name__ == '__main__':\n    resilient_producer()\n```\n"
  },
  {
    "path": "content/kedro/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Kedro package guide for Python projects covering project creation, configuration, sessions, and data catalogs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"kedro,python,data-engineering,data-science,pipelines,mlops\"\n---\n\n# Kedro Python Package Guide\n\n## Golden Rule\n\nUse `kedro==1.2.0` on Python 3.10+ and treat `kedro-datasets` as a separate dependency for real dataset connectors. As of March 12, 2026, PyPI lists `kedro 1.2.0` with `Requires: Python >=3.10`; some Kedro docs search snippets still mention Python 3.9+, so use the PyPI metadata as the install floor.\n\n## Install\n\nUse a virtual environment and pin Kedro explicitly:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"kedro==1.2.0\"\n```\n\n`uv` also works:\n\n```bash\nuv venv\nsource .venv/bin/activate\nuv pip install \"kedro==1.2.0\"\n```\n\nUseful extras from PyPI:\n\n```bash\npython -m pip install \"kedro[jupyter]==1.2.0\"\npython -m pip install \"kedro[docs]==1.2.0\"\n```\n\nMost real projects also need dataset implementations from `kedro-datasets`:\n\n```bash\npython -m pip install \"kedro-datasets[pandas]\"\n```\n\nVerify the CLI is available:\n\n```bash\nkedro info\n```\n\n## Create A Project\n\nThe current docs recommend `uvx kedro new` when you want to generate a project without first installing Kedro globally:\n\n```bash\nuvx kedro new --name=spaceflights --tools=lint,test,data --example=y\ncd spaceflights\nuv pip install -r requirements.txt\nkedro run\n```\n\nIf Kedro is already installed in your environment, use the same workflow with `kedro new`:\n\n```bash\nkedro new --name=my-project --tools=lint,test,data --example=n\ncd my-project\npython -m pip install -r requirements.txt\n```\n\nImportant generated project locations:\n\n- `pyproject.toml`: project metadata and Kedro package settings\n- `conf/base/`: shared config such as catalog and parameters\n- `conf/local/`: developer-local overrides and credentials\n- `src/<package_name>/pipeline_registry.py`: registers named pipelines\n- `src/<package_name>/settings.py`: config loader, hooks, and project settings\n\n## Core Workflow\n\n### Add a modular pipeline\n\nCreate a new pipeline scaffold:\n\n```bash\nkedro pipeline create data_processing\n```\n\nMinimal node and pipeline code:\n\n```python\n# src/my_project/pipelines/data_processing/nodes.py\nimport pandas as pd\n\ndef add_total_price(orders: pd.DataFrame) -> pd.DataFrame:\n    enriched = orders.copy()\n    enriched[\"total_price\"] = enriched[\"quantity\"] * enriched[\"unit_price\"]\n    return enriched\n```\n\n```python\n# src/my_project/pipelines/data_processing/pipeline.py\nfrom kedro.pipeline import node, pipeline\n\nfrom .nodes import add_total_price\n\ndef create_pipeline(**kwargs):\n    return pipeline(\n        [\n            node(\n                func=add_total_price,\n                inputs=\"orders\",\n                outputs=\"orders_enriched\",\n                name=\"add_total_price\",\n            )\n        ]\n    )\n```\n\nRegister it so the CLI can run it by name:\n\n```python\n# src/my_project/pipeline_registry.py\nfrom kedro.framework.project import find_pipelines\n\ndef register_pipelines():\n    pipelines = find_pipelines()\n    pipelines[\"__default__\"] = sum(pipelines.values())\n    return pipelines\n```\n\nRun the whole project or a specific pipeline:\n\n```bash\nkedro run\nkedro run --pipeline=data_processing\nkedro run --env=prod\nkedro run --params=batch_size=500,model.random_state=7\nkedro run --runner=ThreadRunner\n```\n\nRunner notes:\n\n- `SequentialRunner` is the default\n- `ParallelRunner` uses multiprocessing\n- `ThreadRunner` is the safer concurrency option when you need threaded I/O and is the documented workaround when `SparkDataset` does not behave well with `ParallelRunner`\n\n### Use Kedro programmatically\n\nWhen you are outside the CLI and want to run or inspect a project from Python, bootstrap the project first:\n\n```python\nfrom pathlib import Path\n\nfrom kedro.framework.session import KedroSession\nfrom kedro.framework.startup import bootstrap_project\n\nproject_path = Path(\"/path/to/your-kedro-project\")\nbootstrap_project(project_path)\n\nwith KedroSession.create(\n    project_path=project_path,\n    env=\"local\",\n    runtime_params={\"sample_size\": 100},\n) as session:\n    context = session.load_context()\n    catalog = context.catalog\n    companies = catalog.load(\"companies\")\n    result = session.run(pipeline_name=\"data_processing\")\n```\n\nUse `bootstrap_project()` for source-tree projects. The Kedro session docs note that packaged projects can use `configure_project()` instead.\n\n## Configuration And Credentials\n\nKedro loads configuration through `OmegaConfigLoader` by default.\n\nThe normal layout is:\n\n```text\nconf/\n  base/\n    catalog.yml\n    parameters.yml\n  local/\n    credentials.yml\n```\n\nKey behavior from the stable configuration docs:\n\n- `conf/base` is the shared default\n- `conf/local` overrides `base`\n- duplicate top-level keys inside the same environment raise a `ValueError`\n- `local` is for user-specific or secret config and should not be committed\n\nExample catalog plus credentials split:\n\n```yaml\n# conf/base/catalog.yml\norders:\n  type: pandas.CSVDataset\n  filepath: data/01_raw/orders.csv\n\nwarehouse_orders:\n  type: pandas.CSVDataset\n  filepath: s3://my-bucket/orders.csv\n  credentials: dev_s3\n```\n\n```yaml\n# conf/local/credentials.yml\ndev_s3:\n  client_kwargs:\n    aws_access_key_id: ${oc.env:AWS_ACCESS_KEY_ID}\n    aws_secret_access_key: ${oc.env:AWS_SECRET_ACCESS_KEY}\n```\n\nImportant constraints:\n\n- `oc.env` is intended for `credentials.yml`; the advanced config docs say not to use it in catalog or parameter files\n- if you set `KEDRO_ENV=prod`, Kedro will load that environment for `kedro run`, `kedro ipython`, and Kedro Jupyter commands\n- `--env=<name>` overrides `KEDRO_ENV`\n- `--conf-source=<path>` lets you load config from another folder, a `.tar.gz`, a `.zip`, or supported remote storage\n\nIf you need direct access in Python, load config first and build a catalog from it:\n\n```python\nfrom pathlib import Path\n\nfrom kedro.config import OmegaConfigLoader\nfrom kedro.framework.project import settings\nfrom kedro.io import DataCatalog\n\nproject_path = Path(\"/path/to/project\")\nconf_path = str(project_path / settings.CONF_SOURCE)\n\nconf_loader = OmegaConfigLoader(\n    conf_source=conf_path,\n    base_env=\"base\",\n    default_run_env=\"local\",\n)\n\ncatalog = DataCatalog.from_config(\n    catalog=conf_loader[\"catalog\"],\n    credentials=conf_loader[\"credentials\"],\n)\n```\n\n## Data Catalog Usage\n\nKedro's `DataCatalog` handles dataset I/O so nodes can stay pure.\n\nProgrammatic catalog construction:\n\n```python\nfrom kedro.io import DataCatalog\nfrom kedro_datasets.pandas import CSVDataset\n\ncatalog = DataCatalog(\n    {\n        \"orders\": CSVDataset(filepath=\"data/01_raw/orders.csv\"),\n        \"orders_enriched\": CSVDataset(filepath=\"data/04_feature/orders_enriched.csv\"),\n    }\n)\n\norders = catalog.load(\"orders\")\ncatalog.save(\"orders_enriched\", orders)\n```\n\nUseful catalog inspection commands in a project:\n\n```bash\nkedro catalog describe-datasets --pipeline=data_processing\nkedro catalog list-patterns\nkedro registry list\nkedro registry describe data_processing\n```\n\nAvoid calling catalog I/O directly inside node functions unless you are deliberately breaking Kedro's pure-function model.\n\n## Common Pitfalls\n\n- Install `kedro-datasets` separately. Since Kedro `0.19.0`, dataset implementations are no longer shipped in core `kedro`.\n- Use the new dataset class names. Since `kedro-datasets 2.0.0`, `CSVDataSet`-style names became `CSVDataset`.\n- Keep secrets in `conf/local/credentials.yml` or environment variables, not in `conf/base`.\n- When multiprocessing re-imports code under `ParallelRunner` on macOS or Windows, project bootstrap/configuration matters. If concurrency is needed and multiprocessing causes trouble, test `ThreadRunner` first.\n- Avoid dots in dataset names unless you intentionally want namespace semantics; the pipeline docs warn that dot notation can produce disconnected or confusing pipelines.\n- Do not perform `catalog.load()` or `catalog.save()` inside normal nodes. Let Kedro inject datasets as node inputs and outputs.\n\n## Version-Sensitive Notes\n\n- Version used here and current PyPI release agree: `1.2.0` was published on January 29, 2026.\n- The stable docs remain the right canonical docs root for review, but some search-indexed Kedro pages still surface older `0.19.x` URLs. Double-check the URL path before copying examples.\n- PyPI metadata currently says `Requires: Python >=3.10`; if you see older install snippets mentioning Python 3.9+, treat those as stale for `1.2.0`.\n- `kedro-datasets` is now a separate package, and modern examples should import classes from `kedro_datasets.*`, not the old in-core dataset modules.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/kedro/\n- Stable docs root: https://docs.kedro.org/en/stable/\n- New project tools: https://docs.kedro.org/en/stable/create/new_project_tools/\n- CLI reference: https://docs.kedro.org/en/stable/getting-started/commands_reference/\n- Configuration basics: https://docs.kedro.org/en/stable/configure/configuration_basics/\n- Advanced configuration: https://docs.kedro.org/en/stable/configure/advanced_configuration/\n- Credentials: https://docs.kedro.org/en/stable/configuration/credentials.html\n- Data catalog usage: https://docs.kedro.org/en/stable/catalog-data/advanced_data_catalog_usage/\n- Data catalog YAML examples: https://docs.kedro.org/en/stable/data/data_catalog_yaml_examples.html\n- KedroSession lifecycle: https://docs.kedro.org/en/stable/kedro_project_setup/session.html\n"
  },
  {
    "path": "content/keras/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Keras 3.13.2 package guide for Python deep learning with TensorFlow, JAX, PyTorch, and OpenVINO backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.13.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"keras,python,deep-learning,machine-learning,tensorflow,jax,pytorch,openvino\"\n---\n\n# Keras Python Package Guide\n\n## What It Is\n\n`keras` is the Keras 3 multi-backend deep learning package for Python. It supports TensorFlow, JAX, and PyTorch as training backends, plus OpenVINO for inference-only workloads.\n\nFor new code:\n\n- use `import keras`, not `from tensorflow import keras`\n- use the Functional API for most non-trivial models\n- use `keras.ops` in custom layers and metrics if you want backend-agnostic code\n\n`keras` does not talk to a remote service and has no API authentication model. The main setup decision is which backend runtime you install and select.\n\n## Install\n\nInstall the Keras package itself:\n\n```bash\npython -m pip install \"keras==3.13.2\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"keras==3.13.2\"\n```\n\nYou must also install at least one backend package. The official Keras package metadata and install docs list these minimum backend versions for the current Keras 3 line:\n\n- TensorFlow: `>=2.16.1`\n- JAX: `>=0.4.20`\n- PyTorch: `>=2.1.0`\n- OpenVINO: `>=2025.3.0` for inference only\n\nCommon installs:\n\n```bash\npython -m pip install \"keras==3.13.2\" \"tensorflow>=2.16.1\"\npython -m pip install \"keras==3.13.2\" \"jax>=0.4.20\"\npython -m pip install \"keras==3.13.2\" \"torch>=2.1.0\"\n```\n\nIf you need legacy Keras 2 behavior, the official package note is that Keras 2 remains available separately as `tf-keras`. Do not assume `keras` is an alias for the old standalone Keras 2 package.\n\n## Backend Selection And Setup\n\nSet the backend before importing `keras`. The official docs are explicit that the backend cannot be changed after import.\n\n```python\nimport os\n\nos.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n\nimport keras\n```\n\nSupported backend names:\n\n- `\"tensorflow\"`\n- `\"jax\"`\n- `\"torch\"`\n- `\"openvino\"`\n\nYou can also configure the backend through `~/.keras/keras.json`, but the environment variable is the safest approach for scripts, tests, notebooks, and agent-generated code because it is explicit in-process.\n\nOpenVINO is inference-only. Use it for `model.predict(...)`, not for training.\n\n## Core Workflow\n\nFor most real projects, start with the Functional API instead of `Sequential`. The official Models API says the Functional API is what most people should be using because it handles arbitrary model graphs, shared layers, and multiple inputs or outputs.\n\n```python\nimport os\n\nos.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n\nimport numpy as np\nimport keras\nfrom keras import layers\n\ninputs = keras.Input(shape=(20,), name=\"features\")\nx = layers.Dense(64, activation=\"relu\")(inputs)\nx = layers.Dropout(0.2)(x)\noutputs = layers.Dense(3, activation=\"softmax\", name=\"label\")(x)\n\nmodel = keras.Model(inputs=inputs, outputs=outputs)\n\nmodel.compile(\n    optimizer=\"adam\",\n    loss=\"sparse_categorical_crossentropy\",\n    metrics=[\"accuracy\"],\n)\n\nx_train = np.random.random((256, 20)).astype(\"float32\")\ny_train = np.random.randint(0, 3, size=(256,))\n\nhistory = model.fit(\n    x_train,\n    y_train,\n    batch_size=32,\n    epochs=5,\n    validation_split=0.2,\n)\n\neval_metrics = model.evaluate(x_train, y_train, verbose=0)\npredictions = model.predict(x_train[:5], verbose=0)\n```\n\nThe standard built-in workflow is:\n\n1. Define a model.\n2. `compile(...)` with optimizer, loss, and metrics.\n3. `fit(...)` on NumPy arrays, `tf.data.Dataset`, or other supported dataset-style inputs.\n4. `evaluate(...)` on held-out data.\n5. `predict(...)` for inference.\n\nUseful training notes from the official guides:\n\n- `validation_split` only works with NumPy array inputs\n- `tf.data.Dataset` can be passed directly to `fit()`, `evaluate()`, and `predict()`\n- use callbacks such as `keras.callbacks.EarlyStopping(...)` and `keras.callbacks.ModelCheckpoint(...)` for real training jobs\n- `class_weight` and `sample_weight` are first-class `fit(...)` inputs\n\n## When To Use `Sequential`, Functional API, Or Subclassing\n\n- Use `keras.Sequential([...])` only for straight single-input, single-output stacks.\n- Use the Functional API for most application code.\n- Subclass `keras.Model` only when the model cannot be expressed as a DAG of layers or when you need custom training behavior.\n\nIf you expect to save, inspect, plot, or reuse parts of the model graph, the Functional API is usually the best default.\n\n## Backend-Agnostic Custom Code\n\nKeras 3 will run TensorFlow-specific code when the backend is TensorFlow, but cross-backend code should prefer Keras namespaces:\n\n- `keras.layers` for layers\n- `keras.ops` instead of raw `tf.*` ops in symbolic model-building code\n- `keras.random` for backend-agnostic random operations\n\nExample:\n\n```python\nimport keras\n\ninputs = keras.layers.Input(shape=(2, 2, 1))\noutputs = keras.ops.squeeze(inputs, axis=-1)\nmodel = keras.Model(inputs, outputs)\n```\n\nThis pattern matters if you want the same layer, metric, or model code to run on JAX, TensorFlow, and PyTorch.\n\n## Saving, Loading, And Export\n\nKeras 3 changed the default persistence story. The official saving guide says the only supported native `model.save()` format in Keras 3 is the `.keras` format.\n\nSave and reload a full model:\n\n```python\nmodel.save(\"classifier.keras\")\n\nrestored = keras.models.load_model(\"classifier.keras\")\n```\n\nImportant Keras 3 rules:\n\n- `model.save(\"my_model.keras\")` is the preferred full-model save path\n- legacy `.h5` is still supported, but `.keras` is the current native format\n- `model.save(\"saved_model\")` no longer writes a TensorFlow SavedModel directory\n- use `model.export(\"saved_model\")` when you specifically need TensorFlow SavedModel output for TF Serving, TFLite, or similar tooling\n\nIf you need to consume an existing TensorFlow SavedModel inside Keras 3, `keras.models.load_model()` will not load it. The migration guide says to use `keras.layers.TFSMLayer(...)` for inference-only loading:\n\n```python\nlayer = keras.layers.TFSMLayer(\n    \"saved_model\",\n    call_endpoint=\"serving_default\",\n)\n```\n\nFor custom layers, activations, or models that need robust round-tripping, prefer registering them:\n\n```python\n@keras.saving.register_keras_serializable(package=\"MyProject\")\nclass MyLayer(keras.layers.Layer):\n    ...\n```\n\nThat avoids brittle `custom_objects={...}` loading paths.\n\n## Configuration And Environment\n\nKeras has no auth configuration. Focus on runtime configuration:\n\n- backend choice via `KERAS_BACKEND`\n- backend package version compatibility\n- CPU vs GPU environment isolation\n- checkpoint and model file paths\n\nThe upstream install notes recommend a clean Python environment per backend when working with CUDA-enabled stacks to avoid dependency conflicts.\n\nOfficial install guidance also says Keras 3 is compatible with Linux and macOS, and recommends WSL2 for Windows users.\n\n## Common Pitfalls\n\n- **Importing `tf.keras` in new Keras 3 code:** replace `from tensorflow import keras` and `tf.keras.*` usage with `import keras` and `keras.*`.\n- **Forgetting to install a backend:** `pip install keras` alone is not enough for training.\n- **Setting `KERAS_BACKEND` too late:** choose the backend before `import keras`.\n- **Trying to switch backends mid-process:** the official docs say you cannot change backend after import.\n- **Using raw TensorFlow ops on `KerasTensor` objects during Functional API graph construction:** use `keras.ops` equivalents instead.\n- **Assuming deep nested input structures still work:** Keras 3 disallows inputs and outputs nested more than one level deep in Functional models.\n- **Passing `None` inside nested `call()` tensor arguments or returns:** Keras 3 disallows this; make optional values separate arguments instead.\n- **Hitting XLA errors on GPU with TensorFlow backend:** Keras 3 sets `jit_compile=True` by default on GPU. If a custom layer or model uses unsupported ops, compile with `jit_compile=False`.\n- **Using `model.save(\"dir\")` expecting a TensorFlow SavedModel:** use `.keras` for native save or `model.export(...)` for SavedModel export.\n- **Trying to load a SavedModel with `keras.models.load_model(...)`:** use `keras.layers.TFSMLayer(...)` instead.\n- **Expecting per-output losses from `evaluate()` automatically in multi-output models:** provide explicit metrics in `compile(...)`.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `keras 3.13.2` with Python requirement `>=3.11`.\n- The Keras 3 API docs are current-maintainer docs rather than per-patch frozen docs, so examples here are aligned to the Keras 3 line, not a patch-specific rendered manual.\n- The official package description says Keras 2 remains available as `tf-keras`. That is the clearest escape hatch if a project is pinned to pre-Keras-3 behavior.\n- OpenVINO is supported as an inference-only backend, not a training backend.\n- If you are migrating TensorFlow-first code and want cross-backend portability, replacing `tf.*` calls with `keras.ops.*` is one of the highest-value changes.\n\n## Official Sources\n\n- Keras API root: https://keras.io/api/\n- Keras getting started: https://keras.io/getting_started/\n- Keras Models API: https://keras.io/api/models/\n- Keras training guide: https://keras.io/guides/training_with_built_in_methods/\n- Keras Functional API guide: https://keras.io/guides/functional_api/\n- Keras saving guide: https://keras.io/guides/serialization_and_saving/\n- Keras migration guide: https://keras.io/guides/migrating_to_keras_3/\n- PyPI package page: https://pypi.org/project/keras/\n"
  },
  {
    "path": "content/kombu/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"kombu package guide for Python - broker connections, producers, consumers, transports, and retries\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.6.2\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"kombu,messaging,amqp,rabbitmq,redis,sqs,queues\"\n---\n\n# kombu Python Package Guide\n\n## What It Is\n\n`kombu` is the low-level messaging library used by Celery. Use it when you need direct broker access in Python without adopting Celery's task layer.\n\nThe core objects are:\n\n- `Connection` for broker and transport connectivity\n- `Exchange` and `Queue` for routing\n- `Producer` for publishing\n- `Consumer` for receiving and acknowledging messages\n- `SimpleQueue` for the quickest request/response or one-queue workflows\n\nIf you only need a task queue, use Celery. If you need broker-aware application code, transport-specific setup, or explicit publish/consume control, use `kombu`.\n\n## Install\n\nUse the version used here unless the project already pins another compatible release:\n\n```bash\npython -m pip install \"kombu==5.6.2\"\n```\n\nFor lockfile-based projects:\n\n```bash\nuv add \"kombu==5.6.2\"\npoetry add \"kombu==5.6.2\"\n```\n\nAMQP works with Kombu's standard dependencies. Other transports can require transport-specific client libraries and configuration in the host application environment.\n\n## Initialization And Broker Setup\n\n`Connection` is lazy. Creating it does not open the socket yet. Errors usually appear on `connect()`, `drain_events()`, channel creation, or publish/consume operations.\n\n### Common broker URLs\n\n```python\nfrom kombu import Connection\n\n# RabbitMQ / AMQP\namqp = Connection(\"amqp://guest:guest@localhost:5672//\")\n\n# Redis transport\nredis = Connection(\"redis://localhost:6379/0\")\n\n# Amazon SQS transport\nsqs = Connection(\n    \"sqs://\",\n    transport_options={\"region\": \"us-east-1\"},\n)\n\n# In-memory transport for single-process tests\nmemory = Connection(\"memory://\")\n```\n\nUse a context manager so channels and sockets close cleanly:\n\n```python\nfrom kombu import Connection\n\nwith Connection(\"amqp://guest:guest@localhost:5672//\", heartbeat=30) as conn:\n    conn.connect()\n    print(conn.connected)\n```\n\n### Keep configuration outside code\n\n```python\nimport os\n\nfrom kombu import Connection\n\nbroker_url = os.environ[\"BROKER_URL\"]\n\ntransport_options = {}\nif broker_url.startswith(\"sqs://\"):\n    transport_options[\"region\"] = os.getenv(\"AWS_REGION\", \"us-east-1\")\n\nwith Connection(broker_url, transport_options=transport_options) as conn:\n    conn.connect()\n```\n\nFor SQS, upstream Celery docs recommend either IAM/environment credentials with `sqs://` or carefully URL-encoding credentials if you embed them in the URL. Prefer IAM roles or environment-based auth over hardcoding secrets.\n\n### SSL and transport options\n\nPass broker-specific TLS and transport configuration at connection creation time:\n\n```python\nimport ssl\n\nfrom kombu import Connection\n\nconn = Connection(\n    \"amqps://user:password@broker.example.com:5671//\",\n    ssl={\"cert_reqs\": ssl.CERT_REQUIRED},\n    heartbeat=30,\n)\n```\n\nKeep `transport_options` close to the broker URL. Redis, SQS, AMQP, and virtual transports do not share the same options.\n\n## Publish Messages\n\nThe normal pattern is:\n\n1. Create an `Exchange`\n2. Create a `Queue`\n3. Declare them on a channel\n4. Publish with an explicit serializer and retry policy\n\n```python\nfrom kombu import Connection, Exchange, Producer, Queue\n\nexchange = Exchange(\"tasks\", type=\"direct\")\nqueue = Queue(\"tasks\", exchange=exchange, routing_key=\"tasks.process\")\n\nwith Connection(\"amqp://guest:guest@localhost:5672//\") as conn:\n    with conn.channel() as channel:\n        producer = Producer(channel, exchange=exchange, routing_key=\"tasks.process\")\n\n        producer.publish(\n            {\"task\": \"resize-image\", \"image_id\": 42},\n            serializer=\"json\",\n            declare=[queue],\n            retry=True,\n            retry_policy={\n                \"max_retries\": 3,\n                \"interval_start\": 0,\n                \"interval_step\": 0.5,\n                \"interval_max\": 2,\n            },\n        )\n```\n\nUse `serializer=\"json\"` unless you have a specific interoperability reason not to. Kombu's serializer docs explicitly treat pickle and YAML as disabled by default because of security risk.\n\n## Consume Messages\n\nFor durable workers:\n\n- set `accept` explicitly\n- `ack()` only after successful processing\n- use `reject()` or let the broker retry according to your queue semantics\n- set `prefetch_count` deliberately instead of accepting the default\n\n```python\nfrom kombu import Connection, Consumer, Exchange, Queue\n\nexchange = Exchange(\"tasks\", type=\"direct\")\nqueue = Queue(\"tasks\", exchange=exchange, routing_key=\"tasks.process\")\n\ndef handle_message(body, message):\n    try:\n        print(\"received\", body)\n        message.ack()\n    except Exception:\n        message.reject()\n        raise\n\nwith Connection(\"amqp://guest:guest@localhost:5672//\", heartbeat=30) as conn:\n    with Consumer(\n        conn,\n        queues=[queue],\n        callbacks=[handle_message],\n        accept=[\"json\"],\n        prefetch_count=10,\n    ):\n        while True:\n            conn.drain_events(timeout=1)\n            conn.heartbeat_check()\n```\n\nIf you are building a long-running worker process, upstream docs recommend `ConsumerMixin` instead of hand-writing the lifecycle loop each time.\n\n## Fastest Working API: `SimpleQueue`\n\nUse `SimpleQueue` when you only need one queue and do not need custom routing yet.\n\n```python\nfrom kombu import Connection\n\nwith Connection(\"amqp://guest:guest@localhost:5672//\") as conn:\n    simple_queue = conn.SimpleQueue(\"demo\")\n    try:\n        simple_queue.put({\"hello\": \"world\"}, serializer=\"json\")\n\n        message = simple_queue.get(block=True, timeout=5)\n        print(message.payload)\n        message.ack()\n    finally:\n        simple_queue.close()\n```\n\nThis is the quickest path for scripts, smoke tests, and integration tests. Move to explicit `Exchange` and `Queue` objects once routing or broker topology matters.\n\n## Retry, Failover, And Pools\n\n### Multiple broker URLs\n\n```python\nfrom kombu import Connection\n\nconn = Connection(\n    [\n        \"amqp://guest:guest@rabbitmq-a:5672//\",\n        \"amqp://guest:guest@rabbitmq-b:5672//\",\n    ],\n    failover_strategy=\"round-robin\",\n)\n```\n\n### Retry a broker operation with `ensure`\n\n```python\nfrom kombu import Connection, Exchange, Producer\n\nexchange = Exchange(\"events\", type=\"fanout\")\n\nwith Connection(\"amqp://guest:guest@localhost:5672//\") as conn:\n    with conn.channel() as channel:\n        producer = Producer(channel, exchange=exchange)\n        safe_publish = conn.ensure(\n            producer,\n            producer.publish,\n            max_retries=3,\n        )\n\n        safe_publish({\"event\": \"started\"}, serializer=\"json\")\n```\n\n### Reuse pooled connections\n\n```python\nfrom kombu import Connection\n\nconn = Connection(\"amqp://guest:guest@localhost:5672//\")\npool = conn.Pool(limit=10)\n\nwith pool.acquire(block=True) as pooled_conn:\n    pooled_conn.connect()\n    print(\"pooled connection ready\")\n```\n\nUse retries for network and broker availability failures. Do not bury application-level validation errors inside retry loops.\n\n## Serialization And Message Safety\n\nUpstream Kombu docs default to safe serializers:\n\n- JSON is the right default for most application code\n- binary payloads should be sent as raw bytes or explicitly encoded\n- pickle, YAML, and msgpack are disabled by default unless you enable insecure serializers\n\nExamples:\n\n```python\nproducer.publish({\"ok\": True}, serializer=\"json\")\nproducer.publish(b\"raw-bytes\", content_type=\"application/octet-stream\", content_encoding=\"binary\")\n```\n\nIf you need non-JSON serializers, enable them intentionally and keep the consumer `accept` list in sync.\n\n## Common Pitfalls\n\n- Constructing `Connection(...)` does not prove the broker is reachable. Call `connect()` or perform a real broker operation.\n- `drain_events()` blocks until a message arrives or the timeout expires. Wrap it in retry and shutdown handling for worker processes.\n- If you set a heartbeat on the connection, call `heartbeat_check()` regularly inside manual consume loops.\n- Do not rely on broad serializer defaults. Set `serializer=` on publish and `accept=` on consume.\n- `SimpleQueue` is convenient but limited. Do not use it when you need exchange types, routing keys, or broker topology control.\n- Keep broker credentials out of source files. Use environment variables, secrets managers, or platform credentials.\n- Transport options are transport-specific. A Redis option copied into an SQS or AMQP connection will not do what you expect.\n\n## Version-Sensitive Notes For 5.6.x\n\n- The docs URL `https://kombu.readthedocs.io/en/latest/` is a rolling docs entry point. For `5.6.2`, prefer the `stable` docs pages plus the `5.6.2` PyPI release page when you need version-pinned behavior.\n- The 5.6 changelog adds `max_prefetch` support to QoS so workers can restore a configured prefetch ceiling after temporary reductions.\n- The Redis transport in 5.6 respects `polling_interval` from `transport_options`, which matters for busy polling loops and latency tuning.\n- Kombu 5.5 introduced native delayed delivery queue support for RabbitMQ quorum queues. The changelog notes that direct exchanges are not supported for that path.\n- Kombu 5.6 also formalizes the Python 3.9+ baseline. Do not copy older Python 3.8-era examples forward unchanged.\n\n## Official Sources Used\n\n- Stable docs root: https://docs.celeryq.dev/projects/kombu/en/stable/\n- Connections guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/connections.html\n- Producers guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/producers.html\n- Consumers guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/consumers.html\n- Simple interface guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/simple.html\n- Pools guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/pools.html\n- Serialization guide: https://docs.celeryq.dev/projects/kombu/en/stable/userguide/serialization.html\n- Changelog: https://docs.celeryq.dev/projects/kombu/en/stable/changelog.html\n- PyPI release page: https://pypi.org/project/kombu/5.6.2/\n- Celery SQS broker auth notes: https://docs.celeryq.dev/en/main/getting-started/backends-and-brokers/sqs.html\n"
  },
  {
    "path": "content/kornia/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Kornia Python package guide for differentiable computer vision and image augmentation with PyTorch tensors\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"kornia,pytorch,computer-vision,image-processing,augmentation,deep-learning\"\n---\n\n# Kornia Python Package Guide\n\n## Golden Rule\n\nUse `kornia` as a PyTorch-first computer vision library. Install a compatible `torch` build first, keep image tensors in channels-first layout, and check dtype and value range before composing color, geometry, or augmentation operators.\n\n## Install\n\nInstall a matching PyTorch build first, then pin Kornia:\n\n```bash\npython -m pip install \"kornia==0.8.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"kornia==0.8.2\"\npoetry add \"kornia==0.8.2\"\n```\n\nOptional Rust-backed image I/O:\n\n```bash\npython -m pip install \"kornia_rs\"\n```\n\nThe official `kornia.io` docs note that `kornia_rs` is a separate install and currently Linux-only.\n\nVerify the installed version:\n\n```python\nimport kornia\n\nprint(kornia.__version__)\n```\n\n## Setup\n\nKornia does not use API keys or service configuration. The important runtime setup is:\n\n- install the correct `torch` wheel for your CPU or CUDA environment before adding Kornia\n- keep tensors and models on the same device\n- use channels-first image layout: `(C, H, W)` or `(B, C, H, W)`\n- check dtype and value range before applying operators\n\nTypical starter setup:\n\n```python\nimport torch\nimport kornia\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nimages = torch.rand(4, 3, 256, 256, device=device)  # BCHW, float32, [0, 1]\n```\n\n## Core Usage\n\n### Geometry and color transforms\n\nMost Kornia operators work directly on PyTorch tensors and stay differentiable.\n\n```python\nimport torch\nfrom kornia.color import rgb_to_grayscale\nfrom kornia.geometry.transform import resize\n\nimages = torch.rand(2, 3, 256, 256)\n\nsmaller = resize(images, (128, 128), antialias=True)\ngray = rgb_to_grayscale(smaller)\n\nprint(smaller.shape)  # (2, 3, 128, 128)\nprint(gray.shape)     # (2, 1, 128, 128)\n```\n\nUse Kornia operators inside normal PyTorch modules when you want gradients to flow through preprocessing or geometric transformations.\n\n### Build augmentation pipelines\n\n`kornia.augmentation` provides module-style augmentations that fit naturally into training code.\n\n```python\nimport torch\nimport kornia.augmentation as K\n\naug = K.AugmentationSequential(\n    K.RandomHorizontalFlip(p=0.5),\n    K.RandomAffine(degrees=15.0, p=0.5),\n    data_keys=[\"input\"],\n    same_on_batch=False,\n)\n\nimages = torch.rand(8, 3, 224, 224)\naugmented = aug(images)\n```\n\nUse `same_on_batch=True` only when every sample in the batch should receive the same random transform.\n\n### Load images with `kornia_rs`\n\nIf you install `kornia_rs`, the `kornia.io` helpers can decode directly to tensors:\n\n```python\nimport kornia as K\nfrom kornia.io import ImageLoadType\n\nimage = K.io.load_image(\"cat.png\", ImageLoadType.RGB32, device=\"cpu\")\nbatch = image.unsqueeze(0)\n\nprint(image.shape)  # (3, H, W)\nprint(image.dtype)  # torch.float32 in [0, 1]\n```\n\nUse `ImageLoadType.RGB8` or `GRAY8` when you explicitly want `uint8` tensors in `[0, 255]`.\n\n### Convert between NumPy-style images and tensors\n\nKornia also exposes helpers for moving between HWC NumPy arrays and channels-first tensors:\n\n```python\nimport numpy as np\nfrom kornia.image import image_to_tensor, tensor_to_image\n\nnp_image = np.zeros((64, 64, 3), dtype=np.uint8)\ntensor = image_to_tensor(np_image, keepdim=False)  # (1, 3, 64, 64)\nround_trip = tensor_to_image(tensor)\n\nprint(tensor.shape)\nprint(round_trip.shape)\n```\n\nThis is useful at dataset boundaries. Stay in tensor form after conversion if you want Kornia ops to remain differentiable.\n\n## Configuration Notes\n\n- No auth or credentials are required.\n- The biggest configuration choice is your PyTorch runtime: CPU-only vs CUDA/MPS build, plus matching device placement in code.\n- Kornia examples and most operator docs assume tensor inputs, not PIL images.\n- Prefer explicit module imports such as `kornia.augmentation`, `kornia.color`, `kornia.geometry.transform`, `kornia.io`, and `kornia.image` instead of guessing top-level aliases.\n\n## Common Pitfalls\n\n- Install `torch` first. Kornia depends on PyTorch and follows its device and dtype rules.\n- Do not pass HWC arrays directly into tensor operators. Convert to `(C, H, W)` or `(B, C, H, W)` first.\n- Watch value ranges. Many image functions expect float tensors in `[0, 1]`, while some I/O helpers can return `uint8` in `[0, 255]`.\n- `kornia.io` is optional. If `kornia_rs` is not installed, do not assume `K.io.load_image(...)` is available in every environment.\n- Mixing CPU tensors, CUDA tensors, or mismatched dtypes inside one pipeline will fail just like ordinary PyTorch code.\n- Converting tensors back to NumPy for intermediate processing breaks gradient flow and often creates unnecessary host-device copies.\n\n## Version-Sensitive Notes For 0.8.2\n\n- As of March 12, 2026, PyPI lists `kornia 0.8.2`, so the version used here matches the current package release.\n- The docs URL `https://kornia.readthedocs.io/en/latest/` currently resolves to the same 0.8.2 documentation surfaced under the stable docs tree, so `https://kornia.readthedocs.io/en/stable/` is the cleaner canonical root for this doc.\n- The latest landing pages advertise newer multi-framework helpers such as `to_numpy()`, `to_tensorflow()`, and `to_jax()`, but the core installation and operator docs for `0.8.2` still center on PyTorch tensors. For coding agents, PyTorch-first usage is still the safest default.\n- The official `kornia.io` page still documents `kornia_rs` as a separate package with Linux-only support, so treat Rust-backed file I/O as optional rather than a baseline assumption.\n\n## Official Sources\n\n- PyPI package: `https://pypi.org/project/kornia/`\n- PyPI JSON metadata: `https://pypi.org/pypi/kornia/json`\n- Docs root: `https://kornia.readthedocs.io/en/latest/`\n- Canonical docs root used here: `https://kornia.readthedocs.io/en/stable/`\n- Introduction: `https://kornia.readthedocs.io/en/stable/get-started/introduction.html`\n- Installation: `https://kornia.readthedocs.io/en/stable/get-started/installation.html`\n- Augmentations: `https://kornia.readthedocs.io/en/stable/applications/image_augmentations.html`\n- Image I/O: `https://kornia.readthedocs.io/en/stable/io.html`\n- Image conversion helpers: `https://kornia.readthedocs.io/en/stable/image.html`\n- GitHub releases: `https://github.com/kornia/kornia/releases`\n"
  },
  {
    "path": "content/kubernetes/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Kubernetes Python client for cluster API access, watches, exec and attach, YAML apply helpers, and custom resources\"\nmetadata:\n  languages: \"python\"\n  versions: \"35.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"kubernetes,k8s,python,cluster,containers,watch,custom-resources\"\n---\n\n# Kubernetes Python Client Package Guide\n\n## Golden Rule\n\nUse the official `kubernetes` package, load configuration before creating API objects, and keep the client version aligned with the cluster minor version when possible. For this package line, `35.y.z` maps to Kubernetes `1.35`. For exec, attach, or port-forward style calls, use `kubernetes.stream.stream(...)` instead of calling the generated method directly, and recreate the API client afterward because the stream helper changes the transport layer.\n\n## Install\n\nPin the client version explicitly when you need predictable generated API behavior:\n\n```bash\npython -m pip install \"kubernetes==35.0.0\"\nuv add \"kubernetes==35.0.0\"\npoetry add \"kubernetes==35.0.0\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"kubernetes[google-auth]==35.0.0\"\npython -m pip install \"kubernetes[adal]==35.0.0\"\n```\n\nUse those extras only if your kubeconfig or environment relies on those auth providers.\n\n## Authentication And Setup\n\n### Load local kubeconfig\n\nUse this for development machines, CI jobs with a kubeconfig file, or admin scripts running outside the cluster:\n\n```python\nfrom kubernetes import client, config\n\nconfig.load_kube_config(context=\"my-context\")\n\ncore = client.CoreV1Api()\nfor namespace in core.list_namespace().items:\n    print(namespace.metadata.name)\n```\n\nPass `context=...` when the current kubeconfig context is not the one you want to target.\n\n### Load in-cluster credentials\n\nUse this only from code running inside Kubernetes with a mounted service account token and CA bundle:\n\n```python\nfrom kubernetes import client, config\n\nconfig.load_incluster_config()\n\ncore = client.CoreV1Api()\npod = core.read_namespaced_pod(name=\"my-pod\", namespace=\"default\")\nprint(pod.metadata.name)\n```\n\n### Configure the API client directly\n\nUse explicit configuration when you are not using kubeconfig or in-cluster auth:\n\n```python\nfrom kubernetes import client\n\ncfg = client.Configuration()\ncfg.host = \"https://my-api-server:6443\"\ncfg.api_key = {\"authorization\": \"YOUR_TOKEN\"}\ncfg.api_key_prefix = {\"authorization\": \"Bearer\"}\ncfg.ssl_ca_cert = \"/path/to/cluster-ca.crt\"\n\napi_client = client.ApiClient(cfg)\ncore = client.CoreV1Api(api_client)\n```\n\nPrefer a real cluster CA certificate over disabling TLS verification.\n\n## Core Usage\n\n### List pods in a namespace\n\n```python\nfrom kubernetes import client, config\n\nconfig.load_kube_config()\ncore = client.CoreV1Api()\n\npods = core.list_namespaced_pod(namespace=\"default\")\nfor pod in pods.items:\n    print(pod.metadata.name, pod.status.phase)\n```\n\n### Create a deployment with the typed API\n\nGenerated API groups are versioned. Use the matching class such as `AppsV1Api`, `BatchV1Api`, or `NetworkingV1Api` instead of looking for a generic API surface.\n\n```python\nfrom kubernetes import client, config\n\nconfig.load_kube_config()\napps = client.AppsV1Api()\n\ndeployment = client.V1Deployment(\n    metadata=client.V1ObjectMeta(name=\"demo\"),\n    spec=client.V1DeploymentSpec(\n        replicas=1,\n        selector=client.V1LabelSelector(match_labels={\"app\": \"demo\"}),\n        template=client.V1PodTemplateSpec(\n            metadata=client.V1ObjectMeta(labels={\"app\": \"demo\"}),\n            spec=client.V1PodSpec(\n                containers=[\n                    client.V1Container(\n                        name=\"demo\",\n                        image=\"nginx:1.27\",\n                        ports=[client.V1ContainerPort(container_port=80)],\n                    )\n                ]\n            ),\n        ),\n    ),\n)\n\napps.create_namespaced_deployment(namespace=\"default\", body=deployment)\n```\n\n### Watch for changes\n\nUse `watch.Watch().stream(...)` for event streams rather than polling list endpoints in a loop:\n\n```python\nfrom kubernetes import client, config, watch\n\nconfig.load_kube_config()\ncore = client.CoreV1Api()\nw = watch.Watch()\n\nfor event in w.stream(core.list_namespaced_pod, namespace=\"default\", timeout_seconds=30):\n    obj = event[\"object\"]\n    print(event[\"type\"], obj.metadata.name, obj.status.phase)\n```\n\nAlways set `timeout_seconds` or stop the watcher explicitly.\n\n### Work with CRDs through `CustomObjectsApi`\n\nCustom resources are usually handled as dictionaries, not generated model classes:\n\n```python\nfrom kubernetes import client, config\n\nconfig.load_kube_config()\ncustom = client.CustomObjectsApi()\n\nwidget = custom.get_namespaced_custom_object(\n    group=\"example.com\",\n    version=\"v1\",\n    namespace=\"default\",\n    plural=\"widgets\",\n    name=\"widget-1\",\n)\n\nprint(widget[\"metadata\"][\"name\"])\n```\n\nThis is the normal path for CRDs unless you generate and maintain your own typed client.\n\n### Apply YAML manifests\n\nUse the helper in `kubernetes.utils` when you want the client to create resources from an existing YAML file:\n\n```python\nfrom kubernetes import client, config, utils\n\nconfig.load_kube_config()\napi_client = client.ApiClient()\n\nutils.create_from_yaml(\n    api_client,\n    \"manifests/demo.yaml\",\n    namespace=\"default\",\n)\n```\n\nIf the manifest contains cluster-scoped resources, do not force a namespace argument onto all objects.\n\n### Exec into a pod\n\nUse `stream(...)` around the generated exec method:\n\n```python\nfrom kubernetes import client, config\nfrom kubernetes.stream import stream\n\nconfig.load_kube_config()\ncore = client.CoreV1Api()\n\noutput = stream(\n    core.connect_get_namespaced_pod_exec,\n    \"example-pod\",\n    \"default\",\n    command=[\"/bin/sh\", \"-c\", \"echo hello\"],\n    stderr=True,\n    stdin=False,\n    stdout=True,\n    tty=False,\n)\n\nprint(output)\n```\n\nAfter using `stream(...)`, recreate the API object before making normal API calls:\n\n```python\ncore = client.CoreV1Api()\n```\n\n## Error Handling\n\nThe client raises `kubernetes.client.exceptions.ApiException` for API failures:\n\n```python\nfrom kubernetes import client, config\nfrom kubernetes.client.exceptions import ApiException\n\nconfig.load_kube_config()\ncore = client.CoreV1Api()\n\ntry:\n    core.read_namespaced_pod(\"missing-pod\", \"default\")\nexcept ApiException as exc:\n    if exc.status == 404:\n        print(\"pod not found\")\n    else:\n        raise\n```\n\nFor debugging, inspect `exc.status`, `exc.reason`, and `exc.body`.\n\n## Configuration And Auth Notes\n\n- `load_kube_config()` is the normal out-of-cluster path; `load_incluster_config()` is the normal in-cluster path.\n- Service account RBAC still applies in-cluster. A mounted token does not bypass namespace or resource permissions.\n- Kubeconfig auth flows may depend on optional extras such as `google-auth` or `adal`, or on external exec credential plugins installed separately on the machine.\n- TLS failures are usually a real config problem. Fix the host name, CA bundle, or dependency mismatch rather than turning off verification.\n- If you need separate credentials or clusters in one process, create separate `client.Configuration()` and `client.ApiClient()` instances instead of assuming a single global default is safe for all call sites.\n\n## Common Pitfalls\n\n- Client and cluster minors are not interchangeable. `35.y.z` is the exact match for Kubernetes `1.35`; other nearby minors are only partial matches in the upstream compatibility table.\n- For exec or attach, calling the generated method directly is wrong. Wrap it with `stream(...)`.\n- After `stream(...)`, reuse of the same API client can break ordinary operations because the helper changes the protocol handling.\n- Watches do not end on their own in long-running processes. Set timeouts and restart loops deliberately.\n- CRDs do not magically show up as generated Python classes. Use `CustomObjectsApi` unless you maintain your own generated client for that API group.\n- Upstream troubleshooting still calls out `ssl.CertificateError` host mismatches when older dependency combinations are in play, especially around `ipaddress` and `urllib3`.\n- On macOS, older system Python and OpenSSL setups can cause SSL problems. Use a supported Python build if TLS behavior looks inconsistent.\n\n## Version-Sensitive Notes For `35.0.0`\n\n- PyPI lists `35.0.0` as a stable release published on `2026-01-16`.\n- The upstream compatibility matrix marks `35.y.z` as the exact match for Kubernetes `1.35`, with `34.y.z` and `36.y.z` shown as partial matches around that line.\n- The project README still documents the `stream(...)` transport mutation caveat, so treat it as current behavior for this version.\n- The generated docs root for this release line is `https://kubernetes.readthedocs.io/en/stable/`.\n\n## Official Sources\n\n- Repository and README: `https://github.com/kubernetes-client/python`\n- PyPI package metadata: `https://pypi.org/project/kubernetes/`\n- Generated docs root: `https://kubernetes.readthedocs.io/en/stable/`\n- Config docs: `https://kubernetes.readthedocs.io/en/stable/kubernetes.config.html`\n- Utils docs: `https://kubernetes.readthedocs.io/en/stable/kubernetes.utils.html`\n- Watch docs: `https://kubernetes.readthedocs.io/en/stable/kubernetes.watch.html`\n- Exec example: `https://github.com/kubernetes-client/python/blob/master/examples/pod_exec.py`\n"
  },
  {
    "path": "content/lancedb/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"lancedb package guide for Python with local and cloud connections, schema definition, vector search, filtering, and indexing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"lancedb,python,vector-database,vector-search,embeddings,arrow,pydantic,rag\"\n---\n\n# lancedb Python Package Guide\n\n## Golden Rule\n\n- Use `lancedb` as an embedded or remote database handle, then work through tables.\n- For local development, connect to a filesystem path first. For hosted deployments, use a `db://...` URI with an API key and region.\n- Define schema up front for production use, especially vector dimensions and embedding behavior.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `0.29.2`.\n- PyPI currently lists `0.29.2` as the latest release for `lancedb`.\n- PyPI metadata for `0.29.2` requires Python `>=3.10`.\n- The main docs site is version-light and currently lives under `/docs/v0/`, so use PyPI for exact package pinning and the docs site for current 0.x usage patterns.\n\n## Install\n\nPin the package when you need reproducible behavior:\n\n```bash\npython -m pip install \"lancedb==0.29.2\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"lancedb==0.29.2\"\n```\n\nIf you use Poetry:\n\n```bash\npoetry add \"lancedb==0.29.2\"\n```\n\n## Connect To A Database\n\n### Local embedded database\n\nUse a directory path for local development, tests, or single-node apps:\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\"data/sample-lancedb\")\n```\n\nLanceDB creates and manages data under that path. Reuse the same path to reopen the database later.\n\n### Object storage or self-managed cloud storage\n\nThe Python SDK also accepts storage URIs such as `s3://...` and supports `storage_options` when the backend needs explicit configuration:\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\n    \"s3://my-bucket/lancedb\",\n    storage_options={\"timeout\": \"60s\"},\n)\n```\n\nIn practice, also make sure the underlying cloud credentials are available through the storage backend you are using.\n\n### LanceDB Cloud\n\nUse a `db://` URI plus an API key and region:\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\n    \"db://my-database\",\n    api_key=\"ldb_...\",\n    region=\"us-east-1\",\n)\n```\n\nIf you are targeting LanceDB Cloud, do not treat it like a local path. The connection parameters are different.\n\n## Define A Table Schema\n\nYou can start with plain Python dictionaries, but schema-first definitions are safer when vectors, filters, and production queries matter.\n\n### Pydantic model with a vector column\n\nThe official docs show `LanceModel` and `Vector(...)` for typed schemas:\n\n```python\nfrom lancedb.pydantic import LanceModel, Vector\n\nclass Item(LanceModel):\n    id: str\n    title: str\n    vector: Vector(3)\n```\n\nThis is the main constraint to remember: the vector dimension in the schema must match the data you insert and the query vectors you send later.\n\n### Schema with an embedding function\n\nIf you want to search with text queries, define the embedding behavior in the schema:\n\n```python\nimport lancedb\nfrom lancedb.embeddings import get_registry\nfrom lancedb.pydantic import LanceModel, Vector\n\nregistry = get_registry()\nfunc = registry.get(\"openai\").create()\n\nclass Document(LanceModel):\n    text: str = func.SourceField()\n    vector: Vector(func.ndims()) = func.VectorField()\n\ndb = lancedb.connect(\"data/sample-lancedb\")\n```\n\nThis pattern lets LanceDB turn text into vectors for indexing and search. Provider-specific embedding setups can still require additional credentials or model downloads.\n\n## Create And Reopen Tables\n\n### Create a table from rows\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\"data/sample-lancedb\")\n\ntable = db.create_table(\n    \"docs\",\n    data=[\n        {\"id\": \"a\", \"title\": \"cat\", \"vector\": [0.1, 0.2, 0.3]},\n        {\"id\": \"b\", \"title\": \"dog\", \"vector\": [0.3, 0.2, 0.1]},\n    ],\n)\n```\n\n### Reopen an existing table\n\n```python\ntable = db.open_table(\"docs\")\n```\n\nUse `create_table(...)` for first-time creation and `open_table(...)` for later access. Do not assume a table already exists.\n\n## Add Data\n\nAppend more rows with `add(...)`:\n\n```python\ntable.add(\n    [\n        {\"id\": \"c\", \"title\": \"bird\", \"vector\": [0.8, 0.1, 0.1]},\n    ]\n)\n```\n\nKeep row shapes consistent with the table schema. Inconsistent field names or vector sizes will cause avoidable failures.\n\n## Search\n\n### Vector search\n\nIf your table stores explicit vectors, pass a numeric vector to `search(...)`:\n\n```python\nresults = table.search([0.2, 0.2, 0.2]).limit(3).to_pandas()\nprint(results)\n```\n\n### Text search through an embedding function\n\nIf the schema defines an embedding function, you can search with text:\n\n```python\nresults = table.search(query=\"puppy\").limit(3).to_pandas()\nprint(results[[\"text\", \"_distance\"]])\n```\n\nThe text-query flow depends on embedding-aware schema setup. If you only created a raw vector column, send vectors instead of strings.\n\n### Filter search results\n\nThe Python query builder supports `where(...)` filters:\n\n```python\nresults = (\n    table.search([0.2, 0.2, 0.2])\n    .where(\"id != 'b'\")\n    .limit(3)\n    .to_pandas()\n)\n```\n\nUse filters to keep reranking and result handling smaller, especially when you already know tenant, status, or category constraints.\n\n## Indexing And Performance\n\nSearch works without an index, but larger tables should add one deliberately. The Python docs show `create_index(...)` on the table:\n\n```python\ntable.create_index(metric=\"cosine\")\n```\n\nFor small prototypes, skip manual indexing until you have enough data to care about latency. For production-scale tables, add indexes before benchmarking query behavior.\n\n## Practical Setup Patterns\n\n### Minimal local flow\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\"data/app.lancedb\")\n\ntable = db.create_table(\n    \"items\",\n    data=[\n        {\"id\": \"1\", \"title\": \"apple\", \"vector\": [0.1, 0.0, 0.0]},\n        {\"id\": \"2\", \"title\": \"orange\", \"vector\": [0.0, 0.1, 0.0]},\n    ],\n)\n\nrows = table.search([0.1, 0.0, 0.0]).limit(5).to_pandas()\nprint(rows)\n```\n\n### Minimal cloud flow\n\n```python\nimport lancedb\n\ndb = lancedb.connect(\n    \"db://my-database\",\n    api_key=\"ldb_...\",\n    region=\"us-east-1\",\n)\n\ntable = db.open_table(\"documents\")\nrows = table.search(\"semantic search query\").limit(5).to_pandas()\n```\n\nThis cloud example assumes the table was created with an embedding-aware schema, so string search can be converted into vectors.\n\n## Common Pitfalls\n\n- Python version mismatch: PyPI metadata for `0.29.2` requires Python `>=3.10`.\n- Wrong connection mode: local paths, object storage URIs, and `db://` cloud databases use different connection parameters.\n- Missing cloud auth: LanceDB Cloud requires both `api_key` and `region`.\n- Vector dimension mismatch: `Vector(n)` must match inserted vectors and query vectors.\n- Text query without embeddings: `search(query=\"...\")` is for embedding-aware tables; plain vector tables should be queried with numeric vectors.\n- Benchmarking before indexing: large-table performance can look worse than expected if you never call `create_index(...)`.\n\n## Official Sources\n\n- Docs root: `https://lancedb.com/docs/`\n- Python quickstart: `https://lancedb.com/docs/quickstart/`\n- Python cloud quickstart: `https://lancedb.com/docs/cloud/quickstart/`\n- Python local/cloud storage guide: `https://lancedb.com/docs/storage/integrations/localcloud-storage/`\n- Python search and filtering guide: `https://lancedb.github.io/lancedb/python/python/#search-and-filtering`\n- Pydantic integration guide: `https://lancedb.com/docs/integrations/frameworks/pydantic/`\n- GitHub repository: `https://github.com/lancedb/lancedb`\n- PyPI package: `https://pypi.org/project/lancedb/`\n"
  },
  {
    "path": "content/landingai/docs/ade/api/DOC.md",
    "content": "---\nname: api\ndescription: \"REST API specification for LandingAI's Agentic Document Extraction (ADE). Covers all endpoints (Parse, Extract, Split, Parse Jobs), request parameters, response structures, data types, error codes, model versions, and curl examples.\"\nmetadata:\n  languages: \"http\"\n  versions: \"v1\"\n  updated-on: \"2026-03-04\"\n  source: maintainer\n  tags: \"landingai,ade,api,document-extraction,parse,extract,split,parse-jobs,curl,rest\"\n---\n\n# LandingAI ADE API Specification\n\nComplete API specification for LandingAI's Agentic Document Extraction (ADE).\n\n## Overview\n\nADE provides a REST API for document parsing, splitting, data extraction, and large file parse jobs. All SDKs and tools (Python, TypeScript) use this same underlying API.\n\n**Core workflow**: Parse first → then Split and/or Extract from the parsed markdown. Extract and Split accept **markdown, not raw files**.\n\n## Base Configuration\n\n| Region | Base URL |\n|--------|----------|\n| US (default) | `https://api.va.landing.ai/v1/ade` |\n| EU | `https://api.va.eu-west-1.landing.ai/v1/ade` |\n\nAll endpoint paths below are relative to the base URL (e.g., `POST {base}/parse`).\n\n**Authentication**: All requests require `Authorization: Bearer $VISION_AGENT_API_KEY`\n\n**Content type**: Always use `-F` (multipart form data), never `-d` (JSON body).\n\n## Common Mistakes\n\n| Mistake | Fix |\n|---------|-----|\n| Sending a PDF/image to `/extract` or `/split` | **Parse first** to get markdown, then extract/split from that |\n| `Authorization: Basic` | Must be `Authorization: Bearer` |\n| `-F \"pdf=@...\"` or `-F \"file=@...\"` | Field name is `document` (parse) or `markdown` (extract/split) |\n| Missing `@` before file path in curl | `-F \"document=@/path/to/file\"` needs the `@` |\n| Using `-d` (JSON body) instead of `-F` | Always use `-F` for multipart form data |\n| Missing `schema` on extract | Required — define a JSON schema for the fields you want |\n| Not using `jq -r` when extracting markdown | Plain `jq` wraps output in quotes with escapes; `jq -r` gives raw text |\n| Sync parse on huge documents | Use `/parse/jobs` for files >50MB or >50 pages |\n\n---\n\n## API Endpoints\n\n### 1. Parse API\n\n**Endpoint**: `POST /parse`\n\nConverts documents to structured markdown with visual grounding.\n\n#### Request Parameters\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `document` | file | One required | Local file — PDF, images (JPG/PNG/TIFF/WEBP/GIF/BMP/PSD + more), Word (DOC/DOCX/ODT), PowerPoint (PPT/PPTX/ODP), spreadsheets (XLSX/CSV) |\n| `document_url` | string | One required | Remote document URL |\n| `model` | string | No | Model version (default: `dpt-2-latest`) |\n| `split` | string | No | Split mode: `\"page\"` to split by pages |\n| `password` | string | No | Decrypt password-protected files (requires ZDR enabled). Supported: PDF, DOC, DOCX, ODT, PPT, PPTX, XLSX |\n\n#### Response Structure\n\n```\n.markdown          → string: full document as markdown\n.chunks[]          → {id, type, markdown, grounding: {page, box: {left, top, right, bottom}}}\n.grounding         → {id → {type, page, box, confidence?, low_confidence_spans?, position?}} — bounding boxes, confidence scores, and tableCell positions\n.splits[]          → {chunks[], class, identifier, markdown, pages[]} — always present; contains a single \"full\" split by default, or per-page splits if split=\"page\". Note: singular `markdown` string since each split is one page (or the full doc)\n.metadata          → {filename, org_id, page_count, duration_ms, credit_usage (float), version, job_id, failed_pages}\n```\n\n<details>\n<summary>Full JSON example</summary>\n\n```json\n{\n  \"markdown\": \"string\",\n  \"chunks\": [\n    {\n      \"id\": \"uuid\",\n      \"type\": \"text|table|marginalia|figure|scan_code|logo|card|attestation\",\n      \"markdown\": \"string\",\n      \"grounding\": {\n        \"page\": 0,\n        \"box\": { \"left\": 0.1, \"top\": 0.2, \"right\": 0.9, \"bottom\": 0.3 }\n      }\n    }\n  ],\n  \"grounding\": {\n    \"chunk-id\": {\n      \"type\": \"chunkText|chunkTable|chunkFigure|chunkMarginalia|chunkLogo|chunkCard|chunkAttestation|chunkScanCode|table|tableCell\",\n      \"page\": 0,\n      \"box\": { \"left\": 0.1, \"top\": 0.2, \"right\": 0.9, \"bottom\": 0.3 },\n      \"confidence\": 0.95,\n      \"low_confidence_spans\": []\n    },\n    \"0-1\": { \"type\": \"table\", \"page\": 0, \"box\": {} },\n    \"0-2\": {\n      \"type\": \"tableCell\", \"page\": 0, \"box\": {},\n      \"position\": { \"row\": 0, \"col\": 0, \"rowspan\": 1, \"colspan\": 1, \"chunk_id\": \"uuid\" }\n    }\n  },\n  \"splits\": [\n    { \"chunks\": [\"chunk-id-1\"], \"class\": \"full\", \"identifier\": \"full\", \"markdown\": \"string\", \"pages\": [0, 1, 2] }\n  ],\n  \"metadata\": {\n    \"filename\": \"document.pdf\", \"org_id\": \"org_abc123\", \"page_count\": 5,\n    \"duration_ms\": 1234, \"credit_usage\": 3.0, \"version\": \"dpt-2-latest\",\n    \"job_id\": \"job_abc123\", \"failed_pages\": []\n  }\n}\n```\n\n</details>\n\n### 2. Extract API\n\n**Endpoint**: `POST /extract`\n\nExtracts structured data from markdown using JSON schemas. **Accepts markdown, not raw documents** — parse first if needed.\n\n#### Request Parameters\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `schema` | JSON string | Yes | JSON Schema defining extraction structure (under 30 properties recommended) |\n| `markdown` | string/file | One required | Markdown content or markdown file to extract from |\n| `markdown_url` | string | One required | URL to markdown content |\n| `model` | string | No | Model version (default: `extract-latest`) |\n\n#### Response Structure\n\n```\n.extraction        → object: extracted key-value pairs matching schema\n.extraction_metadata → {field → {chunk_ids: [string], cell_ids?: [string]}} for grounding\n.metadata          → {credit_usage, duration_ms, filename, job_id, org_id, version, fallback_model_version, schema_violation_error}\n```\n\n### 3. Split API\n\n**Endpoint**: `POST /split`\n\nClassifies and splits mixed documents by type. **Accepts markdown, not raw documents** — parse first if needed.\n\n#### Request Parameters\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `split_class` | JSON array | Yes | Classification configuration (see below) |\n| `markdown` | string | One required | Markdown content to split |\n| `markdown_url` | string | One required | URL to markdown content |\n| `model` | string | No | Model version (default: `split-latest`) |\n\n#### Split Class Structure\n\n```json\n{\n  \"name\": \"Invoice\",              // Required: Classification name\n  \"description\": \"Sales invoice\", // Optional: Description for better classification\n  \"identifier\": \"Invoice Number\"  // Optional: Field to group documents by\n}\n// Maximum 19 split classes per request\n```\n\n#### Response Structure\n\n```\n.splits[]          → {classification, identifier, markdowns[], pages[]}\n.metadata          → {filename, page_count, duration_ms, credit_usage, org_id, job_id, version}\n```\n\n> **Note:** The Split API returns `markdowns[]` (array) because a split can span multiple pages. The Parse API's page-level splits return singular `markdown` (string) since each split is exactly one page.\n\n### 4. Parse Jobs API (Async)\n\nFor large files (>50MB or >50 pages), use asynchronous processing. Supports files up to **1 GB** or **6,000 pages**.\n\n#### Create Job\n\n**Endpoint**: `POST /parse/jobs`\n\n**Parameters**: Same as Parse API plus:\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `output_save_url` | string | If ZDR | URL for zero data retention output |\n\n**Response**: `{ \"job_id\": \"cml1kaihb08dxcn01b3mlfy5b\" }`\n\n#### Get Job Status\n\n**Endpoint**: `GET /parse/jobs/{job_id}`\n\n```\n.job_id            → string\n.status            → string: pending|processing|completed|failed|cancelled\n.progress          → number: 0.0 to 1.0\n.failure_reason    → string | null: error message if failed\n.received_at       → number: Unix timestamp\n.data              → ParseResponse | null: full result when completed (if output_save_url not used)\n.output_url        → string | null: presigned URL when result >1MB or output_save_url was set (expires 1hr)\n.org_id            → string\n.version           → string\n.metadata          → ParseMetadata | null\n```\n\n#### List Jobs\n\n**Endpoint**: `GET /parse/jobs`\n\n**Query Parameters**: `status` (filter), `page` (0-indexed), `pageSize` (items per page)\n\n```\n.jobs[]            → {job_id, status, progress, failure_reason, received_at}\n.has_more          → boolean\n.org_id            → string\n```\n\n---\n\n## Data Types\n\n### Chunk Types\n- `text` — Characters, paragraphs, headings, lists, form fields, checkboxes, code blocks\n- `table` — Grid of rows and columns; includes spreadsheets and receipts\n- `figure` — Visual/graphical non-text content — images, graphs, flowcharts, diagrams\n- `marginalia` — Content in document margins — headers, footers, page numbers, handwritten notes\n- `logo` — Logos (DPT-2 only)\n- `card` — ID cards and driver's licenses (DPT-2 only)\n- `attestation` — Signatures, stamps, and seals (DPT-2 only)\n- `scan_code` — QR codes and barcodes (DPT-2 only)\n\n### Grounding Types\n\n#### For Chunks (with \"chunk\" prefix)\n- `chunkText`, `chunkTable`, `chunkFigure`, `chunkMarginalia`, `chunkLogo`, `chunkCard`, `chunkAttestation`, `chunkScanCode`\n\n#### For Structure Elements (no prefix)\n- `table` — Actual table structure\n- `tableCell` — Individual table cell with position\n\n### Bounding Box\n\nAll coordinates normalized 0–1: `{ left, top, right, bottom }`.\n\n### Confidence Scores\n\nTop-level grounding entries may include:\n- **`confidence`** (`float | null`): Overall confidence score (0.0–1.0) for the chunk's transcription\n- **`low_confidence_spans`** (`array | null`): Specific text spans with low confidence, each containing `confidence` (float), `text` (string), and `span` (position markers)\n\nNot all grounding entries have confidence (e.g., `table`/`tableCell` types may not).\n\n### Table Cell Position\n\n`{ row, col, rowspan, colspan, chunk_id }` — all zero-indexed.\n\n### Table Chunk Formats\n\nTable chunks render as HTML. The ID format and grounding availability differ by source document type.\n\n#### PDF / Image / Document Tables\n\nElement IDs use the format `{page_number}-{base62_sequential_number}` (page starts at 0, numbers increment per element within the page). Cells may include `rowspan`/`colspan` attributes. The `grounding` object contains bounding boxes and `tableCell` position entries for every cell.\n\n```html\n<a id='chunk-uuid'></a>\n\n<table id=\"0-1\">\n<tr><td id=\"0-2\" colspan=\"2\">Product Summary</td></tr>\n<tr><td id=\"0-3\">Product</td><td id=\"0-4\">Revenue</td></tr>\n<tr><td id=\"0-5\">Hardware</td><td id=\"0-6\">15,230</td></tr>\n</table>\n```\n\n#### Spreadsheet Tables (XLSX / CSV)\n\nElement IDs use the format `{tab_name}-{cell_reference}` (e.g., `Sheet 1-A1`). The table element itself uses `{tab_name}-{start_cell}:{end_cell}` (e.g., `Sheet 1-A1:B4`). Embedded images and charts become `figure` chunks.\n\n**`grounding` is `null`** for spreadsheet table chunks — cell positions are encoded in the IDs themselves.\n\n```html\n<a id='Sheet 1-A1:B4-chunk'></a>\n\n<table id='Sheet 1-A1:B4'>\n  <tr>\n    <td id='Sheet 1-A1'>Program</td>\n    <td id='Sheet 1-B1'>Interest Rate</td>\n  </tr>\n  <tr>\n    <td id='Sheet 1-A2'>15 Year Fixed-Rate Mortgage</td>\n    <td id='Sheet 1-B2'>0.05125</td>\n  </tr>\n</table>\n```\n\n### Spreadsheet Parse Response\n\nSpreadsheets (CSV, XLSX) return a **different response type** (`SpreadsheetParseResponse`) with key differences:\n\n| Field | Documents (`ParseResponse`) | Spreadsheets (`SpreadsheetParseResponse`) |\n|---|---|---|\n| `metadata.page_count` | ✓ | ✗ (uses `sheet_count`, `total_rows`, `total_cells`, `total_chunks`, `total_images`) |\n| `splits[].pages` | ✓ | ✗ (uses `sheets` — array of sheet indices) |\n| `grounding` (top-level) | ✓ | ✗ (not present for spreadsheets) |\n| Chunk grounding | Always present | Optional (null for table chunks, present for embedded image chunks) |\n\n---\n\n## Error Responses\n\nAll errors follow this format:\n\n```json\n{\n  \"error\": {\n    \"message\": \"Human-readable error message\",\n    \"type\": \"error_type\",\n    \"details\": { \"field\": \"problem_field\", \"reason\": \"Specific reason\" }\n  }\n}\n```\n\n### HTTP Status Codes\n\n| Status | Name | Description | Solution |\n|--------|------|-------------|----------|\n| 200 | Success | Request completed successfully | Continue with normal operations |\n| 206 | Partial Content | Parse: some pages failed (check `metadata.failed_pages`). Extract: data does not fully conform to schema (check `metadata.schema_violation_error`) | Review failed pages or schema violations; partial data is still returned and credits are consumed |\n| 400 | Bad Request | Invalid request due to malformed input, unsupported version, or client-side errors | Review error message for specific issue |\n| 401 | Unauthorized | Missing or invalid API key | Check that `VISION_AGENT_API_KEY` is present and valid |\n| 402 | Payment Required | Account does not have enough credits | Verify correct API key; add more credits to your account |\n| 422 | Unprocessable Entity | Input validation failed | Review request parameters, file format, and schema JSON |\n| 429 | Too Many Requests | Rate limit exceeded | Wait before retrying; implement exponential backoff |\n| 500 | Internal Server Error | Server error during processing | Retry with backoff; if persistent, contact support@landing.ai |\n| 504 | Gateway Timeout | Request exceeded timeout limit (475 seconds) | Reduce document size or simplify schema; use Parse Jobs API |\n\n## Model Versions\n\n### Parse Models\n\n| Model | Best For | Chunk Types |\n|-------|----------|-------------|\n| **`dpt-2-latest`** | Complex documents with logos, signatures, ID cards | text, table, figure, marginalia, logo, card, attestation, scan_code |\n| **`dpt-2-mini`** | Simple, digitally-native documents (faster, cheaper) | text, table, figure, marginalia |\n| **`dpt-1`** | ⚠️ **Deprecated March 31, 2026** — migrate to dpt-2 | text, table, figure, marginalia |\n\n**Version Pinning:** For production, use dated versions (e.g., `dpt-2-20251103`) for reproducibility.\n\n### Extract & Split Models\n\n| Operation | Current Version | Description |\n|-----------|----------------|-------------|\n| Extract | `extract-latest` (currently `extract-20251024`) | Schema-based extraction |\n| Split | `split-latest` | Document classification |\n\n## Supported File Types\n\n| Category | Formats | Notes |\n|----------|---------|-------|\n| **PDF** | PDF | Up to 100 pages in Playground (see rate limits for API); no password-protected files |\n| **Images** | JPEG, JPG, PNG, APNG, BMP, DCX, DDS, DIB, GD, GIF, ICNS, JP2, PCX, PPM, PSD, TGA, TIF, TIFF, WEBP | |\n| **Text Documents** | DOC, DOCX, ODT | Converted to PDF before parsing |\n| **Presentations** | ODP, PPT, PPTX | Converted to PDF before parsing |\n| **Spreadsheets** | CSV, XLSX | Up to 10 MB in Playground; no limit in API |\n\n> **Note:** Word, PowerPoint, and OpenDocument files are converted to PDF server-side before parsing.\n\n> **Spreadsheets** return a different response type — see [Spreadsheet Parse Response](#spreadsheet-parse-response) above.\n\n## Best Practices\n\n### File Size Handling\n- < 50MB: Use synchronous Parse API\n- \\> 50MB: Use Parse Jobs API\n- \\> 100MB: Consider splitting document first\n\n### Rate Limiting\n- Implement exponential backoff — start with 10s, double on each retry, max 5 retries\n\n### Cost Optimization\n- Parse once, extract/split multiple times\n- Use specific schemas (avoid extracting everything)\n- Cache parsed results when possible\n\n---\n\n# API (curl) Reference\n\nDirect HTTP API implementation using curl and shell scripts.\n\n## Authentication\n\n```bash\nexport VISION_AGENT_API_KEY=\"v2_...\"\nBASE_URL=\"https://api.va.landing.ai/v1/ade\"  # or https://api.va.eu-west-1.landing.ai/v1/ade for EU\n```\n\n## Parse Examples\n\n### Basic Parse\n```bash\ncurl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@document.pdf\" \\\n  -F \"model=dpt-2-latest\"\n```\n\n### Parse with Page Splitting\n```bash\ncurl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@multi_page.pdf\" \\\n  -F \"split=page\"\n```\n\n### Parse from URL\n```bash\ncurl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document_url=https://example.com/document.pdf\"\n```\n\n## Extract Examples\n\n```bash\nSCHEMA='{\n  \"type\": \"object\",\n  \"properties\": {\n    \"invoice_number\": {\"type\": \"string\", \"description\": \"Invoice number\"},\n    \"total_amount\": {\"type\": \"number\", \"description\": \"Total amount\"},\n    \"vendor_name\": {\"type\": \"string\", \"description\": \"Vendor name\"}\n  }\n}'\n\n# Extract from a markdown file (parse first if you have a PDF)\ncurl -s -X POST \"$BASE_URL/extract\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"markdown=@parsed_invoice.md\" \\\n  -F \"schema=$SCHEMA\" \\\n  -F \"model=extract-latest\"\n```\n\n### Parse Once, Extract Many\n```bash\n# Parse once, save markdown\nMARKDOWN=$(curl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@invoice.pdf\" \\\n  | jq -r '.markdown')\n\n# Extract with different schemas\ncurl -s -X POST \"$BASE_URL/extract\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"markdown=$MARKDOWN\" \\\n  -F \"schema=$SCHEMA\"\n```\n\n## Split Examples\n\n```bash\nSPLIT_CLASSES='[\n  {\"name\": \"Invoice\", \"identifier\": \"Invoice Number\"},\n  {\"name\": \"Receipt\", \"identifier\": \"Receipt Number\"},\n  {\"name\": \"Purchase Order\", \"identifier\": \"PO Number\"}\n]'\n\n# Parse first, then split\nMARKDOWN=$(curl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@mixed_documents.pdf\" \\\n  | jq -r '.markdown')\n\ncurl -s -X POST \"$BASE_URL/split\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"markdown=$MARKDOWN\" \\\n  -F \"split_class=$SPLIT_CLASSES\" \\\n  -F \"model=split-latest\"\n```\n\n## Parse Jobs (Async, Large Files)\n\n```bash\n#!/bin/bash\n\n# Create job\nJOB_ID=$(curl -s -X POST \"$BASE_URL/parse/jobs\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@large_document.pdf\" \\\n  -F \"model=dpt-2-latest\" \\\n  | jq -r '.job_id')\n\necho \"Created job: $JOB_ID\"\n\n# Poll for completion\nwhile true; do\n  STATUS=$(curl -s -X GET \"$BASE_URL/parse/jobs/$JOB_ID\" \\\n    -H \"Authorization: Bearer $VISION_AGENT_API_KEY\")\n\n  STATE=$(echo \"$STATUS\" | jq -r '.status')\n  PROGRESS=$(echo \"$STATUS\" | jq -r '.progress')\n\n  echo \"Status: $STATE, Progress: $(echo \"$PROGRESS * 100\" | bc)%\"\n\n  if [ \"$STATE\" = \"completed\" ]; then\n    echo \"$STATUS\" | jq '.data' > \"parse_result.json\"\n    break\n  elif [ \"$STATE\" = \"failed\" ]; then\n    echo \"Job failed: $(echo \"$STATUS\" | jq -r '.failure_reason')\" >&2\n    exit 1\n  fi\n\n  sleep 5\ndone\n```\n\n## Complete Workflow: Parse → Split → Extract\n\n```bash\n#!/bin/bash\n\n# 1. Parse\nMARKDOWN=$(curl -s -X POST \"$BASE_URL/parse\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"document=@mixed_invoices.pdf\" \\\n  | jq -r '.markdown')\n\n# 2. Split\nSPLIT_CLASSES='[\n  {\"name\": \"Invoice\", \"identifier\": \"Invoice Number\"},\n  {\"name\": \"Credit Note\", \"identifier\": \"Credit Note Number\"}\n]'\n\nSPLITS=$(curl -s -X POST \"$BASE_URL/split\" \\\n  -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n  -F \"markdown=$MARKDOWN\" \\\n  -F \"split_class=$SPLIT_CLASSES\")\n\n# 3. Extract from each split\nSCHEMA='{\"type\": \"object\", \"properties\": {\n  \"document_number\": {\"type\": \"string\"},\n  \"total\": {\"type\": \"number\"},\n  \"date\": {\"type\": \"string\"}\n}}'\n\necho \"$SPLITS\" | jq -c '.splits[]' | while read -r split; do\n  TYPE=$(echo \"$split\" | jq -r '.classification')\n  ID=$(echo \"$split\" | jq -r '.identifier')\n  MD=$(echo \"$split\" | jq -r '.markdowns[0]')\n\n  echo \"Processing $TYPE: $ID\"\n\n  curl -s -X POST \"$BASE_URL/extract\" \\\n    -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n    -F \"markdown=$MD\" \\\n    -F \"schema=$SCHEMA\" \\\n    | jq '.extraction'\ndone\n```\n\n## Error Handling with Retry\n\n```bash\n#!/bin/bash\n\nMAX_RETRIES=3\nRETRY_COUNT=0\n\nwhile [ $RETRY_COUNT -lt $MAX_RETRIES ]; do\n  RESPONSE=$(curl -s -w \"\\n%{http_code}\" -X POST \"$BASE_URL/parse\" \\\n    -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n    -F \"document=@document.pdf\")\n\n  HTTP_CODE=$(echo \"$RESPONSE\" | tail -n 1)\n  BODY=$(echo \"$RESPONSE\" | sed '$d')\n\n  if [ \"$HTTP_CODE\" -eq 200 ] || [ \"$HTTP_CODE\" -eq 206 ]; then\n    echo \"$BODY\"\n    break\n  elif [ \"$HTTP_CODE\" -eq 429 ]; then\n    WAIT_TIME=$((2 ** RETRY_COUNT * 10))\n    echo \"Rate limited. Waiting ${WAIT_TIME}s...\" >&2\n    sleep $WAIT_TIME\n    RETRY_COUNT=$((RETRY_COUNT + 1))\n  elif [ \"$HTTP_CODE\" -eq 504 ]; then\n    echo \"Timeout — use parse jobs API\" >&2\n    exit 1\n  elif [ \"$HTTP_CODE\" -eq 402 ]; then\n    echo \"Insufficient credits\" >&2\n    exit 1\n  else\n    echo \"Error: HTTP $HTTP_CODE\" >&2\n    echo \"$BODY\" | jq '.error' >&2\n    exit 1\n  fi\ndone\n```\n\n## jq Recipes\n\n```bash\n# Extract just markdown\ncurl -s ... | jq -r '.markdown'\n\n# Get all tables\ncurl -s ... | jq '.chunks[] | select(.type == \"table\")'\n\n# Extract table cells with positions\ncurl -s ... | jq '.grounding | to_entries[] | select(.value.type == \"tableCell\")'\n\n# Get chunks from specific page\ncurl -s ... | jq '.chunks[] | select(.grounding.page == 0)'\n\n# Group chunks by type with counts\ncurl -s ... | jq '.chunks | group_by(.type) | map({type: .[0].type, count: length})'\n\n# Get specific extracted field\ncurl -s ... | jq '.extraction.invoice_number'\n\n# Process extracted line items\ncurl -s ... | jq '.extraction.line_items[] | {sku: .sku, total: (.quantity * .unit_price)}'\n```\n\n## Shell Functions for Reuse\n\n```bash\nade_parse() {\n  curl -s -X POST \"$BASE_URL/parse\" \\\n    -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n    -F \"document=@$1\"\n}\n\nade_extract() {\n  curl -s -X POST \"$BASE_URL/extract\" \\\n    -H \"Authorization: Bearer $VISION_AGENT_API_KEY\" \\\n    -F \"markdown=$1\" \\\n    -F \"schema=$2\"\n}\n```\n\n---\n\n## External Links\n\n- [API Reference](https://docs.landing.ai/api-reference)\n- [ADE Documentation](https://docs.landing.ai/ade)\n- [Supported File Types](https://docs.landing.ai/ade/ade-file-types)\n"
  },
  {
    "path": "content/landingai/docs/ade/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Python SDK reference for LandingAI's Agentic Document Extraction (ADE). Includes Pydantic schema extraction, async processing, error handling, save_to, visual grounding, table cell lookup, and complete API context.\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.0\"\n  updated-on: \"2026-03-04\"\n  source: maintainer\n  tags: \"landingai,ade,python,sdk,pydantic,document-extraction,parse,extract,split,async\"\n---\n\n# LandingAI ADE — Python SDK Reference\n\nPython SDK for LandingAI's Agentic Document Extraction.\n\n## Installation\n\n```bash\npip install landingai-ade\nexport VISION_AGENT_API_KEY=\"v2_...\"\n```\n\n## Client Setup\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()  # Uses VISION_AGENT_API_KEY env var\n```\n\n### Constructor Arguments\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `api_key` | `str \\| None` | env `VISION_AGENT_API_KEY` | API key |\n| `environment` | `\"production\" \\| \"eu\"` | `\"production\"` | Region — `\"production\"` (US) or `\"eu\"` |\n| `base_url` | `str \\| None` | — | Override base URL |\n| `timeout` | `float \\| Timeout \\| None` | SDK default | Request timeout in seconds |\n| `max_retries` | `int` | SDK default | Max retry attempts for transient errors |\n| `http_client` | `httpx.Client \\| None` | — | Custom httpx client |\n\n```python\n# EU region\nclient = LandingAIADE(environment=\"eu\")\n\n# Pass key directly\nclient = LandingAIADE(api_key=\"v2_...\")\n```\n\n---\n\n## 1. Parse\n\nConverts documents to structured markdown with visual grounding.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `document` | `FileTypes \\| None` | One required | Local file (Path, bytes, file-like) |\n| `document_url` | `str \\| None` | One required | Remote document URL |\n| `model` | `str \\| None` | No | Model version (default: `dpt-2-latest`) |\n| `split` | `\"page\" \\| None` | No | Split by pages |\n| `password` | `str \\| None` | No | Decrypt password-protected files (requires ZDR enabled) |\n| `save_to` | `str \\| None` | No | Directory to save `{filename}_parse_output.json` |\n\n### Returns `ParseResponse`\n\n```\n.markdown          → str: full document as markdown\n.chunks[]          → Chunk: {id, type, markdown, grounding: {page, box}}\n.grounding         → dict: {id → Grounding} with bounding boxes, confidence scores, and tableCell positions\n.splits[]          → Split: {chunks[], class, identifier, markdown, pages[]} — always present; contains a single \"full\" split by default, or per-page splits if split=\"page\"\n.metadata          → ParseMetadata: {filename, org_id, page_count, duration_ms, credit_usage (float), version, job_id, failed_pages}\n```\n\n### Example\n\n```python\nresponse = client.parse(\n    document=Path(\"invoice.pdf\"),\n    model=\"dpt-2-latest\",\n    save_to=\"./output\",\n)\n\nprint(response.markdown)\nprint(f\"{len(response.chunks)} chunks, {response.metadata.page_count} pages\")\n\ntables = [c for c in response.chunks if c.type == \"table\"]\n```\n\n### Visual Grounding and Table Cells\n\n> **Important:** `response.grounding` is a `dict[str, Grounding]` — the outer container is a dict (so `.items()`, `.get()` work), but each **value** is a Pydantic model. Use **attribute access** (`grounding.type`, `grounding.box.left`) not dict access (`grounding[\"type\"]`). In contrast, `response.extraction` IS a plain dict — `extraction[\"field\"]` is correct.\n\n```python\nfor chunk in response.chunks:\n    box = chunk.grounding.box\n    print(f\"{chunk.type} on page {chunk.grounding.page}: \"\n          f\"({box.left:.3f}, {box.top:.3f}) → ({box.right:.3f}, {box.bottom:.3f})\")\n\nfor gid, grounding in response.grounding.items():\n    if grounding.type == \"tableCell\":\n        pos = grounding.position\n        print(f\"Cell ({pos.row}, {pos.col}) span=({pos.rowspan}x{pos.colspan})\")\n```\n\n### Extract a Cell Value by Row and Column (PDF)\n\n```python\nimport re\n\ntable = next(c for c in response.chunks if c.type == \"table\")\n\nrows = re.findall(r'<tr[^>]*>(.*?)</tr>', table.markdown, re.DOTALL)\ngrid = {}\nfor r, row_html in enumerate(rows):\n    for c, m in enumerate(re.finditer(r'<td[^>]*>(.*?)</td>', row_html, re.DOTALL)):\n        grid[(r, c)] = re.sub(r'<[^>]+>', '', m.group(1)).strip()\n\nvalue = grid[(1, 0)]  # zero-indexed row, col\n```\n\n### Read a Spreadsheet Cell by Reference\n\n```python\nimport re\n\nresponse = client.parse(document=Path(\"report.xlsx\"))\ntable = next(c for c in response.chunks if c.type == \"table\")\n\n# Spreadsheet cell IDs are \"{tab_name}-{cell_ref}\" (e.g., \"Sheet 1-B2\").\n# grounding is null for spreadsheets, so parse IDs directly from HTML.\ncell_text = {}\nfor m in re.finditer(\n    r'<td[^>]*\\bid=[\"\\']([^\"\\']+)[\"\\'][^>]*>(.*?)</td>',\n    table.markdown, re.DOTALL,\n):\n    cell_text[m.group(1)] = re.sub(r\"<[^>]+>\", \"\", m.group(2)).strip()\n\nvalue = cell_text[\"Sheet 1-B2\"]\n```\n\n---\n\n## 2. Extract\n\nExtracts structured data from markdown using a JSON schema.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `schema` | `str` | Yes | JSON schema string (use `pydantic_to_json_schema()` to generate from Pydantic models) |\n| `markdown` | `FileTypes \\| str \\| None` | One required | Markdown content, string, or file |\n| `markdown_url` | `str \\| None` | One required | URL to markdown |\n| `model` | `str \\| None` | No | Model version (default: `extract-latest`) |\n| `save_to` | `str \\| None` | No | Directory to save `{filename}_extract_output.json` |\n\n### Returns `ExtractResponse`\n\n```\n.extraction        → dict: extracted key-value pairs matching schema\n.extraction_metadata → dict: {field → {chunk_ids: [str], cell_ids?: [str]}} for grounding\n.metadata          → Metadata: {credit_usage, duration_ms, filename, job_id, org_id, version, schema_violation_error, fallback_model_version}\n```\n\n### Pydantic Schema Extraction\n\n```python\nfrom pydantic import BaseModel, Field\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclass InvoiceData(BaseModel):\n    invoice_number: str = Field(description=\"Invoice number or ID\")\n    total_amount: float = Field(description=\"Total amount to be paid\")\n    vendor_name: str = Field(description=\"Vendor or supplier name\")\n    line_items: list[dict] | None = Field(default=None, description=\"Line items\")\n\n# Parse once, extract many\nparsed = client.parse(document=Path(\"invoice.pdf\"))\n\nresponse = client.extract(\n    markdown=parsed.markdown,\n    schema=pydantic_to_json_schema(InvoiceData),\n)\n\ninvoice = InvoiceData(**response.extraction)\nprint(f\"Invoice {invoice.invoice_number}: ${invoice.total_amount}\")\n```\n\n### Grounding References (Tracing Back to Source)\n\n```python\nchunk_map = {c.id: c for c in parsed.chunks}\n\nfor field, meta in response.extraction_metadata.items():\n    if meta.get(\"chunk_ids\"):\n        chunk = chunk_map.get(meta[\"chunk_ids\"][0])\n        if chunk:\n            print(f\"{field}: page {chunk.grounding.page}, type={chunk.type}\")\n```\n\n### `pydantic_to_json_schema(model)`\n\nConverts a Pydantic `BaseModel` class to a resolved JSON schema string (all `$ref` inlined). Pass the result directly to `schema=`.\n\n```python\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nschema_str = pydantic_to_json_schema(InvoiceData)  # → JSON string\n```\n\n---\n\n## 3. Split\n\nClassifies and splits mixed documents by type.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `split_class` | `Iterable[SplitClass]` | Yes | List of `{\"name\": str, \"description\"?: str, \"identifier\"?: str}` |\n| `markdown` | `FileTypes \\| str \\| None` | One required | Markdown content or file |\n| `markdown_url` | `str \\| None` | One required | URL to markdown |\n| `model` | `str \\| None` | No | Model version (default: `split-latest`) |\n| `save_to` | `str \\| None` | No | Directory to save `{filename}_split_output.json` |\n\n### Returns `SplitResponse`\n\n```\n.splits[]          → Split: {classification, identifier, markdowns[], pages[]}\n.metadata          → SplitMetadata: {filename, page_count, duration_ms, credit_usage, org_id, job_id, version}\n```\n\n### Split → Extract Pipeline\n\n```python\nparsed = client.parse(document=Path(\"mixed_invoices.pdf\"))\n\nsplits = client.split(\n    markdown=parsed.markdown,\n    split_class=[\n        {\"name\": \"Invoice\", \"description\": \"Sales invoice\", \"identifier\": \"Invoice Number\"},\n        {\"name\": \"Receipt\", \"description\": \"Payment receipt\", \"identifier\": \"Receipt Number\"},\n    ],\n)\n\nfor split in splits.splits:\n    print(f\"{split.classification}: {split.identifier} (pages {split.pages})\")\n\n# Extract from each split\nschema = pydantic_to_json_schema(InvoiceData)\nresults = []\nfor split in splits.splits:\n    extracted = client.extract(markdown=split.markdowns[0], schema=schema)\n    results.append({\"type\": split.classification, \"id\": split.identifier, **extracted.extraction})\n```\n\n---\n\n## 4. Parse Jobs (Async, Large Files)\n\nFor files >50MB or >50 pages, use asynchronous processing. Supports files up to **1 GB** or **6,000 pages**.\n\n### `parse_jobs.create()` Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `document` | `FileTypes \\| None` | One required | Local file |\n| `document_url` | `str \\| None` | One required | Remote document URL |\n| `model` | `str \\| None` | No | Model version (default: `dpt-2-latest`) |\n| `split` | `\"page\" \\| None` | No | Split by pages |\n| `output_save_url` | `str \\| None` | If ZDR | URL for zero data retention output |\n\n### Returns `ParseJobCreateResponse`\n\n```\n.job_id            → str: unique job identifier\n```\n\n### `parse_jobs.get(job_id)` Returns `ParseJobGetResponse`\n\n```\n.job_id            → str\n.status            → str: pending|processing|completed|failed|cancelled\n.progress          → float: 0.0 to 1.0\n.failure_reason    → str | None: error message if failed\n.data              → ParseResponse | None: full result when completed\n.output_url        → str | None: presigned URL if result >1MB (expires 1hr)\n```\n\n### `parse_jobs.list()` Arguments & Returns\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `status` | `\"pending\" \\| \"processing\" \\| \"completed\" \\| \"failed\" \\| \"cancelled\"` | No | Filter by status |\n| `page` | `int \\| None` | No | Page number (0-indexed) |\n| `page_size` | `int \\| None` | No | Items per page |\n\n```\n.jobs[]            → Job: {job_id, status, progress, received_at, failure_reason}\n.has_more          → bool | None\n```\n\n### Example\n\n```python\nimport time\n\njob = client.parse_jobs.create(document=Path(\"large.pdf\"))\nprint(f\"Job ID: {job.job_id}\")\n\nwhile True:\n    status = client.parse_jobs.get(job.job_id)\n    print(f\"Status: {status.status}, Progress: {status.progress * 100:.0f}%\")\n\n    if status.status == \"completed\":\n        result = status.data  # ParseResponse\n        break\n    elif status.status == \"failed\":\n        raise RuntimeError(f\"Job failed: {status.failure_reason}\")\n\n    time.sleep(5)\n```\n\n---\n\n## Error Handling\n\n### Exception Classes\n\nAll exceptions inherit from `LandingAiadeError`:\n\n| Exception | HTTP Status | Description |\n|-----------|-------------|-------------|\n| `BadRequestError` | 400 | Invalid request due to malformed input or unsupported version |\n| `AuthenticationError` | 401 | Missing or invalid API key |\n| `UnprocessableEntityError` | 422 | Input validation failed |\n| `RateLimitError` | 429 | Rate limit exceeded |\n| `InternalServerError` | 5xx | Server error during processing |\n| `APIConnectionError` | — | Network failure |\n| `APITimeoutError` | — | Request timeout |\n\n`APIStatusError` is the base for all HTTP errors and has a `status_code` attribute. Note: HTTP 206 (Partial Content) is returned as a successful response with `schema_violation_error` or `failed_pages` in metadata. HTTP 402 (Payment Required) indicates insufficient credits.\n\n### Retry with Fallback to Jobs\n\n```python\nfrom landingai_ade import RateLimitError, APITimeoutError, APIStatusError, APIConnectionError\n\ndef parse_with_retry(client, file_path, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            return client.parse(document=Path(file_path))\n        except RateLimitError:\n            time.sleep(2 ** attempt * 10)\n        except (APITimeoutError, APIStatusError) as e:\n            if isinstance(e, APIStatusError) and e.status_code != 504:\n                raise\n            print(\"Timeout — switching to parse jobs\")\n            job = client.parse_jobs.create(document=Path(file_path))\n            return poll_job(client, job.job_id)\n        except APIConnectionError:\n            time.sleep(2)\n    raise RuntimeError(\"Failed after retries\")\n\ndef poll_job(client, job_id, timeout=300):\n    start = time.time()\n    while time.time() - start < timeout:\n        status = client.parse_jobs.get(job_id)\n        if status.status == \"completed\":\n            return status.data\n        if status.status == \"failed\":\n            raise RuntimeError(f\"Job failed: {status.failure_reason}\")\n        time.sleep(5)\n    raise TimeoutError(\"Job did not complete in time\")\n```\n\n---\n\n## Async / Concurrent Processing\n\n```python\nimport asyncio\nfrom landingai_ade import AsyncLandingAIADE\n\nasync def parse_multiple(files: list[str]):\n    client = AsyncLandingAIADE()\n    tasks = [client.parse(document=Path(f)) for f in files]\n    results = await asyncio.gather(*tasks, return_exceptions=True)\n    return [r for r in results if not isinstance(r, Exception)]\n```\n\n`AsyncLandingAIADE` has the same constructor and methods as `LandingAIADE` — all methods are `async`.\n\n---\n\n## API Reference\n\nThe following sections provide the complete API context so this document is fully self-contained.\n\n### Base Configuration\n\n| Region | Base URL |\n|--------|----------|\n| US (default) | `https://api.va.landing.ai/v1/ade` |\n| EU | `https://api.va.eu-west-1.landing.ai/v1/ade` |\n\n**Authentication**: All requests require `Authorization: Bearer $VISION_AGENT_API_KEY`\n\n### Quick Reference\n\n| Endpoint | Method | Path | Model | Input |\n|----------|--------|------|-------|-------|\n| Parse | POST | `/v1/ade/parse` | `dpt-2-latest` | `document` (file) or `document_url` |\n| Extract | POST | `/v1/ade/extract` | `extract-latest` | `markdown` (file/string) or `markdown_url` + `schema` |\n| Split | POST | `/v1/ade/split` | `split-latest` | `markdown` (file/string) or `markdown_url` + `split_class` |\n| Create Job | POST | `/v1/ade/parse/jobs` | `dpt-2-latest` | `document` or `document_url` |\n| Get Job | GET | `/v1/ade/parse/jobs/{id}` | — | — |\n| List Jobs | GET | `/v1/ade/parse/jobs` | — | `?status=&page=&pageSize=` |\n\n### Data Types\n\n#### Chunk Types\n- `text` — Characters, paragraphs, headings, lists, form fields, checkboxes, code blocks\n- `table` — Grid of rows and columns; includes spreadsheets and receipts\n- `figure` — Visual/graphical non-text content — images, graphs, flowcharts, diagrams\n- `marginalia` — Content in document margins — headers, footers, page numbers, handwritten notes\n- `logo` — Logos (DPT-2 only)\n- `card` — ID cards and driver's licenses (DPT-2 only)\n- `attestation` — Signatures, stamps, and seals (DPT-2 only)\n- `scan_code` — QR codes and barcodes (DPT-2 only)\n\n#### Grounding Types\n- Chunk grounding: `chunkText`, `chunkTable`, `chunkFigure`, `chunkMarginalia`, `chunkLogo`, `chunkCard`, `chunkAttestation`, `chunkScanCode`\n- Structure: `table`, `tableCell` (with position data)\n\n#### Bounding Box\nAll coordinates normalized 0–1: `{ left, top, right, bottom }`.\n\n#### Confidence Scores\nTop-level grounding entries may include `confidence` (float, 0.0–1.0) and `low_confidence_spans` (list of `{confidence, text, span}`). Not all entries have confidence (e.g., `table`/`tableCell` types may not).\n\n#### Table Cell Position\n`{ row, col, rowspan, colspan, chunk_id }` — zero-indexed.\n\n#### Table Chunk Formats\n\n**PDF/Image tables**: Element IDs use `{page}-{base62_seq}`. Grounding object has bounding boxes and `tableCell` entries.\n\n**Spreadsheet tables (XLSX/CSV)**: Element IDs use `{tab_name}-{cell_ref}` (e.g., `Sheet 1-B2`). **Grounding is null** — positions are encoded in IDs.\n\n### Error Codes\n\n| Status | Name | Description | Solution |\n|--------|------|-------------|----------|\n| 200 | Success | Request completed successfully | Continue with normal operations |\n| 206 | Partial Content | Parse: some pages failed (`metadata.failed_pages`). Extract: schema violation (`metadata.schema_violation_error`) | Review failed pages or schema violations; partial data returned, credits consumed |\n| 400 | Bad Request | Invalid request due to malformed input or unsupported version | Review error message for specific issue |\n| 401 | Unauthorized | Missing or invalid API key | Check VISION_AGENT_API_KEY |\n| 402 | Payment Required | Account does not have enough credits | Verify correct API key; add credits |\n| 422 | Unprocessable Entity | Input validation failed | Review request parameters and schema JSON |\n| 429 | Too Many Requests | Rate limit exceeded | Implement exponential backoff |\n| 500 | Internal Server Error | Server error during processing | Retry with backoff |\n| 504 | Gateway Timeout | Request exceeded timeout limit (475 seconds) | Reduce document size or use Parse Jobs API |\n\n### Supported File Types\n\n| Category | Formats | Notes |\n|----------|---------|-------|\n| **PDF** | PDF | Up to 100 pages in Playground (see rate limits for API); no password-protected files |\n| **Images** | JPEG, JPG, PNG, APNG, BMP, DCX, DDS, DIB, GD, GIF, ICNS, JP2, PCX, PPM, PSD, TGA, TIF, TIFF, WEBP | |\n| **Text Documents** | DOC, DOCX, ODT | Converted to PDF before parsing |\n| **Presentations** | ODP, PPT, PPTX | Converted to PDF before parsing |\n| **Spreadsheets** | CSV, XLSX | Up to 10 MB in Playground; no limit in API |\n\n> **Note:** Word, PowerPoint, and OpenDocument files are converted to PDF server-side before parsing.\n\n> **Spreadsheets** return a different response type (`SpreadsheetParseResponse`) — uses `sheet_count`/`total_rows`/`total_cells` instead of `page_count`, splits use `sheets` instead of `pages`, and top-level `grounding` is not present.\n\n### Model Versions\n\n| Model | Best For | Chunk Types |\n|-------|----------|-------------|\n| **`dpt-2-latest`** | Complex documents with logos, signatures, ID cards | text, table, figure, marginalia, logo, card, attestation, scan_code |\n| **`dpt-2-mini`** | Simple, digitally-native documents (faster, cheaper) | text, table, figure, marginalia |\n| **`dpt-1`** | ⚠️ **Deprecated March 31, 2026** — migrate to dpt-2 | text, table, figure, marginalia |\n\n| Operation | Current Version | Description |\n|-----------|----------------|-------------|\n| Extract | `extract-latest` (currently `extract-20251024`) | Schema-based extraction |\n| Split | `split-latest` | Document classification |\n\n**Version Pinning:** For production, use dated versions (e.g., `dpt-2-20251103`) for reproducibility.\n\n---\n\n## External Links\n\n- [Python SDK Documentation](https://docs.landing.ai/ade/ade-python)\n- [Python SDK GitHub](https://github.com/landing-ai/ade-python)\n"
  },
  {
    "path": "content/landingai/docs/ade/typescript/DOC.md",
    "content": "---\nname: sdk\ndescription: \"TypeScript/JavaScript SDK reference for LandingAI's Agentic Document Extraction (ADE). Includes type definitions, Zod schema validation, async processing, error handling, type guards, and complete API context.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.2.0\"\n  updated-on: \"2026-03-04\"\n  source: maintainer\n  tags: \"landingai,ade,typescript,javascript,sdk,zod,document-extraction,parse,extract,split,async\"\n---\n\n# LandingAI ADE — TypeScript SDK Reference\n\nTypeScript/JavaScript SDK for LandingAI's Agentic Document Extraction.\n\n## Installation\n\n```bash\nnpm install landingai-ade\n# or: yarn add landingai-ade / pnpm add landingai-ade\nexport VISION_AGENT_API_KEY=\"v2_...\"\n```\n\n## Client Setup\n\n```typescript\nimport { LandingAIADE } from \"landingai-ade\";\n\nconst client = new LandingAIADE();  // Uses VISION_AGENT_API_KEY env var\n```\n\n### Constructor Arguments\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `apikey` | `string \\| undefined` | env `VISION_AGENT_API_KEY` | API key (note: lowercase) |\n| `environment` | `\"production\" \\| \"eu\"` | `\"production\"` | Region — `\"production\"` (US) or `\"eu\"` |\n| `baseURL` | `string \\| undefined` | — | Override base URL |\n| `timeout` | `number \\| undefined` | SDK default | Request timeout in ms |\n| `maxRetries` | `number \\| undefined` | SDK default | Max retry attempts for transient errors |\n| `defaultHeaders` | `Record<string, string>` | — | Custom headers for all requests |\n| `fetch` | `typeof global.fetch` | — | Custom fetch implementation |\n\n```typescript\n// EU region\nconst client = new LandingAIADE({ environment: \"eu\" });\n\n// Pass key directly\nconst client = new LandingAIADE({ apikey: \"v2_...\" });\n\n// Full config\nconst client = new LandingAIADE({\n  apikey: \"v2_...\",\n  timeout: 60000,\n  maxRetries: 3,\n});\n```\n\n---\n\n## 1. Parse\n\nConverts documents to structured markdown with visual grounding.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `document` | `Uploadable \\| null` | One required | Local file (Buffer, ReadStream, File object) |\n| `document_url` | `string \\| null` | One required | Remote document URL |\n| `model` | `string \\| null` | No | Model version (default: `dpt-2-latest`) |\n| `split` | `\"page\" \\| null` | No | Split by pages |\n| `password` | `string \\| null` | No | Decrypt password-protected files (requires ZDR enabled) |\n| `saveTo` | `string` | No | Directory to save `{filename}_parse_output.json` |\n\n### Returns `ParseResponse`\n\n```\n.markdown          → string: full document as markdown\n.chunks[]          → Chunk: {id, type, markdown, grounding: {page, box}}\n.grounding         → Record<string, Grounding>: bounding boxes, confidence scores, and tableCell positions\n.splits[]          → Split: {chunks[], class, identifier, markdown, pages[]} — always present; contains a single \"full\" split by default, or per-page splits if split=\"page\"\n.metadata          → Metadata: {filename, org_id, page_count, duration_ms, credit_usage (float), version, job_id, failed_pages}\n```\n\n### Example\n\n```typescript\nconst response = await client.parse({\n  document: fs.createReadStream(\"./invoice.pdf\"),\n  model: \"dpt-2-latest\",\n  saveTo: \"./output\",\n});\n\nconsole.log(response.markdown);\nconsole.log(`${response.chunks.length} chunks, ${response.metadata.page_count} pages`);\n\nconst tables = response.chunks.filter(c => c.type === \"table\");\n```\n\n### Working with Chunks and Grounding\n\n```typescript\n// Filter by type and page\nconst tables = response.chunks.filter(c => c.type === \"table\");\nconst page0 = response.chunks.filter(c => c.grounding.page === 0);\n\n// Find table cells with positions\nconst tableCells = Object.entries(response.grounding)\n  .filter(([_, g]) => g.type === \"tableCell\")\n  .map(([id, g]) => ({ id, page: g.page, position: g.position! }));\n\ntableCells.forEach(cell => {\n  const { row, col, rowspan, colspan } = cell.position;\n  console.log(`Cell (${row},${col}) span ${rowspan}x${colspan}`);\n});\n```\n\n---\n\n## 2. Extract\n\nExtracts structured data from markdown using a JSON schema.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `schema` | `string` | Yes | JSON schema string (use `zodToJsonSchema()` from `zod-to-json-schema` to generate from Zod models) |\n| `markdown` | `Uploadable \\| string \\| null` | One required | Markdown content, string, or file |\n| `markdown_url` | `string \\| null` | One required | URL to markdown |\n| `model` | `string \\| null` | No | Model version (default: `extract-latest`) |\n| `saveTo` | `string` | No | Directory to save `{filename}_extract_output.json` |\n\n### Returns `ExtractResponse`\n\n```\n.extraction        → Record<string, any>: extracted key-value pairs matching schema\n.extraction_metadata → Record<string, {chunk_ids?: string[], cell_ids?: string[]}>: chunk and cell references for grounding\n.metadata          → Metadata: {credit_usage, duration_ms, filename, job_id, org_id, version, schema_violation_error, fallback_model_version}\n```\n\n### Using Zod for Schema Validation\n\n```typescript\nimport { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";  // separate npm package\n\nconst InvoiceSchema = z.object({\n  invoice_number: z.string().describe(\"Invoice number or ID\"),\n  total_amount: z.number().positive().describe(\"Total amount\"),\n  vendor_name: z.string().describe(\"Vendor name\"),\n  line_items: z.array(z.object({\n    description: z.string(),\n    quantity: z.number().int().positive(),\n    unit_price: z.number().positive(),\n    total: z.number().positive()\n  })).optional()\n});\n\n// Parse once, extract many\nconst parsed = await client.parse({ document: fs.createReadStream(\"./invoice.pdf\") });\n\nconst response = await client.extract({\n  markdown: parsed.markdown,\n  schema: JSON.stringify(zodToJsonSchema(InvoiceSchema)),\n});\n\n// Validate extracted data against Zod schema\nconst validated = InvoiceSchema.parse(response.extraction);\nconsole.log(`Invoice ${validated.invoice_number}: $${validated.total_amount}`);\n```\n\n### Grounding References (Tracing Back to Source)\n\n```typescript\nconst chunkMap = new Map(parsed.chunks.map(c => [c.id, c]));\n\nObject.entries(response.extraction).forEach(([field, value]) => {\n  const chunkIds = response.extraction_metadata[field]?.chunk_ids;\n  if (chunkIds?.length) {\n    const chunk = chunkMap.get(chunkIds[0]);\n    if (chunk) {\n      console.log(`${field}=${value} → page ${chunk.grounding.page}`);\n    }\n  }\n});\n```\n\n---\n\n## 3. Split\n\nClassifies and splits mixed documents by type.\n\n### Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `split_class` | `Array<{name: string, description?: string, identifier?: string}>` | Yes | Classification configuration |\n| `markdown` | `Uploadable \\| string \\| null` | One required | Markdown content or file |\n| `markdown_url` | `string \\| null` | One required | URL to markdown |\n| `model` | `string \\| null` | No | Model version (default: `split-latest`) |\n| `saveTo` | `string` | No | Directory to save `{filename}_split_output.json` |\n\n### Returns `SplitResponse`\n\n```\n.splits[]          → Split: {classification, identifier, markdowns[], pages[]}\n.metadata          → SplitMetadata: {filename, page_count, duration_ms, credit_usage, org_id, job_id, version}\n```\n\n### Split → Extract Pipeline\n\n```typescript\nconst parsed = await client.parse({ document: fs.createReadStream(\"./mixed_invoices.pdf\") });\n\nconst splitResponse = await client.split({\n  markdown: parsed.markdown,\n  split_class: [\n    { name: \"Invoice\", description: \"Sales invoice\", identifier: \"Invoice Number\" },\n    { name: \"Receipt\", description: \"Payment receipt\", identifier: \"Receipt Number\" },\n  ],\n});\n\nfor (const split of splitResponse.splits) {\n  console.log(`${split.classification}: ${split.identifier} (pages ${split.pages})`);\n}\n\n// Extract from each split\nconst schema = JSON.stringify(zodToJsonSchema(InvoiceSchema));\nconst results = [];\nfor (const split of splitResponse.splits) {\n  const extracted = await client.extract({ markdown: split.markdowns[0], schema });\n  results.push({ type: split.classification, id: split.identifier, data: extracted.extraction });\n}\n```\n\n---\n\n## 4. Parse Jobs (Async, Large Files)\n\nFor files >50MB or >50 pages, use asynchronous processing. Supports files up to **1 GB** or **6,000 pages**.\n\n### `parseJobs.create()` Arguments\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `document` | `Uploadable \\| null` | One required | Local file |\n| `document_url` | `string \\| null` | One required | Remote document URL |\n| `model` | `string \\| null` | No | Model version (default: `dpt-2-latest`) |\n| `split` | `\"page\" \\| null` | No | Split by pages |\n| `output_save_url` | `string \\| null` | If ZDR | URL for zero data retention output |\n\n### Returns `ParseJobCreateResponse`\n\n```\n.job_id            → string: unique job identifier\n```\n\n### `parseJobs.get(jobId)` Returns `ParseJobGetResponse`\n\n```\n.job_id            → string\n.status            → string: pending|processing|completed|failed|cancelled\n.progress          → number: 0.0 to 1.0\n.failure_reason    → string | undefined: error message if failed\n.data              → ParseResponse | undefined: full result when completed\n.output_url        → string | undefined: presigned URL if result >1MB (expires 1hr)\n.received_at       → number: Unix timestamp\n.org_id            → string\n.version           → string\n.metadata          → ParseMetadata | undefined\n```\n\n### `parseJobs.list()` Arguments & Returns\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `status` | `string` | No | Filter: `\"pending\" \\| \"processing\" \\| \"completed\" \\| \"failed\" \\| \"cancelled\"` |\n| `page` | `number` | No | Page number (0-indexed) |\n| `pageSize` | `number` | No | Items per page |\n\n```\n.jobs[]            → JobSummary: {job_id, status, progress, received_at, failure_reason}\n.has_more          → boolean\n```\n\n### Example\n\n```typescript\nconst job = await client.parseJobs.create({\n  document: fs.createReadStream(\"./large.pdf\"),\n});\nconsole.log(`Job ID: ${job.job_id}`);\n\nwhile (true) {\n  const status = await client.parseJobs.get(job.job_id);\n  console.log(`${status.status}: ${(status.progress * 100).toFixed(0)}%`);\n\n  if (status.status === \"completed\") {\n    const result = status.data!;  // ParseResponse\n    break;\n  }\n  if (status.status === \"failed\") {\n    throw new Error(`Job failed: ${status.failure_reason}`);\n  }\n\n  await new Promise(r => setTimeout(r, 5000));\n}\n```\n\n---\n\n## Error Handling\n\n### Error Classes\n\nAll errors inherit from `LandingAIADEError`. Import from `\"landingai-ade\"`:\n\n| Exception | HTTP Status | Description |\n|-----------|-------------|-------------|\n| `BadRequestError` | 400 | Invalid request due to malformed input or unsupported version |\n| `AuthenticationError` | 401 | Missing or invalid API key |\n| `UnprocessableEntityError` | 422 | Input validation failed |\n| `RateLimitError` | 429 | Rate limit exceeded |\n| `InternalServerError` | 5xx | Server error during processing |\n| `APIConnectionError` | — | Network failure |\n| `APIConnectionTimeoutError` | — | Request timeout (extends `APIConnectionError`) |\n\nNote: HTTP 206 (Partial Content) is returned as a successful response with `schema_violation_error` or `failed_pages` in metadata. HTTP 402 (Payment Required) indicates insufficient credits.\n\n### Retry with Fallback to Jobs\n\n```typescript\nimport {\n  RateLimitError,\n  APIConnectionTimeoutError,\n  AuthenticationError,\n  APIConnectionError,\n} from \"landingai-ade\";\n\nasync function robustParse(\n  client: LandingAIADE, filePath: string, maxRetries = 3\n): Promise<ParseResponse> {\n  for (let attempt = 0; attempt < maxRetries; attempt++) {\n    try {\n      return await client.parse({ document: fs.createReadStream(filePath) });\n    } catch (error) {\n      if (error instanceof RateLimitError) {\n        await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 10000));\n      } else if (error instanceof APIConnectionTimeoutError) {\n        console.log(\"Timeout — switching to parse jobs\");\n        return await parseLargeFile(client, filePath);\n      } else if (error instanceof AuthenticationError) {\n        throw error;  // Non-retryable\n      } else if (error instanceof APIConnectionError) {\n        await new Promise(r => setTimeout(r, 2000));\n      } else {\n        throw error;\n      }\n    }\n  }\n  throw new Error(\"Failed after retries\");\n}\n```\n\n---\n\n## Type Definitions\n\n```typescript\ninterface ParseResponse {\n  markdown: string;\n  chunks: Chunk[];\n  grounding: Record<string, Grounding>;\n  splits: Split[];  // Always present — contains a single \"full\" split by default\n  metadata: Metadata;\n}\n\ninterface Chunk {\n  id: string;\n  type: \"text\" | \"table\" | \"figure\" | \"marginalia\" | \"logo\" | \"card\" | \"attestation\" | \"scan_code\";\n  markdown: string;\n  grounding: { page: number; box: BoundingBox };\n}\n\ninterface BoundingBox {\n  left: number; top: number; right: number; bottom: number;  // 0-1 normalized\n}\n\ninterface Grounding {\n  type: string;\n  page: number;\n  box: BoundingBox;\n  confidence?: number;  // 0.0-1.0, not all types have this\n  low_confidence_spans?: Array<{ confidence: number; text: string; span: number[] }>;\n  position?: TablePosition;  // Only for tableCell type\n}\n\ninterface TablePosition {\n  row: number; col: number; rowspan: number; colspan: number; chunk_id: string;\n}\n\ninterface ExtractResponse {\n  extraction: Record<string, any>;\n  extraction_metadata: Record<string, { chunk_ids?: string[]; cell_ids?: string[] }>;\n  metadata: Metadata;\n}\n\ninterface SplitResponse {\n  splits: Split[];\n  metadata: Metadata;\n}\n\ninterface Split {\n  classification: string;\n  identifier: string | null;\n  markdowns: string[];\n  pages: number[];\n}\n\ninterface Metadata {\n  filename: string; org_id: string; page_count: number;\n  duration_ms: number; credit_usage: number; version: string;\n  job_id: string; failed_pages?: number[];\n}\n```\n\n### Type Guards\n\n```typescript\nfunction isTableChunk(chunk: Chunk): boolean {\n  return chunk.type === \"table\";\n}\n\nfunction isTableCell(\n  grounding: Grounding\n): grounding is Grounding & { position: TablePosition } {\n  return grounding.type === \"tableCell\" && grounding.position !== undefined;\n}\n\n// Usage\nObject.values(response.grounding).forEach(g => {\n  if (isTableCell(g)) {\n    console.log(`Cell at (${g.position.row}, ${g.position.col})`);\n  }\n});\n```\n\n---\n\n## API Reference\n\nThe following sections provide the complete API context so this document is fully self-contained.\n\n### Base Configuration\n\n| Region | Base URL |\n|--------|----------|\n| US (default) | `https://api.va.landing.ai/v1/ade` |\n| EU | `https://api.va.eu-west-1.landing.ai/v1/ade` |\n\n**Authentication**: All requests require `Authorization: Bearer $VISION_AGENT_API_KEY`\n\n### Quick Reference\n\n| Endpoint | Method | Path | Model | Input |\n|----------|--------|------|-------|-------|\n| Parse | POST | `/v1/ade/parse` | `dpt-2-latest` | `document` (file) or `document_url` |\n| Extract | POST | `/v1/ade/extract` | `extract-latest` | `markdown` (file/string) or `markdown_url` + `schema` |\n| Split | POST | `/v1/ade/split` | `split-latest` | `markdown` (file/string) or `markdown_url` + `split_class` |\n| Create Job | POST | `/v1/ade/parse/jobs` | `dpt-2-latest` | `document` or `document_url` |\n| Get Job | GET | `/v1/ade/parse/jobs/{id}` | — | — |\n| List Jobs | GET | `/v1/ade/parse/jobs` | — | `?status=&page=&pageSize=` |\n\n### Data Types\n\n#### Chunk Types\n- `text` — Characters, paragraphs, headings, lists, form fields, checkboxes, code blocks\n- `table` — Grid of rows and columns; includes spreadsheets and receipts\n- `figure` — Visual/graphical non-text content — images, graphs, flowcharts, diagrams\n- `marginalia` — Content in document margins — headers, footers, page numbers, handwritten notes\n- `logo` — Logos (DPT-2 only)\n- `card` — ID cards and driver's licenses (DPT-2 only)\n- `attestation` — Signatures, stamps, and seals (DPT-2 only)\n- `scan_code` — QR codes and barcodes (DPT-2 only)\n\n#### Grounding Types\n- Chunk grounding: `chunkText`, `chunkTable`, `chunkFigure`, `chunkMarginalia`, `chunkLogo`, `chunkCard`, `chunkAttestation`, `chunkScanCode`\n- Structure: `table`, `tableCell` (with position data)\n\n#### Bounding Box\nAll coordinates normalized 0–1: `{ left, top, right, bottom }`.\n\n#### Confidence Scores\nTop-level grounding entries may include `confidence` (float, 0.0–1.0) and `low_confidence_spans` (list of `{confidence, text, span}`). Not all entries have confidence (e.g., `table`/`tableCell` types may not).\n\n#### Table Cell Position\n`{ row, col, rowspan, colspan, chunk_id }` — zero-indexed.\n\n#### Table Chunk Formats\n\n**PDF/Image tables**: Element IDs use `{page}-{base62_seq}`. Grounding object has bounding boxes and `tableCell` entries.\n\n**Spreadsheet tables (XLSX/CSV)**: Element IDs use `{tab_name}-{cell_ref}` (e.g., `Sheet 1-B2`). **Grounding is null** — positions are encoded in IDs.\n\n### Error Codes\n\n| Status | Name | Description | Solution |\n|--------|------|-------------|----------|\n| 200 | Success | Request completed successfully | Continue with normal operations |\n| 206 | Partial Content | Parse: some pages failed (`metadata.failed_pages`). Extract: schema violation (`metadata.schema_violation_error`) | Review failed pages or schema violations; partial data returned, credits consumed |\n| 400 | Bad Request | Invalid request due to malformed input or unsupported version | Review error message for specific issue |\n| 401 | Unauthorized | Missing or invalid API key | Check VISION_AGENT_API_KEY |\n| 402 | Payment Required | Account does not have enough credits | Verify correct API key; add credits |\n| 422 | Unprocessable Entity | Input validation failed | Review request parameters and schema JSON |\n| 429 | Too Many Requests | Rate limit exceeded | Implement exponential backoff |\n| 500 | Internal Server Error | Server error during processing | Retry with backoff |\n| 504 | Gateway Timeout | Request exceeded timeout limit (475 seconds) | Reduce document size or use Parse Jobs API |\n\n### Supported File Types\n\n| Category | Formats | Notes |\n|----------|---------|-------|\n| **PDF** | PDF | Up to 100 pages in Playground (see rate limits for API); no password-protected files |\n| **Images** | JPEG, JPG, PNG, APNG, BMP, DCX, DDS, DIB, GD, GIF, ICNS, JP2, PCX, PPM, PSD, TGA, TIF, TIFF, WEBP | |\n| **Text Documents** | DOC, DOCX, ODT | Converted to PDF before parsing |\n| **Presentations** | ODP, PPT, PPTX | Converted to PDF before parsing |\n| **Spreadsheets** | CSV, XLSX | Up to 10 MB in Playground; no limit in API |\n\n> **Note:** Word, PowerPoint, and OpenDocument files are converted to PDF server-side before parsing.\n\n> **Spreadsheets** return a different response type (`SpreadsheetParseResponse`) — uses `sheet_count`/`total_rows`/`total_cells` instead of `page_count`, splits use `sheets` instead of `pages`, and top-level `grounding` is not present.\n\n### Model Versions\n\n| Model | Best For | Chunk Types |\n|-------|----------|-------------|\n| **`dpt-2-latest`** | Complex documents with logos, signatures, ID cards | text, table, figure, marginalia, logo, card, attestation, scan_code |\n| **`dpt-2-mini`** | Simple, digitally-native documents (faster, cheaper) | text, table, figure, marginalia |\n| **`dpt-1`** | ⚠️ **Deprecated March 31, 2026** — migrate to dpt-2 | text, table, figure, marginalia |\n\n| Operation | Current Version | Description |\n|-----------|----------------|-------------|\n| Extract | `extract-latest` (currently `extract-20251024`) | Schema-based extraction |\n| Split | `split-latest` | Document classification |\n\n**Version Pinning:** For production, use dated versions (e.g., `dpt-2-20251103`) for reproducibility.\n\n---\n\n## External Links\n\n- [TypeScript SDK Documentation](https://docs.landing.ai/ade/ade-typescript)\n- [TypeScript SDK GitHub](https://github.com/landing-ai/ade-typescript)\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/.env-sample",
    "content": "# LandingAI ADE API Key\n# Get your API key from: https://va.landing.ai/settings/api-key\nVISION_AGENT_API_KEY=your_api_key_here\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/.gitignore",
    "content": ".env\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/SKILL.md",
    "content": "---\nname: document-extraction\ndescription: Use this skill for intelligent document processing and content extraction using LandingAI's Agentic Document Extraction (ADE). Trigger when users need to (1) Parse documents (PDFs, images, spreadsheets, presentations) into structured Markdown with layout understanding, (2) Extract specific structured data from documents using schemas (invoice fields, form data, table data, etc.), (3) Classify and separate multi-document batches by type (invoices vs receipts, statements vs forms, etc.), (4) Process large documents asynchronously (up to 1GB/1000 pages), (5) Get visual grounding (bounding boxes, page numbers) for extracted content — use when users mention bounding boxes, word locations, grounding, highlighting extracted content, or showing where data appears in a document. Use this skill when the task involves understanding document content for a set of documents. In particular this skill can help you write code that run on sets of documents. This will increase speed, and reduce the cost of loading the documents on the Agent context window because you can use a single script to extract the information needed.\n---\n\n# Document Extraction (ADE)\n\n## Overview\n\nLandingAI's Agentic Document Extraction (ADE) is a document processing SaaS that parses, extracts, and classifies documents without requiring templates or training. It provides three main capabilities:\n\n1. **Parse**: Convert documents into structured Markdown with hierarchical JSON representation\n2. **Extract**: Pull specific structured data using JSON schemas or Pydantic models\n3. **Split**: Classify and separate multi-document batches by type\n\n**Key Benefits:**\n- No ML training or templates required\n- Layout-agnostic parsing (works with any document structure)\n- Supports 20+ file formats (PDF, images, spreadsheets, presentations)\n- Precise visual grounding (bounding boxes, page numbers)\n- Multiple models optimized for different document types\n\n## Quick Start\n\n### 1. Installation\n\nNever install packages globally without user approval. Always check for a local Python environment first.\n\n```\n1. .venv/bin/python       — uv-managed (this project)\n2. venv/bin/python        — standard Python venv\n3. uv run python          — if pyproject.toml exists\n4. poetry run python      — if poetry.lock exists\n5. python3                — system fallback; warn the user\n```\nUse the local environment to install: `landingai-ade`, `python-dotenv`\n\n### 2. API Key Setup\n\nThe user may have already setup a `.env` file in the same directory as the `document-extraction` skill with the API key. You MUST check this path first (ls -la .*/skills/document-extraction/.env). Also try checking on the same directory as this SKILL.md file.\n\nIf not, provide instructions to create one. The script below will search for `.env` in common locations and load it.\n\n```bash\n.venv/bin/python - << 'EOF'\nimport os\nfrom pathlib import Path\nfrom dotenv import load_dotenv\n\n# Load API key: prefer existing env var, then .env file lookup\nif os.environ.get(\"VISION_AGENT_API_KEY\"):\n    print(\"API key found in existing environment variable\")\nelse:\n    def _find_env():\n        for d in [Path.cwd().resolve(), *Path.cwd().resolve().parents]:\n            for candidate in [\n                # ADD the directory where the document-extraction skill is located\n                d / '.env',\n                d / 'document-extraction/.env',\n                d / 'skills/document-extraction/.env',\n            ]:\n                if candidate.is_file():\n                    return candidate\n        return None\n    env = _find_env()\n    if env:\n        load_dotenv(env)\n        print(f\"API key loaded from: {env}\")\n    else:\n        print(\"Warning: VISION_AGENT_API_KEY not set and no .env found\")\nEOF\n```\n\nIf not key is found instruct the user to get an API key from [https://va.landing.ai/settings/api-key](https://va.landing.ai/settings/api-key)\n\nCopy `.env-sample` to `.env` and add your API key:\n\n```bash\ncp .env-sample .env\n```\n\nEdit `.env` and add your key:\n```\nVISION_AGENT_API_KEY=your_actual_api_key_here\n```\n\n**Note:** The `.env` file is gitignored for security. Advanced users can also set the environment variable directly: `export VISION_AGENT_API_KEY=<your-key>`\n\n**EU Endpoint:** If using the EU endpoint, set `environment=\"eu\"` when initializing the client.\n\n### 3. Basic Parse Example\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()  # Load API key from .env\n\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Parse a document\nresponse = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Access results\nprint(f\"Pages: {response.metadata.page_count}\")\nprint(f\"Chunks: {len(response.chunks)}\")\nprint(\"\\nMarkdown output:\")\nprint(response.markdown[:500])  # First 500 chars\n\n# Save Markdown for extraction\nwith open(\"output.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(response.markdown)\n```\n\n### 4. Basic Extract Example\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom pydantic import BaseModel, Field\nfrom pathlib import Path\n\n# Define extraction schema using Pydantic\nclass Invoice(BaseModel):\n    invoice_number: str = Field(description=\"Invoice number\")\n    invoice_date: str = Field(description=\"Invoice date\")\n    total_amount: float = Field(description=\"Total amount in USD\")\n    vendor_name: str = Field(description=\"Vendor name\")\n\n# Convert to JSON schema\nschema = pydantic_to_json_schema(Invoice)\n\nclient = LandingAIADE()\n\n# Extract from parsed markdown\nresponse = client.extract(\n    schema=schema,\n    markdown=Path(\"output.md\"),  # From parse step\n    model=\"extract-latest\"\n)\n\n# Access extracted data\nprint(response.extraction)\n# Output: {'invoice_number': 'INV-12345', 'invoice_date': '2024-01-15', ...}\n\n# Check extraction metadata (traceability)\nprint(response.extraction_metadata)\n```\n\n## Document Parsing\n\n### Parse Local Files\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\nresponse = client.parse(\n    document=Path(\"/path/to/document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Work with chunks\nfor chunk in response.chunks:\n    print(f\"Type: {chunk.type}, Page: {chunk.grounding.page}\")\n    print(f\"Content: {chunk.markdown[:100]}...\")\n```\n\n### Parse Remote URLs\n\n```python\nresponse = client.parse(\n    document_url=\"https://example.com/document.pdf\",\n    model=\"dpt-2-latest\"\n)\n```\n\n### Parse Spreadsheets\n\nSpreadsheets (CSV, XLSX) return a **different response type** than documents. Key differences:\n\n| Field | Documents (`ParseResponse`) | Spreadsheets (`SpreadsheetParseResponse`) |\n|---|---|---|\n| `metadata.page_count` | ✓ | ✗ (uses `sheet_count`, `total_rows`, `total_cells`, `total_chunks`, `total_images`) |\n| `splits[].pages` | ✓ | ✗ (uses `sheets` — array of sheet indices) |\n| `grounding` (top-level) | ✓ | ✗ (not present for spreadsheets) |\n| Chunk grounding | Always present | Optional (null for table chunks, present for embedded image chunks) |\n\n```python\nresponse = client.parse(\n    document=Path(\"data.xlsx\"),\n    model=\"dpt-2-latest\"\n)\n\n# Spreadsheet metadata\nprint(f\"Sheets: {response.metadata.sheet_count}\")\nprint(f\"Total rows: {response.metadata.total_rows}\")\nprint(f\"Total cells: {response.metadata.total_cells}\")\n\n# Splits use 'sheets' instead of 'pages'\nfor split in response.splits:\n    print(f\"Sheet indices: {split.sheets}\")\n    print(f\"Markdown: {split.markdown[:200]}...\")\n```\n\n### Model Selection\n\nChoose the right model for your documents:\n\n| Model | Best For | Chunk Types |\n|-------|----------|-------------|\n| **dpt-2-latest** | Complex documents with logos, signatures, ID cards | text, table, figure, logo, card, attestation, scan_code, marginalia |\n| **dpt-2-mini** | Simple, digitally-native documents (faster, cheaper) | text, table, figure, marginalia |\n| **dpt-1** | ⚠️ **Deprecated March 31, 2026** — migrate to dpt-2 | text, table, figure, marginalia |\n\n**Recommendation:** Use `dpt-2-latest` unless you have simple documents where cost/speed is critical.\n\n**Version Pinning:** For production, use dated versions (e.g., `dpt-2-20260302`) for reproducibility.\n\n### Parse Large Files (Async)\n\nFor files up to 1 GB or 6,000 pages, use Parse Jobs:\n\n```python\nimport time\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Step 1: Create parse job\njob = client.parse_jobs.create(\n    document=Path(\"large_document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\njob_id = job.job_id\nprint(f\"Job {job_id} created\")\n\n# Step 2: Poll for completion\nwhile True:\n    response = client.parse_jobs.get(job_id)\n    if response.status == \"completed\":\n        print(f\"Job {job_id} completed\")\n        break\n    print(f\"Progress: {response.progress * 100:.0f}%\")\n    time.sleep(5)\n\n# Step 3: Access results\n# Results are in response.data (or response.output_url for large results)\nif response.data:\n    print(f\"Chunks: {len(response.data.chunks)}\")\n    with open(\"output.md\", \"w\", encoding=\"utf-8\") as f:\n        f.write(response.data.markdown)\nelif response.output_url:\n    # Results > 1MB are returned as a presigned URL\n    print(f\"Download results from: {response.output_url}\")\n```\n\n**Job Status Response Fields:**\n- `job_id`, `status` (pending, processing, completed, failed, cancelled), `progress` (0-1)\n- `data`: The `ParseResponse` (or `SpreadsheetParseResponse`) when complete and result < 1MB\n- `output_url`: Presigned S3 URL when result > 1MB or when `output_save_url` was used. Expires after 1 hour; a new URL is generated on each GET.\n- `metadata`: Same as sync parse (`filename`, `page_count`, `duration_ms`, etc.)\n- `failure_reason`: Error message if job failed\n\n### Zero Data Retention (ZDR)\n\nIf ZDR is enabled for your organization, you must provide an `output_save_url` where parsed results will be saved. The results will not be returned in the API response. ZDR is not enabled by default. Typically `output_save_url` is a presigned url with write permissions to your S3 bucket, but you can also use other storage solutions that support file uploads via HTTP PUT requests.\n\n```python\njob = client.parse_jobs.create(\n    document=Path(\"sensitive_document.pdf\"),\n    model=\"dpt-2-latest\",\n    output_save_url=\"https://your-bucket.s3.amazonaws.com/output.json\"\n)\n```\n\n### List Parse Jobs\n\nList all async parse jobs with optional pagination and status filtering:\n\n```python\n# List recent jobs\njobs_response = client.parse_jobs.list(page=0, page_size=10)\nfor job in jobs_response.jobs:\n    print(f\"{job.job_id}: {job.status} ({job.progress:.0%})\")\n\n# Filter by status\ncompleted = client.parse_jobs.list(status=\"completed\", page_size=5)\nprint(f\"Completed jobs: {len(completed.jobs)}, more: {completed.has_more}\")\n```\n\n**Available status filters:** `pending`, `processing`, `completed`, `failed`, `cancelled`\n\n### Understanding Parse Outputs\n\nParse returns a `ParseResponse` with:\n\n- **`markdown`**: Complete document in Markdown with HTML anchor tags\n- **`chunks`**: Array of extracted elements (each with unique ID, type, content, and per-chunk grounding)\n- **`grounding`**: Dictionary mapping element IDs to detailed location data (page, bounding box, grounding type, and table cell position). See [JSON Response](#json-response) for structure.\n- **`metadata`**: Processing info — `filename`, `org_id`, `page_count`, `duration_ms`, `credit_usage` (float), `job_id`, `version`, `failed_pages`\n- **`splits`**: Array of split objects grouping chunks. Always present — contains a single `\"full\"` split by default, or per-page splits if `split=\"page\"` was used. **Note:** Parse splits use a `class` field (values: `\"full\"` or `\"page\"`), which is different from the Split API's `classification` field.\n\n**Common chunk types**: `text`, `table`, `figure`, `logo`, `card`, `attestation`, `scan_code`, `marginalia`\n\nFor detailed chunk type reference, see [references/chunk-types.md](references/chunk-types.md)\n\n> **Anchor tag prefix in `chunk.markdown`:** Every chunk's `markdown` field\n> is prefixed with an HTML anchor tag embedding the chunk UUID:\n> `<a id='abc123...'></a>\\n\\nActual content…`. This is how the full document\n> markdown links back to individual chunks. Strip it before string matching,\n> display, or RAG indexing:\n>\n> ```python\n> import re\n> _ANCHOR_RE = re.compile(r\"<a[^>]*></a>\\s*\", re.IGNORECASE)\n>\n> def chunk_text(ch) -> str:\n>     \"\"\"Return clean chunk markdown without the anchor prefix.\"\"\"\n>     return _ANCHOR_RE.sub(\"\", ch.markdown or \"\").strip()\n>\n> # Example: fingerprint match against a section of the full markdown\n> intro_chunks = [ch for ch in response.chunks\n>                 if chunk_text(ch)[:80] in intro_markdown]\n> ```\n\n### Saving Parse Responses\n\nThe SDK provides a built-in `save_to` parameter on `parse()`, `extract()`, and `split()` that automatically saves the JSON response to a folder:\n\n```python\nfrom pathlib import Path\n\n# Parse and auto-save response JSON to output/ folder\nresponse = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\",\n    save_to=\"output/\"  # Creates output/document_parse_output.json\n)\n\n# Response is still returned normally for immediate use\nprint(response.markdown[:200])\n```\n\nThe `save_to` parameter:\n- Creates the folder if it doesn't exist\n- Names the file `{input_filename}_{method}_output.json` (e.g., `document_parse_output.json`)\n- Works on `client.parse()`, `client.extract()`, and `client.split()`\n- Is a **client-side convenience** — it saves the full response locally after the API call\n\nFor manual serialization (e.g., custom filenames or selective saving), use `model_dump()`:\n\n```python\nimport json\n\nresponse_dict = response.model_dump()\nwith open(\"parse_response.json\", \"w\", encoding=\"utf-8\") as f:\n    json.dump(response_dict, f, indent=2, ensure_ascii=False)\n\n# Save markdown separately for extraction\nwith open(\"document_parsed.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(response.markdown)\n```\n\n**Important:** Always use `model_dump()` to serialize the complete response. Do not manually construct dictionaries with selected fields, as you may miss important data like the `splits` array or complete grounding information.\n\n### Parse Parameters\n\n```python\nresponse = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\",\n    split=\"page\",       # Optional: organize chunks by page\n    password=\"secret\",   # Optional: decrypt protected files (ZDR only)\n    save_to=\"output/\",   # Optional: auto-save response JSON\n)\n```\n\n### Parse Password-Protected Files\n\nOrganizations with [Zero Data Retention (ZDR)](https://docs.landing.ai/ade/zdr) enabled can parse password-protected files by passing the `password` parameter. Supported formats: PDF, DOC, DOCX, ODT, PPT, PPTX, XLSX.\n\n```python\n# Sync parse\nresponse = client.parse(\n    document=Path(\"encrypted.pdf\"),\n    password=\"document_password\",\n    model=\"dpt-2-latest\"\n)\n\n# Async parse jobs\njob = client.parse_jobs.create(\n    document=Path(\"encrypted.pdf\"),\n    password=\"document_password\",\n    model=\"dpt-2-latest\"\n)\n```\n\n> **Note:** Without ZDR the API returns HTTP 422. If the password is wrong the API\n> returns HTTP 422 with a decryption error. The parameter is ignored for unencrypted documents.\n\n## Structured Data Extraction\n\n### Schema Definition\n\nDefine what to extract using JSON Schema or Pydantic models.\n\n**Pydantic approach (recommended for Python):**\n\n```python\nfrom pydantic import BaseModel, Field\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclass BankStatement(BaseModel):\n    account_holder: str = Field(description=\"Account holder name\")\n    account_number: str = Field(description=\"Account number\")\n    beginning_balance: float = Field(description=\"Beginning balance in USD\")\n    ending_balance: float = Field(description=\"Ending balance in USD\")\n\nschema = pydantic_to_json_schema(BankStatement)\n```\n\n**JSON Schema approach:**\n\n```python\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"account_holder\": {\n            \"type\": \"string\",\n            \"description\": \"Account holder name\"\n        },\n        \"account_number\": {\n            \"type\": \"string\",\n            \"description\": \"Account number\"\n        },\n        \"beginning_balance\": {\n            \"type\": \"number\",\n            \"description\": \"Beginning balance in USD\"\n        },\n        \"ending_balance\": {\n            \"type\": \"number\",\n            \"description\": \"Ending balance in USD\"\n        }\n    },\n    \"required\": [\"account_holder\", \"account_number\"]\n}\n```\n\n### Extraction Workflow\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Step 1: Parse document\nparse_response = client.parse(\n    document=Path(\"bank_statement.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Save markdown\nwith open(\"parsed.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(parse_response.markdown)\n\n# Step 2: Extract structured data\nextract_response = client.extract(\n    schema=schema,  # Your JSON schema\n    markdown=Path(\"parsed.md\"),\n    model=\"extract-latest\"\n)\n\n# Access extracted data\nprint(extract_response.extraction)\n\n# Check traceability (which chunks provided each field)\nfor field, metadata in extract_response.extraction_metadata.items():\n    print(f\"{field}: from chunks {metadata.chunk_ids}\")\n```\n\n### Extract from URL\n\nYou can extract from a remotely-hosted Markdown file using `markdown_url`:\n\n```python\nextract_response = client.extract(\n    schema=schema,\n    markdown_url=\"https://example.com/parsed_document.md\",\n    model=\"extract-latest\"\n)\n```\n\n### Common Schema Patterns\n\nFor detailed schema patterns, see [references/extraction-schemas.md](references/extraction-schemas.md)\n\n**Nested objects:**\n```python\nclass Address(BaseModel):\n    street: str\n    city: str\n    zip_code: str\n\nclass Invoice(BaseModel):\n    invoice_number: str\n    billing_address: Address  # Nested object\n```\n\n**Arrays (lists):**\n```python\nclass LineItem(BaseModel):\n    description: str\n    quantity: int\n    amount: float\n\nclass Invoice(BaseModel):\n    invoice_number: str\n    line_items: list[LineItem]  # Array of objects\n```\n\n**Enums (restricted values):**\n```python\nclass BankStatement(BaseModel):\n    account_type: str = Field(\n        description=\"Account type\",\n        enum=[\"Checking\", \"Savings\"]  # Only these values allowed\n    )\n```\n\n**Nullable fields:**\n```python\nclass Patient(BaseModel):\n    first_name: str\n    middle_name: str | None = Field(default=None)  # Optional field\n    last_name: str\n```\n\n### Document Classification\n\nClassify documents before extracting type-specific fields:\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom pydantic import BaseModel, Field\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom pathlib import Path\n\n# Step 1: Define classification schema\nclass DocumentType(BaseModel):\n    document_type: str = Field(\n        description=\"Document classification\",\n        enum=[\"Invoice\", \"Receipt\", \"Bank Statement\", \"Other\"]\n    )\n\nclient = LandingAIADE()\n\n# Step 2: Parse document\nparse_response = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Step 3: Classify document\nclassification_schema = pydantic_to_json_schema(DocumentType)\nclassification_response = client.extract(\n    schema=classification_schema,\n    markdown=parse_response.markdown,\n    model=\"extract-latest\"\n)\n\ndoc_type = classification_response.extraction[\"document_type\"]\nprint(f\"Classified as: {doc_type}\")\n\n# Step 4: Extract based on type\nif doc_type == \"Invoice\":\n    schema = pydantic_to_json_schema(InvoiceSchema)\nelif doc_type == \"Receipt\":\n    schema = pydantic_to_json_schema(ReceiptSchema)\nelse:\n    print(\"Unsupported document type\")\n    exit()\n\n# Extract type-specific fields\nextract_response = client.extract(\n    schema=schema,\n    markdown=parse_response.markdown,\n    model=\"extract-latest\"\n)\n```\n\n## Document Classification & Splitting\n\n### When to Use Split API\n\nUse the Split API when you have multi-document batches on  single file that need to be separated:\n\n- Financial services: Separate bank statements, utility bills, ID documents\n- Healthcare: Split intake forms, medical reports, medication lists\n- Accounting: Separate multiple invoices and receipts\n- Academic: Separate article bodies from references\n\n### Split Classification\n\nDefine how to classify and separate documents using `split_class`:\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Step 1: Parse multi-document PDF\nparse_response = client.parse(\n    document=Path(\"batch.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Step 2: Define split classes\nsplit_classes = [\n    {\n        \"name\": \"Invoice\",\n        \"description\": \"Commercial invoices with itemized charges\",\n        \"identifier\": \"Invoice Number\"  # Separate by invoice number\n    },\n    {\n        \"name\": \"Receipt\",\n        \"description\": \"Payment receipts showing transaction details\",\n        \"identifier\": \"Receipt Date\"\n    },\n    {\n        \"name\": \"Bank Statement\",\n        \"description\": \"Monthly bank account statements\"\n    }\n]\n\n# Step 3: Split document\nsplit_response = client.split(\n    markdown=parse_response.markdown,\n    split_class=split_classes\n)\n\n# Step 4: Process each split\nfor split in split_response.splits:\n    print(f\"Type: {split.classification}\")\n    print(f\"Identifier: {split.identifier}\")\n    print(f\"Pages: {split.pages}\")\n    print(f\"Content: {split.markdowns[0][:200]}...\")\n```\n\n**Split Class Components:**\n- **name** (required): Document classification label (e.g., \"Invoice\")\n- **description** (optional): Context for classification (more detail = better accuracy)\n- **identifier** (optional): Field that makes each instance unique (creates separate split per unique value)\n- **Limit:** Maximum 19 split classes per request\n\n**Split from URL:** You can also split from a remotely-hosted Markdown file:\n\n```python\nsplit_response = client.split(\n    markdown_url=\"https://example.com/parsed_document.md\",\n    split_class=split_classes\n)\n```\n\n## Output Formats\n\n### Markdown\n\nADE converts documents to structured Markdown:\n\n```markdown\n# Document Title\n\n## Section 1\n\nParagraph text...\n\n| Column 1 | Column 2 |\n|----------|----------|\n| Data 1   | Data 2   |\n\n<::Caption: Bar chart showing quarterly revenue::>\n```\n\n**Features:**\n- HTML anchor tags for traceability (link to chunk IDs)\n- Special delimiters for visual elements: `<::Caption: description::>`\n- HTML tables for spreadsheet data\n- Preserved structure and hierarchy\n\n### JSON Response\n\nParse returns structured JSON with five top-level fields:\n\n```json\n{\n  \"markdown\": \"# Document...\",\n  \"chunks\": [\n    {\n      \"id\": \"7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506\",\n      \"type\": \"text\",\n      \"markdown\": \"Content...\",\n      \"grounding\": {\n        \"page\": 0,\n        \"box\": { \"left\": 0.1, \"top\": 0.2, \"right\": 0.9, \"bottom\": 0.3 }\n      }\n    }\n  ],\n  \"splits\": [\n    {\n      \"class\": \"full\",\n      \"identifier\": \"full\",\n      \"pages\": [0],\n      \"markdown\": \"# Document...\",\n      \"chunks\": [\"7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506\"]\n    }\n  ],\n  \"grounding\": {\n    \"7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506\": {\n      \"box\": { \"left\": 0.1, \"top\": 0.2, \"right\": 0.9, \"bottom\": 0.3 },\n      \"page\": 0,\n      \"type\": \"chunkText\",\n      \"confidence\": 0.95,\n      \"low_confidence_spans\": []\n    },\n    \"0-1\": {\n      \"box\": { \"left\": 0.15, \"top\": 0.4, \"right\": 0.85, \"bottom\": 0.7 },\n      \"page\": 0,\n      \"type\": \"table\"\n    },\n    \"0-2\": {\n      \"box\": { \"left\": 0.15, \"top\": 0.4, \"right\": 0.5, \"bottom\": 0.55 },\n      \"page\": 0,\n      \"type\": \"tableCell\",\n      \"position\": { \"row\": 0, \"col\": 0, \"rowspan\": 1, \"colspan\": 1,\n                     \"chunk_id\": \"ef24b1ea-...\" }\n    }\n  },\n  \"metadata\": {\n    \"filename\": \"document.pdf\",\n    \"org_id\": \"org-123\",\n    \"page_count\": 5,\n    \"duration_ms\": 1500,\n    \"credit_usage\": 2.0,\n    \"job_id\": \"abc-123\",\n    \"version\": \"dpt-2-20260302\",\n    \"failed_pages\": []\n  }\n}\n```\n\n**Top-level `grounding`** is a dictionary keyed by element ID (UUID for chunks, `{page}-{base62}` for tables/cells). Each value contains `box`, `page`, `type`, and optionally `confidence` and `low_confidence_spans` (see [Confidence Scores](#confidence-scores)). Table cell entries also include a `position` field (see [Grounding and Traceability](#grounding-and-traceability)).\n\n#### Grounding Type Mapping\n\nGrounding types use a `chunk` prefix to distinguish them from chunk types. The `table` and `tableCell` types are grounding-only (no corresponding chunk type):\n\n| Grounding Type | Chunk Type | Description |\n|---|---|---|\n| `chunkText` | `text` | Text content |\n| `chunkTable` | `table` | Table chunk (overall location) |\n| `chunkFigure` | `figure` | Figures and images |\n| `chunkMarginalia` | `marginalia` | Headers, footers, page numbers |\n| `chunkLogo` | `logo` | Company logos (DPT-2) |\n| `chunkCard` | `card` | ID cards, licenses (DPT-2) |\n| `chunkAttestation` | `attestation` | Signatures, stamps (DPT-2) |\n| `chunkScanCode` | `scan_code` | QR codes, barcodes (DPT-2) |\n| `table` | _(grounding only)_ | HTML `<table>` element within a table chunk |\n| `tableCell` | _(grounding only)_ | Individual cell within a table |\n\nExtract returns:\n\n```json\n{\n  \"extraction\": {\n    \"invoice_number\": \"INV-12345\",\n    \"total\": 1250.00\n  },\n  \"extraction_metadata\": {\n    \"invoice_number\": {\n      \"chunk_ids\": [\"chunk-uuid-1\"]\n    },\n    \"total\": {\n      \"chunk_ids\": [\"chunk-uuid-2\"],\n      \"cell_ids\": [\"2-a5\"]\n    }\n  },\n  \"metadata\": {\n    \"filename\": \"markdown.md\",\n    \"org_id\": \"org-123\",\n    \"duration_ms\": 850,\n    \"credit_usage\": 1.0,\n    \"job_id\": \"abc-456\",\n    \"version\": \"extract-20251024\",\n    \"schema_violation_error\": null,\n    \"fallback_model_version\": null\n  }\n}\n```\n\n**Extract Metadata Fields:**\n- **`schema_violation_error`**: `null` when extraction matches schema. Contains a detailed error message when the extracted data doesn't fully conform (HTTP 206 response). Extraction still returns partial data and consumes credits.\n- **`fallback_model_version`**: `null` normally. Contains the model version actually used when the initial extraction attempt failed with the requested version and a fallback was used.\n\n### Grounding and Traceability\n\nEvery parsed element includes precise location information in the top-level `grounding` dictionary:\n\n- **Page references**: Zero-indexed page numbers\n- **Bounding boxes**: Normalized coordinates (0-1) for position\n  - `left`, `top`, `right`, `bottom`\n  - Convert to pixels: multiply by image dimensions\n- **Element IDs**: UUID for chunks, `{page}-{base62}` for tables and table cells\n  - Table/cell IDs use sequential base62 numbering per page: `0-1`, `0-2`, ..., `0-9`, `0-a`, ..., `0-z`, `0-A`, ..., `0-Z`, `0-10`, etc.\n  - Numbering restarts on each page (e.g., first table on page 1 → `1-1`)\n- **Grounding types**: Each entry has a `type` field using prefixed names (e.g., `chunkText`, `chunkTable`). See [Grounding Type Mapping](#grounding-type-mapping).\n- **Table cell position**: `tableCell` entries include a `position` object with `row`, `col` (zero-indexed), `rowspan`, `colspan`, and `chunk_id` (the parent table chunk UUID)\n- **Extraction metadata**: Shows which chunks/cells provided each field\n\n**Per-chunk grounding** (on each chunk object) contains only `box` and `page`. The **top-level grounding dictionary** adds `type` and, for table cells, `position`.\n\n**Example:**\n```python\n# Per-chunk grounding (basic location)\nfor chunk in response.chunks:\n    print(f\"Chunk {chunk.id} on page {chunk.grounding.page}\")\n    bbox = chunk.grounding.box\n    print(f\"Location: ({bbox.left}, {bbox.top}) to ({bbox.right}, {bbox.bottom})\")\n\n# Top-level grounding (detailed, with type and position)\n# NOTE: grounding values are Pydantic models — use attribute access, not dict access\nfor elem_id, info in response.grounding.items():\n    print(f\"{elem_id}: type={info.type}, page={info.page}\")\n    if info.type == \"tableCell\" and info.position:\n        print(f\"  Cell at row={info.position.row}, col={info.position.col}\")\n```\n\n> **Important:** `response.grounding` is a `Dict[str, Grounding]` — the outer container is a dict (so `.items()`, `.get()` work), but each **value** is a Pydantic model. Use **attribute access** (`info.type`, `info.box.left`) not dict access (`info[\"type\"]`).\n\n### Confidence Scores {#confidence-scores}\n\nTop-level grounding entries may include confidence information:\n\n- **`confidence`** (`float | None`): Overall confidence score (0.0–1.0) for the chunk's transcription\n- **`low_confidence_spans`** (`list | None`): Specific text spans with low confidence, each containing:\n  - `confidence` (`float`): Span-level confidence score\n  - `text` (`str`): The low-confidence text\n  - `span` (`list`): Position markers within the chunk\n\n```python\n# Access confidence scores from top-level grounding\nfor elem_id, info in response.grounding.items():\n    if info.confidence is not None:\n        print(f\"{elem_id}: confidence={info.confidence:.2f}\")\n    for span in info.low_confidence_spans or []:\n        print(f\"  Low confidence ({span.confidence:.2f}): \"\n              f\"'{span.text}'\")\n```\n\n**Notes:**\n- Confidence is only present in **top-level grounding** (not per-chunk grounding)\n- Not all grounding entries will have confidence (e.g., `table`/`tableCell` types may not)\n- Use confidence scores to flag chunks that may need human review\n\n## Best Practices\n\n### Model Selection\n\n- **Use dpt-2-latest** for most documents (complex layouts, logos, signatures)\n- **Use dpt-2-mini** for simple, digitally-native documents (faster, cheaper)\n- **Pin versions in production** for reproducibility (e.g., `dpt-2-20260302`)\n- **Use extract-latest** for extraction (automatically uses newest model)\n- **Do NOT use dpt-1** — deprecated March 31, 2026; migrate to dpt-2\n\n### Schema Design\n\n- **Be specific**: Use descriptive field names (`invoice_number` not `number`)\n- **Add descriptions**: Include format requirements (\"in USD\", \"as YYYY-MM-DD\")\n- **Keep it simple**: Start with few fields, add more as needed\n- **Limit complexity**: Under 30 properties for optimal performance\n- **Match document structure**: Order fields as they appear in document\n\nFor detailed schema patterns, see [references/extraction-schemas.md](references/extraction-schemas.md)\n\n### Error Handling\n\n```python\ntry:\n    response = client.parse(document=Path(\"doc.pdf\"), model=\"dpt-2-latest\")\nexcept Exception as e:\n    print(f\"Parse error: {e}\")\n    # Handle error (check file format, file size, API key, etc.)\n\ntry:\n    extract_response = client.extract(schema=schema, markdown=response.markdown)\nexcept Exception as e:\n    print(f\"Extract error: {e}\")\n    # Handle error (check schema validity, markdown format, etc.)\n```\n\n### Handling Partial Results (HTTP 206)\n\nBoth Parse and Extract APIs can return HTTP 206 (Partial Content) when processing partially succeeds:\n\n**Parse 206**: Some pages failed to parse. Check `metadata.failed_pages`:\n```python\nresponse = client.parse(document=Path(\"doc.pdf\"), model=\"dpt-2-latest\")\nif response.metadata.failed_pages:\n    print(f\"Failed pages: {response.metadata.failed_pages}\")\n    # Remaining pages were parsed successfully\n```\n\n**Extract 206**: Extraction completed but data doesn't fully match schema. Check `metadata.schema_violation_error`:\n```python\nresponse = client.extract(schema=schema, markdown=markdown)\nerr = response.metadata.schema_violation_error\nif err:\n    print(f\"Schema violation: {err}\")\n    # Extraction still returns partial data; credits are consumed\n```\n\n**Note:** 206 responses still consume credits. The API returns the best results it could produce.\n\n### Performance\n\n- **Large files**: Use Parse Jobs API (async) for files > 50 pages or > 10 MB\n- **Batch processing**: Process documents in parallel when possible\n- **Cache parse results**: Save markdown to avoid re-parsing for multiple extractions\n- **Optimize parsing**: Use the `split=\"page\"` parameter when you need page-level organization\n\n### File Formats\n\n- **Prefer PDF** for native documents (no conversion needed)\n- **Use high-resolution images** (300+ DPI) for better OCR\n- **Password-protected files**: Use the `password` parameter (requires ZDR). Without ZDR, remove password protection before parsing\n- **Test conversion** for DOCX/PPTX files (layout may change)\n\nFor complete file format reference, see [references/file-formats.md](references/file-formats.md)\n\n## Use Cases\n\nSee [references/use-cases.md](references/use-cases.md) for complete worked examples: invoice processing, form data extraction, multi-document classification, table extraction, and figure cropping with PyMuPDF.\n\n## Troubleshooting\n\nSee [references/troubleshooting.md](references/troubleshooting.md) for HTTP error codes, parse failures, extraction accuracy issues, schema validation errors, and performance guidance.\n\n## Links\n\n### Official Documentation\n- [LandingAI ADE Documentation](https://docs.landing.ai/ade/)\n- [Parse API Reference](https://docs.landing.ai/api-reference/tools/ade-parse)\n- [Extract API Reference](https://docs.landing.ai/api-reference/tools/ade-extract)\n- [Split API Reference](https://docs.landing.ai/api-reference/tools/ade-split)\n- [Python Library (GitHub)](https://github.com/landing-ai/ade-python)\n\n### API Key\n- [Get API Key](https://va.landing.ai/settings/api-key)\n\n### Reference Files\n- [Extraction Schema Patterns](references/extraction-schemas.md) - Detailed schema examples\n- [Chunk Types Reference](references/chunk-types.md) - Complete chunk type guide\n- [File Formats](references/file-formats.md) - Supported formats and considerations\n- [Use Cases](references/use-cases.md) - Worked examples for invoices, forms, tables, and figure extraction\n- [Troubleshooting](references/troubleshooting.md) - HTTP error codes and common issues\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/references/chunk-types.md",
    "content": "# Chunk Types Reference\n\n## Overview\n\nA **chunk** is a discrete element extracted from a document during parsing. When you send a document to ADE, it analyzes the content, breaks it down into meaningful elements, and returns each as a chunk with structured metadata describing its content and location.\n\n## What is Semantic Chunking?\n\nADE uses **semantic chunking**, which intelligently groups content based on meaning rather than just layout or formatting. Instead of splitting at arbitrary points (like fixed lengths or paragraph breaks), ADE identifies coherent units of information and extracts them as individual chunks.\n\n**Benefits:**\n- Enables efficient processing of large documents (avoids token limits)\n- Improves retrieval granularity for downstream tasks\n- Supports semantic search and embeddings\n- Maintains human readability and logical relationships\n\n## Chunk Type Comparison by Model\n\n| Chunk Type | DPT-1 ⚠️ | DPT-2 | Confidence | Description |\n|------------|-----------|-------|------------|-------------|\n| text | ✓ | ✓ | ✓ | Paragraphs, headings, lists, forms, code |\n| table | ✓ | ✓ | ✗ | Grids of data, receipts, spreadsheets |\n| figure | ✓ | ✓ | ✓ | Images, graphs, flowcharts, diagrams |\n| marginalia | ✓ | ✓ | ✓ | Headers, footers, page numbers, margin notes |\n| logo | ✗ | ✓ | ✓ | Company logos |\n| card | ✗ | ✓ | ✓ | ID cards, driver licenses |\n| attestation | ✗ | ✓ | ✓ | Signatures, stamps, seals |\n| scan_code | ✗ | ✓ | ✓ | QR codes, barcodes |\n\n> ⚠️ **DPT-1 Deprecation:** DPT-1 will be removed on **March 31, 2026**. Migrate to DPT-2 now.\n\n**Note:** DPT-2 provides more granular chunk types. In DPT-1, logos, QR codes, barcodes, stamps, signatures, and ID cards are all classified as `figure`. The **Confidence** column indicates which chunk types support confidence scores in top-level grounding (Preview feature).\n\n## Chunk Type Details\n\n### text\n\n**Description:** Content consisting entirely of characters (letters and numbers).\n\n**Includes:**\n- Paragraphs\n- Titles and headings\n- Lists (bulleted, numbered)\n- Form fields\n- Checkboxes and radio buttons\n- Equations\n- Code blocks\n- Handwritten text\n\n**Key-Value Pairs:** If text contains form fields with key-value pairs, the extracted data is returned as key-value pairs separated by line breaks (`\\n`).\n\n**Example Output:**\n```markdown\n## Solar Energy Benefits\n\nSolar energy is a renewable and clean source of power that has numerous advantages:\n- Reduces electricity bills\n- Environmentally friendly\n- Low maintenance costs\n- Energy independence\n```\n\n### table\n\n**Description:** Grids of rows and columns containing data.\n\n**Includes:**\n- Traditional tables with gridlines\n- Well-aligned data without gridlines (e.g., receipt line items)\n- Spreadsheet data\n\n**Note:** ADE doesn't require gridlines to be present. It interprets well-aligned sets of data as tables.\n\n**Example Output:**\n```markdown\n| Item | Quantity | Price |\n|------|----------|-------|\n| Coffee | 2 | $5.00 |\n| Sandwich | 1 | $8.50 |\n| **Total** | | **$13.50** |\n```\n\n### marginalia\n\n**Description:** Text in the top, bottom, or side margins of a document.\n\n**Includes:**\n- Page headers\n- Page footers\n- Page numbers\n- Handwritten notes in margins\n- Line numbers\n\n**Example Output:**\n```markdown\n_Confidential Report - Page 3_\n```\n\n### figure\n\n**Description:** Visual or graphical non-text content.\n\n**Includes:**\n- Pictures and photographs\n- Graphs (bar, line, pie charts)\n- Flowcharts\n- Diagrams\n\n**DPT-1 also includes:** logos, QR codes, barcodes, stamps, signatures, ID cards (these have dedicated types in DPT-2)\n\n**Example Output:**\n```markdown\n<::Caption: Bar chart showing quarterly revenue growth from Q1 to Q4::>\n```\n\n### logo\n\n**Description:** Company logos and branding elements.\n\n**Availability:** DPT-2 only\n\n**Example Output:**\n```markdown\n<::Caption: Landing AI logo::>\n```\n\n### card\n\n**Description:** Identification cards and licenses.\n\n**Includes:**\n- ID cards\n- Driver licenses\n\n**Availability:** DPT-2 only\n\n**Example Output:**\n```markdown\n<::Caption: Driver's license with photo and personal information::>\n```\n\n### attestation\n\n**Description:** Elements that serve as authentication or approval.\n\n**Includes:**\n- Signatures (handwritten or digital)\n- Stamps\n- Seals\n\n**Availability:** DPT-2 only\n\n**Example Output:**\n```markdown\n<::Caption: Handwritten signature::>\n```\n\n### scan_code\n\n**Description:** Machine-readable codes.\n\n**Includes:**\n- QR codes\n- Barcodes (UPC, Code 39, Code 128, etc.)\n\n**Availability:** DPT-2 only\n\n**Example Output:**\n```markdown\n<::Caption: Barcode::>\n```\n\n## Working with Chunks\n\n### Accessing Chunks in Python\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\nresponse = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n\n# Access all chunks\nfor chunk in response.chunks:\n    print(f\"Type: {chunk.type}\")\n    print(f\"ID: {chunk.id}\")\n    print(f\"Content: {chunk.markdown}\")\n    print(f\"Page: {chunk.grounding.page}\")\n    print(\"---\")\n```\n\n### Filtering by Chunk Type\n\n```python\n# Get all text chunks\ntext_chunks = [chunk for chunk in response.chunks if chunk.type == 'text']\n\n# Get all tables\ntables = [chunk for chunk in response.chunks if chunk.type == 'table']\n\n# Get all figures\nfigures = [chunk for chunk in response.chunks if chunk.type == 'figure']\n```\n\n### Filtering by Page\n\n```python\n# Get all chunks from page 0 (first page)\npage_0_chunks = [chunk for chunk in response.chunks\n                 if chunk.grounding.page == 0]\n```\n\n### Accessing Chunk Location (Grounding)\n\n```python\nfor chunk in response.chunks:\n    print(f\"Chunk ID: {chunk.id}\")\n    print(f\"Page: {chunk.grounding.page}\")\n    print(f\"Bounding box: {chunk.grounding.box}\")\n    # Bounding box format: {left, top, right, bottom}\n    # Values are normalized 0-1\n```\n\n### Grounding Type Mapping\n\nThe top-level `grounding` dictionary in the Parse response uses **grounding types** (prefixed with `chunk`) rather than chunk types. This allows the grounding dictionary to also include table-specific entries (`table`, `tableCell`) that don't correspond to chunk types.\n\n| Grounding Type | Chunk Type | Notes |\n|---|---|---|\n| `chunkText` | `text` | |\n| `chunkTable` | `table` | Overall table location |\n| `chunkFigure` | `figure` | |\n| `chunkMarginalia` | `marginalia` | |\n| `chunkLogo` | `logo` | DPT-2 only |\n| `chunkCard` | `card` | DPT-2 only |\n| `chunkAttestation` | `attestation` | DPT-2 only |\n| `chunkScanCode` | `scan_code` | DPT-2 only |\n| `table` | _(grounding only)_ | HTML `<table>` element within a table chunk |\n| `tableCell` | _(grounding only)_ | Individual cell; includes `position` (row, col, rowspan, colspan, chunk_id) |\n\n**Example — looking up grounding type for a chunk:**\n```python\nfor chunk in response.chunks:\n    grounding_entry = response.grounding.get(chunk.id)\n    if grounding_entry:\n        print(f\"Chunk type: {chunk.type}\")\n        print(f\"Grounding type: {grounding_entry.type}\")\n        # e.g. chunk type \"text\" → grounding type \"chunkText\"\n```\n\n## Common Use Cases by Chunk Type\n\n### text\n- Extract document content for RAG systems\n- Build searchable document indices\n- Extract form field values\n- Process questionnaires and surveys\n\n### table\n- Extract financial data from statements\n- Process invoices and receipts\n- Parse spreadsheet data\n- Extract structured data from reports\n\n### figure\n- Index images for visual search\n- Generate image captions for accessibility\n- Extract diagrams for documentation\n- Archive visual content\n\n### marginalia\n- Track document metadata (page numbers, headers)\n- Extract document versioning information\n- Identify document sections from headers\n\n### logo (DPT-2)\n- Brand recognition and classification\n- Document authenticity verification\n- Company identification from documents\n\n### card (DPT-2)\n- KYC (Know Your Customer) processing\n- Identity verification workflows\n- License verification\n\n### attestation (DPT-2)\n- Contract validation\n- Approval workflow tracking\n- Signature verification\n- Document authenticity checks\n\n### scan_code (DPT-2)\n- Inventory tracking (barcodes)\n- Payment processing (QR codes)\n- Product identification\n- Link extraction from QR codes\n\n## Deprecated Chunk Types\n\n**Note:** The following chunk types were deprecated and consolidated (as of May 22, 2025):\n\n**Consolidated into `marginalia`:**\n- `page_header`\n- `page_footer`\n- `page_number`\n\n**Consolidated into `text`:**\n- `title`\n- `form`\n- `key_value`\n\n**Action Required:** If your code references these deprecated types, update to use the new consolidated types (`marginalia` or `text`).\n\n## Best Practices\n\n### 1. Choose the Right Model\n- Use **DPT-2** for documents with logos, signatures, ID cards, or barcodes\n- Use **DPT-2 mini** for simple, digitally-native documents\n\n### 2. Filter Chunks by Type\nFilter chunks to focus on relevant content for your use case:\n```python\n# Extract only text and tables for data extraction\ndata_chunks = [c for c in response.chunks\n               if c.type in ['text', 'table']]\n```\n\n### 3. Use Chunk IDs for Traceability\nEach chunk has a unique ID that can be referenced in extraction metadata:\n```python\n# Extract data and trace back to source chunks\nextract_response = client.extract(schema=schema, markdown=response.markdown)\nfor field, metadata in extract_response.extraction_metadata.items():\n    print(f\"{field} extracted from chunks: {metadata.chunk_ids}\")\n```\n\n### 4. Handle Visual Elements\nFor figures, logos, attestations, and scan_codes, the markdown includes a caption:\n```python\n# Check if chunk is visual\nvisual_types = ['figure', 'logo', 'card', 'attestation', 'scan_code']\nif chunk.type in visual_types:\n    print(f\"Visual element: {chunk.markdown}\")\n    # Caption format: <::Caption: description::>\n```\n\n## References\n\n- [Official Chunk Types Documentation](https://docs.landing.ai/ade/ade-chunk-types)\n- [Parse Models (DPT-1 vs DPT-2)](https://docs.landing.ai/ade/ade-parse-models)\n- [JSON Response Structure](https://docs.landing.ai/ade/ade-json-response)\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/references/extraction-schemas.md",
    "content": "# Extraction Schema Patterns\n\nThis reference provides patterns and examples for creating extraction schemas for the LandingAI ADE Extract API.\n\n## Overview\n\nExtraction schemas are JSON Schema objects that define what structured data should be extracted from parsed documents. You can use either JSON Schema format (for API calls) or Pydantic models (when using the Python library).\n\n## Basic Structure\n\nEvery extraction schema must follow this structure:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"field_name\": {\n      \"type\": \"string\",\n      \"description\": \"Description of what to extract\"\n    }\n  },\n  \"required\": [\"field_name\"]\n}\n```\n\n**Key points:**\n- Top-level `type` must be `\"object\"`\n- Define fields in the `properties` object\n- Use `required` array for mandatory fields\n- Add `description` for better accuracy\n\n## Supported Field Types\n\n| Type | Description | Example Use Case |\n|------|-------------|------------------|\n| `string` | Text values | Names, addresses, IDs |\n| `number` | Numeric values with decimals | Prices, amounts, percentages |\n| `integer` | Whole numbers | Counts, quantities |\n| `boolean` | True/false values | Checkboxes, yes/no questions |\n| `array` | Lists of items | Line items, charges, addresses |\n| `object` | Nested structures | Address with street/city/zip |\n\n## Common Patterns\n\n### 1. Basic Field Extraction\n\nExtract simple fields from a document:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"patient_name\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the patient\"\n    },\n    \"doctor\": {\n      \"type\": \"string\",\n      \"description\": \"Primary care physician of the patient\"\n    },\n    \"copay\": {\n      \"type\": \"number\",\n      \"description\": \"Copay that the patient is required to pay before services are rendered\"\n    }\n  },\n  \"required\": [\"patient_name\"]\n}\n```\n\n### 2. Nested Objects\n\nExtract hierarchical data with up to 5 levels of nesting:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"invoice\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"number\": {\n          \"type\": \"string\",\n          \"description\": \"Invoice number\"\n        },\n        \"date\": {\n          \"type\": \"string\",\n          \"description\": \"Invoice date in YYYY-MM-DD format\"\n        },\n        \"total\": {\n          \"type\": \"number\",\n          \"description\": \"Total amount in USD\"\n        }\n      }\n    },\n    \"vendor\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"name\": {\"type\": \"string\"},\n        \"address\": {\"type\": \"string\"},\n        \"phone\": {\"type\": \"string\"}\n      }\n    }\n  }\n}\n```\n\n### 3. Arrays (Lists)\n\nExtract repeating items from tables or lists:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"charges\": {\n      \"type\": \"array\",\n      \"description\": \"List of charges on the utility bill\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"charge_type\": {\n            \"type\": \"string\",\n            \"description\": \"Type of charge (e.g., electricity, gas, water)\"\n          },\n          \"amount\": {\n            \"type\": \"number\",\n            \"description\": \"Charge amount in USD\"\n          },\n          \"usage\": {\n            \"type\": \"string\",\n            \"description\": \"Usage amount with unit (e.g., '450 kWh', '25 CCF')\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### 4. Enum (Restricted Values)\n\nLimit extracted values to a specific set (string enums only):\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"account_type\": {\n      \"type\": \"string\",\n      \"enum\": [\"Premium Checking\", \"Standard Checking\"],\n      \"description\": \"Bank account type\"\n    }\n  }\n}\n```\n\n### 5. Document Classification\n\nUse enum to classify documents and extract different fields per type:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"document_type\": {\n      \"type\": \"string\",\n      \"enum\": [\"Passport\", \"Invoice\", \"Receipt\", \"Other\"]\n    }\n  },\n  \"required\": [\"document_type\"]\n}\n```\n\nAfter classification, make a second extraction call with type-specific schema.\n\n### 6. Nullable Fields\n\n**For extract-20251024 (recommended):**\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"middle_name\": {\n      \"type\": \"string\",\n      \"nullable\": true,\n      \"description\": \"Patient's middle name, if provided\"\n    }\n  }\n}\n```\n\n**For extract-20250930:**\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"middle_name\": {\n      \"type\": [\"string\", \"null\"],\n      \"description\": \"Patient's middle name, if provided\"\n    }\n  }\n}\n```\n\n### 7. Union Types\n\nWhen a field can accept multiple types, use `anyOf` (especially with objects or arrays):\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"field1\": {\"type\": \"string\"},\n    \"field2\": {\n      \"anyOf\": [\n        {\"type\": \"number\"},\n        {\"type\": \"object\"}\n      ]\n    }\n  }\n}\n```\n\n> **Validation rule:** Every sub-schema within `anyOf` must include either a `type` or `anyOf` keyword. If a sub-schema is missing both, the API returns a **400 error** identifying the invalid path. For example, `\"anyOf\": [{\"description\": \"a number\"}]` will fail because the sub-schema has no `type`.\n\n## Pydantic Example (Python Library)\n\nWhen using the landingai-ade Python library, use Pydantic models:\n\n```python\nfrom pydantic import BaseModel, Field\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclass Invoice(BaseModel):\n    invoice_number: str = Field(description=\"Invoice number\")\n    invoice_date: str = Field(description=\"Invoice date\")\n    total_amount: float = Field(description=\"Total amount in USD\")\n    vendor_name: str = Field(description=\"Vendor name\")\n\n# Convert to JSON schema\nschema = pydantic_to_json_schema(Invoice)\n```\n\n## Best Practices\n\n### 1. Use Descriptive Field Names\n- **Good**: `invoice_number`, `patient_name`, `total_amount`\n- **Bad**: `number`, `name`, `amount`\n\n### 2. Add Detailed Descriptions\nInclude in descriptions:\n- Exactly what to extract\n- Format requirements (\"in USD\", \"as YYYY-MM-DD\")\n- What to include/exclude (\"excluding tax\", \"including area code\")\n\nExample:\n```json\n{\n  \"total_amount\": {\n    \"type\": \"number\",\n    \"description\": \"Total amount in USD, excluding tax\"\n  }\n}\n```\n\n### 3. Match Document Structure\nOrder fields in your schema to match their order in the document.\n\n### 4. Limit Complexity\n- Keep schemas under 30 properties for optimal performance\n- Start with a few fields, add more as needed\n- Keep names short but descriptive\n- Flatten nested arrays when possible\n- Reduce optional properties\n\n### 5. Use Appropriate Types\n- Use `number` for monetary values or calculations\n- Use `integer` for counts\n- Use `array` for repeating items (tables, lists)\n- Use `object` for hierarchical data\n\n## Model-Specific Considerations\n\n### extract-20251024 (Latest, Recommended)\n\n**Supported Keywords:**\n- `type`, `properties`, `required`, `description`, `title`\n- `enum` (string only), `nullable`\n- `array`, `items`, `maxItems`, `minItems`\n- `number`, `maximum`, `minimum`\n- `anyOf`, `$ref`, `$defs`\n- `format`, `propertyOrdering`\n\n**Behavior:**\n- Missing fields return `null` (even if required)\n- Falls back to extract-20250930 if schema is too complex\n\n### extract-20250930 (Previous Version)\n\n**Unsupported Keywords:**\n- `allOf`, `not`, `dependentRequired`, `dependentSchemas`, `if`, `then`, `else`\n\n**Behavior:**\n- Inconsistent handling of missing fields (may return `null`, `0`, empty string, etc.)\n- Use type array for nullable: `\"type\": [\"string\", \"null\"]`\n\n## Troubleshooting\n\n### Schema Validation Errors (422)\n- Ensure top-level type is \"object\"\n- Check JSON syntax\n- Verify required structure\n\n### Partial Extraction (206)\n- Extracted data doesn't match schema\n- API returns partial results and consumes credits\n- Review field types and descriptions\n\n### Low Accuracy\n- Add more detailed descriptions\n- Use more specific field names\n- Match schema to document structure\n- Reduce schema complexity\n\n## Examples by Use Case\n\n### Invoice Processing\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"invoice_number\": {\"type\": \"string\"},\n    \"invoice_date\": {\"type\": \"string\", \"description\": \"Date in YYYY-MM-DD format\"},\n    \"due_date\": {\"type\": \"string\", \"description\": \"Due date in YYYY-MM-DD format\"},\n    \"vendor_name\": {\"type\": \"string\"},\n    \"total_amount\": {\"type\": \"number\", \"description\": \"Total in USD\"},\n    \"line_items\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"description\": {\"type\": \"string\"},\n          \"quantity\": {\"type\": \"integer\"},\n          \"unit_price\": {\"type\": \"number\"},\n          \"amount\": {\"type\": \"number\"}\n        }\n      }\n    }\n  },\n  \"required\": [\"invoice_number\", \"total_amount\"]\n}\n```\n\n### Bank Statement\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"account_holder\": {\"type\": \"string\"},\n    \"account_number\": {\"type\": \"string\"},\n    \"statement_period\": {\"type\": \"string\"},\n    \"beginning_balance\": {\"type\": \"number\"},\n    \"ending_balance\": {\"type\": \"number\"},\n    \"transactions\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"date\": {\"type\": \"string\"},\n          \"description\": {\"type\": \"string\"},\n          \"amount\": {\"type\": \"number\"},\n          \"type\": {\"type\": \"string\", \"enum\": [\"Debit\", \"Credit\"]}\n        }\n      }\n    }\n  }\n}\n```\n\n### Medical Form\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"patient\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"first_name\": {\"type\": \"string\"},\n        \"middle_name\": {\"type\": \"string\", \"nullable\": true},\n        \"last_name\": {\"type\": \"string\"},\n        \"date_of_birth\": {\"type\": \"string\"},\n        \"insurance_id\": {\"type\": \"string\"}\n      }\n    },\n    \"provider\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"name\": {\"type\": \"string\"},\n        \"specialty\": {\"type\": \"string\"}\n      }\n    },\n    \"has_allergies\": {\"type\": \"boolean\"},\n    \"allergies\": {\n      \"type\": \"array\",\n      \"items\": {\"type\": \"string\"}\n    }\n  }\n}\n```\n\n## References\n\n- [Official Extraction Schema Documentation](https://docs.landing.ai/ade/ade-extract-schema-json)\n- [Python Library Documentation](https://docs.landing.ai/ade/ade-python)\n- [Extraction Models](https://docs.landing.ai/ade/ade-extract-models)\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/references/file-formats.md",
    "content": "# Supported File Formats\n\n## Overview\n\nLandingAI ADE supports 20+ file formats across PDFs, images, documents, presentations, and spreadsheets. This reference details supported formats, limitations, and considerations for each category.\n\n## Quick Reference\n\n| Category | Formats | Notes |\n|----------|---------|-------|\n| **PDF** | PDF | Up to 100 pages in Playground; see rate limits for API |\n| **Images** | JPEG, JPG, PNG, + 15 more | Common formats fully supported |\n| **Documents** | DOC, DOCX, ODT | Converted to PDF before parsing |\n| **Presentations** | PPT, PPTX, ODP | Converted to PDF before parsing |\n| **Spreadsheets** | CSV, XLSX | Up to 10 MB in Playground; no limit in API |\n\n## PDFs\n\n### Supported\n- Standard PDF files (.pdf)\n- Multi-page PDFs (up to 100 pages in Playground)\n- Scanned PDFs (OCR applied automatically)\n\n### API Limits\n- Playground: Up to 100 pages\n- API: See [Rate Limits](https://docs.landing.ai/ade/ade-rate-limits)\n- Parse Jobs (async): Up to 1 GB or 6,000 pages\n\n\n\n### Usage Example\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\nresponse = client.parse(\n    document=Path(\"document.pdf\"),\n    model=\"dpt-2-latest\"\n)\n```\n\n## Images\n\n### Fully Supported (Playground + API)\n- **JPEG** - Joint Photographic Experts Group\n- **JPG** - JPEG variant\n- **PNG** - Portable Network Graphics\n\n### API-Only Supported\n- **APNG** - Animated PNG\n- **BMP** - Bitmap\n- **DCX** - Multi-page PCX\n- **DDS** - DirectDraw Surface\n- **DIB** - Device Independent Bitmap\n- **GD** - GD Graphics\n- **GIF** - Graphics Interchange Format\n- **ICNS** - Apple Icon\n- **JP2** - JPEG 2000\n- **PCX** - PC Paintbrush\n- **PPM** - Portable Pixmap\n- **PSD** - Photoshop Document\n- **TGA** - Truevision Graphics Adapter\n- **TIFF** - Tagged Image File Format\n- **WEBP** - Web Picture format\n\n### Considerations\n- All images are processed with OCR if they contain text\n- Images with complex layouts benefit from DPT-2\n- Scanned documents work best as images or PDFs\n\n### Usage Example\n```python\n# Parse an image file\nresponse = client.parse(\n    document=Path(\"receipt.jpg\"),\n    model=\"dpt-2-latest\"\n)\n\n# Parse from URL\nresponse = client.parse(\n    document_url=\"https://example.com/invoice.png\",\n    model=\"dpt-2-latest\"\n)\n```\n\n## Text Documents\n\n### Supported Formats\n- **DOC** - Microsoft Word (legacy)\n- **DOCX** - Microsoft Word\n- **ODT** - OpenDocument Text (LibreOffice)\n\n### Important: File Conversion\n\n**All text documents are converted to PDF before parsing.**\n\n**Impact:**\n- Layout may change during conversion\n- Unsupported fonts are replaced (may cause text wrapping changes)\n- Page count may increase or decrease\n- Text may overflow onto additional pages\n\n**Parsing Quality:**\nDespite layout changes, ADE still parses content correctly. The semantic chunking and content extraction work as expected.\n\n### Best Practices\n- Test with sample documents to understand conversion impact\n- For critical layout preservation, convert to PDF manually first\n- Use DPT-2 for documents with complex formatting\n\n### Usage Example\n```python\n# Parse Word document\nresponse = client.parse(\n    document=Path(\"contract.docx\"),\n    model=\"dpt-2-latest\"\n)\n```\n\n## Presentations\n\n### Supported Formats\n- **PPT** - Microsoft PowerPoint (legacy)\n- **PPTX** - Microsoft PowerPoint\n- **ODP** - OpenDocument Presentation (LibreOffice)\n\n### Important: File Conversion\n\n**All presentations are converted to PDF before parsing.**\n\n**Impact:**\n- Each slide becomes a page in the PDF\n- Animations and transitions are lost\n- Layout may change (same considerations as text documents)\n- Speaker notes may not be preserved\n\n**Parsing Quality:**\nSlide content, text, images, and tables are extracted correctly.\n\n### Best Practices\n- Test presentation conversion with sample files\n- For critical slides, export to PDF manually first\n- Use DPT-2 for slides with complex graphics or logos\n\n### Usage Example\n```python\n# Parse PowerPoint\nresponse = client.parse(\n    document=Path(\"presentation.pptx\"),\n    model=\"dpt-2-latest\"\n)\n```\n\n## Spreadsheets\n\n### Supported Formats\n- **CSV** - Comma-Separated Values\n- **XLSX** - Microsoft Excel\n\n### Limits\n\n| Environment | CSV Limit | XLSX Limit | Sheets/Rows/Columns |\n|-------------|-----------|------------|---------------------|\n| Playground | 10 MB | 10 MB | Unlimited |\n| API/Library | Unlimited | Unlimited | Unlimited |\n\n**Note:** In Playground, a render limit applies and only a truncated version is displayed. This does **not** affect parsing results.\n\n### How Spreadsheets are Parsed\n\n**Each table/sheet:**\n- Extracted as `table` chunk type\n- Cell-level IDs generated for traceability\n- Converted to HTML tables in Markdown\n- Grounding includes cell positions\n\n### Best Practices\n- Use CSV for simple data (faster processing)\n- Use XLSX for multi-sheet workbooks\n- For large spreadsheets, use Parse Jobs API (async)\n- Filter specific sheets if only subset needed\n\n### Usage Example\n```python\n# Parse Excel file\nresponse = client.parse(\n    document=Path(\"sales_data.xlsx\"),\n    model=\"dpt-2-latest\"\n)\n\n# Access table chunks\ntables = [chunk for chunk in response.chunks if chunk.type == 'table']\nfor table in tables:\n    print(table.markdown)  # HTML table\n```\n\n## Loading from Bytes\n\n### Python Library Support\n\nYou can load documents from bytes (useful for API responses, web uploads, or in-memory processing):\n\n```python\nfrom pathlib import Path\n\n# Load PDF from bytes\nwith open(\"document.pdf\", \"rb\") as f:\n    pdf_bytes = f.read()\n\nresponse = client.parse(\n    document=pdf_bytes,  # Pass bytes directly\n    model=\"dpt-2-latest\"\n)\n\n# Load image from bytes\nwith open(\"image.jpg\", \"rb\") as f:\n    image_bytes = f.read()\n\nresponse = client.parse(\n    document=image_bytes,\n    model=\"dpt-2-latest\"\n)\n```\n\n**Use Cases:**\n- Processing files from web uploads without saving to disk\n- Working with files from cloud storage APIs\n- Processing encrypted files after decryption in memory\n\n## Format Selection Guide\n\n### When to Use Each Format\n\n| Format | Best For | Considerations |\n|--------|----------|----------------|\n| **PDF** | Any document type, forms, reports | Native format - no conversion |\n| **Images** | Receipts, photos, scanned docs | Use high resolution for better OCR |\n| **DOCX** | Contracts, reports, letters | Layout may change during conversion |\n| **PPTX** | Slide content extraction | Animations lost |\n| **XLSX** | Financial data, tables, lists | Best for structured data |\n| **CSV** | Simple tabular data | Fast processing |\n\n## Troubleshooting\n\n### Error: \"document closed or encrypted\"\n**Cause:** Password-protected document\n**Solution:** Pass `password=\"...\"` parameter (requires ZDR enabled). Without ZDR, remove password protection before parsing.\n\n### Poor OCR Results from Images\n**Possible Causes:**\n- Low resolution (< 300 DPI)\n- Poor image quality\n- Blurry or skewed text\n\n**Solutions:**\n- Increase image resolution\n- Ensure good lighting for scanned documents\n- Use deskewing tools if needed\n\n### Unexpected Layout Changes (DOCX/PPTX)\n**Cause:** File conversion to PDF\n**Solutions:**\n- Convert to PDF manually with preferred tool\n- Test conversion with sample files\n- Accept layout changes if content extraction is primary goal\n\n### Large File Processing Slow\n**Solutions:**\n- Use Parse Jobs API for files > 50 pages\n- Compress images before processing\n- Split multi-document PDFs if possible\n\n### Spreadsheet Too Large\n**Solutions:**\n- Filter to specific sheets before parsing\n- Split large XLSX into smaller files\n- Use CSV format if possible (faster)\n- Use Parse Jobs API (async processing)\n\n## API vs Playground Support\n\n| Feature | Playground | API/Library |\n|---------|------------|-------------|\n| PDF Pages | Up to 100 | See rate limits |\n| Common Images | ✓ | ✓ |\n| Extended Images | ✗ | ✓ |\n| Documents | ✓ | ✓ |\n| Presentations | ✓ | ✓ |\n| Spreadsheets | Up to 10 MB | Unlimited |\n| Parse Jobs | ✗ | ✓ |\n| Bytes Loading | ✗ | ✓ |\n\n## References\n\n- [Official File Types Documentation](https://docs.landing.ai/ade/ade-file-types)\n- [Rate Limits](https://docs.landing.ai/ade/ade-rate-limits)\n- [Parse Jobs for Large Files](https://docs.landing.ai/ade/ade-parse-async)\n- [Python Library](https://docs.landing.ai/ade/ade-python)\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/references/troubleshooting.md",
    "content": "# Troubleshooting\n\n## HTTP Error Codes\n\n| Code | Meaning | Common Causes | Action |\n|------|---------|---------------|--------|\n| **400** | Bad Request | `anyOf` sub-schema missing `type`/`anyOf` keyword; invalid parameter | Fix schema per error message |\n| **401** | Unauthorized | Missing or invalid `VISION_AGENT_API_KEY` | Check `.env` file and key validity |\n| **413** | Payload Too Large | File exceeds sync parse limit | Use Parse Jobs API for large files |\n| **422** | Unprocessable Entity | Invalid JSON schema; unsupported keywords; top-level type not `\"object\"`; password-protected file without ZDR or with wrong password | Validate schema structure; check password; enable ZDR |\n| **429** | Rate Limited | Too many concurrent requests | Add retry with exponential backoff |\n| **206** | Partial Content | Some pages failed (parse) or schema violation (extract) | Check `metadata.failed_pages` or `metadata.schema_violation_error` |\n\n## Parse Failures\n\n- **Password-protected file**: Pass `password=\"...\"` parameter (requires ZDR). Without ZDR, remove password protection before parsing\n- **Unsupported format**: Check [file formats reference](file-formats.md)\n- **File too large**: Use Parse Jobs API (`client.parse_jobs.create()`) for files > 50 pages or > 10 MB\n- **Poor OCR quality**: Use high-resolution scans (300+ DPI); consider `dpt-2-latest` over `dpt-2-mini` for scanned docs\n\n## Low Extraction Accuracy\n\n- Add more detailed field descriptions (include format hints: \"as YYYY-MM-DD\", \"in USD\")\n- Use more specific field names (`invoice_total_usd` rather than `total`)\n- Match schema field order to how data appears in the document\n- Reduce schema complexity — stay under 30 properties for best results\n- Try `model=\"extract-20251024\"` if the latest model misses fields it should return as `null`\n\n## Missing Fields\n\n- Verify the field actually exists in the document\n- Check that the field description clearly identifies the data\n- `extract-20251024` returns `null` for absent fields; `extract-latest` may omit them entirely\n- Check `extraction_metadata` — if the field has `chunk_ids`, the model found it but may have returned an unexpected value\n\n## Schema Validation Errors (HTTP 422)\n\n- Top-level schema must have `\"type\": \"object\"`\n- `anyOf` / `oneOf` sub-schemas each need their own `type` or `anyOf` keyword\n- Avoid unsupported JSON Schema keywords (e.g., `if`/`then`, `$ref`)\n- Use `pydantic_to_json_schema()` from `landingai_ade.lib` for reliable schema generation\n\n## Performance Issues\n\n- Use `dpt-2-mini` for simple, digitally-native documents (faster and cheaper)\n- Enable Parse Jobs (`client.parse_jobs.create()`) for large files to avoid timeouts\n- Process documents in parallel with `ThreadPoolExecutor` — see [document-workflows batch-processing.md](../../document-workflows/references/batch-processing.md)\n- Cache parse results (save `response.markdown` to disk) when running multiple extractions on the same document\n\n## Partial Results (HTTP 206)\n\n**Parse 206** — Some pages failed:\n```python\nresponse = client.parse(document=Path(\"doc.pdf\"), model=\"dpt-2-latest\")\nif response.metadata.failed_pages:\n    print(f\"Failed pages: {response.metadata.failed_pages}\")\n    # Remaining pages were parsed successfully; credits are consumed\n```\n\n**Extract 206** — Schema violation:\n```python\nresponse = client.extract(schema=schema, markdown=markdown)\nerr = response.metadata.schema_violation_error\nif err:\n    print(f\"Schema violation: {err}\")\n    # Partial data is still returned; credits are consumed\n```\n"
  },
  {
    "path": "content/landingai/skills/ade/document-extraction/references/use-cases.md",
    "content": "# Use Cases\n\nCommon document processing patterns using LandingAI ADE. All examples assume the client and dependencies are set up per `SKILL.md`.\n\n## Invoice Processing\n\n```python\nfrom pydantic import BaseModel, Field\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclass LineItem(BaseModel):\n    description: str = Field(description=\"Item description\")\n    quantity: int = Field(description=\"Quantity\")\n    unit_price: float = Field(description=\"Unit price in USD\")\n    amount: float = Field(description=\"Line total in USD\")\n\nclass Invoice(BaseModel):\n    invoice_number: str = Field(description=\"Invoice number\")\n    invoice_date: str = Field(description=\"Invoice date as YYYY-MM-DD\")\n    vendor_name: str = Field(description=\"Vendor company name\")\n    vendor_address: str = Field(description=\"Vendor address\")\n    total_amount: float = Field(description=\"Total amount due in USD\")\n    line_items: list[LineItem] = Field(description=\"List of line items\")\n\nclient = LandingAIADE()\n\nparse_response = client.parse(document=Path(\"invoice.pdf\"), model=\"dpt-2-latest\")\nextract_response = client.extract(\n    schema=pydantic_to_json_schema(Invoice),\n    markdown=parse_response.markdown,\n    model=\"extract-latest\"\n)\n\ninvoice = extract_response.extraction\nprint(f\"Invoice #{invoice['invoice_number']} — ${invoice['total_amount']}\")\nfor item in invoice['line_items']:\n    print(f\"  {item['description']}: {item['quantity']} x ${item['unit_price']}\")\n```\n\n## Form Data Extraction\n\n```python\nfrom pydantic import BaseModel, Field\nfrom typing import Optional\n\nclass PatientIntake(BaseModel):\n    patient_name: str = Field(description=\"Full patient name\")\n    date_of_birth: str = Field(description=\"Date of birth as YYYY-MM-DD\")\n    insurance_id: str = Field(description=\"Insurance ID number\")\n    emergency_contact: str = Field(description=\"Emergency contact name and phone\")\n    allergies: list[str] = Field(description=\"List of known allergies\")\n    has_existing_conditions: bool = Field(description=\"Whether patient has existing conditions\")\n    primary_complaint: Optional[str] = Field(default=None, description=\"Primary complaint or reason for visit\")\n\n# Parse and extract\nparse_response = client.parse(document=Path(\"intake_form.pdf\"), model=\"dpt-2-latest\")\nextract_response = client.extract(\n    schema=pydantic_to_json_schema(PatientIntake),\n    markdown=parse_response.markdown,\n    model=\"extract-latest\"\n)\nprint(extract_response.extraction)\n```\n\n## Multi-Document Classification and Extraction\n\nSplit a batch PDF into document types, then extract type-specific fields from each:\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Step 1: Parse the batch\nparse_response = client.parse(document=Path(\"batch.pdf\"), model=\"dpt-2-latest\")\n\n# Step 2: Split by document type\nsplit_response = client.split(\n    markdown=parse_response.markdown,\n    split_class=[\n        {\"name\": \"Invoice\", \"description\": \"Commercial invoice with line items\", \"identifier\": \"Invoice Number\"},\n        {\"name\": \"Receipt\", \"description\": \"Payment receipt\", \"identifier\": \"Receipt Date\"},\n        {\"name\": \"Bank Statement\", \"description\": \"Monthly bank account statement\"}\n    ]\n)\n\n# Step 3: Extract from each split based on its classification\nfor split in split_response.splits:\n    print(f\"Type: {split.classification}, Pages: {split.pages}\")\n    if split.classification == \"Invoice\":\n        extract_response = client.extract(\n            schema=pydantic_to_json_schema(Invoice),\n            markdown=split.markdowns[0],\n            model=\"extract-latest\"\n        )\n        print(f\"  Invoice #{extract_response.extraction['invoice_number']}\")\n    elif split.classification == \"Bank Statement\":\n        # Use bank statement schema\n        pass\n```\n\n## Table Extraction\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\nimport json\n\nclient = LandingAIADE()\n\n# Parse document or spreadsheet\nresponse = client.parse(document=Path(\"data.xlsx\"), model=\"dpt-2-latest\")\n\n# Filter table chunks\ntables = [chunk for chunk in response.chunks if chunk.type == \"table\"]\nprint(f\"Found {len(tables)} tables\")\n\nfor i, table in enumerate(tables, start=1):\n    print(f\"\\nTable {i} on page {table.grounding.page}:\")\n    print(table.markdown)  # HTML table — parse with pandas or BeautifulSoup\n\n# Save as CSV using pandas\nimport pandas as pd\nfrom io import StringIO\n\nfor i, table in enumerate(tables, start=1):\n    try:\n        dfs = pd.read_html(StringIO(table.markdown))\n        if dfs:\n            dfs[0].to_csv(f\"table_{i:02d}.csv\", index=False)\n            print(f\"Saved table_{i:02d}.csv\")\n    except Exception as e:\n        print(f\"Table {i}: could not parse as HTML ({e})\")\n```\n\n> **Multi-page tables:** When a table spans multiple pages, ADE emits separate chunks per page\n> and may represent some pages as plain text instead of table chunks. See\n> [Table Stitching](../../document-workflows/references/table-stitching.md) in the\n> `document-workflows` skill for three approaches to merge them into a single output.\n\n## Figure Extraction with Cropping\n\nExtract figures from PDFs as individual PNG files using bounding boxes:\n\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n\nimport fitz  # PyMuPDF — install with: pip install pymupdf\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\n\n# Step 1: Parse the PDF\npdf_path = Path(\"document.pdf\")\nresponse = client.parse(document=pdf_path, model=\"dpt-2-latest\")\n\n# Step 2: Filter figure chunks\nfigure_chunks = [chunk for chunk in response.chunks if chunk.type == \"figure\"]\nprint(f\"Found {len(figure_chunks)} figures\")\n\n# Step 3: Open PDF with PyMuPDF and crop each figure\npdf_doc = fitz.open(pdf_path)\n\nfor idx, chunk in enumerate(figure_chunks, start=1):\n    page_num = chunk.grounding.page\n    bbox = chunk.grounding.box  # Always present — API guarantees grounding on returned chunks\n\n    page = pdf_doc[page_num]\n\n    # Convert normalized coordinates (0-1) to absolute pixel coordinates\n    x0 = bbox.left * page.rect.width\n    y0 = bbox.top * page.rect.height\n    x1 = bbox.right * page.rect.width\n    y1 = bbox.bottom * page.rect.height\n\n    # Render at 2x zoom for quality\n    zoom = 2.0\n    mat = fitz.Matrix(zoom, zoom)\n    pix = page.get_pixmap(matrix=mat, clip=fitz.Rect(x0, y0, x1, y1))\n\n    output_path = f\"figure_{idx:02d}_page{page_num + 1}.png\"\n    pix.save(output_path)\n    print(f\"Figure {idx}: saved as {output_path}\")\n\n    # IMPORTANT: Read back the first output PNG and visually verify it shows the right content\n    # before continuing. Page indexing bugs are easy to miss without a visual check.\n\npdf_doc.close()\n```\n\n**Key Points:**\n- Bounding boxes use normalized coordinates (0-1); multiply by page dimensions to get pixels\n- Every chunk returned by the API is guaranteed to have `grounding.box`\n- Use `zoom=2.0` or higher for crisp output\n- Page numbers are zero-indexed in ADE\n- After saving the first PNG, read it back and confirm it shows the expected figure\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/SKILL.md",
    "content": "---\nname: document-workflows\ndescription: >\n  Use this skill for building end-to-end document processing workflows and\n  pipelines using LandingAI ADE. Trigger when users need to:\n  (1) Process batches of documents in parallel or async,\n  (2) Build classify-then-extract pipelines for mixed document types,\n  (3) Prepare parsed documents for RAG systems with chunking and vector DB ingestion,\n  (4) Load extraction results into databases like Snowflake or export to CSV/DataFrames,\n  (5) Visualize extraction results: draw bounding box overlays on pages, crop\n  chunk images, or highlight/annotate specific words or phrases found in documents,\n  (6) Build Streamlit or web UIs for document processing,\n  (7) Find and highlight specific terms within document sections using word-level\n  grounding (e.g. highlight \"L2S\" in the Introduction, redact PII, annotate\n  extracted values on the original page).\n  This skill complements the document-extraction skill which covers ADE SDK basics.\n  Use document-extraction to write code that executes parse/extract/split operations with more precision and less cost than adding the document image to the prompt and asking the LLM to find the relevant info.\n  Use document-workflows when composing those operations into pipelines,\n  or when you need visualization, annotation, or word-level grounding on\n  parsed documents.\n---\n\n# Document Workflows — ADE Pipeline Patterns\n\n## Overview\n\nThis skill provides **reusable building blocks** for composing LandingAI ADE\nprimitives (parse, extract, split) into production-ready document processing\npipelines. It complements the `document-extraction` skill:\n\n| Concern | `document-extraction` | `document-workflows` |\n|---------|----------------------|---------------------|\n| Scope | ADE SDK API: parse, extract, split, grounding | End-to-end pipelines: batch, RAG, DB, classify-route |\n| When | Need to call a single ADE operation | Need to compose operations into a workflow |\n| Code | SDK method calls with parameters | Complete functions with error handling, parallelism |\n| Deps | `landingai-ade` only | + workflow-specific libs (pandas, chromadb, etc.) |\n\n**Philosophy:** Organize by *workflow pattern* (batch, RAG, DB insertion),\nnot by document type. The same pattern applies whether documents are invoices,\nutility bills, or medical forms.\n\n---\n\n## Step 0 (mandatory) — Pre-Flight Document Exploration {#pre-flight}\n\n**Run this before writing any pipeline code** whenever working with documents\nwhose internal structure has not already been inspected in this session.\n\n> **Rule: never write section-detection, heading-matching, or text-search code\n> without first running Tool 2 (diagnostic parse) on the sample document.\n> Heading format is document-specific and cannot be inferred from the task\n> description or document type alone — the only reliable way to know it is to\n> look at the actual ADE output.**\n>\n> Common surprises: a paper's \"Introduction\" heading may appear as\n> `1. Introduction` (plain text, no `#`), `## Introduction`, `INTRODUCTION`\n> (all-caps), or embedded inside a text chunk with body copy. Getting this\n> wrong means a silent failure (zero chunks matched) that requires a full\n> re-parse to debug.\n\nRun Tool 1 (visual render) and Tool 2 (diagnostic parse) on 1–3 representative\nsample documents before writing any code. This takes under a minute and\nprevents debugging iterations that a pre-flight would have avoided.\n\n### Tool 1 — Visual page render\n\nRender 1–2 pages as PNG and read them as visual context. No ADE credits used,\nbut each PNG consumes context tokens. Use when layout is ambiguous or document\norigin is unknown (handwriting? scan? form?).\n\n```bash\n.venv/bin/python - << 'EOF'\nimport pymupdf\nfrom pathlib import Path\nfrom PIL import Image\n\npdf = Path('path/to/sample.pdf')\nout_dir = Path('/tmp/ade_preflight'); out_dir.mkdir(exist_ok=True)\ndoc = pymupdf.open(pdf)\nfor pg in range(min(2, len(doc))):   # first 2 pages only\n    pix = doc[pg].get_pixmap(matrix=pymupdf.Matrix(1.5, 1.5))   # 108 DPI\n    img = Image.frombytes(\"RGB\", [pix.width, pix.height], pix.samples)\n    out = out_dir / f\"{pdf.stem}_page{pg + 1}.png\"\n    img.save(out)\n    print(out)\ndoc.close()\nEOF\n```\n\nThen read the saved PNGs. Immediately answers:\n- Are headings **bold text** (→ ADE may output plain-text heading, not `# Heading`)\n- Is the document handwritten or scanned? → Tesseract OCR needed, not PyMuPDF\n- Single-column or two-column layout?\n- Any noise: running headers, page numbers, watermarks, stamps?\n\n### Tool 2 — ADE diagnostic parse\n\nParses 1 sample and prints markdown structure + chunk inventory. Uses ADE\ncredits — keep to **1–3 samples only**, never the full corpus.\n\n```bash\n.venv/bin/python - << 'EOF'\nimport os\nfrom pathlib import Path\nfrom collections import Counter\nfrom dotenv import load_dotenv\n\n# Load API key: prefer existing env var, then .env file lookup\nload_dotenv()  # Load API key from .env. Add a path to the .env if needed.\n\nfrom landingai_ade import LandingAIADE\nclient = LandingAIADE()\npr = client.parse(document=Path('path/to/sample.pdf'))\n\nprint(\"=== MARKDOWN (first 80 lines) ===\")\nfor i, ln in enumerate(pr.markdown.splitlines()[:80], 1):\n    print(f\"{i:3}: {ln}\")\n\nprint(\"\\n=== CHUNKS ===\")\nfor ch in pr.chunks:\n    txt = (ch.markdown or '').replace('\\n', ' ')[:70]\n    b = ch.grounding.box\n    print(f\"p{ch.grounding.page} {ch.type:12} \"\n          f\"l={b.left:.2f} t={b.top:.2f} r={b.right:.2f} b={b.bottom:.2f} | {txt}\")\n\nprint(f\"\\nPages: {pr.metadata.page_count}  \"\n      f\"Chunks: {len(pr.chunks)}  \"\n      f\"Types: {dict(Counter(ch.type for ch in pr.chunks))}\")\nEOF\n```\n\n> **Cost note:** Save the parse result with `pr.model_dump()` to a JSON file\n> after the first run. Load it for later development instead of calling\n> `client.parse()` again. Only re-parse when the document set changes.\n\n### What to look for\n\n| Observation | Implication |\n|-------------|-------------|\n| Heading is `1. Introduction` (plain text, no `#`) | ADE markdown won't use ATX header → use ADE extract, not regex |\n| Heading format varies across docs (`# INTRO` in one, `1. Intro` in another) | Regex will break on some docs → use ADE extract for robustness |\n| Every `ch.markdown` starts with `<a id='...'></a>` | Strip anchor before string matching or display |\n| Two-column: chunks on same page with `l=0.07` vs `l=0.50` | Text order is left column then right; sections may span both |\n| Chunk text cut mid-word at page break | Section spans pages; collect chunks from multiple pages |\n| `marginalia` chunks at `t<0.08` or `t>0.90` | Running headers / page numbers → exclude from content extraction |\n| Scanned / handwritten content visible in page image | PyMuPDF text extraction won't work → use Tesseract OCR |\n\n### Tool 3 — Post-Crop Visual Verification (mandatory for bounding-box workflows) {#post-crop-verification}\n\nAfter producing any bounding-box crop or overlay (figure extraction, chunk\ncropping, table cell extraction, word-level grounding), **read back at least\none output PNG as an image** and describe what you see. Compare your\ndescription against the user's request. This catches:\n\n- **Wrong-page bugs** — ADE page numbers are 0-indexed; an off-by-one error\n  lands the crop on an adjacent page with completely different content\n- **Wrong-region bugs** — coordinate system mismatches that crop blank space\n  or an unrelated section\n\n> **Rule: never declare a crop workflow complete without visually reading at\n> least one output PNG and confirming its content matches the user's request.**\n\n#### Verification steps\n\n1. Save the first crop as PNG (the workflow already does this)\n2. Read the PNG file as an image (use the `read_file` tool on the PNG path)\n3. Describe what you see: what content, table, figure, or text appears?\n4. Compare against the user's request:\n   - User asked for \"the Events table\" → does the crop show an Events table?\n   - User asked for \"Figure 3\" → does the crop show a chart/diagram?\n   - User asked for \"Introduction section\" → does the crop show intro text?\n5. If the description doesn't match → investigate page indexing and\n   bounding-box coordinates before continuing\n6. Only proceed with remaining crops after the first one is verified\n\n#### Why LLM vision, not heuristics\n\nA blank-check heuristic (e.g. \"mean brightness > 250 → blank\") catches only\nthe most obvious failures. The agent's own vision capability can semantically\nverify: \"this crop shows a bar chart\" vs \"the user asked for a data table.\"\nThis catches wrong-page errors even when the crop contains valid content from\nthe wrong section.\n\n---\n\n## Quick Reference — Building Blocks\n\n| # | Block | Pattern | Reference |\n|---|-------|---------|-----------|\n| 0 | Pre-flight (mandatory) | Render pages + diagnostic parse before building | [Above](#pre-flight) |\n| 1 | Parse + Save | Single doc → JSON + markdown | [Below](#core-workflow) |\n| 2 | Parse + Extract + Save | Single doc → structured data | [Below](#core-workflow) |\n| 3 | Batch (sync) | ThreadPoolExecutor + tqdm | [batch-processing.md](references/batch-processing.md) |\n| 4 | Batch (async) | AsyncLandingAIADE + aiolimiter | [batch-processing.md](references/batch-processing.md) |\n| 5 | Large files | Parse Jobs API (async polling) | [batch-processing.md](references/batch-processing.md) |\n| 6 | Classify → Extract | Enum classification + schema routing | [Below](#classify-then-extract) |\n| 7 | Results → DataFrame | Flatten nested extraction to tables | [database-integration.md](references/database-integration.md) |\n| 8 | Results → CSV | Summary + per-document export | [database-integration.md](references/database-integration.md) |\n| 9 | Results → Snowflake | 4 normalized tables + COPY upload | [database-integration.md](references/database-integration.md) |\n| 10 | Chunks → RAG CSV | 19-column chunk dataset | [rag-pipelines.md](references/rag-pipelines.md) |\n| 11 | Chunks → ChromaDB | OpenAI embeddings + persistent store | [rag-pipelines.md](references/rag-pipelines.md) |\n| 12 | Chunks → FAISS | LangChain Documents + FAISS index | [rag-pipelines.md](references/rag-pipelines.md) |\n| 13 | RAG query | RetrievalQA chain with sources | [rag-pipelines.md](references/rag-pipelines.md) |\n| 14 | Chunk images | Crop chunks from pages as PNGs | [visualization.md](references/visualization.md) |\n| 15 | Grounding overlay | Color-coded bounding boxes on pages | [visualization.md](references/visualization.md) |\n| 16 | Word-level grounding | OCR + fuzzy match highlighting | [visualization.md](references/visualization.md) |\n| 17 | Section extraction | Named section from markdown (regex or ADE extract) | [Below](#section-extraction) |\n| 18 | Embedding computation | Local (FastEmbed) or API (OpenAI) with best practices | [rag-pipelines.md](references/rag-pipelines.md) |\n| 19 | Hierarchical chunking | Group ADE chunks into semantic units for embedding | [rag-pipelines.md](references/rag-pipelines.md) |\n| 20 | Multi-granularity RAG | Chunk vs hierarchical vs document-level strategy | [rag-pipelines.md](references/rag-pipelines.md) |\n| 21 | Table stitching | Parse-only or parse+extract merge of multi-page tables | [table-stitching.md](references/table-stitching.md) |\n| — | Schema catalog | Ready-to-use Pydantic models | [schema-catalog.md](references/schema-catalog.md) |\n\n---\n\n## Core Workflow: Parse + Extract + Save\n\nThe fundamental two-step ADE pattern. Every other workflow builds on this.\n\n```python\nimport io\nfrom pathlib import Path\nfrom typing import Any, Tuple, Type\n\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\n\ndef parse_extract_save(\n    doc_path: Path,\n    client: LandingAIADE,\n    schema_cls: Type[Any],\n    output_dir: str = \"./ade_results\",\n) -> Tuple[Any, Any]:\n    \"\"\"Parse a document, extract structured data, save both\n    as JSON via save_to. Returns (parse_result, extract_result).\"\"\"\n    # Step 1 — Parse (auto-saves {stem}_parse_output.json)\n    parse_result = client.parse(\n        document=doc_path, save_to=output_dir,\n    )\n\n    # Step 2 — Extract (auto-saves {stem}_extract_output.json)\n    extract_result = client.extract(\n        schema=pydantic_to_json_schema(schema_cls),\n        markdown=io.BytesIO(\n            parse_result.markdown.encode(\"utf-8\")\n        ),\n        save_to=output_dir,\n    )\n    return parse_result, extract_result\n```\n\n> **`save_to` parameter:** Available on `parse()`, `extract()`, and `split()`.\n> Creates the folder if needed and writes `{input_filename}_{method}_output.json`.\n> This is a client-side convenience — the full response is saved locally after the API call.\n\n### Parse-Only (no extraction)\n\n```python\ndef parse_and_save(\n    doc_path: Path,\n    client: LandingAIADE,\n    output_dir: str = \"./ade_results\",\n) -> Any:\n    return client.parse(\n        document=doc_path, save_to=output_dir,\n    )\n```\n\n> **Schemas:** See [schema-catalog.md](references/schema-catalog.md) for\n> ready-to-use Pydantic models (invoice, utility bill, bank statement,\n> pay stub, food label, CME certificate, document classifier).\n> See the `document-extraction` skill for schema design rules.\n\n---\n\n## Classify-then-Extract\n\nProcess mixed document types by first classifying, then applying the\nappropriate schema. Two approaches:\n\n### Approach 1: Classification Extraction (any document mix)\n\n```python\nfrom typing import Literal\nfrom pydantic import BaseModel, Field\n\n\nclass DocType(BaseModel):\n    type: Literal[\n        \"invoice\", \"bank_statement\", \"pay_stub\",\n        \"utility_bill\",\n    ] = Field(description=\"The type of the document.\")\n\n\n# Map types to schemas (from schema-catalog.md)\nSCHEMA_MAP: dict[str, type] = {\n    \"invoice\": InvoiceSchema,\n    \"bank_statement\": BankStatementSchema,\n    \"pay_stub\": PayStubSchema,\n    \"utility_bill\": UtilityBillSchema,\n}\n\n\ndef classify_and_extract(\n    doc_path: Path,\n    client: LandingAIADE,\n) -> dict:\n    \"\"\"Classify a document then extract with the matching\n    schema.\"\"\"\n    pr = client.parse(document=doc_path)\n\n    # Classify using first page\n    cls = client.extract(\n        schema=pydantic_to_json_schema(DocType),\n        markdown=pr.markdown,\n    )\n    doc_type: str = cls.extraction[\"type\"]\n\n    # Extract with type-specific schema\n    schema_cls = SCHEMA_MAP[doc_type]\n    er = client.extract(\n        schema=pydantic_to_json_schema(schema_cls),\n        markdown=pr.markdown,\n    )\n    return {\n        \"type\": doc_type,\n        \"extraction\": er.extraction,\n        \"parse_result\": pr,\n        \"extract_result\": er,\n    }\n```\n\n### Approach 2: Split API (multi-document PDFs)\n\nWhen a single PDF contains multiple document types (e.g., a packet with\ninvoices + receipts), use the Split API first:\n\n```python\ndef split_classify_extract(\n    pdf_path: Path,\n    client: LandingAIADE,\n    split_classes: list[dict],\n) -> list[dict]:\n    \"\"\"Split a multi-doc PDF, classify each split, extract.\"\"\"\n    pr = client.parse(document=pdf_path, split=\"page\")\n\n    # Split into sub-documents\n    split_result = client.split(\n        markdown=pr.markdown,\n        split_class=split_classes,\n    )\n\n    results = []\n    for split_doc in split_result.splits:\n        # Classify\n        cls = client.extract(\n            schema=pydantic_to_json_schema(DocType),\n            markdown=split_doc.markdowns[0],\n        )\n        doc_type = cls.extraction[\"type\"]\n\n        # Extract\n        schema_cls = SCHEMA_MAP[doc_type]\n        er = client.extract(\n            schema=pydantic_to_json_schema(schema_cls),\n            markdown=split_doc.markdowns[0],\n        )\n        results.append({\n            \"type\": doc_type,\n            \"extraction\": er.extraction,\n            \"pages\": split_doc.pages,\n        })\n    return results\n```\n\n> **Split API parameters:** Use `split_class` (list of dicts with `name`, `description`, `identifier` keys).\n> See the `document-extraction` skill for full Split API reference.\n\n> **When to use Split vs Classification:**\n> - **Split API**: One PDF contains multiple separate documents\n> - **Classification extraction**: Each file is one document, but types vary\n\n---\n\n## Section Extraction\n\nExtract a named section (e.g. \"Introduction\", \"Abstract\") from a parsed\ndocument's markdown. Two approaches — choose based on document diversity\nand whether the extra API cost is justified.\n\n**Decision:** If the diagnostic parse (Tool 2) shows consistent ATX headers (`## Introduction`, `## 2. Methods`) across all your documents, use Approach A. If you see any plain-text numbered headings (`1. Introduction`) or formatting variation across documents, skip Approach A entirely and go straight to Approach B.\n\n| Approach | When to use |\n|----------|-------------|\n| **A — regex** | Uniform, well-structured docs (academic papers, reports). Free, fast. |\n| **B — ADE extract** | Mixed or unpredictable formatting (slides, scanned papers, varied templates). Costs an extra extract credit per document. |\n\n### Approach A — Rule-based regex (free, fast, brittle)\n\nADE may emit headings as ATX markdown (`## 2. Related Work`) or plain-text\n(`1. Introduction`) even within the same document. Handle both patterns:\n\n```python\nimport re\n\ndef find_section(markdown: str, name: str) -> str | None:\n    \"\"\"Extract a named section from ADE markdown, handling both ATX\n    headers (## Introduction) and plain-text numbered headings\n    (1. Introduction) which ADE may emit inconsistently.\"\"\"\n\n    # Pattern 1: ATX header  (# Introduction, ## 1. Introduction …)\n    m = re.search(\n        r\"^(#{1,6})\\s+(?:\\d+\\.?\\s+)?\" + re.escape(name) + r\"\\b.*$\",\n        markdown, re.IGNORECASE | re.MULTILINE,\n    )\n    if m:\n        level = len(m.group(1))\n        end = re.search(r\"^#{1,\" + str(level) + r\"}\\s\",\n                        markdown[m.end():], re.MULTILINE)\n        end_pos = m.end() + (end.start() if end else len(markdown[m.end():]))\n        return markdown[m.start():m.end() + end_pos].strip()\n\n    # Pattern 2: plain-text numbered heading  (1. Introduction)\n    m2 = re.search(r\"^(?:\\d+\\.?\\s+)?\" + re.escape(name) + r\"\\s*$\",\n                   markdown, re.IGNORECASE | re.MULTILINE)\n    if m2:\n        end2 = re.search(\n            r\"^#{1,6}\\s|^(?:\\d+\\.?\\s+)[A-Z][a-zA-Z ]{3,}\\s*$\",\n            markdown[m2.end():], re.MULTILINE,\n        )\n        end_pos = m2.end() + (end2.start() if end2 else len(markdown[m2.end():]))\n        return markdown[m2.start():end_pos].strip()\n    return None\n```\n\n### Approach B — ADE extract (robust, handles document diversity)\n\nUse ADE's own extraction to semantically locate sections — no regex needed.\nThe LLM understands section meaning even when formatting is inconsistent:\n\n```python\nfrom pydantic import BaseModel, Field\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom pathlib import Path\n\n\nclass PaperSections(BaseModel):\n    abstract: str = Field(\n        description=\"The abstract section, plain text only, \"\n                    \"no markdown formatting or anchor tags.\"\n    )\n    introduction: str = Field(\n        description=\"The introduction section, plain text only, \"\n                    \"no markdown formatting or anchor tags.\"\n    )\n\n\nclient = LandingAIADE()\npr = client.parse(document=Path(\"paper.pdf\"))\ner = client.extract(\n    schema=pydantic_to_json_schema(PaperSections),\n    markdown=pr.markdown,\n)\nintro_text = er.extraction[\"introduction\"]\n```\n\n> **Cost note:** Each `extract()` call consumes additional credits on top of\n> `parse()`. For high-volume pipelines with uniform document types, Approach A\n> avoids this cost. For diverse or unpredictable documents the accuracy\n> improvement justifies the extra credit.\n\n---\n\n## Multi-Page Table Stitching {#table-stitching}\n\nWhen a table spans multiple pages, ADE may emit it as separate table chunks\nper page — and may emit some pages as plain text instead of table chunks.\nThis inconsistency can occur on **any** page, not just the last one.\n\nThree approaches handle this, with different cost/accuracy/fragility\ntrade-offs:\n\n| Approach | ADE Calls | Handles non-table chunks | Fragility |\n|----------|-----------|--------------------------|-----------|\n| **A — Parse + Extract** | 2 | ✓ LLM reads full markdown | Low — no custom parsing |\n| **B — HTML table parsing** | 1 | ✓ with fallback regex | **High** — requires uniform row structure |\n| **C — pandas read_html** | 1 | ✗ misses non-table chunks | Medium |\n\n**Decision guide:**\n- Use **Approach A** when accuracy is paramount and cost is secondary\n- Use **Approach B** when rows are highly uniform, document structure is\n  predictable, and cost savings justify the fragility of regex-based parsing\n- Use **Approach C** for quick prototyping or when missing some rows is\n  acceptable\n\n### Pre-flight additions for table stitching\n\nBefore choosing an approach, run the diagnostic parse (Tool 2) and check:\n\n| What to check | How | Why |\n|---------------|-----|-----|\n| Chunk types per page | Count `type == \"table\"` vs `\"text\"` per page | Any page may have inconsistent types |\n| Column count consistency | Compare column counts across table chunks | Inconsistent counts may indicate different tables |\n| Header row presence | Check first row of each table chunk | Needed for detection and row filtering |\n| Non-target tables | Look for summary/metadata tables with same column count | Must distinguish target from others |\n| Row uniformity | Compare row structure across pages | Low uniformity makes Approach B fragile |\n\n### Domain-specific semantic checks\n\nAfter stitching, add validation checks that leverage domain knowledge:\n- **Financial:** running balances, column totals = sum of rows\n- **Inventory:** quantity conservation across rows\n- **Time-series:** chronological ordering, no sequence gaps\n- **Scientific:** consistent units, monotonic IDs\n\nThese checks serve as both **validation** (confirming correctness) and\n**disambiguation** (resolving structural ambiguity in parsed output).\n\n> **Full code** for all three approaches with reusable patterns:\n> see [table-stitching.md](references/table-stitching.md).\n\n---\n\n## Batch Processing\n\nTwo patterns depending on scale. Both include per-document error handling.\n\n### Quick: ThreadPoolExecutor (sync)\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom tqdm import tqdm\n\n\ndef batch_process(\n    files: list[Path],\n    schema_cls: type,\n    max_workers: int = 4,\n) -> list[tuple[Path, Any, Any]]:\n    client = LandingAIADE()\n    results: list[tuple[Path, Any, Any]] = []\n    with ThreadPoolExecutor(max_workers=max_workers) as pool:\n        futures = {\n            pool.submit(\n                parse_extract_save, fp, client, schema_cls\n            ): fp\n            for fp in files\n        }\n        for fut in tqdm(\n            as_completed(futures), total=len(futures)\n        ):\n            fp = futures[fut]\n            try:\n                results.append((fp, *fut.result()))\n            except Exception as e:\n                print(f\"FAILED {fp.name}: {e}\")\n    return results\n```\n\n### Scalable: AsyncLandingAIADE (async)\n\n```python\nimport asyncio\nfrom aiolimiter import AsyncLimiter\nfrom landingai_ade import AsyncLandingAIADE\n\n\nasync def batch_parse_async(\n    files: list[Path],\n    rate_limit: int = 30,\n) -> list[dict]:\n    client = AsyncLandingAIADE()\n    limiter = AsyncLimiter(rate_limit, 60)\n\n    async def _process(fp: Path) -> dict | None:\n        try:\n            async with limiter:\n                return {\n                    \"path\": fp,\n                    \"result\": await client.parse(document=fp),\n                }\n        except Exception as e:\n            print(f\"FAILED {fp.name}: {e}\")\n            return None\n\n    raw = await asyncio.gather(*[_process(fp) for fp in files])\n    return [r for r in raw if r]\n```\n\n> **Full code** with output directory organization, CSV export, and chunk\n> image saving: see [batch-processing.md](references/batch-processing.md).\n\n---\n\n## Results to DataFrames and CSV\n\nFlatten nested ADE extraction results into 4 normalized tables:\n\n```python\nimport uuid\nfrom datetime import datetime, timezone\n\n\ndef rows_from_doc(\n    file_path: str,\n    parse_result: Any,\n    extract_result: Any,\n    run_id: str = \"\",\n) -> tuple[dict, list[dict], list[dict], dict]:\n    \"\"\"Returns (main_row, line_rows, chunk_rows, md_record).\n\n    - main_row: flattened top-level fields (nested__field)\n    - line_rows: one per list item (line items, transactions)\n    - chunk_rows: one per parsed chunk with bounding boxes\n    - md_record: full markdown for traceability\n    \"\"\"\n    doc_uuid = str(uuid.uuid4())\n    f = extract_result.extraction\n\n    # Flatten top-level fields\n    main_row = {\"doc_uuid\": doc_uuid, \"document_name\": Path(file_path).name}\n    for k, v in f.items():\n        if isinstance(v, dict):\n            for sk, sv in v.items():\n                main_row[f\"{k}__{sk}\"] = sv\n        elif not isinstance(v, list):\n            main_row[k] = v\n\n    # Extract list fields as line rows\n    line_rows = [\n        {\"doc_uuid\": doc_uuid, \"list_field\": k, \"line_index\": i, **item}\n        for k, v in f.items() if isinstance(v, list)\n        for i, item in enumerate(v) if isinstance(item, dict)\n    ]\n\n    # Chunk rows from parse result\n    chunk_rows = [\n        {\n            \"doc_uuid\": doc_uuid,\n            \"chunk_id\": getattr(ch, \"id\", None),\n            \"chunk_type\": getattr(ch, \"type\", None),\n            \"page\": ch.grounding.page if hasattr(ch, \"grounding\") else None,\n        }\n        for ch in (parse_result.chunks or [])\n    ]\n\n    md_record = {\n        \"doc_uuid\": doc_uuid,\n        \"markdown\": parse_result.markdown,\n    }\n    return main_row, line_rows, chunk_rows, md_record\n```\n\n> **Full code** with Snowflake upload, UUID traceability, and bounding box\n> columns: see [database-integration.md](references/database-integration.md).\n\n---\n\n## RAG Preparation\n\nQuick path from parsed documents to a queryable RAG system. Two\nembedding options: **local** (free, offline) or **API** (higher quality).\n\n### Option A — Local embeddings with FastEmbed (free)\n\n```python\nimport re\nfrom fastembed import TextEmbedding\n\n\ndef ade_to_embeddings_local(\n    parse_results: list[dict],\n    model: str = \"BAAI/bge-small-en-v1.5\",\n) -> list[dict]:\n    \"\"\"Embed ADE chunks locally. Returns list of dicts with\n    text, vector, and grounding metadata.\"\"\"\n    embedder = TextEmbedding(model_name=model)\n    items: list[dict] = []\n    for pr in parse_results:\n        for ch in (pr[\"parse_result\"].chunks or []):\n            text = re.sub(\n                r\"<a id='[^']*'>\\s*</a>\", \"\", ch.markdown,\n            ).strip()\n            if not text:\n                continue\n            items.append({\n                \"text\": text,\n                \"source\": pr[\"name\"],\n                \"page\": ch.grounding.page,\n                \"box\": {\n                    \"l\": ch.grounding.box.left,\n                    \"t\": ch.grounding.box.top,\n                    \"r\": ch.grounding.box.right,\n                    \"b\": ch.grounding.box.bottom,\n                },\n            })\n    vecs = list(embedder.embed([i[\"text\"] for i in items]))\n    for item, vec in zip(items, vecs):\n        item[\"vector\"] = vec.tolist()\n    return items\n```\n\n### Option B — API embeddings with OpenAI\n\n```python\nfrom langchain.docstore.document import Document\nfrom langchain_community.vectorstores import FAISS\nfrom langchain_openai import OpenAIEmbeddings\n\n\ndef ade_to_rag(\n    parse_results: list[dict],\n    embedding_model: str = \"text-embedding-3-small\",\n) -> FAISS:\n    \"\"\"Convert ADE parse results to a FAISS vector store.\n\n    Args:\n        parse_results: list of {\"name\": str, \"parse_result\": ParseResponse}\n    \"\"\"\n    docs = [\n        Document(\n            page_content=ch.markdown,\n            metadata={\n                \"source\": item[\"name\"],\n                \"chunk_type\": getattr(ch, \"type\", \"\"),\n                \"page\": ch.grounding.page if hasattr(ch, \"grounding\") else -1,\n            },\n        )\n        for item in parse_results\n        for ch in (item[\"parse_result\"].chunks or [])\n        if ch.markdown.strip()\n    ]\n    return FAISS.from_documents(\n        docs, OpenAIEmbeddings(model=embedding_model)\n    )\n```\n\n> **Full code** with embedding best practices, hierarchical chunking,\n> multi-granularity strategies, ChromaDB, LangChain RetrievalQA, and\n> CSV export: see [rag-pipelines.md](references/rag-pipelines.md).\n\n**Advanced RAG patterns in [rag-pipelines.md](references/rag-pipelines.md):**\n\n- **Embedding computation** (blocks 18–19) — choosing between local (FastEmbed, free) and API (OpenAI, higher quality) embeddings, including batch sizing and rate limiting\n- **Hierarchical chunking** (block 20) — embed at multiple granularities (chunk, section, document) for hybrid retrieval\n- **Multi-granularity RAG** (block 21) — combine chunk-level precision with document-level context, routing queries to the right embedding level based on scope\n\n---\n\n## Visualization\n\nQuick snippet for bounding box overlays on parsed pages:\n\n```python\nfrom PIL import Image, ImageDraw\nimport pymupdf\n\nCHUNK_COLORS = {\n    \"text\": (40, 167, 69),\n    \"table\": (0, 123, 255),\n    \"figure\": (255, 0, 255),\n    \"marginalia\": (111, 66, 193),\n}\n\ndef annotate_page(\n    img: Image.Image, chunks: list, page: int,\n) -> Image.Image:\n    annotated = img.copy()\n    draw = ImageDraw.Draw(annotated)\n    w, h = img.size\n    for ch in chunks:\n        if not hasattr(ch, \"grounding\") or ch.grounding.page != page:\n            continue\n        box = ch.grounding.box\n        color = CHUNK_COLORS.get(getattr(ch, \"type\", \"\"), (200, 200, 200))\n        draw.rectangle(\n            [int(box.left * w), int(box.top * h),\n             int(box.right * w), int(box.bottom * h)],\n            outline=color, width=3,\n        )\n    return annotated\n```\n\n> **Full code** with chunk image cropping, extraction-only overlays, and\n> word-level OCR grounding: see [visualization.md](references/visualization.md).\n\n---\n\n## Streamlit UI Pattern\n\nQuick Streamlit app for interactive document processing:\n\n```python\nimport streamlit as st\nfrom pathlib import Path\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nst.title(\"Document Processor\")\n\nuploaded = st.file_uploader(\n    \"Upload document\", type=[\"pdf\", \"png\", \"jpg\"]\n)\nif uploaded:\n    # Save temp file\n    tmp = Path(f\"/tmp/{uploaded.name}\")\n    tmp.write_bytes(uploaded.read())\n\n    client = LandingAIADE()\n\n    with st.spinner(\"Parsing...\"):\n        pr = client.parse(document=tmp)\n\n    st.subheader(\"Markdown Preview\")\n    st.markdown(pr.markdown[:2000])\n\n    st.subheader(\"Chunks\")\n    for ch in pr.chunks:\n        with st.expander(\n            f\"{ch.type} (page {ch.grounding.page})\"\n        ):\n            st.text(ch.markdown[:500])\n```\n<!-- Requires: pip install landingai-ade streamlit -->\n\n> **Full Streamlit app** with batch upload, extraction display, and\n> visualization tabs: adapt from the patterns in\n> [batch-processing.md](references/batch-processing.md) and\n> [visualization.md](references/visualization.md).\n\n---\n\n## Dependency Guide\n\n| Workflow | Install |\n|----------|---------|\n| Core (parse + extract) | `pip install landingai-ade` |\n| Batch sync | `pip install landingai-ade tqdm` |\n| Batch async | `pip install landingai-ade aiolimiter` |\n| DataFrames / CSV | `pip install landingai-ade pandas` |\n| Snowflake | `pip install landingai-ade pandas snowflake-connector-python[pandas]` |\n| RAG (local embeddings) | `pip install landingai-ade fastembed` |\n| RAG (ChromaDB) | `pip install landingai-ade chromadb openai` |\n| RAG (FAISS + LangChain) | `pip install landingai-ade langchain langchain-openai langchain-community faiss-cpu` |\n| Visualization | `pip install landingai-ade Pillow pymupdf` |\n| Word-level grounding | `pip install landingai-ade Pillow pymupdf pytesseract fuzzywuzzy` + `tesseract` binary |\n| Streamlit UI | `pip install landingai-ade streamlit` |\n| Schema conversion | `from landingai_ade.lib import pydantic_to_json_schema` (included in landingai-ade) |\n\n---\n\n## Reference Files\n\nRead these for full implementations when building a specific workflow:\n\n- **[schema-catalog.md](references/schema-catalog.md)** — Ready-to-use Pydantic schemas for invoice, utility bill, bank statement, pay stub, food label, CME certificate, and document classification\n- **[batch-processing.md](references/batch-processing.md)** — ThreadPoolExecutor, AsyncLandingAIADE, and Parse Jobs API patterns with full error handling\n- **[rag-pipelines.md](references/rag-pipelines.md)** — Chunks to CSV, ChromaDB ingestion, FAISS + LangChain, and RAG query chains\n- **[database-integration.md](references/database-integration.md)** — DataFrame normalization, Snowflake upload, and CSV export patterns\n- **[visualization.md](references/visualization.md)** — Chunk image cropping, bounding box overlays, and word-level OCR grounding\n- **[table-stitching.md](references/table-stitching.md)** — Parse+Extract (robust), HTML parsing (fragile), and pandas approaches for merging multi-page tables into a single output\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/batch-processing.md",
    "content": "# Batch Processing Patterns\n\nThree approaches for processing multiple documents, from simplest to most\nscalable. All patterns include per-document error handling so one failure\ndoesn't stop the batch.\n\n---\n\n## 1. Sync Parallel — ThreadPoolExecutor\n\nBest for: moderate batches (10–200 docs), simple scripts, notebooks.\n\n```python\nimport io\nimport json\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom pathlib import Path\nfrom typing import Any, List, Tuple, Type\n\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom tqdm import tqdm\n\n\ndef parse_extract_save(\n    doc_path: Path,\n    client: LandingAIADE,\n    schema_cls: Type[Any],\n    output_dir: Path,\n) -> Tuple[Any, Any]:\n    \"\"\"Parse one document, extract with schema, save both\n    results as JSON. Returns (parse_result, extract_result).\"\"\"\n    output_dir.mkdir(parents=True, exist_ok=True)\n    stem = doc_path.stem\n\n    # Step 1 — Parse\n    parse_result = client.parse(document=doc_path)\n    _save_json(\n        parse_result, output_dir / f\"parse_{stem}.json\"\n    )\n\n    # Step 2 — Extract\n    json_schema = pydantic_to_json_schema(schema_cls)\n    extract_result = client.extract(\n        schema=json_schema,\n        markdown=io.BytesIO(\n            parse_result.markdown.encode(\"utf-8\")\n        ),\n    )\n    _save_json(\n        extract_result, output_dir / f\"extract_{stem}.json\"\n    )\n    return parse_result, extract_result\n\n\ndef _save_json(obj: Any, path: Path) -> None:\n    data = (\n        obj.model_dump()\n        if hasattr(obj, \"model_dump\")\n        else obj\n    )\n    path.write_text(\n        json.dumps(data, indent=2, default=str),\n        encoding=\"utf-8\",\n    )\n\n\ndef batch_parse_extract(\n    file_paths: List[Path],\n    schema_cls: Type[Any],\n    output_dir: Path = Path(\"./ade_results\"),\n    max_workers: int = 4,\n    api_key: str | None = None,\n) -> List[Tuple[Path, Any, Any]]:\n    \"\"\"Process a list of documents in parallel.\n\n    Returns list of (path, parse_result, extract_result)\n    for successful documents. Failures are printed but\n    do not stop the batch.\n    \"\"\"\n    client = LandingAIADE(\n        **({\"apikey\": api_key} if api_key else {})\n    )\n    results: List[Tuple[Path, Any, Any]] = []\n\n    with ThreadPoolExecutor(max_workers=max_workers) as pool:\n        futures = {\n            pool.submit(\n                parse_extract_save,\n                fp, client, schema_cls, output_dir,\n            ): fp\n            for fp in file_paths\n        }\n        for future in tqdm(\n            as_completed(futures),\n            total=len(futures),\n            desc=\"Processing\",\n        ):\n            fp = futures[future]\n            try:\n                pr, er = future.result()\n                results.append((fp, pr, er))\n            except Exception as exc:\n                print(f\"FAILED {fp.name}: {exc}\")\n\n    return results\n```\n\n### Usage\n\n```python\nfrom pathlib import Path\nfrom my_schema import InvoiceSchema  # or any Pydantic model\n\nfiles = sorted(Path(\"invoices/\").glob(\"*.pdf\"))\nresults = batch_parse_extract(\n    files,\n    schema_cls=InvoiceSchema,\n    output_dir=Path(\"./results\"),\n    max_workers=6,\n)\nprint(f\"Processed {len(results)}/{len(files)} documents\")\n```\n\n---\n\n## 2. Async Parallel — AsyncLandingAIADE\n\nBest for: large batches (100+ docs), CLI tools, production pipelines.\nUses `asyncio` + `aiolimiter` for rate-limited concurrency.\n\n```python\nimport asyncio\nimport json\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional\n\nimport pandas as pd\nfrom aiolimiter import AsyncLimiter\nfrom landingai_ade import AsyncLandingAIADE\n\n\nSUPPORTED_EXTS = {\".pdf\", \".png\", \".jpg\", \".jpeg\"}\n\n\ndef collect_files(input_dir: Path) -> List[Path]:\n    return sorted(\n        p for p in input_dir.glob(\"*\")\n        if p.is_file() and p.suffix.lower() in SUPPORTED_EXTS\n    )\n\n\nasync def process_document(\n    file_path: Path,\n    client: AsyncLandingAIADE,\n    output_dirs: Dict[str, Path],\n    rate_limiter: AsyncLimiter,\n) -> Optional[Dict[str, Any]]:\n    \"\"\"Parse one document async, save JSON + markdown.\"\"\"\n    try:\n        async with rate_limiter:\n            result = await client.parse(document=file_path)\n\n        stem = file_path.stem\n        # Save JSON\n        (output_dirs[\"json\"] / f\"{stem}.json\").write_text(\n            json.dumps(\n                result.model_dump(), indent=2, default=str\n            ),\n            encoding=\"utf-8\",\n        )\n        # Save markdown\n        (output_dirs[\"markdown\"] / f\"{stem}.md\").write_text(\n            result.markdown, encoding=\"utf-8\"\n        )\n        return {\"path\": file_path, \"result\": result}\n    except Exception as exc:\n        print(f\"FAILED {file_path.name}: {exc}\")\n        return None\n\n\nasync def batch_parse_async(\n    input_dir: Path,\n    output_dir: Path,\n    max_concurrent: int = 10,\n    rate_limit: int = 30,\n    api_key: str | None = None,\n) -> List[Dict[str, Any]]:\n    \"\"\"Parse all documents in input_dir concurrently.\n\n    Args:\n        input_dir: folder with documents\n        output_dir: base output folder (json/, markdown/\n                    subdirs created automatically)\n        max_concurrent: max parallel requests\n        rate_limit: max requests per minute\n    \"\"\"\n    files = collect_files(input_dir)\n    if not files:\n        print(f\"No documents found in {input_dir}\")\n        return []\n\n    # Create output subdirectories\n    dirs: Dict[str, Path] = {}\n    for sub in (\"json\", \"markdown\"):\n        d = output_dir / sub\n        d.mkdir(parents=True, exist_ok=True)\n        dirs[sub] = d\n\n    client = AsyncLandingAIADE(\n        **({\"apikey\": api_key} if api_key else {})\n    )\n    limiter = AsyncLimiter(rate_limit, 60)\n\n    tasks = [\n        process_document(fp, client, dirs, limiter)\n        for fp in files\n    ]\n    raw = await asyncio.gather(*tasks)\n    return [r for r in raw if r is not None]\n```\n\n### Usage\n\n```python\nimport asyncio\nfrom pathlib import Path\n\nresults = asyncio.run(\n    batch_parse_async(\n        input_dir=Path(\"documents/\"),\n        output_dir=Path(\"results/\"),\n        max_concurrent=10,\n        rate_limit=30,\n    )\n)\nprint(f\"Parsed {len(results)} documents\")\n```\n\n### Adding Extraction to Async Pipeline\n\n```python\nimport io\nfrom landingai_ade.lib import pydantic_to_json_schema\n\n\nasync def process_with_extraction(\n    file_path: Path,\n    client: AsyncLandingAIADE,\n    schema_cls: type,\n    output_dirs: Dict[str, Path],\n    rate_limiter: AsyncLimiter,\n) -> Optional[Dict[str, Any]]:\n    try:\n        async with rate_limiter:\n            parse_result = await client.parse(\n                document=file_path\n            )\n        async with rate_limiter:\n            extract_result = await client.extract(\n                schema=pydantic_to_json_schema(schema_cls),\n                markdown=io.BytesIO(\n                    parse_result.markdown.encode(\"utf-8\")\n                ),\n            )\n        return {\n            \"path\": file_path,\n            \"parse\": parse_result,\n            \"extract\": extract_result,\n        }\n    except Exception as exc:\n        print(f\"FAILED {file_path.name}: {exc}\")\n        return None\n```\n\n---\n\n## 3. Large File Processing — Parse Jobs API\n\nBest for: files > 50 MB (up to ~1 GB). Uses async job submission +\npolling instead of synchronous upload.\n\n```python\nimport time\nfrom pathlib import Path\nfrom typing import Any\n\nfrom landingai_ade import LandingAIADE\n\n\ndef parse_large_file(\n    file_path: Path,\n    client: LandingAIADE,\n    poll_interval: int = 10,\n    max_wait: int = 600,\n) -> Any:\n    \"\"\"Submit a large file as a parse job and poll until\n    complete.\n\n    Returns the parse result (same shape as client.parse()).\n    \"\"\"\n    # Step 1 — Submit job\n    job = client.parse(\n        document=file_path, is_async=True\n    )\n    job_id = job.request_id\n    print(f\"Job submitted: {job_id}\")\n\n    # Step 2 — Poll for completion\n    elapsed = 0\n    while elapsed < max_wait:\n        status = client.get_parse_job(job_id)\n        if status.status == \"complete\":\n            print(f\"Job complete after {elapsed}s\")\n            return status.data\n        if status.status == \"failed\":\n            raise RuntimeError(\n                f\"Parse job {job_id} failed: {status}\"\n            )\n        time.sleep(poll_interval)\n        elapsed += poll_interval\n\n    raise TimeoutError(\n        f\"Job {job_id} not complete after {max_wait}s\"\n    )\n```\n\n### Batch Large Files\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor\n\ndef batch_parse_large(\n    file_paths: list[Path],\n    max_workers: int = 3,\n) -> list[Any]:\n    client = LandingAIADE()\n    results = []\n    with ThreadPoolExecutor(max_workers=max_workers) as pool:\n        futures = {\n            pool.submit(\n                parse_large_file, fp, client\n            ): fp\n            for fp in file_paths\n        }\n        for fut in futures:\n            try:\n                results.append(fut.result())\n            except Exception as exc:\n                fp = futures[fut]\n                print(f\"FAILED {fp.name}: {exc}\")\n    return results\n```\n\n---\n\n## Rate Limiting & Error Handling Tips\n\n| Concern | Recommendation |\n|---------|---------------|\n| API rate limits | Use `aiolimiter.AsyncLimiter(30, 60)` for async; limit `max_workers` for sync |\n| Transient failures | Wrap individual doc processing in try/except; log and continue |\n| Large batches (1000+) | Use async pattern with `rate_limit=20`; monitor API response times |\n| Memory | Process results incrementally (save to disk per doc) rather than accumulating in memory |\n| Retries | Add exponential backoff for 429/5xx errors: `tenacity.retry(wait=wait_exponential())` |\n\n### Dependencies\n\n```\n# Sync parallel (ThreadPoolExecutor)\npip install landingai-ade tqdm\n\n# Async parallel\npip install landingai-ade aiolimiter pandas\n\n# Large files — no extra deps beyond landingai-ade\n```\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/database-integration.md",
    "content": "# Database Integration Patterns\n\nPatterns for normalizing ADE extraction results into relational tables\nand loading them into databases. Covers DataFrame normalization, CSV\nexport, and Snowflake insertion.\n\n---\n\n## 1. DataFrame Normalization\n\nADE extraction results are nested dicts. This pattern flattens them into\n4 normalized tables suitable for any relational DB:\n\n| Table | Contents |\n|-------|----------|\n| `main` | One row per document — top-level extracted fields |\n| `line_items` | One row per line item / repeating element |\n| `chunks` | One row per parsed chunk with bounding boxes |\n| `markdown` | One row per document — full markdown for traceability |\n\n```python\nimport uuid\nfrom datetime import datetime, timezone\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple\n\n\ndef _dig(obj: Any, *keys: str, default: Any = None) -> Any:\n    \"\"\"Safely traverse nested dicts/objects by key path.\"\"\"\n    for k in keys:\n        if obj is None:\n            return default\n        if isinstance(obj, dict):\n            obj = obj.get(k, default)\n        else:\n            obj = getattr(obj, k, default)\n    return obj\n\n\ndef _to_float(v: Any) -> Optional[float]:\n    if v is None:\n        return None\n    try:\n        return float(v)\n    except (ValueError, TypeError):\n        return None\n\n\ndef rows_from_doc(\n    file_path: str,\n    parse_result: Any,\n    extract_result: Any,\n    run_id: str | None = None,\n) -> Tuple[\n    Dict[str, Any],\n    List[Dict[str, Any]],\n    List[Dict[str, Any]],\n    Dict[str, Any],\n]:\n    \"\"\"Transform ADE parse + extract results into 4 row types.\n\n    Returns: (main_row, line_rows, chunk_rows, markdown_record)\n\n    Args:\n        file_path: original document path\n        parse_result: from client.parse()\n        extract_result: from client.extract()\n        run_id: optional batch run identifier\n    \"\"\"\n    doc_name = Path(file_path).name\n    doc_uuid = str(uuid.uuid4())\n    now = datetime.now(timezone.utc).isoformat()\n    rid = run_id or doc_uuid\n\n    f = extract_result.extraction  # dict\n    m = getattr(extract_result, \"extraction_metadata\", {})\n\n    # --- markdown record ---\n    markdown_record = {\n        \"run_id\": rid,\n        \"doc_uuid\": doc_uuid,\n        \"document_name\": doc_name,\n        \"processed_at\": now,\n        \"markdown\": parse_result.markdown,\n    }\n\n    # --- chunk rows ---\n    chunk_rows: List[Dict[str, Any]] = []\n    for ch in (parse_result.chunks or []):\n        box = (\n            ch.grounding.box\n            if hasattr(ch, \"grounding\")\n            and hasattr(ch.grounding, \"box\")\n            else None\n        )\n        chunk_rows.append({\n            \"run_id\": rid,\n            \"doc_uuid\": doc_uuid,\n            \"document_name\": doc_name,\n            \"chunk_id\": getattr(ch, \"id\", None),\n            \"chunk_type\": getattr(ch, \"type\", None),\n            \"text\": getattr(ch, \"markdown\", None),\n            \"page\": (\n                ch.grounding.page\n                if hasattr(ch, \"grounding\")\n                else None\n            ),\n            \"box_l\": _to_float(box.left if box else None),\n            \"box_t\": _to_float(box.top if box else None),\n            \"box_r\": _to_float(box.right if box else None),\n            \"box_b\": _to_float(box.bottom if box else None),\n        })\n\n    # --- main row (flatten top-level fields) ---\n    main_row: Dict[str, Any] = {\n        \"run_id\": rid,\n        \"doc_uuid\": doc_uuid,\n        \"document_name\": doc_name,\n        \"processed_at\": now,\n    }\n    # Flatten one level of nesting\n    for key, val in f.items():\n        if isinstance(val, dict):\n            for sub_key, sub_val in val.items():\n                main_row[f\"{key}__{sub_key}\"] = sub_val\n        elif isinstance(val, list):\n            pass  # lists go to line_items\n        else:\n            main_row[key] = val\n\n    # --- line item rows ---\n    line_rows: List[Dict[str, Any]] = []\n    for key, val in f.items():\n        if not isinstance(val, list):\n            continue\n        for idx, item in enumerate(val):\n            row: Dict[str, Any] = {\n                \"run_id\": rid,\n                \"doc_uuid\": doc_uuid,\n                \"document_name\": doc_name,\n                \"list_field\": key,\n                \"line_index\": idx,\n            }\n            if isinstance(item, dict):\n                row.update(item)\n            else:\n                row[\"value\"] = item\n            line_rows.append(row)\n\n    return main_row, line_rows, chunk_rows, markdown_record\n```\n\n### Usage — Build DataFrames from a Batch\n\n```python\nimport pandas as pd\nfrom pathlib import Path\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclient = LandingAIADE()\nrun_id = \"batch_2025_01\"\n\nall_main, all_lines, all_chunks, all_md = [], [], [], []\n\nfor fp in Path(\"invoices/\").glob(\"*.pdf\"):\n    pr = client.parse(document=fp)\n    er = client.extract(\n        schema=pydantic_to_json_schema(InvoiceSchema),\n        markdown=pr.markdown,\n    )\n    main, lines, chunks, md = rows_from_doc(\n        str(fp), pr, er, run_id=run_id\n    )\n    all_main.append(main)\n    all_lines.extend(lines)\n    all_chunks.extend(chunks)\n    all_md.append(md)\n\ndf_main = pd.DataFrame(all_main)\ndf_lines = pd.DataFrame(all_lines)\ndf_chunks = pd.DataFrame(all_chunks)\ndf_md = pd.DataFrame(all_md)\n\n# Save to CSV\nfor name, df in [\n    (\"main\", df_main),\n    (\"line_items\", df_lines),\n    (\"chunks\", df_chunks),\n    (\"markdown\", df_md),\n]:\n    df.to_csv(f\"{run_id}_{name}.csv\", index=False)\n```\n\n---\n\n## 2. Snowflake Integration\n\nUpload normalized tables to Snowflake using the connector's\n`write_pandas` or staged COPY pattern.\n\n> **Note:** ADE is also available as a **Snowflake Native App** (GA since Nov 2025), which runs ADE directly inside your Snowflake account without data leaving Snowflake. The patterns below use the standard Python SDK connector approach. For the Native App, see [Snowflake Native App docs](https://docs.landing.ai/ade/ade-snowflake).\n\n### Connection Setup\n\n```python\nimport snowflake.connector\nfrom snowflake.connector.pandas_tools import write_pandas\n\n\ndef get_snowflake_conn(\n    account: str,\n    user: str,\n    password: str,\n    database: str,\n    schema: str,\n    warehouse: str,\n    role: str = \"SYSADMIN\",\n) -> snowflake.connector.SnowflakeConnection:\n    return snowflake.connector.connect(\n        account=account,\n        user=user,\n        password=password,\n        database=database,\n        schema=schema,\n        warehouse=warehouse,\n        role=role,\n    )\n```\n\n### Table Creation\n\n```sql\n-- Main extraction results (one row per document)\nCREATE TABLE IF NOT EXISTS ade_extractions (\n    run_id          VARCHAR,\n    doc_uuid        VARCHAR PRIMARY KEY,\n    document_name   VARCHAR,\n    processed_at    TIMESTAMP_TZ,\n    -- Add flattened extraction columns here\n    -- e.g., invoice_info__invoice_number VARCHAR\n);\n\n-- Line items (one row per repeating element)\nCREATE TABLE IF NOT EXISTS ade_line_items (\n    run_id          VARCHAR,\n    doc_uuid        VARCHAR REFERENCES ade_extractions(doc_uuid),\n    document_name   VARCHAR,\n    list_field      VARCHAR,\n    line_index      INTEGER,\n    -- Add line item columns here\n);\n\n-- Parsed chunks with bounding boxes\nCREATE TABLE IF NOT EXISTS ade_chunks (\n    run_id          VARCHAR,\n    doc_uuid        VARCHAR REFERENCES ade_extractions(doc_uuid),\n    document_name   VARCHAR,\n    chunk_id        VARCHAR,\n    chunk_type      VARCHAR,\n    text            VARCHAR,\n    page            INTEGER,\n    box_l           FLOAT,\n    box_t           FLOAT,\n    box_r           FLOAT,\n    box_b           FLOAT\n);\n\n-- Full markdown for traceability\nCREATE TABLE IF NOT EXISTS ade_markdown (\n    run_id          VARCHAR,\n    doc_uuid        VARCHAR REFERENCES ade_extractions(doc_uuid),\n    document_name   VARCHAR,\n    processed_at    TIMESTAMP_TZ,\n    markdown        VARCHAR(16777216)\n);\n```\n\n### Upload DataFrames\n\n```python\ndef upload_to_snowflake(\n    conn: snowflake.connector.SnowflakeConnection,\n    df_main: \"pd.DataFrame\",\n    df_lines: \"pd.DataFrame\",\n    df_chunks: \"pd.DataFrame\",\n    df_md: \"pd.DataFrame\",\n) -> None:\n    \"\"\"Upload all 4 normalized tables to Snowflake.\"\"\"\n    # Column names must be UPPER CASE for Snowflake\n    for table, df in [\n        (\"ADE_EXTRACTIONS\", df_main),\n        (\"ADE_LINE_ITEMS\", df_lines),\n        (\"ADE_CHUNKS\", df_chunks),\n        (\"ADE_MARKDOWN\", df_md),\n    ]:\n        if df.empty:\n            continue\n        df.columns = [c.upper() for c in df.columns]\n        write_pandas(\n            conn, df, table,\n            auto_create_table=True,\n            overwrite=False,\n        )\n        print(f\"Uploaded {len(df)} rows to {table}\")\n```\n\n### Full Pipeline: Parse → Extract → Snowflake\n\n```python\nimport io\nimport pandas as pd\nfrom pathlib import Path\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\n\ndef ade_to_snowflake(\n    input_dir: Path,\n    schema_cls: type,\n    sf_conn: \"snowflake.connector.SnowflakeConnection\",\n    run_id: str = \"default\",\n) -> int:\n    \"\"\"Parse, extract, normalize, and upload to Snowflake.\n\n    Returns number of documents processed.\n    \"\"\"\n    client = LandingAIADE()\n    exts = {\".pdf\", \".png\", \".jpg\", \".jpeg\"}\n    files = [\n        p for p in input_dir.glob(\"*\")\n        if p.suffix.lower() in exts\n    ]\n\n    all_main, all_lines, all_chunks, all_md = (\n        [], [], [], []\n    )\n    for fp in files:\n        try:\n            pr = client.parse(document=fp)\n            er = client.extract(\n                schema=pydantic_to_json_schema(schema_cls),\n                markdown=io.BytesIO(\n                    pr.markdown.encode(\"utf-8\")\n                ),\n            )\n            main, lines, chunks, md = rows_from_doc(\n                str(fp), pr, er, run_id=run_id\n            )\n            all_main.append(main)\n            all_lines.extend(lines)\n            all_chunks.extend(chunks)\n            all_md.append(md)\n        except Exception as exc:\n            print(f\"FAILED {fp.name}: {exc}\")\n\n    upload_to_snowflake(\n        sf_conn,\n        pd.DataFrame(all_main),\n        pd.DataFrame(all_lines),\n        pd.DataFrame(all_chunks),\n        pd.DataFrame(all_md),\n    )\n    return len(all_main)\n```\n\n---\n\n## 3. CSV Export Patterns\n\n### Summary CSV — One Row per Document\n\n```python\ndef extractions_to_summary_csv(\n    results: list[tuple[str, dict]],\n    output_path: Path,\n) -> \"pd.DataFrame\":\n    \"\"\"Create a summary CSV with one row per document.\n\n    Args:\n        results: list of (filename, extraction_dict) tuples\n        output_path: CSV file path\n    \"\"\"\n    rows = []\n    for name, extraction in results:\n        row = {\"document_name\": name}\n        for k, v in extraction.items():\n            if isinstance(v, dict):\n                for sk, sv in v.items():\n                    row[f\"{k}__{sk}\"] = sv\n            elif isinstance(v, list):\n                row[f\"{k}__count\"] = len(v)\n            else:\n                row[k] = v\n        rows.append(row)\n    df = pd.DataFrame(rows)\n    df.to_csv(output_path, index=False)\n    return df\n```\n\n### Per-Document JSON + Combined CSV\n\n```python\nimport json\n\ndef save_results(\n    file_path: Path,\n    parse_result: Any,\n    extract_result: Any,\n    output_dir: Path,\n) -> None:\n    \"\"\"Save individual JSON files + append to combined CSV.\"\"\"\n    stem = file_path.stem\n    output_dir.mkdir(parents=True, exist_ok=True)\n\n    # Individual JSON\n    for prefix, obj in [\n        (\"parse\", parse_result),\n        (\"extract\", extract_result),\n    ]:\n        data = (\n            obj.model_dump()\n            if hasattr(obj, \"model_dump\")\n            else obj\n        )\n        (output_dir / f\"{prefix}_{stem}.json\").write_text(\n            json.dumps(data, indent=2, default=str),\n            encoding=\"utf-8\",\n        )\n```\n\n---\n\n## Dependencies\n\n```\n# DataFrame + CSV only\npip install landingai-ade pandas\n\n# Snowflake integration\npip install landingai-ade pandas snowflake-connector-python[pandas]\n\n# Environment variable management\npip install python-dotenv pydantic-settings\n```\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/rag-pipelines.md",
    "content": "# RAG Pipeline Patterns\n\nEnd-to-end patterns for preparing ADE-parsed documents for Retrieval\nAugmented Generation (RAG) systems. Covers embedding computation,\nchunking strategies, vector DB ingestion, and query pipelines.\n\n---\n\n## 1. Chunks to CSV — RAG-Ready Dataset\n\nExtract all chunks from parsed documents into a structured CSV with 19\ncolumns including bounding boxes, sequence info, and metadata. This CSV\ncan feed any vector DB or search index.\n\n> **Grounding-aware records:** Every record includes `page`, `box_l`,\n> `box_t`, `box_r`, `box_b` from ADE's grounding data. Preserve these\n> columns when ingesting into a vector DB — they let you trace retrieval\n> results back to exact document locations for highlighting or citation.\n\n```python\nimport re\nfrom pathlib import Path\nfrom typing import Any, Dict, List\n\nimport pandas as pd\n\n\ndef clean_chunk_text(text: str) -> str:\n    \"\"\"Remove anchor tags and strip whitespace.\"\"\"\n    cleaned = re.sub(r\"<a id='[^']*'>\\s*</a>\", \"\", text)\n    return cleaned.strip()\n\n\ndef chunks_to_records(\n    parse_result: Any,\n    document_name: str,\n    model_version: str = \"unknown\",\n) -> List[Dict[str, Any]]:\n    \"\"\"Convert parse result chunks to flat dicts.\n\n    Each dict has 19 columns suitable for CSV / DataFrame:\n    DOCUMENT_NAME, chunk_id, chunk_sequence_number,\n    chunk_type, chunk_content_raw, chunk_content,\n    chunk_text_length, chunk_word_count, page,\n    box_l, box_t, box_r, box_b,\n    prev_chunk_id, next_chunk_id, chunk_image_path,\n    processed_at, ade_version, model_version\n    \"\"\"\n    from datetime import datetime, timezone\n\n    import landingai_ade\n\n    chunks = parse_result.chunks or []\n    now = datetime.now(timezone.utc).isoformat()\n    records: List[Dict[str, Any]] = []\n\n    for idx, ch in enumerate(chunks):\n        raw = ch.markdown if hasattr(ch, \"markdown\") else \"\"\n        clean = clean_chunk_text(raw)\n        box = (\n            ch.grounding.box\n            if hasattr(ch, \"grounding\")\n            and hasattr(ch.grounding, \"box\")\n            else None\n        )\n        page = (\n            ch.grounding.page\n            if hasattr(ch, \"grounding\")\n            else None\n        )\n        records.append({\n            \"DOCUMENT_NAME\": document_name,\n            \"chunk_id\": getattr(ch, \"id\", None),\n            \"chunk_sequence_number\": idx,\n            \"chunk_type\": getattr(ch, \"type\", None),\n            \"chunk_content_raw\": raw,\n            \"chunk_content\": clean,\n            \"chunk_text_length\": len(clean),\n            \"chunk_word_count\": len(clean.split()) if clean else 0,\n            \"page\": page,\n            \"box_l\": box.left if box else None,\n            \"box_t\": box.top if box else None,\n            \"box_r\": box.right if box else None,\n            \"box_b\": box.bottom if box else None,\n            \"prev_chunk_id\": (\n                chunks[idx - 1].id if idx > 0 else None\n            ),\n            \"next_chunk_id\": (\n                chunks[idx + 1].id\n                if idx < len(chunks) - 1\n                else None\n            ),\n            \"chunk_image_path\": None,\n            \"processed_at\": now,\n            \"ade_version\": landingai_ade.__version__,\n            \"model_version\": model_version,\n        })\n    return records\n\n\ndef batch_chunks_to_csv(\n    results: List[Dict[str, Any]],\n    output_path: Path,\n) -> pd.DataFrame:\n    \"\"\"Combine chunk records from multiple documents into\n    one CSV.\n\n    Args:\n        results: list of dicts with keys 'name' and\n                 'parse_result'\n        output_path: CSV file path\n    \"\"\"\n    all_records: List[Dict[str, Any]] = []\n    for r in results:\n        all_records.extend(\n            chunks_to_records(r[\"parse_result\"], r[\"name\"])\n        )\n    df = pd.DataFrame(all_records)\n    df.to_csv(output_path, index=False)\n    return df\n```\n\n### Usage\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\nresults = []\nfor fp in Path(\"docs/\").glob(\"*.pdf\"):\n    pr = client.parse(document=fp)\n    results.append({\"name\": fp.name, \"parse_result\": pr})\n\ndf = batch_chunks_to_csv(results, Path(\"all_chunks.csv\"))\nprint(f\"{len(df)} chunks from {df['DOCUMENT_NAME'].nunique()} docs\")\n```\n\n---\n\n## 2. Vector DB Ingestion — ChromaDB\n\nLocal persistent vector store using OpenAI embeddings. Good for\nprototyping and small-to-medium corpora.\n\n```python\nfrom pathlib import Path\nfrom typing import Any, List\n\nimport chromadb\nfrom chromadb.config import Settings\nfrom openai import OpenAI\n\n\ndef ade_chunks_to_chromadb(\n    parse_results: List[dict],\n    collection_name: str = \"ade_documents\",\n    persist_dir: str = \"./chroma_db\",\n    embedding_model: str = \"text-embedding-3-small\",\n) -> chromadb.Collection:\n    \"\"\"Ingest ADE chunks into a persistent ChromaDB collection.\n\n    Args:\n        parse_results: list of dicts with 'name' (str) and\n                       'parse_result' (ParseResponse)\n        collection_name: ChromaDB collection name\n        persist_dir: directory for persistent storage\n        embedding_model: OpenAI embedding model name\n\n    Returns:\n        The ChromaDB collection with all chunks ingested.\n    \"\"\"\n    openai_client = OpenAI()\n    chroma_client = chromadb.PersistentClient(\n        path=persist_dir\n    )\n    collection = chroma_client.get_or_create_collection(\n        name=collection_name,\n        metadata={\"hnsw:space\": \"cosine\"},\n    )\n\n    for doc in parse_results:\n        name = doc[\"name\"]\n        chunks = doc[\"parse_result\"].chunks or []\n\n        texts, ids, metadatas = [], [], []\n        for ch in chunks:\n            text = ch.markdown if hasattr(ch, \"markdown\") else \"\"\n            if not text.strip():\n                continue\n            chunk_id = f\"{name}:{ch.id}\"\n            texts.append(text)\n            ids.append(chunk_id)\n            metadatas.append({\n                \"document\": name,\n                \"chunk_type\": getattr(ch, \"type\", \"unknown\"),\n                \"page\": (\n                    ch.grounding.page\n                    if hasattr(ch, \"grounding\")\n                    else -1\n                ),\n            })\n\n        if not texts:\n            continue\n\n        # Generate embeddings in batches of 100\n        all_embeddings: List[List[float]] = []\n        for i in range(0, len(texts), 100):\n            batch = texts[i : i + 100]\n            resp = openai_client.embeddings.create(\n                input=batch, model=embedding_model\n            )\n            all_embeddings.extend(\n                [e.embedding for e in resp.data]\n            )\n\n        collection.add(\n            ids=ids,\n            documents=texts,\n            embeddings=all_embeddings,\n            metadatas=metadatas,\n        )\n\n    return collection\n```\n\n### Query ChromaDB\n\n```python\ndef query_chromadb(\n    collection: chromadb.Collection,\n    question: str,\n    n_results: int = 5,\n    embedding_model: str = \"text-embedding-3-small\",\n) -> dict:\n    \"\"\"Query the collection and return matching chunks.\"\"\"\n    openai_client = OpenAI()\n    resp = openai_client.embeddings.create(\n        input=[question], model=embedding_model\n    )\n    query_embedding = resp.data[0].embedding\n    return collection.query(\n        query_embeddings=[query_embedding],\n        n_results=n_results,\n    )\n```\n\n---\n\n## 3. Vector DB Ingestion — FAISS + LangChain\n\nFor LangChain-based RAG pipelines. Uses FAISS for in-memory vector\nsearch.\n\n```python\nfrom typing import Any, List\n\nfrom langchain.docstore.document import Document\nfrom langchain_community.vectorstores import FAISS\nfrom langchain_openai import OpenAIEmbeddings\n\n\ndef ade_to_langchain_docs(\n    parse_results: List[dict],\n) -> List[Document]:\n    \"\"\"Convert ADE parse results to LangChain Documents.\n\n    Each chunk becomes one Document with metadata including\n    source document name, chunk type, and page number.\n    \"\"\"\n    docs: List[Document] = []\n    for item in parse_results:\n        name = item[\"name\"]\n        chunks = item[\"parse_result\"].chunks or []\n        for ch in chunks:\n            text = ch.markdown if hasattr(ch, \"markdown\") else \"\"\n            if not text.strip():\n                continue\n            docs.append(Document(\n                page_content=text,\n                metadata={\n                    \"source\": name,\n                    \"chunk_type\": getattr(ch, \"type\", \"unknown\"),\n                    \"chunk_id\": getattr(ch, \"id\", \"\"),\n                    \"page\": (\n                        ch.grounding.page\n                        if hasattr(ch, \"grounding\")\n                        else -1\n                    ),\n                },\n            ))\n    return docs\n\n\ndef build_faiss_index(\n    documents: List[Document],\n    embedding_model: str = \"text-embedding-3-small\",\n) -> FAISS:\n    \"\"\"Build a FAISS vector store from LangChain Documents.\"\"\"\n    embeddings = OpenAIEmbeddings(model=embedding_model)\n    return FAISS.from_documents(documents, embeddings)\n```\n\n### RAG Query with LangChain\n\n```python\nfrom langchain.chains import RetrievalQA\nfrom langchain_openai import ChatOpenAI\n\n\ndef build_rag_chain(\n    vectorstore: FAISS,\n    model: str = \"gpt-4o-mini\",\n    k: int = 5,\n) -> RetrievalQA:\n    \"\"\"Build a RetrievalQA chain from a FAISS index.\"\"\"\n    retriever = vectorstore.as_retriever(\n        search_kwargs={\"k\": k}\n    )\n    return RetrievalQA.from_chain_type(\n        llm=ChatOpenAI(model=model, temperature=0),\n        chain_type=\"stuff\",\n        retriever=retriever,\n        return_source_documents=True,\n    )\n\n\n# Usage\nchain = build_rag_chain(vectorstore)\nanswer = chain.invoke({\"query\": \"What is the total revenue?\"})\nprint(answer[\"result\"])\nfor doc in answer[\"source_documents\"]:\n    print(f\"  - {doc.metadata['source']} p{doc.metadata['page']}\")\n```\n\n---\n\n## 4. Full RAG Pipeline — End to End\n\nCombines parsing, chunking, vector DB, and querying into one flow.\n\n```python\nimport asyncio\nfrom pathlib import Path\n\nfrom langchain.chains import RetrievalQA\nfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings\nfrom langchain_community.vectorstores import FAISS\nfrom landingai_ade import LandingAIADE\n\n\ndef build_rag_from_folder(\n    input_dir: Path,\n    embedding_model: str = \"text-embedding-3-small\",\n    llm_model: str = \"gpt-4o-mini\",\n) -> RetrievalQA:\n    \"\"\"One-shot: parse all docs in a folder and build a\n    RAG chain ready for querying.\n\n    Returns a LangChain RetrievalQA chain.\n    \"\"\"\n    client = LandingAIADE()\n    exts = {\".pdf\", \".png\", \".jpg\", \".jpeg\"}\n    files = [\n        p for p in input_dir.glob(\"*\")\n        if p.suffix.lower() in exts\n    ]\n\n    # Parse all documents\n    parse_results = []\n    for fp in files:\n        pr = client.parse(document=fp)\n        parse_results.append({\"name\": fp.name, \"parse_result\": pr})\n\n    # Convert to LangChain docs\n    docs = ade_to_langchain_docs(parse_results)\n\n    # Build vector store\n    embeddings = OpenAIEmbeddings(model=embedding_model)\n    vectorstore = FAISS.from_documents(docs, embeddings)\n\n    # Build chain\n    return RetrievalQA.from_chain_type(\n        llm=ChatOpenAI(model=llm_model, temperature=0),\n        chain_type=\"stuff\",\n        retriever=vectorstore.as_retriever(\n            search_kwargs={\"k\": 5}\n        ),\n        return_source_documents=True,\n    )\n```\n\n### Usage\n\n```python\nchain = build_rag_from_folder(Path(\"10k_filings/\"))\nresult = chain.invoke(\n    {\"query\": \"What were the main risk factors?\"}\n)\nprint(result[\"result\"])\n```\n\n---\n\n## 5. Embedding Computation\n\nTwo approaches for computing embeddings from ADE chunks: **local**\n(free, offline, fast) and **API-based** (higher quality, paid). Choose\nbased on your cost/quality tradeoff.\n\n### Local Embeddings with FastEmbed\n\nUses [FastEmbed](https://github.com/qdrant/fastembed) to run embedding\nmodels locally. No API key needed, no per-token cost, works offline.\n\n```python\nfrom typing import Any\n\nfrom fastembed import TextEmbedding\n\n\ndef compute_embeddings_local(\n    texts: list[str],\n    model: str = \"BAAI/bge-small-en-v1.5\",\n) -> list[list[float]]:\n    \"\"\"Embed texts locally with FastEmbed (batched).\n\n    Default model: BAAI/bge-small-en-v1.5 (384 dims, ~33M params).\n    Other options:\n      - BAAI/bge-base-en-v1.5  (768 dims, ~110M params)\n      - sentence-transformers/all-MiniLM-L6-v2  (384 dims)\n    \"\"\"\n    embedder = TextEmbedding(model_name=model)\n    return [v.tolist() for v in embedder.embed(texts)]\n```\n\n### API Embeddings with OpenAI\n\nHigher quality, especially for domain-specific content. Requires\n`OPENAI_API_KEY` and incurs per-token cost.\n\n```python\nfrom openai import OpenAI\n\n\ndef compute_embeddings_openai(\n    texts: list[str],\n    model: str = \"text-embedding-3-small\",\n    batch_size: int = 100,\n) -> list[list[float]]:\n    \"\"\"Embed texts via OpenAI API in batches.\"\"\"\n    client = OpenAI()\n    all_vecs: list[list[float]] = []\n    for i in range(0, len(texts), batch_size):\n        resp = client.embeddings.create(\n            input=texts[i : i + batch_size], model=model,\n        )\n        all_vecs.extend(e.embedding for e in resp.data)\n    return all_vecs\n```\n\n### Embedding Best Practices\n\n| Practice | Why | Example |\n|----------|-----|---------|\n| **Prepend title/heading** | Gives the embedding semantic context about what the chunk is about | `f\"{title}\\n\\n{body}\"` |\n| **Batch all texts in one call** | Faster than embedding one-by-one; both FastEmbed and OpenAI support batching | `embedder.embed(all_texts)` |\n| **Store model metadata** | Consumers need to know which model produced the vectors to query correctly | `{\"model\": \"bge-small-en-v1.5\", \"dims\": 384}` |\n| **Carry grounding refs** | Enables source attribution — trace retrieval hits back to page + bounding box | `{\"page\": 2, \"box\": {...}}` |\n| **Clean anchor tags first** | ADE chunks contain `<a id='...'>` tags that add noise to embeddings | `re.sub(r\"<a id='[^']*'>\\s*</a>\", \"\", text)` |\n\n### Self-Describing Embedding Output\n\nAlways store the embedding model name and dimensions alongside the\nvector so downstream consumers can interpret it correctly:\n\n```python\ndef make_embedding_record(\n    text: str,\n    vector: list[float],\n    model: str,\n    metadata: dict | None = None,\n) -> dict:\n    \"\"\"Wrap a vector with its model info and metadata.\"\"\"\n    return {\n        \"text\": text,\n        \"embedding\": {\n            \"model\": model,\n            \"dimensions\": len(vector),\n            \"vector\": vector,\n        },\n        \"metadata\": metadata or {},\n    }\n```\n\n### Model Selection Guide\n\n| Model | Dims | Cost | Quality | Best for |\n|-------|------|------|---------|----------|\n| `BAAI/bge-small-en-v1.5` | 384 | Free (local) | Good | Prototyping, cost-sensitive, offline |\n| `BAAI/bge-base-en-v1.5` | 768 | Free (local) | Better | Local with higher quality needs |\n| `text-embedding-3-small` | 1536 | ~$0.02/1M tokens | High | Production, mixed-domain content |\n| `text-embedding-3-large` | 3072 | ~$0.13/1M tokens | Highest | Maximum retrieval accuracy |\n\n---\n\n## 6. Multi-Granularity Embedding Strategy\n\nADE chunks are the finest-grained unit, but they're not always the\nright unit for embedding. Choose the granularity that matches your\nretrieval needs.\n\n### Granularity Levels\n\n| Level | Unit | How to build | Best for |\n|-------|------|-------------|----------|\n| **Chunk** | Raw ADE chunk | Direct from `parse_result.chunks` | Tables, figures, forms with independent fields |\n| **Hierarchical** | Group of consecutive chunks | Group by boundary detection (see below) | Narrative docs where answers span paragraphs |\n| **Document** | Full markdown or summary | `parse_result.markdown` or ADE extract summary | Classification, routing, coarse-grained search |\n\n### Chunk-Level (default)\n\nEach ADE chunk gets its own embedding. This is what Sections 2–4 above\nuse. Fine-grained but may split semantic units across multiple vectors.\n\n```python\n# Already shown in Sections 2-4 — each chunk → one embedding\ntexts = [\n    clean_chunk_text(ch.markdown)\n    for ch in parse_result.chunks\n    if ch.markdown.strip()\n    and getattr(ch, \"type\", \"\") in {\"text\", \"table\", \"card\"}\n]\n```\n\n### Hierarchical Chunking\n\nGroup consecutive ADE chunks into higher-level semantic units before\nembedding. The grouping boundary is **document-specific** — the pattern\nis always the same but the boundary detection varies:\n\n- **Heading detection** (regex or ADE extract) — for papers, reports\n- **Clause boundaries** (ADE split API or extract) — for contracts\n- **Page boundaries** — simple, works for any document\n- **Fixed-size sliding windows** — N consecutive chunks with overlap\n\nThe abstract pattern:\n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Any, Callable\n\n\n@dataclass\nclass ChunkGroup:\n    \"\"\"A group of consecutive ADE chunks forming a semantic unit.\"\"\"\n    label: str\n    chunks: list[Any] = field(default_factory=list)\n    grounding_refs: list[dict] = field(default_factory=list)\n\n    @property\n    def text(self) -> str:\n        return \"\\n\".join(\n            clean_chunk_text(ch.markdown)\n            for ch in self.chunks if ch.markdown.strip()\n        )\n\n    @property\n    def embedding_input(self) -> str:\n        \"\"\"Prepend label for better embedding quality.\"\"\"\n        return f\"{self.label}\\n\\n{self.text}\"\n\n\ndef group_chunks(\n    chunks: list[Any],\n    is_boundary: Callable[[Any], str | None],\n) -> list[ChunkGroup]:\n    \"\"\"Group ADE chunks by a boundary detection function.\n\n    Args:\n        chunks: ADE parse_result.chunks\n        is_boundary: function that returns a group label\n            (str) if the chunk starts a new group, or\n            None if it continues the current group.\n\n    Returns:\n        List of ChunkGroup with grounding refs preserved.\n    \"\"\"\n    groups: list[ChunkGroup] = []\n    current: ChunkGroup | None = None\n    for ch in chunks:\n        label = is_boundary(ch)\n        if label is not None:\n            current = ChunkGroup(label=label)\n            groups.append(current)\n        if current is None:\n            current = ChunkGroup(label=\"(preamble)\")\n            groups.append(current)\n        current.chunks.append(ch)\n        if hasattr(ch, \"grounding\"):\n            b = ch.grounding.box\n            current.grounding_refs.append({\n                \"page\": ch.grounding.page,\n                \"box\": {\n                    \"left\": b.left, \"top\": b.top,\n                    \"right\": b.right, \"bottom\": b.bottom,\n                },\n            })\n    return groups\n```\n\n**Example boundary detectors:**\n\n```python\nimport re\n\n# Page-based: new group every page\ndef by_page(ch: Any) -> str | None:\n    page = ch.grounding.page if hasattr(ch, \"grounding\") else -1\n    return f\"Page {page + 1}\" if not hasattr(by_page, \"_last\") or by_page._last != page else None\n    # (simplified — use a closure or class for production)\n\n# Heading-based: new group on ATX or numbered headings\ndef by_heading(ch: Any) -> str | None:\n    text = re.sub(r\"<a id='[^']*'></a>\\s*\", \"\", ch.markdown or \"\").strip()\n    first_line = text.split(\"\\n\")[0].strip()\n    if re.match(r\"^#{1,6}\\s+\", first_line):\n        return re.sub(r\"^#{1,6}\\s+\", \"\", first_line)\n    if re.match(r\"^\\d+(?:\\.\\d+)*\\.?\\s+[A-Z]\", first_line):\n        return first_line\n    return None\n```\n\n**Using groups for embedding:**\n\n```python\ngroups = group_chunks(parse_result.chunks, by_heading)\ntexts = [g.embedding_input for g in groups if g.text.strip()]\nvectors = compute_embeddings_local(texts)\n\n# Each group carries grounding_refs for source attribution\nfor g, vec in zip(groups, vectors):\n    print(f\"{g.label}: {len(g.grounding_refs)} chunk refs, \"\n          f\"{len(vec)} dims\")\n```\n\n### Document-Level\n\nEmbed the full document markdown or a summary. Useful for routing\nqueries to the right document before doing fine-grained search.\n\n```python\n# Full markdown (may be long — consider truncation)\ndoc_text = parse_result.markdown[:8000]\ndoc_vec = compute_embeddings_local([doc_text])[0]\n\n# Or use ADE extract to get a summary first\nfrom landingai_ade.lib import pydantic_to_json_schema\nfrom pydantic import BaseModel, Field\n\nclass DocSummary(BaseModel):\n    summary: str = Field(\n        description=\"A 2-3 sentence summary of the document.\"\n    )\n\ner = client.extract(\n    schema=pydantic_to_json_schema(DocSummary),\n    markdown=parse_result.markdown,\n)\nsummary_vec = compute_embeddings_local(\n    [er.extraction[\"summary\"]]\n)[0]\n```\n\n### Decision Matrix\n\n| Document Type | Recommended | Rationale |\n|--------------|-------------|-----------|\n| Academic papers, reports | Hierarchical (by heading) | Answers span paragraphs within sections |\n| Invoices, forms | Chunk-level | Each field is independent |\n| Mixed document batches | Document-level + chunk-level | Route first, then search within |\n| Contracts, legal docs | Hierarchical (by clause) | Clauses are the natural retrieval unit |\n| Slide decks | Chunk-level (by page) | Each slide is self-contained |\n| Long narratives (books) | Hierarchical (sliding window) | Fixed-size windows with overlap |\n\n---\n\n## Chunk Filtering Tips\n\nNot all chunks are useful for RAG. Filter by type to improve relevance:\n\n```python\n# Keep only text and table chunks (skip logos, scan codes)\nRAG_CHUNK_TYPES = {\"text\", \"table\", \"card\"}\n\ndocs = [\n    Document(page_content=ch.markdown, metadata={...})\n    for ch in parse_result.chunks\n    if getattr(ch, \"type\", \"\") in RAG_CHUNK_TYPES\n    and ch.markdown.strip()\n]\n```\n\n---\n\n## Dependencies\n\n```\n# Chunks to CSV only\npip install landingai-ade pandas\n\n# Local embeddings (free, offline)\npip install landingai-ade fastembed\n\n# ChromaDB pipeline (API embeddings)\npip install landingai-ade chromadb openai\n\n# FAISS + LangChain pipeline (API embeddings)\npip install landingai-ade langchain langchain-openai langchain-community faiss-cpu\n\n# Local embeddings + ChromaDB\npip install landingai-ade fastembed chromadb\n\n# Full pipeline (all options)\npip install landingai-ade pandas fastembed chromadb openai langchain langchain-openai langchain-community faiss-cpu\n```\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/schema-catalog.md",
    "content": "# Schema Catalog — Ready-to-Use Pydantic Models\n\nReady-to-use extraction schemas for common document types.\nEach schema is a Pydantic `BaseModel` that can be converted to JSON Schema\nvia `pydantic_to_json_schema` and passed to `client.extract()`.\n\n> **Tip:** ADE supports **one level of nesting**. Use nested `BaseModel`\n> sub-classes for logical grouping, and `List[SubModel]` for repeating items\n> like line items or transactions.\n\n---\n\n## Usage Pattern (all schemas)\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclient = LandingAIADE()\nparse_result = client.parse(document=path)\nextract_result = client.extract(\n    schema=pydantic_to_json_schema(MySchema),\n    markdown=parse_result.markdown,\n)\ndata: dict = extract_result.extraction\n```\n\n---\n\n## 1. Invoice Schema\n\n6 nested groups, 30+ fields. Covers invoices from any vendor/country.\n\n```python\nfrom typing import Optional, List\nfrom datetime import date\nfrom pydantic import BaseModel, Field\n\n\nclass DocumentInfo(BaseModel):\n    invoice_date_raw: str = Field(\n        ...,\n        description=(\n            \"Invoice date as found in the document.\"\n            \" Do not reformat.\"\n        ),\n    )\n    invoice_date: Optional[date] = Field(\n        ..., description=\"Invoice date in YYYY-MM-DD.\"\n    )\n    invoice_number: str = Field(\n        ..., description=\"Invoice number.\"\n    )\n    order_date: Optional[str] = Field(\n        None, description=\"Order or purchase date.\"\n    )\n    po_number: Optional[str] = Field(\n        None, description=\"Customer purchase order (PO) number.\"\n    )\n    status: Optional[str] = Field(\n        None,\n        description=\"Payment status (e.g., PAID, UNPAID).\",\n    )\n\n\nclass CustomerInfo(BaseModel):\n    sold_to_name: str = Field(\n        ...,\n        description=(\n            \"Name of the customer billed.\"\n            \" Can be a person or an organization.\"\n        ),\n    )\n    sold_to_address: Optional[str] = Field(\n        None, description=\"Address of the customer billed.\"\n    )\n    customer_email: Optional[str] = Field(\n        None, description=\"Email address for the customer.\"\n    )\n\n\nclass SupplierInfo(BaseModel):\n    supplier_name: str = Field(\n        ..., description=\"Name of the supplier company.\"\n    )\n    supplier_address: Optional[str] = Field(\n        None, description=\"Address of the supplier.\"\n    )\n    representative: Optional[str] = Field(\n        None, description=\"Sales representative(s).\"\n    )\n    email: Optional[str] = Field(\n        None, description=\"Email address of the supplier.\"\n    )\n    phone: Optional[str] = Field(\n        None, description=\"Phone number of the supplier.\"\n    )\n    gstin: Optional[str] = Field(\n        None, description=\"GSTIN of the supplier (India).\"\n    )\n    pan: Optional[str] = Field(\n        None, description=\"Permanent Account Number (India).\"\n    )\n\n\nclass TermsAndShipping(BaseModel):\n    payment_terms: Optional[str] = Field(\n        None, description=\"Payment terms (e.g., Net 30).\"\n    )\n    ship_via: Optional[str] = Field(\n        None, description=\"Carrier/service (e.g., UPS Ground).\"\n    )\n    ship_date: Optional[str] = Field(\n        None, description=\"Date shipped.\"\n    )\n    tracking_number: Optional[str] = Field(\n        None, description=\"Tracking number.\"\n    )\n\n\nclass TotalsSummary(BaseModel):\n    currency: Optional[str] = Field(\n        None, description=\"ISO currency code.\"\n    )\n    total_due_raw: Optional[str] = Field(\n        None, description=\"Total due as shown in the doc.\"\n    )\n    total_due: float = Field(\n        ..., description=\"Total amount due (numeric, no symbols).\"\n    )\n    subtotal: Optional[float] = Field(\n        None, description=\"Subtotal (numeric).\"\n    )\n    tax: Optional[float] = Field(\n        None, description=\"Tax (numeric).\"\n    )\n    shipping: Optional[float] = Field(\n        None, description=\"Shipping (numeric).\"\n    )\n    handling_fee: Optional[float] = Field(\n        None, description=\"Handling fee (numeric).\"\n    )\n\n\nclass LineItem(BaseModel):\n    line_number: Optional[str] = Field(\n        None, description=\"Printed line number.\"\n    )\n    sku: Optional[str] = Field(\n        None, description=\"SKU / Item code / Part number.\"\n    )\n    description: str = Field(\n        ..., description=\"Item or service description.\"\n    )\n    quantity: Optional[float] = Field(\n        None, description=\"Quantity purchased.\"\n    )\n    unit_price: Optional[float] = Field(\n        None, description=\"Unit price (numeric).\"\n    )\n    amount: Optional[float] = Field(\n        None, description=\"Extended line amount (numeric).\"\n    )\n\n\nclass InvoiceSchema(BaseModel):\n    invoice_info: DocumentInfo = Field(\n        description=\"Key identifiers and dates.\"\n    )\n    customer_info: CustomerInfo = Field(\n        description=\"Details about the customer billed.\"\n    )\n    company_info: SupplierInfo = Field(\n        description=\"Details about the issuing company.\"\n    )\n    order_details: TermsAndShipping = Field(\n        description=\"Payment and shipping information.\"\n    )\n    totals_summary: TotalsSummary = Field(\n        description=\"Financial totals by category.\"\n    )\n    line_items: List[LineItem] = Field(\n        default_factory=list,\n        description=\"List of items included in the invoice.\",\n    )\n```\n\n---\n\n## 2. Utility Bill Schema\n\nProvider, account, billing summary, electric and gas charges.\n\n```python\nfrom typing import Optional\nfrom pydantic import BaseModel, Field\n\n\nclass ProviderInfo(BaseModel):\n    provider: str = Field(\n        ..., description=\"Name of the utility provider.\"\n    )\n    phone_number: Optional[str] = Field(\n        None,\n        description=\"Customer service phone (XXX-XXX-XXXX).\",\n    )\n    website: Optional[str] = Field(\n        None, description=\"Official website URL.\"\n    )\n    usage_bar_chart: bool = Field(\n        False,\n        description=\"Does the bill include a usage trend chart?\",\n    )\n\n\nclass AccountInfo(BaseModel):\n    account_holder: str = Field(\n        ...,\n        description=(\n            \"Full name of the account holder.\"\n            \" May be a person or organization.\"\n        ),\n    )\n    account_number: str = Field(\n        ..., description=\"Unique customer account identifier.\"\n    )\n    service_address: str = Field(\n        ...,\n        description=(\n            \"Full service address on one line\"\n            \" (remove newlines, replace with space).\"\n        ),\n    )\n    service_address_city: Optional[str] = Field(\n        None, description=\"City of service address.\"\n    )\n    service_address_state: Optional[str] = Field(\n        None, description=\"2-letter state abbreviation.\"\n    )\n    service_address_zip: Optional[str] = Field(\n        None, description=\"5-digit ZIP code.\"\n    )\n\n\nclass BillingSummary(BaseModel):\n    due_date: str = Field(\n        ..., description=\"Payment due date (YYYY-MM-DD).\"\n    )\n    bill_date: str = Field(\n        ..., description=\"Bill issue date (YYYY-MM-DD).\"\n    )\n    service_start_date: Optional[str] = Field(\n        None, description=\"Service period start (MM-DD-YYYY).\"\n    )\n    service_end_date: Optional[str] = Field(\n        None, description=\"Service period end (MM-DD-YYYY).\"\n    )\n    total_amount_due: str = Field(\n        ...,\n        description=\"Total amount due including currency symbol.\",\n    )\n\n\nclass ElectricCharges(BaseModel):\n    meter_number: Optional[str] = Field(\n        None,\n        description=(\n            \"Electric meter identifier.\"\n            \" Blank if no electric service.\"\n        ),\n    )\n    usage_kwh: Optional[str] = Field(\n        None, description=\"Total kWh for billing period.\"\n    )\n    total_electric_charges: Optional[str] = Field(\n        None,\n        description=\"Total electric charges with currency symbol.\",\n    )\n\n\nclass GasCharges(BaseModel):\n    meter_number: Optional[str] = Field(\n        None,\n        description=(\n            \"Gas meter identifier.\"\n            \" Blank if no gas service.\"\n        ),\n    )\n    usage_therms: Optional[str] = Field(\n        None, description=\"Total therms for billing period.\"\n    )\n    total_gas_charges: Optional[str] = Field(\n        None,\n        description=\"Total gas charges with currency symbol.\",\n    )\n\n\nclass UtilityBillSchema(BaseModel):\n    provider_info: ProviderInfo = Field(\n        description=\"Energy provider details.\"\n    )\n    account_info: AccountInfo = Field(\n        description=\"Account and customer identifiers.\"\n    )\n    billing_summary: BillingSummary = Field(\n        description=\"Charges and due dates.\"\n    )\n    electric_charges: ElectricCharges = Field(\n        description=\"Electric usage and charges.\"\n    )\n    gas_charges: GasCharges = Field(\n        description=\"Gas usage and charges.\"\n    )\n```\n\n---\n\n## 3. Bank Statement Schema\n\n```python\nfrom typing import Optional, List\nfrom pydantic import BaseModel, Field\n\n\nclass BankTransaction(BaseModel):\n    date: str = Field(\n        ..., description=\"Transaction date (YYYY-MM-DD).\"\n    )\n    description: str = Field(\n        ..., description=\"Transaction description.\"\n    )\n    amount: float = Field(\n        ..., description=\"Transaction amount (numeric).\"\n    )\n    type: Optional[str] = Field(\n        None,\n        description=\"Transaction type: debit or credit.\",\n    )\n\n\nclass BankStatementSchema(BaseModel):\n    bank_name: str = Field(\n        ..., description=\"Name of the bank.\"\n    )\n    account_number: str = Field(\n        ..., description=\"Bank account number.\"\n    )\n    statement_period: Optional[str] = Field(\n        None,\n        description=\"Statement period (e.g., Jan 1 - Jan 31, 2025).\",\n    )\n    opening_balance: Optional[float] = Field(\n        None, description=\"Opening balance (numeric).\"\n    )\n    closing_balance: float = Field(\n        ..., description=\"Closing / current balance (numeric).\"\n    )\n    total_deposits: Optional[float] = Field(\n        None, description=\"Total deposits (numeric).\"\n    )\n    total_withdrawals: Optional[float] = Field(\n        None, description=\"Total withdrawals (numeric).\"\n    )\n    transactions: List[BankTransaction] = Field(\n        default_factory=list,\n        description=\"List of transactions in the statement.\",\n    )\n```\n\n---\n\n## 3b. Multi-Page Table Schema (for Table Stitching)\n\nUse this pattern when a table spans multiple pages and you want the LLM\nto stitch all rows into a single list via `client.extract()`.\n\n```python\nfrom typing import List, Optional\nfrom pydantic import BaseModel, Field\n\n\nclass TableRow(BaseModel):\n    \"\"\"Generic row — customize fields for your table.\"\"\"\n    key_column: str = Field(\n        description=(\n            \"Primary identifier (e.g., date, ID). \"\n            \"Use empty string for continuation rows.\"\n        )\n    )\n    description: str = Field(\n        description=\"Description or label column.\"\n    )\n    amount_a: Optional[str] = Field(\n        default=None,\n        description=(\n            \"First amount column (digits and commas only, \"\n            \"no currency symbol). \"\n            \"Null if not applicable for this row.\"\n        ),\n    )\n    amount_b: Optional[str] = Field(\n        default=None,\n        description=(\n            \"Second amount column. \"\n            \"Null if not applicable.\"\n        ),\n    )\n    running_total: str = Field(\n        description=(\n            \"Running total or balance after this row.\"\n        )\n    )\n\n\nclass MultiPageTable(BaseModel):\n    rows: List[TableRow] = Field(\n        description=(\n            \"All data rows in order across ALL pages of \"\n            \"the document. Include rows from every page, \"\n            \"even if some pages render as plain text \"\n            \"rather than tables. \"\n            \"Skip column-header rows and section-header \"\n            \"rows.\"\n        )\n    )\n```\n\n**Schema design tips for multi-page tables:**\n- Say **\"across ALL pages\"** in the `List` field description\n- Mention **\"even if some pages render as plain text\"**\n- Say **\"Skip column-header rows\"** to avoid duplicated headers\n- Use `Optional[str]` for mutually exclusive amount columns\n- Use `str` (not `float`) for amounts to preserve original formatting\n- Add domain-specific hints in descriptions (e.g., \"running balance\n  after this transaction\") to help the LLM resolve ambiguities\n\n> **Full patterns** for three table stitching approaches (parse+extract,\n> HTML parsing, pandas): see\n> [table-stitching.md](table-stitching.md).\n\n---\n\n## 4. Pay Stub Schema\n\n```python\nfrom typing import Optional, List\nfrom pydantic import BaseModel, Field\n\n\nclass Deduction(BaseModel):\n    name: str = Field(\n        ..., description=\"Deduction name (e.g., Federal Tax).\"\n    )\n    amount: float = Field(\n        ..., description=\"Deduction amount (numeric).\"\n    )\n\n\nclass PayStubSchema(BaseModel):\n    employee_name: str = Field(\n        ..., description=\"Full name of the employee.\"\n    )\n    employer_name: Optional[str] = Field(\n        None, description=\"Name of the employer.\"\n    )\n    pay_period: str = Field(\n        ..., description=\"Pay period covered by this stub.\"\n    )\n    pay_date: Optional[str] = Field(\n        None, description=\"Payment date (YYYY-MM-DD).\"\n    )\n    gross_pay: float = Field(\n        ..., description=\"Gross pay amount (numeric).\"\n    )\n    net_pay: float = Field(\n        ..., description=\"Net pay after deductions (numeric).\"\n    )\n    total_deductions: Optional[float] = Field(\n        None, description=\"Total deductions (numeric).\"\n    )\n    deductions: List[Deduction] = Field(\n        default_factory=list,\n        description=\"Itemized deductions.\",\n    )\n```\n\n---\n\n## 5. Food / Product Label Schema\n\n27 fields covering identification, weight, certifications, and dietary claims.\n\n```python\nfrom pydantic import BaseModel, Field\n\n\nclass ProductLabelSchema(BaseModel):\n    # Identification\n    product_name: str = Field(\n        ...,\n        description=(\n            \"Full product name excluding brand\"\n            \" as it appears on packaging.\"\n        ),\n    )\n    brand: str = Field(\n        ..., description=\"Brand or company name.\"\n    )\n    product_type: str = Field(\n        ...,\n        description=(\n            \"General category (e.g., yogurt, hot dogs,\"\n            \" supplement, beef sticks).\"\n        ),\n    )\n    flavor: str = Field(\n        ...,\n        description=(\n            \"Flavor if applicable. Empty if not found.\"\n        ),\n    )\n    # Weight / Serving\n    net_weight_oz: float = Field(\n        ..., description=\"Net weight in ounces.\"\n    )\n    net_weight_g: float = Field(\n        ..., description=\"Net weight in grams.\"\n    )\n    servings_per_container: int = Field(\n        ..., description=\"Total servings per container.\"\n    )\n    serving_size: str = Field(\n        ...,\n        description=\"Serving size as printed (e.g., '1 stick (45g)').\",\n    )\n    # Certifications (bool flags)\n    is_organic: bool = Field(\n        ..., description=\"True if labeled Organic / USDA Organic.\"\n    )\n    is_non_gmo: bool = Field(\n        ..., description=\"True if Non-GMO Project Verified.\"\n    )\n    is_grass_fed: bool = Field(\n        ..., description=\"True if labeled Grass-Fed.\"\n    )\n    is_kosher: bool = Field(\n        ..., description=\"True if Kosher certified.\"\n    )\n    is_gluten_free: bool = Field(\n        ..., description=\"True if labeled Gluten-Free.\"\n    )\n    # Dietary claims\n    is_keto_friendly: bool = Field(\n        ..., description=\"True if labeled Keto.\"\n    )\n    is_dairy_free: bool = Field(\n        ..., description=\"True if labeled Dairy-Free.\"\n    )\n    has_no_added_sugar: bool = Field(\n        ...,\n        description=\"True if No Added Sugar / Zero Sugar.\",\n    )\n```\n\n> **Note:** The full food label schema has 27 fields including\n> `is_pasture_raised`, `is_certified_humane`, `no_antibiotics`,\n> `no_hormones`, `is_regenerative`, `is_paleo_friendly`,\n> `is_whole30_approved`, `is_lactose_free`, `usda_inspected`, etc.\n> Add fields as needed for your use case.\n\n---\n\n## 6. CME / Continuing Education Certificate\n\n```python\nfrom typing import Optional\nfrom pydantic import BaseModel, Field\n\n\nclass CMECertificateSchema(BaseModel):\n    recipient_name: str = Field(\n        ..., description=\"Full name of the certificate recipient.\"\n    )\n    issuing_organization: str = Field(\n        ...,\n        description=\"Organization that issued the certificate.\",\n    )\n    activity_title: str = Field(\n        ...,\n        description=\"Title of the educational activity or course.\",\n    )\n    completion_date: Optional[str] = Field(\n        None, description=\"Completion date (YYYY-MM-DD).\"\n    )\n    credits_earned: float = Field(\n        ..., description=\"Number of credits earned (numeric).\"\n    )\n    credit_type: Optional[str] = Field(\n        None,\n        description=(\n            \"Type of credit (e.g., CME, CE, CPE, CLE).\"\n        ),\n    )\n    certificate_id: Optional[str] = Field(\n        None, description=\"Certificate or confirmation number.\"\n    )\n    accreditation_statement: Optional[str] = Field(\n        None,\n        description=\"Accreditation or approval statement text.\",\n    )\n```\n\n---\n\n## 7. Document Classification Schema\n\nGeneric classifier using `Literal` enum. Adapt the type list to your\ndocument mix.\n\n```python\nfrom typing import Literal\nfrom pydantic import BaseModel, Field\n\n\nclass DocTypeClassification(BaseModel):\n    type: Literal[\n        \"invoice\",\n        \"bank_statement\",\n        \"pay_stub\",\n        \"utility_bill\",\n        \"receipt\",\n        \"contract\",\n    ] = Field(\n        description=\"The type of the document.\",\n        title=\"Document Type\",\n    )\n```\n\n### Classify-then-Extract Pattern\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nschema_map = {\n    \"invoice\": InvoiceSchema,\n    \"bank_statement\": BankStatementSchema,\n    \"pay_stub\": PayStubSchema,\n    \"utility_bill\": UtilityBillSchema,\n}\n\nclient = LandingAIADE()\nparse_result = client.parse(document=path)\n\n# Step 1: Classify\ncls_result = client.extract(\n    schema=pydantic_to_json_schema(DocTypeClassification),\n    markdown=parse_result.markdown,\n)\ndoc_type: str = cls_result.extraction[\"type\"]\n\n# Step 2: Extract with type-specific schema\nschema_cls = schema_map[doc_type]\nextract_result = client.extract(\n    schema=pydantic_to_json_schema(schema_cls),\n    markdown=parse_result.markdown,\n)\n```\n\n---\n\n## Tips for Custom Schemas\n\n1. **Use descriptive `description` fields** — ADE uses them as extraction\n   instructions. Be specific about format expectations.\n2. **Mark optional fields** with `Optional[T]` and `default=None` to avoid\n   extraction failures when a field is absent.\n3. **Use `default_factory=list`** for array fields (line items,\n   transactions) to avoid null results.\n4. **Keep nesting to one level** — ADE supports `TopLevel.nested_object`\n   but not `TopLevel.nested.deeper`.\n5. **Use `Literal` for enums** — constrains extraction to known values.\n6. **Prefer `float` over `str` for monetary amounts** — easier downstream\n   processing. Keep a `_raw` string variant if you need the original format.\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/table-stitching.md",
    "content": "# Table Stitching — Multi-Page Table Extraction\n\nWhen a table spans multiple pages, ADE emits separate chunks per page and\nmay represent some pages as plain text instead of `<table>` HTML. This\ninconsistency can occur on **any** page — not just the last one. This\nreference covers three approaches to stitch those chunks into a single\noutput, generalized for any document type.\n\n---\n\n## Decision Guide\n\n| Approach | ADE Calls | Handles non-table chunks | Fragility | Best when |\n|----------|-----------|--------------------------|-----------|-----------|\n| **A — Parse + Extract** | 2 | ✓ LLM reads full markdown | Low | Accuracy is paramount; cost is secondary |\n| **B — HTML table parsing** | 1 | ✓ with fallback regex | **High** — requires uniform row structure | Rows are highly uniform; cost savings justify fragility |\n| **C — pandas read_html** | 1 | ✗ misses non-table chunks | Medium | Quick prototyping; missing some rows is acceptable |\n\n---\n\n## Approach A — Parse + Extract (LLM-based)\n\nThe simplest and most robust approach. Parse the document, then call\n`client.extract()` with a schema that describes the full table as a\n`List[RowModel]`. The LLM reads the entire markdown — including any\npages where the table was emitted as plain text — and returns structured\nJSON.\n\n### Schema design for multi-page tables\n\n```python\nfrom typing import List, Optional\nfrom pydantic import BaseModel, Field\n\n\nclass TableRow(BaseModel):\n    \"\"\"Customize fields for your specific table.\"\"\"\n    key_column: str = Field(\n        description=(\n            \"Primary identifier (e.g., date, ID, row number). \"\n            \"Use empty string for continuation rows.\"\n        )\n    )\n    description: str = Field(\n        description=\"Description or label column.\"\n    )\n    amount_a: Optional[str] = Field(\n        default=None,\n        description=(\n            \"First amount column (digits and commas only, \"\n            \"no currency symbol). \"\n            \"Null if not applicable for this row.\"\n        ),\n    )\n    amount_b: Optional[str] = Field(\n        default=None,\n        description=(\n            \"Second amount column. \"\n            \"Null if not applicable.\"\n        ),\n    )\n    running_total: str = Field(\n        description=\"Running total or balance after this row.\"\n    )\n\n\nclass DocumentWithTable(BaseModel):\n    rows: List[TableRow] = Field(\n        description=(\n            \"All data rows in order across ALL pages of the \"\n            \"document. Include rows from every page of the \"\n            \"table, even if some pages render as plain text \"\n            \"rather than tables. \"\n            \"Skip column-header rows and section-header rows.\"\n        )\n    )\n```\n\n### Key schema tips\n\n- **Say \"across ALL pages\"** in the `List` field description — this\n  tells the LLM to look beyond the first table chunk.\n- **Mention \"even if some pages render as plain text\"** — the LLM\n  will then scan text chunks for table-like content.\n- **Say \"Skip column-header rows\"** — continued tables often repeat\n  headers on each page.\n- **Use `Optional[str]` for mutually exclusive columns** — e.g., when\n  only one of \"debit\" or \"credit\" applies per row.\n- **Use `str` (not `float`) for amounts** to preserve original\n  formatting (commas, decimals). Convert downstream if needed.\n\n### Implementation pattern\n\n```python\nimport json\nfrom pathlib import Path\n\nfrom landingai_ade import LandingAIADE\nfrom landingai_ade.lib import pydantic_to_json_schema\n\nclient = LandingAIADE()\n\n# Step 1: Parse (cache the result to avoid re-parsing)\nparse_json = Path(\"output/parsed.json\")\nif parse_json.exists():\n    data = json.loads(parse_json.read_text())\n    markdown = data[\"markdown\"]\nelse:\n    pr = client.parse(document=Path(\"document.pdf\"))\n    parse_json.parent.mkdir(parents=True, exist_ok=True)\n    parse_json.write_text(\n        json.dumps(pr.model_dump(), indent=2, default=str)\n    )\n    markdown = pr.markdown\n\n# Step 2: Extract with the multi-page table schema\ner = client.extract(\n    schema=pydantic_to_json_schema(DocumentWithTable),\n    markdown=markdown,\n)\nrows = er.extraction[\"rows\"]\n```\n\n### Pros / Cons\n\n- ✅ Handles all pages uniformly, including plain-text edge cases\n- ✅ No custom parsing code\n- ❌ Two ADE API calls → ~2× credit cost\n- ❌ Slower: two network round-trips\n\n---\n\n## Approach B — HTML Table Parsing (parse-only, fragile)\n\nReuse the cached parse result (zero extra credits). Parse `<table>`\nelements from the ADE markdown, detect which tables belong to the\ntarget table, merge their rows, then fall back to regex for any\nplain-text rows.\n\n> **Warning:** This approach requires **strong similarity between rows**\n> to write reliable detection and extraction regex. It is brittle when\n> table format varies across documents or even across pages of the same\n> document. Always validate against Approach A on a sample before\n> relying on this in production.\n\n### Generic HTML table parser\n\n```python\nfrom html.parser import HTMLParser\n\n\nclass TableParser(HTMLParser):\n    \"\"\"Extract all <table> elements as list-of-rows-of-cells.\"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self._tables: list[list[list[str]]] = []\n        self._tbl: list[list[str]] | None = None\n        self._row: list[str] | None = None\n        self._cell: list[str] | None = None\n\n    def handle_starttag(self, tag: str, attrs: list) -> None:\n        if tag == \"table\":\n            self._tbl = []\n        elif tag == \"tr\" and self._tbl is not None:\n            self._row = []\n        elif tag == \"td\" and self._row is not None:\n            self._cell = []\n\n    def handle_endtag(self, tag: str) -> None:\n        if tag == \"table\" and self._tbl is not None:\n            self._tables.append(self._tbl)\n            self._tbl = None\n        elif tag == \"tr\" and self._tbl is not None:\n            if self._row is not None:\n                self._tbl.append(self._row)\n            self._row = None\n        elif tag == \"td\" and self._row is not None:\n            if self._cell is not None:\n                self._row.append(\n                    \"\".join(self._cell).strip()\n                )\n            self._cell = None\n\n    def handle_data(self, data: str) -> None:\n        if self._cell is not None:\n            self._cell.append(data)\n\n    @property\n    def tables(self) -> list[list[list[str]]]:\n        return self._tables\n\n\ndef extract_html_tables(\n    markdown: str,\n) -> list[list[list[str]]]:\n    p = TableParser()\n    p.feed(markdown)\n    return p.tables\n```\n\n### Table detection strategies\n\nColumn count alone is often insufficient — multiple table types may\nshare the same number of columns. Use content-based signals:\n\n```\nIs there a header row with known column names?\n  ├─ YES → Match on header content (most reliable)\n  │        e.g., cells[0]==\"Date\" and \"Description\" in cells[1]\n  └─ NO → Does the first data cell match a known pattern?\n       ├─ YES → Match on first-column pattern\n       │        e.g., regex for \"Mon DD\" date format\n       └─ NO → Use column count + content heuristics\n                (least reliable — last resort)\n```\n\n### Row filtering\n\nAfter detecting the target table, filter out non-data rows:\n\n- **Column-header rows** — repeated on each page (e.g., `cells[0] == \"Date\"`)\n- **Section sub-headers** — account names, category labels\n- **Summary/totals rows** — may need special handling\n\n### Plain-text fallback\n\nWhen ADE emits table rows as a text chunk, use regex to extract them.\nThis is the most fragile part — it requires the text to have a\npredictable structure:\n\n```python\nimport re\n\n# Example: lines starting with a date pattern\nDATE_RE = re.compile(\n    r\"^((?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\"\n    r\"\\s+\\d{1,2})\\s+(.*)\"\n)\nAMOUNT_RE = re.compile(r\"[\\d,]+\\.\\d{2}\")\n\n\ndef parse_text_rows(\n    text: str,\n) -> list[dict[str, str]]:\n    \"\"\"Extract rows from plain-text table content.\n\n    Customize the date/amount patterns for your document type.\n    \"\"\"\n    rows: list[dict[str, str]] = []\n    for line in text.splitlines():\n        m = DATE_RE.match(line.strip())\n        if not m:\n            continue\n        date_str, rest = m.group(1), m.group(2)\n        amounts = AMOUNT_RE.findall(rest)\n        desc = AMOUNT_RE.sub(\"\", rest).strip()\n        rows.append({\n            \"date\": date_str,\n            \"description\": desc,\n            \"amounts\": amounts,\n        })\n    return rows\n```\n\n### Domain-specific semantic checks\n\nAfter stitching, add validation that leverages domain knowledge to\nboth **confirm correctness** and **resolve ambiguity**:\n\n| Domain | Check | Example |\n|--------|-------|---------|\n| Financial | Running balance | `prev ± amount ≈ new_balance` |\n| Financial | Column totals | Sum of rows = reported total |\n| Inventory | Quantity conservation | `in - out = remaining` |\n| Time-series | Chronological order | Dates are monotonically increasing |\n| Scientific | Consistent units | All values in same column share units |\n\nThese checks are especially valuable when plain-text fallback\nproduces amounts that could belong to multiple columns.\n\n### Pros / Cons\n\n- ✅ Single ADE API call → half the credit cost\n- ✅ Fast (parse result is cached; parsing runs locally)\n- ❌ Requires strong row similarity for reliable regex\n- ❌ Brittle — format changes across documents break detection\n- ❌ Plain-text fallback needs domain-specific validation\n\n---\n\n## Approach C — pandas `read_html` (parse-only, quick)\n\nLet pandas do the heavy lifting. Extract `<table>` HTML strings with\na regex, feed each to `pd.read_html()`, use pandas signals to detect\ntarget tables, then `pd.concat` to merge.\n\n> **Limitation:** This approach cannot recover rows from non-table\n> chunks. If ADE emits some pages as plain text, those rows are lost.\n\n### Implementation pattern\n\n```python\nimport re\nfrom io import StringIO\n\nimport pandas as pd\n\nTABLE_RE = re.compile(r\"<table\\b[^>]*>.*?</table>\", re.DOTALL)\n\n\ndef stitch_tables_pandas(\n    markdown: str,\n    expected_cols: int,\n    date_pattern: str = (\n        r\"^(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\"\n        r\"\\s+\\d+\"\n    ),\n) -> pd.DataFrame:\n    \"\"\"Extract and merge multi-page tables from ADE markdown.\n\n    Args:\n        markdown: Full ADE markdown output.\n        expected_cols: Expected number of columns in the target table.\n        date_pattern: Regex to match date-like values in column 0.\n    \"\"\"\n    table_htmls = TABLE_RE.findall(markdown)\n    target_dfs: list[pd.DataFrame] = []\n\n    for html in table_htmls:\n        df = pd.read_html(StringIO(html), thousands=\",\")[0]\n        if df.shape[1] != expected_cols:\n            continue\n        col0 = df.iloc[:, 0]\n        has_date = bool(\n            col0.astype(str).str.match(date_pattern).any()\n        )\n        has_numeric = (\n            df.select_dtypes(include=\"number\").shape[1] >= 1\n        )\n        if has_date or has_numeric:\n            target_dfs.append(df)\n\n    if not target_dfs:\n        raise ValueError(\"No target tables found\")\n    return pd.concat(target_dfs, ignore_index=True)\n```\n\n### Detection signals from pandas\n\n| Signal | How | Use |\n|--------|-----|-----|\n| `df.shape` | Column count | Filter by expected column count |\n| `select_dtypes(\"number\")` | Numeric column count | Tables without headers have auto-inferred numeric cols |\n| `col0.str.match(pattern)` | First-column pattern | Date, ID, or other key column pattern |\n| `col0.str.strip() == \"Header\"` | Header presence | Detect repeated column headers to drop |\n\n### Pitfall: pandas 3.x NaN trap\n\nAfter `pd.read_html`, empty cells are `float('nan')`. In pandas 3.x,\nafter `.astype(str)`, StringDtype keeps them as the `float('nan')`\n**object** rather than the string `\"nan\"`. This means:\n\n```python\n# BROKEN in pandas 3.x:\ncol_str = df.iloc[:, 0].astype(str)\nmask = col_str == \"nan\"  # Always False!\n\n# CORRECT — check on the raw column before string conversion:\nmask = pd.isna(df.iloc[:, 0])\n```\n\n### Amount formatting\n\n`pd.read_html(thousands=\",\")` strips commas from numbers during dtype\ninference. If you need comma-formatted output in CSV:\n\n```python\ndef fmt_amount(val: object) -> str:\n    if pd.isna(val):\n        return \"\"\n    if isinstance(val, float):\n        return f\"{val:,.2f}\"\n    s = str(val).strip()\n    try:\n        return f\"{float(s):,.2f}\"\n    except ValueError:\n        return s\n```\n\n### Pros / Cons\n\n- ✅ Least code — `pd.read_html` + `pd.concat` do most of the work\n- ✅ No custom HTML parser or regex\n- ✅ pandas dtype signals give a clear detection path\n- ❌ Cannot recover rows from non-table chunks\n- ❌ `pd.NA` / `float('nan')` trap in pandas 3.x\n- ❌ `thousands=\",\"` strips commas — must re-format for output\n\n---\n\n## Common Pitfalls\n\n1. **ADE may emit any page as plain text** — not just the last page.\n   Always check chunk types across all pages during pre-flight.\n\n2. **Column count alone is insufficient** — when multiple table types\n   share the same column count, use content-based detection (header\n   matching, first-column patterns, dtype signals).\n\n3. **Approach B regex is brittle** — test on multiple documents before\n   relying on it. Format variations across documents (or even across\n   pages of the same document) will break detection.\n\n4. **Always validate with domain-specific semantic checks** — these\n   catch errors that structural parsing misses and resolve ambiguities\n   in column assignment.\n\n5. **Cache parse results** — save `pr.model_dump()` to JSON after the\n   first parse. Load it for development instead of calling\n   `client.parse()` again. Only re-parse when the document changes.\n\n---\n\n## Pre-Flight Checklist for Table Stitching\n\nBefore choosing an approach, run the diagnostic parse and check:\n\n| What to check | How | Why |\n|---------------|-----|-----|\n| Chunk types per page | Count `type == \"table\"` vs `\"text\"` per page | Any page may have inconsistent types |\n| Column count consistency | Compare column counts across table chunks | Inconsistent counts may indicate different tables |\n| Header row presence | Check first row of each table chunk | Needed for detection and row filtering |\n| Non-target tables | Look for summary/metadata tables with same column count | Must distinguish target from others |\n| Row uniformity | Compare row structure across pages | Low uniformity makes Approach B fragile |\n| Plain-text table content | Inspect text chunks for table-like patterns | Determines if fallback is needed |\n"
  },
  {
    "path": "content/landingai/skills/ade/document-workflows/references/visualization.md",
    "content": "# Visualization Patterns\n\nPatterns for visualizing ADE parse and extraction results: chunk image\ncropping, bounding box overlays, and word-level grounding highlights.\n\n---\n\n## 1. Chunk Image Extraction\n\nCrop individual chunks from document pages using bounding box coordinates.\nUseful for QA, debugging, and building visual search indexes.\n\n```python\nfrom pathlib import Path\nfrom typing import Any, List, Optional\n\nfrom PIL import Image\n\ntry:\n    import pymupdf\nexcept ImportError:\n    pymupdf = None  # type: ignore[assignment]\n\n\ndef save_chunk_images(\n    parse_result: Any,\n    document_path: Path,\n    output_dir: Path,\n    zoom: float = 2.0,\n) -> Optional[Path]:\n    \"\"\"Crop and save each chunk as a PNG image.\n\n    Creates: output_dir/<doc_stem>/page_<N>/<type>.<id>.png\n\n    Args:\n        parse_result: from client.parse()\n        document_path: original document file\n        output_dir: base directory for chunk images\n        zoom: render scale factor (2.0 = 144 DPI)\n\n    Returns:\n        Path to created document directory, or None on error.\n    \"\"\"\n    if pymupdf is None:\n        print(\"Install pymupdf: pip install pymupdf\")\n        return None\n\n    doc_dir = output_dir / document_path.stem\n    chunks = parse_result.chunks or []\n\n    def _save_page_chunks(\n        img: Image.Image,\n        page_chunks: List[Any],\n        page_num: int,\n    ) -> None:\n        w, h = img.size\n        page_dir = doc_dir / f\"page_{page_num}\"\n        page_dir.mkdir(parents=True, exist_ok=True)\n        for ch in page_chunks:\n            if (\n                not hasattr(ch, \"grounding\")\n                or ch.grounding.page != page_num\n            ):\n                continue\n            box = ch.grounding.box\n            crop = img.crop((\n                int(box.left * w),\n                int(box.top * h),\n                int(box.right * w),\n                int(box.bottom * h),\n            ))\n            fname = f\"{ch.type}.{ch.id}.png\"\n            crop.save(page_dir / fname)\n\n    try:\n        if document_path.suffix.lower() == \".pdf\":\n            pdf = pymupdf.open(document_path)\n            mat = pymupdf.Matrix(zoom, zoom)\n            for page_num in range(len(pdf)):\n                pix = pdf[page_num].get_pixmap(matrix=mat)\n                img = Image.frombytes(\n                    \"RGB\", [pix.width, pix.height], pix.samples\n                )\n                _save_page_chunks(img, chunks, page_num)\n            pdf.close()\n        else:\n            img = Image.open(document_path).convert(\"RGB\")\n            _save_page_chunks(img, chunks, 0)\n        return doc_dir\n    except Exception as exc:\n        print(f\"Failed to save chunk images: {exc}\")\n        return None\n```\n\n### Usage\n\n```python\nfrom landingai_ade import LandingAIADE\nfrom pathlib import Path\n\nclient = LandingAIADE()\npr = client.parse(document=Path(\"report.pdf\"))\nsave_chunk_images(pr, Path(\"report.pdf\"), Path(\"chunk_images/\"))\n# Creates: chunk_images/report/page_0/text.abc123.png, etc.\n```\n\n---\n\n## 2. Grounding Overlay — Bounding Boxes on Pages\n\nDraw color-coded bounding boxes on rendered page images to show where\neach chunk was detected.\n\n```python\nfrom pathlib import Path\nfrom typing import Any, Dict, Tuple\n\nfrom PIL import Image, ImageDraw\n\ntry:\n    import pymupdf\nexcept ImportError:\n    pymupdf = None  # type: ignore[assignment]\n\n# Color map for chunk types (RGB tuples)\nCHUNK_COLORS: Dict[str, Tuple[int, int, int]] = {\n    \"text\": (40, 167, 69),         # green\n    \"table\": (0, 123, 255),        # blue\n    \"marginalia\": (111, 66, 193),  # purple\n    \"figure\": (255, 0, 255),       # magenta\n    \"logo\": (144, 238, 144),       # light green\n    \"card\": (255, 165, 0),         # orange\n    \"attestation\": (0, 255, 255),  # cyan\n    \"scan_code\": (255, 193, 7),    # yellow\n}\nDEFAULT_COLOR = (200, 200, 200)\n\n\ndef render_page_image(\n    document_path: Path,\n    page_num: int,\n    zoom: float = 2.0,\n) -> Image.Image:\n    \"\"\"Render a single page as a PIL Image.\"\"\"\n    if document_path.suffix.lower() == \".pdf\":\n        if pymupdf is None:\n            raise ImportError(\"pip install pymupdf\")\n        pdf = pymupdf.open(document_path)\n        pix = pdf[page_num].get_pixmap(\n            matrix=pymupdf.Matrix(zoom, zoom)\n        )\n        img = Image.frombytes(\n            \"RGB\", [pix.width, pix.height], pix.samples\n        )\n        pdf.close()\n        return img\n    return Image.open(document_path).convert(\"RGB\")\n\n\ndef annotate_page(\n    img: Image.Image,\n    chunks: list,\n    page_num: int,\n    line_width: int = 3,\n) -> Image.Image:\n    \"\"\"Draw bounding boxes for all chunks on a page image.\"\"\"\n    annotated = img.copy()\n    draw = ImageDraw.Draw(annotated)\n    w, h = img.size\n\n    for ch in chunks:\n        if (\n            not hasattr(ch, \"grounding\")\n            or ch.grounding.page != page_num\n        ):\n            continue\n        box = ch.grounding.box\n        color = CHUNK_COLORS.get(\n            getattr(ch, \"type\", \"\"), DEFAULT_COLOR\n        )\n        coords = [\n            int(box.left * w),\n            int(box.top * h),\n            int(box.right * w),\n            int(box.bottom * h),\n        ]\n        draw.rectangle(coords, outline=color, width=line_width)\n    return annotated\n\n\ndef visualize_parse(\n    parse_result: Any,\n    document_path: Path,\n    output_dir: Path,\n    zoom: float = 2.0,\n) -> None:\n    \"\"\"Render all pages with chunk bounding box overlays.\n\n    Saves: output_dir/<doc_stem>/page_<N>_annotated.png\n    \"\"\"\n    doc_dir = output_dir / document_path.stem\n    doc_dir.mkdir(parents=True, exist_ok=True)\n    chunks = parse_result.chunks or []\n\n    # Determine page count\n    if document_path.suffix.lower() == \".pdf\":\n        pdf = pymupdf.open(document_path)\n        n_pages = len(pdf)\n        pdf.close()\n    else:\n        n_pages = 1\n\n    for page_num in range(n_pages):\n        img = render_page_image(document_path, page_num, zoom)\n        annotated = annotate_page(img, chunks, page_num)\n        out_path = doc_dir / f\"page_{page_num + 1}_annotated.png\"\n        annotated.save(out_path)\n```\n\n### Visualize Extracted Fields Only\n\nShow only the chunks that contributed to extracted fields (using\nextraction metadata references):\n\n```python\ndef visualize_extraction(\n    parse_result: Any,\n    extract_result: Any,\n    document_path: Path,\n    output_dir: Path,\n    zoom: float = 2.0,\n) -> None:\n    \"\"\"Draw boxes only for chunks referenced by extracted\n    fields.\"\"\"\n    doc_dir = output_dir / document_path.stem\n    doc_dir.mkdir(parents=True, exist_ok=True)\n\n    # Collect referenced chunk IDs\n    meta = getattr(extract_result, \"extraction_metadata\", {})\n    if isinstance(meta, dict):\n        ref_ids = set()\n        for field_meta in meta.values():\n            refs = (\n                field_meta.get(\"references\", [])\n                if isinstance(field_meta, dict)\n                else getattr(field_meta, \"references\", [])\n            )\n            ref_ids.update(refs)\n    else:\n        ref_ids = set()\n\n    # Filter chunks to only referenced ones\n    ref_chunks = [\n        ch for ch in (parse_result.chunks or [])\n        if getattr(ch, \"id\", None) in ref_ids\n    ]\n\n    if document_path.suffix.lower() == \".pdf\":\n        pdf = pymupdf.open(document_path)\n        n_pages = len(pdf)\n        pdf.close()\n    else:\n        n_pages = 1\n\n    for page_num in range(n_pages):\n        img = render_page_image(document_path, page_num, zoom)\n        annotated = annotate_page(img, ref_chunks, page_num)\n        out = doc_dir / f\"page_{page_num + 1}_annotated.png\"\n        annotated.save(out)\n```\n\n---\n\n## 3. Word-Level Grounding\n\nTwo approaches depending on whether the PDF contains native text or is scanned.\n\n| Scenario | Approach |\n|----------|----------|\n| Native text PDF (most PDFs) | **3a** — PyMuPDF native extraction (exact, fast, no extra deps) |\n| Scanned / image-only PDF | **3b** — Tesseract OCR + fuzzy match |\n\n---\n\n## 3a. Native PDF Word Search (preferred)\n\nFor text-based PDFs, PyMuPDF's `get_text(\"words\", clip=rect)` finds words\nexactly with no OCR required. The key pattern is **spatially restricting the\nsearch to specific ADE chunk bounding boxes**, so occurrences in adjacent\nsections on the same page (e.g. an abstract above the introduction) are\nautomatically excluded.\n\n```python\nfrom pathlib import Path\nfrom typing import Any, List, Tuple\n\nfrom PIL import Image, ImageDraw\n\ntry:\n    import pymupdf\nexcept ImportError:\n    pymupdf = None  # type: ignore[assignment]\n\n\ndef find_term_in_chunks(\n    pdf_path: Path,\n    page_num: int,\n    chunks: list,           # ADE chunk objects with grounding\n    term: str,\n    zoom: float = 2.0,\n) -> List[dict]:\n    \"\"\"Find *term* only within the ADE chunk bounding boxes on *page_num*.\n\n    Uses PyMuPDF native text extraction clipped to each chunk rect so that\n    occurrences outside the supplied chunks are ignored.\n\n    Returns list of dicts: text, left, top, width, height (pixel coords\n    at *zoom* scale, matching the image from render_page_image()).\n    \"\"\"\n    if pymupdf is None:\n        raise ImportError(\"pip install pymupdf\")\n    pdf = pymupdf.open(pdf_path)\n    page = pdf[page_num]\n    pw, ph = page.rect.width, page.rect.height\n\n    boxes = []\n    for ch in chunks:\n        b = ch.grounding.box\n        clip = pymupdf.Rect(b.left * pw, b.top * ph, b.right * pw, b.bottom * ph)\n        # Each word entry: (x0, y0, x1, y1, \"word\", block_no, line_no, word_no)\n        for x0, y0, x1, y1, text, *_ in page.get_text(\"words\", clip=clip):\n            if text.strip(\".,;:!?()[]{}\\\"'–—\") == term:\n                boxes.append({\n                    \"text\":   text,\n                    \"left\":   int(x0 * zoom),\n                    \"top\":    int(y0 * zoom),\n                    \"width\":  int((x1 - x0) * zoom),\n                    \"height\": int((y1 - y0) * zoom),\n                })\n    pdf.close()\n    return boxes\n```\n\n### Annotation and Redaction\n\nThe same `annotate_page` function handles both use cases — the only\ndifference is the alpha value of the fill colour:\n\n```python\n# Highlight: semi-transparent colour (text remains readable)\nHIGHLIGHT = (255, 255, 0, 120)   # yellow\n\n# Redact: opaque box (text is visually hidden)\nREDACT = (0, 0, 0, 255)          # black, fully opaque\n\n\ndef annotate_page(\n    page_img: Image.Image,\n    boxes: List[dict],\n    fill: Tuple[int, int, int, int] = HIGHLIGHT,\n) -> Image.Image:\n    \"\"\"Overlay filled rectangles on a page image.\n\n    Pass HIGHLIGHT for annotation or REDACT to cover sensitive content.\n    Output is a PNG image — not a PDF-native redaction.\n    \"\"\"\n    rgba = page_img.convert(\"RGBA\")\n    overlay = Image.new(\"RGBA\", rgba.size, (0, 0, 0, 0))\n    draw = ImageDraw.Draw(overlay)\n    for b in boxes:\n        draw.rectangle(\n            [b[\"left\"], b[\"top\"],\n             b[\"left\"] + b[\"width\"], b[\"top\"] + b[\"height\"]],\n            fill=fill,\n        )\n    return Image.alpha_composite(rgba, overlay)\n```\n\n> **PDF-native redaction** (permanently removes underlying text, not just\n> visually covers it) uses `page.add_redact_annot()` /\n> `page.apply_redactions()` from PyMuPDF. That does not depend on ADE and\n> belongs in the `pdf` skill.\n\n### Usage\n\n```python\nfrom landingai_ade import LandingAIADE\n\nclient = LandingAIADE()\npr = client.parse(document=Path(\"paper.pdf\"))\n\n# Select only the chunks you want to search within\ntarget_chunks = [ch for ch in pr.chunks if ch.grounding.page == 1\n                 and \"introduction\" in (ch.markdown or \"\").lower()]\n\nboxes = find_term_in_chunks(Path(\"paper.pdf\"), page_num=1,\n                            chunks=target_chunks, term=\"L2S\")\nimg = render_page_image(Path(\"paper.pdf\"), page_num=1)\nhighlighted = annotate_page(img, boxes, fill=HIGHLIGHT)\nhighlighted.convert(\"RGB\").save(\"page_2_highlighted.png\")\n```\n\n---\n\n## 3b. OCR Word-Level Grounding (scanned PDFs)\n\nFor precise highlighting of extracted values within chunks. Uses\nTesseract OCR on chunk crops + fuzzy matching to locate exact words.\n\n> **Requires:** `pytesseract`, `tesseract` system binary, `fuzzywuzzy`\n\n```python\nfrom typing import List, Tuple\n\nfrom PIL import Image, ImageDraw\n\ntry:\n    import pytesseract\n    from fuzzywuzzy import fuzz\n    WORD_GROUNDING_AVAILABLE = True\nexcept ImportError:\n    WORD_GROUNDING_AVAILABLE = False\n\n\ndef find_words_in_chunk(\n    chunk_image: Image.Image,\n    search_text: str,\n    confidence_threshold: int = 60,\n    fuzzy_threshold: int = 80,\n) -> List[dict]:\n    \"\"\"Find word-level bounding boxes matching search_text.\n\n    Returns list of dicts with keys: text, left, top, width,\n    height, conf, match_score.\n    \"\"\"\n    if not WORD_GROUNDING_AVAILABLE:\n        raise ImportError(\n            \"pip install pytesseract fuzzywuzzy python-Levenshtein\"\n        )\n\n    ocr_data = pytesseract.image_to_data(\n        chunk_image, output_type=pytesseract.Output.DICT\n    )\n    search_words = search_text.lower().split()\n    matches: List[dict] = []\n\n    for i, word in enumerate(ocr_data[\"text\"]):\n        conf = int(ocr_data[\"conf\"][i])\n        if conf < confidence_threshold or not word.strip():\n            continue\n        for sw in search_words:\n            score = fuzz.ratio(word.lower(), sw)\n            if score >= fuzzy_threshold:\n                matches.append({\n                    \"text\": word,\n                    \"left\": ocr_data[\"left\"][i],\n                    \"top\": ocr_data[\"top\"][i],\n                    \"width\": ocr_data[\"width\"][i],\n                    \"height\": ocr_data[\"height\"][i],\n                    \"conf\": conf,\n                    \"match_score\": score,\n                })\n    return matches\n\n\ndef highlight_words(\n    chunk_image: Image.Image,\n    matches: List[dict],\n    color: Tuple[int, int, int, int] = (255, 255, 0, 100),\n) -> Image.Image:\n    \"\"\"Draw semi-transparent highlights over matched words.\"\"\"\n    highlighted = chunk_image.convert(\"RGBA\")\n    overlay = Image.new(\"RGBA\", highlighted.size, (0, 0, 0, 0))\n    draw = ImageDraw.Draw(overlay)\n\n    for m in matches:\n        draw.rectangle(\n            [\n                m[\"left\"],\n                m[\"top\"],\n                m[\"left\"] + m[\"width\"],\n                m[\"top\"] + m[\"height\"],\n            ],\n            fill=color,\n        )\n    return Image.alpha_composite(highlighted, overlay)\n```\n\n### Full Word-Level Grounding Pipeline\n\n```python\ndef word_level_grounding(\n    parse_result: Any,\n    extract_result: Any,\n    document_path: Path,\n    output_dir: Path,\n    zoom: float = 2.0,\n) -> None:\n    \"\"\"For each extracted field, find and highlight the exact\n    words in the source chunk.\n\n    Saves highlighted chunk crops to output_dir.\n    \"\"\"\n    output_dir.mkdir(parents=True, exist_ok=True)\n    meta = getattr(extract_result, \"extraction_metadata\", {})\n    extraction = extract_result.extraction\n\n    # Build chunk lookup\n    chunk_map = {\n        ch.id: ch for ch in (parse_result.chunks or [])\n        if hasattr(ch, \"id\")\n    }\n\n    for field_name, field_meta in (\n        meta.items() if isinstance(meta, dict) else []\n    ):\n        refs = (\n            field_meta.get(\"references\", [])\n            if isinstance(field_meta, dict)\n            else getattr(field_meta, \"references\", [])\n        )\n        if not refs:\n            continue\n\n        # Get the extracted value\n        value = _dig_value(extraction, field_name)\n        if not value or not isinstance(value, str):\n            continue\n\n        chunk_id = refs[0]\n        chunk = chunk_map.get(chunk_id)\n        if not chunk or not hasattr(chunk, \"grounding\"):\n            continue\n\n        # Crop the chunk from the page\n        page_num = chunk.grounding.page\n        page_img = render_page_image(\n            document_path, page_num, zoom\n        )\n        box = chunk.grounding.box\n        w, h = page_img.size\n        crop = page_img.crop((\n            int(box.left * w),\n            int(box.top * h),\n            int(box.right * w),\n            int(box.bottom * h),\n        ))\n\n        # Find and highlight words\n        matches = find_words_in_chunk(crop, str(value))\n        if matches:\n            highlighted = highlight_words(crop, matches)\n            out = output_dir / f\"{field_name}_{chunk_id}.png\"\n            highlighted.save(out)\n\n\ndef _dig_value(d: dict, dotted_key: str) -> Any:\n    \"\"\"Get value from nested dict using __ separator.\"\"\"\n    parts = dotted_key.split(\"__\")\n    obj: Any = d\n    for p in parts:\n        if isinstance(obj, dict):\n            obj = obj.get(p)\n        else:\n            return None\n    return obj\n```\n\n---\n\n## Dependencies\n\n```\n# Chunk images + bounding box overlays + native word search (Sections 1–3a)\npip install landingai-ade Pillow pymupdf\n\n# OCR word-level grounding / scanned PDFs (Section 3b)\npip install landingai-ade Pillow pymupdf pytesseract fuzzywuzzy python-Levenshtein\n# Also requires: brew install tesseract (macOS) or apt install tesseract-ocr (Linux)\n```\n"
  },
  {
    "path": "content/langchain/docs/community/python/DOC.md",
    "content": "---\nname: community\ndescription: \"langchain-community package guide for Python covering third-party integrations, loaders, vector stores, tools, and 0.4.1 version notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain-community,langchain,python,integrations,document-loaders,vectorstores,tools\"\n---\n\n# langchain-community Python Package Guide\n\n## What It Is\n\n`langchain-community` is the catch-all Python package for community and third-party LangChain integrations. Use it when you need loaders, vector stores, tools, retrievers, utilities, or wrappers that implement LangChain interfaces but do not live in `langchain-core` and do not have a dedicated modern `langchain-*` provider package yet.\n\nPrefer dedicated integration packages when they exist. LangChain's provider docs now center standalone packages such as `langchain-openai`, `langchain-anthropic`, `langchain-qdrant`, and similar provider-specific packages for cleaner versioning, dependency management, and testing.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `0.4.1`.\n- PyPI lists `0.4.1` as the current package version covered here and shows it was uploaded on October 27, 2025.\n- LangChain's Python release policy explicitly says `langchain-community` does not follow the same strict semantic versioning guarantees as `langchain` and `langchain-core`. Pin exact versions when you need reproducible behavior.\n- PyPI metadata for `0.4.1` requires Python `>=3.10,<4.0`.\n- PyPI metadata for `0.4.1` also shows the package depends on the `1.x` lines of `langchain-core` and `langchain-classic`. Do not mix this package with pre-`1.0` LangChain dependencies.\n- The current LangChain integration publishing guidance says new integrations should usually be standalone `langchain-*` packages instead of new additions to the monorepo. Treat `langchain-community` as the compatibility bucket for community or older shared integrations, not the first package to assume for every provider.\n- The PyPI project description still contains stale wording that says `langchain-community` is on version `0.0.x`; use the actual PyPI release metadata and current reference docs instead of that older description text.\n\n## Install\n\nPin the package if your project depends on a known set of community integrations:\n\n```bash\npython -m pip install \"langchain-community==0.4.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"langchain-community==0.4.1\"\npoetry add \"langchain-community==0.4.1\"\n```\n\nIn practice you often install this package together with:\n\n- `langchain` when you want the higher-level agent and application APIs\n- `langchain-core` when you are composing lower-level runnables and prompts directly\n- a dedicated provider package such as `langchain-openai`\n- the backend library required by the specific integration, such as `faiss-cpu`, `duckduckgo-search`, `pypdf`, or `unstructured`\n\nExample installs:\n\n```bash\npython -m pip install \"langchain-community==0.4.1\" \"langchain-openai\"\npython -m pip install \"langchain-community==0.4.1\" \"faiss-cpu\"\npython -m pip install \"langchain-community==0.4.1\" \"duckduckgo-search\"\n```\n\n## Setup And Configuration\n\n`langchain-community` does not define one package-wide auth scheme. Configuration depends on the specific integration you use.\n\nPractical setup rules:\n\n1. Install the extra dependency required by the integration.\n2. Set the provider-specific environment variables for that integration.\n3. Keep tracing optional and separate from provider auth.\n\nTypical environment setup when combining community integrations with an OpenAI embedding model and optional LangSmith tracing:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport LANGSMITH_TRACING=\"true\"\nexport LANGSMITH_API_KEY=\"lsv2_...\"\n```\n\nImportant boundary:\n\n- credentials usually belong to the provider package or vendor SDK, not to `langchain-community` itself\n- many integrations will import successfully only after you install their separate backend dependency\n\n## Core Usage\n\n### Load Documents From Local Files\n\n`TextLoader` is a straightforward way to turn local text files into LangChain `Document` objects:\n\n```python\nfrom langchain_community.document_loaders import TextLoader\n\nloader = TextLoader(\"notes.txt\")\ndocs = loader.load()\n\nfor doc in docs:\n    print(doc.page_content[:80])\n    print(doc.metadata)\n```\n\nFor larger corpora, prefer loader APIs such as `lazy_load()` when available so you do not eagerly read everything into memory.\n\n### Build A Local FAISS Vector Store\n\nThe official FAISS reference for `langchain-community` documents `FAISS` in this package and calls out the separate `faiss-cpu` dependency.\n\n```python\nfrom langchain_community.vectorstores import FAISS\nfrom langchain_openai import OpenAIEmbeddings\n\ntexts = [\n    \"LangChain Community contains third-party integrations.\",\n    \"FAISS is useful for local similarity search.\",\n]\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\nvector_store = FAISS.from_texts(texts, embeddings)\n\nresults = vector_store.similarity_search(\"Which package contains third-party integrations?\", k=1)\n\nfor doc in results:\n    print(doc.page_content)\n```\n\nCommon extension points:\n\n- `similarity_search_with_score(...)` when you need scores\n- `save_local(...)` and `load_local(...)` for persistence\n- `as_retriever(...)` when you want retriever behavior instead of direct vector-store calls\n\n### Turn A Vector Store Into A Retriever\n\n`FAISS.as_retriever(...)` is the quickest bridge from a local index to retrieval-oriented chains or agents:\n\n```python\nretriever = vector_store.as_retriever(\n    search_type=\"mmr\",\n    search_kwargs={\"k\": 2, \"fetch_k\": 4, \"lambda_mult\": 0.5},\n)\n\ndocs = retriever.invoke(\"third-party LangChain integrations\")\nfor doc in docs:\n    print(doc.page_content)\n```\n\n### Use A Community Tool Wrapper\n\nTool wrappers in this package follow the normal LangChain tool interface. For example, the DuckDuckGo integration requires the extra `duckduckgo-search` package:\n\n```python\nfrom langchain_community.tools import DuckDuckGoSearchRun\n\ntool = DuckDuckGoSearchRun()\nresult = tool.invoke(\"latest LangChain release policy\")\nprint(result)\n```\n\nUse these wrappers when you need a LangChain `BaseTool` implementation quickly, but check the LangChain integrations index first in case the provider now has a dedicated package that should be preferred.\n\n## Common Pitfalls\n\n- `langchain-community` is not the default answer for every integration anymore. Check the LangChain integrations index first for a dedicated `langchain-*` package.\n- Installing only `langchain-community` is often insufficient. Many integrations need a second package such as `faiss-cpu`, `duckduckgo-search`, `pypdf`, `unstructured`, or a vendor SDK.\n- The package has no universal API key. Environment variables are integration-specific.\n- Older blog posts often show pre-`1.0` imports, or provider classes that have moved out of `langchain-community` into dedicated packages. Prefer current docs over older snippets.\n- Do not assume `langchain-community` version numbers should match `langchain` or `langchain-core` version numbers. They are versioned separately.\n- Because `langchain-community` may have breaking changes on minor releases, copying examples across `0.x` minors without pinning can break working code.\n- Loader `.load()` methods are eager. For large inputs, use `lazy_load()` or another streaming-friendly path when the loader supports it.\n- Some integrations in this package are effectively legacy. If the official provider page says the community path is outdated or points to a standalone package, follow the standalone package.\n\n## What To Reach For First\n\n- Use `langchain-community` for document loaders, vector stores, tools, utilities, and older shared integrations that still live here.\n- Use `langchain-core` for prompts, runnables, tools, and shared abstractions.\n- Use `langchain` for higher-level agent and application APIs.\n- Use dedicated provider packages for models, embeddings, and provider-owned integrations whenever possible.\n\n## Official Sources Used For This Entry\n\n- PyPI package page: `https://pypi.org/project/langchain-community/`\n- PyPI release history: `https://pypi.org/project/langchain-community/#history`\n- Docs URL: `https://python.langchain.com/api_reference/community/`\n- Canonical API reference root: `https://reference.langchain.com/python/langchain-community/`\n- LangChain integrations overview: `https://docs.langchain.com/oss/python/integrations/providers/overview`\n- LangChain install guide: `https://docs.langchain.com/oss/python/langchain/install`\n- LangChain Python release policy: `https://docs.langchain.com/oss/python/release-policy`\n- LangChain integration publishing guidance: `https://docs.langchain.com/oss/python/contributing/publish-langchain`\n"
  },
  {
    "path": "content/langchain/docs/core/python/DOC.md",
    "content": "---\nname: core\ndescription: \"langchain-core package guide for Python covering runnables, prompt templates, messages, tools, config, and tracing handoff points\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.18\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"langchain-core,langchain,python,llm,runnables,prompts,tools,langsmith\"\n---\n\n# langchain-core Python Package Guide\n\n## What It Is\n\n`langchain-core` is the base abstractions package for LangChain Python apps.\n\nUse it when you need:\n\n- prompt templates and message objects\n- runnable composition with the LangChain Expression Language (LCEL)\n- tool definitions and schemas\n- output parsers, documents, callbacks, and shared config plumbing\n\nImportant boundary: `langchain-core` does not ship provider clients, embeddings, or vector store integrations. For real model calls, pair it with an integration package such as `langchain-openai`, `langchain-anthropic`, or another provider package.\n\nCommon imports:\n\n- `langchain_core.prompts`\n- `langchain_core.messages`\n- `langchain_core.runnables`\n- `langchain_core.tools`\n- `langchain_core.output_parsers`\n\n## Version Covered\n\n- Package: `langchain-core`\n- Ecosystem: `pypi`\n- Target version version: `1.2.18`\n- PyPI latest on 2026-03-11: `1.2.18`\n- Requires Python: `>=3.10,<4.0`\n- Registry URL: `https://pypi.org/project/langchain-core/`\n- Canonical API reference root used for this entry: `https://reference.langchain.com/python/langchain_core/`\n\nVersion note:\n\n- The docs URL `https://python.langchain.com/api_reference/core/` now redirects to the canonical reference site under `reference.langchain.com`.\n- The package is on the LangChain `1.x` line. Prefer current `langchain_core.*` imports and current reference docs over older `0.x` blog posts.\n\n## Install\n\nPin the version used here when you need reproducible behavior:\n\n```bash\npython -m pip install \"langchain-core==1.2.18\"\n```\n\nIf you are building an actual application, you will usually install at least one provider integration too:\n\n```bash\npython -m pip install \"langchain-core==1.2.18\" \"langchain-openai\"\n```\n\n## Recommended Setup\n\nStart by separating concerns:\n\n- use `langchain-core` for composition and types\n- use an integration package for model or embedding access\n- keep provider credentials in environment variables owned by the integration package\n\nFor pure `langchain-core` experiments, no API key is required.\n\n## Core Usage\n\n### Prompt Templates And Messages\n\n`ChatPromptTemplate` builds a chat prompt from message-like tuples and returns a prompt value that downstream runnables can consume.\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Reply in one short sentence.\"),\n        (\"human\", \"Explain {topic}.\"),\n    ]\n)\n\nprompt_value = prompt.invoke({\"topic\": \"Python context managers\"})\n\nfor message in prompt_value.to_messages():\n    print(type(message).__name__, message.content)\n```\n\nUse this when you want prompt construction to stay explicit and testable before you attach a model.\n\n### Runnable Composition With LCEL\n\n`RunnableLambda` turns a Python callable into a runnable, and the `|` operator composes runnables into a sequence.\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_core.runnables import RunnableLambda\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Be concise.\"),\n        (\"human\", \"Summarize {topic} in one sentence.\"),\n    ]\n)\n\ndef mock_model(prompt_value) -> str:\n    last_message = prompt_value.to_messages()[-1].content\n    return f\"Stub answer for: {last_message}\"\n\nchain = prompt | RunnableLambda(mock_model)\n\nprint(chain.invoke({\"topic\": \"LCEL\"}))\n```\n\nPractical interface to remember:\n\n- `invoke(...)` for one input\n- `ainvoke(...)` for async use\n- `batch([...])` for many inputs\n- `stream(...)` and `astream(...)` when the runnable supports streaming\n\n### Parallel Fan-Out\n\nUse `RunnableParallel` when the same input should feed multiple branches.\n\n```python\nfrom langchain_core.runnables import RunnableLambda, RunnableParallel\n\nanalysis = RunnableParallel(\n    original=RunnableLambda(lambda x: x[\"text\"]),\n    upper=RunnableLambda(lambda x: x[\"text\"].upper()),\n    word_count=RunnableLambda(lambda x: len(x[\"text\"].split())),\n)\n\nresult = analysis.invoke({\"text\": \"langchain core keeps abstractions reusable\"})\nprint(result)\n```\n\nThis pattern is useful for enrichment pipelines, feature extraction, or preparing multiple prompt inputs from one request payload.\n\n### Tools\n\nUse `@tool` when you need a callable with a name, description, and argument schema that an agent or model integration can consume.\n\n```python\nfrom langchain_core.tools import tool\n\n@tool\ndef lookup_order(order_id: str) -> str:\n    \"\"\"Return a stub shipping status for an order.\"\"\"\n    return f\"{order_id}: shipped\"\n\nprint(lookup_order.name)\nprint(lookup_order.invoke({\"order_id\": \"A-100\"}))\n```\n\nPractical rule: include type hints and a useful docstring. That gives the tool a better schema and description.\n\n### Runnable Config\n\nUse `with_config(...)` to attach run metadata, tags, callbacks, or configurable values without rewriting the runnable itself.\n\n```python\nfrom langchain_core.runnables import RunnableLambda\n\nuppercase = RunnableLambda(lambda text: text.upper()).with_config(\n    run_name=\"uppercase_demo\",\n    tags=[\"demo\", \"langchain-core\"],\n    metadata={\"package\": \"langchain-core\"},\n)\n\nprint(uppercase.invoke(\"hello\"))\n```\n\nCommon config keys worth knowing:\n\n- `run_name`\n- `tags`\n- `metadata`\n- `callbacks`\n- `max_concurrency`\n- `recursion_limit`\n- `configurable`\n\n## Auth And Configuration\n\n### No Provider Auth In langchain-core Itself\n\n`langchain-core` is intentionally provider-agnostic. It does not define an API key environment variable of its own for model access.\n\nFor actual model calls:\n\n1. install the matching integration package\n2. set that provider's environment variables\n3. compose the provider runnable with your `langchain_core` prompt or tool pipeline\n\nExample with the official LangChain OpenAI integration:\n\n```bash\npython -m pip install \"langchain-openai\"\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_openai import ChatOpenAI\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Reply tersely.\"),\n        (\"human\", \"Summarize {topic} in one sentence.\"),\n    ]\n)\n\nmodel = ChatOpenAI(model=\"gpt-4.1-mini\")\nchain = prompt | model\n\nprint(chain.invoke({\"topic\": \"LangChain\"}).content)\n```\n\n### Optional LangSmith Tracing\n\nIf you want tracing and observability, LangChain's docs point to LangSmith environment variables:\n\n```bash\nexport LANGSMITH_TRACING=true\nexport LANGSMITH_API_KEY=\"lsv2_...\"\nexport LANGSMITH_PROJECT=\"my-project\"\n```\n\nThis is optional. Pure `langchain-core` composition does not require LangSmith.\n\n## Common Pitfalls\n\n- `langchain-core` is not the full application stack. If you need a hosted model, vector store, or retriever integration, install the relevant integration package too.\n- `ChatPromptTemplate.invoke(...)` returns a prompt value with message objects, not a plain string. Downstream code must accept prompt values or messages.\n- `RunnableLambda` is convenient for normal Python logic, but the official reference notes it is best for code that does not need token-by-token streaming support.\n- Tool schemas are only as good as the underlying function signature and docstring. Untyped or poorly described callables produce weaker tool metadata.\n- Older LangChain examples on the web may still target pre-`1.0` imports or the older docs hostname. Prefer the current `reference.langchain.com` pages for `1.2.18`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `1.2.18`, and that version matches the current PyPI latest on 2026-03-11.\n- LangChain's install docs emphasize a package split: keep `langchain-core` for abstractions and add integrations separately.\n- When copying examples, check whether the snippet depends only on `langchain-core` or also on `langchain`, `langgraph`, LangSmith, or a provider package. Many official examples span more than one package.\n\n## Official Sources Used For This Entry\n\n- PyPI package page: `https://pypi.org/project/langchain-core/`\n- PyPI release history: `https://pypi.org/project/langchain-core/#history`\n- Install docs: `https://docs.langchain.com/oss/python/langchain/install`\n- Canonical API reference root: `https://reference.langchain.com/python/langchain_core/`\n- `RunnableLambda` reference: `https://reference.langchain.com/python/langchain_core/runnables/#langchain_core.runnables.base.RunnableLambda`\n- `ChatPromptTemplate` reference: `https://reference.langchain.com/python/langchain_core/prompts/#langchain_core.prompts.chat.ChatPromptTemplate`\n- LangSmith observability quickstart: `https://docs.langchain.com/langsmith/observability-quickstart`\n"
  },
  {
    "path": "content/langchain/docs/openai/python/DOC.md",
    "content": "---\nname: openai\ndescription: \"langchain-openai package guide for Python covering ChatOpenAI, OpenAIEmbeddings, Responses API, Azure setup, and 1.1.11 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain-openai,langchain,openai,python,llm,embeddings,azure-openai\"\n---\n\n# langchain-openai Python Package Guide\n\n## What It Is\n\n`langchain-openai` is LangChain's maintained Python integration for OpenAI and Azure OpenAI models.\n\nUse it when you need:\n\n- `ChatOpenAI` for chat and responses-style model calls\n- `OpenAIEmbeddings` for embeddings\n- `AzureChatOpenAI` or `AzureOpenAIEmbeddings` for traditional Azure-specific setup\n- LangChain-native features such as tool binding, structured output, async calls, and streaming on top of OpenAI models\n\nImportant boundary: `langchain-openai` is an integration package, not the full framework. Install `langchain` or `langchain-core` alongside it when your app also needs prompts, runnables, agents, or graph orchestration.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.1.11`.\n- PyPI still shows `1.1.11` as the current release on 2026-03-12, so the version used here matches upstream for review.\n- The docs URL `https://python.langchain.com/api_reference/openai/` is a legacy LangChain API-reference landing page. Current conceptual guides live under `docs.langchain.com`, and the current Python API reference is under `reference.langchain.com`.\n- LangChain's release policy treats integration packages such as `langchain-openai` as separately versioned packages. Do not assume they should match `langchain` or `langchain-core` patch versions.\n- Official docs note that `ChatOpenAI` can automatically use the OpenAI Responses API in some cases and can be forced with `use_responses_api=True`. If behavior matters, test against the exact model and request shape you use.\n- Official docs also note that, as of `langchain-openai >= 1.0.1`, `ChatOpenAI` and `OpenAIEmbeddings` can target Azure OpenAI's v1 API directly. Older Azure-specific examples may still use `AzureChatOpenAI` and `AzureOpenAIEmbeddings`.\n- The current chat integration guide marks OpenAI tool search as requiring `langchain-openai >= 1.1.11`, so this pinned version is new enough for that feature.\n\n## Install\n\nPin the integration package and whichever LangChain package your app actually uses:\n\n```bash\npython -m pip install \"langchain-openai==1.1.11\" \"langchain-core\"\n```\n\nTypical application install:\n\n```bash\npython -m pip install \"langchain==1.2.11\" \"langchain-openai==1.1.11\"\n```\n\nIf you are using Azure and want to stay close to LangChain's Azure-specific examples, the same package provides those classes:\n\n```bash\npython -m pip install \"langchain-openai==1.1.11\"\n```\n\n## Auth And Setup\n\n### OpenAI\n\nSet credentials in the environment before constructing models or embeddings:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nBasic model setup:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    temperature=0,\n)\n```\n\nYou can also pass request/client settings directly:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    organization=\"org_...\",\n    timeout=30,\n    max_retries=2,\n)\n```\n\n### Azure OpenAI\n\nFor traditional Azure-specific setup, use the Azure classes and Azure environment variables:\n\n```bash\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://my-resource.openai.azure.com/\"\nexport AZURE_OPENAI_API_VERSION=\"2024-10-21\"\n```\n\n```python\nfrom langchain_openai import AzureChatOpenAI\n\nllm = AzureChatOpenAI(\n    azure_deployment=\"gpt-4.1-mini\",\n    api_version=\"2024-10-21\",\n    temperature=0,\n)\n```\n\nFor Azure's newer v1 API shape, official docs say `ChatOpenAI` and `OpenAIEmbeddings` can also be pointed at an Azure `.../openai/v1/` base URL directly in modern `1.x` releases.\n\n## Core Usage\n\n### Basic Chat Invocation\n\nUse `invoke(...)` for a single request and read the returned `AIMessage`:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\n\nresponse = llm.invoke(\"Give me a one-sentence summary of LangChain.\")\nprint(response.content)\n```\n\nMessage-based input works too:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\n\nresponse = llm.invoke(\n    [\n        (\"system\", \"Reply in JSON.\"),\n        (\"human\", \"Return the keys name and role for Ada Lovelace.\"),\n    ]\n)\nprint(response.content)\n```\n\n### Tool Calling\n\n`ChatOpenAI` supports LangChain tool binding:\n\n```python\nfrom langchain_core.tools import tool\nfrom langchain_openai import ChatOpenAI\n\n@tool\ndef get_weather(city: str) -> str:\n    \"\"\"Return a stub weather string.\"\"\"\n    return f\"{city}: sunny\"\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\nllm_with_tools = llm.bind_tools([get_weather])\n\nresponse = llm_with_tools.invoke(\"What is the weather in San Francisco?\")\nprint(response.tool_calls)\n```\n\nUse this when you want the model to choose tools through LangChain's standard tool interface instead of calling the OpenAI SDK directly.\n\n### Structured Output\n\nFor typed extraction, use `with_structured_output(...)`:\n\n```python\nfrom pydantic import BaseModel\nfrom langchain_openai import ChatOpenAI\n\nclass Person(BaseModel):\n    name: str\n    role: str\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\nstructured_llm = llm.with_structured_output(Person)\n\nperson = structured_llm.invoke(\"Ada Lovelace was an early computing pioneer.\")\nprint(person)\n```\n\nOfficial docs call out modern methods such as `json_schema` for OpenAI's structured output support. Prefer current structured-output helpers over older prompt-only JSON parsing.\n\n### Responses API And Conversation State\n\nOfficial docs describe two patterns worth knowing:\n\n- force the Responses API path with `use_responses_api=True` when you need Responses-specific behavior\n- use `previous_response_id` or automatic conversation-state management when you want the model to continue from a prior response in supported flows\n\nExample:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    use_responses_api=True,\n)\n\nresponse = llm.invoke(\"List three uses for embeddings.\")\nprint(response.content)\n```\n\nIf you rely on Responses-specific content blocks or reasoning output, verify the exact response shape in your tests before hard-coding assumptions.\n\n### Streaming\n\nUse `.stream(...)` for incremental tokens. If you need token usage with streaming, the docs call out `stream_usage=True`.\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    stream_usage=True,\n)\n\nfor chunk in llm.stream(\"Write a short haiku about Python packaging.\"):\n    print(chunk.content, end=\"\")\n```\n\n### Embeddings\n\nUse `OpenAIEmbeddings` for text/vector generation:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-large\")\n\nvector = embeddings.embed_query(\"LangChain integrates models into one interface.\")\nprint(len(vector))\n```\n\nBatch embedding:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n\nvectors = embeddings.embed_documents(\n    [\n        \"first document\",\n        \"second document\",\n    ]\n)\nprint(len(vectors), len(vectors[0]))\n```\n\nFor `text-embedding-3-*` models, the official reference documents a `dimensions` option when you need smaller vectors:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(\n    model=\"text-embedding-3-large\",\n    dimensions=1024,\n)\n```\n\n## Common Configuration Choices\n\n- `model`: OpenAI or Azure deployment/model identifier\n- `temperature`: randomness for chat models\n- `timeout`: request timeout\n- `max_retries`: client retry count\n- `base_url`: alternate API base, including modern Azure v1 endpoints\n- `organization`: OpenAI org when applicable\n- `stream_usage`: include usage metadata during streaming\n- `reasoning`: reasoning controls for supported OpenAI reasoning-capable models\n\nKeep these in constructor arguments or environment variables, not hard-coded inside prompts or helper functions.\n\n## Common Pitfalls\n\n- Installing `langchain-openai` alone is not enough if your code also imports `langchain` or `langchain_core` abstractions.\n- Do not assume every `langchain-*` package should share the same version number. `langchain-openai` is separately versioned.\n- Older blog posts often show legacy `OpenAI` completion classes or pre-Responses OpenAI behavior. For new code, prefer `ChatOpenAI` unless you specifically need older completion behavior.\n- The hosted docs are live product docs, not an archive pinned to `1.1.11`. If you are debugging a version-specific mismatch, check PyPI release history and the LangChain release policy before copying a newer example verbatim.\n- When streaming, usage metadata is not automatic in all paths. If your code depends on token counts, enable the documented usage option and test it.\n- If you are targeting Azure, do not mix OpenAI and Azure environment variables casually. Pick either the Azure-specific class pattern or the Azure v1 `base_url` pattern and keep the configuration consistent.\n- `OpenAIEmbeddings.dimensions` applies to the newer embedding models; do not assume every model supports custom dimensions.\n- `langchain-openai` is designed around OpenAI's API semantics. OpenAI-compatible third-party providers may need extra parameters or different behavior that LangChain intentionally does not preserve.\n\n## What To Reach For First\n\n- Use `ChatOpenAI` for most OpenAI model calls in LangChain.\n- Use `OpenAIEmbeddings` for retrieval, semantic search, and vector indexing.\n- Use `with_structured_output(...)` for typed extraction.\n- Use `bind_tools(...)` when you need model-driven tool selection.\n- Use `AzureChatOpenAI` or `AzureOpenAIEmbeddings` when your codebase already follows the Azure-specific configuration pattern.\n\n## Official Sources Used\n\n- `https://python.langchain.com/api_reference/openai/`\n- `https://docs.langchain.com/oss/python/integrations/chat/openai`\n- `https://docs.langchain.com/oss/python/integrations/text_embedding/openai`\n- `https://reference.langchain.com/python/integrations/langchain_openai`\n- `https://docs.langchain.com/oss/python/release-policy`\n- `https://pypi.org/project/langchain-openai/`\n"
  },
  {
    "path": "content/langchain/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LangChain package guide for Python with v1 agent patterns, model initialization, provider setup, and 1.2.11 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain,python,agents,llm,rag,langgraph,langsmith\"\n---\n\n# LangChain Python Package Guide\n\n## When To Use LangChain\n\nUse `langchain` when Python code needs:\n\n- a standard interface for chat models, tools, messages, and agent execution\n- v1 agent building on top of LangGraph\n- provider-swappable model setup without rewriting the whole app\n- optional observability with LangSmith\n\n`langchain` is the high-level framework package. It does not bundle every model provider. For real model calls you usually install `langchain` plus a provider integration such as `langchain-openai` or `langchain-anthropic`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.2.11`.\n- PyPI release history shows `1.2.11` was released on 2026-03-11 and `1.2.12` on 2026-03-12. The earlier pinned version is already one patch behind current upstream.\n- The docs site is a live v1 documentation site, not a patch-versioned archive. If an example behaves differently in `1.2.11`, check the LangChain release notes before assuming the docs exactly match that patch.\n- PyPI metadata for `1.2.11` requires Python `>=3.10,<4.0`.\n- In v1, many older pre-1.0 chains, agents, and memory helpers were moved into `langchain-classic`. Use `langchain-classic` only when maintaining legacy code. For new code, prefer the v1 `create_agent(...)` and LangGraph-based patterns.\n- LangChain's versioning policy says `langchain` and `langchain-core` share major and minor versions. Integration packages such as `langchain-openai`, `langchain-anthropic`, and `langchain-community` are separately versioned. Do not assume all companion packages should match `1.2.11`.\n\n## Install\n\nFor reproducible behavior, pin `langchain` and install the provider integration you actually use:\n\n```bash\npython -m pip install \"langchain==1.2.11\" \"langchain-openai\"\n```\n\nOther common integrations follow the same pattern:\n\n```bash\npython -m pip install \"langchain==1.2.11\" \"langchain-anthropic\"\npython -m pip install \"langchain==1.2.11\" \"langchain-community\"\n```\n\nIf you need production memory or checkpoint persistence, install the relevant LangGraph checkpoint package separately. The official install docs use packages such as `langgraph-checkpoint-postgres`.\n\n## Recommended Setup\n\nSet provider credentials in environment variables. The exact variable depends on the model provider package you install.\n\nOpenAI example:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nOptional LangSmith tracing:\n\n```bash\nexport LANGSMITH_TRACING=true\nexport LANGSMITH_API_KEY=\"lsv2_...\"\n```\n\nLangChain can initialize a model from a provider-qualified string:\n\n```python\nfrom langchain.chat_models import init_chat_model\n\nmodel = init_chat_model(\"openai:gpt-4.1-mini\")\n```\n\nThat requires the corresponding provider package to be installed. If `langchain-openai` is missing, model initialization will fail even though `langchain` itself is installed.\n\n## Core Usage\n\n### Initialize And Call A Chat Model\n\nUse `init_chat_model(...)` for direct model access when you do not need an agent loop:\n\n```python\nfrom langchain.chat_models import init_chat_model\n\nmodel = init_chat_model(\"openai:gpt-4.1-mini\")\n\nresponse = model.invoke(\"Write a one-sentence summary of LangChain.\")\nprint(response.content)\n```\n\nThis gives you the standard LangChain chat-model interface and keeps provider-specific client setup behind the integration package.\n\n### Create A Basic Agent\n\nFor tool-using workflows, use `create_agent(...)` in v1:\n\n```python\nfrom langchain.agents import create_agent\n\ndef get_weather(city: str) -> str:\n    return f\"It is always sunny in {city}!\"\n\nagent = create_agent(\n    model=\"openai:gpt-4.1-mini\",\n    tools=[get_weather],\n    system_prompt=\"You are a concise assistant.\",\n)\n\nresult = agent.invoke(\n    {\n        \"messages\": [\n            {\"role\": \"user\", \"content\": \"What is the weather in San Francisco?\"}\n        ]\n    }\n)\n\nprint(result[\"messages\"][-1].content)\n```\n\nPractical notes:\n\n- Pass a provider-qualified model string like `openai:gpt-4.1-mini`, or pass a model object created with `init_chat_model(...)`.\n- Agent input is message-based. For agent flows, the stable shape to reach for is a dict with a `messages` list.\n- Tool functions should have clear type hints and simple signatures. LangChain uses those to build tool schemas.\n\n### Model And Provider Configuration\n\nTwo setup patterns are most useful:\n\n1. Initialize the model once and reuse it.\n2. Keep provider credentials outside source code.\n\nExample with explicit configuration:\n\n```python\nfrom langchain.chat_models import init_chat_model\n\nmodel = init_chat_model(\n    \"openai:gpt-4.1-mini\",\n    temperature=0,\n)\n\nreply = model.invoke(\"Return exactly three bullet points about Python packaging.\")\nprint(reply.content)\n```\n\nIf your team switches providers, change the model string and install the new integration package. The surrounding LangChain code can often stay the same.\n\n### LangSmith Tracing\n\nIf you set `LANGSMITH_TRACING=true` and `LANGSMITH_API_KEY`, LangChain will emit traces to LangSmith for supported workflows. Use this when you need to inspect prompts, model calls, tool steps, and agent state transitions.\n\nTracing is optional. Do not hard-code LangSmith credentials into application code or example files.\n\n## Common Pitfalls\n\n- Installing only `langchain` is not enough for real provider calls. Also install the provider package such as `langchain-openai`.\n- Many search results still show pre-v1 imports and abstractions such as `LLMChain`, older agent executors, or legacy memory classes. Treat those as migration material, not the default pattern for new code.\n- The docs site is current-state documentation. When you are pinned to `1.2.11`, verify behavior against PyPI release history and LangChain release notes if you hit a mismatch.\n- Companion packages are versioned independently. Avoid blanket pinning every `langchain-*` package to `1.2.11` unless that package actually uses that version line.\n- Agent code expects message-oriented state. If you pass the wrong input shape to `agent.invoke(...)`, failures are often schema or state errors rather than model errors.\n- LangSmith tracing is useful in development, but it can leak sensitive inputs if you enable it indiscriminately in production environments.\n\n## What To Reach For First\n\n- Use `init_chat_model(...)` when you only need direct model invocation.\n- Use `create_agent(...)` when the workflow needs tools or a ReAct-style loop.\n- Use provider integration packages for actual model access.\n- Use `langchain-classic` only to keep older code running while you migrate.\n\n## Official Sources Used\n\n- LangChain Python docs root: `https://python.langchain.com/docs/`\n- LangChain install docs: `https://python.langchain.com/docs/how_to/installation/`\n- LangChain quickstart: `https://python.langchain.com/docs/tutorials/llm_chain/`\n- LangChain models guide: `https://python.langchain.com/docs/how_to/chat_models_universal_init/`\n- LangChain v1 release notes: `https://docs.langchain.com/oss/python/releases/langchain-v1`\n- LangChain versioning policy: `https://docs.langchain.com/oss/python/release-policy`\n- LangChain GitHub README: `https://github.com/langchain-ai/langchain`\n- PyPI package page: `https://pypi.org/project/langchain/`\n- PyPI release history: `https://pypi.org/project/langchain/#history`\n"
  },
  {
    "path": "content/langchain-community/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"langchain-community package guide for Python covering community integrations, loaders, vector stores, tools, and practical 0.4.1 usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain-community,langchain,python,integrations,document-loaders,vectorstores,tools\"\n---\n\n# langchain-community Python Package Guide\n\n## What It Is\n\n`langchain-community` is the Python package for community and third-party LangChain integrations that do not live in `langchain-core` and are not published as dedicated `langchain-*` provider packages.\n\nUse it for integration surfaces such as:\n\n- document loaders\n- vector stores\n- tools\n- retrievers\n- utilities and wrappers\n\nDo not treat it as the default package for every provider. LangChain's current integrations docs center dedicated packages such as `langchain-openai` and other provider-specific packages when they exist.\n\n## Version Notes\n\n- This guide is pinned to `langchain-community==0.4.1`.\n- LangChain's Python release policy explicitly calls out that integration packages such as `langchain-community` do not follow the same guarantees as `langchain` and `langchain-core`.\n- Pin exact versions if you need reproducible behavior across environments.\n- The current LangChain publishing guidance prefers standalone `langchain-*` packages for new integrations, so some older community integrations are transitional or effectively legacy.\n- The PyPI project page still contains older prose that refers to the `0.0.x` line; prefer the live package version and current LangChain reference docs over that stale summary text.\n\n## Install\n\nInstall the package itself:\n\n```bash\npython -m pip install \"langchain-community==0.4.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"langchain-community==0.4.1\"\npoetry add \"langchain-community==0.4.1\"\n```\n\nIn practice you usually install it with the dependency required by the integration you actually use:\n\n```bash\npython -m pip install \"langchain-community==0.4.1\" \"langchain-openai\"\npython -m pip install \"langchain-community==0.4.1\" \"faiss-cpu\"\npython -m pip install \"langchain-community==0.4.1\" \"duckduckgo-search\"\n```\n\nTypical package boundaries:\n\n- install `langchain` for higher-level agent and application APIs\n- install `langchain-core` for lower-level prompts, runnables, and shared abstractions\n- install a dedicated provider package when one exists\n- install the backend library required by the community integration you chose\n\n## Setup And Configuration\n\n`langchain-community` does not have one package-wide authentication model. Setup depends on the integration.\n\nPractical rules:\n\n1. Install the backend dependency required by the integration.\n2. Set provider-specific environment variables for the provider package or vendor SDK you use.\n3. Keep LangSmith tracing separate from model or service credentials.\n\nExample environment setup for a local FAISS workflow that uses OpenAI embeddings:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport LANGSMITH_TRACING=\"true\"\nexport LANGSMITH_API_KEY=\"lsv2_...\"\n```\n\nImportant boundary:\n\n- credentials usually belong to the provider package or vendor SDK, not to `langchain-community` itself\n- many community integrations only work after you install a second package such as `faiss-cpu`, `duckduckgo-search`, `pypdf`, or `unstructured`\n\n## Common Workflows\n\n### Load Local Files With `TextLoader`\n\nUse `TextLoader` to turn a local text file into LangChain `Document` objects:\n\n```python\nfrom langchain_community.document_loaders import TextLoader\n\nloader = TextLoader(\"notes.txt\")\ndocs = loader.load()\n\nfor doc in docs:\n    print(doc.page_content[:80])\n    print(doc.metadata)\n```\n\nIf the loader supports it and your input is large, prefer `lazy_load()` over eager `.load()`.\n\n### Build A FAISS Vector Store\n\nThe `FAISS` integration in `langchain-community` uses the separate `faiss-cpu` package for the index itself.\n\n```python\nfrom langchain_community.vectorstores import FAISS\nfrom langchain_openai import OpenAIEmbeddings\n\ntexts = [\n    \"LangChain Community contains third-party integrations.\",\n    \"FAISS is useful for local similarity search.\",\n]\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\nvector_store = FAISS.from_texts(texts, embeddings)\n\nresults = vector_store.similarity_search(\n    \"Which package contains third-party integrations?\",\n    k=1,\n)\n\nfor doc in results:\n    print(doc.page_content)\n```\n\nUseful follow-on calls:\n\n- `similarity_search_with_score(...)` when you need scores\n- `save_local(...)` and `load_local(...)` for persistence\n- `as_retriever(...)` when you want retriever behavior\n\n### Turn The Vector Store Into A Retriever\n\n`FAISS.as_retriever(...)` is the direct bridge from a local index to retrieval-oriented LangChain components:\n\n```python\nretriever = vector_store.as_retriever(\n    search_type=\"mmr\",\n    search_kwargs={\"k\": 2, \"fetch_k\": 4, \"lambda_mult\": 0.5},\n)\n\ndocs = retriever.invoke(\"third-party LangChain integrations\")\n\nfor doc in docs:\n    print(doc.page_content)\n```\n\n### Use A Community Tool Wrapper\n\n`DuckDuckGoSearchRun` is a simple example of a tool wrapper from this package:\n\n```python\nfrom langchain_community.tools import DuckDuckGoSearchRun\n\ntool = DuckDuckGoSearchRun()\nresult = tool.invoke(\"latest LangChain release policy\")\nprint(result)\n```\n\nInstall `duckduckgo-search` first, and check the integrations index before adopting a community tool wrapper for a provider that may already have a dedicated package.\n\n## Common Pitfalls\n\n- `langchain-community` is not the first package to assume for every provider; check the integrations overview for a dedicated package first.\n- Installing only `langchain-community` is often not enough; many integrations need an extra backend library or vendor SDK.\n- The package has no universal API key or shared client object.\n- Older LangChain examples on the web often use pre-`1.0` import paths or community wrappers that have since moved into dedicated packages.\n- Do not assume `langchain-community` version numbers should match `langchain` or `langchain-core`; these packages are versioned separately.\n- Minor-version changes in `0.x` integration packages can change behavior, so pin exact versions when you need stable builds.\n- `.load()` is eager; use streaming-friendly loader methods when the loader supports them.\n\n## What To Reach For First\n\n- Use `langchain-community` for loaders, vector stores, tools, utilities, and older shared integrations that still live here.\n- Use `langchain-core` for prompts, runnables, tools, and shared interfaces.\n- Use `langchain` for higher-level agent and application APIs.\n- Use dedicated provider packages for models, embeddings, and provider-owned integrations whenever possible.\n\n## Official Sources Used For This Entry\n\n- PyPI package page: `https://pypi.org/project/langchain-community/`\n- PyPI release history: `https://pypi.org/project/langchain-community/#history`\n- Maintainer docs URL: `https://python.langchain.com/api_reference/community/`\n- Canonical API reference root: `https://reference.langchain.com/python/langchain-community/`\n- LangChain integrations overview: `https://docs.langchain.com/oss/python/integrations/providers/overview`\n- LangChain install guide: `https://docs.langchain.com/oss/python/langchain/install`\n- LangChain Python release policy: `https://docs.langchain.com/oss/python/release-policy`\n- LangChain integration publishing guidance: `https://docs.langchain.com/oss/python/contributing/publish-langchain`\n"
  },
  {
    "path": "content/langchain-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"langchain-core package guide for Python covering runnables, prompt templates, tools, configuration, and integration boundaries\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain-core,langchain,python,llm,runnables,prompts,tools,langsmith\"\n---\n\n# langchain-core Python Package Guide\n\n## What This Package Provides\n\n`langchain-core` is the base abstractions package for LangChain Python applications.\n\nUse it for:\n\n- prompt templates and message objects\n- runnable composition with the LangChain Expression Language (LCEL)\n- tools and tool schemas\n- output parsers, documents, callbacks, and shared config plumbing\n\nImportant boundary: `langchain-core` does not include provider clients, embeddings, or vector store integrations. For actual model calls, pair it with an integration package such as `langchain-openai`.\n\nCommon imports:\n\n- `langchain_core.prompts`\n- `langchain_core.messages`\n- `langchain_core.runnables`\n- `langchain_core.tools`\n- `langchain_core.output_parsers`\n\n## Version Covered\n\n- Package: `langchain-core`\n- Version: `1.2.18`\n- Python requirement on PyPI: `>=3.10,<4.0`\n- Registry: `https://pypi.org/project/langchain-core/`\n- Canonical reference root: `https://reference.langchain.com/python/langchain_core/`\n\nThe maintainer docs URL `https://python.langchain.com/api_reference/core/` redirects to the current reference site under `reference.langchain.com`.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"langchain-core==1.2.18\"\n```\n\nIf you plan to call a hosted model, install the matching provider package too:\n\n```bash\npython -m pip install \"langchain-core==1.2.18\" \"langchain-openai\"\n```\n\n## Core Workflow\n\n### Build chat prompts\n\n`ChatPromptTemplate` turns message templates into a prompt value that downstream runnables can consume.\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Reply in one short sentence.\"),\n        (\"human\", \"Explain {topic}.\"),\n    ]\n)\n\nprompt_value = prompt.invoke({\"topic\": \"Python context managers\"})\n\nfor message in prompt_value.to_messages():\n    print(type(message).__name__, message.content)\n```\n\n`prompt.invoke(...)` returns a prompt value with message objects, not a plain string.\n\n### Compose runnables with LCEL\n\n`RunnableLambda` wraps a normal Python callable so it can participate in LCEL pipelines.\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_core.runnables import RunnableLambda\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Be concise.\"),\n        (\"human\", \"Summarize {topic} in one sentence.\"),\n    ]\n)\n\ndef mock_model(prompt_value) -> str:\n    last_message = prompt_value.to_messages()[-1].content\n    return f\"Stub answer for: {last_message}\"\n\nchain = prompt | RunnableLambda(mock_model)\n\nprint(chain.invoke({\"topic\": \"LCEL\"}))\n```\n\nInterfaces to remember:\n\n- `invoke(...)` for one input\n- `ainvoke(...)` for async use\n- `batch([...])` for multiple inputs\n- `stream(...)` and `astream(...)` when the runnable supports streaming\n\nThe reference docs note that `RunnableLambda` is best for logic that does not need token-by-token streaming.\n\n### Fan out one input into parallel branches\n\nUse `RunnableParallel` when the same input should feed multiple computations.\n\n```python\nfrom langchain_core.runnables import RunnableLambda, RunnableParallel\n\nanalysis = RunnableParallel(\n    original=RunnableLambda(lambda x: x[\"text\"]),\n    upper=RunnableLambda(lambda x: x[\"text\"].upper()),\n    word_count=RunnableLambda(lambda x: len(x[\"text\"].split())),\n)\n\nresult = analysis.invoke({\"text\": \"langchain core keeps abstractions reusable\"})\nprint(result)\n```\n\n### Define tools\n\nUse `@tool` when you need a callable with a name, description, and argument schema that an agent or model integration can consume.\n\n```python\nfrom langchain_core.tools import tool\n\n@tool\ndef lookup_order(order_id: str) -> str:\n    \"\"\"Return a stub shipping status for an order.\"\"\"\n    return f\"{order_id}: shipped\"\n\nprint(lookup_order.name)\nprint(lookup_order.invoke({\"order_id\": \"A-100\"}))\n```\n\nUse type hints and a useful docstring so the generated tool schema is accurate.\n\n### Attach run metadata and callbacks\n\nUse `with_config(...)` to add metadata, tags, callbacks, or concurrency settings without rewriting the runnable.\n\n```python\nfrom langchain_core.runnables import RunnableLambda\n\nuppercase = RunnableLambda(lambda text: text.upper()).with_config(\n    run_name=\"uppercase_demo\",\n    tags=[\"demo\", \"langchain-core\"],\n    metadata={\"package\": \"langchain-core\"},\n)\n\nprint(uppercase.invoke(\"hello\"))\n```\n\nCommon config keys:\n\n- `run_name`\n- `tags`\n- `metadata`\n- `callbacks`\n- `max_concurrency`\n- `recursion_limit`\n- `configurable`\n\n## Auth And Initialization\n\n### `langchain-core` has no provider auth of its own\n\n`langchain-core` is intentionally provider-agnostic. It does not define a package-specific API key for model access.\n\nFor real model calls:\n\n1. install the provider integration package\n2. set that provider's environment variables\n3. compose the provider client with your `langchain_core` prompt or runnable pipeline\n\nExample with `langchain-openai`:\n\n```bash\npython -m pip install \"langchain-openai\"\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_openai import ChatOpenAI\n\nprompt = ChatPromptTemplate(\n    [\n        (\"system\", \"Reply tersely.\"),\n        (\"human\", \"Summarize {topic} in one sentence.\"),\n    ]\n)\n\nmodel = ChatOpenAI(model=\"gpt-4.1-mini\")\nchain = prompt | model\n\nprint(chain.invoke({\"topic\": \"LangChain\"}).content)\n```\n\n### Optional LangSmith tracing\n\nLangSmith tracing is optional, but the official LangChain docs document these environment variables:\n\n```bash\nexport LANGSMITH_TRACING=true\nexport LANGSMITH_API_KEY=\"lsv2_...\"\nexport LANGSMITH_PROJECT=\"my-project\"\n```\n\nYou can use those settings when you want traces for prompt execution and runnable graphs. Pure `langchain-core` composition does not require LangSmith.\n\n## Practical Pitfalls\n\n- `langchain-core` is not the full application stack. Install separate provider or storage integrations when your workflow needs them.\n- `ChatPromptTemplate.invoke(...)` returns a prompt value with messages, not a plain string.\n- `RunnableLambda` is convenient for Python-only logic, but it is not the right wrapper when you need token streaming behavior from the callable itself.\n- Tool schemas depend on the Python signature and docstring. Untyped or poorly described functions produce weaker tool metadata.\n- Many LangChain examples on the web mix `langchain-core` with `langchain`, `langgraph`, LangSmith, or provider packages. Check imports before copying a snippet into a project pinned to `langchain-core` only.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/langchain-core/`\n- Install docs: `https://docs.langchain.com/oss/python/langchain/install`\n- Canonical API reference root: `https://reference.langchain.com/python/langchain_core/`\n- `RunnableLambda` reference: `https://reference.langchain.com/python/langchain_core/runnables/#langchain_core.runnables.base.RunnableLambda`\n- `ChatPromptTemplate` reference: `https://reference.langchain.com/python/langchain_core/prompts/#langchain_core.prompts.chat.ChatPromptTemplate`\n- LangSmith observability quickstart: `https://docs.langchain.com/langsmith/observability-quickstart`\n"
  },
  {
    "path": "content/langchain-openai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"langchain-openai package guide for Python covering ChatOpenAI, OpenAIEmbeddings, Responses API, Azure setup, and 1.1.11 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langchain-openai,langchain,openai,python,llm,embeddings,azure-openai\"\n---\n\n# langchain-openai Python Package Guide\n\n## What It Is\n\n`langchain-openai` is LangChain's maintained Python integration for OpenAI and Azure OpenAI models.\n\nUse it when you need:\n\n- `ChatOpenAI` for chat and responses-style model calls\n- `OpenAIEmbeddings` for embeddings\n- `AzureChatOpenAI` or `AzureOpenAIEmbeddings` for traditional Azure-specific setup\n- LangChain-native features such as tool binding, structured output, async calls, and streaming on top of OpenAI models\n\nImportant boundary: `langchain-openai` is an integration package, not the full framework. Install `langchain` or `langchain-core` alongside it when your app also needs prompts, runnables, agents, or graph orchestration.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.1.11`.\n- The docs URL `https://python.langchain.com/api_reference/openai/` is a legacy LangChain API-reference landing page. Current conceptual guides live under `docs.langchain.com`, and the current Python API reference is under `reference.langchain.com`.\n- LangChain's release policy treats integration packages such as `langchain-openai` as separately versioned packages. Do not assume they should match `langchain` or `langchain-core` patch versions.\n- Official docs note that `ChatOpenAI` can automatically use the OpenAI Responses API in some cases and can be forced with `use_responses_api=True`. If behavior matters, test against the exact model and request shape you use.\n- Official docs also note that, as of `langchain-openai >= 1.0.1`, `ChatOpenAI` and `OpenAIEmbeddings` can target Azure OpenAI's v1 API directly. Older Azure-specific examples may still use `AzureChatOpenAI` and `AzureOpenAIEmbeddings`.\n- The current chat integration guide marks OpenAI tool search as requiring `langchain-openai >= 1.1.11`, so this pinned version is new enough for that feature.\n\n## Install\n\nPin the integration package and whichever LangChain package your app actually uses:\n\n```bash\npython -m pip install \"langchain-openai==1.1.11\" \"langchain-core\"\n```\n\nTypical application install:\n\n```bash\npython -m pip install \"langchain==1.2.11\" \"langchain-openai==1.1.11\"\n```\n\nIf you are using Azure and want to stay close to LangChain's Azure-specific examples, the same package provides those classes:\n\n```bash\npython -m pip install \"langchain-openai==1.1.11\"\n```\n\n## Auth And Setup\n\n### OpenAI\n\nSet credentials in the environment before constructing models or embeddings:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nBasic model setup:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    temperature=0,\n)\n```\n\nYou can also pass request/client settings directly:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    organization=\"org_...\",\n    timeout=30,\n    max_retries=2,\n)\n```\n\n### Azure OpenAI\n\nFor traditional Azure-specific setup, use the Azure classes and Azure environment variables:\n\n```bash\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://my-resource.openai.azure.com/\"\nexport AZURE_OPENAI_API_VERSION=\"2024-10-21\"\n```\n\n```python\nfrom langchain_openai import AzureChatOpenAI\n\nllm = AzureChatOpenAI(\n    azure_deployment=\"gpt-4.1-mini\",\n    api_version=\"2024-10-21\",\n    temperature=0,\n)\n```\n\nFor Azure's newer v1 API shape, official docs say `ChatOpenAI` and `OpenAIEmbeddings` can also be pointed at an Azure `.../openai/v1/` base URL directly in modern `1.x` releases.\n\n## Core Usage\n\n### Basic Chat Invocation\n\nUse `invoke(...)` for a single request and read the returned `AIMessage`:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\n\nresponse = llm.invoke(\"Give me a one-sentence summary of LangChain.\")\nprint(response.content)\n```\n\nMessage-based input works too:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\n\nresponse = llm.invoke(\n    [\n        (\"system\", \"Reply in JSON.\"),\n        (\"human\", \"Return the keys name and role for Ada Lovelace.\"),\n    ]\n)\nprint(response.content)\n```\n\n### Tool Calling\n\n`ChatOpenAI` supports LangChain tool binding:\n\n```python\nfrom langchain_core.tools import tool\nfrom langchain_openai import ChatOpenAI\n\n@tool\ndef get_weather(city: str) -> str:\n    \"\"\"Return a stub weather string.\"\"\"\n    return f\"{city}: sunny\"\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\nllm_with_tools = llm.bind_tools([get_weather])\n\nresponse = llm_with_tools.invoke(\"What is the weather in San Francisco?\")\nprint(response.tool_calls)\n```\n\nUse this when you want the model to choose tools through LangChain's standard tool interface instead of calling the OpenAI SDK directly.\n\n### Structured Output\n\nFor typed extraction, use `with_structured_output(...)`:\n\n```python\nfrom pydantic import BaseModel\nfrom langchain_openai import ChatOpenAI\n\nclass Person(BaseModel):\n    name: str\n    role: str\n\nllm = ChatOpenAI(model=\"gpt-4.1-mini\", temperature=0)\nstructured_llm = llm.with_structured_output(Person)\n\nperson = structured_llm.invoke(\"Ada Lovelace was an early computing pioneer.\")\nprint(person)\n```\n\nOfficial docs call out modern methods such as `json_schema` for OpenAI's structured output support. Prefer current structured-output helpers over older prompt-only JSON parsing.\n\n### Responses API And Conversation State\n\nOfficial docs describe two patterns worth knowing:\n\n- force the Responses API path with `use_responses_api=True` when you need Responses-specific behavior\n- use `previous_response_id` or automatic conversation-state management when you want the model to continue from a prior response in supported flows\n\nExample:\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    use_responses_api=True,\n)\n\nresponse = llm.invoke(\"List three uses for embeddings.\")\nprint(response.content)\n```\n\nIf you rely on Responses-specific content blocks or reasoning output, verify the exact response shape in your tests before hard-coding assumptions.\n\n### Streaming\n\nUse `.stream(...)` for incremental tokens. If you need token usage with streaming, the docs call out `stream_usage=True`.\n\n```python\nfrom langchain_openai import ChatOpenAI\n\nllm = ChatOpenAI(\n    model=\"gpt-4.1-mini\",\n    stream_usage=True,\n)\n\nfor chunk in llm.stream(\"Write a short haiku about Python packaging.\"):\n    print(chunk.content, end=\"\")\n```\n\n### Embeddings\n\nUse `OpenAIEmbeddings` for text/vector generation:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-large\")\n\nvector = embeddings.embed_query(\"LangChain integrates models into one interface.\")\nprint(len(vector))\n```\n\nBatch embedding:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n\nvectors = embeddings.embed_documents(\n    [\n        \"first document\",\n        \"second document\",\n    ]\n)\nprint(len(vectors), len(vectors[0]))\n```\n\nFor `text-embedding-3-*` models, the official reference documents a `dimensions` option when you need smaller vectors:\n\n```python\nfrom langchain_openai import OpenAIEmbeddings\n\nembeddings = OpenAIEmbeddings(\n    model=\"text-embedding-3-large\",\n    dimensions=1024,\n)\n```\n\n## Common Configuration Choices\n\n- `model`: OpenAI or Azure deployment/model identifier\n- `temperature`: randomness for chat models\n- `timeout`: request timeout\n- `max_retries`: client retry count\n- `base_url`: alternate API base, including modern Azure v1 endpoints\n- `organization`: OpenAI org when applicable\n- `stream_usage`: include usage metadata during streaming\n- `reasoning`: reasoning controls for supported OpenAI reasoning-capable models\n\nKeep these in constructor arguments or environment variables, not hard-coded inside prompts or helper functions.\n\n## Common Pitfalls\n\n- Installing `langchain-openai` alone is not enough if your code also imports `langchain` or `langchain_core` abstractions.\n- Do not assume every `langchain-*` package should share the same version number. `langchain-openai` is separately versioned.\n- Older blog posts often show legacy `OpenAI` completion classes or pre-Responses OpenAI behavior. For new code, prefer `ChatOpenAI` unless you specifically need older completion behavior.\n- The hosted docs are live product docs, not an archive pinned to `1.1.11`. If you are debugging a version-specific mismatch, check PyPI release history and the LangChain release policy before copying a newer example verbatim.\n- When streaming, usage metadata is not automatic in all paths. If your code depends on token counts, enable the documented usage option and test it.\n- If you are targeting Azure, do not mix OpenAI and Azure environment variables casually. Pick either the Azure-specific class pattern or the Azure v1 `base_url` pattern and keep the configuration consistent.\n- `OpenAIEmbeddings.dimensions` applies to the newer embedding models; do not assume every model supports custom dimensions.\n- `langchain-openai` is designed around OpenAI's API semantics. OpenAI-compatible third-party providers may need extra parameters or different behavior that LangChain intentionally does not preserve.\n\n## What To Reach For First\n\n- Use `ChatOpenAI` for most OpenAI model calls in LangChain.\n- Use `OpenAIEmbeddings` for retrieval, semantic search, and vector indexing.\n- Use `with_structured_output(...)` for typed extraction.\n- Use `bind_tools(...)` when you need model-driven tool selection.\n- Use `AzureChatOpenAI` or `AzureOpenAIEmbeddings` when your codebase already follows the Azure-specific configuration pattern.\n\n## Official Sources Used\n\n- `https://python.langchain.com/api_reference/openai/`\n- `https://docs.langchain.com/oss/python/integrations/chat/openai`\n- `https://docs.langchain.com/oss/python/integrations/text_embedding/openai`\n- `https://reference.langchain.com/python/integrations/langchain_openai`\n- `https://docs.langchain.com/oss/python/release-policy`\n- `https://pypi.org/project/langchain-openai/`\n"
  },
  {
    "path": "content/langfuse/docs/observability/python/DOC.md",
    "content": "---\nname: observability\ndescription: \"Langfuse Python SDK v3 for LLM observability, tracing, prompt management, scoring, and experiment evaluation\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.14.5\"\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: community\n  tags: \"langfuse,observability,tracing,llm,evaluation,prompts\"\n---\n\n\n# Langfuse Python SDK v3 Guidelines\n\nYou are a Langfuse SDK coding expert. Help me with writing code using the Langfuse Python SDK for LLM observability, tracing, prompt management, scoring, and evaluation.\n\nOfficial documentation: https://langfuse.com/docs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Langfuse Python SDK v3 (built on OpenTelemetry). v2 is deprecated and receives security patches only.\n\n- **Library Name:** Langfuse Python SDK\n- **Python Package:** `langfuse`\n- **Installation:** `pip install langfuse`\n- **Python Requirement:** `>=3.10, <4.0`\n\n**Correct imports (v3):**\n\n- **Correct:** `from langfuse import Langfuse, get_client, observe`\n- **Correct:** `from langfuse import propagate_attributes`\n- **Correct:** `from langfuse.openai import openai` (OpenAI drop-in wrapper)\n- **Correct:** `from langfuse.langchain import CallbackHandler` (LangChain integration)\n\n**Incorrect imports (v2 — do not use):**\n\n- **Wrong:** `from langfuse.decorators import observe` → use `from langfuse import observe`\n- **Wrong:** `from langfuse.callback import CallbackHandler` → use `from langfuse.langchain import CallbackHandler`\n- **Wrong:** `langfuse_context.update_current_trace()` → use `langfuse.update_current_trace()`\n\n## Environment Variables\n\n```bash\nLANGFUSE_SECRET_KEY=\"sk-lf-...\"\nLANGFUSE_PUBLIC_KEY=\"pk-lf-...\"\nLANGFUSE_BASE_URL=\"https://cloud.langfuse.com\"        # EU (default)\n# LANGFUSE_BASE_URL=\"https://us.cloud.langfuse.com\"   # US region\n```\n\n**Important:** The env var was renamed from `LANGFUSE_HOST` (v2) to `LANGFUSE_BASE_URL` (v3). The old name still works but is deprecated.\n\nOptional:\n- `LANGFUSE_DEBUG=\"True\"` — enables debug logging\n\n## Initialisation\n\nThe v3 client is a **singleton**. Two ways to access it:\n\n```python\n# Option 1: get_client() — preferred, uses env vars automatically\nfrom langfuse import get_client\n\nlangfuse = get_client()\n```\n\n```python\n# Option 2: Constructor with explicit credentials\nfrom langfuse import Langfuse\n\nlangfuse = Langfuse(\n    public_key=\"pk-lf-...\",\n    secret_key=\"sk-lf-...\",\n    base_url=\"https://cloud.langfuse.com\",\n)\n```\n\nVerify connection (development only):\n\n```python\nif langfuse.auth_check():\n    print(\"Connected to Langfuse\")\n```\n\n## Core Concepts\n\n- **Trace:** Top-level container for a request. In v3, traces are implicitly created by the first root observation — no explicit `langfuse.trace()` call.\n- **Span:** General-purpose observation for tracking any operation (retrieval, processing, etc.).\n- **Generation:** Specialised observation for LLM calls, with fields for `model`, `usage_details`, input/output tokens.\n- **Score:** Evaluation data attached to traces/observations. Types: `NUMERIC`, `CATEGORICAL`, `BOOLEAN`.\n- **Dataset:** Collection of input/expected-output items for running experiments.\n- **Prompt:** Version-controlled templates managed in Langfuse and fetched at runtime.\n\n## Tracing with the @observe() Decorator\n\nThe simplest and recommended approach. The outermost `@observe()` call creates a trace. Nested decorated functions automatically become child spans/generations.\n\n```python\nfrom langfuse import observe, get_client\n\n@observe()\ndef my_pipeline(query: str) -> str:\n    context = retrieve_context(query)\n    answer = generate_answer(query, context)\n    return answer\n\n@observe()\ndef retrieve_context(query: str) -> str:\n    # Automatically becomes a child span of my_pipeline\n    return \"relevant context\"\n\n@observe(name=\"llm-call\", as_type=\"generation\")\ndef generate_answer(query: str, context: str) -> str:\n    # Becomes a child generation observation\n    return \"answer based on context\"\n```\n\n**Decorator parameters:**\n\n| Parameter | Type | Default | Purpose |\n|---|---|---|---|\n| `name` | `str` | function name | Custom observation name |\n| `as_type` | `str` | `\"span\"` | `\"span\"` or `\"generation\"` |\n| `capture_input` | `bool` | `True` | Capture function args |\n| `capture_output` | `bool` | `True` | Capture return value |\n\nWorks with both sync and async functions.\n\n**Updating observations from within a decorated function:**\n\n```python\n@observe()\ndef my_function():\n    langfuse = get_client()\n    langfuse.update_current_span(metadata={\"step\": \"complete\"})\n    langfuse.update_current_trace(\n        input={\"query\": \"...\"},\n        output={\"answer\": \"...\"},\n    )\n```\n\n## Tracing with Context Managers\n\nFor more control over observation lifecycle:\n\n```python\nfrom langfuse import get_client, propagate_attributes\n\nlangfuse = get_client()\n\nwith langfuse.start_as_current_observation(\n    as_type=\"span\",\n    name=\"user-request-pipeline\",\n    input={\"user_query\": \"Tell me a joke\"},\n) as root_span:\n    with propagate_attributes(user_id=\"user_123\", session_id=\"session_abc\"):\n        with langfuse.start_as_current_observation(\n            as_type=\"generation\",\n            name=\"joke-generation\",\n            model=\"gpt-4o\",\n        ) as generation:\n            generation.update(output=\"Why did the chicken...\")\n\n    root_span.update(output={\"final_joke\": \"...\"})\n```\n\nThe context manager handles `.end()` automatically.\n\n## Manual Observation Creation\n\nFor cases where decorators or context managers don't fit:\n\n```python\nlangfuse = get_client()\n\nspan = langfuse.start_observation(name=\"manual-span\")\nspan.update(input=\"data\")\nchild = span.start_observation(name=\"child-gen\", as_type=\"generation\")\nchild.end()   # YOU MUST call .end() manually\nspan.end()    # YOU MUST call .end() manually\n```\n\n**Critical:** With `start_observation()`, you are responsible for calling `.end()`. Failure to do so results in incomplete/missing observations.\n\n## Setting Trace-Level Attributes\n\nUse `propagate_attributes()` to set user, session, and metadata on all observations:\n\n```python\nfrom langfuse import get_client, propagate_attributes\n\nlangfuse = get_client()\n\nwith langfuse.start_as_current_observation(as_type=\"span\", name=\"workflow\"):\n    with propagate_attributes(\n        user_id=\"user_123\",\n        session_id=\"session_abc\",\n        metadata={\"experiment\": \"variant_a\"},\n        tags=[\"production\"],\n        version=\"1.0\",\n    ):\n        # All observations created inside inherit these attributes\n        pass\n```\n\nFor cross-service distributed tracing, use `as_baggage=True` inside `propagate_attributes()`.\n\n## OpenAI Integration (Drop-in Wrapper)\n\nChange only the import — everything else stays the same:\n\n```python\nfrom langfuse.openai import openai\n# Or individually: from langfuse.openai import OpenAI, AsyncOpenAI, AzureOpenAI\n\n# Use exactly like the standard OpenAI client\nresponse = openai.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n)\n```\n\nAutomatically captures: prompts, completions, token counts, latencies, errors, streaming time-to-first-token.\n\n**Combining with @observe() for grouped traces:**\n\n```python\nfrom langfuse import observe\nfrom langfuse.openai import openai\n\n@observe()\ndef my_pipeline(country: str) -> str:\n    capital = openai.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Capital of {country}?\"}],\n        name=\"get-capital\",\n    ).choices[0].message.content\n\n    poem = openai.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Write a poem about {capital}\"}],\n        name=\"generate-poem\",\n    ).choices[0].message.content\n    return poem\n```\n\n**Setting trace attributes via metadata:**\n\n```python\nresponse = openai.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[...],\n    metadata={\n        \"langfuse_user_id\": \"user_123\",\n        \"langfuse_session_id\": \"session_456\",\n        \"langfuse_tags\": [\"chat\"],\n        \"custom_key\": \"custom_value\",  # Non-prefixed keys become custom metadata\n    },\n)\n```\n\n## LangChain Integration\n\n```python\nfrom langfuse.langchain import CallbackHandler\n\nlangfuse_handler = CallbackHandler()\n\nresponse = chain.invoke(\n    {\"topic\": \"cats\"},\n    config={\n        \"callbacks\": [langfuse_handler],\n        \"metadata\": {\n            \"langfuse_user_id\": \"user_123\",\n            \"langfuse_session_id\": \"session_456\",\n            \"langfuse_tags\": [\"langchain\"],\n        },\n    },\n)\n```\n\n**Combining with @observe():**\n\n```python\n@observe()\ndef process_user_query(user_input: str):\n    with propagate_attributes(session_id=\"s-1234\", user_id=\"u-5678\"):\n        handler = CallbackHandler()\n        result = chain.invoke(\n            {\"input\": user_input},\n            config={\"callbacks\": [handler]},\n        )\n    return result\n```\n\n## Prompt Management\n\n**Create a prompt:**\n\n```python\nlangfuse = get_client()\n\nlangfuse.create_prompt(\n    name=\"movie-critic\",\n    type=\"text\",  # or \"chat\" — type cannot be changed after creation\n    prompt=\"As a {{criticlevel}} movie critic, do you like {{movie}}?\",\n    labels=[\"production\"],\n)\n```\n\n**Fetch and compile:**\n\n```python\nprompt = langfuse.get_prompt(\"movie-critic\")  # Fetches \"production\" label by default\ncompiled = prompt.compile(criticlevel=\"expert\", movie=\"Dune 2\")\n# Returns: \"As an expert movie critic, do you like Dune 2?\"\n```\n\nFor chat prompts, `.compile()` returns a list of message dicts with `role`/`content`.\n\n- **Variable syntax:** `{{variableName}}` using double curly braces\n- **Caching:** Prompts are cached client-side — recently updated prompts may not appear immediately\n- **Prompt types:** `\"text\"` (returns string) and `\"chat\"` (returns list of messages)\n\n## Scoring\n\nThree types: `NUMERIC` (float), `CATEGORICAL` (string), `BOOLEAN` (0 or 1).\n\n```python\nlangfuse = get_client()\n\n# Low-level: create_score()\nlangfuse.create_score(\n    name=\"correctness\",\n    value=0.9,\n    trace_id=\"trace_id_here\",\n    observation_id=\"obs_id_here\",  # optional\n    data_type=\"NUMERIC\",\n    comment=\"Factually correct\",\n)\n\n# From a span context\nwith langfuse.start_as_current_observation(as_type=\"span\", name=\"op\") as span:\n    span.score(name=\"correctness\", value=0.9, data_type=\"NUMERIC\")\n    span.score_trace(name=\"overall_quality\", value=0.95, data_type=\"NUMERIC\")\n\n# Score current context\nwith langfuse.start_as_current_observation(as_type=\"span\", name=\"op\"):\n    langfuse.score_current_span(name=\"quality\", value=0.9, data_type=\"NUMERIC\")\n    langfuse.score_current_trace(name=\"overall\", value=0.95, data_type=\"NUMERIC\")\n```\n\n**Important:** Boolean scores must explicitly set `data_type=\"BOOLEAN\"` — otherwise a value of `0` or `1` is inferred as numeric.\n\n## Experiments and Evaluation\n\nThe experiment runner is the recommended way to run evaluations:\n\n```python\nfrom langfuse import get_client, Evaluation\nfrom langfuse.openai import OpenAI\n\nlangfuse = get_client()\n\n# Define a task\ndef my_task(*, item, **kwargs):\n    response = OpenAI().chat.completions.create(\n        model=\"gpt-4.1\",\n        messages=[{\"role\": \"user\", \"content\": item[\"input\"]}],\n    )\n    return response.choices[0].message.content\n\n# Define item-level evaluators\ndef accuracy_evaluator(*, input, output, expected_output, metadata, **kwargs):\n    if expected_output and expected_output.lower() in output.lower():\n        return Evaluation(name=\"accuracy\", value=1.0, comment=\"Correct\")\n    return Evaluation(name=\"accuracy\", value=0.0, comment=\"Incorrect\")\n\n# Define run-level evaluators\ndef average_accuracy(*, item_results, **kwargs):\n    accuracies = [\n        e.value for r in item_results for e in r.evaluations if e.name == \"accuracy\"\n    ]\n    avg = sum(accuracies) / len(accuracies) if accuracies else 0\n    return Evaluation(name=\"avg_accuracy\", value=avg)\n\n# Run with local data\nlocal_data = [\n    {\"input\": \"Capital of France?\", \"expected_output\": \"Paris\"},\n    {\"input\": \"Capital of Germany?\", \"expected_output\": \"Berlin\"},\n]\n\nresult = langfuse.run_experiment(\n    name=\"Geography Quiz\",\n    description=\"Testing basic geography\",\n    data=local_data,\n    task=my_task,\n    evaluators=[accuracy_evaluator],\n    run_evaluators=[average_accuracy],\n    max_concurrency=5,\n)\nprint(result.format())\n```\n\n**Using a Langfuse-hosted dataset:**\n\n```python\ndataset = langfuse.get_dataset(\"my-evaluation-dataset\")\nresult = dataset.run_experiment(\n    name=\"Production Model Test\",\n    task=my_task,\n    evaluators=[accuracy_evaluator],\n)\n```\n\n**Function signatures:**\n- Task: `def my_task(*, item, **kwargs)` — `item` is a dict (local) or `DatasetItemClient` (access `.input`, `.expected_output`, `.metadata`)\n- Item evaluator: `def eval(*, input, output, expected_output, metadata, **kwargs)` — returns `Evaluation`\n- Run evaluator: `def eval(*, item_results, **kwargs)` — returns `Evaluation`\n\n## Flush, Shutdown, and Lifecycle\n\nThe SDK batches events in the background. You must handle shutdown explicitly:\n\n```python\nlangfuse = get_client()\n\n# For short-lived scripts / serverless / notebooks:\nlangfuse.flush()     # Blocks until all buffered events are sent\n\n# For application shutdown:\nlangfuse.shutdown()  # Flushes + waits for background threads to terminate\n```\n\n**When you MUST flush/shutdown:**\n- Serverless functions (Lambda, Cloud Functions)\n- Scripts and notebooks\n- Before process exit in any application\n\n## Common Gotchas\n\n1. **Forgetting `.end()`:** When using `start_observation()` (manual spans), you MUST call `.end()`. The context manager and decorator handle this automatically.\n2. **Forgetting `flush()`/`shutdown()`:** In short-lived processes, events will be lost if you don't flush before exit.\n3. **Threading:** The `@observe()` decorator uses `contextvars`. It does NOT work with `ThreadPoolExecutor`, `ProcessPoolExecutor`, or manually spawned threads — the context is not copied.\n4. **OTEL noise:** v3 captures ALL OpenTelemetry spans in your application (database queries, HTTP clients, etc.). Filter or disable unwanted instrumentation to avoid excessive data.\n5. **Async context:** In async code, use context managers or `@observe()` rather than manual span management to avoid losing context across `await` boundaries.\n6. **Boolean scores:** Must explicitly set `data_type=\"BOOLEAN\"` — otherwise `0`/`1` is inferred as numeric.\n7. **Prompt caching:** `get_prompt()` returns a cached version. Recently updated prompts may not appear immediately.\n8. **Self-hosted:** Python SDK v3 requires Langfuse platform >= 3.125.0.\n9. **`as_type=\"generation\"` on `@observe()`:** Cannot be the outermost call — it must be nested inside another `@observe()` or context-managed span.\n\n## Key v2 to v3 Migration Changes\n\n| Area | v2 (deprecated) | v3 (current) |\n|---|---|---|\n| Client access | `Langfuse()` direct | `get_client()` singleton |\n| Trace creation | `langfuse.trace()` | Implicit via first root observation |\n| Span/generation | `trace.generation()`, `trace.span()` | `start_as_current_observation(as_type=...)` |\n| Decorator import | `from langfuse.decorators import observe` | `from langfuse import observe` |\n| Context updates | `langfuse_context.update_current_trace()` | `langfuse.update_current_trace()` |\n| LangChain import | `from langfuse.callback import CallbackHandler` | `from langfuse.langchain import CallbackHandler` |\n| Host env var | `LANGFUSE_HOST` | `LANGFUSE_BASE_URL` |\n| Trace attributes | Direct params (`user_id=...`) | Via `metadata={\"langfuse_user_id\": ...}` or `propagate_attributes()` |\n"
  },
  {
    "path": "content/langgraph/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"langgraph package guide for Python graphs, persistence, streaming, and local agent development\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"langgraph,langchain,agents,graphs,workflow,streaming,persistence\"\n---\n\n# langgraph Python Package Guide\n\n## What It Is\n\n`langgraph` is LangChain's low-level orchestration library for long-running, stateful agent and workflow graphs. Use it when you need explicit control over graph state, node routing, checkpointing, streaming, interrupts, and multi-step execution.\n\nIf you only need a higher-level agent abstraction, the LangChain docs recommend starting with `langchain`'s `create_agent` and dropping to LangGraph when you need custom orchestration.\n\n## Install\n\nBase package:\n\n```bash\npip install -U langgraph\n```\n\nLangGraph examples in the official docs often also install LangChain and a model provider integration:\n\n```bash\npip install -U langchain\npip install -U langchain-openai\n```\n\nLocal Agent Server and Studio development use the separate CLI package:\n\n```bash\npip install -U \"langgraph-cli[inmem]\"\n```\n\nPython requirements from official sources:\n\n- `langgraph`: Python `>=3.10`\n- `langgraph-cli[inmem]`: Python `>=3.11`\n\n## Core Imports\n\nMost graph code starts from these imports:\n\n```python\nfrom typing_extensions import TypedDict\nfrom langgraph.graph import StateGraph, START, END\n```\n\nFor chat-style state, use `MessagesState`:\n\n```python\nfrom langgraph.graph import MessagesState\n```\n\n## Minimal Graph\n\nUse `StateGraph` to define a typed state schema, add nodes, wire edges, then compile before invoking:\n\n```python\nfrom typing_extensions import TypedDict\nfrom langgraph.graph import StateGraph, START, END\n\nclass State(TypedDict):\n    text: str\n\ndef node_a(state: State) -> dict:\n    return {\"text\": state[\"text\"] + \"a\"}\n\ndef node_b(state: State) -> dict:\n    return {\"text\": state[\"text\"] + \"b\"}\n\nbuilder = StateGraph(State)\nbuilder.add_node(\"node_a\", node_a)\nbuilder.add_node(\"node_b\", node_b)\nbuilder.add_edge(START, \"node_a\")\nbuilder.add_edge(\"node_a\", \"node_b\")\nbuilder.add_edge(\"node_b\", END)\n\ngraph = builder.compile()\nresult = graph.invoke({\"text\": \"\"})\nprint(result)  # {\"text\": \"ab\"}\n```\n\nRules that matter:\n\n- Nodes take `State` and return a partial state update as `dict`.\n- `StateGraph` is a builder only. You must call `.compile()` before `invoke()`, `ainvoke()`, `stream()`, or `astream()`.\n- Use reducers on state keys when multiple nodes may update the same key in one step.\n\n## Chat / Agent-Style Graph\n\nFor message-oriented workflows, define state around messages and call a model inside a node:\n\n```python\nimport operator\nfrom typing import Annotated\nfrom typing_extensions import TypedDict\nfrom langchain.chat_models import init_chat_model\nfrom langchain.messages import AnyMessage, SystemMessage\nfrom langgraph.graph import StateGraph, START, END\n\nclass AgentState(TypedDict):\n    messages: Annotated[list[AnyMessage], operator.add]\n    llm_calls: int\n\nmodel = init_chat_model(\"gpt-4.1\", temperature=0)\n\ndef llm_call(state: AgentState) -> dict:\n    response = model.invoke(\n        [SystemMessage(content=\"You are a concise assistant.\")] + state[\"messages\"]\n    )\n    return {\n        \"messages\": [response],\n        \"llm_calls\": state.get(\"llm_calls\", 0) + 1,\n    }\n\nbuilder = StateGraph(AgentState)\nbuilder.add_node(\"llm_call\", llm_call)\nbuilder.add_edge(START, \"llm_call\")\nbuilder.add_edge(\"llm_call\", END)\n\ngraph = builder.compile()\n```\n\nOfficial quickstarts also show tool-calling flows built on the same pattern: define tools, bind them to the model, then route between an LLM node and a tool-execution node.\n\n## Persistence And Threaded Execution\n\nCheckpointing is the main LangGraph primitive for resumability, memory, interrupts, and fault tolerance.\n\nDevelopment example:\n\n```python\nfrom langgraph.checkpoint.memory import InMemorySaver\n\ncheckpointer = InMemorySaver()\ngraph = builder.compile(checkpointer=checkpointer)\n\nresult = graph.invoke(\n    {\"messages\": [{\"role\": \"user\", \"content\": \"hi\"}]},\n    {\"configurable\": {\"thread_id\": \"thread-1\"}},\n)\n```\n\nImportant behavior:\n\n- With a checkpointer, LangGraph saves a checkpoint at each super-step.\n- Checkpoints are grouped by `thread_id`.\n- If you want conversation continuity, reuse the same `thread_id`.\n- If you forget `thread_id`, persistent chat and resume behavior will not work as expected.\n\nProduction guidance from official docs:\n\n- `InMemorySaver` is for debugging and testing.\n- For local persistent experiments, install a real backend such as SQLite.\n- For production, use a persistent backend such as Postgres-based checkpointing or LangSmith-managed infrastructure.\n\n## Long-Term Store\n\nUse a store for data that must survive across threads, such as user memory or shared application state:\n\n```python\nfrom dataclasses import dataclass\nfrom langgraph.runtime import Runtime\nfrom langgraph.store.memory import InMemoryStore\nfrom langgraph.checkpoint.memory import InMemorySaver\nfrom langgraph.graph import StateGraph, MessagesState\n\n@dataclass\nclass Context:\n    user_id: str\n\nstore = InMemoryStore()\ncheckpointer = InMemorySaver()\n\nasync def read_or_write_memory(state: MessagesState, runtime: Runtime[Context]):\n    namespace = (runtime.context.user_id, \"memories\")\n    memories = await runtime.store.asearch(namespace, query=\"recent preferences\", limit=3)\n    return {}\n\nbuilder = StateGraph(MessagesState, context_schema=Context)\nbuilder.add_node(\"memory\", read_or_write_memory)\ngraph = builder.compile(checkpointer=checkpointer, store=store)\n```\n\nUse this split consistently:\n\n- Checkpointer: thread-level state across steps in one conversation or run lineage\n- Store: cross-thread, user-level, or app-level memory\n\n## Streaming\n\nCompiled graphs support `stream()` and `astream()`. Official stream modes include:\n\n- `\"values\"`: full graph state after each step\n- `\"updates\"`: only node/task updates\n- `\"messages\"`: token/message streaming from LLM calls\n- `\"custom\"`: your own events from inside nodes\n- `\"checkpoints\"` / `\"tasks\"` / `\"debug\"`: deeper runtime visibility\n\nExample:\n\n```python\nfor chunk in graph.stream(\n    {\"messages\": [{\"role\": \"user\", \"content\": \"summarize this\"}]},\n    {\"configurable\": {\"thread_id\": \"thread-1\"}},\n    stream_mode=\"updates\",\n):\n    print(chunk)\n```\n\nCustom stream events from inside a node:\n\n```python\nfrom langgraph.config import get_stream_writer\n\ndef my_node(state):\n    writer = get_stream_writer()\n    writer({\"stage\": \"starting\"})\n    return {}\n```\n\n`get_stream_writer()` relies on context variables. Official reference notes this is not supported for async LangGraph execution on Python `<3.11`.\n\n## Config And Auth\n\n`langgraph` itself does not define a single auth scheme. In practice you usually configure:\n\n- Model provider credentials such as `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`\n- Optional LangSmith tracing settings such as `LANGSMITH_API_KEY` and `LANGSMITH_TRACING=true`\n- Optional `LANGGRAPH_AES_KEY` if you enable encrypted checkpoint serialization\n\nTypical setup:\n\n```bash\nexport OPENAI_API_KEY=\"...\"\nexport LANGSMITH_API_KEY=\"...\"\nexport LANGSMITH_TRACING=\"true\"\n```\n\nFor local Agent Server / Studio workflows, the official LangGraph docs list `LANGSMITH_API_KEY` as a prerequisite.\n\n## Local Agent Server\n\nUse the CLI when you want a local API server, Studio integration, or a production-like deployment path:\n\n```bash\npip install -U \"langgraph-cli[inmem]\"\nlanggraph new my-agent --template new-langgraph-project-python\ncd my-agent\npip install -e .\nlanggraph dev\n```\n\nWhat this gives you:\n\n- local Agent Server on `http://127.0.0.1:2024`\n- Studio URL backed by your local server\n- generated API docs at `/docs`\n\nUse `langgraph dev` for fast local development. Official platform docs describe `langgraph up` as the more production-like Docker-backed path.\n\n## Common Pitfalls\n\n- Do not call methods on the builder. Compile first, then use the compiled graph.\n- Do not use `InMemorySaver` or `InMemoryStore` as your production persistence layer.\n- Do not expect checkpointing to work without passing `thread_id` in `configurable`.\n- Do not assume LangGraph ships every LLM integration. Install model-provider packages separately.\n- Do not treat LangGraph as a prompt framework. It orchestrates state and execution; prompt/model setup usually comes from LangChain or your own code.\n- If multiple nodes update the same state key in one step, define a reducer or you can get invalid concurrent update errors.\n- If you need cross-thread memory, a checkpointer alone is not enough; add a store.\n\n## Version-Sensitive Notes\n\n- The target version for this session is `1.1.0`.\n- The official docs site is now rooted at `docs.langchain.com`, and the API reference is at `reference.langchain.com`; the previous `langchain-ai.github.io` URL is an older docs location.\n- Official reference pages still display package labels such as `v1.0.9` and `v1.0.10` on some modules. Treat the docs as a floating v1.x reference and verify your installed package version when debugging behavior differences.\n- The official v1 release notes state that LangGraph's `create_react_agent` prebuilt is deprecated in favor of LangChain's `create_agent`.\n- If you copy pre-v1 examples from blogs or archived docs, re-check imports and prebuilt APIs against the current reference before using them unchanged.\n\n## Official Sources\n\n- Docs overview: https://docs.langchain.com/oss/python/langgraph/\n- Install: https://docs.langchain.com/oss/python/langgraph/install\n- Quickstart: https://docs.langchain.com/oss/python/langgraph/quickstart\n- Graph API guide: https://docs.langchain.com/oss/python/langgraph/use-graph-api\n- Persistence: https://docs.langchain.com/oss/python/langgraph/persistence\n- Memory: https://docs.langchain.com/oss/python/langgraph/add-memory\n- Local server: https://docs.langchain.com/oss/python/langgraph/local-server\n- CLI reference: https://docs.langchain.com/langgraph-platform/cli\n- API reference root: https://reference.langchain.com/python/langgraph/\n- PyPI: https://pypi.org/project/langgraph/\n- Source repository: https://github.com/langchain-ai/langgraph\n"
  },
  {
    "path": "content/langserve/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"langserve package guide for Python FastAPI deployment, RemoteRunnable clients, auth boundaries, and 0.3.3 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langserve,langchain,fastapi,runnable,api,python\"\n---\n\n# langserve Python Package Guide\n\n## When To Use LangServe\n\nUse `langserve` when you need to expose a LangChain `Runnable` as HTTP endpoints on top of FastAPI and call it from Python or JavaScript clients.\n\nIt is most useful for:\n\n- internal tools that already use LangChain `Runnable` graphs\n- thin API wrappers around a prompt, retriever, or chain\n- teams that want a built-in playground and schema endpoints for a runnable\n\nFor new greenfield deployments, the maintainers now recommend **LangGraph Platform** instead of LangServe. Keep using `langserve` only if you already depend on it or specifically want its FastAPI route model.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.3.3`, so the version used here matches current upstream as of 2026-03-12.\n- The `langchain-ai/langserve` repository is archived. The archive banner on GitHub says it was archived on **March 10, 2026**.\n- The maintainer migration guide says new users should use LangGraph Platform and migrate off LangServe over time.\n- The docs URL now redirects into the general LangChain documentation overview instead of a maintained LangServe-specific doc tree. For practical usage, the archived repository README and migration guide are the canonical maintainer sources.\n- `langserve>=0.3` supports Pydantic 2 fully.\n- If you combine LangServe with older LangChain packages, watch the Pydantic boundary carefully:\n  - with `langchain-core<0.3`, keep `pydantic==1.10.17`\n  - do not mix Pydantic 1 and 2 namespaces inside the same FastAPI app unless you have verified the OpenAPI behavior you need\n- The README notes that FastAPI cannot generate OpenAPI docs for LangServe invoke/batch/stream endpoints when LangServe uses Pydantic 2 but other FastAPI routes still use Pydantic 1 models. Upgrading to `langchain-core>=0.3` is the clean path.\n\n## Install\n\nInstall the package plus the web server pieces explicitly:\n\n```bash\npython -m pip install \"langserve==0.3.3\" fastapi uvicorn\n```\n\nIf you want the package's convenience extras from the maintainer README:\n\n```bash\npython -m pip install \"langserve[all]==0.3.3\"\n```\n\nWhat you still need to choose separately:\n\n- your runnable implementation, often from `langchain-core`\n- any provider packages such as model integrations\n- deployment runtime such as `uvicorn` or another ASGI server\n\n## Minimal Server Setup\n\nThe core server API is `add_routes(app, runnable, path=...)`.\n\n```python\nfrom fastapi import FastAPI\nfrom langchain_core.runnables import RunnableLambda\nfrom langserve import add_routes\n\ndef shout(text: str) -> str:\n    return text.upper()\n\napp = FastAPI(title=\"LangServe Example\")\nrunnable = RunnableLambda(shout)\n\nadd_routes(app, runnable, path=\"/shout\")\n```\n\nRun it:\n\n```bash\nuvicorn server:app --reload\n```\n\nThat route mount creates these useful endpoints under `/shout`:\n\n- `POST /invoke`\n- `POST /batch`\n- `POST /stream`\n- `POST /stream_log`\n- `POST /astream_events`\n- `GET /input_schema`\n- `GET /output_schema`\n- `GET /config_schema`\n- `GET /playground/`\n\n## Remote Client Usage\n\nUse `RemoteRunnable` when application code should call a LangServe deployment like a normal runnable.\n\n```python\nfrom langserve import RemoteRunnable\n\nremote = RemoteRunnable(\"http://localhost:8000/shout/\")\n\nprint(remote.invoke(\"hello\"))\nprint(remote.batch([\"one\", \"two\"]))\n```\n\nStreaming works through the same client object:\n\n```python\nfrom langserve import RemoteRunnable\n\nremote = RemoteRunnable(\"http://localhost:8000/shout/\")\n\nfor chunk in remote.stream(\"stream me\"):\n    print(chunk)\n```\n\nUse the remote client instead of hand-building JSON requests unless you are integrating from a non-LangChain HTTP client.\n\n## Serving Structured Inputs\n\nIn real apps, the runnable usually takes structured input rather than a single string. Keep the example schema explicit so the generated endpoint contracts stay predictable.\n\n```python\nfrom typing import TypedDict\n\nfrom fastapi import FastAPI\nfrom langchain_core.runnables import RunnableLambda\nfrom langserve import add_routes\n\nclass JokeInput(TypedDict):\n    topic: str\n\ndef make_joke(data: JokeInput) -> str:\n    topic = data[\"topic\"]\n    return f\"Why did the {topic} cross the road? To get to the runnable.\"\n\napp = FastAPI(title=\"Joke Service\")\nrunnable = RunnableLambda(make_joke)\n\nadd_routes(app, runnable, path=\"/joke\", input_type=JokeInput)\n```\n\nPractical note:\n\n- `langserve` only exposes the runnable boundary.\n- Secrets, model credentials, and provider-specific setup belong to the underlying code inside the runnable, not to LangServe itself.\n\n## Route Configuration\n\nThe most important `add_routes(...)` knobs for production work are:\n\n- `path`: mount point for the runnable\n- `input_type` and `output_type`: stabilize schemas when automatic inference is too loose\n- `config_keys`: explicitly allow only the client-configurable runnable config keys you want exposed\n- `enabled_endpoints`: reduce the surface area if you do not want every generated endpoint\n- `disabled_endpoints`: selectively turn off generated endpoints\n- `playground_type`: use `\"chat\"` for chat-style playground behavior when the input shape matches the README requirements\n\nUse explicit schemas when the runnable input is complex:\n\n```python\nfrom typing import TypedDict\n\nfrom fastapi import FastAPI\nfrom langserve import add_routes\n\nclass JokeInput(TypedDict):\n    topic: str\n\napp = FastAPI()\n\nadd_routes(\n    app,\n    runnable,\n    path=\"/joke\",\n    input_type=JokeInput,\n)\n```\n\n## Browser Access And CORS\n\nIf the playground or a browser client runs on a different origin than the API, add FastAPI CORS middleware. The maintainer README explicitly calls this out.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\n\napp = FastAPI()\n\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"http://localhost:3000\"],\n    allow_credentials=True,\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n    expose_headers=[\"*\"],\n)\n```\n\nWithout CORS, the playground or browser app may fail even though direct Python calls work.\n\n## Auth And Per-Request Config\n\nLangServe does not provide a package-level auth system. Treat auth and authorization as FastAPI concerns.\n\nUse these boundaries:\n\n- authenticate requests with FastAPI dependencies, middleware, or a gateway in front of the app\n- keep secrets and tenant selection server-side\n- only expose client-settable config through `config_keys`\n- use `per_req_config_modifier` to derive runnable config from the authenticated request\n\nThe `add_routes(...)` source defines `per_req_config_modifier` as a callable that receives `(config, request)` and returns the config dict used for that request.\n\nPattern to follow:\n\n```python\nfrom fastapi import FastAPI, Request\nfrom langserve import add_routes\n\ndef attach_request_config(config: dict, request: Request) -> dict:\n    user_id = request.headers.get(\"x-user-id\")\n    if user_id:\n        configurable = dict(config.get(\"configurable\", {}))\n        configurable[\"user_id\"] = user_id\n        config = dict(config)\n        config[\"configurable\"] = configurable\n    return config\n\nadd_routes(\n    app,\n    runnable,\n    path=\"/secure-runnable\",\n    config_keys=[\"configurable\"],\n    per_req_config_modifier=attach_request_config,\n)\n```\n\nDo not let clients directly choose sensitive config such as provider API keys, internal datastore selectors, or unrestricted tracing flags.\n\n## LangSmith Feedback And Trace Links\n\nLangServe can expose feedback and public trace link endpoints for the playground, but the README treats these as optional LangSmith-integrated features.\n\nTypical environment variables for that path are:\n\n```bash\nexport LANGCHAIN_TRACING_V2=true\nexport LANGCHAIN_PROJECT=\"your-project\"\nexport LANGCHAIN_API_KEY=\"ls__...\"\n```\n\nSecurity note from the maintainer README:\n\n- do not enable `enable_public_trace_link_endpoint=True` on a public internet-facing app\n- public trace links can expose internal chain data and intermediate steps\n\n## Common Pitfalls\n\n- The old LangServe examples use older LangChain import paths in places. Validate the runnable's provider imports against the current packages in your own project.\n- `RemoteRunnable` should point at the runnable base path, for example `http://localhost:8000/joke/`, not directly at `/invoke`.\n- If browser calls fail but Python calls succeed, check CORS before debugging the runnable itself.\n- If OpenAPI docs look broken in mixed FastAPI apps, audit your Pydantic 1 versus 2 usage first.\n- If you want a smaller public surface, disable unused generated endpoints instead of exposing every route by default.\n- The package is archived, so treat third-party blog posts with caution and prefer the archived maintainer README plus PyPI metadata.\n\n## Canonical Sources\n\n- PyPI package page: `https://pypi.org/project/langserve/`\n- Archived maintainer repository and README: `https://github.com/langchain-ai/langserve`\n- Migration guide: `https://github.com/langchain-ai/langserve/blob/main/MIGRATION.md`\n- Docs URL now redirecting away from LangServe-specific docs: `https://python.langchain.com/docs/langserve/`\n"
  },
  {
    "path": "content/langsmith/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LangSmith 0.7.16 package guide for tracing, evaluation, and testing in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.16\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"langsmith,python,llm,observability,tracing,evaluation,testing\"\n---\n\n# LangSmith Python Package Guide\n\n## Install\n\nBase install:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"langsmith==0.7.16\"\n```\n\nUseful extras:\n\n```bash\npip install \"langsmith[pytest]==0.7.16\"\npip install \"langsmith[otel]==0.7.16\"\n```\n\n- `pytest` adds richer test output and request-caching helpers for the LangSmith pytest integration.\n- `otel` lets LangSmith receive OpenTelemetry spans from already-instrumented apps.\n\n## Auth And Configuration\n\nMinimal environment setup for the hosted service:\n\n```bash\nexport LANGSMITH_API_KEY=\"YOUR_API_KEY\"\nexport LANGSMITH_TRACING=\"true\"\nexport LANGSMITH_PROJECT=\"my-app\"\n```\n\nAdditional environment variables:\n\n```bash\n# Set this only when your API key can access multiple workspaces.\nexport LANGSMITH_WORKSPACE_ID=\"YOUR_WORKSPACE_ID\"\n\n# Set this for the EU SaaS region or a self-hosted deployment.\nexport LANGSMITH_ENDPOINT=\"https://api.smith.langchain.com\"\n```\n\nNotes:\n\n- `LANGSMITH_TRACING=true` is what actually turns automatic tracing on for decorators and wrapped model clients.\n- If `LANGSMITH_PROJECT` is omitted, traces go to the default project.\n- For EU accounts, use the EU API endpoint instead of the US default.\n- Avoid hardcoding the API key into source code. Use environment variables or your app's secret manager.\n\nIf environment variables are not practical, configure a client directly:\n\n```python\nfrom langsmith import Client\n\nclient = Client(\n    api_key=\"YOUR_API_KEY\",\n    api_url=\"https://api.smith.langchain.com\",\n    workspace_id=\"YOUR_WORKSPACE_ID\",  # omit when not needed\n)\n```\n\n## Core Tracing Patterns\n\n### Trace Plain Python Functions\n\nUse `@traceable` for normal Python functions. This is the simplest way to get spans for custom application logic.\n\n```python\nfrom langsmith import traceable\n\n@traceable(run_type=\"chain\", name=\"answer_question\")\ndef answer_question(question: str) -> dict[str, str]:\n    answer = question.upper()\n    return {\"answer\": answer}\n\nresult = answer_question(\"Where is the trace?\")\nprint(result)\n```\n\nImportant:\n\n- Decorated functions are only sent to LangSmith when tracing is enabled with env vars or `tracing_context`.\n- Use `run_type` to make traces easier to read in the UI (`chain`, `tool`, `llm`, and so on).\n\n### Wrap Supported Model SDKs\n\nFor provider SDKs that LangSmith knows how to wrap, wrap the client once and keep the rest of your code normal.\n\n```python\nfrom openai import OpenAI\n\nfrom langsmith import traceable\nfrom langsmith.wrappers import wrap_openai\n\nopenai_client = wrap_openai(OpenAI())\n\n@traceable(name=\"chat_pipeline\")\ndef chat_pipeline(question: str) -> str:\n    response = openai_client.chat.completions.create(\n        model=\"gpt-4.1-mini\",\n        messages=[{\"role\": \"user\", \"content\": question}],\n    )\n    return response.choices[0].message.content or \"\"\n\nprint(chat_pipeline(\"Summarize LangSmith in one sentence.\"))\n```\n\nPitfall: wrapping the client does not bypass configuration. You still need `LANGSMITH_TRACING=true` or a `tracing_context(enabled=True)` block.\n\n### Enable Tracing Without Environment Variables\n\nUse `tracing_context` when you want explicit per-block control or cannot rely on process-wide environment variables.\n\n```python\nfrom langsmith import Client, traceable, tracing_context\n\nclient = Client(api_key=\"YOUR_API_KEY\")\n\n@traceable(run_type=\"tool\")\ndef normalize(text: str) -> str:\n    return text.strip().lower()\n\nwith tracing_context(\n    client=client,\n    project_name=\"manual-config\",\n    enabled=True,\n    tags=[\"local-dev\"],\n):\n    print(normalize(\"  LangSmith  \"))\n```\n\nThis pattern is useful in notebooks, unit tests, local scripts, and serverless code where environment setup is awkward.\n\n### Manual Span Control With `RunTree`\n\nUse `RunTree` when you need explicit parent/child span control, need to trace code that cannot use decorators, or need to post and patch runs manually.\n\n```python\nfrom langsmith.run_trees import RunTree\n\nrun = RunTree(\n    name=\"fetch-context\",\n    run_type=\"tool\",\n    inputs={\"query\": \"langsmith\"},\n)\nrun.post()\n\ntry:\n    output = {\"documents\": 3}\n    run.end(outputs=output)\nfinally:\n    run.patch()\n```\n\nFor nested spans, create child runs from the parent `RunTree` instead of creating unrelated top-level runs.\n\n## Datasets And Evaluation\n\nLangSmith datasets are the basis for offline evaluation, regression tracking, and reproducible test suites.\n\nCreate a dataset and seed examples programmatically:\n\n```python\nfrom langsmith import Client\n\nclient = Client()\n\ndataset = client.create_dataset(\n    dataset_name=\"qa-smoke\",\n    description=\"Small regression set for answer generation\",\n)\n\nclient.create_examples(\n    dataset_id=dataset.id,\n    examples=[\n        {\n            \"inputs\": {\"question\": \"What is the capital of France?\"},\n            \"outputs\": {\"answer\": \"Paris\"},\n            \"metadata\": {\"source\": \"seed\"},\n        },\n        {\n            \"inputs\": {\"question\": \"2 + 2\"},\n            \"outputs\": {\"answer\": \"4\"},\n            \"metadata\": {\"source\": \"seed\"},\n        },\n    ],\n)\n```\n\nRecommended workflow:\n\n1. Create or sync a dataset with `Client`.\n2. Keep example `inputs` and reference `outputs` small and deterministic.\n3. Run `evaluate()` or `aevaluate()` against that dataset with your application callable and evaluator functions.\n4. Inspect the experiment in LangSmith before promoting model or prompt changes.\n\nPractical note: dataset changes create a new dataset version. If you care about experiment reproducibility, avoid mutating a shared dataset casually.\n\n## Testing Integration\n\nThe SDK includes a pytest plugin by default. The `pytest` extra adds richer output and request caching.\n\nMinimal test instrumentation:\n\n```python\nimport pytest\nfrom langsmith import testing as t\n\n@pytest.mark.langsmith\ndef test_translation():\n    t.log_inputs({\"text\": \"hola\"})\n    t.log_reference_outputs({\"translation\": \"hello\"})\n    t.log_outputs({\"translation\": \"hello\"})\n    assert True\n```\n\nRun with a named suite:\n\n```bash\nexport LANGSMITH_TEST_SUITE=\"smoke\"\npytest tests/\n```\n\nUseful test settings:\n\n- `LANGSMITH_TEST_TRACKING=false` disables LangSmith reporting while leaving the test code intact.\n- `LANGSMITH_TEST_CACHE=tests/cassettes` enables request caching for slower or non-deterministic external calls.\n- Use `pytest --langsmith-output` for rich console output. The older `--output=langsmith` form only applies to much older SDK versions.\n\n## Sensitive Data Controls\n\nIf traces may contain secrets or user content, use the SDK's masking controls instead of disabling tracing entirely.\n\nAvailable options include:\n\n- Environment-based hiding for inputs and outputs.\n- `Client(...)` masking hooks such as `hide_inputs`, `hide_outputs`, and `hide_metadata`.\n- Selective tracing scopes with `tracing_context(enabled=False)` around code that should never emit traces.\n\nPrefer masking over manual string scrubbing inside business logic.\n\n## Async And OpenTelemetry\n\n- Use `AsyncClient` if your app already interacts with the LangSmith API from async code and you want to avoid wrapping sync client calls in executors.\n- If your app already emits OpenTelemetry spans, install `langsmith[otel]` and enable LangSmith's OTEL bridge instead of duplicating instrumentation.\n- The OTEL setup docs require `langsmith>=0.3.18` and recommend `>=0.4.25`; `0.7.16` satisfies that guidance.\n\n## Common Pitfalls\n\n- `Client()` configures access to the LangSmith API. It does not replace model providers such as OpenAI or Anthropic.\n- Wrapped clients still require tracing to be enabled. A wrapped client alone does not send traces.\n- The web app URL (`smith.langchain.com`) and the API endpoint (`api.smith.langchain.com`) are different surfaces.\n- `LANGSMITH_WORKSPACE_ID` is only needed when one API key can access more than one workspace.\n- The hosted docs are not version-pinned per release. For `0.7.16`, prefer features already reflected in the current tracing, testing, and evaluation guides and avoid copying stale third-party snippets.\n\n## Version-Sensitive Notes For `0.7.16`\n\n- `0.7.16` is the current PyPI release reflected in the upstream package metadata as of 2026-03-12.\n- Python 3.9 is not supported. Use Python 3.10 or newer.\n- The pytest plugin is bundled with the SDK, but richer pytest output and caching helpers come from the `pytest` extra.\n- OpenTelemetry support guidance in the official docs applies to this version because `0.7.16` is newer than the documented minimums.\n"
  },
  {
    "path": "content/launchdarkly/docs/feature-flags/javascript/DOC.md",
    "content": "---\nname: feature-flags\ndescription: \"LaunchDarkly Node.js Server SDK for feature flag management and experimentation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.10.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"launchdarkly,feature-flags,toggles,experimentation,rollout\"\n---\n\n# LaunchDarkly Node.js Server SDK\n\n## Golden Rule\n\n**Always use `@launchdarkly/node-server-sdk` for server-side Node.js applications.**\n\n```bash\nnpm install @launchdarkly/node-server-sdk\n```\n\nDo NOT use:\n- `launchdarkly-node-server-sdk` (deprecated, last updated 2021)\n- `launchdarkly-node-client-sdk` (client-side only, different use case)\n- Any unofficial or third-party LaunchDarkly packages\n\nThe official package is `@launchdarkly/node-server-sdk` maintained by LaunchDarkly.\n\n---\n\n## Installation\n\n```bash\nnpm install @launchdarkly/node-server-sdk\n```\n\nOptional observability plugin (requires v9.10+):\n\n```bash\nnpm install @launchdarkly/observability-node\n```\n\n---\n\n## Environment Variables\n\nSet your SDK key as an environment variable:\n\n```bash\nexport LAUNCHDARKLY_SDK_KEY=\"sdk-key-123abc\"\n```\n\n---\n\n## Initialization\n\n### Basic Initialization\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY);\n\n// Wait for initialization before evaluating flags\nawait client.waitForInitialization({ timeout: 10 });\n```\n\n### With Configuration Options\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\n\nconst options = {\n  timeout: 10,\n  capacity: 1000,\n  flushInterval: 30,\n  stream: true,\n  allAttributesPrivate: false,\n  privateAttributes: ['email', 'ssn'],\n  offline: false,\n  diagnosticOptOut: false,\n  wrapperName: 'my-wrapper',\n  wrapperVersion: '1.0.0'\n};\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, options);\nawait client.waitForInitialization({ timeout: 10 });\n```\n\n### With Observability Plugin\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\nimport { Observability } from '@launchdarkly/observability-node';\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  plugins: [new Observability()]\n});\n\nawait client.waitForInitialization({ timeout: 10 });\n```\n\n### Singleton Pattern\n\n**Critical:** Make the LDClient a singleton. Do NOT create multiple instances per request.\n\n```javascript\n// app.js or server initialization\nimport { init } from '@launchdarkly/node-server-sdk';\n\nlet ldClient;\n\nasync function initializeLaunchDarkly() {\n  ldClient = init(process.env.LAUNCHDARKLY_SDK_KEY);\n  await ldClient.waitForInitialization({ timeout: 10 });\n  return ldClient;\n}\n\nexport function getLDClient() {\n  if (!ldClient) {\n    throw new Error('LaunchDarkly client not initialized');\n  }\n  return ldClient;\n}\n\n// Initialize once at app startup\nawait initializeLaunchDarkly();\n```\n\n### Error Handling During Initialization\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY);\n\nclient.once('ready', () => {\n  console.log('LaunchDarkly client initialized successfully');\n});\n\nclient.once('failed', () => {\n  console.error('LaunchDarkly client failed to initialize');\n});\n\ntry {\n  await client.waitForInitialization({ timeout: 10 });\n  console.log('Client ready');\n} catch (error) {\n  console.error('Initialization timeout:', error);\n  // Client will still work but may return default values\n}\n```\n\n---\n\n## Contexts\n\n### Simple User Context\n\n```javascript\nconst context = {\n  kind: 'user',\n  key: 'user-key-123abc',\n  name: 'Sandy Smith',\n  email: 'sandy@example.com'\n};\n```\n\n### Context with Custom Attributes\n\n```javascript\nconst context = {\n  kind: 'user',\n  key: 'user-key-123abc',\n  name: 'Sandy Smith',\n  email: 'sandy@example.com',\n  plan: 'premium',\n  betaTester: true,\n  customAttribute: 'custom-value'\n};\n```\n\n### Anonymous Context\n\n```javascript\nconst context = {\n  kind: 'user',\n  key: 'anonymous-user-123',\n  anonymous: true\n};\n```\n\n### Multi-Context (Multiple Kinds)\n\n```javascript\nconst multiContext = {\n  kind: 'multi',\n  user: {\n    key: 'user-key-123',\n    name: 'Sandy'\n  },\n  organization: {\n    key: 'org-key-456',\n    name: 'Acme Corp'\n  },\n  device: {\n    key: 'device-key-789',\n    platform: 'iOS'\n  }\n};\n```\n\n### Private Attributes\n\nMark specific attributes as private (not sent to LaunchDarkly):\n\n```javascript\nconst context = {\n  kind: 'user',\n  key: 'user-key-123abc',\n  name: 'Sandy Smith',\n  email: 'sandy@example.com',\n  ssn: '123-45-6789',\n  _meta: {\n    privateAttributes: ['email', 'ssn']\n  }\n};\n```\n\n---\n\n## Flag Evaluation\n\n### Boolean Flag\n\n```javascript\nconst showFeature = await client.variation('flag-key-123abc', context, false);\n\nif (showFeature) {\n  // Feature enabled\n} else {\n  // Feature disabled\n}\n```\n\n### String Flag\n\n```javascript\nconst theme = await client.variation('theme-flag', context, 'light');\n\nconsole.log(`User theme: ${theme}`); // 'dark' or 'light'\n```\n\n### Number Flag\n\n```javascript\nconst maxItems = await client.variation('max-items', context, 10);\n\nconsole.log(`Max items: ${maxItems}`); // e.g., 50\n```\n\n### JSON Flag\n\n```javascript\nconst config = await client.variation('config-flag', context, {\n  timeout: 30,\n  retries: 3\n});\n\nconsole.log(`Timeout: ${config.timeout}, Retries: ${config.retries}`);\n```\n\n### Callback Style (Legacy)\n\n```javascript\nclient.variation('flag-key-123abc', context, false, (err, showFeature) => {\n  if (err) {\n    console.error('Error evaluating flag:', err);\n    return;\n  }\n\n  if (showFeature) {\n    // Feature enabled\n  }\n});\n```\n\n### Synchronous Variation (After Initialization)\n\n```javascript\n// Only use after client is fully initialized\nconst showFeature = client.variation('flag-key-123abc', context, false);\n```\n\n---\n\n## Flag Evaluation with Details\n\n### Get Evaluation Reason\n\n```javascript\nconst result = await client.variationDetail('flag-key-123abc', context, false);\n\nconsole.log('Value:', result.value);\nconsole.log('Variation Index:', result.variationIndex);\nconsole.log('Reason:', result.reason);\n```\n\n### Reason Object Structure\n\n```javascript\nconst result = await client.variationDetail('flag-key-123abc', context, false);\n\n// result.reason can be:\n// { kind: 'OFF' }\n// { kind: 'FALLTHROUGH' }\n// { kind: 'TARGET_MATCH' }\n// { kind: 'RULE_MATCH', ruleIndex: 0, ruleId: 'rule-id' }\n// { kind: 'PREREQUISITE_FAILED', prerequisiteKey: 'other-flag' }\n// { kind: 'ERROR', errorKind: 'MALFORMED_FLAG' }\n```\n\n### Using Evaluation Details for Debugging\n\n```javascript\nconst result = await client.variationDetail('experiment-flag', context, 'control');\n\nif (result.reason.kind === 'ERROR') {\n  console.error('Flag evaluation error:', result.reason.errorKind);\n} else if (result.reason.kind === 'RULE_MATCH') {\n  console.log('Matched rule:', result.reason.ruleIndex);\n} else if (result.reason.kind === 'FALLTHROUGH') {\n  console.log('Using fallthrough variation');\n}\n\nconsole.log('Serving variation:', result.value);\n```\n\n---\n\n## All Flags State\n\n### Get All Flags for a Context\n\n```javascript\nconst state = await client.allFlagsState(context);\n\nconst allFlags = state.allValues();\nconsole.log('All flags:', allFlags);\n// { 'flag-1': true, 'flag-2': 'value', 'flag-3': 42 }\n```\n\n### For Client-Side Bootstrapping\n\n```javascript\nconst state = await client.allFlagsState(context, {\n  clientSideOnly: true,\n  withReasons: true,\n  detailsOnlyForTrackedFlags: false\n});\n\nconst bootstrapData = state.toJSON();\n\n// Send to client-side\nres.json({\n  flags: bootstrapData\n});\n```\n\n### Check If State Is Valid\n\n```javascript\nconst state = await client.allFlagsState(context);\n\nif (state.valid) {\n  console.log('Successfully retrieved all flags');\n  const flags = state.allValues();\n} else {\n  console.error('Failed to retrieve flags');\n}\n```\n\n---\n\n## Event Tracking\n\n### Track Custom Event\n\n```javascript\nclient.track('button-clicked', context);\n```\n\n### Track Event with Data\n\n```javascript\nclient.track('purchase-completed', context, {\n  itemId: 'item-123',\n  price: 29.99,\n  currency: 'USD'\n});\n```\n\n### Track Event with Numeric Metric\n\n```javascript\nclient.track('purchase-completed', context, {\n  itemId: 'item-123'\n}, 29.99);\n```\n\n### Identify Context\n\nSend context attributes to LaunchDarkly for targeting:\n\n```javascript\nclient.identify(context);\n```\n\n### Flush Events\n\nForce immediate delivery of pending events:\n\n```javascript\nawait client.flush();\n```\n\n### Auto-Flush on Shutdown\n\n```javascript\nprocess.on('SIGTERM', async () => {\n  await client.flush();\n  await client.close();\n  process.exit(0);\n});\n```\n\n---\n\n## Data Modes\n\n### Streaming Mode (Default)\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  stream: true\n});\n```\n\n### Polling Mode\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  stream: false,\n  pollInterval: 60 // seconds\n});\n```\n\n### Offline Mode\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  offline: true\n});\n\n// All flags return default values\nconst result = await client.variation('flag-key', context, false);\n// Will always return false (the default)\n```\n\n---\n\n## Relay Proxy\n\n### Using LaunchDarkly Relay Proxy\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  baseUri: 'http://relay-proxy.example.com',\n  streamUri: 'http://relay-proxy.example.com',\n  eventsUri: 'http://relay-proxy.example.com'\n});\n```\n\n### Daemon Mode\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  useLdd: true,\n  featureStore: myFeatureStore\n});\n```\n\n---\n\n## Feature Stores\n\n### Redis Feature Store\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\nimport { RedisFeatureStore } from '@launchdarkly/node-server-sdk-redis';\n\nconst redisStore = RedisFeatureStore({\n  redisOpts: {\n    host: 'localhost',\n    port: 6379\n  },\n  prefix: 'ld',\n  cacheTTL: 30\n});\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  featureStore: redisStore\n});\n```\n\n### DynamoDB Feature Store\n\n```javascript\nimport { DynamoDBFeatureStore } from '@launchdarkly/node-server-sdk-dynamodb';\n\nconst dynamoStore = DynamoDBFeatureStore('feature-flags-table', {\n  cacheTTL: 30\n});\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  featureStore: dynamoStore\n});\n```\n\n---\n\n## Bootstrapping\n\n### File-Based Data Source\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\nimport { FileDataSource } from '@launchdarkly/node-server-sdk-file';\n\nconst fileSource = FileDataSource({\n  paths: ['./flags.json']\n});\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  updateProcessor: fileSource\n});\n```\n\n### flags.json Format\n\n```json\n{\n  \"flags\": {\n    \"flag-key-123abc\": {\n      \"key\": \"flag-key-123abc\",\n      \"on\": true,\n      \"variations\": [true, false],\n      \"fallthrough\": {\n        \"variation\": 0\n      }\n    }\n  },\n  \"segments\": {}\n}\n```\n\n---\n\n## Subscribing to Flag Changes\n\n### Listen for Specific Flag Changes\n\n```javascript\nclient.on('update:flag-key-123abc', (newValue, oldValue) => {\n  console.log(`Flag changed from ${oldValue} to ${newValue}`);\n});\n```\n\n### Listen for All Flag Updates\n\n```javascript\nclient.on('update', (settings) => {\n  console.log('Flags updated');\n});\n```\n\n---\n\n## Big Segments\n\n### Configure Big Segments Store\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\nimport { RedisBigSegmentStore } from '@launchdarkly/node-server-sdk-redis';\n\nconst bigSegmentStore = RedisBigSegmentStore({\n  redisOpts: {\n    host: 'localhost',\n    port: 6379\n  },\n  prefix: 'big-segments'\n});\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  bigSegments: {\n    store: bigSegmentStore,\n    contextCacheSize: 1000,\n    contextCacheTime: 5,\n    statusPollInterval: 5,\n    staleAfter: 120\n  }\n});\n```\n\n### Check Big Segments Status\n\n```javascript\nconst result = await client.variationDetail('segment-flag', context, false);\n\nif (result.reason.bigSegmentsStatus === 'STALE') {\n  console.warn('Big segments data is stale');\n}\n```\n\n---\n\n## Hooks\n\n### Create a Hook\n\n```javascript\nclass LoggingHook {\n  getMetadata() {\n    return { name: 'logging-hook' };\n  }\n\n  beforeEvaluation(hookContext, data) {\n    console.log('Evaluating flag:', hookContext.flagKey);\n    return data;\n  }\n\n  afterEvaluation(hookContext, data, detail) {\n    console.log('Flag result:', detail.value);\n    return data;\n  }\n}\n```\n\n### Register Hook via Configuration\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  hooks: [new LoggingHook()]\n});\n```\n\n### Add Hook at Runtime\n\n```javascript\nconst hook = new LoggingHook();\nclient.addHook(hook);\n```\n\n---\n\n## Migrations\n\n### Create Migration\n\n```javascript\nimport { createMigration } from '@launchdarkly/node-server-sdk';\n\nconst migration = createMigration(client, {\n  execution: 'parallel',\n  latencyTracking: true,\n  errorTracking: true,\n\n  readOld: async (payload) => {\n    return await oldDatabase.read(payload.id);\n  },\n\n  readNew: async (payload) => {\n    return await newDatabase.read(payload.id);\n  },\n\n  writeOld: async (payload) => {\n    await oldDatabase.write(payload.id, payload.data);\n  },\n\n  writeNew: async (payload) => {\n    await newDatabase.write(payload.id, payload.data);\n  },\n\n  check: (oldValue, newValue) => {\n    return JSON.stringify(oldValue) === JSON.stringify(newValue);\n  }\n});\n```\n\n### Execute Migration Read\n\n```javascript\nconst stage = await client.variation('migration-flag', context, 'off');\n\nconst result = await migration.read('migration-flag', context, stage, {\n  id: 'record-123'\n});\n\nif (result.isSuccessful()) {\n  console.log('Data:', result.getValue());\n} else {\n  console.error('Migration read failed');\n}\n```\n\n### Execute Migration Write\n\n```javascript\nconst stage = await client.variation('migration-flag', context, 'off');\n\nconst result = await migration.write('migration-flag', context, stage, {\n  id: 'record-123',\n  data: { name: 'Example' }\n});\n\nif (result.isSuccessful()) {\n  console.log('Write completed');\n}\n```\n\n### Migration Stages\n\n- `'off'` - Use old implementation only\n- `'dualwrite'` - Write to both, read from old\n- `'shadow'` - Read from both, write to both, use old for responses\n- `'live'` - Read from both, write to both, use new for responses\n- `'rampdown'` - Write to both, read from new\n- `'complete'` - Use new implementation only\n\n---\n\n## HTTP Configuration\n\n### Configure Proxy\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  proxyOptions: {\n    host: 'proxy.example.com',\n    port: 8080,\n    auth: 'username:password'\n  }\n});\n```\n\n### Custom TLS Options\n\n```javascript\nimport * as fs from 'fs';\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  tlsOptions: {\n    ca: fs.readFileSync('./ca-cert.pem'),\n    cert: fs.readFileSync('./client-cert.pem'),\n    key: fs.readFileSync('./client-key.pem')\n  }\n});\n```\n\n### Custom HTTP Headers\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  requestHeaderTransform: (headers) => {\n    headers['X-Custom-Header'] = 'custom-value';\n    return headers;\n  }\n});\n```\n\n---\n\n## Application Metadata\n\n### Set Application Info\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  application: {\n    id: 'my-app',\n    version: '1.2.3',\n    name: 'My Application',\n    versionName: 'v1.2.3-beta'\n  }\n});\n```\n\n---\n\n## Secure Mode\n\n### Generate Secure Mode Hash\n\n```javascript\nimport { createHmac } from 'crypto';\n\nfunction generateSecureModeHash(sdkKey, contextKey) {\n  return createHmac('sha256', sdkKey)\n    .update(contextKey)\n    .digest('hex');\n}\n\nconst hash = generateSecureModeHash(\n  process.env.LAUNCHDARKLY_SDK_KEY,\n  context.key\n);\n\n// Send hash to client-side\nres.json({ hash });\n```\n\n---\n\n## Testing\n\n### Using Test Data Source\n\n```javascript\nimport { init, TestData } from '@launchdarkly/node-server-sdk';\n\nconst td = TestData();\n\ntd.update(td.flag('flag-key-123abc')\n  .variations(true, false)\n  .variationForAll(true)\n);\n\nconst client = init('sdk-key', {\n  updateProcessor: td.getFactory()\n});\n\n// Update flag during test\ntd.update(td.flag('flag-key-123abc').variationForAll(false));\n```\n\n### Mock Client for Unit Tests\n\n```javascript\nconst mockClient = {\n  variation: jest.fn().mockResolvedValue(true),\n  variationDetail: jest.fn().mockResolvedValue({\n    value: true,\n    variationIndex: 0,\n    reason: { kind: 'OFF' }\n  }),\n  track: jest.fn(),\n  identify: jest.fn(),\n  flush: jest.fn().mockResolvedValue(undefined),\n  close: jest.fn().mockResolvedValue(undefined)\n};\n```\n\n---\n\n## Error Handling\n\n### Handle Initialization Errors\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY);\n\nclient.on('error', (error) => {\n  console.error('LaunchDarkly error:', error);\n});\n\ntry {\n  await client.waitForInitialization({ timeout: 10 });\n} catch (error) {\n  console.error('Initialization timeout');\n  // Client will still work with default values\n}\n```\n\n### Handle Evaluation Errors\n\n```javascript\nconst result = await client.variationDetail('flag-key', context, false);\n\nif (result.reason.kind === 'ERROR') {\n  switch (result.reason.errorKind) {\n    case 'MALFORMED_FLAG':\n      console.error('Flag configuration is invalid');\n      break;\n    case 'FLAG_NOT_FOUND':\n      console.error('Flag does not exist');\n      break;\n    case 'USER_NOT_SPECIFIED':\n      console.error('Context is invalid');\n      break;\n    case 'WRONG_TYPE':\n      console.error('Flag type mismatch');\n      break;\n    default:\n      console.error('Unknown error:', result.reason.errorKind);\n  }\n}\n```\n\n---\n\n## Logging\n\n### Custom Logger\n\n```javascript\nimport { BasicLogger } from '@launchdarkly/node-server-sdk';\n\nconst logger = BasicLogger.get();\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  logger: logger\n});\n```\n\n### Set Log Level\n\n```javascript\nimport { BasicLogger } from '@launchdarkly/node-server-sdk';\n\nconst logger = BasicLogger.get();\nlogger.setLevel('debug'); // 'debug', 'info', 'warn', 'error'\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  logger: logger\n});\n```\n\n### Custom Logger Implementation\n\n```javascript\nclass CustomLogger {\n  debug(message) {\n    console.log('[DEBUG]', message);\n  }\n\n  info(message) {\n    console.log('[INFO]', message);\n  }\n\n  warn(message) {\n    console.warn('[WARN]', message);\n  }\n\n  error(message) {\n    console.error('[ERROR]', message);\n  }\n}\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  logger: new CustomLogger()\n});\n```\n\n---\n\n## Complete Express.js Example\n\n```javascript\nimport express from 'express';\nimport { init } from '@launchdarkly/node-server-sdk';\n\nconst app = express();\nlet ldClient;\n\n// Initialize LaunchDarkly client\nasync function initLaunchDarkly() {\n  ldClient = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n    timeout: 10,\n    stream: true\n  });\n\n  await ldClient.waitForInitialization({ timeout: 10 });\n  console.log('LaunchDarkly initialized');\n}\n\n// Middleware to add LD client to request\napp.use((req, res, next) => {\n  req.ldClient = ldClient;\n  next();\n});\n\n// Route using feature flag\napp.get('/feature', async (req, res) => {\n  const context = {\n    kind: 'user',\n    key: req.headers['x-user-id'] || 'anonymous',\n    email: req.headers['x-user-email']\n  };\n\n  const showNewFeature = await ldClient.variation(\n    'new-feature-flag',\n    context,\n    false\n  );\n\n  if (showNewFeature) {\n    res.json({ feature: 'new', message: 'Welcome to the new feature!' });\n  } else {\n    res.json({ feature: 'old', message: 'Using legacy feature' });\n  }\n});\n\n// Track custom event\napp.post('/track-event', async (req, res) => {\n  const context = {\n    kind: 'user',\n    key: req.body.userId\n  };\n\n  ldClient.track('button-clicked', context, {\n    buttonId: req.body.buttonId\n  });\n\n  res.json({ success: true });\n});\n\n// Graceful shutdown\nprocess.on('SIGTERM', async () => {\n  console.log('Shutting down...');\n  await ldClient.flush();\n  await ldClient.close();\n  process.exit(0);\n});\n\n// Start server\nconst PORT = process.env.PORT || 3000;\n\ninitLaunchDarkly()\n  .then(() => {\n    app.listen(PORT, () => {\n      console.log(`Server running on port ${PORT}`);\n    });\n  })\n  .catch((error) => {\n    console.error('Failed to initialize LaunchDarkly:', error);\n    process.exit(1);\n  });\n```\n\n---\n\n## TypeScript Support\n\n### Type Definitions\n\n```typescript\nimport {\n  init,\n  LDClient,\n  LDContext,\n  LDOptions,\n  LDFlagValue,\n  LDEvaluationDetail\n} from '@launchdarkly/node-server-sdk';\n\nconst options: LDOptions = {\n  timeout: 10,\n  stream: true\n};\n\nconst client: LDClient = init(process.env.LAUNCHDARKLY_SDK_KEY!, options);\n\nconst context: LDContext = {\n  kind: 'user',\n  key: 'user-123',\n  name: 'Sandy'\n};\n\nconst value: LDFlagValue = await client.variation('flag-key', context, false);\n```\n\n### Typed Flag Values\n\n```typescript\ninterface FeatureConfig {\n  maxItems: number;\n  enabled: boolean;\n  theme: string;\n}\n\nconst config = await client.variation<FeatureConfig>(\n  'config-flag',\n  context,\n  { maxItems: 10, enabled: false, theme: 'light' }\n);\n\nconsole.log(config.maxItems); // Type-safe\n```\n\n---\n\n## OpenTelemetry Integration\n\n### Setup OpenTelemetry with LaunchDarkly\n\n```javascript\nimport { init } from '@launchdarkly/node-server-sdk';\nimport { Observability } from '@launchdarkly/observability-node';\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { PrometheusExporter } from '@opentelemetry/exporter-prometheus';\n\nconst sdk = new NodeSDK({\n  metricReader: new PrometheusExporter({\n    port: 9464\n  }),\n  instrumentations: [getNodeAutoInstrumentations()]\n});\n\nsdk.start();\n\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  plugins: [new Observability()]\n});\n```\n\n---\n\n## Private Attributes Configuration\n\n### Global Private Attributes\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  privateAttributes: ['email', 'ssn', 'address'],\n  allAttributesPrivate: false\n});\n```\n\n### All Attributes Private\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  allAttributesPrivate: true\n});\n```\n\n---\n\n## Diagnostics\n\n### Disable Diagnostic Events\n\n```javascript\nconst client = init(process.env.LAUNCHDARKLY_SDK_KEY, {\n  diagnosticOptOut: true\n});\n```\n\n---\n\n## Shutdown and Cleanup\n\n### Graceful Shutdown\n\n```javascript\nasync function shutdown() {\n  console.log('Flushing events...');\n  await client.flush();\n\n  console.log('Closing client...');\n  await client.close();\n\n  console.log('Shutdown complete');\n}\n\nprocess.on('SIGINT', shutdown);\nprocess.on('SIGTERM', shutdown);\n```\n\n### Check Initialization Status\n\n```javascript\nif (client.initialized()) {\n  console.log('Client is ready');\n} else {\n  console.log('Client is not initialized yet');\n}\n```\n"
  },
  {
    "path": "content/launchdarkly/docs/feature-flags/python/DOC.md",
    "content": "---\nname: feature-flags\ndescription: \"LaunchDarkly Python Server SDK for feature flag management and experimentation\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.12.3\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"launchdarkly,feature-flags,toggles,experimentation,rollout\"\n---\n\n# LaunchDarkly Python Server SDK\n\n## Golden Rule\n\n**Always use `launchdarkly-server-sdk` for server-side Python applications.**\n\n```bash\npip install launchdarkly-server-sdk\n```\n\nDo NOT use:\n- `launchdarkly-client` (deprecated, last updated 2019)\n- `launchdarkly-python-client` (unofficial package)\n- Any unofficial or third-party LaunchDarkly packages\n\nThe official package is `launchdarkly-server-sdk` maintained by LaunchDarkly.\n\nRequires Python 3.9 or higher (as of v9.12+).\n\n---\n\n## Installation\n\n```bash\npip install launchdarkly-server-sdk\n```\n\nOptional observability plugin (requires v9.12+):\n\n```bash\npip install launchdarkly-observability\n```\n\n---\n\n## Environment Variables\n\nSet your SDK key as an environment variable:\n\n```bash\nexport LAUNCHDARKLY_SDK_KEY=\"sdk-key-123abc\"\n```\n\n---\n\n## Initialization\n\n### Basic Initialization\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\nldclient.set_config(Config(os.environ['LAUNCHDARKLY_SDK_KEY']))\nclient = ldclient.get()\n\n# Wait for initialization\nif client.is_initialized():\n    print('LaunchDarkly client initialized')\nelse:\n    print('LaunchDarkly client failed to initialize')\n```\n\n### With Timeout\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\nldclient.set_config(Config(os.environ['LAUNCHDARKLY_SDK_KEY']))\nclient = ldclient.get()\n\n# Wait up to 10 seconds for initialization\nif client.wait_for_initialization(10):\n    print('Client initialized successfully')\nelse:\n    print('Client initialization timeout')\n```\n\n### With Configuration Options\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    stream=True,\n    connect_timeout=10,\n    read_timeout=15,\n    offline=False,\n    all_attributes_private=False,\n    private_attributes={'email', 'ssn'},\n    flush_interval=5,\n    poll_interval=30,\n    diagnostic_opt_out=False,\n    wrapper_name='my-wrapper',\n    wrapper_version='1.0.0'\n)\n\nldclient.set_config(config)\nclient = ldclient.get()\n```\n\n### With Observability Plugin\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nfrom ldobserve import ObservabilityPlugin\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    plugins=[ObservabilityPlugin()]\n)\n\nldclient.set_config(config)\nclient = ldclient.get()\n```\n\n### Singleton Pattern\n\n**Critical:** The `ldclient` module maintains a singleton. Use `ldclient.get()` to access the shared instance.\n\n```python\n# Initialize once at application startup\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\ndef initialize_launchdarkly():\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n\n    client = ldclient.get()\n    if not client.wait_for_initialization(10):\n        raise Exception('LaunchDarkly failed to initialize')\n\n    return client\n\n# Call once at startup\nclient = initialize_launchdarkly()\n\n# Access anywhere in application\ndef get_ld_client():\n    return ldclient.get()\n```\n\n### Error Handling During Initialization\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\ntry:\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n    client = ldclient.get()\n\n    if client.wait_for_initialization(10):\n        print('Client initialized successfully')\n    else:\n        print('Client initialization timeout - will use default values')\nexcept Exception as e:\n    print(f'Initialization error: {e}')\n```\n\n---\n\n## Contexts\n\n### Simple User Context\n\n```python\nfrom ldclient import Context\n\ncontext = Context.builder('user-key-123abc') \\\n    .name('Sandy Smith') \\\n    .build()\n```\n\n### Context with Custom Attributes\n\n```python\nfrom ldclient import Context\n\ncontext = Context.builder('user-key-123abc') \\\n    .name('Sandy Smith') \\\n    .set('email', 'sandy@example.com') \\\n    .set('plan', 'premium') \\\n    .set('betaTester', True) \\\n    .build()\n```\n\n### Simple Context (Shorthand)\n\n```python\nfrom ldclient import Context\n\n# Just a key (defaults to 'user' kind)\ncontext = Context.create('user-key-123abc')\n\n# With kind specified\ncontext = Context.create('org-key-456', 'organization')\n```\n\n### Anonymous Context\n\n```python\nfrom ldclient import Context\n\ncontext = Context.builder('anonymous-123') \\\n    .anonymous(True) \\\n    .build()\n```\n\n### Multi-Context (Multiple Kinds)\n\n```python\nfrom ldclient import Context\n\nuser_context = Context.builder('user-key-123') \\\n    .kind('user') \\\n    .name('Sandy') \\\n    .build()\n\norg_context = Context.builder('org-key-456') \\\n    .kind('organization') \\\n    .name('Acme Corp') \\\n    .build()\n\ndevice_context = Context.builder('device-key-789') \\\n    .kind('device') \\\n    .set('platform', 'iOS') \\\n    .build()\n\nmulti_context = Context.create_multi(user_context, org_context, device_context)\n```\n\n### Private Attributes\n\nMark specific attributes as private (not sent to LaunchDarkly):\n\n```python\nfrom ldclient import Context\n\ncontext = Context.builder('user-key-123abc') \\\n    .name('Sandy Smith') \\\n    .set('email', 'sandy@example.com') \\\n    .set('ssn', '123-45-6789') \\\n    .private('email', 'ssn') \\\n    .build()\n```\n\n### Context from Dictionary\n\n```python\nfrom ldclient import Context\n\ncontext_dict = {\n    'kind': 'user',\n    'key': 'user-key-123abc',\n    'name': 'Sandy Smith',\n    'email': 'sandy@example.com'\n}\n\ncontext = Context.from_dict(context_dict)\n```\n\n---\n\n## Flag Evaluation\n\n### Boolean Flag\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nshow_feature = client.variation('flag-key-123abc', context, False)\n\nif show_feature:\n    print('Feature enabled')\nelse:\n    print('Feature disabled')\n```\n\n### String Flag\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\ntheme = client.variation('theme-flag', context, 'light')\n\nprint(f'User theme: {theme}')  # 'dark' or 'light'\n```\n\n### Number Flag\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nmax_items = client.variation('max-items', context, 10)\n\nprint(f'Max items: {max_items}')  # e.g., 50\n```\n\n### JSON Flag\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nconfig = client.variation('config-flag', context, {\n    'timeout': 30,\n    'retries': 3\n})\n\nprint(f\"Timeout: {config['timeout']}, Retries: {config['retries']}\")\n```\n\n---\n\n## Flag Evaluation with Details\n\n### Get Evaluation Reason\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nresult = client.variation_detail('flag-key-123abc', context, False)\n\nprint('Value:', result.value)\nprint('Variation Index:', result.variation_index)\nprint('Reason:', result.reason)\n```\n\n### Reason Object Structure\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nresult = client.variation_detail('flag-key-123abc', context, False)\n\n# result.reason examples:\n# {'kind': 'OFF'}\n# {'kind': 'FALLTHROUGH'}\n# {'kind': 'TARGET_MATCH'}\n# {'kind': 'RULE_MATCH', 'ruleIndex': 0, 'ruleId': 'rule-id'}\n# {'kind': 'PREREQUISITE_FAILED', 'prerequisiteKey': 'other-flag'}\n# {'kind': 'ERROR', 'errorKind': 'MALFORMED_FLAG'}\n```\n\n### Using Evaluation Details for Debugging\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nresult = client.variation_detail('experiment-flag', context, 'control')\n\nif result.reason['kind'] == 'ERROR':\n    print(f\"Flag evaluation error: {result.reason['errorKind']}\")\nelif result.reason['kind'] == 'RULE_MATCH':\n    print(f\"Matched rule: {result.reason['ruleIndex']}\")\nelif result.reason['kind'] == 'FALLTHROUGH':\n    print('Using fallthrough variation')\n\nprint(f'Serving variation: {result.value}')\n```\n\n---\n\n## All Flags State\n\n### Get All Flags for a Context\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nstate = client.all_flags_state(context)\n\nif state.valid:\n    all_flags = state.to_values_map()\n    print('All flags:', all_flags)\n    # {'flag-1': True, 'flag-2': 'value', 'flag-3': 42}\n```\n\n### For Client-Side Bootstrapping\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nstate = client.all_flags_state(\n    context,\n    client_side_only=True,\n    with_reasons=True,\n    details_only_for_tracked_flags=False\n)\n\nif state.valid:\n    bootstrap_data = state.to_json_dict()\n    # Send to client-side\n    return {'flags': bootstrap_data}\n```\n\n### Get Individual Flag from State\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nstate = client.all_flags_state(context)\n\nflag_value = state.get_flag_value('flag-key-123abc')\nflag_reason = state.get_flag_reason('flag-key-123abc')\n\nprint(f'Value: {flag_value}')\nprint(f'Reason: {flag_reason}')\n```\n\n---\n\n## Event Tracking\n\n### Track Custom Event\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nclient.track('button-clicked', context)\n```\n\n### Track Event with Data\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nclient.track('purchase-completed', context, data={\n    'item_id': 'item-123',\n    'price': 29.99,\n    'currency': 'USD'\n})\n```\n\n### Track Event with Numeric Metric\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nclient.track('purchase-completed', context, data={\n    'item_id': 'item-123'\n}, metric_value=29.99)\n```\n\n### Identify Context\n\nSend context attributes to LaunchDarkly for targeting:\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\n\ncontext = Context.builder('user-key-123abc') \\\n    .name('Sandy Smith') \\\n    .set('email', 'sandy@example.com') \\\n    .build()\n\nclient.identify(context)\n```\n\n### Flush Events\n\nForce immediate delivery of pending events:\n\n```python\nimport ldclient\n\nclient = ldclient.get()\nclient.flush()\n```\n\n### Auto-Flush on Shutdown\n\n```python\nimport ldclient\nimport signal\nimport sys\n\ndef shutdown_handler(signum, frame):\n    print('Shutting down...')\n    client = ldclient.get()\n    client.flush()\n    client.close()\n    sys.exit(0)\n\nsignal.signal(signal.SIGTERM, shutdown_handler)\nsignal.signal(signal.SIGINT, shutdown_handler)\n```\n\n---\n\n## Data Modes\n\n### Streaming Mode (Default)\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    stream=True\n)\n\nldclient.set_config(config)\n```\n\n### Polling Mode\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    stream=False,\n    poll_interval=60  # seconds\n)\n\nldclient.set_config(config)\n```\n\n### Offline Mode\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    offline=True\n)\n\nldclient.set_config(config)\nclient = ldclient.get()\n\n# All flags return default values\nresult = client.variation('flag-key', context, False)\n# Will always return False (the default)\n```\n\n---\n\n## HTTP Configuration\n\n### Configure HTTP Timeouts\n\n```python\nfrom ldclient.config import Config, HTTPConfig\nimport ldclient\nimport os\n\nhttp_config = HTTPConfig(\n    connect_timeout=10,\n    read_timeout=15\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    http=http_config\n)\n\nldclient.set_config(config)\n```\n\n### Configure HTTP Proxy\n\n```python\nfrom ldclient.config import Config, HTTPConfig\nimport ldclient\nimport os\n\nhttp_config = HTTPConfig(\n    http_proxy='http://proxy.example.com:8080'\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    http=http_config\n)\n\nldclient.set_config(config)\n```\n\n### Environment Variable Proxy\n\n```python\nimport os\n\nos.environ['HTTPS_PROXY'] = 'https://proxy.example.com:8080'\n\n# SDK will automatically use the proxy\n```\n\n### Custom CA Certificates\n\n```python\nfrom ldclient.config import Config, HTTPConfig\nimport ldclient\nimport os\n\nhttp_config = HTTPConfig(\n    ca_certs='/path/to/ca-bundle.crt'\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    http=http_config\n)\n\nldclient.set_config(config)\n```\n\n### Disable SSL Verification (Not Recommended)\n\n```python\nfrom ldclient.config import Config, HTTPConfig\nimport ldclient\nimport os\n\nhttp_config = HTTPConfig(\n    disable_ssl_verification=True\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    http=http_config\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## Relay Proxy\n\n### Using LaunchDarkly Relay Proxy\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    base_uri='http://relay-proxy.example.com',\n    stream_uri='http://relay-proxy.example.com',\n    events_uri='http://relay-proxy.example.com'\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## Feature Stores\n\n### Redis Feature Store\n\n```python\nfrom ldclient.config import Config\nfrom ldclient.integrations import Redis\nimport ldclient\nimport os\n\nredis_store = Redis.new_feature_store(\n    url='redis://localhost:6379',\n    prefix='ld',\n    max_connections=16,\n    expiration=30\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    feature_store=redis_store\n)\n\nldclient.set_config(config)\n```\n\n### DynamoDB Feature Store\n\n```python\nfrom ldclient.config import Config\nfrom ldclient.integrations import DynamoDB\nimport ldclient\nimport os\n\ndynamodb_store = DynamoDB.new_feature_store(\n    'feature-flags-table',\n    prefix='ld',\n    expiration=30\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    feature_store=dynamodb_store\n)\n\nldclient.set_config(config)\n```\n\n### Consul Feature Store\n\n```python\nfrom ldclient.config import Config\nfrom ldclient.integrations import Consul\nimport ldclient\nimport os\n\nconsul_store = Consul.new_feature_store(\n    host='localhost',\n    port=8500,\n    prefix='ld',\n    expiration=30\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    feature_store=consul_store\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## File-Based Data Source\n\n### Load Flags from File\n\n```python\nfrom ldclient.config import Config\nfrom ldclient.integrations import Files\nimport ldclient\nimport os\n\nfile_source = Files.new_data_source(\n    paths=['./flags.json'],\n    auto_update=True,\n    poll_interval=1\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    update_processor_class=file_source\n)\n\nldclient.set_config(config)\n```\n\n### flags.json Format\n\n```json\n{\n  \"flags\": {\n    \"flag-key-123abc\": {\n      \"key\": \"flag-key-123abc\",\n      \"on\": true,\n      \"variations\": [true, false],\n      \"fallthrough\": {\n        \"variation\": 0\n      }\n    }\n  },\n  \"segments\": {}\n}\n```\n\n---\n\n## Big Segments\n\n### Configure Big Segments Store\n\n```python\nfrom ldclient.config import Config, BigSegmentsConfig\nfrom ldclient.integrations import Redis\nimport ldclient\nimport os\n\nredis_store = Redis.new_big_segment_store(\n    url='redis://localhost:6379',\n    prefix='big-segments'\n)\n\nbig_segments = BigSegmentsConfig(\n    store=redis_store,\n    context_cache_size=1000,\n    context_cache_time=5,\n    status_poll_interval=5,\n    stale_after=120\n)\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    big_segments=big_segments\n)\n\nldclient.set_config(config)\n```\n\n### Check Big Segments Status\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nresult = client.variation_detail('segment-flag', context, False)\n\nif result.reason.get('bigSegmentsStatus') == 'STALE':\n    print('Big segments data is stale')\n```\n\n---\n\n## Hooks\n\n### Create a Hook\n\n```python\nfrom ldclient.hook import Hook, Metadata\n\nclass LoggingHook(Hook):\n    @property\n    def metadata(self):\n        return Metadata(name='logging-hook')\n\n    def before_evaluation(self, series_context, data):\n        print(f'Evaluating flag: {series_context.flag_key}')\n        return data\n\n    def after_evaluation(self, series_context, data, detail):\n        print(f'Flag result: {detail.value}')\n        return data\n```\n\n### Register Hook via Configuration\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    hooks=[LoggingHook()]\n)\n\nldclient.set_config(config)\n```\n\n### Add Hook at Runtime\n\n```python\nimport ldclient\n\nclient = ldclient.get()\nhook = LoggingHook()\nclient.add_hook(hook)\n```\n\n---\n\n## Migrations\n\n### Create Migration\n\n```python\nimport ldclient\nfrom ldclient.migrations import MigratorBuilder, Stage, ExecutionOrder\n\nclient = ldclient.get()\n\ndef old_read(payload):\n    return old_database.read(payload['id'])\n\ndef new_read(payload):\n    return new_database.read(payload['id'])\n\ndef old_write(payload):\n    old_database.write(payload['id'], payload['data'])\n\ndef new_write(payload):\n    new_database.write(payload['id'], payload['data'])\n\ndef check_consistency(old_value, new_value):\n    return old_value == new_value\n\nmigrator = MigratorBuilder(client) \\\n    .read(old_read, new_read, check_consistency) \\\n    .write(old_write, new_write) \\\n    .read_execution_order(ExecutionOrder.PARALLEL) \\\n    .track_latency(True) \\\n    .track_errors(True) \\\n    .build()\n```\n\n### Execute Migration Read\n\n```python\nimport ldclient\nfrom ldclient import Context\nfrom ldclient.migrations import Stage\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nstage_str = client.variation('migration-flag', context, 'off')\nstage = Stage.from_str(stage_str)\n\nresult = migrator.read(\n    'migration-flag',\n    context,\n    stage,\n    payload={'id': 'record-123'}\n)\n\nif result.is_success():\n    print('Data:', result.value)\nelse:\n    print('Migration read failed')\n```\n\n### Execute Migration Write\n\n```python\nimport ldclient\nfrom ldclient import Context\nfrom ldclient.migrations import Stage\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nstage_str = client.variation('migration-flag', context, 'off')\nstage = Stage.from_str(stage_str)\n\nresult = migrator.write(\n    'migration-flag',\n    context,\n    stage,\n    payload={'id': 'record-123', 'data': {'name': 'Example'}}\n)\n\nif result.is_success():\n    print('Write completed')\n```\n\n### Migration Stages\n\n```python\nfrom ldclient.migrations import Stage\n\n# Available stages:\nStage.OFF        # Use old implementation only\nStage.DUALWRITE  # Write to both, read from old\nStage.SHADOW     # Read from both, write to both, use old for responses\nStage.LIVE       # Read from both, write to both, use new for responses\nStage.RAMPDOWN   # Write to both, read from new\nStage.COMPLETE   # Use new implementation only\n```\n\n### Execution Order\n\n```python\nfrom ldclient.migrations import ExecutionOrder\n\nExecutionOrder.SERIAL    # Execute old then new sequentially\nExecutionOrder.RANDOM    # Randomize execution order\nExecutionOrder.PARALLEL  # Execute both concurrently\n```\n\n---\n\n## Worker-Based Servers (uWSGI, Gunicorn)\n\n### uWSGI Configuration\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\n# Initialize before forking\nconfig = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\nldclient.set_config(config)\nclient = ldclient.get()\n\n# Reinitialize after fork\ntry:\n    import uwsgidecorators\n\n    @uwsgidecorators.postfork\n    def reinit_ld_after_fork():\n        ldclient.get().postfork()\n        print('LaunchDarkly reinitialized after fork')\nexcept ImportError:\n    pass\n```\n\n### Gunicorn Configuration\n\n```python\n# gunicorn_config.py\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\ndef on_starting(server):\n    \"\"\"Called just before the master process is initialized.\"\"\"\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n\ndef post_fork(server, worker):\n    \"\"\"Called just after a worker has been forked.\"\"\"\n    ldclient.get().postfork()\n```\n\n### Without Decorator\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\n# After forking in worker process\nconfig = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\nldclient.set_config(config)\nclient = ldclient.get()\n\n# Reinitialize\nclient.postfork()\n```\n\n---\n\n## Application Metadata\n\n### Set Application Info\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    application={\n        'id': 'my-app',\n        'version': '1.2.3',\n        'name': 'My Application',\n        'version_name': 'v1.2.3-beta'\n    }\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## Secure Mode\n\n### Generate Secure Mode Hash\n\n```python\nimport hashlib\nimport hmac\nimport os\n\ndef generate_secure_mode_hash(sdk_key, context_key):\n    \"\"\"Generate secure mode hash for client-side SDK.\"\"\"\n    return hmac.new(\n        sdk_key.encode(),\n        context_key.encode(),\n        hashlib.sha256\n    ).hexdigest()\n\nhash_value = generate_secure_mode_hash(\n    os.environ['LAUNCHDARKLY_SDK_KEY'],\n    'user-key-123abc'\n)\n\n# Send hash to client-side\nreturn {'hash': hash_value}\n```\n\n---\n\n## Logging\n\n### Configure Logger\n\n```python\nimport logging\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\n# Set up logging\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger('ldclient')\nlogger.setLevel(logging.DEBUG)\n\nconfig = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\nldclient.set_config(config)\n```\n\n### Custom Log Level\n\n```python\nimport logging\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\n# Create custom logger\nld_logger = logging.getLogger('ldclient')\nld_logger.setLevel(logging.WARNING)\n\nhandler = logging.StreamHandler()\nhandler.setLevel(logging.WARNING)\nformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')\nhandler.setFormatter(formatter)\nld_logger.addHandler(handler)\n\nconfig = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\nldclient.set_config(config)\n```\n\n---\n\n## Private Attributes Configuration\n\n### Global Private Attributes\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    private_attributes={'email', 'ssn', 'address'}\n)\n\nldclient.set_config(config)\n```\n\n### All Attributes Private\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    all_attributes_private=True\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## Diagnostics\n\n### Disable Diagnostic Events\n\n```python\nfrom ldclient.config import Config\nimport ldclient\nimport os\n\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    diagnostic_opt_out=True\n)\n\nldclient.set_config(config)\n```\n\n---\n\n## Testing\n\n### Using File Data Source for Tests\n\n```python\nfrom ldclient.config import Config\nfrom ldclient.integrations import Files\nimport ldclient\n\n# Create test flags file\ntest_flags = {\n    'flags': {\n        'test-flag': {\n            'key': 'test-flag',\n            'on': True,\n            'variations': [True, False],\n            'fallthrough': {'variation': 0}\n        }\n    },\n    'segments': {}\n}\n\n# Write to file\nimport json\nwith open('test-flags.json', 'w') as f:\n    json.dump(test_flags, f)\n\n# Configure client with file source\nfile_source = Files.new_data_source(paths=['test-flags.json'])\n\nconfig = Config(\n    sdk_key='test-sdk-key',\n    update_processor_class=file_source,\n    send_events=False\n)\n\nldclient.set_config(config)\nclient = ldclient.get()\n```\n\n### Mock Client for Unit Tests\n\n```python\nfrom unittest.mock import Mock, MagicMock\nfrom ldclient import EvaluationDetail\n\nmock_client = Mock()\nmock_client.variation = Mock(return_value=True)\nmock_client.variation_detail = Mock(return_value=EvaluationDetail(\n    value=True,\n    variation_index=0,\n    reason={'kind': 'OFF'}\n))\nmock_client.track = Mock()\nmock_client.identify = Mock()\nmock_client.flush = Mock()\nmock_client.close = Mock()\n```\n\n---\n\n## Shutdown and Cleanup\n\n### Graceful Shutdown\n\n```python\nimport ldclient\n\ndef shutdown():\n    print('Flushing events...')\n    client = ldclient.get()\n    client.flush()\n\n    print('Closing client...')\n    client.close()\n\n    print('Shutdown complete')\n```\n\n### Check Initialization Status\n\n```python\nimport ldclient\n\nclient = ldclient.get()\n\nif client.is_initialized():\n    print('Client is ready')\nelse:\n    print('Client is not initialized yet')\n```\n\n---\n\n## Complete Flask Example\n\n```python\nfrom flask import Flask, request, jsonify\nimport ldclient\nfrom ldclient.config import Config\nfrom ldclient import Context\nimport os\nimport signal\nimport sys\n\napp = Flask(__name__)\n\n# Initialize LaunchDarkly\ndef init_launchdarkly():\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n\n    client = ldclient.get()\n    if not client.wait_for_initialization(10):\n        print('LaunchDarkly initialization timeout')\n    else:\n        print('LaunchDarkly initialized')\n\n    return client\n\n# Route using feature flag\n@app.route('/feature')\ndef feature():\n    client = ldclient.get()\n\n    user_id = request.headers.get('X-User-ID', 'anonymous')\n    user_email = request.headers.get('X-User-Email')\n\n    context = Context.builder(user_id) \\\n        .set('email', user_email) \\\n        .build()\n\n    show_new_feature = client.variation('new-feature-flag', context, False)\n\n    if show_new_feature:\n        return jsonify({\n            'feature': 'new',\n            'message': 'Welcome to the new feature!'\n        })\n    else:\n        return jsonify({\n            'feature': 'old',\n            'message': 'Using legacy feature'\n        })\n\n# Track custom event\n@app.route('/track-event', methods=['POST'])\ndef track_event():\n    client = ldclient.get()\n\n    data = request.get_json()\n    user_id = data.get('userId')\n\n    context = Context.create(user_id)\n\n    client.track('button-clicked', context, data={\n        'button_id': data.get('buttonId')\n    })\n\n    return jsonify({'success': True})\n\n# Graceful shutdown\ndef shutdown_handler(signum, frame):\n    print('Shutting down...')\n    client = ldclient.get()\n    client.flush()\n    client.close()\n    sys.exit(0)\n\nsignal.signal(signal.SIGTERM, shutdown_handler)\nsignal.signal(signal.SIGINT, shutdown_handler)\n\nif __name__ == '__main__':\n    init_launchdarkly()\n    app.run(port=5000)\n```\n\n---\n\n## Complete Django Example\n\n```python\n# settings.py\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\n# Initialize LaunchDarkly\ndef init_launchdarkly():\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n\n    client = ldclient.get()\n    if client.wait_for_initialization(10):\n        print('LaunchDarkly initialized')\n\n    return client\n\nLAUNCHDARKLY_CLIENT = init_launchdarkly()\n\n\n# views.py\nfrom django.http import JsonResponse\nfrom ldclient import Context\nimport ldclient\n\ndef feature_view(request):\n    client = ldclient.get()\n\n    user_id = request.META.get('HTTP_X_USER_ID', 'anonymous')\n    user_email = request.META.get('HTTP_X_USER_EMAIL')\n\n    context = Context.builder(user_id) \\\n        .set('email', user_email) \\\n        .build()\n\n    show_new_feature = client.variation('new-feature-flag', context, False)\n\n    if show_new_feature:\n        return JsonResponse({\n            'feature': 'new',\n            'message': 'Welcome to the new feature!'\n        })\n    else:\n        return JsonResponse({\n            'feature': 'old',\n            'message': 'Using legacy feature'\n        })\n\n\n# apps.py (for cleanup on shutdown)\nfrom django.apps import AppConfig\nimport ldclient\n\nclass MyAppConfig(AppConfig):\n    name = 'myapp'\n\n    def ready(self):\n        import signal\n        import sys\n\n        def shutdown_handler(signum, frame):\n            client = ldclient.get()\n            client.flush()\n            client.close()\n            sys.exit(0)\n\n        signal.signal(signal.SIGTERM, shutdown_handler)\n```\n\n---\n\n## Complete FastAPI Example\n\n```python\nfrom fastapi import FastAPI, Header\nfrom pydantic import BaseModel\nimport ldclient\nfrom ldclient.config import Config\nfrom ldclient import Context\nimport os\n\napp = FastAPI()\n\n# Initialize LaunchDarkly\n@app.on_event(\"startup\")\nasync def startup_event():\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n\n    client = ldclient.get()\n    if not client.wait_for_initialization(10):\n        print('LaunchDarkly initialization timeout')\n    else:\n        print('LaunchDarkly initialized')\n\n# Shutdown\n@app.on_event(\"shutdown\")\nasync def shutdown_event():\n    client = ldclient.get()\n    client.flush()\n    client.close()\n\n# Route using feature flag\n@app.get(\"/feature\")\nasync def get_feature(\n    x_user_id: str = Header(default='anonymous'),\n    x_user_email: str = Header(default=None)\n):\n    client = ldclient.get()\n\n    context = Context.builder(x_user_id) \\\n        .set('email', x_user_email) \\\n        .build()\n\n    show_new_feature = client.variation('new-feature-flag', context, False)\n\n    if show_new_feature:\n        return {\n            'feature': 'new',\n            'message': 'Welcome to the new feature!'\n        }\n    else:\n        return {\n            'feature': 'old',\n            'message': 'Using legacy feature'\n        }\n\n# Track custom event\nclass TrackEventRequest(BaseModel):\n    userId: str\n    buttonId: str\n\n@app.post(\"/track-event\")\nasync def track_event(event: TrackEventRequest):\n    client = ldclient.get()\n\n    context = Context.create(event.userId)\n\n    client.track('button-clicked', context, data={\n        'button_id': event.buttonId\n    })\n\n    return {'success': True}\n```\n\n---\n\n## OpenTelemetry Integration\n\n### Setup OpenTelemetry with LaunchDarkly\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nfrom ldobserve import ObservabilityPlugin\nfrom opentelemetry import metrics\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\nfrom opentelemetry.exporter.prometheus import PrometheusMetricReader\nimport os\n\n# Set up OpenTelemetry\nprometheus_reader = PrometheusMetricReader()\nmeter_provider = MeterProvider(metric_readers=[prometheus_reader])\nmetrics.set_meter_provider(meter_provider)\n\n# Initialize LaunchDarkly with observability\nconfig = Config(\n    sdk_key=os.environ['LAUNCHDARKLY_SDK_KEY'],\n    plugins=[ObservabilityPlugin()]\n)\n\nldclient.set_config(config)\nclient = ldclient.get()\n```\n\n---\n\n## Error Handling\n\n### Handle Initialization Errors\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nimport os\n\ntry:\n    config = Config(os.environ['LAUNCHDARKLY_SDK_KEY'])\n    ldclient.set_config(config)\n    client = ldclient.get()\n\n    if not client.wait_for_initialization(10):\n        print('Initialization timeout - using default values')\nexcept Exception as e:\n    print(f'LaunchDarkly initialization error: {e}')\n```\n\n### Handle Evaluation Errors\n\n```python\nimport ldclient\nfrom ldclient import Context\n\nclient = ldclient.get()\ncontext = Context.create('user-key-123abc')\n\nresult = client.variation_detail('flag-key', context, False)\n\nif result.reason['kind'] == 'ERROR':\n    error_kind = result.reason['errorKind']\n\n    if error_kind == 'MALFORMED_FLAG':\n        print('Flag configuration is invalid')\n    elif error_kind == 'FLAG_NOT_FOUND':\n        print('Flag does not exist')\n    elif error_kind == 'USER_NOT_SPECIFIED':\n        print('Context is invalid')\n    elif error_kind == 'WRONG_TYPE':\n        print('Flag type mismatch')\n    else:\n        print(f'Unknown error: {error_kind}')\n```\n"
  },
  {
    "path": "content/launchdarkly-server-sdk/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LaunchDarkly Python server-side SDK for evaluating feature flags, targeting contexts, and sending analytics events\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.15.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"launchdarkly,feature-flags,feature-management,experimentation,python,sdk\"\n---\n\n# LaunchDarkly Python Server-side SDK\n\n## Golden Rule\n\nUse `launchdarkly-server-sdk` for server-side Python evaluation, authenticate with a server-side SDK key, initialize the client once per process, and evaluate flags against `Context` objects rather than legacy user dictionaries. Always provide an explicit fallback value in code because LaunchDarkly will return that fallback when the client is offline, uninitialized, or the flag cannot be evaluated.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"launchdarkly-server-sdk==9.15.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"launchdarkly-server-sdk==9.15.0\"\npoetry add \"launchdarkly-server-sdk==9.15.0\"\n```\n\nUseful extras published by the package:\n\n```bash\npython -m pip install \"launchdarkly-server-sdk[redis]==9.15.0\"\npython -m pip install \"launchdarkly-server-sdk[dynamodb]==9.15.0\"\npython -m pip install \"launchdarkly-server-sdk[consul]==9.15.0\"\npython -m pip install \"launchdarkly-server-sdk[test-filesource]==9.15.0\"\n```\n\nOptional observability support is a separate package:\n\n```bash\npython -m pip install launchdarkly-observability\n```\n\n## Authentication And Initialization\n\nServer-side SDKs use an SDK key from the LaunchDarkly environment you want to read from. Keep it in a secret manager or environment variable.\n\n```bash\nexport LAUNCHDARKLY_SDK_KEY=\"sdk-xxxxxxxxxxxxxxxx\"\n```\n\nInitialize once during process startup and reuse the singleton client:\n\n```python\nimport os\n\nimport ldclient\nfrom ldclient.config import Config\n\nldclient.set_config(\n    Config(\n        sdk_key=os.environ[\"LAUNCHDARKLY_SDK_KEY\"],\n    )\n)\n\nclient = ldclient.get()\n\nif not client.is_initialized():\n    # The SDK will still return your fallback values.\n    # Decide whether to continue in degraded mode or fail startup.\n    raise RuntimeError(\"LaunchDarkly client did not initialize\")\n```\n\nIf your app can keep serving when LaunchDarkly is unavailable, log the failure and continue with conservative fallback values instead of crashing.\n\n### Add common configuration\n\n```python\nimport os\n\nimport ldclient\nfrom ldclient.config import Config\n\nldclient.set_config(\n    Config(\n        sdk_key=os.environ[\"LAUNCHDARKLY_SDK_KEY\"],\n        offline=False,\n        send_events=True,\n        all_attributes_private=False,\n        private_attributes={\"email\", \"phone\", \"ssn\"},\n    )\n)\n\nclient = ldclient.get()\n```\n\nNotes:\n\n- `private_attributes` and `all_attributes_private` control which context attributes are omitted from analytics payloads.\n- Use `offline=True` only when you intentionally want the SDK to skip network access and return fallbacks.\n- Close the client during shutdown so pending analytics events flush cleanly.\n\n```python\nclient.flush()\nclient.close()\n```\n\n## Core Usage\n\n### Build a context\n\n`Context` is the current targeting model. The simplest form is a key-only user context:\n\n```python\nfrom ldclient import Context\n\ncontext = Context.builder(\"user-123\").name(\"Ada Lovelace\").set(\"plan\", \"pro\").build()\n```\n\nUse custom kinds for non-user entities such as organizations, tenants, or devices:\n\n```python\nfrom ldclient import Context\n\norg = Context.builder(\"org-42\").kind(\"organization\").name(\"Acme\").build()\n```\n\nUse a multi-context when flag rules depend on more than one entity:\n\n```python\nfrom ldclient import Context\n\nuser = Context.builder(\"user-123\").name(\"Ada Lovelace\").build()\norg = Context.builder(\"org-42\").kind(\"organization\").name(\"Acme\").build()\n\nmulti = Context.create_multi(user, org)\n```\n\n### Evaluate a flag\n\nUse the typed variation method that matches the fallback value you want:\n\n```python\nenabled = client.variation(\"new-checkout\", context, False)\n\nif enabled:\n    run_new_checkout()\nelse:\n    run_legacy_checkout()\n```\n\nIf you need the evaluation reason for debugging or audits, use `variation_detail`:\n\n```python\ndetail = client.variation_detail(\"new-checkout\", context, False)\n\nprint(detail.value)\nprint(detail.reason)\n```\n\n### Track custom events\n\nUse `track` for business events that should appear in LaunchDarkly experiments or analytics:\n\n```python\nclient.track(\n    \"checkout-completed\",\n    context,\n    data={\"cart_value\": 125.50, \"currency\": \"USD\"},\n    metric_value=125.50,\n)\n```\n\n### Get multiple flag values\n\n`all_flags_state` is useful when you need a snapshot of flag values for server-rendered pages or bootstrapping a client:\n\n```python\nstate = client.all_flags_state(context)\nflag_values = state.to_json_dict()\n```\n\n## Configuration Patterns\n\n### Keep sensitive attributes private\n\nLaunchDarkly contexts can carry application data, but private fields should not be sent in events.\n\nGlobal config:\n\n```python\nldclient.set_config(\n    Config(\n        sdk_key=os.environ[\"LAUNCHDARKLY_SDK_KEY\"],\n        private_attributes={\"email\", \"ssn\"},\n    )\n)\n```\n\n### Use offline mode intentionally\n\nOffline mode disables LaunchDarkly network access. The SDK then serves only your code-level fallback values.\n\n```python\nldclient.set_config(\n    Config(\n        sdk_key=\"ignored-in-offline-mode\",\n        offline=True,\n    )\n)\n```\n\nThis is useful for local development, deterministic tests, or emergency kill-switch behavior, but it is not a substitute for real flag data.\n\n### Load flag data from files or test data\n\nFor local development or tests, the SDK supports file-based data and an in-memory test data source.\n\n```python\nimport os\n\nimport ldclient\nfrom ldclient.config import Config\nfrom ldclient.integrations import Files\n\ndata_source = Files.new_data_source(paths=[\"tests/flags.json\"], auto_update=False)\n\nldclient.set_config(\n    Config(\n        sdk_key=os.environ[\"LAUNCHDARKLY_SDK_KEY\"],\n        update_processor_class=data_source,\n        send_events=False,\n    )\n)\n```\n\nFor programmatic tests:\n\n```python\nimport ldclient\nfrom ldclient.config import Config\nfrom ldclient.integrations.test_data import TestData\n\ntd = TestData.data_source()\ntd.update(td.flag(\"new-checkout\").variation_for_all(True))\n\nldclient.set_config(Config(\"sdk-test-key\", update_processor_class=td))\nclient = ldclient.get()\n```\n\n### Use a persistent store or Relay Proxy when needed\n\nIf you need shared flag state across processes, LaunchDarkly supports persistent feature stores such as Redis, DynamoDB, and Consul. If your application should read from a Relay Proxy daemon instead of LaunchDarkly directly, configure a feature store and set `use_ldd=True`.\n\nThis is the pattern to reach for when:\n\n- many worker processes would otherwise open their own streaming connections\n- you want daemon mode through Relay Proxy\n- you need a shared cache across short-lived processes\n\n### Call `postfork()` in worker-process servers\n\nThe SDK is not fork-safe. In servers that fork after initialization, call `postfork()` in each child so background threads and connections are recreated correctly.\n\n```python\ndef post_fork(server, worker):\n    ldclient.get().postfork()\n```\n\nLaunchDarkly documents this for worker-based servers such as uWSGI and requires Relay Proxy `8.11+` if you use `postfork()` together with daemon mode.\n\n## Common Pitfalls\n\n- Do not use a client-side ID or mobile key on the server. The server SDK requires an SDK key.\n- Do not create a new LaunchDarkly client per request. Initialize once per process and reuse it.\n- Do not keep using legacy user dictionaries in new code. Use `Context` and multi-context targeting.\n- `variation()` returns the fallback value when the client is offline, uninitialized, the flag is missing, or the context is invalid. Pick fallback values deliberately.\n- `offline=True` does not serve remote flags. It only returns local fallback values unless you also wire in a file or test data source.\n- If you use file data for tests, disable events unless you intentionally want analytics emitted from those runs.\n- In pre-fork servers, initialize carefully and call `postfork()` in child workers. Reusing a pre-fork client without that step can produce broken background threads or stale connections.\n- Remember to `flush()` and `close()` the client during shutdown so analytics are not dropped.\n\n## Version-Sensitive Notes For 9.15.0\n\n- `9.15.0` drops Python 3.9 support. LaunchDarkly's high-level Python SDK page still says `9.12+` requires Python `3.9+`, but the `9.15.0` PyPI metadata and upstream `pyproject.toml` require `>=3.10`.\n- Modern LaunchDarkly Python code should use `Context`. If you are migrating older code, treat \"users\" examples from pre-v8 blog posts as legacy guidance.\n- The observability plugin support on the Python server-side docs requires SDK `9.12+`.\n- The `9.15.0` changelog marks breaking changes only for the early-access file data system (`Files.new_data_source_v2`, `fdv2`, and related APIs). Avoid those v2 APIs in general-purpose agent code unless you are intentionally targeting the early-access data-system model.\n\n## Official Source URLs\n\n- `https://launchdarkly.com/docs/sdk/server-side/python`\n- `https://launchdarkly.com/docs/home/flags/context-attributes`\n- `https://launchdarkly.com/docs/sdk/features/config#python`\n- `https://launchdarkly.com/docs/sdk/features/offline-mode#python`\n- `https://launchdarkly.com/docs/sdk/features/flags-from-files#python`\n- `https://launchdarkly.com/docs/sdk/features/storing-data#python`\n- `https://launchdarkly.com/docs/sdk/server-side/python#worker-based-servers`\n- `https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-main.html`\n- `https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-integrations.html`\n- `https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-testing.html`\n- `https://pypi.org/project/launchdarkly-server-sdk/`\n- `https://github.com/launchdarkly/python-server-sdk`\n- `https://github.com/launchdarkly/python-server-sdk/blob/main/CHANGELOG.md`\n"
  },
  {
    "path": "content/librosa/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"librosa Python package guide for audio loading, feature extraction, beat tracking, and streaming analysis\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"librosa,python,audio,music,dsp,signal-processing,feature-extraction\"\n---\n\n# librosa Python Package Guide\n\n## Golden Rule\n\nUse `librosa` for offline music and audio analysis, but be explicit about sample rate, channel handling, and frame settings. The most common agent mistake is calling `librosa.load()` and then forgetting that it resamples to `22050` Hz by default and mixes audio to mono unless you override that behavior.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"librosa==0.11.0\"\n```\n\nIf you want plotting helpers from `librosa.display`, install the display extra:\n\n```bash\npython -m pip install \"librosa[display]==0.11.0\"\n```\n\nIf you prefer conda, the maintainers also publish packages on conda-forge:\n\n```bash\nconda install -c conda-forge librosa\n```\n\nNotes:\n\n- `librosa` depends on `soundfile` for audio decoding in the supported path. On some Linux systems, `soundfile` may need system `libsndfile` packages installed first.\n- If you need codecs that `soundfile` cannot decode, you may still see projects rely on `audioread`, but `audioread` support is deprecated in `0.10.x` and scheduled for removal in `1.0`.\n\n## Initialize And Inspect The Environment\n\nBasic import and version check:\n\n```python\nimport librosa\n\nprint(librosa.__version__)\nlibrosa.show_versions()\n```\n\n`show_versions()` is useful in bug reports because audio backends, NumPy/SciPy versions, and optional dependencies affect behavior.\n\n## Core Usage\n\n### Load audio safely\n\nUse `sr=None` when you need the file's native sample rate, and use `mono=False` when channel structure matters:\n\n```python\nimport librosa\n\ny, sr = librosa.load(\"audio.wav\", sr=None, mono=True)\nprint(y.shape, sr)\n```\n\nUseful options:\n\n- `sr=None`: keep the original sample rate instead of resampling to `22050`\n- `mono=False`: preserve channels instead of downmixing\n- `offset=` and `duration=`: read only part of a file\n- `res_type=`: choose a different resampler when you do want resampling\n\n### Compute a mel spectrogram\n\n```python\nimport librosa\n\ny, sr = librosa.load(\"audio.wav\", sr=None)\nmel = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=2048, hop_length=512, n_mels=128)\nmel_db = librosa.power_to_db(mel, ref=\"max\")\n\nprint(mel_db.shape)\n```\n\nThis is the standard entry point for many classification, similarity, and visualization pipelines.\n\n### Estimate tempo and beats\n\n```python\nimport librosa\n\ny, sr = librosa.load(\"audio.wav\", sr=None)\ntempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)\nbeat_times = librosa.frames_to_time(beat_frames, sr=sr)\n\nprint(tempo, beat_times[:10])\n```\n\nIf you need times in seconds, convert frames explicitly with `frames_to_time`.\n\n### Work from example audio in the docs\n\nThe maintainers provide downloadable example recordings:\n\n```python\nimport librosa\n\npath = librosa.util.example(\"brahms\")\ny, sr = librosa.load(path, sr=None)\n```\n\nThis is useful for tests, debugging, and reproducible examples.\n\n### Stream long files instead of loading everything\n\nFor large files, stream blocks and process each frame window incrementally:\n\n```python\nimport soundfile as sf\nimport librosa\n\nwith sf.SoundFile(\"long_recording.wav\") as f:\n    for y_block in librosa.stream(\n        f,\n        block_length=256,\n        frame_length=2048,\n        hop_length=512,\n        mono=True,\n    ):\n        rms = librosa.feature.rms(y=y_block, frame_length=2048, hop_length=512)\n        print(rms.shape)\n```\n\nWhen using `librosa.stream`, pair it with frame-based feature extraction and disable centered analysis where applicable. Centered framing assumes full random access to the signal and is usually incompatible with streamed blocks.\n\n## Configuration And Runtime Notes\n\nThere is no auth or remote service configuration. The main runtime choices are audio backend behavior, cache/example data location, and numerical settings.\n\nUseful environment and setup notes:\n\n- `LIBROSA_DATA_DIR` controls where example audio files downloaded by `librosa.util.example()` are cached.\n- Plotting with `librosa.display` requires the optional display dependencies.\n- Resampling quality and speed depend on the selected backend and `res_type`.\n- Numerical results can shift slightly across NumPy/SciPy/audio-backend versions, so pin dependencies for reproducible pipelines.\n\n## Common Pitfalls\n\n- `librosa.load()` defaults to `sr=22050`. If your model or analysis expects the source sample rate, pass `sr=None`.\n- `librosa.load()` defaults to mono mixing. Pass `mono=False` for stereo or multichannel workflows.\n- Old blog posts often use positional arguments that no longer match current keyword-only signatures cleanly. Prefer explicit keyword arguments such as `y=y, sr=sr`.\n- `librosa.stream()` is not a drop-in replacement for `load()`. Features that depend on centered windows or future context need different settings.\n- `librosa.beat.beat_track()` in current docs returns tempo together with beat frames; downstream code should not assume only one return value.\n- If decoding fails for compressed formats, check whether the file is supported by `soundfile` before reaching for deprecated `audioread` workarounds.\n- If you import `librosa.display` without the extra plotting dependencies installed, plotting code will fail even though the core package imported successfully.\n\n## Version-Sensitive Notes For 0.11.0\n\n- `0.11.0` is the current stable release on PyPI as of March 12, 2026, and the versioned docs root `https://librosa.org/doc/0.11.0/` is safer than relying on the floating `latest/` URL.\n- The project supports NumPy 2.0 in the modern `0.11.0` line, so very old compatibility advice around pinning pre-2.0 NumPy is often stale.\n- The changelog notes that the default FFT backend now uses `scipy.fft`, and the old `librosa.set_fftlib` path is deprecated in favor of SciPy backend control.\n- `audioread` support was deprecated in the `0.10` series and is planned for removal in `1.0`; prefer `soundfile`-based workflows when writing new code.\n\n## Official Source URLs\n\n- Docs root: `https://librosa.org/doc/0.11.0/`\n- Installation: `https://librosa.org/doc/0.11.0/install.html`\n- Changelog: `https://librosa.org/doc/0.11.0/changelog.html`\n- `librosa.load`: `https://librosa.org/doc/0.11.0/generated/librosa.load.html`\n- Mel spectrograms: `https://librosa.org/doc/0.11.0/generated/librosa.feature.melspectrogram.html`\n- Beat tracking: `https://librosa.org/doc/0.11.0/generated/librosa.beat.beat_track.html`\n- Streaming: `https://librosa.org/doc/0.11.0/generated/librosa.stream.html`\n- Example audio helper: `https://librosa.org/doc/0.11.0/generated/librosa.util.example.html`\n- PyPI: `https://pypi.org/project/librosa/0.11.0/`\n"
  },
  {
    "path": "content/lightgbm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LightGBM Python package guide for gradient boosting models using the official LightGBM 4.6.0 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"lightgbm,gradient-boosting,machine-learning,scikit-learn,python\"\n---\n\n# LightGBM Python Package Guide\n\n## Golden Rule\n\nUse the official `lightgbm` package, import it as `import lightgbm as lgb`, and prefer the scikit-learn estimators (`LGBMClassifier`, `LGBMRegressor`, `LGBMRanker`) when you need pipeline or cross-validation compatibility. Use the native `lgb.train()` API when you need tighter control over datasets, callbacks, ranking groups, or model persistence.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"lightgbm==4.6.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"lightgbm==4.6.0\"\npoetry add \"lightgbm==4.6.0\"\n```\n\nOptional extras from PyPI:\n\n```bash\npython -m pip install \"lightgbm[pandas,scikit-learn]==4.6.0\"\npython -m pip install \"lightgbm[dask]==4.6.0\"\npython -m pip install \"lightgbm[pyarrow]==4.6.0\"\n```\n\nInstallation notes:\n\n- `numpy` and `scipy` are required core dependencies.\n- The `pandas`, `scikit-learn`, `dask`, and `pyarrow` extras are only needed if your code uses those integrations.\n- The PyPI page notes that the Dask integration is only tested on Linux.\n- On macOS, LightGBM commonly needs OpenMP installed separately, for example `brew install libomp`.\n- On Linux, an import error mentioning `libgomp.so.1` usually means the OpenMP runtime is missing from the system image.\n- The install guide documents experimental GPU-enabled wheels for Windows and Linux. For CUDA-specific builds or custom build flags, follow the upstream installation guide instead of assuming the default wheel will fit the environment.\n\n## Initialize And Prepare Data\n\nLightGBM can train from NumPy arrays, SciPy sparse matrices, pandas DataFrames, H2O DataTables, and PyArrow Tables. For the native API, convert training data into `lgb.Dataset` objects.\n\n```python\nimport lightgbm as lgb\n\ntrain_data = lgb.Dataset(X_train, label=y_train)\nvalid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)\n```\n\nStart with a small, explicit parameter set:\n\n```python\nparams = {\n    \"objective\": \"binary\",\n    \"metric\": \"binary_logloss\",\n    \"learning_rate\": 0.05,\n    \"num_leaves\": 31,\n    \"feature_fraction\": 0.9,\n    \"bagging_fraction\": 0.8,\n    \"bagging_freq\": 1,\n    \"verbosity\": -1,\n}\n```\n\n## Core Usage\n\n### Native training API\n\nUse `lgb.train()` when you want direct access to `Dataset`, callbacks, ranking groups, or low-level training control.\n\n```python\nimport lightgbm as lgb\n\ntrain_data = lgb.Dataset(X_train, label=y_train)\nvalid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)\n\nparams = {\n    \"objective\": \"binary\",\n    \"metric\": \"binary_logloss\",\n    \"learning_rate\": 0.05,\n    \"num_leaves\": 31,\n    \"verbosity\": -1,\n}\n\nbooster = lgb.train(\n    params,\n    train_data,\n    num_boost_round=300,\n    valid_sets=[valid_data],\n    callbacks=[\n        lgb.early_stopping(stopping_rounds=20),\n        lgb.log_evaluation(period=20),\n    ],\n)\n\npredictions = booster.predict(X_valid, num_iteration=booster.best_iteration)\n```\n\n### Scikit-learn estimators\n\nUse the sklearn wrappers for `Pipeline`, `GridSearchCV`, and the usual estimator API.\n\n```python\nimport lightgbm as lgb\n\nmodel = lgb.LGBMClassifier(\n    objective=\"binary\",\n    n_estimators=300,\n    learning_rate=0.05,\n    num_leaves=31,\n    random_state=42,\n)\n\nmodel.fit(\n    X_train,\n    y_train,\n    eval_set=[(X_valid, y_valid)],\n    eval_metric=\"binary_logloss\",\n    callbacks=[lgb.early_stopping(stopping_rounds=20)],\n)\n\nprobabilities = model.predict_proba(X_valid)[:, 1]\nlabels = model.predict(X_valid)\n```\n\n### Regression\n\n```python\nimport lightgbm as lgb\n\nmodel = lgb.LGBMRegressor(\n    objective=\"regression\",\n    n_estimators=500,\n    learning_rate=0.05,\n    num_leaves=63,\n    random_state=42,\n)\n\nmodel.fit(X_train, y_train)\npredictions = model.predict(X_test)\n```\n\n### Save and load a model\n\n```python\nimport lightgbm as lgb\n\nbooster.save_model(\"model.txt\")\n\nloaded = lgb.Booster(model_file=\"model.txt\")\npredictions = loaded.predict(X_test)\n```\n\nFor sklearn estimators, use the wrapped booster when you need LightGBM-native serialization:\n\n```python\nmodel.booster_.save_model(\"model.txt\")\n```\n\n## Configuration Notes\n\n- There is no service-side authentication layer. Runtime behavior is controlled by model parameters, callbacks, and local build/runtime dependencies.\n- The most important training parameters to set intentionally are usually `objective`, `metric`, `learning_rate`, `num_leaves`, `max_depth`, `min_data_in_leaf`, `feature_fraction`, `bagging_fraction`, and `bagging_freq`.\n- Use `random_state` on sklearn estimators or `seed`-style parameters in the native API when you need reproducible runs.\n- Use `num_threads` or estimator `n_jobs` carefully in constrained CI or container environments; otherwise LightGBM will use multithreading aggressively.\n- Ranking tasks require group information. With the native API, set `group` on the `Dataset`; with sklearn ranking wrappers, pass the group data explicitly to fit and evaluation.\n- LightGBM supports categorical features, but the values must be represented as integer-coded categories or pandas categorical columns. Do not pass raw object/string columns and expect native categorical handling to work automatically.\n\n## Common Pitfalls\n\n- Old blog posts often use `early_stopping_rounds=` directly in estimator calls. In LightGBM 4.x, prefer the documented callback path such as `callbacks=[lgb.early_stopping(...)]`.\n- The sklearn wrapper docs explicitly warn that `**kwargs` is not supported well in sklearn mode and may cause unexpected behavior. Pass documented estimator arguments directly.\n- `num_leaves` is the main complexity control. If you also set a positive `max_depth`, keep `num_leaves <= 2^max_depth` or you can create an inconsistent tree configuration.\n- The upstream tuning guide recommends increasing `min_data_in_leaf` to combat overfitting. Very small values often make models look great on the training set and unstable on validation data.\n- GPU usage is not just a training parameter. It is also an installation and runtime-dependency issue. Confirm that the environment matches the documented OpenCL or CUDA setup before turning on GPU-related parameters.\n- When using early stopping, predict with `best_iteration` or `best_iteration_` instead of blindly using all configured boosting rounds.\n- LightGBM accepts missing values natively, but mixed dtypes and accidental object columns from pandas can still break dataset construction or categorical handling.\n\n## Version-Sensitive Notes For 4.6.0\n\n- PyPI and the official docs align on `4.6.0` for the version covered here, but the docs URL used the floating `latest` docs tree. This doc intentionally uses the versioned docs root `https://lightgbm.readthedocs.io/en/v4.6.0/`.\n- The `4.6.0` release notes add Python `3.13` support and introduce the `bagging_by_query` parameter, so older tuning examples will not mention that option.\n- The `4.5.0` line added the sklearn-compatible `feature_names_in_` attribute. If you are working with older 4.x examples that inspect feature names manually, check whether your installed version already exposes that attribute.\n\n## Official Sources\n\n- LightGBM docs root: `https://lightgbm.readthedocs.io/en/v4.6.0/`\n- Installation guide: `https://lightgbm.readthedocs.io/en/v4.6.0/Installation-Guide.html`\n- Python package intro: `https://lightgbm.readthedocs.io/en/v4.6.0/Python-Intro.html`\n- Python API: `https://lightgbm.readthedocs.io/en/v4.6.0/Python-API.html`\n- Parameters tuning: `https://lightgbm.readthedocs.io/en/v4.6.0/Parameters-Tuning.html`\n- PyPI package page: `https://pypi.org/project/lightgbm/`\n"
  },
  {
    "path": "content/lightning/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Lightning package guide for PyTorch training loops, Trainer orchestration, callbacks, checkpointing, and multi-device execution\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"lightning,pytorch,deep-learning,training,trainer,distributed\"\n---\n\n# Lightning Python Package Guide\n\n## Golden Rule\n\nInstall `lightning`, import the PyTorch API from `lightning.pytorch`, and treat older `pytorch_lightning` examples as legacy unless the project is already pinned to that older package layout.\n\nAs of March 12, 2026, both PyPI and the Lightning PyTorch stable docs point to `lightning 2.6.1`.\n\n## Install\n\nIf you need a specific CUDA, ROCm, or CPU-only PyTorch build, install `torch` the way PyTorch recommends first, then install Lightning on top.\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"lightning==2.6.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"lightning==2.6.1\"\npoetry add \"lightning==2.6.1\"\n```\n\nIf you also need PyTorch in the same step and you are using the default wheel channel:\n\n```bash\npython -m pip install \"torch\" \"lightning==2.6.1\"\n```\n\n## Initialize A Minimal Project\n\nLightning wraps a normal PyTorch model inside a `LightningModule` and delegates orchestration to `Trainer`.\n\n```python\nimport lightning as L\nimport torch\nfrom torch import nn\nfrom torch.utils.data import DataLoader, TensorDataset\n\nclass Classifier(L.LightningModule):\n    def __init__(self, input_dim: int = 32, num_classes: int = 2) -> None:\n        super().__init__()\n        self.save_hyperparameters()\n        self.model = nn.Sequential(\n            nn.Linear(input_dim, 64),\n            nn.ReLU(),\n            nn.Linear(64, num_classes),\n        )\n        self.loss_fn = nn.CrossEntropyLoss()\n\n    def forward(self, x: torch.Tensor) -> torch.Tensor:\n        return self.model(x)\n\n    def training_step(self, batch, batch_idx: int) -> torch.Tensor:\n        x, y = batch\n        logits = self(x)\n        loss = self.loss_fn(logits, y)\n        self.log(\"train_loss\", loss, prog_bar=True, on_step=True, on_epoch=True)\n        return loss\n\n    def validation_step(self, batch, batch_idx: int) -> None:\n        x, y = batch\n        logits = self(x)\n        loss = self.loss_fn(logits, y)\n        preds = logits.argmax(dim=1)\n        acc = (preds == y).float().mean()\n        self.log(\"val_loss\", loss, prog_bar=True)\n        self.log(\"val_acc\", acc, prog_bar=True)\n\n    def configure_optimizers(self):\n        return torch.optim.Adam(self.parameters(), lr=1e-3)\n\ndef make_loader(num_rows: int) -> DataLoader:\n    x = torch.randn(num_rows, 32)\n    y = torch.randint(0, 2, (num_rows,))\n    return DataLoader(TensorDataset(x, y), batch_size=64, shuffle=True)\n\nmodel = Classifier()\ntrain_loader = make_loader(2048)\nval_loader = make_loader(512)\n\ntrainer = L.Trainer(\n    max_epochs=5,\n    accelerator=\"auto\",\n    devices=\"auto\",\n    deterministic=True,\n)\ntrainer.fit(model, train_dataloaders=train_loader, val_dataloaders=val_loader)\n```\n\nUse `self.log(...)` inside module hooks instead of printing metrics manually. Lightning routes those values to the progress bar, logger, callbacks, and checkpoints.\n\n## Use A LightningDataModule For Reusable Data Setup\n\nFor anything beyond a toy script, put data preparation and loader creation in a `LightningDataModule`.\n\n```python\nimport lightning as L\nfrom torch.utils.data import DataLoader, random_split\nfrom torchvision import transforms\nfrom torchvision.datasets import MNIST\n\nclass MNISTDataModule(L.LightningDataModule):\n    def __init__(self, data_dir: str = \"./data\", batch_size: int = 64) -> None:\n        super().__init__()\n        self.data_dir = data_dir\n        self.batch_size = batch_size\n        self.transform = transforms.ToTensor()\n\n    def prepare_data(self) -> None:\n        MNIST(self.data_dir, train=True, download=True)\n        MNIST(self.data_dir, train=False, download=True)\n\n    def setup(self, stage: str | None = None) -> None:\n        if stage in (\"fit\", None):\n            full = MNIST(self.data_dir, train=True, transform=self.transform)\n            self.mnist_train, self.mnist_val = random_split(full, [55_000, 5_000])\n        if stage in (\"test\", None):\n            self.mnist_test = MNIST(self.data_dir, train=False, transform=self.transform)\n\n    def train_dataloader(self) -> DataLoader:\n        return DataLoader(self.mnist_train, batch_size=self.batch_size, shuffle=True)\n\n    def val_dataloader(self) -> DataLoader:\n        return DataLoader(self.mnist_val, batch_size=self.batch_size)\n\n    def test_dataloader(self) -> DataLoader:\n        return DataLoader(self.mnist_test, batch_size=self.batch_size)\n```\n\n`prepare_data()` is for download and disk-side work. `setup()` is for assigning state used by each process, such as train/val/test datasets.\n\n## Trainer Configuration That Matters In Real Projects\n\nThe main control surface is `Trainer(...)`.\n\nUseful defaults to set explicitly:\n\n```python\nfrom lightning.pytorch import Trainer, seed_everything\nfrom lightning.pytorch.callbacks import ModelCheckpoint\n\nseed_everything(42, workers=True)\n\ntrainer = Trainer(\n    accelerator=\"auto\",\n    devices=1,\n    max_epochs=10,\n    default_root_dir=\"artifacts/lightning\",\n    log_every_n_steps=10,\n    deterministic=True,\n    callbacks=[\n        ModelCheckpoint(\n            monitor=\"val_loss\",\n            mode=\"min\",\n            save_top_k=1,\n            filename=\"epoch{epoch:02d}-val_loss{val_loss:.3f}\",\n        )\n    ],\n)\n```\n\nPractical notes:\n\n- `accelerator=\"auto\"` and `devices=\"auto\"` let Lightning pick CPU, GPU, MPS, TPU, or other supported hardware automatically.\n- If you want exactly one device, set `devices=1` instead of relying on auto-detection.\n- `default_root_dir` controls where checkpoints and logs land when you do not pass logger or checkpoint paths explicitly.\n- `seed_everything(42, workers=True)` is the standard reproducibility starting point for dataloader workers and training state.\n- `fast_dev_run=True` is the quickest smoke test for hook wiring, dataloaders, and shape mismatches.\n\n## Checkpointing, Resume, And Inference\n\nLightning checkpointing is built around `Trainer.fit(...)` and `LightningModule.load_from_checkpoint(...)`.\n\n```python\nfrom lightning.pytorch import Trainer\n\ntrainer = Trainer(max_epochs=10)\ntrainer.fit(model, datamodule=datamodule, ckpt_path=\"last\")\n```\n\nLoad a model later:\n\n```python\nmodel = Classifier.load_from_checkpoint(\"artifacts/lightning/checkpoints/best.ckpt\")\n```\n\nRun validation, testing, or prediction from a checkpoint:\n\n```python\ntrainer.validate(model=model, datamodule=datamodule, ckpt_path=\"best\")\ntrainer.test(model=model, datamodule=datamodule, ckpt_path=\"best\")\npredictions = trainer.predict(model=model, datamodule=datamodule, ckpt_path=\"best\")\n```\n\nBy default, validation, test, and predict run under inference mode. If your evaluation code needs gradients, set `inference_mode=False` on the `Trainer`.\n\n## Config, Secrets, And External Integrations\n\nLightning itself does not require API keys or service authentication.\n\nConfiguration usually comes from:\n\n- your experiment config system or CLI\n- environment variables for dataset locations, checkpoint roots, and logger settings\n- credentials required by integrations such as Weights & Biases, MLflow, cloud storage, or remote artifact stores\n\nA simple pattern is to keep Lightning config separate from model code:\n\n```python\nimport os\n\nCHECKPOINT_ROOT = os.getenv(\"LIGHTNING_ROOT_DIR\", \"./artifacts/lightning\")\nMAX_EPOCHS = int(os.getenv(\"LIGHTNING_MAX_EPOCHS\", \"10\"))\nUSE_CUDA = os.getenv(\"LIGHTNING_USE_CUDA\", \"1\") == \"1\"\n```\n\nThen feed those values into `Trainer(...)` rather than hard-coding infrastructure-specific paths.\n\n## Common Pitfalls\n\n- Do not copy old `pytorch_lightning` or `Trainer(gpus=...)` snippets into a `2.6.1` project. Use `lightning` or `lightning.pytorch`, plus `accelerator=` and `devices=`.\n- Do not put dataset objects or process-local state in `prepare_data()`. Use `setup()` for that.\n- Do not manually add a `DistributedSampler` unless you know why. Lightning injects one automatically for distributed strategies unless you disable `use_distributed_sampler`.\n- Do not assume `Trainer()` means single-GPU training. Auto device selection can use all available GPUs on a machine.\n- `save_hyperparameters()` is convenient, but exclude non-serializable objects such as dataset handles, file descriptors, or large live clients.\n- `fast_dev_run=True` is for debugging; it intentionally changes normal training behavior and suppresses some side effects such as full logging and checkpoint flow.\n- Keep `default_root_dir` explicit in scripts and jobs. Otherwise artifacts often end up in an unexpected working directory.\n- If your project mixes raw PyTorch and Lightning hooks, keep the ownership boundary clean. Let Lightning drive the loop and let your module define step logic.\n\n## Version-Sensitive Notes For `2.6.1`\n\n- The stable Lightning PyTorch docs and PyPI both resolve to `2.6.1` as of `2026-03-12`.\n- PyPI metadata for `lightning 2.6.1` requires Python `>=3.10`.\n- Lightning's versioning policy says patch releases are for backward-compatible bug fixes, while minor releases can include backward-incompatible changes with notice. If you need stable training behavior, pin the minor line, for example `lightning~=2.6.1`.\n- The current upgrade guide still matters for older codebases: many `1.x` and early `2.0` examples on the web use removed or renamed Trainer arguments and old import paths.\n\n## Official Sources\n\n- Lightning docs root: https://lightning.ai/docs/pytorch/stable/\n- Installation guide: https://lightning.ai/docs/pytorch/stable/starter/installation.html\n- LightningModule guide: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html\n- DataModule guide: https://lightning.ai/docs/pytorch/stable/data/datamodule.html\n- Trainer guide: https://lightning.ai/docs/pytorch/stable/common/trainer.html\n- GPU basics: https://lightning.ai/docs/pytorch/stable/accelerators/gpu_basic.html\n- Upgrade guide: https://lightning.ai/docs/pytorch/stable/upgrade/migration_guide.html\n- Versioning policy: https://lightning.ai/docs/pytorch/stable/versioning.html\n- PyPI package page: https://pypi.org/project/lightning/\n"
  },
  {
    "path": "content/linear/docs/tracker/DOC.md",
    "content": "---\nname: tracker\ndescription: \"Linear SDK for JavaScript/TypeScript for issue tracking and project management via GraphQL\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"62.0.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"linear,tracker,issues,project-management,graphql\"\n---\n\n# Linear SDK for JavaScript/TypeScript\n\n## Golden Rule\n\n**ALWAYS use `@linear/sdk` version 62.0.0 or later.**\n\nInstall with:\n```bash\nnpm install @linear/sdk\n```\n\n**DO NOT use:**\n- Unofficial Linear packages\n- Direct GraphQL requests without the SDK (unless specifically required)\n- Deprecated authentication methods\n- Outdated Linear client libraries\n\nThe `@linear/sdk` is the official Linear TypeScript SDK that provides strongly-typed access to Linear's GraphQL API.\n\n---\n\n## Installation\n\n### Install the SDK\n\n```bash\nnpm install @linear/sdk\n```\n\n### Environment Setup\n\nCreate a `.env` file:\n\n```bash\nLINEAR_API_KEY=lin_api_your_personal_api_key_here\n# OR for OAuth\nLINEAR_ACCESS_TOKEN=your_oauth_access_token_here\n```\n\n### TypeScript Configuration (Optional)\n\nThe SDK ships with TypeScript types. No additional `@types` package needed.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"commonjs\",\n    \"esModuleInterop\": true,\n    \"strict\": true\n  }\n}\n```\n\n---\n\n## Initialization\n\n### Import the Client\n\n```typescript\nimport { LinearClient } from '@linear/sdk'\n```\n\n```javascript\nconst { LinearClient } = require('@linear/sdk')\n```\n\n### Authentication with API Key\n\n```typescript\nimport { LinearClient } from '@linear/sdk'\n\nconst client = new LinearClient({\n  apiKey: process.env.LINEAR_API_KEY\n})\n```\n\n```javascript\nconst { LinearClient } = require('@linear/sdk')\nrequire('dotenv').config()\n\nconst client = new LinearClient({\n  apiKey: process.env.LINEAR_API_KEY\n})\n```\n\n### Authentication with OAuth 2.0\n\n```typescript\nconst client = new LinearClient({\n  accessToken: process.env.LINEAR_ACCESS_TOKEN\n})\n```\n\n### Get Current User\n\n```typescript\nasync function getCurrentUser() {\n  const me = await client.viewer\n  console.log(`Logged in as: ${me.name} (${me.email})`)\n  return me\n}\n```\n\n---\n\n## Core API Surfaces\n\n### Issues\n\n#### Fetch All Issues\n\n**Minimal:**\n\n```typescript\nasync function getAllIssues() {\n  const issues = await client.issues()\n\n  issues.nodes.forEach(issue => {\n    console.log(`${issue.identifier}: ${issue.title}`)\n  })\n\n  return issues\n}\n```\n\n**Advanced with Pagination:**\n\n```typescript\nasync function getIssuesPaginated() {\n  const issues = await client.issues({\n    first: 50,\n    orderBy: 'createdAt'\n  })\n\n  for (const issue of issues.nodes) {\n    console.log(`[${issue.identifier}] ${issue.title}`)\n    console.log(`  Status: ${(await issue.state)?.name}`)\n    console.log(`  Assignee: ${(await issue.assignee)?.displayName || 'Unassigned'}`)\n    console.log(`  Priority: ${issue.priority}`)\n  }\n\n  // Handle pagination\n  if (issues.pageInfo.hasNextPage) {\n    const nextPage = await client.issues({\n      first: 50,\n      after: issues.pageInfo.endCursor\n    })\n    // Process next page\n  }\n\n  return issues\n}\n```\n\n#### Get User's Assigned Issues\n\n```typescript\nasync function getMyIssues() {\n  const me = await client.viewer\n  const myIssues = await me.assignedIssues()\n\n  if (myIssues.nodes.length) {\n    myIssues.nodes.forEach(issue => {\n      console.log(`${me.displayName} has issue: ${issue.title}`)\n    })\n  }\n\n  return myIssues\n}\n```\n\n#### Query Single Issue by ID\n\n```typescript\nasync function getIssueById(issueId: string) {\n  const issue = await client.issue(issueId)\n\n  console.log(`Title: ${issue.title}`)\n  console.log(`Description: ${issue.description}`)\n  console.log(`Created: ${issue.createdAt}`)\n\n  const state = await issue.state\n  console.log(`State: ${state?.name}`)\n\n  const assignee = await issue.assignee\n  console.log(`Assignee: ${assignee?.displayName}`)\n\n  return issue\n}\n\n// Usage: Can use UUID or identifier like \"ENG-123\"\ngetIssueById(\"ENG-123\")\n```\n\n#### Create Issue\n\n**Minimal:**\n\n```typescript\nasync function createIssue(teamId: string, title: string) {\n  const issuePayload = await client.issueCreate({\n    teamId: teamId,\n    title: title\n  })\n\n  if (issuePayload.success) {\n    console.log(`Created issue: ${issuePayload.issue?.identifier}`)\n    return issuePayload.issue\n  } else {\n    throw new Error('Failed to create issue')\n  }\n}\n```\n\n**Advanced with All Fields:**\n\n```typescript\nasync function createDetailedIssue() {\n  // First get team ID\n  const teams = await client.teams()\n  const team = teams.nodes[0]\n\n  // Get workflow state\n  const states = await client.workflowStates({\n    filter: { team: { id: { eq: team.id } } }\n  })\n  const todoState = states.nodes.find(s => s.name === 'Todo')\n\n  // Get labels\n  const labels = await client.issueLabels()\n  const bugLabel = labels.nodes.find(l => l.name === 'Bug')\n\n  const issuePayload = await client.issueCreate({\n    teamId: team.id,\n    title: 'Fix authentication error',\n    description: '## Problem\\n\\nUsers cannot log in\\n\\n## Steps to reproduce\\n\\n1. Go to login\\n2. Enter credentials',\n    priority: 1, // 0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low\n    estimate: 3, // Story points\n    stateId: todoState?.id,\n    labelIds: bugLabel ? [bugLabel.id] : [],\n    assigneeId: (await client.viewer).id,\n    dueDate: new Date('2025-12-31')\n  })\n\n  if (issuePayload.success) {\n    return issuePayload.issue\n  }\n\n  throw new Error('Failed to create issue')\n}\n```\n\n#### Update Issue\n\n**Minimal:**\n\n```typescript\nasync function updateIssue(issueId: string, title: string) {\n  const updatePayload = await client.issueUpdate(issueId, {\n    title: title\n  })\n\n  if (updatePayload.success) {\n    console.log('Issue updated')\n    return updatePayload.issue\n  }\n}\n```\n\n**Advanced:**\n\n```typescript\nasync function updateIssueComplete(issueId: string) {\n  // Get \"Done\" state\n  const issue = await client.issue(issueId)\n  const team = await issue.team\n  const states = await client.workflowStates({\n    filter: { team: { id: { eq: team.id } } }\n  })\n  const doneState = states.nodes.find(s => s.name === 'Done')\n\n  const updatePayload = await client.issueUpdate(issueId, {\n    stateId: doneState?.id,\n    title: 'Updated Issue Title',\n    description: 'New description',\n    priority: 3,\n    estimate: 5\n  })\n\n  if (updatePayload.success) {\n    console.log(`Updated: ${updatePayload.issue?.title}`)\n    return updatePayload.issue\n  }\n}\n```\n\n#### Filter Issues\n\n```typescript\nasync function filterIssues() {\n  const issues = await client.issues({\n    filter: {\n      assignee: {\n        email: { eq: 'user@example.com' }\n      },\n      state: {\n        name: { in: ['Todo', 'In Progress'] }\n      },\n      priority: {\n        gte: 2 // High priority and above\n      },\n      createdAt: {\n        gte: new Date('2025-01-01')\n      }\n    },\n    orderBy: 'priority',\n    first: 25\n  })\n\n  return issues.nodes\n}\n```\n\n#### Complex Filtering with AND/OR\n\n```typescript\nasync function complexFilterIssues() {\n  const issues = await client.issues({\n    filter: {\n      or: [\n        { priority: { eq: 1 } }, // Urgent\n        {\n          and: [\n            { priority: { eq: 2 } }, // High\n            { dueDate: { lte: new Date() } } // Overdue\n          ]\n        }\n      ]\n    }\n  })\n\n  return issues.nodes\n}\n```\n\n#### Archive Issue\n\n```typescript\nasync function archiveIssue(issueId: string) {\n  const payload = await client.issueArchive(issueId)\n\n  if (payload.success) {\n    console.log('Issue archived')\n  }\n\n  return payload\n}\n```\n\n### Comments\n\n#### Get Issue Comments\n\n```typescript\nasync function getIssueComments(issueId: string) {\n  const issue = await client.issue(issueId)\n  const comments = await issue.comments()\n\n  for (const comment of comments.nodes) {\n    const user = await comment.user\n    console.log(`${user?.displayName}: ${comment.body}`)\n    console.log(`Posted: ${comment.createdAt}`)\n  }\n\n  return comments\n}\n```\n\n#### Create Comment\n\n**Minimal:**\n\n```typescript\nasync function addComment(issueId: string, body: string) {\n  const commentPayload = await client.commentCreate({\n    issueId: issueId,\n    body: body\n  })\n\n  if (commentPayload.success) {\n    console.log('Comment added')\n    return commentPayload.comment\n  }\n\n  throw new Error('Failed to create comment')\n}\n```\n\n**Advanced with Markdown:**\n\n```typescript\nasync function addDetailedComment(issueId: string) {\n  const body = `## Update\n\nI've investigated this issue and found:\n\n- The authentication token expires too quickly\n- Need to implement refresh token logic\n\n**Next steps:**\n1. Update token service\n2. Add refresh endpoint\n3. Test token renewal\n\ncc @teammate`\n\n  const commentPayload = await client.commentCreate({\n    issueId: issueId,\n    body: body\n  })\n\n  return commentPayload.comment\n}\n```\n\n#### Update Comment\n\n```typescript\nasync function updateComment(commentId: string, newBody: string) {\n  const payload = await client.commentUpdate(commentId, {\n    body: newBody\n  })\n\n  if (payload.success) {\n    return payload.comment\n  }\n}\n```\n\n#### Delete Comment\n\n```typescript\nasync function deleteComment(commentId: string) {\n  const payload = await client.commentDelete(commentId)\n\n  if (payload.success) {\n    console.log('Comment deleted')\n  }\n\n  return payload\n}\n```\n\n### Teams\n\n#### Get All Teams\n\n```typescript\nasync function getTeams() {\n  const teams = await client.teams()\n\n  teams.nodes.forEach(team => {\n    console.log(`${team.name} (${team.key})`)\n  })\n\n  return teams\n}\n```\n\n#### Get Team by ID\n\n```typescript\nasync function getTeam(teamId: string) {\n  const team = await client.team(teamId)\n\n  console.log(`Team: ${team.name}`)\n  console.log(`Key: ${team.key}`)\n  console.log(`Description: ${team.description}`)\n\n  return team\n}\n```\n\n#### Get Team Issues\n\n```typescript\nasync function getTeamIssues(teamId: string) {\n  const team = await client.team(teamId)\n  const issues = await team.issues({\n    first: 50,\n    orderBy: 'updatedAt'\n  })\n\n  console.log(`${team.name} has ${issues.nodes.length} issues`)\n\n  return issues\n}\n```\n\n#### Get Team Members\n\n```typescript\nasync function getTeamMembers(teamId: string) {\n  const team = await client.team(teamId)\n  const members = await team.members()\n\n  for (const member of members.nodes) {\n    console.log(`${member.displayName} - ${member.email}`)\n  }\n\n  return members\n}\n```\n\n### Projects\n\n#### Get All Projects\n\n```typescript\nasync function getProjects() {\n  const projects = await client.projects()\n\n  for (const project of projects.nodes) {\n    console.log(`${project.name}`)\n    console.log(`  State: ${project.state}`)\n    console.log(`  Progress: ${project.progress}%`)\n  }\n\n  return projects\n}\n```\n\n#### Get Project by ID\n\n```typescript\nasync function getProject(projectId: string) {\n  const project = await client.project(projectId)\n\n  console.log(`Project: ${project.name}`)\n  console.log(`Description: ${project.description}`)\n  console.log(`Start: ${project.startDate}`)\n  console.log(`Target: ${project.targetDate}`)\n\n  const lead = await project.lead\n  console.log(`Lead: ${lead?.displayName}`)\n\n  return project\n}\n```\n\n#### Get Project Issues\n\n```typescript\nasync function getProjectIssues(projectId: string) {\n  const project = await client.project(projectId)\n  const issues = await project.issues()\n\n  console.log(`${project.name} issues:`)\n  issues.nodes.forEach(issue => {\n    console.log(`  - ${issue.identifier}: ${issue.title}`)\n  })\n\n  return issues\n}\n```\n\n#### Create Project\n\n```typescript\nasync function createProject(teamId: string) {\n  const payload = await client.projectCreate({\n    teamIds: [teamId],\n    name: 'Q4 Authentication Improvements',\n    description: 'Improve authentication flow and security',\n    state: 'started',\n    targetDate: new Date('2025-12-31')\n  })\n\n  if (payload.success) {\n    return payload.project\n  }\n}\n```\n\n#### Update Project\n\n```typescript\nasync function updateProject(projectId: string) {\n  const payload = await client.projectUpdate(projectId, {\n    state: 'completed',\n    progress: 100\n  })\n\n  if (payload.success) {\n    console.log('Project completed')\n    return payload.project\n  }\n}\n```\n\n### Labels\n\n#### Get All Labels\n\n```typescript\nasync function getLabels() {\n  const labels = await client.issueLabels()\n\n  labels.nodes.forEach(label => {\n    console.log(`${label.name} - ${label.color}`)\n  })\n\n  return labels\n}\n```\n\n#### Get Label by ID\n\n```typescript\nasync function getLabel(labelId: string) {\n  const label = await client.issueLabel(labelId)\n\n  console.log(`Label: ${label.name}`)\n  console.log(`Description: ${label.description}`)\n\n  return label\n}\n```\n\n#### Create Label\n\n```typescript\nasync function createLabel(teamId: string) {\n  const payload = await client.issueLabelCreate({\n    teamId: teamId,\n    name: 'security',\n    description: 'Security related issues',\n    color: '#ff0000'\n  })\n\n  if (payload.success) {\n    return payload.issueLabel\n  }\n}\n```\n\n#### Filter Issues by Label\n\n```typescript\nasync function getIssuesByLabel(labelName: string) {\n  const issues = await client.issues({\n    filter: {\n      labels: {\n        name: { eq: labelName }\n      }\n    }\n  })\n\n  return issues.nodes\n}\n```\n\n### Workflow States\n\n#### Get All Workflow States\n\n```typescript\nasync function getWorkflowStates() {\n  const states = await client.workflowStates()\n\n  states.nodes.forEach(state => {\n    console.log(`${state.name} (${state.type})`)\n  })\n\n  return states\n}\n```\n\n#### Get Workflow States for Team\n\n```typescript\nasync function getTeamWorkflowStates(teamId: string) {\n  const states = await client.workflowStates({\n    filter: {\n      team: { id: { eq: teamId } }\n    }\n  })\n\n  console.log('Available states:')\n  states.nodes.forEach(state => {\n    console.log(`  - ${state.name}`)\n  })\n\n  return states\n}\n```\n\n#### Get Issues in Specific State\n\n```typescript\nasync function getIssuesInState(stateId: string) {\n  const state = await client.workflowState(stateId)\n  const issues = await state.issues()\n\n  console.log(`Issues in \"${state.name}\":`)\n  issues.nodes.forEach(issue => {\n    console.log(`  ${issue.identifier}: ${issue.title}`)\n  })\n\n  return issues\n}\n```\n\n### Users\n\n#### Get Current User\n\n```typescript\nasync function getCurrentUser() {\n  const me = await client.viewer\n\n  console.log(`Name: ${me.displayName}`)\n  console.log(`Email: ${me.email}`)\n  console.log(`Admin: ${me.admin}`)\n\n  return me\n}\n```\n\n#### Get User by ID\n\n```typescript\nasync function getUser(userId: string) {\n  const user = await client.user(userId)\n\n  console.log(`${user.displayName}`)\n  console.log(`Email: ${user.email}`)\n  console.log(`Active: ${user.active}`)\n\n  return user\n}\n```\n\n#### Get All Users\n\n```typescript\nasync function getUsers() {\n  const users = await client.users()\n\n  users.nodes.forEach(user => {\n    console.log(`${user.displayName} - ${user.email}`)\n  })\n\n  return users\n}\n```\n\n#### Get User's Teams\n\n```typescript\nasync function getUserTeams(userId: string) {\n  const user = await client.user(userId)\n  const teams = await user.teams()\n\n  console.log(`${user.displayName}'s teams:`)\n  teams.nodes.forEach(team => {\n    console.log(`  - ${team.name}`)\n  })\n\n  return teams\n}\n```\n\n### Cycles\n\n#### Get Active Cycles\n\n```typescript\nasync function getActiveCycles() {\n  const cycles = await client.cycles({\n    filter: {\n      isActive: { eq: true }\n    }\n  })\n\n  for (const cycle of cycles.nodes) {\n    console.log(`${cycle.name}`)\n    console.log(`  Start: ${cycle.startsAt}`)\n    console.log(`  End: ${cycle.endsAt}`)\n    console.log(`  Progress: ${cycle.progress}%`)\n  }\n\n  return cycles\n}\n```\n\n#### Get Cycle Issues\n\n```typescript\nasync function getCycleIssues(cycleId: string) {\n  const cycle = await client.cycle(cycleId)\n  const issues = await cycle.issues()\n\n  console.log(`${cycle.name} issues:`)\n  issues.nodes.forEach(issue => {\n    console.log(`  ${issue.identifier}: ${issue.title}`)\n  })\n\n  return issues\n}\n```\n\n### Attachments\n\n#### Create Attachment\n\n```typescript\nasync function createAttachment(issueId: string) {\n  const payload = await client.attachmentCreate({\n    issueId: issueId,\n    title: 'Design Mockup',\n    url: 'https://example.com/mockup.png',\n    subtitle: 'Login page redesign'\n  })\n\n  if (payload.success) {\n    return payload.attachment\n  }\n}\n```\n\n#### Get Issue Attachments\n\n```typescript\nasync function getIssueAttachments(issueId: string) {\n  const issue = await client.issue(issueId)\n  const attachments = await issue.attachments()\n\n  attachments.nodes.forEach(attachment => {\n    console.log(`${attachment.title}: ${attachment.url}`)\n  })\n\n  return attachments\n}\n```\n\n### Webhooks\n\n#### Create Webhook\n\n```typescript\nasync function createWebhook() {\n  const payload = await client.webhookCreate({\n    url: 'https://example.com/webhook',\n    label: 'Issue Updates',\n    resourceTypes: ['Issue', 'Comment'],\n    enabled: true\n  })\n\n  if (payload.success) {\n    console.log(`Webhook created: ${payload.webhook?.id}`)\n    return payload.webhook\n  }\n}\n```\n\n#### Get Webhooks\n\n```typescript\nasync function getWebhooks() {\n  const webhooks = await client.webhooks()\n\n  webhooks.nodes.forEach(webhook => {\n    console.log(`${webhook.label}`)\n    console.log(`  URL: ${webhook.url}`)\n    console.log(`  Enabled: ${webhook.enabled}`)\n    console.log(`  Resources: ${webhook.resourceTypes.join(', ')}`)\n  })\n\n  return webhooks\n}\n```\n\n#### Update Webhook\n\n```typescript\nasync function updateWebhook(webhookId: string) {\n  const payload = await client.webhookUpdate(webhookId, {\n    enabled: false\n  })\n\n  if (payload.success) {\n    return payload.webhook\n  }\n}\n```\n\n#### Delete Webhook\n\n```typescript\nasync function deleteWebhook(webhookId: string) {\n  const payload = await client.webhookDelete(webhookId)\n\n  if (payload.success) {\n    console.log('Webhook deleted')\n  }\n\n  return payload\n}\n```\n\n### Search\n\n#### Search Issues\n\n```typescript\nasync function searchIssues(query: string) {\n  const results = await client.searchIssues(query)\n\n  results.nodes.forEach(issue => {\n    console.log(`${issue.identifier}: ${issue.title}`)\n  })\n\n  return results\n}\n\n// Usage\nsearchIssues('authentication bug')\n```\n\n#### Search Projects\n\n```typescript\nasync function searchProjects(query: string) {\n  const results = await client.searchProjects(query)\n\n  results.nodes.forEach(project => {\n    console.log(`${project.name}`)\n  })\n\n  return results\n}\n```\n\n---\n\n## Pagination\n\n### Basic Pagination\n\n```typescript\nasync function paginateIssues() {\n  let allIssues = []\n  let hasNextPage = true\n  let cursor = null\n\n  while (hasNextPage) {\n    const issues = await client.issues({\n      first: 50,\n      after: cursor\n    })\n\n    allIssues.push(...issues.nodes)\n\n    hasNextPage = issues.pageInfo.hasNextPage\n    cursor = issues.pageInfo.endCursor\n  }\n\n  console.log(`Total issues: ${allIssues.length}`)\n  return allIssues\n}\n```\n\n### Reverse Pagination\n\n```typescript\nasync function paginateReverse() {\n  const issues = await client.issues({\n    last: 25,\n    before: someCursor\n  })\n\n  return issues.nodes\n}\n```\n\n---\n\n## Error Handling\n\n### Try-Catch Pattern\n\n```typescript\nasync function safeCreateIssue(teamId: string, title: string) {\n  try {\n    const payload = await client.issueCreate({\n      teamId: teamId,\n      title: title\n    })\n\n    if (!payload.success) {\n      console.error('Issue creation failed')\n      return null\n    }\n\n    return payload.issue\n  } catch (error) {\n    console.error('Error creating issue:', error.message)\n    throw error\n  }\n}\n```\n\n### Check Success Field\n\n```typescript\nasync function updateWithCheck(issueId: string) {\n  const payload = await client.issueUpdate(issueId, {\n    title: 'Updated Title'\n  })\n\n  if (payload.success) {\n    console.log('Update successful')\n    return payload.issue\n  } else {\n    console.error('Update failed')\n    return null\n  }\n}\n```\n\n---\n\n## Advanced Operations\n\n### Batch Operations\n\n```typescript\nasync function batchCreateIssues(teamId: string, titles: string[]) {\n  const promises = titles.map(title =>\n    client.issueCreate({\n      teamId: teamId,\n      title: title\n    })\n  )\n\n  const results = await Promise.all(promises)\n\n  const created = results.filter(r => r.success)\n  console.log(`Created ${created.length}/${titles.length} issues`)\n\n  return created.map(r => r.issue)\n}\n```\n\n### Complex Relationships\n\n```typescript\nasync function getCompleteIssueData(issueId: string) {\n  const issue = await client.issue(issueId)\n\n  // Fetch all related data\n  const [state, assignee, team, comments, attachments, labels, project, cycle] = await Promise.all([\n    issue.state,\n    issue.assignee,\n    issue.team,\n    issue.comments(),\n    issue.attachments(),\n    issue.labels(),\n    issue.project,\n    issue.cycle\n  ])\n\n  return {\n    issue,\n    state,\n    assignee,\n    team,\n    comments: comments.nodes,\n    attachments: attachments.nodes,\n    labels: labels.nodes,\n    project,\n    cycle\n  }\n}\n```\n\n### Conditional Updates\n\n```typescript\nasync function updateIfAssigned(issueId: string) {\n  const issue = await client.issue(issueId)\n  const assignee = await issue.assignee\n\n  if (assignee) {\n    await client.issueUpdate(issueId, {\n      priority: 2 // Increase priority if assigned\n    })\n  }\n}\n```\n\n### Archive Completed Issues\n\n```typescript\nasync function archiveCompletedIssues(teamId: string) {\n  const team = await client.team(teamId)\n  const states = await client.workflowStates({\n    filter: { team: { id: { eq: teamId } } }\n  })\n\n  const doneState = states.nodes.find(s => s.name === 'Done')\n\n  if (!doneState) return\n\n  const issues = await client.issues({\n    filter: {\n      state: { id: { eq: doneState.id } },\n      completedAt: { lte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) } // 30 days ago\n    }\n  })\n\n  for (const issue of issues.nodes) {\n    await client.issueArchive(issue.id)\n    console.log(`Archived: ${issue.identifier}`)\n  }\n}\n```\n\n---\n\n## Real-World Examples\n\n### Daily Standup Report\n\n```typescript\nasync function generateStandupReport() {\n  const me = await client.viewer\n  const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000)\n\n  // Issues completed yesterday\n  const completed = await client.issues({\n    filter: {\n      assignee: { id: { eq: me.id } },\n      completedAt: { gte: yesterday }\n    }\n  })\n\n  // Issues in progress\n  const inProgress = await client.issues({\n    filter: {\n      assignee: { id: { eq: me.id } },\n      state: { name: { eq: 'In Progress' } }\n    }\n  })\n\n  console.log('## Completed Yesterday')\n  completed.nodes.forEach(i => console.log(`- ${i.identifier}: ${i.title}`))\n\n  console.log('\\n## In Progress')\n  inProgress.nodes.forEach(i => console.log(`- ${i.identifier}: ${i.title}`))\n\n  return { completed: completed.nodes, inProgress: inProgress.nodes }\n}\n```\n\n### Team Velocity Report\n\n```typescript\nasync function calculateTeamVelocity(teamId: string, days: number = 7) {\n  const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000)\n\n  const completed = await client.issues({\n    filter: {\n      team: { id: { eq: teamId } },\n      completedAt: { gte: since }\n    }\n  })\n\n  let totalEstimate = 0\n  for (const issue of completed.nodes) {\n    totalEstimate += issue.estimate || 0\n  }\n\n  console.log(`Team completed ${completed.nodes.length} issues`)\n  console.log(`Total points: ${totalEstimate}`)\n  console.log(`Velocity: ${(totalEstimate / days * 7).toFixed(1)} points/week`)\n\n  return {\n    issueCount: completed.nodes.length,\n    totalPoints: totalEstimate,\n    velocityPerWeek: totalEstimate / days * 7\n  }\n}\n```\n\n### Bug Triage\n\n```typescript\nasync function triageBugs(teamId: string) {\n  const labels = await client.issueLabels()\n  const bugLabel = labels.nodes.find(l => l.name.toLowerCase() === 'bug')\n\n  if (!bugLabel) {\n    console.log('No bug label found')\n    return\n  }\n\n  const bugs = await client.issues({\n    filter: {\n      team: { id: { eq: teamId } },\n      labels: { id: { eq: bugLabel.id } },\n      priority: { eq: 0 } // No priority set\n    },\n    orderBy: 'createdAt'\n  })\n\n  console.log(`Found ${bugs.nodes.length} untriaged bugs`)\n\n  for (const bug of bugs.nodes) {\n    console.log(`\\n${bug.identifier}: ${bug.title}`)\n    console.log(`Created: ${bug.createdAt}`)\n\n    // Auto-prioritize based on keywords\n    const desc = (bug.description || '').toLowerCase()\n    let priority = 4 // Low\n\n    if (desc.includes('crash') || desc.includes('error')) {\n      priority = 2 // High\n    } else if (desc.includes('login') || desc.includes('payment')) {\n      priority = 1 // Urgent\n    }\n\n    await client.issueUpdate(bug.id, { priority })\n    console.log(`Set priority to ${priority}`)\n  }\n}\n```\n\n### Sync GitHub Issues to Linear\n\n```typescript\nasync function syncGitHubIssue(teamId: string, githubIssue: any) {\n  const existingIssues = await client.issues({\n    filter: {\n      team: { id: { eq: teamId } },\n      title: { contains: githubIssue.title }\n    }\n  })\n\n  if (existingIssues.nodes.length > 0) {\n    console.log('Issue already exists')\n    return existingIssues.nodes[0]\n  }\n\n  const labels = await client.issueLabels()\n  const githubLabel = labels.nodes.find(l => l.name === 'github')\n\n  const payload = await client.issueCreate({\n    teamId: teamId,\n    title: githubIssue.title,\n    description: `${githubIssue.body}\\n\\n---\\nSource: ${githubIssue.html_url}`,\n    labelIds: githubLabel ? [githubLabel.id] : []\n  })\n\n  if (payload.success) {\n    console.log(`Created Linear issue: ${payload.issue?.identifier}`)\n    return payload.issue\n  }\n}\n```\n\n### Automated Sprint Planning\n\n```typescript\nasync function planSprint(teamId: string, sprintCapacity: number) {\n  const states = await client.workflowStates({\n    filter: { team: { id: { eq: teamId } } }\n  })\n  const backlogState = states.nodes.find(s => s.name === 'Backlog')\n  const todoState = states.nodes.find(s => s.name === 'Todo')\n\n  if (!backlogState || !todoState) return\n\n  const backlogIssues = await client.issues({\n    filter: {\n      team: { id: { eq: teamId } },\n      state: { id: { eq: backlogState.id } }\n    },\n    orderBy: 'priority'\n  })\n\n  let totalEstimate = 0\n  const sprintIssues = []\n\n  for (const issue of backlogIssues.nodes) {\n    const estimate = issue.estimate || 1\n\n    if (totalEstimate + estimate <= sprintCapacity) {\n      await client.issueUpdate(issue.id, {\n        stateId: todoState.id\n      })\n\n      sprintIssues.push(issue)\n      totalEstimate += estimate\n\n      console.log(`Added to sprint: ${issue.identifier} (${estimate} points)`)\n    }\n\n    if (totalEstimate >= sprintCapacity) break\n  }\n\n  console.log(`\\nSprint planned with ${totalEstimate}/${sprintCapacity} points`)\n  return sprintIssues\n}\n```\n\n---\n\n## Environment Variable Configuration\n\n### Complete Setup Example\n\n```typescript\nimport { LinearClient } from '@linear/sdk'\nimport * as dotenv from 'dotenv'\n\ndotenv.config()\n\ninterface LinearConfig {\n  apiKey?: string\n  accessToken?: string\n}\n\nfunction createLinearClient(): LinearClient {\n  const config: LinearConfig = {}\n\n  if (process.env.LINEAR_API_KEY) {\n    config.apiKey = process.env.LINEAR_API_KEY\n  } else if (process.env.LINEAR_ACCESS_TOKEN) {\n    config.accessToken = process.env.LINEAR_ACCESS_TOKEN\n  } else {\n    throw new Error('LINEAR_API_KEY or LINEAR_ACCESS_TOKEN must be set')\n  }\n\n  return new LinearClient(config)\n}\n\nexport const client = createLinearClient()\n```\n\n---\n\n## Type Definitions\n\n### Important Types\n\n```typescript\nimport {\n  LinearClient,\n  LinearFetch,\n  User,\n  Issue,\n  IssueConnection,\n  Team,\n  Project,\n  Comment,\n  WorkflowState,\n  IssueLabel\n} from '@linear/sdk'\n\n// LinearFetch is a Promise-like type\nconst user: LinearFetch<User> = client.viewer\n\n// Connections have nodes and pageInfo\nconst issues: LinearFetch<IssueConnection> = client.issues()\n\n// Access the actual data\nconst issuesData = await issues\nconst firstIssue: Issue = issuesData.nodes[0]\n```\n\n### Custom Types\n\n```typescript\ninterface IssueWithDetails {\n  issue: Issue\n  state: WorkflowState | null\n  assignee: User | null\n  team: Team\n  labels: IssueLabel[]\n}\n\nasync function getIssueWithDetails(id: string): Promise<IssueWithDetails> {\n  const issue = await client.issue(id)\n\n  return {\n    issue,\n    state: await issue.state,\n    assignee: await issue.assignee,\n    team: await issue.team,\n    labels: (await issue.labels()).nodes\n  }\n}\n```\n\n---\n\n## Priority Values\n\n```typescript\n// Priority mapping\nconst PRIORITY = {\n  NONE: 0,\n  URGENT: 1,\n  HIGH: 2,\n  MEDIUM: 3,\n  LOW: 4\n}\n\n// Usage\nawait client.issueCreate({\n  teamId: teamId,\n  title: 'Critical bug',\n  priority: PRIORITY.URGENT\n})\n```\n\n---\n\n## GraphQL Direct Queries (Advanced)\n\n### Raw GraphQL Query\n\n```typescript\nasync function rawGraphQL() {\n  const query = `\n    query {\n      viewer {\n        id\n        name\n        assignedIssues(first: 10) {\n          nodes {\n            id\n            title\n            state {\n              name\n            }\n          }\n        }\n      }\n    }\n  `\n\n  // The SDK wraps the GraphQL API, but you can access raw client if needed\n  // For most use cases, use the typed SDK methods instead\n}\n```\n\n---\n\n## Complete Application Example\n\n```typescript\nimport { LinearClient } from '@linear/sdk'\nimport * as dotenv from 'dotenv'\n\ndotenv.config()\n\nconst client = new LinearClient({\n  apiKey: process.env.LINEAR_API_KEY\n})\n\nasync function main() {\n  try {\n    // Get current user\n    const me = await client.viewer\n    console.log(`Logged in as: ${me.displayName}`)\n\n    // Get teams\n    const teams = await client.teams()\n    const myTeam = teams.nodes[0]\n    console.log(`Working with team: ${myTeam.name}`)\n\n    // Create an issue\n    const issuePayload = await client.issueCreate({\n      teamId: myTeam.id,\n      title: 'Test issue from SDK',\n      description: 'This is a test issue created via the Linear SDK',\n      priority: 3\n    })\n\n    if (issuePayload.success && issuePayload.issue) {\n      const issue = issuePayload.issue\n      console.log(`Created issue: ${issue.identifier}`)\n\n      // Add a comment\n      const commentPayload = await client.commentCreate({\n        issueId: issue.id,\n        body: 'First comment on this issue!'\n      })\n\n      if (commentPayload.success) {\n        console.log('Comment added')\n      }\n\n      // Get workflow states\n      const states = await client.workflowStates({\n        filter: { team: { id: { eq: myTeam.id } } }\n      })\n\n      const inProgressState = states.nodes.find(s => s.name === 'In Progress')\n\n      if (inProgressState) {\n        // Update issue state\n        const updatePayload = await client.issueUpdate(issue.id, {\n          stateId: inProgressState.id\n        })\n\n        if (updatePayload.success) {\n          console.log('Issue moved to In Progress')\n        }\n      }\n\n      // Get updated issue data\n      const updatedIssue = await client.issue(issue.id)\n      const currentState = await updatedIssue.state\n      console.log(`Current state: ${currentState?.name}`)\n\n      // Get all comments\n      const comments = await updatedIssue.comments()\n      console.log(`Issue has ${comments.nodes.length} comment(s)`)\n    }\n\n  } catch (error) {\n    console.error('Error:', error.message)\n  }\n}\n\nmain()\n```\n"
  },
  {
    "path": "content/litellm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"litellm package guide for Python with multi-provider LLM calls, auth, routing, responses API, and proxy setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.82.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"litellm,llm,openai,anthropic,routing,proxy,python\"\n---\n\n# litellm Python Package Guide\n\n## What It Is\n\n`litellm` is a Python package for calling multiple LLM providers through a mostly OpenAI-shaped interface. Use it when you need one client layer across providers, want to swap models without rewriting the whole call path, or need routing and fallback logic on top of provider SDKs.\n\nThe package can be used in two distinct modes:\n\n- Direct Python SDK calls such as `completion()`, `acompletion()`, and `responses()`\n- Optional proxy or gateway mode if you install the `proxy` extra\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.82.1`.\n- The official docs site is unversioned. Use the docs for current API shape and provider behavior, but use the versioned PyPI release page when you need an exact package pin.\n- The PyPI release page for `1.82.1` was current on 2026-03-12 and lists `proxy` as a published extra.\n- Provider coverage changes quickly. Before using embeddings, responses, rerank, image generation, or other non-chat endpoints, verify support on the LiteLLM provider page for that provider.\n\n## Install\n\nBase SDK install:\n\n```bash\npython -m pip install \"litellm==1.82.1\"\n```\n\nInstall the proxy extra only if you need LiteLLM's proxy or gateway features:\n\n```bash\npython -m pip install \"litellm[proxy]==1.82.1\"\n```\n\n## Authentication And Provider Setup\n\nLiteLLM supports both explicit credentials and provider environment variables.\n\n- For deterministic scripts and tests, pass `api_key=` directly.\n- For local development and deployed apps, provider environment variables are usually cleaner.\n- For OpenAI-compatible endpoints or gateways, pass `base_url=` explicitly.\n\nCommon provider environment variables from the official docs:\n\n- `OPENAI_API_KEY`\n- `ANTHROPIC_API_KEY`\n\nMinimal shell setup:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n```\n\nIf you are targeting a provider-specific model family, verify the exact model name and any provider prefix on that provider's LiteLLM page before writing code.\n\n## Core Usage\n\n### Synchronous chat completion\n\n```python\nimport os\n\nfrom litellm import completion\n\nresponse = completion(\n    model=\"gpt-4o\",\n    messages=[\n        {\"role\": \"user\", \"content\": \"Reply with one short sentence about LiteLLM.\"}\n    ],\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n\nprint(response.choices[0].message.content)\n```\n\nLiteLLM follows the OpenAI-style `messages=[...]` request shape for chat-style calls. In most provider-backed completion flows, the generated text is available at `response.choices[0].message.content`.\n\n### Async completion\n\n```python\nimport asyncio\nimport os\n\nfrom litellm import acompletion\n\nasync def main() -> None:\n    response = await acompletion(\n        model=\"claude-sonnet-4-20250514\",\n        messages=[{\"role\": \"user\", \"content\": \"Say hello from async LiteLLM.\"}],\n        api_key=os.environ[\"ANTHROPIC_API_KEY\"],\n    )\n    print(response.choices[0].message.content)\n\nasyncio.run(main())\n```\n\nUse `acompletion()` in async servers, workers, or batch jobs. Do not call it from synchronous code without an event loop boundary.\n\n### Responses API\n\nThe docs also expose a `responses()` helper for the OpenAI Responses-style API:\n\n```python\nimport os\n\nfrom litellm import responses\n\nresponse = responses(\n    model=\"gpt-5\",\n    input=\"What is the capital of France?\",\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n\nprint(response.output_text)\n```\n\nUse `responses()` when your application already targets the newer Responses-style surface. Use `completion()` when your codebase is already structured around chat completions and `messages`.\n\n## Routing, Fallbacks, And Multi-Model Setup\n\nLiteLLM's `Router` is the right entry point when you need load balancing, fallback routing, or a shared model alias across providers.\n\n```python\nimport os\n\nfrom litellm import Router\n\nrouter = Router(\n    model_list=[\n        {\n            \"model_name\": \"fast-chat\",\n            \"litellm_params\": {\n                \"model\": \"gpt-4o-mini\",\n                \"api_key\": os.environ[\"OPENAI_API_KEY\"],\n            },\n        },\n        {\n            \"model_name\": \"reliable-chat\",\n            \"litellm_params\": {\n                \"model\": \"claude-sonnet-4-20250514\",\n                \"api_key\": os.environ[\"ANTHROPIC_API_KEY\"],\n            },\n        },\n    ]\n)\n\nresponse = router.completion(\n    model=\"fast-chat\",\n    messages=[{\"role\": \"user\", \"content\": \"Answer in five words.\"}],\n)\n\nprint(response.choices[0].message.content)\n```\n\nPractical guidance:\n\n- Use `model_name` as your app-facing alias and keep provider-specific model strings inside `litellm_params`.\n- Centralize retries, fallbacks, and load balancing in the router config instead of scattering provider-switching logic across your code.\n- Keep provider keys outside source control and inject them through environment variables or secret stores.\n\n## Optional Proxy Mode\n\nInstall `litellm[proxy]` if you need the proxy server or gateway features. The direct SDK install is enough for normal in-process Python usage.\n\nUse proxy mode when you want:\n\n- one internal OpenAI-compatible endpoint in front of multiple providers\n- centralized auth, routing, logging, or budgeting\n- app code that talks to a single gateway instead of every provider directly\n\nThe proxy documentation lives under the LiteLLM docs root and should be treated as a separate operational surface from the Python SDK.\n\n## Error Handling And Common Pitfalls\n\nLiteLLM documents OpenAI-compatible exception mapping. In practice, the most important families are authentication failures, bad request errors, rate limits, and unavailable upstream providers.\n\nCommon pitfalls:\n\n- Do not assume every provider supports every OpenAI parameter. LiteLLM documents `drop_params=True` for cases where you intentionally want unsupported OpenAI params omitted instead of raising.\n- Do not copy model names across providers blindly. Check the provider page for the exact supported model string and required auth variable.\n- Do not treat the unversioned docs site as proof of package pinning. Use the versioned PyPI page for `1.82.1` when you need reproducible installs.\n- Do not install `litellm[proxy]` unless you need proxy mode. The base package is enough for direct SDK calls.\n- If you switch between `completion()` and `responses()`, keep the response shape straight. `completion()` is typically read from `choices`, while `responses()` exposes `output_text`.\n- If a provider rejects an OpenAI-style field, confirm whether LiteLLM documents that field for the target provider before adding compatibility flags.\n\n## Recommended Workflow For Agents\n\n1. Pin `litellm==1.82.1` when reproducing bugs or generating project changes that need a stable dependency version.\n2. Start with `completion()` unless the codebase already uses the Responses API or a LiteLLM router.\n3. Set auth with explicit env vars or `api_key=` and add `base_url=` only when targeting an OpenAI-compatible gateway or custom endpoint.\n4. Check the provider page and supported-endpoints page before adding embeddings, responses, rerank, or image features.\n5. Move to `Router` only when the task actually needs multi-model routing, fallback, or aliasing.\n\n## Official Sources\n\n- Docs root: `https://docs.litellm.ai/docs/`\n- Completion quick start and async usage: `https://docs.litellm.ai/docs/completion/input`\n- Responses API: `https://docs.litellm.ai/docs/response_api`\n- Router and load balancing: `https://docs.litellm.ai/docs/routing-load-balancing`\n- Supported endpoints and provider coverage: `https://docs.litellm.ai/docs/providers`\n- OpenAI provider auth and examples: `https://docs.litellm.ai/docs/providers/openai`\n- Exception mapping: `https://docs.litellm.ai/docs/exception_mapping`\n- PyPI release page for this version: `https://pypi.org/project/litellm/1.82.1/`\n"
  },
  {
    "path": "content/litestar/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Litestar ASGI framework for Python APIs with typed routing, DI, DTOs, auth, OpenAPI, and testing.\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.21.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"litestar,python,asgi,api,web,openapi,async\"\n---\n\n# `litestar` for Python\n\nLitestar is a typed ASGI framework for building APIs and web apps. Reach for it when you want typed route handlers, layered routing, dependency injection, DTO-based input/output control, built-in OpenAPI, and first-party test helpers without stitching multiple libraries together yourself.\n\n## Install\n\nBase package:\n\n```bash\npip install litestar==2.21.1\n```\n\nRecommended local development install if you want the CLI and a bundled ASGI server:\n\n```bash\npip install 'litestar[standard]==2.21.1'\n```\n\nIf you only need JWT helpers, PyPI publishes an explicit extra for that too:\n\n```bash\npip install 'litestar[jwt]==2.21.1'\n```\n\nPyPI also lists extras such as `full`, `sqlalchemy`, `pydantic`, `redis`, `structlog`, `prometheus`, `jinja`, and `cryptography`. Install only the extras your app actually uses.\n\n## Minimal App\n\n```python\nfrom litestar import Litestar, get\n\n@get(\"/\")\nasync def hello_world() -> dict[str, str]:\n    return {\"hello\": \"world\"}\n\napp = Litestar(route_handlers=[hello_world])\n```\n\nRun it:\n\n```bash\nlitestar run\n```\n\nIf autodiscovery does not find your app, pass it explicitly:\n\n```bash\nlitestar --app=my_project.app:app run\n```\n\nThe CLI autodiscovers canonical modules such as `app.py`, `asgi.py`, `app/__init__.py`, `application.py`, and related submodules. It looks for a `Litestar` instance named `app` or `application`, any `Litestar` instance, or a callable named `create_app`.\n\n## Core Application Structure\n\nEvery Litestar app starts with a `Litestar(...)` instance whose `route_handlers` can include:\n\n- standalone route handler functions\n- `Router` instances\n- `Controller` classes\n\n```python\nfrom litestar import Litestar, Router, get\nfrom litestar.controller import Controller\n\n@get(\"/health\")\ndef healthcheck() -> dict[str, str]:\n    return {\"status\": \"ok\"}\n\nclass UserController(Controller):\n    path = \"/users\"\n\n    @get(\"/{user_id:int}\")\n    async def get_user(self, user_id: int) -> dict[str, int]:\n        return {\"user_id\": user_id}\n\nadmin_router = Router(path=\"/admin\", route_handlers=[UserController])\n\napp = Litestar(route_handlers=[healthcheck, admin_router])\n```\n\nOperational notes:\n\n- Route paths support typed converters such as `/{user_id:int}` and `/{order_id:uuid}`.\n- Controllers and standalone handlers can be registered multiple times under different routers.\n- Mounted ASGI apps are supported when you need to delegate a sub-path to another ASGI application.\n- Litestar uses trie-based routing. That matters mostly for large route trees, not for day-to-day handler code.\n\n## Lifespan and Shared State\n\nUse app lifespan hooks for long-lived resources such as DB engines, caches, HTTP clients, or message brokers. Store those resources on `app.state`.\n\n```python\nfrom collections.abc import AsyncGenerator\nfrom contextlib import asynccontextmanager\n\nfrom litestar import Litestar\n\n@asynccontextmanager\nasync def db_lifespan(app: Litestar) -> AsyncGenerator[None, None]:\n    app.state.db = object()\n    try:\n        yield\n    finally:\n        app.state.db = None\n\napp = Litestar(route_handlers=[], lifespan=[db_lifespan])\n```\n\nThis keeps initialization out of route handlers and gives you one place to manage startup and shutdown cleanup.\n\n## Request Parsing and Typed Handlers\n\nLitestar is strict about typing because it uses annotations for validation, parsing, and OpenAPI generation. Missing or vague handler types cause problems quickly, so annotate inputs and return values deliberately.\n\nBasic JSON body parsing:\n\n```python\nfrom litestar import Litestar, post\n\n@post(\"/users\")\nasync def create_user(data: dict[str, str]) -> dict[str, str]:\n    return data\n\napp = Litestar(route_handlers=[create_user])\n```\n\nUse `Body(...)` when you need explicit validation or OpenAPI metadata:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Annotated\n\nfrom litestar import Litestar, post\nfrom litestar.params import Body\n\n@dataclass\nclass UserCreate:\n    id: int\n    name: str\n\n@post(\"/users\")\nasync def create_user(\n    data: Annotated[\n        UserCreate,\n        Body(title=\"Create User\", description=\"Create a new user.\"),\n    ],\n) -> UserCreate:\n    return data\n\napp = Litestar(route_handlers=[create_user])\n```\n\nUse explicit request encodings for forms and uploads:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Annotated\n\nfrom litestar import Litestar, post\nfrom litestar.enums import RequestEncodingType\nfrom litestar.params import Body\n\n@dataclass\nclass LoginForm:\n    username: str\n    password: str\n\n@post(\"/login\")\nasync def login(\n    data: Annotated[LoginForm, Body(media_type=RequestEncodingType.URL_ENCODED)],\n) -> dict[str, str]:\n    return {\"username\": data.username}\n\napp = Litestar(route_handlers=[login])\n```\n\nImportant limit: `request_max_body_size` defaults to `10MB`. If a request exceeds the limit, Litestar returns `413 Request Entity Too Large`. Setting `request_max_body_size=None` is explicitly discouraged upstream because it can expose the app to DoS-style memory exhaustion.\n\n## Dependency Injection\n\nDependencies are declared by key and wrapped with `Provide(...)`. They can be attached at the app, router, controller, or route-handler layer.\n\n```python\nfrom litestar import Litestar, get\nfrom litestar.di import Provide\n\nasync def provide_request_id() -> str:\n    return \"req-123\"\n\n@get(\"/\", dependencies={\"request_id\": Provide(provide_request_id)})\nasync def index(request_id: str) -> dict[str, str]:\n    return {\"request_id\": request_id}\n\napp = Litestar(route_handlers=[index])\n```\n\nWhat matters in practice:\n\n- The dependency dictionary key must match the handler parameter name.\n- Dependencies can depend on other dependencies.\n- Lower scopes override higher scopes cleanly because dependencies are string-keyed at each layer.\n- `Provide.use_cache=True` memoizes the first result for the current request only. Do not treat it as a cross-request cache.\n\nFor resources that need cleanup, use generator dependencies and always wrap `yield` in `try` / `finally`:\n\n```python\nfrom collections.abc import Generator\n\nfrom litestar import Litestar, get\nfrom litestar.di import Provide\n\ndef open_resource() -> Generator[dict[str, bool], None, None]:\n    resource = {\"open\": True}\n    try:\n        yield resource\n    finally:\n        resource[\"open\"] = False\n\n@get(\"/\", dependencies={\"resource\": Provide(open_resource)})\ndef handler(resource: dict[str, bool]) -> dict[str, bool]:\n    return resource\n\napp = Litestar(route_handlers=[handler])\n```\n\nUpstream notes that cleanup runs after the handler returns and that cleanup exceptions are re-raised in an `ExceptionGroup`. Also use `Dependency(skip_validation=True)` sparingly; the docs explicitly warn to use it with caution.\n\n## DTOs for Create and Update Flows\n\nUse DTOs when you need different read/write contracts, partial update behavior, field exclusion, or tighter control over generated schemas.\n\n```python\nfrom dataclasses import dataclass\n\nfrom litestar import Litestar, patch\nfrom litestar.dto import DataclassDTO, DTOConfig, DTOData\n\n@dataclass\nclass User:\n    id: int\n    name: str\n    email: str\n\nclass UserReadDTO(DataclassDTO[User]):\n    config = DTOConfig(exclude={\"email\"})\n\nclass UserPatchDTO(DataclassDTO[User]):\n    config = DTOConfig(exclude={\"id\"}, partial=True)\n\n@patch(\"/users/{user_id:int}\", dto=UserPatchDTO, return_dto=UserReadDTO, sync_to_thread=False)\ndef update_user(user_id: int, data: DTOData[User]) -> User:\n    user = User(id=user_id, name=\"Jane\", email=\"jane@example.com\")\n    return data.update_instance(user)\n\napp = Litestar(route_handlers=[update_user])\n```\n\nThis is the common pattern for CRUD handlers:\n\n- `dto=` controls request parsing\n- `return_dto=` controls response serialization\n- `DTOData[T]` gives you update helpers such as `update_instance(...)`\n- `partial=True` is the switch you want for `PATCH`\n\n## JWT Authentication\n\nLitestar ships a JWT auth backend that can inject middleware and OpenAPI config during app initialization.\n\n```python\nfrom os import environ\nfrom typing import Any\n\nfrom litestar import Litestar, Request, get, post\nfrom litestar.openapi import OpenAPIConfig\nfrom litestar.security.jwt import JWTAuth, Token\n\nclass User:\n    def __init__(self, user_id: str) -> None:\n        self.id = user_id\n\nasync def retrieve_user_handler(token: Token, connection: Any) -> User | None:\n    return User(token.sub) if token.sub else None\n\njwt_auth = JWTAuth[User](\n    retrieve_user_handler=retrieve_user_handler,\n    token_secret=environ[\"JWT_SECRET\"],\n    exclude=[\"/login\", \"/schema\"],\n)\n\n@post(\"/login\")\nasync def login_handler() -> dict[str, str]:\n    token = jwt_auth.create_token(identifier=\"user-123\")\n    return {\"access_token\": token}\n\n@get(\"/me\")\ndef me(request: Request[User, Token, Any]) -> dict[str, str]:\n    return {\"user_id\": request.user.id}\n\napp = Litestar(\n    route_handlers=[login_handler, me],\n    on_app_init=[jwt_auth.on_app_init],\n    openapi_config=OpenAPIConfig(title=\"Example API\", version=\"1.0.0\"),\n)\n```\n\nAuth notes:\n\n- `retrieve_user_handler` is required for `JWTAuth`.\n- `jwt_auth.on_app_init` wires in middleware and OpenAPI integration.\n- Excluding `/login` and `/schema` is a common upstream pattern.\n- Authenticated handlers can read both `request.user` and `request.auth`.\n- If you need revocation, the official docs show a `revoked_token_handler` pattern.\n\n## Testing\n\nLitestar’s test client is built on top of `httpx`. Use the regular in-process clients for most handlers, and only switch to subprocess clients when you need real server behavior.\n\nSimple isolated route test:\n\n```python\nfrom litestar import get\nfrom litestar.testing import create_test_client\n\n@get(\"/health-check\")\ndef health_check() -> str:\n    return \"healthy\"\n\ndef test_health_check() -> None:\n    with create_test_client(route_handlers=[health_check]) as client:\n        response = client.get(\"/health-check\")\n        assert response.status_code == 200\n        assert response.text == \"healthy\"\n```\n\nAsync fixture style:\n\n```python\nfrom collections.abc import AsyncIterator\n\nimport pytest\nfrom litestar import Litestar, get\nfrom litestar.testing import AsyncTestClient\n\n@get(\"/ping\", sync_to_thread=False)\ndef ping() -> str:\n    return \"pong\"\n\napp = Litestar(route_handlers=[ping], debug=True)\n\n@pytest.fixture\nasync def test_client() -> AsyncIterator[AsyncTestClient[Litestar]]:\n    async with AsyncTestClient(app=app) as client:\n        yield client\n```\n\nTesting notes:\n\n- `create_test_client(...)` is the fastest way to test isolated handlers.\n- `websocket_connect(...)` is available on the test client for websocket tests.\n- For infinite SSE streams or cases where HTTPX’s in-process emulation is insufficient, Litestar provides `subprocess_sync_client()` and `subprocess_async_client()`.\n\n## OpenAPI and Schema Defaults\n\nLitestar generates OpenAPI automatically from your typed handlers, DTOs, parameters, and response models. During tests and local inspection, `/schema/openapi.json` is the default machine-readable endpoint you will most often use.\n\nIf you are adding auth, custom titles, or other schema settings, keep an explicit `OpenAPIConfig(...)` near app initialization so docs generation stays predictable.\n\n## Common Pitfalls\n\n- The docs URL `https://docs.litestar.dev/latest/` is a moving target. This guide covers `2.21.1`, so verify version-sensitive behavior against PyPI and the 2.x changelog before copying examples later.\n- Litestar expects strong typing. Missing return annotations or vague body types often break validation or schema generation.\n- The `litestar run` command does not scan arbitrary filenames. Use canonical `app` / `application` modules or pass `--app`.\n- Dependency keys and handler argument names must match exactly.\n- Do not disable request body limits casually. Upstream explicitly warns that `request_max_body_size=None` can enable memory-exhaustion attacks unless another layer enforces limits.\n- Use `try` / `finally` around generator dependencies so cleanup still runs on errors.\n- If you test SSE or other streaming behavior with infinite generators, do not assume the normal test client is enough; use subprocess test helpers.\n\n## Version-Sensitive Notes for `2.21.1`\n\n- PyPI lists `2.21.1` as the latest Litestar release and marks it as released on `2026-03-07`.\n- The official 2.x changelog for `2.21.1` is a bugfix release focused on DTO behavior:\n  - nested DTO schema references with custom `__schema_name__`\n  - `TypeError` cases involving deeply nested optional DTO fields\n- If your code depends on advanced DTO schema generation or deeply nested optional payloads, prefer `2.21.1` examples and avoid older blog posts or issues that predate these fixes.\n- The docs root is still correct, but it is not version-frozen. Re-check the changelog if `latest` has moved beyond `2.21.1`.\n\n## Official Sources\n\n- Docs landing page: https://docs.litestar.dev/latest/\n- Applications: https://docs.litestar.dev/latest/usage/applications.html\n- Routing: https://docs.litestar.dev/latest/usage/routing/overview.html\n- Requests: https://docs.litestar.dev/latest/usage/requests.html\n- Dependency injection: https://docs.litestar.dev/latest/usage/dependency-injection.html\n- JWT auth: https://docs.litestar.dev/latest/usage/security/jwt.html\n- CLI: https://docs.litestar.dev/latest/usage/cli.html\n- DTO updating tutorial: https://docs.litestar.dev/2/tutorials/dto-tutorial/09-updating.html\n- Testing: https://docs.litestar.dev/2/usage/testing.html\n- 2.x changelog: https://docs.litestar.dev/2/release-notes/changelog.html\n- PyPI package page: https://pypi.org/project/litestar/2.21.1/\n"
  },
  {
    "path": "content/livekit/docs/realtime/javascript/DOC.md",
    "content": "---\nname: realtime\ndescription: \"LiveKit Client SDK for JavaScript/TypeScript enabling real-time video, audio, and data communication via WebRTC.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.15.13\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"livekit,realtime,webrtc,video,audio\"\n---\n\n# LiveKit Client SDK Coding Guidelines (JavaScript/TypeScript)\n\nYou are a LiveKit Client SDK expert. Help me with writing code using the LiveKit Client SDK for JavaScript/TypeScript. Please follow the following guidelines when generating code. You can find the official SDK documentation and code samples here: https://docs.livekit.io\n\n## Golden Rule: Use the Current LiveKit Client SDK\n\nAlways use the official LiveKit Client SDK for JavaScript/TypeScript, which is the standard library for all LiveKit real-time communication interactions.\n\n- **Library Name:** LiveKit Client SDK\n- **Package Name:** `livekit-client`\n- **Current Version:** 2.11.3 \n\n**Installation:**\n- **Correct:** `npm install livekit-client`\n- **Correct:** `yarn add livekit-client`\n- **Correct:** `pnpm add livekit-client`\n\n**Import Patterns:**\n- **Correct:** `import { Room, connect } from 'livekit-client'`\n- **Correct:** `import { LocalParticipant, RemoteParticipant } from 'livekit-client'`\n- **Correct:** `import { Track, RoomEvent } from 'livekit-client'`\n- **Correct:** `import { createLocalTracks } from 'livekit-client'`\n\n## Core Architecture\n\nThe LiveKit Client SDK is built around three main concepts: **Rooms**, **Participants**, and **Tracks** <cite />. Understanding this hierarchy is crucial for effective usage.\n\n### Room Connection\n\nAlways start by connecting to a room using the `connect` function:\n\n```typescript\nimport { connect, Room } from 'livekit-client';\n\nconst room = await connect(url, token, {\n  // connection options\n  autoSubscribe: true,\n  publishDefaults: {\n    simulcast: true,\n  }\n});\n```\n\n### Event-Driven Architecture\n\nLiveKit uses an event-driven model. Always set up event listeners before connecting <cite />:\n\n```typescript\nroom.on(RoomEvent.Connected, () => {\n  console.log('Connected to room');\n});\n\nroom.on(RoomEvent.ParticipantConnected, (participant) => {\n  console.log('Participant joined:', participant.identity);\n});\n\nroom.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {\n  if (track.kind === Track.Kind.Video) {\n    const videoElement = track.attach();\n    document.body.appendChild(videoElement);\n  }\n});\n```\n\n## Media Management\n\n### Publishing Local Media\n\nUse the `LocalParticipant` methods for common media types:\n\n```typescript\nconst localParticipant = room.localParticipant;\n\n// Enable camera and microphone\nawait localParticipant.setCameraEnabled(true);\nawait localParticipant.setMicrophoneEnabled(true);\n\n// Enable screen sharing\nawait localParticipant.setScreenShareEnabled(true);\n\n// Disable camera (mute)\nawait localParticipant.setCameraEnabled(false);\n```\n\n### Publishing Custom Tracks\n\nFor custom media sources, use `publishTrack`:\n\n```typescript\nconst publication = await room.localParticipant.publishTrack(mediaStreamTrack, {\n  name: 'mytrack',\n  simulcast: true,\n  source: Track.Source.Camera, // or .Microphone, .ScreenShare\n});\n\n// Mute or unpublish later\npublication.setMuted(true);\nroom.localParticipant.unpublishTrack(mediaStreamTrack);\n```\n\n### Subscribing to Remote Media\n\nAccess remote participants and their tracks:\n\n```typescript\nconst remoteParticipant = room.remoteParticipants.get('participant-identity');\nif (remoteParticipant) {\n  if (remoteParticipant.isCameraEnabled) {\n    const publication = remoteParticipant.getTrackPublication(Track.Source.Camera);\n    if (publication?.isSubscribed) {\n      const videoElement = publication.videoTrack?.attach();\n      // Add to DOM\n    }\n  }\n}\n```\n\n## Advanced Features\n\n### Pre-creating Tracks\n\nCreate tracks before joining a room for staging areas:\n\n```typescript\nconst tracks = await createLocalTracks({\n  audio: true,\n  video: true,\n});\n```\n\n### Device Management\n\nList and switch between devices:\n\n```typescript\n// List devices\nconst devices = await Room.getLocalDevices('audioinput');\n\n// Switch to specific device\nconst device = devices[devices.length - 1];\nawait room.switchActiveDevice('audioinput', device.deviceId);\n\n// Switch using constraints (mobile camera)\nawait videoTrack.restartTrack({\n  facingMode: 'environment',\n});\n```\n\n### Error Handling\n\nHandle device failures properly:\n\n```typescript\nroom.on(RoomEvent.MediaDevicesError, (error) => {\n  const failure = MediaDeviceFailure.getFailure(error);\n  switch (failure) {\n    case 'PermissionDenied':\n      // Handle permission denied\n      break;\n    case 'NotFound':\n      // Handle device not found\n      break;\n    case 'DeviceInUse':\n      // Handle device in use\n      break;\n  }\n});\n\n// Check last errors\nconsole.log(room.localParticipant.lastCameraError);\nconsole.log(room.localParticipant.lastMicrophoneError);\n```\n\n### RPC (Remote Procedure Calls)\n\nFor participant-to-participant communication:\n\n```typescript\n// Register an RPC method\nroom.localParticipant?.registerRpcMethod(\n  'greet',\n  async (data: RpcInvocationData) => {\n    console.log(`Received greeting from ${data.callerIdentity}: ${data.payload}`);\n    return `Hello, ${data.callerIdentity}!`;\n  },\n);\n\n// Call an RPC method\ntry {\n  const response = await room.localParticipant!.performRpc({\n    destinationIdentity: 'recipient-identity',\n    method: 'greet',\n    payload: 'Hello from RPC!',\n  });\n  console.log('RPC response:', response);\n} catch (error) {\n  console.error('RPC call failed:', error);\n}\n```\n\n## Video Quality and Simulcast\n\n### Simulcast Configuration\n\nThe SDK automatically configures simulcast layers based on video resolution. Default presets include:\n\n- **16:9 content:** Uses `h180` and `h360` simulcast layers\n- **4:3 content:** Uses corresponding 4:3 presets\n- **Screen sharing:** Uses custom calculated layers \n\n```typescript\n// Enable simulcast (recommended)\nawait room.localParticipant.publishTrack(videoTrack, {\n  simulcast: true,\n  videoCodec: 'vp9', // or 'vp8', 'h264', 'av1'\n});\n```\n\n## Connection Quality\n\n### Monitor Connection Quality\n\nTrack participant connection quality:\n\n```typescript\nroom.on(RoomEvent.ConnectionQualityChanged, (quality, participant) => {\n  console.log(`${participant.identity} quality: ${quality}`);\n  // quality can be: 'excellent', 'good', 'poor', 'lost', 'unknown'\n});\n```\n\n## Browser Compatibility\n\nThe SDK supports modern browsers:\n\n- Chrome (desktop and Android)\n- Firefox (desktop and Android)  \n- Safari (macOS and iOS)\n- Edge (Chromium-based)\n\nCheck compatibility:\n\n```typescript\nimport { isBrowserSupported, supportsAdaptiveStream, supportsDynacast } from 'livekit-client';\n\nif (!isBrowserSupported()) {\n  console.warn('Browser not supported');\n}\n\nif (supportsAdaptiveStream()) {\n  // Enable adaptive streaming features\n}\n```\n\n## Best Practices\n\n1. **Always handle events:** Set up event listeners before connecting\n2. **Use simulcast:** Enable simulcast for better quality adaptation\n3. **Handle errors gracefully:** Implement proper error handling for device failures\n4. **Clean up resources:** Disconnect from rooms and dispose of tracks when done\n5. **Check browser support:** Verify compatibility before initializing\n6. **Use TypeScript:** The SDK is built with TypeScript for better developer experience\n\n## Error Codes\n\nCommon error codes you may encounter:\n\n| Code | Name | Reason |\n|------|------|--------|\n| 1 | `ConnectionError` | Various connection issues |\n| 10 | `UnsupportedServer` | Server version incompatible |\n| 12 | `UnexpectedConnectionState` | Connection state error |\n| 13 | `NegotiationError` | WebRTC negotiation failed |\n| 20 | `TrackInvalidError` | Track-related error |\n| 21 | `DeviceUnsupportedError` | Device not supported |\n| 40 | `CryptorError` | E2EE encryption error |\n\n## Useful Links\n\n- Documentation: https://docs.livekit.io\n- GitHub Repository: https://github.com/livekit/client-sdk-js\n- Examples: https://github.com/livekit-examples\n- LiveKit Cloud: https://livekit.io/cloud\n\n## Notes\n\nThis guide covers the core functionality of the LiveKit Client SDK. The SDK also includes advanced features like End-to-End Encryption (E2EE), connection diagnostics, and sophisticated media transport optimizations that are documented in the Advanced Features section of the codebase <cite />. For React applications, consider using the LiveKit React Components library for pre-built UI components.\n\nWiki pages you might want to explore:\n- [Overview (livekit/client-sdk-js)](/wiki/livekit/client-sdk-js#1)\n- [Advanced Features (livekit/client-sdk-js)](/wiki/livekit/client-sdk-js#6)\n\n"
  },
  {
    "path": "content/livekit/docs/realtime/python/DOC.md",
    "content": "---\nname: realtime\ndescription: \"LiveKit Python SDK for real-time video, audio, and data communication including room management and recording.\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.17\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"livekit,realtime,webrtc,video,audio\"\n---\n\n# LiveKit Python SDK Example\n\nThis repository contains an interactive Streamlit demo application showcasing the LiveKit Python SDK capabilities for real-time video, audio, and data communication.\n\n## Overview\n\nThe example demonstrates key LiveKit Python SDK features including:\n- Access token generation\n- Room management operations\n- Recording (Egress) functionality\n- Real-time connection handling\n- Remote Procedure Calls (RPC)\n- Environment configuration\n\n## Prerequisites\n\n- Python 3.8 or higher\n- LiveKit server instance (LiveKit Cloud or self-hosted)\n\n## Installation\n\n1. **Install dependencies:**\n   ```bash\n   pip install streamlit livekit livekit-api\n   ```\n\n   Or using the provided pyproject.toml:\n   ```bash\n   pip install -e .\n   ```\n\n2. **Set up environment variables:**\n\n   Copy the sample environment file and configure your LiveKit credentials:\n   ```bash\n   cp example/.env.sample example/.env\n   ```\n\n   Edit `example/.env` with your LiveKit server details:\n   ```\n   LIVEKIT_URL=wss://your-project.livekit.cloud\n   LIVEKIT_API_KEY=your-api-key\n   LIVEKIT_API_SECRET=your-api-secret\n   ```\n\n## Running the Demo\n\n1. **Navigate to the example directory:**\n   ```bash\n   cd example\n   ```\n\n2. **Run the Streamlit application:**\n   ```bash\n   streamlit run app.py\n   ```\n\n3. **Open your browser:**\n   The application will automatically open in your default browser at `http://localhost:8501`\n\n## Demo Features\n\n### Access Token Generation\nGenerate JWT tokens for client authentication with configurable:\n- User identity and display name\n- Room permissions (join, publish, subscribe)\n- Token expiration settings\n\n### Room Management\nDemonstrate server API capabilities:\n- Create new rooms with custom settings\n- List existing rooms\n- Delete rooms\n- Manage room participants\n\n### Recording (Egress)\nShow recording functionality:\n- Start room composite recordings\n- Configure output formats\n- Monitor recording status\n\n### Real-time Connection\nInteractive examples of:\n- Connecting to rooms as a participant\n- Handling track subscriptions\n- Processing video/audio streams\n- Managing connection events\n\n### RPC Methods\nRemote procedure call demonstrations:\n- Register RPC method handlers\n- Perform RPC calls between participants\n- Handle responses and errors\n\n## Project Structure\n\n```\nexample/\n├── app.py              # Main Streamlit application\n├── pyproject.toml      # Project dependencies and configuration\n├── .env.sample         # Environment variables template\n└── .streamlit/         # Streamlit configuration\n    └── config.toml\n```\n\n## SDK Documentation\n\nFor comprehensive documentation and additional examples:\n- **Official Documentation**: https://docs.livekit.io/\n- **Python SDK Guide**: https://docs.livekit.io/home/client/connect/\n- **Server API Reference**: https://docs.livekit.io/reference/server/server-apis\n- **Community Examples**: https://github.com/livekit-examples\n\n## Environment Variables\n\nThe application requires the following environment variables:\n\n| Variable | Description | Required |\n|----------|-------------|----------|\n| `LIVEKIT_URL` | LiveKit server WebSocket URL | Yes |\n| `LIVEKIT_API_KEY` | API authentication key | Yes |\n| `LIVEKIT_API_SECRET` | API authentication secret | Yes |\n\n## Development\n\n### Code Style\nThe project uses Black and Ruff for code formatting and linting:\n\n```bash\n# Format code\nblack .\n\n# Lint code\nruff check .\n```\n\n### Testing\nRun tests using pytest:\n\n```bash\npytest\n```\n\n## Support\n\n- **Documentation**: https://docs.livekit.io/\n- **Community Slack**: https://livekit.io/join-slack\n- **GitHub Issues**: Report issues on the respective SDK repositories\n\n## License\n\nThis example is provided under the same license as the LiveKit Python SDK."
  },
  {
    "path": "content/llama-index/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LlamaIndex package guide for Python RAG pipelines, ingestion, retrieval, and agent workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.14.16\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"llama-index,rag,agents,retrieval,vector-index,python\"\n---\n\n# LlamaIndex Python Package Guide\n\n## What This Package Is For\n\n`llama-index` is the Python starter package for building LLM applications around your own data. Use it when you need:\n\n- document loading and chunking\n- embeddings and vector indexes\n- query engines and chat engines\n- agent and workflow building blocks\n- pluggable model, embedding, reader, and vector-store integrations\n\nFor Python code, the main imports come from `llama_index.core` plus provider-specific integration packages such as `llama_index.llms.openai` or `llama_index.embeddings.huggingface`.\n\n## Install\n\nInstall the starter bundle pinned to the package version you want:\n\n```bash\npip install \"llama-index==0.14.16\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"llama-index==0.14.16\"\npoetry add \"llama-index==0.14.16\"\n```\n\nVerify what is installed:\n\n```bash\npython -c \"import llama_index; print(llama_index.__version__)\"\n```\n\n### Lean Install Pattern\n\nThe upstream installation guide recommends installing only the core package plus the integrations you actually need when you want a smaller dependency set:\n\n```bash\npip install llama-index-core\npip install llama-index-llms-openai\npip install llama-index-embeddings-openai\n```\n\nFor local models:\n\n```bash\npip install llama-index-core\npip install llama-index-llms-ollama\npip install llama-index-embeddings-huggingface\n```\n\nUse the single `llama-index` starter package when you want the standard getting-started experience. Use `llama-index-core` plus explicit integrations when dependency size and provider control matter.\n\n## Setup And Auth\n\nLlamaIndex itself does not have one global platform API key. Authentication depends on the providers you plug in.\n\n### OpenAI-backed setup\n\nThe official starter examples assume OpenAI for both the LLM and embeddings. Set provider configuration explicitly instead of relying on implicit defaults:\n\n```bash\nexport OPENAI_API_KEY=\"...\"\nexport OPENAI_MODEL=\"your-openai-chat-model\"\nexport OPENAI_EMBED_MODEL=\"text-embedding-3-small\"\n```\n\n### Local-model setup\n\nFor local development with Ollama plus Hugging Face embeddings:\n\n```bash\nollama serve\nollama pull llama3.1\npip install llama-index-llms-ollama llama-index-embeddings-huggingface\n```\n\nNo LlamaIndex-specific auth is required for that setup, but the Ollama server must be running and the model must already exist locally.\n\n## Core Usage: Build A Queryable Index\n\nThe smallest useful flow is:\n\n1. load documents\n2. choose an LLM and embedding model\n3. build an index\n4. query it\n\n```python\nimport os\n\nfrom llama_index.core import Settings, SimpleDirectoryReader, VectorStoreIndex\nfrom llama_index.embeddings.openai import OpenAIEmbedding\nfrom llama_index.llms.openai import OpenAI\n\nSettings.llm = OpenAI(model=os.environ[\"OPENAI_MODEL\"])\nSettings.embed_model = OpenAIEmbedding(\n    model=os.getenv(\"OPENAI_EMBED_MODEL\", \"text-embedding-3-small\")\n)\nSettings.chunk_size = 1024\n\ndocuments = SimpleDirectoryReader(\"data\").load_data()\nindex = VectorStoreIndex.from_documents(documents)\n\nquery_engine = index.as_query_engine(similarity_top_k=3)\nresponse = query_engine.query(\"Summarize the main topics in these files.\")\n\nprint(str(response))\n```\n\nPractical notes:\n\n- `SimpleDirectoryReader` is the standard file-based loader for local directories.\n- `VectorStoreIndex.from_documents(...)` handles parsing, chunking, embedding, and indexing in one path.\n- `Settings` is global. Set it once at process startup, or override per component when different parts of the app use different models.\n\n## Switch To Local Models\n\nThe same indexing flow works with local or self-hosted model providers.\n\n```python\nfrom llama_index.core import Settings, SimpleDirectoryReader, VectorStoreIndex\nfrom llama_index.embeddings.huggingface import HuggingFaceEmbedding\nfrom llama_index.llms.ollama import Ollama\n\nSettings.llm = Ollama(model=\"llama3.1\", request_timeout=120.0)\nSettings.embed_model = HuggingFaceEmbedding(model_name=\"BAAI/bge-base-en-v1.5\")\nSettings.chunk_size = 1024\n\ndocuments = SimpleDirectoryReader(\"data\").load_data()\nindex = VectorStoreIndex.from_documents(documents)\n\nresponse = index.as_query_engine(similarity_top_k=3).query(\n    \"What are the most important points?\"\n)\nprint(str(response))\n```\n\nUse this pattern when you need local development, lower cloud dependence, or a non-OpenAI stack.\n\n## Control Chunking And Transformations\n\nYou can use global settings for defaults, but explicit transformations are safer when one index needs different chunking from the rest of the application.\n\n```python\nfrom llama_index.core import SimpleDirectoryReader, VectorStoreIndex\nfrom llama_index.core.node_parser import SentenceSplitter\n\ndocuments = SimpleDirectoryReader(\"data\").load_data()\n\nindex = VectorStoreIndex.from_documents(\n    documents,\n    transformations=[\n        SentenceSplitter(chunk_size=512, chunk_overlap=50),\n    ],\n)\n```\n\nPrefer explicit transformations when:\n\n- different indexes in one process need different chunk sizes\n- you are tuning retrieval quality\n- you want indexing behavior to stay stable even if global `Settings` changes elsewhere\n\n## Persist And Reload An Index\n\nPersist the index when you do not want to recompute embeddings on every run.\n\n```python\nfrom llama_index.core import StorageContext, load_index_from_storage\n\nindex.storage_context.persist(persist_dir=\"storage\")\n\nstorage_context = StorageContext.from_defaults(persist_dir=\"storage\")\nrestored_index = load_index_from_storage(storage_context)\n\nresponse = restored_index.as_query_engine().query(\"Ask the same corpus a new question.\")\nprint(str(response))\n```\n\nImportant behavior:\n\n- Reload with the same embedding setup you used when building the index.\n- Persisted storage saves index state, not your original source-of-truth documents.\n- If you change chunking, embeddings, or vector-store backend, rebuild the index instead of assuming old persisted state is still valid.\n\n## Use An External Vector Store\n\nLlamaIndex can write to external vector stores instead of using the default in-memory path.\n\n```bash\npip install chromadb llama-index-vector-stores-chroma\n```\n\n```python\nimport chromadb\n\nfrom llama_index.core import SimpleDirectoryReader, StorageContext, VectorStoreIndex\nfrom llama_index.vector_stores.chroma import ChromaVectorStore\n\ndocuments = SimpleDirectoryReader(\"data\").load_data()\n\nclient = chromadb.PersistentClient(path=\"chroma-db\")\ncollection = client.get_or_create_collection(\"docs\")\nvector_store = ChromaVectorStore(chroma_collection=collection)\nstorage_context = StorageContext.from_defaults(vector_store=vector_store)\n\nindex = VectorStoreIndex.from_documents(\n    documents,\n    storage_context=storage_context,\n)\n```\n\nThe same pattern applies to Pinecone, Qdrant, Weaviate, Postgres, and other officially supported integrations: install the dedicated `llama-index-vector-stores-*` package and wire it through `StorageContext`.\n\n## Common Pitfalls\n\n- Package name and import name differ. Install `llama-index`, but import from `llama_index...`.\n- `llama-index` is not every integration. Install the extra `llama-index-llms-*`, `llama-index-embeddings-*`, `llama-index-readers-*`, and `llama-index-vector-stores-*` packages you actually use.\n- Prefer `Settings`, not `ServiceContext`. The upstream migration guide introduced `Settings` in `v0.10.0`; older blog posts still show deprecated patterns.\n- Do not rely on implicit model defaults. Set `Settings.llm` and `Settings.embed_model` explicitly so upgrades do not silently change behavior.\n- `SimpleDirectoryReader` is for files. Database, SaaS, or web-source ingestion usually needs a dedicated reader/integration package.\n- Reusing persisted indexes across different embedding models produces bad retrieval results. Keep embeddings stable per index.\n- Global `Settings` can leak across tests or mixed workloads. For libraries or complex apps, prefer local overrides or isolate setup code.\n\n## Version-Sensitive Notes For `0.14.16`\n\n- PyPI lists `0.14.16` as the current package version, uploaded on `2026-03-10`.\n- The docs URL `https://docs.llamaindex.ai/en/stable/` is still valid, but it redirects to the newer `developers.llamaindex.ai` docs host.\n- The current framework docs emphasize the package split: `llama-index-core` for the base framework and add-on packages for providers and vector stores.\n- The durable API pattern for new code is `Settings` plus `llama_index.core`. Treat `ServiceContext` examples as legacy unless you are maintaining an older codebase.\n\n## Official Sources\n\n- Docs home: `https://developers.llamaindex.ai/python/framework/`\n- Installation: `https://developers.llamaindex.ai/python/framework/getting_started/installation/`\n- Starter tutorial: `https://developers.llamaindex.ai/python/framework/getting_started/starter_example/`\n- Local models: `https://developers.llamaindex.ai/python/framework/getting_started/starter_example_local/`\n- Using `Settings`: `https://developers.llamaindex.ai/python/framework/module_guides/supporting_modules/settings/`\n- Persisting and loading: `https://developers.llamaindex.ai/python/framework/understanding/rag/storing/`\n- ServiceContext migration: `https://developers.llamaindex.ai/python/framework/module_guides/supporting_modules/service_context_migration/`\n- PyPI package: `https://pypi.org/project/llama-index/`\n"
  },
  {
    "path": "content/localstack/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"LocalStack Python package guide for running the LocalStack CLI and wiring Python AWS SDK clients to local emulated AWS services\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"localstack,aws,python,boto3,testing,docker,cloud-emulator\"\n---\n\n# LocalStack Python Package Guide\n\n## Golden Rule\n\nUse the `localstack` PyPI package to install the LocalStack CLI, but treat LocalStack as local infrastructure, not as an application library you import into your service code. Your Python app usually talks to LocalStack through normal AWS clients such as `boto3`, pointed at the LocalStack endpoint.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"localstack==4.14.0\"\nlocalstack --version\n```\n\nLocalStack requires Docker for the normal runtime path. Confirm Docker is available before starting services:\n\n```bash\ndocker info >/dev/null\n```\n\nIf you use the AWS CLI often, install `awslocal` as well:\n\n```bash\npython -m pip install awscli-local\n```\n\n## Start And Stop LocalStack\n\nDetached local development flow:\n\n```bash\nlocalstack start -d\nlocalstack wait\nlocalstack status services\n```\n\nUseful lifecycle commands:\n\n```bash\nlocalstack logs\nlocalstack stop\n```\n\nIf you need a custom profile:\n\n```bash\nCONFIG_PROFILE=dev localstack start -d\n```\n\nOr:\n\n```bash\nlocalstack --profile=dev start -d\n```\n\n`CONFIG_PROFILE` and `--profile` apply to the CLI. The LocalStack docs explicitly note that profile-based configuration is not supported in Docker Compose.\n\n## Minimal Docker Compose Setup\n\nPin the image tag instead of relying on `latest`-style behavior:\n\n```yaml\nservices:\n  localstack:\n    image: localstack/localstack:4.14.0\n    ports:\n      - \"4566:4566\"\n    environment:\n      - SERVICES=s3,sqs\n      - PERSISTENCE=1\n      - DEBUG=1\n    volumes:\n      - \"./volume:/var/lib/localstack\"\n      - \"/var/run/docker.sock:/var/run/docker.sock\"\n```\n\nNotes:\n\n- `4566` is the edge port for all emulated AWS APIs.\n- `SERVICES` limits startup to the services you actually need.\n- `PERSISTENCE=1` enables disk-backed state.\n- Mounting the Docker socket is required for features that need nested containers.\n\n## Credentials And Auth\n\nFor most local development, use test credentials:\n\n```bash\nexport AWS_ACCESS_KEY_ID=test\nexport AWS_SECRET_ACCESS_KEY=test\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\nImportant LocalStack-specific rules from the AWS credentials docs:\n\n- LocalStack accepts any credentials by default, but the access key can influence the simulated account namespace.\n- The secret access key is ignored by LocalStack itself, but LocalStack recommends keeping it set to `test`, especially for S3 presigned URL workflows.\n- LocalStack rejects `AKIA...` and `ASIA...` access key patterns by default to reduce accidental use of real AWS credentials. If you pass a real-looking key anyway, many requests fall back to account `000000000000`.\n- If you need multiple emulated accounts, use a valid 12-digit account ID as the access key.\n\nFor LocalStack Pro authentication, set a token before starting the container:\n\n```bash\nlocalstack auth set-token <your-auth-token>\n```\n\nOr pass it as an environment variable:\n\n```bash\nexport LOCALSTACK_AUTH_TOKEN=<your-auth-token>\n```\n\n## Core Python Usage With boto3\n\nPoint your AWS SDK clients at LocalStack's edge endpoint. `localhost.localstack.cloud` is the official hostname LocalStack documents for localhost access:\n\n```python\nimport boto3\n\ns3 = boto3.client(\n    \"s3\",\n    endpoint_url=\"http://localhost.localstack.cloud:4566\",\n    aws_access_key_id=\"test\",\n    aws_secret_access_key=\"test\",\n    region_name=\"us-east-1\",\n)\n\ns3.create_bucket(Bucket=\"demo-bucket\")\nprint(s3.list_buckets())\n```\n\nSQS example:\n\n```python\nimport boto3\n\nsqs = boto3.client(\n    \"sqs\",\n    endpoint_url=\"http://localhost.localstack.cloud:4566\",\n    aws_access_key_id=\"test\",\n    aws_secret_access_key=\"test\",\n    region_name=\"us-east-1\",\n)\n\nqueue_url = sqs.create_queue(QueueName=\"jobs\")[\"QueueUrl\"]\nsqs.send_message(QueueUrl=queue_url, MessageBody=\"hello\")\nprint(sqs.receive_message(QueueUrl=queue_url))\n```\n\nIf your app runs inside another container on the same Docker network, use the container hostname instead of `localhost`. The LocalStack networking guide documents `localstack-main` as the default main container name and also supports user-defined network aliases such as `localstack`.\n\n## AWS CLI And `awslocal`\n\nPrefer `awslocal` over `aws --endpoint-url ...` for routine shell automation:\n\n```bash\nawslocal s3 mb s3://demo-bucket\nawslocal s3 ls\nawslocal sqs create-queue --queue-name jobs\n```\n\nThe LocalStack AWS CLI docs call out a common pitfall: `aws --no-sign-request` can route requests to the wrong service. Use `awslocal` when possible.\n\n## Init Hooks And Seeding Infrastructure\n\nLocalStack can run bootstrap scripts during container startup. This is the cleanest way to pre-create buckets, queues, or other test infrastructure for integration tests.\n\nSupported hook directories:\n\n- `/etc/localstack/init/boot.d`\n- `/etc/localstack/init/start.d`\n- `/etc/localstack/init/ready.d`\n- `/etc/localstack/init/shutdown.d`\n\n`ready.d` is the most common choice because services are available by then. Example:\n\n```bash\n#!/bin/bash\nset -euo pipefail\n\nawslocal s3 mb s3://demo-bucket || true\nawslocal sqs create-queue --queue-name jobs >/dev/null\n```\n\nMount it into the container:\n\n```yaml\nvolumes:\n  - \"./init/01-bootstrap.sh:/etc/localstack/init/ready.d/01-bootstrap.sh\"\n```\n\nHook files run in alphanumeric order. LocalStack supports shell and Python scripts plus Terraform files through the extension-based auto-detection in the init-hook docs.\n\n## Persistence And State\n\nEnable persistence when your tests or local workflows need state to survive restarts:\n\n```bash\nPERSISTENCE=1 localstack start -d\n```\n\nIn Docker-based setups, LocalStack stores state under:\n\n```text\n/var/lib/localstack/state\n```\n\nYou can also export and import state snapshots through the state-management API:\n\n```bash\ncurl -X POST http://localhost:4566/_localstack/state/export\ncurl -X POST http://localhost:4566/_localstack/state/import\n```\n\nState files are not guaranteed to be portable across LocalStack versions, so do not assume a snapshot from one version will restore cleanly on another.\n\n## Configuration Notes\n\n- `SERVICES=s3,sqs,...` reduces startup time and keeps service initialization explicit.\n- `EAGER_SERVICE_LOADING=1` preloads configured services on startup instead of waiting for first use.\n- `LOCALSTACK_VOLUME_DIR` changes the host directory used for mounted LocalStack data.\n- `MAIN_DOCKER_NETWORK` controls which Docker network child containers join.\n- `GATEWAY_LISTEN` can change the bind address or edge port if `4566` conflicts with another process.\n\n## Common Pitfalls\n\n- The `localstack` package is mainly the CLI. Do not design your app around importing `localstack`; configure your normal AWS SDK clients to hit the LocalStack endpoint instead.\n- LocalStack depends on Docker for the standard runtime flow. A successful `pip install` is not enough if Docker is missing or unhealthy.\n- Pin the Docker image tag in Compose or CI. The install docs warn that a bare `docker compose up` can otherwise pull the current mainline image.\n- If your code runs in Docker, `localhost` inside that container is not the LocalStack host. Use a shared-network hostname such as `localstack` or `localstack-main`.\n- Keep region values consistent. Many AWS SDK examples silently default to `us-east-1`; mismatched regions can make resources appear \"missing.\"\n- For S3 presigned URLs and similar flows, keep both `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` set, even though LocalStack ignores the secret internally.\n- `CONFIG_PROFILE` is a CLI feature, not a Compose feature.\n- Persistence snapshots can break across version upgrades. Recreate fixtures if a restored state behaves strangely after a version bump.\n\n## Version-Sensitive Notes For 4.14.0\n\n- PyPI lists `localstack 4.14.0` with Python `>=3.10`, released on February 26, 2026.\n- The LocalStack install docs currently show `localstack --version` returning `4.14.0`.\n- The LocalStack credentials docs say the single authenticated image rollout for LocalStack for AWS starts on March 23, 2026. If your existing setup assumes unauthenticated image pulls, verify whether you now need `localstack auth set-token` or `LOCALSTACK_AUTH_TOKEN`.\n- The PyPI project page and docs both support `pip install localstack`, but parts of the long PyPI project description still mention `localstack-cli-standalone`. Prefer the package named in this entry unless your environment specifically needs the standalone CLI distribution.\n\n## Official Sources Used\n\n- LocalStack docs root: `https://docs.localstack.cloud/references/`\n- Install LocalStack: `https://docs.localstack.cloud/getting-started/installation/`\n- Configuration: `https://docs.localstack.cloud/references/configuration/`\n- AWS credentials: `https://docs.localstack.cloud/aws/capabilities/config/credentials/`\n- AWS CLI integration: `https://docs.localstack.cloud/aws/integrations/aws-native-tools/aws-cli/`\n- Boto3 integration: `https://docs.localstack.cloud/aws/integrations/aws-sdks/python-boto3/`\n- Initialization hooks: `https://docs.localstack.cloud/aws/capabilities/config/initialization-hooks/`\n- State management: `https://docs.localstack.cloud/aws/capabilities/state-management/`\n- Networking / endpoint guidance: `https://docs.localstack.cloud/aws/capabilities/networking/accessing-endpoint-url/`\n- PyPI package page: `https://pypi.org/project/localstack/`\n"
  },
  {
    "path": "content/locust/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Locust package guide for Python load testing with the official Locust 2.43.3 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.43.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"locust,python,load-testing,performance,http,distributed\"\n---\n\n# Locust Python Package Guide\n\n## Golden Rule\n\nUse `locust` for protocol-level load testing, not browser automation. Write a `locustfile.py`, run Locust against a known target host, and validate response content explicitly when status code alone is not enough.\n\n## Install\n\nPin the package version used by the project:\n\n```bash\npython -m pip install \"locust==2.43.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"locust==2.43.3\"\npoetry add \"locust==2.43.3\"\n```\n\nUseful PyPI extras when you need them:\n\n```bash\npython -m pip install \"locust[mqtt]==2.43.3\"\npython -m pip install \"locust[otel]==2.43.3\"\n```\n\nLocust also documents `uvx locust` for one-off runs without installing it into the current environment.\n\n## Minimal `locustfile.py`\n\nThe common starting point is `HttpUser` plus `task` functions:\n\n```python\nfrom locust import HttpUser, between, task\n\nclass WebsiteUser(HttpUser):\n    wait_time = between(1, 3)\n    host = \"https://example.com\"\n\n    @task\n    def index(self) -> None:\n        self.client.get(\"/\")\n\n    @task(3)\n    def health(self) -> None:\n        self.client.get(\"/health\")\n```\n\nRun it with the web UI:\n\n```bash\nlocust -f locustfile.py\n```\n\nBy default the UI listens on `http://localhost:8089`.\n\n## Headless Runs And CI\n\nFor automation or CI, run headless and set user count, spawn rate, and runtime explicitly:\n\n```bash\nlocust -f locustfile.py \\\n  --headless \\\n  --users 20 \\\n  --spawn-rate 5 \\\n  --run-time 2m \\\n  --host https://staging.example.com\n```\n\nUseful report outputs:\n\n```bash\nlocust -f locustfile.py --headless --users 50 --spawn-rate 10 --run-time 5m --html report.html\nlocust -f locustfile.py --headless --users 50 --spawn-rate 10 --run-time 5m --csv run_metrics\n```\n\nIf you want a run to start automatically but keep the web UI available, use `--autostart` instead of `--headless`.\n\n## Core Usage Patterns\n\n### Reuse session state and log in once\n\n`on_start()` is the normal place to establish authenticated state for each simulated user:\n\n```python\nfrom locust import HttpUser, task\n\nclass ApiUser(HttpUser):\n    host = \"https://api.example.com\"\n\n    def on_start(self) -> None:\n        response = self.client.post(\n            \"/login\",\n            json={\"username\": \"demo\", \"password\": \"secret\"},\n        )\n        response.raise_for_status()\n\n    @task\n    def profile(self) -> None:\n        self.client.get(\"/me\")\n```\n\nCookies are persisted by the HTTP client. For token-based auth, store the token from `on_start()` and send it in headers.\n\n### Group dynamic URLs in stats\n\nUse `name=` so IDs or query-heavy routes do not explode the statistics table:\n\n```python\n@task\ndef item(self) -> None:\n    item_id = 123\n    self.client.get(f\"/items/{item_id}\", name=\"/items/[id]\")\n```\n\n### Validate response content with `catch_response`\n\nWhen a 200 response can still be logically wrong, mark success or failure yourself:\n\n```python\n@task\ndef search(self) -> None:\n    with self.client.get(\"/search?q=locust\", catch_response=True) as response:\n        if \"locust\" not in response.text.lower():\n            response.failure(\"expected search term in body\")\n```\n\n### Organize or filter tasks\n\nUse task weights for traffic mix and `@tag` when you need selective execution:\n\n```python\nfrom locust import HttpUser, between, tag, task\n\nclass TaggedUser(HttpUser):\n    wait_time = between(1, 2)\n\n    @tag(\"smoke\")\n    @task\n    def smoke(self) -> None:\n        self.client.get(\"/health\")\n```\n\nThen run only tagged tasks:\n\n```bash\nlocust -f locustfile.py --tags smoke\n```\n\n## Configuration\n\nLocust reads configuration in this order: home config, local config, explicit `--config`, environment variables, then CLI flags. In practice, CLI flags override everything else.\n\nCommon config file names:\n\n- `~/.locust.conf`\n- `./locust.conf`\n- `./pyproject.toml`\n\nExample `locust.conf`:\n\n```ini\nheadless = true\nusers = 25\nspawn-rate = 5\nrun-time = 3m\nhost = https://staging.example.com\nhtml = reports/locust.html\n```\n\nUseful environment variables:\n\n```bash\nexport LOCUST_HOST=\"https://staging.example.com\"\nexport LOCUST_USERS=\"25\"\nexport LOCUST_SPAWN_RATE=\"5\"\nexport LOCUST_HEADLESS=\"true\"\n```\n\n## Web UI Authentication\n\nThere are two separate auth concerns:\n\n1. Application-under-test auth: usually handled in `on_start()` with your app's login flow or bearer tokens.\n2. Locust web UI auth: protects the Locust dashboard itself.\n\nFor simple web UI protection, enable the built-in login screen:\n\n```bash\nlocust -f locustfile.py --web-login\n```\n\nFor custom authentication, register the documented `username_password_callback` hook and use `environment.web_ui.auth_args` to configure the UI. Locust's extension docs show how to integrate custom auth providers and `Flask-Login`.\n\n## Distributed Execution And Higher Load\n\nSingle-process Locust runs can become CPU-bound before the target system is saturated. The official guidance is:\n\n- use more workers or `--processes` when one machine has multiple cores\n- use distributed mode for larger tests\n- switch to `FastHttpUser` when the Python HTTP client becomes the bottleneck\n\nTypical distributed startup:\n\n```bash\n# controller\nlocust -f locustfile.py --master\n\n# worker nodes\nlocust -f locustfile.py --worker --master-host 192.168.1.10\n```\n\nFor a quick multi-process run on one machine:\n\n```bash\nlocust -f locustfile.py --processes -1\n```\n\nIf the locustfile is only present on the master, workers can fetch it by starting with `-f -`.\n\n## Common Pitfalls\n\n- `HttpUser` is not a real browser. It will not execute JavaScript, parse DOM state, or load assets the way Playwright or Selenium would.\n- If you do not set `host` on the class and do not pass `--host`, your test will fail before requests can run.\n- Very high `wait_time` values, blocking code, and expensive response parsing can make the generator the bottleneck instead of the target service.\n- Group dynamic endpoints with `name=` or stats become noisy and hard to interpret.\n- Use `catch_response=True` when correctness depends on response body content, not just status code.\n- Headless CI runs should always set `--users`, `--spawn-rate`, and `--run-time`; otherwise runs are easy to misread or leave hanging.\n- Distributed mode only helps if each worker can reach the same target environment and any shared test data is coordinated safely.\n\n## Version-Sensitive Notes For 2.43.3\n\n- PyPI currently lists `locust 2.43.3` and `Requires-Python >=3.10`.\n- The official changelog for the 2.43.x line notes a `requests>=2.32.5` update in `2.43.0`; avoid copying older environment snapshots that pin older `requests` versions around Locust.\n- `2.43.3` is a small patch release in the stable line rather than a major behavior shift, so most current stable docs examples still apply directly to this version.\n"
  },
  {
    "path": "content/lodash/docs/lodash/javascript/DOC.md",
    "content": "---\nname: lodash\ndescription: \"Lodash utility library for JavaScript with modular imports, deep object helpers, collection transforms, function wrappers, and templating\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.17.23\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"lodash,javascript,utility,collections,objects,functions\"\n---\n\n# Lodash JavaScript Package Guide\n\n## What It Is\n\n`lodash` is a general-purpose JavaScript utility library for working with arrays, objects, strings, and functions.\n\nUse it when you need:\n\n- safe deep property reads and writes with `_.get`, `_.has`, and `_.set`\n- collection transforms such as `_.groupBy`, `_.map`, and `_.sortBy`\n- function wrappers such as `_.debounce`, `_.throttle`, and `_.memoize`\n- deep cloning and comparison with `_.cloneDeep` and `_.isEqual`\n- simple string templating with `_.template`\n\n## Install\n\n```bash\nnpm install lodash@4.17.23\n```\n\nCommon import patterns from the maintainer package README:\n\n```javascript\nconst _ = require('lodash');\nconst core = require('lodash/core');\nconst fp = require('lodash/fp');\n\nconst get = require('lodash/get');\nconst debounce = require('lodash/debounce');\n```\n\nUse the full build when convenience matters most. Use `lodash/<method>` imports when you only need a few helpers and want smaller bundles.\n\n## Setup Model\n\nThere is no client initialization, authentication flow, or required environment variable.\n\nPick the entrypoint that matches your app:\n\n- `require('lodash')` for the full build\n- `require('lodash/core')` for the core build\n- `require('lodash/fp')` for immutable, auto-curried, iteratee-first, data-last helpers\n- `require('lodash/<method>')` to load one method directly\n\n## Core Usage\n\n### Read nested data safely\n\n```javascript\nconst _ = require('lodash');\n\nconst response = {\n  data: [\n    {\n      profile: {\n        email: 'ada@example.com',\n      },\n    },\n  ],\n};\n\nconst email = _.get(response, 'data[0].profile.email');\nconst city = _.get(response, 'data[0].profile.city', 'unknown');\nconst hasEmail = _.has(response, ['data', '0', 'profile', 'email']);\n\nconsole.log({ email, city, hasEmail });\n```\n\n`_.get()` returns the fallback only when the resolved value is `undefined`.\n\n### Build and patch nested config objects\n\n```javascript\nconst _ = require('lodash');\n\nconst defaults = {\n  http: { timeoutMs: 5000, retries: 1 },\n  features: { search: false },\n};\n\nconst envConfig = {\n  http: { retries: 3 },\n  features: { search: true },\n};\n\nconst config = _.cloneDeep(defaults);\n\n_.set(config, 'logging.level', 'debug');\n_.merge(config, envConfig);\n\nconsole.log(config);\n// {\n//   http: { timeoutMs: 5000, retries: 3 },\n//   features: { search: true },\n//   logging: { level: 'debug' }\n// }\n```\n\n`_.set()` and `_.merge()` mutate the destination object. Clone first if you need to preserve the original.\n\n### Group and reshape collections\n\n```javascript\nconst _ = require('lodash');\n\nconst jobs = [\n  { id: 1, state: 'queued', owner: 'api' },\n  { id: 2, state: 'running', owner: 'worker' },\n  { id: 3, state: 'queued', owner: 'worker' },\n];\n\nconst byState = _.groupBy(jobs, 'state');\nconst queuedIds = _.map(byState.queued, 'id');\n\nconsole.log(byState);\nconsole.log(queuedIds);\n```\n\n`_.groupBy()` accepts a function iteratee or a property-name shorthand such as `'state'`.\n\n### Debounce and throttle repeated calls\n\n```javascript\nconst _ = require('lodash');\n\nfunction saveDraft(body) {\n  console.log('saving', body);\n}\n\nconst debouncedSave = _.debounce(saveDraft, 300, {\n  maxWait: 1000,\n  trailing: true,\n});\n\nconst throttledRefresh = _.throttle(() => {\n  console.log('refreshing status');\n}, 1000, {\n  leading: true,\n  trailing: true,\n});\n\ndebouncedSave('draft-1');\ndebouncedSave('draft-2');\nthrottledRefresh();\nthrottledRefresh();\n\nprocess.on('SIGTERM', () => {\n  debouncedSave.flush();\n  throttledRefresh.cancel();\n});\n```\n\nBoth wrappers return functions with `cancel()` and `flush()` helpers. Keep a reference to the wrapped function, not just the original callback.\n\n### Memoize expensive pure functions\n\n```javascript\nconst _ = require('lodash');\n\nconst buildPermissionList = _.memoize(\n  (tenantId, role) => {\n    console.log('cache miss');\n    return [`${tenantId}:${role}:read`, `${tenantId}:${role}:write`];\n  },\n  (tenantId, role) => `${tenantId}:${role}`,\n);\n\nconsole.log(buildPermissionList('acme', 'admin'));\nconsole.log(buildPermissionList('acme', 'admin'));\n```\n\nWithout a resolver, `_.memoize()` uses only the first argument as the cache key.\n\n### Deep-clone and compare structured values\n\n```javascript\nconst _ = require('lodash');\n\nconst original = [{ id: 1, tags: ['a', 'b'] }];\nconst copy = _.cloneDeep(original);\n\ncopy[0].tags.push('c');\n\nconsole.log(original[0].tags); // ['a', 'b']\nconsole.log(copy[0].tags);     // ['a', 'b', 'c']\nconsole.log(_.isEqual(original, copy)); // false\n```\n\nUse `_.cloneDeep()` before applying mutating helpers when you want a separate copy.\n\n### Chain multi-step transforms\n\n```javascript\nconst _ = require('lodash');\n\nconst users = [\n  { user: 'barney', age: 36, active: true },\n  { user: 'fred', age: 40, active: false },\n  { user: 'pebbles', age: 1, active: true },\n];\n\nconst youngestActiveUser = _.chain(users)\n  .filter((user) => user.active)\n  .sortBy('age')\n  .map((user) => `${user.user}:${user.age}`)\n  .head()\n  .value();\n\nconsole.log(youngestActiveUser); // pebbles:1\n```\n\n`_.chain()` enables explicit wrapper chains. Finish the sequence with `.value()`.\n\n### Render small templates\n\n```javascript\nconst _ = require('lodash');\n\nconst renderUser = _.template('<li><%- name %> (<%= role %>)</li>');\n\nconsole.log(renderUser({ name: '<Admin>', role: 'owner' }));\n// <li>&lt;Admin&gt; (owner)</li>\n```\n\n`<%- %>` HTML-escapes output. `<%= %>` interpolates values, and `<% %>` executes JavaScript inside the template.\n\n## Important Pitfalls\n\n- `_.set()` and `_.merge()` mutate the destination object. Clone first when you need immutable updates.\n- `_.merge()` recursively merges arrays and plain objects. It does not concatenate arrays by default; use `_.mergeWith()` if you need custom array behavior.\n- `_.memoize()` uses the first argument as its default cache key. Pass a resolver when the result depends on multiple arguments.\n- `_.debounce()` and `_.throttle()` return wrapper functions. Hold onto those wrappers so you can call `cancel()` or `flush()` during cleanup.\n- `_.template()` can execute JavaScript with `<% %>`. Only compile trusted template strings.\n- If bundle size matters, prefer `lodash/<method>` or `lodash/core` instead of always importing the full build.\n\n## Version Notes For 4.17.23\n\n- This guide targets `lodash@4.17.23`.\n- The maintainer docs URL is versioned as `4.17.21`, while the npm package README for `4.17.23` keeps the same documented entrypoints: `lodash`, `lodash/core`, `lodash/fp`, and `lodash/<method>`.\n\n## Official Sources\n\n- Maintainer docs: https://lodash.com/docs/4.17.21\n- Package homepage: https://lodash.com/\n- npm package: https://www.npmjs.com/package/lodash\n- Package source tree: https://github.com/lodash/lodash/tree/4.17.23-npm\n"
  },
  {
    "path": "content/loguru/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Loguru Python package guide for structured, file, async, and application-aware logging\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"loguru,python,logging,structured-logging,observability\"\n---\n\n# Loguru Python Package Guide\n\n## Golden Rule\n\nUse Loguru through the single shared `logger` object from `from loguru import logger`, configure handlers once at your application's entry point, remove the default stderr handler before adding your own sinks, and avoid `diagnose=True` in production because exception rendering can expose local variable values.\n\nIf you are writing a library, do not call `logger.add()` at import time. Disable your package namespace instead and let the application decide how logging should be configured.\n\n## Install\n\nPin the version if your project depends on current `0.7.x` behavior:\n\n```bash\npython -m pip install \"loguru==0.7.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"loguru==0.7.3\"\npoetry add \"loguru==0.7.3\"\n```\n\nLoguru is pure Python and PyPI classifiers for `0.7.3` include CPython and PyPy across Python 3.x versions.\n\n## Initialize And Configure\n\nLoguru ships with one pre-configured handler that logs to `sys.stderr`. That is convenient for scripts, but most real applications should replace it explicitly.\n\n### Minimal application setup\n\n```python\nimport sys\nfrom loguru import logger\n\ndef configure_logging() -> None:\n    logger.remove()\n    logger.add(\n        sys.stderr,\n        level=\"INFO\",\n        format=\"{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} | {message}\",\n        backtrace=False,\n        diagnose=False,\n    )\n\nif __name__ == \"__main__\":\n    configure_logging()\n    logger.info(\"Application started\")\n```\n\nNotes:\n\n- Call `logger.remove()` first or you will usually get duplicate console logs.\n- Configure handlers once, ideally inside the entry point guarded by `if __name__ == \"__main__\":`.\n- Reconfiguring in imported modules or worker startup paths commonly causes duplicate output and file conflicts.\n\n### Add a rotating file sink\n\n```python\nfrom loguru import logger\n\nlogger.add(\n    \"app.log\",\n    level=\"DEBUG\",\n    rotation=\"100 MB\",\n    retention=\"14 days\",\n    compression=\"gz\",\n    enqueue=True,\n    backtrace=False,\n    diagnose=False,\n)\n```\n\nUse `enqueue=True` when multiple threads or processes can write concurrently. Call `logger.complete()` before child processes exit so queued messages flush cleanly.\n\n### Configure from structured data\n\n`logger.configure()` is the Loguru replacement for `logging.basicConfig()` and `logging.dictConfig()`:\n\n```python\nimport sys\nfrom loguru import logger\n\nlogger.configure(\n    handlers=[\n        {\n            \"sink\": sys.stderr,\n            \"level\": \"INFO\",\n            \"format\": \"{time} | {level} | {message}\",\n        }\n    ],\n    extra={\"service\": \"billing-api\"},\n)\n```\n\n## Core Usage\n\n### Basic logging\n\nLoguru uses `{}` formatting, not `%s` formatting:\n\n```python\nfrom loguru import logger\n\nuser_id = 42\nlogger.info(\"User {} signed in\", user_id)\nlogger.warning(\"Quota for {user} is almost exhausted\", user=\"alice\")\n```\n\nDo not pre-format with f-strings when values may contain braces. Let Loguru do the formatting.\n\n### Exceptions\n\n```python\nfrom loguru import logger\n\ntry:\n    1 / 0\nexcept ZeroDivisionError:\n    logger.exception(\"Computation failed\")\n```\n\nFor automatic exception logging around a function or block:\n\n```python\nfrom loguru import logger\n\n@logger.catch\ndef run_job() -> None:\n    raise RuntimeError(\"boom\")\n```\n\n`logger.catch()` is useful, but keep `diagnose=False` on production sinks unless you explicitly want local variable values in traces.\n\n### Structured context with `bind()` and `contextualize()`\n\n```python\nfrom loguru import logger\n\nlogger.remove()\nlogger.add(\n    lambda msg: print(msg, end=\"\"),\n    format=\"{time} | {extra[request_id]} | {message}\",\n)\n\nrequest_logger = logger.bind(request_id=\"req-123\")\nrequest_logger.info(\"Request accepted\")\n\nwith logger.contextualize(request_id=\"req-456\"):\n    logger.info(\"Context-local request\")\n```\n\nUse:\n\n- `bind()` for a derived logger carrying stable per-object or per-request metadata\n- `contextualize()` for temporary context scoped to a block\n- `patch()` when you need to inject dynamic values into every record before sinks receive it\n\nExample `patch()` usage:\n\n```python\nfrom datetime import datetime, timezone\nfrom loguru import logger\n\npatched_logger = logger.patch(\n    lambda record: record[\"extra\"].update(utc=datetime.now(timezone.utc).isoformat())\n)\n```\n\n### JSON logs\n\n```python\nimport sys\nfrom loguru import logger\n\nlogger.remove()\nlogger.add(sys.stdout, serialize=True, backtrace=False, diagnose=False)\nlogger.bind(request_id=\"req-123\").info(\"Created order\")\n```\n\n`serialize=True` is the simplest path when you want machine-readable logs for ingestion systems.\n\n### Lazy debug values\n\nIf computing log values is expensive, use `opt(lazy=True)`:\n\n```python\nfrom loguru import logger\n\ndef expensive_value() -> str:\n    return \"computed\"\n\nlogger.opt(lazy=True).debug(\"Debug payload: {}\", expensive_value)\n```\n\nThe callable is only evaluated if a configured sink would actually emit the message.\n\n## Configuration And Environment\n\nThere is no authentication model for Loguru. Configuration is local to your process and controlled through handlers, formats, levels, and optional environment variables.\n\nUseful environment variables:\n\n- `LOGURU_AUTOINIT=False` disables the pre-configured default stderr sink\n- `LOGURU_FORMAT=...` changes the default sink format\n- `LOGURU_DIAGNOSE=NO` disables verbose exception variable capture for the default sink\n- `LOGURU_LEVEL=INFO` changes the default sink level\n\nEnvironment variables are most useful for scripts and temporary overrides. For applications, explicit code configuration is easier to audit.\n\n## Library Vs Application Usage\n\nFor an application:\n\n- configure handlers in the entry file\n- import `logger` everywhere else\n- avoid repeated `add()` calls across modules\n\nFor a library:\n\n```python\nfrom loguru import logger\n\nlogger.disable(\"my_library\")\n```\n\nKeep this in your package initialization path and do not add handlers there. Applications that want your library logs can opt in with `logger.enable(\"my_library\")`.\n\n## Common Pitfalls\n\n### Duplicate logs\n\nThe usual causes are:\n\n- adding handlers without first calling `logger.remove()`\n- configuring logging in more than one module\n- configuring logging in code that is re-executed by `multiprocessing`, Gunicorn, or Uvicorn workers\n\nGuard application setup with `if __name__ == \"__main__\":` and configure once.\n\n### Curly braces and f-strings\n\nLoguru treats log messages like `str.format()`. These can fail:\n\n```python\ndata = {\"foo\": 42}\nlogger.info(f\"Processing {data}\", data=data)\n```\n\nPrefer:\n\n```python\nlogger.info(\"Processing {data}\", data=data)\nlogger.bind(data=data).info(\"Processing payload\")\n```\n\nIf you need literal braces, escape them as `{{` and `}}`.\n\n### Missing `extra[...]` keys in formats\n\nThis format will fail if `request_id` is absent:\n\n```python\n\"{time} | {extra[request_id]} | {message}\"\n```\n\nEither ensure the key is always bound or provide a patcher/default `extra` configuration so every record contains the expected fields.\n\n### Deadlocks and unsafe sink behavior\n\nDo not log from inside your own sink function, a signal handler, or cleanup paths that can re-enter Loguru. The logger is not re-entrant and can raise `RuntimeError` to avoid deadlocks.\n\n### Multiprocessing on Windows\n\nThe default stderr sink is not picklable. For spawned processes on Windows:\n\n- remove the default sink first\n- add file or queue-backed sinks with `enqueue=True`\n- call `logger.complete()` before the child exits\n\nIf you use a non-default multiprocessing context, pass it through `logger.add(..., context=context)`.\n\n### Production exception leakage\n\n`diagnose=True` is convenient in development, but it can print local variables and sensitive values. Prefer:\n\n```python\nlogger.add(\"app.log\", backtrace=False, diagnose=False)\n```\n\n## Interop With Standard `logging`\n\nIf you are migrating from the standard library:\n\n- replace `logging.getLogger(__name__)` with `from loguru import logger`\n- replace `basicConfig()` and `dictConfig()` with `logger.configure()`\n- replace `%s`-style formatting with `{}` formatting\n- replace `LoggerAdapter` or `extra=` patterns with `bind()`\n- replace `isEnabledFor()` guard code with `logger.opt(lazy=True)`\n\n`logger.add()` can also accept a built-in `logging.Handler` sink when you need to bridge into an existing `logging`-based stack.\n\n## Version-Sensitive Notes\n\n- `0.7.3` is the current upstream release in the stable docs and PyPI as of 2026-03-12.\n- The `0.7.3` changelog includes fixes for Cython stack-frame incompatibility, a thread-safety issue affecting `logger.remove()`, Python 3.13 `diagnose=True` formatting, and standard-library `logging.Formatter()` compatibility for non-standard levels.\n- `0.7.1` added the `context=` argument to `logger.add()` for multiprocessing context control. If you see examples using custom multiprocessing contexts, they require at least `0.7.1`.\n- `0.7.0` made `patch()` cumulative instead of overriding prior patchers. Older blog posts may describe pre-`0.7.0` behavior.\n\n## Official Sources\n\n- Stable docs: `https://loguru.readthedocs.io/en/stable/`\n- API reference: `https://loguru.readthedocs.io/en/stable/api/logger.html`\n- Migration guide: `https://loguru.readthedocs.io/en/stable/resources/migration.html`\n- Troubleshooting: `https://loguru.readthedocs.io/en/stable/resources/troubleshooting.html`\n- Recipes: `https://loguru.readthedocs.io/en/stable/resources/recipes.html`\n- Changelog: `https://loguru.readthedocs.io/en/stable/project/changelog.html`\n- PyPI: `https://pypi.org/project/loguru/`\n"
  },
  {
    "path": "content/lru-cache/docs/lru-cache/javascript/DOC.md",
    "content": "---\nname: lru-cache\ndescription: \"lru-cache JavaScript package guide for bounded in-memory caching, TTLs, async cache loading, and size-based eviction\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"11.2.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"lru-cache,javascript,nodejs,caching,memoization,ttl\"\n---\n\n# lru-cache JavaScript Package Guide\n\n## Golden Rule\n\nUse `lru-cache` for in-process hot data, not as a shared or durable cache. Always give the cache a real bound with `max`, `maxSize`, or `ttl`, and prefer setting `max` even when you also use TTL or size tracking.\n\n## Install\n\nPin the package version your app expects:\n\n```bash\nnpm install lru-cache@11.2.6\n```\n\n`lru-cache@11.2.6` declares Node `20 || >=22` in its published package metadata.\n\nUse the named export:\n\n```js\nimport { LRUCache } from 'lru-cache'\n```\n\nCommonJS also works:\n\n```js\nconst { LRUCache } = require('lru-cache')\n```\n\n## Setup And Configuration\n\n`lru-cache` is an in-memory library. There is no auth flow, no service endpoint, and no required environment variables.\n\nThe important configuration choices are:\n\n- Which bound you want: `max`, `maxSize`, or `ttl`\n- Whether TTL should be lazy or proactively purged\n- Whether entries need size accounting with `sizeCalculation`\n- Whether values need cleanup on eviction with `dispose` or `disposeAfter`\n- Whether cache misses should load values through `fetchMethod` or `memoMethod`\n\nConstructor safety rules to keep in mind:\n\n- At least one of `max`, `maxSize`, or `ttl` is required.\n- `max` is the fastest and safest default because storage is pre-allocated.\n- If you use `maxSize`, every entry must provide size information through `sizeCalculation` or `cache.set(key, value, { size })`.\n- If you use `ttl` without `max` or `maxSize`, stale entries are still removed lazily unless you also enable `ttlAutopurge`.\n\n## Core Usage\n\n### Start with a bounded cache\n\n```js\nimport { LRUCache } from 'lru-cache'\n\nconst userCache = new LRUCache({\n  max: 500,\n  ttl: 5 * 60 * 1000,\n})\n\nexport async function getUser(userId) {\n  const key = `user:${userId}`\n  const cachedUser = userCache.get(key)\n\n  if (cachedUser !== undefined) {\n    return cachedUser\n  }\n\n  const response = await fetch(`https://example.com/api/users/${userId}`)\n  if (!response.ok) {\n    throw new Error(`Failed to load user ${userId}: ${response.status}`)\n  }\n\n  const user = await response.json()\n  userCache.set(key, user)\n  return user\n}\n\nexport function invalidateUser(userId) {\n  userCache.delete(`user:${userId}`)\n}\n```\n\n`get()` returns the cached value and updates recency. If you need to inspect a value without affecting LRU order, use `peek()` instead.\n\n### Add TTL-based expiration\n\n```js\nimport { LRUCache } from 'lru-cache'\n\nconst sessionCache = new LRUCache({\n  max: 10_000,\n  ttl: 15 * 60 * 1000,\n  updateAgeOnGet: true,\n})\n\nexport function storeSession(sessionId, session) {\n  sessionCache.set(sessionId, session)\n}\n\nexport function getSession(sessionId) {\n  return sessionCache.get(sessionId)\n}\n\nsetInterval(() => {\n  sessionCache.purgeStale()\n}, 60_000).unref()\n```\n\nWith `updateAgeOnGet: true`, reads reset the entry age and make TTL behave like sliding expiration. By default, stale entries are treated as missing when accessed and removed lazily. If you need proactive cleanup, enable `ttlAutopurge`, but the maintainer docs warn that it can significantly reduce performance.\n\n### Limit by payload size\n\n```js\nimport { LRUCache } from 'lru-cache'\n\nconst responseCache = new LRUCache({\n  max: 500,\n  maxSize: 5 * 1024 * 1024,\n  maxEntrySize: 256 * 1024,\n  sizeCalculation: value => Buffer.byteLength(JSON.stringify(value), 'utf8'),\n})\n\nexport function cacheResponse(key, value) {\n  responseCache.set(key, value)\n}\n\nexport function getResponse(key) {\n  return responseCache.get(key)\n}\n```\n\nUse this when entries vary widely in size. `maxSize` bounds total cache weight, and `maxEntrySize` prevents one oversized value from crowding out the rest of the cache.\n\n### Load missing values with `fetch()`\n\n```js\nimport { LRUCache } from 'lru-cache'\n\nasync function loadProduct(productId, signal) {\n  const response = await fetch(`https://example.com/api/products/${productId}`, {\n    signal,\n  })\n\n  if (!response.ok) {\n    throw new Error(`Failed to load product ${productId}: ${response.status}`)\n  }\n\n  return response.json()\n}\n\nconst productCache = new LRUCache({\n  max: 1000,\n  ttl: 60_000,\n  allowStale: true,\n  fetchMethod: async (key, staleValue, { signal }) => {\n    const productId = key.slice('product:'.length)\n    return loadProduct(productId, signal)\n  },\n})\n\nexport function getProduct(productId) {\n  return productCache.fetch(`product:${productId}`)\n}\n```\n\n`fetch()` is useful when many callers may ask for the same missing key at once. Concurrent `fetch()` calls for the same key are coalesced into one underlying `fetchMethod` call. If you do not provide `fetchMethod`, `cache.fetch(key)` is effectively `Promise.resolve(cache.get(key))`.\n\nIf you need a timeout, pass a signal when calling `fetch()`:\n\n```js\nconst product = await productCache.fetch('product:42', {\n  signal: AbortSignal.timeout(250),\n})\n```\n\n### Memoize synchronous computation with `memo()`\n\n```js\nimport { readFileSync } from 'node:fs'\nimport { LRUCache } from 'lru-cache'\n\nconst configCache = new LRUCache({\n  max: 50,\n  ttl: 60_000,\n  memoMethod: filePath => JSON.parse(readFileSync(filePath, 'utf8')),\n})\n\nexport function loadConfig(filePath) {\n  return configCache.memo(filePath)\n}\n```\n\nUse `memo()` when the value can be computed synchronously from the key. For async work, use `fetch()` instead.\n\n### Snapshot and restore cache contents\n\n```js\nimport { LRUCache } from 'lru-cache'\n\nconst cache = new LRUCache({\n  max: 100,\n  ttl: 60_000,\n})\n\nconst snapshot = JSON.stringify(cache.dump())\n\nconst restoredCache = new LRUCache({\n  max: 100,\n  ttl: 60_000,\n})\n\nrestoredCache.load(JSON.parse(snapshot))\n```\n\n`dump()` and `load()` are useful for warm starts inside the same application architecture. Use the same cache options on restore, and remember that `dump()` includes stale entries as well.\n\n## Common Pitfalls\n\n- `ttl` is lazy expiration, not exact eviction timing. Without `ttlAutopurge`, stale entries remain until access, `purgeStale()`, or normal eviction.\n- `cache.set(key, undefined)` behaves like `cache.delete(key)`. `undefined` is never stored in the cache.\n- The public API expects keys and values to be non-null. Prefer explicit sentinel objects or symbols instead of `null` or `undefined` cache values.\n- `get()` updates recency, while `peek()` does not. `has()` does not update recency unless `updateAgeOnHas` is enabled, and stale entries return `false` from `has()`.\n- Object keys are matched by identity, not deep equality. Two distinct objects with the same shape are different keys.\n- With `maxSize`, every entry must have size information. If an entry is larger than `maxEntrySize`, it is not cached.\n- `fetch()` coalesces concurrent loads for the same key. The first in-flight call controls options such as abort and stale-on-rejection handling for the group.\n\n## Version-Sensitive Notes For 11.2.6\n\n- `11.2.6` declares Node `20 || >=22`.\n- The package export is named-only. Use `import { LRUCache } from 'lru-cache'` rather than a default import.\n- The published package also exports `lru-cache/raw` when you need the raw build instead of the standard `lru-cache` entrypoint.\n\n## Official Sources Used\n\n- Maintainer repository: https://github.com/isaacs/node-lru-cache\n- Maintainer README: https://github.com/isaacs/node-lru-cache#readme\n- Maintainer API docs: https://isaacs.github.io/node-lru-cache/\n- npm package metadata: https://www.npmjs.com/package/lru-cache\n"
  },
  {
    "path": "content/luigi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Luigi package guide for Python batch pipelines, task dependencies, and scheduler configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"luigi,python,pipeline,workflow,scheduler,batch,orchestration\"\n---\n\n# Luigi Python Package Guide\n\n## Golden Rule\n\nUse `luigi` to model batch pipelines as Python `Task` classes with explicit `requires()`, `output()`, and `run()` methods. Start with `--local-scheduler` for development, but use `luigid` in shared environments so Luigi can prevent duplicate task runs and give you the scheduler UI.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"luigi==3.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"luigi==3.8.0\"\npoetry add \"luigi==3.8.0\"\n```\n\nUseful extras from PyPI:\n\n```bash\npython -m pip install \"luigi[toml]==3.8.0\"\npython -m pip install \"luigi[prometheus]==3.8.0\"\npython -m pip install \"luigi[jsonschema]==3.8.0\"\n```\n\nNotes:\n\n- `luigi[toml]` adds TOML-based config support.\n- `luigi[prometheus]` is useful when you want scheduler or worker metrics integration.\n- `luigi[jsonschema]` is only needed if your code or config relies on that optional support.\n\n## Core Model\n\nLuigi task graphs are built from Python classes:\n\n- `requires()`: upstream task dependencies\n- `output()`: the `Target` that marks completion\n- `run()`: the work to execute\n- `complete()`: usually inherited; a task is complete when its outputs exist\n\nLuigi treats `output()` as the contract for completion, so your `run()` method must fully create the declared target before downstream tasks can run safely.\n\n## Minimal Working Pipeline\n\nThis is the common local-file pattern for simple ETL or reporting tasks:\n\n```python\nfrom __future__ import annotations\n\nimport json\nfrom pathlib import Path\n\nimport luigi\n\nclass FetchNumbers(luigi.Task):\n    date = luigi.DateParameter()\n\n    def output(self) -> luigi.LocalTarget:\n        return luigi.LocalTarget(f\"data/raw/{self.date}.json\")\n\n    def run(self) -> None:\n        Path(\"data/raw\").mkdir(parents=True, exist_ok=True)\n        rows = [{\"value\": 2}, {\"value\": 3}, {\"value\": 5}]\n        with self.output().open(\"w\") as f:\n            json.dump(rows, f)\n\nclass SumNumbers(luigi.Task):\n    date = luigi.DateParameter()\n\n    def requires(self) -> FetchNumbers:\n        return FetchNumbers(date=self.date)\n\n    def output(self) -> luigi.LocalTarget:\n        return luigi.LocalTarget(f\"data/processed/{self.date}.txt\")\n\n    def run(self) -> None:\n        Path(\"data/processed\").mkdir(parents=True, exist_ok=True)\n        with self.input().open(\"r\") as f:\n            rows = json.load(f)\n\n        total = sum(row[\"value\"] for row in rows)\n        with self.output().open(\"w\") as f:\n            f.write(f\"{total}\\n\")\n```\n\nRun it from the CLI:\n\n```bash\npython -m luigi --module my_pipeline SumNumbers --date 2026-03-12 --local-scheduler\n```\n\nNotes:\n\n- Task parameter names become CLI flags after the task family name.\n- Parameters with `_` in Python use `-` on the CLI, for example `my_parameter` becomes `--my-parameter`.\n- `self.input()` maps the `requires()` graph into the corresponding `Target` objects.\n\n## Running From Python\n\nUse `luigi.build()` when your entrypoint already has Python logic for argument parsing, configuration loading, or selecting tasks dynamically:\n\n```python\nimport datetime as dt\n\nimport luigi\n\nfrom my_pipeline import SumNumbers\n\nif __name__ == \"__main__\":\n    ok = luigi.build(\n        [SumNumbers(date=dt.date(2026, 3, 12))],\n        workers=4,\n        local_scheduler=True,\n    )\n    if not ok:\n        raise SystemExit(\"Luigi build failed\")\n```\n\nThis is often easier than shelling out to the CLI from another Python program.\n\n## Configuration And Scheduler Setup\n\nLuigi supports both config files and task parameters, but the docs note that parameters have largely superseded config for many application-level settings. Use config mainly for scheduler, worker, logging, and shared infrastructure defaults.\n\n### Config file discovery\n\nDefault config lookup for the `cfg` parser, from lower to higher priority:\n\n- `/etc/luigi/client.cfg` and `client.cfg` are deprecated old paths\n- `/etc/luigi/luigi.cfg`\n- `luigi.cfg`\n- `LUIGI_CONFIG_PATH`\n\nFor TOML configs:\n\n- `/etc/luigi/luigi.toml`\n- `luigi.toml`\n- `LUIGI_CONFIG_PATH`\n\nSet `LUIGI_CONFIG_PARSER=toml` if you want Luigi to read TOML instead of `cfg`.\n\n### Typical local config\n\n```ini\n[core]\ndefault-scheduler-host=localhost\ndefault-scheduler-port=8082\nno_configure_logging=false\n\n[worker]\nkeep_alive=true\ncheck_unfulfilled_deps=true\ncheck_complete_on_run=true\ncache_task_completion=true\n```\n\n`check_complete_on_run=true` is a useful safeguard when agents generate tasks that might forget to materialize outputs cleanly.\n\n### Local scheduler vs central scheduler\n\nUse `--local-scheduler` while iterating on task code:\n\n```bash\npython -m luigi --module my_pipeline SumNumbers --date 2026-03-12 --local-scheduler\n```\n\nFor shared or production-style runs, start the central scheduler:\n\n```bash\nluigid\n```\n\nThen run tasks without `--local-scheduler`. By default Luigi connects to `http://localhost:8082/`.\n\nUse the central scheduler when you need:\n\n- duplicate-run protection across workers or hosts\n- the web UI for dependency graphs and task state\n- task history or centralized scheduling behavior\n\n## Targets And Storage\n\n`luigi.LocalTarget` is the default file target for local pipelines. Luigi writes atomically, which is one reason targets are central to the framework.\n\nWhen using multiple workers or machines, your outputs must live on storage visible to all workers. If one worker writes only to local disk and another worker cannot see that path, Luigi may recompute the same task because completion is target-based.\n\nIf you need an externally created dependency, wrap it as `luigi.ExternalTask` instead of returning a bare `Target` from `requires()`.\n\n```python\nimport luigi\n\nclass UpstreamExport(luigi.ExternalTask):\n    date = luigi.DateParameter()\n\n    def output(self) -> luigi.LocalTarget:\n        return luigi.LocalTarget(f\"incoming/{self.date}.csv\")\n```\n\n## Common Patterns\n\n### Dynamic dependencies\n\nIf you only know a dependency at runtime, `yield` another task from `run()`. Luigi will suspend the current task, run the yielded task, then re-enter `run()`.\n\nThat means `run()` must be idempotent. Do not append blindly to files or mutate external state before the yielded task finishes unless you can safely repeat the work.\n\n### Parameterized recurring tasks\n\nLuigi is good at date-partitioned and backfill-style pipelines:\n\n```python\nclass DailyReport(luigi.Task):\n    date = luigi.DateParameter()\n```\n\nPrefer modeling partitions as parameters instead of hard-coding paths or dates inside `run()`.\n\n## Authentication And Network Notes\n\nLuigi itself is not a cloud auth SDK. Authentication depends on the systems your tasks talk to, such as databases, object stores, Hadoop, or APIs.\n\nFor the scheduler itself:\n\n- local development usually talks to `localhost:8082`\n- remote scheduler access is plain HTTP by default\n- if you need TLS, terminate it with an HTTP proxy and point Luigi at the resulting URL\n\nKeep secrets for downstream systems out of task IDs and scheduler-visible significant parameters. Luigi parameters are part of task identity unless marked otherwise.\n\n## Common Pitfalls\n\n- Do not return a `Target` directly from `requires()`. Luigi expects `Task` objects there; use `ExternalTask` for external data.\n- Do not declare multiple outputs unless you can preserve atomicity yourself. A single output target is the safest default.\n- Do not assume `run()` success means the task is complete. Completion is output-driven.\n- Do not use local disk outputs for multi-worker production jobs unless every worker shares that filesystem.\n- Do not forget `--local-scheduler` during early development. Otherwise Luigi will try to connect to a scheduler on `localhost:8082`.\n- Do not expose secrets as normal significant parameters. They can leak into task identity and scheduler UI state.\n- If you use dynamic dependencies with `yield`, make sure `run()` is repeatable because Luigi resumes it from scratch.\n- If you write binary files, use `format=Nop` with `LocalTarget`; Luigi strips the normal binary flag handling for its atomic file semantics.\n\n## Version-Sensitive Notes For Luigi 3.8.0\n\n- PyPI shows `luigi 3.8.0` released on March 6, 2026, and the verified Python requirement is now `>=3.10,<3.14`.\n- The top-level Read the Docs landing page also shows `3.8.0`, but several deeper pages still display older subpage version banners such as `3.7.x` or `3.6.0`. Treat those pages as authoritative for behavior only when the content still matches the current package release.\n- The docs now describe Python 3.10 through 3.13 as the tested range. Older blog posts and examples for Python 3.8 or 3.9 are stale for new environments.\n- `client.cfg` paths remain documented but deprecated. Prefer `luigi.cfg` or `luigi.toml` for new setups.\n\n## Official Sources\n\n- PyPI project page: https://pypi.org/project/luigi/\n- Repository: https://github.com/spotify/luigi\n- Docs root: https://luigi.readthedocs.io/\n- Tasks guide: https://luigi.readthedocs.io/en/latest/tasks.html\n- Running Luigi: https://luigi.readthedocs.io/en/stable/running_luigi.html\n- Central scheduler guide: https://luigi.readthedocs.io/en/stable/central_scheduler.html\n- Configuration guide: https://luigi.readthedocs.io/en/stable/configuration.html\n"
  },
  {
    "path": "content/lxml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"lxml Python package guide for XML and HTML parsing, XPath, XSLT, and schema validation\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"lxml,python,xml,html,xpath,xslt,elementtree\"\n---\n\n# lxml Python Package Guide\n\n## Golden Rule\n\nUse `lxml` when a Python project needs fast XML or HTML processing with XPath, XSLT, schema validation, or ElementTree-compatible APIs. Import the specific module you need, most commonly `from lxml import etree` for XML and `from lxml import html` for HTML.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"lxml==6.0.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"lxml==6.0.2\"\npoetry add \"lxml==6.0.2\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"lxml[cssselect]==6.0.2\"\npython -m pip install \"lxml[html5]==6.0.2\"\npython -m pip install \"lxml[htmlsoup]==6.0.2\"\npython -m pip install \"lxml[source]==6.0.2\"\n```\n\nSource-build notes:\n\n- Prebuilt wheels are usually the simplest path.\n- If pip falls back to a source build on Linux, install `libxml2`, `libxslt`, and Python development headers first.\n- If you want a static build of the bundled C libraries, the install docs use `STATIC_DEPS=true pip install lxml`.\n- The install docs note that if you also use the official `libxml2` Python bindings in the same process, a static build is the safest way to avoid interference between the two extension modules.\n\n## Core Modules\n\nUse the smallest surface that fits the task:\n\n- `lxml.etree`: XML parsing, tree construction, XPath, XSLT, Relax NG, XML Schema, and serialization.\n- `lxml.html`: HTML parsing helpers, document cleanup, form handling, and link rewriting.\n- `lxml.objectify`: object-like access to XML documents when you want attribute-style traversal.\n\n## Initialize And Parse XML\n\nFor most XML work, start with an explicit parser so the behavior is obvious in agent-authored code:\n\n```python\nfrom lxml import etree\n\nxml_bytes = b\"\"\"\n<feed xmlns=\"urn:example\">\n  <entry id=\"1\"><title>Hello</title></entry>\n  <entry id=\"2\"><title>World</title></entry>\n</feed>\n\"\"\"\n\nparser = etree.XMLParser(\n    ns_clean=True,\n    no_network=True,\n    recover=False,\n    remove_blank_text=True,\n    resolve_entities=False,\n)\n\nroot = etree.fromstring(xml_bytes, parser=parser)\nprint(root.tag)\n```\n\nUseful parser options from the API reference:\n\n- `no_network=True` is the default and blocks fetching related files over the network.\n- `huge_tree=False` is the default; turning it on disables parser security restrictions for very deep or very large inputs.\n- `decompress=False` is the current default.\n- `resolve_entities` is configurable; be explicit when handling untrusted XML.\n\nParse from a file or file-like object:\n\n```python\nfrom lxml import etree\n\ntree = etree.parse(\"document.xml\")\nroot = tree.getroot()\n```\n\n## XPath And Namespaces\n\nXPath is one of the main reasons to choose `lxml` over the stdlib XML stack.\n\n```python\nfrom lxml import etree\n\nroot = etree.fromstring(\n    b\"\"\"\n    <feed xmlns=\"urn:example\">\n      <entry id=\"1\"><title>Hello</title></entry>\n      <entry id=\"2\"><title>World</title></entry>\n    </feed>\n    \"\"\"\n)\n\nns = {\"x\": \"urn:example\"}\ntitles = root.xpath(\"//x:entry/x:title/text()\", namespaces=ns)\nprint(titles)\n```\n\nFor repeated queries, compile the XPath once:\n\n```python\nfrom lxml import etree\n\nfind_titles = etree.XPath(\"//x:entry/x:title/text()\", namespaces={\"x\": \"urn:example\"})\ntitles = find_titles(root)\n```\n\nDefault namespaces are a common pitfall. Map them to an explicit prefix in `namespaces=...`; XPath cannot use an empty prefix for a default namespace.\n\n## Build And Serialize XML\n\n```python\nfrom lxml import etree\n\nroot = etree.Element(\"items\")\nitem = etree.SubElement(root, \"item\", id=\"123\")\nitem.text = \"example\"\n\nxml_bytes = etree.tostring(\n    root,\n    pretty_print=True,\n    xml_declaration=True,\n    encoding=\"UTF-8\",\n)\n\nprint(xml_bytes.decode(\"utf-8\"))\n```\n\nIf you want a Python string instead of bytes, use `encoding=\"unicode\"`.\n\n## Parse HTML\n\nUse `lxml.html` for real-world HTML instead of strict XML parsing:\n\n```python\nfrom lxml import html\n\ndoc = html.fromstring(\n    \"\"\"\n    <html>\n      <body>\n        <a href=\"/a\">First</a>\n        <a href=\"/b\">Second</a>\n      </body>\n    </html>\n    \"\"\"\n)\n\nlinks = doc.xpath(\"//a/@href\")\nprint(links)\n```\n\nIf you want CSS selectors, install the `cssselect` extra and use:\n\n```python\nfrom lxml.cssselect import CSSSelector\n\nselect_links = CSSSelector(\"a[href]\")\nnodes = select_links(doc)\n```\n\n## Stream Large XML Files\n\nUse `iterparse()` for large documents so you do not keep the whole tree in memory:\n\n```python\nfrom lxml import etree\n\nfor event, elem in etree.iterparse(\"large.xml\", events=(\"end\",), tag=\"record\"):\n    record_id = elem.get(\"id\")\n    process_text = elem.findtext(\"title\")\n    print(record_id, process_text)\n\n    elem.clear()\n```\n\nIn long-running parses, clear processed elements promptly. Otherwise memory use grows even when you are iterating incrementally.\n\n## Validation And XSLT\n\nValidate against an XML Schema:\n\n```python\nfrom lxml import etree\n\nschema_doc = etree.parse(\"schema.xsd\")\nschema = etree.XMLSchema(schema_doc)\n\ndoc = etree.parse(\"document.xml\")\nschema.assertValid(doc)\n```\n\nRun an XSLT transform:\n\n```python\nfrom lxml import etree\n\nxml_doc = etree.parse(\"document.xml\")\nxslt_doc = etree.parse(\"transform.xsl\")\ntransform = etree.XSLT(xslt_doc)\n\nresult = transform(xml_doc)\nprint(str(result))\n```\n\n## Configuration Notes\n\n`lxml` does not have an auth model. The important setup variables are parser configuration and native-library packaging:\n\n- Prefer explicit parser construction when whitespace handling, entity resolution, recovery mode, or network behavior matters.\n- Keep XML parsing and HTML parsing separate. `lxml.html` is intentionally forgiving; `lxml.etree.XML()` and `etree.fromstring()` are not.\n- If your environment builds from source, pin the package version and make native build dependencies part of the image or CI setup instead of relying on ad hoc compiler availability.\n\n## Common Pitfalls\n\n- `etree.tostring()` returns bytes unless you request `encoding=\"unicode\"`.\n- Namespace-aware XPath fails silently if you forget the namespace map.\n- `recover=True` can help with malformed content, but it may also hide upstream data-quality problems. Use it intentionally.\n- `huge_tree=True` relaxes parser safety limits. Do not switch it on just to \"make the parse work\" without understanding the input size and trust boundary.\n- `iterparse()` is the right default for large XML feeds; naive `parse()` on multi-gigabyte files will consume too much memory.\n- HTML tag soup should go through `lxml.html` or an HTML parser, not the strict XML parser.\n- The install docs warn about mixing `lxml` with the official `libxml2` Python bindings in the same process unless `lxml` is built statically.\n\n## Version-Sensitive Notes For 6.0.x\n\n- PyPI lists `6.0.2` as the current package version, but the maintainer docs site and API reference pages are still branded `6.0.0`. Use PyPI and release notes to confirm patch-level behavior.\n- `6.0.x` requires Python `>=3.8`.\n- The `6.0.0` release notes document a default change for automatic gzip decompression: for libxml2 2.15+ builds, HTTP, FTP, and zlib support are no longer compiled in by default, so `decompress=False` is now the parser default.\n- The `6.0.2` release notes call out a fix for `decompress=True` parser behavior and a fix for compilation with libxml2 2.15.0. If your project depends on explicit decompression or source builds against system libraries, patch-level upgrades matter.\n\n## Official Sources\n\n- Main docs: `https://lxml.de/`\n- Installation: `https://lxml.de/installation.html`\n- Parsing guide: `https://lxml.de/parsing.html`\n- Tutorial: `https://lxml.de/tutorial.html`\n- API reference: `https://lxml.de/apidoc/`\n- Changelog: `https://github.com/lxml/lxml/releases`\n- PyPI: `https://pypi.org/project/lxml/`\n"
  },
  {
    "path": "content/mage-ai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Mage OSS Python package guide for building and running data pipelines with the mage CLI and project-based workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.79\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mage,mage-ai,python,data-pipelines,orchestration,etl,elt\"\n---\n\n# Mage OSS Python Package Guide\n\n## Golden Rule\n\nTreat `mage-ai` as an app and project framework first, not as a generic Python SDK. The stable workflow is: install the package, create or open a Mage project, run it with the `mage` CLI, and write decorated pipeline blocks inside that project. Avoid building new code against random internal `mage_ai.*` modules unless the official docs show that import path.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"mage-ai==0.9.79\"\n```\n\nMage supports optional extras for connectors and integrations. Install only what you need:\n\n```bash\npython -m pip install \"mage-ai[postgres,s3,dbt]==0.9.79\"\npython -m pip install \"mage-ai[bigquery]==0.9.79\"\n```\n\nThere is also an `all` extra, but it pulls in a very large dependency set and is usually the wrong default for lightweight local development:\n\n```bash\npython -m pip install \"mage-ai[all]==0.9.79\"\n```\n\nUpstream quickstart still recommends Docker for the easiest first run, especially on machines where native connector dependencies are painful. For Python-native projects, `pip install` is fine if you keep dependencies pinned.\n\n## Initialize And Start A Project\n\nThe explicit project-creation flow is the clearest:\n\n```bash\nmage init my_project --project-type standalone\nmage start my_project --host 0.0.0.0 --port 6789\n```\n\nThen open `http://localhost:6789`.\n\nImportant CLI behavior:\n\n- `mage start [project_path]` starts the web UI and scheduler for an existing project path.\n- `mage run <project_path> <pipeline_uuid>` runs a pipeline or block from the CLI.\n- `mage --help` and `mage <command> --help` are worth checking because the CLI surface is larger than the basic quickstart suggests.\n\nExample pipeline execution:\n\n```bash\nmage run my_project my_pipeline_uuid --runtime-vars '{\"env\": \"dev\"}' --test\n```\n\n`--runtime-vars` overwrites pipeline global variables for that run, which is the clean way to inject execution-time values from automation.\n\n## Core Usage\n\n### Write Python blocks with decorators\n\nThe common Mage workflow is to create blocks in the UI, then edit the generated Python code inside the project:\n\n```python\nfrom io import StringIO\n\nimport pandas as pd\nimport requests\n\nif 'data_loader' not in globals():\n    from mage_ai.data_preparation.decorators import data_loader\nif 'transformer' not in globals():\n    from mage_ai.data_preparation.decorators import transformer\nif 'test' not in globals():\n    from mage_ai.data_preparation.decorators import test\n\n@data_loader\ndef load_data(*args, **kwargs) -> pd.DataFrame:\n    response = requests.get(\"https://raw.githubusercontent.com/mage-ai/datasets/master/medical.csv\")\n    response.raise_for_status()\n    return pd.read_csv(StringIO(response.text))\n\n@transformer\ndef transform(df: pd.DataFrame, *args, **kwargs) -> pd.DataFrame:\n    return df.loc[:, [\"patient_id\", \"health_score\"]].head(100)\n\n@test\ndef test_output(df, *args) -> None:\n    assert df is not None\n    assert len(df.index) > 0\n```\n\nThe function decorated as `data_loader`, `transformer`, `data_exporter`, or similar is the executable entrypoint for the block. Tests run against the block output and can fail the block run.\n\n### Use `io_config.yaml` for data-system credentials\n\nMage expects `io_config.yaml` in the project root. Start with the standard format:\n\n```yaml\nversion: 0.1.1\ndefault:\n  POSTGRES_DBNAME: analytics\n  POSTGRES_USER: analytics_user\n  POSTGRES_PASSWORD: \"{{ env_var('POSTGRES_PASSWORD') }}\"\n  POSTGRES_HOST: db.internal\n  POSTGRES_PORT: 5432\n```\n\nTypical Python block pattern:\n\n```python\nfrom os import path\n\nfrom mage_ai.io.config import ConfigFileLoader\nfrom mage_ai.io.postgres import Postgres\nfrom mage_ai.settings.repo import get_repo_path\n\nif 'data_loader' not in globals():\n    from mage_ai.data_preparation.decorators import data_loader\n\n@data_loader\ndef load_data(**kwargs):\n    config_path = path.join(get_repo_path(), \"io_config.yaml\")\n    config_profile = kwargs.get(\"profile\", \"default\")\n\n    with Postgres.with_config(ConfigFileLoader(config_path, config_profile)) as loader:\n        return loader.load(\"SELECT * FROM events LIMIT 100\")\n```\n\nUse multiple profiles such as `development`, `staging`, and `production` rather than rewriting one shared `default` profile for every environment.\n\n### Trigger downstream pipelines from code\n\nMage includes orchestration helpers for pipeline chaining:\n\n```python\nfrom mage_ai.orchestration.triggers.api import trigger_pipeline\n\nif 'data_loader' not in globals():\n    from mage_ai.data_preparation.decorators import data_loader\n\n@data_loader\ndef trigger_downstream(*args, **kwargs):\n    trigger_pipeline(\n        \"downstream_pipeline\",\n        variables={\"env\": \"dev\"},\n        check_status=True,\n        error_on_failure=True,\n        poll_interval=30,\n    )\n```\n\nThis is useful when an agent needs to stitch together batch workflows without reimplementing scheduling logic outside Mage.\n\n## Configuration And Authentication\n\nMage has four main variable types:\n\n- Environment variables, referenced as `{{ env_var() }}`\n- Runtime variables, referenced through `kwargs` or `{{ variables() }}`\n- Block variables, accessed through `kwargs[\"configuration\"][key]`\n- Secrets, referenced as `{{ mage_secret_var() }}`\n\nFor `0.9.79`, user authentication is enabled by default.\n\nDefault owner behavior:\n\n- If no owner exists, Mage creates one automatically.\n- Default credentials are `admin@admin.com` / `admin`.\n- Supported customization env vars are `DEFAULT_OWNER_EMAIL`, `DEFAULT_OWNER_PASSWORD`, and `DEFAULT_OWNER_USERNAME`.\n\nChange those defaults immediately on any non-throwaway instance.\n\nUseful environment variables for real deployments:\n\n- `USER_CODE_PATH`: in Docker, point this to `/home/src/<project_name>` so Mage starts the intended project and installs its `requirements.txt`\n- `MAGE_DATABASE_CONNECTION_URL`: moves orchestration state off the default local SQLite database\n- `MAGE_PUBLIC_HOST`: sets the public URL used in notifications and external links\n- `MAGE_ACCESS_TOKEN_EXPIRY_TIME`: customizes access-token lifetime\n\nIf you automate against Mage APIs, assume authenticated endpoints need both the Mage API key and, when auth is enabled, a valid session token created through `/api/sessions`.\n\n## Common Pitfalls\n\n- Do not treat `mage-ai` as a stable general-purpose SDK. The supported surface is the CLI, project layout, documented decorators, and documented integration helpers.\n- `mage start my_project` and `mage run my_project ...` both depend on the correct project path. Agents often run commands from the wrong directory and then debug the wrong failure.\n- Keep `io_config.yaml` in the project root. Many connector examples assume `get_repo_path()` plus that filename.\n- Do not hard-code passwords in `io_config.yaml`. Use `env_var`, `mage_secret_var`, or an external secrets backend instead.\n- In Docker, missing `USER_CODE_PATH` causes confusing behavior: Mage starts, but the wrong project or missing `requirements.txt` install path breaks execution later.\n- The `all` extra is convenient but heavy. Prefer targeted extras to reduce dependency conflicts and startup time.\n- API auth changed in newer `0.9.x`; older blog posts that assume unauthenticated local access are often wrong for `0.9.79`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `0.9.79` published on January 21, 2026.\n- `mage-ai 0.9.79` still requires Python `>=3.9`.\n- Mage OSS versions `0.9.78` and above enable user authentication by default; versions `0.8.4` through `0.9.77` treated it as optional.\n- PyPI release history shows several older `0.9.x` yanked releases, including `0.9.55` and `0.9.56` for scheduler/trigger bugs. Avoid broad unreviewed `0.9.*` assumptions in automation.\n\n## Official Sources\n\n- Docs: https://docs.mage.ai/getting-started/setup\n- CLI reference: https://docs.mage.ai/development/cli-commands\n- Variables: https://docs.mage.ai/development/variables/overview\n- Environment variables: https://docs.mage.ai/development/variables/environment-variables\n- IO config: https://docs.mage.ai/development/io_config\n- IO config setup: https://docs.mage.ai/development/io_config_setup\n- Authentication: https://docs.mage.ai/production/authentication/overview\n- Repository: https://github.com/mage-ai/mage-ai\n- PyPI: https://pypi.org/project/mage-ai/\n"
  },
  {
    "path": "content/mailchimp/docs/marketing/DOC.md",
    "content": "---\nname: marketing\ndescription: \"Mailchimp Marketing API Node.js SDK Coding Guidelines for email marketing, audience management, and campaign management\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.80\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"mailchimp,marketing,email,campaigns,audience\"\n---\n\n# Mailchimp Marketing API Node.js SDK Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Mailchimp Marketing API coding expert. Help me with writing code using the official Mailchimp Marketing Node.js library for email marketing, audience management, campaign management, and e-commerce integrations. Please follow the following guidelines when generating code.\n\nYou can find the official documentation and code samples here: https://mailchimp.com/developer/marketing/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Mailchimp Marketing Node.js SDK, which is the standard library for all Mailchimp Marketing API interactions.\n\n- **Primary Package:** `@mailchimp/mailchimp_marketing`\n- **GitHub Repository:** https://github.com/mailchimp/mailchimp-marketing-node\n- **Current Version:** 3.0.80\n\n**Installation:**\n\n```bash\nnpm install @mailchimp/mailchimp_marketing\n```\n\n**APIs and Usage:**\n\n- **Correct:** `const mailchimp = require('@mailchimp/mailchimp_marketing')`\n- **Correct:** `mailchimp.setConfig({ apiKey: '...', server: '...' })`\n- **Correct:** `await mailchimp.lists.getAllLists()`\n- **Correct:** `await mailchimp.campaigns.create({ ... })`\n- **Incorrect:** Using legacy or unofficial packages like `mailchimp`, `mailchimp-api-v3`, or `node-mailchimp`\n\n## Prerequisites and Setup\n\nBefore using the Mailchimp Marketing Node.js library, ensure you have:\n\n- Node.js installed (version 12 or higher recommended)\n- A Mailchimp account with an API key\n- Your Mailchimp server prefix (e.g., `us19`, `us6`)\n\n## Finding Your Server Prefix\n\nThe server prefix is required for API authentication. To find it:\n\n1. Log into your Mailchimp account\n2. Look at the URL in your browser: `https://us19.admin.mailchimp.com/`\n3. The `us19` part is your server prefix\n\nAlternatively, your API key ends with the server prefix: if your key is `abc123-us6`, then `us6` is your server prefix.\n\n## API Key Configuration\n\n**Never hardcode your API key.** Always use environment variables:\n\n```bash\n# .env file\nMAILCHIMP_API_KEY=your_api_key_here\nMAILCHIMP_SERVER_PREFIX=us19\n```\n\n```javascript\nrequire('dotenv').config();\n\nconst mailchimp = require('@mailchimp/mailchimp_marketing');\n\nmailchimp.setConfig({\n  apiKey: process.env.MAILCHIMP_API_KEY,\n  server: process.env.MAILCHIMP_SERVER_PREFIX,\n});\n```\n\n## Initialization\n\n### Basic Authentication (API Key)\n\n```javascript\nconst mailchimp = require('@mailchimp/mailchimp_marketing');\n\nmailchimp.setConfig({\n  apiKey: process.env.MAILCHIMP_API_KEY,\n  server: process.env.MAILCHIMP_SERVER_PREFIX,\n});\n\n// Test connection\nasync function testConnection() {\n  try {\n    const response = await mailchimp.ping.get();\n    console.log('Connected to Mailchimp:', response);\n  } catch (error) {\n    console.error('Connection failed:', error);\n  }\n}\n```\n\n### OAuth2 Authentication\n\nFor applications that access Mailchimp on behalf of other users:\n\n```javascript\nconst mailchimp = require('@mailchimp/mailchimp_marketing');\n\nmailchimp.setConfig({\n  accessToken: process.env.MAILCHIMP_ACCESS_TOKEN,\n  server: process.env.MAILCHIMP_SERVER_PREFIX,\n});\n```\n\n## Audiences (Lists) Management\n\n### Get All Lists\n\n```javascript\nasync function getAllLists() {\n  try {\n    const response = await mailchimp.lists.getAllLists();\n    console.log('Total lists:', response.total_items);\n\n    response.lists.forEach(list => {\n      console.log(`List: ${list.name} (ID: ${list.id})`);\n      console.log(`Members: ${list.stats.member_count}`);\n    });\n\n    return response.lists;\n  } catch (error) {\n    console.error('Error fetching lists:', error);\n  }\n}\n```\n\n### Get Specific List Information\n\n```javascript\nasync function getListInfo(listId) {\n  try {\n    const response = await mailchimp.lists.getList(listId);\n    console.log('List Name:', response.name);\n    console.log('Total Members:', response.stats.member_count);\n    console.log('Unsubscribe Count:', response.stats.unsubscribe_count);\n    console.log('Open Rate:', response.stats.open_rate);\n    console.log('Click Rate:', response.stats.click_rate);\n    return response;\n  } catch (error) {\n    console.error('Error fetching list info:', error);\n  }\n}\n```\n\n### Create a New List\n\n```javascript\nasync function createList() {\n  try {\n    const response = await mailchimp.lists.createList({\n      name: 'My New Newsletter',\n      contact: {\n        company: 'My Company',\n        address1: '123 Main St',\n        city: 'New York',\n        state: 'NY',\n        zip: '10001',\n        country: 'US',\n      },\n      permission_reminder: 'You signed up for updates on our website.',\n      campaign_defaults: {\n        from_name: 'My Company',\n        from_email: 'hello@mycompany.com',\n        subject: 'Newsletter',\n        language: 'en',\n      },\n      email_type_option: true,\n    });\n\n    console.log('List created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error creating list:', error);\n  }\n}\n```\n\n## List Members Management\n\n### Add a Member to a List\n\n```javascript\nasync function addMemberToList(listId, email, firstName, lastName) {\n  try {\n    const response = await mailchimp.lists.addListMember(listId, {\n      email_address: email,\n      status: 'subscribed',\n      merge_fields: {\n        FNAME: firstName,\n        LNAME: lastName,\n      },\n    });\n\n    console.log(`Added ${email} to list`);\n    return response;\n  } catch (error) {\n    console.error('Error adding member:', error);\n    if (error.status === 400) {\n      console.error('Member might already exist or email is invalid');\n    }\n  }\n}\n```\n\n### Add or Update a Member\n\nUse this to avoid errors when a member already exists:\n\n```javascript\nconst crypto = require('crypto');\n\nasync function addOrUpdateMember(listId, email, firstName, lastName, tags = []) {\n  try {\n    // Create MD5 hash of lowercase email for subscriber_hash\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.lists.setListMember(\n      listId,\n      subscriberHash,\n      {\n        email_address: email,\n        status_if_new: 'subscribed',\n        merge_fields: {\n          FNAME: firstName,\n          LNAME: lastName,\n        },\n        tags: tags,\n      }\n    );\n\n    console.log(`Added/Updated ${email}`);\n    return response;\n  } catch (error) {\n    console.error('Error adding/updating member:', error);\n  }\n}\n```\n\n### Get List Members\n\n```javascript\nasync function getListMembers(listId, count = 100) {\n  try {\n    const response = await mailchimp.lists.getListMembersInfo(listId, {\n      count: count,\n      offset: 0,\n    });\n\n    console.log(`Total members: ${response.total_items}`);\n\n    response.members.forEach(member => {\n      console.log(`${member.email_address} - ${member.status}`);\n    });\n\n    return response.members;\n  } catch (error) {\n    console.error('Error fetching members:', error);\n  }\n}\n```\n\n### Get Specific Member Information\n\n```javascript\nconst crypto = require('crypto');\n\nasync function getMemberInfo(listId, email) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.lists.getListMember(\n      listId,\n      subscriberHash\n    );\n\n    console.log('Member:', response.email_address);\n    console.log('Status:', response.status);\n    console.log('Member since:', response.timestamp_opt);\n    console.log('Tags:', response.tags);\n\n    return response;\n  } catch (error) {\n    console.error('Error fetching member:', error);\n  }\n}\n```\n\n### Update Member Information\n\n```javascript\nconst crypto = require('crypto');\n\nasync function updateMember(listId, email, updates) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.lists.updateListMember(\n      listId,\n      subscriberHash,\n      updates\n    );\n\n    console.log('Member updated:', response.email_address);\n    return response;\n  } catch (error) {\n    console.error('Error updating member:', error);\n  }\n}\n\n// Example usage\nupdateMember('list123', 'user@example.com', {\n  merge_fields: {\n    FNAME: 'Jane',\n    LNAME: 'Smith',\n  },\n  status: 'subscribed',\n});\n```\n\n### Delete a Member\n\n```javascript\nconst crypto = require('crypto');\n\nasync function deleteMember(listId, email) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    await mailchimp.lists.deleteListMember(listId, subscriberHash);\n    console.log(`Deleted ${email} from list`);\n  } catch (error) {\n    console.error('Error deleting member:', error);\n  }\n}\n```\n\n### Batch Subscribe or Unsubscribe\n\n```javascript\nasync function batchSubscribe(listId, members) {\n  try {\n    const response = await mailchimp.lists.batchListMembers(listId, {\n      members: members.map(member => ({\n        email_address: member.email,\n        status: 'subscribed',\n        merge_fields: {\n          FNAME: member.firstName,\n          LNAME: member.lastName,\n        },\n      })),\n      update_existing: true,\n    });\n\n    console.log('New members:', response.new_members.length);\n    console.log('Updated members:', response.updated_members.length);\n    console.log('Errors:', response.errors.length);\n\n    return response;\n  } catch (error) {\n    console.error('Error batch subscribing:', error);\n  }\n}\n\n// Example usage\nbatchSubscribe('list123', [\n  { email: 'user1@example.com', firstName: 'John', lastName: 'Doe' },\n  { email: 'user2@example.com', firstName: 'Jane', lastName: 'Smith' },\n]);\n```\n\n## Tags Management\n\n### Add Tags to a Member\n\n```javascript\nconst crypto = require('crypto');\n\nasync function addTagsToMember(listId, email, tags) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.lists.updateListMemberTags(\n      listId,\n      subscriberHash,\n      {\n        tags: tags.map(tag => ({ name: tag, status: 'active' })),\n      }\n    );\n\n    console.log(`Added tags to ${email}`);\n    return response;\n  } catch (error) {\n    console.error('Error adding tags:', error);\n  }\n}\n\n// Example usage\naddTagsToMember('list123', 'user@example.com', ['VIP', 'Newsletter']);\n```\n\n### Remove Tags from a Member\n\n```javascript\nconst crypto = require('crypto');\n\nasync function removeTagsFromMember(listId, email, tags) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.lists.updateListMemberTags(\n      listId,\n      subscriberHash,\n      {\n        tags: tags.map(tag => ({ name: tag, status: 'inactive' })),\n      }\n    );\n\n    console.log(`Removed tags from ${email}`);\n    return response;\n  } catch (error) {\n    console.error('Error removing tags:', error);\n  }\n}\n```\n\n## Segments Management\n\n### Get All Segments for a List\n\n```javascript\nasync function getSegments(listId) {\n  try {\n    const response = await mailchimp.lists.listSegments(listId);\n\n    console.log('Total segments:', response.total_items);\n\n    response.segments.forEach(segment => {\n      console.log(`Segment: ${segment.name} (ID: ${segment.id})`);\n      console.log(`Type: ${segment.type}, Members: ${segment.member_count}`);\n    });\n\n    return response.segments;\n  } catch (error) {\n    console.error('Error fetching segments:', error);\n  }\n}\n```\n\n### Create a Segment\n\n```javascript\nasync function createSegment(listId, segmentName, conditions) {\n  try {\n    const response = await mailchimp.lists.createSegment(listId, {\n      name: segmentName,\n      static_segment: [],\n    });\n\n    console.log('Segment created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error creating segment:', error);\n  }\n}\n```\n\n### Add Members to a Segment\n\n```javascript\nasync function addMembersToSegment(listId, segmentId, emails) {\n  try {\n    const response = await mailchimp.lists.batchSegmentMembers(\n      listId,\n      segmentId,\n      {\n        members_to_add: emails,\n      }\n    );\n\n    console.log('Members added to segment:', response.members_added.length);\n    return response;\n  } catch (error) {\n    console.error('Error adding members to segment:', error);\n  }\n}\n```\n\n## Campaigns Management\n\n### Get All Campaigns\n\n```javascript\nasync function getAllCampaigns(count = 100) {\n  try {\n    const response = await mailchimp.campaigns.list({\n      count: count,\n      sort_field: 'create_time',\n      sort_dir: 'DESC',\n    });\n\n    console.log('Total campaigns:', response.total_items);\n\n    response.campaigns.forEach(campaign => {\n      console.log(`Campaign: ${campaign.settings.title}`);\n      console.log(`Status: ${campaign.status}, Type: ${campaign.type}`);\n    });\n\n    return response.campaigns;\n  } catch (error) {\n    console.error('Error fetching campaigns:', error);\n  }\n}\n```\n\n### Create a Campaign\n\n```javascript\nasync function createCampaign(listId, subject, fromName, replyTo) {\n  try {\n    const response = await mailchimp.campaigns.create({\n      type: 'regular',\n      recipients: {\n        list_id: listId,\n      },\n      settings: {\n        subject_line: subject,\n        title: subject,\n        from_name: fromName,\n        reply_to: replyTo,\n      },\n    });\n\n    console.log('Campaign created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error creating campaign:', error);\n  }\n}\n```\n\n### Set Campaign Content\n\n```javascript\nasync function setCampaignContent(campaignId, htmlContent) {\n  try {\n    const response = await mailchimp.campaigns.setContent(campaignId, {\n      html: htmlContent,\n    });\n\n    console.log('Campaign content set');\n    return response;\n  } catch (error) {\n    console.error('Error setting campaign content:', error);\n  }\n}\n```\n\n### Send a Campaign\n\n```javascript\nasync function sendCampaign(campaignId) {\n  try {\n    const response = await mailchimp.campaigns.send(campaignId);\n    console.log('Campaign sent successfully');\n    return response;\n  } catch (error) {\n    console.error('Error sending campaign:', error);\n  }\n}\n```\n\n### Complete Campaign Workflow\n\n```javascript\nasync function createAndSendCampaign(listId, subject, htmlContent) {\n  try {\n    // 1. Create campaign\n    const campaign = await mailchimp.campaigns.create({\n      type: 'regular',\n      recipients: {\n        list_id: listId,\n      },\n      settings: {\n        subject_line: subject,\n        title: subject,\n        from_name: 'My Company',\n        reply_to: 'hello@mycompany.com',\n      },\n    });\n\n    console.log('Campaign created:', campaign.id);\n\n    // 2. Set content\n    await mailchimp.campaigns.setContent(campaign.id, {\n      html: htmlContent,\n    });\n\n    console.log('Campaign content set');\n\n    // 3. Send campaign\n    await mailchimp.campaigns.send(campaign.id);\n\n    console.log('Campaign sent successfully');\n\n    return campaign;\n  } catch (error) {\n    console.error('Error in campaign workflow:', error);\n  }\n}\n```\n\n### Schedule a Campaign\n\n```javascript\nasync function scheduleCampaign(campaignId, scheduleTime) {\n  try {\n    const response = await mailchimp.campaigns.schedule(campaignId, {\n      schedule_time: scheduleTime, // ISO 8601 format: \"2024-12-31T10:00:00Z\"\n    });\n\n    console.log('Campaign scheduled for:', scheduleTime);\n    return response;\n  } catch (error) {\n    console.error('Error scheduling campaign:', error);\n  }\n}\n```\n\n### Update Campaign Settings\n\n```javascript\nasync function updateCampaign(campaignId, updates) {\n  try {\n    const response = await mailchimp.campaigns.update(campaignId, updates);\n    console.log('Campaign updated');\n    return response;\n  } catch (error) {\n    console.error('Error updating campaign:', error);\n  }\n}\n\n// Example usage\nupdateCampaign('campaign123', {\n  settings: {\n    subject_line: 'Updated Subject Line',\n    preview_text: 'Check out our latest updates!',\n  },\n});\n```\n\n### Delete a Campaign\n\n```javascript\nasync function deleteCampaign(campaignId) {\n  try {\n    await mailchimp.campaigns.remove(campaignId);\n    console.log('Campaign deleted');\n  } catch (error) {\n    console.error('Error deleting campaign:', error);\n  }\n}\n```\n\n## Templates Management\n\n### Get All Templates\n\n```javascript\nasync function getAllTemplates() {\n  try {\n    const response = await mailchimp.templates.list({\n      count: 100,\n    });\n\n    console.log('Total templates:', response.total_items);\n\n    response.templates.forEach(template => {\n      console.log(`Template: ${template.name} (ID: ${template.id})`);\n      console.log(`Type: ${template.type}, Category: ${template.category}`);\n    });\n\n    return response.templates;\n  } catch (error) {\n    console.error('Error fetching templates:', error);\n  }\n}\n```\n\n### Get Specific Template\n\n```javascript\nasync function getTemplate(templateId) {\n  try {\n    const response = await mailchimp.templates.getTemplate(templateId);\n    console.log('Template:', response.name);\n    console.log('HTML:', response.html);\n    return response;\n  } catch (error) {\n    console.error('Error fetching template:', error);\n  }\n}\n```\n\n### Create a Template\n\n```javascript\nasync function createTemplate(name, htmlContent) {\n  try {\n    const response = await mailchimp.templates.create({\n      name: name,\n      html: htmlContent,\n    });\n\n    console.log('Template created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error creating template:', error);\n  }\n}\n```\n\n### Use Template in Campaign\n\n```javascript\nasync function createCampaignFromTemplate(listId, templateId, subject) {\n  try {\n    const campaign = await mailchimp.campaigns.create({\n      type: 'regular',\n      recipients: {\n        list_id: listId,\n      },\n      settings: {\n        subject_line: subject,\n        title: subject,\n        from_name: 'My Company',\n        reply_to: 'hello@mycompany.com',\n        template_id: templateId,\n      },\n    });\n\n    console.log('Campaign created from template:', campaign.id);\n    return campaign;\n  } catch (error) {\n    console.error('Error creating campaign from template:', error);\n  }\n}\n```\n\n## Automation Workflows\n\n### Get All Automations\n\n```javascript\nasync function getAllAutomations() {\n  try {\n    const response = await mailchimp.automations.list({\n      count: 100,\n    });\n\n    console.log('Total automations:', response.total_items);\n\n    response.automations.forEach(automation => {\n      console.log(`Automation: ${automation.settings.title}`);\n      console.log(`Status: ${automation.status}, Recipients: ${automation.recipients.list_id}`);\n    });\n\n    return response.automations;\n  } catch (error) {\n    console.error('Error fetching automations:', error);\n  }\n}\n```\n\n### Get Specific Automation\n\n```javascript\nasync function getAutomation(workflowId) {\n  try {\n    const response = await mailchimp.automations.get(workflowId);\n    console.log('Automation:', response.settings.title);\n    console.log('Status:', response.status);\n    console.log('Emails:', response.emails.length);\n    return response;\n  } catch (error) {\n    console.error('Error fetching automation:', error);\n  }\n}\n```\n\n### Pause an Automation\n\n```javascript\nasync function pauseAutomation(workflowId) {\n  try {\n    await mailchimp.automations.pause(workflowId);\n    console.log('Automation paused');\n  } catch (error) {\n    console.error('Error pausing automation:', error);\n  }\n}\n```\n\n### Start an Automation\n\n```javascript\nasync function startAutomation(workflowId) {\n  try {\n    await mailchimp.automations.start(workflowId);\n    console.log('Automation started');\n  } catch (error) {\n    console.error('Error starting automation:', error);\n  }\n}\n```\n\n### Add Subscriber to Automation Email Queue\n\n```javascript\nasync function addSubscriberToAutomation(workflowId, workflowEmailId, email) {\n  try {\n    const response = await mailchimp.automations.addWorkflowEmailSubscriber(\n      workflowId,\n      workflowEmailId,\n      {\n        email_address: email,\n      }\n    );\n\n    console.log(`Added ${email} to automation queue`);\n    return response;\n  } catch (error) {\n    console.error('Error adding subscriber to automation:', error);\n  }\n}\n```\n\n## Reports and Analytics\n\n### Get Campaign Reports\n\n```javascript\nasync function getCampaignReport(campaignId) {\n  try {\n    const response = await mailchimp.reports.getCampaignReport(campaignId);\n\n    console.log('Campaign:', response.campaign_title);\n    console.log('Emails sent:', response.emails_sent);\n    console.log('Opens:', response.opens.opens_total);\n    console.log('Unique opens:', response.opens.unique_opens);\n    console.log('Open rate:', response.opens.open_rate);\n    console.log('Clicks:', response.clicks.clicks_total);\n    console.log('Unique clicks:', response.clicks.unique_clicks);\n    console.log('Click rate:', response.clicks.click_rate);\n    console.log('Unsubscribes:', response.unsubscribed);\n\n    return response;\n  } catch (error) {\n    console.error('Error fetching campaign report:', error);\n  }\n}\n```\n\n### Get All Campaign Reports\n\n```javascript\nasync function getAllCampaignReports(count = 100) {\n  try {\n    const response = await mailchimp.reports.getAllCampaignReports({\n      count: count,\n    });\n\n    console.log('Total reports:', response.total_items);\n\n    response.reports.forEach(report => {\n      console.log(`Campaign: ${report.campaign_title}`);\n      console.log(`Open rate: ${report.opens.open_rate}%`);\n      console.log(`Click rate: ${report.clicks.click_rate}%`);\n    });\n\n    return response.reports;\n  } catch (error) {\n    console.error('Error fetching reports:', error);\n  }\n}\n```\n\n### Get Email Activity for a Member\n\n```javascript\nconst crypto = require('crypto');\n\nasync function getEmailActivity(campaignId, email) {\n  try {\n    const subscriberHash = crypto\n      .createHash('md5')\n      .update(email.toLowerCase())\n      .digest('hex');\n\n    const response = await mailchimp.reports.getEmailActivityForSubscriber(\n      campaignId,\n      subscriberHash\n    );\n\n    console.log(`Email activity for ${email}:`);\n    response.activity.forEach(activity => {\n      console.log(`${activity.action} at ${activity.timestamp}`);\n    });\n\n    return response;\n  } catch (error) {\n    console.error('Error fetching email activity:', error);\n  }\n}\n```\n\n### Get List Growth History\n\n```javascript\nasync function getListGrowthHistory(listId) {\n  try {\n    const response = await mailchimp.lists.getListGrowthHistory(listId, {\n      count: 100,\n    });\n\n    console.log('Growth history for list:');\n    response.history.forEach(history => {\n      console.log(`Month: ${history.month}`);\n      console.log(`Subscribed: ${history.subscribed}, Unsubscribed: ${history.unsubscribed}`);\n      console.log(`Existing: ${history.existing}`);\n    });\n\n    return response.history;\n  } catch (error) {\n    console.error('Error fetching growth history:', error);\n  }\n}\n```\n\n## E-commerce Integration\n\n### Add a Store\n\n```javascript\nasync function addStore(listId, storeId, storeName, currencyCode) {\n  try {\n    const response = await mailchimp.ecommerce.addStore({\n      id: storeId,\n      list_id: listId,\n      name: storeName,\n      currency_code: currencyCode,\n    });\n\n    console.log('Store created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error adding store:', error);\n  }\n}\n```\n\n### Get All Stores\n\n```javascript\nasync function getAllStores() {\n  try {\n    const response = await mailchimp.ecommerce.getStores();\n\n    console.log('Total stores:', response.total_items);\n\n    response.stores.forEach(store => {\n      console.log(`Store: ${store.name} (ID: ${store.id})`);\n      console.log(`Currency: ${store.currency_code}`);\n    });\n\n    return response.stores;\n  } catch (error) {\n    console.error('Error fetching stores:', error);\n  }\n}\n```\n\n### Add a Customer\n\n```javascript\nasync function addCustomer(storeId, customerId, email, firstName, lastName) {\n  try {\n    const response = await mailchimp.ecommerce.addStoreCustomer(storeId, {\n      id: customerId,\n      email_address: email,\n      opt_in_status: true,\n      first_name: firstName,\n      last_name: lastName,\n    });\n\n    console.log('Customer added:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error adding customer:', error);\n  }\n}\n```\n\n### Add a Product\n\n```javascript\nasync function addProduct(storeId, productId, title, price) {\n  try {\n    const response = await mailchimp.ecommerce.addStoreProduct(storeId, {\n      id: productId,\n      title: title,\n      variants: [\n        {\n          id: `${productId}-variant-1`,\n          title: 'Default Variant',\n          price: price,\n        },\n      ],\n    });\n\n    console.log('Product added:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error adding product:', error);\n  }\n}\n```\n\n### Add an Order\n\n```javascript\nasync function addOrder(storeId, orderId, customerId, lineItems, total) {\n  try {\n    const response = await mailchimp.ecommerce.addStoreOrder(storeId, {\n      id: orderId,\n      customer: {\n        id: customerId,\n      },\n      lines: lineItems.map(item => ({\n        id: item.id,\n        product_id: item.productId,\n        product_variant_id: item.variantId,\n        quantity: item.quantity,\n        price: item.price,\n      })),\n      currency_code: 'USD',\n      order_total: total,\n      processed_at_foreign: new Date().toISOString(),\n    });\n\n    console.log('Order added:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error adding order:', error);\n  }\n}\n\n// Example usage\naddOrder('store123', 'order456', 'customer789', [\n  {\n    id: 'line1',\n    productId: 'prod1',\n    variantId: 'prod1-variant-1',\n    quantity: 2,\n    price: 29.99,\n  },\n], 59.98);\n```\n\n### Add a Cart\n\n```javascript\nasync function addCart(storeId, cartId, customerId, lineItems) {\n  try {\n    const response = await mailchimp.ecommerce.addStoreCart(storeId, {\n      id: cartId,\n      customer: {\n        id: customerId,\n      },\n      lines: lineItems.map(item => ({\n        id: item.id,\n        product_id: item.productId,\n        product_variant_id: item.variantId,\n        quantity: item.quantity,\n        price: item.price,\n      })),\n      currency_code: 'USD',\n    });\n\n    console.log('Cart added:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error adding cart:', error);\n  }\n}\n```\n\n## Error Handling\n\n### Comprehensive Error Handling\n\n```javascript\nasync function handleMailchimpRequest() {\n  try {\n    const response = await mailchimp.lists.getAllLists();\n    return response;\n  } catch (error) {\n    console.error('Mailchimp API Error:', error);\n\n    if (error.status) {\n      console.error('Status Code:', error.status);\n      console.error('Error Message:', error.response?.body?.title);\n      console.error('Error Detail:', error.response?.body?.detail);\n\n      switch (error.status) {\n        case 401:\n          console.error('Authentication failed. Check your API key.');\n          break;\n        case 403:\n          console.error('Forbidden. Check your permissions.');\n          break;\n        case 404:\n          console.error('Resource not found.');\n          break;\n        case 400:\n          console.error('Bad request. Check your parameters.');\n          if (error.response?.body?.errors) {\n            console.error('Validation errors:', error.response.body.errors);\n          }\n          break;\n        case 429:\n          console.error('Rate limit exceeded. Wait before retrying.');\n          break;\n        case 500:\n          console.error('Mailchimp server error. Try again later.');\n          break;\n        default:\n          console.error('Unexpected error occurred.');\n      }\n    }\n\n    throw error;\n  }\n}\n```\n\n### Retry Logic for Rate Limiting\n\n```javascript\nasync function retryRequest(requestFn, maxRetries = 3, delay = 1000) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await requestFn();\n    } catch (error) {\n      if (error.status === 429 && i < maxRetries - 1) {\n        console.log(`Rate limited. Retrying in ${delay}ms...`);\n        await new Promise(resolve => setTimeout(resolve, delay));\n        delay *= 2; // Exponential backoff\n      } else {\n        throw error;\n      }\n    }\n  }\n}\n\n// Example usage\nconst result = await retryRequest(() => mailchimp.lists.getAllLists());\n```\n\n## Pagination\n\n### Paginate Through Large Result Sets\n\n```javascript\nasync function getAllListMembersPaginated(listId) {\n  let offset = 0;\n  const count = 100;\n  const allMembers = [];\n\n  while (true) {\n    try {\n      const response = await mailchimp.lists.getListMembersInfo(listId, {\n        count: count,\n        offset: offset,\n      });\n\n      allMembers.push(...response.members);\n\n      console.log(`Fetched ${offset + response.members.length} of ${response.total_items} members`);\n\n      if (response.members.length < count) {\n        break; // No more results\n      }\n\n      offset += count;\n    } catch (error) {\n      console.error('Error during pagination:', error);\n      break;\n    }\n  }\n\n  return allMembers;\n}\n```\n\n## TypeScript Support\n\nThe SDK includes TypeScript definitions:\n\n```typescript\nimport mailchimp from '@mailchimp/mailchimp_marketing';\n\nmailchimp.setConfig({\n  apiKey: process.env.MAILCHIMP_API_KEY as string,\n  server: process.env.MAILCHIMP_SERVER_PREFIX as string,\n});\n\ninterface ListMember {\n  email_address: string;\n  status: 'subscribed' | 'unsubscribed' | 'cleaned' | 'pending';\n  merge_fields: {\n    FNAME: string;\n    LNAME: string;\n  };\n}\n\nasync function addTypedMember(listId: string, member: ListMember) {\n  const response = await mailchimp.lists.addListMember(listId, member);\n  return response;\n}\n```\n\n## Common Patterns\n\n### Bulk Import Subscribers from CSV\n\n```javascript\nconst fs = require('fs');\nconst csv = require('csv-parser');\n\nasync function importFromCSV(listId, csvFilePath) {\n  const members = [];\n\n  return new Promise((resolve, reject) => {\n    fs.createReadStream(csvFilePath)\n      .pipe(csv())\n      .on('data', (row) => {\n        members.push({\n          email_address: row.email,\n          status: 'subscribed',\n          merge_fields: {\n            FNAME: row.first_name,\n            LNAME: row.last_name,\n          },\n        });\n      })\n      .on('end', async () => {\n        try {\n          // Batch in groups of 500 (Mailchimp limit)\n          const batchSize = 500;\n          for (let i = 0; i < members.length; i += batchSize) {\n            const batch = members.slice(i, i + batchSize);\n\n            const response = await mailchimp.lists.batchListMembers(listId, {\n              members: batch,\n              update_existing: true,\n            });\n\n            console.log(`Batch ${i / batchSize + 1}: ${response.new_members.length} added, ${response.updated_members.length} updated`);\n          }\n\n          resolve();\n        } catch (error) {\n          reject(error);\n        }\n      });\n  });\n}\n```\n\n### Send Welcome Email via Automation\n\n```javascript\nasync function setupWelcomeAutomation(listId) {\n  try {\n    // Create a basic automation trigger when someone subscribes\n    const automation = await mailchimp.automations.create({\n      recipients: {\n        list_id: listId,\n      },\n      trigger_settings: {\n        workflow_type: 'welcomeSeries',\n      },\n      settings: {\n        title: 'Welcome Email Series',\n        from_name: 'My Company',\n        reply_to: 'hello@mycompany.com',\n      },\n    });\n\n    console.log('Welcome automation created:', automation.id);\n    return automation;\n  } catch (error) {\n    console.error('Error setting up welcome automation:', error);\n  }\n}\n```\n\n### Segment Users by Engagement\n\n```javascript\nasync function createEngagementSegment(listId, segmentName) {\n  try {\n    const response = await mailchimp.lists.createSegment(listId, {\n      name: segmentName,\n      options: {\n        match: 'all',\n        conditions: [\n          {\n            condition_type: 'EmailClient',\n            field: 'email_client',\n            op: 'is',\n            value: 'Gmail',\n          },\n        ],\n      },\n    });\n\n    console.log('Engagement segment created:', response.id);\n    return response;\n  } catch (error) {\n    console.error('Error creating segment:', error);\n  }\n}\n```\n\n## Webhooks\n\n### Process Webhook Events\n\n```javascript\nconst express = require('express');\nconst crypto = require('crypto');\n\nconst app = express();\napp.use(express.json());\n\n// Verify webhook signature\nfunction verifyWebhook(secret, body, signature) {\n  const hash = crypto\n    .createHmac('sha1', secret)\n    .update(JSON.stringify(body))\n    .digest('hex');\n\n  return hash === signature;\n}\n\napp.post('/mailchimp-webhook', (req, res) => {\n  const signature = req.headers['x-mailchimp-signature'];\n  const webhookSecret = process.env.MAILCHIMP_WEBHOOK_SECRET;\n\n  if (!verifyWebhook(webhookSecret, req.body, signature)) {\n    return res.status(401).send('Invalid signature');\n  }\n\n  const { type, data } = req.body;\n\n  switch (type) {\n    case 'subscribe':\n      console.log('New subscriber:', data.email);\n      break;\n    case 'unsubscribe':\n      console.log('Unsubscribed:', data.email);\n      break;\n    case 'profile':\n      console.log('Profile updated:', data.email);\n      break;\n    case 'campaign':\n      console.log('Campaign event:', data);\n      break;\n    default:\n      console.log('Unknown webhook type:', type);\n  }\n\n  res.status(200).send('OK');\n});\n\napp.listen(3000, () => console.log('Webhook server running on port 3000'));\n```\n\n## Notes\n\nThe Mailchimp Marketing Node.js SDK is auto-generated from the OpenAPI specification and provides comprehensive access to all Mailchimp Marketing API endpoints. Always use environment variables for API keys and server prefixes. The library supports both Basic Auth (API key) and OAuth2 authentication methods. Rate limits apply: 10 simultaneous connections per account and throttling based on your plan. Use batch operations when adding multiple members to optimize API usage.\n"
  },
  {
    "path": "content/mako/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Mako template library for Python projects using Template and TemplateLookup for file-based templating, inheritance, and escaping\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.10\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mako,python,templates,templating,html,web\"\n---\n\n# Mako Python Package Guide\n\n## Golden Rule\n\nUse `Mako` when the project already depends on Mako or you need Python-powered templating with inheritance and defs. Import `Template` or `TemplateLookup` from `mako`, keep template source trusted, and enable explicit escaping instead of assuming HTML autoescape is on by default.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"Mako==1.3.10\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Mako==1.3.10\"\npoetry add \"Mako==1.3.10\"\n```\n\nIf you only need the runtime, no extra initialization step is required after installation.\n\n## Core Usage\n\n### Render a string template\n\nUse `Template` for inline or one-off templates:\n\n```python\nfrom mako.template import Template\n\ntemplate = Template(\"Hello ${name}!\")\nresult = template.render(name=\"Ada\")\n\nprint(result)\n```\n\nBy default, `render()` returns a Python string unless you configure `output_encoding`. If you set an output encoding, `render()` returns `bytes`; use `render_unicode()` when you want text output consistently.\n\n### Load templates from files\n\nUse `TemplateLookup` for any real application with multiple template files, includes, or inheritance:\n\n```python\nfrom mako.lookup import TemplateLookup\n\nlookup = TemplateLookup(\n    directories=[\"templates\"],\n    module_directory=\".mako_modules\",\n    filesystem_checks=True,\n    strict_undefined=True,\n)\n\ntemplate = lookup.get_template(\"users/detail.html\")\nhtml = template.render(user={\"name\": \"Ada\"})\n```\n\nKey options:\n\n- `directories`: search roots for template URIs\n- `module_directory`: compiled Python module cache; use a writable location\n- `filesystem_checks`: `True` for development reloads, often `False` in production for less stat overhead\n- `strict_undefined`: raise immediately for missing variables instead of letting `UNDEFINED` fail later during stringification\n\n### Use Mako syntax correctly\n\nCommon syntax you will need:\n\n```mako\n<%page expression_filter=\"h\"/>\n\n% if user:\n  <h1>${user[\"name\"]}</h1>\n% else:\n  <h1>Anonymous</h1>\n% endif\n\n<%def name=\"badge(label)\">\n  <span class=\"badge\">${label}</span>\n</%def>\n\n${badge(\"admin\")}\n```\n\nImportant constructs:\n\n- `${expr}`: evaluate and emit an expression\n- `% ...`: control lines such as `if`, `for`, and `while`\n- `<% ... %>`: embedded Python block\n- `<%def>`: reusable template function\n- `<%block>` and `<%inherit file=\"...\">`: layout composition and template inheritance\n\n### Template inheritance\n\nUse inheritance for layouts and `<%block>` for replaceable sections:\n\n```mako\n## base.html\n<html>\n  <body>\n    <%block name=\"body\"/>\n  </body>\n</html>\n```\n\n```mako\n## child.html\n<%inherit file=\"base.html\"/>\n\n<%block name=\"body\">\n  Hello ${name}\n</%block>\n```\n\n```python\nfrom mako.lookup import TemplateLookup\n\nlookup = TemplateLookup(directories=[\"templates\"])\nhtml = lookup.get_template(\"child.html\").render(name=\"Ada\")\n```\n\n## Escaping And Output Configuration\n\nMako does not behave like Jinja's autoescape-by-default setups. If you output HTML, opt into escaping deliberately.\n\n### Escape individual expressions\n\n```mako\n${user_input | h}\n```\n\n`h` applies HTML escaping. This is the safest default for untrusted values inserted into HTML text nodes.\n\n### Set escaping for the whole template\n\nUse page-level or lookup-level filters so you do not have to remember `| h` everywhere:\n\n```mako\n<%page expression_filter=\"h\"/>\n```\n\nOr configure the lookup:\n\n```python\nfrom mako.lookup import TemplateLookup\n\nlookup = TemplateLookup(\n    directories=[\"templates\"],\n    default_filters=[\"str\", \"h\"],\n)\n```\n\nUseful filter notes:\n\n- `expression_filter=\"h\"` or `default_filters=[\"str\", \"h\"]` is a practical HTML default\n- `n` disables the default filter chain for a specific expression when you intentionally need raw output\n- `str` is part of the default filter behavior in Python 3 and is why many old Python 2 era examples no longer match current behavior\n\n### Return bytes when you need encoded output\n\n```python\nfrom mako.template import Template\n\ntemplate = Template(\n    \"Hello ${name}\",\n    output_encoding=\"utf-8\",\n    encoding_errors=\"replace\",\n)\n\npayload = template.render(name=\"Ada\")\nassert isinstance(payload, bytes)\n```\n\nIf the caller expects text, prefer `render_unicode()` or avoid `output_encoding`.\n\n## Error Handling And Debugging\n\nFor development, turn on strict variable checking and readable exception formatting:\n\n```python\nfrom mako import exceptions\nfrom mako.lookup import TemplateLookup\n\nlookup = TemplateLookup(\n    directories=[\"templates\"],\n    strict_undefined=True,\n    format_exceptions=True,\n)\n\ntry:\n    html = lookup.get_template(\"users/detail.html\").render(user=None)\nexcept Exception:\n    print(exceptions.text_error_template().render())\n```\n\nUseful exception helpers:\n\n- `format_exceptions=True`: render HTML traceback output instead of a blank server error page in many web integrations\n- `exceptions.text_error_template()`: readable text traceback\n- `exceptions.html_error_template()`: HTML traceback page\n- `exceptions.RichTraceback()`: structured traceback details when you need custom logging\n\n## Configuration Notes\n\n### Template lookup cache\n\n`TemplateLookup` caches templates in memory and can also write compiled modules to disk. In production:\n\n- keep `module_directory` on persistent writable storage\n- disable `filesystem_checks` only when template files are deployed atomically and do not need live reload\n- tune `collection_size` only if you create a very large number of distinct templates and need LRU-style eviction\n\n### Imports and shared helpers\n\nIf templates need shared imports, configure them on the lookup instead of repeating imports in every file:\n\n```python\nfrom mako.lookup import TemplateLookup\n\nlookup = TemplateLookup(\n    directories=[\"templates\"],\n    imports=[\"from myapp.formatting import format_money\"],\n)\n```\n\n### Web framework integration\n\nMost integrations still reduce to \"build a `TemplateLookup`, then render a template with a context dict\". Keep the lookup object process-wide when possible instead of rebuilding it per request.\n\n## Common Pitfalls\n\n- Do not treat template source as safe user input. Mako templates can contain arbitrary Python code, so template authors are effectively trusted-code authors.\n- Missing variables become `UNDEFINED` by default and may fail later in a confusing place. Use `strict_undefined=True` for application templates.\n- HTML escaping is not automatic unless you configure it. `Template(\"${value}\")` will emit raw content.\n- `render()` can return `bytes` when `output_encoding` is set. That is a common source of framework integration bugs.\n- File-based features such as `<%inherit>`, `<%include>`, and URI lookups are much easier to manage through `TemplateLookup` than by instantiating `Template(filename=...)` ad hoc everywhere.\n- If you disable `filesystem_checks`, template edits will not be picked up until the process restarts or the cache is invalidated.\n- Old blog posts often use Python 2 examples or pre-`strict_undefined` workarounds. Prefer the current docs for filter behavior and undefined-variable handling.\n\n## Version-Sensitive Notes For 1.3.10\n\n- `Mako 1.3.10` is the current version on PyPI as of March 12, 2026.\n- `1.3.10` fixes a `strict_undefined` bug involving nested list comprehensions, so projects that rely on strict undefined checking should prefer `1.3.10` over earlier `1.3.x` releases.\n- PyPI marks `1.3.7` and `1.3.4` as yanked. Avoid pinning them in new work.\n- If you are copying older examples, remember that Python 3 output/filter behavior assumes `str` in the default filter chain; current filtering docs reflect that behavior.\n\n## Official Sources\n\n- Docs: `https://docs.makotemplates.org/en/latest/`\n- Usage and API patterns: `https://docs.makotemplates.org/en/latest/usage.html`\n- Syntax reference: `https://docs.makotemplates.org/en/latest/syntax.html`\n- Filtering and escaping: `https://docs.makotemplates.org/en/latest/filtering.html`\n- Runtime behavior: `https://docs.makotemplates.org/en/latest/runtime.html`\n- Changelog: `https://docs.makotemplates.org/en/latest/changelog.html`\n- PyPI package page: `https://pypi.org/project/Mako/`\n"
  },
  {
    "path": "content/markupsafe/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"MarkupSafe package guide for Python safe HTML escaping and markup handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"markupsafe,python,html,escaping,security,templating\"\n---\n\n# MarkupSafe Python Package Guide\n\n## What It Is\n\n`markupsafe` escapes untrusted text for HTML and XML and tracks whether a value is already safe. Its core types are:\n\n- `escape()` for turning untrusted input into escaped HTML-safe text\n- `Markup` for values that are already safe to insert into HTML/XML\n- `escape_silent()` for optional values that may be `None`\n- `soft_str()` for preserving an existing `Markup` value when converting to text\n\nUse it when generating HTML fragments directly, writing framework integrations that expose HTML, or preserving safe template output without double-escaping it.\n\n## Install\n\n`3.0.3` requires Python 3.9 or newer.\n\n```bash\npip install markupsafe==3.0.3\n```\n\nCommon imports:\n\n```python\nfrom markupsafe import Markup, escape, escape_silent, soft_str\n```\n\n## Setup Model\n\nThere is no service initialization, config file, or authentication layer.\n\nThe main setup decision is whether a value is:\n\n- untrusted text that must be escaped with `escape()`\n- trusted markup you intentionally wrap with `Markup(...)`\n- an object that provides safe HTML via `__html__()` or `__html_format__()`\n\nIf that distinction is unclear, default to `escape()`.\n\n## Core Usage\n\n### Escape untrusted input\n\n```python\nfrom markupsafe import escape\n\nuser_input = '<script>alert(\"xss\")</script>'\nsafe = escape(user_input)\n\nhtml = f\"<p>{safe}</p>\"\nprint(html)\n# <p>&lt;script&gt;alert(&#34;xss&#34;)&lt;/script&gt;</p>\n```\n\n`escape()` returns a `Markup` instance, not a plain `str`. Once a value is `Markup`, combining it with more text will escape the new text automatically.\n\n### Build HTML fragments safely\n\n```python\nfrom markupsafe import Markup\n\nname = 'Alice <Admin>'\nhtml = Markup(\"<strong>%s</strong>\") % name\n\nprint(html)\n# <strong>Alice &lt;Admin&gt;</strong>\n```\n\n`Markup` is a `str` subclass. Formatting and concatenation return `Markup` and escape inserted values.\n\n### Handle optional values\n\n```python\nfrom markupsafe import Markup, escape_silent\n\nnickname = None\nhtml = Markup(\"<span>%s</span>\") % escape_silent(nickname)\n\nprint(html)\n# <span></span>\n```\n\nUse `escape_silent()` when `None` should render as an empty string instead of the literal text `\"None\"`.\n\n### Preserve safe strings when normalizing values\n\n```python\nfrom markupsafe import escape, soft_str\n\nvalue = escape(\"<User 1>\")\n\ndouble_escaped = escape(str(value))\ncorrect = escape(soft_str(value))\n\nprint(double_escaped)  # &amp;lt;User 1&amp;gt;\nprint(correct)         # &lt;User 1&gt;\n```\n\nUse `soft_str()` instead of `str()` if the value may already be `Markup`.\n\n### Implement HTML on your own objects\n\n```python\nfrom markupsafe import Markup, escape\n\nclass UserLink:\n    def __init__(self, user_id: int, display_name: str) -> None:\n        self.user_id = user_id\n        self.display_name = display_name\n\n    def __html__(self) -> str:\n        return f'<a href=\"/users/{self.user_id}\">{escape(self.display_name)}</a>'\n\nhtml = Markup(\"%s\") % UserLink(7, \"<Admin>\")\nprint(html)\n# <a href=\"/users/7\">&lt;Admin&gt;</a>\n```\n\nIf an object defines `__html__()`, MarkupSafe treats that result as already safe and will not escape it again.\n\n### Use `format()` when HTML-specific formatting matters\n\n```python\nfrom markupsafe import Markup\n\ntemplate = Markup(\"<p>User: {name}</p>\")\nhtml = template.format(name='\"World\"')\n\nprint(html)\n# <p>User: &#34;World&#34;</p>\n```\n\n`Markup.format()` escapes inserted values. If you need format-spec behavior for safe HTML objects, implement `__html_format__()`.\n\n### Convert markup back to plain text\n\n```python\nfrom markupsafe import Markup\n\nvalue = Markup(\"Main &raquo; <em>About</em>\")\n\nprint(value.unescape())   # Main » <em>About</em>\nprint(value.striptags())  # Main » About\n```\n\nUse:\n\n- `unescape()` when you want text with HTML entities resolved\n- `striptags()` when you want display text without tags\n\n## Config And Auth\n\nThere are no package-specific environment variables, auth flows, credentials, or runtime config objects.\n\nThe only meaningful policy decision is your trust boundary:\n\n- call `escape()` for untrusted or unknown text\n- only create `Markup(...)` from literals or already-sanitized HTML you trust\n- keep `__html__()` and `__html_format__()` implementations strict and reviewable\n\n## Common Pitfalls\n\n### `Markup(...)` does not escape input\n\nThis is the most important footgun.\n\n```python\nfrom markupsafe import Markup, escape\n\nraw = \"<script>alert(1)</script>\"\n\nunsafe = Markup(raw)\nsafe = escape(raw)\n```\n\n`Markup(raw)` marks the text safe as-is. It is only correct if `raw` is already trusted HTML.\n\n### Plain string interpolation is still unsafe\n\nThis is wrong if `user_input` is untrusted:\n\n```python\nhtml = f\"<p>{user_input}</p>\"\n```\n\nEscape first, or format through `Markup`.\n\n### `__html__()` bypasses normal escaping\n\nIf your object returns HTML from `__html__()`, any user-controlled fields inside that output must be escaped manually.\n\n### `str()` can lose the safe-string marker\n\nConverting `Markup` to plain `str` and then escaping again can double-escape entities. Prefer `soft_str()`.\n\n### Do not assume all `Markup` string methods still escape arguments\n\nIn `3.0.0`, some `str`-style methods stopped escaping their search/removal arguments:\n\n- `strip`, `lstrip`, `rstrip`\n- `removeprefix`, `removesuffix`\n- `partition`, `rpartition`\n- `replace` only escapes its `new` argument\n\nDo not rely on these methods to sanitize input. Escape explicitly before mixing in user data.\n\n### Prefer `importlib.metadata.version()` over `markupsafe.__version__`\n\n`__version__` is deprecated in `3.0.x`. For version checks:\n\n```python\nfrom importlib.metadata import version\n\nmarkupsafe_version = version(\"markupsafe\")\n```\n\n## Version Notes For 3.0.3\n\n- `3.0.3` is the package version covered by this doc.\n- PyPI metadata for `3.0.3` requires Python `>=3.9`.\n- `3.0.3` changes include a `DeprecationWarning` for `__version__` instead of `UserWarning`, plus packaging and wheel updates.\n- `3.0.2` fixed compatibility when `__str__` returns a `str` subclass.\n- `3.0.1` fixed compatibility with proxy objects.\n- `3.0.0` dropped Python 3.7 and 3.8 support and changed argument-escaping behavior for some `Markup` string methods.\n\nIf code was written against `2.x`, review `3.0.0` changes before copying old examples.\n\n## Official Sources\n\n- Docs root: https://markupsafe.palletsprojects.com/en/stable/\n- Working with safe text: https://markupsafe.palletsprojects.com/en/stable/escaping/\n- HTML representations: https://markupsafe.palletsprojects.com/en/stable/html/\n- String formatting: https://markupsafe.palletsprojects.com/en/stable/formatting/\n- Changelog: https://markupsafe.palletsprojects.com/en/stable/changes/\n- PyPI: https://pypi.org/project/markupsafe/\n"
  },
  {
    "path": "content/marshmallow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"marshmallow 4.2.2 package guide for Python schema validation, serialization, and deserialization\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"marshmallow,python,serialization,validation,schema,json\"\n---\n\n# marshmallow Python Package Guide\n\n## Golden Rule\n\nUse explicit `Schema` subclasses with declared fields, validate incoming data with `load()` or `validate()`, and assume `marshmallow 4` behavior. `dump()` serializes objects but does not validate them, so do not treat a successful dump as input validation.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"marshmallow==4.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"marshmallow==4.2.2\"\npoetry add \"marshmallow==4.2.2\"\n```\n\nNotes:\n\n- The PyPI package is `marshmallow`, and the main import is also `marshmallow`.\n- `marshmallow` itself has no runtime service credentials or network setup.\n- PyPI exposes extras such as `dev`, `docs`, and `tests` for upstream development workflows; most applications should install the base package only.\n\n## Initialize A Schema\n\nThe main setup step is defining a schema class with explicit fields.\n\n```python\nfrom marshmallow import Schema, fields\n\nclass UserSchema(Schema):\n    id = fields.UUID(dump_only=True)\n    email = fields.Email(required=True)\n    display_name = fields.String(required=True)\n    created_at = fields.DateTime(dump_only=True)\n    is_admin = fields.Boolean(load_default=False)\n\nuser_schema = UserSchema()\nusers_schema = UserSchema(many=True)\n```\n\nKey patterns:\n\n- Use `required=True` for mandatory input fields.\n- Use `load_default=...` for default values during deserialization.\n- Use `dump_only=True` and `load_only=True` for output-only and input-only fields.\n- Use `many=True` when working with lists of objects.\n\n## Core Usage\n\n### Deserialize and validate input\n\n`load()` validates and converts incoming data into Python-native values.\n\n```python\nfrom marshmallow import Schema, ValidationError, fields\n\nclass UserInputSchema(Schema):\n    email = fields.Email(required=True)\n    age = fields.Integer(required=True)\n\nschema = UserInputSchema()\n\npayload = {\"email\": \"dev@example.com\", \"age\": \"42\"}\n\ntry:\n    data = schema.load(payload)\n    print(data)  # {'email': 'dev@example.com', 'age': 42}\nexcept ValidationError as err:\n    print(err.messages)\n```\n\nIf you only need validation errors without deserialized output, use `schema.validate(payload)`.\n\n### Serialize Python objects or dicts\n\n`dump()` converts Python objects into plain dicts. It does not run the same validation path as `load()`.\n\n```python\nfrom dataclasses import dataclass\nfrom datetime import datetime, UTC\nfrom uuid import uuid4\n\n@dataclass\nclass User:\n    id: str\n    email: str\n    display_name: str\n    created_at: datetime\n    is_admin: bool\n\nuser = User(\n    id=str(uuid4()),\n    email=\"dev@example.com\",\n    display_name=\"Dev\",\n    created_at=datetime.now(UTC),\n    is_admin=False,\n)\n\nresult = UserSchema().dump(user)\nprint(result)\n```\n\n### Build objects with `post_load`\n\nUse `@post_load` when you want `load()` to return application objects instead of plain dicts.\n\n```python\nfrom dataclasses import dataclass\n\nfrom marshmallow import Schema, fields, post_load\n\n@dataclass\nclass User:\n    email: str\n    display_name: str\n\nclass UserSchema(Schema):\n    email = fields.Email(required=True)\n    display_name = fields.String(required=True)\n\n    @post_load\n    def make_user(self, data, **kwargs):\n        return User(**data)\n```\n\n### Handle nested structures\n\nUse `fields.Nested` for embedded objects and `fields.Pluck` when you only need one field from a nested schema.\n\n```python\nfrom marshmallow import Schema, fields\n\nclass AuthorSchema(Schema):\n    id = fields.Integer(required=True)\n    name = fields.String(required=True)\n\nclass ArticleSchema(Schema):\n    title = fields.String(required=True)\n    author = fields.Nested(AuthorSchema, required=True)\n    author_name = fields.Pluck(AuthorSchema, \"name\", dump_only=True, attribute=\"author\")\n```\n\nFor self-referential or recursive schemas in `marshmallow 4`, prefer a callable:\n\n```python\nclass CategorySchema(Schema):\n    name = fields.String(required=True)\n    children = fields.List(fields.Nested(lambda: CategorySchema()))\n```\n\n### Rename wire-format keys\n\nUse `data_key` when the external payload name differs from the Python field name.\n\n```python\nfrom marshmallow import Schema, fields\n\nclass EventSchema(Schema):\n    occurred_at = fields.DateTime(data_key=\"occurredAt\", required=True)\n```\n\n## Configuration And Input-Control Choices\n\n`marshmallow` does not have auth config. The important configuration surface is schema behavior.\n\n### Unknown fields\n\nThe safest default for API request parsing is usually to reject or explicitly exclude unknown input.\n\n```python\nfrom marshmallow import EXCLUDE, Schema, fields\n\nclass UserSchema(Schema):\n    name = fields.String(required=True)\n\n    class Meta:\n        unknown = EXCLUDE\n```\n\nOptions:\n\n- `RAISE`: fail on unknown fields\n- `EXCLUDE`: ignore unknown fields during `load()`\n- `INCLUDE`: keep unknown fields in output from `load()`\n\nYou can also override this per call:\n\n```python\nresult = UserSchema().load(payload, unknown=EXCLUDE)\n```\n\n### Partial updates\n\nUse `partial=True` for PATCH-style payloads.\n\n```python\nclass ProfileSchema(Schema):\n    email = fields.Email(required=True)\n    bio = fields.String(required=True)\n\nschema = ProfileSchema()\ndata = schema.load({\"bio\": \"Updated\"}, partial=True)\n```\n\n### Read-only and write-only fields\n\nMark fields explicitly instead of filtering dicts by hand:\n\n```python\nclass LoginSchema(Schema):\n    email = fields.Email(required=True)\n    password = fields.String(required=True, load_only=True)\n    access_token = fields.String(dump_only=True)\n```\n\n## Schema Hooks And Custom Behavior\n\n### Normalize input with hooks\n\n`pre_load`, `post_load`, `pre_dump`, and `post_dump` let you adapt data before or after marshmallow's main processing.\n\n```python\nfrom marshmallow import Schema, fields, post_load, pre_load\n\nclass SignupSchema(Schema):\n    email = fields.Email(required=True)\n    display_name = fields.String(required=True)\n\n    @pre_load\n    def normalize_email(self, data, **kwargs):\n        if \"email\" in data:\n            data[\"email\"] = data[\"email\"].strip().lower()\n        return data\n\n    @post_load\n    def finalize(self, data, **kwargs):\n        data[\"display_name\"] = data[\"display_name\"].strip()\n        return data\n```\n\nIf you are upgrading old code, decorator arguments renamed in `4.x`: use `pass_collection`, not `pass_many`.\n\n### Cross-field validation\n\nUse `@validates_schema` for checks that depend on more than one field.\n\n```python\nfrom marshmallow import Schema, ValidationError, fields, validates_schema\n\nclass DateRangeSchema(Schema):\n    starts_at = fields.DateTime(required=True)\n    ends_at = fields.DateTime(required=True)\n\n    @validates_schema\n    def validate_range(self, data, **kwargs):\n        if data[\"ends_at\"] <= data[\"starts_at\"]:\n            raise ValidationError(\n                \"ends_at must be after starts_at\",\n                field_name=\"ends_at\",\n            )\n```\n\n### Computed or custom fields\n\nPrefer `fields.Method` or `fields.Function` when you only need computed serialization or deserialization logic.\n\n```python\nfrom marshmallow import Schema, fields\n\nclass UserSummarySchema(Schema):\n    first_name = fields.String(required=True)\n    last_name = fields.String(required=True)\n    full_name = fields.Method(\"get_full_name\", dump_only=True)\n\n    def get_full_name(self, obj):\n        return f\"{obj['first_name']} {obj['last_name']}\"\n```\n\nCreate a custom field subclass only when built-in fields, `Method`, and `Function` are not enough.\n\n## Common Pitfalls\n\n- `dump()` is serialization, not validation. Run `load()` or `validate()` on untrusted input.\n- In `marshmallow 4`, implicit field creation is removed. Every schema field must be declared explicitly unless another library generates it for you.\n- `Schema.context` was removed in `4.x`. Do not rely on `self.context` from old examples; pass values another way or evaluate the experimental context API in the upgrading guide.\n- `fields.Field`, `fields.Number`, and `fields.Mapping` are no longer meant to be dropped directly into schemas as concrete fields. Use specific field classes like `String`, `Integer`, `Dict`, or subclass `fields.Field`.\n- Custom validators should raise `ValidationError`; old examples that return `False` are outdated.\n- `dump_only` fields are treated as unknown during `load()`. This matters if you switch to `unknown=INCLUDE`, because those fields can then pass through as unvalidated data.\n- For recursive schemas, avoid old `\"self\"` nesting patterns from older blog posts. Use a callable such as `lambda: CategorySchema()`.\n- `DateTime` uses Python's standard-library ISO parsing in `4.x`. Inputs like `YYYY-MM-DD` may deserialize differently than older `3.x` assumptions.\n\n## Version-Sensitive Notes For 4.2.2\n\n- `4.2.2` is the current PyPI release and the stable docs version as of March 12, 2026.\n- PyPI currently requires Python `>=3.10`. `marshmallow 4.1.0` dropped Python 3.9 support, so do not copy older CI matrices blindly.\n- `4.0.0` removed several long-deprecated patterns that still appear in third-party examples: implicit field creation, `Schema.context`, and old decorator argument names such as `pass_many`.\n- `4.0.0` changed `DateTime` parsing to use `datetime.fromisoformat()` for `\"iso\"` handling and removed the `TimeDelta` `precision` argument.\n- `4.2.2` includes a fix for `fields.Constant(None)` so it deserializes back to `None` consistently. If your project uses constant-valued fields, prefer `4.2.2` or newer in the `4.2.x` line.\n\n## Official Sources\n\n- Docs root: `https://marshmallow.readthedocs.io/en/stable/`\n- Quickstart: `https://marshmallow.readthedocs.io/en/stable/quickstart.html`\n- Nesting guide: `https://marshmallow.readthedocs.io/en/stable/nesting.html`\n- Custom fields guide: `https://marshmallow.readthedocs.io/en/stable/custom_fields.html`\n- Hooks guide: `https://marshmallow.readthedocs.io/en/stable/extending/pre_and_post_processing_methods.html`\n- Upgrading guide: `https://marshmallow.readthedocs.io/en/stable/upgrading.html`\n- Changelog: `https://marshmallow.readthedocs.io/en/stable/changelog.html`\n- PyPI project: `https://pypi.org/project/marshmallow/`\n- Repository: `https://github.com/marshmallow-code/marshmallow`\n"
  },
  {
    "path": "content/matplotlib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Matplotlib package guide for Python plotting, figures, styles, and backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.10.8\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"matplotlib,python,plotting,visualization,figures\"\n---\n\n# matplotlib Python Package Guide\n\n## What It Is\n\n`matplotlib` is the standard plotting library for Python. Use it to build static figures, basic interactive plots, and files for reports, notebooks, dashboards, and test artifacts.\n\nFor coding agents, the safest default is:\n\n1. Install `matplotlib` into the project environment.\n2. Use the object-oriented `Figure` and `Axes` API via `plt.subplots()`.\n3. Choose a backend explicitly in headless or notebook environments when display behavior matters.\n4. Save files with `fig.savefig(...)` for deterministic output.\n\n## Installation\n\n```bash\npip install matplotlib==3.10.8\n```\n\nWith `uv`:\n\n```bash\nuv add matplotlib==3.10.8\n```\n\nVerify the installed version:\n\n```bash\npython -c \"import matplotlib; print(matplotlib.__version__)\"\n```\n\nPyPI for `3.10.8` requires Python `>=3.10`. If interactive windows fail to open, the usual problem is not `matplotlib` itself but a missing GUI toolkit or an unsuitable backend for the current environment.\n\n## First Working Plot\n\nUse `plt.subplots()` and operate on the returned `Axes` object instead of building larger scripts around the implicit pyplot state.\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nx = np.linspace(0, 2 * np.pi, 200)\ny = np.sin(x)\n\nfig, ax = plt.subplots(figsize=(6, 4))\nax.plot(x, y, label=\"sin(x)\")\nax.set_title(\"Sine wave\")\nax.set_xlabel(\"x\")\nax.set_ylabel(\"y\")\nax.legend()\nfig.tight_layout()\n\nfig.savefig(\"sine.png\", dpi=150)\nplt.show()\n```\n\n## Core Usage Patterns\n\n### Preferred interface\n\nMatplotlib documents two major interfaces:\n\n- The explicit object-oriented `Axes` interface\n- The implicit `pyplot` interface\n\nPrefer the explicit `Axes` interface for functions, libraries, tests, and any code that needs predictable behavior.\n\n```python\nimport matplotlib.pyplot as plt\n\nfig, ax = plt.subplots()\nax.plot([1, 2, 3], [2, 4, 3], marker=\"o\")\nax.set(xlabel=\"step\", ylabel=\"value\", title=\"Run metrics\")\nfig.tight_layout()\n```\n\n### Multiple plots\n\n```python\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 4))\n\naxes[0].bar([\"A\", \"B\", \"C\"], [3, 5, 2])\naxes[0].set_title(\"Bars\")\n\naxes[1].scatter([1, 2, 3, 4], [4, 1, 3, 2])\naxes[1].set_title(\"Scatter\")\n\nfig.tight_layout()\nfig.savefig(\"summary.png\", dpi=150)\n```\n\n### Use NumPy arrays directly\n\nMost examples in the official docs pass lists or NumPy arrays directly into plotting calls. For numeric work, keep the data as arrays and let `Axes.plot`, `Axes.scatter`, `Axes.imshow`, and similar methods consume them directly.\n\n### Save files for agents and CI\n\nFor scripts, tests, or non-interactive jobs, prefer explicit file output:\n\n```python\nfig.savefig(\"plot.svg\")\nfig.savefig(\"plot.png\", dpi=200, bbox_inches=\"tight\")\n```\n\n`PNG`, `PDF`, and `SVG` are the usual safe defaults.\n\n## Configuration And Environment\n\n### Backends\n\nThe backend controls where figures render: GUI windows, notebooks, or image files. Matplotlib documents three main ways to configure it:\n\n1. `rcParams[\"backend\"]` in configuration\n2. The `MPLBACKEND` environment variable\n3. `matplotlib.use()`\n\nFor headless jobs, set `Agg` before importing `pyplot`:\n\n```python\nimport matplotlib\n\nmatplotlib.use(\"Agg\")\n\nimport matplotlib.pyplot as plt\n```\n\nIf you need interactive windows locally, use an interactive backend supported by your environment instead of forcing `Agg`.\n\n### Styles and rcParams\n\nUse styles for broad appearance changes and `rcParams` for targeted defaults.\n\n```python\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nplt.style.use(\"ggplot\")\nmpl.rcParams[\"figure.dpi\"] = 150\nmpl.rcParams[\"axes.grid\"] = True\n```\n\nProject-level defaults can live in a `matplotlibrc` file. Runtime settings override configuration-file defaults.\n\n### Config directory\n\n`MPLCONFIGDIR` points Matplotlib at the directory used for configuration and cache files. Set it in locked-down CI or container environments if the default user cache/config location is not writable.\n\n```bash\nexport MPLCONFIGDIR=\"$PWD/.matplotlib\"\n```\n\n## Notebooks And Interactive Workflows\n\nIn notebooks, inline rendering is usually enough:\n\n```python\nimport matplotlib.pyplot as plt\n\nplt.plot([1, 2, 3], [1, 4, 9])\nplt.show()\n```\n\nIf a project expects richer widget-based interactivity, confirm the notebook backend and any extra dependency such as `ipympl` before writing code around pan/zoom callbacks or live updates.\n\n## Common Pitfalls\n\n### No display in CI, containers, or servers\n\nSymptom: `plt.show()` does nothing useful or backend import errors appear.\n\nUse a non-interactive backend and save files instead:\n\n```python\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport matplotlib.pyplot as plt\n```\n\n### Switching backends too late\n\n`matplotlib.use()` must happen before figures are created. In practice, do it before importing `matplotlib.pyplot`.\n\n### Mixing pyplot state with reusable library code\n\nStateful pyplot calls are fine for short scripts, but library code is easier to test and compose if it accepts an `Axes` and returns a `Figure` or `Axes`.\n\n```python\ndef render_series(ax, xs, ys):\n    ax.plot(xs, ys)\n    ax.set_title(\"Series\")\n    return ax\n```\n\n### Interactive backend missing dependencies\n\nIf the default backend fails on a local desktop, install or enable a supported GUI toolkit for that environment, or fall back to file output.\n\n### Blank or incomplete saved images\n\nApply layout before saving and save from the `Figure` object you actually modified:\n\n```python\nfig.tight_layout()\nfig.savefig(\"figure.png\", dpi=150)\n```\n\n## Version-Sensitive Notes For 3.10.8\n\n- This guide targets `matplotlib` `3.10.8`, which is also the current stable docs version linked above.\n- PyPI for `3.10.8` requires Python `>=3.10`.\n- Use the stable documentation for API details that vary by minor release, especially backend behavior, configuration defaults, and notebook integration.\n- If you use `uv` and want the `tkagg` backend with Python builds managed by `uv`, Matplotlib's install docs call out `uv` `0.8.7` or later for bundled `tkinter` support.\n\n## Official Sources\n\n- Matplotlib stable API index: https://matplotlib.org/stable/api/index.html\n- Getting started: https://matplotlib.org/stable/users/getting_started/\n- Installation: https://matplotlib.org/stable/users/installing/index.html\n- Application interfaces: https://matplotlib.org/stable/users/explain/figure/api_interfaces.html\n- Backends: https://matplotlib.org/stable/users/explain/figure/backends.html\n- Customizing with styles and rcParams: https://matplotlib.org/stable/users/explain/customizing.html\n- Configuration API: https://matplotlib.org/stable/api/matplotlib_configuration_api.html\n- PyPI package page: https://pypi.org/project/matplotlib/\n"
  },
  {
    "path": "content/maturin/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"maturin guide for building, testing, and publishing Rust-backed Python packages\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"maturin,rust,python,packaging,wheels,pyo3,cffi,uniffi\"\n---\n\n# maturin Python Package Guide\n\n## Golden Rule\n\nUse `maturin` when you need to build or publish a Python package backed by Rust. Keep packaging metadata and `maturin` settings in `pyproject.toml`, use `maturin develop` for fast local iteration inside a virtualenv, and use `maturin build -r` for the wheel you intend to ship.\n\n## Install The Tool\n\nThe upstream docs prefer installing `maturin` as a tool instead of as a project dependency:\n\n```bash\npipx install maturin\nuv tool install maturin\n```\n\n`pip install maturin` also works:\n\n```bash\npython -m pip install \"maturin==1.12.6\"\n```\n\nIf you need platform-repair or cross-compilation helpers, the published extras are:\n\n```bash\npython -m pip install \"maturin[patchelf]==1.12.6\"\npython -m pip install \"maturin[zig]==1.12.6\"\n```\n\nIf you already have Rust via `rustup` and want a Rust-native install path:\n\n```bash\ncargo install --locked maturin\n```\n\n## Initialize A Project\n\nFor a new package, `maturin new` is the quickest path:\n\n```bash\nmaturin new --bindings pyo3 --mixed hello-maturin\ncd hello-maturin\npython -m venv .venv\nsource .venv/bin/activate\nmaturin develop\n```\n\nUseful `maturin new` options from the user guide:\n\n- `--bindings pyo3|cffi|uniffi|bin`\n- `--mixed` for a mixed Rust/Python layout\n- `--src` for a Python-first source layout under `src/`\n\nIf you already have a Rust crate, add a `pyproject.toml` next to `Cargo.toml`:\n\n```toml\n[build-system]\nrequires = [\"maturin>=1.0,<2.0\"]\nbuild-backend = \"maturin\"\n\n[project]\nname = \"hello-maturin\"\nversion = \"0.1.0\"\nrequires-python = \">=3.8\"\n\n[tool.maturin]\nbindings = \"pyo3\"\ncompatibility = \"pypi\"\n```\n\nFor older `pyo3` projects, add the extension feature explicitly:\n\n```toml\n[tool.maturin]\nfeatures = [\"pyo3/extension-module\"]\n```\n\nYou only need that for `pyo3 0.26` and earlier. The user guide says `pyo3 0.27` handles it automatically.\n\n## Recommended Layouts\n\n### Pure Rust package\n\nFor a pure Rust project, keep `Cargo.toml`, `pyproject.toml`, and `src/` at the project root. `maturin` will generate the package `__init__.py` during wheel build.\n\n### Mixed Rust/Python package\n\nFor most real packages, the mixed layout is safer and more flexible:\n\n```text\nhello-maturin/\n├── Cargo.toml\n├── pyproject.toml\n├── python/\n│   └── hello_maturin/\n│       └── __init__.py\n└── src/\n    └── lib.rs\n```\n\nConfigure it like this:\n\n```toml\n[tool.maturin]\nbindings = \"pyo3\"\npython-source = \"python\"\nmodule-name = \"hello_maturin._core\"\ncompatibility = \"pypi\"\nauditwheel = \"repair\"\n```\n\nThis layout avoids the common import-path collision the upstream docs call out. If you set `module-name = \"hello_maturin._core\"`, make the Rust module name match `_core` in your `#[pymodule]` declaration.\n\n## Core Commands\n\n### Fast local development\n\nRun this inside an active virtualenv:\n\n```bash\nmaturin develop\n```\n\nCommon variants:\n\n```bash\nmaturin develop -r\nmaturin develop --features pyo3/abi3-py38\nmaturin develop --skip-install\n```\n\nNotes:\n\n- `develop` builds in debug mode by default.\n- `--skip-install` only makes sense for mixed Rust/Python layouts.\n- `develop` is faster than the wheel-install path, but the upstream docs explicitly note it does not support every feature that `pip install` after `maturin build` supports.\n\n### Build wheels\n\n```bash\nmaturin build -r\n```\n\nBy default, wheels go to `target/wheels/`.\n\nUseful variants:\n\n```bash\nmaturin build -r --compatibility pypi\nmaturin build -r --bindings cffi\nmaturin build -r --target x86_64-unknown-linux-gnu\n```\n\nFor Linux wheels intended for broad PyPI use, keep `compatibility = \"pypi\"` and use a manylinux container or Zig-based cross compilation when needed.\n\n### Build an sdist or use the PEP 517 backend\n\nIf the project has the `[build-system]` block shown above, you can use standard Python packaging flows:\n\n```bash\npip install .\npip install . --config-settings=\"build-args=--features pyo3/abi3-py38\"\npython -m pip wheel .\nmaturin sdist\n```\n\n`maturin` also honors:\n\n```bash\nexport MATURIN_PEP517_ARGS=\"--features pyo3/abi3-py38 --profile release\"\n```\n\nBut `pip --config-settings` takes priority over `MATURIN_PEP517_ARGS`.\n\n## Binding Modes You Should Pick Explicitly\n\n`maturin` supports these binding types:\n\n- `pyo3`\n- `pyo3-ffi`\n- `cffi`\n- `uniffi`\n- `bin`\n\nPractical guidance:\n\n- `pyo3` is the default choice for Python extension modules.\n- `cffi` and `uniffi` can produce wheels usable across Python versions, but they have extra setup requirements.\n- `bin` packages a Rust executable as a Python-installed script on the user's `PATH`.\n\nImportant detection rule:\n\n- `cffi` and `bin` projects are the ones most worth declaring explicitly in `[tool.maturin]` or on the CLI, especially when auto-detection is ambiguous.\n\nExample:\n\n```toml\n[tool.maturin]\nbindings = \"cffi\"\ncompatibility = \"linux\"\n```\n\n## Configuration That Matters Most\n\nThe main `maturin` options live under `[tool.maturin]` in `pyproject.toml`.\n\n```toml\n[tool.maturin]\nbindings = \"pyo3\"\ncompatibility = \"pypi\"\nauditwheel = \"repair\"\npython-source = \"python\"\ninclude = [\"hello_maturin/data/*.json\"]\nstrip = true\nuse-base-python = false\n```\n\nWhat these settings do in practice:\n\n- `bindings`: selects `pyo3`, `cffi`, `uniffi`, or `bin`\n- `compatibility`: controls the wheel platform tag and PyPI compatibility checks\n- `auditwheel`: `repair`, `check`, or `skip` for Linux shared-library handling\n- `python-source`: points at your Python package tree for mixed layouts\n- `include`: adds extra files to `sdist` and/or wheel outputs\n- `strip`: reduces native artifact size\n- `use-base-python`: can avoid repeated rebuilds in PEP 517 flows, but upstream warns not to use it when the sdist build needs packages installed inside the venv\n\n## Publishing And Auth\n\nThe README now recommends building with `maturin` and publishing with `uv`:\n\n```bash\nmaturin build -r\nuv publish target/wheels/*\n```\n\nIf you still rely on `maturin` upload credentials, the documented environment variables are:\n\n```bash\nexport MATURIN_PYPI_TOKEN=\"pypi-...\"\nexport MATURIN_REPOSITORY=\"pypi\"\nexport MATURIN_REPOSITORY_URL=\"https://test.pypi.org/legacy/\"\nexport MATURIN_USERNAME=\"__token__\"\nexport MATURIN_PASSWORD=\"...\"\nexport MATURIN_NON_INTERACTIVE=1\n```\n\nUse `MATURIN_REPOSITORY_URL` for custom indexes or TestPyPI. Prefer token auth over username/password when publishing to PyPI.\n\n## Cross-Compilation And Platform Notes\n\n- The upstream install docs expose a `zig` extra specifically for easier cross compilation and manylinux compliance.\n- The `patchelf` extra is for repairing Linux wheels that link additional shared libraries.\n- On Linux, `auditwheel = \"repair\"` is the default path for fixing wheel portability when possible.\n- For macOS universal2 or multi-arch builds, `ARCHFLAGS=\"-arch x86_64 -arch arm64\"` is the documented environment-variable path.\n- For PyO3 cross compilation, `PYO3_CROSS_PYTHON_VERSION`, `PYO3_CROSS_LIB_DIR`, and `PYO3_CONFIG_FILE` are the main env vars the user guide documents.\n\n## Common Pitfalls\n\n- Do not keep old `maturin` metadata in `Cargo.toml`. Current configuration belongs in `[tool.maturin]` inside `pyproject.toml`.\n- Do not assume `maturin develop` is identical to `pip install .`; it is an editable-development shortcut, not the full packaging path.\n- For mixed layouts, avoid giving the native extension the same import name as the top-level Python package unless you want the nested import style.\n- If you use `python-source`, make sure the Python package actually exists there; the `1.12` line tightened checks around missing modules.\n- For `cffi` and `uniffi`, budget for extra tooling and packaging steps instead of assuming the `pyo3` examples map over directly.\n- For Linux wheel publishing, a local build on a modern distro often produces a too-specific `linux` tag unless you use manylinux or Zig correctly.\n- `maturin` builds Rust artifacts; if `cargo` is unavailable during a PEP 517 build, the tool may try to install Rust unless you set `MATURIN_NO_INSTALL_RUST`.\n\n## Version-Sensitive Notes\n\n- The version used here `1.12.6` matches the current PyPI latest release as of March 12, 2026. PyPI shows it was released on March 1, 2026.\n- When using `maturin` as a build backend, the upstream tutorial still recommends `requires = [\"maturin>=1.0,<2.0\"]` rather than pinning an exact patch release in `pyproject.toml`.\n- The migration guide says the old `[package.metadata.maturin]` path was removed in `0.15`; modern projects should keep config in `[tool.maturin]`.\n- The changelog marks `publish` and `upload` as deprecated since `1.11.0`, which is why the current README recommends `uv publish`.\n- The `1.12.0` line added `MATURIN_STRIP` support, improved include handling, and hardened `python-source` validation. If you are upgrading from older `1.x` releases, re-check custom include globs and mixed-layout packaging.\n\n## Official Links\n\n- User guide: https://www.maturin.rs/\n- Installation: https://www.maturin.rs/installation.html\n- Tutorial: https://www.maturin.rs/tutorial.html\n- Project layout: https://www.maturin.rs/project_layout.html\n- Bindings: https://www.maturin.rs/bindings.html\n- Configuration: https://www.maturin.rs/config.html\n- Environment variables: https://www.maturin.rs/environment-variables.html\n- Migration guide: https://www.maturin.rs/migration.html\n- Changelog: https://www.maturin.rs/changelog.html\n- PyPI: https://pypi.org/project/maturin/\n"
  },
  {
    "path": "content/mccabe/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"mccabe Python package guide for cyclomatic complexity checks directly or through Flake8\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"mccabe,python,flake8,linting,complexity,cyclomatic-complexity\"\n---\n\n# mccabe Python Package Guide\n\n## Golden Rule\n\nUse `mccabe` for one job: measuring cyclomatic complexity in Python code. In most projects, the practical entry point is Flake8's `--max-complexity` option, because `mccabe` ships as a Flake8 plugin and reports `C901` when a function is over the configured threshold.\n\nAs of March 13, 2026, PyPI still lists `0.7.0` as the current release. That release requires Python 3.6 or newer.\n\n## Install\n\nCreate or activate a virtual environment, then install the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"mccabe==0.7.0\"\n```\n\nIf you want the normal linting workflow, install Flake8 alongside it:\n\n```bash\npython -m pip install \"flake8\" \"mccabe==0.7.0\"\n```\n\n## Runtime Setup\n\n`mccabe` runs entirely on local source code. There are no API keys, service credentials, or environment variables to configure, and there is no client object to initialize.\n\nThe direct Python imports are:\n\n```python\nfrom mccabe import McCabeChecker, get_code_complexity, get_module_complexity\n```\n\n## Use The Standalone CLI\n\nThe built-in command-line entry point is module-based:\n\n```bash\npython -m mccabe --min 10 path/to/module.py\n```\n\n`--min` controls the minimum complexity value that should be printed. The source sets its default to `1`.\n\nTo emit Graphviz DOT output instead of the text listing:\n\n```bash\npython -m mccabe --dot --min 10 path/to/module.py > complexity.dot\n```\n\nThis mode is file-oriented. The standalone command reads one source file path and analyzes that file.\n\n## Use It Through Flake8\n\nWhen both `flake8` and `mccabe` are installed, Flake8 exposes the plugin's threshold setting:\n\n```bash\nflake8 --max-complexity 10 src/\n```\n\nYou can confirm the plugin is loaded with:\n\n```bash\nflake8 --version\n```\n\nFor a project-level threshold, set it in your Flake8 configuration:\n\n```ini\n[flake8]\nmax-complexity = 10\n```\n\n`mccabe` only emits `C901`. Flake8's docs describe `--max-complexity` as the `mccabe` plugin option, and the package README documents `# noqa: C901` for silencing a specific function on the reported line.\n\n```python\ndef legacy_branching_code(value):  # noqa: C901\n    ...\n```\n\n## Call The Python API\n\n### Quick check from source text\n\n`get_code_complexity()` compiles the code to an AST, prints any matching violations, and returns the number of functions or blocks over the threshold:\n\n```python\nfrom pathlib import Path\n\nfrom mccabe import get_code_complexity\n\nfilename = \"src/example.py\"\nsource = Path(filename).read_text(encoding=\"utf-8\")\n\nviolations = get_code_complexity(source, threshold=10, filename=filename)\nprint(f\"{violations} blocks exceeded the threshold\")\n```\n\n### Quick check from a file path\n\n`get_module_complexity()` reads the file for you and then delegates to `get_code_complexity()`:\n\n```python\nfrom mccabe import get_module_complexity\n\nviolations = get_module_complexity(\"src/example.py\", threshold=10)\nprint(f\"{violations} blocks exceeded the threshold\")\n```\n\n### Structured results with `McCabeChecker`\n\nIf you want to handle the violations yourself instead of using the helper that prints to stdout, use `McCabeChecker` directly. Its `run()` method yields `(line, column, message, checker_type)` tuples.\n\n```python\nimport ast\nfrom pathlib import Path\n\nfrom mccabe import McCabeChecker\n\nfilename = \"src/example.py\"\nsource = Path(filename).read_text(encoding=\"utf-8\")\ntree = compile(source, filename, \"exec\", ast.PyCF_ONLY_AST)\n\nMcCabeChecker.max_complexity = 10\n\nfor line, column, message, _ in McCabeChecker(tree, filename).run():\n    print((line, column, message))\n```\n\n## Important Pitfalls\n\n- `mccabe` does not recursively walk directories on its own. Use Flake8 if you want normal project-wide linting.\n- `McCabeChecker.run()` does nothing unless `McCabeChecker.max_complexity` is set to a non-negative threshold first.\n- `get_code_complexity()` prints findings as a side effect and returns a count. Use `McCabeChecker` directly if you need structured results without that print behavior.\n- The threshold is inclusive in `0.7.0`: a function with complexity `10` passes when the limit is `10`; only values greater than the threshold trigger `C901`.\n- Place `# noqa: C901` on the line Flake8 reports for that function, which can be the function definition line or a decorator line above it.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/PyCQA/mccabe`\n- Package README and release notes: `https://github.com/PyCQA/mccabe#readme`\n- PyPI package page: `https://pypi.org/project/mccabe/`\n- Flake8 option reference for `--max-complexity`: `https://flake8.pycqa.org/en/7.1.0/user/options.html#cmdoption-flake8-max-complexity`\n- Flake8 configuration reference: `https://flake8.pycqa.org/en/7.0.0/user/configuration.html`\n- Flake8 error code reference for `C901`: `https://flake8.pycqa.org/en/3.2.1/user/error-codes.html`\n"
  },
  {
    "path": "content/mcp/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"mcp package guide for Python MCP servers and clients with FastMCP, stdio, and Streamable HTTP\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.26.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mcp,model-context-protocol,python,fastmcp,server,client,stdio,streamable-http,oauth\"\n---\n\n# mcp Python Package Guide\n\n## What It Is\n\n`mcp` is the official Python SDK for the Model Context Protocol. It supports both sides of the protocol:\n\n- building MCP servers with the higher-level `FastMCP` API\n- building MCP clients with `ClientSession`\n- using local `stdio` transport or networked Streamable HTTP transport\n- adding OAuth-based authorization for remote servers when needed\n\nFor most server work, start with `FastMCP`. Drop down to the low-level server APIs only if you need custom lifecycle control or nonstandard transports.\n\n## Installation\n\nInstall the exact version covered here:\n\n```bash\npip install mcp==1.26.0\n```\n\nCommon package-manager equivalents:\n\n```bash\nuv add mcp==1.26.0\npoetry add mcp==1.26.0\n```\n\nIf you are writing both server and client code in the same project, the base package is usually enough. Add web-framework or auth dependencies separately only when your server integration needs them.\n\n## Choose The Right Abstraction\n\n### FastMCP for most servers\n\nUse `FastMCP` when you want to expose tools, resources, and prompts without handling the protocol framing yourself.\n\n```python\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"demo\")\n\n@mcp.tool()\ndef add(a: int, b: int) -> int:\n    return a + b\n\n@mcp.resource(\"config://app\")\ndef app_config() -> str:\n    return '{\"mode\":\"demo\"}'\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\nThis is the default path for local tool servers launched by an MCP host over `stdio`.\n\n### Low-level server/client APIs for advanced control\n\nUse the lower-level SDK only if you need behavior that `FastMCP` does not cover cleanly, such as custom transport handling or tight control over request/session flow.\n\n## Core Server Usage\n\n### Local server over stdio\n\nThe simplest production shape for a local MCP server is:\n\n1. define a `FastMCP` app\n2. register tools/resources/prompts with decorators\n3. call `mcp.run()` in `__main__`\n\nThat gives you a server that MCP hosts can spawn as a subprocess and communicate with over standard input/output.\n\n### Remote server over Streamable HTTP\n\nFor network-accessible servers, run FastMCP with the current HTTP transport:\n\n```python\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\n    \"demo-http\",\n    host=\"0.0.0.0\",\n    port=8000,\n    path=\"/mcp\",\n)\n\n@mcp.tool()\ndef add(a: int, b: int) -> int:\n    return a + b\n\nif __name__ == \"__main__\":\n    mcp.run(transport=\"streamable-http\")\n```\n\nUse the exact path your server exposes. If the server runs on `http://localhost:8000/mcp`, the client must connect to that full URL, not just the host root.\n\n### Tools, resources, and prompts\n\nThe FastMCP model is:\n\n- `@mcp.tool()` for executable functions\n- `@mcp.resource(...)` for named content endpoints\n- `@mcp.prompt()` for reusable prompt templates\n\nKeep tool functions small and deterministic when possible. MCP hosts often surface tool descriptions and signatures directly to models, so precise names, docstrings, and parameter types matter.\n\n## Core Client Usage\n\n### Connect to a local stdio server\n\nThe standard local client flow is:\n\n```python\nimport asyncio\n\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\n\nserver_params = StdioServerParameters(\n    command=\"python\",\n    args=[\"server.py\"],\n)\n\nasync def main() -> None:\n    async with stdio_client(server_params) as (read_stream, write_stream):\n        async with ClientSession(read_stream, write_stream) as session:\n            await session.initialize()\n\n            tools = await session.list_tools()\n            print([tool.name for tool in tools.tools])\n\n            result = await session.call_tool(\"add\", {\"a\": 2, \"b\": 3})\n            print(result)\n\nasyncio.run(main())\n```\n\nCritical step: always call `await session.initialize()` before trying to list tools, read resources, or call prompts/tools.\n\n### Connect to a remote HTTP server\n\nFor remote servers, use the matching Streamable HTTP client transport from the SDK rather than trying to hand-roll protocol requests. Keep the transport context manager and `ClientSession` lifetime aligned so streams are closed cleanly.\n\n### Sync client support\n\nThe SDK also provides sync-client support. Prefer the async APIs unless you have a hard requirement to stay synchronous, because most MCP integrations are transport- and session-oriented already.\n\n## Configuration And Auth\n\n### Local stdio servers\n\nLocal subprocess servers usually do not need protocol-level auth. Focus on:\n\n- the correct executable in `command`\n- the correct script/module path in `args`\n- any environment variables the child process needs\n\nIf your server depends on secrets or configuration, pass them through the process environment instead of hardcoding them into the tool logic.\n\n### Remote HTTP servers\n\nFor remote deployments, the SDK supports authorization flows for Streamable HTTP servers and clients. The maintainer docs describe:\n\n- server-side auth integration for FastMCP\n- token verification helpers\n- OAuth provider support on the client side\n- bearer-token based auth for simpler cases\n\n### Request timeout\n\nFor long-running server requests, the Python SDK documents an `MCP_SERVER_REQUEST_TIMEOUT` environment variable. If you have tools that legitimately run longer than the default, set this explicitly in the server environment rather than leaving timeouts implicit.\n\n## Common Patterns\n\n### Expose a tool\n\n```python\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"math\")\n\n@mcp.tool()\ndef multiply(a: int, b: int) -> int:\n    \"\"\"Multiply two integers.\"\"\"\n    return a * b\n```\n\n### Expose a prompt\n\n```python\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"prompts\")\n\n@mcp.prompt()\ndef summarize_topic(topic: str) -> str:\n    return f\"Summarize {topic} in five bullet points.\"\n```\n\n### Launch a server process from a client\n\n```python\nfrom mcp import StdioServerParameters\n\nserver_params = StdioServerParameters(\n    command=\"python\",\n    args=[\"server.py\"],\n)\n```\n\nThis is the canonical pattern for testing a local server from Python without involving a separate MCP host application.\n\n## Common Pitfalls\n\n- Do not skip `session.initialize()`. The session is not ready until initialization completes.\n- Do not use `FastMCP` and low-level server wiring in the same path unless you have a concrete reason. Pick one abstraction level.\n- Do not point an HTTP client at the wrong path. If the server is mounted at `/mcp`, use that full URL.\n- Do not copy older HTTP+SSE examples blindly. The current MCP transport guidance prefers Streamable HTTP.\n- Do not leave tool signatures vague. Typed parameters and clear docstrings improve host-side tool discovery.\n- Do not leak long-running work past session or transport shutdown. Keep async context managers scoped tightly.\n- Do not assume local stdio and remote HTTP share the same operational concerns. Stdio is process-launch/config oriented; HTTP adds auth, routing, proxies, and deployment timeouts.\n\n## Version-Sensitive Notes For 1.26.0\n\n- PyPI is the authoritative source for the covered package version: `1.26.0`.\n- PyPI metadata for `1.26.0` requires Python `>=3.10`.\n- The docs and spec emphasize Streamable HTTP as the current HTTP transport. Older SSE-era examples are the most likely source of stale guidance when copying from blogs, gists, or older issue threads.\n- The official docs root is not version-pinned to `1.26.0`. When a docs example and the package version appear to drift, trust PyPI for the released version and prefer the Python SDK repository examples over third-party material.\n\n## Official Sources\n\n- MCP docs root: https://modelcontextprotocol.io/docs/\n- MCP authorization docs: https://modelcontextprotocol.io/docs/concepts/authorization\n- MCP transport docs: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports\n- Python SDK repository: https://github.com/modelcontextprotocol/python-sdk\n- PyPI project page: https://pypi.org/project/mcp/\n- PyPI release metadata for `1.26.0`: https://pypi.org/pypi/mcp/1.26.0/json\n"
  },
  {
    "path": "content/mediapipe/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"MediaPipe Python package guide for on-device vision, text, and audio tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.10.32\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mediapipe,google-ai-edge,vision,text,audio,ml,computer-vision\"\n---\n\n# MediaPipe Python Package Guide\n\n## What This Package Is For\n\n`mediapipe` is the Python package for MediaPipe Tasks: prebuilt on-device ML APIs for vision, text, and audio workloads. In current upstream docs, the practical Python entry point is the Tasks API under `mediapipe.tasks.python`, not the older `mp.solutions` examples.\n\nUse this package when you need local inference in Python for tasks such as object detection, image classification, hand or pose landmarks, text classification, text embedding, language detection, or audio classification.\n\n## Package Snapshot\n\n- Ecosystem: `pypi`\n- Package: `mediapipe`\n- Import root: `import mediapipe as mp`\n- Version covered: `0.10.32`\n- Upstream docs root: `https://ai.google.dev/edge/mediapipe/`\n- Registry page: `https://pypi.org/project/mediapipe/`\n- Auth: none; inference runs locally\n\n## Installation\n\nPin the package when you want reproducible agent output:\n\n```bash\npython -m pip install \"mediapipe==0.10.32\"\n```\n\nQuick import smoke test:\n\n```bash\npython - <<'PY'\nimport mediapipe as mp\nprint(mp.__version__)\nPY\n```\n\n### Python and platform constraints\n\nThe official Python setup guide documents support for Python `3.9` through `3.12` on Windows, Mac, Linux, and Raspberry Pi OS 64-bit.\n\nFor `0.10.32`, the published PyPI artifacts are more specific:\n\n- `win_amd64`\n- `manylinux_2_28_x86_64`\n- `macosx_11_0_arm64`\n- no source distribution is published on PyPI\n\nIf `pip install mediapipe` fails on another architecture or on an older Linux baseline, use the official build-from-source wheel instructions instead of assuming the package should install everywhere.\n\n## Import Layout\n\nThe setup guide and task pages use this import structure:\n\n```python\nimport mediapipe as mp\nfrom mediapipe.tasks.python import vision, text, audio\n```\n\nCommon aliases from the official examples:\n\n```python\nBaseOptions = mp.tasks.BaseOptions\nVisionRunningMode = mp.tasks.vision.RunningMode\n```\n\n## Core Workflow\n\nMost Python task integrations follow the same shape:\n\n1. Install `mediapipe`.\n2. Download a task-compatible model file (`.task` or `.tflite`) from the task overview/model page.\n3. Build `BaseOptions` with `model_asset_path` or `model_asset_buffer`.\n4. Choose the domain module (`vision`, `text`, or `audio`) and a task-specific `...Options` class.\n5. Pick the correct running mode: `IMAGE`, `VIDEO`, or `LIVE_STREAM`.\n6. Create the task with `create_from_options(...)`.\n7. Convert input data into MediaPipe objects and call the task method for that running mode.\n\n### Minimal image task example\n\nThis example uses the vision Task API pattern shown in the official object detection guide:\n\n```python\nimport mediapipe as mp\nfrom mediapipe.tasks.python import vision\n\nBaseOptions = mp.tasks.BaseOptions\nObjectDetector = vision.ObjectDetector\nObjectDetectorOptions = vision.ObjectDetectorOptions\nRunningMode = vision.RunningMode\n\noptions = ObjectDetectorOptions(\n    base_options=BaseOptions(\n        model_asset_path=\"/absolute/path/to/lite-model_efficientdet_lite0_detection_metadata_1.tflite\"\n    ),\n    running_mode=RunningMode.IMAGE,\n    max_results=5,\n    score_threshold=0.3,\n)\n\nimage = mp.Image.create_from_file(\"/absolute/path/to/image.jpg\")\n\nwith ObjectDetector.create_from_options(options) as detector:\n    result = detector.detect(image)\n    print(result)\n```\n\n### Live stream pattern\n\nUse `LIVE_STREAM` only when you can provide timestamps and handle async callbacks:\n\n```python\nimport mediapipe as mp\nfrom mediapipe.tasks.python import vision\n\nBaseOptions = mp.tasks.BaseOptions\nObjectDetector = vision.ObjectDetector\nObjectDetectorOptions = vision.ObjectDetectorOptions\nRunningMode = vision.RunningMode\n\ndef on_result(result, output_image, timestamp_ms):\n    print(timestamp_ms, result)\n\noptions = ObjectDetectorOptions(\n    base_options=BaseOptions(model_asset_path=\"/absolute/path/to/model.tflite\"),\n    running_mode=RunningMode.LIVE_STREAM,\n    result_callback=on_result,\n)\n\nwith ObjectDetector.create_from_options(options) as detector:\n    # detector.detect_async(mp_image, frame_timestamp_ms)\n    pass\n```\n\n## Models and Setup\n\nInstalling the package is not enough for most tasks. The task guides expect you to download a compatible model and point `BaseOptions` at it:\n\n```python\nbase_options = mp.tasks.BaseOptions(model_asset_path=\"/absolute/path/to/model.task\")\n```\n\n`BaseOptions` also supports `model_asset_buffer` when you already have the model bytes in memory.\n\nChoose the model from the overview page for the exact task you are using. Do not mix a random `.tflite` or `.task` file with a task API that expects packaged metadata from a specific task family.\n\n## Data Preparation\n\nThe Python guides use `mediapipe.Image` as the common container for vision inputs.\n\nFrom file:\n\n```python\nmp_image = mp.Image.create_from_file(\"/absolute/path/to/image.jpg\")\n```\n\nFrom a NumPy array:\n\n```python\nmp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=numpy_image)\n```\n\nFor video or webcam pipelines, the official guides use OpenCV to load frames and then wrap each frame as an `mp.Image`. In practice, make sure the pixel format you pass matches the `image_format` you declare.\n\n## Configuration Notes\n\nThere is no remote service configuration or API key flow. Configuration is local and task-specific.\n\nCommon settings you will see across task guides:\n\n- `base_options`: model path or bytes\n- `running_mode`: `IMAGE`, `VIDEO`, or `LIVE_STREAM`\n- `result_callback`: required for async live-stream usage\n- result limits or thresholds such as `max_results` and `score_threshold`\n- task-specific filters such as category allowlists or denylists\n\nFor `VIDEO` and `LIVE_STREAM`, you must pass timestamps alongside frames. The task guides also note an important execution difference:\n\n- image/video methods block until inference completes\n- live-stream methods return immediately and deliver results through the callback\n\n## Legacy vs Current API\n\nPrefer the Task APIs under `mediapipe.tasks.python`.\n\nThe official MediaPipe Solutions guide says support for the listed legacy solutions ended on **March 1, 2023**, and that the old repository and binaries continue only on an as-is basis. Upgraded replacements include:\n\n- `Hands` -> `HandLandmarker`\n- `Pose` -> `PoseLandmarker`\n- `Face Detection` -> `FaceDetector`\n- `Face Mesh`/`Iris` -> `FaceLandmarker`\n- `Selfie Segmentation` -> image segmentation tasks\n\nIf you find code using `mp.solutions.hands`, `mp.solutions.pose`, or similar, treat it as legacy unless you have a strong compatibility reason to keep it.\n\n## Common Pitfalls\n\n- Missing model file: many task APIs will import correctly but still fail at runtime until you provide a compatible `.task` or `.tflite` asset.\n- Wrong running mode: `detect()`, `detect_for_video()`, and `detect_async()` are mode-specific. Match the method to the mode used when creating the task.\n- Missing timestamps: `VIDEO` and `LIVE_STREAM` calls require frame timestamps.\n- Dropped live frames: the task guides note that live-stream tasks can ignore new input frames when the task is still busy processing the previous one.\n- Platform mismatch: the PyPI package does not publish wheels for every Python/OS/architecture combination. Check the wheel list before assuming install problems are user error.\n- Legacy examples: many blog posts still use `mp.solutions.*`; prefer the current task guides and API reference.\n\n## Version-Sensitive Notes for `0.10.32`\n\n- PyPI lists `0.10.32` as the current release, uploaded on `2026-01-22`.\n- GitHub releases list `MediaPipe v0.10.32` as the latest release as of `2026-03-12`.\n- The Google AI Edge task guides are still labeled \"MediaPipe Solutions Preview\", and several Python setup/task pages were last updated in 2024 even though the package version is newer.\n\nTreat the docs as the canonical API shape, but verify exact runtime behavior against the package you installed when copying older examples or debugging installation issues.\n\n## Official Links\n\n- Docs root: https://ai.google.dev/edge/mediapipe/\n- Tasks overview: https://ai.google.dev/edge/mediapipe/solutions/tasks\n- Python setup guide: https://ai.google.dev/edge/mediapipe/solutions/setup_python\n- Solutions guide: https://ai.google.dev/edge/mediapipe/solutions/guide\n- Python API reference index: https://ai.google.dev/edge/mediapipe/api/solutions\n- Build Python wheel: https://ai.google.dev/edge/mediapipe/solutions/build_python\n- PyPI: https://pypi.org/project/mediapipe/\n- Releases: https://github.com/google-ai-edge/mediapipe/releases\n"
  },
  {
    "path": "content/meilisearch/docs/search/DOC.md",
    "content": "---\nname: search\ndescription: \"Meilisearch JavaScript SDK coding guidelines for full-text search and indexing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.53.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"meilisearch,search,full-text,indexing,instant\"\n---\n\n# Meilisearch JavaScript SDK Coding Guidelines\n\nYou are a Meilisearch API coding expert. Help me with writing code using the Meilisearch API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://meilisearch.github.io/meilisearch-js/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Meilisearch JavaScript SDK to call Meilisearch, which is the standard library for all Meilisearch API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Meilisearch JavaScript SDK\n- **NPM Package:** `meilisearch`\n- **Legacy Libraries**: Other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install meilisearch`\n\n**APIs and Usage:**\n\n- **Correct:** `import { MeiliSearch } from 'meilisearch'`\n- **Correct:** `const client = new MeiliSearch({ host, apiKey })`\n- **Correct:** `await client.index('indexName').search('query')`\n- **Correct:** `await client.index('indexName').addDocuments(documents)`\n- **Incorrect:** `MeilisearchClient` or `MeiliSearchAPI`\n- **Incorrect:** Legacy v0.x packages\n\n## Installation\n\n```bash\nnpm install meilisearch\n```\n\nFor browser environments, you can use a CDN:\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/meilisearch@latest/dist/bundles/meilisearch.umd.js\"></script>\n```\n\n## Initialization\n\nThe `meilisearch` library requires creating a `MeiliSearch` instance for all API calls.\n\n### Basic Initialization\n\n```javascript\nimport { MeiliSearch } from 'meilisearch';\n\nconst client = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: 'masterKey',\n});\n```\n\n### Using Environment Variables\n\nFor production applications, always use environment variables to store API keys:\n\n```javascript\nimport { MeiliSearch } from 'meilisearch';\n\nconst client = new MeiliSearch({\n  host: process.env.MEILISEARCH_HOST || 'http://127.0.0.1:7700',\n  apiKey: process.env.MEILISEARCH_API_KEY,\n});\n```\n\n### CommonJS Import\n\n```javascript\nconst { MeiliSearch } = require('meilisearch');\n\nconst client = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: 'masterKey',\n});\n```\n\n### Browser Initialization\n\n```javascript\nconst client = new window.MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: 'searchOnlyApiKey', // Use search-only key for frontend\n});\n```\n\n## API Keys and Security\n\nMeilisearch uses API keys for authentication. There are different types of API keys for different use cases.\n\n### Master Key\n\nThe master key has full access to all endpoints and should only be used server-side:\n\n```javascript\nconst adminClient = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: process.env.MEILISEARCH_MASTER_KEY,\n});\n```\n\n### Default Search API Key\n\nUse the search-only key for frontend applications to limit access:\n\n```javascript\nconst searchClient = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: process.env.MEILISEARCH_SEARCH_KEY,\n});\n```\n\n### Creating Custom API Keys\n\n```javascript\nconst key = await client.createKey({\n  description: 'Search key for products index',\n  actions: ['search'],\n  indexes: ['products'],\n  expiresAt: new Date('2025-12-31'),\n});\n\nconsole.log(key.key); // Use this key in your application\n```\n\n### Getting All API Keys\n\n```javascript\nconst keys = await client.getKeys();\nconsole.log(keys.results);\n```\n\n### Deleting an API Key\n\n```javascript\nawait client.deleteKey('your-key-uid');\n```\n\n## Indexes\n\nIndexes are where your documents are stored and searched.\n\n### Creating an Index\n\n```javascript\nconst index = await client.createIndex('movies', { primaryKey: 'id' });\nconsole.log(index.uid); // 'movies'\n```\n\n### Getting an Index\n\n```javascript\nconst index = client.index('movies');\n```\n\n### Listing All Indexes\n\n```javascript\nconst indexes = await client.getIndexes();\nconsole.log(indexes.results);\n```\n\n### Updating an Index\n\n```javascript\nawait client.index('movies').update({ primaryKey: 'movie_id' });\n```\n\n### Deleting an Index\n\n```javascript\nawait client.deleteIndex('movies');\n```\n\n### Getting Index Stats\n\n```javascript\nconst stats = await client.index('movies').getStats();\nconsole.log(stats.numberOfDocuments);\nconsole.log(stats.isIndexing);\n```\n\n## Documents\n\nDocuments are the individual records in your index.\n\n### Adding Documents\n\n```javascript\nconst documents = [\n  { id: 1, title: 'Inception', genre: 'Sci-Fi', year: 2010 },\n  { id: 2, title: 'The Dark Knight', genre: 'Action', year: 2008 },\n  { id: 3, title: 'Interstellar', genre: 'Sci-Fi', year: 2014 },\n];\n\nconst response = await client.index('movies').addDocuments(documents);\nconsole.log(response.taskUid); // Use this to check task status\n```\n\n### Adding Documents with Auto-ID Generation\n\nIf documents don't have an ID, Meilisearch can generate them:\n\n```javascript\nconst documents = [\n  { title: 'Movie without ID', genre: 'Drama' },\n];\n\nawait client.index('movies').addDocuments(documents);\n```\n\n### Adding Documents with Primary Key\n\nSpecify a custom primary key field:\n\n```javascript\nconst documents = [\n  { movie_id: 'mv001', title: 'Inception' },\n  { movie_id: 'mv002', title: 'The Matrix' },\n];\n\nawait client.index('movies').addDocuments(documents, { primaryKey: 'movie_id' });\n```\n\n### Updating Documents\n\nUpdate existing documents (replaces entire document):\n\n```javascript\nconst documents = [\n  { id: 1, title: 'Inception', genre: 'Sci-Fi', year: 2010, rating: 8.8 },\n];\n\nawait client.index('movies').updateDocuments(documents);\n```\n\n### Getting a Document\n\n```javascript\nconst document = await client.index('movies').getDocument(1);\nconsole.log(document.title);\n```\n\n### Getting Documents with Pagination\n\n```javascript\nconst documents = await client.index('movies').getDocuments({\n  offset: 0,\n  limit: 20,\n});\n\nconsole.log(documents.results);\n```\n\n### Getting Documents with Field Selection\n\n```javascript\nconst documents = await client.index('movies').getDocuments({\n  fields: ['id', 'title', 'year'],\n  limit: 10,\n});\n```\n\n### Deleting a Single Document\n\n```javascript\nawait client.index('movies').deleteDocument(1);\n```\n\n### Deleting Multiple Documents\n\n```javascript\nawait client.index('movies').deleteDocuments([1, 2, 3]);\n```\n\n### Deleting Documents by Filter\n\n```javascript\nawait client.index('movies').deleteDocuments({\n  filter: 'year < 2000',\n});\n```\n\n### Deleting All Documents\n\n```javascript\nawait client.index('movies').deleteAllDocuments();\n```\n\n## Search\n\nThe core functionality of Meilisearch is search.\n\n### Basic Search\n\n```javascript\nconst results = await client.index('movies').search('inception');\n\nconsole.log(results.hits); // Array of matching documents\nconsole.log(results.query); // The search query\nconsole.log(results.processingTimeMs); // Search duration\nconsole.log(results.estimatedTotalHits); // Number of matches\n```\n\n### Search with Options\n\n```javascript\nconst results = await client.index('movies').search('batman', {\n  limit: 10,\n  offset: 0,\n  attributesToRetrieve: ['id', 'title', 'year'],\n  attributesToHighlight: ['title'],\n  attributesToCrop: ['overview'],\n  cropLength: 20,\n  filter: 'year > 2000',\n  sort: ['year:desc'],\n  matchingStrategy: 'last',\n});\n\nconsole.log(results.hits);\n```\n\n### Filtering\n\nConfigure filterable attributes first:\n\n```javascript\nawait client.index('movies').updateFilterableAttributes([\n  'genre',\n  'year',\n  'rating',\n]);\n```\n\nThen use filters in search:\n\n```javascript\n// Exact match\nconst sciFi = await client.index('movies').search('space', {\n  filter: 'genre = \"Sci-Fi\"',\n});\n\n// Numeric comparison\nconst recent = await client.index('movies').search('', {\n  filter: 'year > 2015',\n});\n\n// Range filter\nconst highRated = await client.index('movies').search('', {\n  filter: 'rating 8 TO 10',\n});\n\n// Multiple filters with AND\nconst filtered = await client.index('movies').search('', {\n  filter: 'genre = \"Action\" AND year > 2010',\n});\n\n// Multiple filters with OR\nconst multiGenre = await client.index('movies').search('', {\n  filter: 'genre = \"Action\" OR genre = \"Sci-Fi\"',\n});\n\n// Array syntax for AND\nconst arrayFilter = await client.index('movies').search('', {\n  filter: [\n    'genre = \"Action\"',\n    'year > 2010',\n  ],\n});\n\n// Nested array syntax for OR within AND\nconst complexFilter = await client.index('movies').search('', {\n  filter: [\n    ['genre = \"Action\"', 'genre = \"Sci-Fi\"'],\n    'year > 2010',\n  ],\n});\n```\n\n### Sorting\n\nConfigure sortable attributes first:\n\n```javascript\nawait client.index('movies').updateSortableAttributes([\n  'year',\n  'rating',\n  'title',\n]);\n```\n\nThen use sort in search:\n\n```javascript\n// Sort by single attribute\nconst byYear = await client.index('movies').search('', {\n  sort: ['year:desc'],\n});\n\n// Sort by multiple attributes\nconst multiSort = await client.index('movies').search('', {\n  sort: ['rating:desc', 'year:desc'],\n});\n```\n\n### Pagination\n\n```javascript\nconst page1 = await client.index('movies').search('action', {\n  limit: 20,\n  offset: 0,\n});\n\nconst page2 = await client.index('movies').search('action', {\n  limit: 20,\n  offset: 20,\n});\n\n// Using hitsPerPage and page (alternative pagination)\nconst results = await client.index('movies').search('action', {\n  hitsPerPage: 20,\n  page: 1,\n});\n```\n\n### Faceted Search\n\nConfigure facets:\n\n```javascript\nawait client.index('movies').updateFilterableAttributes([\n  'genre',\n  'year',\n  'director',\n]);\n```\n\nSearch with facets:\n\n```javascript\nconst results = await client.index('movies').search('classic', {\n  facets: ['genre', 'year', 'director'],\n});\n\nconsole.log(results.facetDistribution);\n// {\n//   genre: { 'Sci-Fi': 42, 'Action': 38, 'Drama': 25 },\n//   year: { '2020': 10, '2019': 15, '2018': 12 },\n//   director: { 'Nolan': 5, 'Spielberg': 8 }\n// }\n\nconsole.log(results.facetStats);\n// { year: { min: 1980, max: 2024 } }\n```\n\n### Facet Search\n\nSearch within facet values:\n\n```javascript\nconst results = await client.index('movies').searchForFacetValues({\n  facetName: 'genre',\n  facetQuery: 'sci',\n  filter: 'year > 2010',\n});\n\nconsole.log(results.facetHits);\n// [{ value: 'Sci-Fi', count: 42 }]\n```\n\n### Highlighting and Cropping\n\n```javascript\nconst results = await client.index('movies').search('space exploration', {\n  attributesToHighlight: ['title', 'overview'],\n  attributesToCrop: ['overview'],\n  cropLength: 30,\n  cropMarker: '...',\n  highlightPreTag: '<mark>',\n  highlightPostTag: '</mark>',\n});\n\nconsole.log(results.hits[0]._formatted.title);\n// \"The <mark>Space</mark> Between Us\"\nconsole.log(results.hits[0]._formatted.overview);\n// \"...astronaut on a mission of <mark>space</mark> <mark>exploration</mark>...\"\n```\n\n### Geosearch\n\nAdd documents with `_geo` field:\n\n```javascript\nconst restaurants = [\n  {\n    id: 1,\n    name: \"Joe's Pizza\",\n    _geo: { lat: 40.7484, lng: -73.9857 },\n  },\n  {\n    id: 2,\n    name: \"Pasta Palace\",\n    _geo: { lat: 40.7589, lng: -73.9851 },\n  },\n];\n\nawait client.index('restaurants').addDocuments(restaurants);\n```\n\nConfigure `_geo` as filterable:\n\n```javascript\nawait client.index('restaurants').updateFilterableAttributes(['_geo']);\n```\n\nSearch by geo radius:\n\n```javascript\nconst results = await client.index('restaurants').search('pizza', {\n  filter: '_geoRadius(40.7484, -73.9857, 5000)', // 5km radius\n});\n```\n\nSearch by geo bounding box:\n\n```javascript\nconst results = await client.index('restaurants').search('', {\n  filter: '_geoBoundingBox([40.7590, -73.9850], [40.7480, -73.9860])',\n});\n```\n\nSort by distance from a point:\n\n```javascript\nawait client.index('restaurants').updateSortableAttributes(['_geo']);\n\nconst results = await client.index('restaurants').search('', {\n  sort: ['_geoPoint(40.7484, -73.9857):asc'],\n});\n\nconsole.log(results.hits[0]._geoDistance); // Distance in meters\n```\n\n## Multi-Search\n\nPerform multiple searches in a single request:\n\n```javascript\nconst results = await client.multiSearch({\n  queries: [\n    {\n      indexUid: 'movies',\n      q: 'batman',\n      filter: 'year > 2000',\n    },\n    {\n      indexUid: 'movies',\n      q: 'superman',\n      limit: 5,\n    },\n    {\n      indexUid: 'books',\n      q: 'javascript',\n    },\n  ],\n});\n\nconsole.log(results.results[0].hits); // Batman search results\nconsole.log(results.results[1].hits); // Superman search results\nconsole.log(results.results[2].hits); // JavaScript books results\n```\n\n### Federated Search\n\nMerge results from multiple queries into a single list:\n\n```javascript\nconst results = await client.multiSearch({\n  federation: {\n    limit: 20,\n    offset: 0,\n  },\n  queries: [\n    {\n      indexUid: 'movies',\n      q: 'batman',\n    },\n    {\n      indexUid: 'comics',\n      q: 'batman',\n    },\n    {\n      indexUid: 'books',\n      q: 'batman',\n    },\n  ],\n});\n\nconsole.log(results.hits); // Merged results from all three indexes\nconsole.log(results.facetsByIndex); // Facets grouped by index\n```\n\n## Index Settings\n\nSettings control how Meilisearch processes and ranks search results.\n\n### Get All Settings\n\n```javascript\nconst settings = await client.index('movies').getSettings();\nconsole.log(settings);\n```\n\n### Update All Settings\n\n```javascript\nawait client.index('movies').updateSettings({\n  searchableAttributes: ['title', 'overview', 'genre'],\n  filterableAttributes: ['genre', 'year', 'rating'],\n  sortableAttributes: ['year', 'rating'],\n  rankingRules: [\n    'words',\n    'typo',\n    'proximity',\n    'attribute',\n    'sort',\n    'exactness',\n  ],\n  stopWords: ['the', 'a', 'an'],\n  synonyms: {\n    'wolverine': ['logan', 'weapon x'],\n    'batman': ['dark knight', 'caped crusader'],\n  },\n  distinctAttribute: 'movie_id',\n  typoTolerance: {\n    enabled: true,\n    minWordSizeForTypos: {\n      oneTypo: 5,\n      twoTypos: 9,\n    },\n  },\n  pagination: {\n    maxTotalHits: 1000,\n  },\n});\n```\n\n### Reset All Settings\n\n```javascript\nawait client.index('movies').resetSettings();\n```\n\n### Searchable Attributes\n\nDefines which fields are searchable and their ranking order:\n\n```javascript\nawait client.index('movies').updateSearchableAttributes([\n  'title',\n  'overview',\n  'genre',\n]);\n```\n\nGet searchable attributes:\n\n```javascript\nconst attrs = await client.index('movies').getSearchableAttributes();\n```\n\nReset to default (all attributes):\n\n```javascript\nawait client.index('movies').resetSearchableAttributes();\n```\n\n### Filterable Attributes\n\nDefines which fields can be used in filters and facets:\n\n```javascript\nawait client.index('movies').updateFilterableAttributes([\n  'genre',\n  'year',\n  'rating',\n  'director',\n]);\n```\n\n### Sortable Attributes\n\nDefines which fields can be used for sorting:\n\n```javascript\nawait client.index('movies').updateSortableAttributes([\n  'year',\n  'rating',\n  'title',\n]);\n```\n\n### Ranking Rules\n\nControls how results are ranked:\n\n```javascript\nawait client.index('movies').updateRankingRules([\n  'words',\n  'typo',\n  'proximity',\n  'attribute',\n  'sort',\n  'exactness',\n  'rating:desc', // Custom ranking rule\n]);\n```\n\nGet ranking rules:\n\n```javascript\nconst rules = await client.index('movies').getRankingRules();\n```\n\nReset to default:\n\n```javascript\nawait client.index('movies').resetRankingRules();\n```\n\n### Stop Words\n\nWords ignored during search:\n\n```javascript\nawait client.index('movies').updateStopWords([\n  'the',\n  'a',\n  'an',\n  'and',\n  'or',\n  'but',\n]);\n```\n\n### Synonyms\n\nConfigure word equivalences:\n\n```javascript\nawait client.index('movies').updateSynonyms({\n  'wolverine': ['logan', 'weapon x'],\n  'batman': ['dark knight', 'caped crusader'],\n  'sw': ['star wars'],\n});\n```\n\n### Distinct Attribute\n\nReturn only one document per distinct value:\n\n```javascript\nawait client.index('movies').updateDistinctAttribute('movie_id');\n```\n\n### Typo Tolerance\n\nConfigure typo tolerance settings:\n\n```javascript\nawait client.index('movies').updateTypoTolerance({\n  enabled: true,\n  minWordSizeForTypos: {\n    oneTypo: 5,\n    twoTypos: 9,\n  },\n  disableOnWords: ['spiderman', 'batman'],\n  disableOnAttributes: ['title'],\n});\n```\n\nGet typo tolerance settings:\n\n```javascript\nconst settings = await client.index('movies').getTypoTolerance();\n```\n\n### Faceting Settings\n\nConfigure faceting behavior:\n\n```javascript\nawait client.index('movies').updateFaceting({\n  maxValuesPerFacet: 100,\n  sortFacetValuesBy: {\n    '*': 'alpha',\n    'genre': 'count',\n  },\n});\n```\n\n### Pagination Settings\n\nConfigure maximum search results:\n\n```javascript\nawait client.index('movies').updatePagination({\n  maxTotalHits: 1000,\n});\n```\n\n### Displayed Attributes\n\nControl which fields are returned in search results:\n\n```javascript\nawait client.index('movies').updateDisplayedAttributes([\n  'id',\n  'title',\n  'year',\n  'genre',\n  'rating',\n]);\n```\n\n## Tasks\n\nAll operations in Meilisearch are asynchronous and return a task.\n\n### Get Task by UID\n\n```javascript\nconst task = await client.getTask(12);\n\nconsole.log(task.status); // 'enqueued', 'processing', 'succeeded', 'failed', 'canceled'\nconsole.log(task.type); // 'documentAdditionOrUpdate', 'settingsUpdate', etc.\nconsole.log(task.details);\nconsole.log(task.duration);\n```\n\n### Get Tasks\n\n```javascript\nconst tasks = await client.getTasks({\n  limit: 20,\n  from: 0,\n});\n\nconsole.log(tasks.results);\n```\n\n### Get Tasks with Filters\n\n```javascript\nconst tasks = await client.getTasks({\n  indexUids: ['movies'],\n  statuses: ['succeeded', 'failed'],\n  types: ['documentAdditionOrUpdate'],\n  limit: 50,\n});\n```\n\n### Wait for Task\n\n```javascript\nconst response = await client.index('movies').addDocuments(documents);\n\n// Wait for the task to complete\nconst task = await client.waitForTask(response.taskUid);\n\nif (task.status === 'succeeded') {\n  console.log('Documents added successfully');\n} else if (task.status === 'failed') {\n  console.error('Task failed:', task.error);\n}\n```\n\n### Wait for Multiple Tasks\n\n```javascript\nawait client.waitForTasks([taskUid1, taskUid2, taskUid3]);\n```\n\n### Cancel Tasks\n\n```javascript\nawait client.cancelTasks({\n  uids: [12, 13, 14],\n});\n\n// Cancel by filter\nawait client.cancelTasks({\n  statuses: ['enqueued'],\n  indexUids: ['movies'],\n});\n```\n\n### Delete Tasks\n\n```javascript\nawait client.deleteTasks({\n  uids: [12, 13, 14],\n});\n\n// Delete by filter\nawait client.deleteTasks({\n  statuses: ['succeeded', 'failed'],\n  beforeEnqueuedAt: new Date('2024-01-01'),\n});\n```\n\n## Tenant Tokens\n\nTenant tokens provide secure, scoped access for multi-tenant applications.\n\n### Generating Tenant Tokens\n\n```javascript\nimport { MeiliSearch } from 'meilisearch';\n\n// Server-side code\nconst client = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: 'YOUR_MASTER_KEY',\n});\n\nconst apiKey = await client.getKey('YOUR_API_KEY_UID');\n\nconst searchRules = {\n  'patient_medical_records': {\n    filter: 'user_id = 42',\n  },\n};\n\nconst token = await client.generateTenantToken(\n  apiKey.uid,\n  searchRules,\n  {\n    apiKey: apiKey.key,\n    expiresAt: new Date('2025-12-31'),\n  }\n);\n\n// Send this token to the frontend\n```\n\n### Using Tenant Tokens\n\n```javascript\n// Frontend code\nconst frontendClient = new MeiliSearch({\n  host: 'http://127.0.0.1:7700',\n  apiKey: tenantToken, // Token from backend\n});\n\nconst results = await frontendClient.index('patient_medical_records').search('blood test');\n// Only returns documents where user_id = 42\n```\n\n### Multi-Index Tenant Tokens\n\n```javascript\nconst searchRules = {\n  'products': {\n    filter: 'company_id = 123',\n  },\n  'orders': {\n    filter: 'company_id = 123',\n  },\n  'invoices': {\n    filter: 'company_id = 123',\n  },\n};\n\nconst token = await client.generateTenantToken(\n  apiKeyUid,\n  searchRules,\n  { apiKey: apiKey.key }\n);\n```\n\n### Wildcard Tenant Tokens\n\n```javascript\nconst searchRules = {\n  '*': {\n    filter: 'tenant_id = 456',\n  },\n};\n\nconst token = await client.generateTenantToken(\n  apiKeyUid,\n  searchRules,\n  { apiKey: apiKey.key }\n);\n```\n\n## Health and Stats\n\n### Check Health\n\n```javascript\nconst health = await client.health();\nconsole.log(health.status); // 'available'\n```\n\n### Get Version\n\n```javascript\nconst version = await client.getVersion();\nconsole.log(version.pkgVersion); // '1.12.0'\n```\n\n### Get Database Stats\n\n```javascript\nconst stats = await client.getStats();\nconsole.log(stats.databaseSize);\nconsole.log(stats.lastUpdate);\nconsole.log(stats.indexes);\n```\n\n## Error Handling\n\n```javascript\ntry {\n  const results = await client.index('movies').search('batman');\n  console.log(results.hits);\n} catch (error) {\n  if (error.message.includes('index_not_found')) {\n    console.error('Index does not exist');\n  } else if (error.message.includes('invalid_api_key')) {\n    console.error('Invalid API key');\n  } else {\n    console.error('Search error:', error.message);\n  }\n}\n```\n\n### Handling Task Failures\n\n```javascript\nconst response = await client.index('movies').addDocuments(documents);\nconst task = await client.waitForTask(response.taskUid);\n\nif (task.status === 'failed') {\n  console.error('Error code:', task.error.code);\n  console.error('Error type:', task.error.type);\n  console.error('Error message:', task.error.message);\n  console.error('Error link:', task.error.link);\n}\n```\n\n## Advanced Examples\n\n### Full-Text Search with Filters and Sorting\n\n```javascript\nawait client.index('movies').updateSettings({\n  searchableAttributes: ['title', 'overview', 'genre'],\n  filterableAttributes: ['genre', 'year', 'rating', 'director'],\n  sortableAttributes: ['year', 'rating'],\n  rankingRules: ['words', 'typo', 'proximity', 'attribute', 'sort', 'exactness'],\n});\n\nconst results = await client.index('movies').search('space adventure', {\n  filter: [\n    ['genre = \"Sci-Fi\"', 'genre = \"Adventure\"'],\n    'year > 2010',\n    'rating >= 7.0',\n  ],\n  sort: ['rating:desc', 'year:desc'],\n  attributesToRetrieve: ['title', 'year', 'rating', 'overview'],\n  attributesToHighlight: ['title', 'overview'],\n  attributesToCrop: ['overview'],\n  cropLength: 50,\n  limit: 20,\n});\n```\n\n### E-commerce Product Search\n\n```javascript\nconst products = [\n  {\n    id: 1,\n    name: 'Laptop Pro 15',\n    category: 'Electronics',\n    brand: 'TechCorp',\n    price: 1299.99,\n    rating: 4.5,\n    inStock: true,\n  },\n  {\n    id: 2,\n    name: 'Wireless Mouse',\n    category: 'Electronics',\n    brand: 'TechCorp',\n    price: 29.99,\n    rating: 4.8,\n    inStock: true,\n  },\n];\n\nawait client.index('products').addDocuments(products);\n\nawait client.index('products').updateSettings({\n  filterableAttributes: ['category', 'brand', 'price', 'rating', 'inStock'],\n  sortableAttributes: ['price', 'rating'],\n  rankingRules: ['words', 'typo', 'proximity', 'attribute', 'sort', 'exactness'],\n});\n\nconst results = await client.index('products').search('laptop', {\n  filter: [\n    'category = \"Electronics\"',\n    'inStock = true',\n    'price 0 TO 1500',\n  ],\n  sort: ['rating:desc'],\n  facets: ['brand', 'category'],\n  limit: 20,\n});\n```\n\n### Location-Based Restaurant Search\n\n```javascript\nconst restaurants = [\n  {\n    id: 1,\n    name: 'Italian Bistro',\n    cuisine: 'Italian',\n    rating: 4.5,\n    priceRange: '$$',\n    _geo: { lat: 40.7589, lng: -73.9851 },\n  },\n  {\n    id: 2,\n    name: 'Sushi Palace',\n    cuisine: 'Japanese',\n    rating: 4.8,\n    priceRange: '$$$',\n    _geo: { lat: 40.7484, lng: -73.9857 },\n  },\n];\n\nawait client.index('restaurants').addDocuments(restaurants);\n\nawait client.index('restaurants').updateSettings({\n  filterableAttributes: ['cuisine', 'rating', 'priceRange', '_geo'],\n  sortableAttributes: ['rating', '_geo'],\n});\n\nconst results = await client.index('restaurants').search('', {\n  filter: [\n    '_geoRadius(40.7580, -73.9855, 2000)', // 2km radius\n    'rating >= 4.0',\n  ],\n  sort: ['_geoPoint(40.7580, -73.9855):asc'],\n  limit: 10,\n});\n\nresults.hits.forEach(hit => {\n  console.log(`${hit.name} - ${hit._geoDistance}m away`);\n});\n```\n\n### Real-Time Search with Autocomplete\n\n```javascript\nlet timeoutId;\n\nfunction handleSearchInput(query) {\n  clearTimeout(timeoutId);\n\n  timeoutId = setTimeout(async () => {\n    const results = await client.index('movies').search(query, {\n      limit: 5,\n      attributesToRetrieve: ['id', 'title', 'year'],\n      attributesToHighlight: ['title'],\n    });\n\n    displayResults(results.hits);\n  }, 300); // Debounce for 300ms\n}\n```\n\n### Bulk Document Operations\n\n```javascript\n// Process large datasets in batches\nconst batchSize = 1000;\nconst allDocuments = [...]; // Your large dataset\n\nfor (let i = 0; i < allDocuments.length; i += batchSize) {\n  const batch = allDocuments.slice(i, i + batchSize);\n  const response = await client.index('movies').addDocuments(batch);\n  await client.waitForTask(response.taskUid);\n  console.log(`Processed ${i + batch.length} documents`);\n}\n```\n\n### Search with Custom Ranking\n\n```javascript\nawait client.index('movies').updateSettings({\n  rankingRules: [\n    'words',\n    'typo',\n    'proximity',\n    'attribute',\n    'sort',\n    'exactness',\n    'rating:desc', // Boost higher-rated content\n    'year:desc',   // Prefer newer content\n  ],\n});\n\nconst results = await client.index('movies').search('action');\n```\n\n## Useful Links\n\n- Official Documentation: https://www.meilisearch.com/docs\n- JavaScript SDK Documentation: https://meilisearch.github.io/meilisearch-js/\n- API Reference: https://www.meilisearch.com/docs/reference/api/overview\n- GitHub Repository: https://github.com/meilisearch/meilisearch-js\n- Cloud Hosting: https://www.meilisearch.com/cloud\n"
  },
  {
    "path": "content/mem0ai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"mem0ai package guide for Python with local Memory, hosted MemoryClient, and v1.0.5 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mem0ai,mem0,python,memory,rag,agents,llm\"\n---\n\n# mem0ai Python Package Guide\n\n## What It Is\n\n`mem0ai` adds long-term memory to AI applications. In Python, the package has two main surfaces:\n\n- `Memory` / `AsyncMemory` for self-managed open-source memory pipelines\n- `MemoryClient` / `AsyncMemoryClient` for the hosted Mem0 Platform API\n\nPick the surface first. Most integration mistakes come from mixing the local `Memory` setup flow with the hosted `MemoryClient` flow.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.0.5`.\n- Official PyPI shows `mem0ai 1.0.5` published on `2026-03-03`.\n- The current docs root is a v1 docs site. Older v0 examples and blog posts may use different constructors and payload shapes.\n- In the current maintainer docs and README, self-managed usage starts with `Memory.from_config(...)` or `AsyncMemory.from_config(...)`.\n- Hosted usage starts with `MemoryClient(...)` or `AsyncMemoryClient(...)`, not the local `Memory(...)` surface.\n- Graph memory is optional. Install the `graph` extra if you need it.\n\n## Install\n\nPin the package when you need reproducible behavior:\n\n```bash\npython -m pip install \"mem0ai==1.0.5\"\n```\n\nIf you plan to use graph memory:\n\n```bash\npython -m pip install \"mem0ai[graph]==1.0.5\"\n```\n\n## Golden Rules\n\n- Use `MemoryClient` for Mem0 Platform and `Memory` for self-managed memory. Do not treat them as interchangeable constructors.\n- Keep API keys in environment variables, not source code.\n- Pass stable scope identifiers such as `user_id`, `agent_id`, or `run_id`; retrieval only works if writes and reads use the same scope.\n- For local memory, confirm the provider config for your embedder, vector store, and LLM before copying an example from another backend.\n\n## Hosted Setup With `MemoryClient`\n\nUse the hosted client when your application should talk to Mem0's managed API.\n\n```bash\nexport MEM0_API_KEY=\"m0-...\"\n```\n\n```python\nimport os\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=os.environ[\"MEM0_API_KEY\"])\n\nmessages = [\n    {\"role\": \"user\", \"content\": \"I prefer aisle seats on long flights.\"},\n    {\"role\": \"assistant\", \"content\": \"I'll remember that preference.\"},\n]\n\nclient.add(messages, user_id=\"alice\")\n\nresults = client.search(\n    \"What seating preference does Alice have?\",\n    user_id=\"alice\",\n)\n\nprint(results)\n```\n\nUse the async client in async services:\n\n```python\nimport asyncio\nimport os\n\nfrom mem0 import AsyncMemoryClient\n\nasync def main() -> None:\n    client = AsyncMemoryClient(api_key=os.environ[\"MEM0_API_KEY\"])\n    await client.add(\n        [{\"role\": \"user\", \"content\": \"My favorite editor is Neovim.\"}],\n        user_id=\"alice\",\n    )\n    results = await client.search(\"What editor does Alice use?\", user_id=\"alice\")\n    print(results)\n\nasyncio.run(main())\n```\n\n## Local Open-Source Setup With `Memory`\n\nUse the open-source surface when you want to choose and operate the vector store, embedder, and LLM yourself.\n\nThe official quickstart shows a config-driven setup. Provider-specific auth belongs inside that config, usually from environment variables such as `OPENAI_API_KEY`.\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\n```python\nimport os\n\nfrom mem0 import Memory\n\nconfig = {\n    \"vector_store\": {\n        \"provider\": \"qdrant\",\n        \"config\": {\n            \"host\": \"localhost\",\n            \"port\": 6333,\n        },\n    },\n    \"llm\": {\n        \"provider\": \"openai\",\n        \"config\": {\n            \"api_key\": os.environ[\"OPENAI_API_KEY\"],\n            \"model\": \"gpt-4.1-mini\",\n        },\n    },\n    \"embedder\": {\n        \"provider\": \"openai\",\n        \"config\": {\n            \"api_key\": os.environ[\"OPENAI_API_KEY\"],\n            \"model\": \"text-embedding-3-small\",\n        },\n    },\n}\n\nmemory = Memory.from_config(config_dict=config)\n\nmemory.add(\"Alice prefers aisle seats on long flights.\", user_id=\"alice\")\n\nresults = memory.search(\n    \"What seating preference does Alice have?\",\n    user_id=\"alice\",\n)\n\nprint(results)\n```\n\nPractical setup notes:\n\n- The sample above expects a reachable Qdrant instance.\n- Switching providers means changing the nested config shape, not just the model name.\n- Use the provider pages under the official docs root before swapping to OpenAI-compatible, Anthropic, Azure OpenAI, or other backends.\n\n## Core Operations\n\nThe current v1 Python API reference documents these day-to-day operations:\n\n- `add(...)` to write memory from text or chat messages\n- `search(...)` to retrieve semantically relevant memories for a scope\n- `get_all(...)` to list stored memories for a scope\n- `update(...)` and `delete(...)` to maintain specific memories\n- `delete_all(...)`, `history(...)`, and `reset()` for cleanup and debugging workflows\n\nFor agent systems, the common loop is:\n\n1. Add important user or conversation facts with a stable `user_id`.\n2. Search memories at the start of the next interaction.\n3. Update or delete memories when a preference changes instead of blindly appending duplicates.\n\n## Config And Auth Checklist\n\nHosted Mem0 Platform:\n\n- `MEM0_API_KEY` authenticates `MemoryClient` and `AsyncMemoryClient`.\n\nSelf-managed open-source usage:\n\n- Provider credentials such as `OPENAI_API_KEY` live inside the config for the chosen embedder or LLM provider.\n- The vector store backend may also need its own host, port, URL, or token settings.\n\nShared advice:\n\n- Keep secrets in environment variables or a secret manager.\n- Reuse one configured client or memory instance per process or request scope when possible.\n- Keep your scope IDs explicit. `user_id=\"alice\"` and `user_id=\"Alice\"` are different scopes.\n\n## Common Pitfalls\n\n- Mixing the hosted and local setup models. `MemoryClient(api_key=...)` is for Mem0 Platform; `Memory.from_config(...)` is for self-managed memory.\n- Copying older pre-v1 examples that instantiate different classes or skip the config factory.\n- Forgetting backend prerequisites for local mode. A vector database like Qdrant must be running and reachable if your config points to it.\n- Writing memories under one scope and searching another. Missing or inconsistent `user_id` values make retrieval look broken.\n- Installing plain `mem0ai` and then enabling graph features without the `graph` extra.\n\n## Official Sources\n\n- Docs root: `https://docs.mem0.ai/`\n- Open-source Python quickstart: `https://docs.mem0.ai/open-source/python-quickstart`\n- Memory v1 quickstart: `https://docs.mem0.ai/v1.0/components/memory/quickstart`\n- Memory API reference: `https://docs.mem0.ai/v1.0/components/memory/api-reference/python/add`\n- Migration guide: `https://docs.mem0.ai/migration-guide`\n- PyPI package page: `https://pypi.org/project/mem0ai/`\n- Maintainer repository: `https://github.com/mem0ai/mem0`\n"
  },
  {
    "path": "content/metaflow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Metaflow package guide for Python flows, local iteration, remote execution, and production orchestration\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.19.20\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"metaflow,python,ml,workflow,orchestration,batch,kubernetes\"\n---\n\n# Metaflow Python Package Guide\n\n## Golden Rule\n\nUse Metaflow's own flow model and CLI instead of wrapping it in an unrelated job runner. A Metaflow program is a `FlowSpec` subclass with `@step` methods, run with commands like `python myflow.py run`.\n\nAs of March 12, 2026, the version used here `2.19.20` matches the current PyPI release.\n\n## Install\n\nUse a virtual environment or project manager and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"metaflow==2.19.20\"\n```\n\nAlternatives supported by upstream:\n\n```bash\nconda install -c conda-forge metaflow\nuv add metaflow\n```\n\nMetaflow can run locally without any cloud setup. Remote compute, shared metadata, and production scheduling require additional infrastructure configuration.\n\n## First Flow\n\nMetaflow flows are Python classes inheriting from `FlowSpec`. Each workflow step is a method decorated with `@step`, and transitions are declared with `self.next(...)`.\n\n```python\nfrom metaflow import FlowSpec, Parameter, current, step\n\nclass HelloFlow(FlowSpec):\n    name = Parameter(\"name\", default=\"world\", help=\"Who to greet\")\n\n    @step\n    def start(self):\n        self.message = f\"hello, {self.name}\"\n        self.next(self.end)\n\n    @step\n    def end(self):\n        print(self.message)\n        print(current.pathspec)\n\nif __name__ == \"__main__\":\n    HelloFlow()\n```\n\nCommon local commands:\n\n```bash\npython hello_flow.py show\npython hello_flow.py run\npython hello_flow.py run --name metaflow\npython hello_flow.py resume\n```\n\nRules that matter:\n\n- Every flow needs a `start` step and an `end` step.\n- `self.next(...)` should be the last statement in every non-terminal step.\n- Values assigned to `self.<name>` become artifacts available in downstream steps.\n\n## Parameters, Files, And Branching\n\nUse `Parameter` for CLI-provided inputs and `IncludeFile` when the input should be read from a local file and stored as an artifact.\n\n```python\nfrom metaflow import FlowSpec, IncludeFile, Parameter, step\n\nclass TrainFlow(FlowSpec):\n    sample = Parameter(\"sample\", default=100, type=int)\n    config_text = IncludeFile(\"config\", default=\"config.json\")\n\n    @step\n    def start(self):\n        self.rows = list(range(self.sample))\n        self.next(self.end)\n\n    @step\n    def end(self):\n        print(len(self.rows), self.config_text[:40])\n\nif __name__ == \"__main__\":\n    TrainFlow()\n```\n\nUseful flow patterns from the API:\n\n- Straight line: `self.next(self.train)`\n- Static fan-out: `self.next(self.a, self.b)`\n- Foreach: `self.next(self.worker, foreach=\"items\")`\n- Conditional routing: `self.next({\"small\": self.fast, \"large\": self.slow}, condition=\"route\")`\n\n## Dependencies And Environments\n\nFor step-specific dependencies, use `@pypi` or `@conda`. Upstream documents them as interchangeable patterns for isolated execution environments; in practice, choose one approach per step.\n\n```python\nfrom metaflow import FlowSpec, pypi, step\n\nclass PandasFlow(FlowSpec):\n    @pypi(\n        python=\"3.11.9\",\n        packages={\n            \"pandas\": \"2.2.3\",\n            \"pyarrow\": \"18.1.0\",\n        },\n    )\n    @step\n    def start(self):\n        import pandas as pd\n\n        self.rows = len(pd.DataFrame({\"x\": [1, 2, 3]}))\n        self.next(self.end)\n\n    @step\n    def end(self):\n        print(self.rows)\n\nif __name__ == \"__main__\":\n    PandasFlow()\n```\n\nIf your project already uses `uv`, Metaflow supports it directly:\n\n```bash\nuv init myflow\ncd myflow\nuv add metaflow pandas\nuv run flow.py run\nuv run flow.py --environment=uv run\n```\n\nTo avoid repeating the flag:\n\n```bash\nexport METAFLOW_ENVIRONMENT=uv\n```\n\nUse `uv` when you want project-level dependency management. Use `@pypi` or `@conda` when you want Metaflow-managed step environments with stronger reproducibility for remote tasks.\n\n## Working With Data And Run Context\n\nArtifacts are persisted automatically when assigned to `self`. Inside a running step, inspect the active run with `current`.\n\n```python\nfrom metaflow import FlowSpec, current, step\n\nclass ContextFlow(FlowSpec):\n    @step\n    def start(self):\n        self.values = [1, 2, 3]\n        print(current.flow_name, current.run_id, current.step_name)\n        print(current.pathspec)\n        self.next(self.end)\n\n    @step\n    def end(self):\n        print(sum(self.values))\n\nif __name__ == \"__main__\":\n    ContextFlow()\n```\n\n`current` is only available during flow execution. Use it for run IDs, task IDs, retry counts, cards, and project metadata.\n\nFor large datasets already in S3, use Metaflow's S3 utilities instead of pulling everything through ordinary local temp files. For normal step-to-step data, prefer persisted artifacts on `self`.\n\n## Inspect Past Runs\n\nMetaflow ships a client API for querying runs, steps, tasks, artifacts, and tags. The object hierarchy is centered on pathspecs such as `FlowName/12/start/1`.\n\n```python\nfrom metaflow import Flow, Run\n\nflow = Flow(\"HelloFlow\")\nrun = flow.latest_successful_run\nprint(run.pathspec)\nprint(run.tags)\n\nsame_run = Run(run.pathspec)\nprint(same_run.created_at)\n```\n\nImportant behavior:\n\n- Client API visibility is filtered by the current namespace.\n- The client uses the currently configured metadata provider.\n- If you \"cannot find\" runs that exist, check namespace and metadata configuration before assuming the run is missing.\n\n## Run Flows Programmatically\n\nUse `Runner` when another Python process needs to launch or resume flows.\n\n```python\nfrom metaflow import Runner\n\nwith Runner(\"hello_flow.py\", profile=\"default\") as runner:\n    execution = runner.run(name=\"metaflow\")\n    print(execution.run.pathspec)\n```\n\nNotes:\n\n- `Runner` and `ExecutingRun` are designed to be used as context managers.\n- If you do not use a context manager, call `cleanup()` yourself.\n- `NBRunner` is the notebook-oriented equivalent.\n\n## Configuration And Profiles\n\nMetaflow supports structured flow configuration through `Config`, CLI flags, and environment variables.\n\n```python\nimport time\nfrom metaflow import Config, FlowSpec, step, timeout\n\nclass TimeoutConfigFlow(FlowSpec):\n    config = Config(\"config\", default=\"myconfig.json\")\n\n    @timeout(seconds=config.timeout)\n    @step\n    def start(self):\n        time.sleep(1)\n        self.next(self.end)\n\n    @step\n    def end(self):\n        print(self.config)\n\nif __name__ == \"__main__\":\n    TimeoutConfigFlow()\n```\n\nPass config at runtime:\n\n```bash\npython timeout_config.py --config-value config '{\"timeout\": 3}' run\n```\n\nOr through environment variables:\n\n```bash\nexport METAFLOW_FLOW_CONFIG_VALUE='{\"config\": {\"timeout\": 3}}'\npython timeout_config.py run\n```\n\nFor environment-level switching, Metaflow uses configuration profiles. The official APIs and runner docs refer to `METAFLOW_PROFILE` for selecting the active profile, and `Runner(..., profile=\"...\")` when launching programmatically.\n\nMetadata configuration matters for both the client API and orchestration:\n\n- Local mode stores metadata in the local `.metaflow` directory.\n- Remote mode uses Metaflow Service.\n- You can switch providers in Python with `metadata(...)`, but the usual pattern is configuring the provider in a profile and selecting it with `METAFLOW_PROFILE`.\n\n## Secrets And Authentication\n\nDo not pass credentials as ordinary Metaflow parameters if they are real secrets. Use `@secrets` and a secrets manager.\n\n```python\nimport os\nfrom metaflow import FlowSpec, secrets, step\n\nclass SecretFlow(FlowSpec):\n    @secrets(sources=[\"my-db-credentials\"])\n    @step\n    def start(self):\n        print(os.environ[\"DB_USER\"])\n        self.next(self.end)\n\n    @step\n    def end(self):\n        pass\n\nif __name__ == \"__main__\":\n    SecretFlow()\n```\n\nOfficially documented secret backends:\n\n- AWS Secrets Manager via `METAFLOW_DEFAULT_SECRETS_BACKEND_TYPE = \"aws-secrets-manager\"`\n- Azure Key Vault via `METAFLOW_DEFAULT_SECRETS_BACKEND_TYPE = \"az-key-vault\"`\n- GCP Secret Manager with the documented GCP secret path and prefix settings\n\nOperational notes:\n\n- `@secrets` exposes secret values through environment variables for the step.\n- Access control is handled by the cloud identity in the execution environment.\n- For AWS, you can supply a specific IAM role in `@secrets(..., role=\"arn:...\")` when the default role should not read the secret directly.\n- For local prototyping, plain environment variables may still be acceptable until you move to shared or production environments.\n\n## Remote Compute And Production\n\nRemote compute is where Metaflow becomes more than a local workflow helper. Cloud execution is available through decorators like `@batch` and `@kubernetes`, but these features require a deployed Metaflow stack first. Upstream recommends Metaflow Sandbox when you want to try the remote model before setting up infrastructure.\n\nHigh-level AWS model from the official docs:\n\n- Datastore: local directory in local mode, S3 in AWS mode\n- Compute: local processes in local mode, AWS Batch in AWS mode\n- Metadata: local directory or Metaflow Service\n- Scheduling: Step Functions plus EventBridge\n\nFor production deployments, use the CLI or `Deployer` API to create scheduler-managed flows.\n\n## Common Pitfalls\n\n- Forgetting `@step`, `start`, or `end` produces broken flows quickly.\n- Putting logic after `self.next(...)` is wrong; treat it as the end of the step.\n- `spin` is for rapid local step iteration, not for durable runs. It does not persist metadata or artifacts by default, and it does not support remote execution.\n- Client API results depend on namespace and metadata provider. Wrong profile is a common cause of \"missing\" runs.\n- Remote `@batch` and `@kubernetes` execution do not work in a plain local-only setup; deploy the stack first.\n- Do not rely on ad hoc system packages for remote tasks. Declare dependencies explicitly with `@pypi`, `@conda`, or `--environment=uv`.\n- If you launch flows through `Runner` without a context manager, temp files accumulate unless you call `cleanup()`.\n- Keep secrets in a secrets manager for shared or production runs; ordinary parameters and checked-in config files are not appropriate for credentials.\n\n## Version-Sensitive Notes For 2.19.20\n\n- PyPI currently lists `2.19.20`, released on February 26, 2026.\n- The 2.19 line introduced the `spin` command for iterative single-step development.\n- The 2.19.x line also includes recent fixes around dependency packaging and cross-platform PyPI resolution, so avoid copying older blog posts that assume pre-2.19 behavior.\n- If you adopt `uv`, remember that remote execution still requires `--environment=uv` or `METAFLOW_ENVIRONMENT=uv`; local `uv run` alone is not enough for cloud tasks.\n"
  },
  {
    "path": "content/micromatch/docs/micromatch/javascript/DOC.md",
    "content": "---\nname: micromatch\ndescription: \"Micromatch for filtering strings, paths, and object keys with Bash-style glob patterns in JavaScript and Node.js.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"micromatch,glob,matching,paths,nodejs,javascript\"\n---\n\n# Micromatch Guide for JavaScript\n\n## Golden Rule\n\nUse `micromatch` to match strings you already have against glob patterns. It does not walk directories or expand files from disk by itself. First collect candidate paths or keys, then pass that list to `micromatch`.\n\n`micromatch` does not need environment variables, authentication, or client initialization. Import it and call the exported functions directly.\n\n## Install\n\n```bash\nnpm install micromatch@4.0.8\n```\n\nThe published `4.0.8` package metadata declares `node >=8.6`.\n\n## Imports\n\nMicromatch 4.0.8 publishes CommonJS. Use `require()` in CommonJS, or a default import in ESM.\n\n```js\n// CommonJS\nconst micromatch = require('micromatch');\n```\n\n```js\n// ESM\nimport micromatch from 'micromatch';\n```\n\nHelpers are methods on the default export, such as `micromatch.isMatch()`, `micromatch.matcher()`, `micromatch.makeRe()`, and `micromatch.matchKeys()`.\n\n## Common Workflows\n\n### Filter a list of paths\n\nPass an array of candidate strings and one or more glob patterns. Negated patterns are supported in the pattern list.\n\n```js\nimport micromatch from 'micromatch';\n\nconst files = [\n  'src/index.js',\n  'src/app.test.js',\n  'src/lib/util.js',\n  'README.md',\n];\n\nconst matches = micromatch(files, [\n  'src/**/*.js',\n  '!src/**/*.test.js',\n]);\n\nconsole.log(matches);\n// ['src/index.js', 'src/lib/util.js']\n```\n\nUse `ignore` when you want exclusions to live in options instead of the main pattern list:\n\n```js\nconst matches = micromatch(files, 'src/**/*.js', {\n  ignore: ['**/*.test.js'],\n});\n```\n\n### Check one string or path\n\nUse `isMatch()` when you want a boolean for a single string.\n\n```js\nimport micromatch from 'micromatch';\n\nconsole.log(micromatch.isMatch('src/index.js', '**/*.js'));\n// true\n\nconsole.log(micromatch.isMatch('src/index.css', '**/*.js'));\n// false\n```\n\nUse `contains()` when the pattern may match only part of the string instead of the whole value:\n\n```js\nconsole.log(micromatch.contains('src/components/button.js', 'components/*'));\n// true\n```\n\n### Reuse a compiled matcher\n\n`matcher()` compiles a glob once and returns a predicate function. Use it when you will test many strings against the same pattern.\n\n```js\nimport micromatch from 'micromatch';\n\nconst isSourceFile = micromatch.matcher('src/**/*.{js,ts}', {\n  dot: true,\n});\n\nconst selected = [\n  'src/index.js',\n  'src/.generated/types.ts',\n  'test/index.test.js',\n].filter(isSourceFile);\n\nconsole.log(selected);\n// ['src/index.js', 'src/.generated/types.ts']\n```\n\n### Match object keys\n\n`matchKeys()` filters only the top-level keys of an object.\n\n```js\nimport micromatch from 'micromatch';\n\nconst commands = {\n  'build:app': './scripts/build-app.js',\n  'build:docs': './scripts/build-docs.js',\n  'test:unit': './scripts/test-unit.js',\n};\n\nconst buildCommands = micromatch.matchKeys(commands, 'build:*');\n\nconsole.log(buildCommands);\n// { 'build:app': './scripts/build-app.js', 'build:docs': './scripts/build-docs.js' }\n```\n\n### Create a regular expression or capture segments\n\nUse `makeRe()` when you need a regular expression, and `capture()` when you need the wildcard captures from a matching path.\n\n```js\nimport micromatch from 'micromatch';\n\nconst regex = micromatch.makeRe('src/*.js');\nconsole.log(regex.test('src/index.js'));\n// true\n\nconsole.log(micromatch.capture('src/*/index.js', 'src/utils/index.js'));\n// ['utils']\n```\n\n## Pattern Features\n\nMicromatch supports the usual Bash-style glob features and several extended forms:\n\n- Wildcards: `*.js`, `file-?.txt`\n- Globstars: `src/**/*.js`\n- Negation: `!**/*.test.js`\n- Extglobs: `src/**/!(*.test).js`, `@(api|ui)/**/*.ts`\n- Braces: `src/*.{js,ts}`, `docs/{guide,api}.md`\n- POSIX bracket expressions: `[[:alpha:]][[:digit:]].txt`\n- Regex-style groups: `(foo|bar).js`\n\n```js\nimport micromatch from 'micromatch';\n\nconst entries = [\n  'src/api/index.ts',\n  'src/api/index.test.ts',\n  'src/ui/button.ts',\n];\n\nconst result = micromatch(entries, 'src/**/!(*.test).ts');\n\nconsole.log(result);\n// ['src/api/index.ts', 'src/ui/button.ts']\n```\n\n## Important Options\n\n### Match basenames instead of full paths\n\nBy default, `*.js` does not match `src/app.js` because the pattern has no slash. Set `basename: true` (or the alias `matchBase: true`) to match against the final path segment.\n\n```js\nimport micromatch from 'micromatch';\n\nconst files = ['src/app.js', 'src/app.css'];\n\nconsole.log(micromatch(files, '*.js'));\n// []\n\nconsole.log(micromatch(files, '*.js', { basename: true }));\n// ['src/app.js']\n```\n\n### Include dotfiles\n\nDotfiles are ignored unless the pattern explicitly starts with `.` or you set `dot: true`.\n\n```js\nimport micromatch from 'micromatch';\n\nconst files = ['.config.js', 'index.js'];\n\nconsole.log(micromatch(files, '*.js'));\n// ['index.js']\n\nconsole.log(micromatch(files, '*.js', { dot: true }));\n// ['.config.js', 'index.js']\n```\n\n### Normalize or preserve Windows separators\n\nOn Windows, `posixSlashes` defaults to `true`, so returned matches are normalized to `/`. Set `posixSlashes: false` if your application must keep backslashes in returned values.\n\n### Disable specific glob syntax\n\nUse these options when you need more literal matching behavior:\n\n- `nonegate`: treat a leading `!` as a literal character\n- `noextglob`: disable extglobs like `!(foo)`\n- `noglobstar`: disable `**`\n- `nobrace`: disable brace expansion like `{js,ts}`\n- `nocase`: perform case-insensitive matching\n\n### Control no-match behavior\n\nBy default, no matches returns an empty array. Two options change that behavior:\n\n- `failglob: true` throws when nothing matches\n- `nonull: true` or `nullglob: true` returns the original pattern or patterns when nothing matches\n\n```js\nimport micromatch from 'micromatch';\n\ntry {\n  micromatch(['README.md'], '**/*.js', { failglob: true });\n} catch (err) {\n  console.error(err.message);\n}\n```\n\n## Pitfalls\n\n- Do not use `path.join()` to build glob patterns on Windows. Micromatch reserves backslashes for escaping, so `path.join('foo', '*')` becomes `foo\\\\*`, which matches a literal `*`. Write glob patterns with forward slashes instead.\n- `micromatch()` matches the list you provide; it does not scan the filesystem.\n- `contains()` is looser than `isMatch()`. Use `isMatch()` when the whole string or path should satisfy the glob.\n- `matchKeys()` does not recurse into nested objects.\n- If you need callbacks during matching, `onMatch`, `onIgnore`, and `onResult` are available in options.\n\n## Minimal Example\n\n```js\nimport micromatch from 'micromatch';\n\nconst changedFiles = [\n  'src/index.js',\n  'src/index.test.js',\n  'scripts/release.mjs',\n  '.github/workflows/ci.yml',\n];\n\nconst filesToLint = micromatch(changedFiles, ['**/*.{js,mjs}', '!**/*.test.js'], {\n  dot: true,\n  ignore: ['**/node_modules/**'],\n});\n\nif (filesToLint.length > 0) {\n  console.log('Lint these files:', filesToLint);\n}\n```\n"
  },
  {
    "path": "content/microsoft/docs/onedrive/javascript/DOC.md",
    "content": "---\nname: onedrive\ndescription: \"Microsoft OneDrive API coding guidelines for JavaScript/TypeScript using the official Microsoft Graph SDK\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.7\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"microsoft,onedrive,storage,graph-api,files\"\n---\n\n# Microsoft OneDrive API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a **Microsoft OneDrive API coding expert**. Help me write correct, idiomatic JavaScript/TypeScript that accesses OneDrive files and folders using the official Microsoft Graph SDK.\n\nUse **only official Microsoft sources** for behavior, fields, and constraints. This guide summarizes key patterns for both **Node.js** and **browser** applications.\n\n> Ground truth: Microsoft Graph OneDrive API documentation on learn.microsoft.com.\n\n\n## Golden Rule: Use the Official Microsoft Graph SDK\n\n**ALWAYS use `@microsoft/microsoft-graph-client` version 3.0.7 or later** for OneDrive operations. This is the official Microsoft Graph JavaScript SDK that provides access to OneDrive, SharePoint, and all other Microsoft Graph APIs.\n\n**DO NOT use**:\n- Deprecated `onedrivesdk` package (obsolete)\n- Direct REST calls without the SDK (unless absolutely necessary)\n- Unofficial third-party OneDrive libraries\n\n**Install (Node.js):**\n```bash\nnpm install @microsoft/microsoft-graph-client\nnpm install @azure/identity\nnpm install @microsoft/microsoft-graph-client/authProviders/azureTokenCredentials\n```\n\n**For TypeScript projects, add type definitions:**\n```bash\nnpm install --save-dev @microsoft/microsoft-graph-types\n```\n\n\n## Installation\n\n### Complete Setup for Node.js Applications\n\n```bash\n# Core Microsoft Graph SDK\nnpm install @microsoft/microsoft-graph-client\n\n# Azure authentication library\nnpm install @azure/identity\n\n# Install isomorphic-fetch for Node.js environments\nnpm install isomorphic-fetch\n\n# TypeScript types (optional but recommended)\nnpm install --save-dev @microsoft/microsoft-graph-types\n```\n\n### Browser Applications\n\nFor browser-based applications, you can load the SDK via CDN or bundle it with your application:\n\n```html\n<!-- Microsoft Graph Client -->\n<script src=\"https://cdn.jsdelivr.net/npm/@microsoft/microsoft-graph-client/lib/graph-js-sdk.js\"></script>\n\n<!-- For authentication in browser, use MSAL -->\n<script src=\"https://alcdn.msauth.net/browser/2.32.0/js/msal-browser.min.js\"></script>\n```\n\n\n## Authentication\n\nOneDrive access through Microsoft Graph requires OAuth 2.0 authentication. You need to register an application in Azure Active Directory (Azure AD) to obtain credentials.\n\n### Azure AD App Registration\n\n1. Go to [Azure Portal](https://portal.azure.com) → Azure Active Directory → App registrations\n2. Create a new registration\n3. Note your **Application (client) ID** and **Directory (tenant) ID**\n4. Create a client secret under \"Certificates & secrets\"\n5. Add API permissions: Microsoft Graph → **Files.Read**, **Files.ReadWrite**, **Files.Read.All**, **Files.ReadWrite.All**\n6. Grant admin consent for the permissions\n\n### Required Scopes\n\nCommon OneDrive permission scopes:\n\n```javascript\n// Read-only access to user's files\nconst SCOPES_READONLY = ['https://graph.microsoft.com/Files.Read'];\n\n// Read/write access to user's files\nconst SCOPES_READWRITE = ['https://graph.microsoft.com/Files.ReadWrite'];\n\n// Read all files user can access (including shared)\nconst SCOPES_READ_ALL = ['https://graph.microsoft.com/Files.Read.All'];\n\n// Full access to all files user can access\nconst SCOPES_READWRITE_ALL = ['https://graph.microsoft.com/Files.ReadWrite.All'];\n\n// Application permissions (no user context, requires admin consent)\nconst SCOPES_APP = ['https://graph.microsoft.com/.default'];\n```\n\n\n## Initialization\n\n### Node.js with Client Credentials (Service/Daemon Apps)\n\nFor server-side applications using application permissions:\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';\nimport { ClientSecretCredential } from '@azure/identity';\nimport 'isomorphic-fetch';\n\n// Environment variables\nconst tenantId = process.env.AZURE_TENANT_ID;\nconst clientId = process.env.AZURE_CLIENT_ID;\nconst clientSecret = process.env.AZURE_CLIENT_SECRET;\n\n// Create credential\nconst credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n\n// Create authentication provider\nconst authProvider = new TokenCredentialAuthenticationProvider(credential, {\n  scopes: ['https://graph.microsoft.com/.default']\n});\n\n// Initialize Microsoft Graph client\nconst client = Client.initWithMiddleware({ authProvider });\n\n// Example: List files in user's OneDrive root\nasync function listFiles(userId) {\n  const response = await client\n    .api(`/users/${userId}/drive/root/children`)\n    .get();\n\n  return response.value;\n}\n```\n\n### Node.js with Device Code Flow (Interactive)\n\nFor CLI applications that need user interaction:\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';\nimport { DeviceCodeCredential } from '@azure/identity';\nimport 'isomorphic-fetch';\n\nconst credential = new DeviceCodeCredential({\n  tenantId: process.env.AZURE_TENANT_ID,\n  clientId: process.env.AZURE_CLIENT_ID,\n  userPromptCallback: (info) => {\n    console.log(info.message);\n  }\n});\n\nconst authProvider = new TokenCredentialAuthenticationProvider(credential, {\n  scopes: ['Files.ReadWrite', 'Files.Read.All']\n});\n\nconst client = Client.initWithMiddleware({ authProvider });\n```\n\n### Node.js with On-Behalf-Of Flow (Web APIs)\n\nFor web APIs that act on behalf of a signed-in user:\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';\nimport { OnBehalfOfCredential } from '@azure/identity';\n\nconst credential = new OnBehalfOfCredential({\n  tenantId: process.env.AZURE_TENANT_ID,\n  clientId: process.env.AZURE_CLIENT_ID,\n  clientSecret: process.env.AZURE_CLIENT_SECRET,\n  userAssertionToken: userToken // Token from incoming request\n});\n\nconst authProvider = new TokenCredentialAuthenticationProvider(credential, {\n  scopes: ['https://graph.microsoft.com/Files.ReadWrite']\n});\n\nconst client = Client.initWithMiddleware({ authProvider });\n```\n\n### Browser with MSAL (Interactive User Sign-In)\n\nFor single-page applications:\n\n```typescript\nimport * as msal from '@azure/msal-browser';\nimport { Client } from '@microsoft/microsoft-graph-client';\n\n// MSAL configuration\nconst msalConfig = {\n  auth: {\n    clientId: 'YOUR_CLIENT_ID',\n    authority: 'https://login.microsoftonline.com/YOUR_TENANT_ID',\n    redirectUri: 'http://localhost:3000'\n  }\n};\n\nconst msalInstance = new msal.PublicClientApplication(msalConfig);\n\n// Custom authentication provider for MSAL\nclass MsalAuthenticationProvider {\n  constructor(msalInstance, scopes) {\n    this.msalInstance = msalInstance;\n    this.scopes = scopes;\n  }\n\n  async getAccessToken() {\n    const accounts = this.msalInstance.getAllAccounts();\n    if (accounts.length === 0) {\n      await this.msalInstance.loginPopup({ scopes: this.scopes });\n    }\n\n    const request = {\n      scopes: this.scopes,\n      account: this.msalInstance.getAllAccounts()[0]\n    };\n\n    try {\n      const response = await this.msalInstance.acquireTokenSilent(request);\n      return response.accessToken;\n    } catch (error) {\n      const response = await this.msalInstance.acquireTokenPopup(request);\n      return response.accessToken;\n    }\n  }\n}\n\n// Initialize Graph client\nconst authProvider = new MsalAuthenticationProvider(\n  msalInstance,\n  ['Files.ReadWrite']\n);\n\nconst client = Client.initWithMiddleware({\n  authProvider: (done) => {\n    authProvider.getAccessToken().then(token => {\n      done(null, token);\n    }).catch(err => done(err, null));\n  }\n});\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file:\n\n```bash\nAZURE_TENANT_ID=your-tenant-id\nAZURE_CLIENT_ID=your-client-id\nAZURE_CLIENT_SECRET=your-client-secret\nUSER_ID=user@domain.com\n```\n\nLoad environment variables:\n\n```typescript\nimport dotenv from 'dotenv';\ndotenv.config();\n```\n\n\n## Core API Surfaces\n\n\n### 1. Listing Files and Folders\n\n#### List Root Folder Contents\n\n```typescript\n// Current user's OneDrive root\nconst result = await client.api('/me/drive/root/children').get();\n\nconsole.log(result.value); // Array of DriveItem objects\n```\n\n#### List Specific Folder Contents\n\n```typescript\n// By item ID\nconst result = await client\n  .api(`/me/drive/items/{item-id}/children`)\n  .get();\n\n// By path\nconst result = await client\n  .api('/me/drive/root:/Documents/Projects:/children')\n  .get();\n\n// With pagination\nlet items = [];\nlet nextLink = '/me/drive/root/children';\n\nwhile (nextLink) {\n  const response = await client.api(nextLink).get();\n  items = items.concat(response.value);\n  nextLink = response['@odata.nextLink'];\n}\n```\n\n#### Advanced Listing with Query Parameters\n\n```typescript\n// Select specific fields\nconst result = await client\n  .api('/me/drive/root/children')\n  .select('id,name,size,createdDateTime,lastModifiedDateTime')\n  .get();\n\n// Filter files by type\nconst result = await client\n  .api('/me/drive/root/children')\n  .filter('file ne null')\n  .get();\n\n// Order by name\nconst result = await client\n  .api('/me/drive/root/children')\n  .orderby('name asc')\n  .get();\n\n// Limit results\nconst result = await client\n  .api('/me/drive/root/children')\n  .top(10)\n  .get();\n\n// Expand related properties\nconst result = await client\n  .api('/me/drive/root/children')\n  .expand('thumbnails')\n  .get();\n\n// Combine multiple query options\nconst result = await client\n  .api('/me/drive/root/children')\n  .select('id,name,size,file')\n  .filter('file ne null')\n  .orderby('lastModifiedDateTime desc')\n  .top(20)\n  .get();\n```\n\n#### List All Drives\n\n```typescript\n// List all drives accessible to user\nconst drives = await client.api('/me/drives').get();\n\n// Get specific drive\nconst drive = await client.api('/drives/{drive-id}').get();\n\n// Get default drive\nconst defaultDrive = await client.api('/me/drive').get();\n```\n\n\n### 2. Getting File/Folder Metadata\n\n#### Get Item Metadata\n\n```typescript\n// By item ID\nconst item = await client\n  .api(`/me/drive/items/{item-id}`)\n  .get();\n\nconsole.log(item.id);\nconsole.log(item.name);\nconsole.log(item.size);\nconsole.log(item.createdDateTime);\nconsole.log(item.lastModifiedDateTime);\nconsole.log(item.webUrl);\n\n// By path\nconst item = await client\n  .api('/me/drive/root:/Documents/report.pdf')\n  .get();\n```\n\n#### Get File with Specific Properties\n\n```typescript\nconst item = await client\n  .api('/me/drive/items/{item-id}')\n  .select('id,name,size,file,@microsoft.graph.downloadUrl')\n  .get();\n\n// Access file-specific properties\nif (item.file) {\n  console.log('MIME type:', item.file.mimeType);\n  console.log('Hashes:', item.file.hashes);\n}\n\n// Get download URL\nconsole.log('Download URL:', item['@microsoft.graph.downloadUrl']);\n```\n\n\n### 3. Downloading Files\n\n#### Simple Download (Small Files)\n\n```typescript\nimport fs from 'fs';\nimport { Readable } from 'stream';\n\n// Download file content\nconst fileStream = await client\n  .api(`/me/drive/items/{item-id}/content`)\n  .getStream();\n\n// Save to disk\nconst writeStream = fs.createWriteStream('./downloaded-file.pdf');\nfileStream.pipe(writeStream);\n\nawait new Promise((resolve, reject) => {\n  writeStream.on('finish', resolve);\n  writeStream.on('error', reject);\n});\n```\n\n#### Download with Pre-Authenticated URL\n\n```typescript\nimport fetch from 'node-fetch';\nimport fs from 'fs';\n\n// Get item with download URL\nconst item = await client\n  .api('/me/drive/items/{item-id}')\n  .select('@microsoft.graph.downloadUrl')\n  .get();\n\nconst downloadUrl = item['@microsoft.graph.downloadUrl'];\n\n// Download using the URL (valid for a few minutes)\nconst response = await fetch(downloadUrl);\nconst buffer = await response.buffer();\nfs.writeFileSync('./file.dat', buffer);\n```\n\n#### Download Specific Byte Range\n\n```typescript\n// Download partial file content\nconst stream = await client\n  .api(`/me/drive/items/{item-id}/content`)\n  .header('Range', 'bytes=0-1023')\n  .getStream();\n```\n\n\n### 4. Uploading Files\n\n#### Simple Upload (Files < 4MB)\n\n```typescript\nimport fs from 'fs';\n\n// Upload file from buffer or stream\nconst fileContent = fs.readFileSync('./local-file.pdf');\n\nconst uploadedFile = await client\n  .api('/me/drive/root:/Documents/uploaded-file.pdf:/content')\n  .putStream(fs.createReadStream('./local-file.pdf'));\n\nconsole.log('Uploaded file ID:', uploadedFile.id);\n\n// Or upload with buffer\nconst uploadedFile = await client\n  .api('/me/drive/items/{parent-folder-id}:/filename.txt:/content')\n  .put(fileContent);\n```\n\n#### Upload to Specific Folder\n\n```typescript\n// Upload to folder by ID\nconst file = await client\n  .api(`/me/drive/items/{folder-id}:/newfile.txt:/content`)\n  .put('File content here');\n\n// Upload to folder by path\nconst file = await client\n  .api('/me/drive/root:/Documents/Projects:/report.pdf:/content')\n  .putStream(fs.createReadStream('./report.pdf'));\n```\n\n#### Large File Upload (Files > 4MB) - Resumable Upload Session\n\n```typescript\nimport { LargeFileUploadTask, StreamUpload } from '@microsoft/microsoft-graph-client';\nimport fs from 'fs';\n\n// Step 1: Create upload session\nconst uploadSession = await client\n  .api('/me/drive/root:/large-file.zip:/createUploadSession')\n  .post({\n    item: {\n      '@microsoft.graph.conflictBehavior': 'rename',\n      name: 'large-file.zip'\n    }\n  });\n\n// Step 2: Upload file in chunks\nconst fileObject = new StreamUpload(\n  fs.createReadStream('./large-file.zip'),\n  'large-file.zip',\n  fs.statSync('./large-file.zip').size\n);\n\nconst task = new LargeFileUploadTask(client, fileObject, uploadSession);\n\nconst uploadResult = await task.upload();\n\nconsole.log('Upload complete:', uploadResult);\n```\n\n#### Advanced Large File Upload with Progress Tracking\n\n```typescript\nimport { LargeFileUploadTask, StreamUpload, UploadEventHandlers } from '@microsoft/microsoft-graph-client';\nimport fs from 'fs';\n\nconst fileName = 'video.mp4';\nconst filePath = './video.mp4';\nconst stats = fs.statSync(filePath);\nconst fileSize = stats.size;\n\n// Create upload session with conflict resolution\nconst uploadSession = await client\n  .api('/me/drive/root:/Videos:/video.mp4:/createUploadSession')\n  .post({\n    item: {\n      '@microsoft.graph.conflictBehavior': 'replace', // or 'fail', 'rename'\n      name: fileName\n    }\n  });\n\n// Configure upload\nconst fileStream = fs.createReadStream(filePath);\nconst fileObject = new StreamUpload(fileStream, fileName, fileSize);\n\n// Upload with custom chunk size (must be multiple of 320 KB)\nconst options = {\n  rangeSize: 1024 * 1024 * 10, // 10 MB chunks (recommended: 5-10 MB)\n  uploadEventHandlers: {\n    progress: (range, extraCallbackParam) => {\n      const percentage = ((range?.minValue || 0) / fileSize) * 100;\n      console.log(`Uploaded ${percentage.toFixed(2)}%`);\n    },\n    extraCallbackParam: null\n  }\n};\n\nconst task = new LargeFileUploadTask(client, fileObject, uploadSession);\nconst uploadResult = await task.upload();\n\nconsole.log('File uploaded successfully:', uploadResult.id);\n```\n\n#### Resume Interrupted Upload\n\n```typescript\n// If upload fails, you can resume from where it stopped\nconst uploadSession = await client\n  .api('/me/drive/root:/large-file.zip:/createUploadSession')\n  .post({\n    item: {\n      '@microsoft.graph.conflictBehavior': 'replace',\n      name: 'large-file.zip'\n    }\n  });\n\nconst fileObject = new StreamUpload(\n  fs.createReadStream('./large-file.zip'),\n  'large-file.zip',\n  fs.statSync('./large-file.zip').size\n);\n\nconst task = new LargeFileUploadTask(client, fileObject, uploadSession);\n\ntry {\n  const uploadResult = await task.upload();\n  console.log('Upload complete');\n} catch (error) {\n  console.error('Upload failed, attempting to resume...');\n\n  // Resume upload\n  const resumeResult = await task.resume();\n  console.log('Resumed and completed:', resumeResult);\n}\n```\n\n\n### 5. Creating Folders\n\n```typescript\n// Create folder in root\nconst folder = await client\n  .api('/me/drive/root/children')\n  .post({\n    name: 'New Folder',\n    folder: {},\n    '@microsoft.graph.conflictBehavior': 'rename'\n  });\n\n// Create folder at specific path\nconst folder = await client\n  .api('/me/drive/root:/Documents/Projects:/children')\n  .post({\n    name: 'Project Alpha',\n    folder: {},\n    '@microsoft.graph.conflictBehavior': 'fail' // or 'replace', 'rename'\n  });\n\n// Create nested folder structure\nconst parentFolder = await client\n  .api('/me/drive/root/children')\n  .post({\n    name: 'Parent',\n    folder: {}\n  });\n\nconst childFolder = await client\n  .api(`/me/drive/items/${parentFolder.id}/children`)\n  .post({\n    name: 'Child',\n    folder: {}\n  });\n```\n\n\n### 6. Searching Files\n\n```typescript\n// Search in entire drive\nconst results = await client\n  .api('/me/drive/root/search(q=\\'{search-query}\\')')\n  .get();\n\n// Example: Search for PDFs\nconst pdfFiles = await client\n  .api('/me/drive/root/search(q=\\'.pdf\\')')\n  .get();\n\n// Search in specific folder\nconst results = await client\n  .api('/me/drive/items/{folder-id}/search(q=\\'quarterly report\\')')\n  .get();\n\n// Search with select and filter\nconst results = await client\n  .api('/me/drive/root/search(q=\\'presentation\\')')\n  .select('id,name,size,webUrl')\n  .filter('file ne null')\n  .top(10)\n  .get();\n```\n\n\n### 7. Updating/Renaming Files and Folders\n\n```typescript\n// Rename file\nconst updated = await client\n  .api('/me/drive/items/{item-id}')\n  .patch({\n    name: 'new-name.pdf'\n  });\n\n// Update file metadata\nconst updated = await client\n  .api('/me/drive/items/{item-id}')\n  .patch({\n    description: 'Updated description',\n    name: 'renamed-file.docx'\n  });\n\n// Move file to different folder\nconst moved = await client\n  .api('/me/drive/items/{item-id}')\n  .patch({\n    parentReference: {\n      id: '{new-parent-folder-id}'\n    }\n  });\n\n// Move and rename simultaneously\nconst updated = await client\n  .api('/me/drive/items/{item-id}')\n  .patch({\n    name: 'new-name.xlsx',\n    parentReference: {\n      id: '{new-parent-folder-id}'\n    }\n  });\n```\n\n\n### 8. Copying Files\n\n```typescript\n// Copy file to another location\nconst copyOperation = await client\n  .api('/me/drive/items/{item-id}/copy')\n  .post({\n    parentReference: {\n      id: '{destination-folder-id}'\n    },\n    name: 'copied-file.pdf'\n  });\n\n// Monitor copy operation status\nconst monitorUrl = copyOperation.headers.get('Location');\n\n// Poll for completion\nasync function waitForCopy(monitorUrl) {\n  while (true) {\n    const response = await fetch(monitorUrl);\n    const status = await response.json();\n\n    if (status.status === 'completed') {\n      return status.resourceId;\n    } else if (status.status === 'failed') {\n      throw new Error('Copy failed: ' + status.error);\n    }\n\n    await new Promise(resolve => setTimeout(resolve, 1000));\n  }\n}\n```\n\n\n### 9. Deleting Files and Folders\n\n```typescript\n// Delete file or folder\nawait client\n  .api('/me/drive/items/{item-id}')\n  .delete();\n\n// Delete by path\nawait client\n  .api('/me/drive/root:/Documents/old-file.pdf')\n  .delete();\n```\n\n\n### 10. Sharing and Permissions\n\n#### Create Sharing Link\n\n```typescript\n// Create anonymous view link\nconst link = await client\n  .api('/me/drive/items/{item-id}/createLink')\n  .post({\n    type: 'view', // 'view', 'edit', 'embed'\n    scope: 'anonymous' // 'anonymous', 'organization'\n  });\n\nconsole.log('Share link:', link.link.webUrl);\n\n// Create organization-wide edit link\nconst link = await client\n  .api('/me/drive/items/{item-id}/createLink')\n  .post({\n    type: 'edit',\n    scope: 'organization'\n  });\n\n// Create link with expiration\nconst link = await client\n  .api('/me/drive/items/{item-id}/createLink')\n  .post({\n    type: 'view',\n    scope: 'anonymous',\n    expirationDateTime: '2025-12-31T23:59:59Z',\n    password: 'SecurePass123' // Optional password protection\n  });\n```\n\n#### Grant Permissions to Specific Users\n\n```typescript\n// Invite user with edit permissions\nconst permission = await client\n  .api('/me/drive/items/{item-id}/invite')\n  .post({\n    requireSignIn: true,\n    sendInvitation: true,\n    roles: ['write'], // 'read' or 'write'\n    recipients: [\n      { email: 'user@example.com' }\n    ],\n    message: 'Here is the file I mentioned'\n  });\n\n// Add multiple recipients\nconst permission = await client\n  .api('/me/drive/items/{item-id}/invite')\n  .post({\n    requireSignIn: false,\n    sendInvitation: true,\n    roles: ['read'],\n    recipients: [\n      { email: 'user1@example.com' },\n      { email: 'user2@example.com' }\n    ]\n  });\n```\n\n#### List Permissions\n\n```typescript\n// Get all permissions for an item\nconst permissions = await client\n  .api('/me/drive/items/{item-id}/permissions')\n  .get();\n\npermissions.value.forEach(permission => {\n  console.log('Permission ID:', permission.id);\n  console.log('Roles:', permission.roles);\n  if (permission.grantedTo) {\n    console.log('Granted to:', permission.grantedTo.user.displayName);\n  }\n  if (permission.link) {\n    console.log('Share link:', permission.link.webUrl);\n  }\n});\n```\n\n#### Remove Permissions\n\n```typescript\n// Delete specific permission\nawait client\n  .api('/me/drive/items/{item-id}/permissions/{permission-id}')\n  .delete();\n```\n\n#### List Files Shared With Me\n\n```typescript\n// Get files shared with the current user\nconst sharedItems = await client\n  .api('/me/drive/sharedWithMe')\n  .get();\n\nsharedItems.value.forEach(item => {\n  console.log('Shared file:', item.name);\n  console.log('Owner:', item.remoteItem.createdBy.user.displayName);\n  console.log('Parent path:', item.remoteItem.parentReference.path);\n});\n```\n\n\n### 11. Thumbnails\n\n```typescript\n// Get thumbnails for an item\nconst thumbnails = await client\n  .api('/me/drive/items/{item-id}/thumbnails')\n  .get();\n\n// Access different sizes\nconst thumbs = thumbnails.value[0];\nconsole.log('Small:', thumbs.small.url);\nconsole.log('Medium:', thumbs.medium.url);\nconsole.log('Large:', thumbs.large.url);\n\n// Get specific thumbnail size\nconst thumbnail = await client\n  .api('/me/drive/items/{item-id}/thumbnails/0/medium')\n  .get();\n\nconsole.log('Thumbnail URL:', thumbnail.url);\n```\n\n\n### 12. Delta (Change Tracking)\n\n```typescript\n// Get initial delta token and items\nlet deltaUrl = '/me/drive/root/delta';\nlet allItems = [];\n\nwhile (deltaUrl) {\n  const response = await client.api(deltaUrl).get();\n\n  allItems = allItems.concat(response.value);\n\n  if (response['@odata.nextLink']) {\n    deltaUrl = response['@odata.nextLink'];\n  } else {\n    // Store delta token for next sync\n    const deltaToken = response['@odata.deltaLink'];\n    console.log('Delta token:', deltaToken);\n    break;\n  }\n}\n\n// Later, use the delta token to get only changes\nconst changes = await client\n  .api('/me/drive/root/delta?token={previous-delta-token}')\n  .get();\n\nchanges.value.forEach(item => {\n  if (item.deleted) {\n    console.log('Deleted:', item.id);\n  } else {\n    console.log('Added/Modified:', item.name);\n  }\n});\n```\n\n\n### 13. Special Folders\n\n```typescript\n// Access special folders\nconst documents = await client\n  .api('/me/drive/special/documents')\n  .get();\n\nconst photos = await client\n  .api('/me/drive/special/photos')\n  .get();\n\nconst cameraRoll = await client\n  .api('/me/drive/special/cameraroll')\n  .get();\n\nconst appRoot = await client\n  .api('/me/drive/special/approot')\n  .get();\n\n// List children of special folder\nconst files = await client\n  .api('/me/drive/special/documents/children')\n  .get();\n```\n\n\n### 14. Working with SharePoint Document Libraries\n\n```typescript\n// Access SharePoint site drive\nconst drive = await client\n  .api('/sites/{site-id}/drive')\n  .get();\n\n// List document library contents\nconst items = await client\n  .api('/sites/{site-id}/drive/root/children')\n  .get();\n\n// Upload to SharePoint\nconst file = await client\n  .api('/sites/{site-id}/drive/root:/folder/file.pdf:/content')\n  .put(fileContent);\n\n// Get site by path\nconst site = await client\n  .api('/sites/{hostname}:/{server-relative-path}')\n  .get();\n\n// Example: Get site by URL\nconst site = await client\n  .api('/sites/contoso.sharepoint.com:/sites/marketing')\n  .get();\n```\n\n\n### 15. Batch Requests\n\n```typescript\n// Batch multiple requests\nconst batch = {\n  requests: [\n    {\n      id: '1',\n      method: 'GET',\n      url: '/me/drive/root/children'\n    },\n    {\n      id: '2',\n      method: 'GET',\n      url: '/me/drive/special/documents'\n    },\n    {\n      id: '3',\n      method: 'GET',\n      url: '/me/drive/root/search(q=\\'report\\')'\n    }\n  ]\n};\n\nconst batchResponse = await client\n  .api('/$batch')\n  .post(batch);\n\nbatchResponse.responses.forEach(response => {\n  console.log(`Request ${response.id}:`, response.status);\n  console.log('Body:', response.body);\n});\n\n// Batch with dependencies\nconst batchWithDeps = {\n  requests: [\n    {\n      id: '1',\n      method: 'POST',\n      url: '/me/drive/root/children',\n      body: {\n        name: 'NewFolder',\n        folder: {}\n      },\n      headers: {\n        'Content-Type': 'application/json'\n      }\n    },\n    {\n      id: '2',\n      dependsOn: ['1'],\n      method: 'PUT',\n      url: '/me/drive/items/{$1.id}:/file.txt:/content',\n      body: 'File content',\n      headers: {\n        'Content-Type': 'text/plain'\n      }\n    }\n  ]\n};\n```\n\n\n## Error Handling\n\n```typescript\nimport { GraphError } from '@microsoft/microsoft-graph-client';\n\ntry {\n  const item = await client\n    .api('/me/drive/items/{item-id}')\n    .get();\n} catch (error) {\n  if (error instanceof GraphError) {\n    console.error('Graph error code:', error.code);\n    console.error('Status code:', error.statusCode);\n    console.error('Message:', error.message);\n\n    // Handle specific errors\n    if (error.statusCode === 404) {\n      console.error('Item not found');\n    } else if (error.statusCode === 401) {\n      console.error('Unauthorized - check authentication');\n    } else if (error.statusCode === 403) {\n      console.error('Forbidden - check permissions');\n    } else if (error.statusCode === 429) {\n      console.error('Too many requests - rate limited');\n      const retryAfter = error.headers?.get('Retry-After');\n      console.log(`Retry after ${retryAfter} seconds`);\n    }\n  } else {\n    console.error('Unexpected error:', error);\n  }\n}\n```\n\n\n## Complete Working Examples\n\n\n### Example 1: File Upload and Share Workflow\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport { ClientSecretCredential } from '@azure/identity';\nimport { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';\nimport fs from 'fs';\nimport 'isomorphic-fetch';\n\nasync function uploadAndShare() {\n  // Initialize client\n  const credential = new ClientSecretCredential(\n    process.env.AZURE_TENANT_ID!,\n    process.env.AZURE_CLIENT_ID!,\n    process.env.AZURE_CLIENT_SECRET!\n  );\n\n  const authProvider = new TokenCredentialAuthenticationProvider(credential, {\n    scopes: ['https://graph.microsoft.com/.default']\n  });\n\n  const client = Client.initWithMiddleware({ authProvider });\n\n  const userId = process.env.USER_ID!;\n\n  // Create folder\n  const folder = await client\n    .api(`/users/${userId}/drive/root/children`)\n    .post({\n      name: 'Shared Documents',\n      folder: {},\n      '@microsoft.graph.conflictBehavior': 'rename'\n    });\n\n  console.log('Created folder:', folder.id);\n\n  // Upload file\n  const fileContent = fs.readFileSync('./document.pdf');\n  const uploadedFile = await client\n    .api(`/users/${userId}/drive/items/${folder.id}:/document.pdf:/content`)\n    .put(fileContent);\n\n  console.log('Uploaded file:', uploadedFile.id);\n\n  // Create share link\n  const shareLink = await client\n    .api(`/users/${userId}/drive/items/${uploadedFile.id}/createLink`)\n    .post({\n      type: 'view',\n      scope: 'organization',\n      expirationDateTime: '2025-12-31T23:59:59Z'\n    });\n\n  console.log('Share URL:', shareLink.link.webUrl);\n\n  return shareLink.link.webUrl;\n}\n```\n\n\n### Example 2: Download All Files from Folder\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport fs from 'fs';\nimport path from 'path';\n\nasync function downloadFolder(client, folderId, localPath) {\n  // Create local directory\n  if (!fs.existsSync(localPath)) {\n    fs.mkdirSync(localPath, { recursive: true });\n  }\n\n  // Get folder contents\n  const items = await client\n    .api(`/me/drive/items/${folderId}/children`)\n    .get();\n\n  for (const item of items.value) {\n    if (item.folder) {\n      // Recursively download subfolder\n      const subPath = path.join(localPath, item.name);\n      await downloadFolder(client, item.id, subPath);\n    } else if (item.file) {\n      // Download file\n      console.log(`Downloading ${item.name}...`);\n\n      const stream = await client\n        .api(`/me/drive/items/${item.id}/content`)\n        .getStream();\n\n      const filePath = path.join(localPath, item.name);\n      const writeStream = fs.createWriteStream(filePath);\n      stream.pipe(writeStream);\n\n      await new Promise((resolve, reject) => {\n        writeStream.on('finish', resolve);\n        writeStream.on('error', reject);\n      });\n\n      console.log(`Downloaded to ${filePath}`);\n    }\n  }\n}\n```\n\n\n### Example 3: Sync Local Folder to OneDrive\n\n```typescript\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport fs from 'fs';\nimport path from 'path';\nimport { LargeFileUploadTask, StreamUpload } from '@microsoft/microsoft-graph-client';\n\nasync function syncFolderToOneDrive(client, localPath, oneDrivePath) {\n  const files = fs.readdirSync(localPath);\n\n  for (const file of files) {\n    const filePath = path.join(localPath, file);\n    const stats = fs.statSync(filePath);\n\n    if (stats.isDirectory()) {\n      // Create folder in OneDrive\n      const folder = await client\n        .api(`/me/drive/root:/${oneDrivePath}:/children`)\n        .post({\n          name: file,\n          folder: {},\n          '@microsoft.graph.conflictBehavior': 'rename'\n        });\n\n      // Recursively sync subfolder\n      await syncFolderToOneDrive(\n        client,\n        filePath,\n        `${oneDrivePath}/${file}`\n      );\n    } else {\n      // Upload file\n      console.log(`Uploading ${file}...`);\n\n      if (stats.size < 4 * 1024 * 1024) {\n        // Small file - simple upload\n        const content = fs.readFileSync(filePath);\n        await client\n          .api(`/me/drive/root:/${oneDrivePath}/${file}:/content`)\n          .put(content);\n      } else {\n        // Large file - resumable upload\n        const uploadSession = await client\n          .api(`/me/drive/root:/${oneDrivePath}/${file}:/createUploadSession`)\n          .post({\n            item: {\n              '@microsoft.graph.conflictBehavior': 'replace'\n            }\n          });\n\n        const fileObject = new StreamUpload(\n          fs.createReadStream(filePath),\n          file,\n          stats.size\n        );\n\n        const task = new LargeFileUploadTask(client, fileObject, uploadSession);\n        await task.upload();\n      }\n\n      console.log(`Uploaded ${file}`);\n    }\n  }\n}\n```\n\n\n### Example 4: Search and Download Files by Type\n\n```typescript\nasync function downloadFilesByType(client, fileExtension, downloadPath) {\n  if (!fs.existsSync(downloadPath)) {\n    fs.mkdirSync(downloadPath, { recursive: true });\n  }\n\n  // Search for files\n  const results = await client\n    .api(`/me/drive/root/search(q='.${fileExtension}')`)\n    .select('id,name,size,@microsoft.graph.downloadUrl')\n    .get();\n\n  console.log(`Found ${results.value.length} ${fileExtension} files`);\n\n  for (const file of results.value) {\n    if (file.file) {\n      console.log(`Downloading ${file.name}...`);\n\n      const stream = await client\n        .api(`/me/drive/items/${file.id}/content`)\n        .getStream();\n\n      const filePath = path.join(downloadPath, file.name);\n      const writeStream = fs.createWriteStream(filePath);\n      stream.pipe(writeStream);\n\n      await new Promise((resolve, reject) => {\n        writeStream.on('finish', resolve);\n        writeStream.on('error', reject);\n      });\n    }\n  }\n\n  console.log('Download complete');\n}\n\n// Usage\nawait downloadFilesByType(client, 'pdf', './downloads/pdfs');\n```\n\n\n## Rate Limiting and Throttling\n\nMicrosoft Graph implements throttling to maintain service health:\n\n```typescript\nasync function makeRequestWithRetry(client, apiPath, maxRetries = 3) {\n  let retries = 0;\n\n  while (retries < maxRetries) {\n    try {\n      return await client.api(apiPath).get();\n    } catch (error) {\n      if (error.statusCode === 429) {\n        const retryAfter = parseInt(error.headers?.get('Retry-After') || '5');\n        console.log(`Rate limited. Waiting ${retryAfter} seconds...`);\n\n        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n        retries++;\n      } else {\n        throw error;\n      }\n    }\n  }\n\n  throw new Error('Max retries exceeded');\n}\n```\n\n\n## Advanced Configuration\n\n### Custom Middleware\n\n```typescript\nimport { Middleware } from '@microsoft/microsoft-graph-client';\n\n// Custom logging middleware\nclass LoggingMiddleware implements Middleware {\n  async execute(context) {\n    console.log(`Request: ${context.request}`);\n\n    await this.nextMiddleware.execute(context);\n\n    console.log(`Response: ${context.response.status}`);\n  }\n}\n\n// Register middleware\nconst client = Client.initWithMiddleware({\n  authProvider,\n  middleware: new LoggingMiddleware()\n});\n```\n\n### Custom Headers\n\n```typescript\n// Add custom headers to requests\nconst result = await client\n  .api('/me/drive/root/children')\n  .header('Prefer', 'HonorNonIndexedQueriesWarningMayFailRandomly')\n  .header('ConsistencyLevel', 'eventual')\n  .get();\n```\n\n\n## Working with Different Drive Types\n\n```typescript\n// Personal OneDrive\nconst personalDrive = await client.api('/me/drive').get();\n\n// User's OneDrive (requires admin permissions)\nconst userDrive = await client.api('/users/{user-id}/drive').get();\n\n// Group drive\nconst groupDrive = await client.api('/groups/{group-id}/drive').get();\n\n// SharePoint site drive\nconst siteDrive = await client.api('/sites/{site-id}/drive').get();\n\n// Specific drive by ID\nconst drive = await client.api('/drives/{drive-id}').get();\n```\n\n\n## Webhooks and Change Notifications\n\n```typescript\n// Subscribe to changes in a drive\nconst subscription = await client\n  .api('/subscriptions')\n  .post({\n    changeType: 'updated',\n    notificationUrl: 'https://your-webhook-endpoint.com/notifications',\n    resource: '/me/drive/root',\n    expirationDateTime: '2025-12-31T18:23:45.9356913Z',\n    clientState: 'secretClientState'\n  });\n\nconsole.log('Subscription ID:', subscription.id);\n\n// Renew subscription\nconst renewed = await client\n  .api(`/subscriptions/${subscription.id}`)\n  .patch({\n    expirationDateTime: '2026-01-31T18:23:45.9356913Z'\n  });\n\n// Delete subscription\nawait client\n  .api(`/subscriptions/${subscription.id}`)\n  .delete();\n```\n"
  },
  {
    "path": "content/microsoft/docs/onedrive/python/DOC.md",
    "content": "---\nname: onedrive\ndescription: \"Microsoft OneDrive API coding guidelines for Python using the official Microsoft Graph SDK\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.48.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"microsoft,onedrive,storage,graph-api,files\"\n---\n\n# Microsoft OneDrive API Coding Guidelines (Python)\n\nYou are a **Microsoft OneDrive API coding expert**. Help me write correct, idiomatic Python code that accesses OneDrive files and folders using the official Microsoft Graph SDK.\n\nUse **only official Microsoft sources** for behavior, fields, and constraints. This guide summarizes key patterns for Python applications.\n\n> Ground truth: Microsoft Graph OneDrive API documentation on learn.microsoft.com.\n\n\n## Golden Rule: Use the Official Microsoft Graph SDK\n\n**ALWAYS use `msgraph-sdk` version 1.48.0 or later** for OneDrive operations. This is the official Microsoft Graph Python SDK that provides access to OneDrive, SharePoint, and all other Microsoft Graph APIs.\n\n**DO NOT use**:\n- Deprecated `onedrivesdk` package (obsolete)\n- Direct REST calls without the SDK (unless absolutely necessary)\n- Unofficial third-party OneDrive libraries\n\n**Install (Python):**\n```bash\npip install msgraph-sdk\npip install azure-identity\n```\n\n\n## Installation\n\n### Complete Setup for Python Applications\n\n```bash\n# Core Microsoft Graph SDK\npip install msgraph-sdk\n\n# Azure authentication library\npip install azure-identity\n\n# For async support (recommended)\npip install aiohttp\n\n# Environment variable management\npip install python-dotenv\n```\n\n### Using requirements.txt\n\n```text\nmsgraph-sdk>=1.48.0\nazure-identity>=1.19.0\npython-dotenv>=1.0.0\naiohttp>=3.9.0\n```\n\n### Using pyproject.toml (Poetry/UV)\n\n```toml\n[project]\ndependencies = [\n    \"msgraph-sdk>=1.48.0\",\n    \"azure-identity>=1.19.0\",\n    \"python-dotenv>=1.0.0\",\n    \"aiohttp>=3.9.0\"\n]\n```\n\n\n## Authentication\n\nOneDrive access through Microsoft Graph requires OAuth 2.0 authentication. You need to register an application in Azure Active Directory (Azure AD) to obtain credentials.\n\n### Azure AD App Registration\n\n1. Go to [Azure Portal](https://portal.azure.com) → Azure Active Directory → App registrations\n2. Create a new registration\n3. Note your **Application (client) ID** and **Directory (tenant) ID**\n4. Create a client secret under \"Certificates & secrets\"\n5. Add API permissions: Microsoft Graph → **Files.Read**, **Files.ReadWrite**, **Files.Read.All**, **Files.ReadWrite.All**\n6. Grant admin consent for the permissions\n\n### Required Scopes\n\nCommon OneDrive permission scopes:\n\n```python\n# Read-only access to user's files\nSCOPES_READONLY = ['https://graph.microsoft.com/Files.Read']\n\n# Read/write access to user's files\nSCOPES_READWRITE = ['https://graph.microsoft.com/Files.ReadWrite']\n\n# Read all files user can access (including shared)\nSCOPES_READ_ALL = ['https://graph.microsoft.com/Files.Read.All']\n\n# Full access to all files user can access\nSCOPES_READWRITE_ALL = ['https://graph.microsoft.com/Files.ReadWrite.All']\n\n# Application permissions (no user context, requires admin consent)\nSCOPES_APP = ['https://graph.microsoft.com/.default']\n```\n\n\n## Initialization\n\n### Async Client with Client Credentials (Service/Daemon Apps)\n\nFor server-side applications using application permissions:\n\n```python\nimport asyncio\nfrom azure.identity.aio import ClientSecretCredential\nfrom msgraph import GraphServiceClient\nfrom msgraph.generated.users.item.user_item_request_builder import UserItemRequestBuilder\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\n# Environment variables\ntenant_id = os.getenv('AZURE_TENANT_ID')\nclient_id = os.getenv('AZURE_CLIENT_ID')\nclient_secret = os.getenv('AZURE_CLIENT_SECRET')\n\n# Create credential\ncredentials = ClientSecretCredential(\n    tenant_id=tenant_id,\n    client_id=client_id,\n    client_secret=client_secret\n)\n\n# Scopes for application permissions\nscopes = ['https://graph.microsoft.com/.default']\n\n# Initialize Microsoft Graph client\nclient = GraphServiceClient(credentials=credentials, scopes=scopes)\n\n# Example: List files in user's OneDrive root\nasync def list_files(user_id: str):\n    result = await client.users.by_user_id(user_id).drive.root.children.get()\n    return result.value\n\nasync def main():\n    user_id = os.getenv('USER_ID')\n    files = await list_files(user_id)\n\n    for file in files:\n        print(f\"{file.name} - {file.size} bytes\")\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Sync Client with Client Credentials\n\nFor synchronous applications:\n\n```python\nfrom azure.identity import ClientSecretCredential\nfrom msgraph import GraphServiceClient\nimport os\n\ncredentials = ClientSecretCredential(\n    tenant_id=os.getenv('AZURE_TENANT_ID'),\n    client_id=os.getenv('AZURE_CLIENT_ID'),\n    client_secret=os.getenv('AZURE_CLIENT_SECRET')\n)\n\nscopes = ['https://graph.microsoft.com/.default']\nclient = GraphServiceClient(credentials=credentials, scopes=scopes)\n\n# Use sync methods\ndef list_files_sync(user_id: str):\n    # Note: The SDK is primarily async, synchronous usage requires running in event loop\n    import asyncio\n    loop = asyncio.get_event_loop()\n    result = loop.run_until_complete(\n        client.users.by_user_id(user_id).drive.root.children.get()\n    )\n    return result.value\n```\n\n### Async Client with Device Code Flow (Interactive)\n\nFor CLI applications that need user interaction:\n\n```python\nfrom azure.identity.aio import DeviceCodeCredential\nfrom msgraph import GraphServiceClient\nimport os\n\nasync def init_graph_client():\n    credentials = DeviceCodeCredential(\n        client_id=os.getenv('AZURE_CLIENT_ID'),\n        tenant_id=os.getenv('AZURE_TENANT_ID')\n    )\n\n    scopes = ['Files.ReadWrite', 'Files.Read.All']\n    client = GraphServiceClient(credentials=credentials, scopes=scopes)\n\n    return client\n\nasync def main():\n    client = await init_graph_client()\n\n    # List files in current user's drive\n    result = await client.me.drive.root.children.get()\n\n    for item in result.value:\n        print(f\"{item.name}\")\n\nasyncio.run(main())\n```\n\n### Async Client with Interactive Browser\n\nFor desktop applications with interactive login:\n\n```python\nfrom azure.identity.aio import InteractiveBrowserCredential\nfrom msgraph import GraphServiceClient\nimport os\n\nasync def init_graph_client():\n    credentials = InteractiveBrowserCredential(\n        client_id=os.getenv('AZURE_CLIENT_ID'),\n        tenant_id=os.getenv('AZURE_TENANT_ID')\n    )\n\n    scopes = ['Files.ReadWrite']\n    client = GraphServiceClient(credentials=credentials, scopes=scopes)\n\n    return client\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file:\n\n```bash\nAZURE_TENANT_ID=your-tenant-id\nAZURE_CLIENT_ID=your-client-id\nAZURE_CLIENT_SECRET=your-client-secret\nUSER_ID=user@domain.com\n```\n\nLoad environment variables:\n\n```python\nfrom dotenv import load_dotenv\nimport os\n\nload_dotenv()\n\ntenant_id = os.getenv('AZURE_TENANT_ID')\nclient_id = os.getenv('AZURE_CLIENT_ID')\nclient_secret = os.getenv('AZURE_CLIENT_SECRET')\n```\n\n\n## Core API Surfaces\n\n\n### 1. Listing Files and Folders\n\n#### List Root Folder Contents\n\n```python\nfrom msgraph import GraphServiceClient\n\nasync def list_root_files(client: GraphServiceClient):\n    # Current user's OneDrive root\n    result = await client.me.drive.root.children.get()\n\n    if result and result.value:\n        for item in result.value:\n            item_type = \"Folder\" if item.folder else \"File\"\n            print(f\"{item_type}: {item.name} (ID: {item.id})\")\n\n    return result.value\n```\n\n#### List Specific Folder Contents\n\n```python\n# By item ID\nasync def list_folder_by_id(client: GraphServiceClient, item_id: str):\n    result = await client.me.drive.items.by_drive_item_id(item_id).children.get()\n    return result.value\n\n# By path\nasync def list_folder_by_path(client: GraphServiceClient, folder_path: str):\n    # Example: /Documents/Projects\n    result = await client.me.drive.root.item_with_path(folder_path).children.get()\n    return result.value\n\n# With pagination\nasync def list_all_items_paginated(client: GraphServiceClient):\n    items = []\n    result = await client.me.drive.root.children.get()\n\n    while result:\n        if result.value:\n            items.extend(result.value)\n\n        # Check for next page\n        if hasattr(result, 'odata_next_link') and result.odata_next_link:\n            # Fetch next page\n            result = await client.me.drive.root.children.get()\n        else:\n            break\n\n    return items\n```\n\n#### Advanced Listing with Query Parameters\n\n```python\nfrom msgraph.generated.users.item.drive.root.children.children_request_builder import ChildrenRequestBuilder\n\nasync def list_with_filters(client: GraphServiceClient):\n    # Configure request\n    query_params = ChildrenRequestBuilder.ChildrenRequestBuilderGetQueryParameters(\n        select=['id', 'name', 'size', 'created_date_time', 'last_modified_date_time'],\n        filter='file ne null',  # Only files\n        orderby=['name asc'],\n        top=10\n    )\n\n    request_config = ChildrenRequestBuilder.ChildrenRequestBuilderGetRequestConfiguration(\n        query_parameters=query_params\n    )\n\n    result = await client.me.drive.root.children.get(request_configuration=request_config)\n    return result.value\n\n# Filter folders only\nasync def list_folders_only(client: GraphServiceClient):\n    query_params = ChildrenRequestBuilder.ChildrenRequestBuilderGetQueryParameters(\n        filter='folder ne null'\n    )\n\n    request_config = ChildrenRequestBuilder.ChildrenRequestBuilderGetRequestConfiguration(\n        query_parameters=query_params\n    )\n\n    result = await client.me.drive.root.children.get(request_configuration=request_config)\n    return result.value\n\n# Order by last modified date\nasync def list_by_modified_date(client: GraphServiceClient):\n    query_params = ChildrenRequestBuilder.ChildrenRequestBuilderGetQueryParameters(\n        orderby=['lastModifiedDateTime desc'],\n        top=20\n    )\n\n    request_config = ChildrenRequestBuilder.ChildrenRequestBuilderGetRequestConfiguration(\n        query_parameters=query_params\n    )\n\n    result = await client.me.drive.root.children.get(request_configuration=request_config)\n    return result.value\n```\n\n#### List All Drives\n\n```python\n# List all drives accessible to user\nasync def list_drives(client: GraphServiceClient):\n    drives = await client.me.drives.get()\n\n    if drives and drives.value:\n        for drive in drives.value:\n            print(f\"Drive: {drive.name} (ID: {drive.id})\")\n            print(f\"  Type: {drive.drive_type}\")\n            print(f\"  Owner: {drive.owner.user.display_name if drive.owner else 'N/A'}\")\n\n    return drives.value\n\n# Get default drive\nasync def get_default_drive(client: GraphServiceClient):\n    drive = await client.me.drive.get()\n    return drive\n\n# Get specific drive\nasync def get_drive_by_id(client: GraphServiceClient, drive_id: str):\n    drive = await client.drives.by_drive_id(drive_id).get()\n    return drive\n```\n\n\n### 2. Getting File/Folder Metadata\n\n#### Get Item Metadata\n\n```python\n# By item ID\nasync def get_item_metadata(client: GraphServiceClient, item_id: str):\n    item = await client.me.drive.items.by_drive_item_id(item_id).get()\n\n    print(f\"ID: {item.id}\")\n    print(f\"Name: {item.name}\")\n    print(f\"Size: {item.size} bytes\")\n    print(f\"Created: {item.created_date_time}\")\n    print(f\"Modified: {item.last_modified_date_time}\")\n    print(f\"Web URL: {item.web_url}\")\n\n    if item.file:\n        print(f\"MIME Type: {item.file.mime_type}\")\n        if item.file.hashes:\n            print(f\"SHA1 Hash: {item.file.hashes.sha1_hash}\")\n\n    return item\n\n# By path\nasync def get_item_by_path(client: GraphServiceClient, file_path: str):\n    # Example: /Documents/report.pdf\n    item = await client.me.drive.root.item_with_path(file_path).get()\n    return item\n```\n\n#### Get File with Specific Properties\n\n```python\nfrom msgraph.generated.users.item.drive.items.item.drive_item_item_request_builder import DriveItemItemRequestBuilder\n\nasync def get_item_with_select(client: GraphServiceClient, item_id: str):\n    query_params = DriveItemItemRequestBuilder.DriveItemItemRequestBuilderGetQueryParameters(\n        select=['id', 'name', 'size', 'file', 'createdDateTime']\n    )\n\n    request_config = DriveItemItemRequestBuilder.DriveItemItemRequestBuilderGetRequestConfiguration(\n        query_parameters=query_params\n    )\n\n    item = await client.me.drive.items.by_drive_item_id(item_id).get(\n        request_configuration=request_config\n    )\n\n    return item\n```\n\n\n### 3. Downloading Files\n\n#### Simple Download (All File Sizes)\n\n```python\nimport aiofiles\n\nasync def download_file(client: GraphServiceClient, item_id: str, save_path: str):\n    # Get file content as stream\n    stream = await client.me.drive.items.by_drive_item_id(item_id).content.get()\n\n    # Save to disk\n    async with aiofiles.open(save_path, 'wb') as f:\n        await f.write(stream)\n\n    print(f\"Downloaded to {save_path}\")\n\n# Download by path\nasync def download_file_by_path(client: GraphServiceClient, file_path: str, save_path: str):\n    # Example: /Documents/report.pdf\n    stream = await client.me.drive.root.item_with_path(file_path).content.get()\n\n    async with aiofiles.open(save_path, 'wb') as f:\n        await f.write(stream)\n```\n\n#### Download Multiple Files\n\n```python\nimport os\nimport asyncio\n\nasync def download_folder(client: GraphServiceClient, folder_id: str, local_path: str):\n    # Create local directory\n    os.makedirs(local_path, exist_ok=True)\n\n    # Get folder contents\n    items = await client.me.drive.items.by_drive_item_id(folder_id).children.get()\n\n    if not items or not items.value:\n        return\n\n    for item in items.value:\n        if item.folder:\n            # Recursively download subfolder\n            subfolder_path = os.path.join(local_path, item.name)\n            await download_folder(client, item.id, subfolder_path)\n        elif item.file:\n            # Download file\n            print(f\"Downloading {item.name}...\")\n            file_path = os.path.join(local_path, item.name)\n\n            stream = await client.me.drive.items.by_drive_item_id(item.id).content.get()\n\n            async with aiofiles.open(file_path, 'wb') as f:\n                await f.write(stream)\n\n            print(f\"Downloaded {item.name}\")\n```\n\n\n### 4. Uploading Files\n\n#### Simple Upload (Files < 4MB)\n\n```python\nasync def upload_small_file(client: GraphServiceClient, file_path: str, upload_path: str):\n    \"\"\"\n    Upload a file smaller than 4MB\n\n    Args:\n        file_path: Local file path\n        upload_path: OneDrive path (e.g., '/Documents/file.pdf')\n    \"\"\"\n    async with aiofiles.open(file_path, 'rb') as f:\n        content = await f.read()\n\n    # Upload to specific path\n    item = await client.me.drive.root.item_with_path(upload_path).content.put(content)\n\n    print(f\"Uploaded: {item.name} (ID: {item.id})\")\n    return item\n\n# Upload to specific folder by ID\nasync def upload_to_folder(client: GraphServiceClient, file_path: str, folder_id: str, filename: str):\n    async with aiofiles.open(file_path, 'rb') as f:\n        content = await f.read()\n\n    item = await client.me.drive.items.by_drive_item_id(folder_id).item_with_path(filename).content.put(content)\n\n    return item\n```\n\n#### Large File Upload (Files > 4MB) - Resumable Upload Session\n\n```python\nimport math\nimport aiohttp\n\nasync def upload_large_file(client: GraphServiceClient, file_path: str, upload_path: str):\n    \"\"\"\n    Upload large files using resumable upload session\n\n    Args:\n        file_path: Local file path\n        upload_path: OneDrive path (e.g., '/Documents/video.mp4')\n    \"\"\"\n    import os\n    from msgraph.generated.drives.item.items.item.create_upload_session.create_upload_session_post_request_body import CreateUploadSessionPostRequestBody\n    from msgraph.generated.models.drive_item_uploadable_properties import DriveItemUploadableProperties\n\n    file_size = os.path.getsize(file_path)\n\n    # Step 1: Create upload session\n    props = DriveItemUploadableProperties()\n    props.odata_type = \"#microsoft.graph.driveItemUploadableProperties\"\n    props.microsoft_graph_conflict_behavior = \"rename\"  # or 'fail', 'replace'\n    props.name = os.path.basename(file_path)\n\n    request_body = CreateUploadSessionPostRequestBody()\n    request_body.item = props\n\n    upload_session = await client.me.drive.root.item_with_path(upload_path).create_upload_session.post(request_body)\n\n    # Step 2: Upload file in chunks\n    chunk_size = 320 * 1024 * 10  # 3.2 MB chunks (must be multiple of 320 KB)\n\n    async with aiofiles.open(file_path, 'rb') as f:\n        file_content = await f.read()\n\n    num_chunks = math.ceil(file_size / chunk_size)\n\n    for i in range(num_chunks):\n        start = i * chunk_size\n        end = min(start + chunk_size, file_size)\n        chunk = file_content[start:end]\n\n        content_range = f\"bytes {start}-{end-1}/{file_size}\"\n\n        headers = {\n            'Content-Length': str(len(chunk)),\n            'Content-Range': content_range\n        }\n\n        # Upload chunk\n        async with aiohttp.ClientSession() as session:\n            async with session.put(\n                upload_session.upload_url,\n                data=chunk,\n                headers=headers\n            ) as response:\n                if response.status in [200, 201, 202]:\n                    progress = (end / file_size) * 100\n                    print(f\"Upload progress: {progress:.2f}%\")\n                else:\n                    error_text = await response.text()\n                    raise Exception(f\"Upload failed: {error_text}\")\n\n    print(\"Upload complete!\")\n    return upload_session\n\n# Alternative: Using helper function for large uploads\nasync def upload_large_file_simple(client: GraphServiceClient, file_path: str, folder_id: str):\n    \"\"\"\n    Simplified large file upload\n    \"\"\"\n    import os\n    from msgraph.generated.drives.item.items.item.create_upload_session.create_upload_session_post_request_body import CreateUploadSessionPostRequestBody\n    from msgraph.generated.models.drive_item_uploadable_properties import DriveItemUploadableProperties\n\n    filename = os.path.basename(file_path)\n    file_size = os.path.getsize(file_path)\n\n    # Create upload session\n    props = DriveItemUploadableProperties()\n    props.microsoft_graph_conflict_behavior = \"replace\"\n    props.name = filename\n\n    request_body = CreateUploadSessionPostRequestBody()\n    request_body.item = props\n\n    upload_session = await client.me.drive.items.by_drive_item_id(folder_id).item_with_path(filename).create_upload_session.post(request_body)\n\n    # Upload in chunks\n    chunk_size = 10 * 1024 * 1024  # 10 MB\n\n    async with aiofiles.open(file_path, 'rb') as f:\n        offset = 0\n\n        while offset < file_size:\n            chunk = await f.read(chunk_size)\n            chunk_len = len(chunk)\n\n            content_range = f\"bytes {offset}-{offset + chunk_len - 1}/{file_size}\"\n\n            headers = {\n                'Content-Length': str(chunk_len),\n                'Content-Range': content_range\n            }\n\n            async with aiohttp.ClientSession() as session:\n                async with session.put(\n                    upload_session.upload_url,\n                    data=chunk,\n                    headers=headers\n                ) as response:\n                    if response.status not in [200, 201, 202]:\n                        raise Exception(f\"Upload failed: {await response.text()}\")\n\n            offset += chunk_len\n            progress = (offset / file_size) * 100\n            print(f\"Uploaded: {progress:.1f}%\")\n\n    print(\"Upload complete!\")\n```\n\n\n### 5. Creating Folders\n\n```python\nfrom msgraph.generated.models.drive_item import DriveItem\nfrom msgraph.generated.models.folder import Folder\n\nasync def create_folder(client: GraphServiceClient, folder_name: str, parent_id: str = None):\n    \"\"\"\n    Create a new folder\n\n    Args:\n        folder_name: Name of the folder to create\n        parent_id: Parent folder ID (None for root)\n    \"\"\"\n    drive_item = DriveItem()\n    drive_item.name = folder_name\n    drive_item.folder = Folder()\n    drive_item.microsoft_graph_conflict_behavior = \"rename\"  # or 'fail', 'replace'\n\n    if parent_id:\n        folder = await client.me.drive.items.by_drive_item_id(parent_id).children.post(drive_item)\n    else:\n        folder = await client.me.drive.root.children.post(drive_item)\n\n    print(f\"Created folder: {folder.name} (ID: {folder.id})\")\n    return folder\n\n# Create folder at specific path\nasync def create_folder_by_path(client: GraphServiceClient, folder_path: str):\n    \"\"\"\n    Create folder at path (e.g., '/Documents/Projects/New Folder')\n    \"\"\"\n    drive_item = DriveItem()\n    drive_item.name = os.path.basename(folder_path)\n    drive_item.folder = Folder()\n    drive_item.microsoft_graph_conflict_behavior = \"fail\"\n\n    parent_path = os.path.dirname(folder_path)\n\n    if parent_path and parent_path != '/':\n        folder = await client.me.drive.root.item_with_path(parent_path).children.post(drive_item)\n    else:\n        folder = await client.me.drive.root.children.post(drive_item)\n\n    return folder\n\n# Create nested folder structure\nasync def create_nested_folders(client: GraphServiceClient, path_parts: list):\n    \"\"\"\n    Create nested folders\n\n    Args:\n        path_parts: List of folder names ['Parent', 'Child', 'Grandchild']\n    \"\"\"\n    parent_id = None\n\n    for folder_name in path_parts:\n        folder = await create_folder(client, folder_name, parent_id)\n        parent_id = folder.id\n\n    return parent_id\n```\n\n\n### 6. Searching Files\n\n```python\nfrom msgraph.generated.users.item.drive.root.search_with_q.search_with_q_request_builder import SearchWithQRequestBuilder\n\nasync def search_files(client: GraphServiceClient, query: str):\n    \"\"\"\n    Search for files and folders\n\n    Args:\n        query: Search query string\n    \"\"\"\n    result = await client.me.drive.root.search_with_q(query).get()\n\n    if result and result.value:\n        for item in result.value:\n            item_type = \"Folder\" if item.folder else \"File\"\n            print(f\"{item_type}: {item.name} - {item.web_url}\")\n\n    return result.value\n\n# Search in specific folder\nasync def search_in_folder(client: GraphServiceClient, folder_id: str, query: str):\n    result = await client.me.drive.items.by_drive_item_id(folder_id).search_with_q(query).get()\n    return result.value\n\n# Search with filters\nasync def search_pdfs(client: GraphServiceClient):\n    \"\"\"Search for PDF files only\"\"\"\n    result = await client.me.drive.root.search_with_q('.pdf').get()\n\n    # Additional filtering in code\n    pdf_files = [item for item in result.value if item.file and item.name.lower().endswith('.pdf')]\n\n    return pdf_files\n\n# Advanced search with query parameters\nasync def advanced_search(client: GraphServiceClient, query: str):\n    query_params = SearchWithQRequestBuilder.SearchWithQRequestBuilderGetQueryParameters(\n        select=['id', 'name', 'size', 'webUrl'],\n        top=10\n    )\n\n    request_config = SearchWithQRequestBuilder.SearchWithQRequestBuilderGetRequestConfiguration(\n        query_parameters=query_params\n    )\n\n    result = await client.me.drive.root.search_with_q(query).get(request_configuration=request_config)\n    return result.value\n```\n\n\n### 7. Updating/Renaming Files and Folders\n\n```python\nfrom msgraph.generated.models.drive_item import DriveItem\nfrom msgraph.generated.models.item_reference import ItemReference\n\nasync def rename_item(client: GraphServiceClient, item_id: str, new_name: str):\n    \"\"\"Rename a file or folder\"\"\"\n    drive_item = DriveItem()\n    drive_item.name = new_name\n\n    updated = await client.me.drive.items.by_drive_item_id(item_id).patch(drive_item)\n\n    print(f\"Renamed to: {updated.name}\")\n    return updated\n\n# Update file metadata\nasync def update_metadata(client: GraphServiceClient, item_id: str, description: str):\n    drive_item = DriveItem()\n    drive_item.description = description\n\n    updated = await client.me.drive.items.by_drive_item_id(item_id).patch(drive_item)\n    return updated\n\n# Move file to different folder\nasync def move_item(client: GraphServiceClient, item_id: str, new_parent_id: str):\n    \"\"\"Move file or folder to new location\"\"\"\n    drive_item = DriveItem()\n\n    parent_ref = ItemReference()\n    parent_ref.id = new_parent_id\n    drive_item.parent_reference = parent_ref\n\n    moved = await client.me.drive.items.by_drive_item_id(item_id).patch(drive_item)\n\n    print(f\"Moved {moved.name} to new location\")\n    return moved\n\n# Move and rename simultaneously\nasync def move_and_rename(client: GraphServiceClient, item_id: str, new_parent_id: str, new_name: str):\n    drive_item = DriveItem()\n    drive_item.name = new_name\n\n    parent_ref = ItemReference()\n    parent_ref.id = new_parent_id\n    drive_item.parent_reference = parent_ref\n\n    updated = await client.me.drive.items.by_drive_item_id(item_id).patch(drive_item)\n    return updated\n```\n\n\n### 8. Copying Files\n\n```python\nimport asyncio\nfrom msgraph.generated.drives.item.items.item.copy.copy_post_request_body import CopyPostRequestBody\nfrom msgraph.generated.models.item_reference import ItemReference\n\nasync def copy_file(client: GraphServiceClient, item_id: str, destination_folder_id: str, new_name: str = None):\n    \"\"\"\n    Copy file to another location\n\n    Args:\n        item_id: Source file ID\n        destination_folder_id: Destination folder ID\n        new_name: Optional new name for copied file\n    \"\"\"\n    request_body = CopyPostRequestBody()\n\n    parent_ref = ItemReference()\n    parent_ref.id = destination_folder_id\n    request_body.parent_reference = parent_ref\n\n    if new_name:\n        request_body.name = new_name\n\n    # Initiate copy operation\n    await client.me.drive.items.by_drive_item_id(item_id).copy.post(request_body)\n\n    # Copy is async operation; monitor using returned location header if needed\n    print(f\"Copy operation initiated\")\n\n    # Wait a bit for copy to complete\n    await asyncio.sleep(2)\n```\n\n\n### 9. Deleting Files and Folders\n\n```python\nasync def delete_item(client: GraphServiceClient, item_id: str):\n    \"\"\"Delete a file or folder\"\"\"\n    await client.me.drive.items.by_drive_item_id(item_id).delete()\n    print(f\"Deleted item: {item_id}\")\n\n# Delete by path\nasync def delete_by_path(client: GraphServiceClient, item_path: str):\n    \"\"\"\n    Delete file or folder by path\n\n    Args:\n        item_path: Path like '/Documents/old-file.pdf'\n    \"\"\"\n    await client.me.drive.root.item_with_path(item_path).delete()\n    print(f\"Deleted: {item_path}\")\n\n# Safe delete with confirmation\nasync def safe_delete(client: GraphServiceClient, item_id: str):\n    \"\"\"Delete with metadata check first\"\"\"\n    # Get item info first\n    item = await client.me.drive.items.by_drive_item_id(item_id).get()\n\n    print(f\"About to delete: {item.name}\")\n    print(f\"Size: {item.size} bytes\")\n    print(f\"Modified: {item.last_modified_date_time}\")\n\n    # Confirm and delete\n    await client.me.drive.items.by_drive_item_id(item_id).delete()\n    print(\"Deleted successfully\")\n```\n\n\n### 10. Sharing and Permissions\n\n#### Create Sharing Link\n\n```python\nfrom msgraph.generated.drives.item.items.item.create_link.create_link_post_request_body import CreateLinkPostRequestBody\n\nasync def create_share_link(client: GraphServiceClient, item_id: str, link_type: str = \"view\", scope: str = \"anonymous\"):\n    \"\"\"\n    Create a sharing link\n\n    Args:\n        item_id: File or folder ID\n        link_type: 'view', 'edit', or 'embed'\n        scope: 'anonymous' or 'organization'\n    \"\"\"\n    request_body = CreateLinkPostRequestBody()\n    request_body.type = link_type\n    request_body.scope = scope\n\n    permission = await client.me.drive.items.by_drive_item_id(item_id).create_link.post(request_body)\n\n    print(f\"Share link: {permission.link.web_url}\")\n    return permission.link.web_url\n\n# Create link with expiration\nasync def create_expiring_link(client: GraphServiceClient, item_id: str, expiration_date: str):\n    \"\"\"\n    Create link with expiration\n\n    Args:\n        expiration_date: ISO 8601 format like '2025-12-31T23:59:59Z'\n    \"\"\"\n    request_body = CreateLinkPostRequestBody()\n    request_body.type = \"view\"\n    request_body.scope = \"anonymous\"\n    request_body.expiration_date_time = expiration_date\n\n    permission = await client.me.drive.items.by_drive_item_id(item_id).create_link.post(request_body)\n    return permission.link.web_url\n\n# Create password-protected link\nasync def create_protected_link(client: GraphServiceClient, item_id: str, password: str):\n    request_body = CreateLinkPostRequestBody()\n    request_body.type = \"view\"\n    request_body.scope = \"anonymous\"\n    request_body.password = password\n\n    permission = await client.me.drive.items.by_drive_item_id(item_id).create_link.post(request_body)\n    return permission.link.web_url\n```\n\n#### Grant Permissions to Specific Users\n\n```python\nfrom msgraph.generated.drives.item.items.item.invite.invite_post_request_body import InvitePostRequestBody\nfrom msgraph.generated.models.drive_recipient import DriveRecipient\n\nasync def invite_users(client: GraphServiceClient, item_id: str, email_addresses: list, role: str = \"read\"):\n    \"\"\"\n    Invite users to access a file\n\n    Args:\n        item_id: File or folder ID\n        email_addresses: List of email addresses\n        role: 'read' or 'write'\n    \"\"\"\n    request_body = InvitePostRequestBody()\n    request_body.require_sign_in = True\n    request_body.send_invitation = True\n    request_body.roles = [role]\n    request_body.message = \"I've shared a file with you\"\n\n    recipients = []\n    for email in email_addresses:\n        recipient = DriveRecipient()\n        recipient.email = email\n        recipients.append(recipient)\n\n    request_body.recipients = recipients\n\n    permissions = await client.me.drive.items.by_drive_item_id(item_id).invite.post(request_body)\n\n    print(f\"Invited {len(email_addresses)} users\")\n    return permissions\n```\n\n#### List Permissions\n\n```python\nasync def list_permissions(client: GraphServiceClient, item_id: str):\n    \"\"\"Get all permissions for an item\"\"\"\n    permissions = await client.me.drive.items.by_drive_item_id(item_id).permissions.get()\n\n    if permissions and permissions.value:\n        for perm in permissions.value:\n            print(f\"Permission ID: {perm.id}\")\n            print(f\"Roles: {perm.roles}\")\n\n            if perm.granted_to_v2:\n                print(f\"Granted to: {perm.granted_to_v2.user.display_name}\")\n\n            if perm.link:\n                print(f\"Link: {perm.link.web_url}\")\n\n            print(\"---\")\n\n    return permissions.value\n\n# Remove permission\nasync def remove_permission(client: GraphServiceClient, item_id: str, permission_id: str):\n    \"\"\"Delete a specific permission\"\"\"\n    await client.me.drive.items.by_drive_item_id(item_id).permissions.by_permission_id(permission_id).delete()\n    print(f\"Removed permission: {permission_id}\")\n```\n\n#### List Files Shared With Me\n\n```python\nasync def list_shared_with_me(client: GraphServiceClient):\n    \"\"\"Get files shared with the current user\"\"\"\n    shared_items = await client.me.drive.shared_with_me.get()\n\n    if shared_items and shared_items.value:\n        for item in shared_items.value:\n            print(f\"Shared file: {item.name}\")\n            if item.remote_item:\n                print(f\"  Size: {item.remote_item.size}\")\n                if item.remote_item.created_by:\n                    print(f\"  Owner: {item.remote_item.created_by.user.display_name}\")\n\n    return shared_items.value\n```\n\n\n### 11. Thumbnails\n\n```python\nasync def get_thumbnails(client: GraphServiceClient, item_id: str):\n    \"\"\"Get thumbnails for an item\"\"\"\n    thumbnails = await client.me.drive.items.by_drive_item_id(item_id).thumbnails.get()\n\n    if thumbnails and thumbnails.value:\n        thumb_set = thumbnails.value[0]\n\n        if thumb_set.small:\n            print(f\"Small: {thumb_set.small.url}\")\n        if thumb_set.medium:\n            print(f\"Medium: {thumb_set.medium.url}\")\n        if thumb_set.large:\n            print(f\"Large: {thumb_set.large.url}\")\n\n    return thumbnails.value\n\n# Get specific thumbnail size\nasync def get_medium_thumbnail(client: GraphServiceClient, item_id: str):\n    thumbnail = await client.me.drive.items.by_drive_item_id(item_id).thumbnails.by_thumbnail_set_id(\"0\").medium.get()\n\n    if thumbnail:\n        print(f\"Thumbnail URL: {thumbnail.url}\")\n        print(f\"Size: {thumbnail.width}x{thumbnail.height}\")\n\n    return thumbnail\n```\n\n\n### 12. Delta (Change Tracking)\n\n```python\nasync def get_initial_delta(client: GraphServiceClient):\n    \"\"\"Get initial delta token and all items\"\"\"\n    all_items = []\n    delta_link = None\n\n    result = await client.me.drive.root.delta.get()\n\n    while result:\n        if result.value:\n            all_items.extend(result.value)\n\n        # Check for next page or delta link\n        if hasattr(result, 'odata_next_link') and result.odata_next_link:\n            # More pages to fetch\n            result = await client.me.drive.root.delta.get()\n        elif hasattr(result, 'odata_delta_link') and result.odata_delta_link:\n            # Save delta link for future syncs\n            delta_link = result.odata_delta_link\n            break\n        else:\n            break\n\n    print(f\"Initial sync: {len(all_items)} items\")\n    print(f\"Delta link: {delta_link}\")\n\n    return all_items, delta_link\n\n# Get changes since last sync\nasync def get_delta_changes(client: GraphServiceClient, delta_token: str):\n    \"\"\"\n    Get changes since last delta sync\n\n    Args:\n        delta_token: Token from previous delta sync\n    \"\"\"\n    # Note: Use the full delta link URL saved from previous call\n    # This is a simplified example\n    result = await client.me.drive.root.delta.get()\n\n    changes = []\n\n    if result and result.value:\n        for item in result.value:\n            if hasattr(item, 'deleted') and item.deleted:\n                print(f\"Deleted: {item.id}\")\n                changes.append(('deleted', item))\n            else:\n                print(f\"Added/Modified: {item.name}\")\n                changes.append(('modified', item))\n\n    return changes\n```\n\n\n### 13. Special Folders\n\n```python\nasync def get_special_folders(client: GraphServiceClient):\n    \"\"\"Access special OneDrive folders\"\"\"\n\n    # Documents folder\n    documents = await client.me.drive.special.by_drive_item_id(\"documents\").get()\n    print(f\"Documents: {documents.name}\")\n\n    # Photos folder\n    photos = await client.me.drive.special.by_drive_item_id(\"photos\").get()\n    print(f\"Photos: {photos.name}\")\n\n    # Camera roll\n    cameraroll = await client.me.drive.special.by_drive_item_id(\"cameraroll\").get()\n    print(f\"Camera Roll: {cameraroll.name}\")\n\n    # App root folder\n    approot = await client.me.drive.special.by_drive_item_id(\"approot\").get()\n    print(f\"App Root: {approot.name}\")\n\n# List children of special folder\nasync def list_documents_folder(client: GraphServiceClient):\n    files = await client.me.drive.special.by_drive_item_id(\"documents\").children.get()\n\n    if files and files.value:\n        for file in files.value:\n            print(f\"{file.name}\")\n\n    return files.value\n```\n\n\n### 14. Working with SharePoint Document Libraries\n\n```python\nasync def get_sharepoint_drive(client: GraphServiceClient, site_id: str):\n    \"\"\"Access SharePoint site drive\"\"\"\n    drive = await client.sites.by_site_id(site_id).drive.get()\n\n    print(f\"Drive: {drive.name}\")\n    print(f\"Type: {drive.drive_type}\")\n\n    return drive\n\n# List SharePoint document library contents\nasync def list_sharepoint_files(client: GraphServiceClient, site_id: str):\n    items = await client.sites.by_site_id(site_id).drive.root.children.get()\n\n    if items and items.value:\n        for item in items.value:\n            print(f\"{item.name}\")\n\n    return items.value\n\n# Upload to SharePoint\nasync def upload_to_sharepoint(client: GraphServiceClient, site_id: str, file_path: str, upload_path: str):\n    async with aiofiles.open(file_path, 'rb') as f:\n        content = await f.read()\n\n    item = await client.sites.by_site_id(site_id).drive.root.item_with_path(upload_path).content.put(content)\n\n    return item\n\n# Get site by URL\nasync def get_site_by_path(client: GraphServiceClient, hostname: str, server_relative_path: str):\n    \"\"\"\n    Get SharePoint site by path\n\n    Example:\n        hostname: 'contoso.sharepoint.com'\n        server_relative_path: '/sites/marketing'\n    \"\"\"\n    site = await client.sites.by_site_id(f\"{hostname}:{server_relative_path}\").get()\n    return site\n```\n\n\n### 15. Batch Requests\n\n```python\nfrom msgraph.generated.models.batch_request_content import BatchRequestContent\nfrom msgraph.generated.models.batch_response_content import BatchResponseContent\n\nasync def batch_requests(client: GraphServiceClient):\n    \"\"\"Execute multiple requests in a single batch\"\"\"\n\n    # Create batch request\n    batch_request_content = BatchRequestContent()\n\n    # Add requests to batch\n    request1_id = batch_request_content.add_batch_request_step(\n        {\n            \"id\": \"1\",\n            \"method\": \"GET\",\n            \"url\": \"/me/drive/root/children\"\n        }\n    )\n\n    request2_id = batch_request_content.add_batch_request_step(\n        {\n            \"id\": \"2\",\n            \"method\": \"GET\",\n            \"url\": \"/me/drive/special/documents\"\n        }\n    )\n\n    # Execute batch\n    batch_response = await client.batch.post(batch_request_content)\n\n    # Process responses\n    for response_id, response in batch_response.get_responses().items():\n        print(f\"Request {response_id}: Status {response.status}\")\n        print(f\"Body: {response.body}\")\n```\n\n\n## Error Handling\n\n```python\nfrom msgraph.generated.models.o_data_errors.o_data_error import ODataError\nfrom azure.core.exceptions import HttpResponseError\n\nasync def safe_get_item(client: GraphServiceClient, item_id: str):\n    \"\"\"Example of comprehensive error handling\"\"\"\n    try:\n        item = await client.me.drive.items.by_drive_item_id(item_id).get()\n        return item\n\n    except ODataError as e:\n        print(f\"OData Error: {e.error.code if e.error else 'Unknown'}\")\n        print(f\"Message: {e.error.message if e.error else 'Unknown'}\")\n\n        if e.response_status_code == 404:\n            print(\"Item not found\")\n        elif e.response_status_code == 401:\n            print(\"Unauthorized - check authentication\")\n        elif e.response_status_code == 403:\n            print(\"Forbidden - check permissions\")\n        elif e.response_status_code == 429:\n            print(\"Too many requests - rate limited\")\n\n        return None\n\n    except HttpResponseError as e:\n        print(f\"HTTP Error: {e.status_code}\")\n        print(f\"Message: {e.message}\")\n        return None\n\n    except Exception as e:\n        print(f\"Unexpected error: {type(e).__name__}\")\n        print(f\"Details: {str(e)}\")\n        return None\n```\n\n\n## Complete Working Examples\n\n\n### Example 1: File Backup Script\n\n```python\nimport asyncio\nimport os\nfrom azure.identity.aio import ClientSecretCredential\nfrom msgraph import GraphServiceClient\nfrom dotenv import load_dotenv\nimport aiofiles\n\nload_dotenv()\n\nasync def backup_onedrive_folder(folder_id: str, local_backup_path: str):\n    \"\"\"Backup an entire OneDrive folder to local disk\"\"\"\n\n    # Initialize client\n    credentials = ClientSecretCredential(\n        tenant_id=os.getenv('AZURE_TENANT_ID'),\n        client_id=os.getenv('AZURE_CLIENT_ID'),\n        client_secret=os.getenv('AZURE_CLIENT_SECRET')\n    )\n\n    client = GraphServiceClient(\n        credentials=credentials,\n        scopes=['https://graph.microsoft.com/.default']\n    )\n\n    user_id = os.getenv('USER_ID')\n\n    async def download_folder_recursive(folder_id: str, local_path: str):\n        os.makedirs(local_path, exist_ok=True)\n\n        items = await client.users.by_user_id(user_id).drive.items.by_drive_item_id(folder_id).children.get()\n\n        if not items or not items.value:\n            return\n\n        for item in items.value:\n            if item.folder:\n                subfolder_path = os.path.join(local_path, item.name)\n                print(f\"Backing up folder: {item.name}\")\n                await download_folder_recursive(item.id, subfolder_path)\n\n            elif item.file:\n                file_path = os.path.join(local_path, item.name)\n                print(f\"Backing up file: {item.name} ({item.size} bytes)\")\n\n                stream = await client.users.by_user_id(user_id).drive.items.by_drive_item_id(item.id).content.get()\n\n                async with aiofiles.open(file_path, 'wb') as f:\n                    await f.write(stream)\n\n    await download_folder_recursive(folder_id, local_backup_path)\n    print(\"Backup complete!\")\n\nif __name__ == '__main__':\n    asyncio.run(backup_onedrive_folder('FOLDER_ID_HERE', './backup'))\n```\n\n\n### Example 2: Sync Local Directory to OneDrive\n\n```python\nimport asyncio\nimport os\nfrom pathlib import Path\nfrom azure.identity.aio import ClientSecretCredential\nfrom msgraph import GraphServiceClient\nfrom msgraph.generated.models.drive_item import DriveItem\nfrom msgraph.generated.models.folder import Folder\nimport aiofiles\n\nasync def sync_to_onedrive(local_path: str, onedrive_folder_id: str):\n    \"\"\"Sync local directory to OneDrive\"\"\"\n\n    credentials = ClientSecretCredential(\n        tenant_id=os.getenv('AZURE_TENANT_ID'),\n        client_id=os.getenv('AZURE_CLIENT_ID'),\n        client_secret=os.getenv('AZURE_CLIENT_SECRET')\n    )\n\n    client = GraphServiceClient(\n        credentials=credentials,\n        scopes=['https://graph.microsoft.com/.default']\n    )\n\n    user_id = os.getenv('USER_ID')\n\n    async def sync_folder(local_dir: str, parent_id: str):\n        for entry in os.listdir(local_dir):\n            entry_path = os.path.join(local_dir, entry)\n\n            if os.path.isdir(entry_path):\n                # Create folder in OneDrive\n                drive_item = DriveItem()\n                drive_item.name = entry\n                drive_item.folder = Folder()\n                drive_item.microsoft_graph_conflict_behavior = \"replace\"\n\n                folder = await client.users.by_user_id(user_id).drive.items.by_drive_item_id(parent_id).children.post(drive_item)\n                print(f\"Created folder: {entry}\")\n\n                # Recursively sync subfolder\n                await sync_folder(entry_path, folder.id)\n\n            else:\n                # Upload file\n                file_size = os.path.getsize(entry_path)\n                print(f\"Uploading {entry} ({file_size} bytes)...\")\n\n                if file_size < 4 * 1024 * 1024:\n                    # Small file\n                    async with aiofiles.open(entry_path, 'rb') as f:\n                        content = await f.read()\n\n                    await client.users.by_user_id(user_id).drive.items.by_drive_item_id(parent_id).item_with_path(entry).content.put(content)\n                else:\n                    # Large file - would need upload session (simplified here)\n                    print(f\"Skipping large file: {entry}\")\n\n                print(f\"Uploaded: {entry}\")\n\n    await sync_folder(local_path, onedrive_folder_id)\n    print(\"Sync complete!\")\n\nif __name__ == '__main__':\n    asyncio.run(sync_to_onedrive('./local-folder', 'ONEDRIVE_FOLDER_ID'))\n```\n\n\n### Example 3: Share Files with Team\n\n```python\nimport asyncio\nfrom azure.identity.aio import ClientSecretCredential\nfrom msgraph import GraphServiceClient\nfrom msgraph.generated.drives.item.items.item.invite.invite_post_request_body import InvitePostRequestBody\nfrom msgraph.generated.models.drive_recipient import DriveRecipient\n\nasync def share_folder_with_team(folder_id: str, team_emails: list):\n    \"\"\"Share a folder with team members\"\"\"\n\n    credentials = ClientSecretCredential(\n        tenant_id=os.getenv('AZURE_TENANT_ID'),\n        client_id=os.getenv('AZURE_CLIENT_ID'),\n        client_secret=os.getenv('AZURE_CLIENT_SECRET')\n    )\n\n    client = GraphServiceClient(\n        credentials=credentials,\n        scopes=['https://graph.microsoft.com/.default']\n    )\n\n    user_id = os.getenv('USER_ID')\n\n    # Get folder info\n    folder = await client.users.by_user_id(user_id).drive.items.by_drive_item_id(folder_id).get()\n    print(f\"Sharing folder: {folder.name}\")\n\n    # Invite users\n    request_body = InvitePostRequestBody()\n    request_body.require_sign_in = True\n    request_body.send_invitation = True\n    request_body.roles = [\"write\"]\n    request_body.message = f\"You've been invited to collaborate on {folder.name}\"\n\n    recipients = []\n    for email in team_emails:\n        recipient = DriveRecipient()\n        recipient.email = email\n        recipients.append(recipient)\n\n    request_body.recipients = recipients\n\n    permissions = await client.users.by_user_id(user_id).drive.items.by_drive_item_id(folder_id).invite.post(request_body)\n\n    print(f\"Successfully shared with {len(team_emails)} team members\")\n\n    return permissions\n\nif __name__ == '__main__':\n    team = ['alice@example.com', 'bob@example.com', 'charlie@example.com']\n    asyncio.run(share_folder_with_team('FOLDER_ID', team))\n```\n\n\n## Rate Limiting and Throttling\n\n```python\nimport asyncio\nfrom msgraph.generated.models.o_data_errors.o_data_error import ODataError\n\nasync def request_with_retry(client, request_func, max_retries=3):\n    \"\"\"Make request with automatic retry on rate limit\"\"\"\n    retries = 0\n\n    while retries < max_retries:\n        try:\n            return await request_func()\n\n        except ODataError as e:\n            if e.response_status_code == 429:\n                # Rate limited\n                retry_after = 5  # Default wait time\n\n                if e.response_headers and 'Retry-After' in e.response_headers:\n                    retry_after = int(e.response_headers['Retry-After'])\n\n                print(f\"Rate limited. Waiting {retry_after} seconds...\")\n                await asyncio.sleep(retry_after)\n                retries += 1\n            else:\n                raise\n\n    raise Exception(\"Max retries exceeded\")\n\n# Usage\nasync def example_with_retry(client: GraphServiceClient):\n    result = await request_with_retry(\n        client,\n        lambda: client.me.drive.root.children.get()\n    )\n    return result\n```\n\n\n## Testing Helper Functions\n\n```python\nasync def test_connection(client: GraphServiceClient):\n    \"\"\"Test if client is properly configured\"\"\"\n    try:\n        me = await client.me.get()\n        print(f\"Connected as: {me.display_name}\")\n        print(f\"Email: {me.user_principal_name}\")\n        return True\n    except Exception as e:\n        print(f\"Connection test failed: {e}\")\n        return False\n\nasync def get_drive_info(client: GraphServiceClient):\n    \"\"\"Get OneDrive quota and usage information\"\"\"\n    drive = await client.me.drive.get()\n\n    quota = drive.quota\n\n    if quota:\n        total = quota.total / (1024**3)  # Convert to GB\n        used = quota.used / (1024**3)\n        remaining = quota.remaining / (1024**3)\n\n        print(f\"OneDrive Storage:\")\n        print(f\"  Total: {total:.2f} GB\")\n        print(f\"  Used: {used:.2f} GB\")\n        print(f\"  Remaining: {remaining:.2f} GB\")\n        print(f\"  State: {quota.state}\")\n\n    return quota\n```\n"
  },
  {
    "path": "content/minimatch/docs/minimatch/javascript/DOC.md",
    "content": "---\nname: minimatch\ndescription: \"Glob pattern matching and glob-to-RegExp utilities for JavaScript paths and filenames\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.2.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,glob,pattern-matching,paths,regex\"\n---\n\n# minimatch for JavaScript\n\nUse `minimatch` to test strings or paths against Bash-style glob patterns, filter in-memory lists, expand braces, and compile glob patterns into reusable matchers or regular expressions.\n\n## Install\n\n```bash\nnpm install minimatch\n```\n\nThe published `10.2.4` package declares these supported Node.js versions:\n\n- `18`\n- `20`\n- `>=22`\n\n## Import and setup\n\n`minimatch` does not use environment variables, authentication, or client initialization.\n\nThe package supports both ESM and CommonJS:\n\n```js\nimport { minimatch, Minimatch, braceExpand, makeRe, match, escape, unescape } from 'minimatch';\n```\n\n```js\nconst {\n  minimatch,\n  Minimatch,\n  braceExpand,\n  makeRe,\n  match,\n  escape,\n  unescape,\n} = require('minimatch');\n```\n\n## Match a path or filename\n\nUse `minimatch(path, pattern, options)` for one-off checks.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(minimatch('src/app.js', 'src/*.js'));\n// true\n\nconsole.log(minimatch('src/app.ts', 'src/*.js'));\n// false\n\nconsole.log(minimatch('src/app.test.js', 'src/**/!(*.spec).js'));\n// true\n```\n\nSupported pattern features in the maintainer README include:\n\n- Brace expansion: `src/*.{js,ts}`\n- Extglobs: `+(api|ui).js`, `!(*.test).js`\n- Globstars: `src/**/*.js`\n- POSIX character classes: `[[:alpha:]]`, `[[:digit:]]`\n\n## Filter a list of paths\n\n`minimatch` matches the strings you give it. It does not scan the filesystem.\n\nUse `match()` to filter a list in one call, or `minimatch.filter()` when you need a predicate function.\n\n```js\nimport { minimatch, match } from 'minimatch';\n\nconst files = [\n  'src/index.js',\n  'src/index.test.js',\n  'src/utils/format.js',\n  'README.md',\n];\n\nconst jsFiles = match(files, 'src/**/*.js');\nconst nonTestFiles = files.filter(\n  minimatch.filter('src/**/!(*.test).js')\n);\n\nconsole.log(jsFiles);\nconsole.log(nonTestFiles);\n```\n\nIf you want the original pattern back when nothing matches, pass `nonull: true`:\n\n```js\nimport { match } from 'minimatch';\n\nconsole.log(match(['README.md'], '**/*.ts', { nonull: true }));\n// ['**/*.ts']\n```\n\n## Reuse a compiled matcher\n\nUse `new Minimatch(pattern, options)` when you will test many paths against the same pattern.\n\n```js\nimport { Minimatch } from 'minimatch';\n\nconst mm = new Minimatch('src/**/*.{js,ts}', {\n  dot: false,\n  nocase: false,\n});\n\nconsole.log(mm.hasMagic());\n// true\n\nfor (const file of ['src/index.js', 'src/.hidden.js', 'test/index.js']) {\n  if (mm.match(file)) {\n    console.log(`matched: ${file}`);\n  }\n}\n```\n\nUse `makeRe()` when another API expects a `RegExp`:\n\n```js\nimport { makeRe } from 'minimatch';\n\nconst regex = makeRe('src/*.{js,ts}');\n\nif (!regex) {\n  throw new Error('Invalid glob pattern');\n}\n\nconsole.log(regex.test('src/index.js'));\n// true\n```\n\n## Expand braces or treat patterns literally\n\nUse `braceExpand()` to inspect what a brace pattern becomes:\n\n```js\nimport { braceExpand } from 'minimatch';\n\nconsole.log(braceExpand('src/*.{js,ts,tsx}'));\n// ['src/*.js', 'src/*.ts', 'src/*.tsx']\n```\n\nUse `escape()` before matching a user-controlled filename as a literal string rather than as a glob pattern.\n\n```js\nimport { escape, minimatch, unescape } from 'minimatch';\n\nconst literalName = 'docs/[draft].md';\nconst safePattern = escape(literalName);\n\nconsole.log(safePattern);\nconsole.log(minimatch('docs/[draft].md', safePattern));\n// true\n\nconsole.log(unescape(safePattern));\n// 'docs/[draft].md'\n```\n\nSlashes cannot be escaped or unescaped. In `windowsPathsNoEscape` mode, backslashes also cannot be escaped or unescaped.\n\n## Important options\n\n### Match dotfiles\n\nLike Bash, filenames starting with `.` are not matched unless the pattern starts with `.` or you set `dot: true`.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(minimatch('.eslintrc.js', '*.js'));\n// false\n\nconsole.log(minimatch('.eslintrc.js', '*.js', { dot: true }));\n// true\n```\n\n### Match the basename when the pattern has no slash\n\nBy default, `*.js` does not match `src/app.js`. Set `matchBase: true` to match against the last path segment.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(minimatch('src/app.js', '*.js'));\n// false\n\nconsole.log(minimatch('src/app.js', '*.js', { matchBase: true }));\n// true\n```\n\n### Allow case-insensitive matching\n\nUse `nocase: true` when your application should treat path case as equivalent.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(minimatch('SRC/App.JS', 'src/*.js'));\n// false\n\nconsole.log(minimatch('SRC/App.JS', 'src/*.js', { nocase: true }));\n// true\n```\n\n### Match partial paths during directory walking\n\nUse `partial: true` when you are traversing directories and want to keep paths that could still become a full match later.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(minimatch('/a/b', '/a/*/c/d', { partial: true }));\n// true\n\nconsole.log(minimatch('/a/b', '/**/d', { partial: true }));\n// true\n\nconsole.log(minimatch('/x/y/z', '/a/**/z', { partial: true }));\n// false\n```\n\n### Disable specific glob syntax\n\nUse these options when you need more literal or restricted pattern behavior:\n\n- `nobrace`: disable brace expansion\n- `noglobstar`: treat `**` like `*`\n- `noext`: disable extglobs such as `+(a|b)`\n- `nonegate`: treat a leading `!` as a literal character\n- `nocomment`: treat a leading `#` as a normal pattern\n\n## Windows and path separators\n\nWrite glob patterns with forward slashes only.\n\n```js\nimport { minimatch } from 'minimatch';\nimport path from 'node:path';\n\nconst filePath = path.join('src', 'app.js');\n\nconsole.log(filePath);\n// 'src\\\\app.js' on Windows\n\nconsole.log(minimatch(filePath, 'src/*.js'));\n// true on Windows and POSIX\n```\n\nDo not build glob patterns with `path.join()` on Windows, because backslashes in patterns are treated as escape characters by default.\n\n```js\nimport { minimatch } from 'minimatch';\nimport path from 'node:path';\n\nconst badPattern = path.join('src', '*.js');\n\nconsole.log(badPattern);\n// 'src\\\\*.js' on Windows\n\nconsole.log(minimatch('src/app.js', badPattern));\n// not the same as matching against 'src/*.js'\n```\n\nIf you intentionally need Windows-style separators in the pattern, use `windowsPathsNoEscape: true`.\n\n```js\nimport { minimatch } from 'minimatch';\n\nconsole.log(\n  minimatch('src\\\\app.js', 'src\\\\*.js', {\n    windowsPathsNoEscape: true,\n    platform: 'win32',\n  })\n);\n// true\n```\n\n`platform: 'win32'` enables Windows-specific behavior such as UNC path handling and treating `\\\\` as a separator in file paths.\n\n## Security and correctness pitfalls\n\n- Do not treat untrusted user input as a safe glob pattern. The maintainer explicitly warns that JavaScript glob matchers built on regular expressions are vulnerable to ReDoS when attackers control the pattern.\n- `minimatch` matches strings you pass in; use another library such as `glob` if you need filesystem traversal.\n- Patterns starting with `#` are comments unless you set `nocomment: true`.\n- Patterns starting with `!` are negated unless you set `nonegate: true`.\n- If you raise `optimizationLevel` to `2` or higher, `Minimatch.match()` keeps path optimization aligned with the pattern, but testing raw paths directly against the `RegExp` returned by `makeRe()` can differ unless the path is optimized in the same way.\n- Defaults like `maxGlobstarRecursion` and `maxExtglobRecursion` exist for performance and safety. Extremely deep or malicious patterns may intentionally produce false negatives instead of exhaustive matching.\n\n## Minimal example\n\n```js\nimport { match, minimatch } from 'minimatch';\n\nconst changedFiles = [\n  'src/index.js',\n  'src/index.test.js',\n  'src/components/button.ts',\n  '.github/workflows/ci.yml',\n];\n\nconst buildInputs = match(changedFiles, 'src/**/*.{js,ts}');\nconst shouldRunUnitTests = changedFiles.some((file) =>\n  minimatch(file, 'src/**/!(*.test).{js,ts}')\n);\n\nconsole.log({ buildInputs, shouldRunUnitTests });\n```\n"
  },
  {
    "path": "content/mistralai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Mistral AI Python SDK for chat completions, embeddings, files, OCR, and related platform APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mistral,mistralai,llm,chat,embeddings,ocr,agents\"\n---\n\n# mistralai Python Package Guide\n\n## Golden Rule\n\nFor `mistralai==2.0.0`, use the current official v2 SDK patterns and check the migration guide before copying older code.\n\n- New code can follow the official README import style: `from mistralai import Mistral`\n- If you are migrating v1 code, replace `MistralClient` with `Mistral`\n- Treat responses as typed models, not plain dictionaries\n\n## Installation\n\n```bash\npip install mistralai==2.0.0\n```\n\n```bash\nuv add mistralai==2.0.0\n```\n\n```bash\npoetry add mistralai==2.0.0\n```\n\nOptional extras exposed by the package metadata:\n\n- `mistralai[agents]`\n- `mistralai[gcp]`\n- `mistralai[realtime]`\n\nUse an extra only if you need that surface. The base package is enough for normal chat, embeddings, files, and OCR calls.\n\n## Authentication And Client Setup\n\nSet a Mistral API key in the environment:\n\n```bash\nexport MISTRAL_API_KEY=\"your_api_key\"\n```\n\nBasic client setup:\n\n```python\nimport os\n\nfrom mistralai import Mistral\n\nclient = Mistral(api_key=os.environ[\"MISTRAL_API_KEY\"])\n```\n\nPractical setup notes:\n\n- Fail fast if `MISTRAL_API_KEY` is missing instead of silently constructing a broken client.\n- Keep the client as a shared object in your app instead of recreating it per request.\n- If you are targeting Azure, GCP, Cloudflare, or Mistral Europe deployments, use the official migration guide for provider-specific initialization instead of adapting generic OpenAI examples.\n\n## Core Usage\n\n### Chat Completion\n\n```python\nimport os\n\nfrom mistralai import Mistral\n\nclient = Mistral(api_key=os.environ[\"MISTRAL_API_KEY\"])\n\nresponse = client.chat.complete(\n    model=\"mistral-small-latest\",\n    messages=[\n        {\n            \"role\": \"user\",\n            \"content\": \"Summarize HTTP caching in 3 bullets.\",\n        }\n    ],\n)\n\nprint(response.choices[0].message.content)\n```\n\nUse model aliases like `mistral-small-latest` only when you want the provider-selected latest model for that family. For reproducible behavior, pin a concrete model name from the official model docs instead of relying on a moving alias.\n\n### Streaming\n\n```python\nimport os\n\nfrom mistralai import Mistral\n\nclient = Mistral(api_key=os.environ[\"MISTRAL_API_KEY\"])\n\nstream = client.chat.stream(\n    model=\"mistral-small-latest\",\n    messages=[{\"role\": \"user\", \"content\": \"Count from 1 to 5.\"}],\n)\n\nfor event in stream:\n    delta = event.data.choices[0].delta.content\n    if delta is not None:\n        print(delta, end=\"\", flush=True)\nprint()\n```\n\nWhen streaming, assemble text incrementally from `delta.content`. Do not assume each event contains a full message.\n\n### Embeddings\n\n```python\nimport os\n\nfrom mistralai import Mistral\n\nclient = Mistral(api_key=os.environ[\"MISTRAL_API_KEY\"])\n\nresponse = client.embeddings.create(\n    model=\"mistral-embed\",\n    inputs=[\"first text\", \"second text\"],\n)\n\nvectors = [item.embedding for item in response.data]\nprint(len(vectors), len(vectors[0]))\n```\n\nThe response is model-backed data, so use attribute access like `response.data` and `item.embedding`.\n\n### File Upload And OCR\n\nOCR requires an upload step first.\n\n```python\nimport os\n\nfrom mistralai import Mistral\n\nclient = Mistral(api_key=os.environ[\"MISTRAL_API_KEY\"])\n\nwith open(\"invoice.pdf\", \"rb\") as handle:\n    uploaded = client.files.upload(\n        file={\"file_name\": \"invoice.pdf\", \"content\": handle},\n        purpose=\"ocr\",\n    )\n\nocr_response = client.ocr.process(\n    model=\"mistral-ocr-latest\",\n    document={\n        \"type\": \"file\",\n        \"file_id\": uploaded.id,\n    },\n)\n\nprint(ocr_response.pages[0].markdown)\n```\n\nIf you skip the upload and pass a local path directly to `ocr.process`, the call will fail. Upload first, then pass the returned file id.\n\n## Configuration Notes\n\n### Version-Sensitive Imports\n\nOfficial sources currently show two valid-looking v2 styles:\n\n- README examples use `from mistralai import Mistral`\n- The migration guide describes the v1 to v2 class rename as `MistralClient` to `mistralai.client.Mistral`\n\nUse one v2 style consistently in a codebase and do not mix in `MistralClient` or old async-client imports from v1 examples.\n\n### Typed Responses\n\nThe migration guide explicitly calls out that responses are now Pydantic-based models instead of plain dictionaries.\n\nUse:\n\n```python\ntext = response.choices[0].message.content\npayload = response.model_dump()\n```\n\nDo not write:\n\n```python\ntext = response[\"choices\"][0][\"message\"][\"content\"]\n```\n\n### Cloud And Provider Routing\n\nThe v2 migration guide documents provider-specific initialization for:\n\n- hosted Mistral API\n- Mistral Europe\n- Cloudflare\n- Azure\n- GCP\n\nIf your project uses a non-default provider, check the migration guide before adding base URLs, auth headers, or provider-specific environment variables. The setup is not interchangeable with OpenAI-compatible clients.\n\n## Common Pitfalls\n\n- Mixing v1 and v2 examples. `MistralClient`, `ChatMessage`, and dict-style response handling are migration clues that you are looking at older code.\n- Assuming the SDK version pins a model version. SDK version `2.0.0` and model aliases like `mistral-small-latest` are separate concerns.\n- Treating streamed events like final responses. Build the output from deltas.\n- Forgetting the file upload step for OCR and other file-based workflows.\n- Copying third-party snippets that use unofficial import paths or outdated async helpers.\n\n## Recommended Agent Workflow\n\n1. Install `mistralai==2.0.0` and confirm Python `>=3.9`.\n2. Set `MISTRAL_API_KEY` and create a single shared `Mistral` client.\n3. Start with `chat.complete` or `chat.stream` for normal LLM calls.\n4. Add `embeddings.create`, `files.upload`, or `ocr.process` only when the task actually needs them.\n5. Check the migration guide before reusing any example that mentions `MistralClient`, `ChatMessage`, or dict indexing.\n\n## Official Sources Used For This Entry\n\n- Docs root: `https://docs.mistral.ai/`\n- PyPI project: `https://pypi.org/project/mistralai/`\n- PyPI JSON metadata: `https://pypi.org/pypi/mistralai/json`\n- Official Python SDK repository: `https://github.com/mistralai/client-python`\n- Official migration guide: `https://github.com/mistralai/client-python/blob/main/MIGRATION.md`\n"
  },
  {
    "path": "content/mkdirp/docs/mkdirp/javascript/DOC.md",
    "content": "---\nname: mkdirp\ndescription: \"Use `mkdirp` to create nested directories from JavaScript or the CLI, with promise and sync APIs, mode options, and implementation-selection notes.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"mkdirp,node,filesystem,directories,cli,javascript,npm\"\n---\n\n# mkdirp JavaScript Guide\n\n`mkdirp` creates a directory and any missing parent directories, similar to `mkdir -p`.\n\nIt works in both ESM and CommonJS projects, ships async and sync APIs, and includes a CLI. There are no credentials, network settings, or package-specific initialization steps.\n\n## Install\n\nLibrary usage:\n\n```bash\nnpm install mkdirp\n```\n\nCLI usage without a local install:\n\n```bash\nnpx mkdirp --help\n```\n\n`mkdirp@3.0.1` declares `node >=10` in `package.json`. The package uses Node's native recursive `fs.mkdir()` path on Node `10.12.0+` when possible.\n\n## Import And Basic Usage\n\nESM:\n\n```js\nimport { mkdirp } from 'mkdirp'\n```\n\nCommonJS:\n\n```js\nconst { mkdirp } = require('mkdirp')\n```\n\nCreate an application data directory before writing a file:\n\n```js\nimport { mkdirp } from 'mkdirp'\nimport { writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nconst appDataDir = process.env.APP_DATA_DIR ?? './var/app-data'\n\nawait mkdirp(appDataDir)\n\nawait writeFile(\n  join(appDataDir, 'settings.json'),\n  JSON.stringify({ theme: 'dark' }, null, 2),\n  'utf8'\n)\n```\n\n`mkdirp()` resolves to the first directory it actually created, or `undefined` when the full path already exists.\n\n## Common Workflows\n\n### Create a nested directory and inspect what was created\n\n```js\nimport { mkdirp } from 'mkdirp'\n\nconst made = await mkdirp('./var/cache/images')\n\nif (made) {\n  console.log(`created starting at ${made}`)\n} else {\n  console.log('directory tree already existed')\n}\n```\n\nThe returned `made` value is the first directory that did not already exist.\n\n### Create directories synchronously during startup\n\nUse the sync API when later startup work must not begin until the directory exists.\n\n```js\nimport { mkdirp } from 'mkdirp'\nimport { createWriteStream } from 'node:fs'\nimport { join } from 'node:path'\n\nconst logDir = process.env.LOG_DIR ?? './var/log'\n\nmkdirp.sync(logDir)\n\nconst stream = createWriteStream(join(logDir, 'app.log'), { flags: 'a' })\nstream.write('server started\\n')\nstream.end()\n```\n\n### Set a directory mode\n\nPass either an options object, a number, or an octal string.\n\n```js\nimport { mkdirp } from 'mkdirp'\n\nawait mkdirp('./var/shared/uploads', { mode: 0o775 })\nawait mkdirp('./var/private/cache', 0o700)\nawait mkdirp('./var/releases', '755')\n```\n\nIf you omit `mode`, `mkdirp` uses `0o777` and lets the operating system apply the process umask.\n\n### Force the native or manual implementation\n\nThe default `mkdirp()` entry point selects an implementation for you. Use an explicit variant only when you need to control that choice.\n\n```js\nimport { mkdirp } from 'mkdirp'\n\nawait mkdirp.native('./var/native-cache')\nawait mkdirp.manual('./var/manual-cache')\n```\n\nAt `3.0.1`, the package uses the native recursive implementation on Node `10.12.0+` unless you override the filesystem methods through options.\n\n### Use a custom `fs` implementation\n\nYou can swap in another filesystem implementation, or override just the methods that `mkdirp` uses.\n\n```js\nimport { mkdirp } from 'mkdirp'\nimport { mkdir, stat } from 'node:fs'\n\nawait mkdirp('./sandbox/output', {\n  fs: {\n    mkdir,\n    stat,\n  },\n})\n```\n\nFor async usage, the package expects `mkdir(path, opts, cb)` and `stat(path, cb)`. For sync usage, provide `mkdirSync(path, opts)` and `statSync(path)`.\n\n## CLI\n\nThe package ships a `mkdirp` command.\n\nCreate one or more directories:\n\n```bash\nnpx mkdirp ./var/cache ./var/log\n```\n\nPrint the first created path for each argument and set a mode:\n\n```bash\nnpx mkdirp --print --mode=755 ./var/cache ./var/log\n```\n\nForce the manual implementation:\n\n```bash\nnpx mkdirp --manual ./var/cache\n```\n\nAvailable flags from the packaged CLI are:\n\n- `-m<mode>` or `--mode=<mode>`\n- `-p` or `--print`\n- `--manual`\n- `-v` or `--version`\n- `-h` or `--help`\n\n## Important Pitfalls\n\n- `mkdirp()` returns the first directory created, not always the final target path.\n- The package resolves input paths before creating directories, so relative input paths produce absolute resolved return values.\n- Recursive creation is not atomic. If a call fails partway through, some parent directories may already exist.\n- Root-directory behavior differs by platform. On Windows, attempting to create a drive root or UNC root can fail with `EPERM` or `ENOENT`; on POSIX, recursive creation of `/` is treated as already existing.\n- The package retries with its manual implementation when the native recursive path hits `ENOENT`, because Node's native error reporting can be misleading in some cases.\n- If you override filesystem methods, provide the async or sync methods that match the API you are calling.\n\n## Version Notes For `3.0.1`\n\n- The package is a hybrid module: the maintainer README shows both `import { mkdirp } from 'mkdirp'` and `const { mkdirp } = require('mkdirp')`.\n- `3.0.1` publishes declaration files and `exports` metadata from the runtime package itself.\n- The package still includes the `mkdirp` CLI in this release.\n"
  },
  {
    "path": "content/mkdocs/docs/material/python/DOC.md",
    "content": "---\nname: material\ndescription: \"Material for MkDocs package guide for building and customizing MkDocs documentation sites\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.7.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mkdocs-material,mkdocs,python,documentation,static-site,theme\"\n---\n\n# Material for MkDocs Python Package Guide\n\n## Golden Rule\n\n`mkdocs-material` is the Material theme package for MkDocs. Configure it in `mkdocs.yml` with `theme.name: material`, and do normal development through the `mkdocs` CLI. For standard usage there is no Python import, client object, or API key.\n\n## Install\n\nInstall the theme into the same Python environment that will run `mkdocs`:\n\n```bash\npython -m pip install \"mkdocs-material==9.7.5\"\n```\n\nConfirm the CLI is available:\n\n```bash\nmkdocs --version\n```\n\n## No Auth Or Environment Variables\n\nMaterial for MkDocs does not require service credentials for normal use.\n\n- No API key or token is required.\n- No Python initialization step is required.\n- Day-to-day setup lives in `mkdocs.yml` and the `docs/` directory.\n\n## Start A New Site\n\nCreate a new MkDocs project, then switch the theme to Material:\n\n```bash\nmkdocs new my-docs\ncd my-docs\n```\n\nMinimal `mkdocs.yml`:\n\n```yaml\nsite_name: My Docs\ntheme:\n  name: material\nplugins:\n  - search\nnav:\n  - Home: index.md\n```\n\nMinimal `docs/index.md`:\n\n```md\n# My Docs\n\nWelcome to the project documentation.\n```\n\nRun the local development server:\n\n```bash\nmkdocs serve\n```\n\nBuild the static site:\n\n```bash\nmkdocs build\n```\n\n## Common Configuration\n\n### Enable common Material features\n\nPut Material-specific UI options under `theme.features`:\n\n```yaml\nsite_name: My Docs\ntheme:\n  name: material\n  features:\n    - navigation.tabs\n    - navigation.sections\n    - content.code.copy\n  palette:\n    primary: indigo\n    accent: indigo\n```\n\nThis is the normal place to enable navigation behaviors, code-copy buttons, and theme colors.\n\n### Enable Markdown extensions for Material components\n\nMany Material components depend on Python Markdown and `pymdown-extensions` settings. If you want admonitions, expandable blocks, or tabbed content, enable the matching extensions explicitly:\n\n```yaml\nmarkdown_extensions:\n  - admonition\n  - pymdownx.details\n  - pymdownx.superfences\n  - pymdownx.tabbed:\n      alternate_style: true\n```\n\nExample Markdown that uses those extensions:\n\n````markdown\n!!! note\n    Material components render correctly only when the related Markdown extensions are enabled.\n\n=== \"Python\"\n\n    ```python\n    print(\"hello\")\n    ```\n\n=== \"Bash\"\n\n    ```bash\n    echo \"hello\"\n    ```\n````\n\nIf you add Material-specific markup without the corresponding extensions, the page usually renders the raw syntax instead of the intended component.\n\n### Add custom CSS, JavaScript, and theme overrides\n\nUse `extra_css` and `extra_javascript` for static assets, and `theme.custom_dir` for template overrides:\n\n```yaml\ntheme:\n  name: material\n  custom_dir: overrides\n\nextra_css:\n  - stylesheets/extra.css\n\nextra_javascript:\n  - javascripts/extra.js\n```\n\nTypical project layout:\n\n```text\nmy-docs/\n  docs/\n    index.md\n    stylesheets/\n      extra.css\n    javascripts/\n      extra.js\n  overrides/\n    main.html\n  mkdocs.yml\n```\n\nKeep static assets under `docs/` so MkDocs copies them into the built site. Use `overrides/` only for theme template overrides.\n\n## Common Commands\n\n```bash\nmkdocs serve\nmkdocs build\nmkdocs build --clean\n```\n\nUse `mkdocs serve` for local iteration and `mkdocs build` in CI or deployment jobs.\n\n## Common Pitfalls\n\n- Set `theme.name: material`, not `theme.name: mkdocs-material`.\n- Keep using the `mkdocs` CLI after installation; `mkdocs-material` is not a separate executable.\n- Enable the matching `markdown_extensions` for any Material component syntax you add to content.\n- Put template overrides in the directory referenced by `theme.custom_dir`, but keep CSS and JavaScript files inside `docs/` and reference them with `extra_css` and `extra_javascript`.\n- Install the package into the same environment that runs the docs build, especially in CI or containerized deploys.\n\n## Official Sources\n\n- Maintainer docs home: `https://squidfunk.github.io/mkdocs-material/`\n- Getting started: `https://squidfunk.github.io/mkdocs-material/getting-started/`\n- Setup and configuration: `https://squidfunk.github.io/mkdocs-material/setup/`\n- Python Markdown extensions: `https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown/`\n- Component reference: `https://squidfunk.github.io/mkdocs-material/reference/`\n- PyPI release page: `https://pypi.org/project/mkdocs-material/9.7.5/`\n"
  },
  {
    "path": "content/mkdocs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"MkDocs package guide for building and deploying Markdown documentation sites from Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mkdocs,python,documentation,static-site,markdown\"\n---\n\n# MkDocs Python Package Guide\n\n## Golden Rule\n\nUse MkDocs through a checked-in `mkdocs.yml` file and a `docs/` content directory, then preview with `mkdocs serve` and publish the generated `site/` output. MkDocs is a static site generator, not a runtime application framework: there is no client object to initialize and no package-specific auth flow.\n\n## Install\n\nCreate a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"mkdocs==1.6.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"mkdocs==1.6.1\"\npoetry add --group docs \"mkdocs==1.6.1\"\n```\n\nMkDocs does not require API keys, tokens, or service credentials for normal local use. The main configuration surface is `mkdocs.yml`; deployment credentials, if needed, come from your git host or CI platform rather than from MkDocs itself.\n\n## Initialize A Project\n\nScaffold a new docs site:\n\n```bash\nmkdocs new mydocs\ncd mydocs\nmkdocs serve\n```\n\nThis creates a small project like:\n\n```text\nmydocs/\n  mkdocs.yml\n  docs/\n    index.md\n```\n\n`mkdocs serve` starts the development server and rebuilds the site when files change.\n\n## Minimal Configuration\n\n`mkdocs.yml`\n\n```yaml\nsite_name: Example Docs\nsite_url: https://docs.example.com/\ndocs_dir: docs\nsite_dir: site\n\ntheme:\n  name: mkdocs\n\nnav:\n  - Home: index.md\n  - Getting Started: getting-started.md\n\nplugins:\n  - search\n```\n\nAdd the referenced page:\n\n`docs/getting-started.md`\n\n```md\n# Getting Started\n\nInstall the project dependencies, then run the app locally.\n```\n\nWhat these keys do:\n\n- `site_name`: title shown in the generated site\n- `site_url`: public base URL for the deployed docs site\n- `docs_dir`: directory containing Markdown pages and static assets\n- `site_dir`: output directory for generated HTML\n- `theme.name`: active theme; MkDocs includes `mkdocs` and `readthedocs`\n- `nav`: explicit page order and labels\n- `plugins`: enabled plugins; `search` keeps the built-in search feature active\n\n## Core Workflow\n\n### Preview locally\n\n```bash\nmkdocs serve\n```\n\nBind the dev server to a specific address if needed:\n\n```bash\nmkdocs serve -a 127.0.0.1:8000\n```\n\n### Build the static site\n\n```bash\nmkdocs build\n```\n\nFor CI, prefer strict mode so warnings fail the build:\n\n```bash\nmkdocs build --strict\n```\n\n### Publish to GitHub Pages\n\n```bash\nmkdocs gh-deploy\n```\n\nUse `gh-deploy` only in a git repository with the correct remote configured. It publishes the generated site to the `gh-pages` branch.\n\n## Common Configuration Options\n\nThese settings are the ones most projects reach for first:\n\n- `nav`: define the left-nav or top-nav order instead of relying on file discovery\n- `theme`: choose the built-in theme or an installed theme package\n- `plugins`: enable search and any additional installed plugins\n- `markdown_extensions`: turn on Python-Markdown extensions such as tables, admonitions, or table-of-contents links\n- `repo_url` and `edit_uri`: link the deployed docs back to the source repository and edit page locations\n- `extra_css` and `extra_javascript`: ship additional local static assets with the site\n\nExample with a few common additions:\n\n```yaml\nsite_name: Example Docs\nsite_url: https://docs.example.com/\nrepo_url: https://github.com/example/example-repo\nedit_uri: edit/main/docs/\n\ntheme:\n  name: readthedocs\n\nplugins:\n  - search\n\nmarkdown_extensions:\n  - admonition\n  - tables\n  - toc:\n      permalink: true\n```\n\n## Common Pitfalls\n\n- Do not treat `mkdocs serve` as a production web server. Deploy the generated `site/` output with your normal static hosting flow.\n- If you set `plugins:` explicitly, keep `search` in the list if you still want the built-in search UI.\n- When you define `nav`, every referenced Markdown file must exist under `docs_dir` or the build will fail.\n- Do not hand-edit files under `site/`; they are generated artifacts and will be replaced on the next build.\n- Theme packages and plugin packages are normal Python dependencies. Install them into the same environment as `mkdocs` before referencing them in `mkdocs.yml`.\n- `mkdocs gh-deploy` assumes a git-based deployment flow. If your team deploys through another platform, use `mkdocs build` and publish the `site/` directory there instead.\n\n## Official Sources\n\n- MkDocs docs root: https://www.mkdocs.org/\n- Getting started: https://www.mkdocs.org/getting-started/\n- Installation guide: https://www.mkdocs.org/user-guide/installation/\n- Writing your docs: https://www.mkdocs.org/user-guide/writing-your-docs/\n- Configuration reference: https://www.mkdocs.org/user-guide/configuration/\n- CLI reference: https://www.mkdocs.org/user-guide/cli/\n- Deploying your docs: https://www.mkdocs.org/user-guide/deploying-your-docs/\n- PyPI package page: https://pypi.org/project/mkdocs/\n"
  },
  {
    "path": "content/mlflow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"mlflow package guide for Python with experiment tracking, model logging, tracking servers, auth, and serving\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.10.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"mlflow,python,ml,tracking,experiments,models,serving\"\n---\n\n# mlflow Python Package Guide\n\n## What This Package Is For\n\n`mlflow` is the main Python package for MLflow. Use it when you need to:\n\n- track experiment runs with parameters, metrics, tags, and artifacts\n- log models from supported ML libraries and reload or serve them later\n- point training code at a local or remote tracking server\n- compare runs, register models, and move model metadata between training and deployment workflows\n\nIf a project only needs to serialize a single model locally, `joblib` or framework-native save/load may be enough. Reach for `mlflow` when run tracking, reproducibility, model packaging, or a shared tracking backend matters.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `3.10.1`.\n- PyPI currently publishes `3.10.1` as the latest package version, so the version used here matches current upstream.\n- `mlflow` `3.10.1` requires Python `>=3.10`.\n- The docs URL `https://mlflow.org/docs/latest/python_api/` resolves to the current API reference path `https://mlflow.org/docs/latest/api_reference/python_api/`.\n- MLflow 3 introduces first-class Logged Models and model IDs. Newer docs may use `model_id`, `models:/<model_id>`, and `search_logged_models()`. Older examples from blogs or codebases may still assume only run-artifact URIs such as `runs:/<run_id>/model`.\n- `mlflow.autolog()` is useful, but support depends on the integration and the underlying ML library version. Do not assume identical behavior across frameworks.\n\n## Install\n\nPin the package when you want reproducible examples and client behavior:\n\n```bash\npython -m pip install \"mlflow==3.10.1\"\n```\n\nIf you are using `uv` or Poetry:\n\n```bash\nuv add mlflow==3.10.1\npoetry add mlflow==3.10.1\n```\n\n## Recommended Setup\n\nFor local-only work, MLflow uses a local file backend by default and writes runs under `./mlruns`.\n\nFor a remote or explicit tracking backend, set the tracking URI before you start runs:\n\n```bash\nexport MLFLOW_TRACKING_URI=\"http://127.0.0.1:5000\"\n```\n\n```python\nimport mlflow\n\nmlflow.set_tracking_uri(\"http://127.0.0.1:5000\")\nmlflow.set_experiment(\"fraud-model-dev\")\n```\n\n`set_tracking_uri()` accepts a local path, `file:` URI, or `http` / `https` tracking server URI. Set it once near process startup so every run in the process goes to the intended backend.\n\n## Core Tracking Workflow\n\nThis is the basic shape to copy when you need params, metrics, tags, and artifacts recorded for one run:\n\n```python\nfrom pathlib import Path\nimport json\n\nimport mlflow\n\nmlflow.set_experiment(\"fraud-model-dev\")\n\nreport_path = Path(\"artifacts/summary.json\")\nreport_path.parent.mkdir(parents=True, exist_ok=True)\nreport_path.write_text(json.dumps({\"rows\": 1250, \"source\": \"train.csv\"}))\n\nwith mlflow.start_run(run_name=\"baseline\") as run:\n    mlflow.log_param(\"model_type\", \"xgboost\")\n    mlflow.log_param(\"max_depth\", 6)\n    mlflow.log_metric(\"roc_auc\", 0.9134)\n    mlflow.set_tag(\"stage\", \"dev\")\n    mlflow.log_artifact(str(report_path), artifact_path=\"reports\")\n\nprint(run.info.run_id)\n```\n\nImportant defaults:\n\n- If you do not call `mlflow.set_experiment(...)`, runs usually land in the `Default` experiment.\n- If you do not set a tracking URI, runs go to the local backend under `./mlruns`.\n\n## Model Logging And Loading\n\n### Logging a scikit-learn model\n\nThe quickstart pattern is to train inside a run, infer a signature, then log the model with `mlflow.sklearn.log_model(...)`.\n\n```python\nimport mlflow\nimport mlflow.sklearn\nfrom mlflow.models import infer_signature\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.model_selection import train_test_split\n\nX = training_df.drop(columns=[\"target\"])\ny = training_df[\"target\"]\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)\n\nwith mlflow.start_run():\n    model = RandomForestRegressor(n_estimators=200, random_state=42)\n    model.fit(X_train, y_train)\n\n    predictions = model.predict(X_test)\n    signature = infer_signature(X_test, predictions)\n\n    mlflow.log_metric(\"rmse\", rmse(predictions, y_test))\n    model_info = mlflow.sklearn.log_model(\n        sk_model=model,\n        name=\"fraud-model\",\n        signature=signature,\n        input_example=X_test.iloc[:5],\n    )\n\nprint(model_info.model_uri)\n```\n\n### Loading a logged model\n\nUse the returned `model_uri` with the generic `pyfunc` loader when you want a prediction interface that is independent of the original training library:\n\n```python\nimport mlflow.pyfunc\n\nloaded = mlflow.pyfunc.load_model(model_info.model_uri)\npredictions = loaded.predict(X_test.iloc[:5])\nprint(predictions)\n```\n\nFor MLflow 3 style model references, you may also see URIs like `models:/<model_id>`.\n\n## Autologging\n\nIf you want MLflow to automatically capture parameters, metrics, model artifacts, and framework-specific details for a supported library, enable autologging before training:\n\n```python\nimport mlflow\n\nmlflow.autolog()\n```\n\nUse this when you want fast instrumentation, but verify the exact integration behavior for your framework. The official docs note that compatibility varies by integration and library version.\n\n## Tracking Server And Auth Configuration\n\nFor remote tracking, the environment-variable path is usually the least invasive:\n\n```bash\nexport MLFLOW_TRACKING_URI=\"https://mlflow.example.com\"\n```\n\nIf your tracking server has authentication enabled, MLflow documents these common options:\n\n```bash\nexport MLFLOW_TRACKING_USERNAME=\"alice\"\nexport MLFLOW_TRACKING_PASSWORD=\"secret\"\n```\n\nOr token-based auth:\n\n```bash\nexport MLFLOW_TRACKING_TOKEN=\"token-value\"\n```\n\nFor custom TLS handling, MLflow also documents:\n\n- `MLFLOW_TRACKING_SERVER_CERT_PATH`\n- `MLFLOW_TRACKING_CLIENT_CERT_PATH`\n- `MLFLOW_TRACKING_INSECURE_TLS=true`\n\nOnly set the auth and TLS variables you actually need for the target tracking server.\n\n## Serving A Logged Model\n\nOnce you have a model URI, you can serve it locally from the CLI:\n\n```bash\nmlflow models serve -m \"$MODEL_URI\" -p 5000 --env-manager local\n```\n\nThen send requests to the local scoring endpoint:\n\n```bash\ncurl http://127.0.0.1:5000/invocations \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"inputs\": [{\"feature_a\": 1.2, \"feature_b\": 3.4}]}'\n```\n\nFor quick local testing, this is often enough. For production deployment, treat the served model environment and dependency set as explicit deployment concerns instead of assuming the training environment automatically matches.\n\n## Common Pitfalls\n\n- Older MLflow examples often use run-artifact paths and older registry flows. For MLflow 3 code, expect more `model_id`-centric examples.\n- `mlflow.autolog()` must be enabled before model training to capture the full run automatically.\n- Logging a model without a signature or input example may be fine for simple internal use, but it makes downstream serving and validation less predictable.\n- A wrong or missing `MLFLOW_TRACKING_URI` silently sends runs to the wrong backend, often the local `./mlruns` store.\n- Tracking server auth variables are only relevant when the target server is configured for auth. Do not add them blindly to local setups.\n\n## Official Source URLs\n\n- https://mlflow.org/docs/latest/\n- https://mlflow.org/docs/latest/api_reference/python_api/\n- https://mlflow.org/docs/latest/ml/tracking/quickstart/\n- https://mlflow.org/docs/latest/self-hosting/architecture/tracking-server/\n- https://mlflow.org/docs/latest/ml/tracking/autolog/\n- https://mlflow.org/docs/latest/ml/tracking/tracking-api/\n- https://mlflow.org/docs/latest/ml/traditional-ml/tutorials/creating-custom-pyfunc/notebooks/basic-pyfunc/\n- https://mlflow.org/docs/latest/ml/migrate/\n- https://pypi.org/project/mlflow/\n"
  },
  {
    "path": "content/mocha/docs/mocha/javascript/DOC.md",
    "content": "---\nname: mocha\ndescription: \"Mocha 11 for JavaScript projects: install it, configure test files and hooks, write async tests, and run common CLI workflows\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"11.7.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"mocha,testing,javascript,nodejs,test-runner,unit-test\"\n---\n\n# Mocha for JavaScript\n\nMocha is a JavaScript test runner for Node.js projects. For end-user app code, treat it as a local dev dependency and configure the test file pattern explicitly so the suite stays predictable.\n\n## Install\n\nInstall Mocha in the project that owns the tests:\n\n```bash\nnpm install -D mocha@11.7.5\n```\n\nMocha does not require API keys, service credentials, or client initialization. The only setup you usually need is a test script and an optional config file.\n\nAdd scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"test\": \"mocha\",\n    \"test:watch\": \"mocha --watch\",\n    \"test:grep\": \"mocha --grep auth\"\n  }\n}\n```\n\nIf you prefer explicit imports instead of relying on global test functions, import helpers from `mocha` in your test files.\n\n## Basic Configuration\n\nCreate `.mocharc.cjs` in the project root:\n\n```js\nmodule.exports = {\n  spec: ['test/**/*.spec.js'],\n  recursive: true,\n  reporter: 'spec',\n  timeout: 2000,\n}\n```\n\nThis keeps file discovery and timeout behavior explicit instead of depending on defaults.\n\nCommon options you will use most often:\n\n- `spec`: test file globs to run\n- `require`: setup files or root hook plugins to load before tests\n- `reporter`: terminal or machine-readable output format\n- `timeout`: default timeout in milliseconds for tests and hooks\n- `recursive`: include matching files in nested directories\n\nRun the suite with either form:\n\n```bash\nnpx mocha\nnpm test\n```\n\n## Write A Basic Test\n\nExample source file `src/math.js`:\n\n```js\nexport function sum(a, b) {\n  return a + b\n}\n```\n\nExample test file `test/math.spec.js`:\n\n```js\nimport assert from 'node:assert/strict'\nimport { describe, it } from 'mocha'\n\nimport { sum } from '../src/math.js'\n\ndescribe('sum', function () {\n  it('adds two numbers', function () {\n    assert.equal(sum(2, 3), 5)\n  })\n})\n```\n\nRun a single file directly when iterating:\n\n```bash\nnpx mocha test/math.spec.js\n```\n\n## Async Tests\n\nMocha supports promise-returning tests, `async` functions, and callback-style tests. Pick one style per test.\n\nPreferred modern pattern:\n\n```js\nimport assert from 'node:assert/strict'\nimport { describe, it } from 'mocha'\n\nasync function fetchUser(userId) {\n  return { id: userId, name: 'Ada' }\n}\n\ndescribe('fetchUser', function () {\n  it('returns a user object', async function () {\n    const user = await fetchUser(42)\n    assert.deepEqual(user, { id: 42, name: 'Ada' })\n  })\n})\n```\n\nCallback-style tests still work when the code under test uses callbacks:\n\n```js\nimport assert from 'node:assert/strict'\nimport { it } from 'mocha'\n\nfunction loadConfig(callback) {\n  setTimeout(() => callback(null, { mode: 'test' }), 10)\n}\n\nit('loads config', function (done) {\n  loadConfig((error, config) => {\n    if (error) {\n      return done(error)\n    }\n\n    assert.equal(config.mode, 'test')\n    done()\n  })\n})\n```\n\nImportant rule: do not return a promise and call `done()` in the same test. Use either `async` / promise style or callback style, not both.\n\n## Hooks And Shared Setup\n\nUse hooks for per-suite setup and teardown:\n\n```js\nimport assert from 'node:assert/strict'\nimport { after, before, beforeEach, describe, it } from 'mocha'\n\nlet db\n\ndescribe('account service', function () {\n  before(async function () {\n    db = await createTestDatabase()\n  })\n\n  beforeEach(async function () {\n    await db.reset()\n  })\n\n  after(async function () {\n    await db.close()\n  })\n\n  it('creates an account', async function () {\n    const account = await db.createAccount({ email: 'user@example.com' })\n    assert.equal(account.email, 'user@example.com')\n  })\n})\n\nasync function createTestDatabase() {\n  return {\n    async reset() {},\n    async close() {},\n    async createAccount(input) {\n      return { id: 1, ...input }\n    },\n  }\n}\n```\n\nFor shared process-level setup, load a root hook plugin with `require`.\n\n`test/hooks.cjs`:\n\n```js\nexports.mochaHooks = {\n  beforeAll() {\n    process.env.NODE_ENV = 'test'\n  },\n}\n```\n\n`.mocharc.cjs`:\n\n```js\nmodule.exports = {\n  spec: ['test/**/*.spec.js'],\n  require: ['./test/hooks.cjs'],\n}\n```\n\nUse this pattern for shared environment setup, database bootstrapping, or global cleanup that must run before any suite executes.\n\n## ESM And CommonJS\n\nMocha works with both module systems. Match the test files to the way your application runs.\n\nFor ESM projects, set `\"type\": \"module\"` in `package.json` and use `import` syntax:\n\n```json\n{\n  \"type\": \"module\"\n}\n```\n\n```js\nimport assert from 'node:assert/strict'\nimport { describe, it } from 'mocha'\n```\n\nFor CommonJS projects, keep test files or setup files as `.cjs` and use `require()`:\n\n```js\nconst assert = require('node:assert/strict')\nconst { describe, it } = require('mocha')\n```\n\nUsing `.mocharc.cjs` is a simple way to keep the Mocha config file portable even when the app itself uses ESM.\n\n## Useful CLI Workflows\n\nRun only one matching suite or test title:\n\n```bash\nnpx mocha --grep \"account service\"\n```\n\nWatch files and rerun on change:\n\n```bash\nnpx mocha --watch\n```\n\nSwitch reporters when CI or tooling needs a different output format:\n\n```bash\nnpx mocha --reporter dot\nnpx mocha --reporter json\n```\n\nLoad setup code before tests start:\n\n```bash\nnpx mocha --require dotenv/config --require ./test/hooks.cjs\n```\n\nIncrease the default timeout for slower integration tests:\n\n```bash\nnpx mocha --timeout 10000\n```\n\n## Pitfalls\n\n### Do not use arrow functions when you need Mocha context\n\nArrow functions do not bind Mocha's test context. If you need APIs such as `this.timeout(...)`, use `function () {}` instead.\n\n```js\nimport { describe, it } from 'mocha'\n\ndescribe('slow path', function () {\n  it('finishes within 10 seconds', function () {\n    this.timeout(10_000)\n  })\n})\n```\n\n### Close open resources in teardown\n\nIf the process does not exit after the suite finishes, the usual cause is an open server, timer, socket, or database handle. Close those resources in `after()` or `afterEach()` instead of masking the problem with ad hoc process-exit workarounds.\n\n### Keep focused tests out of CI\n\n`.only()` is useful locally but dangerous in committed code because it can silently skip most of the suite. If your team relies on CI, add checks that fail the run when focused or pending tests are left in place.\n\n## Minimal Working Layout\n\n```text\n.\n├── .mocharc.cjs\n├── package.json\n├── src/\n│   └── math.js\n└── test/\n    ├── hooks.cjs\n    └── math.spec.js\n```\n\nThis layout is enough for most Node.js services and libraries: a local Mocha dependency, explicit test globs, optional root hooks, and one `npm test` entry point.\n"
  },
  {
    "path": "content/modal/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"modal Python package guide for building, running, and deploying Python functions, jobs, and web endpoints on Modal\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"modal,python,serverless,cloud,gpu,jobs\"\n---\n\n# modal Python Package Guide\n\n## What This Package Is For\n\n`modal` is the Python SDK and CLI for defining Python functions, container images, jobs, web endpoints, scheduled tasks, and stateful resources that run on Modal's managed infrastructure.\n\nUse it when you need to:\n\n- run Python functions remotely with CPU or GPU resources\n- package dependencies into a reproducible image\n- deploy long-lived app objects and web endpoints\n- attach secrets, volumes, queues, or dictionaries to remote code\n- keep local orchestration code in Python instead of writing Dockerfiles and cloud-control code by hand\n\nThe normal import is:\n\n```python\nimport modal\n```\n\n## Version-Sensitive Notes\n\n- Official sources checked on 2026-03-12 align on `1.3.5` as the current package version for this guide.\n- Modal's docs site is a rolling docs site, not a version-pinned archive. Confirm exact method availability against your installed package if you are copying older examples or upgrading from a pre-1.x codebase.\n- PyPI currently declares Python `>=3.9,<3.15`. If your runtime is older than Python 3.9, install will fail before you reach any Modal code.\n- Prefer current docs that use `modal.App(...)` and `@app.function(...)`. Older examples from blogs or issue threads may use older naming or decorators.\n\n## Install\n\nInstall the package and CLI from PyPI:\n\n```bash\npython -m pip install modal\n```\n\nIf you need exact parity with this entry:\n\n```bash\npython -m pip install \"modal==1.3.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add modal\npoetry add modal\n```\n\nConfirm the CLI is available:\n\n```bash\nmodal version\n```\n\n## Authentication And Configuration\n\nFor local development, authenticate once with the CLI:\n\n```bash\nmodal setup\n```\n\nThis opens a browser flow and stores a token for the active profile.\n\nFor CI or other non-interactive environments, configure a token explicitly:\n\n```bash\nexport MODAL_TOKEN_ID=\"...\"\nexport MODAL_TOKEN_SECRET=\"...\"\n```\n\nPractical rules:\n\n- use `modal setup` on a developer machine\n- use token environment variables in CI\n- do not hardcode credentials in source files\n- if you use multiple profiles, inspect the active config with `modal config show`\n\n## Core Workflow\n\n### 1. Define an app and image\n\n```python\nimport modal\n\napp = modal.App(\"hello-modal\")\n\nimage = (\n    modal.Image.debian_slim(python_version=\"3.11\")\n    .pip_install(\"httpx\", \"pandas\")\n)\n```\n\nUse `modal.Image` to declare the runtime environment for remote execution. If your code depends on a local package that is not installed from PyPI inside the image, add it explicitly with `add_local_python_source(...)`.\n\n### 2. Add a remote function\n\n```python\nimport modal\n\napp = modal.App(\"hello-modal\")\nimage = modal.Image.debian_slim().pip_install(\"httpx\")\n\n@app.function(image=image, timeout=300)\ndef fetch_status(url: str) -> int:\n    import httpx\n\n    response = httpx.get(url, timeout=30.0)\n    response.raise_for_status()\n    return response.status_code\n```\n\nCall it remotely from a local entrypoint:\n\n```python\n@app.local_entrypoint()\ndef main():\n    status = fetch_status.remote(\"https://modal.com\")\n    print(status)\n```\n\nRun it from your machine:\n\n```bash\nmodal run app.py\n```\n\nKey call styles from the current API reference:\n\n- `.remote(...)`: execute remotely and wait for the result\n- `.spawn(...)`: start work asynchronously and get a function call handle\n- `.map(...)`: fan out one function over many inputs\n- `.local(...)`: run the wrapped function locally for debugging when supported by your workflow\n\n### 3. Deploy when you want a stable app\n\n```bash\nmodal deploy app.py\n```\n\nUse `modal deploy` for persistent app objects such as scheduled jobs, web endpoints, or named functions that other systems call later. Use `modal run` for ad hoc local orchestration and testing.\n\n## Packaging Local Code And Assets\n\nRemote containers only see what you put into the image or what you mount explicitly.\n\nPackage a local Python module into the image:\n\n```python\nimage = (\n    modal.Image.debian_slim()\n    .pip_install(\"pydantic\")\n    .add_local_python_source(\"my_package\")\n)\n```\n\nBundle a local data directory:\n\n```python\nimage = modal.Image.debian_slim().add_local_dir(\"prompts\", remote_path=\"/root/prompts\")\n```\n\nUse this whenever your app imports local modules, prompt templates, model files, or other assets that are not downloaded inside the container build itself.\n\n## Secrets And Environment Variables\n\nAttach a named Modal secret to a function:\n\n```python\nsecret = modal.Secret.from_name(\"openai-api-key\")\n\n@app.function(secrets=[secret])\ndef use_secret() -> None:\n    import os\n\n    print(bool(os.environ[\"OPENAI_API_KEY\"]))\n```\n\nCreate an ephemeral secret from local values when needed:\n\n```python\nruntime_secret = modal.Secret.from_dict(\n    {\n        \"OPENAI_API_KEY\": \"sk-...\",\n        \"APP_ENV\": \"dev\",\n    }\n)\n```\n\nPractical rule: if code needs an environment variable inside the remote container, pass it through a Modal secret or another explicit Modal config mechanism. Your shell environment is not automatically mirrored into remote execution.\n\n## Persistent Storage And Shared State\n\nUse a `Volume` when multiple runs or containers need shared files:\n\n```python\nvolume = modal.Volume.from_name(\"model-cache\", create_if_missing=True)\n\n@app.function(volumes={\"/cache\": volume})\ndef write_file() -> None:\n    path = \"/cache/result.txt\"\n    with open(path, \"w\", encoding=\"utf-8\") as f:\n        f.write(\"hello from modal\\n\")\n    volume.commit()\n```\n\nImportant behavior from the reference docs:\n\n- `commit()` persists new or changed files from the running container into the volume\n- `reload()` refreshes a mounted volume view from the latest committed state\n- use a `Volume` for files, not for secrets\n\nIf you need keyed shared state instead of files, consider Modal's named objects such as `modal.Dict` or `modal.Queue`.\n\n## Common Patterns\n\n### Batch fan-out\n\n```python\n@app.function()\ndef square(x: int) -> int:\n    return x * x\n\n@app.local_entrypoint()\ndef main():\n    for result in square.map(range(5)):\n        print(result)\n```\n\n### GPU-backed function\n\n```python\n@app.function(gpu=\"A10G\", image=modal.Image.debian_slim().pip_install(\"torch\"))\ndef train() -> str:\n    return \"started\"\n```\n\nOnly request a GPU when the workload actually needs one. Modal allocates infrastructure from the decorator configuration, so resource choices affect startup behavior and cost.\n\n### Web entrypoints\n\nUse `modal deploy` plus the current web-serving decorators from the Modal guide when you need HTTP entrypoints. Keep the local `@app.local_entrypoint()` for smoke tests and administrative workflows, not for the production request path.\n\n## Common Pitfalls\n\n### Calling the function the wrong way\n\n`@app.function` creates a Modal function object. For remote execution, call `.remote(...)`, `.spawn(...)`, or `.map(...)` on that object instead of assuming a plain Python call will execute in the cloud.\n\n### Forgetting to package local imports\n\nIf the remote function imports a local package, add it to the image with `add_local_python_source(...)` or install it during the image build. Your local virtualenv does not get copied automatically.\n\n### Depending on undeclared Python packages\n\nEvery third-party dependency used inside the remote function must be installed in the image with `pip_install(...)`, `uv_pip_install(...)`, or another image build step.\n\n### Assuming local environment variables exist remotely\n\nRemote containers only receive what you pass in through Modal-managed configuration such as secrets. Missing environment variables usually mean the function was configured locally but not attached remotely.\n\n### Forgetting volume synchronization\n\nIf one container writes files and another needs to read them later, commit the changes and reload where needed. A mounted `Volume` is shared state, but visibility still depends on the documented `commit()` and `reload()` flow.\n\n### Mixing local orchestration and remote imports carelessly\n\nKeep orchestration code inside `@app.local_entrypoint()` or normal top-level Python, and keep cloud-executed code inside decorated functions and classes. This makes it obvious what runs locally and what runs in Modal's containers.\n\n## Minimal End-To-End Example\n\n```python\nimport modal\n\napp = modal.App(\"fetch-example\")\n\nimage = (\n    modal.Image.debian_slim(python_version=\"3.11\")\n    .pip_install(\"httpx\")\n)\n\napi_secret = modal.Secret.from_name(\"api-token\")\ncache = modal.Volume.from_name(\"fetch-cache\", create_if_missing=True)\n\n@app.function(image=image, secrets=[api_secret], volumes={\"/cache\": cache})\ndef fetch(url: str) -> str:\n    import httpx\n\n    body = httpx.get(url, timeout=30.0).text\n    with open(\"/cache/last-response.html\", \"w\", encoding=\"utf-8\") as f:\n        f.write(body)\n    cache.commit()\n    return body[:200]\n\n@app.local_entrypoint()\ndef main():\n    print(fetch.remote(\"https://modal.com\"))\n```\n\nRun locally:\n\n```bash\nmodal run app.py\n```\n\nDeploy when you want a stable app object:\n\n```bash\nmodal deploy app.py\n```\n\n## Official Sources Used For This Entry\n\n- Modal guide: `https://modal.com/docs/guide`\n- Modal API reference: `https://modal.com/docs/reference`\n- `modal.App` reference: `https://modal.com/docs/reference/modal.App`\n- `modal.Function` reference: `https://modal.com/docs/reference/modal.Function`\n- `modal.Image` reference: `https://modal.com/docs/reference/modal.Image`\n- `modal.Secret` reference: `https://modal.com/docs/reference/modal.Secret`\n- `modal.Volume` reference: `https://modal.com/docs/reference/modal.Volume`\n- Local data guide: `https://modal.com/docs/guide/local-data`\n- Global objects guide: `https://modal.com/docs/guide/global-objects`\n- Changelog: `https://modal.com/docs/reference/changelog`\n- PyPI registry page: `https://pypi.org/project/modal/`\n"
  },
  {
    "path": "content/mongodb/docs/atlas/DOC.md",
    "content": "---\nname: atlas\ndescription: \"MongoDB Node.js driver for interacting with MongoDB Atlas databases using the official JavaScript/TypeScript SDK.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.20.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"mongodb,atlas,database,nosql,driver\"\n---\n\n# MongoDB Atlas Coding Guidelines (JavaScript/TypeScript)\n\nYou are a MongoDB Atlas coding expert. Help me with writing code using the MongoDB Node.js driver calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official MongoDB Node.js driver for all MongoDB Atlas interactions.\n\n- **Library Name:** MongoDB Node.js Driver\n- **NPM Package:** `mongodb`\n- **GitHub:** https://github.com/mongodb/node-mongodb-native\n\n**Installation:**\n\n```bash\nnpm install mongodb\n```\n\n**Import Patterns:**\n\n```javascript\n// ES6 import (recommended)\nimport { MongoClient } from 'mongodb';\n\n// CommonJS require\nconst { MongoClient } = require('mongodb');\n\n// Additional utilities\nimport { MongoClient, ObjectId, Timestamp } from 'mongodb';\n```\n\n**Do NOT use:**\n- Deprecated MongoDB packages\n- Third-party MongoDB wrappers (unless specifically requested)\n- Old connection patterns from MongoDB driver v2 or v3\n\n## Installation and Environment Setup\n\n```bash\nnpm install mongodb\n```\n\n**Environment Variables Setup:**\n\nCreate a `.env` file in your project root:\n\n```bash\nMONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/database?retryWrites=true&w=majority\n```\n\n**Using dotenv for environment variables:**\n\n```bash\nnpm install dotenv\n```\n\n```javascript\nimport 'dotenv/config';\nimport { MongoClient } from 'mongodb';\n\nconst uri = process.env.MONGODB_URI;\n```\n\n## Initialization and Connection\n\nThe MongoDB driver requires creating a `MongoClient` instance for all database operations.\n\n**Basic Connection:**\n\n```javascript\nimport { MongoClient } from 'mongodb';\n\nconst uri = process.env.MONGODB_URI;\nconst client = new MongoClient(uri);\n\nasync function main() {\n  try {\n    await client.connect();\n    console.log('Connected to MongoDB Atlas');\n\n    const database = client.db('myDatabase');\n    const collection = database.collection('myCollection');\n\n    // Perform operations...\n\n  } finally {\n    await client.close();\n  }\n}\n\nmain().catch(console.error);\n```\n\n**Connection with Options:**\n\n```javascript\nimport { MongoClient, ServerApiVersion } from 'mongodb';\n\nconst uri = process.env.MONGODB_URI;\n\nconst client = new MongoClient(uri, {\n  serverApi: {\n    version: ServerApiVersion.v1,\n    strict: true,\n    deprecationErrors: true,\n  }\n});\n\nasync function run() {\n  try {\n    await client.connect();\n    await client.db('admin').command({ ping: 1 });\n    console.log('Pinged your deployment. Successfully connected to MongoDB!');\n  } finally {\n    await client.close();\n  }\n}\n\nrun().catch(console.error);\n```\n\n**Reusable Connection Pattern:**\n\n```javascript\nimport { MongoClient } from 'mongodb';\n\nlet client;\nlet clientPromise;\n\nconst uri = process.env.MONGODB_URI;\nconst options = {};\n\nif (process.env.NODE_ENV === 'development') {\n  // In development mode, use a global variable to preserve connection\n  if (!global._mongoClientPromise) {\n    client = new MongoClient(uri, options);\n    global._mongoClientPromise = client.connect();\n  }\n  clientPromise = global._mongoClientPromise;\n} else {\n  // In production mode, create a new client\n  client = new MongoClient(uri, options);\n  clientPromise = client.connect();\n}\n\nexport default clientPromise;\n```\n\n## CRUD Operations\n\n### Insert Documents\n\n**Insert One Document:**\n\n```javascript\nimport { MongoClient } from 'mongodb';\n\nconst client = new MongoClient(process.env.MONGODB_URI);\n\nasync function insertDocument() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const doc = {\n      name: 'John Doe',\n      email: 'john@example.com',\n      age: 30,\n      createdAt: new Date()\n    };\n\n    const result = await collection.insertOne(doc);\n    console.log(`Document inserted with _id: ${result.insertedId}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ninsertDocument().catch(console.error);\n```\n\n**Insert Multiple Documents:**\n\n```javascript\nasync function insertMultipleDocuments() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const docs = [\n      { name: 'Alice', email: 'alice@example.com', age: 25 },\n      { name: 'Bob', email: 'bob@example.com', age: 32 },\n      { name: 'Charlie', email: 'charlie@example.com', age: 28 }\n    ];\n\n    const result = await collection.insertMany(docs);\n    console.log(`${result.insertedCount} documents inserted`);\n    console.log('Inserted IDs:', result.insertedIds);\n\n  } finally {\n    await client.close();\n  }\n}\n\ninsertMultipleDocuments().catch(console.error);\n```\n\n**Insert with Options:**\n\n```javascript\nasync function insertWithOptions() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const doc = { name: 'David', email: 'david@example.com' };\n\n    const result = await collection.insertOne(doc, {\n      writeConcern: { w: 'majority', wtimeout: 5000 }\n    });\n\n    console.log(`Document inserted: ${result.insertedId}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ninsertWithOptions().catch(console.error);\n```\n\n### Find Documents\n\n**Find All Documents:**\n\n```javascript\nasync function findAllDocuments() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const cursor = collection.find({});\n    const documents = await cursor.toArray();\n\n    console.log('All documents:', documents);\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindAllDocuments().catch(console.error);\n```\n\n**Find with Filter:**\n\n```javascript\nasync function findWithFilter() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Find users older than 25\n    const query = { age: { $gt: 25 } };\n    const cursor = collection.find(query);\n    const results = await cursor.toArray();\n\n    console.log('Users older than 25:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindWithFilter().catch(console.error);\n```\n\n**Find One Document:**\n\n```javascript\nasync function findOneDocument() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const query = { email: 'john@example.com' };\n    const user = await collection.findOne(query);\n\n    if (user) {\n      console.log('Found user:', user);\n    } else {\n      console.log('User not found');\n    }\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindOneDocument().catch(console.error);\n```\n\n**Find with Projection:**\n\n```javascript\nasync function findWithProjection() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const query = { age: { $gte: 25 } };\n    const options = {\n      projection: { _id: 0, name: 1, email: 1 }\n    };\n\n    const cursor = collection.find(query, options);\n    const results = await cursor.toArray();\n\n    console.log('Users (name and email only):', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindWithProjection().catch(console.error);\n```\n\n**Find with Sort, Limit, and Skip:**\n\n```javascript\nasync function findWithSortLimitSkip() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const cursor = collection.find({})\n      .sort({ age: -1 })  // Sort by age descending\n      .limit(10)          // Limit to 10 results\n      .skip(5);           // Skip first 5 results\n\n    const results = await cursor.toArray();\n\n    console.log('Sorted and paginated results:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindWithSortLimitSkip().catch(console.error);\n```\n\n**Pagination Pattern:**\n\n```javascript\nasync function paginateDocuments(page = 1, pageSize = 10) {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const skip = (page - 1) * pageSize;\n\n    const cursor = collection.find({})\n      .sort({ createdAt: -1 })\n      .skip(skip)\n      .limit(pageSize);\n\n    const documents = await cursor.toArray();\n    const total = await collection.countDocuments({});\n\n    return {\n      documents,\n      page,\n      pageSize,\n      totalPages: Math.ceil(total / pageSize),\n      totalDocuments: total\n    };\n\n  } finally {\n    await client.close();\n  }\n}\n\npaginateDocuments(1, 20).then(console.log).catch(console.error);\n```\n\n**Cursor-Based Pagination (Better Performance):**\n\n```javascript\nasync function cursorPagination(lastId = null, pageSize = 10) {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const query = lastId ? { _id: { $gt: lastId } } : {};\n\n    const cursor = collection.find(query)\n      .sort({ _id: 1 })\n      .limit(pageSize);\n\n    const documents = await cursor.toArray();\n\n    return {\n      documents,\n      nextCursor: documents.length > 0\n        ? documents[documents.length - 1]._id\n        : null\n    };\n\n  } finally {\n    await client.close();\n  }\n}\n\ncursorPagination(null, 20).then(console.log).catch(console.error);\n```\n\n### Update Documents\n\n**Update One Document:**\n\n```javascript\nasync function updateOneDocument() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const update = {\n      $set: { age: 31, updatedAt: new Date() }\n    };\n\n    const result = await collection.updateOne(filter, update);\n\n    console.log(`${result.matchedCount} document(s) matched the filter`);\n    console.log(`${result.modifiedCount} document(s) updated`);\n\n  } finally {\n    await client.close();\n  }\n}\n\nupdateOneDocument().catch(console.error);\n```\n\n**Update Multiple Documents:**\n\n```javascript\nasync function updateManyDocuments() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { age: { $lt: 30 } };\n    const update = {\n      $set: { category: 'young', updatedAt: new Date() }\n    };\n\n    const result = await collection.updateMany(filter, update);\n\n    console.log(`${result.matchedCount} document(s) matched`);\n    console.log(`${result.modifiedCount} document(s) updated`);\n\n  } finally {\n    await client.close();\n  }\n}\n\nupdateManyDocuments().catch(console.error);\n```\n\n**Update with Upsert:**\n\n```javascript\nasync function updateWithUpsert() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'newuser@example.com' };\n    const update = {\n      $set: {\n        name: 'New User',\n        email: 'newuser@example.com',\n        age: 22,\n        createdAt: new Date()\n      }\n    };\n\n    const options = { upsert: true };\n    const result = await collection.updateOne(filter, update, options);\n\n    if (result.upsertedId) {\n      console.log(`Document inserted with _id: ${result.upsertedId}`);\n    } else {\n      console.log(`${result.modifiedCount} document(s) updated`);\n    }\n\n  } finally {\n    await client.close();\n  }\n}\n\nupdateWithUpsert().catch(console.error);\n```\n\n**Update Operators:**\n\n```javascript\nasync function updateOperators() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const update = {\n      $set: { status: 'active' },\n      $inc: { loginCount: 1 },\n      $push: { tags: 'premium' },\n      $currentDate: { lastModified: true }\n    };\n\n    const result = await collection.updateOne(filter, update);\n    console.log(`${result.modifiedCount} document(s) updated`);\n\n  } finally {\n    await client.close();\n  }\n}\n\nupdateOperators().catch(console.error);\n```\n\n**Replace Document:**\n\n```javascript\nasync function replaceDocument() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const replacement = {\n      name: 'John Doe Updated',\n      email: 'john@example.com',\n      age: 31,\n      status: 'active',\n      updatedAt: new Date()\n    };\n\n    const result = await collection.replaceOne(filter, replacement);\n    console.log(`${result.modifiedCount} document(s) replaced`);\n\n  } finally {\n    await client.close();\n  }\n}\n\nreplaceDocument().catch(console.error);\n```\n\n**Find and Modify:**\n\n```javascript\nasync function findAndModify() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const update = { $inc: { age: 1 } };\n    const options = {\n      returnDocument: 'after',  // Return the updated document\n      upsert: false\n    };\n\n    const result = await collection.findOneAndUpdate(filter, update, options);\n\n    if (result) {\n      console.log('Updated document:', result);\n    }\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindAndModify().catch(console.error);\n```\n\n### Delete Documents\n\n**Delete One Document:**\n\n```javascript\nasync function deleteOneDocument() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const result = await collection.deleteOne(filter);\n\n    console.log(`${result.deletedCount} document(s) deleted`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ndeleteOneDocument().catch(console.error);\n```\n\n**Delete Multiple Documents:**\n\n```javascript\nasync function deleteManyDocuments() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { age: { $lt: 18 } };\n    const result = await collection.deleteMany(filter);\n\n    console.log(`${result.deletedCount} document(s) deleted`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ndeleteManyDocuments().catch(console.error);\n```\n\n**Find and Delete:**\n\n```javascript\nasync function findAndDelete() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const filter = { email: 'john@example.com' };\n    const options = {\n      sort: { createdAt: -1 }\n    };\n\n    const result = await collection.findOneAndDelete(filter, options);\n\n    if (result) {\n      console.log('Deleted document:', result);\n    } else {\n      console.log('No document found to delete');\n    }\n\n  } finally {\n    await client.close();\n  }\n}\n\nfindAndDelete().catch(console.error);\n```\n\n## Aggregation Pipeline\n\n**Basic Aggregation:**\n\n```javascript\nasync function basicAggregation() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const pipeline = [\n      { $match: { age: { $gte: 25 } } },\n      { $group: {\n          _id: '$status',\n          count: { $sum: 1 },\n          avgAge: { $avg: '$age' }\n        }\n      },\n      { $sort: { count: -1 } }\n    ];\n\n    const results = await collection.aggregate(pipeline).toArray();\n    console.log('Aggregation results:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\nbasicAggregation().catch(console.error);\n```\n\n**Advanced Aggregation with Multiple Stages:**\n\n```javascript\nasync function advancedAggregation() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('orders');\n\n    const pipeline = [\n      {\n        $match: {\n          status: 'completed',\n          createdAt: { $gte: new Date('2024-01-01') }\n        }\n      },\n      {\n        $group: {\n          _id: {\n            year: { $year: '$createdAt' },\n            month: { $month: '$createdAt' }\n          },\n          totalSales: { $sum: '$amount' },\n          orderCount: { $sum: 1 },\n          avgOrderValue: { $avg: '$amount' }\n        }\n      },\n      {\n        $sort: { '_id.year': 1, '_id.month': 1 }\n      },\n      {\n        $project: {\n          _id: 0,\n          year: '$_id.year',\n          month: '$_id.month',\n          totalSales: 1,\n          orderCount: 1,\n          avgOrderValue: { $round: ['$avgOrderValue', 2] }\n        }\n      }\n    ];\n\n    const results = await collection.aggregate(pipeline).toArray();\n    console.log('Sales report:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\nadvancedAggregation().catch(console.error);\n```\n\n**Aggregation with $lookup (Join):**\n\n```javascript\nasync function aggregationWithLookup() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('orders');\n\n    const pipeline = [\n      {\n        $lookup: {\n          from: 'users',\n          localField: 'userId',\n          foreignField: '_id',\n          as: 'userDetails'\n        }\n      },\n      {\n        $unwind: '$userDetails'\n      },\n      {\n        $project: {\n          orderNumber: 1,\n          amount: 1,\n          userName: '$userDetails.name',\n          userEmail: '$userDetails.email'\n        }\n      }\n    ];\n\n    const results = await collection.aggregate(pipeline).toArray();\n    console.log('Orders with user details:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\naggregationWithLookup().catch(console.error);\n```\n\n**Aggregation with $facet (Multiple Pipelines):**\n\n```javascript\nasync function aggregationWithFacet() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('products');\n\n    const pipeline = [\n      {\n        $facet: {\n          categoryCounts: [\n            { $group: { _id: '$category', count: { $sum: 1 } } },\n            { $sort: { count: -1 } }\n          ],\n          priceStats: [\n            {\n              $group: {\n                _id: null,\n                avgPrice: { $avg: '$price' },\n                minPrice: { $min: '$price' },\n                maxPrice: { $max: '$price' }\n              }\n            }\n          ],\n          topProducts: [\n            { $sort: { sales: -1 } },\n            { $limit: 5 },\n            { $project: { name: 1, sales: 1, price: 1 } }\n          ]\n        }\n      }\n    ];\n\n    const results = await collection.aggregate(pipeline).toArray();\n    console.log('Product analytics:', results[0]);\n\n  } finally {\n    await client.close();\n  }\n}\n\naggregationWithFacet().catch(console.error);\n```\n\n## Indexes\n\n**Create Single Field Index:**\n\n```javascript\nasync function createIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const result = await collection.createIndex({ email: 1 });\n    console.log(`Index created: ${result}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateIndex().catch(console.error);\n```\n\n**Create Compound Index:**\n\n```javascript\nasync function createCompoundIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const result = await collection.createIndex(\n      { lastName: 1, firstName: 1 }\n    );\n    console.log(`Compound index created: ${result}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateCompoundIndex().catch(console.error);\n```\n\n**Create Unique Index:**\n\n```javascript\nasync function createUniqueIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const result = await collection.createIndex(\n      { email: 1 },\n      { unique: true }\n    );\n    console.log(`Unique index created: ${result}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateUniqueIndex().catch(console.error);\n```\n\n**Create Text Index:**\n\n```javascript\nasync function createTextIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('articles');\n\n    const result = await collection.createIndex(\n      { title: 'text', content: 'text' }\n    );\n    console.log(`Text index created: ${result}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateTextIndex().catch(console.error);\n```\n\n**Text Search Query:**\n\n```javascript\nasync function textSearch() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('articles');\n\n    const query = { $text: { $search: 'mongodb tutorial' } };\n    const projection = { score: { $meta: 'textScore' } };\n\n    const cursor = collection\n      .find(query, { projection })\n      .sort({ score: { $meta: 'textScore' } });\n\n    const results = await cursor.toArray();\n    console.log('Search results:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\ntextSearch().catch(console.error);\n```\n\n**Create 2dsphere Index (Geospatial):**\n\n```javascript\nasync function createGeospatialIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('locations');\n\n    const result = await collection.createIndex(\n      { location: '2dsphere' }\n    );\n    console.log(`Geospatial index created: ${result}`);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateGeospatialIndex().catch(console.error);\n```\n\n**Geospatial Query ($near):**\n\n```javascript\nasync function geospatialNearQuery() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('locations');\n\n    const query = {\n      location: {\n        $near: {\n          $geometry: {\n            type: 'Point',\n            coordinates: [-73.9667, 40.78]  // [longitude, latitude]\n          },\n          $maxDistance: 5000  // 5km in meters\n        }\n      }\n    };\n\n    const results = await collection.find(query).limit(10).toArray();\n    console.log('Nearby locations:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\ngeospatialNearQuery().catch(console.error);\n```\n\n**Geospatial Query ($geoWithin):**\n\n```javascript\nasync function geospatialWithinQuery() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('locations');\n\n    const query = {\n      location: {\n        $geoWithin: {\n          $geometry: {\n            type: 'Polygon',\n            coordinates: [[\n              [-74.0, 40.7],\n              [-73.9, 40.7],\n              [-73.9, 40.8],\n              [-74.0, 40.8],\n              [-74.0, 40.7]\n            ]]\n          }\n        }\n      }\n    };\n\n    const results = await collection.find(query).toArray();\n    console.log('Locations within polygon:', results);\n\n  } finally {\n    await client.close();\n  }\n}\n\ngeospatialWithinQuery().catch(console.error);\n```\n\n**List Indexes:**\n\n```javascript\nasync function listIndexes() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const indexes = await collection.listIndexes().toArray();\n    console.log('Indexes:', indexes);\n\n  } finally {\n    await client.close();\n  }\n}\n\nlistIndexes().catch(console.error);\n```\n\n**Drop Index:**\n\n```javascript\nasync function dropIndex() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const result = await collection.dropIndex('email_1');\n    console.log('Index dropped:', result);\n\n  } finally {\n    await client.close();\n  }\n}\n\ndropIndex().catch(console.error);\n```\n\n## Bulk Write Operations\n\n**Bulk Write with Mixed Operations:**\n\n```javascript\nasync function bulkWrite() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const operations = [\n      {\n        insertOne: {\n          document: { name: 'User 1', email: 'user1@example.com' }\n        }\n      },\n      {\n        updateOne: {\n          filter: { email: 'john@example.com' },\n          update: { $set: { status: 'active' } }\n        }\n      },\n      {\n        updateMany: {\n          filter: { age: { $lt: 25 } },\n          update: { $set: { category: 'young' } }\n        }\n      },\n      {\n        deleteOne: {\n          filter: { email: 'old@example.com' }\n        }\n      },\n      {\n        replaceOne: {\n          filter: { email: 'replace@example.com' },\n          replacement: { name: 'Replaced', email: 'replace@example.com', age: 40 }\n        }\n      }\n    ];\n\n    const result = await collection.bulkWrite(operations);\n\n    console.log(`${result.insertedCount} documents inserted`);\n    console.log(`${result.modifiedCount} documents modified`);\n    console.log(`${result.deletedCount} documents deleted`);\n    console.log(`${result.upsertedCount} documents upserted`);\n\n  } finally {\n    await client.close();\n  }\n}\n\nbulkWrite().catch(console.error);\n```\n\n**Ordered vs Unordered Bulk Write:**\n\n```javascript\nasync function orderedVsUnorderedBulk() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const operations = [\n      { insertOne: { document: { name: 'User A' } } },\n      { insertOne: { document: { name: 'User B' } } }\n    ];\n\n    // Ordered (default): stops on first error\n    const orderedResult = await collection.bulkWrite(operations, { ordered: true });\n\n    // Unordered: continues on errors, may execute in parallel\n    const unorderedResult = await collection.bulkWrite(operations, { ordered: false });\n\n    console.log('Ordered result:', orderedResult);\n    console.log('Unordered result:', unorderedResult);\n\n  } finally {\n    await client.close();\n  }\n}\n\norderedVsUnorderedBulk().catch(console.error);\n```\n\n## Transactions\n\n**Transaction with Session (Convenient API):**\n\n```javascript\nasync function transactionExample() {\n  const session = client.startSession();\n\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n\n    const result = await session.withTransaction(async () => {\n      const accounts = database.collection('accounts');\n      const transactions = database.collection('transactions');\n\n      // Deduct from account A\n      await accounts.updateOne(\n        { accountId: 'A' },\n        { $inc: { balance: -100 } },\n        { session }\n      );\n\n      // Add to account B\n      await accounts.updateOne(\n        { accountId: 'B' },\n        { $inc: { balance: 100 } },\n        { session }\n      );\n\n      // Record transaction\n      await transactions.insertOne(\n        {\n          from: 'A',\n          to: 'B',\n          amount: 100,\n          timestamp: new Date()\n        },\n        { session }\n      );\n\n      return 'Transaction completed';\n    });\n\n    console.log(result);\n\n  } finally {\n    await session.endSession();\n    await client.close();\n  }\n}\n\ntransactionExample().catch(console.error);\n```\n\n**Transaction with Core API (Manual Control):**\n\n```javascript\nasync function manualTransaction() {\n  const session = client.startSession();\n\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const accounts = database.collection('accounts');\n\n    // Start transaction\n    session.startTransaction({\n      readConcern: { level: 'snapshot' },\n      writeConcern: { w: 'majority' }\n    });\n\n    try {\n      // Perform operations within transaction\n      await accounts.updateOne(\n        { accountId: 'A' },\n        { $inc: { balance: -100 } },\n        { session }\n      );\n\n      await accounts.updateOne(\n        { accountId: 'B' },\n        { $inc: { balance: 100 } },\n        { session }\n      );\n\n      // Commit transaction\n      await session.commitTransaction();\n      console.log('Transaction committed');\n\n    } catch (error) {\n      // Abort transaction on error\n      await session.abortTransaction();\n      console.error('Transaction aborted:', error);\n      throw error;\n    }\n\n  } finally {\n    await session.endSession();\n    await client.close();\n  }\n}\n\nmanualTransaction().catch(console.error);\n```\n\n**Transaction with Retry Logic:**\n\n```javascript\nasync function transactionWithRetry() {\n  const session = client.startSession();\n\n  async function runTransactionWithRetry(txnFunc, session) {\n    while (true) {\n      try {\n        return await txnFunc(session);\n      } catch (error) {\n        if (error.hasErrorLabel('TransientTransactionError')) {\n          console.log('TransientTransactionError, retrying transaction...');\n          continue;\n        }\n        throw error;\n      }\n    }\n  }\n\n  async function commitWithRetry(session) {\n    while (true) {\n      try {\n        await session.commitTransaction();\n        console.log('Transaction committed');\n        break;\n      } catch (error) {\n        if (error.hasErrorLabel('UnknownTransactionCommitResult')) {\n          console.log('UnknownTransactionCommitResult, retrying commit...');\n          continue;\n        }\n        throw error;\n      }\n    }\n  }\n\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n\n    await runTransactionWithRetry(async (session) => {\n      session.startTransaction();\n\n      const accounts = database.collection('accounts');\n\n      await accounts.updateOne(\n        { accountId: 'A' },\n        { $inc: { balance: -50 } },\n        { session }\n      );\n\n      await accounts.updateOne(\n        { accountId: 'B' },\n        { $inc: { balance: 50 } },\n        { session }\n      );\n\n      await commitWithRetry(session);\n    }, session);\n\n  } finally {\n    await session.endSession();\n    await client.close();\n  }\n}\n\ntransactionWithRetry().catch(console.error);\n```\n\n## Change Streams\n\n**Watch Collection for Changes:**\n\n```javascript\nasync function watchCollection() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const changeStream = collection.watch();\n\n    console.log('Watching for changes...');\n\n    changeStream.on('change', (change) => {\n      console.log('Change detected:', change);\n    });\n\n    changeStream.on('error', (error) => {\n      console.error('Change stream error:', error);\n    });\n\n    // Keep the connection open\n    // In production, you'd handle this differently\n\n  } catch (error) {\n    console.error(error);\n  }\n}\n\nwatchCollection().catch(console.error);\n```\n\n**Watch with Filter Pipeline:**\n\n```javascript\nasync function watchWithFilter() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    const pipeline = [\n      {\n        $match: {\n          'operationType': { $in: ['insert', 'update'] },\n          'fullDocument.age': { $gte: 18 }\n        }\n      }\n    ];\n\n    const changeStream = collection.watch(pipeline);\n\n    console.log('Watching for adult user changes...');\n\n    for await (const change of changeStream) {\n      console.log('Change:', change);\n\n      if (change.operationType === 'insert') {\n        console.log('New user inserted:', change.fullDocument);\n      } else if (change.operationType === 'update') {\n        console.log('User updated:', change.documentKey);\n      }\n    }\n\n  } catch (error) {\n    console.error(error);\n  }\n}\n\nwatchWithFilter().catch(console.error);\n```\n\n**Watch Database for Changes:**\n\n```javascript\nasync function watchDatabase() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n\n    const changeStream = database.watch();\n\n    console.log('Watching database for changes...');\n\n    changeStream.on('change', (change) => {\n      console.log(`Change in collection ${change.ns.coll}:`, change);\n    });\n\n  } catch (error) {\n    console.error(error);\n  }\n}\n\nwatchDatabase().catch(console.error);\n```\n\n## ObjectId Utilities\n\n**Working with ObjectId:**\n\n```javascript\nimport { ObjectId } from 'mongodb';\n\nasync function objectIdExamples() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Generate new ObjectId\n    const newId = new ObjectId();\n    console.log('New ObjectId:', newId.toString());\n\n    // Insert with custom ObjectId\n    await collection.insertOne({\n      _id: new ObjectId(),\n      name: 'User with custom ID'\n    });\n\n    // Find by ObjectId string\n    const userId = '507f1f77bcf86cd799439011';\n    const user = await collection.findOne({\n      _id: new ObjectId(userId)\n    });\n\n    // Get timestamp from ObjectId\n    if (user) {\n      const timestamp = user._id.getTimestamp();\n      console.log('Document created at:', timestamp);\n    }\n\n    // Validate ObjectId\n    const isValid = ObjectId.isValid('507f1f77bcf86cd799439011');\n    console.log('Is valid ObjectId:', isValid);\n\n  } finally {\n    await client.close();\n  }\n}\n\nobjectIdExamples().catch(console.error);\n```\n\n## Error Handling\n\n**Comprehensive Error Handling:**\n\n```javascript\nimport { MongoClient, MongoServerError } from 'mongodb';\n\nasync function errorHandlingExample() {\n  const client = new MongoClient(process.env.MONGODB_URI);\n\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Attempt operation\n    await collection.insertOne({\n      email: 'duplicate@example.com'\n    });\n\n  } catch (error) {\n    if (error instanceof MongoServerError) {\n      switch (error.code) {\n        case 11000:\n          console.error('Duplicate key error:', error.message);\n          break;\n        case 121:\n          console.error('Document validation failed:', error.message);\n          break;\n        default:\n          console.error('MongoDB server error:', error.message);\n      }\n    } else if (error.name === 'MongoNetworkError') {\n      console.error('Network error - cannot connect to MongoDB:', error.message);\n    } else if (error.name === 'MongoParseError') {\n      console.error('Invalid connection string:', error.message);\n    } else {\n      console.error('Unexpected error:', error);\n    }\n  } finally {\n    await client.close();\n  }\n}\n\nerrorHandlingExample().catch(console.error);\n```\n\n**Retry Logic for Transient Errors:**\n\n```javascript\nasync function retryOperation(operation, maxRetries = 3) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await operation();\n    } catch (error) {\n      if (attempt === maxRetries) {\n        throw error;\n      }\n\n      const isRetryable =\n        error.name === 'MongoNetworkError' ||\n        error.code === 'ETIMEDOUT' ||\n        error.code === 'ECONNRESET';\n\n      if (!isRetryable) {\n        throw error;\n      }\n\n      const delay = Math.pow(2, attempt) * 1000;\n      console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);\n      await new Promise(resolve => setTimeout(resolve, delay));\n    }\n  }\n}\n\nasync function useRetryLogic() {\n  const client = new MongoClient(process.env.MONGODB_URI);\n\n  try {\n    await retryOperation(async () => {\n      await client.connect();\n      const database = client.db('sample_db');\n      const collection = database.collection('users');\n\n      return await collection.findOne({ email: 'test@example.com' });\n    });\n\n  } finally {\n    await client.close();\n  }\n}\n\nuseRetryLogic().catch(console.error);\n```\n\n## Query Operators\n\n**Comparison Operators:**\n\n```javascript\nasync function comparisonOperators() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('products');\n\n    // $eq (equal)\n    const equal = await collection.find({ price: { $eq: 99 } }).toArray();\n\n    // $ne (not equal)\n    const notEqual = await collection.find({ status: { $ne: 'discontinued' } }).toArray();\n\n    // $gt, $gte (greater than, greater than or equal)\n    const greaterThan = await collection.find({ price: { $gt: 50 } }).toArray();\n    const greaterOrEqual = await collection.find({ stock: { $gte: 100 } }).toArray();\n\n    // $lt, $lte (less than, less than or equal)\n    const lessThan = await collection.find({ price: { $lt: 100 } }).toArray();\n    const lessOrEqual = await collection.find({ rating: { $lte: 3 } }).toArray();\n\n    // $in (in array)\n    const inArray = await collection.find({\n      category: { $in: ['electronics', 'computers'] }\n    }).toArray();\n\n    // $nin (not in array)\n    const notInArray = await collection.find({\n      status: { $nin: ['discontinued', 'out-of-stock'] }\n    }).toArray();\n\n    console.log('Query results:', equal, notEqual, greaterThan);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncomparisonOperators().catch(console.error);\n```\n\n**Logical Operators:**\n\n```javascript\nasync function logicalOperators() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('products');\n\n    // $and\n    const andQuery = await collection.find({\n      $and: [\n        { price: { $lt: 100 } },\n        { stock: { $gt: 0 } }\n      ]\n    }).toArray();\n\n    // $or\n    const orQuery = await collection.find({\n      $or: [\n        { category: 'electronics' },\n        { featured: true }\n      ]\n    }).toArray();\n\n    // $not\n    const notQuery = await collection.find({\n      price: { $not: { $gt: 100 } }\n    }).toArray();\n\n    // $nor\n    const norQuery = await collection.find({\n      $nor: [\n        { status: 'discontinued' },\n        { stock: 0 }\n      ]\n    }).toArray();\n\n    console.log('Logical query results:', andQuery.length, orQuery.length);\n\n  } finally {\n    await client.close();\n  }\n}\n\nlogicalOperators().catch(console.error);\n```\n\n**Element Operators:**\n\n```javascript\nasync function elementOperators() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // $exists\n    const hasPhone = await collection.find({\n      phone: { $exists: true }\n    }).toArray();\n\n    // $type\n    const stringEmails = await collection.find({\n      email: { $type: 'string' }\n    }).toArray();\n\n    console.log('Element query results:', hasPhone.length, stringEmails.length);\n\n  } finally {\n    await client.close();\n  }\n}\n\nelementOperators().catch(console.error);\n```\n\n**Array Operators:**\n\n```javascript\nasync function arrayOperators() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // $all\n    const allTags = await collection.find({\n      tags: { $all: ['premium', 'verified'] }\n    }).toArray();\n\n    // $elemMatch\n    const elemMatch = await collection.find({\n      scores: { $elemMatch: { $gte: 80, $lt: 90 } }\n    }).toArray();\n\n    // $size\n    const exactSize = await collection.find({\n      tags: { $size: 3 }\n    }).toArray();\n\n    console.log('Array query results:', allTags.length, elemMatch.length);\n\n  } finally {\n    await client.close();\n  }\n}\n\narrayOperators().catch(console.error);\n```\n\n## Advanced Patterns\n\n**Connection Pooling:**\n\n```javascript\nimport { MongoClient } from 'mongodb';\n\nconst uri = process.env.MONGODB_URI;\n\nconst client = new MongoClient(uri, {\n  maxPoolSize: 50,\n  minPoolSize: 10,\n  maxIdleTimeMS: 30000,\n  waitQueueTimeoutMS: 5000\n});\n\nlet isConnected = false;\n\nasync function getDatabase() {\n  if (!isConnected) {\n    await client.connect();\n    isConnected = true;\n  }\n  return client.db('sample_db');\n}\n\nexport { getDatabase, client };\n```\n\n**Database and Collection Management:**\n\n```javascript\nasync function databaseManagement() {\n  try {\n    await client.connect();\n\n    // List databases\n    const adminDb = client.db().admin();\n    const dbList = await adminDb.listDatabases();\n    console.log('Databases:', dbList.databases);\n\n    // List collections\n    const database = client.db('sample_db');\n    const collections = await database.listCollections().toArray();\n    console.log('Collections:', collections);\n\n    // Create collection with options\n    await database.createCollection('newCollection', {\n      validator: {\n        $jsonSchema: {\n          bsonType: 'object',\n          required: ['name', 'email'],\n          properties: {\n            name: {\n              bsonType: 'string',\n              description: 'must be a string and is required'\n            },\n            email: {\n              bsonType: 'string',\n              pattern: '^.+@.+$',\n              description: 'must be a valid email'\n            }\n          }\n        }\n      }\n    });\n\n    // Drop collection\n    // await database.collection('oldCollection').drop();\n\n  } finally {\n    await client.close();\n  }\n}\n\ndatabaseManagement().catch(console.error);\n```\n\n**Schema Validation:**\n\n```javascript\nasync function addSchemaValidation() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n\n    await database.command({\n      collMod: 'users',\n      validator: {\n        $jsonSchema: {\n          bsonType: 'object',\n          required: ['name', 'email', 'age'],\n          properties: {\n            name: {\n              bsonType: 'string',\n              description: 'must be a string and is required'\n            },\n            email: {\n              bsonType: 'string',\n              pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$',\n              description: 'must be a valid email and is required'\n            },\n            age: {\n              bsonType: 'int',\n              minimum: 0,\n              maximum: 150,\n              description: 'must be an integer between 0 and 150'\n            },\n            status: {\n              enum: ['active', 'inactive', 'suspended'],\n              description: 'can only be one of the enum values'\n            }\n          }\n        }\n      },\n      validationLevel: 'moderate',\n      validationAction: 'error'\n    });\n\n    console.log('Schema validation added');\n\n  } finally {\n    await client.close();\n  }\n}\n\naddSchemaValidation().catch(console.error);\n```\n\n**Time Series Collections:**\n\n```javascript\nasync function createTimeSeriesCollection() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n\n    await database.createCollection('sensor_data', {\n      timeseries: {\n        timeField: 'timestamp',\n        metaField: 'sensorId',\n        granularity: 'seconds'\n      }\n    });\n\n    const collection = database.collection('sensor_data');\n\n    // Insert time series data\n    await collection.insertMany([\n      {\n        sensorId: 'sensor1',\n        timestamp: new Date('2024-01-01T00:00:00Z'),\n        temperature: 22.5,\n        humidity: 60\n      },\n      {\n        sensorId: 'sensor1',\n        timestamp: new Date('2024-01-01T00:01:00Z'),\n        temperature: 22.7,\n        humidity: 59\n      }\n    ]);\n\n    console.log('Time series data inserted');\n\n  } finally {\n    await client.close();\n  }\n}\n\ncreateTimeSeriesCollection().catch(console.error);\n```\n\n**Read and Write Concerns:**\n\n```javascript\nasync function readWriteConcerns() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Write concern\n    const insertResult = await collection.insertOne(\n      { name: 'John', email: 'john@example.com' },\n      {\n        writeConcern: {\n          w: 'majority',\n          j: true,\n          wtimeout: 5000\n        }\n      }\n    );\n\n    // Read concern\n    const findResult = await collection.findOne(\n      { email: 'john@example.com' },\n      {\n        readConcern: { level: 'majority' }\n      }\n    );\n\n    console.log('Insert result:', insertResult);\n    console.log('Find result:', findResult);\n\n  } finally {\n    await client.close();\n  }\n}\n\nreadWriteConcerns().catch(console.error);\n```\n\n**Count Documents:**\n\n```javascript\nasync function countExamples() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Count all documents\n    const totalCount = await collection.countDocuments({});\n    console.log('Total documents:', totalCount);\n\n    // Count with filter\n    const activeCount = await collection.countDocuments({ status: 'active' });\n    console.log('Active users:', activeCount);\n\n    // Estimated count (faster but less accurate)\n    const estimatedCount = await collection.estimatedDocumentCount();\n    console.log('Estimated count:', estimatedCount);\n\n  } finally {\n    await client.close();\n  }\n}\n\ncountExamples().catch(console.error);\n```\n\n**Distinct Values:**\n\n```javascript\nasync function distinctValues() {\n  try {\n    await client.connect();\n    const database = client.db('sample_db');\n    const collection = database.collection('users');\n\n    // Get distinct values\n    const cities = await collection.distinct('city');\n    console.log('Distinct cities:', cities);\n\n    // Get distinct values with filter\n    const activeCities = await collection.distinct('city', { status: 'active' });\n    console.log('Cities with active users:', activeCities);\n\n  } finally {\n    await client.close();\n  }\n}\n\ndistinctValues().catch(console.error);\n```\n"
  },
  {
    "path": "content/mongoengine/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"MongoEngine ODM for modeling, validating, and querying MongoDB documents from Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mongoengine,mongodb,odm,pymongo,nosql\"\n---\n\n# MongoEngine Python Package Guide\n\n## Golden Rule\n\nUse `mongoengine` as a thin ODM on top of MongoDB and connect with a normal MongoDB URI. Be explicit about aliases, authentication database, indexes, and dereferencing behavior. The official docs site is still branded as `0.29.0`, while PyPI currently publishes `0.29.3`, so treat the guide pages as canonical for usage patterns and cross-check release-specific behavior against PyPI and the changelog.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"mongoengine==0.29.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"mongoengine==0.29.3\"\npoetry add \"mongoengine==0.29.3\"\n```\n\nFor tests using an in-memory mock server:\n\n```bash\npython -m pip install \"mongoengine==0.29.3\" mongomock\n```\n\n## Connect And Authenticate\n\nUse `connect()` once during app startup. Prefer a MongoDB URI so auth, replica set, TLS, retry settings, and timeouts stay in one place.\n\n```python\nfrom mongoengine import connect\n\nconnect(\n    db=\"appdb\",\n    alias=\"default\",\n    host=\"mongodb://appuser:secret@localhost:27017/appdb?authSource=admin\",\n)\n```\n\nNotes:\n\n- `alias=\"default\"` is the connection name used unless a document specifies a different `db_alias`.\n- If you pass both a URI and separate parameters like `db`, `username`, or `password`, MongoEngine follows the URI values.\n- Be explicit about `authSource` when the user is stored outside the target database. Since `0.26.0`, `connect()` no longer silently defaults `authentication_source` to `admin`.\n\n### Multiple databases\n\nRegister separate aliases and bind documents with `meta[\"db_alias\"]`:\n\n```python\nfrom mongoengine import Document, StringField, connect\n\nconnect(\n    db=\"appdb\",\n    alias=\"default\",\n    host=\"mongodb://localhost:27017/appdb\",\n)\nconnect(\n    db=\"analytics\",\n    alias=\"analytics\",\n    host=\"mongodb://localhost:27017/analytics\",\n)\n\nclass AuditEvent(Document):\n    event = StringField(required=True)\n\n    meta = {\n        \"db_alias\": \"analytics\",\n        \"collection\": \"audit_events\",\n    }\n```\n\n### Testing with `mongomock`\n\nDo not use the old `mongomock://` URI form. Current MongoEngine expects an explicit client class:\n\n```python\nimport mongomock\nfrom mongoengine import connect, disconnect\n\ndisconnect(alias=\"default\")\nconnect(\n    \"mongoenginetest\",\n    alias=\"default\",\n    host=\"mongodb://localhost\",\n    mongo_client_class=mongomock.MongoClient,\n)\n```\n\nCall `disconnect()` before reconnecting an alias in tests, otherwise stale connections can leak across test cases.\n\n## Define Documents\n\nModel documents with field classes and `meta` options for collection names, indexes, ordering, and strictness:\n\n```python\nfrom mongoengine import (\n    CASCADE,\n    DateTimeField,\n    Document,\n    IntField,\n    ListField,\n    ReferenceField,\n    StringField,\n)\n\nclass User(Document):\n    email = StringField(required=True, unique=True)\n\nclass Post(Document):\n    title = StringField(required=True, max_length=200)\n    status = StringField(choices=(\"draft\", \"published\"), default=\"draft\")\n    tags = ListField(StringField(max_length=50))\n    author = ReferenceField(User, required=True, reverse_delete_rule=CASCADE)\n    published_at = DateTimeField()\n    view_count = IntField(default=0)\n\n    meta = {\n        \"collection\": \"posts\",\n        \"indexes\": [\n            \"status\",\n            \"-published_at\",\n            {\"fields\": (\"author\", \"status\"), \"unique\": False},\n        ],\n        \"ordering\": [\"-published_at\"],\n        \"strict\": True,\n    }\n```\n\nUseful upstream behaviors:\n\n- `reverse_delete_rule` matters for document relationships. Define it intentionally instead of relying on orphaned references.\n- `strict=True` is the safer default. `strict=False` accepts undeclared fields, which is useful for legacy collections but also hides typos in agent-written code.\n- MongoDB stores datetimes with millisecond precision, so `DateTimeField` values can lose microseconds.\n\n### Validation hooks\n\nUse field validation for shape constraints and `clean()` for cross-field validation or normalization that should run on `save()`:\n\n```python\nfrom mongoengine import Document, IntField, StringField, ValidationError\n\nclass Product(Document):\n    name = StringField(required=True)\n    price_cents = IntField(min_value=0, required=True)\n    currency = StringField(default=\"USD\", choices=(\"USD\", \"EUR\"))\n\n    def clean(self):\n        if self.currency == \"USD\" and self.price_cents % 5:\n            raise ValidationError(\"USD prices must be stored in 5-cent increments\")\n```\n\n`save()` runs validation by default. Raw update operations do not.\n\n## Core Usage\n\n### Create and save a document\n\n```python\nfrom datetime import datetime, timezone\n\npost = Post(\n    title=\"MongoEngine notes\",\n    author=user,\n    tags=[\"mongodb\", \"odm\"],\n    status=\"published\",\n    published_at=datetime.now(timezone.utc),\n)\npost.save()\n```\n\n### Query documents\n\n```python\npublished = Post.objects(status=\"published\").order_by(\"-published_at\")\n\nfor post in published[:20]:\n    print(post.title)\n```\n\nCompose more complex filters with `Q` objects:\n\n```python\nfrom mongoengine.queryset.visitor import Q\n\nposts = Post.objects(\n    Q(status=\"published\") & (Q(tags=\"mongodb\") | Q(title__icontains=\"mongo\"))\n)\n```\n\nCommon query operators map to Django-style suffixes such as `__in`, `__ne`, `__lte`, `__icontains`, and `__exists`.\n\n### Atomic updates\n\nPrefer update operators when you do not need full document validation:\n\n```python\nupdated = Post.objects(id=post.id).update_one(\n    set__status=\"published\",\n    inc__view_count=1,\n)\n```\n\nIf you need the updated document back:\n\n```python\npost = Post.objects(id=post.id).modify(\n    new=True,\n    set__status=\"published\",\n)\n```\n\n`modify()` and `update*()` operate directly in MongoDB and bypass `clean()` and model validation.\n\n### Reduce dereferencing overhead\n\n`ReferenceField` dereferences related documents automatically, which is convenient but can create extra queries. For hot paths:\n\n- use `select_related()` when you want eager dereferencing\n- use `no_dereference()` when you only need raw references\n- use `LazyReferenceField` instead of `ReferenceField` when you want explicit fetches\n\n## Indexing And Collection Options\n\nMongoEngine lets you declare indexes in `meta[\"indexes\"]`, but index creation behavior matters:\n\n```python\nclass Event(Document):\n    event_type = StringField(required=True)\n    created_at = DateTimeField(required=True)\n\n    meta = {\n        \"indexes\": [\n            \"event_type\",\n            {\"fields\": (\"event_type\", \"-created_at\")},\n        ],\n        \"index_background\": True,\n    }\n```\n\nOperational notes:\n\n- Since `0.26.0`, `.save()` no longer calls `ensure_indexes()` automatically.\n- If your app expects indexes to exist before writes, create them at startup with `YourDocument.ensure_indexes()` or enable `meta[\"auto_create_index_on_save\"]` deliberately.\n- `compare_indexes()` is useful in deployment checks when you need to detect drift between declared indexes and the live collection.\n- MongoEngine `0.29.0` added support for timeseries collection options via document metadata. Use this only when the backing MongoDB deployment supports timeseries collections.\n\n## Common Pitfalls\n\n- `update()`, `update_one()`, and `modify()` bypass validation and `clean()`. Use them for atomic operations, not for user-input validation paths.\n- `ReferenceField` can cause hidden N+1 behavior due to automatic dereferencing. Use `LazyReferenceField`, `select_related()`, or `no_dereference()` deliberately.\n- Delete rules only apply when the related models are imported and registered. If your app lazily imports model modules, cascade behavior can appear inconsistent.\n- `strict=False` is not a free schema-migration tool. It prevents crashes on unknown fields, but it also makes misspelled field names harder to detect.\n- Datetime precision is milliseconds, not microseconds.\n- Reusing the same alias across tests without `disconnect()` often leads to confusing state leakage.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.29.3`, released on March 10, 2026. The Read the Docs site still shows `MongoEngine 0.29.0 documentation`, so expect some release lag in headings and changelog coverage.\n- `0.29.1` fixed compatibility issues with newer PyMongo `4.8` and `4.9` releases. If older examples fail with recent PyMongo, upgrade before debugging query code.\n- `0.29.0` added timeseries collection support and `array_filters` support in `modify()`. It also changed `ListField(EmbeddedDocumentField(...))` patterns for custom embedded document classes.\n- `0.28.0` changed `no_dereference` usage so the context manager is applied from the queryset object rather than imported as a standalone helper.\n- `0.27.0` removed the legacy `mongomock://` and `is_mock` connection styles. Use `mongo_client_class=mongomock.MongoClient`.\n- `0.26.0` changed two behaviors that still break copied blog examples:\n  - `save()` no longer auto-creates indexes\n  - `connect()` no longer defaults `authentication_source` to `admin`\n\n## Official Sources\n\n- Docs root: `https://mongoengine-odm.readthedocs.io/`\n- Connecting guide: `https://mongoengine-odm.readthedocs.io/guide/connecting.html`\n- Defining documents guide: `https://mongoengine-odm.readthedocs.io/guide/defining-documents.html`\n- Querying guide: `https://mongoengine-odm.readthedocs.io/guide/querying.html`\n- Validation guide: `https://mongoengine-odm.readthedocs.io/guide/validation.html`\n- Changelog: `https://mongoengine-odm.readthedocs.io/changelog.html`\n- PyPI: `https://pypi.org/project/mongoengine/`\n"
  },
  {
    "path": "content/more-itertools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"more-itertools package guide for Python iterable helpers, recipes, and advanced iterator utilities\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"more-itertools,itertools,iterators,iterables,python,utilities\"\n---\n\n# more-itertools Python Package Guide\n\n## Golden Rule\n\nUse `more-itertools` when the standard `itertools` module is close but not quite enough. Install the package as `more-itertools`, import it as `more_itertools`, and assume most helpers either consume an iterator or cache part of it unless the docs say otherwise.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"more-itertools==10.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"more-itertools==10.8.0\"\npoetry add \"more-itertools==10.8.0\"\n```\n\n## Setup\n\nThere is no client initialization, auth, or environment configuration. Import the helpers you need directly:\n\n```python\nfrom more_itertools import chunked, windowed\n\nrows = list(chunked(range(7), 3))\nwindows = list(windowed([1, 2, 3, 4], 2))\n```\n\nIf you use many helpers in one file, the module alias is convenient:\n\n```python\nimport more_itertools as mit\n\nprint(list(mit.chunked(\"ABCDEFG\", 3)))\nprint(list(mit.sliding_window(range(5), 3)))\n```\n\n## Core Usage\n\n### Group items into batches\n\nUse `chunked()` for generic iterables when you want lists:\n\n```python\nfrom more_itertools import chunked\n\nfor batch in chunked(range(8), 3):\n    print(batch)\n\n# [0, 1, 2]\n# [3, 4, 5]\n# [6, 7]\n```\n\nSet `strict=True` when partial final batches should be rejected:\n\n```python\nfrom more_itertools import chunked\n\nlist(chunked(range(8), 3, strict=True))\n# raises ValueError because the last chunk is short\n```\n\nUse `sliced()` for sliceable sequences such as tuples, strings, and lists when you want tuple slices instead of list batches:\n\n```python\nfrom more_itertools import sliced\n\nprint(list(sliced((1, 2, 3, 4, 5), 2)))\n# [(1, 2), (3, 4), (5,)]\n```\n\n### Build sliding windows\n\nUse `windowed()` when you want padded windows or a `step` argument:\n\n```python\nfrom more_itertools import windowed\n\nprint(list(windowed([1, 2, 3, 4, 5], 3)))\n# [(1, 2, 3), (2, 3, 4), (3, 4, 5)]\n\nprint(list(windowed([1, 2, 3], 4)))\n# [(1, 2, 3, None)]\n```\n\nUse `sliding_window()` when incomplete windows should be dropped instead of padded:\n\n```python\nfrom more_itertools import sliding_window\n\nprint(list(sliding_window(range(6), 4)))\n# [(0, 1, 2, 3), (1, 2, 3, 4), (2, 3, 4, 5)]\n```\n\n### Peek ahead without consuming values\n\n`peekable()` wraps an iterator so you can look ahead, prepend items, and check truthiness for exhaustion:\n\n```python\nfrom more_itertools import peekable\n\ntokens = peekable(iter([\"SELECT\", \"*\", \"FROM\"]))\n\nif tokens and tokens.peek() == \"SELECT\":\n    print(next(tokens))\n\ntokens.prepend(\"WITH\")\nprint(list(tokens))\n# ['WITH', '*', 'FROM']\n```\n\nFor one-time inspection without changing the iterable contract, `spy()` is often simpler:\n\n```python\nfrom more_itertools import spy\n\nhead, it = spy(range(5), 2)\nprint(head)\nprint(list(it))\n```\n\n### Partition an iterable by key\n\n`bucket()` groups a source iterable into child iterables keyed by a function:\n\n```python\nfrom more_itertools import bucket\n\nitems = [\"a1\", \"b1\", \"a2\", \"c1\", \"b2\"]\ngrouped = bucket(items, key=lambda item: item[0])\n\nprint(list(grouped[\"a\"]))\nprint(list(grouped[\"b\"]))\n```\n\nUse a `validator` when probing keys that might not exist, especially for long or infinite iterables:\n\n```python\nfrom itertools import count, islice\nfrom more_itertools import bucket\n\nodds = bucket(\n    count(1, 2),\n    key=lambda n: n % 10,\n    validator=lambda key: key in {1, 3, 5, 7, 9},\n)\n\nprint(list(islice(odds[3], 3)))\nprint(list(odds[2]))\n```\n\n### Rewind an iterator\n\nUse `seekable()` when you need to revisit already-consumed values:\n\n```python\nfrom more_itertools import seekable\n\nit = seekable(str(n) for n in range(5))\n\nprint(next(it), next(it))\nit.seek(0)\nprint(list(it))\n```\n\nThis is useful when a parser needs a second pass over a streamed token source and you cannot materialize the whole input up front.\n\n## Configuration And Environment\n\n- No API keys, credentials, or environment variables are required.\n- The package is pure utility code; behavior is controlled entirely by function arguments.\n- If reproducibility matters, pin the package version explicitly because helper semantics do change across major releases.\n\n## Common Pitfalls\n\n- The package name uses a hyphen, but the import uses an underscore: `pip install more-itertools`, then `import more_itertools`.\n- Iterator helpers usually consume input. Do not expect to reuse a generator after passing it to `chunked()`, `windowed()`, `bucket()`, or similar helpers.\n- `peekable`, `seekable`, `bucket`, `ichunked`, and `distribute` can cache data internally. On large or infinite streams, this can become a memory problem.\n- `sliced()` only works with objects that support slicing. For generic iterators, use `chunked()` instead.\n- `divide()` preserves order but exhausts the input before returning; `distribute()` starts streaming sooner but uses `itertools.tee()` and changes the grouping order.\n- `windowed()` pads short inputs with `fillvalue`; `sliding_window()` yields nothing when the input is shorter than the window size.\n- `chunked()` returns lists. If you need tuple batches or want parity with newer stdlib behavior, check whether `batched()` or `itertools.batched()` is the better fit.\n\n## Version-Sensitive Notes\n\n- `10.8.0` adds `derangements()`, `argmin()`, `argmax()`, `running_median()`, and `extract()`. Prefer these over custom helpers when you see them in upstream examples.\n- `10.6.0` dropped official Python 3.8 support; current package metadata requires Python `>=3.9`.\n- `10.0.0` changed `batched()` and `matmul()` to yield tuples instead of lists. If older code expects list batches, it will break.\n- `10.0.0` also removed the `DeprecationWarning` from `batched()`. On newer Python versions, stdlib overlap is increasingly intentional, so prefer the stdlib when it already covers your use case.\n\n## Official Sources\n\n- Stable docs: `https://more-itertools.readthedocs.io/en/stable/`\n- API reference: `https://more-itertools.readthedocs.io/en/stable/api.html`\n- Version history: `https://more-itertools.readthedocs.io/en/stable/versions.html`\n- PyPI: `https://pypi.org/project/more-itertools/`\n"
  },
  {
    "path": "content/motor/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Motor async MongoDB driver for Python projects using asyncio or Tornado\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.7.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"motor,mongodb,asyncio,tornado,pymongo,database\"\n---\n\n# Motor Python Package Guide\n\n## Golden Rule\n\nUse `motor` `3.7.1` when you are maintaining an existing Motor codebase or you still need Tornado integration. For new asyncio-only projects, plan around the PyMongo Async API instead: upstream says Motor will be deprecated on May 14, 2026, with only critical bug fixes through May 14, 2027.\n\n## Install\n\nMost projects only need the base package:\n\n```bash\npython -m pip install \"motor==3.7.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"motor==3.7.1\"\npoetry add \"motor==3.7.1\"\n```\n\nOptional extras from the official PyPI metadata:\n\n```bash\npython -m pip install \"motor[srv]\"\npython -m pip install \"motor[gssapi]\"\npython -m pip install \"motor[aws]\"\npython -m pip install \"motor[ocsp]\"\npython -m pip install \"motor[snappy]\"\npython -m pip install \"motor[zstd]\"\npython -m pip install \"motor[encryption]\"\n```\n\n## Initialize One Client Per Process\n\nMotor clients connect on demand, so fail fast at startup with a `ping` instead of waiting for the first request path to discover a bad URI or auth problem.\n\n```python\nimport os\n\nfrom motor.motor_asyncio import AsyncIOMotorClient\n\nMONGODB_URI = os.environ[\"MONGODB_URI\"]\nMONGODB_DB = os.getenv(\"MONGODB_DB\", \"app\")\n\nclient = AsyncIOMotorClient(\n    MONGODB_URI,\n    appname=\"my-service\",\n    serverSelectionTimeoutMS=5000,\n)\ndb = client[MONGODB_DB]\n\nasync def startup() -> None:\n    await client.admin.command(\"ping\")\n\nasync def shutdown() -> None:\n    client.close()\n```\n\nGuidelines:\n\n- Create the client once at app startup and reuse it.\n- Close it during process shutdown.\n- Do not create a new client per request, task, or repository object.\n\n## Core CRUD Pattern\n\n`find()` returns a cursor immediately and does not perform I/O until you iterate it or call cursor helpers like `to_list()`. Most other collection operations are coroutines and must be awaited.\n\n```python\nfrom bson import ObjectId\n\nasync def create_user(email: str) -> ObjectId:\n    result = await db.users.insert_one({\"email\": email, \"active\": True})\n    return result.inserted_id\n\nasync def get_user(user_id: ObjectId) -> dict | None:\n    return await db.users.find_one({\"_id\": user_id})\n\nasync def list_active_users(limit: int = 100) -> list[dict]:\n    cursor = db.users.find({\"active\": True}).sort(\"email\", 1)\n    return await cursor.to_list(length=limit)\n\nasync def deactivate_user(user_id: ObjectId) -> None:\n    await db.users.update_one({\"_id\": user_id}, {\"$set\": {\"active\": False}})\n\nasync def delete_user(user_id: ObjectId) -> None:\n    await db.users.delete_one({\"_id\": user_id})\n```\n\nStreaming a cursor:\n\n```python\nasync def iter_active_users() -> None:\n    async for user in db.users.find({\"active\": True}):\n        print(user[\"email\"])\n```\n\n## Sessions And Transactions\n\nMotor sessions are awaited when created, but `start_transaction()` itself is not awaited.\n\n```python\nasync def transfer(from_id: ObjectId, to_id: ObjectId, amount: int) -> None:\n    async with await client.start_session() as session:\n        async with session.start_transaction():\n            await db.accounts.update_one(\n                {\"_id\": from_id},\n                {\"$inc\": {\"balance\": -amount}},\n                session=session,\n            )\n            await db.accounts.update_one(\n                {\"_id\": to_id},\n                {\"$inc\": {\"balance\": amount}},\n                session=session,\n            )\n```\n\nPass the `session=` argument to every operation that belongs inside the transaction.\n\n## Config And Authentication\n\nPrefer a standard MongoDB connection URI and keep credentials in environment variables or a secret manager.\n\n```python\nimport os\nfrom urllib.parse import quote_plus\n\nfrom motor.motor_asyncio import AsyncIOMotorClient\n\nusername = quote_plus(os.environ[\"MONGODB_USER\"])\npassword = quote_plus(os.environ[\"MONGODB_PASSWORD\"])\n\nuri = (\n    f\"mongodb://{username}:{password}@db.example.net:27017/app\"\n    \"?authSource=admin\"\n    \"&replicaSet=rs0\"\n    \"&retryWrites=true\"\n    \"&w=majority\"\n)\n\nclient = AsyncIOMotorClient(uri, tls=True)\n```\n\nPractical notes:\n\n- Percent-encode usernames and passwords before putting them in the URI.\n- Set `authSource=` when the user is stored in a different database, commonly `admin`.\n- Use `mongodb+srv://...` for Atlas or SRV-based deployments.\n- Keep timeouts explicit for production paths: `serverSelectionTimeoutMS`, `socketTimeoutMS`, and `connectTimeoutMS` are often worth setting deliberately.\n- If you use optional auth or transport features, install the matching extra before assuming the URI will work.\n\n## Tornado-Specific Entry Point\n\nIf the codebase is still on Tornado rather than native `asyncio`, use the Tornado client class instead of the asyncio variant:\n\n```python\nimport os\n\nfrom motor.motor_tornado import MotorClient\n\nclient = MotorClient(os.environ[\"MONGODB_URI\"])\ndb = client[os.getenv(\"MONGODB_DB\", \"app\")]\n```\n\nKeep the rest of the codebase consistent with that runtime. Do not mix Motor's Tornado and asyncio client styles in the same application layer.\n\n## Common Pitfalls\n\n- Do not write `await db.users.find(...)`. `find()` is synchronous and returns a cursor.\n- Do not forget the first real operation triggers connection and authentication. Call `await client.admin.command(\"ping\")` during startup if you want early failure.\n- Do not create clients per request. Reuse one client for the app lifetime.\n- `cursor.to_list()` accepts `length=None` in Motor 3.6+, but bounded lengths are safer for memory and still match most existing examples.\n- `aggregate()` returns a cursor lazily. If the pipeline uses `$out` or `$merge`, you must iterate the cursor or convert it to a list for the operation to run.\n- Close the client on shutdown so Motor can clean up connection pools and monitor threads.\n- The PyMongo Async API is similar but not identical. Migration changes include imports, missing `each()`, and some `to_list()` behavior differences.\n\n## Version-Sensitive Notes\n\n- `3.7.1` contains documentation-only changes. If your project already runs on `3.7.0`, there is no new runtime feature surface in `3.7.1`.\n- `3.7.0` added support for PyMongo `4.10` and dropped Python `3.8` and MongoDB `3.6`.\n- `3.6.0` added support for MongoDB `8.0`, raised the PyMongo floor to `4.9`, and made `MotorCursor.to_list()`'s `length` parameter optional.\n- The `latest` docs have already moved past stable and describe `3.7.2.dev0` or newer development work. For package-specific guidance against `3.7.1`, use the `/en/stable/` docs URLs instead of `/en/latest/`.\n- Upstream now treats PyMongo Async as the forward path. If you are starting greenfield asyncio code and do not need Tornado compatibility, verify whether `pymongo.AsyncMongoClient` is the better fit before adding Motor.\n\n## Official Links\n\n- Docs: `https://motor.readthedocs.io/en/stable/`\n- Requirements and compatibility: `https://motor.readthedocs.io/en/stable/requirements.html`\n- Asyncio tutorial: `https://motor.readthedocs.io/en/stable/tutorial-asyncio.html`\n- Authentication examples: `https://motor.readthedocs.io/en/stable/examples/authentication.html`\n- Changelog: `https://motor.readthedocs.io/en/stable/changelog.html`\n- Migration guide to PyMongo Async: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/`\n- PyPI package page: `https://pypi.org/project/motor/`\n"
  },
  {
    "path": "content/msal/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"MSAL for Python package guide covering app registration, token acquisition flows, caching, broker support, and version-sensitive notes for 1.35.1\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.35.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"msal,microsoft-entra,azure-ad,oauth,openid-connect,authentication,tokens,broker,managed-identity,python\"\n---\n\n# msal Python Package Guide\n\n## What This Package Is\n\n`msal` is the Microsoft Authentication Library for Python. Use it when Python code needs to sign in users or apps with Microsoft identities and acquire tokens for Microsoft Graph, Microsoft APIs, or your own APIs protected by Microsoft Entra ID.\n\nFor `1.35.1`, the PyPI release requires Python `>=3.8` and provides an optional `broker` extra. As of `2026-03-12`, the official Read the Docs landing page still shows `MSAL Python 1.35.0 documentation`, so treat the docs site as slightly behind the package version.\n\n## Install\n\n```bash\npip install \"msal==1.35.1\"\n```\n\nWith broker support:\n\n```bash\npip install \"msal[broker]==1.35.1\"\n```\n\n## Before You Write Code\n\nYou usually need a Microsoft Entra app registration with:\n\n- an application (client) ID\n- a tenant-specific authority or an explicit multi-tenant authority\n- the correct redirect URI for the flow you are using\n- delegated scopes or application permissions for the downstream API\n- a client secret or certificate for confidential clients\n\nCommon authorities:\n\n- Single tenant: `https://login.microsoftonline.com/<tenant-id>`\n- Multi-tenant workforce accounts: `https://login.microsoftonline.com/organizations`\n- Workforce plus personal Microsoft accounts: `https://login.microsoftonline.com/common`\n\nUse a tenant-specific authority for daemon apps, on-behalf-of flows, and most production web apps. `common` is mainly for interactive user sign-in.\n\n## Pick The Right Application Type\n\n- `msal.PublicClientApplication`: desktop apps, CLIs, device-code flows, and other apps that cannot safely hold a secret\n- `msal.ConfidentialClientApplication`: web apps, web APIs, daemons, and background jobs that can safely hold a client secret or certificate\n- `msal.ManagedIdentityClient`: Azure-hosted workloads using managed identity instead of an Entra app credential\n\nMSAL returns a dictionary. Check for `access_token` first and treat anything else as an error payload.\n\n```python\ndef require_access_token(result: dict) -> str:\n    if \"access_token\" in result:\n        return result[\"access_token\"]\n    raise RuntimeError(\n        f\"{result.get('error')}: {result.get('error_description')}\"\n    )\n```\n\n## Public Client Apps\n\nUse `PublicClientApplication` for user sign-in flows in CLIs, desktop apps, and local tools.\n\n### Interactive Sign-In\n\n```python\nimport msal\n\nCLIENT_ID = \"your-client-id\"\nAUTHORITY = \"https://login.microsoftonline.com/common\"\nSCOPES = [\"User.Read\"]\n\napp = msal.PublicClientApplication(\n    CLIENT_ID,\n    authority=AUTHORITY,\n)\n\naccounts = app.get_accounts()\nresult = None\n\nif accounts:\n    result = app.acquire_token_silent(SCOPES, account=accounts[0])\n\nif not result:\n    result = app.acquire_token_interactive(\n        scopes=SCOPES,\n        redirect_uri=\"http://localhost\",\n    )\n\naccess_token = require_access_token(result)\n```\n\nNotes:\n\n- `acquire_token_interactive()` uses PKCE automatically.\n- `http://localhost` must be registered as a redirect URI in the app registration.\n- For delegated user flows, request named scopes like `User.Read`, not `resource/.default`.\n\n### Device Code Flow\n\nUse this for terminals, remote shells, or headless hosts.\n\n```python\nimport json\nimport msal\n\napp = msal.PublicClientApplication(\n    \"your-client-id\",\n    authority=\"https://login.microsoftonline.com/common\",\n)\n\nflow = app.initiate_device_flow(scopes=[\"User.Read\"])\nif \"user_code\" not in flow:\n    raise RuntimeError(json.dumps(flow, indent=2))\n\nprint(flow[\"message\"])\nresult = app.acquire_token_by_device_flow(flow)\naccess_token = require_access_token(result)\n```\n\n### Brokered Interactive Sign-In\n\nBroker support is optional and platform-specific. The API reference for the current docs exposes `enable_broker_on_windows`, `enable_broker_on_mac`, `enable_broker_on_linux`, and `enable_broker_on_wsl`.\n\n```python\nimport msal\n\napp = msal.PublicClientApplication(\n    \"your-client-id\",\n    authority=\"https://login.microsoftonline.com/common\",\n    enable_broker_on_windows=True,\n)\n\nresult = app.acquire_token_interactive(\n    scopes=[\"User.Read\"],\n    parent_window_handle=app.CONSOLE_WINDOW_HANDLE,\n)\n```\n\nBroker-specific notes:\n\n- Install the package with `msal[broker]`.\n- Windows broker requires a broker redirect URI of the form `ms-appx-web://microsoft.aad.brokerplugin/<client_id>`.\n- Do not keep using `allow_broker`; the API reference marks it deprecated in favor of explicit platform flags.\n- The Learn WAM article is Windows-focused. Use the API reference for the cross-platform flags that are present in the current package line.\n\n### Avoid Username/Password\n\nDo not build new code on `acquire_token_by_username_password()`. The official docs mark it deprecated for public client flows.\n\n## Confidential Client Apps\n\nUse `ConfidentialClientApplication` when your code can securely hold credentials.\n\n### Client Credentials Flow\n\nUse this when the app acts as itself.\n\n```python\nimport msal\n\napp = msal.ConfidentialClientApplication(\n    client_id=\"your-client-id\",\n    client_credential=\"your-client-secret\",\n    authority=\"https://login.microsoftonline.com/your-tenant-id\",\n)\n\nresult = app.acquire_token_for_client(\n    scopes=[\"https://graph.microsoft.com/.default\"]\n)\n\naccess_token = require_access_token(result)\n```\n\nNotes:\n\n- Client credentials use `resource/.default` scopes.\n- Since MSAL Python `1.23`, `acquire_token_for_client()` checks the token cache before making a network call.\n- `client_credential` can be a client secret, a certificate dictionary, or another advanced credential form supported by the API docs.\n\n### Authorization Code Flow For Web Apps\n\n```python\nimport msal\n\napp = msal.ConfidentialClientApplication(\n    client_id=\"your-client-id\",\n    client_credential=\"your-client-secret\",\n    authority=\"https://login.microsoftonline.com/your-tenant-id\",\n)\n\nflow = app.initiate_auth_code_flow(\n    scopes=[\"User.Read\"],\n    redirect_uri=\"https://app.example.com/callback\",\n    response_mode=\"form_post\",\n)\n\n# Redirect the browser to flow[\"auth_uri\"]\n```\n\nThen handle the callback:\n\n```python\ntry:\n    result = app.acquire_token_by_auth_code_flow(\n        auth_code_flow=session[\"flow\"],\n        auth_response=request.form or request.args,\n    )\nexcept ValueError as exc:\n    raise RuntimeError(\"State or CSRF validation failed\") from exc\n\naccess_token = require_access_token(result)\n```\n\nNotes:\n\n- `response_mode=\"form_post\"` is safer than query parameters for web apps and is supported in the current MSAL docs.\n- Keep redirect URI, authority, and app registration settings exactly aligned.\n\n### On-Behalf-Of Flow\n\nUse this when your API receives a user token and needs a downstream token.\n\n```python\nimport msal\n\napp = msal.ConfidentialClientApplication(\n    client_id=\"your-client-id\",\n    client_credential=\"your-client-secret\",\n    authority=\"https://login.microsoftonline.com/your-tenant-id\",\n)\n\nincoming_access_token = request.headers[\"Authorization\"].split()[1]\n\nresult = app.acquire_token_on_behalf_of(\n    user_assertion=incoming_access_token,\n    scopes=[\"api://downstream-api-id/.default\"],\n)\n\ndownstream_access_token = require_access_token(result)\n```\n\n## Token Cache And Persistence\n\nMSAL caches tokens in memory by default. If you want persistence, you must supply it.\n\n```python\nimport atexit\nimport os\n\nimport msal\n\nCACHE_FILE = \".msal_cache.bin\"\n\ncache = msal.SerializableTokenCache()\nif os.path.exists(CACHE_FILE):\n    with open(CACHE_FILE, \"r\", encoding=\"utf-8\") as f:\n        cache.deserialize(f.read())\n\ndef persist_cache() -> None:\n    if cache.has_state_changed:\n        with open(CACHE_FILE, \"w\", encoding=\"utf-8\") as f:\n            f.write(cache.serialize())\n\natexit.register(persist_cache)\n\napp = msal.PublicClientApplication(\n    \"your-client-id\",\n    authority=\"https://login.microsoftonline.com/common\",\n    token_cache=cache,\n)\n```\n\nPractical rules:\n\n- Try `acquire_token_silent()` before any interactive prompt.\n- Use `acquire_token_silent_with_error()` when you need to tell \"cache miss\" from \"refresh failed\".\n- `SerializableTokenCache` does not encrypt or persist to disk by itself.\n- If you need encrypted persistence, use the Microsoft-maintained `msal-extensions` helper library.\n\n### `http_cache`\n\nMSAL also supports a separate `http_cache` for non-token HTTP metadata. It can reduce repeated instance-discovery and OpenID metadata fetches in long-lived CLIs, but its format is intentionally not stable across versions.\n\n## Managed Identity\n\nUse `ManagedIdentityClient` only on supported Azure hosts and only when you actually want managed identity semantics instead of a normal app registration.\n\n```python\nimport msal\nimport requests\n\nmanaged_identity = msal.SystemAssignedManagedIdentity()\nclient = msal.ManagedIdentityClient(\n    managed_identity,\n    http_client=requests.Session(),\n)\n\nresult = client.acquire_token_for_client(\n    resource=\"https://vault.azure.net\"\n)\n\naccess_token = require_access_token(result)\n```\n\nNotes:\n\n- Managed identity support is available in MSAL Python `1.29.0+`.\n- Managed identity uses `resource=...`, not a `scopes=[...]` list.\n- Pass a reusable `requests.Session()` as `http_client`.\n- If your code already uses Azure Identity successfully, stay there unless you specifically need MSAL-level control.\n\n## Configuration Options Worth Knowing\n\n### `client_capabilities`\n\nUse `client_capabilities=[\"CP1\"]` when your app must declare support for claims challenges such as Continuous Access Evaluation.\n\n### `exclude_scopes`\n\nMSAL historically adds `offline_access`. If you do not want refresh-token style behavior:\n\n```python\napp = msal.PublicClientApplication(\n    \"your-client-id\",\n    exclude_scopes=[\"offline_access\"],\n)\n```\n\n### `oidc_authority`\n\nUse `oidc_authority` for a custom OIDC provider outside the standard Microsoft Entra authority patterns.\n\n```python\napp = msal.PublicClientApplication(\n    \"your-client-id\",\n    oidc_authority=\"https://contoso.example/tenant\",\n)\n```\n\nNotes:\n\n- This was added before the `1.35.x` line and is available in the current package version.\n- The API docs explicitly say broker does not work with `oidc_authority`.\n\n### `instance_discovery`\n\nLeave `instance_discovery` enabled unless you know exactly which authorities are valid in your environment. Disabling it blindly can weaken authority validation.\n\n### Certificate Credentials\n\nIf you use certificate auth, verify the current credential shape against the API reference. The current docs line supports PFX-based inputs and notes that a SHA-256 thumbprint can be calculated automatically when `public_certificate` is available and `thumbprint` is omitted.\n\n## Common Pitfalls\n\n- Do not use `resource/.default` for normal interactive delegated sign-in unless that consent model is intentional.\n- Do not skip cache lookups. Repeated sign-in is usually a flow bug.\n- Do not mix broker redirect URIs and localhost redirect URIs; they solve different problems.\n- Do not treat managed identity like a normal `scopes=[...]` flow.\n- Do not use `common` for daemon apps and most production web APIs.\n- Do not disable authority validation or instance discovery unless you control the authority list.\n- Do not assume the docs site is fully version-pinned. The official docs root currently shows `1.35.0`, while the target package version here is `1.35.1`.\n- Do not keep using `allow_broker`; use the explicit platform flags instead.\n\n## Version-Sensitive Notes For 1.35.1\n\n- Target version version: `1.35.1`\n- PyPI release date: `2026-03-04`\n- Python requirement on that release: `>=3.8`\n- Optional extra on that release: `broker`\n- Official docs root status on `2026-03-12`: Read the Docs landing page still shows `MSAL Python 1.35.0 documentation`\n- Official `1.35.1` release note: instance discovery remains cloud-local on known clouds\n- Official `1.35.0` release notes and API docs highlight:\n  - Python `3.14` support\n  - support for `response_mode=\"form_post\"` in auth-code flow helpers\n  - OIDC issuer validation support for managed identity\n  - a Linux broker silent-flow redirect fix\n  - certificate handling updates around PFX inputs and SHA-256 thumbprints\n\nInference from official sources:\n\n- `1.35.1` appears to be a patch release on top of the `1.35.0` docs line, not a separate new docs set.\n- If your code depends on authority discovery behavior, broker behavior, or certificate auth details, prefer the package version page plus GitHub release notes over assuming the Read the Docs landing page is fully current.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/msal/\n- PyPI `1.35.1` page: https://pypi.org/project/msal/1.35.1/\n- API docs root: https://msal-python.readthedocs.io/en/latest/\n- Token acquisition guide: https://learn.microsoft.com/en-us/entra/msal/python/getting-started/acquiring-tokens\n- Managed identity guide: https://learn.microsoft.com/en-us/entra/msal/python/advanced/managed-identity\n- WAM and broker guide: https://learn.microsoft.com/en-us/entra/msal/python/advanced/wam\n- Releases page: https://github.com/AzureAD/microsoft-authentication-library-for-python/releases\n"
  },
  {
    "path": "content/msgpack/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"msgpack package guide for Python with pack/unpack, streaming, custom types, security limits, and compatibility flags\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"msgpack,messagepack,python,serialization,binary,streaming\"\n---\n\n# msgpack Python Package Guide\n\n## Golden Rule\n\nUse `msgpack` when you need compact binary serialization between Python and other MessagePack clients. For new Python code, serialize with `msgpack.packb(..., use_bin_type=True)` and deserialize with `msgpack.unpackb(..., raw=False, strict_map_key=True)` unless you are intentionally targeting older raw-byte behavior.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI lists `msgpack 1.1.2` released on October 8, 2025.\n- The Read the Docs site still renders page chrome that says `msgpack 1.0 documentation`, so use PyPI for exact version pinning and the API docs for behavior.\n- The upstream module code published on Read the Docs reports `__version__ = (1, 1, 2)`, which matches PyPI.\n- The `1.1.0` changelog added `buf_size` to `msgpack.Packer`, made the pure-Python fallback require keyword arguments for `Packer` and `Unpacker`, and improved `Timestamp` precision and `datetime=True` handling.\n- The `1.1.2` changelog notes source code was unchanged from `1.1.1`; the release refreshed wheels and packaging.\n\n## Install\n\nPin the version when your project depends on exact wire compatibility or reproducible builds:\n\n```bash\npython -m pip install \"msgpack==1.1.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"msgpack==1.1.2\"\npoetry add \"msgpack==1.1.2\"\n```\n\n## Initialize And Choose The API Surface\n\n`msgpack` exposes two common patterns:\n\n- `packb()` / `unpackb()` for one-shot in-memory bytes\n- `Packer` / `Unpacker` for streams, sockets, or concatenated messages\n\nMinimal import:\n\n```python\nimport msgpack\n```\n\n## Core Usage\n\n### Pack And Unpack Bytes\n\n```python\nimport msgpack\n\npayload = {\n    \"id\": 123,\n    \"name\": \"example\",\n    \"enabled\": True,\n    \"tags\": [\"a\", \"b\"],\n}\n\nwire = msgpack.packb(payload, use_bin_type=True)\nrestored = msgpack.unpackb(wire, raw=False, strict_map_key=True)\n\nprint(type(wire))      # <class 'bytes'>\nprint(restored[\"name\"])  # example\n```\n\nKey flags:\n\n- `use_bin_type=True` writes Python `bytes` using MessagePack bin types instead of old raw string encoding.\n- `raw=False` decodes MessagePack string types to Python `str` and keeps binary data as `bytes`.\n- `strict_map_key=True` rejects non-string and non-bytes map keys, which is safer for untrusted data.\n\n### Write To And Read From File-Like Objects\n\n```python\nimport io\nimport msgpack\n\nbuffer = io.BytesIO()\nmsgpack.pack({\"event\": \"created\", \"ok\": True}, buffer, use_bin_type=True)\n\nbuffer.seek(0)\nevent = msgpack.unpack(buffer, raw=False, strict_map_key=True)\nprint(event)\n```\n\nUse `pack()` and `unpack()` when you already have a file, socket wrapper, or `BytesIO`.\n\n### Stream Multiple Messages\n\nUse `Unpacker` for concatenated frames or incremental reads from a socket:\n\n```python\nimport msgpack\n\nchunks = [\n    msgpack.packb({\"seq\": 1}, use_bin_type=True),\n    msgpack.packb({\"seq\": 2}, use_bin_type=True),\n]\n\nunpacker = msgpack.Unpacker(raw=False, strict_map_key=True)\n\nfor chunk in chunks:\n    unpacker.feed(chunk)\n    for item in unpacker:\n        print(item)\n```\n\nThis is the right surface when the stream may contain zero, one, or many complete MessagePack objects per read.\n\n## Custom Types\n\nUse `default=` during packing and `ext_hook=` during unpacking for types MessagePack does not natively understand.\n\nExample with `uuid.UUID`:\n\n```python\nimport uuid\n\nimport msgpack\n\nUUID_EXT_CODE = 1\n\ndef encode_custom(obj):\n    if isinstance(obj, uuid.UUID):\n        return msgpack.ExtType(UUID_EXT_CODE, obj.bytes)\n    raise TypeError(f\"Unsupported type: {type(obj)!r}\")\n\ndef decode_custom(code, data):\n    if code == UUID_EXT_CODE:\n        return uuid.UUID(bytes=data)\n    return msgpack.ExtType(code, data)\n\nvalue = {\"user_id\": uuid.uuid4()}\nwire = msgpack.packb(value, default=encode_custom, use_bin_type=True)\nrestored = msgpack.unpackb(wire, ext_hook=decode_custom, raw=False, strict_map_key=True)\n```\n\nIf you only need tuples or subclasses handled more strictly, look at `strict_types=True` on the pack side.\n\n## Timestamp And Datetime Handling\n\n`msgpack` has native `Timestamp` support. For Python `datetime`, use timezone-aware UTC values and opt in explicitly.\n\n```python\nfrom datetime import datetime, timezone\n\nimport msgpack\n\nvalue = {\"created_at\": datetime.now(timezone.utc)}\nwire = msgpack.packb(value, datetime=True, use_bin_type=True)\n\nrestored = msgpack.unpackb(\n    wire,\n    raw=False,\n    strict_map_key=True,\n    timestamp=3,\n)\n\nprint(restored[\"created_at\"])\n```\n\nPractical rules:\n\n- `datetime=True` only packs aware datetimes with `tzinfo`.\n- `timestamp=3` unpacks timestamps as UTC `datetime.datetime` objects.\n- If you need full manual control, pack and unpack `msgpack.Timestamp` values directly.\n\n## Configuration And Compatibility\n\n### String Vs Bytes Compatibility\n\nFor modern Python-only or cross-language code:\n\n```python\nwire = msgpack.packb(value, use_bin_type=True)\nrestored = msgpack.unpackb(wire, raw=False)\n```\n\nOnly use the older raw-string compatibility mode when you must interoperate with legacy peers that still encode strings as raw bytes:\n\n```python\nwire = msgpack.packb(value, use_bin_type=False)\nrestored = msgpack.unpackb(wire, raw=True)\n```\n\n### Lists Vs Tuples\n\nBy default arrays unpack to Python `list`. If you need tuples:\n\n```python\nitem = msgpack.unpackb(wire, raw=False, use_list=False)\n```\n\n### Reusing A `Packer`\n\n`Packer` can reduce allocation overhead in tight loops:\n\n```python\nimport msgpack\n\npacker = msgpack.Packer(use_bin_type=True, autoreset=False, buf_size=1024 * 1024)\n\nfor item in [{\"n\": 1}, {\"n\": 2}]:\n    packer.pack(item)\n    wire = packer.bytes()\n    print(len(wire))\n    packer.reset()\n```\n\nNotes:\n\n- `autoreset=False` means you must call `bytes()` and then `reset()` yourself.\n- `buf_size` was added in `1.1.0` and helps when packing many similarly sized messages.\n\n### Pure Python Fallback\n\nCPython normally uses the C extension for speed. The upstream module supports forcing the pure-Python implementation with:\n\n```bash\nexport MSGPACK_PUREPYTHON=1\n```\n\nThis is mainly useful for debugging, compatibility testing, or environments where the extension cannot load. It is slower than the default extension-backed path.\n\n## Security And Limits\n\nWhen unpacking untrusted data, keep limits explicit:\n\n```python\nimport msgpack\n\nsafe_value = msgpack.unpackb(\n    wire,\n    raw=False,\n    strict_map_key=True,\n    max_buffer_size=16 * 1024 * 1024,\n)\n```\n\nImportant guardrails from the upstream docs and README:\n\n- Keep `strict_map_key=True` for untrusted input.\n- Set `max_buffer_size` deliberately for large or attacker-controlled payloads.\n- Avoid `unicode_errors=` unless you are intentionally recovering malformed input; the docs warn against casual use.\n- Expect `ExtraData` when multiple packed objects are present but you call `unpackb()` on the whole byte string.\n\n## Common Pitfalls\n\n- `packb()` returns `bytes`, not text. Do not decode it to UTF-8 just to store or send it.\n- `unpackb()` expects exactly one object. For concatenated objects, use `Unpacker`.\n- If a peer expects old raw-string behavior, `raw=False` plus `use_bin_type=True` may not round-trip with that peer.\n- Naive `datetime` values are not automatically serialized when `datetime=True`; use timezone-aware values.\n- `default=` must raise `TypeError` for unsupported objects so `msgpack` can fail predictably.\n- The pure-Python fallback in `1.1.x` expects keyword arguments for `Packer` and `Unpacker`; do not depend on positional-only initialization patterns there.\n\n## Official Sources\n\n- Docs root: `https://msgpack-python.readthedocs.io/en/latest/`\n- API reference: `https://msgpack-python.readthedocs.io/en/latest/api.html`\n- Advanced usage: `https://msgpack-python.readthedocs.io/en/latest/advanced.html`\n- Published module code: `https://msgpack-python.readthedocs.io/en/latest/_modules/msgpack.html`\n- PyPI project page: `https://pypi.org/project/msgpack/`\n- Upstream changelog: `https://github.com/msgpack/msgpack-python/blob/main/ChangeLog.rst`\n"
  },
  {
    "path": "content/mui/docs/material/javascript/DOC.md",
    "content": "---\nname: material\ndescription: \"Material UI component library for React apps using @mui/material with theming, layout, forms, and Emotion-based styling.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.3.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"mui,material-ui,react,ui,components,emotion\"\n---\n\n# Material UI Guide (JavaScript)\n\n## Golden Rule\n\nUse `@mui/material` for React UI components, and install its default styling peer dependencies at the same time: `@emotion/react` and `@emotion/styled`.\n\nFor app-wide styling, create one theme with `createTheme`, provide it with `ThemeProvider`, and add `CssBaseline` once near the root.\n\n## Install\n\nInstall the package and its default styling dependencies:\n\n```bash\nnpm install @mui/material @emotion/react @emotion/styled\n```\n\nIf your project does not already use React:\n\n```bash\nnpm install react react-dom\n```\n\nOptional packages commonly used with Material UI:\n\n```bash\nnpm install @mui/icons-material\nnpm install @fontsource/roboto\n```\n\nMaterial UI does not require API keys, secrets, or service client initialization. The only setup is React rendering plus the MUI theme provider.\n\n## Initialize Material UI\n\nCreate the theme once and wrap your app with `ThemeProvider`.\n\n```jsx\n// src/main.jsx\nimport { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { ThemeProvider, createTheme } from \"@mui/material/styles\";\nimport CssBaseline from \"@mui/material/CssBaseline\";\nimport App from \"./App.jsx\";\n\nconst theme = createTheme({\n  palette: {\n    mode: \"light\",\n    primary: {\n      main: \"#1976d2\",\n    },\n  },\n});\n\nconst rootElement = document.getElementById(\"root\");\n\nif (!rootElement) {\n  throw new Error(\"Missing #root element\");\n}\n\ncreateRoot(rootElement).render(\n  <StrictMode>\n    <ThemeProvider theme={theme}>\n      <CssBaseline />\n      <App />\n    </ThemeProvider>\n  </StrictMode>,\n);\n```\n\nUse Material UI components directly inside your app:\n\n```jsx\n// src/App.jsx\nimport { useState } from \"react\";\nimport {\n  Alert,\n  Button,\n  Container,\n  Stack,\n  TextField,\n  Typography,\n} from \"@mui/material\";\n\nexport default function App() {\n  const [email, setEmail] = useState(\"\");\n  const [submitted, setSubmitted] = useState(false);\n\n  function handleSubmit(event) {\n    event.preventDefault();\n    setSubmitted(true);\n  }\n\n  return (\n    <Container maxWidth=\"sm\" sx={{ py: 6 }}>\n      <Stack component=\"form\" spacing={3} onSubmit={handleSubmit}>\n        <Typography component=\"h1\" variant=\"h4\">\n          Create account\n        </Typography>\n\n        {submitted ? (\n          <Alert severity=\"success\">We will contact {email}.</Alert>\n        ) : null}\n\n        <TextField\n          label=\"Email\"\n          type=\"email\"\n          value={email}\n          onChange={(event) => setEmail(event.target.value)}\n          required\n          fullWidth\n        />\n\n        <Button type=\"submit\" variant=\"contained\" disabled={!email}>\n          Sign up\n        </Button>\n      </Stack>\n    </Container>\n  );\n}\n```\n\n## Common Workflows\n\n### Use `sx` for one-off layout and spacing\n\nThe `sx` prop is the fastest way to apply theme-aware spacing, color, borders, and responsive layout.\n\n```jsx\nimport { Box, Chip, Paper, Stack, Typography } from \"@mui/material\";\n\nexport function StatusCard() {\n  return (\n    <Paper\n      variant=\"outlined\"\n      sx={{\n        p: 3,\n        borderRadius: 2,\n      }}\n    >\n      <Stack direction=\"row\" spacing={1} sx={{ mb: 1.5 }}>\n        <Chip label=\"Production\" color=\"success\" size=\"small\" />\n        <Chip label=\"EU region\" variant=\"outlined\" size=\"small\" />\n      </Stack>\n\n      <Typography variant=\"h6\" sx={{ mb: 1 }}>\n        Billing service\n      </Typography>\n\n      <Box sx={{ color: \"text.secondary\" }}>\n        Healthy for the last 30 days.\n      </Box>\n    </Paper>\n  );\n}\n```\n\n### Customize shared design tokens with `createTheme`\n\nUse `createTheme` to centralize palette values, typography, and component defaults.\n\n```jsx\nimport { ThemeProvider, createTheme } from \"@mui/material/styles\";\n\nconst theme = createTheme({\n  palette: {\n    primary: {\n      main: \"#0057b8\",\n    },\n    secondary: {\n      main: \"#7b1fa2\",\n    },\n  },\n  typography: {\n    h4: {\n      fontWeight: 700,\n    },\n  },\n  components: {\n    MuiButton: {\n      defaultProps: {\n        disableElevation: true,\n      },\n    },\n    MuiTextField: {\n      defaultProps: {\n        fullWidth: true,\n        size: \"small\",\n      },\n    },\n  },\n});\n\nexport function AppProviders({ children }) {\n  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;\n}\n```\n\n### Build reusable themed components with `styled`\n\nUse `styled` when the same UI pattern appears in multiple places and should stay connected to the theme.\n\n```jsx\nimport Button from \"@mui/material/Button\";\nimport { styled } from \"@mui/material/styles\";\n\nconst PrimaryAction = styled(Button)(({ theme }) => ({\n  borderRadius: theme.shape.borderRadius * 2,\n  paddingInline: theme.spacing(3),\n  textTransform: \"none\",\n}));\n\nexport function CheckoutButton() {\n  return <PrimaryAction variant=\"contained\">Checkout</PrimaryAction>;\n}\n```\n\n### Add Material icons when you need them\n\nIcons are in a separate package.\n\n```bash\nnpm install @mui/icons-material\n```\n\n```jsx\nimport Button from \"@mui/material/Button\";\nimport SaveIcon from \"@mui/icons-material/Save\";\n\nexport function SaveButton() {\n  return (\n    <Button variant=\"contained\" startIcon={<SaveIcon />}>\n      Save changes\n    </Button>\n  );\n}\n```\n\n## Important Pitfalls\n\n- Install `@emotion/react` and `@emotion/styled` with `@mui/material`. The default Material UI setup depends on them.\n- `ThemeProvider` only affects the subtree it wraps. Put it near the top of the app if most screens share the same theme.\n- Add `CssBaseline` once, not in every page component.\n- If you want Material UI's default typography, install and load `@fontsource/roboto` or provide your own font in the theme.\n- `@mui/icons-material` is not included in `@mui/material`; install it separately before importing icons.\n\n## Version Notes\n\nThis guide targets `@mui/material` version `7.3.9` and uses the default Emotion-based styling setup from the Material UI docs.\n"
  },
  {
    "path": "content/multidict/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"multidict package guide for Python projects that need ordered multi-value mappings and case-insensitive header containers\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.7.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"multidict,python,mapping,http,headers,querystring,aio-libs\"\n---\n\n# multidict Python Package Guide\n\n## Golden Rule\n\nUse `MultiDict` or `CIMultiDict` when a key may appear more than once and insertion order matters, such as HTTP headers or URL query parameters. `md[key]`, `get()`, and `getone()` return only the first matching value; use `getall()` when duplicate keys are expected.\n\n## Install\n\n`multidict 6.7.1` requires Python `>=3.9`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"multidict==6.7.1\"\n```\n\nThe project publishes wheels for Linux, Windows, and macOS. On unsupported platforms, or on Alpine Linux where a source build is used, installation needs a C compiler and Python headers.\n\nIf you need to skip the optional C extensions during install, set the documented environment variable before running `pip`:\n\n```bash\nexport MULTIDICT_NO_EXTENSIONS=1\npython -m pip install \"multidict==6.7.1\"\n```\n\nThe maintainer docs note that the pure-Python build is much slower than the compiled extension, so prefer the default wheel install when performance matters.\n\n## Choose The Right Type\n\n- `MultiDict`: mutable mapping with duplicate keys and preserved insertion order.\n- `CIMultiDict`: like `MultiDict`, but key lookup is case-insensitive.\n- `MultiDictProxy`: read-only dynamic view over a `MultiDict`.\n- `CIMultiDictProxy`: read-only dynamic view over a `CIMultiDict`.\n- `istr`: string subclass used for case-insensitive key handling.\n\nKeys must be `str` instances or subclasses of `str` such as `istr`.\n\n## Initialize And Read Values\n\nUse a sequence of `(key, value)` pairs when duplicates matter.\n\n```python\nfrom multidict import MultiDict\n\nparams = MultiDict([\n    (\"tag\", \"python\"),\n    (\"tag\", \"asyncio\"),\n    (\"page\", \"1\"),\n])\n\nfirst_tag = params[\"tag\"]\nall_tags = params.getall(\"tag\")\npage = params.getone(\"page\")\nsort = params.get(\"sort\", \"created\")\n\nprint(first_tag)\nprint(all_tags)\nprint(page)\nprint(sort)\nprint(list(params.items()))\n```\n\n`items()`, `keys()`, and `values()` include duplicate entries in insertion order.\n\n## Add Values Without Replacing Existing Ones\n\nUse `add()` for one value at a time, or `extend()` for multiple incoming pairs.\n\n```python\nfrom multidict import MultiDict\n\nheaders = MultiDict([(\"Accept\", \"application/json\")])\n\nheaders.add(\"Accept\", \"text/plain\")\nheaders.extend([\n    (\"X-Trace-Id\", \"req-1\"),\n    (\"X-Trace-Id\", \"req-2\"),\n])\n\nprint(list(headers.items()))\nprint(headers.getall(\"Accept\"))\nprint(headers.getall(\"X-Trace-Id\"))\n```\n\nUse `extend()` when you want to keep existing values and append additional entries for the same key.\n\n## Replace Existing Values For A Key\n\nUse assignment when a key should end up with one value, and `update()` when incoming data should replace the current values for matching keys.\n\n```python\nfrom multidict import MultiDict\n\nheaders = MultiDict([\n    (\"Accept\", \"application/json\"),\n    (\"Accept\", \"text/plain\"),\n    (\"Authorization\", \"Bearer old-token\"),\n])\n\nheaders[\"Accept\"] = \"application/xml\"\nheaders.update([\n    (\"Authorization\", \"Bearer new-token\"),\n    (\"Accept\", \"application/json\"),\n    (\"Accept\", \"text/csv\"),\n])\n\nprint(list(headers.items()))\nprint(headers.getall(\"Accept\"))\n```\n\nPractical behavior:\n\n- `headers[key] = value` removes other existing values for that key and keeps one value.\n- `update(...)` replaces the current values for keys present in the incoming data.\n- If the incoming `update(...)` payload contains the same key multiple times, those incoming values are preserved.\n\n## Merge Only Missing Keys\n\nUse `merge()` when you want to add values only for keys that are not already present.\n\n```python\nfrom multidict import MultiDict\n\nheaders = MultiDict([\n    (\"Accept\", \"application/json\"),\n    (\"Authorization\", \"Bearer token\"),\n])\n\nheaders.merge([\n    (\"Accept\", \"text/plain\"),\n    (\"User-Agent\", \"example-client/1.0\"),\n])\n\nprint(list(headers.items()))\n```\n\nIn this example, `Accept` is left unchanged because the key already exists, while `User-Agent` is added.\n\n## Case-Insensitive Headers With `CIMultiDict`\n\nUse `CIMultiDict` for HTTP-style headers where lookup should ignore key casing.\n\n```python\nfrom multidict import CIMultiDict, istr\n\nheaders = CIMultiDict()\nheaders[\"Content-Type\"] = \"application/json\"\nheaders.add(\"Set-Cookie\", \"a=1\")\nheaders.add(istr(\"set-cookie\"), \"b=2\")\n\ncontent_type = headers[\"content-type\"]\ncookies = headers.getall(\"SET-COOKIE\")\n\nprint(content_type)\nprint(cookies)\nprint(\"content-type\" in headers)\nprint(list(headers.items()))\n```\n\nLookup is case-insensitive, but the inserted key strings are preserved when you iterate items.\n\n## Read-Only Views With Proxies\n\nUse a proxy when callers should be able to read a multidict without mutating it.\n\n```python\nfrom multidict import MultiDict, MultiDictProxy\n\nbase = MultiDict([(\"tag\", \"python\")])\nview = MultiDictProxy(base)\n\nbase.add(\"tag\", \"asyncio\")\nsnapshot = view.copy()\nbase.add(\"tag\", \"http\")\n\nprint(view.getall(\"tag\"))\nprint(snapshot.getall(\"tag\"))\n```\n\n`MultiDictProxy` is a live view over the original object. Call `copy()` when you need a detached mutable `MultiDict` snapshot.\n\n## Remove Values\n\nUse `popone()` to remove the first matching value, `popall()` to remove all values for a key, and `del md[key]` to delete every occurrence of the key.\n\n```python\nfrom multidict import MultiDict\n\nparams = MultiDict([\n    (\"tag\", \"python\"),\n    (\"tag\", \"asyncio\"),\n    (\"page\", \"1\"),\n])\n\nfirst_tag = params.popone(\"tag\")\nremaining_tags = params.popall(\"tag\", [])\ndel params[\"page\"]\n\nprint(first_tag)\nprint(remaining_tags)\nprint(list(params.items()))\n```\n\n## Runtime Configuration\n\n`multidict` has no service authentication, API keys, or runtime client configuration.\n\nThe only documented environment variables are install-time switches:\n\n- `MULTIDICT_NO_EXTENSIONS=1` disables the optional C extensions.\n- `MULTIDICT_DEBUG_BUILD=1` builds extensions in debug mode for extension development.\n\n## Common Pitfalls\n\n- Use `getall()` for repeated keys. `md[key]`, `get()`, and `getone()` return only the first value.\n- Use a list of pairs when duplicates matter. A plain `dict` or keyword arguments cannot represent repeated keys.\n- Use `add()` or `extend()` to preserve existing values. Assignment and `update()` replace the current values for matching keys.\n- Use `CIMultiDict` for HTTP headers. Plain `MultiDict` is case-sensitive.\n- Treat `MultiDictProxy` as a live view, not as an immutable snapshot.\n- Pass only `str` keys or subclasses of `str`; other key types raise `TypeError`.\n- Prefer the compiled extension build for production performance unless you explicitly need the pure-Python fallback.\n\n## Version-Sensitive Notes\n\n- `6.7.1` requires Python `>=3.9`.\n- PyPI classifiers for `6.7.1` include Python `3.9` through `3.14`.\n- Binary wheels are published for Linux, Windows, and macOS; unsupported targets may need a source build.\n\n## Practical Guidance For Agents\n\n1. Use `MultiDict` for query strings, form fields, or any protocol surface where the same key may repeat.\n2. Use `CIMultiDict` for HTTP headers so lookup is case-insensitive.\n3. Use `add()` or `extend()` when preserving repeated values is intentional.\n4. Use assignment or `update()` when the goal is to replace a key's existing values.\n5. Use `getall()` before serializing or forwarding repeated keys to another API.\n\n## Official Sources\n\n- Maintainer docs: `https://multidict.aio-libs.org/en/stable/`\n- Changelog: `https://multidict.aio-libs.org/en/latest/changes/`\n- Source repository: `https://github.com/aio-libs/multidict`\n- PyPI package page: `https://pypi.org/project/multidict/`\n"
  },
  {
    "path": "content/multiprocess/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"multiprocess package guide for Python projects using the official multiprocess docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.70.19\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"multiprocess,python,parallelism,processes,pool,dill\"\n---\n\n# multiprocess Python Package Guide\n\n## Golden Rule\n\nUse `multiprocess` when you want the `multiprocessing` API with `dill`-backed serialization. The package is a fork of Python's standard-library `multiprocessing`, so the core API is intentionally familiar: `Process`, `Queue`, `Pool`, `Manager`, locks, semaphores, and shared values all work the same way, with broader object serialization support.\n\nFor `0.70.19`, use the stable docs and stable PyPI metadata as the source of truth. The `latest` Read the Docs site is already on `0.70.20.dev0`.\n\n## Install\n\n`multiprocess` requires Python 3.9+ and `dill >= 0.4.1`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"multiprocess==0.70.19\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"multiprocess==0.70.19\"\npoetry add \"multiprocess==0.70.19\"\n```\n\n## Environment Variables And Initialization\n\n`multiprocess` does not use API keys, service URLs, or package-specific environment variables.\n\nImport the primitives you need directly from `multiprocess`:\n\n```python\nfrom multiprocess import (\n    Manager,\n    Pool,\n    Process,\n    Queue,\n    freeze_support,\n    set_start_method,\n)\n```\n\nIf your application needs an explicit start method, set it once before creating processes or pools:\n\n```python\nfrom multiprocess import freeze_support, set_start_method\n\n\ndef main() -> None:\n    ...\n\n\nif __name__ == \"__main__\":\n    freeze_support()\n    set_start_method(\"spawn\")\n    main()\n```\n\nUse `freeze_support()` for frozen executables and keep startup code under the `if __name__ == \"__main__\":` guard, as shown in both the `multiprocess` and Python docs.\n\n## Start A Single Worker Process\n\nThis is the smallest useful pattern for background work and process-to-process communication:\n\n```python\nfrom multiprocess import Process, Queue\n\n\ndef worker(queue: Queue) -> None:\n    queue.put(\"hello from child\")\n\n\nif __name__ == \"__main__\":\n    queue = Queue()\n    proc = Process(target=worker, args=(queue,))\n    proc.start()\n\n    print(queue.get())\n\n    proc.join()\n```\n\nUse a `Queue` when you need to pass Python objects back to the parent process.\n\n## Use A Pool For Parallel Map And Async Work\n\n`Pool` is the main API for fan-out work across multiple child processes:\n\n```python\nfrom multiprocess import Pool, TimeoutError\n\n\ndef square(x: int) -> int:\n    return x * x\n\n\nif __name__ == \"__main__\":\n    with Pool(processes=4) as pool:\n        print(pool.map(square, range(6)))\n\n        result = pool.apply_async(square, (10,))\n        print(result.get(timeout=1))\n```\n\nUse `map()` for bulk synchronous work and `apply_async()` when you want an `AsyncResult` that you can wait on later with `.get(timeout=...)`.\n\n## Use Dill-Backed Serialization For Callables That Stdlib multiprocessing Often Rejects\n\nThe main practical reason to choose `multiprocess` over `multiprocessing` is that `dill` extends serialization to most Python objects.\n\n```python\nfrom multiprocess import Pool\n\n\nif __name__ == \"__main__\":\n    with Pool(processes=4) as pool:\n        values = pool.map(\n            lambda x: (lambda y: y ** 2)(x) + x,\n            range(5),\n        )\n        print(values)\n```\n\nThis is useful when your worker function closes over state or is not a simple top-level function.\n\n## Share Mutable State With A Manager\n\nManagers let you create shared objects backed by a manager process:\n\n```python\nfrom multiprocess import Manager, Process\n\n\ndef append_item(shared_list, item: int) -> None:\n    shared_list.append(item)\n\n\nif __name__ == \"__main__\":\n    with Manager() as manager:\n        shared_list = manager.list([1, 2, 3])\n\n        proc = Process(target=append_item, args=(shared_list, 4))\n        proc.start()\n        proc.join()\n\n        print(list(shared_list))\n```\n\nUse `manager.list()`, `manager.dict()`, `manager.Queue()`, and similar helpers when several processes need coordinated access to mutable state.\n\n## Share Simple Data In Shared Memory\n\nFor simple numeric data, use `Value` and `Array`:\n\n```python\nfrom multiprocess import Array, Process, Value\n\n\ndef bump(counter: Value, numbers: Array) -> None:\n    with counter.get_lock():\n        counter.value += 1\n    numbers[0] = numbers[0] + 10\n\n\nif __name__ == \"__main__\":\n    counter = Value(\"i\", 0)\n    numbers = Array(\"i\", [1, 2, 3])\n\n    proc = Process(target=bump, args=(counter, numbers))\n    proc.start()\n    proc.join()\n\n    print(counter.value)\n    print(list(numbers))\n```\n\nUse shared memory for small, simple data structures. For richer Python objects, a manager-backed proxy is usually easier.\n\n## Common Pitfalls\n\n- Keep process and pool creation inside `if __name__ == \"__main__\":`. The official examples do this for a reason.\n- If you call `set_start_method()`, do it before creating a `Process`, `Pool`, `Manager`, `Queue`, `Value`, or `Array`. Python's multiprocessing docs note that the global start method can only be set once unless you force-reset it.\n- Manage pools explicitly. Use `with Pool(...) as pool:` or call `close()` and `join()` yourself. The Python docs warn that relying on garbage collection can leave a program hanging during shutdown.\n- Pool workers need the main module to be importable. That means ad hoc REPL snippets and notebook-local functions are a poor fit for many pool examples unless the worker function lives in an importable module.\n- Use the stable `0.70.19` docs when you are pinned to `0.70.19`. The `latest` docs currently describe the unreleased `0.70.20.dev0` line.\n\n## Version-Sensitive Notes For 0.70.19\n\n- PyPI lists `0.70.19` as the current stable release, published on January 19, 2026.\n- PyPI lists the runtime requirement as Python 3.9+, while the `latest` docs page tracks `0.70.20.dev0`. Avoid copying behavior from `latest` unless you confirm it is also present in `0.70.19`.\n- The stable docs explicitly position `multiprocess` as a fork of `multiprocessing`, so Python's standard `multiprocessing` reference is still relevant for start methods, contexts, pool lifecycle, and other process-model details.\n\n## Official Sources\n\n- Stable docs root: https://multiprocess.readthedocs.io/en/stable/\n- Development docs root (`latest`): https://multiprocess.readthedocs.io/en/latest/\n- PyPI package page: https://pypi.org/project/multiprocess/\n- Python `multiprocessing` reference: https://docs.python.org/3/library/multiprocessing.html\n"
  },
  {
    "path": "content/mypy/docs/extensions/python/DOC.md",
    "content": "---\nname: extensions\ndescription: \"mypy-extensions package guide for legacy mypy and mypyc typing helpers in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,typing,mypy,mypyc,types\"\n---\n\n# mypy-extensions Python Package Guide\n\n## Golden Rule\n\nUse `mypy-extensions` only for legacy code or for helpers that are specific to `mypy` and `mypyc`. For new application code, prefer the standard `typing` module or `typing_extensions` when the package itself marks a symbol as deprecated.\n\n## Install\n\n`mypy-extensions` 1.1.0 requires Python 3.8 or later.\n\n```bash\npython -m pip install mypy-extensions==1.1.0\n```\n\nIf you manage dependencies in `pyproject.toml`:\n\n```toml\n[project]\ndependencies = [\n  \"mypy-extensions==1.1.0\",\n]\n```\n\nThe distribution name on PyPI is `mypy-extensions`, but the import name in code is `mypy_extensions`.\n\n## Initialization And Environment\n\nThere are no environment variables, API keys, or client objects to configure. Import the helpers you need directly from `mypy_extensions`.\n\n```python\nfrom mypy_extensions import (\n    Arg,\n    DefaultArg,\n    DefaultNamedArg,\n    KwArg,\n    NamedArg,\n    VarArg,\n    i64,\n    mypyc_attr,\n    trait,\n)\n```\n\n## Recommended Modern Replacements\n\nTwo legacy names exposed by `mypy_extensions` are explicitly deprecated in 1.1.0:\n\n- `mypy_extensions.TypedDict` → use `typing.TypedDict` or `typing_extensions.TypedDict`\n- `mypy_extensions.NoReturn` → use `typing.NoReturn` or `typing_extensions.NoReturn`\n\nUse the modern forms in new code:\n\n```python\nfrom typing import NoReturn\nfrom typing_extensions import TypedDict\n\n\nclass UserPayload(TypedDict):\n    id: int\n    email: str\n\n\ndef fail(message: str) -> NoReturn:\n    raise RuntimeError(message)\n```\n\n## Common Workflows\n\n### Describe callable argument kinds for `mypy`\n\n`Arg`, `DefaultArg`, `NamedArg`, `DefaultNamedArg`, `VarArg`, and `KwArg` let `mypy` describe argument kinds inside a `Callable[...]` type. At runtime, these helpers simply return the wrapped type.\n\n```python\nfrom collections.abc import Callable\n\nfrom mypy_extensions import Arg, DefaultNamedArg, KwArg, VarArg\n\nPluginHook = Callable[[\n    Arg(str, \"event\"),\n    DefaultNamedArg(bool, \"dry_run\"),\n    VarArg(bytes),\n    KwArg(str),\n], None]\n\n\ndef emit(\n    event: str,\n    *payload: bytes,\n    dry_run: bool = False,\n    **labels: str,\n) -> None:\n    print(event, payload, dry_run, labels)\n\n\nhook: PluginHook = emit\n```\n\nUse these helpers only in type annotations. They do not enforce argument behavior at runtime.\n\n### Keep a legacy `TypedDict` import working\n\nIf you are maintaining older code that already imports `TypedDict` from `mypy_extensions`, the symbol still exists in 1.1.0, but it is deprecated and emits a `DeprecationWarning` when the typed dict class is created.\n\n```python\nfrom mypy_extensions import TypedDict\n\n\nclass LegacyMovie(TypedDict):\n    title: str\n    year: int\n\n\nmovie: LegacyMovie = {\"title\": \"Alien\", \"year\": 1979}\n```\n\nPrefer migrating that import to `typing.TypedDict` or `typing_extensions.TypedDict` instead of adding new uses of the legacy form.\n\n### Mark classes for `mypyc`\n\n`trait` and `mypyc_attr(...)` are decorators used by tooling in the `mypy` and `mypyc` ecosystem. At runtime they behave like identity decorators.\n\n```python\nfrom mypy_extensions import mypyc_attr, trait\n\n\n@trait\nclass Visitor:\n    def visit_int(self, value: int) -> str:\n        raise NotImplementedError\n\n\n@mypyc_attr(allow_interpreted_subclasses=True)\nclass Node:\n    def __init__(self, value: int) -> None:\n        self.value = value\n```\n\nUse these only if your project already relies on `mypyc` behavior. In ordinary Python execution they do not add runtime validation or behavior.\n\n### Use mypyc fixed-width integer marker types\n\n`i64`, `i32`, `i16`, and `u8` represent native fixed-width integer types for `mypyc`. In normal Python code, they construct plain `int` values and `isinstance(x, i64)` behaves like `isinstance(x, int)`.\n\n```python\nfrom mypy_extensions import i16, i64, u8\n\ncount: i64 = i64(10)\nsmall: i16 = i16(\"12\")\nbyte: u8 = u8(255)\n\nassert isinstance(count, i64)\nassert isinstance(count, int)\nassert isinstance(byte, u8)\n```\n\nThese types are useful only when your code is interpreted by tooling that understands the mypyc-specific integer semantics.\n\n## Common Pitfalls\n\n- Do not install `mypy-extensions` and then import `mypy-extensions`; the Python module name is `mypy_extensions`.\n- Do not use `mypy_extensions.TypedDict` or `mypy_extensions.NoReturn` in new code; both are deprecated in 1.1.0.\n- Do not expect `Arg(...)`, `NamedArg(...)`, `VarArg(...)`, or `KwArg(...)` to change runtime behavior; they are typing helpers, not runtime wrappers.\n- Do not use `isinstance(value, TypedDictSubclass)` or `issubclass(...)` checks with legacy typed dicts; `mypy_extensions.TypedDict` explicitly rejects instance and class checks.\n- Do not expect `i64`, `i32`, `i16`, or `u8` to behave like fixed-width integers in normal Python execution; outside mypyc-specific contexts they behave like `int`.\n- Do not assume legacy typed dict introspection matches modern `typing.TypedDict`; `mypy_extensions.TypedDict` exposes `__annotations__` and `__total__`, but not the newer required/optional key metadata used by modern typed dict implementations.\n\n## Version-Sensitive Notes For 1.1.0\n\n- `mypy-extensions` 1.1.0 declares `Requires-Python >=3.8`.\n- The 1.1.0 wheel advertises Python 3.8 through 3.13 support.\n- `TypedDict` emits a deprecation warning telling you to use `typing.TypedDict` or `typing_extensions.TypedDict`.\n- `NoReturn` is provided through module attribute fallback and emits a deprecation warning telling you to use `typing.NoReturn` or `typing_extensions.NoReturn`.\n- The package surface is intentionally small; if you need broader modern typing features, reach for `typing` or `typing_extensions` rather than expecting this package to mirror them.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/python/mypy_extensions\n- PyPI project: https://pypi.org/project/mypy-extensions/\n- 1.1.0 wheel published on PyPI: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl\n"
  },
  {
    "path": "content/mypy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"mypy package guide for Python projects using the official mypy 1.19.1 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.19.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"mypy,python,typing,type-checking,static-analysis,pep-561\"\n---\n\n# mypy Python Package Guide\n\n## Golden Rule\n\nUse `mypy` as the type checker, configure it in a single repo-level config file, and check the packages your project actually imports instead of relying on blanket global ignores. `mypy` itself requires Python `>=3.9` to run, but it can type-check code that targets older Python versions when you set `python_version` in config.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"mypy==1.19.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"mypy==1.19.1\"\npoetry add --group dev \"mypy==1.19.1\"\n```\n\nOptional extra for faster cache serialization:\n\n```bash\npython -m pip install \"mypy[faster-cache]==1.19.1\"\n```\n\nIf you run `mypy` in CI, install it in the same environment as the project dependencies and stubs it needs to inspect.\n\n## Initialize In An Existing Project\n\nStart by checking a narrow target instead of the whole repository:\n\n```bash\npython -m mypy src/\npython -m mypy path/to/module.py\n```\n\nThen add a repo-level config file. `mypy` looks for configuration in this order:\n\n1. `mypy.ini`\n2. `.mypy.ini`\n3. `pyproject.toml`\n4. `setup.cfg`\n\nThere is no config merging. Once `mypy` finds one file, that is the file it uses.\n\nRecommended `pyproject.toml` starter:\n\n```toml\n[tool.mypy]\npython_version = \"3.12\"\nfiles = [\"src\", \"tests\"]\nwarn_unused_configs = true\nstrict = true\n```\n\nUse `python_version` for the code you are checking, not necessarily the Python version used to run `mypy`.\n\nIf `strict = true` is too noisy for an existing codebase, start with a narrower baseline:\n\n```toml\n[tool.mypy]\npython_version = \"3.12\"\nfiles = [\"src\"]\nwarn_unused_configs = true\ndisallow_untyped_defs = true\nno_implicit_optional = true\nwarn_return_any = true\nwarn_redundant_casts = true\nwarn_unused_ignores = true\n```\n\n## Core Usage\n\n### Check files, packages, or modules\n\n```bash\npython -m mypy src/\npython -m mypy -p your_package\npython -m mypy -m your_package.module\n```\n\nUseful patterns:\n\n- Use `-p` to type-check an importable package.\n- Use `-m` for a specific module.\n- Use directory paths when you want the check to follow the on-disk tree directly.\n\n### Use in CI\n\n```bash\npython -m mypy --config-file pyproject.toml\n```\n\nIf the config already sets `files = [...]`, you can omit paths on the command line and let the config control the scope.\n\n### Use per-module overrides instead of global ignores\n\nPrefer targeted overrides in config:\n\n```toml\n[tool.mypy]\npython_version = \"3.12\"\nwarn_unused_configs = true\n\n[[tool.mypy.overrides]]\nmodule = [\"legacy_package.*\"]\nignore_errors = true\n\n[[tool.mypy.overrides]]\nmodule = [\"untyped_vendor_lib\"]\nignore_missing_imports = true\n```\n\nThis keeps the rest of the repo checked normally.\n\n### Install missing stub packages\n\nIf a third-party library ships no inline types, `mypy` may suggest a PEP 561 stub package such as `types-requests`.\n\nTwo options:\n\n1. Install the suggested stub package directly in your environment.\n2. Let `mypy` install available stubs:\n\n```bash\npython -m mypy --install-types --non-interactive\n```\n\n`--install-types` can be convenient, but it effectively adds an install step and then reruns the type check, so it is slower and less deterministic than pinning stub packages yourself.\n\n### Speed up repeated runs with `dmypy`\n\nFor local development on larger codebases, use the daemon:\n\n```bash\ndmypy run -- src/\ndmypy status\ndmypy restart -- src/\n```\n\n`dmypy` keeps state across runs and is often much faster than cold-starting `mypy` every time.\n\n## Import Discovery And Project Layout\n\n`mypy` needs to resolve your imports the same way your project does.\n\nCommon setups:\n\n- Standard package layout: run `mypy` from the repo root and check `src/` or the importable package.\n- `src/` layout: keep `files = [\"src\", \"tests\"]` and run from the repo root.\n- Additional local stub or source directories: set `MYPYPATH` or `mypy_path`.\n\nExample:\n\n```toml\n[tool.mypy]\npython_version = \"3.12\"\nmypy_path = [\"src\", \"stubs\"]\n```\n\nIf you use namespace packages or a nonstandard layout, read the import-discovery flags carefully before papering over errors with `ignore_missing_imports`.\n\n## Config Notes\n\n- `warn_unused_configs = true` is worth enabling immediately; it catches misspelled sections and ineffective overrides.\n- Prefer one config file at the repo root. Do not split settings across `mypy.ini` and `pyproject.toml`.\n- `files = [...]` makes CI and editor behavior more predictable than relying on ad hoc command-line paths.\n- Use per-module overrides for legacy code, generated code, or untyped vendors.\n- Use error-code-specific ignores when possible, for example `# type: ignore[attr-defined]`, instead of bare `# type: ignore`.\n\n## Common Pitfalls\n\n- Running `mypy` with one Python interpreter while the code and dependencies live in a different virtual environment. This produces missing-import noise and wrong platform assumptions.\n- Using `--ignore-missing-imports` globally. It can hide real integration problems across the whole project.\n- Forgetting that `mypy` stops at the first config file it finds. There is no merging between `mypy.ini`, `.mypy.ini`, `pyproject.toml`, and `setup.cfg`.\n- Checking the wrong target. `python -m mypy src/` and `python -m mypy -p your_package` can behave differently if the project layout is off.\n- Assuming every dependency ships types. Many still need separately installed stub packages.\n- Leaving broad `# type: ignore` comments in place after upgrading `mypy`; newer releases may support narrower and more accurate fixes.\n- Treating `strict = true` as all-or-nothing. On existing code, it is usually better to enable specific strictness flags and tighten them over time.\n\n## Version-Sensitive Notes For 1.19.1\n\n- As of March 12, 2026, PyPI and the stable docs both point to `mypy 1.19.1`.\n- `mypy 1.19.1` still requires Python `>=3.9` to run, even if you are type-checking code that targets an older Python version.\n- The stable changelog for the `1.19` line includes support work for newer Python versions such as Python 3.14. If your project is on a new interpreter, prefer current `1.19.x` docs over older blog posts.\n- The `faster-cache` extra is available on PyPI in `1.19.1`; use it when cache performance matters and you control the development environment.\n- Error codes, strictness defaults, and typeshed coverage keep evolving. Revalidate old `type: ignore` comments and per-module overrides when upgrading across `mypy` releases.\n\n## Official Sources Used\n\n- Stable docs root: `https://mypy.readthedocs.io/en/stable/`\n- Getting started: `https://mypy.readthedocs.io/en/stable/getting_started.html`\n- Config file docs: `https://mypy.readthedocs.io/en/stable/config_file.html`\n- Running and managing imports: `https://mypy.readthedocs.io/en/stable/running_mypy.html`\n- mypy daemon: `https://mypy.readthedocs.io/en/stable/mypy_daemon.html`\n- Changelog: `https://mypy.readthedocs.io/en/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/mypy/`\n"
  },
  {
    "path": "content/nanoid/docs/nanoid/javascript/DOC.md",
    "content": "---\nname: nanoid\ndescription: \"Nano ID for generating short, secure, URL-safe unique IDs in JavaScript and TypeScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.1.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"nanoid,ids,uuid,random,javascript,typescript\"\n---\n\n# Nano ID for JavaScript\n\nUse `nanoid` to generate short, URL-safe IDs without any service setup. Version `5.1.6` is a published ESM package for Node.js 18+ and also provides browser and React Native builds.\n\nThere are no environment variables, API keys, or client objects to configure. Import the functions you need and call them directly.\n\n## Install\n\n```bash\nnpm install nanoid@5.1.6\n```\n\nTo generate IDs from the command line, use the package binary through `npx`:\n\n```bash\nnpx nanoid\nnpx nanoid --size 15\nnpx nanoid --size 10 --alphabet abc\n```\n\n## Imports and runtime requirements\n\n### ECMAScript modules\n\n`nanoid@5.1.6` publishes an ESM entrypoint. In Node.js, use `import`:\n\n```js\nimport {\n  nanoid,\n  customAlphabet,\n  customRandom,\n  random,\n  urlAlphabet,\n} from 'nanoid';\n```\n\n### CommonJS\n\nThe published `5.1.6` package does not expose a CommonJS `require()` entry. If your app still runs in CommonJS, load it with dynamic `import()`:\n\n```js\nasync function createId() {\n  const { nanoid } = await import('nanoid');\n  return nanoid();\n}\n```\n\n### Browser and React Native\n\nUse the same import path in bundler-based browser apps and React Native apps:\n\n```js\nimport { nanoid } from 'nanoid';\n\nconst id = nanoid();\n```\n\n## Common workflows\n\n### Generate a default ID\n\nThe default size is `21`, which Nano ID documents as having collision probability similar to UUID v4.\n\n```js\nimport { nanoid } from 'nanoid';\n\nconst user = {\n  id: nanoid(),\n  email: 'alice@example.com',\n};\n\nconsole.log(user.id);\n```\n\n### Generate shorter or longer IDs\n\nPass a size when you need a different length.\n\n```js\nimport { nanoid } from 'nanoid';\n\nconst shortId = nanoid(10);\nconst longId = nanoid(32);\n\nconsole.log({ shortId, longId });\n```\n\n### Use a custom alphabet\n\nUse `customAlphabet()` when IDs must match an allowed character set, such as uppercase letters and digits for public order numbers.\n\n```js\nimport { customAlphabet } from 'nanoid';\n\nconst orderId = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', 12);\n\nconst id = orderId();\nconsole.log(id);\n```\n\nNano ID requires custom alphabets to contain `256` symbols or fewer.\n\n### Reuse the built-in URL-safe alphabet with a custom length\n\nIf you want the default URL-safe character set but a shorter ID, combine `urlAlphabet` with `customAlphabet()`.\n\n```js\nimport { customAlphabet, urlAlphabet } from 'nanoid';\n\nconst publicId = customAlphabet(urlAlphabet, 8);\n\nconsole.log(publicId());\n```\n\n### Use a custom random byte source\n\nUse `customRandom()` only when you already have a byte generator and need Nano ID to format the result with a specific alphabet.\n\n```js\nimport { customRandom } from 'nanoid';\n\nconst hexId = customRandom('0123456789abcdef', 16, (bytes) => {\n  return globalThis.crypto.getRandomValues(new Uint8Array(bytes));\n});\n\nconsole.log(hexId());\n```\n\nIf you want Nano ID's built-in secure randomness, use `nanoid()` or `customAlphabet()` instead.\n\n### Use the non-secure variant\n\n`nanoid/non-secure` uses a predictable random generator with a higher collision probability. Use it only when cryptographic randomness is not required.\n\n```js\nimport { nanoid, customAlphabet } from 'nanoid/non-secure';\n\nconst tempId = nanoid();\n\nconst cssScopeId = customAlphabet('abcdef0123456789', 6);\n\nconsole.log({ tempId, cssScope: cssScopeId() });\n```\n\n## TypeScript usage\n\nThe type definitions support a string subtype generic, which is useful if you brand IDs in your application types.\n\n```ts\nimport { nanoid } from 'nanoid';\n\ntype UserId = string & { readonly __brand: 'UserId' };\n\nconst id = nanoid<UserId>();\n```\n\n## CLI usage\n\nThe package ships a `nanoid` binary.\n\n```bash\nnpx nanoid --help\n```\n\nCommon examples:\n\n```bash\nnpx nanoid\nnpx nanoid -s 15\nnpx nanoid --size 10 --alphabet abc\n```\n\n## Important pitfalls\n\n- `nanoid@5.1.6` requires Node.js `^18 || >=20` in Node environments.\n- The package is ESM-first. Prefer `import`; in CommonJS, use dynamic `import()`.\n- `customAlphabet()` and `customRandom()` require alphabets with `256` symbols or fewer.\n- `nanoid/non-secure` is intentionally less safe and more collision-prone than the default secure generator.\n- Older examples may reference subpaths such as `nanoid/async`; the published `5.1.6` package exports `nanoid` and `nanoid/non-secure`.\n"
  },
  {
    "path": "content/nbconvert/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"nbconvert Python package guide for converting, executing, and templating Jupyter notebooks\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nbconvert,jupyter,notebook,export,html,pdf,cli\"\n---\n\n# nbconvert Python Package Guide\n\n## Golden Rule\n\nUse `nbconvert` when you need to convert or execute Jupyter notebooks from Python or the `jupyter nbconvert` CLI. Install the extra system dependencies that match the export target before debugging template or exporter code: Pandoc for some markup conversions, XeLaTeX for `--to pdf`, and Playwright/Chromium for `--to webpdf`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"nbconvert==7.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"nbconvert==7.17.0\"\npoetry add \"nbconvert==7.17.0\"\nconda install nbconvert\n```\n\nFor WebPDF output, upstream documents the `webpdf` extra:\n\n```bash\npython -m pip install \"nbconvert[webpdf]==7.17.0\"\nplaywright install chromium\n```\n\nImportant dependency matrix:\n\n- `--to html`, `--to markdown`, `--to script`, `--to notebook`: package install is usually enough.\n- `--to rst` and some markup conversions: requires Pandoc.\n- `--to pdf`: requires a TeX environment with XeLaTeX.\n- `--to webpdf`: requires Playwright/Chromium; `--allow-chromium-download` can fetch Chromium if a suitable version is missing.\n\n## Initialize And Check The CLI\n\nThe package integrates into Jupyter and exposes `jupyter nbconvert`:\n\n```bash\njupyter nbconvert --help\njupyter nbconvert --show-config\n```\n\nGenerate a default config file when you need stable project-level settings:\n\n```bash\njupyter nbconvert --generate-config\n```\n\nUpstream documents the config file path as:\n\n```text\n~/.jupyter/jupyter_nbconvert_config.py\n```\n\n## Core CLI Usage\n\n### Convert a notebook to HTML\n\n```bash\njupyter nbconvert --to html notebook.ipynb\n```\n\nNotes:\n\n- HTML uses the `lab` template by default in current docs.\n- The output is written in the current working directory with the notebook base name.\n- Supporting assets go into a sibling `*_files/` directory when needed.\n\n### Send simple output to stdout\n\n```bash\njupyter nbconvert --to markdown notebook.ipynb --stdout\n```\n\n### Execute a notebook and save the executed copy\n\n```bash\njupyter nbconvert --to notebook --execute report.ipynb\n```\n\nBehavior to expect:\n\n- The default output file is `report.nbconvert.ipynb`.\n- `--inplace` overwrites the original notebook.\n- Execution aborts on the first exception unless you also pass `--allow-errors`.\n\n### Convert multiple notebooks\n\n```bash\njupyter nbconvert --to html notebook1.ipynb notebook2.ipynb\njupyter nbconvert --to html notebook*.ipynb\n```\n\n### Pick a specific template\n\n```bash\njupyter nbconvert --to html notebook.ipynb --template classic\njupyter nbconvert --to html notebook.ipynb --template basic\n```\n\n## Execute Notebooks From Python\n\nUse `ExecutePreprocessor` when you need deterministic notebook execution inside tests, CI, report pipelines, or dataset refresh jobs.\n\n```python\nfrom pathlib import Path\n\nimport nbformat\nfrom nbconvert.preprocessors import ExecutePreprocessor\n\nnotebook_path = Path(\"reports/daily.ipynb\")\n\nwith notebook_path.open(encoding=\"utf-8\") as f:\n    nb = nbformat.read(f, as_version=4)\n\nep = ExecutePreprocessor(timeout=600, kernel_name=\"python3\")\nep.preprocess(nb, {\"metadata\": {\"path\": str(notebook_path.parent)}})\n\nwith Path(\"reports/daily.executed.ipynb\").open(\"w\", encoding=\"utf-8\") as f:\n    nbformat.write(nb, f)\n```\n\nExecution details that matter:\n\n- Upstream documents a default per-cell timeout of `30` seconds.\n- Set `timeout=None` or `timeout=-1` to remove the timeout.\n- `kernel_name` overrides notebook metadata when you must force a specific kernel.\n- The execution `path` controls the working directory for relative file access.\n\nIf you want execution to continue after cell failures:\n\n```python\nfrom nbconvert.preprocessors import ExecutePreprocessor\n\nep = ExecutePreprocessor(timeout=600, kernel_name=\"python3\", allow_errors=True)\n```\n\nIf you want to stop on the first error but still persist the partially executed notebook, catch `CellExecutionError` and write the notebook in `finally`.\n\n## Convert Notebooks From Python\n\nUse exporters directly when you want conversion in-process instead of spawning the CLI.\n\n```python\nimport nbformat\nfrom nbconvert import HTMLExporter\n\nwith open(\"notebook.ipynb\", encoding=\"utf-8\") as f:\n    nb = nbformat.read(f, as_version=4)\n\nexporter = HTMLExporter(template_name=\"classic\")\nbody, resources = exporter.from_notebook_node(nb)\n\nwith open(\"notebook.html\", \"w\", encoding=\"utf-8\") as f:\n    f.write(body)\n```\n\nExporter behavior to remember:\n\n- Exporters are effectively stateless and can be reused across multiple notebooks.\n- Exporters expose `from_notebook_node`, `from_file`, and `from_filename`.\n- The return value is `(body, resources)`.\n- `resources` contains output metadata and, for some exporters or preprocessors, extracted assets.\n- Writing files is your job unless you use a writer such as `FilesWriter`.\n\nWhen you need extracted figures or other preprocessor-driven outputs, configure the exporter with `traitlets.Config`:\n\n```python\nfrom traitlets.config import Config\nfrom nbconvert import HTMLExporter\n\nc = Config()\nc.HTMLExporter.preprocessors = [\"nbconvert.preprocessors.ExtractOutputPreprocessor\"]\n\nexporter = HTMLExporter(config=c)\nbody, resources = exporter.from_filename(\"notebook.ipynb\")\n\nprint(sorted(resources.get(\"outputs\", {}).keys()))\n```\n\n## Configuration And Templates\n\nThere is no service authentication layer in `nbconvert`. Configuration is about exporters, templates, preprocessors, output paths, and execution behavior.\n\nUseful CLI flags and aliases from the upstream config reference:\n\n- `--execute`\n- `--allow-errors`\n- `--stdout`\n- `--inplace`\n- `--output`\n- `--output-dir`\n- `--template`\n- `--template-file`\n- `--no-input`\n- `--allow-chromium-download`\n- `--disable-chromium-sandbox`\n\nTemplate configuration highlights:\n\n- Templates live under Jupyter data paths and typically include a `conf.json`.\n- `conf.json` declares the base template, supported mimetypes, and preprocessors to register.\n- Template inheritance is layered; derived templates can override files like `index.html.j2`, `base.html.j2`, and static assets.\n- If your custom template directory is outside the notebook directory, add `--TemplateExporter.extra_template_basedirs=/path/to/parent`.\n\nExample: hide code input across templates without inventing a custom exporter:\n\n```python\nfrom traitlets.config import Config\nfrom nbconvert import HTMLExporter\n\nc = Config()\nc.TemplateExporter.exclude_input = True\n\nexporter = HTMLExporter(config=c)\nbody, resources = exporter.from_filename(\"notebook.ipynb\")\n```\n\n## Remove Cells, Inputs, Or Outputs\n\nFor report-style output, prefer metadata-driven preprocessing over post-processing the generated HTML.\n\n```python\nfrom traitlets.config import Config\nfrom nbconvert.exporters import HTMLExporter\nfrom nbconvert.preprocessors import TagRemovePreprocessor\n\nc = Config()\nc.TagRemovePreprocessor.enabled = True\nc.TagRemovePreprocessor.remove_cell_tags = (\"remove_cell\",)\nc.TagRemovePreprocessor.remove_input_tags = (\"remove_input\",)\nc.TagRemovePreprocessor.remove_all_outputs_tags = (\"remove_output\",)\nc.HTMLExporter.preprocessors = [\"nbconvert.preprocessors.TagRemovePreprocessor\"]\n\nexporter = HTMLExporter(config=c)\nexporter.register_preprocessor(TagRemovePreprocessor(config=c), True)\n\nbody, resources = exporter.from_filename(\"notebook.ipynb\")\n```\n\nCLI equivalent:\n\n```bash\njupyter nbconvert notebook.ipynb \\\n  --to html \\\n  --TagRemovePreprocessor.enabled=True \\\n  --TagRemovePreprocessor.remove_cell_tags remove_cell\n```\n\nUse `RegexRemovePreprocessor` when the decision should be based on cell content instead of tags.\n\n## Custom Exporters\n\nReach for a custom exporter only when templates and built-in preprocessors are not enough.\n\nUpstream extension model:\n\n- Custom exporters are importable Python classes.\n- Packages can register them via the `nbconvert.exporters` entry-point group.\n- After registration, users can call them with `jupyter nbconvert --to your-exporter-name notebook.ipynb`.\n- Without entry points, users can still pass the fully qualified class name to `--to`.\n\nThis matters for agent-generated code because many examples online subclass an exporter when a template or preprocessor would be simpler and more stable.\n\n## Common Pitfalls\n\n- Missing system dependencies are the most common failure mode. `nbconvert` may be installed correctly while PDF or RST export still fails because Pandoc, XeLaTeX, or Chromium is missing.\n- `--to notebook --execute` writes `*.nbconvert.ipynb` by default, not back to the source file. Use `--inplace` only when overwriting is intentional.\n- Relative paths during execution depend on `metadata.path` in `ExecutePreprocessor.preprocess(...)`, not on the notebook file location automatically.\n- The default execution timeout is only `30` seconds per cell. Long-running notebooks need an explicit timeout override.\n- `allow_errors=True` preserves failing outputs but can hide broken notebooks if your pipeline forgets to inspect the resulting file.\n- `TemplateExporter.exclude_input` and related flags affect rendered output, not the original notebook content.\n- `--disable-chromium-sandbox` is often required in containers for WebPDF, but upstream explicitly warns it can enable server-side code execution from notebook JavaScript in some circumstances.\n- Custom exporter packages should keep CLI semantics aligned with built-ins; otherwise agent-generated flags may stop working.\n\n## Version-Sensitive Notes For 7.17.0\n\n- The upstream docs site and PyPI both reflect `7.17.0` as the current package version on that date.\n- The `7.17.0` changelog adds support for arbitrary browser arguments on `WebPDFExporter`, which is relevant when Chromium needs extra launch flags in CI or locked-down environments.\n- The same release fixes `QtPNGExporter` returning empty bytes on macOS.\n- The `7.17.0` changelog also notes a fix for `CVE-2025-53000` around secure Inkscape path handling on Windows.\n- There is mild upstream version drift in Python support messaging: the install page still says tested Python `3.9-3.12`, while the `7.17.0` changelog notes test updates for Python `3.13`, `3.14`, and dropping tests on `3.9`; PyPI metadata still says `Requires: Python >=3.9`. Prefer the PyPI floor for installation gating and treat the tested-version wording as potentially lagging docs text.\n\n## Official Sources\n\n- Docs root: https://nbconvert.readthedocs.io/en/latest/\n- Installation: https://nbconvert.readthedocs.io/en/latest/install.html\n- CLI usage: https://nbconvert.readthedocs.io/en/latest/usage.html\n- Execution API: https://nbconvert.readthedocs.io/en/latest/execute_api.html\n- Library API guide: https://nbconvert.readthedocs.io/en/latest/nbconvert_library.html\n- Config reference: https://nbconvert.readthedocs.io/en/latest/config_options.html\n- Template customization: https://nbconvert.readthedocs.io/en/latest/customizing.html\n- Exporter customization: https://nbconvert.readthedocs.io/en/latest/external_exporters.html\n- Cell removal: https://nbconvert.readthedocs.io/en/latest/removing_cells.html\n- Changelog: https://nbconvert.readthedocs.io/en/latest/changelog.html\n- PyPI metadata: https://pypi.org/project/nbconvert/\n"
  },
  {
    "path": "content/nbdev/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"nbdev for building, testing, documenting, and packaging Python libraries from Jupyter notebooks\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0.12\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nbdev,python,jupyter,notebooks,quarto,packaging,documentation\"\n---\n\n# nbdev Python Package Guide\n\n## What It Is\n\n`nbdev` is notebook-first tooling for Python libraries. Use it when notebooks are the source of truth and you want a single workflow for exported Python modules, tests, and documentation.\n\n## Install\n\nUse a virtual environment and pin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"nbdev==3.0.12\"\n```\n\n`nbdev`'s docs commands depend on Quarto. Install Quarto on any machine that will build or preview docs:\n\n```bash\nnbdev_install_quarto\n```\n\nKeep your notebook kernel in the same environment as `nbdev` and your package dependencies, otherwise notebook execution and local imports drift apart.\n\n## Auth And Environment\n\n`nbdev` is local project tooling. There is no API key, no service authentication flow, and no client object to initialize.\n\nThe important setup surfaces are:\n\n- your Python environment\n- the notebook kernel used by Jupyter\n- Quarto for docs generation and preview\n- `settings.ini` at the project root\n\n## Start A New Project\n\nRun `nbdev_new` in a new repository or empty project directory:\n\n```bash\nmkdir mylib\ncd mylib\ngit init\nnbdev_new\n```\n\nAfter scaffolding, review `settings.ini` before you export code or build docs. A minimal configuration looks like this:\n\n```ini\n[DEFAULT]\nrepo = mylib\nlib_name = mylib\nuser = your-github-user\ndescription = Notebook-first Python library\nauthor = Your Name\nauthor_email = you@example.com\nbranch = main\nversion = 0.0.1\nnbs_path = nbs\nlib_path = mylib\ndoc_path = _docs\n```\n\nThen install your package editable so exported modules are immediately importable while you work:\n\n```bash\npython -m pip install -e .\n```\n\n## Write Library Code In Notebooks\n\nThe standard pattern is:\n\n1. keep source notebooks under `nbs/`\n2. declare the target module with a `#| default_exp ...` directive\n3. mark public code cells with `#| export`\n\nExample notebook cells:\n\n```python\n#| default_exp core\n```\n\n```python\n#| export\ndef say_hello(name: str) -> str:\n    return f\"Hello {name}\"\n```\n\n`#| export` is the key directive here. If a cell is not exported, it stays notebook-only and does not become part of the generated Python package.\n\n## Export And Import The Package\n\nExport notebook code into Python modules:\n\n```bash\nnbdev_export\n```\n\nThen import the generated module normally:\n\n```python\nfrom mylib.core import say_hello\n\nprint(say_hello(\"nbdev\"))\n```\n\nEdit the notebooks, not the generated `.py` files. Re-running export overwrites generated modules.\n\n## Render API Docs In A Notebook\n\nWhen you want rendered API docs inside notebook content, `show_doc` is the main helper:\n\n```python\nfrom nbdev.showdoc import show_doc\nfrom mylib.core import say_hello\n\nshow_doc(say_hello)\n```\n\nThis is useful when notebook content is also the source for published project docs.\n\n## Core Commands\n\nThese are the commands most agents need in day-to-day use:\n\n- `nbdev_new` to scaffold a new project\n- `nbdev_export` to write exported notebook cells into Python modules\n- `nbdev_test` to run the project's tests and notebook checks\n- `nbdev_docs` to build docs\n- `nbdev_preview` to preview docs locally\n- `nbdev_clean` to strip notebook noise before committing\n- `nbdev_prepare` when you want the standard combined prep step instead of running the main commands one by one\n\n## Typical Workflow\n\n```bash\nnbdev_export\nnbdev_test\nnbdev_docs\n```\n\nFor an edit-preview loop while authoring docs:\n\n```bash\nnbdev_preview\n```\n\nFor a combined prep pass before committing or publishing:\n\n```bash\nnbdev_prepare\n```\n\n## Common Pitfalls\n\n- If Quarto is missing, docs build and preview commands fail even if export works.\n- If you forget `#| export`, your code never lands in the generated package.\n- If you edit generated modules directly, those changes are lost the next time you export from notebooks.\n- If your shell environment and notebook kernel use different Python environments, imports may work in one place and fail in the other.\n- If you copy examples from older nbdev posts, verify the commands against current nbdev 3 docs before using them unchanged.\n\n## Version-Sensitive Notes For 3.0.12\n\n- `nbdev` 3 uses a Quarto-based docs workflow, so older pre-Quarto guidance is often stale.\n- The main user-facing surface is the CLI plus notebook directives; most projects should not import `nbdev` into application runtime code.\n- Treat `settings.ini` as part of the project's source of truth. If `lib_name`, paths, or repo metadata drift, exports and docs generation become confusing quickly.\n\n## Official Sources\n\n- nbdev docs: `https://nbdev.fast.ai/`\n- PyPI: `https://pypi.org/project/nbdev/`\n"
  },
  {
    "path": "content/nbformat/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"nbformat package guide for reading, validating, converting, and signing Jupyter notebooks in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.10.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nbformat,jupyter,notebook,ipynb,validation,jsonschema\"\n---\n\n# nbformat Python Package Guide\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"nbformat==5.10.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"nbformat==5.10.4\"\npoetry add \"nbformat==5.10.4\"\n```\n\nPyPI currently lists Python 3.8 through 3.12 classifiers for `5.10.4`.\n\n## Setup And Version Selection\n\nNotebook files are JSON documents with top-level `metadata`, `nbformat`, `nbformat_minor`, and `cells` keys. In Python, `nbformat` works with `NotebookNode` objects, which behave like dictionaries with attribute access.\n\nCheck the notebook format version your installed library understands:\n\n```python\nimport nbformat\n\nprint(nbformat.current_nbformat)\nprint(nbformat.current_nbformat_minor)\n```\n\nWhen reading notebooks, always pass an explicit `as_version`:\n\n```python\nimport nbformat\n\nnb = nbformat.read(\"analysis.ipynb\", as_version=4)\n```\n\nUse:\n\n- `as_version=4` when your code expects the current 4.x notebook structure\n- `as_version=nbformat.NO_CONVERT` when you want to preserve the on-disk version exactly\n\n## Core Usage\n\n### Create A Notebook Programmatically\n\n```python\nfrom pathlib import Path\n\nimport nbformat\nfrom nbformat.v4 import new_code_cell, new_markdown_cell, new_notebook\n\nnb = new_notebook(\n    metadata={\n        \"kernelspec\": {\n            \"name\": \"python3\",\n            \"display_name\": \"Python 3\",\n        },\n        \"language_info\": {\n            \"name\": \"python\",\n            \"version\": \"3.12\",\n        },\n    },\n    cells=[\n        new_markdown_cell(\"# Demo notebook\"),\n        new_code_cell(\"answer = 40 + 2\\nprint(answer)\"),\n    ],\n)\n\nnbformat.validate(nb)\nnbformat.write(nb, Path(\"demo.ipynb\"))\n```\n\nUse the `nbformat.v4` constructors instead of hand-building cell dictionaries. They create the required shape for notebook and cell objects.\n\n### Read, Validate, And Update A Notebook\n\n```python\nimport nbformat\nfrom nbformat import ValidationError\n\npath = \"analysis.ipynb\"\nnb = nbformat.read(path, as_version=4)\n\ntry:\n    nbformat.validate(nb)\nexcept ValidationError as exc:\n    raise RuntimeError(f\"Invalid notebook: {exc}\") from exc\n\nnb.cells.append(nbformat.v4.new_markdown_cell(\"Generated by automation.\"))\nnbformat.write(nb, path)\n```\n\nIf you want validation details without raising during `read()` or `write()`, pass a mutable dict to `capture_validation_error`.\n\n### Work From A Raw Dict Or JSON String\n\n```python\nimport nbformat\n\npayload = {\n    \"cells\": [],\n    \"metadata\": {},\n    \"nbformat\": 4,\n    \"nbformat_minor\": 5,\n}\n\nnb = nbformat.from_dict(payload)\nnbformat.validate(nb)\n\ntext = nbformat.writes(nb)\nround_tripped = nbformat.reads(text, as_version=4)\n```\n\n`from_dict()` only converts nested dictionaries into `NotebookNode` objects. It does not make invalid notebook content valid, so call `validate()` before trusting the result.\n\n### Convert Notebook Versions\n\n```python\nimport nbformat\n\nnb = nbformat.read(\"legacy.ipynb\", as_version=nbformat.NO_CONVERT)\n\nif nb.nbformat != 4:\n    nb = nbformat.convert(nb, 4)\n    nbformat.validate(nb)\n    nbformat.write(nb, \"legacy-v4.ipynb\")\n```\n\n`convert()` works across major notebook versions. It is useful when migration code needs a stable 4.x shape before making edits.\n\n### Sign And Trust Notebooks\n\nUse notebook signing only if your workflow participates in Jupyter's trust model for outputs.\n\n```python\nimport nbformat\nfrom nbformat.sign import NotebookNotary\n\npath = \"report.ipynb\"\nnb = nbformat.read(path, as_version=4)\n\nnotary = NotebookNotary()\n\nif not notary.check_signature(nb):\n    notary.sign(nb)\n    notary.mark_cells(nb, True)\n    nbformat.write(nb, path)\n```\n\n`NotebookNotary` uses an SQLite-backed signature store by default when SQLite bindings are available, and an in-memory store otherwise.\n\n## Configuration Notes\n\n- `nbformat` does not use network auth, API keys, or service credentials.\n- The main runtime choice is validator behavior. The upstream repository notes that `fastjsonschema` is the default validator in current releases; set `NBFORMAT_VALIDATOR=jsonschema` if you need the `jsonschema` backend instead.\n- Treat notebook metadata as shared namespace. For custom metadata, use a unique prefix such as `metadata.my_tool.*`.\n- Notebook files on disk may store multi-line strings as either a string or a list of strings. The Python API normalizes these back to strings when reading.\n\n## Common Pitfalls\n\n- Do not read notebooks without `as_version`. The API expects you to declare which structure your code knows how to handle.\n- Do not treat arbitrary dictionaries as valid notebooks just because `from_dict()` succeeded. Validation is separate.\n- Do not depend on `validate()` to silently repair notebooks. That behavior was deprecated in `5.5.0`.\n- Do not generate duplicate or malformed cell IDs. Since the 4.5 schema, every cell must have a unique `id` matching the schema rules.\n- Do not assume all metadata is meaningful. The format explicitly allows optional metadata that tools may ignore.\n- Do not parse notebook JSON manually unless you really need raw control. The library already handles version conversion, NotebookNode wrapping, and validation.\n\n## Version-Sensitive Notes\n\n- `5.10.4` is a maintenance release. The upstream changelog does not list API-level behavior changes for this patch.\n- Since `5.5.0`, `validate()` no longer represents the \"fix up the notebook for me\" path. If you truly need normalization, call the validator module's `normalize()` helper explicitly, but upstream still recommends generating valid notebooks directly.\n- Since `5.3.0`, `fastjsonschema` is the default validator backend.\n- Since `5.1.0` and the 4.5 notebook schema, cell IDs are part of the spec. Older blog posts and old handcrafted notebook fixtures often miss them.\n\n## Official Sources\n\n- Docs root: `https://nbformat.readthedocs.io/en/latest/`\n- Python API: `https://nbformat.readthedocs.io/en/latest/api.html`\n- Notebook format description: `https://nbformat.readthedocs.io/en/latest/format_description.html`\n- Changelog: `https://nbformat.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/nbformat/`\n"
  },
  {
    "path": "content/neo4j/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Neo4j Python driver for connecting to Neo4j, running Cypher queries, and managing transactions\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"neo4j,graph,database,cypher,bolt,asyncio\"\n---\n\n# Neo4j Python Package Guide\n\n## Golden Rule\n\nUse the official `neo4j` package for Python applications. Do not install `neo4j-driver`; the API docs mark `neo4j-driver` as the old package name and say it stopped receiving updates starting with 6.0.0.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"neo4j==6.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"neo4j==6.1.0\"\npoetry add \"neo4j==6.1.0\"\n```\n\nOptional high-performance drop-in replacement:\n\n```bash\npython -m pip install neo4j-rust-ext\n```\n\nThe Rust extension uses the same API as `neo4j` and the Neo4j manual says it can be significantly faster.\n\n## Initialize The Driver\n\nThe core entry point is `GraphDatabase.driver(...)`. Create one long-lived driver per process, verify connectivity once, and create short-lived sessions as needed.\n\n```python\nimport os\nfrom neo4j import GraphDatabase\n\nURI = os.environ[\"NEO4J_URI\"]\nAUTH = (os.environ[\"NEO4J_USERNAME\"], os.environ[\"NEO4J_PASSWORD\"])\nDATABASE = os.getenv(\"NEO4J_DATABASE\", \"neo4j\")\n\ndriver = GraphDatabase.driver(URI, auth=AUTH)\ndriver.verify_connectivity()\n\ntry:\n    records, summary, keys = driver.execute_query(\n        \"\"\"\n        MERGE (p:Person {name: $name})\n        SET p.updated_at = datetime()\n        RETURN p.name AS name, p.updated_at AS updated_at\n        \"\"\",\n        name=\"Alice\",\n        database_=DATABASE,\n    )\n    print(records[0][\"name\"])\nfinally:\n    driver.close()\n```\n\nRecommended environment variables:\n\n```bash\nexport NEO4J_URI=\"neo4j+s://<instance-id>.databases.neo4j.io\"\nexport NEO4J_USERNAME=\"neo4j\"\nexport NEO4J_PASSWORD=\"<password>\"\nexport NEO4J_DATABASE=\"neo4j\"\n```\n\nFor local development, the URI is often `neo4j://localhost:7687` or `bolt://localhost:7687`.\n\n## Connection And Auth\n\n### URI schemes\n\n- `neo4j://`: routing-aware connection, good default for local and clustered setups\n- `neo4j+s://`: TLS with CA-signed certificates; this is the normal Aura scheme\n- `neo4j+ssc://`: TLS with self-signed certificates\n- `bolt://`: direct connection to a specific server, without routing\n\nUse the scheme required by the server. The driver does not infer it for you.\n\n### Basic auth\n\nBasic username/password auth is the common case:\n\n```python\nfrom neo4j import GraphDatabase\n\ndriver = GraphDatabase.driver(\n    \"neo4j+s://<instance-id>.databases.neo4j.io\",\n    auth=(\"neo4j\", \"password\"),\n)\n```\n\n### Bearer or rotating auth\n\nIf your Neo4j deployment uses SSO or expiring bearer tokens, use an auth manager instead of rebuilding the driver for each token refresh:\n\n```python\nimport neo4j\nfrom neo4j.auth_management import AuthManagers, ExpiringAuth\n\ndef auth_provider():\n    token = get_sso_token()\n    return ExpiringAuth(\n        auth=neo4j.bearer_auth(token)\n    ).expires_in(50)\n\ndriver = neo4j.GraphDatabase.driver(\n    URI,\n    auth=AuthManagers.bearer(auth_provider),\n)\n```\n\nThe auth manager must always return credentials for the same identity. It is not a user-switching mechanism.\n\n## Core Query Workflow\n\n### Use `execute_query()` for one query\n\n`driver.execute_query()` is the simplest API for a single query. It eagerly returns `(records, summary, keys)`.\n\n```python\nrecords, summary, keys = driver.execute_query(\n    \"\"\"\n    MATCH (p:Person)\n    WHERE p.name STARTS WITH $prefix\n    RETURN p.name AS name\n    ORDER BY name\n    LIMIT $limit\n    \"\"\",\n    prefix=\"Al\",\n    limit=10,\n    database_=\"neo4j\",\n    routing_=\"r\",\n)\n\nnames = [record[\"name\"] for record in records]\nprint(names)\nprint(summary.result_available_after)\n```\n\nRules that matter:\n\n- Always pass `database_=\"...\"` explicitly. Neo4j documents this as both the recommended pattern and a performance optimization.\n- Use Cypher parameters like `$prefix` and `$limit`; do not build query strings with string interpolation.\n- Use `routing_=\"r\"` for read-only queries when you want the driver to route them as reads.\n\n### Use sessions and managed transactions for multi-step writes\n\nUse a session plus `execute_write()` or `execute_read()` when a logical operation spans multiple queries.\n\n```python\nfrom neo4j import GraphDatabase\n\ndef create_friendship(tx, person_name: str, friend_name: str) -> list[str]:\n    tx.run(\n        \"MERGE (:Person {name: $name})\",\n        name=person_name,\n    )\n    result = tx.run(\n        \"\"\"\n        MATCH (a:Person {name: $person_name})\n        MERGE (b:Person {name: $friend_name})\n        MERGE (a)-[:KNOWS]->(b)\n        RETURN a.name AS person, b.name AS friend\n        \"\"\",\n        person_name=person_name,\n        friend_name=friend_name,\n    )\n    record = result.single(strict=True)\n    return [record[\"person\"], record[\"friend\"]]\n\nwith GraphDatabase.driver(URI, auth=AUTH) as driver:\n    with driver.session(database=\"neo4j\") as session:\n        person, friend = session.execute_write(\n            create_friendship,\n            \"Alice\",\n            \"Bob\",\n        )\n        print(person, friend)\n```\n\nImportant transaction behavior:\n\n- Sessions are lightweight and not thread-safe. Create a separate session per thread or unit of work.\n- Transaction callbacks should return concrete values, not the raw `Result` object.\n- Managed transactions retry retryable failures for you; if you catch `Neo4jError`, check `is_retryable()` before retrying explicit transaction logic.\n\n## Async Usage\n\nUse `AsyncGraphDatabase` if your application already uses `asyncio` and needs concurrent database work.\n\n```python\nimport asyncio\nfrom neo4j import AsyncGraphDatabase\n\nURI = \"neo4j+s://<instance-id>.databases.neo4j.io\"\nAUTH = (\"neo4j\", \"password\")\n\nasync def main() -> None:\n    async with AsyncGraphDatabase.driver(URI, auth=AUTH) as driver:\n        await driver.verify_connectivity()\n        records, summary, keys = await driver.execute_query(\n            \"MATCH (p:Person) RETURN p.name AS name LIMIT 5\",\n            database_=\"neo4j\",\n            routing_=\"r\",\n        )\n        print([record[\"name\"] for record in records])\n\nasyncio.run(main())\n```\n\nOnly use the async driver if the rest of the stack is async-aware. Do not share async sessions across tasks.\n\n## Common Configuration\n\nTypical application configuration:\n\n```python\nimport os\n\nNEO4J_URI = os.environ[\"NEO4J_URI\"]\nNEO4J_USERNAME = os.environ[\"NEO4J_USERNAME\"]\nNEO4J_PASSWORD = os.environ[\"NEO4J_PASSWORD\"]\nNEO4J_DATABASE = os.getenv(\"NEO4J_DATABASE\", \"neo4j\")\n```\n\nOperational guidance:\n\n- Keep one driver object per app process and inject it where needed.\n- Keep secrets out of source control.\n- Explicitly close drivers and sessions, or use `with` / `async with`.\n- If you need to run queries as another user for a single operation, use the `auth_=` parameter on `execute_query()` instead of creating a separate driver.\n\n## Common Pitfalls\n\n- Installing `neo4j-driver` instead of `neo4j`. `neo4j-driver` is deprecated and frozen.\n- Omitting `database_` or `database`. It works, but costs an extra round-trip and is not the recommended pattern.\n- Returning a raw `Result` from a transaction callback. Consume it inside the callback and return plain Python values.\n- Forgetting to close the driver. In 6.x, objects are not implicitly closed in destructors.\n- Using removed APIs such as `session.read_transaction()` and `session.write_transaction()`. In 6.x, use `execute_read()` and `execute_write()`.\n- Relying on legacy numeric graph ids. Prefer `element_id` over `id`.\n- Mixing query parameters into strings instead of using Cypher placeholders.\n\n## Version-Sensitive Notes For 6.1.0\n\n- PyPI currently lists `neo4j 6.1.0`, released on January 12, 2026.\n- The current 6.x manual says this driver line is compatible with Neo4j 4.4, 5.x, and the 2025/2026 server series, so driver upgrades can usually happen before server upgrades.\n- Version 6 removed `read_transaction()` and `write_transaction()`, removed implicit cleanup through `__del__()`, and stopped updating the `neo4j-driver` package alias.\n- The 6.x upgrade guide also calls out newer `Vector` support and GQL status objects in errors. If you are updating older code, review the upstream upgrade page before copying 5.x examples.\n\n## Official Sources\n\n- Python manual: https://neo4j.com/docs/python-manual/current/\n- Connect to the database: https://neo4j.com/docs/python-manual/current/connect/\n- Query the database: https://neo4j.com/docs/python-manual/current/query-simple/\n- Run your own transactions: https://neo4j.com/docs/python-manual/current/transactions/\n- Run concurrent transactions: https://neo4j.com/docs/python-manual/current/concurrency/\n- Performance recommendations: https://neo4j.com/docs/python-manual/current/performance/\n- Advanced connection information: https://neo4j.com/docs/python-manual/current/connect-advanced/\n- API docs: https://neo4j.com/docs/api/python-driver/current/\n- PyPI: https://pypi.org/project/neo4j/\n"
  },
  {
    "path": "content/neptune/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Neptune package guide for Python experiment tracking with runs, auth, offline mode, and 2.x versus Neptune Scale docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"neptune,python,experiment-tracking,mlops,metadata,logging,runs\"\n---\n\n# Neptune Python Package Guide\n\n## Golden Rule\n\n- For `neptune==1.14.0`, use the legacy Neptune 2.x client API: `import neptune` and `neptune.init_run(...)`.\n- Do not mix this package with Neptune 3.x / `neptune-scale` examples from the main docs landing pages.\n- Set `NEPTUNE_API_TOKEN` and `NEPTUNE_PROJECT` before running code unless you pass `api_token=` and `project=` explicitly.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.14.0`.\n- The docs URL now points at Neptune's current docs experience, which includes Neptune 3.x and `neptune-scale`. For `neptune==1.14.0`, the official package docs are under `docs-legacy.neptune.ai`.\n- Neptune's official GitHub repository is still named `neptune-client`, but the maintained PyPI package is `neptune`.\n- Older blog posts and snippets may still say `pip install neptune-client`. For new installs matching this entry, use `pip install neptune==1.14.0`.\n- `neptune.init_run()` supports multiple connection modes. The practical ones are `async` (default), `sync`, `offline`, `read-only`, and `debug`.\n\n## Install\n\nInstall the pinned version:\n\n```bash\npython -m pip install \"neptune==1.14.0\"\n```\n\nVerify the import and version:\n\n```bash\npython - <<'PY'\nimport neptune\nprint(neptune.__version__)\nPY\n```\n\n## Authentication And Project Setup\n\nThe official docs use two main environment variables:\n\n- `NEPTUNE_API_TOKEN`: your user or service-account token\n- `NEPTUNE_PROJECT`: project name in `workspace-name/project-name` form\n\nSet them in the shell:\n\n```bash\nexport NEPTUNE_API_TOKEN=\"your-api-token\"\nexport NEPTUNE_PROJECT=\"workspace-name/project-name\"\n```\n\nThen initialize without hardcoding secrets in code:\n\n```python\nimport neptune\n\nrun = neptune.init_run()\n```\n\nIf you need explicit configuration:\n\n```python\nimport neptune\n\nrun = neptune.init_run(\n    project=\"workspace-name/project-name\",\n    api_token=\"your-api-token\",\n)\n```\n\nUse the special token `ANONYMOUS` only for public projects where anonymous access is enabled.\n\n## Initialize A Run\n\nStart with a single run object and close it when the script is done:\n\n```python\nimport neptune\n\nrun = neptune.init_run()\n\nrun[\"parameters\"] = {\n    \"learning_rate\": 1e-3,\n    \"batch_size\": 64,\n    \"optimizer\": \"adamw\",\n}\n\nrun[\"train/loss\"].append(0.842)\nrun[\"train/loss\"].append(0.611)\nrun[\"train/accuracy\"] = 0.91\nrun[\"sys/tags\"].add([\"baseline\", \"resnet\"])\n\nrun.stop()\n```\n\nUse `run.stop()` in scripts, tests, and batch jobs so buffered metadata is flushed before process exit.\n\n## Core Logging Patterns\n\n### Log scalar values and time series\n\nUse assignment for single values and `append(...)` for series:\n\n```python\nrun[\"eval/f1\"] = 0.88\nrun[\"train/loss\"].append(0.42)\nrun[\"train/loss\"].append(0.31)\n```\n\n### Log files and artifacts\n\n```python\nrun[\"artifacts/model\"].upload(\"checkpoints/model.pt\")\nrun[\"artifacts/config\"].upload(\"configs/train.yaml\")\n```\n\n### Organize metadata by namespace\n\nNeptune fields are path-like keys. Use stable namespaces so downstream dashboards and queries stay consistent:\n\n```python\nrun[\"config/model/name\"] = \"resnet50\"\nrun[\"metrics/val/loss\"].append(0.27)\nrun[\"metrics/val/accuracy\"].append(0.93)\n```\n\n## Resume Or Reattach To Existing Runs\n\nUse `with_id=` when you already know the Neptune run ID and want to reopen that run:\n\n```python\nimport neptune\n\nrun = neptune.init_run(with_id=\"CLS-123\")\nrun[\"train/loss\"].append(0.22)\nrun.stop()\n```\n\nUse `custom_run_id=` when your application has its own stable external identifier for a run:\n\n```python\nimport neptune\n\nrun = neptune.init_run(custom_run_id=\"train-job-2026-03-12-001\")\n```\n\nPractical distinction:\n\n- `with_id=`: reopen a specific Neptune run that already exists\n- `custom_run_id=`: attach your own stable identifier to a run so distributed or restarted jobs can refer to it consistently\n\n## Useful Modes\n\n### Default: `async`\n\n`async` is the default mode. Use it for normal training or application code where background logging is fine.\n\n```python\nrun = neptune.init_run(mode=\"async\")\n```\n\n### `sync`\n\nUse `sync` when you want logging calls to block until data is sent. This is useful in short-lived scripts or tests where you want simpler timing behavior.\n\n```python\nrun = neptune.init_run(mode=\"sync\")\n```\n\n### `offline`\n\nUse `offline` when the job cannot reach Neptune during execution. The legacy docs describe syncing offline data later with the `neptune sync` CLI.\n\n```python\nrun = neptune.init_run(mode=\"offline\")\n```\n\n### `read-only`\n\nUse `read-only` for code that only fetches metadata from existing objects and must not create new logs.\n\n```python\nrun = neptune.init_run(with_id=\"CLS-123\", mode=\"read-only\")\n```\n\n### `debug`\n\nUse `debug` in tests when you want Neptune calls to be effectively disabled without touching production code paths.\n\n```python\nrun = neptune.init_run(mode=\"debug\")\n```\n\n## Reading Existing Metadata\n\nFor inspection code, fetch existing fields instead of re-logging them:\n\n```python\nimport neptune\n\nrun = neptune.init_run(with_id=\"CLS-123\", mode=\"read-only\")\n\nbest_score = run[\"eval/best_f1\"].fetch()\nprint(best_score)\n\nrun.stop()\n```\n\nUse read-only access in analysis scripts, dashboards, or CI verification steps so they cannot accidentally mutate tracking state.\n\n## Common Pitfalls\n\n### Mixing the wrong Neptune product docs\n\nThe biggest failure mode is using current Neptune Scale docs for this package. If the example imports `neptune_scale`, talks about Neptune 3.x tables as the primary API, or assumes the new docs navigation, it is not the right source for `neptune==1.14.0`.\n\n### Forgetting `run.stop()`\n\nIn notebooks this is less visible, but in short-lived scripts or worker jobs, failing to stop the run can leave data unsent.\n\n### Wrong project format\n\n`project=` is not a URL. Use `workspace-name/project-name`.\n\n### Confusing `with_id` and `custom_run_id`\n\n`with_id` reopens a Neptune run by Neptune's own identifier. `custom_run_id` is your application-level identifier. Using the wrong one leads to resume bugs and duplicate tracking records.\n\n### Assuming anonymous auth works everywhere\n\nThe `ANONYMOUS` token only works for public projects configured to allow it. For private workspaces, use a real API token.\n\n### Ignoring offline and test modes\n\nFor air-gapped jobs, CI, or unit tests, choose `offline`, `read-only`, or `debug` deliberately instead of letting default networked logging fail at runtime.\n\n## Recommended Workflow For Agents\n\n1. Confirm the project is using the legacy `neptune` package, not `neptune-scale`.\n2. Pin `neptune==1.14.0` if reproducibility matters.\n3. Set `NEPTUNE_API_TOKEN` and `NEPTUNE_PROJECT`.\n4. Start with `neptune.init_run()`, log parameters and metrics, and call `run.stop()`.\n5. Reach for `with_id=...`, `custom_run_id=...`, or `mode=...` only when the task needs resume, offline execution, or read-only access.\n\n## Official Source URLs\n\n- Main docs landing page: `https://docs.neptune.ai/`\n- Migration note that points `neptune` users to legacy docs: `https://docs.neptune.ai/3.20250901/migration_guide/`\n- Legacy docs root for this package: `https://docs-legacy.neptune.ai/`\n- Legacy quickstart: `https://docs-legacy.neptune.ai/quickstart/`\n- Legacy auth docs: `https://docs-legacy.neptune.ai/setup/neptune-api-token/`\n- Legacy `init_run()` reference: `https://docs-legacy.neptune.ai/api/neptune/#init_run`\n- PyPI project page: `https://pypi.org/project/neptune/`\n- Official repository: `https://github.com/neptune-ai/neptune-client`\n"
  },
  {
    "path": "content/networkx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"NetworkX graph library for Python with practical guidance for graph types, algorithms, I/O, and backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.6.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"networkx,python,graphs,algorithms,graphml,json,backends\"\n---\n\n# NetworkX Python Package Guide\n\n## What It Is\n\n`networkx` is a pure-Python graph library for creating, mutating, analyzing, and serializing graphs. Use it when you need:\n\n- in-memory graph data structures with node and edge attributes\n- built-in graph algorithms such as shortest paths, centrality, connectivity, and traversal\n- interchange with common graph formats such as edge lists, GraphML, GEXF, GML, and JSON\n\nIt does not handle authentication or service credentials because it is a local library, not a network client.\n\n## Install\n\nFor the typical install recommended by the upstream docs:\n\n```bash\npython -m pip install \"networkx[default]==3.6.1\"\n```\n\nThat pulls in common scientific-Python dependencies used by more of the library.\n\nIf you want the minimal pure-Python install:\n\n```bash\npython -m pip install \"networkx==3.6.1\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"networkx[default]==3.6.1\"\n```\n\nOptional extras commonly used with NetworkX:\n\n- `pygraphviz` or `pydot` for Graphviz-based drawing and layouts\n- `lxml` for GraphML support\n\n```bash\npython -m pip install pygraphviz pydot lxml\n```\n\n## Initialize And Choose A Graph Type\n\nImport convention:\n\n```python\nimport networkx as nx\n```\n\nChoose the graph class based on edge directionality and whether parallel edges matter:\n\n- `nx.Graph()`: undirected, self-loops allowed, no parallel edges\n- `nx.DiGraph()`: directed, self-loops allowed, no parallel edges\n- `nx.MultiGraph()`: undirected, self-loops allowed, parallel edges allowed\n- `nx.MultiDiGraph()`: directed, self-loops allowed, parallel edges allowed\n\nStart with `Graph` or `DiGraph` unless you explicitly need multiple edges between the same node pair.\n\n```python\nimport networkx as nx\n\nG = nx.DiGraph(name=\"payments\")\nG.add_node(\"api\", team=\"backend\")\nG.add_edge(\"api\", \"db\", weight=2.5, relationship=\"writes\")\n```\n\nImportant node rules:\n\n- nodes must be hashable Python objects\n- `None` is not allowed as a node\n- do not mutate a node object if its hash depends on mutable contents\n\n## Core Usage\n\n### Build A Graph With Attributes\n\n```python\nimport networkx as nx\n\nG = nx.Graph()\n\nG.add_nodes_from(\n    [\n        (\"sfo\", {\"city\": \"San Francisco\"}),\n        (\"lax\", {\"city\": \"Los Angeles\"}),\n        (\"las\", {\"city\": \"Las Vegas\"}),\n    ]\n)\n\nG.add_weighted_edges_from(\n    [\n        (\"sfo\", \"lax\", 337),\n        (\"lax\", \"las\", 236),\n        (\"sfo\", \"las\", 417),\n    ],\n    weight=\"distance_miles\",\n)\n\nG.nodes[\"sfo\"][\"hub\"] = True\nG.edges[\"sfo\", \"lax\"][\"airline\"] = \"example\"\n```\n\n### Run Algorithms\n\nMost algorithms consume a graph plus attribute names such as `weight`.\n\n```python\nimport networkx as nx\n\nG = nx.DiGraph()\nG.add_weighted_edges_from(\n    [\n        (\"start\", \"a\", 4),\n        (\"start\", \"b\", 1),\n        (\"b\", \"a\", 2),\n        (\"a\", \"finish\", 1),\n        (\"b\", \"finish\", 5),\n    ]\n)\n\npath = nx.shortest_path(G, \"start\", \"finish\", weight=\"weight\")\nlength = nx.shortest_path_length(G, \"start\", \"finish\", weight=\"weight\")\n\nprint(path)    # ['start', 'b', 'a', 'finish']\nprint(length)  # 4\n```\n\nUseful patterns:\n\n- use `G.nodes(data=True)` and `G.edges(data=True)` when attributes matter\n- pass `weight=\"...\"` explicitly for weighted algorithms\n- prefer graph views for temporary filtering, and `.copy()` if you need an isolated graph you can mutate\n\n### Convert From Tabular Data\n\nIf you already have a Pandas edge list:\n\n```python\nimport networkx as nx\nimport pandas as pd\n\ndf = pd.DataFrame(\n    [\n        {\"src\": \"a\", \"dst\": \"b\", \"weight\": 3},\n        {\"src\": \"b\", \"dst\": \"c\", \"weight\": 5},\n    ]\n)\n\nG = nx.from_pandas_edgelist(\n    df,\n    source=\"src\",\n    target=\"dst\",\n    edge_attr=[\"weight\"],\n    create_using=nx.DiGraph,\n)\n```\n\n## Read, Write, And Interoperate\n\nNetworkX supports many formats out of the box, including edge lists, GraphML, GEXF, GML, Pajek, JSON, and Matrix Market.\n\n### JSON For Web And API Interop\n\nUse node-link JSON when you need a JSON-serializable representation:\n\n```python\nimport json\nimport networkx as nx\n\nG = nx.Graph([(\"A\", \"B\")])\n\npayload = nx.node_link_data(G)\nraw_json = json.dumps(payload)\n\nrestored = nx.node_link_graph(json.loads(raw_json))\n```\n\nIn `3.6.1`, the supported keyword names on `node_link_data` are `source=`, `target=`, `name=`, `key=`, `edges=`, and `nodes=`.\n\n### GraphML\n\nUse GraphML when you need a richer graph exchange format:\n\n```python\nimport networkx as nx\n\nG = nx.path_graph(4)\nnx.write_graphml(G, \"graph.graphml\")\n\nloaded = nx.read_graphml(\"graph.graphml\")\n```\n\nNotes that matter in practice:\n\n- `write_graphml()` uses `lxml`\n- `read_graphml()` may return `MultiGraph` or `MultiDiGraph` if the file contains parallel edges\n- GraphML default node and edge attributes are stored in `G.graph` and are not automatically copied onto every node or edge\n\n## Config And Backends\n\nNetworkX itself has no auth or credential setup.\n\nConfiguration that matters most in coding sessions is backend dispatch. NetworkX can route some operations to separately installed backends for better performance or specialized execution while keeping the same Python API.\n\nRelevant controls from the official backend docs:\n\n- per-call backend selection: `backend=\"parallel\"` on supported functions\n- `NETWORKX_BACKEND_PRIORITY`: backend order for dispatchable algorithm calls\n- `NETWORKX_BACKEND_PRIORITY_GENERATORS`: backend order for graph-producing functions\n- `NETWORKX_FALLBACK_TO_NX`: fall back to default NetworkX implementations when a backend graph reaches an unsupported function\n- `NETWORKX_CACHE_CONVERTED_GRAPHS`: whether converted backend graphs are cached\n\nExample:\n\n```bash\nNETWORKX_BACKEND_PRIORITY=cugraph python my_script.py\n```\n\nUse backend configuration only after confirming the backend is installed and supports the functions you call. Conversion and caching can improve speed, but they also add overhead and memory use.\n\n## Common Pitfalls\n\n- `G.add_nodes_from(\"spam\")` adds four nodes: `\"s\"`, `\"p\"`, `\"a\"`, `\"m\"`. Use `G.add_node(\"spam\")` for one string node.\n- Nodes must be hashable, and `None` is reserved by the library for optional arguments.\n- `from_pandas_edgelist()` iterates over `DataFrame.values`; rows with mixed numeric types can be coerced to floats.\n- `read_graphml()` and the GraphML parser should only be used on trusted files because the parser relies on Python's standard XML library.\n- GraphML default attributes live in `G.graph[\"node_default\"]` and `G.graph[\"edge_default\"]`; they are not pushed into every node and edge automatically.\n- `G.nodes`, `G.edges`, `G.adj`, and `G.degree` are live views into the graph. Materialize them with `list(...)` or `dict(...)` if you need snapshot behavior.\n\n## Version-Sensitive Notes For 3.6.1\n\n- NetworkX explicitly says it does not use semantic versioning. Point releases can include minor API breakage, so pin exact versions for tooling-sensitive code instead of relying on `~=`.\n- The `3.6` line replaced `random_lobster` with `random_lobster_graph` and `maybe_regular_expander` with `maybe_regular_expander_graph`.\n- The deprecated `link` keyword in node-link JSON helpers expired in `3.6`; use `edges=` and `nodes=` instead.\n- This guide is for `3.6.1`, which is also the stable documentation version currently published at the upstream docs URL.\n\n## Official Sources Used For This Guide\n\n- Install: `https://networkx.org/documentation/stable/install.html`\n- Tutorial: `https://networkx.org/documentation/stable/tutorial.html`\n- Graph types: `https://networkx.org/documentation/stable/reference/classes/index.html`\n- Backends: `https://networkx.org/documentation/stable/reference/backends.html`\n- Read/write overview: `https://networkx.org/documentation/stable/reference/readwrite/index.html`\n- `read_graphml`: `https://networkx.org/documentation/stable/reference/readwrite/generated/networkx.readwrite.graphml.read_graphml.html`\n- `write_graphml`: `https://networkx.org/documentation/stable/reference/readwrite/generated/networkx.readwrite.graphml.write_graphml.html`\n- `node_link_data`: `https://networkx.org/documentation/stable/reference/readwrite/generated/networkx.readwrite.json_graph.node_link_data.html`\n- `from_pandas_edgelist`: `https://networkx.org/documentation/stable/reference/generated/networkx.convert_matrix.from_pandas_edgelist.html`\n- Releases: `https://networkx.org/documentation/stable/release/index.html`\n- `3.6` release notes: `https://networkx.org/documentation/stable/release/release_3.6.html`\n- PyPI: `https://pypi.org/project/networkx/`\n"
  },
  {
    "path": "content/newrelic/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"New Relic Python agent for APM instrumentation, transaction tracing, error reporting, and logs in context\"\nmetadata:\n  languages: \"python\"\n  versions: \"11.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"newrelic,apm,observability,monitoring,tracing,logging\"\n---\n\n# New Relic Python Agent\n\n## Golden Rule\n\nUse `newrelic` as an early-process instrumentation agent, not as a library you initialize after your app is already imported. Install the agent, configure `license_key` and `app_name`, and start your server or worker through `newrelic-admin run-program` whenever possible. If you must initialize manually, call `newrelic.agent.initialize(...)` before importing framework code so auto-instrumentation can attach correctly.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"newrelic==11.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"newrelic==11.5.0\"\npoetry add \"newrelic==11.5.0\"\n```\n\n## Initial Setup\n\nThe agent needs a New Relic license key and an application name. The standard bootstrap flow is:\n\n1. Generate a starter config file\n2. Review the file and set `app_name`\n3. Start the target process through `newrelic-admin`\n\nGenerate a config file:\n\n```bash\nnewrelic-admin generate-config YOUR_LICENSE_KEY newrelic.ini\n```\n\nMinimal config values to verify:\n\n```ini\n[newrelic]\nlicense_key = YOUR_LICENSE_KEY\napp_name = My Service\nmonitor_mode = true\nlog_level = info\n```\n\nPoint the agent at the config file and wrap the final process command:\n\n```bash\nNEW_RELIC_CONFIG_FILE=newrelic.ini \\\nnewrelic-admin run-program gunicorn myproject.wsgi\n```\n\nThe wrapper approach is the safest default because it initializes the agent before your application imports.\n\n## Manual Initialization\n\nUse manual initialization only when the process manager cannot be wrapped directly.\n\n```python\nimport newrelic.agent\n\nnewrelic.agent.initialize(\"newrelic.ini\")\n\nfrom myapp import create_app\n\napp = create_app()\n```\n\nImportant constraints:\n\n- Initialize before importing Django, Flask, FastAPI, Celery task modules, database clients, or any code you expect the agent to instrument.\n- If you delay initialization until after app creation, middleware, database, and external-call instrumentation can be incomplete.\n\n## Core Usage\n\n### Web apps\n\nFor WSGI or ASGI apps, the common path is to let the agent auto-instrument the framework and libraries, then run the server through the wrapper:\n\n```bash\nNEW_RELIC_CONFIG_FILE=newrelic.ini \\\nnewrelic-admin run-program uvicorn myapp.asgi:app\n```\n\nFor Django:\n\n```bash\nNEW_RELIC_CONFIG_FILE=newrelic.ini \\\nnewrelic-admin run-program gunicorn mysite.wsgi\n```\n\n### Background jobs and standalone work\n\nMark non-web work as a background task so it shows up as its own transaction type:\n\n```python\nimport newrelic.agent\n\nnewrelic.agent.initialize(\"newrelic.ini\")\n\n@newrelic.agent.background_task(name=\"sync_customers\")\ndef sync_customers() -> None:\n    # job logic\n    pass\n```\n\nUse this for scheduled jobs, queue workers, and management commands. The Python agent docs note that background tasks running longer than 20 minutes are not reported, so long-running daemons should split work into shorter units or separate transactions.\n\n### Add custom attributes\n\nAttach business identifiers that help with filtering and debugging:\n\n```python\nimport newrelic.agent\n\ndef handle_order(order_id: str, tenant_id: str) -> None:\n    newrelic.agent.add_custom_attribute(\"order.id\", order_id)\n    newrelic.agent.add_custom_attribute(\"tenant.id\", tenant_id)\n```\n\n### Report handled exceptions\n\nIf your code catches an exception but you still want it recorded in APM, use `notice_error()`:\n\n```python\nimport newrelic.agent\n\ndef process_message(message: dict) -> None:\n    try:\n        run_business_logic(message)\n    except Exception:\n        newrelic.agent.notice_error()\n        raise\n```\n\n## Configuration And Authentication\n\nThe agent authenticates with your New Relic account using the license key in the config file or the environment. Keep the key outside source control.\n\nUseful configuration entry points:\n\n- `newrelic.ini` or `newrelic.toml` as the main agent config\n- `NEW_RELIC_CONFIG_FILE` to choose the config file at process start\n- `app_name` to control the APM entity name\n- `license_key` for ingest authentication\n- `monitor_mode` to enable or disable reporting\n- `log_level` to adjust agent logging during setup and troubleshooting\n\nVersion-sensitive config note:\n\n- `newrelic.toml` is supported only on Python `3.11+` and requires agent `10.3.0+`. If you need older Python runtimes, keep using `.ini`.\n\nServer-side configuration can override local config for settings exposed in the New Relic UI, so verify the effective value in the APM application settings when local changes appear to do nothing.\n\n## Logs In Context\n\nThe Python agent can decorate logs with linking metadata and can forward application logs to New Relic. This is useful when you want logs correlated with traces and transactions.\n\nOperational guidance:\n\n- If your platform already forwards logs through Fluent Bit, Vector, CloudWatch, or another collector, avoid enabling a second forwarding path unless you want duplicates.\n- Use the logs-in-context features for correlation, not as a substitute for normal application logging configuration.\n\n## Common Pitfalls\n\n- Initializing too late is the most common mistake. If the framework or client libraries are imported first, auto-instrumentation may not attach.\n- Wrap the real process entrypoint. Starting a shell script under `newrelic-admin` is only useful if the script eventually `exec`s the target server or worker.\n- Use `background_task()` only for non-web work. Web requests are normally instrumented automatically by the framework integration.\n- Keep the license key out of the repo and deployment manifests when possible; inject it through secrets management or environment configuration.\n- If the app name in APM does not match expectations, check both the local config file and any server-side config overrides in New Relic.\n- If transaction data appears but logs are duplicated, review whether both agent log forwarding and an external log pipeline are enabled.\n\n## Version-Sensitive Notes For 11.5.0\n\n- `11.5.0` adds Hybrid Agent tracing support with OpenTelemetry API compatibility and `TraceIdRatioBased` sampler support. This capability is disabled by default and can be enabled with `otel_enabled = true` or `NEW_RELIC_OTEL_ENABLED=true`.\n- `11.0.0` removed several long-deprecated APIs. Older snippets from blogs or internal wikis may still reference removed calls, so prefer the current Python agent API guide.\n- `11.0.0` also renamed the application logging forwarding setting from `application_logging.forwarding.max_samples_stored` to `application_logging.forwarding.max_samples`.\n- If you need `.toml` config support, that requires `10.3.0+` and Python `3.11+`.\n\n## Official Sources\n\n- Python agent docs root: `https://docs.newrelic.com/docs/apm/agents/python-agent/`\n- Installation and config: `https://docs.newrelic.com/docs/apm/agents/python-agent/installation/python-agent-admin-script-advanced-usage/`\n- API guide: `https://docs.newrelic.com/docs/apm/agents/python-agent/python-agent-api/guide-using-python-agent-api/`\n- Background task API: `https://docs.newrelic.com/docs/apm/agents/python-agent/python-agent-api/backgroundtask-python-agent-api/`\n- Custom attribute API: `https://docs.newrelic.com/docs/apm/agents/python-agent/python-agent-api/addcustomattribute-python-agent-api/`\n- Configuration reference: `https://docs.newrelic.com/docs/apm/agents/python-agent/configuration/python-agent-configuration/`\n- Python agent release notes: `https://docs.newrelic.com/docs/release-notes/agent-release-notes/python-release-notes/4/`\n- PyPI package page: `https://pypi.org/project/newrelic/`\n"
  },
  {
    "path": "content/next/docs/next/javascript/DOC.md",
    "content": "---\nname: next\ndescription: \"Next.js 16 JavaScript guide for App Router apps, including installation, project structure, client components, route handlers, environment variables, images, and production builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"16.1.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"next,nextjs,javascript,react,app-router,ssr\"\n---\n\n# Next.js JavaScript Guide\n\n## Golden Rule\n\nFor new work in `next@16.1.6`, use the App Router:\n\n- put routes under `app/`\n- treat components as Server Components by default\n- add `'use client'` only in files that need browser APIs, state, effects, or event handlers\n- put backend HTTP endpoints in `app/api/**/route.js`\n\nNext.js itself has no API key or client SDK initialization step. Setup is mainly package installation, file conventions, environment variables, and `next.config.*`.\n\n## Install\n\nFor a new JavaScript app, the official starter flow is `create-next-app`:\n\n```bash\nnpx create-next-app@latest my-app --js --app\ncd my-app\nnpm run dev\n```\n\nTo add Next.js to an existing project, install the framework with React:\n\n```bash\nnpm install next@16.1.6 react react-dom\n```\n\nAdd the standard scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\"\n  }\n}\n```\n\n## Minimal App Router Setup\n\nThe smallest useful App Router app needs a root layout and a page.\n\n```text\napp/\n  layout.js\n  page.js\n```\n\n`app/layout.js`:\n\n```js\nexport const metadata = {\n  title: \"My App\",\n  description: \"Next.js app\",\n};\n\nexport default function RootLayout({ children }) {\n  return (\n    <html lang=\"en\">\n      <body>{children}</body>\n    </html>\n  );\n}\n```\n\n`app/page.js`:\n\n```js\nexport default function HomePage() {\n  return <main>Hello from Next.js</main>;\n}\n```\n\nRun the app locally:\n\n```bash\nnpm run dev\n```\n\n## Server Components And Client Components\n\nFiles in `app/` are Server Components by default. Use this for data fetching, server-only code, and secrets.\n\nWhen a component needs interactivity, mark that file with `'use client'`.\n\n`app/components/counter.js`:\n\n```js\n'use client';\n\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [count, setCount] = useState(0);\n\n  return (\n    <button onClick={() => setCount((value) => value + 1)}>\n      Count: {count}\n    </button>\n  );\n}\n```\n\n`app/page.js`:\n\n```js\nimport Counter from './components/counter';\n\nexport default function HomePage() {\n  return (\n    <main>\n      <h1>Dashboard</h1>\n      <Counter />\n    </main>\n  );\n}\n```\n\nUse `'use client'` only where needed. Adding it too high in the tree turns more of your component graph into client-side code than necessary.\n\n## Environment Variables\n\nPut local secrets in `.env.local`.\n\n```dotenv\nDATABASE_URL=postgres://user:pass@localhost:5432/appdb\nINTERNAL_API_KEY=super-secret\nNEXT_PUBLIC_APP_NAME=My App\n```\n\nAccess server-only variables in Server Components, Route Handlers, and other server code:\n\n```js\nexport default function HomePage() {\n  const appName = process.env.NEXT_PUBLIC_APP_NAME;\n  const hasDatabase = Boolean(process.env.DATABASE_URL);\n\n  return (\n    <main>\n      <h1>{appName}</h1>\n      <p>Database configured: {String(hasDatabase)}</p>\n    </main>\n  );\n}\n```\n\nImportant rule:\n\n- only variables prefixed with `NEXT_PUBLIC_` are exposed to browser-side code\n- keep secrets such as database credentials, private tokens, and signing keys unprefixed so they stay server-only\n\n## Route Handlers\n\nUse Route Handlers under `app/api/**/route.js` for JSON endpoints and webhooks.\n\n`app/api/posts/route.js`:\n\n```js\nconst posts = [\n  { id: 1, title: 'Hello' },\n  { id: 2, title: 'World' },\n];\n\nexport async function GET() {\n  return Response.json(posts);\n}\n\nexport async function POST(request) {\n  const body = await request.json();\n\n  const post = {\n    id: posts.length + 1,\n    title: body.title,\n  };\n\n  posts.push(post);\n\n  return Response.json(post, { status: 201 });\n}\n```\n\nExample requests while the dev server is running:\n\n```bash\ncurl http://localhost:3000/api/posts\n\ncurl -X POST http://localhost:3000/api/posts \\\n  -H \"content-type: application/json\" \\\n  -d '{\"title\":\"New post\"}'\n```\n\nFor external APIs that can be cached and revalidated, use Next's fetch options:\n\n```js\nexport default async function BlogPage() {\n  const response = await fetch('https://example.com/api/posts', {\n    next: { revalidate: 60 },\n  });\n\n  const posts = await response.json();\n\n  return <pre>{JSON.stringify(posts, null, 2)}</pre>;\n}\n```\n\n## Metadata\n\nUse the Metadata API instead of manually editing `<head>` inside page components.\n\nStatic metadata in a page or layout:\n\n```js\nexport const metadata = {\n  title: 'Settings',\n  description: 'Account settings page',\n};\n\nexport default function SettingsPage() {\n  return <main>Settings</main>;\n}\n```\n\n## Images\n\nUse `next/image` for optimized images. If you load remote images, allow their hosts in `next.config.mjs`.\n\n`next.config.mjs`:\n\n```js\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  images: {\n    remotePatterns: [\n      {\n        protocol: 'https',\n        hostname: 'images.example.com',\n      },\n    ],\n  },\n};\n\nexport default nextConfig;\n```\n\nComponent usage:\n\n```js\nimport Image from 'next/image';\n\nexport default function Avatar() {\n  return (\n    <Image\n      src=\"https://images.example.com/avatar.png\"\n      alt=\"User avatar\"\n      width={128}\n      height={128}\n    />\n  );\n}\n```\n\nIf you forget to configure the remote host, remote image rendering fails at runtime.\n\n## Production Build And Standalone Output\n\nCreate a production build:\n\n```bash\nnpm run build\nnpm run start\n```\n\nFor container-style deployments, Next supports standalone output:\n\n`next.config.mjs`:\n\n```js\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  output: 'standalone',\n};\n\nexport default nextConfig;\n```\n\nBuild after enabling it:\n\n```bash\nnpm run build\n```\n\n## Common Pitfalls\n\n- Do not add `'use client'` to a page or layout unless the file really needs client-side React features.\n- Do not expose secrets with the `NEXT_PUBLIC_` prefix. That prefix is specifically for values that are safe in browser bundles.\n- Put HTTP handlers in `app/api/**/route.js`, not in arbitrary server files, if you want them to be routable endpoints.\n- Use `next/image` with `images.remotePatterns` for remote hosts instead of raw `<img>` tags when you want Next image optimization.\n- Keep `app/layout.js` present. The App Router requires a root layout.\n\n## Version-Sensitive Notes\n\n- This guide targets `next@16.1.6`.\n- The examples here use the App Router and file conventions from the current official Next.js docs.\n- If you maintain an older Pages Router app under `pages/`, follow that router's conventions consistently instead of mixing patterns across routers.\n\n## Official Sources\n\n- https://nextjs.org/docs/app/getting-started/installation\n- https://nextjs.org/docs/app/getting-started/project-structure\n- https://nextjs.org/docs/app/api-reference/directives/use-client\n- https://nextjs.org/docs/app/guides/environment-variables\n- https://nextjs.org/docs/app/building-your-application/routing/route-handlers\n- https://nextjs.org/docs/app/api-reference/functions/generate-metadata\n- https://nextjs.org/docs/app/api-reference/components/image\n- https://nextjs.org/docs/app/api-reference/config/next-config-js/output\n- https://nextjs.org/docs/app/building-your-application/data-fetching\n- https://www.npmjs.com/package/next\n"
  },
  {
    "path": "content/nicegui/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"NiceGUI package guide for building browser-based and native Python UIs with NiceGUI 3.8.0\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nicegui,python,ui,web,fastapi,desktop\"\n---\n\n# NiceGUI Python Package Guide\n\n## Golden Rule\n\nUse `nicegui` when you want a Python-first UI that runs in the browser or in NiceGUI's native window mode. Pick one app structure per entry point:\n\n- a simple NiceGUI script with UI elements in module scope\n- a single root function passed to `ui.run(...)`\n- explicit `@ui.page(...)` route functions\n\nSince NiceGUI `3.0.0`, those patterns are no longer interchangeable in one file. If you mix script mode with `@ui.page`, routing and reload behavior become the first thing to debug.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"nicegui==3.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"nicegui==3.8.0\"\npoetry add \"nicegui==3.8.0\"\n```\n\nUseful extras from the published package metadata:\n\n```bash\npython -m pip install \"nicegui[native]==3.8.0\"\npython -m pip install \"nicegui[redis]==3.8.0\"\n```\n\nUse `native` when you want a desktop-style window via `pywebview`. Use `redis` only when you actually need Redis-backed persistence or coordination.\n\n## Quick Start\n\nThe upstream package README still shows the core happy path:\n\n```python\nfrom nicegui import ui\n\nui.label('Hello NiceGUI!')\nui.button('BUTTON', on_click=lambda: ui.notify('button was pressed'))\n\nui.run()\n```\n\nRun it:\n\n```bash\npython main.py\n```\n\nBy default NiceGUI serves the app on `http://localhost:8080/` and reloads the page when the source changes.\n\n## Choose An App Structure\n\n### Single-page script\n\nFor a very small app, keep the UI in module scope and finish with `ui.run()`:\n\n```python\nfrom nicegui import ui\n\nui.markdown('## Build a small internal tool')\nui.button('Ping', on_click=lambda: ui.notify('pong'))\n\nui.run(host='0.0.0.0', port=8080)\n```\n\nUse this when the app is effectively one page and you do not need `@ui.page`.\n\n### Root function for a larger single-page app\n\nNiceGUI `3.x` added a `root` page parameter for `ui.run(...)`. This is the cleanest way to keep one routed entry point without relying on global script mode:\n\n```python\nfrom nicegui import ui\n\ndef root() -> None:\n    ui.label('Dashboard')\n    ui.button('Refresh', on_click=lambda: ui.notify('refresh requested'))\n\nui.run(root, host='0.0.0.0', port=8080)\n```\n\nUse this when you want one main page with reusable functions and clearer structure than a module-level script.\n\n### Routed pages\n\nUse `@ui.page` when the app has multiple pages or login/protected routes:\n\n```python\nfrom nicegui import ui\n\n@ui.page('/')\ndef index() -> None:\n    ui.label('Home')\n    ui.link('Settings', '/settings')\n\n@ui.page('/settings')\ndef settings() -> None:\n    ui.label('Settings page')\n\nui.run()\n```\n\nDo not mix this with module-scope script UI in the same file unless you have verified the behavior against current `3.x` docs and examples.\n\n## Attach NiceGUI To FastAPI\n\nNiceGUI is built on FastAPI/Starlette, and the supported integration path is `ui.run_with(app)`:\n\n```python\nfrom fastapi import FastAPI\nfrom nicegui import ui\n\nfastapi_app = FastAPI()\n\n@fastapi_app.get('/healthz')\ndef healthz() -> dict[str, bool]:\n    return {'ok': True}\n\n@ui.page('/')\ndef index() -> None:\n    ui.label('NiceGUI mounted into an existing FastAPI app')\n\nui.run_with(fastapi_app, storage_secret='replace-me')\n```\n\nPractical notes:\n\n- Register plain FastAPI routes before `ui.run_with(...)`.\n- If you depend on session-backed NiceGUI storage, use a real `storage_secret`.\n- If your FastAPI app already has `SessionMiddleware`, keep the session secret aligned with the NiceGUI storage secret. There is an open upstream bug report showing storage persistence breaks when they differ.\n\n## Authentication And Per-user Storage\n\nThe upstream authentication example uses `app.storage.user` plus middleware that redirects unauthenticated requests away from protected pages.\n\nMinimal pattern:\n\n```python\nfrom fastapi import Request\nfrom fastapi.responses import RedirectResponse\nfrom starlette.middleware.base import BaseHTTPMiddleware\n\nfrom nicegui import app, ui\n\nunrestricted_page_routes = {'/login'}\n\n@app.add_middleware\nclass AuthMiddleware(BaseHTTPMiddleware):\n    async def dispatch(self, request: Request, call_next):\n        if not app.storage.user.get('authenticated', False):\n            if not request.url.path.startswith('/_nicegui') and request.url.path not in unrestricted_page_routes:\n                return RedirectResponse(f'/login?redirect_to={request.url.path}')\n        return await call_next(request)\n\n@ui.page('/login')\ndef login(redirect_to: str = '/') -> None:\n    def do_login() -> None:\n        app.storage.user.update({'authenticated': True, 'username': username.value})\n        ui.navigate.to(redirect_to)\n\n    username = ui.input('Username')\n    ui.button('Log in', on_click=do_login)\n\n@ui.page('/')\ndef index() -> None:\n    ui.label(f'Hello {app.storage.user.get(\"username\", \"user\")}')\n\nif __name__ in {'__main__', '__mp_main__'}:\n    ui.run(storage_secret='replace-this-secret')\n```\n\nImportant details agents often miss:\n\n- `app.storage.user` is session-backed per-user storage, so it needs `storage_secret` to persist safely.\n- Exclude `/_nicegui` from auth redirects or the frontend runtime breaks.\n- Replace the demo login with a real auth provider for production. The upstream example explicitly says to use OAuth2/Authlib or another real authentication system instead of plain passwords in code.\n\n## Native Mode\n\nNiceGUI can run in a desktop-style native window instead of only in the browser:\n\n```python\nfrom nicegui import ui\n\nui.label('Desktop window')\nui.run(native=True, reload=False)\n```\n\nUse the `native` extra first:\n\n```bash\npython -m pip install \"nicegui[native]==3.8.0\"\n```\n\nPractical caveats:\n\n- Treat native mode as `pywebview` integration, not as a separate GUI toolkit.\n- Keep `reload=False` in native mode unless you have validated a different setup.\n- Platform-specific `pywebview` renderer issues still show up in upstream issue reports, especially on Windows and Linux desktop environments.\n\n## Deployment And Runtime Notes\n\n- NiceGUI uses WebSockets after the initial page load, so proxy and ingress config must forward WebSocket traffic correctly.\n- The project README describes NiceGUI as a single-worker async setup. Do not assume a multi-worker deployment is safe without validating session, storage, and websocket behavior.\n- For containers or remote development, bind explicitly:\n\n```python\nui.run(host='0.0.0.0', port=8080)\n```\n\n- When you need custom API endpoints, mount files, or extra ASGI behavior, prefer attaching NiceGUI to a FastAPI app instead of fighting the default script entry point.\n\n## Common Pitfalls\n\n- Mixing script mode and `@ui.page` after the `3.0.0` routing changes.\n- Forgetting `storage_secret` and then wondering why `app.storage.user` data disappears after refresh.\n- Protecting all routes with middleware and accidentally redirecting requests under `/_nicegui`.\n- Calling `ui.run_with(app)` before defining the FastAPI routes you still need.\n- Assuming browser examples will work unchanged in native mode.\n- Copying old `2.x` snippets that rely on the old shared auto-index page semantics.\n\n## Version-Sensitive Notes\n\n### `3.8.0`\n\n- `3.8.0` is the current PyPI release as of `2026-03-12`.\n- The `3.8.0` release hardens `run_method()` and `run_*_method()` against XSS by no longer accepting arbitrary JavaScript expressions as method names. If you find older examples that pass a JS lambda string into those helpers, rewrite them to use `run_javascript(...)` instead.\n- The same release added a security best-practices section to the official docs. Prefer that guidance over blog posts for HTML/Markdown sanitization and client-side method execution patterns.\n\n### `3.1.x`\n\n- `3.1.0` added session cookie attribute configuration from `ui.run()`. If you need stricter cookie settings, check the `3.1+` API instead of older examples.\n\n### `3.0.x`\n\n- `3.0.0` introduced NiceGUI script mode and the `root` parameter for `ui.run(...)`.\n- It also removed the old shared auto-index client behavior. Global-scope UI now behaves as a script page that is recreated on each visit.\n- Old snippets that assume global UI state is shared across clients are no longer reliable in `3.x`.\n\n## Official Sources\n\n- Documentation: `https://nicegui.io/documentation`\n- Package registry: `https://pypi.org/project/nicegui/`\n- Repository: `https://github.com/zauberzeug/nicegui`\n- Releases: `https://github.com/zauberzeug/nicegui/releases`\n- Authentication example: `https://github.com/zauberzeug/nicegui/blob/main/examples/authentication/main.py`\n"
  },
  {
    "path": "content/nltk/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"nltk package guide for Python - tokenization, tagging, corpora, downloader setup, and WordNet-based NLP workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.9.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nltk,nlp,tokenization,tagging,wordnet,corpora,text-processing\"\n---\n\n# nltk Python Package Guide\n\n## What It Is\n\n`nltk` is the Natural Language Toolkit: a broad Python NLP toolkit with tokenizers, taggers, parsers, stemmers, corpus readers, WordNet access, and simple training utilities.\n\nUse it when you need classical NLP building blocks or ready-made corpora inside Python code. Do not assume that installing `nltk` also installs the language data files it uses at runtime. Most real workflows need a second setup step with the NLTK downloader.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"nltk==3.9.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"nltk==3.9.3\"\npoetry add \"nltk==3.9.3\"\n```\n\nPyPI also publishes optional extras such as `machine-learning`, `plot`, `tgrep`, `twitter`, `corenlp`, and `all`. If you need the broad optional dependency bundle:\n\n```bash\npython -m pip install \"nltk[all]==3.9.3\"\n```\n\n## Data Setup\n\nInstalling the package is not enough for tokenizers, corpora, taggers, or WordNet. Download the resources your code actually uses.\n\nFor local development, programmatic download is usually enough:\n\n```python\nimport nltk\n\nnltk.download(\"punkt_tab\")\nnltk.download(\"averaged_perceptron_tagger_eng\")\nnltk.download(\"wordnet\")\nnltk.download(\"omw-1.4\")\nnltk.download(\"stopwords\")\n```\n\nFor headless or container setup, prefer the CLI downloader and pin a data directory:\n\n```bash\npython -m nltk.downloader -d ./nltk_data \\\n  punkt_tab averaged_perceptron_tagger_eng wordnet omw-1.4 stopwords\nexport NLTK_DATA=\"$PWD/nltk_data\"\n```\n\nIf you want the standard teaching/demo bundle from the upstream docs:\n\n```python\nimport nltk\n\nnltk.download(\"popular\")\n```\n\n## Configuration And Environment\n\nThere is no auth or API key setup. The main operational config is where NLTK looks for downloaded data.\n\n### Control the data search path\n\n`nltk.data.find(...)` searches `nltk.data.path`. You can inspect or extend it:\n\n```python\nimport nltk\n\nprint(nltk.data.path)\nnltk.data.path.append(\"/app/nltk_data\")\n```\n\nEnvironment-first setup is usually cleaner in CI or Docker:\n\n```bash\nexport NLTK_DATA=/app/nltk_data\n```\n\nProgrammatic downloader with an explicit directory:\n\n```python\nimport nltk\n\nnltk.download(\"wordnet\", download_dir=\"/app/nltk_data\", quiet=True)\nnltk.download(\"omw-1.4\", download_dir=\"/app/nltk_data\", quiet=True)\n```\n\nPractical rule: keep the code environment and the downloaded data volume aligned. A common failure mode is installing the package into a virtualenv while the runtime cannot see the data directory.\n\n## Core Usage\n\n### Tokenize sentences and words\n\n`word_tokenize(...)` and `sent_tokenize(...)` are the standard high-level entry points:\n\n```python\nimport nltk\nfrom nltk.tokenize import sent_tokenize, word_tokenize\n\nnltk.download(\"punkt_tab\", quiet=True)\n\ntext = \"NLTK makes tokenization easy. It also provides corpora and taggers.\"\n\nprint(sent_tokenize(text))\nprint(word_tokenize(text))\n```\n\n### Part-of-speech tag tokens\n\n`pos_tag(...)` expects tokenized input, not a raw string:\n\n```python\nimport nltk\nfrom nltk import pos_tag, word_tokenize\n\nnltk.download(\"punkt_tab\", quiet=True)\nnltk.download(\"averaged_perceptron_tagger_eng\", quiet=True)\n\ntokens = word_tokenize(\"The striped bats are hanging on their feet for best.\")\ntagged = pos_tag(tokens)\n\nprint(tagged)\n```\n\nFor batches, use `pos_tag_sents(...)` instead of calling `pos_tag(...)` in a loop.\n\n### Lemmatize with WordNet\n\n`WordNetLemmatizer.lemmatize(...)` defaults to noun behavior unless you pass a part of speech. For better results, map POS tags before lemmatizing:\n\n```python\nimport nltk\nfrom nltk import pos_tag, word_tokenize\nfrom nltk.corpus import wordnet as wn\nfrom nltk.stem import WordNetLemmatizer\n\nnltk.download(\"punkt_tab\", quiet=True)\nnltk.download(\"averaged_perceptron_tagger_eng\", quiet=True)\nnltk.download(\"wordnet\", quiet=True)\n\nlemmatizer = WordNetLemmatizer()\n\ndef to_wordnet_pos(tag: str) -> str:\n    if tag.startswith(\"J\"):\n        return wn.ADJ\n    if tag.startswith(\"V\"):\n        return wn.VERB\n    if tag.startswith(\"R\"):\n        return wn.ADV\n    return wn.NOUN\n\ntokens = word_tokenize(\"The striped bats are hanging on their feet\")\ntagged = pos_tag(tokens)\nlemmas = [lemmatizer.lemmatize(word, to_wordnet_pos(tag)) for word, tag in tagged]\n\nprint(lemmas)\n```\n\n### Query WordNet\n\nUse `wordnet` when you need synonyms, definitions, or semantic relations:\n\n```python\nimport nltk\nfrom nltk.corpus import wordnet as wn\n\nnltk.download(\"wordnet\", quiet=True)\n\nsynsets = wn.synsets(\"dog\")\nfirst = synsets[0]\n\nprint(first.name())\nprint(first.definition())\nprint(first.lemma_names())\nprint(first.hypernyms())\n```\n\nInstall `omw-1.4` if you need broader multilingual WordNet support.\n\n### Work with corpora and quick frequency counts\n\n```python\nimport nltk\nfrom nltk import FreqDist\nfrom nltk.corpus import stopwords\n\nnltk.download(\"stopwords\", quiet=True)\n\nwords = [\"this\", \"is\", \"a\", \"tiny\", \"tiny\", \"example\"]\nfdist = FreqDist(words)\n\nprint(fdist.most_common(2))\nprint(\"english\" in stopwords.fileids())\n```\n\nFor larger corpora, download exactly the corpus you need rather than using `all`.\n\n## Common Pitfalls\n\n- Installing `nltk` does not install corpora or models. Missing-resource errors are normal until you download the needed data package.\n- In `3.9.x`, Punkt tokenization loads `punkt_tab`, not the older pickled tokenizer resources that many blog posts still reference.\n- `pos_tag(...)` in current source loads language-specific tagger data such as `averaged_perceptron_tagger_eng`. Older instructions that say only `averaged_perceptron_tagger` can be incomplete.\n- `word_tokenize(...)` depends on tokenizer data. If you want zero downloader dependencies, use lower-level tokenizers like `TreebankWordTokenizer`, but their behavior differs.\n- `WordNetLemmatizer.lemmatize(word)` defaults to noun mode. Verbs like `\"running\"` stay unchanged unless you pass `pos=\"v\"` or map POS tags first.\n- `nltk.data.path` and `NLTK_DATA` control where resources are found. Containerized jobs often fail because data was downloaded somewhere outside the runtime search path.\n- The GUI downloader is not a good default for CI, containers, or remote shells. Use `python -m nltk.downloader ...` or `nltk.download(..., quiet=True)`.\n- NLTK is a toolkit, not a single end-to-end modern ML stack. For transformer pipelines, use NLTK where it adds value and pair it with more specialized libraries when needed.\n\n## Version-Sensitive Notes For 3.9.3\n\n- The version used here `3.9.3` matches the current PyPI release.\n- The official docs pages currently exposed at `nltk.org` still show the `3.9.2` docs build, so minor details can lag one patch behind PyPI.\n- The `3.9` line moved away from pickled models for security reasons. That is why current tokenizer and tagger resource names differ from many older tutorials.\n- For `3.9.3`, trust live PyPI metadata and the upstream repository for Python-version support and package metadata when they disagree with older HTML docs pages.\n"
  },
  {
    "path": "content/node-fetch/docs/node-fetch/javascript/DOC.md",
    "content": "---\nname: node-fetch\ndescription: \"Fetch API implementation for Node.js with ESM imports, streaming bodies, multipart uploads, abort support, and Node-specific request options\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"node-fetch,fetch,http-client,http,nodejs\"\n---\n\n# node-fetch (JavaScript)\n\n`node-fetch` brings the Fetch API to Node.js and also exports `Headers`, `Request`, `Response`, `FormData`, `File`, `FetchError`, and `AbortError`.\n\n## Install and import\n\n`node-fetch` `3.x` requires Node.js `>=12.20.0` and is ESM-only.\n\n```bash\nnpm install node-fetch\n```\n\nUse the default export for requests:\n\n```js\nimport fetch from 'node-fetch';\n```\n\nImport the extra classes and helpers when you need them:\n\n```js\nimport fetch, {\n  AbortError,\n  FetchError,\n  FormData,\n  Headers,\n  Request,\n  Response,\n  fileFrom,\n  fileFromSync,\n} from 'node-fetch';\n```\n\nIf your app is still CommonJS, load `node-fetch` with dynamic `import()`:\n\n```js\nconst fetch = (...args) =>\n  import('node-fetch').then(({ default: fetch }) => fetch(...args));\n```\n\nIf older code expects a global `fetch`, you can patch it explicitly:\n\n```js\nimport fetch, { Headers, Request, Response } from 'node-fetch';\n\nif (!globalThis.fetch) {\n  globalThis.fetch = fetch;\n  globalThis.Headers = Headers;\n  globalThis.Request = Request;\n  globalThis.Response = Response;\n}\n```\n\n## Configuration and auth\n\n`node-fetch` does not create a client object and does not manage authentication for you. Store API settings in environment variables and send headers on each request.\n\n```bash\nexport API_BASE_URL=\"https://api.example.com\"\nexport API_TOKEN=\"your-token\"\n```\n\n```js\nfunction apiUrl(path) {\n  return new URL(path, process.env.API_BASE_URL);\n}\n\nfunction authHeaders(extra = {}) {\n  return {\n    Accept: 'application/json',\n    Authorization: `Bearer ${process.env.API_TOKEN}`,\n    ...extra,\n  };\n}\n```\n\nUse absolute URLs. `node-fetch` rejects path-relative and protocol-relative URLs.\n\n## Make a JSON request\n\n`fetch()` resolves for HTTP error statuses too. Check `response.ok` or `response.status` yourself.\n\n```js\nimport fetch from 'node-fetch';\n\nclass HTTPResponseError extends Error {\n  constructor(response, body) {\n    super(`HTTP ${response.status} ${response.statusText}`);\n    this.response = response;\n    this.body = body;\n  }\n}\n\nasync function getUser(userId) {\n  const response = await fetch(apiUrl(`/users/${userId}`), {\n    headers: authHeaders(),\n  });\n\n  if (!response.ok) {\n    throw new HTTPResponseError(response, await response.text());\n  }\n\n  return response.json();\n}\n\nconst user = await getUser('123');\nconsole.log(user.email);\n```\n\n## Send JSON\n\nSerialize the payload yourself and set `Content-Type: application/json`.\n\n```js\nimport fetch from 'node-fetch';\n\nconst response = await fetch(apiUrl('/users'), {\n  method: 'POST',\n  headers: authHeaders({\n    'Content-Type': 'application/json',\n  }),\n  body: JSON.stringify({\n    name: 'Ada Lovelace',\n    role: 'admin',\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(await response.text());\n}\n\nconst createdUser = await response.json();\nconsole.log(createdUser.id);\n```\n\nFor form-style bodies, pass `URLSearchParams` directly. `node-fetch` automatically sets `application/x-www-form-urlencoded` for a `URLSearchParams` body.\n\n```js\nimport fetch from 'node-fetch';\n\nconst params = new URLSearchParams();\nparams.append('grant_type', 'client_credentials');\nparams.append('scope', 'read:users');\n\nconst response = await fetch(apiUrl('/oauth/token'), {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.API_TOKEN}`,\n  },\n  body: params,\n});\n```\n\n## Upload files with multipart form data\n\nUse the built-in `FormData` and `fileFrom()` helpers.\n\n```js\nimport fetch, { FormData, fileFrom } from 'node-fetch';\n\nconst form = new FormData();\nform.set('title', 'Quarterly report');\nform.set('file', await fileFrom('./report.csv', 'text/csv'));\n\nconst response = await fetch(apiUrl('/uploads'), {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.API_TOKEN}`,\n  },\n  body: form,\n});\n\nif (!response.ok) {\n  throw new Error(await response.text());\n}\n```\n\nYou can also create a `File` or `Blob` yourself, or use `fileFromSync()` when synchronous file setup is simpler.\n\n## Stream a response to disk\n\n`response.body` is a Node.js `Readable` stream, not a WHATWG `ReadableStream`. Pipe it with `stream.pipeline()`.\n\n```js\nimport { createWriteStream } from 'node:fs';\nimport { pipeline } from 'node:stream';\nimport { promisify } from 'node:util';\nimport fetch from 'node-fetch';\n\nconst streamPipeline = promisify(pipeline);\n\nconst response = await fetch(apiUrl('/exports/latest.csv'), {\n  headers: authHeaders(),\n});\n\nif (!response.ok) {\n  throw new Error(`Download failed: ${response.status} ${response.statusText}`);\n}\n\nawait streamPipeline(response.body, createWriteStream('./latest.csv'));\n```\n\n## Cancel a request with `AbortController`\n\nPass `signal` in the request options. When the request is aborted, `node-fetch` throws `AbortError`.\n\n```js\nimport fetch, { AbortError } from 'node-fetch';\n\nconst controller = new AbortController();\nconst timeout = setTimeout(() => controller.abort(), 1_500);\n\ntry {\n  const response = await fetch(apiUrl('/reports/slow'), {\n    headers: authHeaders(),\n    signal: controller.signal,\n  });\n\n  if (!response.ok) {\n    throw new Error(await response.text());\n  }\n\n  console.log(await response.json());\n} catch (error) {\n  if (error instanceof AbortError) {\n    console.error('Request timed out');\n  } else {\n    throw error;\n  }\n} finally {\n  clearTimeout(timeout);\n}\n```\n\nOn Node.js `>=14.17.0`, `AbortController` is available globally. On older supported runtimes, add a compatible `AbortController` implementation yourself.\n\n## Node-specific request options\n\n`node-fetch` adds a few options beyond the standard Fetch API:\n\n- `follow`: maximum redirect count, default `20`\n- `compress`: enable gzip/deflate/brotli decoding, default `true`\n- `size`: maximum response body size in bytes, default `0` for no limit\n- `agent`: custom `http.Agent` or `https.Agent`, or a function returning one\n- `highWaterMark`: internal stream buffer size, default `16384`\n- `insecureHTTPParser`: pass through Node's lenient HTTP parser option\n\nExample with keep-alive agents and a response size limit:\n\n```js\nimport http from 'node:http';\nimport https from 'node:https';\nimport fetch from 'node-fetch';\n\nconst httpAgent = new http.Agent({ keepAlive: true });\nconst httpsAgent = new https.Agent({ keepAlive: true });\n\nconst response = await fetch('https://api.example.com/data', {\n  agent(parsedUrl) {\n    return parsedUrl.protocol === 'http:' ? httpAgent : httpsAgent;\n  },\n  follow: 5,\n  size: 10 * 1024 * 1024,\n});\n```\n\nIf you run on Node.js `19+`, the default Node agent already enables keep-alive.\n\n## Cookies and response headers\n\n`node-fetch` does not store cookies automatically. Read `Set-Cookie` headers yourself and send `Cookie` headers explicitly on later requests.\n\n```js\nimport fetch from 'node-fetch';\n\nconst response = await fetch('https://example.com/login');\nconst setCookies = response.headers.raw()['set-cookie'] ?? [];\n\nconsole.log(setCookies);\n```\n\n`Headers.raw()` is a `node-fetch` extension and returns header values as arrays.\n\n## Important behavior and pitfalls\n\n- `3.x` is ESM-only. Use dynamic `import()` from CommonJS, or stay on `node-fetch@2` if the app cannot move off `require()`.\n- `fetch()` only throws for network failures, aborted requests, and operational errors. `4xx` and `5xx` responses still resolve normally.\n- `GET` and `HEAD` requests cannot include a body.\n- URLs with embedded credentials such as `https://user:pass@example.com/` are rejected.\n- `redirect: 'manual'` does not behave like browser fetch. `node-fetch` returns a basic filtered response so you can inspect the `Location` header and follow redirects yourself.\n- When a response is large and you call `response.clone()`, resolve both bodies in parallel or increase `highWaterMark` if needed.\n"
  },
  {
    "path": "content/nodeenv/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"nodeenv Python package guide for creating isolated Node.js environments from Python tooling\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nodeenv,nodejs,npm,python,virtualenv,cli\"\n---\n\n# nodeenv Python Package Guide\n\n## Golden Rule\n\nTreat `nodeenv` as a CLI for creating an isolated Node.js toolchain under a directory or inside an existing Python virtual environment. Pin both the Python package version and the Node.js version you want, prefer the default prebuilt install path unless you specifically need a source build, and use the generated activation script before running `node`, `npm`, or globally installed npm CLIs.\n\n## Install\n\nPin the package version in your Python environment:\n\n```bash\npython -m pip install \"nodeenv==1.10.0\"\n```\n\nCheck that the CLI is available:\n\n```bash\nnodeenv --version\npython -m nodeenv --help\n```\n\nMaintainer docs list these prerequisites:\n\n- for `nodeenv` itself: Python, `make`, and `tail`\n- for building Node.js with SSL support from source: `libssl-dev`\n\nIf you only use the default prebuilt downloads, you usually do not need a full source-build toolchain.\n\n## Create A Standalone Node Environment\n\nCreate an environment in a project-local directory and pin the Node.js version explicitly:\n\n```bash\npython -m nodeenv --node=22.11.0 .nodeenv\nsource .nodeenv/bin/activate\nnode --version\nnpm --version\n```\n\nUseful version selectors from the maintainer docs:\n\n- `--node=latest`: latest stable release\n- `--node=lts`: latest LTS release\n- `--node=system`: use the system-installed `node` instead of downloading one\n\nThe package defaults to `--prebuilt`, which installs Node.js from a prebuilt archive when available.\n\n## Add Node To An Existing Python Virtual Environment\n\nUse `-p` when you already have a Python virtual environment or Conda environment active and want Node.js tools to live inside that same prefix:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install \"nodeenv==1.10.0\"\nnodeenv -p --node=22.11.0\nnode --version\nnpm --version\n```\n\n`nodeenv -p` resolves the target prefix from the active Python environment. In the source, it checks the current virtualenv or Conda prefix and errors if no Python virtual environment is active.\n\n## Install And Reapply npm Packages From A Requirements File\n\n`nodeenv` supports a plain-text requirements file with one npm package per line:\n\n```text\neslint@8.57.1\ntypescript@5.6.3\nprettier@3.6.2\n```\n\nCreate a new environment and install those packages:\n\n```bash\nnodeenv --node=22.11.0 --requirements=requirements.txt .nodeenv\nsource .nodeenv/bin/activate\neslint --version\n```\n\nUpdate packages later without reinstalling Node.js:\n\n```bash\nsource .nodeenv/bin/activate\nnodeenv --requirements=requirements.txt --update .nodeenv\n```\n\nFor modern npm versions, the implementation installs these packages with `npm install -g` inside the environment.\n\n## Capture The Current Global Package Set\n\nAfter activation, `nodeenv` defines a `freeze` shell function that writes installed npm packages in a format you can reuse later:\n\n```bash\nsource .nodeenv/bin/activate\nnpm install -g eslint prettier\nfreeze requirements.txt\n```\n\nUse `freeze -l` to capture only packages local to the current environment:\n\n```bash\nfreeze -l requirements-local.txt\n```\n\n## Activation And Environment Variables\n\nThe generated activation script is the normal entry point for shell usage:\n\n```bash\nsource .nodeenv/bin/activate\necho \"$NODE_VIRTUAL_ENV\"\necho \"$NPM_CONFIG_PREFIX\"\n```\n\nWhen activated, `nodeenv`:\n\n- sets `NODE_VIRTUAL_ENV` to the environment path\n- prepends the environment `bin` directory and `lib/node_modules/.bin` to `PATH`\n- sets `NODE_PATH` to the environment's module directory\n- sets `NPM_CONFIG_PREFIX` and `npm_config_prefix` to the environment prefix\n- defines `deactivate_node` and `freeze` shell functions\n\nTo leave the environment:\n\n```bash\ndeactivate_node\n```\n\nIf you are using `fish`, source `bin/activate.fish` instead of `bin/activate`.\n\n## Run Node Without Activating The Shell\n\nThe maintainer docs include a `shim` script for invoking the environment's Node.js binary directly:\n\n```bash\n./.nodeenv/bin/shim --version\n```\n\nThis is useful in scripts where you do not want to source an activation script first.\n\n## Configuration Files\n\n`nodeenv` can load defaults from config files. By default it looks at:\n\n- `./tox.ini`\n- `./setup.cfg`\n- `~/.nodeenvrc`\n\nThe implementation loads those files in that precedence order, and if a `.node-version` file exists in the current directory, its value becomes the default Node.js version.\n\nExample `~/.nodeenvrc`:\n\n```ini\n[nodeenv]\nnode = 22.11.0\nnpm = latest\nprebuilt = True\njobs = 4\nmirror = https://nodejs.org/download/release\n```\n\nThe keys match the long command-line option names.\n\nUse a specific config file:\n\n```bash\nnodeenv --config-file=/path/to/nodeenv.ini .nodeenv\n```\n\nDisable config-file loading entirely and use only built-in defaults plus CLI flags:\n\n```bash\nnodeenv --config-file= .nodeenv\n```\n\n## Automate From Python\n\n`nodeenv` is documented as a CLI, not as a separate object-oriented Python API. For automation, invoke the module entry point with `subprocess`:\n\n```python\nimport subprocess\n\nsubprocess.run(\n    [\"python\", \"-m\", \"nodeenv\", \"--node=22.11.0\", \".nodeenv\"],\n    check=True,\n)\n```\n\nIf your automation depends on the current Python virtual environment, call `nodeenv -p` from an already activated environment instead of hard-coding paths.\n\n## Common Pitfalls\n\n- `bin/activate` must be sourced, not executed directly.\n- `--update` only reinstalls npm packages from the requirements file; it does not reinstall or change the Node.js runtime.\n- Existing destination directories require `--force` unless you are attaching to the current Python virtual environment with `-p`.\n- `--source` is for source builds and is much slower than the default prebuilt flow.\n- `--node=system` is not supported on Windows; the program exits with an error there.\n- `--ignore_ssl_certs` disables certificate verification for downloads and is explicitly marked unsafe.\n- Config surprises are common when `./tox.ini`, `./setup.cfg`, `~/.nodeenvrc`, or `.node-version` silently override the Node.js version you expected.\n- On `x86_64` musl systems and on `riscv64`, the implementation switches prebuilt downloads to `unofficial-builds.nodejs.org` unless you explicitly set `--mirror`.\n\n## Version-Sensitive Notes For 1.10.0\n\n- The package version covered here is `1.10.0`.\n- PyPI metadata for `1.10.0` declares `Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*`.\n- The maintainer README bundled with `1.10.0` documents `--prebuilt` as the default install mode and `--source` as the explicit alternative.\n- The primary maintainer documentation for this release is the repository README mirrored on GitHub and PyPI rather than a separate docs site.\n\n## Official Sources\n\n- https://github.com/ekalinin/nodeenv\n- https://pypi.org/project/nodeenv/\n"
  },
  {
    "path": "content/notebook/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Jupyter Notebook package guide for Python with install, launch, configuration, security, extensions, and Notebook 7 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.5.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"notebook,jupyter,python,server,ipynb,interactive,development\"\n---\n\n# notebook Python Package Guide\n\n## Golden Rule\n\nTreat `notebook` as a Jupyter application package, not as a normal Python library API. Start it with the `jupyter notebook` CLI, keep server configuration under Jupyter Server settings, and assume older Notebook 6 examples may be wrong for Notebook 7 unless they were updated for Jupyter Server and JupyterLab-based extensions.\n\n## Install\n\nUse a virtual environment unless you intentionally want a global Notebook install:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"notebook==7.5.5\"\n```\n\nThe Jupyter install guide also covers distribution-based installs such as Anaconda if your environment is managed that way.\n\nUseful sanity checks:\n\n```bash\njupyter --version\njupyter notebook --help\npython -m pip show notebook\n```\n\nNotebook installs the IPython kernel for Python. If you need additional languages, install their kernels separately so they appear in the Notebook UI.\n\n## Launch And Open Notebooks\n\nStart the server in the current directory:\n\n```bash\njupyter notebook\n```\n\nOpen a specific notebook file:\n\n```bash\njupyter notebook analysis.ipynb\n```\n\nRun on a fixed port without opening a browser:\n\n```bash\njupyter notebook --no-browser --port 9999\n```\n\nThe dashboard reflects the directory where you launched the command, so start the server in the project root or the notebook workspace you actually want exposed.\n\n## Core Usage\n\n### Create or edit notebooks interactively\n\nNotebook is primarily a browser UI for `.ipynb` documents. Typical workflow:\n\n1. Launch `jupyter notebook`\n2. Open the dashboard in a browser\n3. Create or open a notebook\n4. Select the right kernel\n5. Run cells incrementally and save the `.ipynb`\n\nIf code should run headlessly from the terminal, prefer the Jupyter CLI instead of trying to drive the browser manually:\n\n```bash\njupyter execute analysis.ipynb\n```\n\nThat is the simplest official path for non-interactive notebook execution.\n\n### Use the right kernel\n\nNotebook itself is not the kernel. The kernel controls what runtime executes code cells.\n\n- Python notebooks normally use the bundled IPython kernel\n- Other languages need separately installed kernels\n- If the wrong environment is selected, imports and package resolution will fail even though the notebook server itself is running correctly\n\n### Prefer Jupyter Server APIs for server-side code\n\nNotebook 7 is built on Jupyter Server. If you are writing server extensions, auth helpers, or server-side integrations, use Jupyter Server imports instead of older Notebook 6 import paths.\n\nExamples from the migration guidance:\n\n```python\nfrom jupyter_server.auth import passwd\nfrom jupyter_server import serverapp\n```\n\nDo not assume older imports like `from notebook.auth import passwd` or `from notebook import notebookapp` are the current interfaces for Notebook 7 code.\n\n### Extension model changed in Notebook 7\n\nNotebook 7 uses the same extension system as JupyterLab for front-end customization and Jupyter Server for server extensions.\n\nPractical implication:\n\n- Old classic Notebook front-end extensions often do not work unchanged\n- New extension work should target Notebook 7 / JupyterLab compatibility\n- If a project depends on classic behavior, confirm whether it actually needs `nbclassic` instead of Notebook 7\n\n## Configuration And Authentication\n\n### Generate config\n\nNotebook 7 relies on Jupyter Server configuration. Generate a config file with:\n\n```bash\njupyter server --generate-config\n```\n\nImportant server settings usually live in `jupyter_server_config.py` or `jupyter_server_config.json`.\n\nUseful settings for coding agents and deployment scripts:\n\n- `c.ServerApp.ip`\n- `c.ServerApp.port`\n- `c.ServerApp.open_browser`\n- `c.ServerApp.root_dir`\n- `c.ServerApp.base_url`\n- `c.ServerApp.token`\n- `c.ServerApp.password`\n- `c.ServerApp.certfile`\n- `c.ServerApp.keyfile`\n\nMinimal local-dev example:\n\n```python\nc.ServerApp.ip = \"127.0.0.1\"\nc.ServerApp.port = 8888\nc.ServerApp.open_browser = False\nc.ServerApp.root_dir = \"/path/to/project\"\n```\n\n### Token and password behavior\n\nJupyter Server uses token authentication by default. For local development, the launch output includes a URL with the token.\n\nTo set a password interactively:\n\n```bash\njupyter server password\n```\n\nThat command writes password configuration to `jupyter_server_config.json`. In Jupyter Server, values from the JSON config file take precedence over the Python config file, so check both if a setting appears to be ignored.\n\nOr generate a hashed password in Python:\n\n```python\nfrom jupyter_server.auth import passwd\n\nhashed = passwd(\"replace-me\")\nprint(hashed)\n```\n\nIf a password is set, token auth is no longer the default requirement. For remote access, use HTTPS and a real password or a higher-level deployment solution.\n\n### Remote access and public servers\n\nFor a remote single-user server, you usually need all of:\n\n- `c.ServerApp.ip = \"0.0.0.0\"` or another externally reachable address\n- a password or token strategy you control deliberately\n- TLS via `certfile` and `keyfile` or a trusted reverse proxy\n- a fixed `base_url` when serving behind a subpath proxy\n\nNotebook's public-server guidance is for a single-user server. If multiple users need separate sessions, use JupyterHub instead of exposing one Notebook server to many users.\n\n## Common Pitfalls\n\n- Notebook 7 is not Notebook 6 with a small skin change. It is based on Jupyter Server and JupyterLab components, so old extension and import examples are often stale.\n- Use `ServerApp` settings for new configuration work. Older `NotebookApp` references are common in blog posts and issue threads.\n- Do not import server auth helpers from old `notebook.*` modules in new code. Use `jupyter_server.*` imports instead.\n- The launched server root is the current working directory unless you override `root_dir`. Agents often expose the wrong folder by launching from the wrong directory.\n- A running Notebook server does not guarantee the notebook kernel is correct. Kernel/environment mismatches are a common source of \"package installed but import fails\" confusion.\n- Browser access to a remote Notebook server without TLS and deliberate auth is unsafe.\n- Classic Notebook front-end extensions and `nbextensions` guidance may not apply to Notebook 7. Validate extension compatibility before copying old setup steps.\n- If a workflow explicitly requires the classic interface, install and use `nbclassic` rather than assuming Notebook 7 will behave the same.\n\n## Version-Sensitive Notes For 7.5.5\n\n- PyPI `7.5.5` requires Python `>=3.9`; Python 3.8 is no longer supported in the 7.5 line.\n- The `7.5` series updates Notebook to JupyterLab `4.5`; compatibility claims for front-end extensions should be checked against Notebook 7 / JupyterLab 4, not against Notebook 6-era tutorials.\n- The `7.5.5` changelog entry is a maintenance release that updates Notebook to JupyterLab `4.5.6` and includes dependency and CI maintenance. It is not a major behavioral rewrite, but it is still the patch level to target when the project says `7.5.5`.\n- Upstream docs currently have minor patch-version header drift. When patch versions disagree, use the changelog and PyPI page to resolve the real current version.\n\n## Official Sources\n\n- Notebook docs root: `https://jupyter-notebook.readthedocs.io/en/stable/`\n- Notebook changelog: `https://jupyter-notebook.readthedocs.io/en/stable/changelog.html`\n- Notebook configuration overview: `https://jupyter-notebook.readthedocs.io/en/stable/configuring/config_overview.html`\n- Notebook extension configuration: `https://jupyter-notebook.readthedocs.io/en/stable/configuring/config_extensions.html`\n- Notebook 7 server-extension migration: `https://jupyter-notebook.readthedocs.io/en/stable/migrating/server-extensions.html`\n- Jupyter install docs: `https://docs.jupyter.org/en/latest/install/notebook-classic.html`\n- Jupyter kernel install docs: `https://docs.jupyter.org/en/latest/install/kernel_install.html`\n- Jupyter running docs: `https://docs.jupyter.org/en/latest/running.html`\n- Jupyter Server security docs: `https://jupyter-server.readthedocs.io/en/stable/operators/security.html`\n- Jupyter Server public-server docs: `https://jupyter-server.readthedocs.io/en/stable/operators/public-server.html`\n- PyPI package page: `https://pypi.org/project/notebook/7.5.5/`\n"
  },
  {
    "path": "content/notion/docs/workspace-api/javascript/DOC.md",
    "content": "---\nname: workspace-api\ndescription: \"Notion JavaScript/TypeScript SDK for interacting with Notion workspaces, pages, and databases via the official API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.3.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"notion,api,workspace,pages,databases\"\n---\n\n# Notion API JavaScript/TypeScript SDK Coding Guidelines\n\nYou are a Notion API coding expert. Help me with writing code using the Notion API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.notion.com/reference/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Notion JavaScript SDK to interact with Notion workspaces, which is the standard library for all Notion API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Notion JavaScript SDK\n- **NPM Package:** `@notionhq/client`\n- **Legacy Libraries**: `notion-api-js`, `notion-client`, and other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install @notionhq/client`\n\n**APIs and Usage:**\n\n- **Correct:** `const { Client } = require(\"@notionhq/client\")`\n- **Correct:** `const notion = new Client({ auth: process.env.NOTION_TOKEN })`\n- **Correct:** `await notion.pages.create(...)`\n- **Correct:** `await notion.databases.query(...)`\n- **Correct:** `await notion.dataSources.query(...)`\n- **Incorrect:** `NotionClient` or `NotionAPI`\n- **Incorrect:** Legacy notion-py style APIs\n\n## Installation\n\nInstall the Notion JavaScript SDK using npm:\n\n```bash\nnpm install @notionhq/client\n```\n\nSet your environment variable for the Notion API token:\n\n```bash\nexport NOTION_TOKEN=\"your_integration_token_here\"\n```\n\nYou can obtain an integration token by creating a new integration at:\nhttps://www.notion.com/my-integrations\n\n## Initialization and API Key\n\nThe `@notionhq/client` library requires creating a `Client` instance for all API calls.\n\n- Always use `const notion = new Client({})` to create an instance.\n- Set the `NOTION_TOKEN` environment variable, which will be picked up automatically.\n\n```javascript\nconst { Client } = require('@notionhq/client');\n\n// Uses the NOTION_TOKEN environment variable if auth not specified\nconst notion = new Client({\n  auth: process.env.NOTION_TOKEN,\n});\n```\n\n### Client Configuration Options\n\n```javascript\nconst { Client, LogLevel } = require('@notionhq/client');\n\nconst notion = new Client({\n  auth: process.env.NOTION_TOKEN,\n  logLevel: LogLevel.DEBUG, // Controls logging verbosity (default: LogLevel.WARN)\n  timeoutMs: 60000, // Request timeout in milliseconds (default: 60000)\n  baseUrl: 'https://api.notion.com', // API endpoint (default shown)\n});\n```\n\n## Important API Version Changes (2025-09-03)\n\nAs of API version 2025-09-03, Notion separated databases and data sources:\n\n- **Databases** parent one or more data sources\n- **Data Sources** each parent zero or more pages\n- Use `notion.dataSources.query()` instead of `notion.databases.query()` for newer implementations\n- The SDK minimum version for this API is v5.0.0+\n\n## Pages API\n\n### Create a Page\n\nCreate a new page as a child of an existing page:\n\n```javascript\nconst { Client } = require('@notionhq/client');\nconst notion = new Client({ auth: process.env.NOTION_TOKEN });\n\nasync function createPage() {\n  const response = await notion.pages.create({\n    parent: {\n      page_id: '494c87d072c44cf6960f55f8427f7692',\n    },\n    properties: {\n      title: {\n        type: 'title',\n        title: [\n          {\n            type: 'text',\n            text: { content: 'A note from your pals at Notion' },\n          },\n        ],\n      },\n    },\n  });\n\n  console.log(response);\n}\n\ncreatePage();\n```\n\n### Create a Page in a Data Source (Database)\n\n```javascript\nasync function createPageInDataSource() {\n  const response = await notion.pages.create({\n    parent: {\n      data_source_id: '897e5a76-ae52-4b48-9fdf-e71f5945d1af',\n    },\n    properties: {\n      // Properties must match your data source schema\n      Name: {\n        title: [\n          {\n            text: {\n              content: 'Golden Gate Bridge',\n            },\n          },\n        ],\n      },\n      Tags: {\n        multi_select: [\n          { name: 'Landmark' },\n          { name: 'San Francisco' },\n        ],\n      },\n      Status: {\n        status: {\n          name: 'Active',\n        },\n      },\n    },\n  });\n\n  return response;\n}\n```\n\n### Create a Page with Content Blocks\n\n```javascript\nasync function createPageWithContent() {\n  const response = await notion.pages.create({\n    parent: {\n      page_id: '494c87d072c44cf6960f55f8427f7692',\n    },\n    properties: {\n      title: {\n        title: [{ text: { content: 'My New Page' } }],\n      },\n    },\n    children: [\n      {\n        object: 'block',\n        type: 'heading_2',\n        heading_2: {\n          rich_text: [{ type: 'text', text: { content: 'Introduction' } }],\n        },\n      },\n      {\n        object: 'block',\n        type: 'paragraph',\n        paragraph: {\n          rich_text: [\n            {\n              type: 'text',\n              text: { content: 'This is a paragraph with ' },\n            },\n            {\n              type: 'text',\n              text: { content: 'bold text', link: null },\n              annotations: { bold: true },\n            },\n          ],\n        },\n      },\n      {\n        object: 'block',\n        type: 'bulleted_list_item',\n        bulleted_list_item: {\n          rich_text: [{ type: 'text', text: { content: 'First bullet point' } }],\n        },\n      },\n    ],\n  });\n\n  return response;\n}\n```\n\n### Retrieve a Page\n\n```javascript\nasync function retrievePage(pageId) {\n  const response = await notion.pages.retrieve({\n    page_id: pageId,\n  });\n\n  console.log('Page title:', response.properties.title);\n  console.log('Created at:', response.created_time);\n  console.log('Last edited:', response.last_edited_time);\n\n  return response;\n}\n```\n\n### Update Page Properties\n\n```javascript\nasync function updatePage(pageId) {\n  const response = await notion.pages.update({\n    page_id: pageId,\n    properties: {\n      Status: {\n        status: {\n          name: 'Completed',\n        },\n      },\n      Tags: {\n        multi_select: [\n          { name: 'Updated' },\n          { name: 'Important' },\n        ],\n      },\n    },\n  });\n\n  return response;\n}\n```\n\n### Archive (Trash) a Page\n\n```javascript\nasync function archivePage(pageId) {\n  const response = await notion.pages.update({\n    page_id: pageId,\n    archived: true,\n  });\n\n  return response;\n}\n```\n\n## Databases API\n\n### Query a Database (Legacy - Pre 2025-09-03)\n\n```javascript\nasync function queryDatabase(databaseId) {\n  const response = await notion.databases.query({\n    database_id: databaseId,\n  });\n\n  console.log('Results:', response.results);\n  return response;\n}\n```\n\n### Query with Filters and Sorting\n\n```javascript\nasync function queryDatabaseWithFilters(databaseId) {\n  const response = await notion.databases.query({\n    database_id: databaseId,\n    filter: {\n      and: [\n        {\n          property: 'Status',\n          status: {\n            equals: 'Active',\n          },\n        },\n        {\n          property: 'Priority',\n          select: {\n            equals: 'High',\n          },\n        },\n      ],\n    },\n    sorts: [\n      {\n        property: 'Created',\n        direction: 'descending',\n      },\n    ],\n  });\n\n  return response;\n}\n```\n\n### Query Data Source (API Version 2025-09-03+)\n\n```javascript\nasync function queryDataSource(dataSourceId) {\n  const response = await notion.dataSources.query({\n    data_source_id: dataSourceId,\n    filter: {\n      property: 'Landmark',\n      rich_text: {\n        contains: 'Bridge',\n      },\n    },\n  });\n\n  return response;\n}\n```\n\n### Filter Examples\n\n```javascript\n// Text property contains value\nconst textFilter = {\n  property: 'Description',\n  rich_text: { contains: 'important' },\n};\n\n// Checkbox equals value\nconst checkboxFilter = {\n  property: 'Done',\n  checkbox: { equals: true },\n};\n\n// Date is after specific date\nconst dateFilter = {\n  property: 'Due Date',\n  date: { after: '2025-01-01' },\n};\n\n// Number greater than value\nconst numberFilter = {\n  property: 'Score',\n  number: { greater_than: 50 },\n};\n\n// Multi-select contains value\nconst multiSelectFilter = {\n  property: 'Tags',\n  multi_select: { contains: 'urgent' },\n};\n\n// Compound OR filter\nconst orFilter = {\n  or: [\n    { property: 'Tags', multi_select: { contains: 'A' } },\n    { property: 'Tags', multi_select: { contains: 'B' } },\n  ],\n};\n\n// Compound AND filter\nconst andFilter = {\n  and: [\n    { property: 'Done', checkbox: { equals: false } },\n    { property: 'Priority', select: { equals: 'High' } },\n  ],\n};\n```\n\n### Retrieve a Database\n\n```javascript\nasync function retrieveDatabase(databaseId) {\n  const response = await notion.databases.retrieve({\n    database_id: databaseId,\n  });\n\n  console.log('Database title:', response.title);\n  console.log('Properties:', response.properties);\n\n  return response;\n}\n```\n\n### Create a Database\n\n```javascript\nasync function createDatabase(parentPageId) {\n  const response = await notion.databases.create({\n    parent: {\n      type: 'page_id',\n      page_id: parentPageId,\n    },\n    title: [\n      {\n        type: 'text',\n        text: {\n          content: 'Task List',\n        },\n      },\n    ],\n    properties: {\n      Name: {\n        title: {},\n      },\n      Status: {\n        status: {\n          options: [\n            { name: 'Not started', color: 'red' },\n            { name: 'In progress', color: 'yellow' },\n            { name: 'Completed', color: 'green' },\n          ],\n        },\n      },\n      Priority: {\n        select: {\n          options: [\n            { name: 'High', color: 'red' },\n            { name: 'Medium', color: 'yellow' },\n            { name: 'Low', color: 'gray' },\n          ],\n        },\n      },\n      Tags: {\n        multi_select: {\n          options: [\n            { name: 'Bug', color: 'red' },\n            { name: 'Feature', color: 'blue' },\n          ],\n        },\n      },\n      'Due Date': {\n        date: {},\n      },\n    },\n  });\n\n  return response;\n}\n```\n\n### Update Database Properties\n\n```javascript\nasync function updateDatabase(databaseId) {\n  const response = await notion.databases.update({\n    database_id: databaseId,\n    title: [\n      {\n        text: {\n          content: 'Updated Task List',\n        },\n      },\n    ],\n    properties: {\n      Status: {\n        status: {\n          options: [\n            { name: 'To Do', color: 'red' },\n            { name: 'Doing', color: 'yellow' },\n            { name: 'Done', color: 'green' },\n          ],\n        },\n      },\n    },\n  });\n\n  return response;\n}\n```\n\n## Blocks API\n\n### Retrieve Block Children\n\n```javascript\nasync function getBlockChildren(blockId) {\n  const response = await notion.blocks.children.list({\n    block_id: blockId,\n    page_size: 50,\n  });\n\n  console.log('Number of blocks:', response.results.length);\n  return response.results;\n}\n```\n\n### Append Block Children\n\n```javascript\nasync function appendBlockChildren(blockId) {\n  const response = await notion.blocks.children.append({\n    block_id: blockId,\n    children: [\n      {\n        object: 'block',\n        type: 'heading_2',\n        heading_2: {\n          rich_text: [\n            {\n              type: 'text',\n              text: { content: 'New Section' },\n            },\n          ],\n        },\n      },\n      {\n        object: 'block',\n        type: 'paragraph',\n        paragraph: {\n          rich_text: [\n            {\n              type: 'text',\n              text: { content: 'This is a new paragraph.' },\n            },\n          ],\n        },\n      },\n      {\n        object: 'block',\n        type: 'to_do',\n        to_do: {\n          rich_text: [{ type: 'text', text: { content: 'Complete this task' } }],\n          checked: false,\n        },\n      },\n    ],\n  });\n\n  return response;\n}\n```\n\n### Common Block Types\n\n```javascript\n// Heading blocks\nconst heading1 = {\n  type: 'heading_1',\n  heading_1: {\n    rich_text: [{ text: { content: 'Heading 1' } }],\n  },\n};\n\nconst heading2 = {\n  type: 'heading_2',\n  heading_2: {\n    rich_text: [{ text: { content: 'Heading 2' } }],\n  },\n};\n\nconst heading3 = {\n  type: 'heading_3',\n  heading_3: {\n    rich_text: [{ text: { content: 'Heading 3' } }],\n  },\n};\n\n// Paragraph with formatting\nconst paragraph = {\n  type: 'paragraph',\n  paragraph: {\n    rich_text: [\n      { text: { content: 'Normal text ' } },\n      { text: { content: 'bold' }, annotations: { bold: true } },\n      { text: { content: ' and ' } },\n      { text: { content: 'italic' }, annotations: { italic: true } },\n      { text: { content: ' and ' } },\n      { text: { content: 'code' }, annotations: { code: true } },\n    ],\n  },\n};\n\n// Bulleted list item\nconst bulletedListItem = {\n  type: 'bulleted_list_item',\n  bulleted_list_item: {\n    rich_text: [{ text: { content: 'Bullet point' } }],\n  },\n};\n\n// Numbered list item\nconst numberedListItem = {\n  type: 'numbered_list_item',\n  numbered_list_item: {\n    rich_text: [{ text: { content: 'Numbered item' } }],\n  },\n};\n\n// To-do item\nconst toDo = {\n  type: 'to_do',\n  to_do: {\n    rich_text: [{ text: { content: 'Task to complete' } }],\n    checked: false,\n  },\n};\n\n// Toggle block (collapsible)\nconst toggle = {\n  type: 'toggle',\n  toggle: {\n    rich_text: [{ text: { content: 'Click to expand' } }],\n  },\n};\n\n// Quote\nconst quote = {\n  type: 'quote',\n  quote: {\n    rich_text: [{ text: { content: 'This is a quote' } }],\n  },\n};\n\n// Callout\nconst callout = {\n  type: 'callout',\n  callout: {\n    rich_text: [{ text: { content: 'Important note' } }],\n    icon: { emoji: '💡' },\n  },\n};\n\n// Code block\nconst codeBlock = {\n  type: 'code',\n  code: {\n    rich_text: [{ text: { content: 'const x = 42;' } }],\n    language: 'javascript',\n  },\n};\n\n// Divider\nconst divider = {\n  type: 'divider',\n  divider: {},\n};\n\n// Image\nconst image = {\n  type: 'image',\n  image: {\n    type: 'external',\n    external: {\n      url: 'https://example.com/image.png',\n    },\n  },\n};\n\n// Bookmark\nconst bookmark = {\n  type: 'bookmark',\n  bookmark: {\n    url: 'https://notion.so',\n  },\n};\n```\n\n### Update a Block\n\n```javascript\nasync function updateBlock(blockId) {\n  const response = await notion.blocks.update({\n    block_id: blockId,\n    paragraph: {\n      rich_text: [\n        {\n          text: {\n            content: 'Updated paragraph content',\n          },\n        },\n      ],\n    },\n  });\n\n  return response;\n}\n```\n\n### Delete a Block\n\n```javascript\nasync function deleteBlock(blockId) {\n  const response = await notion.blocks.delete({\n    block_id: blockId,\n  });\n\n  return response;\n}\n```\n\n### Retrieve a Block\n\n```javascript\nasync function retrieveBlock(blockId) {\n  const response = await notion.blocks.retrieve({\n    block_id: blockId,\n  });\n\n  console.log('Block type:', response.type);\n  return response;\n}\n```\n\n## Users API\n\n### List All Users\n\n```javascript\nasync function listUsers() {\n  const response = await notion.users.list({});\n\n  console.log('Users:', response.results);\n  return response.results;\n}\n```\n\n### Retrieve a User\n\n```javascript\nasync function retrieveUser(userId) {\n  const response = await notion.users.retrieve({\n    user_id: userId,\n  });\n\n  console.log('User name:', response.name);\n  console.log('User type:', response.type);\n\n  return response;\n}\n```\n\n### Retrieve Bot User (Your Integration)\n\n```javascript\nasync function retrieveBotUser() {\n  const response = await notion.users.me();\n\n  console.log('Bot name:', response.name);\n  console.log('Bot ID:', response.id);\n\n  return response;\n}\n```\n\n## Search API\n\n### Basic Search\n\n```javascript\nasync function searchPages(query) {\n  const response = await notion.search({\n    query: query,\n    filter: {\n      value: 'page',\n      property: 'object',\n    },\n    sort: {\n      direction: 'descending',\n      timestamp: 'last_edited_time',\n    },\n  });\n\n  return response.results;\n}\n```\n\n### Search for Databases\n\n```javascript\nasync function searchDatabases(query) {\n  const response = await notion.search({\n    query: query,\n    filter: {\n      value: 'database',\n      property: 'object',\n    },\n  });\n\n  return response.results;\n}\n```\n\n### Search All Content\n\n```javascript\nasync function searchAll(query) {\n  const response = await notion.search({\n    query: query,\n    page_size: 100,\n  });\n\n  console.log(`Found ${response.results.length} results`);\n  return response.results;\n}\n```\n\n## Comments API\n\n### Create a Comment\n\n```javascript\nasync function createComment(pageId) {\n  const response = await notion.comments.create({\n    parent: {\n      page_id: pageId,\n    },\n    rich_text: [\n      {\n        text: {\n          content: 'This is a comment on the page.',\n        },\n      },\n    ],\n  });\n\n  return response;\n}\n```\n\n### Create a Discussion Comment (Reply)\n\n```javascript\nasync function createDiscussionComment(discussionId) {\n  const response = await notion.comments.create({\n    discussion_id: discussionId,\n    rich_text: [\n      {\n        text: {\n          content: 'This is a reply to an existing comment.',\n        },\n      },\n    ],\n  });\n\n  return response;\n}\n```\n\n### List Comments\n\n```javascript\nasync function listComments(blockId) {\n  const response = await notion.comments.list({\n    block_id: blockId,\n  });\n\n  console.log('Comments:', response.results);\n  return response.results;\n}\n```\n\n## Pagination\n\n### Manual Pagination\n\n```javascript\nasync function getAllPages(databaseId) {\n  let hasMore = true;\n  let startCursor = undefined;\n  let allResults = [];\n\n  while (hasMore) {\n    const response = await notion.databases.query({\n      database_id: databaseId,\n      start_cursor: startCursor,\n      page_size: 100,\n    });\n\n    allResults = allResults.concat(response.results);\n    hasMore = response.has_more;\n    startCursor = response.next_cursor;\n  }\n\n  console.log(`Retrieved ${allResults.length} total results`);\n  return allResults;\n}\n```\n\n### Using Pagination Helpers\n\n```javascript\nconst { iteratePaginatedAPI, collectPaginatedAPI } = require('@notionhq/client');\n\n// Iterate through paginated results\nasync function iterateBlocks(blockId) {\n  for await (const block of iteratePaginatedAPI(notion.blocks.children.list, {\n    block_id: blockId,\n  })) {\n    console.log('Block type:', block.type);\n  }\n}\n\n// Collect all paginated results at once\nasync function collectAllBlocks(blockId) {\n  const blocks = await collectPaginatedAPI(notion.blocks.children.list, {\n    block_id: blockId,\n  });\n\n  console.log(`Total blocks: ${blocks.length}`);\n  return blocks;\n}\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\nconst { Client, APIErrorCode } = require('@notionhq/client');\n\nconst notion = new Client({ auth: process.env.NOTION_TOKEN });\n\nasync function handleErrors() {\n  try {\n    const response = await notion.pages.retrieve({\n      page_id: 'invalid-id',\n    });\n  } catch (error) {\n    if (error.code === APIErrorCode.ObjectNotFound) {\n      console.error('Page not found');\n    } else if (error.code === APIErrorCode.Unauthorized) {\n      console.error('Invalid API token');\n    } else if (error.code === APIErrorCode.RestrictedResource) {\n      console.error('Access denied - integration not shared with this resource');\n    } else if (error.code === APIErrorCode.RateLimited) {\n      console.error('Rate limit exceeded');\n    } else {\n      console.error('Error:', error.message);\n    }\n  }\n}\n```\n\n### TypeScript Error Handling\n\n```typescript\nimport { Client, isNotionClientError, ClientErrorCode, APIErrorCode } from '@notionhq/client';\n\nconst notion = new Client({ auth: process.env.NOTION_TOKEN });\n\nasync function handleErrorsTypescript() {\n  try {\n    const response = await notion.pages.retrieve({\n      page_id: 'some-id',\n    });\n  } catch (error: unknown) {\n    if (isNotionClientError(error)) {\n      switch (error.code) {\n        case ClientErrorCode.RequestTimeout:\n          console.error('Request timed out');\n          break;\n        case APIErrorCode.ObjectNotFound:\n          console.error('Object not found');\n          break;\n        case APIErrorCode.Unauthorized:\n          console.error('Unauthorized');\n          break;\n        case APIErrorCode.RestrictedResource:\n          console.error('Access denied');\n          break;\n        case APIErrorCode.RateLimited:\n          console.error('Rate limited');\n          break;\n        default:\n          console.error('Unknown error:', error);\n      }\n    }\n  }\n}\n```\n\n### Common Error Codes\n\n| Error Code | Description |\n|------------|-------------|\n| `ObjectNotFound` | The requested resource doesn't exist |\n| `Unauthorized` | Invalid or missing API token |\n| `RestrictedResource` | Integration doesn't have access to the resource |\n| `RateLimited` | Too many requests, retry after delay |\n| `ValidationError` | Invalid request parameters |\n| `ConflictError` | Resource conflict (e.g., duplicate) |\n| `RequestTimeout` | Request took too long |\n\n## Advanced Features\n\n### Custom Request\n\n```javascript\nasync function customRequest() {\n  const response = await notion.request({\n    path: 'comments',\n    method: 'post',\n    body: {\n      parent: { page_id: '5c6a28216bb14a7eb6e1c50111515c3d' },\n      rich_text: [{ text: { content: 'Custom request comment' } }],\n    },\n  });\n\n  return response;\n}\n```\n\n### TypeScript Type Guards\n\n```typescript\nimport { isFullPageOrDataSource, isFullBlock } from '@notionhq/client';\n\nasync function useTypeGuards(dataSourceId: string) {\n  const response = await notion.dataSources.query({\n    data_source_id: dataSourceId,\n  });\n\n  for (const page of response.results) {\n    if (isFullPageOrDataSource(page)) {\n      // Now TypeScript knows page has full properties\n      console.log('Created at:', page.created_time);\n      console.log('Last edited:', page.last_edited_time);\n    }\n  }\n}\n\nasync function checkBlockType(blockId: string) {\n  const block = await notion.blocks.retrieve({ block_id: blockId });\n\n  if (isFullBlock(block)) {\n    console.log('Block type:', block.type);\n  }\n}\n```\n\n### Rich Text Formatting\n\n```javascript\nconst richText = [\n  {\n    type: 'text',\n    text: { content: 'Plain text ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'bold text' },\n    annotations: { bold: true },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'italic text' },\n    annotations: { italic: true },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'strikethrough' },\n    annotations: { strikethrough: true },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'underline' },\n    annotations: { underline: true },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'code' },\n    annotations: { code: true },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'colored text' },\n    annotations: { color: 'red' },\n  },\n  {\n    type: 'text',\n    text: { content: ' ' },\n  },\n  {\n    type: 'text',\n    text: { content: 'link text', link: { url: 'https://notion.so' } },\n  },\n];\n```\n\n### Property Types\n\n```javascript\n// Title property\nconst titleProperty = {\n  title: [\n    {\n      text: { content: 'Page Title' },\n    },\n  ],\n};\n\n// Rich text property\nconst richTextProperty = {\n  rich_text: [\n    {\n      text: { content: 'Some text content' },\n    },\n  ],\n};\n\n// Number property\nconst numberProperty = {\n  number: 42,\n};\n\n// Select property\nconst selectProperty = {\n  select: {\n    name: 'Option 1',\n  },\n};\n\n// Multi-select property\nconst multiSelectProperty = {\n  multi_select: [\n    { name: 'Tag 1' },\n    { name: 'Tag 2' },\n  ],\n};\n\n// Date property\nconst dateProperty = {\n  date: {\n    start: '2025-01-01',\n    end: '2025-01-31',\n  },\n};\n\n// Checkbox property\nconst checkboxProperty = {\n  checkbox: true,\n};\n\n// URL property\nconst urlProperty = {\n  url: 'https://notion.so',\n};\n\n// Email property\nconst emailProperty = {\n  email: 'user@example.com',\n};\n\n// Phone number property\nconst phoneProperty = {\n  phone_number: '+1-555-0100',\n};\n\n// Status property\nconst statusProperty = {\n  status: {\n    name: 'In Progress',\n  },\n};\n\n// People property\nconst peopleProperty = {\n  people: [\n    {\n      object: 'user',\n      id: 'user-id-here',\n    },\n  ],\n};\n\n// Files property\nconst filesProperty = {\n  files: [\n    {\n      name: 'Document.pdf',\n      type: 'external',\n      external: {\n        url: 'https://example.com/document.pdf',\n      },\n    },\n  ],\n};\n\n// Relation property\nconst relationProperty = {\n  relation: [\n    {\n      id: 'related-page-id',\n    },\n  ],\n};\n```\n\n## Complete Example: Task Management System\n\n```javascript\nconst { Client } = require('@notionhq/client');\n\nconst notion = new Client({\n  auth: process.env.NOTION_TOKEN,\n});\n\nasync function createTaskManagementSystem() {\n  // 1. Create a database for tasks\n  const database = await notion.databases.create({\n    parent: {\n      type: 'page_id',\n      page_id: process.env.PARENT_PAGE_ID,\n    },\n    title: [\n      {\n        type: 'text',\n        text: { content: 'Task Manager' },\n      },\n    ],\n    properties: {\n      Name: {\n        title: {},\n      },\n      Status: {\n        status: {\n          options: [\n            { name: 'Not started', color: 'red' },\n            { name: 'In progress', color: 'yellow' },\n            { name: 'Completed', color: 'green' },\n          ],\n        },\n      },\n      Priority: {\n        select: {\n          options: [\n            { name: 'High', color: 'red' },\n            { name: 'Medium', color: 'yellow' },\n            { name: 'Low', color: 'gray' },\n          ],\n        },\n      },\n      'Due Date': {\n        date: {},\n      },\n      Tags: {\n        multi_select: {\n          options: [\n            { name: 'Bug', color: 'red' },\n            { name: 'Feature', color: 'blue' },\n            { name: 'Documentation', color: 'purple' },\n          ],\n        },\n      },\n      Assignee: {\n        people: {},\n      },\n    },\n  });\n\n  console.log('Database created:', database.id);\n\n  // 2. Create a task\n  const task = await notion.pages.create({\n    parent: {\n      database_id: database.id,\n    },\n    properties: {\n      Name: {\n        title: [\n          {\n            text: { content: 'Implement user authentication' },\n          },\n        ],\n      },\n      Status: {\n        status: { name: 'In progress' },\n      },\n      Priority: {\n        select: { name: 'High' },\n      },\n      'Due Date': {\n        date: { start: '2025-02-01' },\n      },\n      Tags: {\n        multi_select: [{ name: 'Feature' }],\n      },\n    },\n  });\n\n  console.log('Task created:', task.id);\n\n  // 3. Add content to the task\n  await notion.blocks.children.append({\n    block_id: task.id,\n    children: [\n      {\n        object: 'block',\n        type: 'heading_2',\n        heading_2: {\n          rich_text: [{ text: { content: 'Task Details' } }],\n        },\n      },\n      {\n        object: 'block',\n        type: 'paragraph',\n        paragraph: {\n          rich_text: [\n            {\n              text: {\n                content: 'Implement OAuth 2.0 authentication for user login.',\n              },\n            },\n          ],\n        },\n      },\n      {\n        object: 'block',\n        type: 'heading_3',\n        heading_3: {\n          rich_text: [{ text: { content: 'Requirements' } }],\n        },\n      },\n      {\n        object: 'block',\n        type: 'to_do',\n        to_do: {\n          rich_text: [{ text: { content: 'Set up OAuth provider' } }],\n          checked: false,\n        },\n      },\n      {\n        object: 'block',\n        type: 'to_do',\n        to_do: {\n          rich_text: [{ text: { content: 'Create login page' } }],\n          checked: false,\n        },\n      },\n      {\n        object: 'block',\n        type: 'to_do',\n        to_do: {\n          rich_text: [{ text: { content: 'Test authentication flow' } }],\n          checked: false,\n        },\n      },\n    ],\n  });\n\n  // 4. Add a comment\n  await notion.comments.create({\n    parent: { page_id: task.id },\n    rich_text: [\n      {\n        text: { content: 'Starting work on this task today.' },\n      },\n    ],\n  });\n\n  // 5. Query all high priority tasks\n  const highPriorityTasks = await notion.databases.query({\n    database_id: database.id,\n    filter: {\n      property: 'Priority',\n      select: {\n        equals: 'High',\n      },\n    },\n    sorts: [\n      {\n        property: 'Due Date',\n        direction: 'ascending',\n      },\n    ],\n  });\n\n  console.log('High priority tasks:', highPriorityTasks.results.length);\n\n  // 6. Update task status\n  await notion.pages.update({\n    page_id: task.id,\n    properties: {\n      Status: {\n        status: { name: 'Completed' },\n      },\n    },\n  });\n\n  console.log('Task marked as completed');\n}\n\n// Run the example\ncreateTaskManagementSystem().catch(console.error);\n```\n\n## Useful Links\n\n- Documentation: https://developers.notion.com/\n- API Reference: https://developers.notion.com/reference/\n- SDK Repository: https://github.com/makenotion/notion-sdk-js\n- NPM Package: https://www.npmjs.com/package/@notionhq/client\n- Create Integration: https://www.notion.com/my-integrations\n- Community: Notion Developers Slack\n"
  },
  {
    "path": "content/notion/docs/workspace-api/python/DOC.md",
    "content": "---\nname: workspace-api\ndescription: \"Notion Python SDK for interacting with Notion workspaces, pages, and databases via the official API.\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"notion,api,workspace,pages,databases\"\n---\n\n# Notion API Python SDK Coding Guidelines\n\nYou are a Notion API coding expert. Help me with writing code using the Notion API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developers.notion.com/reference/\nhttps://ramnes.github.io/notion-sdk-py/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Notion Python SDK to interact with Notion workspaces, which is the standard library for all Notion API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Notion Python SDK\n- **PyPI Package:** `notion-client`\n- **Legacy Libraries**: `notion-py`, `notion`, `notion-sdk`, and other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `pip install notion-client`\n\n**APIs and Usage:**\n\n- **Correct:** `from notion_client import Client`\n- **Correct:** `notion = Client(auth=os.environ[\"NOTION_TOKEN\"])`\n- **Correct:** `notion.pages.create(...)`\n- **Correct:** `notion.databases.query(...)`\n- **Correct:** `notion.data_sources.query(...)`\n- **Incorrect:** `NotionClient` or `NotionAPI` from other packages\n- **Incorrect:** Legacy notion-py APIs\n\n## Installation\n\nInstall the Notion Python SDK using pip:\n\n```bash\npip install notion-client\n```\n\nSet your environment variable for the Notion API token:\n\n```bash\nexport NOTION_TOKEN=\"your_integration_token_here\"\n```\n\nYou can obtain an integration token by creating a new integration at:\nhttps://www.notion.com/my-integrations\n\n## Initialization and API Key\n\nThe `notion-client` library requires creating a `Client` instance for all API calls.\n\n- Always use `notion = Client(auth=token)` to create an instance.\n- Set the `NOTION_TOKEN` environment variable for security.\n\n```python\nimport os\nfrom notion_client import Client\n\n# Uses the NOTION_TOKEN environment variable\nnotion = Client(auth=os.environ[\"NOTION_TOKEN\"])\n```\n\n### Client Configuration Options\n\n```python\nfrom notion_client import Client\n\nnotion = Client(\n    auth=os.environ[\"NOTION_TOKEN\"],\n    log_level=\"DEBUG\",  # Logging verbosity: DEBUG, INFO, WARNING, ERROR\n    timeout_ms=60000,   # Request timeout in milliseconds (default: 60000)\n)\n```\n\n### Async Client\n\nThe SDK supports async/await operations:\n\n```python\nimport os\nfrom notion_client import AsyncClient\n\nasync_notion = AsyncClient(auth=os.environ[\"NOTION_TOKEN\"])\n\n# Use with async/await\nasync def get_users():\n    response = await async_notion.users.list()\n    return response\n```\n\n## Important API Version Changes (2025-09-03)\n\nAs of API version 2025-09-03, Notion separated databases and data sources:\n\n- **Databases** parent one or more data sources\n- **Data Sources** each parent zero or more pages\n- Use `notion.data_sources.query()` instead of `notion.databases.query()` for newer implementations\n\n## Pages API\n\n### Create a Page\n\nCreate a new page as a child of an existing page:\n\n```python\nfrom notion_client import Client\nimport os\n\nnotion = Client(auth=os.environ[\"NOTION_TOKEN\"])\n\ndef create_page():\n    response = notion.pages.create(\n        parent={\n            \"page_id\": \"494c87d072c44cf6960f55f8427f7692\"\n        },\n        properties={\n            \"title\": {\n                \"type\": \"title\",\n                \"title\": [\n                    {\n                        \"type\": \"text\",\n                        \"text\": {\"content\": \"A note from your pals at Notion\"}\n                    }\n                ]\n            }\n        }\n    )\n\n    return response\n\npage = create_page()\nprint(page)\n```\n\n### Create a Page in a Data Source (Database)\n\n```python\ndef create_page_in_data_source():\n    response = notion.pages.create(\n        parent={\n            \"data_source_id\": \"897e5a76-ae52-4b48-9fdf-e71f5945d1af\"\n        },\n        properties={\n            \"Name\": {\n                \"title\": [\n                    {\n                        \"text\": {\n                            \"content\": \"Golden Gate Bridge\"\n                        }\n                    }\n                ]\n            },\n            \"Tags\": {\n                \"multi_select\": [\n                    {\"name\": \"Landmark\"},\n                    {\"name\": \"San Francisco\"}\n                ]\n            },\n            \"Status\": {\n                \"status\": {\n                    \"name\": \"Active\"\n                }\n            }\n        }\n    )\n\n    return response\n```\n\n### Create a Page with Content Blocks\n\n```python\ndef create_page_with_content():\n    response = notion.pages.create(\n        parent={\n            \"page_id\": \"494c87d072c44cf6960f55f8427f7692\"\n        },\n        properties={\n            \"title\": {\n                \"title\": [{\"text\": {\"content\": \"My New Page\"}}]\n            }\n        },\n        children=[\n            {\n                \"object\": \"block\",\n                \"type\": \"heading_2\",\n                \"heading_2\": {\n                    \"rich_text\": [{\"type\": \"text\", \"text\": {\"content\": \"Introduction\"}}]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"paragraph\",\n                \"paragraph\": {\n                    \"rich_text\": [\n                        {\n                            \"type\": \"text\",\n                            \"text\": {\"content\": \"This is a paragraph with \"}\n                        },\n                        {\n                            \"type\": \"text\",\n                            \"text\": {\"content\": \"bold text\"},\n                            \"annotations\": {\"bold\": True}\n                        }\n                    ]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"bulleted_list_item\",\n                \"bulleted_list_item\": {\n                    \"rich_text\": [{\"type\": \"text\", \"text\": {\"content\": \"First bullet point\"}}]\n                }\n            }\n        ]\n    )\n\n    return response\n```\n\n### Retrieve a Page\n\n```python\ndef retrieve_page(page_id):\n    response = notion.pages.retrieve(page_id=page_id)\n\n    print(\"Page title:\", response[\"properties\"][\"title\"])\n    print(\"Created at:\", response[\"created_time\"])\n    print(\"Last edited:\", response[\"last_edited_time\"])\n\n    return response\n```\n\n### Update Page Properties\n\n```python\ndef update_page(page_id):\n    response = notion.pages.update(\n        page_id=page_id,\n        properties={\n            \"Status\": {\n                \"status\": {\n                    \"name\": \"Completed\"\n                }\n            },\n            \"Tags\": {\n                \"multi_select\": [\n                    {\"name\": \"Updated\"},\n                    {\"name\": \"Important\"}\n                ]\n            }\n        }\n    )\n\n    return response\n```\n\n### Archive (Trash) a Page\n\n```python\ndef archive_page(page_id):\n    response = notion.pages.update(\n        page_id=page_id,\n        archived=True\n    )\n\n    return response\n```\n\n## Databases API\n\n### Query a Database\n\n```python\ndef query_database(database_id):\n    response = notion.databases.query(database_id=database_id)\n\n    print(\"Results:\", response[\"results\"])\n    return response\n```\n\n### Query with Filters and Sorting\n\n```python\ndef query_database_with_filters(database_id):\n    response = notion.databases.query(\n        database_id=database_id,\n        filter={\n            \"and\": [\n                {\n                    \"property\": \"Status\",\n                    \"status\": {\n                        \"equals\": \"Active\"\n                    }\n                },\n                {\n                    \"property\": \"Priority\",\n                    \"select\": {\n                        \"equals\": \"High\"\n                    }\n                }\n            ]\n        },\n        sorts=[\n            {\n                \"property\": \"Created\",\n                \"direction\": \"descending\"\n            }\n        ]\n    )\n\n    return response\n```\n\n### Query Data Source (API Version 2025-09-03+)\n\n```python\ndef query_data_source(data_source_id):\n    response = notion.data_sources.query(\n        data_source_id=data_source_id,\n        filter={\n            \"property\": \"Landmark\",\n            \"rich_text\": {\n                \"contains\": \"Bridge\"\n            }\n        }\n    )\n\n    return response\n```\n\n### Filter Examples\n\n```python\n# Text property contains value\ntext_filter = {\n    \"property\": \"Description\",\n    \"rich_text\": {\"contains\": \"important\"}\n}\n\n# Checkbox equals value\ncheckbox_filter = {\n    \"property\": \"Done\",\n    \"checkbox\": {\"equals\": True}\n}\n\n# Date is after specific date\ndate_filter = {\n    \"property\": \"Due Date\",\n    \"date\": {\"after\": \"2025-01-01\"}\n}\n\n# Number greater than value\nnumber_filter = {\n    \"property\": \"Score\",\n    \"number\": {\"greater_than\": 50}\n}\n\n# Multi-select contains value\nmulti_select_filter = {\n    \"property\": \"Tags\",\n    \"multi_select\": {\"contains\": \"urgent\"}\n}\n\n# Compound OR filter\nor_filter = {\n    \"or\": [\n        {\"property\": \"Tags\", \"multi_select\": {\"contains\": \"A\"}},\n        {\"property\": \"Tags\", \"multi_select\": {\"contains\": \"B\"}}\n    ]\n}\n\n# Compound AND filter\nand_filter = {\n    \"and\": [\n        {\"property\": \"Done\", \"checkbox\": {\"equals\": False}},\n        {\"property\": \"Priority\", \"select\": {\"equals\": \"High\"}}\n    ]\n}\n```\n\n### Retrieve a Database\n\n```python\ndef retrieve_database(database_id):\n    response = notion.databases.retrieve(database_id=database_id)\n\n    print(\"Database title:\", response[\"title\"])\n    print(\"Properties:\", response[\"properties\"])\n\n    return response\n```\n\n### Create a Database\n\n```python\ndef create_database(parent_page_id):\n    response = notion.databases.create(\n        parent={\n            \"type\": \"page_id\",\n            \"page_id\": parent_page_id\n        },\n        title=[\n            {\n                \"type\": \"text\",\n                \"text\": {\n                    \"content\": \"Task List\"\n                }\n            }\n        ],\n        properties={\n            \"Name\": {\n                \"title\": {}\n            },\n            \"Status\": {\n                \"status\": {\n                    \"options\": [\n                        {\"name\": \"Not started\", \"color\": \"red\"},\n                        {\"name\": \"In progress\", \"color\": \"yellow\"},\n                        {\"name\": \"Completed\", \"color\": \"green\"}\n                    ]\n                }\n            },\n            \"Priority\": {\n                \"select\": {\n                    \"options\": [\n                        {\"name\": \"High\", \"color\": \"red\"},\n                        {\"name\": \"Medium\", \"color\": \"yellow\"},\n                        {\"name\": \"Low\", \"color\": \"gray\"}\n                    ]\n                }\n            },\n            \"Tags\": {\n                \"multi_select\": {\n                    \"options\": [\n                        {\"name\": \"Bug\", \"color\": \"red\"},\n                        {\"name\": \"Feature\", \"color\": \"blue\"}\n                    ]\n                }\n            },\n            \"Due Date\": {\n                \"date\": {}\n            }\n        }\n    )\n\n    return response\n```\n\n### Update Database Properties\n\n```python\ndef update_database(database_id):\n    response = notion.databases.update(\n        database_id=database_id,\n        title=[\n            {\n                \"text\": {\n                    \"content\": \"Updated Task List\"\n                }\n            }\n        ],\n        properties={\n            \"Status\": {\n                \"status\": {\n                    \"options\": [\n                        {\"name\": \"To Do\", \"color\": \"red\"},\n                        {\"name\": \"Doing\", \"color\": \"yellow\"},\n                        {\"name\": \"Done\", \"color\": \"green\"}\n                    ]\n                }\n            }\n        }\n    )\n\n    return response\n```\n\n## Blocks API\n\n### Retrieve Block Children\n\n```python\ndef get_block_children(block_id):\n    response = notion.blocks.children.list(\n        block_id=block_id,\n        page_size=50\n    )\n\n    print(\"Number of blocks:\", len(response[\"results\"]))\n    return response[\"results\"]\n```\n\n### Append Block Children\n\n```python\ndef append_block_children(block_id):\n    response = notion.blocks.children.append(\n        block_id=block_id,\n        children=[\n            {\n                \"object\": \"block\",\n                \"type\": \"heading_2\",\n                \"heading_2\": {\n                    \"rich_text\": [\n                        {\n                            \"type\": \"text\",\n                            \"text\": {\"content\": \"New Section\"}\n                        }\n                    ]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"paragraph\",\n                \"paragraph\": {\n                    \"rich_text\": [\n                        {\n                            \"type\": \"text\",\n                            \"text\": {\"content\": \"This is a new paragraph.\"}\n                        }\n                    ]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"to_do\",\n                \"to_do\": {\n                    \"rich_text\": [{\"type\": \"text\", \"text\": {\"content\": \"Complete this task\"}}],\n                    \"checked\": False\n                }\n            }\n        ]\n    )\n\n    return response\n```\n\n### Common Block Types\n\n```python\n# Heading blocks\nheading_1 = {\n    \"type\": \"heading_1\",\n    \"heading_1\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Heading 1\"}}]\n    }\n}\n\nheading_2 = {\n    \"type\": \"heading_2\",\n    \"heading_2\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Heading 2\"}}]\n    }\n}\n\nheading_3 = {\n    \"type\": \"heading_3\",\n    \"heading_3\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Heading 3\"}}]\n    }\n}\n\n# Paragraph with formatting\nparagraph = {\n    \"type\": \"paragraph\",\n    \"paragraph\": {\n        \"rich_text\": [\n            {\"text\": {\"content\": \"Normal text \"}},\n            {\"text\": {\"content\": \"bold\"}, \"annotations\": {\"bold\": True}},\n            {\"text\": {\"content\": \" and \"}},\n            {\"text\": {\"content\": \"italic\"}, \"annotations\": {\"italic\": True}},\n            {\"text\": {\"content\": \" and \"}},\n            {\"text\": {\"content\": \"code\"}, \"annotations\": {\"code\": True}}\n        ]\n    }\n}\n\n# Bulleted list item\nbulleted_list_item = {\n    \"type\": \"bulleted_list_item\",\n    \"bulleted_list_item\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Bullet point\"}}]\n    }\n}\n\n# Numbered list item\nnumbered_list_item = {\n    \"type\": \"numbered_list_item\",\n    \"numbered_list_item\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Numbered item\"}}]\n    }\n}\n\n# To-do item\nto_do = {\n    \"type\": \"to_do\",\n    \"to_do\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Task to complete\"}}],\n        \"checked\": False\n    }\n}\n\n# Toggle block (collapsible)\ntoggle = {\n    \"type\": \"toggle\",\n    \"toggle\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Click to expand\"}}]\n    }\n}\n\n# Quote\nquote = {\n    \"type\": \"quote\",\n    \"quote\": {\n        \"rich_text\": [{\"text\": {\"content\": \"This is a quote\"}}]\n    }\n}\n\n# Callout\ncallout = {\n    \"type\": \"callout\",\n    \"callout\": {\n        \"rich_text\": [{\"text\": {\"content\": \"Important note\"}}],\n        \"icon\": {\"emoji\": \"💡\"}\n    }\n}\n\n# Code block\ncode_block = {\n    \"type\": \"code\",\n    \"code\": {\n        \"rich_text\": [{\"text\": {\"content\": \"x = 42\"}}],\n        \"language\": \"python\"\n    }\n}\n\n# Divider\ndivider = {\n    \"type\": \"divider\",\n    \"divider\": {}\n}\n\n# Image\nimage = {\n    \"type\": \"image\",\n    \"image\": {\n        \"type\": \"external\",\n        \"external\": {\n            \"url\": \"https://example.com/image.png\"\n        }\n    }\n}\n\n# Bookmark\nbookmark = {\n    \"type\": \"bookmark\",\n    \"bookmark\": {\n        \"url\": \"https://notion.so\"\n    }\n}\n```\n\n### Update a Block\n\n```python\ndef update_block(block_id):\n    response = notion.blocks.update(\n        block_id=block_id,\n        paragraph={\n            \"rich_text\": [\n                {\n                    \"text\": {\n                        \"content\": \"Updated paragraph content\"\n                    }\n                }\n            ]\n        }\n    )\n\n    return response\n```\n\n### Delete a Block\n\n```python\ndef delete_block(block_id):\n    response = notion.blocks.delete(block_id=block_id)\n    return response\n```\n\n### Retrieve a Block\n\n```python\ndef retrieve_block(block_id):\n    response = notion.blocks.retrieve(block_id=block_id)\n\n    print(\"Block type:\", response[\"type\"])\n    return response\n```\n\n## Users API\n\n### List All Users\n\n```python\ndef list_users():\n    response = notion.users.list()\n\n    print(\"Users:\", response[\"results\"])\n    return response[\"results\"]\n```\n\n### Retrieve a User\n\n```python\ndef retrieve_user(user_id):\n    response = notion.users.retrieve(user_id=user_id)\n\n    print(\"User name:\", response[\"name\"])\n    print(\"User type:\", response[\"type\"])\n\n    return response\n```\n\n### Retrieve Bot User (Your Integration)\n\n```python\ndef retrieve_bot_user():\n    response = notion.users.me()\n\n    print(\"Bot name:\", response[\"name\"])\n    print(\"Bot ID:\", response[\"id\"])\n\n    return response\n```\n\n## Search API\n\n### Basic Search\n\n```python\ndef search_pages(query):\n    response = notion.search(\n        query=query,\n        filter={\n            \"value\": \"page\",\n            \"property\": \"object\"\n        },\n        sort={\n            \"direction\": \"descending\",\n            \"timestamp\": \"last_edited_time\"\n        }\n    )\n\n    return response[\"results\"]\n```\n\n### Search for Databases\n\n```python\ndef search_databases(query):\n    response = notion.search(\n        query=query,\n        filter={\n            \"value\": \"database\",\n            \"property\": \"object\"\n        }\n    )\n\n    return response[\"results\"]\n```\n\n### Search All Content\n\n```python\ndef search_all(query):\n    response = notion.search(\n        query=query,\n        page_size=100\n    )\n\n    print(f\"Found {len(response['results'])} results\")\n    return response[\"results\"]\n```\n\n## Comments API\n\n### Create a Comment\n\n```python\ndef create_comment(page_id):\n    response = notion.comments.create(\n        parent={\n            \"page_id\": page_id\n        },\n        rich_text=[\n            {\n                \"text\": {\n                    \"content\": \"This is a comment on the page.\"\n                }\n            }\n        ]\n    )\n\n    return response\n```\n\n### Create a Discussion Comment (Reply)\n\n```python\ndef create_discussion_comment(discussion_id):\n    response = notion.comments.create(\n        discussion_id=discussion_id,\n        rich_text=[\n            {\n                \"text\": {\n                    \"content\": \"This is a reply to an existing comment.\"\n                }\n            }\n        ]\n    )\n\n    return response\n```\n\n### List Comments\n\n```python\ndef list_comments(block_id):\n    response = notion.comments.list(block_id=block_id)\n\n    print(\"Comments:\", response[\"results\"])\n    return response[\"results\"]\n```\n\n## Pagination\n\n### Manual Pagination\n\n```python\ndef get_all_pages(database_id):\n    has_more = True\n    start_cursor = None\n    all_results = []\n\n    while has_more:\n        response = notion.databases.query(\n            database_id=database_id,\n            start_cursor=start_cursor,\n            page_size=100\n        )\n\n        all_results.extend(response[\"results\"])\n        has_more = response[\"has_more\"]\n        start_cursor = response.get(\"next_cursor\")\n\n    print(f\"Retrieved {len(all_results)} total results\")\n    return all_results\n```\n\n### Using Pagination Helpers\n\n```python\nfrom notion_client import iterate_paginated_api, collect_paginated_api\n\n# Iterate through paginated results\ndef iterate_blocks(block_id):\n    for block in iterate_paginated_api(\n        notion.blocks.children.list,\n        block_id=block_id\n    ):\n        print(\"Block type:\", block[\"type\"])\n\n# Collect all paginated results at once\ndef collect_all_blocks(block_id):\n    blocks = collect_paginated_api(\n        notion.blocks.children.list,\n        block_id=block_id\n    )\n\n    print(f\"Total blocks: {len(blocks)}\")\n    return blocks\n```\n\n### Async Pagination Helpers\n\n```python\nfrom notion_client import AsyncClient, async_iterate_paginated_api, async_collect_paginated_api\n\nasync_notion = AsyncClient(auth=os.environ[\"NOTION_TOKEN\"])\n\n# Async iteration\nasync def async_iterate_blocks(block_id):\n    async for block in async_iterate_paginated_api(\n        async_notion.blocks.children.list,\n        block_id=block_id\n    ):\n        print(\"Block type:\", block[\"type\"])\n\n# Async collection\nasync def async_collect_blocks(block_id):\n    blocks = await async_collect_paginated_api(\n        async_notion.blocks.children.list,\n        block_id=block_id\n    )\n    return blocks\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom notion_client import Client, APIResponseError\n\nnotion = Client(auth=os.environ[\"NOTION_TOKEN\"])\n\ndef handle_errors():\n    try:\n        response = notion.pages.retrieve(page_id=\"invalid-id\")\n    except APIResponseError as error:\n        if error.code == \"object_not_found\":\n            print(\"Page not found\")\n        elif error.code == \"unauthorized\":\n            print(\"Invalid API token\")\n        elif error.code == \"restricted_resource\":\n            print(\"Access denied - integration not shared with this resource\")\n        elif error.code == \"rate_limited\":\n            print(\"Rate limit exceeded\")\n        else:\n            print(f\"Error: {error.message}\")\n```\n\n### Advanced Error Handling\n\n```python\nfrom notion_client import Client, APIResponseError, RequestTimeoutError\n\ndef advanced_error_handling():\n    try:\n        response = notion.pages.retrieve(page_id=\"some-id\")\n    except RequestTimeoutError:\n        print(\"Request timed out\")\n    except APIResponseError as error:\n        print(f\"API Error: {error.code}\")\n        print(f\"Status: {error.status}\")\n        print(f\"Message: {error.message}\")\n\n        # Access full response\n        if hasattr(error, 'response'):\n            print(f\"Full response: {error.response}\")\n    except Exception as error:\n        print(f\"Unexpected error: {error}\")\n```\n\n### Common Error Codes\n\n| Error Code | Description |\n|------------|-------------|\n| `object_not_found` | The requested resource doesn't exist |\n| `unauthorized` | Invalid or missing API token |\n| `restricted_resource` | Integration doesn't have access to the resource |\n| `rate_limited` | Too many requests, retry after delay |\n| `validation_error` | Invalid request parameters |\n| `conflict_error` | Resource conflict (e.g., duplicate) |\n\n## Advanced Features\n\n### Rich Text Formatting\n\n```python\nrich_text = [\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"Plain text \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"bold text\"},\n        \"annotations\": {\"bold\": True}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"italic text\"},\n        \"annotations\": {\"italic\": True}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"strikethrough\"},\n        \"annotations\": {\"strikethrough\": True}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"underline\"},\n        \"annotations\": {\"underline\": True}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"code\"},\n        \"annotations\": {\"code\": True}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"colored text\"},\n        \"annotations\": {\"color\": \"red\"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \" \"}\n    },\n    {\n        \"type\": \"text\",\n        \"text\": {\"content\": \"link text\", \"link\": {\"url\": \"https://notion.so\"}}\n    }\n]\n```\n\n### Property Types\n\n```python\n# Title property\ntitle_property = {\n    \"title\": [\n        {\n            \"text\": {\"content\": \"Page Title\"}\n        }\n    ]\n}\n\n# Rich text property\nrich_text_property = {\n    \"rich_text\": [\n        {\n            \"text\": {\"content\": \"Some text content\"}\n        }\n    ]\n}\n\n# Number property\nnumber_property = {\n    \"number\": 42\n}\n\n# Select property\nselect_property = {\n    \"select\": {\n        \"name\": \"Option 1\"\n    }\n}\n\n# Multi-select property\nmulti_select_property = {\n    \"multi_select\": [\n        {\"name\": \"Tag 1\"},\n        {\"name\": \"Tag 2\"}\n    ]\n}\n\n# Date property\ndate_property = {\n    \"date\": {\n        \"start\": \"2025-01-01\",\n        \"end\": \"2025-01-31\"\n    }\n}\n\n# Checkbox property\ncheckbox_property = {\n    \"checkbox\": True\n}\n\n# URL property\nurl_property = {\n    \"url\": \"https://notion.so\"\n}\n\n# Email property\nemail_property = {\n    \"email\": \"user@example.com\"\n}\n\n# Phone number property\nphone_property = {\n    \"phone_number\": \"+1-555-0100\"\n}\n\n# Status property\nstatus_property = {\n    \"status\": {\n        \"name\": \"In Progress\"\n    }\n}\n\n# People property\npeople_property = {\n    \"people\": [\n        {\n            \"object\": \"user\",\n            \"id\": \"user-id-here\"\n        }\n    ]\n}\n\n# Files property\nfiles_property = {\n    \"files\": [\n        {\n            \"name\": \"Document.pdf\",\n            \"type\": \"external\",\n            \"external\": {\n                \"url\": \"https://example.com/document.pdf\"\n            }\n        }\n    ]\n}\n\n# Relation property\nrelation_property = {\n    \"relation\": [\n        {\n            \"id\": \"related-page-id\"\n        }\n    ]\n}\n```\n\n## Complete Example: Task Management System\n\n```python\nimport os\nfrom notion_client import Client\n\nnotion = Client(auth=os.environ[\"NOTION_TOKEN\"])\n\ndef create_task_management_system():\n    # 1. Create a database for tasks\n    database = notion.databases.create(\n        parent={\n            \"type\": \"page_id\",\n            \"page_id\": os.environ[\"PARENT_PAGE_ID\"]\n        },\n        title=[\n            {\n                \"type\": \"text\",\n                \"text\": {\"content\": \"Task Manager\"}\n            }\n        ],\n        properties={\n            \"Name\": {\n                \"title\": {}\n            },\n            \"Status\": {\n                \"status\": {\n                    \"options\": [\n                        {\"name\": \"Not started\", \"color\": \"red\"},\n                        {\"name\": \"In progress\", \"color\": \"yellow\"},\n                        {\"name\": \"Completed\", \"color\": \"green\"}\n                    ]\n                }\n            },\n            \"Priority\": {\n                \"select\": {\n                    \"options\": [\n                        {\"name\": \"High\", \"color\": \"red\"},\n                        {\"name\": \"Medium\", \"color\": \"yellow\"},\n                        {\"name\": \"Low\", \"color\": \"gray\"}\n                    ]\n                }\n            },\n            \"Due Date\": {\n                \"date\": {}\n            },\n            \"Tags\": {\n                \"multi_select\": {\n                    \"options\": [\n                        {\"name\": \"Bug\", \"color\": \"red\"},\n                        {\"name\": \"Feature\", \"color\": \"blue\"},\n                        {\"name\": \"Documentation\", \"color\": \"purple\"}\n                    ]\n                }\n            },\n            \"Assignee\": {\n                \"people\": {}\n            }\n        }\n    )\n\n    print(f\"Database created: {database['id']}\")\n\n    # 2. Create a task\n    task = notion.pages.create(\n        parent={\n            \"database_id\": database[\"id\"]\n        },\n        properties={\n            \"Name\": {\n                \"title\": [\n                    {\n                        \"text\": {\"content\": \"Implement user authentication\"}\n                    }\n                ]\n            },\n            \"Status\": {\n                \"status\": {\"name\": \"In progress\"}\n            },\n            \"Priority\": {\n                \"select\": {\"name\": \"High\"}\n            },\n            \"Due Date\": {\n                \"date\": {\"start\": \"2025-02-01\"}\n            },\n            \"Tags\": {\n                \"multi_select\": [{\"name\": \"Feature\"}]\n            }\n        }\n    )\n\n    print(f\"Task created: {task['id']}\")\n\n    # 3. Add content to the task\n    notion.blocks.children.append(\n        block_id=task[\"id\"],\n        children=[\n            {\n                \"object\": \"block\",\n                \"type\": \"heading_2\",\n                \"heading_2\": {\n                    \"rich_text\": [{\"text\": {\"content\": \"Task Details\"}}]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"paragraph\",\n                \"paragraph\": {\n                    \"rich_text\": [\n                        {\n                            \"text\": {\n                                \"content\": \"Implement OAuth 2.0 authentication for user login.\"\n                            }\n                        }\n                    ]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"heading_3\",\n                \"heading_3\": {\n                    \"rich_text\": [{\"text\": {\"content\": \"Requirements\"}}]\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"to_do\",\n                \"to_do\": {\n                    \"rich_text\": [{\"text\": {\"content\": \"Set up OAuth provider\"}}],\n                    \"checked\": False\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"to_do\",\n                \"to_do\": {\n                    \"rich_text\": [{\"text\": {\"content\": \"Create login page\"}}],\n                    \"checked\": False\n                }\n            },\n            {\n                \"object\": \"block\",\n                \"type\": \"to_do\",\n                \"to_do\": {\n                    \"rich_text\": [{\"text\": {\"content\": \"Test authentication flow\"}}],\n                    \"checked\": False\n                }\n            }\n        ]\n    )\n\n    # 4. Add a comment\n    notion.comments.create(\n        parent={\"page_id\": task[\"id\"]},\n        rich_text=[\n            {\n                \"text\": {\"content\": \"Starting work on this task today.\"}\n            }\n        ]\n    )\n\n    # 5. Query all high priority tasks\n    high_priority_tasks = notion.databases.query(\n        database_id=database[\"id\"],\n        filter={\n            \"property\": \"Priority\",\n            \"select\": {\n                \"equals\": \"High\"\n            }\n        },\n        sorts=[\n            {\n                \"property\": \"Due Date\",\n                \"direction\": \"ascending\"\n            }\n        ]\n    )\n\n    print(f\"High priority tasks: {len(high_priority_tasks['results'])}\")\n\n    # 6. Update task status\n    notion.pages.update(\n        page_id=task[\"id\"],\n        properties={\n            \"Status\": {\n                \"status\": {\"name\": \"Completed\"}\n            }\n        }\n    )\n\n    print(\"Task marked as completed\")\n\n# Run the example\nif __name__ == \"__main__\":\n    create_task_management_system()\n```\n\n## Async Example\n\n```python\nimport os\nimport asyncio\nfrom notion_client import AsyncClient\n\nasync_notion = AsyncClient(auth=os.environ[\"NOTION_TOKEN\"])\n\nasync def async_example():\n    # List users\n    users = await async_notion.users.list()\n    print(f\"Found {len(users['results'])} users\")\n\n    # Create a page\n    page = await async_notion.pages.create(\n        parent={\"page_id\": \"parent-page-id\"},\n        properties={\n            \"title\": {\n                \"title\": [{\"text\": {\"content\": \"Async Page\"}}]\n            }\n        }\n    )\n\n    # Query a database\n    results = await async_notion.databases.query(\n        database_id=\"database-id\"\n    )\n\n    return results\n\n# Run async code\nif __name__ == \"__main__\":\n    asyncio.run(async_example())\n```\n\n## Useful Links\n\n- Documentation: https://developers.notion.com/\n- API Reference: https://developers.notion.com/reference/\n- SDK Repository: https://github.com/ramnes/notion-sdk-py\n- SDK Documentation: https://ramnes.github.io/notion-sdk-py/\n- PyPI Package: https://pypi.org/project/notion-client/\n- Create Integration: https://www.notion.com/my-integrations\n- Community: Notion Developers Slack\n"
  },
  {
    "path": "content/nox/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Nox package guide for Python task automation across multiple interpreters\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"nox,python,testing,automation,ci,virtualenv\"\n---\n\n# Nox Python Package Guide\n\n## Golden Rule\n\nUse `nox` for Python automation only when the project already expects a Python-defined task runner. Start from a checked-in `noxfile.py`, keep each session explicit, and prefer `session.install(...)` plus `session.run(...)` over shell-heavy wrappers.\n\n## Install\n\nFor a user-level CLI, install with `pipx`:\n\n```bash\npipx install nox\n```\n\nProject or CI install:\n\n```bash\npython -m pip install \"nox==2026.2.9\"\n```\n\nUseful extras:\n\n```bash\npython -m pip install \"nox[uv]==2026.2.9\"\npython -m pip install \"nox[pbs]==2026.2.9\"\n```\n\n- `nox[uv]`: enables the `uv` venv backend if `uv` is available\n- `nox[pbs]`: enables Python downloads from python-build-standalone when `uv` is not the backend\n\n## Initialize A Project\n\nCreate a `noxfile.py` at the repo root:\n\n```python\nimport nox\n\n@nox.session\ndef lint(session):\n    session.install(\"ruff\")\n    session.run(\"ruff\", \"check\", \".\")\n\n@nox.session(python=[\"3.11\", \"3.12\"])\ndef tests(session):\n    session.install(\"-e\", \".[test]\")\n    session.run(\"pytest\", *session.posargs)\n```\n\nBasic commands:\n\n```bash\nnox -l\nnox\nnox -s lint\nnox -s tests-3.12 -- tests/unit/test_cli.py -q\n```\n\nWhat happens:\n\n- `nox -l` lists sessions, including parametrized interpreter variants like `tests-3.11`\n- `nox` runs all default sessions in file order\n- `-s` or `--session` targets one or more sessions\n- arguments after `--` become `session.posargs`\n\n## Core Usage\n\n### Session model\n\nEach `@nox.session` function receives a `session` object. The core workflow is:\n\n1. install tools or your package into the session environment\n2. run commands inside that environment\n3. optionally branch on interpreter, tags, or passed arguments\n\n```python\nimport nox\n\n@nox.session\ndef tests(session):\n    session.install(\"-e\", \".[test]\")\n    session.run(\"pytest\", *session.posargs)\n```\n\n### Multiple Python versions\n\n```python\nimport nox\n\n@nox.session(python=[\"3.10\", \"3.11\", \"3.12\"])\ndef tests(session):\n    session.install(\"-e\", \".[test]\")\n    session.run(\"pytest\")\n```\n\nNox creates a separate session for each interpreter, such as `tests-3.10` and `tests-3.12`.\n\n### Parametrized sessions\n\nUse `@nox.parametrize` when the matrix is not just Python versions:\n\n```python\nimport nox\n\n@nox.session\n@nox.parametrize(\"dependency\", [\"pydantic<2\", \"pydantic>=2\"])\ndef tests(session, dependency):\n    session.install(\"-e\", \".\", dependency, \"pytest\")\n    session.run(\"pytest\")\n```\n\n### Reusing environments locally\n\nNox recreates environments by default. For faster local iteration:\n\n```bash\nnox --reuse-venv=yes -s tests-3.12\nnox --reuse-venv=yes --no-install -s tests-3.12\n```\n\n`--reuse-existing-virtualenvs` still works, but current docs prefer `--reuse-venv=yes|no|always|never`.\n\n### Selecting and filtering sessions\n\nUseful CLI patterns:\n\n```bash\nnox --session lint --session tests-3.12\nnox --tags quick\nnox --keywords \"tests and not slow\"\nnox --force-python 3.12 -s lint\n```\n\n- `--tags` and `--keywords` are useful once a `noxfile.py` grows into a larger matrix\n\n## `pyproject.toml` Integration\n\n`nox.project` helpers are useful when the project already defines dependency groups or supported Python versions in `pyproject.toml`.\n\n```python\nimport nox\n\nPYPROJECT = nox.project.load_toml(\"pyproject.toml\")\n\n@nox.session\ndef tests(session):\n    session.install(*nox.project.dependency_groups(PYPROJECT, \"test\"))\n    session.run(\"pytest\")\n```\n\nYou can also derive session Python versions from project metadata:\n\n```python\nimport nox\n\nPYPROJECT = nox.project.load_toml(\"pyproject.toml\")\nPYTHON_VERSIONS = nox.project.python_versions(PYPROJECT)\n\n@nox.session(python=PYTHON_VERSIONS)\ndef tests(session):\n    session.install(\"-e\", \".[test]\")\n    session.run(\"pytest\")\n```\n\nThis reduces drift between packaging metadata and CI task definitions.\n\n## Environment And Configuration\n\nThere is no built-in auth model. `nox` just runs local commands, so any credentials come from your normal environment, `.env` loading, CI secrets, or the tools invoked inside a session.\n\nCommon Noxfile-level options:\n\n```python\nimport nox\n\nnox.options.sessions = [\"lint\", \"tests\"]\nnox.options.default_venv_backend = \"uv|virtualenv\"\nnox.options.reuse_venv = \"yes\"\nnox.options.error_on_missing_interpreters = True\nnox.options.error_on_external_run = True\n```\n\nNotes:\n\n- command-line flags override `nox.options.*`\n- `default_venv_backend` can use fallbacks such as `uv|virtualenv`\n- `error_on_missing_interpreters` is useful in CI so missing Python versions fail loudly\n- `error_on_external_run` tightens execution and forces explicit `external=True` for tools outside the session env\n\nIf you need to pass or block environment variables per command:\n\n```python\n@nox.session\ndef integration(session):\n    session.install(\"-e\", \".[test]\")\n    session.run(\"pytest\", env={\"API_TOKEN\": session.env[\"API_TOKEN\"]})\n```\n\nUse explicit `env={...}` when a session depends on secrets or environment-sensitive behavior.\n\n## CI And Interpreter Management\n\nBy default, Nox can download interpreters when a requested Python is missing:\n\n```bash\nnox --download-python auto\nnox --download-python never\nnox --download-python always\n```\n\nCurrent behavior to remember:\n\n- `auto` is the documented default\n- on CI, missing interpreters are treated as errors by default when `CI` is set\n- if you are not using the `uv` backend, Python downloads require the `pbs` extra\n\n## Common Pitfalls\n\n### Running tools outside the session environment\n\nIf a command is not installed in the session, Nox may warn and still run the external program unless you enable `--error-on-external-run`. This can hide undeclared dependencies.\n\nPrefer:\n\n```python\nsession.install(\"pytest\")\nsession.run(\"pytest\")\n```\n\ninstead of assuming `pytest` already exists on the host machine.\n\n### Reused envs with stale dependencies\n\n`--reuse-venv=yes --no-install` is fast but only safe when dependencies did not change. If a lockfile, extras, or editable install changed, rerun without `--no-install`.\n\n### Missing interpreters silently skipping locally\n\nOutside CI, missing interpreters may skip sessions unless you opt into:\n\n```bash\nnox --error-on-missing-interpreters\n```\n\nThis matters for multi-Python matrices where a skipped interpreter would otherwise look like success.\n\n### `uv` backend surprises\n\nThe `uv` backend is fast, but it does not install `pip` by default. If a session or debug workflow expects `pip`, install it explicitly:\n\n```python\nsession.install(\"pip\")\n```\n\n### Overusing shell wrappers\n\nKeep `noxfile.py` readable Python. If a session mostly shells out to a long bash script, agents lose the benefit of clear dependency installation, argument passing, and interpreter control.\n\n## Version-Sensitive Notes For `2026.2.9`\n\n- PyPI and the stable docs both currently resolve to `2026.2.9`.\n- The stable docs root is `nox.thea.codes`; PyPI metadata also points there, while some older project text still references `nox.readthedocs.io`.\n- Current docs prefer `--reuse-venv=...` and `nox.options.reuse_venv` over the older `reuse_existing_virtualenvs` naming.\n- Current docs treat `--download-python auto` as the default, with `uv` or `pbs` determining how interpreter downloads happen.\n- The 2026.2.9 changelog notes support for `uv 0.10`.\n\n## Official Sources\n\n- Stable docs: `https://nox.thea.codes/en/stable/`\n- Configuration and API: `https://nox.thea.codes/en/stable/config.html`\n- Command-line usage: `https://nox.thea.codes/en/stable/usage.html`\n- Changelog: `https://nox.thea.codes/en/latest/CHANGELOG.html`\n- PyPI: `https://pypi.org/project/nox/`\n"
  },
  {
    "path": "content/numba/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Numba package guide for Python JIT compilation of NumPy-heavy CPU kernels, parallel loops, and CUDA-aware setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.64.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"numba,jit,numpy,performance,parallel,cuda,llvm\"\n---\n\n# Numba Python Package Guide\n\n## Golden Rule\n\nUse `@njit` on NumPy-heavy, type-stable functions and loops, not on general Python application code. Warm up and benchmark after compilation, keep inputs as NumPy arrays or other homogeneous types, and treat CUDA as a separate dependency path by installing `numba-cuda` when GPU support matters.\n\n## Install\n\nFor the package version used here:\n\n```bash\npython -m pip install \"numba==0.64.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"numba==0.64.0\"\npoetry add \"numba==0.64.0\"\n```\n\nNotes:\n\n- `pip install numba` also installs the required `llvmlite` wheel; you do not need a system LLVM install for standard wheel-based usage.\n- The official version-support table for `0.64.0` lists `llvmlite 0.46.x`, LLVM `20.x`, and NumPy `1.22 <= version < 1.27` or `2.0 <= version < 2.5`.\n- For CUDA work, install the CUDA toolkit as required by your platform and add `numba-cuda` explicitly:\n\n```bash\npython -m pip install \"numba==0.64.0\" \"numba-cuda\"\n```\n\n## Check The Environment\n\nConfirm the package imports and the version is what you expect:\n\n```bash\npython - <<'PY'\nimport numba\nprint(numba.__version__)\nPY\n```\n\nFor runtime diagnostics, threading-layer availability, CPU features, and CUDA detection:\n\n```bash\nnumba -s\n```\n\n`numba -s` is the fastest official way to debug \"why is this machine behaving differently?\" issues before rewriting code.\n\n## Core Usage\n\n### Start with `@njit`\n\nPrefer `@njit` over `@jit` when you want predictable performance. `@njit` enforces nopython compilation and fails loudly instead of silently leaving work in slow Python-object paths.\n\n```python\nimport numpy as np\nfrom numba import njit\n\n@njit(cache=True)\ndef sum_of_squares(values):\n    total = 0.0\n    for value in values:\n        total += value * value\n    return total\n\narr = np.arange(1_000_000, dtype=np.float64)\nprint(sum_of_squares(arr))\n```\n\nImportant behavior:\n\n- The first call compiles the function for the observed argument types.\n- Later calls with the same signature reuse the compiled version.\n- `cache=True` persists compiled artifacts on disk so repeated runs start faster.\n\n### Loops Are Fine\n\nNumba is designed for numerical loops. You do not need to contort code into vectorized NumPy form just to make it fast under Numba.\n\n```python\nimport numpy as np\nfrom numba import njit\n\n@njit(cache=True)\ndef l2_norms(x, y):\n    out = np.empty(x.shape[0], dtype=np.float64)\n    for i in range(x.shape[0]):\n        out[i] = (x[i] * x[i] + y[i] * y[i]) ** 0.5\n    return out\n```\n\nKeep array dtypes explicit and stable. Mixed Python objects, changing container element types, and shape-dependent Python branching make compilation less reliable.\n\n### Parallel CPU Loops With `prange`\n\nUse `parallel=True` together with `prange` for embarrassingly parallel loops or supported reductions:\n\n```python\nimport numpy as np\nfrom numba import njit, prange\n\n@njit(parallel=True, cache=True)\ndef column_sums(matrix):\n    out = np.zeros(matrix.shape[1], dtype=np.float64)\n    for j in prange(matrix.shape[1]):\n        total = 0.0\n        for i in range(matrix.shape[0]):\n            total += matrix[i, j]\n        out[j] = total\n    return out\n```\n\nOfficial parallel docs call out two constraints that matter in practice:\n\n- `prange` only runs in parallel when the loop has no unsafe cross-iteration dependencies.\n- Mutating shared containers like Python lists, sets, or dicts inside a `prange` region is not thread-safe.\n\n### Build Ufuncs With `@vectorize`\n\nWhen the natural API is elementwise array math, `@vectorize` can expose a NumPy-style ufunc:\n\n```python\nfrom numba import vectorize\n\n@vectorize([\"float64(float64, float64)\"], nopython=True, cache=True)\ndef clipped_add(x, y):\n    value = x + y\n    return 1.0 if value > 1.0 else value\n```\n\nThis is useful when you want a callable that behaves like a NumPy ufunc instead of a plain function compiled by `@njit`.\n\n## Configuration And Runtime Controls\n\nNumba has no auth or remote-service setup. Configuration is local process configuration.\n\nUseful controls from the official environment-variable reference:\n\n- `NUMBA_DISABLE_JIT=1`: disable JIT entirely so decorated functions execute as plain Python, useful for stepping through logic in a debugger.\n- `NUMBA_NUM_THREADS=8`: cap the CPU thread pool used by `@njit(parallel=True)` and parallel CPU ufunc targets.\n- `NUMBA_THREADING_LAYER=safe`: prefer a thread-safe and fork-safe threading backend when mixing Numba parallelism with multiprocessing.\n- `NUMBA_CPU_NAME=generic`: emit more portable cached machine code within the same OS and CPU architecture.\n\nYou can persist settings in a `.numba_config.yaml` file in the working directory if `pyyaml` is installed:\n\n```yaml\ndeveloper_mode: 1\ncolor_scheme: dark_bg\n```\n\nEnvironment variables override the config file.\n\n## Common Pitfalls\n\n- First-call latency is compilation time, not steady-state runtime. Do not benchmark a jitted function from its very first call.\n- Prefer `@njit` to force nopython mode. If compilation fails, fix the unsupported code path instead of dropping back to slow object-heavy code.\n- Numba is not a general accelerator for Pandas, arbitrary Python classes, or string-heavy business logic. Focus on numerical kernels.\n- Keep types homogeneous. Lists with mixed element types, dicts with unstable key or value types, and implicit dtype changes often cause typing errors.\n- `parallel=True` is not a magic speed flag. Some loops will not parallelize, and unsafe writes can introduce wrong answers rather than exceptions.\n- `fastmath=True` can change floating-point semantics. Use it only when reassociation and relaxed IEEE behavior are acceptable.\n- `numba.typed.List` and `numba.typed.Dict` remain the explicit path when you need compiled containers, but the docs still label them experimental. Prefer NumPy arrays unless you truly need dynamic containers.\n- Cached machine code is still specialization-sensitive. A different signature or incompatible CPU target will trigger recompilation.\n\n## Version-Sensitive Notes For 0.64.0\n\n- The official support table for `0.64.0` lists Python `3.10.x <= version < 3.15`.\n- `0.64.0` adds support for NumPy `2.4`. If you are modernizing code for NumPy 2.4, replace removed APIs such as `np.trapz` with `np.trapezoid` and `np.in1d` with `np.isin`.\n- The built-in CUDA target is deprecated. Official deprecation guidance says CUDA development has moved to the separate `numba-cuda` package, and CUDA users should install `numba-cuda`.\n- Intel macOS x86_64 is no longer officially supported starting with `0.63.0+`. The deprecation notice recommends pinning `numba<0.63` if you need the last officially supported Intel Mac release line.\n- `0.64.0` includes a cache-related fix for functions that call `parallel=True` functions. If you saw stale or incorrect cache behavior in older releases around nested parallel calls, re-test on `0.64.0`.\n\n## Official Source URLs\n\n- Docs root: `https://numba.readthedocs.io/en/stable/`\n- Installation and version support: `https://numba.readthedocs.io/en/stable/user/installing.html`\n- Quickstart: `https://numba.readthedocs.io/en/stable/user/5minguide.html`\n- Parallel CPU docs: `https://numba.readthedocs.io/en/stable/user/parallel.html`\n- Environment variables: `https://numba.readthedocs.io/en/stable/reference/envvars.html`\n- Deprecations: `https://numba.readthedocs.io/en/stable/reference/deprecation.html`\n- Release notes for `0.64.0`: `https://numba.readthedocs.io/en/stable/release/0.64.0-notes.html`\n- PyPI: `https://pypi.org/project/numba/`\n"
  },
  {
    "path": "content/numpy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"NumPy package guide for Python array computing, broadcasting, typing, random generation, and NumPy 2.x migration\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"numpy,python,array,ndarray,numerical,scientific-computing,linear-algebra,random\"\n---\n\n# NumPy Python Package Guide\n\n## Golden Rule\n\n**Use `import numpy as np`, operate on whole arrays instead of Python loops when possible, and check shapes, dtypes, and copy semantics before assuming behavior.**\n\nNumPy is the core Python package for n-dimensional arrays, vectorized math, broadcasting, linear algebra helpers, and random number generation. For most projects, it is the foundation that other scientific and data libraries build on top of.\n\n## Installation\n\nInstall with `pip`:\n\n```bash\npython -m pip install numpy==2.4.3\n```\n\nIf you use Conda or Miniconda, install from the `conda-forge` channel:\n\n```bash\nconda install -c conda-forge numpy\n```\n\nVerify the environment and version:\n\n```bash\npython - <<'PY'\nimport numpy as np\nprint(np.__version__)\nPY\n```\n\n## Initialize And Create Arrays\n\nMost code starts with one of:\n\n```python\nimport numpy as np\n\na = np.array([1, 2, 3], dtype=np.int64)\nb = np.asarray([1.0, 2.0, 3.0], dtype=np.float64)\nc = np.zeros((2, 3))\nd = np.ones((2, 3), dtype=np.float32)\ne = np.arange(0, 10, 2)\nf = np.linspace(0.0, 1.0, num=5)\n```\n\nCheck the properties that control behavior:\n\n```python\narr = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)\n\nprint(arr.shape)   # (2, 3)\nprint(arr.ndim)    # 2\nprint(arr.dtype)   # int32\nprint(arr.size)    # 6\n```\n\nUse `np.asarray(...)` when you want an array view of array-like input without forcing an unnecessary copy. In NumPy 2.x, `copy=False` is strict and raises if a copy would be required; use `copy=None` to allow a copy when needed, or `copy=True` to force one.\n\n```python\ndata = [[1, 2], [3, 4]]\narr = np.asarray(data, dtype=np.float64, copy=None)\n```\n\n## Core Usage Patterns\n\n### Elementwise math and reductions\n\nNumPy operations usually apply elementwise:\n\n```python\nimport numpy as np\n\nx = np.array([1.0, 2.0, 3.0])\ny = np.array([10.0, 20.0, 30.0])\n\nprint(x + y)        # [11. 22. 33.]\nprint(x * y)        # [10. 40. 90.]\nprint(np.sqrt(y))   # elementwise ufunc\nprint(x.sum())      # scalar reduction\nprint(y.mean())     # scalar reduction\n```\n\nUse `axis=` for row/column reductions:\n\n```python\nmatrix = np.array([[1, 2, 3], [4, 5, 6]])\n\nprint(matrix.sum(axis=0))   # column sums\nprint(matrix.sum(axis=1))   # row sums\n```\n\n### Matrix multiplication\n\n`*` is elementwise multiplication, not matrix multiplication. Use `@` or `np.matmul(...)`:\n\n```python\na = np.array([[1, 2], [3, 4]])\nb = np.array([[5, 6], [7, 8]])\n\nprint(a @ b)\n```\n\n### Reshaping and stacking\n\n```python\narr = np.arange(12)\ngrid = arr.reshape(3, 4)\nflat = grid.ravel()\nstacked = np.stack([grid, grid])\n```\n\nUse `reshape(...)` only when the element count matches the target shape.\n\n## Indexing, Slicing, And Broadcasting\n\n### Basic indexing\n\n```python\narr = np.arange(10)\n\nprint(arr[0])      # first element\nprint(arr[-1])     # last element\nprint(arr[2:7:2])  # slice\n```\n\nFor multidimensional arrays:\n\n```python\ngrid = np.arange(12).reshape(3, 4)\n\nprint(grid[1, 2])   # row 1, col 2\nprint(grid[:, 0])   # first column\nprint(grid[1:3, :2])\n```\n\n### Broadcasting\n\nBroadcasting lets NumPy apply operations to arrays with compatible shapes without materializing repeated copies:\n\n```python\ndata = np.array([[1.0, 2.0, 3.0],\n                 [4.0, 5.0, 6.0]])\noffset = np.array([10.0, 20.0, 30.0])\n\nprint(data + offset)\n```\n\nBroadcasting works when dimensions are equal or one of them is `1`, compared from the trailing dimensions backward. If shapes are incompatible, NumPy raises `ValueError: operands could not be broadcast together`.\n\n## Random Number Generation\n\nPrefer `np.random.default_rng(...)` and a `Generator` instance for new code:\n\n```python\nimport numpy as np\n\nrng = np.random.default_rng(seed=42)\n\nsamples = rng.normal(loc=0.0, scale=1.0, size=(2, 3))\nints = rng.integers(low=0, high=10, size=5)\n```\n\nThis is better than using legacy global functions such as `np.random.seed(...)` and `np.random.rand(...)` in new code. If you need reproducibility, keep the seed explicit. NumPy documents no compatibility guarantee for the `Generator` bit stream across versions.\n\n## Typing\n\nUse `numpy.typing` for type hints:\n\n```python\nfrom typing import Any\nimport numpy as np\nimport numpy.typing as npt\n\ndef normalize(x: npt.ArrayLike) -> npt.NDArray[np.float64]:\n    arr = np.asarray(x, dtype=np.float64)\n    denom = np.linalg.norm(arr)\n    return arr if denom == 0.0 else arr / denom\n```\n\nUseful typing names:\n\n- `npt.ArrayLike` for function inputs that can become arrays\n- `npt.NDArray[dtype]` for ndarray return types\n\nIf you run `mypy`, NumPy provides a plugin (`numpy.typing.mypy_plugin`) to resolve platform-specific scalar precisions more accurately.\n\n## Configuration And Environment Notes\n\nNumPy itself does not use API authentication.\n\nThe main things that behave like \"configuration\" for coding tasks are:\n\n- `dtype=`: controls numeric precision and casting behavior\n- `copy=`: controls whether data may be shared or must be copied\n- `order=`: memory layout (`\"C\"` or `\"F\"`) for some constructors and conversions\n- RNG seed: controls reproducibility in random workflows\n- `np.set_printoptions(...)`: useful when tests or logs need stable array rendering\n\nFor isolated projects, install NumPy into a virtual environment or Conda environment instead of the system interpreter.\n\n## Common Pitfalls\n\n### Views vs copies\n\nBasic slicing usually creates a **view**, so writing through the slice can mutate the original array:\n\n```python\narr = np.array([1, 2, 3, 4])\nview = arr[1:3]\nview[0] = 99\n\nprint(arr)   # [ 1 99  3  4]\n```\n\nAdvanced indexing creates a **copy**, not a view:\n\n```python\narr = np.array([1, 2, 3, 4])\ncopy = arr[[1, 3]]\ncopy[0] = 99\n\nprint(arr)   # unchanged\n```\n\n### `np.arange(...)` with float steps\n\n`np.arange(...)` is fine for integer ranges. For evenly spaced floats, prefer `np.linspace(...)` to avoid surprising endpoint and precision behavior.\n\n### Dtype promotion and in-place operations\n\nMixed dtypes can change result dtypes, and in-place writes can fail if NumPy would need an unsafe cast:\n\n```python\narr = np.array([1, 2, 3], dtype=np.int64)\n\n# This can raise because the float result cannot be cast back safely.\narr += 0.5\n```\n\nBe explicit about the dtype you want before combining arrays or scalars with different numeric types.\n\n### Shape mismatches\n\nMost runtime NumPy bugs are shape bugs. Inspect `.shape` before assuming broadcasting or matrix multiplication will work:\n\n```python\nassert features.ndim == 2\nassert weights.shape == (features.shape[1],)\n```\n\n## Version-Sensitive Notes For NumPy 2.x\n\n- The version used here for this package session is `2.4.3`, and PyPI lists `2.4.3` as the current release.\n- NumPy 2.0 changed type-promotion behavior in some mixed-dtype operations. If a project was written against 1.x behavior, check the NumPy 2.0 migration guide before \"fixing\" results by guesswork.\n- NumPy 2.0 changed `np.asarray(...)` semantics by adding `copy=` and `device=` keyword arguments. `copy=False` now means \"never copy\" and can raise if the conversion cannot honor that requirement.\n- Several legacy aliases and compatibility shims were removed in 2.x. Old blog posts or snippets may fail even if the overall idea is still correct.\n- For extension modules that compile against the NumPy C API, NumPy 2.0 is a binary-compatibility boundary. Pure Python code using public NumPy APIs is usually much less affected.\n\n## Practical Workflow For Agents\n\n1. Install `numpy` into the active project environment and confirm `np.__version__`.\n2. Convert external inputs with `np.asarray(...)` only once near the boundary.\n3. Check `.shape` and `.dtype` before writing vectorized operations.\n4. Prefer array expressions, ufuncs, and reductions over Python loops.\n5. Use `default_rng(...)` for new random code.\n6. When behavior looks surprising, inspect broadcasting rules and whether you are working with a view or a copy.\n7. If the project recently moved from NumPy 1.x to 2.x, check the migration guide before assuming a bug is in your own code.\n\n## Official Sources Used\n\n- NumPy install guide: https://numpy.org/install\n- NumPy absolute beginners guide: https://numpy.org/doc/stable/user/absolute_beginners.html\n- NumPy quickstart: https://numpy.org/doc/stable/user/quickstart.html\n- NumPy broadcasting guide: https://numpy.org/doc/stable/user/basics.broadcasting.html\n- NumPy copies and views guide: https://numpy.org/doc/stable/user/basics.copies.html\n- `numpy.asarray` reference: https://numpy.org/doc/stable/reference/generated/numpy.asarray.html\n- Random `Generator` reference: https://numpy.org/doc/stable/reference/random/generator.html\n- NumPy typing reference: https://numpy.org/doc/stable/reference/typing.html\n- NumPy 2.0 migration guide: https://numpy.org/doc/stable/numpy_2_0_migration_guide.html\n- PyPI package page: https://pypi.org/project/numpy/\n"
  },
  {
    "path": "content/nuxt/docs/nuxt/javascript/DOC.md",
    "content": "---\nname: nuxt\ndescription: \"Nuxt framework for building Vue applications with file-based routing, server routes, runtime config, plugins, and production build commands\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"nuxt,vue,ssr,ssg,nitro,meta-framework\"\n---\n\n# Nuxt for JavaScript\n\nUse `nuxt` when you need the framework package itself: project scaffolding, app configuration, file-based pages, server routes, plugins, runtime config, and build/dev commands.\n\n## Install and start a project\n\nCreate a new Nuxt app with the official initializer:\n\n```bash\nnpx nuxi@latest init my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nFor an existing Vue project, install the framework package and the Vue runtime packages it depends on:\n\n```bash\nnpm install nuxt vue vue-router\n```\n\nMinimal `package.json` scripts:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"nuxt dev\",\n    \"build\": \"nuxt build\",\n    \"preview\": \"nuxt preview\",\n    \"generate\": \"nuxt generate\"\n  }\n}\n```\n\n## Minimal project setup\n\n`nuxt.config.js` is the main entry point for framework configuration.\n\n```js\nexport default defineNuxtConfig({\n  runtimeConfig: {\n    apiSecret: process.env.NUXT_API_SECRET,\n    public: {\n      apiBase: process.env.NUXT_PUBLIC_API_BASE || \"/api\"\n    }\n  }\n})\n```\n\nExample `.env`:\n\n```env\nNUXT_API_SECRET=replace-me\nNUXT_PUBLIC_API_BASE=/api\n```\n\nImportant runtime config rule:\n\n- Top-level keys such as `apiSecret` are server-only.\n- Keys under `runtimeConfig.public` are exposed to both server and browser code.\n\n## Create pages and fetch data\n\nNuxt turns files in `pages/` into routes automatically.\n\n`pages/index.vue`\n\n```vue\n<script setup>\nconst { data, pending, error, refresh } = await useFetch(\"/hello\", {\n  baseURL: useRuntimeConfig().public.apiBase\n})\n</script>\n\n<template>\n  <main>\n    <h1>Nuxt app</h1>\n\n    <p v-if=\"pending\">Loading…</p>\n    <p v-else-if=\"error\">{{ error.message }}</p>\n    <pre v-else>{{ data }}</pre>\n\n    <button type=\"button\" @click=\"refresh()\">Refresh</button>\n  </main>\n</template>\n```\n\nUse `useFetch()` in pages, components, and composables when you want Nuxt-aware data fetching that works with server rendering.\n\n## Add a server API route\n\nFiles in `server/api/` become server endpoints under `/api`.\n\n`server/api/hello.get.js`\n\n```js\nexport default defineEventHandler((event) => {\n  const config = useRuntimeConfig(event)\n\n  return {\n    message: \"Hello from the server\",\n    apiBase: config.public.apiBase,\n    hasSecret: Boolean(config.apiSecret)\n  }\n})\n```\n\nThe page example above calls this route through the public `apiBase` value.\n\n## Initialize a reusable API client in a plugin\n\nUse a Nuxt plugin when you want one configured client instance available across the app.\n\n`plugins/api.js`\n\n```js\nexport default defineNuxtPlugin(() => {\n  const config = useRuntimeConfig()\n\n  const api = $fetch.create({\n    baseURL: config.public.apiBase,\n    headers: {\n      accept: \"application/json\"\n    }\n  })\n\n  return {\n    provide: {\n      api\n    }\n  }\n})\n```\n\nUse the injected client from components, pages, or composables:\n\n```vue\n<script setup>\nconst { $api } = useNuxtApp()\nconst profile = await $api(\"/hello\")\n</script>\n\n<template>\n  <pre>{{ profile }}</pre>\n</template>\n```\n\n## Route middleware\n\nUse named middleware in `middleware/` to guard pages.\n\n`middleware/auth.js`\n\n```js\nexport default defineNuxtRouteMiddleware(() => {\n  const loggedIn = useState(\"logged-in\", () => false)\n\n  if (!loggedIn.value) {\n    return navigateTo(\"/login\")\n  }\n})\n```\n\nApply it in a page:\n\n`pages/account.vue`\n\n```vue\n<script setup>\ndefinePageMeta({\n  middleware: \"auth\"\n})\n</script>\n\n<template>\n  <div>Private account page</div>\n</template>\n```\n\n## Common commands\n\n```bash\n# Start the development server\nnpm run dev\n\n# Build the production server bundle\nnpm run build\n\n# Preview the production build locally\nnpm run preview\n\n# Generate a static site when your app is configured for prerender/static output\nnpm run generate\n```\n\n## Common pitfalls\n\n- Do not put secrets in `runtimeConfig.public`; everything there is available to client-side code.\n- Use `useFetch()` inside Nuxt app code where composables are allowed; use `$fetch()` for imperative requests in plugins, route handlers, or utilities.\n- Keep server endpoints in `server/api/`; client code should call them with relative `/api/...` paths or a public runtime-config base URL.\n- Call Nuxt composables such as `useRuntimeConfig()`, `useFetch()`, and `useState()` inside Nuxt setup/context, not at module top level.\n- Register shared clients and cross-cutting setup in `plugins/` instead of recreating them in each page.\n\n## Useful links\n\n- `https://nuxt.com/docs/getting-started/installation`\n- `https://nuxt.com/docs/api/commands/init`\n- `https://nuxt.com/docs/api/commands/dev`\n- `https://nuxt.com/docs/api/commands/build`\n- `https://nuxt.com/docs/api/commands/preview`\n- `https://nuxt.com/docs/api/commands/generate`\n- `https://nuxt.com/docs/api/utils/define-nuxt-config`\n- `https://nuxt.com/docs/guide/going-further/runtime-config`\n- `https://nuxt.com/docs/api/composables/use-fetch`\n- `https://nuxt.com/docs/guide/directory-structure/server`\n- `https://nuxt.com/docs/guide/directory-structure/plugins`\n- `https://nuxt.com/docs/guide/directory-structure/middleware`\n"
  },
  {
    "path": "content/oauthlib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"oauthlib package guide for low-level OAuth 1.0a and OAuth 2.0 client flows in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,oauthlib,oauth,oauth1,oauth2\"\n---\n\n# oauthlib Python Package Guide\n\n## What It Does\n\n`oauthlib` is a low-level OAuth library. It prepares authorization URLs, token request bodies, signed request headers, and token parsing logic, but it does not send HTTP requests for you.\n\nUse it when you want direct control over the OAuth protocol details or need to integrate with your own HTTP stack. If you mainly want OAuth support on top of `requests`, the maintainer README points to `requests-oauthlib` as the higher-level option.\n\nThis guide focuses on the client-side pieces most applications need:\n\n- `oauthlib.oauth2.WebApplicationClient` for authorization code flow\n- `oauthlib.oauth2.BackendApplicationClient` for client credentials flow\n- `oauthlib.oauth1.Client` for OAuth 1.0a request signing\n\n`oauthlib 3.3.1` requires Python `>=3.8`.\n\n## Install\n\n```bash\npip install oauthlib==3.3.1\n```\n\nOptional extras declared in the package metadata:\n\n```bash\npip install \"oauthlib[rsa]\"\npip install \"oauthlib[signedtoken]\"\npip install \"oauthlib[signals]\"\n```\n\n## Shared Setup\n\nKeep provider-specific endpoints and secrets in environment variables:\n\n```bash\nexport OAUTH_CLIENT_ID=\"replace-me\"\nexport OAUTH_CLIENT_SECRET=\"replace-me\"\nexport OAUTH_REDIRECT_URI=\"https://app.example.com/callback\"\nexport OAUTH_AUTHORIZATION_URL=\"https://provider.example.com/oauth/authorize\"\nexport OAUTH_TOKEN_URL=\"https://provider.example.com/oauth/token\"\nexport API_BASE_URL=\"https://provider.example.com/api\"\n```\n\nFor local HTTP callback testing only, `oauthlib` also recognizes:\n\n```bash\nexport OAUTHLIB_INSECURE_TRANSPORT=1\n```\n\nDo not set that in production. `oauthlib` checks for HTTPS on authorization URLs, token URLs, and protected-resource URLs unless that variable is present.\n\nThe examples below use the Python standard library to send HTTP requests because `oauthlib` itself does not include an HTTP client.\n\n```python\nimport base64\nfrom urllib.request import Request, urlopen\n\n\ndef basic_auth_header(client_id, client_secret):\n    raw = f\"{client_id}:{client_secret}\".encode(\"utf-8\")\n    return \"Basic \" + base64.b64encode(raw).decode(\"ascii\")\n\n\ndef post_form(url, body, client_id=None, client_secret=None):\n    headers = {\n        \"Accept\": \"application/json\",\n        \"Content-Type\": \"application/x-www-form-urlencoded\",\n    }\n    if client_id and client_secret:\n        headers[\"Authorization\"] = basic_auth_header(client_id, client_secret)\n\n    request = Request(url, data=body.encode(\"utf-8\"), headers=headers, method=\"POST\")\n    with urlopen(request) as response:\n        return response.read().decode(\"utf-8\")\n```\n\n## OAuth 2.0 Authorization Code Flow\n\n`WebApplicationClient` is the normal choice for server-side web apps. The base client docs recommend the `prepare_*_request` methods because they add HTTPS and state checks.\n\nThis example uses PKCE with `S256`. `oauthlib` accepts `code_challenge` and `code_verifier`, but you generate them yourself.\n\n```python\nimport base64\nimport hashlib\nimport os\nimport secrets\nfrom urllib.request import Request, urlopen\n\nfrom oauthlib.oauth2 import WebApplicationClient\n\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"OAUTH_CLIENT_SECRET\"]\nREDIRECT_URI = os.environ[\"OAUTH_REDIRECT_URI\"]\nAUTHORIZATION_URL = os.environ[\"OAUTH_AUTHORIZATION_URL\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\nAPI_BASE_URL = os.environ[\"API_BASE_URL\"]\n\n\ndef code_challenge_s256(code_verifier):\n    digest = hashlib.sha256(code_verifier.encode(\"ascii\")).digest()\n    return base64.urlsafe_b64encode(digest).rstrip(b\"=\").decode(\"ascii\")\n\n\nclient = WebApplicationClient(CLIENT_ID)\nstate = secrets.token_urlsafe(32)\ncode_verifier = secrets.token_urlsafe(64)\n\nauthorization_url, _, _ = client.prepare_authorization_request(\n    AUTHORIZATION_URL,\n    redirect_url=REDIRECT_URI,\n    scope=[\"openid\", \"profile\", \"email\"],\n    state=state,\n    code_challenge=code_challenge_s256(code_verifier),\n    code_challenge_method=\"S256\",\n)\n\nprint(\"Open this URL in a browser:\")\nprint(authorization_url)\n\nauthorization_response = input(\"Paste the full redirect URL: \").strip()\n\ntoken_url, _, token_body = client.prepare_token_request(\n    TOKEN_URL,\n    authorization_response=authorization_response,\n    redirect_url=REDIRECT_URI,\n    include_client_id=False,\n    code_verifier=code_verifier,\n)\n\ntoken_response_body = post_form(\n    token_url,\n    token_body,\n    client_id=CLIENT_ID,\n    client_secret=CLIENT_SECRET,\n)\ntoken = client.parse_request_body_response(token_response_body)\n\nresource_url, resource_headers, _ = client.add_token(\n    f\"{API_BASE_URL}/userinfo\",\n    http_method=\"GET\",\n)\n\nrequest = Request(resource_url, headers=resource_headers, method=\"GET\")\nwith urlopen(request) as response:\n    profile = response.read().decode(\"utf-8\")\n\nprint(token)\nprint(profile)\n```\n\nNotes:\n\n- `prepare_token_request(..., authorization_response=...)` parses the callback URL and verifies `state`\n- `include_client_id=False` is appropriate when the token request uses HTTP Basic auth with `client_id` and `client_secret`\n- for public clients with no client secret, omit the Basic auth header and keep `include_client_id=True`\n\n## Client Credentials Flow\n\nUse `BackendApplicationClient` when the application is acting on its own behalf and the provider supports the `client_credentials` grant.\n\n```python\nimport os\nfrom urllib.request import Request, urlopen\n\nfrom oauthlib.oauth2 import BackendApplicationClient\n\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"OAUTH_CLIENT_SECRET\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\nAPI_BASE_URL = os.environ[\"API_BASE_URL\"]\n\nclient = BackendApplicationClient(CLIENT_ID)\n\ntoken_body = client.prepare_request_body(\n    scope=[\"read:orders\"],\n    include_client_id=False,\n)\n\ntoken_response_body = post_form(\n    TOKEN_URL,\n    token_body,\n    client_id=CLIENT_ID,\n    client_secret=CLIENT_SECRET,\n)\ntoken = client.parse_request_body_response(token_response_body)\n\nresource_url, resource_headers, _ = client.add_token(\n    f\"{API_BASE_URL}/orders\",\n    http_method=\"GET\",\n)\n\nrequest = Request(resource_url, headers=resource_headers, method=\"GET\")\nwith urlopen(request) as response:\n    orders = response.read().decode(\"utf-8\")\n\nprint(token)\nprint(orders)\n```\n\nIf your provider expects client credentials in the form body instead of HTTP Basic auth, call `prepare_request_body(..., include_client_id=True)` and send the request without the `Authorization` header.\n\n## Refreshing An OAuth 2.0 Token\n\nIf the token response included a `refresh_token`, pass the stored token dict back into the client and prepare a refresh request.\n\n```python\nimport json\nimport os\nfrom pathlib import Path\n\nfrom oauthlib.oauth2 import WebApplicationClient\n\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"OAUTH_CLIENT_SECRET\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\n\nstored_token = json.loads(Path(\"oauth-token.json\").read_text())\nclient = WebApplicationClient(CLIENT_ID, token=stored_token)\n\nrefresh_url, _, refresh_body = client.prepare_refresh_token_request(\n    TOKEN_URL,\n    include_client_id=False,\n)\n\nrefresh_response_body = post_form(\n    refresh_url,\n    refresh_body,\n    client_id=CLIENT_ID,\n    client_secret=CLIENT_SECRET,\n)\nnew_token = client.parse_request_body_response(refresh_response_body)\n\nPath(\"oauth-token.json\").write_text(json.dumps(new_token))\nprint(new_token)\n```\n\n`parse_request_body_response()` expects the raw JSON response body string, not a pre-parsed dict.\n\n## OAuth 1.0a Request Signing\n\nUse `oauthlib.oauth1.Client` when you already have OAuth 1.0a credentials and need to sign outgoing requests.\n\n```bash\nexport OAUTH1_CLIENT_KEY=\"replace-me\"\nexport OAUTH1_CLIENT_SECRET=\"replace-me\"\nexport OAUTH1_RESOURCE_OWNER_KEY=\"replace-me\"\nexport OAUTH1_RESOURCE_OWNER_SECRET=\"replace-me\"\nexport API_BASE_URL=\"https://provider.example.com/api\"\n```\n\n```python\nimport os\nfrom urllib.request import Request, urlopen\n\nfrom oauthlib.oauth1 import Client as OAuth1Client\n\n\nclient = OAuth1Client(\n    client_key=os.environ[\"OAUTH1_CLIENT_KEY\"],\n    client_secret=os.environ[\"OAUTH1_CLIENT_SECRET\"],\n    resource_owner_key=os.environ[\"OAUTH1_RESOURCE_OWNER_KEY\"],\n    resource_owner_secret=os.environ[\"OAUTH1_RESOURCE_OWNER_SECRET\"],\n)\n\nuri, headers, body = client.sign(\n    f\"{os.environ['API_BASE_URL']}/account/verify_credentials\",\n    http_method=\"GET\",\n)\n\nrequest = Request(uri, headers=headers, method=\"GET\")\nwith urlopen(request) as response:\n    payload = response.read().decode(\"utf-8\")\n\nprint(payload)\n```\n\nIf your provider requires a different signature algorithm, pass one of the exported constants such as `SIGNATURE_HMAC_SHA256`, `SIGNATURE_HMAC_SHA512`, `SIGNATURE_RSA_SHA1`, `SIGNATURE_RSA_SHA256`, or `SIGNATURE_RSA_SHA512` when you create the client.\n\n## Common Pitfalls\n\n- `oauthlib` does not perform token exchange or API calls by itself; you must send the returned URL, headers, and body through your own HTTP library\n- OAuth 2.0 helper methods reject non-HTTPS authorization, token, and resource URLs unless `OAUTHLIB_INSECURE_TRANSPORT` is set\n- keep the redirect URI identical between the authorization request and token request or the provider can reject the code exchange\n- keep `state` stable across the redirect; `prepare_token_request(..., authorization_response=...)` raises `MismatchingStateError` if it does not match\n- `add_token()` needs an `access_token`; if the token dict includes an expired `expires_at`, it raises `TokenExpiredError`\n- for OAuth 1.0a, body signatures only work with `application/x-www-form-urlencoded` payloads, and `GET` or `HEAD` requests should not include a body\n- `LegacyApplicationClient` exists for the resource owner password credentials grant, but its own class docs describe it as suitable only when there is a strong trust relationship and other flows are not viable\n"
  },
  {
    "path": "content/okta/docs/identity/javascript/DOC.md",
    "content": "---\nname: identity\ndescription: \"Okta Node.js SDK coding guidelines for the Okta Management API using official libraries\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.3.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"okta,identity,sso,oauth,authentication\"\n---\n\n# Okta Node.js SDK Coding Guidelines\n\nYou are an Okta API coding expert. Help me with writing code using the Okta Management API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developer.okta.com/docs/reference/api/users/\nhttps://github.com/okta/okta-sdk-nodejs\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Okta Node.js SDK to interact with the Okta Management API. This is the standard library for all Okta Management API interactions. Do not use deprecated packages or the authentication SDK for management tasks.\n\n- **Library Name:** Okta Node.js SDK\n- **NPM Package:** `@okta/okta-sdk-nodejs`\n- **Current Version:** 7.3.0\n- **Authentication SDK (Different Use Case):** `@okta/okta-auth-js` - Only for end-user authentication flows, NOT for management API\n\n**Installation:**\n\n- **Correct:** `npm install @okta/okta-sdk-nodejs`\n\n**APIs and Usage:**\n\n- **Correct:** `const okta = require('@okta/okta-sdk-nodejs')`\n- **Correct:** `const client = new okta.Client({ orgUrl, token })`\n- **Correct:** `await client.userApi.createUser({ body: newUser })`\n- **Correct:** `await client.groupApi.createGroup({ group: newGroup })`\n- **Correct:** `await client.applicationApi.createApplication({ application })`\n- **Incorrect:** Using `@okta/okta-auth-js` for management operations\n- **Incorrect:** Direct HTTP calls without SDK\n\n## System Requirements\n\nThe Okta Node.js SDK requires:\n- Node.js v12.0.0 or higher\n- An Okta organization URL\n- An API token or OAuth 2.0 credentials\n\n## Initialization and API Authentication\n\nThe `@okta/okta-sdk-nodejs` library requires creating a `Client` instance for all API calls.\n\n### API Token Authentication (Simple)\n\n```javascript\nconst okta = require('@okta/okta-sdk-nodejs');\n\nconst client = new okta.Client({\n  orgUrl: 'https://dev-1234.okta.com',\n  token: process.env.OKTA_API_TOKEN\n});\n```\n\n### OAuth 2.0 Private Key Authentication (Recommended for Service Apps)\n\nWhen using OAuth 2.0 with private key authentication, you don't need an API token. The SDK automatically requests access tokens.\n\n```javascript\nconst okta = require('@okta/okta-sdk-nodejs');\n\nconst client = new okta.Client({\n  orgUrl: 'https://dev-1234.okta.com',\n  authorizationMode: 'PrivateKey',\n  clientId: process.env.OKTA_CLIENT_ID,\n  scopes: ['okta.users.manage', 'okta.groups.manage'],\n  privateKey: process.env.OKTA_PRIVATE_KEY, // JWK JSON string or PEM format\n  keyId: process.env.OKTA_KEY_ID // Optional if kid is in JWK\n});\n```\n\n### Private Key Formats\n\nThe `privateKey` parameter accepts:\n\n- **JWK (JSON Web Key) as string:**\n```javascript\nprivateKey: '{\"kty\":\"RSA\",\"kid\":\"my-key-id\",\"n\":\"...\",\"e\":\"AQAB\",\"d\":\"...\"}'\n```\n\n- **JWK as object:**\n```javascript\nprivateKey: {\n  kty: 'RSA',\n  kid: 'my-key-id',\n  n: '...',\n  e: 'AQAB',\n  d: '...'\n}\n```\n\n- **PEM format:**\n```javascript\nprivateKey: `-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...\n-----END PRIVATE KEY-----`\n```\n\n## User Management\n\n### Create a User\n\nCreate a new user with profile information and password:\n\n```javascript\nconst okta = require('@okta/okta-sdk-nodejs');\nconst client = new okta.Client({ orgUrl, token });\n\nasync function createUser() {\n  const newUser = {\n    profile: {\n      firstName: 'John',\n      lastName: 'Doe',\n      email: 'john.doe@example.com',\n      login: 'john.doe@example.com'\n    },\n    credentials: {\n      password: {\n        value: 'SecurePassword123!'\n      }\n    }\n  };\n\n  const user = await client.userApi.createUser({ body: newUser });\n  console.log('Created user:', user.id);\n  return user;\n}\n```\n\n### Create User with Activation\n\nCreate and automatically activate a user:\n\n```javascript\nasync function createAndActivateUser() {\n  const newUser = {\n    profile: {\n      firstName: 'Jane',\n      lastName: 'Smith',\n      email: 'jane.smith@example.com',\n      login: 'jane.smith@example.com'\n    },\n    credentials: {\n      password: {\n        value: 'SecurePassword123!'\n      }\n    }\n  };\n\n  const user = await client.userApi.createUser({\n    body: newUser,\n    activate: true\n  });\n\n  console.log('Created and activated user:', user.id);\n  return user;\n}\n```\n\n### Get a User\n\nRetrieve a user by ID or login:\n\n```javascript\nasync function getUser() {\n  // By user ID\n  let user = await client.userApi.getUser({\n    userId: 'ausmvdt5xg8wRVI1d0g3'\n  });\n\n  // By login email\n  user = await client.userApi.getUser({\n    userId: 'john.doe@example.com'\n  });\n\n  console.log('User:', user.profile.firstName, user.profile.lastName);\n  return user;\n}\n```\n\n### List All Users\n\nIterate through all users in your organization:\n\n```javascript\nasync function listAllUsers() {\n  const collection = await client.userApi.listUsers();\n\n  // Using .each() method\n  await collection.each(user => {\n    console.log(`${user.profile.firstName} ${user.profile.lastName} (${user.profile.email})`);\n  });\n}\n```\n\n### List Users with Async Iteration\n\n```javascript\nasync function listUsersAsyncIteration() {\n  const collection = await client.userApi.listUsers();\n\n  // Using for...await\n  for await (let user of collection) {\n    console.log(`User ID: ${user.id}, Name: ${user.profile.firstName} ${user.profile.lastName}`);\n  }\n}\n```\n\n### Search Users by Query\n\nSearch users using simple query string:\n\n```javascript\nasync function searchUsersByName() {\n  const collection = await client.userApi.listUsers({\n    q: 'Robert'\n  });\n\n  for await (let user of collection) {\n    console.log('Found user:', user.profile.email);\n  }\n}\n```\n\n### Search Users with SCIM Filter\n\nUse SCIM expressions for precise filtering:\n\n```javascript\nasync function searchUsersWithFilter() {\n  // SCIM filter for exact match\n  const collection = await client.userApi.listUsers({\n    search: 'profile.nickName eq \"bobby\"'\n  });\n\n  for await (let user of collection) {\n    console.log('Found user:', user.profile.email);\n  }\n}\n```\n\n### Filter Users by Time\n\nFind users updated after a specific time:\n\n```javascript\nasync function findRecentlyUpdatedUsers() {\n  const collection = await client.userApi.listUsers({\n    filter: 'lastUpdated gt \"2025-01-01T00:00:00.000Z\"'\n  });\n\n  for await (let user of collection) {\n    console.log('Recently updated:', user.profile.email, 'at', user.lastUpdated);\n  }\n}\n```\n\n### Update a User\n\nModify user profile information:\n\n```javascript\nasync function updateUser(userId) {\n  const user = await client.userApi.getUser({ userId });\n\n  // Update profile fields\n  user.profile.nickName = 'Johnny';\n  user.profile.mobilePhone = '+1-555-123-4567';\n\n  await client.userApi.updateUser({\n    userId: user.id,\n    user: user\n  });\n\n  console.log('User updated successfully');\n}\n```\n\n### Partial Update a User\n\nUpdate specific fields without retrieving the full user object:\n\n```javascript\nasync function partialUpdateUser(userId) {\n  const updates = {\n    profile: {\n      nickName: 'JD',\n      department: 'Engineering'\n    }\n  };\n\n  await client.userApi.updateUser({\n    userId: userId,\n    user: updates\n  });\n\n  console.log('User partially updated');\n}\n```\n\n### Deactivate a User\n\nDeactivate a user account:\n\n```javascript\nasync function deactivateUser(userId) {\n  await client.userApi.deactivateUser({ userId });\n  console.log('User deactivated');\n}\n```\n\n### Delete a User\n\nPermanently delete a user (must be deactivated first):\n\n```javascript\nasync function deleteUser(userId) {\n  // First deactivate\n  await client.userApi.deactivateUser({ userId });\n\n  // Then delete\n  await client.userApi.deleteUser({ userId });\n\n  console.log('User deleted permanently');\n}\n```\n\n### Reactivate a User\n\nReactivate a previously deactivated user:\n\n```javascript\nasync function reactivateUser(userId) {\n  await client.userApi.activateUser({\n    userId: userId,\n    sendEmail: false\n  });\n\n  console.log('User reactivated');\n}\n```\n\n### Suspend and Unsuspend User\n\nTemporarily suspend a user:\n\n```javascript\nasync function suspendUser(userId) {\n  await client.userApi.suspendUser({ userId });\n  console.log('User suspended');\n}\n\nasync function unsuspendUser(userId) {\n  await client.userApi.unsuspendUser({ userId });\n  console.log('User unsuspended');\n}\n```\n\n### Reset User Password\n\nSend a password reset email:\n\n```javascript\nasync function resetUserPassword(userId) {\n  await client.userApi.resetPassword({\n    userId: userId,\n    sendEmail: true\n  });\n\n  console.log('Password reset email sent');\n}\n```\n\n### Expire User Password\n\nForce a user to change password on next login:\n\n```javascript\nasync function expireUserPassword(userId) {\n  const user = await client.userApi.expirePassword({\n    userId: userId\n  });\n\n  console.log('Password expired for user:', user.id);\n}\n```\n\n## Group Management\n\n### Create a Group\n\nCreate a new group:\n\n```javascript\nasync function createGroup() {\n  const newGroup = {\n    profile: {\n      name: 'Engineering Team',\n      description: 'All engineering department members'\n    }\n  };\n\n  const group = await client.groupApi.createGroup({ group: newGroup });\n  console.log('Created group:', group.id);\n  return group;\n}\n```\n\n### Get a Group\n\nRetrieve a group by ID:\n\n```javascript\nasync function getGroup(groupId) {\n  const group = await client.groupApi.getGroup({ groupId });\n  console.log('Group:', group.profile.name);\n  return group;\n}\n```\n\n### List All Groups\n\nList all groups in the organization:\n\n```javascript\nasync function listAllGroups() {\n  const collection = await client.groupApi.listGroups();\n\n  for await (let group of collection) {\n    console.log(`Group: ${group.profile.name} (${group.id})`);\n  }\n}\n```\n\n### Search Groups by Name\n\nSearch for groups matching a query:\n\n```javascript\nasync function searchGroups() {\n  const collection = await client.groupApi.listGroups({\n    q: 'Engineering'\n  });\n\n  for await (let group of collection) {\n    console.log('Found group:', group.profile.name);\n  }\n}\n```\n\n### Update a Group\n\nUpdate group profile information:\n\n```javascript\nasync function updateGroup(groupId) {\n  const group = await client.groupApi.getGroup({ groupId });\n\n  group.profile.description = 'Updated description';\n\n  await client.groupApi.updateGroup({\n    groupId: group.id,\n    group: group\n  });\n\n  console.log('Group updated');\n}\n```\n\n### Delete a Group\n\nDelete a group:\n\n```javascript\nasync function deleteGroup(groupId) {\n  await client.groupApi.deleteGroup({ groupId });\n  console.log('Group deleted');\n}\n```\n\n### Assign User to Group\n\nAdd a user to a group:\n\n```javascript\nasync function assignUserToGroup(groupId, userId) {\n  await client.groupApi.assignUserToGroup({\n    groupId: groupId,\n    userId: userId\n  });\n\n  console.log(`User ${userId} added to group ${groupId}`);\n}\n```\n\n### Remove User from Group\n\nRemove a user from a group:\n\n```javascript\nasync function removeUserFromGroup(groupId, userId) {\n  await client.groupApi.unassignUserFromGroup({\n    groupId: groupId,\n    userId: userId\n  });\n\n  console.log(`User ${userId} removed from group ${groupId}`);\n}\n```\n\n### List Group Members\n\nGet all users in a group:\n\n```javascript\nasync function listGroupMembers(groupId) {\n  const collection = await client.groupApi.listGroupUsers({ groupId });\n\n  for await (let user of collection) {\n    console.log(`Member: ${user.profile.firstName} ${user.profile.lastName}`);\n  }\n}\n```\n\n### List User's Groups\n\nGet all groups a user belongs to:\n\n```javascript\nasync function listUserGroups(userId) {\n  const collection = await client.userApi.listUserGroups({ userId });\n\n  for await (let group of collection) {\n    console.log(`User is in group: ${group.profile.name}`);\n  }\n}\n```\n\n## Application Management\n\n### Create a Basic Auth Application\n\n```javascript\nasync function createBasicAuthApp() {\n  const application = {\n    name: 'template_basic_auth',\n    label: 'Sample Basic Auth App',\n    signOnMode: 'BASIC_AUTH',\n    settings: {\n      app: {\n        url: 'https://example.com/auth.htm',\n        authURL: 'https://example.com/login.html'\n      }\n    }\n  };\n\n  const app = await client.applicationApi.createApplication({\n    application: application\n  });\n\n  console.log('Created application:', app.id);\n  return app;\n}\n```\n\n### Create a SAML 2.0 Application\n\n```javascript\nasync function createSAMLApp() {\n  const application = {\n    name: 'template_saml_2_0',\n    label: 'SAML 2.0 App',\n    signOnMode: 'SAML_2_0',\n    settings: {\n      signOn: {\n        defaultRelayState: '',\n        ssoAcsUrl: 'https://example.com/sso/saml',\n        recipient: 'https://example.com/sso/saml',\n        destination: 'https://example.com/sso/saml',\n        audience: 'https://example.com',\n        idpIssuer: 'http://www.okta.com/${org.externalKey}',\n        subjectNameIdTemplate: '${user.userName}',\n        subjectNameIdFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',\n        responseSigned: true,\n        assertionSigned: true,\n        signatureAlgorithm: 'RSA_SHA256',\n        digestAlgorithm: 'SHA256',\n        honorForceAuthn: true,\n        authnContextClassRef: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'\n      }\n    }\n  };\n\n  const app = await client.applicationApi.createApplication({\n    application: application\n  });\n\n  console.log('Created SAML application:', app.id);\n  return app;\n}\n```\n\n### Create an OAuth 2.0 Application\n\n```javascript\nasync function createOAuthApp() {\n  const application = {\n    name: 'oidc_client',\n    label: 'OAuth 2.0 App',\n    signOnMode: 'OPENID_CONNECT',\n    credentials: {\n      oauthClient: {\n        token_endpoint_auth_method: 'client_secret_post'\n      }\n    },\n    settings: {\n      oauthClient: {\n        client_uri: 'https://example.com',\n        logo_uri: 'https://example.com/logo.png',\n        redirect_uris: ['https://example.com/oauth/callback'],\n        response_types: ['code'],\n        grant_types: ['authorization_code', 'refresh_token'],\n        application_type: 'web'\n      }\n    }\n  };\n\n  const app = await client.applicationApi.createApplication({\n    application: application\n  });\n\n  console.log('Created OAuth app:', app.id);\n  console.log('Client ID:', app.credentials.oauthClient.client_id);\n  console.log('Client Secret:', app.credentials.oauthClient.client_secret);\n  return app;\n}\n```\n\n### Get an Application\n\nRetrieve an application by ID:\n\n```javascript\nasync function getApplication(appId) {\n  const app = await client.applicationApi.getApplication({\n    appId: appId\n  });\n\n  console.log('Application:', app.label);\n  return app;\n}\n```\n\n### List All Applications\n\n```javascript\nasync function listAllApplications() {\n  const collection = await client.applicationApi.listApplications();\n\n  for await (let app of collection) {\n    console.log(`App: ${app.label} (${app.id})`);\n  }\n}\n```\n\n### Update an Application\n\n```javascript\nasync function updateApplication(appId) {\n  const app = await client.applicationApi.getApplication({ appId });\n\n  app.label = 'Updated Application Name';\n\n  await client.applicationApi.updateApplication({\n    appId: app.id,\n    application: app\n  });\n\n  console.log('Application updated');\n}\n```\n\n### Delete an Application\n\n```javascript\nasync function deleteApplication(appId) {\n  await client.applicationApi.deactivateApplication({ appId });\n  await client.applicationApi.deleteApplication({ appId });\n  console.log('Application deleted');\n}\n```\n\n### Assign User to Application\n\n```javascript\nasync function assignUserToApplication(appId, userId) {\n  const appUser = await client.applicationApi.assignUserToApplication({\n    appId: appId,\n    appUser: {\n      id: userId\n    }\n  });\n\n  console.log('User assigned to application:', appUser.id);\n  return appUser;\n}\n```\n\n### Assign User with Profile to Application\n\n```javascript\nasync function assignUserWithProfile(appId, userId) {\n  const appUser = await client.applicationApi.assignUserToApplication({\n    appId: appId,\n    appUser: {\n      id: userId,\n      credentials: {\n        userName: 'user@example.com',\n        password: { value: 'AppSpecificPassword123!' }\n      },\n      profile: {\n        role: 'Admin',\n        department: 'Engineering'\n      }\n    }\n  });\n\n  console.log('User assigned with profile');\n  return appUser;\n}\n```\n\n### Remove User from Application\n\n```javascript\nasync function removeUserFromApplication(appId, userId) {\n  await client.applicationApi.unassignUserFromApplication({\n    appId: appId,\n    userId: userId\n  });\n\n  console.log('User removed from application');\n}\n```\n\n### Assign Group to Application\n\n```javascript\nasync function assignGroupToApplication(appId, groupId) {\n  const assignment = await client.applicationApi.assignGroupToApplication({\n    appId: appId,\n    groupId: groupId,\n    applicationGroupAssignment: {}\n  });\n\n  console.log('Group assigned to application');\n  return assignment;\n}\n```\n\n### Remove Group from Application\n\n```javascript\nasync function removeGroupFromApplication(appId, groupId) {\n  await client.applicationApi.unassignApplicationFromGroup({\n    appId: appId,\n    groupId: groupId\n  });\n\n  console.log('Group removed from application');\n}\n```\n\n### List Application Users\n\nGet all users assigned to an application:\n\n```javascript\nasync function listApplicationUsers(appId) {\n  const collection = await client.applicationApi.listApplicationUsers({\n    appId: appId\n  });\n\n  for await (let appUser of collection) {\n    console.log(`User ${appUser.id} assigned to app`);\n  }\n}\n```\n\n### List Application Groups\n\nGet all groups assigned to an application:\n\n```javascript\nasync function listApplicationGroups(appId) {\n  const collection = await client.applicationApi.listApplicationGroupAssignments({\n    appId: appId\n  });\n\n  for await (let assignment of collection) {\n    console.log(`Group ${assignment.id} assigned to app`);\n  }\n}\n```\n\n## Authentication and Sessions\n\n### List Active User Sessions\n\n```javascript\nasync function listUserSessions(userId) {\n  const collection = await client.userApi.listUserSessions({ userId });\n\n  for await (let session of collection) {\n    console.log(`Session ID: ${session.id}, Created: ${session.createdAt}`);\n  }\n}\n```\n\n### Clear User Sessions\n\nClear all sessions for a user:\n\n```javascript\nasync function clearUserSessions(userId) {\n  await client.userApi.clearUserSessions({ userId });\n  console.log('All user sessions cleared');\n}\n```\n\n## Error Handling\n\nAlways wrap API calls in try-catch blocks:\n\n```javascript\nasync function handleErrors() {\n  try {\n    const user = await client.userApi.getUser({\n      userId: 'nonexistent@example.com'\n    });\n  } catch (error) {\n    if (error.status === 404) {\n      console.error('User not found');\n    } else if (error.status === 401) {\n      console.error('Authentication failed - check your API token');\n    } else if (error.status === 403) {\n      console.error('Forbidden - insufficient permissions');\n    } else if (error.status === 429) {\n      console.error('Rate limit exceeded');\n    } else {\n      console.error('API Error:', error.message);\n    }\n  }\n}\n```\n\n### Comprehensive Error Handling Pattern\n\n```javascript\nasync function createUserWithErrorHandling(userData) {\n  try {\n    const newUser = {\n      profile: {\n        firstName: userData.firstName,\n        lastName: userData.lastName,\n        email: userData.email,\n        login: userData.email\n      },\n      credentials: {\n        password: {\n          value: userData.password\n        }\n      }\n    };\n\n    const user = await client.userApi.createUser({ body: newUser });\n    console.log('User created successfully:', user.id);\n    return { success: true, user };\n\n  } catch (error) {\n    console.error('Error creating user:', error.message);\n\n    if (error.status === 400) {\n      console.error('Bad request - check user data format');\n      if (error.body && error.body.errorCauses) {\n        error.body.errorCauses.forEach(cause => {\n          console.error('Error cause:', cause.errorSummary);\n        });\n      }\n    } else if (error.status === 401) {\n      console.error('Authentication failed');\n    } else if (error.status === 403) {\n      console.error('Forbidden - insufficient permissions');\n    } else if (error.status === 409) {\n      console.error('Conflict - user already exists');\n    } else if (error.status === 429) {\n      console.error('Rate limit exceeded - retry after delay');\n    } else if (error.status >= 500) {\n      console.error('Server error - Okta service issue');\n    }\n\n    return { success: false, error: error.message };\n  }\n}\n```\n\n## Pagination\n\nCollections automatically handle pagination. Use `limit` to control page size:\n\n```javascript\nasync function paginateUsers() {\n  const collection = await client.userApi.listUsers({\n    limit: 20 // 20 users per page\n  });\n\n  for await (let user of collection) {\n    // SDK automatically fetches next pages\n    console.log(user.profile.email);\n  }\n}\n```\n\n### Manual Pagination with After Parameter\n\n```javascript\nasync function manualPagination() {\n  let after;\n  let pageCount = 0;\n\n  do {\n    const response = await client.userApi.listUsers({\n      limit: 10,\n      after: after\n    });\n\n    const users = response.users || [];\n    console.log(`Page ${++pageCount}: ${users.length} users`);\n\n    users.forEach(user => {\n      console.log('  -', user.profile.email);\n    });\n\n    // Check if there's a next page\n    after = response.nextPage ? response.nextPage.after : null;\n\n  } while (after);\n}\n```\n\n## Rate Limiting\n\nThe SDK automatically handles rate limiting with retry logic. Be aware of Okta rate limits:\n\n- Most endpoints: 600 requests per minute\n- Authentication endpoints: Varies by org tier\n- Concurrent requests: Limited per org\n\n```javascript\nasync function bulkOperationWithRateLimit() {\n  const users = []; // Large array of users to create\n\n  for (const userData of users) {\n    try {\n      const user = await client.userApi.createUser({ body: userData });\n      console.log('Created user:', user.id);\n\n      // Optional: Add delay between requests\n      await new Promise(resolve => setTimeout(resolve, 100));\n\n    } catch (error) {\n      if (error.status === 429) {\n        console.log('Rate limit hit, waiting before retry...');\n        await new Promise(resolve => setTimeout(resolve, 5000));\n        // Retry logic here\n      }\n    }\n  }\n}\n```\n\n## Working with Custom User Attributes\n\n### Create User with Custom Attributes\n\n```javascript\nasync function createUserWithCustomAttributes() {\n  const newUser = {\n    profile: {\n      firstName: 'John',\n      lastName: 'Doe',\n      email: 'john.doe@example.com',\n      login: 'john.doe@example.com',\n      // Custom attributes (must be defined in user schema first)\n      employeeId: 'EMP-12345',\n      department: 'Engineering',\n      costCenter: 'CC-100'\n    },\n    credentials: {\n      password: {\n        value: 'SecurePassword123!'\n      }\n    }\n  };\n\n  const user = await client.userApi.createUser({ body: newUser });\n  console.log('Created user with custom attributes:', user.id);\n}\n```\n\n## Complete Example Application\n\n```javascript\nconst okta = require('@okta/okta-sdk-nodejs');\n\n// Initialize client\nconst client = new okta.Client({\n  orgUrl: process.env.OKTA_ORG_URL,\n  token: process.env.OKTA_API_TOKEN\n});\n\nasync function main() {\n  try {\n    // Create a user\n    const newUser = {\n      profile: {\n        firstName: 'Alice',\n        lastName: 'Johnson',\n        email: 'alice.johnson@example.com',\n        login: 'alice.johnson@example.com'\n      },\n      credentials: {\n        password: { value: 'SecurePassword123!' }\n      }\n    };\n\n    const user = await client.userApi.createUser({\n      body: newUser,\n      activate: true\n    });\n    console.log('Created user:', user.id);\n\n    // Create a group\n    const newGroup = {\n      profile: {\n        name: 'Project Team Alpha',\n        description: 'Members of Project Alpha'\n      }\n    };\n\n    const group = await client.groupApi.createGroup({ group: newGroup });\n    console.log('Created group:', group.id);\n\n    // Add user to group\n    await client.groupApi.assignUserToGroup({\n      groupId: group.id,\n      userId: user.id\n    });\n    console.log('User added to group');\n\n    // Create an application\n    const application = {\n      name: 'template_basic_auth',\n      label: 'Team Application',\n      signOnMode: 'BASIC_AUTH',\n      settings: {\n        app: {\n          url: 'https://example.com/app',\n          authURL: 'https://example.com/login'\n        }\n      }\n    };\n\n    const app = await client.applicationApi.createApplication({\n      application: application\n    });\n    console.log('Created application:', app.id);\n\n    // Assign group to application\n    await client.applicationApi.assignGroupToApplication({\n      appId: app.id,\n      groupId: group.id,\n      applicationGroupAssignment: {}\n    });\n    console.log('Group assigned to application');\n\n    // List all users in the group\n    console.log('\\nGroup members:');\n    const members = await client.groupApi.listGroupUsers({ groupId: group.id });\n    for await (let member of members) {\n      console.log(`  - ${member.profile.firstName} ${member.profile.lastName}`);\n    }\n\n  } catch (error) {\n    console.error('Error:', error.message);\n    if (error.status) {\n      console.error('Status:', error.status);\n    }\n  }\n}\n\nmain();\n```\n\n## Environment Variables Setup\n\nCreate a `.env` file for configuration:\n\n```bash\nOKTA_ORG_URL=https://dev-1234567.okta.com\nOKTA_API_TOKEN=your_api_token_here\n```\n\nLoad environment variables:\n\n```javascript\nrequire('dotenv').config();\n\nconst okta = require('@okta/okta-sdk-nodejs');\n\nconst client = new okta.Client({\n  orgUrl: process.env.OKTA_ORG_URL,\n  token: process.env.OKTA_API_TOKEN\n});\n```\n\n## OAuth 2.0 Private Key Configuration\n\nFor OAuth 2.0 authentication, use environment variables:\n\n```bash\nOKTA_ORG_URL=https://dev-1234567.okta.com\nOKTA_CLIENT_ID=your_client_id\nOKTA_PRIVATE_KEY='{\"kty\":\"RSA\",\"kid\":\"key-id\",\"n\":\"...\",\"e\":\"AQAB\",\"d\":\"...\"}'\nOKTA_KEY_ID=key-id\nOKTA_SCOPES=okta.users.manage,okta.groups.manage,okta.apps.manage\n```\n\n```javascript\nrequire('dotenv').config();\nconst okta = require('@okta/okta-sdk-nodejs');\n\nconst client = new okta.Client({\n  orgUrl: process.env.OKTA_ORG_URL,\n  authorizationMode: 'PrivateKey',\n  clientId: process.env.OKTA_CLIENT_ID,\n  scopes: process.env.OKTA_SCOPES.split(','),\n  privateKey: process.env.OKTA_PRIVATE_KEY,\n  keyId: process.env.OKTA_KEY_ID\n});\n```\n\n## Useful Links\n\n- Official Documentation: https://developer.okta.com/\n- API Reference: https://developer.okta.com/docs/reference/\n- Users API: https://developer.okta.com/docs/reference/api/users/\n- Groups API: https://developer.okta.com/docs/reference/api/groups/\n- Applications API: https://developer.okta.com/docs/reference/api/apps/\n- GitHub Repository: https://github.com/okta/okta-sdk-nodejs\n- NPM Package: https://www.npmjs.com/package/@okta/okta-sdk-nodejs\n"
  },
  {
    "path": "content/okta/docs/identity/python/DOC.md",
    "content": "---\nname: identity\ndescription: \"Okta Python SDK coding guidelines for the Okta Management API using official libraries\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.13\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"okta,identity,sso,oauth,authentication\"\n---\n\n# Okta Python SDK Coding Guidelines\n\nYou are an Okta API coding expert. Help me with writing code using the Okta Management API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://developer.okta.com/docs/reference/api/users/\nhttps://github.com/okta/okta-sdk-python\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Okta Python SDK to interact with the Okta Management API. This is the standard library for all Okta Management API interactions. Do not construct manual HTTP requests or use unofficial libraries.\n\n- **Library Name:** Okta Python SDK\n- **PyPI Package:** `okta`\n- **Current Version:** 2.9.13\n- **Important:** This SDK is for the Management API only. For Authentication API, construct your own HTTP requests.\n\n**Installation:**\n\n- **Correct:** `pip install okta`\n\n**APIs and Usage:**\n\n- **Correct:** `from okta.client import Client as OktaClient`\n- **Correct:** `client = OktaClient(config)`\n- **Correct:** `await client.create_user(user_request)`\n- **Correct:** `users, resp, err = await client.list_users()`\n- **Incorrect:** Manual HTTP requests to Management API endpoints\n- **Incorrect:** Using unofficial Okta Python packages\n\n## System Requirements\n\nThe Okta Python SDK requires:\n- Python 3.9 or higher\n- An Okta organization URL\n- An API token or OAuth 2.0 credentials\n\n## Initialization and API Authentication\n\nThe Okta Python SDK uses asynchronous operations with `async`/`await` syntax throughout.\n\n### API Token Authentication (Simple)\n\n```python\nfrom okta.client import Client as OktaClient\nimport asyncio\nimport os\n\nconfig = {\n    'orgUrl': os.getenv('OKTA_ORG_URL'),\n    'token': os.getenv('OKTA_API_TOKEN')\n}\n\nclient = OktaClient(config)\n```\n\n### OAuth 2.0 Private Key Authentication (Recommended for Service Apps)\n\nWhen using OAuth 2.0 with private key authentication, you don't need an API token. The SDK automatically requests access tokens.\n\n```python\nfrom okta.client import Client as OktaClient\nimport os\n\nconfig = {\n    'orgUrl': os.getenv('OKTA_ORG_URL'),\n    'authorizationMode': 'PrivateKey',\n    'clientId': os.getenv('OKTA_CLIENT_ID'),\n    'scopes': ['okta.users.manage', 'okta.groups.manage'],\n    'privateKey': os.getenv('OKTA_PRIVATE_KEY'),  # JWK JSON string or PEM format\n    'kid': os.getenv('OKTA_KEY_ID')  # Optional if kid is in JWK\n}\n\nclient = OktaClient(config)\n```\n\n### Async Event Loop Pattern\n\nAll SDK operations are asynchronous and must be executed within an event loop:\n\n```python\nimport asyncio\nfrom okta.client import Client as OktaClient\n\nasync def main():\n    config = {\n        'orgUrl': 'https://dev-1234567.okta.com',\n        'token': 'your_api_token'\n    }\n    client = OktaClient(config)\n\n    users, resp, err = await client.list_users()\n    print(f\"Total users: {len(users)}\")\n\n# Run the async function\nloop = asyncio.get_event_loop()\nloop.run_until_complete(main())\n```\n\n### Response Pattern\n\nAll SDK methods return a tuple of `(result, response, error)`:\n\n```python\nusers, resp, err = await client.list_users()\n\nif err:\n    print(f\"Error occurred: {err}\")\nelse:\n    print(f\"Retrieved {len(users)} users\")\n```\n\n## User Management\n\n### Create a User\n\nCreate a new user with profile information and password:\n\n```python\nfrom okta.client import Client as OktaClient\nfrom okta.models import UserProfile, PasswordCredential, UserCredentials, CreateUserRequest\nimport asyncio\n\nasync def create_user():\n    config = {\n        'orgUrl': 'https://dev-1234567.okta.com',\n        'token': 'your_api_token'\n    }\n    client = OktaClient(config)\n\n    # Create user profile\n    user_profile = UserProfile({\n        'firstName': 'John',\n        'lastName': 'Doe',\n        'email': 'john.doe@example.com',\n        'login': 'john.doe@example.com'\n    })\n\n    # Create password credential\n    password_credential = PasswordCredential({\n        'value': 'SecurePassword123!'\n    })\n\n    user_credentials = UserCredentials({\n        'password': password_credential\n    })\n\n    # Create user request\n    create_user_request = CreateUserRequest({\n        'profile': user_profile,\n        'credentials': user_credentials\n    })\n\n    # Create the user\n    user, resp, err = await client.create_user(create_user_request)\n\n    if err:\n        print(f\"Error creating user: {err}\")\n    else:\n        print(f\"Created user: {user.id}\")\n        return user\n\nasyncio.run(create_user())\n```\n\n### Create User with Activation\n\nCreate and automatically activate a user:\n\n```python\nasync def create_and_activate_user():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user_profile = UserProfile({\n        'firstName': 'Jane',\n        'lastName': 'Smith',\n        'email': 'jane.smith@example.com',\n        'login': 'jane.smith@example.com',\n        'mobilePhone': '555-123-4567'\n    })\n\n    password_credential = PasswordCredential({'value': 'SecurePassword123!'})\n    user_credentials = UserCredentials({'password': password_credential})\n\n    create_user_request = CreateUserRequest({\n        'profile': user_profile,\n        'credentials': user_credentials\n    })\n\n    # Activate on creation\n    user, resp, err = await client.create_user(\n        create_user_request,\n        activate=True,\n        provider=False\n    )\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"Created and activated user: {user.id}\")\n        return user\n\nasyncio.run(create_and_activate_user())\n```\n\n### Get a User\n\nRetrieve a user by ID or login:\n\n```python\nasync def get_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # By user ID or login email\n    user, resp, err = await client.get_user(user_id)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"User: {user.profile.first_name} {user.profile.last_name}\")\n        print(f\"Email: {user.profile.email}\")\n        print(f\"Status: {user.status}\")\n        return user\n\n# Can use ID or email\nasyncio.run(get_user('00u1234567890abcdef'))\nasyncio.run(get_user('john.doe@example.com'))\n```\n\n### List All Users\n\nRetrieve all users in your organization:\n\n```python\nasync def list_all_users():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    users, resp, err = await client.list_users()\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"Total users: {len(users)}\")\n        for user in users:\n            print(f\"  - {user.profile.first_name} {user.profile.last_name} ({user.profile.email})\")\n        return users\n\nasyncio.run(list_all_users())\n```\n\n### List Users with Query Parameters\n\nFilter users with query parameters:\n\n```python\nasync def list_users_with_filters():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Search by query string\n    query_params = {'q': 'Robert'}\n    users, resp, err = await client.list_users(query_params)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"Found {len(users)} users matching 'Robert'\")\n        for user in users:\n            print(f\"  - {user.profile.email}\")\n\nasyncio.run(list_users_with_filters())\n```\n\n### Search Users with SCIM Filter\n\nUse SCIM expressions for precise filtering:\n\n```python\nasync def search_users_scim():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # SCIM filter\n    query_params = {\n        'search': 'profile.nickName eq \"bobby\"'\n    }\n    users, resp, err = await client.list_users(query_params)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        for user in users:\n            print(f\"Found: {user.profile.email}\")\n\nasyncio.run(search_users_scim())\n```\n\n### Filter Users by Time\n\nFind users updated after a specific time:\n\n```python\nasync def find_recently_updated_users():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    query_params = {\n        'filter': 'lastUpdated gt \"2025-01-01T00:00:00.000Z\"'\n    }\n    users, resp, err = await client.list_users(query_params)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"Found {len(users)} recently updated users\")\n        for user in users:\n            print(f\"  - {user.profile.email} (updated: {user.last_updated})\")\n\nasyncio.run(find_recently_updated_users())\n```\n\n### Update a User\n\nModify user profile information:\n\n```python\nasync def update_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Get the user first\n    user, resp, err = await client.get_user(user_id)\n\n    if err:\n        print(f\"Error getting user: {err}\")\n        return\n\n    # Update profile fields\n    user.profile.nick_name = 'Johnny'\n    user.profile.mobile_phone = '+1-555-123-4567'\n    user.profile.department = 'Engineering'\n\n    # Save changes\n    updated_user, resp, err = await client.update_user(user_id, user)\n\n    if err:\n        print(f\"Error updating user: {err}\")\n    else:\n        print(f\"User updated successfully: {updated_user.id}\")\n\nasyncio.run(update_user('00u1234567890abcdef'))\n```\n\n### Partial Update a User\n\nUpdate specific fields without retrieving the full user object:\n\n```python\nfrom okta.models import User\n\nasync def partial_update_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Create a user object with only the fields to update\n    user = User({\n        'profile': {\n            'nickName': 'JD',\n            'department': 'Engineering'\n        }\n    })\n\n    updated_user, resp, err = await client.update_user(user_id, user)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"User partially updated: {updated_user.id}\")\n\nasyncio.run(partial_update_user('00u1234567890abcdef'))\n```\n\n### Deactivate a User\n\nDeactivate a user account:\n\n```python\nasync def deactivate_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user, resp, err = await client.deactivate_user(user_id)\n\n    if err:\n        print(f\"Error deactivating user: {err}\")\n    else:\n        print(f\"User deactivated: {user.id}\")\n\nasyncio.run(deactivate_user('00u1234567890abcdef'))\n```\n\n### Delete a User\n\nPermanently delete a user (must be deactivated first):\n\n```python\nasync def delete_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # First deactivate\n    _, resp, err = await client.deactivate_user(user_id)\n    if err:\n        print(f\"Error deactivating: {err}\")\n        return\n\n    # Then delete\n    resp, err = await client.delete_user(user_id)\n\n    if err:\n        print(f\"Error deleting user: {err}\")\n    else:\n        print(f\"User deleted permanently\")\n\nasyncio.run(delete_user('00u1234567890abcdef'))\n```\n\n### Reactivate a User\n\nReactivate a previously deactivated user:\n\n```python\nasync def reactivate_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    query_params = {'sendEmail': False}\n    user, resp, err = await client.activate_user(user_id, query_params)\n\n    if err:\n        print(f\"Error reactivating user: {err}\")\n    else:\n        print(f\"User reactivated: {user.id}\")\n\nasyncio.run(reactivate_user('00u1234567890abcdef'))\n```\n\n### Suspend and Unsuspend User\n\nTemporarily suspend a user:\n\n```python\nasync def suspend_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user, resp, err = await client.suspend_user(user_id)\n\n    if err:\n        print(f\"Error suspending user: {err}\")\n    else:\n        print(f\"User suspended: {user.id}\")\n\nasync def unsuspend_user(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user, resp, err = await client.unsuspend_user(user_id)\n\n    if err:\n        print(f\"Error unsuspending user: {err}\")\n    else:\n        print(f\"User unsuspended: {user.id}\")\n\nasyncio.run(suspend_user('00u1234567890abcdef'))\nasyncio.run(unsuspend_user('00u1234567890abcdef'))\n```\n\n### Reset User Password\n\nSend a password reset email:\n\n```python\nasync def reset_user_password(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    query_params = {'sendEmail': True}\n    reset_token, resp, err = await client.reset_password(user_id, query_params)\n\n    if err:\n        print(f\"Error resetting password: {err}\")\n    else:\n        print(f\"Password reset email sent\")\n\nasyncio.run(reset_user_password('00u1234567890abcdef'))\n```\n\n### Expire User Password\n\nForce a user to change password on next login:\n\n```python\nasync def expire_user_password(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user, resp, err = await client.expire_password(user_id)\n\n    if err:\n        print(f\"Error expiring password: {err}\")\n    else:\n        print(f\"Password expired for user: {user.id}\")\n\nasyncio.run(expire_user_password('00u1234567890abcdef'))\n```\n\n## Group Management\n\n### Create a Group\n\nCreate a new group:\n\n```python\nfrom okta.models import Group, GroupProfile\n\nasync def create_group():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    group_profile = GroupProfile({\n        'name': 'Engineering Team',\n        'description': 'All engineering department members'\n    })\n\n    new_group = Group({'profile': group_profile})\n\n    group, resp, err = await client.create_group(new_group)\n\n    if err:\n        print(f\"Error creating group: {err}\")\n    else:\n        print(f\"Created group: {group.id}\")\n        return group\n\nasyncio.run(create_group())\n```\n\n### Get a Group\n\nRetrieve a group by ID:\n\n```python\nasync def get_group(group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    group, resp, err = await client.get_group(group_id)\n\n    if err:\n        print(f\"Error getting group: {err}\")\n    else:\n        print(f\"Group: {group.profile.name}\")\n        print(f\"Description: {group.profile.description}\")\n        return group\n\nasyncio.run(get_group('00g1234567890abcdef'))\n```\n\n### List All Groups\n\nList all groups in the organization:\n\n```python\nasync def list_all_groups():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    groups, resp, err = await client.list_groups()\n\n    if err:\n        print(f\"Error listing groups: {err}\")\n    else:\n        print(f\"Total groups: {len(groups)}\")\n        for group in groups:\n            print(f\"  - {group.profile.name} ({group.id})\")\n        return groups\n\nasyncio.run(list_all_groups())\n```\n\n### Search Groups by Name\n\nSearch for groups matching a query:\n\n```python\nasync def search_groups(query):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    query_params = {'q': query}\n    groups, resp, err = await client.list_groups(query_params)\n\n    if err:\n        print(f\"Error searching groups: {err}\")\n    else:\n        print(f\"Found {len(groups)} groups matching '{query}'\")\n        for group in groups:\n            print(f\"  - {group.profile.name}\")\n\nasyncio.run(search_groups('Engineering'))\n```\n\n### Update a Group\n\nUpdate group profile information:\n\n```python\nasync def update_group(group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Get the group first\n    group, resp, err = await client.get_group(group_id)\n\n    if err:\n        print(f\"Error getting group: {err}\")\n        return\n\n    # Update profile\n    group.profile.description = 'Updated description for the team'\n\n    # Save changes\n    updated_group, resp, err = await client.update_group(group_id, group)\n\n    if err:\n        print(f\"Error updating group: {err}\")\n    else:\n        print(f\"Group updated: {updated_group.id}\")\n\nasyncio.run(update_group('00g1234567890abcdef'))\n```\n\n### Delete a Group\n\nDelete a group:\n\n```python\nasync def delete_group(group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    resp, err = await client.delete_group(group_id)\n\n    if err:\n        print(f\"Error deleting group: {err}\")\n    else:\n        print(f\"Group deleted successfully\")\n\nasyncio.run(delete_group('00g1234567890abcdef'))\n```\n\n### Assign User to Group\n\nAdd a user to a group:\n\n```python\nasync def assign_user_to_group(group_id, user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    resp, err = await client.add_user_to_group(group_id, user_id)\n\n    if err:\n        print(f\"Error adding user to group: {err}\")\n    else:\n        print(f\"User {user_id} added to group {group_id}\")\n\nasyncio.run(assign_user_to_group('00g1234567890abcdef', '00u1234567890abcdef'))\n```\n\n### Remove User from Group\n\nRemove a user from a group:\n\n```python\nasync def remove_user_from_group(group_id, user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    resp, err = await client.remove_user_from_group(group_id, user_id)\n\n    if err:\n        print(f\"Error removing user from group: {err}\")\n    else:\n        print(f\"User {user_id} removed from group {group_id}\")\n\nasyncio.run(remove_user_from_group('00g1234567890abcdef', '00u1234567890abcdef'))\n```\n\n### List Group Members\n\nGet all users in a group:\n\n```python\nasync def list_group_members(group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    users, resp, err = await client.list_group_users(group_id)\n\n    if err:\n        print(f\"Error listing group members: {err}\")\n    else:\n        print(f\"Group has {len(users)} members:\")\n        for user in users:\n            print(f\"  - {user.profile.first_name} {user.profile.last_name}\")\n\nasyncio.run(list_group_members('00g1234567890abcdef'))\n```\n\n### List User's Groups\n\nGet all groups a user belongs to:\n\n```python\nasync def list_user_groups(user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    groups, resp, err = await client.list_user_groups(user_id)\n\n    if err:\n        print(f\"Error listing user groups: {err}\")\n    else:\n        print(f\"User belongs to {len(groups)} groups:\")\n        for group in groups:\n            print(f\"  - {group.profile.name}\")\n\nasyncio.run(list_user_groups('00u1234567890abcdef'))\n```\n\n## Application Management\n\n### Create an Application\n\nCreate a basic authentication application:\n\n```python\nfrom okta.models import Application\n\nasync def create_application():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    application = Application({\n        'name': 'template_basic_auth',\n        'label': 'Sample Basic Auth App',\n        'signOnMode': 'BASIC_AUTH',\n        'settings': {\n            'app': {\n                'url': 'https://example.com/auth.htm',\n                'authURL': 'https://example.com/login.html'\n            }\n        }\n    })\n\n    app, resp, err = await client.create_application(application)\n\n    if err:\n        print(f\"Error creating application: {err}\")\n    else:\n        print(f\"Created application: {app.id}\")\n        return app\n\nasyncio.run(create_application())\n```\n\n### Create an OAuth 2.0 Application\n\n```python\nasync def create_oauth_application():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    application = Application({\n        'name': 'oidc_client',\n        'label': 'OAuth 2.0 App',\n        'signOnMode': 'OPENID_CONNECT',\n        'credentials': {\n            'oauthClient': {\n                'token_endpoint_auth_method': 'client_secret_post'\n            }\n        },\n        'settings': {\n            'oauthClient': {\n                'client_uri': 'https://example.com',\n                'logo_uri': 'https://example.com/logo.png',\n                'redirect_uris': ['https://example.com/oauth/callback'],\n                'response_types': ['code'],\n                'grant_types': ['authorization_code', 'refresh_token'],\n                'application_type': 'web'\n            }\n        }\n    })\n\n    app, resp, err = await client.create_application(application)\n\n    if err:\n        print(f\"Error creating OAuth app: {err}\")\n    else:\n        print(f\"Created OAuth app: {app.id}\")\n        if hasattr(app.credentials, 'oauthClient'):\n            print(f\"Client ID: {app.credentials.oauthClient.client_id}\")\n            print(f\"Client Secret: {app.credentials.oauthClient.client_secret}\")\n        return app\n\nasyncio.run(create_oauth_application())\n```\n\n### Get an Application\n\nRetrieve an application by ID:\n\n```python\nasync def get_application(app_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    app, resp, err = await client.get_application(app_id)\n\n    if err:\n        print(f\"Error getting application: {err}\")\n    else:\n        print(f\"Application: {app.label}\")\n        print(f\"Sign-on mode: {app.sign_on_mode}\")\n        return app\n\nasyncio.run(get_application('0oa1234567890abcdef'))\n```\n\n### List All Applications\n\n```python\nasync def list_all_applications():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    apps, resp, err = await client.list_applications()\n\n    if err:\n        print(f\"Error listing applications: {err}\")\n    else:\n        print(f\"Total applications: {len(apps)}\")\n        for app in apps:\n            print(f\"  - {app.label} ({app.id})\")\n        return apps\n\nasyncio.run(list_all_applications())\n```\n\n### Update an Application\n\n```python\nasync def update_application(app_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Get the application first\n    app, resp, err = await client.get_application(app_id)\n\n    if err:\n        print(f\"Error getting application: {err}\")\n        return\n\n    # Update label\n    app.label = 'Updated Application Name'\n\n    # Save changes\n    updated_app, resp, err = await client.update_application(app_id, app)\n\n    if err:\n        print(f\"Error updating application: {err}\")\n    else:\n        print(f\"Application updated: {updated_app.id}\")\n\nasyncio.run(update_application('0oa1234567890abcdef'))\n```\n\n### Delete an Application\n\n```python\nasync def delete_application(app_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # First deactivate\n    resp, err = await client.deactivate_application(app_id)\n    if err:\n        print(f\"Error deactivating application: {err}\")\n        return\n\n    # Then delete\n    resp, err = await client.delete_application(app_id)\n\n    if err:\n        print(f\"Error deleting application: {err}\")\n    else:\n        print(f\"Application deleted successfully\")\n\nasyncio.run(delete_application('0oa1234567890abcdef'))\n```\n\n### Assign User to Application\n\n```python\nfrom okta.models import AppUser\n\nasync def assign_user_to_application(app_id, user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    app_user = AppUser({'id': user_id})\n\n    assigned_user, resp, err = await client.assign_user_to_application(app_id, app_user)\n\n    if err:\n        print(f\"Error assigning user to application: {err}\")\n    else:\n        print(f\"User {user_id} assigned to application {app_id}\")\n        return assigned_user\n\nasyncio.run(assign_user_to_application('0oa1234567890abcdef', '00u1234567890abcdef'))\n```\n\n### Assign User with Credentials to Application\n\n```python\nasync def assign_user_with_credentials(app_id, user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    app_user = AppUser({\n        'id': user_id,\n        'credentials': {\n            'userName': 'user@example.com',\n            'password': {'value': 'AppSpecificPassword123!'}\n        },\n        'profile': {\n            'role': 'Admin',\n            'department': 'Engineering'\n        }\n    })\n\n    assigned_user, resp, err = await client.assign_user_to_application(app_id, app_user)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"User assigned with credentials\")\n\nasyncio.run(assign_user_with_credentials('0oa1234567890abcdef', '00u1234567890abcdef'))\n```\n\n### Remove User from Application\n\n```python\nasync def remove_user_from_application(app_id, user_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    resp, err = await client.delete_application_user(app_id, user_id)\n\n    if err:\n        print(f\"Error removing user from application: {err}\")\n    else:\n        print(f\"User {user_id} removed from application {app_id}\")\n\nasyncio.run(remove_user_from_application('0oa1234567890abcdef', '00u1234567890abcdef'))\n```\n\n### Assign Group to Application\n\n```python\nfrom okta.models import ApplicationGroupAssignment\n\nasync def assign_group_to_application(app_id, group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    assignment = ApplicationGroupAssignment({'priority': 0})\n\n    result, resp, err = await client.create_application_group_assignment(\n        app_id,\n        group_id,\n        assignment\n    )\n\n    if err:\n        print(f\"Error assigning group to application: {err}\")\n    else:\n        print(f\"Group {group_id} assigned to application {app_id}\")\n        return result\n\nasyncio.run(assign_group_to_application('0oa1234567890abcdef', '00g1234567890abcdef'))\n```\n\n### Remove Group from Application\n\n```python\nasync def remove_group_from_application(app_id, group_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    resp, err = await client.delete_application_group_assignment(app_id, group_id)\n\n    if err:\n        print(f\"Error removing group from application: {err}\")\n    else:\n        print(f\"Group {group_id} removed from application {app_id}\")\n\nasyncio.run(remove_group_from_application('0oa1234567890abcdef', '00g1234567890abcdef'))\n```\n\n### List Application Users\n\nGet all users assigned to an application:\n\n```python\nasync def list_application_users(app_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    app_users, resp, err = await client.list_application_users(app_id)\n\n    if err:\n        print(f\"Error listing application users: {err}\")\n    else:\n        print(f\"Application has {len(app_users)} users:\")\n        for app_user in app_users:\n            print(f\"  - User ID: {app_user.id}\")\n\nasyncio.run(list_application_users('0oa1234567890abcdef'))\n```\n\n### List Application Groups\n\nGet all groups assigned to an application:\n\n```python\nasync def list_application_groups(app_id):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    groups, resp, err = await client.list_application_group_assignments(app_id)\n\n    if err:\n        print(f\"Error listing application groups: {err}\")\n    else:\n        print(f\"Application has {len(groups)} groups assigned:\")\n        for group in groups:\n            print(f\"  - Group ID: {group.id}\")\n\nasyncio.run(list_application_groups('0oa1234567890abcdef'))\n```\n\n## Custom Headers Management\n\nSet custom headers sent with every request (requires SDK v1.3.0+):\n\n```python\nasync def use_custom_headers():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Set custom headers\n    client.set_custom_headers({'Custom-Header': 'custom value', 'X-Request-ID': '12345'})\n\n    # Make API calls with custom headers\n    users, resp, err = await client.list_users()\n\n    # Get current custom headers\n    headers = client.get_custom_headers()\n    print(f\"Custom headers: {headers}\")\n\n    # Clear custom headers\n    client.clear_custom_headers()\n    print(f\"Headers after clear: {client.get_custom_headers()}\")\n\nasyncio.run(use_custom_headers())\n```\n\n## Error Handling\n\nAlways check the error return value:\n\n```python\nasync def handle_errors():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    user, resp, err = await client.get_user('nonexistent@example.com')\n\n    if err:\n        print(f\"Error occurred: {err}\")\n        if hasattr(err, 'status'):\n            if err.status == 404:\n                print(\"User not found\")\n            elif err.status == 401:\n                print(\"Authentication failed - check your API token\")\n            elif err.status == 403:\n                print(\"Forbidden - insufficient permissions\")\n            elif err.status == 429:\n                print(\"Rate limit exceeded\")\n    else:\n        print(f\"User found: {user.profile.email}\")\n\nasyncio.run(handle_errors())\n```\n\n### Comprehensive Error Handling Pattern\n\n```python\nasync def create_user_with_error_handling(user_data):\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    try:\n        user_profile = UserProfile(user_data['profile'])\n        password_credential = PasswordCredential({'value': user_data['password']})\n        user_credentials = UserCredentials({'password': password_credential})\n\n        create_user_request = CreateUserRequest({\n            'profile': user_profile,\n            'credentials': user_credentials\n        })\n\n        user, resp, err = await client.create_user(create_user_request)\n\n        if err:\n            print(f\"Error creating user: {err}\")\n\n            if hasattr(err, 'status'):\n                if err.status == 400:\n                    print(\"Bad request - check user data format\")\n                elif err.status == 401:\n                    print(\"Authentication failed\")\n                elif err.status == 403:\n                    print(\"Forbidden - insufficient permissions\")\n                elif err.status == 409:\n                    print(\"Conflict - user already exists\")\n                elif err.status == 429:\n                    print(\"Rate limit exceeded - retry after delay\")\n                elif err.status >= 500:\n                    print(\"Server error - Okta service issue\")\n\n            return {'success': False, 'error': str(err)}\n        else:\n            print(f\"User created successfully: {user.id}\")\n            return {'success': True, 'user': user}\n\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n        return {'success': False, 'error': str(e)}\n\nuser_data = {\n    'profile': {\n        'firstName': 'Alice',\n        'lastName': 'Johnson',\n        'email': 'alice.johnson@example.com',\n        'login': 'alice.johnson@example.com'\n    },\n    'password': 'SecurePassword123!'\n}\n\nasyncio.run(create_user_with_error_handling(user_data))\n```\n\n## Pagination\n\nHandle pagination for large result sets:\n\n```python\nasync def paginate_users():\n    config = {'orgUrl': 'https://dev-1234567.okta.com', 'token': 'your_api_token'}\n    client = OktaClient(config)\n\n    # Limit results per page\n    query_params = {'limit': 20}\n\n    users, resp, err = await client.list_users(query_params)\n\n    if err:\n        print(f\"Error: {err}\")\n    else:\n        print(f\"Retrieved {len(users)} users\")\n\n        # Check if there are more pages\n        if hasattr(resp, 'has_next') and resp.has_next():\n            print(\"More pages available\")\n\nasyncio.run(paginate_users())\n```\n\n## Complete Example Application\n\n```python\nimport asyncio\nimport os\nfrom okta.client import Client as OktaClient\nfrom okta.models import (\n    UserProfile, PasswordCredential, UserCredentials, CreateUserRequest,\n    Group, GroupProfile, Application\n)\n\nasync def main():\n    # Initialize client\n    config = {\n        'orgUrl': os.getenv('OKTA_ORG_URL'),\n        'token': os.getenv('OKTA_API_TOKEN')\n    }\n    client = OktaClient(config)\n\n    try:\n        # Create a user\n        print(\"Creating user...\")\n        user_profile = UserProfile({\n            'firstName': 'Alice',\n            'lastName': 'Johnson',\n            'email': 'alice.johnson@example.com',\n            'login': 'alice.johnson@example.com'\n        })\n\n        password_credential = PasswordCredential({'value': 'SecurePassword123!'})\n        user_credentials = UserCredentials({'password': password_credential})\n\n        create_user_request = CreateUserRequest({\n            'profile': user_profile,\n            'credentials': user_credentials\n        })\n\n        user, resp, err = await client.create_user(create_user_request, activate=True)\n        if err:\n            print(f\"Error creating user: {err}\")\n            return\n        print(f\"Created user: {user.id}\")\n\n        # Create a group\n        print(\"\\nCreating group...\")\n        group_profile = GroupProfile({\n            'name': 'Project Team Alpha',\n            'description': 'Members of Project Alpha'\n        })\n        new_group = Group({'profile': group_profile})\n\n        group, resp, err = await client.create_group(new_group)\n        if err:\n            print(f\"Error creating group: {err}\")\n            return\n        print(f\"Created group: {group.id}\")\n\n        # Add user to group\n        print(\"\\nAdding user to group...\")\n        resp, err = await client.add_user_to_group(group.id, user.id)\n        if err:\n            print(f\"Error adding user to group: {err}\")\n        else:\n            print(\"User added to group successfully\")\n\n        # Create an application\n        print(\"\\nCreating application...\")\n        application = Application({\n            'name': 'template_basic_auth',\n            'label': 'Team Application',\n            'signOnMode': 'BASIC_AUTH',\n            'settings': {\n                'app': {\n                    'url': 'https://example.com/app',\n                    'authURL': 'https://example.com/login'\n                }\n            }\n        })\n\n        app, resp, err = await client.create_application(application)\n        if err:\n            print(f\"Error creating application: {err}\")\n            return\n        print(f\"Created application: {app.id}\")\n\n        # Assign group to application\n        print(\"\\nAssigning group to application...\")\n        from okta.models import ApplicationGroupAssignment\n        assignment = ApplicationGroupAssignment({'priority': 0})\n\n        result, resp, err = await client.create_application_group_assignment(\n            app.id,\n            group.id,\n            assignment\n        )\n        if err:\n            print(f\"Error assigning group: {err}\")\n        else:\n            print(\"Group assigned to application successfully\")\n\n        # List all users in the group\n        print(\"\\nGroup members:\")\n        members, resp, err = await client.list_group_users(group.id)\n        if err:\n            print(f\"Error listing group members: {err}\")\n        else:\n            for member in members:\n                print(f\"  - {member.profile.first_name} {member.profile.last_name}\")\n\n        print(\"\\n✅ All operations completed successfully!\")\n\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n## Environment Variables Setup\n\nCreate a `.env` file for configuration:\n\n```bash\nOKTA_ORG_URL=https://dev-1234567.okta.com\nOKTA_API_TOKEN=your_api_token_here\n```\n\nLoad environment variables:\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom okta.client import Client as OktaClient\n\nload_dotenv()\n\nconfig = {\n    'orgUrl': os.getenv('OKTA_ORG_URL'),\n    'token': os.getenv('OKTA_API_TOKEN')\n}\n\nclient = OktaClient(config)\n```\n\n## OAuth 2.0 Private Key Configuration\n\nFor OAuth 2.0 authentication, use environment variables:\n\n```bash\nOKTA_ORG_URL=https://dev-1234567.okta.com\nOKTA_CLIENT_ID=your_client_id\nOKTA_PRIVATE_KEY={\"kty\":\"RSA\",\"kid\":\"key-id\",\"n\":\"...\",\"e\":\"AQAB\",\"d\":\"...\"}\nOKTA_KEY_ID=key-id\n```\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom okta.client import Client as OktaClient\n\nload_dotenv()\n\nconfig = {\n    'orgUrl': os.getenv('OKTA_ORG_URL'),\n    'authorizationMode': 'PrivateKey',\n    'clientId': os.getenv('OKTA_CLIENT_ID'),\n    'scopes': ['okta.users.manage', 'okta.groups.manage', 'okta.apps.manage'],\n    'privateKey': os.getenv('OKTA_PRIVATE_KEY'),\n    'kid': os.getenv('OKTA_KEY_ID')\n}\n\nclient = OktaClient(config)\n```\n\n## Useful Links\n\n- Official Documentation: https://developer.okta.com/\n- API Reference: https://developer.okta.com/docs/reference/\n- Users API: https://developer.okta.com/docs/reference/api/users/\n- Groups API: https://developer.okta.com/docs/reference/api/groups/\n- Applications API: https://developer.okta.com/docs/reference/api/apps/\n- GitHub Repository: https://github.com/okta/okta-sdk-python\n- PyPI Package: https://pypi.org/project/okta/\n"
  },
  {
    "path": "content/olakai/docs/cli/javascript/DOC.md",
    "content": "---\nname: cli\ndescription: \"Olakai CLI for managing agents, workflows, KPIs, and custom data — the configuration layer for AI analytics and governance\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.1.13\"\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"olakai,cli,agents,workflows,kpis,configuration\"\n---\n\n# Olakai CLI\n\nThe Olakai CLI manages the configuration layer for AI analytics and governance: agents, workflows, KPIs, and custom data fields. It is separate from the SDKs, which handle event tracking at runtime.\n\n> **v0.1.13** | Node.js 20+ | `npm install -g olakai-cli`\n\n## Installation & Auth\n\n```bash\nnpm install -g olakai-cli\nolakai login     # opens browser for OAuth 2.0 Device Flow\nolakai whoami    # verify your session\n```\n\n## Environment Selection\n\n```bash\nolakai --env staging agents list     # use staging environment\nolakai --env local agents list       # use localhost:3000\n\n# Or set via environment variable\nexport OLAKAI_ENV=staging            # production | staging | local\n```\n\n## Agents\n\nAgents represent individual AI services or components being monitored.\n\n```bash\n# List all agents\nolakai agents list [--json] [--include-kpis]\n\n# Get agent details (includes API key)\nolakai agents get <id> [--json]\n\n# Create an agent with an API key for SDK use\nolakai agents create \\\n  --name \"Document Processor\" \\\n  --description \"Extracts and summarizes documents\" \\\n  --workflow <workflow-id> \\\n  --with-api-key \\\n  --json\n\n# Update an agent\nolakai agents update <id> \\\n  --name \"New Name\" \\\n  --workflow <workflow-id> \\\n  --role WORKER|COORDINATOR\n\n# Delete an agent\nolakai agents delete <id> --force\n```\n\n### Retrieve an Agent's API Key\n\n```bash\nolakai agents get <id> --json | jq '.apiKey'\n```\n\nUse this key as `OLAKAI_API_KEY` in your SDK configuration.\n\n## Workflows\n\nWorkflows group agents into logical units. Every agent should belong to a workflow, even if it's the only one.\n\n```bash\n# List workflows\nolakai workflows list [--json] [--include-agents] [--include-inactive]\n\n# Get workflow details\nolakai workflows get <id> [--json]\n\n# Create a workflow\nolakai workflows create --name \"Customer Support Pipeline\" [--description \"...\"] [--json]\n\n# Update a workflow\nolakai workflows update <id> --name \"New Name\" [--active|--inactive] [--json]\n\n# Delete a workflow\nolakai workflows delete <id> --force\n```\n\n### Agent-Workflow Hierarchy\n\n```\nWorkflow: \"Customer Support Pipeline\"\n├── Agent: \"Ticket Classifier\"\n├── Agent: \"Response Generator\"\n└── Agent: \"Quality Checker\"\n\nWorkflow: \"Document Processing\"\n└── Agent: \"Document Summarizer\"  ← single-agent workflows are valid\n```\n\n## KPIs\n\nKPIs define business-specific calculations that run against event data from the SDKs.\n\n### Create KPIs\n\n```bash\n# Formula-based KPI (uses custom data fields as variables)\nolakai kpis create \\\n  --name \"Documents Processed\" \\\n  --agent-id <agent-id> \\\n  --calculator-id formula \\\n  --formula \"IF(Success = 1, 1, 0)\" \\\n  --unit \"count\" \\\n  --aggregation SUM\n\n# Classifier KPI (AI-evaluated from conversation content)\nolakai kpis create \\\n  --name \"User Satisfaction\" \\\n  --agent-id <agent-id> \\\n  --calculator-id classifier \\\n  --template-id sentiment_scorer \\\n  --scope CHAT\n```\n\n### Manage KPIs\n\n```bash\n# List KPIs\nolakai kpis list [--agent-id <id>] [--include-inactive] [--json]\n\n# Get KPI details\nolakai kpis get <id> [--json]\n\n# Update a KPI\nolakai kpis update <id> --formula \"NewVariable * 100\" [--active|--inactive]\n\n# Delete a KPI\nolakai kpis delete <id> --force\n```\n\n### Validate Formulas\n\n```bash\n# Check a formula before creating a KPI\nolakai kpis validate --formula \"IF(SuccessRate < 1, 1, 0)\" --agent-id <id>\n\n# List available context variables for formulas\nolakai kpis context-variables [--agent-id <id>] [--json]\n```\n\n### Formula Reference\n\n| Category | Operators |\n|----------|-----------|\n| Arithmetic | `+`, `-`, `*`, `/` |\n| Comparison | `<`, `<=`, `=`, `<>`, `>=`, `>` |\n| Logical | `AND`, `OR`, `NOT` |\n| Conditional | `IF(condition, true_val, false_val)` |\n| Null handling | `ISNA(value)`, `ISDEFINED(value)` |\n\nCommon patterns:\n\n```bash\n--formula \"StepCount\"                          # passthrough\n--formula \"SuccessRate * 100\"                  # percentage\n--formula \"IF(Success = 1, 1, 0)\"              # conditional count\n--formula \"IF(ISDEFINED(MyField), MyField, 0)\" # null-safe\n```\n\n### Aggregation Types\n\n| Type | Use For |\n|------|---------|\n| `SUM` | Totals, counts |\n| `AVERAGE` | Rates, percentages |\n| `COUNT` | Event counts |\n| `MIN` / `MAX` | Extremes |\n| `LATEST` | Most recent value |\n\n## Custom Data\n\nCustom data configs define which fields from SDK `customData` become available as KPI formula variables. Only registered fields can power KPIs.\n\n```bash\n# Create a numeric field (usable in KPI formulas)\nolakai custom-data create \\\n  --agent-id <agent-id> \\\n  --name \"StepCount\" \\\n  --type NUMBER \\\n  --description \"Number of workflow steps\"\n\n# Create a string field (for filtering, not calculations)\nolakai custom-data create \\\n  --agent-id <agent-id> \\\n  --name \"ExecutionId\" \\\n  --type STRING\n\n# List all configs for an agent\nolakai custom-data list --agent-id <agent-id>\n```\n\n### Data Pipeline\n\n```\nSDK customData → CustomDataConfig (schema) → Context Variable → KPI Formula → kpiData\n```\n\nRegister configs **before** sending data from the SDK. Unregistered fields are stored but cannot be used in KPI formulas.\n\n## Activity\n\nView events sent by the SDKs.\n\n```bash\n# List recent activity\nolakai activity list [--agent-id <id>] [--limit 10] [--json]\n\n# Get full event details (includes customData and kpiData)\nolakai activity get <event-id> [--json]\n\n# View session groupings\nolakai activity sessions [--agent-id <id>] [--json]\n```\n\n### Validating SDK Integration\n\nAfter setting up the SDK, verify data flows correctly:\n\n```bash\n# 1. Trigger a test event from your application\n\n# 2. Fetch the latest event\nolakai activity list --agent-id <id> --limit 1 --json\n\n# 3. Inspect customData and kpiData\nolakai activity get <event-id> --json | jq '{customData, kpiData}'\n```\n\n**Check kpiData values are numeric** (not strings or null):\n- Strings mean the formula is stored incorrectly — fix with `olakai kpis update <id> --formula \"Variable\"`\n- Null means the CustomDataConfig is missing or the field name doesn't match (case-sensitive)\n\n## Typical Setup Flow\n\n```bash\n# 1. Authenticate\nolakai login\n\n# 2. Create workflow\nolakai workflows create --name \"My AI Workflow\" --json\n# → note the workflow ID\n\n# 3. Create agent with API key\nolakai agents create \\\n  --name \"My Agent\" \\\n  --workflow <workflow-id> \\\n  --with-api-key --json\n# → note the agent ID and API key\n\n# 4. Register custom data fields\nolakai custom-data create --agent-id <id> --name \"Success\" --type NUMBER\nolakai custom-data create --agent-id <id> --name \"StepCount\" --type NUMBER\n\n# 5. Create KPIs\nolakai kpis create --agent-id <id> --name \"Success Rate\" \\\n  --calculator-id formula --formula \"Success * 100\" --aggregation AVERAGE\n\n# 6. Configure SDK with the API key, send events, then validate:\nolakai activity list --agent-id <id> --limit 1 --json\n```\n\n## Links\n\n- Full documentation: https://app.olakai.ai/llms.txt\n- Dashboard: https://app.olakai.ai\n- GitHub: https://github.com/ailocalnode/olakai-cli\n"
  },
  {
    "path": "content/olakai/docs/sdk/javascript/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Olakai SDK for measuring AI ROI, governing risk, and controlling costs across agents and AI applications\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.2.0\"\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"olakai,ai-analytics,governance,agents,kpi,roi,monitoring\"\n---\n\n# Olakai TypeScript/JavaScript SDK\n\nOlakai is a vendor-neutral platform that helps enterprises measure AI ROI, govern risk, and control costs across agents and AI applications. The SDK tracks AI interactions from your code and feeds data into KPIs, governance checks, and ROI dashboards.\n\n> **v2.2.0** | Node.js 18+ | `npm install @olakai/sdk`\n\n## Installation\n\n```bash\nnpm install @olakai/sdk\n# or\npnpm add @olakai/sdk\n```\n\n## Initialize\n\n```typescript\nimport { olakaiConfig } from \"@olakai/sdk\";\n\nolakaiConfig({\n  apiKey: process.env.OLAKAI_API_KEY,\n  endpoint: \"https://app.olakai.ai\", // default\n  debug: false, // true for development logging\n});\n```\n\nEach agent has its own API key. Create one via CLI: `olakai agents create --name \"My Agent\" --with-api-key`\n\n## Fire-and-Forget Tracking\n\nTrack any AI interaction without awaiting the result. The call returns immediately and sends data in the background.\n\n```typescript\nimport { olakai } from \"@olakai/sdk\";\n\n// After your LLM call completes\nolakai(\"event\", \"ai_activity\", {\n  prompt: \"Summarize this quarterly report\",\n  response: \"Revenue grew 15% quarter-over-quarter...\",\n  task: \"Data Processing & Analysis\",\n  userEmail: \"analyst@company.com\",\n  tokens: 1200,\n  requestTime: 3500, // ms\n  chatId: \"session-abc123\", // groups conversation turns\n  customData: {\n    DocumentType: \"quarterly-report\",\n    PageCount: 12,\n    Success: 1,\n  },\n});\n```\n\n## Awaitable Reporting\n\nWhen you need confirmation that the event was recorded (e.g., for governance checks that may block content):\n\n```typescript\nimport { olakaiReport } from \"@olakai/sdk\";\n\nconst result = await olakaiReport(\n  \"Draft an email to the client about project delays\",\n  \"Dear Client, I wanted to update you on the current timeline...\",\n  {\n    task: \"Communication Strategy\",\n    userEmail: \"pm@company.com\",\n    tokens: 450,\n  }\n);\n```\n\n## Function Monitoring\n\nWrap any function to automatically track its input/output:\n\n```typescript\nimport { olakaiMonitor } from \"@olakai/sdk\";\n\nconst summarize = olakaiMonitor(\n  async (text: string) => {\n    const response = await openai.chat.completions.create({\n      model: \"gpt-4o\",\n      messages: [{ role: \"user\", content: `Summarize: ${text}` }],\n    });\n    return response.choices[0].message.content;\n  },\n  {\n    task: \"Content Refinement\",\n    userEmail: \"editor@company.com\",\n  }\n);\n\n// Use normally — monitoring happens automatically\nconst summary = await summarize(longArticle);\n```\n\n## Content Governance (Blocking)\n\nWhen governance policies detect sensitive content, the SDK throws `OlakaiBlockedError`:\n\n```typescript\nimport { OlakaiBlockedError } from \"@olakai/sdk\";\n\ntry {\n  const result = await monitoredFunction(userInput);\n} catch (error) {\n  if (error instanceof OlakaiBlockedError) {\n    // error.details.detectedSensitivity: [\"PII\", \"PHI\", \"CODE\", \"SECRET\"]\n    // error.details.isAllowedPersona: boolean\n    if (error.details.detectedSensitivity.includes(\"PII\")) {\n      return \"This request contains personal information and was blocked by policy.\";\n    }\n  }\n  throw error;\n}\n```\n\n## Parameters Reference\n\nAll tracking functions accept these fields via `OlakaiEventParams`:\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `prompt` | `string` | The input sent to the AI model |\n| `response` | `string` | The AI model's output |\n| `userEmail` | `string?` | User email for per-user analytics |\n| `chatId` | `string?` | Groups related interactions into a session |\n| `task` | `string?` | Task category (e.g., \"Customer Experience\") |\n| `subTask` | `string?` | Specific sub-task within the category |\n| `tokens` | `number?` | Total token count for the interaction |\n| `requestTime` | `number?` | Request duration in milliseconds |\n| `shouldScore` | `boolean?` | Whether to run quality scoring |\n| `taskExecutionId` | `string?` | Correlates events across agents in a multi-agent task |\n| `customData` | `object?` | Key-value pairs for KPI formulas (see below) |\n| `customDimensions` | `object?` | String dimensions for categorization (`dim1`–`dim5`) |\n| `customMetrics` | `object?` | Numeric values for analysis (`metric1`–`metric5`) |\n\n## Custom Data Pipeline\n\nCustom data flows through Olakai to power KPIs:\n\n```\nSDK customData → CustomDataConfig (schema) → Context Variable → KPI Formula → kpiData\n```\n\n### How It Works\n\n1. You send `customData` fields with each event\n2. Only fields registered as **CustomDataConfigs** on the platform become usable in KPI formulas\n3. KPI formulas reference these fields as variables (e.g., `IF(Success = 1, 1, 0)`)\n4. Computed KPI values appear on dashboards and in alerts\n\n### Rules\n\n| Rule | Detail |\n|------|--------|\n| Register fields first | Unregistered `customData` fields are stored but cannot power KPIs |\n| NUMBER configs need numeric values | Send `5` (number), not `\"5\"` (string) |\n| Formula variables are case-insensitive | `stepCount`, `STEPCOUNT`, `StepCount` all resolve the same |\n| KPIs are per-agent | Each agent needs its own KPI definitions |\n\n### Example\n\n```typescript\n// 1. Register via CLI:\n//    olakai custom-data create --agent-id $ID --name \"StepCount\" --type NUMBER\n//    olakai custom-data create --agent-id $ID --name \"Success\" --type NUMBER\n//    olakai kpis create --agent-id $ID --name \"Steps\" --formula \"StepCount\" --aggregation SUM\n//    olakai kpis create --agent-id $ID --name \"Success Rate\" --formula \"Success * 100\" --aggregation AVERAGE\n\n// 2. Send matching fields in SDK:\nolakai(\"event\", \"ai_activity\", {\n  prompt: taskInput,\n  response: taskOutput,\n  customData: {\n    StepCount: 3,   // NUMBER — matches registered config\n    Success: 1,     // NUMBER — 1/0 for boolean values\n  },\n});\n```\n\n## Agentic Workflows\n\nFor agents that make multiple LLM calls per task, aggregate them into one event:\n\n```typescript\nasync function processDocument(doc: Document) {\n  const startTime = Date.now();\n  let totalTokens = 0;\n\n  // Step 1: Extract\n  const extraction = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: `Extract from: ${doc.content}` }],\n  });\n  totalTokens += extraction.usage?.total_tokens ?? 0;\n\n  // Step 2: Analyze\n  const analysis = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: `Analyze: ${extraction.choices[0].message.content}` }],\n  });\n  totalTokens += analysis.usage?.total_tokens ?? 0;\n\n  const result = analysis.choices[0].message.content ?? \"\";\n\n  // Track the complete workflow as ONE event\n  olakai(\"event\", \"ai_activity\", {\n    prompt: `Process: ${doc.title}`,\n    response: result,\n    tokens: totalTokens,\n    requestTime: Date.now() - startTime,\n    taskExecutionId: crypto.randomUUID(), // share across agents for cross-agent correlation\n    task: \"Data Processing & Analysis\",\n    customData: {\n      DocumentType: doc.type,\n      StepCount: 2,\n      Success: 1,\n    },\n  });\n\n  return result;\n}\n```\n\n### Cross-Agent Task Correlation\n\nWhen multiple agents collaborate on one task, generate a single `taskExecutionId` in the orchestrator and pass it to every agent. This links their events into one logical task for analytics.\n\n```typescript\nconst taskId = crypto.randomUUID();\n\n// Orchestrator passes taskId to each agent\nawait classifierAgent.run(input, { taskExecutionId: taskId });\nawait writerAgent.run(classified, { taskExecutionId: taskId });\nawait reviewerAgent.run(draft, { taskExecutionId: taskId });\n```\n\n## Framework Examples\n\n### Next.js API Route\n\n```typescript\n// app/api/chat/route.ts\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { olakai } from \"@olakai/sdk\";\n\nexport async function POST(req: NextRequest) {\n  const { message } = await req.json();\n\n  const response = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: message }],\n  });\n\n  const reply = response.choices[0].message.content;\n\n  olakai(\"event\", \"ai_activity\", {\n    prompt: message,\n    response: reply,\n    tokens: response.usage?.total_tokens,\n    task: \"Customer Experience\",\n  });\n\n  return NextResponse.json({ reply });\n}\n```\n\n### Express.js\n\n```typescript\nimport { olakaiConfig, olakai } from \"@olakai/sdk\";\n\nolakaiConfig({ apiKey: process.env.OLAKAI_API_KEY });\n\napp.post(\"/chat\", async (req, res) => {\n  const response = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: req.body.message }],\n  });\n\n  olakai(\"event\", \"ai_activity\", {\n    prompt: req.body.message,\n    response: response.choices[0].message.content,\n    userEmail: req.user.email,\n    task: \"Customer Experience\",\n  });\n\n  res.json({ reply: response.choices[0].message.content });\n});\n```\n\n## Troubleshooting\n\n**Events not appearing:** Verify `olakaiConfig()` was called before any tracking calls. Enable `debug: true` to see request/response logs.\n\n**Content blocked unexpectedly:** Check your governance policies in the Olakai dashboard. The `OlakaiBlockedError.details` object shows which sensitivity was detected.\n\n**KPIs showing null:** Ensure the field name in `customData` exactly matches the CustomDataConfig name (case-sensitive), and that NUMBER configs receive numeric values.\n\n## Links\n\n- Full documentation: https://app.olakai.ai/llms.txt\n- Dashboard: https://app.olakai.ai\n- GitHub: https://github.com/ailocalnode/olakai-sdk-typescript\n"
  },
  {
    "path": "content/olakai/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Olakai SDK for measuring AI ROI, governing risk, and controlling costs across agents and AI applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"olakai,ai-analytics,governance,agents,kpi,roi,monitoring\"\n---\n\n# Olakai Python SDK\n\nOlakai is a vendor-neutral platform that helps enterprises measure AI ROI, govern risk, and control costs across agents and AI applications. The SDK tracks AI interactions from your code and feeds data into KPIs, governance checks, and ROI dashboards.\n\n> **v1.2.0** | Python 3.7+ | `pip install olakai-sdk`\n\n## Installation\n\n```bash\npip install olakai-sdk\n```\n\nThe import name is `olakaisdk`:\n\n```python\nfrom olakaisdk import olakai_config, olakai, olakai_report, olakai_monitor\n```\n\n## Initialize\n\n```python\nimport os\nfrom olakaisdk import olakai_config\n\nolakai_config(\n    api_key=os.getenv(\"OLAKAI_API_KEY\"),\n    endpoint=\"https://app.olakai.ai\",  # default\n    debug=False  # True for development logging\n)\n```\n\nEach agent has its own API key. Create one via CLI: `olakai agents create --name \"My Agent\" --with-api-key`\n\n## Fire-and-Forget Tracking\n\nTrack any AI interaction. The call sends data in the background without blocking your code.\n\n```python\nfrom olakaisdk import olakai, OlakaiEventParams\n\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=\"Summarize this quarterly report\",\n    response=\"Revenue grew 15% quarter-over-quarter...\",\n    task=\"Data Processing & Analysis\",\n    userEmail=\"analyst@company.com\",\n    tokens=1200,\n    requestTime=3500,  # ms\n    chatId=\"session-abc123\",  # groups conversation turns\n    customData={\n        \"DocumentType\": \"quarterly-report\",\n        \"PageCount\": 12,\n        \"Success\": 1,\n    },\n))\n```\n\n## Direct Reporting\n\nReport events without the decorator pattern. Useful when you need inline tracking:\n\n```python\nfrom olakaisdk import olakai_report\n\nolakai_report(\n    prompt=\"Draft an email to the client about project delays\",\n    response=\"Dear Client, I wanted to update you on the current timeline...\",\n    options={\n        \"task\": \"Communication Strategy\",\n        \"userEmail\": \"pm@company.com\",\n        \"tokens\": 450,\n    }\n)\n```\n\n## Function Monitoring (Decorator)\n\nWrap any function to automatically track its input and output:\n\n```python\nfrom olakaisdk import olakai_config, olakai_monitor\n\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\n@olakai_monitor(\n    task=\"Content Refinement\",\n    userEmail=\"editor@company.com\",\n)\ndef summarize(text: str) -> str:\n    response = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Summarize: {text}\"}],\n    )\n    return response.choices[0].message.content\n\n# Use normally — monitoring happens automatically\nsummary = summarize(long_article)\n```\n\n### Dynamic User Email\n\nPass a lambda to resolve the user at call time:\n\n```python\n@olakai_monitor(\n    userEmail=lambda args: get_user_email(args[0]),  # args[0] is the first positional arg\n    task=\"Customer Experience\",\n)\ndef handle_query(user_id: str, question: str) -> str:\n    # Your AI logic\n    return answer\n```\n\n### Async Support\n\nThe decorator works with both sync and async functions:\n\n```python\n@olakai_monitor(task=\"Research & Intelligence\")\nasync def async_research(topic: str) -> str:\n    response = await async_client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Research: {topic}\"}],\n    )\n    return response.choices[0].message.content\n```\n\n## Parameters Reference\n\nAll tracking functions accept these fields via `OlakaiEventParams` or option dicts:\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `prompt` | `str` | The input sent to the AI model |\n| `response` | `str` | The AI model's output |\n| `userEmail` | `str?` | User email for per-user analytics |\n| `chatId` | `str?` | Groups related interactions into a session |\n| `task` | `str?` | Task category (e.g., \"Customer Experience\") |\n| `subTask` | `str?` | Specific sub-task within the category |\n| `tokens` | `int?` | Total token count for the interaction |\n| `requestTime` | `int?` | Request duration in milliseconds |\n| `shouldScore` | `bool?` | Whether to run quality scoring |\n| `taskExecutionId` | `str?` | Correlates events across agents in a multi-agent task |\n| `customData` | `dict?` | Key-value pairs for KPI formulas (see below) |\n| `customDimensions` | `dict?` | String dimensions for categorization (`dim1`–`dim5`) |\n| `customMetrics` | `dict?` | Numeric values for analysis (`metric1`–`metric5`) |\n\n## Custom Data Pipeline\n\nCustom data flows through Olakai to power KPIs:\n\n```\nSDK customData → CustomDataConfig (schema) → Context Variable → KPI Formula → kpiData\n```\n\n### How It Works\n\n1. You send `customData` fields with each event\n2. Only fields registered as **CustomDataConfigs** on the platform become usable in KPI formulas\n3. KPI formulas reference these fields as variables (e.g., `IF(Success = 1, 1, 0)`)\n4. Computed KPI values appear on dashboards and in alerts\n\n### Rules\n\n| Rule | Detail |\n|------|--------|\n| Register fields first | Unregistered `customData` fields are stored but cannot power KPIs |\n| NUMBER configs need numeric values | Send `5` (int/float), not `\"5\"` (str) |\n| Formula variables are case-insensitive | `stepCount`, `STEPCOUNT`, `StepCount` all resolve the same |\n| KPIs are per-agent | Each agent needs its own KPI definitions |\n\n### Example\n\n```python\n# 1. Register via CLI:\n#    olakai custom-data create --agent-id $ID --name \"StepCount\" --type NUMBER\n#    olakai custom-data create --agent-id $ID --name \"Success\" --type NUMBER\n#    olakai kpis create --agent-id $ID --name \"Steps\" --formula \"StepCount\" --aggregation SUM\n\n# 2. Send matching fields in SDK:\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=task_input,\n    response=task_output,\n    customData={\n        \"StepCount\": 3,   # int — matches registered config\n        \"Success\": 1,     # int — 1/0 for boolean values\n    },\n))\n```\n\n## Agentic Workflows\n\nFor agents that make multiple LLM calls per task, aggregate them into one event:\n\n```python\nimport time\nimport uuid\nfrom olakaisdk import olakai, OlakaiEventParams\n\ndef process_document(doc: dict) -> str:\n    start_time = time.time()\n    total_tokens = 0\n\n    # Step 1: Extract\n    extraction = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Extract from: {doc['content']}\"}],\n    )\n    total_tokens += extraction.usage.total_tokens\n\n    # Step 2: Analyze\n    analysis = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": f\"Analyze: {extraction.choices[0].message.content}\"}],\n    )\n    total_tokens += analysis.usage.total_tokens\n\n    result = analysis.choices[0].message.content\n\n    # Track the complete workflow as ONE event\n    olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n        prompt=f\"Process: {doc['title']}\",\n        response=result,\n        tokens=total_tokens,\n        requestTime=int((time.time() - start_time) * 1000),\n        taskExecutionId=str(uuid.uuid4()),  # share across agents for correlation\n        task=\"Data Processing & Analysis\",\n        customData={\n            \"DocumentType\": doc[\"type\"],\n            \"StepCount\": 2,\n            \"Success\": 1,\n        },\n    ))\n\n    return result\n```\n\n### Cross-Agent Task Correlation\n\nWhen multiple agents collaborate on one task, generate a single `taskExecutionId` in the orchestrator and pass it to every agent. This links their events into one logical task for analytics.\n\n```python\ntask_id = str(uuid.uuid4())\n\nawait classifier_agent.run(input_data, task_execution_id=task_id)\nawait writer_agent.run(classified, task_execution_id=task_id)\nawait reviewer_agent.run(draft, task_execution_id=task_id)\n```\n\n## Framework Examples\n\n### FastAPI\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\n\napp = FastAPI()\n\n@app.on_event(\"startup\")\nasync def startup():\n    olakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\n@app.post(\"/chat\")\nasync def chat(message: str, user: User = Depends(get_current_user)):\n    response = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": message}],\n    )\n    reply = response.choices[0].message.content\n\n    olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n        prompt=message,\n        response=reply,\n        userEmail=user.email,\n        task=\"Customer Experience\",\n        tokens=response.usage.total_tokens,\n    ))\n\n    return {\"reply\": reply}\n```\n\n### Flask\n\n```python\nfrom flask import Flask, request, jsonify\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\n\napp = Flask(__name__)\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\n@app.route(\"/chat\", methods=[\"POST\"])\ndef chat():\n    message = request.json[\"message\"]\n\n    response = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": message}],\n    )\n    reply = response.choices[0].message.content\n\n    olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n        prompt=message,\n        response=reply,\n        task=\"Customer Experience\",\n    ))\n\n    return jsonify({\"reply\": reply})\n```\n\n## Content Governance (Blocking)\n\nWhen governance policies detect sensitive content, the SDK raises `OlakaiBlockedError`:\n\n```python\nfrom olakaisdk import OlakaiBlockedError\n\ntry:\n    result = monitored_function(user_input)\nexcept OlakaiBlockedError as e:\n    # e.details[\"detectedSensitivity\"]: [\"PII\", \"PHI\", \"CODE\", \"SECRET\"]\n    # e.details[\"isAllowedPersona\"]: bool\n    if \"PII\" in e.details.get(\"detectedSensitivity\", []):\n        return \"This request contains personal information and was blocked by policy.\"\n    raise\n```\n\n## Troubleshooting\n\n**Events not appearing:** Verify `olakai_config()` was called before any tracking calls. Enable `debug=True` to see request/response logs.\n\n**Import errors:** The package installs as `olakai-sdk` but imports as `olakaisdk`. Run `pip install --upgrade olakai-sdk` to get the latest version.\n\n**KPIs showing null:** Ensure the field name in `customData` exactly matches the CustomDataConfig name (case-sensitive), and that NUMBER configs receive numeric values (int/float, not str).\n\n## Links\n\n- Full documentation: https://app.olakai.ai/llms.txt\n- Dashboard: https://app.olakai.ai\n- GitHub: https://github.com/ailocalnode/olakai-sdk-python\n"
  },
  {
    "path": "content/olakai/skills/integrate/SKILL.md",
    "content": "---\nname: integrate\ndescription: \"Add Olakai monitoring to existing AI code — wrap your LLM client, configure custom KPIs, and validate the integration end-to-end\"\nmetadata:\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"olakai,integration,monitoring,sdk,kpi,governance\"\n---\n\n# Integrate Olakai into Existing AI Code\n\nThis skill guides you through adding Olakai monitoring to an existing AI agent or LLM-powered application with minimal code changes.\n\nFor full SDK documentation, see: https://app.olakai.ai/llms.txt\n\n## Prerequisites\n\n- Existing working AI agent/application using OpenAI, Anthropic, or other LLM\n- Olakai CLI installed and authenticated (`npm install -g olakai-cli && olakai login`)\n- Olakai API key for your agent (get via CLI: `olakai agents get AGENT_ID --json | jq '.apiKey'`)\n- Node.js 18+ (for TypeScript) or Python 3.7+ (for Python)\n\n> **Note:** Each agent can have its own API key. Create one with `olakai agents create --name \"Name\" --with-api-key`\n\n## Why Custom KPIs Are Essential\n\nAdding monitoring is only the first step. **The real value of Olakai comes from tracking custom KPIs specific to your agent's business purpose.**\n\n**Without KPIs configured:**\n- Only basic token counts and request data\n- No aggregated business KPIs on dashboard\n- No alerting capabilities\n- No ROI tracking\n\n**With KPIs configured:**\n- Custom KPIs (items processed, success rates, quality scores)\n- Trend analysis and performance dashboards\n- Threshold-based alerting\n- Business value calculations\n\n> **Plan to configure at least 2-4 KPIs** that answer: \"How do I know this agent is performing well?\"\n\n> **KPIs are unique per agent.** If adding monitoring to an agent that needs the same KPIs as another already-configured agent, you must still create new KPI definitions for this agent. KPIs cannot be shared or reused across agents.\n\n## Understanding the customData to KPI Pipeline\n\nBefore adding monitoring, understand how custom data flows through Olakai:\n\n```\nSDK customData → CustomDataConfig (Schema) → Context Variable → KPI Formula → kpiData\n```\n\n### Critical Rules\n\n| Rule | Consequence |\n|------|-------------|\n| Only CustomDataConfig fields become variables | Unregistered customData fields are NOT usable in KPIs |\n| Formula evaluation is case-insensitive | `stepCount`, `STEPCOUNT`, `StepCount` all work in formulas |\n| NUMBER configs need numeric values | Don't send `\"5\"` (string), send `5` (number) |\n\n> **IMPORTANT**: The SDK accepts any JSON in `customData`, but **only fields registered as CustomDataConfigs are processed**. Unregistered fields are stored but cannot be used in KPIs.\n\n## Quick Start (5-Minute Integration)\n\n### For TypeScript/JavaScript\n\n**1. Install the SDK:**\n```bash\nnpm install @olakai/sdk\n```\n\n**2. Add tracking after your LLM call:**\n\nBefore:\n```typescript\nimport OpenAI from \"openai\";\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\nconst response = await openai.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: userMessage }],\n});\n```\n\nAfter:\n```typescript\nimport OpenAI from \"openai\";\nimport { olakaiConfig, olakai } from \"@olakai/sdk\";\n\nolakaiConfig({ apiKey: process.env.OLAKAI_API_KEY });\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\nconst response = await openai.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: userMessage }],\n});\n\n// Track the interaction (fire-and-forget)\nolakai(\"event\", \"ai_activity\", {\n  prompt: userMessage,\n  response: response.choices[0].message.content,\n  tokens: response.usage?.total_tokens,\n  userEmail: user.email,\n  task: \"Customer Experience\",\n});\n```\n\n### For Python\n\n**1. Install the SDK:**\n```bash\npip install olakai-sdk\n```\n\n**2. Add tracking after your LLM call:**\n\nBefore:\n```python\nfrom openai import OpenAI\nclient = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": user_message}],\n)\n```\n\nAfter:\n```python\nfrom openai import OpenAI\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\n\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\nclient = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": user_message}],\n)\n\n# Track the interaction\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=user_message,\n    response=response.choices[0].message.content,\n    tokens=response.usage.total_tokens,\n    userEmail=user.email,\n    task=\"Customer Experience\",\n))\n```\n\n---\n\n## Detailed Integration Guide\n\n### Step 1: Identify Your Integration Pattern\n\n**Pattern A: Single LLM Client**\nYou have one OpenAI/Anthropic client used throughout your app.\nUse the fire-and-forget `olakai()` call after each completion.\n\n**Pattern B: Multiple LLM Calls per Request**\nYour agent makes several LLM calls to complete one task.\nUse manual event tracking to aggregate calls into a single event.\n\n**Pattern C: Streaming Responses**\nYou stream LLM responses to users.\nTrack after the stream completes with the full accumulated response.\n\n**Pattern D: Third-Party LLM (not OpenAI/Anthropic)**\nYou use Perplexity, Groq, local models, etc.\nUse manual event tracking via `olakai()` or `olakai_event()`.\n\n### Step 2: Install and Configure\n\n#### TypeScript Setup\n\n```typescript\n// lib/olakai.ts - Initialize once at app startup\nimport { olakaiConfig } from \"@olakai/sdk\";\n\nolakaiConfig({\n  apiKey: process.env.OLAKAI_API_KEY!,\n  debug: process.env.NODE_ENV === \"development\",\n});\n```\n\n#### Python Setup\n\n```python\n# lib/olakai.py - Initialize once at app startup\nimport os\nfrom olakaisdk import olakai_config\n\nolakai_config(\n    api_key=os.getenv(\"OLAKAI_API_KEY\"),\n    debug=os.getenv(\"DEBUG\") == \"true\"\n)\n```\n\n### Step 3: Add Context to Calls\n\n#### Adding User Information\n\nTypeScript:\n```typescript\nolakai(\"event\", \"ai_activity\", {\n  prompt: userMessage,\n  response: aiResponse,\n  userEmail: user.email,\n  task: \"Customer Experience\",\n});\n```\n\nPython:\n```python\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=user_message,\n    response=ai_response,\n    userEmail=user.email,\n    task=\"Customer Experience\",\n))\n```\n\n#### Grouping Events by Conversation (chatId)\n\nFor assistive AI (chatbots/copilots), use `chatId` to group multiple turns of a conversation together. This is required for CHAT-scoped KPIs that analyze the full conversation.\n\n```typescript\nolakai(\"event\", \"ai_activity\", {\n  prompt: userMessage,\n  response: aiResponse,\n  chatId: conversationId,  // groups turns in the same conversation\n  userEmail: user.email,\n});\n```\n\n> **When to use `chatId`:** If your agent handles multi-turn conversations and you want KPIs that evaluate the entire conversation (e.g., sentiment scoring, satisfaction), pass a consistent `chatId` across all turns.\n\n#### Adding Custom Data\n\n> **IMPORTANT**: Only send fields you've registered as CustomDataConfigs (Step 5.3). Unregistered fields are stored but **cannot be used in KPIs**.\n\n> **Only send data you'll use in KPIs or for filtering.** Don't duplicate fields already tracked by the platform (session ID, agent ID, user email, timestamps, token count, model, provider — all tracked automatically).\n\nTypeScript:\n```typescript\nolakai(\"event\", \"ai_activity\", {\n  prompt: userMessage,\n  response: aiResponse,\n  userEmail: user.email,\n  customData: {\n    // Only include fields registered as CustomDataConfigs\n    Department: user.department,\n    ProjectId: currentProject.id,\n    Priority: ticket.priority,\n  },\n});\n```\n\n### Step 4: Handle Agentic Workflows\n\nIf your agent makes multiple LLM calls per task, aggregate them into a single event.\n\n> **`taskExecutionId` — Critical for multi-agent workflows.** If multiple agents collaborate on the same task, the orchestrator must generate ONE `taskExecutionId` and pass it to all agents. This is how Olakai correlates cross-agent work as a single logical task.\n\n```typescript\nasync function processDocument(doc: Document): Promise<string> {\n  const startTime = Date.now();\n  let totalTokens = 0;\n\n  // Step 1: Extract\n  const extraction = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: `Extract from: ${doc.content}` }],\n  });\n  totalTokens += extraction.usage?.total_tokens ?? 0;\n\n  // Step 2: Analyze\n  const analysis = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: `Analyze: ${extraction.choices[0].message.content}` }],\n  });\n  totalTokens += analysis.usage?.total_tokens ?? 0;\n\n  const result = analysis.choices[0].message.content ?? \"\";\n\n  // Track the complete workflow as ONE event\n  olakai(\"event\", \"ai_activity\", {\n    prompt: `Process document: ${doc.title}`,\n    response: result,\n    tokens: totalTokens,\n    requestTime: Date.now() - startTime,\n    taskExecutionId: crypto.randomUUID(),\n    task: \"Data Processing & Analysis\",\n    customData: {\n      DocumentType: doc.type,\n      StepCount: 2,\n      Success: 1,\n    },\n  });\n\n  return result;\n}\n```\n\n### Step 5: Configure Custom KPIs (Essential for Value)\n\n> **This step is required to get real value from Olakai.** Without KPIs, you're only tracking events — not gaining actionable insights.\n\n#### 5.1 Install CLI (if not already)\n```bash\nnpm install -g olakai-cli\nolakai login\n```\n\n#### 5.2 Register Your Agent\n```bash\nolakai agents create \\\n  --name \"Document Processor\" \\\n  --description \"Processes and summarizes documents\" \\\n  --workflow WORKFLOW_ID \\\n  --with-api-key\n```\n\n#### 5.2.1 Ensure Agent Has a Workflow\n\n> **Every agent MUST belong to a workflow**, even if it's the only agent.\n\n```bash\n# Check if agent has a workflow\nolakai agents get YOUR_AGENT_ID --json | jq '.workflowId'\n\n# If null, create a workflow and associate:\nolakai workflows create --name \"Your Workflow Name\" --json\nolakai agents update YOUR_AGENT_ID --workflow WORKFLOW_ID\n```\n\n#### 5.3 Create Custom Data Configs FIRST\n\n> **IMPORTANT**: Create configs for ALL fields you send in `customData`. Only registered fields can be used in KPIs. CustomDataConfigs are agent-scoped.\n\n```bash\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"DocumentType\" --type STRING\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"StepCount\" --type NUMBER\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"Success\" --type NUMBER\n\n# Verify all configs exist for this agent\nolakai custom-data list --agent-id YOUR_AGENT_ID\n```\n\n#### 5.4 Create KPIs\n\n```bash\nolakai kpis create \\\n  --name \"Documents Processed\" \\\n  --agent-id YOUR_AGENT_ID \\\n  --calculator-id formula \\\n  --formula \"IF(Success = 1, 1, 0)\" \\\n  --aggregation SUM\n\nolakai kpis create \\\n  --name \"Avg Steps per Document\" \\\n  --agent-id YOUR_AGENT_ID \\\n  --calculator-id formula \\\n  --formula \"StepCount\" \\\n  --aggregation AVERAGE\n```\n\n#### 5.5 Update SDK Code to Match\n\nAfter creating configs, ensure your SDK code sends **exactly those field names**:\n\n```typescript\ncustomData: {\n  DocumentType: doc.type,     // Matches CustomDataConfig \"DocumentType\"\n  StepCount: 2,               // Matches CustomDataConfig \"StepCount\"\n  Success: true ? 1 : 0,      // Matches CustomDataConfig \"Success\"\n}\n```\n\n## Framework-Specific Integrations\n\n### Next.js API Routes\n\n```typescript\n// app/api/chat/route.ts\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { olakai } from \"@olakai/sdk\";\nimport { auth } from \"@/auth\";\n\nexport async function POST(req: NextRequest) {\n  const session = await auth();\n  if (!session?.user) {\n    return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n  }\n\n  const { message } = await req.json();\n\n  const response = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages: [{ role: \"user\", content: message }],\n  });\n\n  olakai(\"event\", \"ai_activity\", {\n    prompt: message,\n    response: response.choices[0].message.content,\n    userEmail: session.user.email!,\n    task: \"Customer Experience\",\n  });\n\n  return NextResponse.json({ reply: response.choices[0].message.content });\n}\n```\n\n### FastAPI (Python)\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\n\napp = FastAPI()\n\n@app.on_event(\"startup\")\nasync def startup():\n    olakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\nclient = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n\n@app.post(\"/chat\")\nasync def chat(message: str, user: User = Depends(get_current_user)):\n    response = client.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=[{\"role\": \"user\", \"content\": message}]\n    )\n\n    olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n        prompt=message,\n        response=response.choices[0].message.content,\n        userEmail=user.email,\n        task=\"Customer Experience\",\n    ))\n\n    return {\"reply\": response.choices[0].message.content}\n```\n\n## Handling Edge Cases\n\n### Streaming Responses\n\nTrack after the stream completes with the full response:\n\n```typescript\nconst stream = await openai.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: userMessage }],\n  stream: true,\n});\n\nlet fullResponse = \"\";\nfor await (const chunk of stream) {\n  fullResponse += chunk.choices[0]?.delta?.content ?? \"\";\n  res.write(chunk.choices[0]?.delta?.content ?? \"\");\n}\n\n// Track after stream completes\nolakai(\"event\", \"ai_activity\", {\n  prompt: userMessage,\n  response: fullResponse,\n  userEmail: user.email,\n});\n```\n\n### Error Handling\n\n```typescript\ntry {\n  const response = await openai.chat.completions.create({\n    model: \"gpt-4o\",\n    messages,\n  });\n  return response.choices[0].message.content;\n} catch (error) {\n  // Track the failed attempt\n  olakai(\"event\", \"ai_activity\", {\n    prompt: messages[messages.length - 1].content,\n    response: `Error: ${error instanceof Error ? error.message : \"Unknown\"}`,\n    task: \"Software Development\",\n    customData: { Success: 0 },\n  });\n  throw error;\n}\n```\n\n### Non-OpenAI Providers\n\nFor Anthropic, Perplexity, or other providers, use manual tracking:\n\n```typescript\nimport Anthropic from \"@anthropic-ai/sdk\";\n\nconst anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });\n\nasync function callClaude(prompt: string): Promise<string> {\n  const startTime = Date.now();\n\n  const response = await anthropic.messages.create({\n    model: \"claude-sonnet-4-20250514\",\n    max_tokens: 1024,\n    messages: [{ role: \"user\", content: prompt }],\n  });\n\n  const content = response.content[0].type === \"text\" ? response.content[0].text : \"\";\n\n  olakai(\"event\", \"ai_activity\", {\n    prompt,\n    response: content,\n    tokens: response.usage.input_tokens + response.usage.output_tokens,\n    requestTime: Date.now() - startTime,\n    task: \"Content Development\",\n  });\n\n  return content;\n}\n```\n\n## Test-Validate-Iterate Cycle\n\n**Never assume your integration is working. Always validate by generating a test event and inspecting the actual data.**\n\n### Step 1: Generate a Test Event\n\nRun your application to trigger at least one LLM call.\n\n### Step 2: Fetch and Inspect the Event\n\n```bash\nolakai activity list --limit 1 --json\nolakai activity get EVENT_ID --json\n```\n\n### Step 3: Validate Each Component\n\n**Check customData is present:**\n```bash\nolakai activity get EVENT_ID --json | jq '.customData'\n```\n\n**Check KPIs are numeric (not strings or null):**\n```bash\nolakai activity get EVENT_ID --json | jq '.kpiData'\n```\n\n**CORRECT:**\n```json\n{ \"My KPI\": 42 }\n```\n\n**WRONG (formula stored as string):**\n```json\n{ \"My KPI\": \"MyVariable\" }\n```\nFix: `olakai kpis update KPI_ID --formula \"MyVariable\"`\n\n**WRONG (null value):**\n```json\n{ \"My KPI\": null }\n```\nFix by ensuring:\n1. CustomDataConfig exists: `olakai custom-data create --agent-id ID --name \"MyVariable\" --type NUMBER`\n2. Field name case matches exactly (case-sensitive)\n3. SDK actually sends the field in customData\n\n### Validation Flow\n\n```\n1. Trigger LLM call (generate event)\n           ↓\n2. Fetch: olakai activity get ID --json\n           ↓\n3. Event exists? NO → Check API key, SDK init, debug mode\n           ↓\n4. customData correct? NO → Fix SDK customData parameter\n           ↓\n5. kpiData numeric? NO → olakai kpis update ID --formula \"X\"\n           ↓\n6. kpiData not null? NO → Create CustomDataConfig, check field name case\n           ↓\n✅ Integration validated\n```\n\n## KPI Formula Reference\n\n### Supported Operators\n\n| Category | Operators |\n|----------|-----------|\n| Arithmetic | `+`, `-`, `*`, `/` |\n| Comparison | `<`, `<=`, `=`, `<>`, `>=`, `>` |\n| Logical | `AND`, `OR`, `NOT` |\n| Conditional | `IF(condition, true_val, false_val)` |\n| Null handling | `ISNA(value)`, `ISDEFINED(value)` |\n\n### Common Formula Patterns\n\n```bash\n--formula \"StepCount\"                          # passthrough\n--formula \"SuccessRate * 100\"                  # percentage conversion\n--formula \"IF(Success = 1, 1, 0)\"              # conditional counting\n--formula \"IF(PII detected, 1, 0)\"             # built-in variable\n--formula \"IF(ISDEFINED(MyField), MyField, 0)\" # null-safe\n```\n\n### Aggregation Types\n\n| Aggregation | Use For |\n|-------------|---------|\n| `SUM` | Totals, counts |\n| `AVERAGE` | Rates, percentages |\n\n## Quick Reference\n\n```typescript\n// TypeScript — initialize once\nimport { olakaiConfig, olakai } from \"@olakai/sdk\";\nolakaiConfig({ apiKey: process.env.OLAKAI_API_KEY });\n\n// Track any interaction\nolakai(\"event\", \"ai_activity\", {\n  prompt: \"input\",\n  response: \"output\",\n  tokens: 1500,\n  requestTime: 5000,\n  userEmail: \"user@example.com\",\n  chatId: \"conversation-id\",\n  taskExecutionId: \"uuid-shared-across-agents\",\n  task: \"Data Processing & Analysis\",\n  customData: { StepCount: 3, Success: 1 },\n});\n```\n\n```python\n# Python — initialize once\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\n# Track any interaction\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=\"input\",\n    response=\"output\",\n    tokens=1500,\n    requestTime=5000,\n    userEmail=\"user@example.com\",\n    chatId=\"conversation-id\",\n    taskExecutionId=\"uuid-shared-across-agents\",\n    task=\"Data Processing & Analysis\",\n    customData={\"StepCount\": 3, \"Success\": 1},\n))\n```\n"
  },
  {
    "path": "content/olakai/skills/new-project/SKILL.md",
    "content": "---\nname: new-project\ndescription: \"Build a new AI agent with Olakai monitoring from scratch — project setup, SDK integration, KPI configuration, and end-to-end validation\"\nmetadata:\n  revision: 1\n  updated-on: \"2026-03-10\"\n  source: maintainer\n  tags: \"olakai,new-project,agent,monitoring,kpi,governance\"\n---\n\n# Build a New AI Agent Project with Olakai\n\nThis skill guides you through creating a new AI agent that is fully integrated with Olakai for analytics, KPI tracking, and governance.\n\n## Prerequisites\n\nBefore starting, ensure:\n1. Olakai CLI installed: `npm install -g olakai-cli`\n2. CLI authenticated: `olakai login`\n3. API key for SDK (generated per-agent via CLI — see Step 2.2)\n\n## Why Custom KPIs Are Essential\n\nOlakai's core value is **tracking business-specific KPIs for your AI agents**. Without KPIs, you're tracking events without gaining actionable insights.\n\n**What you can measure with KPIs:**\n- Business outcomes (items processed, success rates, revenue impact)\n- Operational data (step counts, retry rates, execution time)\n- Quality indicators (error rates, user satisfaction signals)\n\n**Without KPIs configured:**\n- No dashboard KPIs beyond basic token counts\n- No aggregated performance views\n- No alerting thresholds\n- No ROI calculations\n\n> **Every agent should have 2-4 KPIs that answer: \"How do I know this agent is performing well?\"**\n\n> **KPIs created here belong to this specific agent only.** If you later create additional agents, each one needs its own KPI definitions — KPIs cannot be shared or reused across agents.\n\n## Understanding the customData to KPI Pipeline\n\nBefore diving into implementation, understand how data flows through Olakai:\n\n```\nSDK customData → CustomDataConfig (Schema) → Context Variable → KPI Formula → kpiData\n```\n\n### How It Works\n\n1. **customData** (SDK): Raw JSON you send with each event\n2. **CustomDataConfig** (Platform): Schema defining which fields are processed\n3. **Context Variables**: CustomDataConfig fields become available for formulas\n4. **KPI Formula**: Expression that computes a value (e.g., `SuccessRate * 100`)\n5. **kpiData** (Response): Computed KPI values returned with each event\n\n### Critical Rules\n\n| Rule | Consequence |\n|------|-------------|\n| Only CustomDataConfig fields become variables | Unregistered customData fields are NOT usable in KPIs |\n| Formula evaluation is case-insensitive | `stepCount`, `STEPCOUNT`, `StepCount` all work in formulas |\n| NUMBER configs need numeric values | Don't send `\"5\"` (string), send `5` (number) |\n| KPIs are unique per agent | Each KPI belongs to exactly one agent — create separately for each |\n\n### Built-in Context Variables (Always Available)\n\n| Variable | Type | Description |\n|----------|------|-------------|\n| `Prompt` | string | The prompt text sent to the LLM |\n| `Response` | string | The LLM response text |\n| `Documents count` | number | Number of attached documents |\n| `PII detected` | boolean | Whether PII was detected |\n| `PHI detected` | boolean | Whether PHI was detected |\n| `CODE detected` | boolean | Whether code was detected |\n| `SECRET detected` | boolean | Whether secrets were detected |\n\n## Step 1: Design the Agent Architecture\n\n### 1.1 Determine Agent Type\n\n**Agentic AI** (Multi-step autonomous workflows):\n- Research agents, document processors, data pipelines\n- Track as SINGLE events aggregating all internal LLM calls\n- Focus on workflow-level KPIs (total tokens, total time, success/failure)\n\n**Assistive AI** (Interactive chatbots/copilots):\n- Customer support agents, coding assistants, Q&A systems\n- Track EACH interaction as separate events\n- Focus on conversation-level KPIs (per-message tokens, response quality)\n\n### 1.2 Design Your KPI Schema (CRITICAL)\n\n**Design your KPIs BEFORE writing any SDK code.** This ensures only meaningful data is sent and tracked.\n\n#### Step A: Identify Business Questions\n\nWhat do stakeholders need to know about this agent?\n- \"How many items does it process per run?\"\n- \"What's the success/failure rate?\"\n- \"How efficient is each execution?\"\n\n#### Step B: Map Questions to Data Fields\n\n| Business Question | Field Name | Type | KPI Formula | Aggregation |\n|-------------------|------------|------|-------------|-------------|\n| Throughput | ItemsProcessed | NUMBER | `ItemsProcessed` | SUM |\n| Reliability | SuccessRate | NUMBER | `SuccessRate * 100` | AVERAGE |\n| Error count | SuccessRate | NUMBER | `IF(SuccessRate < 1, 1, 0)` | SUM |\n| Correlation | ExecutionId | STRING | (for filtering only) | - |\n\n#### Step C: Plan Your customData Structure\n\n```typescript\n// ONLY include fields you'll register as CustomDataConfigs\ncustomData: {\n  // Business KPIs\n  ItemsProcessed: number,  // Count of items handled\n  SuccessRate: number,     // 0-1 success ratio\n\n  // Performance KPIs\n  StepCount: number,       // Number of workflow steps\n\n  // Identification (for filtering, not KPIs)\n  ExecutionId: string,     // Correlation ID\n}\n```\n\n> **IMPORTANT**: Only include fields you will register as CustomDataConfigs. Unregistered fields are stored but **cannot be used in KPIs**.\n\n### What NOT to Include in customData\n\nThe Olakai platform automatically tracks these — do NOT duplicate them:\n\n| Already Tracked | Where | Don't Send As customData |\n|-----------------|-------|--------------------------|\n| Session ID | Main payload | `sessionId` |\n| Agent ID | API key association | `agentId` |\n| User email | `userEmail` parameter | `email`, `userEmail` |\n| Timestamp | Event metadata | `timestamp`, `createdAt` |\n| Request time | `requestTime` parameter | `duration`, `latency` |\n| Token count | `tokens` parameter | `tokenCount` |\n| Model | Auto-detected | `model`, `modelName` |\n| Provider | Client config | `provider` |\n\n**customData is ONLY for:**\n1. **KPI variables** — Fields you'll use in formula calculations\n2. **Tagging/filtering** — Fields you'll filter by in queries\n\n## Step 2: Configure Olakai Platform\n\n### 2.1 Create a Workflow (Required)\n\n> **Every agent MUST belong to a workflow**, even if it's the only agent in that workflow.\n\n```bash\nolakai workflows create --name \"Your Workflow Name\" --json\n# Output: { \"id\": \"wfl_xxx...\", \"name\": \"Your Workflow Name\" }\n```\n\n### 2.2 Create the Agent in Olakai\n\n```bash\nolakai agents create \\\n  --name \"Your Agent Name\" \\\n  --description \"What this agent does\" \\\n  --workflow WORKFLOW_ID \\\n  --with-api-key \\\n  --json\n\n# Returns agent details including apiKey:\n# {\n#   \"id\": \"cmkbteqn501kyjy4yu6p6xrrx\",\n#   \"name\": \"Your Agent Name\",\n#   \"workflowId\": \"wfl_xxx...\",\n#   \"apiKey\": \"sk_agent_xxxxx...\"   <-- Use this in your SDK\n# }\n```\n\n**Agent-Workflow Hierarchy:**\n```\nWorkflow: \"Customer Support Pipeline\"\n├── Agent: \"Ticket Classifier\"\n├── Agent: \"Response Generator\"\n└── Agent: \"Quality Checker\"\n\nWorkflow: \"Document Processing\"\n└── Agent: \"Document Summarizer\"  ← single-agent workflows are valid\n```\n\n### 2.3 Create Custom Data Configurations (BEFORE Writing SDK Code)\n\n> **This step MUST be completed before Step 3 (SDK Integration).** Only fields registered here can be used in KPI formulas.\n\n> **ONLY create configs for data you'll use in KPIs or for filtering.** Don't create configs for data already tracked automatically.\n\n```bash\n# For numeric fields (can be used in KPI calculations)\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"ItemsProcessed\" --type NUMBER\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"SuccessRate\" --type NUMBER\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"StepCount\" --type NUMBER\n\n# For string fields (for filtering/grouping, not calculations)\nolakai custom-data create --agent-id YOUR_AGENT_ID --name \"ExecutionId\" --type STRING\n\n# Verify all configs are created\nolakai custom-data list --agent-id YOUR_AGENT_ID\n```\n\n### 2.4 Create KPI Definitions\n\n#### Quick Start with Templates\n\nInstead of writing formulas from scratch, use predefined classifier templates:\n\n```bash\n# List available templates\nolakai kpis templates\n\n# Create a classifier KPI from a template\nolakai kpis create --name \"User Satisfaction\" \\\n  --calculator-id classifier --template-id sentiment_scorer \\\n  --scope CHAT --agent-id $AGENT_ID\n\n# Create a time-saved estimator\nolakai kpis create --name \"Time Saved\" \\\n  --calculator-id classifier --template-id time_saved_estimator \\\n  --scope CHAT --agent-id $AGENT_ID\n```\n\n#### Custom Formula KPIs\n\n```bash\n# Variable passthrough\nolakai kpis create \\\n  --name \"Items Processed\" \\\n  --agent-id YOUR_AGENT_ID \\\n  --calculator-id formula \\\n  --formula \"ItemsProcessed\" \\\n  --unit \"items\" \\\n  --aggregation SUM\n\n# Percentage calculation\nolakai kpis create \\\n  --name \"Success Rate\" \\\n  --agent-id YOUR_AGENT_ID \\\n  --calculator-id formula \\\n  --formula \"SuccessRate * 100\" \\\n  --unit \"%\" \\\n  --aggregation AVERAGE\n\n# Conditional counting\nolakai kpis create \\\n  --name \"Error Count\" \\\n  --agent-id YOUR_AGENT_ID \\\n  --calculator-id formula \\\n  --formula \"IF(SuccessRate < 1, 1, 0)\" \\\n  --unit \"errors\" \\\n  --aggregation SUM\n\n# Validate formulas before creating\nolakai kpis validate --formula \"ItemsProcessed\" --agent-id YOUR_AGENT_ID\n```\n\n## Step 3: Implement SDK Integration\n\n### 3.1 TypeScript Implementation\n\n**Install dependencies:**\n```bash\nnpm install @olakai/sdk openai\n```\n\n**Initialize and track:**\n```typescript\nimport { olakaiConfig, olakai } from \"@olakai/sdk\";\nimport OpenAI from \"openai\";\n\n// Initialize Olakai\nolakaiConfig({\n  apiKey: process.env.OLAKAI_API_KEY!,\n  debug: process.env.NODE_ENV === \"development\",\n});\n\n// Create LLM client\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// Use wrapped client — monitoring happens automatically\nconst response = await openai.chat.completions.create({\n  model: \"gpt-4o\",\n  messages: [{ role: \"user\", content: userPrompt }],\n});\n```\n\n**Agentic workflow with manual event tracking:**\n\n> **`taskExecutionId` — Cross-Agent Task Correlation.** Generate ONE `taskExecutionId` per task and share it across all agents in a multi-agent workflow. This links events from different agents into a single logical task for analytics.\n\n```typescript\nasync function runAgent(input: string): Promise<string> {\n  const startTime = Date.now();\n  const executionId = crypto.randomUUID();\n  const taskExecutionId = crypto.randomUUID();\n  let totalTokens = 0;\n  let stepCount = 0;\n  let itemsProcessed = 0;\n\n  try {\n    // Step 1: Planning\n    stepCount++;\n    const plan = await openai.chat.completions.create({\n      model: \"gpt-4o\",\n      messages: [{ role: \"user\", content: `Plan: ${input}` }],\n    });\n    totalTokens += plan.usage?.total_tokens ?? 0;\n\n    // Step 2: Process items\n    const items = parseItems(plan.choices[0].message.content);\n    for (const item of items) {\n      stepCount++;\n      const result = await openai.chat.completions.create({\n        model: \"gpt-4o\",\n        messages: [{ role: \"user\", content: `Process: ${item}` }],\n      });\n      totalTokens += result.usage?.total_tokens ?? 0;\n      itemsProcessed++;\n    }\n\n    // Step 3: Summarize\n    stepCount++;\n    const summary = await openai.chat.completions.create({\n      model: \"gpt-4o\",\n      messages: [{ role: \"user\", content: \"Summarize results\" }],\n    });\n    totalTokens += summary.usage?.total_tokens ?? 0;\n\n    const finalResponse = summary.choices[0].message.content ?? \"\";\n\n    // Track the complete workflow as a single event\n    // Only send fields that have CustomDataConfigs (from Step 2.3)\n    olakai(\"event\", \"ai_activity\", {\n      prompt: input,\n      response: finalResponse,\n      tokens: totalTokens,\n      requestTime: Date.now() - startTime,\n      taskExecutionId,\n      task: \"Data Processing & Analysis\",\n      customData: {\n        ExecutionId: executionId,\n        StepCount: stepCount,\n        ItemsProcessed: itemsProcessed,\n        SuccessRate: 1.0,\n      },\n    });\n\n    return finalResponse;\n  } catch (error) {\n    // Track failed execution — same fields, different values\n    olakai(\"event\", \"ai_activity\", {\n      prompt: input,\n      response: `Error: ${error instanceof Error ? error.message : \"Unknown\"}`,\n      tokens: totalTokens,\n      requestTime: Date.now() - startTime,\n      taskExecutionId,\n      task: \"Data Processing & Analysis\",\n      customData: {\n        ExecutionId: executionId,\n        StepCount: stepCount,\n        ItemsProcessed: itemsProcessed,\n        SuccessRate: 0,\n      },\n    });\n    throw error;\n  }\n}\n```\n\n### 3.2 Python Implementation\n\n**Install dependencies:**\n```bash\npip install olakai-sdk openai\n```\n\n**Initialize and track:**\n```python\nimport os\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\nfrom openai import OpenAI\n\n# Initialize Olakai\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\n# Create OpenAI client\nclient = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n```\n\n**Agentic workflow:**\n```python\nimport time\nimport uuid\n\ndef run_agent(input_text: str) -> str:\n    start_time = time.time()\n    execution_id = str(uuid.uuid4())\n    task_execution_id = str(uuid.uuid4())\n    total_tokens = 0\n    step_count = 0\n    items_processed = 0\n\n    try:\n        # Your workflow steps here...\n        step_count += 1\n        response = client.chat.completions.create(\n            model=\"gpt-4o\",\n            messages=[{\"role\": \"user\", \"content\": input_text}]\n        )\n        total_tokens += response.usage.total_tokens\n        final_response = response.choices[0].message.content\n\n        # Track successful execution\n        olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n            prompt=input_text,\n            response=final_response,\n            tokens=total_tokens,\n            requestTime=int((time.time() - start_time) * 1000),\n            taskExecutionId=task_execution_id,\n            task=\"Data Processing & Analysis\",\n            customData={\n                \"ExecutionId\": execution_id,\n                \"StepCount\": step_count,\n                \"ItemsProcessed\": items_processed,\n                \"SuccessRate\": 1.0,\n            }\n        ))\n\n        return final_response\n\n    except Exception as e:\n        olakai(\"event\", \"ai_activity\", OlakaiEventParams(\n            prompt=input_text,\n            response=f\"Error: {str(e)}\",\n            tokens=total_tokens,\n            requestTime=int((time.time() - start_time) * 1000),\n            taskExecutionId=task_execution_id,\n            task=\"Data Processing & Analysis\",\n            customData={\n                \"ExecutionId\": execution_id,\n                \"StepCount\": step_count,\n                \"ItemsProcessed\": items_processed,\n                \"SuccessRate\": 0,\n            }\n        ))\n        raise\n```\n\n### 3.3 REST API Direct Integration\n\nFor other languages or custom integrations:\n\n```bash\ncurl -X POST \"https://app.olakai.ai/api/monitoring/prompt\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-api-key: YOUR_API_KEY\" \\\n  -d '{\n    \"prompt\": \"User input here\",\n    \"response\": \"Agent response here\",\n    \"app\": \"your-agent-name\",\n    \"task\": \"Data Processing & Analysis\",\n    \"tokens\": 1500,\n    \"requestTime\": 5000,\n    \"customData\": {\n      \"ExecutionId\": \"abc-123\",\n      \"StepCount\": 5,\n      \"ItemsProcessed\": 10,\n      \"SuccessRate\": 1.0\n    }\n  }'\n```\n\n## Step 4: Test-Validate-Iterate Cycle\n\n**Always validate your implementation by running a test and inspecting the actual event data.**\n\n### 4.1 Run Your Agent\n\nExecute your agent with test data to generate at least one event.\n\n### 4.2 Fetch and Inspect the Event\n\n```bash\nolakai activity list --agent-id YOUR_AGENT_ID --limit 1 --json\nolakai activity get EVENT_ID --json\n```\n\n### 4.3 Validate Each Component\n\n**Check customData is present and correct:**\n```bash\nolakai activity get EVENT_ID --json | jq '.customData'\n```\n\n**Check KPIs are numeric (not strings):**\n```bash\nolakai activity get EVENT_ID --json | jq '.kpiData'\n```\n\n**CORRECT** — numeric values:\n```json\n{\n  \"Items Processed\": 10,\n  \"Success Rate\": 100\n}\n```\n\n**WRONG** — string values (broken formula):\n```json\n{\n  \"Items Processed\": \"itemsProcessed\"\n}\n```\nFix: `olakai kpis update KPI_ID --formula \"YourVariable\"`\n\n**WRONG** — null values:\nFix by verifying:\n1. CustomDataConfig exists: `olakai custom-data list --agent-id ID`\n2. Field name case matches exactly (case-sensitive)\n3. SDK actually sends the field in customData\n\n### 4.4 Validation Flow\n\n```\n1. Run agent (generate event)\n           ↓\n2. Fetch event: olakai activity get ID --json\n           ↓\n3. Check customData present? NO → Fix SDK code\n           ↓\n4. Check kpiData numeric? NO → Fix formula\n           ↓\n5. Check kpiData not null? NO → Create CustomDataConfig or fix field name\n           ↓\n✅ All validations pass — implementation complete\n```\n\n## Step 5: Production Checklist\n\nBefore deploying to production:\n\n- [ ] API key stored securely in environment variables\n- [ ] Error handling wraps all LLM calls\n- [ ] Failed executions still report events (with SuccessRate: 0)\n- [ ] All custom data fields have corresponding CustomDataConfig entries\n- [ ] KPI formulas validated and showing numeric values (not strings)\n- [ ] SDK configured with appropriate retries and timeouts\n- [ ] Sensitive data redaction enabled if needed\n\n## KPI Formula Reference\n\n### Supported Operators\n\n| Category | Operators |\n|----------|-----------|\n| Arithmetic | `+`, `-`, `*`, `/` |\n| Comparison | `<`, `<=`, `=`, `<>`, `>=`, `>` |\n| Logical | `AND`, `OR`, `NOT` |\n| Conditional | `IF(condition, true_val, false_val)`, `MAP(value, match1, out1, default)` |\n| Math | `ABS`, `MAX`, `MIN`, `AVERAGE`, `TRUNC` |\n| Null handling | `ISNA(value)`, `ISDEFINED(value)`, `NA()` |\n\n### Common Formula Patterns\n\n```bash\n--formula \"ItemsProcessed\"                              # passthrough\n--formula \"SuccessRate * 100\"                            # percentage (0-1 to 0-100)\n--formula \"IF(SuccessRate < 1, 1, 0)\"                    # conditional counting\n--formula \"IF(PII detected, 1, 0)\"                       # built-in variable\n--formula \"IF(ISDEFINED(MyField), MyField, 0)\"           # null-safe\n--formula \"IF(AND(StepCount > 5, SuccessRate < 0.9), 1, 0)\"  # compound conditions\n```\n\n### Aggregation Types\n\n| Aggregation | Use For | Example |\n|-------------|---------|---------|\n| `SUM` | Totals, counts | Total items processed across all runs |\n| `AVERAGE` | Rates, percentages | Average success rate |\n\n## Task Categories Reference\n\nUse these predefined task categories for the `task` field:\n\n| Category | Example Use |\n|----------|-------------|\n| Research & Intelligence | Competitive intelligence, market research |\n| Data Processing & Analysis | Data extraction, statistical analysis |\n| Content Development | Blog writing, technical documentation |\n| Content Refinement | Editing, proofreading |\n| Customer Experience | Complaint resolution, ticket triage |\n| Software Development | Code generation, code review, debugging |\n| Strategic Planning | Roadmap development, scenario planning |\n\n## Quick Reference\n\n```bash\n# CLI Commands\nolakai login                                              # Authenticate\nolakai workflows create --name \"Name\" --json              # Create workflow\nolakai agents create --name \"Name\" --workflow ID --with-api-key  # Register agent\nolakai custom-data create --agent-id ID --name X --type NUMBER   # Create custom field\nolakai kpis create --formula \"X\" --agent-id ID            # Create KPI\nolakai activity list --agent-id ID                        # View events\n```\n\n```typescript\n// TypeScript SDK\nimport { olakaiConfig, olakai } from \"@olakai/sdk\";\nolakaiConfig({ apiKey: process.env.OLAKAI_API_KEY });\n\nolakai(\"event\", \"ai_activity\", {\n  prompt: \"input\",\n  response: \"output\",\n  tokens: 1500,\n  task: \"Data Processing & Analysis\",\n  customData: { StepCount: 3, Success: 1 },\n});\n```\n\n```python\n# Python SDK\nfrom olakaisdk import olakai_config, olakai, OlakaiEventParams\nolakai_config(os.getenv(\"OLAKAI_API_KEY\"))\n\nolakai(\"event\", \"ai_activity\", OlakaiEventParams(\n    prompt=\"input\",\n    response=\"output\",\n    tokens=1500,\n    task=\"Data Processing & Analysis\",\n    customData={\"StepCount\": 3, \"Success\": 1},\n))\n```\n"
  },
  {
    "path": "content/omegaconf/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"OmegaConf Python package guide for hierarchical configuration, YAML loading, merges, interpolation, and structured configs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"omegaconf,config,yaml,dataclass,interpolation,python\"\n---\n\n# OmegaConf Python Package Guide\n\n## Golden Rule\n\nUse `omegaconf` when you need hierarchical configuration that can be loaded from YAML, Python containers, dataclasses, and CLI-style overrides through one API. For package version `2.3.0`, prefer the version-pinned `2.3_branch` docs instead of the previous `latest` URL, because `latest` currently tracks the `2.4.0.dev` branch.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"omegaconf==2.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"omegaconf==2.3.0\"\npoetry add \"omegaconf==2.3.0\"\n```\n\n## Initialize And Load Config\n\nOmegaConf can create configs from Python containers, YAML strings, YAML files, and dotlist or CLI overrides.\n\n### Create from a Python dict\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create(\n    {\n        \"app\": {\"name\": \"demo\", \"debug\": False},\n        \"db\": {\"host\": \"localhost\", \"port\": 5432},\n    }\n)\n\nprint(cfg.app.name)      # demo\nprint(cfg[\"db\"][\"port\"]) # 5432\n```\n\n### Load from YAML\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.load(\"config.yaml\")\nprint(cfg.db.host)\n```\n\nYou can also parse a YAML string:\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create(\n    \"\"\"\n    service:\n      host: 127.0.0.1\n      port: 8080\n    \"\"\"\n)\n```\n\n### Create overrides from CLI-style arguments\n\n```python\nfrom omegaconf import OmegaConf\n\nbase = OmegaConf.load(\"config.yaml\")\noverrides = OmegaConf.from_dotlist(\n    [\n        \"service.host=0.0.0.0\",\n        \"service.port=9000\",\n        \"features.search=true\",\n    ]\n)\n\ncfg = OmegaConf.merge(base, overrides)\n```\n\nUse `OmegaConf.from_cli()` when you want to parse the current process arguments directly.\n\n## Core Usage\n\n### Read and update values\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create({\"server\": {\"host\": \"localhost\", \"port\": 8080}})\n\ncfg.server.port = 8081\ncfg.server.host = \"127.0.0.1\"\n\nprint(cfg.server.port)\n```\n\nFor path-based access:\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create({\"server\": {\"host\": \"localhost\"}})\n\nprint(OmegaConf.select(cfg, \"server.host\"))\nOmegaConf.update(cfg, \"server.host\", \"api.internal\")\n```\n\n`OmegaConf.select()` is safer than direct attribute access when a path may be absent.\n\n### Merge multiple config sources\n\nThis is the main OmegaConf workflow: start with defaults, layer file config, then layer environment or CLI overrides.\n\n```python\nfrom omegaconf import OmegaConf\n\ndefaults = OmegaConf.create(\n    {\n        \"db\": {\"host\": \"localhost\", \"port\": 5432},\n        \"logging\": {\"level\": \"INFO\"},\n    }\n)\nfile_cfg = OmegaConf.load(\"config.yaml\")\ncli_cfg = OmegaConf.from_dotlist([\"logging.level=DEBUG\"])\n\ncfg = OmegaConf.merge(defaults, file_cfg, cli_cfg)\n```\n\nFast merge is available:\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.unsafe_merge(defaults, file_cfg, cli_cfg)\n```\n\nUse `unsafe_merge()` only when you do not need the input configs afterward. It is faster, but it destroys the merged inputs.\n\n### Structured configs with dataclasses\n\nStructured configs are the safest way to keep config typed and validated.\n\n```python\nfrom dataclasses import dataclass\nfrom omegaconf import MISSING, OmegaConf\n\n@dataclass\nclass MySQLConfig:\n    host: str = \"localhost\"\n    port: int = 3306\n\n@dataclass\nclass AppConfig:\n    debug: bool = False\n    db: MySQLConfig = MISSING\n\ncfg = OmegaConf.structured(AppConfig)\nprint(cfg.debug)      # False\nprint(cfg.db.host)    # raises until db is provided\n```\n\nPopulate it by merging in real values:\n\n```python\nruntime_cfg = OmegaConf.merge(\n    OmegaConf.structured(AppConfig),\n    {\"db\": {\"host\": \"db.internal\", \"port\": 3307}},\n)\n```\n\nTyped structured configs matter because OmegaConf validates assignments:\n\n```python\nruntime_cfg.db.port = 5432   # ok\n# runtime_cfg.db.port = \"5432\"  # implicit conversion may work for primitives\n# runtime_cfg.db.port = \"bad\"   # raises ValidationError\n```\n\n### Interpolation and environment-driven config\n\nUse interpolations to derive values from other nodes or environment variables.\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create(\n    {\n        \"db\": {\n            \"host\": \"localhost\",\n            \"port\": 5432,\n            \"url\": \"postgresql://${db.host}:${db.port}/app\",\n        },\n        \"workers\": \"${oc.env:APP_WORKERS,4}\",\n    }\n)\n\nprint(cfg.db.url)\nprint(cfg.workers)\n```\n\nImportant for `2.3.0`: use `${oc.env:NAME,default}` for environment lookups. Older `${env:NAME}` examples are obsolete.\n\n### Custom resolvers\n\nRegister resolvers once during process startup, then reference them in config.\n\n```python\nfrom omegaconf import OmegaConf\n\nif not OmegaConf.has_resolver(\"as_int\"):\n    OmegaConf.register_new_resolver(\"as_int\", lambda value: int(value))\n\ncfg = OmegaConf.create(\n    {\n        \"web\": {\n            \"workers\": \"${as_int:${oc.env:APP_WORKERS,4}}\",\n        }\n    }\n)\n\nprint(cfg.web.workers)\n```\n\nIf tests need a clean resolver registry, remove custom resolvers explicitly:\n\n```python\nOmegaConf.clear_resolver(\"as_int\")\n```\n\n### Convert back to plain Python or dataclass objects\n\n```python\nfrom dataclasses import dataclass\nfrom omegaconf import OmegaConf\n\n@dataclass\nclass Settings:\n    debug: bool = False\n\ncfg = OmegaConf.structured(Settings)\n\nplain = OmegaConf.to_container(cfg, resolve=True)\nobj = OmegaConf.to_object(cfg)\n```\n\nUse `to_container(resolve=True)` when you need a plain `dict` or `list` for serialization or for passing to libraries that do not understand `DictConfig` and `ListConfig`.\n\n### Save resolved config\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.create({\"host\": \"localhost\", \"url\": \"http://${host}:8080\"})\nOmegaConf.save(cfg=cfg, f=\"generated.yaml\", resolve=True)\n```\n\n## Configuration Inputs And Runtime Setup\n\nOmegaConf has no auth model. The practical setup concerns are where your config values come from and how strictly they are validated.\n\nCommon input sources:\n\n- checked-in YAML defaults\n- environment-specific YAML files\n- environment variables via `${oc.env:...}`\n- CLI or dotlist overrides from deployment tooling\n- dataclass-backed structured configs for validation\n\nA common application pattern is:\n\n```python\nfrom omegaconf import OmegaConf\n\ncfg = OmegaConf.merge(\n    OmegaConf.structured(AppConfig),\n    OmegaConf.load(\"defaults.yaml\"),\n    OmegaConf.load(\"local.yaml\"),\n    OmegaConf.from_dotlist([\"db.host=db.prod.internal\"]),\n)\n```\n\nResolve interpolations before handing the config to other libraries if they expect plain Python values:\n\n```python\nsettings = OmegaConf.to_container(cfg, resolve=True, throw_on_missing=True)\n```\n\n## Common Pitfalls\n\n- `OmegaConf.create()` returns `DictConfig` or `ListConfig`, not plain `dict` or `list`. Convert with `OmegaConf.to_container()` when another API expects native containers.\n- `OmegaConf.unsafe_merge()` is destructive. Do not reuse the inputs after calling it.\n- Missing values use `???` or `MISSING` and raise when accessed. Use `throw_on_missing=True` during export to fail fast before runtime.\n- Structured config fields enforce declared types. This is useful, but it can surface `ValidationError` earlier than plain-dict code expects.\n- If `struct` mode is enabled, adding unknown keys fails unless you temporarily open the config for mutation.\n\n```python\nfrom omegaconf import OmegaConf, open_dict\n\ncfg = OmegaConf.create({\"db\": {\"host\": \"localhost\"}})\nOmegaConf.set_struct(cfg, True)\n\nwith open_dict(cfg):\n    cfg.db.port = 5432\n```\n\n- Environment interpolation examples on blogs often still use `${env:VAR}`. On `2.3.0`, use `${oc.env:VAR}`.\n- Dataclass fields without a default are treated as missing. Plan for that when creating structured configs from schemas.\n\n## Version-Sensitive Notes For 2.3.0\n\n- PyPI still lists `2.3.0` as the stable release on March 12, 2026. The `latest` Read the Docs site is for the `2.4.0.dev` branch, so use `https://omegaconf.readthedocs.io/en/2.3_branch/` for stable `2.3.0` behavior.\n- The `2.3.0` release adds Python 3.11 support.\n- The `2.3.0` release adds support for ignoring structured-config fields whose metadata sets `omegaconf_ignore=True`.\n- `2.3.0` fixes a nested structured-config merge bug, so older workarounds around merge exceptions may be stale.\n- If you are upgrading from older 2.0 or early 2.1 examples, note that `${env}` is no longer the supported environment resolver and several resolver APIs changed in `2.2`.\n\n## Official Sources\n\n- Stable docs for `2.3.0`: https://omegaconf.readthedocs.io/en/2.3_branch/\n- Usage guide: https://omegaconf.readthedocs.io/en/2.3_branch/usage.html\n- Structured config guide: https://omegaconf.readthedocs.io/en/2.3_branch/structured_config.html\n- Custom resolvers guide: https://omegaconf.readthedocs.io/en/2.3_branch/custom_resolvers.html\n- Docs `latest` landing page: https://omegaconf.readthedocs.io/en/latest/\n- PyPI package page: https://pypi.org/project/omegaconf/\n- Official GitHub releases: https://github.com/omry/omegaconf/releases\n"
  },
  {
    "path": "content/onnx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"onnx package guide for Python covering model creation, load/save, checking, shape inference, external data, and model hub usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.20.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"onnx,python,ml,model-format,protobuf,shape-inference\"\n---\n\n# onnx Python Package Guide\n\n## What It Is\n\n`onnx` is the core Python package for working with ONNX model files and protobuf objects.\n\nUse it when you need to:\n\n- load or save `.onnx` models\n- inspect graphs, nodes, tensors, and metadata\n- validate models with `onnx.checker`\n- build or rewrite graphs with `onnx.helper`\n- infer shapes with `onnx.shape_inference`\n- work with large models that use external tensor data\n- download sample models from the ONNX Model Hub\n\nCommon imports:\n\n- `import onnx`\n- `from onnx import TensorProto, checker, helper, hub, numpy_helper, shape_inference`\n\nPractical boundary: `onnx` is primarily for model representation and tooling. If you need production inference, verify the runtime or backend separately.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `1.20.1`.\n- PyPI has an exact release page for `1.20.1`, but the versionless ONNX docs root may move ahead of `1.20.1`. Treat examples from `onnx.ai/onnx/` as current-maintainer guidance, then verify anything version-sensitive against the `1.20.x` release line.\n- The official `v1.20.1` release notes describe this as a patch release with important bug fixes and build-system changes rather than a large Python API shift.\n- PyPI publishes an optional `reference` extra: `pip install \"onnx[reference]==1.20.1\"`.\n\n## Install\n\nPin the package when you need reproducible tooling behavior:\n\n```bash\npython -m pip install \"onnx==1.20.1\"\n```\n\nIf you need the optional reference implementation dependencies:\n\n```bash\npython -m pip install \"onnx[reference]==1.20.1\"\n```\n\nVerify the installed version:\n\n```bash\npython -c \"import onnx; print(onnx.__version__)\"\n```\n\n## Quick Start: Load, Inspect, Validate\n\nStart by loading a model, checking it, and inspecting the graph shape before making changes.\n\n```python\nimport onnx\nfrom onnx import checker\n\nmodel = onnx.load(\"model.onnx\")\nchecker.check_model(model)\n\nprint(\"ir_version:\", model.ir_version)\nprint(\"producer:\", model.producer_name)\nprint(\"graph name:\", model.graph.name)\nprint(\"inputs:\", [value.name for value in model.graph.input])\nprint(\"outputs:\", [value.name for value in model.graph.output])\nprint(\"nodes:\", len(model.graph.node))\n```\n\nUse this pattern before writing graph-rewrite code. It catches malformed models early and gives you the key metadata you usually need for debugging.\n\n## Create And Save A Model\n\nThe Python API overview uses `onnx.helper` to build graphs and models. Be explicit about tensor types, shapes, and opset imports.\n\n```python\nimport onnx\nfrom onnx import TensorProto, checker, helper\n\ninput_info = helper.make_tensor_value_info(\"X\", TensorProto.FLOAT, [1, 2])\noutput_info = helper.make_tensor_value_info(\"Y\", TensorProto.FLOAT, [1, 2])\n\nconst_tensor = helper.make_tensor(\n    name=\"bias\",\n    data_type=TensorProto.FLOAT,\n    dims=[1, 2],\n    vals=[1.0, 1.0],\n)\n\nadd_node = helper.make_node(\"Add\", inputs=[\"X\", \"bias\"], outputs=[\"Y\"])\n\ngraph = helper.make_graph(\n    nodes=[add_node],\n    name=\"add_bias_graph\",\n    inputs=[input_info],\n    outputs=[output_info],\n    initializer=[const_tensor],\n)\n\nmodel = helper.make_model(\n    graph,\n    opset_imports=[helper.make_opsetid(\"\", 18)],\n    producer_name=\"context-hub-example\",\n)\n\nchecker.check_model(model)\nonnx.save_model(model, \"add_bias.onnx\")\n```\n\nPractical rules:\n\n- Set `opset_imports` deliberately instead of relying on whatever default your environment provides.\n- Run `checker.check_model(...)` before saving generated models.\n- Use `onnx.save_model(...)` for file output and `model.SerializeToString()` when another API needs raw bytes.\n\n## Convert Between NumPy Arrays And ONNX Tensors\n\n`onnx.numpy_helper` is the practical bridge when you need to inspect or inject tensor values.\n\n```python\nimport numpy as np\nfrom onnx import numpy_helper\n\narray = np.array([[1.0, 2.0]], dtype=np.float32)\ntensor = numpy_helper.from_array(array, name=\"weights\")\nround_trip = numpy_helper.to_array(tensor)\n\nprint(tensor.name)\nprint(round_trip.shape)\n```\n\nUse this for initializers, test fixtures, and model-inspection tools.\n\n## Shape Inference\n\nRun shape inference after graph edits so downstream code can rely on richer type information.\n\n```python\nimport onnx\nfrom onnx import shape_inference\n\nmodel = onnx.load(\"add_bias.onnx\")\ninferred = shape_inference.infer_shapes(model)\n\nfor value in inferred.graph.value_info:\n    print(value.name)\n```\n\nFor very large models or models stored with external data, prefer path-based APIs:\n\n```python\nfrom onnx import checker, shape_inference\n\nchecker.check_model(\"model.onnx\")\nshape_inference.infer_shapes_path(\"model.onnx\", \"model-inferred.onnx\")\n```\n\nThat avoids loading the entire protobuf into memory when you only need file-based validation or shape updates.\n\n## External Data For Large Models\n\nONNX supports storing tensor data outside the main `.onnx` file. This matters for large weights and for models near or above protobuf size limits.\n\n```python\nimport onnx\n\nmodel = onnx.load(\"model.onnx\")\n\nonnx.save_model(\n    model,\n    \"model-with-external-data.onnx\",\n    save_as_external_data=True,\n    all_tensors_to_one_file=True,\n    location=\"model.weights.bin\",\n    size_threshold=1024,\n)\n```\n\nUseful behaviors from the official docs:\n\n- `onnx.load(...)` loads external data by default.\n- If you need only the structure first, pass `load_external_data=False`.\n- After loading with `load_external_data=False`, call `onnx.load_external_data_for_model(model, base_dir)` when you are ready to resolve the tensor files.\n- For models larger than 2 GB, use the path-based checker and shape-inference APIs rather than object-based ones.\n\n## Model Hub Usage\n\n`onnx.hub` can download models from the ONNX Model Hub.\n\n```python\nfrom onnx import hub\n\nmodel = hub.load(\"mnist\")\nprint(model.graph.name)\n```\n\nTreat remote model loading as a trusted-source operation. The official hub docs explicitly place responsibility on the user to verify that the source is trusted and safe to extract or execute.\n\n## Configuration And Environment\n\nThere is no service authentication layer in `onnx`. The main configuration surface is about model compatibility and file handling:\n\n- Python version must satisfy the PyPI requirement for the package line you install.\n- Opset version matters when you create or transform graphs.\n- External-data paths matter when models store weights outside the main file.\n- Relative paths are resolved from the model location or the `base_dir` you pass when loading external tensor files.\n\nUseful checks in scripts and CI:\n\n```python\nimport onnx\n\nprint(\"onnx version:\", onnx.__version__)\n```\n\n```bash\npython -m pip show onnx\n```\n\n## Common Pitfalls\n\n- Do not assume the versionless docs root is patch-pinned to `1.20.1`.\n- Do not skip `checker.check_model(...)` after graph rewrites or generated-model output.\n- Do not rely on implicit opset defaults when you create models; set `opset_imports` explicitly.\n- Do not forget external tensor files when moving or packaging a model saved with `save_as_external_data=True`.\n- Do not load untrusted Hub content into sensitive environments without reviewing the source.\n- Do not assume `onnx` itself is the runtime you will use for production inference.\n\n## Official URLs Used For This Entry\n\n- API root: `https://onnx.ai/onnx/api/`\n- Python API overview: `https://onnx.ai/onnx/repo-docs/PythonAPIOverview.html`\n- Python intro: `https://onnx.ai/onnx/intro/python.html`\n- Model hub API: `https://onnx.ai/onnx/api/hub.html`\n- PyPI project: `https://pypi.org/project/onnx/`\n- Exact PyPI release: `https://pypi.org/project/onnx/1.20.1/`\n- Release notes: `https://github.com/onnx/onnx/releases/tag/v1.20.1`\n"
  },
  {
    "path": "content/onnxruntime/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"onnxruntime package guide for Python inference with InferenceSession, execution providers, SessionOptions, OrtValue, and I/O binding\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.24.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"onnxruntime,onnx,inference,machine-learning,execution-providers,cpu,gpu\"\n---\n\n# onnxruntime Python Package Guide\n\n## What It Does\n\n`onnxruntime` runs inference for models in ONNX or ORT format from Python. Use it when a model has already been exported and you need a fast runtime with CPU execution by default and optional hardware acceleration through execution providers.\n\nIt is an inference runtime, not a training framework and not the exporter itself.\n\n## Version-Sensitive Notes\n\n- The version used here and the latest PyPI release both showed `1.24.3` on `2026-03-12`.\n- PyPI metadata for `1.24.3` requires Python `>=3.10`.\n- `onnxruntime` is the CPU release. CUDA inference uses the separate `onnxruntime-gpu` package.\n- The official Python guide says only one of `onnxruntime` and `onnxruntime-gpu` should be installed in the same environment at a time.\n- Since ONNX Runtime `1.10`, the docs require explicit provider selection for non-CPU targets. CPU is the only case where omitting `providers=` is acceptable.\n- The `1.24.3` release is a patch release with bug fixes, security fixes, performance work, and execution-provider updates. The release notes also call out a Python map-input refcount fix and Python 3.14 CI enablement.\n\n## Install\n\nPin the runtime when you need reproducible behavior:\n\n```bash\npython -m pip install \"onnxruntime==1.24.3\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"onnxruntime==1.24.3\"\n```\n\nWith Poetry:\n\n```bash\npoetry add \"onnxruntime==1.24.3\"\n```\n\nIf you need CUDA, install `onnxruntime-gpu` in a separate environment instead of layering it on top of `onnxruntime`.\n\nIf you also need to export or validate models, install the exporter stack separately:\n\n- PyTorch export: `torch`\n- TensorFlow export: `tf2onnx`\n- scikit-learn export: `skl2onnx`\n- ONNX model inspection/checking: `onnx`\n\n## Minimal Inference Flow\n\nStart by loading the model, reading the real input and output names from the session, and feeding NumPy arrays that match the model types and shapes.\n\n```python\nfrom pathlib import Path\n\nimport numpy as np\nimport onnxruntime as ort\n\nmodel_path = Path(\"model.onnx\")\n\nsession = ort.InferenceSession(\n    model_path.as_posix(),\n    providers=[\"CPUExecutionProvider\"],\n)\n\ninput_meta = session.get_inputs()[0]\noutput_meta = session.get_outputs()[0]\n\nx = np.random.rand(1, 4).astype(np.float32)\n\ny = session.run(\n    [output_meta.name],\n    {input_meta.name: x},\n)[0]\n\nprint(y.shape)\n```\n\nFor quick scripts, `session.run(None, feed_dict)` returns all outputs. For production code, requesting only the outputs you need is usually clearer.\n\n## Choosing Execution Providers\n\nExecution providers determine where kernels run. Provider order is priority order, and ONNX Runtime will use a lower-priority provider when a higher-priority provider cannot execute a node.\n\nCheck the installed wheel first:\n\n```python\nimport onnxruntime as ort\n\nprint(ort.get_version_string())\nprint(ort.get_available_providers())\n```\n\nSafe provider selection pattern:\n\n```python\nimport onnxruntime as ort\n\navailable = ort.get_available_providers()\n\nif \"CUDAExecutionProvider\" in available:\n    providers = [\"CUDAExecutionProvider\", \"CPUExecutionProvider\"]\nelse:\n    providers = [\"CPUExecutionProvider\"]\n\nsession = ort.InferenceSession(\"model.onnx\", providers=providers)\nprint(session.get_providers())\n```\n\nProvider options can be passed inline as tuples:\n\n```python\nimport onnxruntime as ort\n\nsession = ort.InferenceSession(\n    \"model.onnx\",\n    providers=[\n        (\"CUDAExecutionProvider\", {\"device_id\": 0}),\n        \"CPUExecutionProvider\",\n    ],\n)\n```\n\nUse `onnxruntime` when you want CPU execution. Use `onnxruntime-gpu` when you actually need CUDA/TensorRT-backed inference.\n\n## Session Configuration\n\nThere is no authentication layer. Configuration is local process configuration:\n\n- which model file to load\n- which providers to register\n- provider-specific options\n- `SessionOptions` and optional per-run options\n\nUseful `SessionOptions` in practice:\n\n- `graph_optimization_level`\n- `intra_op_num_threads`\n- `inter_op_num_threads`\n- `enable_profiling`\n- `use_deterministic_compute`\n- `optimized_model_filepath`\n- `register_custom_ops_library(...)` for custom kernels\n\nExample:\n\n```python\nimport numpy as np\nimport onnxruntime as ort\n\nso = ort.SessionOptions()\nso.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL\nso.intra_op_num_threads = 1\nso.inter_op_num_threads = 1\nso.enable_profiling = True\nso.use_deterministic_compute = True\nso.optimized_model_filepath = \"model.optimized.ort\"\nso.add_session_config_entry(\"session.save_model_format\", \"ORT\")\n\nsession = ort.InferenceSession(\n    \"model.onnx\",\n    sess_options=so,\n    providers=[\"CPUExecutionProvider\"],\n)\n\ninput_name = session.get_inputs()[0].name\nsession.run(None, {input_name: np.zeros((1, 4), dtype=np.float32)})\nprofile_path = session.end_profiling()\nprint(profile_path)\n```\n\nNotes:\n\n- `inter_op_num_threads` controls parallelism across graph nodes.\n- `intra_op_num_threads` controls parallelism within nodes.\n- `optimized_model_filepath` only writes an optimized model if you set it.\n- If your model depends on custom ops, load the custom op shared library before running inference.\n\n## Inspect Inputs And Outputs Instead Of Hardcoding Names\n\nUse the model metadata APIs before building feeds:\n\n```python\nimport onnxruntime as ort\n\nsession = ort.InferenceSession(\"model.onnx\", providers=[\"CPUExecutionProvider\"])\n\nfor arg in session.get_inputs():\n    print(arg.name, arg.shape, arg.type)\n\nfor arg in session.get_outputs():\n    print(arg.name, arg.shape, arg.type)\n```\n\nThis avoids the common mistake of guessing names like `\"input\"` or `\"output\"` when the exporter generated something else.\n\n## Working With NumPy, OrtValue, And Device Memory\n\nThe common path is NumPy on CPU:\n\n```python\nimport numpy as np\nimport onnxruntime as ort\n\nx = np.ones((1, 3, 224, 224), dtype=np.float32)\nsession = ort.InferenceSession(\"model.onnx\", providers=[\"CPUExecutionProvider\"])\noutputs = session.run(None, {\"input\": x})\n```\n\nFor more control, create `OrtValue` objects explicitly:\n\n```python\nimport numpy as np\nimport onnxruntime as ort\n\nx = np.ones((1, 4), dtype=np.float32)\nort_value = ort.OrtValue.ortvalue_from_numpy(x)\n\nsession = ort.InferenceSession(\"model.onnx\", providers=[\"CPUExecutionProvider\"])\nresult = session.run(None, {\"input\": ort_value})\n```\n\nThe API docs note that some ONNX data types are not supported by NumPy, including bfloat16 and some float8 types. For those cases, the documented path is direct device binding, for example with Torch tensors on GPU.\n\n## I/O Binding For Device-Resident Data\n\nBy default, ONNX Runtime places inputs and outputs on CPU. If your pipeline already has tensors on an accelerator, use I/O binding to avoid extra device-to-CPU copies.\n\nInput on CPU, output copied back to CPU:\n\n```python\nimport numpy as np\nimport onnxruntime as ort\n\nx = np.ones((1, 4), dtype=np.float32)\nsession = ort.InferenceSession(\n    \"model.onnx\",\n    providers=[\"CUDAExecutionProvider\", \"CPUExecutionProvider\"],\n)\n\nbinding = session.io_binding()\nbinding.bind_cpu_input(\"input\", x)\nbinding.bind_output(\"output\")\n\nsession.run_with_iobinding(binding)\ny = binding.copy_outputs_to_cpu()[0]\n```\n\nFor fully device-resident workflows, bind `OrtValue` inputs and outputs on the target device and call `run_with_iobinding(...)`.\n\n## Async Execution\n\nIf you need asynchronous execution from Python, `run_async(...)` executes inference in a separate C++ thread and invokes a callback with the results.\n\n```python\nimport numpy as np\nimport onnxruntime as ort\n\nsession = ort.InferenceSession(\"model.onnx\", providers=[\"CPUExecutionProvider\"])\ninput_name = session.get_inputs()[0].name\n\ndef on_done(results, user_data, error):\n    if error:\n        raise RuntimeError(error)\n    print(results[0].shape)\n\nsession.run_async(\n    [session.get_outputs()[0].name],\n    {input_name: np.ones((1, 4), dtype=np.float32)},\n    on_done,\n    None,\n)\n```\n\nUse this only when you actually need callback-style execution. Most code is simpler with synchronous `run(...)`.\n\n## Common Pitfalls\n\n- Do not install both `onnxruntime` and `onnxruntime-gpu` in one environment.\n- Do not assume the model input name is `\"input\"` or the output name is `\"output\"`. Read them from `get_inputs()` and `get_outputs()`.\n- Match dtypes exactly. A large share of examples require `np.float32`, not Python floats or float64 NumPy arrays.\n- Match shapes exactly, including batch dimensions. Exported models often expect `NCHW` image tensors or fixed feature counts.\n- Do not assume the installed wheel actually exposes CUDA or another accelerator. Check `ort.get_available_providers()`.\n- For non-CPU execution, pass `providers=` explicitly. The docs call this out as required starting with ORT `1.10`.\n- By default, outputs land on CPU. If your surrounding pipeline is on GPU, use I/O binding to avoid unnecessary copies.\n- If your model uses custom operators, register the custom ops library before creating the session.\n- If you serialize optimized models, remember that `.ort` implies ORT model format, and you can also force it with `session.save_model_format=ORT`.\n\n## Official Sources Used\n\n- Python API docs: `https://onnxruntime.ai/docs/api/python/api_summary.html`\n- Python getting started: `https://onnxruntime.ai/docs/get-started/with-python.html`\n- Install guide: `https://onnxruntime.ai/docs/install/`\n- Execution providers overview: `https://onnxruntime.ai/docs/execution-providers/`\n- PyPI package page: `https://pypi.org/project/onnxruntime/`\n- `1.24.3` release notes: `https://github.com/Microsoft/onnxruntime/releases/tag/v1.24.3`\n"
  },
  {
    "path": "content/openai/docs/chat/go/DOC.md",
    "content": "---\nname: chat\ndescription: \"OpenAI API for text generation, chat completions, streaming, function calling, vision, embeddings, and assistants\"\nmetadata:\n  languages: \"go\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-09\"\n  source: community\n  tags: \"openai,chat,llm,ai\"\n---\n\n# OpenAI Go SDK Coding Guidelines\n\nYou are an OpenAI API coding expert. Help me with writing code using the OpenAI API calling the official Go SDK.\n\nYou can find the official SDK documentation and code samples here:\nhttps://platform.openai.com/docs/api-reference\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official OpenAI Go SDK to call OpenAI models.\n\n**Module:** `github.com/openai/openai-go`\n\n**Installation:**\n```bash\ngo get github.com/openai/openai-go\n```\n\n**APIs and Usage:**\n- **Primary API (Recommended):** `client.Responses.Create(...)`\n- **Legacy API (Still Supported):** `client.Chat.Completions.New(...)`\n\n## Initialization and API Key\n\nSet the `OPENAI_API_KEY` environment variable; the SDK picks it up automatically.\n\n```go\nimport (\n    \"github.com/openai/openai-go\"\n    \"github.com/openai/openai-go/option\"\n)\n\n// Uses OPENAI_API_KEY environment variable automatically\nclient := openai.NewClient()\n\n// Or pass the API key explicitly (not recommended for production)\n// client := openai.NewClient(option.WithAPIKey(\"your-api-key-here\"))\n```\n\nUse environment secrets or a secrets manager to keep keys out of source control.\n\n## Models (as of March 2026)\n\nUse typed model constants from the SDK — never hardcode strings directly.\n\nDefault choices:\n- **General Text Tasks:** `openai.ChatModelGPT4_1` (non-reasoning)\n- **Fast & Cost-Efficient:** `openai.ChatModelGPT4_1Mini`\n- **Cheapest / Fastest:** `openai.ChatModelGPT4_1Nano`\n\n```go\n// Typed constants — preferred\nmodel: openai.F(openai.ChatModelGPT4_1),\n\n// String literal — only when using a model not yet in constants\nmodel: openai.F(\"gpt-5.4\"),\n```\n\n## Basic Inference (Text Generation)\n\n### Primary Method: Responses API (Recommended)\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/openai/openai-go\"\n    \"github.com/openai/openai-go/responses\"\n)\n\nfunc main() {\n    client := openai.NewClient()\n\n    resp, err := client.Responses.New(context.Background(), responses.ResponseNewParams{\n        Model:        openai.F(\"gpt-4.1\"),\n        Instructions: openai.F(\"You are a helpful coding assistant.\"),\n        Input:        responses.ResponseNewParamsInputUnionString(\"How do I reverse a slice in Go?\"),\n    })\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(resp.OutputText())\n}\n```\n\n### Legacy Method: Chat Completions API\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/openai/openai-go\"\n)\n\nfunc main() {\n    client := openai.NewClient()\n\n    completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{\n        Model: openai.F(openai.ChatModelGPT4_1),\n        Messages: openai.F([]openai.ChatCompletionMessageParamUnion{\n            openai.SystemMessage(\"You are a helpful assistant.\"),\n            openai.UserMessage(\"How do I reverse a slice in Go?\"),\n        }),\n    })\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(completion.Choices[0].Message.Content)\n}\n```\n\n## The `openai.F()` Wrapper — Critical Pattern\n\n**All parameter fields in the Go SDK must be wrapped with `openai.F()`.**\nThis is Go-specific and does not appear in Python or JavaScript SDK docs.\n\n```go\n// CORRECT — all fields wrapped\nopenai.ChatCompletionNewParams{\n    Model:       openai.F(openai.ChatModelGPT4_1),\n    MaxTokens:   openai.F(int64(1024)),\n    Temperature: openai.F(0.7),\n    Messages:    openai.F([]openai.ChatCompletionMessageParamUnion{...}),\n}\n\n// WRONG — missing F() wrappers (will not compile)\nopenai.ChatCompletionNewParams{\n    Model:    openai.ChatModelGPT4_1,   // BAD\n    Messages: []openai.ChatCompletionMessageParamUnion{...}, // BAD\n}\n```\n\nUse `openai.Bool(true)` and `openai.Int(n)` as shortcuts for pointer-wrapped booleans and ints.\n\n## Streaming Responses\n\n### Responses API Streaming\n\n```go\nstream := client.Responses.NewStreaming(context.Background(), responses.ResponseNewParams{\n    Model: openai.F(\"gpt-4.1\"),\n    Input: responses.ResponseNewParamsInputUnionString(\"Write a short story about a robot.\"),\n})\n\nfor stream.Next() {\n    event := stream.Current()\n    fmt.Print(event.OutputText())\n}\nif err := stream.Err(); err != nil {\n    panic(err)\n}\n```\n\n### Chat Completions Streaming\n\n```go\nstream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{\n    Model: openai.F(openai.ChatModelGPT4_1),\n    Messages: openai.F([]openai.ChatCompletionMessageParamUnion{\n        openai.UserMessage(\"Tell me a joke\"),\n    }),\n})\n\nacc := openai.ChatCompletionAccumulator{}\nfor stream.Next() {\n    chunk := stream.Current()\n    acc.AddChunk(chunk)\n    if len(chunk.Choices) > 0 {\n        fmt.Print(chunk.Choices[0].Delta.Content)\n    }\n}\nif err := stream.Err(); err != nil {\n    panic(err)\n}\n// acc.Choices[0].Message.Content now holds the full assembled response\n```\n\n## Function Calling (Tools)\n\n```go\ntools := []openai.ChatCompletionToolParam{\n    {\n        Type: openai.F(openai.ChatCompletionToolTypeFunction),\n        Function: openai.F(openai.FunctionDefinitionParam{\n            Name:        openai.F(\"get_weather\"),\n            Description: openai.F(\"Get current weather for a city\"),\n            Parameters: openai.F(openai.FunctionParameters{\n                \"type\": \"object\",\n                \"properties\": map[string]interface{}{\n                    \"city\": map[string]string{\n                        \"type\":        \"string\",\n                        \"description\": \"City name\",\n                    },\n                },\n                \"required\": []string{\"city\"},\n            }),\n        }),\n    },\n}\n\nresp, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{\n    Model: openai.F(openai.ChatModelGPT4_1),\n    Messages: openai.F([]openai.ChatCompletionMessageParamUnion{\n        openai.UserMessage(\"What's the weather in Paris?\"),\n    }),\n    Tools: openai.F(tools),\n})\nif err != nil {\n    panic(err)\n}\n// Inspect resp.Choices[0].Message.ToolCalls for the model's invocation\nfor _, tc := range resp.Choices[0].Message.ToolCalls {\n    fmt.Printf(\"Function: %s, Args: %s\\n\", tc.Function.Name, tc.Function.Arguments)\n}\n```\n\n## Structured Outputs (JSON Schema)\n\n```go\nimport \"encoding/json\"\n\ntype Step struct {\n    Explanation string `json:\"explanation\"`\n    Output      string `json:\"output\"`\n}\ntype MathReasoning struct {\n    Steps       []Step `json:\"steps\"`\n    FinalAnswer string `json:\"final_answer\"`\n}\n\nschemaParam := openai.ResponseFormatJSONSchemaJSONSchemaParam{\n    Name:        openai.F(\"math_reasoning\"),\n    Description: openai.F(\"Step-by-step math solution\"),\n    Schema:      openai.F(generateSchema[MathReasoning]()),\n    Strict:      openai.Bool(true),\n}\n\nresp, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{\n    Model: openai.F(openai.ChatModelGPT4_1Mini),\n    Messages: openai.F([]openai.ChatCompletionMessageParamUnion{\n        openai.UserMessage(\"Solve: 8x + 31 = 2\"),\n    }),\n    ResponseFormat: openai.F[openai.ChatCompletionNewParamsResponseFormatUnion](\n        openai.ResponseFormatJSONSchemaParam{\n            Type:       openai.F(openai.ResponseFormatJSONSchemaTypeJSONSchema),\n            JSONSchema: openai.F(schemaParam),\n        },\n    ),\n})\n\nvar result MathReasoning\njson.Unmarshal([]byte(resp.Choices[0].Message.Content), &result)\nfmt.Println(result.FinalAnswer)\n```\n\n## Vision (Multimodal)\n\n```go\nresp, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{\n    Model: openai.F(openai.ChatModelGPT4_1Mini),\n    Messages: openai.F([]openai.ChatCompletionMessageParamUnion{\n        openai.UserMessageParts(\n            openai.TextPart(\"What is in this image?\"),\n            openai.ImagePart(\"https://example.com/image.jpg\"),\n        ),\n    }),\n})\n```\n\n## Embeddings\n\n```go\nresp, err := client.Embeddings.New(context.Background(), openai.EmbeddingNewParams{\n    Model: openai.F(openai.EmbeddingModelTextEmbedding3Small),\n    Input: openai.F(openai.EmbeddingNewParamsInputUnionString(\n        \"The quick brown fox jumps over the lazy dog.\",\n    )),\n})\nif err != nil {\n    panic(err)\n}\nfmt.Printf(\"Dimensions: %d\\n\", len(resp.Data[0].Embedding))\n```\n\n## Error Handling\n\n```go\nimport \"github.com/openai/openai-go/apierror\"\n\nresp, err := client.Chat.Completions.New(ctx, params)\nif err != nil {\n    var apiErr *apierror.Error\n    if errors.As(err, &apiErr) {\n        fmt.Printf(\"API error %d: %s\\n\", apiErr.StatusCode, apiErr.Message)\n        // apiErr.StatusCode: 401 auth, 429 rate limit, 500 server error\n    }\n    return err\n}\n```\n\n## Retries and Timeouts\n\n```go\nimport \"time\"\n\n// Configure retries at client level\nclient := openai.NewClient(\n    option.WithMaxRetries(5),\n)\n\n// Configure timeout via context (preferred)\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\n\n// Per-request options\nresp, err := client.Chat.Completions.New(ctx, params,\n    option.WithMaxRetries(3),\n)\n```\n\n## Microsoft Azure OpenAI\n\n```go\nclient := openai.NewClient(\n    option.WithBaseURL(\"https://your-endpoint.openai.azure.com/openai/deployments/your-deployment/\"),\n    option.WithAPIKey(os.Getenv(\"AZURE_OPENAI_API_KEY\")),\n    option.WithHeaderAdd(\"api-version\", \"2024-08-01-preview\"),\n)\n```\n\n## Notes\n\n- **`openai.F()`** is mandatory for all param fields — missing it causes a compile error.\n- **`openai.Bool()` / `openai.Int()`** are convenience wrappers for optional pointer types.\n- **Context is always first** in every API call — use `context.WithTimeout` in production.\n- Prefer the Responses API for new work; Chat Completions remains fully supported.\n- Both sync calls and streaming iterators (`stream.Next()`) follow the same pattern throughout the SDK.\n- Use `openai.ChatModelGPT4_1` typed constants; only use string literals for unreleased models.\n"
  },
  {
    "path": "content/openai/docs/chat/javascript/DOC.md",
    "content": "---\nname: chat\ndescription: \"OpenAI API for text generation, chat completions, streaming, function calling, vision, embeddings, and assistants\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.27.0\"\n  updated-on: \"2026-03-06\"\n  source: maintainer\n  tags: \"openai,chat,llm,ai\"\n---\n\n# OpenAI API Coding Guidelines (JavaScript/TypeScript)\n\nYou are an OpenAI API coding expert. Help me with writing code using the OpenAI API calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official OpenAI Node.js SDK for all OpenAI API interactions.\n\n- **Library Name:** OpenAI Node.js SDK\n- **NPM Package:** `openai`\n- **JSR Package:** `@openai/openai`\n\n**Installation:**\n\n```bash\n# NPM\nnpm install openai\n\n# JSR (Deno/Node.js)\ndeno add jsr:@openai/openai\nnpx jsr add @openai/openai\n```\n\n**Import Patterns:**\n\n```typescript\n// Correct - ES6 import\nimport OpenAI from 'openai';\n\n// Correct - with additional utilities\nimport OpenAI, { toFile } from 'openai';\n\n// JSR import for Deno\nimport OpenAI from 'jsr:@openai/openai';\n```\n\n## Initialization and API Key\n\nThe OpenAI library requires creating an `OpenAI` client instance for all API calls.\n\n```typescript\nimport OpenAI from 'openai';\n\n// Uses OPENAI_API_KEY environment variable automatically\nconst client = new OpenAI({\n  apiKey: process.env['OPENAI_API_KEY'], // This is the default and can be omitted\n});\n\n// Or pass API key directly\nconst client = new OpenAI({\n  apiKey: 'your-api-key-here'\n});\n```\n\n## Models (as of March 2026)\n\nDefault choices:\n- **General Text Tasks:** `gpt-5.4` (frontier) or `gpt-4.1` (non-reasoning)\n- **Complex Reasoning Tasks:** `gpt-5.4` or `gpt-5.4-pro`\n- **Fast & Cost-Efficient:** `gpt-5-mini` or `gpt-4.1-mini`\n- **Cheapest / Fastest:** `gpt-5-nano` or `gpt-4.1-nano`\n- **Audio Processing:** `gpt-audio` or `gpt-audio-mini`\n- **Vision Tasks:** `gpt-5.4` or `gpt-4.1`\n- **Agentic Coding:** `gpt-5.3-codex`\n- **Search (Chat Completions):** `gpt-5-search-api`, `gpt-4o-search-preview`, or `gpt-4o-mini-search-preview`\n\nFrontier (reasoning, configurable effort):\n- `gpt-5.4`, `gpt-5.4-2026-03-05`, `gpt-5.4-pro`, `gpt-5.4-pro-2026-03-05`\n- `gpt-5.2`, `gpt-5.2-2025-12-11`, `gpt-5.2-pro`\n- `gpt-5.1`, `gpt-5.1-2025-11-13`, `gpt-5.1-pro`\n- `gpt-5`, `gpt-5-2025-08-07`, `gpt-5-pro`\n- `gpt-5-mini`, `gpt-5-mini-2025-08-07`\n- `gpt-5-nano`, `gpt-5-nano-2025-08-07`\n\nNon-reasoning:\n- `gpt-4.1`, `gpt-4.1-2025-04-14`\n- `gpt-4.1-mini`, `gpt-4.1-mini-2025-04-14`\n- `gpt-4.1-nano`, `gpt-4.1-nano-2025-04-14`\n\nReasoning (o-series, succeeded by GPT-5):\n- `o3`, `o3-2025-04-16`, `o3-pro`, `o3-pro-2025-06-10`\n- `o4-mini`, `o4-mini-2025-04-16`\n- `o3-mini`, `o3-mini-2025-01-31`\n- `o1`, `o1-2024-12-17`\n\nDeep research: `o3-deep-research`, `o4-mini-deep-research`\n\nCodex (agentic coding, Responses API only):\n- `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.1-codex`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini`, `gpt-5-codex`\n\nAudio chat: `gpt-audio`, `gpt-audio-2025-08-28`, `gpt-audio-mini`\nRealtime: `gpt-realtime`, `gpt-realtime-2025-08-28`, `gpt-realtime-mini`\nTTS: `gpt-4o-mini-tts`, `gpt-4o-mini-tts-2025-12-15`, `tts-1`, `tts-1-hd`\nSTT: `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe-diarize`, `whisper-1`\nImage generation: `gpt-image-1.5`, `gpt-image-1.5-2025-12-16`, `gpt-image-1`, `gpt-image-1-mini`, `chatgpt-image-latest`\nEmbeddings: `text-embedding-3-large`, `text-embedding-3-small`, `text-embedding-ada-002`\nModeration: `omni-moderation-latest`\nSearch (Chat Completions only): `gpt-5-search-api`, `gpt-4o-search-preview`, `gpt-4o-mini-search-preview`\n\nLegacy (still available): `gpt-4o`, `gpt-4o-mini`, `gpt-4-turbo`, `gpt-3.5-turbo`\n\nDeprecated (shutdown scheduled):\n- `dall-e-3`, `dall-e-2` → May 12, 2026 (use `gpt-image-1`)\n- `o1-preview`, `o1-mini` → deprecated (use `o3` or `gpt-5`)\n- `codex-mini-latest` → shut down Feb 12, 2026\n- `chatgpt-4o-latest` → shut down Feb 17, 2026\n- `gpt-4o-realtime-preview` → Mar 24, 2026 (use `gpt-realtime`)\n- `gpt-4o-mini-audio-preview` → Mar 24, 2026 (use `gpt-audio-mini`)\n- `gpt-4.5-preview` → deprecated\n- Assistants API → sunset Aug 26, 2026 (migrate to Responses API)\n\n## Primary APIs\n\n### Responses API (Recommended)\n\nThe Responses API is the primary interface for text generation.\n\n```typescript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI({\n  apiKey: process.env['OPENAI_API_KEY'],\n});\n\nconst response = await client.responses.create({\n  model: 'gpt-5.4',\n  instructions: 'You are a coding assistant that talks like a pirate',\n  input: 'Are semicolons optional in JavaScript?',\n});\n\nconsole.log(response.output_text);\n```\n\n### Chat Completions API (Legacy but Supported)\n\nThe Chat Completions API remains fully supported for existing applications.\n\n```typescript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI({\n  apiKey: process.env['OPENAI_API_KEY'],\n});\n\nconst completion = await client.chat.completions.create({\n  model: 'gpt-5.4',\n  messages: [\n    { role: 'developer', content: 'Talk like a pirate.' },\n    { role: 'user', content: 'Are semicolons optional in JavaScript?' },\n  ],\n});\n\nconsole.log(completion.choices[0].message.content);\n```\n\n## API Resources Structure\n\nThe OpenAI client organizes endpoints into logical resource groupings:\n\n```typescript\n// Core API resources available on client\nclient.completions     // Text completions\nclient.chat           // Chat completions\nclient.embeddings     // Text embeddings\nclient.files          // File management\nclient.images         // Image generation\nclient.audio          // Audio processing\nclient.moderations    // Content moderation\nclient.models         // Model information\nclient.fineTuning     // Fine-tuning jobs\nclient.graders        // Model evaluation\n```\n\n## Streaming Responses\n\nBoth Responses and Chat Completions APIs support streaming for real-time output.\n\n### Responses API Streaming\n\n```typescript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI();\n\nconst stream = await client.responses.create({\n  model: 'gpt-5.4',\n  input: 'Say \"Sheep sleep deep\" ten times fast!',\n  stream: true,\n});\n\nfor await (const event of stream) {\n  console.log(event);\n}\n```\n\n### Chat Completions Streaming\n\n```typescript\nconst stream = await client.chat.completions.create({\n  model: 'gpt-5.4',\n  messages: [{ role: 'user', content: 'Count to 10' }],\n  stream: true,\n});\n\nfor await (const chunk of stream) {\n  process.stdout.write(chunk.choices[0]?.delta?.content || '');\n}\n```\n\n## File Uploads\n\nThe library supports multiple file upload formats for various use cases.\n\n```typescript\nimport fs from 'fs';\nimport OpenAI, { toFile } from 'openai';\n\nconst client = new OpenAI();\n\n// Method 1: Node.js fs.ReadStream (recommended for Node.js)\nawait client.files.create({\n  file: fs.createReadStream('input.jsonl'),\n  purpose: 'fine-tune'\n});\n\n// Method 2: Web File API\nawait client.files.create({\n  file: new File(['my bytes'], 'input.jsonl'),\n  purpose: 'fine-tune'\n});\n\n// Method 3: Fetch Response\nawait client.files.create({\n  file: await fetch('https://somesite/input.jsonl'),\n  purpose: 'fine-tune'\n});\n\n// Method 4: toFile helper utility\nawait client.files.create({\n  file: await toFile(Buffer.from('my bytes'), 'input.jsonl'),\n  purpose: 'fine-tune',\n});\n```\n\n## Advanced Configuration\n\n### Function Calling (Tools)\n\n```typescript\nconst completion = await client.chat.completions.create({\n  model: 'gpt-5.4',\n  messages: [{ role: 'user', content: 'What is the weather like today?' }],\n  tools: [\n    {\n      type: 'function',\n      function: {\n        name: 'get_current_weather',\n        description: 'Get the current weather in a given location',\n        parameters: {\n          type: 'object',\n          properties: {\n            location: {\n              type: 'string',\n              description: 'The city and state, e.g. San Francisco, CA',\n            },\n            unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },\n          },\n          required: ['location'],\n        },\n      },\n    },\n  ],\n  tool_choice: 'auto',\n});\n```\n\n### Temperature and Sampling Parameters\n\nConfigure model behavior using parameters in the chat completions API:\n\n```typescript\nconst completion = await client.chat.completions.create({\n  model: 'gpt-5.4',\n  messages: [{ role: 'user', content: 'Write a creative story' }],\n  temperature: 0.8,        // Higher = more creative (0-2)\n  max_tokens: 1000,        // Maximum response length\n  top_p: 0.9,             // Nucleus sampling\n  frequency_penalty: 0.1,  // Reduce repetition\n  presence_penalty: 0.1,   // Encourage new topics\n});\n```\n\n### Structured Outputs (JSON Mode)\n\n```typescript\nconst completion = await client.chat.completions.create({\n  model: 'gpt-5.4',\n  messages: [\n    { role: 'user', content: 'Extract the name and age from: \"John is 30 years old\"' }\n  ],\n  response_format: {\n    type: 'json_object'\n  },\n});\n\nconst result = JSON.parse(completion.choices[0].message.content);\n```\n\n## Error Handling\n\nThe library provides specific error types for different failure scenarios:\n\n```typescript\nimport OpenAI from 'openai';\n\nconst client = new OpenAI();\n\ntry {\n  const completion = await client.chat.completions.create({\n    model: 'gpt-5.4',\n    messages: [{ role: 'user', content: 'Hello!' }],\n  });\n} catch (error) {\n  if (error instanceof OpenAI.RateLimitError) {\n    console.log('Rate limit exceeded');\n  } else if (error instanceof OpenAI.AuthenticationError) {\n    console.log('Invalid API key');\n  } else if (error instanceof OpenAI.APIError) {\n    console.log(error.status);  // HTTP status code\n    console.log(error.name);    // Error name\n    console.log(error.headers); // Response headers\n  } else {\n    console.log('Unexpected error:', error);\n  }\n}\n```\n\n## Common Patterns\n\n### Retry Logic with Exponential Backoff\n\n```typescript\nasync function createCompletionWithRetry(messages: any[], maxRetries = 3) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await client.chat.completions.create({\n        model: 'gpt-5.4',\n        messages,\n      });\n    } catch (error) {\n      if (error instanceof OpenAI.RateLimitError && attempt < maxRetries) {\n        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff\n        await new Promise(resolve => setTimeout(resolve, delay));\n        continue;\n      }\n      throw error;\n    }\n  }\n}\n```\n\n### Conversation Management\n\n```typescript\nclass ChatSession {\n  private messages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\n\n  constructor(private client: OpenAI, systemPrompt?: string) {\n    if (systemPrompt) {\n      this.messages.push({ role: 'system', content: systemPrompt });\n    }\n  }\n\n  async sendMessage(content: string) {\n    this.messages.push({ role: 'user', content });\n\n    const completion = await this.client.chat.completions.create({\n      model: 'gpt-5.4',\n      messages: this.messages,\n    });\n\n    const response = completion.choices[0].message;\n    this.messages.push(response);\n\n    return response.content;\n  }\n}\n```\n\n## Useful Links\n\n- **Documentation:** https://platform.openai.com/docs/api-reference\n- **API Keys:** https://platform.openai.com/api-keys\n- **Models:** https://platform.openai.com/docs/models\n- **Pricing:** https://openai.com/pricing\n- **Rate Limits:** https://platform.openai.com/docs/guides/rate-limits\n"
  },
  {
    "path": "content/openai/docs/chat/python/DOC.md",
    "content": "---\nname: chat\ndescription: \"OpenAI API for text generation, chat completions, streaming, function calling, vision, embeddings, and assistants\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.26.0\"\n  updated-on: \"2026-03-06\"\n  source: maintainer\n  tags: \"openai,chat,llm,ai\"\n---\n\n# OpenAI Python SDK Coding Guidelines\n\nYou are an OpenAI API coding expert. Help me with writing code using the OpenAI API calling the official Python SDK.\n\nYou can find the official SDK documentation and code samples here:\nhttps://platform.openai.com/docs/api-reference\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official OpenAI Python SDK to call OpenAI models, which is the standard library for all OpenAI API interactions.\n\n**Library Name:** OpenAI Python SDK\n**PyPI Package:** `openai`\n\n**Installation:**\n- **Correct:** `pip install openai`\n\n**APIs and Usage:**\n- **Correct:** `from openai import OpenAI`\n- **Correct:** `client = OpenAI()`\n- **Primary API (Recommended):** `client.responses.create(...)`\n- **Legacy API (Still Supported):** `client.chat.completions.create(...)`\n\n## Initialization and API Key\n\nSet the `OPENAI_API_KEY` environment variable; the SDK will pick it up automatically.\n\n```python\nimport os\nfrom openai import OpenAI\n\n# Uses the OPENAI_API_KEY environment variable\nclient = OpenAI()\n\n# Or pass the API key directly (not recommended for production)\n# client = OpenAI(api_key=\"your-api-key-here\")\n```\n\nUse `python-dotenv` or your secret manager of choice to keep keys out of source control.\n\n## Models (as of March 2026)\n\nDefault choices:\n- **General Text Tasks:** `gpt-5.4` (frontier) or `gpt-4.1` (non-reasoning)\n- **Complex Reasoning Tasks:** `gpt-5.4` or `gpt-5.4-pro`\n- **Fast & Cost-Efficient:** `gpt-5-mini` or `gpt-4.1-mini`\n- **Cheapest / Fastest:** `gpt-5-nano` or `gpt-4.1-nano`\n- **Audio Processing:** `gpt-audio` or `gpt-audio-mini`\n- **Vision Tasks:** `gpt-5.4` or `gpt-4.1`\n- **Agentic Coding:** `gpt-5.3-codex`\n- **Search (Chat Completions):** `gpt-5-search-api`, `gpt-4o-search-preview`, or `gpt-4o-mini-search-preview`\n\nFrontier (reasoning, configurable effort):\n- `gpt-5.4`, `gpt-5.4-2026-03-05`, `gpt-5.4-pro`, `gpt-5.4-pro-2026-03-05`\n- `gpt-5.2`, `gpt-5.2-2025-12-11`, `gpt-5.2-pro`\n- `gpt-5.1`, `gpt-5.1-2025-11-13`, `gpt-5.1-pro`\n- `gpt-5`, `gpt-5-2025-08-07`, `gpt-5-pro`\n- `gpt-5-mini`, `gpt-5-mini-2025-08-07`\n- `gpt-5-nano`, `gpt-5-nano-2025-08-07`\n\nNon-reasoning:\n- `gpt-4.1`, `gpt-4.1-2025-04-14`\n- `gpt-4.1-mini`, `gpt-4.1-mini-2025-04-14`\n- `gpt-4.1-nano`, `gpt-4.1-nano-2025-04-14`\n\nReasoning (o-series, succeeded by GPT-5):\n- `o3`, `o3-2025-04-16`, `o3-pro`, `o3-pro-2025-06-10`\n- `o4-mini`, `o4-mini-2025-04-16`\n- `o3-mini`, `o3-mini-2025-01-31`\n- `o1`, `o1-2024-12-17`\n\nDeep research: `o3-deep-research`, `o4-mini-deep-research`\n\nCodex (agentic coding, Responses API only):\n- `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.1-codex`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini`, `gpt-5-codex`\n\nAudio chat: `gpt-audio`, `gpt-audio-2025-08-28`, `gpt-audio-mini`\nRealtime: `gpt-realtime`, `gpt-realtime-2025-08-28`, `gpt-realtime-mini`\nTTS: `gpt-4o-mini-tts`, `gpt-4o-mini-tts-2025-12-15`, `tts-1`, `tts-1-hd`\nSTT: `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe-diarize`, `whisper-1`\nImage generation: `gpt-image-1.5`, `gpt-image-1.5-2025-12-16`, `gpt-image-1`, `gpt-image-1-mini`, `chatgpt-image-latest`\nEmbeddings: `text-embedding-3-large`, `text-embedding-3-small`, `text-embedding-ada-002`\nModeration: `omni-moderation-latest`\nSearch (Chat Completions only): `gpt-5-search-api`, `gpt-4o-search-preview`, `gpt-4o-mini-search-preview`\n\nLegacy (still available): `gpt-4o`, `gpt-4o-mini`, `gpt-4-turbo`, `gpt-3.5-turbo`\n\nDeprecated (shutdown scheduled):\n- `dall-e-3`, `dall-e-2` → May 12, 2026 (use `gpt-image-1`)\n- `o1-preview`, `o1-mini` → deprecated (use `o3` or `gpt-5`)\n- `codex-mini-latest` → shut down Feb 12, 2026\n- `chatgpt-4o-latest` → shut down Feb 17, 2026\n- `gpt-4o-realtime-preview` → Mar 24, 2026 (use `gpt-realtime`)\n- `gpt-4o-mini-audio-preview` → Mar 24, 2026 (use `gpt-audio-mini`)\n- `gpt-4.5-preview` → deprecated\n- Assistants API → sunset Aug 26, 2026 (migrate to Responses API)\n\n## Basic Inference (Text Generation)\n\n### Primary Method: Responses API (Recommended)\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nresponse = client.responses.create(\n    model=\"gpt-5.4\",\n    instructions=\"You are a helpful coding assistant.\",\n    input=\"How do I reverse a string in Python?\",\n)\n\nprint(response.output_text)\n```\n\n### Legacy Method: Chat Completions API\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\ncompletion = client.chat.completions.create(\n    model=\"gpt-4.1\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n        {\"role\": \"user\", \"content\": \"How do I reverse a string in Python?\"},\n    ],\n)\n\nprint(completion.choices[0].message.content)\n```\n\n## Vision (Multimodal Inputs)\n\n### With Image URL (Responses API)\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nresponse = client.responses.create(\n    model=\"gpt-4.1-mini\",\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What is in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.jpg\"},\n            ],\n        }\n    ],\n)\n```\n\n### With Base64 Encoded Image\n\n```python\nimport base64\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nwith open(\"path/to/image.png\", \"rb\") as image_file:\n    b64_image = base64.b64encode(image_file.read()).decode(\"utf-8\")\n\nresponse = client.responses.create(\n    model=\"gpt-4.1-mini\",\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What is in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": f\"data:image/png;base64,{b64_image}\"},\n            ],\n        }\n    ],\n)\n```\n\n## Async Usage\n\n```python\nimport asyncio\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI()\n\nasync def main():\n    response = await client.responses.create(\n        model=\"gpt-5.4\",\n        input=\"Explain quantum computing to a beginner.\"\n    )\n    print(response.output_text)\n\nasyncio.run(main())\n```\n\nOptionally use `aiohttp` backend via `pip install openai[aiohttp]` and instantiate with `DefaultAioHttpClient()`.\n\n## Streaming Responses\n\n### Responses API Streaming\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nstream = client.responses.create(\n    model=\"gpt-5.4\",\n    input=\"Write a short story about a robot.\",\n    stream=True,\n)\n\nfor event in stream:\n    print(event)\n```\n\n### Chat Completions Streaming\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nstream = client.chat.completions.create(\n    model=\"gpt-4.1\",\n    messages=[{\"role\": \"user\", \"content\": \"Tell me a joke\"}],\n    stream=True,\n)\n\nfor chunk in stream:\n    if chunk.choices[0].delta.content is not None:\n        print(chunk.choices[0].delta.content, end=\"\")\n```\n\n## Function Calling (Tools)\n\nType-safe function calling with Pydantic helpers.\n\n```python\nfrom pydantic import BaseModel\nfrom openai import OpenAI\nimport openai\n\nclass WeatherQuery(BaseModel):\n    \"\"\"Get the current weather for a location\"\"\"\n    location: str\n    unit: str = \"celsius\"\n\nclient = OpenAI()\n\ncompletion = client.chat.completions.parse(\n    model=\"gpt-4.1\",\n    messages=[{\"role\": \"user\", \"content\": \"What's the weather like in Paris?\"}],\n    tools=[openai.pydantic_function_tool(WeatherQuery)],\n)\n\nif completion.choices[0].message.tool_calls:\n    for tool_call in completion.choices[0].message.tool_calls:\n        if getattr(tool_call, \"parsed_arguments\", None):\n            print(tool_call.parsed_arguments.location)\n```\n\n## Structured Outputs\n\nAuto-parse JSON into Pydantic models.\n\n```python\nfrom typing import List\nfrom pydantic import BaseModel\nfrom openai import OpenAI\n\nclass Step(BaseModel):\n    explanation: str\n    output: str\n\nclass MathResponse(BaseModel):\n    steps: List[Step]\n    final_answer: str\n\nclient = OpenAI()\ncompletion = client.chat.completions.parse(\n    model=\"gpt-4.1\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are a helpful math tutor.\"},\n        {\"role\": \"user\", \"content\": \"solve 8x + 31 = 2\"},\n    ],\n    response_format=MathResponse,\n)\n\nmessage = completion.choices[0].message\nif message.parsed:\n    print(message.parsed.final_answer)\n```\n\n## Audio Capabilities\n\n### Speech Synthesis (Text-to-Speech)\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nresponse = client.audio.speech.create(\n    model=\"gpt-4o-mini-tts\",\n    voice=\"alloy\",\n    input=\"Hello, this is a test of the text to speech API.\"\n)\n\nwith open(\"output.mp3\", \"wb\") as f:\n    f.write(response.content)\n```\n\n### Audio Transcription\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nwith open(\"audio.mp3\", \"rb\") as audio_file:\n    transcription = client.audio.transcriptions.create(\n        model=\"gpt-4o-transcribe\",\n        file=audio_file\n    )\nprint(transcription.text)\n```\n\n### Audio Translation\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nwith open(\"audio.mp3\", \"rb\") as audio_file:\n    translation = client.audio.translations.create(\n        model=\"whisper-1\",\n        file=audio_file\n    )\nprint(translation.text)\n```\n\n## File Operations\n\n### Upload Files\n\n```python\nfrom pathlib import Path\nfrom openai import OpenAI\nclient = OpenAI()\n\nfile_response = client.files.create(\n    file=Path(\"training_data.jsonl\"),\n    purpose=\"fine-tune\"\n)\n\nprint(f\"File ID: {file_response.id}\")\n```\n\n### Retrieve, Download, Delete Files\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\n# List files\nfiles = client.files.list()\n\n# Retrieve a specific file\nfile_info = client.files.retrieve(\"file-abc123\")\n\n# Download file content\nfile_content = client.files.content(\"file-abc123\")\n\n# Delete a file\nclient.files.delete(\"file-abc123\")\n```\n\n## Embeddings\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nresponse = client.embeddings.create(\n    model=\"text-embedding-3-small\",\n    input=\"The quick brown fox jumps over the lazy dog.\"\n)\n\nembeddings = response.data[0].embedding\nprint(f\"Embedding dimensions: {len(embeddings)}\")\n```\n\n## Image Generation\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nresponse = client.images.generate(\n    model=\"gpt-image-1.5\",\n    prompt=\"A futuristic city skyline at sunset\",\n    size=\"1024x1024\",\n    quality=\"standard\",\n    n=1,\n)\n\nimage_url = response.data[0].url\nprint(f\"Generated image: {image_url}\")\n```\n\n## Error Handling\n\n```python\nimport openai\nfrom openai import OpenAI\nclient = OpenAI()\n\ntry:\n    response = client.responses.create(model=\"gpt-5.4\", input=\"Hello, world!\")\nexcept openai.RateLimitError:\n    print(\"Rate limit exceeded. Please wait before retrying.\")\nexcept openai.APIConnectionError:\n    print(\"Failed to connect to OpenAI API.\")\nexcept openai.AuthenticationError:\n    print(\"Invalid API key provided.\")\nexcept openai.APIStatusError as e:\n    print(f\"API error occurred: {e.status_code}\")\n    print(f\"Error response: {e.response}\")\n```\n\n## Request IDs and Debugging\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()\n\nresponse = client.responses.create(model=\"gpt-5.4\", input=\"Test message\")\nprint(f\"Request ID: {response._request_id}\")\n```\n\n## Retries and Timeouts\n\n```python\nfrom openai import OpenAI\n\n# Configure retries\nclient = OpenAI(max_retries=5)\n\n# Configure timeouts\nclient = OpenAI(timeout=30.0)\n\n# Per-request configuration\nresponse = client.with_options(\n    max_retries=3,\n    timeout=60.0\n).responses.create(\n    model=\"gpt-5.4\",\n    input=\"Hello\"\n)\n```\n\n## Realtime API\n\n```python\nimport asyncio\nfrom openai import AsyncOpenAI\n\nasync def main():\n    client = AsyncOpenAI()\n\n    async with client.realtime.connect(model=\"gpt-realtime\") as connection:\n        await connection.session.update(session={'modalities': ['text']})\n\n        await connection.conversation.item.create(\n            item={\n                \"type\": \"message\",\n                \"role\": \"user\",\n                \"content\": [{\"type\": \"input_text\", \"text\": \"Say hello!\"}],\n            }\n        )\n        await connection.response.create()\n\n        async for event in connection:\n            if event.type == \"response.output_text.delta\":\n                print(event.delta, end=\"\")\n            elif event.type == \"response.done\":\n                break\n\nasyncio.run(main())\n```\n\n## Microsoft Azure OpenAI\n\n```python\nfrom openai import AzureOpenAI\n\nclient = AzureOpenAI(\n    azure_endpoint=\"https://your-endpoint.openai.azure.com\",\n)\n\ncompletion = client.chat.completions.create(\n    model=\"deployment-name\",  # Your deployment name\n    messages=[{\"role\": \"user\", \"content\": \"Hello, Azure OpenAI!\"}],\n)\nprint(completion.choices[0].message.content)\n```\n\n## Webhook Verification\n\n```python\nfrom flask import Flask, request\nfrom openai import OpenAI\n\napp = Flask(__name__)\nclient = OpenAI()  # Uses OPENAI_WEBHOOK_SECRET environment variable\n\n@app.route(\"/webhook\", methods=[\"POST\"])\ndef webhook():\n    request_body = request.get_data(as_text=True)\n\n    try:\n        event = client.webhooks.unwrap(request_body, request.headers)\n\n        if event.type == \"response.completed\":\n            print(\"Response completed:\", event.data)\n\n        return \"ok\"\n    except Exception as e:\n        print(\"Invalid signature:\", e)\n        return \"Invalid signature\", 400\n```\n\n## Pagination\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\n# Automatic pagination\nall_files = []\nfor file in client.files.list(limit=20):\n    all_files.append(file)\n\n# Manual pagination\nfirst_page = client.files.list(limit=20)\nif first_page.has_next_page():\n    next_page = first_page.get_next_page()\n```\n\n## Notes\n\n- Prefer the Responses API for new work; Chat Completions remains supported.\n- Keep API keys in env vars or a secret manager.\n- Both sync and async clients are available; interfaces mirror each other.\n- Use streaming for lower latency UX.\n- Pydantic-based structured outputs and function calling provide type safety.\n"
  },
  {
    "path": "content/openai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"openai package guide for Python with OpenAI(), AsyncOpenAI(), Responses API, streaming, webhooks, pagination, and AzureOpenAI notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.26.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"openai,python,sdk,llm,responses,chat,streaming,webhooks\"\n---\n\n# openai Python Package Guide\n\n## Golden Rule\n\n- Use the official `openai` package and instantiate an explicit client with `OpenAI()` or `AsyncOpenAI()`.\n- Prefer `client.responses.create(...)` for new text, multimodal, and tool-using workflows.\n- Keep secrets in environment variables, not source code. For core API usage that usually means `OPENAI_API_KEY`. For webhook verification it also means `OPENAI_WEBHOOK_SECRET`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `2.26.0`.\n- Upstream currently publishes `v2.26.0` as the latest GitHub release and PyPI package version, so the version used here matches current upstream.\n- `openai` requires Python `>=3.9`.\n- The maintainers describe the package as generally following SemVer, but they reserve some backwards-incompatible changes for minor releases when the impact is limited to static typing, internals, or low-impact runtime behavior. Do not assume every `2.x` minor bump is completely frictionless.\n- The SDK README describes the Responses API as the primary API for model interaction. Chat Completions remains supported, but it is no longer the default shape to copy for new code.\n- `AzureOpenAI` is a separate client class, and the README explicitly warns that Azure API shapes differ from the core OpenAI API shapes, so static response and parameter types may not always line up perfectly.\n\n## Install\n\nPin the version when you need reproducible behavior:\n\n```bash\npython -m pip install \"openai==2.26.0\"\n```\n\nIf you want the optional `aiohttp` backend for the async client:\n\n```bash\npython -m pip install \"openai[aiohttp]==2.26.0\"\n```\n\n## Recommended Setup\n\nStart with environment variables and a single long-lived client per process or request scope.\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n```\n\nIf you need to manage connection cleanup explicitly, use a context manager:\n\n```python\nfrom openai import OpenAI\n\nwith OpenAI() as client:\n    response = client.responses.create(\n        model=\"gpt-4.1\",\n        input=\"Ping\",\n    )\n    print(response.output_text)\n```\n\n## Core Usage\n\n### Responses API For New Code\n\nUse `responses.create()` for new projects unless you have a specific reason to stay on Chat Completions.\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nresponse = client.responses.create(\n    model=\"gpt-4.1\",\n    instructions=\"You are a concise coding assistant.\",\n    input=\"How do I reverse a list in Python?\",\n)\n\nprint(response.output_text)\nprint(response._request_id)\n```\n\nUseful request fields to reach for first:\n\n- `model`\n- `input`\n- `instructions`\n- `tools`\n- `previous_response_id`\n- `stream=True`\n\nThe official Responses API reference is the right place to confirm request shapes for built-in tools, conversation state, structured outputs, and multimodal inputs.\n\n### Chat Completions For Existing Code\n\nThe SDK still supports Chat Completions. Keep using it when the codebase already depends on it or when you want the SDK parsing helpers documented under `helpers.md`.\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\ncompletion = client.chat.completions.create(\n    model=\"gpt-4.1\",\n    messages=[\n        {\"role\": \"developer\", \"content\": \"Be concise.\"},\n        {\"role\": \"user\", \"content\": \"Give me a Python dict comprehension example.\"},\n    ],\n)\n\nprint(completion.choices[0].message.content)\n```\n\n### Async Client\n\nThe async surface mirrors the sync surface.\n\n```python\nimport asyncio\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI()\n\nasync def main() -> None:\n    response = await client.responses.create(\n        model=\"gpt-4.1\",\n        input=\"Explain what an event loop does in Python.\",\n    )\n    print(response.output_text)\n\nasyncio.run(main())\n```\n\nFor higher-concurrency async workloads, the maintainers document `aiohttp` as an optional backend:\n\n```python\nimport asyncio\nfrom openai import AsyncOpenAI, DefaultAioHttpClient\n\nasync def main() -> None:\n    async with AsyncOpenAI(http_client=DefaultAioHttpClient()) as client:\n        response = await client.responses.create(\n            model=\"gpt-4.1\",\n            input=\"Say hello.\",\n        )\n        print(response.output_text)\n\nasyncio.run(main())\n```\n\n### Streaming\n\nFor simple streaming, set `stream=True` and iterate over events.\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nstream = client.responses.create(\n    model=\"gpt-4.1\",\n    input=\"Write a one-sentence bedtime story about a unicorn.\",\n    stream=True,\n)\n\nfor event in stream:\n    print(event)\n```\n\nIf you need more structured streaming helpers for Chat Completions, the SDK also documents `client.chat.completions.stream(...)` in `helpers.md`.\n\n### Vision And Multimodal Inputs\n\nThe Responses API accepts multimodal input content arrays:\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nresponse = client.responses.create(\n    model=\"gpt-4.1-mini\",\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What is in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/cat.png\"},\n            ],\n        }\n    ],\n)\n\nprint(response.output_text)\n```\n\n### Structured Outputs With Pydantic\n\nThe SDK's documented auto-parsing helper is on Chat Completions, not on the Responses API. Use it when you want parsed Pydantic output.\n\n```python\nfrom pydantic import BaseModel\nfrom openai import OpenAI\n\nclass Summary(BaseModel):\n    title: str\n    bullets: list[str]\n\nclient = OpenAI()\n\ncompletion = client.chat.completions.parse(\n    model=\"gpt-4o-2024-08-06\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"Return a short structured summary.\"},\n        {\"role\": \"user\", \"content\": \"Summarize how Python context managers work.\"},\n    ],\n    response_format=Summary,\n)\n\nmessage = completion.choices[0].message\nif message.parsed:\n    print(message.parsed.title)\n    print(message.parsed.bullets)\nelse:\n    print(message.refusal)\n```\n\nImportant helper restrictions documented by upstream:\n\n- `chat.completions.parse()` may raise special errors when the finish reason is `length` or `content_filter`.\n- Tool parsing requires strict function tools. Use `openai.pydantic_function_tool(...)` or provide `\"strict\": True` in the tool schema.\n\n## Config And Authentication\n\n### Core OpenAI API\n\nDefault auth path:\n\n- `OPENAI_API_KEY`\n\nUseful optional configuration:\n\n- `base_url=` or `OPENAI_BASE_URL` for a compatible API endpoint\n- `max_retries=` for retry policy\n- `timeout=` for request timeouts\n- `OPENAI_LOG=info` or `debug` for SDK logging\n\nExample:\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI(\n    max_retries=2,\n    timeout=30.0,\n)\n```\n\nPer-request overrides use `with_options(...)`:\n\n```python\nresponse = client.with_options(timeout=5.0, max_retries=0).responses.create(\n    model=\"gpt-4.1\",\n    input=\"Quick health check.\",\n)\n```\n\n### Azure OpenAI\n\nUse `AzureOpenAI`, not `OpenAI`, when targeting Azure-hosted deployments.\n\n```python\nfrom openai import AzureOpenAI\n\nclient = AzureOpenAI(\n    api_version=\"2023-07-01-preview\",\n    azure_endpoint=\"https://example-endpoint.openai.azure.com\",\n)\n\ncompletion = client.chat.completions.create(\n    model=\"deployment-name\",\n    messages=[{\"role\": \"user\", \"content\": \"Say hello\"}],\n)\n\nprint(completion.to_json())\n```\n\nAzure-specific options documented in the README include:\n\n- `azure_endpoint` or `AZURE_OPENAI_ENDPOINT`\n- `azure_deployment`\n- `api_version` or `OPENAI_API_VERSION`\n- `azure_ad_token` or `AZURE_OPENAI_AD_TOKEN`\n- `azure_ad_token_provider`\n\n## Common Operational Patterns\n\n### Pagination\n\nList endpoints are auto-paginating iterators:\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nfor job in client.fine_tuning.jobs.list(limit=20):\n    print(job.id)\n```\n\nIf you need page-level control, use:\n\n- `.has_next_page()`\n- `.next_page_info()`\n- `.get_next_page()`\n\n### File Uploads\n\nUpload parameters accept bytes, path-like objects, or `(filename, contents, media_type)` tuples.\n\n```python\nfrom pathlib import Path\nfrom openai import OpenAI\n\nclient = OpenAI()\n\nuploaded = client.files.create(\n    file=Path(\"training.jsonl\"),\n    purpose=\"fine-tune\",\n)\n\nprint(uploaded.id)\n```\n\n### Webhook Verification\n\nPass the raw request body string to the webhook helpers. Do not JSON-decode it before verification.\n\n```python\nfrom flask import Flask, request\nfrom openai import OpenAI\n\napp = Flask(__name__)\nclient = OpenAI()\n\n@app.post(\"/webhook\")\ndef webhook() -> tuple[str, int] | str:\n    body = request.get_data(as_text=True)\n\n    try:\n        event = client.webhooks.unwrap(body, request.headers)\n        print(event.type)\n        return \"ok\"\n    except Exception:\n        return \"invalid signature\", 400\n```\n\nIf you only want signature verification, use `client.webhooks.verify_signature(...)` and parse the JSON yourself afterward.\n\n### Error Handling\n\nThe main exception families to branch on are:\n\n- `openai.APIConnectionError`\n- `openai.APIStatusError`\n- `openai.RateLimitError`\n- `openai.APITimeoutError`\n\n```python\nimport openai\nfrom openai import OpenAI\n\nclient = OpenAI()\n\ntry:\n    client.responses.create(model=\"gpt-4.1\", input=\"Hello\")\nexcept openai.RateLimitError:\n    # Back off and retry later.\n    raise\nexcept openai.APIStatusError as exc:\n    print(exc.status_code)\n    print(exc.request_id)\n    raise\n```\n\n## Realtime API\n\nThe async client exposes a WebSocket-based realtime interface:\n\n```python\nimport asyncio\nfrom openai import AsyncOpenAI\n\nasync def main() -> None:\n    client = AsyncOpenAI()\n\n    async with client.realtime.connect(model=\"gpt-realtime\") as connection:\n        await connection.session.update(\n            session={\"type\": \"realtime\", \"output_modalities\": [\"text\"]}\n        )\n        await connection.conversation.item.create(\n            item={\n                \"type\": \"message\",\n                \"role\": \"user\",\n                \"content\": [{\"type\": \"input_text\", \"text\": \"Say hello!\"}],\n            }\n        )\n        await connection.response.create()\n\n        async for event in connection:\n            if event.type == \"response.output_text.delta\":\n                print(event.delta, end=\"\", flush=True)\n            elif event.type == \"response.done\":\n                break\n\nasyncio.run(main())\n```\n\nRealtime pitfall: upstream documents that `error` events are delivered on the open connection and are not automatically raised as Python exceptions. You must handle `event.type == \"error\"` in your loop.\n\n## Common Pitfalls\n\n- Do not copy old pre-1.x examples that call module-level APIs like `openai.ChatCompletion.create(...)`. For `2.x`, instantiate `OpenAI()` or `AsyncOpenAI()`.\n- Prefer the Responses API for new code. Many third-party blog posts still default to older Chat Completions examples.\n- Do not parse webhook JSON before `unwrap()` or `verify_signature()`. The helper expects the raw request body string.\n- The default timeout is 10 minutes and default retry count is 2. Tight latency budgets often need smaller timeouts and explicit retry policy.\n- `_request_id` is intentionally public for debugging. Most other underscore-prefixed internals are not public API.\n- `AzureOpenAI` is not a drop-in type-perfect substitute for `OpenAI`; expect some shape mismatches because Azure differs from the core API.\n- `chat.completions.parse()` has extra restrictions compared with `chat.completions.create()`. Use it deliberately.\n\n## Official Sources Used For This Entry\n\n- OpenAI Python SDK README: `https://github.com/openai/openai-python`\n- OpenAI Python SDK helpers: `https://github.com/openai/openai-python/blob/main/helpers.md`\n- OpenAI Responses API reference: `https://platform.openai.com/docs/api-reference/responses`\n- PyPI package page: `https://pypi.org/project/openai/2.26.0/`\n"
  },
  {
    "path": "content/opencv-python/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"opencv-python package guide for cv2 installs, image and video workflows, headless variants, and common runtime pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.13.0.92\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opencv,opencv-python,cv2,computer-vision,image-processing,video\"\n---\n\n# opencv-python Python Package Guide\n\n## What It Is\n\n`opencv-python` is the PyPI wheel distribution for OpenCV's Python bindings. You install the package as `opencv-python`, but you import it as `cv2`.\n\nUse it when you need:\n\n- image loading, writing, resizing, drawing, and color conversion\n- camera and video-file capture\n- classic computer vision features from core OpenCV modules\n- prebuilt CPU-only wheels instead of compiling OpenCV from source\n\nThe official wheel project is for CPU-only builds. If you need CUDA or other custom build options, you need a source build instead of the stock PyPI wheels.\n\n## Version Covered\n\n- Package: `opencv-python`\n- Ecosystem: `pypi`\n- Version: `4.13.0.92`\n- Release date on PyPI: `2026-02-05`\n- Import name: `cv2`\n- Registry: https://pypi.org/project/opencv-python/\n- Docs root used for this guide: https://docs.opencv.org/4.x/\n- Packaging repository: https://github.com/opencv/opencv-python\n\n## Install\n\nPrefer an isolated virtual environment.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip setuptools wheel\npython -m pip install opencv-python==4.13.0.92\n```\n\nWindows PowerShell:\n\n```powershell\npy -m venv .venv\n.venv\\Scripts\\Activate.ps1\npy -m pip install --upgrade pip setuptools wheel\npy -m pip install opencv-python==4.13.0.92\n```\n\n### Choose Exactly One OpenCV Wheel Variant\n\nOpenCV publishes four related PyPI packages that all provide the same `cv2` import namespace. Install exactly one of them in a given environment:\n\n- `opencv-python`: core modules with GUI/backends\n- `opencv-contrib-python`: core + contrib modules\n- `opencv-python-headless`: no GUI/backends, better for servers and CI\n- `opencv-contrib-python-headless`: contrib + headless\n\nIf you install multiple variants into the same environment, uninstall them all and reinstall only the one you actually want.\n\n### When To Use Headless\n\nUse `opencv-python-headless` instead of `opencv-python` when:\n\n- you are running in Docker, CI, or a server environment\n- you do not need `cv.imshow`, window creation, or other HighGUI features\n- you want to avoid desktop GUI dependencies\n\nIf your code needs `cv.imshow(...)`, start from `opencv-python`, not a headless package.\n\n## Initialize And Verify\n\n```python\nimport cv2 as cv\n\nprint(cv.__version__)\nprint(cv.getBuildInformation().splitlines()[0])\n```\n\n`cv.getBuildInformation()` is the fastest way to inspect what codecs, modules, and third-party libraries are actually compiled into your installed wheel.\n\n## Core Usage\n\n### Load, Transform, And Save An Image\n\n`cv.imread()` returns a NumPy array, or `None` if the file cannot be read. Check that before continuing.\n\n```python\nfrom pathlib import Path\n\nimport cv2 as cv\n\nimage_path = Path(\"input.jpg\")\nimg = cv.imread(str(image_path))\nif img is None:\n    raise FileNotFoundError(f\"Could not read {image_path}\")\n\ngray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\nsmall = cv.resize(gray, (640, 480))\n\nok = cv.imwrite(\"output-gray.png\", small)\nif not ok:\n    raise RuntimeError(\"cv.imwrite failed\")\n```\n\nImportant details:\n\n- OpenCV images use BGR channel order by default, not RGB.\n- `cv.imread()` returning `None` usually means the path is wrong or the codec/backend cannot decode that file.\n- `cv.imwrite()` returns a boolean; treat `False` as a real failure.\n\n### Display A Window In Desktop Environments\n\nOnly do this with a non-headless wheel:\n\n```python\nimport cv2 as cv\n\nimg = cv.imread(\"input.jpg\")\nif img is None:\n    raise FileNotFoundError(\"input.jpg\")\n\ncv.imshow(\"preview\", img)\ncv.waitKey(0)\ncv.destroyAllWindows()\n```\n\nFor headless-safe code, save the output with `cv.imwrite(...)` instead of calling `cv.imshow(...)`.\n\n### Capture Frames From A Camera\n\nUse `cap.isOpened()` and check the boolean from `cap.read()` on every iteration.\n\n```python\nimport cv2 as cv\n\ncap = cv.VideoCapture(0)\nif not cap.isOpened():\n    raise RuntimeError(\"Cannot open camera\")\n\ntry:\n    while True:\n        ret, frame = cap.read()\n        if not ret:\n            raise RuntimeError(\"Failed to read frame from camera\")\n\n        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)\n        cv.imshow(\"camera\", gray)\n\n        if cv.waitKey(1) == ord(\"q\"):\n            break\nfinally:\n    cap.release()\n    cv.destroyAllWindows()\n```\n\nIf camera or video-file capture behaves differently across machines, inspect `cv.getBuildInformation()` and verify the local multimedia stack. The upstream video tutorial explicitly notes that video capture problems are often caused by FFmpeg or GStreamer installation issues.\n\n### Use Built-In Haar Cascade Data\n\nThe wheel packages include Haar cascade files. The package exposes their location through `cv2.data.haarcascades`.\n\n```python\nimport cv2 as cv\n\ncascade = cv.CascadeClassifier(\n    cv.data.haarcascades + \"haarcascade_frontalface_default.xml\"\n)\nif cascade.empty():\n    raise RuntimeError(\"Failed to load Haar cascade\")\n```\n\nThis is the most reliable way to reference the bundled cascade files without hard-coding a site-packages path.\n\n## Configuration And Environment Notes\n\n`opencv-python` does not use API credentials or service authentication. Configuration is mostly about:\n\n- selecting the correct wheel variant\n- using the intended Python interpreter and virtual environment\n- making sure the input files, camera devices, and codecs you rely on exist at runtime\n- understanding what your installed wheel was built with\n\n### IDE Interpreter Mismatch\n\nIf `import cv2` works in your terminal but fails in VS Code, PyCharm, or another IDE, the IDE is probably using a different interpreter than the one where you installed the package.\n\nVerify both of these:\n\n```bash\npython -c \"import sys, cv2; print(sys.executable); print(cv2.__version__)\"\npython -m pip show opencv-python\n```\n\n### Runtime Build Inspection\n\nWhen behavior depends on compiled backends or bundled modules, inspect the wheel instead of guessing:\n\n```python\nimport cv2 as cv\n\ninfo = cv.getBuildInformation()\nprint(info)\n```\n\nThis is especially useful for debugging:\n\n- video I/O backend availability\n- codec support\n- enabled modules\n- platform-specific wheel differences\n\n## Common Pitfalls\n\n### Package Name And Import Name Differ\n\nInstall:\n\n```bash\npython -m pip install opencv-python\n```\n\nImport:\n\n```python\nimport cv2\n```\n\nDo not try `import opencv_python`.\n\n### Mixing Multiple OpenCV Wheel Variants\n\nIf both `opencv-python` and `opencv-python-headless` are installed, or if you mix base and contrib variants, import behavior becomes unreliable because all of them provide the same `cv2` namespace.\n\nStart over cleanly if needed:\n\n```bash\npython -m pip uninstall -y opencv-python opencv-python-headless opencv-contrib-python opencv-contrib-python-headless\npython -m pip install opencv-python==4.13.0.92\n```\n\n### Expecting CUDA In The PyPI Wheels\n\nThe official wheel project provides prebuilt CPU-only packages. If your task requires CUDA-enabled OpenCV, the PyPI wheel is the wrong artifact; build from source with the options you need.\n\n### `cv.imshow()` In Containers Or Servers\n\nIf you run on CI, Docker, or a machine without GUI libraries, `cv.imshow()` and other window APIs are the wrong default. Use a headless wheel and write images to disk instead.\n\n### BGR vs RGB Confusion\n\nOpenCV images are BGR by default. If you pass frames directly into libraries that expect RGB, convert them first:\n\n```python\nrgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)\n```\n\n### Slow Per-Pixel Python Loops\n\nThe upstream tutorials explicitly warn that direct per-pixel NumPy loops are slow and that `cv.split()` is relatively costly. Prefer vectorized NumPy indexing or OpenCV operations over Python-level loops.\n\n### Old Packaging Tooling Or Unsupported Wheels\n\nIf `pip` starts building from source unexpectedly, or you see \"No matching distribution found\":\n\n- upgrade `pip`, `setuptools`, and `wheel`\n- verify your Python version and platform match a published wheel\n- try a mainstream interpreter version in a fresh virtual environment\n\n## Version-Sensitive Notes For `4.13.0.92`\n\n- PyPI lists `4.13.0.92` as the current `opencv-python` release as of `2026-02-05`.\n- The OpenCV docs root `https://docs.opencv.org/4.x/` is a rolling `4.x` site and currently renders `OpenCV 4.14.0-pre`, generated on `2026-03-02`.\n- That means the official docs site can be slightly ahead of the specific PyPI wheel version pinned in this guide.\n- For code that depends on newly added APIs or backend behavior, prefer checking `cv.__version__` and `cv.getBuildInformation()` in the target environment before assuming the rolling `4.x` docs exactly match your installed wheel.\n- The current official pip-install tutorial states that the OpenCV team maintains the PyPI packages; Conda and vendor-specific builds may differ from the official wheels.\n\n## Official Sources Used\n\n- PyPI package page: https://pypi.org/project/opencv-python/\n- OpenCV pip install guide: https://docs.opencv.org/4.x/db/dd1/tutorial_py_pip_install.html\n- OpenCV Python tutorials root: https://docs.opencv.org/4.x/d6/d00/tutorial_py_root.html\n- OpenCV basic image operations tutorial: https://docs.opencv.org/4.x/d3/df2/tutorial_py_basic_ops.html\n- OpenCV video capture tutorial: https://docs.opencv.org/4.x/dd/d43/tutorial_py_video_display.html\n- OpenCV core utility reference (`cv.getBuildInformation`): https://docs.opencv.org/4.x/db/de0/group__core__utils.html\n- OpenCV packaging repository: https://github.com/opencv/opencv-python\n- OpenCV 4.13.0 release page: https://github.com/opencv/opencv/releases/tag/4.13.0\n"
  },
  {
    "path": "content/openpyxl/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"openpyxl package guide for Python Excel workbooks: install, load/save flags, streaming modes, formulas, styles, and common pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n---\n\n# openpyxl Python Package Guide\n\n## Golden Rule\n\nUse `openpyxl` for Office Open XML Excel workbooks in Python, typically `.xlsx` and `.xlsm`. Treat it as a workbook editor, not an Excel calculation engine: write formulas as strings, read cached results with `data_only=True` only when the file has already been recalculated by Excel or LibreOffice, and use the optimized read/write modes for large files.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"openpyxl==3.1.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"openpyxl==3.1.5\"\npoetry add \"openpyxl==3.1.5\"\n```\n\nOptional companion packages called out by the official sources:\n\n```bash\npython -m pip install lxml pillow defusedxml\n```\n\nUse them only when needed:\n\n- `lxml`: faster XML writing, especially for large-file creation workloads\n- `pillow`: required if you need image support\n- `defusedxml`: recommended when processing untrusted workbooks because the project does not guard against quadratic blowup or billion laughs XML attacks by default\n\n## Initialize And Mental Model\n\n`openpyxl` revolves around three core objects:\n\n- `Workbook`: the Excel file\n- `Worksheet`: a sheet inside the workbook\n- `Cell`: an addressed value such as `A1`\n\nBasic workbook creation:\n\n```python\nfrom openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.title = \"Report\"\n\nws[\"A1\"] = \"region\"\nws[\"B1\"] = \"sales\"\nws.append([\"west\", 120])\nws.append([\"east\", 95])\n\nwb.save(\"report.xlsx\")\n```\n\nImportant save behavior: saving to an existing filename overwrites the file without warning.\n\n## Core Usage\n\n### Load an existing workbook\n\nUse `load_workbook()` when you need to inspect or modify an existing file:\n\n```python\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\"report.xlsx\")\nws = wb[\"Report\"]\n\nprint(ws[\"A2\"].value)\n```\n\nUseful flags:\n\n```python\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\n    \"report.xlsm\",\n    read_only=False,\n    data_only=False,\n    keep_vba=True,\n    keep_links=True,\n    rich_text=False,\n)\n```\n\nUse these flags deliberately:\n\n- `read_only=True`: stream rows from large workbooks with low memory usage\n- `data_only=True`: read cached formula results instead of formula strings\n- `keep_vba=True`: preserve existing VBA content in macro-enabled files when saving\n- `keep_links=False`: drop external-link preservation when you do not need it\n- `rich_text=True`: preserve rich text runs when that formatting matters\n\n### Iterate through rows and columns\n\n```python\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\"report.xlsx\")\nws = wb.active\n\nfor row in ws.iter_rows(min_row=2, values_only=True):\n    region, sales = row\n    print(region, sales)\n```\n\n`values_only=True` is usually the right default when you only need Python values rather than `Cell` objects.\n\n### Write tabular data\n\n```python\nfrom openpyxl import Workbook\n\nrows = [\n    (\"name\", \"team\", \"score\"),\n    (\"Ava\", \"blue\", 10),\n    (\"Noah\", \"green\", 14),\n]\n\nwb = Workbook()\nws = wb.active\n\nfor row in rows:\n    ws.append(row)\n\nwb.save(\"scores.xlsx\")\n```\n\nUse `append()` for row-oriented writes. Use direct cell assignment such as `ws[\"C2\"] = 42` when you need random access updates.\n\n### Read formulas vs cached values\n\nWrite formulas as strings:\n\n```python\nfrom openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\n\nws[\"A1\"] = 10\nws[\"A2\"] = 20\nws[\"A3\"] = \"=SUM(A1:A2)\"\n\nwb.save(\"formula.xlsx\")\n```\n\nIf you reopen the file with `data_only=False`, you read the formula text. If you reopen with `data_only=True`, you get the last cached value stored by spreadsheet software. `openpyxl` itself does not calculate formulas.\n\nThe official docs also note that function names must use the English Excel names and argument separators must use commas.\n\n### Apply simple styles\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill\n\nwb = Workbook()\nws = wb.active\nws.append([\"name\", \"team\", \"score\"])\n\nheader_font = Font(bold=True)\nheader_fill = PatternFill(\"solid\", fgColor=\"D9EAF7\")\n\nfor cell in ws[1]:\n    cell.font = header_font\n    cell.fill = header_fill\n\nwb.save(\"styled.xlsx\")\n```\n\nStyle objects are immutable once assigned. Create a new style object rather than mutating one already attached to cells.\n\n### Add an image\n\nImage support requires `Pillow`:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.drawing.image import Image\n\nwb = Workbook()\nws = wb.active\n\nimg = Image(\"logo.png\")\nws.add_image(img, \"D2\")\n\nwb.save(\"with-image.xlsx\")\n```\n\n## Large Files And Optimized Modes\n\n### Read-only mode\n\nUse `read_only=True` when loading large workbooks:\n\n```python\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\"large.xlsx\", read_only=True)\nws = wb.active\n\nfor row in ws.rows:\n    values = [cell.value for cell in row]\n    print(values)\n\nwb.close()\n```\n\nNotes from the official optimized-modes docs:\n\n- read-only worksheets use lazy loading and return `ReadOnlyCell` objects\n- the workbook must be explicitly closed\n- some worksheet methods are unavailable in read-only mode\n- if a producer writes incorrect worksheet dimensions, check `ws.calculate_dimension()` and call `ws.reset_dimensions()` when needed\n\n### Write-only mode\n\nUse `Workbook(write_only=True)` to stream output for very large exports:\n\n```python\nfrom openpyxl import Workbook\n\nwb = Workbook(write_only=True)\nws = wb.create_sheet(title=\"Export\")\n\nfor i in range(1, 100001):\n    ws.append([i, f\"row-{i}\"])\n\nwb.save(\"export.xlsx\")\n```\n\nWrite-only mode is append-only, does not expose random cell access, and the official docs warn that a write-only workbook can be saved only once.\n\n## Configuration And File-Type Notes\n\n`openpyxl` has no package-level authentication or environment configuration. Almost all \"configuration\" is per-call behavior:\n\n- load-time flags such as `read_only`, `data_only`, `keep_vba`, `keep_links`, and `rich_text`\n- workbook mode such as normal vs `write_only=True`\n- file extension and whether the workbook contains macros or templates\n\nMacro/template caveats from the official tutorial:\n\n- keep macros with `keep_vba=True` and save with a macro-capable extension such as `.xlsm`\n- use `wb.template = True` when intentionally producing a template and save with the matching template extension\n- do not mix workbook content and file extension types; Excel may refuse to open the file\n\n## Common Pitfalls\n\n- `openpyxl` does not calculate formulas. If you need computed results, recalculate the workbook in Excel or LibreOffice before reading it with `data_only=True`.\n- `data_only=True` can return `None` or stale values when the workbook has never been recalculated since the formula changed.\n- Saving overwrites existing files without warning.\n- `copy_worksheet()` does not copy images or charts, and you cannot copy a worksheet between different workbooks.\n- VBA preservation is not the same as VBA editing. `keep_vba=True` is for preserving existing macro content while manipulating the workbook.\n- Read-only mode is not a drop-in replacement for the normal API. Some iteration helpers and random-access operations are intentionally unavailable.\n- Write-only mode is append-only and one-shot. Build rows in order and save once.\n- Be careful with untrusted files. The project documentation explicitly recommends installing `defusedxml`.\n\n## Version-Sensitive Notes\n\n- The official docs build is behind the PyPI release: `stable` is `3.1.3`, the `3.1` branch is `3.1.4`, and PyPI is `3.1.5`.\n- When examples disagree across community posts, prefer the official 3.1 docs series plus PyPI metadata over older blog posts.\n- If you depend on behavior around macros, rich text preservation, or optimized modes, verify against the official tutorial and optimized-modes pages rather than generic snippets.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/openpyxl/`\n- Official docs root (`3.1`): `https://openpyxl.readthedocs.io/en/3.1/`\n- Official stable docs root: `https://openpyxl.readthedocs.io/en/stable/`\n- Tutorial: `https://openpyxl.readthedocs.io/en/3.1/tutorial.html`\n- Optimized modes: `https://openpyxl.readthedocs.io/en/3.1/optimized.html`\n- Formula reference: `https://openpyxl.readthedocs.io/en/3.1/simple_formulae.html`\n"
  },
  {
    "path": "content/opensearch-py/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"opensearch-py package guide for Python clients connecting to OpenSearch clusters\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opensearch,search,analytics,python,aws,async\"\n---\n\n# opensearch-py Python Package Guide\n\n## Golden Rule\n\nUse `opensearch-py` for Python access to OpenSearch clusters, and write 3.x code with keyword arguments for API calls. As of March 12, 2026, PyPI still lists `3.1.0` as the current release.\n\n## Install\n\n```bash\npython -m pip install \"opensearch-py==3.1.0\"\n```\n\nAsync support:\n\n```bash\npython -m pip install \"opensearch-py[async]==3.1.0\"\n```\n\nIf you need AWS SigV4 auth, install `boto3` or `botocore` in the same environment:\n\n```bash\npython -m pip install \"opensearch-py==3.1.0\" boto3\n```\n\n## What The Package Covers\n\n`opensearch-py` is the main Python client for OpenSearch. It gives you:\n\n- low-level wrappers around the OpenSearch REST APIs\n- sync and async clients\n- bulk helpers\n- high-level DSL functionality merged from `opensearch-dsl-py` starting in `2.2.0`\n\nFor new work, prefer this package instead of the archived `opensearch-dsl-py` package.\n\n## Initialize A Client\n\n### Local or self-managed cluster\n\nUse TLS and certificate verification in real environments. The insecure flags below are only acceptable for local testing.\n\n```python\nfrom opensearchpy import OpenSearch\n\nclient = OpenSearch(\n    hosts=[{\"host\": \"localhost\", \"port\": 9200}],\n    http_auth=(\"admin\", \"admin\"),\n    http_compress=True,\n    use_ssl=True,\n    verify_certs=False,\n    ssl_assert_hostname=False,\n    ssl_show_warn=False,\n)\n\ninfo = client.info()\nprint(info[\"version\"][\"number\"])\n```\n\n### Verified TLS with a CA bundle\n\n```python\nfrom opensearchpy import OpenSearch\n\nclient = OpenSearch(\n    hosts=[{\"host\": \"search.example.com\", \"port\": 9200}],\n    http_auth=(\"user\", \"pass\"),\n    http_compress=True,\n    use_ssl=True,\n    verify_certs=True,\n    ca_certs=\"/path/to/root-ca.pem\",\n)\n```\n\nUse `client_cert` and `client_key` if your cluster is configured for client certificate authentication.\n\n### Amazon OpenSearch Service or Serverless\n\nMatch the signer to the connection class. In the package source, `AWSV4SignerAuth` is a deprecated alias of `RequestsAWSV4SignerAuth`.\n\n```python\nimport boto3\nfrom opensearchpy import OpenSearch, RequestsHttpConnection, RequestsAWSV4SignerAuth\n\ncredentials = boto3.Session().get_credentials()\nauth = RequestsAWSV4SignerAuth(credentials, region=\"us-west-2\", service=\"es\")\n\nclient = OpenSearch(\n    hosts=[{\"host\": \"my-domain.us-west-2.es.amazonaws.com\", \"port\": 443}],\n    http_auth=auth,\n    use_ssl=True,\n    verify_certs=True,\n    connection_class=RequestsHttpConnection,\n    pool_maxsize=20,\n)\n```\n\nFor OpenSearch Serverless, change `service=\"aoss\"`.\n\nIf you use the default urllib3 connection class instead of requests, use `Urllib3AWSV4SignerAuth`.\n\n### Async client\n\n```python\nimport asyncio\nfrom opensearchpy import AsyncHttpConnection, AsyncOpenSearch\n\nasync def main() -> None:\n    client = AsyncOpenSearch(\n        hosts=[{\"host\": \"localhost\", \"port\": 9200}],\n        http_auth=(\"admin\", \"admin\"),\n        use_ssl=True,\n        verify_certs=False,\n        ssl_show_warn=False,\n        connection_class=AsyncHttpConnection,\n    )\n    try:\n        info = await client.info()\n        print(info[\"version\"][\"number\"])\n    finally:\n        await client.close()\n\nasyncio.run(main())\n```\n\nThe async guide shows the same setup with `opensearch-py[async]`. Source inspection for `AsyncOpenSearch` in the official repo shows `close()` is async, so `await client.close()` is the safe pattern.\n\n## Core Usage\n\n### Ping and inspect cluster info\n\n```python\nif not client.ping():\n    raise RuntimeError(\"OpenSearch is not reachable\")\n\ninfo = client.info()\nversion = info[\"version\"][\"number\"]\ndistribution = info[\"version\"][\"distribution\"]\n```\n\n### Create an index\n\nUse keyword arguments. In `3.0.0`, generated API methods were changed to require keyword-only arguments.\n\n```python\nindex_name = \"movies\"\n\nclient.indices.create(\n    index=index_name,\n    body={\n        \"settings\": {\n            \"index\": {\n                \"number_of_shards\": 1,\n                \"number_of_replicas\": 1,\n            }\n        }\n    },\n)\n```\n\n### Index and search documents\n\n```python\nclient.index(\n    index=\"movies\",\n    id=\"1\",\n    body={\n        \"title\": \"Moneyball\",\n        \"director\": \"Bennett Miller\",\n        \"year\": 2011,\n    },\n    refresh=True,\n)\n\nresponse = client.search(\n    index=\"movies\",\n    body={\n        \"query\": {\n            \"multi_match\": {\n                \"query\": \"miller\",\n                \"fields\": [\"title^2\", \"director\"],\n            }\n        }\n    },\n)\n\nhits = response[\"hits\"][\"hits\"]\n```\n\n### Bulk indexing with helpers\n\nPrefer `helpers.bulk()` or `helpers.parallel_bulk()` over hand-building newline-delimited JSON.\n\n```python\nfrom opensearchpy import OpenSearch, helpers\n\ndocs = [\n    {\"_index\": \"movies\", \"_id\": \"1\", \"title\": \"Moneyball\", \"year\": 2011},\n    {\"_index\": \"movies\", \"_id\": \"2\", \"title\": \"Interstellar\", \"year\": 2014},\n]\n\nhelpers.bulk(client, docs, max_retries=3)\n```\n\nFor large ingests, `helpers.parallel_bulk()` lets you tune `chunk_size`, `max_chunk_bytes`, and `request_timeout`.\n\n## Configuration And Auth Notes\n\n### Connection classes\n\n- `Urllib3HttpConnection` is the default sync connection class and the project recommendation unless your app is standardized on `requests`.\n- `RequestsHttpConnection` is the sync choice when you specifically want the requests stack.\n- `AsyncHttpConnection` uses `aiohttp` and is the async option.\n\n### TLS and certificate handling\n\n- Prefer `verify_certs=True` in any non-local environment.\n- Pass `ca_certs` when you need a custom CA bundle.\n- Only set `ssl_assert_hostname=False` when you intentionally need to bypass hostname verification, such as local testing or certificate mismatch debugging.\n- The SSL guide notes that CA discovery can fall back to OpenSSL env vars, `certifi`, or backend defaults if `ca_certs` is not provided.\n\n### Pooling and compression\n\n- Use `http_compress=True` for request-body gzip compression when indexing larger payloads.\n- Increase `pool_maxsize` for threaded or high-concurrency workloads.\n\n## Common Pitfalls\n\n- The import is `opensearchpy`, not `opensearch_py`.\n- Old examples that pass positional parameters to generated APIs are a poor fit on `3.x`; use `index=...`, `body=...`, `id=...`, and similar keyword arguments.\n- Do not copy the docs' local-test settings into production: `verify_certs=False` and `ssl_assert_hostname=False` weaken TLS.\n- `refresh=True` is convenient for tests and demos but can hurt indexing throughput in real workloads.\n- The async client requires the `async` extra. `pip install opensearch-py` alone is not enough for `AsyncOpenSearch`.\n- For AWS-managed clusters, match the signer and connection class correctly. The repo auth guide distinguishes `RequestsAWSV4SignerAuth`, `Urllib3AWSV4SignerAuth`, and `AWSV4SignerAsyncAuth`.\n- `opensearch-dsl-py` has been merged into `opensearch-py`; avoid building new code on the archived package.\n\n## Version-Sensitive Notes For 3.1.0\n\n- `3.1.0` is the current PyPI release as of March 12, 2026.\n- `3.1.0` supports Python `3.10`, `3.11`, and `3.12`; the package metadata requires `>=3.10,<4`.\n- The `3.1.0` changelog explicitly deprecates Python `3.8` and `3.9` support, so treat older runtime examples as stale.\n- The compatibility matrix says `3.x.x` clients work with OpenSearch `1.0.0` through `3.x`, as long as you avoid features removed from newer server versions.\n- Since `3.0.0`, generated APIs use mandatory keyword-only arguments. If you are adapting pre-3.0 snippets, update the call style before assuming the example is valid.\n\n## Official Sources\n\n- Docs root: https://docs.opensearch.org/latest/clients/python-low-level/\n- PyPI: https://pypi.org/project/opensearch-py/\n- Repository: https://github.com/opensearch-project/opensearch-py\n- User guide: https://github.com/opensearch-project/opensearch-py/blob/main/USER_GUIDE.md\n- Auth guide: https://github.com/opensearch-project/opensearch-py/blob/main/guides/auth.md\n- Async guide: https://github.com/opensearch-project/opensearch-py/blob/main/guides/async.md\n- SSL guide: https://github.com/opensearch-project/opensearch-py/blob/main/guides/ssl.md\n- Bulk guide: https://github.com/opensearch-project/opensearch-py/blob/main/guides/bulk.md\n- Compatibility matrix: https://github.com/opensearch-project/opensearch-py/blob/main/COMPATIBILITY.md\n- Changelog: https://github.com/opensearch-project/opensearch-py/blob/main/CHANGELOG.md\n"
  },
  {
    "path": "content/opentelemetry/docs/api/python/DOC.md",
    "content": "---\nname: api\ndescription: \"OpenTelemetry Python API package guide for manual instrumentation, context propagation, metrics, and logs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,otel,python,observability,tracing,metrics,logs,context-propagation\"\n---\n\n# OpenTelemetry Python API Package Guide\n\n## Golden Rule\n\nUse `opentelemetry-api` as the dependency surface for reusable libraries, and pair it with `opentelemetry-sdk` in applications that must actually emit telemetry. Keep all OpenTelemetry Python package versions aligned across `opentelemetry-api`, `opentelemetry-sdk`, exporters, and instrumentation packages.\n\n## Install\n\nLibrary-only dependency:\n\n```bash\npython -m pip install \"opentelemetry-api==1.40.0\"\n```\n\nApplication setup that will emit telemetry:\n\n```bash\npython -m pip install \\\n  \"opentelemetry-api==1.40.0\" \\\n  \"opentelemetry-sdk==1.40.0\"\n```\n\nIf the app needs OTLP export, add a matching exporter package:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp-proto-http==1.40.0\"\n```\n\n## Setup Patterns\n\n### Libraries: depend on API only\n\nLibraries should create tracers, meters, or loggers but should not install global providers. That keeps the host application in control of exporters, batching, sampling, and credentials.\n\n```python\nfrom opentelemetry import trace\n\ntracer = trace.get_tracer(\"acme.widgets\", \"2.3.0\")\n\ndef render_widget(widget_id: str) -> str:\n    with tracer.start_as_current_span(\"acme.widgets.render\") as span:\n        span.set_attribute(\"widget.id\", widget_id)\n        return f\"widget:{widget_id}\"\n```\n\n### Applications: install providers once\n\nApplications should configure the SDK exactly once near process startup, then retrieve tracers or meters from the API.\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter\n\nprovider = TracerProvider()\nprovider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))\ntrace.set_tracer_provider(provider)\n\ntracer = trace.get_tracer(\"myapp.checkout\", \"1.0.0\")\n\nwith tracer.start_as_current_span(\"checkout\") as span:\n    span.set_attribute(\"cart.items\", 3)\n```\n\n`trace.set_tracer_provider(...)` can only be done once. If no provider is installed, `get_tracer(...)` still returns an object, but it is backed by the default proxy or no-op behavior and nothing is exported.\n\n## Core Usage\n\n### Create spans\n\nUse a stable instrumentation scope name such as your package or service name. Add attributes rather than encoding data into span names.\n\n```python\nfrom opentelemetry import trace\n\ntracer = trace.get_tracer(\"payments.api\", \"2026.3\")\n\ndef charge(order_id: str, amount_cents: int) -> None:\n    with tracer.start_as_current_span(\"payments.charge\") as span:\n        span.set_attribute(\"order.id\", order_id)\n        span.set_attribute(\"payment.amount_cents\", amount_cents)\n```\n\n### Propagate context and baggage\n\n`propagate.inject(...)` writes tracing context and baggage into a carrier such as HTTP headers. `propagate.extract(...)` reconstructs context from an incoming carrier.\n\n```python\nfrom opentelemetry import baggage, propagate\nfrom opentelemetry.context import attach, detach\n\nheaders: dict[str, str] = {}\n\nctx = baggage.set_baggage(\"tenant.id\", \"acme\")\ntoken = attach(ctx)\ntry:\n    propagate.inject(headers)\nfinally:\n    detach(token)\n\nincoming_context = propagate.extract(headers)\ntenant_id = baggage.get_baggage(\"tenant.id\", incoming_context)\n```\n\nUse `attach(...)` and `detach(...)` as a pair. Forgetting to detach leaves the current context polluted for later work on the same thread or task.\n\n### Create metrics\n\nThe metrics API comes from `opentelemetry-api`, but exporting requires an SDK meter provider and at least one metric reader.\n\n```python\nfrom opentelemetry import metrics\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader\n\nreader = PeriodicExportingMetricReader(ConsoleMetricExporter())\nmetrics.set_meter_provider(MeterProvider(metric_readers=[reader]))\n\nmeter = metrics.get_meter(\"myapp.checkout\", \"1.0.0\")\nrequest_counter = meter.create_counter(\n    \"checkout.requests\",\n    unit=\"1\",\n    description=\"Number of checkout requests\",\n)\n\nrequest_counter.add(1, {\"route\": \"/checkout\", \"method\": \"POST\"})\n```\n\nLike tracing, `metrics.set_meter_provider(...)` should happen once during startup.\n\n### Emit logs through the OpenTelemetry logging pipeline\n\nFor application code, the practical path is usually standard `logging` plus the OpenTelemetry SDK logging handler.\n\n```python\nimport logging\n\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.sdk._logs import LoggerProvider, LoggingHandler\nfrom opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter\n\nprovider = LoggerProvider()\nprovider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogRecordExporter()))\nset_logger_provider(provider)\n\nhandler = LoggingHandler(level=logging.INFO, logger_provider=provider)\nlogging.basicConfig(level=logging.INFO, handlers=[handler])\n\nlogging.getLogger(\"myapp.checkout\").info(\"checkout started\", extra={\"order_id\": \"ord_123\"})\n```\n\nIf you only install `opentelemetry-api`, loggers can be created from the API, but no provider means no records are exported.\n\n## Configuration Notes\n\nThere is no authentication in `opentelemetry-api` itself. Authentication, endpoints, headers, and backend-specific settings belong to SDK exporters such as OTLP exporters.\n\nUseful environment variables from the official Python docs:\n\n- `OTEL_PROPAGATORS`: selects global propagators; the default is `tracecontext,baggage`\n- `OTEL_PYTHON_CONTEXT`: selects the runtime context implementation\n- `OTEL_PYTHON_TRACER_PROVIDER`: loads a tracer provider implementation from an entry point\n- `OTEL_PYTHON_METER_PROVIDER`: loads a meter provider implementation from an entry point\n\nPractical guidance:\n\n- Prefer explicit startup code for provider registration in application code unless your deployment already standardizes environment-driven setup.\n- Keep exporter endpoint and credential configuration in the SDK/exporter layer, not in library code that only depends on `opentelemetry-api`.\n- When using custom carriers for propagation, implement the appropriate getter or setter instead of assuming your object behaves like a plain dict.\n\n## Common Pitfalls\n\n- Installing `opentelemetry-api` alone does not make spans, metrics, or logs appear in a backend. You need the SDK plus exporter or readers.\n- Global provider setters are one-time operations. If multiple modules try to set them, later attempts log warnings and are ignored.\n- Do not make reusable libraries call `set_tracer_provider(...)` or `set_meter_provider(...)`. That steals control from the host app.\n- Avoid unstable instrumentation scope names such as `__name__` in scripts. Use a durable package or service name so telemetry stays grouped sensibly.\n- `propagate.inject(...)` only writes context to a carrier. It does not send network requests or automatically attach headers to your HTTP client.\n- Baggage is for small cross-service key-value context, not for large payloads or secrets.\n- Logs in OpenTelemetry Python are still marked as development status. Treat logging internals as more version-sensitive than traces and metrics.\n\n## Version-Sensitive Notes For 1.40.0\n\n- As of March 12, 2026, PyPI lists `opentelemetry-api 1.40.0` as the current release.\n- `opentelemetry-api 1.40.0` requires Python `>=3.9`.\n- The OpenTelemetry Python repository marks tracing and metrics as stable, while logging remains in development status.\n- The current Python instrumentation docs use `ConsoleLogRecordExporter`. Older examples from versions earlier than `1.39.0` may still show `ConsoleLogExporter`; update those snippets before copying them.\n"
  },
  {
    "path": "content/opentelemetry/docs/exporter-otlp/python/DOC.md",
    "content": "---\nname: exporter-otlp\ndescription: \"OpenTelemetry OTLP exporter package for sending Python traces, metrics, and logs to an OpenTelemetry Collector or OTLP backend\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,otel,otlp,observability,tracing,metrics,logging,collector\"\n---\n\n# opentelemetry-exporter-otlp Python Package Guide\n\n## Golden Rule\n\n`opentelemetry-exporter-otlp` is the convenience meta-package. Install it when you want both OTLP transports available, but write code against the concrete HTTP or gRPC exporter modules. The package does not create providers, processors, or resources for you; you still need `opentelemetry-sdk` setup, and OTLP is usually sent to an OpenTelemetry Collector or a vendor endpoint that speaks OTLP.\n\n## Install\n\nIf you want the convenience bundle:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp==1.40.0\" \"opentelemetry-sdk==1.40.0\"\n```\n\nIf you already know the transport, prefer the smaller concrete package:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp-proto-http==1.40.0\" \"opentelemetry-sdk==1.40.0\"\npython -m pip install \"opentelemetry-exporter-otlp-proto-grpc==1.40.0\" \"opentelemetry-sdk==1.40.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"opentelemetry-exporter-otlp==1.40.0\" \"opentelemetry-sdk==1.40.0\"\npoetry add \"opentelemetry-exporter-otlp==1.40.0\" \"opentelemetry-sdk==1.40.0\"\n```\n\nIf you are using auto-instrumentation instead of manual SDK setup, keep in mind that the instrumentation release train is separate. For the `1.40.0` core release, the matching contrib line is `0.61b0`.\n\n## Choose A Transport First\n\nUse HTTP/protobuf when:\n\n- your backend documents OTLP/HTTP endpoints\n- you want explicit per-signal URLs such as `/v1/traces`\n- proxies and load balancers behave better with HTTP than long-lived gRPC\n\nUse gRPC when:\n\n- your backend or collector expects OTLP/gRPC\n- you want a single endpoint instead of signal-specific URLs\n- your environment already handles gRPC/TLS well\n\nThe OpenTelemetry OTLP defaults are:\n\n- HTTP base endpoint: `http://localhost:4318`\n- gRPC endpoint: `http://localhost:4317`\n\n## Minimal Manual Setup\n\nAll signals should share a `Resource` so telemetry carries the same service identity.\n\n```python\nfrom opentelemetry.sdk.resources import Resource\n\nresource = Resource.create(\n    {\n        \"service.name\": \"billing-api\",\n        \"service.version\": \"2026.03.12\",\n        \"deployment.environment\": \"dev\",\n    }\n)\n```\n\n### Traces Over OTLP/HTTP\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\nresource = Resource.create({\"service.name\": \"billing-api\"})\n\nprovider = TracerProvider(resource=resource)\nprovider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(\n            endpoint=\"http://localhost:4318/v1/traces\",\n            headers={\"authorization\": \"Bearer <token>\"},\n            timeout=10,\n        )\n    )\n)\ntrace.set_tracer_provider(provider)\n\ntracer = trace.get_tracer(__name__)\n\nwith tracer.start_as_current_span(\"checkout\"):\n    pass\n```\n\n### Traces Over OTLP/gRPC\n\nFor gRPC, use the gRPC exporter import and point it at the collector/backend endpoint without `/v1/traces`:\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\nresource = Resource.create({\"service.name\": \"billing-api\"})\n\nprovider = TracerProvider(resource=resource)\nprovider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(\n            endpoint=\"http://localhost:4317\",\n            insecure=True,\n            headers={\"authorization\": \"Bearer <token>\"},\n            timeout=10,\n        )\n    )\n)\ntrace.set_tracer_provider(provider)\n```\n\nNotes:\n\n- `insecure=True` is for plain local or trusted network gRPC. For TLS, use an `https://` endpoint or pass credentials instead.\n- In `1.40.0`, OTLP exporter `headers` also accept a string as well as a dict, which helps when reusing env-style header values.\n\n### Metrics Over OTLP/HTTP\n\n```python\nfrom opentelemetry import metrics\nfrom opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\nfrom opentelemetry.sdk.resources import Resource\n\nresource = Resource.create({\"service.name\": \"billing-api\"})\n\nmetric_reader = PeriodicExportingMetricReader(\n    OTLPMetricExporter(\n        endpoint=\"http://localhost:4318/v1/metrics\",\n        headers={\"authorization\": \"Bearer <token>\"},\n        timeout=10,\n    ),\n    export_interval_millis=5000,\n)\n\nprovider = MeterProvider(resource=resource, metric_readers=[metric_reader])\nmetrics.set_meter_provider(provider)\n\nmeter = metrics.get_meter(__name__)\nrequests_counter = meter.create_counter(\"http.server.requests\")\nrequests_counter.add(1, {\"route\": \"/checkout\", \"method\": \"POST\"})\n```\n\n### Logs\n\nThe OTLP package includes `OTLPLogExporter` for HTTP and gRPC, but log setup in Python is still the least stable signal. The reliable shape is:\n\n- create a `LoggerProvider`\n- attach `BatchLogRecordProcessor`\n- attach `OTLPLogExporter`\n- bridge application logging carefully\n\nFor `1.40.0`, treat log examples as version-sensitive and verify them against the current upstream logging docs before copying older snippets. The `1.40.0` release notes also deprecate `LoggingHandler`, so do not anchor new code on it unless you have confirmed the current replacement path in the docs for your stack.\n\n## Auto-Instrumentation\n\nFor zero-code or low-code instrumentation, the exporter is usually configured by environment variables instead of constructor arguments:\n\n```bash\npython -m pip install \"opentelemetry-distro==0.61b0\" \"opentelemetry-exporter-otlp==1.40.0\"\nopentelemetry-bootstrap -a install\n\nexport OTEL_SERVICE_NAME=\"billing-api\"\nexport OTEL_EXPORTER_OTLP_PROTOCOL=\"http/protobuf\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4318\"\n\nopentelemetry-instrument python app.py\n```\n\nWhen using OTLP/HTTP with the base endpoint variable above, the SDK builds signal-specific URLs automatically:\n\n- traces -> `/v1/traces`\n- metrics -> `/v1/metrics`\n- logs -> `/v1/logs`\n\nIf you set `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`, or `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`, those values are already full per-signal endpoints.\n\n## Configuration And Authentication\n\nMost real backends use one or more of these patterns:\n\n- Authorization or tenant headers\n- TLS certificates\n- Separate per-signal endpoints\n- A collector in front of the vendor backend\n\nUseful environment variables:\n\n- `OTEL_EXPORTER_OTLP_PROTOCOL`: `grpc` or `http/protobuf`\n- `OTEL_EXPORTER_OTLP_ENDPOINT`: one base endpoint for all signals\n- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_HEADERS`: comma-separated key/value pairs for auth or tenancy\n- `OTEL_EXPORTER_OTLP_TIMEOUT`\n- `OTEL_EXPORTER_OTLP_COMPRESSION`\n\nSignal-specific variants exist too, such as `OTEL_EXPORTER_OTLP_TRACES_HEADERS` and `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT`.\n\nTypical header-based auth:\n\n```bash\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>,x-tenant-id=<tenant>\"\n```\n\nHTTP exporters also support certificate and client-cert file arguments. gRPC exporters support channel credentials and TLS-aware endpoints.\n\n## Common Pitfalls\n\n- Installing the meta-package does not mean you import `opentelemetry_exporter_otlp` directly. Import the concrete HTTP or gRPC exporter modules.\n- OTLP exporter setup alone is not enough. Without `TracerProvider`, `MeterProvider`, processors, and a `Resource`, you will not emit useful telemetry.\n- Missing `service.name` is one of the fastest ways to get hard-to-find telemetry in the backend.\n- OTLP/HTTP base endpoints and per-signal endpoints behave differently. `OTEL_EXPORTER_OTLP_ENDPOINT=http://host:4318` is correct; `OTEL_EXPORTER_OTLP_ENDPOINT=http://host:4318/v1/traces` is wrong if you expect metrics and logs to derive cleanly from the same base.\n- gRPC endpoints do not use `/v1/traces`, `/v1/metrics`, or `/v1/logs`.\n- Vendor backends often require headers even when the collector on localhost does not. Local success does not prove production auth is correct.\n- Batch processors export asynchronously. Short-lived scripts should call provider shutdown or force-flush paths before exiting.\n- Logs remain the most version-sensitive signal in Python OpenTelemetry. Re-check upstream examples before pasting older log bridge code.\n\n## Version-Sensitive Notes For 1.40.0\n\n- PyPI currently lists `1.40.0` for `opentelemetry-exporter-otlp`, so the version used here is current as of March 12, 2026.\n- The package is production/stable on PyPI and advertises Python `3.9` through `3.14`.\n- The `1.40.0` release train for the core Python packages is paired with contrib/instrumentation `0.61b0`.\n- The release notes for `1.40.0` call out ongoing logging changes, including deprecation of `LoggingHandler`; treat log integrations as higher-churn than traces and metrics.\n\n## Official Sources\n\n- OpenTelemetry Python exporter docs: `https://opentelemetry-python.readthedocs.io/en/latest/exporter/otlp/otlp.html`\n- OpenTelemetry Python exporter guide: `https://opentelemetry.io/docs/languages/python/exporters/`\n- OTLP exporter configuration: `https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/`\n- OTLP protocol exporter spec: `https://opentelemetry.io/docs/specs/otel/protocol/exporter/`\n- PyPI package page: `https://pypi.org/project/opentelemetry-exporter-otlp/`\n- PyPI JSON metadata: `https://pypi.org/pypi/opentelemetry-exporter-otlp/json`\n"
  },
  {
    "path": "content/opentelemetry/docs/exporter-prometheus/python/DOC.md",
    "content": "---\nname: exporter-prometheus\ndescription: \"OpenTelemetry Prometheus exporter for Python applications that expose scraped metrics endpoints\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,prometheus,metrics,observability,monitoring\"\n---\n\n# opentelemetry-exporter-prometheus Python Package Guide\n\n## Golden Rule\n\nUse `opentelemetry-exporter-prometheus` when your Python process must expose a Prometheus scrape endpoint itself. If you already run an OpenTelemetry Collector or Prometheus with the OTLP receiver enabled, OpenTelemetry recommends OTLP for production because it preserves more of the OTel data model and fits Collector-based deployments better.\n\n## Install\n\nPin the exporter version your project expects:\n\n```bash\npython -m pip install \"opentelemetry-exporter-prometheus==0.61b0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"opentelemetry-exporter-prometheus==0.61b0\"\npoetry add \"opentelemetry-exporter-prometheus==0.61b0\"\n```\n\nWhat gets installed with it:\n\n- `opentelemetry-sdk`\n- `opentelemetry-api`\n- `prometheus_client`\n\nDo not try to force the exporter package version to match the SDK numerically. In this release train, the exporter is `0.61b0` while the package metadata depends on the `1.x` OpenTelemetry API/SDK line.\n\n## Initialize The Exporter\n\nThis exporter is a `MetricReader`. Your app still needs a normal OpenTelemetry `MeterProvider`, a `Resource`, and metric instruments.\n\n```python\nfrom prometheus_client import start_http_server\n\nfrom opentelemetry import metrics\nfrom opentelemetry.exporter.prometheus import PrometheusMetricReader\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.resources import SERVICE_NAME, Resource\n\nresource = Resource.create(\n    {\n        SERVICE_NAME: \"checkout-api\",\n        \"deployment.environment\": \"dev\",\n    }\n)\n\nstart_http_server(port=9464, addr=\"localhost\")\n\nreader = PrometheusMetricReader()\nprovider = MeterProvider(resource=resource, metric_readers=[reader])\nmetrics.set_meter_provider(provider)\n\nmeter = metrics.get_meter(\"checkout-api\")\nrequest_counter = meter.create_counter(\n    \"http.server.requests\",\n    unit=\"1\",\n    description=\"HTTP requests handled\",\n)\nlatency = meter.create_histogram(\n    \"http.server.duration\",\n    unit=\"ms\",\n    description=\"HTTP request latency\",\n)\n\nrequest_counter.add(1, {\"method\": \"GET\", \"route\": \"/health\"})\nlatency.record(12.7, {\"method\": \"GET\", \"route\": \"/health\"})\n```\n\nAfter the process starts, Prometheus-format metrics are exposed at `http://localhost:9464/metrics`.\n\n## Scrape From Prometheus\n\nMinimal Prometheus config:\n\n```yaml\nscrape_configs:\n  - job_name: checkout-api\n    scrape_interval: 5s\n    static_configs:\n      - targets: [\"host.docker.internal:9464\"]\n```\n\nIf Prometheus is not in Docker, replace `host.docker.internal` with the actual hostname or IP that can reach the Python process.\n\n## Auto-Instrumented / Zero-Code Setup\n\nThe package registers a `prometheus` metrics exporter entry point for OpenTelemetry Python auto-configuration. If you already run your app through `opentelemetry-instrument`, this package can start the scrape server for you.\n\n```bash\npython -m pip install \"opentelemetry-distro\" \"opentelemetry-exporter-prometheus==0.61b0\"\n\nexport OTEL_SERVICE_NAME=\"checkout-api\"\nexport OTEL_METRICS_EXPORTER=\"prometheus\"\nexport OTEL_EXPORTER_PROMETHEUS_HOST=\"0.0.0.0\"\nexport OTEL_EXPORTER_PROMETHEUS_PORT=\"9464\"\n\nopentelemetry-instrument python app.py\n```\n\nUse this path only when you are already relying on the OpenTelemetry auto-instrumentation tooling. For normal code-based instrumentation, instantiate `PrometheusMetricReader()` yourself and call `start_http_server(...)` explicitly.\n\n## Configuration And Exposure\n\nSupported Prometheus-specific environment variables:\n\n- `OTEL_EXPORTER_PROMETHEUS_HOST`: bind host, default `localhost`\n- `OTEL_EXPORTER_PROMETHEUS_PORT`: bind port, default `9464`\n\nAuthentication and transport:\n\n- This exporter does not add authentication, TLS, or authorization to the metrics endpoint.\n- Treat the endpoint as internal infrastructure.\n- Bind to `localhost` in development, or put the endpoint behind a trusted reverse proxy, service mesh, or private network path in shared environments.\n\n## Common Pitfalls\n\n- Do not copy the older `PrometheusMetricReader(prefix)` example from the docs page. In `0.61b0`, the actual constructor is `PrometheusMetricReader(disable_target_info: bool = False)`.\n- Do not start two scrape servers. If auto-instrumentation starts the HTTP server for you, do not also call `start_http_server(...)` in application code.\n- This package is pull-based. Nothing is pushed anywhere; Prometheus or a Collector with a Prometheus receiver must scrape `/metrics`.\n- No multiprocessing support. The official docs explicitly call this out; do not assume Gunicorn-style multi-worker setups will aggregate metrics correctly through this exporter.\n- Set a service name in the `Resource`. OpenTelemetry’s Python exporter docs note that a service name is required for most backends.\n- Keep label cardinality under control. Prometheus labels created from metric attributes can explode in size if you include request IDs, user IDs, or other unbounded values.\n\n## Version-Sensitive Notes\n\n- `0.61b0` is a pre-release version from the OpenTelemetry Python beta exporter line. Pin it deliberately; do not assume it behaves like a stable `1.x` package.\n- The package metadata for this release requires Python `>=3.9`.\n- The current Read the Docs page mixes an older `prefix` example with the newer API signature. Prefer the API signature and source code over that stale example.\n- If your deployment already has an OpenTelemetry Collector, OTLP is usually the better long-term production path. Use this Prometheus exporter when you specifically need a scrape endpoint from the app process.\n\n## Official Sources\n\n- Prometheus exporter docs: `https://opentelemetry-python.readthedocs.io/en/latest/exporter/prometheus/prometheus.html`\n- OpenTelemetry Python exporters guide: `https://opentelemetry.io/docs/languages/python/exporters/`\n- OpenTelemetry Python zero-code guide: `https://opentelemetry.io/docs/zero-code/python/`\n- PyPI package page: `https://pypi.org/project/opentelemetry-exporter-prometheus/`\n- Upstream package metadata: `https://raw.githubusercontent.com/open-telemetry/opentelemetry-python/main/exporter/opentelemetry-exporter-prometheus/pyproject.toml`\n- Upstream exporter source: `https://raw.githubusercontent.com/open-telemetry/opentelemetry-python/main/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py`\n"
  },
  {
    "path": "content/opentelemetry/docs/instrumentation/python/DOC.md",
    "content": "---\nname: instrumentation\ndescription: \"OpenTelemetry Python auto-instrumentation tools for bootstrapping, configuring, and running zero-code instrumentation\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,observability,tracing,metrics,logging,otlp,auto-instrumentation\"\n---\n\n# OpenTelemetry Instrumentation Python Package Guide\n\n## Golden Rule\n\nUse `opentelemetry-instrumentation` when you want OpenTelemetry Python auto-instrumentation tooling such as `opentelemetry-bootstrap`, `opentelemetry-instrument`, or programmatic `initialize()`. For most real applications, do not stop at this package alone: install `opentelemetry-distro` plus an exporter, then add the matching instrumentation packages for the libraries your app actually uses.\n\nIf you want manual spans, custom providers, or library-level instrumentation code, use `opentelemetry-sdk` and the normal OpenTelemetry Python API/SDK instead of treating this package as the full SDK.\n\n## What This Package Actually Does\n\n`opentelemetry-instrumentation` provides the Python-side tooling for automatic instrumentation:\n\n- `opentelemetry-bootstrap` inspects installed packages and recommends or installs matching instrumentation packages\n- `opentelemetry-instrument` launches your app with auto-instrumentation enabled\n- programmatic initialization is available when you cannot wrap the process with the CLI\n\nWhat it does not do by itself:\n\n- it is not the full SDK initialization story for manual instrumentation\n- it does not replace installing a distro and exporter\n- it cannot instrument libraries that do not have an OpenTelemetry integration package installed\n\n## Install\n\nIf you specifically need this package pinned:\n\n```bash\npython -m pip install \"opentelemetry-instrumentation==0.61b0\"\n```\n\nFor the normal zero-code setup, install the distro and an OTLP exporter. The distro currently ships on the same `0.61b0` contrib line:\n\n```bash\npython -m pip install \"opentelemetry-distro[otlp]==0.61b0\"\n```\n\nIf your app dependencies are already installed, add matching instrumentation packages:\n\n```bash\nopentelemetry-bootstrap -a install\n```\n\nIf you want to inspect the recommended instrumentations without installing them yet:\n\n```bash\nopentelemetry-bootstrap\n```\n\nWith `uv`, use the documented requirements flow instead of `-a install`:\n\n```bash\nuv add \"opentelemetry-distro==0.61b0\" opentelemetry-exporter-otlp\nuv run opentelemetry-bootstrap -a requirements | uv add --requirement -\n```\n\n## Zero-Code Setup\n\nThe standard workflow is:\n\n1. Install your app dependencies.\n2. Install `opentelemetry-distro` and an exporter.\n3. Run `opentelemetry-bootstrap -a install` so the matching `opentelemetry-instrumentation-*` packages are added.\n4. Start the app through `opentelemetry-instrument`.\n\nMinimal example:\n\n```bash\npython -m pip install \"opentelemetry-distro[otlp]==0.61b0\" flask\nopentelemetry-bootstrap -a install\n\nexport OTEL_SERVICE_NAME=\"my-flask-api\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4317\"\nexport OTEL_TRACES_EXPORTER=\"otlp\"\nexport OTEL_METRICS_EXPORTER=\"otlp\"\n\nopentelemetry-instrument flask run --port 8000\n```\n\nGeneric Python entrypoint:\n\n```bash\nexport OTEL_SERVICE_NAME=\"my-service\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4317\"\nopentelemetry-instrument python app.py\n```\n\n`opentelemetry-instrument` defaults to the `otlp` exporter. The package docs also note that the default OTLP transport for this command is gRPC.\n\n## Programmatic Auto-Instrumentation\n\nUse this when you cannot prepend `opentelemetry-instrument` to the process command, or when you need initialization to happen inside a worker process after forking.\n\nCall `initialize()` before importing the libraries you expect to be patched:\n\n```python\nfrom opentelemetry.instrumentation.auto_instrumentation import initialize\n\ninitialize()\n\nfrom fastapi import FastAPI\n\napp = FastAPI()\n```\n\nThis ordering matters. Some integrations will not patch correctly if the target library was imported before auto-instrumentation initialization.\n\n## Core Configuration\n\n### Service identity and resource attributes\n\nSet the service name explicitly. The OpenTelemetry docs note that the default `service.name` is `unknown_service`.\n\n```bash\nexport OTEL_SERVICE_NAME=\"billing-api\"\nexport OTEL_RESOURCE_ATTRIBUTES=\"deployment.environment.name=prod,service.version=2026.03.12\"\n```\n\n`OTEL_SERVICE_NAME` overrides `service.name` if you also include it in `OTEL_RESOURCE_ATTRIBUTES`.\n\n### OTLP endpoint, protocol, and headers\n\nCommon OTLP settings:\n\n```bash\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"https://otel.example.com:443\"\nexport OTEL_EXPORTER_OTLP_PROTOCOL=\"grpc\"\nexport OTEL_EXPORTER_OTLP_HEADERS=\"api-key=secret-token\"\n```\n\nUseful defaults from the OpenTelemetry configuration docs:\n\n- `OTEL_EXPORTER_OTLP_ENDPOINT` defaults to `http://localhost:4317` for gRPC and `http://localhost:4318` for HTTP\n- `OTEL_EXPORTER_OTLP_PROTOCOL` is SDK-dependent, typically `grpc` or `http/protobuf`\n- signal-specific endpoints such as `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` override the shared endpoint\n\nIf your vendor requires separate headers or endpoints for traces, metrics, or logs, use the signal-specific variables instead of the shared ones.\n\n### Exporter selection\n\n`opentelemetry-instrument` supports configuration through CLI flags or environment variables:\n\n```bash\nexport OTEL_TRACES_EXPORTER=\"console,otlp\"\nexport OTEL_METRICS_EXPORTER=\"otlp\"\nexport OTEL_LOGS_EXPORTER=\"otlp\"\n```\n\nYou can disable automatic trace exporter initialization with:\n\n```bash\nexport OTEL_TRACES_EXPORTER=\"none\"\n```\n\n### Disabling or filtering instrumentation\n\nDisable specific integrations by entry point name:\n\n```bash\nexport OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=\"redis,kafka,grpc_client\"\n```\n\nFilter noisy URLs globally or per library:\n\n```bash\nexport OTEL_PYTHON_EXCLUDED_URLS=\"healthcheck,metrics\"\nexport OTEL_PYTHON_REQUESTS_EXCLUDED_URLS=\"healthcheck\"\nexport OTEL_PYTHON_URLLIB3_EXCLUDED_URLS=\"client/.*/info\"\n```\n\n### Log correlation\n\nFor log enrichment and automatic logging handler setup:\n\n```bash\nexport OTEL_PYTHON_LOG_CORRELATION=\"true\"\nexport OTEL_PYTHON_LOG_AUTO_INSTRUMENTATION=\"true\"\nexport OTEL_PYTHON_LOG_LEVEL=\"info\"\n```\n\n## Common Pitfalls\n\n- Installing only `opentelemetry-instrumentation` is not enough for most apps. The maintainer docs explicitly tell you to install a distro package to get auto-instrumentation working.\n- `opentelemetry-bootstrap -a install` only adds integrations for packages already present in the active environment. Run it after installing app dependencies.\n- `uv sync` or dependency updates can invalidate the generated instrumentation set. The OpenTelemetry troubleshooting docs say to rerun the bootstrap requirements flow after updates when using `uv`.\n- Flask debug mode with the reloader can prevent instrumentation from working. If you must run with debug mode, set `use_reloader=False`.\n- Pre-fork servers with multiple workers can break metrics auto-instrumentation because of forking and background metric reader threads. For ASGI apps, the docs recommend Gunicorn with `uvicorn.workers.UvicornWorker`, or programmatic initialization inside each worker, or falling back to a single worker.\n- Programmatic initialization must happen before importing instrumented libraries such as `FastAPI`.\n- On slim Linux images, package installation may fail until build prerequisites such as compiler and Python dev packages are installed.\n\n## Version-Sensitive Notes\n\n- `0.61b0` is a beta pre-release published on March 4, 2026. Keep that prerelease status in mind when copying examples from older stable blog posts.\n- The current distro release is also `0.61b0`, which is the safest line to pair with this package for zero-code setup.\n- This package depends on `opentelemetry-semantic-conventions==0.61b0`, so mixing contrib packages from different prerelease lines is a common way to create dependency drift.\n- The agent configuration docs note that before OpenTelemetry Python `1.40.0`, logs auto-instrumentation behavior was controlled differently via `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED`. Current docs use `OTEL_PYTHON_LOG_AUTO_INSTRUMENTATION`.\n- The OTLP exporter docs describe both gRPC and HTTP/protobuf transports. If your backend expects `/v1/traces`, `/v1/metrics`, or `/v1/logs` style paths, prefer the HTTP-specific endpoint variables or set `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` explicitly.\n\n## When To Use Something Else\n\n- Use `opentelemetry-sdk` when you need manual spans, explicit provider setup, or custom sampling/export pipeline code.\n- Use individual `opentelemetry-instrumentation-<library>` packages directly when you want manual control over a specific integration rather than process-wide auto-instrumentation.\n- Use the OpenTelemetry Collector or vendor-specific collector guidance when transport, auth, batching, retries, or routing rules are more important than Python-side patching.\n\n## Official Sources Used\n\n- `https://pypi.org/project/opentelemetry-instrumentation/`\n- `https://pypi.org/pypi/opentelemetry-instrumentation/0.61b0/json`\n- `https://pypi.org/project/opentelemetry-distro/`\n- `https://opentelemetry.io/docs/zero-code/python/`\n- `https://opentelemetry.io/docs/zero-code/python/configuration/`\n- `https://opentelemetry.io/docs/zero-code/python/troubleshooting/`\n- `https://opentelemetry.io/docs/languages/python/instrumentation/`\n- `https://opentelemetry.io/docs/languages/sdk-configuration/general/`\n- `https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/`\n"
  },
  {
    "path": "content/opentelemetry/docs/instrumentation-django/python/DOC.md",
    "content": "---\nname: instrumentation-django\ndescription: \"OpenTelemetry Django instrumentation for tracing Django requests, middleware, templates, and database activity in Python apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,django,observability,tracing,otlp,instrumentation\"\n---\n\n# OpenTelemetry Django Instrumentation for Python\n\n## Golden Rule\n\nUse `opentelemetry-instrumentation-django` only as one piece of a complete OpenTelemetry setup: install the Django instrumentation package, configure an SDK and exporter or `opentelemetry-distro`, and instrument the app exactly once during process startup. This package is on a beta contrib release line, so pin exact versions and keep related OpenTelemetry contrib packages on the same release line.\n\n## Install\n\nFor programmatic instrumentation, install the package plus an SDK and exporter:\n\n```bash\npython -m pip install \"opentelemetry-instrumentation-django==0.61b0\" \\\n  opentelemetry-sdk \\\n  opentelemetry-exporter-otlp\n```\n\nIf you want zero-code or mostly zero-code setup, install the distro and bootstrap dependencies:\n\n```bash\npython -m pip install \"opentelemetry-distro\" \"opentelemetry-instrumentation-django==0.61b0\"\nopentelemetry-bootstrap -a install\n```\n\nPractical versioning rule:\n\n- Pin this package explicitly because `0.61b0` is a pre-release.\n- Avoid mixing `0.61b0` with older `0.60b1` or main-branch `0.62b0.dev` contrib packages.\n- If your project already pins other `opentelemetry-instrumentation-*` packages, keep them on the same beta line unless you have verified compatibility.\n\n## Initialize Programmatically\n\nInstrument before Django builds the WSGI or ASGI application so the middleware is inserted early enough.\n\nExample `mysite/wsgi.py`:\n\n```python\nimport os\n\nfrom django.core.wsgi import get_wsgi_application\n\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.instrumentation.django import DjangoInstrumentor\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\nresource = Resource.create(\n    {\n        \"service.name\": os.getenv(\"OTEL_SERVICE_NAME\", \"mysite\"),\n        \"deployment.environment.name\": os.getenv(\"DEPLOY_ENV\", \"dev\"),\n    }\n)\n\nprovider = TracerProvider(resource=resource)\nprovider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(\n            endpoint=os.getenv(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://localhost:4317\"),\n        )\n    )\n)\ntrace.set_tracer_provider(provider)\n\ndef response_hook(span, request, response):\n    if span and getattr(request, \"user\", None) and request.user.is_authenticated:\n        span.set_attribute(\"enduser.id\", str(request.user.pk))\n\nDjangoInstrumentor().instrument(response_hook=response_hook)\n\napplication = get_wsgi_application()\n```\n\nNotes:\n\n- Call `DjangoInstrumentor().instrument()` once per process.\n- Use `response_hook` when you need middleware-populated request data such as `request.user`; the maintainer docs note that `request_hook` runs before middleware executes.\n- The package exposes `DjangoInstrumentor().uninstrument()` if you need to disable it in tests or teardown code.\n\n## Zero-Code Startup\n\nOpenTelemetry's Python zero-code flow can instrument Django from the command line. Do not combine this with a manual `DjangoInstrumentor().instrument()` call in the same process.\n\nTypical setup:\n\n```bash\nexport OTEL_SERVICE_NAME=mysite\nexport OTEL_TRACES_EXPORTER=otlp\nexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\nexport OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\n\nopentelemetry-instrument python manage.py runserver\n```\n\nFor OTLP backends that require auth, add headers such as:\n\n```bash\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>\"\n```\n\nPractical note:\n\n- If the Django development autoreloader causes duplicate initialization or duplicate spans, run the underlying app entrypoint without reloading or instrument the production server command instead. This is an operational safeguard rather than a Django-package-specific API rule.\n\n## Core Django-Specific Configuration\n\n### Exclude noisy URLs\n\nThe maintainer docs support a Django-specific excluded-URLs environment variable:\n\n```bash\nexport OTEL_PYTHON_DJANGO_EXCLUDED_URLS=\"healthz,metrics,admin/jsi18n/\"\n```\n\nYou can also pass `excluded_urls=` directly when instrumenting.\n\n### Capture selected request attributes\n\nSet `OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS` to a comma-separated list of request attribute names:\n\n```bash\nexport OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS=\"resolver_match,user.is_authenticated\"\n```\n\nUse this carefully. Only trace small, stable attributes that are safe to emit.\n\n### Control middleware placement\n\nIf middleware ordering matters, the package supports both:\n\n- `middleware_position=` in `DjangoInstrumentor().instrument(...)`\n- `OTEL_PYTHON_DJANGO_MIDDLEWARE_POSITION`\n\nThis is useful when custom middleware must run before or after OpenTelemetry's middleware.\n\n### Temporarily disable Django instrumentation\n\nIf the package is installed but should not instrument a process, set:\n\n```bash\nexport OTEL_PYTHON_DJANGO_INSTRUMENT=False\n```\n\n### Request and response hooks\n\nThe Django instrumentor accepts `request_hook` and `response_hook` callbacks:\n\n```python\nfrom opentelemetry.instrumentation.django import DjangoInstrumentor\n\ndef request_hook(span, request):\n    if span:\n        span.set_attribute(\"http.request_id\", request.headers.get(\"X-Request-ID\", \"\"))\n\ndef response_hook(span, request, response):\n    if span:\n        span.set_attribute(\"http.response.template_status\", response.status_code)\n\nDjangoInstrumentor().instrument(\n    request_hook=request_hook,\n    response_hook=response_hook,\n)\n```\n\nThe official docs explicitly call out that response hooks are the right place to read middleware-generated values like authenticated user data or `django.contrib.sites` information.\n\n## Headers And SQL Commenter\n\nThe maintainer docs support the standard Python instrumentation environment variables for HTTP header capture and sanitization:\n\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS`\n\nUse these sparingly and sanitize aggressively because headers often contain secrets or PII.\n\nSQLCommenter support is built in and can be enabled with:\n\n```python\nDjangoInstrumentor().instrument(\n    is_sql_commentor_enabled=True,\n)\n```\n\nOr in `settings.py`:\n\n```python\nSQLCOMMENTER_WITH_CONTROLLER = True\nSQLCOMMENTER_WITH_ROUTE = True\nSQLCOMMENTER_WITH_APP_NAME = True\nSQLCOMMENTER_WITH_OPENTELEMETRY = True\n```\n\nOnly enable SQL commenting when your database path and privacy requirements allow it. If you already use SQL commenter features elsewhere in your stack, avoid duplicating them.\n\n## Common Pitfalls\n\n- Do not mix zero-code startup and manual `DjangoInstrumentor().instrument()` in the same process.\n- Instrument before `get_wsgi_application()` or `get_asgi_application()` so middleware insertion happens early enough.\n- Prefer `response_hook` over `request_hook` for data populated by Django middleware.\n- Be conservative with traced request attributes and header capture to avoid leaking secrets or high-cardinality data.\n- Exclude health, readiness, metrics, and similar endpoints early so they do not dominate trace volume.\n- Treat the ReadTheDocs pages as maintainer guidance for the current contrib line, not as a perfect snapshot of `0.61b0`.\n\n## Version-Sensitive Notes\n\n- The version used here and the PyPI release page align on `0.61b0`.\n- The maintainer docs page is versionless `latest`, and the public repository already advertises `0.62b0.dev`; that means examples in `latest` docs can drift ahead of the exact release you have pinned.\n- When there is any ambiguity, prefer the exact PyPI release page for package version identity and the package docs page for behavioral guidance.\n\n## Official Sources Used\n\n- PyPI release page: `https://pypi.org/project/opentelemetry-instrumentation-django/0.61b0/`\n- Django instrumentation docs: `https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/django/django.html`\n- OpenTelemetry Python zero-code example docs: `https://opentelemetry.io/docs/zero-code/python/example/`\n- Maintainer repo package metadata: `https://raw.githubusercontent.com/open-telemetry/opentelemetry-python-contrib/main/instrumentation/opentelemetry-instrumentation-django/pyproject.toml`\n- Maintainer repo instrumentor code: `https://raw.githubusercontent.com/open-telemetry/opentelemetry-python-contrib/main/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py`\n- Maintainer repo environment variable definitions: `https://raw.githubusercontent.com/open-telemetry/opentelemetry-python-contrib/main/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/environment_variables.py`\n"
  },
  {
    "path": "content/opentelemetry/docs/instrumentation-fastapi/python/DOC.md",
    "content": "---\nname: instrumentation-fastapi\ndescription: \"OpenTelemetry FastAPI instrumentation for tracing incoming FastAPI requests in Python applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,otel,fastapi,asgi,tracing,observability\"\n---\n\n# OpenTelemetry FastAPI Instrumentation Python Package Guide\n\n## Golden Rule\n\n`opentelemetry-instrumentation-fastapi` instruments incoming FastAPI and ASGI request handling, but it does not become useful until you also configure an OpenTelemetry SDK/exporter or run under `opentelemetry-instrument`. As of `2026-03-12`, the PyPI project page publishes `0.61b0` for this package. The canonical docs page is the FastAPI instrumentation page under `opentelemetry-python-contrib.readthedocs.io`, not the broader OpenTelemetry Python docs root.\n\n\n## Install\n\nFor manual setup, install the FastAPI instrumentation package plus an SDK and exporter:\n\n```bash\npython -m pip install \\\n  \"opentelemetry-sdk\" \\\n  \"opentelemetry-exporter-otlp-proto-http\" \\\n  \"opentelemetry-instrumentation-fastapi==0.61b0\"\n```\n\nIf you plan to use zero-code auto-instrumentation:\n\n```bash\npython -m pip install \\\n  \"opentelemetry-distro\" \\\n  \"opentelemetry-exporter-otlp\" \\\n  \"opentelemetry-instrumentation-fastapi==0.61b0\"\nopentelemetry-bootstrap -a install\n```\n\nPractical version note:\n\n- Keep contrib instrumentation packages on the same beta release train in one environment, for example `opentelemetry-instrumentation-fastapi`, `opentelemetry-instrumentation`, and `opentelemetry-instrumentation-asgi`. That is an inference from the official shared source tree and release cadence, and it avoids resolver churn across mixed `0.xx` prereleases.\n\n## Manual Setup\n\nCreate a tracer provider, attach an exporter, then instrument the FastAPI app before the app starts serving traffic:\n\n```python\nfrom fastapi import FastAPI\n\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\nfrom opentelemetry.sdk.resources import SERVICE_NAME, Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\nresource = Resource.create({SERVICE_NAME: \"orders-api\"})\ntracer_provider = TracerProvider(resource=resource)\ntracer_provider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(endpoint=\"http://localhost:4318/v1/traces\")\n    )\n)\ntrace.set_tracer_provider(tracer_provider)\n\napp = FastAPI()\n\nFastAPIInstrumentor.instrument_app(\n    app,\n    tracer_provider=tracer_provider,\n    excluded_urls=\"^/healthz$,^/metrics$\",\n    exclude_spans=[\"receive\", \"send\"],\n)\n\n@app.get(\"/orders/{order_id}\")\nasync def get_order(order_id: str) -> dict[str, str]:\n    return {\"order_id\": order_id}\n```\n\nWhy these choices matter:\n\n- `SERVICE_NAME` keeps spans grouped correctly in your backend.\n- `BatchSpanProcessor` is the normal production choice; avoid per-span exporting.\n- `exclude_spans=[\"receive\", \"send\"]` suppresses lower-level ASGI internal spans when you only want server spans.\n- `excluded_urls` is a regex list for endpoints like health checks and metrics that would otherwise dominate trace volume.\n\n## Zero-Code Setup\n\nIf you want automatic instrumentation at process launch, configure the exporter with environment variables and run the server through `opentelemetry-instrument`:\n\n```bash\nexport OTEL_SERVICE_NAME=orders-api\nexport OTEL_TRACES_EXPORTER=otlp\nexport OTEL_METRICS_EXPORTER=none\nexport OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\nexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n\nopentelemetry-instrument uvicorn app:app --host 0.0.0.0 --port 8000\n```\n\nUse zero-code instrumentation when you want broad framework coverage with minimal code changes. Use manual setup when you need explicit SDK construction, custom resources, or programmatic control over sampling and span processors.\n\n## Core Usage\n\n### Add hooks to customize spans\n\nThe FastAPI instrumentation supports server hooks plus ASGI client hooks for the internal `receive` and `send` spans:\n\n```python\nfrom typing import Any\n\nfrom fastapi import FastAPI\nfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\nfrom opentelemetry.trace import Span\n\napp = FastAPI()\n\ndef server_request_hook(span: Span, scope: dict[str, Any]) -> None:\n    if span and span.is_recording():\n        route = scope.get(\"path\", \"\")\n        span.set_attribute(\"app.route_path\", route)\n\ndef client_request_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]) -> None:\n    if span and span.is_recording():\n        span.set_attribute(\"app.asgi.event.type\", message.get(\"type\", \"\"))\n\nFastAPIInstrumentor.instrument_app(\n    app,\n    server_request_hook=server_request_hook,\n    client_request_hook=client_request_hook,\n)\n```\n\nUse hooks for request-derived attributes, tenant IDs, feature flags, or other context that is not automatically captured.\n\n### Capture selected headers\n\nThe FastAPI instrumentation docs support header capture via environment variables:\n\n```bash\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=\"x-request-id,authorization\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=\"content-type\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=\"authorization,set-cookie\"\n```\n\nNotes:\n\n- Header capture is explicitly marked experimental in the official docs.\n- Always sanitize secrets such as `authorization`, cookies, or internal tokens before enabling broad capture.\n\n### Exclude URLs from instrumentation\n\nYou can exclude URLs in code with `excluded_urls=...`, or by environment variable:\n\n```bash\nexport OTEL_PYTHON_FASTAPI_EXCLUDED_URLS=\"^/healthz$,^/metrics$\"\n```\n\nThe docs also note the generic fallback:\n\n```bash\nexport OTEL_PYTHON_EXCLUDED_URLS=\"^/healthz$,^/metrics$\"\n```\n\n## Config And Auth\n\nThe FastAPI instrumentation package itself does not require an API key. Auth usually matters in one of two places:\n\n1. Your exporter to the collector or backend, for example OTLP headers such as `OTEL_EXPORTER_OTLP_HEADERS`.\n2. Your application code, which may need its own auth middleware or dependency injection and can attach request metadata through hooks.\n\nUseful config knobs:\n\n- `OTEL_SERVICE_NAME` or `OTEL_RESOURCE_ATTRIBUTES`: service identity\n- `OTEL_EXPORTER_OTLP_ENDPOINT`: collector base URL\n- `OTEL_EXPORTER_OTLP_PROTOCOL`: usually `http/protobuf` or `grpc`\n- `OTEL_EXPORTER_OTLP_HEADERS`: auth or tenant headers for the collector\n- `OTEL_PYTHON_FASTAPI_EXCLUDED_URLS`: FastAPI-specific instrumentation exclusions\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`: opt-in request header capture\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`: opt-in response header capture\n- `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS`: redact sensitive headers\n\n## Common Pitfalls\n\n- Installing only `opentelemetry-instrumentation-fastapi` is not enough. Without an SDK/exporter or distro, you will not see useful telemetry.\n- Instrument the app once. The official source keeps an `_is_instrumented_by_opentelemetry` flag and warns on duplicate instrumentation attempts.\n- Instrument before the app handles traffic. Delayed instrumentation can miss startup-time behavior or interact poorly with test fixtures and reload flows.\n- This package covers inbound FastAPI request handling. Add separate instrumentation for outbound HTTP clients, database libraries, or background task queues you also use.\n- Excluding nothing can create noisy traces from `/healthz`, `/metrics`, docs routes, and probes.\n- Capturing headers without sanitization can leak credentials into telemetry backends.\n- In tests or hot-reload scenarios, call `FastAPIInstrumentor.uninstrument_app(app)` before rebuilding instrumentation state.\n\n## Version-Sensitive Notes\n\n- The opened PyPI project page currently lists `opentelemetry-instrumentation-fastapi 0.61b0` with `Requires: Python >=3.9`.\n- The live package page currently lists `0.61b0`, but search-result snippets briefly lagged and suggested `0.60b1`.\n- Use the FastAPI instrumentation page under `opentelemetry-python-contrib.readthedocs.io` as the canonical docs page.\n"
  },
  {
    "path": "content/opentelemetry/docs/instrumentation-flask/python/DOC.md",
    "content": "---\nname: instrumentation-flask\ndescription: \"OpenTelemetry Flask instrumentation for tracing incoming Flask requests in Python applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,otel,flask,wsgi,tracing,observability\"\n---\n\n# OpenTelemetry Flask Instrumentation Python Package Guide\n\n## Golden Rule\n\n`opentelemetry-instrumentation-flask` instruments inbound Flask request handling. It does not replace the OpenTelemetry SDK, exporter, or distro setup. Configure telemetry export first, then instrument the Flask app exactly once with `FlaskInstrumentor().instrument_app(app)`.\n\nIf you use zero-code startup with `opentelemetry-instrument`, do not also call `FlaskInstrumentor().instrument_app(app)` in the same process.\n\n## Install\n\nFor explicit in-app instrumentation, install the Flask instrumentor plus an SDK and exporter:\n\n```bash\npython -m pip install \\\n  \"Flask>=1.0\" \\\n  \"opentelemetry-instrumentation-flask==0.61b0\" \\\n  \"opentelemetry-sdk\" \\\n  \"opentelemetry-exporter-otlp-proto-http\"\n```\n\nFor zero-code startup, install the distro and OTLP exporter, then let bootstrap install matching instrumentations:\n\n```bash\npython -m pip install \\\n  \"Flask>=1.0\" \\\n  \"opentelemetry-distro[otlp]==0.61b0\" \\\n  \"opentelemetry-instrumentation-flask==0.61b0\"\n\nopentelemetry-bootstrap -a install\n```\n\nPractical version notes:\n\n- Keep contrib instrumentation packages on the same `0.61b0` release train in one environment when possible.\n- This package lives on the contrib prerelease line, so pinning exact versions is safer than floating prereleases.\n\n## Manual Setup\n\nCreate a tracer provider, attach an exporter, then instrument the Flask app before it starts handling requests:\n\n```python\nfrom flask import Flask\n\nfrom opentelemetry import trace\nfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\nfrom opentelemetry.instrumentation.flask import FlaskInstrumentor\nfrom opentelemetry.sdk.resources import SERVICE_NAME, Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\napp = Flask(__name__)\n\nresource = Resource.create({SERVICE_NAME: \"orders-api\"})\ntracer_provider = TracerProvider(resource=resource)\ntracer_provider.add_span_processor(\n    BatchSpanProcessor(\n        OTLPSpanExporter(endpoint=\"http://localhost:4318/v1/traces\")\n    )\n)\ntrace.set_tracer_provider(tracer_provider)\n\nFlaskInstrumentor().instrument_app(app, tracer_provider=tracer_provider)\n\n@app.get(\"/orders/<order_id>\")\ndef get_order(order_id: str):\n    return {\"order_id\": order_id}\n\n\nif __name__ == \"__main__\":\n    app.run(port=8000, debug=True)\n```\n\nWhat the Flask instrumentor adds:\n\n- server spans around incoming Flask requests\n- span names based on the matched Flask route\n- `http.route` on spans when Flask resolves a route\n- request and response hooks for app-specific attributes\n- optional SQLCommenter metadata when used with supported database instrumentation\n\n## Zero-Code Setup\n\nIf you want process-level auto-instrumentation without editing application startup code, configure the exporter with environment variables and launch the app through `opentelemetry-instrument`:\n\n```bash\nexport OTEL_SERVICE_NAME=orders-api\nexport OTEL_TRACES_EXPORTER=otlp\nexport OTEL_METRICS_EXPORTER=none\nexport OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\nexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n\nopentelemetry-instrument python app.py\n```\n\nUse this path when you want minimal code changes. Use manual setup when you need explicit control over the tracer provider, resource attributes, span processors, or exporter configuration.\n\n## Core Usage\n\n### Exclude noisy routes\n\nUse URL exclusions for health checks, metrics endpoints, and static assets:\n\n```python\nFlaskInstrumentor().instrument_app(\n    app,\n    excluded_urls=\"healthz,metrics,/static/.*\",\n)\n```\n\nEquivalent environment variable:\n\n```bash\nexport OTEL_PYTHON_FLASK_EXCLUDED_URLS=\"healthz,metrics,/static/.*\"\n```\n\nTo apply exclusions across multiple Python instrumentations, use:\n\n```bash\nexport OTEL_PYTHON_EXCLUDED_URLS=\"healthz,metrics,/static/.*\"\n```\n\n### Add request and response hooks\n\nHooks are the normal way to attach business attributes to the automatically created server span:\n\n```python\nfrom opentelemetry.trace import Span\n\n\ndef request_hook(span: Span, environ) -> None:\n    if span and span.is_recording():\n        tenant_id = environ.get(\"HTTP_X_TENANT_ID\")\n        if tenant_id:\n            span.set_attribute(\"app.tenant_id\", tenant_id)\n\n\ndef response_hook(span: Span, status: str, response_headers) -> None:\n    if span and span.is_recording():\n        span.set_attribute(\"app.http_status_line\", status)\n\n\nFlaskInstrumentor().instrument_app(\n    app,\n    request_hook=request_hook,\n    response_hook=response_hook,\n)\n```\n\nKeep hook data low-cardinality and avoid copying raw user input, secrets, or large payloads into span attributes.\n\n### Capture selected HTTP headers\n\nHeader capture is configured through environment variables:\n\n```bash\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=\"x-request-id,user-agent\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=\"content-type\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=\".*session.*,set-cookie,authorization\"\n```\n\nImportant details:\n\n- header matching is case-insensitive\n- captured header attribute names are normalized to lowercase with `-` replaced by `_`\n- sanitize sensitive headers aggressively before enabling capture in production\n- the header-capture environment variables are still marked experimental upstream\n\n### Enable SQLCommenter support\n\nIf your database stack also supports SQLCommenter, Flask instrumentation can add route and framework context to downstream SQL comments:\n\n```python\nFlaskInstrumentor().instrument_app(\n    app,\n    enable_commenter=True,\n    commenter_options={\n        \"controller\": False,\n    },\n)\n```\n\nThis only helps when the database driver or ORM instrumentation in the same process also understands SQLCommenter.\n\n### Uninstrument in tests or app reload flows\n\nIf your tests rebuild or reuse the same Flask app object, remove instrumentation before reapplying it:\n\n```python\nFlaskInstrumentor().uninstrument_app(app)\n```\n\n## Configuration And OTLP Auth\n\nThis package does not have its own authentication flow. Authentication is configured on the exporter or collector side.\n\nCommon environment variables for OTLP export:\n\n```bash\nexport OTEL_SERVICE_NAME=orders-api\nexport OTEL_RESOURCE_ATTRIBUTES=\"deployment.environment.name=prod,service.namespace=payments\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>,x-tenant-id=acme\"\n```\n\nPractical notes:\n\n- set `OTEL_SERVICE_NAME` explicitly or your service can appear as `unknown_service`\n- use `OTEL_RESOURCE_ATTRIBUTES` for deployment environment, namespace, and version metadata\n- many hosted backends expect auth tokens in `OTEL_EXPORTER_OTLP_HEADERS`\n- choose `http://localhost:4318` with `http/protobuf` or `http://localhost:4317` for default gRPC-style OTLP setups\n\n## Common Pitfalls\n\n- Installing only `opentelemetry-instrumentation-flask` is not enough. Without an SDK/exporter or distro, spans are not exported anywhere useful.\n- Do not instrument the same app twice. Pick either manual `instrument_app(app)` or process-level `opentelemetry-instrument` for a given process.\n- Prefer `instrument_app(app)` in normal Flask app code. `FlaskInstrumentor().instrument()` patches `flask.Flask` globally.\n- Instrument before the app starts serving requests so routing and request handling are wrapped consistently.\n- Excluded URL lists are regex patterns, not Flask route names. Test them before deploying broad filters.\n- Capturing headers without sanitization can leak credentials, cookies, session IDs, or tenant identifiers.\n- If you want auto-instrumentation everywhere except Flask, use `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=flask`.\n\n## Version-Sensitive Notes For `0.61b0`\n\n- This guide targets `opentelemetry-instrumentation-flask 0.61b0`.\n- The package is on the OpenTelemetry Python contrib `0.x` prerelease line, so behavior and experimental configuration can change between releases.\n- The Flask instrumentation docs are published under the contrib `latest` docs site, which can move ahead of a pinned package version. Use the exact PyPI release page for version identity and the maintainer docs page for API behavior.\n- PyPI metadata for this release indicates Python `>=3.9`.\n\n## Official Sources Used\n\n- PyPI release page: `https://pypi.org/project/opentelemetry-instrumentation-flask/0.61b0/`\n- Flask instrumentation docs: `https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/flask/flask.html`\n- OpenTelemetry Python exporters docs: `https://opentelemetry.io/docs/languages/python/exporters/`\n- OpenTelemetry Python zero-code example docs: `https://opentelemetry.io/docs/zero-code/python/example/`\n- OpenTelemetry Python zero-code configuration docs: `https://opentelemetry.io/docs/zero-code/python/configuration/`\n"
  },
  {
    "path": "content/opentelemetry/docs/instrumentation-requests/python/DOC.md",
    "content": "---\nname: instrumentation-requests\ndescription: \"OpenTelemetry requests instrumentation for tracing and metrics on outbound Python requests calls\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.61b0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,requests,tracing,metrics,observability,http\"\n---\n\n# opentelemetry-instrumentation-requests Python Package Guide\n\n## Golden Rule\n\n`opentelemetry-instrumentation-requests` only patches `requests`; it does not configure telemetry export by itself. Set up the OpenTelemetry SDK or distro first, instrument once during process startup, and avoid combining manual `RequestsInstrumentor().instrument()` with `opentelemetry-instrument` for the same process.\n\n## Install\n\nInstall the instrumented library plus the OpenTelemetry pieces your app actually uses.\n\nMinimal manual setup:\n\n```bash\npython -m pip install \"requests\" \\\n  \"opentelemetry-api\" \\\n  \"opentelemetry-sdk\" \\\n  \"opentelemetry-instrumentation-requests==0.61b0\"\n```\n\nCommon production setup with OTLP export:\n\n```bash\npython -m pip install \"requests\" \\\n  \"opentelemetry-distro\" \\\n  \"opentelemetry-exporter-otlp\" \\\n  \"opentelemetry-instrumentation-requests==0.61b0\"\n```\n\nIf you are using auto-instrumentation broadly, the OpenTelemetry docs recommend:\n\n```bash\npython -m pip install opentelemetry-distro opentelemetry-exporter-otlp\nopentelemetry-bootstrap -a install\n```\n\n`opentelemetry-bootstrap -a install` installs matching instrumentation packages for libraries already present in the active environment.\n\n## Manual Setup\n\nFor code-driven setup, initialize the SDK before instrumenting `requests`:\n\n```python\nimport requests\n\nfrom opentelemetry import trace\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter\n\nresource = Resource.create({\"service.name\": \"billing-client\"})\n\nprovider = TracerProvider(resource=resource)\nprovider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))\ntrace.set_tracer_provider(provider)\n\nRequestsInstrumentor().instrument()\n\nresponse = requests.get(\"https://httpbin.org/get\", timeout=10)\nprint(response.status_code)\n```\n\nUse a real exporter such as OTLP in production; `ConsoleSpanExporter` is mainly useful to confirm that spans are being created.\n\nIf your app manages providers explicitly, `instrument()` also accepts `tracer_provider=` and `meter_provider=` keyword arguments.\n\n## Auto-Instrumentation\n\nIf the process already uses the OpenTelemetry Python agent, do not also call `RequestsInstrumentor().instrument()` in your code.\n\nCLI example:\n\n```bash\nopentelemetry-instrument \\\n  --traces_exporter otlp \\\n  --metrics_exporter console \\\n  --service_name billing-client \\\n  python app.py\n```\n\nEnvironment-variable example:\n\n```bash\nexport OTEL_SERVICE_NAME=\"billing-client\"\nexport OTEL_TRACES_EXPORTER=\"otlp\"\nexport OTEL_METRICS_EXPORTER=\"console\"\nexport OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=\"http://127.0.0.1:4318/v1/traces\"\n\nopentelemetry-instrument python app.py\n```\n\nAuto-instrumentation uses monkey patching, so start the process through `opentelemetry-instrument` from the beginning rather than enabling it halfway through a long-running worker.\n\n## Core Usage\n\n### Instrument all outbound `requests` traffic\n\nAfter `RequestsInstrumentor().instrument()`, normal `requests.get()`, `post()`, and `Session` calls emit client telemetry automatically:\n\n```python\nimport requests\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\nRequestsInstrumentor().instrument()\n\nsession = requests.Session()\nsession.headers[\"Authorization\"] = \"Bearer secret-token\"\n\nresponse = session.post(\n    \"https://api.example.com/orders\",\n    json={\"id\": 123},\n    timeout=10,\n)\n```\n\n### Add request and response hooks\n\nHooks are the main extension point for attaching application-specific attributes:\n\n```python\nimport requests\n\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\ndef request_hook(span, request_obj):\n    if span and span.is_recording():\n        request_id = request_obj.headers.get(\"X-Request-ID\")\n        if request_id:\n            span.set_attribute(\"app.request_id\", request_id)\n\ndef response_hook(span, request_obj, response):\n    if span and span.is_recording():\n        span.set_attribute(\"app.status_family\", f\"{response.status_code // 100}xx\")\n\nRequestsInstrumentor().instrument(\n    request_hook=request_hook,\n    response_hook=response_hook,\n)\n\nrequests.get(\"https://httpbin.org/status/200\", timeout=10)\n```\n\n`request_obj` is a `requests.PreparedRequest`, and `response` is a `requests.Response`.\n\n### Exclude noisy endpoints\n\nUse regex-based exclude lists for health checks, metadata calls, or other low-value traffic:\n\n```bash\nexport OTEL_PYTHON_REQUESTS_EXCLUDED_URLS=\"healthcheck,client/.*/info\"\n```\n\nYou can also pass `excluded_urls=` directly to `instrument()` if you want the rule in code instead of environment config.\n\n### Capture selected request and response headers\n\n`0.61b0` documents client request and client response header capture through environment variables:\n\n```bash\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST=\"x-request-id,content-type\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE=\"content-type,x-ratelimit-remaining\"\nexport OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=\"authorization,cookie,set-cookie\"\n```\n\nHeader capture is useful for debugging, but sanitize aggressively. These environment variable names are still marked experimental in the upstream docs.\n\n### Customize request-duration histogram boundaries\n\nIf you are tuning metrics buckets, pass explicit boundaries:\n\n```python\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\nRequestsInstrumentor().instrument(\n    duration_histogram_boundaries=[0.0, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]\n)\n```\n\nBe careful here during semantic-convention migration: the source code for `0.61b0` still supports both the old `http.client.duration` metric in milliseconds and the newer `http.client.request.duration` metric in seconds, depending on the active semantic-convention mode.\n\n## Configuration And Auth Notes\n\n- This package has no package-specific authentication flow.\n- Outbound request authentication is whatever your `requests` code sets, such as `Authorization` headers, cookies, or client certificates.\n- Telemetry exporter authentication is configured on the SDK/exporter or distro side, not on `RequestsInstrumentor`.\n- The instrumentor injects tracing context headers into outbound requests automatically. Do not confuse those propagation headers with application auth headers.\n\n## Common Pitfalls\n\n- No SDK, no telemetry. Installing this package alone does not export spans anywhere.\n- Do not double instrument. Pick either manual `RequestsInstrumentor().instrument()` or the `opentelemetry-instrument` launcher for a given process.\n- Instrument as early as possible in startup so all worker traffic is patched consistently.\n- This package instruments outbound HTTP clients only. It does not create inbound server spans for Django, Flask, FastAPI, or ASGI apps.\n- If you capture headers, sanitize `authorization`, `cookie`, `set-cookie`, and any tenant- or user-identifying custom headers.\n- Exclude-list patterns are regexes, not plain path prefixes. Test them before assuming traffic is filtered.\n- If you need to remove instrumentation from a single `requests.Session`, use `RequestsInstrumentor.uninstrument_session(session)`.\n\n## Version-Sensitive Notes For `0.61b0`\n\n- PyPI lists `0.61b0` as a pre-release published on March 4, 2026. This package is still in the contrib `0.x` beta line.\n- The contrib repository states these instrumentation libraries are currently beta and generally should not be treated like fully stable `1.0` APIs.\n- The contrib repository also notes a monthly release cadence, so version drift is common. Re-check PyPI before pinning examples in generated code.\n- HTTP semantic-convention migration is active across Python HTTP-related instrumentations. Attribute names and metric names can differ across environments depending on semantic-convention opt-in settings.\n"
  },
  {
    "path": "content/opentelemetry/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"OpenTelemetry SDK package guide for Python applications using manual instrumentation, resources, exporters, metrics, and logs\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"opentelemetry,observability,telemetry,tracing,metrics,logs,otlp\"\n---\n\n# OpenTelemetry SDK Python Package Guide\n\n## Golden Rule\n\nUse `opentelemetry-sdk` in application code, not in reusable libraries. Application code installs and configures the SDK, exporters, and resources; libraries should depend on `opentelemetry-api` only and emit telemetry only when the host application has configured an SDK.\n\nFor production, set a real `service.name`, export through OTLP to an OpenTelemetry Collector, and treat console exporters as local debugging tools.\n\n## Install\n\nFor manual instrumentation, install the SDK and usually pin the matching API version too:\n\n```bash\npython -m pip install \"opentelemetry-api==1.40.0\" \"opentelemetry-sdk==1.40.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"opentelemetry-api==1.40.0\" \"opentelemetry-sdk==1.40.0\"\npoetry add \"opentelemetry-api==1.40.0\" \"opentelemetry-sdk==1.40.0\"\n```\n\nThe SDK does not include every exporter or instrumentation package. Install what you actually use:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp-proto-http==1.40.0\"\npython -m pip install \"opentelemetry-exporter-otlp-proto-grpc==1.40.0\"\npython -m pip install \"opentelemetry-instrumentation-requests==0.61b0\"\n```\n\nNotes:\n\n- `opentelemetry-api` and `opentelemetry-sdk` are separate packages by design.\n- Exporters and instrumentation libraries are separate extension packages.\n- If you want zero-code or low-code auto-instrumentation, use the Python distro and contrib instrumentations instead of trying to make `opentelemetry-sdk` do everything on its own.\n\n## Initialize Tracing\n\nThis is the shortest reliable manual setup for local development:\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter\n\nresource = Resource.create(\n    {\n        \"service.name\": \"checkout-api\",\n        \"service.version\": \"1.40.0\",\n        \"deployment.environment\": \"dev\",\n    }\n)\n\ntrace_provider = TracerProvider(resource=resource)\ntrace_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))\ntrace.set_tracer_provider(trace_provider)\n\ntracer = trace.get_tracer(__name__)\n\nwith tracer.start_as_current_span(\"create-order\") as span:\n    span.set_attribute(\"app.order_id\", \"ord_123\")\n    span.add_event(\"validating_request\")\n```\n\nWhy this shape:\n\n- `Resource.create(...)` is where service identity belongs.\n- `BatchSpanProcessor` is the normal production-oriented processor; `SimpleSpanProcessor` is mostly for debugging or very small programs.\n- `trace.set_tracer_provider(...)` configures the process-wide provider. Do this once during startup.\n\nIn short-lived scripts and tests, flush before exit:\n\n```python\ntrace.get_tracer_provider().force_flush()\ntrace.get_tracer_provider().shutdown()\n```\n\n## Add Metrics\n\nMetrics require a `MeterProvider` plus at least one `MetricReader`:\n\n```python\nfrom opentelemetry import metrics\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import (\n    ConsoleMetricExporter,\n    PeriodicExportingMetricReader,\n)\nfrom opentelemetry.sdk.resources import Resource\n\nmetric_reader = PeriodicExportingMetricReader(\n    ConsoleMetricExporter(),\n    export_interval_millis=5000,\n)\n\nmeter_provider = MeterProvider(\n    metric_readers=[metric_reader],\n    resource=Resource.create({\"service.name\": \"checkout-api\"}),\n)\nmetrics.set_meter_provider(meter_provider)\n\nmeter = metrics.get_meter(__name__)\nrequest_counter = meter.create_counter(\"http.server.requests\")\nrequest_counter.add(1, {\"http.method\": \"GET\", \"http.route\": \"/healthz\"})\n```\n\nNotes:\n\n- `PeriodicExportingMetricReader` handles timed collection and export.\n- Console metrics are diagnostic output only.\n- For unit tests, `InMemoryMetricReader` is often a better fit than waiting for timed exports.\n\n## Export To A Collector With OTLP\n\nCollector-first OTLP is the safest default. Install one OTLP exporter package and configure it with environment variables instead of hard-coding endpoints in application code.\n\nOTLP over HTTP:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp-proto-http==1.40.0\"\n\nexport OTEL_SERVICE_NAME=\"checkout-api\"\nexport OTEL_RESOURCE_ATTRIBUTES=\"deployment.environment=prod,service.version=1.40.0\"\nexport OTEL_EXPORTER_OTLP_PROTOCOL=\"http/protobuf\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4318\"\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>\"\n```\n\nOTLP over gRPC:\n\n```bash\npython -m pip install \"opentelemetry-exporter-otlp-proto-grpc==1.40.0\"\n\nexport OTEL_SERVICE_NAME=\"checkout-api\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4317\"\nexport OTEL_EXPORTER_OTLP_HEADERS=\"authorization=Bearer <token>\"\n```\n\nImportant endpoint behavior:\n\n- With `OTEL_EXPORTER_OTLP_ENDPOINT` and OTLP/HTTP, the exporter appends per-signal paths such as `/v1/traces`, `/v1/metrics`, and `/v1/logs`.\n- With per-signal variables such as `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, the URL is used as-is.\n- `OTEL_EXPORTER_OTLP_HEADERS` is the standard place for backend auth headers.\n- Certificate, compression, timeout, and per-signal overrides are also available through OTLP exporter environment variables.\n\n## Logs\n\nPython logs support is still in development, so keep log-specific code conservative and version-aware.\n\nCurrent basic setup:\n\n```python\nimport logging\n\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.sdk._logs import LoggerProvider, LoggingHandler\nfrom opentelemetry.sdk._logs.export import (\n    BatchLogRecordProcessor,\n    ConsoleLogRecordExporter,\n)\nfrom opentelemetry.sdk.resources import Resource\n\nlogger_provider = LoggerProvider(\n    resource=Resource.create({\"service.name\": \"checkout-api\"})\n)\nlogger_provider.add_log_record_processor(\n    BatchLogRecordProcessor(ConsoleLogRecordExporter())\n)\nset_logger_provider(logger_provider)\n\nhandler = LoggingHandler(level=logging.INFO, logger_provider=logger_provider)\nlogging.basicConfig(handlers=[handler], level=logging.INFO)\n\nlogging.getLogger(__name__).info(\"payment accepted\", extra={\"order_id\": \"ord_123\"})\n```\n\nUse logs only if you specifically need them. Traces and metrics have a much more stable Python surface today.\n\n## Auto-Instrumentation And Third-Party Libraries\n\nTwo rules matter:\n\n- If you are instrumenting your application, install the SDK and then add instrumentation packages for frameworks and clients you use.\n- If you are writing a reusable library, do not take a hard dependency on `opentelemetry-sdk`; depend on `opentelemetry-api` only.\n\nTypical application add-ons:\n\n```bash\npython -m pip install \"opentelemetry-instrumentation-fastapi==0.61b0\"\npython -m pip install \"opentelemetry-instrumentation-sqlalchemy==0.61b0\"\npython -m pip install \"opentelemetry-instrumentation-requests==0.61b0\"\n```\n\n## Common Pitfalls\n\n- Forgetting to set `service.name`. Telemetry without a stable service identity is much harder to use.\n- Installing only `opentelemetry-sdk` and expecting OTLP export to work without an OTLP exporter package.\n- Initializing providers multiple times. The process-wide tracer and meter providers should normally be set once at startup.\n- Using console exporters in production. Send data to a Collector instead.\n- Ending the process immediately after emitting spans or metrics. Call `force_flush()` or `shutdown()` in short-lived processes.\n- Treating logs as equally stable with traces and metrics in Python. They are not.\n- Putting `opentelemetry-sdk` into a reusable library dependency tree. That makes SDK selection harder for the final application.\n- Mixing incompatible package series. Keep `opentelemetry-api`, `opentelemetry-sdk`, OTLP exporters, and semantic-convention-sensitive integrations aligned to the same release family when possible.\n- Copying old logging examples that use pre-1.39 log class names.\n\n## Version-Sensitive Notes For 1.40.0\n\n- PyPI lists `1.40.0` as the latest `opentelemetry-sdk` release on March 12, 2026, released on March 4, 2026.\n- Python support in the official docs is `3.9+`, and the `1.40.0` changelog adds Python `3.14` support.\n- The `1.40.0` changelog deprecates `LoggingHandler` in favor of `opentelemetry-instrumentation-logging`. Existing `LoggingHandler` examples still work for now, but prefer newer logging guidance when wiring fresh code.\n- The `1.39.0` line made breaking log-signal renames from `Log` to `LogRecord` types. If a snippet uses names such as `ConsoleLogExporter`, it is from an older package line; current code should use `ConsoleLogRecordExporter`.\n- The `1.40.0` changelog also drops old Jaeger exporter environment variables that were already obsolete after the Jaeger exporter removal in `1.22.0`. Prefer OTLP-based export paths.\n"
  },
  {
    "path": "content/optuna/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Optuna package guide for Python hyperparameter optimization, study storage, and parallel workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.7.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"optuna,python,hyperparameter-optimization,ml,study,pruning,samplers\"\n---\n\n# Optuna Python Package Guide\n\n## Golden Rule\n\nUse `optuna` when you need programmatic hyperparameter optimization in Python, and keep the objective function focused on three things:\n\n1. Sample parameters from `trial`.\n2. Train or evaluate the model.\n3. Return one numeric objective value.\n\nSet study direction and storage explicitly instead of relying on defaults from old examples.\n\n```bash\npip install optuna==4.7.0\n```\n\n## What Optuna Is Good At\n\nOptuna is a define-by-run hyperparameter optimization framework. The core concepts are:\n\n- `Study`: the optimization run and its storage-backed history\n- `Trial`: one evaluation of your objective function\n- Sampler: how Optuna chooses the next parameters\n- Pruner: how Optuna stops weak trials early\n\nThe default sampler is `TPESampler`.\n\n## Installation\n\n### pip\n\n```bash\npip install optuna\n```\n\n### uv\n\n```bash\nuv add optuna\n```\n\n### Poetry\n\n```bash\npoetry add optuna\n```\n\n### Conda\n\n```bash\nconda install -c conda-forge optuna\n```\n\n## Quick Start\n\nThis is the basic shape to copy into application code.\n\n```python\nimport optuna\n\ndef objective(trial: optuna.Trial) -> float:\n    learning_rate = trial.suggest_float(\"learning_rate\", 1e-5, 1e-1, log=True)\n    max_depth = trial.suggest_int(\"max_depth\", 3, 12)\n    subsample = trial.suggest_float(\"subsample\", 0.5, 1.0)\n\n    # Replace this block with real training and validation.\n    score = (max_depth - 7) ** 2 + abs(subsample - 0.8) + learning_rate\n    return score\n\nsampler = optuna.samplers.TPESampler(seed=42)\nstudy = optuna.create_study(\n    study_name=\"example-study\",\n    direction=\"minimize\",\n    sampler=sampler,\n)\nstudy.optimize(objective, n_trials=50)\n\nprint(study.best_value)\nprint(study.best_params)\n```\n\nNotes:\n\n- `create_study()` minimizes by default. Set `direction=\"maximize\"` for metrics such as accuracy or AUC.\n- Use `directions=[...]` for multi-objective studies.\n- Read results from `study.best_trial`, `study.best_value`, `study.best_params`, or `study.trials_dataframe()`.\n\n## Pruning And Intermediate Metrics\n\nUse pruning when your training loop can report intermediate scores by epoch, boosting round, or step.\n\n```python\nimport optuna\n\ndef objective(trial: optuna.Trial) -> float:\n    alpha = trial.suggest_float(\"alpha\", 1e-5, 1e-1, log=True)\n\n    for step in range(20):\n        validation_loss = train_one_step(alpha=alpha, step=step)\n        trial.report(validation_loss, step=step)\n\n        if trial.should_prune():\n            raise optuna.TrialPruned()\n\n    return validation_loss\n\nstudy = optuna.create_study(\n    direction=\"minimize\",\n    pruner=optuna.pruners.SuccessiveHalvingPruner(),\n)\nstudy.optimize(objective, n_trials=100)\n```\n\nPractical guidance:\n\n- `MedianPruner` appears in many examples, but the Optuna tutorial notes that `SuccessiveHalvingPruner` and `HyperbandPruner` generally outperform it.\n- Raise `optuna.TrialPruned()` when `trial.should_prune()` returns `True`.\n- Framework-specific pruning callbacks may live in `optuna-integration`, not only in `optuna` itself.\n\n## Storage, Persistence, And Resume\n\nChoose storage based on how many workers you need and whether results must survive process restarts.\n\n### Single process or throwaway runs\n\nThe default in-memory storage is enough:\n\n```python\nstudy = optuna.create_study(direction=\"minimize\")\nstudy.optimize(objective, n_trials=20)\n```\n\n### Local persistence with SQLite\n\nUse SQLite when you want a simple local file you can resume later.\n\n```python\nimport optuna\n\nstudy = optuna.create_study(\n    study_name=\"sqlite-study\",\n    storage=\"sqlite:///example.db\",\n    load_if_exists=True,\n    direction=\"minimize\",\n)\nstudy.optimize(objective, n_trials=50)\n```\n\n### File-backed shared storage with `JournalStorage`\n\nUse journal storage for shared file-backed workflows and multi-process runs on one machine.\n\n```python\nimport optuna\nfrom optuna.storages import JournalStorage\nfrom optuna.storages.journal import JournalFileBackend\n\nstorage = JournalStorage(JournalFileBackend(\"./optuna_journal_storage.log\"))\nstudy = optuna.create_study(\n    study_name=\"journal-study\",\n    storage=storage,\n    load_if_exists=True,\n    direction=\"minimize\",\n)\nstudy.optimize(objective, n_trials=50)\n```\n\n### Server-backed storage for multi-node runs\n\nUse an RDB backend when multiple machines must share the same study.\n\n```python\nimport os\nimport optuna\n\nstudy = optuna.create_study(\n    study_name=\"distributed-study\",\n    storage=os.environ[\"OPTUNA_STORAGE_URL\"],\n    load_if_exists=True,\n    direction=\"minimize\",\n)\nstudy.optimize(objective, n_trials=100)\n```\n\nExample environment variable:\n\n```bash\nexport OPTUNA_STORAGE_URL='mysql://username:password@127.0.0.1:3306/example'\n```\n\nIf you need very large multi-node throughput, Optuna also documents `GrpcStorageProxy` on top of `RDBStorage`.\n\n## Config And Auth\n\nOptuna does not have package-level auth settings. Configuration is mostly:\n\n- study name\n- objective direction or directions\n- sampler and pruner choices\n- storage backend\n- storage connection string or storage object\n\nAuthentication only applies to the backing storage you choose:\n\n- SQLite: no auth, local file path\n- Journal storage: no auth, local file path\n- MySQL/PostgreSQL or another RDB: credentials are embedded in the storage URL or handled by the SQLAlchemy backend you configure\n\nFor production code:\n\n- keep storage URLs in environment variables or secrets management\n- use `load_if_exists=True` when multiple runs may attach to the same study\n- set a stable `study_name` for resumable or reproducible workflows\n\n## Parallelization\n\nOptuna supports three common parallel patterns.\n\n### Threads in one process\n\n```python\nstudy.optimize(objective, n_trials=100, n_jobs=4)\n```\n\nUse this only when threading is actually useful for your workload. The Optuna FAQ notes that `n_jobs != 1` uses multi-threading and Python's GIL means CPU-bound Python code usually will not speed up much.\n\n### Multiple processes on one machine\n\nUse shared storage such as `JournalStorage` or `RDBStorage`, then let each process attach to the same study.\n\n### Multiple machines\n\nUse `RDBStorage`, and consider `GrpcStorageProxy` if you need very high concurrency.\n\n## Reproducibility\n\nFor reproducible runs:\n\n```python\nimport optuna\n\nsampler = optuna.samplers.TPESampler(seed=10)\nstudy = optuna.create_study(\n    study_name=\"reproducible-study\",\n    direction=\"minimize\",\n    sampler=sampler,\n)\nstudy.optimize(objective, n_trials=50)\n```\n\nImportant caveats from the official FAQ:\n\n- reproducibility is much harder in parallel or distributed optimization\n- `HyperbandPruner` reproducibility also depends on a fixed `study_name`\n- storage does not persist the in-memory state of sampler or pruner instances\n\nIf you resume a study and need sampler continuity, persist and restore the sampler object yourself, for example with `pickle`.\n\n## Common Pitfalls\n\n- Forgetting `direction=\"maximize\"` for accuracy-like metrics. The default is minimize.\n- Treating `n_jobs` as multiprocessing. It is threading.\n- Using `InMemoryStorage` across processes. It is not shareable across processes.\n- Assuming storage resumes sampler state automatically. It does not.\n- Returning `float(\"nan\")` from the objective. Optuna marks that trial as failed.\n- Letting exceptions escape the objective when you intended the study to continue. Use `catch=(YourRecoverableError,)` in `study.optimize(...)` when appropriate.\n- Running large numbers of trials without memory cleanup. If memory grows, use `gc_after_trial=True` or call `gc.collect()` from a callback.\n- Copying old tutorials that import removed multi-objective APIs from `optuna.multi_objective`.\n- Expecting every integration to stay in core `optuna`. Many third-party integrations are migrating to `optuna-integration`.\n\n## Version-Sensitive Notes For 4.7.0\n\n- This guide targets Optuna `4.7.0`, the current PyPI release published on `2026-01-19`.\n- Optuna `4.7.0` requires Python `3.9` or newer.\n- Since Optuna `4.0`, old `optuna.multi_objective.*` APIs are removed. Use the normal `Study` and `Trial` APIs with `directions=[...]`.\n- Since Optuna `4.0`, `JournalStorage` is officially supported and the reorganized `optuna.storages.journal.JournalFileBackend` path is the stable form to use.\n- The `optuna.integration` docs explicitly note that third-party integrations are migrating to the separate `optuna-integration` package.\n\n## Official Context\n\n- Stable docs: https://optuna.readthedocs.io/en/stable/\n- Installation: https://optuna.readthedocs.io/en/stable/installation.html\n- Tutorial: https://optuna.readthedocs.io/en/stable/tutorial/\n- API reference: https://optuna.readthedocs.io/en/stable/reference/\n- FAQ: https://optuna.readthedocs.io/en/stable/faq.html\n- PyPI: https://pypi.org/project/optuna/\n- Repository: https://github.com/optuna/optuna\n"
  },
  {
    "path": "content/orjson/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"orjson package guide for fast Python JSON serialization and deserialization with dataclass, datetime, UUID, and numpy support\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.11.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"orjson,python,json,serialization,deserialization,dataclass,datetime,numpy\"\n---\n\n# orjson Python Package Guide\n\n## Golden Rule\n\nUse `orjson` when a Python project needs very fast JSON encoding and decoding on CPython, and treat it as a bytes-first library. `orjson.dumps()` returns UTF-8 `bytes`, not `str`, and `orjson.loads()` is strict about valid UTF-8 and valid RFC 8259 JSON.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"orjson==3.11.7\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"orjson==3.11.7\"\npoetry add \"orjson==3.11.7\"\n```\n\nNotes:\n\n- PyPI publishes wheels for common Linux, macOS, and Windows targets. Normal installs should not need a local toolchain.\n- If `pip` falls back to building from source, upstream says packaging requires Rust `1.89+`, a C compiler, and `maturin`.\n- `orjson` does not support PyPy.\n\n## Core API Surface\n\nThe library is intentionally small:\n\n- `orjson.dumps(obj, *, default=..., option=...) -> bytes`\n- `orjson.loads(data) -> Any`\n\nPractical implications:\n\n- `dumps()` returns `bytes`, so decode only at boundaries that require `str`, such as text files or framework APIs that do not accept bytes.\n- `loads()` accepts `bytes`, `bytearray`, `memoryview`, and `str`. Prefer passing bytes-like input directly instead of decoding first.\n- The library does not handle file I/O, NDJSON/JSONL framing, or schema-aware object reconstruction.\n\n## Basic Usage\n\n### Serialize and deserialize\n\n```python\nimport orjson\n\npayload = {\n    \"ok\": True,\n    \"count\": 3,\n    \"tags\": [\"a\", \"b\"],\n}\n\nblob = orjson.dumps(payload)\nassert isinstance(blob, bytes)\n\ndata = orjson.loads(blob)\nassert data == payload\n```\n\nIf an API needs a string body:\n\n```python\nbody = orjson.dumps(payload).decode(\"utf-8\")\n```\n\n### Pretty-print or append newlines\n\n```python\nimport orjson\n\nblob = orjson.dumps(\n    {\"a\": 1, \"nested\": {\"b\": True}},\n    option=orjson.OPT_INDENT_2 | orjson.OPT_APPEND_NEWLINE,\n)\n```\n\nUse pretty printing for logs, snapshots, or fixtures. Skip it on hot paths.\n\n## Common Native Types\n\n`orjson` natively serializes many types agents often reach for `default=` to handle:\n\n- `dataclasses.dataclass`\n- `datetime.datetime`, `datetime.date`, `datetime.time`\n- `uuid.UUID`\n- `typing.TypedDict`\n- enums whose values are supported types\n\nExample:\n\n```python\nfrom dataclasses import dataclass\nfrom datetime import UTC, datetime\nfrom uuid import UUID\n\nimport orjson\n\n@dataclass\nclass Event:\n    id: UUID\n    created_at: datetime\n    name: str\n\nevent = Event(\n    id=UUID(\"12345678-1234-5678-1234-567812345678\"),\n    created_at=datetime(2026, 3, 12, 10, 30, tzinfo=UTC),\n    name=\"build.finished\",\n)\n\nblob = orjson.dumps(event)\n```\n\n## Custom Serialization\n\nUse `default=` only for unsupported types or when you explicitly want to override native behavior.\n\n```python\nfrom decimal import Decimal\n\nimport orjson\n\ndef default(obj):\n    if isinstance(obj, Decimal):\n        return str(obj)\n    raise TypeError\n\nblob = orjson.dumps({\"price\": Decimal(\"12.50\")}, default=default)\n```\n\nImportant behavior:\n\n- Your `default` function must raise `TypeError` for unhandled objects.\n- If `default` forgets to raise, Python returns `None` implicitly and `orjson` will serialize that as `null`.\n- `orjson` raises `JSONEncodeError` on unsupported objects, circular references, invalid UTF-8 strings, and integers beyond its supported range.\n\n### Override native dataclass, datetime, or subclass handling\n\nVersion 3 serializes dataclasses and UUIDs by default. If you need custom behavior, combine `default=` with passthrough options:\n\n```python\nimport dataclasses\nfrom datetime import datetime\n\nimport orjson\n\n@dataclasses.dataclass\nclass User:\n    id: str\n    password: str\n\ndef default(obj):\n    if isinstance(obj, User):\n        return {\"id\": obj.id}\n    if isinstance(obj, datetime):\n        return obj.strftime(\"%a, %d %b %Y %H:%M:%S GMT\")\n    raise TypeError\n\nblob = orjson.dumps(\n    {\n        \"user\": User(\"u_123\", \"secret\"),\n        \"created_at\": datetime(2026, 3, 12, 10, 30),\n    },\n    default=default,\n    option=orjson.OPT_PASSTHROUGH_DATACLASS | orjson.OPT_PASSTHROUGH_DATETIME,\n)\n```\n\nUse `OPT_PASSTHROUGH_SUBCLASS` the same way when subclasses of builtin types should not serialize through their base type behavior.\n\n## Datetime and Key Options\n\n`orjson` serializes datetimes as RFC 3339 strings.\n\n```python\nfrom datetime import UTC, datetime\n\nimport orjson\n\ndt = datetime(2026, 3, 12, 10, 30, tzinfo=UTC)\n\nprint(orjson.dumps(dt))\nprint(orjson.dumps(dt, option=orjson.OPT_UTC_Z))\nprint(orjson.dumps(datetime(2026, 3, 12, 10, 30), option=orjson.OPT_NAIVE_UTC))\n```\n\nUse these options when the receiving system has explicit formatting requirements:\n\n- `OPT_UTC_Z`: render UTC as `Z` instead of `+00:00`\n- `OPT_NAIVE_UTC`: treat naive `datetime` values as UTC during serialization\n- `OPT_NON_STR_KEYS`: allow keys like `int`, `UUID`, and `datetime`\n\nBe careful with `OPT_NON_STR_KEYS`: different Python keys can serialize to the same JSON string key, which can silently collapse data.\n\n## Numpy\n\nNumpy serialization is opt-in:\n\n```python\nimport numpy as np\nimport orjson\n\narr = np.array([[1, 2], [3, 4]], dtype=np.int64)\nblob = orjson.dumps(arr, option=orjson.OPT_SERIALIZE_NUMPY)\n```\n\nNotes:\n\n- Upstream states `orjson` is compatible with numpy v1 and v2.\n- Arrays must be contiguous C arrays and use supported dtypes.\n- Unsupported arrays fall through to `default=`.\n- Native numpy serialization can produce different float rounding than `ndarray.tolist()` because it avoids converting through Python `double` first.\n\n## Strictness And Performance Notes\n\n- `loads()` rejects invalid JSON values such as `NaN`, `Infinity`, and `-Infinity`, even though Python's standard `json` module accepts them by default.\n- `dumps()` serializes `NaN`, `Infinity`, and `-Infinity` as `null`.\n- The GIL is held for the duration of `dumps()` and `loads()`.\n- `OPT_SORT_KEYS` is available for deterministic output, but upstream documents a substantial performance penalty.\n- `OPT_STRICT_INTEGER` enforces the 53-bit integer range for ecosystems that cannot safely consume wider integers, such as JavaScript clients.\n\n## Fragment For Embedding Cached JSON\n\n`orjson.Fragment` lets you embed already-serialized JSON without parsing it first:\n\n```python\nimport orjson\n\ncached = b'{\"roles\":[\"admin\",\"editor\"]}'\nblob = orjson.dumps({\"user_id\": 7, \"permissions\": orjson.Fragment(cached)})\n```\n\nUse this when you already trust the JSON source, such as a cached payload or JSONB column. `Fragment` does not reformat or validate the embedded JSON beyond UTF-8 checks for `str` input.\n\n## Config And Auth\n\n`orjson` has no service auth, network setup, credentials, or environment-variable configuration.\n\nThe main configuration surface is the `option=` bitmask on `dumps()`. The options most likely to matter in application code are:\n\n- `OPT_INDENT_2`\n- `OPT_APPEND_NEWLINE`\n- `OPT_NAIVE_UTC`\n- `OPT_UTC_Z`\n- `OPT_NON_STR_KEYS`\n- `OPT_SERIALIZE_NUMPY`\n- `OPT_SORT_KEYS`\n- `OPT_STRICT_INTEGER`\n- `OPT_PASSTHROUGH_DATACLASS`\n- `OPT_PASSTHROUGH_DATETIME`\n- `OPT_PASSTHROUGH_SUBCLASS`\n\n## Common Pitfalls\n\n- Expecting `str` output. `orjson.dumps()` returns `bytes`.\n- Decoding bytes before `loads()`. If you already have bytes, pass them directly.\n- Assuming it behaves exactly like `json`. `loads()` is stricter, and `dumps()` has different defaults around bytes output and native type support.\n- Using `default=` to customize dataclasses or datetimes without enabling the relevant passthrough option.\n- Turning on `OPT_NON_STR_KEYS` without considering duplicate-key collisions after string conversion.\n- Turning on `OPT_SORT_KEYS` in hot paths. Upstream calls out a real performance cost.\n- Forgetting `OPT_SERIALIZE_NUMPY` for ndarray payloads.\n- Assuming it supports PyPy, subinterpreters, NDJSON/JSONL, object reconstruction, or file helpers. It intentionally does not.\n\n## Version-Sensitive Notes For 3.11.7\n\n- PyPI lists `3.11.7` as the latest release on `2026-02-02`.\n- The `3.11.7` changelog notes a faster float serializer and a byte-level output change for positive exponents, for example `1.2e+30` instead of `1.2e30`. Both are JSON-spec compliant, but exact-string regression tests may need updates.\n- The prior `3.11.6` release dropped Python `3.9` support, so `3.11.7` should be treated as Python `3.10+` only.\n- The changelog for `3.11.6` also raised the source-build requirement to Rust `1.89+`.\n- Version 3 behavior that still trips older examples: dataclasses and UUIDs serialize by default, and subclasses of `str`, `int`, `dict`, and `list` also serialize by default unless you opt into passthrough behavior.\n\n## Official Sources\n\n- Documentation and README: `https://github.com/ijl/orjson`\n- PyPI package page: `https://pypi.org/project/orjson/`\n- PyPI JSON metadata: `https://pypi.org/pypi/orjson/json`\n- Changelog: `https://github.com/ijl/orjson/blob/master/CHANGELOG.md`\n"
  },
  {
    "path": "content/packaging/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"packaging for Python - PEP 440 versions, specifiers, markers, wheel tags, metadata, and lock files\"\nmetadata:\n  languages: \"python\"\n  versions: \"26.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"packaging,pypi,pep440,requirements,wheels,metadata\"\n---\n\n# packaging Python Package Guide\n\n## What It Is\n\n`packaging` is the PyPA utility library for parsing and validating Python packaging data. Use it when code needs to work with:\n\n- PEP 440 versions\n- version specifiers such as `>=1.2,<2`\n- PEP 508 requirement strings\n- environment markers\n- normalized distribution names\n- wheel and sdist filenames\n- wheel compatibility tags\n- core metadata\n- Python lock files\n\nIt does not install packages, resolve dependencies, or talk to package indexes. Use `pip`, `uv`, Poetry, or another installer for that.\n\n## Installation\n\n```bash\npip install packaging==26.0\n```\n\n```bash\nuv add packaging==26.0\n```\n\nPython requirement for `packaging` 26.0: Python 3.8+.\n\n`packaging` uses calendar-based versioning (`YY.N`).\n\n## Imports At A Glance\n\n```python\nfrom packaging.version import Version, InvalidVersion, parse\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.requirements import Requirement, InvalidRequirement\nfrom packaging.markers import Marker, default_environment\nfrom packaging.utils import canonicalize_name, canonicalize_version\nfrom packaging.tags import sys_tags\nfrom packaging.metadata import Metadata\n```\n\n## Setup Notes\n\n- No auth, credentials, or service configuration is required.\n- Most APIs are pure parsing and comparison helpers.\n- Invalid inputs raise `InvalidVersion`, `InvalidRequirement`, `InvalidSpecifier`, or metadata exceptions. Catch them at input boundaries.\n- Prefer `Version(...)` when you need strict PEP 440 validation. Use `parse(...)` only when you want the same validated object with a shorter call site.\n\n## Core Usage\n\n### Parse And Compare Versions\n\n```python\nfrom packaging.version import Version\n\ncurrent = Version(\"26.0\")\nminimum = Version(\"25.0\")\n\nif current > minimum:\n    print(\"new enough\")\n\nassert Version(\"1.0a5\") < Version(\"1.0\")\nassert Version(\"1.0.post1\") > Version(\"1.0\")\n```\n\nUse `Version` instead of string comparison. PEP 440 ordering is not the same as lexical ordering.\n\n### Check Whether Versions Match A Specifier\n\n```python\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.version import Version\n\nspec = SpecifierSet(\">=25,<27\")\n\nassert Version(\"26.0\") in spec\nassert Version(\"27.0\") not in spec\n\ncandidates = [\"24.2\", \"25.0\", \"26.0\", \"26.0rc1\"]\nallowed = [v for v in candidates if Version(v) in spec]\nprint(allowed)  # ['25.0', '26.0']\n```\n\nFor candidate lists, `SpecifierSet.filter(...)` is often cleaner:\n\n```python\nfrom packaging.specifiers import SpecifierSet\n\nspec = SpecifierSet(\">=1.0,<2.0\")\nprint(list(spec.filter([\"0.9\", \"1.0\", \"1.5\", \"2.0\"])))\n```\n\n### Parse PEP 508 Requirements\n\n```python\nfrom packaging.requirements import Requirement\n\nreq = Requirement('requests[security]>=2.31; python_version >= \"3.10\"')\n\nprint(req.name)        # requests\nprint(req.extras)      # {'security'}\nprint(req.specifier)   # >=2.31\nprint(req.marker)      # python_version >= \"3.10\"\nprint(req.url)         # None\n```\n\nThis is the right entry point for parsing dependency strings from `pyproject.toml`, lock data, or config files.\n\n### Evaluate Environment Markers\n\n```python\nfrom packaging.markers import Marker, default_environment\n\nmarker = Marker('python_version >= \"3.10\" and sys_platform == \"linux\"')\nenv = default_environment()\n\nif marker.evaluate(environment=env, context=\"requirement\"):\n    print(\"dependency applies\")\n```\n\nUse the `context` argument intentionally:\n\n- `\"requirement\"` for dependency requirements\n- `\"metadata\"` for core metadata checks\n- `\"lock_file\"` for lock-file evaluation\n\n### Normalize Names And Versions\n\n```python\nfrom packaging.utils import canonicalize_name, canonicalize_version\n\nassert canonicalize_name(\"My_Package\") == \"my-package\"\nassert canonicalize_version(\"1.4.0.0.0\") == \"1.4\"\n```\n\nUse canonicalized names for cache keys, lookups, and deduping. Python package names are case-insensitive and normalize `_`, `.`, and `-`.\n\n### Parse Wheel Filenames And Check Compatibility\n\n```python\nfrom packaging.tags import sys_tags\nfrom packaging.utils import parse_wheel_filename\n\nname, version, build, tags = parse_wheel_filename(\n    \"packaging-26.0-py3-none-any.whl\"\n)\n\nsupported = set(sys_tags())\nif tags & supported:\n    print(f\"{name} {version} is installable on this interpreter\")\n```\n\n`parse_sdist_filename(...)` and `parse_wheel_filename(...)` are useful when tooling needs to inspect artifacts before installation.\n\n### Read Core Metadata\n\n```python\nfrom packaging.metadata import Metadata, parse_email\n\nraw = \"\"\"\\\nMetadata-Version: 2.4\nName: demo-package\nVersion: 1.2.3\nRequires-Python: >=3.10\nRequires-Dist: requests>=2.31\n\"\"\"\n\nparsed, unparsed = parse_email(raw)\nmetadata = Metadata.from_raw(parsed)\n\nprint(metadata.name)\nprint(metadata.version)\nprint(metadata.requires_python)\nprint(metadata.requires_dist)\nprint(unparsed)  # {}\n```\n\nUse metadata parsing when you are validating generated package metadata, building package inspection tooling, or processing `.dist-info/METADATA`.\n\n### Work With Lock Files\n\n`packaging` 26.0 adds the `packaging.pylock` module for the Python lock file specification.\n\n```python\nfrom packaging.pylock import Package, PackageWheel, Pylock\nfrom packaging.utils import NormalizedName\nfrom packaging.version import Version\n\nlock = Pylock(\n    lock_version=\"1.0\",\n    created_by=\"example-tool\",\n    packages=[\n        Package(\n            name=NormalizedName(\"packaging\"),\n            version=Version(\"26.0\"),\n            wheels=[\n                PackageWheel(\n                    url=\"https://files.pythonhosted.org/packages/example/packaging-26.0-py3-none-any.whl\",\n                    hashes={\"sha256\": \"abc123\"},\n                )\n            ],\n        )\n    ],\n)\n\ndata = lock.to_dict()\nround_tripped = Pylock.from_dict(data)\nassert round_tripped.packages[0].name == \"packaging\"\n```\n\nUse this only for lock-file data structures. It is not a resolver.\n\n## Common Patterns\n\n### Validate User-Supplied Version Constraints\n\n```python\nfrom packaging.specifiers import SpecifierSet, InvalidSpecifier\n\ndef validate_constraint(raw: str) -> bool:\n    try:\n        SpecifierSet(raw)\n    except InvalidSpecifier:\n        return False\n    return True\n```\n\n### Parse Requirements Safely From Config\n\n```python\nfrom packaging.requirements import Requirement, InvalidRequirement\n\ndef parse_requirement(raw: str) -> Requirement | None:\n    try:\n        return Requirement(raw)\n    except InvalidRequirement:\n        return None\n```\n\n### Select The Best Matching Version\n\n```python\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.version import Version\n\ndef best_match(available: list[str], constraint: str) -> str | None:\n    spec = SpecifierSet(constraint)\n    matches = sorted((Version(v) for v in available if Version(v) in spec))\n    return str(matches[-1]) if matches else None\n```\n\n## Common Pitfalls\n\n### `packaging` Is Strict\n\nInvalid versions and malformed requirement strings fail fast. That is usually desirable in tooling, but it means copying raw text from user input or old metadata can raise exceptions immediately.\n\n### Pre-Releases Are Easy To Misread\n\nSpecifier behavior around pre-releases is subtle. Be explicit when checking release candidates and beta versions, and test the exact constraints you plan to generate.\n\n### Requirement URLs Are Not General URL Validators\n\nSince `packaging` 23.2, `Requirement` no longer rejects every unusual URL shape during parsing. If you care about network safety or allowed hosts, validate the URL separately after parsing.\n\n### Name Normalization Matters\n\nDo not compare package names with raw strings from filenames or user input. Normalize them first with `canonicalize_name(...)`.\n\n### Marker Evaluation Depends On Context\n\nUse the right marker evaluation context for the data you are checking. `\"requirement\"`, `\"metadata\"`, and `\"lock_file\"` are not interchangeable.\n\n### This Library Does Not Resolve Dependencies\n\n`packaging` helps parse, compare, and validate packaging data. It will not tell you which transitive dependency set to install.\n\n## Version-Sensitive Notes\n\n- `26.0` adds `packaging.pylock` for Python lock files, `Metadata.import_names` and `Metadata.import_namespaces`, metadata writing helpers, and `Version.__replace__`. It also changes some `Specifier` and marker edge-case behavior, including returning `False` instead of raising for `.contains(...)` on an invalid version.\n- `25.0` added support for PEP 751 extras and dependency groups in markers plus new platform tags including Android support.\n- `24.2` changed prerelease handling for `<` and `>` specifiers to align with PEP 440 and added support for PEP 639 license expressions and license files.\n- `23.2` stopped over-validating requirement URLs during requirement parsing.\n- `22.0` removed legacy version and specifier parsing. If old code still imports `LegacyVersion` or `LegacySpecifier`, it needs to be rewritten.\n\n## When To Reach For Other Tools\n\n- Use `pip` or `uv` to install packages.\n- Use `importlib.metadata` when you need metadata for already installed distributions in the current environment.\n- Use `build`, `hatchling`, `setuptools`, or Poetry when you are creating distributions.\n- Use `resolvelib`, Poetry, pip, or uv when you need dependency resolution.\n\n## Official Sources\n\n- Documentation: https://packaging.pypa.io/en/stable/\n- Version handling: https://packaging.pypa.io/en/stable/version.html\n- Specifiers: https://packaging.pypa.io/en/stable/specifiers.html\n- Requirements: https://packaging.pypa.io/en/stable/requirements.html\n- Markers: https://packaging.pypa.io/en/stable/markers.html\n- Utils: https://packaging.pypa.io/en/stable/utils.html\n- Tags: https://packaging.pypa.io/en/stable/tags.html\n- Metadata: https://packaging.pypa.io/en/stable/metadata.html\n- Changelog: https://packaging.pypa.io/en/stable/changelog.html\n- PyPI: https://pypi.org/project/packaging/\n"
  },
  {
    "path": "content/pandas/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pandas package guide for Python 3.0.1: installation, DataFrame workflows, IO, options, and 3.0 migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pandas,dataframe,data-analysis,io,timeseries,pyarrow\"\n---\n\n# pandas Python Package Guide\n\n## Golden Rule\n\nUse `pandas` when you need labeled tabular data in Python: `Series` for 1D data and `DataFrame` for 2D data. Treat the official getting started, user guide, and API reference as the source of truth for method behavior and optional IO dependencies.\n\n## Installation\n\n### pip\n\n```bash\npip install pandas==3.0.1\n```\n\n### conda-forge\n\n```bash\nconda install -c conda-forge pandas\n```\n\n### Common optional extras\n\n```bash\npip install \"pandas[excel]\"\npip install \"pandas[performance]\"\npip install \"pandas[aws]\"\npip install \"pandas[parquet]\"\npip install \"pandas[all]\"\n```\n\nUse extras only when the workflow needs them. pandas raises `ImportError` when you call a method that depends on an optional package you did not install.\n\nExamples from the official docs:\n\n- Excel IO needs engines such as `openpyxl`, `python-calamine`, or `xlsxwriter`\n- SQL workflows commonly use `sqlalchemy`\n- Remote filesystem URLs rely on `fsspec`-style backends\n- Performance-sensitive work can benefit from `numexpr`, `bottleneck`, and `numba`\n\n## Initialize And Inspect Data\n\n```python\nimport pandas as pd\n\ndf = pd.DataFrame(\n    {\n        \"city\": [\"SF\", \"NYC\", \"SEA\"],\n        \"sales\": [10, 15, 7],\n        \"date\": pd.to_datetime([\"2026-01-01\", \"2026-01-02\", \"2026-01-03\"]),\n    }\n)\n\nprint(df.dtypes)\nprint(df.head())\nprint(df.describe(include=\"all\"))\n```\n\nUse `DataFrame` for table-shaped data and `Series` for a single labeled column. The package overview and API reference organize pandas around `Series`, `DataFrame`, `GroupBy`, `Resampling`, `Window`, IO, and options/settings.\n\n## Core Workflows\n\n### Read and write tabular data\n\n```python\nimport pandas as pd\n\ndf = pd.read_csv(\"input.csv\")\ndf.to_parquet(\"output.parquet\", index=False)\n```\n\n`read_*` and `to_*` cover CSV, Excel, JSON, HTML, XML, Parquet, Feather, SQL, and more.\n\nIf you need Excel:\n\n```python\ndf = pd.read_excel(\"input.xlsx\")\ndf.to_excel(\"output.xlsx\", index=False)\n```\n\nMake sure the matching engine is installed first.\n\n### Select, filter, and assign\n\n```python\nactive = df.loc[df[\"sales\"] > 8, [\"city\", \"sales\"]]\nfirst_two_rows = df.iloc[:2, :]\n\ndf.loc[:, \"sales_with_tax\"] = df[\"sales\"] * 1.1\n```\n\nUse:\n\n- `[]` for simple column access\n- `loc` for label-based row/column selection\n- `iloc` for position-based selection\n\n### Aggregate with groupby\n\n```python\nsummary = (\n    df.groupby(\"city\", dropna=False)[\"sales\"]\n    .agg([\"count\", \"sum\", \"mean\"])\n    .sort_values(\"sum\", ascending=False)\n)\n```\n\n`groupby` is the main split-apply-combine tool. Use `value_counts()` for quick category counts.\n\n### Join and reshape\n\n```python\ncustomers = pd.DataFrame({\"customer_id\": [1, 2], \"name\": [\"A\", \"B\"]})\norders = pd.DataFrame({\"customer_id\": [1, 1, 2], \"total\": [25, 30, 20]})\n\njoined = customers.merge(orders, on=\"customer_id\", how=\"left\")\n```\n\nUse `merge`, `join`, `concat`, `pivot`, `pivot_table`, `stack`, and `unstack` for relational and reporting-style transforms.\n\n### Time series\n\n```python\nts = (\n    df.set_index(\"date\")\n    .sort_index()\n    .resample(\"MS\")[\"sales\"]\n    .sum()\n)\n```\n\nUse `to_datetime`, `date_range`, timezone-aware dtypes, rolling windows, and `resample()` for date-based pipelines.\n\n### Expression-based column creation\n\n`pandas 3.0` added `pd.col()` for expression-style column references:\n\n```python\ndf = df.assign(double_sales=pd.col(\"sales\") * 2)\n```\n\nThis is useful in `assign`, `loc`, and similar places that accept callables returning a `Series`.\n\n## Config And Backend Integration\n\n### Display and runtime options\n\nUse the options API for temporary or global formatting changes:\n\n```python\nimport pandas as pd\n\npd.set_option(\"display.max_rows\", 200)\n\nwith pd.option_context(\"display.max_columns\", 20, \"display.width\", 120):\n    print(df)\n```\n\nImportant options APIs:\n\n- `pd.get_option()`\n- `pd.set_option()`\n- `pd.reset_option()`\n- `pd.describe_option()`\n- `pd.option_context()`\n\nUse full option names in code. Short patterns can become ambiguous across releases.\n\n### Remote files and cloud storage\n\npandas itself does not have package-level authentication. Credentials come from the underlying storage or database backend.\n\nFor remote files, use URL-aware readers and pass backend configuration through `storage_options` when needed:\n\n```python\nimport pandas as pd\n\ndf = pd.read_csv(\n    \"s3://my-bucket/path/data.csv\",\n    storage_options={\"anon\": False},\n)\n```\n\nThe IO guide also shows passing backend-specific client settings via `storage_options`, for example `client_kwargs` for S3-compatible endpoints.\n\n### SQL connections\n\n```python\nimport pandas as pd\nfrom sqlalchemy import create_engine\n\nengine = create_engine(\"postgresql+psycopg://user:pass@host/db\")\ndf = pd.read_sql(\"select * from orders\", engine)\n```\n\nPut connection credentials in your database URL, driver config, environment, or secret manager. pandas reads through the DBAPI/SQLAlchemy connection you provide.\n\nIf you care about preserving database types more closely, the IO guide recommends `dtype_backend=\"pyarrow\"` for `read_sql()` round-trips.\n\n## Common Pitfalls\n\n### Missing optional dependencies\n\nMany pandas methods work only when their backend package is installed. Typical failures:\n\n- `read_excel()` without an Excel engine\n- `read_parquet()` without Parquet support\n- `read_csv(\"s3://...\")` without the appropriate filesystem backend\n- `to_markdown()` without `tabulate`\n\nInstall the matching extra or dependency before changing code.\n\n### Chained assignment changed in pandas 3.0\n\nIn pandas 3.0, chained assignment no longer works as a mutation pattern. Old code like this is wrong:\n\n```python\ndf[df[\"sales\"] > 0][\"sales\"] = 0\n```\n\nWrite the mutation in one step instead:\n\n```python\ndf.loc[df[\"sales\"] > 0, \"sales\"] = 0\n```\n\n### String dtype assumptions changed\n\nThe pandas 3.0 release notes call out a new default string dtype. Code that assumes string columns stay `object` dtype, or code that depends on a specific missing-value sentinel, can break after upgrading.\n\n### Be explicit with indexes before joins and resampling\n\n`merge`, `groupby`, and `resample` are easier to reason about when you normalize dtypes first and make the relevant key or timestamp column explicit.\n\n```python\ndf[\"date\"] = pd.to_datetime(df[\"date\"], utc=True)\ndf[\"customer_id\"] = df[\"customer_id\"].astype(\"int64\")\n```\n\n### Large-data performance is opt-in\n\npandas is flexible, not magically distributed. For large datasets:\n\n- install performance extras\n- prefer vectorized operations over Python loops\n- choose columnar formats like Parquet when possible\n- use `dtype_backend=\"pyarrow\"` selectively when it improves downstream interoperability\n\n## Version-Sensitive Notes For 3.0.1\n\n- `pandas 3.0.0` was released on January 21, 2026 and introduced breaking behavior around Copy-on-Write semantics and chained assignment.\n- `pandas 3.0.0` also introduced `pd.col()` expression support.\n- `pandas 3.0.1` was released on February 17, 2026 and fixes early 3.0 regressions, including:\n  - unary operators on `pd.col()`\n  - some pyarrow-backed string operations\n  - a `merge()` bug involving `NaN` values in pyarrow-backed string join keys on Windows with pyarrow 21\n  - Copy-on-Write handling in some constructor paths\n\nIf you are on `3.0.0` and using `pd.col()`, pyarrow-backed strings, or Windows joins, prefer `3.0.1`.\n\n## Official Sources\n\n- Docs root: https://pandas.pydata.org/docs/\n- API reference: https://pandas.pydata.org/docs/reference/index.html\n- Installation: https://pandas.pydata.org/docs/getting_started/install.html\n- Package overview: https://pandas.pydata.org/docs/getting_started/overview.html\n- Tutorials index: https://pandas.pydata.org/docs/getting_started/intro_tutorials/index.html\n- IO guide: https://pandas.pydata.org/docs/user_guide/io.html\n- Options guide: https://pandas.pydata.org/docs/user_guide/options.html\n- Release notes 3.0.0: https://pandas.pydata.org/docs/whatsnew/v3.0.0.html\n- Release notes 3.0.1: https://pandas.pydata.org/docs/whatsnew/v3.0.1.html\n- PyPI package: https://pypi.org/project/pandas/3.0.1/\n"
  },
  {
    "path": "content/pandera/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pandera dataframe validation library for pandas-first Python workflows, with backend support for Polars, Ibis, and PySpark\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pandera,python,data-validation,pandas,polars,pyspark,ibis,dataframe\"\n---\n\n# Pandera Python Package Guide\n\n## Golden Rule\n\nUse backend-specific Pandera imports and validate data at dataframe boundaries instead of sprinkling ad hoc assertions through the pipeline. For pandas workflows, follow the current docs and import `pandera.pandas as pa`, not the legacy top-level `import pandera as pa`.\n\n## Install\n\nFor pandas projects, install the package with the pandas extra and pin the version your project expects:\n\n```bash\npython -m pip install \"pandera[pandas]==0.29.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv pip install \"pandera[pandas]==0.29.0\"\npoetry add \"pandera[pandas]==0.29.0\"\n```\n\nNotes:\n\n- The upstream install examples are pandas-first. If you are using a different dataframe engine, use the backend-specific docs and import path for that engine.\n- The docs and PyPI README explicitly show backend-specific modules such as `pandera.pandas` and `pandera.polars`.\n- If you only install `pandera` without the matching backend dependencies, validation code may import cleanly but fail later when a backend-specific dependency is missing.\n\n## Initialize And Choose A Backend\n\n### Pandas setup\n\n```python\nimport pandas as pd\nimport pandera.pandas as pa\nfrom pandera.typing import DataFrame, Series\n```\n\n### Other documented backends\n\nUse the backend module that matches the dataframe library you are validating:\n\n```python\nimport pandera.polars as pa\n# or\nimport pandera.ibis as pa\n# or\nimport pandera.pyspark as pa\n```\n\nDo not assume all backends expose identical behavior. Pandera’s pandas API is the most common path, but backend support is documented separately and can differ in available checks and typing behavior.\n\n## Core Usage\n\n### Object-based schema with `DataFrameSchema`\n\nUse `DataFrameSchema` when you want an explicit schema object that you can reuse across validation calls.\n\n```python\nimport pandas as pd\nimport pandera.pandas as pa\n\ntransactions_schema = pa.DataFrameSchema(\n    {\n        \"user_id\": pa.Column(int, pa.Check.ge(1)),\n        \"amount\": pa.Column(float, pa.Check.gt(0)),\n        \"country\": pa.Column(str),\n    },\n    strict=True,\n    coerce=True,\n)\n\ndf = pd.DataFrame(\n    {\n        \"user_id\": [\"1\", \"2\"],\n        \"amount\": [10.5, 42.0],\n        \"country\": [\"us\", \"ca\"],\n    }\n)\n\nvalidated = transactions_schema.validate(df)\nprint(validated.dtypes)\n```\n\nUse `strict=True` when extra columns should fail validation. Use `coerce=True` when upstream data often arrives as strings or mixed types and you want Pandera to cast before checking constraints.\n\n### Class-based schema with `DataFrameModel`\n\nUse `DataFrameModel` when you want reusable schema definitions that also work well with function annotations.\n\n```python\nimport pandera.pandas as pa\nfrom pandera.typing import DataFrame, Series\n\nclass Transactions(pa.DataFrameModel):\n    user_id: Series[int] = pa.Field(ge=1)\n    amount: Series[float] = pa.Field(gt=0)\n    country: Series[str]\n\n    class Config:\n        strict = True\n        coerce = True\n\n@pa.check_types\ndef normalize_country(df: DataFrame[Transactions]) -> DataFrame[Transactions]:\n    return df.assign(country=df[\"country\"].str.upper())\n```\n\nThis is usually the cleanest pattern for ETL helpers and pipeline stages: annotate the input and output once, then let `@pa.check_types` enforce the schema at the boundary.\n\n### Decorate untyped functions\n\nIf a function cannot use dataframe type annotations cleanly, validate with explicit decorators:\n\n```python\nimport pandas as pd\nimport pandera.pandas as pa\n\ninput_schema = pa.DataFrameSchema(\n    {\"amount\": pa.Column(float, pa.Check.gt(0))},\n    coerce=True,\n)\n\n@pa.check_input(input_schema)\n@pa.check_output(input_schema)\ndef keep_positive_amounts(df: pd.DataFrame) -> pd.DataFrame:\n    return df.loc[df[\"amount\"] > 0].copy()\n```\n\nUse `@pa.check_input`, `@pa.check_output`, and `@pa.check_io` when runtime validation matters more than static typing clarity.\n\n## Error Handling And Debugging\n\nBy default, Pandera raises on the first failure. For debugging or batch diagnostics, use lazy validation so you can inspect all failures at once:\n\n```python\nimport pandera.pandas as pa\n\ntry:\n    transactions_schema.validate(df, lazy=True)\nexcept pa.errors.SchemaErrors as exc:\n    print(exc.failure_cases)\n```\n\nThis is the right default for agent-written data cleanup code because it gives you a structured failure table instead of a single first error.\n\n## Configuration And Runtime Controls\n\nPandera has no credentials or API keys. Configuration is about validation scope and runtime behavior.\n\nTemporarily adjust validation behavior in code with `config_context`:\n\n```python\nfrom pandera.config import ValidationDepth, config_context\n\nwith config_context(validation_depth=ValidationDepth.SCHEMA_ONLY):\n    transactions_schema.validate(df)\n```\n\nUseful controls from the official configuration docs:\n\n- `validation_enabled`: disable validation in a controlled scope when benchmarking or bypassing checks intentionally\n- `validation_depth`: reduce how much validation runs, for example schema-only checks\n- `cache_dataframe`: cache dataframe state during validation when supported by the backend\n\nEnvironment variables also exist for these runtime controls, including `PANDERA_VALIDATION_ENABLED` and `PANDERA_VALIDATION_DEPTH`.\n\n## Common Pitfalls\n\n- Do not keep using `import pandera as pa` for pandas schemas. The upstream docs treat `pandera.pandas` as the recommended import path, and the top-level path is documented as deprecated for these classes.\n- Install the backend you actually use. Pandera covers more than pandas, but the backend import and dependencies must match the dataframe engine.\n- `coerce=True` changes data before checks run. That is often useful, but it can hide upstream type issues if you expected a pure validation pass.\n- `strict=True` rejects unexpected columns. Use it when the schema is an API contract; avoid it when your upstream source adds benign extra columns that you plan to ignore.\n- `@pa.check_types` only helps if the function is annotated with Pandera dataframe types. If a function accepts plain `pd.DataFrame`, use explicit decorators or a direct `.validate(...)` call.\n- Backend docs are not interchangeable. A pandas example copied into a Polars or PySpark project may fail because the import path and supported checks differ.\n- For bulk debugging, prefer `lazy=True`; otherwise Pandera stops on the first failure and you lose the full error picture.\n\n## Version-Sensitive Notes For `0.29.0`\n\n- The version used here `0.29.0` matched live PyPI on March 12, 2026.\n- The current stable docs still carry the import-path warning introduced in `0.24.0`: for pandas workflows, move code to `import pandera.pandas as pa` instead of relying on the top-level `pandera` namespace for `DataFrameSchema` and `DataFrameModel`.\n- The `0.29.0` docs document `@pa.check_types` support for collection return and parameter types such as `list[...]`, `tuple[...]`, and `dict[..., ...]` containing dataframe-typed objects. This matters if your helpers split data into multiple validated frames.\n- Use backend-specific docs when upgrading old examples. Much older blog posts often assume pandas-only imports from the top-level package and miss the current backend module split.\n"
  },
  {
    "path": "content/panel/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"panel package guide for Python dashboards and apps with widgets, templates, notebooks, and server deployment\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"panel,holoviz,bokeh,dashboard,widgets,jupyter,python\"\n---\n\n# panel Python Package Guide\n\n## Golden Rule\n\nUse `panel` as `import panel as pn`, call `pn.extension()` before rendering widgets or templates, and choose one execution model deliberately: notebook output, `panel serve`, or `pn.serve(...)`. For most app logic, prefer Panel's reactive APIs such as `pn.bind`, `pn.rx`, and `@pn.depends` instead of hand-wiring lower-level callbacks.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, the official Panel release docs and PyPI package page point to `1.8.7`, not the older version reference `1.8.9`.\n- The docs site currently mixes version labels across pages. Some pages or assets show `v1.8.9`, while the release page still advertises `1.8.7`. Use PyPI and the release notes as the source of truth for exact package pinning.\n- The installation docs say Panel supports Python `3.9+`. Confirm the exact interpreter support from the version you pin in your environment and lockfile before changing CI or deployment images.\n- The docs URL points at the API reference. For package-level work, the installation, app-building, reactive API, serving, and authentication guides are more useful than starting from `/api/`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"panel==1.8.7\"\n```\n\nConda-based installs are also first-class in the official docs:\n\n```bash\nconda install -c conda-forge panel\nmamba install -c conda-forge panel\n```\n\nBasic verification:\n\n```bash\npython - <<'PY'\nimport panel as pn\nprint(pn.__version__)\nPY\n```\n\n## Initialization And Setup\n\nPanel can run inside notebooks or as a served app. In both cases, initialize the frontend first:\n\n```python\nimport panel as pn\n\npn.extension(sizing_mode=\"stretch_width\")\n```\n\nNotes:\n\n- Call `pn.extension()` once near process startup or near the top of a notebook.\n- Pass optional frontend extensions such as `\"tabulator\"` or `\"plotly\"` if you use components that need extra JavaScript resources.\n- Keep Panel installed in the same environment as your Jupyter kernel and JupyterLab server to avoid frontend-extension confusion.\n\n## Core Usage\n\n### Minimal served app\n\nUse `.servable()` in files that will be launched with `panel serve`:\n\n```python\nimport panel as pn\n\npn.extension(sizing_mode=\"stretch_width\")\n\nname = pn.widgets.TextInput(name=\"Name\", value=\"Panel\")\ngreeting = pn.bind(lambda value: f\"Hello {value}\", name)\n\napp = pn.Column(name, greeting)\napp.servable()\n```\n\nRun it locally:\n\n```bash\npanel serve app.py --show --dev\n```\n\nUse `--dev` during local development for autoreload-style iteration. For production, serve the app without dev flags and put it behind your normal process manager or reverse proxy.\n\n### Notebook usage\n\nIn notebooks, you usually display Panel objects directly after calling `pn.extension()`:\n\n```python\nimport panel as pn\n\npn.extension()\n\nslider = pn.widgets.IntSlider(name=\"Value\", start=0, end=10, value=3)\nview = pn.bind(lambda n: f\"Current value: {n}\", slider)\n\npn.Column(slider, view)\n```\n\n### Use `pn.bind` for simple reactive flows\n\n`pn.bind` is usually the fastest path from widgets to working app logic:\n\n```python\nimport panel as pn\n\npn.extension()\n\nspecies = pn.widgets.Select(name=\"Species\", options=[\"cat\", \"dog\", \"otter\"])\n\ndef describe(choice: str) -> str:\n    return f\"You selected {choice}\"\n\npn.Row(species, pn.bind(describe, species))\n```\n\nUse this when you want a plain Python function to react to widget or parameter values.\n\n### Use `@pn.depends` when composing with Param or reusable functions\n\n```python\nimport panel as pn\n\npn.extension()\n\nslider = pn.widgets.FloatSlider(name=\"Scale\", start=0, end=2, step=0.1, value=1.0)\n\n@pn.depends(slider)\ndef scaled_message(scale):\n    return f\"Scale is {scale:.1f}\"\n\npn.Column(slider, scaled_message)\n```\n\nThis pattern stays useful when you are working with Param-based classes or methods.\n\n### Use templates for full-page apps\n\nFor multi-section apps, start with a template instead of hand-building a page shell:\n\n```python\nimport panel as pn\n\npn.extension(sizing_mode=\"stretch_width\")\n\ntemplate = pn.template.FastListTemplate(title=\"Panel Demo\")\ntemplate.main.append(pn.pane.Markdown(\"## Hello from Panel\"))\ntemplate.main.append(pn.widgets.IntSlider(name=\"Rows\", start=10, end=100, value=25))\ntemplate.servable()\n```\n\n### Use `pn.serve(...)` when embedding Panel in a Python process\n\nIf you need to launch apps programmatically:\n\n```python\nimport panel as pn\n\npn.extension()\n\ndef make_app():\n    slider = pn.widgets.IntSlider(name=\"Value\", start=0, end=10, value=5)\n    return pn.Column(slider, pn.bind(lambda v: v * 2, slider))\n\npn.serve({\"app\": make_app}, show=False, port=5006)\n```\n\nThis is useful when integrating Panel with a larger Python application or a custom launch script.\n\n## Configuration And Authentication\n\nThere is no package-level API key or service auth requirement for local Panel use. Configuration is mostly about frontend initialization, server options, and optional app protection for deployed dashboards.\n\nPractical defaults:\n\n- Use `pn.extension(...)` for frontend setup and optional component extensions.\n- Use `pn.config` and server flags when you need global behavior changes instead of scattering per-widget overrides.\n- Treat public serving as a deployment concern, not just a Python import concern.\n\nFor protected apps, the official auth docs cover:\n\n- basic auth via `panel serve` for simple internal deployments\n- OAuth providers configured with command-line flags or `PANEL_...` environment variables\n- cookie-secret and encryption-key settings for secure session handling\n\nCommon OAuth-related environment variables from the auth docs include:\n\n- `PANEL_OAUTH_KEY`\n- `PANEL_OAUTH_SECRET`\n- `PANEL_COOKIE_SECRET`\n\nIf you expose a Panel app publicly, configure auth explicitly instead of assuming the default dev server setup is safe enough.\n\n## Common Pitfalls\n\n- Forgetting `pn.extension()` before rendering widgets, templates, or panes.\n- Using `.show()` in code that should be served with `panel serve`; prefer `.servable()` for served apps.\n- Installing Panel in one environment while Jupyter runs from another.\n- Forgetting to load required frontend extensions for components such as Tabulator or Plotly-backed panes.\n- Reaching for low-level callback wiring when `pn.bind` or `@pn.depends` is enough.\n- Treating `--dev` as a production flag; it is for local iteration.\n- Publishing a dashboard without auth, cookie-secret, or reverse-proxy planning.\n- Trusting page-level version banners over PyPI when the docs site shows mixed version labels.\n\n## Official Source URLs\n\n- `https://panel.holoviz.org/`\n- `https://panel.holoviz.org/getting_started/installation.html`\n- `https://panel.holoviz.org/getting_started/build_app.html`\n- `https://panel.holoviz.org/explanation/api/reactive.html`\n- `https://panel.holoviz.org/tutorials/basic/serve.html`\n- `https://panel.holoviz.org/how_to/server/commandline.html`\n- `https://panel.holoviz.org/how_to/authentication/configuration.html`\n- `https://panel.holoviz.org/about/releases.html`\n- `https://pypi.org/project/panel/`\n- `https://github.com/holoviz/panel`\n"
  },
  {
    "path": "content/papermill/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"papermill for parameterizing, executing, and saving Jupyter notebooks in Python pipelines\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"papermill,jupyter,notebooks,pipeline,parameters,automation\"\n---\n\n# papermill Python Package Guide\n\n## What It Is\n\n`papermill` is a notebook runner for parameterized Jupyter workflows. Use it when a `.ipynb` file is part of a repeatable job and you need to inject inputs, execute the notebook, and keep the executed output notebook as an artifact.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"papermill==2.7.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"papermill==2.7.0\"\npoetry add \"papermill==2.7.0\"\n```\n\nOptional extras are important when your notebooks live outside the local filesystem or you want optional helpers:\n\n```bash\npython -m pip install \"papermill[s3]==2.7.0\"\npython -m pip install \"papermill[azure]==2.7.0\"\npython -m pip install \"papermill[gcs]==2.7.0\"\npython -m pip install \"papermill[github]==2.7.0\"\npython -m pip install \"papermill[hdfs]==2.7.0\"\npython -m pip install \"papermill[black]==2.7.0\"\npython -m pip install \"papermill[all]==2.7.0\"\n```\n\nExecution prerequisites agents often miss:\n\n- The notebook's kernel must exist on the machine where `papermill` runs.\n- The kernel environment must also contain the notebook's runtime dependencies.\n- `papermill` itself runs in one environment, but the executed notebook runs through the selected Jupyter kernel.\n\n## Prepare A Notebook For Parameters\n\nPapermill expects a cell tagged `parameters`. Treat that cell as defaults only.\n\nExample notebook cell:\n\n```python\n# tag this cell as: parameters\nrun_date = \"2026-03-12\"\nlimit = 100\ninclude_archived = False\n```\n\nWhen executed, papermill inserts an `injected-parameters` cell immediately after the tagged cell and writes only the overridden values there.\n\nIf no cell is tagged `parameters`, papermill inserts the `injected-parameters` cell at the top of the notebook instead.\n\n## Core Usage\n\n### Execute A Notebook From Python\n\n`execute_notebook(...)` is the main API. It returns the executed `NotebookNode` and, unless `output_path=None`, writes the executed notebook to disk or another supported backend.\n\n```python\nimport papermill as pm\n\nnb = pm.execute_notebook(\n    \"notebooks/daily_report.ipynb\",\n    \"artifacts/daily_report-2026-03-12.ipynb\",\n    parameters={\n        \"run_date\": \"2026-03-12\",\n        \"limit\": 100,\n        \"include_archived\": False,\n    },\n    kernel_name=\"python3\",\n    cwd=\"notebooks\",\n    log_output=True,\n    progress_bar=False,\n    autosave_cell_every=60,\n)\n\nprint(nb.metadata.papermill[\"status\"])\n```\n\nUseful execution arguments for coding agents:\n\n- `kernel_name`: set explicitly when notebook metadata is missing or unreliable.\n- `cwd`: run the notebook relative to the repo or notebook directory instead of the process cwd.\n- `prepare_only=True`: inject parameters and metadata without executing cells.\n- `start_timeout`: increase this when kernels are slow to start.\n- `execution_timeout`: fail long-running cells instead of waiting forever.\n- `report_mode=True`: hide input cells for report-style outputs.\n- `output_path=None`: execute and return the notebook object without saving a file.\n\n### Execute From The CLI\n\nBasic execution:\n\n```bash\npapermill notebooks/daily_report.ipynb artifacts/daily_report.ipynb \\\n  -p run_date 2026-03-12 \\\n  -p limit 100 \\\n  -p include_archived false\n```\n\nParameter input modes:\n\n```bash\npapermill in.ipynb out.ipynb -p limit 100\npapermill in.ipynb out.ipynb -r version 1.0\npapermill in.ipynb out.ipynb -f parameters.yaml\npapermill in.ipynb out.ipynb -y $'items:\\n  - a\\n  - b'\npapermill in.ipynb out.ipynb -b YWxwaGE6IDAuNgpsaW1pdDogMTAwCg==\n```\n\nUse `-p` when you want scalar values to be parsed as numbers or booleans. Use `-r` when the value must remain a string.\n\n### Inspect Notebook Parameters Before Running\n\nFor a notebook you did not author, inspect first:\n\n```python\nimport papermill as pm\n\nparams = pm.inspect_notebook(\"notebooks/daily_report.ipynb\")\nprint(params)\n```\n\nCLI equivalent:\n\n```bash\npapermill --help-notebook notebooks/daily_report.ipynb\n```\n\nThis is the fastest way to confirm parameter names, inferred types, and default values before generating automation code.\n\n### Prepare Without Execution\n\nUse this when you want a parameterized notebook artifact for review or a later execution stage:\n\n```python\nimport papermill as pm\n\npm.execute_notebook(\n    \"notebooks/template.ipynb\",\n    \"artifacts/prepared.ipynb\",\n    parameters={\"run_date\": \"2026-03-12\"},\n    prepare_only=True,\n)\n```\n\nCLI equivalent:\n\n```bash\npapermill notebooks/template.ipynb artifacts/prepared.ipynb \\\n  -p run_date 2026-03-12 \\\n  --prepare-only\n```\n\n### Use Remote Storage Paths\n\nPapermill supports local files plus named handlers for remote paths. The upstream docs explicitly call out:\n\n- local filesystem\n- `http://` and `https://`\n- `s3://`\n- `adl://`\n- `abs://`\n- `gs://`\n\nExample with S3 output:\n\n```bash\nAWS_PROFILE=dev papermill local/input.ipynb s3://my-bucket/output.ipynb \\\n  -p run_date 2026-03-12\n```\n\nThe handler must be installed through extras and its underlying SDK credentials must already work in the environment.\n\n## Configuration And Auth\n\nPapermill itself has no service-specific auth config. Authentication is delegated to the storage backend libraries used by each handler.\n\n### Local notebooks\n\nNo extra auth is required. The two settings that matter most are:\n\n- `cwd` for relative file access\n- `kernel_name` for consistent execution in automated jobs\n\n### S3\n\nInstall:\n\n```bash\npython -m pip install \"papermill[s3]==2.7.0\"\n```\n\nAuth uses the normal boto3 credential chain. In CLI workflows, `AWS_PROFILE` is the most useful knob when multiple accounts are configured.\n\n### Google Cloud Storage\n\nInstall:\n\n```bash\npython -m pip install \"papermill[gcs]==2.7.0\"\n```\n\nAuth is handled by `gcsfs`. In practice, use the credential flow you already use for Google Cloud tooling, typically Application Default Credentials in local or CI environments.\n\n### Azure Blob Storage / Data Lake\n\nInstall:\n\n```bash\npython -m pip install \"papermill[azure]==2.7.0\"\n```\n\nAuth is handled by the Azure storage and identity libraries. Keep credential setup outside notebook code and validate it independently before assuming papermill path access works.\n\n## Common Pitfalls\n\n- Missing `parameters` tag: papermill will still inject parameters, but it inserts the cell at the top of the notebook, which is easy to misread during debugging.\n- Inter-dependent defaults in the `parameters` cell do not re-evaluate. If the defaults are `a = 1` and `twice = a * 2`, then running with `-p a 9` still leaves `twice = 2`. Put derived values in a later cell.\n- Wrong parameter type from the CLI: `-p` parses scalars, while `-r` keeps values as strings. Use YAML-based inputs for lists and nested objects.\n- `NoSuchKernel` errors with conda-managed notebooks: install `jupyter` or at least `ipykernel` in the target environment, expose that environment as a Jupyter kernel, or pass `-k <kernel-name>` explicitly.\n- Output notebook not written: `execute_notebook(..., output_path=None)` is valid and returns a notebook object, but no artifact is saved anywhere.\n- Long-running cells on ephemeral infrastructure: tune `request_save_on_cell_execute`, `autosave_cell_every`, `stdout_file`, `stderr_file`, and `log_output` so partial progress is preserved outside the notebook UI.\n- Remote paths without extras: `s3://`, `gs://`, `adl://`, and `abs://` handlers do not work from a bare `pip install papermill`.\n\n## Version-Sensitive Notes For 2.7.0\n\n- `2.7.0` was released on February 27, 2026.\n- `2.7.0` supports Python `3.10+` only. The release dropped Python 3.8 and 3.9 support and added Python 3.13 support.\n- The 2.7.0 release removed the `ansicolors` dependency and migrated packaging to `pyproject.toml`.\n- The changelog also notes that parameter inspection now raises the same missing-kernel and missing-language errors as the other execution pathways.\n- The previous release on PyPI was `2.6.0` on April 26, 2024, so older blog posts may assume pre-2.7.0 Python support or dependency behavior.\n\n## Official Sources\n\n- Docs root: `https://papermill.readthedocs.io/en/latest/`\n- Installation: `https://papermill.readthedocs.io/en/latest/installation.html`\n- Parameterization: `https://papermill.readthedocs.io/en/latest/usage-parameterize.html`\n- Inspect: `https://papermill.readthedocs.io/en/latest/usage-inspect.html`\n- Execute: `https://papermill.readthedocs.io/en/latest/usage-execute.html`\n- CLI: `https://papermill.readthedocs.io/en/latest/usage-cli.html`\n- Troubleshooting: `https://papermill.readthedocs.io/en/latest/troubleshooting.html`\n- Workflow reference: `https://papermill.readthedocs.io/en/latest/reference/papermill-workflow.html`\n- Input/output reference: `https://papermill.readthedocs.io/en/latest/reference/papermill-io.html`\n- Package registry: `https://pypi.org/project/papermill/`\n"
  },
  {
    "path": "content/paramiko/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Paramiko SSHv2 library for Python clients, SFTP transfers, host-key verification, and low-level SSH automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"paramiko,ssh,sftp,python,security,automation\"\n---\n\n# Paramiko Python Package Guide\n\n## Golden Rule\n\nUse `paramiko` for low-level SSHv2 and SFTP automation in Python, verify host keys instead of blindly trusting them, and prefer key-based authentication over embedded passwords. If you just need high-level remote task execution, upstream points most users toward Fabric, which is built on Paramiko.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"paramiko==4.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"paramiko==4.0.0\"\npoetry add \"paramiko==4.0.0\"\n```\n\nOptional Kerberos / GSS-API support:\n\n```bash\npython -m pip install \"paramiko[gssapi]==4.0.0\"\n```\n\nVersion-specific install notes for `4.0.0`:\n\n- `paramiko[invoke]`, `paramiko[all]`, and `paramiko[ed25519]` were removed in `4.0.0`.\n- Old guides that tell you to install those extras are stale.\n- `cryptography` remains a normal dependency, so key algorithms such as Ed25519 do not need a special extra.\n\n## Core Client Setup\n\n`SSHClient` is the usual entry point for application code:\n\n```python\nfrom pathlib import Path\n\nimport paramiko\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(\n        hostname=\"server.example.com\",\n        username=\"deploy\",\n        key_filename=str(Path.home() / \".ssh\" / \"id_ed25519\"),\n        look_for_keys=True,\n        allow_agent=True,\n        timeout=10,\n        banner_timeout=10,\n        auth_timeout=10,\n    )\n\n    stdin, stdout, stderr = client.exec_command(\"uname -a\")\n    print(stdout.read().decode(\"utf-8\"))\n```\n\nPractical defaults:\n\n- Call `load_system_host_keys()` so Paramiko can verify hosts against the user's `known_hosts`.\n- Keep the default reject behavior for unknown host keys in production.\n- Set `timeout`, `banner_timeout`, and `auth_timeout` explicitly when connecting over unreliable networks.\n\n## Host Keys And Trust Policy\n\nHost-key verification is the security boundary most agents get wrong.\n\nSafe pattern:\n\n```python\nimport paramiko\n\nclient = paramiko.SSHClient()\nclient.load_system_host_keys()\nclient.load_host_keys(\"/path/to/team-known_hosts\")\nclient.connect(hostname=\"server.example.com\", username=\"deploy\")\n```\n\nUnsafe pattern except in disposable test environments:\n\n```python\nimport paramiko\n\nclient = paramiko.SSHClient()\nclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())\n```\n\nUse `AutoAddPolicy` only when the environment is controlled and host identities are managed out of band. Otherwise you are silently trusting the first key a server presents.\n\n## Authentication\n\n`SSHClient.connect()` tries authentication in a defined order. The important inputs are:\n\n1. `pkey` or `key_filename`\n2. Keys available from an SSH agent\n3. Discoverable default private keys under `~/.ssh/`\n4. Plain password authentication, if you pass `password=...`\n\n### Load a private key explicitly\n\n`PKey.from_path()` is convenient when you want Paramiko to infer the key type from a path:\n\n```python\nfrom pathlib import Path\n\nimport paramiko\n\nkey = paramiko.PKey.from_path(Path.home() / \".ssh\" / \"id_ed25519\")\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(\n        hostname=\"server.example.com\",\n        username=\"deploy\",\n        pkey=key,\n        passphrase=\"key-passphrase-if-needed\",\n    )\n```\n\nNotes:\n\n- Prefer `pkey=` when your code already knows exactly which key object to use.\n- Use `passphrase=` for encrypted private keys.\n- `key_filename=` can also point at OpenSSH public certificates ending in `-cert.pub`; Paramiko will look for the matching private key automatically.\n\n### Password authentication\n\n```python\nimport os\n\nimport paramiko\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(\n        hostname=\"server.example.com\",\n        username=\"deploy\",\n        password=os.environ[\"SSH_PASSWORD\"],\n    )\n```\n\nUse passwords only when key-based auth is not available. Keep secrets in environment variables or a secret manager, not in source code.\n\n## Run Commands\n\n`exec_command()` returns file-like objects for stdin, stdout, and stderr:\n\n```python\nimport paramiko\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(hostname=\"server.example.com\", username=\"deploy\")\n\n    stdin, stdout, stderr = client.exec_command(\"python3 --version\")\n    exit_code = stdout.channel.recv_exit_status()\n\n    print(\"exit:\", exit_code)\n    print(\"stdout:\", stdout.read().decode(\"utf-8\"))\n    print(\"stderr:\", stderr.read().decode(\"utf-8\"))\n```\n\nIf you need an interactive shell, use `invoke_shell()` instead of trying to force shell semantics through `exec_command()`.\n\n## SFTP\n\nOpen SFTP from an authenticated `SSHClient`:\n\n```python\nimport paramiko\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(hostname=\"server.example.com\", username=\"deploy\")\n\n    with client.open_sftp() as sftp:\n        sftp.put(\"build/output.txt\", \"/tmp/output.txt\")\n        sftp.get(\"/var/log/app.log\", \"app.log\")\n        print(sftp.listdir(\"/tmp\"))\n```\n\nUseful SFTP operations:\n\n- `put()` and `get()` for whole-file transfers\n- `file()` for remote file-like access\n- `listdir()` / `listdir_attr()` for directory reads\n- `mkdir()`, `remove()`, `rename()`, and `posix_rename()` for remote filesystem changes\n- `stat()` and `lstat()` for metadata checks before overwriting files\n\n## SSH Config Integration\n\nParamiko can parse OpenSSH-style config files:\n\n```python\nfrom pathlib import Path\n\nimport paramiko\n\nconfig = paramiko.SSHConfig.from_path(Path.home() / \".ssh\" / \"config\")\nhost = config.lookup(\"prod-box\")\nidentity_files = host.get(\"identityfile\", [])\n\nwith paramiko.SSHClient() as client:\n    client.load_system_host_keys()\n    client.connect(\n        hostname=host.get(\"hostname\", \"prod-box\"),\n        username=host.get(\"user\"),\n        port=int(host.get(\"port\", 22)),\n        key_filename=identity_files[0] if identity_files else None,\n    )\n```\n\nThis is useful when your deployment already centralizes `Host`, `User`, `Port`, and `IdentityFile` in `~/.ssh/config`.\n\n## Configuration And Compatibility Notes\n\n- Use `disabled_algorithms` only for deliberate compatibility workarounds with old servers, not as a blanket default.\n- `sock=` on `connect()` lets you supply an existing socket or proxy-wrapped connection when a direct TCP connection is not appropriate.\n- Paramiko is a low-level SSH library. It does not read shell startup files or emulate every OpenSSH CLI behavior for you.\n- Close `SSHClient`, `Transport`, and `SFTPClient` objects promptly. Context managers are the safest pattern.\n\n## Common Pitfalls\n\n- Unknown host keys are rejected by default. Do not \"fix\" this with `AutoAddPolicy` unless you accept the security tradeoff.\n- `exec_command()` is not interactive. Commands that require a TTY, prompt for input, or expect shell state often need `invoke_shell()` or explicit command wrapping.\n- Remote paths in SFTP are server paths, not local paths. Validate them with `stat()` or `listdir()` when debugging transfer failures.\n- Authentication failures are often key-selection failures. When debugging, pass `pkey=` or a single `key_filename=` instead of relying on agent discovery.\n- Some timeout failures happen after the TCP connection succeeds. Set `banner_timeout` and `auth_timeout`, not just `timeout`.\n\n## Version-Sensitive Notes For 4.0.0\n\n- Paramiko `4.0.0` requires Python `>=3.9`.\n- `4.0.0` removes DSA / DSS key support entirely. Old code using `DSSKey` or DSA host keys will break and should be migrated to Ed25519, ECDSA, or RSA.\n- Old installation advice for `paramiko[invoke]`, `paramiko[all]`, or `paramiko[ed25519]` is obsolete in `4.0.0`.\n- The versioned docs under `/en/4.0/` are a better reference for this package entry than the floating `/en/stable/` URL when you need version-accurate behavior.\n"
  },
  {
    "path": "content/passlib/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Passlib password hashing framework for Python applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.7.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"passlib,passwords,hashing,security,python\"\n---\n\n# Passlib Python Package Guide\n\nPasslib is a local password-hashing library for Python. It does not talk to a remote service, so there are no API keys or required environment variables. The main API for application code is `passlib.context.CryptContext`, which lets you hash new passwords, verify existing hashes, and migrate old hashes to a new policy during login.\n\n## Install\n\nInstall the base package if you only need schemes implemented by Passlib itself:\n\n```bash\npip install passlib==1.7.4\n```\n\nInstall an extra when you want a backend-dependent scheme:\n\n```bash\npip install \"passlib[bcrypt]==1.7.4\"\npip install \"passlib[argon2]==1.7.4\"\n```\n\nPasslib 1.7.4 declares these extras upstream:\n\n- `passlib[bcrypt]` installs `bcrypt>=3.1.0`\n- `passlib[argon2]` installs `argon2-cffi>=18.2.0`\n\n## Recommended App Pattern\n\nCreate one `CryptContext` during app startup and reuse it everywhere you hash or verify passwords.\n\n```python\n# security.py\nfrom passlib.context import CryptContext\n\npassword_context = CryptContext(\n    schemes=[\"pbkdf2_sha256\"],\n    deprecated=\"auto\",\n    pbkdf2_sha256__default_rounds=200000,\n    pbkdf2_sha256__min_rounds=200000,\n)\n\n\ndef hash_password(password):\n    return password_context.hash(password)\n\n\ndef verify_password(password, password_hash):\n    return password_context.verify(password, password_hash)\n```\n\nUse it when creating or updating a user record:\n\n```python\nfrom security import hash_password\n\nuser.password_hash = hash_password(plain_password)\n```\n\nStore the returned hash string exactly as Passlib returns it. Passlib identifies the algorithm from the stored hash content, so you do not need a separate \"algorithm\" column for normal application code.\n\n## Rehash On Login\n\nUse `verify_and_update()` when you want old hashes to be upgraded automatically after a successful login.\n\n```python\nfrom security import password_context\n\n\ndef authenticate_user(user, password):\n    verified, replacement_hash = password_context.verify_and_update(\n        password,\n        user.password_hash,\n    )\n\n    if not verified:\n        return False\n\n    if replacement_hash is not None:\n        user.password_hash = replacement_hash\n        user.save(update_fields=[\"password_hash\"])\n\n    return True\n```\n\n`verify_and_update()` always returns one of these shapes:\n\n- `(False, None)` when verification fails\n- `(True, None)` when the password matches and the stored hash is still acceptable\n- `(True, \"<new hash>\")` when the password matches but the stored hash should be replaced\n\nThis is the easiest way to move users off deprecated schemes or too-low work factors without forcing password resets.\n\n## Direct Handler API\n\nIf you are writing a one-off script, migration, or CLI tool, you can use a specific handler directly instead of building a full `CryptContext`.\n\n```python\nfrom passlib.hash import pbkdf2_sha256\n\npassword_hash = pbkdf2_sha256.hash(\"correct horse battery staple\")\n\nif pbkdf2_sha256.verify(\"correct horse battery staple\", password_hash):\n    print(\"password matches\")\n\nstronger_hash = pbkdf2_sha256.using(rounds=300000).hash(\n    \"correct horse battery staple\"\n)\n```\n\nUse direct handlers for narrow tasks. For application code that must accept old hashes and issue new ones consistently, prefer `CryptContext`.\n\n## Load Policy From Config\n\nPasslib can build a `CryptContext` from an INI-style config string or file. This is useful when you want password policy outside application code.\n\n```ini\n; passlib.ini\n[passlib]\nschemes = pbkdf2_sha256\ndefault = pbkdf2_sha256\ndeprecated = auto\npbkdf2_sha256__default_rounds = 200000\npbkdf2_sha256__min_rounds = 200000\n```\n\n```python\nfrom passlib.context import CryptContext\n\npassword_context = CryptContext.from_path(\"passlib.ini\")\n```\n\nYou can also use `CryptContext.from_string()` if the config comes from another source.\n\n## Common Pitfalls\n\n- Install the matching backend for the scheme you choose. The base `passlib` install does not include `bcrypt` or `argon2-cffi`.\n- Do not use the deprecated `scheme=` keyword with `CryptContext.hash()`, `verify()`, `needs_update()`, or `verify_and_update()`. In Passlib 1.7 it is deprecated and scheduled for removal in 2.0.\n- Do not use legacy APIs such as `encrypt()`, `genconfig()`, or `genhash()` in new code. Use `hash()`, direct handler `.using(...)`, and `verify()` or `verify_and_update()`.\n- If you choose `bcrypt`, remember that BCrypt truncates passwords longer than 72 bytes by default. Set `truncate_error=True` to reject oversize passwords, or use `bcrypt_sha256` if you want a bcrypt-based scheme without the 72-byte truncation limit.\n- `verify(password, None)` returns `False`, and `verify_and_update(password, None)` returns `(False, None)`. That lets you keep a single login code path even when a user has no stored hash.\n\n## Version Notes For 1.7.x\n\n- Passlib 1.7 renamed `encrypt()` to `hash()`; `encrypt()` remains only as a deprecated alias.\n- Passlib 1.7 deprecated the explicit `scheme=` keyword on `CryptContext` hash/verify methods.\n- Passlib 1.7.3 changed `bcrypt_sha256` to an HMAC-SHA256-based `v=2` format while retaining support for older hashes. Let Passlib verify existing hashes instead of parsing bcrypt-sha256 strings yourself.\n\n## Official Sources\n\n- Maintainer docs: https://passlib.readthedocs.io/en/stable/\n- Changelog: https://passlib.readthedocs.io/en/stable/history\n- PyPI package page: https://pypi.org/project/passlib/\n"
  },
  {
    "path": "content/paypal/docs/checkout/DOC.md",
    "content": "---\nname: checkout\ndescription: \"PayPal JavaScript SDK for integrating checkout, payments, subscriptions, and orders into web applications.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.0.3\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"paypal,payments,checkout,subscriptions,orders\"\n---\n\n# PayPal JavaScript SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official PayPal JavaScript SDK packages:**\n- Core SDK: `@paypal/paypal-js` \n- React wrapper: `@paypal/react-paypal-js` \n\n**Never use deprecated or unofficial libraries.** These are the only supported PayPal JS SDK packages maintained by PayPal. \n\n## 2. Installation\n\n### npm\n```bash\nnpm install @paypal/paypal-js\n# For React applications\nnpm install @paypal/react-paypal-js\n```\n\n### yarn\n```bash\nyarn add @paypal/paypal-js\n# For React applications  \nyarn add @paypal/react-paypal-js\n```\n\n### pnpm\n```bash\npnpm add @paypal/paypal-js\n# For React applications\npnpm add @paypal/react-paypal-js\n``` \n\n**Environment Variables (Optional):**\n```bash\nPAYPAL_CLIENT_ID=your_client_id_here\nPAYPAL_ENVIRONMENT=sandbox # or production\n```\n\n## 3. Initialization\n\n### Vanilla JavaScript\n```javascript\nimport { loadScript } from \"@paypal/paypal-js\";\n\n// Basic initialization\nconst paypal = await loadScript({\n    clientId: \"your-client-id\",\n    currency: \"USD\"\n});\n``` \n\n### React Application\n```javascript\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\";\n\nfunction App() {\n    const initialOptions = {\n        clientId: \"your-client-id\",\n        currency: \"USD\",\n        intent: \"capture\"\n    };\n\n    return (\n        <PayPalScriptProvider options={initialOptions}>\n            {/* Your PayPal components here */}\n        </PayPalScriptProvider>\n    );\n}\n``` \n\nThe `PayPalScriptProvider` manages script loading and provides context to child components using React's Context API. \n\n## 4. Core API Surfaces\n\n### PayPal Buttons\n\n**Minimal Example:**\n```javascript\nimport { PayPalButtons } from \"@paypal/react-paypal-js\";\n\n<PayPalButtons\n    createOrder={(data, actions) => {\n        return actions.order.create({\n            purchase_units: [{\n                amount: { value: \"10.00\" }\n            }]\n        });\n    }}\n    onApprove={(data, actions) => {\n        return actions.order.capture();\n    }}\n/>\n```\n\n**Advanced Example:**\n```javascript\n<PayPalButtons\n    style={{\n        layout: \"vertical\",\n        color: \"gold\",\n        shape: \"rect\",\n        label: \"paypal\"\n    }}\n    createOrder={createOrder}\n    onApprove={onApprove}\n    onCancel={onCancel}\n    onError={onError}\n    fundingSource=\"paypal\"\n    disabled={false}\n    forceReRender={[amount, currency]}\n/>\n``` \n\n### Braintree Integration\n\n**Minimal Example:**\n```javascript\nimport { BraintreePayPalButtons } from \"@paypal/react-paypal-js\";\n\n<PayPalScriptProvider options={{\n    clientId: \"your-client-id\",\n    dataClientToken: \"your-braintree-client-token\"\n}}>\n    <BraintreePayPalButtons\n        createOrder={(data, actions) => {\n            return actions.braintree.createPayment({\n                flow: \"checkout\",\n                amount: \"10.00\",\n                currency: \"USD\"\n            });\n        }}\n        onApprove={(data, actions) => {\n            return actions.braintree.tokenizePayment(data);\n        }}\n    />\n</PayPalScriptProvider>\n``` \n\n### Messages and Marks\n```javascript\nimport { PayPalMessages, PayPalMarks } from \"@paypal/react-paypal-js\";\n\n<PayPalMessages\n    amount=\"10.00\"\n    placement=\"home\"\n    style={{\n        layout: \"text\",\n        logo: { type: \"primary\" }\n    }}\n/>\n\n<PayPalMarks />\n``` \n\n## 5. Advanced Features\n\n### Error Handling\n\nThe SDK provides comprehensive error handling through callback functions and component lifecycle management:\n\n```javascript\nconst onError = (err) => {\n    console.error(\"PayPal error:\", err);\n    // Handle specific error types\n    if (err.name === \"VALIDATION_ERROR\") {\n        // Handle validation errors\n    }\n};\n\n<PayPalButtons\n    onError={onError}\n    onCancel={onCancel}\n    // other props\n/>\n```\n\nThe PayPal Buttons component includes built-in error handling that catches rendering failures and SDK initialization errors. \n\n### Script Loading States\n\n```javascript\nimport { usePayPalScriptReducer } from \"@paypal/react-paypal-js\";\n\nfunction PayPalStatus() {\n    const [{ isLoaded, isPending, isRejected }] = usePayPalScriptReducer();\n    \n    if (isPending) return <div>Loading PayPal SDK...</div>;\n    if (isLoaded) return <div>SDK ready</div>;\n    if (isRejected) return <div>Failed to load SDK</div>;\n}\n```\n\n### Component Lifecycle Management\n\nThe PayPal components handle their lifecycle automatically, including cleanup when components unmount: \n\n### Dynamic Configuration\n\n```javascript\nimport { DISPATCH_ACTION } from \"@paypal/react-paypal-js\";\n\nconst [{ options }, dispatch] = usePayPalScriptReducer();\n\n// Update currency dynamically\ndispatch({\n    type: DISPATCH_ACTION.RESET_OPTIONS,\n    value: {\n        ...options,\n        currency: \"EUR\"\n    }\n});\n``` \n\n### Eligibility Checking\n\nThe SDK automatically checks component eligibility before rendering:\n\n## 6. TypeScript Usage\n\n### Import Types\n```typescript\nimport type {\n    PayPalScriptOptions,\n    PayPalButtonsComponentOptions,\n    PayPalNamespace,\n    FUNDING_SOURCE\n} from \"@paypal/paypal-js\";\n```\n\n### Type-Safe Component Usage\n```typescript\nimport { PayPalButtons } from \"@paypal/react-paypal-js\";\nimport type { PayPalButtonsComponentOptions } from \"@paypal/paypal-js\";\n\nconst buttonOptions: PayPalButtonsComponentOptions = {\n    style: {\n        layout: \"vertical\",\n        color: \"gold\"\n    },\n    createOrder: (data, actions) => {\n        return actions.order.create({\n            purchase_units: [{\n                amount: { value: \"10.00\" }\n            }]\n        });\n    },\n    onApprove: (data, actions) => {\n        return actions.order.capture();\n    }\n};\n\n<PayPalButtons {...buttonOptions} />\n```\n\n### Script Options Interface\n```typescript\nconst scriptOptions: PayPalScriptOptions = {\n    clientId: \"your-client-id\",\n    currency: \"USD\",\n    components: [\"buttons\", \"marks\"],\n    disableFunding: [\"credit\", \"card\"],\n    dataClientToken: \"braintree-token\"\n};\n```\n\n\n"
  },
  {
    "path": "content/pdf2image/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pdf2image Python package guide for converting PDFs to Pillow images with Poppler\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pdf2image,pdf,poppler,pillow,image,conversion\"\n---\n\n# pdf2image Python Package Guide\n\n## Golden Rule\n\n`pdf2image` is not a standalone PDF renderer. It is a Python wrapper around Poppler command-line tools such as `pdftoppm`, `pdftocairo`, and `pdfinfo`. If Poppler is missing or too old, your code will fail even if `pip install pdf2image` succeeded.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pdf2image==1.17.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pdf2image==1.17.0\"\npoetry add \"pdf2image==1.17.0\"\n```\n\nInstall Poppler separately.\n\nUbuntu or Debian:\n\n```bash\nsudo apt-get install poppler-utils\n```\n\nArch Linux:\n\n```bash\nsudo pacman -S poppler\n```\n\nmacOS:\n\n```bash\nbrew install poppler\n```\n\nWindows:\n\n1. Install `pdf2image` with `pip`.\n2. Download a Poppler build for Windows from the upstream-recommended `oschwartz10612/poppler-windows` releases.\n3. Add the extracted `bin` directory to `PATH`, or pass that directory as `poppler_path=...`.\n\nVerify Poppler before debugging Python code:\n\n```bash\npdftoppm -h\npdfinfo -h\n```\n\n## Setup And Initialization\n\nThere is no service authentication layer. Configuration is local:\n\n- Poppler executable discovery through `PATH`\n- optional `poppler_path` override\n- optional PDF password via `userpw`\n\nBasic imports:\n\n```python\nfrom pdf2image import convert_from_bytes, convert_from_path\nfrom pdf2image.exceptions import (\n    PDFInfoNotInstalledError,\n    PDFPageCountError,\n    PDFPopplerTimeoutError,\n    PDFSyntaxError,\n)\n```\n\nUsing an explicit Poppler location is common on Windows or inside custom containers:\n\n```python\nfrom pdf2image import convert_from_path\n\nimages = convert_from_path(\n    \"document.pdf\",\n    poppler_path=r\"C:\\poppler\\Library\\bin\",\n)\n```\n\n## Core Usage\n\n### Convert a PDF file from disk\n\n```python\nfrom pdf2image import convert_from_path\n\nimages = convert_from_path(\n    \"report.pdf\",\n    dpi=200,\n    fmt=\"jpeg\",\n)\n\nfor i, image in enumerate(images, start=1):\n    image.save(f\"page-{i}.jpg\", \"JPEG\")\n```\n\n`convert_from_path()` returns a list of Pillow `Image` objects, one per page.\n\n### Convert from bytes\n\nUse this when the PDF already lives in memory, for example after downloading it from object storage or a database.\n\n```python\nfrom pdf2image import convert_from_bytes\n\nwith open(\"report.pdf\", \"rb\") as f:\n    pdf_bytes = f.read()\n\nimages = convert_from_bytes(pdf_bytes, dpi=200, fmt=\"png\")\n```\n\n### Limit work to a page range\n\n```python\nfrom pdf2image import convert_from_path\n\nimages = convert_from_path(\n    \"report.pdf\",\n    first_page=1,\n    last_page=3,\n    fmt=\"png\",\n)\n```\n\n### Password-protected PDFs\n\n`pdf2image` supports the user password for encrypted PDFs:\n\n```python\nfrom pdf2image import convert_from_path\n\nimages = convert_from_path(\n    \"protected.pdf\",\n    userpw=\"secret-password\",\n)\n```\n\n### Large PDFs: write to disk instead of keeping everything in memory\n\nThis is the main operational pattern for real workloads.\n\n```python\nimport tempfile\n\nfrom pdf2image import convert_from_path\n\nwith tempfile.TemporaryDirectory() as tmpdir:\n    images = convert_from_path(\n        \"large.pdf\",\n        output_folder=tmpdir,\n        fmt=\"jpeg\",\n        paths_only=True,\n    )\n\n    for image_path in images:\n        print(image_path)\n```\n\nUse `paths_only=True` when your next step works on file paths and you want to avoid loading every page into memory.\n\n### Inspect page metadata first\n\nUse `pdfinfo_from_path()` when you want the page count before deciding what to render:\n\n```python\nfrom pdf2image import pdfinfo_from_path\n\ninfo = pdfinfo_from_path(\"report.pdf\")\npage_count = info[\"Pages\"]\nprint(page_count)\n```\n\n## Important Options\n\n- `dpi`: output resolution. Higher DPI improves quality but increases CPU, memory, and file size.\n- `fmt`: common values are `ppm`, `jpeg`, `png`, and `tiff`.\n- `first_page` / `last_page`: limit rendering to the pages you need.\n- `thread_count`: parallelizes Poppler work; upstream recommends staying conservative because I/O becomes the bottleneck quickly.\n- `output_folder`: strongly recommended for big PDFs.\n- `paths_only`: return file paths instead of Pillow objects; requires `output_folder`.\n- `use_pdftocairo`: can improve performance for some documents.\n- `timeout`: raises `PDFPopplerTimeoutError` if Poppler takes too long.\n- `strict=True`: raises `PDFSyntaxError` on syntax errors instead of swallowing them.\n- `size`: resizes output pages after rendering.\n- `grayscale=True`: render grayscale images.\n\n## Common Pitfalls\n\n- Missing Poppler is the first thing to check. The failure often shows up as `PDFInfoNotInstalledError` or `PDFPageCountError`, not as a Python import error.\n- `pdf2image` can exhaust memory on large PDFs if you render many pages to in-memory Pillow objects. Prefer `output_folder` and `paths_only=True`.\n- `paths_only=True` only makes sense with `output_folder`. Without an output directory, there are no files to point at.\n- Default `ppm` output is large and uncompressed. Use `fmt=\"jpeg\"` for faster I/O and smaller files when JPEG is acceptable.\n- PNG is slower because of compression. Use it when you need lossless output or transparency, not by default.\n- Old Poppler versions can fail on some PDFs, especially the DocuSign-style broken-xref case documented upstream. If you see `Unable to get page count` with syntax errors, update Poppler before changing Python code.\n- More threads are not automatically better. Upstream explicitly warns that high `thread_count` values usually become I/O-bound; keep it modest.\n\n## Version-Sensitive Notes\n\n- The version used here `1.17.0` still matches the latest PyPI release as of March 12, 2026.\n- The official docs site currently renders `1.16.1`, so prefer the GitHub README and PyPI project page for package-level setup and behavior when you need `1.17.0` context.\n- The `1.17.0` GitHub release notes call out fixes around public exports, `pdfinfo` page-range support, and a `single_file` plus `thread_count` bug.\n- Upstream package text says Python `3.7+`, but the PyPI classifiers shown on March 12, 2026 stop at Python `3.10`. Treat newer Python versions as plausible but verify them in your own CI instead of assuming classifier coverage means active testing.\n- The current `master` branch source exposes parameters that are not described consistently across the README and docs site. For agent work pinned to `1.17.0`, avoid relying on `master`-only signatures without checking the installed package.\n\n## Official Sources\n\n- GitHub repository: `https://github.com/Belval/pdf2image`\n- GitHub releases: `https://github.com/Belval/pdf2image/releases`\n- Official docs site: `https://belval.github.io/pdf2image/`\n- PyPI project page: `https://pypi.org/project/pdf2image/`\n"
  },
  {
    "path": "content/pdfplumber/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pdfplumber package guide for extracting text, tables, and layout data from PDFs in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.11.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pdfplumber,pdf,pdfminer,text-extraction,tables,python\"\n---\n\n# pdfplumber Python Package Guide\n\n## Golden Rule\n\nUse `pdfplumber` for reading and extracting structured data from machine-generated PDFs. It is not a PDF editor and it does not perform OCR, so scanned image PDFs usually need an OCR step before `pdfplumber` can extract meaningful text.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pdfplumber==0.11.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pdfplumber==0.11.9\"\npoetry add \"pdfplumber==0.11.9\"\n```\n\nPublished `0.11.9` metadata depends on `pdfminer.six==20251230`, `Pillow>=9.1`, and `pypdfium2>=4.18.0`.\n\n## Initialization And Setup\n\n`pdfplumber` has no auth layer. The main setup work is choosing how to open the PDF and which parsing options you need.\n\nOpen a local file and ensure handles and page caches are released with a context manager:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"statement.pdf\") as pdf:\n    first_page = pdf.pages[0]\n    text = first_page.extract_text()\n    print(text)\n```\n\nOpen encrypted PDFs with `password=`:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"protected.pdf\", password=\"secret\") as pdf:\n    print(len(pdf.pages))\n```\n\nOpen from bytes or a file-like object when the PDF comes from cloud storage or an HTTP response:\n\n```python\nfrom io import BytesIO\n\nimport pdfplumber\nimport requests\n\nresponse = requests.get(\"https://example.com/report.pdf\", timeout=30)\nresponse.raise_for_status()\n\nwith pdfplumber.open(BytesIO(response.content)) as pdf:\n    print(pdf.pages[0].extract_text())\n```\n\nUseful open-time options:\n\n- `laparams={...}` passes layout-analysis settings through to `pdfminer.six`\n- `unicode_norm=\"NFC\" | \"NFKC\" | \"NFD\" | \"NFKD\"` normalizes Unicode before extraction\n- `strict_metadata=True` turns invalid metadata values into exceptions instead of warnings\n- `password=\"...\"` opens encrypted PDFs\n\n## Core Usage\n\n### Extract plain text\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"report.pdf\") as pdf:\n    page = pdf.pages[0]\n    text = page.extract_text()\n    print(text)\n```\n\nIf spacing or line grouping matters, try the layout-aware path:\n\n```python\ntext = page.extract_text(layout=True)\n```\n\n### Extract words with coordinates\n\n`extract_words()` is often better than raw text when you need positions for downstream parsing:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"invoice.pdf\") as pdf:\n    words = pdf.pages[0].extract_words()\n\nfor word in words[:5]:\n    print(word[\"text\"], word[\"x0\"], word[\"top\"], word[\"x1\"], word[\"bottom\"])\n```\n\nThis is a common starting point for invoice, statement, and form parsers.\n\n### Search for text on a page\n\n`search()` returns matched text with positions, which is useful when you need anchors before cropping nearby content:\n\n```python\nimport re\n\nimport pdfplumber\n\nwith pdfplumber.open(\"invoice.pdf\") as pdf:\n    matches = pdf.pages[0].search(re.compile(r\"Invoice Number\"))\n\nfor match in matches:\n    print(match[\"text\"], match[\"x0\"], match[\"top\"])\n```\n\n### Crop to a region before extracting\n\nCropping usually improves reliability when the page has headers, footers, or multiple columns:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"report.pdf\") as pdf:\n    page = pdf.pages[0]\n    body = page.crop((40, 80, page.width - 40, page.height - 60))\n    print(body.extract_text())\n```\n\nThe bounding box format is `(x0, top, x1, bottom)`.\n\n### Remove duplicate characters\n\nSome PDFs contain overlapping character layers, which causes repeated text. `dedupe_chars()` helps before text extraction:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"overlay.pdf\") as pdf:\n    page = pdf.pages[0].dedupe_chars()\n    print(page.extract_text())\n```\n\n### Extract tables\n\nStart with the defaults:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"table.pdf\") as pdf:\n    table = pdf.pages[0].extract_table()\n\nfor row in table or []:\n    print(row)\n```\n\nIf the defaults miss rows or columns, pass `table_settings` explicitly:\n\n```python\nimport pdfplumber\n\ntable_settings = {\n    \"vertical_strategy\": \"lines\",\n    \"horizontal_strategy\": \"text\",\n}\n\nwith pdfplumber.open(\"table.pdf\") as pdf:\n    tables = pdf.pages[0].extract_tables(table_settings=table_settings)\n```\n\nFor hard PDFs, the usual workflow is:\n\n1. crop to the table region\n2. inspect with `debug_tablefinder(...)`\n3. adjust `vertical_strategy`, `horizontal_strategy`, tolerances, and edge filtering\n\n### Visual debugging\n\nUse page images to debug table detection and geometry:\n\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"table.pdf\") as pdf:\n    page = pdf.pages[0]\n    image = page.to_image(resolution=150)\n    image.debug_tablefinder()\n    image.save(\"table-debug.png\")\n```\n\nThis is especially useful in notebooks because `PageImage` objects render inline.\n\n### Command-line usage\n\nThe package installs a `pdfplumber` CLI. Typical examples:\n\n```bash\npdfplumber input.pdf --format text\npdfplumber input.pdf --format csv --pages 1,2\npdfplumber input.pdf --types char rect line\n```\n\nUse the CLI for quick inspection and switch to Python when you need cropping, custom matching logic, or post-processing.\n\n## Configuration Notes\n\nThere is no service configuration or API credential model. The main configuration surfaces are:\n\n- `laparams` for layout analysis behavior inherited from `pdfminer.six`\n- `table_settings` for table extraction behavior\n- page cropping and filtering for scoping extraction\n- password handling for encrypted PDFs\n\nIf you fetch PDFs over the network, handle authentication yourself with `requests`, `httpx`, cloud SDKs, or your storage client, then pass a path or file-like object into `pdfplumber`.\n\n## Common Pitfalls\n\n- `pdfplumber` works best on digitally generated PDFs. If the source is scanned images, text extraction may return little or nothing until OCR is applied.\n- Coordinate math is easy to get wrong. Most page objects expose `x0`, `x1`, `top`, and `bottom`, and crop boxes use `(x0, top, x1, bottom)`.\n- Large PDFs can hold substantial cached layout data. Prefer `with pdfplumber.open(...)` and call `page.close()` if you need to aggressively flush cached page data mid-run.\n- `Page.filter(...)` changes extraction results but does not affect the current `to_image(...)` rendering, so visual debug output can differ from filtered extraction output.\n- Table extraction is sensitive to page noise and layout. Crop first and tune strategies instead of assuming `extract_table()` will work globally on the full page.\n- `search()` discards zero-width and all-whitespace matches because they do not have meaningful page positions.\n- Image objects in a PDF expose metadata, but `pdfplumber` is not a full image reconstruction pipeline. Use a dedicated PDF or imaging tool if you need to recover embedded image bytes exactly.\n\n## Version-Sensitive Notes\n\n- `0.11.9` updates the `pdfminer.six` dependency to `20251230`. If text extraction behavior changes after an upgrade, check whether `pdfminer.six` changes are the cause.\n- `0.11.8` added `edge_min_length_prefilter` to `table_settings`, which can help reduce short-edge noise in table detection.\n- `0.11.7` removed `stroking_pattern` and `non_stroking_pattern` attributes after upstream parser changes. Avoid depending on those fields in object dictionaries.\n- `0.11.5` added CLI `--format text` support and the `raise_unicode_errors` option on `open(...)`.\n- The table extraction redesign landed in `v0.5.0`; older blog posts and examples written for pre-`0.5` releases are often incompatible with current settings and result shapes.\n- PyPI `0.11.9` metadata declares `Python >=3.8`. If the maintainer branch README mentions newer tested interpreter ranges, treat the published package metadata as authoritative for this pinned release.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/jsvine/pdfplumber`\n- Project README: `https://raw.githubusercontent.com/jsvine/pdfplumber/stable/README.md`\n- Changelog: `https://raw.githubusercontent.com/jsvine/pdfplumber/stable/CHANGELOG.md`\n- Tagged release requirements: `https://raw.githubusercontent.com/jsvine/pdfplumber/v0.11.9/requirements.txt`\n- PyPI package page: `https://pypi.org/project/pdfplumber/`\n- PyPI JSON metadata: `https://pypi.org/pypi/pdfplumber/0.11.9/json`\n"
  },
  {
    "path": "content/pdm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PDM package guide for Python projects using pyproject.toml, lockfiles, scripts, and publishing workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.26.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pdm,python,packaging,dependency-management,pyproject,lockfile,publishing\"\n---\n\n# PDM Python Package Guide\n\n## Golden Rule\n\nUse `pdm` as a project tool, not as a runtime dependency of your application. Prefer the default virtualenv workflow unless you intentionally want PEP 582, and treat `pdm.lock` as the source of truth for installs. Commit `pdm.lock` for applications and most service repos; decide deliberately for pure libraries if you want CI to mimic end-user installs instead.\n\n## Install PDM\n\nPrefer installing PDM as a user-level tool instead of adding it to a project virtualenv.\n\nRecommended isolated installs:\n\n```bash\nuv tool install pdm\npipx install pdm\n```\n\nOfficial installer scripts:\n\n```bash\ncurl -sSL https://pdm-project.org/install.sh | bash\ncurl -sSL https://pdm-project.org/install.sh | bash -s -- -v 2.26.6\n```\n\nIf you need a plain Python install:\n\n```bash\npython -m pip install --user \"pdm==2.26.6\"\n```\n\nCheck the installed version:\n\n```bash\npdm --version\n```\n\nUpdate an existing installation:\n\n```bash\npdm self update\n```\n\n## Initialize A Project\n\nFor a new project, use `pdm new`:\n\n```bash\npdm new my-project\ncd my-project\n```\n\nFor an existing directory, generate `pyproject.toml` with `pdm init`:\n\n```bash\ncd existing-project\npdm init\n```\n\nImportant setup details:\n\n- PDM stores the selected interpreter path in `.pdm-python`.\n- `PDM_PYTHON=/path/to/python` overrides the saved interpreter.\n- If `.python-version` exists, PDM can use that version hint.\n- In `2.26.6`, virtualenv mode is the default. On first install for a new project, PDM usually creates `.venv` unless you configure otherwise.\n\nPick the project type carefully:\n\n- Application: usually no build backend is needed.\n- Library: needs package metadata and a build backend because you expect to build and publish wheels/sdists.\n\nFor library behavior, PDM uses `distribution = true` under `[tool.pdm]`.\n\n## Core Workflow\n\n### Add And Manage Dependencies\n\nAdd production dependencies:\n\n```bash\npdm add requests httpx\n```\n\nAdd an optional dependency group that becomes `[project.optional-dependencies]`:\n\n```bash\npdm add -G postgres psycopg[binary]\n```\n\nAdd development dependencies under `[dependency-groups]`:\n\n```bash\npdm add -dG test pytest pytest-cov\npdm add -dG lint ruff mypy\n```\n\nRemove or update dependencies:\n\n```bash\npdm remove httpx\npdm update requests\npdm outdated\n```\n\nNotes:\n\n- `pdm add requests` saves a minimum version specifier by default, such as `>=x.y.z`.\n- Use `--save-compatible` or `--save-exact` when you need tighter constraints.\n- Editable installs are allowed only in development groups:\n\n```bash\npdm add -d -e ./shared-lib\n```\n\n### Install And Sync From The Lockfile\n\n```bash\npdm install\npdm sync\npdm sync --clean\n```\n\nUse group selection when needed:\n\n```bash\npdm install --prod\npdm install -G postgres\npdm install -G test\npdm install -G:all\n```\n\nKey behavior:\n\n- `pdm.lock` is the install source of truth.\n- `pdm install` and `pdm add` automatically create or update `pdm.lock`.\n- `pdm sync --clean` removes packages that are not in the selected locked groups.\n\nCheck or refresh the lockfile:\n\n```bash\npdm lock --check\npdm lock --refresh\n```\n\n### Minimal `pyproject.toml` Shape\n\nApplication-oriented example:\n\n```toml\n[project]\nrequires-python = \">=3.12\"\ndependencies = [\n  \"fastapi>=0.118.0\",\n  \"uvicorn>=0.37.0\",\n]\n\n[dependency-groups]\ntest = [\"pytest>=8.3.0\"]\nlint = [\"ruff>=0.11.0\"]\n\n[tool.pdm]\ndistribution = false\n```\n\nLibrary-oriented example:\n\n```toml\n[project]\nname = \"example-lib\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = [\"httpx>=0.28.0\"]\n\n[build-system]\nrequires = [\"pdm-backend\"]\nbuild-backend = \"pdm.backend\"\n\n[tool.pdm]\ndistribution = true\n```\n\n## Virtual Environments And Python Selection\n\nDefault behavior in current docs:\n\n- Virtualenvs are preferred over PEP 582 because ecosystem tooling and IDE support are better.\n- First-time `pdm install` on a new project usually creates `.venv`.\n- `pdm use` can switch interpreters, and with `python.use_venv = true` it will create a virtualenv for the chosen interpreter.\n\nCommon commands:\n\n```bash\npdm info\npdm use 3.12\npdm venv create 3.12\npdm use -f /path/to/venv\n```\n\nUseful config:\n\n```bash\npdm config python.use_venv true\npdm config venv.in_project true\npdm config venv.backend virtualenv\n```\n\nIf you disable in-project environments, named virtualenvs go under `venv.location` instead of `.venv`.\n\n## Lockfiles And Reproducibility\n\nPDM creates cross-platform lockfiles by default. That is usually what you want for shared repos, but it can cause trouble when packages publish incomplete wheel sets.\n\nUseful commands:\n\n```bash\npdm lock\npdm lock --strategy no_cross_platform\npdm lock --exclude-newer 2026-01-01\n```\n\nRelevant current behavior:\n\n- `inherit_metadata` is enabled by default and speeds up installs.\n- Since `2.25.0`, PDM also supports the experimental `pylock.toml` format from PEP 751.\n- In `2.26.6`, the default lock format is still `pdm.lock`, not `pylock.toml`.\n\nTo switch formats explicitly:\n\n```bash\npdm config lock.format pylock\n```\n\n## Private Indexes, Auth, And Configuration\n\nUse `[[tool.pdm.source]]` when the index definition should be shared with the project:\n\n```toml\n[[tool.pdm.source]]\nname = \"private\"\nurl = \"https://private.example.com/simple\"\nverify_ssl = true\n```\n\nUse `pdm config` for machine-local index settings:\n\n```bash\npdm config pypi.url \"https://test.pypi.org/simple\"\npdm config pypi.extra.url \"https://extra.example.com/simple\"\n```\n\nImportant distinction:\n\n- Indexes (`pypi.*`, `tool.pdm.source`) are for resolving and locking.\n- Repositories (`repository.*`) are for publishing.\n\nFor publish credentials:\n\n```bash\npdm config repository.pypi.username \"__token__\"\npdm config repository.pypi.password \"pypi-...\"\n```\n\nOr use environment variables:\n\n```bash\nexport PDM_PUBLISH_USERNAME=\"__token__\"\nexport PDM_PUBLISH_PASSWORD=\"pypi-...\"\n```\n\nFor source credentials, prefer environment-variable expansion instead of committing secrets:\n\n```toml\n[[tool.pdm.source]]\nname = \"private\"\nurl = \"https://${PRIVATE_PYPI_USERNAME}:${PRIVATE_PYPI_PASSWORD}@private.example.com/simple\"\n```\n\nWhen keyring support is available, PDM can store index and repository passwords there instead of writing them into config files.\n\nIf teams must use only the indexes committed in the repo:\n\n```bash\npdm config pypi.ignore_stored_index true\n```\n\nIf source priority matters:\n\n```toml\n[tool.pdm.resolution]\nrespect-source-order = true\n```\n\n## Scripts And Task Running\n\nPDM can act as a lightweight task runner through `[tool.pdm.scripts]`.\n\nExample:\n\n```toml\n[tool.pdm.scripts]\ntest = \"pytest\"\nserve.cmd = \"uvicorn app.main:app --reload\"\nserve.env_file = \".env\"\ncheck.composite = [\"test\", \"ruff check .\"]\n```\n\nRun scripts with:\n\n```bash\npdm run test\npdm run serve\npdm run check\npdm run --list\n```\n\nPractical notes:\n\n- `env_file` loads dotenv-style variables for the script.\n- `composite` runs multiple named tasks in order.\n- `pdm run` is usually the right entrypoint for local dev commands because it uses the project environment and dependency graph.\n\n## Build And Publish\n\nFor libraries:\n\n```bash\npdm build\npdm publish --no-build\n```\n\nOr build and upload in one step:\n\n```bash\npdm publish\n```\n\nCurrent docs note:\n\n- `pdm publish` builds both wheel and sdist before upload.\n- PyPI uploads use `__token__` as the username and the API token as the password.\n- Trusted publishing is supported for CI and is preferable to storing long-lived PyPI tokens in GitHub Actions or GitLab CI.\n\n## Version Control\n\nUsually commit these files:\n\n- `pyproject.toml`\n- `pdm.lock` for applications and most deployable repos\n- `pdm.toml` when you want to share project-wide PDM config\n\nSometimes skip `pdm.lock` for pure libraries if your CI intentionally tests resolution against current ecosystem packages instead of a pinned graph.\n\nDo not commit:\n\n- `.pdm-python`\n\n## Common Pitfalls\n\n- Do not treat `pdm` like an importable library. It is primarily a CLI tool for managing the project.\n- Do not share one existing virtualenv across multiple projects and then run `pdm sync --clean`; PDM can remove packages that are not declared in the current project.\n- Do not confuse optional dependency groups with development groups. Optional groups go into package metadata; dev groups do not.\n- Editable installs only work in dev dependency groups.\n- `--prod` cannot be combined with dev groups.\n- Do not put private credentials directly in committed `pyproject.toml`; use environment variables, local config, or keyring.\n- Publishing repositories and install indexes are separate config systems. `repository.*` does not affect locking, and `pypi.*` does not affect publishing.\n- Set `requires-python` carefully. PDM resolves against the whole declared range, so an overly broad range can produce `ResolutionImpossible` failures.\n\n## Version-Sensitive Notes For `2.26.6`\n\n- PyPI lists `pdm 2.26.6` as the latest release on January 22, 2026.\n- `2.26.6` is a patch release that fixes compatibility with `packaging==26.0`; if you see version-comparison issues on older PDM releases, upgrade before debugging the resolver.\n- `pdm new` is relatively recent, added in `2.24.0`. Older guides may tell you to use `pdm init` for everything.\n- Support for `pylock.toml` was added in `2.25.0`, but `pdm.lock` is still the default format in `2.26.6`.\n- PDM itself requires Python `>=3.9` to run. Current docs also note that application projects without a build backend can still target older Python versions, but library builds remain constrained by the selected backend. The default `pdm-backend` supports Python `>=3.7`.\n"
  },
  {
    "path": "content/pdoc/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pdoc package guide for generating API documentation from Python modules and docstrings\"\nmetadata:\n  languages: \"python\"\n  versions: \"16.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pdoc,python,documentation,docstrings,api-docs\"\n---\n\n# pdoc Python Package Guide\n\n## When To Use pdoc\n\nUse `pdoc` when you want API documentation generated directly from importable Python modules and their docstrings. It works well for libraries and internal packages where the public API already lives in code and you want a simple HTML output without a larger docs stack.\n\n`pdoc` runs locally against your source tree. There are no service credentials or remote API keys to configure.\n\n## Install\n\nCreate an environment and install the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pdoc==16.0.0\"\n```\n\nIf you are documenting a local package, make sure that package is importable before you run `pdoc`:\n\n```bash\npython -m pip install -e .\n```\n\nFor a `src/` layout, setting `PYTHONPATH` is the simplest option when you do not want an editable install:\n\n```bash\nexport PYTHONPATH=\"$PWD/src\"\n```\n\n## Minimal Package Layout\n\n`pdoc` reads docstrings from importable modules. A minimal package looks like this:\n\n```text\nexample_pkg/\n  __init__.py\n  math_utils.py\n```\n\n```python\n# example_pkg/__init__.py\n\"\"\"Example package used for pdoc generation.\"\"\"\n\nfrom .math_utils import add\n\n__all__ = [\"add\"]\n```\n\n```python\n# example_pkg/math_utils.py\n\"\"\"Small math helpers.\"\"\"\n\ndef add(left: int, right: int) -> int:\n    \"\"\"Return the sum of two integers.\"\"\"\n    return left + right\n```\n\n## Preview Docs Locally\n\nUse the package import path you want to document:\n\n```bash\nexport PYTHONPATH=\"$PWD\"\npdoc example_pkg\n```\n\nThis is the quickest way to check whether `pdoc` can import the package cleanly and whether module, class, and function docstrings render the way you expect.\n\nIf your code lives under `src/`, use that directory instead:\n\n```bash\nexport PYTHONPATH=\"$PWD/src\"\npdoc example_pkg\n```\n\n## Generate Static HTML\n\nWrite the generated documentation to an output directory:\n\n```bash\nexport PYTHONPATH=\"$PWD/src\"\npdoc example_pkg -o docs/api\n```\n\nThat pattern works well in CI, release automation, or a docs publish step.\n\n## Generate Docs From Python\n\nUse the Python API when you want docs generation inside a build script or task runner:\n\n```python\nfrom pathlib import Path\n\nimport pdoc\n\npdoc.pdoc(\"example_pkg\", output_directory=Path(\"docs/api\"))\n```\n\nThis is the core programmatic entry point to copy into an application or automation script.\n\n## Common Workflow For A Library Repo\n\n1. Put public modules and functions behind stable import paths.\n2. Add docstrings to packages, modules, classes, and functions.\n3. Make the package importable with `pip install -e .` or `PYTHONPATH`.\n4. Run `pdoc your_package -o docs/api`.\n5. Publish the generated HTML from your docs or static-site pipeline.\n\n## Important Pitfalls\n\n### Your package must import cleanly\n\n`pdoc` inspects real Python modules, so import failures stop documentation generation. Run it in the same environment your package expects, and install optional dependencies that are imported at module import time.\n\n### Import side effects show up during docs generation\n\nIf a module opens network connections, reads unavailable files, or depends on missing environment variables at import time, docs generation can fail. Keep import-time side effects minimal and move runtime setup behind functions or `if __name__ == \"__main__\":` blocks.\n\n### The import path matters\n\nIf `pdoc` cannot resolve `example_pkg`, either install the package editable or set `PYTHONPATH` to the directory that contains the package root:\n\n```bash\npython -m pip install -e .\n```\n\nor:\n\n```bash\nexport PYTHONPATH=\"$PWD/src\"\n```\n\n### Document the public API you actually export\n\nIf your package re-exports functions or classes from submodules, keep those imports explicit in the package namespace you want users to see. `pdoc` is easiest to work with when the documented public surface is importable directly.\n\n## Practical CI Step\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install -e . \"pdoc==16.0.0\"\npdoc example_pkg -o docs/api\n```\n\nUse the same package import path here that your users import in code.\n\n## Official Sources\n\n- Maintainer docs: `https://pdoc.dev/docs/pdoc.html`\n- PyPI package page: `https://pypi.org/project/pdoc/`\n"
  },
  {
    "path": "content/pdpyras/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pdpyras package guide for Python projects using PagerDuty REST, Events, and Change Events APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pagerduty,api,incidents,events,python,requests\"\n---\n\n# pdpyras Python Package Guide\n\n## Golden Rule\n\n`pdpyras` `5.4.1` is upstream-maintained but officially deprecated. Use it when you are maintaining an existing codebase that already depends on `pdpyras`; for new PagerDuty integrations, PagerDuty directs you to `python-pagerduty` and its migration guide.\n\nPin the version if you need behavior that matches this guide:\n\n```bash\npip install \"pdpyras==5.4.1\"\n```\n\n## Install\n\n### pip\n\n```bash\npip install pdpyras\n```\n\n### Pin the documented version\n\n```bash\npip install \"pdpyras==5.4.1\"\n```\n\n### Poetry\n\n```bash\npoetry add \"pdpyras==5.4.1\"\n```\n\n### uv\n\n```bash\nuv add \"pdpyras==5.4.1\"\n```\n\n## Authentication And Setup\n\n### REST API v2 session\n\nUse `APISession` for PagerDuty REST API v2 work with a token from the PagerDuty web UI or OAuth flow:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\n```\n\nFor an OAuth access token, set `auth_type=\"oauth2\"`:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(\n    os.environ[\"PAGERDUTY_OAUTH_TOKEN\"],\n    auth_type=\"oauth2\",\n)\n```\n\n### `From` header for account-level API tokens\n\nPagerDuty requires a user identity for some mutating actions when you use an account-level API token. Set `default_from` once on the session instead of repeating headers per request:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\nsession.default_from = os.environ[\"PAGERDUTY_FROM_EMAIL\"]\n```\n\nIf you skip this when the endpoint requires it, PagerDuty will reject the request even though the token itself is valid.\n\n### EU service region\n\n`APISession` defaults to the US API host. If your PagerDuty account is in the EU service region, change the base URL before making requests:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\nsession.url = \"https://api.eu.pagerduty.com\"\n```\n\n### Events API v2\n\nUse `EventsAPISession` for trigger, acknowledge, and resolve events:\n\n```python\nimport os\nimport pdpyras\n\nevents = pdpyras.EventsAPISession(os.environ[\"PAGERDUTY_EVENTS_ROUTING_KEY\"])\n```\n\n### Change Events API\n\nUse `ChangeEventsAPISession` for deployment or release annotations:\n\n```python\nimport os\nimport pdpyras\n\nchanges = pdpyras.ChangeEventsAPISession(\n    os.environ[\"PAGERDUTY_CHANGE_EVENTS_ROUTING_KEY\"]\n)\n```\n\n## Core Usage\n\n### Read a REST resource\n\nThe `r*` helpers return decoded entity payloads instead of raw `requests.Response` objects:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\n\nuser = session.rget(\"users/me\")\nprint(user[\"name\"])\nprint(user[\"email\"])\n```\n\nUse the non-`r` methods such as `get()` if you specifically need the raw HTTP response.\n\n### Find one object by attribute\n\n`find()` is the convenience path when you want a single match from an index endpoint:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\n\nservice = session.find(\"services\", \"Primary API\", attribute=\"name\")\nif service is None:\n    raise RuntimeError(\"Service not found\")\n\nprint(service[\"id\"])\n```\n\n### Iterate paginated collections\n\nUse `iter_all()` for endpoints that support classic list pagination:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\n\nfor service in session.iter_all(\"services\"):\n    print(service[\"id\"], service[\"name\"])\n```\n\nIf you actually need a materialized list, `list_all()` collects the iterator into memory.\n\n### Create or update an object idempotently\n\n`persist()` is useful when your automation should create a resource if it does not exist yet:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\nsession.default_from = os.environ[\"PAGERDUTY_FROM_EMAIL\"]\n\npayload = {\n    \"type\": \"service\",\n    \"name\": \"Automation Demo Service\",\n    \"escalation_policy\": {\n        \"id\": \"P12345\",\n        \"type\": \"escalation_policy_reference\",\n    },\n}\n\nservice = session.persist(\n    \"services\",\n    \"name\",\n    payload,\n)\n\nprint(service[\"id\"])\n```\n\n### Update an existing REST object\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\nsession.default_from = os.environ[\"PAGERDUTY_FROM_EMAIL\"]\n\nupdated = session.rput(\n    \"users/PABC123\",\n    json={\n        \"user\": {\n            \"type\": \"user\",\n            \"job_title\": \"On-call Engineer\",\n        }\n    },\n)\n\nprint(updated[\"job_title\"])\n```\n\n### Trigger, acknowledge, and resolve incidents with the Events API\n\n```python\nimport os\nimport pdpyras\n\nevents = pdpyras.EventsAPISession(os.environ[\"PAGERDUTY_EVENTS_ROUTING_KEY\"])\n\ndedup_key = \"checkout-api-prod\"\n\ndedup_key = events.trigger(\n    \"Checkout API latency is above threshold\",\n    \"checkout-api-prod\",\n    dedup_key=dedup_key,\n    severity=\"critical\",\n    custom_details={\n        \"component\": \"checkout-api\",\n        \"group\": \"payments\",\n        \"class\": \"latency\",\n    },\n)\n\nevents.acknowledge(dedup_key)\nevents.resolve(dedup_key)\n\nprint(dedup_key)\n```\n\nKeep the same `dedup_key` across trigger, acknowledge, and resolve calls so PagerDuty correlates them into one incident lifecycle.\n\n### Submit a change event\n\n```python\nimport os\nimport pdpyras\n\nchanges = pdpyras.ChangeEventsAPISession(\n    os.environ[\"PAGERDUTY_CHANGE_EVENTS_ROUTING_KEY\"]\n)\n\nchanges.submit(\n    \"Deployed checkout-api 2026.03.12\",\n    source=\"github-actions\",\n    custom_details={\n        \"service\": \"checkout-api\",\n        \"environment\": \"prod\",\n        \"release\": \"2026.03.12\",\n    },\n)\n```\n\n`submit()` also accepts a `timestamp` parameter. Upstream added that in the `5.1.0` line, which matters if you need the event to reflect the actual deployment time rather than submission time.\n\n## Configuration And HTTP Behavior\n\n### Timeouts and retries\n\n`pdpyras` includes retry logic on top of `requests`. The module reference exposes defaults such as:\n\n- `TIMEOUT = 60`\n- `max_http_attempts = 10`\n- unlimited retries on `429` rate-limit responses by default\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\nsession.timeout = 30\nsession.max_http_attempts = 5\nsession.retry[500] = 2\n```\n\nThe same retry-oriented defaults were extended to `EventsAPISession` and `ChangeEventsAPISession` in the `5.1.2` line.\n\n### Query parameters\n\nPass PagerDuty query parameters as normal Python dict keys:\n\n```python\nimport os\nimport pdpyras\n\nsession = pdpyras.APISession(os.environ[\"PAGERDUTY_API_TOKEN\"])\n\nincidents = session.list_all(\n    \"incidents\",\n    params={\n        \"statuses\": [\"triggered\", \"acknowledged\"],\n        \"limit\": 25,\n    },\n)\n```\n\nUpstream notes that list-valued parameters are automatically normalized to the `param[]=` form PagerDuty expects.\n\n### Raw response vs wrapped entity\n\nThe convenience methods come in three common shapes:\n\n- `get`, `post`, `put`, `delete`: raw `requests.Response`\n- `jget`, `jpost`, `jput`: decoded JSON document\n- `rget`, `rpost`, `rput`: unwrapped PagerDuty entity payload\n\nChoose the helper that matches the response shape you actually need.\n\n## Common Pitfalls\n\n- Do not start new greenfield integrations on `pdpyras`. PagerDuty marks it deprecated and recommends `python-pagerduty`.\n- `APISession` defaults to `https://api.pagerduty.com`. Set `session.url = \"https://api.eu.pagerduty.com\"` for EU-region accounts before you make requests.\n- Account-level API tokens often need a `From` header. Set `session.default_from` for mutating operations.\n- `iter_all()` paginates live collections. Upstream explicitly warns against mutating the same collection while you are iterating it.\n- Keep `dedup_key` stable across Events API lifecycle calls or you will create separate incidents instead of acknowledging or resolving the original one.\n- Use `r*` helpers only when the endpoint returns a wrapped entity like `{\"user\": {...}}`. If you need headers, status code, or an unwrapped body, use `get()` or `jget()` instead.\n- Retry behavior is helpful for scripts, but the default unlimited retry on `429` can stall short-lived jobs longer than you expect.\n\n## Version-Sensitive Notes For 5.4.1\n\n- PyPI currently lists `5.4.1` as the latest `pdpyras` release.\n- The official docs landing page for `5.4.1` now opens with a deprecation notice and links to the `python-pagerduty` migration guide.\n- The upstream changelog marks deprecation in the `5.4.0` line, so `5.4.1` should be treated as a maintenance-era release rather than the start of a new feature line.\n- The `5.1.x` line added important behavior that many older blog posts will miss: `ChangeEventsAPISession.submit()` gained a `timestamp` parameter in `5.1.0`, and retry defaults were added to the Events and Change Events sessions in `5.1.2`.\n- If you are reading older examples, remember that `pdpyras` has three session types with different auth tokens and base URLs. Do not pass a REST API token to `EventsAPISession` or a routing key to `APISession`.\n\n## Official Sources\n\n- Docs root: https://pagerduty.github.io/pdpyras/\n- User guide: https://pagerduty.github.io/pdpyras/user_guide.html\n- Module reference: https://pagerduty.github.io/pdpyras/module_reference.html\n- Changelog: https://pagerduty.github.io/pdpyras/changelog.html\n- Migration guide: https://github.com/PagerDuty/pdpyras/blob/master/migration_guide.md\n- PyPI: https://pypi.org/project/pdpyras/\n"
  },
  {
    "path": "content/peewee/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Peewee ORM package guide for Python projects using the official 4.0.1 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"peewee,python,orm,sqlite,postgresql,mysql,database\"\n---\n\n# Peewee Python Package Guide\n\n## Golden Rule\n\nUse the official `peewee` package and write against the Peewee 4.x docs, not old 3.x blog posts. As of March 12, 2026, both the official docs and PyPI point to `peewee 4.0.1`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"peewee==4.0.1\"\n```\n\nDriver extras from the maintainer docs:\n\n```bash\npython -m pip install \"peewee[postgres]==4.0.1\"\npython -m pip install \"peewee[psycopg3]==4.0.1\"\npython -m pip install \"peewee[mysql]==4.0.1\"\n```\n\nAsync extras from the 4.x asyncio docs:\n\n```bash\npython -m pip install \"peewee[aiosqlite]==4.0.1\"\npython -m pip install \"peewee[aiopg]==4.0.1\"\npython -m pip install \"peewee[asyncpg]==4.0.1\"\npython -m pip install \"peewee[aiomysql]==4.0.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"peewee==4.0.1\"\npoetry add \"peewee==4.0.1\"\n```\n\n## Initialize A Database\n\n### Basic SQLite setup\n\n```python\nfrom peewee import (\n    CharField,\n    ForeignKeyField,\n    Model,\n    SqliteDatabase,\n    TextField,\n)\n\ndb = SqliteDatabase(\n    \"app.db\",\n    pragmas={\n        \"journal_mode\": \"wal\",\n        \"foreign_keys\": 1,\n    },\n    autoconnect=False,\n)\n\nclass BaseModel(Model):\n    class Meta:\n        database = db\n\nclass User(BaseModel):\n    username = CharField(unique=True)\n\nclass Note(BaseModel):\n    user = ForeignKeyField(User, backref=\"notes\", on_delete=\"CASCADE\")\n    body = TextField()\n\ndb.connect()\ndb.create_tables([User, Note])\n```\n\nWhy this shape:\n\n- `autoconnect=False` is safer for explicit connection handling.\n- SQLite should usually enable `foreign_keys`.\n- A shared `BaseModel` keeps `Meta.database` in one place.\n\n### Configure from a database URL\n\nUse `playhouse.db_url.connect()` when config comes from an environment variable:\n\n```python\nimport os\n\nfrom playhouse.db_url import connect\n\nDATABASE_URL = os.environ[\"DATABASE_URL\"]\ndb = connect(DATABASE_URL)\n```\n\nThis supports URLs such as:\n\n- `sqlite:///app.db`\n- `postgresql://user:pass@localhost:5432/app`\n- `mysql://user:pass@localhost:3306/app`\n\n### Delay binding until runtime\n\nIf the database is chosen later, use `DatabaseProxy`:\n\n```python\nfrom peewee import DatabaseProxy, Model, PostgresqlDatabase, SqliteDatabase\n\ndatabase_proxy = DatabaseProxy()\n\nclass BaseModel(Model):\n    class Meta:\n        database = database_proxy\n\ndef init_db(testing: bool) -> None:\n    if testing:\n        database_proxy.initialize(SqliteDatabase(\":memory:\"))\n    else:\n        database_proxy.initialize(PostgresqlDatabase(\"app\"))\n```\n\n## Define Models\n\n```python\nimport datetime\n\nfrom peewee import (\n    AutoField,\n    CharField,\n    DateTimeField,\n    ForeignKeyField,\n    Model,\n    TextField,\n)\n\nclass BaseModel(Model):\n    class Meta:\n        database = db\n\nclass Blog(BaseModel):\n    id = AutoField()\n    title = CharField(max_length=200, unique=True)\n    created_at = DateTimeField(default=datetime.datetime.utcnow)\n\nclass Entry(BaseModel):\n    id = AutoField()\n    blog = ForeignKeyField(Blog, backref=\"entries\", on_delete=\"CASCADE\")\n    title = CharField(max_length=200)\n    content = TextField()\n    created_at = DateTimeField(default=datetime.datetime.utcnow)\n```\n\nUse `AutoField` for the normal integer primary key case. Use `ForeignKeyField(..., backref=...)` so reverse access is predictable.\n\n## Core Query Patterns\n\n### Create rows\n\n```python\nblog = Blog.create(title=\"Engineering\")\n\nentry = Entry.create(\n    blog=blog,\n    title=\"Peewee 4 notes\",\n    content=\"Ship the migration first.\",\n)\n```\n\n### Select and filter\n\n```python\nquery = (\n    Entry.select(Entry, Blog)\n    .join(Blog)\n    .where(Blog.title == \"Engineering\")\n    .order_by(Entry.created_at.desc())\n)\n\nfor entry in query:\n    print(entry.title, entry.blog.title)\n```\n\n### Update and delete\n\n```python\n(\n    Entry.update(content=\"Updated content\")\n    .where(Entry.id == entry.id)\n    .execute()\n)\n\n(\n    Entry.delete()\n    .where(Entry.created_at < datetime.datetime(2026, 1, 1))\n    .execute()\n)\n```\n\n### Bulk inserts and upserts\n\n```python\nrows = [\n    {\"title\": \"A\"},\n    {\"title\": \"B\"},\n]\n\nBlog.insert_many(rows).execute()\n\n(\n    Blog.insert(title=\"Engineering\")\n    .on_conflict_ignore()\n    .execute()\n)\n```\n\nUse bulk queries for large writes instead of looping over `.create()`.\n\n## Transactions\n\nWrap multi-step writes in `db.atomic()`:\n\n```python\nwith db.atomic():\n    blog = Blog.create(title=\"Infra\")\n    Entry.create(blog=blog, title=\"Runbook\", content=\"...\")\n```\n\nNested `atomic()` blocks use savepoints when the backend supports them.\n\n## Async Support In 4.x\n\nPeewee 4 adds first-class asyncio support under `playhouse.pwasyncio`.\n\n```python\nimport asyncio\n\nfrom peewee import CharField\nfrom playhouse.pwasyncio import AsyncSqliteDatabase\n\ndb = AsyncSqliteDatabase(\"app.db\")\n\nclass User(db.Model):\n    username = CharField(unique=True)\n\nasync def main() -> None:\n    async with db:\n        await db.create_tables([User])\n\n        user = await User.create(username=\"huey\")\n        fetched = await User.get(User.username == \"huey\")\n        print(user.id, fetched.username)\n\n        rows = await db.run(User.select().where(User.username.startswith(\"h\")))\n        print([row.username for row in rows])\n\nasyncio.run(main())\n```\n\nUse the async APIs consistently inside async code. Do not mix synchronous query execution into an async request path.\n\n## Schema Migrations\n\nUse `playhouse.migrate` for straightforward column and table changes:\n\n```python\nfrom playhouse.migrate import SqliteMigrator, migrate\n\nmigrator = SqliteMigrator(db)\n\nwith db.atomic():\n    migrate(\n        migrator.add_column(\"entry\", \"slug\", CharField(null=True)),\n    )\n```\n\nFor larger production migrations, treat Peewee's migrator as a low-level tool and still plan rollout steps yourself.\n\n## Useful Playhouse Extensions\n\nThe official `playhouse` modules cover common production needs:\n\n- `playhouse.db_url`: parse a `DATABASE_URL` string into the right database class\n- `playhouse.pool`: pooled Postgres/MySQL/SQLite database classes\n- `playhouse.migrate`: schema migrations\n- `playhouse.shortcuts`: helpers like `model_to_dict()` and `dict_to_model()`\n- `playhouse.signals`: model lifecycle hooks when you need them\n\n## Common Pitfalls\n\n### 1. Manage connections explicitly\n\nIn web apps or workers, open a connection at request/job start and close it at the end. Do not rely on implicit autoconnect in long-running services.\n\nTypical pattern:\n\n```python\ndef handle_request() -> None:\n    db.connect(reuse_if_open=True)\n    try:\n        ...\n    finally:\n        if not db.is_closed():\n            db.close()\n```\n\n### 2. SQLite defaults are not enough by themselves\n\nIf you need enforced foreign keys in SQLite, set the pragma. Without it, deletes and cascades may not behave like Postgres.\n\n### 3. Field defaults are usually Python-side\n\nPeewee applies `default=` in Python. That does not create a database-level default constraint. Use explicit constraints if the database itself must own the default.\n\nFor mutable values, pass a callable such as `default=dict` or `default=list` on the relevant field type. Do not use `default={}` or `default=[]`.\n\n### 4. Query expressions use Peewee operators, not Python boolean operators\n\nUse:\n\n```python\nBlog.select().where((Blog.title != \"\") & (Blog.title != \"admin\"))\n```\n\nDo not use `and` / `or` inside `.where(...)`, and use `.in_(...)` instead of Python's `in`.\n\n### 5. Avoid N+1 queries\n\nWhen you know you need related rows, join or prefetch instead of lazy-loading each foreign key in a loop.\n\n```python\nfrom peewee import prefetch\n\nblogs = Blog.select()\nentries = Entry.select()\n\nfor blog in prefetch(blogs, entries):\n    print(blog.title, [entry.title for entry in blog.entries])\n```\n\n### 6. Stream large result sets\n\nNormal iteration caches rows. For large exports, use `.iterator()` and narrower row formats like `.tuples()` or `.dicts()` when you do not need model instances.\n\n```python\nquery = Entry.select(Entry.id, Entry.title).tuples().iterator()\n\nfor entry_id, title in query:\n    print(entry_id, title)\n```\n\n## Version-Sensitive Notes For 4.0.1\n\n- Peewee 4 is the major-version line documented at `docs.peewee-orm.com/en/latest/`; do not assume 3.x blog examples still match 4.x behavior.\n- The official changelog says 4.0 adds asyncio support and `psycopg3` support.\n- The 4.0.1 changelog removes `SqliteExtDatabase`; use `SqliteDatabase` instead.\n- If you find older snippets importing from legacy SQLite extension classes or third-party async wrappers, rewrite them for the built-in 4.x async modules before copying them into production code.\n\n## Official Sources\n\n- Docs root: https://docs.peewee-orm.com/en/latest/\n- Quickstart: https://docs.peewee-orm.com/en/latest/peewee/quickstart.html\n- Database config: https://docs.peewee-orm.com/en/latest/peewee/database.html\n- Querying: https://docs.peewee-orm.com/en/latest/peewee/querying.html\n- Asyncio: https://docs.peewee-orm.com/en/latest/peewee/asyncio.html\n- Playhouse extensions: https://docs.peewee-orm.com/en/latest/peewee/playhouse.html\n- Changelog: https://github.com/coleifer/peewee/blob/master/CHANGELOG.md\n- PyPI: https://pypi.org/project/peewee/\n"
  },
  {
    "path": "content/peft/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PEFT Python package guide for parameter-efficient fine-tuning, adapter loading, and adapter-based inference with Hugging Face models\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.18.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"peft,huggingface,transformers,lora,adapters,fine-tuning,ml\"\n---\n\n# PEFT Python Package Guide\n\n## Golden Rule\n\nUse `peft` to add, train, save, and load adapters on top of a separately loaded base model. Do not treat a PEFT adapter as a standalone model checkpoint unless you explicitly merge it back into the base model. As of March 12, 2026, PyPI publishes `peft 0.18.1`, while the Hugging Face stable docs are still labeled `v0.18.0`; use the stable docs for API shape and the `0.18.1` release notes for patch-level drift.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"peft==0.18.1\"\n```\n\nTypical LLM fine-tuning stack:\n\n```bash\npython -m pip install \"peft==0.18.1\" transformers accelerate torch\n```\n\nIf you are doing 4-bit or 8-bit adapter training, add quantization support explicitly:\n\n```bash\npython -m pip install \"peft==0.18.1\" transformers accelerate torch bitsandbytes\n```\n\nNotes:\n\n- The PEFT install docs still say the library is tested on Python 3.9+, but PyPI metadata for `0.18.1` requires Python 3.10 or newer. For installation constraints, prefer PyPI.\n- PEFT examples often assume recent `transformers`, `accelerate`, and `torch` versions. If an example fails unexpectedly, check dependency drift before changing the PEFT code.\n\n## Initialize A LoRA Adapter\n\nThe common workflow is:\n\n1. Load the base model with `transformers`\n2. Define a PEFT config such as `LoraConfig`\n3. Wrap the model with `get_peft_model`\n4. Train only the adapter weights\n5. Save the adapter with `save_pretrained`\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nfrom peft import LoraConfig, TaskType, get_peft_model\n\nmodel_id = \"Qwen/Qwen2.5-3B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nbase_model = AutoModelForCausalLM.from_pretrained(\n    model_id,\n    device_map=\"auto\",\n)\n\npeft_config = LoraConfig(\n    task_type=TaskType.CAUSAL_LM,\n    inference_mode=False,\n    r=16,\n    lora_alpha=32,\n    lora_dropout=0.05,\n    target_modules=[\"q_proj\", \"v_proj\"],\n)\n\nmodel = get_peft_model(base_model, peft_config)\nmodel.print_trainable_parameters()\n```\n\nNotes:\n\n- `target_modules` is model-architecture specific. Reuse a known-good example for the exact backbone you are adapting instead of assuming `q_proj` and `v_proj` exist everywhere.\n- `print_trainable_parameters()` is the fastest sanity check that PEFT actually froze the base model and only exposed adapter parameters for training.\n\n## Train And Save The Adapter\n\nAfter wrapping the model, train it with your normal training loop or `transformers.Trainer`. Save the adapter artifacts when training completes:\n\n```python\nmodel.save_pretrained(\"artifacts/my-lora-adapter\")\ntokenizer.save_pretrained(\"artifacts/my-lora-adapter\")\n```\n\nWhat gets saved:\n\n- PEFT config\n- Adapter weights\n- Optional tokenizer files if you save them separately\n\nWhat does not get saved by default:\n\n- The full base model weights\n\nThat distinction matters when you reload the adapter later.\n\n## Load An Existing Adapter For Inference\n\nThe explicit pattern is to load the base model first, then attach the adapter:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nfrom peft import PeftModel\n\nbase_model_id = \"Qwen/Qwen2.5-3B-Instruct\"\nadapter_path = \"artifacts/my-lora-adapter\"\n\ntokenizer = AutoTokenizer.from_pretrained(base_model_id)\nbase_model = AutoModelForCausalLM.from_pretrained(\n    base_model_id,\n    device_map=\"auto\",\n)\n\nmodel = PeftModel.from_pretrained(base_model, adapter_path)\nmodel.eval()\n\ninputs = tokenizer(\"Write a haiku about adapters.\", return_tensors=\"pt\").to(model.device)\noutputs = model.generate(**inputs, max_new_tokens=40)\nprint(tokenizer.decode(outputs[0], skip_special_tokens=True))\n```\n\nIf the adapter repository already contains the PEFT config that points at its base model, `AutoPeftModelForCausalLM` is the shortest load path:\n\n```python\nfrom transformers import AutoTokenizer\nfrom peft import AutoPeftModelForCausalLM\n\nadapter_repo = \"ybelkada/opt-350m-lora\"\n\nmodel = AutoPeftModelForCausalLM.from_pretrained(\n    adapter_repo,\n    device_map=\"auto\",\n)\ntokenizer = AutoTokenizer.from_pretrained(\"facebook/opt-350m\")\n```\n\nUse `PeftModel.from_pretrained(...)` when your code already manages the base model lifecycle. Use `AutoPeftModel...` when you want PEFT to reconstruct the adapted model from the adapter repository metadata. In either case, keep the tokenizer aligned with the same base model family used during fine-tuning.\n\n## Merge The Adapter Back Into The Base Model\n\nIf you need a single merged checkpoint for deployment or export, merge the adapter and unload the PEFT wrappers:\n\n```python\nfrom transformers import AutoModelForCausalLM\nfrom peft import PeftModel\n\nbase_model = AutoModelForCausalLM.from_pretrained(\"Qwen/Qwen2.5-3B-Instruct\")\nmodel = PeftModel.from_pretrained(base_model, \"artifacts/my-lora-adapter\")\n\nmerged_model = model.merge_and_unload(safe_merge=True)\nmerged_model.save_pretrained(\"artifacts/merged-model\")\n```\n\nUse merging deliberately:\n\n- It removes the adapter indirection\n- It is useful for export or serving systems that expect a normal `transformers` model\n- It gives up the flexibility of swapping adapters at runtime\n\n## Hub Authentication And Runtime Configuration\n\nPEFT commonly loads both base models and adapters from the Hugging Face Hub. For private or gated repositories, authenticate before calling `from_pretrained(...)`:\n\n```bash\n# In CI or containers\nexport HF_TOKEN=hf_your_token_here\n\n# Or in local development\nhf auth login\n```\n\nUseful environment variables:\n\n- `HF_TOKEN`: access token for private or gated Hub assets\n- `HF_HOME`: root directory for Hugging Face local state\n- `HF_HUB_CACHE`: explicit Hub cache directory\n\nPractical guidance:\n\n- In local development, `hf auth login` is usually enough.\n- In CI or containers, set `HF_TOKEN` through your secret manager instead of hard-coding credentials.\n- If a model or adapter is gated, authenticate before debugging PEFT itself. Many apparent load failures are Hub permission failures.\n\n## Common Pitfalls\n\n- `save_pretrained()` saves adapter artifacts, not a standalone base model checkpoint. Reload the compatible base model before attaching the adapter again.\n- Use `low_cpu_mem_usage=True` for adapter loading paths such as `from_pretrained()` and `load_adapter()`, not as a substitute for correctly constructing a fresh trainable adapter.\n- If you added tokens or resized embeddings during fine-tuning, recreate the same tokenizer and embedding shape before loading the adapter. The PEFT troubleshooting guide calls out embedding mismatches and `save_embedding_layers` as common fixes.\n- Mixed-precision training can break if trainable parameters stay in `float16`. PEFT 0.12.0 and newer automatically promotes adapter weights to `float32`; only disable that behavior if you understand the tradeoff.\n- Multi-package version drift is common. If examples break, check the exact installed versions of `peft`, `transformers`, `accelerate`, and `torch` before rewriting the code path.\n- `set_adapter()` makes the activated adapter trainable unless you set `inference_mode=True`. That matters when you load multiple adapters and expect inference-only behavior.\n- The stable docs are still versioned as `v0.18.0`. For `0.18.1`, use the same API docs but also read the `v0.18.1` release notes for patch fixes.\n\n## Version-Sensitive Notes For 0.18.x\n\n- `0.18.0` dropped Python 3.9 support and added compatibility work for `transformers v5`.\n- `0.18.1` is a patch release on top of that line. The official release notes call out fixes for upcoming `transformers v5` special cases, an AMD ROCm issue in `BoneLayer`, and a regression that incorrectly required `transformers>=4.52`.\n- Because the docs site stable branch is still `v0.18.0`, patch-level behavior that changed in `0.18.1` may only be visible in release notes or source history.\n\n## Official Sources\n\n- PEFT docs root: `https://huggingface.co/docs/peft/index`\n- PEFT installation guide: `https://huggingface.co/docs/peft/installation`\n- PEFT quicktour: `https://huggingface.co/docs/peft/quicktour`\n- PEFT troubleshooting: `https://huggingface.co/docs/peft/developer_guides/troubleshooting`\n- PEFT model merging guide: `https://huggingface.co/docs/peft/developer_guides/model_merging`\n- PEFT package reference for model loading: `https://huggingface.co/docs/peft/package_reference/auto_class`\n- Hugging Face Hub environment variables: `https://huggingface.co/docs/huggingface_hub/package_reference/environment_variables`\n- Hugging Face Hub authentication: `https://huggingface.co/docs/huggingface_hub/package_reference/authentication`\n- Hugging Face Hub CLI auth command: `https://huggingface.co/docs/huggingface_hub/package_reference/cli`\n- PyPI package page: `https://pypi.org/project/peft/`\n- PEFT `v0.18.0` release notes: `https://github.com/huggingface/peft/releases/tag/v0.18.0`\n- PEFT `v0.18.1` release notes: `https://github.com/huggingface/peft/releases/tag/v0.18.1`\n"
  },
  {
    "path": "content/pendulum/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pendulum Python datetime library for timezone-aware datetimes, parsing, formatting, durations, intervals, and test time travel\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pendulum,python,datetime,timezones,duration,interval,testing\"\n---\n\n# Pendulum Python Package Guide\n\n## Golden Rule\n\nUse `pendulum` when you need timezone-aware datetime handling, humanized diffs, or interval and duration helpers in Python. Keep timezone behavior explicit with `tz=...`, prefer IANA timezone names, and treat the official docs site as a generic 3.x reference rather than a patch-specific `3.2.0` manual.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"pendulum==3.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pendulum==3.2.0\"\npoetry add \"pendulum==3.2.0\"\n```\n\nInstall the optional test helpers when you need time travel in tests:\n\n```bash\npython -m pip install \"pendulum[test]==3.2.0\"\npoetry add \"pendulum[test]==3.2.0\"\n```\n\n## Initialization And Basic Setup\n\nPendulum has no auth or service configuration layer. The main setup decisions are:\n\n- which timezone you want to use by default in your code paths\n- whether you need localized formatting or `diff_for_humans()`\n- whether your test environment needs the `test` extra\n\nBasic creation patterns:\n\n```python\nimport pendulum\n\nutc_now = pendulum.now(\"UTC\")\nlocal_now = pendulum.now()\n\nmeeting = pendulum.datetime(2026, 3, 12, 9, 30, tz=\"America/Los_Angeles\")\nlocal_meeting = pendulum.local(2026, 3, 12, 9, 30)\n\nprint(utc_now)\nprint(meeting.timezone_name)\nprint(local_meeting.timezone_name)\n```\n\nImportant defaults:\n\n- `pendulum.datetime(...)` defaults to `UTC` unless you pass `tz=...`\n- `pendulum.now()` uses the current local timezone unless you pass a timezone\n- the `tz` argument is keyword-only\n- timezone strings should be IANA names like `UTC`, `Europe/Paris`, or `America/New_York`\n\n## Core Usage\n\n### Create, convert, and normalize datetimes\n\n```python\nimport pendulum\n\nstart = pendulum.datetime(2026, 3, 12, 9, 30, tz=\"America/Los_Angeles\")\nparis = start.in_timezone(\"Europe/Paris\")\n\n# set(tz=...) replaces timezone info without converting the instant\nretagged = start.set(tz=\"UTC\")\n\nprint(start.to_iso8601_string())\nprint(paris.to_iso8601_string())\nprint(retagged.to_iso8601_string())\n```\n\nUse `in_timezone()` or `in_tz()` when you want a real conversion. Use `set(tz=...)` only when you intentionally want to retag the same wall-clock value.\n\nPendulum normalizes DST-transition timestamps for the given timezone:\n\n```python\nimport pendulum\n\ndt = pendulum.datetime(2013, 3, 31, 2, 30, tz=\"Europe/Paris\")\nprint(dt)  # normalized to the actual valid time in that zone\n```\n\n### Parse strings and timestamps\n\n```python\nimport pendulum\n\ndt1 = pendulum.parse(\"2026-03-12T17:45:00Z\")\ndt2 = pendulum.parse(\"2026-03-12 17:45:00\", tz=\"America/New_York\")\ndt3 = pendulum.from_format(\"2026-03-12 17\", \"YYYY-MM-DD HH\", tz=\"UTC\")\ndt4 = pendulum.from_timestamp(1_773_343_500, tz=\"UTC\")\n\nprint(dt1, dt2, dt3, dt4)\n```\n\nUse `from_format()` when the input is not a clean ISO 8601 or RFC 3339 string. `parse()` is strict by default:\n\n```python\nimport pendulum\n\nparsed = pendulum.parse(\"31-01-01\", strict=False)\ndate_only = pendulum.parse(\"2026-03-12\", exact=True)\ntime_only = pendulum.parse(\"17:45:00\", exact=True)\n\nprint(parsed)\nprint(type(date_only).__name__)\nprint(type(time_only).__name__)\n```\n\n`strict=False` allows a fallback parser for ambiguous non-standard strings. `exact=True` returns `Date` or `Time` when the input represents only that type.\n\n### Format and localize output\n\n```python\nimport pendulum\n\ndt = pendulum.datetime(2026, 3, 12, 17, 45, tz=\"UTC\")\n\nprint(dt.to_datetime_string())\nprint(dt.format(\"dddd DD MMMM YYYY HH:mm:ss\", locale=\"fr\"))\nprint(dt.diff_for_humans(locale=\"de\"))\n```\n\nIf you need consistent locale output across a process, you can set a global locale:\n\n```python\nimport pendulum\n\npendulum.set_locale(\"en\")\n```\n\nPrefer per-call `locale=...` when writing library code or test suites to avoid global state surprises.\n\n### Arithmetic, durations, and intervals\n\n```python\nimport pendulum\n\nstart = pendulum.datetime(2026, 3, 12, 9, 30, tz=\"UTC\")\nend = start.add(days=3, hours=6)\n\ninterval = end - start\nduration = pendulum.duration(days=2, hours=5, minutes=30)\n\nprint(start.add(weeks=1))\nprint(start.start_of(\"day\"))\nprint(end.diff_for_humans(start, absolute=True))\nprint(interval.in_hours())\nprint(duration.in_words())\n```\n\nWhen you subtract two `DateTime` values or call `diff()`, Pendulum returns an `Interval`, which tracks the start and end datetimes. Many arithmetic operations on an `Interval` return a `Duration` instead.\n\nIterating over an interval:\n\n```python\nimport pendulum\n\nstart = pendulum.datetime(2026, 3, 1, tz=\"UTC\")\nend = pendulum.datetime(2026, 3, 5, tz=\"UTC\")\ninterval = pendulum.interval(start, end)\n\nfor dt in interval.range(\"days\"):\n    print(dt.to_date_string())\n```\n\n### Interop with standard `datetime`\n\n```python\nfrom datetime import datetime\nimport pendulum\n\nnative = datetime(2026, 3, 12, 17, 45)\ndt = pendulum.instance(native)\n\nprint(dt)\nprint(isinstance(dt, datetime))\n```\n\nPendulum objects are subclasses of the standard library date/time types, but some integrations still do strict type checks.\n\n## Configuration Notes\n\n- There is no API key, network auth, or credentials setup.\n- Timezone identifiers come from the IANA timezone database.\n- `pendulum.datetime()` defaults to `UTC`; `pendulum.local()` and `pendulum.now()` are the local-timezone entry points.\n- The `test` extra is required for `travel()`, `travel_to()`, and `travel_back()`.\n- Prefer per-call `locale=...` over global `pendulum.set_locale()` unless your process really wants one locale everywhere.\n\n## Testing With Time Travel\n\nPendulum 3.x test helpers live behind the optional `test` extra:\n\n```python\nimport pendulum\n\nwith pendulum.travel(minutes=5, freeze=True):\n    print(pendulum.now())\n\ntarget = pendulum.datetime(2026, 3, 12, 9, 30, tz=\"UTC\")\npendulum.travel_to(target, freeze=True)\nprint(pendulum.now())\npendulum.travel_back()\n```\n\nWithout `freeze=True`, the clock keeps ticking from the traveled point. Use the context-manager form when possible so cleanup is automatic.\n\n## Common Pitfalls\n\n- `tz` is keyword-only. `pendulum.datetime(2026, 3, 12, \"UTC\")` is wrong; use `tz=\"UTC\"`.\n- `set(tz=...)` is not the same as `in_timezone(...)`. `set()` retags the timezone, while `in_timezone()` converts the instant.\n- `parse()` is strict for non-standard inputs. For custom formats, prefer `from_format()`, or use `strict=False` only when fallback parsing is acceptable.\n- `pendulum.datetime(...)` defaults to UTC, not local time. Agents often assume local time and silently shift schedules.\n- Locale can be global state. `pendulum.set_locale()` affects later humanized output in the same process.\n- Some libraries and database adapters use `type()` checks instead of `isinstance()`. The upstream docs call out `sqlite3`, `mysqlclient`, `PyMySQL`, and Django as cases where adapters or native conversion may be needed.\n- Interval arithmetic can change type. If you need start/end-aware behavior after math, confirm you still have an `Interval` and not a plain `Duration`.\n\n## Version-Sensitive Notes For 3.2.0\n\n- The official docs site currently presents itself as \"Version 3.0\" and a generic `3.x` reference, but PyPI publishes `pendulum 3.2.0`. Treat the site as the maintained 3.x manual, not a patch-level release mirror.\n- The published package metadata and the repository `pyproject.toml` declare `Python >=3.9`. The current repository README says \"Supports Python 3.10 and newer\", so prefer the published package metadata when checking install compatibility for `3.2.0`.\n- Pendulum 3.x removed the old Pendulum 2 testing helpers `set_test_now()` and `test()`. Use `travel()`, `travel_to()`, and `travel_back()` instead.\n- The 3.x line uses `zoneinfo.ZoneInfo` internally rather than the old `pytz`-style timezone model. Avoid porting older blog examples that assume pre-3.x internals.\n- The upstream changelog currently documents the 3.0.0 and 3.1.0 changes, but it does not yet describe a dedicated `3.2.0` section. For `3.2.0`, rely on the docs, PyPI metadata, and the published package itself instead of assuming a richer patch-note page exists.\n"
  },
  {
    "path": "content/petl/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"petl Python package guide for lazy ETL pipelines over CSV, Excel, databases, pandas, and remote files\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.7.17\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"petl,python,etl,csv,excel,sql,pandas,data\"\n---\n\n# petl Python Package Guide\n\n## Golden Rule\n\nUse `petl` as a lazy table-transformation toolkit, not as an in-memory dataframe library. Start with `import petl as etl`, read from a concrete source such as CSV, Excel, or a database query, apply explicit transforms, then materialize with `look()`, `tocsv()`, `toxlsx()`, `todb()`, or another sink. Convert types deliberately because text-based sources arrive as strings.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"petl==1.7.17\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"petl==1.7.17\"\npoetry add \"petl==1.7.17\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"petl[db,pandas,remote,xlsx]==1.7.17\"\n```\n\nAvailable extras on PyPI include `avro`, `db`, `pandas`, `remote`, `xls`, `xlsx`, `xml`, and `all`.\n\nUse extras only for the formats you need:\n\n- `db`: database helpers; you still need the actual DB driver and in some cases SQLAlchemy-compatible tooling\n- `pandas`: dataframe bridge helpers\n- `remote`: remote URLs through `fsspec`; install provider packages such as `s3fs` when the protocol needs them\n- `xlsx`: modern Excel `.xlsx` support via `openpyxl`\n- `xls`: legacy Excel `.xls` support\n\n## Initialize And Mental Model\n\n`petl` works with table objects that are usually lazy. A table describes a pipeline; it does not necessarily read all rows immediately.\n\nTypical workflow:\n\n1. Read from a source such as `fromcsv()`, `fromxlsx()`, `fromdb()`, or `fromdataframe()`\n2. Apply transforms such as `cut()`, `select()`, `convert()`, `addfield()`, `sort()`, or joins\n3. Materialize into a sink such as `tocsv()`, `toxlsx()`, `todb()`, `todataframe()`, or a preview such as `look()`\n\nThe root import already exposes the fluent interface, so modern code normally uses `import petl as etl`.\n\n## Core Usage\n\n### Build a CSV pipeline\n\n```python\nimport petl as etl\n\ntable = (\n    etl\n    .fromcsv(\"orders.csv\")\n    .convert(\"amount\", float)\n    .addfield(\"is_large\", lambda row: row.amount >= 1000)\n    .cut(\"order_id\", \"customer_id\", \"amount\", \"is_large\")\n)\n\ntable.tocsv(\"orders-normalized.csv\")\n```\n\nThis is the common pattern for file-to-file ETL:\n\n- read with `fromcsv()`\n- normalize types with `convert()`\n- derive new columns with `addfield()`\n- project only needed fields with `cut()`\n- write with `tocsv()`\n\n### Join two datasets\n\n```python\nimport petl as etl\n\norders = etl.fromcsv(\"orders.csv\")\ncustomers = etl.fromcsv(\"customers.csv\")\n\nenriched = etl.join(orders, customers, key=\"customer_id\")\n\nprint(etl.look(enriched))\n```\n\nUse `join()` when both sides can have multiple matching rows. Use `lookupjoin()` only when taking the first matching row from the right-hand table is acceptable.\n\n### Read from a database query\n\n```python\nimport sqlite3\nimport petl as etl\n\nconn = sqlite3.connect(\"app.db\")\n\nusers = etl.fromdb(conn, \"SELECT id, email, created_at FROM users\")\nrecent = users.cut(\"id\", \"email\")\n\nprint(etl.look(recent))\n```\n\nFor non-SQLite backends, install the appropriate DB driver. If you need SQLAlchemy-backed database helpers, check the version note below about SQLAlchemy 2.x support.\n\n### Bridge to pandas\n\n```python\nimport pandas as pd\nimport petl as etl\n\ndf = pd.read_csv(\"orders.csv\")\ntable = etl.fromdataframe(df)\n\nclean = table.convert(\"amount\", float)\nresult_df = etl.todataframe(clean)\n```\n\nUse `petl` when you want deterministic extract/transform/load steps around files and databases, and convert to pandas only when you actually need dataframe operations downstream.\n\n## Configuration And Auth\n\n`petl` has no package-level authentication system and almost no global runtime configuration. Configuration happens at the integration boundary:\n\n- file inputs/outputs: local paths or URLs\n- remote filesystems: `fsspec` plus backend-specific packages and credentials\n- databases: DB-API connection objects, connection strings, or SQLAlchemy-compatible configuration depending on the helper you use\n- Excel/format support: install the optional dependency for the format before calling the corresponding loader or writer\n\nExamples of external auth/config that `petl` relies on rather than manages:\n\n- S3 URLs usually rely on `fsspec` plus `s3fs`, with AWS credentials coming from the normal AWS environment or config chain\n- database access relies on the driver or engine configuration you provide\n- Excel readers/writers rely on packages such as `openpyxl`, `xlrd`, or `xlwt`\n\n## Common Pitfalls\n\n- CSV and other text sources yield strings by default. Call `convert()` for numeric, date, boolean, or structured fields before doing real logic.\n- Pipelines are lazy. Re-iterating a table can re-read the source or recompute the transform chain. Use `cache()` when you need to materialize an intermediate table once and reuse it.\n- `look()` is only a preview. It is useful for inspection, not as proof that the full pipeline has already run.\n- `lookupjoin()` keeps only the first matching row from the right-hand side. Do not use it when you need full many-to-one or many-to-many semantics.\n- Some sources infer headers or schema from the data. When reproducibility matters, define headers and type conversion explicitly instead of relying on inference.\n- Remote URLs are not automatic just because the path starts with `s3://` or similar. You need the `remote` extra or equivalent `fsspec` install, plus any provider-specific package.\n- Database examples on the web often omit the driver dependency. `petl` does not replace `psycopg`, `pymysql`, `pyodbc`, or other backend drivers.\n- For large files, be careful with transforms that force eager materialization or repeated scans. Keep the pipeline streaming where possible and materialize only when necessary.\n\n## Version-Sensitive Notes\n\n- `1.x` uses `import petl as etl` as the normal entry point. Older imports such as `petl.fluent` and `petl.interactive` were retired long ago and should not appear in new code.\n- Since the `1.0` line, text I/O was unified around `fromcsv()` and `tocsv()`. Legacy helpers such as `fromucsv()` and `toucsv()` are obsolete.\n- Remote filesystem support was added through `fsspec` in the `1.6` line. Prefer the current remote-path approach instead of older ad hoc remote file recipes.\n- The stable changelog notes that `1.7.14` does not support SQLAlchemy `2.0`. If your pipeline uses SQLAlchemy-mediated DB helpers, pin SQLAlchemy `<2` unless you have verified newer compatibility in the repository.\n- The docs also note that `fromxlsx(read_only=True)` can truncate some LibreOffice-generated `.xlsx` files at `65536` rows. Leave `read_only=False` unless you have a confirmed memory or performance reason to change it.\n- The `1.3` line changed `fromxlsx()` offset arguments from `row_offset` and `column_offset` to `min_row` and `min_col`. Old blog posts still use the removed names.\n\n## Official Sources\n\n- PyPI package metadata and release history: `https://pypi.org/project/petl/`\n- Maintainer repository: `https://github.com/petl-developers/petl`\n- Maintainer docs: `https://petl.readthedocs.io/latest/`\n- Stable changelog: `https://petl.readthedocs.io/stable/changes.html`\n"
  },
  {
    "path": "content/phidata/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"phidata Python package guide for building agents, tools, knowledge bases, and playground apps\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.7.10\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"phidata,agents,llm,rag,playground,python\"\n---\n\n# phidata Python Package Guide\n\n## What This Covers\n\nThis guide is for the PyPI package `phidata` version `2.7.10`.\n\n- Install name: `phidata`\n- Primary import namespace: `phi`\n- Docs root: `https://docs.phidata.com/`\n- Package registry: `https://pypi.org/project/phidata/`\n\n`phidata` is the pre-Agno package line for building agents, teams, tools, knowledge-backed assistants, and local playground apps. The official repo now points new users to Agno, but projects pinned to `phidata==2.7.10` should still use the `phidata` package and `phi.*` imports documented here.\n\n## Install\n\nInstall the pinned package plus the model provider you plan to call:\n\n```bash\npip install phidata==2.7.10 openai\n```\n\nCommon optional dependencies from the official examples:\n\n```bash\npip install duckduckgo-search\npip install lancedb tantivy pypdf sqlalchemy\npip install \"fastapi[standard]\"\n```\n\nPyPI also exposes extras such as `aws`, `docker`, `k8s`, `server`, and `all` if you want a broader integration bundle, but most projects should install only the provider and tool packages they actually use.\n\n## Minimal Agent\n\nSet your model provider credentials first:\n\n```bash\nexport OPENAI_API_KEY=your-key\n```\n\nBasic synchronous agent:\n\n```python\nfrom phi.agent import Agent\nfrom phi.model.openai import OpenAIChat\n\nagent = Agent(\n    model=OpenAIChat(id=\"gpt-4o\"),\n    markdown=True,\n)\n\nagent.print_response(\"Explain how retries work in HTTP clients.\", stream=True)\n```\n\nWhat matters:\n\n- Use `Agent`, not the older `Assistant` class.\n- Pass `model=...`, not the older `llm=...` argument.\n- The package does not ship model-provider SDKs for you; install `openai`, `anthropic`, or other provider packages separately.\n\n## Add Tools\n\nOfficial examples use tool objects that the agent can call during a run:\n\n```python\nfrom phi.agent import Agent\nfrom phi.model.openai import OpenAIChat\nfrom phi.tools.duckduckgo import DuckDuckGo\n\nagent = Agent(\n    model=OpenAIChat(id=\"gpt-4o\"),\n    tools=[DuckDuckGo()],\n    instructions=[\"Cite sources in plain language.\"],\n    show_tool_calls=True,\n    markdown=True,\n)\n\nagent.print_response(\"What changed in Python 3.12?\", stream=True)\n```\n\nPractical notes:\n\n- If a tool import fails, you are usually missing a separate dependency such as `duckduckgo-search`.\n- `show_tool_calls=True` is useful while iterating because it makes tool execution visible in logs and terminal output.\n- Keep instructions short; the framework already handles tool orchestration.\n\n## Add Knowledge / RAG\n\nThe docs show knowledge bases backed by a vector database. A common setup uses `PDFUrlKnowledgeBase` with LanceDB:\n\n```python\nfrom phi.agent import Agent\nfrom phi.knowledge.pdf import PDFUrlKnowledgeBase\nfrom phi.model.openai import OpenAIChat\nfrom phi.vectordb.lancedb import LanceDb, SearchType\n\nknowledge_base = PDFUrlKnowledgeBase(\n    urls=[\"https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf\"],\n    vector_db=LanceDb(\n        table_name=\"recipes\",\n        uri=\"tmp/lancedb\",\n        search_type=SearchType.vector,\n    ),\n)\n\nknowledge_base.load(upsert=True)\n\nagent = Agent(\n    model=OpenAIChat(id=\"gpt-4o\"),\n    knowledge=knowledge_base,\n    search_knowledge=True,\n    markdown=True,\n)\n\nagent.print_response(\"How do I make green curry?\", stream=True)\n```\n\nUse this pattern when you need retrieval over PDFs or other indexed data instead of stuffing raw documents into the prompt.\n\n## Persist Sessions And Memory\n\nUse storage when you want resumable sessions or chat history across runs:\n\n```python\nfrom phi.agent import Agent\nfrom phi.model.openai import OpenAIChat\nfrom phi.storage.agent.sqlite import SqlAgentStorage\n\nstorage = SqlAgentStorage(\n    table_name=\"agent_sessions\",\n    db_file=\"tmp/agents.db\",\n)\n\nagent = Agent(\n    model=OpenAIChat(id=\"gpt-4o\"),\n    storage=storage,\n    add_history_to_messages=True,\n    markdown=True,\n)\n```\n\nThis is the simplest official persistence path for local development. SQLite is fine for local apps; switch storage backends only when you need shared or remote state.\n\n## Run A Local Playground App\n\nFor a browser UI around one or more agents:\n\n```python\nfrom phi.agent import Agent\nfrom phi.model.openai import OpenAIChat\nfrom phi.playground import Playground, serve_playground_app\n\nagent = Agent(\n    name=\"assistant\",\n    model=OpenAIChat(id=\"gpt-4o\"),\n    markdown=True,\n)\n\napp = Playground(agents=[agent]).get_app()\n\nif __name__ == \"__main__\":\n    serve_playground_app(\"playground:app\", reload=True)\n```\n\nInstall the serving dependencies first:\n\n```bash\npip install \"fastapi[standard]\" sqlalchemy\n```\n\n## Config And Auth\n\nThere are two auth layers to keep straight:\n\n1. Model/provider auth.\n   Set the environment variables required by the provider you instantiate, such as `OPENAI_API_KEY`.\n\n2. Phidata platform auth.\n   `phi auth` and `PHI_API_KEY` are only needed for Phidata-hosted features such as the hosted playground or monitoring. They are not required for a plain local `Agent(...)` that only calls a model provider.\n\nIf code works in a local script but the playground or monitoring flow fails, you are usually missing the Phidata platform login rather than the model key.\n\n## Common Pitfalls\n\n- Install/import mismatch: the package is `phidata`, but most imports start with `phi.`.\n- Missing provider package: `phidata` does not replace `openai`, `anthropic`, or other model SDKs.\n- Missing tool dependencies: toolkit examples often require extra packages that are not installed automatically.\n- Old examples from blogs: many older snippets use `Assistant`, `llm=`, or `knowledge_base=`. For `2.7.10`, prefer `Agent`, `model=`, and `knowledge=`.\n- Assuming the docs rename means the package renamed too: the repo now says \"Phidata is now Agno\", but the pinned PyPI package for this entry is still `phidata==2.7.10`.\n\n## Version-Sensitive Notes For 2.7.10\n\nThe official migration guide for `2.5.0` is still relevant to `2.7.10` because the newer package line keeps those renamed APIs:\n\n- `Assistant` was renamed to `Agent`.\n- `llm` was renamed to `model`.\n- `knowledge_base` was renamed to `knowledge`.\n- `run()` examples were updated toward `print_response()` for terminal-style usage.\n\nWhen working on an older codebase, scan for those names first before assuming the code and docs are aligned.\n\n## Official Sources\n\n- Docs root: https://docs.phidata.com/\n- Agent docs: https://docs.phidata.com/agents\n- Knowledge docs: https://docs.phidata.com/agents/knowledge\n- Playground docs: https://docs.phidata.com/playground/introduction\n- Migration guide: https://docs.phidata.com/migration/2-5-0\n- PyPI package page: https://pypi.org/project/phidata/\n- Official repository: https://github.com/bz-e/phidata\n"
  },
  {
    "path": "content/phonenumbers/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"phonenumbers package guide for parsing, validating, formatting, and extracting international phone numbers in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.25\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"phonenumbers,python,phone-numbers,libphonenumber,validation,formatting\"\n---\n\n# phonenumbers Python Package Guide\n\n## Install\n\nUse a virtual environment and pin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"phonenumbers==9.0.25\"\n```\n\nThere is no API key, service account, or network initialization step. `phonenumbers` is a local metadata-driven library.\n\n## Runtime Setup\n\nNo environment variables are required.\n\nImport the top-level package and the format enum you need:\n\n```python\nimport phonenumbers\nfrom phonenumbers import NumberParseException, PhoneNumberFormat\n```\n\nFor user-entered national numbers, pass a default region such as `\"US\"` or `\"GB\"`. For numbers already in international form with a leading `+`, pass `None`.\n\n## Parse, Validate, And Normalize\n\nUse `parse()` first, then check both `is_possible_number()` and `is_valid_number()` before storing or acting on the result.\n\n```python\nfrom typing import Optional\n\nimport phonenumbers\nfrom phonenumbers import NumberParseException, PhoneNumberFormat\n\n\ndef normalize_phone_number(raw_number: str, region: Optional[str] = \"US\") -> str:\n    try:\n        number = phonenumbers.parse(raw_number, region)\n    except NumberParseException as exc:\n        raise ValueError(f\"Could not parse phone number: {exc}\") from exc\n\n    if not phonenumbers.is_possible_number(number):\n        raise ValueError(\"Phone number has an impossible length or structure\")\n\n    if not phonenumbers.is_valid_number(number):\n        raise ValueError(\"Phone number is not a valid assigned number\")\n\n    return phonenumbers.format_number(number, PhoneNumberFormat.E164)\n\n\nprint(normalize_phone_number(\"(650) 253-0000\", \"US\"))\nprint(normalize_phone_number(\"+44 20 8366 1177\", None))\n```\n\nUse E.164 as the canonical stored form when you need a stable database value.\n\n## Format For Display\n\n`phonenumbers` can render the same parsed number in different formats depending on where you display it.\n\n```python\nimport phonenumbers\nfrom phonenumbers import PhoneNumberFormat\n\nnumber = phonenumbers.parse(\"+12025550123\", None)\n\nprint(phonenumbers.format_number(number, PhoneNumberFormat.E164))\nprint(phonenumbers.format_number(number, PhoneNumberFormat.INTERNATIONAL))\nprint(phonenumbers.format_number(number, PhoneNumberFormat.NATIONAL))\nprint(phonenumbers.format_number(number, PhoneNumberFormat.RFC3966))\n```\n\nUse `PhoneNumberFormat.E164` for storage and APIs, and `NATIONAL` or `INTERNATIONAL` for UI depending on audience.\n\n## Extract Numbers From Text\n\nUse `PhoneNumberMatcher` when you need to scan free-form text, emails, or logs for phone numbers.\n\n```python\nimport phonenumbers\nfrom phonenumbers import PhoneNumberFormat\n\ntext = \"Call the US office at (650) 253-0000 or the UK office at +44 20 8366 1177.\"\n\nfor match in phonenumbers.PhoneNumberMatcher(text, \"US\"):\n    print(match.raw_string)\n    print(phonenumbers.format_number(match.number, PhoneNumberFormat.E164))\n```\n\nThe matcher still needs a default region for numbers written without an international prefix.\n\n## Format As The User Types\n\nUse `AsYouTypeFormatter` for input widgets that progressively format a number as digits arrive.\n\n```python\nfrom phonenumbers import AsYouTypeFormatter\n\nformatter = AsYouTypeFormatter(\"US\")\n\nfor digit in \"6502530000\":\n    print(formatter.input_digit(digit))\n```\n\n## Geocoding, Carrier, And Time Zone Helpers\n\nThe full `phonenumbers` package includes helper modules for offline metadata lookups.\n\n```python\nimport phonenumbers\nfrom phonenumbers import carrier, geocoder, timezone\n\nnumber = phonenumbers.parse(\"+442083661177\", None)\n\nprint(geocoder.description_for_number(number, \"en\"))\nprint(carrier.name_for_number(number, \"en\"))\nprint(timezone.time_zones_for_number(number))\n```\n\n## Common Pitfalls\n\n- `parse()` raises `NumberParseException` for malformed input, missing region context, and other parse failures. Catch it at the boundary where raw user input enters your app.\n- `is_possible_number()` is only a structural check. Use `is_valid_number()` as well before treating a number as real.\n- National numbers need a region hint. `phonenumbers.parse(\"020 8366 1177\", None)` is not the same as `phonenumbers.parse(\"020 8366 1177\", \"GB\")`.\n- Store normalized E.164 strings if you need deduplication, unique constraints, or API interoperability.\n- If you need `geocoder`, `carrier`, or `timezone`, make sure you installed `phonenumbers`, not the lighter `phonenumberslite` package.\n- Numbering metadata changes over time. If a recently assigned number fails validation unexpectedly, upgrade the package before adding custom workarounds.\n"
  },
  {
    "path": "content/picocolors/docs/picocolors/javascript/DOC.md",
    "content": "---\nname: picocolors\ndescription: \"Minimal ANSI color formatting helpers for Node.js CLIs and browser-safe string formatting\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"picocolors,cli,terminal,ansi,colors\"\n---\n\n# picocolors for JavaScript\n\n`picocolors` is a tiny formatting library for terminal output. It does not create a client, open a connection, or require authentication — you import it and call formatter functions directly.\n\n## Install\n\n```bash\nnpm install picocolors\n```\n\nThe published package includes CommonJS entrypoints, TypeScript declarations, and a browser build.\n\n## Import and basic usage\n\nESM:\n\n```javascript\nimport pc from \"picocolors\";\n\nconsole.log(pc.green(\"Build succeeded\"));\nconsole.log(pc.bold(pc.blue(\"server started\")));\nconsole.log(pc.yellow(`warning: ${pc.underline(\"check config\")}`));\n```\n\nCommonJS:\n\n```javascript\nconst pc = require(\"picocolors\");\n\nconsole.log(pc.red(\"Build failed\"));\n```\n\nNested formatting is supported:\n\n```javascript\nimport pc from \"picocolors\";\n\nconsole.log(pc.green(`How are ${pc.italic(\"you\")} doing?`));\n```\n\n## Initialization and color control\n\nThe default export includes two things you will use most often:\n\n- `pc.isColorSupported` — boolean flag computed when the module loads\n- `pc.createColors(enabled?)` — returns a formatter set with colors enabled or disabled\n\nIf you want explicit control instead of environment-based auto-detection, create your own formatter set:\n\n```javascript\nimport pc from \"picocolors\";\n\nconst colors = pc.createColors(process.stdout.isTTY);\n\nconsole.log(colors.cyan(\"Starting CLI\"));\nconsole.log(colors.bold(\"Ready\"));\n```\n\nDisable colors completely:\n\n```javascript\nimport pc from \"picocolors\";\n\nconst colors = pc.createColors(false);\n\nconsole.log(colors.red(\"This stays plain text\"));\n```\n\nForce colors on:\n\n```javascript\nimport pc from \"picocolors\";\n\nconst colors = pc.createColors(true);\n\nconsole.log(colors.green(\"Always emit ANSI colors\"));\n```\n\n## Environment variables and CLI flags\n\nThe default `pc.isColorSupported` value is controlled by process state at import time.\n\nColors are disabled when either of these is true:\n\n- `NO_COLOR` is set\n- `--no-color` appears in `process.argv`\n\nColors are enabled when colors are not disabled and any of these is true:\n\n- `FORCE_COLOR` is set\n- `--color` appears in `process.argv`\n- `process.platform === \"win32\"`\n- `process.stdout.isTTY` is truthy and `TERM !== \"dumb\"`\n- `CI` is set\n\nExamples for a Node CLI:\n\n```bash\nNO_COLOR=1 node cli.js\nFORCE_COLOR=1 node cli.js\nnode cli.js --no-color\nnode cli.js --color\n```\n\nIf your program changes environment variables after import, the default formatter object does not re-evaluate support automatically. In that case, call `pc.createColors(true)` or `pc.createColors(false)` yourself.\n\n## Common CLI patterns\n\nCreate shared log helpers once and reuse them across your CLI:\n\n```javascript\nimport pc from \"picocolors\";\n\nconst colors = pc.createColors();\n\nexport function info(message) {\n  console.log(`${colors.cyan(\"info\")} ${message}`);\n}\n\nexport function warn(message) {\n  console.warn(`${colors.yellow(\"warn\")} ${message}`);\n}\n\nexport function fail(message) {\n  console.error(`${colors.red(colors.bold(\"error\"))} ${message}`);\n}\n```\n\nFormat values inline without changing surrounding text:\n\n```javascript\nimport pc from \"picocolors\";\n\nfunction renderSummary(fileCount, outDir) {\n  return [\n    `${pc.green(\"done\")}: processed ${pc.bold(fileCount)} files`,\n    `output: ${pc.underline(outDir)}`,\n  ].join(\"\\n\");\n}\n```\n\n## Available formatter methods\n\nText styles:\n\n- `reset`\n- `bold`\n- `dim`\n- `italic`\n- `underline`\n- `inverse`\n- `hidden`\n- `strikethrough`\n\nForeground colors:\n\n- `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `gray`\n- `blackBright`, `redBright`, `greenBright`, `yellowBright`, `blueBright`, `magentaBright`, `cyanBright`, `whiteBright`\n\nBackground colors:\n\n- `bgBlack`, `bgRed`, `bgGreen`, `bgYellow`, `bgBlue`, `bgMagenta`, `bgCyan`, `bgWhite`\n- `bgBlackBright`, `bgRedBright`, `bgGreenBright`, `bgYellowBright`, `bgBlueBright`, `bgMagentaBright`, `bgCyanBright`, `bgWhiteBright`\n\nEach formatter accepts `string | number | null | undefined` and returns a string.\n\n## Browser behavior\n\nThe published package declares a browser-specific build. In browser bundles, `picocolors` reports `isColorSupported: false`, and formatter functions return plain strings instead of ANSI escape sequences.\n\nThat makes it safe to share formatting helpers between Node and browser code when you only need readable text in the browser:\n\n```javascript\nimport pc from \"picocolors\";\n\nconst label = pc.bold(\"Status\");\nconst value = pc.green(\"ok\");\n\nconsole.log(`${label}: ${value}`);\n```\n\n## Practical pitfalls\n\n- `picocolors` is only for ANSI styling; it does not provide prompts, spinners, tables, or logging transports.\n- Auto-detection happens when the module is loaded, so set `NO_COLOR`, `FORCE_COLOR`, or CLI flags before importing it.\n- Use `pc.createColors(false)` for deterministic snapshot tests or machine-readable output.\n- Use `pc.createColors(true)` only when you know the output target should receive ANSI escape codes.\n"
  },
  {
    "path": "content/picomatch/docs/picomatch/javascript/DOC.md",
    "content": "---\nname: picomatch\ndescription: \"picomatch guide for glob matching JavaScript paths, filenames, and custom tooling\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"picomatch,glob,matching,paths,files,regex\"\n---\n\n# picomatch for JavaScript\n\n`picomatch` compiles glob patterns into matcher functions or regular expressions. It matches strings only. It does not walk the file system, and it does not do shell-style brace expansion.\n\n## Install\n\n```bash\nnpm install picomatch@4.0.3\n```\n\n`picomatch 4.0.3` declares `node >=12`.\n\n## Import and initialize\n\nThere is no client object, auth flow, or environment-variable setup. Import the package, create a matcher, and reuse it.\n\n```js\nconst picomatch = require('picomatch');\n\nconst isJavaScript = picomatch('*.js');\n\nconsole.log(isJavaScript('index.js')); // true\nconsole.log(isJavaScript('index.ts')); // false\nconsole.log(isJavaScript('src/index.js')); // false\n```\n\n`*` matches within a single path segment. Use `**` when you want to match nested directories:\n\n```js\nconst picomatch = require('picomatch');\n\nconst isNestedJavaScript = picomatch('**/*.js');\n\nconsole.log(isNestedJavaScript('src/index.js')); // true\nconsole.log(isNestedJavaScript('src/lib/util.ts')); // false\n```\n\n## Common workflows\n\n### Reuse a compiled matcher\n\nCompile once and call the returned function for repeated checks.\n\n```js\nconst picomatch = require('picomatch');\n\nconst shouldWatch = picomatch(['src/**/*.js', 'scripts/**/*.mjs'], {\n  ignore: ['**/*.test.js', '**/dist/**'],\n});\n\nfor (const file of [\n  'src/index.js',\n  'src/index.test.js',\n  'scripts/build.mjs',\n  'src/dist/bundle.js',\n]) {\n  console.log(file, shouldWatch(file));\n}\n\n// src/index.js true\n// src/index.test.js false\n// scripts/build.mjs true\n// src/dist/bundle.js false\n```\n\nWhen you pass an array of patterns, `picomatch()` returns a single matcher that succeeds when any pattern matches.\n\n### Match a basename anywhere in a path\n\nIf the pattern has no slash, set `basename: true` to match against the last path segment.\n\n```js\nconst picomatch = require('picomatch');\n\nconst isReadme = picomatch('README.md', { basename: true });\n\nconsole.log(isReadme('README.md')); // true\nconsole.log(isReadme('docs/README.md')); // true\nconsole.log(isReadme('docs/README.txt')); // false\n```\n\nFor a one-off basename check, use `picomatch.matchBase()`:\n\n```js\nconst picomatch = require('picomatch');\n\nconsole.log(picomatch.matchBase('docs/guide.md', '*.md')); // true\nconsole.log(picomatch.matchBase('docs/guide.txt', '*.md')); // false\n```\n\n### Enable dotfiles, extglobs, and POSIX character classes\n\nDotfiles are skipped by default. POSIX bracket expressions are also disabled unless you opt in with `posix: true`.\n\n```js\nconst picomatch = require('picomatch');\n\nconst isConfigFile = picomatch('*.@(js|json)', {\n  dot: true,\n});\n\nconsole.log(isConfigFile('.eslintrc.js')); // true\nconsole.log(isConfigFile('package.json')); // true\n\nconsole.log(picomatch.isMatch('A', '[[:upper:]]', { posix: true })); // true\nconsole.log(picomatch.isMatch('7', '[[:digit:]]', { posix: true })); // true\n```\n\n### Generate a `RegExp`\n\nUse `makeRe()` when another API expects a regular expression instead of a matcher function.\n\n```js\nconst picomatch = require('picomatch');\n\nconst sourceFileRe = picomatch.makeRe('src/**/*.js');\n\nconsole.log(sourceFileRe.test('src/index.js')); // true\nconsole.log(sourceFileRe.test('test/index.js')); // false\n```\n\nIf you only need a one-off boolean check, `picomatch.isMatch()` is shorter:\n\n```js\nconst picomatch = require('picomatch');\n\nconsole.log(picomatch.isMatch('src/index.js', '**/*.js')); // true\nconsole.log(picomatch.isMatch('src/index.ts', '**/*.js')); // false\n```\n\n### Inspect a pattern for custom tooling\n\n`scan()` is useful when you need to separate a prefix, base path, and glob portion before matching.\n\n```js\nconst picomatch = require('picomatch');\n\nconst result = picomatch.scan('!./src/**/*.js', { tokens: true });\n\nconsole.log(result.prefix); // !./\nconsole.log(result.base);   // src\nconsole.log(result.glob);   // **/*.js\nconsole.log(result.negated); // true\nconsole.log(result.parts);   // ['src', '**/*.js']\n```\n\n## Path handling and cross-platform behavior\n\nThe main `picomatch` entry auto-detects the current OS and sets `windows` when you do not pass it yourself. That means the same pattern can behave differently on Windows and non-Windows hosts.\n\nFor predictable POSIX-style matching everywhere, use `picomatch/posix`:\n\n```js\nconst picomatch = require('picomatch/posix');\n\nconst isMatch = picomatch('src/*');\n\nconsole.log(isMatch('src/index.js')); // true\nconsole.log(isMatch('src\\\\index.js')); // false\n```\n\nIf you want to accept backslashes as path separators, set `windows: true`:\n\n```js\nconst picomatch = require('picomatch');\n\nconst isMatch = picomatch('src/*', { windows: true });\n\nconsole.log(isMatch('src/index.js')); // true\nconsole.log(isMatch('src\\\\index.js')); // true\n```\n\n## Configuration\n\nThere are no package-wide config files or environment variables. Configure behavior per matcher with options.\n\nCommon options for application code:\n\n- `dot: true` to include dotfiles\n- `ignore` to exclude matches after a positive include match\n- `basename: true` or `matchBase: true` to match the last path segment\n- `nocase: true` for case-insensitive matching\n- `windows: true` to accept backslashes as separators\n- `posix: true` to enable POSIX bracket expressions such as `[[:digit:]]`\n- `contains: true` when the glob should match any substring instead of the whole input\n\nExample:\n\n```js\nconst picomatch = require('picomatch');\n\nconst matchesArtifact = picomatch('build', {\n  contains: true,\n  nocase: true,\n});\n\nconsole.log(matchesArtifact('tmp/Build/output.txt')); // true\nconsole.log(matchesArtifact('tmp/dist/output.txt')); // false\n```\n\n## Common pitfalls\n\n- `*` does not match across `/`. Use `**` for nested directories.\n- Dotfiles are ignored unless the pattern starts with `.` or you pass `dot: true`.\n- POSIX bracket classes like `[[:word:]]` require `posix: true`.\n- `picomatch` has basic brace support for matching, but it does not do brace expansion. If you need expansion semantics, use `micromatch` or expand patterns before calling `picomatch`.\n- The main export auto-detects Windows path handling. Normalize input paths or choose `picomatch/posix` if your tooling needs identical results across platforms.\n- If you need literal special characters such as `$`, `^`, `*`, `+`, `?`, `(`, `)`, or `[]` in a glob, escape them with backslashes or quotes.\n- `picomatch` only matches strings. Pair it with your own directory traversal or file-list source when you need to discover files on disk.\n\n## Version-sensitive notes\n\n- This guide covers `picomatch 4.0.3`.\n- `4.0.3` publishes a CommonJS entrypoint and declares `node >=12`.\n- The root `picomatch` export auto-detects the host platform when `options.windows` is omitted; `picomatch/posix` avoids that auto-detection.\n\n## Official sources\n\n- Repository: https://github.com/micromatch/picomatch\n- Maintainer README: https://github.com/micromatch/picomatch/blob/master/README.md\n- Package source entrypoint: https://github.com/micromatch/picomatch/blob/master/index.js\n- Package matcher implementation: https://github.com/micromatch/picomatch/blob/master/lib/picomatch.js\n- npm package page: https://www.npmjs.com/package/picomatch\n"
  },
  {
    "path": "content/pika/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pika Python package guide for AMQP 0-9-1 messaging with RabbitMQ and other compatible brokers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pika,rabbitmq,amqp,messaging,queues,python\"\n---\n\n# Pika Python Package Guide\n\n## Golden Rule\n\nUse `pika` for AMQP 0-9-1 messaging in Python, choose the adapter that matches your runtime model, and treat connections and channels as stateful broker resources instead of stateless request clients. `BlockingConnection` is the practical default for scripts and workers; use `AsyncioConnection` or another async adapter when you are already inside an event loop.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"pika==1.3.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pika==1.3.2\"\npoetry add \"pika==1.3.2\"\n```\n\n## Connection Setup\n\n### AMQP URL\n\nFor most apps, start from an AMQP URL and let `URLParameters` parse it:\n\n```python\nimport pika\n\nparams = pika.URLParameters(\n    \"amqp://guest:guest@localhost:5672/%2F?heartbeat=30&blocked_connection_timeout=300\"\n)\n\nconnection = pika.BlockingConnection(params)\nchannel = connection.channel()\n```\n\nNotes:\n\n- Use `amqps://...` when your broker requires TLS.\n- The default RabbitMQ virtual host `/` appears as `%2F` in the URL.\n- `heartbeat` and `blocked_connection_timeout` are worth setting explicitly for long-running workers.\n\n### Structured connection parameters\n\nUse `ConnectionParameters` when the broker config comes from separate fields:\n\n```python\nimport pika\n\ncredentials = pika.PlainCredentials(\"app-user\", \"secret-password\")\n\nparams = pika.ConnectionParameters(\n    host=\"rabbitmq.internal\",\n    port=5672,\n    virtual_host=\"/\",\n    credentials=credentials,\n    heartbeat=30,\n    blocked_connection_timeout=300,\n    client_properties={\"connection_name\": \"billing-worker\"},\n)\n\nconnection = pika.BlockingConnection(params)\nchannel = connection.channel()\n```\n\n### TLS\n\nFor TLS, build an `ssl.SSLContext` and pass it through `SSLOptions`:\n\n```python\nimport ssl\nimport pika\n\ncontext = ssl.create_default_context(cafile=\"/etc/ssl/certs/ca.pem\")\ncontext.load_cert_chain(\n    certfile=\"/etc/ssl/certs/client-cert.pem\",\n    keyfile=\"/etc/ssl/private/client-key.pem\",\n)\n\nparams = pika.ConnectionParameters(\n    host=\"rabbitmq.example.com\",\n    port=5671,\n    virtual_host=\"/\",\n    credentials=pika.PlainCredentials(\"app-user\", \"secret-password\"),\n    ssl_options=pika.SSLOptions(context, \"rabbitmq.example.com\"),\n)\n\nconnection = pika.BlockingConnection(params)\n```\n\n## Core Usage\n\n### Publish a message\n\nDeclare the queue before publishing, enable publisher confirms when delivery matters, and use persistent messages with durable queues if the message must survive broker restarts.\n\n```python\nimport json\nimport pika\n\nparams = pika.URLParameters(\"amqp://guest:guest@localhost:5672/%2F\")\nconnection = pika.BlockingConnection(params)\nchannel = connection.channel()\n\nchannel.queue_declare(queue=\"jobs\", durable=True)\nchannel.confirm_delivery()\n\npayload = {\"job_id\": \"job-123\", \"task\": \"rebuild-index\"}\n\nchannel.basic_publish(\n    exchange=\"\",\n    routing_key=\"jobs\",\n    body=json.dumps(payload).encode(\"utf-8\"),\n    properties=pika.BasicProperties(\n        content_type=\"application/json\",\n        delivery_mode=pika.DeliveryMode.Persistent,\n    ),\n    mandatory=True,\n)\n\nconnection.close()\n```\n\n### Consume with manual acknowledgements\n\nUse manual acknowledgements for real work queues so messages can be retried when the worker crashes partway through processing.\n\n```python\nimport json\nimport pika\n\nparams = pika.URLParameters(\n    \"amqp://guest:guest@localhost:5672/%2F?heartbeat=30&blocked_connection_timeout=300\"\n)\nconnection = pika.BlockingConnection(params)\nchannel = connection.channel()\n\nchannel.queue_declare(queue=\"jobs\", durable=True)\nchannel.basic_qos(prefetch_count=1)\n\ndef handle_message(ch, method, properties, body):\n    try:\n        payload = json.loads(body)\n        print(f\"processing {payload['job_id']}\")\n        ch.basic_ack(delivery_tag=method.delivery_tag)\n    except Exception:\n        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)\n\nchannel.basic_consume(queue=\"jobs\", on_message_callback=handle_message, auto_ack=False)\nchannel.start_consuming()\n```\n\n### Pull one message synchronously\n\n`basic_get()` is fine for admin tools, one-off scripts, or tests. Do not use it as a high-throughput polling loop unless you intentionally want pull-style semantics.\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.URLParameters(\"amqp://guest:guest@localhost:5672/%2F\")\n)\nchannel = connection.channel()\n\nmethod, properties, body = channel.basic_get(queue=\"jobs\", auto_ack=False)\n\nif method is not None:\n    print(body.decode(\"utf-8\"))\n    channel.basic_ack(method.delivery_tag)\n\nconnection.close()\n```\n\n## Async Adapters And Threading\n\nPika ships multiple adapters. Use the adapter that matches the concurrency model you already have:\n\n- `BlockingConnection`: simplest choice for scripts, CLIs, and worker processes\n- `AsyncioConnection`: for applications already using `asyncio`\n- `SelectConnection`: event-loop driven without `asyncio`\n\nThreading rules that matter in practice:\n\n- Do not share a channel across threads.\n- Do not assume `BlockingConnection` is generally thread-safe.\n- If another thread must notify a blocking connection, use `add_callback_threadsafe()` instead of touching channels directly from that thread.\n\n## Recovery And Retry Pattern\n\nPika can raise connection and channel exceptions when the broker is unavailable, closes the connection, or rejects topology changes. For long-running consumers, wrap startup in a reconnect loop and recreate the connection, channel, queue declarations, QoS, and consumer bindings after reconnect.\n\n```python\nimport time\nimport pika\n\ndef handle_message(ch, method, properties, body):\n    print(body.decode(\"utf-8\"))\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\nwhile True:\n    try:\n        connection = pika.BlockingConnection(\n            pika.URLParameters(\"amqp://guest:guest@localhost:5672/%2F\")\n        )\n        channel = connection.channel()\n        channel.queue_declare(queue=\"jobs\", durable=True)\n        channel.basic_qos(prefetch_count=1)\n        channel.basic_consume(queue=\"jobs\", on_message_callback=handle_message)\n        channel.start_consuming()\n    except pika.exceptions.AMQPConnectionError:\n        time.sleep(5)\n```\n\nKeep the reconnect policy outside your message handler so failures during startup and failures during message processing are handled separately.\n\n## Configuration Notes\n\n- Broker credentials are usually username/password plus virtual host, passed either in the AMQP URL or through `PlainCredentials`.\n- Use `ExternalCredentials` only when your broker is configured for external SASL auth and the upstream broker docs explicitly require it.\n- Set `client_properties[\"connection_name\"]` so RabbitMQ management UI and logs identify your app instance clearly.\n- Set `heartbeat` for long-lived connections; leaving it implicit makes timeout behavior harder to reason about.\n- Set `blocked_connection_timeout` when using `BlockingConnection` so synchronous calls fail instead of hanging indefinitely during broker resource alarms.\n\n## Common Pitfalls\n\n- Durable queues are not enough on their own. If the message must persist, publish with `delivery_mode=pika.DeliveryMode.Persistent`.\n- `auto_ack=True` acknowledges delivery before your code finishes processing. That is unsafe for jobs that must be retried on failure.\n- Publisher confirms are separate from queue durability. Use `channel.confirm_delivery()` when your producer needs broker-level publish acknowledgement.\n- Blocking adapters can appear hung when the broker emits `Connection.Blocked`. The official examples recommend `blocked_connection_timeout` to break that state.\n- Redeclare topology after reconnect. A fresh TCP connection does not preserve your previous channel state, consumers, or QoS configuration.\n- AMQP URLs are easy to get subtly wrong. Encode the `/` virtual host as `%2F` and switch to `amqps://` for TLS.\n- If your app already runs on `asyncio`, do not hide `BlockingConnection` inside random thread pools unless you have a clear reason. Use `AsyncioConnection` instead.\n\n## Version-Sensitive Notes\n\n- The version used here, PyPI stable release, and the stable docs URL all align on `1.3.2`.\n- The upstream GitHub releases page also shows a newer beta line (`1.4.0b0`). Do not assume beta examples or unreleased changes apply to a project pinned to `1.3.2`.\n- `1.3.2` is the current stable line documented at `readthedocs.io/en/stable/`; if your project upgrades to a later stable release, re-check adapter behavior and connection parameter defaults before copying old snippets.\n\n## Official Sources\n\n- Stable docs: https://pika.readthedocs.io/en/stable/\n- Connection parameters: https://pika.readthedocs.io/en/stable/modules/parameters.html\n- Credentials: https://pika.readthedocs.io/en/stable/modules/credentials.html\n- Blocking consumer example: https://pika.readthedocs.io/en/stable/examples/blocking_consume.html\n- URL parameters example: https://pika.readthedocs.io/en/stable/examples/using_urlparameters.html\n- Heartbeat and blocked timeout example: https://pika.readthedocs.io/en/stable/examples/heartbeat_and_blocked_timeouts.html\n- TLS example: https://pika.readthedocs.io/en/stable/examples/tls_server_authentication.html\n- Asyncio consumer example: https://pika.readthedocs.io/en/stable/examples/asyncio_consumer.html\n- FAQ: https://pika.readthedocs.io/en/stable/faq.html\n- PyPI: https://pypi.org/project/pika/\n- GitHub repository and releases: https://github.com/pika/pika\n"
  },
  {
    "path": "content/pillow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pillow package guide for Python image processing, formats, and installation-dependent features\"\nmetadata:\n  languages: \"python\"\n  versions: \"12.1.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pillow,pil,images,imaging,python\"\n---\n\n# Pillow Python Package Guide\n\n## Golden Rule\n\nInstall `Pillow`, but import from `PIL`:\n\n```bash\npython3 -m pip install --upgrade Pillow\n```\n\n```python\nfrom PIL import Image\n```\n\nDo not use `import pillow`. Pillow is the maintained fork of PIL, but the runtime import namespace is still `PIL`.\n\nIf an old `PIL` package is installed in the same environment, remove it before installing Pillow. The upstream docs say Pillow and PIL cannot co-exist.\n\n## Installation\n\n### pip\n\n```bash\npython3 -m pip install --upgrade pip\npython3 -m pip install --upgrade Pillow\n```\n\n### uv\n\n```bash\nuv add Pillow\n```\n\n### Poetry\n\n```bash\npoetry add Pillow\n```\n\n### Optional companion packages\n\nThe official install docs call out these optional packages:\n\n```bash\npython3 -m pip install --upgrade defusedxml olefile\n```\n\n- `defusedxml`: lets Pillow read XMP data\n- `olefile`: lets Pillow read FPX and MIC images\n\n### Source builds and native libraries\n\nOfficial wheels usually include support for common formats. If you compile Pillow from source, format support depends on system libraries:\n\n- Required by default: `zlib` and `libjpeg`\n- Common optional libraries: `libtiff`, `libfreetype`, `littlecms2`, `libwebp`, `openjpeg`, `libavif`\n- Text layout features need `libraqm` plus its dependencies\n- Official binaries do not ship with `libimagequant`\n\nIf a project depends on a format such as WebP, AVIF, JPEG 2000, or advanced font layout, verify the compiled feature set after installation.\n\n## Initialize And Verify Features\n\nUse `PIL.features` to inspect what your current build can actually do:\n\n```python\nfrom PIL import features\n\nprint(\"webp:\", features.check_module(\"webp\"))\nprint(\"avif:\", features.check_module(\"avif\"))\nprint(\"jpg_2000:\", features.check_codec(\"jpg_2000\"))\nprint(\"raqm:\", features.check_feature(\"raqm\"))\n```\n\nFor a full report:\n\n```bash\npython3 -m PIL\n```\n\nThis matters because two machines can have the same `Pillow==12.1.1` version but different codec or text-layout support.\n\n## Core Usage\n\n### Open, inspect, and save images\n\n```python\nfrom pathlib import Path\nfrom PIL import Image\n\nsource = Path(\"input.png\")\ntarget = Path(\"output.jpg\")\n\nwith Image.open(source) as img:\n    print(img.format, img.size, img.mode)\n\n    rgb = img.convert(\"RGB\")\n    rgb.save(target, format=\"JPEG\", quality=90, optimize=True)\n```\n\nNotes:\n\n- `Image.open()` raises `OSError` if the file cannot be opened\n- `open()` identifies an image from file contents, not the filename\n- `save()` uses the destination filename extension unless you pass `format=...`\n\n### Resize safely for thumbnails and web output\n\n```python\nfrom PIL import Image\n\nwith Image.open(\"photo.webp\") as img:\n    preview = img.copy()\n    preview.thumbnail((512, 512))\n    preview.save(\"photo-preview.webp\")\n\nwith Image.open(\"photo.webp\") as img:\n    resized = img.resize((1200, 800), Image.Resampling.LANCZOS)\n    resized.save(\"photo-1200.webp\")\n```\n\nUse `thumbnail()` when you want to preserve aspect ratio and cap the maximum size. It modifies the image in place, so copy first if you still need the original object.\n\n### Crop, paste, and compose\n\n```python\nfrom PIL import Image\n\nwith Image.open(\"base.png\") as base, Image.open(\"overlay.png\") as overlay:\n    card = base.convert(\"RGBA\")\n    badge = overlay.convert(\"RGBA\")\n\n    region = card.crop((40, 40, 360, 240))\n    region.save(\"region.png\")\n\n    card.alpha_composite(badge, dest=(24, 24))\n    card.save(\"composited.png\")\n```\n\nFor masked paste workflows, convert to `RGBA` first so transparency behaves predictably.\n\n### Create images from scratch\n\n```python\nfrom PIL import Image, ImageDraw\n\nimg = Image.new(\"RGB\", (400, 200), \"white\")\ndraw = ImageDraw.Draw(img)\ndraw.rectangle((20, 20, 380, 180), outline=\"black\", width=3)\ndraw.text((40, 80), \"Generated with Pillow\", fill=\"black\")\nimg.save(\"generated.png\")\n```\n\n### Read from bytes or file-like objects\n\n```python\nimport io\nfrom pathlib import Path\nfrom PIL import Image\n\nraw_bytes = Path(\"input.png\").read_bytes()\n\nwith Image.open(io.BytesIO(raw_bytes)) as img:\n    print(img.size)\n```\n\nWhen using a file-like object, keep it open until Pillow has loaded the data. Pillow may call `seek()` while reading headers or pixel data.\n\n### Convert NumPy arrays to images\n\n```python\nimport numpy as np\nfrom PIL import Image\n\narr = np.zeros((128, 128, 3), dtype=np.uint8)\narr[:, :, 0] = 255\n\nimg = Image.fromarray(arr)\nimg.save(\"red.png\")\n```\n\n`Image.fromarray()` is the standard bridge from NumPy-style image buffers into Pillow objects.\n\n### Work with multiframe images\n\n```python\nfrom PIL import Image, ImageSequence\n\nwith Image.open(\"animation.gif\") as img:\n    for i, frame in enumerate(ImageSequence.Iterator(img)):\n        frame.convert(\"RGBA\").save(f\"frame-{i}.png\")\n```\n\nIf you need to keep additional frames available, do not assume the underlying file can be closed after the first `load()`.\n\n## Config, Environment, And Safety Controls\n\nPillow has no credential setup. The practical runtime controls are feature availability and resource limits.\n\n### Decompression bomb protection\n\nPillow warns when an image exceeds `Image.MAX_IMAGE_PIXELS` and raises `DecompressionBombError` above twice that threshold.\n\n```python\nimport warnings\nfrom PIL import Image\n\nwarnings.simplefilter(\"error\", Image.DecompressionBombWarning)\n```\n\nOnly disable the pixel limit if the input is trusted and you understand the memory cost:\n\n```python\nfrom PIL import Image\n\nImage.MAX_IMAGE_PIXELS = None\n```\n\n### Deterministic file handling\n\nUse a context manager or call `close()` yourself. For single-frame images, Pillow can close its underlying file after `load()`, but multi-frame images may need the file to stay open for `seek()`.\n\nIf you need the image after the context manager exits, load or copy it inside the `with` block.\n\n## Common Pitfalls\n\n- Install name and import name differ: `pip install Pillow`, `from PIL import Image`\n- Legacy PIL and Pillow cannot co-exist in one environment\n- `thumbnail()` mutates in place; use `copy()` if you still need the original size\n- JPEG does not support alpha; convert `RGBA` or `P` images to `RGB` before saving as JPEG\n- `save()` infers format from the output extension unless `format=` is provided explicitly\n- Copies and derived images lose file-format-specific state like `format` and `fp`\n- A closed file-like object can break delayed image loading; keep binary streams open until data is loaded\n- Feature support is build-dependent; check WebP, AVIF, JPEG 2000, and Raqm explicitly on production hosts\n\n## Version-Sensitive Notes For 12.1.x\n\n- `12.1.1` is a patch release from `2026-02-11`\n- The `12.1.1` release fixes an out-of-bounds write issue triggered by crafted PSD files; the upstream note says this affects Pillow `>=10.3.0`\n- `12.1.0` deprecated `Image.getdata()`; prefer `Image.get_flattened_data()`\n- Pillow uses semantic versioning and quarterly main releases; patch releases are reserved for security, installation, or critical bug fixes\n- The current PyPI metadata for `12.1.1` requires Python `>=3.10`\n\n## Official Sources\n\n- Docs root: `https://pillow.readthedocs.io/en/stable/`\n- Package index: `https://pypi.org/project/pillow/`\n- Reference index: `https://pillow.readthedocs.io/en/stable/reference/`\n- Release notes: `https://pillow.readthedocs.io/en/stable/releasenotes/`\n"
  },
  {
    "path": "content/pinecone/docs/sdk/javascript/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Vector database for AI applications with semantic search, hybrid search, reranking, and integrated embeddings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.1.2\"\n  updated-on: \"2025-10-26\"\n  source: maintainer\n  tags: \"pinecone,sdk,vector-db,ai,search\"\n---\n# Pinecone JavaScript/TypeScript SDK Coding Guidelines\n\nYou are a Pinecone vector database coding expert. Help me with writing code using the Pinecone SDK for JavaScript/TypeScript.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.pinecone.io/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Pinecone TypeScript SDK for all Pinecone vector database interactions. Do not use legacy libraries or unofficial packages.\n\n- **Library Name:** Pinecone TypeScript SDK\n- **NPM Package:** `@pinecone-database/pinecone`\n- **Legacy Libraries**: `pinecone-client` and other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install @pinecone-database/pinecone`\n\n**APIs and Usage:**\n\n- **Correct:** `import { Pinecone } from '@pinecone-database/pinecone'`\n- **Correct:** `const pc = new Pinecone({})`\n- **Correct:** `await pc.createIndex(...)`\n- **Correct:** `pc.index('index-name')`\n- **Incorrect:** `PineconeClient`\n- **Incorrect:** Legacy initialization patterns\n\n**Important Security Note:**\n\nThe Pinecone TypeScript SDK is intended for server-side use only. Using the SDK within a browser context can expose your API key(s). Always use server-side code or proxy requests through a backend.\n\n## Installation\n\nInstall the Pinecone SDK using npm:\n\n```bash\nnpm install @pinecone-database/pinecone\n```\n\n**Requirements:**\n- TypeScript >=4.1\n- Node.js >=18.x\n\n## Initialization and API Key\n\nThe SDK requires creating a `Pinecone` instance for all API calls.\n\n### Using Environment Variables\n\nSet your API key as an environment variable:\n\n```bash\nexport PINECONE_API_KEY=\"your_api_key_here\"\n```\n\nThen initialize without arguments:\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\n```\n\n### Using Configuration Object\n\nPass credentials directly:\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone({\n  apiKey: 'your_api_key_here',\n});\n```\n\n### With Custom Retry Configuration\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone({\n  apiKey: process.env.PINECONE_API_KEY,\n  maxRetries: 5,\n});\n```\n\nThe `maxRetries` parameter (defaults to 3) applies to operations like `upsert`, `update`, and `configureIndex`.\n\n## Creating Indexes\n\n### Serverless Index (Basic)\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\n\nawait pc.createIndex({\n  name: 'my-index',\n  dimension: 1536,\n  metric: 'cosine',\n  spec: {\n    serverless: {\n      cloud: 'aws',\n      region: 'us-west-2',\n    },\n  },\n});\n```\n\n### Serverless Index with Wait\n\nUse `waitUntilReady` to block until the index is operational:\n\n```typescript\nawait pc.createIndex({\n  name: 'serverless-index',\n  dimension: 1536,\n  metric: 'cosine',\n  spec: {\n    serverless: {\n      cloud: 'aws',\n      region: 'us-east-1',\n    },\n  },\n  waitUntilReady: true,\n});\n```\n\n### Pod-Based Index\n\n```typescript\nawait pc.createIndex({\n  name: 'pod-index',\n  dimension: 1536,\n  metric: 'dotproduct',\n  spec: {\n    pod: {\n      environment: 'us-west-2',\n      podType: 'p1.x1',\n      pods: 1,\n      replicas: 1,\n    },\n  },\n});\n```\n\n### Hybrid Search Index (Sparse-Dense)\n\nFor hybrid search supporting both dense and sparse vectors, use `dotproduct` metric:\n\n```typescript\nawait pc.createIndex({\n  name: 'hybrid-index',\n  dimension: 1024,\n  metric: 'dotproduct',\n  spec: {\n    serverless: {\n      cloud: 'aws',\n      region: 'us-east-1',\n    },\n  },\n});\n```\n\n**Note:** The `dotproduct` metric is the only metric that supports sparse-dense hybrid search.\n\n## Index Management\n\n### Describe Index\n\nGet index details including status, dimension, and host:\n\n```typescript\nconst indexStats = await pc.describeIndex('my-index');\nconsole.log(indexStats);\n```\n\n### List All Indexes\n\n```typescript\nconst indexList = await pc.listIndexes();\nconsole.log(indexList.indexes);\n```\n\n### Delete Index\n\n```typescript\nawait pc.deleteIndex('my-index');\n```\n\n### Configure Index (Scale)\n\nFor pod-based indexes, adjust replicas and pod type:\n\n```typescript\nawait pc.configureIndex('pod-index', {\n  spec: {\n    pod: {\n      replicas: 2,\n      podType: 'p1.x2',\n    },\n  },\n});\n```\n\n## Connecting to an Index\n\n### Basic Connection\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n```\n\n### Connection with Namespace\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index').namespace('my-namespace');\n```\n\n### Connection with Host (Faster)\n\nIf you know the index host, connect directly:\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index', 'https://my-index-abc123.svc.pinecone.io');\n```\n\n## Upserting Vectors\n\n### Dense Vectors (Basic)\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nawait index.upsert([\n  {\n    id: 'vec1',\n    values: [0.1, 0.2, 0.3, 0.4, 0.5],\n  },\n  {\n    id: 'vec2',\n    values: [0.2, 0.3, 0.4, 0.5, 0.6],\n  },\n]);\n```\n\n### Dense Vectors with Metadata\n\n```typescript\nawait index.upsert([\n  {\n    id: 'vec1',\n    values: [0.1, 0.2, 0.3, 0.4, 0.5],\n    metadata: {\n      genre: 'comedy',\n      year: 2020,\n      title: 'Movie Title',\n    },\n  },\n  {\n    id: 'vec2',\n    values: [0.2, 0.3, 0.4, 0.5, 0.6],\n    metadata: {\n      genre: 'action',\n      year: 2021,\n      title: 'Another Movie',\n    },\n  },\n]);\n```\n\n### Namespaced Upsert\n\n```typescript\nconst pc = new Pinecone();\nconst ns = pc.index('my-index').namespace('example-namespace');\n\nawait ns.upsert([\n  {\n    id: 'vec1',\n    values: [0.1, 0.2, 0.3],\n    metadata: { category: 'A' },\n  },\n]);\n```\n\n### Batch Upsert (Large Datasets)\n\nFor upserting many vectors, batch them in groups of up to 1,000 records (max 2 MB per batch):\n\n```typescript\nconst batchSize = 1000;\nconst vectors = []; // Your vector array\n\nfor (let i = 0; i < vectors.length; i += batchSize) {\n  const batch = vectors.slice(i, i + batchSize);\n  await index.upsert(batch);\n}\n```\n\n### Sparse-Dense Vectors (Hybrid Search)\n\n```typescript\nawait index.upsert([\n  {\n    id: 'vec1',\n    values: [0.1, 0.2, 0.3], // Dense vector\n    sparseValues: {\n      indices: [10, 45, 16],\n      values: [0.5, 0.5, 0.2],\n    },\n    metadata: { text: 'original text content' },\n  },\n]);\n```\n\n## Querying Vectors\n\n### Basic Query (Dense)\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nconst queryResponse = await index.query({\n  vector: [0.1, 0.2, 0.3, 0.4, 0.5],\n  topK: 10,\n  includeMetadata: true,\n  includeValues: false,\n});\n\nconsole.log(queryResponse.matches);\n```\n\n### Query with Metadata Filter\n\n```typescript\nconst queryResponse = await index.query({\n  vector: [0.1, 0.2, 0.3, 0.4, 0.5],\n  topK: 5,\n  filter: {\n    genre: { $eq: 'comedy' },\n  },\n  includeMetadata: true,\n});\n```\n\n### Complex Metadata Filters\n\n```typescript\n// Multiple conditions with $and\nconst response = await index.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 10,\n  filter: {\n    $and: [\n      { genre: { $eq: 'comedy' } },\n      { year: { $gte: 2020 } },\n    ],\n  },\n  includeMetadata: true,\n});\n\n// Using $or operator\nconst response2 = await index.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 10,\n  filter: {\n    $or: [\n      { genre: { $eq: 'comedy' } },\n      { genre: { $eq: 'drama' } },\n    ],\n  },\n  includeMetadata: true,\n});\n\n// Using $in for multiple values\nconst response3 = await index.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 10,\n  filter: {\n    genre: { $in: ['comedy', 'action', 'drama'] },\n  },\n  includeMetadata: true,\n});\n```\n\n### Query by ID\n\n```typescript\nconst queryResponse = await index.query({\n  id: 'vec1',\n  topK: 10,\n  includeMetadata: true,\n});\n```\n\n### Namespaced Query\n\n```typescript\nconst ns = pc.index('my-index').namespace('example-namespace');\n\nconst queryResponse = await ns.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 5,\n  includeMetadata: true,\n});\n```\n\n### Hybrid Query (Sparse-Dense)\n\n```typescript\nconst queryResponse = await index.query({\n  vector: [0.1, 0.2, 0.3], // Dense query vector\n  sparseVector: {\n    indices: [10, 45, 16],\n    values: [0.5, 0.5, 0.2],\n  },\n  topK: 10,\n  includeMetadata: true,\n});\n```\n\n## Fetching Vectors\n\n### Fetch by IDs\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nconst fetchResponse = await index.fetch(['vec1', 'vec2', 'vec3']);\nconsole.log(fetchResponse.records);\n```\n\n### Fetch from Namespace\n\n```typescript\nconst ns = pc.index('my-index').namespace('example-namespace');\nconst fetchResponse = await ns.fetch(['vec1', 'vec2']);\nconsole.log(fetchResponse.records);\n```\n\n## Updating Vectors\n\n### Update Values\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nawait index.update({\n  id: 'vec1',\n  values: [0.9, 0.8, 0.7, 0.6, 0.5],\n});\n```\n\n### Update Metadata\n\n```typescript\nawait index.update({\n  id: 'vec1',\n  metadata: {\n    genre: 'documentary',\n    year: 2023,\n  },\n});\n```\n\n### Update with Namespace\n\n```typescript\nconst ns = pc.index('my-index').namespace('example-namespace');\n\nawait ns.update({\n  id: 'vec1',\n  values: [0.1, 0.2, 0.3],\n  metadata: { updated: true },\n});\n```\n\n## Deleting Vectors\n\n### Delete by IDs\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nawait index.deleteOne('vec1');\n\n// Delete multiple\nawait index.deleteMany(['vec1', 'vec2', 'vec3']);\n```\n\n### Delete with Metadata Filter\n\n```typescript\nawait index.deleteMany({\n  filter: {\n    genre: { $eq: 'comedy' },\n  },\n});\n```\n\n### Delete All in Namespace\n\n```typescript\nconst ns = pc.index('my-index').namespace('example-namespace');\nawait ns.deleteAll();\n```\n\n**Warning:** Deleting all records from a namespace will also delete the namespace itself. This operation is irreversible.\n\n### Delete from Specific Namespace\n\n```typescript\nconst index = pc.index('my-index');\n\nawait index.namespace('example-namespace').deleteMany(['vec1', 'vec2']);\n```\n\n## Index Statistics\n\n### Get Index Stats\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\nconst stats = await index.describeIndexStats();\nconsole.log(stats);\n```\n\nReturns information including:\n- Total vector count\n- Dimension\n- Index fullness\n- Namespaces with vector counts\n\n### Get Stats with Filter\n\n```typescript\nconst stats = await index.describeIndexStats({\n  filter: {\n    genre: { $eq: 'comedy' },\n  },\n});\n```\n\n## Integrated Inference (Embeddings)\n\nPinecone provides hosted embedding models through the Inference API.\n\n### Generate Embeddings\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\n\n// Embed documents\nconst embeddings = await pc.inference.embed({\n  model: 'multilingual-e5-large',\n  inputs: [\n    { text: 'Turkey is a classic meat to eat at American Thanksgiving.' },\n    { text: 'Many people enjoy the beautiful mosques in Turkey.' },\n  ],\n  parameters: {\n    inputType: 'passage',\n    truncate: 'END',\n  },\n});\n\nconsole.log(embeddings);\n```\n\n### Embed Queries\n\n```typescript\nconst pc = new Pinecone();\n\nconst queryEmbedding = await pc.inference.embed({\n  model: 'multilingual-e5-large',\n  inputs: [{ text: 'How should I prepare my turkey?' }],\n  parameters: {\n    inputType: 'query',\n    truncate: 'END',\n  },\n});\n\n// Use the embedding for querying\nconst index = pc.index('my-index');\nconst results = await index.query({\n  vector: queryEmbedding[0].values,\n  topK: 10,\n  includeMetadata: true,\n});\n```\n\n### Available Embedding Models\n\n- `multilingual-e5-large`: Efficient dense embedding model trained on multilingual datasets\n- `pinecone-sparse-english-v0`: Sparse embedding model for keyword or hybrid semantic/keyword search\n\n## Integrated Records (Auto-Embedding)\n\nFor indexes with integrated embedding, use `upsertRecords` to automatically convert text to vectors.\n\n### Upsert with Auto-Embedding\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('integrated-index').namespace('my-namespace');\n\nawait index.upsertRecords([\n  {\n    id: 'rec1',\n    chunk_text: \"Apple's first product was the Apple I computer.\",\n    metadata: { category: 'tech' },\n  },\n  {\n    id: 'rec2',\n    chunk_text: 'The company was founded in 1976.',\n    metadata: { category: 'history' },\n  },\n]);\n```\n\n### Query with Integrated Embedding\n\n```typescript\nconst results = await index.queryRecords({\n  query: 'Tell me about Apple computers',\n  topK: 5,\n  filter: { category: { $eq: 'tech' } },\n  includeMetadata: true,\n});\n\nconsole.log(results.matches);\n```\n\n## Namespaces\n\nNamespaces partition records within an index and enable multitenancy.\n\n### Create Namespace (Implicit)\n\nNamespaces are created automatically when you upsert to them:\n\n```typescript\nconst ns1 = pc.index('my-index').namespace('customer-1');\nawait ns1.upsert([{ id: 'vec1', values: [0.1, 0.2, 0.3] }]);\n\nconst ns2 = pc.index('my-index').namespace('customer-2');\nawait ns2.upsert([{ id: 'vec1', values: [0.4, 0.5, 0.6] }]);\n```\n\n### List Namespaces\n\n```typescript\nconst stats = await index.describeIndexStats();\nconsole.log(Object.keys(stats.namespaces));\n```\n\n### Default Namespace\n\nIf no namespace is specified, vectors are stored in the `\"__default__\"` namespace:\n\n```typescript\nconst index = pc.index('my-index');\n// This uses the default namespace\nawait index.upsert([{ id: 'vec1', values: [0.1, 0.2, 0.3] }]);\n```\n\n## Reranking\n\nUse Pinecone's reranking models to reorder results by relevance.\n\n### Rerank Results\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\n\nconst reranked = await pc.inference.rerank({\n  model: 'bge-reranker-v2-m3',\n  query: 'What is the capital of France?',\n  documents: [\n    { id: 'doc1', text: 'Paris is the capital of France.' },\n    { id: 'doc2', text: 'London is the capital of England.' },\n    { id: 'doc3', text: 'Berlin is the capital of Germany.' },\n  ],\n  topN: 2,\n  returnDocuments: true,\n});\n\nconsole.log(reranked);\n```\n\n## Collections (Backups)\n\nCollections are static snapshots of an index that can be used to create new indexes.\n\n### Create Collection\n\n```typescript\nconst pc = new Pinecone();\n\nawait pc.createCollection({\n  name: 'my-collection',\n  source: 'my-index',\n});\n```\n\n### List Collections\n\n```typescript\nconst collections = await pc.listCollections();\nconsole.log(collections);\n```\n\n### Create Index from Collection\n\n```typescript\nawait pc.createIndex({\n  name: 'new-index-from-backup',\n  dimension: 1536,\n  metric: 'cosine',\n  spec: {\n    serverless: {\n      cloud: 'aws',\n      region: 'us-west-2',\n    },\n  },\n  sourceCollection: 'my-collection',\n});\n```\n\n### Delete Collection\n\n```typescript\nawait pc.deleteCollection('my-collection');\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```typescript\nimport { Pinecone, PineconeConnectionError } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\nconst index = pc.index('my-index');\n\ntry {\n  await index.query({\n    vector: [0.1, 0.2, 0.3],\n    topK: 10,\n  });\n} catch (error) {\n  if (error instanceof PineconeConnectionError) {\n    console.error('Connection error:', error.message);\n  } else {\n    console.error('Unexpected error:', error);\n  }\n}\n```\n\n### Retry Configuration\n\n```typescript\nconst pc = new Pinecone({\n  apiKey: process.env.PINECONE_API_KEY,\n  maxRetries: 5, // Increase retries for operations\n});\n```\n\n## Performance Best Practices\n\n### Batch Operations\n\nAlways batch upsert operations for better throughput:\n\n```typescript\n// Good: Batch upsert\nconst vectors = generateVectors(1000);\nawait index.upsert(vectors);\n\n// Bad: Individual upserts\nfor (const vector of vectors) {\n  await index.upsert([vector]); // Don't do this\n}\n```\n\n### Parallel Requests\n\nUse Promise.all for independent parallel operations:\n\n```typescript\nconst [stats, listResult, queryResult] = await Promise.all([\n  index.describeIndexStats(),\n  pc.listIndexes(),\n  index.query({ vector: [0.1, 0.2, 0.3], topK: 5 }),\n]);\n```\n\n### Connection Reuse\n\nReuse the index connection instead of recreating it:\n\n```typescript\n// Good: Create once, reuse\nconst index = pc.index('my-index');\nfor (let i = 0; i < 100; i++) {\n  await index.query({ vector: getVector(i), topK: 5 });\n}\n\n// Bad: Recreate each time\nfor (let i = 0; i < 100; i++) {\n  const index = pc.index('my-index'); // Don't do this\n  await index.query({ vector: getVector(i), topK: 5 });\n}\n```\n\n## Metadata Filtering Operators\n\nPinecone supports MongoDB-style query operators for metadata filtering:\n\n- `$eq`: Equal to\n- `$ne`: Not equal to\n- `$gt`: Greater than\n- `$gte`: Greater than or equal to\n- `$lt`: Less than\n- `$lte`: Less than or equal to\n- `$in`: In array\n- `$nin`: Not in array\n- `$exists`: Field exists\n- `$and`: Logical AND\n- `$or`: Logical OR\n\n### Example: Complex Filter\n\n```typescript\nconst results = await index.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 10,\n  filter: {\n    $and: [\n      { year: { $gte: 2020, $lte: 2023 } },\n      {\n        $or: [\n          { genre: { $eq: 'comedy' } },\n          { genre: { $eq: 'drama' } },\n        ],\n      },\n      { rating: { $exists: true } },\n    ],\n  },\n  includeMetadata: true,\n});\n```\n\n## Limits and Constraints\n\n- **Max vectors per upsert**: 1,000 records (or 2 MB per batch)\n- **Max vectors per upsert (with text)**: 96 records\n- **Metadata size per vector**: 40 KB max\n- **Record ID length**: 512 characters max\n- **Dense vector dimensions**: Up to 20,000\n- **Sparse vector non-zero values**: 2,048 max\n- **Top-K query limit**: 10,000\n\n## Common Patterns\n\n### Pattern: Upsert and Query Flow\n\n```typescript\nimport { Pinecone } from '@pinecone-database/pinecone';\n\nconst pc = new Pinecone();\n\n// Create index\nawait pc.createIndex({\n  name: 'example-index',\n  dimension: 1536,\n  metric: 'cosine',\n  spec: {\n    serverless: { cloud: 'aws', region: 'us-west-2' },\n  },\n  waitUntilReady: true,\n});\n\n// Connect and upsert\nconst index = pc.index('example-index');\nawait index.upsert([\n  {\n    id: 'doc1',\n    values: [0.1, 0.2, 0.3], // ... 1536 dimensions\n    metadata: { title: 'Document 1', category: 'A' },\n  },\n]);\n\n// Query\nconst results = await index.query({\n  vector: [0.1, 0.2, 0.3], // ... 1536 dimensions\n  topK: 5,\n  includeMetadata: true,\n});\n\nconsole.log(results.matches);\n```\n\n### Pattern: Multi-Tenant with Namespaces\n\n```typescript\nconst pc = new Pinecone();\nconst index = pc.index('multi-tenant-index');\n\n// Tenant 1\nconst tenant1 = index.namespace('tenant-1');\nawait tenant1.upsert([\n  { id: 'vec1', values: [0.1, 0.2, 0.3], metadata: { user: 'user1' } },\n]);\n\n// Tenant 2\nconst tenant2 = index.namespace('tenant-2');\nawait tenant2.upsert([\n  { id: 'vec1', values: [0.4, 0.5, 0.6], metadata: { user: 'user2' } },\n]);\n\n// Query tenant-specific data\nconst tenant1Results = await tenant1.query({\n  vector: [0.1, 0.2, 0.3],\n  topK: 5,\n});\n```\n\n### Pattern: Hybrid Search with Weighting\n\n```typescript\n// Alpha controls dense vs sparse weighting\n// alpha=1 is pure dense, alpha=0 is pure sparse\nconst alpha = 0.7;\n\nconst denseVector = [0.1, 0.2, 0.3];\nconst sparseVector = {\n  indices: [10, 45, 16],\n  values: [0.5, 0.5, 0.2],\n};\n\n// Apply weighting\nconst weightedDense = denseVector.map(v => v * alpha);\nconst weightedSparse = {\n  indices: sparseVector.indices,\n  values: sparseVector.values.map(v => v * (1 - alpha)),\n};\n\nconst results = await index.query({\n  vector: weightedDense,\n  sparseVector: weightedSparse,\n  topK: 10,\n  includeMetadata: true,\n});\n```\n"
  },
  {
    "path": "content/pinecone/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Vector database for AI applications with semantic search, hybrid search, reranking, and integrated embeddings\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.3.0\"\n  updated-on: \"2025-10-26\"\n  source: maintainer\n  tags: \"pinecone,sdk,vector-db,ai,search\"\n---\n# Pinecone Python SDK Coding Guidelines\n\nYou are a Pinecone vector database coding expert. Help me with writing code using the Pinecone SDK for Python.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.pinecone.io/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Pinecone Python SDK for all Pinecone vector database interactions. Do not use legacy libraries or unofficial packages.\n\n- **Library Name:** Pinecone Python SDK\n- **PyPI Package:** `pinecone`\n- **Legacy Libraries**: `pinecone-client` (deprecated) and other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `pip install pinecone`\n- **Correct (with optional dependencies):** `pip install \"pinecone[asyncio,grpc]\"`\n\n**APIs and Usage:**\n\n- **Correct:** `from pinecone import Pinecone`\n- **Correct:** `pc = Pinecone(api_key='...')`\n- **Correct:** `pc.create_index(...)`\n- **Correct:** `pc.Index(host=...)`\n- **Incorrect:** `import pinecone` (legacy pattern)\n- **Incorrect:** `pinecone.init()` (deprecated)\n- **Incorrect:** `pinecone.Index('name')` (legacy pattern)\n\n## Installation\n\nInstall the Pinecone SDK using pip:\n\n```bash\npip install pinecone\n```\n\n### With Optional Dependencies\n\nFor enhanced functionality, install with optional dependencies:\n\n```bash\npip install \"pinecone[asyncio,grpc]\"\n```\n\n- `asyncio`: Enables async/await support\n- `grpc`: Enables gRPC for better performance with high-concurrency scenarios\n\n### Alternative Package Managers\n\n**Using uv:**\n```bash\nuv add pinecone\n```\n\n**Using Poetry:**\n```bash\npoetry add pinecone\n```\n\n**Requirements:**\n- Python 3.9 or higher\n- Tested with CPython 3.9 to 3.13\n\n## Initialization and API Key\n\nThe SDK requires creating a `Pinecone` instance for all API calls.\n\n### Using Environment Variable\n\nSet your API key as an environment variable:\n\n```bash\nexport PINECONE_API_KEY=\"your_api_key_here\"\n```\n\nThen initialize:\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone()\n```\n\n### Using Configuration Parameter\n\nPass the API key directly:\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n```\n\n### gRPC Client (Recommended for High Performance)\n\nFor better performance with high-concurrency operations:\n\n```python\nfrom pinecone.grpc import PineconeGRPC as Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n```\n\nThe gRPC client offers multiplexing advantages over REST for parallel processing.\n\n## Creating Indexes\n\n### Serverless Index (Basic)\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_index(\n    name='my-index',\n    dimension=1536,\n    metric='cosine',\n    spec=ServerlessSpec(\n        cloud='aws',\n        region='us-west-2'\n    )\n)\n```\n\n### Serverless Index with Deletion Protection\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_index(\n    name='protected-index',\n    dimension=1536,\n    metric='cosine',\n    spec=ServerlessSpec(\n        cloud='aws',\n        region='us-east-1'\n    ),\n    deletion_protection='enabled'\n)\n```\n\n### Pod-Based Index\n\n```python\nfrom pinecone import Pinecone, PodSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_index(\n    name='pod-index',\n    dimension=1536,\n    metric='cosine',\n    spec=PodSpec(\n        environment='us-west-2',\n        pod_type='p1.x1',\n        pods=1,\n        replicas=1\n    )\n)\n```\n\n### Hybrid Search Index (Sparse-Dense)\n\nFor hybrid search supporting both dense and sparse vectors, use `dotproduct` metric:\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_index(\n    name='hybrid-index',\n    dimension=1024,\n    metric='dotproduct',\n    spec=ServerlessSpec(\n        cloud='aws',\n        region='us-east-1'\n    )\n)\n```\n\n**Note:** The `dotproduct` metric is the only metric that supports sparse-dense hybrid search.\n\n### Using Enums for Type Safety\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec, CloudProvider, AwsRegion, VectorType\n\npc = Pinecone(api_key='your_api_key_here')\n\nindex_config = pc.create_index(\n    name='typed-index',\n    dimension=1536,\n    metric='cosine',\n    spec=ServerlessSpec(\n        cloud=CloudProvider.AWS,\n        region=AwsRegion.US_EAST_1\n    ),\n    vector_type=VectorType.DENSE\n)\n\nprint(index_config.host)\n```\n\n## Index Management\n\n### Describe Index\n\nGet index details including status, dimension, and host:\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nindex_description = pc.describe_index('my-index')\nprint(index_description)\nprint(f\"Host: {index_description.host}\")\n```\n\n### List All Indexes\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nindex_list = pc.list_indexes()\nfor index in index_list:\n    print(index.name)\n```\n\n### Delete Index\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.delete_index('my-index')\n```\n\n### Configure Index (Scale)\n\nFor pod-based indexes, adjust replicas and pod type:\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.configure_index(\n    name='pod-index',\n    replicas=2,\n    pod_type='p1.x2'\n)\n```\n\n### Check if Index Exists\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nif pc.has_index('my-index'):\n    print('Index exists')\nelse:\n    print('Index does not exist')\n```\n\n## Connecting to an Index\n\n### Basic Connection\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\n# Get index host from description\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n```\n\n### Using gRPC Client\n\n```python\nfrom pinecone.grpc import PineconeGRPC as Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n```\n\n## Upserting Vectors\n\n### Dense Vectors (Basic)\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nindex.upsert(\n    vectors=[\n        (\"vec1\", [0.1, 0.2, 0.3, 0.4, 0.5]),\n        (\"vec2\", [0.2, 0.3, 0.4, 0.5, 0.6]),\n    ]\n)\n```\n\n### Dense Vectors with Metadata\n\n```python\nindex.upsert(\n    vectors=[\n        (\"vec1\", [0.1, 0.2, 0.3, 0.4, 0.5], {\"genre\": \"comedy\", \"year\": 2020}),\n        (\"vec2\", [0.2, 0.3, 0.4, 0.5, 0.6], {\"genre\": \"action\", \"year\": 2021}),\n    ]\n)\n```\n\n### Using Dictionary Format\n\n```python\nindex.upsert(\n    vectors=[\n        {\n            \"id\": \"vec1\",\n            \"values\": [0.1, 0.2, 0.3, 0.4, 0.5],\n            \"metadata\": {\"genre\": \"comedy\", \"year\": 2020}\n        },\n        {\n            \"id\": \"vec2\",\n            \"values\": [0.2, 0.3, 0.4, 0.5, 0.6],\n            \"metadata\": {\"genre\": \"action\", \"year\": 2021}\n        }\n    ]\n)\n```\n\n### Namespaced Upsert\n\n```python\nindex.upsert(\n    vectors=[\n        (\"vec1\", [0.1, 0.2, 0.3], {\"category\": \"A\"}),\n    ],\n    namespace='example-namespace'\n)\n```\n\n### Batch Upsert (Large Datasets)\n\nFor upserting many vectors, batch them in groups of up to 1,000 records (max 2 MB per batch):\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nbatch_size = 1000\nvectors = []  # Your vector list\n\nfor i in range(0, len(vectors), batch_size):\n    batch = vectors[i:i + batch_size]\n    index.upsert(vectors=batch)\n```\n\n### Sparse-Dense Vectors (Hybrid Search)\n\n```python\nindex.upsert(\n    vectors=[\n        {\n            \"id\": \"vec1\",\n            \"values\": [0.1, 0.2, 0.3],  # Dense vector\n            \"sparse_values\": {\n                \"indices\": [10, 45, 16],\n                \"values\": [0.5, 0.5, 0.2]\n            },\n            \"metadata\": {\"text\": \"original text content\"}\n        }\n    ]\n)\n```\n\n### Parallel Upsert with Threading\n\nFor better throughput, use parallel upserts:\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\ndef upsert_batch(batch):\n    return index.upsert(vectors=batch)\n\nbatch_size = 1000\nbatches = [vectors[i:i + batch_size] for i in range(0, len(vectors), batch_size)]\n\nwith ThreadPoolExecutor(max_workers=10) as executor:\n    results = list(executor.map(upsert_batch, batches))\n```\n\n## Querying Vectors\n\n### Basic Query (Dense)\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nquery_response = index.query(\n    vector=[0.1, 0.2, 0.3, 0.4, 0.5],\n    top_k=10,\n    include_metadata=True,\n    include_values=False\n)\n\nfor match in query_response.matches:\n    print(f\"ID: {match.id}, Score: {match.score}, Metadata: {match.metadata}\")\n```\n\n### Query with Metadata Filter\n\n```python\nquery_response = index.query(\n    vector=[0.1, 0.2, 0.3, 0.4, 0.5],\n    top_k=5,\n    filter={\"genre\": {\"$eq\": \"comedy\"}},\n    include_metadata=True\n)\n```\n\n### Complex Metadata Filters\n\n```python\n# Multiple conditions with $and\nresponse = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=10,\n    filter={\n        \"$and\": [\n            {\"genre\": {\"$eq\": \"comedy\"}},\n            {\"year\": {\"$gte\": 2020}}\n        ]\n    },\n    include_metadata=True\n)\n\n# Using $or operator\nresponse2 = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=10,\n    filter={\n        \"$or\": [\n            {\"genre\": {\"$eq\": \"comedy\"}},\n            {\"genre\": {\"$eq\": \"drama\"}}\n        ]\n    },\n    include_metadata=True\n)\n\n# Using $in for multiple values\nresponse3 = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=10,\n    filter={\"genre\": {\"$in\": [\"comedy\", \"action\", \"drama\"]}},\n    include_metadata=True\n)\n```\n\n### Query by ID\n\n```python\nquery_response = index.query(\n    id='vec1',\n    top_k=10,\n    include_metadata=True\n)\n```\n\n### Namespaced Query\n\n```python\nquery_response = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=5,\n    namespace='example-namespace',\n    include_metadata=True\n)\n```\n\n### Hybrid Query (Sparse-Dense)\n\n```python\nquery_response = index.query(\n    vector=[0.1, 0.2, 0.3],  # Dense query vector\n    sparse_vector={\n        \"indices\": [10, 45, 16],\n        \"values\": [0.5, 0.5, 0.2]\n    },\n    top_k=10,\n    include_metadata=True\n)\n```\n\n## Fetching Vectors\n\n### Fetch by IDs\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nfetch_response = index.fetch(ids=['vec1', 'vec2', 'vec3'])\nprint(fetch_response.vectors)\n```\n\n### Fetch from Namespace\n\n```python\nfetch_response = index.fetch(\n    ids=['vec1', 'vec2'],\n    namespace='example-namespace'\n)\n\nfor id, vector in fetch_response.vectors.items():\n    print(f\"ID: {id}, Values: {vector.values}, Metadata: {vector.metadata}\")\n```\n\n## Updating Vectors\n\n### Update Values\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nindex.update(\n    id='vec1',\n    values=[0.9, 0.8, 0.7, 0.6, 0.5]\n)\n```\n\n### Update Metadata\n\n```python\nindex.update(\n    id='vec1',\n    set_metadata={\"genre\": \"documentary\", \"year\": 2023}\n)\n```\n\n### Update with Namespace\n\n```python\nindex.update(\n    id='vec1',\n    values=[0.1, 0.2, 0.3],\n    set_metadata={\"updated\": True},\n    namespace='example-namespace'\n)\n```\n\n### Update Both Values and Metadata\n\n```python\nindex.update(\n    id='vec1',\n    values=[0.9, 0.8, 0.7, 0.6, 0.5],\n    set_metadata={\"genre\": \"thriller\", \"updated\": True}\n)\n```\n\n## Deleting Vectors\n\n### Delete by IDs\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nindex.delete(ids=['vec1', 'vec2', 'vec3'])\n```\n\n### Delete with Metadata Filter\n\n```python\nindex.delete(\n    filter={\"genre\": {\"$eq\": \"comedy\"}}\n)\n```\n\n### Delete All in Namespace\n\n```python\nindex.delete(delete_all=True, namespace='example-namespace')\n```\n\n**Warning:** Deleting all records from a namespace will also delete the namespace itself. This operation is irreversible.\n\n### Delete from Specific Namespace\n\n```python\nindex.delete(\n    ids=['vec1', 'vec2'],\n    namespace='example-namespace'\n)\n```\n\n## Index Statistics\n\n### Get Index Stats\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nstats = index.describe_index_stats()\nprint(f\"Total vectors: {stats.total_vector_count}\")\nprint(f\"Dimension: {stats.dimension}\")\nprint(f\"Namespaces: {stats.namespaces}\")\n```\n\n### Get Stats with Filter\n\n```python\nstats = index.describe_index_stats(\n    filter={\"genre\": {\"$eq\": \"comedy\"}}\n)\nprint(f\"Filtered vector count: {stats.total_vector_count}\")\n```\n\n## Integrated Inference (Embeddings)\n\nPinecone provides hosted embedding models through the Inference API.\n\n### Generate Embeddings\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\n# Embed documents\nembeddings = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=[\n        \"Turkey is a classic meat to eat at American Thanksgiving.\",\n        \"Many people enjoy the beautiful mosques in Turkey.\"\n    ],\n    parameters={\n        \"input_type\": \"passage\",\n        \"truncate\": \"END\"\n    }\n)\n\nfor embedding in embeddings:\n    print(f\"Values: {embedding['values'][:5]}...\")  # Show first 5 dimensions\n```\n\n### Embed Queries\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nquery_embedding = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=[\"How should I prepare my turkey?\"],\n    parameters={\n        \"input_type\": \"query\",\n        \"truncate\": \"END\"\n    }\n)\n\n# Use the embedding for querying\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nresults = index.query(\n    vector=query_embedding[0]['values'],\n    top_k=10,\n    include_metadata=True\n)\n```\n\n### Using Enum for Models\n\n```python\nfrom pinecone import Pinecone, EmbedModel\n\npc = Pinecone(api_key='your_api_key_here')\n\nembeddings = pc.inference.embed(\n    model=EmbedModel.Multilingual_E5_Large,\n    inputs=[\"Sample text\"],\n    parameters={\"input_type\": \"passage\"}\n)\n```\n\n### Available Embedding Models\n\n- `multilingual-e5-large`: Efficient dense embedding model trained on multilingual datasets\n- `pinecone-sparse-english-v0`: Sparse embedding model for keyword or hybrid semantic/keyword search\n\n## Sparse Embeddings for Hybrid Search\n\n### Using Pinecone Sparse Embedding\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\n# Generate sparse embeddings\nsparse_embeddings = pc.inference.embed(\n    model=\"pinecone-sparse-english-v0\",\n    inputs=[\n        \"Apple's first product was the Apple I computer.\",\n        \"The company was founded in 1976.\"\n    ],\n    parameters={\n        \"input_type\": \"passage\"\n    }\n)\n\n# Generate dense embeddings\ndense_embeddings = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=[\n        \"Apple's first product was the Apple I computer.\",\n        \"The company was founded in 1976.\"\n    ],\n    parameters={\n        \"input_type\": \"passage\"\n    }\n)\n\n# Upsert both\nindex_config = pc.describe_index('hybrid-index')\nindex = pc.Index(host=index_config.host)\n\nfor i, (dense, sparse) in enumerate(zip(dense_embeddings, sparse_embeddings)):\n    index.upsert(\n        vectors=[{\n            \"id\": f\"doc{i}\",\n            \"values\": dense['values'],\n            \"sparse_values\": {\n                \"indices\": sparse['indices'],\n                \"values\": sparse['values']\n            }\n        }]\n    )\n```\n\n## Namespaces\n\nNamespaces partition records within an index and enable multitenancy.\n\n### Create Namespace (Implicit)\n\nNamespaces are created automatically when you upsert to them:\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\n# Create namespace for customer 1\nindex.upsert(\n    vectors=[(\"vec1\", [0.1, 0.2, 0.3])],\n    namespace='customer-1'\n)\n\n# Create namespace for customer 2\nindex.upsert(\n    vectors=[(\"vec1\", [0.4, 0.5, 0.6])],\n    namespace='customer-2'\n)\n```\n\n### List Namespaces\n\n```python\nstats = index.describe_index_stats()\nprint(list(stats.namespaces.keys()))\n```\n\n### Default Namespace\n\nIf no namespace is specified, vectors are stored in the `\"\"` (empty string) namespace:\n\n```python\n# This uses the default namespace\nindex.upsert(vectors=[(\"vec1\", [0.1, 0.2, 0.3])])\n\n# Equivalent to\nindex.upsert(vectors=[(\"vec1\", [0.1, 0.2, 0.3])], namespace='')\n```\n\n## Reranking\n\nUse Pinecone's reranking models to reorder results by relevance.\n\n### Rerank Results\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\nreranked = pc.inference.rerank(\n    model=\"bge-reranker-v2-m3\",\n    query=\"What is the capital of France?\",\n    documents=[\n        {\"id\": \"doc1\", \"text\": \"Paris is the capital of France.\"},\n        {\"id\": \"doc2\", \"text\": \"London is the capital of England.\"},\n        {\"id\": \"doc3\", \"text\": \"Berlin is the capital of Germany.\"}\n    ],\n    top_n=2,\n    return_documents=True\n)\n\nfor result in reranked.data:\n    print(f\"ID: {result['id']}, Score: {result['score']}, Text: {result.get('document', {}).get('text')}\")\n```\n\n### Rerank Query Results\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\n# First, query for candidates\nquery_response = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=50,\n    include_metadata=True\n)\n\n# Prepare documents for reranking\ndocuments = [\n    {\"id\": match.id, \"text\": match.metadata.get('text', '')}\n    for match in query_response.matches\n]\n\n# Rerank\nreranked = pc.inference.rerank(\n    model=\"bge-reranker-v2-m3\",\n    query=\"User's search query\",\n    documents=documents,\n    top_n=10\n)\n\nprint(reranked)\n```\n\n## Collections (Backups)\n\nCollections are static snapshots of an index that can be used to create new indexes.\n\n### Create Collection\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_collection(\n    name='my-collection',\n    source='my-index'\n)\n```\n\n### List Collections\n\n```python\ncollections = pc.list_collections()\nfor collection in collections:\n    print(collection.name)\n```\n\n### Describe Collection\n\n```python\ncollection_info = pc.describe_collection('my-collection')\nprint(collection_info)\n```\n\n### Create Index from Collection\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\npc.create_index(\n    name='new-index-from-backup',\n    dimension=1536,\n    metric='cosine',\n    spec=ServerlessSpec(\n        cloud='aws',\n        region='us-west-2'\n    ),\n    source_collection='my-collection'\n)\n```\n\n### Delete Collection\n\n```python\npc.delete_collection('my-collection')\n```\n\n## Async Support\n\nThe SDK supports async/await for non-blocking operations.\n\n### Installation with Async Support\n\n```bash\npip install \"pinecone[asyncio]\"\n```\n\n### Async Initialization\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host, async_req=True)\n```\n\n### Async Upsert\n\n```python\nimport asyncio\nfrom pinecone import Pinecone\n\nasync def async_upsert():\n    pc = Pinecone(api_key='your_api_key_here')\n    index_config = pc.describe_index('my-index')\n    index = pc.Index(host=index_config.host, async_req=True)\n\n    await index.upsert(\n        vectors=[(\"vec1\", [0.1, 0.2, 0.3])]\n    )\n\nasyncio.run(async_upsert())\n```\n\n### Async Query\n\n```python\nimport asyncio\nfrom pinecone import Pinecone\n\nasync def async_query():\n    pc = Pinecone(api_key='your_api_key_here')\n    index_config = pc.describe_index('my-index')\n    index = pc.Index(host=index_config.host, async_req=True)\n\n    results = await index.query(\n        vector=[0.1, 0.2, 0.3],\n        top_k=10,\n        include_metadata=True\n    )\n    return results\n\nresults = asyncio.run(async_query())\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom pinecone import Pinecone\nfrom pinecone.exceptions import PineconeException\n\npc = Pinecone(api_key='your_api_key_here')\n\ntry:\n    index_config = pc.describe_index('my-index')\n    index = pc.Index(host=index_config.host)\n\n    results = index.query(\n        vector=[0.1, 0.2, 0.3],\n        top_k=10\n    )\nexcept PineconeException as e:\n    print(f\"Pinecone error: {e}\")\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n### Handling Specific Errors\n\n```python\nfrom pinecone import Pinecone\nfrom pinecone.exceptions import NotFoundException, UnauthorizedException\n\npc = Pinecone(api_key='your_api_key_here')\n\ntry:\n    index_config = pc.describe_index('nonexistent-index')\nexcept NotFoundException:\n    print(\"Index not found\")\nexcept UnauthorizedException:\n    print(\"Invalid API key\")\n```\n\n## Performance Best Practices\n\n### Use gRPC Client for High Throughput\n\n```python\nfrom pinecone.grpc import PineconeGRPC as Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n```\n\nThe gRPC client offers better performance for high-concurrency scenarios.\n\n### Batch Operations\n\nAlways batch upsert operations for better throughput:\n\n```python\n# Good: Batch upsert\nvectors = generate_vectors(1000)\nindex.upsert(vectors=vectors)\n\n# Bad: Individual upserts\nfor vector in vectors:\n    index.upsert(vectors=[vector])  # Don't do this\n```\n\n### Parallel Requests\n\nUse ThreadPoolExecutor for independent parallel operations:\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\ndef query_batch(query_vector):\n    return index.query(vector=query_vector, top_k=5)\n\nquery_vectors = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9]]\n\nwith ThreadPoolExecutor(max_workers=10) as executor:\n    results = list(executor.map(query_batch, query_vectors))\n```\n\n### Connection Reuse\n\nReuse the index connection instead of recreating it:\n\n```python\n# Good: Create once, reuse\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('my-index')\nindex = pc.Index(host=index_config.host)\n\nfor i in range(100):\n    index.query(vector=get_vector(i), top_k=5)\n\n# Bad: Recreate each time\nfor i in range(100):\n    index_config = pc.describe_index('my-index')\n    index = pc.Index(host=index_config.host)  # Don't do this\n    index.query(vector=get_vector(i), top_k=5)\n```\n\n## Metadata Filtering Operators\n\nPinecone supports MongoDB-style query operators for metadata filtering:\n\n- `$eq`: Equal to\n- `$ne`: Not equal to\n- `$gt`: Greater than\n- `$gte`: Greater than or equal to\n- `$lt`: Less than\n- `$lte`: Less than or equal to\n- `$in`: In array\n- `$nin`: Not in array\n- `$exists`: Field exists\n- `$and`: Logical AND\n- `$or`: Logical OR\n\n### Example: Complex Filter\n\n```python\nresults = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=10,\n    filter={\n        \"$and\": [\n            {\"year\": {\"$gte\": 2020, \"$lte\": 2023}},\n            {\n                \"$or\": [\n                    {\"genre\": {\"$eq\": \"comedy\"}},\n                    {\"genre\": {\"$eq\": \"drama\"}}\n                ]\n            },\n            {\"rating\": {\"$exists\": True}}\n        ]\n    },\n    include_metadata=True\n)\n```\n\n## Limits and Constraints\n\n- **Max vectors per upsert**: 1,000 records (or 2 MB per batch)\n- **Max vectors per upsert (with text)**: 96 records\n- **Metadata size per vector**: 40 KB max\n- **Record ID length**: 512 characters max\n- **Dense vector dimensions**: Up to 20,000\n- **Sparse vector non-zero values**: 2,048 max\n- **Top-K query limit**: 10,000\n\n## Common Patterns\n\n### Pattern: Complete Workflow\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\n# Initialize\npc = Pinecone(api_key='your_api_key_here')\n\n# Create index\nif not pc.has_index('example-index'):\n    pc.create_index(\n        name='example-index',\n        dimension=1536,\n        metric='cosine',\n        spec=ServerlessSpec(cloud='aws', region='us-west-2')\n    )\n\n# Connect to index\nindex_config = pc.describe_index('example-index')\nindex = pc.Index(host=index_config.host)\n\n# Upsert vectors\nindex.upsert(\n    vectors=[\n        (\"doc1\", [0.1] * 1536, {\"title\": \"Document 1\", \"category\": \"A\"}),\n        (\"doc2\", [0.2] * 1536, {\"title\": \"Document 2\", \"category\": \"B\"}),\n    ]\n)\n\n# Query\nresults = index.query(\n    vector=[0.1] * 1536,\n    top_k=5,\n    filter={\"category\": {\"$eq\": \"A\"}},\n    include_metadata=True\n)\n\nfor match in results.matches:\n    print(f\"ID: {match.id}, Score: {match.score}, Metadata: {match.metadata}\")\n```\n\n### Pattern: Multi-Tenant with Namespaces\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\nindex_config = pc.describe_index('multi-tenant-index')\nindex = pc.Index(host=index_config.host)\n\n# Tenant 1\nindex.upsert(\n    vectors=[(\"vec1\", [0.1, 0.2, 0.3], {\"user\": \"user1\"})],\n    namespace='tenant-1'\n)\n\n# Tenant 2\nindex.upsert(\n    vectors=[(\"vec1\", [0.4, 0.5, 0.6], {\"user\": \"user2\"})],\n    namespace='tenant-2'\n)\n\n# Query tenant-specific data\ntenant1_results = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=5,\n    namespace='tenant-1'\n)\n\ntenant2_results = index.query(\n    vector=[0.1, 0.2, 0.3],\n    top_k=5,\n    namespace='tenant-2'\n)\n```\n\n### Pattern: Hybrid Search with Integrated Inference\n\n```python\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key='your_api_key_here')\n\n# Create hybrid index\nif not pc.has_index('hybrid-index'):\n    pc.create_index(\n        name='hybrid-index',\n        dimension=1024,\n        metric='dotproduct',\n        spec=ServerlessSpec(cloud='aws', region='us-east-1')\n    )\n\n# Connect to index\nindex_config = pc.describe_index('hybrid-index')\nindex = pc.Index(host=index_config.host)\n\n# Prepare data\ndata = [\n    \"Turkey is a classic meat to eat at American Thanksgiving.\",\n    \"Many people enjoy the beautiful mosques in Turkey.\"\n]\n\n# Generate dense embeddings\ndense_embeddings = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=data,\n    parameters={\"input_type\": \"passage\"}\n)\n\n# Generate sparse embeddings\nsparse_embeddings = pc.inference.embed(\n    model=\"pinecone-sparse-english-v0\",\n    inputs=data,\n    parameters={\"input_type\": \"passage\"}\n)\n\n# Upsert combined vectors\nrecords = []\nfor i, (text, dense, sparse) in enumerate(zip(data, dense_embeddings, sparse_embeddings)):\n    records.append({\n        \"id\": f\"doc{i}\",\n        \"values\": dense['values'],\n        \"sparse_values\": {\n            \"indices\": sparse['indices'],\n            \"values\": sparse['values']\n        },\n        \"metadata\": {\"text\": text}\n    })\n\nindex.upsert(vectors=records)\n\n# Query with hybrid search\nquery = \"How should I prepare my turkey?\"\n\nquery_dense = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=[query],\n    parameters={\"input_type\": \"query\"}\n)\n\nquery_sparse = pc.inference.embed(\n    model=\"pinecone-sparse-english-v0\",\n    inputs=[query],\n    parameters={\"input_type\": \"query\"}\n)\n\n# Apply alpha weighting (0.7 = 70% dense, 30% sparse)\nalpha = 0.7\n\nresults = index.query(\n    vector=[v * alpha for v in query_dense[0]['values']],\n    sparse_vector={\n        \"indices\": query_sparse[0]['indices'],\n        \"values\": [v * (1 - alpha) for v in query_sparse[0]['values']]\n    },\n    top_k=10,\n    include_metadata=True\n)\n\nfor match in results.matches:\n    print(f\"Score: {match.score}, Text: {match.metadata['text']}\")\n```\n\n### Pattern: RAG Pipeline\n\n```python\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key='your_api_key_here')\n\n# Embed and upsert documents\ndocuments = [\n    \"Document 1 text content...\",\n    \"Document 2 text content...\",\n    \"Document 3 text content...\"\n]\n\nembeddings = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=documents,\n    parameters={\"input_type\": \"passage\"}\n)\n\nindex_config = pc.describe_index('rag-index')\nindex = pc.Index(host=index_config.host)\n\nvectors = [\n    (f\"doc{i}\", emb['values'], {\"text\": doc})\n    for i, (doc, emb) in enumerate(zip(documents, embeddings))\n]\n\nindex.upsert(vectors=vectors)\n\n# Query and retrieve context\nuser_query = \"What is the content about?\"\n\nquery_embedding = pc.inference.embed(\n    model=\"multilingual-e5-large\",\n    inputs=[user_query],\n    parameters={\"input_type\": \"query\"}\n)\n\nresults = index.query(\n    vector=query_embedding[0]['values'],\n    top_k=3,\n    include_metadata=True\n)\n\n# Extract context for LLM\ncontext = \"\\n\\n\".join([match.metadata['text'] for match in results.matches])\nprint(f\"Context for LLM:\\n{context}\")\n```\n"
  },
  {
    "path": "content/pinecone-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pinecone-client Python package guide for Pinecone vector database SDK usage and migration to the renamed pinecone package\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pinecone,pinecone-client,vector-database,embeddings,rag,python\"\n---\n\n# pinecone-client Python Package Guide\n\n## Golden Rule\n\n`pinecone-client` is deprecated. For `6.0.0`, treat this package entry as a migration target to the official `pinecone` SDK package:\n\n```bash\npip uninstall pinecone-client\npip install \"pinecone==6.0.0\"\n```\n\nDo not keep both `pinecone-client` and `pinecone` installed in the same environment. Pinecone explicitly warns that this can cause confusing interactions.\n\n## When To Use It\n\nUse Pinecone when your Python app needs a managed vector database for:\n\n- semantic search and retrieval\n- RAG pipelines\n- metadata-filtered nearest-neighbor search\n- hybrid workflows with Pinecone-managed embedding and reranking\n\nFor new code, pin the `pinecone` package version that matches your deployment target. This doc tracks the `6.0.0` line because that is the version used here associated with `pinecone-client`.\n\n## Install\n\n### Standard install\n\n```bash\npip uninstall -y pinecone-client\npip install \"pinecone==6.0.0\"\n```\n\n### gRPC transport for higher-throughput data operations\n\n```bash\npip uninstall -y pinecone-client\npip install \"pinecone[grpc]==6.0.0\"\n```\n\nUse gRPC when `upsert` and `query` throughput matter more than keeping dependencies minimal.\n\n### Async support\n\n```bash\npip uninstall -y pinecone-client\npip install \"pinecone[asyncio]==6.0.0\"\n```\n\nUse the asyncio extra for async web stacks such as FastAPI or `aiohttp`.\n\n## Auth And Configuration\n\nSet your API key before creating a client:\n\n```bash\nexport PINECONE_API_KEY=\"your-api-key\"\nexport PINECONE_INDEX_HOST=\"your-index-host\"\n```\n\n`PINECONE_INDEX_HOST` is the unique DNS host for a specific index. Pinecone recommends targeting indexes by host in production instead of by index name, because using the name forces an extra `describe_index` lookup.\n\nYou can get the host from:\n\n- the Pinecone console\n- `describe_index(name=\"...\")` during setup or provisioning\n\n## Initialize The Client\n\n```python\nimport os\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key=os.environ[\"PINECONE_API_KEY\"])\nindex = pc.Index(host=os.environ[\"PINECONE_INDEX_HOST\"])\n```\n\nFor quick experiments, `pc.Index(\"index-name\")` is convenient. For production code, cache the host and pass `host=...` directly.\n\n## Create An Index\n\nFor vectors generated outside Pinecone:\n\n```python\nimport os\nfrom pinecone import Pinecone, ServerlessSpec\n\npc = Pinecone(api_key=os.environ[\"PINECONE_API_KEY\"])\nindex_name = \"docs-example\"\n\nif not pc.has_index(index_name):\n    pc.create_index(\n        name=index_name,\n        vector_type=\"dense\",\n        dimension=1536,\n        metric=\"cosine\",\n        spec=ServerlessSpec(cloud=\"aws\", region=\"us-east-1\"),\n        deletion_protection=\"disabled\",\n    )\n```\n\nMatch `dimension` and `metric` to the embedding model you actually use. Pinecone will not fix a dimension mismatch for you.\n\n## Core Vector Workflow\n\n### Upsert vectors\n\n```python\nindex.upsert(\n    vectors=[\n        {\n            \"id\": \"vec1\",\n            \"values\": [0.1] * 1536,\n            \"metadata\": {\"genre\": \"comedy\", \"year\": 2020},\n        },\n        {\n            \"id\": \"vec2\",\n            \"values\": [0.2] * 1536,\n            \"metadata\": {\"genre\": \"documentary\", \"year\": 2019},\n        },\n    ],\n    namespace=\"example-namespace\",\n)\n```\n\n### Query by vector\n\n```python\nresults = index.query(\n    namespace=\"example-namespace\",\n    vector=[0.15] * 1536,\n    top_k=3,\n    include_metadata=True,\n    include_values=False,\n    filter={\"genre\": {\"$eq\": \"documentary\"}},\n)\n```\n\n### Fetch by ID\n\n```python\nrecords = index.fetch(\n    ids=[\"vec1\", \"vec2\"],\n    namespace=\"example-namespace\",\n)\n```\n\n### Delete by ID or metadata filter\n\n```python\nindex.delete(ids=[\"vec1\"], namespace=\"example-namespace\")\n\nindex.delete(\n    filter={\"genre\": {\"$eq\": \"documentary\"}},\n    namespace=\"example-namespace\",\n)\n```\n\nPinecone is eventually consistent. After `upsert` or `delete`, allow for a short delay before assuming queries will reflect the latest state.\n\n## Integrated Embedding Workflow\n\nIf you want Pinecone to generate embeddings from source text, create an index configured for a model and use `upsert_records` plus `search`:\n\n```python\nimport os\nfrom pinecone import Pinecone\n\npc = Pinecone(api_key=os.environ[\"PINECONE_API_KEY\"])\nindex_name = \"integrated-search\"\n\nif not pc.has_index(index_name):\n    pc.create_index_for_model(\n        name=index_name,\n        cloud=\"aws\",\n        region=\"us-east-1\",\n        embed={\n            \"model\": \"llama-text-embed-v2\",\n            \"field_map\": {\"text\": \"chunk_text\"},\n        },\n    )\n\nindex = pc.Index(host=os.environ[\"PINECONE_INDEX_HOST\"])\n\nindex.upsert_records(\n    namespace=\"docs\",\n    records=[\n        {\n            \"_id\": \"doc-1\",\n            \"chunk_text\": \"Pinecone stores and searches vectors.\",\n            \"category\": \"guide\",\n        }\n    ],\n)\n\nresults = index.search(\n    namespace=\"docs\",\n    query={\"inputs\": {\"text\": \"vector search setup\"}, \"top_k\": 3},\n    fields=[\"category\", \"chunk_text\"],\n)\n```\n\nUse `search` with text only on indexes that were created with integrated embedding. For regular vector indexes, use `query` with a vector.\n\n## Async And gRPC Variants\n\n### gRPC\n\nThe API shape stays the same, but you import a different client:\n\n```python\nfrom pinecone.grpc import PineconeGRPC as Pinecone\n```\n\nPinecone documents gRPC as a modest performance improvement for data operations such as `upsert` and `query`. It also supports parallel writes with `async_req=True`.\n\n### asyncio\n\n```python\nimport os\nimport asyncio\nfrom pinecone import PineconeAsyncio\n\nasync def main():\n    async with PineconeAsyncio(api_key=os.environ[\"PINECONE_API_KEY\"]) as pc:\n        async with pc.IndexAsyncio(host=os.environ[\"PINECONE_INDEX_HOST\"]) as idx:\n            await idx.query(vector=[0.15] * 1536, top_k=3)\n\nasyncio.run(main())\n```\n\nClose async clients with `async with` so `aiohttp` sessions are cleaned up correctly.\n\n## Common Pitfalls\n\n- Do not install both `pinecone-client` and `pinecone`. Remove the deprecated package first.\n- Do not assume the package name matches the import name. Use `pinecone`, not `pinecone_client`, in code.\n- Do not target an index by name in production hot paths. Cache the index host and use `pc.Index(host=...)`.\n- Do not mix text search and vector query semantics. `search(...)` with text input is for integrated-embedding indexes; `query(...)` is for vector or record-ID search.\n- Do not ignore vector dimensions. The query vector length must match the index dimension.\n- Do not assume namespace APIs are symmetric across transports. For example, `delete_namespace` is documented as not supported with `pinecone[grpc]`.\n- Do not assume immediate read-after-write visibility. Pinecone documents eventual consistency for record freshness.\n\n## Version-Sensitive Notes For 6.0.0\n\n- `6.0.0` is the first major version after Pinecone's package rename guidance. The deprecated `pinecone-client` project on PyPI exists mainly to direct users to `pinecone`.\n- Pinecone maps SDK major versions to API versions. Their Python SDK overview associates `v6.x` with API version `2025-01`.\n- Pinecone's upgrade notes for `6.x` say Python `3.8` support was dropped and Python `3.13` support was added. Treat Python `3.9+` as the safe floor for this version line.\n- Pinecone's current latest SDK docs are ahead of this package version and now describe later major versions as requiring Python `3.10+`. Do not copy that later interpreter requirement back onto a `6.0.0` environment without checking the actual pinned SDK version.\n- Pinecone's upgrade notes also call out `asyncio` support in `6.x` and the removal of some deprecated internal configuration hooks. If you are upgrading older `5.x` code, re-check any custom client initialization.\n\n## Official Sources\n\n- Python SDK overview: `https://docs.pinecone.io/reference/python-sdk`\n- Current SDK reference root: `https://sdk.pinecone.io/python/`\n- SDK upgrading notes: `https://sdk.pinecone.io/python/upgrading.html`\n- Deprecated package registry page: `https://pypi.org/project/pinecone-client/`\n- Canonical runtime package registry page: `https://pypi.org/project/pinecone/`\n"
  },
  {
    "path": "content/pip/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pip package guide for Python installs, environments, requirements, indexes, and configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"26.0.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pip,python,packaging,pypi,requirements,virtualenv\"\n---\n\n# pip Python Package Guide\n\n## Golden Rules\n\n- Use `python -m pip ...` instead of bare `pip ...` when you need to target a specific interpreter.\n- Install into an isolated virtual environment unless you intentionally manage a system or base interpreter.\n- Treat `pip` as a command-line tool, not a library. Do not `import pip` inside application code.\n- Prefer a single trusted index for automated installs. Be careful with `--extra-index-url` because it can introduce dependency-confusion risk.\n\n## What `pip` Is For\n\n`pip` is the standard package installer for Python. It installs packages from package indexes, local archives, local project directories, VCS URLs, and requirement files.\n\nFor coding agents, the common workflow is:\n\n1. Select the correct Python interpreter.\n2. Create or activate a virtual environment.\n3. Upgrade `pip` in that environment.\n4. Install from `requirements.txt`, a constraints file, or explicit package specifiers.\n5. Run `pip check` or equivalent validation before assuming the environment is usable.\n\n## Install and Bootstrap\n\n### Check the active `pip`\n\n```bash\npython -m pip --version\npython3 -m pip --version\npy -m pip --version\n```\n\n### Upgrade `pip`\n\n```bash\npython -m pip install --upgrade pip\n```\n\n### If `pip` is missing\n\nUse `ensurepip` where it is available:\n\n```bash\npython -m ensurepip --upgrade\n```\n\nThe official installation guide also provides `get-pip.py` for bootstrap scenarios where `pip` is not already present.\n\n## Recommended Environment Setup\n\nCreate a virtual environment and upgrade `pip` inside it:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n```\n\nWindows PowerShell:\n\n```powershell\npy -m venv .venv\n.venv\\Scripts\\Activate.ps1\npy -m pip install --upgrade pip\n```\n\nIf `pip` is installed for one interpreter but you need to manage another, use the global `--python` option:\n\n```bash\npython -m pip --python /path/to/python install requests\n```\n\nThat is the safest way to avoid installing into the wrong environment when multiple Python versions are present.\n\n## Core Commands\n\n### Install packages\n\n```bash\npython -m pip install requests\npython -m pip install \"urllib3>=2,<3\"\npython -m pip install ./local-project\npython -m pip install \"git+https://github.com/pypa/pip.git\"\n```\n\n### Upgrade or reinstall\n\n```bash\npython -m pip install --upgrade requests\npython -m pip install --force-reinstall requests\n```\n\n### Uninstall\n\n```bash\npython -m pip uninstall requests\n```\n\n### Inspect what is installed\n\n```bash\npython -m pip list\npython -m pip show requests\npython -m pip freeze\npython -m pip check\n```\n\nUse `pip freeze` for a snapshot of installed distributions. Use `pip check` to detect broken or incompatible installed requirements after changes.\n\n## Requirements, Constraints, and Repeatable Installs\n\n### Install from a requirements file\n\n```bash\npython -m pip install -r requirements.txt\n```\n\nGenerate a simple pinned snapshot:\n\n```bash\npython -m pip freeze > requirements.txt\n```\n\n### Use constraints to limit resolver choices\n\n```bash\npython -m pip install -r requirements.txt -c constraints.txt\n```\n\nConstraints files do not trigger installation by themselves. They only limit versions that the resolver may choose for requirements requested elsewhere.\n\n### Build constraints\n\nFor modern `pip`, build constraints can restrict versions used only inside isolated build environments:\n\n```bash\npython -m pip install --build-constraint build-constraints.txt .\n```\n\nThis is useful when builds need older or pinned build dependencies without constraining the final runtime environment.\n\n### Hash-checking mode for stronger repeatability\n\n```bash\npython -m pip install --require-hashes -r requirements.txt\n```\n\nUse this when you need repeatable installs with explicit artifact hashes.\n\n## Indexes, Private Repositories, and Authentication\n\n### Install from a specific index\n\n```bash\npython -m pip install --index-url https://pypi.org/simple requests\n```\n\n### Add credentials in the URL\n\n```bash\npython -m pip install --index-url https://username:password@example.com/simple internal-package\n```\n\nFor HTTP basic auth, credentials can be embedded in the index URL. If a username or password contains reserved characters, percent-encode them.\n\n### Prefer a single trusted index in automation\n\n`--extra-index-url` is convenient, but the official docs warn it is unsafe because a public package can be chosen instead of an internal one. If you must use a private repository, prefer a single authoritative index or a controlled mirror.\n\n### Keyring behavior\n\n`pip` can use keyring integrations for credential lookup. In non-interactive automation, `--no-input` disables prompting, which can also affect keyring usage.\n\n## Configuration\n\n`pip` reads settings from three places, in this order of precedence:\n\n1. Command-line options\n2. Environment variables\n3. Configuration files\n\n### Useful environment variables\n\n```bash\nexport PIP_INDEX_URL=https://mirror.example.com/simple\nexport PIP_EXTRA_INDEX_URL=https://packages.example.com/simple\nexport PIP_TIMEOUT=60\n```\n\nLong command-line options map to environment variables as `PIP_<OPTION_NAME>`. For example, `--index-url` becomes `PIP_INDEX_URL`.\n\n### Configure with `pip config`\n\n```bash\npython -m pip config set global.index-url https://mirror.example.com/simple\npython -m pip config set global.timeout 60\npython -m pip config list\n```\n\n### Common config file locations\n\n- Unix global: `/etc/xdg/pip/pip.conf`, then `/etc/pip.conf`\n- macOS global: `/Library/Application Support/pip/pip.conf`\n- User config: `~/.config/pip/pip.conf`\n- Legacy user config: `~/.pip/pip.conf`\n- Virtualenv site config: `$VIRTUAL_ENV/pip.conf`\n- Windows user config: `%APPDATA%\\\\pip\\\\pip.ini`\n\nUse the site-specific config inside a virtual environment when a project needs settings that should not leak into the user or system interpreter.\n\n## Common Pitfalls\n\n### Installing into the wrong interpreter\n\nThis is the most common `pip` mistake on systems with multiple Python versions. Prefer:\n\n```bash\npython -m pip install ...\n```\n\nnot:\n\n```bash\npip install ...\n```\n\n### Using `pip` outside a virtual environment by default\n\nProject dependencies installed into a global interpreter are harder to reproduce and easier to break. Use `venv` unless you have an explicit reason not to.\n\n### Importing `pip` as a library\n\nThe official user guide says you must not use `pip`'s internal APIs from your code. If you need package-management automation, shell out to `python -m pip` with `subprocess.run(...)`.\n\n### Trusting `pip freeze` as a full lock workflow\n\n`pip freeze` captures what is installed now. It does not replace reviewing resolver behavior, index policy, platform differences, or build dependencies.\n\n### Mixing public and private indexes casually\n\nIf the same package name can exist on both public and private indexes, the wrong distribution may be selected. This matters most when using `--extra-index-url`.\n\n## Version-Sensitive Notes for `26.0.1`\n\n- The `pip lock` command now exists in the stable command set, but lockfile workflows are still newer than classic `requirements.txt` plus constraints patterns. Check the current command page before standardizing on it across teams.\n- Build constraints are documented as available starting in `25.3`. Older `pip` versions do not support `--build-constraint`.\n- `pip` only supports Python versions that are not end-of-life. On older Python interpreters, you may need an older `pip` release instead of `26.0.1`.\n\n## Minimal Automation Pattern\n\n```python\nimport subprocess\nimport sys\n\ndef pip(*args: str) -> None:\n    subprocess.run([sys.executable, \"-m\", \"pip\", *args], check=True)\n\npip(\"install\", \"--upgrade\", \"pip\")\npip(\"install\", \"-r\", \"requirements.txt\")\npip(\"check\")\n```\n\nThis keeps `pip` bound to the current interpreter and avoids relying on unsupported internal imports.\n\n## Official URLs\n\n- Documentation: https://pip.pypa.io/en/stable/\n- Installation: https://pip.pypa.io/en/stable/installation/\n- User guide: https://pip.pypa.io/en/stable/user_guide/\n- Configuration: https://pip.pypa.io/en/stable/topics/configuration/\n- Authentication: https://pip.pypa.io/en/stable/topics/authentication/\n- Install command reference: https://pip.pypa.io/en/stable/cli/pip_install/\n- Lock command reference: https://pip.pypa.io/en/stable/cli/pip_lock/\n- PyPI package: https://pypi.org/project/pip/\n"
  },
  {
    "path": "content/pip-tools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pip-tools package guide for Python projects using pip-compile and pip-sync to produce reproducible dependency locks\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.5.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pip-tools,pip-compile,pip-sync,packaging,dependencies,python\"\n---\n\n# pip-tools Python Package Guide\n\n## Golden Rule\n\nUse `pip-tools` as a command-line workflow, not as an application library. Treat `pip-compile` as the lockfile generator, treat `pip-sync` as the environment reconciler, and run both from the same Python version and platform you are targeting because the resolved output can vary across environments.\n\n## Install\n\nInstall `pip-tools` into the same virtual environment you use for dependency management:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pip-tools==7.5.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv tool install \"pip-tools==7.5.3\"\npipx install \"pip-tools==7.5.3\"\n```\n\nIf you use `uv tool install` or `pipx`, keep in mind that the tool still resolves packages for the interpreter and platform it runs under. Compile inside the target project environment when the output must match deploy-time markers or wheel availability.\n\n## Initialize A Lockfile Workflow\n\n### Recommended: compile from `pyproject.toml`\n\n`pip-tools` can read dependencies directly from `pyproject.toml`:\n\n```toml\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\ndependencies = [\n  \"django>=5.2,<5.3\",\n  \"httpx>=0.28,<0.29\",\n]\n\n[project.optional-dependencies]\ndev = [\n  \"pytest>=8.3,<9\",\n  \"ruff>=0.11,<0.12\",\n]\n```\n\nCompile the default dependency set:\n\n```bash\npython -m piptools compile -o requirements.txt pyproject.toml\n```\n\nCompile an extra into a separate lock file:\n\n```bash\npython -m piptools compile --extra dev -o dev-requirements.txt pyproject.toml\n```\n\n### Alternative: compile from `requirements.in`\n\nIf the project does not use PEP 621 metadata yet, keep direct requirements in a small input file and compile it:\n\n```txt\n# requirements.in\ndjango>=5.2,<5.3\nhttpx>=0.28,<0.29\n```\n\n```bash\npython -m piptools compile requirements.in\n```\n\nThe default output is `requirements.txt` next to the input file.\n\n## Core Commands\n\n### Generate a lock file\n\nBasic compile:\n\n```bash\npython -m piptools compile -o requirements.txt pyproject.toml\n```\n\nGenerate hashes for repeatable installs:\n\n```bash\npython -m piptools compile --generate-hashes -o requirements.txt pyproject.toml\n```\n\nRe-resolve everything from scratch:\n\n```bash\npython -m piptools compile --rebuild -o requirements.txt pyproject.toml\n```\n\nUpgrade all packages:\n\n```bash\npython -m piptools compile --upgrade -o requirements.txt pyproject.toml\n```\n\nUpgrade only one or two packages while leaving the rest pinned:\n\n```bash\npython -m piptools compile \\\n  --upgrade-package django \\\n  --upgrade-package httpx \\\n  -o requirements.txt \\\n  pyproject.toml\n```\n\nImportant behavior: if an output file already exists, `pip-compile` uses its existing pins as constraints unless you explicitly ask for upgrades or delete the file.\n\n### Sync an environment to the lock file\n\nApply the compiled requirements to the current environment:\n\n```bash\npython -m piptools sync requirements.txt\n```\n\nSync multiple lock files together:\n\n```bash\npython -m piptools sync requirements.txt dev-requirements.txt\n```\n\n`pip-sync` installs missing packages, updates mismatched ones, and uninstalls packages that are not present in the compiled files. The docs note one important exception: it does not upgrade or uninstall packaging tools such as `pip`, `setuptools`, or `pip-tools` itself.\n\n### Layer production and development requirements\n\nUse a compiled base file as a constraint for a dev file:\n\n```txt\n# requirements.in\ndjango>=5.2,<5.3\nhttpx>=0.28,<0.29\n```\n\n```txt\n# dev-requirements.in\n-c requirements.txt\npytest>=8.3,<9\nruff>=0.11,<0.12\n```\n\n```bash\npython -m piptools compile requirements.in\npython -m piptools compile dev-requirements.in\npython -m piptools sync requirements.txt dev-requirements.txt\n```\n\nThis keeps development-only tools from changing the production dependency set.\n\n## Configuration And Package Indexes\n\nBoth `pip-compile` and `pip-sync` can read defaults from `.pip-tools.toml` or `pyproject.toml`. The docs show these lookup rules:\n\n- `.pip-tools.toml` is checked first\n- `pyproject.toml` is checked next\n- command-line flags still override config values\n\nExample `pyproject.toml` configuration:\n\n```toml\n[tool.pip-tools]\ngenerate_hashes = true\nallow_unsafe = false\n\n[tool.pip-tools.compile]\nresolver = \"backtracking\"\ndry_run = false\nextra_index_url = [\"https://pypi.mycompany.example/simple\"]\n```\n\nUse list values in TOML for options that can be repeated on the CLI, such as `extra_index_url`, `find_links`, or `upgrade_package`.\n\n### Private indexes and credentials\n\n`pip-tools` follows pip's index configuration model. In practice, prefer one of these:\n\n- `PIP_INDEX_URL` and `PIP_EXTRA_INDEX_URL` in the environment\n- pip config files managed by `pip config`\n- a secrets manager that injects index credentials at runtime\n\nExample:\n\n```bash\nexport PIP_INDEX_URL=\"https://__token__:${PYPI_TOKEN}@pypi.mycompany.example/simple\"\npython -m piptools compile --generate-hashes -o requirements.txt pyproject.toml\n```\n\nBe careful with `--emit-index-url` or config that writes index URLs into generated output. If your index URL contains credentials, do not commit those lock files without sanitizing the emitted URL.\n\n## Common Pitfalls\n\n- `pip-tools` lock files are environment-sensitive. Compile separately for different Python versions, operating systems, or platforms when markers and wheel availability differ.\n- A stale `requirements.txt` can silently constrain future resolves. Use `--upgrade`, `--upgrade-package`, or `--rebuild` when you actually want new versions.\n- `pip-sync` is for compiled outputs, not loose input files. Syncing from hand-edited requirement sets defeats the point of the workflow.\n- Compiling with hashes against private or extra indexes is exactly where misconfigured index URLs surface. Validate the generated file and a fresh install path, not just the compile step.\n- `piptools` has private API documentation, which is a signal that internals are not a stable integration surface. For automation, prefer shelling out to `pip-compile` and `pip-sync` instead of importing `piptools.*`.\n- Agents often forget that `pip-sync` mutates the current environment aggressively. Do not point it at a shared global interpreter.\n\n## Version-Sensitive Notes For 7.5.3\n\n- PyPI lists `7.5.3` as the current release, and the versioned stable docs match that release.\n- `7.5.3` requires Python `>=3.9`. The changelog records Python 3.8 support as dropped in this release.\n- The `7.5.3` changelog also calls out compatibility fixes for `pip 26.0`.\n- If you use `--generate-hashes` together with private or extra package indexes, `7.5.3` matters: the changelog notes a fix so index URL options are preserved while looking up hashes.\n- The changelog also notes normalization for `--unsafe-package`; use canonical package names in automation and avoid depending on older casing behavior.\n\n## Official Sources\n\n- Stable docs root: `https://pip-tools.readthedocs.io/en/stable/`\n- `pip-compile` reference: `https://pip-tools.readthedocs.io/en/stable/cli/pip-compile/`\n- `pip-sync` reference: `https://pip-tools.readthedocs.io/en/stable/cli/pip-sync/`\n- Changelog: `https://pip-tools.readthedocs.io/en/stable/changelog/`\n- PyPI release page: `https://pypi.org/project/pip-tools/7.5.3/`\n"
  },
  {
    "path": "content/pipdeptree/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pipdeptree CLI for inspecting installed Python package dependency trees and dependency conflicts\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.31.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,pip,packaging,dependencies,cli,virtualenv\"\n---\n\n# pipdeptree Python Package Guide\n\n## Golden Rule\n\n`pipdeptree` reports the packages installed in one Python environment. Run it against the exact interpreter or virtualenv your project uses, or the output will describe the wrong dependency graph.\n\n## Install\n\nInstall it into the environment you want to inspect:\n\n```bash\npython -m pip install \"pipdeptree==2.31.0\"\n```\n\nIf you want Graphviz output formats, install the optional extra:\n\n```bash\npython -m pip install \"pipdeptree[graphviz]==2.31.0\"\n```\n\nTypical project-local setup:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install -r requirements.txt\npython -m pip install \"pipdeptree==2.31.0\"\n```\n\n## Environment Targeting\n\n`pipdeptree` has no authentication or service configuration. The important setup is choosing the correct Python environment.\n\nIf you are already inside the right virtualenv, just run:\n\n```bash\npipdeptree\n```\n\nIf you want to inspect a specific interpreter:\n\n```bash\npipdeptree --python /path/to/project/.venv/bin/python\n```\n\nIf your virtualenv is active or discoverable, `2.21.0+` supports automatic interpreter detection:\n\n```bash\npipdeptree --python auto\n```\n\nUseful environment-scoping flags:\n\n- `--path /some/site-packages`: restrict package discovery to one or more paths\n- `--local-only`: hide globally installed packages when the virtualenv can see them\n- `--user-only`: inspect only the user site directory\n\n## Core Usage\n\n### Print the dependency tree\n\n```bash\npipdeptree\n```\n\nThis is the default text output. Warnings about conflicting or cyclic dependencies are printed to `stderr`.\n\n### Show only selected packages\n\n```bash\npipdeptree --packages requests,urllib3\n```\n\nWildcards are supported in package filters, for example `somepackage.*`.\n\n### Find why a package is installed\n\nUse reverse mode to show which installed packages depend on a package:\n\n```bash\npipdeptree --reverse --packages urllib3\n```\n\n### Fail CI on dependency warnings\n\n```bash\npipdeptree --warn fail\n```\n\n`--warn fail` keeps warnings visible and exits non-zero if conflicts or cycles are found. Use this for CI checks. Use `--warn silence` when you need machine-readable output without warnings on `stderr`.\n\n### Limit tree depth\n\n```bash\npipdeptree --depth 2\n```\n\nThis is useful when you only need the top of the graph instead of the full transitive tree.\n\n### Exclude noisy packages\n\n```bash\npipdeptree --exclude pip,setuptools,wheel\n```\n\nCombine with `--exclude-dependencies` if you want excluded packages and their dependency subtrees omitted.\n\n## Machine-Readable Output\n\n`2.30.0+` prefers `-o/--output` instead of the older dedicated output flags.\n\nJSON formats:\n\n```bash\npipdeptree -o json > deps.json\npipdeptree -o json-tree > deps-tree.json\n```\n\nFreeze-style output:\n\n```bash\npipdeptree -o freeze --warn silence > locked-requirements.txt\n```\n\nMermaid flowchart output:\n\n```bash\npipdeptree -o mermaid > deps.mmd\n```\n\nGraphviz output:\n\n```bash\npipdeptree -o graphviz-dot > deps.dot\npipdeptree -o graphviz-svg > deps.svg\n```\n\nInstall the `graphviz` extra before using Graphviz renderers.\n\n## Common Pitfalls\n\n- Wrong interpreter: the most common mistake is running `pipdeptree` outside the project virtualenv and inspecting the wrong site-packages.\n- Warnings on `stderr`: parsers often fail because the tree is on `stdout` while conflict/cycle warnings are on `stderr`. Use `--warn silence` for clean machine output.\n- Deprecated flags: `-f`, `--json`, `--json-tree`, `--mermaid`, and `--graph-output` still exist in `2.31.0` but are deprecated in favor of `-o/--output`.\n- Not a resolver: `pipdeptree` only inspects already installed packages. It does not solve dependencies from a requirements file or lock file.\n- Pip internals: the project documents that it relies on pip internals, so unpinned `pip` upgrades can occasionally break automation.\n- Optional Graphviz support: `graphviz-*` outputs need the `graphviz` extra and the relevant Graphviz tooling available.\n\n## Version-Sensitive Notes\n\n- The version used here `2.31.0` matches the live PyPI release as of March 12, 2026.\n- `2.30.0` introduced `-o/--output` and deprecated the older output-specific flags. Prefer the new interface in new scripts.\n- `2.31.0` added `--depth` support for Graphviz output, so depth-limited graph exports depend on at least this release.\n- `--python auto` requires `2.21.0` or later. Do not assume it exists in older project environments.\n\n## Official Sources\n\n- Repository and README: `https://github.com/tox-dev/pipdeptree`\n- Changelog: `https://github.com/tox-dev/pipdeptree/blob/main/CHANGELOG.md`\n- PyPI project page: `https://pypi.org/project/pipdeptree/`\n- PyPI JSON metadata: `https://pypi.org/pypi/pipdeptree/json`\n"
  },
  {
    "path": "content/plaid/docs/banking/javascript/DOC.md",
    "content": "---\nname: banking\ndescription: \"Plaid API Coding Guidelines for JavaScript/TypeScript using the official Plaid libraries and SDKs\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"39.1.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"plaid,banking,fintech,payments,financial-data\"\n---\n\n# Plaid API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Plaid API coding expert. Help me with writing code using the Plaid API calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Plaid Node.js SDK for all Plaid API interactions.\n\n- **Library Name:** Plaid Node.js SDK\n- **NPM Package:** `plaid`\n- **Current Version:** 39.1.0\n\n**Installation:**\n\n```bash\nnpm install plaid\n```\n\n**Import Patterns:**\n\n```typescript\n// Correct - ES6 import\nimport { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';\n\n// Correct - CommonJS\nconst { Configuration, PlaidApi, PlaidEnvironments } = require('plaid');\n```\n\n**Important Notes:**\n\n- The plaid-node client library is updated monthly\n- Always use a recent version of the library for new endpoints and fields support\n- This library uses semantic versioning with breaking changes indicated by major version bumps\n- The library is generated from the OpenAPI spec\n\n## Initialization and Authentication\n\nThe Plaid library requires creating a `Configuration` object and `PlaidApi` client instance for all API calls.\n\n```typescript\nimport { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';\n\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.sandbox,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n\nconst plaidClient = new PlaidApi(configuration);\n```\n\n### Environment Configuration\n\nPlaid has multiple environments for different use cases:\n\n```typescript\n// Sandbox - for testing with stateful test data\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.sandbox,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_SANDBOX_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n\n// Development - for testing with live credentials\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.development,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_DEVELOPMENT_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n\n// Production - for live users\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.production,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_PRODUCTION_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n```\n\n### Environment Variables Setup\n\n```bash\n# .env file\nPLAID_CLIENT_ID=your_client_id_here\nPLAID_SANDBOX_SECRET=your_sandbox_secret_here\nPLAID_DEVELOPMENT_SECRET=your_development_secret_here\nPLAID_PRODUCTION_SECRET=your_production_secret_here\n```\n\n```typescript\n// Load environment variables\nimport dotenv from 'dotenv';\ndotenv.config();\n\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.sandbox,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_SANDBOX_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n```\n\n## Core Plaid Flow\n\nThe standard Plaid integration flow follows these steps:\n\n1. Create a link_token\n2. Initialize Plaid Link on the frontend\n3. Receive a public_token from Link\n4. Exchange the public_token for an access_token\n5. Use the access_token to make API requests\n\n### Step 1: Create Link Token\n\nCreate a temporary link_token to authenticate your app with Plaid Link:\n\n```typescript\nimport {\n  Configuration,\n  PlaidApi,\n  PlaidEnvironments,\n  Products,\n  CountryCode\n} from 'plaid';\n\nconst plaidClient = new PlaidApi(configuration);\n\nasync function createLinkToken(userId: string) {\n  const request = {\n    user: {\n      client_user_id: userId,\n    },\n    client_name: 'My Application',\n    products: [Products.Auth, Products.Transactions],\n    country_codes: [CountryCode.Us],\n    language: 'en',\n    webhook: 'https://your-domain.com/plaid/webhook',\n  };\n\n  try {\n    const response = await plaidClient.linkTokenCreate(request);\n    const linkToken = response.data.link_token;\n    return linkToken;\n  } catch (error) {\n    console.error('Error creating link token:', error);\n    throw error;\n  }\n}\n```\n\n### Step 2: Exchange Public Token for Access Token\n\nAfter the user completes the Link flow, exchange the public_token for a permanent access_token:\n\n```typescript\nasync function exchangePublicToken(publicToken: string) {\n  try {\n    const response = await plaidClient.itemPublicTokenExchange({\n      public_token: publicToken,\n    });\n\n    const accessToken = response.data.access_token;\n    const itemId = response.data.item_id;\n\n    // Store these securely in your database\n    console.log('Access Token:', accessToken);\n    console.log('Item ID:', itemId);\n\n    return { accessToken, itemId };\n  } catch (error) {\n    console.error('Error exchanging public token:', error);\n    throw error;\n  }\n}\n```\n\n## Product APIs\n\n### Auth - Account and Routing Numbers\n\nRetrieve bank account and routing numbers for ACH transfers:\n\n```typescript\nasync function getAuthData(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.authGet(request);\n    const accounts = response.data.accounts;\n    const numbers = response.data.numbers;\n\n    console.log('Accounts:', accounts);\n    console.log('Account Numbers:', numbers.ach);\n    console.log('Routing Numbers:', numbers.ach[0].routing);\n\n    return { accounts, numbers };\n  } catch (error) {\n    console.error('Error getting auth data:', error);\n    throw error;\n  }\n}\n```\n\n**Advanced Auth with Options:**\n\n```typescript\nasync function getAuthDataWithOptions(accessToken: string, accountIds?: string[]) {\n  try {\n    const request = {\n      access_token: accessToken,\n      options: {\n        account_ids: accountIds, // Optional: filter specific accounts\n      },\n    };\n\n    const response = await plaidClient.authGet(request);\n    return response.data;\n  } catch (error) {\n    console.error('Error getting auth data:', error);\n    throw error;\n  }\n}\n```\n\n### Accounts - Retrieve Account Information\n\nGet account details including balances and metadata:\n\n```typescript\nasync function getAccounts(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.accountsGet(request);\n    const accounts = response.data.accounts;\n\n    accounts.forEach(account => {\n      console.log('Account ID:', account.account_id);\n      console.log('Name:', account.name);\n      console.log('Type:', account.type);\n      console.log('Subtype:', account.subtype);\n      console.log('Current Balance:', account.balances.current);\n      console.log('Available Balance:', account.balances.available);\n    });\n\n    return accounts;\n  } catch (error) {\n    console.error('Error getting accounts:', error);\n    throw error;\n  }\n}\n```\n\n### Balance - Real-time Balance Information\n\nGet up-to-date balance information:\n\n```typescript\nasync function getBalance(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.accountsBalanceGet(request);\n    const accounts = response.data.accounts;\n\n    accounts.forEach(account => {\n      console.log(`${account.name}: $${account.balances.current}`);\n      console.log(`Available: $${account.balances.available}`);\n      console.log(`Currency: ${account.balances.iso_currency_code}`);\n    });\n\n    return accounts;\n  } catch (error) {\n    console.error('Error getting balance:', error);\n    throw error;\n  }\n}\n```\n\n**Advanced Balance with Account Filtering:**\n\n```typescript\nasync function getBalanceForSpecificAccounts(\n  accessToken: string,\n  accountIds: string[]\n) {\n  try {\n    const request = {\n      access_token: accessToken,\n      options: {\n        account_ids: accountIds,\n      },\n    };\n\n    const response = await plaidClient.accountsBalanceGet(request);\n    return response.data.accounts;\n  } catch (error) {\n    console.error('Error getting balance:', error);\n    throw error;\n  }\n}\n```\n\n### Identity - Account Holder Information\n\nRetrieve identity information for account holders:\n\n```typescript\nasync function getIdentity(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.identityGet(request);\n    const accounts = response.data.accounts;\n\n    accounts.forEach(account => {\n      console.log('Account:', account.name);\n      account.owners.forEach(owner => {\n        console.log('Name:', owner.names);\n        console.log('Email:', owner.emails);\n        console.log('Phone:', owner.phone_numbers);\n        console.log('Address:', owner.addresses);\n      });\n    });\n\n    return response.data;\n  } catch (error) {\n    console.error('Error getting identity:', error);\n    throw error;\n  }\n}\n```\n\n### Transactions - Transaction History\n\nPlaid provides two methods for retrieving transactions: `/transactions/get` (legacy) and `/transactions/sync` (recommended).\n\n#### Transactions Sync (Recommended)\n\nThe `/transactions/sync` endpoint provides incremental updates and is the recommended approach:\n\n```typescript\nasync function syncTransactions(accessToken: string, cursor?: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n      cursor: cursor || undefined,\n      count: 100, // Number of transactions to fetch (max 500)\n    };\n\n    const response = await plaidClient.transactionsSync(request);\n\n    console.log('Added transactions:', response.data.added.length);\n    console.log('Modified transactions:', response.data.modified.length);\n    console.log('Removed transactions:', response.data.removed.length);\n    console.log('Next cursor:', response.data.next_cursor);\n    console.log('Has more:', response.data.has_more);\n\n    // Process transactions\n    response.data.added.forEach(transaction => {\n      console.log('Date:', transaction.date);\n      console.log('Name:', transaction.name);\n      console.log('Amount:', transaction.amount);\n      console.log('Category:', transaction.category);\n    });\n\n    return response.data;\n  } catch (error) {\n    console.error('Error syncing transactions:', error);\n    throw error;\n  }\n}\n```\n\n**Paginated Transaction Sync:**\n\n```typescript\nasync function getAllTransactions(accessToken: string) {\n  let cursor: string | undefined = undefined;\n  let allTransactions: any[] = [];\n  let hasMore = true;\n\n  try {\n    while (hasMore) {\n      const request = {\n        access_token: accessToken,\n        cursor: cursor,\n        count: 500, // Use maximum for efficiency\n      };\n\n      const response = await plaidClient.transactionsSync(request);\n\n      allTransactions = allTransactions.concat(response.data.added);\n      cursor = response.data.next_cursor;\n      hasMore = response.data.has_more;\n\n      console.log(`Fetched ${response.data.added.length} transactions`);\n    }\n\n    console.log(`Total transactions: ${allTransactions.length}`);\n    return allTransactions;\n  } catch (error) {\n    console.error('Error getting all transactions:', error);\n    throw error;\n  }\n}\n```\n\n#### Transactions Get (Legacy)\n\nFor retrieving transactions within a specific date range:\n\n```typescript\nasync function getTransactions(\n  accessToken: string,\n  startDate: string,\n  endDate: string\n) {\n  try {\n    const request = {\n      access_token: accessToken,\n      start_date: startDate, // Format: 'YYYY-MM-DD'\n      end_date: endDate,     // Format: 'YYYY-MM-DD'\n      options: {\n        count: 250,\n        offset: 0,\n      },\n    };\n\n    const response = await plaidClient.transactionsGet(request);\n    const transactions = response.data.transactions;\n    const totalTransactions = response.data.total_transactions;\n\n    console.log(`Retrieved ${transactions.length} of ${totalTransactions}`);\n\n    return transactions;\n  } catch (error) {\n    console.error('Error getting transactions:', error);\n    throw error;\n  }\n}\n```\n\n**Paginated Transactions Get:**\n\n```typescript\nasync function getAllTransactionsInRange(\n  accessToken: string,\n  startDate: string,\n  endDate: string\n) {\n  let offset = 0;\n  const batchSize = 500;\n  let allTransactions: any[] = [];\n  let totalTransactions = 0;\n\n  try {\n    do {\n      const request = {\n        access_token: accessToken,\n        start_date: startDate,\n        end_date: endDate,\n        options: {\n          count: batchSize,\n          offset: offset,\n        },\n      };\n\n      const response = await plaidClient.transactionsGet(request);\n      const transactions = response.data.transactions;\n      totalTransactions = response.data.total_transactions;\n\n      allTransactions = allTransactions.concat(transactions);\n      offset += transactions.length;\n\n      console.log(`Fetched ${allTransactions.length} of ${totalTransactions}`);\n    } while (allTransactions.length < totalTransactions);\n\n    return allTransactions;\n  } catch (error) {\n    console.error('Error getting all transactions:', error);\n    throw error;\n  }\n}\n```\n\n### Investments - Holdings and Transactions\n\nRetrieve investment account holdings and transactions:\n\n```typescript\nasync function getInvestmentHoldings(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.investmentsHoldingsGet(request);\n    const holdings = response.data.holdings;\n    const securities = response.data.securities;\n\n    holdings.forEach(holding => {\n      const security = securities.find(s => s.security_id === holding.security_id);\n      console.log('Security:', security?.name);\n      console.log('Ticker:', security?.ticker_symbol);\n      console.log('Quantity:', holding.quantity);\n      console.log('Institution Price:', holding.institution_price);\n      console.log('Value:', holding.institution_value);\n    });\n\n    return { holdings, securities };\n  } catch (error) {\n    console.error('Error getting investment holdings:', error);\n    throw error;\n  }\n}\n```\n\n**Investment Transactions:**\n\n```typescript\nasync function getInvestmentTransactions(\n  accessToken: string,\n  startDate: string,\n  endDate: string\n) {\n  try {\n    const request = {\n      access_token: accessToken,\n      start_date: startDate,\n      end_date: endDate,\n    };\n\n    const response = await plaidClient.investmentsTransactionsGet(request);\n    const transactions = response.data.investment_transactions;\n\n    transactions.forEach(transaction => {\n      console.log('Date:', transaction.date);\n      console.log('Name:', transaction.name);\n      console.log('Type:', transaction.type);\n      console.log('Amount:', transaction.amount);\n      console.log('Quantity:', transaction.quantity);\n      console.log('Price:', transaction.price);\n    });\n\n    return transactions;\n  } catch (error) {\n    console.error('Error getting investment transactions:', error);\n    throw error;\n  }\n}\n```\n\n### Liabilities - Loan and Credit Card Data\n\nAccess loan balances, interest rates, and credit card information:\n\n```typescript\nasync function getLiabilities(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.liabilitiesGet(request);\n    const liabilities = response.data.liabilities;\n\n    // Credit cards\n    liabilities.credit?.forEach(card => {\n      console.log('Credit Card:', card.name);\n      console.log('APRs:', card.aprs);\n      console.log('Last Payment:', card.last_payment_amount);\n      console.log('Minimum Payment:', card.minimum_payment_amount);\n    });\n\n    // Student loans\n    liabilities.student?.forEach(loan => {\n      console.log('Student Loan:', loan.account_id);\n      console.log('Interest Rate:', loan.interest_rate_percentage);\n      console.log('Origination Date:', loan.origination_date);\n      console.log('Outstanding Balance:', loan.outstanding_interest_amount);\n    });\n\n    // Mortgages\n    liabilities.mortgage?.forEach(mortgage => {\n      console.log('Mortgage:', mortgage.account_id);\n      console.log('Interest Rate:', mortgage.interest_rate.percentage);\n      console.log('Origination Date:', mortgage.origination_date);\n      console.log('Maturity Date:', mortgage.maturity_date);\n    });\n\n    return liabilities;\n  } catch (error) {\n    console.error('Error getting liabilities:', error);\n    throw error;\n  }\n}\n```\n\n### Payment Initiation (UK and Europe)\n\nCreate and manage payments:\n\n```typescript\nimport { PaymentInitiationPaymentCreateRequest } from 'plaid';\n\nasync function createPayment(accessToken: string) {\n  try {\n    const request: PaymentInitiationPaymentCreateRequest = {\n      recipient_id: 'recipient_id_from_previous_call',\n      reference: 'Invoice #12345',\n      amount: {\n        currency: 'GBP',\n        value: 100.00,\n      },\n    };\n\n    const response = await plaidClient.paymentInitiationPaymentCreate(request);\n    const paymentId = response.data.payment_id;\n\n    console.log('Payment ID:', paymentId);\n    return paymentId;\n  } catch (error) {\n    console.error('Error creating payment:', error);\n    throw error;\n  }\n}\n```\n\n**Get Payment Status:**\n\n```typescript\nasync function getPaymentStatus(paymentId: string) {\n  try {\n    const request = {\n      payment_id: paymentId,\n    };\n\n    const response = await plaidClient.paymentInitiationPaymentGet(request);\n    const payment = response.data;\n\n    console.log('Status:', payment.status);\n    console.log('Amount:', payment.amount);\n    console.log('Last Updated:', payment.last_status_update);\n\n    return payment;\n  } catch (error) {\n    console.error('Error getting payment status:', error);\n    throw error;\n  }\n}\n```\n\n## Items Management\n\nAn Item represents a user's connection to a financial institution.\n\n### Get Item Information\n\n```typescript\nasync function getItem(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.itemGet(request);\n    const item = response.data.item;\n\n    console.log('Item ID:', item.item_id);\n    console.log('Institution ID:', item.institution_id);\n    console.log('Available Products:', item.available_products);\n    console.log('Billed Products:', item.billed_products);\n    console.log('Error:', item.error);\n\n    return item;\n  } catch (error) {\n    console.error('Error getting item:', error);\n    throw error;\n  }\n}\n```\n\n### Remove Item\n\n```typescript\nasync function removeItem(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.itemRemove(request);\n    console.log('Item removed successfully');\n    return response.data;\n  } catch (error) {\n    console.error('Error removing item:', error);\n    throw error;\n  }\n}\n```\n\n### Update Item Webhook\n\n```typescript\nasync function updateWebhook(accessToken: string, newWebhook: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n      webhook: newWebhook,\n    };\n\n    const response = await plaidClient.itemWebhookUpdate(request);\n    const item = response.data.item;\n\n    console.log('Webhook updated to:', newWebhook);\n    return item;\n  } catch (error) {\n    console.error('Error updating webhook:', error);\n    throw error;\n  }\n}\n```\n\n## Webhooks\n\nPlaid sends webhook notifications for various events. Configure webhooks via `/link/token/create` or the Plaid Dashboard.\n\n### Webhook Handler Example\n\n```typescript\nimport express from 'express';\n\nconst app = express();\napp.use(express.json());\n\napp.post('/plaid/webhook', async (req, res) => {\n  const webhook = req.body;\n\n  console.log('Webhook Type:', webhook.webhook_type);\n  console.log('Webhook Code:', webhook.webhook_code);\n\n  switch (webhook.webhook_type) {\n    case 'TRANSACTIONS':\n      await handleTransactionsWebhook(webhook);\n      break;\n    case 'ITEM':\n      await handleItemWebhook(webhook);\n      break;\n    case 'AUTH':\n      await handleAuthWebhook(webhook);\n      break;\n    default:\n      console.log('Unknown webhook type:', webhook.webhook_type);\n  }\n\n  res.json({ status: 'received' });\n});\n\nasync function handleTransactionsWebhook(webhook: any) {\n  if (webhook.webhook_code === 'SYNC_UPDATES_AVAILABLE') {\n    const itemId = webhook.item_id;\n    console.log('New transactions available for item:', itemId);\n    // Fetch new transactions using transactionsSync\n  }\n}\n\nasync function handleItemWebhook(webhook: any) {\n  if (webhook.webhook_code === 'ERROR') {\n    console.log('Item error:', webhook.error);\n    // Handle item error\n  }\n}\n\nasync function handleAuthWebhook(webhook: any) {\n  if (webhook.webhook_code === 'AUTOMATICALLY_VERIFIED') {\n    console.log('Account automatically verified:', webhook.account_id);\n  }\n}\n```\n\n## Sandbox Testing\n\nThe Sandbox environment provides test data and utilities for development.\n\n### Fire a Test Webhook\n\n```typescript\nasync function fireSandboxWebhook(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n      webhook_code: 'SYNC_UPDATES_AVAILABLE',\n    };\n\n    const response = await plaidClient.sandboxItemFireWebhook(request);\n    console.log('Webhook fired:', response.data);\n    return response.data;\n  } catch (error) {\n    console.error('Error firing webhook:', error);\n    throw error;\n  }\n}\n```\n\n### Reset Sandbox Item Login\n\n```typescript\nasync function resetSandboxItem(accessToken: string) {\n  try {\n    const request = {\n      access_token: accessToken,\n    };\n\n    const response = await plaidClient.sandboxItemResetLogin(request);\n    console.log('Item login reset');\n    return response.data;\n  } catch (error) {\n    console.error('Error resetting item:', error);\n    throw error;\n  }\n}\n```\n\n### Set Verification Status (Sandbox)\n\n```typescript\nasync function setVerificationStatus(\n  accessToken: string,\n  accountId: string,\n  verificationStatus: string\n) {\n  try {\n    const request = {\n      access_token: accessToken,\n      account_id: accountId,\n      verification_status: verificationStatus,\n    };\n\n    const response = await plaidClient.sandboxItemSetVerificationStatus(request);\n    console.log('Verification status set');\n    return response.data;\n  } catch (error) {\n    console.error('Error setting verification status:', error);\n    throw error;\n  }\n}\n```\n\n## Error Handling\n\nPlaid errors include an `error_type`, `error_code`, and HTTP status code.\n\n```typescript\nimport { PlaidError } from 'plaid';\n\nasync function makeApiCall(accessToken: string) {\n  try {\n    const response = await plaidClient.accountsGet({\n      access_token: accessToken,\n    });\n    return response.data;\n  } catch (error: any) {\n    if (error.response) {\n      const plaidError = error.response.data;\n\n      console.log('Error Type:', plaidError.error_type);\n      console.log('Error Code:', plaidError.error_code);\n      console.log('Error Message:', plaidError.error_message);\n      console.log('Display Message:', plaidError.display_message);\n      console.log('HTTP Status:', error.response.status);\n\n      switch (plaidError.error_type) {\n        case 'ITEM_ERROR':\n          if (plaidError.error_code === 'ITEM_LOGIN_REQUIRED') {\n            console.log('User needs to re-authenticate');\n            // Trigger Link update mode\n          }\n          break;\n        case 'RATE_LIMIT_EXCEEDED':\n          console.log('Rate limit exceeded, retry after delay');\n          // Implement exponential backoff\n          break;\n        case 'API_ERROR':\n          console.log('Plaid API error, retry request');\n          // Retry with idempotency key if available\n          break;\n        case 'INVALID_REQUEST':\n          console.log('Invalid request parameters');\n          break;\n        case 'INVALID_INPUT':\n          console.log('Invalid input data');\n          break;\n        case 'INSTITUTION_ERROR':\n          console.log('Institution is down or experiencing issues');\n          break;\n        default:\n          console.log('Unexpected error type');\n      }\n    } else {\n      console.error('Network or unexpected error:', error);\n    }\n    throw error;\n  }\n}\n```\n\n### Retry Logic with Exponential Backoff\n\n```typescript\nasync function makeApiCallWithRetry<T>(\n  apiCall: () => Promise<T>,\n  maxRetries = 3\n): Promise<T> {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await apiCall();\n    } catch (error: any) {\n      const isLastAttempt = attempt === maxRetries;\n      const shouldRetry = error.response?.data?.error_type === 'RATE_LIMIT_EXCEEDED' ||\n                          error.response?.data?.error_type === 'API_ERROR';\n\n      if (!shouldRetry || isLastAttempt) {\n        throw error;\n      }\n\n      const delay = Math.pow(2, attempt) * 1000; // Exponential backoff\n      console.log(`Retrying after ${delay}ms (attempt ${attempt}/${maxRetries})`);\n      await new Promise(resolve => setTimeout(resolve, delay));\n    }\n  }\n  throw new Error('Max retries exceeded');\n}\n\n// Usage\nconst accounts = await makeApiCallWithRetry(() =>\n  plaidClient.accountsGet({ access_token: accessToken })\n);\n```\n\n## Rate Limits\n\nPlaid enforces rate limits to ensure API stability:\n\n- `/auth/get`: 15 requests per Item per minute (Production)\n- `/institutions/get`: 25 requests per client per minute (Production), 10 requests per client per minute (Sandbox)\n- Most other endpoints: Custom limits based on your account\n\nTo reduce rate limit errors:\n\n- Increase the `count` parameter in `/transactions/sync` to the maximum of 500\n- Cache responses when appropriate\n- Implement exponential backoff retry logic\n- Use webhooks instead of polling for updates\n\n```typescript\n// Efficient transactions sync with maximum count\nasync function efficientTransactionSync(accessToken: string, cursor?: string) {\n  const request = {\n    access_token: accessToken,\n    cursor: cursor,\n    count: 500, // Use maximum to reduce number of requests\n  };\n\n  const response = await plaidClient.transactionsSync(request);\n  return response.data;\n}\n```\n\n## Complete Integration Example\n\n```typescript\nimport express from 'express';\nimport { Configuration, PlaidApi, PlaidEnvironments, Products, CountryCode } from 'plaid';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst app = express();\napp.use(express.json());\n\n// Initialize Plaid client\nconst configuration = new Configuration({\n  basePath: PlaidEnvironments.sandbox,\n  baseOptions: {\n    headers: {\n      'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,\n      'PLAID-SECRET': process.env.PLAID_SANDBOX_SECRET,\n      'Plaid-Version': '2020-09-14',\n    },\n  },\n});\n\nconst plaidClient = new PlaidApi(configuration);\n\n// Store access tokens (use a database in production)\nconst accessTokenStore = new Map<string, string>();\n\n// Create link token\napp.post('/api/create_link_token', async (req, res) => {\n  try {\n    const { userId } = req.body;\n\n    const response = await plaidClient.linkTokenCreate({\n      user: {\n        client_user_id: userId,\n      },\n      client_name: 'My Financial App',\n      products: [Products.Auth, Products.Transactions],\n      country_codes: [CountryCode.Us],\n      language: 'en',\n      webhook: 'https://your-domain.com/plaid/webhook',\n    });\n\n    res.json({ link_token: response.data.link_token });\n  } catch (error) {\n    console.error('Error creating link token:', error);\n    res.status(500).json({ error: 'Failed to create link token' });\n  }\n});\n\n// Exchange public token\napp.post('/api/exchange_public_token', async (req, res) => {\n  try {\n    const { public_token, userId } = req.body;\n\n    const response = await plaidClient.itemPublicTokenExchange({\n      public_token: public_token,\n    });\n\n    const accessToken = response.data.access_token;\n    const itemId = response.data.item_id;\n\n    // Store access token securely (use database in production)\n    accessTokenStore.set(userId, accessToken);\n\n    res.json({ success: true, item_id: itemId });\n  } catch (error) {\n    console.error('Error exchanging public token:', error);\n    res.status(500).json({ error: 'Failed to exchange public token' });\n  }\n});\n\n// Get accounts\napp.get('/api/accounts/:userId', async (req, res) => {\n  try {\n    const { userId } = req.params;\n    const accessToken = accessTokenStore.get(userId);\n\n    if (!accessToken) {\n      return res.status(404).json({ error: 'No access token found' });\n    }\n\n    const response = await plaidClient.accountsGet({\n      access_token: accessToken,\n    });\n\n    res.json({ accounts: response.data.accounts });\n  } catch (error) {\n    console.error('Error getting accounts:', error);\n    res.status(500).json({ error: 'Failed to get accounts' });\n  }\n});\n\n// Get transactions\napp.get('/api/transactions/:userId', async (req, res) => {\n  try {\n    const { userId } = req.params;\n    const accessToken = accessTokenStore.get(userId);\n\n    if (!accessToken) {\n      return res.status(404).json({ error: 'No access token found' });\n    }\n\n    const response = await plaidClient.transactionsSync({\n      access_token: accessToken,\n      count: 100,\n    });\n\n    res.json({\n      added: response.data.added,\n      modified: response.data.modified,\n      removed: response.data.removed,\n      next_cursor: response.data.next_cursor,\n      has_more: response.data.has_more,\n    });\n  } catch (error) {\n    console.error('Error getting transactions:', error);\n    res.status(500).json({ error: 'Failed to get transactions' });\n  }\n});\n\n// Webhook handler\napp.post('/plaid/webhook', async (req, res) => {\n  const webhook = req.body;\n  console.log('Received webhook:', webhook);\n\n  if (webhook.webhook_type === 'TRANSACTIONS') {\n    if (webhook.webhook_code === 'SYNC_UPDATES_AVAILABLE') {\n      // Fetch new transactions\n      console.log('New transactions available for item:', webhook.item_id);\n    }\n  }\n\n  res.json({ status: 'received' });\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n  console.log(`Server running on port ${PORT}`);\n});\n```\n\n## Useful Links\n\n- **Documentation:** https://plaid.com/docs/\n- **API Reference:** https://plaid.com/docs/api/\n- **Dashboard:** https://dashboard.plaid.com/\n- **GitHub Repository:** https://github.com/plaid/plaid-node\n- **Quickstart Guide:** https://plaid.com/docs/quickstart/\n- **Changelog:** https://plaid.com/docs/changelog/\n"
  },
  {
    "path": "content/plaid/docs/banking/python/DOC.md",
    "content": "---\nname: banking\ndescription: \"Plaid API Coding Guidelines for Python using the official Plaid libraries and SDKs\"\nmetadata:\n  languages: \"python\"\n  versions: \"37.1.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"plaid,banking,fintech,payments,financial-data\"\n---\n\n# Plaid API Coding Guidelines (Python)\n\nYou are a Plaid API coding expert. Help me with writing code using the Plaid API calling the official libraries and SDKs.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Plaid Python SDK for all Plaid API interactions.\n\n- **Library Name:** Plaid Python SDK\n- **PyPI Package:** `plaid-python`\n- **Current Version:** 37.1.0\n\n**Installation:**\n\n```bash\npip install plaid-python\n```\n\n**Important Notes:**\n\n- The plaid-python client library is updated monthly\n- This library only supports Python 3 (Python >=3.6)\n- This release only supports the latest Plaid API version: 2020-09-14\n- The library is generated from the Plaid OpenAPI spec\n- Always use a recent version for new endpoints and fields support\n\n## Initialization and Authentication\n\nThe Plaid library requires creating a `Configuration` object, `ApiClient`, and `PlaidApi` instance for all API calls.\n\n```python\nimport plaid\nfrom plaid.api import plaid_api\n\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': 'your_client_id',\n        'secret': 'your_sandbox_secret',\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n```\n\n### Environment Configuration\n\nPlaid has multiple environments for different use cases:\n\n```python\nimport plaid\nfrom plaid.api import plaid_api\n\n# Sandbox - for testing with stateful test data\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': 'your_client_id',\n        'secret': 'your_sandbox_secret',\n    }\n)\n\n# Development - for testing with live credentials\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Development,\n    api_key={\n        'clientId': 'your_client_id',\n        'secret': 'your_development_secret',\n    }\n)\n\n# Production - for live users\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Production,\n    api_key={\n        'clientId': 'your_client_id',\n        'secret': 'your_production_secret',\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n```\n\n### Environment Variables Setup\n\n```python\nimport os\nimport plaid\nfrom plaid.api import plaid_api\n\n# Load from environment variables\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': os.environ['PLAID_CLIENT_ID'],\n        'secret': os.environ['PLAID_SANDBOX_SECRET'],\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n```\n\n**.env file:**\n\n```bash\nPLAID_CLIENT_ID=your_client_id_here\nPLAID_SANDBOX_SECRET=your_sandbox_secret_here\nPLAID_DEVELOPMENT_SECRET=your_development_secret_here\nPLAID_PRODUCTION_SECRET=your_production_secret_here\n```\n\n**Using python-dotenv:**\n\n```python\nimport os\nfrom dotenv import load_dotenv\nimport plaid\nfrom plaid.api import plaid_api\n\nload_dotenv()\n\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': os.environ['PLAID_CLIENT_ID'],\n        'secret': os.environ['PLAID_SANDBOX_SECRET'],\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n```\n\n## Core Plaid Flow\n\nThe standard Plaid integration flow follows these steps:\n\n1. Create a link_token\n2. Initialize Plaid Link on the frontend\n3. Receive a public_token from Link\n4. Exchange the public_token for an access_token\n5. Use the access_token to make API requests\n\n### Step 1: Create Link Token\n\nCreate a temporary link_token to authenticate your app with Plaid Link:\n\n```python\nimport plaid\nfrom plaid.api import plaid_api\nfrom plaid.model.link_token_create_request import LinkTokenCreateRequest\nfrom plaid.model.link_token_create_request_user import LinkTokenCreateRequestUser\nfrom plaid.model.products import Products\nfrom plaid.model.country_code import CountryCode\n\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': os.environ['PLAID_CLIENT_ID'],\n        'secret': os.environ['PLAID_SANDBOX_SECRET'],\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n\ndef create_link_token(user_id: str) -> str:\n    try:\n        request = LinkTokenCreateRequest(\n            user=LinkTokenCreateRequestUser(\n                client_user_id=user_id\n            ),\n            client_name='My Application',\n            products=[Products('auth'), Products('transactions')],\n            country_codes=[CountryCode('US')],\n            language='en',\n            webhook='https://your-domain.com/plaid/webhook'\n        )\n\n        response = client.link_token_create(request)\n        link_token = response['link_token']\n\n        print(f'Link token: {link_token}')\n        return link_token\n    except plaid.ApiException as e:\n        print(f'Error creating link token: {e}')\n        raise\n```\n\n### Step 2: Exchange Public Token for Access Token\n\nAfter the user completes the Link flow, exchange the public_token for a permanent access_token:\n\n```python\nfrom plaid.model.item_public_token_exchange_request import ItemPublicTokenExchangeRequest\n\ndef exchange_public_token(public_token: str) -> dict:\n    try:\n        request = ItemPublicTokenExchangeRequest(\n            public_token=public_token\n        )\n\n        response = client.item_public_token_exchange(request)\n        access_token = response['access_token']\n        item_id = response['item_id']\n\n        # Store these securely in your database\n        print(f'Access Token: {access_token}')\n        print(f'Item ID: {item_id}')\n\n        return {\n            'access_token': access_token,\n            'item_id': item_id\n        }\n    except plaid.ApiException as e:\n        print(f'Error exchanging public token: {e}')\n        raise\n```\n\n## Product APIs\n\n### Auth - Account and Routing Numbers\n\nRetrieve bank account and routing numbers for ACH transfers:\n\n```python\nfrom plaid.model.auth_get_request import AuthGetRequest\n\ndef get_auth_data(access_token: str) -> dict:\n    try:\n        request = AuthGetRequest(\n            access_token=access_token\n        )\n\n        response = client.auth_get(request)\n        accounts = response['accounts']\n        numbers = response['numbers']\n\n        print('Accounts:', accounts)\n        print('Account Numbers:', numbers['ach'])\n\n        for ach in numbers['ach']:\n            print(f'Account: {ach[\"account_id\"]}')\n            print(f'Account Number: {ach[\"account\"]}')\n            print(f'Routing Number: {ach[\"routing\"]}')\n\n        return {\n            'accounts': accounts,\n            'numbers': numbers\n        }\n    except plaid.ApiException as e:\n        print(f'Error getting auth data: {e}')\n        raise\n```\n\n**Advanced Auth with Options:**\n\n```python\nfrom plaid.model.auth_get_request import AuthGetRequest\nfrom plaid.model.auth_get_request_options import AuthGetRequestOptions\n\ndef get_auth_data_with_options(access_token: str, account_ids: list = None) -> dict:\n    try:\n        options = AuthGetRequestOptions(\n            account_ids=account_ids\n        ) if account_ids else None\n\n        request = AuthGetRequest(\n            access_token=access_token,\n            options=options\n        )\n\n        response = client.auth_get(request)\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error getting auth data: {e}')\n        raise\n```\n\n### Accounts - Retrieve Account Information\n\nGet account details including balances and metadata:\n\n```python\nfrom plaid.model.accounts_get_request import AccountsGetRequest\n\ndef get_accounts(access_token: str) -> list:\n    try:\n        request = AccountsGetRequest(\n            access_token=access_token\n        )\n\n        response = client.accounts_get(request)\n        accounts = response['accounts']\n\n        for account in accounts:\n            print(f'Account ID: {account[\"account_id\"]}')\n            print(f'Name: {account[\"name\"]}')\n            print(f'Type: {account[\"type\"]}')\n            print(f'Subtype: {account[\"subtype\"]}')\n            print(f'Current Balance: ${account[\"balances\"][\"current\"]}')\n            print(f'Available Balance: ${account[\"balances\"][\"available\"]}')\n            print('---')\n\n        return accounts\n    except plaid.ApiException as e:\n        print(f'Error getting accounts: {e}')\n        raise\n```\n\n### Balance - Real-time Balance Information\n\nGet up-to-date balance information:\n\n```python\nfrom plaid.model.accounts_balance_get_request import AccountsBalanceGetRequest\n\ndef get_balance(access_token: str) -> list:\n    try:\n        request = AccountsBalanceGetRequest(\n            access_token=access_token\n        )\n\n        response = client.accounts_balance_get(request)\n        accounts = response['accounts']\n\n        for account in accounts:\n            balances = account['balances']\n            print(f'{account[\"name\"]}: ${balances[\"current\"]}')\n            print(f'Available: ${balances[\"available\"]}')\n            print(f'Currency: {balances[\"iso_currency_code\"]}')\n            print('---')\n\n        return accounts\n    except plaid.ApiException as e:\n        print(f'Error getting balance: {e}')\n        raise\n```\n\n**Advanced Balance with Account Filtering:**\n\n```python\nfrom plaid.model.accounts_balance_get_request import AccountsBalanceGetRequest\nfrom plaid.model.accounts_balance_get_request_options import AccountsBalanceGetRequestOptions\n\ndef get_balance_for_specific_accounts(access_token: str, account_ids: list) -> list:\n    try:\n        options = AccountsBalanceGetRequestOptions(\n            account_ids=account_ids\n        )\n\n        request = AccountsBalanceGetRequest(\n            access_token=access_token,\n            options=options\n        )\n\n        response = client.accounts_balance_get(request)\n        return response['accounts']\n    except plaid.ApiException as e:\n        print(f'Error getting balance: {e}')\n        raise\n```\n\n### Identity - Account Holder Information\n\nRetrieve identity information for account holders:\n\n```python\nfrom plaid.model.identity_get_request import IdentityGetRequest\n\ndef get_identity(access_token: str) -> dict:\n    try:\n        request = IdentityGetRequest(\n            access_token=access_token\n        )\n\n        response = client.identity_get(request)\n        accounts = response['accounts']\n\n        for account in accounts:\n            print(f'Account: {account[\"name\"]}')\n            for owner in account['owners']:\n                print(f'Names: {owner[\"names\"]}')\n                print(f'Emails: {owner[\"emails\"]}')\n                print(f'Phone Numbers: {owner[\"phone_numbers\"]}')\n                print(f'Addresses: {owner[\"addresses\"]}')\n                print('---')\n\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error getting identity: {e}')\n        raise\n```\n\n### Transactions - Transaction History\n\nPlaid provides two methods for retrieving transactions: `/transactions/get` (legacy) and `/transactions/sync` (recommended).\n\n#### Transactions Sync (Recommended)\n\nThe `/transactions/sync` endpoint provides incremental updates and is the recommended approach:\n\n```python\nfrom plaid.model.transactions_sync_request import TransactionsSyncRequest\n\ndef sync_transactions(access_token: str, cursor: str = None) -> dict:\n    try:\n        request = TransactionsSyncRequest(\n            access_token=access_token,\n            cursor=cursor,\n            count=100  # Number of transactions to fetch (max 500)\n        )\n\n        response = client.transactions_sync(request)\n\n        print(f'Added transactions: {len(response[\"added\"])}')\n        print(f'Modified transactions: {len(response[\"modified\"])}')\n        print(f'Removed transactions: {len(response[\"removed\"])}')\n        print(f'Next cursor: {response[\"next_cursor\"]}')\n        print(f'Has more: {response[\"has_more\"]}')\n\n        # Process transactions\n        for transaction in response['added']:\n            print(f'Date: {transaction[\"date\"]}')\n            print(f'Name: {transaction[\"name\"]}')\n            print(f'Amount: ${transaction[\"amount\"]}')\n            print(f'Category: {transaction[\"category\"]}')\n            print('---')\n\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error syncing transactions: {e}')\n        raise\n```\n\n**Paginated Transaction Sync:**\n\n```python\nfrom plaid.model.transactions_sync_request import TransactionsSyncRequest\n\ndef get_all_transactions(access_token: str) -> list:\n    cursor = None\n    all_transactions = []\n    has_more = True\n\n    try:\n        while has_more:\n            request = TransactionsSyncRequest(\n                access_token=access_token,\n                cursor=cursor,\n                count=500  # Use maximum for efficiency\n            )\n\n            response = client.transactions_sync(request)\n\n            all_transactions.extend(response['added'])\n            cursor = response['next_cursor']\n            has_more = response['has_more']\n\n            print(f'Fetched {len(response[\"added\"])} transactions')\n\n        print(f'Total transactions: {len(all_transactions)}')\n        return all_transactions\n    except plaid.ApiException as e:\n        print(f'Error getting all transactions: {e}')\n        raise\n```\n\n#### Transactions Get (Legacy)\n\nFor retrieving transactions within a specific date range:\n\n```python\nfrom plaid.model.transactions_get_request import TransactionsGetRequest\nfrom plaid.model.transactions_get_request_options import TransactionsGetRequestOptions\nfrom datetime import datetime, timedelta\n\ndef get_transactions(access_token: str, start_date: str, end_date: str) -> list:\n    try:\n        options = TransactionsGetRequestOptions(\n            count=250,\n            offset=0\n        )\n\n        request = TransactionsGetRequest(\n            access_token=access_token,\n            start_date=datetime.strptime(start_date, '%Y-%m-%d').date(),\n            end_date=datetime.strptime(end_date, '%Y-%m-%d').date(),\n            options=options\n        )\n\n        response = client.transactions_get(request)\n        transactions = response['transactions']\n        total_transactions = response['total_transactions']\n\n        print(f'Retrieved {len(transactions)} of {total_transactions}')\n\n        return transactions\n    except plaid.ApiException as e:\n        print(f'Error getting transactions: {e}')\n        raise\n```\n\n**Paginated Transactions Get:**\n\n```python\nfrom plaid.model.transactions_get_request import TransactionsGetRequest\nfrom plaid.model.transactions_get_request_options import TransactionsGetRequestOptions\nfrom datetime import datetime\n\ndef get_all_transactions_in_range(access_token: str, start_date: str, end_date: str) -> list:\n    offset = 0\n    batch_size = 500\n    all_transactions = []\n    total_transactions = 0\n\n    try:\n        while True:\n            options = TransactionsGetRequestOptions(\n                count=batch_size,\n                offset=offset\n            )\n\n            request = TransactionsGetRequest(\n                access_token=access_token,\n                start_date=datetime.strptime(start_date, '%Y-%m-%d').date(),\n                end_date=datetime.strptime(end_date, '%Y-%m-%d').date(),\n                options=options\n            )\n\n            response = client.transactions_get(request)\n            transactions = response['transactions']\n            total_transactions = response['total_transactions']\n\n            all_transactions.extend(transactions)\n            offset += len(transactions)\n\n            print(f'Fetched {len(all_transactions)} of {total_transactions}')\n\n            if len(all_transactions) >= total_transactions:\n                break\n\n        return all_transactions\n    except plaid.ApiException as e:\n        print(f'Error getting all transactions: {e}')\n        raise\n```\n\n### Investments - Holdings and Transactions\n\nRetrieve investment account holdings and transactions:\n\n```python\nfrom plaid.model.investments_holdings_get_request import InvestmentsHoldingsGetRequest\n\ndef get_investment_holdings(access_token: str) -> dict:\n    try:\n        request = InvestmentsHoldingsGetRequest(\n            access_token=access_token\n        )\n\n        response = client.investments_holdings_get(request)\n        holdings = response['holdings']\n        securities = response['securities']\n\n        # Create security lookup dictionary\n        security_map = {s['security_id']: s for s in securities}\n\n        for holding in holdings:\n            security = security_map.get(holding['security_id'])\n            if security:\n                print(f'Security: {security[\"name\"]}')\n                print(f'Ticker: {security.get(\"ticker_symbol\", \"N/A\")}')\n            print(f'Quantity: {holding[\"quantity\"]}')\n            print(f'Institution Price: ${holding[\"institution_price\"]}')\n            print(f'Value: ${holding[\"institution_value\"]}')\n            print('---')\n\n        return {\n            'holdings': holdings,\n            'securities': securities\n        }\n    except plaid.ApiException as e:\n        print(f'Error getting investment holdings: {e}')\n        raise\n```\n\n**Investment Transactions:**\n\n```python\nfrom plaid.model.investments_transactions_get_request import InvestmentsTransactionsGetRequest\nfrom datetime import datetime\n\ndef get_investment_transactions(access_token: str, start_date: str, end_date: str) -> list:\n    try:\n        request = InvestmentsTransactionsGetRequest(\n            access_token=access_token,\n            start_date=datetime.strptime(start_date, '%Y-%m-%d').date(),\n            end_date=datetime.strptime(end_date, '%Y-%m-%d').date()\n        )\n\n        response = client.investments_transactions_get(request)\n        transactions = response['investment_transactions']\n\n        for transaction in transactions:\n            print(f'Date: {transaction[\"date\"]}')\n            print(f'Name: {transaction[\"name\"]}')\n            print(f'Type: {transaction[\"type\"]}')\n            print(f'Amount: ${transaction[\"amount\"]}')\n            print(f'Quantity: {transaction[\"quantity\"]}')\n            print(f'Price: ${transaction[\"price\"]}')\n            print('---')\n\n        return transactions\n    except plaid.ApiException as e:\n        print(f'Error getting investment transactions: {e}')\n        raise\n```\n\n### Liabilities - Loan and Credit Card Data\n\nAccess loan balances, interest rates, and credit card information:\n\n```python\nfrom plaid.model.liabilities_get_request import LiabilitiesGetRequest\n\ndef get_liabilities(access_token: str) -> dict:\n    try:\n        request = LiabilitiesGetRequest(\n            access_token=access_token\n        )\n\n        response = client.liabilities_get(request)\n        liabilities = response['liabilities']\n\n        # Credit cards\n        if 'credit' in liabilities and liabilities['credit']:\n            print('Credit Cards:')\n            for card in liabilities['credit']:\n                print(f'  Name: {card.get(\"name\", \"N/A\")}')\n                print(f'  APRs: {card.get(\"aprs\", [])}')\n                print(f'  Last Payment: ${card.get(\"last_payment_amount\", 0)}')\n                print(f'  Minimum Payment: ${card.get(\"minimum_payment_amount\", 0)}')\n                print('---')\n\n        # Student loans\n        if 'student' in liabilities and liabilities['student']:\n            print('Student Loans:')\n            for loan in liabilities['student']:\n                print(f'  Account ID: {loan[\"account_id\"]}')\n                print(f'  Interest Rate: {loan.get(\"interest_rate_percentage\", 0)}%')\n                print(f'  Origination Date: {loan.get(\"origination_date\", \"N/A\")}')\n                print(f'  Outstanding Interest: ${loan.get(\"outstanding_interest_amount\", 0)}')\n                print('---')\n\n        # Mortgages\n        if 'mortgage' in liabilities and liabilities['mortgage']:\n            print('Mortgages:')\n            for mortgage in liabilities['mortgage']:\n                print(f'  Account ID: {mortgage[\"account_id\"]}')\n                if 'interest_rate' in mortgage:\n                    print(f'  Interest Rate: {mortgage[\"interest_rate\"].get(\"percentage\", 0)}%')\n                print(f'  Origination Date: {mortgage.get(\"origination_date\", \"N/A\")}')\n                print(f'  Maturity Date: {mortgage.get(\"maturity_date\", \"N/A\")}')\n                print('---')\n\n        return liabilities\n    except plaid.ApiException as e:\n        print(f'Error getting liabilities: {e}')\n        raise\n```\n\n### Payment Initiation (UK and Europe)\n\nCreate and manage payments:\n\n```python\nfrom plaid.model.payment_initiation_payment_create_request import PaymentInitiationPaymentCreateRequest\nfrom plaid.model.payment_amount import PaymentAmount\n\ndef create_payment(recipient_id: str) -> str:\n    try:\n        amount = PaymentAmount(\n            currency='GBP',\n            value=100.00\n        )\n\n        request = PaymentInitiationPaymentCreateRequest(\n            recipient_id=recipient_id,\n            reference='Invoice #12345',\n            amount=amount\n        )\n\n        response = client.payment_initiation_payment_create(request)\n        payment_id = response['payment_id']\n\n        print(f'Payment ID: {payment_id}')\n        return payment_id\n    except plaid.ApiException as e:\n        print(f'Error creating payment: {e}')\n        raise\n```\n\n**Get Payment Status:**\n\n```python\nfrom plaid.model.payment_initiation_payment_get_request import PaymentInitiationPaymentGetRequest\n\ndef get_payment_status(payment_id: str) -> dict:\n    try:\n        request = PaymentInitiationPaymentGetRequest(\n            payment_id=payment_id\n        )\n\n        response = client.payment_initiation_payment_get(request)\n        payment = response.to_dict()\n\n        print(f'Status: {payment[\"status\"]}')\n        print(f'Amount: {payment[\"amount\"]}')\n        print(f'Last Updated: {payment.get(\"last_status_update\", \"N/A\")}')\n\n        return payment\n    except plaid.ApiException as e:\n        print(f'Error getting payment status: {e}')\n        raise\n```\n\n## Items Management\n\nAn Item represents a user's connection to a financial institution.\n\n### Get Item Information\n\n```python\nfrom plaid.model.item_get_request import ItemGetRequest\n\ndef get_item(access_token: str) -> dict:\n    try:\n        request = ItemGetRequest(\n            access_token=access_token\n        )\n\n        response = client.item_get(request)\n        item = response['item']\n\n        print(f'Item ID: {item[\"item_id\"]}')\n        print(f'Institution ID: {item.get(\"institution_id\", \"N/A\")}')\n        print(f'Available Products: {item.get(\"available_products\", [])}')\n        print(f'Billed Products: {item.get(\"billed_products\", [])}')\n        if 'error' in item and item['error']:\n            print(f'Error: {item[\"error\"]}')\n\n        return item\n    except plaid.ApiException as e:\n        print(f'Error getting item: {e}')\n        raise\n```\n\n### Remove Item\n\n```python\nfrom plaid.model.item_remove_request import ItemRemoveRequest\n\ndef remove_item(access_token: str) -> dict:\n    try:\n        request = ItemRemoveRequest(\n            access_token=access_token\n        )\n\n        response = client.item_remove(request)\n        print('Item removed successfully')\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error removing item: {e}')\n        raise\n```\n\n### Update Item Webhook\n\n```python\nfrom plaid.model.item_webhook_update_request import ItemWebhookUpdateRequest\n\ndef update_webhook(access_token: str, new_webhook: str) -> dict:\n    try:\n        request = ItemWebhookUpdateRequest(\n            access_token=access_token,\n            webhook=new_webhook\n        )\n\n        response = client.item_webhook_update(request)\n        item = response['item']\n\n        print(f'Webhook updated to: {new_webhook}')\n        return item\n    except plaid.ApiException as e:\n        print(f'Error updating webhook: {e}')\n        raise\n```\n\n## Webhooks\n\nPlaid sends webhook notifications for various events. Configure webhooks via `/link/token/create` or the Plaid Dashboard.\n\n### Webhook Handler Example (Flask)\n\n```python\nfrom flask import Flask, request, jsonify\nimport plaid\nfrom plaid.api import plaid_api\n\napp = Flask(__name__)\n\n# Initialize Plaid client\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': os.environ['PLAID_CLIENT_ID'],\n        'secret': os.environ['PLAID_SANDBOX_SECRET'],\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n\n@app.route('/plaid/webhook', methods=['POST'])\ndef plaid_webhook():\n    webhook = request.json\n\n    print(f'Webhook Type: {webhook[\"webhook_type\"]}')\n    print(f'Webhook Code: {webhook[\"webhook_code\"]}')\n\n    webhook_type = webhook['webhook_type']\n\n    if webhook_type == 'TRANSACTIONS':\n        handle_transactions_webhook(webhook)\n    elif webhook_type == 'ITEM':\n        handle_item_webhook(webhook)\n    elif webhook_type == 'AUTH':\n        handle_auth_webhook(webhook)\n    else:\n        print(f'Unknown webhook type: {webhook_type}')\n\n    return jsonify({'status': 'received'}), 200\n\ndef handle_transactions_webhook(webhook):\n    if webhook['webhook_code'] == 'SYNC_UPDATES_AVAILABLE':\n        item_id = webhook['item_id']\n        print(f'New transactions available for item: {item_id}')\n        # Fetch new transactions using transactions_sync\n\ndef handle_item_webhook(webhook):\n    if webhook['webhook_code'] == 'ERROR':\n        print(f'Item error: {webhook.get(\"error\", {})}')\n        # Handle item error\n\ndef handle_auth_webhook(webhook):\n    if webhook['webhook_code'] == 'AUTOMATICALLY_VERIFIED':\n        print(f'Account automatically verified: {webhook.get(\"account_id\", \"N/A\")}')\n\nif __name__ == '__main__':\n    app.run(port=5000)\n```\n\n## Sandbox Testing\n\nThe Sandbox environment provides test data and utilities for development.\n\n### Fire a Test Webhook\n\n```python\nfrom plaid.model.sandbox_item_fire_webhook_request import SandboxItemFireWebhookRequest\n\ndef fire_sandbox_webhook(access_token: str) -> dict:\n    try:\n        request = SandboxItemFireWebhookRequest(\n            access_token=access_token,\n            webhook_code='SYNC_UPDATES_AVAILABLE'\n        )\n\n        response = client.sandbox_item_fire_webhook(request)\n        print(f'Webhook fired: {response}')\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error firing webhook: {e}')\n        raise\n```\n\n### Reset Sandbox Item Login\n\n```python\nfrom plaid.model.sandbox_item_reset_login_request import SandboxItemResetLoginRequest\n\ndef reset_sandbox_item(access_token: str) -> dict:\n    try:\n        request = SandboxItemResetLoginRequest(\n            access_token=access_token\n        )\n\n        response = client.sandbox_item_reset_login(request)\n        print('Item login reset')\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error resetting item: {e}')\n        raise\n```\n\n### Set Verification Status (Sandbox)\n\n```python\nfrom plaid.model.sandbox_item_set_verification_status_request import SandboxItemSetVerificationStatusRequest\n\ndef set_verification_status(access_token: str, account_id: str, verification_status: str) -> dict:\n    try:\n        request = SandboxItemSetVerificationStatusRequest(\n            access_token=access_token,\n            account_id=account_id,\n            verification_status=verification_status\n        )\n\n        response = client.sandbox_item_set_verification_status(request)\n        print('Verification status set')\n        return response.to_dict()\n    except plaid.ApiException as e:\n        print(f'Error setting verification status: {e}')\n        raise\n```\n\n## Error Handling\n\nPlaid errors include an `error_type`, `error_code`, and HTTP status code.\n\n```python\nimport plaid\nfrom plaid.api import plaid_api\nfrom plaid.model.accounts_get_request import AccountsGetRequest\n\ndef make_api_call(access_token: str):\n    try:\n        request = AccountsGetRequest(\n            access_token=access_token\n        )\n\n        response = client.accounts_get(request)\n        return response.to_dict()\n    except plaid.ApiException as e:\n        error = e.body\n\n        print(f'Error Type: {error.get(\"error_type\", \"N/A\")}')\n        print(f'Error Code: {error.get(\"error_code\", \"N/A\")}')\n        print(f'Error Message: {error.get(\"error_message\", \"N/A\")}')\n        print(f'Display Message: {error.get(\"display_message\", \"N/A\")}')\n        print(f'HTTP Status: {e.status}')\n\n        error_type = error.get('error_type')\n        error_code = error.get('error_code')\n\n        if error_type == 'ITEM_ERROR':\n            if error_code == 'ITEM_LOGIN_REQUIRED':\n                print('User needs to re-authenticate')\n                # Trigger Link update mode\n        elif error_type == 'RATE_LIMIT_EXCEEDED':\n            print('Rate limit exceeded, retry after delay')\n            # Implement exponential backoff\n        elif error_type == 'API_ERROR':\n            print('Plaid API error, retry request')\n            # Retry with idempotency key if available\n        elif error_type == 'INVALID_REQUEST':\n            print('Invalid request parameters')\n        elif error_type == 'INVALID_INPUT':\n            print('Invalid input data')\n        elif error_type == 'INSTITUTION_ERROR':\n            print('Institution is down or experiencing issues')\n        else:\n            print('Unexpected error type')\n\n        raise\n```\n\n### Retry Logic with Exponential Backoff\n\n```python\nimport time\nimport plaid\n\ndef make_api_call_with_retry(api_call, max_retries=3):\n    for attempt in range(1, max_retries + 1):\n        try:\n            return api_call()\n        except plaid.ApiException as e:\n            is_last_attempt = attempt == max_retries\n            error = e.body\n            error_type = error.get('error_type')\n\n            should_retry = error_type in ['RATE_LIMIT_EXCEEDED', 'API_ERROR']\n\n            if not should_retry or is_last_attempt:\n                raise\n\n            delay = 2 ** attempt  # Exponential backoff\n            print(f'Retrying after {delay}s (attempt {attempt}/{max_retries})')\n            time.sleep(delay)\n\n    raise Exception('Max retries exceeded')\n\n# Usage\ndef get_accounts_safe(access_token: str):\n    def api_call():\n        request = AccountsGetRequest(access_token=access_token)\n        return client.accounts_get(request)\n\n    return make_api_call_with_retry(api_call)\n```\n\n## Rate Limits\n\nPlaid enforces rate limits to ensure API stability:\n\n- `/auth/get`: 15 requests per Item per minute (Production)\n- `/institutions/get`: 25 requests per client per minute (Production), 10 requests per client per minute (Sandbox)\n- Most other endpoints: Custom limits based on your account\n\nTo reduce rate limit errors:\n\n- Increase the `count` parameter in `/transactions/sync` to the maximum of 500\n- Cache responses when appropriate\n- Implement exponential backoff retry logic\n- Use webhooks instead of polling for updates\n\n```python\nfrom plaid.model.transactions_sync_request import TransactionsSyncRequest\n\ndef efficient_transaction_sync(access_token: str, cursor: str = None) -> dict:\n    # Use maximum count to reduce number of requests\n    request = TransactionsSyncRequest(\n        access_token=access_token,\n        cursor=cursor,\n        count=500\n    )\n\n    response = client.transactions_sync(request)\n    return response.to_dict()\n```\n\n## Complete Integration Example (Flask)\n\n```python\nimport os\nfrom flask import Flask, request, jsonify\nfrom dotenv import load_dotenv\nimport plaid\nfrom plaid.api import plaid_api\nfrom plaid.model.link_token_create_request import LinkTokenCreateRequest\nfrom plaid.model.link_token_create_request_user import LinkTokenCreateRequestUser\nfrom plaid.model.item_public_token_exchange_request import ItemPublicTokenExchangeRequest\nfrom plaid.model.accounts_get_request import AccountsGetRequest\nfrom plaid.model.transactions_sync_request import TransactionsSyncRequest\nfrom plaid.model.products import Products\nfrom plaid.model.country_code import CountryCode\n\nload_dotenv()\n\napp = Flask(__name__)\n\n# Initialize Plaid client\nconfiguration = plaid.Configuration(\n    host=plaid.Environment.Sandbox,\n    api_key={\n        'clientId': os.environ['PLAID_CLIENT_ID'],\n        'secret': os.environ['PLAID_SANDBOX_SECRET'],\n    }\n)\n\napi_client = plaid.ApiClient(configuration)\nclient = plaid_api.PlaidApi(api_client)\n\n# Store access tokens (use a database in production)\naccess_token_store = {}\n\n@app.route('/api/create_link_token', methods=['POST'])\ndef create_link_token():\n    try:\n        user_id = request.json.get('user_id')\n\n        link_request = LinkTokenCreateRequest(\n            user=LinkTokenCreateRequestUser(\n                client_user_id=user_id\n            ),\n            client_name='My Financial App',\n            products=[Products('auth'), Products('transactions')],\n            country_codes=[CountryCode('US')],\n            language='en',\n            webhook='https://your-domain.com/plaid/webhook'\n        )\n\n        response = client.link_token_create(link_request)\n        return jsonify({'link_token': response['link_token']})\n    except plaid.ApiException as e:\n        print(f'Error creating link token: {e}')\n        return jsonify({'error': 'Failed to create link token'}), 500\n\n@app.route('/api/exchange_public_token', methods=['POST'])\ndef exchange_public_token():\n    try:\n        public_token = request.json.get('public_token')\n        user_id = request.json.get('user_id')\n\n        exchange_request = ItemPublicTokenExchangeRequest(\n            public_token=public_token\n        )\n\n        response = client.item_public_token_exchange(exchange_request)\n        access_token = response['access_token']\n        item_id = response['item_id']\n\n        # Store access token securely (use database in production)\n        access_token_store[user_id] = access_token\n\n        return jsonify({'success': True, 'item_id': item_id})\n    except plaid.ApiException as e:\n        print(f'Error exchanging public token: {e}')\n        return jsonify({'error': 'Failed to exchange public token'}), 500\n\n@app.route('/api/accounts/<user_id>', methods=['GET'])\ndef get_accounts(user_id):\n    try:\n        access_token = access_token_store.get(user_id)\n\n        if not access_token:\n            return jsonify({'error': 'No access token found'}), 404\n\n        accounts_request = AccountsGetRequest(\n            access_token=access_token\n        )\n\n        response = client.accounts_get(accounts_request)\n        return jsonify({'accounts': response['accounts']})\n    except plaid.ApiException as e:\n        print(f'Error getting accounts: {e}')\n        return jsonify({'error': 'Failed to get accounts'}), 500\n\n@app.route('/api/transactions/<user_id>', methods=['GET'])\ndef get_transactions(user_id):\n    try:\n        access_token = access_token_store.get(user_id)\n\n        if not access_token:\n            return jsonify({'error': 'No access token found'}), 404\n\n        transactions_request = TransactionsSyncRequest(\n            access_token=access_token,\n            count=100\n        )\n\n        response = client.transactions_sync(transactions_request)\n\n        return jsonify({\n            'added': response['added'],\n            'modified': response['modified'],\n            'removed': response['removed'],\n            'next_cursor': response['next_cursor'],\n            'has_more': response['has_more']\n        })\n    except plaid.ApiException as e:\n        print(f'Error getting transactions: {e}')\n        return jsonify({'error': 'Failed to get transactions'}), 500\n\n@app.route('/plaid/webhook', methods=['POST'])\ndef plaid_webhook():\n    webhook = request.json\n    print(f'Received webhook: {webhook}')\n\n    if webhook['webhook_type'] == 'TRANSACTIONS':\n        if webhook['webhook_code'] == 'SYNC_UPDATES_AVAILABLE':\n            print(f'New transactions available for item: {webhook[\"item_id\"]}')\n\n    return jsonify({'status': 'received'}), 200\n\nif __name__ == '__main__':\n    app.run(port=5000, debug=True)\n```\n\n## Useful Links\n\n- **Documentation:** https://plaid.com/docs/\n- **API Reference:** https://plaid.com/docs/api/\n- **Dashboard:** https://dashboard.plaid.com/\n- **GitHub Repository:** https://github.com/plaid/plaid-python\n- **Quickstart Guide:** https://plaid.com/docs/quickstart/\n- **Changelog:** https://plaid.com/docs/changelog/\n"
  },
  {
    "path": "content/platformdirs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"platformdirs package guide for Python: platform-specific user and shared directories for app data, config, cache, logs, state, and runtime files\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.9.4\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"platformdirs,paths,filesystem,xdg,windows,macos,linux,android\"\n---\n\n# platformdirs Python Package Guide\n\n## What It Does\n\n`platformdirs` resolves the correct platform-specific directories for application data, config, cache, logs, state, runtime files, and several user folders. It hides the OS-specific rules for Linux and other Unix systems, macOS, Windows, and Android.\n\nUse it when code needs a writable or discoverable app directory and you do not want to hardcode `~/.config`, `~/Library`, `AppData`, `/var`, or similar platform-specific paths yourself.\n\n## Version Scope\n\n- Package: `platformdirs`\n- Language: `python`\n- Version covered in frontmatter: `4.9.4`\n- Latest release on PyPI at the time of writing: `4.9.4` on 2026-03-05\n- Python requirement from PyPI metadata: `>=3.10`\n\nThe API reference and docs site cover the 4.9.x line well, but the published changelog currently goes through `4.9.2` while PyPI already has `4.9.4`. For coding work, treat the 4.9.x API surface as current and verify any very recent release detail on PyPI when version drift matters.\n\n## Install\n\n```bash\npip install platformdirs==4.9.4\n```\n\n```bash\nuv add platformdirs==4.9.4\n```\n\n```bash\npoetry add platformdirs==4.9.4\n```\n\n## Choose An API Style\n\n### `PlatformDirs` instance\n\nUse this when one app needs several related directories.\n\n```python\nfrom platformdirs import PlatformDirs\n\ndirs = PlatformDirs(appname=\"acme-tool\", appauthor=\"Acme\")\n\nprint(dirs.user_data_path)\nprint(dirs.user_config_path)\nprint(dirs.user_cache_path)\nprint(dirs.user_log_path)\nprint(dirs.user_runtime_path)\n```\n\n### Convenience functions\n\nUse these for one-off lookups.\n\n```python\nfrom platformdirs import user_config_path, user_cache_dir\n\nconfig_path = user_config_path(\"acme-tool\", \"Acme\")\ncache_dir = user_cache_dir(\"acme-tool\", \"Acme\")\n```\n\n### `*_dir` vs `*_path`\n\n- `*_dir` returns `str`\n- `*_path` returns `pathlib.Path`\n\nPrefer `*_path` in new code. It avoids manual `Path(...)` wrapping and makes file IO and joins straightforward.\n\n## Initialization And Core Parameters\n\n```python\nfrom platformdirs import PlatformDirs\n\ndirs = PlatformDirs(\n    appname=\"acme-tool\",\n    appauthor=\"Acme\",\n    version=\"2.0\",\n    roaming=False,\n    multipath=False,\n    opinion=True,\n    ensure_exists=False,\n    use_site_for_root=False,\n)\n```\n\nParameters that matter in practice:\n\n- `appname`: app-specific suffix. Pass this unless you explicitly want the raw platform root.\n- `appauthor`: Windows-only in practice. It adds a vendor directory such as `Acme\\\\acme-tool`. Pass `False` to suppress that extra level on Windows.\n- `version`: appends a version component so incompatible on-disk layouts can coexist.\n- `roaming`: Windows-only. Redirects user data/config to roaming AppData instead of local AppData.\n- `multipath`: on Unix/macOS, `site_data_dir` and `site_config_dir` can return all configured roots joined by `os.pathsep`.\n- `opinion`: keeps opinionated subdirectories such as `Cache`, `Logs`, or `/log`.\n- `ensure_exists`: creates directories on access.\n- `use_site_for_root`: Unix-only. When running as root, redirects `user_*` lookups to `site_*` directories instead of `/root/...`.\n\n## Core Usage\n\n### Create app-local config, cache, and logs\n\n```python\nfrom platformdirs import PlatformDirs\n\ndirs = PlatformDirs(\"acme-tool\", \"Acme\", ensure_exists=True)\n\nconfig_file = dirs.user_config_path / \"settings.toml\"\ncache_file = dirs.user_cache_path / \"responses.json\"\nlog_file = dirs.user_log_path / \"app.log\"\n\nconfig_file.write_text(\"debug = false\\n\", encoding=\"utf-8\")\ncache_file.write_text(\"{}\", encoding=\"utf-8\")\nlog_file.write_text(\"started\\n\", encoding=\"utf-8\")\n```\n\nIf you do not want property access to create directories, leave `ensure_exists=False` and create parents yourself:\n\n```python\nfrom platformdirs import user_data_path\n\ndb_file = user_data_path(\"acme-tool\") / \"state.db\"\ndb_file.parent.mkdir(parents=True, exist_ok=True)\ndb_file.write_bytes(b\"sqlite-bytes\")\n```\n\n### Keep incompatible app data separated by version\n\n```python\nfrom platformdirs import user_data_path\n\nstate_dir = user_data_path(\"acme-tool\", version=\"2026.03\")\ndb_path = state_dir / \"state.db\"\n```\n\nThe upstream how-to guide shows this as the intended pattern for migration between incompatible on-disk versions.\n\n### Merge defaults from shared config and override per user\n\n```python\nfrom platformdirs import PlatformDirs\n\ndirs = PlatformDirs(\"acme-tool\", \"Acme\")\n\nfor base in dirs.iter_config_paths():\n    candidate = base / \"settings.toml\"\n    if candidate.exists():\n        print(f\"found config at {candidate}\")\n\nuser_override = dirs.user_config_path / \"settings.toml\"\n```\n\nUse the iterator methods when you want the user path plus all shared candidate paths, rather than just one resolved string.\n\n### Use the newer helper directories directly\n\n```python\nfrom platformdirs import user_documents_path, user_downloads_path, user_bin_path\n\ndocuments = user_documents_path()\ndownloads = user_downloads_path()\nscripts_dir = user_bin_path()\n```\n\nThese helpers are useful for launcher registration, user-installed script locations, and file export workflows.\n\n### Compatibility alias for `appdirs` migrations\n\n```python\nfrom platformdirs import AppDirs\n\ndirs = AppDirs(\"acme-tool\", \"Acme\")\nassert dirs.user_cache_dir\n```\n\n`AppDirs` remains an alias for `PlatformDirs`, which helps when porting code from the older `appdirs` package.\n\n## Platform Behavior You Need To Remember\n\n### Linux and other Unix platforms\n\n- Uses XDG-style defaults such as `~/.local/share`, `~/.config`, `~/.cache`, `~/.local/state`, and `/run/user/<uid>`.\n- Honors `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, `XDG_CACHE_HOME`, `XDG_STATE_HOME`, `XDG_RUNTIME_DIR`, `XDG_DATA_DIRS`, and `XDG_CONFIG_DIRS`.\n- Shared directory helpers can be multi-root when `multipath=True`.\n- `use_site_for_root=True` changes `user_*` resolution when the process runs as root.\n\n### macOS\n\n- Data, config, and state default to `~/Library/Application Support/<AppName>`.\n- Cache defaults to `~/Library/Caches/<AppName>`.\n- Logs default to `~/Library/Logs/<AppName>`.\n- The same XDG environment variables are also honored on macOS and take precedence when set.\n\n### Windows\n\n- User data/config are under AppData and may include both `appauthor` and `appname`.\n- `roaming=True` switches user data/config to roaming AppData.\n- `Cache` and `Logs` suffixes are added by default when `opinion=True`.\n- The docs reference `WIN_PD_OVERRIDE_*` environment variables for overriding default Windows roots.\n\n### Android\n\n- Android-specific roots are supported for data, cache, runtime, and user folders.\n- Treat Android paths as platform-detected behavior; do not hardcode them unless your runtime contract guarantees Android.\n\n## Configuration And Environment\n\nThere is no auth model. Configuration is local and path-resolution driven.\n\nCommon controls:\n\n- Set XDG environment variables in tests, containers, or CI when you need deterministic Unix/macOS paths.\n- On Windows, use the documented `WIN_PD_OVERRIDE_*` overrides only when you intentionally need non-default roots.\n- Use `version=` when data formats are incompatible across app versions.\n- Use `ensure_exists=True` only when directory creation on read is acceptable.\n- Use `use_site_for_root=True` for root-owned services that should use system directories instead of `/root`.\n\nExample: deterministic config paths in tests.\n\n```python\nimport os\nfrom platformdirs import user_config_path\n\nos.environ[\"XDG_CONFIG_HOME\"] = \"/tmp/test-config\"\n\nconfig_dir = user_config_path(\"acme-tool\")\nassert str(config_dir) == \"/tmp/test-config/acme-tool\"\n```\n\nExample: Windows vendor folder suppression.\n\n```python\nfrom platformdirs import user_data_dir\n\npath_without_vendor = user_data_dir(\"acme-tool\", False)\n```\n\n## Common Pitfalls\n\n### Treating `site_*` paths as normal app-write locations\n\n`site_*` directories are generally shared and often require elevated permissions. Normal applications should usually write to `user_*` paths.\n\n### Forgetting that macOS data and config share the same base location\n\nOn macOS, `user_data_dir` and `user_config_dir` both resolve under `~/Library/Application Support/<AppName>`. If your app wants separate logical areas, create subdirectories yourself.\n\n### Expecting `multipath=True` to return a list\n\nFor `site_data_dir` and `site_config_dir`, `multipath=True` returns a path string joined by `os.pathsep`. Use `iter_*_paths()` or `iter_*_dirs()` if you need discrete candidates.\n\n### Causing unintended side effects with `ensure_exists=True`\n\nWhen enabled, property access can create directories. Keep it `False` in discovery code, dry runs, or read-only checks.\n\n### Mixing `str` and `Path`\n\nDo not call `Path` methods on `*_dir` results. Prefer `*_path` if you are going to join paths or read and write files.\n\n### Omitting `appname`\n\nWithout `appname`, many helpers return the raw platform root rather than an app-specific subdirectory. That is rarely what application code wants.\n\n### Assuming every helper appends `appname`\n\nHelpers such as `user_bin_dir`, `site_bin_dir`, `user_applications_dir`, and `site_applications_dir` return shared script or launcher directories and do not append `appname` or `version`.\n\n## Version-Sensitive Notes\n\n### 4.9.x\n\n- PyPI currently lists `4.9.4` as the latest release, published on 2026-03-05.\n- The Read the Docs site was last updated on 2026-03-02 and its changelog currently documents `4.9.2`, `4.9.1`, and `4.9.0`, not `4.9.4`.\n- `4.9.0` added `site_bin_dir` and `site_applications_dir`, and documented `use_site_for_root`.\n- `4.9.2` was documentation-focused, not an API-shape change.\n\n### 4.8.x\n\n- `4.8.0` added `user_applications_dir`, `user_bin_dir`, `site_state_dir`, `site_log_dir`, and `use_site_for_root`.\n- `4.8.0` also added Windows override support via `WIN_PD_OVERRIDE_*` and `PLATFORMDIRS_*` environment variables.\n\n### 4.7.x\n\n- `4.7.0` changed Unix runtime behavior to fall back to a temp directory when the runtime dir is not writable.\n\nIf your environment is pinned below `4.8.0` or `4.9.0`, verify that the newer helpers you plan to call actually exist before writing code against them.\n\n## Recommended Agent Workflow\n\n1. Prefer `PlatformDirs` when you need several directories for the same app.\n2. Prefer `*_path` variants in new Python code.\n3. Write normal app state to `user_*` directories, not `site_*`.\n4. Use iterator helpers when merging config or data from user and shared locations.\n5. Control XDG environment variables in tests before asserting exact Unix/macOS paths.\n6. Confirm version-sensitive helpers if the project is pinned below `4.8.0` or `4.9.0`.\n\n## Official Sources\n\n- Documentation root: https://platformdirs.readthedocs.io/en/latest/\n- Tutorial: https://platformdirs.readthedocs.io/en/latest/tutorial.html\n- How-to guides: https://platformdirs.readthedocs.io/en/latest/howto.html\n- Parameter reference: https://platformdirs.readthedocs.io/en/latest/parameters.html\n- API reference: https://platformdirs.readthedocs.io/en/latest/api.html\n- Platform details: https://platformdirs.readthedocs.io/en/latest/platforms.html\n- Changelog: https://platformdirs.readthedocs.io/en/latest/changelog.html\n- PyPI registry page: https://pypi.org/project/platformdirs/\n"
  },
  {
    "path": "content/playwright/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Playwright Python package guide for browser automation, end-to-end testing, and authenticated browser flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.58.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"playwright,python,browser,testing,e2e,automation\"\n---\n\n# Playwright Python Package Guide\n\n## Golden Rule\n\nUse the official `playwright` Python package, install the browser binaries after installing the wheel, and choose one API style per codepath: `playwright.sync_api` for sync code or `playwright.async_api` for async code. For resilient tests and automation, prefer locator-based actions such as `get_by_role()` over brittle CSS/XPath selectors.\n\n## Install And Setup\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"playwright==1.58.0\"\n```\n\nInstall browser binaries after the package install:\n\n```bash\npython -m playwright install\n```\n\nCommon variants:\n\n```bash\npython -m playwright install chromium\npython -m playwright install chromium firefox webkit\npython -m playwright install --with-deps chromium\nuv add \"playwright==1.58.0\"\npoetry add \"playwright==1.58.0\"\n```\n\nNotes:\n\n- `pip install playwright` does not download browser binaries.\n- On Linux CI or fresh containers, `python -m playwright install --with-deps chromium` is the quickest path to a working Chromium setup.\n- Use `pytest-playwright` when you want the pytest plugin and its browser fixtures; the core `playwright` package is enough for scripts, crawlers, smoke tests, and custom harnesses.\n\n## Initialize A Browser Session\n\n### Sync API\n\nUse the sync API in scripts, CLIs, and regular synchronous test code:\n\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True)\n    page = browser.new_page()\n    page.goto(\"https://playwright.dev/\")\n    page.get_by_role(\"link\", name=\"Docs\").click()\n    print(page.title())\n    browser.close()\n```\n\n### Async API\n\nUse the async API when your app already uses `asyncio`:\n\n```python\nimport asyncio\nfrom playwright.async_api import async_playwright\n\nasync def main() -> None:\n    async with async_playwright() as p:\n        browser = await p.chromium.launch(headless=True)\n        page = await browser.new_page()\n        await page.goto(\"https://playwright.dev/\")\n        await page.get_by_role(\"link\", name=\"Docs\").click()\n        print(await page.title())\n        await browser.close()\n\nasyncio.run(main())\n```\n\n## Core Usage Patterns\n\n### Use browser contexts for isolation\n\nContexts isolate cookies, local storage, permissions, extra headers, locale, and viewport settings:\n\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    context = browser.new_context(\n        base_url=\"https://example.com\",\n        locale=\"en-US\",\n        viewport={\"width\": 1440, \"height\": 900},\n    )\n    page = context.new_page()\n    page.goto(\"/\")\n    page.get_by_label(\"Email\").fill(\"user@example.com\")\n    page.get_by_label(\"Password\").fill(\"correct-horse-battery-staple\")\n    page.get_by_role(\"button\", name=\"Sign in\").click()\n    context.close()\n    browser.close()\n```\n\nUse a new context per test or workflow unless you intentionally want shared browser state.\n\n### Prefer locators over manual waits\n\nPlaywright's locator API auto-waits for actionability. Prefer:\n\n- `page.get_by_role(...)`\n- `page.get_by_label(...)`\n- `page.get_by_text(...)`\n- `page.get_by_test_id(...)`\n\nAvoid writing code that depends on `time.sleep(...)` or fragile selectors when a semantic locator exists.\n\n### Bootstrap selectors with codegen when needed\n\n```bash\npython -m playwright codegen https://example.com\n```\n\nUse generated selectors as a starting point, then simplify them into stable role, label, or test-id locators before committing test code.\n\n## Pytest Plugin Workflow\n\nInstall the plugin separately:\n\n```bash\npython -m pip install pytest-playwright\n```\n\nMinimal pytest usage:\n\n```python\ndef test_homepage(page):\n    page.goto(\"https://playwright.dev/\")\n    assert page.get_by_role(\"link\", name=\"Docs\").is_visible()\n```\n\nCommon CLI flags:\n\n```bash\npytest --browser chromium\npytest --browser firefox --headed\npytest --device \"iPhone 13\"\n```\n\nImportant plugin behavior:\n\n- Plugin CLI arguments only apply to the default `browser`, `context`, and `page` fixtures.\n- If you call `browser.new_context()` yourself, pass the options explicitly or override fixtures such as `browser_context_args`.\n- For async pytest fixtures and tests, use `pytest-playwright-asyncio` together with a compatible `pytest-asyncio` release instead of mixing sync fixtures into async code.\n\n## Authentication And State Reuse\n\nPersist authenticated state with `storage_state()` so login happens once and later runs reuse the session:\n\n```python\nfrom pathlib import Path\nfrom playwright.sync_api import sync_playwright\n\nAUTH_FILE = Path(\"playwright/.auth/user.json\")\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    context = browser.new_context()\n    page = context.new_page()\n\n    page.goto(\"https://example.com/login\")\n    page.get_by_label(\"Email\").fill(\"user@example.com\")\n    page.get_by_label(\"Password\").fill(\"correct-horse-battery-staple\")\n    page.get_by_role(\"button\", name=\"Sign in\").click()\n\n    AUTH_FILE.parent.mkdir(parents=True, exist_ok=True)\n    context.storage_state(path=str(AUTH_FILE), indexed_db=True)\n\n    context.close()\n    browser.close()\n```\n\nReuse it later:\n\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    context = browser.new_context(storage_state=\"playwright/.auth/user.json\")\n    page = context.new_page()\n    page.goto(\"https://example.com/app\")\n    browser.close()\n```\n\nNotes:\n\n- Treat storage-state files like secrets; they can contain session cookies and local storage.\n- Add `playwright/.auth/` to `.gitignore`.\n- `indexed_db=True` matters for apps that keep auth in IndexedDB instead of only cookies or local storage.\n\n## Browser And Network Configuration\n\nUseful launch and install controls:\n\n```python\nbrowser = p.chromium.launch(\n    headless=False,\n    slow_mo=250,\n    channel=\"chrome\",\n)\n```\n\nEnvironment variables that matter in enterprise and CI setups:\n\n- `PLAYWRIGHT_BROWSERS_PATH`: share browser binaries across projects or CI jobs\n- `PLAYWRIGHT_DOWNLOAD_HOST`: use a custom download mirror\n- `PLAYWRIGHT_NODEJS_PATH`: point Playwright at a custom Node.js binary for browser installs\n- `HTTPS_PROXY`: proxy for browser downloads\n- `NODE_EXTRA_CA_CERTS`: extra trusted CAs for TLS interception environments\n\nIf browser downloads fail behind a corporate proxy or custom CA, fix the environment first instead of retrying tests with partially installed browsers.\n\n## Common Pitfalls\n\n### 1. Package installed, browsers missing\n\nIf you see executable-not-found errors after `pip install`, run:\n\n```bash\npython -m playwright install\n```\n\nRe-run it after upgrading Playwright to a version that expects newer browser builds.\n\n### 2. Mixing sync and async APIs\n\nDo not call sync Playwright APIs inside an `asyncio` event loop, and do not forget `await` on async Playwright calls. Pick one import style and keep the whole stack consistent.\n\n### 3. Using brittle selectors\n\nIn `1.58`, the deprecated React and Vue locator engines (`_react=`, `_vue=`) and the `:light` CSS extension were removed. Prefer accessibility-first locators and test IDs.\n\n### 4. Assuming old launch options still exist\n\nThe `devtools` launch option was removed in `1.58`. Pass Chromium args directly when you need equivalent behavior.\n\n### 5. Leaking state between tests\n\nA `browser` can host many contexts. Reusing one context across unrelated tests usually creates order-dependent failures. Prefer a fresh context per test or per authenticated role.\n\n### 6. Committing auth artifacts\n\nStorage-state files and screenshots can contain secrets, account data, or internal URLs. Keep them out of version control unless they are sanitized fixtures created for testing only.\n\n## Version-Sensitive Notes For 1.58.0\n\n- `1.58.0` removed `_react`, `_vue`, `:light`, and the `devtools` launch option.\n- The same release dropped macOS 13 support for WebKit.\n- If you are copying older community snippets, expect selector and launch-option drift around these removed features.\n- Auth-state reuse got more robust in recent Playwright releases because `storage_state(indexed_db=True)` can now capture IndexedDB-backed auth state; use it when cookie-only snapshots are not enough.\n\n## Official Source URLs\n\n- Docs intro: `https://playwright.dev/python/docs/intro`\n- API reference: `https://playwright.dev/python/docs/api/class-playwright`\n- Library guide: `https://playwright.dev/python/docs/library`\n- Locators guide: `https://playwright.dev/python/docs/locators`\n- Authentication guide: `https://playwright.dev/python/docs/auth`\n- Test runners guide: `https://playwright.dev/python/docs/test-runners`\n- Browsers and install env vars: `https://playwright.dev/python/docs/browsers`\n- Release notes: `https://playwright.dev/python/docs/release-notes`\n- PyPI package: `https://pypi.org/project/playwright/`\n"
  },
  {
    "path": "content/playwright/docs/playwright/javascript/DOC.md",
    "content": "---\nname: playwright\ndescription: \"Playwright for JavaScript and Node.js: browser automation, locators, auth state reuse, and browser installation\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.58.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"playwright,javascript,nodejs,browser,testing,e2e,automation\"\n---\n\n# Playwright JavaScript Package Guide\n\n## Golden Rule\n\nUse the official `playwright` package for browser automation in JavaScript and Node.js, keep browser binaries aligned with the installed package version, prefer locator-based actions such as `getByRole()` over brittle CSS/XPath selectors, and use a fresh browser context per test or workflow. If you want the Playwright test runner, install `@playwright/test` separately.\n\n## Install And Setup\n\nInstall the library package:\n\n```bash\nnpm install -D playwright\n```\n\nCommon package-manager variants:\n\n```bash\npnpm add -D playwright\nyarn add -D playwright\n```\n\nProvision browsers explicitly on fresh machines, CI, or container images:\n\n```bash\nnpx playwright install\nnpx playwright install chromium\nnpx playwright install chromium firefox webkit\nnpx playwright install --with-deps chromium\n```\n\nNotes:\n\n- `playwright` is the browser automation library plus CLI.\n- `playwright-core` is the lower-level package when you do not want Playwright to manage browser downloads.\n- `@playwright/test` is the Playwright test runner package; install it separately when you want fixtures, assertions, retries, projects, and reporter support.\n- On Linux CI or brand-new containers, `npx playwright install --with-deps chromium` is the quickest path to a working Chromium setup.\n\n## Useful Environment Variables\n\nThese environment variables matter most in CI, proxy, or enterprise setups:\n\n```bash\nPLAYWRIGHT_BROWSERS_PATH=\"$HOME/.cache/ms-playwright\"\nHTTPS_PROXY=\"http://proxy.internal:8080\"\nNODE_EXTRA_CA_CERTS=\"/etc/ssl/certs/internal-root-ca.pem\"\n```\n\nTypical commands:\n\n```bash\nPLAYWRIGHT_BROWSERS_PATH=\"$HOME/.cache/ms-playwright\" npx playwright install chromium\nPWDEBUG=1 node scripts/login.mjs\n```\n\nImportant variables from the browser-install docs:\n\n- `PLAYWRIGHT_BROWSERS_PATH`: store browser binaries in a shared location instead of the default cache.\n- `PLAYWRIGHT_DOWNLOAD_HOST`: use a custom browser download mirror.\n- `HTTPS_PROXY`: route browser downloads through a proxy.\n- `NODE_EXTRA_CA_CERTS`: trust additional CA certificates when TLS interception is in place.\n- `PWDEBUG=1`: launch headed debugging with Playwright Inspector.\n\nIf browser installation fails behind a proxy or custom certificate chain, fix the environment first instead of retrying tests with partially installed browsers.\n\n## Initialize A Browser Session\n\nUse the library directly in scripts, custom harnesses, crawlers, and smoke tests:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch({ headless: true });\nconst context = await browser.newContext({\n  baseURL: process.env.E2E_BASE_URL ?? 'https://playwright.dev',\n  locale: 'en-US',\n  viewport: { width: 1440, height: 900 },\n});\n\nconst page = await context.newPage();\nawait page.goto('/');\nawait page.getByRole('link', { name: 'Docs' }).click();\n\nconsole.log(await page.title());\n\nawait context.close();\nawait browser.close();\n```\n\nIf your project uses CommonJS instead of ESM:\n\n```javascript\nconst { chromium } = require('playwright');\n```\n\n## Core Usage Patterns\n\n### Use browser contexts for isolation\n\nContexts isolate cookies, local storage, permissions, headers, locale, timezone, and viewport settings:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst context = await browser.newContext({\n  baseURL: process.env.E2E_BASE_URL ?? 'https://example.com',\n  locale: 'en-US',\n  timezoneId: 'America/Los_Angeles',\n  viewport: { width: 1440, height: 900 },\n  extraHTTPHeaders: {\n    'x-test-run': 'smoke',\n  },\n});\n\nconst page = await context.newPage();\nawait page.goto('/login');\nawait page.getByLabel('Email').fill(process.env.E2E_EMAIL ?? 'user@example.com');\nawait page.getByLabel('Password').fill(process.env.E2E_PASSWORD ?? 'correct-horse-battery-staple');\nawait page.getByRole('button', { name: 'Sign in' }).click();\n\nawait context.close();\nawait browser.close();\n```\n\nUse a new context per test or per authenticated role unless you intentionally want shared browser state.\n\n### Prefer locators over manual waits\n\nPlaywright locators auto-wait for visibility, stability, and other actionability checks. Prefer:\n\n- `page.getByRole(...)`\n- `page.getByLabel(...)`\n- `page.getByText(...)`\n- `page.getByTestId(...)`\n- `page.locator(...)` when you truly need a CSS or text-based locator chain\n\nAvoid `page.waitForTimeout()` for readiness checks when a locator, navigation wait, or network wait expresses the condition directly.\n\n### Persist and reuse authenticated state\n\nSave storage state after an interactive login so later runs can start from an already-authenticated session:\n\n```javascript\nimport { chromium } from 'playwright';\nimport { mkdir } from 'node:fs/promises';\n\nconst authFile = 'playwright/.auth/user.json';\n\nconst browser = await chromium.launch();\nconst context = await browser.newContext();\nconst page = await context.newPage();\n\nawait page.goto(`${process.env.E2E_BASE_URL ?? 'https://example.com'}/login`);\nawait page.getByLabel('Email').fill(process.env.E2E_EMAIL ?? 'user@example.com');\nawait page.getByLabel('Password').fill(process.env.E2E_PASSWORD ?? 'correct-horse-battery-staple');\nawait page.getByRole('button', { name: 'Sign in' }).click();\n\nawait mkdir('playwright/.auth', { recursive: true });\nawait context.storageState({\n  path: authFile,\n  indexedDB: true,\n});\n\nawait context.close();\nawait browser.close();\n```\n\nReuse it later:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst context = await browser.newContext({\n  storageState: 'playwright/.auth/user.json',\n});\n\nconst page = await context.newPage();\nawait page.goto(`${process.env.E2E_BASE_URL ?? 'https://example.com'}/app`);\n\nawait context.close();\nawait browser.close();\n```\n\nNotes:\n\n- Treat storage-state files like secrets because they can contain cookies, local storage, and IndexedDB-backed auth state.\n- Add `playwright/.auth/` to `.gitignore`.\n- `indexedDB: true` matters when the app stores authentication outside cookies or local storage.\n\n### Intercept or stub network requests\n\nUse routing when you need deterministic UI tests or want to decouple browser flows from unstable backends:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst context = await browser.newContext({\n  baseURL: process.env.E2E_BASE_URL ?? 'https://example.com',\n});\nconst page = await context.newPage();\n\nawait page.route('**/api/search**', async (route) => {\n  await route.fulfill({\n    status: 200,\n    contentType: 'application/json',\n    body: JSON.stringify({ items: [{ id: 1, title: 'stubbed result' }] }),\n  });\n});\n\nawait page.goto('/search');\nawait page.getByRole('textbox', { name: 'Search' }).fill('playwright');\nawait page.getByRole('button', { name: 'Submit' }).click();\n\nawait context.close();\nawait browser.close();\n```\n\nUse `route.continue()` when you want to modify or inspect the outgoing request and still hit the real backend.\n\n### Bootstrap selectors with codegen\n\nUse the code generator to explore a page and capture initial locator suggestions:\n\n```bash\nnpx playwright codegen https://example.com\n```\n\nTreat generated selectors as a starting point. Simplify them into role, label, or test-id locators before committing test code.\n\n### Capture a trace for debugging\n\nTracing is useful when a browser flow works locally but fails in CI:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst browser = await chromium.launch();\nconst context = await browser.newContext();\n\nawait context.tracing.start({\n  screenshots: true,\n  snapshots: true,\n});\n\nconst page = await context.newPage();\nawait page.goto(process.env.E2E_BASE_URL ?? 'https://playwright.dev');\n\nawait context.tracing.stop({ path: 'playwright-trace.zip' });\nawait context.close();\nawait browser.close();\n```\n\nOpen the trace locally:\n\n```bash\nnpx playwright show-trace playwright-trace.zip\n```\n\n## Playwright Test Runner Workflow\n\nThe `playwright` package does not replace the test-runner package. When you want `test()`, `expect()`, fixtures, retries, and project configuration, install `@playwright/test` too:\n\n```bash\nnpm install -D @playwright/test\nnpx playwright install\n```\n\nMinimal `playwright.config.ts`:\n\n```typescript\nimport { defineConfig, devices } from '@playwright/test';\n\nexport default defineConfig({\n  testDir: './tests',\n  use: {\n    baseURL: process.env.E2E_BASE_URL ?? 'http://127.0.0.1:3000',\n    trace: 'on-first-retry',\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n  ],\n});\n```\n\nMinimal test:\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest('homepage shows docs link', async ({ page }) => {\n  await page.goto('/');\n  await expect(page.getByRole('link', { name: 'Docs' })).toBeVisible();\n});\n```\n\nRun it:\n\n```bash\nnpx playwright test\nnpx playwright test --project=chromium --headed\n```\n\n## Common Pitfalls\n\n### 1. Package installed, browsers missing or mismatched\n\nIf you see browser executable errors or version-mismatch errors, run:\n\n```bash\nnpx playwright install\n```\n\nRe-run browser installation after upgrading Playwright to a version that expects newer browser builds.\n\n### 2. Confusing `playwright`, `playwright-core`, and `@playwright/test`\n\n- Use `playwright` for the automation library and CLI.\n- Use `@playwright/test` for the test runner.\n- Use `playwright-core` only when another tool or environment manages browsers for you.\n\n### 3. Using brittle selectors\n\nPrefer role, label, placeholder, text, and test-id locators. Older community snippets that depend on framework-specific selector engines or long CSS chains are usually harder to maintain.\n\n### 4. Waiting with fixed sleeps\n\n`page.waitForTimeout()` is fine for local debugging, but it is a poor readiness strategy in committed tests. Prefer locator actions, `waitForURL()`, `waitForResponse()`, or other waits that match the real condition.\n\n### 5. Reusing one context across unrelated tests\n\nA browser can host many contexts. Reusing one context across unrelated tests tends to leak cookies, permissions, and storage, which creates order-dependent failures.\n\n### 6. Committing auth artifacts and traces\n\nStorage-state files, screenshots, videos, and traces can contain secrets, account data, and internal URLs. Keep them out of version control unless they are sanitized fixtures created for testing.\n\n## Version-Sensitive Notes For 1.58.2\n\n- Playwright `1.58.x` includes the `1.58.0` breaking removals of `_react`, `_vue`, `:light`, and the Chromium `devtools` launch option.\n- If you are copying older snippets, rewrite selector logic around role, label, text, or test-id locators instead of removed selector engines.\n- If you relied on the old `devtools` launch flag, switch to Chromium launch arguments or Playwright Inspector-based debugging.\n- Playwright `1.58` also dropped macOS 13 support for WebKit.\n\n## Official Source URLs\n\n- Intro: `https://playwright.dev/docs/intro`\n- API reference: `https://playwright.dev/docs/api/class-playwright`\n- Library guide: `https://playwright.dev/docs/library`\n- Locators guide: `https://playwright.dev/docs/locators`\n- Authentication guide: `https://playwright.dev/docs/auth`\n- Network guide: `https://playwright.dev/docs/network`\n- Codegen guide: `https://playwright.dev/docs/codegen`\n- Browser install and environment variables: `https://playwright.dev/docs/browsers`\n- Release notes: `https://playwright.dev/docs/release-notes`\n- npm package: `https://www.npmjs.com/package/playwright`\n"
  },
  {
    "path": "content/playwright-community/skills/login-flows/SKILL.md",
    "content": "---\nname: login-flows\ndescription: Common login automation patterns for web apps using Playwright\nmetadata:\n  updated-on: \"2026-02-01\"\n  source: community\n  tags: \"browser,automation,playwright,login,testing\"\n---\n\n# Login Flow Patterns for Playwright\n\nReusable patterns for automating login flows in end-to-end tests.\n\n## Basic Username/Password Login\n\n```typescript\nimport { Page } from '@playwright/test';\n\nasync function login(page: Page, username: string, password: string) {\n  await page.goto('/login');\n  await page.fill('[name=\"username\"]', username);\n  await page.fill('[name=\"password\"]', password);\n  await page.click('button[type=\"submit\"]');\n  await page.waitForURL('/dashboard');\n}\n```\n\n## OAuth / SSO Login\n\nFor OAuth flows that redirect to an external provider:\n\n```typescript\nasync function loginWithOAuth(page: Page) {\n  await page.goto('/login');\n  await page.click('text=Sign in with Google');\n\n  // Handle the OAuth popup or redirect\n  await page.fill('input[type=\"email\"]', process.env.TEST_EMAIL!);\n  await page.click('text=Next');\n  await page.fill('input[type=\"password\"]', process.env.TEST_PASSWORD!);\n  await page.click('text=Next');\n\n  // Wait for redirect back to app\n  await page.waitForURL('**/dashboard');\n}\n```\n\n## Persisting Auth State (storageState)\n\nAvoid logging in before every test by saving and reusing browser state:\n\n```typescript\n// global-setup.ts — runs once before all tests\nimport { chromium } from '@playwright/test';\n\nasync function globalSetup() {\n  const browser = await chromium.launch();\n  const page = await browser.newPage();\n\n  await page.goto('/login');\n  await page.fill('[name=\"username\"]', 'testuser');\n  await page.fill('[name=\"password\"]', 'testpass');\n  await page.click('button[type=\"submit\"]');\n  await page.waitForURL('/dashboard');\n\n  // Save signed-in state\n  await page.context().storageState({ path: './auth.json' });\n  await browser.close();\n}\n\nexport default globalSetup;\n```\n\nThen in `playwright.config.ts`:\n\n```typescript\nexport default defineConfig({\n  globalSetup: './global-setup.ts',\n  use: {\n    storageState: './auth.json',\n  },\n});\n```\n\n## MFA / 2FA Handling\n\nFor test environments with TOTP-based 2FA:\n\n```typescript\nimport { authenticator } from 'otplib';\n\nasync function loginWithMFA(page: Page, secret: string) {\n  await login(page, 'user', 'pass');\n\n  // Generate TOTP code\n  const code = authenticator.generate(secret);\n  await page.fill('[name=\"totp\"]', code);\n  await page.click('button[type=\"submit\"]');\n  await page.waitForURL('/dashboard');\n}\n```\n\n## Tips\n\n- Always use `storageState` to avoid repeated logins — it's the single biggest speedup for E2E suites\n- Use environment variables for credentials, never hardcode them\n- For CI, consider a dedicated test user with stable credentials\n- Use `page.waitForURL()` instead of arbitrary `waitForTimeout()` after login\n"
  },
  {
    "path": "content/plotly/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Plotly Python graphing library for interactive figures, notebook display, HTML export, and static image generation\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"plotly,python,visualization,charts,dash,jupyter\"\n---\n\n# Plotly Python Package Guide\n\n## Golden Rule\n\nUse `plotly` for interactive visualization in Python, start with `plotly.express` for most charts, and drop to `plotly.graph_objects` when you need precise trace or layout control. In Plotly 6.x, assume notebook rendering, image export, and map traces are the areas most likely to break if you copy older examples without checking the current docs.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"plotly==6.6.0\"\n```\n\nUseful variants:\n\n```bash\npython -m pip install \"plotly[express]==6.6.0\"\npython -m pip install \"plotly==6.6.0\" \"kaleido>=1\"\nuv add \"plotly==6.6.0\"\npoetry add \"plotly==6.6.0\"\n```\n\nNotes:\n\n- `plotly[express]` installs dependencies used by Plotly Express; you still need a supported dataframe library for dataframe-centric workflows.\n- Install `kaleido` if you need `write_image()` or other static export helpers.\n- Install `plotly-geo==1.0.0` only for older geo features that rely on the separate shape bundle, such as the county choropleth figure factory.\n\n## Initialize And Display Figures\n\nMinimal Plotly Express example:\n\n```python\nimport plotly.express as px\n\nfig = px.line(\n    x=[\"2026-03-10\", \"2026-03-11\", \"2026-03-12\"],\n    y=[12, 18, 15],\n    title=\"Requests per day\",\n    markers=True,\n)\n\nfig.update_layout(xaxis_title=\"Date\", yaxis_title=\"Requests\")\nfig.show()\n```\n\nMinimal Graph Objects example:\n\n```python\nimport plotly.graph_objects as go\n\nfig = go.Figure()\nfig.add_trace(go.Bar(x=[\"ok\", \"warn\", \"error\"], y=[42, 7, 2], name=\"Jobs\"))\nfig.update_layout(title=\"Job Status\", bargap=0.2)\nfig.show()\n```\n\nPractical rule:\n\n- Start with `px.*` for fast figure creation.\n- Use `update_layout()`, `update_traces()`, and `add_trace()` to customize.\n- Switch to `go.Figure(...)` when the chart is assembled incrementally or needs trace types that are easier to control directly.\n\n## Notebook And Renderer Setup\n\nPlotly usually auto-detects a renderer, but notebook environments are the most common source of confusion.\n\nFor JupyterLab:\n\n```bash\npython -m pip install jupyterlab anywidget\n```\n\nFor classic Jupyter Notebook:\n\n```bash\npython -m pip install \"notebook>=7.0\" \"anywidget>=0.9.13\"\n```\n\nTo force browser rendering from a local Python process:\n\n```python\nimport plotly.io as pio\n\npio.renderers.default = \"browser\"\n```\n\nYou can also set the renderer through the environment:\n\n```bash\nexport PLOTLY_RENDERER=browser\n```\n\nUse `renderer=\"browser\"` or another renderer name on `fig.show(...)` when you need a one-off override.\n\n## Core Usage Patterns\n\n### Plotly Express returns normal `Figure` objects\n\nEvery Plotly Express call returns a `plotly.graph_objects.Figure`, so you can mix high-level and low-level APIs:\n\n```python\nimport plotly.express as px\n\nfig = px.scatter(\n    x=[1, 2, 3, 4],\n    y=[10, 14, 13, 17],\n    color=[\"a\", \"a\", \"b\", \"b\"],\n    title=\"Experiment results\",\n)\n\nfig.update_traces(marker_size=12)\nfig.update_layout(template=\"plotly_white\")\nfig.add_hline(y=15, line_dash=\"dash\")\nfig.show()\n```\n\n### Build multi-trace figures explicitly\n\n```python\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\n\nfig = make_subplots(rows=1, cols=2, subplot_titles=[\"Latency\", \"Errors\"])\nfig.add_trace(go.Scatter(x=[1, 2, 3], y=[120, 90, 140], mode=\"lines+markers\"), row=1, col=1)\nfig.add_trace(go.Bar(x=[\"a\", \"b\", \"c\"], y=[1, 0, 2]), row=1, col=2)\nfig.update_layout(height=450, width=900, title=\"Service health\")\nfig.show()\n```\n\n### Save interactive HTML\n\nUse HTML export when the recipient needs hover, zoom, legend toggles, or offline sharing:\n\n```python\nimport plotly.express as px\n\nfig = px.bar(x=[\"A\", \"B\", \"C\"], y=[1, 3, 2], title=\"Interactive export\")\nfig.write_html(\"report.html\", include_plotlyjs=\"cdn\")\n```\n\nUse `fig.to_html(full_html=False)` when embedding a figure into a larger HTML template or web response.\n\n### Save static images\n\n```python\nimport plotly.express as px\n\nfig = px.bar(x=[\"A\", \"B\", \"C\"], y=[1, 3, 2])\nfig.write_image(\"chart.png\", width=900, height=500, scale=2)\n```\n\nIf static export fails, check both `kaleido` and the local Chrome requirement before debugging your figure code.\n\n## Configuration And Auth Notes\n\n`plotly` is a local visualization library, so it does not require API keys for normal figure generation, notebook display, HTML export, or static image export.\n\nAuth-related edge cases:\n\n- Dash apps that display Plotly figures have their own server and deployment configuration, but not Plotly-package auth.\n- External tile providers or custom map styles can introduce their own credentials outside Plotly itself.\n- Plotly-provided map styles no longer require Mapbox API keys when you use the newer MapLibre-backed map traces.\n\nUseful configuration points:\n\n- `pio.renderers.default` sets the default display backend for the current session.\n- `PLOTLY_RENDERER` sets the default renderer at process startup.\n- `template` in `update_layout()` controls theme defaults.\n- `include_plotlyjs` in `write_html()` trades file size against offline portability.\n\n## Common Pitfalls\n\n- Old notebook instructions are often wrong for Plotly 6.x. Use Notebook 7+ and `anywidget`, not legacy extension setup.\n- `go.FigureWidget` now depends on `anywidget`. If a widget example errors in Jupyter, check that package first.\n- `fig.show(renderer=\"browser\")` only works when Python runs locally on the same machine as the browser.\n- `include_plotlyjs=\"cdn\"` makes exported HTML much smaller, but the file will not render offline.\n- `write_image()` needs `kaleido`; with Kaleido v1+, missing Chrome can also cause failures.\n- VS Code notebooks can lag the newest Plotly.js features because rendering depends on the editor extension's bundled frontend.\n- Plotly Express accepts many dataframe-like inputs, but old examples may assume pandas-specific behavior that changed with Narwhals-backed support in v6.\n\n## Version-Sensitive Notes For Plotly 6.x\n\n- Plotly 6 no longer supports Jupyter Notebook versions earlier than `7`.\n- `go.FigureWidget` uses `anywidget` in v6, so older `ipywidgets`-only setup instructions are stale.\n- Plotly Express in v6 uses Narwhals, which improves native support for pandas, Polars, and PyArrow inputs.\n- Mapbox-based traces are deprecated. For new code, prefer `px.scatter_map`, `px.line_map`, `px.choropleth_map`, `px.density_map`, and the `go.*map` trace types instead of `*_mapbox`.\n- When migrating from older map code, update `layout.mapbox` to `layout.map` and `mapbox_style` to `map_style`.\n- Plotly's static export docs still mention Orca in older places, but Orca support was scheduled for removal after September 2025. Use Kaleido in new code.\n- Plotly 6.2.0 deprecated `engine=` for image export and the old `plotly.io.kaleido.scope` path in favor of `plotly.io.defaults`, so prefer current examples when configuring export defaults.\n\n## Official Sources\n\n- Python API reference: `https://plotly.com/python-api-reference/`\n- Getting started: `https://plotly.com/python/getting-started/`\n- Plotly Express overview: `https://plotly.com/python/plotly-express/`\n- Renderers and display: `https://plotly.com/python/renderers/`\n- Interactive HTML export: `https://plotly.com/python/interactive-html-export/`\n- Static image export: `https://plotly.com/python/static-image-export/`\n- Plotly 6 migration guide: `https://plotly.com/python/v6-migration/`\n- MapLibre migration guide: `https://plotly.com/python/mapbox-to-maplibre/`\n- PyPI project page: `https://pypi.org/project/plotly/`\n- PyPI JSON metadata: `https://pypi.org/pypi/plotly/json`\n"
  },
  {
    "path": "content/plotnine/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"plotnine grammar-of-graphics plotting library for Python with pandas and polars DataFrame support\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.15.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"plotnine,python,visualization,ggplot,data-viz,pandas,polars,matplotlib\"\n---\n\n# plotnine Python Package Guide\n\n## Golden Rule\n\nUse `plotnine` when you want ggplot2-style grammar-of-graphics plots in Python. Put dataframe column names in `aes(...)`, set constant styles outside `aes(...)`, use `.show()` in scripts and terminals, and use `.save(...)` for deterministic output files.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"plotnine==0.15.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"plotnine==0.15.3\"\npoetry add \"plotnine==0.15.3\"\n```\n\nInstall optional extras when you need them:\n\n```bash\npython -m pip install \"plotnine[extra]==0.15.3\"\n```\n\n`plotnine[extra]` pulls in commonly needed optional packages such as:\n\n- `adjustText` for automatic text-label adjustment\n- `geopandas` for geographic data helpers\n- `scikit-learn` for Gaussian-process smoothing\n- `scikit-misc` for LOESS smoothing\n\n## Initialize And Render A First Plot\n\nThe standard workflow is:\n\n1. Start with a dataframe.\n2. Create a `ggplot(data, aes(...))` object.\n3. Add layers with `+`.\n4. Render with `.show()` or save with `.save(...)`.\n\n```python\nfrom plotnine import aes, geom_point, geom_smooth, ggplot, labs, theme_minimal\nfrom plotnine.data import penguins\n\np = (\n    ggplot(\n        penguins.dropna(subset=[\"bill_length_mm\", \"bill_depth_mm\", \"species\"]),\n        aes(\"bill_length_mm\", \"bill_depth_mm\", color=\"species\"),\n    )\n    + geom_point(size=2.5, alpha=0.7)\n    + geom_smooth(method=\"lm\", se=False)\n    + labs(\n        title=\"Palmer Penguins\",\n        x=\"Bill length (mm)\",\n        y=\"Bill depth (mm)\",\n    )\n    + theme_minimal()\n)\n\np.show()\n```\n\nNotes:\n\n- In notebooks, returning the plot as the last expression is usually enough to render it.\n- In scripts, REPL sessions, and agent-driven terminal runs, call `.show()` explicitly.\n- The built-in example datasets live under `plotnine.data`.\n\n## Core Usage\n\n### Map data in `aes`, set constants on the geom\n\nMapped aesthetics create scales and legends. Constant aesthetics should be set directly on the layer:\n\n```python\nfrom plotnine import aes, geom_point, ggplot\n\np = (\n    ggplot(df, aes(\"x\", \"y\", color=\"group\"))\n    + geom_point(size=3, alpha=0.8)\n)\n```\n\nDo not do this for a constant color:\n\n```python\nggplot(df, aes(\"x\", \"y\", color=\"blue\"))  # wrong: \"blue\" is treated as mapped data\n```\n\nInstead:\n\n```python\nggplot(df, aes(\"x\", \"y\")) + geom_point(color=\"blue\")\n```\n\n### Facet and label plots\n\n```python\nfrom plotnine import aes, facet_wrap, geom_point, ggplot, labs\n\np = (\n    ggplot(df, aes(\"x\", \"y\", color=\"group\"))\n    + geom_point()\n    + facet_wrap(\"~group\")\n    + labs(title=\"Grouped scatter plot\")\n)\n```\n\n### Control scales vs coordinate zoom\n\nIf you want to zoom without dropping data that affects statistics, use a coordinate system such as `coord_cartesian(...)` instead of scale limits.\n\n```python\nfrom plotnine import aes, coord_cartesian, geom_point, ggplot\n\np = (\n    ggplot(df, aes(\"x\", \"y\"))\n    + geom_point()\n    + coord_cartesian(xlim=(0, 10), ylim=(0, 100))\n)\n```\n\nUse `xlim(...)`, `ylim(...)`, or scale limits only when you intentionally want rows outside the range removed before stats are computed.\n\n### Save reproducible output\n\n`plotnine` uses inches for physical size and `dpi` for raster resolution:\n\n```python\np.save(\"reports/penguins-scatter.png\", width=8, height=5, dpi=150)\n```\n\nUseful save-time options:\n\n- `format=\"svg\"` or a `.svg` filename for vector output\n- `verbose=False` to suppress save logging\n- `limitsize=False` only when you intentionally need images larger than the default 25x25 inch safety limit\n\n## Configuration\n\n`plotnine` does not use API credentials or service authentication. The configuration surface is mainly rendering and theme behavior.\n\n### Set a default figure size\n\n```python\nfrom plotnine.options import set_option\n\nset_option(\"figure_size\", (8, 5))\n```\n\nPer-plot sizing is often clearer when different plots need different output dimensions:\n\n```python\nfrom plotnine import theme\n\np = p + theme(figure_size=(8, 5))\n```\n\n### SVG font portability\n\nIf you save SVGs for environments that may not have the same fonts installed, disable font embedding assumptions:\n\n```python\nfrom plotnine import theme\n\np = p + theme(svg_usefonts=False)\n```\n\n## Common Pitfalls\n\n- `aes(...)` expects variable names or expressions, usually as strings. `aes(\"colname\")` is correct for dataframe columns.\n- Constant style values such as `color=\"red\"` or `size=3` belong on the geom or stat, not inside `aes(...)`.\n- `print(p)` and `repr(p)` are not the modern rendering path. Use `p.show()` in scripts.\n- `save(width=..., height=...)` uses inches, not pixels. Control raster sharpness with `dpi`.\n- `xlim(...)`, `ylim(...)`, and scale limits can remove rows before stats run. Use `coord_cartesian(...)` when you only want to zoom.\n- Text repulsion and some smoothing methods need optional dependencies. If labels or LOESS examples fail, install `plotnine[extra]`.\n- `plotnine` sits on top of `matplotlib`, so missing fonts, backend quirks, and environment-specific rendering issues usually come from the `matplotlib` side.\n\n## Version-Sensitive Notes\n\n- This doc is for stable `0.15.3`, which PyPI lists as the latest stable release as of March 12, 2026. PyPI also shows `0.16.0a*` prereleases; do not copy prerelease behavior into stable projects unless the project is explicitly pinned there.\n- `0.15.0` added plot composition support, so expressions like `(plot_a | plot_b)` and `(plot_a / plot_b)` are valid in the `0.15.x` line.\n- The changelog for `0.15.3` notes compatibility cleanup for pandas `3.0.0` copy-on-write warnings, so older blog posts that warn about those warnings may be stale for `0.15.3`.\n- If you are migrating from much older `plotnine` releases, check the upstream changelog before relying on `print(plot)` examples or composition behavior from pre-`0.15` content.\n\n## Official Sources\n\n- Docs home: `https://plotnine.org/`\n- Reference: `https://plotnine.org/reference/`\n- Installation guide: `https://plotnine.org/#installation`\n- Guide index: `https://plotnine.org/guide/`\n- Changelog: `https://plotnine.org/changelog.html`\n- PyPI: `https://pypi.org/project/plotnine/`\n"
  },
  {
    "path": "content/pluggy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pluggy package guide for building and validating hook-based plugin systems in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pluggy,python,plugins,hooks,extension-points\"\n---\n\n# pluggy Python Package Guide\n\n## What It Is\n\n`pluggy` is the small hook and plugin framework used by `pytest`, but it is also a general-purpose library for any Python application that wants extension points.\n\nThe host application defines hook specifications, plugins implement those hooks, and `pluggy.PluginManager` validates registration and dispatches calls.\n\nThis doc is pinned to `pluggy` `1.6.0`. The official Read the Docs site is the maintainer source of truth, but the `stable` pages are not a frozen release snapshot, so check the `1.6.0` changelog when behavior looks version-sensitive.\n\n## Install\n\n```bash\npip install pluggy==1.6.0\n```\n\n`pluggy` `1.6.0` requires Python `>=3.9`.\n\n## Core Objects\n\n- `pluggy.HookspecMarker(\"myapp\")` marks host hook specifications.\n- `pluggy.HookimplMarker(\"myapp\")` marks plugin implementations.\n- `pluggy.PluginManager(\"myapp\")` owns registration, validation, tracing, and hook dispatch.\n- `pm.add_hookspecs(...)` registers the hook specification namespace.\n- `pm.register(plugin, name=...)` registers a plugin object or module.\n- `pm.hook.<hook_name>(...)` calls a hook across all registered implementations.\n\nThe project name string must match across `HookspecMarker`, `HookimplMarker`, and `PluginManager`.\n\n## Minimal Working Setup\n\n```python\nimport pluggy\n\nhookspec = pluggy.HookspecMarker(\"myapp\")\nhookimpl = pluggy.HookimplMarker(\"myapp\")\n\nclass Spec:\n    @hookspec\n    def transform(self, text: str) -> str:\n        \"\"\"Return a transformed string.\"\"\"\n\nclass UpperPlugin:\n    @hookimpl\n    def transform(self, text: str) -> str:\n        return text.upper()\n\nclass SuffixPlugin:\n    @hookimpl\n    def transform(self, text: str) -> str:\n        return f\"{text}-done\"\n\npm = pluggy.PluginManager(\"myapp\")\npm.add_hookspecs(Spec)\npm.register(UpperPlugin(), name=\"upper\")\npm.register(SuffixPlugin(), name=\"suffix\")\n\nresults = pm.hook.transform(text=\"hello\")\nprint(results)  # ['hello-done', 'HELLO']\n```\n\nHook calls use keyword arguments. By default, non-wrapper implementations run in LIFO registration order, so the most recently registered plugin runs first unless `tryfirst=True` or `trylast=True` changes that order.\n\n## Recommended Host Startup Pattern\n\nUse this sequence in application startup:\n\n1. Create markers and a `PluginManager`.\n2. Register hook specifications with `add_hookspecs(...)`.\n3. Register built-in plugins directly.\n4. Optionally load third-party plugins from entry points.\n5. Call `check_pending()` so mismatches fail early.\n\n```python\nimport pluggy\n\nhookspec = pluggy.HookspecMarker(\"myapp\")\nhookimpl = pluggy.HookimplMarker(\"myapp\")\n\nclass Spec:\n    @hookspec(firstresult=True)\n    def load_config(self, path: str):\n        \"\"\"Return the first plugin that can load this file.\"\"\"\n\nclass YamlPlugin:\n    @hookimpl(tryfirst=True)\n    def load_config(self, path: str):\n        if path.endswith((\".yaml\", \".yml\")):\n            return {\"kind\": \"yaml\", \"path\": path}\n        return None\n\npm = pluggy.PluginManager(\"myapp\")\npm.add_hookspecs(Spec)\npm.register(YamlPlugin(), name=\"yaml\")\npm.load_setuptools_entrypoints(\"myapp\")\npm.check_pending()\n\nconfig = pm.hook.load_config(path=\"settings.yaml\")\nprint(config)  # {'kind': 'yaml', 'path': 'settings.yaml'}\n```\n\nUse `firstresult=True` when the host wants one answer instead of a list. Pluggy stops at the first non-`None` implementation result.\n\n## Registration And Discovery\n\n### Register plugin objects directly\n\n```python\nplugin = MyPlugin()\npm.register(plugin, name=\"my-plugin\")\n```\n\n### Unregister or block a plugin\n\n```python\npm.unregister(plugin)\npm.set_blocked(\"legacy-plugin\")\npm.unblock(\"legacy-plugin\")\n```\n\nBlocking is useful when the host wants to reject a plugin name even if a package is installed.\n\n### Load installed plugins from entry points\n\n```python\nloaded = pm.load_setuptools_entrypoints(\"myapp\")\nprint(f\"loaded {loaded} entry-point plugins\")\n```\n\nUse a stable entry-point group name for your application. `pluggy` only loads those plugins when you call `load_setuptools_entrypoints(...)`; discovery is not automatic.\n\n## Designing Hook Specifications\n\nDefine hook specs on a class or module and register them once:\n\n```python\nclass Spec:\n    @hookspec\n    def render(self, document: str, style: str = \"plain\") -> str:\n        \"\"\"Render a document.\"\"\"\n```\n\nImportant spec options:\n\n- `firstresult=True`: return the first non-`None` result.\n- `historic=True`: remember calls and replay them to plugins registered later.\n- `warn_on_impl=...`: warn whenever a plugin implements that hook.\n- `warn_on_impl_args={...}`: warn only when a plugin implements specific arguments.\n\nPluggy validates implementations against the spec, but it is intentionally forward-compatible about added arguments. A hook implementation can accept fewer named arguments than the spec, which lets the host evolve hook signatures without breaking older plugins immediately.\n\n```python\nclass Spec:\n    @hookspec\n    def render(self, document: str, style: str):\n        \"\"\"Render a document.\"\"\"\n\nclass OldPlugin:\n    @hookimpl\n    def render(self, document: str):\n        return document.upper()\n```\n\nThat implementation is still valid because it accepts a subset of the spec arguments.\n\nIf you use `historic=True`, remember that the host must replay past calls with `call_historic(...)`, and historic hooks cannot be combined with `firstresult=True`.\n\n## Hook Implementations And Wrappers\n\n```python\nclass Plugin:\n    @hookimpl(trylast=True)\n    def render(self, document: str, style: str = \"plain\") -> str:\n        return document.upper()\n```\n\nUseful implementation options:\n\n- `tryfirst=True`: run earlier than normal implementations.\n- `trylast=True`: run later than normal implementations.\n- `optionalhook=True`: allow the implementation even if the host has not registered that spec yet.\n- `wrapper=True`: new-style wrapper API.\n- `hookwrapper=True`: old-style wrapper API kept for compatibility.\n\nPrefer `wrapper=True` for new code:\n\n```python\nclass TimingPlugin:\n    @hookimpl(wrapper=True)\n    def render(self, document: str, style: str = \"plain\"):\n        print(\"before render\")\n        result = yield\n        print(\"after render\")\n        return result\n```\n\nLegacy `hookwrapper=True` plugins still exist in the ecosystem, but wrappers must yield exactly once, and older teardown patterns are easier to get wrong.\n\n## Validation And Debugging\n\n### Fail fast on mismatches\n\n```python\npm = pluggy.PluginManager(\"myapp\")\npm.add_hookspecs(Spec)\npm.register(MyPlugin())\npm.check_pending()\n```\n\n`check_pending()` is the simplest way to surface unknown or invalid hook implementations during startup.\n\n### Inspect hook calls\n\n```python\nundo = pm.add_hookcall_monitoring(\n    before=lambda name, hook_impls, kwargs: print(\"before\", name, kwargs),\n    after=lambda outcome, name, hook_impls, kwargs: print(\"after\", name, outcome),\n)\n\ntry:\n    pm.hook.render(document=\"hello\", style=\"plain\")\nfinally:\n    undo()\n```\n\nYou can also use `pm.enable_tracing()` for built-in tracing through the manager's trace root.\n\n## Configuration And Security Model\n\n`pluggy` does not define authentication, network transport, sandboxing, or a plugin config format.\n\nYour application must decide:\n\n- how plugins are discovered\n- which plugin packages are trusted\n- whether users can enable or disable plugins dynamically\n- what objects and data are passed into hooks\n- how plugin configuration is loaded and validated\n\nFor production systems, treat third-party plugins as application code with full process access unless you provide your own isolation.\n\n## Common Pitfalls\n\n- Project-name mismatch: `PluginManager(\"myapp\")`, `HookspecMarker(\"myapp\")`, and `HookimplMarker(\"myapp\")` must use the same name.\n- Forgetting `add_hookspecs(...)`: register specs before plugins, then call `check_pending()` during startup.\n- Assuming positional calls work: hook invocations should use keyword arguments like `pm.hook.render(document=\"x\")`.\n- Assuming registration order is FIFO: default call order is LIFO for normal implementations.\n- Forgetting entry-point loading: installed plugin packages are ignored until you call `load_setuptools_entrypoints(...)`.\n- Overusing wrappers: wrappers are powerful, but they complicate control flow and error handling.\n- Treating `stable` docs as version-frozen: confirm release-sensitive details against the `1.6.0` changelog and PyPI metadata.\n\n## Version-Sensitive Notes For 1.6.0\n\n- `1.6.0` drops Python `3.8`; the supported range is Python `>=3.9`.\n- `1.6.0` adds `PluginManager.unblock(name)` so hosts can remove a previously blocked plugin name.\n- `1.6.0` adds `Result.force_exception()` for wrapper and result-manipulation flows.\n- `1.5.0` added `warn_on_impl_args`, so do not rely on that option if you still support `1.4.x` or older pluggy releases.\n\n## Official Sources\n\n- Docs root: https://pluggy.readthedocs.io/en/stable/\n- API reference: https://pluggy.readthedocs.io/en/stable/api_reference.html\n- Changelog: https://pluggy.readthedocs.io/en/stable/changelog.html\n- PyPI package: https://pypi.org/project/pluggy/\n- PyPI `1.6.0` metadata: https://pypi.org/pypi/pluggy/1.6.0/json\n- Maintainer repository: https://github.com/pytest-dev/pluggy\n"
  },
  {
    "path": "content/poetry/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Poetry package guide for Python dependency management, virtual environments, packaging, and publishing\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"poetry,python,packaging,dependencies,virtualenv,pyproject,publishing\"\n---\n\n# Poetry Python Package Guide\n\n## Golden Rule\n\nUse Poetry as the project tool that owns `pyproject.toml`, the lock file, and the virtual environment workflow. For Poetry `2.3.2`, prefer the modern `[project]` section for your main package metadata and runtime dependencies, use `poetry sync` when you need the environment to exactly match `poetry.lock`, and keep Poetry-specific settings under `[tool.poetry]`.\n\nDo not add `poetry` as an application dependency with `poetry add poetry`. Install the CLI separately, then use it to manage your project.\n\n## Install Poetry\n\nThe most practical installation for local development is `pipx` so Poetry stays isolated from the project it manages:\n\n```bash\npipx install \"poetry==2.3.2\"\npoetry --version\n```\n\nOfficial installer alternative:\n\n```bash\ncurl -sSL https://install.python-poetry.org | POETRY_VERSION=2.3.2 python3 -\npoetry --version\n```\n\nIf you upgrade later:\n\n```bash\npipx upgrade poetry\n```\n\n## Initialize And Configure A Project\n\n### Create a new package project\n\n`poetry new` scaffolds a package-ready project:\n\n```bash\npoetry new my-package\ncd my-package\npoetry install\n```\n\nUse `--flat` if you do not want the default `src/` layout:\n\n```bash\npoetry new --flat my-package\n```\n\n### Adopt Poetry in an existing project\n\n```bash\ncd existing-project\npoetry init\npoetry install\n```\n\n### Application-style projects\n\nIf the project is an app and you do not plan to build or publish it as a package, disable package mode:\n\n```toml\n[project]\nname = \"demo-app\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = [\n  \"httpx>=0.28,<1.0\",\n]\n\n[tool.poetry]\npackage-mode = false\n\n[tool.poetry.group.dev.dependencies]\npytest = \"^8.0\"\nruff = \"^0.11.0\"\n```\n\nNotes:\n\n- In Poetry 2.x, the docs recommend using `[project]` for the main project metadata and runtime dependencies.\n- Dependency groups, private sources, and Poetry-only behavior still live under `[tool.poetry...]`.\n- Only main dependencies belong in `[project.dependencies]`; grouped dependencies stay under `[tool.poetry.group.<name>.dependencies]`.\n\n## Core Workflow\n\n### Choose the Python interpreter\n\nPoint Poetry at the interpreter you want before installing dependencies:\n\n```bash\npoetry env use 3.12\n```\n\nOr use an explicit path:\n\n```bash\npoetry env use /full/path/to/python\n```\n\nCheck the current environment:\n\n```bash\npoetry env info\npoetry env list\n```\n\n### Keep the virtual environment inside the project\n\nFor agent-driven work, a project-local `.venv` is usually the least ambiguous setup:\n\n```bash\npoetry config virtualenvs.in-project true --local\npoetry install\n```\n\nThis writes project-local Poetry settings to `poetry.toml`, not to `pyproject.toml`.\n\n### Install vs sync\n\nUse `install` when bootstrapping, and `sync` when you need the environment to exactly match the lock file:\n\n```bash\npoetry install\npoetry sync\n```\n\nCommon variants:\n\n```bash\npoetry install --with dev\npoetry sync --with dev,docs\npoetry install --only main\n```\n\nRule of thumb:\n\n- `poetry install` installs what the project needs but does not aggressively clean extras already present in the environment.\n- `poetry sync` reconciles the environment to the lock file and removes packages that should no longer be there.\n\n### Add, update, and remove dependencies\n\n```bash\npoetry add requests\npoetry add pytest --group dev\npoetry add mkdocs --group docs\npoetry remove requests\n```\n\nAfter dependency edits, Poetry updates `poetry.lock` automatically.\n\nUse these when you need to inspect or change resolution state directly:\n\n```bash\npoetry show --tree\npoetry lock\npoetry update\npoetry update requests\n```\n\n### Run commands inside the managed environment\n\n`poetry run` is the most automation-friendly choice:\n\n```bash\npoetry run python -V\npoetry run pytest\npoetry run ruff check .\n```\n\nIf you need shell activation text for interactive work:\n\n```bash\npoetry env activate\n```\n\n### Validate and build\n\n```bash\npoetry check\npoetry build\n```\n\n`poetry check` catches invalid `pyproject.toml` configuration before you waste time debugging installs or publishes.\n\n## Private Indexes, Publishing, And Auth\n\n### Add a package source for installs\n\n```bash\npoetry source add --priority=explicit internal-pypi https://packages.example.com/simple/\n```\n\nThen add a dependency from that source:\n\n```bash\npoetry add --source internal-pypi acme-lib\n```\n\nFor private-source workflows, be explicit about which packages come from which source. This reduces dependency-confusion risk and matches Poetry's source model.\n\n### Store project-local repository config\n\n```bash\npoetry config repositories.internal-pub https://packages.example.com/legacy/ --local\n```\n\n### Configure credentials\n\nBasic auth:\n\n```bash\npoetry config http-basic.internal-pub username password\n```\n\nPyPI token:\n\n```bash\npoetry config pypi-token.pypi pypi-AgEIcHlwaS5vcmc...\n```\n\nEnvironment-variable alternatives are better for CI:\n\n```bash\nexport POETRY_HTTP_BASIC_INTERNAL_PUB_USERNAME=\"username\"\nexport POETRY_HTTP_BASIC_INTERNAL_PUB_PASSWORD=\"password\"\nexport POETRY_PYPI_TOKEN_PYPI=\"pypi-AgEIcHlwaS5vcmc...\"\n```\n\nIf keyring integration causes trouble in CI or containers:\n\n```bash\npoetry config keyring.enabled false --local\n```\n\n### Publish a built package\n\n```bash\npoetry publish --build\n```\n\nFor a named repository:\n\n```bash\npoetry publish --build --repository internal-pub\n```\n\n## Common Pitfalls\n\n- Do not install Poetry into the same environment it is managing unless you have a deliberate reason. `pipx` is the clean default.\n- Do not assume `poetry install` cleans stale packages. Use `poetry sync` for reproducible CI or agent workflows.\n- If you switch Python versions outside Poetry, rerun `poetry env use ...` so the environment and lock constraints stay aligned.\n- If your project is an application rather than a distributable package, set `package-mode = false` or Poetry will expect package metadata and build-oriented behavior.\n- In Poetry 2.x, main dependencies belong in `[project.dependencies]`. Dependency groups still belong in `[tool.poetry.group.*.dependencies]`; mixing those up is a common source of broken `pyproject.toml` files.\n- Private package sources are Poetry-specific configuration. Keep source definitions and grouped dependencies under `[tool.poetry]`, not in `[project]`.\n- `poetry env activate` prints shell-specific activation code. For scripts, CI, and agents, `poetry run ...` is usually more reliable.\n- `poetry check` should be part of the edit loop whenever an agent writes `pyproject.toml`.\n\n## Version-Sensitive Notes For 2.3.2\n\n- PyPI lists `2.3.2` as the current Poetry release. The version used here matches live upstream as of March 12, 2026.\n- Poetry `2.3.x` requires Python `>=3.10,<4.0`. Some older docs snippets still mention Python 3.9, but the `2.3.0` release history and PyPI metadata are the authoritative signals for this series.\n- Poetry 2.x prefers `[project]` metadata and runtime dependencies. Older blog posts often use only `[tool.poetry.dependencies]`; that is no longer the best default for new work.\n- The CLI docs mark `export` as provided by the Export Poetry Plugin, and the `2.3.0` release history notes that Poetry no longer depends on `poetry-plugin-export` by default. If `poetry export` is missing, install the plugin explicitly:\n\n```bash\npoetry self add poetry-plugin-export\n```\n\n- The `2.3.0` release history also notes the installer default `installer.re-resolve = false` behavior. If you compare behavior with much older Poetry examples, dependency resolution details may not match exactly.\n\n## Official Source URLs\n\n- Docs root: `https://python-poetry.org/docs/`\n- Dependency specification: `https://python-poetry.org/docs/dependency-specification/`\n- Configuration: `https://python-poetry.org/docs/configuration/`\n- Repositories: `https://python-poetry.org/docs/repositories/`\n- Managing environments: `https://python-poetry.org/docs/managing-environments/`\n- `pyproject.toml` reference: `https://python-poetry.org/docs/pyproject/`\n- CLI reference: `https://python-poetry.org/docs/cli/`\n- Release history: `https://python-poetry.org/history/`\n- PyPI project page: `https://pypi.org/project/poetry/`\n"
  },
  {
    "path": "content/polars/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"polars package guide for Python DataFrame, LazyFrame, expressions, IO, and cloud-backed analytics workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.38.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"polars,dataframe,lazyframe,columnar,parquet,sql\"\n---\n\n# polars Python Package Guide\n\n## What It Is\n\n`polars` is a columnar DataFrame library for Python built around expressions, lazy query planning, and fast parquet/csv/ndjson/database-style data workflows.\n\nUse it when you need:\n\n- DataFrame operations that stay vectorized instead of row-by-row Python loops\n- lazy query planning with predicate and projection pushdown\n- efficient parquet and IPC/Arrow interop\n- SQL-style analytics on local files, in-memory frames, or cloud-backed datasets\n\nFor new code, prefer the expression API and the lazy API unless you specifically need eager materialization.\n\n## Install\n\nBase install:\n\n```bash\npython -m pip install polars==1.38.1\n```\n\nCommon alternatives:\n\n```bash\nuv add polars==1.38.1\npoetry add polars==1.38.1\nconda install -c conda-forge polars=1.38.1\n```\n\nUseful optional extras from the official package metadata:\n\n```bash\npython -m pip install \"polars[numpy,fsspec]==1.38.1\"\npython -m pip install \"polars[pyarrow]==1.38.1\"\npython -m pip install \"polars[all]==1.38.1\"\n```\n\nNotes:\n\n- `fsspec` is commonly needed for filesystem integrations and some remote-storage workflows.\n- `pyarrow` is optional for many `polars` tasks, but it is useful when a codebase already depends on Arrow or pandas/Arrow interchange.\n- The PyPI page also documents runtime compatibility wheels such as `rtcompat` and `rt64` for specific environments; use them only when the upstream install guidance calls for them.\n\n## Import And First Frame\n\n```python\nimport polars as pl\n\ndf = pl.DataFrame(\n    {\n        \"city\": [\"sf\", \"nyc\", \"la\"],\n        \"count\": [10, 7, 5],\n        \"active\": [True, True, False],\n    }\n)\n\nprint(df)\nprint(df.schema)\n```\n\n`polars` uses a few core types repeatedly:\n\n- `pl.DataFrame` for eager tabular data\n- `pl.LazyFrame` for deferred query execution\n- `pl.Series` for a single column\n- `pl.Expr` for reusable column expressions inside `select`, `with_columns`, `filter`, `group_by`, and joins\n\n## Core Usage\n\n### Expressions First\n\nThe official user guide treats expressions as the main building block. Write transformations with `pl.col(...)`, literals, and expression methods instead of Python loops.\n\n```python\nimport polars as pl\n\nresult = (\n    df\n    .filter(pl.col(\"active\"))\n    .with_columns(\n        count_doubled=pl.col(\"count\") * 2,\n        city_upper=pl.col(\"city\").str.to_uppercase(),\n    )\n    .select(\"city_upper\", \"count_doubled\")\n)\n```\n\n`DataFrame.with_columns(...)` returns a new frame but does not copy existing data buffers just to add or replace derived columns.\n\n### Prefer Lazy Execution For Pipelines\n\nUse `scan_*` for file-backed work and keep the query lazy until the end.\n\n```python\nimport polars as pl\n\nq = (\n    pl.scan_parquet(\"data/events/*.parquet\")\n    .filter(pl.col(\"event_date\") >= pl.date(2026, 1, 1))\n    .group_by(\"user_id\")\n    .agg(\n        events=pl.len(),\n        total_amount=pl.col(\"amount\").sum(),\n    )\n    .sort(\"total_amount\", descending=True)\n)\n\nresult = q.collect()\n```\n\nWhy this matters:\n\n- `scan_parquet`, `scan_csv`, and similar lazy readers allow predicate/projection pushdown\n- the optimizer can remove unused columns and push filters closer to the source\n- `read_csv(...).lazy()` is usually the wrong starting point because the file was already read eagerly\n\nFor large pipelines, the upstream docs also expose streaming execution on supported plans via `collect(engine=\"streaming\")` and sink APIs.\n\n### Read And Write Files\n\nEager read when the data is small and immediate materialization is fine:\n\n```python\nimport polars as pl\n\ndf = pl.read_csv(\n    \"input.csv\",\n    try_parse_dates=True,\n    infer_schema_length=10_000,\n)\n```\n\nLazy read when the dataset is large or you will filter/select before collecting:\n\n```python\nimport polars as pl\n\nq = pl.scan_csv(\n    \"input.csv\",\n    try_parse_dates=True,\n)\n\nresult = q.select(\"id\", \"ts\", \"value\").filter(pl.col(\"value\") > 0).collect()\n```\n\nWrite parquet for downstream analytics:\n\n```python\nimport polars as pl\n\ndf.write_parquet(\n    \"output.parquet\",\n    compression=\"zstd\",\n    statistics=True,\n)\n```\n\n### Grouping, Joins, And Windowed Logic\n\n```python\nimport polars as pl\n\norders = pl.DataFrame(\n    {\n        \"user_id\": [1, 1, 2, 3],\n        \"amount\": [40, 60, 10, 25],\n    }\n)\n\nusers = pl.DataFrame(\n    {\n        \"user_id\": [1, 2, 3],\n        \"plan\": [\"pro\", \"free\", \"pro\"],\n    }\n)\n\nsummary = (\n    orders\n    .group_by(\"user_id\")\n    .agg(total_amount=pl.col(\"amount\").sum())\n    .join(users, on=\"user_id\", how=\"left\")\n    .with_columns(\n        amount_rank=pl.col(\"total_amount\").rank(descending=True)\n    )\n)\n```\n\n`polars` also supports SQL via `SQLContext`, but the expression API is the primary interface and is usually the best default for generated code.\n\n### Pandas And Arrow Interop\n\n```python\nimport pandas as pd\nimport polars as pl\n\npandas_df = pd.DataFrame({\"x\": [1, 2, 3]})\npl_df = pl.from_pandas(pandas_df)\n\nround_trip = pl_df.to_pandas()\n```\n\nUse Arrow/pandas interop when a surrounding library requires it, but keep your main transformation pipeline in native `polars` when possible.\n\n## Config And Auth\n\n`polars` has no service-level authentication model for ordinary local DataFrame work. The main configuration surfaces are display/runtime settings and storage credentials for remote IO.\n\n### Display And Session Config\n\nUse `pl.Config` to adjust table formatting or set temporary display behavior:\n\n```python\nimport polars as pl\n\nwith pl.Config(tbl_rows=20, fmt_str_lengths=80):\n    print(df)\n```\n\nFor debugging environment issues, the API reference also exposes `pl.show_versions()`.\n\n### Cloud And Remote Storage Credentials\n\nRemote readers/writers such as `scan_parquet`, `read_parquet`, and related APIs support `storage_options=` and, for credentialed workflows, `credential_provider=`.\n\nTypical shape:\n\n```python\nimport polars as pl\n\nq = pl.scan_parquet(\n    \"s3://analytics-bucket/events/date=2026-03-12/*.parquet\",\n    storage_options={\n        \"aws_region\": \"us-west-2\",\n    },\n)\n```\n\nIf the codebase needs a shared default credential source, `pl.Config.set_default_credential_provider(...)` is the official API surface to look at. In practice, many projects rely on provider-native environment variables and let the underlying cloud auth chain resolve credentials.\n\n## Common Pitfalls\n\n- Eager-vs-lazy confusion: do not start with `read_csv(...).lazy()` when `scan_csv(...)` can avoid unnecessary upfront IO.\n- Python loops: avoid `for`-loop row processing and `DataFrame.apply`-style patterns when an expression exists. Generated code should stay inside the expression engine whenever possible.\n- Schema inference surprises: for CSV and loosely typed input, set `schema=`, `schema_overrides=`, or a larger `infer_schema_length` when type stability matters.\n- Row orientation: when constructing a frame from row-like records in ambiguous cases, pass `orient=\"row\"` explicitly.\n- Strict casting and construction: version 1 tightened several behaviors. Expect invalid values to error unless you intentionally opt into non-strict behavior.\n- Lazy schema access: on modern Polars, `LazyFrame.schema`, `dtypes`, `columns`, and `width` can trigger work and generate performance warnings. Prefer `collect_schema()` when you need schema information for a lazy plan.\n- String/object assumptions from pandas: Polars is stricter about dtypes and null handling than pandas. Cast deliberately instead of assuming implicit coercion.\n- SQL is optional: SQL support exists, but most docs, optimizations, and community examples are built around expressions. If SQL and expression examples disagree, prefer the expression-native API.\n\n## Version-Sensitive Notes\n\n- The version used here `1.38.1` matches the current PyPI release as of `2026-03-12`.\n- The Python API reference URL in this package brief is the stable docs root, not a version-pinned `1.38.1` snapshot. Re-check the changelog or release notes before copying behavior into code that must exactly match older releases.\n- The official Version 1 upgrade guide is still relevant for current code because it changed strictness defaults and several APIs that older blog posts still use.\n- From the Version 1 guide, the constructor is stricter, ambiguous row-oriented construction should use `orient=\"row\"`, many `replace` patterns moved to `replace_strict`, and lazy schema inspection should use `collect_schema()`.\n- Streaming execution is opt-in and plan-dependent. Do not assume every lazy query automatically runs in streaming mode.\n\n## Practical Guidance For Agents\n\n1. Start with `import polars as pl` and keep transformations in `select`, `with_columns`, `filter`, `group_by`, and joins.\n2. Use `scan_parquet` / `scan_csv` for file pipelines, then `.collect()` only at the boundary where materialized results are actually needed.\n3. Prefer explicit casts and schema overrides when reading CSV, JSON, or heterogeneous Python objects.\n4. Keep cloud IO auth simple: start with provider-native environment credentials, then add `storage_options` or `credential_provider` only when the upstream docs require it.\n5. If a project mixes pandas and Polars, convert at the edges rather than bouncing repeatedly between the two in the middle of a pipeline.\n\n## Official Sources\n\n- Docs root: `https://docs.pola.rs/`\n- Installation: `https://docs.pola.rs/user-guide/installation/`\n- User guide: `https://docs.pola.rs/user-guide/`\n- Expressions and contexts: `https://docs.pola.rs/user-guide/concepts/expressions-and-contexts/`\n- SQL interface: `https://docs.pola.rs/user-guide/sql/intro/`\n- Python API reference: `https://docs.pola.rs/api/python/stable/reference/`\n- `LazyFrame` reference: `https://docs.pola.rs/api/python/stable/reference/lazyframe/`\n- `scan_parquet`: `https://docs.pola.rs/api/python/stable/reference/api/polars.scan_parquet.html`\n- `Config.set_default_credential_provider`: `https://docs.pola.rs/api/python/stable/reference/api/polars.Config.set_default_credential_provider.html`\n- `show_versions`: `https://docs.pola.rs/api/python/stable/reference/api/polars.show_versions.html`\n- Version 1 upgrade guide: `https://docs.pola.rs/releases/upgrade/1/`\n- PyPI package page: `https://pypi.org/project/polars/`\n"
  },
  {
    "path": "content/polyfactory/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"polyfactory package guide for Python mock-data factories across dataclasses, Pydantic, TypedDict, attrs, msgspec, and SQLAlchemy\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"polyfactory,python,testing,factories,mock-data,pydantic,sqlalchemy\"\n---\n\n# polyfactory Python Package Guide\n\n## Golden Rule\n\nUse `polyfactory` when you need typed test data from model definitions, not hand-written fixtures. Define one factory per model, call `.build()` for one instance or `.batch()` for many, and make version-sensitive defaults explicit when upgrading from the old `pydantic-factories` / Polyfactory v2 behavior.\n\n## Install\n\nBase install:\n\n```bash\npython -m pip install \"polyfactory==3.3.0\"\n```\n\nOptional integration extras from PyPI:\n\n```bash\npython -m pip install \"polyfactory[pydantic]==3.3.0\"\npython -m pip install \"polyfactory[attrs]==3.3.0\"\npython -m pip install \"polyfactory[msgspec]==3.3.0\"\npython -m pip install \"polyfactory[sqlalchemy]==3.3.0\"\npython -m pip install \"polyfactory[beanie]==3.3.0\"\npython -m pip install \"polyfactory[odmantic]==3.3.0\"\npython -m pip install \"polyfactory[full]==3.3.0\"\n```\n\nCommon package managers:\n\n```bash\nuv add \"polyfactory==3.3.0\"\npoetry add \"polyfactory==3.3.0\"\n```\n\n## Choose The Right Factory Base\n\n- `DataclassFactory[T]`: stdlib dataclasses and compatible dataclass implementations\n- `TypedDictFactory[T]`: `TypedDict`\n- `ModelFactory[T]`: Pydantic models\n- `AttrsFactory[T]`: attrs models\n- `SQLAlchemyFactory[T]`: SQLAlchemy declarative models\n\nPolyfactory also ships library-specific factories for `msgspec`, Beanie, and Odmantic.\n\n## Quick Start\n\nFor simple models, subclass the right factory and call `.build()`:\n\n```python\nfrom dataclasses import dataclass\n\nfrom polyfactory.factories import DataclassFactory\n\n@dataclass\nclass User:\n    id: int\n    name: str\n    is_active: bool\n\nclass UserFactory(DataclassFactory[User]):\n    ...\n\nuser = UserFactory.build()\nusers = UserFactory.batch(size=3)\ncustom = UserFactory.build(name=\"Ada Lovelace\")\n```\n\nAs of Polyfactory `2.13.0+`, you can omit `__model__` on declarative factories if the generic parameter already identifies the model.\n\nPolyfactory will infer nested models and many standard Python types from annotations. If you need a factory class dynamically, use `create_factory()`:\n\n```python\npet_factory = DataclassFactory.create_factory(model=User)\npet = pet_factory.build()\n```\n\n## Core Customization\n\n### Deterministic test data\n\nUse the factory-scoped RNG instead of the stdlib global random state:\n\n```python\nfrom polyfactory.factories import DataclassFactory\n\nclass UserFactory(DataclassFactory[User]):\n    __random_seed__ = 7\n```\n\n`__random_seed__` makes factory output deterministic and also affects the attached Faker instance. If you need a fully custom RNG or locale-aware faker, set `__random__` or `__faker__` explicitly.\n\n### Control specific fields\n\nThe main helpers are:\n\n- `Use(...)`: call a function at build time\n- `Ignore()`: omit a field from generated output\n- `Require()`: force callers to pass a value to `.build(...)`\n- `PostGenerated(...)`: derive one field from already-generated values\n\nExample:\n\n```python\nfrom dataclasses import dataclass\n\nfrom polyfactory import Require, Use\nfrom polyfactory.factories import DataclassFactory\n\n@dataclass\nclass Payment:\n    amount: int\n    currency: str\n    reference: str\n\nclass PaymentFactory(DataclassFactory[Payment]):\n    amount = Require()\n    currency = Use(lambda: \"USD\")\n\npayment = PaymentFactory.build(amount=500)\n```\n\nFactories can also be used as fields directly, and `Use(OtherFactory.batch, size=...)` is the standard way to generate nested lists.\n\n### Defaults, optional fields, and collection length\n\nUseful config flags:\n\n- `__use_defaults__ = True`: prefer model default values instead of random ones\n- `__allow_none_optionals__ = False`: force `Optional[...]` fields to get actual generated values\n- `__randomize_collection_length__ = True`: vary collection sizes\n- `__min_collection_length__` / `__max_collection_length__`: bound randomized collection sizes\n\nExample:\n\n```python\nclass UserFactory(DataclassFactory[User]):\n    __allow_none_optionals__ = False\n    __randomize_collection_length__ = True\n    __min_collection_length__ = 1\n    __max_collection_length__ = 3\n```\n\n## Pydantic Usage\n\nUse `ModelFactory` for Pydantic models:\n\n```python\nfrom pydantic import BaseModel, Field\n\nfrom polyfactory.factories.pydantic_factory import ModelFactory\n\nclass Customer(BaseModel):\n    email: str\n    country: str = Field(examples=[\"US\", \"DE\", \"JP\"])\n\nclass CustomerFactory(ModelFactory[Customer]):\n    __use_examples__ = True\n\ncustomer = CustomerFactory.build()\n```\n\nVersion-sensitive Pydantic notes:\n\n- `__use_examples__ = True` uses Pydantic v2 field `examples` when present.\n- `__by_name__ = True` is the current switch for validation-alias handling with `validation_alias` / `AliasPath`.\n- The changelog shows `by_name` support landed in `3.2.0`, so this is safe for `3.3.0`.\n\n## SQLAlchemy Usage\n\nUse `SQLAlchemyFactory` when you need ORM instances and optionally persisted rows:\n\n```python\nfrom sqlalchemy.orm import Session\n\nfrom polyfactory.factories.sqlalchemy_factory import (\n    SQLAlchemyFactory,\n    SQLAlchemyPersistenceMethod,\n)\n\nclass AuthorFactory(SQLAlchemyFactory[Author]):\n    __set_relationships__ = True\n    __session__ = Session(engine)\n    __persistence_method__ = SQLAlchemyPersistenceMethod.FLUSH\n\nauthor = AuthorFactory.create_sync()\n```\n\nImportant behavior:\n\n- `build()` creates ORM objects without persisting them.\n- `create_sync()` uses `__session__`; `create_async()` uses `__async_session__`.\n- Current docs say the default persistence behavior commits unless you switch to `SQLAlchemyPersistenceMethod.FLUSH`.\n- Current docs also say `__set_relationships__` and `__set_association_proxy__` default to `True` in v3, which is a behavioral change from older defaults.\n\nThe official changelog for `3.3.0` adds SQLAlchemy computed-field support and the `__persistence_method__` configuration.\n\n## Custom Types And Shared Base Factories\n\nIf your model includes unsupported custom types, extend the provider map or register a provider globally:\n\n```python\nfrom polyfactory.factories.base import BaseFactory\n\nBaseFactory.add_provider(CustomSecret, lambda: CustomSecret(\"token\"))\n```\n\nFor broader reuse, create a custom base factory with `__is_base_factory__ = True` and override `get_provider_map()`. If that base class adds extra config knobs, extend `__config_keys__` so concrete factories inherit them correctly.\n\n## Pytest Integration\n\nPolyfactory can register factories as pytest fixtures:\n\n```python\nfrom polyfactory.pytest_plugin import register_fixture\n\n@register_fixture\nclass UserFactory(DataclassFactory[User]):\n    ...\n```\n\nThis exposes a fixture like `user_factory` while leaving the class usable directly.\n\n## Coverage Generation\n\nUse `coverage()` when you want the smallest set of examples that exercises unions and literal choices instead of purely random batches:\n\n```python\ncases = list(ProfileFactory.coverage())\n```\n\nThis is especially useful for parameterized tests over discriminated or union-like models.\n\nKnown limitations in the official docs:\n\n- recursive models can raise `RecursionError`\n- `__min_collection_length__` and `__max_collection_length__` are ignored by `coverage()`\n\n## Config And Environment\n\nPolyfactory is a local library with no auth flow or network configuration. The main setup decisions are:\n\n- which optional extra to install\n- whether tests need deterministic randomness\n- whether ORM factories should persist with `flush()` or `commit()`\n- whether shared base factories should centralize custom type providers\n\n## Common Pitfalls\n\n- In v3, `__check_model__` defaults to `True` for `Use`, `PostGenerated`, `Ignore`, and `Require` fields. Unknown helper fields now raise instead of silently passing.\n- `__use_defaults__` does nothing for `TypedDictFactory`, because `TypedDict` has no field defaults.\n- Use `cls.__random__` or `__random_seed__`, not global `random`, if you want deterministic tests.\n- For async data needed by a field, resolve it before building and pass the value into `.build(...)`; the docs recommend not doing async fetches inside field declarations.\n- attrs validators are not currently supported by `AttrsFactory`.\n- If you are migrating from `pydantic-factories`, remember the package was renamed to `polyfactory` in v2.\n\n## Version-Sensitive Notes For 3.3.0\n\n- PyPI currently lists `3.3.0` as the latest release, dated February 22, 2026.\n- `3.3.0` adds SQLAlchemy computed-field support and `__persistence_method__`.\n- `3.2.0` added Pydantic `__by_name__` support for validation aliases.\n- v3 changes that matter during upgrades:\n  - `__check_model__` now defaults to `True`\n  - `__set_relationships__` now defaults to `True`\n  - SQLAlchemy association-proxy generation defaults to enabled in current v3 docs\n\n## Official Sources\n\n- Docs: `https://polyfactory.litestar.dev/latest/`\n- Usage guide: `https://polyfactory.litestar.dev/latest/usage/declaring_factories.html`\n- Configuration: `https://polyfactory.litestar.dev/latest/usage/configuration.html`\n- Fields: `https://polyfactory.litestar.dev/latest/usage/fields.html`\n- Custom types: `https://polyfactory.litestar.dev/latest/usage/handling_custom_types.html`\n- SQLAlchemy factory: `https://polyfactory.litestar.dev/latest/usage/library_factories/sqlalchemy_factory.html`\n- Coverage: `https://polyfactory.litestar.dev/latest/usage/model_coverage.html`\n- Fixtures: `https://polyfactory.litestar.dev/latest/usage/fixtures.html`\n- Changelog: `https://polyfactory.litestar.dev/latest/changelog.html`\n- PyPI: `https://pypi.org/project/polyfactory/`\n"
  },
  {
    "path": "content/pony/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pony ORM package guide for Python projects using declarative entities, db_session transactions, and generator-based queries\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.19\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pony,ponyorm,orm,sql,sqlite,postgresql,mysql\"\n---\n\n# Pony ORM Python Package Guide\n\n## Golden Rule\n\nUse `pony` for ORM work only inside a `db_session`, bind the `Database()` explicitly before touching entities, and materialize any data you need before leaving the session. Pony commits automatically on successful exit, rolls back on exceptions, clears its identity map, and returns the connection to the pool when the session ends.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pony==0.7.19\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pony==0.7.19\"\npoetry add \"pony==0.7.19\"\n```\n\nDatabase drivers are separate from Pony:\n\n- SQLite: no extra driver needed\n- PostgreSQL: install a PostgreSQL DB-API driver such as `psycopg2-binary`\n- MySQL: install a supported MySQL DB-API driver such as `PyMySQL`\n- Oracle or CockroachDB: verify the driver and version notes from the upstream docs before wiring production code\n\n## Initialize A Database\n\nCreate one `Database()` object, define entities off `db.Entity`, then call `bind()` and `generate_mapping()`:\n\n```python\nfrom datetime import date\n\nfrom pony.orm import Database, PrimaryKey, Required, Set, db_session, select\n\ndb = Database()\n\nclass Customer(db.Entity):\n    id = PrimaryKey(int, auto=True)\n    email = Required(str, unique=True)\n    orders = Set(\"Order\")\n\nclass Order(db.Entity):\n    id = PrimaryKey(int, auto=True)\n    total_cents = Required(int)\n    created_on = Required(date)\n    customer = Required(Customer)\n\ndb.bind(provider=\"sqlite\", filename=\"app.sqlite\", create_db=True)\ndb.generate_mapping(create_tables=True)\n```\n\nImportant setup rules:\n\n- Define entities before `generate_mapping()`\n- Use `create_tables=True` for new local schemas; do not assume that is the right production migration strategy\n- If you omit an explicit primary key, Pony adds `id = PrimaryKey(int, auto=True)` automatically\n- Relationship fields must be declared on both sides\n\n## reviewnd Transaction Model\n\nAll ORM work should happen inside `@db_session` or `with db_session:`:\n\n```python\nfrom pony.orm import db_session, flush\n\n@db_session\ndef create_customer(email: str) -> int:\n    customer = Customer(email=email)\n    flush()  # assign auto PK before the session exits\n    return customer.id\n\n@db_session\ndef rename_customer(customer_id: int, new_email: str) -> None:\n    Customer[customer_id].email = new_email\n```\n\nContext-manager form:\n\n```python\nfrom pony.orm import db_session\n\nwith db_session:\n    customer = Customer(email=\"alice@example.com\")\n```\n\nWhat `db_session` does for you:\n\n- rolls back if an exception escapes the block\n- commits automatically if data changed and no exception occurred\n- clears the session cache on exit\n- returns the database connection to the pool\n\nPractical rule: entity instances are only safe to use inside the active session. If you need to hand data to templates, APIs, or background jobs, convert entities to plain dicts, lists, or scalar values before the session ends.\n\n## Core Usage\n\n### Create rows\n\n```python\nfrom datetime import date\nfrom pony.orm import db_session\n\n@db_session\ndef seed() -> None:\n    alice = Customer(email=\"alice@example.com\")\n    Order(total_cents=1999, created_on=date.today(), customer=alice)\n```\n\nPony tracks changes automatically. You do not call `.save()` on entities.\n\n### Look up one object\n\n```python\nfrom pony.orm import db_session\n\n@db_session\ndef get_customer(customer_id: int) -> Customer | None:\n    return Customer.get(id=customer_id)\n```\n\nUse cases:\n\n- `Customer[123]`: fetch by primary key and raise if missing\n- `Customer.get(email=\"alice@example.com\")`: return one object or `None`\n\nIf you return data to code outside the session, prefer returning plain values instead of the entity itself.\n\n### Query multiple rows\n\n```python\nfrom pony.orm import db_session, desc, select\n\n@db_session\ndef top_orders(limit: int = 10) -> list[tuple[str, int]]:\n    query = select(order for order in Order).order_by(lambda o: desc(o.total_cents))[:limit]\n    return [(order.customer.email, order.total_cents) for order in query]\n```\n\nUseful query patterns from Pony’s docs:\n\n- generator-based `select(...)`\n- slicing for `LIMIT` / `OFFSET`\n- `order_by(...)`\n- `exists(...)`, `count(...)`, and aggregate expressions when you need booleans or totals\n\n### Update and delete\n\n```python\nfrom pony.orm import db_session\n\n@db_session\ndef update_order(order_id: int, total_cents: int) -> None:\n    order = Order[order_id]\n    order.total_cents = total_cents\n\n@db_session\ndef delete_order(order_id: int) -> None:\n    Order[order_id].delete()\n```\n\nChanges persist automatically when the session exits successfully.\n\n## Provider Configuration\n\nPony does not have API keys or package-level auth. Configuration is database connection config passed to `db.bind(...)`.\n\nSQLite:\n\n```python\ndb.bind(provider=\"sqlite\", filename=\"app.sqlite\", create_db=True)\n```\n\nPostgreSQL:\n\n```python\nimport os\n\ndb.bind(\n    provider=\"postgres\",\n    user=os.environ[\"PGUSER\"],\n    password=os.environ[\"PGPASSWORD\"],\n    host=os.getenv(\"PGHOST\", \"127.0.0.1\"),\n    database=os.environ[\"PGDATABASE\"],\n)\n```\n\nMySQL:\n\n```python\nimport os\n\ndb.bind(\n    provider=\"mysql\",\n    host=os.getenv(\"MYSQL_HOST\", \"127.0.0.1\"),\n    user=os.environ[\"MYSQL_USER\"],\n    passwd=os.environ[\"MYSQL_PASSWORD\"],\n    db=os.environ[\"MYSQL_DATABASE\"],\n)\n```\n\nNotes:\n\n- The getting-started page lists supported databases with the label `postgresql`, but the canonical bind examples use `provider=\"postgres\"`. Follow the bind examples.\n- Use environment variables or your secret manager for credentials instead of hard-coding them.\n- `db.on_connect(...)` exists if you need per-connection session setup such as SQLite PRAGMAs or PostgreSQL session options.\n\n## Common Pitfalls\n\n- Forgetting `db_session`: even read-only work should run inside a session so connections are cleaned up correctly.\n- Returning live entities outside the session: later attribute access can fail because the identity map and connection are gone.\n- Assuming Pony needs explicit `.save()`: it does not. Changes are flushed and committed by the session machinery.\n- Using `create_tables=True` blindly in production: Pony can create missing tables, but schema migration planning is still your job.\n- Copying old docs snippets literally: the official docs still contain Python 2 era examples such as `print` statements without parentheses and broad `from pony.orm import *` imports.\n- Missing both sides of a relationship: Pony relationships are defined bidirectionally.\n\n## Version-Sensitive Notes For 0.7.19\n\n- As of March 12, 2026, PyPI still lists `0.7.19` as the current package version, so the version used here is current.\n- The maintainer changelog indicates `0.7.19` was a small packaging release that added a missed Python 3.12 classifier.\n- The same changelog notes `0.7.18` added Python 3.12 compatibility and fixed a SQLite 3.45 JSON-related SQL issue.\n- The changelog for `0.7.17` says Python 3.7 support was dropped. Treat current support as Python 3.8+ and verify against your runtime if you are pinned to older Python.\n- The docs site is still valuable, but parts of it are older than the latest releases. Trust the current package metadata and changelog for Python-version support when they disagree with older tutorial prose.\n\n## Official Sources\n\n- Docs root: `https://docs.ponyorm.org/`\n- Getting started: `https://docs.ponyorm.org/firststeps.html`\n- Database binding and connection options: `https://docs.ponyorm.org/database.html`\n- Entity declarations: `https://docs.ponyorm.org/entities.html`\n- CRUD and flush/commit behavior: `https://docs.ponyorm.org/crud.html`\n- Query syntax: `https://docs.ponyorm.org/queries.html`\n- Relationships: `https://docs.ponyorm.org/working_with_relationships.html`\n- PyPI package page: `https://pypi.org/project/pony/`\n- Maintainer repository: `https://github.com/ponyorm/pony`\n- Maintainer changelog: `https://github.com/ponyorm/pony/blob/master/CHANGELOG.md`\n"
  },
  {
    "path": "content/postcss/docs/postcss/javascript/DOC.md",
    "content": "---\nname: postcss\ndescription: \"PostCSS core JavaScript API for processing CSS with plugins, AST transforms, and source maps\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.5.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"postcss,css,plugins,ast,source-maps\"\n---\n\n# PostCSS for JavaScript\n\n`postcss` is the core library API for parsing CSS, running plugins, editing the AST, and serializing output. Use it inside build scripts, bundlers, or custom tooling when you need direct programmatic control.\n\n## Installation\n\n```bash\nnpm install postcss\n```\n\nNo authentication or environment variables are required.\n\nThe package metadata for `8.5.8` declares Node.js support as `^10 || ^12 || >=14`.\n\n## Import and initialization\n\nUse the library API directly. The core `postcss` package does not ship a CLI.\n\n```javascript\nimport postcss from 'postcss'\n\nconst uppercaseHexColors = {\n  postcssPlugin: 'uppercase-hex-colors',\n  Declaration(decl) {\n    decl.value = decl.value.replace(/#[0-9a-f]+/gi, match => match.toUpperCase())\n  }\n}\n\nconst processor = postcss([uppercaseHexColors])\n```\n\nCommonJS also works:\n\n```javascript\nconst postcss = require('postcss')\n```\n\n## Process CSS\n\nAlways set `from` and `to` when you know the input and output paths. PostCSS uses them for source maps and syntax error reporting.\n\n```javascript\nimport postcss from 'postcss'\n\nconst uppercaseHexColors = {\n  postcssPlugin: 'uppercase-hex-colors',\n  Declaration(decl) {\n    decl.value = decl.value.replace(/#[0-9a-f]+/gi, match => match.toUpperCase())\n  }\n}\n\nconst input = `\n.button {\n  color: #ff00aa;\n}\n`\n\nconst result = await postcss([uppercaseHexColors]).process(input, {\n  from: 'src/button.css',\n  to: 'dist/button.css',\n  map: { inline: false }\n})\n\nconsole.log(result.css)\n\nif (result.map) {\n  console.log(result.map.toString())\n}\n```\n\nUse `await processor.process(...)` or `.then(...)` for normal application code. PostCSS can run asynchronous plugins, so treating the result as a promise-safe workflow is the default.\n\n## Parse and edit the AST directly\n\nIf you already have CSS and want to mutate the AST yourself, parse it into a `Root`, change nodes, then serialize with `toResult()`.\n\n```javascript\nimport postcss from 'postcss'\n\nconst root = postcss.parse('a { color: black; margin: 0 }', {\n  from: 'src/input.css'\n})\n\nroot.walkDecls('color', decl => {\n  decl.value = '#111'\n})\n\nconst cardRule = postcss.rule({ selector: '.card' })\ncardRule.append(postcss.decl({ prop: 'padding', value: '1rem' }))\nroot.append(cardRule)\n\nconst result = root.toResult({\n  to: 'dist/output.css',\n  map: { inline: false }\n})\n\nconsole.log(result.css)\n```\n\nUseful constructors exposed by the package:\n\n- `postcss.rule(...)`\n- `postcss.decl(...)`\n- `postcss.atRule(...)`\n- `postcss.comment(...)`\n- `postcss.root(...)`\n- `postcss.document(...)`\n\n## Write a plugin\n\nFor PostCSS 8, prefer the current plugin format: return an object with `postcssPlugin` and visitor methods.\n\n```javascript\nimport postcss from 'postcss'\n\nfunction warnOnImportant() {\n  return {\n    postcssPlugin: 'warn-on-important',\n    Declaration(decl, { result }) {\n      if (decl.important) {\n        decl.warn(result, 'Avoid !important', { word: '!important' })\n      }\n    }\n  }\n}\n\nwarnOnImportant.postcss = true\n\nconst result = await postcss([warnOnImportant()]).process(\n  'a { color: red !important }',\n  { from: 'src/app.css' }\n)\n\nfor (const warning of result.warnings()) {\n  console.warn(warning.toString())\n}\n```\n\nYou can register visitors such as `Once`, `OnceExit`, `Rule`, `Declaration`, `AtRule`, `Comment`, and their `...Exit` variants. Declaration and at-rule visitors can also be keyed by property or rule name.\n\n## Source maps\n\nPostCSS supports source maps through the `map` option on `process()` or `toResult()`.\n\n```javascript\nimport postcss from 'postcss'\n\nconst result = await postcss().process('a { color: black }', {\n  from: 'src/app.css',\n  to: 'dist/app.css',\n  map: {\n    inline: false,\n    annotation: true,\n    sourcesContent: true\n  }\n})\n\nconsole.log(result.css)\nconsole.log(result.map?.toString())\n```\n\nIf you use `map.inline: true`, the source map is embedded into `result.css`, and `result.map` can be empty.\n\n## Error handling\n\n`postcss.parse()` throws `CssSyntaxError` for invalid CSS.\n\n```javascript\nimport postcss from 'postcss'\n\ntry {\n  postcss.parse('a { color: red', { from: 'src/broken.css' })\n} catch (error) {\n  if (error.name === 'CssSyntaxError') {\n    console.error(error.message)\n    console.error(error.showSourceCode())\n  } else {\n    throw error\n  }\n}\n```\n\nCheck `error.name === 'CssSyntaxError'` instead of `instanceof`, since a project can end up with multiple PostCSS copies in `node_modules`.\n\n## Important pitfalls\n\n- Do not use `postcss.plugin(...)` for new code. It is deprecated in PostCSS 8.\n- Do not pass a custom syntax object as a plugin. Use the `parser`, `stringifier`, or `syntax` process options instead.\n- Do not rely on synchronous getters like `lazyResult.css`, `lazyResult.root`, or `lazyResult.messages` if any plugin may be asynchronous. Use `await` or call `.sync()` only when every plugin is synchronous.\n- Reuse a `Processor` instance when you are processing many files with the same plugin set.\n"
  },
  {
    "path": "content/postgrest/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PostgREST Python client for sync and async queries, filters, CRUD operations, and RPC calls\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.28.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"postgrest,python,postgres,rest,api\"\n---\n\n# PostgREST Python Package Guide\n\n## Golden Rule\n\nUse the `postgrest` package from PyPI. The published Read the Docs site still reflects the older `postgrest-py` package and a `0.15.0` API reference, but PyPI currently publishes `postgrest 2.28.0`.\n\nThe maintainers document two client classes with the same query-builder interface:\n\n- `SyncPostgrestClient` for synchronous code\n- `AsyncPostgrestClient` for async code\n\nThe package metadata currently requires:\n\n- Python 3.9+\n- PostgreSQL 13+\n- PostgREST 11+\n\n## Install\n\n```bash\npython -m pip install \"postgrest==2.28.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"postgrest==2.28.0\"\npoetry add \"postgrest==2.28.0\"\n```\n\nEnvironment variables used in the examples below:\n\n```bash\nPOSTGREST_URL=http://localhost:3000\nPOSTGREST_BEARER_TOKEN=your-jwt-or-service-token\nPOSTGREST_SCHEMA=public\n```\n\n`POSTGREST_URL` should be the base URL for your PostgREST server.\n\n## Initialize A Client\n\n### Async client\n\n```python\nimport os\n\nfrom postgrest import AsyncPostgrestClient\n\nclient = AsyncPostgrestClient(\n    os.environ[\"POSTGREST_URL\"],\n    schema=os.getenv(\"POSTGREST_SCHEMA\", \"public\"),\n    timeout=10,\n)\n\nclient.auth(f\"Bearer {os.environ['POSTGREST_BEARER_TOKEN']}\")\n```\n\nIf you are already inside an async app, prefer the async client. The maintainer README uses it in an `async with` block so connections are closed automatically:\n\n```python\nimport asyncio\nimport os\n\nfrom postgrest import AsyncPostgrestClient\n\n\nasync def main() -> None:\n    async with AsyncPostgrestClient(\n        os.environ[\"POSTGREST_URL\"],\n        schema=os.getenv(\"POSTGREST_SCHEMA\", \"public\"),\n    ) as client:\n        client.auth(f\"Bearer {os.environ['POSTGREST_BEARER_TOKEN']}\")\n\n        response = await (\n            client.from_(\"countries\")\n            .select(\"id\", \"name\", \"capital\")\n            .order(\"name\")\n            .limit(10)\n            .execute()\n        )\n\n        print(response.data)\n\n\nasyncio.run(main())\n```\n\n### Sync client\n\n```python\nimport os\n\nfrom postgrest import SyncPostgrestClient\n\nclient = SyncPostgrestClient(\n    os.environ[\"POSTGREST_URL\"],\n    schema=os.getenv(\"POSTGREST_SCHEMA\", \"public\"),\n    timeout=10,\n)\n\nclient.auth(f\"Bearer {os.environ['POSTGREST_BEARER_TOKEN']}\")\n\ntry:\n    response = client.from_(\"countries\").select(\"id\", \"name\").limit(5).execute()\n    print(response.data)\nfinally:\n    client.aclose()\n```\n\n## Authentication And Schema Selection\n\nThe client exposes `auth()` for bearer-token or basic-auth configuration and `schema()` to switch the active schema.\n\nBearer token:\n\n```python\nclient.auth(f\"Bearer {os.environ['POSTGREST_BEARER_TOKEN']}\")\n```\n\nBasic auth:\n\n```python\nclient.auth(None, username=\"postgrest_user\", password=\"secret-password\")\n```\n\nSwitch schema for a request chain:\n\n```python\nanalytics = client.schema(\"analytics\")\nresponse = analytics.from_(\"daily_metrics\").select(\"*\").limit(1).execute()\n```\n\nThe auth example in the maintainer docs includes the `\"Bearer \"` prefix. Do not pass only the raw token string unless your server expects a custom authorization value.\n\n## Common Query Patterns\n\n### Read rows\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .select(\"id\", \"name\", \"capital\")\n    .eq(\"name\", \"France\")\n    .execute()\n)\n\nprint(response.data)\n```\n\n### Read one row\n\nUse `single()` when exactly one row should match:\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .select(\"id\", \"name\", \"capital\")\n    .eq(\"id\", 1)\n    .single()\n    .execute()\n)\n\ncountry = response.data\n```\n\nUse `maybe_single()` when zero rows is also acceptable:\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .select(\"id\", \"name\")\n    .eq(\"iso_code\", \"fr\")\n    .maybe_single()\n    .execute()\n)\n```\n\n### Filter, search, sort, and paginate\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .select(\"id\", \"name\")\n    .ilike(\"name\", \"%land%\")\n    .order(\"name\")\n    .limit(20)\n    .execute()\n)\n```\n\nUse `or_()` when you need a raw PostgREST OR expression:\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .select(\"id\", \"name\")\n    .or_(\"name.eq.France,name.eq.Spain\")\n    .execute()\n)\n```\n\n### Insert rows\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .insert(\n        {\n            \"id\": 1,\n            \"name\": \"France\",\n            \"capital\": \"Paris\",\n        }\n    )\n    .execute()\n)\n```\n\nInsert multiple rows:\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .insert(\n        [\n            {\"id\": 1, \"name\": \"France\"},\n            {\"id\": 2, \"name\": \"Spain\"},\n        ]\n    )\n    .execute()\n)\n```\n\n### Upsert rows\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .upsert(\n        {\"id\": 1, \"name\": \"France\", \"capital\": \"Paris\"},\n        on_conflict=\"id\",\n    )\n    .execute()\n)\n```\n\n### Update rows\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .update({\"capital\": \"Paris\"})\n    .eq(\"id\", 1)\n    .execute()\n)\n```\n\n### Delete rows\n\n```python\nresponse = (\n    client.from_(\"countries\")\n    .delete()\n    .eq(\"id\", 1)\n    .execute()\n)\n```\n\n### Call PostgreSQL functions with RPC\n\n```python\nresponse = client.rpc(\"hello_world\").execute()\nprint(response.data)\n```\n\nWith parameters:\n\n```python\nresponse = client.rpc(\n    \"search_countries\",\n    {\"prefix\": \"fr\"},\n).execute()\n```\n\n## Responses And Errors\n\nThe API reference documents these response and error types:\n\n- `APIResponse.data`: returned rows\n- `APIResponse.count`: populated when the request asks PostgREST to return a count\n- `APIError`: exposes `message`, `code`, `hint`, and `details`\n\nMinimal error handling:\n\n```python\nfrom postgrest import APIError, SyncPostgrestClient\n\nclient = SyncPostgrestClient(\"http://localhost:3000\")\n\ntry:\n    response = client.from_(\"countries\").select(\"*\").execute()\nexcept APIError as exc:\n    print(exc.message)\n    print(exc.code)\n    print(exc.hint)\n    print(exc.details)\nfinally:\n    client.aclose()\n```\n\n## Important Pitfalls\n\n- Install `postgrest`, not `postgrest-py`. The hosted docs still mention the old package name.\n- Call `execute()` at the end of a query chain. The builder methods only define the request.\n- For bearer auth, pass the full header value, for example `Bearer <token>`, because that is how the maintainer docs demonstrate `auth()`.\n- Use `from_()` or `table()`. The API reference marks `from_table()` as deprecated.\n- Close sync clients with `aclose()` when you do not use an async context manager.\n- Keep the base URL pointed at your PostgREST endpoint. The client does not discover it for you.\n\n## Version Notes For 2.28.0\n\n- PyPI shows `postgrest 2.28.0` released on February 10, 2026.\n- The official docs URL still serves an older `0.15.0` documentation set under the historic `postgrest-py` name.\n- The current maintainer README and PyPI metadata are the safest sources for package name, supported runtime versions, and the current async client examples.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/postgrest/\n- Maintainer docs root: https://postgrest-py.readthedocs.io/en/latest/\n- Client API reference: https://postgrest-py.readthedocs.io/en/latest/api/client.html\n- Request builder API reference: https://postgrest-py.readthedocs.io/en/latest/api/request_builder.html\n- Response API reference: https://postgrest-py.readthedocs.io/en/latest/api/responses.html\n- Exceptions API reference: https://postgrest-py.readthedocs.io/en/latest/api/exceptions.html\n- Maintainer repository: https://github.com/supabase/postgrest-py\n"
  },
  {
    "path": "content/posthog/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PostHog Python SDK for product analytics, feature flags, experiments, and error tracking\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.9.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"posthog,analytics,feature-flags,experiments,error-tracking,python\"\n---\n\n# PostHog Python SDK\n\n## Golden Rule\n\nUse the official `posthog` package, initialize it with your project token and PostHog host before capturing events, and treat feature flag local evaluation as a separate capability that needs a secure server-side key. If you are upgrading older code, read the `5.x -> 6.x` migration guidance first because `6.x` introduced the contexts API and breaking changes.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"posthog==7.9.11\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"posthog==7.9.11\"\npoetry add \"posthog==7.9.11\"\n```\n\nOptional extra for LangChain integration:\n\n```bash\npython -m pip install \"posthog[langchain]==7.9.11\"\n```\n\n## Authentication And Setup\n\nThe Python SDK needs:\n\n- A PostHog project token for event capture and normal feature flag requests\n- Your PostHog instance host, for example `https://us.i.posthog.com`\n- A separate secret key for local feature flag evaluation when you want low-latency flag checks without a per-request round trip\n\nBasic setup:\n\n```python\nimport os\nfrom posthog import Posthog\n\nposthog = Posthog(\n    os.environ[\"POSTHOG_PROJECT_API_KEY\"],\n    host=os.getenv(\"POSTHOG_HOST\", \"https://us.i.posthog.com\"),\n)\n```\n\nNotes:\n\n- The docs examples use `https://us.i.posthog.com`, but you should use the host for your own PostHog region or self-hosted deployment.\n- PostHog does not require specific environment variable names; the names above are just a sane convention.\n- The local evaluation guide says to use your project's \"Feature Flags Secure API Key\". In the Python constructor, this is still passed as `personal_api_key=...`.\n\n## Core Usage\n\n### Capture backend events\n\n```python\nfrom posthog import Posthog\n\nposthog = Posthog(\"<ph_project_token>\", host=\"https://us.i.posthog.com\")\n\nposthog.capture(\n    distinct_id=\"user-123\",\n    event=\"order_completed\",\n    properties={\n        \"order_id\": \"ord_123\",\n        \"amount\": 4999,\n        \"$set\": {\"email\": \"user@example.com\"},\n        \"$set_once\": {\"initial_referrer\": \"pricing-page\"},\n    },\n)\n```\n\nUse a stable `distinct_id` that matches the user identity you use elsewhere in PostHog.\n\n### Use contexts for request-scoped state\n\n`6.x+` added a contexts API that is the cleanest way to attach the active user, session, and tags across multiple backend events:\n\n```python\nfrom posthog import Posthog, identify_context, new_context, set_context_session, tag\n\nposthog = Posthog(\"<ph_project_token>\", host=\"https://us.i.posthog.com\")\n\nwith new_context():\n    identify_context(\"user-123\")\n    set_context_session(\"01957b8e-91a0-7d9e-8f2c-8df1904f1848\")\n    tag(\"transaction_id\", \"txn-42\")\n\n    posthog.capture(\"checkout_started\")\n    posthog.capture(\"checkout_completed\", properties={\"amount\": 4999})\n```\n\nImportant context behavior:\n\n- Nested contexts inherit parent tags, distinct IDs, and session IDs\n- `new_context(fresh=True)` starts clean instead of inheriting parent state\n- Direct arguments passed to `capture()` override context state for that event\n\nIf you use PostHog on the frontend too, forward the current `distinct_id` and session ID to your backend rather than inventing new values. The docs explicitly recommend passing the frontend distinct ID via `X-POSTHOG-DISTINCT-ID`, and the Django middleware can do this automatically.\n\n### Decorate a function with a fresh context\n\n```python\nfrom posthog import Posthog, identify_context, scoped\n\nposthog = Posthog(\"<ph_project_token>\", host=\"https://us.i.posthog.com\")\n\n@scoped(fresh=True)\ndef process_order(user_id: str, order_id: str) -> None:\n    identify_context(user_id)\n    posthog.capture(\"order_processed\", properties={\"order_id\": order_id})\n```\n\n### Group analytics\n\n```python\nposthog.group_identify(\n    \"company\",\n    \"acme\",\n    {\n        \"name\": \"Acme Inc.\",\n        \"tier\": \"enterprise\",\n        \"employees\": 250,\n    },\n)\n```\n\nUse the `\"name\"` property if you want a readable label in the PostHog UI.\n\n## Feature Flags And Experiments\n\n### Remote evaluation\n\n```python\nvariant = posthog.get_feature_flag(\"new-checkout\", \"user-123\")\n\nif variant == \"treatment\":\n    payload = posthog.get_feature_flag_payload(\"new-checkout\", \"user-123\")\n    print(payload)\n\nis_enabled = posthog.feature_enabled(\"beta-dashboard\", \"user-123\")\n```\n\nBy default, calling `get_feature_flag()` or `feature_enabled()` may also emit `$feature_flag_called` events. If you do not want that analytics event, pass `send_feature_flag_events=False`.\n\n### Include feature flags on a captured event\n\n```python\nposthog.capture(\n    distinct_id=\"user-123\",\n    event=\"checkout_completed\",\n    send_feature_flags=True,\n)\n```\n\nFrom `6.3.0+`, `send_feature_flags` can also be a dict so you can force local-only evaluation or provide properties used by rollout rules:\n\n```python\nposthog.capture(\n    distinct_id=\"user-123\",\n    event=\"checkout_completed\",\n    send_feature_flags={\n        \"only_evaluate_locally\": True,\n        \"person_properties\": {\"plan\": \"premium\"},\n        \"group_properties\": {\"org\": {\"tier\": \"enterprise\"}},\n    },\n)\n```\n\n### Local evaluation for lower latency\n\nUse local evaluation when your backend checks feature flags frequently and you want to avoid a network request on every flag read:\n\n```python\nfrom posthog import Posthog\n\nposthog = Posthog(\n    \"<ph_project_token>\",\n    host=\"https://us.i.posthog.com\",\n    personal_api_key=\"<feature-flags-secure-api-key>\",\n    poll_interval=30,\n)\n\nenabled = posthog.feature_enabled(\n    \"beta-dashboard\",\n    \"user-123\",\n    person_properties={\"plan\": \"premium\"},\n)\n```\n\nWhat matters here:\n\n- Upstream now recommends the \"Feature Flags Secure API Key\" for local evaluation\n- Existing personal API keys still work, but the docs say that path will be deprecated for local evaluation\n- Polling defaults to `30` seconds in Python\n- In edge, Lambda, or other stateless multi-worker environments, the local evaluation docs recommend an external cache provider instead of per-request in-memory initialization\n\nExperiments use the same flag APIs. Treat experiment variants as feature flag variants and branch on the returned value.\n\n## Error Tracking\n\nEnable exception autocapture when PostHog should record backend exceptions automatically:\n\n```python\nfrom posthog import Posthog\n\nposthog = Posthog(\n    \"<ph_project_token>\",\n    host=\"https://us.i.posthog.com\",\n    enable_exception_autocapture=True,\n    capture_exception_code_variables=True,\n)\n```\n\nYou can also capture manually:\n\n```python\ntry:\n    do_work()\nexcept Exception as exc:\n    posthog.capture_exception(\n        exc,\n        \"user-123\",\n        properties={\"job_name\": \"nightly-sync\"},\n    )\n    raise\n```\n\nWithin a context, exceptions are captured automatically unless you create the context with `capture_exceptions=False`.\n\n## Operational Configuration\n\n### Serverless and short-lived processes\n\nThe SDK buffers events by default. In serverless runtimes this can lose events if the process exits before the buffer flushes.\n\nUse one of these patterns:\n\n```python\nposthog = Posthog(\"<ph_project_token>\", host=\"https://us.i.posthog.com\", sync_mode=True)\n```\n\nOr explicitly shut the client down at the end of request handling:\n\n```python\ntry:\n    posthog.capture(\"job_finished\", distinct_id=\"worker-1\")\nfinally:\n    posthog.shutdown()\n```\n\n`shutdown()` is blocking, which is why PostHog recommends it as middleware or request-finalization logic instead of calling it randomly mid-request.\n\n### Connection reuse and networking\n\nThe SDK uses HTTP connection pooling. If your runtime sits behind infrastructure that drops idle pooled connections, the docs recommend one of these before making requests:\n\n```python\nimport posthog\n\nposthog.enable_keep_alive()\n```\n\n```python\nimport posthog\n\nposthog.disable_connection_reuse()\n```\n\nYou can also set custom socket options with `posthog.set_socket_options(...)`.\n\n### Tests and debugging\n\n```python\nposthog.debug = True\nposthog.disabled = True\n```\n\n- `debug = True` enables verbose SDK logging\n- `disabled = True` suppresses capture and network requests during tests\n\n## Common Pitfalls\n\n- Do not confuse the project token with the secure key used for local flag evaluation. Event capture uses the project token; local evaluation needs the feature flags secure API key.\n- Do not let backend code invent a new `distinct_id` if the frontend already has one. Forward the frontend identity and session headers to keep person, session replay, and error tracking views coherent.\n- Do not rely on buffered async capture in Lambda-like environments unless you also call `posthog.shutdown()` or enable `sync_mode=True`.\n- `send_feature_flags=True` can add an extra network request when local evaluation is not configured.\n- Contexts are inherited by nested contexts unless you pass `fresh=True`. That is convenient, but it can also leak tags or session IDs further than intended.\n- GeoIP defaults changed long ago. Since `v3.0`, PostHog no longer enriches events from the server IP by default. If you need GeoIP-based flag evaluation from backend calls, pass the relevant person properties explicitly.\n- The docs mention a special `posthoganalytics` package only for module-name collision scenarios. Use normal `posthog` unless you have that exact problem.\n\n## Version-Sensitive Notes\n\n- `6.x` introduced the contexts API and breaking changes from `5.x`; do not copy `5.x` patterns blindly into `7.x` projects.\n- `6.3.0+` changed feature-flag capture behavior: `send_feature_flags` is explicit, and dict-based advanced control became available.\n- This guide is pinned to `7.9.11`, but PyPI lists `7.9.12` as the latest release on March 12, 2026. Check release drift before pinning examples for a fresh project.\n- The package metadata currently shown on PyPI for `7.9.12` says `Requires: Python >=3.10`. The PostHog docs page separately says Python `3.9` is no longer supported. Inference: treat current `7.9.x` work as Python `3.10+` unless your exact pinned artifact proves otherwise.\n\n## Official Sources\n\n- Python SDK docs: `https://posthog.com/docs/libraries/python`\n- Local evaluation guide: `https://posthog.com/docs/feature-flags/local-evaluation`\n- Distributed local evaluation guide: `https://posthog.com/docs/feature-flags/local-evaluation/distributed`\n- PyPI package page: `https://pypi.org/project/posthog/`\n- Source repository: `https://github.com/PostHog/posthog-python`\n- Changelog: `https://raw.githubusercontent.com/PostHog/posthog-python/master/CHANGELOG.md`\n"
  },
  {
    "path": "content/postmark/docs/transactional-email/DOC.md",
    "content": "---\nname: transactional-email\ndescription: \"Postmark API coding guidelines for transactional email sending using the official Node.js library\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.5\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"postmark,email,transactional,delivery,smtp\"\n---\n\n# Postmark API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Postmark API coding expert. Help me with writing code using the official Postmark Node.js library for transactional email sending and API interactions.\n\nYou can find the official documentation and code samples here: https://postmarkapp.com/developer\n\n## Golden Rule: Use the Correct and Current Package\n\nAlways use the official Postmark Node.js library, which provides complete support for the entire Postmark REST API.\n\n- **Library Name:** Postmark Node.js Library\n- **NPM Package:** `postmark`\n- **Minimum Node.js Version:** v14.0.0\n- **Repository:** https://github.com/ActiveCampaign/postmark.js\n- **Documentation:** https://activecampaign.github.io/postmark.js/\n\n**Installation:**\n\n- **Correct:** `npm install postmark`\n\n**APIs and Usage:**\n\n- **Correct:** `const postmark = require('postmark')`\n- **Correct:** `const client = new postmark.ServerClient(serverToken)`\n- **Correct:** `const accountClient = new postmark.AccountClient(accountToken)`\n- **Correct:** `await client.sendEmail(...)`\n- **Correct:** `await client.sendEmailWithTemplate(...)`\n- **Correct:** `await client.sendEmailBatch(...)`\n- **Incorrect:** Using unofficial packages or legacy libraries\n\n## API Keys and Authentication\n\nPostmark uses two types of API tokens for different purposes:\n\n### Server API Token\n\nUsed for sending emails and accessing server-specific endpoints. Set the `X-Postmark-Server-Token` header for API requests.\n\n```javascript\nconst postmark = require('postmark');\nconst serverToken = process.env.POSTMARK_SERVER_TOKEN;\nconst client = new postmark.ServerClient(serverToken);\n```\n\n### Account API Token\n\nUsed for managing servers and account-level operations. Set the `X-Postmark-Account-Token` header for API requests.\n\n```javascript\nconst postmark = require('postmark');\nconst accountToken = process.env.POSTMARK_ACCOUNT_TOKEN;\nconst accountClient = new postmark.AccountClient(accountToken);\n```\n\n### Environment Variable Configuration\n\nNever hardcode API keys. Always use environment variables:\n\n```bash\necho \"export POSTMARK_SERVER_TOKEN='YOUR_SERVER_TOKEN'\" > postmark.env\necho \"export POSTMARK_ACCOUNT_TOKEN='YOUR_ACCOUNT_TOKEN'\" >> postmark.env\necho \"postmark.env\" >> .gitignore\nsource ./postmark.env\n```\n\n```javascript\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n```\n\n## Prerequisites\n\nBefore sending emails with Postmark:\n\n- Sign up for a Postmark account (free tier: 100 emails/month)\n- Create a server in your Postmark account\n- Verify your sender signature or domain\n- Obtain your Server API token from the API Tokens tab\n\n## Basic Email Sending\n\n### Simple Email\n\nSend a basic email with HTML and text body:\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Hello from Postmark',\n    HtmlBody: '<strong>Hello!</strong> This is a test email.',\n    TextBody: 'Hello! This is a test email.'\n}).then(response => {\n    console.log('Email sent successfully');\n    console.log('Message ID:', response.MessageID);\n    console.log('To:', response.To);\n    console.log('Submitted at:', response.SubmittedAt);\n});\n```\n\n### Using async/await\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nasync function sendEmail() {\n    try {\n        const response = await client.sendEmail({\n            From: 'sender@example.com',\n            To: 'recipient@example.com',\n            Subject: 'Hello from Postmark',\n            HtmlBody: '<h1>Welcome!</h1><p>This is a test email.</p>',\n            TextBody: 'Welcome! This is a test email.'\n        });\n\n        console.log('Email sent:', response.MessageID);\n    } catch (error) {\n        console.error('Error sending email:', error);\n    }\n}\n\nsendEmail();\n```\n\n### Multiple Recipients\n\nSend to multiple recipients in the To, Cc, or Bcc fields:\n\n```javascript\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient1@example.com, recipient2@example.com',\n    Cc: 'cc1@example.com, cc2@example.com',\n    Bcc: 'bcc1@example.com, bcc2@example.com',\n    Subject: 'Multiple recipients',\n    HtmlBody: '<p>This email goes to multiple people.</p>',\n    TextBody: 'This email goes to multiple people.'\n});\n```\n\n**Note:** Maximum 50 recipients per field (To, Cc, Bcc).\n\n### With Reply-To Address\n\nOverride the reply address:\n\n```javascript\nclient.sendEmail({\n    From: 'noreply@example.com',\n    To: 'customer@example.com',\n    ReplyTo: 'support@example.com',\n    Subject: 'Customer Support',\n    HtmlBody: '<p>Reply to this email for support.</p>',\n    TextBody: 'Reply to this email for support.'\n});\n```\n\n## Batch Email Sending\n\nSend up to 500 emails in a single API call (maximum 50 MB payload):\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nclient.sendEmailBatch([\n    {\n        From: 'sender@example.com',\n        To: 'user1@example.com',\n        Subject: 'Welcome User 1',\n        HtmlBody: '<p>Welcome to our service!</p>',\n        TextBody: 'Welcome to our service!'\n    },\n    {\n        From: 'sender@example.com',\n        To: 'user2@example.com',\n        Subject: 'Welcome User 2',\n        HtmlBody: '<p>Welcome to our service!</p>',\n        TextBody: 'Welcome to our service!'\n    },\n    {\n        From: 'sender@example.com',\n        To: 'user3@example.com',\n        Subject: 'Welcome User 3',\n        HtmlBody: '<p>Welcome to our service!</p>',\n        TextBody: 'Welcome to our service!'\n    }\n]).then(responses => {\n    responses.forEach((response, index) => {\n        console.log(`Email ${index + 1}:`, response.Message);\n        console.log('Message ID:', response.MessageID);\n    });\n});\n```\n\n**Important:** Batch requests return HTTP 200 even if individual messages fail validation. Always check each response for error codes.\n\n## Template Emails\n\n### Send Email with Template ID\n\nSend an email using a pre-created template:\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nclient.sendEmailWithTemplate({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    TemplateId: 123456,\n    TemplateModel: {\n        name: 'John Doe',\n        product_name: 'Awesome App',\n        action_url: 'https://example.com/verify',\n        company_name: 'My Company'\n    }\n}).then(response => {\n    console.log('Template email sent:', response.MessageID);\n});\n```\n\n### Send Email with Template Alias\n\nUse a template alias instead of numeric ID:\n\n```javascript\nclient.sendEmailWithTemplate({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    TemplateAlias: 'welcome-email',\n    TemplateModel: {\n        user_name: 'Jane Smith',\n        login_url: 'https://example.com/login'\n    }\n});\n```\n\n### Batch Template Emails\n\nSend multiple template-based emails:\n\n```javascript\nclient.sendEmailBatchWithTemplates([\n    {\n        From: 'sender@example.com',\n        To: 'user1@example.com',\n        TemplateId: 123456,\n        TemplateModel: {\n            name: 'User One',\n            code: 'ABC123'\n        }\n    },\n    {\n        From: 'sender@example.com',\n        To: 'user2@example.com',\n        TemplateAlias: 'welcome-email',\n        TemplateModel: {\n            name: 'User Two',\n            code: 'DEF456'\n        }\n    }\n]).then(responses => {\n    responses.forEach((response, index) => {\n        console.log(`Template email ${index + 1}:`, response.Message);\n    });\n});\n```\n\n## Advanced Email Features\n\n### Tags and Metadata\n\nAdd tags for categorization and metadata for custom tracking:\n\n```javascript\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Order Confirmation',\n    HtmlBody: '<p>Your order has been confirmed.</p>',\n    TextBody: 'Your order has been confirmed.',\n    Tag: 'order-confirmation',\n    Metadata: {\n        order_id: '12345',\n        customer_id: '67890',\n        total_amount: '99.99'\n    }\n});\n```\n\n**Metadata notes:**\n- Maximum 1000 characters per tag\n- Metadata appears in webhooks and API responses\n- Useful for tracking and filtering messages\n\n### Tracking Opens\n\nEnable open tracking to know when recipients open emails:\n\n```javascript\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Track opens',\n    HtmlBody: '<p>This email tracks opens.</p>',\n    TextBody: 'This email tracks opens.',\n    TrackOpens: true\n});\n```\n\n### Tracking Links\n\nTrack clicks on links in your emails:\n\n```javascript\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Track links',\n    HtmlBody: '<p>Click <a href=\"https://example.com\">here</a>.</p>',\n    TextBody: 'Click here: https://example.com',\n    TrackLinks: 'HtmlAndText'\n});\n```\n\n**TrackLinks options:**\n- `'None'` - No link tracking\n- `'HtmlOnly'` - Track links in HTML body only\n- `'TextOnly'` - Track links in text body only\n- `'HtmlAndText'` - Track links in both bodies\n\n### Message Streams\n\nOrganize emails by type using message streams:\n\n```javascript\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Newsletter',\n    HtmlBody: '<p>Monthly newsletter content.</p>',\n    TextBody: 'Monthly newsletter content.',\n    MessageStream: 'broadcasts'\n});\n```\n\n**Default streams:**\n- `'outbound'` - Transactional emails (default)\n- `'broadcasts'` - Marketing/bulk emails\n- Custom streams can be created in your Postmark account\n\n## Attachments\n\n### Basic Attachments\n\nAttach files using Base64 encoding:\n\n```javascript\nconst fs = require('fs');\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nconst fileContent = fs.readFileSync('/path/to/document.pdf');\nconst base64Content = fileContent.toString('base64');\n\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Document attached',\n    HtmlBody: '<p>Please see the attached document.</p>',\n    TextBody: 'Please see the attached document.',\n    Attachments: [\n        {\n            Name: 'document.pdf',\n            Content: base64Content,\n            ContentType: 'application/pdf'\n        }\n    ]\n});\n```\n\n### Using Postmark Models\n\nUse the built-in `Attachment` model for cleaner code:\n\n```javascript\nconst fs = require('fs');\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nconst message = new postmark.Models.Message(\n    'sender@example.com',\n    'Document attached',\n    '<p>Please see the attached files.</p>',\n    'Please see the attached files.',\n    'recipient@example.com'\n);\n\nconst attachment1 = new postmark.Models.Attachment(\n    'report.txt',\n    Buffer.from('Report content here').toString('base64'),\n    'text/plain'\n);\n\nconst attachment2 = new postmark.Models.Attachment(\n    'invoice.pdf',\n    fs.readFileSync('/path/to/invoice.pdf').toString('base64'),\n    'application/pdf'\n);\n\nmessage.Attachments = [attachment1, attachment2];\n\nclient.sendEmail(message);\n```\n\n### Multiple Attachments\n\n```javascript\nconst attachments = [\n    {\n        Name: 'image.jpg',\n        Content: fs.readFileSync('/path/to/image.jpg').toString('base64'),\n        ContentType: 'image/jpeg'\n    },\n    {\n        Name: 'spreadsheet.xlsx',\n        Content: fs.readFileSync('/path/to/data.xlsx').toString('base64'),\n        ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n    },\n    {\n        Name: 'notes.txt',\n        Content: Buffer.from('Meeting notes...').toString('base64'),\n        ContentType: 'text/plain'\n    }\n];\n\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Multiple attachments',\n    HtmlBody: '<p>Three files attached.</p>',\n    TextBody: 'Three files attached.',\n    Attachments: attachments\n});\n```\n\n### Inline Images\n\nEmbed images directly in HTML emails using Content ID (CID):\n\n```javascript\nconst fs = require('fs');\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nconst message = new postmark.Models.Message(\n    'sender@example.com',\n    'Inline image example',\n    '<!DOCTYPE html><html><body><h1>Logo</h1><img src=\"cid:logo.png\"/></body></html>',\n    'Logo image included.',\n    'recipient@example.com'\n);\n\nconst inlineImage = new postmark.Models.Attachment(\n    'logo.png',\n    fs.readFileSync('/path/to/logo.png').toString('base64'),\n    'image/png',\n    'cid:logo.png'\n);\n\nmessage.Attachments = [inlineImage];\n\nclient.sendEmail(message);\n```\n\n## Custom Headers\n\nAdd custom email headers:\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nconst message = new postmark.Models.Message(\n    'sender@example.com',\n    'Custom headers',\n    '<p>Email with custom headers.</p>',\n    'Email with custom headers.',\n    'recipient@example.com'\n);\n\nmessage.Headers = [\n    { Name: 'X-Custom-Header', Value: 'custom-value' },\n    { Name: 'X-Priority', Value: '1' },\n    { Name: 'X-Campaign-ID', Value: 'summer-2025' }\n];\n\nclient.sendEmail(message);\n```\n\n## Template Management\n\n### Get Template\n\nRetrieve a template by ID or alias:\n\n```javascript\n// By template ID\nclient.getTemplate(123456).then(template => {\n    console.log('Template name:', template.Name);\n    console.log('Template alias:', template.Alias);\n    console.log('HTML body:', template.HtmlBody);\n});\n\n// By template alias\nclient.getTemplate('welcome-email').then(template => {\n    console.log('Template:', template);\n});\n```\n\n### Create Template\n\n```javascript\nclient.createTemplate({\n    Name: 'Welcome Email',\n    Alias: 'welcome-email',\n    Subject: 'Welcome to {{company_name}}!',\n    HtmlBody: '<h1>Welcome {{user_name}}!</h1><p>Thanks for joining.</p>',\n    TextBody: 'Welcome {{user_name}}! Thanks for joining.'\n}).then(template => {\n    console.log('Created template ID:', template.TemplateId);\n});\n```\n\n### Edit Template\n\n```javascript\nclient.editTemplate(123456, {\n    Name: 'Updated Welcome Email',\n    Subject: 'Welcome to {{company_name}}, {{user_name}}!',\n    HtmlBody: '<h1>Hi {{user_name}}!</h1><p>Welcome to {{company_name}}.</p>',\n    TextBody: 'Hi {{user_name}}! Welcome to {{company_name}}.'\n}).then(template => {\n    console.log('Updated template:', template.Name);\n});\n```\n\n### Delete Template\n\n```javascript\n// By template ID\nclient.deleteTemplate(123456).then(response => {\n    console.log('Template deleted:', response.Message);\n});\n\n// By template alias\nclient.deleteTemplate('old-template').then(response => {\n    console.log('Template deleted:', response.Message);\n});\n```\n\n### List Templates\n\n```javascript\nclient.getTemplates({\n    Count: 10,\n    Offset: 0\n}).then(result => {\n    console.log('Total templates:', result.TotalCount);\n    result.Templates.forEach(template => {\n        console.log('Template:', template.Name, '(ID:', template.TemplateId + ')');\n    });\n});\n```\n\n### Validate Template\n\nTest template rendering before sending:\n\n```javascript\nclient.validateTemplate({\n    Subject: 'Hello {{name}}',\n    HtmlBody: '<p>Welcome {{name}} to {{company}}!</p>',\n    TextBody: 'Welcome {{name}} to {{company}}!',\n    TestRenderModel: {\n        name: 'John',\n        company: 'Acme Corp'\n    }\n}).then(result => {\n    console.log('Rendered subject:', result.Subject.RenderedContent);\n    console.log('Rendered HTML:', result.HtmlBody.RenderedContent);\n    console.log('Suggested template model:', result.SuggestedTemplateModel);\n});\n```\n\n## Messages API\n\n### Get Outbound Messages\n\nRetrieve sent messages with filtering:\n\n```javascript\nclient.getOutboundMessages({\n    Count: 50,\n    Offset: 0,\n    Recipient: 'user@example.com',\n    FromEmail: 'sender@example.com',\n    Tag: 'order-confirmation',\n    Status: 'sent'\n}).then(result => {\n    console.log('Total messages:', result.TotalCount);\n    result.Messages.forEach(message => {\n        console.log('Message ID:', message.MessageID);\n        console.log('Subject:', message.Subject);\n        console.log('Status:', message.Status);\n    });\n});\n```\n\n### Get Message Details\n\n```javascript\nclient.getOutboundMessageDetails('message-id-here').then(details => {\n    console.log('From:', details.From);\n    console.log('To:', details.To);\n    console.log('Subject:', details.Subject);\n    console.log('Status:', details.Status);\n    console.log('Received at:', details.ReceivedAt);\n    console.log('Message events:', details.MessageEvents);\n});\n```\n\n### Get Message Dump\n\nRetrieve full message content including headers:\n\n```javascript\nclient.getOutboundMessageDump('message-id-here').then(dump => {\n    console.log('Raw message:', dump.Body);\n});\n```\n\n### Get Message Clicks\n\nTrack which links were clicked:\n\n```javascript\nclient.getMessageClicks('message-id-here').then(result => {\n    result.Clicks.forEach(click => {\n        console.log('Link:', click.OriginalLink);\n        console.log('Clicked at:', click.RecordedAt);\n        console.log('Platform:', click.Platform);\n    });\n});\n```\n\n### Get Message Opens\n\nTrack when messages were opened:\n\n```javascript\nclient.getMessageOpens('message-id-here').then(result => {\n    result.Opens.forEach(open => {\n        console.log('Opened at:', open.RecordedAt);\n        console.log('Platform:', open.Platform);\n        console.log('Client:', open.Client);\n    });\n});\n```\n\n## Inbound Email Processing\n\n### Get Inbound Messages\n\nRetrieve inbound emails sent to your Postmark inbox:\n\n```javascript\nclient.getInboundMessages({\n    Count: 50,\n    Offset: 0,\n    Recipient: 'inbox@inbound.example.com',\n    FromEmail: 'sender@example.com'\n}).then(result => {\n    console.log('Total inbound messages:', result.TotalCount);\n    result.InboundMessages.forEach(message => {\n        console.log('From:', message.From);\n        console.log('Subject:', message.Subject);\n        console.log('Received:', message.ReceivedAt);\n    });\n});\n```\n\n### Get Inbound Message Details\n\n```javascript\nclient.getInboundMessageDetails('inbound-message-id').then(message => {\n    console.log('From:', message.From);\n    console.log('To:', message.To);\n    console.log('Subject:', message.Subject);\n    console.log('HTML body:', message.HtmlBody);\n    console.log('Text body:', message.TextBody);\n    console.log('Attachments:', message.Attachments);\n});\n```\n\n### Bypass Blocked Inbound Message\n\nAllow specific blocked inbound messages:\n\n```javascript\nclient.bypassBlockedInboundMessage('inbound-message-id').then(response => {\n    console.log('Message unblocked:', response.Message);\n});\n```\n\n### Retry Inbound Hook\n\nManually retry webhook delivery for an inbound message:\n\n```javascript\nclient.retryInboundHookForMessage('inbound-message-id').then(response => {\n    console.log('Hook retried:', response.Message);\n});\n```\n\n## Bounce Management\n\n### Get Bounces\n\nRetrieve bounced emails:\n\n```javascript\nclient.getBounces({\n    Count: 50,\n    Offset: 0,\n    Type: 'HardBounce',\n    EmailFilter: 'user@example.com',\n    Tag: 'newsletter'\n}).then(result => {\n    console.log('Total bounces:', result.TotalCount);\n    result.Bounces.forEach(bounce => {\n        console.log('Email:', bounce.Email);\n        console.log('Type:', bounce.Type);\n        console.log('Bounced at:', bounce.BouncedAt);\n    });\n});\n```\n\n### Get Bounce Details\n\n```javascript\nclient.getBounce('bounce-id').then(bounce => {\n    console.log('Email:', bounce.Email);\n    console.log('Type:', bounce.Type);\n    console.log('Description:', bounce.Description);\n    console.log('Details:', bounce.Details);\n});\n```\n\n### Get Bounce Dump\n\nRetrieve raw bounce message:\n\n```javascript\nclient.getBounceDump('bounce-id').then(dump => {\n    console.log('Raw bounce:', dump.Body);\n});\n```\n\n### Activate Bounced Email\n\nReactivate a bounced email address:\n\n```javascript\nclient.activateBounce('bounce-id').then(response => {\n    console.log('Bounce activated:', response.Message);\n});\n```\n\n## Suppressions Management\n\n### Get Suppressions\n\nRetrieve suppressed email addresses:\n\n```javascript\nclient.getSuppressions('outbound', {\n    Count: 50,\n    Offset: 0,\n    EmailFilter: 'user@example.com'\n}).then(result => {\n    console.log('Total suppressions:', result.Suppressions.length);\n    result.Suppressions.forEach(suppression => {\n        console.log('Email:', suppression.EmailAddress);\n        console.log('Reason:', suppression.SuppressionReason);\n        console.log('Created at:', suppression.CreatedAt);\n    });\n});\n```\n\n### Create Suppressions\n\nManually suppress email addresses:\n\n```javascript\nclient.createSuppressions('outbound', [\n    { EmailAddress: 'user1@example.com' },\n    { EmailAddress: 'user2@example.com' }\n]).then(result => {\n    console.log('Suppressions created:', result.Suppressions.length);\n});\n```\n\n### Delete Suppressions\n\nRemove email addresses from suppression list:\n\n```javascript\nclient.deleteSuppressions('outbound', [\n    { EmailAddress: 'user1@example.com' },\n    { EmailAddress: 'user2@example.com' }\n]).then(result => {\n    console.log('Suppressions deleted:', result.Suppressions.length);\n});\n```\n\n## Webhooks\n\n### Get Webhooks\n\nRetrieve configured webhooks:\n\n```javascript\nclient.getWebhooks().then(webhooks => {\n    webhooks.Webhooks.forEach(webhook => {\n        console.log('Webhook ID:', webhook.ID);\n        console.log('URL:', webhook.Url);\n        console.log('Message stream:', webhook.MessageStream);\n        console.log('Triggers:', webhook.Triggers);\n    });\n});\n```\n\n### Create Webhook\n\n```javascript\nclient.createWebhook({\n    Url: 'https://example.com/webhooks/postmark',\n    MessageStream: 'outbound',\n    HttpAuth: {\n        Username: 'webhook_user',\n        Password: 'webhook_pass'\n    },\n    HttpHeaders: [\n        { Name: 'X-Custom-Header', Value: 'value' }\n    ],\n    Triggers: {\n        Open: { Enabled: true },\n        Click: { Enabled: true },\n        Delivery: { Enabled: true },\n        Bounce: { Enabled: true },\n        SpamComplaint: { Enabled: true }\n    }\n}).then(webhook => {\n    console.log('Webhook created:', webhook.ID);\n});\n```\n\n### Edit Webhook\n\n```javascript\nclient.editWebhook(123456, {\n    Url: 'https://example.com/webhooks/postmark-updated',\n    Triggers: {\n        Open: { Enabled: true },\n        Click: { Enabled: true },\n        Delivery: { Enabled: false }\n    }\n}).then(webhook => {\n    console.log('Webhook updated:', webhook.ID);\n});\n```\n\n### Delete Webhook\n\n```javascript\nclient.deleteWebhook(123456).then(response => {\n    console.log('Webhook deleted:', response.Message);\n});\n```\n\n## Server Management (Account Client)\n\n### Get Server\n\n```javascript\nconst postmark = require('postmark');\nconst accountClient = new postmark.AccountClient(process.env.POSTMARK_ACCOUNT_TOKEN);\n\naccountClient.getServer(123456).then(server => {\n    console.log('Server name:', server.Name);\n    console.log('Server ID:', server.ID);\n    console.log('Color:', server.Color);\n});\n```\n\n### Create Server\n\n```javascript\naccountClient.createServer({\n    Name: 'Production Server',\n    Color: 'blue'\n}).then(server => {\n    console.log('Server created:', server.ID);\n    console.log('Server token:', server.ApiTokens);\n});\n```\n\n### Edit Server\n\n```javascript\naccountClient.editServer(123456, {\n    Name: 'Updated Server Name',\n    Color: 'green'\n}).then(server => {\n    console.log('Server updated:', server.Name);\n});\n```\n\n### List Servers\n\n```javascript\naccountClient.getServers({\n    Count: 50,\n    Offset: 0,\n    Name: 'Production'\n}).then(result => {\n    console.log('Total servers:', result.TotalCount);\n    result.Servers.forEach(server => {\n        console.log('Server:', server.Name, '(ID:', server.ID + ')');\n    });\n});\n```\n\n## Client Configuration\n\n### Timeout Configuration\n\nSet custom timeout for API requests:\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\n// Set timeout to 30 seconds (default is 30000ms)\nclient.setClientOptions({ timeout: 60000 });\n```\n\n### Custom Headers\n\nAdd default headers to all requests:\n\n```javascript\nclient.setClientOptions({\n    headers: {\n        'X-Custom-Header': 'custom-value'\n    }\n});\n```\n\n### Use Test Token\n\nFor testing without sending actual emails:\n\n```javascript\nconst client = new postmark.ServerClient('POSTMARK_API_TEST');\n\n// This will validate the API call but not actually send the email\nclient.sendEmail({\n    From: 'sender@example.com',\n    To: 'recipient@example.com',\n    Subject: 'Test email',\n    HtmlBody: '<p>This is a test.</p>'\n});\n```\n\n## Error Handling\n\nAlways handle errors properly when making API calls:\n\n```javascript\nconst postmark = require('postmark');\nconst client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);\n\nasync function sendEmailWithErrorHandling() {\n    try {\n        const response = await client.sendEmail({\n            From: 'sender@example.com',\n            To: 'recipient@example.com',\n            Subject: 'Test',\n            HtmlBody: '<p>Test email</p>'\n        });\n\n        console.log('Success:', response.MessageID);\n        return response;\n\n    } catch (error) {\n        // Handle specific error codes\n        if (error.statusCode === 401) {\n            console.error('Invalid API token');\n        } else if (error.statusCode === 422) {\n            console.error('Validation error:', error.message);\n        } else if (error.statusCode === 429) {\n            console.error('Rate limit exceeded');\n        } else if (error.statusCode >= 500) {\n            console.error('Server error:', error.message);\n        } else {\n            console.error('API error:', error.message);\n        }\n\n        console.error('Error code:', error.code);\n        console.error('Error details:', error.body);\n\n        throw error;\n    }\n}\n\nsendEmailWithErrorHandling();\n```\n\n### Common Error Codes\n\n| Status Code | Error Type | Description |\n|-------------|------------|-------------|\n| 401 | Unauthorized | Invalid or missing API token |\n| 403 | Forbidden | Sender signature not verified |\n| 422 | Unprocessable Entity | Validation error (invalid parameters) |\n| 429 | Too Many Requests | Rate limit exceeded |\n| 500 | Internal Server Error | Postmark server error |\n| 503 | Service Unavailable | Postmark temporarily unavailable |\n\n### Batch Error Handling\n\nWhen sending batch emails, check each response individually:\n\n```javascript\nconst responses = await client.sendEmailBatch([\n    { From: 'sender@example.com', To: 'user1@example.com', Subject: 'Test 1', HtmlBody: '<p>Test</p>' },\n    { From: 'sender@example.com', To: 'invalid-email', Subject: 'Test 2', HtmlBody: '<p>Test</p>' },\n    { From: 'sender@example.com', To: 'user3@example.com', Subject: 'Test 3', HtmlBody: '<p>Test</p>' }\n]);\n\nresponses.forEach((response, index) => {\n    if (response.ErrorCode === 0) {\n        console.log(`Email ${index + 1} sent successfully:`, response.MessageID);\n    } else {\n        console.error(`Email ${index + 1} failed:`, response.Message);\n    }\n});\n```\n\n## TypeScript Support\n\nThe Postmark library includes full TypeScript definitions:\n\n```typescript\nimport * as postmark from 'postmark';\nimport { ServerClient, Message, TemplatedMessage } from 'postmark';\n\nconst client: ServerClient = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN!);\n\ninterface EmailResponse {\n    To: string;\n    SubmittedAt: string;\n    MessageID: string;\n    ErrorCode: number;\n    Message: string;\n}\n\nasync function sendTypedEmail(): Promise<EmailResponse> {\n    const message: Message = new postmark.Models.Message(\n        'sender@example.com',\n        'Test email',\n        '<p>HTML body</p>',\n        'Text body',\n        'recipient@example.com'\n    );\n\n    const response = await client.sendEmail(message);\n    return response;\n}\n\nasync function sendTemplateEmail(): Promise<EmailResponse> {\n    const templateMessage: TemplatedMessage = {\n        From: 'sender@example.com',\n        To: 'recipient@example.com',\n        TemplateId: 123456,\n        TemplateModel: {\n            name: 'John Doe',\n            code: 'ABC123'\n        }\n    };\n\n    const response = await client.sendEmailWithTemplate(templateMessage);\n    return response;\n}\n```\n\n## ES6 Module Support\n\nUse ES6 imports:\n\n```javascript\nimport * as postmark from 'postmark';\n\nconst serverToken = process.env.POSTMARK_SERVER_TOKEN;\nconst client = new postmark.ServerClient(serverToken);\n\nexport async function sendWelcomeEmail(recipientEmail, userName) {\n    return await client.sendEmailWithTemplate({\n        From: 'welcome@example.com',\n        To: recipientEmail,\n        TemplateAlias: 'welcome-email',\n        TemplateModel: {\n            user_name: userName\n        }\n    });\n}\n```\n\n## Useful Links\n\n- **Official Documentation:** https://postmarkapp.com/developer\n- **API Reference:** https://postmarkapp.com/developer/api/overview\n- **Node.js Library Docs:** https://activecampaign.github.io/postmark.js/\n- **GitHub Repository:** https://github.com/ActiveCampaign/postmark.js\n- **NPM Package:** https://www.npmjs.com/package/postmark\n- **Email API:** https://postmarkapp.com/developer/api/email-api\n- **Templates API:** https://postmarkapp.com/developer/api/templates-api\n- **Webhooks:** https://postmarkapp.com/developer/webhooks/webhooks-overview\n- **Support:** https://postmarkapp.com/support\n\n## Notes\n\n- Always verify sender signatures or domains before sending emails\n- Use the test token `POSTMARK_API_TEST` for development\n- Batch requests can include up to 500 messages (50 MB max)\n- Open tracking requires HTML body\n- Link tracking works in both HTML and text bodies\n- Metadata is included in webhooks and API responses\n- Messages are stored for 45 days by default (configurable up to 365 days)\n- Rate limits apply based on your account plan\n- Always check individual responses in batch operations\n"
  },
  {
    "path": "content/pre-commit/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pre-commit package guide for managing and running multi-language Git hooks in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.5.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pre-commit,git,hooks,linting,formatting,ci\"\n---\n\n# pre-commit Python Package Guide\n\n## Golden Rule\n\nUse `pre-commit` as a Git-hook manager, keep your hook `rev` values pinned to immutable tags or SHAs, and run `pre-commit install` in every clone. Do not point hooks at mutable refs like `HEAD` or `main`; use `pre-commit autoupdate` when you want newer hook versions.\n\n## Install\n\nInstall it into the environment that owns your repo tooling:\n\n```bash\npython -m pip install \"pre-commit==4.5.1\"\n```\n\nIf you want the CLI without managing a virtualenv, the project also publishes a zipapp:\n\n```bash\ncurl -L https://github.com/pre-commit/pre-commit/releases/download/v4.5.1/pre-commit-4.5.1.pyz -o pre-commit.pyz\npython pre-commit.pyz --version\n```\n\n## Initial Setup\n\nCreate a starter config and install the Git hook scripts:\n\n```bash\npre-commit sample-config > .pre-commit-config.yaml\npre-commit install\n```\n\nUseful variants:\n\n```bash\npre-commit install --install-hooks\npre-commit install --hook-type pre-commit --hook-type pre-push\n```\n\n- `install` writes the hook script into `.git/hooks/`.\n- `--install-hooks` eagerly creates hook environments instead of waiting for the first run.\n- If you want `pre-push`, `commit-msg`, or other hook types, install them explicitly or set `default_install_hook_types` in config.\n\n## Config Shape\n\nThe config file is YAML with a top-level `repos:` list. Each repo entry points at a Git repository that contains hook definitions.\n\nMinimal example:\n\n```yaml\nrepos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: vX.Y.Z\n    hooks:\n      - id: check-yaml\n      - id: end-of-file-fixer\n      - id: trailing-whitespace\n```\n\nCommon top-level settings:\n\n- `minimum_pre_commit_version`: require a minimum local `pre-commit` version when you rely on newer features.\n- `default_install_hook_types`: install additional hook types by default.\n- `default_language_version`: set default runtimes such as `python: python3.12`.\n- `default_stages`: restrict hooks to stages like `pre-commit` or `pre-push`.\n- `files` and `exclude`: global include and exclude regexes.\n- `fail_fast`: stop after the first failing hook.\n\nUseful validation commands:\n\n```bash\npre-commit validate-config\npre-commit validate-manifest\n```\n\n## Core Usage\n\nRun hooks against all tracked files:\n\n```bash\npre-commit run --all-files\n```\n\nRun one hook only:\n\n```bash\npre-commit run black --all-files\n```\n\nRun hooks for a specific stage:\n\n```bash\npre-commit run --hook-stage pre-push --all-files\n```\n\nRun against a diff range in CI:\n\n```bash\npre-commit run --from-ref origin/HEAD --to-ref HEAD\n```\n\nUpdate pinned hook revisions in `.pre-commit-config.yaml`:\n\n```bash\npre-commit autoupdate\n```\n\nClean or rebuild cached environments when they drift:\n\n```bash\npre-commit clean\npre-commit gc\npre-commit install-hooks\n```\n\n## Local And Meta Hooks\n\nUse `repo: local` for project-specific commands that are not published as a reusable hook repo:\n\n```yaml\nrepos:\n  - repo: local\n    hooks:\n      - id: mypy\n        name: mypy\n        entry: mypy\n        language: python\n        types: [python]\n        additional_dependencies:\n          - mypy==1.18.2\n```\n\nUse `repo: meta` for hooks that validate your `pre-commit` setup itself:\n\n```yaml\nrepos:\n  - repo: meta\n    hooks:\n      - id: check-hooks-apply\n      - id: check-useless-excludes\n```\n\n`pre-commit try-repo` is useful when testing a hook repo before publishing or before changing your main config:\n\n```bash\npre-commit try-repo ../hook-repo my-hook-id --all-files\n```\n\n## CI, Cache, And Auth Notes\n\n`pre-commit` itself has no API credentials, but it clones hook repositories with Git and caches hook environments on disk.\n\nImportant environment details:\n\n- Cache directory defaults to `~/.cache/pre-commit`.\n- Set `PRE_COMMIT_HOME` to move the cache.\n- `XDG_CACHE_HOME` also affects the default cache location.\n- Private hook repos need normal Git auth to work: SSH keys, Git credential helpers, or tokens embedded through your CI platform's Git configuration.\n- If `pre-commit` runs inside wrappers such as `tox`, proxy and SSH variables may need to be passed through explicitly. The upstream docs call out `http_proxy`, `https_proxy`, `no_proxy`, and `SSH_AUTH_SOCK`.\n\nA common CI pattern is to cache `PRE_COMMIT_HOME` between runs and execute:\n\n```bash\npre-commit run --all-files --show-diff-on-failure\n```\n\n## Common Pitfalls\n\n- Installing the package is not enough. You still need `pre-commit install` in each clone.\n- New hooks should usually be tested with `pre-commit run --all-files`; otherwise only changed files run and broken old files stay hidden.\n- Do not use mutable refs like `HEAD` in `rev`; the project intentionally rejects that pattern.\n- If a hook needs a non-default Git stage, install that hook type and use explicit `stages`.\n- `SKIP=hook_id pre-commit run --all-files` skips one hook temporarily; `git commit --no-verify` skips all hooks and is much easier to abuse.\n- Existing Git hooks are installed in migration mode by default, so old hooks can still run unless you replace them intentionally.\n- When a hook modifies files, `pre-commit` exits non-zero. Re-add the changed files and rerun.\n- Hook environments are cached by config and runtime details. After interpreter upgrades or broken virtualenvs, `pre-commit clean` or `pre-commit gc` often resolves confusing failures.\n\n## Version-Sensitive Notes For 4.5.1\n\n- `4.5.1` fixes `repo: local` hooks that use `language: python` without `additional_dependencies`. If a local Python hook behaves differently on older installs, upgrade first.\n- `4.5.0` adds `pre-commit migrate-config` and `pre-commit validate-config --allow-missing-config`, plus a `check-hooks-apply` improvement that may require `minimum_pre_commit_version: \"4.5.0\"` if you depend on the new behavior.\n- `4.4.0` renamed the `system` and `script` language aliases to `unsupported` and `unsupported_script`. Older examples may still show the deprecated names.\n- Since `3.2.0`, `stages` values should use actual Git hook names like `pre-commit`, `pre-push`, and `pre-merge-commit` instead of older aliases such as `commit` or `push`.\n- `4.x` is stricter about stale patterns than many blog posts. If copied examples conflict with the current docs, prefer the current docs and release notes over third-party snippets.\n"
  },
  {
    "path": "content/prefect/docs/aws/python/DOC.md",
    "content": "---\nname: aws\ndescription: \"Prefect AWS integration for storing AWS credentials in Prefect blocks and creating boto3 sessions inside flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,aws,python,workflow,orchestration,boto3,s3,blocks\"\n---\n\n# Prefect AWS Python Package Guide\n\n## Golden Rule\n\nUse `prefect-aws` as a Prefect integration package for AWS credentials and AWS-backed workflows. Keep writing flows and tasks with core `prefect`; use this package to store AWS connection details in a Prefect block and create `boto3` sessions or service clients inside your flow code.\n\nIf you only need plain AWS SDK access outside Prefect orchestration, start with `boto3` directly.\n\n## Install\n\nInstall the package version this guide covers:\n\n```bash\npython -m pip install \"prefect-aws==0.7.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-aws\npoetry add prefect-aws\n```\n\nIf your project does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-aws\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-aws\npython -c \"import prefect_aws; print(prefect_aws.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you use `prefect-aws` in a flow, make sure:\n\n- the runtime already has valid AWS credentials for the account you want to access\n- the IAM principal has permission for the AWS APIs you call\n- `AWS_DEFAULT_REGION` is set when your flow logic depends on a default region\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nTypical environment variables:\n\n```bash\nexport AWS_ACCESS_KEY_ID=\"AKIA...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_SESSION_TOKEN=\"...\"         # only for temporary credentials\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nThere is no separate long-lived `prefect-aws` client to initialize first. The common starting point is an `AwsCredentials` block.\n\n## Initialize An AWS Credentials Block\n\nCreate an `AwsCredentials` block from environment variables when your flow needs to authenticate to AWS.\n\n```python\nimport os\n\nfrom prefect_aws import AwsCredentials\n\n\naws_credentials = AwsCredentials(\n    aws_access_key_id=os.environ[\"AWS_ACCESS_KEY_ID\"],\n    aws_secret_access_key=os.environ[\"AWS_SECRET_ACCESS_KEY\"],\n    aws_session_token=os.getenv(\"AWS_SESSION_TOKEN\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\n```\n\nUse this direct-instantiation pattern when credentials already come from environment variables or another secret manager and you do not need to persist a named Prefect block yet.\n\n## Save And Reuse A Named Block\n\nWhen several flows or deployments should share the same AWS connection definition, save the block in Prefect and load it by name later.\n\n```python\nimport os\n\nfrom prefect_aws import AwsCredentials\n\n\naws_credentials = AwsCredentials(\n    aws_access_key_id=os.environ[\"AWS_ACCESS_KEY_ID\"],\n    aws_secret_access_key=os.environ[\"AWS_SECRET_ACCESS_KEY\"],\n    aws_session_token=os.getenv(\"AWS_SESSION_TOKEN\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\n\naws_credentials.save(\"aws-dev\", overwrite=True)\n```\n\nLoad that block later:\n\n```python\nfrom prefect_aws import AwsCredentials\n\n\naws_credentials = AwsCredentials.load(\"aws-dev\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they require a working Prefect API configuration\n- direct instantiation of `AwsCredentials(...)` does not require Prefect Cloud or a self-hosted server\n\n## Create A Boto3 Session And Call AWS APIs\n\nThe most direct workflow is to turn the saved or in-memory block into a `boto3` session, then use normal AWS service clients.\n\n```python\nimport os\n\nfrom prefect_aws import AwsCredentials\n\n\naws_credentials = AwsCredentials.load(\"aws-dev\")\nsession = aws_credentials.get_boto3_session()\n\ns3 = session.client(\"s3\")\n\ns3.put_object(\n    Bucket=os.environ[\"AWS_S3_BUCKET\"],\n    Key=\"healthcheck.txt\",\n    Body=b\"ok\\n\",\n)\n\nresponse = s3.get_object(\n    Bucket=os.environ[\"AWS_S3_BUCKET\"],\n    Key=\"healthcheck.txt\",\n)\n\nprint(response[\"Body\"].read().decode(\"utf-8\"))\n```\n\nThis pattern is a good default when you already know the AWS service you need and want the rest of the code to look like standard `boto3`.\n\n## Use Saved AWS Credentials Inside A Flow\n\nLoad the block inside tasks or flows where the AWS client is actually needed.\n\n```python\nimport os\n\nfrom prefect import flow, task\nfrom prefect_aws import AwsCredentials\n\n\n@task\ndef write_marker() -> None:\n    aws_credentials = AwsCredentials.load(\"aws-dev\")\n    session = aws_credentials.get_boto3_session()\n    s3 = session.client(\"s3\")\n    s3.put_object(\n        Bucket=os.environ[\"AWS_S3_BUCKET\"],\n        Key=\"prefect/demo.txt\",\n        Body=b\"written from Prefect\\n\",\n    )\n\n\n@task\ndef read_marker() -> str:\n    aws_credentials = AwsCredentials.load(\"aws-dev\")\n    session = aws_credentials.get_boto3_session()\n    s3 = session.client(\"s3\")\n    response = s3.get_object(\n        Bucket=os.environ[\"AWS_S3_BUCKET\"],\n        Key=\"prefect/demo.txt\",\n    )\n    return response[\"Body\"].read().decode(\"utf-8\")\n\n\n@flow(log_prints=True)\ndef aws_demo() -> None:\n    write_marker()\n    print(read_marker())\n\n\nif __name__ == \"__main__\":\n    aws_demo()\n```\n\nThis is usually enough for S3 checks, metadata reads, queue publishing, secrets lookups, or other service calls where Prefect orchestrates the workflow and `boto3` does the AWS API work.\n\n## Save A Reusable S3 Block Definition\n\nIf several flows should refer to the same bucket definition, save an `S3Bucket` block alongside your credentials.\n\n```python\nimport os\n\nfrom prefect_aws import AwsCredentials\nfrom prefect_aws.s3 import S3Bucket\n\n\naws_credentials = AwsCredentials.load(\"aws-dev\")\n\ns3_bucket = S3Bucket(\n    bucket_name=os.environ[\"AWS_S3_BUCKET\"],\n    credentials=aws_credentials,\n)\n\ns3_bucket.save(\"app-bucket\", overwrite=True)\n```\n\nUse this pattern when the bucket itself is part of your reusable deployment configuration, not just an input string passed to one function.\n\n## Common Pitfalls\n\n- Installing `prefect-aws` does not replace core `prefect`; you still use `prefect` for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving or loading blocks by name requires a reachable Prefect API. Direct instantiation does not.\n- `prefect-aws` does not bypass AWS IAM. A valid key is not enough if the principal lacks permission for the service call you make.\n- If you use temporary AWS credentials, include `AWS_SESSION_TOKEN` or equivalent session-token configuration.\n- The environment that runs the deployment or worker needs both the Python package and AWS credentials, not just the machine where you registered the flow.\n- Keep credentials out of flow source. Prefer environment variables, your platform secret manager, or Prefect blocks.\n\n## Version Notes For `prefect-aws` 0.7.5\n\n- This guide covers the PyPI package version `0.7.5`.\n- Treat `prefect-aws` as an integration layered on top of core Prefect instead of a standalone workflow framework.\n- Older Prefect examples may use pre-worker orchestration patterns; for current orchestration, prefer current Prefect flows, deployments, work pools, workers, and blocks.\n\n## Official Sources\n\n- Prefect docs root: `https://docs.prefect.io/v3/`\n- Prefect integrations root: `https://docs.prefect.io/integrations/`\n- Prefect blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Prefect settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Prefect AWS integration docs: `https://docs.prefect.io/integrations/prefect-aws/`\n- PyPI package page: `https://pypi.org/project/prefect-aws/`\n"
  },
  {
    "path": "content/prefect/docs/azure/python/DOC.md",
    "content": "---\nname: azure\ndescription: \"Prefect Azure integration for storing Azure Blob Storage credentials in Prefect blocks and creating Blob Storage clients inside flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,azure,python,workflow,orchestration,blob-storage,blocks\"\n---\n\n# Prefect Azure Python Package Guide\n\n## Golden Rule\n\nUse `prefect-azure` as a Prefect integration package for Azure-backed workflows. Keep writing flows and tasks with core `prefect`; use this package to store Azure connection details in a Prefect block and create Azure Blob Storage clients inside your flow code.\n\nIf you only need the raw Azure SDK outside Prefect orchestration, start with the Azure SDK directly.\n\n## Install\n\nInstall the package version this guide covers:\n\n```bash\npython -m pip install \"prefect-azure==0.4.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-azure\npoetry add prefect-azure\n```\n\nIf your project does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-azure\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-azure\npython -c \"import prefect_azure; print(prefect_azure.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you use `prefect-azure` in a flow, make sure:\n\n- the runtime already has access to the Azure Storage account you want to use\n- the storage connection string or equivalent credential grants permission for the container and blob operations you call\n- the target Blob Storage container already exists\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nExample environment variables:\n\n```bash\nexport AZURE_STORAGE_CONNECTION_STRING=\"DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net\"\nexport AZURE_STORAGE_CONTAINER=\"prefect-artifacts\"\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nThere is no separate long-lived `prefect-azure` client to initialize first. A practical starting point is an `AzureBlobStorageCredentials` block.\n\n## Initialize Azure Blob Storage Credentials\n\nCreate an `AzureBlobStorageCredentials` block from environment variables when your flow needs to authenticate to Azure Blob Storage.\n\n```python\nimport os\n\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\nazure_credentials = AzureBlobStorageCredentials(\n    connection_string=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n)\n```\n\nUse this direct-instantiation pattern when credentials already come from environment variables or another secret manager and you do not need to persist a named Prefect block yet.\n\n## Save And Reuse A Named Block\n\nWhen several flows or deployments should share the same Azure connection definition, save the block in Prefect and load it by name later.\n\n```python\nimport os\n\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\nazure_credentials = AzureBlobStorageCredentials(\n    connection_string=os.environ[\"AZURE_STORAGE_CONNECTION_STRING\"],\n)\n\nazure_credentials.save(\"azure-blob-creds\", overwrite=True)\n```\n\nLoad that block later:\n\n```python\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\nazure_credentials = AzureBlobStorageCredentials.load(\"azure-blob-creds\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they require a working Prefect API configuration\n- direct instantiation of `AzureBlobStorageCredentials(...)` does not require Prefect Cloud or a self-hosted server\n\n## Create A Blob Service Client And Read Or Write A Blob\n\nThe most direct workflow is to load the saved or in-memory block, turn it into a Blob Storage client, then use normal Azure Blob Storage client calls.\n\n```python\nimport os\n\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\nazure_credentials = AzureBlobStorageCredentials.load(\"azure-blob-creds\")\nblob_service_client = azure_credentials.get_client()\n\ncontainer_client = blob_service_client.get_container_client(\n    os.environ[\"AZURE_STORAGE_CONTAINER\"],\n)\n\ncontainer_client.upload_blob(\n    name=\"healthcheck.txt\",\n    data=b\"ok\\n\",\n    overwrite=True,\n)\n\ncontent = container_client.download_blob(\"healthcheck.txt\").readall()\nprint(content.decode(\"utf-8\"))\n```\n\nThis pattern is a good default when you want Prefect to manage credentials and orchestration while the actual storage operations still use the normal Azure client surface.\n\n## Use Saved Azure Credentials Inside A Flow\n\nLoad the block inside tasks or flows where the Azure client is actually needed.\n\n```python\nimport os\n\nfrom prefect import flow, task\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\n@task\ndef upload_marker() -> None:\n    azure_credentials = AzureBlobStorageCredentials.load(\"azure-blob-creds\")\n    blob_service_client = azure_credentials.get_client()\n    container_client = blob_service_client.get_container_client(\n        os.environ[\"AZURE_STORAGE_CONTAINER\"],\n    )\n    container_client.upload_blob(\n        name=\"prefect/demo.txt\",\n        data=b\"written from Prefect\\n\",\n        overwrite=True,\n    )\n\n\n@task\ndef read_marker() -> str:\n    azure_credentials = AzureBlobStorageCredentials.load(\"azure-blob-creds\")\n    blob_service_client = azure_credentials.get_client()\n    container_client = blob_service_client.get_container_client(\n        os.environ[\"AZURE_STORAGE_CONTAINER\"],\n    )\n    return container_client.download_blob(\"prefect/demo.txt\").readall().decode(\"utf-8\")\n\n\n@flow(log_prints=True)\ndef azure_blob_demo() -> None:\n    upload_marker()\n    print(read_marker())\n\n\nif __name__ == \"__main__\":\n    azure_blob_demo()\n```\n\nThis is usually enough for simple artifact exchange, health checks, marker files, or other blob-backed workflow state where Prefect orchestrates the workflow and Azure Blob Storage holds the data.\n\n## Save A Reusable Container Block Definition\n\nIf several flows should refer to the same container definition, save an `AzureBlobStorageContainer` block alongside your credentials.\n\n```python\nimport os\n\nfrom prefect_azure.blob_storage import AzureBlobStorageContainer\nfrom prefect_azure.credentials import AzureBlobStorageCredentials\n\n\nazure_credentials = AzureBlobStorageCredentials.load(\"azure-blob-creds\")\n\nazure_container = AzureBlobStorageContainer(\n    container_name=os.environ[\"AZURE_STORAGE_CONTAINER\"],\n    credentials=azure_credentials,\n)\n\nazure_container.save(\"app-container\", overwrite=True)\n```\n\nUse this pattern when the container itself is part of reusable deployment configuration, not just a string passed into one function.\n\n## Common Pitfalls\n\n- Installing `prefect-azure` does not replace core `prefect`; you still use `prefect` for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving or loading blocks by name requires a reachable Prefect API. Direct instantiation does not.\n- `prefect-azure` does not bypass Azure RBAC or storage account permissions. A valid connection string still needs the right permissions for the blob operations you call.\n- The environment that runs the deployment or worker needs both the Python package and Azure access, not just the machine where you registered the flow.\n- Keep connection strings and other Azure secrets out of flow source. Prefer environment variables, your platform secret manager, or Prefect blocks.\n- Older Prefect examples may use agent-based orchestration patterns. For current orchestration, prefer current Prefect flows, deployments, work pools, workers, and blocks.\n\n## Version Notes For `prefect-azure` 0.4.9\n\n- This guide covers the PyPI package version `0.4.9`.\n- Treat `prefect-azure` as an integration layered on top of core Prefect instead of a standalone workflow framework.\n- Azure service behavior and storage account configuration are versioned separately from the Python integration package, so pin the package version your project expects and manage Azure-side compatibility independently.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Package integration docs: `https://docs.prefect.io/integrations/prefect-azure/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Python reference root: `https://reference.prefect.io/prefect_azure/`\n- PyPI package page: `https://pypi.org/project/prefect-azure/`\n"
  },
  {
    "path": "content/prefect/docs/databricks/python/DOC.md",
    "content": "---\nname: databricks\ndescription: \"Prefect Databricks integration for storing Databricks credentials and submitting Databricks Jobs runs from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,databricks,python,workflow,orchestration,jobs,blocks\"\n---\n\n# Prefect Databricks Python Package Guide\n\n## Golden Rule\n\nUse `prefect-databricks` as a Prefect integration package for Databricks Jobs workflows. Keep writing flows and tasks with core `prefect`; use this package to hold Databricks credentials in a Prefect block and to submit Databricks job runs from a flow.\n\nIf you only need a general Databricks SDK client outside Prefect orchestration, this package is usually not the right starting point.\n\n## Install\n\nInstall the integration version this guide covers:\n\n```bash\npython -m pip install \"prefect-databricks==0.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-databricks\npoetry add prefect-databricks\n```\n\nIf your project does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-databricks\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-databricks\npython -c \"import prefect_databricks; print(prefect_databricks.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you call Databricks from a Prefect flow, make sure:\n\n- your Databricks workspace is reachable from the environment running the flow or worker\n- you have a Databricks personal access token or equivalent workspace credential\n- the notebook path, cluster, or Databricks job you reference already exists\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nExample environment variables:\n\n```bash\nexport DATABRICKS_INSTANCE=\"dbc-1234567890123456.cloud.databricks.com\"\nexport DATABRICKS_TOKEN=\"dapi_...\"\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nThere is no separate long-lived `prefect-databricks` client you need to initialize first. The common entry point is a credentials block.\n\n## Initialize A Databricks Credentials Block\n\nCreate a `DatabricksCredentials` block from environment variables when you want flow code to authenticate to your Databricks workspace.\n\n```python\nimport os\n\nfrom prefect_databricks import DatabricksCredentials\n\n\ndatabricks_credentials = DatabricksCredentials(\n    databricks_instance=os.environ[\"DATABRICKS_INSTANCE\"],\n    token=os.environ[\"DATABRICKS_TOKEN\"],\n)\n```\n\nUse this direct-instantiation pattern when your credentials already come from environment variables or another secret manager and you do not need to persist a named Prefect block yet.\n\n## Save And Reuse A Named Block\n\nWhen several flows or deployments should share the same Databricks connection definition, save the block in Prefect and load it by name later.\n\n```python\nimport os\n\nfrom prefect_databricks import DatabricksCredentials\n\n\ndatabricks_credentials = DatabricksCredentials(\n    databricks_instance=os.environ[\"DATABRICKS_INSTANCE\"],\n    token=os.environ[\"DATABRICKS_TOKEN\"],\n)\n\ndatabricks_credentials.save(\"databricks-dev\", overwrite=True)\n```\n\nLoad the block inside flow code:\n\n```python\nfrom prefect_databricks import DatabricksCredentials\n\n\ndatabricks_credentials = DatabricksCredentials.load(\"databricks-dev\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they require a working Prefect API configuration\n- direct instantiation of `DatabricksCredentials(...)` does not require Prefect Cloud or a self-hosted server\n\n## Submit A One-Time Databricks Job Run\n\nThe most practical workflow is to load a credentials block, then submit a Databricks Jobs run from a Prefect flow and wait for completion.\n\n```python\nfrom prefect import flow\nfrom prefect_databricks import DatabricksCredentials\nfrom prefect_databricks.flows import jobs_runs_submit_and_wait_for_completion\n\n\n@flow(log_prints=True)\ndef run_databricks_notebook() -> None:\n    databricks_credentials = DatabricksCredentials.load(\"databricks-dev\")\n\n    jobs_runs_submit_and_wait_for_completion(\n        databricks_credentials=databricks_credentials,\n        run_name=\"prefect-databricks-demo\",\n        tasks=[\n            {\n                \"task_key\": \"run-demo-notebook\",\n                \"existing_cluster_id\": \"1234-567890-abcd123\",\n                \"notebook_task\": {\n                    \"notebook_path\": \"/Shared/prefect-demo\",\n                    \"base_parameters\": {\n                        \"run_date\": \"2026-03-13\",\n                    },\n                },\n            }\n        ],\n    )\n\n\nif __name__ == \"__main__\":\n    run_databricks_notebook()\n```\n\nWhy this pattern is useful:\n\n- it keeps Databricks credentials out of the flow source\n- it uses a normal Prefect flow entry point, so you can run it locally or turn it into a deployment later\n- it maps closely to the Databricks Jobs `runs/submit` workflow when you want a one-off run instead of a permanently scheduled Databricks job\n\nIf you already manage compute in Databricks, use an existing cluster ID as shown above. If your team submits ephemeral runs instead, build the task payload with the cluster settings required by the Databricks Jobs API for your workspace.\n\n## Use The Flow In A Deployment\n\n`prefect-databricks` does not change the standard Prefect deployment model. After the flow works locally, deploy it the same way as any other Prefect flow.\n\n```python\nif __name__ == \"__main__\":\n    run_databricks_notebook.deploy(\n        name=\"daily-databricks-run\",\n        work_pool_name=\"docker-pool\",\n        image=\"ghcr.io/acme/prefect-databricks:latest\",\n        push=False,\n        cron=\"0 6 * * *\",\n    )\n```\n\nMake sure the worker image or runtime environment includes both your flow code and `prefect-databricks`.\n\n## Common Pitfalls\n\n- Installing `prefect-databricks` does not replace `prefect`; you still use core Prefect for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving a block with `save(...)` and loading it by name with `load(...)` requires a reachable Prefect API.\n- Databricks credentials belong in environment variables, secret management, or Prefect blocks, not hard-coded in source.\n- The Databricks notebook path, existing cluster ID, and job payload fields must match real resources in your Databricks workspace.\n- The Python package version is separate from Databricks Runtime versions and from any workspace-side Jobs API changes.\n- Older Prefect examples may refer to Prefect 2 agent workflows. For current orchestration patterns, prefer Prefect 3 deployments, work pools, workers, and blocks.\n\n## Version Notes For `prefect-databricks` 0.4.0\n\n- This guide covers the PyPI package version `0.4.0`.\n- Treat `prefect-databricks` as an integration layered on top of Prefect, not as a standalone workflow framework.\n- Pin the integration version your project expects, then manage Databricks workspace compatibility separately through your own workspace configuration and Jobs payloads.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Package integration docs: `https://docs.prefect.io/integrations/prefect-databricks/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Python reference root: `https://reference.prefect.io/prefect_databricks/`\n- PyPI package page: `https://pypi.org/project/prefect-databricks/`\n"
  },
  {
    "path": "content/prefect/docs/dbt/python/DOC.md",
    "content": "---\nname: dbt\ndescription: \"Prefect dbt integration for running dbt Core commands with Prefect observability and triggering dbt Cloud jobs from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.20\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,dbt,python,workflow,orchestration,analytics,blocks\"\n---\n\n# Prefect dbt Python Package Guide\n\n## Golden Rule\n\nUse `prefect-dbt` as the Prefect integration layer for dbt. Keep writing orchestration with core `prefect`, then use:\n\n- `PrefectDbtRunner` for dbt Core commands in `prefect-dbt` 0.7.0 and later\n- `DbtCloudCredentials`, `DbtCloudJob`, and `run_dbt_cloud_job` for dbt Cloud jobs\n\nIf you only need plain dbt CLI execution with no Prefect flows, blocks, logs, or deployments, run dbt directly instead of adding Prefect.\n\n## Install\n\nIf your project already pins Prefect separately, install the integration directly:\n\n```bash\npython -m pip install \"prefect-dbt==0.7.20\"\n```\n\nThe official Prefect docs also support installing the matching extra, which installs a compatible `prefect` and `prefect-dbt` pair:\n\n```bash\npython -m pip install \"prefect[dbt]\"\n```\n\nFor dbt Core profiles that need one of the published extras:\n\n```bash\npython -m pip install \"prefect-dbt[snowflake]\"\npython -m pip install \"prefect-dbt[bigquery]\"\npython -m pip install \"prefect-dbt[postgres]\"\n```\n\nOr install all published extras:\n\n```bash\npython -m pip install -U \"prefect-dbt[all_extras]\"\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-dbt\npython -c \"import prefect_dbt; print(prefect_dbt.__file__)\"\n```\n\n## Prerequisites And Environment\n\n`prefect-dbt` requires Python 3.10 or newer.\n\nFor dbt Core runs, make sure the runtime already has:\n\n- a real dbt project directory containing `dbt_project.yml`\n- a valid `profiles.yml` or equivalent dbt profile configuration\n- the warehouse adapter your dbt project uses\n\nFor dbt Cloud runs, collect:\n\n- a dbt Cloud service token\n- the dbt Cloud account ID\n- the dbt Cloud job ID you want to trigger\n\nIf you want to save and later load Prefect blocks by name, configure Prefect too:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nRegister the integration's block types so they appear in the Prefect UI:\n\n```bash\nprefect block register -m prefect_dbt\n```\n\n## Run dbt Core Commands With `PrefectDbtRunner`\n\nFor `prefect-dbt` 0.7.0 and later, `PrefectDbtRunner` is the current interface for dbt Core execution.\n\n```python\nfrom prefect import flow\nfrom prefect_dbt import PrefectDbtRunner, PrefectDbtSettings\n\n\n@flow(log_prints=True)\ndef run_dbt_build() -> None:\n    runner = PrefectDbtRunner(\n        settings=PrefectDbtSettings(\n            project_dir=\"analytics\",\n            profiles_dir=\".dbt\",\n        )\n    )\n    runner.invoke([\"build\"])\n\n\nif __name__ == \"__main__\":\n    run_dbt_build()\n```\n\nWhat this gives you:\n\n- `invoke(...)` accepts the same argument style as dbt Core's `DbtRunner.invoke(...)`\n- each dbt node is reflected as a Prefect task when you call `.invoke()` inside a flow or task\n- dbt node logs show up in Prefect with normal log-level filtering\n\nIf your runtime already sets dbt environment variables, `PrefectDbtSettings` can be omitted and dbt defaults apply.\n\n## Control dbt Settings And Logging\n\n`PrefectDbtSettings` automatically reads `DBT_`-prefixed environment variables that affect `PrefectDbtRunner`.\n\nTypical environment variables:\n\n```bash\nexport DBT_PROFILES_DIR=\"$PWD/.dbt\"\nexport DBT_LOG_LEVEL=\"warn\"\n```\n\nYou can also override settings in code:\n\n```python\nfrom dbt_common.events.base_types import EventLevel\nfrom prefect import flow\nfrom prefect_dbt import PrefectDbtRunner, PrefectDbtSettings\n\n\n@flow\ndef run_dbt_models() -> None:\n    PrefectDbtRunner(\n        settings=PrefectDbtSettings(\n            project_dir=\"analytics\",\n            profiles_dir=\".dbt\",\n            log_level=EventLevel.ERROR,\n        )\n    ).invoke([\"run\", \"--select\", \"marts.finance\"])\n\n\nif __name__ == \"__main__\":\n    run_dbt_models()\n```\n\nBy default, dbt uses Prefect's logging level. Use `DBT_LOG_LEVEL`, `PrefectDbtSettings.log_level`, or dbt CLI flags when you need stricter filtering.\n\n## Handle Failures Deliberately\n\nBy default, dbt node failures raise an exception and fail the surrounding flow or task. If you want the run result without failing the flow immediately, set `raise_on_failure=False`.\n\n```python\nfrom prefect import flow\nfrom prefect_dbt import PrefectDbtRunner\n\n\n@flow\ndef run_dbt_without_failing_flow():\n    result = PrefectDbtRunner(\n        raise_on_failure=False,\n    ).invoke([\"build\"])\n    return result\n```\n\nUse this sparingly. It is useful when your flow needs to inspect the dbt result and decide what to do next instead of failing fast.\n\n## Use Prefect Templating In `profiles.yml`\n\n`PrefectDbtRunner` supports templating Prefect blocks and variables inside `profiles.yml`. This is useful when you want the same dbt project to resolve different credentials or targets at runtime.\n\nExample:\n\n```yaml\nexample:\n  outputs:\n    dev:\n      type: duckdb\n      path: dev.duckdb\n      threads: 1\n\n    prod:\n      type: snowflake\n      account: \"{{ prefect.blocks.snowflake-credentials.warehouse-access.account }}\"\n      user: \"{{ prefect.blocks.snowflake-credentials.warehouse-access.user }}\"\n      password: \"{{ prefect.blocks.snowflake-credentials.warehouse-access.password }}\"\n      database: \"{{ prefect.blocks.snowflake-connector.prod-connector.database }}\"\n      schema: \"{{ prefect.blocks.snowflake-connector.prod-connector.schema }}\"\n      warehouse: \"{{ prefect.blocks.snowflake-connector.prod-connector.warehouse }}\"\n      threads: 4\n\n  target: \"{{ prefect.variables.target }}\"\n```\n\nThis pattern only works when the runtime can resolve the referenced Prefect blocks and variables.\n\n## Save dbt Cloud Credentials And Job Blocks\n\nFor dbt Cloud, the practical setup is:\n\n1. Save a `DbtCloudCredentials` block with your service token and account ID.\n2. Save a `DbtCloudJob` block for the job you want Prefect to run.\n3. Load that job block inside a flow and call `run_dbt_cloud_job(...)`.\n\nExample environment variables:\n\n```bash\nexport DBT_CLOUD_API_KEY=\"replace-me\"\nexport DBT_CLOUD_ACCOUNT_ID=\"123456\"\nexport DBT_CLOUD_JOB_ID=\"7891011\"\n```\n\nSave the credentials block:\n\n```python\nimport os\n\nfrom prefect_dbt.cloud import DbtCloudCredentials\n\n\nDbtCloudCredentials(\n    api_key=os.environ[\"DBT_CLOUD_API_KEY\"],\n    account_id=os.environ[\"DBT_CLOUD_ACCOUNT_ID\"],\n).save(\"dbt-cloud-creds\")\n```\n\nSave the job block:\n\n```python\nimport os\n\nfrom prefect_dbt.cloud import DbtCloudCredentials, DbtCloudJob\n\n\ndbt_cloud_credentials = DbtCloudCredentials.load(\"dbt-cloud-creds\")\n\nDbtCloudJob(\n    dbt_cloud_credentials=dbt_cloud_credentials,\n    job_id=os.environ[\"DBT_CLOUD_JOB_ID\"],\n).save(\"daily-models-job\")\n```\n\n## Run A dbt Cloud Job From A Flow\n\nThe official integration docs show `run_dbt_cloud_job(...)` in an async flow:\n\n```python\nimport asyncio\n\nfrom prefect import flow\nfrom prefect_dbt.cloud import DbtCloudJob\nfrom prefect_dbt.cloud.jobs import run_dbt_cloud_job\n\n\n@flow\nasync def run_dbt_job_flow():\n    result = await run_dbt_cloud_job(\n        dbt_cloud_job=await DbtCloudJob.load(\"daily-models-job\"),\n        targeted_retries=0,\n    )\n    return await result\n\n\nif __name__ == \"__main__\":\n    asyncio.run(run_dbt_job_flow())\n```\n\nUse `targeted_retries` when you want Prefect to retry unsuccessful nodes from the dbt Cloud job.\n\n## Common Pitfalls\n\n- `prefect-dbt` does not replace core `prefect`; you still use Prefect for `@flow`, deployments, work pools, workers, and block storage.\n- `PrefectDbtRunner` is the current dbt Core interface for `prefect-dbt` 0.7.x. Older examples built around `DbtCoreOperation` apply to `0.6.6` and earlier.\n- Saving or loading blocks by name requires a reachable Prefect API. Local inline construction does not.\n- For dbt Core, the worker or runtime needs the dbt project, the right adapter, and a valid profile. Installing only `prefect-dbt` is not enough.\n- `prefect block register -m prefect_dbt` registers block types for UI use; it does not create saved blocks by itself.\n- If you depend on `profiles.yml` templating, the referenced Prefect blocks and variables must already exist in the active workspace.\n- dbt failures raise by default. Set `raise_on_failure=False` only when the surrounding flow intentionally handles partial failure.\n\n## Version Notes For `prefect-dbt` 0.7.20\n\n- This guide covers PyPI package version `0.7.20`, released on March 5, 2026.\n- PyPI lists `prefect-dbt 0.7.20` as requiring Python 3.10 or newer.\n- PyPI publishes these extras for this package: `snowflake`, `bigquery`, `postgres`, and `all-extras`.\n- The current official integration docs distinguish `prefect-dbt 0.7.0 and later` from `0.6.6 and earlier`; for `0.7.20`, prefer `PrefectDbtRunner` and the current dbt Cloud flow APIs.\n\n## Official Sources Used\n\n- Prefect integrations overview: `https://docs.prefect.io/integrations/use-integrations`\n- Prefect dbt integration docs: `https://docs.prefect.io/integrations/prefect-dbt/`\n- Prefect dbt runner API reference: `https://docs.prefect.io/integrations/prefect-dbt/api-ref/prefect_dbt-core-runner`\n- Prefect settings reference: `https://docs.prefect.io/v3/api-ref/settings-ref`\n- PyPI package page: `https://pypi.org/project/prefect-dbt/`\n"
  },
  {
    "path": "content/prefect/docs/docker/python/DOC.md",
    "content": "---\nname: docker\ndescription: \"Prefect Docker integration for Docker work pools, image builds, registry credentials, and container tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,docker,python,workflow,orchestration,deployments,workers,containers\"\n---\n\n# Prefect Docker Python Package Guide\n\n## Golden Rule\n\nUse `prefect-docker` as the Docker integration layer for Prefect 3. Keep flow logic in core `prefect`; install this package when your deployments or flow code need Docker infrastructure such as Docker work pools, image build and push steps, Docker host and registry blocks, or container and image tasks.\n\nPrefect's integration docs recommend installing Docker support with the `prefect[docker]` extra so that `prefect` and `prefect-docker` stay compatible.\n\n## Install\n\nRecommended install:\n\n```bash\npython -m pip install \"prefect[docker]\"\n```\n\nUpgrade both packages together:\n\n```bash\npython -m pip install -U \"prefect[docker]\"\n```\n\nIf you need to pin the integration package itself:\n\n```bash\npython -m pip install \"prefect-docker==0.7.1\"\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-docker\npython -c \"import prefect_docker; print(prefect_docker.__file__)\"\n```\n\nPyPI lists `prefect-docker 0.7.1` as the current release covered here, and the package requires Python 3.10 or later.\n\n## Prerequisites And Environment\n\nBefore using the integration:\n\n- Docker must be installed and running.\n- `PREFECT_API_URL` must point at Prefect Cloud or a self-hosted Prefect server if you want to create deployments, run workers, or save and load named blocks.\n- `PREFECT_API_KEY` is also required for Prefect Cloud.\n\nTypical environment variables:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n\nexport DOCKER_REGISTRY_USERNAME=\"your-username\"\nexport DOCKER_REGISTRY_PASSWORD=\"your-password-or-token\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\n## Deploy A Flow To A Docker Work Pool\n\nCreate a Docker work pool:\n\n```bash\nprefect work-pool create \"docker-pool\" --type docker\n```\n\nStart a worker for that pool:\n\n```bash\nprefect worker start --pool \"docker-pool\"\n```\n\nThen register a deployment from Python:\n\n```python\nfrom prefect import flow\n\n\n@flow(log_prints=True)\ndef hello(name: str = \"world\") -> None:\n    print(f\"Hello, {name}!\")\n\n\nif __name__ == \"__main__\":\n    hello.deploy(\n        name=\"hello-docker\",\n        work_pool_name=\"docker-pool\",\n        image=\"docker.io/your-user/prefect-hello:latest\",\n        push=False,\n    )\n```\n\nTrigger it:\n\n```bash\nprefect deployment run \"hello/hello-docker\"\n```\n\nWhat matters here:\n\n- Keep the worker process running or scheduled runs will not start.\n- `push=False` is useful for local development when the worker can use the same local Docker daemon.\n- For remote workers or shared infrastructure, push the image to a registry the worker can pull from.\n\n## Customize The Image Build With `DockerImage`\n\nIf you want to control the Dockerfile or build settings, pass `prefect.docker.DockerImage` to `.deploy()`:\n\n```python\nfrom prefect import flow\nfrom prefect.docker import DockerImage\n\n\n@flow(log_prints=True)\ndef hello(name: str = \"world\") -> None:\n    print(f\"Hello, {name}!\")\n\n\nif __name__ == \"__main__\":\n    hello.deploy(\n        name=\"hello-docker\",\n        work_pool_name=\"docker-pool\",\n        image=DockerImage(\n            name=\"docker.io/your-user/prefect-hello\",\n            tag=\"2026-03-13\",\n            dockerfile=\"Dockerfile\",\n        ),\n        push=True,\n    )\n```\n\nIf you leave `dockerfile` as `\"auto\"` or omit it, Prefect generates a Dockerfile for the deployment image.\n\n## Configure Docker Host And Registry Credentials\n\n`prefect-docker` exposes separate blocks for the Docker daemon and for registry authentication.\n\nCreate and save reusable blocks:\n\n```python\nimport os\n\nfrom prefect_docker import DockerHost, DockerRegistryCredentials\n\n\ndocker_host = DockerHost(base_url=\"unix:///var/run/docker.sock\")\ndocker_host.save(\"local-docker\", overwrite=True)\n\ndocker_registry_credentials = DockerRegistryCredentials(\n    username=os.environ[\"DOCKER_REGISTRY_USERNAME\"],\n    password=os.environ[\"DOCKER_REGISTRY_PASSWORD\"],\n    registry_url=\"registry.hub.docker.com\",\n)\ndocker_registry_credentials.save(\"dockerhub-creds\", overwrite=True)\n```\n\nUse them directly:\n\n```python\nfrom prefect_docker import DockerHost, DockerRegistryCredentials\n\n\ndocker_host = DockerHost.load(\"local-docker\")\ndocker_registry_credentials = DockerRegistryCredentials.load(\"dockerhub-creds\")\n\nwith docker_host.get_client() as client:\n    docker_registry_credentials.login(client)\n    print(client.ping())\n```\n\nIf you do not set `base_url`, `DockerHost` configures the client from the Docker environment.\n\n## Run Docker Image And Container Tasks Inside A Flow\n\nUse the built-in tasks when a flow needs to pull an image, create a container, read logs, and clean up:\n\n```python\nfrom prefect import flow\nfrom prefect_docker import DockerHost\nfrom prefect_docker.containers import (\n    create_docker_container,\n    get_docker_container_logs,\n    remove_docker_container,\n    start_docker_container,\n)\nfrom prefect_docker.images import pull_docker_image\n\n\n@flow(log_prints=True)\ndef run_container() -> str:\n    docker_host = DockerHost(base_url=\"unix:///var/run/docker.sock\")\n\n    pull_docker_image(\n        repository=\"alpine\",\n        tag=\"3.20\",\n        docker_host=docker_host,\n    )\n\n    container = create_docker_container(\n        image=\"alpine:3.20\",\n        command=[\"/bin/sh\", \"-c\", \"echo hello from prefect-docker\"],\n        docker_host=docker_host,\n    )\n    start_docker_container(container_id=container.id, docker_host=docker_host)\n    logs = get_docker_container_logs(container_id=container.id, docker_host=docker_host)\n    remove_docker_container(container_id=container.id, docker_host=docker_host, force=True)\n    return logs.strip()\n\n\nif __name__ == \"__main__\":\n    print(run_container())\n```\n\nIf the registry requires authentication, pass a `DockerRegistryCredentials` block to `pull_docker_image(..., docker_registry_credentials=...)`.\n\n## Use `prefect-docker` In `prefect.yaml`\n\nThe package also provides deployment build and push steps for `prefect.yaml`:\n\n```yaml\nbuild:\n  - prefect_docker.deployments.steps.build_docker_image:\n      id: build-image\n      requires: prefect-docker\n      image_name: docker.io/your-user/prefect-hello\n      tag: latest\n      dockerfile: auto\n\npush:\n  - prefect_docker.deployments.steps.push_docker_image:\n      requires: prefect-docker\n      image_name: \"{{ build-image.image_name }}\"\n      tag: \"{{ build-image.tag }}\"\n      credentials: \"{{ prefect.blocks.docker-registry-credentials.dockerhub-creds }}\"\n```\n\nThis is the right pattern when your deployment workflow already uses `prefect.yaml` instead of `.deploy()` from Python.\n\n## Common Pitfalls\n\n- `prefect-docker` does not replace core `prefect`; you still write flows, deployments, and workers with Prefect itself.\n- Docker must be reachable from the environment where the worker or flow code runs. A deployment can register successfully even if the runtime cannot talk to the Docker daemon later.\n- `push=False` only works when the worker can use the same local image. Remote Docker workers need a registry-accessible image.\n- Loading blocks with `DockerHost.load(...)` or `DockerRegistryCredentials.load(...)` requires a working Prefect API connection.\n- If you omit `base_url`, `DockerHost` falls back to Docker environment configuration. Be explicit when you need a specific socket or remote daemon.\n- Keep the worker process alive. Closing the worker terminal stops polling for scheduled runs.\n\n## Version Notes For `prefect-docker` 0.7.1\n\n- PyPI lists `0.7.1` as the latest release, published on January 15, 2026.\n- The current integration docs live under `https://docs.prefect.io/integrations/prefect-docker`, while most deployment examples for Docker work pools are in the Prefect v3 deployment docs.\n- `prefect-docker` 0.7.1 requires Python 3.10+.\n\n## Official Sources\n\n- Prefect Docker integration docs: `https://docs.prefect.io/integrations/prefect-docker`\n- Prefect Docker deployment guide: `https://docs.prefect.io/v3/how-to-guides/deployment_infra/docker`\n- Prefect workers concept docs: `https://docs.prefect.io/v3/concepts/workers`\n- Prefect work-pool CLI reference: `https://docs.prefect.io/v3/api-ref/cli/work-pool`\n- Prefect Docker image deployment guide: `https://docs.prefect.io/v3/how-to-guides/deployments/deploy-via-python`\n- `prefect.docker.DockerImage` SDK reference: `https://reference.prefect.io/prefect/docker/docker_image/`\n- `prefect_docker.host` SDK reference: `https://reference.prefect.io/prefect_docker/host/`\n- `prefect_docker.credentials` SDK reference: `https://reference.prefect.io/prefect_docker/credentials/`\n- `prefect_docker.images` SDK reference: `https://reference.prefect.io/prefect_docker/images/`\n- `prefect_docker.containers` SDK reference: `https://reference.prefect.io/prefect_docker/containers/`\n- `prefect_docker.deployments.steps` SDK reference: `https://reference.prefect.io/prefect_docker/deployments/steps/`\n- PyPI package page: `https://pypi.org/project/prefect-docker/`\n"
  },
  {
    "path": "content/prefect/docs/email/python/DOC.md",
    "content": "---\nname: email\ndescription: \"Prefect email integration for storing SMTP credentials in a block and sending messages from flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,email,python,smtp,blocks,notifications\"\n---\n\n# Prefect Email Python Package Guide\n\n## Golden Rule\n\nUse `prefect-email` when a Prefect flow needs to send email through an SMTP account. The package gives you a Prefect block for email server credentials plus a task for sending a message.\n\nIf you only need to send email from a regular Python script and do not need Prefect blocks or flow orchestration, a plain SMTP library is usually a simpler fit.\n\n## Install\n\nInstall the integration in every environment that will run the flow:\n\n```bash\npython -m pip install \"prefect-email==0.4.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-email\npoetry add prefect-email\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-email\n```\n\n## What You Need Before Sending Mail\n\n`prefect-email` does not issue its own API key. Authentication comes from the SMTP account you already use with your mail provider.\n\nCollect these values first:\n\n- SMTP host name, such as `smtp.example.com`\n- SMTP port for your provider\n- SMTP username\n- SMTP password or app password\n- sender email address and recipient email address\n\nExample environment variables:\n\n```bash\nexport SMTP_HOST=\"smtp.example.com\"\nexport SMTP_PORT=\"465\"\nexport SMTP_USERNAME=\"noreply@example.com\"\nexport SMTP_PASSWORD=\"replace-me\"\nexport ALERT_EMAIL_TO=\"ops@example.com\"\n```\n\nIf you plan to save and later load a named Prefect block, configure Prefect itself as well:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nDirect instantiation of `EmailServerCredentials(...)` does not require a Prefect API connection. Saving with `save(...)` and loading with `load(...)` does.\n\n## Initialize Credentials In Code\n\nThere is no long-lived `prefect-email` client to initialize. The main setup object is the `EmailServerCredentials` block.\n\n```python\nimport os\n\nfrom prefect_email import EmailServerCredentials\n\n\nemail_credentials = EmailServerCredentials(\n    username=os.environ[\"SMTP_USERNAME\"],\n    password=os.environ[\"SMTP_PASSWORD\"],\n    smtp_server=os.environ[\"SMTP_HOST\"],\n    smtp_type=\"SSL\",\n    smtp_port=int(os.environ.get(\"SMTP_PORT\", \"465\")),\n)\n```\n\nUse the SMTP security mode and port required by your provider. For example, many providers use SSL on port `465` or STARTTLS on port `587`.\n\n## Save And Reuse A Named Block\n\nWhen several flows should share the same SMTP configuration, save it once and load it by name later.\n\n```python\nimport os\n\nfrom prefect_email import EmailServerCredentials\n\n\nemail_credentials = EmailServerCredentials(\n    username=os.environ[\"SMTP_USERNAME\"],\n    password=os.environ[\"SMTP_PASSWORD\"],\n    smtp_server=os.environ[\"SMTP_HOST\"],\n    smtp_type=\"SSL\",\n    smtp_port=int(os.environ.get(\"SMTP_PORT\", \"465\")),\n)\n\nemail_credentials.save(\"smtp-alerts\", overwrite=True)\n```\n\nLoad the block inside a flow or task:\n\n```python\nfrom prefect_email import EmailServerCredentials\n\n\nemail_credentials = EmailServerCredentials.load(\"smtp-alerts\")\n```\n\n## Send An Email From A Flow\n\nThe practical workflow is to load a credentials block, then call `email_send_message` from inside a flow.\n\n```python\nfrom prefect import flow\nfrom prefect_email import EmailServerCredentials, email_send_message\n\n\n@flow(log_prints=True)\ndef send_failure_notice() -> None:\n    email_credentials = EmailServerCredentials.load(\"smtp-alerts\")\n\n    email_send_message(\n        email_server_credentials=email_credentials,\n        subject=\"Prefect run needs attention\",\n        msg=\"The nightly sync flow failed. Check the Prefect UI for details.\",\n        email_to=[\"ops@example.com\"],\n    )\n\n\nif __name__ == \"__main__\":\n    send_failure_notice()\n```\n\nWhat matters here:\n\n- `email_server_credentials` is the block instance that holds SMTP settings and authentication.\n- `subject`, `msg`, and `email_to` are the core inputs for a basic message send.\n- The runtime environment must have both `prefect-email` installed and network access to the SMTP server.\n\n## Use Direct Instantiation Instead Of A Saved Block\n\nIf your runtime already gets secrets from environment variables or another secret manager, you can skip Prefect block storage and build the credentials inline.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_email import EmailServerCredentials, email_send_message\n\n\n@flow\ndef send_inline_email() -> None:\n    email_credentials = EmailServerCredentials(\n        username=os.environ[\"SMTP_USERNAME\"],\n        password=os.environ[\"SMTP_PASSWORD\"],\n        smtp_server=os.environ[\"SMTP_HOST\"],\n        smtp_type=\"SSL\",\n        smtp_port=int(os.environ.get(\"SMTP_PORT\", \"465\")),\n    )\n\n    email_send_message(\n        email_server_credentials=email_credentials,\n        subject=\"Job finished\",\n        msg=\"Your scheduled flow run completed.\",\n        email_to=[os.environ[\"ALERT_EMAIL_TO\"]],\n    )\n```\n\nThis pattern avoids a Prefect API dependency, but you still need to provide the SMTP credentials securely at runtime.\n\n## Common Pitfalls\n\n- Installing `prefect-email` does not replace core `prefect`; you still use Prefect for `@flow`, tasks, deployments, workers, and block storage.\n- `save(...)` and `load(...)` require a working Prefect API configuration. Inline construction does not.\n- SMTP authentication details are provider-specific. The host, port, and security mode must match the mail service you actually use.\n- The worker or local runtime must be able to reach the SMTP server over the network.\n- Keep SMTP passwords out of source control. Use environment variables, a secret manager, or a saved Prefect block.\n\n## Version Notes For `prefect-email` 0.4.2\n\n- This guide covers the PyPI package version `0.4.2`.\n- Pin the integration version your project expects, especially when you also pin the core `prefect` package.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Package integration docs: `https://docs.prefect.io/integrations/prefect-email/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Python reference root: `https://reference.prefect.io/prefect_email/`\n- PyPI package page: `https://pypi.org/project/prefect-email/`\n"
  },
  {
    "path": "content/prefect/docs/gcp/python/DOC.md",
    "content": "---\nname: gcp\ndescription: \"Prefect GCP integration for storing Google Cloud credentials in Prefect blocks and using BigQuery, Cloud Storage, and Secret Manager from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.17\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,gcp,python,workflow,orchestration,bigquery,cloud-storage,secret-manager,blocks\"\n---\n\n# Prefect GCP Python Package Guide\n\n## Golden Rule\n\nUse `prefect-gcp` as the Google Cloud integration layer for Prefect. Keep writing orchestration with core `prefect`; use `prefect-gcp` for reusable GCP credential blocks and for block-backed access to BigQuery, Cloud Storage, and Secret Manager inside flows.\n\nIf you only need the raw Google Cloud SDK outside Prefect orchestration, start with the Google client library directly.\n\n## Install\n\nInstall the package version this guide covers:\n\n```bash\npython -m pip install \"prefect-gcp==0.6.17\"\n```\n\nIf you want the optional Google service extras documented by Prefect:\n\n```bash\npython -m pip install \"prefect-gcp[all_extras]==0.6.17\"\n```\n\nIf your environment does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-gcp\n```\n\nRegister the block types after installation so they are available in the Prefect UI and CLI:\n\n```bash\nprefect block register -m prefect_gcp\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-gcp\npython -c \"import prefect_gcp; print(prefect_gcp.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you use `prefect-gcp`, make sure:\n\n- the target GCP project exists and the required APIs are enabled\n- the runtime identity has permission for the BigQuery, Cloud Storage, or Secret Manager calls you make\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nTypical environment variables:\n\n```bash\nexport GOOGLE_CLOUD_PROJECT=\"my-gcp-project\"\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/absolute/path/to/service-account.json\"\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nIf you run against a local self-hosted Prefect server instead of Prefect Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\n`GcpCredentials` accepts either `service_account_info` or `service_account_file`. If neither is provided, the block falls back to Google Application Default Credentials (ADC). For containerized workers and remote execution, `service_account_info` is usually the safer saved-block option because it does not depend on a file path existing inside the runtime container.\n\n## Initialize A Credentials Block\n\nCreate a block directly from service-account JSON:\n\n```python\nimport json\nimport os\n\nfrom prefect_gcp import GcpCredentials\n\n\ngcp_credentials = GcpCredentials(\n    service_account_info=json.loads(os.environ[\"GCP_SERVICE_ACCOUNT_INFO\"]),\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n)\n```\n\nOr rely on ADC when the runtime already has a GCP identity:\n\n```python\nimport os\n\nfrom prefect_gcp import GcpCredentials\n\n\ngcp_credentials = GcpCredentials(\n    project=os.environ[\"GOOGLE_CLOUD_PROJECT\"],\n)\n```\n\nUse direct instantiation when credentials already come from environment variables, workload identity, or another secret manager and you do not need a saved Prefect block yet.\n\n## Save And Reuse A Named Block\n\nSave the block when multiple flows or deployments should share the same GCP configuration:\n\n```python\ngcp_credentials.save(\"gcp-prod\", overwrite=True)\n```\n\nLoad it later:\n\n```python\nfrom prefect_gcp import GcpCredentials\n\n\ngcp_credentials = GcpCredentials.load(\"gcp-prod\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` require a working Prefect API connection\n- `prefect block register -m prefect_gcp` should be run once in the environment where you want the block type to appear\n- direct instantiation of `GcpCredentials(...)` does not require Prefect Cloud or a self-hosted server\n\n## Query BigQuery From A Flow\n\nUse `GcpCredentials.get_bigquery_client()` for lower-level setup, then use `BigQueryWarehouse` as the query surface inside the flow. The maintainer reference recommends using `BigQueryWarehouse` as a context manager so the connection and cursors close cleanly.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_gcp import GcpCredentials\nfrom prefect_gcp.bigquery import BigQueryWarehouse\n\n\n@flow(log_prints=True)\ndef bigquery_demo() -> list:\n    project = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n    dataset_id = f\"{project}.prefect_demo\"\n    table_name = f\"`{project}.prefect_demo.customers`\"\n\n    gcp_credentials = GcpCredentials.load(\"gcp-prod\")\n\n    client = gcp_credentials.get_bigquery_client(location=\"US\")\n    client.create_dataset(dataset_id, exists_ok=True)\n\n    with BigQueryWarehouse(\n        gcp_credentials=gcp_credentials,\n        fetch_size=2,\n    ) as warehouse:\n        warehouse.execute(\n            f\"CREATE TABLE IF NOT EXISTS {table_name} (name STRING, city STRING)\"\n        )\n        warehouse.execute_many(\n            f\"INSERT INTO {table_name} (name, city) VALUES (%(name)s, %(city)s)\",\n            seq_of_parameters=[\n                {\"name\": \"Ada\", \"city\": \"London\"},\n                {\"name\": \"Grace\", \"city\": \"New York\"},\n            ],\n        )\n        rows = warehouse.fetch_many(\n            f\"SELECT name, city FROM {table_name} ORDER BY name\",\n            size=10,\n        )\n\n    print(rows)\n    return rows\n\n\nif __name__ == \"__main__\":\n    bigquery_demo()\n```\n\nUse this pattern when you want Prefect to manage authentication and orchestration while the actual SQL still looks like normal database work.\n\n## Upload And Download Files With GCS\n\nCreate a `GcsBucket` block when a flow needs a reusable bucket definition. The bucket must already exist.\n\n```python\nfrom pathlib import Path\n\nfrom prefect import flow\nfrom prefect_gcp import GcpCredentials, GcsBucket\n\n\n@flow(log_prints=True)\ndef gcs_demo() -> str:\n    local_path = Path(\"hello.txt\")\n    local_path.write_text(\"Hello from Prefect GCS\\n\")\n\n    gcs_bucket = GcsBucket(\n        bucket=\"my-prefect-bucket\",\n        bucket_folder=\"prefect-demo\",\n        gcp_credentials=GcpCredentials.load(\"gcp-prod\"),\n    )\n\n    object_path = gcs_bucket.upload_from_path(\n        local_path,\n        to_path=\"hello.txt\",\n    )\n    gcs_bucket.download_object_to_path(\n        object_path,\n        \"downloaded-hello.txt\",\n    )\n    return Path(\"downloaded-hello.txt\").read_text()\n\n\nif __name__ == \"__main__\":\n    print(gcs_demo())\n```\n\nFor directory syncs, `GcsBucket` also exposes `upload_from_folder(...)` and `download_folder_to_path(...)`.\n\n## Store And Read Secrets In Secret Manager\n\nUse `GcpSecret` for workflows that need to create, read, or delete a Google Secret Manager secret version from a flow.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_gcp import GcpCredentials, GcpSecret\n\n\n@flow(log_prints=True)\ndef secret_manager_demo() -> str:\n    gcp_secret = GcpSecret(\n        secret_name=\"prefect-demo-api-key\",\n        secret_version=\"latest\",\n        gcp_credentials=GcpCredentials.load(\"gcp-prod\"),\n    )\n\n    gcp_secret.write_secret(secret_data=os.environ[\"APP_API_KEY\"].encode())\n    secret_value = gcp_secret.read_secret().decode()\n    print(secret_value)\n    return secret_value\n\n\nif __name__ == \"__main__\":\n    secret_manager_demo()\n```\n\nDelete the secret when you are done with an ephemeral test secret:\n\n```python\ngcp_secret.delete_secret()\n```\n\n## Use The Underlying Google Clients\n\nIf you need a lower-level Google client than the block wrappers expose, `GcpCredentials` can build authenticated clients directly:\n\n```python\nfrom prefect_gcp import GcpCredentials\n\n\ngcp_credentials = GcpCredentials.load(\"gcp-prod\")\n\nstorage_client = gcp_credentials.get_cloud_storage_client()\nsecret_manager_client = gcp_credentials.get_secret_manager_client()\nbigquery_client = gcp_credentials.get_bigquery_client(location=\"US\")\n```\n\nThis is a good fit when you want Prefect-managed credentials but still need an API call that is only available on the raw Google SDK client.\n\n## Common Pitfalls\n\n- Installing `prefect-gcp` does not replace core `prefect`; you still use `prefect` for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving or loading blocks by name requires a reachable Prefect API. Direct instantiation does not.\n- `prefect block register -m prefect_gcp` is required before the `prefect-gcp` block types show up in the Prefect block catalog.\n- `GcpCredentials` accepts only one of `service_account_info` or `service_account_file` at a time.\n- If you use `service_account_file`, that file path must exist in the actual worker or container that executes the flow. Saved `service_account_info` is more portable.\n- If you provide neither `service_account_info` nor `service_account_file`, the block falls back to ADC. That usually means setting `GOOGLE_APPLICATION_CREDENTIALS` or running on a GCP runtime with an attached service account.\n- Set `project` on `GcpCredentials` when you use `GcpSecret`; the secret methods build resource names from `gcp_credentials.project`.\n- `BigQueryWarehouse` is intended for query execution and is best used as a context manager.\n- `GcsBucket` does not create a bucket for you. Create the bucket separately before calling `upload_from_path(...)` or `upload_from_folder(...)`.\n- Current Prefect integration docs route Cloud Run and Vertex AI execution through Prefect deployment infrastructure such as work pools and workers; keep new application code focused on blocks, flows, and deployments instead of older ad hoc infrastructure examples.\n\n## Version Notes For `prefect-gcp` 0.6.17\n\n- This guide covers the PyPI package version `0.6.17`, released on February 12, 2026.\n- PyPI lists `prefect-gcp 0.6.17` as requiring Python 3.10 or newer.\n- The current maintainer docs present `prefect-gcp` primarily as a block-based integration package for BigQuery, Cloud Storage, Secret Manager, and Prefect-managed GCP execution workflows.\n\n## Official Sources Used\n\n- Prefect integrations docs: `https://docs.prefect.io/integrations/prefect-gcp/index`\n- Prefect integrations overview: `https://docs.prefect.io/integrations/use-integrations`\n- Prefect blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Prefect settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Prefect Python reference for credentials: `https://reference.prefect.io/prefect_gcp/credentials/`\n- Prefect Python reference for BigQuery: `https://reference.prefect.io/prefect_gcp/bigquery/`\n- Prefect Python reference for Cloud Storage: `https://reference.prefect.io/prefect_gcp/cloud_storage/`\n- Prefect Python reference for Secret Manager: `https://reference.prefect.io/prefect_gcp/secret_manager/`\n- PyPI package page: `https://pypi.org/project/prefect-gcp/0.6.17/`\n"
  },
  {
    "path": "content/prefect/docs/github/python/DOC.md",
    "content": "---\nname: github\ndescription: \"Prefect GitHub integration for GitHub credentials, private repository deployments, and GitHub GraphQL tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,github,python,workflow,orchestration,deployments,blocks,graphql\"\n---\n\n# Prefect GitHub Python Package Guide\n\n## Golden Rule\n\nUse `prefect-github` as the Prefect integration for GitHub authentication and GitHub-specific blocks. Keep writing flows and deployments with core `prefect`; use this package when you need to:\n\n- store a GitHub personal access token in a `GitHubCredentials` block\n- pull flow code from a private GitHub repository at deployment runtime\n- call the GitHub GraphQL API from a flow with the generated repository query and mutation helpers\n\nIf your deployment reads from a public GitHub repository, you can usually use the repository URL directly without installing `prefect-github`.\n\n## Install\n\nInstall the package version this guide covers:\n\n```bash\npython -m pip install \"prefect-github==0.4.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-github\npoetry add prefect-github\n```\n\nIf you want Prefect to choose a compatible integration version for your current Prefect install, use the documented extra instead:\n\n```bash\npython -m pip install \"prefect[github]\"\n```\n\nAfter installation, register the integration block types:\n\n```bash\nprefect block register -m prefect_github\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-github\npython -c \"import prefect_github; print(prefect_github.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore using the integration, make sure:\n\n- the runtime has a GitHub account and a Personal Access Token\n- for private repository cloning, the token has at least read access to repository contents and metadata\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nExample environment variables:\n\n```bash\nexport GITHUB_TOKEN=\"github_pat_...\"\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor an interactive Prefect Cloud setup:\n\n```bash\nprefect cloud login\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\n## Create A GitHub Credentials Block\n\n`GitHubCredentials` is the main entry point for this package. Instantiate it directly when your token already comes from environment variables or another secret manager.\n\n```python\nimport os\n\nfrom prefect_github import GitHubCredentials\n\n\ngithub_credentials = GitHubCredentials(\n    token=os.environ[\"GITHUB_TOKEN\"],\n)\n```\n\nUse this direct-instantiation pattern when you only need the token in the current process and do not need a saved block document yet.\n\n## Save And Reuse A Named Block\n\nWhen multiple deployments or flows should share the same GitHub token, save the block in Prefect and load it by name later.\n\n```python\nimport os\n\nfrom prefect_github import GitHubCredentials\n\n\ngithub_credentials = GitHubCredentials(\n    token=os.environ[\"GITHUB_TOKEN\"],\n)\n\ngithub_credentials.save(\"github-creds\", overwrite=True)\n```\n\nLoad the block later:\n\n```python\nfrom prefect_github import GitHubCredentials\n\n\ngithub_credentials = GitHubCredentials.load(\"github-creds\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they need a reachable Prefect API\n- the block stores a GitHub PAT, not a GitHub App installation token\n- if the block type does not appear in the UI or `load(...)` fails because the type is unknown, run `prefect block register -m prefect_github`\n\n## Deploy A Flow From A Private GitHub Repository\n\nFor a private GitHub repository, Prefect’s current deployment docs use core `prefect.runner.storage.GitRepository` together with a `GitHubCredentials` block.\n\n```python\nfrom prefect import flow\nfrom prefect.runner.storage import GitRepository\nfrom prefect_github import GitHubCredentials\n\n\n@flow\ndef my_flow() -> None:\n    print(\"hello from a private GitHub deployment\")\n\n\nif __name__ == \"__main__\":\n    source = GitRepository(\n        url=\"https://github.com/org/private-repo.git\",\n        credentials=GitHubCredentials.load(\"github-creds\"),\n        branch=\"main\",\n    )\n\n    my_flow.from_source(\n        source=source,\n        entrypoint=\"flows/my_flow.py:my_flow\",\n    ).deploy(\n        name=\"private-github-deploy\",\n        work_pool_name=\"my-pool\",\n    )\n```\n\nUse this pattern when:\n\n- the flow source of truth lives in GitHub\n- your worker should clone the repository at runtime\n- you want the GitHub token stored in Prefect instead of hard-coded in source\n\nFor a public repository, you can usually skip the credentials block and pass the repository URL directly.\n\n## Use `prefect.yaml` Pull Steps With A Saved Block\n\nIf your deployments are defined in `prefect.yaml`, reference the saved block in the `git_clone` pull step:\n\n```yaml\npull:\n  - prefect.deployments.steps.git_clone:\n      repository: https://github.com/org/private-repo.git\n      credentials: \"{{ prefect.blocks.github-credentials.github-creds }}\"\n```\n\nThis keeps the token out of the deployment file while still letting workers resolve it at runtime.\n\n## Clone Repository Contents In Python\n\nIf you want to pull repository files into a local directory from Python code, use `GitHubRepository`. The reference docs show `get_directory(from_path=None, local_path=None)` and note that it defaults to the configured repository reference and the current working directory.\n\n```python\nfrom prefect_github import GitHubCredentials\nfrom prefect_github.repository import GitHubRepository\n\n\nrepo = GitHubRepository(\n    repository_url=\"https://github.com/org/private-repo.git\",\n    reference=\"main\",\n    credentials=GitHubCredentials.load(\"github-creds\"),\n)\n\nrepo.get_directory(\n    from_path=\"flows\",\n    local_path=\"cloned-flow-code\",\n)\n```\n\nUse this when a task or bootstrap script needs files from a GitHub repository, not when you are defining deployment source for `flow.from_source(...)`.\n\n## Call GitHub GraphQL Tasks From A Flow\n\n`GitHubCredentials.get_client()` creates an authenticated GitHub GraphQL client pointed at `https://api.github.com/graphql`, but the most practical pattern is to use the generated query and mutation helpers directly in flows.\n\nThis example follows the official integration docs by querying a repository ID and starring it:\n\n```python\nfrom prefect import flow\nfrom prefect_github import GitHubCredentials\nfrom prefect_github.mutations import add_star_starrable\nfrom prefect_github.repository import query_repository\n\n\n@flow\ndef github_add_star_flow():\n    github_credentials = GitHubCredentials.load(\"github-creds\")\n\n    repository = query_repository(\n        \"PrefectHQ\",\n        \"prefect\",\n        github_credentials=github_credentials,\n        return_fields=\"id\",\n    )\n\n    return add_star_starrable(\n        repository[\"id\"],\n        github_credentials,\n    )\n\n\nif __name__ == \"__main__\":\n    github_add_star_flow()\n```\n\nIf you need the lower-level client directly:\n\n```python\nfrom prefect_github import GitHubCredentials\n\n\ngithub_credentials = GitHubCredentials.load(\"github-creds\")\nclient = github_credentials.get_client()\n```\n\n## Common Pitfalls\n\n- Installing `prefect-github` does not replace core `prefect`; you still use `prefect` for `@flow`, deployments, work pools, workers, and profiles.\n- Register the integration block types after installation or the GitHub blocks may not be available in the UI.\n- Saving and loading named blocks requires a reachable Prefect API. Direct instantiation of `GitHubCredentials(...)` does not.\n- For private repositories, prefer HTTPS with a fine-grained GitHub PAT. Prefect’s deployment docs recommend read access to repository Contents and Metadata.\n- `GitRepository` defaults the branch to `main` when you do not specify one. Set `branch=` explicitly if your repository uses a different default branch.\n- `GitHubRepository` injects the token into an HTTPS clone URL for private repositories. Do not switch that workflow to SSH unless you are intentionally managing Git authentication outside this block.\n- Prefect does not push your local changes back to GitHub when you create a deployment from Git-based storage. Commit and push your code separately.\n\n## Version Notes For `prefect-github` 0.4.2\n\n- This guide covers the PyPI package version `0.4.2`, which PyPI lists as released on February 12, 2026.\n- PyPI lists `Requires: Python >=3.10` for this release.\n- Prefect’s integration docs currently document `pip install \"prefect[github]\"` as the compatibility-oriented install path, while the code-storage guide also shows direct installation of `prefect-github`.\n- If you use Prefect Cloud, the current code-storage docs also describe a Prefect Cloud GitHub App flow that avoids storing a long-lived GitHub token block for private repository access.\n\n## Official Sources Used\n\n- Prefect integrations overview: `https://docs.prefect.io/integrations/use-integrations`\n- Prefect GitHub integration docs: `https://docs.prefect.io/integrations/prefect-github`\n- Prefect blocks docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Prefect Cloud connection docs: `https://docs.prefect.io/v3/manage/cloud/connect-to-cloud`\n- Prefect settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Prefect code storage guide: `https://docs.prefect.io/v3/deploy/infrastructure-concepts/store-flow-code`\n- Prefect `prefect.yaml` guide: `https://docs.prefect.io/v3/deploy/infrastructure-concepts/prefect-yaml`\n- Prefect Python reference for credentials: `https://reference.prefect.io/prefect_github/credentials/`\n- Prefect Python reference for repository helpers: `https://reference.prefect.io/prefect_github/repository/`\n- PyPI package page: `https://pypi.org/project/prefect-github/`\n"
  },
  {
    "path": "content/prefect/docs/gitlab/python/DOC.md",
    "content": "---\nname: gitlab\ndescription: \"Prefect GitLab integration for storing GitLab credentials and using GitLab-hosted source in Prefect deployments\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"prefect,gitlab,python,workflow,orchestration,deployments,blocks\"\n---\n\n# Prefect GitLab Python Package Guide\n\n## Golden Rule\n\nUse `prefect-gitlab` as a Prefect integration package for GitLab-backed source and credentials. Keep writing flows and tasks with core `prefect`; use this package when your flow code lives in GitLab and you want Prefect blocks to hold GitLab authentication details for reusable deployments.\n\nIf your flow code is local or in a public repository that does not need GitLab-specific authentication, core Prefect may be enough without this integration.\n\n## Install\n\nInstall the integration version this guide covers:\n\n```bash\npython -m pip install \"prefect-gitlab==0.3.4\"\n```\n\nIf your project does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-gitlab\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-gitlab\npoetry add prefect-gitlab\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-gitlab\npython -c \"import prefect_gitlab; print(prefect_gitlab.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you use GitLab-backed source with Prefect, make sure:\n\n- your flow code already exists in a GitLab project\n- you have a GitLab token with the repository access your deployment needs\n- the branch, tag, or commit you reference already exists\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nExample environment variables:\n\n```bash\nexport GITLAB_ACCESS_TOKEN=\"glpat-...\"\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nThere is no separate long-lived `prefect-gitlab` runtime you need to start. The common entry points are Prefect blocks that you save once and load inside deployment code.\n\n## Create A GitLab Credentials Block\n\nCreate a `GitLabCredentials` block from environment variables when you want Prefect to reuse GitLab authentication without hard-coding a token into deployment source.\n\n```python\nimport os\n\nfrom prefect_gitlab import GitLabCredentials\n\n\ngitlab_credentials = GitLabCredentials(\n    token=os.environ[\"GITLAB_ACCESS_TOKEN\"],\n)\n```\n\nUse this direct-instantiation pattern when your token already comes from environment variables or another secret manager and you do not need to persist a named block yet.\n\n## Save And Reuse A Named Credentials Block\n\nWhen multiple deployments should share the same GitLab authentication settings, save the block in Prefect and load it by name later.\n\n```python\nimport os\n\nfrom prefect_gitlab import GitLabCredentials\n\n\ngitlab_credentials = GitLabCredentials(\n    token=os.environ[\"GITLAB_ACCESS_TOKEN\"],\n)\n\ngitlab_credentials.save(\"gitlab-creds\", overwrite=True)\n```\n\nLoad the block later:\n\n```python\nfrom prefect_gitlab import GitLabCredentials\n\n\ngitlab_credentials = GitLabCredentials.load(\"gitlab-creds\")\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they require a working Prefect API configuration\n- direct instantiation of `GitLabCredentials(...)` does not require Prefect Cloud or a self-hosted server\n\n## Deploy A Flow From GitLab Source\n\nThe most practical workflow is to store GitLab configuration in Prefect blocks, then deploy a flow from a GitLab-backed source.\n\n```python\nfrom prefect import flow\nfrom prefect_gitlab import GitLabRepository\n\n\nif __name__ == \"__main__\":\n    flow.from_source(\n        source=GitLabRepository.load(\"gitlab-source\"),\n        entrypoint=\"flows/reporting.py:daily_report\",\n    ).deploy(\n        name=\"gitlab-reporting\",\n        work_pool_name=\"docker-pool\",\n    )\n```\n\nWhat this assumes:\n\n- you already saved a `GitLabRepository` block named `gitlab-source`\n- the block points at the correct GitLab project and branch, tag, or commit\n- `entrypoint` matches the Python file and flow function inside that repository\n- the worker environment can still install your project dependencies when the deployment runs\n\nThis pattern is the right fit when source-of-truth flow code lives in GitLab and you want deployments to keep pulling from that repository instead of packaging local files manually.\n\n## Typical Setup Pattern\n\nFor most teams, a clean split is:\n\n- keep the GitLab token in a `GitLabCredentials` block\n- keep the repository definition in a `GitLabRepository` block\n- load the repository block inside `flow.from_source(...)`\n- use normal Prefect work pools and workers for execution\n\nThat keeps GitLab access details reusable and separate from flow logic.\n\n## Common Pitfalls\n\n- Installing `prefect-gitlab` does not replace `prefect`; you still use core Prefect for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving a block with `save(...)` and loading it by name with `load(...)` requires a reachable Prefect API.\n- GitLab tokens belong in environment variables, secret management, or Prefect blocks, not hard-coded in source.\n- The repository block must point at a real GitLab project and a real branch, tag, or commit that contains the `entrypoint` file.\n- The deployment worker still needs the Python dependencies required by the pulled flow code.\n- Older Prefect examples may refer to agent-based deployment patterns. For current orchestration patterns, prefer deployments, work pools, workers, and blocks.\n\n## Version Notes For `prefect-gitlab` 0.3.4\n\n- This guide covers the PyPI package version `0.3.4`.\n- Treat `prefect-gitlab` as an integration layered on top of Prefect, not as a standalone GitLab client or workflow framework.\n- The Python package version is separate from your GitLab server version and from the Prefect core version in the rest of your stack.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Package integration docs: `https://docs.prefect.io/integrations/prefect-gitlab/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Python reference root: `https://reference.prefect.io/prefect_gitlab/`\n- PyPI package page: `https://pypi.org/project/prefect-gitlab/`\n"
  },
  {
    "path": "content/prefect/docs/kubernetes/python/DOC.md",
    "content": "---\nname: kubernetes\ndescription: \"Prefect Kubernetes integration for deploying Prefect flows to Kubernetes-backed work pools and workers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"prefect,kubernetes,python,workflow,orchestration,workers,deployment\"\n---\n\n# Prefect Kubernetes Python Package Guide\n\n## Golden Rule\n\nUse `prefect-kubernetes` when your Prefect deployments should run on Kubernetes. Keep writing flows with core `prefect`; this package is the Kubernetes integration layer for worker infrastructure and cluster-backed execution.\n\nIf you only run flows locally with `flow()` and do not need Kubernetes work pools or workers, you usually do not need this package.\n\n## Install\n\nInstall the integration into the environment that will register deployments and into the worker image or environment that will execute them:\n\n```bash\npython -m pip install \"prefect-kubernetes==0.7.5\"\n```\n\nIf you are pinning your full orchestration stack, pin Prefect alongside it:\n\n```bash\npython -m pip install \"prefect==3.6.21\" \"prefect-kubernetes==0.7.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-kubernetes\npoetry add prefect-kubernetes\n```\n\nSanity-check the package install:\n\n```bash\npython -m pip show prefect-kubernetes\n```\n\n## Prerequisites\n\nBefore you deploy to Kubernetes, make sure all of these are true:\n\n- `PREFECT_API_URL` points at a real Prefect server or Prefect Cloud workspace.\n- `PREFECT_API_KEY` is set when you use Prefect Cloud.\n- Your Kubernetes cluster is reachable from the worker environment.\n- The target namespace, service account, and RBAC rules already exist.\n- The image you deploy is available to the cluster and includes your flow code plus runtime dependencies.\n\nTypical Prefect environment variables:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\n## Kubernetes Authentication\n\nThere is no separate `prefect-kubernetes` API token. The integration uses normal Kubernetes authentication from the environment where the worker runs:\n\n- in-cluster service account credentials when the worker runs inside Kubernetes\n- a kubeconfig file when the worker runs outside the cluster\n\nPractical guidance:\n\n- Prefer an in-cluster service account for production workers.\n- Give that service account only the permissions needed to create and watch the workload objects your pool uses.\n- Do not hard-code kubeconfig content or cluster credentials into flow code.\n\n## Minimal Deployment Workflow\n\n`prefect-kubernetes` does not introduce a separate Python client you need to initialize in app code. You still write flows with `prefect`, then deploy them to a Kubernetes-backed work pool.\n\n### Define a flow and register a deployment\n\n```python\nfrom prefect import flow\n\n\n@flow(name=\"sync-customers\", log_prints=True)\ndef sync_customers() -> None:\n    print(\"Running in Kubernetes through a Prefect worker\")\n\n\nif __name__ == \"__main__\":\n    sync_customers.deploy(\n        name=\"daily\",\n        work_pool_name=\"kubernetes-pool\",\n        image=\"ghcr.io/acme/prefect-sync:latest\",\n        push=False,\n        cron=\"0 2 * * *\",\n    )\n```\n\nWhat matters here:\n\n- `work_pool_name` must point to a Kubernetes work pool.\n- `image` must contain your project code and its Python dependencies.\n- `push=False` only works if the referenced image already exists in a registry the cluster can pull from.\n\n### Start a worker for that pool\n\nRun the worker in an environment that has both Prefect connectivity and Kubernetes access:\n\n```bash\nprefect worker start --pool kubernetes-pool\n```\n\n### Trigger the deployment\n\n```bash\nprefect deployment run \"sync-customers/daily\"\n```\n\n## Image And Runtime Setup\n\nThe most common failure is registering a deployment from one environment and then running it in a container image that is missing your code or dependencies.\n\nMake sure the runtime image includes:\n\n- `prefect-kubernetes`\n- your application package or source tree\n- every library imported by the flow at runtime\n\nExample `requirements.txt` fragment:\n\n```text\nprefect==3.6.21\nprefect-kubernetes==0.7.5\n```\n\n## Common Pitfalls\n\n- Installing `prefect-kubernetes` locally does not make Kubernetes execution work unless the worker environment also has the package and valid cluster access.\n- A deployment can register successfully even when the worker later fails on image pulls, missing namespaces, or RBAC errors.\n- The worker needs network reachability to both the Prefect API and the Kubernetes API.\n- Kubernetes credentials belong in cluster configuration or worker runtime configuration, not inside the flow function.\n- If the worker runs outside the cluster, make sure the kubeconfig it uses points at the intended cluster and context.\n- If you want remote execution on Kubernetes, do not stop at calling the flow directly; register a deployment and keep a worker running for its pool.\n\n## Version Notes For `prefect-kubernetes` 0.7.5\n\n- This guide covers the PyPI package version `0.7.5`.\n- Treat the package as an integration for current Prefect work-pool and worker patterns, not older Prefect 2 agent-based examples.\n- When you copy older blog posts or snippets, translate them to current Prefect deployment and worker workflows before using them in production.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Deploy and workers docs: `https://docs.prefect.io/v3/deploy/`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- PyPI package page: `https://pypi.org/project/prefect-kubernetes/`\n"
  },
  {
    "path": "content/prefect/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Prefect Python workflow orchestration package for flows, tasks, scheduling, deployments, workers, and configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.6.21\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"prefect,python,workflow,orchestration,pipelines,scheduling,automation\"\n---\n\n# Prefect Python Package Guide\n\n## Golden Rule\n\nUse the full `prefect` package for Python workflow orchestration, define workflows with `@flow` and `@task`, and connect the runtime to a real Prefect API when you need deployments, workers, schedules, blocks, variables, or the UI. Running a flow function directly works locally, but orchestration features depend on either Prefect Cloud or a self-hosted Prefect server.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"prefect==3.6.21\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"prefect==3.6.21\"\npoetry add \"prefect==3.6.21\"\n```\n\nSanity-check the install:\n\n```bash\nprefect version\npython -c \"import prefect; print(prefect.__version__)\"\n```\n\nNotes:\n\n- Install `prefect`, not just `prefect-client`, when you need decorators, CLI commands, local orchestration features, workers, or server integration.\n- Provider integrations are separate packages. If your flow needs AWS, GCP, Databricks, dbt, Docker, Kubernetes, or similar integrations, install the matching `prefect-*` package instead of assuming core `prefect` includes every block or worker type.\n\n## Initialize And Connect To An API\n\n### Local development with a self-hosted server\n\nStart the local API and UI:\n\n```bash\nprefect server start\n```\n\nPoint your current profile at that API:\n\n```bash\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\nprefect config view --show-defaults\n```\n\n### Prefect Cloud\n\nThe simplest path is the login flow from the official docs:\n\n```bash\nprefect cloud login\n```\n\nIf you are scripting setup instead of using the interactive login, configure the workspace API URL and API key through environment variables or profile settings:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\n### Profiles And Settings Files\n\nUseful profile commands:\n\n```bash\nprefect profile ls\nprefect profile create local-server\nprefect profile use local-server\nprefect config view\n```\n\nPractical configuration guidance:\n\n- Use profiles to keep local, CI, staging, and production settings separate.\n- Use environment variables for secrets and CI overrides.\n- Prefect can also read project configuration from `.env`, `prefect.toml`, or `[tool.prefect]` in `pyproject.toml`.\n- Settings precedence is: environment variables, `.env`, `prefect.toml`, `pyproject.toml`, active profile, then defaults.\n- When something behaves unexpectedly, inspect the effective settings with `prefect config view` before changing code.\n\n## Core Usage\n\n### Define tasks and flows\n\n```python\nfrom datetime import timedelta\n\nfrom prefect import flow, task\nfrom prefect.cache_policies import INPUTS\n\n@task(\n    retries=3,\n    retry_delay_seconds=5,\n    cache_policy=INPUTS,\n    cache_expiration=timedelta(minutes=30),\n    persist_result=True,\n)\ndef fetch_customer(customer_id: str) -> dict[str, str]:\n    print(f\"Fetching {customer_id}\")\n    return {\"customer_id\": customer_id, \"status\": \"ok\"}\n\n@flow(name=\"sync-customers\", log_prints=True)\ndef sync_customers(customer_ids: list[str]) -> list[dict[str, str]]:\n    return [fetch_customer(customer_id) for customer_id in customer_ids]\n\nif __name__ == \"__main__\":\n    print(sync_customers([\"cust-1\", \"cust-2\"]))\n```\n\nWhy this pattern matters:\n\n- Put retry policy on tasks, not only on the surrounding flow.\n- Use `persist_result=True` when you expect caching or downstream result reuse to matter.\n- `log_prints=True` is useful during development because plain `print()` output is attached to the flow run logs.\n\n### Serve a flow from a long-running process\n\nUse `.serve()` when the same Python environment will stay alive and register scheduled or ad hoc runs itself:\n\n```python\nif __name__ == \"__main__\":\n    sync_customers.serve(\n        name=\"sync-customers-local\",\n        cron=\"0 * * * *\",\n    )\n```\n\n`serve()` is good for a developer machine, a VM, or a simple service process. Keep that process running or the schedule will stop being polled.\n\n### Deploy to a work pool for remote execution\n\nUse deployments and workers when execution should happen in managed infrastructure instead of the process that created the schedule:\n\n```python\nif __name__ == \"__main__\":\n    sync_customers.deploy(\n        name=\"hourly\",\n        work_pool_name=\"docker-pool\",\n        image=\"ghcr.io/acme/prefect-sync:latest\",\n        push=False,\n        cron=\"0 * * * *\",\n    )\n```\n\nThen start a worker for that pool:\n\n```bash\nprefect worker start --pool docker-pool\n```\n\nTrigger the deployment manually when needed:\n\n```bash\nprefect deployment run \"sync-customers/hourly\"\n```\n\nRule of thumb:\n\n- `flow()` call: just run Python now\n- `.serve()`: schedule from the current long-lived process\n- `.deploy()`: register remote execution for workers in a work pool\n\n## Configuration, Variables, And Secrets\n\n### Non-secret runtime configuration\n\nUse Variables for lightweight, JSON-serializable runtime values that may change without a code redeploy:\n\n```python\nfrom prefect.variables import Variable\n\napi_base_url = Variable.get(\"customer-api-base-url\", default=\"https://api.example.com\")\n```\n\nVariables are not the right place for credentials.\n\n### Secrets and reusable connection objects\n\nUse blocks for sensitive values and reusable infrastructure or credential configuration:\n\n```python\nfrom prefect.blocks.system import Secret\n\ntoken = Secret.load(\"customer-api-token\").get()\n```\n\nBlocks are better than hard-coded secrets because they can be updated in Prefect without editing the flow source.\n\n## Common Pitfalls\n\n- Flows can run without an API, but deployments, workers, blocks, variables, automations, and the UI require `PREFECT_API_URL` to point at a real server or Cloud workspace.\n- A served flow does nothing after registration unless the serving process keeps running.\n- A deployment does nothing unless a worker is running for the target work pool.\n- Do not store credentials in Variables. Use Secret blocks or environment variables.\n- Caching often disappoints when agents forget `persist_result=True` or expect local result storage to be shared across machines.\n- Fresh installs start on the `ephemeral` profile unless you configure another one. Set an explicit `PREFECT_API_URL` when you want persistent orchestration state.\n- Old Prefect 2 blog posts still mention agents. For Prefect 3, prefer current work-pool and worker guidance from the v3 docs.\n- Installing only `prefect-client` is a common mistake when the project actually needs the orchestration package and CLI.\n- Integration-specific blocks or workers will not import until the related `prefect-*` integration package is installed.\n\n## Version-Sensitive Notes For Prefect 3.6.21\n\n- PyPI lists `prefect 3.6.21` as the current package version covered here.\n- The docs URL used `https://docs.prefect.io/latest/`; for authoring, the stable canonical docs root is `https://docs.prefect.io/v3/`.\n- Some official docs examples still show older sample output such as `prefect-3.4.24` during installation. Treat that as example output, not the current package version.\n- Project-level config in `prefect.toml` and `[tool.prefect]` in `pyproject.toml` requires Prefect `>=3.1`.\n- Loading config from `.env` requires Prefect `>=3.0.5`.\n- When you find examples built around Prefect 2 agents or older deployment flows, translate them to Prefect 3 work pools and workers before copying them into production code.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/latest/`\n- Installation: `https://docs.prefect.io/v3/get-started/install`\n- Quickstart: `https://docs.prefect.io/v3/get-started/quickstart`\n- Connect to Prefect Cloud: `https://docs.prefect.io/v3/manage/cloud/connect-to-cloud`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Blocks: `https://docs.prefect.io/v3/concepts/blocks`\n- Variables: `https://docs.prefect.io/v3/concepts/variables`\n- PyPI package page: `https://pypi.org/project/prefect/`\n"
  },
  {
    "path": "content/prefect/docs/redis/python/DOC.md",
    "content": "---\nname: redis\ndescription: \"Prefect Redis integration for configuring Redis-backed blocks and using Redis connections inside Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.2.8\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"prefect,redis,python,workflow,orchestration,blocks,cache\"\n---\n\n# Prefect Redis Python Package Guide\n\n## Golden Rule\n\nUse `prefect-redis` as a Prefect integration package, not as a replacement for core `prefect`. The usual pattern is:\n\n- write flows and tasks with `prefect`\n- configure Redis connectivity with a `prefect-redis` block\n- load that block inside flows when you want a reusable Redis connection definition\n\nIf you only need one-off local code, you can instantiate the block directly in Python. If you want to save and reload named blocks, your environment must also be connected to a real Prefect API.\n\n## Install\n\nInstall the integration package version this guide covers:\n\n```bash\npython -m pip install \"prefect-redis==0.2.8\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-redis\npoetry add prefect-redis\n```\n\nIf your project does not already include Prefect, install it too:\n\n```bash\npython -m pip install prefect prefect-redis\n```\n\nSanity-check the package install:\n\n```bash\npython -m pip show prefect-redis\npython -c \"import prefect_redis; print(prefect_redis.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore using the integration, make sure:\n\n- a Redis server is reachable from the process that runs your flow\n- the flow environment has the Redis host, port, and any required credentials\n- `PREFECT_API_URL` is set if you want to save or load named Prefect blocks\n- `PREFECT_API_KEY` is also set when you use Prefect Cloud\n\nExample environment variables:\n\n```bash\nexport REDIS_HOST=\"127.0.0.1\"\nexport REDIS_PORT=\"6379\"\nexport REDIS_DB=\"0\"\nexport REDIS_USERNAME=\"default\"   # optional\nexport REDIS_PASSWORD=\"secret\"    # optional\n\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nThere is no separate `prefect-redis` token. Authentication is whatever your Redis server requires plus normal Prefect API settings when you store blocks in Prefect.\n\n## Initialize A Redis Block\n\n`prefect-redis` does not introduce a separate long-lived SDK client object for your app. The common entry point is a block such as `RedisDatabase`, then a Redis client retrieved from that block.\n\n```python\nimport os\n\nfrom prefect_redis import RedisDatabase\n\n\nredis_block = RedisDatabase(\n    host=os.environ[\"REDIS_HOST\"],\n    port=int(os.getenv(\"REDIS_PORT\", \"6379\")),\n    db=int(os.getenv(\"REDIS_DB\", \"0\")),\n    username=os.getenv(\"REDIS_USERNAME\"),\n    password=os.getenv(\"REDIS_PASSWORD\"),\n)\n\nclient = redis_block.get_client()\n\nclient.ping()\nclient.set(\"healthcheck\", \"ok\")\n\nvalue = client.get(\"healthcheck\")\nprint(value)\n\nclient.close()\n```\n\nUse this pattern when the connection details come from process environment or other local configuration and you do not need a saved block in Prefect yet.\n\n## Save And Reuse A Named Block\n\nWhen multiple flows, deployments, or environments should share the same Redis connection definition, save the block in Prefect and load it by name.\n\n```python\nimport os\n\nfrom prefect_redis import RedisDatabase\n\n\nredis_block = RedisDatabase(\n    host=os.environ[\"REDIS_HOST\"],\n    port=int(os.getenv(\"REDIS_PORT\", \"6379\")),\n    db=int(os.getenv(\"REDIS_DB\", \"0\")),\n    username=os.getenv(\"REDIS_USERNAME\"),\n    password=os.getenv(\"REDIS_PASSWORD\"),\n)\n\nredis_block.save(\"redis-dev\", overwrite=True)\n```\n\nLoad and use that block later:\n\n```python\nfrom prefect_redis import RedisDatabase\n\n\nredis_block = RedisDatabase.load(\"redis-dev\")\nclient = redis_block.get_client()\n\nclient.set(\"app:last-run\", \"2026-03-12T00:00:00Z\")\nprint(client.get(\"app:last-run\"))\n\nclient.close()\n```\n\nWhat matters here:\n\n- `save(...)` and `load(...)` depend on Prefect block storage, so they require a working Prefect API configuration.\n- Direct instantiation of `RedisDatabase(...)` does not require Prefect Cloud or a self-hosted server.\n\n## Use Redis Inside A Flow\n\nLoad the block inside tasks or flows where the Redis connection is actually needed.\n\n```python\nfrom prefect import flow, task\nfrom prefect_redis import RedisDatabase\n\n\n@task\ndef write_status(run_id: str) -> None:\n    redis_block = RedisDatabase.load(\"redis-dev\")\n    client = redis_block.get_client()\n    client.set(f\"flow-run:{run_id}:status\", \"running\")\n    client.close()\n\n\n@task\ndef read_status(run_id: str):\n    redis_block = RedisDatabase.load(\"redis-dev\")\n    client = redis_block.get_client()\n    value = client.get(f\"flow-run:{run_id}:status\")\n    client.close()\n    return value\n\n\n@flow(log_prints=True)\ndef redis_cache_demo(run_id: str = \"demo-1\"):\n    write_status(run_id)\n    print(read_status(run_id))\n\n\nif __name__ == \"__main__\":\n    redis_cache_demo()\n```\n\nThis is a good fit for simple status markers, cache entries, idempotency keys, or coordination state that already belongs in Redis.\n\n## Common Pitfalls\n\n- Installing `prefect-redis` does not replace `prefect`; you still use core Prefect for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving a block with `save(...)` can work only when `PREFECT_API_URL` points to a reachable Prefect API.\n- Redis credentials belong in environment variables, secret management, or Prefect blocks, not hard-coded in flow source.\n- The returned Redis client may give you `bytes` values for reads such as `get(...)`; decode them in your application if you need plain strings.\n- A flow can use Redis locally without Prefect Cloud, but loading blocks by name depends on a real Prefect server or Cloud workspace.\n- Older Prefect examples may refer to Prefect 2 agent workflows. For current orchestration patterns, prefer Prefect 3 deployments, work pools, workers, and blocks.\n\n## Version Notes For `prefect-redis` 0.2.8\n\n- This guide covers the PyPI package version `0.2.8`.\n- Treat `prefect-redis` as an integration package layered on top of core Prefect instead of a standalone workflow framework.\n- Redis server versioning is separate from the Python integration version; pin the Python package version your project expects and configure Redis compatibility at the infrastructure level.\n\n## Official Sources Used\n\n- Docs root: `https://docs.prefect.io/v3/`\n- Integrations root: `https://docs.prefect.io/integrations/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Python reference root: `https://reference.prefect.io/`\n- PyPI package page: `https://pypi.org/project/prefect-redis/`\n"
  },
  {
    "path": "content/prefect/docs/shell/python/DOC.md",
    "content": "---\nname: shell\ndescription: \"Prefect Shell integration for running shell commands and reusable shell-operation blocks from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,shell,python,workflow,commands,blocks\"\n---\n\n# Prefect Shell Python Package Guide\n\n## Golden Rule\n\nUse `prefect-shell` when a Prefect flow needs to execute shell commands or scripts and capture their output in Prefect logs. Use `ShellOperation.run()` for short multi-command jobs, `ShellOperation.trigger()` when you want to start a process and wait on it later, and `shell_run_command()` for a single shell command task.\n\n## Install\n\nThe maintainer docs recommend installing the integration through Prefect extras so the versions stay compatible:\n\n```bash\npython -m pip install \"prefect[shell]\"\n```\n\nIf you need to pin the integration directly, install the package version covered here:\n\n```bash\npython -m pip install \"prefect-shell==0.3.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-shell\npoetry add prefect-shell\n```\n\nIf you want the `ShellOperation` block type to appear in Prefect block storage and the UI, register it once after installation:\n\n```bash\nprefect block register -m prefect_shell\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-shell\npython -c \"import prefect_shell; print(prefect_shell.__file__)\"\n```\n\n`prefect-shell 0.3.5` requires Python 3.10 or newer.\n\n## Prerequisites And Environment\n\nThere is no separate `prefect-shell` API key or client configuration. Setup falls into two buckets:\n\n- Prefect configuration when you want to save or load named blocks from Prefect Cloud or a self-hosted Prefect server\n- runtime environment variables needed by the shell commands you actually execute\n\nFor Prefect Cloud:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted server:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nExample command-specific environment variables:\n\n```bash\nexport PROJECT_ROOT=\"$PWD\"\nexport APP_ENV=\"dev\"\n```\n\n## Initialize A `ShellOperation`\n\nThere is no long-lived integration client to construct first. The main reusable object is `ShellOperation`.\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom prefect_shell import ShellOperation\n\n\nshell_operation = ShellOperation(\n    commands=[\n        \"mkdir -p logs\",\n        \"printf 'env=%s\\\\n' \\\"$APP_ENV\\\" > logs/run.txt\",\n        \"python -V\",\n    ],\n    env={\"APP_ENV\": os.environ.get(\"APP_ENV\", \"dev\")},\n    working_dir=Path(os.environ[\"PROJECT_ROOT\"]).resolve(),\n    shell=\"bash\",\n)\n```\n\nUse an absolute path for `working_dir`. If you leave `shell` unset, Prefect uses `powershell` on Windows and `bash` on other platforms.\n\n## Run Short-Lived Commands With `run()`\n\n`run()` executes the configured commands, waits for completion, and returns the output as a list of lines.\n\n```python\nfrom pathlib import Path\n\nfrom prefect import flow\nfrom prefect_shell import ShellOperation\n\n\n@flow(log_prints=True)\ndef prepare_workspace(project_root: str) -> list[str]:\n    return ShellOperation(\n        commands=[\n            \"mkdir -p build\",\n            \"python -V\",\n        ],\n        working_dir=Path(project_root).resolve(),\n        stream_output=True,\n    ).run()\n\n\nif __name__ == \"__main__\":\n    print(prepare_workspace(\".\"))\n```\n\n## Trigger A Longer-Running Process\n\nFor a longer process, keep the block open as a context manager, call `trigger()`, then wait for completion when you are ready.\n\n```python\nfrom pathlib import Path\n\nfrom prefect import flow\nfrom prefect_shell import ShellOperation\n\n\n@flow\ndef run_background_job(project_root: str) -> list[str]:\n    with ShellOperation(\n        commands=[\n            \"sleep 5\",\n            \"echo background work finished\",\n        ],\n        working_dir=Path(project_root).resolve(),\n    ) as shell_operation:\n        shell_process = shell_operation.trigger()\n\n        # Do other flow work here if needed.\n\n        shell_process.wait_for_completion()\n        return shell_process.fetch_result()\n\n\nif __name__ == \"__main__\":\n    print(run_background_job(\".\"))\n```\n\n`wait_for_completion()` raises `RuntimeError` if the process exits with a non-zero code. If you call `fetch_result()` before the process finishes, the output can be incomplete.\n\n## Save And Reuse A Named Shell Block\n\n`ShellOperation` is also a Prefect block, so you can save a command set once and load it in later flows.\n\n```python\nfrom prefect_shell import ShellOperation\n\n\noperation = ShellOperation(\n    commands=[\"python manage.py migrate\"],\n)\noperation.save(\"django-migrate\", overwrite=True)\n\nloaded_operation = ShellOperation.load(\"django-migrate\")\n```\n\nThen run the loaded block inside a flow:\n\n```python\nfrom prefect import flow\nfrom prefect_shell import ShellOperation\n\n\n@flow\ndef run_saved_operation() -> list[str]:\n    operation = ShellOperation.load(\"django-migrate\")\n    return operation.run()\n```\n\nNamed block documents are stored through the Prefect API, so this workflow depends on a reachable Prefect server or Prefect Cloud workspace. Register `prefect_shell` block types first if they are not available yet.\n\n## Run A One-Off Command With `shell_run_command`\n\nUse `shell_run_command()` when you only need one command and do not want to build a `ShellOperation` object first.\n\n```python\nfrom pathlib import Path\n\nfrom prefect import flow\nfrom prefect_shell import shell_run_command\n\n\n@flow\ndef git_status(project_root: str) -> list[str]:\n    return shell_run_command(\n        command=\"git status --short\",\n        cwd=Path(project_root).resolve(),\n        env={\"GIT_PAGER\": \"cat\"},\n        return_all=True,\n        shell=\"bash\",\n    )\n\n\nif __name__ == \"__main__\":\n    print(git_status(\".\"))\n```\n\nUseful details:\n\n- `return_all=False` is the default, so without `return_all=True` you only get the last output line back.\n- `helper_command=` lets you run setup in the same shell process before the main command.\n- `cwd=` sets the working directory for the subprocess.\n\n## Common Pitfalls\n\n- `ShellOperation.working_dir` expects an absolute path. Use `Path(...).resolve()` instead of assuming the worker starts in your project directory.\n- Shell syntax is shell-specific. If your command assumes Bash syntax, set `shell=\"bash\"` explicitly instead of relying on the platform default.\n- `run()` returns a list of output lines. `shell_run_command()` returns only the last line unless you set `return_all=True`.\n- `wait_for_completion()` and `shell_run_command()` both raise `RuntimeError` when the subprocess exits non-zero.\n- Saving or loading named `ShellOperation` blocks depends on Prefect block registration plus a reachable Prefect API.\n\n## Version Notes For `prefect-shell` 0.3.5\n\n- This guide covers the PyPI package version `0.3.5`, released on March 10, 2026.\n- PyPI marks `0.3.5` as the latest release and lists `Python >=3.10` as the package requirement.\n- The current maintainer docs for `prefect-shell` live under the Prefect integrations site and match current Prefect 3 integration patterns.\n\n## Official Sources Used\n\n- Integrations guide: `https://docs.prefect.io/integrations/prefect-shell`\n- SDK reference: `https://reference.prefect.io/prefect_shell/commands/`\n- Blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Self-hosted server setup: `https://docs.prefect.io/v3/how-to-guides/self-hosted`\n- PyPI package page: `https://pypi.org/project/prefect-shell/`\n"
  },
  {
    "path": "content/prefect/docs/slack/python/DOC.md",
    "content": "---\nname: slack\ndescription: \"Prefect Slack integration for sending bot-token messages and incoming-webhook notifications from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,slack,python,notifications,blocks,workflow\"\n---\n\n# Prefect Slack Python Package Guide\n\n## Golden Rule\n\nUse `prefect-slack` when a Prefect flow needs to post to Slack with either a bot token or an incoming webhook. Keep using core `prefect` for flows, tasks, deployments, workers, and block storage; this package adds Slack-specific blocks and tasks on top.\n\nIf you only need a generic incoming-webhook notification block and do not need the Slack SDK client, Prefect also ships a built-in `prefect.blocks.notifications.SlackWebhook` block in core `prefect`.\n\n## Install\n\nThe Prefect integration docs recommend installing the Slack integration through the Prefect extra:\n\n```bash\npython -m pip install \"prefect[slack]\"\n```\n\nIf you are pinning the integration package directly, install the package version this guide covers:\n\n```bash\npython -m pip install \"prefect-slack==0.3.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-slack\npoetry add prefect-slack\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-slack\npython -c \"import prefect_slack; print(prefect_slack.__file__)\"\n```\n\n## Prerequisites And Environment\n\nChoose one Slack authentication path before you write flow code:\n\n- Bot token workflow: a Slack bot token such as `xoxb-...` with permission to post to the target channel\n- Incoming webhook workflow: a Slack incoming webhook URL for the target channel\n\nExample environment variables:\n\n```bash\nexport SLACK_BOT_TOKEN=\"xoxb-...\"\nexport SLACK_CHANNEL=\"#alerts\"\nexport SLACK_WEBHOOK_URL=\"https://hooks.slack.com/services/...\"\n```\n\nIf you want to save and later load named Prefect blocks, configure Prefect as well:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted server instead of Prefect Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nDirect instantiation of `SlackCredentials(...)` or `SlackWebhook(...)` does not require a Prefect API. Saving with `save(...)` and loading with `load(...)` does.\n\n## Send A Channel Message With A Bot Token\n\nUse `SlackCredentials` plus `send_chat_message` when you want normal Slack chat messages backed by a bot token.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_slack import SlackCredentials\nfrom prefect_slack.messages import send_chat_message\n\n\n@flow\nasync def post_status_message() -> None:\n    slack_credentials = SlackCredentials(token=os.environ[\"SLACK_BOT_TOKEN\"])\n\n    await send_chat_message(\n        slack_credentials=slack_credentials,\n        channel=os.environ[\"SLACK_CHANNEL\"],\n        text=\"Nightly sync completed successfully.\",\n    )\n\n\nif __name__ == \"__main__\":\n    import asyncio\n\n    asyncio.run(post_status_message())\n```\n\nUse this path when you need a real Slack bot identity and channel posting through Slack's Web API.\n\n## Save And Reuse A Slack Bot Credentials Block\n\nWhen several flows share the same bot token, save the credentials as a named Prefect block and load it where needed.\n\n```python\nimport os\n\nfrom prefect_slack import SlackCredentials\n\n\nslack_credentials = SlackCredentials(token=os.environ[\"SLACK_BOT_TOKEN\"])\nslack_credentials.save(\"slack-bot\", overwrite=True)\n```\n\nLoad the block inside your flow:\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_slack import SlackCredentials\nfrom prefect_slack.messages import send_chat_message\n\n\n@flow\nasync def notify_ops() -> None:\n    slack_credentials = SlackCredentials.load(\"slack-bot\")\n\n    await send_chat_message(\n        slack_credentials=slack_credentials,\n        channel=os.environ[\"SLACK_CHANNEL\"],\n        text=\"Flow run needs attention.\",\n    )\n```\n\n## Send A Message Through An Incoming Webhook\n\nUse `SlackWebhook` plus `send_incoming_webhook_message` when you already have a Slack webhook URL and only need notification-style delivery.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_slack import SlackWebhook\nfrom prefect_slack.messages import send_incoming_webhook_message\n\n\n@flow\nasync def post_webhook_message() -> None:\n    slack_webhook = SlackWebhook(url=os.environ[\"SLACK_WEBHOOK_URL\"])\n\n    await send_incoming_webhook_message(\n        slack_webhook=slack_webhook,\n        text=\"Warehouse load finished.\",\n    )\n\n\nif __name__ == \"__main__\":\n    import asyncio\n\n    asyncio.run(post_webhook_message())\n```\n\nIf the webhook configuration is shared across flows, save it once:\n\n```python\nimport os\n\nfrom prefect_slack import SlackWebhook\n\n\nslack_webhook = SlackWebhook(url=os.environ[\"SLACK_WEBHOOK_URL\"])\nslack_webhook.save(\"slack-webhook\", overwrite=True)\n```\n\nThen load it later:\n\n```python\nfrom prefect_slack import SlackWebhook\n\n\nslack_webhook = SlackWebhook.load(\"slack-webhook\")\n```\n\n## Use The Slack SDK Client Directly\n\n`SlackCredentials` can also create an authenticated Slack SDK client when you need an API call that is not wrapped by a Prefect task.\n\n```python\nimport os\n\nfrom prefect import flow\nfrom prefect_slack import SlackCredentials\n\n\n@flow\nasync def post_with_sdk() -> None:\n    slack_credentials = SlackCredentials(token=os.environ[\"SLACK_BOT_TOKEN\"])\n    client = slack_credentials.get_client()\n\n    await client.chat_postMessage(\n        channel=os.environ[\"SLACK_CHANNEL\"],\n        text=\"Posted through slack_sdk.AsyncWebClient\",\n    )\n```\n\nThis is the escape hatch for Slack API methods beyond the packaged helper tasks.\n\n## Common Pitfalls\n\n- `prefect-slack` does not replace core `prefect`; install and configure Prefect itself when you need flows, deployments, workers, or block storage.\n- Bot tokens and incoming webhook URLs are different authentication surfaces. Use `SlackCredentials` for token-based chat API calls and `SlackWebhook` for incoming webhooks.\n- Saving and loading blocks requires a working Prefect API configuration. Inline construction from environment variables does not.\n- The core `prefect.blocks.notifications.SlackWebhook` block and `prefect_slack.SlackWebhook` are different block types. A block saved under one class is not loaded through the other.\n- Prefer sending a plain-text `text` field even if you later add richer Slack formatting. Slack's webhook guidance treats `text` as a best practice and fallback for accessibility.\n- The runtime that executes the flow needs the Slack credentials or webhook URL and the `prefect-slack` package installed; registering a deployment elsewhere is not enough.\n\n## Version Notes For `prefect-slack` 0.3.1\n\n- This guide covers the PyPI package version `0.3.1`.\n- PyPI currently marks `prefect-slack` as requiring Python `>=3.9`.\n- The current Prefect integrations docs recommend `pip install \"prefect[slack]\"` instead of treating `prefect-slack` as a fully standalone install path.\n- The PyPI project description still references Prefect 2 wording, but the maintained integration docs live under the current Prefect docs and fit current Prefect block and configuration guidance.\n\n## Official Sources\n\n- Prefect integrations root: `https://docs.prefect.io/integrations/`\n- Prefect Slack integration docs: `https://docs.prefect.io/integrations/prefect-slack/`\n- Prefect blocks concept docs: `https://docs.prefect.io/v3/concepts/blocks`\n- Prefect settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- Prefect Cloud connection docs: `https://docs.prefect.io/v3/manage/cloud/connect-to-cloud`\n- Prefect Slack Python reference: `https://reference.prefect.io/prefect_slack/`\n- PyPI package page: `https://pypi.org/project/prefect-slack/`\n"
  },
  {
    "path": "content/prefect/docs/snowflake/python/DOC.md",
    "content": "---\nname: snowflake\ndescription: \"Prefect Snowflake integration for storing Snowflake credentials in Prefect blocks and running Snowflake queries from Python flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.28.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,snowflake,python,workflow,orchestration,database,sql,blocks\"\n---\n\n# Prefect Snowflake Python Package Guide\n\n## Golden Rule\n\nUse `prefect-snowflake` as the Prefect integration layer for Snowflake access. Keep orchestration in core `prefect`; use this package for `SnowflakeCredentials`, `SnowflakeConnector`, and Snowflake query helpers inside flows and tasks.\n\nIf you only need a plain Snowflake client outside Prefect orchestration, start with the Snowflake Python connector directly.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"prefect-snowflake==0.28.7\"\n```\n\nOfficial Prefect docs also support installing the matching extra from `prefect`:\n\n```bash\npython -m pip install \"prefect[snowflake]\"\n```\n\nCommon alternatives:\n\n```bash\nuv add prefect-snowflake\npoetry add prefect-snowflake\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-snowflake\npython -c \"import prefect_snowflake; print(prefect_snowflake.__file__)\"\n```\n\nPyPI lists `prefect-snowflake 0.28.7` as requiring Python `>=3.10`.\n\n## Prerequisites And Environment\n\nBefore you save blocks or run flows, make sure you have:\n\n- a Snowflake account, user, and an authentication method supported by `SnowflakeCredentials`\n- a database, schema, and warehouse you can query\n- `PREFECT_API_URL` configured if you want saved named blocks instead of in-memory objects\n- `PREFECT_API_KEY` as well when you use Prefect Cloud\n\nTypical environment variables:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n\nexport SNOWFLAKE_ACCOUNT=\"xy12345.us-east-1\"\nexport SNOWFLAKE_USER=\"analytics_user\"\nexport SNOWFLAKE_PASSWORD=\"...\"\nexport SNOWFLAKE_DATABASE=\"ANALYTICS\"\nexport SNOWFLAKE_SCHEMA=\"PUBLIC\"\nexport SNOWFLAKE_WAREHOUSE=\"COMPUTE_WH\"\nexport SNOWFLAKE_ROLE=\"ANALYST\"\n```\n\nIf you use a self-hosted Prefect server instead of Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nRegister the integration blocks if you want to view and manage them in the Prefect UI:\n\n```bash\nprefect block register -m prefect_snowflake\n```\n\n## Create And Save Blocks\n\nThe two common block types are:\n\n- `SnowflakeCredentials` for authentication details\n- `SnowflakeConnector` for the database, schema, warehouse, and fetch settings\n\nCreate and save both blocks:\n\n```python\nimport os\n\nfrom prefect_snowflake import SnowflakeConnector, SnowflakeCredentials\n\n\ncredentials = SnowflakeCredentials(\n    account=os.environ[\"SNOWFLAKE_ACCOUNT\"],\n    user=os.environ[\"SNOWFLAKE_USER\"],\n    password=os.environ[\"SNOWFLAKE_PASSWORD\"],\n    role=os.getenv(\"SNOWFLAKE_ROLE\"),\n    authenticator=\"snowflake\",\n)\ncredentials.save(\"snowflake-credentials\", overwrite=True)\n\nconnector = SnowflakeConnector(\n    credentials=credentials,\n    database=os.environ[\"SNOWFLAKE_DATABASE\"],\n    schema=os.environ[\"SNOWFLAKE_SCHEMA\"],\n    warehouse=os.environ[\"SNOWFLAKE_WAREHOUSE\"],\n    fetch_size=500,\n)\nconnector.save(\"snowflake-analytics\", overwrite=True)\n```\n\nLoad the saved connector later:\n\n```python\nfrom prefect_snowflake import SnowflakeConnector\n\n\nconnector = SnowflakeConnector.load(\"snowflake-analytics\")\n```\n\n## Run Queries In A Flow\n\nUse the connector as a context manager so the Snowflake connection and cursors are closed cleanly after the task or flow finishes.\n\n```python\nfrom prefect import flow, task\nfrom prefect_snowflake import SnowflakeConnector\n\n\n@task\ndef setup_demo_table() -> None:\n    with SnowflakeConnector.load(\"snowflake-analytics\") as connector:\n        connector.execute(\n            \"\"\"\n            CREATE TABLE IF NOT EXISTS demo_customers (\n                id INT,\n                name STRING,\n                status STRING\n            )\n            \"\"\"\n        )\n        connector.execute_many(\n            \"\"\"\n            INSERT INTO demo_customers (id, name, status)\n            VALUES (%(id)s, %(name)s, %(status)s)\n            \"\"\",\n            seq_of_parameters=[\n                {\"id\": 1, \"name\": \"Marvin\", \"status\": \"active\"},\n                {\"id\": 2, \"name\": \"Ford\", \"status\": \"inactive\"},\n                {\"id\": 3, \"name\": \"Trillian\", \"status\": \"active\"},\n            ],\n        )\n\n\n@task\ndef fetch_active_customers() -> list[tuple]:\n    with SnowflakeConnector.load(\"snowflake-analytics\") as connector:\n        return connector.fetch_all(\n            \"\"\"\n            SELECT id, name, status\n            FROM demo_customers\n            WHERE status = %(status)s\n            ORDER BY id\n            \"\"\",\n            parameters={\"status\": \"active\"},\n        )\n\n\n@flow(log_prints=True)\ndef snowflake_demo() -> None:\n    setup_demo_table()\n    rows = fetch_active_customers()\n    print(rows)\n\n\nif __name__ == \"__main__\":\n    snowflake_demo()\n```\n\nKeep the connector load, query, and close cycle inside one task or flow. The API reference warns that if you pass the block across separate tasks or flows, the connection and cursor state can be lost.\n\n## Stream Large Result Sets\n\n`fetch_many` is the safer default when the result set may be too large to hold in memory at once.\n\nRepeated calls with the same query continue from the previous cursor position until you call `reset_cursors()`.\n\n```python\nfrom prefect import flow\nfrom prefect_snowflake import SnowflakeConnector\n\n\n@flow\ndef process_large_query() -> int:\n    processed = 0\n\n    with SnowflakeConnector.load(\"snowflake-analytics\") as connector:\n        while True:\n            rows = connector.fetch_many(\n                \"\"\"\n                SELECT id, name\n                FROM demo_customers\n                ORDER BY id\n                \"\"\",\n                size=1000,\n            )\n            if not rows:\n                break\n\n            processed += len(rows)\n\n        connector.reset_cursors()\n\n    return processed\n```\n\nUse `fetch_one` when you expect one row, `fetch_all` when the full result is small, and `fetch_many` when you want chunked reads.\n\n## Use The Underlying Snowflake Connection\n\nIf you need connector features that `SnowflakeConnector` does not wrap directly, call `get_connection()` and use the raw Snowflake connection.\n\nThis is the documented path for `write_pandas`:\n\n```python\nimport pandas as pd\nfrom prefect import flow\nfrom prefect_snowflake import SnowflakeConnector\nfrom snowflake.connector.pandas_tools import write_pandas\n\n\n@flow\ndef load_dataframe() -> tuple[bool, int]:\n    with SnowflakeConnector.load(\"snowflake-analytics\") as connector:\n        with connector.get_connection() as connection:\n            table_name = \"DEMO_METRICS\"\n\n            with connection.cursor() as cursor:\n                cursor.execute(\n                    f\"\"\"\n                    CREATE TABLE IF NOT EXISTS {table_name} (\n                        NAME STRING,\n                        VALUE INT\n                    )\n                    \"\"\"\n                )\n\n            dataframe = pd.DataFrame(\n                [(\"rows_loaded\", 2), (\"errors\", 0)],\n                columns=[\"NAME\", \"VALUE\"],\n            )\n\n            success, _, num_rows, _ = write_pandas(\n                conn=connection,\n                df=dataframe,\n                table_name=table_name,\n                database=connector.database,\n                schema=connector.schema_,\n            )\n\n            return success, num_rows\n```\n\nTwo details matter here:\n\n- `schema` is passed to the block constructor, but the attribute on the block is `schema_`\n- the `write_pandas` example depends on Snowflake column-name case matching the DataFrame columns you send\n\n## Authentication Options\n\n`SnowflakeCredentials` supports more than username and password. The current API reference also documents:\n\n- key-pair auth with `private_key` or `private_key_path` and optional `private_key_passphrase`\n- `authenticator=\"snowflake_jwt\"` for JWT-style auth\n- `authenticator=\"oauth\"` with `token`\n- `authenticator=\"okta_endpoint\"` with `endpoint`\n- `authenticator=\"externalbrowser\"` when a browser is available on the runtime host\n- `authenticator=\"username_password_mfa\"` for MFA-based login flows\n\nExample using a private key file:\n\n```python\nimport os\nfrom pathlib import Path\n\nfrom prefect_snowflake import SnowflakeCredentials\n\n\ncredentials = SnowflakeCredentials(\n    account=os.environ[\"SNOWFLAKE_ACCOUNT\"],\n    user=os.environ[\"SNOWFLAKE_USER\"],\n    private_key_path=Path(\"/path/to/rsa_key.p8\"),\n    private_key_passphrase=os.getenv(\"SNOWFLAKE_PRIVATE_KEY_PASSPHRASE\"),\n    authenticator=\"snowflake_jwt\",\n)\n```\n\n## Common Pitfalls\n\n- Installing `prefect-snowflake` does not replace core `prefect`; you still use `@flow`, `@task`, deployments, workers, and profiles from Prefect itself.\n- Registering blocks with `prefect block register -m prefect_snowflake` makes them available in the UI, but `load()` only works after you have actually saved a block document.\n- Load and use `SnowflakeConnector` inside a single task or flow. Do not assume a live connection or cursor survives being passed between tasks.\n- Repeated `fetch_one`, `fetch_many`, and `fetch_all` calls with the same query reuse cursor state. Call `reset_cursors()` when you want to start over.\n- `externalbrowser` authentication only works in environments where an interactive browser is available.\n- If you need connector-specific behavior that the block methods do not expose, switch to `get_connection()` and use the underlying Snowflake client directly.\n\n## Version Notes For `prefect-snowflake` 0.28.7\n\n- This guide covers the PyPI package version `0.28.7`.\n- PyPI lists `0.28.7` as released on November 17, 2025.\n- PyPI lists Python `>=3.10` as the supported runtime requirement for the current package.\n\n## Official Sources Used\n\n- Prefect integrations overview: `https://docs.prefect.io/integrations/use-integrations`\n- Prefect Snowflake integration docs: `https://docs.prefect.io/latest/integrations/prefect-snowflake/`\n- Prefect Snowflake credentials API reference: `https://reference.prefect.io/prefect_snowflake/credentials/`\n- Prefect Snowflake database API reference: `https://reference.prefect.io/prefect_snowflake/database/`\n- PyPI package page: `https://pypi.org/project/prefect-snowflake/`\n"
  },
  {
    "path": "content/prefect/docs/sqlalchemy/python/DOC.md",
    "content": "---\nname: sqlalchemy\ndescription: \"Prefect SQLAlchemy integration for storing database connection settings in blocks and running sync or async SQL from Prefect flows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prefect,sqlalchemy,python,database,postgresql,sqlite,blocks\"\n---\n\n# Prefect SQLAlchemy Python Package Guide\n\n## Golden Rule\n\nUse `prefect-sqlalchemy` as the Prefect integration layer for SQLAlchemy-backed databases. Keep writing flows and tasks with core `prefect`; use `SqlAlchemyConnector` blocks to store connection settings, open SQLAlchemy engines or connections, and run SQL inside a flow.\n\nIf you only need plain SQLAlchemy outside Prefect orchestration, start with SQLAlchemy directly instead of this integration package.\n\n## Install\n\nInstall the integration package version this guide covers:\n\n```bash\npython -m pip install \"prefect-sqlalchemy==0.6.1\"\n```\n\nIf your project is also pinning Prefect itself, install them together:\n\n```bash\npython -m pip install \"prefect==3.6.21\" \"prefect-sqlalchemy==0.6.1\"\n```\n\nPrefect also supports installing the integration through the main package extra:\n\n```bash\npython -m pip install \"prefect[sqlalchemy]\"\n```\n\nSanity-check the install:\n\n```bash\npython -m pip show prefect-sqlalchemy\npython -c \"import prefect_sqlalchemy; print(prefect_sqlalchemy.__file__)\"\n```\n\n## Prerequisites And Environment\n\nBefore you save or load a named block, make sure Prefect is connected to a real API:\n\n```bash\nexport PREFECT_API_URL=\"https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>\"\nexport PREFECT_API_KEY=\"pnu_...\"\n```\n\nFor a local self-hosted API instead of Prefect Cloud:\n\n```bash\nprefect server start\nprefect config set PREFECT_API_URL=\"http://127.0.0.1:4200/api\"\n```\n\nRegister the block types after installing a new integration so they appear in Prefect:\n\n```bash\nprefect block register -m prefect_sqlalchemy\n```\n\nTypical database environment variables:\n\n```bash\nexport DB_HOST=\"db.example.internal\"\nexport DB_PORT=\"5432\"\nexport DB_NAME=\"app\"\nexport DB_USER=\"app_user\"\nexport DB_PASSWORD=\"...\"\n```\n\nDirect instantiation of a block in Python does not require a Prefect API. Saving or loading it by name does.\n\n## Create A Connector Block\n\nThe documented connector block is `SqlAlchemyConnector`. You can build it from structured connection components or from a SQLAlchemy URL string.\n\n### PostgreSQL with structured connection components\n\n```python\nimport os\n\nfrom prefect_sqlalchemy import ConnectionComponents, SqlAlchemyConnector, SyncDriver\n\n\npostgres_connector = SqlAlchemyConnector(\n    connection_info=ConnectionComponents(\n        driver=SyncDriver.POSTGRESQL_PSYCOPG2,\n        username=os.environ[\"DB_USER\"],\n        password=os.environ[\"DB_PASSWORD\"],\n        host=os.environ[\"DB_HOST\"],\n        port=int(os.environ.get(\"DB_PORT\", \"5432\")),\n        database=os.environ[\"DB_NAME\"],\n    ),\n    fetch_size=100,\n)\n\npostgres_connector.save(\"warehouse-postgres\", overwrite=True)\n```\n\n### SQLite with a connection string\n\n```python\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\nsqlite_connector = SqlAlchemyConnector(\n    connection_info=\"sqlite+pysqlite:///./app.db\"\n)\n\nsqlite_connector.save(\"local-sqlite\", overwrite=True)\n```\n\nUse a URL string when your runtime already has a complete SQLAlchemy database URL. Use `ConnectionComponents` when you want clearer typed fields for driver, host, username, and database.\n\n## Load A Saved Block In A Flow\n\nLoad the block where the database work actually happens:\n\n```python\nfrom prefect import flow, task\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\n@task\ndef load_active_users() -> list[tuple]:\n    with SqlAlchemyConnector.load(\"warehouse-postgres\") as connector:\n        rows = connector.fetch_many(\n            \"SELECT id, email FROM users WHERE is_active = true ORDER BY id\"\n        )\n        return list(rows)\n\n\n@flow(log_prints=True)\ndef sync_users() -> None:\n    for row in load_active_users():\n        print(row)\n\n\nif __name__ == \"__main__\":\n    sync_users()\n```\n\nThe block works as a context manager. That is the safest default because it closes opened resources when the block exits.\n\n## Run SQL Statements\n\n`SqlAlchemyConnector` exposes a small set of helper methods that cover the common cases.\n\n### Execute DDL or DML\n\n```python\nfrom prefect import flow\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\n@flow\ndef create_and_seed() -> None:\n    with SqlAlchemyConnector.load(\"local-sqlite\") as connector:\n        connector.execute(\n            \"CREATE TABLE IF NOT EXISTS customers (id INTEGER PRIMARY KEY, email TEXT NOT NULL)\"\n        )\n        connector.execute_many(\n            \"INSERT INTO customers (email) VALUES (:email)\",\n            seq_of_parameters=[\n                {\"email\": \"ada@example.com\"},\n                {\"email\": \"grace@example.com\"},\n            ],\n        )\n\n\nif __name__ == \"__main__\":\n    create_and_seed()\n```\n\n### Fetch one row, many rows, or all rows\n\n```python\nfrom prefect import flow\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\n@flow\ndef query_customers() -> None:\n    with SqlAlchemyConnector.load(\"local-sqlite\") as connector:\n        first_row = connector.fetch_one(\n            \"SELECT id, email FROM customers ORDER BY id\"\n        )\n        print(first_row)\n\n        next_rows = connector.fetch_many(\n            \"SELECT id, email FROM customers ORDER BY id\",\n            size=10,\n        )\n        print(list(next_rows))\n\n        connector.reset_connections()\n\n        all_rows = connector.fetch_all(\n            \"SELECT id, email FROM customers ORDER BY id\"\n        )\n        print(list(all_rows))\n\n\nif __name__ == \"__main__\":\n    query_customers()\n```\n\nWhy `reset_connections()` matters: the connector caches opened connections and result objects. Repeating the same fetch operation without a reset can advance through an existing result set instead of re-running the SQL from the beginning.\n\n## Use Raw SQLAlchemy Clients When Needed\n\nIf you need an engine or a low-level connection, the block can return SQLAlchemy clients directly.\n\n```python\nfrom sqlalchemy import text\n\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\nwith SqlAlchemyConnector.load(\"warehouse-postgres\") as connector:\n    engine = connector.get_client(\"engine\")\n    with engine.begin() as connection:\n        result = connection.execute(text(\"SELECT 1\"))\n        print(result.scalar())\n```\n\nYou can also request a connection from the block itself:\n\n```python\nfrom sqlalchemy import text\n\nfrom prefect_sqlalchemy import SqlAlchemyConnector\n\n\nwith SqlAlchemyConnector.load(\"warehouse-postgres\") as connector:\n    connection = connector.get_connection(begin=False)\n    try:\n        result = connection.execute(text(\"SELECT current_database()\"))\n        print(result.scalar())\n    finally:\n        connection.close()\n```\n\nUse these lower-level entry points when existing SQLAlchemy code already expects an engine or connection object.\n\n## Async Usage\n\nThe SDK reference documents async support on `SqlAlchemyConnector` when you configure an async driver.\n\n```python\nimport asyncio\nimport os\n\nfrom prefect_sqlalchemy import AsyncDriver, ConnectionComponents, SqlAlchemyConnector\n\n\nasync def main() -> None:\n    connector = SqlAlchemyConnector(\n        connection_info=ConnectionComponents(\n            driver=AsyncDriver.POSTGRESQL_ASYNCPG,\n            username=os.environ[\"DB_USER\"],\n            password=os.environ[\"DB_PASSWORD\"],\n            host=os.environ[\"DB_HOST\"],\n            port=int(os.environ.get(\"DB_PORT\", \"5432\")),\n            database=os.environ[\"DB_NAME\"],\n        )\n    )\n    async with connector as loaded:\n        rows = await loaded.fetch_all(\"SELECT id, email FROM users ORDER BY id\")\n        print(list(rows))\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nUse the async pattern only when the driver is async, such as `postgresql+asyncpg` or `sqlite+aiosqlite`.\n\n## Common Pitfalls\n\n- Installing `prefect-sqlalchemy` does not replace core `prefect`; you still use `prefect` for `@flow`, `@task`, deployments, workers, and configuration.\n- Saving or loading a block by name requires a reachable Prefect API. Direct instantiation in Python does not.\n- Register block types after installation with `prefect block register -m prefect_sqlalchemy` or the block may not appear in the UI.\n- Keep database credentials in environment variables, your secret manager, or Prefect blocks. Do not hard-code them in flow source.\n- The runtime environment that executes the flow still needs the database driver that matches your SQLAlchemy URL or documented driver enum.\n- Prefer using the block as a context manager. The SDK reference explicitly recommends this when blocks cross task or flow boundaries.\n- If you repeat a fetch and get the \"next\" rows instead of the full result again, call `reset_connections()` for sync usage or `reset_async_connections()` for async usage before re-running the query.\n\n## Version Notes For `prefect-sqlalchemy` 0.6.1\n\n- This guide covers the PyPI package version `0.6.1`.\n- The current Prefect integrations page shows async examples, but the SDK reference is the reliable source for the concrete async API surface. Follow the `SqlAlchemyConnector` reference methods shown above when you need async support.\n- Treat this package as a Prefect integration layered on top of SQLAlchemy, not as a replacement for SQLAlchemy's own engine, dialect, or ORM documentation.\n\n## Official Sources\n\n- Prefect docs root: `https://docs.prefect.io/v3/`\n- Prefect integrations overview: `https://docs.prefect.io/integrations/`\n- Prefect SQLAlchemy integration page: `https://docs.prefect.io/integrations/prefect-sqlalchemy`\n- Prefect integrations install guidance: `https://docs.prefect.io/integrations/use-integrations`\n- Prefect SQLAlchemy SDK reference: `https://reference.prefect.io/prefect_sqlalchemy/database/`\n- Prefect SQLAlchemy credentials reference: `https://reference.prefect.io/prefect_sqlalchemy/credentials/`\n- Prefect settings and profiles: `https://docs.prefect.io/v3/concepts/settings-and-profiles`\n- PyPI package page: `https://pypi.org/project/prefect-sqlalchemy/`\n"
  },
  {
    "path": "content/prettier/docs/prettier/javascript/DOC.md",
    "content": "---\nname: prettier\ndescription: \"Prettier 3 guide for JavaScript projects, including CLI usage, config files, ignore rules, and the async Node API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.8.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,prettier,formatting,code-style,cli\"\n---\n\n# Prettier JavaScript Guide\n\n## Golden Rule\n\nInstall `prettier` as a development dependency and use either:\n\n- the CLI for project-wide formatting and CI checks\n- the async `prettier` Node API for generators, codemods, and custom tooling\n\nPrettier does not require authentication, API keys, service accounts, or package-specific environment variables.\n\n```bash\nnpm install -D prettier\n```\n\n## Recommended Project Setup\n\n### Add package scripts\n\n```json\n{\n  \"scripts\": {\n    \"format\": \"prettier . --write\",\n    \"format:check\": \"prettier . --check\"\n  }\n}\n```\n\n- `prettier . --write` rewrites matching files in place.\n- `prettier . --check` is the safer CI command because it exits non-zero when formatting is needed.\n\n### Add a Prettier config file\n\nCreate `.prettierrc.json` in your project root:\n\n```json\n{\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"printWidth\": 100\n}\n```\n\nPrettier resolves config from the file path you format. It can also read `.editorconfig` unless you disable that behavior with `--no-editorconfig` in the CLI or `editorconfig: false` in the API.\n\n### Ignore generated output and vendored files\n\nCreate `.prettierignore` in the project root:\n\n```gitignore\ndist\ncoverage\nnode_modules\n*.min.js\n```\n\n## Common CLI Workflows\n\n### Format the whole project\n\n```bash\nnpx prettier . --write\n```\n\n### Check formatting in CI\n\n```bash\nnpx prettier . --check\n```\n\n### List only files that need formatting\n\n```bash\nnpx prettier . --list-different\n```\n\n### Format a single file\n\n```bash\nnpx prettier src/index.js --write\n```\n\n### Format piped input and still infer the parser from a filename\n\n```bash\ncat src/index.js | npx prettier --stdin-filepath src/index.js\n```\n\n`--stdin-filepath` is the important flag when your code comes from stdin, because it lets Prettier infer the correct parser and apply the matching config.\n\n### Find the config file Prettier will use\n\n```bash\nnpx prettier --find-config-path src/index.js\n```\n\n## Use Prettier From Node.js\n\nPrettier's Node API is async in Prettier 3. Use `await` with `format`, `check`, `resolveConfig`, `resolveConfigFile`, `getFileInfo`, and `getSupportInfo`.\n\n### Format a file using the project's config\n\n```javascript\nconst { readFile, writeFile } = require(\"node:fs/promises\");\nconst prettier = require(\"prettier\");\n\nasync function formatFile(filePath) {\n  const input = await readFile(filePath, \"utf8\");\n  const options = (await prettier.resolveConfig(filePath)) ?? {};\n\n  const output = await prettier.format(input, {\n    ...options,\n    filepath: filePath,\n  });\n\n  if (output !== input) {\n    await writeFile(filePath, output, \"utf8\");\n  }\n}\n```\n\nPassing `filepath` is the safest default for real files because Prettier uses it to infer the parser and discover the right config.\n\n### Format generated JavaScript before writing it to disk\n\n```javascript\nconst prettier = require(\"prettier\");\n\nasync function formatGeneratedModule(source) {\n  return prettier.format(source, {\n    parser: \"babel\",\n    singleQuote: true,\n    trailingComma: \"all\",\n  });\n}\n```\n\nUse an explicit `parser` when you are formatting a snippet that does not already have a meaningful file path.\n\n### Check whether source is already formatted\n\n```javascript\nconst prettier = require(\"prettier\");\n\nasync function isFormatted(source, filePath) {\n  const options = (await prettier.resolveConfig(filePath)) ?? {};\n\n  return prettier.check(source, {\n    ...options,\n    filepath: filePath,\n  });\n}\n```\n\n### Skip ignored or unsupported files in custom tooling\n\n```javascript\nconst { readFile } = require(\"node:fs/promises\");\nconst prettier = require(\"prettier\");\n\nasync function formatIfSupported(filePath) {\n  const info = await prettier.getFileInfo(filePath);\n\n  if (info.ignored || !info.inferredParser) {\n    return null;\n  }\n\n  const input = await readFile(filePath, \"utf8\");\n  const options = (await prettier.resolveConfig(filePath)) ?? {};\n\n  return prettier.format(input, {\n    ...options,\n    filepath: filePath,\n  });\n}\n```\n\n## Practical Notes\n\n- Prettier already supports JavaScript, TypeScript, JSX, JSON, CSS, HTML, Markdown, YAML, GraphQL, and other common file types out of the box.\n- For languages outside the built-in set, install the appropriate Prettier plugin and load it through the CLI `--plugin` flag or the API `plugins` option.\n- The CLI ignores `node_modules` by default. Use `--with-node-modules` only when you explicitly want to format files there.\n- If you are writing an editor or long-running tool that watches config files, call `await prettier.clearConfigCache()` after config changes.\n\n## Important Pitfalls\n\n- Do not treat the Node API as synchronous in Prettier 3; the core methods shown here return promises.\n- Prefer `filepath` for files on disk instead of hard-coding `parser`, so Prettier can infer the parser and locate config automatically.\n- Use `--check` or `--list-different` in CI, not `--write`.\n- `--write` edits files in place. Keep it for local formatting commands and pre-commit hooks.\n- If stdin formatting gives the wrong parser, add `--stdin-filepath`.\n\n## Version Notes\n\n- This guide targets `prettier` `3.8.1`.\n- The API examples here follow the async Prettier 3 API shape documented for the current 3.x line.\n\n## Official Sources\n\n- https://www.npmjs.com/package/prettier\n- https://prettier.io/docs/en/\n- https://prettier.io/docs/en/install.html\n- https://prettier.io/docs/en/options.html\n- https://prettier.io/docs/en/cli.html\n- https://prettier.io/docs/en/configuration.html\n- https://prettier.io/docs/en/api.html\n- https://prettier.io/docs/en/ignore.html\n- https://prettier.io/docs/en/plugins.html\n"
  },
  {
    "path": "content/prettytable/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PrettyTable package guide for building formatted text, HTML, JSON, CSV, LaTeX, and Markdown tables in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.17.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"prettytable,python,table,terminal,html,csv\"\n---\n\n# PrettyTable Python Package Guide\n\n## Golden Rule\n\nUse the maintained `prettytable` package for rendering small tabular datasets in Python. It does not need credentials or environment variables; initialize a `PrettyTable` or `ColorTable` object in code and format the output you need.\n\n## Install\n\n`prettytable 3.17.0` requires Python 3.10 or newer.\n\n```bash\npython -m pip install \"prettytable==3.17.0\"\n```\n\nIf you are adding it to a project dependency file:\n\n```bash\nuv add \"prettytable==3.17.0\"\npoetry add \"prettytable==3.17.0\"\n```\n\n## Initialize A Table\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"team\", \"points\"]\ntable.add_row([\"Ada\", \"red\", 12])\ntable.add_row([\"Lin\", \"blue\", 8])\n\nprint(table)\n```\n\nYou can also pass rows in one call:\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"team\", \"points\"]\ntable.add_rows(\n    [\n        [\"Ada\", \"red\", 12],\n        [\"Lin\", \"blue\", 8],\n        [\"Sam\", \"red\", 15],\n    ]\n)\n\nprint(table.get_string())\n```\n\n## Common Display Controls\n\nUse table attributes when you want a persistent layout, or pass options to `get_string()` when the formatting is specific to one output.\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"team\", \"points\"]\ntable.add_rows(\n    [\n        [\"Ada\", \"red\", 12],\n        [\"Lin\", \"blue\", 8],\n        [\"Sam\", \"red\", 15],\n    ]\n)\n\ntable.align = {\"name\": \"l\", \"team\": \"l\", \"points\": \"r\"}\ntable.sortby = \"points\"\ntable.reversesort = True\n\nprint(table.get_string(fields=[\"name\", \"points\"]))\n```\n\nUseful options from the maintainer docs:\n\n- `fields`: choose a subset of columns for one render\n- `start` and `end`: slice rows for one render\n- `row_filter`: include only rows that match a predicate\n- `sortby` and `reversesort`: sort at render time\n- `align`: set left, center, or right alignment per column\n- `max_width`: wrap wide content by column\n- `none_format`: replace `None` values with a display string\n\n`3.17.0` explicitly documents dictionary values for column-specific attributes, so patterns like `table.align = {\"name\": \"l\"}` and `table.none_format = {\"points\": \"-\"}` are part of the supported API.\n\n## Import Data From CSV Or A DB Cursor\n\nBuild a table directly from a CSV reader target:\n\n```python\nfrom pathlib import Path\n\nfrom prettytable import from_csv\n\nwith Path(\"scores.csv\").open(newline=\"\", encoding=\"utf-8\") as fp:\n    table = from_csv(fp)\n\nprint(table)\n```\n\nBuild a table from a DB-API cursor after executing a query:\n\n```python\nimport sqlite3\n\nfrom prettytable import from_db_cursor\n\nconn = sqlite3.connect(\":memory:\")\ncur = conn.cursor()\ncur.execute(\"CREATE TABLE users (id INTEGER, name TEXT)\")\ncur.executemany(\n    \"INSERT INTO users VALUES (?, ?)\",\n    [(1, \"Ada\"), (2, \"Lin\")],\n)\ncur.execute(\"SELECT id, name FROM users ORDER BY id\")\n\ntable = from_db_cursor(cur)\nprint(table)\n```\n\n## Export Other Formats\n\nPrettyTable can render more than plain terminal text.\n\n### HTML\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"team\"]\ntable.add_row([\"Ada\", \"red\"])\n\nhtml = table.get_html_string(format=True, attributes={\"class\": \"scores\"})\nprint(html)\n```\n\n### JSON\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"points\"]\ntable.add_rows([[\"Ada\", 12], [\"Lin\", 8]])\n\njson_text = table.get_json_string()\nprint(json_text)\n```\n\n### CSV, LaTeX, MediaWiki, Or Format-Selected Output\n\n```python\nfrom prettytable import PrettyTable\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"points\"]\ntable.add_rows([[\"Ada\", 12], [\"Lin\", 8]])\n\nprint(table.get_formatted_string(out_format=\"csv\"))\nprint(table.get_formatted_string(out_format=\"latex\"))\nprint(table.get_mediawiki_string())\nprint(table.get_formatted_string(out_format=\"json\"))\n```\n\n## Markdown And Table Styles\n\nUse `TableStyle` when you need a specific border and separator layout.\n\n```python\nfrom prettytable import PrettyTable, TableStyle\n\ntable = PrettyTable()\ntable.field_names = [\"name\", \"points\"]\ntable.add_rows([[\"Ada\", 12], [\"Lin\", 8]])\n\ntable.set_style(TableStyle.MARKDOWN)\nprint(table)\n```\n\nOther documented built-in styles include `DEFAULT`, `PLAIN_COLUMNS`, `MSWORD_FRIENDLY`, `ORGMODE`, `DOUBLE_BORDER`, and `SINGLE_BORDER`.\n\nFor ANSI-colored terminal output:\n\n```python\nfrom prettytable.colortable import ColorTable, Themes\n\ntable = ColorTable(theme=Themes.OCEAN)\ntable.field_names = [\"service\", \"status\"]\ntable.add_rows(\n    [\n        [\"api\", \"ok\"],\n        [\"worker\", \"degraded\"],\n    ]\n)\n\nprint(table)\n```\n\n## Common Pitfalls\n\n- `field_names` must match the number of values in each row. Mismatched row lengths raise errors.\n- `sortby` must name an existing field, so set `field_names` before relying on sorting or field selection.\n- HTML output escapes cell data by default. Only disable escaping if you are intentionally emitting trusted HTML.\n- Rendering helpers like `get_html_string()` and `get_json_string()` return strings; they do not write files for you.\n- PrettyTable is best for presentation, not large-data processing. Materialize and filter your data before formatting it into a table.\n\n## Version-Sensitive Notes For 3.17.0\n\n- `prettytable 3.17.0` raises the minimum supported Python version to 3.10 and adds Python 3.15 support.\n- The `3.17.0` release notes call out improved support for dictionary values across column-specific attributes and additional docs around `none_format`.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/jazzband/prettytable\n- README and usage examples: https://github.com/jazzband/prettytable/blob/main/README.md\n- `3.17.0` release notes: https://github.com/prettytable/prettytable/releases/tag/3.17.0\n- PyPI package page: https://pypi.org/project/prettytable/\n- PyPI version page for `3.17.0`: https://pypi.org/project/prettytable/3.17.0/\n"
  },
  {
    "path": "content/prisma/docs/orm/javascript/DOC.md",
    "content": "---\nname: orm\ndescription: \"Prisma ORM client for JavaScript/TypeScript with type-safe database access and migrations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.19.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"prisma,orm,database,typescript,migrations\"\n---\n\n# Prisma ORM - JavaScript/TypeScript\n\n## Golden Rule\n\n**ALWAYS use `@prisma/client` version 6.19.0+ with the `prisma` CLI for development.**\n\n```bash\nnpm install @prisma/client@6.19.0\nnpm install -D prisma@6.19.0\n```\n\n**DO NOT** use deprecated packages like:\n- `@prisma/cli` (deprecated - use `prisma` instead)\n- Old Prisma 1.x packages\n- Unofficial Prisma wrappers\n\nPrisma ORM is the official next-generation ORM for Node.js and TypeScript. It provides type-safe database access, auto-completion, and an intuitive data modeling experience.\n\n---\n\n## Installation\n\n### Step 1: Install Dependencies\n\n```bash\nnpm install @prisma/client\nnpm install -D prisma typescript tsx @types/node\n```\n\n### Step 2: Initialize Prisma\n\n```bash\nnpx prisma init --datasource-provider postgresql\n```\n\nThis creates:\n- `prisma/schema.prisma` - Your database schema\n- `.env` - Environment variables file\n\n### Step 3: Configure Database Connection\n\nEdit `.env`:\n\n```env\nDATABASE_URL=\"postgresql://user:password@localhost:5432/mydb?schema=public\"\n```\n\nFor other databases:\n\n```env\n# MySQL\nDATABASE_URL=\"mysql://user:password@localhost:3306/mydb\"\n\n# SQLite\nDATABASE_URL=\"file:./dev.db\"\n\n# MongoDB\nDATABASE_URL=\"mongodb+srv://user:password@cluster.mongodb.net/mydb\"\n\n# SQL Server\nDATABASE_URL=\"sqlserver://localhost:1433;database=mydb;user=sa;password=password;encrypt=true\"\n```\n\n### Step 4: Initialize TypeScript (if needed)\n\n```bash\nnpx tsc --init\n```\n\n---\n\n## Initialization\n\n### Basic Client Setup\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient()\n\nasync function main() {\n  // Your database queries here\n}\n\nmain()\n  .catch((e) => {\n    console.error(e)\n    process.exit(1)\n  })\n  .finally(async () => {\n    await prisma.$disconnect()\n  })\n```\n\n### Client with Logging\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient({\n  log: ['query', 'info', 'warn', 'error'],\n})\n```\n\n### Client with Error Formatting\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient({\n  errorFormat: 'pretty', // 'pretty' | 'colorless' | 'minimal'\n})\n```\n\n### Environment-Based Configuration\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient({\n  datasources: {\n    db: {\n      url: process.env.DATABASE_URL,\n    },\n  },\n})\n```\n\n---\n\n## Schema Definition\n\n### Basic Schema Structure\n\n```prisma\n// prisma/schema.prisma\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  name      String?\n  createdAt DateTime @default(now())\n  updatedAt DateTime @updatedAt\n}\n```\n\n### Field Types\n\n```prisma\nmodel Example {\n  id        Int      @id @default(autoincrement())\n  string    String\n  int       Int\n  bigInt    BigInt\n  float     Float\n  decimal   Decimal\n  boolean   Boolean\n  dateTime  DateTime\n  json      Json\n  bytes     Bytes\n  optional  String?\n  array     String[]\n}\n```\n\n### Field Attributes\n\n```prisma\nmodel User {\n  id        Int      @id @default(autoincrement())\n  uuid      String   @default(uuid())\n  email     String   @unique\n  role      String   @default(\"USER\")\n  createdAt DateTime @default(now())\n  updatedAt DateTime @updatedAt\n\n  @@unique([email, name])\n  @@index([email])\n  @@map(\"users\")\n}\n```\n\n### Enums\n\n```prisma\nenum Role {\n  USER\n  ADMIN\n  MODERATOR\n}\n\nmodel User {\n  id   Int  @id @default(autoincrement())\n  role Role @default(USER)\n}\n```\n\n---\n\n## Relations\n\n### One-to-One\n\n```prisma\nmodel User {\n  id      Int      @id @default(autoincrement())\n  email   String   @unique\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  bio    String\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n}\n```\n\n### One-to-Many\n\n```prisma\nmodel User {\n  id    Int    @id @default(autoincrement())\n  email String @unique\n  posts Post[]\n}\n\nmodel Post {\n  id       Int    @id @default(autoincrement())\n  title    String\n  author   User   @relation(fields: [authorId], references: [id])\n  authorId Int\n}\n```\n\n### Many-to-Many (Implicit)\n\n```prisma\nmodel Post {\n  id         Int        @id @default(autoincrement())\n  title      String\n  categories Category[]\n}\n\nmodel Category {\n  id    Int    @id @default(autoincrement())\n  name  String\n  posts Post[]\n}\n```\n\n### Many-to-Many (Explicit)\n\n```prisma\nmodel Post {\n  id               Int                @id @default(autoincrement())\n  title            String\n  postCategories   PostCategory[]\n}\n\nmodel Category {\n  id               Int                @id @default(autoincrement())\n  name             String\n  postCategories   PostCategory[]\n}\n\nmodel PostCategory {\n  post       Post     @relation(fields: [postId], references: [id])\n  postId     Int\n  category   Category @relation(fields: [categoryId], references: [id])\n  categoryId Int\n  assignedAt DateTime @default(now())\n\n  @@id([postId, categoryId])\n}\n```\n\n### Self-Relations\n\n```prisma\nmodel User {\n  id         Int    @id @default(autoincrement())\n  name       String\n  invitedBy  User?  @relation(\"UserInvites\", fields: [inviterId], references: [id])\n  inviterId  Int?\n  invites    User[] @relation(\"UserInvites\")\n}\n```\n\n---\n\n## Migrations\n\n### Create Migration\n\n```bash\nnpx prisma migrate dev --name init\n```\n\n### Apply Migrations in Production\n\n```bash\nnpx prisma migrate deploy\n```\n\n### Reset Database\n\n```bash\nnpx prisma migrate reset\n```\n\n### Generate Client After Schema Changes\n\n```bash\nnpx prisma generate\n```\n\n---\n\n## CRUD Operations\n\n### Create\n\n#### Single Record\n\n```typescript\nconst user = await prisma.user.create({\n  data: {\n    email: 'alice@prisma.io',\n    name: 'Alice',\n  },\n})\n```\n\n#### Multiple Records\n\n```typescript\nconst users = await prisma.user.createMany({\n  data: [\n    { email: 'bob@prisma.io', name: 'Bob' },\n    { email: 'charlie@prisma.io', name: 'Charlie' },\n  ],\n  skipDuplicates: true,\n})\n```\n\n#### Create and Return Multiple (v5.14.0+)\n\n```typescript\nconst users = await prisma.user.createManyAndReturn({\n  data: [\n    { email: 'alice@prisma.io', name: 'Alice' },\n    { email: 'bob@prisma.io', name: 'Bob' },\n  ],\n})\n```\n\n#### Create with Relations\n\n```typescript\nconst user = await prisma.user.create({\n  data: {\n    email: 'alice@prisma.io',\n    name: 'Alice',\n    posts: {\n      create: [\n        { title: 'First Post' },\n        { title: 'Second Post' },\n      ],\n    },\n  },\n})\n```\n\n#### Create with Nested Relations\n\n```typescript\nconst user = await prisma.user.create({\n  data: {\n    email: 'alice@prisma.io',\n    posts: {\n      create: {\n        title: 'Hello World',\n        categories: {\n          create: [\n            { name: 'Tech' },\n            { name: 'News' },\n          ],\n        },\n      },\n    },\n  },\n})\n```\n\n### Read\n\n#### Find Unique\n\n```typescript\nconst user = await prisma.user.findUnique({\n  where: { email: 'alice@prisma.io' },\n})\n```\n\n#### Find Unique or Throw\n\n```typescript\nconst user = await prisma.user.findUniqueOrThrow({\n  where: { id: 1 },\n})\n```\n\n#### Find First\n\n```typescript\nconst user = await prisma.user.findFirst({\n  where: {\n    posts: {\n      some: {\n        likes: { gt: 100 },\n      },\n    },\n  },\n  orderBy: { id: 'desc' },\n})\n```\n\n#### Find First or Throw\n\n```typescript\nconst user = await prisma.user.findFirstOrThrow({\n  where: { email: { contains: 'prisma.io' } },\n})\n```\n\n#### Find Many\n\n```typescript\nconst users = await prisma.user.findMany()\n```\n\n#### Find Many with Filter\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    email: { endsWith: 'prisma.io' },\n    posts: {\n      some: {\n        published: true,\n      },\n    },\n  },\n})\n```\n\n#### Select Specific Fields\n\n```typescript\nconst user = await prisma.user.findUnique({\n  where: { email: 'alice@prisma.io' },\n  select: {\n    id: true,\n    email: true,\n    name: true,\n  },\n})\n```\n\n#### Include Relations\n\n```typescript\nconst users = await prisma.user.findMany({\n  include: {\n    posts: true,\n  },\n})\n```\n\n#### Include with Nested Relations\n\n```typescript\nconst users = await prisma.user.findMany({\n  include: {\n    posts: {\n      include: {\n        categories: true,\n      },\n    },\n  },\n})\n```\n\n#### Include with Filtering\n\n```typescript\nconst users = await prisma.user.findMany({\n  include: {\n    posts: {\n      where: {\n        published: true,\n      },\n      orderBy: {\n        createdAt: 'desc',\n      },\n      take: 5,\n    },\n  },\n})\n```\n\n### Update\n\n#### Update Single Record\n\n```typescript\nconst user = await prisma.user.update({\n  where: { email: 'alice@prisma.io' },\n  data: { name: 'Alice Smith' },\n})\n```\n\n#### Update Multiple Records\n\n```typescript\nconst users = await prisma.user.updateMany({\n  where: {\n    email: { contains: 'prisma.io' },\n  },\n  data: {\n    role: 'ADMIN',\n  },\n})\n```\n\n#### Update and Return Multiple (v6.2.0+)\n\n```typescript\nconst users = await prisma.user.updateManyAndReturn({\n  where: { email: { contains: 'prisma.io' } },\n  data: { role: 'ADMIN' },\n})\n```\n\n#### Upsert (Update or Create)\n\n```typescript\nconst user = await prisma.user.upsert({\n  where: { email: 'alice@prisma.io' },\n  update: { name: 'Alice Updated' },\n  create: {\n    email: 'alice@prisma.io',\n    name: 'Alice',\n  },\n})\n```\n\n#### Atomic Number Operations\n\n```typescript\nconst post = await prisma.post.update({\n  where: { id: 1 },\n  data: {\n    views: { increment: 1 },\n    likes: { increment: 5 },\n  },\n})\n```\n\n```typescript\nconst post = await prisma.post.update({\n  where: { id: 1 },\n  data: {\n    views: { decrement: 1 },\n    score: { multiply: 2 },\n    total: { divide: 10 },\n  },\n})\n```\n\n#### Update with Relations\n\n```typescript\nconst user = await prisma.user.update({\n  where: { id: 1 },\n  data: {\n    posts: {\n      create: { title: 'New Post' },\n    },\n  },\n})\n```\n\n#### Connect Existing Relations\n\n```typescript\nconst user = await prisma.user.update({\n  where: { id: 1 },\n  data: {\n    posts: {\n      connect: { id: 5 },\n    },\n  },\n})\n```\n\n#### Disconnect Relations\n\n```typescript\nconst user = await prisma.user.update({\n  where: { id: 1 },\n  data: {\n    posts: {\n      disconnect: { id: 5 },\n    },\n  },\n})\n```\n\n### Delete\n\n#### Delete Single Record\n\n```typescript\nconst user = await prisma.user.delete({\n  where: { email: 'alice@prisma.io' },\n})\n```\n\n#### Delete Multiple Records\n\n```typescript\nconst users = await prisma.user.deleteMany({\n  where: {\n    email: { contains: 'prisma.io' },\n  },\n})\n```\n\n#### Delete All Records\n\n```typescript\nconst users = await prisma.user.deleteMany({})\n```\n\n---\n\n## Filtering and Sorting\n\n### Basic Filters\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    email: { equals: 'alice@prisma.io' },\n    name: { not: 'Bob' },\n    age: { gt: 18 },\n  },\n})\n```\n\n### String Filters\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    email: { startsWith: 'alice' },\n    name: { endsWith: 'Smith' },\n    bio: { contains: 'developer' },\n  },\n})\n```\n\n### Number Filters\n\n```typescript\nconst posts = await prisma.post.findMany({\n  where: {\n    views: { gt: 100 },\n    likes: { gte: 50 },\n    comments: { lt: 10 },\n    shares: { lte: 5 },\n    rating: { in: [4, 5] },\n    score: { notIn: [0, 1] },\n  },\n})\n```\n\n### Logical Operators\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    OR: [\n      { email: { contains: 'prisma.io' } },\n      { name: { contains: 'Alice' } },\n    ],\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    AND: [\n      { email: { contains: 'prisma.io' } },\n      { role: 'ADMIN' },\n    ],\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    NOT: {\n      email: { contains: 'spam.com' },\n    },\n  },\n})\n```\n\n### Relation Filters\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    posts: {\n      some: {\n        published: true,\n      },\n    },\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    posts: {\n      every: {\n        published: true,\n      },\n    },\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    posts: {\n      none: {\n        published: false,\n      },\n    },\n  },\n})\n```\n\n### Sorting\n\n```typescript\nconst users = await prisma.user.findMany({\n  orderBy: {\n    name: 'asc',\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  orderBy: [\n    { role: 'desc' },\n    { name: 'asc' },\n  ],\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  orderBy: {\n    posts: {\n      _count: 'desc',\n    },\n  },\n})\n```\n\n---\n\n## Pagination\n\n### Offset Pagination\n\n```typescript\nconst users = await prisma.user.findMany({\n  skip: 10,\n  take: 10,\n})\n```\n\n### Cursor-Based Pagination\n\n```typescript\nconst users = await prisma.user.findMany({\n  take: 10,\n  cursor: {\n    id: lastUserId,\n  },\n  skip: 1, // Skip cursor itself\n})\n```\n\n---\n\n## Aggregation\n\n### Count\n\n```typescript\nconst count = await prisma.user.count()\n```\n\n```typescript\nconst count = await prisma.user.count({\n  where: {\n    email: { contains: 'prisma.io' },\n  },\n})\n```\n\n### Aggregate Operations\n\n```typescript\nconst result = await prisma.post.aggregate({\n  _count: {\n    _all: true,\n  },\n  _avg: {\n    views: true,\n    likes: true,\n  },\n  _sum: {\n    views: true,\n  },\n  _min: {\n    createdAt: true,\n  },\n  _max: {\n    createdAt: true,\n  },\n})\n```\n\n### Group By\n\n```typescript\nconst result = await prisma.user.groupBy({\n  by: ['role'],\n  _count: {\n    _all: true,\n  },\n})\n```\n\n```typescript\nconst result = await prisma.user.groupBy({\n  by: ['country'],\n  _sum: {\n    profileViews: true,\n  },\n  _avg: {\n    age: true,\n  },\n  having: {\n    age: {\n      _avg: {\n        gt: 18,\n      },\n    },\n  },\n})\n```\n\n```typescript\nconst result = await prisma.post.groupBy({\n  by: ['authorId'],\n  _count: {\n    _all: true,\n  },\n  orderBy: {\n    _count: {\n      _all: 'desc',\n    },\n  },\n})\n```\n\n---\n\n## Transactions\n\n### Sequential Operations Transaction\n\n```typescript\nconst [deletedPosts, deletedUser] = await prisma.$transaction([\n  prisma.post.deleteMany({ where: { authorId: 1 } }),\n  prisma.user.delete({ where: { id: 1 } }),\n])\n```\n\n### Interactive Transaction\n\n```typescript\nconst result = await prisma.$transaction(async (tx) => {\n  const user = await tx.user.create({\n    data: { email: 'alice@prisma.io', name: 'Alice' },\n  })\n\n  const post = await tx.post.create({\n    data: {\n      title: 'Hello World',\n      authorId: user.id,\n    },\n  })\n\n  return { user, post }\n})\n```\n\n### Transaction with Timeout\n\n```typescript\nconst result = await prisma.$transaction(\n  async (tx) => {\n    // Operations here\n  },\n  {\n    maxWait: 5000, // Wait max 5s to start transaction\n    timeout: 10000, // Max 10s for transaction\n  }\n)\n```\n\n### Transaction with Isolation Level\n\n```typescript\nconst result = await prisma.$transaction(\n  async (tx) => {\n    // Operations here\n  },\n  {\n    isolationLevel: 'Serializable',\n  }\n)\n```\n\n---\n\n## Raw Queries\n\n### Raw Query (Read)\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient()\n\nconst users = await prisma.$queryRaw`\n  SELECT * FROM \"User\" WHERE \"email\" = ${'alice@prisma.io'}\n`\n```\n\n### Raw Execute (Write)\n\n```typescript\nconst result = await prisma.$executeRaw`\n  UPDATE \"User\" SET \"name\" = ${'Alice'} WHERE \"id\" = ${1}\n`\n```\n\n### Raw Query Unsafe (Use with Caution)\n\n```typescript\nconst users = await prisma.$queryRawUnsafe(\n  'SELECT * FROM User WHERE id = ?',\n  1\n)\n```\n\n### Raw Queries in Transactions\n\n```typescript\nconst [users, count] = await prisma.$transaction([\n  prisma.$queryRaw`SELECT * FROM \"User\"`,\n  prisma.$executeRaw`UPDATE \"User\" SET \"role\" = 'ADMIN' WHERE \"id\" = ${1}`,\n])\n```\n\n---\n\n## Advanced Features\n\n### Distinct\n\n```typescript\nconst distinctEmails = await prisma.user.findMany({\n  distinct: ['email'],\n})\n```\n\n### Null Filtering\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    name: { not: null },\n  },\n})\n```\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    name: null,\n  },\n})\n```\n\n### Case-Insensitive Filtering (PostgreSQL, MongoDB)\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    email: {\n      equals: 'ALICE@PRISMA.IO',\n      mode: 'insensitive',\n    },\n  },\n})\n```\n\n### Full-Text Search (PostgreSQL)\n\n```typescript\nconst posts = await prisma.post.findMany({\n  where: {\n    title: {\n      search: 'database | prisma',\n    },\n  },\n})\n```\n\n### JSON Filtering\n\n```typescript\nconst users = await prisma.user.findMany({\n  where: {\n    metadata: {\n      path: ['tags'],\n      array_contains: 'developer',\n    },\n  },\n})\n```\n\n---\n\n## Client Extensions\n\n### Custom Result Fields\n\n```typescript\nconst prisma = new PrismaClient().$extends({\n  result: {\n    user: {\n      fullName: {\n        needs: { firstName: true, lastName: true },\n        compute(user) {\n          return `${user.firstName} ${user.lastName}`\n        },\n      },\n    },\n  },\n})\n\nconst user = await prisma.user.findUnique({\n  where: { id: 1 },\n})\n\nconsole.log(user.fullName)\n```\n\n### Custom Model Methods\n\n```typescript\nconst prisma = new PrismaClient().$extends({\n  model: {\n    user: {\n      async findByEmail(email: string) {\n        return await prisma.user.findUnique({\n          where: { email },\n        })\n      },\n    },\n  },\n})\n\nconst user = await prisma.user.findByEmail('alice@prisma.io')\n```\n\n### Query Extensions\n\n```typescript\nconst prisma = new PrismaClient().$extends({\n  query: {\n    user: {\n      async findMany({ args, query }) {\n        console.log('Finding users...')\n        return query(args)\n      },\n    },\n  },\n})\n```\n\n---\n\n## Middleware\n\n```typescript\nconst prisma = new PrismaClient()\n\nprisma.$use(async (params, next) => {\n  const before = Date.now()\n  const result = await next(params)\n  const after = Date.now()\n\n  console.log(`Query ${params.model}.${params.action} took ${after - before}ms`)\n\n  return result\n})\n```\n\n```typescript\nprisma.$use(async (params, next) => {\n  if (params.model === 'User' && params.action === 'delete') {\n    params.action = 'update'\n    params.args['data'] = { deleted: true }\n  }\n  return next(params)\n})\n```\n\n---\n\n## Error Handling\n\n### Handle Specific Errors\n\n```typescript\nimport { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'\n\ntry {\n  const user = await prisma.user.create({\n    data: { email: 'alice@prisma.io' },\n  })\n} catch (error) {\n  if (error instanceof PrismaClientKnownRequestError) {\n    if (error.code === 'P2002') {\n      console.log('Unique constraint violation')\n    }\n  }\n  throw error\n}\n```\n\n### Common Error Codes\n\n- `P2002`: Unique constraint violation\n- `P2003`: Foreign key constraint violation\n- `P2025`: Record not found\n- `P2014`: Relation violation\n\n---\n\n## Database Utilities\n\n### Connection Test\n\n```typescript\nawait prisma.$connect()\nawait prisma.$disconnect()\n```\n\n### Execute Raw SQL\n\n```typescript\nawait prisma.$executeRawUnsafe('TRUNCATE TABLE \"User\" CASCADE')\n```\n\n### Run Commands\n\n```typescript\nawait prisma.$runCommandRaw({\n  drop: 'User',\n})\n```\n\n---\n\n## Best Patterns for Code Generation\n\n### Type-Safe Queries\n\n```typescript\nimport { Prisma } from '@prisma/client'\n\nconst whereClause: Prisma.UserWhereInput = {\n  email: { contains: 'prisma.io' },\n}\n\nconst users = await prisma.user.findMany({\n  where: whereClause,\n})\n```\n\n### Reusable Query Fragments\n\n```typescript\nconst userWithPosts = Prisma.validator<Prisma.UserDefaultArgs>()({\n  include: { posts: true },\n})\n\ntype UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>\n\nconst user: UserWithPosts = await prisma.user.findUnique({\n  where: { id: 1 },\n  ...userWithPosts,\n})\n```\n\n### Type Utilities\n\n```typescript\nimport { Prisma } from '@prisma/client'\n\n// Get the type for creating a user\ntype UserCreateInput = Prisma.UserCreateInput\n\n// Get the type for a user from the database\ntype User = Prisma.UserGetPayload<{}>\n\n// Get the type for a user with relations\ntype UserWithPosts = Prisma.UserGetPayload<{\n  include: { posts: true }\n}>\n```\n\n---\n\n## Database-Specific Features\n\n### PostgreSQL\n\n```prisma\nmodel User {\n  id   Int    @id @default(autoincrement())\n  data Json   @db.JsonB\n  tags String[] @db.VarChar(255)\n}\n```\n\n### MySQL\n\n```prisma\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String @db.VarChar(255)\n  bio  String @db.Text\n}\n```\n\n### SQLite\n\n```prisma\ndatasource db {\n  provider = \"sqlite\"\n  url      = \"file:./dev.db\"\n}\n```\n\n### MongoDB\n\n```prisma\ndatasource db {\n  provider = \"mongodb\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel User {\n  id    String @id @default(auto()) @map(\"_id\") @db.ObjectId\n  email String @unique\n}\n```\n\n---\n\n## Complete Example Application\n\n```typescript\nimport { PrismaClient } from '@prisma/client'\n\nconst prisma = new PrismaClient()\n\nasync function main() {\n  // Create user with posts\n  const user = await prisma.user.create({\n    data: {\n      email: 'alice@prisma.io',\n      name: 'Alice',\n      posts: {\n        create: [\n          {\n            title: 'Getting Started with Prisma',\n            content: 'Learn how to use Prisma ORM...',\n            published: true,\n          },\n          {\n            title: 'Advanced Prisma Patterns',\n            content: 'Dive deeper into Prisma...',\n            published: false,\n          },\n        ],\n      },\n    },\n    include: {\n      posts: true,\n    },\n  })\n  console.log('Created user:', user)\n\n  // Find all published posts with author\n  const publishedPosts = await prisma.post.findMany({\n    where: { published: true },\n    include: { author: true },\n  })\n  console.log('Published posts:', publishedPosts)\n\n  // Update post\n  const updatedPost = await prisma.post.update({\n    where: { id: 1 },\n    data: {\n      views: { increment: 1 },\n    },\n  })\n  console.log('Updated post:', updatedPost)\n\n  // Aggregate data\n  const stats = await prisma.post.aggregate({\n    _count: { _all: true },\n    _avg: { views: true },\n    where: { published: true },\n  })\n  console.log('Post statistics:', stats)\n\n  // Transaction\n  const result = await prisma.$transaction(async (tx) => {\n    const newUser = await tx.user.create({\n      data: {\n        email: 'bob@prisma.io',\n        name: 'Bob',\n      },\n    })\n\n    const newPost = await tx.post.create({\n      data: {\n        title: 'Bob\\'s First Post',\n        authorId: newUser.id,\n      },\n    })\n\n    return { user: newUser, post: newPost }\n  })\n  console.log('Transaction result:', result)\n}\n\nmain()\n  .catch((e) => {\n    console.error(e)\n    process.exit(1)\n  })\n  .finally(async () => {\n    await prisma.$disconnect()\n  })\n```\n"
  },
  {
    "path": "content/prisma/docs/orm/python/DOC.md",
    "content": "---\nname: orm\ndescription: \"Prisma Client Python for type-safe database access and schema-driven development\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.15.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"prisma,orm,database,python,migrations\"\n---\n\n# Prisma Client Python\n\n## Golden Rule\n\n**ALWAYS use `prisma` (prisma-client-py) version 0.15.0+ for Python projects.**\n\n```bash\npip install prisma==0.15.0\n```\n\n**IMPORTANT NOTE:** Prisma Client Python is no longer actively maintained as of April 2025. However, version 0.15.0 remains functional and is documented here for existing projects.\n\n**DO NOT** use:\n- Old `prisma2` packages\n- Unofficial Prisma Python wrappers\n- `prisma-client` (different package on PyPI)\n\nPrisma Client Python is an auto-generated, fully type-safe database client designed for ease of use with Python applications. It provides intuitive data modeling, automated migrations, and comprehensive type safety.\n\n---\n\n## Installation\n\n### Step 1: Install Prisma\n\n```bash\npip install prisma\n```\n\n### Step 2: Create Schema File\n\nCreate `schema.prisma` in your project root:\n\n```prisma\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\ngenerator client {\n  provider             = \"prisma-client-py\"\n  recursive_type_depth = 5\n}\n\nmodel User {\n  id    Int     @id @default(autoincrement())\n  email String  @unique\n  name  String?\n}\n```\n\n### Step 3: Set Environment Variable\n\nCreate `.env` file:\n\n```env\nDATABASE_URL=\"postgresql://user:password@localhost:5432/mydb?schema=public\"\n```\n\nFor other databases:\n\n```env\n# MySQL\nDATABASE_URL=\"mysql://user:password@localhost:3306/mydb\"\n\n# SQLite\nDATABASE_URL=\"file:./dev.db\"\n\n# MongoDB\nDATABASE_URL=\"mongodb+srv://user:password@cluster.mongodb.net/mydb\"\n\n# CockroachDB\nDATABASE_URL=\"postgresql://user:password@localhost:26257/mydb\"\n```\n\n### Step 4: Generate Client and Push Schema\n\n```bash\nprisma db push\n```\n\nOr separately:\n\n```bash\nprisma generate\nprisma db push\n```\n\nFor auto-regeneration during development:\n\n```bash\nprisma generate --watch\n```\n\n---\n\n## Initialization\n\n### Async Client (Recommended)\n\n```python\nimport asyncio\nfrom prisma import Prisma\n\nasync def main() -> None:\n    db = Prisma()\n    await db.connect()\n\n    # Your database queries here\n\n    await db.disconnect()\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Sync Client\n\n```python\nfrom prisma import Prisma\n\ndb = Prisma()\ndb.connect()\n\n# Your database queries here\n\ndb.disconnect()\n```\n\n### Context Manager (Auto Connect/Disconnect)\n\n```python\nimport asyncio\nfrom prisma import Prisma\n\nasync def main() -> None:\n    async with Prisma() as db:\n        # Database operations here\n        user = await db.user.create(\n            data={'name': 'Alice', 'email': 'alice@prisma.io'}\n        )\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Client with Auto-Register (Model-Based Access)\n\n```python\nfrom prisma import Prisma\nfrom prisma.models import User\n\nasync def main() -> None:\n    db = Prisma(auto_register=True)\n    await db.connect()\n\n    # Access via model\n    user = await User.prisma().create(\n        data={'name': 'Alice', 'email': 'alice@prisma.io'}\n    )\n\n    await db.disconnect()\n```\n\n---\n\n## Schema Definition\n\n### Basic Schema\n\n```prisma\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\ngenerator client {\n  provider             = \"prisma-client-py\"\n  recursive_type_depth = 5\n}\n\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  name      String?\n  createdAt DateTime @default(now())\n  updatedAt DateTime @updatedAt\n}\n```\n\n### Field Types\n\n```prisma\nmodel Example {\n  id       Int      @id @default(autoincrement())\n  string   String\n  int      Int\n  bigInt   BigInt\n  float    Float\n  decimal  Decimal\n  boolean  Boolean\n  dateTime DateTime\n  json     Json\n  bytes    Bytes\n  optional String?\n  array    String[]\n}\n```\n\n### Field Attributes\n\n```prisma\nmodel User {\n  id        Int      @id @default(autoincrement())\n  uuid      String   @default(uuid())\n  email     String   @unique\n  role      String   @default(\"USER\")\n  createdAt DateTime @default(now())\n  updatedAt DateTime @updatedAt\n\n  @@unique([email, name])\n  @@index([email])\n  @@map(\"users\")\n}\n```\n\n### Enums\n\n```prisma\nenum Role {\n  USER\n  ADMIN\n  MODERATOR\n}\n\nmodel User {\n  id   Int  @id @default(autoincrement())\n  role Role @default(USER)\n}\n```\n\n---\n\n## Relations\n\n### One-to-One\n\n```prisma\nmodel User {\n  id      Int      @id @default(autoincrement())\n  email   String   @unique\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  bio    String\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n}\n```\n\n### One-to-Many\n\n```prisma\nmodel User {\n  id    Int    @id @default(autoincrement())\n  email String @unique\n  posts Post[]\n}\n\nmodel Post {\n  id       Int    @id @default(autoincrement())\n  title    String\n  author   User   @relation(fields: [authorId], references: [id])\n  authorId Int\n}\n```\n\n### Many-to-Many (Implicit)\n\n```prisma\nmodel Post {\n  id         Int        @id @default(autoincrement())\n  title      String\n  categories Category[]\n}\n\nmodel Category {\n  id    Int    @id @default(autoincrement())\n  name  String\n  posts Post[]\n}\n```\n\n### Many-to-Many (Explicit)\n\n```prisma\nmodel Post {\n  id             Int            @id @default(autoincrement())\n  title          String\n  postCategories PostCategory[]\n}\n\nmodel Category {\n  id             Int            @id @default(autoincrement())\n  name           String\n  postCategories PostCategory[]\n}\n\nmodel PostCategory {\n  post       Post     @relation(fields: [postId], references: [id])\n  postId     Int\n  category   Category @relation(fields: [categoryId], references: [id])\n  categoryId Int\n  assignedAt DateTime @default(now())\n\n  @@id([postId, categoryId])\n}\n```\n\n---\n\n## CRUD Operations\n\n### Create\n\n#### Single Record\n\n```python\nuser = await db.user.create(\n    data={\n        'email': 'alice@prisma.io',\n        'name': 'Alice',\n    }\n)\n```\n\n#### Multiple Records\n\n```python\ncount = await db.user.create_many(\n    data=[\n        {'email': 'bob@prisma.io', 'name': 'Bob'},\n        {'email': 'charlie@prisma.io', 'name': 'Charlie'},\n    ],\n    skip_duplicates=True,\n)\n```\n\n#### Create with Relations\n\n```python\nuser = await db.user.create(\n    data={\n        'email': 'alice@prisma.io',\n        'name': 'Alice',\n        'posts': {\n            'create': [\n                {'title': 'First Post', 'published': True},\n                {'title': 'Second Post', 'published': False},\n            ]\n        }\n    }\n)\n```\n\n#### Create with Nested Relations\n\n```python\nuser = await db.user.create(\n    data={\n        'email': 'alice@prisma.io',\n        'name': 'Alice',\n        'posts': {\n            'create': {\n                'title': 'Hello World',\n                'categories': {\n                    'create': [\n                        {'name': 'Tech'},\n                        {'name': 'News'},\n                    ]\n                }\n            }\n        }\n    }\n)\n```\n\n### Read\n\n#### Find Unique\n\n```python\nuser = await db.user.find_unique(\n    where={'email': 'alice@prisma.io'}\n)\n```\n\n#### Find Unique or Raise\n\n```python\nuser = await db.user.find_unique_or_raise(\n    where={'id': 1}\n)\n```\n\n#### Find First\n\n```python\npost = await db.post.find_first(\n    where={\n        'title': {'contains': 'Prisma'}\n    },\n    order={'createdAt': 'desc'}\n)\n```\n\n#### Find First or Raise\n\n```python\npost = await db.post.find_first_or_raise(\n    where={'published': True}\n)\n```\n\n#### Find Many\n\n```python\nusers = await db.user.find_many()\n```\n\n#### Find Many with Filter\n\n```python\nusers = await db.user.find_many(\n    where={\n        'email': {'endswith': 'prisma.io'},\n        'posts': {\n            'some': {\n                'published': True\n            }\n        }\n    }\n)\n```\n\n#### Include Relations\n\n```python\nusers = await db.user.find_many(\n    include={'posts': True}\n)\n```\n\n#### Include with Nested Relations\n\n```python\nusers = await db.user.find_many(\n    include={\n        'posts': {\n            'include': {\n                'categories': True\n            }\n        }\n    }\n)\n```\n\n#### Include with Filtering\n\n```python\nusers = await db.user.find_many(\n    include={\n        'posts': {\n            'where': {\n                'published': True\n            },\n            'order': {\n                'createdAt': 'desc'\n            },\n            'take': 5\n        }\n    }\n)\n```\n\n### Update\n\n#### Update Single Record\n\n```python\nuser = await db.user.update(\n    where={'email': 'alice@prisma.io'},\n    data={'name': 'Alice Smith'}\n)\n```\n\n#### Update Multiple Records\n\n```python\ncount = await db.user.update_many(\n    where={\n        'email': {'contains': 'prisma.io'}\n    },\n    data={'role': 'ADMIN'}\n)\n```\n\n#### Upsert (Update or Create)\n\n```python\nuser = await db.user.upsert(\n    where={'email': 'alice@prisma.io'},\n    data={\n        'create': {\n            'email': 'alice@prisma.io',\n            'name': 'Alice'\n        },\n        'update': {\n            'name': 'Alice Updated'\n        }\n    }\n)\n```\n\n#### Atomic Number Operations\n\n```python\npost = await db.post.update(\n    where={'id': 1},\n    data={\n        'views': {'increment': 1},\n        'likes': {'increment': 5}\n    }\n)\n```\n\n```python\npost = await db.post.update(\n    where={'id': 1},\n    data={\n        'views': {'decrement': 1},\n        'score': {'multiply': 2},\n        'total': {'divide': 10}\n    }\n)\n```\n\n#### Update with Relations\n\n```python\nuser = await db.user.update(\n    where={'id': 1},\n    data={\n        'posts': {\n            'create': {'title': 'New Post'}\n        }\n    }\n)\n```\n\n#### Connect Existing Relations\n\n```python\nuser = await db.user.update(\n    where={'id': 1},\n    data={\n        'posts': {\n            'connect': [{'id': 5}]\n        }\n    }\n)\n```\n\n#### Disconnect Relations\n\n```python\nuser = await db.user.update(\n    where={'id': 1},\n    data={\n        'posts': {\n            'disconnect': [{'id': 5}]\n        }\n    }\n)\n```\n\n### Delete\n\n#### Delete Single Record\n\n```python\nuser = await db.user.delete(\n    where={'email': 'alice@prisma.io'}\n)\n```\n\n#### Delete Multiple Records\n\n```python\ncount = await db.user.delete_many(\n    where={\n        'email': {'contains': 'prisma.io'}\n    }\n)\n```\n\n#### Delete All Records\n\n```python\ncount = await db.user.delete_many()\n```\n\n---\n\n## Filtering and Sorting\n\n### Basic Filters\n\n```python\nusers = await db.user.find_many(\n    where={\n        'email': {'equals': 'alice@prisma.io'},\n        'name': {'not': 'Bob'},\n        'age': {'gt': 18}\n    }\n)\n```\n\n### String Filters\n\n```python\nusers = await db.user.find_many(\n    where={\n        'email': {'startswith': 'alice'},\n        'name': {'endswith': 'Smith'},\n        'bio': {'contains': 'developer'}\n    }\n)\n```\n\n### Number Filters\n\n```python\nposts = await db.post.find_many(\n    where={\n        'views': {'gt': 100},\n        'likes': {'gte': 50},\n        'comments': {'lt': 10},\n        'shares': {'lte': 5},\n        'rating': {'in': [4, 5]},\n        'score': {'not_in': [0, 1]}\n    }\n)\n```\n\n### Logical Operators\n\n```python\nusers = await db.user.find_many(\n    where={\n        'OR': [\n            {'email': {'contains': 'prisma.io'}},\n            {'name': {'contains': 'Alice'}}\n        ]\n    }\n)\n```\n\n```python\nusers = await db.user.find_many(\n    where={\n        'AND': [\n            {'email': {'contains': 'prisma.io'}},\n            {'role': 'ADMIN'}\n        ]\n    }\n)\n```\n\n```python\nusers = await db.user.find_many(\n    where={\n        'NOT': {\n            'email': {'contains': 'spam.com'}\n        }\n    }\n)\n```\n\n### Relation Filters\n\n```python\nusers = await db.user.find_many(\n    where={\n        'posts': {\n            'some': {\n                'published': True\n            }\n        }\n    }\n)\n```\n\n```python\nusers = await db.user.find_many(\n    where={\n        'posts': {\n            'every': {\n                'published': True\n            }\n        }\n    }\n)\n```\n\n```python\nusers = await db.user.find_many(\n    where={\n        'posts': {\n            'none': {\n                'published': False\n            }\n        }\n    }\n)\n```\n\n```python\nposts = await db.post.find_many(\n    where={\n        'author': {\n            'is': {\n                'name': 'Alice'\n            }\n        }\n    }\n)\n```\n\n```python\nposts = await db.post.find_many(\n    where={\n        'author': {\n            'is_not': {\n                'role': 'BANNED'\n            }\n        }\n    }\n)\n```\n\n### Sorting\n\n```python\nusers = await db.user.find_many(\n    order={'name': 'asc'}\n)\n```\n\n```python\nusers = await db.user.find_many(\n    order=[\n        {'role': 'desc'},\n        {'name': 'asc'}\n    ]\n)\n```\n\n---\n\n## Pagination\n\n### Offset Pagination\n\n```python\nusers = await db.user.find_many(\n    skip=10,\n    take=10\n)\n```\n\n### Cursor-Based Pagination\n\n```python\nusers = await db.user.find_many(\n    take=10,\n    cursor={'id': last_user_id},\n    skip=1  # Skip cursor itself\n)\n```\n\n---\n\n## Aggregation\n\n### Count\n\n```python\ncount = await db.user.count()\n```\n\n```python\ncount = await db.user.count(\n    where={\n        'email': {'contains': 'prisma.io'}\n    }\n)\n```\n\n### Group By\n\n```python\nresults = await db.user.group_by(\n    by=['role']\n)\n```\n\n```python\nresults = await db.user.group_by(\n    by=['country'],\n    count={'_all': True}\n)\n```\n\n```python\nresults = await db.user.group_by(\n    by=['country'],\n    count={'_all': True, 'city': True},\n    sum={'views': True},\n    avg={'age': True},\n    order={'country': 'desc'},\n    having={\n        'age': {\n            '_avg': {\n                'gt': 18\n            }\n        }\n    }\n)\n```\n\n```python\nresults = await db.post.group_by(\n    by=['authorId'],\n    count={'_all': True},\n    order={\n        '_count': {\n            '_all': 'desc'\n        }\n    }\n)\n```\n\n---\n\n## Transactions\n\n### Transaction with Context Manager (Async)\n\n```python\nasync with db.tx() as transaction:\n    user = await transaction.user.update(\n        where={'id': from_user_id},\n        data={'balance': {'decrement': 50}}\n    )\n\n    if user.balance < 0:\n        raise ValueError(f'{user.name} does not have enough balance')\n\n    await transaction.user.update(\n        where={'id': to_user_id},\n        data={'balance': {'increment': 50}}\n    )\n```\n\n### Transaction with Context Manager (Sync)\n\n```python\nwith db.tx() as transaction:\n    user = transaction.user.update(\n        where={'id': from_user_id},\n        data={'balance': {'decrement': 50}}\n    )\n\n    if user.balance < 0:\n        raise ValueError(f'{user.name} does not have enough balance')\n\n    transaction.user.update(\n        where={'id': to_user_id},\n        data={'balance': {'increment': 50}}\n    )\n```\n\n### Manual Transaction Management\n\n```python\ntransaction = db.tx()\nawait transaction.start()\n\ntry:\n    user = await transaction.user.create(\n        data={'email': 'alice@prisma.io', 'name': 'Alice'}\n    )\n\n    post = await transaction.post.create(\n        data={'title': 'Hello', 'authorId': user.id}\n    )\n\n    await transaction.commit()\nexcept Exception as e:\n    await transaction.rollback()\n    raise e\n```\n\n---\n\n## Raw Queries\n\n### Raw Query (Select)\n\n```python\nresults = await db.query_raw(\n    'SELECT * FROM \"User\" WHERE email = $1',\n    'alice@prisma.io'\n)\n```\n\n### Raw Execute (Insert/Update/Delete)\n\n```python\ncount = await db.execute_raw(\n    'UPDATE \"User\" SET name = $1 WHERE id = $2',\n    'Alice',\n    1\n)\n```\n\n### Unsafe Raw Queries (Use with Caution)\n\n```python\nusers = await db.query_raw('SELECT * FROM \"User\"')\n```\n\n---\n\n## Advanced Features\n\n### Distinct\n\n```python\nusers = await db.user.find_many(\n    distinct=['email']\n)\n```\n\n### Null Filtering\n\n```python\nusers = await db.user.find_many(\n    where={\n        'name': {'not': None}\n    }\n)\n```\n\n```python\nusers = await db.user.find_many(\n    where={\n        'name': None\n    }\n)\n```\n\n### Case-Insensitive Filtering\n\n```python\nusers = await db.user.find_many(\n    where={\n        'email': {\n            'equals': 'ALICE@PRISMA.IO',\n            'mode': 'insensitive'\n        }\n    }\n)\n```\n\n### Full-Text Search (PostgreSQL)\n\n```python\nposts = await db.post.find_many(\n    where={\n        'title': {\n            'search': 'database | prisma'\n        }\n    }\n)\n```\n\n---\n\n## Type Safety\n\n### Using Generated Types\n\n```python\nfrom prisma.models import User\nfrom prisma.types import UserCreateInput, UserWhereInput\n\n# Type-safe create input\nuser_data: UserCreateInput = {\n    'email': 'alice@prisma.io',\n    'name': 'Alice'\n}\n\nuser = await db.user.create(data=user_data)\n\n# Type-safe where clause\nwhere: UserWhereInput = {\n    'email': {'contains': 'prisma.io'}\n}\n\nusers = await db.user.find_many(where=where)\n```\n\n### Model Instance Methods\n\n```python\nfrom prisma.models import User\n\nuser = await User.prisma().create(\n    data={'email': 'alice@prisma.io', 'name': 'Alice'}\n)\n\n# Access fields\nprint(user.id)\nprint(user.email)\nprint(user.name)\n\n# Update instance\nupdated_user = await user.update(\n    data={'name': 'Alice Smith'}\n)\n\n# Delete instance\nawait user.delete()\n```\n\n---\n\n## Database-Specific Features\n\n### PostgreSQL\n\n```prisma\nmodel User {\n  id   Int      @id @default(autoincrement())\n  data Json     @db.JsonB\n  tags String[] @db.VarChar(255)\n}\n```\n\n### MySQL\n\n```prisma\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String @db.VarChar(255)\n  bio  String @db.Text\n}\n```\n\n### SQLite\n\n```prisma\ndatasource db {\n  provider = \"sqlite\"\n  url      = \"file:./dev.db\"\n}\n```\n\n### MongoDB\n\n```prisma\ndatasource db {\n  provider = \"mongodb\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel User {\n  id    String @id @default(auto()) @map(\"_id\") @db.ObjectId\n  email String @unique\n}\n```\n\n---\n\n## Complete Example Application\n\n```python\nimport asyncio\nfrom prisma import Prisma\nfrom prisma.models import User, Post\n\nasync def main() -> None:\n    db = Prisma()\n    await db.connect()\n\n    # Create user with posts\n    user = await db.user.create(\n        data={\n            'email': 'alice@prisma.io',\n            'name': 'Alice',\n            'posts': {\n                'create': [\n                    {\n                        'title': 'Getting Started with Prisma',\n                        'content': 'Learn how to use Prisma...',\n                        'published': True\n                    },\n                    {\n                        'title': 'Advanced Prisma Patterns',\n                        'content': 'Dive deeper...',\n                        'published': False\n                    }\n                ]\n            }\n        },\n        include={'posts': True}\n    )\n    print(f'Created user: {user}')\n\n    # Find all published posts with author\n    published_posts = await db.post.find_many(\n        where={'published': True},\n        include={'author': True}\n    )\n    print(f'Published posts: {published_posts}')\n\n    # Update post\n    updated_post = await db.post.update(\n        where={'id': 1},\n        data={'views': {'increment': 1}}\n    )\n    print(f'Updated post: {updated_post}')\n\n    # Aggregate data\n    stats = await db.post.group_by(\n        by=['published'],\n        count={'_all': True},\n        avg={'views': True}\n    )\n    print(f'Post statistics: {stats}')\n\n    # Transaction\n    async with db.tx() as transaction:\n        new_user = await transaction.user.create(\n            data={\n                'email': 'bob@prisma.io',\n                'name': 'Bob'\n            }\n        )\n\n        new_post = await transaction.post.create(\n            data={\n                'title': \"Bob's First Post\",\n                'authorId': new_user.id\n            }\n        )\n\n        print(f'Transaction completed: {new_user}, {new_post}')\n\n    await db.disconnect()\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n---\n\n## Batch Operations\n\n### Batch Queries\n\n```python\n# Execute multiple queries in parallel\nusers, posts = await asyncio.gather(\n    db.user.find_many(),\n    db.post.find_many()\n)\n```\n\n### Batch Creates\n\n```python\nusers = await db.user.create_many(\n    data=[\n        {'email': f'user{i}@example.com', 'name': f'User {i}'}\n        for i in range(100)\n    ]\n)\n```\n\n---\n\n## Error Handling\n\n```python\nfrom prisma.errors import (\n    UniqueViolationError,\n    RecordNotFoundError,\n    PrismaError\n)\n\ntry:\n    user = await db.user.create(\n        data={'email': 'alice@prisma.io', 'name': 'Alice'}\n    )\nexcept UniqueViolationError:\n    print('User with this email already exists')\nexcept RecordNotFoundError:\n    print('Record not found')\nexcept PrismaError as e:\n    print(f'Database error: {e}')\n```\n\n---\n\n## Connection Management\n\n### Connect and Disconnect\n\n```python\ndb = Prisma()\nawait db.connect()\n\n# Perform operations\n\nawait db.disconnect()\n```\n\n### Check Connection Status\n\n```python\nif db.is_connected():\n    print('Connected to database')\nelse:\n    print('Not connected')\n```\n\n### Connection Pooling\n\nPrisma Client Python handles connection pooling automatically based on the underlying Prisma engine configuration.\n\n---\n\n## CLI Commands\n\n### Generate Client\n\n```bash\nprisma generate\n```\n\n### Push Schema to Database\n\n```bash\nprisma db push\n```\n\n### Create Migration\n\n```bash\nprisma migrate dev --name init\n```\n\n### Apply Migrations\n\n```bash\nprisma migrate deploy\n```\n\n### Reset Database\n\n```bash\nprisma migrate reset\n```\n\n### Open Prisma Studio\n\n```bash\nprisma studio\n```\n\n### Format Schema\n\n```bash\nprisma format\n```\n\n### Validate Schema\n\n```bash\nprisma validate\n```\n"
  },
  {
    "path": "content/prometheus-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"prometheus-client Python package for instrumenting code, exposing Prometheus metrics, and handling ASGI/WSGI, multiprocess, and Pushgateway workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.24.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"prometheus,monitoring,metrics,instrumentation,observability,python\"\n---\n\n# prometheus-client Python Package Guide\n\n## Golden Rule\n\nUse `prometheus-client` as the package name, import it as `prometheus_client`, and keep instrumentation simple: create metrics once at module scope, expose them on `/metrics`, and switch to the documented multiprocess pattern before running under multiple worker processes. For Pushgateway and batch jobs, use a dedicated `CollectorRegistry` rather than the default global registry.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"prometheus-client==0.24.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"prometheus-client==0.24.1\"\npoetry add \"prometheus-client==0.24.1\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"prometheus-client[aiohttp]==0.24.1\"\npython -m pip install \"prometheus-client[django]==0.24.1\"\npython -m pip install \"prometheus-client[twisted]==0.24.1\"\n```\n\n## Quick Start\n\nThe simplest pattern is the library quickstart: define metrics once, start the HTTP exporter, then update metrics from application code.\n\n```python\nfrom prometheus_client import Summary, start_http_server\nimport random\nimport time\n\nREQUEST_TIME = Summary(\n    \"request_processing_seconds\",\n    \"Time spent processing a request\",\n)\n\n@REQUEST_TIME.time()\ndef process_request(delay_seconds: float) -> None:\n    time.sleep(delay_seconds)\n\nif __name__ == \"__main__\":\n    start_http_server(8000)\n    while True:\n        process_request(random.random())\n```\n\nPrometheus can then scrape `http://localhost:8000/`.\n\n## Core Metric Types\n\n### Counter\n\nUse `Counter` for values that only increase.\n\n```python\nfrom prometheus_client import Counter\n\nREQUESTS = Counter(\n    \"myapp_requests_total\",\n    \"Total requests handled\",\n    [\"method\", \"endpoint\"],\n)\n\nREQUESTS.labels(\"GET\", \"/health\").inc()\nREQUESTS.labels(\"POST\", \"/jobs\").inc()\n```\n\nUseful helper:\n\n```python\nfrom prometheus_client import Counter\n\nFAILURES = Counter(\"myapp_failures_total\", \"Unhandled failures\")\n\n@FAILURES.count_exceptions()\ndef run_job() -> None:\n    raise RuntimeError(\"boom\")\n```\n\n### Gauge\n\nUse `Gauge` for values that can go up or down.\n\n```python\nfrom prometheus_client import Gauge\n\nIN_PROGRESS = Gauge(\"myapp_inprogress_requests\", \"Requests currently in progress\")\n\n@IN_PROGRESS.track_inprogress()\ndef handle_request() -> None:\n    ...\n```\n\nFor callback-driven gauges:\n\n```python\nfrom prometheus_client import Gauge\n\nQUEUE_SIZE = Gauge(\"myapp_queue_size\", \"Items waiting in memory\")\nqueue = []\nQUEUE_SIZE.set_function(lambda: len(queue))\n```\n\n### Histogram\n\nUse `Histogram` for latency or size distributions that you want to aggregate across instances.\n\n```python\nfrom prometheus_client import Histogram\n\nLATENCY = Histogram(\n    \"myapp_request_latency_seconds\",\n    \"Request latency\",\n    buckets=(0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10),\n)\n\n@LATENCY.time()\ndef query_backend() -> None:\n    ...\n```\n\n### Summary\n\nUse `Summary` when you want count and sum in-process and do not need histogram buckets.\n\n```python\nfrom prometheus_client import Summary\n\nREQUEST_SIZE = Summary(\"myapp_request_size_bytes\", \"Request payload size\")\nREQUEST_SIZE.observe(512)\n```\n\n### Info and Enum\n\nThese exist and are useful for build metadata or state-style values:\n\n```python\nfrom prometheus_client import Enum, Info\n\nBUILD = Info(\"myapp_build\", \"Build metadata\")\nBUILD.info({\"version\": \"1.2.3\", \"git_sha\": \"abc123\"})\n\nSTATE = Enum(\"myapp_state\", \"Worker state\", states=[\"starting\", \"running\", \"stopped\"])\nSTATE.state(\"running\")\n```\n\nDo not use `Info` or `Enum` in multiprocess mode.\n\n## Labels And Registry Basics\n\nLabeled metrics are not initialized until you call `.labels(...)`. If you expect a fixed set of label values, pre-create them during startup so your dashboards do not look empty until the first request.\n\n```python\nfrom prometheus_client import Counter\n\nREQUESTS = Counter(\n    \"myapp_requests_total\",\n    \"Requests handled\",\n    [\"method\", \"endpoint\"],\n)\n\nfor method, endpoint in [\n    (\"GET\", \"/health\"),\n    (\"POST\", \"/jobs\"),\n]:\n    REQUESTS.labels(method, endpoint)\n```\n\nThe library uses the default global `REGISTRY` unless you pass `registry=...`. Keep using the default registry for long-running services unless you have a concrete reason to isolate metrics. Use a separate `CollectorRegistry()` for batch jobs, Pushgateway pushes, tests, or custom exporter endpoints.\n\n## Configuration And Auth\n\nKey environment-driven settings:\n\n- `PROMETHEUS_MULTIPROC_DIR=/path/to/dir`: required for multiprocess mode; set it before Python starts and wipe the directory between runs.\n- `PROMETHEUS_DISABLE_CREATED_SERIES=True`: disables `_created` time series for counters, histograms, and summaries if you do not want them.\n\nEquivalent runtime call for `_created` series:\n\n```python\nfrom prometheus_client import disable_created_metrics\n\ndisable_created_metrics()\n```\n\nAuthentication is not built into the plain `/metrics` endpoint by default. If you need auth or network restrictions, enforce them in your ASGI/WSGI app, reverse proxy, ingress, or by enabling HTTPS or mTLS on the standalone exporter.\n\n## Export Metrics\n\n### Standalone HTTP or HTTPS exporter\n\n`start_http_server()` is the easiest way to expose metrics from a process:\n\n```python\nfrom prometheus_client import Counter, start_http_server\n\nREQUESTS = Counter(\"myapp_requests_total\", \"Requests handled\")\n\nserver, thread = start_http_server(8000)\n\nREQUESTS.inc()\n\n# Later, for graceful shutdown:\n# server.shutdown()\n# server.server_close()\n# thread.join()\n```\n\nFor TLS:\n\n```python\nfrom prometheus_client import start_http_server\n\nstart_http_server(\n    8443,\n    certfile=\"server.crt\",\n    keyfile=\"server.key\",\n)\n```\n\nThe exporter only serves `GET` and `OPTIONS`; other methods are rejected.\n\n### Mount into ASGI apps\n\nUse `make_asgi_app()` for FastAPI, Starlette, or other ASGI apps:\n\n```python\nfrom fastapi import FastAPI\nfrom prometheus_client import make_asgi_app\n\napp = FastAPI()\napp.mount(\"/metrics\", make_asgi_app())\n```\n\nCompression is enabled when the scraper sends `Accept-Encoding: gzip`. Disable it only if you have a reason:\n\n```python\nmetrics_app = make_asgi_app(disable_compression=True)\n```\n\n### Mount into WSGI apps\n\nUse `make_wsgi_app()` with Flask or other WSGI frameworks:\n\n```python\nfrom flask import Flask\nfrom prometheus_client import make_wsgi_app\nfrom werkzeug.middleware.dispatcher import DispatcherMiddleware\n\napp = Flask(__name__)\napp.wsgi_app = DispatcherMiddleware(app.wsgi_app, {\n    \"/metrics\": make_wsgi_app(),\n})\n```\n\nIf you just want a thread-backed WSGI exporter, `start_wsgi_server(8000)` is also available.\n\n### Custom endpoint with `generate_latest`\n\nIf you need full control over the response path:\n\n```python\nfrom prometheus_client import CONTENT_TYPE_LATEST, Counter, generate_latest\nfrom starlette.responses import Response\n\nREQUESTS = Counter(\"myapp_requests_total\", \"Requests handled\")\n\nasync def metrics_endpoint(request) -> Response:\n    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)\n```\n\n## Pushgateway For Batch Jobs\n\nUse Pushgateway only for short-lived or batch jobs that Prometheus cannot scrape directly. Use a separate registry so you do not accidentally push process-level defaults from the global registry.\n\n```python\nfrom prometheus_client import CollectorRegistry, Gauge, push_to_gateway\n\nregistry = CollectorRegistry()\nlast_success = Gauge(\n    \"job_last_success_unixtime\",\n    \"Last successful completion timestamp\",\n    registry=registry,\n)\n\nlast_success.set_to_current_time()\npush_to_gateway(\"pushgateway.internal:9091\", job=\"nightly-report\", registry=registry)\n```\n\nAuthentication handlers are built in:\n\n```python\nfrom prometheus_client import CollectorRegistry, Gauge, push_to_gateway\nfrom prometheus_client.exposition import basic_auth_handler\n\ndef auth_handler(url, method, timeout, headers, data):\n    return basic_auth_handler(\n        url,\n        method,\n        timeout,\n        headers,\n        data,\n        username=\"metrics\",\n        password=\"secret123\",\n    )\n\nregistry = CollectorRegistry()\nGauge(\"job_last_success_unixtime\", \"Last success time\", registry=registry).set_to_current_time()\npush_to_gateway(\n    \"pushgateway.internal:9091\",\n    job=\"nightly-report\",\n    registry=registry,\n    handler=auth_handler,\n    compression=\"gzip\",\n)\n```\n\nTLS auth handlers are also available. In multiprocess mode, Pushgateway is not supported.\n\n## Multiprocess Mode\n\nPrometheus Python clients assume shared in-process metrics by default. That breaks under pre-fork worker models such as Gunicorn with multiple workers. When you run multiple processes, switch to the documented multiprocess flow.\n\n### Required environment\n\nSet `PROMETHEUS_MULTIPROC_DIR` in the startup environment, and wipe that directory between runs:\n\n```bash\nexport PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus-multiproc\nrm -rf \"$PROMETHEUS_MULTIPROC_DIR\"\nmkdir -p \"$PROMETHEUS_MULTIPROC_DIR\"\n```\n\nSet the variable in the shell or process manager before Python starts so child workers inherit it.\n\n### Build the registry per scrape\n\n```python\nfrom prometheus_client import CollectorRegistry, CONTENT_TYPE_LATEST, generate_latest, multiprocess\nfrom starlette.responses import Response\n\nasync def metrics_endpoint(request) -> Response:\n    registry = CollectorRegistry()\n    multiprocess.MultiProcessCollector(registry)\n    data = generate_latest(registry)\n    return Response(data, media_type=CONTENT_TYPE_LATEST)\n```\n\n### Gunicorn cleanup hook\n\n```python\nfrom prometheus_client import multiprocess\n\ndef child_exit(server, worker):\n    multiprocess.mark_process_dead(worker.pid)\n```\n\n### Gauge tuning\n\nPick a `multiprocess_mode` explicitly for gauges so you get the aggregation behavior you want:\n\n```python\nfrom prometheus_client import Gauge\n\nIN_PROGRESS = Gauge(\n    \"myapp_inprogress_requests\",\n    \"Requests in progress\",\n    multiprocess_mode=\"livesum\",\n)\n```\n\nUseful modes include `sum`, `max`, `mostrecent`, and the `live...` variants.\n\n## Default Collectors\n\nThe default registry includes collector metrics by default:\n\n- `process_*` metrics for CPU, memory, file descriptors, and start time\n- `python_info`\n- garbage-collection metrics\n\nImportant caveat: `process_*` metrics are only available on Linux.\n\nIf these defaults are not appropriate for a service, unregister them explicitly:\n\n```python\nimport prometheus_client\n\nprometheus_client.REGISTRY.unregister(prometheus_client.GC_COLLECTOR)\nprometheus_client.REGISTRY.unregister(prometheus_client.PLATFORM_COLLECTOR)\nprometheus_client.REGISTRY.unregister(prometheus_client.PROCESS_COLLECTOR)\n```\n\n## Advanced Features\n\n### Exemplars\n\nCounters and histograms support exemplars:\n\n```python\nfrom prometheus_client import Counter\n\nREQUESTS = Counter(\"myapp_requests_total\", \"Requests handled\", [\"path\"])\nREQUESTS.labels(\"/checkout\").inc(exemplar={\"trace_id\": \"abc123\"})\n```\n\nExemplars are only emitted in OpenMetrics exposition, not plain Prometheus text exposition.\n\n### Parse Prometheus text format\n\nFor advanced ingestion or bridging workflows:\n\n```python\nfrom prometheus_client.parser import text_string_to_metric_families\n\npayload = \"my_gauge 1.0\\n\"\n\nfor family in text_string_to_metric_families(payload):\n    for sample in family.samples:\n        print(sample)\n```\n\n### Custom collectors\n\nUse custom collectors when you need to proxy or transform metrics from another source:\n\n```python\nfrom prometheus_client.core import GaugeMetricFamily, REGISTRY\n\nclass QueueCollector:\n    def collect(self):\n        yield GaugeMetricFamily(\"external_queue_depth\", \"Queue depth\", value=7)\n\nREGISTRY.register(QueueCollector())\n```\n\nCustom collectors do not work in multiprocess mode.\n\n## Common Pitfalls\n\n- The package name is `prometheus-client`, but the import path is `prometheus_client`.\n- If you create a `Counter` named with a `_total` suffix, the client normalizes it internally and exports it with `_total` for compatibility.\n- Labeled metrics do not exist until `.labels(...)` is called for a given label set.\n- Use `Histogram` instead of `Summary` when you need aggregation across multiple instances or workers.\n- Use a dedicated `CollectorRegistry()` for Pushgateway jobs instead of pushing the default registry.\n- `Gauge.set_function()`, `Info`, `Enum`, exemplars, custom collectors, and label `remove`/`clear` are not supported in multiprocess mode.\n- Do not reuse a registry that already has registered metrics when wrapping it with `multiprocess.MultiProcessCollector`, or you can export duplicates.\n- The default `process_*` collectors are Linux-only, so code and dashboards should tolerate them being absent on macOS or Windows.\n- The built-in HTTP exporter rejects methods other than `GET` and `OPTIONS`.\n\n## Version-Sensitive Notes\n\n- PyPI lists `prometheus-client 0.24.1` as the current release on January 14, 2026.\n- PyPI metadata for `0.24.1` requires Python `>=3.9`; Python 3.8 support was removed in `0.22.0`.\n- PyPI marks `0.23.0` as yanked because it accidentally included an unlisted dependency. Prefer `0.23.1+` if you encounter older pins.\n- `0.20.0` added graceful shutdown support by returning the server and thread objects from `start_http_server()` and `start_wsgi_server()`.\n- `0.22.0` added UTF-8 metric support and parser/exposition improvements, so very old examples that assume ASCII-only names or labels are stale.\n\n## Official Sources\n\n- Docs root: `https://prometheus.github.io/client_python/`\n- Instrumenting guide: `https://prometheus.github.io/client_python/instrumenting/`\n- Labels: `https://prometheus.github.io/client_python/instrumenting/labels/`\n- Counter: `https://prometheus.github.io/client_python/instrumenting/counter/`\n- Gauge: `https://prometheus.github.io/client_python/instrumenting/gauge/`\n- Histogram: `https://prometheus.github.io/client_python/instrumenting/histogram/`\n- Exemplars: `https://prometheus.github.io/client_python/instrumenting/exemplars/`\n- Collector guide: `https://prometheus.github.io/client_python/collector/`\n- Custom collectors: `https://prometheus.github.io/client_python/collector/custom/`\n- HTTP/HTTPS exporter: `https://prometheus.github.io/client_python/exporting/http/`\n- WSGI exporter: `https://prometheus.github.io/client_python/exporting/http/wsgi/`\n- ASGI exporter: `https://prometheus.github.io/client_python/exporting/http/asgi/`\n- FastAPI + Gunicorn: `https://prometheus.github.io/client_python/exporting/http/fastapi-gunicorn/`\n- Pushgateway: `https://prometheus.github.io/client_python/exporting/pushgateway/`\n- Multiprocess mode: `https://prometheus.github.io/client_python/multiprocess/`\n- Parser: `https://prometheus.github.io/client_python/parser/`\n- PyPI package metadata and release history: `https://pypi.org/project/prometheus-client/`\n- GitHub releases: `https://github.com/prometheus/client_python/releases`\n"
  },
  {
    "path": "content/protobuf/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"protobuf package guide for Python message generation, serialization, and JSON interop\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.34.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"protobuf,protocol-buffers,serialization,codegen,json\"\n---\n\n# protobuf Python Package Guide\n\n## What It Is\n\n`protobuf` is the Python runtime for Protocol Buffers. In Python code you install `protobuf`, but the runtime APIs live under `google.protobuf`. Typical work is:\n\n1. define messages in `.proto` files\n2. generate Python modules with `protoc`\n3. construct message objects, then serialize, parse, or convert them to JSON\n\n## Install\n\nInstall the runtime:\n\n```bash\npip install protobuf==7.34.0\n```\n\nWith `uv`:\n\n```bash\nuv add protobuf==7.34.0\n```\n\nWith Poetry:\n\n```bash\npoetry add protobuf@7.34.0\n```\n\n## Setup\n\n### Runtime only\n\nIf your repository already commits generated `*_pb2.py` files, the runtime package is enough.\n\n### Generate Python code from `.proto`\n\nThe Python package does not replace the Protocol Buffer compiler. Install `protoc` separately, then generate code:\n\n```bash\nprotoc --proto_path=. --python_out=. example.proto\n```\n\nIf you also want type stubs:\n\n```bash\nprotoc --proto_path=. --python_out=. --pyi_out=. example.proto\n```\n\nThe protobuf install docs warn that package-manager `protoc` builds can be old. Check the compiler version explicitly:\n\n```bash\nprotoc --version\n```\n\n## Core Usage\n\n### 1. Define a schema\n\n```proto\nsyntax = \"proto3\";\n\nmessage User {\n  string id = 1;\n  string email = 2;\n  repeated string roles = 3;\n}\n```\n\n### 2. Generate Python code\n\n```bash\nprotoc --proto_path=. --python_out=. user.proto\n```\n\nThis creates `user_pb2.py`.\n\n### 3. Create, serialize, and parse messages\n\n```python\nimport user_pb2\n\nuser = user_pb2.User(\n    id=\"u_123\",\n    email=\"dev@example.com\",\n    roles=[\"admin\", \"billing\"],\n)\n\npayload = user.SerializeToString()\n\nparsed = user_pb2.User()\nparsed.ParseFromString(payload)\n\nassert parsed.id == \"u_123\"\nassert parsed.roles == [\"admin\", \"billing\"]\n```\n\n### 4. Convert to and from JSON\n\nUse `google.protobuf.json_format` for API boundaries that expect JSON rather than protobuf wire format.\n\n```python\nimport user_pb2\nfrom google.protobuf.json_format import MessageToDict, ParseDict\n\nuser = user_pb2.User(id=\"u_123\", email=\"dev@example.com\")\n\ndata = MessageToDict(user, preserving_proto_field_name=True)\n\nround_tripped = user_pb2.User()\nParseDict(data, round_tripped)\n```\n\n### 5. Common message operations\n\n```python\nmsg = user_pb2.User()\n\nmsg.id = \"u_123\"\nmsg.roles.append(\"reader\")\n\ncopy = user_pb2.User()\ncopy.CopyFrom(msg)\n\nassert copy == msg\nassert copy.IsInitialized()\n```\n\n## Generated-Code Rules That Matter\n\n- Python output modules are named `*_pb2.py`.\n- `*_pb2.py` files are generated code. Do not hand-edit them.\n- The `.proto` `package` declaration does **not** control the Python import path. Python imports follow where generated files are written.\n- Generated message classes are not intended to be subclassed. Wrap them in your own classes if you need higher-level behavior.\n\n## Config And Environment\n\nThere is no authentication layer in `protobuf`. The relevant configuration is build/runtime configuration:\n\n- Pin `protobuf` in your Python environment if generated code is committed to the repo.\n- Keep `protoc` reasonably aligned with the Python runtime series you use.\n- If you need Python-only behavior when interoperating with C++ extensions, protobuf documents `PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python` for that fallback path.\n\n## Common Pitfalls\n\n### Install name vs import name\n\nYou install `protobuf`, but import from `google.protobuf` or from generated `*_pb2` modules.\n\n### Generated code path surprises\n\nIf `protoc` writes files into `generated/`, import paths will usually come from that filesystem layout, not from the `.proto` package name.\n\n### Presence rules differ by field type\n\nUse `HasField()` only for fields with presence. Repeated fields do not support scalar presence checks the same way singular message or optional fields do.\n\n### Repeated message fields use protobuf helpers\n\nFor repeated message fields, use protobuf’s collection helpers such as `.add()` instead of assigning plain dicts or arbitrary objects.\n\n### Keyword collisions are real\n\nIf a field name conflicts with a Python keyword, protobuf documents using `getattr()` and related dynamic access patterns.\n\n### JSON conversion is explicit\n\n`SerializeToString()` produces protobuf wire bytes, not JSON. Use `json_format` helpers for JSON APIs.\n\n## Version-Sensitive Notes For 7.34.0\n\n- `7.34.0` is the Python major-version bump announced by protobuf on September 19, 2025.\n- Upstream states that `6.33` is the final `6.x` minor release and that `7.34.0` does not change Python gencode, so older generated files should not trip new poison-pill checks in `7.34.x`.\n- The 7.34.0 change note also calls out stricter runtime behavior:\n  - incorrect type conversion to `Timestamp` or `Duration` now raises `TypeError`\n  - assigning `bool` to enum or integer fields is rejected instead of being silently coerced\n\n## Agent Guidance\n\n- If a repo contains `.proto` files but no generated `*_pb2.py`, assume you need `protoc` before writing runtime code.\n- If a repo contains generated files from an older protobuf line, prefer upgrading the runtime and regenerating with the project’s chosen compiler version together.\n- For web APIs, prefer `MessageToDict` or `MessageToJson` with `preserving_proto_field_name=True` when snake_case field names need to stay stable.\n- When debugging equality or merge behavior, use message methods such as `CopyFrom`, `MergeFrom`, `ClearField`, and `HasField` instead of manipulating internals.\n\n## Official Sources Used\n\n- Python reference root: https://protobuf.dev/reference/python/\n- Python generated code guide: https://protobuf.dev/reference/python/python-generated/\n- Python/C++ comparison notes: https://protobuf.dev/reference/python/python-comparison/\n- Python tutorial: https://protobuf.dev/getting-started/pythontutorial/\n- Compiler installation: https://protobuf.dev/installation/\n- Version support policy: https://protobuf.dev/support/version-support/\n- 7.34.0 Python change note: https://protobuf.dev/news/2025-09-19/\n- PyPI package page: https://pypi.org/project/protobuf/\n"
  },
  {
    "path": "content/psutil/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"psutil Python package guide for process and system monitoring\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"psutil,python,process,system,monitoring,metrics\"\n---\n\n# psutil Python Package Guide\n\n## Golden Rule\n\nUse `psutil` for local process and system inspection, not for remote host management. Prefer module-level APIs for machine-wide metrics, `Process(pid)` for per-process inspection, and `oneshot()` or `process_iter(attrs=...)` when gathering many fields so you do not pay repeated syscalls.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"psutil==7.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"psutil==7.2.2\"\npoetry add \"psutil==7.2.2\"\n```\n\nNotes:\n\n- Wheels are available for common Linux, macOS, and Windows targets. If pip falls back to building from source, you need a working C compiler toolchain.\n- In containers, metrics reflect the runtime and host/kernel limits visible from that container, not necessarily the full physical machine.\n\n## Setup And Privilege Model\n\n`psutil` has no API keys, service endpoints, or authentication flow. The practical setup variables are:\n\n- which process you want to inspect\n- what privilege level the current user has\n- which operating system features are available\n\nBasic import and capability check:\n\n```python\nimport psutil\n\nprint(psutil.__version__)\nprint(psutil.boot_time())\nprint(psutil.cpu_count(logical=True))\n```\n\nPrivilege expectations:\n\n- Reading your own processes is usually fine without elevation.\n- Inspecting other users' processes, open connections, or some memory details may raise `psutil.AccessDenied`.\n- Some APIs are OS-specific or partially implemented on certain platforms. Check `hasattr(psutil.Process(), \"...\")` or the docs before assuming parity across Linux, macOS, Windows, and BSD.\n\n## Core Usage\n\n### Read system-wide metrics\n\n```python\nimport psutil\n\ncpu_percent = psutil.cpu_percent(interval=1.0)\nvm = psutil.virtual_memory()\ndisk = psutil.disk_usage(\"/\")\nnet = psutil.net_io_counters()\n\nprint({\n    \"cpu_percent\": cpu_percent,\n    \"mem_available\": vm.available,\n    \"mem_percent\": vm.percent,\n    \"disk_percent\": disk.percent,\n    \"bytes_sent\": net.bytes_sent,\n    \"bytes_recv\": net.bytes_recv,\n})\n```\n\nUse `interval=1.0` or another real interval when you need a meaningful CPU percentage sample. The first non-blocking call is commonly `0.0`.\n\n### Iterate processes safely\n\n`process_iter()` is the standard way to scan running processes. Request only the fields you need:\n\n```python\nimport psutil\n\nfor proc in psutil.process_iter(\n    attrs=[\"pid\", \"name\", \"username\", \"status\", \"memory_info\"],\n    ad_value=None,\n):\n    info = proc.info\n    rss = info[\"memory_info\"].rss if info[\"memory_info\"] else None\n    print(info[\"pid\"], info[\"name\"], info[\"status\"], rss)\n```\n\nWhy this pattern matters:\n\n- it avoids repeated lookups for the same process\n- it degrades more cleanly when a field is unavailable\n- it reduces races compared with manual per-PID probing\n\n### Inspect one process\n\n```python\nimport psutil\n\nproc = psutil.Process()\n\nwith proc.oneshot():\n    print(proc.pid)\n    print(proc.name())\n    print(proc.status())\n    print(proc.cpu_percent(interval=0.1))\n    print(proc.memory_info().rss)\n    print(proc.open_files())\n```\n\nUse `oneshot()` when reading several attributes from one `Process`. It batches internal lookups and is significantly cheaper than independent calls.\n\n### Handle transient process errors\n\nProcesses can exit while you inspect them. Catch `NoSuchProcess` and `AccessDenied` explicitly:\n\n```python\nimport psutil\n\ntry:\n    proc = psutil.Process(12345)\n    print(proc.exe())\nexcept psutil.NoSuchProcess:\n    print(\"process exited\")\nexcept psutil.AccessDenied:\n    print(\"permission denied\")\n```\n\n### Work with subprocesses you create\n\n`psutil.Popen` gives you `subprocess.Popen` behavior plus psutil process methods:\n\n```python\nimport psutil\n\nproc = psutil.Popen([\"python\", \"-c\", \"import time; time.sleep(5)\"])\nprint(proc.pid)\nprint(proc.is_running())\nprint(proc.wait(timeout=10))\n```\n\nThis is useful when you need both process lifecycle control and psutil inspection without manually wrapping the child PID.\n\n## Configuration Notes\n\nThere is no global client object or config file. Most \"configuration\" in `psutil` is call-level:\n\n- `interval` for CPU sampling\n- `percpu=True` when you need per-core metrics\n- `nowrap=True` on selected counters to avoid wraparound surprises\n- `attrs=[...]` and `ad_value=...` for process iteration\n- explicit `pid` selection for per-process reads\n\nUseful examples:\n\n```python\nimport psutil\n\nprint(psutil.cpu_percent(interval=0.5, percpu=True))\nprint(psutil.disk_io_counters(nowrap=True))\nprint(psutil.net_io_counters(nowrap=True))\n```\n\nIf you need a stable snapshot over time, normalize these choices in your own wrapper instead of scattering raw psutil calls across the codebase.\n\n## Common Pitfalls\n\n- `cpu_percent()` and `Process.cpu_percent()` usually need a real interval or a warm-up call. A first immediate call often returns `0.0`.\n- For memory pressure checks, prefer `virtual_memory().available` over `virtual_memory().free`. \"Free\" memory is often the wrong signal on modern OSes.\n- Treat every per-process read as racy. PIDs can disappear between discovery and inspection.\n- Catch `psutil.NoSuchProcess`, `psutil.AccessDenied`, and sometimes `psutil.ZombieProcess` in monitoring code.\n- Use `psutil.net_connections()` or `Process.net_connections()`; older `connections()` names are deprecated in `7.x`.\n- Do not assume all metrics exist on all platforms. Sensor, swap, open-files, terminal, and connection details vary by OS and privilege level.\n- If you hold a `Process` object for a long time, verify it still refers to the same live process before acting on it. PID reuse is real.\n- Scanning every process and calling many getters inside a loop is expensive. Prefer `process_iter(attrs=...)` and `oneshot()`.\n\n## Version-Sensitive Notes\n\n### `7.2.2` versus the live `latest` docs\n\nThe docs root `https://psutil.readthedocs.io/en/latest/` renders `psutil 8.0.0` as of `2026-03-12`, not `7.2.2`. That matters because newer docs include changes that are not valid for this package version.\n\n### Relevant `6.x` and `7.x` behavior to remember\n\n- Since `6.0.0`, `process_iter()` no longer checks whether a yielded PID was reused. If you keep `Process` objects around, call `is_running()` or refresh state before taking action.\n- Since `7.0.0`, `connections()` is deprecated in favor of `net_connections()`.\n- `7.2.0` added `Process.heap_info()` and `Process.heap_trim()` on supported platforms. These are not portable across every OS.\n- `7.2.2` improves `Popen.wait()` by using better kernel facilities on newer Linux and BSD/macOS combinations, so long waits on managed child processes behave better than older examples may suggest.\n\n### `8.0.0` examples you should not blindly backport\n\nThe current `latest` docs describe `8.0.0` changes including:\n\n- enum values for `Process.status()`\n- enum values for the `kind` argument in connection APIs\n- changed field order in `cpu_times()` and `cpu_times_percent()`\n- support policy shifted to Python `3.7+`\n\nIf your project is pinned to `7.2.2`, keep using the `7.x` behavior your tests observe and do not assume those `8.0.0` API details.\n\n## Official Sources\n\n- Docs root: `https://psutil.readthedocs.io/en/latest/`\n- Install guide: `https://psutil.readthedocs.io/en/latest/#install`\n- API reference: `https://psutil.readthedocs.io/en/latest/#psutil-documentation`\n- PyPI release page: `https://pypi.org/project/psutil/`\n"
  },
  {
    "path": "content/psycopg/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Psycopg PostgreSQL adapter guide for Python projects using Psycopg 3\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"psycopg,postgresql,database,sql,async,connection-pool\"\n---\n\n# Psycopg Python Package Guide\n\n## Golden Rule\n\nUse `psycopg` for new PostgreSQL code, not `psycopg2`. As of March 12, 2026, PyPI lists `psycopg 3.3.3` as the latest stable release, while the main docs root is already serving `3.3.4.dev1`. Treat the docs as the authoritative API guide for Psycopg 3, but double-check edge features against the installed package when the docs mention newer development behavior.\n\n## Install\n\nFor most applications, install the binary build plus the pool extra:\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"psycopg[binary,pool]==3.3.3\"\n```\n\nOther supported install choices:\n\n```bash\n# Pure Python package only. Requires a local libpq runtime.\npython -m pip install \"psycopg==3.3.3\"\n\n# Build the C extension against the system libpq.\npython -m pip install \"psycopg[c,pool]==3.3.3\"\n```\n\nChoose installs based on what you are shipping:\n\n- Application/service: `psycopg[binary]` is the fastest path to a working install; `psycopg[c]` is the preferred production-style install when you want to link against the system `libpq`.\n- Reusable library: depend on `psycopg`, not `psycopg[binary]`, so the final application can choose the implementation.\n- Connection pooling: install `psycopg[pool]` or the separate `psycopg_pool` package. Pooling is released separately from the base package.\n\n## Connection Setup\n\nPsycopg accepts a PostgreSQL conninfo string or keyword arguments. A practical pattern is to store a full DSN in an environment variable.\n\n```bash\nexport DATABASE_URL=\"postgresql://app:secret@db.example.com:5432/appdb?sslmode=require\"\n```\n\nBasic sync setup:\n\n```python\nimport os\n\nimport psycopg\nfrom psycopg.rows import dict_row\n\ndsn = os.environ[\"DATABASE_URL\"]\n\nwith psycopg.connect(dsn, row_factory=dict_row) as conn:\n    with conn.cursor() as cur:\n        cur.execute(\"SELECT current_database() AS db, current_user AS user\")\n        print(cur.fetchone())\n```\n\nEquivalent keyword-style setup:\n\n```python\nimport psycopg\n\nconn = psycopg.connect(\n    dbname=\"appdb\",\n    host=\"db.example.com\",\n    port=5432,\n    user=\"app\",\n    password=\"secret\",\n    sslmode=\"require\",\n    application_name=\"context-hub-example\",\n)\n```\n\nIf you need to inspect or merge conninfo values programmatically, use `psycopg.conninfo.make_conninfo()` and `conninfo_to_dict()`.\n\n## Core Query Workflow\n\nThe import name is `psycopg`, not `psycopg3`.\n\n```python\nimport psycopg\nfrom psycopg.rows import dict_row\n\nwith psycopg.connect(row_factory=dict_row) as conn:\n    with conn.cursor() as cur:\n        cur.execute(\n            \"\"\"\n            INSERT INTO users (email, active)\n            VALUES (%s, %s)\n            RETURNING id, email, active\n            \"\"\",\n            (\"alice@example.com\", True),\n        )\n        user = cur.fetchone()\n        print(user[\"id\"], user[\"email\"], user[\"active\"])\n```\n\nUseful defaults and shortcuts:\n\n- `with psycopg.connect(...) as conn` closes the connection and commits on normal exit or rolls back on exception.\n- `with conn.cursor() as cur` closes the cursor automatically.\n- `executemany()` is the normal batch-write path for repeated parameter sets.\n- `row_factory` can be set on the connection or per cursor. `dict_row`, `namedtuple_row`, `scalar_row`, and `class_row(...)` are the most useful built-ins.\n\nExample using dataclass rows:\n\n```python\nfrom dataclasses import dataclass\n\nimport psycopg\nfrom psycopg.rows import class_row\n\n@dataclass\nclass UserRecord:\n    id: int\n    email: str\n\nwith psycopg.connect() as conn:\n    with conn.cursor(row_factory=class_row(UserRecord)) as cur:\n        cur.execute(\"SELECT id, email FROM users WHERE id = %s\", (1,))\n        print(cur.fetchone())\n```\n\n## Transactions\n\nBy default, Psycopg starts a transaction on the first database operation, including a plain `SELECT`. That surprises people coming from `psql` and is a common source of idle-in-transaction sessions.\n\nFor request/response style application code, the connection context is often enough:\n\n```python\nimport psycopg\n\nwith psycopg.connect() as conn:\n    with conn.cursor() as cur:\n        cur.execute(\n            \"INSERT INTO audit_log (event_type, payload) VALUES (%s, %s)\",\n            (\"user.created\", '{\"id\": 1}'),\n        )\n```\n\nFor long-lived workers, prefer autocommit and open explicit transaction blocks only when needed:\n\n```python\nimport psycopg\n\nwith psycopg.connect(autocommit=True) as conn:\n    with conn.transaction():\n        conn.execute(\n            \"INSERT INTO ledger (account_id, delta) VALUES (%s, %s)\",\n            (123, -50),\n        )\n        conn.execute(\n            \"INSERT INTO ledger (account_id, delta) VALUES (%s, %s)\",\n            (456, 50),\n        )\n```\n\nUse `autocommit=True` when you need statements that cannot run inside a transaction, such as `CREATE DATABASE`, `VACUUM`, or stored procedures that use transaction control.\n\nIf one statement fails, the transaction remains aborted until you call `rollback()`.\n\n## Safe SQL Composition\n\nUse `%s` or `%(name)s` placeholders only for values. Do not merge user input into SQL with `%`, `+`, or f-strings.\n\n```python\nwith conn.cursor() as cur:\n    cur.execute(\n        \"INSERT INTO events (kind, payload) VALUES (%s, %s)\",\n        (\"signup\", '{\"plan\":\"pro\"}'),\n    )\n```\n\nIf you need dynamic table or column names, use `psycopg.sql`:\n\n```python\nfrom psycopg import sql\n\ntable = \"users\"\ncolumns = [\"id\", \"email\"]\n\nquery = sql.SQL(\"SELECT {fields} FROM {table} WHERE id = %s\").format(\n    fields=sql.SQL(\", \").join(map(sql.Identifier, columns)),\n    table=sql.Identifier(table),\n)\n\nwith conn.cursor() as cur:\n    cur.execute(query, (42,))\n    print(cur.fetchone())\n```\n\nImportant server-side binding caveat: placeholders do not work for every SQL construct. Statements such as `SET`, `NOTIFY`, and many DDL commands cannot bind values server-side the same way normal DML does. For those cases, use PostgreSQL helper functions where possible or compose the statement with `psycopg.sql`.\n\n## Async Usage\n\nUse `AsyncConnection` and `AsyncCursor` for `asyncio` applications.\n\n```python\nimport asyncio\nimport os\n\nimport psycopg\nfrom psycopg.rows import dict_row\n\nasync def main() -> None:\n    async with await psycopg.AsyncConnection.connect(\n        os.environ[\"DATABASE_URL\"],\n        row_factory=dict_row,\n    ) as conn:\n        async with conn.cursor() as cur:\n            await cur.execute(\n                \"SELECT id, email FROM users WHERE active = %s\",\n                (True,),\n            )\n            async for row in cur:\n                print(row)\n\nasyncio.run(main())\n```\n\nAsync-specific notes:\n\n- `AsyncConnection.connect()` must be awaited before it can be used as a context manager. `async with psycopg.AsyncConnection.connect(...)` is wrong; use `async with await ...`.\n- On Windows, Psycopg async support is not compatible with the default `ProactorEventLoop`; use `SelectorEventLoop`.\n- Since Psycopg 3.1, async connect resolves DNS without blocking. Before 3.1, avoiding DNS blocking required `hostaddr` or `resolve_hostaddr_async()`.\n\n## Connection Pooling\n\nPsycopg pools live in `psycopg_pool` and are also installable through the `pool` extra.\n\n```python\nfrom psycopg_pool import ConnectionPool\n\npool = ConnectionPool(\n    conninfo=\"postgresql://app:secret@db.example.com:5432/appdb?sslmode=require\",\n    min_size=1,\n    max_size=10,\n)\n\nwith pool:\n    with pool.connection() as conn:\n        with conn.cursor() as cur:\n            cur.execute(\"SELECT now()\")\n            print(cur.fetchone())\n```\n\nFor async code:\n\n```python\nimport os\n\nfrom psycopg_pool import AsyncConnectionPool\n\nasync with AsyncConnectionPool(conninfo=os.environ[\"DATABASE_URL\"]) as pool:\n    async with pool.connection() as conn:\n        await conn.execute(\"SELECT 1\")\n```\n\nPool connections behave like normal Psycopg connections: leaving the `pool.connection()` block commits or rolls back the current transaction and returns the connection to the pool.\n\n## Concurrency Notes\n\n- `Connection` objects are thread-safe, but query execution on one connection is serialized.\n- `Cursor` objects are not thread-safe.\n- Connections are not process-safe; create them after worker processes fork.\n- If you need real parallel database work, use multiple connections or a pool instead of many cursors on one shared connection.\n\n## Common Pitfalls\n\n- Do not install `psycopg2` for new code unless you are maintaining an existing `psycopg2`-based dependency chain.\n- Do not write `import psycopg3`; the module is `psycopg`.\n- Do not forget that even `SELECT` starts a transaction by default. Long-lived jobs should usually use `autocommit=True` plus explicit `conn.transaction()` blocks.\n- Do not pass a scalar directly as the second argument to `execute()`. A single value still needs a sequence such as `(value,)`.\n- Do not quote placeholders. Use `WHERE id = %s`, not `WHERE id = '%s'`.\n- Do not try to bind identifiers with `%s`; use `psycopg.sql.Identifier`.\n- Do not assume async code gives parallel SQL execution on one connection. Access is still serialized per connection.\n- Do not forget that pooling is separate from the base install unless you add the `pool` extra.\n\n## Version-Sensitive Notes For Psycopg 3.3.3\n\n- PyPI stable is `3.3.3` on February 18, 2026. The docs root currently serves `3.3.4.dev1`, so examples for very new edge behavior may reflect the development branch.\n- Psycopg 3.3 supports Python `3.10` through `3.14`. Python `3.8` and `3.9` support ended before the 3.3 line.\n- Psycopg 3.3 adds template string queries for Python `3.14+`. They are safer than f-strings because Psycopg processes the interpolated values itself.\n- Psycopg 3.3 adds `Transaction.status` and improves cursor result-set navigation with `Cursor.results()` and `Cursor.set_result()`.\n- Psycopg 3.3 cursors are iterators, so `next(cur)` and `anext(cur)` now work directly.\n"
  },
  {
    "path": "content/psycopg2-binary/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"psycopg2-binary package guide for Python projects using PostgreSQL via psycopg2\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"postgresql,python,database,sql,db-api,psycopg2\"\n---\n\n# psycopg2-binary Python Package Guide\n\n## Golden Rule\n\nUse `psycopg2-binary` when you need the Psycopg 2 driver installed quickly from wheels, but write application code against the `psycopg2` import path and Psycopg 2 APIs. For production environments, the upstream project advises using the source-built `psycopg2` package instead of the binary wheel package. For new greenfield projects, upstream also advises considering Psycopg 3 (`psycopg`), because Psycopg 2 is maintained but not expected to receive new features.\n\n## Install\n\nFastest install:\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install \"psycopg2-binary==2.9.11\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"psycopg2-binary==2.9.11\"\npoetry add \"psycopg2-binary==2.9.11\"\n```\n\nThe package name is `psycopg2-binary`, but the import remains:\n\n```python\nimport psycopg2\n```\n\n## Connection Setup\n\n`psycopg2.connect()` accepts a DSN string or keyword arguments. The common connection fields are `dbname`, `user`, `password`, `host`, `port`, and libpq-supported extras such as `sslmode` and `options`.\n\nExample with environment variables:\n\n```bash\nexport PGHOST=localhost\nexport PGPORT=5432\nexport PGDATABASE=appdb\nexport PGUSER=app\nexport PGPASSWORD=secret\n```\n\n```python\nimport os\nimport psycopg2\n\nconn = psycopg2.connect(\n    dbname=os.environ[\"PGDATABASE\"],\n    user=os.environ[\"PGUSER\"],\n    password=os.environ[\"PGPASSWORD\"],\n    host=os.environ.get(\"PGHOST\", \"localhost\"),\n    port=os.environ.get(\"PGPORT\", \"5432\"),\n    sslmode=os.environ.get(\"PGSSLMODE\", \"prefer\"),\n)\n```\n\nExample with a DSN string:\n\n```python\nimport psycopg2\n\ndsn = \"dbname=appdb user=app password=secret host=localhost port=5432\"\nconn = psycopg2.connect(dsn)\n```\n\nUseful connection options:\n\n- `sslmode=\"require\"` or stricter in managed/cloud environments\n- `connect_timeout=5` to fail fast\n- `application_name=\"my-service\"` for PostgreSQL observability\n- `options=\"-c search_path=app,public\"` when schema selection must be explicit\n\n## Core Usage\n\n### Basic query flow\n\n```python\nimport psycopg2\n\nconn = psycopg2.connect(\n    dbname=\"appdb\",\n    user=\"app\",\n    password=\"secret\",\n    host=\"localhost\",\n    port=5432,\n)\n\ntry:\n    with conn.cursor() as cur:\n        cur.execute(\n            \"\"\"\n            CREATE TABLE IF NOT EXISTS users (\n                id serial PRIMARY KEY,\n                email text NOT NULL UNIQUE,\n                active boolean NOT NULL DEFAULT true\n            )\n            \"\"\"\n        )\n\n        cur.execute(\n            \"INSERT INTO users (email, active) VALUES (%s, %s) RETURNING id\",\n            (\"ada@example.com\", True),\n        )\n        user_id = cur.fetchone()[0]\n\n        cur.execute(\n            \"SELECT id, email, active FROM users WHERE id = %s\",\n            (user_id,),\n        )\n        row = cur.fetchone()\n\n    conn.commit()\n    print(row)\nexcept Exception:\n    conn.rollback()\n    raise\nfinally:\n    conn.close()\n```\n\n### Prefer context managers for transactions\n\nConnections and cursors support `with`. In Psycopg 2, leaving `with conn:` commits on success and rolls back on exception, but it does **not** close the connection.\n\n```python\nimport psycopg2\n\nconn = psycopg2.connect(\"dbname=appdb user=app password=secret host=localhost\")\ntry:\n    with conn:\n        with conn.cursor() as cur:\n            cur.execute(\n                \"INSERT INTO audit_log (event_type, payload) VALUES (%s, %s)\",\n                (\"user.created\", '{\"id\": 1}'),\n            )\nfinally:\n    conn.close()\n```\n\n### Use parameters, never string interpolation\n\nUse `%s` placeholders for values, even for integers and dates. Do not use Python `%` formatting, f-strings, or string concatenation to build value expressions.\n\n```python\ncur.execute(\n    \"SELECT id, email FROM users WHERE email = %s AND active = %s\",\n    (\"ada@example.com\", True),\n)\n```\n\nNamed parameters are supported too:\n\n```python\ncur.execute(\n    \"\"\"\n    UPDATE users\n    SET email = %(email)s\n    WHERE id = %(id)s\n    \"\"\",\n    {\"id\": 42, \"email\": \"new@example.com\"},\n)\n```\n\n### Dynamic identifiers need `psycopg2.sql`\n\nValues go through `execute(..., params)`. Table names, column names, and schema names must be composed with `psycopg2.sql`.\n\n```python\nfrom psycopg2 import sql\n\ntable_name = \"users\"\n\nquery = sql.SQL(\"SELECT id, email FROM {} WHERE active = %s\").format(\n    sql.Identifier(table_name)\n)\ncur.execute(query, (True,))\n```\n\n### Dict-like rows\n\nFor handler code and APIs, `RealDictCursor` is often more convenient than tuple rows.\n\n```python\nimport psycopg2\nfrom psycopg2.extras import RealDictCursor\n\nwith psycopg2.connect(\"dbname=appdb user=app password=secret host=localhost\") as conn:\n    with conn.cursor(cursor_factory=RealDictCursor) as cur:\n        cur.execute(\"SELECT id, email FROM users ORDER BY id LIMIT 2\")\n        rows = cur.fetchall()\n        print(rows[0][\"email\"])\n```\n\n### Bulk inserts\n\nFor large insert batches, prefer `psycopg2.extras.execute_values()` over looping `execute()` calls.\n\n```python\nfrom psycopg2.extras import execute_values\n\nrows = [\n    (\"ada@example.com\", True),\n    (\"grace@example.com\", True),\n    (\"linus@example.com\", False),\n]\n\nexecute_values(\n    cur,\n    \"INSERT INTO users (email, active) VALUES %s\",\n    rows,\n)\n```\n\n### Stream large result sets\n\nNamed cursors create server-side cursors so you do not pull the entire result set into memory at once.\n\n```python\nwith conn.cursor(name=\"users_stream\") as cur:\n    cur.itersize = 1000\n    cur.execute(\"SELECT id, email FROM users ORDER BY id\")\n    for row in cur:\n        process(row)\n```\n\n## Transactions And Autocommit\n\nPsycopg starts a transaction for normal statements. If you never commit or rollback, the session can remain idle in transaction and hold locks or prevent cleanup work.\n\nUse default transactional behavior for normal CRUD:\n\n```python\nwith conn:\n    with conn.cursor() as cur:\n        cur.execute(\"UPDATE accounts SET balance = balance - %s WHERE id = %s\", (10, 1))\n        cur.execute(\"UPDATE accounts SET balance = balance + %s WHERE id = %s\", (10, 2))\n```\n\nEnable autocommit only for commands that must run outside a transaction, such as `CREATE DATABASE` or `VACUUM`:\n\n```python\nconn.autocommit = True\nwith conn.cursor() as cur:\n    cur.execute(\"VACUUM\")\n```\n\n## JSON, Arrays, UUID, And PostgreSQL Types\n\nPsycopg 2 adapts many Python types automatically, including `None`, `bool`, `int`, `Decimal`, `datetime`, lists to PostgreSQL arrays, `UUID`, and JSON-capable values. For explicit JSON adaptation:\n\n```python\nfrom psycopg2.extras import Json\n\ncur.execute(\n    \"INSERT INTO events (kind, payload) VALUES (%s, %s)\",\n    (\"user.created\", Json({\"id\": 1, \"email\": \"ada@example.com\"})),\n)\n```\n\n## Errors And Diagnostics\n\nCatch broad DB-API exceptions when you need a rollback boundary, and use PostgreSQL-specific subclasses or SQLSTATE codes when behavior depends on the exact error.\n\n```python\nimport psycopg2\nfrom psycopg2 import errorcodes, errors\n\ntry:\n    cur.execute(\"INSERT INTO users (email) VALUES (%s)\", (\"ada@example.com\",))\nexcept errors.UniqueViolation:\n    conn.rollback()\n    raise\nexcept psycopg2.Error as exc:\n    conn.rollback()\n    if exc.pgcode == errorcodes.DEADLOCK_DETECTED:\n        raise RuntimeError(\"retry this transaction\") from exc\n    raise\n```\n\n## Connection Pooling\n\nOpening PostgreSQL connections is relatively expensive. For threaded apps, use `ThreadedConnectionPool`. `SimpleConnectionPool` is only for single-threaded applications.\n\n```python\nfrom psycopg2.pool import ThreadedConnectionPool\n\npool = ThreadedConnectionPool(\n    minconn=1,\n    maxconn=10,\n    dbname=\"appdb\",\n    user=\"app\",\n    password=\"secret\",\n    host=\"localhost\",\n    port=5432,\n)\n\nconn = pool.getconn()\ntry:\n    with conn:\n        with conn.cursor() as cur:\n            cur.execute(\"SELECT 1\")\nfinally:\n    pool.putconn(conn)\n```\n\n## Common Pitfalls\n\n- Package name and import name differ: install `psycopg2-binary`, import `psycopg2`.\n- Do not interpolate query values with f-strings or `%`; always pass parameters separately.\n- `%s` is the placeholder for all values. Do not switch to `%d` or quote placeholders yourself.\n- Do not use bound parameters for table or column names; use `psycopg2.sql.Identifier`.\n- `with conn:` manages the transaction only; it does not close the connection.\n- Long-lived transactions can leave sessions idle in transaction. Commit or rollback promptly.\n- Cursors are not safe to share across threads. Keep cursor scope local and use a pool or one connection per concurrent unit.\n- In forked worker models, create connections after the fork instead of reusing inherited connections.\n- `executemany()` is usually not the fastest bulk insert path for PostgreSQL; use `execute_values()` or `COPY` for larger loads.\n\n## Version-Sensitive Notes\n\n- The upstream docs and PyPI both currently show `2.9.11` as the active Psycopg 2 line as of March 12, 2026.\n- The 2.9.11 release notes add Python 3.14 support and drop Python 3.8 support, so treat Python 3.9+ as the safe baseline for this package version.\n- `psycopg2-binary` and `psycopg2` share the same runtime API; the difference is mainly packaging and linked client libraries.\n- Upstream states that `psycopg2-binary` is convenient for development and testing, but production deployments should prefer the source-built `psycopg2` package.\n- Upstream also states Psycopg 2 is still maintained but not expected to receive new features; new projects should consider Psycopg 3 (`psycopg`) if migration cost is low.\n- Psycopg 2.9 changed `with connection` behavior so it starts a transaction even on autocommit connections; avoid assuming the context manager is transaction-free.\n\n## Official Sources\n\n- Docs root: https://www.psycopg.org/docs/\n- Installation: https://www.psycopg.org/docs/install.html\n- Basic usage: https://www.psycopg.org/docs/usage.html\n- SQL composition: https://www.psycopg.org/docs/sql.html\n- Extras: https://www.psycopg.org/docs/extras.html\n- Pooling: https://www.psycopg.org/docs/pool.html\n- PyPI: https://pypi.org/project/psycopg2-binary/\n"
  },
  {
    "path": "content/pulumi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pulumi Python package guide for project setup, stack config, outputs, secrets, and state backends\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.225.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pulumi,python,iac,infrastructure,cloud,devops\"\n---\n\n# Pulumi Python Package Guide\n\n## Golden Rule\n\n`pulumi` is the core Python SDK, not the whole toolchain. For real Pulumi programs you usually need all three pieces:\n\n- the Pulumi CLI\n- the `pulumi` Python package\n- one or more provider packages such as `pulumi-aws`, `pulumi-kubernetes`, or `pulumi-random`\n\nIn code, keep deployment logic declarative. Treat `Output` values as asynchronous deployment-time values, use `Config` for stack settings, and avoid calling `Output.get()` inside a normal `pulumi up` program.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `3.225.1`.\n- As of March 12, 2026, PyPI lists `3.225.1` as the latest stable `pulumi` release. Newer `3.226.0b...` entries are prereleases.\n- The Pulumi install page currently advertises CLI `3.225.1`, so the CLI and Python SDK stable versions are aligned right now.\n- The Python API reference uses a `latest` docs URL. Use PyPI for exact package pinning and the Pulumi docs for behavior, project structure, and CLI workflow.\n\n## Install\n\nInstall the CLI first, then the Python packages for your project.\n\nCLI examples:\n\n```bash\nbrew install pulumi/tap/pulumi\n```\n\n```bash\ncurl -fsSL https://get.pulumi.com | sh\n```\n\nFor Python, pin the core SDK and add the provider packages your stack uses:\n\n```bash\npython -m pip install \"pulumi==3.225.1\"\npython -m pip install \"pulumi-aws\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pulumi==3.225.1\"\npoetry add \"pulumi==3.225.1\"\n```\n\nIf the project already has a lockfile, follow that instead of mixing package manager conventions.\n\n## Initialize A Python Project\n\nThe fastest clean start is a Pulumi template for Python:\n\n```bash\nmkdir infra\ncd infra\npython -m venv .venv\nsource .venv/bin/activate\npulumi login\npulumi new aws-python\npulumi config set aws:region us-west-2\npulumi up\n```\n\nThe generated project usually includes:\n\n- `Pulumi.yaml`: project metadata and runtime\n- `Pulumi.<stack>.yaml`: stack-scoped config values\n- `__main__.py`: entry point for the Python program\n- `requirements.txt` or `pyproject.toml`: Python dependencies, including `pulumi` and provider packages\n\nIf the stack already exists but the local environment does not, install dependencies first and then run:\n\n```bash\npulumi stack select dev\npulumi preview\n```\n\n## Core Usage\n\n### Read Config And Export Values\n\nUse `pulumi.Config()` for stack config and `pulumi.export()` for stack outputs.\n\n```python\nimport pulumi\n\nconfig = pulumi.Config()\n\nenvironment = config.get(\"environment\") or pulumi.get_stack()\nowner = config.require(\"owner\")\ndb_password = config.require_secret(\"dbPassword\")\n\npulumi.export(\"stackName\", pulumi.get_stack())\npulumi.export(\"environment\", environment)\npulumi.export(\"owner\", owner)\npulumi.export(\n    \"serviceUrl\",\n    pulumi.Output.format(\"https://{}.{}.example.com\", pulumi.get_project(), environment),\n)\npulumi.export(\"dbPassword\", db_password)\n```\n\nCLI commands that populate those values:\n\n```bash\npulumi config set owner platform\npulumi config set environment prod\npulumi config set --secret dbPassword 'correct-horse-battery-staple'\n```\n\n### Work With `Output` Values Correctly\n\nPulumi values that come from resources, stack references, or secret config are often `Output[...]`, not plain Python values.\n\nUse `Output.all(...)` and `apply(...)` to transform them:\n\n```python\nimport pulumi\n\nhost = pulumi.Output.from_input(\"api.internal.example\")\nport = pulumi.Output.from_input(443)\n\norigin = pulumi.Output.all(host=host, port=port).apply(\n    lambda args: f\"https://{args['host']}:{args['port']}\"\n)\n\npulumi.export(\"origin\", origin)\n```\n\nUse `Output.format(...)` when string formatting is all you need:\n\n```python\nimport pulumi\n\nsubdomain = pulumi.Output.from_input(\"app\")\nstack = pulumi.get_stack()\n\nurl = pulumi.Output.format(\"https://{}.{}.example.com\", subdomain, stack)\npulumi.export(\"url\", url)\n```\n\nDo not call `Output.get()` during deployment. The API reference explicitly limits `get()` to code that runs after deployment is complete.\n\n### Build Reusable Components\n\nFor shared infrastructure building blocks, define a `ComponentResource` and call `register_outputs()`.\n\n```python\nfrom __future__ import annotations\n\nimport pulumi\n\nclass ServiceEndpoint(pulumi.ComponentResource):\n    url: pulumi.Output[str]\n\n    def __init__(\n        self,\n        name: str,\n        domain: pulumi.Input[str],\n        opts: pulumi.ResourceOptions | None = None,\n    ) -> None:\n        super().__init__(\"example:components:ServiceEndpoint\", name, None, opts)\n\n        self.url = pulumi.Output.format(\"https://{}\", domain)\n\n        self.register_outputs(\n            {\n                \"url\": self.url,\n            }\n        )\n\nservice = ServiceEndpoint(\"api\", domain=\"api.example.com\")\npulumi.export(\"serviceUrl\", service.url)\n```\n\n### Read Values From Another Stack\n\nUse `StackReference` when one stack needs outputs from another stack:\n\n```python\nimport pulumi\n\nnetwork = pulumi.StackReference(\"acme/network/prod\")\nsubnet_id = network.get_output(\"subnetId\")\nvpc_id = network.get_output(\"vpcId\")\n\npulumi.export(\"subnetId\", subnet_id)\npulumi.export(\"vpcId\", vpc_id)\n```\n\nThis is the normal way to compose environments such as `network`, `platform`, and `application` stacks without hardcoding cloud identifiers.\n\n## Config, Secrets, And Authentication\n\nPulumi has two separate auth layers that agents often mix up:\n\n1. Pulumi backend auth for state storage and stack operations\n2. Cloud provider auth for actually creating resources\n\n### Pulumi Backend Login\n\nDefault Pulumi Cloud login:\n\n```bash\npulumi login\n```\n\nNon-interactive CI usually uses an access token:\n\n```bash\nexport PULUMI_ACCESS_TOKEN=\"...\"\npulumi login\n```\n\nOther supported backends include local state and object storage:\n\n```bash\npulumi login --local\npulumi login s3://my-pulumi-state\npulumi login azblob://my-container\npulumi login gs://my-pulumi-state\n```\n\n### Stack Config And Secret Values\n\n- Use `pulumi config set` for normal values.\n- Use `pulumi config set --secret` for credentials and anything that should stay encrypted in state.\n- In Python, read normal values with `Config.get()` or `Config.require()`.\n- Read encrypted values with `Config.get_secret()` or `Config.require_secret()`.\n\nProvider config is typically namespaced. For example, AWS region lives under `aws:region`, not a plain project key:\n\n```bash\npulumi config set aws:region us-west-2\n```\n\n### Cloud Provider Credentials\n\nThe `pulumi` package does not replace provider auth. After `pulumi login`, you still need the normal credentials for the provider package you are using:\n\n- AWS: environment variables, shared config, profiles, IAM roles\n- Azure: Azure CLI, service principal, managed identity\n- GCP: ADC or service account credentials\n- Kubernetes: `KUBECONFIG` or explicit cluster config\n\nIf `pulumi preview` succeeds but provider operations fail, the usual problem is missing provider credentials rather than a Pulumi backend login issue.\n\n## Common Pitfalls\n\n- Installing only `pulumi` is not enough. Most projects also need the Pulumi CLI and one or more provider packages.\n- Do not create resources inside `Output.apply(...)` unless you are deliberately accepting deferred, harder-to-reason-about resource graphs. Prefer passing `Output` values directly into resource arguments.\n- Do not call `Output.get()` in a normal Pulumi program. Use `apply`, `Output.all`, or `Output.format` instead.\n- Secret config returns secret outputs. Treat them as `Output` values and avoid logging or stringifying them casually.\n- `Pulumi.<stack>.yaml` is stack-specific. If config seems to \"disappear\", check that the selected stack is the one you expect.\n- `pulumi refresh` updates state from the provider, but it does not replace understanding your desired program changes. Do not use refresh as a substitute for reviewing diffs.\n- The project and stack names affect config namespaces, stack references, and backend paths. Renaming them midstream can break assumptions in automation and CI.\n- Keep provider package versions in sync with the project lockfile. Copying examples that assume a different provider major version is a common source of broken code.\n\n## Practical Guidance For Agents\n\n1. Start by confirming the stack backend, selected stack, and provider package set before editing code.\n2. When you need runtime-like values from resources, model them as `Output` transformations instead of forcing eager Python values.\n3. Put user-provided settings in stack config, not hardcoded constants in `__main__.py`.\n4. Use `ComponentResource` for repeatable abstractions and `StackReference` for cross-stack wiring.\n5. When debugging, separate backend login issues from provider credential issues before changing code.\n\n## Official Sources\n\n- Python API reference: `https://www.pulumi.com/docs/reference/pkg/python/pulumi/`\n- Install Pulumi CLI: `https://www.pulumi.com/docs/iac/download-install/`\n- Pulumi Python language guide: `https://www.pulumi.com/docs/iac/languages-sdks/python/`\n- Configuration concepts: `https://www.pulumi.com/docs/iac/concepts/config/`\n- Inputs and outputs: `https://www.pulumi.com/docs/iac/concepts/inputs-outputs/`\n- Stack outputs and references: `https://www.pulumi.com/docs/iac/concepts/stacks/`\n- State backends and login: `https://www.pulumi.com/docs/iac/concepts/state-and-backends/`\n- PyPI package page: `https://pypi.org/project/pulumi/`\n"
  },
  {
    "path": "content/puppeteer/docs/puppeteer/javascript/DOC.md",
    "content": "---\nname: puppeteer\ndescription: \"JavaScript guide for `puppeteer`, including browser installation, launch configuration, navigation, selectors, screenshots, PDFs, and common automation patterns.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"24.39.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"puppeteer,javascript,browser,automation,testing,scraping,npm\"\n---\n\n# Puppeteer Guide\n\n## Golden Rule\n\nUse the `puppeteer` package when you want one package to handle both the Puppeteer API and a compatible browser install.\n\nIf you skip the browser download, also provide a browser executable path or install a browser separately before calling `puppeteer.launch()`.\n\nNo API key or remote service authentication is required. Puppeteer controls a local or already-running browser.\n\n## Install\n\nInstall the runtime package:\n\n```bash\nnpm install puppeteer\n```\n\nBy default, `puppeteer` downloads a compatible browser during installation.\n\nIf your environment already provides a browser binary, skip the bundled download:\n\n```bash\nPUPPETEER_SKIP_DOWNLOAD=1 npm install puppeteer\n```\n\nIf you skip the download and still want Puppeteer to manage browser binaries later, install one explicitly:\n\n```bash\nnpx puppeteer browsers install chrome\n```\n\n## Optional Environment Variables\n\nUse environment variables when you need to control browser installation or execution without hardcoding paths in application code.\n\n```bash\nexport PUPPETEER_SKIP_DOWNLOAD=1\nexport PUPPETEER_EXECUTABLE_PATH=\"/path/to/chrome-or-chromium\"\n```\n\n- `PUPPETEER_SKIP_DOWNLOAD=1` skips the browser download during package installation.\n- `PUPPETEER_EXECUTABLE_PATH` points Puppeteer at a browser binary you manage yourself.\n\n## Initialization\n\n### Launch a browser\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nconst browser = await puppeteer.launch({\n  headless: true,\n});\n\ntry {\n  const page = await browser.newPage();\n  await page.goto(\"https://example.com\", { waitUntil: \"networkidle2\" });\n  console.log(await page.title());\n} finally {\n  await browser.close();\n}\n```\n\n### Launch with an executable path from the environment\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nfunction getLaunchOptions() {\n  return {\n    headless: true,\n    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,\n  };\n}\n\nconst browser = await puppeteer.launch(getLaunchOptions());\n```\n\nUsing `process.env.PUPPETEER_EXECUTABLE_PATH || undefined` avoids passing an empty string into `executablePath`.\n\n### Connect to an already-running browser\n\nUse `connect()` when Chrome or Chromium is already running with remote debugging enabled.\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nconst browser = await puppeteer.connect({\n  browserURL: \"http://127.0.0.1:9222\",\n});\n\nconst page = await browser.newPage();\nawait page.goto(\"https://example.com\");\n```\n\n## Common Workflows\n\n### Open a page and wait for content\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nexport async function openHomePage(url) {\n  const browser = await puppeteer.launch({ headless: true });\n\n  try {\n    const page = await browser.newPage();\n    await page.setViewport({ width: 1280, height: 800 });\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n    await page.waitForSelector(\"body\", { timeout: 30_000 });\n    return await page.title();\n  } finally {\n    await browser.close();\n  }\n}\n```\n\n### Wait for selectors and extract structured data\n\n`$$eval()` is a practical way to return plain serializable data from the page.\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nexport async function readProducts(url) {\n  const browser = await puppeteer.launch({ headless: true });\n\n  try {\n    const page = await browser.newPage();\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n\n    await page.waitForSelector(\".product-card\", {\n      visible: true,\n      timeout: 30_000,\n    });\n\n    return await page.$$eval(\".product-card\", (cards) => {\n      return cards.map((card) => ({\n        title: card.querySelector(\"h2\")?.textContent?.trim() ?? \"\",\n        price: card.querySelector(\".price\")?.textContent?.trim() ?? \"\",\n      }));\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\n### Fill a form and submit it\n\nIf a click triggers navigation, start `waitForNavigation()` and the click together.\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nexport async function login(url, email, password) {\n  const browser = await puppeteer.launch({ headless: true });\n\n  try {\n    const page = await browser.newPage();\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n\n    await page.type('input[name=\"email\"]', email);\n    await page.type('input[name=\"password\"]', password);\n\n    await Promise.all([\n      page.waitForNavigation({ waitUntil: \"networkidle2\" }),\n      page.click('button[type=\"submit\"]'),\n    ]);\n\n    await page.waitForSelector(\"[data-test='account-home']\", {\n      visible: true,\n      timeout: 30_000,\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\n### Capture a screenshot\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nexport async function captureScreenshot(url, outputPath = \"page.png\") {\n  const browser = await puppeteer.launch({ headless: true });\n\n  try {\n    const page = await browser.newPage();\n    await page.setViewport({ width: 1440, height: 900 });\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n\n    await page.screenshot({\n      path: outputPath,\n      fullPage: true,\n      type: \"png\",\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\n### Generate a PDF\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nexport async function writePdf(url, outputPath = \"page.pdf\") {\n  const browser = await puppeteer.launch({ headless: true });\n\n  try {\n    const page = await browser.newPage();\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n    await page.pdf({\n      path: outputPath,\n      format: \"A4\",\n      printBackground: true,\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\n## Important Pitfalls\n\n- `puppeteer` downloads a browser by default during installation. If you skip that step, `launch()` still needs a usable browser.\n- Always close the browser in a `finally` block so background browser processes do not accumulate.\n- Use `waitForSelector()` before interacting with dynamic pages instead of assuming the DOM is ready immediately after `goto()`.\n- If an action causes navigation, pair it with `waitForNavigation()` in `Promise.all()` so you do not miss the navigation event.\n- `evaluate()`, `$eval()`, and `$$eval()` should return serializable values, not DOM nodes or handles.\n- This guide covers `puppeteer`. If you switch to `puppeteer-core`, browser download and configuration behavior is different.\n\n## Minimal End-to-End Example\n\n```javascript\nimport puppeteer from \"puppeteer\";\n\nfunction getLaunchOptions() {\n  return {\n    headless: true,\n    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,\n  };\n}\n\nexport async function fetchHeadlines(url) {\n  const browser = await puppeteer.launch(getLaunchOptions());\n\n  try {\n    const page = await browser.newPage();\n\n    await page.setViewport({ width: 1280, height: 800 });\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n    await page.waitForSelector(\"h1, h2\", {\n      visible: true,\n      timeout: 30_000,\n    });\n\n    return await page.$$eval(\"h1, h2\", (elements) => {\n      return elements\n        .slice(0, 10)\n        .map((element) => element.textContent?.trim() ?? \"\")\n        .filter(Boolean);\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\nThis example keeps the main integration points explicit:\n\n- launch configuration can come from environment variables\n- the browser lifecycle stays inside one function\n- page reads return plain JavaScript data\n"
  },
  {
    "path": "content/pyarrow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pyarrow package guide for Python: Arrow arrays and tables, Parquet, datasets, filesystems, and pandas interop\"\nmetadata:\n  languages: \"python\"\n  versions: \"23.0.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pyarrow,apache-arrow,columnar,parquet,dataset,pandas\"\n---\n\n# pyarrow Python Package Guide\n\n## What This Package Is For\n\n`pyarrow` is the Python binding for Apache Arrow. Use it when you need:\n\n- in-memory columnar data structures such as `Array`, `Table`, `ChunkedArray`, and `RecordBatch`\n- Parquet, IPC/Feather, CSV, JSON, ORC, and dataset IO\n- fast conversion between Arrow and pandas\n- filesystem access for local files and object stores such as S3\n- vectorized compute kernels through `pyarrow.compute`\n\nIf a project only needs pandas CSV or JSON loading, `pyarrow` may be unnecessary. Reach for it when Arrow-native types, Parquet, datasets, or cross-language columnar data matter.\n\n## Install\n\n`pyarrow` 23.0.1 supports Python 3.10 and newer.\n\n```bash\npip install pyarrow==23.0.1\n```\n\nCommon alternatives:\n\n```bash\nuv add pyarrow==23.0.1\npoetry add pyarrow==23.0.1\nconda install -c conda-forge pyarrow=23.0.1\n```\n\nFor timezone-aware timestamp work on Windows or minimal Linux images, also install timezone data if your environment does not already provide it:\n\n```bash\npip install tzdata\n```\n\n## Import Pattern\n\n```python\nimport pyarrow as pa\nimport pyarrow.compute as pc\nimport pyarrow.parquet as pq\nimport pyarrow.dataset as ds\n```\n\nAdd other modules only when needed:\n\n```python\nfrom pyarrow import csv\nfrom pyarrow import fs\n```\n\n## Core Data Structures\n\n### Arrays and Schemas\n\nUse Arrow types explicitly when nullability, timestamp precision, decimals, nested types, or cross-language compatibility matter.\n\n```python\nimport pyarrow as pa\n\nschema = pa.schema(\n    [\n        (\"id\", pa.int64()),\n        (\"name\", pa.string()),\n        (\"score\", pa.float64()),\n        (\"active\", pa.bool_()),\n    ]\n)\n\nids = pa.array([1, 2, 3], type=pa.int64())\nnames = pa.array([\"a\", \"b\", None], type=pa.string())\n```\n\n### Tables\n\n`pa.table(...)` is the quickest way to build a table from Python objects. Use an explicit schema when you need stable downstream typing.\n\n```python\nimport pyarrow as pa\n\ntable = pa.table(\n    {\n        \"id\": [1, 2, 3],\n        \"name\": [\"alice\", \"bob\", \"carol\"],\n        \"score\": [9.2, 8.7, 9.8],\n    }\n)\n\nprint(table.schema)\nprint(table.num_rows, table.num_columns)\n```\n\nFor batch-oriented pipelines:\n\n```python\nbatch = pa.record_batch(\n    [\n        pa.array([1, 2, 3]),\n        pa.array([\"x\", \"y\", \"z\"]),\n    ],\n    names=[\"id\", \"label\"],\n)\n```\n\n## Compute Kernels\n\nUse `pyarrow.compute` for vectorized operations over Arrow arrays and table columns.\n\n```python\nimport pyarrow as pa\nimport pyarrow.compute as pc\n\nvalues = pa.array([1, 2, None, 4, 5])\n\nclean = pc.fill_null(values, 0)\nfiltered = pc.filter(clean, pc.greater(clean, 2))\ntotal = pc.sum(clean).as_py()\n\nprint(filtered)\nprint(total)\n```\n\nFor dataset scanning, build expressions with `pc.field(...)`:\n\n```python\npredicate = (pc.field(\"year\") == 2026) & (pc.field(\"amount\") > 0)\n```\n\n## Pandas Interop\n\n### pandas to Arrow\n\nUse `Table.from_pandas` when Arrow is an IO or compute layer under a pandas workflow.\n\n```python\nimport pandas as pd\nimport pyarrow as pa\n\ndf = pd.DataFrame(\n    {\n        \"id\": [1, 2, 3],\n        \"name\": [\"alice\", \"bob\", None],\n        \"created_at\": pd.to_datetime(\n            [\"2026-03-01T10:00:00Z\", \"2026-03-02T10:00:00Z\", \"2026-03-03T10:00:00Z\"],\n            utc=True,\n        ),\n    }\n)\n\ntable = pa.Table.from_pandas(df, preserve_index=False)\n```\n\n### Arrow to pandas\n\n```python\nround_tripped = table.to_pandas()\n```\n\nImportant behavior:\n\n- `preserve_index=False` avoids writing pandas index columns unless you need them.\n- pandas `object` columns infer poorly when values are mixed or mostly null; pass an explicit schema if types matter.\n- Arrow preserves more exact typing than pandas. Converting back to pandas can widen integer columns with nulls unless you opt into pandas nullable dtypes in your own pipeline.\n\n## Parquet\n\n`pyarrow.parquet` is the direct Parquet API. Use it for single-file reads and writes.\n\n### Write a Parquet file\n\n```python\nimport pyarrow as pa\nimport pyarrow.parquet as pq\n\ntable = pa.table(\n    {\n        \"id\": [1, 2, 3],\n        \"country\": [\"us\", \"ca\", \"us\"],\n        \"amount\": [125.5, 89.0, 42.25],\n    }\n)\n\npq.write_table(\n    table,\n    \"data/example.parquet\",\n    compression=\"zstd\",\n    row_group_size=100_000,\n)\n```\n\n### Read a Parquet file\n\n```python\nimport pyarrow.parquet as pq\n\ntable = pq.read_table(\"data/example.parquet\")\n```\n\n### Read selected columns or filtered rows\n\n```python\nimport pyarrow.parquet as pq\n\ntable = pq.read_table(\n    \"data/example.parquet\",\n    columns=[\"id\", \"amount\"],\n    filters=[(\"country\", \"=\", \"us\")],\n)\n```\n\nUse `filters` only when the underlying file or dataset layout can benefit from predicate pushdown. For partitioned directory trees, `pyarrow.dataset` is usually a better fit than direct `pq.read_table`.\n\n## Datasets\n\nUse `pyarrow.dataset` for partitioned data, directory trees, multi-file scans, and dataset-style writes.\n\n### Open a dataset\n\n```python\nimport pyarrow.dataset as ds\n\ndataset = ds.dataset(\"warehouse/events\", format=\"parquet\", partitioning=\"hive\")\ntable = dataset.to_table(columns=[\"event_id\", \"year\", \"amount\"])\n```\n\n### Scan with a predicate\n\n```python\nimport pyarrow.compute as pc\nimport pyarrow.dataset as ds\n\ndataset = ds.dataset(\"warehouse/events\", format=\"parquet\", partitioning=\"hive\")\n\ntable = dataset.to_table(\n    filter=(pc.field(\"year\") == 2026) & (pc.field(\"amount\") > 0),\n    columns=[\"event_id\", \"amount\", \"year\"],\n)\n```\n\n### Write a partitioned dataset\n\n```python\nimport pyarrow as pa\nimport pyarrow.dataset as ds\n\ntable = pa.table(\n    {\n        \"event_id\": [1, 2, 3],\n        \"year\": [2026, 2026, 2025],\n        \"month\": [3, 3, 12],\n        \"amount\": [10, 20, 30],\n    }\n)\n\nds.write_dataset(\n    table,\n    base_dir=\"warehouse/events\",\n    format=\"parquet\",\n    partitioning=[\"year\", \"month\"],\n    existing_data_behavior=\"overwrite_or_ignore\",\n)\n```\n\nCommon write controls worth remembering:\n\n- `partitioning=...` controls the directory layout.\n- `existing_data_behavior=...` determines whether existing files are overwritten, ignored, or cause failure.\n- `basename_template=...` is useful when deterministic output filenames matter.\n\n## Filesystems and Cloud/Object Storage\n\nUse `pyarrow.fs` when you want Arrow-native filesystem objects instead of fsspec wrappers.\n\n### Local filesystem\n\n```python\nfrom pyarrow import fs\n\nlocal = fs.LocalFileSystem()\n```\n\n### Build a filesystem from a URI\n\n```python\nfrom pyarrow import fs\n\nfilesystem, path = fs.FileSystem.from_uri(\"s3://my-bucket/datasets/events\")\nprint(type(filesystem), path)\n```\n\n### S3\n\n```python\nfrom pyarrow import fs\n\ns3 = fs.S3FileSystem(\n    region=\"us-east-1\",\n    access_key=\"AWS_ACCESS_KEY_ID\",\n    secret_key=\"AWS_SECRET_ACCESS_KEY\",\n)\n```\n\n`S3FileSystem` can also use ambient AWS credentials, assumed roles (`role_arn=...`), anonymous access (`anonymous=True`), and custom endpoints for S3-compatible stores.\n\nYou can combine a filesystem with dataset APIs:\n\n```python\nimport pyarrow.dataset as ds\nfrom pyarrow import fs\n\ns3 = fs.S3FileSystem(region=\"us-east-1\")\ndataset = ds.dataset(\n    \"my-bucket/warehouse/events\",\n    filesystem=s3,\n    format=\"parquet\",\n    partitioning=\"hive\",\n)\n```\n\n### fsspec interop\n\nIf the rest of the project already uses fsspec, wrap it with `PyFileSystem(FSSpecHandler(...))` instead of rewriting the storage layer.\n\n## Initialization Checklist\n\nFor most projects, the minimal setup is:\n\n1. Install `pyarrow` at the version your project expects.\n2. Decide whether your primary interface is `Table`, `dataset`, or pandas interop.\n3. Pin explicit Arrow schemas for columns that must stay stable across files or services.\n4. Choose the right IO layer:\n   `pyarrow.parquet` for single files, `pyarrow.dataset` for partitioned collections, `pyarrow.fs` for storage access.\n5. Verify object-store credentials before debugging dataset reads.\n\n## Common Pitfalls\n\n- Arrow types are stricter than pandas and Python containers. Inference can surprise you when values are mixed, nested, or mostly null.\n- `Table.from_pandas` will preserve indexes unless you disable that behavior.\n- pandas `object` columns are a common source of unexpected Arrow schemas. Prefer explicit pandas dtypes or an explicit Arrow schema.\n- `pq.read_table()` on a directory may work, but `ds.dataset()` is the better abstraction for partitioned datasets and scanner-style filtering.\n- Predicate pushdown only helps when the file format and layout support it. Do not assume every filter avoids reading all data.\n- S3 issues are often credential or region issues, not Parquet issues. Confirm filesystem setup independently.\n- Timezone-aware timestamps may need system tzdata available in the runtime.\n\n## Version-Sensitive Notes For 23.0.1\n\n- The 23.0.1 docs and PyPI metadata both point to Python 3.10+ support. Do not assume older Python versions are still supported.\n- Prefer the dataset APIs for modern partitioned-lake patterns rather than older file-by-file loops.\n- Use explicit schemas for data interchange boundaries. Arrow and pandas keep evolving their dtype interop, and implicit inference is where regressions usually show up first.\n- When copying examples from older blog posts, re-check parameter names against the 23.0.1 API reference, especially dataset and filesystem APIs.\n\n## Official Sources Used\n\n- PyPI package page: https://pypi.org/project/pyarrow/\n- Python docs root: https://arrow.apache.org/docs/python/\n- API reference: https://arrow.apache.org/docs/python/api.html\n- Install guide: https://arrow.apache.org/docs/python/install.html\n- Getting started: https://arrow.apache.org/docs/python/getstarted.html\n- Compute guide: https://arrow.apache.org/docs/python/compute.html\n- Parquet guide: https://arrow.apache.org/docs/python/parquet.html\n- Dataset guide: https://arrow.apache.org/docs/python/dataset.html\n- Filesystems guide: https://arrow.apache.org/docs/python/filesystems.html\n- pandas integration guide: https://arrow.apache.org/docs/python/pandas.html\n"
  },
  {
    "path": "content/pyasn1-modules/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pyasn1-modules package guide for Python projects that decode and encode RFC-based ASN.1 structures with pyasn1\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.4.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"pyasn1-modules,pyasn1,asn1,x509,cms,ldap,snmp\"\n---\n\n# pyasn1-modules Python Package Guide\n\n## Golden Rule\n\nUse `pyasn1-modules` for prebuilt ASN.1 schema definitions, and use `pyasn1` codecs to decode or encode bytes against those schemas.\n\nThis package does not create network clients, manage certificates, or validate trust chains for you. It gives you Python classes for standards-based ASN.1 structures such as X.509, CMS, LDAP, SNMP, and PKCS so you can parse or build those payloads correctly.\n\n## Install\n\n`pyasn1-modules 0.4.2` requires Python 3.8 or newer. The maintainer `pyproject.toml` declares `pyasn1>=0.6.1,<0.7.0`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pyasn1-modules==0.4.2\"\n```\n\nIf you pin both packages explicitly:\n\n```bash\npython -m pip install \"pyasn1-modules==0.4.2\" \"pyasn1>=0.6.1,<0.7.0\"\n```\n\nThere are no environment variables, credentials, or client initialization steps. Usage starts with imports.\n\n## Imports\n\n```python\nfrom pyasn1.codec.der.decoder import decode as der_decode\nfrom pyasn1.codec.der.encoder import encode as der_encode\nfrom pyasn1.codec.native.encoder import encode as to_native\nfrom pyasn1_modules import pem, rfc5280\n```\n\n`pyasn1-modules` ships many RFC-specific modules. The maintainer repository includes modules such as `rfc2251.py`, `rfc5280.py`, `rfc5652.py`, `rfc5958.py`, and `rfc7030.py`. Import the RFC module that matches the payload you are working with, then pass its top-level ASN.1 type to a `pyasn1` codec.\n\n## Decode A PEM Certificate\n\nThe package includes `pyasn1_modules.pem` helpers for PEM and base64 inputs. `readPemFromFile()` returns DER bytes for the first matching PEM block in a text file.\n\n```python\nfrom pyasn1.codec.der.decoder import decode as der_decode\nfrom pyasn1.codec.native.encoder import encode as to_native\nfrom pyasn1_modules import pem, rfc5280\n\nwith open(\"certificate.pem\", \"r\", encoding=\"ascii\") as fh:\n    der_bytes = pem.readPemFromFile(fh)\n\ncertificate, rest = der_decode(\n    der_bytes,\n    asn1Spec=rfc5280.Certificate(),\n)\n\nif rest:\n    raise ValueError(f\"Unexpected trailing bytes: {len(rest)}\")\n\nnative_certificate = to_native(certificate)\n\nprint(native_certificate[\"tbsCertificate\"][\"serialNumber\"])\nprint(native_certificate[\"tbsCertificate\"][\"issuer\"])\nprint(native_certificate[\"tbsCertificate\"][\"subject\"])\n```\n\nUse this pattern whenever you already know which ASN.1 structure the bytes should contain:\n\n1. Read PEM or DER bytes.\n2. Import the matching RFC module from `pyasn1_modules`.\n3. Pass `asn1Spec=...` to the decoder.\n4. Check `rest` so you do not silently ignore trailing data.\n\n## Read Specific PEM Block Types\n\n`readPemBlocksFromFile()` is useful when one file can contain different block types and you need to choose which one you got back.\n\n```python\nfrom pyasn1_modules import pem\n\nmarkers = (\n    (\"-----BEGIN CERTIFICATE-----\", \"-----END CERTIFICATE-----\"),\n    (\"-----BEGIN PKCS7-----\", \"-----END PKCS7-----\"),\n)\n\nwith open(\"bundle.pem\", \"r\", encoding=\"ascii\") as fh:\n    marker_index, substrate = pem.readPemBlocksFromFile(fh, *markers)\n\nif marker_index == 0:\n    print(\"Decoded a certificate block\")\nelif marker_index == 1:\n    print(\"Decoded a PKCS7 block\")\nelse:\n    raise ValueError(\"No supported PEM block found\")\n```\n\nFor base64 text that is not wrapped in PEM markers, `pem.readBase64fromText()` and `pem.readBase64FromFile()` return decoded bytes you can feed into BER, CER, or DER decoders.\n\n## Re-Encode A Parsed Object\n\nOnce you have a typed ASN.1 object, re-encode it with the matching codec:\n\n```python\nfrom pyasn1.codec.der.decoder import decode as der_decode\nfrom pyasn1.codec.der.encoder import encode as der_encode\nfrom pyasn1_modules import pem, rfc5280\n\nwith open(\"certificate.pem\", \"r\", encoding=\"ascii\") as fh:\n    original_der = pem.readPemFromFile(fh)\n\ncertificate, rest = der_decode(original_der, asn1Spec=rfc5280.Certificate())\nif rest:\n    raise ValueError(\"Unexpected trailing bytes\")\n\nencoded_der = der_encode(certificate)\n\nassert encoded_der == original_der\n```\n\nUse BER codecs for BER payloads and DER codecs for DER payloads. `pyasn1-modules` gives you the schema objects; the wire-format codec still comes from `pyasn1`.\n\n## Generating Missing RFC Modules\n\nThe maintainer README describes `pyasn1-modules` as a collection of precompiled ASN.1 modules and points to `asn1ate` if the RFC or schema you need is not already included. Use that path when you have ASN.1 syntax for a standard or private schema that `pyasn1-modules` does not ship.\n\n## Common Pitfalls\n\n- Do not treat `pyasn1-modules` as a certificate or CMS validation library. It parses structures; it does not verify signatures, trust stores, revocation, or application-level policy.\n- Open PEM inputs in text mode. The package PEM helpers read lines and strip marker text before base64-decoding.\n- Always pass `asn1Spec=` to the decoder when you know the expected structure. Without it, `pyasn1` will decode into generic ASN.1 objects that are harder to work with correctly.\n- Always inspect the decoder `rest` value. Non-empty trailing bytes usually mean you decoded the wrong top-level type or only part of the payload.\n- Keep `pyasn1` compatible with the maintainer pin. For `pyasn1-modules 0.4.2`, the upstream project declares `pyasn1>=0.6.1,<0.7.0`.\n\n## Version Notes For 0.4.2\n\n- PyPI currently lists `0.4.2` as the package version for `pyasn1-modules`.\n- The maintainer `pyproject.toml` for the current main branch also uses version `0.4.2`.\n- If your project is pinned to an older `pyasn1-modules` release, confirm the paired `pyasn1` range before copying examples from newer docs.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/pyasn1-modules/\n- Maintainer repository: https://github.com/pyasn1/pyasn1-modules\n- Maintainer README: https://github.com/pyasn1/pyasn1-modules/blob/main/README.md\n- Maintainer `pyproject.toml`: https://github.com/pyasn1/pyasn1-modules/blob/main/pyproject.toml\n- Maintainer `pem.py`: https://github.com/pyasn1/pyasn1-modules/blob/main/pyasn1_modules/pem.py\n- pyasn1 codec documentation: https://pyasn1.readthedocs.io/en/stable/pyasn1/codec/der/contents.html\n- pyasn1 native codec documentation: https://pyasn1.readthedocs.io/en/stable/pyasn1/codec/native/contents.html\n"
  },
  {
    "path": "content/pycodestyle/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pycodestyle package guide for checking Python source against selected PEP 8 style rules\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.14.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"pycodestyle,python,lint,pep8,style,cli\"\n---\n\n# pycodestyle Python Package Guide\n\n## Golden Rule\n\nUse `pycodestyle` when you need the upstream PEP 8 style checker itself: a small, dependency-free CLI and library for reporting style errors and warnings. It does not autofix code, it does not try to cover every rule in PEP 8, and the maintainer docs point you to `flake8` plus extensions for broader plugin-based linting.\n\nFor `pycodestyle 2.14.0`, PyPI lists `Requires: Python >=3.9`, and the 2.14.0 changelog adds Python 3.14 support.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pycodestyle==2.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pycodestyle==2.14.0\"\npoetry add --group dev \"pycodestyle==2.14.0\"\n```\n\nThere is no auth step and no required environment variable. `pycodestyle` is a local checker.\n\n## Run The CLI\n\nCheck one file:\n\n```bash\npycodestyle app.py\n```\n\nCheck multiple files or directories:\n\n```bash\npycodestyle src/ tests/\n```\n\nStop after the first occurrence of each error code:\n\n```bash\npycodestyle --first src/\n```\n\nShow the offending source line and the related PEP 8 text:\n\n```bash\npycodestyle --show-source --show-pep8 src/package/module.py\n```\n\nPrint aggregate statistics and fail the command if any issue is found:\n\n```bash\npycodestyle --statistics --count src/ tests/\n```\n\n`pycodestyle` exits with status `1` when it reports any errors or warnings, so it fits directly into CI jobs and pre-merge checks.\n\n## Configure Project Defaults\n\n`pycodestyle` reads configuration from:\n\n- user config: `~/.pycodestyle` on Windows, `XDG_CONFIG_HOME/pycodestyle` when `XDG_CONFIG_HOME` is set, otherwise `~/.config/pycodestyle`\n- project config: `setup.cfg` or `tox.ini` with a `[pycodestyle]` section\n\nThe maintainer docs only document `setup.cfg` and `tox.ini` for project-level config. Do not assume `pyproject.toml` settings will be read by `pycodestyle` itself.\n\nExample `setup.cfg`:\n\n```ini\n[pycodestyle]\nexclude = .git,__pycache__,.venv,build,dist\nfilename = *.py\nmax-line-length = 88\nmax-doc-length = 72\nstatistics = True\nshow-source = True\n```\n\nEquivalent `tox.ini` section:\n\n```ini\n[pycodestyle]\nignore = E203,W503\nselect = E,W\nformat = pylint\n```\n\nYou can also point the library API at a specific config file:\n\n```python\nimport pycodestyle\n\nstyle = pycodestyle.StyleGuide(config_file=\"tox.ini\")\nreport = style.check_files([\"src\", \"tests\"])\n```\n\n## Common CLI Workflows\n\nCheck only a subset of codes:\n\n```bash\npycodestyle --select=E,W6 src/\n```\n\nIgnore specific codes:\n\n```bash\npycodestyle --ignore=E203,W503 src/\n```\n\nUse a custom machine-readable format:\n\n```bash\npycodestyle --format='%(path)s|%(row)d|%(col)d| %(code)s %(text)s' src/\n```\n\nLimit checks to changed lines from a unified diff:\n\n```bash\ngit diff --unified=0 | pycodestyle --diff\n```\n\nWhen `--diff` is enabled, `pycodestyle` reads the diff from stdin and reports only lines included in the patch.\n\n## Use The Python API\n\nCheck multiple paths with `StyleGuide`:\n\n```python\nimport pycodestyle\n\nstyle = pycodestyle.StyleGuide(\n    quiet=False,\n    ignore=[\"E203\", \"W503\"],\n    max_line_length=88,\n)\n\nreport = style.check_files([\"src\", \"tests\"])\n\nif report.total_errors:\n    raise SystemExit(1)\n```\n\nCheck a single file with `Checker`:\n\n```python\nimport pycodestyle\n\nchecker = pycodestyle.Checker(\n    \"src/package/module.py\",\n    show_source=True,\n)\nfile_errors = checker.check_all()\n\nprint(f\"Found {file_errors} errors\")\n```\n\n`StyleGuide` is the right entry point when you want to check several paths, reuse configuration, or embed the tool in test or CI code. `Checker` is the lower-level single-file API.\n\n## Use In Tests\n\nThe maintainer docs show `pycodestyle` embedded in `unittest`:\n\n```python\nimport unittest\n\nimport pycodestyle\n\n\nclass TestCodeFormat(unittest.TestCase):\n    def test_conformance(self) -> None:\n        style = pycodestyle.StyleGuide(quiet=True)\n        result = style.check_files([\"src\", \"tests\"])\n        self.assertEqual(\n            result.total_errors,\n            0,\n            \"Found code style errors (and warnings).\",\n        )\n```\n\n## Important Pitfalls\n\n- `--ignore` overrides the built-in ignore defaults instead of adding to them. If you pass `--ignore`, include every code you still want ignored.\n- `# noqa` can disable checks for a line, but the docs recommend reserving it for special cases.\n- `max-line-length` defaults to `79`. `max-doc-length` is different: doc/comment line length checking is off unless you set it.\n- `pycodestyle` does not cover naming conventions, docstring conventions, or automatic fixing. The docs point to `flake8` with extensions, `pydocstyle`, and separate fixers for those jobs.\n- Project configuration is discovered from the checked path upward. If you pass `--config=path`, only that config file is used.\n- `pycodestyle` is intentionally lightweight and has no external runtime dependencies, so broader lint stacks often wrap it rather than extending it directly.\n"
  },
  {
    "path": "content/pycparser/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pycparser guide for parsing C source into an AST, traversing nodes, and generating C from Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"pycparser,c,parser,ast,codegen,python\"\n---\n\n# pycparser Python Package Guide\n\n## Golden Rule\n\nUse `pycparser` when you need a Python-native C parser that builds an AST. For `pycparser 3.0`, the maintained package requires Python 3.10+ and the supported public entry points are `CParser`, `parse_file`, `c_ast`, and `c_generator`.\n\nMost real C files must be preprocessed before parsing. `pycparser` can run `cpp`, `gcc -E`, or `clang -E` for you through `parse_file(..., use_cpp=True)`.\n\n## Install\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pycparser==3.0\"\n```\n\n`pycparser` itself has no external Python dependencies, but parsing non-trivial source usually also requires a C preprocessor on your machine.\n\n## Parse C Source Already In Memory\n\nUse `CParser` directly when your input string is already preprocessed or simple enough not to need the C preprocessor:\n\n```python\nfrom pycparser import CParser\n\nsource = r\"\"\"\nint add(int left, int right) {\n    return left + right;\n}\n\"\"\"\n\nparser = CParser()\nast = parser.parse(source, filename=\"example.c\")\n\nast.show()\n```\n\nPass a real filename when you have one. Error coordinates in the AST and parse failures are more useful when `filename` is set.\n\n## Parse A File With The C Preprocessor\n\n`parse_file` can invoke the preprocessor for you. This is the normal path for source files that use `#include`, `#define`, or other preprocessor features.\n\nThis example uses two app-level environment variables:\n\n```bash\nexport PYCPARSER_CPP=clang\nexport PYCPARSER_FAKE_LIBC_INCLUDE=/absolute/path/to/pycparser/utils/fake_libc_include\n```\n\n`pycparser` does not read these names itself; they are just a clean way to configure your application.\n\n```python\nimport os\nfrom pycparser import parse_file\n\ncpp_path = os.environ.get(\"PYCPARSER_CPP\", \"cpp\")\nfake_libc = os.environ[\"PYCPARSER_FAKE_LIBC_INCLUDE\"]\n\nast = parse_file(\n    \"hello.c\",\n    use_cpp=True,\n    cpp_path=cpp_path,\n    cpp_args=[\n        \"-E\",\n        rf\"-I{fake_libc}\",\n    ],\n    encoding=\"utf-8\",\n)\n\nast.show(showcoord=True)\n```\n\n`cpp_args` can be a string or a list of strings. A list is usually easier to extend safely.\n\n## Walk The AST\n\nUse `c_ast.NodeVisitor` to inspect the parse tree:\n\n```python\nfrom pycparser import CParser, c_ast\n\nsource = r\"\"\"\nint add(int left, int right) {\n    return left + right;\n}\n\nvoid log_message(void) {\n}\n\"\"\"\n\nclass FunctionCollector(c_ast.NodeVisitor):\n    def __init__(self) -> None:\n        self.names: list[str] = []\n\n    def visit_FuncDef(self, node: c_ast.FuncDef) -> None:\n        self.names.append(node.decl.name)\n        self.generic_visit(node)\n\nparser = CParser()\nast = parser.parse(source, filename=\"example.c\")\n\ncollector = FunctionCollector()\ncollector.visit(ast)\n\nprint(collector.names)\n```\n\n## Rewrite The AST And Emit C Again\n\n`pycparser` ships a C code generator. A common workflow is parse -> transform -> generate:\n\n```python\nfrom pycparser import CParser, c_ast, c_generator\n\nsource = r\"\"\"\nvoid greet(void) {\n}\n\"\"\"\n\nclass ParamAdder(c_ast.NodeVisitor):\n    def visit_FuncDecl(self, node: c_ast.FuncDecl) -> None:\n        type_decl = c_ast.TypeDecl(\n            declname=\"_hidden\",\n            quals=[],\n            align=[],\n            type=c_ast.IdentifierType([\"int\"]),\n        )\n        new_param = c_ast.Decl(\n            name=\"_hidden\",\n            quals=[],\n            align=[],\n            storage=[],\n            funcspec=[],\n            type=type_decl,\n            init=None,\n            bitsize=None,\n            coord=node.coord,\n        )\n\n        if node.args is None:\n            node.args = c_ast.ParamList(params=[new_param])\n        else:\n            node.args.params.append(new_param)\n\nparser = CParser()\nast = parser.parse(source, filename=\"example.c\")\n\nParamAdder().visit(ast)\n\ngenerator = c_generator.CGenerator()\nprint(generator.visit(ast))\n```\n\n## Common Pitfalls\n\n- Do not point `parse_file(..., use_cpp=True)` at raw source unless a compatible preprocessor is installed and reachable through `cpp_path` or `PATH`.\n- The maintainer README is explicit that `utils/fake_libc_include` is not installed with the `pip` package. If you need those headers, copy or vendor them from the source distribution or repository checkout.\n- The fake libc headers now include C11 constructs. The maintainer docs note they may fail if you force the preprocessor to an older standard such as `-std=c99`.\n- `pycparser` aims for full C99 and some C11, but only limited GCC extensions. If your codebase depends heavily on GCC-specific syntax, preprocess or normalize it before parsing.\n- `CParser` still accepts old lexer/yacc compatibility arguments, but the current source says arguments after `lexer` are kept for backward compatibility and are otherwise unused.\n\n## Version Notes For 3.0\n\n- `pyproject.toml` for `pycparser 3.0` sets `requires-python = \">=3.10\"`.\n- The maintained package version is `3.0` on PyPI, while the repository README and source expose it as `v3.00` / `__version__ = \"3.00\"`.\n"
  },
  {
    "path": "content/pydantic/docs/ai/python/DOC.md",
    "content": "---\nname: ai\ndescription: \"PydanticAI framework for building typed Python agents with tools, structured output, message history, and multi-provider model support\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.67.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydantic-ai,python,agents,llm,pydantic,tools,structured-output\"\n---\n\n# PydanticAI Python Package Guide\n\n## Golden Rule\n\nUse `pydantic-ai` when you want typed agent workflows in Python, but treat it as an orchestration layer, not a model provider. The package gives you `Agent`, tool registration, dependency injection, structured output validation, message history, and provider abstractions; you still need to pick a model backend and configure its credentials separately.\n\n## Install\n\nInstall the full package when you want the default provider integrations and optional observability dependencies:\n\n```bash\npython -m pip install \"pydantic-ai==1.67.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pydantic-ai==1.67.0\"\npoetry add \"pydantic-ai==1.67.0\"\n```\n\nIf you want a smaller install and only the providers you actually use, install `pydantic-ai-slim` with extras:\n\n```bash\npython -m pip install \"pydantic-ai-slim[openai]==1.67.0\"\npython -m pip install \"pydantic-ai-slim[anthropic]==1.67.0\"\npython -m pip install \"pydantic-ai-slim[logfire]==1.67.0\"\n```\n\nUse the non-slim package unless dependency size is a real constraint. Agents often fail by installing `pydantic-ai-slim` with no provider extras, then trying to use a provider client that was never installed.\n\n## Model And Credential Setup\n\nThe shortest path is to choose a model with the `provider:model_name` shorthand:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\"openai:gpt-4o\")\n```\n\nFor OpenAI-backed models, set `OPENAI_API_KEY` before running the agent:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nThen use the agent normally:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    instructions=\"Be concise and return plain text.\",\n)\n```\n\nIf you need a custom base URL or a preconfigured provider client, instantiate the provider explicitly:\n\n```python\nfrom openai import AsyncOpenAI\nfrom pydantic_ai import Agent\nfrom pydantic_ai.models.openai import OpenAIResponsesModel\nfrom pydantic_ai.providers.openai import OpenAIProvider\n\nclient = AsyncOpenAI(\n    api_key=\"token-from-secret-store\",\n    base_url=\"https://my-proxy.example/v1\",\n)\n\nmodel = OpenAIResponsesModel(\n    \"gpt-4o\",\n    provider=OpenAIProvider(openai_client=client),\n)\n\nagent = Agent(model)\n```\n\nNotes:\n\n- `pydantic-ai` supports multiple providers; each provider has its own auth rules and environment variables.\n- Use provider shorthand only when the provider can be inferred cleanly from the model string.\n- For OpenAI-compatible gateways, the docs distinguish native OpenAI models from gateway-style provider routing such as `gateway/openai:...`; copy the provider syntax from the relevant provider page, not from blog posts.\n\n## Core Usage\n\n### Minimal agent\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    instructions=\"You are a helpful Python assistant.\",\n)\n\nresult = agent.run_sync(\"Write a slugify function.\")\nprint(result.output)\n```\n\n`run_sync()` is fine for scripts and CLIs. In async applications, prefer `await agent.run(...)`.\n\n### Typed structured output\n\nUse `output_type` to validate the final output against a Pydantic model:\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_ai import Agent\n\nclass City(BaseModel):\n    name: str\n    country_code: str\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    instructions=\"Extract a city from the prompt.\",\n    output_type=City,\n)\n\nresult = agent.run_sync(\"The conference is in Berlin, Germany.\")\nprint(result.output.name)\nprint(result.output.country_code)\n```\n\nWhen you need more control over how output is enforced, `pydantic-ai` also documents `NativeOutput`, `ToolOutput`, `PromptedOutput`, and `TextOutput`.\n\n### Tools with typed context\n\nUse `@agent.tool` when the tool needs a `RunContext` and shared dependencies:\n\n```python\nfrom dataclasses import dataclass\n\nfrom pydantic_ai import Agent, RunContext\n\n@dataclass\nclass SupportDeps:\n    customer_tier: str\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    deps_type=SupportDeps,\n    instructions=\"Answer using the available support lookup tools.\",\n)\n\n@agent.tool\ndef current_tier(ctx: RunContext[SupportDeps]) -> str:\n    return ctx.deps.customer_tier\n\nresult = agent.run_sync(\n    \"What support level does this customer have?\",\n    deps=SupportDeps(customer_tier=\"gold\"),\n)\nprint(result.output)\n```\n\nUse `@agent.tool_plain` only for tools that do not need `ctx`.\n\n### Continue a conversation with message history\n\nPersist message history from one run and pass it back into the next run:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\"openai:gpt-4o\")\n\nfirst = agent.run_sync(\"My name is Sam.\")\nsecond = agent.run_sync(\n    \"What is my name?\",\n    message_history=first.all_messages(),\n)\n\nprint(second.output)\n```\n\nFor storage or replay, the docs also cover serializing messages to JSON and restoring them later.\n\n## Output And Tooling Patterns\n\n- Prefer `output_type=MyModel` when downstream code needs typed data instead of free-form text.\n- Keep tool signatures simple and well-typed. `pydantic-ai` uses schema generation from type hints and docstrings, so vague signatures degrade tool calling quality.\n- Add parameter descriptions in docstrings when a tool has multiple arguments or ambiguous names.\n- Use plain text output only when you truly want prose. Most automation flows are easier to test and safer to maintain with typed output.\n\n## Testing\n\nThe testing docs provide purpose-built model doubles such as `TestModel` and `FunctionModel`, which are better than hitting real providers in unit tests.\n\nTypical test pattern:\n\n```python\nfrom pydantic_ai import Agent\nfrom pydantic_ai.models.test import TestModel\n\nagent = Agent(TestModel(), instructions=\"Return a greeting.\")\n\nresult = agent.run_sync(\"Say hello.\")\nassert result.output is not None\n```\n\nPractical guidance:\n\n- Keep real model calls out of unit tests.\n- Use `FunctionModel` when you want deterministic behavior for tool and output validation logic.\n- If your test suite imports modules that construct agents at import time, make sure model requests are disabled unless the test explicitly opts into live calls.\n\n## MCP And Ecosystem Features\n\n`pydantic-ai` can expose Model Context Protocol toolsets via stdio or HTTP transports. Use the built-in MCP support when your agent should call external tool servers instead of registering every tool locally.\n\nThe package also integrates with Pydantic Logfire for tracing and observability. If you want built-in instrumentation, install the appropriate extra and enable instrumentation from the Logfire docs before debugging production agent behavior.\n\n## Common Pitfalls\n\n- `pydantic-ai` is not the same package as `pydantic`. Installing one does not install the other workflow assumptions you may need.\n- The package name is `pydantic-ai`, but imports are from `pydantic_ai`.\n- If you use `pydantic-ai-slim`, install the provider extras you need or your provider integration may fail at runtime.\n- Older examples may use deprecated terminology like `result_type` or refer to `result.data`; current docs use `output_type` and `result.output`.\n- `message_history` must come from compatible message objects; do not pass arbitrary chat dicts from another SDK without adapting them first.\n- Tool schemas come from annotations and docstrings. Missing descriptions or overly broad `dict`/`Any` types make tool calling worse.\n- `run_sync()` blocks. In FastAPI, asyncio workers, or other async runtimes, use `await agent.run(...)` instead.\n- Provider credentials are separate from `pydantic-ai` itself. `pip install pydantic-ai` does not configure `OPENAI_API_KEY`, Anthropic keys, or any gateway tokens.\n\n## Version-Sensitive Notes For 1.67.0\n\n- PyPI and the official docs currently align on `1.67.0` as of 2026-03-12.\n- `1.67.0` is in the stable `1.x` line. The official version policy says `v1` should avoid intentional breaking changes in minor releases; treat pre-v1 blog posts and old examples as suspect.\n- The docs still call out some beta surfaces in the broader ecosystem, especially around `pydantic_graph`. Do not assume beta-marked pieces have the same stability guarantees as the core agent APIs.\n- If you are migrating from older `0.x` examples, prefer the current docs for naming and result handling. The modern API centers on `Agent`, `instructions`, `output_type`, `RunContext`, and `result.output`.\n\n## Official Sources\n\n- Docs root: `https://ai.pydantic.dev/`\n- Installation: `https://ai.pydantic.dev/install/`\n- Agent API: `https://ai.pydantic.dev/agent/`\n- Models overview: `https://ai.pydantic.dev/models/overview/`\n- OpenAI provider: `https://ai.pydantic.dev/models/openai/`\n- Tools: `https://ai.pydantic.dev/tools/`\n- Dependencies: `https://ai.pydantic.dev/dependencies/`\n- Message history: `https://ai.pydantic.dev/message-history/`\n- Output: `https://ai.pydantic.dev/output/`\n- MCP: `https://ai.pydantic.dev/mcp/`\n- Testing: `https://ai.pydantic.dev/testing/`\n- Version policy: `https://ai.pydantic.dev/version-policy/`\n- PyPI: `https://pypi.org/project/pydantic-ai/`\n"
  },
  {
    "path": "content/pydantic/docs/core/python/DOC.md",
    "content": "---\nname: core\ndescription: \"pydantic-core 2.42.0 package guide for low-level validation, parsing, and serialization in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.42.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydantic,python,validation,serialization,json,schema\"\n---\n\n# pydantic-core Python Package Guide\n\n## What It Is\n\n`pydantic-core` is the low-level validation and serialization engine used by Pydantic v2. Use it directly when you need to validate or serialize data from an explicit `CoreSchema` without `BaseModel`.\n\nPrefer `pydantic` for normal application code. Reach for `pydantic-core` when you are:\n\n- building a framework, adapter, or plugin system\n- validating hot-path data with minimal overhead\n- consuming JSON bytes directly\n- generating and reusing `SchemaValidator` or `SchemaSerializer` instances yourself\n\n## Install\n\n```bash\npip install \"pydantic-core==2.42.0\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"pydantic-core==2.42.0\"\n```\n\nIf you use Poetry:\n\n```bash\npoetry add \"pydantic-core==2.42.0\"\n```\n\nNotes:\n\n- The package name is `pydantic-core`, but the import is `pydantic_core`.\n- PyPI normalizes the project URL to the underscore form: `pydantic_core`.\n\n## Core Validator Pattern\n\nBuild a schema once, compile a `SchemaValidator` once, and reuse it.\n\n```python\nfrom pydantic_core import SchemaValidator, ValidationError, core_schema\n\nuser_schema = core_schema.typed_dict_schema(\n    {\n        \"name\": core_schema.typed_dict_field(core_schema.str_schema()),\n        \"age\": core_schema.typed_dict_field(core_schema.int_schema(ge=0)),\n        \"is_admin\": core_schema.typed_dict_field(\n            core_schema.bool_schema(),\n            required=False,\n        ),\n    },\n    extra_behavior=\"forbid\",\n)\n\nvalidator = SchemaValidator(user_schema)\n\nuser = validator.validate_python({\"name\": \"Ada\", \"age\": \"41\"})\nassert user == {\"name\": \"Ada\", \"age\": 41}\n\ntry:\n    validator.validate_python({\"name\": \"Ada\", \"age\": -1})\nexcept ValidationError as exc:\n    print(exc.errors())\n```\n\nOperational notes:\n\n- Validation is coercive by default. `\"41\"` becomes `41` unless you make the schema or call strict.\n- `extra_behavior=\"forbid\"` is the low-level way to reject unknown keys in typed dict input.\n- Reuse compiled validators instead of creating them in tight loops.\n\n## JSON And String Inputs\n\nUse the entry point that matches the raw input you already have.\n\n### JSON bytes or JSON text\n\n```python\nfrom pydantic_core import SchemaValidator, core_schema\n\nnumbers_schema = core_schema.list_schema(core_schema.int_schema())\nvalidator = SchemaValidator(numbers_schema)\n\nnumbers = validator.validate_json(b'[1, 2, \"3\"]')\nassert numbers == [1, 2, 3]\n```\n\nUse `validate_json(...)` when the payload is already JSON. It avoids a separate `json.loads(...)` step.\n\n### String-only maps from env vars, forms, or query params\n\n```python\nfrom pydantic_core import SchemaValidator, core_schema\n\nsettings_schema = core_schema.typed_dict_schema(\n    {\n        \"port\": core_schema.typed_dict_field(core_schema.int_schema()),\n        \"debug\": core_schema.typed_dict_field(\n            core_schema.bool_schema(),\n            required=False,\n        ),\n    }\n)\n\nvalidator = SchemaValidator(settings_schema)\nsettings = validator.validate_strings({\"port\": \"8080\", \"debug\": \"true\"})\n\nassert settings == {\"port\": 8080, \"debug\": True}\n```\n\nUse `validate_strings(...)` only when your input is already split into strings. It is not a replacement for parsing JSON bytes.\n\n## Fast JSON Parsing Without A Schema\n\nIf you only need fast JSON decoding and do not need schema validation yet, use `from_json(...)`.\n\n```python\nfrom pydantic_core import from_json\n\npayload = from_json(b'{\"name\":\"Ada\",\"active\":true}')\nassert payload == {\"name\": \"Ada\", \"active\": True}\n```\n\nThis is useful when:\n\n- you want a fast parse step before separate business logic\n- you need partial or staged processing\n- you are integrating `pydantic-core` into another validation layer\n\n## Serialization\n\nUse `SchemaSerializer` when you want serialization rules tied to the same schema shape.\n\n```python\nfrom pydantic_core import SchemaSerializer, core_schema\n\nschema = core_schema.typed_dict_schema(\n    {\n        \"name\": core_schema.typed_dict_field(core_schema.str_schema()),\n        \"age\": core_schema.typed_dict_field(core_schema.int_schema()),\n    }\n)\n\nserializer = SchemaSerializer(schema)\nvalue = {\"name\": \"Ada\", \"age\": 41}\n\npython_value = serializer.to_python(value)\njson_bytes = serializer.to_json(value, indent=2)\n\nassert python_value == {\"name\": \"Ada\", \"age\": 41}\nprint(json_bytes.decode(\"utf-8\"))\n```\n\nSerialization notes:\n\n- `to_python(...)` returns Python objects.\n- `to_json(...)` returns `bytes`.\n- If another layer expects JSON-compatible Python objects instead of bytes, use `to_jsonable_python(...)`.\n\n## Validation Behavior And Config\n\nMost behavior is controlled in one of three places:\n\n- the schema itself, such as `strict=True` on `int_schema(...)`\n- per-call flags on `validate_python(...)`, `validate_json(...)`, and `validate_strings(...)`\n- reusable validator config using the `CoreConfig` fields documented in the upstream API\n\nSimple strict-mode example:\n\n```python\nfrom pydantic_core import SchemaValidator, ValidationError, core_schema\n\nstrict_ints = SchemaValidator(\n    core_schema.list_schema(core_schema.int_schema(strict=True))\n)\n\nassert strict_ints.validate_python([1, 2, 3]) == [1, 2, 3]\n\ntry:\n    strict_ints.validate_python([\"1\", 2, 3])\nexcept ValidationError as exc:\n    print(exc.errors())\n```\n\nUseful runtime flags in the official API docs include:\n\n- `strict` to disable coercion for that call\n- `extra` to control extra-field behavior for that call\n- `from_attributes` when validating from object attributes\n- `by_alias` and `by_name` for alias-aware lookups\n- `allow_partial` for intentionally incomplete or streamed input\n\n## When To Use `pydantic-core` Directly\n\nUse `pydantic-core` directly when:\n\n- you need a standalone validator without `BaseModel`\n- you are generating schemas programmatically\n- you need to validate JSON bytes at a low level\n- you want explicit control over serialization behavior\n\nPrefer `pydantic` when:\n\n- you want `BaseModel`\n- you want authoring driven by Python type hints\n- you want model methods, settings integration, or JSON Schema generation from models\n- you are writing normal application code rather than framework internals\n\n## Config And Auth\n\nThere is no network client, authentication flow, API key setting, or service endpoint setup in `pydantic-core`.\n\nThe relevant \"configuration\" is validation and serialization behavior:\n\n- schema constraints\n- strictness and extra-field handling\n- alias and attribute lookup behavior\n- serializer output mode\n\nIf your project needs environment-backed settings or secret loading, use `pydantic-settings` alongside `pydantic`, not `pydantic-core` alone.\n\n## Common Pitfalls\n\n- Installing `pydantic-core` but importing `pydantic-core` instead of `pydantic_core`.\n- Rebuilding validators or serializers per request instead of compiling once and reusing them.\n- Assuming validation is strict by default. Most schemas coerce unless configured otherwise.\n- Using `validate_python(...)` after already receiving raw JSON bytes. Prefer `validate_json(...)`.\n- Forgetting that `to_json(...)` returns `bytes`, not `str`.\n- Writing large raw schema dictionaries by hand. Use `pydantic_core.core_schema` helpers for maintainable code.\n\n## Version-Sensitive Notes For `2.42.0`\n\n- PyPI lists `2.42.0` as the current package version and requires Python `>=3.9`.\n- The official API docs live under `docs.pydantic.dev/latest/...`; they are authoritative, but they are not a version-pinned docs snapshot.\n- The standalone `pydantic/pydantic-core` GitHub repository is archived and marked read-only. Active development moved into the main `pydantic` repository under `pydantic-core/`.\n- If your application is pinned to an older `2.x` release, verify method signatures and flags against the installed wheel before copying examples from the latest docs.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/pydantic_core/\n- API docs: https://docs.pydantic.dev/latest/api/pydantic_core/\n- Repository: https://github.com/pydantic/pydantic-core\n- Active code location notice: https://github.com/pydantic/pydantic/tree/main/pydantic-core\n"
  },
  {
    "path": "content/pydantic/docs/extra-types/python/DOC.md",
    "content": "---\nname: extra-types\ndescription: \"pydantic-extra-types 2.11.0 guide for validating colors, countries, phone numbers, payment cards, coordinates, and time zones in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.11.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"pydantic,pydantic-extra-types,python,validation,types,phone-numbers,countries,timezones\"\n---\n\n# pydantic-extra-types Python Package Guide\n\n## What It Is\n\n`pydantic-extra-types` is the separately installed package for Pydantic v2 extra field types. Use it when a model field should validate structured values such as CSS colors, ISO country codes, phone numbers, payment card numbers, latitude/longitude pairs, or IANA time zone names.\n\nThere is no client object, auth flow, or environment-variable setup. You import the type you need and use it directly in a Pydantic model.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pydantic-extra-types==2.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pydantic-extra-types==2.11.0\"\npoetry add \"pydantic-extra-types==2.11.0\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"pydantic-extra-types[phonenumbers]==2.11.0\"\npython -m pip install \"pydantic-extra-types[all]==2.11.0\"\n```\n\nNotes:\n\n- PyPI lists Python `>=3.9` for `2.11.0`.\n- The package is for the Pydantic v2 ecosystem; these types are no longer imported from `pydantic` itself.\n- If your runtime does not have an IANA timezone database available, install `tzdata` before using `TimeZoneName`.\n\n## Core Pattern\n\nUse extra types as normal field annotations in `BaseModel` classes:\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_extra_types.color import Color\nfrom pydantic_extra_types.coordinate import Coordinate\nfrom pydantic_extra_types.country import CountryAlpha2\nfrom pydantic_extra_types.timezone_name import TimeZoneName\n\n\nclass Warehouse(BaseModel):\n    accent_color: Color\n    country: CountryAlpha2\n    location: Coordinate\n    timezone: TimeZoneName\n\n\nwarehouse = Warehouse.model_validate(\n    {\n        \"accent_color\": \"rgb(0, 170, 255)\",\n        \"country\": \"US\",\n        \"location\": (37.7749, -122.4194),\n        \"timezone\": \"America/Los_Angeles\",\n    }\n)\n\nprint(warehouse.accent_color.as_hex())\nprint(warehouse.country.alpha3)\nprint(warehouse.location.latitude, warehouse.location.longitude)\nprint(str(warehouse.timezone))\n```\n\nWhy this is useful:\n\n- `Color` parses common CSS-style color inputs and gives you serializer helpers such as `as_hex()`.\n- `CountryAlpha2` validates ISO 3166 alpha-2 values and exposes related ISO metadata.\n- `Coordinate` stores latitude and longitude together as one validated value.\n- `TimeZoneName` validates timezone identifiers such as `America/Los_Angeles`.\n\n## Common Workflows\n\n### Payment card validation\n\nUse `PaymentCardNumber` when a field must validate card-number structure and expose derived metadata:\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_extra_types.payment import PaymentCardNumber\n\n\nclass CardInput(BaseModel):\n    number: PaymentCardNumber\n\n\ncard = CardInput.model_validate({\"number\": \"4111111111111111\"}).number\n\nprint(card.brand)\nprint(card.bin)\nprint(card.last4)\nprint(card.masked)\n```\n\nThis is the current import path to use in Pydantic v2 code. Do not copy older examples that import `PaymentCardNumber` from `pydantic.types`.\n\n### Phone number parsing and normalization\n\n`PhoneNumber` support depends on the `phonenumbers` package. For the default behavior, use the built-in type:\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_extra_types.phone_numbers import PhoneNumber\n\n\nclass Contact(BaseModel):\n    support_number: PhoneNumber\n\n\ncontact = Contact.model_validate({\"support_number\": \"+1 650-253-0000\"})\nprint(contact.support_number)\n```\n\nIf you need application-specific output or region rules, use `PhoneNumberValidator` with `Annotated`:\n\n```python\nfrom typing import Annotated, Union\n\nimport phonenumbers\nfrom pydantic import BaseModel\nfrom pydantic_extra_types.phone_numbers import PhoneNumberValidator\n\nUSNationalPhone = Annotated[\n    Union[str, phonenumbers.PhoneNumber],\n    PhoneNumberValidator(\n        default_region=\"US\",\n        supported_regions=[\"US\"],\n        number_format=\"NATIONAL\",\n    ),\n]\n\n\nclass Signup(BaseModel):\n    phone: USNationalPhone\n\n\nsignup = Signup.model_validate({\"phone\": \"650-253-0000\"})\nprint(signup.phone)\n```\n\nUse a subclass of `PhoneNumber` instead when you want one reusable policy shared across many models.\n\n### Standalone validation with `TypeAdapter`\n\nYou do not need a wrapper model for one-off validation:\n\n```python\nfrom pydantic import TypeAdapter\nfrom pydantic_extra_types.country import CountryAlpha2\nfrom pydantic_extra_types.timezone_name import TimeZoneName\n\ncountry = TypeAdapter(CountryAlpha2).validate_python(\"DE\")\ntimezone = TypeAdapter(TimeZoneName).validate_python(\"Europe/Berlin\")\n\nprint(country.alpha3)\nprint(str(timezone))\n```\n\nThis is the simplest pattern for parsing config values, CLI inputs, or isolated request fields.\n\n## Common Pitfalls\n\n- `pydantic-extra-types` is a separate install. Importing `Color` or `PaymentCardNumber` from old `pydantic` examples is a v1-era pattern.\n- There is no runtime initialization step. If validation fails, the fix is usually the input value or a missing optional dependency, not missing client setup.\n- `PhoneNumber` requires the `phonenumbers` dependency. Install the `phonenumbers` extra before using it.\n- `TimeZoneName` relies on the IANA timezone database. Install `tzdata` if your deployment image does not already provide timezone data.\n- The main Pydantic types docs note that strictness and extra constraints are not applied to these extra types. If you need narrower rules, add a validator, use `Annotated` metadata such as `PhoneNumberValidator`, or define a subtype such as a custom `PhoneNumber` subclass.\n- The official docs root uses `/latest/`, so copy examples cautiously if your project is pinned to a much older or newer wheel than `2.11.0`.\n\n## Version-Sensitive Notes For `2.11.0`\n\n- PyPI lists `2.11.0` as the package version covered here and requires Python `>=3.9`.\n- The current maintainer docs for extra types live under the main Pydantic docs site, not a separate package site.\n- Pydantic v2 moved these types out of the main package. If you are migrating v1 code, prefer imports from `pydantic_extra_types.*` and re-check any old field examples.\n\n## Official Sources\n\n- Docs root: `https://docs.pydantic.dev/latest/`\n- Color API: `https://docs.pydantic.dev/latest/api/pydantic_extra_types_color/`\n- Country API: `https://docs.pydantic.dev/latest/api/pydantic_extra_types_country/`\n- Coordinate API: `https://docs.pydantic.dev/latest/api/pydantic_extra_types_coordinate/`\n- Payment card API: `https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/`\n- Phone numbers API: `https://docs.pydantic.dev/2.11/api/pydantic_extra_types_phone_numbers/`\n- Timezone name API: `https://docs.pydantic.dev/latest/api/pydantic_extra_types_timezone_name/`\n- Main types docs: `https://docs.pydantic.dev/latest/api/types/`\n- PyPI: `https://pypi.org/project/pydantic-extra-types/2.11.0/`\n"
  },
  {
    "path": "content/pydantic/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pydantic 2.12.5 package guide for Python data validation, settings, and schema generation\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.12.5\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pydantic,python,validation,typing,json-schema,settings\"\n---\n\n# Pydantic Python Package Guide\n\n## What It Is\n\n`pydantic` validates Python data against type hints and turns it into typed objects. In v2, the main surfaces to reach for are:\n\n- `BaseModel` for structured request, config, and domain models\n- `TypeAdapter` for validating arbitrary types without creating a model\n- `Field(...)` for defaults and field constraints\n- `ConfigDict(...)` for model behavior such as extra-field handling, strictness, aliases, and attribute-based loading\n\n`pydantic` itself does not do network calls or authentication. If you need environment-backed application settings, use the separate `pydantic-settings` package.\n\n## Install\n\n```bash\npip install \"pydantic==2.12.5\"\n```\n\nIf you use `uv`:\n\n```bash\nuv add \"pydantic==2.12.5\"\n```\n\nIf you need `EmailStr` and related email validation helpers:\n\n```bash\npip install \"pydantic[email]==2.12.5\"\n```\n\n## Core Model Pattern\n\nUse `BaseModel` for typed inputs and outputs. Default to explicit field types and fail closed on unknown input unless you have a reason not to.\n\n```python\nfrom pydantic import BaseModel, ConfigDict, Field\n\nclass UserCreate(BaseModel):\n    model_config = ConfigDict(extra=\"forbid\", str_strip_whitespace=True)\n\n    id: int\n    email: str\n    is_admin: bool = False\n    display_name: str = Field(min_length=1, max_length=80)\n\npayload = {\n    \"id\": \"123\",\n    \"email\": \"dev@example.com\",\n    \"display_name\": \"Ada\",\n}\n\nuser = UserCreate.model_validate(payload)\n\nassert user.id == 123\nassert user.model_dump() == {\n    \"id\": 123,\n    \"email\": \"dev@example.com\",\n    \"is_admin\": False,\n    \"display_name\": \"Ada\",\n}\n```\n\nUseful model methods in v2:\n\n- `model_validate(obj)` validates Python objects like `dict`\n- `model_validate_json(raw_json)` validates JSON bytes or strings directly\n- `model_validate_strings(data)` is useful when every incoming value is a string\n- `model_dump()` returns Python data\n- `model_dump_json()` returns serialized JSON\n- `model_json_schema()` generates JSON Schema for APIs, forms, and tool definitions\n\n## JSON And String Inputs\n\nUse the right entry point for the data shape you actually have:\n\n```python\nfrom datetime import datetime\n\nfrom pydantic import BaseModel\n\nclass Event(BaseModel):\n    at: datetime\n    count: int\n\nevent = Event.model_validate_json('{\"at\":\"2032-06-01T12:00:00Z\",\"count\":3}')\n\nquery_data = {\"at\": \"2032-06-01T12:00:00Z\", \"count\": \"3\"}\nevent_from_strings = Event.model_validate_strings(query_data)\n```\n\nFor request bodies that are already JSON text, `model_validate_json()` avoids a separate `json.loads(...)` step.\n\n## Validate Arbitrary Types With `TypeAdapter`\n\nUse `TypeAdapter` when you do not want a wrapper model:\n\n```python\nfrom typing import Annotated\n\nfrom pydantic import Field, TypeAdapter\n\nUserIds = TypeAdapter(list[Annotated[int, Field(ge=1)]])\n\nids = UserIds.validate_python([\"1\", 2, 3])\nassert ids == [1, 2, 3]\n\nraw = \"[1, 2, 3]\"\nids_from_json = UserIds.validate_json(raw)\n```\n\nThis is the right tool for:\n\n- validating response fragments\n- parsing CLI or env-derived values\n- validating nested types reused across multiple models\n\nIf validation runs in a hot path, instantiate the adapter once and reuse it.\n\n## Config And Settings\n\n### Model Configuration\n\nSet model behavior with `model_config = ConfigDict(...)`:\n\n```python\nfrom pydantic import BaseModel, ConfigDict, Field\n\nclass Account(BaseModel):\n    model_config = ConfigDict(\n        extra=\"forbid\",\n        validate_assignment=True,\n        from_attributes=True,\n        validate_by_name=True,\n        validate_by_alias=True,\n    )\n\n    account_id: int = Field(alias=\"accountId\")\n    owner_name: str\n```\n\nCommon config choices:\n\n- `extra=\"forbid\"` rejects undeclared input keys\n- `validate_assignment=True` re-validates values when attributes change after model creation\n- `from_attributes=True` replaces the v1 `from_orm` pattern for loading from objects with attributes\n- `validate_by_alias=True` and `validate_by_name=True` let you accept both API aliases and Python field names\n- `strict=True` disables coercion globally if you need exact types\n\n### Environment-Backed App Settings\n\n`BaseSettings` moved out of `pydantic` in v2. Use `pydantic-settings`:\n\n```bash\npip install pydantic-settings\n```\n\n```python\nfrom pydantic import Field\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n    model_config = SettingsConfigDict(\n        env_prefix=\"APP_\",\n        env_file=\".env\",\n        extra=\"ignore\",\n    )\n\n    debug: bool = False\n    database_url: str\n    api_key: str = Field(alias=\"API_KEY\")\n\nsettings = Settings()\n```\n\nNotes:\n\n- `env_prefix` scopes environment variables such as `APP_DEBUG`\n- `env_file` lets local development load a `.env`\n- `secrets_dir` is available if you need mounted secret files\n- `pydantic` has no auth model of its own; it only validates your config and secret values\n\n## Validators\n\nUse validators when type hints and `Field(...)` constraints are not enough:\n\n```python\nfrom pydantic import BaseModel, field_validator, model_validator\n\nclass Signup(BaseModel):\n    password: str\n    confirm_password: str\n\n    @field_validator(\"password\")\n    @classmethod\n    def check_length(cls, value: str) -> str:\n        if len(value) < 12:\n            raise ValueError(\"password must be at least 12 characters\")\n        return value\n\n    @model_validator(mode=\"after\")\n    def passwords_match(self) -> \"Signup\":\n        if self.password != self.confirm_password:\n            raise ValueError(\"passwords do not match\")\n        return self\n```\n\nReach for:\n\n- `field_validator(...)` for one-field cleanup or checks\n- `model_validator(mode=\"before\")` to reshape raw input\n- `model_validator(mode=\"after\")` for cross-field checks after parsing\n\n## JSON Schema Generation\n\nUse JSON Schema output when integrating with OpenAPI generators, forms, or LLM tool schemas:\n\n```python\nschema = UserCreate.model_json_schema()\n```\n\nIf you need schema for a non-model type, generate it from `TypeAdapter(...).json_schema()`.\n\n## Common Pitfalls\n\n- V2 renamed many v1 methods. Use `model_validate`, `model_dump`, and `model_json_schema` instead of `parse_obj`, `dict`, and `json_schema`.\n- `from_orm` is gone as the primary pattern. Set `from_attributes=True` and call `model_validate(...)`.\n- `BaseSettings` is no longer in `pydantic`; install `pydantic-settings`.\n- Coercion is powerful but can hide bad input. Use `strict=True` or stricter field types when inputs must not be coerced.\n- Alias handling changed in v2. If you expect both `snake_case` and `camelCase`, configure alias behavior explicitly.\n- `model_construct()` skips validation. Use it only when the data is already trusted and validated elsewhere.\n- For partial updates, prefer `model_copy(update=...)` over rebuilding ad hoc dictionaries.\n- Catch `ValidationError` at system boundaries and return structured errors instead of raw tracebacks.\n\n## Version-Sensitive Notes For 2.12.5\n\n- `2.12.5` is the current stable release on PyPI as of `2026-03-11`.\n- The official docs root `https://docs.pydantic.dev/latest/` currently documents the v2.12 line.\n- PyPI also lists newer pre-release builds; do not assume those APIs are safe to target unless the project explicitly uses them.\n- If you are maintaining v1-era code, the migration guide documents the method renames and the `pydantic.v1` compatibility namespace.\n\n## Recommended Agent Workflow\n\n1. Install the exact version used by the project or pin `2.12.5` when creating new examples.\n2. Start with a `BaseModel` or `TypeAdapter`, not custom parsing code.\n3. Add `extra=\"forbid\"` unless the payload is intentionally open-ended.\n4. Use `model_validate_json()` for raw JSON, `model_validate()` for Python objects, and `model_validate_strings()` for all-string maps.\n5. Move settings loading into `pydantic-settings` instead of mixing env parsing into application code.\n6. Check the migration guide before copying any pre-v2 snippets from blogs, Stack Overflow, or old internal code.\n\n## Official Sources\n\n- Docs: https://docs.pydantic.dev/latest/\n- Install: https://docs.pydantic.dev/latest/install/\n- Models: https://docs.pydantic.dev/latest/concepts/models/\n- Validators: https://docs.pydantic.dev/latest/concepts/validators/\n- JSON parsing: https://docs.pydantic.dev/latest/concepts/json/\n- TypeAdapter: https://docs.pydantic.dev/latest/concepts/type_adapter/\n- Configuration: https://docs.pydantic.dev/latest/concepts/config/\n- Aliases: https://docs.pydantic.dev/latest/concepts/alias/\n- Settings: https://docs.pydantic.dev/latest/concepts/pydantic_settings/\n- Migration guide: https://docs.pydantic.dev/latest/migration/\n- Changelog: https://docs.pydantic.dev/latest/changelog/\n- PyPI: https://pypi.org/project/pydantic/\n"
  },
  {
    "path": "content/pydantic/docs/settings/python/DOC.md",
    "content": "---\nname: settings\ndescription: \"pydantic-settings 2.13.1 package guide for typed application settings, dotenv files, CLI parsing, and secret sources in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.13.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydantic-settings,python,configuration,environment,settings,secrets,cli\"\n---\n\n# pydantic-settings Python Package Guide\n\n## What It Is\n\n`pydantic-settings` adds typed application settings on top of Pydantic v2. Use it when config should come from environment variables, `.env` files, mounted secret files, CLI flags, or extra config sources while still being validated into normal Python types.\n\nReach for it when you want:\n\n- one typed settings object for app startup\n- automatic coercion from env strings to Python values\n- nested settings models\n- source priority you can customize\n- optional integrations for TOML, YAML, AWS Secrets Manager, Azure Key Vault, or Google Secret Manager\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"pydantic-settings==2.13.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pydantic-settings==2.13.1\"\npoetry add \"pydantic-settings==2.13.1\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"pydantic-settings[toml]==2.13.1\"\npython -m pip install \"pydantic-settings[yaml]==2.13.1\"\npython -m pip install \"pydantic-settings[aws-secrets-manager]==2.13.1\"\npython -m pip install \"pydantic-settings[azure-key-vault]==2.13.1\"\npython -m pip install \"pydantic-settings[gcp-secret-manager]==2.13.1\"\n```\n\n## Core Pattern\n\nUse `BaseSettings` for startup config, not for request payloads or domain models.\n\n```python\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass DatabaseSettings(BaseModel):\n    host: str = \"localhost\"\n    port: int = 5432\n    user: str\n    password: SecretStr\n\nclass Settings(BaseSettings):\n    model_config = SettingsConfigDict(\n        env_prefix=\"APP_\",\n        env_file=\".env\",\n        env_nested_delimiter=\"__\",\n        extra=\"ignore\",\n    )\n\n    debug: bool = False\n    log_level: str = \"INFO\"\n    database: DatabaseSettings\n\nsettings = Settings()\n\nprint(settings.debug)\nprint(settings.database.host)\nprint(settings.database.password.get_secret_value())\n```\n\nExample environment:\n\n```dotenv\nAPP_DEBUG=true\nAPP_DATABASE='{\"user\":\"app\",\"password\":\"secret\"}'\nAPP_DATABASE__HOST=db.internal\nAPP_DATABASE__PORT=5433\n```\n\nImportant behavior:\n\n- Complex values such as `list`, `dict`, and nested models are parsed from JSON strings by default.\n- With `env_nested_delimiter=\"__\"`, nested variables such as `APP_DATABASE__HOST` override values from the top-level JSON env var.\n- Nested settings models should be normal Pydantic models such as `BaseModel`, not `BaseSettings`.\n\n## Environment Naming, Aliases, And Prefixes\n\nBy default, `BaseSettings` looks for env vars that match the field name, optionally prefixed by `env_prefix`.\n\nIf the external env name should differ from the Python attribute name, use `validation_alias`:\n\n```python\nfrom pydantic import AliasChoices, Field\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n    model_config = SettingsConfigDict(env_prefix=\"APP_\")\n\n    api_key: str = Field(\n        validation_alias=AliasChoices(\"OPENAI_API_KEY\", \"APP_API_KEY\")\n    )\n```\n\nNotes:\n\n- `validation_alias` changes input names without changing the attribute name.\n- `AliasChoices(...)` is useful during migrations when old and new env var names must both work.\n- `env_prefix` does not apply to fields with an alias, so declare the exact env names you want in the alias.\n\n## Dotenv And Secrets Files\n\nUse `.env` loading for local development and `secrets_dir` for mounted secrets in containers:\n\n```python\nfrom pydantic import SecretStr\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n    model_config = SettingsConfigDict(\n        env_file=\".env\",\n        secrets_dir=\"/run/secrets\",\n        extra=\"ignore\",\n    )\n\n    database_url: str\n    api_token: SecretStr\n```\n\nOperational notes:\n\n- `.env` loading checks the current working directory unless you pass a specific path.\n- `extra=\"forbid\"` is the default for settings. That can make unrelated keys in a shared `.env` fail validation, so `extra=\"ignore\"` is often safer for app config.\n- Secret files are read by filename, so `/run/secrets/api_token` maps to `api_token`.\n- `secrets_dir` is lower priority than init kwargs, env vars, and dotenv values unless you customize source order.\n\n## CLI Parsing\n\n`pydantic-settings` can parse CLI arguments into the same settings model:\n\n```python\nfrom pydantic_settings import BaseSettings\n\nclass Settings(BaseSettings, cli_parse_args=True):\n    dry_run: bool = False\n    workers: int = 4\n\nsettings = Settings()\nprint(settings.model_dump())\n```\n\nExample:\n\n```bash\npython app.py --dry_run=true --workers=8\n```\n\nNotes:\n\n- CLI support is opt-in with `cli_parse_args=True`.\n- When enabled, CLI arguments are the highest-priority source by default.\n- This is useful for scripts and internal tools where you want one schema for env vars and command-line overrides.\n\n## Custom Sources And Source Priority\n\nThe default priority is:\n\n1. CLI arguments, if enabled\n2. Initialization keyword arguments\n3. Environment variables\n4. `.env` file values\n5. Secret files from `secrets_dir`\n6. Field defaults\n\nYou can change source order or add file-backed sources with `settings_customise_sources(...)`:\n\n```python\nfrom pydantic_settings import (\n    BaseSettings,\n    PydanticBaseSettingsSource,\n    PyprojectTomlConfigSettingsSource,\n)\n\nclass Settings(BaseSettings):\n    timeout_seconds: int = 30\n\n    @classmethod\n    def settings_customise_sources(\n        cls,\n        settings_cls,\n        init_settings: PydanticBaseSettingsSource,\n        env_settings: PydanticBaseSettingsSource,\n        dotenv_settings: PydanticBaseSettingsSource,\n        file_secret_settings: PydanticBaseSettingsSource,\n    ) -> tuple[PydanticBaseSettingsSource, ...]:\n        return (\n            init_settings,\n            env_settings,\n            PyprojectTomlConfigSettingsSource(settings_cls),\n            dotenv_settings,\n            file_secret_settings,\n        )\n```\n\nThe first returned source has the highest priority. Built-in helpers documented upstream include JSON, `pyproject.toml`, TOML, and YAML config sources.\n\n## External Secret Managers\n\nThe package ships optional source integrations for external secret stores. Install the matching extra and handle provider authentication separately.\n\nCommon patterns:\n\n- AWS Secrets Manager: install `pydantic-settings[aws-secrets-manager]` and authenticate with normal AWS credentials resolution.\n- Azure Key Vault: install `pydantic-settings[azure-key-vault]` and use Azure credentials such as `DefaultAzureCredential`.\n- Google Secret Manager: install `pydantic-settings[gcp-secret-manager]` and use ADC or explicit Google credentials.\n\nImportant boundary:\n\n- `pydantic-settings` validates and maps secret values; it is not an auth library.\n- Provider IAM, service accounts, and cloud SDK credentials must already be configured correctly.\n\n## Common Pitfalls\n\n- `BaseSettings` moved out of `pydantic` in v2. Import it from `pydantic_settings`, not `pydantic`.\n- The package name is `pydantic-settings`, but the import module is `pydantic_settings`.\n- Defaults are validated for `BaseSettings` by default. If you need a non-validating default, set `validate_default=False` on the field or model config.\n- Complex env values are JSON-decoded by default. If your env format is CSV or another custom string format, use `NoDecode`, `ForceDecode`, or a validator instead of assuming automatic parsing.\n- `env_prefix` does not rewrite aliased fields. If you use `validation_alias` or `alias`, define the exact input names you expect.\n- If nested env parsing splits too aggressively because your field names contain `_`, set `env_nested_max_split` explicitly.\n- Reloading is not automatic. If you intentionally want to re-read sources into an existing mutable settings object, the docs show calling `__init__()` again.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI lists `2.13.1`, which matches the version covered here.\n- The official docs live under the main Pydantic docs site, not a separate `pydantic-settings` docs domain.\n- This package is for the Pydantic v2 settings model. Older blog posts that import `BaseSettings` from `pydantic` are v1-era examples and should not be copied into new code.\n- Python `>=3.10` is required for the current package release.\n"
  },
  {
    "path": "content/pydantic-ai/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PydanticAI framework for building typed Python agents with tools, structured output, message history, and multi-provider model support\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.67.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydantic-ai,python,agents,llm,pydantic,tools,structured-output\"\n---\n\n# pydantic-ai Python Package Guide\n\nUse `pydantic-ai` as an orchestration layer for typed agent workflows in Python. It provides `Agent`, tool registration, dependency injection, structured output validation, message history, testing utilities, and provider abstractions, but you still need to choose a model backend and configure that provider's credentials.\n\n## Install\n\nInstall the main package when you want the default provider integrations:\n\n```bash\npython -m pip install \"pydantic-ai==1.67.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pydantic-ai==1.67.0\"\npoetry add \"pydantic-ai==1.67.0\"\n```\n\nIf you want a smaller install, use `pydantic-ai-slim` and add extras for the providers you actually use:\n\n```bash\npython -m pip install \"pydantic-ai-slim[openai]==1.67.0\"\npython -m pip install \"pydantic-ai-slim[anthropic]==1.67.0\"\npython -m pip install \"pydantic-ai-slim[logfire]==1.67.0\"\n```\n\nThe most common setup mistake is installing `pydantic-ai-slim` without the provider extra you need, then trying to use a model integration that is not installed.\n\n## Choose A Model And Configure Credentials\n\nThe shortest path is to use the `provider:model_name` shorthand:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\"openai:gpt-4o\")\n```\n\nFor OpenAI-backed models, set `OPENAI_API_KEY` before running the agent:\n\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\n```\n\nThen initialize the agent with instructions and run it:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    instructions=\"Be concise and return plain text.\",\n)\n\nresult = agent.run_sync(\"Write a slugify function in Python.\")\nprint(result.output)\n```\n\nIf you need a custom base URL or a preconfigured provider client, build the model explicitly:\n\n```python\nimport os\n\nfrom openai import AsyncOpenAI\nfrom pydantic_ai import Agent\nfrom pydantic_ai.models.openai import OpenAIResponsesModel\nfrom pydantic_ai.providers.openai import OpenAIProvider\n\nclient = AsyncOpenAI(\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n    base_url=\"https://my-proxy.example/v1\",\n)\n\nmodel = OpenAIResponsesModel(\n    \"gpt-4o\",\n    provider=OpenAIProvider(openai_client=client),\n)\n\nagent = Agent(\n    model,\n    instructions=\"Answer as a helpful Python assistant.\",\n)\n```\n\nEach provider has its own auth and configuration rules. `pydantic-ai` does not supply provider credentials for you.\n\n## Core Usage\n\n### Minimal agent\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    instructions=\"You are a helpful Python assistant.\",\n)\n\nresult = agent.run_sync(\"Write a slugify function.\")\nprint(result.output)\n```\n\nUse `run_sync()` for scripts and CLIs. In async applications, prefer `await agent.run(...)`.\n\n### Structured output\n\nUse `output_type` when downstream code needs validated data instead of free-form text:\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_ai import Agent\n\n\nclass City(BaseModel):\n    name: str\n    country_code: str\n\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    output_type=City,\n    instructions=\"Return a city object.\",\n)\n\nresult = agent.run_sync(\"Return London with its ISO country code.\")\nprint(result.output.name)\nprint(result.output.country_code)\n```\n\nThe output docs also cover `NativeOutput`, `ToolOutput`, `PromptedOutput`, and `TextOutput` when you need tighter control over how results are enforced.\n\n### Tools with shared dependencies\n\nUse `@agent.tool` when the tool needs a `RunContext` and typed dependencies:\n\n```python\nfrom dataclasses import dataclass\n\nfrom pydantic_ai import Agent, RunContext\n\n\n@dataclass\nclass SupportDeps:\n    customer_tier: str\n\n\nagent = Agent(\n    \"openai:gpt-4o\",\n    deps_type=SupportDeps,\n    instructions=\"Use the available tools to answer support questions.\",\n)\n\n\n@agent.tool\ndef current_tier(ctx: RunContext[SupportDeps]) -> str:\n    return ctx.deps.customer_tier\n\n\nresult = agent.run_sync(\n    \"What support level does this customer have?\",\n    deps=SupportDeps(customer_tier=\"gold\"),\n)\n\nprint(result.output)\n```\n\nUse `@agent.tool_plain` only for tools that do not need `ctx`.\n\n### Continue a conversation with message history\n\nPass `message_history` from one run into the next run when you want multi-turn behavior:\n\n```python\nfrom pydantic_ai import Agent\n\nagent = Agent(\"openai:gpt-4o\")\n\nfirst = agent.run_sync(\"My name is Sam.\")\nsecond = agent.run_sync(\n    \"What is my name?\",\n    message_history=first.all_messages(),\n)\n\nprint(second.output)\n```\n\nThe message history docs also cover serializing messages to JSON and restoring them later.\n\n## Testing Agents\n\nUse the built-in test models instead of calling live providers in unit tests:\n\n```python\nfrom pydantic_ai import Agent\nfrom pydantic_ai.models.test import TestModel\n\nagent = Agent(TestModel(), instructions=\"Return a greeting.\")\n\nresult = agent.run_sync(\"Say hello.\")\nassert result.output is not None\n```\n\nUse `FunctionModel` when you need deterministic behavior for tool execution or output validation logic.\n\n## Common Pitfalls\n\n- The PyPI package is `pydantic-ai`, but the import path is `pydantic_ai`.\n- `pydantic-ai` is not the same package as `pydantic`; installing one does not replace the other.\n- If you install `pydantic-ai-slim`, add the provider extras you need or provider integrations can fail at runtime.\n- Older examples may use `result_type` or `result.data`; current docs use `output_type` and `result.output`.\n- `message_history` expects compatible PydanticAI message objects, not arbitrary chat dictionaries from another SDK.\n- Tool schemas come from type hints and docstrings; vague `dict` or `Any` types reduce tool-calling quality.\n- `run_sync()` blocks the current thread. In FastAPI or other async runtimes, use `await agent.run(...)` instead.\n- Provider credentials are separate from the framework itself. Installing the package does not configure `OPENAI_API_KEY` or any other provider secret.\n\n## Version Notes For 1.67.0\n\n- This guide targets `pydantic-ai` `1.67.0`.\n- The official version policy describes the `1.x` line as stable and avoids intentional breaking changes in minor releases.\n- Some ecosystem surfaces are documented separately and may have different stability notes than the core `Agent` APIs.\n- If you are migrating from older examples, prefer the current naming and result-handling patterns: `Agent`, `instructions`, `output_type`, `RunContext`, and `result.output`.\n\n## Official Sources\n\n- Docs root: `https://ai.pydantic.dev/`\n- Installation: `https://ai.pydantic.dev/install/`\n- Agent API: `https://ai.pydantic.dev/agent/`\n- Models overview: `https://ai.pydantic.dev/models/overview/`\n- OpenAI provider: `https://ai.pydantic.dev/models/openai/`\n- Tools: `https://ai.pydantic.dev/tools/`\n- Dependencies: `https://ai.pydantic.dev/dependencies/`\n- Message history: `https://ai.pydantic.dev/message-history/`\n- Output: `https://ai.pydantic.dev/output/`\n- MCP: `https://ai.pydantic.dev/mcp/`\n- Testing: `https://ai.pydantic.dev/testing/`\n- Version policy: `https://ai.pydantic.dev/version-policy/`\n- PyPI: `https://pypi.org/project/pydantic-ai/`\n"
  },
  {
    "path": "content/pydantic-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pydantic-core package guide for low-level Python validation and serialization with core schemas\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.42.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydantic-core,python,validation,serialization,json,schema\"\n---\n\n# pydantic-core Python Package Guide\n\n## What It Is\n\n`pydantic-core` is the low-level validation and serialization engine used by `pydantic` v2. Use it directly when you need to:\n\n- compile and reuse validators or serializers in a hot path\n- validate raw Python objects, JSON bytes, or string-heavy inputs against a core schema\n- work with the engine layer instead of `BaseModel` or `TypeAdapter`\n\nFor most application code, prefer `pydantic`. The maintainer README explicitly notes that most users should not need to use `pydantic-core` directly.\n\n## Installation\n\n`pydantic-core 2.42.0` requires Python `>=3.9`.\n\nInstall the package from PyPI:\n\n```bash\npip install \"pydantic-core==2.42.0\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"pydantic-core==2.42.0\"\n```\n\nThe PyPI package name uses a hyphen, but the Python import name uses an underscore:\n\n```python\nimport pydantic_core\nfrom pydantic_core import SchemaSerializer, SchemaValidator, ValidationError, core_schema\n```\n\n## Initialization And Environment\n\nThere is no auth flow, network client, or package-specific required environment variable.\n\nInitialization means compiling a schema into one of these objects:\n\n- `SchemaValidator(schema)` for validation\n- `SchemaSerializer(schema)` for serialization\n\nIn normal application code, create these once at import time or app startup and reuse them.\n\n## Build And Reuse A Validator\n\nThe most direct workflow is:\n\n1. define a core schema with helpers from `pydantic_core.core_schema`\n2. compile it into a `SchemaValidator`\n3. reuse that validator for each input\n\n```python\nfrom pydantic_core import SchemaValidator, core_schema\n\nuser_schema = core_schema.typed_dict_schema(\n    {\n        \"id\": core_schema.typed_dict_field(core_schema.int_schema(ge=1)),\n        \"email\": core_schema.typed_dict_field(\n            core_schema.str_schema(min_length=3, strip_whitespace=True)\n        ),\n        \"is_admin\": core_schema.typed_dict_field(\n            core_schema.bool_schema(),\n            required=False,\n        ),\n    },\n    extra_behavior=\"forbid\",\n)\n\nvalidator = SchemaValidator(user_schema)\n\nuser = validator.validate_python(\n    {\n        \"id\": \"123\",\n        \"email\": \"  dev@example.com  \",\n    }\n)\n\nassert user == {\n    \"id\": 123,\n    \"email\": \"dev@example.com\",\n}\n```\n\nUse the `core_schema` helpers unless you specifically need to build raw schema dictionaries by hand. They are easier to read and less error-prone.\n\n## Choose The Right Validation Entry Point\n\n`SchemaValidator` has separate methods for different input shapes.\n\n### `validate_python(...)`\n\nUse this when you already have Python objects such as `dict`, `list`, or application objects.\n\n```python\nuser = validator.validate_python(\n    {\n        \"id\": \"123\",\n        \"email\": \"dev@example.com\",\n        \"is_admin\": False,\n    }\n)\n```\n\n### `validate_json(...)`\n\nUse this for raw request bodies or cached JSON bytes. The official API docs note that this avoids constructing intermediate Python objects and can be significantly faster than `json.loads(...)` followed by `validate_python(...)`.\n\n```python\nuser = validator.validate_json(\n    b'{\"id\": 123, \"email\": \"dev@example.com\", \"is_admin\": false}'\n)\n```\n\n### `validate_strings(...)`\n\nUse this for query params, form posts, CLI arguments, or environment-derived mappings where every value starts as text.\n\n```python\nfrom pydantic_core import SchemaValidator, core_schema\n\nevent_schema = core_schema.typed_dict_schema(\n    {\n        \"at\": core_schema.typed_dict_field(core_schema.datetime_schema()),\n        \"count\": core_schema.typed_dict_field(core_schema.int_schema(ge=1)),\n    },\n    extra_behavior=\"forbid\",\n)\n\nevent_validator = SchemaValidator(event_schema)\n\nevent = event_validator.validate_strings(\n    {\n        \"at\": \"2032-06-01T12:00:00Z\",\n        \"count\": \"3\",\n    }\n)\n```\n\nThis produces Python values such as `datetime` and `int`, not just cleaned strings.\n\n## Parse JSON Without A Schema\n\nIf you only need fast JSON deserialization, use `from_json(...)`.\n\n```python\nfrom pydantic_core import from_json\n\npayload = from_json(b'{\"ids\": [1, 2, 3], \"name\": \"demo\"}')\n\nassert payload == {\n    \"ids\": [1, 2, 3],\n    \"name\": \"demo\",\n}\n```\n\n`from_json(...)` parses JSON into Python objects. It does not validate that data against a schema. If you need both parsing and validation, call `validate_json(...)` on a `SchemaValidator` instead.\n\n## Serialize Data\n\nUse `SchemaSerializer` when you want serialization behavior tied to a compiled schema.\n\n```python\nfrom pydantic_core import SchemaSerializer\n\nserializer = SchemaSerializer(user_schema)\n\npython_value = serializer.to_python(\n    {\n        \"id\": 123,\n        \"email\": \"dev@example.com\",\n        \"is_admin\": False,\n    }\n)\n\njson_bytes = serializer.to_json(\n    {\n        \"id\": 123,\n        \"email\": \"dev@example.com\",\n        \"is_admin\": False,\n    }\n)\n\nprint(json_bytes.decode(\"utf-8\"))\n```\n\nFor standalone helpers, use `to_json(...)` and `to_jsonable_python(...)`:\n\n```python\nfrom datetime import datetime, timezone\n\nfrom pydantic_core import to_json, to_jsonable_python\n\njson_bytes = to_json({\"id\": 123, \"email\": \"dev@example.com\"})\n\njson_ready = to_jsonable_python(\n    {\"created_at\": datetime(2032, 6, 1, 12, 0, tzinfo=timezone.utc)}\n)\n\nassert json_ready == {\"created_at\": \"2032-06-01T12:00:00Z\"}\n```\n\n`SchemaSerializer.to_json(...)` and `to_json(...)` return `bytes`, not `str`.\n\n## Handle Validation Errors\n\nValidation failures raise `ValidationError`.\n\n```python\nfrom pydantic_core import ValidationError\n\ntry:\n    validator.validate_python(\n        {\n            \"id\": 0,\n            \"email\": \"x\",\n            \"role\": \"admin\",\n        }\n    )\nexcept ValidationError as exc:\n    for error in exc.errors():\n        print(error[\"loc\"], error[\"type\"], error[\"msg\"])\n```\n\nUse these methods depending on how you want to report failures:\n\n- `exc.errors()` for structured Python data\n- `exc.json()` for a JSON string\n- `str(exc)` for a readable multi-line message\n\n## When To Reach For `pydantic` Instead\n\nReach for `pydantic` instead of `pydantic-core` when you want:\n\n- `BaseModel` classes for request and domain models\n- `TypeAdapter` for high-level validation of arbitrary type hints\n- JSON Schema generation\n- settings management through `pydantic-settings`\n- a more stable and ergonomic public API for normal application code\n\nUse `pydantic-core` directly when low-level schema control or validator reuse is the actual goal.\n\n## Common Pitfalls\n\n- Import `pydantic_core`, not `pydantic-core`.\n- Build validators and serializers once. Recompiling schemas in a request loop wastes the main benefit of the package.\n- Use `validate_json(...)` for raw JSON input and `validate_strings(...)` for string-heavy mappings. They solve different problems.\n- `from_json(...)` only parses. It does not enforce a schema.\n- `to_json(...)` and `SchemaSerializer.to_json(...)` return `bytes`; call `.decode(\"utf-8\")` if you need a string.\n- If you mainly want typed models or settings, using `pydantic-core` directly usually adds complexity with little payoff.\n\n## Version-Sensitive Notes\n\n- This guide targets `pydantic-core 2.42.0`.\n- PyPI uses the project name `pydantic-core`, while Python code imports `pydantic_core`.\n- PyPI metadata for this package line requires Python `>=3.9`.\n\n## Official Sources\n\n- Repository and maintainer README: https://github.com/pydantic/pydantic-core\n- API docs root: https://docs.pydantic.dev/latest/api/pydantic_core/\n- PyPI project page: https://pypi.org/project/pydantic-core/\n"
  },
  {
    "path": "content/pydub/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pydub package guide for Python audio loading, editing, effects, export, and ffmpeg-backed transcoding\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.25.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pydub,audio,ffmpeg,media,python\"\n---\n\n# pydub Python Package Guide\n\n## Golden Rule\n\nUse `pydub` as a high-level wrapper around `ffmpeg` or `libav`, not as a standalone codec stack. `AudioSegment` handles slicing, mixing, fades, silence utilities, and export, but compressed formats such as MP3, AAC, OGG, MP4, and FLV still depend on external binaries being installed and discoverable.\n\n## Install\n\nInstall the Python package first:\n\n```bash\npython -m pip install \"pydub==0.25.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pydub==0.25.1\"\npoetry add \"pydub==0.25.1\"\n```\n\nInstall an audio backend as well. For most real work, that means `ffmpeg` plus `ffprobe` on `PATH`:\n\n```bash\nbrew install ffmpeg\nsudo apt-get install ffmpeg\nchoco install ffmpeg\n```\n\nOptional helpers:\n\n- `simpleaudio` for the cleanest local playback path\n- `pyaudio` as a fallback playback backend\n- `scipy` for `pydub.effects.speedup(...)`\n\n## Initialize And Verify Setup\n\nCheck the system binaries before debugging Python code:\n\n```bash\nffmpeg -version\nffprobe -version\n```\n\nMinimal import:\n\n```python\nfrom pydub import AudioSegment\n```\n\nIf `ffmpeg` is installed outside `PATH`, point `pydub` at it explicitly:\n\n```python\nfrom pydub import AudioSegment\n\nAudioSegment.converter = \"/opt/homebrew/bin/ffmpeg\"\nAudioSegment.ffmpeg = AudioSegment.converter\n```\n\n`pydub` resolves the probing binary separately, so keep `ffprobe` or `avprobe` available on `PATH` as well.\n\n## Core Usage\n\n### Load audio\n\n`AudioSegment` is immutable. Each operation returns a new segment.\n\n```python\nfrom pydub import AudioSegment\n\nsong = AudioSegment.from_mp3(\"input.mp3\")\nwav = AudioSegment.from_wav(\"input.wav\")\nclip = AudioSegment.from_file(\"input.m4a\", format=\"m4a\")\n```\n\nIf the file format is ambiguous or the extension is unreliable, pass `format=...` explicitly.\n\n### Slice and transform\n\nAll time values are milliseconds:\n\n```python\nfrom pydub import AudioSegment\n\nsong = AudioSegment.from_mp3(\"podcast.mp3\")\n\nintro = song[:10_000]\nmiddle = song[30_000:45_000]\nlouder = middle + 6\nquieter = middle - 3\nfade = louder.fade_in(2_000).fade_out(3_000)\nmono = fade.set_channels(1)\nresampled = mono.set_frame_rate(16_000)\n```\n\n### Concatenate, crossfade, and overlay\n\n```python\nfrom pydub import AudioSegment\n\nvoice = AudioSegment.from_wav(\"voice.wav\")\nmusic = AudioSegment.from_mp3(\"music.mp3\") - 12\n\nepisode = voice.append(voice, crossfade=1_500)\nmix = music.overlay(voice, position=5_000)\n```\n\nUse `append(..., crossfade=...)` for linear sequencing and `overlay(...)` for mixing simultaneous audio.\n\n### Export\n\n```python\nfrom pydub import AudioSegment\n\nsegment = AudioSegment.from_file(\"input.wav\")\n\nsegment.export(\n    \"output.mp3\",\n    format=\"mp3\",\n    bitrate=\"192k\",\n    tags={\"artist\": \"Example\", \"album\": \"Demo\"},\n)\n```\n\nYou can pass raw encoder flags through `parameters`, and `pydub` does not validate them:\n\n```python\nsegment.export(\n    \"output.mp3\",\n    format=\"mp3\",\n    parameters=[\"-q:a\", \"0\"],\n)\n```\n\n### Silence-driven chunking\n\nUse the silence helpers when you need coarse speech segmentation:\n\n```python\nfrom pydub import AudioSegment\nfrom pydub.silence import split_on_silence\n\naudio = AudioSegment.from_file(\"meeting.wav\")\n\nchunks = split_on_silence(\n    audio,\n    min_silence_len=700,\n    silence_thresh=audio.dBFS - 16,\n    keep_silence=250,\n)\n```\n\nTune `min_silence_len` and `silence_thresh` against the actual recording instead of copying fixed values from old examples.\n\n### Playback\n\n```python\nfrom pydub import AudioSegment\nfrom pydub.playback import play\n\nsegment = AudioSegment.from_file(\"preview.mp3\")\nplay(segment)\n```\n\nIn `0.25.1`, playback tries `simpleaudio`, then `pyaudio`, then `ffplay`. Treat playback as a local convenience, not a deployment primitive.\n\n## Configuration Notes\n\n`pydub` has no auth model and no service configuration. The main runtime configuration is local:\n\n- `ffmpeg` and `ffprobe` binary availability\n- file formats and codecs supported by the installed backend\n- sample rate, channels, and bit depth expected by downstream systems\n- export flags passed through `parameters`\n\nWhen agents generate audio for speech or ML pipelines, normalize explicitly instead of assuming the source file already matches the target format:\n\n```python\nfrom pydub import AudioSegment\n\nsegment = AudioSegment.from_file(\"input.mp3\")\nnormalized = (\n    segment.set_channels(1)\n    .set_frame_rate(16_000)\n    .set_sample_width(2)\n)\n\nnormalized.export(\"speech.wav\", format=\"wav\")\n```\n\n## Common Pitfalls\n\n- Missing `ffmpeg` or `ffprobe` is the most common failure mode for non-WAV formats. Decode or export errors often trace back to missing binaries, not bad Python code.\n- Time indexes are milliseconds, not seconds. `song[:10]` means ten milliseconds, not ten seconds.\n- `AudioSegment` objects are immutable. Methods such as `fade_in`, `set_frame_rate`, and `set_channels` return new segments.\n- `export(..., parameters=[...])` forwards flags directly to `ffmpeg`. Invalid flags fail at runtime.\n- `play(...)` depends on optional local playback backends and may behave differently across machines.\n- Silence splitting is data-dependent. Reuse the structure, not the exact thresholds, from prior examples.\n- For large transcodes or batch jobs, remember that `pydub` is a Python wrapper around command-line tooling. If you need streaming-scale media pipelines, direct `ffmpeg` orchestration may be a better fit.\n\n## Version-Sensitive Notes\n\n- `0.25.1` is still the current released version on both PyPI and the GitHub releases page as of 2026-03-12.\n- The latest release was published on 2021-03-10, so many third-party posts are effectively documenting this same code line. Prefer the maintainer README and API docs over blogs when method signatures look inconsistent.\n- The official API docs still describe `speedup(...)` as requiring `scipy`. Keep that dependency explicit if you use that effect in generated code.\n- This release line is old enough that you should validate newer Python runtimes in CI before assuming compatibility from unsourced blog examples.\n\n## Official Source URLs\n\n- `https://pypi.org/project/pydub/`\n- `https://github.com/jiaaro/pydub`\n- `https://github.com/jiaaro/pydub/blob/master/README.markdown`\n- `https://github.com/jiaaro/pydub/blob/master/API.markdown`\n- `https://github.com/jiaaro/pydub/blob/master/pydub/audio_segment.py`\n- `https://github.com/jiaaro/pydub/blob/master/pydub/utils.py`\n- `https://github.com/jiaaro/pydub/blob/master/pydub/playback.py`\n- `https://github.com/jiaaro/pydub/releases/tag/v0.25.1`\n"
  },
  {
    "path": "content/pyflakes/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pyflakes static analysis guide for checking Python code for undefined names, unused imports, and similar correctness issues\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"pyflakes,python,lint,static-analysis,cli\"\n---\n\n# Pyflakes Python Package Guide\n\n## Golden Rule\n\nUse `pyflakes` for fast correctness checks, not style enforcement. Upstream documents it as a passive checker that parses source without importing modules, so it is safe to run on files with import-time side effects. If you need formatting rules, PEP 8 checks, or project-level configuration, use `flake8` instead of expecting standalone `pyflakes` to do that.\n\n## Install\n\n`pyflakes 3.4.0` requires Python 3.9 or newer.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pyflakes==3.4.0\"\n```\n\nIf you manage dependencies with another tool:\n\n```bash\nuv add \"pyflakes==3.4.0\"\npoetry add \"pyflakes==3.4.0\"\n```\n\nInstall and run it with the same interpreter version as the code you are checking:\n\n```bash\npython3.12 -m pip install \"pyflakes==3.4.0\"\npython3.12 -m pyflakes src tests\n```\n\n## Environment Variables\n\n`pyflakes` does not require authentication, API keys, or service configuration.\n\nOptional environment variables exposed by the checker:\n\n```bash\nPYFLAKES_BUILTINS=_,ngettext\nPYFLAKES_DOCTEST=1\n```\n\n- `PYFLAKES_BUILTINS` adds comma-separated names to the builtins set, which is useful for framework-injected globals.\n- `PYFLAKES_DOCTEST` enables doctest checking. Doctest parsing is disabled by default.\n\n## Command-Line Usage\n\nThe simplest way to run `pyflakes` is with `python -m pyflakes`, which keeps the tool tied to a specific Python interpreter.\n\n### Check one file\n\n```bash\npython -m pyflakes app.py\n```\n\n### Check multiple paths\n\n```bash\npython -m pyflakes src tests scripts/manage.py\n```\n\nWhen you pass directories, `pyflakes` recurses through them and checks Python files it finds. It also recognizes extensionless Python scripts by their shebang, so executable scripts can still be linted.\n\n### Check source from standard input\n\n```bash\ncat app.py | python -m pyflakes\n```\n\n### Print the installed version\n\n```bash\npython -m pyflakes --version\n```\n\nThe CLI exits with status `0` when no warnings are emitted and `1` when one or more warnings are found, which makes it easy to use in CI.\n\n## Common Workflows\n\n### Add a quick CI gate\n\n```bash\npython -m pyflakes src tests\n```\n\nMinimal GitHub Actions step:\n\n```yaml\n- name: Install pyflakes\n  run: python -m pip install \"pyflakes==3.4.0\"\n\n- name: Run pyflakes\n  run: python -m pyflakes src tests\n```\n\n### Treat framework globals as known names\n\nIf your project relies on names injected at runtime, declare them with `PYFLAKES_BUILTINS` before running the checker:\n\n```bash\nexport PYFLAKES_BUILTINS=_,lazy_gettext\npython -m pyflakes src\n```\n\n### Check doctest blocks\n\n```bash\nexport PYFLAKES_DOCTEST=1\npython -m pyflakes docs examples\n```\n\n## Python API\n\nThe supported public API is in `pyflakes.api`.\n\n### Check an in-memory source string\n\n```python\nfrom pyflakes.api import check\n\nsource = \"\"\"\nimport os\n\ndef greet(name):\n    return message\n\"\"\"\n\nwarnings = check(source, \"example.py\")\nif warnings:\n    raise SystemExit(1)\n```\n\n`check()` parses the source, reports warnings through the default reporter when you do not provide one, and returns the number of warnings emitted.\n\n### Check a file from your own tooling\n\n```python\nfrom pyflakes.api import checkPath\n\nwarnings = checkPath(\"app.py\")\nif warnings:\n    raise SystemExit(1)\n```\n\n## Common Pitfalls\n\n- `pyflakes` intentionally does not do style checks. It will not enforce formatting, import sorting, or line length.\n- The standalone CLI is intentionally minimal. In current upstream code, it exposes `--version` and positional paths or stdin; if you need per-project configuration and more switches, upstream points you to `flake8`.\n- Run `pyflakes` with a Python version that can parse your code. Syntax support tracks Python releases, and `3.4.0` adds Python 3.14 support.\n- Doctest checking is off unless `PYFLAKES_DOCTEST` is set.\n- If your project relies on globals that are created outside normal Python name binding, configure them with `PYFLAKES_BUILTINS` or you will get `undefined name` warnings.\n\n## Version Notes For 3.4.0\n\nThe `3.4.0` release adds Python 3.14 support, adds a new \"t-string is missing placeholders\" error, and includes fixes around deferred annotations and `from __future__ import annotations`.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/pyflakes/3.4.0/\n- Maintainer repository: https://github.com/PyCQA/pyflakes\n- Command-line and API implementation: https://github.com/PyCQA/pyflakes/blob/main/pyflakes/api.py\n- Checker implementation: https://github.com/PyCQA/pyflakes/blob/main/pyflakes/checker.py\n- Changelog: https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst\n"
  },
  {
    "path": "content/pygal/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pygal Python package guide for generating SVG charts, styling them, and exporting them for web or file output\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pygal,python,charts,svg,plotting,visualization\"\n---\n\n# pygal Python Package Guide\n\n## Golden Rule\n\nUse `pygal` when you want SVG-first chart generation from Python. Build a chart object, add one or more series, then render to SVG, a file, or PNG. Do not assume maps are bundled in core `pygal`; map charts live in separate plugin packages.\n\nAs of March 12, 2026, PyPI lists `pygal 3.1.0`, but the upstream docs site still labels many pages as `3.0.5`. The official changelog says `3.1.0` mainly fixes docs and adds `reverse_direction` for `Gauge`, so most stable docs examples still apply to `3.1.0`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pygal==3.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pygal==3.1.0\"\npoetry add \"pygal==3.1.0\"\n```\n\nOptional dependencies matter for output quality and convenience:\n\n- PNG export needs `cairosvg` for `render_to_png()`\n- `lxml` can improve rendering behavior and enables some helpers such as `render_in_browser()`\n- The docs note that `tinycss` and `cssselect` can help when rendered images appear black\n\nOne practical install for SVG plus PNG export is:\n\n```bash\npython -m pip install \"pygal==3.1.0\" cairosvg lxml tinycss cssselect\n```\n\n## Initialize And Render A Basic Chart\n\nThe core workflow is always:\n\n1. Create a chart instance such as `Bar`, `Line`, or `Pie`\n2. Set chart-level options like `title` or `x_labels`\n3. Add one or more series with `add()`\n4. Render to bytes, a file, a browser response, or PNG\n\nMinimal example:\n\n```python\nimport pygal\n\nchart = pygal.Bar()\nchart.title = \"Monthly signups\"\nchart.x_labels = [\"Jan\", \"Feb\", \"Mar\", \"Apr\"]\nchart.add(\"Web\", [12, 18, 21, 30])\nchart.add(\"Mobile\", [8, 11, 15, 19])\n\nchart.render_to_file(\"signups.svg\")\n```\n\nIf you need the SVG in memory:\n\n```python\nsvg_bytes = chart.render()\nsvg_text = chart.render(is_unicode=True)\ndata_uri = chart.render_data_uri()\n```\n\n`render()` returns bytes by default. Use `is_unicode=True` if your framework or template code expects a string.\n\n## Core Usage Patterns\n\n### Reuse configuration across charts\n\nUse `pygal.Config` when several charts should share the same settings:\n\n```python\nimport pygal\nfrom pygal import Config\n\nconfig = Config()\nconfig.show_legend = True\nconfig.explicit_size = True\nconfig.width = 900\nconfig.height = 400\nconfig.x_label_rotation = 20\n\nsales = pygal.Line(config)\nsales.title = \"Quarterly revenue\"\nsales.x_labels = [\"Q1\", \"Q2\", \"Q3\", \"Q4\"]\nsales.add(\"2025\", [120, 150, 170, 210])\nsales.add(\"2026\", [140, 165, 190, 240])\nsales.render_to_file(\"revenue.svg\")\n```\n\nYou can also pass config values directly to the chart constructor:\n\n```python\nchart = pygal.Line(show_legend=False, explicit_size=True, width=700, height=300)\n```\n\n### Use styles instead of hand-editing SVG\n\nBuilt-in and custom styles are the intended customization path:\n\n```python\nimport pygal\nfrom pygal.style import Style\n\ncustom_style = Style(\n    background=\"transparent\",\n    plot_background=\"transparent\",\n    foreground=\"#2d3142\",\n    foreground_subtle=\"#7d8597\",\n    colors=(\"#ef8354\", \"#4f5d75\", \"#2d3142\"),\n)\n\nchart = pygal.StackedBar(style=custom_style)\nchart.title = \"Tickets by team\"\nchart.x_labels = [\"Mon\", \"Tue\", \"Wed\"]\nchart.add(\"Support\", [18, 21, 17])\nchart.add(\"Success\", [9, 11, 8])\nchart.render_to_file(\"tickets.svg\")\n```\n\nIf you already know a built-in style fits, use imports like `DarkStyle`, `LightStyle`, `CleanStyle`, or `BlueStyle`.\n\n### Add metadata to individual values\n\n`pygal` accepts dictionaries instead of raw values when you need labels, links, colors, or point-specific formatting:\n\n```python\nimport pygal\n\nchart = pygal.Bar(print_values=True)\nchart.add(\n    \"Errors\",\n    [\n        {\"value\": 2, \"label\": \"API timeout\", \"color\": \"#d90429\"},\n        {\"value\": 5, \"label\": \"Validation\", \"xlink\": {\"href\": \"https://example.com/runbook\"}},\n        {\"value\": 1, \"style\": \"fill: #2b2d42; stroke: #000; stroke-width: 2\"},\n    ],\n)\n\nchart.render_to_file(\"errors.svg\")\n```\n\nUse this when an agent needs tooltips, point-level links, or exceptions highlighted without splitting the series.\n\n### Export PNG when SVG is not enough\n\n```python\nimport pygal\n\nchart = pygal.Line()\nchart.add(\"CPU\", [20, 35, 42, 33])\nchart.render_to_png(\"cpu.png\")\n```\n\nThis requires `cairosvg`. If PNG output is black or malformed, the docs recommend installing `lxml`, `tinycss`, and `cssselect`.\n\n## Web And Framework Output\n\n`pygal` is SVG-first, so web integration is usually simple.\n\n### Flask\n\n```python\nfrom flask import Flask\nimport pygal\n\napp = Flask(__name__)\n\n@app.get(\"/traffic.svg\")\ndef traffic_chart():\n    chart = pygal.Line()\n    chart.add(\"Visits\", [100, 120, 180, 160])\n    return chart.render_response()\n```\n\n### Django\n\n```python\nimport pygal\n\ndef traffic_chart(request):\n    chart = pygal.Line()\n    chart.add(\"Visits\", [100, 120, 180, 160])\n    return chart.render_django_response()\n```\n\n### Inline HTML\n\nIf you embed the raw SVG directly into HTML, disable the XML declaration and include the tooltip JavaScript yourself:\n\n```python\nsvg = chart.render(is_unicode=True, disable_xml_declaration=True)\n```\n\nThe docs also expose a configurable `js` setting for external tooltip assets. If tooltips are not appearing, check whether the generated SVG still references the expected JS and whether your page permits loading it.\n\n## Maps And Plugins\n\nMap charts are not shipped inside the core package. Install the plugin you need, then use the `pygal.maps.*` namespace:\n\n```bash\npython -m pip install pygal_maps_world\n```\n\n```python\nimport pygal.maps.world\n\nworldmap = pygal.maps.world.World()\nworldmap.title = \"Requests by country\"\nworldmap.add(\"Traffic\", {\"us\": 1200, \"fr\": 320, \"de\": 280})\nworldmap.render_to_file(\"traffic-world.svg\")\n```\n\nThe official docs list separate packages such as `pygal_maps_world`, `pygal_maps_fr`, and `pygal_maps_ch`.\n\n## Configuration Notes\n\n- There is no authentication model. The main configuration surface is chart options, style, output format, and optional plugin or rendering dependencies.\n- `Config` objects are reusable and are the cleanest way to keep a consistent chart style across a codebase.\n- Some options can be supplied at chart creation time, on the chart instance, or during `render(...)`.\n- Tooltips depend on JavaScript. Static SVG files still render without it, but interactive hover behavior will be missing.\n- `explicit_size=True` is useful when embedding SVGs into layouts that need fixed `width` and `height` instead of just a `viewBox`.\n\n## Common Pitfalls\n\n- `render()` returns bytes, not text. Use `is_unicode=True` if you need a string.\n- The docs site version banner is stale. Validate feature additions against the changelog when copying examples.\n- Maps require separate packages; `pip install pygal` alone is not enough for `pygal.maps.world`, `pygal.maps.fr`, or `pygal.maps.ch`.\n- Some SVG renderers do not handle pygal’s CSS styling well and can show black output. The upstream docs call out `lxml`, `tinycss`, and `cssselect` as fixes to try.\n- PNG export is optional. If `render_to_png()` fails, check for missing `cairosvg` and related rendering dependencies first.\n- Interactive tooltips need the pygal JavaScript asset. Inline SVG without that JS still draws the chart but loses hover behavior.\n- The docs site still contains old examples using `human_readable=True`; since `2.2.0`, the changelog says to use `pygal.formatters.human_readable` via `value_formatter` instead.\n\n## Version-Sensitive Notes For 3.1.0\n\n- PyPI release `3.1.0` was published on December 9, 2025.\n- PyPI requires Python `>=3.8`.\n- The official changelog says `3.1.0` adds the `reverse_direction` option for `Gauge` and otherwise contains lint and docs fixes.\n- The public docs site still labels many pages as `3.0.5`, so use the changelog to sanity-check newer features rather than assuming the page banner matches the installed version.\n"
  },
  {
    "path": "content/pygithub/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyGithub package guide for Python with token auth, GitHub App auth, pagination, and version-aware API usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pygithub,github,api,auth,pagination,github-apps\"\n---\n\n# PyGithub 2.6.0 Python Package Guide\n\n## What It Is\n\n`PyGithub` is the official-ish Python wrapper around the GitHub REST API from the PyGithub project. In code, you import from `github`, create a `Github(...)` client, and work with lazy objects such as users, repositories, issues, pull requests, and installations.\n\nUse it when you need:\n\n- authenticated GitHub API access from Python\n- a higher-level object model instead of hand-writing REST requests\n- GitHub App installation-token flows\n- pagination helpers for large result sets\n\nPackage identity:\n\n- Ecosystem: `pypi`\n- Package: `PyGithub`\n- Import root: `github`\n- Version covered: `2.6.0`\n- Docs root: `https://pygithub.readthedocs.io/en/stable/`\n- Registry: `https://pypi.org/project/PyGithub/`\n- Repository: `https://github.com/PyGithub/PyGithub`\n\nVersion-sensitive note:\n\n- This guide is pinned to `2.6.0`, the version used here for this session.\n- As of 2026-03-11, PyPI shows `2.8.1` as the latest release.\n- The `stable/` docs root moves with the latest stable series, so treat it as current upstream guidance and keep your project lockfile as the final authority when behavior differs.\n\n## Install\n\n`2.6.0` requires Python `>=3.8`.\n\n```bash\npython -m pip install PyGithub==2.6.0\n```\n\nIf you are reproducing existing project behavior, pin the version explicitly. A lot of online PyGithub snippets still target older 1.x APIs.\n\n## Authentication And Setup\n\nPyGithub 2.x expects an auth object, not a raw token string passed positionally.\n\n### Personal access token\n\n```python\nimport os\n\nfrom github import Auth, Github\n\nauth = Auth.Token(os.environ[\"GITHUB_TOKEN\"])\n\nwith Github(auth=auth) as gh:\n    me = gh.get_user()\n    print(me.login)\n```\n\nNotes:\n\n- PyGithub does not auto-read `GITHUB_TOKEN` for you. Read environment variables in your app and pass the value explicitly.\n- Fine-grained PATs and GitHub App tokens must include the repository and action permissions your code needs.\n- Prefer the context-manager form or call `gh.close()` when you finish with the client.\n\n### GitHub App auth\n\nUse `GithubIntegration` to exchange app credentials for an installation token:\n\n```python\nimport os\n\nfrom github import Auth, GithubIntegration\n\nauth = Auth.AppAuth(\n    os.environ[\"GITHUB_APP_ID\"],\n    os.environ[\"GITHUB_PRIVATE_KEY\"],\n)\nintegration = GithubIntegration(auth=auth)\n\ninstallation = integration.get_repo_installation(\"OWNER\", \"REPO\")\ninstallation_auth = auth.get_installation_auth(installation.id)\n```\n\nYou can then pass `installation_auth` into `Github(auth=installation_auth)` for normal repository operations.\n\n### GitHub Enterprise Server\n\nPoint the client at the API root, not the web UI root:\n\n```python\nfrom github import Auth, Github\n\ngh = Github(\n    base_url=\"https://github.example.com/api/v3\",\n    auth=Auth.Token(\"TOKEN\"),\n)\n```\n\n## Core Usage\n\n### Connect and fetch a repository\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\")) as gh:\n    repo = gh.get_repo(\"octocat/Hello-World\")\n    print(repo.full_name)\n    print(repo.default_branch)\n```\n\n`Github.get_repo(\"owner/name\")` is the normal entry point for repository work.\n\n### Read open issues lazily\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\"), per_page=50) as gh:\n    repo = gh.get_repo(\"OWNER/REPO\")\n    issues = repo.get_issues(state=\"open\")\n\n    for issue in issues[:10]:\n        print(issue.number, issue.title)\n```\n\nPyGithub collections are lazy `PaginatedList` objects. Slicing or iterating triggers API calls as needed.\n\n### Create an issue\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\")) as gh:\n    repo = gh.get_repo(\"OWNER/REPO\")\n    issue = repo.create_issue(\n        title=\"Automated report\",\n        body=\"Generated by a scheduled job.\",\n    )\n    print(issue.html_url)\n```\n\nThis requires a token with issue-write permission on the target repository.\n\n### Check rate limits\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\")) as gh:\n    core_limit, core_remaining = gh.rate_limiting\n    print(core_remaining, \"of\", core_limit)\n\n    rate_limit = gh.get_rate_limit()\n    print(rate_limit.core.remaining)\n```\n\nUnauthenticated clients work for some public data, but the rate limit is much lower. Prefer authenticated access in agent workflows.\n\n## Pagination, Requests, And Tuning\n\n### Fetch bounded pages\n\nUse `get_page()` when you need explicit page-by-page control:\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\")) as gh:\n    repo = gh.get_repo(\"OWNER/REPO\")\n    pulls = repo.get_pulls(state=\"open\")\n\n    first_page = pulls.get_page(0)\n    for pr in first_page:\n        print(pr.number, pr.title)\n```\n\nThis is safer than forcing a whole collection into memory when a repository is large.\n\n### Make a raw REST request\n\nIf PyGithub does not expose the endpoint you need cleanly, use the requester:\n\n```python\nfrom github import Auth, Github\n\nwith Github(auth=Auth.Token(\"TOKEN\")) as gh:\n    headers, data = gh.requester.requestJsonAndCheck(\n        \"GET\",\n        \"/rate_limit\",\n    )\n    print(data[\"resources\"][\"core\"][\"remaining\"])\n```\n\nKeep the path relative to the API root. For GitHub Enterprise Server, that still goes through the `base_url` you configured on the client.\n\n### Constructor options that matter\n\nThe `Github(...)` constructor in the official API docs exposes a few options that are useful in production code:\n\n- `base_url` for GitHub Enterprise Server\n- `timeout` for slow networks\n- `per_page` to control page size\n- `user_agent` when your integration needs a distinct UA string\n- `verify` for TLS verification behavior\n- `retry` for HTTP retry policy\n- `pool_size` for connection reuse under concurrency\n\nOnly override these deliberately. The defaults are usually good enough for simple automation.\n\n## Common Pitfalls\n\n- Import from `github`, not `pygithub`. The package name and import name differ.\n- Do not copy 1.x-era snippets like `Github(\"TOKEN\")` into a `2.6.0` codebase. The 2.x docs standardize on `auth=Auth.Token(...)`.\n- Do not rely on anonymous access for automation. GitHub rate limits unauthenticated requests aggressively.\n- Do not forget to close the client. Use `with Github(...) as gh:` or call `gh.close()`.\n- Do not convert large `PaginatedList` results into `list(...)` unless you actually need everything in memory.\n- Do not point `base_url` at `https://github.example.com/`; use the API root such as `https://github.example.com/api/v3`.\n- Do not assume every REST endpoint is wrapped at the same abstraction level. Fall back to `requester.requestJsonAndCheck(...)` when needed.\n- Do not assume a valid token has the right scopes or installation permissions. Many `404` and `403` responses on private repos are permission problems, not missing resources.\n\n## Version-Sensitive Notes\n\n- PyPI metadata for `2.6.0` declares `Requires-Python >=3.8`.\n- The `stable/` docs root is newer than this guide's pinned package version, so examples there may reflect later releases unless you switch to `https://pygithub.readthedocs.io/en/v2.6.0/`.\n- The official `2.6.0` changelog says repository traffic views and clones were reworked: instead of dict-like access, PyGithub now returns objects with `.timestamp`, `.count`, and `.uniques` attributes.\n- Inference from official sources: the newer examples page still shows dict-style traffic access (`views['count']` and `views['views']`). For `2.6.0`, trust the changelog and use object attributes instead.\n- If you are migrating old code, verify auth construction, pagination behavior, and any direct attribute access copied from old blog posts against the current API reference for `Github`, `Auth`, and the object you are using.\n\nExample for the traffic change:\n\n```python\nviews = repo.get_views_traffic()\nprint(views.count)\nprint(views.views[0].timestamp)\n```\n\n## Official Sources\n\n- Docs root: `https://pygithub.readthedocs.io/en/stable/`\n- Version-pinned introduction: `https://pygithub.readthedocs.io/en/v2.6.0/introduction.html`\n- Version-pinned main class docs: `https://pygithub.readthedocs.io/en/v2.6.0/github.html`\n- Utilities docs: `https://pygithub.readthedocs.io/en/latest/utilities.html`\n- Examples page: `https://pygithub.readthedocs.io/en/latest/examples/MainClass.html`\n- Changelog: `https://pygithub.readthedocs.io/en/v2.6.0/changes.html`\n- Repository README: `https://raw.githubusercontent.com/PyGithub/PyGithub/main/README.md`\n- Repository: `https://github.com/PyGithub/PyGithub`\n- PyPI project: `https://pypi.org/project/PyGithub/`\n- PyPI release JSON for `2.6.0`: `https://pypi.org/pypi/PyGithub/2.6.0/json`\n"
  },
  {
    "path": "content/pygments/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pygments package guide for Python syntax highlighting, lexers, formatters, and CLI usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.19.2\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pygments,python,syntax-highlighting,lexer,formatter,html,cli\"\n---\n\n# Pygments Python Package Guide\n\n## What It Is\n\n`pygments` is a syntax-highlighting library for Python applications and CLIs. It splits the job into:\n\n- **Lexer**: tokenizes source text\n- **Formatter**: turns tokens into output such as HTML, terminal ANSI, SVG, RTF, or LaTeX\n- **Style**: controls colors and token styling\n\nFor most agent work, use the high-level `highlight()` API with an explicit lexer and formatter. Fall back to auto-detection only when the input language is genuinely unknown.\n\n## Install\n\n```bash\npip install Pygments==2.19.2\n```\n\nCommon variants:\n\n```bash\npip install Pygments\npip install \"Pygments[plugins]\"\npip install \"Pygments[windows-terminal]\"\n```\n\n- `plugins` is useful when you rely on third-party lexers, formatters, styles, or filters registered through entry points.\n- `windows-terminal` installs color support for Windows console output.\n- PyPI lists Python `>=3.8` for `2.19.2`.\n\n## Core API\n\nThe usual imports are:\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import PythonLexer, get_lexer_by_name, get_lexer_for_filename, guess_lexer\nfrom pygments.formatters import HtmlFormatter, TerminalFormatter\n```\n\n### Highlight code to HTML\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import PythonLexer\nfrom pygments.formatters import HtmlFormatter\n\ncode = \"\"\"\ndef greet(name: str) -> str:\n    return f\"hello, {name}\"\n\"\"\".strip()\n\nformatter = HtmlFormatter(full=True, style=\"default\")\nhtml = highlight(code, PythonLexer(), formatter)\nprint(html[:200])\n```\n\nUse this when you know the language. It is more reliable than guessing.\n\n### Generate CSS for HTML output\n\n```python\nfrom pygments.formatters import HtmlFormatter\n\nformatter = HtmlFormatter(cssclass=\"codehilite\", style=\"friendly\")\ncss = formatter.get_style_defs(\".codehilite\")\n```\n\n`HtmlFormatter` only emits token spans and CSS classes by default. If you render HTML in a site or app, include the generated CSS or pass `noclasses=True` to inline styles.\n\n### Highlight for terminal output\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import TerminalFormatter\n\ncode = \"SELECT * FROM users WHERE active = 1;\\n\"\nlexer = get_lexer_by_name(\"sql\")\ncolored = highlight(code, lexer, TerminalFormatter())\nprint(colored, end=\"\")\n```\n\nUse terminal formatters for CLI tools, debug output, and TUI-style utilities.\n\n## Choosing a Lexer\n\n### Prefer explicit selection\n\n```python\nlexer = get_lexer_by_name(\"python\")\n```\n\nThis is the safest option when the calling code already knows the language.\n\n### Select from a filename\n\n```python\nlexer = get_lexer_for_filename(\"report.jinja2\", template_text)\n```\n\nUse this when file extension or template name carries useful signal.\n\n### Guess from content\n\n```python\ntry:\n    lexer = guess_lexer(text)\nexcept Exception:\n    lexer = get_lexer_by_name(\"text\")\n```\n\n`guess_lexer()` is convenient but not deterministic enough for security-sensitive or user-visible formatting. Keep a plain-text fallback.\n\n### Plain text fallback\n\n```python\nfrom pygments.lexers.special import TextLexer\n\nlexer = TextLexer()\n```\n\nUse this when you would rather preserve content than risk the wrong lexer.\n\n## Working With Formatters\n\nCommon formatter choices:\n\n- `HtmlFormatter` for docs sites, emails, web apps, and generated reports\n- `TerminalFormatter` for ANSI terminal output\n- `Terminal256Formatter` and `TerminalTrueColorFormatter` when your terminal supports richer color\n- `LatexFormatter`, `SvgFormatter`, and `RtfFormatter` for document-generation pipelines\n\nMost lexers and formatters accept options as keyword arguments:\n\n```python\nlexer = get_lexer_by_name(\"python\", stripnl=False)\nformatter = HtmlFormatter(linenos=True, cssclass=\"source\", style=\"monokai\")\n```\n\nThe command-line interface exposes the same idea through `-O` and `-P` options.\n\n## Styles\n\nInspect available built-in styles:\n\n```python\nfrom pygments.styles import get_all_styles\n\nstyles = sorted(get_all_styles())\nprint(styles[:10])\n```\n\nTypical style names include `default`, `friendly`, `colorful`, `monokai`, `native`, and `dracula`.\n\nIf an application lets users choose a theme, validate the style name first instead of assuming it exists.\n\n## CLI Usage With `pygmentize`\n\n`pygmentize` is the packaged CLI and is often the fastest way to highlight files or pipes in automation.\n\n### Highlight a file to HTML\n\n```bash\npygmentize -f html -O full,style=friendly -o snippet.html app.py\n```\n\n### Force a lexer and formatter\n\n```bash\npygmentize -l python -f terminal256 script.txt\n```\n\n### Guess the lexer from input\n\n```bash\ncat query.sql | pygmentize -g\n```\n\n### List lexers, formatters, filters, and styles\n\n```bash\npygmentize -L\n```\n\n### Print CSS for a style\n\n```bash\npygmentize -S monokai -f html -a .highlight\n```\n\nUseful flags from the official CLI docs:\n\n- `-l` picks a lexer explicitly\n- `-f` picks a formatter explicitly\n- `-O` passes a comma-separated formatter or lexer option list\n- `-P` passes one option at a time\n- `-F` adds a filter\n- `-g` guesses the lexer\n- `-L` lists available components\n- `-S` prints CSS for HTML styling\n\n## Filters and Plugins\n\nPygments can apply filters between lexing and formatting, and it can load third-party extensions through Python entry points.\n\nTypical plugin groups:\n\n- `pygments.lexers`\n- `pygments.formatters`\n- `pygments.styles`\n- `pygments.filters`\n\nFor agent work, the practical rule is:\n\n1. Install the plugin package.\n2. Let it register entry points.\n3. Refer to the new lexer, formatter, style, or filter by its advertised alias or class.\n\nYou usually do not need custom runtime bootstrap code beyond importing or selecting the component after installation.\n\n## Configuration and Environment\n\nPygments does not need API keys, tokens, or service credentials.\n\nConfiguration is usually local to the call site:\n\n- constructor kwargs on lexers and formatters\n- chosen style name\n- CSS generation settings for HTML output\n- CLI flags for one-off commands\n\nIf your app needs stable rendering, pin:\n\n- package version\n- explicit lexer\n- explicit formatter\n- explicit style\n\nThat avoids output drift from auto-detection or defaults changing later.\n\n## Common Pitfalls\n\n### Package name vs import name\n\nInstall with `Pygments` on PyPI, import as `pygments`.\n\n### Missing CSS in HTML output\n\nIf HTML output looks unstyled, you probably generated token spans without also shipping CSS. Use `get_style_defs()` or `pygmentize -S ... -f html`.\n\n### Guessing the wrong language\n\n`guess_lexer()` and `pygmentize -g` are helpful for ad hoc tools, but they can misclassify short snippets or mixed templates. Prefer `get_lexer_by_name()` whenever the caller already knows the language.\n\n### Template and generated-file mismatches\n\nFilename-based detection can choose a template lexer or a generic lexer depending on the extension. For Jinja, Django, and other templating inputs, test the exact filename patterns you expect in production.\n\n### CLI option syntax\n\nWith `pygmentize`, `-O` takes a comma-separated option string, while `-P` passes options individually. Mixing them carelessly is a common source of invalid examples.\n\n### Treating highlighted output as sanitized HTML\n\n`HtmlFormatter` formats tokens into HTML, but that does not make arbitrary source content safe for every embedding context. Escape or sandbox user-controlled surrounding markup appropriately in your application.\n\n## Version-Sensitive Notes For 2.19.2\n\n- `2.19.2` is the version listed on the official PyPI release page and covered here.\n- The official changelog for `2.19.2` calls out fixes around Lua lexer regressions introduced in `2.19.0`; if you saw Lua highlighting break on `2.19.0` or `2.19.1`, upgrade to `2.19.2`.\n- The changelog page also shows `2.20.0` as unreleased and notes planned Python 3.8 deprecation there. Based on that official note, `2.19.2` is the safe documented target if you still support Python 3.8.\n\n## Minimal Recipes\n\n### HTML snippet for a web page\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import HtmlFormatter\n\ncode = \"print('hello')\\n\"\nlexer = get_lexer_by_name(\"python\")\nformatter = HtmlFormatter(cssclass=\"highlight\")\n\nhtml = highlight(code, lexer, formatter)\ncss = formatter.get_style_defs(\".highlight\")\n```\n\n### Terminal highlighting inside a CLI\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import Terminal256Formatter\n\ndef colorize(code: str, language: str) -> str:\n    lexer = get_lexer_by_name(language)\n    return highlight(code, lexer, Terminal256Formatter(style=\"native\"))\n```\n\n### Safe fallback when language is unknown\n\n```python\nfrom pygments import highlight\nfrom pygments.lexers import guess_lexer, get_lexer_by_name\nfrom pygments.formatters import HtmlFormatter\nfrom pygments.util import ClassNotFound\n\ndef to_html(code: str) -> str:\n    try:\n        lexer = guess_lexer(code)\n    except ClassNotFound:\n        lexer = get_lexer_by_name(\"text\")\n    return highlight(code, lexer, HtmlFormatter())\n```\n\n## Official Sources\n\n- Docs root: https://pygments.org/docs/\n- Quickstart: https://pygments.org/docs/quickstart/\n- CLI docs: https://pygments.org/docs/cmdline/\n- API docs: https://pygments.org/docs/api/\n- Styles: https://pygments.org/docs/styles/\n- Plugins: https://pygments.org/docs/plugins/\n- Changelog: https://pygments.org/docs/changelog/\n- Download and install: https://pygments.org/download/\n- PyPI package: https://pypi.org/project/Pygments/\n"
  },
  {
    "path": "content/pyjwt/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyJWT package guide for Python covering token signing, verification, claim validation, and JWKS key lookup\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.11.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyjwt,jwt,jws,jwk,jwks,authentication,security,python\"\n---\n\n# PyJWT Python Package Guide\n\n## What It Is\n\n`PyJWT` is the upstream Python library for encoding and decoding JSON Web Tokens. The pip package is `PyJWT`, but the import name is `jwt`.\n\n- Package name: `PyJWT`\n- Import name: `jwt`\n- Version covered: `2.11.0`\n- Docs root used for this entry: `https://pyjwt.readthedocs.io/en/2.11.0/`\n\n## Install\n\nUse plain `PyJWT` when you only need HMAC signing and verification:\n\n```bash\npip install PyJWT==2.11.0\n```\n\nUse the `crypto` extra for RSA, ECDSA, EdDSA, JWK, and JWKS workflows:\n\n```bash\npip install \"PyJWT[crypto]==2.11.0\"\n```\n\n## Basic Setup\n\n```python\nimport jwt\n\nSECRET_KEY = \"replace-me\"\nALGORITHM = \"HS256\"\n```\n\nCommon pitfall: `import pyjwt` is wrong for normal use. Import `jwt`.\n\n## Encode And Decode\n\n### HMAC example\n\n```python\nfrom datetime import UTC, datetime, timedelta\n\nimport jwt\n\nsecret = \"replace-me\"\n\npayload = {\n    \"sub\": \"user-123\",\n    \"iss\": \"https://auth.example.com\",\n    \"aud\": \"api://my-service\",\n    \"iat\": datetime.now(UTC),\n    \"nbf\": datetime.now(UTC),\n    \"exp\": datetime.now(UTC) + timedelta(minutes=15),\n}\n\ntoken = jwt.encode(payload, secret, algorithm=\"HS256\")\n\nclaims = jwt.decode(\n    token,\n    secret,\n    algorithms=[\"HS256\"],\n    issuer=\"https://auth.example.com\",\n    audience=\"api://my-service\",\n)\n```\n\n`jwt.encode()` returns a string in PyJWT 2.x. Datetime values for claims like `exp`, `nbf`, and `iat` are accepted directly and encoded as JWT NumericDate values.\n\n### RSA example\n\n```python\nimport jwt\n\nprivate_key_pem = open(\"private.pem\", \"rb\").read()\npublic_key_pem = open(\"public.pem\", \"rb\").read()\n\ntoken = jwt.encode({\"sub\": \"user-123\"}, private_key_pem, algorithm=\"RS256\")\n\nclaims = jwt.decode(token, public_key_pem, algorithms=[\"RS256\"])\n```\n\nAsymmetric algorithms generally require `PyJWT[crypto]`.\n\n## Registered Claims And Validation\n\nPass the expected claim values into `decode()` when you want PyJWT to verify them:\n\n```python\nclaims = jwt.decode(\n    token,\n    secret,\n    algorithms=[\"HS256\"],\n    issuer=\"https://auth.example.com\",\n    audience=\"api://my-service\",\n    subject=\"user-123\",\n    leeway=30,\n    options={\"require\": [\"exp\", \"iat\", \"nbf\", \"sub\"]},\n)\n```\n\nWhat matters in practice:\n\n- `exp` rejects expired tokens.\n- `nbf` rejects tokens before they become valid.\n- `iat` is validated when enabled.\n- `iss` is checked against the exact issuer string you pass.\n- `aud` is checked against the audience you pass.\n- `subject` lets you require one specific `sub` value.\n- `leeway` handles small clock skew.\n\nImportant pitfall: `options={\"require\": [...]}` only checks that claims are present. It does not replace normal validation. For example, `aud` still needs an `audience=` value, and `sub` still needs `subject=` when you want to compare it to an expected user or client id.\n\nIf your service expects exactly one audience string and you do not want array-like audience handling, review the `strict_aud` decode option in the API reference.\n\n## Reading Headers Or Claims Without Trusting The Token\n\nUnverified reads are only for routing decisions such as choosing a key by `kid`.\n\n```python\nheader = jwt.get_unverified_header(token)\nclaims = jwt.decode(\n    token,\n    options={\"verify_signature\": False},\n    algorithms=[\"HS256\"],\n)\n```\n\nDo not treat unverified claims as authenticated data.\n\n## JWKS And `PyJWKClient`\n\nFor OIDC and other JWKS-backed issuers, use `PyJWKClient` to fetch the signing key that matches the token header:\n\n```python\nimport jwt\n\njwks_client = jwt.PyJWKClient(\n    \"https://issuer.example.com/.well-known/jwks.json\",\n    cache_keys=True,\n)\nsigning_key = jwks_client.get_signing_key_from_jwt(token)\n\nclaims = jwt.decode(\n    token,\n    signing_key.key,\n    algorithms=[\"RS256\"],\n    issuer=\"https://issuer.example.com/\",\n    audience=\"api://my-service\",\n)\n```\n\nThis path normally needs `PyJWT[crypto]`. In practice, create one `PyJWKClient` per issuer and reuse it so its caching options can help instead of refetching on every request.\n\n## Common Exceptions\n\nCatch PyJWT exceptions around `decode()` and branch on the failure mode you care about:\n\n```python\nimport jwt\n\ntry:\n    claims = jwt.decode(token, secret, algorithms=[\"HS256\"])\nexcept jwt.ExpiredSignatureError:\n    ...\nexcept jwt.InvalidAudienceError:\n    ...\nexcept jwt.InvalidIssuerError:\n    ...\nexcept jwt.InvalidSubjectError:\n    ...\nexcept jwt.MissingRequiredClaimError:\n    ...\nexcept jwt.InvalidTokenError:\n    ...\n```\n\n`InvalidTokenError` is the common base class when you do not need finer-grained handling.\n\n## Auth And Configuration Patterns\n\nKeep these values in app configuration instead of hard-coding them across handlers:\n\n- signing or verification key material\n- accepted algorithms\n- expected issuer\n- expected audience\n- expected subject when applicable\n- JWKS URL\n- allowed clock skew (`leeway`)\n\nExample:\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True)\nclass JwtConfig:\n    algorithms: list[str]\n    issuer: str | None = None\n    audience: str | None = None\n    subject: str | None = None\n    jwks_url: str | None = None\n    leeway_seconds: int = 30\n```\n\nBuild the allowed algorithm list from trusted app config, never from token content.\n\n## High-Value Pitfalls\n\n### Always hard-code allowed algorithms\n\nPass `algorithms=[...]` to `decode()`. PyJWT's API docs explicitly warn not to compute accepted algorithms from attacker-controlled token headers.\n\n### The package name and import name differ\n\nInstall `PyJWT`, but write `import jwt`.\n\n### Install `PyJWT[crypto]` for asymmetric algorithms and JWKS\n\nPlain `PyJWT` is enough for HMAC flows. RSA, ECDSA, EdDSA, JWK, and JWKS use cases depend on `cryptography`.\n\n### `require` checks presence, not semantic validity\n\nIt only enforces that a claim exists. You still need `issuer=`, `audience=`, `subject=`, and normal expiration validation when those checks matter.\n\n### Do not trust unverified payloads\n\n`get_unverified_header()` and `verify_signature=False` are for key selection or debugging only.\n\n### Do not accept unsigned tokens by accident\n\nPyJWT 2.10.x made `\"none\"` algorithm handling more explicit. Treat unsigned tokens as invalid unless your protocol intentionally uses them.\n\n## Version Notes For 2.11.0\n\n- The target version version is `2.11.0`.\n- The `stable` docs root currently renders 2.11.0, but this entry uses versioned URLs for deterministic package-version context.\n- The 2.11.0 changelog is mostly a maintenance release for agents: Python 3.14 support, a new `algorithm_name` property on JWKs, and broader typing around `encode()` and `decode()`.\n- The biggest behavior changes that still affect upgrades came in 2.10.x: stricter `sub` and `jti` validation in 2.10.0 and the issuer-matching fix in 2.10.1.\n\n## Official Sources\n\n- Stable docs root: https://pyjwt.readthedocs.io/en/stable/\n- Versioned docs root: https://pyjwt.readthedocs.io/en/2.11.0/\n- Installation: https://pyjwt.readthedocs.io/en/2.11.0/installation.html\n- Usage: https://pyjwt.readthedocs.io/en/2.11.0/usage.html\n- API reference: https://pyjwt.readthedocs.io/en/2.11.0/api.html\n- Changelog: https://pyjwt.readthedocs.io/en/2.11.0/changelog.html\n- PyPI project: https://pypi.org/project/PyJWT/\n- PyPI version page: https://pypi.org/project/PyJWT/2.11.0/\n"
  },
  {
    "path": "content/pylint/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pylint 4.0.5 package guide for Python linting, config setup, CI integration, and common false-positive traps\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pylint,python,linting,static-analysis,quality,ci\"\n---\n\n# Pylint Python Package Guide\n\n## What It Is\n\n`pylint` is a static analysis and linting tool for Python. It checks code style, probable bugs, import problems, refactor suggestions, and convention issues, then reports them as named messages such as `unused-import`, `import-error`, or `missing-function-docstring`.\n\nUse it when you want:\n\n- one command that can lint files, packages, or directories\n- project-wide configuration in `pyproject.toml` or rc/config files\n- CI- and editor-friendly output formats\n- plugin support for framework-specific checks\n\n## Install\n\nAdd it as a development dependency and keep it pinned with the rest of your tooling:\n\n```bash\npython -m pip install \"pylint==4.0.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pylint==4.0.5\"\npoetry add --group dev \"pylint==4.0.5\"\n```\n\nIf your project uses framework-specific or domain-specific Pylint plugins, install them in the same environment as `pylint`.\n\n## Initialize And Configure\n\nFor new repos, prefer `pyproject.toml`. For existing repos already using INI-style tool config, `.pylintrc` is still fine.\n\nGenerate a starter config:\n\n```bash\npylint --generate-toml-config > /tmp/pylint-generated.toml\n```\n\nor:\n\n```bash\npylint --generate-rcfile > .pylintrc\n```\n\nNotes:\n\n- Do not redirect `--generate-toml-config` straight into an existing `pyproject.toml`; generate to a temporary file and merge the `tool.pylint` sections you want.\n- In monorepos or repos with more than one possible config file, pass `--rcfile=/absolute/or/relative/path` in CI so discovery is deterministic.\n- If you lint code that targets a different Python version than the interpreter running Pylint, set `py-version` in config explicitly.\n\nMinimal setup workflow:\n\n1. Generate a starter config.\n2. Remove broad disables you do not actually want.\n3. Run Pylint against the main package and tests.\n4. Add narrow message disables only after you see real noise from your codebase.\n\n## Core Usage\n\nLint a package or directory:\n\n```bash\npylint src/ tests/\n```\n\nLint a specific module or file:\n\n```bash\npylint my_package my_package/api.py\n```\n\nMachine-readable output for tooling:\n\n```bash\npylint src/ --output-format=json2 > pylint-report.json\n```\n\nGitHub Actions annotations:\n\n```bash\npylint src/ --output-format=github\n```\n\nUseful habits:\n\n- Run Pylint from the project root so imports resolve the same way they do in normal development.\n- Lint the package root in CI, not only individual changed files, because many messages depend on import context.\n- Prefer message symbols like `missing-function-docstring` over numeric IDs when disabling or triaging checks.\n\n## Message Control\n\nThe usual pattern is to keep project defaults in config and reserve inline disables for local exceptions.\n\nCommand-line example:\n\n```bash\npylint src/ --disable=missing-module-docstring,missing-function-docstring\n```\n\nInline example:\n\n```python\nmessage = \"value: {}\".format(value)  # pylint: disable=consider-using-f-string\n```\n\nUse inline pragmas sparingly and keep them attached to the specific line or block that needs the exception.\n\n## Config, Plugins, And Environment\n\nPylint is a local analyzer. There is no auth flow, API key, or remote service setup. The important environment concern is import resolution.\n\nPractical rules:\n\n- Run Pylint in the same virtualenv as the project.\n- Install your package and its runtime dependencies before trusting `import-error` results.\n- If you use a `src/` layout, make sure the package is importable in the lint environment, typically via editable install.\n- If you need framework-specific checks, configure `load-plugins` and install those plugins in the same environment.\n\nFor pre-commit, remember that hooks run in isolated environments. If your lint run depends on plugins or project-only imports, add the required packages to the hook's `additional_dependencies`.\n\n## CI And Automation\n\nTypical CI command:\n\n```bash\npylint src/ tests/ --output-format=text\n```\n\nIf another tool needs structured output, use `json2` instead of parsing the default text format.\n\nIn automation:\n\n- pin the Pylint version so message behavior does not drift unexpectedly\n- pin plugin versions alongside Pylint\n- pass `--rcfile` explicitly in monorepos\n- treat new major versions as behavior changes, not just bugfix upgrades\n\n## Common Pitfalls\n\n### `import-error` false positives\n\nThis usually means the lint environment does not match the app environment. Install the package in editable mode and include optional dependencies or plugins that the code imports.\n\n### Config discovery surprises\n\nPylint can read config from multiple file formats. In larger repos, this can make local runs and CI disagree. Pick one canonical config file and pass it explicitly in scripted runs.\n\n### Over-disabling checks\n\nGenerated starter configs can be noisy, but broad disables reduce the value of linting quickly. Disable by message symbol, keep the scope narrow, and prefer fixing the root cause when possible.\n\n### Pre-commit differs from local runs\n\nA pre-commit hook does not automatically reuse your project virtualenv. Missing plugins or missing app dependencies inside the hook environment are a common reason for inconsistent results.\n\n### Python-version mismatch\n\nPylint inspects code using the interpreter and target-version settings it sees. If your CI runs on Python 3.12 but the codebase targets 3.10, set `py-version` so checks match the code you actually support.\n\n## Version-Sensitive Notes For 4.0.x\n\n- As of `2026-03-12`, both PyPI and the stable docs show `pylint 4.0.5`.\n- The `4.0` line requires Python `>=3.10` and moved to the Astroid `4.x` line.\n- The 4.0 release changed some naming-check behavior, especially around constants, type aliases, and `ClassVar` handling, so older suppressions may need review after upgrading from `3.x`.\n- If you depend on framework plugins or import-order behavior, keep the full lint toolchain pinned together during upgrades instead of upgrading Pylint alone.\n\n## Official Sources Used\n\n- Docs root: `https://pylint.readthedocs.io/en/stable/`\n- Installation guide: `https://pylint.readthedocs.io/en/stable/user_guide/installation/index.html`\n- Running Pylint: `https://pylint.readthedocs.io/en/stable/user_guide/usage/run.html`\n- Configuration guide: `https://pylint.readthedocs.io/en/stable/user_guide/configuration/index.html`\n- What's new in 4.0: `https://pylint.readthedocs.io/en/v4.0.0/whatsnew/4/4.0/`\n- PyPI package page: `https://pypi.org/project/pylint/`\n"
  },
  {
    "path": "content/pymemcache/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pymemcache package guide for Python projects using Memcached clients, pooling, sharding, and explicit value serialization\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pymemcache,memcached,python,cache,client,pooling,sharding\"\n---\n\n# pymemcache Python Package Guide\n\n## Golden Rule\n\nUse `pymemcache` as a thin client for a running Memcached server, not as a data model layer. Reuse client objects instead of reconnecting for every cache call, and decide up front how your application will encode and decode values. If you do not configure a serializer and deserializer, reads come back as raw `bytes`.\n\n## Install And Prerequisites\n\nInstall the package version this guide targets:\n\n```bash\npython -m pip install \"pymemcache==4.0.0\"\n```\n\nYour application also needs a reachable Memcached server. A conventional local setup uses `127.0.0.1:11211`.\n\nExample environment variables:\n\n```bash\nexport MEMCACHED_HOST=127.0.0.1\nexport MEMCACHED_PORT=11211\n```\n\n`pymemcache` does not use an API key or token-based auth flow. You connect directly to a Memcached host and port, so production security usually comes from private networking, firewalls, and any connection controls provided by your platform.\n\n## Create A Client\n\nUse `pymemcache.client.base.Client` for a single Memcached server:\n\n```python\nimport os\n\nfrom pymemcache.client.base import Client\n\nhost = os.getenv(\"MEMCACHED_HOST\", \"127.0.0.1\")\nport = int(os.getenv(\"MEMCACHED_PORT\", \"11211\"))\n\nclient = Client((host, port))\n\ntry:\n    client.set(\"healthcheck\", b\"ok\", expire=10)\n    value = client.get(\"healthcheck\")\n    print(value)\nfinally:\n    client.close()\n```\n\nWithout a deserializer, `value` is `bytes`.\n\n## Serialize Strings And Python Objects\n\nMemcached stores bytes. If your app wants strings, JSON, or other Python objects back from the cache, configure serialization when you create the client.\n\n```python\nimport json\n\nfrom pymemcache.client.base import Client\n\n\ndef json_serializer(key, value):\n    if isinstance(value, bytes):\n        return value, 0\n    if isinstance(value, str):\n        return value.encode(\"utf-8\"), 1\n    return json.dumps(value).encode(\"utf-8\"), 2\n\n\ndef json_deserializer(key, value, flags):\n    if flags == 1:\n        return value.decode(\"utf-8\")\n    if flags == 2:\n        return json.loads(value.decode(\"utf-8\"))\n    return value\n\n\nclient = Client(\n    (\"127.0.0.1\", 11211),\n    serializer=json_serializer,\n    deserializer=json_deserializer,\n)\n\ntry:\n    client.set(\n        \"user:42\",\n        {\"name\": \"Ada\", \"active\": True, \"roles\": [\"admin\"]},\n        expire=300,\n    )\n    user = client.get(\"user:42\")\n    print(user[\"name\"])\nfinally:\n    client.close()\n```\n\nIf you use helpers from `pymemcache.serde`, treat pickle-based serialization as trusted-data-only behavior.\n\n## Common Workflows\n\n### Basic Cache Operations\n\n```python\nfrom pymemcache.client.base import Client\n\nclient = Client((\"127.0.0.1\", 11211))\n\ntry:\n    client.set(\"session:123\", b\"active\", expire=300)\n    status = client.get(\"session:123\")\n\n    client.touch(\"session:123\", 600)\n    client.delete(\"session:123\")\nfinally:\n    client.close()\n```\n\n### Batch Reads And Writes\n\n```python\nfrom pymemcache.client.base import Client\n\nclient = Client((\"127.0.0.1\", 11211))\n\ntry:\n    client.set_many(\n        {\n            \"feature:alpha\": b\"on\",\n            \"feature:beta\": b\"off\",\n        },\n        expire=60,\n    )\n\n    values = client.get_many([\"feature:alpha\", \"feature:beta\"])\n    print(values)\n\n    client.delete_many([\"feature:alpha\", \"feature:beta\"])\nfinally:\n    client.close()\n```\n\n### Counters\n\nUse increment and decrement only for keys whose stored value is a decimal integer.\n\n```python\nfrom pymemcache.client.base import Client\n\nclient = Client((\"127.0.0.1\", 11211))\n\ntry:\n    client.set(\"jobs:queued\", b\"0\")\n    client.incr(\"jobs:queued\", 1)\n    client.decr(\"jobs:queued\", 1)\nfinally:\n    client.close()\n```\n\n### Shard Across Multiple Memcached Servers\n\nUse `HashClient` when your cache layer is spread across multiple Memcached nodes.\n\n```python\nfrom pymemcache.client.hash import HashClient\n\nclient = HashClient(\n    [\n        (\"10.0.0.11\", 11211),\n        (\"10.0.0.12\", 11211),\n    ]\n)\n\ntry:\n    client.set(\"user:42\", b\"cached\")\n    value = client.get(\"user:42\")\n    print(value)\nfinally:\n    client.close()\n```\n\n### Reuse Pooled Connections\n\nIf your app makes many requests to one Memcached server, use `PooledClient` instead of opening a fresh connection for each operation.\n\n```python\nfrom pymemcache.client.base import PooledClient\n\nclient = PooledClient((\"127.0.0.1\", 11211), max_pool_size=4)\n\ntry:\n    client.set(\"task:1\", b\"done\", expire=60)\n    print(client.get(\"task:1\"))\nfinally:\n    client.close()\n```\n\n## Important Pitfalls\n\n- `get()` returns `bytes` unless you configure a deserializer.\n- Keep cache keys simple and protocol-safe; invalid keys are rejected by Memcached.\n- `incr()` and `decr()` do not work for arbitrary serialized objects.\n- Memcached is an in-memory cache. Keys can disappear because of eviction, expiration, or server restart.\n- Reuse client objects and call `close()` on shutdown so sockets are released cleanly.\n- Keep untrusted data out of pickle-based serializers.\n\n## Version Notes\n\n- This guide targets `pymemcache 4.0.0`.\n- If you pin a different major version, re-check constructor options and helper modules before copying code unchanged.\n\n## Official Sources\n\n- Maintainer docs: https://pymemcache.readthedocs.io/en/latest/\n- PyPI project page: https://pypi.org/project/pymemcache/\n"
  },
  {
    "path": "content/pymongo/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pymongo package guide for Python with MongoClient, AsyncMongoClient, Atlas/local connections, CRUD, transactions, and auth extras\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.16.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"mongodb,pymongo,bson,gridfs,python,database\"\n---\n\n# PyMongo Python Package Guide\n\n## Golden Rule\n\n- Use the official `pymongo` package for MongoDB access in Python.\n- Treat MongoDB Docs as the canonical guide surface for setup and examples, and use the PyMongo ReadTheDocs site for API details and changelog entries.\n- Do not install the third-party `bson` package from PyPI. PyMongo ships its own `bson` package and the PyPI `bson` package is incompatible.\n\n## Version-Sensitive Notes\n\n- The docs URL points to `https://pymongo.readthedocs.io/en/stable/`, which is still official, but the current guide-style docs and examples now live under MongoDB Docs at `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/`.\n- MongoDB Docs `Get Started` still says Python `3.8+`, but the live PyPI metadata for `pymongo 4.16.0` requires Python `>=3.9`. Use PyPI for packaging constraints.\n- PyMongo `4.16.0` requires `dnspython>=2.6.1` for `mongodb+srv://` support and removes Eventlet support.\n- PyMongo `4.14` dropped support for MongoDB Server `4.0`; current 4.16 docs target MongoDB Server `4.2+`.\n- Motor is deprecated in favor of the GA PyMongo Async API. Prefer `AsyncMongoClient` for new asyncio code instead of adding `motor`.\n\n## Install\n\nPin the driver when you need reproducible behavior:\n\n```bash\npython -m pip install \"pymongo==4.16.0\"\n```\n\nIf you use SRV connection strings, make sure `dnspython` is available:\n\n```bash\npython -m pip install \"pymongo==4.16.0\" \"dnspython>=2.6.1\"\n```\n\nUseful optional extras from PyPI:\n\n```bash\npython -m pip install \"pymongo[aws]==4.16.0\"\npython -m pip install \"pymongo[gssapi]==4.16.0\"\npython -m pip install \"pymongo[ocsp]==4.16.0\"\npython -m pip install \"pymongo[snappy]==4.16.0\"\npython -m pip install \"pymongo[zstd]==4.16.0\"\npython -m pip install \"pymongo[encryption]==4.16.0\"\n```\n\nUse these extras only when the deployment or feature requires them:\n\n- `aws`: `MONGODB-AWS` authentication\n- `gssapi`: Kerberos / GSSAPI authentication\n- `ocsp`: OCSP certificate validation support\n- `snappy`, `zstd`: wire compression\n- `encryption`: client-side field level encryption / queryable encryption\n\n## Recommended Setup\n\nKeep the connection string in an environment variable and validate connectivity with `ping` immediately after constructing the client. PyMongo client construction does not fail fast on bad credentials or an unavailable server.\n\n```bash\nexport MONGODB_URI=\"mongodb://localhost:27017/\"\n```\n\n```python\nimport os\nfrom pymongo import MongoClient\nfrom pymongo.errors import ConnectionFailure\n\nuri = os.environ[\"MONGODB_URI\"]\nclient = MongoClient(uri, serverSelectionTimeoutMS=5000)\n\ntry:\n    client.admin.command(\"ping\")\nexcept ConnectionFailure:\n    client.close()\n    raise\n```\n\n### Atlas connection\n\nMongoDB's current driver guide shows Atlas examples with Stable API enabled:\n\n```python\nimport os\nimport pymongo\nfrom pymongo import MongoClient\n\nuri = os.environ[\"MONGODB_URI\"]\n\nclient = MongoClient(\n    uri,\n    server_api=pymongo.server_api.ServerApi(\n        version=\"1\",\n        strict=True,\n        deprecation_errors=True,\n    ),\n    serverSelectionTimeoutMS=5000,\n)\n\nclient.admin.command(\"ping\")\n```\n\n### Local development\n\n```python\nfrom pymongo import MongoClient\n\nclient = MongoClient(\"mongodb://localhost:27017/\", serverSelectionTimeoutMS=5000)\nclient.admin.command(\"ping\")\n```\n\n### Async setup\n\nUse `AsyncMongoClient` for asyncio applications:\n\n```python\nimport os\nimport pymongo\nfrom pymongo import AsyncMongoClient\n\nuri = os.environ[\"MONGODB_URI\"]\n\nclient = AsyncMongoClient(\n    uri,\n    server_api=pymongo.server_api.ServerApi(\n        version=\"1\",\n        strict=True,\n        deprecation_errors=True,\n    ),\n    serverSelectionTimeoutMS=5000,\n)\n\nawait client.admin.command(\"ping\")\n```\n\n## Core Usage\n\n### Database and collection handles\n\n```python\nfrom pymongo import MongoClient\n\nclient = MongoClient(\"mongodb://localhost:27017/\")\ndb = client[\"app\"]\nusers = db[\"users\"]\n```\n\n### Insert documents\n\nLet PyMongo generate `_id` values unless you have a strong reason to manage them yourself.\n\n```python\nuser_id = users.insert_one(\n    {\n        \"email\": \"ada@example.com\",\n        \"name\": \"Ada Lovelace\",\n        \"roles\": [\"admin\"],\n    }\n).inserted_id\n```\n\nBatch insert:\n\n```python\nusers.insert_many(\n    [\n        {\"email\": \"grace@example.com\", \"name\": \"Grace Hopper\"},\n        {\"email\": \"linus@example.com\", \"name\": \"Linus Torvalds\"},\n    ]\n)\n```\n\n### Query documents\n\n```python\nuser = users.find_one({\"email\": \"ada@example.com\"})\n\nfor doc in users.find({\"roles\": \"admin\"}):\n    print(doc[\"email\"])\n\ncount = users.count_documents({})\n```\n\nAsync query pattern:\n\n```python\nuser = await users.find_one({\"email\": \"ada@example.com\"})\n\nasync for doc in users.find({\"roles\": \"admin\"}):\n    print(doc[\"email\"])\n```\n\n### Update documents\n\nUse update operators such as `$set`, and use `upsert=True` only when create-if-missing behavior is intended.\n\n```python\nresult = users.update_one(\n    {\"email\": \"ada@example.com\"},\n    {\"$set\": {\"name\": \"Ada Byron\"}},\n)\n\nusers.update_many(\n    {\"team\": \"platform\"},\n    {\"$set\": {\"active\": True}},\n    upsert=True,\n)\n```\n\n### Create indexes explicitly\n\nAdd the indexes your query patterns actually need. PyMongo exposes standard collection indexes and Atlas Search / Vector Search index management.\n\n```python\nusers.create_index(\"email\", unique=True)\nusers.create_index([(\"created_at\", -1)])\n```\n\nFor Atlas Search or Vector Search indexes:\n\n```python\nfrom pymongo.operations import SearchIndexModel\n\nmodel = SearchIndexModel(\n    definition={\n        \"fields\": [\n            {\n                \"type\": \"vector\",\n                \"numDimensions\": 1536,\n                \"path\": \"embedding\",\n                \"similarity\": \"cosine\",\n            }\n        ]\n    },\n    name=\"embedding_index\",\n    type=\"vectorSearch\",\n)\n\nusers.create_search_index(model=model)\n```\n\n## Transactions and Sessions\n\nUse transactions only when you need multi-document atomicity. Keep the callback idempotent because `with_transaction()` can retry the commit or the entire transaction and may invoke the callback multiple times.\n\n```python\nfrom pymongo import MongoClient\nfrom pymongo.errors import ConnectionFailure, OperationFailure\nfrom pymongo.read_concern import ReadConcern\nfrom pymongo.write_concern import WriteConcern\n\nclient = MongoClient(\"<connection string>\")\norders = client[\"shop\"][\"orders\"]\n\ndef write_order(session):\n    coll = orders.with_options(\n        write_concern=WriteConcern(\"majority\"),\n        read_concern=ReadConcern(\"local\"),\n    )\n    coll.insert_one({\"sku\": \"abc123\", \"qty\": 1}, session=session)\n\nwith client.start_session() as session:\n    try:\n        session.with_transaction(write_order)\n    except (ConnectionFailure, OperationFailure):\n        raise\n```\n\nImportant limits from the official docs:\n\n- A `ClientSession` is not thread-safe or fork-safe.\n- PyMongo does not support parallel operations inside a single transaction.\n- On MongoDB Server `8.0+`, `MongoClient.bulk_write()` can perform writes across multiple namespaces inside one transaction.\n\n## Authentication and Connection Configuration\n\n### URI encoding\n\nReserved characters in usernames, passwords, and Unix socket paths must be percent-encoded:\n\n```python\nfrom urllib.parse import quote_plus\nfrom pymongo import MongoClient\n\nuser = quote_plus(\"app-user\")\npassword = quote_plus(\"p@ss:w/rd\")\nhost = \"cluster0.example.mongodb.net\"\n\nclient = MongoClient(f\"mongodb://{user}:{password}@{host}\")\n```\n\n### Supported auth mechanisms\n\nThe current MongoDB driver docs list these mechanisms:\n\n- `SCRAM`\n- `X.509`\n- `AWS IAM`\n- `OIDC`\n- `LDAP (PLAIN)`\n- `Kerberos (GSSAPI)`\n\nFor most application code, the mechanism is implied by the deployment's connection string and server configuration. Reach for explicit auth configuration only when the deployment requires it.\n\n### Useful connection options\n\nThese options come directly from the current `MongoClient` / `AsyncMongoClient` API docs and matter often in real code:\n\n- `serverSelectionTimeoutMS`: how long server selection can take before failing\n- `timeoutMS`: overall per-operation timeout including retries\n- `socketTimeoutMS`: how long to wait for a normal database response\n- `connectTimeoutMS`: how long to wait while opening a new socket\n- `maxPoolSize`, `minPoolSize`, `maxIdleTimeMS`, `maxConnecting`: pool tuning\n- `directConnection`: force a direct connection to a single host\n- `tz_aware`: decode BSON datetimes as timezone-aware Python datetimes\n\nExample:\n\n```python\nfrom pymongo import MongoClient\n\nclient = MongoClient(\n    \"mongodb://localhost:27017/\",\n    serverSelectionTimeoutMS=5000,\n    timeoutMS=10000,\n    connectTimeoutMS=2000,\n    maxPoolSize=50,\n    tz_aware=True,\n)\n```\n\n## Files and Binary Data\n\nUse `gridfs` when files exceed MongoDB's 16 MB BSON document limit:\n\n```python\nimport gridfs\nfrom pymongo import MongoClient\n\nclient = MongoClient(\"<connection string>\")\ndb = client[\"app\"]\nbucket = gridfs.GridFSBucket(db)\n\nwith bucket.open_upload_stream(\n    \"report.pdf\",\n    metadata={\"contentType\": \"application/pdf\"},\n) as grid_in:\n    grid_in.write(b\"file-bytes\")\n```\n\nAsync variant:\n\n```python\nimport gridfs\nfrom pymongo import AsyncMongoClient\n\nclient = AsyncMongoClient(\"<connection string>\")\ndb = client[\"app\"]\nbucket = gridfs.AsyncGridFSBucket(db)\n```\n\n## Common Pitfalls\n\n- Do not `pip install bson`. Use the `bson` module that ships with `pymongo`.\n- Do not assume client construction proves connectivity. Run `ping` early.\n- Do not copy MongoDB docs' Python `3.8+` prerequisite blindly for packaging. PyPI for `pymongo 4.16.0` requires Python `>=3.9`.\n- Do not forget `dnspython` when using `mongodb+srv://`. SRV URIs depend on DNS resolution and implicitly enable TLS.\n- Do not forget to percent-encode reserved characters in usernames and passwords inside MongoDB URIs.\n- Do not share one transaction across concurrent operations. Sessions are sequential.\n- Do not rely on Eventlet with PyMongo `4.16+`; support was removed.\n- Do not add `motor` for new asyncio work unless you are maintaining existing code. MongoDB now recommends PyMongo Async.\n- In PyMongo `4.x`, `directConnection` defaults to `False`. If you truly need a direct single-host connection, set it explicitly.\n- Close clients when they are no longer needed: `client.close()` or `await client.close()`.\n\n## Practical Defaults For Agents\n\n- Default to `MongoClient` unless the surrounding app is already asyncio-native.\n- Store the connection string in `MONGODB_URI`.\n- Create clients once per process, not per request.\n- Add `serverSelectionTimeoutMS` on startup so connection failures surface quickly.\n- Create required indexes in application setup or migrations, not lazily in hot paths.\n- Keep transaction callbacks idempotent because retries can re-run them.\n\n## Official Sources Used For This Entry\n\n- MongoDB driver guide: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/`\n- Get started: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/get-started/`\n- Connect: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/connect/`\n- Authentication: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/security/authentication/`\n- CRUD insert/query/update: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/`\n- Transactions: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/transactions/`\n- Indexes: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/indexes/`\n- GridFS: `https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/gridfs/`\n- PyMongo API docs: `https://pymongo.readthedocs.io/en/stable/`\n- PyMongo changelog: `https://pymongo.readthedocs.io/en/stable/changelog.html`\n- PyPI package metadata: `https://pypi.org/project/pymongo/`\n"
  },
  {
    "path": "content/pymupdf/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyMuPDF Python package guide for opening, inspecting, extracting, rendering, annotating, and saving PDF and document files\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.27.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pymupdf,pdf,documents,ocr,text-extraction,rendering,annotations\"\n---\n\n# PyMuPDF Python Package Guide\n\n## Golden Rule\n\nUse `pymupdf` for document access and manipulation, keep document I/O explicit, and save changes deliberately. The official docs for `1.27.2` use `import pymupdf`, `pymupdf.open(...)`, `page.get_text(...)`, `page.get_pixmap()`, and `doc.save(...)` as the core workflow.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"PyMuPDF==1.27.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"PyMuPDF==1.27.2\"\npoetry add \"PyMuPDF==1.27.2\"\n```\n\nNotes:\n\n- PyPI lists `Requires: Python >=3.10`.\n- Do not install `PyMuPDFb` directly unless you are debugging packaging internals. It is an implementation dependency used by current wheels.\n- OCR support requires a separate Tesseract installation and language data; PyMuPDF does not bundle Tesseract itself.\n\n## Initialize And Open Documents\n\n### Open a local document\n\nUse a context manager so the file handle closes cleanly:\n\n```python\nimport pymupdf\n\nwith pymupdf.open(\"example.pdf\") as doc:\n    print(doc.page_count)\n    print(doc.metadata)\n```\n\n### Create a new empty PDF\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open()\npage = doc.new_page()\npage.insert_text((72, 72), \"Hello, PyMuPDF\")\ndoc.save(\"created.pdf\")\ndoc.close()\n```\n\n### Open from bytes or a network response\n\nFor in-memory data, pass `stream=`. If the format is not obvious from the bytes, also pass `filetype=`.\n\n```python\nimport pymupdf\nimport requests\n\nresponse = requests.get(\"https://example.com/report.pdf\", timeout=30)\nresponse.raise_for_status()\n\ndoc = pymupdf.open(stream=response.content)\nprint(doc.page_count)\ndoc.close()\n```\n\nFor non-PDF streams:\n\n```python\nimport pymupdf\n\nwith open(\"report.xps\", \"rb\") as f:\n    data = f.read()\n\ndoc = pymupdf.open(stream=data, filetype=\"xps\")\ndoc.close()\n```\n\n### Open an encrypted PDF\n\nAuthentication is document-level. If a PDF is password-protected, check `needs_pass` and call `authenticate(...)` before reading pages.\n\n```python\nimport os\nimport pymupdf\n\ndoc = pymupdf.open(\"secret.pdf\")\n\nif doc.needs_pass:\n    ok = doc.authenticate(os.environ[\"PDF_PASSWORD\"])\n    if not ok:\n        raise RuntimeError(\"Failed to authenticate PDF\")\n\nprint(doc.page_count)\ndoc.close()\n```\n\n## Core Usage\n\n### Extract text\n\nThe baseline extraction path is `page.get_text()`. For agent workflows, structured modes are often more useful than plain text.\n\n```python\nimport pymupdf\n\nwith pymupdf.open(\"example.pdf\") as doc:\n    page = doc[0]\n\n    plain_text = page.get_text()\n    blocks = page.get_text(\"blocks\")\n    words = page.get_text(\"words\")\n    markdown = page.get_text(\"markdown\")\n\n    print(plain_text[:500])\n    print(blocks[:2])\n    print(words[:10])\n    print(markdown[:500])\n```\n\nUse:\n\n- default text when you just need readable content\n- `\"blocks\"` or `\"words\"` when reading order matters or you need coordinates\n- `\"markdown\"` when feeding extracted content into another LLM step\n\n### Render a page to an image\n\n```python\nimport pymupdf\n\nwith pymupdf.open(\"example.pdf\") as doc:\n    page = doc[0]\n    pix = page.get_pixmap()\n    pix.save(\"page-1.png\")\n```\n\nIf the default render is too low-resolution for OCR or UI previews, render with a higher DPI or a scaling matrix.\n\n### Add annotations\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"example.pdf\")\npage = doc[0]\n\nrect = pymupdf.Rect(72, 72, 220, 120)\nannot = page.add_freetext_annot(rect, \"Review this section\")\nannot.set_colors(stroke=(1, 0, 0))\nannot.update()\n\ndoc.save(\"annotated.pdf\")\ndoc.close()\n```\n\nPyMuPDF also supports highlight, underline, strikeout, squiggle, shape, text, and stamp annotations. Save after updates or the changes stay in memory only.\n\n### Save changes\n\nUse a new output path unless you explicitly want in-place incremental updates.\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"example.pdf\")\ndoc.set_metadata({})\ndoc.save(\"clean-copy.pdf\", garbage=3, deflate=True)\ndoc.close()\n```\n\nIncremental save is only appropriate when writing back to the original file and when the document still allows it:\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"example.pdf\")\n\nif doc.can_save_incrementally():\n    doc.save(doc.name, incremental=True, encryption=pymupdf.PDF_ENCRYPT_KEEP)\n\ndoc.close()\n```\n\n## OCR Setup And Usage\n\nPyMuPDF can OCR page images through Tesseract, but you must install and configure Tesseract separately.\n\nTypical setup:\n\n```bash\n# macOS\nbrew install tesseract\n\n# Debian / Ubuntu\nsudo apt-get install tesseract-ocr\n\nexport TESSDATA_PREFIX=\"/path/to/tessdata\"\n```\n\nOCR a page once, then reuse the generated `TextPage` for extraction:\n\n```python\nimport pymupdf\n\nwith pymupdf.open(\"scanned.pdf\") as doc:\n    page = doc[0]\n    textpage = page.get_textpage_ocr(language=\"eng\")\n    text = page.get_text(textpage=textpage)\n    print(text[:1000])\n```\n\nGuidance:\n\n- OCR is much slower than normal text extraction, so do it only for scanned or image-only pages.\n- Reuse the `TextPage` instead of calling OCR repeatedly on the same page.\n- Install the Tesseract language packs that match the page language.\n\n## Configuration Notes\n\nPyMuPDF has no package-level network auth, cloud auth, or global configuration file. Configuration is mostly about how you open files and where supporting binaries live.\n\n- Remote auth happens before PyMuPDF sees the file. Fetch bytes with `requests`, `httpx`, S3 clients, or another transport, then pass the bytes to `pymupdf.open(stream=...)`.\n- Password-protected PDFs use `doc.authenticate(...)`, not a global environment variable consumed by PyMuPDF.\n- OCR setup depends on the Tesseract installation and `TESSDATA_PREFIX`.\n- When opening in-memory documents that are not PDFs, pass `filetype=` explicitly.\n\n## Common Pitfalls\n\n- Prefer `import pymupdf` and current official examples. Many older snippets use the older naming style and are more likely to drift.\n- Page access is zero-based: `doc[0]` is the first page.\n- `page.get_text()` is convenient, but plain text order may not match the human reading order on complex layouts. Use `\"blocks\"`, `\"words\"`, or `\"markdown\"` when structure matters.\n- Non-PDF byte streams often need `filetype=`. Without it, open may fail or mis-detect the format.\n- OCR is not automatic. If a scanned PDF returns little or no text, switch to `get_textpage_ocr(...)`.\n- `doc.save()` writes a new file by default. Incremental save only works for specific cases and should be gated with `doc.can_save_incrementally()`.\n- Page and annotation objects depend on the underlying document. Do not keep using them after `doc.close()`.\n\n## Version-Sensitive Notes For 1.27.2\n\n- PyPI currently requires Python `>=3.10`. Treat that as the packaging floor even if some docs pages still mention test coverage for older interpreters.\n- The `1.27.x` docs explicitly document `page.get_text(\"markdown\")`, OCR via `get_textpage_ocr()`, and incremental-save checks via `doc.can_save_incrementally()`. If you are pinned to an older project version, verify those helpers before assuming they exist unchanged.\n\n## Official Sources\n\n- PyMuPDF docs root: `https://pymupdf.readthedocs.io/en/latest/`\n- Installation: `https://pymupdf.readthedocs.io/en/latest/installation.html`\n- Tutorial: `https://pymupdf.readthedocs.io/en/latest/tutorial.html`\n- Opening files: `https://pymupdf.readthedocs.io/en/latest/how-to-open-a-file.html`\n- Text recipes: `https://pymupdf.readthedocs.io/en/latest/recipes-text.html`\n- Image recipes: `https://pymupdf.readthedocs.io/en/latest/recipes-images.html`\n- Annotation recipes: `https://pymupdf.readthedocs.io/en/latest/recipes-annotations.html`\n- OCR recipes: `https://pymupdf.readthedocs.io/en/latest/recipes-ocr.html`\n- Document API: `https://pymupdf.readthedocs.io/en/latest/document.html`\n- Changelog: `https://pymupdf.readthedocs.io/en/latest/changes.html`\n- PyPI package page: `https://pypi.org/project/PyMuPDF/`\n"
  },
  {
    "path": "content/pymysql/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyMySQL package guide for Python with connection setup, cursors, transactions, TLS, and 1.1.2 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pymysql,mysql,mariadb,sql,db-api,python\"\n---\n\n# PyMySQL Python Package Guide\n\n## What It Is\n\n`pymysql` is a pure-Python MySQL and MariaDB client that implements the Python DB-API 2.0 interface. Use it when Python code needs direct MySQL or MariaDB access without compiling a native driver.\n\nPyMySQL is synchronous. If you need async database access, use an async driver or an async ORM layer instead of expecting `pymysql` itself to become non-blocking.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"PyMySQL==1.1.2\"\n```\n\nOptional extras from the official package metadata:\n\n```bash\npython -m pip install \"PyMySQL[rsa]==1.1.2\"\npython -m pip install \"PyMySQL[ed25519]==1.1.2\"\n```\n\nUse `rsa` when the server auth flow needs `sha256_password` or `caching_sha2_password`. Use `ed25519` for MariaDB servers configured with the `ed25519` authentication plugin.\n\n## Golden Rules\n\n- Set `charset=\"utf8mb4\"` unless you have a specific server-side reason not to.\n- Use parameter binding with `%s` or `%(name)s`; do not build SQL with f-strings or string concatenation.\n- Remember that `autocommit` defaults to `False`. Call `commit()` after writes or enable autocommit explicitly.\n- Prefer `database=` and `password=`. The older aliases `db=` and `passwd=` are deprecated.\n- Set connection and I/O timeouts explicitly in production code.\n- Keep `local_infile=False` unless you intentionally need `LOAD DATA LOCAL`.\n\n## Initialize A Connection\n\nTypical application setup uses environment variables and a `DictCursor`:\n\n```python\nimport os\nimport pymysql\nimport pymysql.cursors\n\nconnection = pymysql.connect(\n    host=os.environ[\"MYSQL_HOST\"],\n    port=int(os.getenv(\"MYSQL_PORT\", \"3306\")),\n    user=os.environ[\"MYSQL_USER\"],\n    password=os.environ[\"MYSQL_PASSWORD\"],\n    database=os.environ[\"MYSQL_DATABASE\"],\n    charset=\"utf8mb4\",\n    cursorclass=pymysql.cursors.DictCursor,\n    autocommit=False,\n    connect_timeout=10,\n    read_timeout=30,\n    write_timeout=30,\n)\n```\n\nImportant connection parameters from the official API reference:\n\n- `host` and `port` for TCP connections\n- `unix_socket` for local socket-based connections\n- `database` for the default schema\n- `cursorclass` to choose `Cursor`, `DictCursor`, `SSCursor`, or `SSDictCursor`\n- `read_default_file` to load client options from a `my.cnf`\n- `ssl`, `ssl_ca`, `ssl_cert`, `ssl_key`, `ssl_verify_cert`, `ssl_verify_identity` for TLS\n- `read_timeout` and `write_timeout` for socket I/O\n- `server_public_key` and `auth_plugin_map` for specialized auth flows\n\nIf you want to read credentials from a MySQL client config file:\n\n```python\nimport pymysql\n\nconnection = pymysql.connect(\n    read_default_file=\"~/.my.cnf\",\n    read_default_group=\"client\",\n    database=\"appdb\",\n    charset=\"utf8mb4\",\n)\n```\n\n## Core Usage\n\n### Simple Query Pattern\n\n```python\nimport pymysql\nimport pymysql.cursors\n\nconnection = pymysql.connect(\n    host=\"localhost\",\n    user=\"app\",\n    password=\"secret\",\n    database=\"appdb\",\n    charset=\"utf8mb4\",\n    cursorclass=pymysql.cursors.DictCursor,\n)\n\nwith connection:\n    with connection.cursor() as cursor:\n        cursor.execute(\n            \"SELECT id, email FROM users WHERE status=%s ORDER BY id DESC LIMIT %s\",\n            (\"active\", 20),\n        )\n        rows = cursor.fetchall()\n\n    print(rows)\n```\n\nParameter style reminders:\n\n- Use `%s` for tuple or list parameters.\n- Use `%(name)s` for mapping-style parameters.\n- Do not quote placeholders yourself.\n\n### Insert, Commit, And Roll Back\n\nBecause autocommit is off by default, treat writes as explicit transactions:\n\n```python\nimport pymysql\n\nconnection = pymysql.connect(\n    host=\"localhost\",\n    user=\"app\",\n    password=\"secret\",\n    database=\"appdb\",\n    charset=\"utf8mb4\",\n)\n\ntry:\n    with connection.cursor() as cursor:\n        cursor.execute(\n            \"INSERT INTO users (email, password_hash) VALUES (%s, %s)\",\n            (\"alice@example.com\", \"hashed-password\"),\n        )\n    connection.commit()\nexcept Exception:\n    connection.rollback()\n    raise\nfinally:\n    connection.close()\n```\n\n### Batch Inserts\n\nUse `executemany()` for repeated `INSERT` or `REPLACE` statements:\n\n```python\nrows = [\n    (\"alice@example.com\", \"hash-1\"),\n    (\"bob@example.com\", \"hash-2\"),\n]\n\nwith connection.cursor() as cursor:\n    cursor.executemany(\n        \"INSERT INTO users (email, password_hash) VALUES (%s, %s)\",\n        rows,\n    )\n\nconnection.commit()\n```\n\n`executemany()` improves multi-row insert performance, but it still builds a statement that is bounded by packet-size limits. For very large batches, chunk your input instead of sending everything in one call.\n\n## Cursor Types\n\nChoose the cursor class deliberately:\n\n- `Cursor`: default tuple-based rows\n- `DictCursor`: dict-like rows keyed by column name\n- `SSCursor`: unbuffered streaming cursor for large result sets\n- `SSDictCursor`: unbuffered streaming cursor with dict rows\n\nUse an unbuffered cursor when result sets are large or the connection is remote and you want lower peak memory use:\n\n```python\nimport pymysql.cursors\n\nwith connection.cursor(pymysql.cursors.SSDictCursor) as cursor:\n    cursor.execute(\"SELECT id, payload FROM huge_table\")\n    for row in cursor:\n        process(row)\n```\n\nUnbuffered cursor caveats from the upstream API docs:\n\n- total row count is not known up front\n- backwards scrolling is not supported\n- you should fully consume the result before reusing the connection for another query\n\n## Transactions And Connection State\n\nUseful connection methods:\n\n- `commit()` to persist changes\n- `rollback()` to abandon the current transaction\n- `begin()` to start a transaction explicitly\n- `ping(reconnect=True)` to verify the server is alive and optionally reconnect\n\nDo not treat `ping(reconnect=True)` as a general connection-pooling strategy. In web apps or workers, manage connection lifetime at the framework or application boundary.\n\n## TLS And Authentication\n\nUse TLS for remote database traffic. The connection API accepts either an `ssl.SSLContext` or TLS-related keyword arguments.\n\nExample with an `SSLContext`:\n\n```python\nimport os\nimport ssl\nimport pymysql\n\nssl_context = ssl.create_default_context(cafile=os.environ[\"MYSQL_SSL_CA\"])\nssl_context.check_hostname = True\nssl_context.verify_mode = ssl.CERT_REQUIRED\n\nconnection = pymysql.connect(\n    host=os.environ[\"MYSQL_HOST\"],\n    user=os.environ[\"MYSQL_USER\"],\n    password=os.environ[\"MYSQL_PASSWORD\"],\n    database=os.environ[\"MYSQL_DATABASE\"],\n    ssl=ssl_context,\n)\n```\n\nExample with explicit TLS keyword arguments:\n\n```python\nconnection = pymysql.connect(\n    host=\"db.example.com\",\n    user=\"app\",\n    password=\"secret\",\n    database=\"appdb\",\n    ssl_ca=\"/etc/ssl/certs/mysql-ca.pem\",\n    ssl_cert=\"/etc/ssl/certs/client-cert.pem\",\n    ssl_key=\"/etc/ssl/private/client-key.pem\",\n    ssl_verify_cert=True,\n    ssl_verify_identity=True,\n)\n```\n\nAuthentication notes:\n\n- `PyMySQL[rsa]` is needed for some MySQL auth plugin flows such as `sha256_password` and `caching_sha2_password`.\n- `server_public_key=` is available when the server requires an RSA public key for auth.\n- `auth_plugin_map=` exists for specialized or custom auth plugin handling, but treat it as advanced usage.\n\n## Error Handling\n\nPyMySQL follows DB-API exception families under `pymysql.err`. Common ones:\n\n- `pymysql.err.OperationalError` for network, auth, timeout, or server-state failures\n- `pymysql.err.IntegrityError` for unique-key or foreign-key failures\n- `pymysql.err.ProgrammingError` for malformed SQL or placeholder mistakes\n\nPattern:\n\n```python\nimport pymysql\n\ntry:\n    with connection.cursor() as cursor:\n        cursor.execute(\"SELECT * FROM users WHERE id=%s\", (user_id,))\nexcept pymysql.err.IntegrityError:\n    connection.rollback()\n    raise\nexcept pymysql.MySQLError:\n    connection.rollback()\n    raise\n```\n\n## Common Pitfalls\n\n- Forgetting `commit()` after `INSERT`, `UPDATE`, `DELETE`, or DDL when `autocommit=False`\n- Using string interpolation instead of DB-API placeholders\n- Assuming `?` placeholders work; PyMySQL uses `%s` and `%(name)s`\n- Omitting `charset=\"utf8mb4\"` and then hitting Unicode or emoji issues\n- Leaving `read_timeout` and `write_timeout` unset for long-lived production connections\n- Using `SSCursor.fetchall()` for very large query results and defeating the point of streaming\n- Enabling `local_infile=True` without understanding the security implications\n- Relying on `db=` or `passwd=` in new code even though they are deprecated aliases\n\n## Version-Sensitive Notes For 1.1.2\n\n- PyPI shows `PyMySQL 1.1.2` released on August 24, 2025.\n- The official docs site still uses old `0.7.2` page titles and older requirement text, so do not treat those titles as the package version.\n- PyPI package metadata for `1.1.2` says `Requires-Python >=3.8`.\n- The current upstream README text published on PyPI says CPython `3.9 and newer` and latest PyPy 3.x. Treat this as an upstream documentation mismatch and verify against your deployment target if you are pinned to Python 3.8.\n- The GitHub `v1.1.2` release notes include Python 3.13 support work and MySQL 8.4 compatibility-related changes, so prefer `1.1.2` over older `1.1.0` or `1.1.1` examples when debugging modern runtime behavior.\n\n## Official Sources Used For This Guide\n\n- PyPI release page: `https://pypi.org/project/PyMySQL/1.1.2/`\n- Docs root: `https://pymysql.readthedocs.io/en/latest/`\n- Installation guide: `https://pymysql.readthedocs.io/en/latest/user/installation.html`\n- Examples: `https://pymysql.readthedocs.io/en/latest/user/examples.html`\n- Connection API reference: `https://pymysql.readthedocs.io/en/latest/modules/connections.html`\n- Cursor API reference: `https://pymysql.readthedocs.io/en/latest/modules/cursors.html`\n- GitHub releases: `https://github.com/PyMySQL/PyMySQL/releases`\n"
  },
  {
    "path": "content/pynacl/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyNaCl package guide for Python projects using the official PyNaCl 1.6.2 APIs for signing, encryption, and password hashing\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.6.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pynacl,python,cryptography,libsodium,signing,encryption,password-hashing\"\n---\n\n# PyNaCl Python Package Guide\n\n## Install\n\nPyNaCl `1.6.2` requires Python `>=3.8`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pynacl==1.6.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pynacl==1.6.2\"\npoetry add \"pynacl==1.6.2\"\n```\n\nPyNaCl ships binary wheels for common macOS, Windows, and Linux environments. If you need to build from source against your system `libsodium`, set `SODIUM_INSTALL=system` during install:\n\n```bash\nSODIUM_INSTALL=system python -m pip install \"pynacl==1.6.2\"\n```\n\nUseful source-build environment variables from the maintainer install docs:\n\n```bash\nLIBSODIUM_MAKE_ARGS=-j4 python -m pip install \"pynacl==1.6.2\"\nMAKE=gmake python -m pip install \"pynacl==1.6.2\"\n```\n\n## Runtime Basics\n\nPyNaCl is a local cryptography library. There is no service account, API key, or runtime authentication step.\n\n- Use `bytes` for messages, passwords, salts, keys, and associated data.\n- Use `nacl.encoding.HexEncoder` or another encoder when you need to store keys as text.\n- Let PyNaCl generate nonces unless you have a strict interoperability requirement.\n\n```python\nfrom nacl import encoding, exceptions, pwhash, utils\nfrom nacl.public import Box, PrivateKey, SealedBox\nfrom nacl.secret import Aead, SecretBox\nfrom nacl.signing import SigningKey, VerifyKey\n\nmessage = \"hello\".encode(\"utf-8\")\n```\n\n## Choose The Right Primitive\n\n- `SigningKey` and `VerifyKey`: sign data with Ed25519 and verify tampering.\n- `SecretBox`: encrypt with a shared 32-byte secret key.\n- `Aead`: encrypt with a shared 32-byte secret key and authenticate extra metadata with `aad`.\n- `Box`: encrypt between two Curve25519 keypairs.\n- `SealedBox`: encrypt to a recipient public key when the sender should not be able to decrypt later.\n- `pwhash`: store password hashes or derive a key from a password.\n\n## Generate And Serialize Keys\n\nUse `generate()` for new keys and `encode()` for storage. Rebuild the key object with the same encoder when loading it back.\n\n```python\nfrom nacl.encoding import HexEncoder\nfrom nacl.signing import SigningKey, VerifyKey\n\nsigning_key = SigningKey.generate()\nverify_key = signing_key.verify_key\n\nsigning_key_hex = signing_key.encode(encoder=HexEncoder).decode(\"ascii\")\nverify_key_hex = verify_key.encode(encoder=HexEncoder).decode(\"ascii\")\n\nloaded_signing_key = SigningKey(signing_key_hex.encode(\"ascii\"), encoder=HexEncoder)\nloaded_verify_key = VerifyKey(verify_key_hex.encode(\"ascii\"), encoder=HexEncoder)\n```\n\nFor public-key encryption, generate a `PrivateKey` and keep its `public_key` for peers:\n\n```python\nfrom nacl.public import PrivateKey\n\nprivate_key = PrivateKey.generate()\npublic_key = private_key.public_key\n```\n\n## Sign And Verify Messages\n\n`SigningKey.sign()` returns a `SignedMessage` that contains the combined signed payload plus `.signature` and `.message` helpers.\n\n```python\nfrom nacl import exceptions\nfrom nacl.signing import SigningKey\n\nsigning_key = SigningKey.generate()\nverify_key = signing_key.verify_key\n\nmessage = b\"important payload\"\nsigned = signing_key.sign(message)\n\nassert signed.message == message\nassert verify_key.verify(signed) == message\nassert verify_key.verify(message, signed.signature) == message\n\ntry:\n    verify_key.verify(message, b\"\\x00\" * len(signed.signature))\nexcept exceptions.BadSignatureError:\n    print(\"signature check failed\")\n```\n\n## Encrypt With A Shared Secret\n\nUse `SecretBox` when both sides already share the same secret key.\n\n```python\nfrom nacl import utils\nfrom nacl.secret import SecretBox\n\nkey = utils.random(SecretBox.KEY_SIZE)\nbox = SecretBox(key)\n\nmessage = b\"encrypt this\"\nencrypted = box.encrypt(message)\n\nprint(encrypted.nonce)\nprint(encrypted.ciphertext)\n\nplaintext = box.decrypt(encrypted)\nassert plaintext == message\n```\n\n`SecretBox.encrypt()` prepends the nonce to the returned value, so `box.decrypt(encrypted)` works without passing the nonce separately.\n\n## Encrypt With Associated Data\n\nUse `Aead` when you need to authenticate extra unencrypted metadata, such as a record ID or protocol header.\n\n```python\nfrom nacl import utils\nfrom nacl.secret import Aead\n\nkey = utils.random(Aead.KEY_SIZE)\nbox = Aead(key)\n\nmessage = b\"ciphertext body\"\naad = b\"order:1234\"\n\nencrypted = box.encrypt(message, aad=aad)\nplaintext = box.decrypt(encrypted, aad=aad)\n\nassert plaintext == message\n```\n\nThe same `aad` must be supplied on decrypt or PyNaCl raises `nacl.exceptions.CryptoError`.\n\n## Encrypt Between Peers\n\nUse `Box` when both peers have long-lived keypairs.\n\n```python\nfrom nacl.public import Box, PrivateKey\n\nalice_private = PrivateKey.generate()\nbob_private = PrivateKey.generate()\n\nalice_box = Box(alice_private, bob_private.public_key)\nbob_box = Box(bob_private, alice_private.public_key)\n\nciphertext = alice_box.encrypt(b\"hello bob\")\nplaintext = bob_box.decrypt(ciphertext)\n\nassert plaintext == b\"hello bob\"\n```\n\nUse `SealedBox` for one-way encryption to a recipient public key:\n\n```python\nfrom nacl.public import PrivateKey, SealedBox\n\nrecipient_private = PrivateKey.generate()\nrecipient_public = recipient_private.public_key\n\nsender_box = SealedBox(recipient_public)\nrecipient_box = SealedBox(recipient_private)\n\nsealed = sender_box.encrypt(b\"hello\")\nplaintext = recipient_box.decrypt(sealed)\n\nassert plaintext == b\"hello\"\n```\n\n`SealedBox(recipient_public)` can encrypt only. To decrypt, build the `SealedBox` with the recipient `PrivateKey`.\n\n## Password Hashing And Key Derivation\n\nUse `pwhash.str()` to store a password hash. Use `pwhash.verify()` to check a candidate password.\n\n```python\nfrom nacl import pwhash\n\npassword = b\"correct horse battery staple\"\n\npassword_hash = pwhash.str(password)\nassert pwhash.verify(password_hash, password) is True\n```\n\nWhen you need a fixed-size key from a password, use `nacl.pwhash.argon2id.kdf()` with a random salt:\n\n```python\nfrom nacl import utils\nfrom nacl.pwhash import argon2id\n\npassword = b\"correct horse battery staple\"\nsalt = utils.random(argon2id.SALTBYTES)\n\nkey = argon2id.kdf(\n    size=32,\n    password=password,\n    salt=salt,\n    opslimit=argon2id.OPSLIMIT_MODERATE,\n    memlimit=argon2id.MEMLIMIT_MODERATE,\n)\n```\n\n## Common Pitfalls\n\n- Do not pass Python `str` objects directly; encode to `bytes` first.\n- Do not reuse a nonce with the same key for `SecretBox`, `Aead`, or `Box` if you supply nonces manually.\n- Catch `nacl.exceptions.BadSignatureError` for invalid signatures and `nacl.exceptions.CryptoError` for failed decrypt/auth checks.\n- Keep `SigningKey` seeds, `PrivateKey` values, and symmetric keys secret; they are raw key material, not opaque handles.\n- `SecretBox` and `Aead` both use 32-byte keys, but only `Aead` accepts `aad`.\n- Serialize keys with an explicit encoder such as `HexEncoder`; re-create the object with the same encoder on load.\n\n## Version Notes For 1.6.2\n\n- PyPI metadata for `1.6.2` declares `Requires-Python: >=3.8`.\n- The package metadata publishes a docs extra with Sphinx dependencies and keeps the canonical documentation at `https://pynacl.readthedocs.io`.\n- This guide targets the `1.6.2` API surface exposed by the `nacl` package modules in that release.\n"
  },
  {
    "path": "content/pyo3-pack/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Legacy pyo3-pack guide for building and publishing PyO3-based Python packages\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyo3-pack,pyo3,rust,python,packaging,wheels\"\n---\n\n# pyo3-pack Python Package Guide\n\n## Golden Rule\n\nUse `pyo3-pack` when you are maintaining an older PyO3 packaging flow already pinned to `pyo3-pack==0.6.1`. Keep the Python interpreter explicit, build inside a virtual environment, and treat `develop`, `build`, and `publish` as the core workflow.\n\nCurrent PyO3 documentation focuses on `maturin`, the successor in the same tool lineage. For a project that is already pinned to `pyo3-pack`, keep the legacy CLI and project layout consistent instead of mixing in newer packaging conventions ad hoc.\n\n## Install And Prerequisites\n\n`pyo3-pack` shells out to Cargo and builds a native Python extension, so you need:\n\n- a working Rust toolchain\n- a Python interpreter you want to build against\n- an activated virtual environment for local development installs\n\nInstall the tool and set up an isolated environment:\n\n```bash\nrustup default stable\n\npython3 -m venv .venv\nsource .venv/bin/activate\n\npython -m pip install --upgrade pip\npython -m pip install \"pyo3-pack==0.6.1\"\n```\n\nIf you have more than one Python installed, point PyO3 at the exact interpreter you want to target:\n\n```bash\nexport PYO3_PYTHON=\"$(which python)\"\n```\n\nThat environment variable is the safest way to avoid building against the wrong interpreter or ABI.\n\n## Prepare An Existing PyO3 Crate\n\n`pyo3-pack` expects a Rust crate that is configured as a Python extension module.\n\nAt minimum, your crate must build a shared library:\n\n```toml\n[lib]\nname = \"my_package\"\ncrate-type = [\"cdylib\"]\n```\n\nYour `pyo3` dependency also needs the `extension-module` feature enabled. The import name Python sees must match the module name your Rust crate exports.\n\nFor projects that use a package directory alongside the compiled extension, keep the Python package name and native module name aligned so `import my_package` resolves the expected extension module.\n\n## Local Development\n\nUse `develop` for the edit-build-import loop. It compiles the extension and installs it into the currently active virtual environment.\n\n```bash\nsource .venv/bin/activate\nexport PYO3_PYTHON=\"$(which python)\"\n\npyo3-pack develop\n```\n\nThen import the built module with the same interpreter:\n\n```bash\npython -c \"import my_package; print(my_package.__doc__)\"\n```\n\nRe-run `pyo3-pack develop` after changing Rust code.\n\n## Build Distribution Artifacts\n\nUse `build` when you want wheels for installation or release automation:\n\n```bash\nsource .venv/bin/activate\nexport PYO3_PYTHON=\"$(which python)\"\n\npyo3-pack build --release\n```\n\nThis is the command to use in CI when you want a reproducible release build instead of a development install.\n\nOn Linux, wheel compatibility depends on the manylinux policy you build against. If you are publishing to PyPI, choose the CLI's `--manylinux` setting deliberately for your target environment instead of relying on whatever your host system happens to produce.\n\n## Publish To PyPI\n\nWhen the wheel is ready, upload with `publish`:\n\n```bash\npyo3-pack publish --release\n```\n\nKeep PyPI credentials or tokens in your shell environment or CI secret store, not in source control. Prefer token-based publishing over a password-based workflow when your release process supports it.\n\n## Interpreter Selection And Build Behavior\n\nTwo details matter most when `pyo3-pack` appears to build the wrong thing:\n\n- `PYO3_PYTHON` controls which interpreter PyO3 uses to discover headers, ABI details, and linker settings\n- the active virtual environment controls where `pyo3-pack develop` installs the compiled module\n\nIf your machine has multiple Python versions, make both explicit before every build:\n\n```bash\nsource .venv/bin/activate\nexport PYO3_PYTHON=\"$(which python)\"\npyo3-pack develop\n```\n\nThat avoids the common mismatch where Cargo succeeds but the module cannot be imported from the interpreter you actually run.\n\n## Common Pitfalls\n\n- Missing `crate-type = [\"cdylib\"]` prevents a usable extension module from being produced.\n- Missing PyO3 `extension-module` support causes linker or import-time failures for extension builds.\n- Running `pyo3-pack develop` outside the intended virtual environment installs the module for the wrong interpreter.\n- On Linux, wheel portability is a packaging decision, not just a build command. Check your manylinux target before uploading.\n- Newer PyO3 guides often describe the same workflow with `maturin`. For a project pinned to `pyo3-pack 0.6.1`, verify configuration changes before copying modern examples into the repo.\n"
  },
  {
    "path": "content/pyparsing/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pyparsing parser-combinator library for building PEG-style text parsers in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.3.2\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyparsing,python,parsing,peg,text-processing,parser-combinators\"\n---\n\n# pyparsing Python Package Guide\n\n## What It Is\n\n`pyparsing` is a parser-combinator library for building PEG-style grammars directly in Python code. It is a good fit for DSLs, config files, query languages, structured logs, and other cases where regular expressions become hard to maintain.\n\nFor `3.3.2`, write new code with the snake_case 3.x API: `parse_string`, `set_name`, `set_parse_action`, `DelimitedList`, `one_of`, and `using_each`. Legacy camelCase aliases still exist for compatibility in the 3.x line, but upstream documents them as deprecated and planned for removal in a future 4.0 release.\n\n## Installation\n\n```bash\npip install pyparsing==3.3.2\n```\n\nCommon alternatives:\n\n```bash\npoetry add pyparsing==3.3.2\nuv add pyparsing==3.3.2\n```\n\nInstall railroad-diagram support if you need `create_diagram()` output:\n\n```bash\npip install \"pyparsing[diagrams]==3.3.2\"\n```\n\n## Initialize And Set Up\n\nThere is no auth, network, or service configuration. The important setup choices are grammar style and parser behavior.\n\n```python\nimport pyparsing as pp\n\n# Upstream AI guidance recommends short namespaces for common helpers.\nppc = pp.common\n\n# Optional: enable memoization for complex grammars with repeated backtracking.\n# Call immediately after import if you decide to use it.\n# pp.ParserElement.enable_packrat()\n\n# Optional: enable bounded left recursion for genuinely left-recursive grammars.\n# Do not combine with packrat.\n# pp.ParserElement.enable_left_recursion()\n```\n\nUseful defaults for coding agents:\n\n- Import as `pp`, and use `ppc = pp.common` when you need prebuilt numeric or date helpers.\n- Use `parse_string(..., parse_all=True)` unless you intentionally want partial matches.\n- Give important fields results names so parsed values are accessible as attributes or mapping keys.\n- For nontrivial grammars, `pp.show_best_practices()` and `python -m pyparsing.ai.show_best_practices` expose upstream guidance aimed at parser authoring and testing.\n\n## Core Usage\n\n### Strict key-value parsing\n\n```python\nimport pyparsing as pp\n\nppc = pp.common\n\nidentifier = pp.Word(pp.identchars, pp.identbodychars)\nassignment = (\n    identifier(\"name\")\n    + pp.Suppress(\"=\")\n    + ppc.integer(\"value\")\n)\n\nresult = assignment.parse_string(\"count=3\", parse_all=True)\n\nprint(result.name)       # count\nprint(result[\"value\"])   # 3\nprint(result.as_dict())  # {'name': 'count', 'value': 3}\n```\n\nWhy this is a solid default:\n\n- String literals such as `\"=\"` are auto-converted to parser elements.\n- `Suppress(...)` keeps punctuation out of the returned `ParseResults`.\n- `pp.common.integer` converts the token to `int` for you.\n- `parse_all=True` prevents silent trailing garbage.\n\n### Delimited values and quoted strings\n\n```python\nimport pyparsing as pp\n\nidentifier = pp.Word(pp.identchars, pp.identbodychars)\nvalue = pp.common.number | pp.QuotedString('\"')\n\npair = pp.Group(\n    identifier(\"key\")\n    + pp.Suppress(\"=\")\n    + value(\"value\")\n)\n\nconfig = pp.DelimitedList(pair, delim=\",\")\n\nfor item in config.parse_string('count=3, threshold=2.5, label=\"ok\"', parse_all=True):\n    print(item.key, item.value)\n```\n\nReach for these building blocks first:\n\n- `Word`, `Literal`, `Keyword`, `CaselessKeyword`\n- `QuotedString`, `Regex`, `CharsNotIn`\n- `Optional`, `ZeroOrMore`, `OneOrMore`, `DelimitedList`\n- `Group`, `Dict`, `Suppress`, `Combine`\n- `Forward` for recursive grammars\n- `one_of(...)` and `infix_notation(...)` for token sets and expression grammars\n- `pp.common` for numeric/date helpers with parse actions already attached\n\n### Search, scan, and transform\n\n```python\nimport pyparsing as pp\n\ninteger = pp.common.integer\n\nprint(integer.search_string(\"x=1 y=20 z=300\").as_list())\n\ntitle_case_word = pp.Word(pp.alphas)\ntitle_case_word.set_parse_action(lambda toks: toks[0].title())\nprint(title_case_word.transform_string(\"now is the winter of our discontent\"))\n```\n\nUse the right entry point:\n\n- `parse_string(...)` for full structured inputs\n- `parse_file(...)` for file contents\n- `search_string(...)` to find repeated matches anywhere in larger text\n- `scan_string(...)` when you also need start/end offsets\n- `transform_string(...)` when parse actions should rewrite matched text\n\n## Configuration And Global Behavior\n\n### Whitespace\n\nBy default, pyparsing skips spaces, tabs, newlines, and carriage returns between tokens.\n\n```python\nimport pyparsing as pp\n\npp.ParserElement.set_default_whitespace_chars(\" \\t\")\n```\n\nThat makes newlines significant. Reset to the default when you are done:\n\n```python\npp.ParserElement.set_default_whitespace_chars(\" \\n\\t\\r\")\n```\n\nFor one expression instead of the whole process:\n\n```python\ntoken = pp.Word(pp.printables).leave_whitespace()\n```\n\n### Comments and ignored text\n\n```python\nimport pyparsing as pp\n\nexpr = pp.Word(pp.alphas)[...].ignore(pp.c_style_comment)\n```\n\n`.ignore(...)` can be called repeatedly if your grammar needs to skip multiple comment styles.\n\n### Inline literals\n\nIf your grammar has lots of separators, you can globally auto-suppress string literals:\n\n```python\nimport pyparsing as pp\n\npp.ParserElement.inline_literals_using(pp.Suppress)\n\n# ... build grammar ...\n\npp.ParserElement.inline_literals_using(pp.Literal)\n```\n\nThis is process-wide state. Use it deliberately, especially in tests or shared libraries.\n\n### Packrat vs left recursion\n\n- `pp.ParserElement.enable_packrat()` adds memoization and can speed up complex grammars.\n- `pp.ParserElement.enable_left_recursion()` enables bounded left recursion for left-recursive `Forward` grammars.\n- Upstream documents these modes as incompatible with each other.\n- Both memoization modes can skip repeated parse-action execution during backtracking, so do not depend on parse actions with order-sensitive side effects.\n\n## Testing And Debugging\n\n`run_tests()` is the fastest way to iterate on a small grammar:\n\n```python\nimport pyparsing as pp\n\nnumber = pp.common.number\nnumber.run_tests(\n    \"\"\"\n    100\n    -3.5\n    6.02e23\n    \"\"\"\n)\n```\n\nAlso useful:\n\n- `set_name(\"...\")` to improve parse errors\n- `set_debug()` when you need to trace parser behavior\n- `matches(text)` for quick boolean checks on a subexpression\n- `result.dump()` while shaping `ParseResults`\n- `create_diagram(...)` if you installed `pyparsing[diagrams]`\n\n## Common Pitfalls\n\n### Partial matches are allowed by default\n\n`parse_string(\"count=3 trailing\")` succeeds unless you pass `parse_all=True` or explicitly end the grammar with `StringEnd()`.\n\n### Old examples use deprecated names\n\nLegacy forms such as `parseString`, `setResultsName`, `delimitedList`, `enablePackrat`, and `leaveWhitespace` still appear in older blog posts and in pre-3.x code. Prefer snake_case APIs and `DelimitedList` in new code.\n\n### `Forward` definitions are easy to get wrong\n\nUse `<<=` for recursive assignment:\n\n```python\nexpr = pp.Forward()\nexpr <<= ...\n```\n\nDo not replace the `Forward` with `expr = ...` after creating it, and be careful with operator precedence when combining `<<` or `<<=` with alternation.\n\n### Tabs can break location-sensitive parse actions\n\n`parse_string()` expands tabs before parsing so reported columns are accurate. If a parse action uses `loc` to index into the input string, either call `parse_with_tabs()` before parsing, use the full `(s, loc, toks)` signature, or expand tabs yourself first.\n\n### Global settings leak across a process\n\n`set_default_whitespace_chars(...)` and `inline_literals_using(...)` are global. They are convenient in standalone parsers but risky in shared libraries, test suites, or long-lived agent processes unless you isolate or reset them.\n\n### Parse actions should not do fragile side effects\n\nMemoization, backtracking, and left-recursion support can change when often parse actions are re-executed. Prefer pure parse actions that convert or annotate tokens rather than mutate global state, append to shared lists, or trigger I/O.\n\n## Version-Sensitive Notes For 3.3.2\n\n- PyPI lists `3.3.2` as the latest release, published on January 21, 2026.\n- PyPI metadata says `pyparsing` requires Python `>=3.9` and publishes classifiers through Python `3.14`.\n- The docs URL is still the right canonical docs root, but it currently serves a docs build labeled `PyParsing 3.3.0`, not `3.3.2`.\n- The long-form \"Using the pyparsing module\" guide embedded in that docs site still shows its own internal revision as `3.2.0`. Treat that guide as conceptual guidance and check the API reference page for current names and signatures.\n- The 3.x docs still document camelCase compatibility aliases, but upstream marks them as deprecated and slated for removal in a future 4.0 release. New code should use snake_case names only.\n- Helpers you are likely to rely on in modern code, such as `DelimitedList`, `using_each`, and `show_best_practices`, are documented as additions from the 3.1 line and are available in `3.3.2`.\n- If you need Python 3.8 or earlier, the upstream 3.2.x notes direct users to the `3.1` line for earlier Python 3 and to `2.4.7` for Python 2.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/pyparsing/\n- PyPI release history: https://pypi.org/project/pyparsing/#history\n- Docs root: https://pyparsing-docs.readthedocs.io/en/latest/\n- How-to guide: https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html\n- API reference: https://pyparsing-docs.readthedocs.io/en/latest/pyparsing.html\n- What changed in 3.2.x: https://pyparsing-docs.readthedocs.io/en/latest/whats_new_in_3_2.html\n- Source repository: https://github.com/pyparsing/pyparsing\n- Releases page: https://github.com/pyparsing/pyparsing/releases\n"
  },
  {
    "path": "content/pyproj/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pyproj Python package for CRS parsing, coordinate transformations, geodesic calculations, and PROJ data management\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.7.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyproj,proj,gis,geospatial,crs,coordinate-transformations,geodesic\"\n---\n\n# pyproj Python Package Guide\n\n## Golden Rule\n\nUse `pyproj` through `CRS`, `Transformer`, and `Geod`, not through legacy `Proj` or deprecated `transform()` helpers. For coordinate transforms, decide axis order explicitly with `always_xy=True` when your inputs are longitude/latitude, and treat grid availability as part of your runtime configuration.\n\n## Install\n\nFor most Python projects, use the wheel from PyPI:\n\n```bash\npython -m pip install \"pyproj==3.7.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pyproj==3.7.2\"\npoetry add \"pyproj==3.7.2\"\n```\n\nIf you are using conda, prefer `conda-forge` and avoid mixing `pip install` into that environment unless you understand the consequences:\n\n```bash\nconda config --prepend channels conda-forge\nconda config --set channel_priority strict\nconda create -n geo pyproj\nconda activate geo\n```\n\nSource-build notes:\n\n- Current stable docs say the minimum supported PROJ version is `9.4`\n- Building from source requires a working PROJ installation\n- The installation docs describe `PROJ_DIR`, `PROJ_LIBDIR`, and `PROJ_INCDIR` for source builds\n\n## Core Workflow\n\n### 1. Parse and inspect CRS objects\n\nUse EPSG codes or WKT where possible. The official gotchas page recommends WKT or SRIDs such as EPSG codes over PROJ strings, and prefers WKT2 over WKT1.\n\n```python\nfrom pyproj import CRS\n\nwgs84 = CRS.from_epsg(4326)\nweb_mercator = CRS.from_epsg(3857)\n\nprint(wgs84)\nprint(web_mercator.to_epsg())\nprint(web_mercator.to_wkt())\n```\n\nPractical rule:\n\n- Prefer `CRS.from_epsg(...)` for standard systems\n- Prefer `crs.to_wkt()` when you need a durable serialized CRS form\n- Avoid storing CRS definitions only as PROJ strings when long-term fidelity matters\n\n### 2. Reuse a `Transformer` for coordinate transforms\n\n`Transformer` is the main API for repeated transforms and datum-aware conversions.\n\n```python\nfrom pyproj import Transformer\n\ntransformer = Transformer.from_crs(\n    \"EPSG:4326\",\n    \"EPSG:3857\",\n    always_xy=True,\n)\n\nx, y = transformer.transform(-122.4194, 37.7749)\nprint(x, y)\n```\n\nWhy `always_xy=True` matters:\n\n- EPSG axis order can be latitude/longitude for geographic CRS definitions\n- Many application inputs are longitude/latitude\n- `always_xy=True` forces x/y order so callers can consistently pass `lon, lat`\n\nWhen you need to inspect the chosen operation:\n\n```python\nfrom pyproj import Transformer\n\ntransformer = Transformer.from_crs(\"EPSG:4326\", \"EPSG:26917\", always_xy=True)\n\nprint(transformer.description)\nprint(transformer.accuracy)\nprint(transformer.area_of_use)\n```\n\n### 3. Choose a local UTM CRS from coordinates\n\nThis is often safer than hard-coding a projected CRS for ad hoc point data.\n\n```python\nfrom pyproj import CRS\nfrom pyproj.aoi import AreaOfInterest\nfrom pyproj.database import query_utm_crs_info\n\nutm_candidates = query_utm_crs_info(\n    datum_name=\"WGS 84\",\n    area_of_interest=AreaOfInterest(\n        west_lon_degree=-93.581543,\n        south_lat_degree=42.032974,\n        east_lon_degree=-93.581543,\n        north_lat_degree=42.032974,\n    ),\n)\n\nutm_crs = CRS.from_epsg(utm_candidates[0].code)\nprint(utm_crs)\n```\n\n### 4. Compute geodesic distances, bearings, and destinations\n\nUse `Geod` for accurate work on the ellipsoid. Do not project to Web Mercator and treat planar distance as geodesic distance.\n\n```python\nfrom pyproj import Geod\n\ngeod = Geod(ellps=\"WGS84\")\n\naz12, az21, distance_m = geod.inv(\n    -71.1167, 42.25,\n    -123.6833, 45.5167,\n)\n\nend_lon, end_lat, back_azimuth = geod.fwd(\n    -71.1167, 42.25,\n    az12,\n    distance_m,\n)\n\nprint(distance_m)\nprint(end_lon, end_lat, back_azimuth)\n```\n\nFor polygon measurements without projecting first:\n\n```python\nfrom pyproj import Geod\n\ngeod = Geod(ellps=\"WGS84\")\n\nlons = [-74, -102, -102, -131, -163, 163, 172, 140]\nlats = [-72.9, -71.9, -74.9, -74.3, -77.5, -77.4, -71.7, -65.9]\n\narea_m2, perimeter_m = geod.polygon_area_perimeter(lons, lats)\nprint(area_m2, perimeter_m)\n```\n\nIf your project already uses Shapely, `Geod.geometry_length()` and `Geod.geometry_area_perimeter()` are available for geometry objects.\n\n## Configuration And PROJ Data\n\n### Data directory resolution\n\n`pyproj` resolves its PROJ data directory in this order:\n\n1. A path set with `pyproj.datadir.set_data_dir(...)`\n2. The internal PROJ directory, if present\n3. `PROJ_DATA` for PROJ 9.1+ or `PROJ_LIB` for older PROJ\n4. `sys.prefix`\n5. The system `PATH`\n\nBasic inspection and override:\n\n```python\nfrom pyproj import datadir\n\nprint(datadir.get_data_dir())\ndatadir.set_data_dir(\"/opt/proj/share/proj\")\n```\n\n### Grid downloads and network access\n\nImportant upstream rule: `pyproj 3` wheels do **not** include transformation grids.\n\nImplications:\n\n- If you only use `CRS` or `Geod`, you usually do not need grids\n- Datum transformations may need grids for best accuracy\n- Missing grids can change which transform PROJ selects or make the best transform unavailable\n\nEnable PROJ network access when on-demand grid fetching is acceptable:\n\n```python\nfrom pyproj import network\n\nnetwork.set_network_enabled(True)\nprint(network.is_network_enabled())\n```\n\nThis has the same behavior as the `PROJ_NETWORK` environment variable.\n\nIf you need to preflight or pre-download candidate grids:\n\n```python\nfrom pyproj.sync import get_transform_grid_list\n\ngrids = get_transform_grid_list(\n    source_id=\"us_noaa\",\n    include_already_downloaded=False,\n)\n\nprint(len(grids))\n```\n\nFor offline or controlled environments:\n\n- Mirror or pre-download the grid files into the PROJ data directory\n- Keep `PROJ_NETWORK=OFF` if the runtime must not fetch remote assets\n- Use `pyproj.show_versions()` when debugging mismatched PROJ data, wheel, and runtime environments\n\n```bash\npython -c \"import pyproj; pyproj.show_versions()\"\n```\n\n## Common Pitfalls\n\n- Do not use `Proj` as a generic latitude/longitude to projected-coordinate converter across datums. The official gotchas page recommends `Transformer` for that job.\n- Do not use `+init=EPSG:xxxx` or similar `+init=` syntax. It is deprecated and can fail even when `EPSG:xxxx` works.\n- Do not assume axis order is always `lon, lat`. If your caller works in x/y order, pass `always_xy=True` when creating the transformer.\n- Do not assume PyPI wheels include datum grids. They do not.\n- Do not treat PROJ strings as the best long-term CRS storage format. Prefer EPSG codes or WKT, especially WKT2.\n- Do not ignore `SQLite error on SELECT` messages from PROJ. The upstream gotchas page says they usually indicate mixed PROJ versions or an incompatible data directory.\n- Do not keep using `pyproj.transformer.transform()` or `itransform()` from old examples. The gotchas page marks them as deprecated in favor of `Transformer`.\n\n## Version-Sensitive Notes For 3.7.2\n\n- As of March 12, 2026, the version used here, PyPI latest version, and stable docs version all align on `3.7.2`.\n- The stable docs root for `3.7.2` states the minimum supported Python version is `3.11` and the minimum supported PROJ version is `9.4`.\n- `pyproj.set_use_global_context()` is deprecated since `3.7.0` because pyproj now uses one context per thread. Avoid adding new code that depends on the old global-context toggle.\n- If you are copying older blog posts, watch for pre-`Transformer` examples, `Proj(init=\"epsg:...\")`, or manual axis-order assumptions. Those patterns are stale for modern pyproj.\n\n## Official Sources\n\n- Stable docs: https://pyproj4.github.io/pyproj/stable/\n- Installation: https://pyproj4.github.io/pyproj/stable/installation.html\n- Getting started examples: https://pyproj4.github.io/pyproj/stable/examples.html\n- Gotchas/FAQ: https://pyproj4.github.io/pyproj/stable/gotchas.html\n- Transformation grids: https://pyproj4.github.io/pyproj/stable/transformation_grids.html\n- Data directory API: https://pyproj4.github.io/pyproj/stable/api/datadir.html\n- PROJ network API: https://pyproj4.github.io/pyproj/stable/api/network.html\n- Sync API: https://pyproj4.github.io/pyproj/stable/api/sync.html\n- Global context API: https://pyproj4.github.io/pyproj/stable/api/global_context.html\n- Geod API: https://pyproj4.github.io/pyproj/stable/api/geod.html\n- Show versions API: https://pyproj4.github.io/pyproj/stable/api/show_versions.html\n- PyPI package page: https://pypi.org/project/pyproj/\n"
  },
  {
    "path": "content/pyramid/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pyramid package guide for Python WSGI web applications and services\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyramid,web,framework,wsgi,routing,python\"\n---\n\n# Pyramid Python Package Guide\n\n## What It Is\n\n`pyramid` is a Python web framework for WSGI applications. It favors explicit configuration: define routes, attach views, build a WSGI app, and add only the pieces you need for templates, sessions, security, and persistence.\n\n- Package name: `pyramid`\n- Import name: `pyramid`\n- Version covered: `2.1`\n- PyPI release date for `2.1`: `2026-03-11`\n- PyPI requirement for `2.1`: `Python >=3.10`\n\n## Installation\n\nInstall the framework version your project expects:\n\n```bash\npip install pyramid==2.1\n```\n\nCommon companion tools from the official tutorial and deployment flow are:\n\n```bash\npip install \"pyramid==2.1\" waitress cookiecutter\n```\n\n- `waitress`: production-ready WSGI server commonly used with Pyramid\n- `cookiecutter`: generates the official starter project now that `pcreate` is gone in `2.1`\n\nBasic imports:\n\n```python\nfrom pyramid.config import Configurator\nfrom pyramid.response import Response\nfrom pyramid.view import view_config\n```\n\n## Initialization And Setup\n\n### Fastest Start: Official Starter\n\nPyramid `2.1` removed `pcreate`. Use the official Cookiecutter starter instead:\n\n```bash\ncookiecutter gh:Pylons/pyramid-cookiecutter-starter\ncd <your-project>\npython -m pip install -e \".[testing]\"\npserve development.ini --reload\n```\n\nThis gives you a working application factory, `development.ini` and `production.ini`, and a layout that matches the upstream tutorial and deployment flow.\n\n### Minimal App Without A Scaffold\n\nIf you just need a tiny app or test fixture, wire Pyramid directly:\n\n```python\nfrom wsgiref.simple_server import make_server\n\nfrom pyramid.config import Configurator\nfrom pyramid.response import Response\n\ndef hello_world(request):\n    return Response(\"Hello, Pyramid!\")\n\nif __name__ == \"__main__\":\n    config = Configurator()\n    config.add_route(\"hello\", \"/\")\n    config.add_view(hello_world, route_name=\"hello\")\n    app = config.make_wsgi_app()\n\n    server = make_server(\"127.0.0.1\", 6543, app)\n    server.serve_forever()\n```\n\nImportant setup points:\n\n- `Configurator` is where routes, views, renderers, security policy, session factory, and settings are registered.\n- `config.make_wsgi_app()` produces the WSGI app you serve with `waitress`, `gunicorn`, or another WSGI server.\n- If you use decorator-based configuration such as `@view_config`, call `config.scan()` before `make_wsgi_app()`.\n\n## Core Usage\n\n### Route A URL To A View\n\nImperative configuration is the most direct Pyramid style:\n\n```python\nfrom pyramid.config import Configurator\nfrom pyramid.response import Response\n\ndef healthcheck(request):\n    return Response(\"ok\")\n\nconfig = Configurator()\nconfig.add_route(\"healthcheck\", \"/healthz\")\nconfig.add_view(healthcheck, route_name=\"healthcheck\")\napp = config.make_wsgi_app()\n```\n\n### Use Decorator-Based Views\n\nIf you prefer to colocate routes and handlers, combine `@view_config` with `config.scan()`:\n\n```python\nfrom pyramid.config import Configurator\nfrom pyramid.view import view_config\n\n@view_config(route_name=\"api_status\", renderer=\"json\")\ndef api_status(request):\n    return {\"status\": \"ok\", \"path\": request.path}\n\nconfig = Configurator()\nconfig.add_route(\"api_status\", \"/api/status\")\nconfig.scan()\napp = config.make_wsgi_app()\n```\n\n### Read Settings\n\nApplication settings from your `.ini` file or explicit `settings={...}` are available via the registry:\n\n```python\nfrom pyramid.view import view_config\n\n@view_config(route_name=\"info\", renderer=\"json\")\ndef info(request):\n    settings = request.registry.settings\n    return {\"app_name\": settings.get(\"app.name\", \"example\")}\n```\n\n### Return JSON Or HTTP Responses\n\n- Return a `Response` when you want to control status, headers, or body directly.\n- Use `renderer=\"json\"` for ordinary JSON APIs and return plain Python objects.\n\n```python\nfrom pyramid.response import Response\nfrom pyramid.view import view_config\n\n@view_config(route_name=\"created\")\ndef created(request):\n    return Response(\"created\\n\", status=201)\n```\n\n## Sessions, Security, And CSRF\n\n### Sessions Are Opt-In\n\n```python\nimport os\n\nfrom pyramid.config import Configurator\nfrom pyramid.session import SignedCookieSessionFactory\n\nsession_secret = os.environ[\"PYRAMID_SESSION_SECRET\"]\n\nconfig = Configurator()\nconfig.set_session_factory(\n    SignedCookieSessionFactory(\n        session_secret,\n        secure=True,\n        httponly=True,\n        samesite=\"Lax\",\n    )\n)\n```\n\nPractical guidance:\n\n- Use a long random secret from environment or secret management, not a checked-in constant.\n- Keep `secure=True` in real deployments so session cookies only travel over HTTPS.\n- Set `httponly=True` and an explicit `samesite` value unless you have a specific cross-site requirement.\n- In `2.1`, `SignedCookieSessionFactory` now defaults to `hashalg=\"sha512\"`. If you are upgrading from older defaults, existing signed cookies can stop validating unless you set the same algorithm on both sides of the rollout.\n\n### Prefer Pyramid 2.x Security APIs\n\nFor Pyramid `2.1`, write view logic against the request-facing security API:\n\n- `request.identity`\n- `request.is_authenticated`\n- `request.has_permission(...)`\n\nExample guard in a view:\n\n```python\nfrom pyramid.httpexceptions import HTTPForbidden\nfrom pyramid.view import view_config\n\n@view_config(route_name=\"dashboard\", renderer=\"json\")\ndef dashboard(request):\n    if not request.is_authenticated:\n        raise HTTPForbidden()\n\n    return {\"authenticated\": True}\n```\n\nImportant notes:\n\n- Your application still needs a security policy implementation that supplies identities and permission checks.\n- New `2.x` code should not be based on the old split `authentication_policy` and `authorization_policy` style.\n\nDo not start new code from older examples that rely on:\n\n- `request.authenticated_userid`\n- `request.effective_principals`\n- separate `authentication_policy` and `authorization_policy` configuration\n- the `Unauthenticated` principal\n\nThose are part of the pre-2.0 security model and are deprecated or removed in the 2.x line.\n\n### Enable CSRF For Unsafe Methods\n\nIf your app accepts browser form posts or other cookie-authenticated write requests, enable CSRF protection:\n\n```python\nfrom pyramid.config import Configurator\nfrom pyramid.csrf import check_csrf_token\nfrom pyramid.view import view_config\n\nconfig = Configurator()\nconfig.set_default_csrf_options(require_csrf=True)\n\n@view_config(route_name=\"submit\", request_method=\"POST\", renderer=\"json\")\ndef submit(request):\n    check_csrf_token(request)\n    return {\"saved\": True}\n```\n\nIf you are building a JSON API that does not use browser cookies, do not cargo-cult CSRF checks into token-based machine-to-machine endpoints.\n\n## Running And Deployment\n\nFor scaffolded apps, the standard development entry point is:\n\n```bash\npserve development.ini --reload\n```\n\nFor a direct WSGI app object, `waitress` is a common deployment choice:\n\n```python\nfrom waitress import serve\n\nserve(app, listen=\"127.0.0.1:6543\")\n```\n\nPyramid is a WSGI framework. If the project expects native ASGI patterns, do not assume Pyramid code or middleware is interchangeable with FastAPI or Starlette examples.\n\n## Common Pitfalls\n\n### `pyramid` Is A Framework Core, Not A Full Stack Bundle\n\nThe base package gives you routing, views, requests, responses, configuration, sessions, and security hooks. Database integration, template engines, and authentication backends are typically added through separate packages or your own application code.\n\n### Decorated Views Need `config.scan()`\n\nIf you register views with `@view_config` and forget `config.scan()`, Pyramid will not find them.\n\n### Sessions And Authentication Do Nothing Until Configured\n\n### Old Blog Posts Often Show Pre-2.0 Security Code\n\nFor `2.1`, prefer the unified security-policy model and the request properties listed above.\n\n### `pcreate` Was Removed In 2.1\n\nIf you find old setup instructions that start with `pcreate`, they are stale for current `2.1` work. Use the Cookiecutter starter instead.\n\n### The Stable Docs URL Is Official But Not Version-Pinned\n\n`https://docs.pylonsproject.org/projects/pyramid/en/stable/` is a valid upstream landing page, but it will move as Pyramid releases advance. For version-sensitive behavior in this guide, use the `2.1-branch` pages listed below.\n\n### Session Cookies Can Break Across A 2.1 Upgrade\n\nThe default signed-cookie hash changed to `sha512` in `2.1`. If an existing deployment depends on the older implicit default, make the hash algorithm explicit during the upgrade rather than assuming old cookies remain valid.\n\n## Version-Sensitive Notes For 2.1\n\n- PyPI lists `Requires-Python: >=3.10` for `2.1`.\n- Pyramid `2.1` removed `pcreate`; scaffold new apps with the official Cookiecutter starter.\n- The default `hashalg` for `SignedCookieSessionFactory` is now `sha512`.\n- Pyramid `2.x` code should use `request.identity`, `request.is_authenticated`, and `request.has_permission(...)` instead of pre-2.0 request attributes and policy wiring patterns.\n\n## Official Sources\n\n- Stable docs landing page: https://docs.pylonsproject.org/projects/pyramid/en/stable/\n- Version-pinned docs root used for 2.1 behavior: https://docs.pylonsproject.org/projects/pyramid/en/2.1-branch/\n- Quick tutorial: https://docs.pylonsproject.org/projects/pyramid/en/2.1-branch/quick_tutorial.html\n- Sessions: https://docs.pylonsproject.org/projects/pyramid/en/2.1-branch/narr/sessions.html\n- Security: https://docs.pylonsproject.org/projects/pyramid/en/2.1-branch/narr/security.html\n- What changed in 2.1: https://docs.pylonsproject.org/projects/pyramid/en/2.1-branch/whatsnew-2.1.html\n- Official Cookiecutter starter: https://github.com/Pylons/pyramid-cookiecutter-starter\n- PyPI package page: https://pypi.org/project/pyramid/\n"
  },
  {
    "path": "content/pyright/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Pyright static type checker for Python projects, installed from PyPI and configured with pyrightconfig.json or pyproject.toml\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.408\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyright,python,typing,type-checking,static-analysis,linting\"\n---\n\n# Pyright Python Package Guide\n\n## Golden Rule\n\nUse `pyright` as a development tool, not a runtime dependency. Install the PyPI package that matches your project tooling, pin the version in CI, and keep the type-checker configuration in exactly one place that your team actually uses.\n\nFor Python packaging, the `pyright` package on PyPI is a wrapper that installs and runs Microsoft Pyright. The CLI and config behavior come from the upstream Pyright docs.\n\n## Install\n\nRecommended for most Python projects:\n\n```bash\npython -m pip install \"pyright[nodejs]==1.1.408\"\n```\n\nThat extra makes the wrapper manage a Node.js runtime for you. If your environment already provides Node.js and you want to use it, install without the extra:\n\n```bash\npython -m pip install \"pyright==1.1.408\"\n```\n\nCommon project-tool variants:\n\n```bash\nuv add --dev \"pyright[nodejs]==1.1.408\"\npoetry add --group dev \"pyright[nodejs]==1.1.408\"\n```\n\nVerify the actual engine version used in CI:\n\n```bash\npyright --version\n```\n\n## Initialize And Configure\n\nPyright reads `pyrightconfig.json` if present. It can also read `[tool.pyright]` from `pyproject.toml`. If both exist, `pyrightconfig.json` takes precedence.\n\nMinimal `pyproject.toml` setup:\n\n```toml\n[tool.pyright]\ninclude = [\"src\", \"tests\"]\npythonVersion = \"3.12\"\ntypeCheckingMode = \"standard\"\nvenvPath = \".\"\nvenv = \".venv\"\n```\n\nEquivalent `pyrightconfig.json`:\n\n```json\n{\n  \"include\": [\"src\", \"tests\"],\n  \"pythonVersion\": \"3.12\",\n  \"typeCheckingMode\": \"standard\",\n  \"venvPath\": \".\",\n  \"venv\": \".venv\"\n}\n```\n\nGood defaults for a typed package:\n\n- `typeCheckingMode = \"standard\"` for existing codebases, then tighten selectively.\n- Use `strict = [\"src/your_package\"]` or file-level `# pyright: strict` for new modules instead of flipping a large legacy repo to full strict mode at once.\n- Set `pythonVersion` to the lowest Python version you support, not whatever happens to be installed on one developer machine.\n- Use `stubPath = \"typings\"` only when you maintain custom stubs.\n\nExample with targeted strictness:\n\n```toml\n[tool.pyright]\ninclude = [\"src\", \"tests\"]\npythonVersion = \"3.12\"\ntypeCheckingMode = \"standard\"\nstrict = [\"src/my_package\"]\nreportMissingTypeStubs = false\n```\n\n## Core Usage\n\nRun against the whole project:\n\n```bash\npyright\n```\n\nCheck specific paths:\n\n```bash\npyright src tests\n```\n\nWatch mode for local development:\n\n```bash\npyright --watch\n```\n\nMachine-readable output for CI tooling:\n\n```bash\npyright --outputjson\n```\n\nIf you need to point Pyright at a specific interpreter for one-off checks, prefer `--pythonpath` over hard-coding virtualenv paths into shared config:\n\n```bash\npyright --pythonpath .venv/bin/python\n```\n\nUseful package-author commands:\n\n```bash\npyright --verifytypes my_package\npyright --createstub some_untyped_dependency\n```\n\n- `--verifytypes` checks whether a published package exposes a strong typed surface, especially around `py.typed`.\n- `--createstub` is a fallback for generating starter stubs for untyped dependencies.\n\n## Import Resolution And Environment Setup\n\nPyright resolves imports from the configured execution environment, installed packages, and local source roots. In practice, most false-positive import errors come from environment mismatch rather than from Pyright itself.\n\nRecommended patterns:\n\n- In editors, select the correct interpreter or virtualenv first.\n- In CI, install project dependencies before running Pyright.\n- For `src/` layouts, add `extraPaths = [\"src\"]` if your imports are not resolved the way you expect.\n- Use explicit execution environments when different folders target different Python versions or import roots.\n\nExample `src/` layout:\n\n```toml\n[tool.pyright]\ninclude = [\"src\", \"tests\"]\nextraPaths = [\"src\"]\nvenvPath = \".\"\nvenv = \".venv\"\n```\n\nEditable install caveat from the upstream docs: import hooks that rely on executable code in `.pth` files are not statically analyzable. If editable installs are required, prefer path-based `.pth` strategies marked as compatible or strict by the packaging backend.\n\n## CI And Pre-commit\n\nTypical CI command:\n\n```bash\npython -m pip install \"pyright[nodejs]==1.1.408\"\npyright --outputjson\n```\n\nMinimal `pre-commit` hook:\n\n```yaml\nrepos:\n  - repo: local\n    hooks:\n      - id: pyright\n        name: pyright\n        entry: pyright\n        language: system\n        types: [python]\n        pass_filenames: false\n```\n\nUse `pass_filenames: false` if your config depends on project-wide analysis. Passing only changed files can hide issues in dependent modules.\n\n## Wrapper-Specific Configuration\n\nThe PyPI wrapper has no auth or remote-service configuration. It only controls how the Pyright engine is installed and launched.\n\nUseful wrapper environment variables from the package README:\n\n- `PYRIGHT_PYTHON_FORCE_VERSION`: force a specific Pyright engine version or `latest`\n- `PYRIGHT_PYTHON_GLOBAL_NODE`: use a globally installed `node`\n- `PYRIGHT_PYTHON_NODE_VERSION`: choose the Node.js version managed by the wrapper\n- `PYRIGHT_PYTHON_CACHE_DIR`: customize where the wrapper caches downloads\n- `PYRIGHT_PYTHON_VERBOSE`: print wrapper-level debug output\n\nAvoid `PYRIGHT_PYTHON_FORCE_VERSION` in normal CI unless you deliberately want the wrapper to run a different engine than the pinned package version.\n\n## Common Pitfalls\n\n- Do not treat `pyright` as an importable runtime library. It is a CLI tool for static analysis.\n- Do not keep both `pyrightconfig.json` and `[tool.pyright]` unless you want the JSON file to win.\n- `reportMissingImports` usually means the interpreter, virtualenv, or installed dependencies are wrong, not that Pyright is broken.\n- `venvPath` and `venv` are convenient locally but brittle in shared configs if every developer names environments differently.\n- Editable installs that depend on import hooks can work at runtime and still fail static resolution in Pyright.\n- `useLibraryCodeForTypes` is not a substitute for proper typing metadata. Untyped libraries still benefit from stubs or `py.typed`.\n- Pyright is strict about control flow and `None` handling once you enable stricter modes. Many old blog posts assume looser defaults.\n\n## Version-Sensitive Notes For 1.1.408\n\n- As of 2026-03-12, the version used here `1.1.408` matches the live PyPI package version and the upstream GitHub release tag.\n- The Microsoft docs site tracks upstream Pyright behavior and can move ahead of whatever version your project has pinned, so verify with `pyright --version` before assuming a newly documented flag exists in your environment.\n- The wrapper can intentionally drift from the pinned package if you set `PYRIGHT_PYTHON_FORCE_VERSION` or related launcher variables. Avoid that unless you are debugging a version mismatch on purpose.\n- For VS Code, Microsoft recommends Pylance for the editor experience. Use the PyPI package when you need the CLI in Python tooling, CI, or pre-commit.\n"
  },
  {
    "path": "content/pyspark/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PySpark package guide for Python projects using Apache Spark 4.1.1\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pyspark,spark,dataframe,sql,etl,distributed-computing,big-data\"\n---\n\n# PySpark Python Package Guide\n\n## Golden Rule\n\nUse `pyspark` for Python access to Apache Spark, start from `SparkSession`, prefer DataFrame and Spark SQL APIs over low-level RDD code for new work, and keep the PySpark minor version aligned with the Spark runtime you connect to.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"pyspark==4.1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pyspark==4.1.1\"\npoetry add \"pyspark==4.1.1\"\n```\n\nUseful extras from the official install guide:\n\n```bash\npython -m pip install \"pyspark[sql]==4.1.1\"\npython -m pip install \"pyspark[pandas_on_spark]==4.1.1\" plotly\npython -m pip install \"pyspark[connect]==4.1.1\"\n```\n\nImportant install notes:\n\n- PySpark on PyPI is mainly for local development or as a client to an existing cluster, not for provisioning a Spark cluster by itself.\n- PySpark requires Java 17 or later and a valid `JAVA_HOME`.\n- The default pip distribution uses Hadoop 3.3 and Hive 2.3.\n- `PYSPARK_HADOOP_VERSION=3` is the default pip distribution choice; `without` is also supported, but that install path is explicitly marked experimental by Spark.\n- Conda packages exist, but the official docs note they are maintained separately by the community and are not synchronized exactly with Spark releases.\n\nBasic environment setup for local use:\n\n```bash\nexport JAVA_HOME=/path/to/jdk-17\npython -m pip install \"pyspark==4.1.1\"\n```\n\n## Initialize A Session\n\n### Local or classic Spark session\n\nUse an explicit `master` in scripts so behavior is predictable outside the `pyspark` shell:\n\n```python\nfrom pyspark.sql import SparkSession\n\nspark = (\n    SparkSession.builder\n    .master(\"local[*]\")\n    .appName(\"example-job\")\n    .config(\"spark.sql.session.timeZone\", \"UTC\")\n    .getOrCreate()\n)\n\nprint(spark.version)\n```\n\nThe interactive `pyspark` shell creates `spark` for you automatically, but normal Python code does not.\n\n### Spark Connect session\n\nUse Spark Connect when your Python process should talk to a remote Spark server over `sc://...`:\n\n```python\nfrom pyspark.sql import SparkSession\n\nspark = (\n    SparkSession.builder\n    .remote(\"sc://localhost:15002\")\n    .appName(\"connect-client\")\n    .getOrCreate()\n)\n```\n\nIf you switch from a local/classic session to Spark Connect in the same process, stop the existing regular session first.\n\n### Connect-focused package variants\n\nThe install docs distinguish three relevant package choices:\n\n- `pyspark`: full PySpark package\n- `pyspark-connect`: installs `pyspark` and the Spark Connect dependencies, and supports both `spark.master` and `spark.remote`\n- `pyspark-client`: pure Python Spark Connect client for remote `spark.remote` usage only; it does not rely on JARs or a local JRE\n\n## Core Usage\n\n### Create a DataFrame\n\n```python\nfrom datetime import date\nfrom pyspark.sql import SparkSession\n\nspark = SparkSession.builder.master(\"local[*]\").appName(\"people\").getOrCreate()\n\ndf = spark.createDataFrame(\n    [\n        (1, \"Ada\", date(2026, 3, 12)),\n        (2, \"Linus\", date(2026, 3, 11)),\n    ],\n    schema=\"id long, name string, created_at date\",\n)\n\ndf.show()\n```\n\nPySpark can infer schema from Python rows, dictionaries, pandas DataFrames, and RDDs, but explicit schemas reduce type surprises in real jobs.\n\n### Transform with DataFrame APIs\n\nPySpark DataFrames are lazily evaluated: transformations build a plan, and execution starts only when you trigger an action such as `show()`, `count()`, `collect()`, or a write.\n\n```python\nfrom pyspark.sql import functions as F\n\nresult = (\n    df\n    .withColumn(\"name_upper\", F.upper(\"name\"))\n    .filter(F.col(\"id\") >= 1)\n    .groupBy(\"name_upper\")\n    .agg(F.count(\"*\").alias(\"row_count\"))\n)\n\nresult.show()\n```\n\n### Mix DataFrames and SQL\n\n```python\ndf.createOrReplaceTempView(\"people\")\n\nsummary = spark.sql(\"\"\"\n    SELECT name, COUNT(*) AS row_count\n    FROM people\n    GROUP BY name\n    ORDER BY row_count DESC\n\"\"\")\n\nsummary.show()\n```\n\nSpark SQL and DataFrame APIs share the same execution engine, so it is normal to move between them in one job.\n\n### Read and write data\n\n```python\nevents = spark.read.parquet(\"data/events/\")\n\n(\n    events\n    .filter(\"event_type = 'click'\")\n    .write\n    .mode(\"overwrite\")\n    .parquet(\"out/click-events/\")\n)\n```\n\nFor small local jobs, file paths can be local. For real clusters, use storage paths that are reachable from executors, not just from your laptop.\n\n## Configuration, Packaging, And Cluster Access\n\nUse builder config for application-local settings:\n\n```python\nfrom pyspark.sql import SparkSession\n\nspark = (\n    SparkSession.builder\n    .master(\"local[*]\")\n    .appName(\"etl-job\")\n    .config(\"spark.sql.shuffle.partitions\", \"8\")\n    .config(\"spark.jars.packages\", \"group:artifact:version\")\n    .getOrCreate()\n)\n```\n\nUseful configuration patterns from the official Spark docs:\n\n- Use `.config(...)` or `SparkConf` for per-application settings.\n- Use `spark-submit --conf key=value` for runtime-specific overrides.\n- Use `spark-defaults.conf` when the same settings should apply repeatedly.\n- Use `spark.jars.packages` to resolve connector JARs for the driver and executors.\n- Use `spark.hadoop.*` and `spark.hive.*` properties for Hadoop and Hive-side configuration instead of mutating cluster-wide config files per application.\n- Use `spark.submit.pyFiles` or `spark-submit --py-files` to distribute your own Python modules to executors.\n\nTypical cluster submission:\n\n```bash\nspark-submit \\\n  --master spark://host:7077 \\\n  --conf spark.sql.shuffle.partitions=200 \\\n  --py-files dist/my_job.zip \\\n  jobs/my_job.py\n```\n\nAuth and access note:\n\n- `pyspark` itself is not an auth SDK.\n- Access to S3, GCS, ADLS, Hive metastore, or secured clusters is handled by Spark/Hadoop connectors, cluster configuration, and runtime credentials.\n- If storage access fails, check connector JARs, `spark.hadoop.*` settings, and cluster identity before assuming the Python code is wrong.\n\n## Testing\n\nThe official testing guide recommends using PySpark's built-in test utilities for DataFrame and schema comparisons:\n\n```python\nfrom pyspark.testing.utils import assertDataFrameEqual, assertSchemaEqual\n```\n\nFor larger suites, use `unittest` or `pytest` and create one shared `SparkSession` per test class or fixture instead of spinning up a new session for every assertion.\n\n## Common Pitfalls\n\n- A pip-installed PySpark client must match the Spark cluster minor version closely. The PyPI page warns that Spark standalone clusters can produce odd errors when versions do not match.\n- `collect()` and `toPandas()` bring data back to the driver. Use them only for small result sets.\n- `pyspark` requires Java 17+. Missing or wrong `JAVA_HOME` is still a common local setup failure.\n- Spark Connect and a regular local session cannot coexist in the same process without stopping the existing session first.\n- `pyspark-client` is remote-only. If you need local mode or `master(\"local[*]\")`, use `pyspark` or `pyspark-connect` instead.\n- Python package installation does not automatically solve cluster-side connector setup. Executors still need access to the same data sources and dependencies.\n- Standalone cluster `cluster` deploy mode is not supported for Python applications; use `client` mode there or use another cluster manager that supports your deployment pattern.\n\n## Version-Sensitive Notes For 4.1.1\n\n- Spark 4.1 drops Python 3.9 support in PySpark. Use Python 3.10+.\n- Spark 4.1 raises the minimum supported PyArrow version in PySpark from `11.0.0` to `15.0.0`.\n- Spark 4.1 raises the minimum supported pandas version in PySpark from `2.0.0` to `2.2.0`.\n- In Spark 4.1, `BinaryType` maps to Python `bytes` by default in PySpark instead of the older mixed `bytearray` behavior.\n- In Spark 4.1, `spark.sql.execution.pandas.convertToArrowArraySafely` is enabled by default, so Arrow-backed conversions can now fail on unsafe casts that previously slipped through.\n- If you are upgrading older pandas-on-Spark code, read the upstream upgrade guide before copying pre-4.x examples.\n\n## Official Sources\n\n- Apache Spark PySpark overview: `https://spark.apache.org/docs/latest/api/python/`\n- Apache Spark install guide: `https://spark.apache.org/docs/latest/api/python/getting_started/install.html`\n- Apache Spark DataFrame quickstart: `https://spark.apache.org/docs/latest/api/python/getting_started/quickstart_df.html`\n- Apache Spark Spark Connect quickstart: `https://spark.apache.org/docs/latest/api/python/getting_started/quickstart_connect.html`\n- Apache Spark testing guide: `https://spark.apache.org/docs/latest/api/python/getting_started/testing_pyspark.html`\n- Apache Spark migration guides: `https://spark.apache.org/docs/latest/api/python/migration_guide/index.html`\n- PySpark upgrade notes: `https://spark.apache.org/docs/latest/api/python/migration_guide/pyspark_upgrade.html`\n- Spark configuration: `https://spark.apache.org/docs/latest/configuration.html`\n- Spark submission guide: `https://spark.apache.org/docs/latest/submitting-applications.html`\n- PyPI package page: `https://pypi.org/project/pyspark/`\n"
  },
  {
    "path": "content/pytest/docs/asyncio/python/DOC.md",
    "content": "---\nname: asyncio\ndescription: \"pytest-asyncio package guide for asyncio-based pytest test suites in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-asyncio,pytest,asyncio,testing,python\"\n---\n\n# pytest-asyncio Python Package Guide\n\n## Golden Rule\n\nUse the `stable` docs for `pytest-asyncio 1.3.0`, not the previous `en/latest` docs root. As of March 12, 2026, `https://pytest-asyncio.readthedocs.io/en/latest/` is serving `0.1.dev1` content, while `https://pytest-asyncio.readthedocs.io/en/stable/` matches the current `1.3.0` release.\n\n## What It Does\n\n`pytest-asyncio` is a `pytest` plugin for running `asyncio`-based tests and fixtures. It gives async test functions an event loop, supports async fixtures, and lets you control loop scope per test, fixture, class, module, package, or session.\n\nIt is for `asyncio`. If the project mixes multiple async backends such as Trio and asyncio, be deliberate about plugin mode and fixture decorators.\n\n## Install\n\nInstall it as a test dependency alongside `pytest`:\n\n```bash\npython -m pip install \"pytest>=8.2,<10\" \"pytest-asyncio==1.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest>=8.2,<10\" \"pytest-asyncio==1.3.0\"\npoetry add --group test \"pytest>=8.2,<10\" \"pytest-asyncio==1.3.0\"\n```\n\n`pytest` auto-loads installed plugins, so no manual plugin registration is normally needed.\n\n## Minimal Setup\n\nStrict mode is the default. In strict mode, async tests need the `asyncio` marker and async fixtures should use `@pytest_asyncio.fixture`.\n\n```python\nimport asyncio\n\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_sleep():\n    await asyncio.sleep(0)\n    assert True\n```\n\nRun tests normally:\n\n```bash\npytest\n```\n\n## Recommended Project Configuration\n\nIf the project uses only `asyncio`, set auto mode in `pyproject.toml` so agents do not have to remember `@pytest.mark.asyncio` on every async test:\n\n```toml\n[tool.pytest.ini_options]\nasyncio_mode = \"auto\"\nasyncio_default_fixture_loop_scope = \"function\"\nasyncio_default_test_loop_scope = \"function\"\n```\n\nWhy set both loop-scope defaults explicitly:\n\n- `asyncio_mode` defaults to `strict` if unset.\n- `asyncio_default_test_loop_scope` already defaults to `function`.\n- `asyncio_default_fixture_loop_scope` currently defaults to the fixture scope when unset, but upstream says a future version will change the unset default to `function`.\n\nSet `asyncio_default_fixture_loop_scope` explicitly to avoid future behavior drift.\n\n## Core Usage\n\n### Async tests in strict mode\n\n```python\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_fetch(client):\n    response = await client.get(\"/health\")\n    assert response.status_code == 200\n```\n\n### Async tests in auto mode\n\nWith `asyncio_mode = \"auto\"`, plain async test functions are managed automatically:\n\n```python\nasync def test_fetch(client):\n    response = await client.get(\"/health\")\n    assert response.status_code == 200\n```\n\n### Async fixtures\n\nUse `@pytest_asyncio.fixture` when you need an async fixture, especially in strict mode:\n\n```python\nimport pytest_asyncio\n\n@pytest_asyncio.fixture\nasync def seeded_db():\n    db = await create_test_db()\n    await db.seed()\n    try:\n        yield db\n    finally:\n        await db.close()\n```\n\nThen use it from async tests:\n\n```python\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_query(seeded_db):\n    rows = await seeded_db.fetch_all()\n    assert rows\n```\n\n## Event Loop Scope\n\nBy default, tests run with function-scoped event loops for maximum isolation. If nearby tests must share the same loop, use `loop_scope`.\n\nModule-scoped loop:\n\n```python\nimport asyncio\n\nimport pytest\n\npytestmark = pytest.mark.asyncio(loop_scope=\"module\")\n\nasync def test_remember_loop():\n    loop = asyncio.get_running_loop()\n    assert loop.is_running()\n\nasync def test_same_loop_again():\n    assert asyncio.get_running_loop().is_running()\n```\n\nFixture loop scope:\n\n```python\nimport asyncio\n\nimport pytest\nimport pytest_asyncio\n\n@pytest_asyncio.fixture(loop_scope=\"module\")\nasync def current_loop():\n    return asyncio.get_running_loop()\n\n@pytest.mark.asyncio(loop_scope=\"module\")\nasync def test_uses_module_loop(current_loop):\n    assert current_loop is asyncio.get_running_loop()\n```\n\nKeep neighboring tests on the same loop scope when they logically share setup. Mixing loop scopes in the same module or class makes failures harder to reason about.\n\n## Configuration Reference\n\nSupported config knobs for most projects:\n\n- `asyncio_mode = \"strict\" | \"auto\"`\n- `asyncio_default_fixture_loop_scope = \"function\" | \"class\" | \"module\" | \"package\" | \"session\"`\n- `asyncio_default_test_loop_scope = \"function\" | \"class\" | \"module\" | \"package\" | \"session\"`\n- `asyncio_debug = true | false`\n\nCLI overrides:\n\n```bash\npytest --asyncio-mode=strict\npytest --asyncio-debug\n```\n\nThere is no auth setup for this package. Configuration is entirely through pytest config files and CLI flags.\n\n## Common Pitfalls\n\n- Do not rely on `en/latest` docs for this package until upstream fixes the Read the Docs mapping. Use `en/stable` or versioned pages instead.\n- Default mode is `strict`, not `auto`. Unmarked async tests can be collected without being handled the way you expect.\n- In strict mode, async fixtures should use `@pytest_asyncio.fixture`, not plain `@pytest.fixture`.\n- Async tests still run sequentially. `pytest-asyncio` does not make the test suite concurrent by default.\n- `unittest.TestCase` subclasses are not supported. Use pytest-style tests or `unittest.IsolatedAsyncioTestCase`.\n- Avoid carrying forward old examples that request the deprecated `event_loop` fixture inside async tests. Use `asyncio.get_running_loop()` instead.\n- If you need a different loop implementation, prefer changing the event loop policy instead of re-implementing the old `event_loop` fixture pattern.\n\n## Version-Sensitive Notes\n\n- `1.3.0` adds support for `pytest 9` and removes Python `3.9` support.\n- `1.2.0` adds `--asyncio-debug` and `asyncio_debug`, plus validation for invalid loop-scope config values.\n- `1.0.0` removed the deprecated `event_loop` fixture. If you are upgrading from `0.21.x` or `0.23.x`, migrate async tests and async fixtures to `asyncio.get_running_loop()` and `loop_scope`.\n- The `0.23.x` series had known event-loop/fixture-scope issues that upstream explicitly called out. Prefer `1.x` for new work unless a project is pinned for compatibility reasons.\n\n## Migration Notes For Older Suites\n\nIf a test suite still has pre-`1.0` patterns:\n\n1. Remove async test arguments named `event_loop`.\n2. Replace them with `loop = asyncio.get_running_loop()` inside the coroutine.\n3. Replace old fixture redefinitions with `@pytest_asyncio.fixture(...)`.\n4. Set `loop_scope` explicitly where tests or fixtures need shared loops.\n5. Set `asyncio_default_fixture_loop_scope = \"function\"` unless the suite intentionally shares broader-scoped loops.\n\n## Official Links\n\n- Stable docs: https://pytest-asyncio.readthedocs.io/en/stable/\n- Concepts: https://pytest-asyncio.readthedocs.io/en/stable/concepts.html\n- Configuration: https://pytest-asyncio.readthedocs.io/en/stable/reference/configuration.html\n- Decorators: https://pytest-asyncio.readthedocs.io/en/stable/reference/decorators/\n- Changelog: https://pytest-asyncio.readthedocs.io/en/stable/reference/changelog.html\n- Migration from 0.21: https://pytest-asyncio.readthedocs.io/en/stable/how-to-guides/migrate_from_0_21.html\n- Migration from 0.23: https://pytest-asyncio.readthedocs.io/en/stable/how-to-guides/migrate_from_0_23.html\n- PyPI: https://pypi.org/project/pytest-asyncio/\n"
  },
  {
    "path": "content/pytest/docs/bdd/python/DOC.md",
    "content": "---\nname: bdd\ndescription: \"pytest-bdd package guide for Python projects using Gherkin feature files with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-bdd,pytest,bdd,gherkin,testing,python\"\n---\n\n# pytest-bdd Python Package Guide\n\n## Golden Rule\n\nUse `pytest-bdd` as a thin layer on top of normal `pytest`: keep test state in fixtures, keep feature files readable, and bind scenarios explicitly from Python. Do not design around a separate BDD runner or a shared mutable \"context\" object.\n\n## Install\n\nInstall `pytest-bdd` alongside `pytest` as a test dependency:\n\n```bash\npython -m pip install \"pytest>=8\" \"pytest-bdd==8.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest>=8\" \"pytest-bdd==8.1.0\"\npoetry add --group dev \"pytest>=8\" \"pytest-bdd==8.1.0\"\n```\n\nRun tests with plain `pytest`:\n\n```bash\npytest\n```\n\n## Minimal Setup\n\nRecommended layout:\n\n```text\ntests/\n  features/\n    publish_article.feature\n  test_publish_article.py\npytest.ini\n```\n\nSet a base directory for feature files so step modules can use short relative paths:\n\n```ini\n# pytest.ini\n[pytest]\nbdd_features_base_dir = tests/features\nmarkers =\n    publishing: BDD tag from feature files\n```\n\nIf you use `pytest --strict-markers`, register the markers you expect feature tags to create.\n\n## Write A Feature File\n\nKeep one Gherkin feature per `.feature` file:\n\n```gherkin\nFeature: Blog publishing\n  Scenario: Publishing an article\n    Given a draft article titled \"BDD with pytest\"\n    When the article is published\n    Then the article status is \"published\"\n```\n\n## Bind Scenarios And Implement Steps\n\n```python\nfrom pytest_bdd import given, parsers, scenario, then, when\n\n@scenario(\"publish_article.feature\", \"Publishing an article\")\ndef test_publishing_article():\n    pass\n\n@given(parsers.parse('a draft article titled \"{title}\"'), target_fixture=\"article\")\ndef draft_article(title: str):\n    return {\"title\": title, \"status\": \"draft\"}\n\n@when(\"the article is published\")\ndef publish_article(article):\n    article[\"status\"] = \"published\"\n\n@then(parsers.parse('the article status is \"{status}\"'))\ndef assert_status(article, status: str):\n    assert article[\"status\"] == status\n```\n\nKey points:\n\n- `@scenario(...)` binds a Python test function to a scenario in a `.feature` file.\n- `target_fixture` lets a step provide or override a pytest fixture value.\n- Step functions can depend on normal fixtures exactly like other pytest tests.\n\nFor many scenarios at once, use `scenarios(...)`:\n\n```python\nfrom pytest_bdd import scenarios\n\nscenarios(\"features\")\n```\n\nUse this for bulk binding, but keep any manual `@scenario(...)` declarations earlier in the file.\n\n## Step Parsers And Parameters\n\n`pytest-bdd` supports plain strings and parser helpers:\n\n- `parsers.parse(...)` for typed placeholders such as `{count:d}`\n- `parsers.cfparse(...)` for parse expressions with more converters\n- `parsers.re(...)` for regular expressions when you need exact control\n\nExample with typed parsing:\n\n```python\nfrom pytest_bdd import given, parsers\n\n@given(parsers.parse(\"there are {count:d} users\"), target_fixture=\"users\")\ndef users(count: int):\n    return list(range(count))\n```\n\nUse parser-based steps when values come from the feature file. Keep the parsing logic in the decorator instead of manually splitting strings inside the step function.\n\n## Scenario Outlines\n\nUse Gherkin `Scenario Outline` plus `Examples` for data-driven behavior:\n\n```gherkin\nScenario Outline: Pricing\n  Given a cart total of <total>\n  Then the discount is <discount>\n\n  Examples:\n    | total | discount |\n    | 20    | 0        |\n    | 120   | 10       |\n```\n\nMatch placeholders with parser-based steps:\n\n```python\nfrom pytest_bdd import given, parsers, then\n\n@given(parsers.parse(\"a cart total of {total:d}\"), target_fixture=\"cart_total\")\ndef cart_total(total: int):\n    return total\n\n@then(parsers.parse(\"the discount is {discount:d}\"))\ndef discount(cart_total: int, discount: int):\n    actual = 10 if cart_total >= 100 else 0\n    assert actual == discount\n```\n\nPrefer scenario outlines over stacking `@pytest.mark.parametrize` on top of BDD scenarios.\n\n## Datatables, Docstrings, And Tags\n\n`pytest-bdd` can pass richer Gherkin inputs into step functions:\n\n- Docstrings are exposed as a `docstring` argument.\n- Data tables are exposed as a `datatable` argument.\n- Tags become pytest markers, so you can select with normal pytest filtering.\n\nExample tag selection:\n\n```bash\npytest -m publishing\n```\n\nIf you need custom tag behavior, implement hooks such as `pytest_bdd_apply_tag`. Other useful hooks include scenario and step hooks for reporting or custom logging.\n\n## Config And Test Initialization\n\nThere is no service authentication model in `pytest-bdd`; configuration is local to pytest and your test tree.\n\nUse these setup rules:\n\n- Put shared fixtures in `conftest.py`.\n- Set `bdd_features_base_dir` in `pytest.ini` when feature files live outside the test module directory.\n- Keep step text stable and human-readable; move conditional logic into fixtures and helpers.\n- Use normal pytest fixture scopes (`function`, `module`, `session`) for expensive setup.\n\nExample shared fixture:\n\n```python\n# tests/conftest.py\nimport pytest\n\n@pytest.fixture\ndef app_client():\n    return build_test_client()\n```\n\n## Common Pitfalls\n\n- Only one feature is allowed per `.feature` file.\n- Feature tags become pytest markers. With `--strict-markers`, undeclared tags will fail collection.\n- `bdd_features_base_dir` is resolved from the pytest root directory, not from whatever shell directory you happen to be in.\n- `parsers.re(...)` uses full matching in modern `pytest-bdd`; partial regex matches that used to pass can now fail.\n- Parsed step arguments are regular function arguments, not pytest fixtures. Use `target_fixture` when a step should create or override fixture data.\n- Do not mix scenario outlines and `@pytest.mark.parametrize` for the same behavior unless you have a very specific reason and have verified collection behavior.\n- If you call `scenarios(...)`, keep any manual `@scenario(...)` bindings earlier in the module.\n- In `8.1.0`, `datatable` and `docstring` are reserved step argument names for parser-based steps.\n\n## Version-Sensitive Notes For 8.1.0\n\n- `8.1.0` reserves `datatable` and `docstring` as parser argument names because those names are now used for Gherkin table and docstring injection.\n- `8.1.0` also adds template variable rendering inside docstrings and datatables, which matters if your step logic reads multiline or tabular scenario data.\n- The `8.0` line adds support for `Rule`, localized Gherkin with `# language: ...`, multiple example tables, and tags on individual examples.\n- Since the `7.x` line, `parsers.re(...)` behaves as a full match, so older regex-based steps may need anchors or updated patterns during migration.\n\n## Official Sources\n\n- Stable docs: `https://pytest-bdd.readthedocs.io/en/stable/`\n- Changelog and migration notes: `https://pytest-bdd.readthedocs.io/en/stable/#changelog`\n- PyPI package metadata: `https://pypi.org/project/pytest-bdd/`\n"
  },
  {
    "path": "content/pytest/docs/benchmark/python/DOC.md",
    "content": "---\nname: benchmark\ndescription: \"pytest-benchmark package guide for Python projects using pytest performance benchmarks\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.2.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-benchmark,pytest,benchmark,performance,testing\"\n---\n\n# pytest-benchmark Python Package Guide\n\n## Golden Rule\n\nUse `pytest-benchmark` only for code paths that are already covered by normal correctness tests, and benchmark the callable directly instead of wrapping it in extra Python layers. The plugin is designed for `pytest` suites and auto-calibrates rounds for microbenchmarks unless you explicitly switch to pedantic mode.\n\n## Install\n\nPin the plugin version you expect in CI:\n\n```bash\npython -m pip install \"pytest-benchmark==5.2.3\"\n```\n\nCommon variants:\n\n```bash\nuv add --dev \"pytest-benchmark==5.2.3\"\npoetry add --group dev \"pytest-benchmark==5.2.3\"\n```\n\nOptional extras from PyPI:\n\n```bash\npython -m pip install \"pytest-benchmark[histogram]==5.2.3\"\npython -m pip install \"pytest-benchmark[aspect]==5.2.3\"\npython -m pip install \"pytest-benchmark[elasticsearch]==5.2.3\"\n```\n\n- `histogram`: plotting support for `--benchmark-histogram`\n- `aspect`: experimental `benchmark.weave(...)` patch utilities via `aspectlib`\n- `elasticsearch`: storing benchmark runs in Elasticsearch\n\n## Initialize In A Pytest Suite\n\nOnce installed, the plugin registers the `benchmark` fixture automatically.\n\nBasic benchmark:\n\n```python\nimport json\n\ndef parse_payload(payload: str) -> dict:\n    return json.loads(payload)\n\ndef test_parse_payload(benchmark):\n    payload = '{\"name\": \"context-hub\", \"rank\": 458}'\n    result = benchmark(parse_payload, payload)\n    assert result[\"name\"] == \"context-hub\"\n```\n\nRun only benchmark tests:\n\n```bash\npytest --benchmark-only\n```\n\nRun the full suite but disable stats collection while still executing the benchmarked code once:\n\n```bash\npytest --benchmark-disable\n```\n\nSkip benchmark tests entirely:\n\n```bash\npytest --benchmark-skip\n```\n\n## Project-Level Configuration\n\nThere is no auth setup. Configuration is local to pytest through CLI flags, markers, and your pytest config.\n\nTypical `pyproject.toml` setup:\n\n```toml\n[tool.pytest.ini_options]\naddopts = [\n  \"--benchmark-autosave\",\n  \"--benchmark-sort=mean\",\n  \"--benchmark-columns=min,max,mean,stddev,median,iqr,ops,rounds,iterations\",\n]\n```\n\nUseful CLI options from the official docs:\n\n- `--benchmark-min-time=SECONDS`: minimum time per round\n- `--benchmark-max-time=SECONDS`: max total time per test, default `1.0`\n- `--benchmark-min-rounds=NUM`: lower bound on round count, default `5`\n- `--benchmark-disable-gc`: disable GC during measurement\n- `--benchmark-warmup[=auto|on|off]`: enable warmup, default `auto`\n- `--benchmark-warmup-iterations=NUM`: cap warmup iterations, default `100000`\n- `--benchmark-time-unit=ns|us|ms|s`: force display unit\n\nPer-test tuning uses the `benchmark` marker:\n\n```python\nimport pytest\n\ndef parse_payload(payload: str) -> dict:\n    return {\"raw\": payload}\n\n@pytest.mark.benchmark(\n    group=\"json\",\n    min_time=0.05,\n    max_time=0.5,\n    min_rounds=10,\n    disable_gc=True,\n    warmup=False,\n)\ndef test_parse_payload(benchmark):\n    benchmark(parse_payload, '{\"name\": \"context-hub\"}')\n```\n\n## Core Usage Patterns\n\n### Benchmark the final callable directly\n\nThis is the preferred microbenchmark pattern because extra wrapper calls distort very fast measurements:\n\n```python\ndef test_tokenize(benchmark):\n    text = \"alpha beta gamma\"\n    tokens = benchmark(str.split, text)\n    assert tokens == [\"alpha\", \"beta\", \"gamma\"]\n```\n\n### Keep correctness assertions outside the measured section\n\nThe fixture returns the callable result, so assert afterward:\n\n```python\nimport re\n\ndef test_compile_regex(benchmark):\n    compiled = benchmark(re.compile, r\"pytest-benchmark\")\n    assert compiled.pattern == r\"pytest-benchmark\"\n```\n\n### Save and compare benchmark history\n\nStore runs in the default `.benchmarks/` directory:\n\n```bash\npytest --benchmark-autosave\npytest --benchmark-save=baseline\npytest --benchmark-compare=0001\npytest --benchmark-compare-fail=mean:5%\n```\n\nFor saved runs outside pytest, use the companion CLI:\n\n```bash\npytest-benchmark compare 0001 0002\n```\n\n### Export JSON or histograms\n\n```bash\npytest --benchmark-json=artifacts/benchmark.json\npytest --benchmark-histogram=artifacts/bench\n```\n\nIf you want histogram output, install the `histogram` extra first.\n\n### Attach extra metadata to saved JSON\n\n```python\ndef build_index(path: str) -> dict:\n    return {\"path\": path}\n\ndef test_search_index(benchmark):\n    benchmark.extra_info[\"dataset\"] = \"fixtures/search-v2.json\"\n    benchmark.extra_info[\"scenario\"] = \"cold-cache\"\n    benchmark(build_index, \"fixtures/search-v2.json\")\n```\n\n## Pedantic Mode\n\nUse `benchmark.pedantic(...)` when you need fixed rounds and iterations instead of auto calibration.\n\n```python\ndef encode_record(value: bytes) -> str:\n    return value.hex()\n\ndef test_encode_record(benchmark):\n    payload = b\"context-hub\"\n    benchmark.pedantic(\n        encode_record,\n        args=(payload,),\n        iterations=100,\n        rounds=50,\n        warmup_rounds=5,\n    )\n```\n\nUse `setup` when each round needs fresh inputs:\n\n```python\ndef sort_items(items: list[int]) -> list[int]:\n    return sorted(items)\n\ndef test_sort_items(benchmark):\n    def setup():\n        return ([5, 1, 4, 2, 3],), {}\n\n    benchmark.pedantic(sort_items, setup=setup, rounds=100)\n```\n\nUse `teardown` when each round leaves side effects that need cleanup:\n\n```python\ndef append_item(target: list[int], value: int) -> None:\n    target.append(value)\n\ndef test_append_item(benchmark):\n    values = []\n\n    def teardown(target, value):\n        target.clear()\n\n    benchmark.pedantic(\n        append_item,\n        args=(values, 1),\n        teardown=teardown,\n        rounds=100,\n    )\n```\n\n## Storage And Comparison\n\nSaved runs go to `file://./.benchmarks` by default. You can override that with `--benchmark-storage`.\n\nExamples:\n\n```bash\npytest --benchmark-storage=file://./artifacts/benchmarks --benchmark-autosave\npytest --benchmark-storage=elasticsearch+https://host1,host2/index/doctype?project_name=ContextHub --benchmark-save=main\n```\n\nUse file storage unless you already have a reason to centralize benchmark history.\n\n## Common Pitfalls\n\n- One benchmark test should measure one callable. If you want to compare implementations, parametrize separate tests instead of benchmarking multiple functions in one test.\n- Avoid benchmarking I/O-heavy or non-deterministic code if you want stable regressions. The official FAQ calls out VMs, background services, external resources, GC, and JIT effects as common sources of high `StdDev`.\n- `benchmark(...)` is usually better than the decorator form for microbenchmarks because wrapper call overhead can skew very fast timings.\n- `pytest-xdist` and benchmarks are a bad combination. `pytest-benchmark` auto-disables benchmarks when xdist is enabled by design; run benchmarks in a dedicated non-xdist job.\n- In pedantic mode, the default `iterations=1` is unsafe for functions faster than roughly `100us`. Increase `iterations` or prefer normal auto-calibrated mode.\n- If you supply a pedantic `setup` function, do not also pass `args`, `kwargs`, or `iterations`.\n- `--benchmark-disable` still executes the benchmarked callable once. Use `--benchmark-skip` if you need to avoid the run entirely.\n- If you must benchmark on a noisy machine or VM, the official FAQ suggests trying a custom timer such as `time.process_time`, because it excludes sleeping and waiting for I/O.\n- When `StdDev` is noisy, compare `median` and `iqr` instead of treating `min` or `stddev` as the only signal.\n\n## Version-Sensitive Notes For 5.2.3\n\n- `5.2.3` adds support for `pytest 9.0`.\n- `5.2.2` fixes benchmark auto-disable behavior with newer `pytest-xdist`.\n- `5.2.1` adds markers so pytest does not try to assert-rewrite plugin internals, addressing `PytestAssertRewriteWarning` noise.\n- `5.2.0` adds pedantic `teardown`, the `--benchmark-time-unit` option, and minimal typing support.\n- `5.1.0` raises the minimum supported `pytest` version to `8.1`.\n- `5.0.0` drops Python `3.8`; current PyPI metadata for `5.2.3` requires Python `>=3.9`.\n\n## Official Sources\n\n- Docs root: `https://pytest-benchmark.readthedocs.io/en/stable/`\n- Installation: `https://pytest-benchmark.readthedocs.io/en/latest/installation.html`\n- Usage: `https://pytest-benchmark.readthedocs.io/en/v5.2.3/usage.html`\n- Calibration: `https://pytest-benchmark.readthedocs.io/en/stable/calibration.html`\n- Pedantic mode: `https://pytest-benchmark.readthedocs.io/en/latest/pedantic.html`\n- Comparing past runs: `https://pytest-benchmark.readthedocs.io/en/stable/comparing.html`\n- FAQ: `https://pytest-benchmark.readthedocs.io/en/stable/faq.html`\n- Changelog: `https://pytest-benchmark.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/pytest-benchmark/`\n"
  },
  {
    "path": "content/pytest/docs/cov/python/DOC.md",
    "content": "---\nname: cov\ndescription: \"pytest-cov package guide for running pytest coverage, reports, xdist, and coverage config in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,coverage,testing,python,ci,xdist\"\n---\n\n# pytest-cov Python Package Guide\n\n## Golden Rule\n\nUse `pytest-cov` as a pytest plugin, not as an application import. Install it into the same environment as `pytest`, run coverage through `pytest --cov ...`, and keep the real coverage settings in a coverage config file.\n\nAs of March 12, 2026, PyPI lists `pytest-cov 7.0.0`, while the upstream `latest` docs already include a `7.0.1` changelog entry. This guide is anchored to the released PyPI version `7.0.0`.\n\n## Install\n\nInstall the plugin into the same virtualenv as your test runner:\n\n```bash\npython -m pip install \"pytest-cov==7.0.0\"\n```\n\nIf you run tests in parallel, also install `pytest-xdist`:\n\n```bash\npython -m pip install pytest-xdist\n```\n\n## Basic Usage\n\nMinimal coverage run:\n\n```bash\npytest --cov=src/your_pkg tests\n```\n\nShow missing lines in the terminal:\n\n```bash\npytest --cov=src/your_pkg --cov-report=term-missing tests\n```\n\nFail CI if coverage drops below a threshold:\n\n```bash\npytest --cov=src/your_pkg --cov-branch --cov-fail-under=90 tests\n```\n\nAppend results across multiple runs instead of erasing prior coverage data:\n\n```bash\npytest --cov=src/your_pkg --cov-append tests/unit\npytest --cov=src/your_pkg --cov-append tests/integration\n```\n\n## Persistent Configuration\n\n`pytest-cov` can read coverage settings from `.coveragerc`, `tox.ini`, `setup.cfg`, or `pyproject.toml`. If your tests or subprocesses change the working directory, pass `--cov-config` explicitly so coverage uses the right file.\n\nA practical `pyproject.toml` setup:\n\n```toml\n[tool.pytest.ini_options]\naddopts = [\n  \"--cov\",\n  \"--cov-report=term-missing\",\n  \"--cov-report=xml:coverage.xml\",\n]\n\n[tool.coverage.run]\nsource = [\"src/your_pkg\"]\nbranch = true\n\n[tool.coverage.report]\nshow_missing = true\nskip_covered = true\n```\n\nUse bare `--cov` when `source` is already configured under coverage settings. Passing `--cov=...` on the command line overrides coverage's `source` option.\n\n## Reports\n\n`pytest-cov` supports these report types:\n\n- terminal: `term`\n- terminal with missing lines: `term-missing`\n- HTML: `html[:path]`\n- XML: `xml[:path]`\n- JSON: `json[:path]`\n- LCOV: `lcov[:path]`\n- Markdown: `markdown[:path]`\n- Markdown append: `markdown-append[:path]`\n- Annotated source: `annotate[:path]`\n\nExamples:\n\n```bash\npytest --cov=src/your_pkg \\\n  --cov-report=term-missing \\\n  --cov-report=html:htmlcov \\\n  --cov-report=xml:coverage.xml\n```\n\nIf you specify any `--cov-report`, the default terminal report is not added automatically. Ask for every report you want.\n\nTo generate only file outputs and suppress terminal coverage text:\n\n```bash\npytest --cov=src/your_pkg --cov-report= --cov-report=xml:coverage.xml\n```\n\n## Parallel And Distributed Test Runs\n\nFor `pytest-xdist`:\n\n```bash\npytest -n auto --cov=src/your_pkg tests\n```\n\n`pytest-cov` combines coverage from xdist workers automatically. This is the normal way to collect parallel test coverage in pytest.\n\nPer-test coverage contexts are available with:\n\n```bash\npytest --cov=src/your_pkg --cov-context=test tests\n```\n\nDo not combine `--cov-context=test` with distributed runs. Upstream docs call out that distinct test contexts are not supported with xdist.\n\n## Subprocess Coverage In 7.x\n\n`pytest-cov 7.0.0` removed the old subprocess measurement mechanism that depended on a `.pth` file. If you need coverage from spawned Python subprocesses, enable coverage's subprocess patch instead:\n\n```toml\n[tool.coverage.run]\npatch = [\"subprocess\"]\n```\n\nThis requires a recent coverage release with patch support. Upstream documents this as the replacement path for `pytest-cov 7.x`.\n\n## Debugging And Temporary Opt-Out\n\nCoverage tracing can interfere with debuggers. When you need clean breakpoint behavior, disable the plugin for that run:\n\n```bash\npytest --no-cov -k test_name\n```\n\n`pytest-cov` also exposes a `no_cover` marker and fixture for targeted opt-outs, but `--no-cov` is the simplest whole-run escape hatch while debugging.\n\n## Auth And Environment\n\nThere is no auth layer. The important configuration is local:\n\n- coverage config file location\n- pytest `addopts`\n- output paths for reports such as `coverage.xml` or `htmlcov/`\n- parallel or subprocess behavior when using xdist or spawned Python processes\n\n## Common Pitfalls\n\n- `--cov=path_or_pkg` overrides coverage's `source` setting. If `source` already lives in your coverage config, use bare `--cov`.\n- `pytest-cov` overrides coverage's `parallel` option internally. Do not expect a manual `parallel = true` setting to behave the same way as a plain coverage run.\n- If you pass one explicit `--cov-report`, you must pass all the others you need too.\n- When tests change directories or start subprocesses, an implicit config file lookup can fail. Use `--cov-config=pyproject.toml` or `--cov-config=.coveragerc` when needed.\n- `--cov-context=test` is useful for fine-grained analysis, but not with xdist.\n- For subprocess coverage on `7.0.0`, old blog posts describing automatic `.pth`-based subprocess support are outdated.\n\n## Version-Sensitive Notes\n\n- Version used here: `7.0.0`\n- PyPI current release on March 12, 2026: `7.0.0`\n- Upstream docs drift: the `latest` docs include a `7.0.1` changelog entry dated March 2, 2026\n- Breaking behavior change in `7.0.0`: subprocess coverage moved away from the old `.pth` mechanism to coverage's patch-based approach\n\nWhen copying examples from search results, prefer the official docs over older issue comments or blog posts because `pytest-cov 7.x` changed subprocess behavior and the `latest` docs are slightly ahead of the PyPI release.\n"
  },
  {
    "path": "content/pytest/docs/django/python/DOC.md",
    "content": "---\nname: django\ndescription: \"pytest-django package guide for running Django tests with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.12.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pytest-django,pytest,django,testing,fixtures,database\"\n---\n\n# pytest-django Python Package Guide\n\n## Golden Rule\n\nUse `pytest` as the test runner, point `pytest-django` at your Django settings before collection starts, and request database access explicitly with `@pytest.mark.django_db` or a database fixture. As of March 11, 2026, PyPI has `pytest-django 4.12.0`, but the Read the Docs changelog page still labels `4.12.0` as \"Not released yet\", so treat PyPI as the release-of-record for the package version.\n\n## Install\n\nPin the plugin version to the project series you expect:\n\n```bash\npython -m pip install \"pytest-django==4.12.0\"\n```\n\nIn most projects you also pin `pytest` itself:\n\n```bash\npython -m pip install \"pytest>=7,<9\" \"pytest-django==4.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pytest>=7,<9\" \"pytest-django==4.12.0\"\npoetry add --group dev \"pytest>=7,<9\" \"pytest-django==4.12.0\"\n```\n\n## Minimal Setup\n\nThe plugin needs Django settings before tests import Django models or apps. The common stable setup is `pytest.ini`:\n\n```ini\n[pytest]\nDJANGO_SETTINGS_MODULE = myproject.settings\npython_files = tests.py test_*.py *_tests.py\naddopts = --reuse-db\n```\n\nEquivalent `pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\nDJANGO_SETTINGS_MODULE = \"myproject.settings\"\npython_files = [\"tests.py\", \"test_*.py\", \"*_tests.py\"]\naddopts = \"--reuse-db\"\n```\n\nThe settings resolution order is:\n\n1. `--ds=<settings.module>`\n2. `DJANGO_SETTINGS_MODULE` environment variable\n3. config file value in `pytest.ini`, `tox.ini`, or `pyproject.toml`\n\nExamples:\n\n```bash\npytest --ds=myproject.settings\nDJANGO_SETTINGS_MODULE=myproject.settings pytest\n```\n\nIf the project uses `django-configurations`, also pass `--dc=ConfigName` or set `DJANGO_CONFIGURATION`.\n\n## Project Discovery And Import Path\n\nBy default, `pytest-django` searches for `manage.py` and adds that project directory to `sys.path`. That is convenient for standard layouts, but it can be wrong in monorepos or `src/` layouts.\n\nDisable auto-discovery when you want explicit imports:\n\n```ini\n[pytest]\ndjango_find_project = false\nDJANGO_SETTINGS_MODULE = myproject.settings\n```\n\nThen ensure the Django project is importable yourself, for example with an editable install:\n\n```bash\npython -m pip install -e .\n```\n\nUse this explicit mode if pytest is picking the wrong `manage.py` or the project is not rooted at the repository top level.\n\n## Core Usage\n\n### Fast unit test with no database\n\n```python\ndef test_plain_python_logic():\n    assert 2 + 2 == 4\n```\n\n### Model test that needs the database\n\n```python\nimport pytest\n\nfrom blog.models import Post\n\n@pytest.mark.django_db\ndef test_post_str():\n    post = Post.objects.create(title=\"Hello\")\n    assert str(post) == \"Hello\"\n```\n\n`pytest-django` blocks database access by default. That guard is intentional and catches accidental slow integration tests.\n\n### Transactional test\n\nUse transactional access when the code under test depends on real transaction behavior:\n\n```python\nimport pytest\n\n@pytest.mark.django_db(transaction=True)\ndef test_select_for_update_path():\n    ...\n```\n\nFixture equivalents:\n\n- `db`: normal test database access with transaction rollback\n- `transactional_db`: slower, but closer to real transaction behavior\n\n### Multi-database access\n\n`4.12.0` documents non-experimental support for multiple databases:\n\n```python\nimport pytest\n\n@pytest.mark.django_db(databases=[\"default\", \"other\"])\ndef test_reads_from_replica():\n    ...\n```\n\n### Client-based view test\n\n```python\nimport pytest\nfrom django.urls import reverse\n\n@pytest.mark.django_db\ndef test_dashboard_requires_login(client, django_user_model):\n    user = django_user_model.objects.create_user(\n        username=\"alice\",\n        password=\"secret\",\n    )\n    client.force_login(user)\n\n    response = client.get(reverse(\"dashboard\"))\n\n    assert response.status_code == 200\n```\n\nHigh-value built-in fixtures:\n\n- `client`: Django test client\n- `async_client`: async test client for async views\n- `rf`: `RequestFactory`\n- `async_rf`: async request factory\n- `settings`: temporary settings override fixture\n- `django_user_model`: active user model\n- `admin_user`, `admin_client`: ready-made admin-authenticated fixtures\n- `live_server`: server fixture for browser or external HTTP tests\n\n### Temporary settings override\n\n```python\ndef test_feature_flag(settings):\n    settings.MY_FEATURE_ENABLED = True\n    assert settings.MY_FEATURE_ENABLED is True\n```\n\n## Database Lifecycle And Performance\n\nThe test database is created on first use and then reused inside the current pytest session. For repeated local runs, `--reuse-db` is the standard speed knob:\n\n```bash\npytest --reuse-db\n```\n\nImportant companion flags:\n\n- `--create-db`: rebuild the test database even if `--reuse-db` metadata exists\n- `--no-migrations`: build the test database from models instead of running migrations\n\nUse `--create-db` after schema changes. `--reuse-db` does not automatically detect that your migrations changed.\n\nUse `--no-migrations` only as a local speed optimization. It can hide migration problems that matter in CI or production.\n\nFor custom global database setup, override the session-scoped `django_db_setup` fixture in `conftest.py`.\n\n## Auth And Request Testing\n\n`pytest-django` itself has no external auth configuration layer; auth behavior comes from Django. The fastest stable patterns are:\n\n- create users with `django_user_model`\n- authenticate browser-style tests with `client.force_login(user)`\n- use `admin_client` for built-in admin tests\n- use `rf` only when you want to call a view directly without middleware\n\n`rf` is not the same as `client`: middleware, sessions, and auth are not run automatically. If your code expects `request.user`, session state, or CSRF behavior, prefer `client` unless you are deliberately unit-testing a narrow view function.\n\n## Async And Live Server Notes\n\nUse `async_client` or `async_rf` for async views, and keep the test function compatible with the async pytest stack your project already uses, typically `pytest-asyncio`.\n\n`live_server` depends on `transactional_db`. Because each test starts with a clean database state, do not assume data created in one test will persist into another browser-style or live-server test.\n\n## Common Pitfalls\n\n- Missing settings: `ImproperlyConfigured` during collection usually means `DJANGO_SETTINGS_MODULE` or `--ds` was not set early enough.\n- Wrong import path: auto-discovery found the wrong `manage.py`; disable it with `django_find_project = false` and make imports explicit.\n- Database access denied: add `@pytest.mark.django_db`, `db`, or `transactional_db`.\n- Reused stale schema: after changing migrations, rerun with `pytest --create-db`.\n- RequestFactory confusion: `rf` does not execute middleware or login flows.\n- Hidden migration bugs: `--no-migrations` is useful for local speed, but it is not a substitute for testing real migrations.\n- Async tests hanging or being skipped: install and configure the async pytest plugin your project uses; `pytest-django` does not replace that layer.\n\n## Version-Sensitive Notes\n\n- PyPI lists `pytest-django 4.12.0` as released on February 14, 2026.\n- The Read the Docs changelog currently still shows `v4.12.0 (Not released yet)`, so the changelog page is lagging the package registry.\n- The `4.12.0` changelog entry documents multiple-database support as no longer experimental.\n- If you are maintaining an older project, verify the Django and Python version classifiers on PyPI before copying examples into a project pinned below Django `4.2` or Python `3.10`.\n\n## Official Sources\n\n- Docs root: `https://pytest-django.readthedocs.io/en/latest/`\n- Tutorial: `https://pytest-django.readthedocs.io/en/latest/tutorial.html`\n- Django configuration: `https://pytest-django.readthedocs.io/en/latest/configuring_django.html`\n- Python path and project discovery: `https://pytest-django.readthedocs.io/en/latest/managing_python_path.html`\n- Database usage: `https://pytest-django.readthedocs.io/en/latest/database.html`\n- Fixtures and helpers: `https://pytest-django.readthedocs.io/en/latest/helpers.html`\n- Changelog: `https://pytest-django.readthedocs.io/en/latest/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-django/`\n"
  },
  {
    "path": "content/pytest/docs/env/python/DOC.md",
    "content": "---\nname: env\ndescription: \"pytest-env package guide for configuring test environment variables in pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,testing,environment,configuration,python\"\n---\n\n# pytest-env Python Package Guide\n\n## Golden Rule\n\nUse `pytest-env` as a pytest plugin, not as an importable runtime library. Put test-specific variables in native TOML config under `[tool.pytest_env]` or `[pytest_env]`, use `.env` files only for bulk values, and use `--pytest-env-verbose` any time precedence is unclear.\n\nAs of March 12, 2026, PyPI lists `pytest-env 1.5.0` as the latest release. The maintainer metadata currently documents `Python >=3.10`, and the current upstream project metadata also declares `pytest>=9.0.2`.\n\n## Install\n\nInstall the plugin into the same environment where `pytest` runs:\n\n```bash\npython -m pip install \"pytest-env==1.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-env==1.5.0\"\npoetry add --group test \"pytest-env==1.5.0\"\n```\n\nQuick sanity check that the plugin is active:\n\n```bash\npytest --help | rg 'envfile|pytest-env-verbose'\n```\n\nYou normally do not import `pytest_env` in test code. Pytest discovers the plugin from the installed package.\n\n## Initialize With Native TOML\n\nThe maintainer README treats native TOML as the main configuration format.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest_env]\nDATABASE_URL = \"postgresql://localhost/test_db\"\nDEBUG = \"true\"\n```\n\nOr use a dedicated pytest TOML file:\n\n```toml\n# pytest.toml or .pytest.toml\n[pytest_env]\nDATABASE_URL = \"postgresql://localhost/test_db\"\nDEBUG = \"true\"\n```\n\nA test reads these values through `os.environ`:\n\n```python\nimport os\n\ndef test_database_settings() -> None:\n    assert os.environ[\"DATABASE_URL\"] == \"postgresql://localhost/test_db\"\n    assert os.environ[\"DEBUG\"] == \"true\"\n```\n\nDebug what the plugin actually applied:\n\n```bash\npytest --pytest-env-verbose\n```\n\n## Core Configuration Patterns\n\n### Plain values\n\nPlain values are converted to strings:\n\n```toml\n[tool.pytest_env]\nAPI_URL = \"http://localhost:8000\"\nPORT = 8000\n```\n\n### Transform placeholders explicitly in TOML\n\nIn TOML mode, expansion is off unless `transform = true` is set:\n\n```toml\n[tool.pytest_env]\nRUN_PATH = { value = \"{HOME}/tmp/test-data\", transform = true }\n```\n\n### Preserve existing CI or shell values\n\nUse `skip_if_set = true` when a CI job or shell export should win:\n\n```toml\n[tool.pytest_env]\nDATABASE_URL = { value = \"postgresql://localhost/test_db\", skip_if_set = true }\n```\n\n### Unset variables\n\nUse `unset = true` when a variable must be removed instead of set to an empty string:\n\n```toml\n[tool.pytest_env]\nHTTP_PROXY = { unset = true }\n```\n\n## Load Variables From `.env` Files\n\nUse `env_files` when you have many variables or want to share the same file with local tooling:\n\n```toml\n[tool.pytest_env]\nenv_files = [\".env\", \".env.test\"]\n```\n\nExample `.env` file:\n\n```dotenv\nDATABASE_URL=postgres://localhost/mydb\nexport SECRET_KEY='my-secret-key'\nDEBUG=\"true\"\nAPI_KEY=${FALLBACK_KEY:-default_key}\n```\n\nRuntime overrides:\n\n```bash\npytest --envfile .env.local\npytest --envfile +.env.override\n```\n\nBehavior that matters:\n\n- Configured `env_files` are loaded before inline variables, so inline values override `.env` values.\n- Missing files listed in config are skipped silently.\n- A CLI `--envfile` path must exist; missing files raise `FileNotFoundError`.\n- Paths are resolved relative to the project root.\n\n## INI-Style Configuration\n\nINI syntax is still supported and is useful for simple `KEY=VALUE` pairs:\n\n```ini\n# pytest.ini\n[pytest]\nenv =\n    HOME=~/tmp\n    RUN_ENV=test\n    D:CONDITIONAL=value\n    R:RAW_VALUE={USER}\n    U:REMOVED_VAR\n```\n\nYou can also place the same `env` list in `pyproject.toml` with pytest's native TOML config:\n\n```toml\n[tool.pytest]\nenv = [\n  \"HOME=~/tmp\",\n  \"RUN_ENV=test\",\n]\n```\n\nFlag behavior in INI mode:\n\n- `D:` only sets the variable if it is missing\n- `R:` disables `{VAR}` expansion\n- `U:` unsets the variable\n\nImportant difference: INI mode expands `{VAR}` placeholders by default. Native TOML does not unless `transform = true`.\n\n## Precedence And Discovery\n\nWhen the same variable appears in multiple places, the maintainer README documents this order:\n\n1. Inline variables in config files\n2. Variables loaded from `.env` files\n3. Variables already present in the environment, when preserved by `skip_if_set = true` or `D:`\n\nFormat and file selection also matter:\n\n- Native TOML config takes precedence over INI-style `env` config.\n- For native TOML, the plugin checks `pytest.toml`, then `.pytest.toml`, then `pyproject.toml`, and stops at the first file containing a `pytest_env` section.\n- The plugin walks upward from pytest's resolved configuration directory, so a subdirectory config can intentionally override parent settings for an integration-test subtree.\n\n## Common Pitfalls\n\n- Do not try to `import pytest_env` in application code. This is a pytest plugin, not an app runtime dependency.\n- In TOML mode, `{HOME}` or `{USER}` placeholders do nothing unless `transform = true`.\n- In INI mode, expansion is already on; add `R:` if you need a literal `{VAR}` string.\n- `skip_if_set = true` and `D:` do not make the variable highest priority. They only preserve an existing value if one is already present.\n- `unset = true` and `U:` remove the variable completely. They are not equivalent to setting it to `\"\"`.\n- If nothing seems to happen, check which config file pytest selected and run with `--pytest-env-verbose`.\n- If your repository has nested pytest configs, remember that the first matching native TOML file wins.\n\n## Version-Sensitive Notes\n\n- PyPI currently shows `1.5.0` as the latest `pytest-env` release, published on February 17, 2026.\n- `pytest.toml` and native `[tool.pytest]` config are pytest 9 features. Older pytest docs often use `[tool.pytest.ini_options]`; that is a different configuration path.\n- The current maintainer metadata documents `pytest>=9.0.2` and `python-dotenv>=1.2.1`. If your project is pinned to older pytest versions, verify compatibility before copying 1.5.0 examples directly.\n- The plugin documentation is primarily the GitHub README rather than a separate docs site, so README updates can materially change recommended config shapes.\n\n## Official Sources\n\n- Maintainer docs and reference: `https://github.com/pytest-dev/pytest-env`\n- PyPI package page: `https://pypi.org/project/pytest-env/`\n- PyPI metadata JSON: `https://pypi.org/pypi/pytest-env/json`\n- Pytest configuration reference for pytest 9 TOML behavior: `https://docs.pytest.org/en/latest/customize.html`\n"
  },
  {
    "path": "content/pytest/docs/flask/python/DOC.md",
    "content": "---\nname: flask\ndescription: \"pytest-flask plugin guide for testing Flask apps with pytest fixtures, clients, live servers, and config markers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,flask,testing,pytest-plugin,fixtures\"\n---\n\n# pytest-flask Python Package Guide\n\n## Golden Rule\n\nUse `pytest-flask` as a pytest plugin layered on top of your Flask app's own test configuration. Define a real `app` fixture, enable `TESTING`, and target released `1.3.0` behavior instead of assuming the Read the Docs `latest` build is stable.\n\nAs of March 12, 2026:\n\n- PyPI lists `pytest-flask 1.3.0`\n- Read the Docs `stable` is still `1.2.0`\n- Read the Docs `latest` is a dev build (`1.3.1.dev...`) with unreleased changes\n\nThat version drift matters for fixture behavior and supported Python versions.\n\n## Install\n\nInstall the plugin into the same environment as your Flask app and `pytest`:\n\n```bash\npython -m pip install \"pytest-flask==1.3.0\"\n```\n\nFor a fresh test environment:\n\n```bash\npython -m pip install \"Flask>=2,<4\" \"pytest>=7\" \"pytest-flask==1.3.0\"\n```\n\nIf your project already depends on Flask, you usually only add the plugin:\n\n```bash\nuv add --dev \"pytest-flask==1.3.0\"\npoetry add --group test \"pytest-flask==1.3.0\"\n```\n\n## Minimal Setup\n\n`pytest-flask` does not create your Flask app for you. The core requirement is an `app` fixture in `conftest.py`.\n\n```python\n# tests/conftest.py\nimport pytest\nfrom flask import Flask\n\n@pytest.fixture\ndef app():\n    app = Flask(__name__)\n    app.config.update(\n        TESTING=True,\n        SECRET_KEY=\"test-secret\",\n    )\n\n    @app.get(\"/ping\")\n    def ping():\n        return {\"ok\": True}\n\n    return app\n```\n\nWith that fixture in place, the plugin provides Flask-aware test helpers.\n\n## Core Usage\n\n### `client` fixture\n\nUse `client` for request-level tests. `pytest-flask` automatically pushes a request context around the test client, so Flask globals like `url_for`, `request`, and `session` are available without wrapping each call in `app.test_request_context()`.\n\n```python\nfrom flask import session, url_for\n\ndef test_ping(client):\n    response = client.get(url_for(\"ping\"))\n\n    assert response.status_code == 200\n    assert response.json == {\"ok\": True}\n    assert session is not None\n```\n\n### `client_class` fixture\n\nFor class-based tests, use `client_class` to attach the test client to `self.client`.\n\n```python\nclass TestViews:\n    def test_ping(self, client_class):\n        response = self.client.get(\"/ping\")\n        assert response.json[\"ok\"] is True\n```\n\n### `config` fixture\n\nUse `config` to mutate `app.config` for a specific test.\n\n```python\ndef test_feature_flag(config, client):\n    config[\"FEATURE_X_ENABLED\"] = True\n\n    response = client.get(\"/ping\")\n\n    assert response.status_code == 200\n```\n\n### Content-negotiation fixtures\n\nThe plugin includes request-header fixtures for common Accept values:\n\n- `accept_any`\n- `accept_json`\n- `accept_jsonp`\n- `accept_mimetype`\n\nExample:\n\n```python\ndef test_json_response(client, accept_json):\n    response = client.get(\"/ping\", headers=accept_json)\n    assert response.is_json\n```\n\n### `pytest.mark.options`\n\nUse the `options` marker for per-test config overrides instead of mutating global config in module scope.\n\n```python\nimport pytest\n\n@pytest.mark.options(DEBUG=False, SERVER_NAME=\"example.test\")\ndef test_options_marker(client):\n    response = client.get(\"/ping\")\n    assert response.status_code == 200\n```\n\n## App Factory Pattern\n\nIf your project uses an application factory, keep the fixture thin and create the app inside it:\n\n```python\n# tests/conftest.py\nimport pytest\n\nfrom myapp import create_app\n\n@pytest.fixture\ndef app():\n    app = create_app()\n    app.config.update(\n        TESTING=True,\n        SECRET_KEY=\"test-secret\",\n    )\n    return app\n```\n\nThis keeps the rest of your tests using the same `client`, `config`, and `live_server` fixtures.\n\n## Live Server Tests\n\nUse `live_server` when you need a real HTTP server instead of Flask's in-process test client, for example with browser tests or external callbacks.\n\nBasic pattern:\n\n```python\nimport json\nfrom urllib.request import urlopen\nfrom flask import url_for\n\ndef test_live_server(live_server):\n    @live_server.app.get(\"/health\")\n    def health():\n        return {\"status\": \"ok\"}\n\n    live_server.start()\n    with urlopen(url_for(\"health\", _external=True)) as response:\n        payload = json.load(response)\n\n    assert payload == {\"status\": \"ok\"}\n```\n\nRelevant CLI and config controls from the upstream docs:\n\n- `--start-live-server`: start automatically when the fixture is requested\n- `--no-start-live-server`: require explicit `live_server.start()`\n- `--live-server-port=PORT`: bind a fixed port instead of a random one\n- `--live-server-wait=SECONDS`: wait time before considering startup failed\n- `live_server_scope = session|function`: configure fixture scope in `pytest.ini`\n\nRecommended `pytest.ini` when tests need route registration before startup and better isolation:\n\n```ini\n[pytest]\naddopts = --no-start-live-server\nlive_server_scope = function\n```\n\nWhen you need the server's base URL in requests or browser automation, use `url_for(..., _external=True)` or the `live_server` URL helpers from the plugin rather than hard-coding `localhost`.\n\n## Request Context And Sessions\n\nOne of the main reasons to use `pytest-flask` instead of raw Flask fixtures is automatic request-context handling. That lets you write tests like this:\n\n```python\nfrom flask import session\n\ndef test_session_access(client):\n    client.get(\"/ping\")\n    session[\"seen\"] = True\n    assert session[\"seen\"] is True\n```\n\nFor session-dependent tests, make sure the fixture config sets a deterministic `SECRET_KEY`.\n\n## Configuration Notes\n\nThere is no package-level authentication model in `pytest-flask`. Configuration is about test process behavior and your Flask app settings.\n\nKeep these settings explicit in tests:\n\n- `TESTING = True`\n- `SECRET_KEY` set for session usage\n- `SERVER_NAME` if you rely on `url_for(..., _external=True)`\n- database or extension settings overridden to point at test resources\n\nA practical pattern is to centralize app config in the `app` fixture and use `pytest.mark.options` or the `config` fixture for test-specific overrides.\n\n## Common Pitfalls\n\n- `pytest-flask` requires an `app` fixture. Installing the plugin alone does not create a Flask application or register routes for you.\n- Do not treat Read the Docs `latest` as equivalent to released `1.3.0`. The official docs site currently mixes a stale `stable` build and a newer unreleased `latest` build.\n- `request_ctx` was removed in `1.3.0` for Flask 3.0 compatibility. If older tests or blog posts rely on it, rewrite them around `client`, `session`, `request`, or explicit Flask context managers.\n- `live_server` is session-scoped by default. That can leak routes or config between tests unless you set `live_server_scope = function`.\n- Fixed live-server ports are convenient for browser tools but can collide in parallel CI. Prefer the default random port unless an external dependency requires a known port.\n- If you add routes inside a `live_server` test, use `--no-start-live-server` and call `live_server.start()` after route registration.\n- The plugin will not overwrite a custom response class that already defines `json`. If your app customizes response behavior, test against your own response contract, not assumptions from older examples.\n\n## Version-Sensitive Notes\n\n- PyPI's latest released version is `1.3.0`, published on October 23, 2023.\n- The `1.3.0` release removed the deprecated `request_ctx` fixture and added compatibility fixes for Flask `3.0.0`.\n- The Read the Docs `stable` site still renders `1.2.0`, so it can miss released `1.3.0` changes.\n- The Read the Docs `latest` site shows a `1.3.1.dev...` build. Its changelog includes unreleased work such as Python `3.10`-`3.12` support, dropping `3.7`, and improved typing. Treat those items as upcoming or branch-head behavior until a newer PyPI release exists.\n- PyPI metadata still declares `Python >=3.7`. If your project is on modern Python, that is probably fine in practice, but for strict compatibility claims prefer the released metadata over the unreleased docs.\n\n## Official Sources\n\n- Docs index: `https://pytest-flask.readthedocs.io/en/latest/`\n- Tutorial: `https://pytest-flask.readthedocs.io/en/latest/tutorial.html`\n- Features and fixtures: `https://pytest-flask.readthedocs.io/en/latest/features.html`\n- Changelog: `https://pytest-flask.readthedocs.io/en/latest/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-flask/`\n"
  },
  {
    "path": "content/pytest/docs/html/python/DOC.md",
    "content": "---\nname: html\ndescription: \"pytest-html package guide for Python projects generating HTML test reports from pytest runs\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-html,pytest,testing,html,reporting\"\n---\n\n# pytest-html Python Package Guide\n\n## Golden Rule\n\nUse `pytest-html` as a pytest plugin, not as a standalone reporting tool. Install the package into the same environment as `pytest`, generate reports with `--html=...`, and prefer the official user guide for hook behavior and report customization.\n\nAs of March 12, 2026, the package metadata and maintainer release notes are current for `4.2.0`, but parts of the Read the Docs site still lag that release. PyPI and the maintainer release notes are the safer source for version and compatibility facts.\n\n## Install\n\nInstall `pytest-html` into the same environment as your test suite:\n\n```bash\npython -m pip install \"pytest-html==4.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-html==4.2.0\"\npoetry add --group dev \"pytest-html==4.2.0\"\n```\n\nVerify the plugin is available:\n\n```bash\npytest --help | rg -- --html\n```\n\n## Basic Usage\n\nGenerate an HTML report from a normal pytest run:\n\n```bash\npytest --html=report.html\n```\n\nGenerate a self-contained report that inlines CSS and JavaScript:\n\n```bash\npytest --html=report.html --self-contained-html\n```\n\nThe plugin is auto-discovered by pytest after installation. You do not need to import anything for the basic CLI flow.\n\n## Project Setup\n\nFor repeatable local and CI runs, put the default HTML report options in pytest config instead of repeating CLI flags.\n\n`pytest.ini`:\n\n```ini\n[pytest]\naddopts = --html=reports/pytest.html --self-contained-html\ngenerate_report_on_test = True\nrender_collapsed = all\ninitial_sort = result\nenvironment_table_redact_list =\n    (?i).*token.*\n    (?i).*secret.*\n```\n\nEquivalent `pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"--html=reports/pytest.html --self-contained-html\"\ngenerate_report_on_test = true\nrender_collapsed = \"all\"\ninitial_sort = \"result\"\nenvironment_table_redact_list = [\n  \"(?i).*token.*\",\n  \"(?i).*secret.*\",\n]\n```\n\nUseful config knobs from the official user guide:\n\n- `generate_report_on_test = True`: stream report updates during the run instead of writing only once at the end\n- `render_collapsed = all`: collapse all result rows initially\n- `initial_sort = result`: sort the report by test outcome on initial load\n- `environment_table_redact_list`: regex list for masking sensitive environment values in the Environment section\n\n## Core Customization\n\nPut report hooks in `conftest.py` or a dedicated pytest plugin.\n\n### Set a custom report title\n\n```python\ndef pytest_html_report_title(report):\n    report.title = \"My Project Test Report\"\n```\n\n### Add environment metadata\n\nThe Environment section is driven by `pytest-metadata`. Update it before `pytest-html` finalizes the report:\n\n```python\nimport os\n\nimport pytest\nfrom pytest_metadata.plugin import metadata_key\n\n@pytest.hookimpl(tryfirst=True)\ndef pytest_sessionfinish(session, exitstatus):\n    session.config.stash[metadata_key][\"git_sha\"] = os.getenv(\"GIT_SHA\", \"unknown\")\n    session.config.stash[metadata_key][\"build_id\"] = os.getenv(\"BUILD_ID\", \"local\")\n```\n\n### Attach extras on failures\n\nUse `report.extras` and helpers from `pytest_html.extras`:\n\n```python\nimport pytest\nfrom pytest_html import extras\n\n@pytest.hookimpl(hookwrapper=True)\ndef pytest_runtest_makereport(item, call):\n    outcome = yield\n    report = outcome.get_result()\n\n    if report.when != \"call\":\n        return\n\n    report.extras = getattr(report, \"extras\", [])\n\n    if report.failed:\n        report.extras.append(extras.text(\"request payload here\", name=\"payload\"))\n        report.extras.append(extras.url(\"https://ci.example.test/job/123\", name=\"CI job\"))\n```\n\nAvailable extra types in the official guide include raw HTML, JSON, text, URLs, and images.\n\n### Edit summary or results-table content\n\nCommon hooks:\n\n- `pytest_html_results_summary(prefix, summary, postfix)`\n- `pytest_html_results_table_header(cells)`\n- `pytest_html_results_table_row(report, cells)`\n\nUse these when you need to add columns, remove columns, or append custom summary content.\n\n## CI And Artifact Workflow\n\nTypical CI command:\n\n```bash\npytest --html=artifacts/pytest.html --self-contained-html\n```\n\nRecommended practice:\n\n- write the report into a stable artifacts directory\n- publish the HTML file as a CI artifact\n- prefer `--self-contained-html` when the artifact will be viewed outside the original workspace\n- keep attachments small if you add extras for every failure\n\n## Config And Security Notes\n\n`pytest-html` has no remote authentication model. The main security and configuration concerns are about what runtime data you expose in the report.\n\n- Treat the report as potentially sensitive test output.\n- Redact secrets in the Environment table with `environment_table_redact_list`.\n- Be careful with custom extras; they can embed raw HTML, URLs, logs, and payloads.\n- `--self-contained-html` does not safely inline every external asset you might attach. File and image references can still point outside the report.\n\n## Common Pitfalls\n\n- PyPI for `4.2.0` requires Python `>=3.9`, but the Read the Docs installation page still says Python `3.6+`. Use PyPI for compatibility facts.\n- The Read the Docs changelog page currently stops at `4.1.1`; use the maintainer `4.2.0` GitHub release page for the current release notes.\n- If you mutate environment metadata in `pytest_sessionfinish`, mark the hook with `@pytest.hookimpl(tryfirst=True)` or `pytest-html` may render the old values.\n- `--self-contained-html` is convenient for artifacts, but attached images and linked files can still trigger warnings or broken references.\n- For modern versions, use `report.extras`, not the deprecated `report.extra`.\n- The old `extra` fixture is deprecated; use the `extras` fixture or `pytest_html.extras`.\n- If you customize results-table columns, insert or remove entries from `cells`; older direct assignment patterns are deprecated.\n- `py.xml` is deprecated in the plugin ecosystem. Prefer plain strings or supported helpers in custom hooks.\n\n## Version-Sensitive Notes For 4.2.0\n\n- The maintainer `4.2.0` release adds support for Python `3.13`.\n- The maintainer `4.2.0` release adds support for `pytest 8.4`.\n- The maintainer `4.2.0` release drops support for Python `3.8`.\n- If you are upgrading older hooks, watch for deprecated patterns documented in the official deprecations page: `report.extra`, `extra` fixture naming, direct `cells` reassignment, `py.xml`, and older collapse-format values.\n\n## Official Sources Used\n\n- Docs root: https://pytest-html.readthedocs.io/en/latest/\n- User guide: https://pytest-html.readthedocs.io/en/latest/user_guide.html\n- Installation page: https://pytest-html.readthedocs.io/en/latest/installing.html\n- Deprecations: https://pytest-html.readthedocs.io/en/latest/deprecations.html\n- Changelog page: https://pytest-html.readthedocs.io/en/latest/changelog.html\n- PyPI: https://pypi.org/project/pytest-html/\n- Maintainer release notes: https://github.com/pytest-dev/pytest-html/releases/tag/4.2.0\n"
  },
  {
    "path": "content/pytest/docs/httpx/python/DOC.md",
    "content": "---\nname: httpx\ndescription: \"pytest-httpx package guide for mocking HTTPX requests in Python tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.36.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pytest-httpx,pytest,httpx,testing,mocking,python\"\n---\n\n# pytest-httpx Python Package Guide\n\n## Golden Rule\n\nUse `pytest-httpx` when your code under test uses `httpx`. The plugin installs a `httpx_mock` fixture that intercepts HTTPX requests and fails fast when requests or registered responses do not match your expectations.\n\nAs of `0.36.0`, the published package targets:\n\n- Python `>=3.10`\n- `pytest==9.*`\n- `httpx==0.28.*`\n\n## Install\n\nPin it alongside compatible `pytest` and `httpx` versions:\n\n```bash\npython -m pip install \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\n```\n\nCommon project-manager variants:\n\n```bash\nuv add \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\npoetry add --group test \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\n```\n\nIf you test `async` code, also install your async test runner, commonly:\n\n```bash\npython -m pip install \"pytest-asyncio>=1,<2\"\n```\n\n## Initialize In Tests\n\nThere is no manual setup step beyond installing the plugin. `pytest-httpx` exposes the `httpx_mock` fixture automatically through the pytest plugin entry point.\n\n```python\nimport httpx\n\ndef test_sync_client(httpx_mock):\n    httpx_mock.add_response(json={\"ok\": True})\n\n    with httpx.Client() as client:\n        response = client.get(\"https://api.example.com/health\")\n\n    assert response.json() == {\"ok\": True}\n```\n\nAsync tests work the same way:\n\n```python\nimport httpx\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_async_client(httpx_mock):\n    httpx_mock.add_response(status_code=202, json={\"queued\": True})\n\n    async with httpx.AsyncClient() as client:\n        response = await client.post(\"https://api.example.com/jobs\")\n\n    assert response.status_code == 202\n    assert response.json() == {\"queued\": True}\n```\n\nDefault response behavior if you do not pass arguments to `add_response()`:\n\n- status: `200`\n- protocol: `HTTP/1.1`\n- body: empty\n\n## Core Usage\n\n### Register a specific response\n\n```python\ndef test_post_json(httpx_mock):\n    httpx_mock.add_response(\n        method=\"POST\",\n        url=\"https://api.example.com/items\",\n        status_code=201,\n        json={\"id\": \"item_123\"},\n        headers={\"x-test\": \"pytest-httpx\"},\n    )\n```\n\nMatching is done against the full request. If several registrations match, the first unmatched one is used.\n\n### Match query parameters with `match_params`\n\n`0.36.0` added `match_params`, which is cleaner than encoding every query string variant into the URL:\n\n```python\nfrom unittest.mock import ANY\n\ndef test_partial_query_match(httpx_mock):\n    httpx_mock.add_response(\n        url=\"https://api.example.com/search\",\n        match_params={\"q\": \"books\", \"page\": ANY},\n        json={\"items\": []},\n    )\n```\n\nUse `match_params` only when the `url` does not already include query parameters.\n\n### Match headers, body, JSON, files, or HTTPX extensions\n\n```python\ndef test_match_request_shape(httpx_mock):\n    httpx_mock.add_response(\n        url=\"https://api.example.com/items\",\n        method=\"POST\",\n        match_headers={\"Authorization\": \"Bearer test-token\"},\n        match_json={\"name\": \"widget\"},\n        json={\"created\": True},\n    )\n```\n\nImportant exclusivity rules:\n\n- `match_json` cannot be combined with `match_content` or `match_files`\n- `match_files` cannot be combined with `match_content` or `match_json`\n\n### Return streamed or dynamic responses\n\n```python\nimport httpx\nfrom pytest_httpx import IteratorStream\n\ndef test_streaming(httpx_mock):\n    httpx_mock.add_response(stream=IteratorStream([b\"part-1\", b\"part-2\"]))\n\n    with httpx.Client() as client:\n        with client.stream(\"GET\", \"https://api.example.com/stream\") as response:\n            assert list(response.iter_raw()) == [b\"part-1\", b\"part-2\"]\n```\n\nCallbacks let the mocked response depend on the incoming request:\n\n```python\nimport httpx\n\ndef test_dynamic_response(httpx_mock):\n    def handler(request: httpx.Request) -> httpx.Response:\n        return httpx.Response(status_code=200, json={\"url\": str(request.url)})\n\n    httpx_mock.add_callback(handler)\n\n    with httpx.Client() as client:\n        response = client.get(\"https://api.example.com/test\")\n\n    assert response.json() == {\"url\": \"https://api.example.com/test\"}\n```\n\n### Raise transport errors\n\nUse `add_exception()` when the code path should handle HTTPX failures:\n\n```python\nimport httpx\nimport pytest\n\ndef test_timeout(httpx_mock):\n    httpx_mock.add_exception(httpx.ReadTimeout(\"read timed out\"))\n\n    with httpx.Client() as client:\n        with pytest.raises(httpx.ReadTimeout):\n            client.get(\"https://api.example.com/slow\")\n```\n\nIf no registered response matches, `pytest-httpx` raises `httpx.TimeoutException` immediately and includes mismatch details in the error message.\n\n## Checking What Was Sent\n\nPrefer strict request matching up front, but you can also inspect captured requests:\n\n```python\ndef test_capture_request(httpx_mock):\n    httpx_mock.add_response()\n\n    with httpx.Client() as client:\n        client.get(\"https://api.example.com/items\", headers={\"x-trace\": \"123\"})\n\n    request = httpx_mock.get_request()\n    assert request.headers[\"x-trace\"] == \"123\"\n```\n\nUse:\n\n- `httpx_mock.get_request()` for a single request\n- `httpx_mock.get_requests()` when multiple requests are expected\n\nThe same filtering rules used for response selection also apply when retrieving captured requests.\n\n## Configuration And Test-Suite Integration\n\n`pytest-httpx` does not have an auth model of its own. Configuration is done through the `@pytest.mark.httpx_mock(...)` marker.\n\n### Per-test configuration\n\n```python\nimport pytest\n\n@pytest.mark.httpx_mock(assert_all_responses_were_requested=False)\ndef test_optional_response(httpx_mock):\n    httpx_mock.add_response()\n```\n\n### Main options\n\n- `assert_all_responses_were_requested=False`: allow unused registered responses\n- `assert_all_requests_were_expected=False`: allow unmatched outgoing requests\n- `can_send_already_matched_responses=True`: reuse the last matching response after it has already been consumed\n- `should_mock=lambda request: ...`: let selected requests pass through for partial integration tests\n\nPrefer response-level controls when possible:\n\n- `is_optional=True` is narrower than disabling `assert_all_responses_were_requested`\n- `is_reusable=True` is narrower than enabling `can_send_already_matched_responses`\n\nExample partial pass-through:\n\n```python\nimport pytest\n\n@pytest.mark.httpx_mock(\n    should_mock=lambda request: request.url.host != \"localhost\"\n)\ndef test_local_server_and_remote_mock(httpx_mock):\n    httpx_mock.add_response(url=\"https://api.example.com/data\", json={\"ok\": True})\n```\n\n## Common Pitfalls\n\n- Do not use `pytest-httpx` for code that uses `requests`, `aiohttp`, or another HTTP client. It only intercepts `httpx`.\n- The plugin matches the full URL by default, including query parameters.\n- Query parameter order does not matter, but repeated-value order does.\n- If you use `match_params`, do not also include query parameters in `url`.\n- Unused registered responses fail the test at teardown unless you mark them optional or relax fixture settings.\n- Unexpected outgoing requests still raise `httpx.TimeoutException` even if `assert_all_requests_were_expected=False`; that option only prevents teardown failure for unmatched requests.\n- Suite-wide marker injection through `pytest_collection_modifyitems` is affected by a pytest marker-ordering bug documented upstream; module and class markers may be applied before the suite-level marker.\n\n## Version-Sensitive Notes\n\n- `0.36.0` adds `match_params`, adds Python `3.14` support, requires `pytest==9.*`, and drops Python `3.9` / pytest `8`.\n- `0.35.0` moved to `httpx==0.28.*`. Older test code pinned to HTTPX `0.27.*` needs an older `pytest-httpx`.\n- `0.34.0` added `is_optional` and `is_reusable`; before that, you had to rely more heavily on global marker options.\n\n## Official Sources\n\n- Docs: `https://colin-b.github.io/pytest_httpx/`\n- PyPI metadata: `https://pypi.org/project/pytest-httpx/` and `https://pypi.org/pypi/pytest-httpx/0.36.0/json`\n- Changelog: `https://github.com/Colin-b/pytest_httpx/blob/master/CHANGELOG.md`\n- Repository: `https://github.com/Colin-b/pytest_httpx`\n"
  },
  {
    "path": "content/pytest/docs/lazy-fixture/python/DOC.md",
    "content": "---\nname: lazy-fixture\ndescription: \"pytest-lazy-fixture package guide for parametrizing pytest tests with fixture values\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pytest,testing,fixtures,parametrize,plugin\"\n---\n\n# pytest-lazy-fixture Python Package Guide\n\n## What It Is\n\n`pytest-lazy-fixture` is a small pytest plugin that lets you reference fixtures inside `@pytest.mark.parametrize(...)` and fixture `params=[...]` lists.\n\nUse it when you want parametrized test cases to mix:\n\n- literal values\n- fixture-backed values\n- fixtures that are already parametrized themselves\n\nThe plugin is install-only under normal pytest plugin autoload. It registers a `pytest11` entry point and exposes both `from pytest_lazyfixture import lazy_fixture` and `pytest.lazy_fixture(...)`.\n\n## Install\n\nFor a new project, pin both the plugin and pytest explicitly. Upstream has an open issue for `pytest==8.0.0`, so `pytest<8` is the safe choice for this package version.\n\n```bash\npython -m pip install \"pytest-lazy-fixture==0.6.3\" \"pytest<8\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"pytest-lazy-fixture==0.6.3\" \"pytest<8\"\n```\n\nIf your environment already manages pytest separately:\n\n```bash\npython -m pip install \"pytest-lazy-fixture==0.6.3\"\n```\n\n## Initialize And Setup\n\nThere is no auth or remote configuration.\n\nMinimal setup:\n\n1. Install the package into the same environment as pytest.\n2. Import `lazy_fixture` in test modules, or use `pytest.lazy_fixture(...)`.\n3. Run tests normally with `pytest`.\n\nTypical import pattern:\n\n```python\nimport pytest\nfrom pytest_lazyfixture import lazy_fixture\n```\n\n## Core Usage\n\n### Use a fixture inside `@pytest.mark.parametrize`\n\n```python\nimport pytest\nfrom pytest_lazyfixture import lazy_fixture\n\n@pytest.fixture\ndef one():\n    return 1\n\n@pytest.mark.parametrize(\n    (\"label\", \"value\"),\n    [\n        (\"literal\", 0),\n        (\"fixture\", lazy_fixture(\"one\")),\n    ],\n)\ndef test_value(label, value):\n    assert value in {0, 1}\n```\n\n### Use a parametrized fixture as a single param source\n\n```python\nimport pytest\nfrom pytest_lazyfixture import lazy_fixture\n\n@pytest.fixture(params=[1, 2])\ndef one(request):\n    return request.param\n\n@pytest.mark.parametrize(\"value\", [lazy_fixture(\"one\")])\ndef test_parametrized_fixture(value):\n    assert value in {1, 2}\n```\n\nThis expands as you would expect: pytest generates one test per fixture parameter value.\n\n### Use lazy fixtures inside another fixture's `params`\n\n```python\nimport pytest\nfrom pytest_lazyfixture import lazy_fixture\n\n@pytest.fixture\ndef sqlite_url():\n    return \"sqlite:///test.db\"\n\n@pytest.fixture\ndef postgres_url():\n    return \"postgresql://localhost/test\"\n\n@pytest.fixture(params=lazy_fixture([\"sqlite_url\", \"postgres_url\"]))\ndef database_url(request):\n    return request.param\n\ndef test_database_url(database_url):\n    assert \"://\" in database_url\n```\n\n`lazy_fixture()` accepts either one fixture name or a list of fixture names.\n\n### `pytest.lazy_fixture(...)` also works\n\nThe plugin assigns `pytest.lazy_fixture = lazy_fixture` during pytest startup, so these are equivalent:\n\n```python\nfrom pytest_lazyfixture import lazy_fixture\n\nlazy_fixture(\"user\")\n```\n\n```python\nimport pytest\n\npytest.lazy_fixture(\"user\")\n```\n\nPrefer the direct import when you want explicit module dependencies and better static-analysis clarity.\n\n## Configuration Notes\n\nThis package has no dedicated config file and no runtime options of its own.\n\nThe only setup that usually matters is pytest version selection:\n\n- pin `pytest-lazy-fixture==0.6.3` if you need reproducible behavior\n- pin `pytest<8` unless you have locally verified a patched fork or workaround\n- keep the plugin in the same virtual environment as the `pytest` executable you run\n\n## Common Pitfalls\n\n### `pytest==8.x` breakage\n\nUpstream issue `#65` reports:\n\n- `pytest-lazy-fixture` does not work with `pytest==8.0.0`\n- the observed error is `AttributeError: 'CallSpec2' object has no attribute 'funcargs'`\n\nIf you hit that failure, the first fix is to downgrade pytest:\n\n```bash\npython -m pip install \"pytest<8\" --upgrade\n```\n\n### Do not treat it as normal fixture injection\n\n`lazy_fixture(...)` is only for places where pytest expects parameter values during collection, such as:\n\n- `@pytest.mark.parametrize(...)`\n- fixture `params=[...]`\n\nFor ordinary test dependencies, use regular fixture arguments:\n\n```python\ndef test_user(user):\n    assert user.id\n```\n\n### This plugin is sensitive to pytest internals\n\nThe implementation reaches into pytest internals such as `item.funcargs`, `metafunc._calls`, and `FixtureManager.getfixtureclosure()`. In practice, that makes the plugin version-sensitive when pytest changes collection internals.\n\nTreat this package as a compatibility shim, not a future-proof abstraction.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.6.3` as the latest release, published on February 1, 2020.\n- The published package metadata still declares Python classifiers only through Python 3.7.\n- The repository's GitHub releases UI is older than PyPI and shows `0.6.0` as the latest GitHub release entry, so use PyPI as the canonical package-version source.\n- The plugin source contains compatibility branches for older pytest series, including comments for `<3.6`, `3.6.x`, and `>=5.3`, which is another signal that behavior is tightly coupled to pytest internals.\n\n## Official Sources\n\n- GitHub repository: `https://github.com/TvoroG/pytest-lazy-fixture`\n- README / maintainer docs: `https://github.com/TvoroG/pytest-lazy-fixture`\n- Source file: `https://github.com/TvoroG/pytest-lazy-fixture/blob/master/pytest_lazyfixture.py`\n- Packaging metadata: `https://github.com/TvoroG/pytest-lazy-fixture/blob/master/setup.py`\n- PyPI registry page: `https://pypi.org/project/pytest-lazy-fixture/`\n- Pytest 8 compatibility issue: `https://github.com/TvoroG/pytest-lazy-fixture/issues/65`\n"
  },
  {
    "path": "content/pytest/docs/mock/python/DOC.md",
    "content": "---\nname: mock\ndescription: \"pytest-mock package guide for Python tests using the mocker fixture with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.15.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pytest,pytest-mock,mock,testing,fixtures\"\n---\n\n# pytest-mock Python Package Guide\n\n## Golden Rule\n\nUse `pytest-mock` when you want `unittest.mock`-style patching integrated with pytest fixture lifecycles. Install it in the same environment as pytest, use the `mocker` fixture instead of nested `with patch(...)` blocks, and patch names where the code under test looks them up.\n\n`pytest-mock 3.15.1` is the current PyPI release listed for this package, and the upstream docs for this version live at `https://pytest-mock.readthedocs.io/en/latest/`.\n\n## Install\n\nInstall `pytest-mock` into the same environment that runs your tests:\n\n```bash\npython -m pip install \"pytest>=6.2.5\" \"pytest-mock==3.15.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest>=6.2.5\" \"pytest-mock==3.15.1\"\npoetry add --group test \"pytest>=6.2.5\" \"pytest-mock==3.15.1\"\n```\n\nThe plugin is auto-discovered by pytest through the `pytest11` entry point, so a normal install is enough. You usually do not need to add anything to `conftest.py` or `pytest_plugins`.\n\n## Initialize And Verify Setup\n\nCreate a smoke test to confirm the fixture is available:\n\n```python\nimport os\n\ndef test_smoke(mocker):\n    mocked = mocker.patch(\"os.getcwd\", return_value=\"/tmp/project\")\n    assert mocked() == \"/tmp/project\"\n```\n\nRun:\n\n```bash\npytest\n```\n\nIf pytest reports `fixture 'mocker' not found`, the package is either not installed in the active environment or pytest is running under a different interpreter than the one where you installed it.\n\n## Core Usage\n\n### Basic patching\n\n`mocker` mirrors the `unittest.mock.patch` API, so standard `patch`, `patch.object`, `patch.multiple`, and `patch.dict` patterns still apply:\n\n```python\nimport os\n\ndef rm(path: str) -> None:\n    os.remove(path)\n\ndef test_rm_calls_os_remove(mocker) -> None:\n    remove = mocker.patch(\"os.remove\")\n\n    rm(\"file.txt\")\n\n    remove.assert_called_once_with(\"file.txt\")\n```\n\n### Prefer `autospec=True` when patching callables\n\n`autospec=True` catches wrong signatures earlier and is usually a better default for function or method patching:\n\n```python\nfrom pathlib import Path\n\ndef test_listdir(mocker) -> None:\n    listdir = mocker.patch.object(Path, \"iterdir\", autospec=True, return_value=[])\n\n    assert list(Path(\".\").iterdir()) == []\n    listdir.assert_called_once()\n```\n\n### Spy on real behavior\n\nUse `mocker.spy` when the real function should still run, but you want call assertions and access to return values:\n\n```python\nclass Calculator:\n    def double(self, value: int) -> int:\n        return value * 2\n\ndef test_spy(mocker) -> None:\n    calc = Calculator()\n    spy = mocker.spy(calc, \"double\")\n\n    assert calc.double(21) == 42\n    spy.assert_called_once_with(21)\n    assert spy.spy_return == 42\n```\n\n### Stub callbacks\n\n`mocker.stub()` is useful when your code accepts a callback and you only care that it was invoked with the right arguments:\n\n```python\ndef emit(handler):\n    handler(\"event\", ok=True)\n\ndef test_stub_callback(mocker) -> None:\n    handler = mocker.stub(name=\"handler\")\n\n    emit(handler)\n\n    handler.assert_called_once_with(\"event\", ok=True)\n```\n\n### Async support\n\n`mocker` exposes `AsyncMock`, and `mocker.spy` works with `async def` functions. You still need an async test runner such as `pytest-asyncio` for `@pytest.mark.asyncio` tests:\n\n```python\nimport pytest\n\nasync def fetch_name() -> str:\n    return \"context-hub\"\n\n@pytest.mark.asyncio\nasync def test_async_patch(mocker) -> None:\n    mocked = mocker.patch(__name__ + \".fetch_name\", new_callable=mocker.AsyncMock)\n    mocked.return_value = \"patched\"\n\n    assert await fetch_name() == \"patched\"\n    mocked.assert_awaited_once()\n```\n\n### Reset or stop selected patches\n\nUse `mocker.resetall()` to clear call history on mocks created so far. Use `mocker.stop(mock_or_spy)` to stop a specific patch or spy before the test ends.\n\n```python\nclass Greeter:\n    def hello(self) -> str:\n        return \"hello\"\n\ndef test_stop_spy(mocker) -> None:\n    greeter = Greeter()\n    spy = mocker.spy(greeter, \"hello\")\n\n    assert greeter.hello() == \"hello\"\n    assert spy.call_count == 1\n\n    mocker.stop(spy)\n    assert greeter.hello() == \"hello\"\n    assert spy.call_count == 1\n```\n\n### Other fixture scopes\n\nIf a test class, module, package, or session needs a wider-lived mock fixture, use:\n\n- `class_mocker`\n- `module_mocker`\n- `package_mocker`\n- `session_mocker`\n\nUse wider scopes carefully. They make state leakage between tests easier if you mutate mocks and forget to reset them.\n\n## Configuration\n\nMost projects need no plugin-specific configuration. Install the package and use `mocker`.\n\nThere is no external authentication model for this package. Setup is local to your pytest environment.\n\nIf you specifically want the separate `mock` package instead of `unittest.mock`, configure pytest with:\n\n```ini\n# pytest.ini\n[pytest]\nmock_use_standalone_module = true\n```\n\nThat option forces `pytest-mock` to import `mock` from PyPI instead of the standard-library `unittest.mock`.\n\n## Typing\n\n`pytest-mock` is fully type annotated. For annotated tests, import `MockerFixture` from `pytest_mock`:\n\n```python\nfrom pytest_mock import MockerFixture\n\ndef test_typed(mocker: MockerFixture) -> None:\n    mocked = mocker.patch(\"os.getcwd\", return_value=\"/tmp\")\n    assert mocked() == \"/tmp\"\n```\n\nFor newer versions, `MockType` and `AsyncMockType` are also available from `pytest_mock` if you need explicit annotations for mock objects.\n\n## Common Pitfalls\n\n- Patch where the code under test looks up the symbol, not where it was originally defined. `mocker.patch(\"module.symbol\")` still follows the same lookup rules as `unittest.mock.patch`.\n- Do not use `mocker.patch(...)` or `mocker.patch.object(...)` as a context manager or decorator through the fixture. The plugin warns about that usage because the fixture already manages cleanup. If you really need to patch a real context manager object, use `mocker.patch.context_manager(...)`.\n- Install `pytest-mock` in the test environment itself. A globally installed pytest plus a separate project virtualenv is a common source of `fixture 'mocker' not found`.\n- Prefer `autospec=True` for function and method patches when possible. Bare mocks can hide signature mistakes.\n- `mocker.resetall()` resets existing mocks; it does not replace a stopped patch. Use `mocker.stop(...)` or let fixture teardown clean up at test end.\n- Wider-scoped fixtures such as `session_mocker` are convenient but can leak state between tests if reused carelessly.\n\n## Version-Sensitive Notes For 3.15.1\n\n- `3.15.1` is the latest PyPI release as of March 11, 2026.\n- Starting in `3.15.0`, Python 3.8 is no longer supported. Stay on Python 3.9+ for this package line.\n- `3.15.0` added `spy_return_iter` for `mocker.spy` when the spied function returns an iterator.\n- `3.15.1` changes iterator duplication behavior: pass `duplicate_iterators=True` to `mocker.spy(...)` if you need a duplicated iterator in `spy_return_iter`.\n- `spy_return_list` was added in `3.13` and can be useful when you need the full history of return values from a spy.\n- `mocker.stop(...)` has been available since `3.10`; older examples that manually rebuild spies or rely on teardown-only cleanup can usually be simplified.\n\n## Official Sources\n\n- Documentation: `https://pytest-mock.readthedocs.io/en/latest/`\n- Usage guide: `https://pytest-mock.readthedocs.io/en/latest/usage.html`\n- Configuration: `https://pytest-mock.readthedocs.io/en/latest/configuration.html`\n- Remarks and typing: `https://pytest-mock.readthedocs.io/en/latest/remarks.html`\n- Changelog: `https://pytest-mock.readthedocs.io/en/latest/changelog.html`\n- Package metadata: `https://pypi.org/project/pytest-mock/`\n- Project metadata and dependencies: `https://github.com/pytest-dev/pytest-mock/blob/main/pyproject.toml`\n"
  },
  {
    "path": "content/pytest/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest package guide for Python with practical setup, fixtures, parametrization, plugin, and 9.0.x notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.0.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,testing,python,fixtures,assertions,plugins\"\n---\n\n# pytest Python Package Guide\n\n## What It Is\n\n`pytest` is the standard Python test runner for unit, integration, and plugin-driven test suites. It is designed around plain `assert` statements, fixture injection, powerful test selection, and a large plugin ecosystem.\n\nUse it when a Python project needs:\n\n- normal `test_*.py` / `*_test.py` discovery\n- concise assertions with good failure output\n- reusable setup via fixtures\n- parametrized tests\n- plugin-based behaviors like coverage, async support, or parallel execution\n\n## Install\n\nInstall `pytest` into the project environment and pin it if the test suite depends on 9.0 behavior:\n\n```bash\npython -m pip install \"pytest==9.0.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest==9.0.2\"\npoetry add --group dev \"pytest==9.0.2\"\n```\n\nIf you are authoring a package, also install your package in editable mode so tests exercise the local code cleanly:\n\n```bash\npython -m pip install -e .\n```\n\n## Write And Run A First Test\n\nCreate `tests/test_sample.py`:\n\n```python\ndef inc(x: int) -> int:\n    return x + 1\n\ndef test_inc() -> None:\n    assert inc(3) == 4\n```\n\nRun the suite:\n\n```bash\npytest\n```\n\nUseful variants:\n\n```bash\npytest -q\npytest -x --maxfail=1\npytest --pdb\npytest --durations=10\n```\n\n`pytest` discovers tests from configured `testpaths` or the current directory, then recurses into directories looking for `test_*.py` and `*_test.py`.\n\n## Recommended Layout And Config\n\nFor new projects, the upstream docs recommend a `src/` layout plus `--import-mode=importlib`.\n\nTypical layout:\n\n```text\npyproject.toml\nsrc/\n  mypkg/\n    __init__.py\ntests/\n  test_api.py\n  conftest.py\n```\n\nNative TOML config was added in `pytest 9.0`. Prefer `[tool.pytest]` in `pyproject.toml` for new work:\n\n```toml\n[tool.pytest]\nminversion = \"9.0\"\naddopts = [\"-ra\", \"--import-mode=importlib\"]\ntestpaths = [\"tests\"]\nmarkers = [\"slow\", \"integration\"]\nstrict = true\n```\n\nNotes:\n\n- `strict = true` enables `strict_config`, `strict_markers`, `strict_parametrization_ids`, and `strict_xfail`.\n- Use strict mode only when the project pins or locks the pytest version, because future strictness options may be added.\n- If you register custom markers, keep them in config so `--strict-markers` or strict mode does not break the suite.\n- `pytest.toml` and `.pytest.toml` now exist and take precedence over other config files, even when empty.\n- If you use `[tool.pytest]`, do not also use `[tool.pytest.ini_options]` in the same `pyproject.toml`.\n- Pytest does not merge multiple config files. The first matching config file wins.\n\nIf you use `src/` but do not install the package in editable mode, either run with `PYTHONPATH=src pytest` or set:\n\n```toml\n[tool.pytest]\npythonpath = [\"src\"]\n```\n\nIf you keep application code at the repository root instead of `src/`, `python -m pytest` can help because it also adds the current directory to `sys.path`.\n\n## Core Usage Patterns\n\n### Assertions And Exceptions\n\nUse plain `assert` statements. Pytest rewrites them to provide useful failure output.\n\n```python\nimport pytest\n\ndef normalize(name: str) -> str:\n    if not name:\n        raise ValueError(\"name must not be empty\")\n    return name.strip().lower()\n\ndef test_normalize() -> None:\n    assert normalize(\"  Ada  \") == \"ada\"\n\ndef test_normalize_rejects_empty() -> None:\n    with pytest.raises(ValueError, match=\"must not be empty\"):\n        normalize(\"\")\n```\n\nUse `pytest.raises()` for exceptions your code intentionally raises. Use `xfail(raises=...)` only when documenting a known bug or dependency issue.\n\n### Fixtures\n\nFixtures provide dependency injection for setup and teardown. Put shared fixtures in `tests/conftest.py`.\n\n```python\nimport pytest\n\n@pytest.fixture(scope=\"session\")\ndef base_url() -> str:\n    return \"https://api.example.test\"\n\n@pytest.fixture\ndef auth_headers(monkeypatch: pytest.MonkeyPatch) -> dict[str, str]:\n    monkeypatch.setenv(\"API_TOKEN\", \"test-token\")\n    return {\"Authorization\": \"Bearer test-token\"}\n```\n\nUse fixture scopes deliberately:\n\n- function scope for isolated mutable state\n- session scope for expensive shared setup\n- `yield` fixtures for teardown after the test finishes\n- `autouse=True` only for behavior that truly applies to every test in the scope\n\nExample `yield` fixture:\n\n```python\nimport sqlite3\n\nimport pytest\n\n@pytest.fixture\ndef db_conn(tmp_path):\n    db_path = tmp_path / \"app.db\"\n    conn = sqlite3.connect(db_path)\n    yield conn\n    conn.close()\n```\n\n### Parametrization\n\nUse `@pytest.mark.parametrize` to cover input matrices without copy-pasting tests.\n\n```python\nimport pytest\n\n@pytest.mark.parametrize(\n    (\"raw\", \"expected\"),\n    [\n        (\"Ada\", \"ada\"),\n        (\"  Grace  \", \"grace\"),\n        pytest.param(\"\", None, marks=pytest.mark.xfail),\n    ],\n)\ndef test_normalize_cases(raw: str, expected: str | None) -> None:\n    if expected is None:\n        pytest.xfail(\"empty names are rejected\")\n    assert raw.strip().lower() == expected\n```\n\nWhen strict mode is enabled, duplicate generated parameter IDs become errors. Add explicit `ids=[...]` when parametrization labels must stay stable.\n\n### Useful Built-In Fixtures\n\n`tmp_path` gives each test an isolated temporary directory as a `pathlib.Path`:\n\n```python\ndef test_writes_file(tmp_path) -> None:\n    output = tmp_path / \"out.txt\"\n    output.write_text(\"ok\", encoding=\"utf-8\")\n    assert output.read_text(encoding=\"utf-8\") == \"ok\"\n```\n\nPrefer `tmp_path` and `tmp_path_factory` over legacy `tmpdir` / `tmpdir_factory`.\n\n`monkeypatch` is the standard way to patch environment variables, module attributes, working directory, or `sys.path` during a test:\n\n```python\nfrom pathlib import Path\n\ndef test_home_dir(monkeypatch) -> None:\n    monkeypatch.setattr(Path, \"home\", lambda: Path(\"/tmp/test-home\"))\n    assert str(Path.home()) == \"/tmp/test-home\"\n```\n\n`caplog` lets you assert on logs:\n\n```python\nimport logging\n\ndef test_logs(caplog) -> None:\n    logging.getLogger().info(\"boot complete\")\n    assert (\"root\", logging.INFO, \"boot complete\") in caplog.record_tuples\n```\n\n## Running And Selecting Tests\n\nCommon selectors:\n\n```bash\npytest tests/test_api.py\npytest tests/test_api.py::test_create_user\npytest tests/test_api.py::TestUsers::test_create_user\npytest -k \"create_user and not slow\"\npytest -m \"not integration\"\npytest --pyargs mypkg\npytest --fixtures -q\npytest -h\n```\n\nKey behavior:\n\n- `-k` filters by names and extra keywords.\n- `-m` filters by marker expressions.\n- `--pyargs mypkg` is useful when tests live inside the installed package.\n- `python -m pytest` behaves almost the same as `pytest`, but also adds the current directory to `sys.path`.\n\n## Plugins, Async Tests, And Startup Control\n\nPytest has a large plugin ecosystem, but plugin loading can surprise you in CI or editor-integrated runs.\n\nImportant controls:\n\n- `required_plugins` can force required plugins to be present before the suite runs.\n- `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1` disables auto-loading third-party plugins from the environment.\n- `pytest -p plugin_name` loads a plugin explicitly.\n- `pytest -p no:plugin_name` disables a plugin explicitly.\n\nAsync tests are version-sensitive:\n\n- Since `8.4`, `async def` tests fail instead of warning-and-skipping when no suitable async plugin is installed.\n- For asyncio tests, install and configure something like `pytest-asyncio`.\n- Keep async fixtures and async test plugins aligned; mismatches are a common source of collection or fixture setup errors.\n\n## Common Pitfalls\n\n- Do not mix `[tool.pytest]` and `[tool.pytest.ini_options]` in the same `pyproject.toml`.\n- Do not assume multiple config files merge. A stray empty `pytest.toml` or `pytest.ini` can silently override the config you expected.\n- If tests import local package code incorrectly, check layout first: `src/` layout, editable install, `pythonpath`, and `--import-mode=importlib` usually fix the problem cleanly.\n- Keep shared fixtures in `conftest.py`, but avoid turning it into a grab bag of hidden global state.\n- Register custom markers in config before enabling strict markers or strict mode.\n- Prefer `tmp_path` over legacy `tmpdir`.\n- Use `pytest.raises(..., match=...)` for your own exception contracts instead of broad `except` blocks inside tests.\n- `pytest.main()` is fine for one-off invocation from Python code, but repeated calls in the same process are not recommended because Python import caching means file changes will not be reflected between runs.\n- Plugin autoload can make local runs differ from CI. Disable autoload or require explicit plugins when reproducibility matters.\n\n## Version-Sensitive Notes For 9.0.x\n\n- `pytest 9.0` added native TOML configuration with `[tool.pytest]`, plus `pytest.toml` / `.pytest.toml`.\n- `pytest 9.0` added `strict = true` as a bundled strict-mode switch.\n- `strict_xfail` is the 9.0 name; `xfail_strict` is still accepted as an alias.\n- `pytest 9.0.2` is the latest PyPI release as of March 12, 2026.\n- `pytest 9.0.2` changed the terminal progress plugin defaults on non-Windows platforms. If your local output changed after upgrading, check terminal progress settings and related plugins before assuming collection is broken.\n\n## Official Sources\n\n- Docs root: `https://docs.pytest.org/en/stable/`\n- API reference: `https://docs.pytest.org/en/stable/reference/reference.html`\n- Configuration reference: `https://docs.pytest.org/en/stable/reference/customize.html`\n- Good practices: `https://docs.pytest.org/en/stable/explanation/goodpractices.html`\n- Invocation guide: `https://docs.pytest.org/en/stable/how-to/usage.html`\n- Changelog: `https://docs.pytest.org/en/stable/changelog.html`\n- PyPI: `https://pypi.org/project/pytest/`\n"
  },
  {
    "path": "content/pytest/docs/randomly/python/DOC.md",
    "content": "---\nname: randomly\ndescription: \"pytest-randomly plugin guide for pytest test ordering and reproducible random seeds in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,pytest-randomly,testing,python,random,seeding\"\n---\n\n# pytest-randomly Python Package Guide\n\n## Golden Rule\n\nUse `pytest-randomly` as an automatically loaded pytest plugin, and treat the printed seed as the first debugging artifact when order-dependent failures appear.\n\nAs of March 12, 2026, the version used here `4.0.1` still matches PyPI. The current maintainer README on the `main` branch describes the same core workflow, but it also says current branch support is Python 3.10 to 3.14, while the PyPI release metadata for `4.0.1` still declares `Requires-Python >=3.9`. That likely reflects main-branch support moving ahead of the last release.\n\n## Install\n\nInstall it into the same environment as `pytest`:\n\n```bash\npython -m pip install \"pytest-randomly==4.0.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-randomly==4.0.1\"\npoetry add --group test \"pytest-randomly==4.0.1\"\n```\n\nIf you just need the latest compatible release:\n\n```bash\npython -m pip install pytest-randomly\n```\n\n## How It Works\n\n`pytest-randomly` is a pytest plugin, not a library you normally import in tests. Once installed, pytest auto-discovers it and applies these behaviors by default:\n\n- Randomizes test order by module, then class, then function.\n- Prints a base seed at the start of the run.\n- Resets Python's global `random.seed()` before test setup, run, and teardown.\n- Resets supported libraries' random state when they are installed, including `factory_boy`, `Faker`, `Model Bakery`, and NumPy's legacy random state.\n- Works with `pytest-xdist`.\n\n## Basic Usage\n\nRun pytest normally:\n\n```bash\npytest\n```\n\nYou should see a line like:\n\n```text\nUsing --randomly-seed=1553614239\n```\n\nReuse that seed to reproduce an order-dependent or random-data-dependent failure:\n\n```bash\npytest --randomly-seed=1553614239\n```\n\nYou can also reuse the last stored seed:\n\n```bash\npytest --randomly-seed=last\n```\n\n`last` depends on pytest's cache provider. If the `cacheprovider` plugin is disabled, use an explicit integer seed instead.\n\n## Project Setup\n\nPersist your preferred behavior in pytest config so local runs and CI use the same defaults.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"--randomly-seed=last\"\n```\n\nEquivalent `pytest.ini`:\n\n```ini\n[pytest]\naddopts = --randomly-seed=last\n```\n\nFor CI, prefer one of these approaches:\n\n- Use `--randomly-seed=last` when the cache is preserved between runs.\n- Use an explicit seed in reruns when reproducing a specific failure.\n- Let normal runs randomize freely so hidden inter-test dependencies keep surfacing.\n\n## Useful Flags\n\nKeep the default behavior unless you have a concrete reason to narrow it.\n\nDisable only the per-test reseeding:\n\n```bash\npytest --randomly-dont-reset-seed\n```\n\nDisable only test reordering:\n\n```bash\npytest --randomly-dont-reorganize\n```\n\nDisable the plugin entirely:\n\n```bash\npytest -p no:randomly\n```\n\n## Core Debugging Workflow\n\nWhen a failure appears only under a specific order:\n\n1. Re-run with the printed seed.\n2. Narrow the target to the failing module or class while keeping the same seed.\n3. Look for leaked global state, shared fixtures, database residue, monkeypatches not undone, or random test data that was never pinned.\n\nExample:\n\n```bash\npytest --randomly-seed=1234 tests/test_orders.py\npytest --randomly-seed=1234 tests/test_orders.py::TestCheckoutFlow\n```\n\nBecause ordering is module -> class -> function, narrowing the scope while keeping the same seed is often the fastest way to isolate the dependency.\n\n## Integration With Random-Using Libraries\n\n`pytest-randomly` can reset more than the stdlib RNG:\n\n- `factory_boy`\n- `Faker`\n- `Model Bakery`\n- NumPy legacy random state\n\nThis is useful when tests generate data through factories or fake data providers and still need deterministic reproduction from one seed.\n\nIf your own package has another random generator, you can register a setuptools entry point so `pytest-randomly` reseeds it for every test.\n\n`setup.cfg`:\n\n```ini\n[options.entry_points]\npytest_randomly.random_seeder =\n    mypackage = mypackage.reseed\n```\n\nImplement the callable to accept the new integer seed:\n\n```python\ndef reseed(new_seed: int) -> None:\n    ...\n```\n\n## Config And Auth\n\nThere is no auth or service configuration. The only setup is pytest/plugin configuration.\n\nConfiguration surface to care about in practice:\n\n- CLI flags such as `--randomly-seed`, `--randomly-dont-reset-seed`, and `--randomly-dont-reorganize`\n- shared pytest config in `pyproject.toml` or `pytest.ini`\n- optional pytest plugin loading control with `-p no:randomly`\n- optional `pytest_randomly.random_seeder` entry points for custom RNGs\n\n## Common Pitfalls\n\n- Do not try to `import pytest_randomly` in normal test code just to \"activate\" it. Installation is enough.\n- Do not ignore the printed seed when a flaky failure appears. Without it, reproducing the same order is much harder.\n- `--randomly-seed=last` only works when pytest cache is available.\n- If tests implicitly rely on process-global RNG state, installing this plugin can surface failures immediately. That is usually the point, not a plugin bug.\n- NumPy support only covers the legacy random state. If your test suite uses `numpy.random.default_rng()`, verify your own reproducibility strategy.\n- If you disable reordering to make failures disappear, you may hide real inter-test dependencies instead of fixing them.\n- When combining with `pytest-order`, read that plugin's docs for interaction rules instead of assuming both plugins will preserve your intended order automatically.\n\n## Version-Sensitive Notes For 4.0.1\n\n- PyPI shows `pytest-randomly 4.0.1` released on September 12, 2025.\n- PyPI release metadata for `4.0.1` declares `Requires-Python >=3.9`.\n- The current GitHub README says the `main` branch supports Python 3.10 to 3.14. Treat that as newer maintainer guidance for current development, not necessarily a strict statement about the already-published `4.0.1` wheel.\n- The docs URL points to the GitHub repository, which is the canonical maintainer doc surface for this package; there is no separate hosted documentation site to prefer here.\n\n## Official Sources\n\n- Maintainer docs and usage guide: https://github.com/pytest-dev/pytest-randomly\n- Package registry and release metadata: https://pypi.org/project/pytest-randomly/\n"
  },
  {
    "path": "content/pytest/docs/snapshot/python/DOC.md",
    "content": "---\nname: snapshot\ndescription: \"pytest-snapshot package guide for snapshot testing with pytest fixtures and file-based snapshots\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-snapshot,pytest,python,testing,snapshots\"\n---\n\n# pytest-snapshot Python Package Guide\n\n## What It Is\n\n`pytest-snapshot` is a small pytest plugin for file-based snapshot testing. Once installed, tests get a `snapshot` fixture that can compare strings or bytes against snapshot files on disk and update those files with explicit CLI flags.\n\nThe package is still published at `0.9.0`, and PyPI shows that `0.9.0` is the latest release as of March 12, 2026. The upstream source of truth is the maintainer GitHub repo README plus the plugin implementation itself.\n\n## Install\n\nInstall it into the same environment that runs pytest:\n\n```bash\npython -m pip install pytest-snapshot==0.9.0\n```\n\nWith uv:\n\n```bash\nuv add --dev pytest-snapshot==0.9.0\n```\n\nWith Poetry:\n\n```bash\npoetry add --group dev pytest-snapshot==0.9.0\n```\n\n`pytest-snapshot` is a test-only dependency. It belongs in the test environment, not your application runtime dependencies.\n\n## Initialize And First Run\n\nAfter installation, write tests that accept the `snapshot` fixture. You do not import `snapshot` directly; pytest provides it.\n\nMinimal example:\n\n```python\ndef render_user(user_id: int) -> str:\n    return f\"user:{user_id}\\nactive:true\\n\"\n\ndef test_render_user(snapshot):\n    snapshot.snapshot_dir = \"snapshots\"\n    snapshot.assert_match(render_user(123), \"render_user.txt\")\n```\n\nFirst create or refresh snapshots with:\n\n```bash\npytest --snapshot-update\n```\n\nThen rerun normal verification without the update flag:\n\n```bash\npytest\n```\n\nImportant behavior: when `--snapshot-update` creates, changes, or deletes snapshot files, the run still fails on purpose so you review the diff and rerun tests normally.\n\n## Core Usage\n\n### Compare one string or bytes payload\n\nUse `snapshot.assert_match(value, snapshot_name)` for a single file snapshot.\n\n```python\nimport json\n\ndef make_payload():\n    return {\"name\": \"Ada\", \"roles\": [\"admin\", \"author\"]}\n\ndef test_payload(snapshot):\n    snapshot.snapshot_dir = \"snapshots\"\n    payload = json.dumps(make_payload(), indent=2, sort_keys=True) + \"\\n\"\n    snapshot.assert_match(payload, \"payload.json\")\n```\n\nThe value must be `str` or `bytes`. For dicts, lists, or custom objects, serialize first.\n\n### Compare a directory tree\n\nUse `snapshot.assert_match_dir(mapping, snapshot_dir_name)` when output is naturally multiple files. The README documents nested dict support, which becomes nested directories under the snapshot root.\n\n```python\ndef test_generated_site(snapshot):\n    snapshot.snapshot_dir = \"snapshots\"\n    snapshot.assert_match_dir(\n        {\n            \"index.html\": \"<h1>Home</h1>\\n\",\n            \"posts\": {\n                \"hello.txt\": \"hello\\n\",\n                \"about.txt\": \"about\\n\",\n            },\n        },\n        \"site\",\n    )\n```\n\nThis is useful for generators, codegen, config trees, and multi-file exports where one golden file is too coarse.\n\n### Default snapshot location\n\nIf you do not set `snapshot.snapshot_dir`, the plugin derives a directory automatically under:\n\n```text\nsnapshots/<test_module_stem>/<test_name>\n```\n\nFor parametrized tests, the parameter id is appended as another path segment. Use an explicit `snapshot.snapshot_dir` when you want stable paths shared across helpers or multiple tests.\n\n### Snapshot names are paths\n\n`snapshot_name` can include subdirectories:\n\n```python\ndef test_reports(snapshot):\n    snapshot.snapshot_dir = \"snapshots\"\n    snapshot.assert_match(\"ok\\n\", \"reports/daily/status.txt\")\n```\n\nPaths are resolved relative to `snapshot.snapshot_dir`. Absolute paths are only valid if they still live inside that snapshot root.\n\n## Update And Deletion Workflow\n\nRefresh existing snapshots:\n\n```bash\npytest --snapshot-update\n```\n\nAllow deletion of stale files during directory snapshot updates:\n\n```bash\npytest --snapshot-update --allow-snapshot-deletion\n```\n\nUse the deletion flag carefully. Without it, `assert_match_dir(...)` will report extra snapshot files instead of silently removing them.\n\nRecommended team workflow:\n\n1. Run `pytest --snapshot-update` after intentional output changes.\n2. Review the changed snapshot files in git.\n3. Rerun plain `pytest` to verify the updated snapshots now pass.\n\n## Config And Auth\n\nThere is no service authentication, API key setup, or network configuration.\n\nProject-level configuration is mostly:\n\n- whether to rely on the default snapshot directory layout or set `snapshot.snapshot_dir` explicitly\n- whether CI ever allows snapshot updates, which is usually `no`\n- whether local update flows also allow deletions with `--allow-snapshot-deletion`\n- how structured data is normalized before snapshotting\n\nFor stable diffs, normalize before snapshotting:\n\n- JSON: `json.dumps(..., indent=2, sort_keys=True) + \"\\n\"`\n- timestamps, UUIDs, temp paths: replace or freeze them first\n- platform-specific paths or line endings: normalize them before assertion\n\n## Common Pitfalls\n\n- `--snapshot-update` is not a green build mode. The plugin intentionally fails after modifying snapshot files so you notice and review the changes.\n- Only `str` and `bytes` are accepted snapshot payloads. Serialize Python objects yourself instead of passing raw dicts or lists.\n- Strings containing carriage returns (`\\r`) are rejected by the plugin. If your content really needs CRLF semantics, snapshot bytes instead.\n- If you do not set `snapshot.snapshot_dir`, the generated default path depends on the test file name, test name, and parametrization id. That can surprise refactors.\n- `assert_match_dir(...)` compares the directory contents exactly. Renamed or removed files will fail until you rerun with both `--snapshot-update` and, if needed, `--allow-snapshot-deletion`.\n- Snapshot names must stay inside the snapshot root. Do not try to escape the directory with absolute paths or `..` segments.\n- This package has not shipped a new release since `0.9.0` in April 2022. If your project is on much newer pytest or Python releases, verify behavior in your environment instead of assuming recent ecosystem changes are reflected upstream.\n\n## Version-Sensitive Notes\n\n- PyPI lists `0.9.0` as the latest release, published on April 23, 2022.\n- The published package metadata still advertises broad minimum compatibility: Python `>=3.5` and `pytest>=3.0.0`.\n- The repository README and plugin source are the canonical docs. There is no separate hosted documentation site.\n- Because the release is old, prefer direct upstream examples and source behavior over third-party blog posts, especially for recent pytest versions.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/pytest-snapshot/`\n- Maintainer repository: `https://github.com/joseph-roitman/pytest-snapshot`\n- Upstream README: `https://raw.githubusercontent.com/joseph-roitman/pytest-snapshot/master/README.rst`\n- Plugin implementation: `https://raw.githubusercontent.com/joseph-roitman/pytest-snapshot/master/pytest_snapshot/plugin.py`\n"
  },
  {
    "path": "content/pytest/docs/sugar/python/DOC.md",
    "content": "---\nname: sugar\ndescription: \"pytest-sugar plugin guide for prettier pytest output, progress bars, and Playwright trace hints\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,testing,terminal,ci,playwright\"\n---\n\n# pytest-sugar Python Package Guide\n\n## Golden Rule\n\nUse `pytest-sugar` only as a pytest UI plugin. It changes terminal output, adds a progress bar, and can surface Playwright trace locations, but it does not replace normal pytest configuration or failure semantics.\n\nAs of March 12, 2026, the version used here `1.1.1` still matches the latest PyPI release. The PyPI project description is partly stale for requirements; the current maintainer repo for the `1.1.x` line has moved beyond the older `Python 3.8` / `pytest 6.2` floor shown in the long description.\n\n## Install\n\nInstall it into the same environment as `pytest`:\n\n```bash\npython -m pip install \"pytest-sugar==1.1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pytest-sugar==1.1.1\"\npoetry add \"pytest-sugar==1.1.1\"\n```\n\nRun tests normally after install:\n\n```bash\npytest\n```\n\nThe plugin activates automatically when pytest loads installed plugins.\n\n## Core Usage\n\n### Default behavior\n\nAfter installation, `pytest-sugar` replaces pytest's standard progress/output view with a progress bar and prints failures as they happen.\n\n```bash\npytest\n```\n\n### Verbose mode\n\nUse verbose mode if you want one test per line instead of the condensed progress UI:\n\n```bash\npytest --verbose\n```\n\n### Disable sugar for a run\n\nIf a CI log parser or another plugin expects plain pytest output, disable `pytest-sugar` explicitly:\n\n```bash\npytest -p no:sugar\n```\n\n## Important CLI Options\n\n### Show the older detailed summary format\n\n```bash\npytest --old-summary\n```\n\nUse this when the one-line instant failure display is too compact and you want a more traditional detailed summary.\n\n### Force sugar output in non-interactive environments\n\n```bash\npytest --force-sugar\n```\n\nUse this in CI, containers, or other environments where pytest does not think it is attached to a real terminal.\n\n### Control Playwright trace lookup\n\nBy default, the plugin looks for Playwright traces in the default Playwright Python output directory, `test-results`.\n\n```bash\npytest --sugar-trace-dir artifacts/playwright\n```\n\nDisable trace lookup entirely if it adds noise:\n\n```bash\npytest --sugar-no-trace\n```\n\n## Project Configuration\n\n### Pytest config\n\n`pytest-sugar` does not need credentials or network configuration. For most projects, configuration lives in normal pytest config through `addopts`.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"-ra --force-sugar\"\n```\n\n`pytest.ini`:\n\n```ini\n[pytest]\naddopts = -ra --force-sugar\n```\n\n### Theme and progress bar config\n\nThe plugin also supports a dedicated `pytest-sugar.conf` file for UI tweaks such as theme symbols/colors and progress bar length.\n\n```ini\n[theme]\nsymbol_passed = ✓\nsymbol_failed = x\n\n[sugar]\nprogressbar_length = 30\n```\n\nUse this only for presentation tweaks. Keep real test behavior in pytest config, not in the sugar-specific file.\n\n## Practical Patterns\n\n### Local development\n\n```bash\npytest tests/unit\n```\n\nThis is the common case: auto-loaded plugin, compact progress display, failures shown immediately.\n\n### CI job with forced terminal-style output\n\n```bash\npytest --force-sugar --maxfail=1\n```\n\nThis is useful when CI captures stdout without a real TTY and you still want the sugar progress output.\n\n### Playwright end-to-end tests\n\n```bash\npytest tests/e2e --sugar-trace-dir test-results\n```\n\nIf Playwright writes traces on failures, `pytest-sugar` can point you to those artifacts from the test output.\n\n## Common Pitfalls\n\n- Do not treat `pytest-sugar` as a reporting backend. It is a terminal UX plugin, not a results store or HTML/JUnit replacement.\n- In CI or redirected output, the progress UI may not appear unless you add `--force-sugar`.\n- If another tool parses raw pytest output, disable sugar with `-p no:sugar` for that job.\n- The plugin's terminal formatting is most useful in human-facing runs; plain pytest is often better for machine-consumed logs.\n- Windows terminals can render odd glyphs or colors depending on font/charset settings. If output looks broken, simplify theme symbols or fall back to default pytest output.\n- Playwright trace hints depend on where traces are actually written. If your suite uses a non-default artifact directory, set `--sugar-trace-dir` explicitly.\n\n## Version-Sensitive Notes\n\n- PyPI release history shows `1.1.1` published on August 23, 2025.\n- The PyPI long description still advertises `Python 3.8+` and `pytest 6.2+`, but the maintainer repository for the current line has newer packaging constraints. Verify your environment against the repo's current packaging metadata if you are pinning old interpreters or old pytest versions.\n- The `1.1.x` line includes Playwright trace-related options such as `--sugar-trace-dir` and `--sugar-no-trace`. Older blog posts and screenshots from pre-`1.0` releases may not mention them.\n- If you need deterministic, minimal logs for tooling, prefer plain pytest output for that specific job even if developers use `pytest-sugar` locally.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/pytest-sugar/`\n- PyPI project JSON/API page: `https://pypi.org/pypi/pytest-sugar/`\n- Maintainer repository: `https://github.com/Teemu/pytest-sugar`\n- Changelog/releases source: `https://github.com/Teemu/pytest-sugar/blob/main/CHANGES.rst`\n"
  },
  {
    "path": "content/pytest/docs/timeout/python/DOC.md",
    "content": "---\nname: timeout\ndescription: \"pytest-timeout plugin guide for adding per-test and session time limits to pytest suites\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,testing,timeout,python,ci\"\n---\n\n# pytest-timeout Python Package Guide\n\n## Golden Rule\n\nUse `pytest-timeout` to stop hung or deadlocked test runs, not to measure performance. Pair any whole-suite timeout with a per-test timeout, because session timeouts are cooperative and do not interrupt a single stuck test by themselves.\n\n## Install\n\nInstall it alongside pytest in your test dependencies:\n\n```bash\npython -m pip install \"pytest>=7\" \"pytest-timeout==2.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-timeout==2.4.0\"\npoetry add --group dev \"pytest-timeout==2.4.0\"\n```\n\nThere is no runtime initialization code. After install, the plugin registers pytest options, ini settings, and the `timeout` marker automatically.\n\nCheck that pytest sees the plugin:\n\n```bash\npytest --help | rg timeout\n```\n\n## Quick Start\n\nSet a global timeout for the current run:\n\n```bash\npytest --timeout=30\n```\n\nAdd a session timeout as a second guardrail:\n\n```bash\npytest --timeout=30 --session-timeout=900\n```\n\nSet a timeout on one test only:\n\n```python\nimport pytest\n\n@pytest.mark.timeout(5)\ndef test_fast_path():\n    ...\n```\n\nOverride the method for one test:\n\n```python\nimport pytest\n\n@pytest.mark.timeout(10, method=\"thread\")\ndef test_might_deadlock():\n    ...\n```\n\nDisable a global timeout for one test:\n\n```python\nimport pytest\n\n@pytest.mark.timeout(0)\ndef test_intentionally_long():\n    ...\n```\n\n## Configuration\n\nTimeout precedence is:\n\n1. `timeout` value in pytest config\n2. `PYTEST_TIMEOUT` environment variable\n3. `--timeout` CLI option\n4. `@pytest.mark.timeout(...)` on a specific test\n\nExample `pytest.ini`:\n\n```ini\n[pytest]\ntimeout = 30\ntimeout_method = signal\nsession_timeout = 900\ntimeout_func_only = false\n```\n\nEquivalent `pyproject.toml` using pytest's standard ini-options table:\n\n```toml\n[tool.pytest.ini_options]\ntimeout = 30\ntimeout_method = \"signal\"\nsession_timeout = 900\ntimeout_func_only = false\n```\n\nYou can also set a default timeout from the environment:\n\n```bash\nexport PYTEST_TIMEOUT=30\npytest\n```\n\n## Choosing A Timeout Method\n\n`pytest-timeout` supports two timeout mechanisms:\n\n- `signal`: preferred on POSIX systems with `SIGALRM`; the test run can continue and pytest can fail the timed-out test normally\n- `thread`: the safest fallback; a timer thread terminates the whole process when the timeout expires\n\nUse the hyphenated CLI spelling in new scripts:\n\n```bash\npytest --timeout=30 --timeout-method=thread\n```\n\nOlder docs and examples may still show `--timeout_method`. The config key remains `timeout_method`.\n\nChoose `thread` when:\n\n- your code under test uses signals or `SIGALRM`\n- the signal method is unavailable on the platform\n- you need the most reliable interruption path for a truly wedged test\n\nChoose `signal` when:\n\n- you are on a POSIX platform with `SIGALRM`\n- preserving normal pytest teardown/reporting is more important than hard-stop reliability\n\n## Fixtures, Setup, And Teardown\n\nBy default, the timeout covers the whole test lifecycle:\n\n- fixture setup\n- test body\n- fixture teardown/finalizers\n\nIf fixture time should not count toward the limit, set `timeout_func_only = true` globally or per test:\n\n```python\nimport pytest\n\n@pytest.mark.timeout(10, func_only=True)\ndef test_only_the_function_body_is_timed():\n    ...\n```\n\nBe careful here. If a fixture is what hangs, `func_only=True` will not protect you from that setup/teardown stall.\n\n## Session Timeout\n\nUse `session_timeout` or `--session-timeout` to cap the full pytest invocation:\n\n```bash\npytest --timeout=15 --session-timeout=600\n```\n\nImportant behavior:\n\n- session timeout is checked between tests, not during a still-running test\n- a stuck test still needs a per-test timeout to be interrupted\n\n## Debugger Behavior\n\nThe plugin tries to avoid firing while a debugger is attached. This is convenient for local debugging, but it can hide timeouts if you forget the debugger is active.\n\nIf debugger detection is getting in the way, use the config setting:\n\n```ini\n[pytest]\ntimeout_disable_debugger_detection = true\n```\n\n## Common Pitfalls\n\n- Do not treat timeout failures as a substitute for making tests fast. The maintainers explicitly frame timeouts as a last resort.\n- `thread` mode can terminate the whole process with `os._exit()`. Expect lost teardown, truncated JUnit XML, and incomplete plugin cleanup in that failure path.\n- `signal` mode can conflict with code that already uses `SIGALRM`.\n- Fixture setup and teardown count toward the timeout unless you opt into `timeout_func_only`.\n- A decorator overrides `timeout_func_only = true` unless you pass `func_only=True` again on the marker.\n- Session timeout alone will not rescue a single permanently hung test.\n- Older docs may say timeout diagnostics are written to `stderr`; since `2.3.0`, pytest-timeout reports through pytest's `TerminalReporter`, which moves that output to `stdout`.\n\n## Version-Sensitive Notes For 2.4.0\n\n- `2.4.0` improves debugger detection for debuggers registered with `sys.monitoring`, which matters on newer Python runtimes and debugger integrations.\n- `2.3.0` raised the minimum supported pytest version to `7.0.0`. If you are pinned below pytest 7, do not assume modern `pytest-timeout` examples apply.\n- `2.3.0` added `--session-timeout` and the `session_timeout` config setting. Older versions do not have this whole-suite timeout feature.\n- The changelog changed the preferred CLI spelling from `--timeout_method` to `--timeout-method` long ago; use the hyphenated form in new commands even though old examples still exist.\n- PyPI verified metadata for `2.4.0` requires Python `>=3.7`. The project description still contains older prose saying \"Python 3.6 and higher\"; prefer the verified metadata.\n\n## Official Sources\n\n- GitHub repository: https://github.com/pytest-dev/pytest-timeout\n- PyPI package page for `2.4.0`: https://pypi.org/project/pytest-timeout/2.4.0/\n- PyPI latest page: https://pypi.org/project/pytest-timeout/\n- pytest configuration reference: https://docs.pytest.org/en/stable/reference/customize.html\n- pytest marker reference: https://docs.pytest.org/en/stable/how-to/mark.html\n"
  },
  {
    "path": "content/pytest/docs/xdist/python/DOC.md",
    "content": "---\nname: xdist\ndescription: \"pytest-xdist package guide for parallel pytest runs, worker-aware fixtures, and distributed test scheduling\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.8.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pytest,pytest-xdist,testing,parallelism,ci,python\"\n---\n\n# pytest-xdist Python Package Guide\n\n## Golden Rule\n\nUse `pytest-xdist` only to parallelize a suite that already passes reliably under plain `pytest`. When a failure is hard to understand, rerun with `-n 0` or without `-n` first. The plugin changes scheduling and process boundaries; it does not make nondeterministic tests safe.\n\n## Install\n\nPin the plugin to the version your project expects:\n\n```bash\npython -m pip install \"pytest-xdist==3.8.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-xdist==3.8.0\"\npoetry add --group dev \"pytest-xdist==3.8.0\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"pytest-xdist[psutil]==3.8.0\"\npython -m pip install \"pytest-xdist[setproctitle]==3.8.0\"\n```\n\nUse the `psutil` extra if you want better logical CPU detection for `-n logical`. Use the `setproctitle` extra if process titles in `ps` or `top` are useful while diagnosing stuck workers.\n\n## Minimal Setup\n\nThe plugin auto-registers with pytest after installation. There is no separate initialization step.\n\nRun a suite in parallel:\n\n```bash\npytest -n auto\n```\n\nUseful variants:\n\n```bash\npytest -n 4\npytest -n logical\npytest -n 0\n```\n\n- `-n auto` uses the machine's physical CPU cores.\n- `-n logical` uses logical cores when `psutil` can determine them; otherwise it falls back to `auto` behavior.\n- `-n 0` disables xdist and runs everything in the main process.\n\n## Project Configuration\n\nIf parallel execution is your default in CI, keep it explicit in pytest config rather than hiding it in shell scripts.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"-ra -n auto --dist loadscope\"\n```\n\nEquivalent `pytest.ini`:\n\n```ini\n[pytest]\naddopts = -ra -n auto --dist loadscope\n```\n\nIf worker count should depend on the environment, set the documented environment variable:\n\n```bash\nexport PYTEST_XDIST_AUTO_NUM_WORKERS=6\npytest -n auto\n```\n\nYou can also override auto-detection in code with the `pytest_xdist_auto_num_workers(config)` hook in `conftest.py`.\n\n## Core Usage Patterns\n\n### Basic parallel run\n\n```bash\npytest -n auto\n```\n\nThis is the default entry point for speeding up a CPU-bound or I/O-heavy suite.\n\n### Choose an explicit scheduler\n\n```bash\npytest -n auto --dist load\npytest -n auto --dist loadscope\npytest -n auto --dist loadfile\npytest -n auto --dist loadgroup\npytest -n auto --dist worksteal\n```\n\nDistribution modes that matter in practice:\n\n- `load`: default. Best general-purpose throughput, but test order is not guaranteed.\n- `loadscope`: keeps tests from the same module or class in the same worker. Good when module/class fixtures are expensive or stateful.\n- `loadfile`: keeps each file on one worker. Good when file-level setup or ordering matters.\n- `loadgroup`: keeps tests with the same `xdist_group` mark on one worker. Good for browser sessions, shared containers, or stateful service fixtures.\n- `worksteal`: starts with an even split and then steals queued tests from busy workers. Good when individual test durations vary a lot, but still expect some scheduling churn.\n\n### Keep related tests on the same worker\n\n```python\nimport pytest\n\n@pytest.mark.xdist_group(\"chrome\")\ndef test_login_in_chrome():\n    ...\n\n@pytest.mark.xdist_group(\"chrome\")\ndef test_checkout_in_chrome():\n    ...\n```\n\nRun with:\n\n```bash\npytest -n auto --dist loadgroup\n```\n\n### Control `loadscope` ordering in 3.8.0\n\n`pytest-xdist 3.8.0` added these options:\n\n```bash\npytest -n auto --dist loadscope --no-loadscope-reorder\npytest -n auto --dist loadscope --loadscope-reorder\n```\n\nUse `--no-loadscope-reorder` when relative file ordering matters and you still want `loadscope` grouping.\n\n## Worker-Aware Tests And Fixtures\n\n### Detect the current worker in a fixture\n\n```python\nimport pytest\n\n@pytest.fixture\ndef user_account(worker_id: str) -> str:\n    return f\"account_{worker_id}\"\n```\n\nWhen xdist is disabled, `worker_id` returns `\"master\"`. This makes it safe to share the same fixture implementation between local debugging and parallel CI runs.\n\n### Use worker environment variables\n\nWorkers expose these environment variables:\n\n- `PYTEST_XDIST_WORKER`: current worker name such as `gw0`\n- `PYTEST_XDIST_WORKER_COUNT`: total number of workers\n- `PYTEST_XDIST_TESTRUNUID`: unique id for the whole distributed run\n\nExample:\n\n```python\nimport os\n\ndef test_worker_env():\n    worker_name = os.getenv(\"PYTEST_XDIST_WORKER\", \"master\")\n    worker_count = int(os.getenv(\"PYTEST_XDIST_WORKER_COUNT\", \"1\"))\n    assert worker_count >= 1\n    assert worker_name\n```\n\n### Generate one resource per test run\n\nUse `testrun_uid` when multiple workers must share one logical namespace:\n\n```python\nimport pytest\n\n@pytest.fixture(scope=\"session\")\ndef database_name(testrun_uid: str) -> str:\n    return f\"test_db_{testrun_uid}\"\n```\n\nThis is the right pattern for temporary databases, buckets, queues, or directories that should be unique per CI run rather than per worker.\n\n### Session fixtures run once per worker, not once globally\n\nThis is one of the most important xdist behaviors: each worker performs collection and may execute high-scope fixtures separately. If a `session` fixture must happen exactly once, add your own inter-process locking.\n\nExample with `filelock`:\n\n```python\nimport json\nfrom pathlib import Path\n\nimport pytest\nfrom filelock import FileLock\n\ndef produce_expensive_data() -> dict[str, str]:\n    return {\"token\": \"generated-once\"}\n\n@pytest.fixture(scope=\"session\")\ndef session_data(tmp_path_factory: pytest.TempPathFactory, worker_id: str) -> dict[str, str]:\n    if worker_id == \"master\":\n        return produce_expensive_data()\n\n    root_tmp_dir = tmp_path_factory.getbasetemp().parent\n    data_file = Path(root_tmp_dir) / \"session-data.json\"\n\n    with FileLock(str(data_file) + \".lock\"):\n        if data_file.exists():\n            return json.loads(data_file.read_text())\n\n        data = produce_expensive_data()\n        data_file.write_text(json.dumps(data))\n        return data\n```\n\nInstall `filelock` yourself if you use this pattern; it is not part of the default runtime dependency set.\n\n## Logging And Diagnostics\n\nIf a worker crashes, xdist can restart it automatically. Cap restarts in CI when you want crashes to fail fast instead of being masked by repeated retries:\n\n```bash\npytest -n auto --max-worker-restart 2\npytest -n auto --max-worker-restart 0\n```\n\nTo emit one log file per worker, use `PYTEST_XDIST_WORKER` during `pytest_configure`:\n\n```python\nimport logging\nimport os\n\ndef pytest_configure(config):\n    worker_id = os.environ.get(\"PYTEST_XDIST_WORKER\")\n    if worker_id:\n        logging.basicConfig(\n            filename=f\"tests_{worker_id}.log\",\n            level=config.getini(\"log_file_level\"),\n            format=config.getini(\"log_file_format\"),\n        )\n```\n\nThis is a practical replacement for expecting interleaved stdout from workers in the terminal.\n\n## Common Pitfalls\n\n- `-s` and `--capture=no` do not work with `pytest-xdist`. Worker stdout and stderr are not streamed back live through `execnet`.\n- `--pdb` is disabled during distributed runs. Reproduce the failure with `-n 0` or without `-n` before interactive debugging.\n- Test collection order must be identical across workers. Do not parametrize from unordered sets, generators with unstable iteration, or environment-dependent discovery.\n- `session` fixtures are not global across all workers. If a resource must be created once, add locking or centralize creation outside pytest.\n- Shared temp files, ports, and database names must be made worker-aware or run-aware. `worker_id` and `testrun_uid` exist for this.\n- `load` maximizes throughput but can increase fixture churn. Switch to `loadscope`, `loadfile`, or `loadgroup` when setup cost or state affinity matters.\n- Keep flaky tests and race-sensitive assertions out of parallel mode until they are deterministic in single-process runs.\n\n## Version-Sensitive Notes For 3.8.0\n\n- `pytest-xdist 3.8.0` was released on July 1, 2025 on PyPI.\n- The 3.8.0 changelog adds `--no-loadscope-reorder` and `--loadscope-reorder` for `loadscope` scheduling. Use them if relative ordering matters inside loadscope groups.\n- The 3.7.0 release added Python 3.13 support and dropped Python 3.8 support. For 3.8.0, treat Python 3.9+ as the supported baseline.\n- The 3.6.1 release line already required `pytest>=7.0.0` and `execnet>=2.1.0`; that remains the practical dependency floor for 3.8.0.\n- Remote rsync mode and `--looponfail` are still documented but were deprecated earlier and are planned for removal in xdist 4.0. Avoid building new automation around them.\n- `--boxed` is already removed from modern xdist; use `pytest-forked` if you specifically need fork isolation behavior.\n\n## Recommended Agent Workflow\n\n1. Run `pytest` without xdist first to confirm the suite is already healthy.\n2. Enable parallelism with `pytest -n auto`.\n3. If fixtures or stateful tests churn too much, switch to `--dist loadscope`, `loadfile`, or `loadgroup`.\n4. If failures only happen in parallel mode, add worker-aware resource names and rerun with a smaller fixed worker count such as `-n 2`.\n5. For debugging, rerun the same subset with `-n 0` and then use `--pdb` or your normal debugger.\n\n## Official Sources\n\n- Stable docs: `https://pytest-xdist.readthedocs.io/en/stable/`\n- Distribution guide: `https://pytest-xdist.readthedocs.io/en/stable/distribution.html`\n- How-tos: `https://pytest-xdist.readthedocs.io/en/stable/how-to.html`\n- Known limitations: `https://pytest-xdist.readthedocs.io/en/stable/known-limitations.html`\n- Changelog: `https://pytest-xdist.readthedocs.io/en/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-xdist/`\n"
  },
  {
    "path": "content/pytest-asyncio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-asyncio guide for writing and configuring asyncio tests with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,pytest-asyncio,python,asyncio,testing\"\n---\n\n# pytest-asyncio Python Package Guide\n\n## Golden Rule\n\n`pytest-asyncio` is a pytest plugin for `asyncio` tests and fixtures. After installation, pytest loads the plugin automatically. There is no client object to initialize and no package-specific environment variable to set.\n\nChoose one discovery mode up front:\n\n- `strict` is the default and is the safest choice when your test suite mixes multiple async backends or plugins\n- `auto` is simpler for asyncio-only projects because async tests and fixtures are handled automatically\n\n## Install\n\nVersion `1.3.0` requires Python 3.10 or newer.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pytest\" \"pytest-asyncio==1.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pytest-asyncio==1.3.0\"\npoetry add \"pytest-asyncio==1.3.0\"\n```\n\n## Configure pytest\n\nSet the asyncio mode explicitly in your pytest config. Also set `asyncio_default_fixture_loop_scope` explicitly, because upstream warns that the implicit default will change in a future release.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\nasyncio_mode = \"strict\"\nasyncio_default_fixture_loop_scope = \"function\"\n```\n\nFor an asyncio-only project, switch to `auto` instead:\n\n```toml\n[tool.pytest.ini_options]\nasyncio_mode = \"auto\"\nasyncio_default_fixture_loop_scope = \"function\"\n```\n\n## Write Async Tests\n\nIn `strict` mode, mark async tests with `@pytest.mark.asyncio`.\n\n```python\nimport asyncio\nimport pytest\n\n\nasync def get_value() -> str:\n    await asyncio.sleep(0)\n    return \"ok\"\n\n\n@pytest.mark.asyncio\nasync def test_get_value() -> None:\n    assert await get_value() == \"ok\"\n```\n\nRun the test suite with normal pytest commands:\n\n```bash\npytest\npytest tests/test_async_code.py -q\n```\n\nIf you configure `asyncio_mode = \"auto\"`, async test functions do not need the explicit `@pytest.mark.asyncio` marker.\n\n## Write Async Fixtures\n\nIn `strict` mode, async fixtures should use `@pytest_asyncio.fixture`.\n\n```python\nimport pytest\nimport pytest_asyncio\n\n\nclass FakeClient:\n    def __init__(self) -> None:\n        self.closed = False\n\n    async def fetch_status(self) -> str:\n        return \"ok\"\n\n    async def aclose(self) -> None:\n        self.closed = True\n\n\n@pytest_asyncio.fixture\nasync def client() -> FakeClient:\n    resource = FakeClient()\n    yield resource\n    await resource.aclose()\n\n\n@pytest.mark.asyncio\nasync def test_client_fixture(client: FakeClient) -> None:\n    assert await client.fetch_status() == \"ok\"\n```\n\nIf you switch to `auto` mode, pytest-asyncio can also manage async fixtures declared with the normal `@pytest.fixture` decorator.\n\n## Control Event Loop Scope\n\nUse `loop_scope` when a test should run in a loop that lives longer than one function call.\n\n```python\nimport asyncio\nimport pytest\n\n\n@pytest.mark.asyncio(loop_scope=\"module\")\nasync def test_uses_module_loop() -> None:\n    loop = asyncio.get_running_loop()\n    assert loop.is_running()\n```\n\nUse wider scopes deliberately and keep related tests on the same scope when they share loop-sensitive state.\n\n## Replace The Removed `event_loop` Fixture\n\n`pytest-asyncio 1.x` no longer provides the deprecated `event_loop` fixture. Inside async tests or fixtures, get the running loop directly:\n\n```python\nimport asyncio\nimport pytest\n\n\n@pytest.mark.asyncio\nasync def test_current_loop() -> None:\n    loop = asyncio.get_running_loop()\n    assert loop.is_running()\n```\n\nIf a group of tests or fixtures must share a longer-lived loop, configure `loop_scope` or the relevant asyncio loop-scope setting instead of reintroducing `event_loop`.\n\n## Common Pitfalls\n\n- Async tests are skipped or treated as normal callables in `strict` mode when `@pytest.mark.asyncio` is missing\n- Async fixtures use `@pytest.fixture` in `strict` mode instead of `@pytest_asyncio.fixture`\n- `asyncio_default_fixture_loop_scope` is left unset, which can make future upgrades noisier when the upstream default changes\n- Legacy examples still reference the removed `event_loop` fixture; use `asyncio.get_running_loop()` in async code instead\n\n## Version Notes\n\n- `1.0.0` removes the deprecated `event_loop` fixture\n- `1.3.0` adds support for `pytest 9` and drops Python 3.9, so plan on Python 3.10+\n"
  },
  {
    "path": "content/pytest-bdd/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-bdd package guide for Python projects using Gherkin feature files with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-bdd,pytest,bdd,gherkin,testing,python\"\n---\n\n# pytest-bdd Python Package Guide\n\n## Golden Rule\n\nUse `pytest-bdd` as a thin layer on top of normal `pytest`: keep test state in fixtures, keep feature files readable, and bind scenarios explicitly from Python. Do not design around a separate BDD runner or a shared mutable context object.\n\n## Install\n\nInstall `pytest-bdd` alongside `pytest` as a test dependency:\n\n```bash\npython -m pip install \"pytest>=8\" \"pytest-bdd==8.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest>=8\" \"pytest-bdd==8.1.0\"\npoetry add --group dev \"pytest>=8\" \"pytest-bdd==8.1.0\"\n```\n\nRun BDD tests with plain `pytest`:\n\n```bash\npytest\n```\n\n## Minimal Setup\n\nRecommended layout:\n\n```text\ntests/\n  features/\n    publish_article.feature\n  test_publish_article.py\npytest.ini\n```\n\nThere is no package-specific authentication, client object, or required environment variable. Configuration lives in your normal pytest files.\n\nSet a base directory for feature files so step modules can use short relative paths:\n\n```ini\n# pytest.ini\n[pytest]\nbdd_features_base_dir = tests/features\nmarkers =\n    publishing: BDD tag from feature files\n```\n\nIf you use `pytest --strict-markers`, register the markers you expect feature tags to create.\n\n## Write A Feature File\n\nKeep one Gherkin feature per `.feature` file:\n\n```gherkin\nFeature: Blog publishing\n  Scenario: Publishing an article\n    Given a draft article titled \"BDD with pytest\"\n    When the article is published\n    Then the article status is \"published\"\n```\n\n## Bind Scenarios And Implement Steps\n\n```python\nfrom pytest_bdd import given, parsers, scenario, then, when\n\n\n@scenario(\"publish_article.feature\", \"Publishing an article\")\ndef test_publishing_article():\n    pass\n\n\n@given(parsers.parse('a draft article titled \"{title}\"'), target_fixture=\"article\")\ndef draft_article(title: str):\n    return {\"title\": title, \"status\": \"draft\"}\n\n\n@when(\"the article is published\")\ndef publish_article(article):\n    article[\"status\"] = \"published\"\n\n\n@then(parsers.parse('the article status is \"{status}\"'))\ndef assert_status(article, status: str):\n    assert article[\"status\"] == status\n```\n\nKey APIs:\n\n- `@scenario(...)` binds a Python test function to a scenario in a `.feature` file.\n- `target_fixture` lets a step provide or override a pytest fixture value.\n- Step functions can depend on normal pytest fixtures exactly like other pytest tests.\n\nFor many scenarios at once, use `scenarios(...)`:\n\n```python\nfrom pytest_bdd import scenarios\n\n\nscenarios(\"features\")\n```\n\nUse this for bulk binding, but keep any manual `@scenario(...)` declarations earlier in the file.\n\n## Step Parsers And Parameters\n\n`pytest-bdd` supports plain strings and parser helpers:\n\n- `parsers.parse(...)` for typed placeholders such as `{count:d}`\n- `parsers.cfparse(...)` for parse expressions with more converters\n- `parsers.re(...)` for regular expressions when you need exact control\n\nExample with typed parsing:\n\n```python\nfrom pytest_bdd import given, parsers\n\n\n@given(parsers.parse(\"there are {count:d} users\"), target_fixture=\"users\")\ndef users(count: int):\n    return list(range(count))\n```\n\nUse parser-based steps when values come from the feature file. Keep the parsing logic in the decorator instead of manually splitting strings inside the step function.\n\n## Scenario Outlines\n\nUse Gherkin `Scenario Outline` plus `Examples` for data-driven behavior:\n\n```gherkin\nScenario Outline: Pricing\n  Given a cart total of <total>\n  Then the discount is <discount>\n\n  Examples:\n    | total | discount |\n    | 20    | 0        |\n    | 120   | 10       |\n```\n\nMatch placeholders with parser-based steps:\n\n```python\nfrom pytest_bdd import given, parsers, then\n\n\n@given(parsers.parse(\"a cart total of {total:d}\"), target_fixture=\"cart_total\")\ndef cart_total(total: int):\n    return total\n\n\n@then(parsers.parse(\"the discount is {discount:d}\"))\ndef discount(cart_total: int, discount: int):\n    actual = 10 if cart_total >= 100 else 0\n    assert actual == discount\n```\n\nPrefer scenario outlines over stacking `@pytest.mark.parametrize` on top of BDD scenarios.\n\n## Datatables, Docstrings, And Tags\n\n`pytest-bdd` can pass richer Gherkin inputs into step functions:\n\n- Docstrings are exposed as a `docstring` argument.\n- Data tables are exposed as a `datatable` argument.\n- Tags become pytest markers, so you can select with normal pytest filtering.\n\nExample tag selection:\n\n```bash\npytest -m publishing\n```\n\nIf you need custom tag behavior, implement hooks such as `pytest_bdd_apply_tag`. Other useful hooks include scenario and step hooks for reporting or custom logging.\n\n## Config And Test Initialization\n\nThere is no service authentication model in `pytest-bdd`; configuration is local to pytest and your test tree.\n\nUse these setup rules:\n\n- Put shared fixtures in `conftest.py`.\n- Set `bdd_features_base_dir` in `pytest.ini` when feature files live outside the test module directory.\n- Keep step text stable and human-readable; move conditional logic into fixtures and helpers.\n- Use normal pytest fixture scopes such as `function`, `module`, and `session` for expensive setup.\n\nExample shared fixture:\n\n```python\n# tests/conftest.py\nimport pytest\n\n\n@pytest.fixture\ndef app_client():\n    return build_test_client()\n```\n\n## Common Pitfalls\n\n- Only one feature is allowed per `.feature` file.\n- Feature tags become pytest markers. With `--strict-markers`, undeclared tags fail collection.\n- `bdd_features_base_dir` is resolved from the pytest root directory, not from whatever shell directory you happen to be in.\n- `parsers.re(...)` uses full matching in modern `pytest-bdd`; partial regex matches that used to pass can now fail.\n- Parsed step arguments are regular function arguments, not pytest fixtures. Use `target_fixture` when a step should create or override fixture data.\n- Do not mix scenario outlines and `@pytest.mark.parametrize` for the same behavior unless you have a very specific reason and have verified collection behavior.\n- If you call `scenarios(...)`, keep any manual `@scenario(...)` bindings earlier in the module.\n- In `8.1.0`, `datatable` and `docstring` are reserved step argument names for parser-based steps.\n\n## Version-Sensitive Notes For 8.1.0\n\n- `8.1.0` reserves `datatable` and `docstring` as parser argument names because those names are used for Gherkin table and docstring injection.\n- `8.1.0` also adds template variable rendering inside docstrings and datatables, which matters if your step logic reads multiline or tabular scenario data.\n- The `8.0` line adds support for `Rule`, localized Gherkin with `# language: ...`, multiple example tables, and tags on individual examples.\n- Since the `7.x` line, `parsers.re(...)` behaves as a full match, so older regex-based steps may need anchors or updated patterns during migration.\n\n## Official Sources\n\n- Stable docs: `https://pytest-bdd.readthedocs.io/en/stable/`\n- Test setup: `https://pytest-bdd.readthedocs.io/en/stable/#test-setup`\n- Feature file paths: `https://pytest-bdd.readthedocs.io/en/stable/#feature-file-paths`\n- Step arguments: `https://pytest-bdd.readthedocs.io/en/stable/#step-arguments`\n- Scenario outlines: `https://pytest-bdd.readthedocs.io/en/stable/#scenario-outlines`\n- Changelog and migration notes: `https://pytest-bdd.readthedocs.io/en/stable/#changelog`\n- PyPI package metadata: `https://pypi.org/project/pytest-bdd/`\n"
  },
  {
    "path": "content/pytest-cov/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Practical pytest-cov 7.0.0 guide for pytest coverage runs, reports, xdist, and subprocess measurement\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-cov,pytest,coverage,testing,python,ci\"\n---\n\n# pytest-cov Python Package Guide\n\n## Golden Rule\n\n`pytest-cov` is a pytest plugin, not an application library. Install it into the same environment as `pytest`, run it through `pytest` command-line options such as `--cov`, and keep long-lived coverage settings in a coverage config file.\n\nThis guide targets `pytest-cov 7.0.0`.\n\n## Install\n\nInstall the plugin into the same virtual environment as `pytest`:\n\n```bash\npython -m pip install \"pytest-cov==7.0.0\"\n```\n\nIf you run tests in parallel with `pytest-xdist`, install that alongside the plugin:\n\n```bash\npython -m pip install pytest-xdist\n```\n\n## Runtime Setup\n\n- Import: none in application code\n- Environment variables: none required for normal usage\n- Authentication: none\n- Initialization: run tests with `python -m pytest` and pass coverage options there\n\nThe common setup mistake is treating `pytest-cov` like a runtime package import. In normal use, you do not add `import pytest_cov` to your app.\n\n## Basic Commands\n\nRun coverage for one package or source tree:\n\n```bash\npython -m pytest --cov=src/your_pkg tests\n```\n\nShow missing lines in terminal output:\n\n```bash\npython -m pytest --cov=src/your_pkg --cov-report=term-missing tests\n```\n\nFail CI if total coverage drops below a threshold:\n\n```bash\npython -m pytest \\\n  --cov=src/your_pkg \\\n  --cov-branch \\\n  --cov-fail-under=90 \\\n  tests\n```\n\nAppend coverage data across multiple runs instead of replacing it:\n\n```bash\npython -m pytest --cov=src/your_pkg --cov-append tests/unit\npython -m pytest --cov=src/your_pkg --cov-append tests/integration\n```\n\n## Put Persistent Settings In `pyproject.toml`\n\n`pytest-cov` works best when the CLI stays short and the real coverage settings live in a config file that coverage already understands.\n\n```toml\n[tool.pytest.ini_options]\naddopts = [\n  \"--cov\",\n  \"--cov-report=term-missing\",\n  \"--cov-report=xml:coverage.xml\",\n]\n\n[tool.coverage.run]\nsource = [\"src/your_pkg\"]\nbranch = true\n\n[tool.coverage.report]\nshow_missing = true\nskip_covered = true\n```\n\nUse bare `--cov` when `source` is already configured under coverage settings. Passing `--cov=...` on the command line overrides coverage's `source` value.\n\nIf your tests change the working directory, or you spawn subprocesses from a different location, pass the config path explicitly:\n\n```bash\npython -m pytest --cov --cov-config=pyproject.toml tests\n```\n\n## Reports\n\nCommon report outputs include terminal summaries, HTML, XML, JSON, LCOV, and annotated source output.\n\nGenerate multiple outputs in one run:\n\n```bash\npython -m pytest \\\n  --cov=src/your_pkg \\\n  --cov-report=term-missing \\\n  --cov-report=html:htmlcov \\\n  --cov-report=xml:coverage.xml \\\n  tests\n```\n\nIf you pass any explicit `--cov-report`, the default terminal report is not added automatically. Ask for every report you want.\n\nTo generate only file output and suppress terminal coverage text:\n\n```bash\npython -m pytest --cov=src/your_pkg --cov-report= --cov-report=xml:coverage.xml tests\n```\n\n## Parallel Runs With `pytest-xdist`\n\nFor distributed or parallel pytest runs:\n\n```bash\npython -m pytest -n auto --cov=src/your_pkg tests\n```\n\n`pytest-cov` combines coverage from xdist workers automatically.\n\nFor per-test coverage contexts:\n\n```bash\npython -m pytest --cov=src/your_pkg --cov-context=test tests\n```\n\nDo not combine `--cov-context=test` with xdist. Distinct test contexts are not supported with distributed workers.\n\n## Subprocess Coverage In 7.x\n\n`pytest-cov 7.0.0` no longer uses the older `.pth`-based subprocess measurement approach. If your tests spawn Python subprocesses and you want their coverage included, enable coverage's subprocess patching in your coverage config:\n\n```toml\n[tool.coverage.run]\npatch = [\"subprocess\"]\n```\n\nKeep `--cov-config` explicit when subprocesses may start from a different working directory:\n\n```bash\npython -m pytest --cov --cov-config=pyproject.toml tests\n```\n\n## Debugging And Temporary Opt-Out\n\nCoverage tracing can interfere with debuggers. Disable coverage for that run when you need reliable breakpoint behavior:\n\n```bash\npython -m pytest --no-cov -k test_name\n```\n\n## Common Pitfalls\n\n- `--cov=path_or_pkg` overrides coverage's configured `source`; use bare `--cov` when `source` already lives in config.\n- If you specify one `--cov-report`, specify every report you need for that run.\n- Config-file discovery can break when tests or subprocesses change directories; use `--cov-config=pyproject.toml` or `--cov-config=.coveragerc` explicitly.\n- Older guides that describe automatic `.pth`-based subprocess handling do not match `pytest-cov 7.0.0`.\n- `--cov-context=test` is useful for fine-grained analysis, but not with xdist.\n\n## Official Sources\n\n- Documentation: `https://pytest-cov.readthedocs.io/en/latest/`\n- Configuration: `https://pytest-cov.readthedocs.io/en/latest/config.html`\n- Reporting: `https://pytest-cov.readthedocs.io/en/latest/reporting.html`\n- xdist: `https://pytest-cov.readthedocs.io/en/latest/xdist.html`\n- Subprocess support: `https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html`\n- Changelog: `https://pytest-cov.readthedocs.io/en/latest/changelog.html`\n- PyPI package: `https://pypi.org/project/pytest-cov/`\n"
  },
  {
    "path": "content/pytest-django/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-django package guide for running Django tests with pytest\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.12.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-django,pytest,django,testing,fixtures,database\"\n---\n\n# pytest-django Python Package Guide\n\n## What This Package Does\n\nUse `pytest-django` to run Django tests with `pytest`, load Django settings before test collection, and opt into database access only for tests that need it. There is no separate service client or auth layer; the main setup step is telling pytest which Django settings module to use.\n\n## Install\n\nInstall `pytest-django` alongside `pytest` in your development dependencies:\n\n```bash\npython -m pip install \"pytest>=7,<9\" \"pytest-django==4.12.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest>=7,<9\" \"pytest-django==4.12.0\"\npoetry add --group dev \"pytest>=7,<9\" \"pytest-django==4.12.0\"\n```\n\n## Minimal Setup\n\nThe plugin must know your Django settings module before tests import models, apps, or anything else that touches Django setup.\n\nUse `pytest.ini`:\n\n```ini\n[pytest]\nDJANGO_SETTINGS_MODULE = myproject.settings\npython_files = tests.py test_*.py *_tests.py\naddopts = --reuse-db\n```\n\nOr the equivalent `pyproject.toml` config:\n\n```toml\n[tool.pytest.ini_options]\nDJANGO_SETTINGS_MODULE = \"myproject.settings\"\npython_files = [\"tests.py\", \"test_*.py\", \"*_tests.py\"]\naddopts = \"--reuse-db\"\n```\n\nThe settings resolution order is:\n\n1. `--ds=myproject.settings`\n2. `DJANGO_SETTINGS_MODULE` environment variable\n3. The value in `pytest.ini`, `tox.ini`, or `pyproject.toml`\n\nExamples:\n\n```bash\npytest --ds=myproject.settings\nDJANGO_SETTINGS_MODULE=myproject.settings pytest\n```\n\nIf your project uses `django-configurations`, also provide the configuration class:\n\n```bash\npytest --ds=myproject.settings --dc=Dev\nDJANGO_SETTINGS_MODULE=myproject.settings DJANGO_CONFIGURATION=Dev pytest\n```\n\n## Import Path And Project Discovery\n\nBy default, `pytest-django` looks for `manage.py` and adds that project directory to `sys.path`. That is convenient for the standard Django layout, but it can be wrong in monorepos or `src/` layouts.\n\nDisable project auto-discovery when you want imports to stay explicit:\n\n```ini\n[pytest]\ndjango_find_project = false\nDJANGO_SETTINGS_MODULE = myproject.settings\n```\n\nThen make the project importable yourself, usually with an editable install:\n\n```bash\npython -m pip install -e .\n```\n\nUse this mode if pytest is picking the wrong `manage.py` or your Django package is not rooted at the repository top level.\n\n## Common Test Workflows\n\n### Pure Python test with no database\n\n```python\ndef test_plain_python_logic():\n    assert 2 + 2 == 4\n```\n\n### Model test with database access\n\n`pytest-django` blocks database access by default. Add the marker when a test needs ORM access:\n\n```python\nimport pytest\n\nfrom blog.models import Post\n\n\n@pytest.mark.django_db\ndef test_post_str():\n    post = Post.objects.create(title=\"Hello\")\n    assert str(post) == \"Hello\"\n```\n\nFixture equivalents:\n\n- `db`: standard database access with rollback between tests\n- `transactional_db`: slower, but uses real transaction behavior\n\n### Transaction-sensitive test\n\nUse transactional access when the code under test depends on commits, rollbacks, or database locking behavior:\n\n```python\nimport pytest\n\n\n@pytest.mark.django_db(transaction=True)\ndef test_select_for_update_path():\n    ...\n```\n\n### Multi-database test\n\nIf the project uses more than one Django database alias, declare the aliases explicitly:\n\n```python\nimport pytest\n\n\n@pytest.mark.django_db(databases=[\"default\", \"other\"])\ndef test_reads_from_replica():\n    ...\n```\n\n### Client-based view test\n\nUse the built-in Django test client fixture for request, session, and auth flows:\n\n```python\nimport pytest\nfrom django.urls import reverse\n\n\n@pytest.mark.django_db\ndef test_dashboard_requires_login(client, django_user_model):\n    user = django_user_model.objects.create_user(\n        username=\"alice\",\n        password=\"secret\",\n    )\n    client.force_login(user)\n\n    response = client.get(reverse(\"dashboard\"))\n\n    assert response.status_code == 200\n```\n\n### Temporary settings override\n\nUse the `settings` fixture for per-test overrides:\n\n```python\ndef test_feature_flag(settings):\n    settings.MY_FEATURE_ENABLED = True\n    assert settings.MY_FEATURE_ENABLED is True\n```\n\n## High-Value Fixtures\n\n- `client`: Django test client\n- `async_client`: async test client for async views\n- `rf`: `django.test.RequestFactory`\n- `async_rf`: async request factory\n- `settings`: temporary settings overrides\n- `django_user_model`: the active user model\n- `admin_user`, `admin_client`: ready-made admin fixtures\n- `live_server`: test server for browser or external HTTP tests\n\nUse `rf` only when you want to call a view directly without middleware. If your code depends on sessions, authentication, messages, or CSRF behavior, prefer `client`.\n\n## Database Lifecycle And Performance\n\nThe test database is created on first use and then reused inside the current pytest run. For repeated local runs, `--reuse-db` is the standard speed optimization:\n\n```bash\npytest --reuse-db\n```\n\nImportant companion flags:\n\n- `--create-db`: rebuild the test database even if reuse metadata exists\n- `--no-migrations`: build the test database from models instead of running migrations\n\nUse `--create-db` after schema changes. `--reuse-db` does not detect new migrations automatically.\n\nUse `--no-migrations` only as a local speed optimization. It can hide migration bugs that still matter in CI and production.\n\nFor custom global database setup, override the session-scoped `django_db_setup` fixture in `conftest.py`.\n\n## Async And Live Server Notes\n\nUse `async_client` or `async_rf` for async views, and keep the test function compatible with the async pytest plugin your project already uses, typically `pytest-asyncio`.\n\n`live_server` depends on transactional database access. Do not assume data created in one live-server test will persist into another test.\n\n## Common Pitfalls\n\n- `ImproperlyConfigured` during collection usually means `DJANGO_SETTINGS_MODULE` or `--ds` was not set early enough.\n- If pytest discovers the wrong project root, set `django_find_project = false` and make imports explicit.\n- If database access is denied, add `@pytest.mark.django_db`, `db`, or `transactional_db`.\n- After changing models or migrations, rerun with `pytest --create-db` if you are reusing the test database.\n- `rf` does not run middleware or login flows; use `client` for end-to-end request behavior.\n- `--no-migrations` is useful for local speed, but it is not a replacement for testing real migrations.\n- `pytest-django` does not replace your async pytest plugin.\n\n## Version Notes\n\n- This guide targets `pytest-django 4.12.0`.\n- If your project is pinned to older Django or Python versions, check the package classifiers and changelog before copying this setup unchanged.\n\n## Official Sources\n\n- Docs root: `https://pytest-django.readthedocs.io/en/latest/`\n- Tutorial: `https://pytest-django.readthedocs.io/en/latest/tutorial.html`\n- Django configuration: `https://pytest-django.readthedocs.io/en/latest/configuring_django.html`\n- Python path and project discovery: `https://pytest-django.readthedocs.io/en/latest/managing_python_path.html`\n- Database usage: `https://pytest-django.readthedocs.io/en/latest/database.html`\n- Fixtures and helpers: `https://pytest-django.readthedocs.io/en/latest/helpers.html`\n- Changelog: `https://pytest-django.readthedocs.io/en/latest/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-django/`\n"
  },
  {
    "path": "content/pytest-env/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-env plugin guide for declaring test-only environment variables in pytest configuration\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-env,pytest,python,testing,environment-variables,toml\"\n---\n\n# pytest-env Python Package Guide\n\n## What It Does\n\n`pytest-env` is a pytest plugin for setting environment variables during pytest runs from project configuration.\n\nUse it when your tests need stable, test-only values such as:\n\n- `APP_ENV=test`\n- `DATABASE_URL` pointing at a test database\n- feature flags or service endpoints that should differ from local development defaults\n\nThere is no runtime client to initialize and no auth flow. Once `pytest-env` is installed in the test environment, pytest discovers the plugin automatically.\n\n## Install\n\nCurrent maintainer metadata documents `Python >=3.10` and `pytest >=9.0.2` for the current package line. Install the plugin into your development or CI test environment:\n\n```bash\npython -m pip install \"pytest==9.0.2\" \"pytest-env==1.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest==9.0.2\" \"pytest-env==1.5.0\"\npoetry add --group dev \"pytest==9.0.2\" \"pytest-env==1.5.0\"\n```\n\nVerify that pytest is available on the active environment before debugging config issues:\n\n```bash\npytest --version\n```\n\n## Minimal Setup With `pyproject.toml`\n\nCurrent maintainer guidance is centered on native TOML configuration. For a project using `pyproject.toml`, keep normal pytest options under `[tool.pytest]` and plugin-managed environment variables under `[tool.pytest_env]`.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest]\ntestpaths = [\"tests\"]\naddopts = [\"-q\"]\n\n[tool.pytest_env]\nAPP_ENV = \"test\"\nAPI_BASE_URL = \"https://api.example.test\"\nFEATURE_X_ENABLED = \"0\"\n```\n\nTest code reads those values from the normal process environment:\n\n```python\nimport os\n\n\ndef test_env_is_available() -> None:\n    assert os.environ[\"APP_ENV\"] == \"test\"\n    assert os.environ[\"API_BASE_URL\"] == \"https://api.example.test\"\n    assert os.environ[\"FEATURE_X_ENABLED\"] == \"0\"\n```\n\nRun the suite normally:\n\n```bash\npytest\n```\n\n`pytest-env` sets values for the pytest process, so application code should continue to use `os.environ` or `os.getenv()` as usual.\n\n## `pytest.toml` Layout\n\nIf the project uses `pytest.toml` instead of `pyproject.toml`, place plugin configuration under `[pytest_env]` rather than `[tool.pytest_env]`.\n\nMinimal plugin section:\n\n```toml\n[pytest_env]\nAPP_ENV = \"test\"\n```\n\nThis matches the current pytest 9 native TOML layout described by the maintainer docs.\n\n## Common Workflows\n\n### Keep Shared Test Defaults In VCS\n\nUse checked-in config for non-secret defaults that every developer and CI runner should share:\n\n```toml\n[tool.pytest_env]\nAPP_ENV = \"test\"\nLOG_LEVEL = \"warning\"\nPAYMENTS_ENABLED = \"0\"\n```\n\nThis is usually a better fit than relying on every shell session to export the same values manually.\n\n### Read Settings In Application Code Normally\n\n`pytest-env` is only responsible for preparing the environment. Your code should keep using standard environment access patterns:\n\n```python\nimport os\n\n\ndef load_settings() -> dict[str, str]:\n    return {\n        \"app_env\": os.environ.get(\"APP_ENV\", \"dev\"),\n        \"api_base_url\": os.environ[\"API_BASE_URL\"],\n    }\n```\n\nThat keeps production, local development, and pytest runs aligned around the same configuration interface.\n\n### Use `.env` Or One-Off Overrides When Values Should Not Be Checked In\n\nThe current maintainer README also documents `.env`-based loading and runtime override workflows. Prefer those patterns when:\n\n- values differ by machine\n- CI injects secrets dynamically\n- you need a one-off override for a single test run\n\nFor those cases, follow the current README for the exact option names and file-based workflow instead of inventing custom bootstrap code in `conftest.py`.\n\n## Config And Auth\n\nThere is no auth or service initialization step.\n\nIn practice, the main configuration surface is:\n\n- pytest config in `pyproject.toml` or `pytest.toml`\n- environment variable reads in your application code via `os.environ` or `os.getenv()`\n- optional `.env` or CLI override features documented by the maintainer README\n\n## Common Pitfalls\n\n- Put plugin config in the correct table: `[tool.pytest_env]` for `pyproject.toml` and `[pytest_env]` for `pytest.toml`.\n- Do not try to activate the plugin with `import pytest_env` in tests or `conftest.py`; installation is enough.\n- Remember that `pytest-env` affects pytest runs, not your interactive shell and not standalone `python script.py` execution.\n- Do not commit production credentials into pytest config. Checked-in values should be test defaults only.\n- If a repository already uses pytest 9 TOML config, avoid mixing in older blog-post examples without checking the current README first.\n\n## Version-Sensitive Notes For `1.5.0`\n\n- This guide targets `pytest-env 1.5.0`.\n- The canonical maintainer documentation is the GitHub repository README; there is no separate hosted docs site to prefer here.\n- Current maintainer metadata documents `Python >=3.10`, `pytest >=9.0.2`, and `python-dotenv >=1.2.1` for the current package line.\n- Current maintainer guidance is aligned with pytest 9 native TOML configuration. That matters because older examples built around legacy pytest config files may not match current usage.\n\n## Official Sources\n\n- Maintainer docs: `https://github.com/pytest-dev/pytest-env`\n- Maintainer package metadata: `https://github.com/pytest-dev/pytest-env/blob/main/pyproject.toml`\n- PyPI package page: `https://pypi.org/project/pytest-env/`\n- PyPI JSON metadata: `https://pypi.org/pypi/pytest-env/json`\n- Pytest configuration docs: `https://docs.pytest.org/en/latest/customize.html`\n"
  },
  {
    "path": "content/pytest-flask/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-flask package guide for testing Flask apps with pytest fixtures, clients, live servers, and config markers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-flask,pytest,flask,testing,pytest-plugin,fixtures\"\n---\n\n# pytest-flask Python Package Guide\n\n## Golden Rule\n\nUse `pytest-flask` as a pytest plugin layered on top of your Flask app's own test configuration. Define a real `app` fixture, enable `TESTING`, and target released `1.3.0` behavior instead of assuming the Read the Docs `latest` build is identical to the PyPI release.\n\nAs of the current upstream docs and package metadata:\n\n- PyPI lists `pytest-flask 1.3.0`\n- Read the Docs `stable` still shows `1.2.0`\n- Read the Docs `latest` includes unreleased development changes\n\nThat version drift matters for fixture behavior and compatibility notes.\n\n## Install\n\nInstall the plugin into the same environment as your Flask app and `pytest`:\n\n```bash\npython -m pip install \"pytest-flask==1.3.0\"\n```\n\nFor a fresh test environment:\n\n```bash\npython -m pip install \"Flask>=2,<4\" \"pytest>=7\" \"pytest-flask==1.3.0\"\n```\n\nIf your project already depends on Flask, you usually only add the plugin as a test dependency:\n\n```bash\nuv add --dev \"pytest-flask==1.3.0\"\npoetry add --group test \"pytest-flask==1.3.0\"\n```\n\n## Environment And Prerequisites\n\n`pytest-flask` has no package-specific authentication flow and no required package-specific environment variables.\n\nThe important prerequisites are in your Flask app and test config:\n\n- `pytest` installed\n- a Flask application available to tests\n- `TESTING = True` in the test app config\n- `SECRET_KEY` set if tests use `session`\n- `SERVER_NAME` set when you need `url_for(..., _external=True)`\n\n## Minimal Setup\n\n`pytest-flask` does not create your Flask app for you. The core requirement is an `app` fixture in `conftest.py`.\n\n```python\n# tests/conftest.py\nimport pytest\nfrom flask import Flask\n\n\n@pytest.fixture\ndef app():\n    app = Flask(__name__)\n    app.config.update(\n        TESTING=True,\n        SECRET_KEY=\"test-secret\",\n        SERVER_NAME=\"example.test\",\n    )\n\n    @app.get(\"/ping\")\n    def ping():\n        return {\"ok\": True}\n\n    return app\n```\n\nWith that fixture in place, the plugin provides Flask-aware helpers like `client`, `config`, `client_class`, and `live_server`.\n\n## Basic Request Tests With `client`\n\nUse `client` for request-level tests. The plugin automatically manages request context around the test client so Flask globals such as `url_for`, `request`, and `session` are available without manually opening `app.test_request_context()`.\n\n```python\n# tests/test_ping.py\nfrom flask import session, url_for\n\n\ndef test_ping(client):\n    response = client.get(url_for(\"ping\"))\n\n    assert response.status_code == 200\n    assert response.json == {\"ok\": True}\n    assert session is not None\n```\n\nCommon calls use the standard Flask test client API:\n\n```python\ndef test_post_json(client):\n    response = client.post(\"/items\", json={\"name\": \"widget\"})\n    assert response.status_code in {200, 201}\n```\n\n## Class-Based Tests With `client_class`\n\nFor class-based tests, use `client_class` to attach the client to `self.client`.\n\n```python\nclass TestViews:\n    def test_ping(self, client_class):\n        response = self.client.get(\"/ping\")\n        assert response.json[\"ok\"] is True\n```\n\n## Per-Test App Config With `config` And `pytest.mark.options`\n\nUse `config` when you want to mutate `app.config` inside a test:\n\n```python\ndef test_feature_flag(config, client):\n    config[\"FEATURE_X_ENABLED\"] = True\n\n    response = client.get(\"/ping\")\n\n    assert response.status_code == 200\n```\n\nUse the `options` marker for per-test config overrides declared at the test level:\n\n```python\nimport pytest\n\n\n@pytest.mark.options(DEBUG=False, SERVER_NAME=\"example.test\")\ndef test_options_marker(client):\n    response = client.get(\"/ping\")\n    assert response.status_code == 200\n```\n\nThis is the upstream-supported pattern for configuration overrides instead of mutating module-level globals.\n\n## Accept Header Fixtures\n\nThe plugin includes header fixtures for common Accept values:\n\n- `accept_any`\n- `accept_json`\n- `accept_jsonp`\n- `accept_mimetype`\n\nExample:\n\n```python\ndef test_json_response(client, accept_json):\n    response = client.get(\"/ping\", headers=accept_json)\n    assert response.status_code == 200\n    assert response.mimetype == \"application/json\"\n```\n\n## App Factory Pattern\n\nIf your project uses an application factory, keep the fixture thin and create the app inside it:\n\n```python\n# tests/conftest.py\nimport pytest\n\nfrom myapp import create_app\n\n\n@pytest.fixture\ndef app():\n    app = create_app()\n    app.config.update(\n        TESTING=True,\n        SECRET_KEY=\"test-secret\",\n    )\n    return app\n```\n\nThis lets the rest of your tests keep using the same plugin fixtures.\n\n## Live Server Tests\n\nUse `live_server` when you need a real HTTP server instead of Flask's in-process test client, for example with browser tests or external callbacks.\n\n```python\nimport json\nfrom urllib.request import urlopen\n\nfrom flask import url_for\n\n\ndef test_live_server(live_server):\n    @live_server.app.get(\"/health\")\n    def health():\n        return {\"status\": \"ok\"}\n\n    live_server.start()\n\n    with urlopen(url_for(\"health\", _external=True)) as response:\n        payload = json.load(response)\n\n    assert payload == {\"status\": \"ok\"}\n```\n\nRelevant plugin controls documented upstream:\n\n- `--start-live-server`\n- `--no-start-live-server`\n- `--live-server-port=PORT`\n- `--live-server-wait=SECONDS`\n- `live_server_scope = session|function` in `pytest.ini`\n\nRecommended `pytest.ini` when tests need route registration before startup and better isolation:\n\n```ini\n[pytest]\naddopts = --no-start-live-server\nlive_server_scope = function\n```\n\nWhen you need an external URL, prefer `url_for(..., _external=True)` or the plugin's live-server URL helpers instead of hard-coding `localhost`.\n\n## Request Context And Sessions\n\nOne of the main reasons to use `pytest-flask` is automatic request-context handling around the test client. That lets you use Flask globals directly in tests after a request:\n\n```python\nfrom flask import session\n\n\ndef test_session_access(client):\n    client.get(\"/ping\")\n    session[\"seen\"] = True\n    assert session[\"seen\"] is True\n```\n\nFor session-dependent tests, keep `SECRET_KEY` explicit in the test app config.\n\n## Common Pitfalls\n\n- `pytest-flask` requires an `app` fixture. Installing the plugin alone does not create an application or register routes.\n- Do not assume Read the Docs `latest` matches the released `1.3.0` package. The docs site currently mixes released and unreleased content.\n- The deprecated `request_ctx` fixture was removed in `1.3.0` for Flask `3.0` compatibility. Rewrite older examples around `client`, Flask globals, or explicit Flask context managers.\n- `live_server` is session-scoped by default. Set `live_server_scope = function` if tests should not share routes or config.\n- If you add routes inside a `live_server` test, use `--no-start-live-server` and call `live_server.start()` only after route registration.\n- Fixed live-server ports are convenient for browser tools but can collide in CI. Prefer the default random port unless another tool requires a fixed port.\n- If your app uses a custom response class, test against its actual response contract instead of assuming behavior from older plugin examples.\n\n## Version Notes For `1.3.0`\n\n- PyPI's latest released version is `1.3.0`.\n- The `1.3.0` release removed the deprecated `request_ctx` fixture.\n- The `1.3.0` release includes Flask `3.0.0` compatibility fixes.\n- The Read the Docs `stable` site can miss `1.3.0` changes because it still renders `1.2.0`.\n\n## Official Sources\n\n- Docs index: `https://pytest-flask.readthedocs.io/en/latest/`\n- Tutorial: `https://pytest-flask.readthedocs.io/en/latest/tutorial.html`\n- Features and fixtures: `https://pytest-flask.readthedocs.io/en/latest/features.html`\n- Changelog: `https://pytest-flask.readthedocs.io/en/latest/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-flask/`\n"
  },
  {
    "path": "content/pytest-httpx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-httpx package guide for mocking HTTPX requests in Python tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.36.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-httpx,pytest,httpx,testing,mocking,python\"\n---\n\n# pytest-httpx Python Package Guide\n\n## Golden Rule\n\nUse `pytest-httpx` when your code under test uses `httpx`. The plugin installs a `httpx_mock` fixture that intercepts HTTPX requests and fails fast when requests or registered responses do not match your expectations.\n\nAs of `0.36.0`, the published package targets:\n\n- Python `>=3.10`\n- `pytest==9.*`\n- `httpx==0.28.*`\n\n## Install\n\nPin it alongside compatible `pytest` and `httpx` versions:\n\n```bash\npython -m pip install \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\n```\n\nCommon project-manager variants:\n\n```bash\nuv add \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\npoetry add --group test \"pytest-httpx==0.36.0\" \"pytest==9.*\" \"httpx==0.28.*\"\n```\n\nIf you test `async` code, also install your async test runner, commonly:\n\n```bash\npython -m pip install \"pytest-asyncio>=1,<2\"\n```\n\n## Setup In Tests\n\nThere is no auth or environment-variable setup for `pytest-httpx`. After installation, pytest loads the plugin automatically and exposes the `httpx_mock` fixture.\n\n```python\nimport httpx\n\ndef test_sync_client(httpx_mock):\n    httpx_mock.add_response(json={\"ok\": True})\n\n    with httpx.Client() as client:\n        response = client.get(\"https://api.example.com/health\")\n\n    assert response.json() == {\"ok\": True}\n```\n\nAsync tests work the same way:\n\n```python\nimport httpx\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_async_client(httpx_mock):\n    httpx_mock.add_response(status_code=202, json={\"queued\": True})\n\n    async with httpx.AsyncClient() as client:\n        response = await client.post(\"https://api.example.com/jobs\")\n\n    assert response.status_code == 202\n    assert response.json() == {\"queued\": True}\n```\n\nDefault response behavior if you do not pass arguments to `add_response()`:\n\n- status: `200`\n- protocol: `HTTP/1.1`\n- body: empty\n\n## Core Workflows\n\n### Register a specific response\n\n```python\ndef test_post_json(httpx_mock):\n    httpx_mock.add_response(\n        method=\"POST\",\n        url=\"https://api.example.com/items\",\n        status_code=201,\n        json={\"id\": \"item_123\"},\n        headers={\"x-test\": \"pytest-httpx\"},\n    )\n```\n\nMatching is done against the full request. If several registrations match, the first unmatched one is used.\n\n### Match query parameters with `match_params`\n\n`0.36.0` adds `match_params`, which is cleaner than encoding every query-string variant into the URL:\n\n```python\nfrom unittest.mock import ANY\n\ndef test_partial_query_match(httpx_mock):\n    httpx_mock.add_response(\n        url=\"https://api.example.com/search\",\n        match_params={\"q\": \"books\", \"page\": ANY},\n        json={\"items\": []},\n    )\n```\n\nUse `match_params` only when the `url` does not already include query parameters.\n\n### Match headers, body, JSON, files, or HTTPX extensions\n\n```python\ndef test_match_request_shape(httpx_mock):\n    httpx_mock.add_response(\n        url=\"https://api.example.com/items\",\n        method=\"POST\",\n        match_headers={\"Authorization\": \"Bearer test-token\"},\n        match_json={\"name\": \"widget\"},\n        json={\"created\": True},\n    )\n```\n\nImportant exclusivity rules:\n\n- `match_json` cannot be combined with `match_content` or `match_files`\n- `match_files` cannot be combined with `match_content` or `match_json`\n\n### Return streamed or dynamic responses\n\n```python\nimport httpx\nfrom pytest_httpx import IteratorStream\n\ndef test_streaming(httpx_mock):\n    httpx_mock.add_response(stream=IteratorStream([b\"part-1\", b\"part-2\"]))\n\n    with httpx.Client() as client:\n        with client.stream(\"GET\", \"https://api.example.com/stream\") as response:\n            assert list(response.iter_raw()) == [b\"part-1\", b\"part-2\"]\n```\n\nCallbacks let the mocked response depend on the incoming request:\n\n```python\nimport httpx\n\ndef test_dynamic_response(httpx_mock):\n    def handler(request: httpx.Request) -> httpx.Response:\n        return httpx.Response(status_code=200, json={\"url\": str(request.url)})\n\n    httpx_mock.add_callback(handler)\n\n    with httpx.Client() as client:\n        response = client.get(\"https://api.example.com/test\")\n\n    assert response.json() == {\"url\": \"https://api.example.com/test\"}\n```\n\n### Raise transport errors\n\nUse `add_exception()` when the code path should handle HTTPX failures:\n\n```python\nimport httpx\nimport pytest\n\ndef test_timeout(httpx_mock):\n    httpx_mock.add_exception(httpx.ReadTimeout(\"read timed out\"))\n\n    with httpx.Client() as client:\n        with pytest.raises(httpx.ReadTimeout):\n            client.get(\"https://api.example.com/slow\")\n```\n\nIf no registered response matches, `pytest-httpx` raises `httpx.TimeoutException` immediately and includes mismatch details in the error message.\n\n## Inspect Captured Requests\n\nPrefer strict request matching up front, but you can also inspect captured requests:\n\n```python\ndef test_capture_request(httpx_mock):\n    httpx_mock.add_response()\n\n    with httpx.Client() as client:\n        client.get(\"https://api.example.com/items\", headers={\"x-trace\": \"123\"})\n\n    request = httpx_mock.get_request()\n    assert request.headers[\"x-trace\"] == \"123\"\n```\n\nUse:\n\n- `httpx_mock.get_request()` for a single request\n- `httpx_mock.get_requests()` when multiple requests are expected\n\nThe same filtering rules used for response selection also apply when retrieving captured requests.\n\n## Configuration\n\n`pytest-httpx` does not have an auth model of its own. Configure fixture behavior with the `@pytest.mark.httpx_mock(...)` marker.\n\n### Per-test configuration\n\n```python\nimport pytest\n\n@pytest.mark.httpx_mock(assert_all_responses_were_requested=False)\ndef test_optional_response(httpx_mock):\n    httpx_mock.add_response()\n```\n\n### Main options\n\n- `assert_all_responses_were_requested=False`: allow unused registered responses\n- `assert_all_requests_were_expected=False`: allow unmatched outgoing requests at teardown\n- `can_send_already_matched_responses=True`: reuse the last matching response after it has already been consumed\n- `should_mock=lambda request: ...`: let selected requests pass through for partial integration tests\n\nPrefer response-level controls when possible:\n\n- `is_optional=True` is narrower than disabling `assert_all_responses_were_requested`\n- `is_reusable=True` is narrower than enabling `can_send_already_matched_responses`\n\nExample partial pass-through:\n\n```python\nimport pytest\n\n@pytest.mark.httpx_mock(\n    should_mock=lambda request: request.url.host != \"localhost\"\n)\ndef test_local_server_and_remote_mock(httpx_mock):\n    httpx_mock.add_response(url=\"https://api.example.com/data\", json={\"ok\": True})\n```\n\n## Common Pitfalls\n\n- Do not use `pytest-httpx` for code that uses `requests`, `aiohttp`, or another HTTP client. It only intercepts `httpx`.\n- The plugin matches the full URL by default, including query parameters.\n- Query parameter order does not matter, but repeated-value order does.\n- If you use `match_params`, do not also include query parameters in `url`.\n- Unused registered responses fail the test at teardown unless you mark them optional or relax fixture settings.\n- Unexpected outgoing requests still raise `httpx.TimeoutException` even if `assert_all_requests_were_expected=False`; that option only prevents teardown failure for unmatched requests.\n- Suite-wide marker injection through `pytest_collection_modifyitems` is affected by a pytest marker-ordering bug documented upstream; module and class markers may be applied before the suite-level marker.\n\n## Version-Sensitive Notes\n\n- `0.36.0` adds `match_params`, adds Python `3.14` support, requires `pytest==9.*`, and drops Python `3.9` / pytest `8`.\n- `0.35.0` moved to `httpx==0.28.*`. Older test code pinned to HTTPX `0.27.*` needs an older `pytest-httpx`.\n- `0.34.0` added `is_optional` and `is_reusable`; before that, you had to rely more heavily on global marker options.\n\n## Official Sources\n\n- Docs: `https://colin-b.github.io/pytest_httpx/`\n- PyPI project: `https://pypi.org/project/pytest-httpx/`\n- PyPI version metadata: `https://pypi.org/pypi/pytest-httpx/0.36.0/json`\n- Changelog: `https://github.com/Colin-b/pytest_httpx/blob/master/CHANGELOG.md`\n- Repository: `https://github.com/Colin-b/pytest_httpx`\n"
  },
  {
    "path": "content/pytest-mock/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-mock plugin for pytest with a mocker fixture for patching, spying, and stubbing\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.15.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,pytest-mock,python,testing,mocking\"\n---\n\n# pytest-mock Python Package Guide\n\n## Golden Rule\n\nInstall `pytest-mock` in the same environment as `pytest`, then use the `mocker` fixture for patches, spies, and stubs instead of managing `unittest.mock.patch` cleanup manually. The plugin integrates with pytest and automatically undoes its mocks at the end of the fixture scope.\n\n## Install\n\n`pytest-mock 3.15.1` requires Python `>=3.9` and `pytest>=6.2.5`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"pytest>=6.2.5\" \"pytest-mock==3.15.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pytest-mock==3.15.1\"\npoetry add \"pytest-mock==3.15.1\"\n```\n\nIf you want to confirm the plugin is available in the active environment, run:\n\n```bash\npytest --fixtures\n```\n\nLook for `mocker` and the broader-scope variants such as `module_mocker`.\n\n## How The Plugin Loads\n\nNo authentication, environment variables, or runtime initialization are required. Once `pytest-mock` is installed, pytest discovers it as a plugin and makes these fixtures available:\n\n- `mocker` for function scope\n- `class_mocker` for class scope\n- `module_mocker` for module scope\n- `package_mocker` for package scope\n- `session_mocker` for session scope\n\nTyped test signature:\n\n```python\nfrom pytest_mock import MockerFixture\n\ndef test_example(mocker: MockerFixture) -> None:\n    ...\n```\n\n## Patch Functions And Methods\n\nUse `mocker.patch(...)` when your code looks up a symbol by import path, and `mocker.patch.object(...)` when you already have the object instance or class.\n\n```python\n# app.py\nfrom pathlib import Path\n\n\ndef config_path() -> Path:\n    return Path.home() / \".myapp\" / \"config.toml\"\n```\n\n```python\n# test_app.py\nfrom pathlib import Path\n\nfrom pytest_mock import MockerFixture\n\nimport app\n\n\ndef test_config_path(mocker: MockerFixture) -> None:\n    mocker.patch(\"app.Path.home\", return_value=Path(\"/tmp/test-home\"))\n\n    assert app.config_path() == Path(\"/tmp/test-home/.myapp/config.toml\")\n```\n\n```python\n# notifier.py\nclass Mailer:\n    def send(self, recipient: str) -> bool:\n        raise NotImplementedError\n\n\ndef notify(mailer: Mailer, recipient: str) -> bool:\n    return mailer.send(recipient)\n```\n\n```python\n# test_notifier.py\nfrom pytest_mock import MockerFixture\n\nfrom notifier import Mailer, notify\n\n\ndef test_notify(mocker: MockerFixture) -> None:\n    mailer = Mailer()\n    mocked_send = mocker.patch.object(mailer, \"send\", return_value=True)\n\n    assert notify(mailer, \"dev@example.com\") is True\n    mocked_send.assert_called_once_with(\"dev@example.com\")\n```\n\n## Patch Dicts And Environment Variables\n\nUse `mocker.patch.dict(...)` for dictionaries and `os.environ`.\n\n```python\n# settings.py\nimport os\n\n\ndef feature_enabled() -> bool:\n    return os.environ.get(\"FEATURE_FLAG\") == \"1\"\n```\n\n```python\n# test_settings.py\nimport os\n\nfrom pytest_mock import MockerFixture\n\nimport settings\n\n\ndef test_feature_enabled(mocker: MockerFixture) -> None:\n    mocker.patch.dict(os.environ, {\"FEATURE_FLAG\": \"1\"})\n\n    assert settings.feature_enabled() is True\n```\n\n## Spy On Real Calls\n\nUse `mocker.spy(...)` when you want the real implementation to run but still want call assertions.\n\n```python\n# greeter.py\ndef normalize(name: str) -> str:\n    return name.strip().lower()\n\n\ndef greet(name: str) -> str:\n    return f\"hi {normalize(name)}\"\n```\n\n```python\n# test_greeter.py\nfrom pytest_mock import MockerFixture\n\nimport greeter\n\n\ndef test_greet_uses_normalize(mocker: MockerFixture) -> None:\n    spy = mocker.spy(greeter, \"normalize\")\n\n    assert greeter.greet(\" Alice \") == \"hi alice\"\n\n    spy.assert_called_once_with(\" Alice \")\n    assert spy.spy_return == \"alice\"\n```\n\nIf you only want to observe the first part of a test, stop the spy explicitly:\n\n```python\nfrom pytest_mock import MockerFixture\n\nimport greeter\n\n\ndef test_stop_spy(mocker: MockerFixture) -> None:\n    spy = mocker.spy(greeter, \"normalize\")\n\n    greeter.greet(\" Alice \")\n    mocker.stop(spy)\n    greeter.greet(\" Bob \")\n\n    assert spy.call_count == 1\n```\n\n## Use Stubs For Callbacks\n\nUse `mocker.stub()` when the test only needs a callable placeholder and assertion target.\n\n```python\n# worker.py\ndef run_job(on_complete) -> None:\n    on_complete(\"job-123\")\n```\n\n```python\n# test_worker.py\nfrom pytest_mock import MockerFixture\n\nimport worker\n\n\ndef test_run_job_calls_callback(mocker: MockerFixture) -> None:\n    on_complete = mocker.stub(name=\"on_complete\")\n\n    worker.run_job(on_complete)\n\n    on_complete.assert_called_once_with(\"job-123\")\n```\n\n## Broader Fixture Scopes\n\n`mocker` is function-scoped. When a patch must live across more than one test, request the fixture with the matching pytest scope instead of carrying state manually.\n\n```python\n# conftest.py\nimport pytest\n\n\n@pytest.fixture(scope=\"module\", autouse=True)\ndef patch_api_root(module_mocker) -> None:\n    module_mocker.patch(\"app.API_ROOT\", \"https://example.test\")\n```\n\nUse the narrowest scope that matches the test lifetime you actually need.\n\n## Configuration\n\nIn the normal case, no plugin configuration is required.\n\nBy default, `pytest-mock` uses the standard library `unittest.mock` module. If your project explicitly depends on the standalone `mock` package instead, enable it in `pytest.ini`:\n\n```ini\n[pytest]\nmock_use_standalone_module = true\n```\n\nInstall the standalone package only if your project needs it:\n\n```bash\npython -m pip install mock\n```\n\n## Typing\n\nImport `MockerFixture` from `pytest_mock` when you want explicit type annotations in tests.\n\n```python\nfrom pytest_mock import MockerFixture\n\n\ndef test_compute(mocker: MockerFixture) -> None:\n    mocked = mocker.patch(\"app.compute\", return_value=3)\n\n    assert mocked.return_value == 3\n```\n\n## Common Pitfalls\n\n- Patch the name your code actually uses. If `app.py` imported `Path` directly, patch `app.Path.home`, not `pathlib.Path.home`.\n- Use `mocker.patch(...)` directly. The fixture already handles teardown, so you usually do not need patch decorators or context-manager cleanup.\n- Keep fixture scope in mind. `mocker` resets after each test; use `class_mocker`, `module_mocker`, `package_mocker`, or `session_mocker` only when the broader lifetime is intentional.\n- Install both `pytest` and `pytest-mock`. The plugin does not replace pytest itself.\n- If a project still has to run on Python 3.8, it cannot use `pytest-mock 3.15.x`.\n\n## Version-Sensitive Notes For 3.15.x\n\n- This guide targets `pytest-mock 3.15.1`.\n- `3.15.0` dropped Python 3.8 support, so `3.15.x` requires Python 3.9 or newer.\n- `3.15.1` changed `mocker.spy(..., duplicate_iterators=True)` behavior for iterator duplication. Check the 3.15.1 changelog before reusing older spy assertions for iterator-returning functions.\n\n## Official Sources\n\n- Docs root: https://pytest-mock.readthedocs.io/en/latest/\n- Usage: https://pytest-mock.readthedocs.io/en/latest/usage.html\n- Configuration: https://pytest-mock.readthedocs.io/en/latest/configuration.html\n- Remarks: https://pytest-mock.readthedocs.io/en/latest/remarks.html\n- Changelog: https://pytest-mock.readthedocs.io/en/latest/changelog.html\n- PyPI package page: https://pypi.org/project/pytest-mock/\n- Project metadata: https://github.com/pytest-dev/pytest-mock/blob/main/pyproject.toml\n"
  },
  {
    "path": "content/pytest-randomly/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-randomly plugin guide for pytest test ordering and reproducible random seeds in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,pytest-randomly,testing,python,random,seeding\"\n---\n\n# pytest-randomly Python Package Guide\n\n## Golden Rule\n\nUse `pytest-randomly` as an automatically loaded pytest plugin, and treat the printed seed as the first debugging artifact when order-dependent failures appear.\n\nAs of March 12, 2026, the version used here is `4.0.1`. The current maintainer README on the `main` branch describes the same core workflow, but it also says current branch support is Python 3.10 to 3.14, while the PyPI release metadata for `4.0.1` still declares `Requires-Python >=3.9`. Treat the PyPI metadata as the release-specific installer guidance for `4.0.1`.\n\n## Install\n\nInstall it into the same environment as `pytest`:\n\n```bash\npython -m pip install \"pytest-randomly==4.0.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"pytest-randomly==4.0.1\"\npoetry add --group test \"pytest-randomly==4.0.1\"\n```\n\nIf you just need the latest compatible release:\n\n```bash\npython -m pip install pytest-randomly\n```\n\n`pytest-randomly` is a pytest plugin, not a runtime application library. There is no service to start, no client object to initialize, and no authentication or environment variable setup.\n\n## How It Works\n\nOnce installed, `pytest` auto-discovers the plugin and applies these behaviors by default:\n\n- Randomizes test order by module, then class, then function.\n- Prints a base seed at the start of the run.\n- Resets Python's global `random.seed()` before test setup, run, and teardown.\n- Resets supported libraries' random state when they are installed, including `factory_boy`, `Faker`, `Model Bakery`, and NumPy's legacy random state.\n- Works with `pytest-xdist`.\n\nYou normally do not `import pytest_randomly` in tests just to activate it.\n\n## Basic Usage\n\nRun pytest normally:\n\n```bash\npytest\n```\n\nYou should see a line like:\n\n```text\nUsing --randomly-seed=1553614239\n```\n\nReuse that seed to reproduce an order-dependent or random-data-dependent failure:\n\n```bash\npytest --randomly-seed=1553614239\n```\n\nYou can also reuse the last stored seed:\n\n```bash\npytest --randomly-seed=last\n```\n\n`last` depends on pytest's cache provider. If the `cacheprovider` plugin is disabled, use an explicit integer seed instead.\n\n## Project Configuration\n\nPersist your preferred behavior in pytest config so local runs and CI use the same defaults.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"--randomly-seed=last\"\n```\n\nEquivalent `pytest.ini`:\n\n```ini\n[pytest]\naddopts = --randomly-seed=last\n```\n\nFor CI, prefer one of these approaches:\n\n- Use `--randomly-seed=last` when the cache is preserved between runs.\n- Use an explicit seed in reruns when reproducing a specific failure.\n- Let normal runs randomize freely so hidden inter-test dependencies keep surfacing.\n\n## Useful Flags\n\nKeep the default behavior unless you have a concrete reason to narrow it.\n\nDisable only the per-test reseeding:\n\n```bash\npytest --randomly-dont-reset-seed\n```\n\nDisable only test reordering:\n\n```bash\npytest --randomly-dont-reorganize\n```\n\nDisable the plugin entirely:\n\n```bash\npytest -p no:randomly\n```\n\n## Core Debugging Workflow\n\nWhen a failure appears only under a specific order:\n\n1. Re-run with the printed seed.\n2. Narrow the target to the failing module or class while keeping the same seed.\n3. Look for leaked global state, shared fixtures, database residue, monkeypatches not undone, or random test data that was never pinned.\n\nExample:\n\n```bash\npytest --randomly-seed=1234 tests/test_orders.py\npytest --randomly-seed=1234 tests/test_orders.py::TestCheckoutFlow\n```\n\nBecause ordering is module -> class -> function, narrowing the scope while keeping the same seed is often the fastest way to isolate the dependency.\n\n## Integration With Random-Using Libraries\n\n`pytest-randomly` can reset more than the stdlib RNG:\n\n- `factory_boy`\n- `Faker`\n- `Model Bakery`\n- NumPy legacy random state\n\nThis is useful when tests generate data through factories or fake data providers and still need deterministic reproduction from one seed.\n\nIf your own package has another random generator, register a setuptools entry point so `pytest-randomly` reseeds it for every test.\n\n`setup.cfg`:\n\n```ini\n[options.entry_points]\npytest_randomly.random_seeder =\n    mypackage = mypackage.reseed\n```\n\nImplement the callable to accept the new integer seed:\n\n```python\ndef reseed(new_seed: int) -> None:\n    ...\n```\n\n## Imports, Environment, And Initialization\n\n- Imports: none required for activation; install the plugin and run `pytest`.\n- Environment variables: none required by the plugin itself.\n- Initialization: none; pytest auto-loads installed plugins.\n- Extension hook: optional `pytest_randomly.random_seeder` entry points if your package needs custom reseeding.\n\n## Common Pitfalls\n\n- Do not try to `import pytest_randomly` in normal test code just to \"activate\" it. Installation is enough.\n- Do not ignore the printed seed when a flaky failure appears. Without it, reproducing the same order is much harder.\n- `--randomly-seed=last` only works when pytest cache is available.\n- If tests implicitly rely on process-global RNG state, installing this plugin can surface failures immediately. That is usually the point, not a plugin bug.\n- NumPy support only covers the legacy random state. If your test suite uses `numpy.random.default_rng()`, define and document your own reproducibility strategy.\n- If you disable reordering to make failures disappear, you may hide real inter-test dependencies instead of fixing them.\n- When combining with `pytest-order`, read that plugin's docs for interaction rules instead of assuming both plugins will preserve your intended order automatically.\n\n## Version Notes For 4.0.1\n\n- PyPI shows `pytest-randomly 4.0.1` released on September 12, 2025.\n- PyPI release metadata for `4.0.1` declares `Requires-Python >=3.9`.\n- The current GitHub README says the `main` branch supports Python 3.10 to 3.14. Treat that as newer maintainer guidance for current development, not a stricter requirement for the already-published `4.0.1` release.\n- The maintainer repository is the canonical documentation surface for this package; there is no separate hosted docs site to prefer here.\n\n## Official Sources\n\n- Maintainer docs and usage guide: https://github.com/pytest-dev/pytest-randomly\n- Package registry and release metadata: https://pypi.org/project/pytest-randomly/\n"
  },
  {
    "path": "content/pytest-sugar/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-sugar package guide for prettier pytest output, progress bars, and Playwright trace hints\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest-sugar,pytest,testing,terminal,ci,playwright\"\n---\n\n# pytest-sugar Python Package Guide\n\n## What It Is\n\nUse `pytest-sugar` as a pytest terminal UI plugin. It changes console output, adds a progress bar, and can show Playwright trace locations, but it does not change pytest's core collection, fixture, or assertion behavior.\n\nThis entry covers package version `1.1.1`.\n\n## Install\n\nInstall it into the same environment as `pytest`:\n\n```bash\npython -m pip install \"pytest-sugar==1.1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"pytest-sugar==1.1.1\"\npoetry add \"pytest-sugar==1.1.1\"\n```\n\nRun tests normally after install:\n\n```bash\npytest\n```\n\nThe plugin auto-loads when pytest discovers installed plugins.\n\n## Initialization And Configuration Model\n\nThere is no package-specific Python client to initialize, no authentication flow, and no package-specific environment variable required for normal usage.\n\nUse the same pytest entrypoint you already use:\n\n```bash\npytest\n```\n\nFor persistent defaults, put options in normal pytest config such as `pyproject.toml` or `pytest.ini`.\n\n## Core Usage\n\n### Default behavior\n\nAfter installation, `pytest-sugar` replaces pytest's standard progress/output view with a progress bar and prints failures as they happen.\n\n```bash\npytest\n```\n\n### Verbose mode\n\nUse verbose mode if you want one test per line instead of the condensed progress UI:\n\n```bash\npytest --verbose\n```\n\n### Disable sugar for one run\n\nIf CI tooling or another plugin expects plain pytest output, disable `pytest-sugar` explicitly:\n\n```bash\npytest -p no:sugar\n```\n\n## Important CLI Options\n\n### Use the older detailed summary\n\n```bash\npytest --old-summary\n```\n\nUse this when the default instant-failure display is too compact and you want a more traditional detailed summary.\n\n### Force sugar output in non-interactive environments\n\n```bash\npytest --force-sugar\n```\n\nUse this in CI, containers, or redirected output where pytest does not think it is attached to a real terminal.\n\n### Control Playwright trace lookup\n\nBy default, the plugin looks for Playwright traces in Playwright Python's default output directory, `test-results`.\n\n```bash\npytest --sugar-trace-dir artifacts/playwright\n```\n\nDisable trace lookup entirely if it adds noise:\n\n```bash\npytest --sugar-no-trace\n```\n\n## Project Configuration\n\n### Pytest config\n\nFor most projects, keep defaults in regular pytest config through `addopts`.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"-ra --force-sugar\"\n```\n\n`pytest.ini`:\n\n```ini\n[pytest]\naddopts = -ra --force-sugar\n```\n\n### `pytest-sugar.conf`\n\nUse the optional `pytest-sugar.conf` file only for presentation tweaks such as theme symbols, colors, and progress bar length.\n\n```ini\n[theme]\nsymbol_passed = ✓\nsymbol_failed = x\n\n[sugar]\nprogressbar_length = 30\n```\n\nKeep real test behavior in pytest config, not in the sugar-specific file.\n\n## Common Workflows\n\n### Local development\n\n```bash\npytest tests/unit\n```\n\nThis is the common case: auto-loaded plugin, compact progress display, and failures shown immediately.\n\n### CI with forced terminal-style output\n\n```bash\npytest --force-sugar --maxfail=1\n```\n\nThis is useful when CI captures stdout without a real TTY and you still want the sugar progress UI.\n\n### Playwright end-to-end tests\n\n```bash\npytest tests/e2e --sugar-trace-dir test-results\n```\n\nIf Playwright writes traces on failures, `pytest-sugar` can point to those artifacts from test output.\n\n## Common Pitfalls\n\n- Do not treat `pytest-sugar` as a reporting backend. It is a terminal UX plugin, not an HTML, JUnit, or results storage system.\n- In CI or redirected output, the progress UI may not appear unless you add `--force-sugar`.\n- If another tool parses raw pytest output, disable sugar with `-p no:sugar` for that job.\n- The formatting is most useful in human-facing runs; plain pytest output is often better for machine-consumed logs.\n- Windows terminals can render odd glyphs or colors depending on terminal font and charset settings. If output looks wrong, simplify theme symbols or fall back to plain pytest output.\n- Playwright trace hints depend on where traces are actually written. If your suite uses a non-default artifact directory, set `--sugar-trace-dir` explicitly.\n\n## Version-Sensitive Notes\n\n- This entry targets `1.1.1`.\n- PyPI release history shows `1.1.1` published on August 23, 2025.\n- The PyPI long description still mentions older compatibility floors, while the maintainer repository for the current `1.1.x` line has newer packaging constraints. If you are pinning older Python or pytest versions, check the repo packaging metadata instead of relying on stale PyPI prose.\n- The `1.1.x` line includes Playwright trace-related options such as `--sugar-trace-dir` and `--sugar-no-trace`. Older blog posts and screenshots from pre-`1.0` releases may not mention them.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/pytest-sugar/`\n- PyPI project JSON/API page: `https://pypi.org/pypi/pytest-sugar/`\n- Maintainer repository: `https://github.com/Teemu/pytest-sugar`\n- README: `https://github.com/Teemu/pytest-sugar/blob/main/README.md`\n- Changelog/releases source: `https://github.com/Teemu/pytest-sugar/blob/main/CHANGES.rst`\n"
  },
  {
    "path": "content/pytest-timeout/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-timeout plugin guide for adding per-test and session time limits to pytest suites\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,testing,timeout,python,ci\"\n---\n\n# pytest-timeout Python Package Guide\n\n## What It Is\n\n`pytest-timeout` is a pytest plugin for failing tests that hang longer than an allowed limit. Use it to keep deadlocks, infinite loops, or stuck network calls from blocking the whole test run.\n\nUse timeouts as a safety net, not as a benchmark. If a suite needs a whole-run cap, pair `--session-timeout` with a normal per-test timeout because session timeouts are only checked between tests.\n\n## Install\n\n`pytest-timeout 2.4.0` requires Python `>=3.7`, and the `2.3.x` line raised the minimum supported `pytest` version to `7.0.0`.\n\nInstall it with pytest in the same environment:\n\n```bash\npython -m pip install \"pytest>=7\" \"pytest-timeout==2.4.0\"\n```\n\nThere is no runtime initialization code. After install, pytest loads the plugin automatically and exposes timeout-related CLI options, config keys, and the `timeout` marker.\n\n## Quick Start\n\nSet a default timeout for every test in the current run:\n\n```bash\npytest --timeout=30\n```\n\nAdd a whole-suite cap as a second guardrail:\n\n```bash\npytest --timeout=30 --session-timeout=900\n```\n\nSet a timeout on one test only:\n\n```python\nimport pytest\n\n\n@pytest.mark.timeout(5)\ndef test_fast_path() -> None:\n    ...\n```\n\nOverride the timeout method for one test:\n\n```python\nimport pytest\n\n\n@pytest.mark.timeout(10, method=\"thread\")\ndef test_might_deadlock() -> None:\n    ...\n```\n\nDisable a global timeout for one test:\n\n```python\nimport pytest\n\n\n@pytest.mark.timeout(0)\ndef test_intentionally_long() -> None:\n    ...\n```\n\n## Configure Defaults\n\nTimeout settings apply from lowest to highest priority:\n\n1. `timeout` in pytest config\n2. `PYTEST_TIMEOUT` environment variable\n3. `--timeout` on the command line\n4. `@pytest.mark.timeout(...)` on an individual test\n\nExample `pytest.ini`:\n\n```ini\n[pytest]\ntimeout = 30\ntimeout_method = signal\nsession_timeout = 900\ntimeout_func_only = false\n```\n\nEquivalent `pyproject.toml` config:\n\n```toml\n[tool.pytest.ini_options]\ntimeout = 30\ntimeout_method = \"signal\"\nsession_timeout = 900\ntimeout_func_only = false\n```\n\nYou can also set the default from the environment:\n\n```bash\nexport PYTEST_TIMEOUT=30\npytest\n```\n\n## Choose A Timeout Method\n\n`pytest-timeout` supports two timeout mechanisms:\n\n- `signal`: preferred on POSIX systems where `SIGALRM` is available; pytest can usually fail the timed-out test and keep running normally\n- `thread`: fallback mode that uses a timer thread and terminates the whole process when the timeout expires\n\nUse the hyphenated CLI spelling in new commands:\n\n```bash\npytest --timeout=30 --timeout-method=thread\n```\n\nThe config key stays `timeout_method`, and older docs may still show the old CLI form `--timeout_method`.\n\nChoose `thread` when:\n\n- the code under test already uses signals or `SIGALRM`\n- the signal method is unavailable on the platform\n- hard-stop reliability matters more than preserving normal teardown and reporting\n\nChoose `signal` when:\n\n- you are on a POSIX platform with `SIGALRM`\n- keeping normal pytest teardown and reporting is more important than a hard process exit\n\n## Fixtures, Setup, And Teardown\n\nBy default, the timeout covers the full test lifecycle:\n\n- fixture setup\n- test body\n- fixture teardown and finalizers\n\nIf fixture time should not count, enable `timeout_func_only` globally or pass `func_only=True` on the marker:\n\n```python\nimport pytest\n\n\n@pytest.mark.timeout(10, func_only=True)\ndef test_only_the_function_body_is_timed() -> None:\n    ...\n```\n\nBe careful with this setting. If setup or teardown is what hangs, `func_only=True` will not protect that phase.\n\n## Session Timeout\n\nUse `session_timeout` or `--session-timeout` to cap the full pytest invocation:\n\n```bash\npytest --timeout=15 --session-timeout=600\n```\n\nImportant behavior:\n\n- session timeout is checked between tests, not during a still-running test\n- a stuck test still needs its own timeout to be interrupted\n- combining per-test and session timeouts is the safer setup\n\n## Debugger Behavior\n\nThe plugin tries to avoid firing while a debugger is attached. That helps local debugging, but it can also hide timeouts if a debugger stays active unexpectedly.\n\nIf you need to disable debugger detection, use the config setting:\n\n```ini\n[pytest]\ntimeout_disable_debugger_detection = true\n```\n\n## Common Pitfalls\n\n- Do not use timeout failures as a substitute for making tests fast or deterministic.\n- `thread` mode can end the process with `os._exit()`, which can skip teardown, truncate JUnit XML, and prevent other plugins from cleaning up cleanly.\n- `signal` mode can conflict with code that already depends on `SIGALRM`.\n- Fixture setup and teardown count toward the timeout unless you opt into `timeout_func_only`.\n- A test-level marker overrides a global `timeout_func_only = true` unless that marker also passes `func_only=True`.\n- Session timeout alone will not rescue one permanently hung test.\n- Older docs may mention timeout diagnostics on `stderr`; since `2.3.0`, reporting goes through pytest's `TerminalReporter`, so the output is written through normal pytest terminal reporting.\n\n## Version-Sensitive Notes\n\n- `2.4.0` improves debugger detection for debuggers registered with `sys.monitoring`.\n- `2.3.0` raised the minimum supported pytest version to `7.0.0`.\n- `2.3.0` added `--session-timeout` and the `session_timeout` config setting.\n- The preferred CLI spelling is `--timeout-method`; older examples may still use `--timeout_method`.\n- PyPI metadata for `2.4.0` requires Python `>=3.7`.\n\n## Official Source URLs\n\n- GitHub repository: `https://github.com/pytest-dev/pytest-timeout`\n- PyPI package page for `2.4.0`: `https://pypi.org/project/pytest-timeout/2.4.0/`\n- PyPI latest page: `https://pypi.org/project/pytest-timeout/`\n- pytest configuration reference: `https://docs.pytest.org/en/stable/reference/customize.html`\n- pytest marker reference: `https://docs.pytest.org/en/stable/how-to/mark.html`\n"
  },
  {
    "path": "content/pytest-xdist/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytest-xdist package guide for parallel pytest runs, worker-aware fixtures, and distributed scheduling\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.8.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"pytest,pytest-xdist,python,testing,parallelism,ci\"\n---\n\n# pytest-xdist Python Package Guide\n\n## Golden Rule\n\nUse `pytest-xdist` only to parallelize a suite that already passes reliably under plain `pytest`. The plugin changes scheduling and process boundaries; it does not make flaky or stateful tests safe.\n\n`pytest-xdist` is a pytest plugin, not an application runtime dependency. Install it in the same environment as `pytest` and invoke it through the pytest CLI.\n\n## Install\n\n`pytest-xdist 3.8.0` supports Python `>=3.9` and depends on `pytest>=7.0.0` plus `execnet>=2.1.0`.\n\nInstall it into your test environment:\n\n```bash\npython -m pip install \"pytest-xdist==3.8.0\"\n```\n\nCommon project tool equivalents:\n\n```bash\nuv add --dev \"pytest-xdist==3.8.0\"\npoetry add --group dev \"pytest-xdist==3.8.0\"\n```\n\nOptional extras published on PyPI:\n\n```bash\npython -m pip install \"pytest-xdist[psutil]==3.8.0\"\npython -m pip install \"pytest-xdist[setproctitle]==3.8.0\"\n```\n\n- `psutil` improves CPU detection for `-n logical`.\n- `setproctitle` gives workers clearer process names in tools like `ps` and `top`.\n\n## Initialization And Configuration\n\nThere is no auth setup and no client object to initialize. After installation, the plugin auto-registers with pytest.\n\nMinimal parallel run:\n\n```bash\npytest -n auto\n```\n\nUseful variants:\n\n```bash\npytest -n 4\npytest -n logical\npytest -n 0\n```\n\n- `-n auto` uses the machine's physical CPU cores.\n- `-n logical` uses logical cores when `psutil` can determine them; otherwise it falls back to `auto` behavior.\n- `-n 0` disables xdist and runs in the main process.\n\nIf parallel execution is your default, keep it in pytest config instead of a shell wrapper.\n\n`pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = \"-ra -n auto --dist loadscope\"\n```\n\nEquivalent `pytest.ini`:\n\n```ini\n[pytest]\naddopts = -ra -n auto --dist loadscope\n```\n\nTo override how many workers `-n auto` should use, set the documented environment variable:\n\n```bash\nexport PYTEST_XDIST_AUTO_NUM_WORKERS=6\npytest -n auto\n```\n\nYou can also implement the `pytest_xdist_auto_num_workers(config)` hook in `conftest.py`.\n\n## Common Workflows\n\n### Speed up a suite\n\n```bash\npytest -n auto tests\n```\n\nThis is the standard starting point for a suite that is already stable in single-process mode.\n\n### Choose a scheduler deliberately\n\n```bash\npytest -n auto --dist load\npytest -n auto --dist loadscope\npytest -n auto --dist loadfile\npytest -n auto --dist loadgroup\npytest -n auto --dist worksteal\n```\n\nUse these modes when behavior matters more than raw throughput:\n\n- `load`: default scheduler; good general throughput.\n- `loadscope`: keeps tests from the same module or class on the same worker.\n- `loadfile`: keeps each file on one worker.\n- `loadgroup`: keeps tests sharing an `xdist_group` mark on the same worker.\n- `worksteal`: redistributes queued tests from busy workers to idle ones.\n\n### Keep related tests on one worker\n\nWhen tests need to share a browser session, service container, or other stateful fixture, group them explicitly:\n\n```python\nimport pytest\n\n\n@pytest.mark.xdist_group(\"chrome\")\ndef test_login_in_chrome() -> None:\n    ...\n\n\n@pytest.mark.xdist_group(\"chrome\")\ndef test_checkout_in_chrome() -> None:\n    ...\n```\n\nRun with:\n\n```bash\npytest -n auto --dist loadgroup\n```\n\n### Control `loadscope` ordering in 3.8.0\n\n`pytest-xdist 3.8.0` adds explicit `loadscope` reordering controls:\n\n```bash\npytest -n auto --dist loadscope --no-loadscope-reorder\npytest -n auto --dist loadscope --loadscope-reorder\n```\n\nUse `--no-loadscope-reorder` when relative file ordering still matters inside `loadscope` groups.\n\n## Worker-Aware Tests And Fixtures\n\n### Detect the current worker\n\nUse the built-in `worker_id` fixture when a test resource must be unique per worker:\n\n```python\nimport pytest\n\n\n@pytest.fixture\ndef user_account(worker_id: str) -> str:\n    return f\"account_{worker_id}\"\n```\n\nWhen xdist is disabled, `worker_id` returns `\"master\"`, so the same fixture works for both local debugging and parallel CI.\n\n### Read worker environment variables\n\nWorkers expose these environment variables:\n\n- `PYTEST_XDIST_WORKER`\n- `PYTEST_XDIST_WORKER_COUNT`\n- `PYTEST_XDIST_TESTRUNUID`\n\nExample:\n\n```python\nimport os\n\n\ndef test_worker_env() -> None:\n    worker_name = os.getenv(\"PYTEST_XDIST_WORKER\", \"master\")\n    worker_count = int(os.getenv(\"PYTEST_XDIST_WORKER_COUNT\", \"1\"))\n    assert worker_name\n    assert worker_count >= 1\n```\n\n### Create one namespace per distributed run\n\nUse `testrun_uid` when all workers should share one logical identifier for the entire run:\n\n```python\nimport pytest\n\n\n@pytest.fixture(scope=\"session\")\ndef database_name(testrun_uid: str) -> str:\n    return f\"test_db_{testrun_uid}\"\n```\n\nThis is the right pattern for temporary databases, object stores, or directory prefixes that must be unique per CI run rather than per worker.\n\n### Handle session fixtures correctly\n\nHigh-scope fixtures are not global across all workers. A `session` fixture can run once per worker.\n\nIf setup must happen exactly once, add your own inter-process lock:\n\n```python\nimport json\nfrom pathlib import Path\n\nimport pytest\nfrom filelock import FileLock\n\n\ndef produce_expensive_data() -> dict[str, str]:\n    return {\"token\": \"generated-once\"}\n\n\n@pytest.fixture(scope=\"session\")\ndef session_data(\n    tmp_path_factory: pytest.TempPathFactory,\n    worker_id: str,\n) -> dict[str, str]:\n    if worker_id == \"master\":\n        return produce_expensive_data()\n\n    root_tmp_dir = tmp_path_factory.getbasetemp().parent\n    data_file = Path(root_tmp_dir) / \"session-data.json\"\n\n    with FileLock(str(data_file) + \".lock\"):\n        if data_file.exists():\n            return json.loads(data_file.read_text())\n\n        data = produce_expensive_data()\n        data_file.write_text(json.dumps(data))\n        return data\n```\n\nInstall `filelock` yourself if you use this pattern.\n\n## Diagnostics And Failure Handling\n\nCap automatic worker restarts when you want crashes to fail fast in CI:\n\n```bash\npytest -n auto --max-worker-restart 2\npytest -n auto --max-worker-restart 0\n```\n\nFor one log file per worker, use `PYTEST_XDIST_WORKER` during pytest setup:\n\n```python\nimport logging\nimport os\n\n\ndef pytest_configure(config) -> None:\n    worker_id = os.environ.get(\"PYTEST_XDIST_WORKER\")\n    if worker_id:\n        logging.basicConfig(\n            filename=f\"tests_{worker_id}.log\",\n            level=config.getini(\"log_file_level\"),\n            format=config.getini(\"log_file_format\"),\n        )\n```\n\n## Important Pitfalls\n\n- `-s` and `--capture=no` do not stream live worker stdout or stderr back through xdist.\n- `--pdb` is disabled for distributed runs; rerun with `-n 0` or without `-n` before interactive debugging.\n- Test collection order must match across workers. Avoid parametrizing from unordered sets or other unstable sources.\n- `session` fixtures are not singletons across the whole run.\n- Shared temp files, ports, and database names must be worker-aware or run-aware.\n- `load` gives the highest throughput, but it can increase fixture churn compared with `loadscope`, `loadfile`, or `loadgroup`.\n- Keep flaky tests out of parallel mode until they are deterministic in single-process runs.\n\n## Version Notes For 3.8.0\n\n- `3.8.0` adds `--loadscope-reorder` and `--no-loadscope-reorder`.\n- Python `3.8` support was dropped in `3.7.0`, so `3.9+` is the practical baseline for `3.8.0`.\n- Remote rsync mode and `--looponfail` are still documented but were deprecated earlier and are planned for removal in xdist `4.0`.\n- `--boxed` is already removed from modern xdist; use `pytest-forked` if you specifically need fork isolation.\n\n## Recommended Workflow\n\n1. Run `pytest` without xdist first.\n2. Enable parallelism with `pytest -n auto`.\n3. If stateful tests churn too much, switch to `--dist loadscope`, `loadfile`, or `loadgroup`.\n4. If failures only happen in parallel mode, make resource names worker-aware and rerun with a smaller fixed worker count such as `-n 2`.\n5. For debugging, rerun the same subset with `-n 0` and then use your normal debugger or `--pdb`.\n\n## Official Sources\n\n- Stable docs: `https://pytest-xdist.readthedocs.io/en/stable/`\n- Distribution guide: `https://pytest-xdist.readthedocs.io/en/stable/distribution.html`\n- How-to guide: `https://pytest-xdist.readthedocs.io/en/stable/how-to.html`\n- Known limitations: `https://pytest-xdist.readthedocs.io/en/stable/known-limitations.html`\n- Changelog: `https://pytest-xdist.readthedocs.io/en/stable/changelog.html`\n- PyPI package page: `https://pypi.org/project/pytest-xdist/`\n"
  },
  {
    "path": "content/python-dateutil/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-dateutil for Python: datetime parsing, calendar-aware arithmetic, recurrence rules, and timezone helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.9.0.post0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-dateutil,dateutil,python,datetime,timezone,parsing,rrule,relativedelta\"\n---\n\n# python-dateutil Python Package Guide\n\n## Golden Rules\n\n- Install `python-dateutil`, but import from `dateutil`.\n- Prefer `parser.isoparse()` for strict ISO-8601 input and use `parser.parse()` when the input is loose or human-written.\n- Use `relativedelta` for calendar-aware arithmetic. `timedelta(days=30)` is not a substitute for \"next month\".\n- Use `rrule` for recurring schedules and `dateutil.tz` helpers for timezone-aware and DST-aware datetime handling.\n\n## Installation\n\n```bash\npip install python-dateutil\n```\n\n```bash\npip install \"python-dateutil==2.9.0.post0\"\n```\n\n```bash\nuv add python-dateutil\n```\n\n```bash\npoetry add python-dateutil\n```\n\n## Initialization and Imports\n\nThere is no client object, authentication flow, or service setup. Import only the submodules you need.\n\n```python\nfrom datetime import datetime\n\nfrom dateutil import tz\nfrom dateutil.parser import isoparse, parse\nfrom dateutil.relativedelta import MO, relativedelta\nfrom dateutil.rrule import DAILY, MONTHLY, WE, rrule\n```\n\nOn Python 3.7+, the `2.9.x` line lazily imports submodules, so this also works:\n\n```python\nimport dateutil\n\npacific = dateutil.tz.gettz(\"America/Los_Angeles\")\n```\n\n## Core Usage\n\n### Parse loose date and time strings\n\nUse `parse()` when the input format is inconsistent or user-provided.\n\n```python\nfrom dateutil.parser import parse\n\ndt = parse(\n    \"2026-03-11 09:30 PST\",\n    dayfirst=False,\n    yearfirst=True,\n)\n```\n\nUseful parser controls:\n\n- `default=` fills missing components from a fallback `datetime`\n- `ignoretz=True` ignores timezone information and returns a naive `datetime`\n- `tzinfos=` maps custom abbreviations to offsets or `tzinfo` objects\n- `fuzzy=True` ignores extra words\n- `fuzzy_with_tokens=True` returns both the parsed `datetime` and the ignored text\n\nExample with custom timezone aliases:\n\n```python\nfrom dateutil.parser import parse\nfrom dateutil.tz import gettz\n\ntzinfos = {\n    \"PT\": gettz(\"America/Los_Angeles\"),\n    \"ET\": gettz(\"America/New_York\"),\n}\n\ndt = parse(\"2026-03-11 09:30 PT\", tzinfos=tzinfos)\n```\n\n### Parse strict ISO-8601 input\n\nUse `isoparse()` for API payloads, JSON timestamps, and other machine-generated input.\n\n```python\nfrom dateutil.parser import isoparse\n\ncreated_at = isoparse(\"2026-03-11T09:30:00Z\")\nweek_date = isoparse(\"2026-W11-3T09:30:00+00:00\")\nmidnight_next_day = isoparse(\"2026-03-11T24:00\")\n```\n\n`isoparse()` is stricter than `parse()` and handles ISO week dates and fractional seconds with either `.` or `,`.\n\n### Do calendar-aware arithmetic with `relativedelta`\n\n`relativedelta` handles months, years, weekdays, and month-end rollover.\n\n```python\nfrom datetime import datetime\nfrom dateutil.relativedelta import MO, relativedelta\n\ndt = datetime(2026, 1, 31, 10, 0)\n\nsame_clock_next_month = dt + relativedelta(months=+1)\nfirst_monday_next_month = dt + relativedelta(months=+1, day=1, weekday=MO(1))\n```\n\nImportant rule:\n\n- Singular arguments like `year=`, `month=`, `day=` are absolute replacements.\n- Plural arguments like `years=`, `months=`, `days=` are arithmetic deltas.\n\n```python\nfrom datetime import datetime\nfrom dateutil.relativedelta import relativedelta\n\ndt = datetime(2026, 3, 11, 9, 30)\n\nreplaced = dt + relativedelta(day=1)      # 2026-03-01 09:30\nshifted = dt + relativedelta(days=+1)     # 2026-03-12 09:30\n```\n\n### Generate recurring schedules with `rrule`\n\nUse `rrule` for iCalendar-style recurrence sets.\n\n```python\nfrom datetime import datetime\nfrom dateutil.rrule import MONTHLY, WE, rrule\n\nmeetings = rrule(\n    MONTHLY,\n    count=4,\n    byweekday=WE(2),\n    dtstart=datetime(2026, 1, 1, 9, 0),\n)\n\nfor dt in meetings:\n    print(dt)\n```\n\nThe frequency constants are `YEARLY`, `MONTHLY`, `WEEKLY`, `DAILY`, `HOURLY`, `MINUTELY`, and `SECONDLY`.\n\nIf you will iterate the same recurrence many times, enable caching:\n\n```python\nfrom datetime import datetime\nfrom dateutil.rrule import DAILY, rrule\n\nevents = rrule(DAILY, count=365, cache=True, dtstart=datetime(2026, 1, 1))\n```\n\n### Work with time zones and DST transitions\n\nUse `gettz()` for named zones and `UTC` for a canonical UTC tzinfo.\n\n```python\nfrom datetime import datetime\nfrom dateutil.tz import UTC, datetime_ambiguous, datetime_exists, gettz, resolve_imaginary\n\nnyc = gettz(\"America/New_York\")\ndt = datetime(2026, 3, 8, 2, 30, tzinfo=nyc)\n\nif not datetime_exists(dt):\n    dt = resolve_imaginary(dt)\n\nis_fold = datetime_ambiguous(dt)\nutc_dt = dt.astimezone(UTC)\n```\n\nRepeated calls to `gettz()` with the same zone string return the same object, which helps preserve \"same zone\" semantics in comparisons and conversions.\n\n## Configuration and Environment\n\nThere is no auth or remote service configuration layer.\n\nCommon project-level configuration is limited to:\n\n- parser behavior: `dayfirst`, `yearfirst`, `default`, `tzinfos`, `fuzzy`\n- timezone identifiers passed to `tz.gettz()`\n- recurrence parameters passed to `rrule()`\n\nIf your code depends on local-machine timezone resolution, remember that `gettz()` with no arguments reads the host environment. Container, CI, and developer-laptop defaults can differ.\n\n## Common Pitfalls\n\n### Install name and import name differ\n\nInstall `python-dateutil`, but write imports against `dateutil`.\n\n### `parse()` is intentionally forgiving\n\n`parse()` will accept many ambiguous or partially specified inputs. For stable machine input, prefer `isoparse()` or `datetime.fromisoformat()` when the format is fixed.\n\n### `default=` can silently change missing fields\n\nWhen parsing a partial date, missing components come from `default=`. If that produces an invalid day, `parse()` falls back to the end of the month. Test partial-date behavior explicitly.\n\n### Ambiguous dates need an explicit policy\n\nInputs like `01/02/03` are ambiguous. Set `dayfirst` and `yearfirst` explicitly instead of relying on defaults.\n\n### `ignoretz=True` discards timezone information\n\nIf the source string includes an offset or named timezone, `ignoretz=True` returns a naive `datetime`. That is lossy.\n\n### `relativedelta` singular vs plural changes behavior\n\n`month=1` means \"set month to January\". `months=+1` means \"add one calendar month\". Mixing them is valid, but easy to misread.\n\n### `rrule` skips invalid instances\n\nPer RFC 5545, invalid dates and nonexistent local times are ignored rather than coerced. End-of-month schedules and DST transitions can produce fewer occurrences than you expect.\n\n### Do not mix `count` and `until`\n\nThe docs deprecate using `count` and `until` together in the same recurrence rule to stay aligned with RFC 5545 semantics.\n\n### `gettz()` can return `None`\n\nUnknown timezone strings are not resolved automatically. Check the return value before attaching it to a `datetime`.\n\n## Version-Sensitive Notes\n\n- This doc is pinned to `2.9.0.post0`, the version used here and the current PyPI release for `python-dateutil`.\n- `2.9.0.post0` is a post release. The maintainer release notes describe it as a packaging-only fix for `setuptools_scm` compatibility, so the runtime guidance here is effectively the same as `2.9.0`.\n- The `2.9.0` changelog notes three practical behavior changes relevant to agents:\n  - submodules are lazily imported on Python 3.7+\n  - deprecated `datetime.utcfromtimestamp` usage was removed for Python 3.12 compatibility\n  - the `relativedelta` docs were clarified around month-end behavior\n- The stable Read the Docs site is the right API reference, but its page title/version text is not a reliable package-version signal for this release line. Use PyPI and maintainer release tags when pinning versions.\n\n## Official Sources\n\n- Docs root: https://dateutil.readthedocs.io/en/stable/\n- Parser reference: https://dateutil.readthedocs.io/en/stable/parser.html\n- `relativedelta` reference: https://dateutil.readthedocs.io/en/stable/relativedelta.html\n- `rrule` reference: https://dateutil.readthedocs.io/en/stable/rrule.html\n- Time zone reference: https://dateutil.readthedocs.io/en/stable/tz.html\n- Changelog: https://dateutil.readthedocs.io/en/stable/changelog.html\n- PyPI package page: https://pypi.org/project/python-dateutil/\n- Maintainer release notes: https://github.com/dateutil/dateutil/releases/tag/2.9.0.post0\n"
  },
  {
    "path": "content/python-docx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-docx package guide for creating and editing Word .docx files from Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-docx,docx,word,office,document-generation\"\n---\n\n# python-docx Python Package Guide\n\n## Golden Rule\n\nUse `python-docx` for `.docx` generation and editing, import it as `from docx import Document`, and start from a real `.docx` template whenever styles, numbering, headers, or page layout matter. The package works on Office Open XML Word documents; it does not read legacy `.doc` files.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"python-docx==1.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"python-docx==1.2.0\"\npoetry add \"python-docx==1.2.0\"\n```\n\nNotes:\n\n- `python-docx` installs its XML dependency stack through pip; you normally do not install `lxml` separately.\n- The upstream docs site is current for the API and user guide, but its install page still contains older environment guidance. Prefer modern `pip`, `uv`, or `poetry` commands plus PyPI metadata for version requirements.\n\n## Initialize And Save\n\nCreate a new document:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Quarterly Report\", level=1)\ndocument.add_paragraph(\"Generated by python-docx.\")\ndocument.save(\"report.docx\")\n```\n\nOpen an existing `.docx` as a template so you keep its styles, headers, footers, and page settings:\n\n```python\nfrom docx import Document\n\ndocument = Document(\"template.docx\")\ndocument.add_paragraph(\"Inserted into a styled template.\")\ndocument.save(\"output.docx\")\n```\n\nWrite to memory instead of disk when returning a file from a web handler:\n\n```python\nfrom io import BytesIO\nfrom docx import Document\n\ndocument = Document()\ndocument.add_paragraph(\"Hello from memory\")\n\nbuf = BytesIO()\ndocument.save(buf)\npayload = buf.getvalue()\n```\n\n## Core Usage\n\n### Paragraphs, runs, and styles\n\nParagraph text is made of runs. Use runs when you need mixed formatting:\n\n```python\nfrom docx import Document\n\ndocument = Document()\n\nparagraph = document.add_paragraph(style=\"Body Text\")\nparagraph.add_run(\"Normal text, \")\n\nbold_run = paragraph.add_run(\"bold text\")\nbold_run.bold = True\n\nitalic_run = paragraph.add_run(\", and italic text.\")\nitalic_run.italic = True\n\ndocument.add_paragraph(\"Main heading\", style=\"Heading 1\")\ndocument.save(\"styled.docx\")\n```\n\n### Tables\n\n```python\nfrom docx import Document\n\ndocument = Document()\ntable = document.add_table(rows=1, cols=3)\ntable.style = \"LightShading-Accent1\"\n\nheader = table.rows[0].cells\nheader[0].text = \"Name\"\nheader[1].text = \"Role\"\nheader[2].text = \"Active\"\n\nrow = table.add_row().cells\nrow[0].text = \"Ana\"\nrow[1].text = \"Editor\"\nrow[2].text = \"Yes\"\n\ndocument.save(\"table.docx\")\n```\n\n### Pictures\n\n`python-docx` supports inline pictures:\n\n```python\nfrom docx import Document\nfrom docx.shared import Inches\n\ndocument = Document()\ndocument.add_picture(\"diagram.png\", width=Inches(4.5))\ndocument.save(\"image.docx\")\n```\n\n### Sections, margins, headers, and footers\n\nUse section settings for page layout. When you create a new section, its header and footer are linked to the previous section by default.\n\n```python\nfrom docx import Document\nfrom docx.enum.section import WD_SECTION\nfrom docx.shared import Inches\n\ndocument = Document(\"template.docx\")\n\nsection = document.sections[0]\nsection.left_margin = Inches(1)\nsection.right_margin = Inches(1)\n\nnew_section = document.add_section(WD_SECTION.NEW_PAGE)\nnew_section.header.is_linked_to_previous = False\nnew_section.header.paragraphs[0].text = \"Appendix\"\n\ndocument.save(\"sections.docx\")\n```\n\n### Read existing content\n\nUse `paragraphs` or `tables` for simple top-level reads:\n\n```python\nfrom docx import Document\n\ndocument = Document(\"existing.docx\")\n\nfor paragraph in document.paragraphs:\n    print(paragraph.text)\n```\n\nWhen content order matters, iterate the block items instead of reading paragraphs and tables separately:\n\n```python\nfrom docx import Document\n\ndocument = Document(\"existing.docx\")\n\nfor block in document.iter_inner_content():\n    print(type(block).__name__, getattr(block, \"text\", \"\"))\n```\n\n### Comments\n\n`1.2.0` adds a public comments API:\n\n```python\nfrom docx import Document\n\ndocument = Document()\nparagraph = document.add_paragraph(\"Needs review before publishing.\")\n\ndocument.add_comment(\n    runs=paragraph.runs,\n    text=\"Check the final wording.\",\n    author=\"Reviewer\",\n    initials=\"RV\",\n)\n\ndocument.save(\"comments.docx\")\n```\n\n## Configuration Notes\n\n- There is no service authentication or global package config. The main inputs are the starting document, the style names present in that document, and the paths or file-like objects you load and save.\n- Prefer a template document for anything that depends on custom styles, numbering definitions, page headers, footers, margins, or corporate branding.\n- Style lookup depends on names defined in the document. Built-in Word styles use their English names in the file format, even when the Word UI is localized.\n- For web apps or job runners, treat `.docx` output as a binary artifact. Save to a temp file or `BytesIO`, then upload or return that content.\n\n## Common Pitfalls\n\n- Import from `docx`, not `python_docx` or `python-docx`.\n- `Document()` opens only `.docx` packages. Legacy `.doc` files must be converted before use.\n- Assigning `paragraph.text` or `cell.text` replaces the existing runs in that container. If formatting matters, edit runs instead of overwriting the whole text.\n- `document.paragraphs` and `document.tables` are not a full-fidelity traversal API. They skip nested ordering, and the paragraphs list excludes content inside revision marks like `<w:ins>` or `<w:del>`.\n- `add_picture()` inserts an inline picture. If you need floating shapes or advanced drawing layout, `python-docx` does not expose that as a first-class high-level API.\n- Comment anchors must align with run boundaries, and comment ranges are supported only in the main document body, not inside headers or footers.\n- Table style names are easy to get wrong. Word may show a style like `Light Shading Accent 1`, while the style identifier used in code can be `LightShading-Accent1`.\n- If a style is missing from the starting document, applying that style name will not produce the result you expect. Start from a template that already contains the styles you need.\n\n## Version-Sensitive Notes For 1.2.0\n\n- PyPI metadata for `1.2.0` requires Python `>=3.9`.\n- The `1.2.0` release adds the comments feature, including `Document.add_comment()` and comment collection support.\n- The current Read the Docs site serves the `1.2.0` API and user guide, but some install-page details are older than the package metadata. For environment setup, trust PyPI and the maintained project files over old `easy_install`-style instructions.\n- If a project is pinned below `1.2.0`, verify feature availability before writing code copied from this guide, especially around comments and newer document traversal helpers.\n"
  },
  {
    "path": "content/python-dotenv/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-dotenv package guide for loading, parsing, and managing .env files in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-dotenv,dotenv,environment,configuration,secrets,cli\"\n---\n\n# python-dotenv Python Package Guide\n\n## Golden Rule\n\nUse `python-dotenv` to load development configuration into `os.environ`, but be explicit about when it should win over real environment variables. `load_dotenv()` does not override existing variables unless you pass `override=True`, and variable expansion only works with `${NAME}` syntax, not bare `$NAME`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"python-dotenv==1.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"python-dotenv==1.2.2\"\npoetry add \"python-dotenv==1.2.2\"\n```\n\nInstall the CLI extra only if you need the `dotenv` command:\n\n```bash\npython -m pip install \"python-dotenv[cli]==1.2.2\"\n```\n\n## Initialize And Load Configuration\n\nBasic usage:\n\n```python\nimport os\n\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ndatabase_url = os.environ[\"DATABASE_URL\"]\ndebug = os.getenv(\"DEBUG\", \"\").lower() == \"true\"\n```\n\nDefault `load_dotenv()` behavior:\n\n- It searches for `.env` in the script directory and then walks upward.\n- It loads keys into `os.environ`.\n- It does not override existing environment variables unless you pass `override=True`.\n- It returns `True` if it set at least one environment variable, otherwise `False`.\n\nUse an explicit path when the working directory or process launcher is not trustworthy:\n\n```python\nfrom pathlib import Path\n\nfrom dotenv import load_dotenv\n\nBASE_DIR = Path(__file__).resolve().parent\nload_dotenv(BASE_DIR / \".env\")\n```\n\nUse `override=True` only when the `.env` file should win over already-exported variables:\n\n```python\nfrom dotenv import load_dotenv\n\nload_dotenv(override=True)\n```\n\nDisable loading globally with an environment variable when a dependency calls `load_dotenv()` and you need to suppress it:\n\n```bash\nexport PYTHON_DOTENV_DISABLED=1\n```\n\n## Parse Without Mutating The Environment\n\nUse `dotenv_values()` when you want a parsed config dictionary instead of side effects in `os.environ`:\n\n```python\nimport os\n\nfrom dotenv import dotenv_values\n\nconfig = {\n    **dotenv_values(\".env.shared\"),\n    **dotenv_values(\".env.secret\"),\n    **os.environ,\n}\n\nprint(config[\"DATABASE_URL\"])\n```\n\nImportant behavior:\n\n- `dotenv_values()` returns `dict[str, str | None]`.\n- A line like `EMPTY_VALUE=` becomes an empty string.\n- A line with just `MISSING_VALUE` becomes `None`.\n- `dotenv_values()` prefers values from the `.env` file during interpolation; `load_dotenv(override=False)` prefers existing environment variables first.\n\n## Finding The Right `.env` File\n\nIf you need the resolved path first, call `find_dotenv()` explicitly:\n\n```python\nfrom dotenv import find_dotenv, load_dotenv\n\ndotenv_path = find_dotenv(usecwd=True)\nload_dotenv(dotenv_path)\n```\n\n`usecwd=True` is useful in shells, notebooks, debuggers, or task runners where search relative to the calling Python file is not what you want.\n\n## Loading From Streams\n\n`load_dotenv()` and `dotenv_values()` both accept text streams:\n\n```python\nfrom io import StringIO\n\nfrom dotenv import load_dotenv\n\nstream = StringIO(\"API_TOKEN=dev-token\\nFEATURE_FLAG=true\\n\")\nload_dotenv(stream=stream, override=True)\n```\n\nUse this when config comes from a secret manager, a generated string, or a test fixture instead of a file on disk.\n\n## CLI Usage\n\nThe `dotenv` CLI is part of the optional `cli` extra.\n\nCreate or update keys:\n\n```bash\ndotenv set DATABASE_URL postgresql://localhost/app\ndotenv set DEBUG true\n```\n\nInspect current values:\n\n```bash\ndotenv list\ndotenv list --format=json\ndotenv get DATABASE_URL\n```\n\nRun a command with variables loaded from `.env`:\n\n```bash\ndotenv run -- python app.py\n```\n\nIn `1.2.2`, `dotenv run` forwards flags directly to the target command, which matters if the child command uses options that look like CLI flags.\n\n## Editing `.env` Files Programmatically\n\nUse the helper functions when you need to read or rewrite `.env` files directly:\n\n```python\nfrom dotenv import get_key, set_key, unset_key\n\nenv_path = \".env\"\n\nset_key(env_path, \"DEBUG\", \"true\", quote_mode=\"auto\")\nprint(get_key(env_path, \"DEBUG\"))\nunset_key(env_path, \"DEBUG\")\n```\n\nNotes:\n\n- `set_key()` creates the file if it does not exist.\n- `quote_mode` must be one of `\"always\"`, `\"auto\"`, or `\"never\"`.\n- `export=True` writes entries as `export KEY=value`.\n- In `1.2.2`, `set_key()` and `unset_key()` do not follow symlinks by default. Pass `follow_symlinks=True` only if you intentionally want the old behavior.\n\n## `.env` File Format\n\nSupported patterns:\n\n```dotenv\n# comments are allowed\nDOMAIN=example.org\nADMIN_EMAIL=admin@${DOMAIN}\nROOT_URL=${DOMAIN}/app\nEMPTY_VALUE=\nMULTILINE=\"first line\nsecond line\"\nexport FEATURE_FLAG=true\n```\n\nRules that matter in practice:\n\n- Keys may be unquoted or single-quoted.\n- Values may be unquoted, single-quoted, or double-quoted.\n- Spaces around keys, `=`, and values are ignored.\n- Inline comments are allowed.\n- `export` is accepted but does not change parsing semantics.\n- Variable expansion requires `${NAME}` syntax.\n- Bare `$NAME` is not expanded.\n\n## IPython And Notebook Usage\n\nThe package ships an IPython extension:\n\n```ipython\n%load_ext dotenv\n%dotenv\n%dotenv -o path/to/.env\n```\n\nUseful flags:\n\n- `-o` overrides existing variables.\n- `-v` increases verbosity.\n\n## Common Pitfalls\n\n- Do not commit `.env` files with secrets. Add them to `.gitignore`.\n- Do not assume `load_dotenv()` loads from the current shell directory. By default it uses the calling file path unless the runtime looks interactive or you use `find_dotenv(usecwd=True)`.\n- Do not expect `.env` values to override already-exported CI or production variables unless you pass `override=True`.\n- Do not use bare `$VAR` references in values. Use `${VAR}`.\n- Do not import `python_dotenv`; the import package is `dotenv`.\n- Do not assume the `dotenv` CLI exists after `pip install python-dotenv`; install `python-dotenv[cli]` if your tooling depends on it.\n- Be careful with symlinked `.env` files after upgrading to `1.2.2`; `set_key()` and `unset_key()` no longer follow symlinks unless you opt in.\n\n## Version-Sensitive Notes For 1.2.2\n\n- `1.2.2` supports Python 3.10 through 3.14 and drops Python 3.9 support.\n- `dotenv run` changed in `1.2.2` to forward flags directly to the target command.\n- `set_key()` and `unset_key()` changed in `1.2.2` to avoid following symlinks by default and to preserve file mode more consistently.\n- FIFO support for reading `.env` files landed in `1.2.1`; if older docs say named pipes are unsupported, they are outdated for the `1.2.x` line.\n"
  },
  {
    "path": "content/python-jose/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-jose package guide for signing, verifying, and encrypting JOSE tokens in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-jose,jwt,jws,jwe,jwk,python,security\"\n---\n\n# python-jose Package Guide\n\n## Install\n\n`python-jose 3.5.0` requires Python 3.9 or newer.\n\nFor most applications, install the `cryptography` extra so RSA, EC, AES, and certificate handling use the `cryptography` backend:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"python-jose[cryptography]==3.5.0\"\n```\n\nIf you install `python-jose` without extras, the package uses its native backend based on `rsa`, `ecdsa`, and `pyasn1`.\n\n```bash\npython -m pip install \"python-jose==3.5.0\"\n```\n\nUse the plain install for simple HMAC or key-based flows. Use the `cryptography` extra when you need PEM keys, X.509 certificates, or broader algorithm support through the preferred backend.\n\n## Core Imports\n\nThe package exposes separate modules for each JOSE layer:\n\n```python\nfrom jose import jwe, jwk, jwt\nfrom jose.constants import ALGORITHMS\nfrom jose.exceptions import ExpiredSignatureError, JWEError, JWTClaimsError, JWTError\n```\n\nFor typical application code, start with `jwt`. Drop to `jwe` for compact encryption or `jwk` when you need to construct a key object from a JWK payload directly.\n\n## Create And Verify A JWT\n\nUse `jwt.encode(...)` to sign a claims dictionary and `jwt.decode(...)` to verify the signature and validate reserved claims.\n\n`python-jose` automatically converts `datetime` values in `exp`, `iat`, and `nbf` to NumericDate integers during encoding.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom jose import jwt\nfrom jose.constants import ALGORITHMS\nfrom jose.exceptions import ExpiredSignatureError, JWTClaimsError, JWTError\n\nsecret = os.environ[\"JWT_SECRET\"]\n\ntoken = jwt.encode(\n    {\n        \"sub\": \"user_123\",\n        \"iss\": \"https://auth.example.com\",\n        \"aud\": \"api://payments\",\n        \"iat\": datetime.now(timezone.utc),\n        \"nbf\": datetime.now(timezone.utc),\n        \"exp\": datetime.now(timezone.utc) + timedelta(minutes=15),\n    },\n    secret,\n    algorithm=ALGORITHMS.HS256,\n)\n\ntry:\n    claims = jwt.decode(\n        token,\n        secret,\n        algorithms=[ALGORITHMS.HS256],\n        audience=\"api://payments\",\n        issuer=\"https://auth.example.com\",\n    )\n    print(claims[\"sub\"])\nexcept ExpiredSignatureError:\n    print(\"token expired\")\nexcept JWTClaimsError as exc:\n    print(f\"invalid claims: {exc}\")\nexcept JWTError as exc:\n    print(f\"invalid token: {exc}\")\n```\n\nImportant points:\n\n- Always pass an explicit `algorithms=[...]` allowlist to `jwt.decode(...)`.\n- If the token contains `aud`, pass `audience=...` or decoding fails with `Invalid audience`.\n- `jwt.decode(...)` validates `exp`, `nbf`, `iat`, `iss`, `sub`, `jti`, and `at_hash` according to the options you enable.\n\n## Require Claims And Allow Clock Skew\n\nUse `options` when you need required claims or a small `leeway` for clock skew.\n\n```python\nimport os\n\nfrom jose import jwt\nfrom jose.constants import ALGORITHMS\n\ntoken = os.environ[\"JWT_TOKEN\"]\nsecret = os.environ[\"JWT_SECRET\"]\n\nclaims = jwt.decode(\n    token,\n    secret,\n    algorithms=[ALGORITHMS.HS256],\n    audience=\"api://payments\",\n    issuer=\"https://auth.example.com\",\n    options={\n        \"require_exp\": True,\n        \"require_iat\": True,\n        \"require_nbf\": True,\n        \"leeway\": 30,\n    },\n)\n```\n\n`leeway` is in seconds. You can also disable individual checks with options such as `{\"verify_aud\": False}` when that is intentional for your application.\n\n## Sign And Verify RS256 Tokens With PEM Keys\n\nWhen your issuer uses asymmetric keys, pass a PEM private key to `jwt.encode(...)` and a PEM public key to `jwt.decode(...)`.\n\n```python\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nfrom jose import jwt\nfrom jose.constants import ALGORITHMS\n\nprivate_key = os.environ[\"JWT_PRIVATE_KEY_PEM\"]\npublic_key = os.environ[\"JWT_PUBLIC_KEY_PEM\"]\n\ntoken = jwt.encode(\n    {\n        \"sub\": \"user_123\",\n        \"exp\": datetime.now(timezone.utc) + timedelta(minutes=15),\n    },\n    private_key,\n    algorithm=ALGORITHMS.RS256,\n    headers={\"kid\": \"current-signing-key\"},\n)\n\nclaims = jwt.decode(\n    token,\n    public_key,\n    algorithms=[ALGORITHMS.RS256],\n)\n```\n\nIf your verifier receives a PEM-encoded X.509 certificate instead of a public key, install `python-jose[cryptography]` and pass the certificate PEM to `jwt.decode(...)` the same way.\n\n## Verify With A JWK Or JWK Set\n\n`jwt.decode(...)` also accepts a JWK dictionary or a JWK set shaped like `{\"keys\": [...]}`.\n\n```python\nimport json\nimport os\n\nfrom jose import jwt\nfrom jose.constants import ALGORITHMS\n\ntoken = os.environ[\"JWT_TOKEN\"]\njwks = json.loads(os.environ[\"JWT_JWKS_JSON\"])\n\nclaims = jwt.decode(\n    token,\n    jwks,\n    algorithms=[ALGORITHMS.RS256],\n    audience=\"api://payments\",\n    issuer=\"https://auth.example.com\",\n)\n```\n\nIf you already have a single JWK and need a key object directly, use `jwk.construct(...)`:\n\n```python\nimport json\nimport os\n\nfrom jose import jwk\nfrom jose.constants import ALGORITHMS\n\nsigning_key = jwk.construct(\n    json.loads(os.environ[\"JWT_JWK_JSON\"]),\n    algorithm=ALGORITHMS.RS256,\n)\n```\n\n## Read Headers Or Claims Without Verifying\n\nUse the unverified helpers only for routing decisions such as selecting a candidate key by `kid`. They do not authenticate the token.\n\n```python\nimport os\n\nfrom jose import jwt\n\ntoken = os.environ[\"JWT_TOKEN\"]\n\nheader = jwt.get_unverified_header(token)\nclaims = jwt.get_unverified_claims(token)\n\nprint(header.get(\"kid\"))\nprint(claims.get(\"sub\"))\n```\n\nDo not use `get_unverified_header(...)` or `get_unverified_claims(...)` as an authorization step. Always follow them with `jwt.decode(...)`.\n\n## Encrypt And Decrypt A JWE\n\nUse `jwe.encrypt(...)` and `jwe.decrypt(...)` for JWE compact serialization.\n\n```python\nimport os\n\nfrom jose import jwe\nfrom jose.constants import ALGORITHMS\n\nkey = os.environ[\"JWE_SHARED_KEY\"]\n\nencrypted = jwe.encrypt(\n    \"sensitive payload\",\n    key,\n    algorithm=ALGORITHMS.DIR,\n    encryption=ALGORITHMS.A128GCM,\n)\n\njwe_token = encrypted.decode(\"utf-8\")\nplaintext = jwe.decrypt(jwe_token, key).decode(\"utf-8\")\n\nprint(jwe_token)\nprint(plaintext)\n```\n\nFor direct encryption with `A128GCM`, the shared key must be 16 bytes long. If you switch to another content-encryption algorithm, use a key size that matches that algorithm.\n\n## Common Pitfalls\n\n- Use `python-jose[cryptography]` when you need PEM certificate support. The native backend cannot process X.509 certificates.\n- Match the key type to the algorithm family: shared secret for `HS*`, PEM or JWK key material for `RS*` and `ES*`.\n- Pass `algorithms=[...]` when decoding instead of trusting the token header.\n- Treat `jwt.get_unverified_*` helpers as parsing utilities, not verification.\n- Expect `jwe.encrypt(...)` to return bytes. Decode to UTF-8 text if you need to store or transmit the compact serialization as a string.\n\n## Official References\n\n- Maintainer docs: `https://python-jose.readthedocs.io/en/latest/`\n- PyPI package: `https://pypi.org/project/python-jose/`\n- Source repository: `https://github.com/mpdavis/python-jose/`\n"
  },
  {
    "path": "content/python-json-logger/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-json-logger Python package guide for structured JSON logging with the standard logging module\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-json-logger,logging,json,structured-logging,python,orjson,msgspec\"\n---\n\n# python-json-logger Python Package Guide\n\n## Golden Rule\n\nUse `python-json-logger` as a formatter for Python's built-in `logging` package. It formats `LogRecord` objects as JSON, but it does not send logs anywhere by itself, does not create a client object, and does not use authentication or package-specific environment variables.\n\nFor new code on `4.0.0`, import the standard formatter from `pythonjsonlogger.json`. The older `pythonjsonlogger.jsonlogger` module still exists for compatibility, but it emits a `DeprecationWarning`.\n\n## Install\n\n`python-json-logger` requires Python `3.8+`.\n\nInstall the package version you want to document or pin in your app:\n\n```bash\npython -m pip install \"python-json-logger==4.0.0\"\n```\n\nIf you want one of the optional faster encoders, install it separately:\n\n```bash\npython -m pip install orjson\npython -m pip install msgspec\n```\n\nQuick verification:\n\n```bash\npython - <<'PY'\nfrom importlib.metadata import version\nfrom pythonjsonlogger.json import JsonFormatter\n\nprint(version(\"python-json-logger\"))\nprint(JsonFormatter)\nPY\n```\n\n## Environment And Initialization\n\n`python-json-logger` does not read environment variables.\n\nThe normal setup pattern is:\n\n1. create a `logging.Handler`\n2. attach a `JsonFormatter`\n3. add the handler to a logger\n\nMinimal stream logger:\n\n```python\nimport logging\n\nfrom pythonjsonlogger.json import JsonFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(\n    JsonFormatter(\n        fmt=[\"levelname\", \"name\", \"message\"],\n        rename_fields={\"levelname\": \"level\"},\n        timestamp=\"timestamp\",\n    )\n)\n\nlogger = logging.getLogger(\"app\")\nlogger.setLevel(logging.INFO)\nlogger.propagate = False\nlogger.addHandler(handler)\n\nlogger.info(\"worker started\", extra={\"request_id\": \"req_123\"})\n```\n\nExample output:\n\n```json\n{\"level\": \"INFO\", \"name\": \"app\", \"message\": \"worker started\", \"request_id\": \"req_123\", \"timestamp\": \"2026-03-12T00:00:00+00:00\"}\n```\n\n`timestamp=True` adds a UTC timestamp field named `timestamp`. Pass a string such as `timestamp=\"time\"` if you want a different field name.\n\n## Common Workflows\n\n### Add structured fields with `extra=`\n\nUse standard `logging` calls and pass structured fields through `extra`.\n\n```python\nimport logging\n\nfrom pythonjsonlogger.json import JsonFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(JsonFormatter())\n\nlogger = logging.getLogger(\"billing\")\nlogger.setLevel(logging.INFO)\nlogger.propagate = False\nlogger.addHandler(handler)\n\nlogger.info(\n    \"order created\",\n    extra={\n        \"order_id\": \"ord_123\",\n        \"customer_id\": \"cus_456\",\n        \"amount_cents\": 1250,\n    },\n)\n```\n\nThe keys in `extra` are merged into the top-level JSON object unless they are filtered out by `reserved_attrs`.\n\n### Log a dictionary directly\n\nIf `record.msg` is a dictionary, `python-json-logger` emits that dictionary at the root of the JSON record instead of storing it as a nested message payload.\n\n```python\nimport logging\n\nfrom pythonjsonlogger.json import JsonFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(JsonFormatter(timestamp=True))\n\nlogger = logging.getLogger(\"events\")\nlogger.setLevel(logging.INFO)\nlogger.propagate = False\nlogger.addHandler(handler)\n\nlogger.info(\n    {\n        \"event\": \"checkout.completed\",\n        \"order_id\": \"ord_123\",\n        \"amount_cents\": 1250,\n    }\n)\n```\n\nThis is useful when your application already builds event dictionaries.\n\n### Configure `logging.config.dictConfig`\n\nFor application startup, `dictConfig` is usually the cleanest way to register the formatter.\n\n```python\nimport logging\nimport logging.config\n\nLOGGING = {\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n    \"formatters\": {\n        \"json\": {\n            \"()\": \"pythonjsonlogger.json.JsonFormatter\",\n            \"fmt\": [\"levelname\", \"name\", \"message\"],\n            \"rename_fields\": {\"levelname\": \"level\"},\n            \"timestamp\": \"timestamp\",\n            \"static_fields\": {\"service\": \"billing-api\"},\n        }\n    },\n    \"handlers\": {\n        \"console\": {\n            \"class\": \"logging.StreamHandler\",\n            \"formatter\": \"json\",\n        }\n    },\n    \"root\": {\n        \"level\": \"INFO\",\n        \"handlers\": [\"console\"],\n    },\n}\n\nlogging.config.dictConfig(LOGGING)\n\nlogger = logging.getLogger(__name__)\nlogger.info(\"configured\", extra={\"port\": 8000})\n```\n\nIn `4.0.0`, `fmt` can be a sequence of field names as shown above, or a comma-separated string when you set `style=\",\"`.\n\n### Emit exceptions as arrays of lines\n\nBy default, `exc_info` and `stack_info` are serialized as strings. If your log pipeline prefers arrays, enable the formatter options explicitly.\n\n```python\nimport logging\n\nfrom pythonjsonlogger.json import JsonFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(\n    JsonFormatter(\n        fmt=[\"levelname\", \"name\", \"message\", \"exc_info\"],\n        rename_fields={\"levelname\": \"level\"},\n        exc_info_as_array=True,\n    )\n)\n\nlogger = logging.getLogger(\"jobs\")\nlogger.setLevel(logging.INFO)\nlogger.propagate = False\nlogger.addHandler(handler)\n\ntry:\n    1 / 0\nexcept ZeroDivisionError:\n    logger.exception(\"job failed\", extra={\"job_id\": \"job_123\"})\n```\n\nUse `stack_info_as_array=True` for stack traces produced from `stack_info` as well.\n\n## Choosing A Formatter Backend\n\n### Standard library `json`\n\nUse `pythonjsonlogger.json.JsonFormatter` when you want the fewest extra dependencies.\n\n```python\nfrom pythonjsonlogger.json import JsonFormatter\n\nformatter = JsonFormatter(timestamp=True)\n```\n\nIf you do not pass `json_default` or `json_encoder`, `JsonFormatter` uses the package's built-in `JsonEncoder`.\n\n### `orjson`\n\nUse `pythonjsonlogger.orjson.OrjsonFormatter` only after installing `orjson`.\n\n```python\nimport logging\n\nfrom pythonjsonlogger.orjson import OrjsonFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(\n    OrjsonFormatter(\n        fmt=[\"levelname\", \"name\", \"message\"],\n        rename_fields={\"levelname\": \"level\"},\n        timestamp=True,\n        json_indent=True,\n    )\n)\n```\n\n`json_indent=True` enables two-space pretty printing for the `orjson` backend.\n\n### `msgspec`\n\nUse `pythonjsonlogger.msgspec.MsgspecFormatter` only after installing `msgspec`.\n\n```python\nimport logging\n\nfrom pythonjsonlogger.msgspec import MsgspecFormatter\n\nhandler = logging.StreamHandler()\nhandler.setFormatter(\n    MsgspecFormatter(\n        fmt=[\"levelname\", \"name\", \"message\"],\n        rename_fields={\"levelname\": \"level\"},\n        timestamp=True,\n    )\n)\n```\n\nIf the matching backend package is missing, importing `pythonjsonlogger.orjson` or `pythonjsonlogger.msgspec` raises `MissingPackageError`.\n\n## Custom Serialization\n\nThe standard `JsonFormatter` already handles common non-JSON-native values including `datetime`, `date`, `time`, exceptions, tracebacks, enums, bytes, dataclasses, and Python types.\n\nFor your own application types, provide `json_default` or `json_encoder`.\n\n```python\nfrom decimal import Decimal\n\nfrom pythonjsonlogger.json import JsonFormatter\n\n\ndef encode_value(obj):\n    if isinstance(obj, Decimal):\n        return str(obj)\n    raise TypeError(f\"Object of type {type(obj).__name__} is not JSON serializable\")\n\n\nformatter = JsonFormatter(json_default=encode_value)\n```\n\nUse `json_encoder` when you want to subclass `json.JSONEncoder`; use `json_default` when a simple callback is enough.\n\n## Common Pitfalls\n\n### Install name and import name are different\n\nInstall `python-json-logger`, but import `pythonjsonlogger`.\n\n### `pythonjsonlogger.jsonlogger` is legacy\n\n`4.0.0` keeps `pythonjsonlogger.jsonlogger` as a compatibility stub. Prefer `pythonjsonlogger.json` in new code to avoid deprecation warnings.\n\n### Formatter fields can collide\n\n`fmt`, `defaults`, `static_fields`, dictionary messages, and `extra` all contribute keys to the same top-level JSON object. Reuse field names intentionally so you do not overwrite values by accident.\n\n### `timestamp` is separate from `asctime`\n\n`timestamp=True` or `timestamp=\"field_name\"` adds a UTC datetime derived from `record.created`. If you also want the logging formatter's `asctime` field, include `asctime` in `fmt` explicitly.\n\n### Optional encoder backends are not bundled automatically\n\n`python-json-logger` does not install `orjson` or `msgspec` for you. Install the backend package before importing the matching formatter module.\n\n## Version Notes For `4.0.0`\n\n- `fmt` now accepts a sequence such as `fmt=[\"levelname\", \"name\", \"message\"]`.\n- `fmt` also supports comma-separated field names with `style=\",\"`.\n- The compatibility module `pythonjsonlogger.jsonlogger` remains available, but new code should use `pythonjsonlogger.json`.\n"
  },
  {
    "path": "content/python-multipart/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Streaming parser for multipart form data, URL-encoded forms, and raw file uploads in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.0.22\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-multipart,multipart,form-data,uploads,python\"\n---\n\n# python-multipart Python Guide\n\n## Golden Rule\n\nUse `python_multipart` in new code and let the package parse the request body for you.\n\nThe public entry points to reach for are:\n\n- `parse_form(...)` when you already have a file-like request body stream\n- `create_form_parser(...)` when the body arrives incrementally in chunks\n- `FormParser(...)` only if you need direct control over parser construction\n\nThe package also exposes a compatibility `multipart` import, but that shim emits a `PendingDeprecationWarning` telling you to use `python_multipart` instead.\n\n## Installation\n\n`python-multipart` requires Python `>=3.10`.\n\n```bash\npip install python-multipart==0.0.22\n```\n\nEnvironment variables: none.\n\nAuthentication or client initialization: none. This package is a low-level parser, not an HTTP client.\n\n## Parse `multipart/form-data`\n\n`parse_form()` is the fastest path if you already have the full request body as a stream. It reads chunks from the stream, dispatches parsed fields and files to callbacks, and finalizes the parser when the stream ends.\n\n```python\nfrom io import BytesIO\n\nfrom python_multipart import parse_form\n\n\ndef text(value: bytes | None) -> str | None:\n    return value.decode(\"utf-8\") if value is not None else None\n\n\nbody = (\n    b\"--boundary123\\r\\n\"\n    b\"Content-Disposition: form-data; name=\\\"title\\\"\\r\\n\\r\\n\"\n    b\"hello\\r\\n\"\n    b\"--boundary123\\r\\n\"\n    b\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"hello.txt\\\"\\r\\n\"\n    b\"Content-Type: text/plain\\r\\n\\r\\n\"\n    b\"abc123\\r\\n\"\n    b\"--boundary123--\\r\\n\"\n)\n\nheaders = {\n    \"Content-Type\": b\"multipart/form-data; boundary=boundary123\",\n    \"Content-Length\": str(len(body)).encode(\"ascii\"),\n}\n\nfields: dict[str, str | None] = {}\nfiles: list[dict[str, object]] = []\n\n\ndef on_field(field) -> None:\n    fields[text(field.field_name) or \"\"] = text(field.value)\n\n\ndef on_file(file) -> None:\n    file.file_object.seek(0)\n    files.append(\n        {\n            \"field_name\": text(file.field_name),\n            \"file_name\": text(file.file_name),\n            \"size\": file.size,\n            \"in_memory\": file.in_memory,\n            \"content\": file.file_object.read(),\n        }\n    )\n\n\nparse_form(headers, BytesIO(body), on_field, on_file)\n\nprint(fields[\"title\"])\nprint(files[0][\"file_name\"])\nprint(files[0][\"content\"])\n```\n\nUse this shape when your framework exposes a readable body stream. `Content-Type` is required. `Content-Length` is optional, but when present `parse_form()` uses it to cap reads from the input stream. The default `chunk_size` is `1 MiB`.\n\n## Parse Incrementally From Chunks\n\nIf the request body arrives in pieces, create the parser first and feed it with `write()` until the request is complete.\n\n```python\nfrom python_multipart import create_form_parser\n\n\ndef on_field(field) -> None:\n    print(field.field_name, field.value)\n\n\ndef on_file(file) -> None:\n    print(file.field_name, file.file_name, file.size)\n\n\nheaders = {\n    \"Content-Type\": b\"multipart/form-data; boundary=boundary123\",\n}\n\nparser = create_form_parser(\n    headers=headers,\n    on_field=on_field,\n    on_file=on_file,\n    config={\n        \"MAX_BODY_SIZE\": 20 * 1024 * 1024,\n    },\n)\n\nfor chunk in request_body_chunks:\n    parser.write(chunk)\n\nparser.finalize()\nparser.close()\n```\n\nFor `multipart/form-data`, the boundary must be present in the `Content-Type` header. If it is missing, `FormParser` raises `FormParserError`.\n\n## Parse Raw `application/octet-stream`\n\n`FormParser` also supports a raw file body with `application/octet-stream`. In that mode, there are no form fields, so the file callback receives a `File` object with `field_name=None`.\n\nIf you want the uploaded file to carry a name, pass it in `X-File-Name`.\n\n```python\nfrom io import BytesIO\n\nfrom python_multipart import parse_form\n\n\nbody = b\"raw-bytes\"\nheaders = {\n    \"Content-Type\": b\"application/octet-stream\",\n    \"Content-Length\": str(len(body)).encode(\"ascii\"),\n    \"X-File-Name\": b\"upload.bin\",\n}\n\n\ndef on_file(file) -> None:\n    file.file_object.seek(0)\n    print(file.field_name)\n    print(file.file_name)\n    print(file.file_object.read())\n\n\nparse_form(headers, BytesIO(body), on_field=None, on_file=on_file)\n```\n\n## Control Memory And Temp Files\n\nUploaded files stay in memory until they cross `MAX_MEMORY_FILE_SIZE`, then the `File` object flushes them to a temporary file on disk.\n\nUseful parser and file config keys:\n\n- `MAX_BODY_SIZE`: maximum total request body size accepted by the parser\n- `MAX_MEMORY_FILE_SIZE`: threshold before a file is moved from memory to disk\n- `UPLOAD_DIR`: directory for temporary files\n- `UPLOAD_DELETE_TMP`: whether auto-created temp files are deleted automatically\n- `UPLOAD_KEEP_FILENAME`: keep the uploaded filename instead of generating a temp name\n- `UPLOAD_KEEP_EXTENSIONS`: preserve the original file extension\n- `UPLOAD_ERROR_ON_BAD_CTE`: raise on unknown `Content-Transfer-Encoding`\n\n```python\nfrom python_multipart import create_form_parser\n\n\ndef on_file(file) -> None:\n    print(file.in_memory)\n    print(file.actual_file_name)\n    print(file.size)\n\n\nparser = create_form_parser(\n    headers={\"Content-Type\": b\"multipart/form-data; boundary=boundary123\"},\n    on_field=None,\n    on_file=on_file,\n    config={\n        \"MAX_BODY_SIZE\": 25 * 1024 * 1024,\n        \"MAX_MEMORY_FILE_SIZE\": 256 * 1024,\n        \"UPLOAD_DIR\": \"/tmp/python-multipart\",\n        \"UPLOAD_KEEP_EXTENSIONS\": True,\n        \"UPLOAD_DELETE_TMP\": True,\n    },\n)\n```\n\nFor parsed files:\n\n- `file.file_name` is the filename from the request\n- `file.actual_file_name` is the on-disk name, or `None` if the file never left memory\n- `file.file_object` is the current backing object, either `io.BytesIO` or a real file object\n- `file.in_memory` tells you which storage mode is active\n- `file.size` tracks bytes written\n\n## URL-Encoded Forms\n\n`FormParser` also handles `application/x-www-form-urlencoded` and `application/x-url-encoded`.\n\n```python\nfrom python_multipart import create_form_parser\n\n\ndef on_field(field) -> None:\n    print(field.field_name, field.value)\n\n\nparser = create_form_parser(\n    headers={\"Content-Type\": b\"application/x-www-form-urlencoded\"},\n    on_field=on_field,\n    on_file=None,\n)\n\nparser.write(b\"name=alice&empty=&flag\")\nparser.finalize()\n```\n\nFields are surfaced as `Field` objects. `field.field_name` and `field.value` are bytes. A key with no value can produce `field.value is None`.\n\n## Important Pitfalls\n\n- Import `python_multipart`, not `multipart`, in new code.\n- Pass `Content-Type` in the headers dictionary. `create_form_parser()` raises `ValueError` if it is missing.\n- For `multipart/form-data`, include `boundary=...` in `Content-Type`.\n- `field.field_name`, `field.value`, and `file.file_name` are bytes; decode them before mixing them with string-based application code.\n- Call `parser.finalize()` after the last chunk when you use `create_form_parser()` or `FormParser()` directly.\n- `File.close()` closes the backing file object. Copy or persist the data you need before closing it.\n- `Content-Transfer-Encoding` handling recognizes `binary`, `8bit`, `7bit`, `base64`, and `quoted-printable`. Unknown encodings fall back to raw handling unless `UPLOAD_ERROR_ON_BAD_CTE` is set.\n\n## Source URLs\n\n- https://github.com/Kludex/python-multipart\n- https://kludex.github.io/python-multipart/\n- https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md\n- https://pypi.org/project/python-multipart/\n"
  },
  {
    "path": "content/python-pptx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-pptx package guide for creating and editing PowerPoint .pptx files in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-pptx,powerpoint,pptx,presentation,office,document-generation\"\n---\n\n# python-pptx Python Package Guide\n\n## Golden Rule\n\nUse `python-pptx` with `from pptx import Presentation` to create or edit `.pptx` files, and start from a real template deck whenever layout, theme, or slide size matters. The Read the Docs site still shows `1.0.0` in its page chrome, so check PyPI and the changelog for `1.0.2`-level compatibility notes before assuming the docs site reflects the newest patch release.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"python-pptx==1.0.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"python-pptx==1.0.2\"\npoetry add \"python-pptx==1.0.2\"\n```\n\n`python-pptx` is a local file-format library. It does not call a remote API and does not require Microsoft PowerPoint to be installed.\n\n## Initialize And Save Presentations\n\nCreate a new deck from the built-in default template:\n\n```python\nfrom pptx import Presentation\n\nprs = Presentation()\nprint(len(prs.slide_layouts))\n```\n\nOpen an existing deck or template:\n\n```python\nfrom pptx import Presentation\n\nprs = Presentation(\"template.pptx\")\n```\n\nYou can also read from or save to a file-like object:\n\n```python\nfrom io import BytesIO\nfrom pptx import Presentation\n\nbuffer = BytesIO()\nprs = Presentation()\nprs.save(buffer)\nbuffer.seek(0)\n\nsame_prs = Presentation(buffer)\n```\n\n## Core Usage\n\n### Add a slide and fill placeholders\n\nUse a layout from the template, then populate its placeholders:\n\n```python\nfrom pptx import Presentation\n\nprs = Presentation(\"template.pptx\")\nslide = prs.slides.add_slide(prs.slide_layouts[1])  # often \"Title and Content\"\n\nslide.shapes.title.text = \"Quarterly Review\"\n\ntext_frame = slide.placeholders[1].text_frame\ntext_frame.text = \"Highlights\"\n\nfor bullet in [\"Revenue up 12%\", \"Churn down 2%\", \"Opened EU region\"]:\n    paragraph = text_frame.add_paragraph()\n    paragraph.text = bullet\n    paragraph.level = 1\n\nprs.save(\"quarterly-review.pptx\")\n```\n\n### Add an image with explicit sizing\n\nUse helper units instead of raw integers:\n\n```python\nfrom pptx import Presentation\nfrom pptx.util import Inches\n\nprs = Presentation(\"template.pptx\")\nslide = prs.slides.add_slide(prs.slide_layouts[6])  # often blank\n\nslide.shapes.add_picture(\n    \"chart.png\",\n    Inches(1.0),\n    Inches(1.0),\n    width=Inches(8.0),\n)\n\nprs.save(\"with-image.pptx\")\n```\n\n### Add a chart\n\n`add_chart()` returns a `GraphicFrame`; get the chart from `.chart`:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches\n\nprs = Presentation()\nslide = prs.slides.add_slide(prs.slide_layouts[5])\n\nchart_data = CategoryChartData()\nchart_data.categories = [\"Q1\", \"Q2\", \"Q3\"]\nchart_data.add_series(\"Sales\", (19.2, 21.4, 24.7))\n\ngraphic_frame = slide.shapes.add_chart(\n    XL_CHART_TYPE.COLUMN_CLUSTERED,\n    Inches(1.0),\n    Inches(1.5),\n    Inches(8.0),\n    Inches(4.5),\n    chart_data,\n)\n\nchart = graphic_frame.chart\nchart.has_legend = False\n\nprs.save(\"with-chart.pptx\")\n```\n\n### Add a table\n\n`add_table()` also returns a `GraphicFrame`; use `.table` to reach cells:\n\n```python\nfrom pptx import Presentation\nfrom pptx.util import Inches\n\nprs = Presentation()\nslide = prs.slides.add_slide(prs.slide_layouts[5])\n\ngraphic_frame = slide.shapes.add_table(\n    rows=3,\n    cols=2,\n    left=Inches(1.0),\n    top=Inches(1.5),\n    width=Inches(6.0),\n    height=Inches(1.5),\n)\n\ntable = graphic_frame.table\ntable.cell(0, 0).text = \"Region\"\ntable.cell(0, 1).text = \"Revenue\"\ntable.cell(1, 0).text = \"NA\"\ntable.cell(1, 1).text = \"$1.2M\"\ntable.cell(2, 0).text = \"EU\"\ntable.cell(2, 1).text = \"$0.9M\"\n\nprs.save(\"with-table.pptx\")\n```\n\n### Read an existing deck\n\n```python\nfrom pptx import Presentation\n\nprs = Presentation(\"existing-deck.pptx\")\n\nfor slide in prs.slides:\n    for shape in slide.shapes:\n        if hasattr(shape, \"text\"):\n            print(shape.text)\n```\n\n## Configuration And Auth\n\n- Auth: none. `python-pptx` manipulates local `.pptx` files and does not need API keys, OAuth, or cloud credentials.\n- Template choice is the main configuration surface. Use `Presentation(\"template.pptx\")` when you need your organization's theme, widescreen layout, custom masters, or predefined placeholders.\n- Use `pptx.util` helpers like `Inches`, `Cm`, and `Pt` for positions and font sizes instead of raw EMU values.\n- Prefer file-like objects when integrating with web uploads, object storage downloads, or in-memory attachments.\n\n## Common Pitfalls\n\n- `Presentation()` with no argument uses the package's default template, not your project's branded deck.\n- Placeholder access is keyed by placeholder `idx`, not by visual order. A placeholder index that works in one layout can be missing in another.\n- `slide.shapes.add_chart()` and `slide.shapes.add_table()` return `GraphicFrame` objects. Access `.chart` or `.table` before trying to edit content.\n- Slide layout indexes are template-specific. `slide_layouts[1]` is often \"Title and Content\", but do not hard-code that assumption across arbitrary templates without checking.\n- Coordinates and sizes are stored internally in EMUs. Use `Inches`, `Cm`, or `Pt` helpers or your layout math will be unreadable and easy to break.\n- When editing an existing deck, open that `.pptx` first and save back out from it. Rebuilding from a blank presentation will not preserve the original theme, master slides, or placeholder structure.\n\n## Version-Sensitive Notes For 1.0.2\n\n- PyPI lists `python-pptx 1.0.2` with a release date of `2024-08-07`; the version used here matched the live registry.\n- The Read the Docs `latest` site still displays `python-pptx 1.0.0 documentation`, so treat it as the main usage guide but verify patch-level compatibility against PyPI and the changelog.\n- `1.0.1` dropped Python 3.7 support, added Python 3.12 support, and fixed several chart and image-handling issues.\n- `1.0.2` adds Python 3.13 support and includes bug fixes around hyperlinks, line spacing, font handling, and chart date-axis behavior.\n\n## Official Sources\n\n- Docs root: `https://python-pptx.readthedocs.io/en/latest/`\n- Quickstart: `https://python-pptx.readthedocs.io/en/latest/user/quickstart.html`\n- Working with presentations: `https://python-pptx.readthedocs.io/en/latest/user/presentations.html`\n- Working with placeholders: `https://python-pptx.readthedocs.io/en/latest/user/placeholders-using.html`\n- PyPI package page: `https://pypi.org/project/python-pptx/`\n- Repository README: `https://raw.githubusercontent.com/scanny/python-pptx/master/README.rst`\n- Changelog: `https://raw.githubusercontent.com/scanny/python-pptx/master/HISTORY.rst`\n"
  },
  {
    "path": "content/python-slugify/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"python-slugify for turning Unicode text into predictable slugs in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.0.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python-slugify,slugify,unicode,transliteration,urls,text-processing\"\n---\n\n# python-slugify Python Package Guide\n\n## What It Does\n\n`python-slugify` converts arbitrary text into slug strings you can use in URLs, filenames, and human-readable identifiers.\n\nThe default behavior lowercases the text, transliterates Unicode characters to ASCII, removes disallowed characters, and joins words with `-`.\n\nThis guide covers `8.0.4`.\n\n## Install\n\nPin the version your application expects:\n\n```bash\npython -m pip install \"python-slugify==8.0.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"python-slugify==8.0.4\"\npoetry add \"python-slugify==8.0.4\"\n```\n\nThe project documents `text-unidecode` as the default transliteration dependency. If you want the alternative `Unidecode` backend documented by the maintainer, install the extra:\n\n```bash\npython -m pip install \"python-slugify[unidecode]==8.0.4\"\n```\n\n## Initialize\n\nThere is no client object, auth flow, service endpoint, or environment-variable setup.\n\nImport the top-level helper:\n\n```python\nfrom slugify import slugify\n```\n\n## Common Workflows\n\n### Generate a basic slug\n\n```python\nfrom slugify import slugify\n\ntitle = \"This is a test ---\"\nslug = slugify(title)\n\nprint(slug)\n```\n\nUse this default path when you want lowercase ASCII output with hyphens.\n\n### Keep Unicode characters in the result\n\nBy default, non-ASCII text is transliterated. Pass `allow_unicode=True` if you want the slug to keep Unicode characters:\n\n```python\nfrom slugify import slugify\n\nascii_slug = slugify(\"影師嗎\")\nunicode_slug = slugify(\"影師嗎\", allow_unicode=True)\n```\n\nThis matters for routes and persisted slugs. Decide early whether your application wants ASCII-only slugs or Unicode-preserving slugs, then keep that choice consistent.\n\n### Change the separator\n\nUse `separator` when your application wants underscores or another delimiter:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\"C'est déjà l'été.\", separator=\"_\")\n```\n\n### Apply custom replacements before slug generation\n\n`replacements` lets you map symbols or substrings before normalization:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\n    \"10 | 20 %\",\n    replacements=[[\"|\", \"or\"], [\"%\", \"percent\"]],\n)\n```\n\nUse replacements for domain-specific tokens such as `%`, `&`, or abbreviations that should expand predictably.\n\n### Remove stopwords\n\nUse `stopwords` to drop filler words from the output:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\n    \"the quick brown fox jumps over the lazy dog\",\n    stopwords=[\"the\"],\n)\n```\n\n### Limit slug length without cutting words arbitrarily\n\n`max_length` truncates the slug. Add `word_boundary=True` if you want truncation to respect word boundaries:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\n    \"the quick brown fox jumps over the lazy dog\",\n    max_length=24,\n    word_boundary=True,\n)\n```\n\nIf you also pass `save_order=True`, the package keeps earlier words in their original order while fitting the slug into the requested length:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\n    \"the quick brown fox jumps over the lazy dog\",\n    max_length=24,\n    word_boundary=True,\n    save_order=True,\n)\n```\n\n### Control case and allowed characters\n\nUse `lowercase=False` to preserve case, or `regex_pattern` to override what characters survive normalization:\n\n```python\nfrom slugify import slugify\n\nslug = slugify(\"Build API v2\", lowercase=False)\n\ncustom = slugify(\n    \"api_v2 release\",\n    regex_pattern=r\"[^-a-zA-Z0-9_]+\",\n    lowercase=False,\n)\n```\n\nReach for `regex_pattern` only when your allowed-character set is truly different from the default. It changes the cleanup rules for the whole slug.\n\n### Handle HTML entities and numeric references\n\nThe function exposes flags for entity and numeric reference decoding. The default path is usually what you want for user-visible titles that may already contain HTML entity text:\n\n```python\nfrom slugify import slugify\n\ndecoded = slugify(\"Jack &amp; Jill\")\nliteral = slugify(\"Jack &amp; Jill\", entities=False)\n```\n\nRelated flags are:\n\n- `entities`\n- `decimal`\n- `hexadecimal`\n\nDisable them only if you need to preserve the literal input before slug cleanup.\n\n## Configuration And Auth\n\nThere is no global configuration file, environment-variable contract, or authentication layer.\n\nIn practice, your configuration surface is the `slugify()` call itself:\n\n- `allow_unicode` controls ASCII transliteration vs Unicode-preserving output\n- `separator` controls the delimiter in the final slug\n- `max_length`, `word_boundary`, and `save_order` control truncation behavior\n- `stopwords`, `replacements`, and `regex_pattern` tailor normalization for your domain\n- `lowercase` controls case folding\n\nIf slug stability matters, keep these options centralized in one helper function instead of scattering different combinations across the codebase.\n\n## Common Pitfalls\n\n- `python-slugify` does not guarantee uniqueness. If slugs back database rows or routes, add your own uniqueness check or suffixing strategy.\n- Changing `allow_unicode`, `separator`, `lowercase`, or the transliteration backend after you have persisted slugs can break links and cache keys.\n- `max_length` alone can cut a slug in the middle of a word; pair it with `word_boundary=True` when human readability matters.\n- `regex_pattern` is powerful but easy to misuse. A permissive pattern can keep characters your routes, storage layer, or downstream systems do not expect.\n- Different transliteration backends can produce different ASCII output for the same input text. Pin the backend choice if slug values are part of your public interface.\n- Slugification is not semantic normalization. Do not use slugs as the only canonical copy of important text.\n\n## Version-Sensitive Notes\n\n- This guide targets `python-slugify==8.0.4`.\n- The maintainer docs for this package are the repository README and PyPI project page rather than a separate API reference site.\n- The project documents both the default `text-unidecode` path and an optional `unidecode` extra, which can affect transliteration results.\n\n## Official Links\n\n- Repository: `https://github.com/un33k/python-slugify`\n- PyPI: `https://pypi.org/project/python-slugify/`\n"
  },
  {
    "path": "content/pytz/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"pytz guide for Python projects: installation, timezone conversion, DST-safe localization, and maintenance-mode migration notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.1.post1\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,pytz,datetime,timezone,dst,iana,zoneinfo\"\n---\n\n# pytz Python Package Guide\n\n## Golden Rule\n\nUse `pytz` when you need compatibility with code that already depends on `pytz` timezone objects. For new Python 3.9+ code, the maintainer explicitly recommends the standard-library `zoneinfo` stack instead; `pytz` mainly remains useful for backwards compatibility.\n\nThe two `pytz` rules that matter most are:\n\n1. Localize naive datetimes with `tz.localize(...)`.\n2. Normalize localized datetimes after arithmetic that may cross a DST boundary.\n\n## Install\n\n```bash\npip install pytz\n```\n\nPin the package when you need reproducible timezone data:\n\n```bash\npip install \"pytz==2026.1.post1\"\n```\n\n## Initialization\n\nThere is no service configuration, API key, or account setup. Initialization is just choosing the timezone object you want to work with.\n\n```python\nimport pytz\n\nutc = pytz.UTC\neastern = pytz.timezone(\"America/New_York\")\ntokyo = pytz.timezone(\"Asia/Tokyo\")\n```\n\nFor UTC-only workflows, `pytz.UTC` is the safest default timezone object.\n\n## Core Usage\n\n### Localize a naive datetime\n\n```python\nfrom datetime import datetime\nimport pytz\n\neastern = pytz.timezone(\"America/New_York\")\nnaive = datetime(2026, 1, 15, 9, 30)\nlocal_dt = eastern.localize(naive)\n\nprint(local_dt.isoformat())\n```\n\nDo not build most localized datetimes with `datetime(..., tzinfo=tz)`. Upstream documents that this produces incorrect historical or DST-sensitive offsets for many zones.\n\n### Convert between timezones\n\n```python\nfrom datetime import datetime\nimport pytz\n\nutc_dt = datetime(2026, 1, 15, 14, 0, tzinfo=pytz.UTC)\ntokyo = pytz.timezone(\"Asia/Tokyo\")\ntokyo_dt = utc_dt.astimezone(tokyo)\n\nprint(tokyo_dt.isoformat())\n```\n\nUse `.astimezone(...)` for aware datetimes. `localize(...)` is only for naive datetimes.\n\n### Normalize after arithmetic across DST boundaries\n\n```python\nfrom datetime import datetime, timedelta\nimport pytz\n\neastern = pytz.timezone(\"America/New_York\")\nstart = eastern.localize(datetime(2026, 11, 1, 0, 30))\nlater = start + timedelta(hours=3)\nfixed = eastern.normalize(later)\n\nprint(start.isoformat())\nprint(later.isoformat())  # may keep the old offset\nprint(fixed.isoformat())  # corrected for the DST transition\n```\n\nThis is the other major `pytz` gotcha. Arithmetic happens on the `datetime`, so crossing a timezone transition can leave the offset stale until you call `normalize(...)`.\n\n### Prefer UTC for storage and internal logic\n\n```python\nfrom datetime import datetime\nimport pytz\n\ncreated_at = datetime.now(tz=pytz.UTC)\ndisplay_tz = pytz.timezone(\"Europe/Amsterdam\")\n\nprint(created_at.astimezone(display_tz).isoformat())\n```\n\nThe upstream docs recommend keeping internal timestamps in UTC and converting to local time only at input and display boundaries.\n\n## DST and Ambiguous Times\n\n### Refuse to guess during ambiguous local times\n\n```python\nfrom datetime import datetime\nimport pytz\n\neastern = pytz.timezone(\"America/New_York\")\nnaive = datetime(2026, 11, 1, 1, 30)\n\ntry:\n    dt = eastern.localize(naive, is_dst=None)\nexcept pytz.AmbiguousTimeError:\n    # Choose a policy for your app instead of guessing silently.\n    dt = eastern.localize(naive, is_dst=False)\n```\n\n`is_dst=None` is the safest choice when you want `pytz` to raise instead of silently choosing one of the two possible local times.\n\n### Handle nonexistent local times during spring-forward\n\n```python\nfrom datetime import datetime\nimport pytz\n\npacific = pytz.timezone(\"America/Los_Angeles\")\n\ntry:\n    dt = pacific.localize(datetime(2026, 3, 8, 2, 30), is_dst=None)\nexcept pytz.NonExistentTimeError:\n    # This wall-clock time was skipped by the DST transition.\n    dt = pacific.localize(datetime(2026, 3, 8, 3, 0), is_dst=True)\n```\n\nIf your application accepts local wall-clock input, plan an explicit policy for ambiguous and nonexistent times instead of relying on the library default.\n\n## Common Setup Patterns\n\n### Validate a timezone name from user input\n\n```python\nimport pytz\n\ndef get_timezone(name: str):\n    if name not in pytz.common_timezones_set:\n        raise ValueError(f\"Unsupported timezone: {name}\")\n    return pytz.timezone(name)\n```\n\nUseful built-ins:\n\n- `pytz.timezone(name)` returns a tzinfo object for an IANA timezone name.\n- `pytz.UTC` and `pytz.utc` are the canonical UTC timezone objects.\n- `pytz.common_timezones` and `pytz.common_timezones_set` are better user-facing choices than the full exhaustive timezone list.\n\n## Config and Auth\n\n- No authentication is required.\n- No network setup is required at runtime.\n- The package ships timezone data and Python helpers; configuration is mainly about dependency pinning and choosing a consistent timezone policy.\n- If you integrate with frameworks or older libraries, confirm whether they still expect `pytz` objects or now use `zoneinfo`. Mixing both models in one code path is a common source of subtle bugs.\n\n## Common Pitfalls\n\n- Do not create local times with `datetime(..., tzinfo=pytz.timezone(\"America/New_York\"))`.\n- Do not call `localize(...)` on a datetime that already has `tzinfo`.\n- Do not skip `normalize(...)` after arithmetic across DST or other timezone transitions.\n- Do not assume abbreviations like `EST` or `CST` are unique; use IANA names such as `America/New_York`.\n- Do not silently guess through ambiguous or nonexistent wall-clock times if correctness matters.\n- Do not choose `pytz` for a brand-new Python 3.9+ project unless you need compatibility with an existing `pytz`-based stack.\n\n## Version-Sensitive Notes\n\n- This doc is pinned to `pytz` package version `2026.1.post1`, which PyPI lists as the latest release on March 3, 2026.\n- The official GitHub releases page shows both `release_2026.1` and a later same-day `release_2026.1.post1`; if you pin exact timezone data behavior, use the full `.post1` version instead of assuming `2026.1` is equivalent.\n- Upstream labels `release_2026.1.post1` as an `IANA 2026a` release.\n- The package description still documents legacy compatibility across very old Python versions, but the maintainer now explicitly says Python 3.9+ projects should generally use standard-library timezone support plus packages such as `tzdata`.\n- The docs URL, `https://pythonhosted.org/pytz/`, is official but stale as a version marker. It is still useful for `localize(...)`, `normalize(...)`, and DST exception behavior, but it is labeled `2014.10` and should not be treated as the current release docs homepage.\n\n## Official Sources\n\n- PyPI project page: https://pypi.org/project/pytz/\n- PyPI JSON API: https://pypi.org/pypi/pytz/json\n- Official repository releases: https://github.com/stub42/pytz/releases\n- Legacy upstream docs used for behavior examples: https://pythonhosted.org/pytz/\n"
  },
  {
    "path": "content/pyyaml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyYAML package guide for Python YAML parsing and emitting\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"pyyaml,yaml,serialization,configuration,python\"\n---\n\n# PyYAML Python Package Guide\n\n## What It Is\n\n`PyYAML` is the standard Python package for parsing YAML into Python objects and emitting Python objects as YAML.\n\n- Package name: `PyYAML`\n- Import name: `yaml`\n- Version covered: `6.0.3`\n- Python requirement on PyPI: `>=3.8`\n\n## Installation\n\nInstall the package version your project expects:\n\n```bash\npip install PyYAML==6.0.3\n```\n\nBasic import:\n\n```python\nimport yaml\n```\n\n## Initialization And Setup\n\nPyYAML does not require network setup, authentication, or service credentials.\n\nThe main setup decision is which loader and dumper you use:\n\n- `safe_load` / `safe_dump`: default choice for untrusted or ordinary YAML\n- `load(..., Loader=...)`: only when you intentionally need a specific loader\n- `CLoader` / `CDumper` or `CSafeLoader` / `CSafeDumper`: faster LibYAML-backed implementations when available\n\nOfficial docs recommend this fallback pattern when you want C bindings if available:\n\n```python\nimport yaml\n\ntry:\n    from yaml import CSafeLoader as SafeLoader, CSafeDumper as SafeDumper\nexcept ImportError:\n    from yaml import SafeLoader, SafeDumper\n```\n\n## Core Usage\n\n### Parse YAML Safely\n\nUse `safe_load()` for normal config files and request payloads:\n\n```python\nimport yaml\n\ndata = yaml.safe_load(\"\"\"\ndebug: true\nport: 8080\nhosts:\n  - api.internal\n  - worker.internal\n\"\"\")\n\nassert data == {\n    \"debug\": True,\n    \"port\": 8080,\n    \"hosts\": [\"api.internal\", \"worker.internal\"],\n}\n```\n\n### Parse Multiple YAML Documents\n\nUse `safe_load_all()` when the input contains `---` document separators:\n\n```python\nimport yaml\n\ndocuments = list(yaml.safe_load_all(\"\"\"\n---\nname: app\n---\nname: worker\n\"\"\"))\n```\n\n### Dump Python Objects As YAML\n\n```python\nimport yaml\n\npayload = {\n    \"service\": \"billing\",\n    \"replicas\": 3,\n    \"features\": [\"invoices\", \"refunds\"],\n}\n\ntext = yaml.safe_dump(payload, sort_keys=False)\nprint(text)\n```\n\nUse `safe_dump_all()` for multi-document output:\n\n```python\nimport yaml\n\ndocuments = [\n    {\"kind\": \"ConfigMap\", \"name\": \"app\"},\n    {\"kind\": \"Secret\", \"name\": \"app-secret\"},\n]\n\nyaml_text = yaml.safe_dump_all(documents, sort_keys=False)\n```\n\n### Read And Write Files\n\n```python\nfrom pathlib import Path\nimport yaml\n\nconfig_path = Path(\"config.yaml\")\nconfig = yaml.safe_load(config_path.read_text())\n\nconfig[\"debug\"] = False\nconfig_path.write_text(yaml.safe_dump(config, sort_keys=False))\n```\n\n## Custom Types And Tags\n\nIf you need custom YAML tags, register constructors and representers explicitly instead of switching everything to unsafe loading.\n\nExample with a custom `!env` tag:\n\n```python\nimport os\nimport yaml\n\ndef env_constructor(loader, node):\n    key = loader.construct_scalar(node)\n    return os.environ[key]\n\nclass EnvLoader(yaml.SafeLoader):\n    pass\n\nEnvLoader.add_constructor(\"!env\", env_constructor)\n\nconfig = yaml.load(\"token: !env API_TOKEN\\n\", Loader=EnvLoader)\n```\n\nFor custom Python classes, upstream docs also support using `yaml.YAMLObject` plus explicit safe loader configuration when you want that class to work with safe loading.\n\n## Configuration Notes\n\n### Safe Defaults\n\nFor most agent-written code:\n\n- parse with `yaml.safe_load()`\n- emit with `yaml.safe_dump(..., sort_keys=False)`\n- use a custom `SafeLoader` subclass only when you need a controlled extension such as a custom tag\n\n### Flow Style vs Block Style\n\nPyYAML chooses block style for collections with nested collections and flow style for flat collections unless you override `default_flow_style`.\n\nIf you need stable block-style output:\n\n```python\nyaml.safe_dump(data, sort_keys=False, default_flow_style=False)\n```\n\n### C Bindings\n\nLibYAML-backed loaders and dumpers are usually much faster. Upstream docs note there are some subtle behavioral differences between the pure Python and LibYAML implementations, so keep tests around formatting-sensitive output.\n\n## Common Pitfalls\n\n### Do Not Use `yaml.load()` On Untrusted Input\n\nThe upstream docs are explicit: `yaml.load` is as powerful as `pickle.load`. Treat it as unsafe for untrusted YAML.\n\nPrefer:\n\n```python\ndata = yaml.safe_load(text)\n```\n\nOnly use `yaml.load(text, Loader=...)` when you intentionally need non-safe tags or a custom loader.\n\n### Do Not Copy Legacy One-Argument `yaml.load(...)` Examples\n\nPyYAML's long-lived documentation page still contains older examples and is not tightly version-pinned. For `6.0.3`, use `safe_load()` or pass an explicit `Loader=...`.\n\n### Remember The Import Name\n\nInstall with `pip install PyYAML`, but import with:\n\n```python\nimport yaml\n```\n\n### `safe_load()` Will Not Construct Arbitrary Python Objects\n\nThat limitation is intentional. If you need custom tags, register them on a `SafeLoader` subclass or use an explicit loader only for trusted input.\n\n### C Loader Availability Depends On The Environment\n\nDo not assume `CSafeLoader` or `CDumper` exists everywhere. Keep the import fallback shown above if your code needs to run across multiple environments.\n\n## Version-Sensitive Notes For 6.0.3\n\n- PyPI currently lists `Requires: Python >=3.8` for `6.0.3`.\n- The official wiki documentation page is the main upstream landing page, but it is broad rather than version-scoped and still includes some legacy examples. This is an inference from the current docs content, not a separate upstream compatibility statement.\n- The upstream changelog for `6.0.3` is minimal and package-focused; treat loader safety guidance and current PyPI metadata as the main practical constraints for agent-written code.\n\n## Official Sources\n\n- Docs: https://pyyaml.org/wiki/PyYAMLDocumentation\n- PyPI: https://pypi.org/project/PyYAML/\n- Source repository: https://github.com/yaml/pyyaml\n- Changelog / releases: https://github.com/yaml/pyyaml/releases\n"
  },
  {
    "path": "content/qdrant/docs/vector-search/javascript/DOC.md",
    "content": "---\nname: vector-search\ndescription: \"Qdrant JavaScript SDK — use @qdrant/js-client-rest for vector database operations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.15.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"qdrant,vector-search,embeddings,similarity,ai\"\n---\n\n# Qdrant JavaScript SDK v1.15.1\n\n## Golden Rule\n\n**Always use `@qdrant/js-client-rest` for Qdrant vector database operations.**\n\nInstall with:\n```bash\nnpm install @qdrant/js-client-rest\n```\n\n**Do NOT use:**\n- `node-qdrant` (deprecated, unmaintained)\n- `@qdrant/qdrant-js` (main package, but REST client is preferred for most use cases)\n- `@qdrant/js-client-grpc` (unless you specifically need gRPC)\n\nThe REST client is recommended for most applications. It's easier to debug and provides all necessary functionality. Use gRPC only when you need maximum performance.\n\n## Installation\n\n```bash\nnpm install @qdrant/js-client-rest\n```\n\nFor TypeScript projects, types are included automatically.\n\n## Initialization\n\n### Basic Client Setup\n\n```javascript\nimport { QdrantClient } from '@qdrant/js-client-rest';\n\n// Local Qdrant instance\nconst client = new QdrantClient({\n  url: 'http://127.0.0.1:6333'\n});\n```\n\n### Alternative Initialization\n\n```javascript\nimport { QdrantClient } from '@qdrant/js-client-rest';\n\n// Using host and port\nconst client = new QdrantClient({\n  host: 'localhost',\n  port: 6333\n});\n```\n\n### Cloud Configuration\n\n```javascript\nimport { QdrantClient } from '@qdrant/js-client-rest';\n\n// Qdrant Cloud with API key\nconst client = new QdrantClient({\n  url: 'https://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.us-east-0-1.aws.cloud.qdrant.io',\n  apiKey: process.env.QDRANT_API_KEY,\n});\n```\n\n### With Environment Variables\n\n```javascript\nimport { QdrantClient } from '@qdrant/js-client-rest';\n\nconst client = new QdrantClient({\n  url: process.env.QDRANT_URL || 'http://127.0.0.1:6333',\n  apiKey: process.env.QDRANT_API_KEY,\n});\n```\n\n## Collections\n\n### List Collections\n\n```javascript\nconst result = await client.getCollections();\nconsole.log('Collections:', result.collections);\n```\n\n### Create Collection - Single Vector\n\n```javascript\nawait client.createCollection('my_collection', {\n  vectors: {\n    size: 384,\n    distance: 'Cosine'\n  }\n});\n```\n\n### Create Collection - Named Vectors\n\n```javascript\nawait client.createCollection('multi_vector_collection', {\n  vectors: {\n    image: {\n      size: 512,\n      distance: 'Dot'\n    },\n    text: {\n      size: 384,\n      distance: 'Cosine'\n    },\n  },\n});\n```\n\n### Create Collection - Multivector Configuration\n\n```javascript\nawait client.createCollection('multivec_collection', {\n  vectors: {\n    size: 128,\n    distance: 'Cosine',\n    multivector_config: {\n      comparator: 'max_sim'\n    }\n  }\n});\n```\n\n### Distance Metrics\n\nAvailable distance metrics:\n- `\"Cosine\"` - Cosine similarity (normalized dot product)\n- `\"Euclid\"` - Euclidean distance (L2)\n- `\"Dot\"` - Dot product\n- `\"Manhattan\"` - Manhattan distance (L1)\n\n### Create Collection - Advanced Options\n\n```javascript\nawait client.createCollection('advanced_collection', {\n  vectors: {\n    size: 768,\n    distance: 'Cosine',\n    on_disk: false,\n  },\n  shard_number: 2,\n  replication_factor: 1,\n  write_consistency_factor: 1,\n  optimizers_config: {\n    default_segment_number: 2,\n    indexing_threshold: 20000,\n  },\n  hnsw_config: {\n    m: 16,\n    ef_construct: 100,\n    full_scan_threshold: 10000,\n  }\n});\n```\n\n### Get Collection Info\n\n```javascript\nconst info = await client.getCollection('my_collection');\nconsole.log('Collection info:', info);\n```\n\n### Delete Collection\n\n```javascript\nawait client.deleteCollection('my_collection');\n```\n\n### Update Collection\n\n```javascript\nawait client.updateCollection('my_collection', {\n  optimizers_config: {\n    indexing_threshold: 30000\n  }\n});\n```\n\n## Points (Vectors)\n\n### Upsert Points - Basic\n\n```javascript\nawait client.upsert('my_collection', {\n  points: [\n    {\n      id: 1,\n      vector: [0.05, 0.61, 0.76, 0.74],\n      payload: {\n        city: 'Berlin',\n        price: 1.99,\n      }\n    },\n    {\n      id: 2,\n      vector: [0.19, 0.81, 0.75, 0.11],\n      payload: {\n        city: 'London',\n        price: 2.49,\n      }\n    }\n  ]\n});\n```\n\n### Upsert Points - Named Vectors\n\n```javascript\nawait client.upsert('multi_vector_collection', {\n  points: [\n    {\n      id: 1,\n      vector: {\n        image: [0.1, 0.2, 0.3, 0.4],\n        text: [0.5, 0.6, 0.7, 0.8, 0.9, 0.1, 0.2, 0.3]\n      },\n      payload: {\n        title: 'Product A',\n        category: 'electronics'\n      }\n    }\n  ]\n});\n```\n\n### Upsert Points - Sparse Vectors\n\n```javascript\nawait client.upsert('sparse_collection', {\n  points: [\n    {\n      id: 1,\n      vector: {\n        text: {\n          indices: [1, 3, 5, 7],\n          values: [0.1, 0.2, 0.3, 0.4]\n        }\n      },\n      payload: {\n        document: 'Sample text'\n      }\n    }\n  ]\n});\n```\n\n### Upsert Points - Batch Insert\n\n```javascript\nconst points = [];\nfor (let i = 0; i < 1000; i++) {\n  points.push({\n    id: i,\n    vector: Array(384).fill(0).map(() => Math.random()),\n    payload: {\n      index: i,\n      category: `cat_${i % 10}`\n    }\n  });\n}\n\nawait client.upsert('my_collection', {\n  points: points,\n  wait: true\n});\n```\n\n### Retrieve Points by ID\n\n```javascript\nconst points = await client.retrieve('my_collection', {\n  ids: [1, 2, 3],\n  with_payload: true,\n  with_vector: false\n});\nconsole.log('Retrieved points:', points);\n```\n\n### Retrieve Points - With Vectors\n\n```javascript\nconst points = await client.retrieve('my_collection', {\n  ids: [1, 2, 3],\n  with_payload: true,\n  with_vector: true\n});\n```\n\n### Delete Points by ID\n\n```javascript\nawait client.delete('my_collection', {\n  points: [1, 2, 3]\n});\n```\n\n### Delete Points by Filter\n\n```javascript\nawait client.delete('my_collection', {\n  filter: {\n    must: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      }\n    ]\n  }\n});\n```\n\n### Count Points\n\n```javascript\nconst count = await client.count('my_collection', {\n  exact: true\n});\nconsole.log('Total points:', count.count);\n```\n\n### Count Points with Filter\n\n```javascript\nconst count = await client.count('my_collection', {\n  filter: {\n    must: [\n      {\n        key: 'price',\n        range: {\n          gte: 2.0\n        }\n      }\n    ]\n  },\n  exact: true\n});\n```\n\n## Scroll (Pagination)\n\n### Basic Scroll\n\n```javascript\nconst result = await client.scroll('my_collection', {\n  limit: 10,\n  with_payload: true,\n  with_vector: false\n});\n\nconsole.log('Points:', result.points);\nconsole.log('Next offset:', result.next_page_offset);\n```\n\n### Scroll with Filter\n\n```javascript\nconst result = await client.scroll('my_collection', {\n  filter: {\n    must: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      }\n    ]\n  },\n  limit: 20,\n  with_payload: true\n});\n```\n\n### Scroll Pagination\n\n```javascript\nlet offset = null;\nconst allPoints = [];\n\nwhile (true) {\n  const result = await client.scroll('my_collection', {\n    limit: 100,\n    offset: offset,\n    with_payload: true,\n    with_vector: false\n  });\n\n  allPoints.push(...result.points);\n\n  if (!result.next_page_offset) {\n    break;\n  }\n\n  offset = result.next_page_offset;\n}\n\nconsole.log('Total points retrieved:', allPoints.length);\n```\n\n### Scroll with Order\n\n```javascript\nconst result = await client.scroll('my_collection', {\n  limit: 10,\n  order_by: 'price',\n  with_payload: true\n});\n```\n\n## Search\n\n### Basic Vector Search\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  limit: 5\n});\n\nresults.forEach(result => {\n  console.log(`ID: ${result.id}, Score: ${result.score}`);\n  console.log('Payload:', result.payload);\n});\n```\n\n### Search with Payload Only\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  limit: 5,\n  with_payload: true,\n  with_vector: false\n});\n```\n\n### Search with Score Threshold\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  limit: 10,\n  score_threshold: 0.8\n});\n```\n\n### Search Named Vectors\n\n```javascript\nconst results = await client.search('multi_vector_collection', {\n  vector: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],\n  using: 'text',\n  limit: 5\n});\n```\n\n## Filtering\n\n### Match Filter\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### Range Filter\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'price',\n        range: {\n          gte: 1.0,\n          lt: 3.0\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### Multiple Conditions (AND)\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      },\n      {\n        key: 'price',\n        range: {\n          gte: 2.0\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### OR Conditions\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    should: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      },\n      {\n        key: 'city',\n        match: {\n          value: 'London'\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### NOT Conditions\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must_not: [\n      {\n        key: 'city',\n        match: {\n          value: 'Berlin'\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### Complex Filter\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'category',\n        match: {\n          value: 'electronics'\n        }\n      }\n    ],\n    should: [\n      {\n        key: 'price',\n        range: {\n          lt: 100\n        }\n      },\n      {\n        key: 'discount',\n        match: {\n          value: true\n        }\n      }\n    ],\n    must_not: [\n      {\n        key: 'out_of_stock',\n        match: {\n          value: true\n        }\n      }\n    ]\n  },\n  limit: 10\n});\n```\n\n### Match Any (Array)\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'tags',\n        match: {\n          any: ['electronics', 'gadgets', 'tech']\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### Geo Radius Filter\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        key: 'location',\n        geo_radius: {\n          center: {\n            lon: 13.404954,\n            lat: 52.520008\n          },\n          radius: 5000.0\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n### Is Empty Filter\n\n```javascript\nconst results = await client.search('my_collection', {\n  vector: [0.18, 0.81, 0.75, 0.12],\n  filter: {\n    must: [\n      {\n        is_empty: {\n          key: 'tags'\n        }\n      }\n    ]\n  },\n  limit: 5\n});\n```\n\n## Query API (Universal)\n\n### Basic Query\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: [0.1, 0.2, 0.3, 0.4],\n  limit: 10\n});\n```\n\n### Query with Filter\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: [0.1, 0.1, 0.9],\n  filter: {\n    must: [\n      {\n        key: 'group_id',\n        match: {\n          value: 'user_1'\n        }\n      }\n    ]\n  },\n  limit: 10\n});\n```\n\n### Recommend Query\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: {\n    recommend: {\n      positive: [100, 231],\n      negative: [718]\n    }\n  },\n  limit: 10\n});\n```\n\n### Recommend with Vector Examples\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: {\n    recommend: {\n      positive: [100, 231],\n      negative: [[0.2, 0.3, 0.4, 0.5]]\n    }\n  },\n  limit: 10\n});\n```\n\n### Discover Query\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: {\n    discover: {\n      target: 100,\n      context: [\n        {\n          positive: 200,\n          negative: 300\n        },\n        {\n          positive: 150,\n          negative: 250\n        }\n      ]\n    }\n  },\n  limit: 10\n});\n```\n\n### Context Query\n\n```javascript\nconst results = await client.query('my_collection', {\n  query: {\n    context: [\n      {\n        positive: 100,\n        negative: 718\n      },\n      {\n        positive: 200,\n        negative: 300\n      }\n    ]\n  },\n  limit: 10\n});\n```\n\n## Batch Operations\n\n### Batch Search\n\n```javascript\nconst requests = [\n  {\n    vector: [0.1, 0.2, 0.3, 0.4],\n    limit: 5,\n    filter: {\n      must: [{ key: 'category', match: { value: 'electronics' } }]\n    }\n  },\n  {\n    vector: [0.5, 0.6, 0.7, 0.8],\n    limit: 5,\n    filter: {\n      must: [{ key: 'category', match: { value: 'books' } }]\n    }\n  }\n];\n\nconst results = await client.searchBatch('my_collection', {\n  searches: requests\n});\n\nresults.forEach((result, index) => {\n  console.log(`Results for request ${index}:`, result);\n});\n```\n\n### Batch Query\n\n```javascript\nconst requests = [\n  {\n    query: [0.1, 0.2, 0.3, 0.4],\n    limit: 5\n  },\n  {\n    query: {\n      recommend: {\n        positive: [100, 200],\n        negative: [300]\n      }\n    },\n    limit: 5\n  }\n];\n\nconst results = await client.queryBatch('my_collection', {\n  requests: requests\n});\n```\n\n### Batch Recommend\n\n```javascript\nconst requests = [\n  {\n    positive: [100, 231],\n    negative: [718],\n    limit: 10\n  },\n  {\n    positive: [500, 600],\n    negative: [700, 800],\n    limit: 10,\n    filter: {\n      must: [{ key: 'active', match: { value: true } }]\n    }\n  }\n];\n\nconst results = await client.recommendBatch('my_collection', {\n  searches: requests\n});\n```\n\n### Batch Upsert Operations\n\n```javascript\nconst operations = [\n  {\n    upsert: {\n      points: [\n        {\n          id: 1,\n          vector: [0.1, 0.2, 0.3, 0.4],\n          payload: { title: 'First' }\n        }\n      ]\n    }\n  },\n  {\n    upsert: {\n      points: [\n        {\n          id: 2,\n          vector: [0.5, 0.6, 0.7, 0.8],\n          payload: { title: 'Second' }\n        }\n      ]\n    }\n  }\n];\n\nawait client.batch('my_collection', {\n  operations: operations\n});\n```\n\n### Mixed Batch Operations\n\n```javascript\nconst operations = [\n  {\n    upsert: {\n      points: [\n        { id: 1, vector: [0.1, 0.2, 0.3, 0.4], payload: { title: 'Item 1' } }\n      ]\n    }\n  },\n  {\n    delete_points: {\n      points: [5, 6, 7]\n    }\n  },\n  {\n    set_payload: {\n      payload: { updated: true },\n      points: [1, 2, 3]\n    }\n  }\n];\n\nawait client.batch('my_collection', {\n  operations: operations,\n  wait: true\n});\n```\n\n## Payload Operations\n\n### Set Payload\n\n```javascript\nawait client.setPayload('my_collection', {\n  payload: {\n    updated_at: new Date().toISOString(),\n    verified: true\n  },\n  points: [1, 2, 3]\n});\n```\n\n### Set Payload with Filter\n\n```javascript\nawait client.setPayload('my_collection', {\n  payload: {\n    promoted: true\n  },\n  filter: {\n    must: [\n      {\n        key: 'price',\n        range: {\n          lt: 50\n        }\n      }\n    ]\n  }\n});\n```\n\n### Overwrite Payload\n\n```javascript\nawait client.overwritePayload('my_collection', {\n  payload: {\n    title: 'New Title',\n    price: 99.99\n  },\n  points: [1, 2]\n});\n```\n\n### Delete Payload Keys\n\n```javascript\nawait client.deletePayload('my_collection', {\n  keys: ['old_field', 'deprecated_field'],\n  points: [1, 2, 3]\n});\n```\n\n### Clear Payload\n\n```javascript\nawait client.clearPayload('my_collection', {\n  points: [1, 2, 3]\n});\n```\n\n## Snapshots\n\n### Create Collection Snapshot\n\n```javascript\nconst snapshot = await client.createSnapshot('my_collection');\nconsole.log('Snapshot name:', snapshot.name);\n```\n\n### List Collection Snapshots\n\n```javascript\nconst snapshots = await client.listSnapshots('my_collection');\nconsole.log('Snapshots:', snapshots);\n```\n\n### Delete Snapshot\n\n```javascript\nawait client.deleteSnapshot('my_collection', 'snapshot_name');\n```\n\n### Create Full Storage Snapshot\n\n```javascript\nconst snapshot = await client.createFullSnapshot();\nconsole.log('Full snapshot:', snapshot.name);\n```\n\n## Cluster Operations\n\n### Get Cluster Info\n\n```javascript\nconst clusterInfo = await client.clusterStatus();\nconsole.log('Cluster status:', clusterInfo);\n```\n\n## Payload Indexing\n\n### Create Payload Index\n\n```javascript\nawait client.createPayloadIndex('my_collection', {\n  field_name: 'city',\n  field_schema: 'keyword'\n});\n```\n\n### Create Payload Index - Integer\n\n```javascript\nawait client.createPayloadIndex('my_collection', {\n  field_name: 'price',\n  field_schema: 'integer'\n});\n```\n\n### Create Payload Index - Float\n\n```javascript\nawait client.createPayloadIndex('my_collection', {\n  field_name: 'rating',\n  field_schema: 'float'\n});\n```\n\n### Create Payload Index - Geo\n\n```javascript\nawait client.createPayloadIndex('my_collection', {\n  field_name: 'location',\n  field_schema: 'geo'\n});\n```\n\n### Delete Payload Index\n\n```javascript\nawait client.deletePayloadIndex('my_collection', 'field_name');\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\ntry {\n  const results = await client.search('my_collection', {\n    vector: [0.1, 0.2, 0.3, 0.4],\n    limit: 10\n  });\n  console.log('Results:', results);\n} catch (error) {\n  console.error('Search failed:', error.message);\n}\n```\n\n### Check Collection Exists\n\n```javascript\ntry {\n  const info = await client.getCollection('my_collection');\n  console.log('Collection exists');\n} catch (error) {\n  if (error.status === 404) {\n    console.log('Collection does not exist');\n    // Create collection\n    await client.createCollection('my_collection', {\n      vectors: { size: 384, distance: 'Cosine' }\n    });\n  } else {\n    throw error;\n  }\n}\n```\n\n### Retry Logic\n\n```javascript\nasync function searchWithRetry(collection, params, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await client.search(collection, params);\n    } catch (error) {\n      if (i === maxRetries - 1) throw error;\n      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));\n    }\n  }\n}\n\nconst results = await searchWithRetry('my_collection', {\n  vector: [0.1, 0.2, 0.3, 0.4],\n  limit: 10\n});\n```\n\n## Complete Example\n\n```javascript\nimport { QdrantClient } from '@qdrant/js-client-rest';\n\nconst client = new QdrantClient({\n  url: process.env.QDRANT_URL || 'http://127.0.0.1:6333',\n  apiKey: process.env.QDRANT_API_KEY\n});\n\nasync function main() {\n  const collectionName = 'products';\n\n  // Create collection\n  await client.createCollection(collectionName, {\n    vectors: { size: 4, distance: 'Cosine' }\n  });\n\n  // Upsert points\n  await client.upsert(collectionName, {\n    points: [\n      {\n        id: 1,\n        vector: [0.05, 0.61, 0.76, 0.74],\n        payload: {\n          name: 'Product A',\n          category: 'electronics',\n          price: 299.99\n        }\n      },\n      {\n        id: 2,\n        vector: [0.19, 0.81, 0.75, 0.11],\n        payload: {\n          name: 'Product B',\n          category: 'electronics',\n          price: 199.99\n        }\n      },\n      {\n        id: 3,\n        vector: [0.36, 0.55, 0.47, 0.94],\n        payload: {\n          name: 'Product C',\n          category: 'books',\n          price: 29.99\n        }\n      }\n    ]\n  });\n\n  // Search\n  const results = await client.search(collectionName, {\n    vector: [0.2, 0.7, 0.8, 0.1],\n    limit: 2,\n    with_payload: true\n  });\n\n  console.log('Search results:');\n  results.forEach(result => {\n    console.log(`  ${result.payload.name} - Score: ${result.score}`);\n  });\n\n  // Filtered search\n  const filteredResults = await client.search(collectionName, {\n    vector: [0.2, 0.7, 0.8, 0.1],\n    filter: {\n      must: [\n        {\n          key: 'category',\n          match: { value: 'electronics' }\n        },\n        {\n          key: 'price',\n          range: { lt: 250 }\n        }\n      ]\n    },\n    limit: 5\n  });\n\n  console.log('\\nFiltered results:');\n  filteredResults.forEach(result => {\n    console.log(`  ${result.payload.name} - $${result.payload.price}`);\n  });\n\n  // Count points\n  const count = await client.count(collectionName, { exact: true });\n  console.log(`\\nTotal points: ${count.count}`);\n\n  // Delete collection\n  await client.deleteCollection(collectionName);\n  console.log('Collection deleted');\n}\n\nmain().catch(console.error);\n```\n"
  },
  {
    "path": "content/qdrant/docs/vector-search/python/DOC.md",
    "content": "---\nname: vector-search\ndescription: \"Qdrant Python Client — use qdrant-client for vector database operations in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.15.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"qdrant,vector-search,embeddings,similarity,ai\"\n---\n\n# Qdrant Python Client v1.15.1\n\n## Golden Rule\n\n**Always use `qdrant-client` for Qdrant vector database operations in Python.**\n\nInstall with:\n```bash\npip install qdrant-client\n```\n\nFor FastEmbed integration (automatic embedding generation):\n```bash\npip install 'qdrant-client[fastembed]'\n```\n\n**Do NOT use:**\n- Outdated or unmaintained Qdrant Python packages\n- Direct REST API calls when the client library provides methods\n\nThe official `qdrant-client` provides both synchronous and asynchronous interfaces, gRPC support, and built-in FastEmbed integration.\n\n## Installation\n\n```bash\n# Basic installation\npip install qdrant-client\n\n# With FastEmbed support\npip install 'qdrant-client[fastembed]'\n\n# Or using uv\nuv pip install qdrant-client\n```\n\n## Initialization\n\n### In-Memory Client\n\n```python\nfrom qdrant_client import QdrantClient\n\n# In-memory instance (no persistence)\nclient = QdrantClient(\":memory:\")\n```\n\n### Local Persistent Storage\n\n```python\nfrom qdrant_client import QdrantClient\n\n# Persistent local storage\nclient = QdrantClient(path=\"./qdrant_data\")\n```\n\n### Remote Server\n\n```python\nfrom qdrant_client import QdrantClient\n\n# Connect to Qdrant server\nclient = QdrantClient(host=\"localhost\", port=6333)\n\n# Alternative using URL\nclient = QdrantClient(url=\"http://localhost:6333\")\n```\n\n### Qdrant Cloud\n\n```python\nfrom qdrant_client import QdrantClient\n\n# Connect to Qdrant Cloud\nclient = QdrantClient(\n    url=\"https://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.us-east-0-1.aws.cloud.qdrant.io\",\n    api_key=\"your-api-key-here\"\n)\n```\n\n### With Environment Variables\n\n```python\nimport os\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(\n    url=os.getenv(\"QDRANT_URL\", \"http://localhost:6333\"),\n    api_key=os.getenv(\"QDRANT_API_KEY\")\n)\n```\n\n### gRPC Configuration\n\n```python\nfrom qdrant_client import QdrantClient\n\n# Use gRPC for better performance\nclient = QdrantClient(\n    host=\"localhost\",\n    grpc_port=6334,\n    prefer_grpc=True\n)\n```\n\n### Async Client\n\n```python\nfrom qdrant_client import AsyncQdrantClient\n\n# Async client initialization\nasync_client = AsyncQdrantClient(\n    url=\"http://localhost:6333\"\n)\n\n# Use with async/await\nasync def main():\n    collections = await async_client.get_collections()\n    print(collections)\n```\n\n## Collections\n\n### List Collections\n\n```python\ncollections = client.get_collections()\nprint(collections.collections)\n```\n\n### Check Collection Exists\n\n```python\nexists = client.collection_exists(\"my_collection\")\nprint(f\"Collection exists: {exists}\")\n```\n\n### Create Collection - Single Vector\n\n```python\nfrom qdrant_client.models import Distance, VectorParams\n\nclient.create_collection(\n    collection_name=\"my_collection\",\n    vectors_config=VectorParams(size=384, distance=Distance.COSINE)\n)\n```\n\n### Distance Metrics\n\n```python\nfrom qdrant_client.models import Distance\n\n# Available distance metrics:\n# Distance.COSINE - Cosine similarity\n# Distance.EUCLID - Euclidean distance\n# Distance.DOT - Dot product\n# Distance.MANHATTAN - Manhattan distance\n```\n\n### Create Collection - Named Vectors\n\n```python\nfrom qdrant_client.models import Distance, VectorParams\n\nclient.create_collection(\n    collection_name=\"multi_vector_collection\",\n    vectors_config={\n        \"image\": VectorParams(size=512, distance=Distance.DOT),\n        \"text\": VectorParams(size=384, distance=Distance.COSINE)\n    }\n)\n```\n\n### Create Collection - Advanced Configuration\n\n```python\nfrom qdrant_client.models import (\n    Distance,\n    VectorParams,\n    OptimizersConfigDiff,\n    HnswConfigDiff,\n    QuantizationConfig,\n    ScalarQuantization,\n    ScalarType\n)\n\nclient.create_collection(\n    collection_name=\"advanced_collection\",\n    vectors_config=VectorParams(size=768, distance=Distance.COSINE),\n    shard_number=2,\n    replication_factor=1,\n    write_consistency_factor=1,\n    on_disk_payload=True,\n    hnsw_config=HnswConfigDiff(\n        m=16,\n        ef_construct=100,\n        full_scan_threshold=10000\n    ),\n    optimizers_config=OptimizersConfigDiff(\n        default_segment_number=2,\n        indexing_threshold=20000\n    ),\n    quantization_config=ScalarQuantization(\n        scalar=ScalarType.INT8,\n        quantile=0.99,\n        always_ram=True\n    )\n)\n```\n\n### Create Collection - Sparse Vectors\n\n```python\nfrom qdrant_client.models import Distance, VectorParams, SparseVectorParams\n\nclient.create_collection(\n    collection_name=\"sparse_collection\",\n    vectors_config={\n        \"dense\": VectorParams(size=384, distance=Distance.COSINE),\n        \"sparse\": SparseVectorParams()\n    }\n)\n```\n\n### Get Collection Info\n\n```python\ninfo = client.get_collection(\"my_collection\")\nprint(f\"Points count: {info.points_count}\")\nprint(f\"Vectors config: {info.config.params.vectors}\")\n```\n\n### Update Collection\n\n```python\nfrom qdrant_client.models import OptimizersConfigDiff\n\nclient.update_collection(\n    collection_name=\"my_collection\",\n    optimizers_config=OptimizersConfigDiff(\n        indexing_threshold=30000\n    )\n)\n```\n\n### Delete Collection\n\n```python\nclient.delete_collection(\"my_collection\")\n```\n\n## Points (Vectors)\n\n### Upsert Points - Basic\n\n```python\nfrom qdrant_client.models import PointStruct\n\noperation_info = client.upsert(\n    collection_name=\"my_collection\",\n    wait=True,\n    points=[\n        PointStruct(\n            id=1,\n            vector=[0.05, 0.61, 0.76, 0.74],\n            payload={\"city\": \"Berlin\", \"price\": 1.99}\n        ),\n        PointStruct(\n            id=2,\n            vector=[0.19, 0.81, 0.75, 0.11],\n            payload={\"city\": \"London\", \"price\": 2.49}\n        )\n    ]\n)\n```\n\n### Upsert Points - Auto ID\n\n```python\nfrom qdrant_client.models import PointStruct\nimport uuid\n\npoints = [\n    PointStruct(\n        id=str(uuid.uuid4()),\n        vector=[0.1, 0.2, 0.3, 0.4],\n        payload={\"title\": \"Document 1\"}\n    )\n]\n\nclient.upsert(\n    collection_name=\"my_collection\",\n    points=points\n)\n```\n\n### Upsert Points - Named Vectors\n\n```python\nfrom qdrant_client.models import PointStruct\n\nclient.upsert(\n    collection_name=\"multi_vector_collection\",\n    points=[\n        PointStruct(\n            id=1,\n            vector={\n                \"image\": [0.1, 0.2, 0.3, 0.4],\n                \"text\": [0.5, 0.6, 0.7, 0.8]\n            },\n            payload={\"title\": \"Product A\", \"category\": \"electronics\"}\n        )\n    ]\n)\n```\n\n### Upsert Points - Sparse Vectors\n\n```python\nfrom qdrant_client.models import PointStruct, SparseVector\n\nclient.upsert(\n    collection_name=\"sparse_collection\",\n    points=[\n        PointStruct(\n            id=1,\n            vector={\n                \"dense\": [0.1, 0.2, 0.3, 0.4],\n                \"sparse\": SparseVector(\n                    indices=[1, 3, 5, 7],\n                    values=[0.1, 0.2, 0.3, 0.4]\n                )\n            },\n            payload={\"text\": \"Sample document\"}\n        )\n    ]\n)\n```\n\n### Upsert Points - Batch\n\n```python\nfrom qdrant_client.models import PointStruct\nimport numpy as np\n\nvectors = np.random.rand(1000, 384)\npoints = [\n    PointStruct(\n        id=idx,\n        vector=vector.tolist(),\n        payload={\"index\": idx, \"category\": f\"cat_{idx % 10}\"}\n    )\n    for idx, vector in enumerate(vectors)\n]\n\nclient.upsert(\n    collection_name=\"my_collection\",\n    points=points,\n    wait=True\n)\n```\n\n### Add Documents with FastEmbed\n\n```python\ndocuments = [\n    \"Qdrant has Langchain integrations\",\n    \"Qdrant also has Llama Index integrations\",\n    \"Qdrant is a vector database\"\n]\n\nmetadata = [\n    {\"source\": \"langchain-docs\"},\n    {\"source\": \"llamaindex-docs\"},\n    {\"source\": \"qdrant-docs\"}\n]\n\nids = [1, 2, 3]\n\nclient.add(\n    collection_name=\"demo_collection\",\n    documents=documents,\n    metadata=metadata,\n    ids=ids\n)\n```\n\n### Retrieve Points by ID\n\n```python\npoints = client.retrieve(\n    collection_name=\"my_collection\",\n    ids=[1, 2, 3],\n    with_payload=True,\n    with_vectors=False\n)\n\nfor point in points:\n    print(f\"ID: {point.id}, Payload: {point.payload}\")\n```\n\n### Retrieve Points - With Vectors\n\n```python\npoints = client.retrieve(\n    collection_name=\"my_collection\",\n    ids=[1, 2, 3],\n    with_payload=True,\n    with_vectors=True\n)\n```\n\n### Delete Points by ID\n\n```python\nclient.delete(\n    collection_name=\"my_collection\",\n    points_selector=[1, 2, 3]\n)\n```\n\n### Delete Points by Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nclient.delete(\n    collection_name=\"my_collection\",\n    points_selector=Filter(\n        must=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"Berlin\")\n            )\n        ]\n    )\n)\n```\n\n### Count Points\n\n```python\ncount = client.count(\n    collection_name=\"my_collection\",\n    exact=True\n)\nprint(f\"Total points: {count.count}\")\n```\n\n### Count Points with Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, Range\n\ncount = client.count(\n    collection_name=\"my_collection\",\n    count_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"price\",\n                range=Range(gte=2.0)\n            )\n        ]\n    ),\n    exact=True\n)\n```\n\n## Scroll (Pagination)\n\n### Basic Scroll\n\n```python\nrecords, next_page_offset = client.scroll(\n    collection_name=\"my_collection\",\n    limit=10,\n    with_payload=True,\n    with_vectors=False\n)\n\nfor record in records:\n    print(f\"ID: {record.id}, Payload: {record.payload}\")\n```\n\n### Scroll with Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nrecords, next_page_offset = client.scroll(\n    collection_name=\"my_collection\",\n    scroll_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"Berlin\")\n            )\n        ]\n    ),\n    limit=20,\n    with_payload=True\n)\n```\n\n### Scroll Pagination\n\n```python\noffset = None\nall_points = []\n\nwhile True:\n    records, next_page_offset = client.scroll(\n        collection_name=\"my_collection\",\n        limit=100,\n        offset=offset,\n        with_payload=True,\n        with_vectors=False\n    )\n\n    all_points.extend(records)\n\n    if next_page_offset is None:\n        break\n\n    offset = next_page_offset\n\nprint(f\"Total points retrieved: {len(all_points)}\")\n```\n\n### Scroll with Order By\n\n```python\nrecords, next_page_offset = client.scroll(\n    collection_name=\"my_collection\",\n    limit=15,\n    order_by=\"timestamp\",\n    with_payload=True\n)\n```\n\n## Search\n\n### Basic Vector Search\n\n```python\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.18, 0.81, 0.75, 0.12],\n    limit=5\n)\n\nfor result in search_result:\n    print(f\"ID: {result.id}, Score: {result.score}\")\n    print(f\"Payload: {result.payload}\")\n```\n\n### Search with Score Threshold\n\n```python\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.18, 0.81, 0.75, 0.12],\n    limit=10,\n    score_threshold=0.8\n)\n```\n\n### Search Named Vectors\n\n```python\nsearch_result = client.search(\n    collection_name=\"multi_vector_collection\",\n    query_vector=[0.1, 0.2, 0.3, 0.4],\n    using=\"text\",\n    limit=5\n)\n```\n\n### Search without Vectors\n\n```python\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.18, 0.81, 0.75, 0.12],\n    limit=5,\n    with_payload=True,\n    with_vectors=False\n)\n```\n\n### Text Query with FastEmbed\n\n```python\nsearch_result = client.query(\n    collection_name=\"demo_collection\",\n    query_text=\"This is a query document\",\n    limit=5\n)\n\nfor result in search_result:\n    print(f\"Score: {result.score}, Text: {result.payload}\")\n```\n\n## Filtering\n\n### Match Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"London\")\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Range Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, Range\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"price\",\n                range=Range(gte=1.0, lt=3.0)\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Multiple Conditions (AND)\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue, Range\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"Berlin\")\n            ),\n            FieldCondition(\n                key=\"price\",\n                range=Range(gte=2.0)\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### OR Conditions\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        should=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"Berlin\")\n            ),\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"London\")\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### NOT Conditions\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must_not=[\n            FieldCondition(\n                key=\"city\",\n                match=MatchValue(value=\"Berlin\")\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Complex Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue, Range\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"category\",\n                match=MatchValue(value=\"electronics\")\n            )\n        ],\n        should=[\n            FieldCondition(\n                key=\"price\",\n                range=Range(lt=100)\n            ),\n            FieldCondition(\n                key=\"discount\",\n                match=MatchValue(value=True)\n            )\n        ],\n        must_not=[\n            FieldCondition(\n                key=\"out_of_stock\",\n                match=MatchValue(value=True)\n            )\n        ]\n    ),\n    limit=10\n)\n```\n\n### Match Any (Array)\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchAny\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"tags\",\n                match=MatchAny(any=[\"electronics\", \"gadgets\", \"tech\"])\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Geo Radius Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, GeoRadius, GeoPoint\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"location\",\n                geo_radius=GeoRadius(\n                    center=GeoPoint(lon=13.404954, lat=52.520008),\n                    radius=5000.0\n                )\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Is Empty Filter\n\n```python\nfrom qdrant_client.models import Filter, IsEmptyCondition\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            IsEmptyCondition(is_empty={\"key\": \"tags\"})\n        ]\n    ),\n    limit=5\n)\n```\n\n### Is Null Filter\n\n```python\nfrom qdrant_client.models import Filter, IsNullCondition\n\nsearch_result = client.search(\n    collection_name=\"my_collection\",\n    query_vector=[0.2, 0.1, 0.9, 0.7],\n    query_filter=Filter(\n        must=[\n            IsNullCondition(is_null={\"key\": \"description\"})\n        ]\n    ),\n    limit=5\n)\n```\n\n## Recommend\n\n### Basic Recommend\n\n```python\nrecommend_result = client.recommend(\n    collection_name=\"my_collection\",\n    positive=[1, 2, 3],\n    negative=[10],\n    limit=5\n)\n\nfor result in recommend_result:\n    print(f\"ID: {result.id}, Score: {result.score}\")\n```\n\n### Recommend with Vectors\n\n```python\nrecommend_result = client.recommend(\n    collection_name=\"my_collection\",\n    positive=[1, 2, [0.1, 0.2, 0.3, 0.4]],\n    negative=[[0.9, 0.8, 0.7, 0.6]],\n    limit=5\n)\n```\n\n### Recommend with Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, MatchValue\n\nrecommend_result = client.recommend(\n    collection_name=\"my_collection\",\n    positive=[1, 2, 3],\n    negative=[10],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"category\",\n                match=MatchValue(value=\"electronics\")\n            )\n        ]\n    ),\n    limit=5\n)\n```\n\n### Recommend Strategy\n\n```python\nfrom qdrant_client.models import RecommendStrategy\n\nrecommend_result = client.recommend(\n    collection_name=\"my_collection\",\n    positive=[1, 2, 3],\n    negative=[10],\n    strategy=RecommendStrategy.AVERAGE_VECTOR,\n    limit=5\n)\n```\n\n### Recommend Named Vectors\n\n```python\nrecommend_result = client.recommend(\n    collection_name=\"multi_vector_collection\",\n    positive=[1, 2],\n    negative=[10],\n    using=\"text\",\n    limit=5\n)\n```\n\n## Discover\n\n### Basic Discover\n\n```python\nfrom qdrant_client.models import ContextPair\n\ndiscover_result = client.discover(\n    collection_name=\"my_collection\",\n    target=100,\n    context=[\n        ContextPair(positive=200, negative=300),\n        ContextPair(positive=150, negative=250)\n    ],\n    limit=10\n)\n```\n\n### Discover with Filter\n\n```python\nfrom qdrant_client.models import ContextPair, Filter, FieldCondition, MatchValue\n\ndiscover_result = client.discover(\n    collection_name=\"my_collection\",\n    target=100,\n    context=[\n        ContextPair(positive=200, negative=300)\n    ],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"active\",\n                match=MatchValue(value=True)\n            )\n        ]\n    ),\n    limit=10\n)\n```\n\n## Query API (Universal)\n\n### Vector Query\n\n```python\nfrom qdrant_client.models import QueryRequest, VectorQuery\n\nquery_result = client.query_points(\n    collection_name=\"my_collection\",\n    query=[0.1, 0.2, 0.3, 0.4],\n    limit=10\n)\n```\n\n### Recommend Query\n\n```python\nfrom qdrant_client.models import RecommendQuery\n\nquery_result = client.query_points(\n    collection_name=\"my_collection\",\n    query=RecommendQuery(\n        recommend=RecommendInput(\n            positive=[100, 231],\n            negative=[718]\n        )\n    ),\n    limit=10\n)\n```\n\n### Discover Query\n\n```python\nfrom qdrant_client.models import DiscoverQuery, ContextPair\n\nquery_result = client.query_points(\n    collection_name=\"my_collection\",\n    query=DiscoverQuery(\n        discover=DiscoverInput(\n            target=100,\n            context=[\n                ContextPair(positive=200, negative=300)\n            ]\n        )\n    ),\n    limit=10\n)\n```\n\n### Context Query\n\n```python\nfrom qdrant_client.models import ContextQuery, ContextPair\n\nquery_result = client.query_points(\n    collection_name=\"my_collection\",\n    query=ContextQuery(\n        context=[\n            ContextPair(positive=100, negative=718),\n            ContextPair(positive=200, negative=300)\n        ]\n    ),\n    limit=10\n)\n```\n\n## Batch Operations\n\n### Batch Search\n\n```python\nfrom qdrant_client.models import SearchRequest, Filter, FieldCondition, MatchValue\n\nrequests = [\n    SearchRequest(\n        vector=[0.1, 0.2, 0.3, 0.4],\n        limit=5,\n        filter=Filter(\n            must=[\n                FieldCondition(\n                    key=\"category\",\n                    match=MatchValue(value=\"electronics\")\n                )\n            ]\n        )\n    ),\n    SearchRequest(\n        vector=[0.5, 0.6, 0.7, 0.8],\n        limit=5,\n        filter=Filter(\n            must=[\n                FieldCondition(\n                    key=\"category\",\n                    match=MatchValue(value=\"books\")\n                )\n            ]\n        )\n    )\n]\n\nresults = client.search_batch(\n    collection_name=\"my_collection\",\n    requests=requests\n)\n\nfor i, result in enumerate(results):\n    print(f\"Results for request {i}:\")\n    for point in result:\n        print(f\"  ID: {point.id}, Score: {point.score}\")\n```\n\n### Batch Query\n\n```python\nfrom qdrant_client.models import QueryRequest\n\nrequests = [\n    QueryRequest(\n        query=[0.1, 0.2, 0.3, 0.4],\n        limit=5\n    ),\n    QueryRequest(\n        query=[0.5, 0.6, 0.7, 0.8],\n        limit=5\n    )\n]\n\nresults = client.query_batch_points(\n    collection_name=\"my_collection\",\n    requests=requests\n)\n```\n\n### Batch Recommend\n\n```python\nfrom qdrant_client.models import RecommendRequest, Filter, FieldCondition, MatchValue\n\nrequests = [\n    RecommendRequest(\n        positive=[100, 231],\n        negative=[718],\n        limit=10\n    ),\n    RecommendRequest(\n        positive=[500, 600],\n        negative=[700, 800],\n        limit=10,\n        filter=Filter(\n            must=[\n                FieldCondition(\n                    key=\"active\",\n                    match=MatchValue(value=True)\n                )\n            ]\n        )\n    )\n]\n\nresults = client.recommend_batch(\n    collection_name=\"my_collection\",\n    requests=requests\n)\n```\n\n### Batch Update Points\n\n```python\nfrom qdrant_client.models import (\n    PointStruct,\n    UpsertOperation,\n    DeleteOperation,\n    SetPayloadOperation,\n    PointIdsList,\n    UpdateStatus\n)\n\nclient.batch_update_points(\n    collection_name=\"my_collection\",\n    update_operations=[\n        UpsertOperation(\n            upsert=PointsList(\n                points=[\n                    PointStruct(\n                        id=1,\n                        vector=[1.0, 2.0, 3.0, 4.0],\n                        payload={\"title\": \"Item 1\"}\n                    )\n                ]\n            )\n        ),\n        DeleteOperation(\n            delete=PointIdsList(points=[5, 6, 7])\n        ),\n        SetPayloadOperation(\n            set_payload=SetPayload(\n                payload={\"updated\": True},\n                points=[1, 2, 3]\n            )\n        )\n    ]\n)\n```\n\n### Mixed Batch Operations\n\n```python\nfrom qdrant_client.models import (\n    UpsertOperation,\n    UpdateVectorsOperation,\n    DeletePayloadOperation,\n    PointStruct,\n    PointsList,\n    UpdateVectors,\n    PointVectors,\n    DeletePayload,\n    PointIdsList\n)\n\nclient.batch_update_points(\n    collection_name=\"my_collection\",\n    update_operations=[\n        UpsertOperation(\n            upsert=PointsList(\n                points=[\n                    PointStruct(\n                        id=1,\n                        vector=[1.0, 2.0, 3.0, 4.0],\n                        payload={}\n                    )\n                ]\n            )\n        ),\n        UpdateVectorsOperation(\n            update_vectors=UpdateVectors(\n                points=[\n                    PointVectors(\n                        id=2,\n                        vector=[5.0, 6.0, 7.0, 8.0]\n                    )\n                ]\n            )\n        ),\n        DeletePayloadOperation(\n            delete_payload=DeletePayload(\n                keys=[\"old_field\"],\n                points=PointIdsList(points=[3, 4])\n            )\n        )\n    ]\n)\n```\n\n## Payload Operations\n\n### Set Payload\n\n```python\nfrom datetime import datetime\n\nclient.set_payload(\n    collection_name=\"my_collection\",\n    payload={\n        \"updated_at\": datetime.now().isoformat(),\n        \"verified\": True\n    },\n    points=[1, 2, 3]\n)\n```\n\n### Set Payload with Filter\n\n```python\nfrom qdrant_client.models import Filter, FieldCondition, Range\n\nclient.set_payload(\n    collection_name=\"my_collection\",\n    payload={\"promoted\": True},\n    points=Filter(\n        must=[\n            FieldCondition(\n                key=\"price\",\n                range=Range(lt=50)\n            )\n        ]\n    )\n)\n```\n\n### Overwrite Payload\n\n```python\nclient.overwrite_payload(\n    collection_name=\"my_collection\",\n    payload={\n        \"title\": \"New Title\",\n        \"price\": 99.99\n    },\n    points=[1, 2]\n)\n```\n\n### Delete Payload Keys\n\n```python\nclient.delete_payload(\n    collection_name=\"my_collection\",\n    keys=[\"old_field\", \"deprecated_field\"],\n    points=[1, 2, 3]\n)\n```\n\n### Clear Payload\n\n```python\nclient.clear_payload(\n    collection_name=\"my_collection\",\n    points_selector=[1, 2, 3]\n)\n```\n\n## Payload Indexing\n\n### Create Payload Index - Keyword\n\n```python\nclient.create_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"city\",\n    field_schema=\"keyword\"\n)\n```\n\n### Create Payload Index - Integer\n\n```python\nclient.create_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"price\",\n    field_schema=\"integer\"\n)\n```\n\n### Create Payload Index - Float\n\n```python\nclient.create_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"rating\",\n    field_schema=\"float\"\n)\n```\n\n### Create Payload Index - Geo\n\n```python\nclient.create_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"location\",\n    field_schema=\"geo\"\n)\n```\n\n### Create Payload Index - Text\n\n```python\nfrom qdrant_client.models import TextIndexParams, TokenizerType\n\nclient.create_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"description\",\n    field_schema=TextIndexParams(\n        type=\"text\",\n        tokenizer=TokenizerType.WORD,\n        min_token_len=2,\n        max_token_len=20,\n        lowercase=True\n    )\n)\n```\n\n### Delete Payload Index\n\n```python\nclient.delete_payload_index(\n    collection_name=\"my_collection\",\n    field_name=\"old_index_field\"\n)\n```\n\n## Snapshots\n\n### Create Collection Snapshot\n\n```python\nsnapshot_info = client.create_snapshot(\n    collection_name=\"my_collection\"\n)\nprint(f\"Snapshot created: {snapshot_info.name}\")\n```\n\n### List Collection Snapshots\n\n```python\nsnapshots = client.list_snapshots(\n    collection_name=\"my_collection\"\n)\n\nfor snapshot in snapshots:\n    print(f\"Snapshot: {snapshot.name}, Size: {snapshot.size}\")\n```\n\n### Delete Collection Snapshot\n\n```python\nclient.delete_snapshot(\n    collection_name=\"my_collection\",\n    snapshot_name=\"snapshot_2025-01-15-10-30-00\"\n)\n```\n\n### Create Full Storage Snapshot\n\n```python\nsnapshot_info = client.create_full_snapshot()\nprint(f\"Full snapshot created: {snapshot_info.name}\")\n```\n\n### List Full Snapshots\n\n```python\nsnapshots = client.list_full_snapshots()\nfor snapshot in snapshots:\n    print(f\"Full snapshot: {snapshot.name}\")\n```\n\n### Download Snapshot\n\n```python\nclient.download_snapshot(\n    collection_name=\"my_collection\",\n    snapshot_name=\"snapshot_2025-01-15-10-30-00\",\n    snapshot_path=\"./backups/snapshot.snapshot\"\n)\n```\n\n## Cluster Operations\n\n### Get Cluster Info\n\n```python\ncluster_info = client.cluster_status()\nprint(f\"Peers: {cluster_info.peers}\")\nprint(f\"Raft info: {cluster_info.raft_info}\")\n```\n\n## Async Operations\n\n### Async Client Usage\n\n```python\nfrom qdrant_client import AsyncQdrantClient\nfrom qdrant_client.models import Distance, VectorParams, PointStruct\nimport asyncio\n\nasync def main():\n    client = AsyncQdrantClient(url=\"http://localhost:6333\")\n\n    # Create collection\n    await client.create_collection(\n        collection_name=\"async_collection\",\n        vectors_config=VectorParams(size=4, distance=Distance.COSINE)\n    )\n\n    # Upsert points\n    await client.upsert(\n        collection_name=\"async_collection\",\n        points=[\n            PointStruct(\n                id=1,\n                vector=[0.1, 0.2, 0.3, 0.4],\n                payload={\"title\": \"Async document\"}\n            )\n        ]\n    )\n\n    # Search\n    results = await client.search(\n        collection_name=\"async_collection\",\n        query_vector=[0.1, 0.2, 0.3, 0.4],\n        limit=5\n    )\n\n    for result in results:\n        print(f\"ID: {result.id}, Score: {result.score}\")\n\n    await client.close()\n\nasyncio.run(main())\n```\n\n### Async Context Manager\n\n```python\nfrom qdrant_client import AsyncQdrantClient\n\nasync def main():\n    async with AsyncQdrantClient(url=\"http://localhost:6333\") as client:\n        collections = await client.get_collections()\n        print(collections)\n\nasyncio.run(main())\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\ntry:\n    search_result = client.search(\n        collection_name=\"my_collection\",\n        query_vector=[0.1, 0.2, 0.3, 0.4],\n        limit=10\n    )\nexcept Exception as e:\n    print(f\"Search failed: {e}\")\n```\n\n### Check Collection Exists Before Operations\n\n```python\nif not client.collection_exists(\"my_collection\"):\n    from qdrant_client.models import Distance, VectorParams\n\n    client.create_collection(\n        collection_name=\"my_collection\",\n        vectors_config=VectorParams(size=384, distance=Distance.COSINE)\n    )\n```\n\n### Retry Logic\n\n```python\nimport time\nfrom qdrant_client.http.exceptions import UnexpectedResponse\n\ndef search_with_retry(client, collection_name, query_vector, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            return client.search(\n                collection_name=collection_name,\n                query_vector=query_vector,\n                limit=5\n            )\n        except UnexpectedResponse as e:\n            if attempt == max_retries - 1:\n                raise\n            time.sleep(2 ** attempt)\n\nresults = search_with_retry(client, \"my_collection\", [0.1, 0.2, 0.3, 0.4])\n```\n\n## Complete Example\n\n```python\nfrom qdrant_client import QdrantClient\nfrom qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue, Range\nimport numpy as np\n\n# Initialize client\nclient = QdrantClient(url=\"http://localhost:6333\")\n\ncollection_name = \"products\"\n\n# Create collection\nif not client.collection_exists(collection_name):\n    client.create_collection(\n        collection_name=collection_name,\n        vectors_config=VectorParams(size=4, distance=Distance.COSINE)\n    )\n\n# Upsert points\nclient.upsert(\n    collection_name=collection_name,\n    points=[\n        PointStruct(\n            id=1,\n            vector=[0.05, 0.61, 0.76, 0.74],\n            payload={\n                \"name\": \"Product A\",\n                \"category\": \"electronics\",\n                \"price\": 299.99,\n                \"in_stock\": True\n            }\n        ),\n        PointStruct(\n            id=2,\n            vector=[0.19, 0.81, 0.75, 0.11],\n            payload={\n                \"name\": \"Product B\",\n                \"category\": \"electronics\",\n                \"price\": 199.99,\n                \"in_stock\": True\n            }\n        ),\n        PointStruct(\n            id=3,\n            vector=[0.36, 0.55, 0.47, 0.94],\n            payload={\n                \"name\": \"Product C\",\n                \"category\": \"books\",\n                \"price\": 29.99,\n                \"in_stock\": False\n            }\n        ),\n        PointStruct(\n            id=4,\n            vector=[0.88, 0.22, 0.33, 0.44],\n            payload={\n                \"name\": \"Product D\",\n                \"category\": \"electronics\",\n                \"price\": 399.99,\n                \"in_stock\": True\n            }\n        )\n    ],\n    wait=True\n)\n\n# Basic search\nprint(\"=== Basic Search ===\")\nresults = client.search(\n    collection_name=collection_name,\n    query_vector=[0.2, 0.7, 0.8, 0.1],\n    limit=3\n)\n\nfor result in results:\n    print(f\"{result.payload['name']} - Score: {result.score:.4f}\")\n\n# Filtered search\nprint(\"\\n=== Filtered Search (electronics under $300) ===\")\nfiltered_results = client.search(\n    collection_name=collection_name,\n    query_vector=[0.2, 0.7, 0.8, 0.1],\n    query_filter=Filter(\n        must=[\n            FieldCondition(\n                key=\"category\",\n                match=MatchValue(value=\"electronics\")\n            ),\n            FieldCondition(\n                key=\"price\",\n                range=Range(lt=300)\n            ),\n            FieldCondition(\n                key=\"in_stock\",\n                match=MatchValue(value=True)\n            )\n        ]\n    ),\n    limit=5\n)\n\nfor result in filtered_results:\n    print(f\"{result.payload['name']} - ${result.payload['price']}\")\n\n# Count points\ncount = client.count(collection_name=collection_name, exact=True)\nprint(f\"\\n=== Total Points: {count.count} ===\")\n\n# Recommend\nprint(\"\\n=== Recommendations based on Product A ===\")\nrecommendations = client.recommend(\n    collection_name=collection_name,\n    positive=[1],\n    negative=[],\n    limit=3\n)\n\nfor rec in recommendations:\n    print(f\"{rec.payload['name']} - Score: {rec.score:.4f}\")\n\n# Scroll through all points\nprint(\"\\n=== All Products (via scroll) ===\")\nrecords, next_offset = client.scroll(\n    collection_name=collection_name,\n    limit=10,\n    with_payload=True,\n    with_vectors=False\n)\n\nfor record in records:\n    print(f\"ID {record.id}: {record.payload['name']} - {record.payload['category']}\")\n\n# Cleanup\nclient.delete_collection(collection_name)\nprint(f\"\\n=== Collection '{collection_name}' deleted ===\")\n```\n"
  },
  {
    "path": "content/qdrant-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"qdrant-client for Python - Qdrant vector database client for local, server, and cloud usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"qdrant,vector-database,embeddings,search,retrieval,rag\"\n---\n\n# qdrant-client Python Package Guide\n\n## Golden Rule\n\nUse `qdrant-client` for Python integrations with Qdrant, and choose one connection mode up front:\n\n- local mode for tests and quick prototypes\n- remote REST for normal server or cloud usage\n- gRPC when bulk upload throughput matters\n\nDefine the collection schema before writing points. Vector size and distance metric must match the embeddings you actually send.\n\n## Install\n\n```bash\npip install qdrant-client==1.17.0\n```\n\nOptional local embedding extras from the upstream README:\n\n```bash\npip install \"qdrant-client[fastembed]\"\npip install \"qdrant-client[fastembed-gpu]\"\n```\n\n`qdrant-client` `1.17.0` requires Python `>=3.10`.\n\n## Choose a Connection Mode\n\n### In-memory local mode\n\nUseful for tests, notebooks, and offline prototypes.\n\n```python\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(location=\":memory:\")\n```\n\n### Persistent local mode\n\nStores data on disk without running a separate Qdrant server.\n\n```python\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(path=\"./qdrant-data\")\n```\n\n### Remote server over REST\n\nUse either a full `url=` or `host=` plus ports. Do not mix styles unless you have a specific reason.\n\n```python\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(url=\"http://localhost:6333\")\n```\n\n### Qdrant Cloud\n\n```python\nimport os\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(\n    url=os.environ[\"QDRANT_URL\"],\n    api_key=os.environ[\"QDRANT_API_KEY\"],\n)\n```\n\n### Prefer gRPC for heavier writes\n\nThe client can use gRPC for custom methods and uploads when the server exposes it.\n\n```python\nimport os\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(\n    url=os.environ[\"QDRANT_URL\"],\n    api_key=os.environ.get(\"QDRANT_API_KEY\"),\n    prefer_grpc=True,\n    grpc_port=6334,\n)\n```\n\n## Initialize a Collection\n\nCreate the collection once with the right vector shape and distance metric.\n\n```python\nfrom qdrant_client import QdrantClient, models\n\nclient = QdrantClient(location=\":memory:\")\n\nclient.create_collection(\n    collection_name=\"docs\",\n    vectors_config=models.VectorParams(\n        size=768,\n        distance=models.Distance.COSINE,\n    ),\n)\n```\n\nNotes:\n\n- `size` must match the embedding dimension exactly.\n- The metric is part of the collection schema. Changing models later often means recreating the collection.\n\n## Insert Points\n\nUse `PointStruct` when you already have vectors.\n\n```python\nfrom qdrant_client import QdrantClient, models\n\nclient = QdrantClient(location=\":memory:\")\n\nclient.create_collection(\n    collection_name=\"docs\",\n    vectors_config=models.VectorParams(size=4, distance=models.Distance.COSINE),\n)\n\nclient.upsert(\n    collection_name=\"docs\",\n    points=[\n        models.PointStruct(\n            id=1,\n            vector=[0.05, 0.61, 0.76, 0.74],\n            payload={\"title\": \"Getting started\", \"lang\": \"en\"},\n        ),\n        models.PointStruct(\n            id=2,\n            vector=[0.19, 0.81, 0.75, 0.11],\n            payload={\"title\": \"Async usage\", \"lang\": \"en\"},\n        ),\n    ],\n)\n```\n\nFor large ingests, prefer `upload_collection()` or `upload_points()` instead of hand-written small loops. The upstream client batches lazily and retries automatically.\n\n## Query Points\n\nUse `query_points()` for current generic vector search in the Python client docs.\n\n```python\nfrom qdrant_client import QdrantClient, models\n\nclient = QdrantClient(location=\":memory:\")\n\nresults = client.query_points(\n    collection_name=\"docs\",\n    query=[0.04, 0.60, 0.77, 0.70],\n    limit=3,\n)\n\nfor point in results.points:\n    print(point.id, point.score, point.payload)\n```\n\nAdd filters when you need payload-aware retrieval:\n\n```python\nfrom qdrant_client import models\n\nresults = client.query_points(\n    collection_name=\"docs\",\n    query=[0.04, 0.60, 0.77, 0.70],\n    query_filter=models.Filter(\n        must=[\n            models.FieldCondition(\n                key=\"lang\",\n                match=models.MatchValue(value=\"en\"),\n            )\n        ]\n    ),\n    limit=3,\n)\n```\n\n## Read and Delete\n\n```python\nfrom qdrant_client import models\n\npoints = client.retrieve(\n    collection_name=\"docs\",\n    ids=[1, 2],\n)\n\nclient.delete(\n    collection_name=\"docs\",\n    points_selector=models.PointIdsList(points=[2]),\n)\n```\n\n## Async Usage\n\n`AsyncQdrantClient` exposes the same API shape as the sync client and is available in the Python client from `1.6.1` onward.\n\n```python\nfrom qdrant_client import AsyncQdrantClient, models\n\nclient = AsyncQdrantClient(url=\"http://localhost:6333\")\n\nawait client.create_collection(\n    collection_name=\"docs\",\n    vectors_config=models.VectorParams(size=4, distance=models.Distance.COSINE),\n)\n\nawait client.upsert(\n    collection_name=\"docs\",\n    points=[\n        models.PointStruct(id=1, vector=[0.1, 0.2, 0.3, 0.4], payload={\"kind\": \"note\"}),\n    ],\n)\n\nresults = await client.query_points(\n    collection_name=\"docs\",\n    query=[0.1, 0.2, 0.3, 0.4],\n    limit=1,\n)\n```\n\nUse the async client in FastAPI, Starlette, or other asyncio apps instead of wrapping the sync client in thread pools.\n\n## Optional Embedded Inference Flow\n\nIf you install the FastEmbed extra, the upstream README shows higher-level document APIs:\n\n```python\nfrom qdrant_client import QdrantClient\n\nclient = QdrantClient(\":memory:\")\n\nclient.add(\n    collection_name=\"demo_collection\",\n    documents=[\n        \"Qdrant has a LangChain integration\",\n        \"Qdrant also has a LlamaIndex integration\",\n    ],\n    metadata=[\n        {\"source\": \"langchain-docs\"},\n        {\"source\": \"llamaindex-docs\"},\n    ],\n    ids=[1, 2],\n)\n\nhits = client.query(\n    collection_name=\"demo_collection\",\n    query_text=\"Which integrations does Qdrant support?\",\n)\n```\n\nUse this only when you intentionally want the client to own embedding generation. If your application already uses a separate embedding model or pipeline, keep embeddings explicit and use `upsert()` plus `query_points()`.\n\n## Auth and Configuration\n\n### Common environment variables\n\n```bash\nexport QDRANT_URL=\"https://YOUR-CLUSTER.cloud.qdrant.io:6333\"\nexport QDRANT_API_KEY=\"YOUR_API_KEY\"\n```\n\n### Token-based auth\n\nThe client constructor supports `auth_token_provider` for bearer token flows that must refresh at runtime.\n\n### Compatibility checks\n\nThe constructor supports `check_compatibility=True` by default. Leave it enabled unless you are intentionally testing against a mismatched server.\n\n### Timeout and transport settings\n\nThe constructor also supports `timeout`, `https`, `host`, `port`, `grpc_port`, and `prefer_grpc`. Pick one connection style and keep it consistent per service.\n\n## Common Pitfalls\n\n- Import path is `qdrant_client`, not `qdrant`.\n- Do not create a collection with the wrong vector dimension. Inserts and searches will fail or behave incorrectly.\n- Do not switch embedding models without checking whether the target collection schema still matches the new vectors.\n- Do not assume local mode behaves like a clustered production deployment. It is mainly for development, tests, and lightweight local persistence.\n- Do not mix `url` and `host` or `port` arguments casually. Prefer one style so the resolved endpoint is obvious.\n- If you enable `prefer_grpc=True`, make sure the server exposes the gRPC port and that your network path allows it.\n- Older examples on blogs may use `search()` heavily. In the current Python client docs, `query_points()` is the generic query entry point to prefer.\n- For bulk ingestion, avoid per-point network round trips. Use `upload_points()` or `upload_collection()`.\n\n## Version-Sensitive Notes for 1.17.0\n\n- PyPI package version covered here is `1.17.0`.\n- PyPI metadata for `1.17.0` requires Python `>=3.10`.\n- The package supports both sync `QdrantClient` and async `AsyncQdrantClient`.\n- The constructor surface in the current official API docs includes local mode, cloud API keys, gRPC preference, compatibility checks, and token-provider auth hooks.\n\n## Official Sources\n\n- Docs root: https://python-client.qdrant.tech/\n- Quickstart: https://python-client.qdrant.tech/quickstart\n- Sync API: https://python-client.qdrant.tech/qdrant_client.qdrant_client\n- Async API: https://python-client.qdrant.tech/qdrant_client.async_qdrant_client\n- PyPI package: https://pypi.org/project/qdrant-client/\n- PyPI JSON metadata: https://pypi.org/pypi/qdrant-client/json\n- GitHub README: https://github.com/qdrant/qdrant-client\n"
  },
  {
    "path": "content/rabbitmq/docs/message-queue/javascript/DOC.md",
    "content": "---\nname: message-queue\ndescription: \"RabbitMQ amqplib coding guidelines for JavaScript/Node.js message broker interactions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.10.9\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"rabbitmq,queue,amqp,messaging,async\"\n---\n\n# RabbitMQ amqplib Coding Guidelines (JavaScript/Node.js)\n\nYou are a RabbitMQ amqplib coding expert. Help me with writing code using RabbitMQ message broker via the official amqplib library.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official amqplib library for all RabbitMQ (AMQP 0-9-1) interactions in Node.js.\n\n- **Library Name:** amqplib\n- **NPM Package:** `amqplib`\n- **Current Version:** 0.10.9 or higher\n- **Minimum Required Version:** 0.10.7+ (for RabbitMQ 4.1.0+ compatibility)\n\n**Installation:**\n\n```bash\nnpm install amqplib\n```\n\n**IMPORTANT:** Do not use the deprecated `amqp` or `node-amqp` packages. Always use `amqplib`.\n\n**Import Patterns:**\n\n```javascript\n// Callback API\nconst amqp = require('amqplib/callback_api');\n\n// Promise/async-await API (recommended)\nconst amqp = require('amqplib');\n\n// ES6 import\nimport amqp from 'amqplib';\n```\n\n## Initialization and Connection\n\n### Environment Variables\n\nConfigure RabbitMQ connection using environment variables:\n\n```javascript\n// .env file\nRABBITMQ_URL=amqp://username:password@localhost:5672\nRABBITMQ_HOST=localhost\nRABBITMQ_PORT=5672\nRABBITMQ_USER=guest\nRABBITMQ_PASS=guest\nRABBITMQ_VHOST=/\n```\n\n### Basic Connection (Promise API)\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function connect() {\n  try {\n    // Using connection URL from environment\n    const connection = await amqp.connect(process.env.RABBITMQ_URL || 'amqp://localhost');\n\n    console.log('Connected to RabbitMQ');\n    return connection;\n  } catch (error) {\n    console.error('Connection failed:', error);\n    throw error;\n  }\n}\n```\n\n### Connection with Options\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function connectWithOptions() {\n  const connection = await amqp.connect({\n    protocol: 'amqp',\n    hostname: process.env.RABBITMQ_HOST || 'localhost',\n    port: parseInt(process.env.RABBITMQ_PORT) || 5672,\n    username: process.env.RABBITMQ_USER || 'guest',\n    password: process.env.RABBITMQ_PASS || 'guest',\n    vhost: process.env.RABBITMQ_VHOST || '/',\n    heartbeat: 30,  // Heartbeat interval in seconds (recommended: 30)\n  });\n\n  return connection;\n}\n```\n\n### Connection with Socket Options\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function connectWithSocketOptions() {\n  const connection = await amqp.connect(\n    process.env.RABBITMQ_URL || 'amqp://localhost',\n    {\n      timeout: 10000,        // Socket timeout in milliseconds\n      noDelay: true,         // Disable Nagle's algorithm\n      keepAlive: true,       // Enable TCP keep-alive\n      keepAliveDelay: 30000  // Keep-alive delay in ms\n    }\n  );\n\n  return connection;\n}\n```\n\n### Callback API Connection\n\n```javascript\nconst amqp = require('amqplib/callback_api');\n\namqp.connect('amqp://localhost', function(error, connection) {\n  if (error) {\n    throw error;\n  }\n  console.log('Connected to RabbitMQ');\n\n  // Use connection here\n});\n```\n\n## Channel API\n\n### Creating a Channel\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function createChannel() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  return { connection, channel };\n}\n```\n\n### Creating a Confirm Channel\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function createConfirmChannel() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createConfirmChannel();\n\n  // Confirm channel provides publisher confirms\n  return { connection, channel };\n}\n```\n\n## Core Messaging Patterns\n\n### 1. Simple Queue - Producer\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function sendMessage(queueName, message) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  // Assert queue exists (create if it doesn't)\n  await channel.assertQueue(queueName, {\n    durable: true  // Queue survives broker restart\n  });\n\n  // Send message\n  channel.sendToQueue(queueName, Buffer.from(message), {\n    persistent: true  // Message survives broker restart\n  });\n\n  console.log(`Sent: ${message}`);\n\n  // Close connection after a delay to ensure message is sent\n  setTimeout(() => {\n    connection.close();\n  }, 500);\n}\n\n// Usage\nsendMessage('task_queue', 'Hello World!');\n```\n\n### 2. Simple Queue - Consumer\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function receiveMessages(queueName) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue(queueName, {\n    durable: true\n  });\n\n  console.log(`Waiting for messages in ${queueName}`);\n\n  // Consume messages\n  channel.consume(queueName, (msg) => {\n    if (msg !== null) {\n      const content = msg.content.toString();\n      console.log(`Received: ${content}`);\n\n      // Acknowledge message\n      channel.ack(msg);\n    }\n  }, {\n    noAck: false  // Manual acknowledgment\n  });\n}\n\n// Usage\nreceiveMessages('task_queue');\n```\n\n### 3. Work Queue with Prefetch\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function worker(queueName) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue(queueName, {\n    durable: true\n  });\n\n  // Fair dispatch - only send one message at a time to each worker\n  channel.prefetch(1);\n\n  console.log(`Worker waiting for tasks in ${queueName}`);\n\n  channel.consume(queueName, async (msg) => {\n    if (msg !== null) {\n      const task = msg.content.toString();\n      console.log(`Processing: ${task}`);\n\n      // Simulate work\n      const workTime = (task.match(/\\./g) || []).length * 1000;\n      await new Promise(resolve => setTimeout(resolve, workTime));\n\n      console.log(`Done: ${task}`);\n      channel.ack(msg);\n    }\n  }, {\n    noAck: false\n  });\n}\n\n// Usage\nworker('task_queue');\n```\n\n### 4. Publish/Subscribe with Fanout Exchange\n\n**Publisher:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function publishLog(message) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'logs';\n\n  await channel.assertExchange(exchange, 'fanout', {\n    durable: false\n  });\n\n  channel.publish(exchange, '', Buffer.from(message));\n  console.log(`Sent: ${message}`);\n\n  setTimeout(() => {\n    connection.close();\n  }, 500);\n}\n\n// Usage\npublishLog('Hello World!');\n```\n\n**Subscriber:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function subscribeLogs() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'logs';\n\n  await channel.assertExchange(exchange, 'fanout', {\n    durable: false\n  });\n\n  // Create exclusive queue (auto-delete when consumer disconnects)\n  const q = await channel.assertQueue('', {\n    exclusive: true\n  });\n\n  console.log(`Waiting for logs. Queue: ${q.queue}`);\n\n  // Bind queue to exchange\n  channel.bindQueue(q.queue, exchange, '');\n\n  channel.consume(q.queue, (msg) => {\n    if (msg !== null) {\n      console.log(`Received: ${msg.content.toString()}`);\n    }\n  }, {\n    noAck: true\n  });\n}\n\n// Usage\nsubscribeLogs();\n```\n\n### 5. Routing with Direct Exchange\n\n**Emitter:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function emitLog(severity, message) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'direct_logs';\n\n  await channel.assertExchange(exchange, 'direct', {\n    durable: false\n  });\n\n  channel.publish(exchange, severity, Buffer.from(message));\n  console.log(`Sent [${severity}]: ${message}`);\n\n  setTimeout(() => {\n    connection.close();\n  }, 500);\n}\n\n// Usage\nemitLog('error', 'Critical system error!');\nemitLog('info', 'System started');\nemitLog('warning', 'Disk space low');\n```\n\n**Receiver:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function receiveLogs(severities) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'direct_logs';\n\n  await channel.assertExchange(exchange, 'direct', {\n    durable: false\n  });\n\n  const q = await channel.assertQueue('', {\n    exclusive: true\n  });\n\n  console.log(`Waiting for logs with severities: ${severities.join(', ')}`);\n\n  // Bind queue for each severity\n  for (const severity of severities) {\n    channel.bindQueue(q.queue, exchange, severity);\n  }\n\n  channel.consume(q.queue, (msg) => {\n    if (msg !== null) {\n      console.log(`[${msg.fields.routingKey}]: ${msg.content.toString()}`);\n    }\n  }, {\n    noAck: true\n  });\n}\n\n// Usage - receive only error and warning logs\nreceiveLogs(['error', 'warning']);\n```\n\n### 6. Topics with Topic Exchange\n\n**Emit Log Topic:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function emitLogTopic(routingKey, message) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'topic_logs';\n\n  await channel.assertExchange(exchange, 'topic', {\n    durable: false\n  });\n\n  channel.publish(exchange, routingKey, Buffer.from(message));\n  console.log(`Sent [${routingKey}]: ${message}`);\n\n  setTimeout(() => {\n    connection.close();\n  }, 500);\n}\n\n// Usage - routing keys with dot-separated words\nemitLogTopic('kern.critical', 'A critical kernel error');\nemitLogTopic('kern.info', 'Kernel information');\nemitLogTopic('auth.warning', 'Authentication warning');\n```\n\n**Receive Log Topic:**\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function receiveLogsTopic(bindingKeys) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const exchange = 'topic_logs';\n\n  await channel.assertExchange(exchange, 'topic', {\n    durable: false\n  });\n\n  const q = await channel.assertQueue('', {\n    exclusive: true\n  });\n\n  console.log(`Waiting for logs matching: ${bindingKeys.join(', ')}`);\n\n  // Bind queue with patterns\n  // * (star) can substitute for exactly one word\n  // # (hash) can substitute for zero or more words\n  for (const key of bindingKeys) {\n    channel.bindQueue(q.queue, exchange, key);\n  }\n\n  channel.consume(q.queue, (msg) => {\n    if (msg !== null) {\n      console.log(`[${msg.fields.routingKey}]: ${msg.content.toString()}`);\n    }\n  }, {\n    noAck: true\n  });\n}\n\n// Usage - pattern matching\nreceiveLogsTopic(['kern.*']);           // All kernel messages\nreceiveLogsTopic(['*.critical']);       // All critical messages\nreceiveLogsTopic(['kern.#']);          // All kern.* messages\nreceiveLogsTopic(['#']);               // All messages\nreceiveLogsTopic(['kern.critical', 'auth.*']); // Multiple patterns\n```\n\n### 7. RPC (Remote Procedure Call) Pattern\n\n**RPC Client:**\n\n```javascript\nconst amqp = require('amqplib');\nconst { v4: uuidv4 } = require('uuid');\n\nclass RPCClient {\n  constructor() {\n    this.connection = null;\n    this.channel = null;\n    this.replyQueue = null;\n    this.responseHandlers = new Map();\n  }\n\n  async connect() {\n    this.connection = await amqp.connect('amqp://localhost');\n    this.channel = await this.connection.createChannel();\n\n    // Create reply queue\n    const q = await this.channel.assertQueue('', {\n      exclusive: true\n    });\n\n    this.replyQueue = q.queue;\n\n    // Consume from reply queue\n    this.channel.consume(this.replyQueue, (msg) => {\n      const correlationId = msg.properties.correlationId;\n      const handler = this.responseHandlers.get(correlationId);\n\n      if (handler) {\n        handler(msg.content.toString());\n        this.responseHandlers.delete(correlationId);\n      }\n    }, {\n      noAck: true\n    });\n  }\n\n  async call(n) {\n    const correlationId = uuidv4();\n\n    return new Promise((resolve) => {\n      // Store response handler\n      this.responseHandlers.set(correlationId, resolve);\n\n      // Send RPC request\n      this.channel.sendToQueue('rpc_queue', Buffer.from(n.toString()), {\n        correlationId: correlationId,\n        replyTo: this.replyQueue\n      });\n    });\n  }\n\n  async close() {\n    await this.connection.close();\n  }\n}\n\n// Usage\nasync function makeRPCCall() {\n  const client = new RPCClient();\n  await client.connect();\n\n  console.log('Requesting fib(30)');\n  const result = await client.call(30);\n  console.log(`Result: ${result}`);\n\n  await client.close();\n}\n\nmakeRPCCall();\n```\n\n**RPC Server:**\n\n```javascript\nconst amqp = require('amqplib');\n\nfunction fibonacci(n) {\n  if (n === 0 || n === 1) return n;\n  return fibonacci(n - 1) + fibonacci(n - 2);\n}\n\nasync function startRPCServer() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  const queue = 'rpc_queue';\n\n  await channel.assertQueue(queue, {\n    durable: false\n  });\n\n  channel.prefetch(1);\n  console.log('Awaiting RPC requests');\n\n  channel.consume(queue, (msg) => {\n    const n = parseInt(msg.content.toString());\n\n    console.log(`Computing fibonacci(${n})`);\n    const result = fibonacci(n);\n\n    // Send response\n    channel.sendToQueue(\n      msg.properties.replyTo,\n      Buffer.from(result.toString()),\n      {\n        correlationId: msg.properties.correlationId\n      }\n    );\n\n    channel.ack(msg);\n  });\n}\n\nstartRPCServer();\n```\n\n## Advanced Configuration\n\n### Message Properties\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function sendWithProperties(queue, message) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue(queue, { durable: true });\n\n  channel.sendToQueue(queue, Buffer.from(message), {\n    persistent: true,                    // Survive broker restart\n    expiration: '60000',                 // Message TTL in milliseconds\n    priority: 5,                         // Message priority (0-255)\n    contentType: 'application/json',     // MIME type\n    contentEncoding: 'utf-8',            // Encoding\n    timestamp: Date.now(),               // Timestamp\n    messageId: 'msg-123',                // Application message ID\n    userId: 'guest',                     // Creating user\n    appId: 'my-app',                     // Application ID\n    headers: {                           // Custom headers\n      'x-custom-header': 'value'\n    }\n  });\n\n  setTimeout(() => connection.close(), 500);\n}\n```\n\n### Queue Options\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function declareQueueWithOptions() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue('advanced_queue', {\n    durable: true,           // Queue survives broker restart\n    exclusive: false,        // Can be accessed by other connections\n    autoDelete: false,       // Queue won't be deleted when no consumers\n    messageTtl: 60000,       // Message TTL in milliseconds\n    expires: 300000,         // Queue expires after 5 minutes of non-use\n    maxLength: 1000,         // Maximum queue length\n    maxPriority: 10,         // Enable priority queue (0-10)\n    deadLetterExchange: 'dlx',          // DLX for rejected messages\n    deadLetterRoutingKey: 'dead.letter' // Routing key for DLX\n  });\n\n  await connection.close();\n}\n```\n\n### Exchange Options\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function declareExchangeWithOptions() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertExchange('advanced_exchange', 'topic', {\n    durable: true,        // Exchange survives broker restart\n    autoDelete: false,    // Exchange won't be deleted when no bindings\n    internal: false,      // Can be published to by clients\n    alternateExchange: 'alternate_exchange'  // AE for unroutable messages\n  });\n\n  await connection.close();\n}\n```\n\n### Dead Letter Queue (DLQ)\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function setupDeadLetterQueue() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  // Declare dead letter exchange\n  await channel.assertExchange('dlx', 'direct', {\n    durable: true\n  });\n\n  // Declare dead letter queue\n  await channel.assertQueue('dead_letter_queue', {\n    durable: true\n  });\n\n  // Bind DLQ to DLX\n  await channel.bindQueue('dead_letter_queue', 'dlx', 'dead.letter');\n\n  // Declare main queue with DLX\n  await channel.assertQueue('main_queue', {\n    durable: true,\n    deadLetterExchange: 'dlx',\n    deadLetterRoutingKey: 'dead.letter',\n    messageTtl: 10000  // Messages expire after 10 seconds\n  });\n\n  console.log('Dead letter queue setup complete');\n  await connection.close();\n}\n\nsetupDeadLetterQueue();\n```\n\n### Consuming from Dead Letter Queue\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function consumeDeadLetters() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue('dead_letter_queue', {\n    durable: true\n  });\n\n  console.log('Waiting for dead letter messages');\n\n  channel.consume('dead_letter_queue', (msg) => {\n    if (msg !== null) {\n      console.log('Dead letter received:', msg.content.toString());\n      console.log('Original routing key:', msg.fields.routingKey);\n      console.log('Death reason:', msg.properties.headers['x-death']);\n\n      // Process or log dead letter\n      channel.ack(msg);\n    }\n  });\n}\n\nconsumeDeadLetters();\n```\n\n### Message Rejection and Requeuing\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function consumerWithRetry() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue('task_queue', {\n    durable: true\n  });\n\n  channel.consume('task_queue', async (msg) => {\n    if (msg !== null) {\n      try {\n        const task = msg.content.toString();\n        console.log('Processing:', task);\n\n        // Simulate processing\n        await processTask(task);\n\n        // Success - acknowledge\n        channel.ack(msg);\n      } catch (error) {\n        console.error('Processing failed:', error);\n\n        // Check retry count\n        const retryCount = (msg.properties.headers?.['x-retry-count'] || 0);\n\n        if (retryCount < 3) {\n          // Reject and requeue for retry\n          channel.nack(msg, false, true);\n        } else {\n          // Max retries reached - reject without requeue (goes to DLQ)\n          channel.nack(msg, false, false);\n        }\n      }\n    }\n  });\n}\n\nasync function processTask(task) {\n  // Simulate work\n  if (Math.random() < 0.3) {\n    throw new Error('Random failure');\n  }\n}\n\nconsumerWithRetry();\n```\n\n### Publisher Confirms\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function publishWithConfirm() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createConfirmChannel();\n\n  const queue = 'confirm_queue';\n  await channel.assertQueue(queue, { durable: true });\n\n  const message = 'Important message';\n\n  try {\n    channel.sendToQueue(queue, Buffer.from(message), {\n      persistent: true\n    });\n\n    // Wait for confirmation\n    await channel.waitForConfirms();\n    console.log('Message confirmed by broker');\n  } catch (error) {\n    console.error('Message nacked by broker:', error);\n  }\n\n  await connection.close();\n}\n\npublishWithConfirm();\n```\n\n### Batch Publishing with Confirms\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function batchPublishWithConfirms() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createConfirmChannel();\n\n  const queue = 'batch_queue';\n  await channel.assertQueue(queue, { durable: true });\n\n  const messages = Array.from({ length: 100 }, (_, i) => `Message ${i}`);\n\n  for (const message of messages) {\n    channel.sendToQueue(queue, Buffer.from(message), {\n      persistent: true\n    });\n  }\n\n  try {\n    await channel.waitForConfirms();\n    console.log('All messages confirmed');\n  } catch (error) {\n    console.error('Some messages were nacked:', error);\n  }\n\n  await connection.close();\n}\n\nbatchPublishWithConfirms();\n```\n\n## Error Handling and Reconnection\n\n### Connection Error Handling\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function connectWithErrorHandling() {\n  let connection;\n\n  try {\n    connection = await amqp.connect('amqp://localhost');\n\n    // Handle connection errors\n    connection.on('error', (err) => {\n      console.error('Connection error:', err);\n    });\n\n    // Handle connection close\n    connection.on('close', () => {\n      console.log('Connection closed');\n      // Implement reconnection logic here\n      setTimeout(() => {\n        console.log('Attempting to reconnect...');\n        connectWithErrorHandling();\n      }, 5000);\n    });\n\n    const channel = await connection.createChannel();\n\n    // Handle channel errors\n    channel.on('error', (err) => {\n      console.error('Channel error:', err);\n    });\n\n    // Handle channel close\n    channel.on('close', () => {\n      console.log('Channel closed');\n    });\n\n    return { connection, channel };\n  } catch (error) {\n    console.error('Failed to connect:', error);\n\n    // Retry connection after delay\n    setTimeout(() => {\n      console.log('Retrying connection...');\n      connectWithErrorHandling();\n    }, 5000);\n  }\n}\n\nconnectWithErrorHandling();\n```\n\n### Robust Connection Manager\n\n```javascript\nconst amqp = require('amqplib');\n\nclass RabbitMQConnection {\n  constructor(url) {\n    this.url = url;\n    this.connection = null;\n    this.channel = null;\n    this.reconnecting = false;\n  }\n\n  async connect() {\n    try {\n      this.connection = await amqp.connect(this.url);\n      this.channel = await this.connection.createChannel();\n\n      console.log('Connected to RabbitMQ');\n\n      this.connection.on('error', (err) => {\n        console.error('Connection error:', err);\n        this.reconnect();\n      });\n\n      this.connection.on('close', () => {\n        console.log('Connection closed');\n        this.reconnect();\n      });\n\n      return this.channel;\n    } catch (error) {\n      console.error('Connection failed:', error);\n      this.reconnect();\n    }\n  }\n\n  async reconnect() {\n    if (this.reconnecting) return;\n\n    this.reconnecting = true;\n    console.log('Reconnecting in 5 seconds...');\n\n    setTimeout(async () => {\n      this.reconnecting = false;\n      await this.connect();\n    }, 5000);\n  }\n\n  async close() {\n    if (this.channel) {\n      await this.channel.close();\n    }\n    if (this.connection) {\n      await this.connection.close();\n    }\n  }\n}\n\n// Usage\nconst manager = new RabbitMQConnection('amqp://localhost');\nconst channel = await manager.connect();\n```\n\n### Graceful Shutdown\n\n```javascript\nconst amqp = require('amqplib');\n\nlet connection = null;\nlet channel = null;\n\nasync function setup() {\n  connection = await amqp.connect('amqp://localhost');\n  channel = await connection.createChannel();\n\n  await channel.assertQueue('shutdown_queue', { durable: true });\n\n  channel.consume('shutdown_queue', (msg) => {\n    if (msg !== null) {\n      console.log('Processing:', msg.content.toString());\n      channel.ack(msg);\n    }\n  });\n}\n\nasync function cleanup() {\n  console.log('Shutting down gracefully...');\n\n  if (channel) {\n    // Cancel consumers\n    await channel.close();\n  }\n\n  if (connection) {\n    await connection.close();\n  }\n\n  console.log('Cleanup complete');\n  process.exit(0);\n}\n\n// Handle shutdown signals\nprocess.on('SIGINT', cleanup);\nprocess.on('SIGTERM', cleanup);\n\nsetup();\n```\n\n## Common Patterns\n\n### Message Retry with Delay\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function setupRetryQueue() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  // Main queue\n  await channel.assertQueue('main_queue', {\n    durable: true,\n    deadLetterExchange: 'retry',\n    deadLetterRoutingKey: 'retry'\n  });\n\n  // Retry exchange\n  await channel.assertExchange('retry', 'direct', {\n    durable: true\n  });\n\n  // Retry queue with delay\n  await channel.assertQueue('retry_queue', {\n    durable: true,\n    messageTtl: 30000,  // 30 second delay\n    deadLetterExchange: '',\n    deadLetterRoutingKey: 'main_queue'\n  });\n\n  await channel.bindQueue('retry_queue', 'retry', 'retry');\n\n  console.log('Retry queue setup complete');\n  await connection.close();\n}\n\nsetupRetryQueue();\n```\n\n### Priority Queue\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function setupPriorityQueue() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  // Queue with priority support\n  await channel.assertQueue('priority_queue', {\n    durable: true,\n    maxPriority: 10\n  });\n\n  // Send messages with different priorities\n  channel.sendToQueue('priority_queue', Buffer.from('Low priority'), {\n    priority: 1\n  });\n\n  channel.sendToQueue('priority_queue', Buffer.from('High priority'), {\n    priority: 10\n  });\n\n  channel.sendToQueue('priority_queue', Buffer.from('Medium priority'), {\n    priority: 5\n  });\n\n  setTimeout(() => connection.close(), 500);\n}\n\nsetupPriorityQueue();\n```\n\n### Rate Limiting Consumer\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function rateLimitedConsumer() {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue('rate_limited_queue', {\n    durable: true\n  });\n\n  // Process only 1 message at a time\n  channel.prefetch(1);\n\n  let processing = false;\n\n  channel.consume('rate_limited_queue', async (msg) => {\n    if (msg !== null && !processing) {\n      processing = true;\n\n      console.log('Processing:', msg.content.toString());\n\n      // Simulate rate-limited processing\n      await new Promise(resolve => setTimeout(resolve, 2000));\n\n      channel.ack(msg);\n      processing = false;\n    }\n  });\n}\n\nrateLimitedConsumer();\n```\n\n### JSON Message Handling\n\n```javascript\nconst amqp = require('amqplib');\n\nasync function sendJSON(queue, data) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue(queue, { durable: true });\n\n  const message = JSON.stringify(data);\n\n  channel.sendToQueue(queue, Buffer.from(message), {\n    contentType: 'application/json',\n    persistent: true\n  });\n\n  console.log('Sent JSON:', data);\n\n  setTimeout(() => connection.close(), 500);\n}\n\nasync function receiveJSON(queue) {\n  const connection = await amqp.connect('amqp://localhost');\n  const channel = await connection.createChannel();\n\n  await channel.assertQueue(queue, { durable: true });\n\n  channel.consume(queue, (msg) => {\n    if (msg !== null) {\n      try {\n        const data = JSON.parse(msg.content.toString());\n        console.log('Received JSON:', data);\n        channel.ack(msg);\n      } catch (error) {\n        console.error('Invalid JSON:', error);\n        channel.nack(msg, false, false);\n      }\n    }\n  });\n}\n\n// Usage\nsendJSON('json_queue', { user: 'john', action: 'login', timestamp: Date.now() });\nreceiveJSON('json_queue');\n```\n\n## Useful Links\n\n- **Official Documentation:** https://www.rabbitmq.com/docs\n- **amqplib GitHub:** https://github.com/amqp-node/amqplib\n- **amqplib API Reference:** https://amqp-node.github.io/amqplib/channel_api.html\n- **RabbitMQ Tutorials:** https://www.rabbitmq.com/tutorials\n- **AMQP 0-9-1 Reference:** https://www.rabbitmq.com/amqp-0-9-1-reference.html\n"
  },
  {
    "path": "content/rabbitmq/docs/message-queue/python/DOC.md",
    "content": "---\nname: message-queue\ndescription: \"RabbitMQ Pika coding guidelines for Python message broker interactions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"rabbitmq,queue,amqp,messaging,async\"\n---\n\n# RabbitMQ Pika Coding Guidelines (Python)\n\nYou are a RabbitMQ Pika coding expert. Help me with writing code using RabbitMQ message broker via the official Pika library.\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Pika library for all RabbitMQ (AMQP 0-9-1) interactions in Python.\n\n- **Library Name:** Pika\n- **PyPI Package:** `pika`\n- **Current Version:** 1.3.2 or higher\n- **Python Support:** Python 3.9+\n\n**Installation:**\n\n```bash\npip install pika\n```\n\n**IMPORTANT:** Pika is the official pure-Python RabbitMQ/AMQP 0-9-1 client library. Do not use deprecated alternatives.\n\n**Import Pattern:**\n\n```python\nimport pika\n```\n\n## Initialization and Connection\n\n### Environment Variables\n\nConfigure RabbitMQ connection using environment variables:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\n# .env file\nRABBITMQ_HOST=localhost\nRABBITMQ_PORT=5672\nRABBITMQ_USER=guest\nRABBITMQ_PASS=guest\nRABBITMQ_VHOST=/\n```\n\n### Basic Connection (Blocking)\n\n```python\nimport pika\n\n# Simple connection to localhost\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nprint(\"Connected to RabbitMQ\")\n```\n\n### Connection with Parameters\n\n```python\nimport pika\nimport os\n\ncredentials = pika.PlainCredentials(\n    username=os.getenv('RABBITMQ_USER', 'guest'),\n    password=os.getenv('RABBITMQ_PASS', 'guest')\n)\n\nparameters = pika.ConnectionParameters(\n    host=os.getenv('RABBITMQ_HOST', 'localhost'),\n    port=int(os.getenv('RABBITMQ_PORT', 5672)),\n    virtual_host=os.getenv('RABBITMQ_VHOST', '/'),\n    credentials=credentials,\n    heartbeat=30,  # Heartbeat interval in seconds\n    blocked_connection_timeout=300\n)\n\nconnection = pika.BlockingConnection(parameters)\nchannel = connection.channel()\n```\n\n### Connection with URL\n\n```python\nimport pika\nimport os\n\n# Connection URL format: amqp://username:password@host:port/vhost\nurl = os.getenv('RABBITMQ_URL', 'amqp://guest:guest@localhost:5672/')\n\nparameters = pika.URLParameters(url)\nconnection = pika.BlockingConnection(parameters)\nchannel = connection.channel()\n```\n\n### Connection Options\n\n```python\nimport pika\n\nparameters = pika.ConnectionParameters(\n    host='localhost',\n    port=5672,\n    virtual_host='/',\n    credentials=pika.PlainCredentials('guest', 'guest'),\n    heartbeat=30,                      # Heartbeat interval in seconds\n    blocked_connection_timeout=300,    # Timeout for blocked connection\n    connection_attempts=3,             # Number of connection attempts\n    retry_delay=2,                     # Delay between retries in seconds\n    socket_timeout=10,                 # Socket timeout in seconds\n    stack_timeout=15,                  # Stack timeout in seconds\n    channel_max=2047,                  # Maximum number of channels\n    frame_max=131072,                  # Maximum frame size\n    locale='en_US'                     # Locale for error messages\n)\n\nconnection = pika.BlockingConnection(parameters)\nchannel = connection.channel()\n```\n\n## Core Messaging Patterns\n\n### 1. Simple Queue - Producer\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare queue (create if it doesn't exist)\nchannel.queue_declare(queue='hello', durable=True)\n\n# Send message\nmessage = 'Hello World!'\nchannel.basic_publish(\n    exchange='',\n    routing_key='hello',\n    body=message,\n    properties=pika.BasicProperties(\n        delivery_mode=pika.DeliveryMode.Persistent  # Make message persistent\n    )\n)\n\nprint(f\"Sent: {message}\")\n\nconnection.close()\n```\n\n### 2. Simple Queue - Consumer\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare queue\nchannel.queue_declare(queue='hello', durable=True)\n\n# Callback function for message processing\ndef callback(ch, method, properties, body):\n    message = body.decode('utf-8')\n    print(f\"Received: {message}\")\n\n    # Acknowledge message\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\n# Consume messages\nchannel.basic_consume(\n    queue='hello',\n    on_message_callback=callback,\n    auto_ack=False  # Manual acknowledgment\n)\n\nprint('Waiting for messages. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n### 3. Work Queue with Prefetch\n\n```python\nimport pika\nimport time\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='task_queue', durable=True)\n\n# Fair dispatch - only send one message at a time\nchannel.basic_qos(prefetch_count=1)\n\ndef callback(ch, method, properties, body):\n    message = body.decode('utf-8')\n    print(f\"Processing: {message}\")\n\n    # Simulate work (one dot = 1 second)\n    time.sleep(message.count('.'))\n\n    print(f\"Done: {message}\")\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\nchannel.basic_consume(\n    queue='task_queue',\n    on_message_callback=callback\n)\n\nprint('Worker waiting for tasks. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n### 4. Publish/Subscribe with Fanout Exchange\n\n**Publisher:**\n\n```python\nimport pika\nimport sys\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare fanout exchange\nchannel.exchange_declare(exchange='logs', exchange_type='fanout')\n\nmessage = ' '.join(sys.argv[1:]) or \"info: Hello World!\"\n\n# Publish to exchange\nchannel.basic_publish(\n    exchange='logs',\n    routing_key='',  # Ignored for fanout exchange\n    body=message\n)\n\nprint(f\"Sent: {message}\")\nconnection.close()\n```\n\n**Subscriber:**\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare exchange\nchannel.exchange_declare(exchange='logs', exchange_type='fanout')\n\n# Create exclusive queue (auto-delete when consumer disconnects)\nresult = channel.queue_declare(queue='', exclusive=True)\nqueue_name = result.method.queue\n\n# Bind queue to exchange\nchannel.queue_bind(exchange='logs', queue=queue_name)\n\nprint(f'Waiting for logs. Queue: {queue_name}')\n\ndef callback(ch, method, properties, body):\n    print(f\"Received: {body.decode('utf-8')}\")\n\nchannel.basic_consume(\n    queue=queue_name,\n    on_message_callback=callback,\n    auto_ack=True\n)\n\nchannel.start_consuming()\n```\n\n### 5. Routing with Direct Exchange\n\n**Emitter:**\n\n```python\nimport pika\nimport sys\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare direct exchange\nchannel.exchange_declare(exchange='direct_logs', exchange_type='direct')\n\nseverity = sys.argv[1] if len(sys.argv) > 1 else 'info'\nmessage = ' '.join(sys.argv[2:]) or 'Hello World!'\n\n# Publish with routing key\nchannel.basic_publish(\n    exchange='direct_logs',\n    routing_key=severity,\n    body=message\n)\n\nprint(f\"Sent [{severity}]: {message}\")\nconnection.close()\n```\n\n**Receiver:**\n\n```python\nimport pika\nimport sys\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.exchange_declare(exchange='direct_logs', exchange_type='direct')\n\nresult = channel.queue_declare(queue='', exclusive=True)\nqueue_name = result.method.queue\n\n# Severities to listen for\nseverities = sys.argv[1:] if len(sys.argv) > 1 else ['error', 'warning']\n\n# Bind queue for each severity\nfor severity in severities:\n    channel.queue_bind(\n        exchange='direct_logs',\n        queue=queue_name,\n        routing_key=severity\n    )\n\nprint(f'Waiting for logs with severities: {\", \".join(severities)}')\n\ndef callback(ch, method, properties, body):\n    print(f\"[{method.routing_key}]: {body.decode('utf-8')}\")\n\nchannel.basic_consume(\n    queue=queue_name,\n    on_message_callback=callback,\n    auto_ack=True\n)\n\nchannel.start_consuming()\n```\n\n### 6. Topics with Topic Exchange\n\n**Emit Log Topic:**\n\n```python\nimport pika\nimport sys\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare topic exchange\nchannel.exchange_declare(exchange='topic_logs', exchange_type='topic')\n\nrouting_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'\nmessage = ' '.join(sys.argv[2:]) or 'Hello World!'\n\nchannel.basic_publish(\n    exchange='topic_logs',\n    routing_key=routing_key,\n    body=message\n)\n\nprint(f\"Sent [{routing_key}]: {message}\")\nconnection.close()\n```\n\n**Receive Log Topic:**\n\n```python\nimport pika\nimport sys\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.exchange_declare(exchange='topic_logs', exchange_type='topic')\n\nresult = channel.queue_declare(queue='', exclusive=True)\nqueue_name = result.method.queue\n\n# Binding keys with pattern matching\n# * (star) substitutes for exactly one word\n# # (hash) substitutes for zero or more words\nbinding_keys = sys.argv[1:] if len(sys.argv) > 1 else ['#']\n\nfor binding_key in binding_keys:\n    channel.queue_bind(\n        exchange='topic_logs',\n        queue=queue_name,\n        routing_key=binding_key\n    )\n\nprint(f'Waiting for logs matching: {\", \".join(binding_keys)}')\n\ndef callback(ch, method, properties, body):\n    print(f\"[{method.routing_key}]: {body.decode('utf-8')}\")\n\nchannel.basic_consume(\n    queue=queue_name,\n    on_message_callback=callback,\n    auto_ack=True\n)\n\nchannel.start_consuming()\n```\n\n### 7. RPC (Remote Procedure Call) Pattern\n\n**RPC Client:**\n\n```python\nimport pika\nimport uuid\n\nclass FibonacciRpcClient:\n    def __init__(self):\n        self.connection = pika.BlockingConnection(\n            pika.ConnectionParameters('localhost')\n        )\n        self.channel = self.connection.channel()\n\n        # Declare callback queue\n        result = self.channel.queue_declare(queue='', exclusive=True)\n        self.callback_queue = result.method.queue\n\n        self.channel.basic_consume(\n            queue=self.callback_queue,\n            on_message_callback=self.on_response,\n            auto_ack=True\n        )\n\n        self.response = None\n        self.corr_id = None\n\n    def on_response(self, ch, method, props, body):\n        if self.corr_id == props.correlation_id:\n            self.response = body\n\n    def call(self, n):\n        self.response = None\n        self.corr_id = str(uuid.uuid4())\n\n        self.channel.basic_publish(\n            exchange='',\n            routing_key='rpc_queue',\n            properties=pika.BasicProperties(\n                reply_to=self.callback_queue,\n                correlation_id=self.corr_id\n            ),\n            body=str(n)\n        )\n\n        # Wait for response\n        self.connection.process_data_events(time_limit=None)\n        while self.response is None:\n            self.connection.process_data_events(time_limit=None)\n\n        return int(self.response)\n\n    def close(self):\n        self.connection.close()\n\n# Usage\nfibonacci_rpc = FibonacciRpcClient()\n\nprint(\"Requesting fib(30)\")\nresponse = fibonacci_rpc.call(30)\nprint(f\"Result: {response}\")\n\nfibonacci_rpc.close()\n```\n\n**RPC Server:**\n\n```python\nimport pika\n\ndef fib(n):\n    if n == 0:\n        return 0\n    elif n == 1:\n        return 1\n    else:\n        return fib(n - 1) + fib(n - 2)\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='rpc_queue')\n\ndef on_request(ch, method, props, body):\n    n = int(body)\n    print(f\"Computing fib({n})\")\n\n    response = fib(n)\n\n    # Send response\n    ch.basic_publish(\n        exchange='',\n        routing_key=props.reply_to,\n        properties=pika.BasicProperties(\n            correlation_id=props.correlation_id\n        ),\n        body=str(response)\n    )\n\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\nchannel.basic_qos(prefetch_count=1)\nchannel.basic_consume(queue='rpc_queue', on_message_callback=on_request)\n\nprint(\"Awaiting RPC requests\")\nchannel.start_consuming()\n```\n\n## Advanced Configuration\n\n### Message Properties\n\n```python\nimport pika\nimport time\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='advanced_queue', durable=True)\n\nmessage = 'Important message'\n\n# Comprehensive message properties\nproperties = pika.BasicProperties(\n    delivery_mode=pika.DeliveryMode.Persistent,  # Message persistence\n    priority=5,                                   # Message priority (0-255)\n    content_type='text/plain',                    # MIME type\n    content_encoding='utf-8',                     # Encoding\n    expiration='60000',                           # TTL in milliseconds\n    message_id='msg-123',                         # Application message ID\n    timestamp=int(time.time()),                   # Timestamp\n    type='notification',                          # Message type\n    user_id='guest',                              # Creating user\n    app_id='my-app',                              # Application ID\n    headers={                                     # Custom headers\n        'x-custom-header': 'value',\n        'retry-count': 0\n    }\n)\n\nchannel.basic_publish(\n    exchange='',\n    routing_key='advanced_queue',\n    body=message,\n    properties=properties\n)\n\nconnection.close()\n```\n\n### Queue Options\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Queue with advanced options\nchannel.queue_declare(\n    queue='advanced_queue',\n    durable=True,              # Queue survives broker restart\n    exclusive=False,           # Can be accessed by other connections\n    auto_delete=False,         # Queue won't auto-delete\n    arguments={\n        'x-message-ttl': 60000,                # Message TTL in milliseconds\n        'x-expires': 300000,                   # Queue expires after 5 minutes\n        'x-max-length': 1000,                  # Maximum queue length\n        'x-max-priority': 10,                  # Enable priority queue (0-10)\n        'x-dead-letter-exchange': 'dlx',       # Dead letter exchange\n        'x-dead-letter-routing-key': 'dead.letter',  # DLX routing key\n        'x-queue-mode': 'lazy'                 # Lazy queue mode\n    }\n)\n\nconnection.close()\n```\n\n### Exchange Options\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Exchange with advanced options\nchannel.exchange_declare(\n    exchange='advanced_exchange',\n    exchange_type='topic',\n    durable=True,           # Exchange survives broker restart\n    auto_delete=False,      # Exchange won't auto-delete\n    internal=False,         # Can be published to by clients\n    arguments={\n        'alternate-exchange': 'alternate_exchange'  # AE for unroutable messages\n    }\n)\n\nconnection.close()\n```\n\n### Dead Letter Queue (DLQ)\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Declare dead letter exchange\nchannel.exchange_declare(exchange='dlx', exchange_type='direct', durable=True)\n\n# Declare dead letter queue\nchannel.queue_declare(queue='dead_letter_queue', durable=True)\n\n# Bind DLQ to DLX\nchannel.queue_bind(\n    queue='dead_letter_queue',\n    exchange='dlx',\n    routing_key='dead.letter'\n)\n\n# Declare main queue with DLX\nchannel.queue_declare(\n    queue='main_queue',\n    durable=True,\n    arguments={\n        'x-dead-letter-exchange': 'dlx',\n        'x-dead-letter-routing-key': 'dead.letter',\n        'x-message-ttl': 10000  # Messages expire after 10 seconds\n    }\n)\n\nprint(\"Dead letter queue setup complete\")\nconnection.close()\n```\n\n### Consuming from Dead Letter Queue\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='dead_letter_queue', durable=True)\n\ndef callback(ch, method, properties, body):\n    print(f\"Dead letter received: {body.decode('utf-8')}\")\n    print(f\"Original routing key: {method.routing_key}\")\n\n    # Check death reason\n    if properties.headers and 'x-death' in properties.headers:\n        print(f\"Death reason: {properties.headers['x-death']}\")\n\n    # Process or log dead letter\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\nchannel.basic_consume(\n    queue='dead_letter_queue',\n    on_message_callback=callback\n)\n\nprint('Waiting for dead letter messages. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n### Message Rejection and Requeuing\n\n```python\nimport pika\nimport random\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='task_queue', durable=True)\nchannel.basic_qos(prefetch_count=1)\n\ndef callback(ch, method, properties, body):\n    try:\n        message = body.decode('utf-8')\n        print(f\"Processing: {message}\")\n\n        # Simulate processing with potential failure\n        if random.random() < 0.3:\n            raise Exception('Random failure')\n\n        # Success - acknowledge\n        ch.basic_ack(delivery_tag=method.delivery_tag)\n\n    except Exception as e:\n        print(f\"Processing failed: {e}\")\n\n        # Check retry count\n        retry_count = 0\n        if properties.headers and 'x-retry-count' in properties.headers:\n            retry_count = properties.headers['x-retry-count']\n\n        if retry_count < 3:\n            # Reject and requeue for retry\n            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)\n        else:\n            # Max retries reached - reject without requeue (goes to DLQ)\n            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)\n\nchannel.basic_consume(\n    queue='task_queue',\n    on_message_callback=callback\n)\n\nprint('Consumer with retry waiting for tasks. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n### Publisher Confirms\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Enable publisher confirms\nchannel.confirm_delivery()\n\nchannel.queue_declare(queue='confirm_queue', durable=True)\n\nmessage = 'Important message'\n\ntry:\n    channel.basic_publish(\n        exchange='',\n        routing_key='confirm_queue',\n        body=message,\n        properties=pika.BasicProperties(\n            delivery_mode=pika.DeliveryMode.Persistent\n        ),\n        mandatory=True\n    )\n    print(\"Message confirmed by broker\")\nexcept pika.exceptions.UnroutableError:\n    print(\"Message was returned (unroutable)\")\nexcept pika.exceptions.NackError:\n    print(\"Message was nacked by broker\")\n\nconnection.close()\n```\n\n### Batch Publishing with Confirms\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.confirm_delivery()\nchannel.queue_declare(queue='batch_queue', durable=True)\n\nmessages = [f'Message {i}' for i in range(100)]\n\nconfirmed = 0\nnacked = 0\n\nfor message in messages:\n    try:\n        channel.basic_publish(\n            exchange='',\n            routing_key='batch_queue',\n            body=message,\n            properties=pika.BasicProperties(\n                delivery_mode=pika.DeliveryMode.Persistent\n            )\n        )\n        confirmed += 1\n    except (pika.exceptions.UnroutableError, pika.exceptions.NackError):\n        nacked += 1\n\nprint(f\"Confirmed: {confirmed}, Nacked: {nacked}\")\nconnection.close()\n```\n\n## Error Handling and Reconnection\n\n### Connection Error Handling\n\n```python\nimport pika\nimport time\n\ndef connect_rabbitmq():\n    while True:\n        try:\n            connection = pika.BlockingConnection(\n                pika.ConnectionParameters('localhost')\n            )\n            channel = connection.channel()\n            print(\"Connected to RabbitMQ\")\n            return connection, channel\n\n        except pika.exceptions.AMQPConnectionError as e:\n            print(f\"Connection failed: {e}\")\n            print(\"Retrying in 5 seconds...\")\n            time.sleep(5)\n\n# Usage\nconnection, channel = connect_rabbitmq()\n```\n\n### Robust Connection Manager\n\n```python\nimport pika\nimport time\nimport logging\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\nclass RabbitMQConnection:\n    def __init__(self, host='localhost', max_retries=5, retry_delay=5):\n        self.host = host\n        self.max_retries = max_retries\n        self.retry_delay = retry_delay\n        self.connection = None\n        self.channel = None\n\n    def connect(self):\n        retries = 0\n\n        while retries < self.max_retries:\n            try:\n                self.connection = pika.BlockingConnection(\n                    pika.ConnectionParameters(self.host)\n                )\n                self.channel = self.connection.channel()\n                logger.info(\"Connected to RabbitMQ\")\n                return self.channel\n\n            except pika.exceptions.AMQPConnectionError as e:\n                retries += 1\n                logger.error(f\"Connection failed (attempt {retries}/{self.max_retries}): {e}\")\n\n                if retries < self.max_retries:\n                    logger.info(f\"Retrying in {self.retry_delay} seconds...\")\n                    time.sleep(self.retry_delay)\n                else:\n                    logger.error(\"Max retries reached. Giving up.\")\n                    raise\n\n    def close(self):\n        if self.connection and not self.connection.is_closed:\n            self.connection.close()\n            logger.info(\"Connection closed\")\n\n# Usage\nmanager = RabbitMQConnection(host='localhost', max_retries=5)\nchannel = manager.connect()\n\n# Use channel...\n\nmanager.close()\n```\n\n### Graceful Shutdown\n\n```python\nimport pika\nimport signal\nimport sys\n\nconnection = None\nchannel = None\n\ndef setup():\n    global connection, channel\n\n    connection = pika.BlockingConnection(\n        pika.ConnectionParameters('localhost')\n    )\n    channel = connection.channel()\n\n    channel.queue_declare(queue='shutdown_queue', durable=True)\n\n    channel.basic_consume(\n        queue='shutdown_queue',\n        on_message_callback=callback\n    )\n\ndef callback(ch, method, properties, body):\n    print(f\"Processing: {body.decode('utf-8')}\")\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\ndef cleanup(sig, frame):\n    print(\"\\nShutting down gracefully...\")\n\n    if channel and channel.is_open:\n        channel.stop_consuming()\n        channel.close()\n\n    if connection and connection.is_open:\n        connection.close()\n\n    print(\"Cleanup complete\")\n    sys.exit(0)\n\n# Register signal handlers\nsignal.signal(signal.SIGINT, cleanup)\nsignal.signal(signal.SIGTERM, cleanup)\n\nsetup()\nprint('Waiting for messages. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n## Common Patterns\n\n### Message Retry with Delay\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Main queue\nchannel.queue_declare(\n    queue='main_queue',\n    durable=True,\n    arguments={\n        'x-dead-letter-exchange': 'retry',\n        'x-dead-letter-routing-key': 'retry'\n    }\n)\n\n# Retry exchange\nchannel.exchange_declare(exchange='retry', exchange_type='direct', durable=True)\n\n# Retry queue with delay\nchannel.queue_declare(\n    queue='retry_queue',\n    durable=True,\n    arguments={\n        'x-message-ttl': 30000,  # 30 second delay\n        'x-dead-letter-exchange': '',\n        'x-dead-letter-routing-key': 'main_queue'\n    }\n)\n\nchannel.queue_bind(queue='retry_queue', exchange='retry', routing_key='retry')\n\nprint(\"Retry queue setup complete\")\nconnection.close()\n```\n\n### Priority Queue\n\n```python\nimport pika\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\n# Queue with priority support\nchannel.queue_declare(\n    queue='priority_queue',\n    durable=True,\n    arguments={'x-max-priority': 10}\n)\n\n# Send messages with different priorities\nmessages = [\n    ('Low priority', 1),\n    ('High priority', 10),\n    ('Medium priority', 5)\n]\n\nfor message, priority in messages:\n    channel.basic_publish(\n        exchange='',\n        routing_key='priority_queue',\n        body=message,\n        properties=pika.BasicProperties(priority=priority)\n    )\n\nprint(\"Priority messages sent\")\nconnection.close()\n```\n\n### Rate Limiting Consumer\n\n```python\nimport pika\nimport time\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='rate_limited_queue', durable=True)\n\n# Process only 1 message at a time\nchannel.basic_qos(prefetch_count=1)\n\ndef callback(ch, method, properties, body):\n    print(f\"Processing: {body.decode('utf-8')}\")\n\n    # Simulate rate-limited processing (2 seconds delay)\n    time.sleep(2)\n\n    ch.basic_ack(delivery_tag=method.delivery_tag)\n\nchannel.basic_consume(\n    queue='rate_limited_queue',\n    on_message_callback=callback\n)\n\nprint('Rate-limited consumer started. Press CTRL+C to exit.')\nchannel.start_consuming()\n```\n\n### JSON Message Handling\n\n```python\nimport pika\nimport json\n\nconnection = pika.BlockingConnection(\n    pika.ConnectionParameters('localhost')\n)\nchannel = connection.channel()\n\nchannel.queue_declare(queue='json_queue', durable=True)\n\n# Send JSON message\ndata = {\n    'user': 'john',\n    'action': 'login',\n    'timestamp': 1609459200\n}\n\nmessage = json.dumps(data)\n\nchannel.basic_publish(\n    exchange='',\n    routing_key='json_queue',\n    body=message,\n    properties=pika.BasicProperties(\n        content_type='application/json',\n        delivery_mode=pika.DeliveryMode.Persistent\n    )\n)\n\nprint(f\"Sent JSON: {data}\")\n\n# Receive JSON message\ndef callback(ch, method, properties, body):\n    try:\n        data = json.loads(body)\n        print(f\"Received JSON: {data}\")\n        ch.basic_ack(delivery_tag=method.delivery_tag)\n    except json.JSONDecodeError as e:\n        print(f\"Invalid JSON: {e}\")\n        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)\n\nchannel.basic_consume(\n    queue='json_queue',\n    on_message_callback=callback\n)\n\n# channel.start_consuming()  # Uncomment to start consuming\nconnection.close()\n```\n\n## Async Usage with Select Connection\n\n### Async Producer\n\n```python\nimport pika\n\ndef on_open(connection):\n    connection.channel(on_open_callback=on_channel_open)\n\ndef on_channel_open(channel):\n    channel.queue_declare(\n        queue='async_queue',\n        durable=True,\n        callback=lambda method: on_queue_declared(channel)\n    )\n\ndef on_queue_declared(channel):\n    message = 'Hello Async World!'\n\n    channel.basic_publish(\n        exchange='',\n        routing_key='async_queue',\n        body=message,\n        properties=pika.BasicProperties(\n            delivery_mode=pika.DeliveryMode.Persistent\n        )\n    )\n\n    print(f\"Sent: {message}\")\n    channel.connection.close()\n\n# Create async connection\nparameters = pika.ConnectionParameters('localhost')\nconnection = pika.SelectConnection(parameters, on_open_callback=on_open)\n\ntry:\n    connection.ioloop.start()\nexcept KeyboardInterrupt:\n    connection.close()\n    connection.ioloop.start()\n```\n\n### Async Consumer\n\n```python\nimport pika\n\nclass AsyncConsumer:\n    def __init__(self, queue_name):\n        self.queue_name = queue_name\n        self.connection = None\n        self.channel = None\n\n    def connect(self):\n        parameters = pika.ConnectionParameters('localhost')\n        return pika.SelectConnection(\n            parameters,\n            on_open_callback=self.on_connection_open\n        )\n\n    def on_connection_open(self, connection):\n        self.connection = connection\n        self.connection.channel(on_open_callback=self.on_channel_open)\n\n    def on_channel_open(self, channel):\n        self.channel = channel\n        self.channel.queue_declare(\n            queue=self.queue_name,\n            durable=True,\n            callback=self.on_queue_declared\n        )\n\n    def on_queue_declared(self, method):\n        self.channel.basic_qos(prefetch_count=1)\n        self.channel.basic_consume(\n            queue=self.queue_name,\n            on_message_callback=self.on_message\n        )\n        print(f'Waiting for messages in {self.queue_name}')\n\n    def on_message(self, ch, method, properties, body):\n        print(f\"Received: {body.decode('utf-8')}\")\n        ch.basic_ack(delivery_tag=method.delivery_tag)\n\n    def run(self):\n        self.connection = self.connect()\n        try:\n            self.connection.ioloop.start()\n        except KeyboardInterrupt:\n            self.connection.close()\n            self.connection.ioloop.start()\n\n# Usage\nconsumer = AsyncConsumer('async_queue')\nconsumer.run()\n```\n\n## Useful Links\n\n- **Official Documentation:** https://www.rabbitmq.com/docs\n- **Pika Documentation:** https://pika.readthedocs.io/\n- **Pika GitHub:** https://github.com/pika/pika\n- **RabbitMQ Tutorials (Python):** https://www.rabbitmq.com/tutorials\n- **AMQP 0-9-1 Reference:** https://www.rabbitmq.com/amqp-0-9-1-reference.html\n"
  },
  {
    "path": "content/rasterio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Rasterio Python package guide for reading, writing, windowing, masking, reprojection, and cloud raster access\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"rasterio,python,gdal,gis,raster,geotiff,geospatial\"\n---\n\n# Rasterio Python Package Guide\n\n## Golden Rule\n\nUse `rasterio` as the Python layer over GDAL for raster files, keep dataset access inside `with rasterio.open(...)` blocks, and derive output metadata from `src.profile` or `src.meta` instead of rebuilding raster dimensions, CRS, dtype, and transform by hand.\n\nAs of 2026-03-12, PyPI and the upstream GitHub release are on `1.5.0`, but `https://rasterio.readthedocs.io/en/stable/` is still labeled `1.4.4`. Treat the docs site as the main usage guide and the `1.5.0` release notes as the source of truth for version-specific changes.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"rasterio==1.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"rasterio==1.5.0\"\npoetry add \"rasterio==1.5.0\"\n```\n\nUseful extras published on PyPI:\n\n```bash\npython -m pip install \"rasterio[s3]==1.5.0\"\npython -m pip install \"rasterio[plot]==1.5.0\"\npython -m pip install \"rasterio[all]==1.5.0\"\n```\n\nInstallation notes:\n\n- PyPI wheels are the easiest path for simple applications and include many built-in drivers, but the official installation guide warns they are not tested against every other binary wheel, conda package, or QGIS stack.\n- If your environment already has a GIS stack and binary compatibility matters more than convenience, `conda-forge` or a source build against your existing GDAL may be safer.\n- Source builds need a compatible GDAL installation. The docs still show `gdal-config`-based builds; for `1.5.0`, align with the newer package baseline of Python 3.12+, GDAL 3.8+, and NumPy 2+.\n\n## Core Usage\n\n### Open a dataset and inspect metadata\n\n`rasterio.open()` returns a dataset object. Read metadata from attributes and arrays with `read()`.\n\n```python\nimport rasterio\n\nwith rasterio.open(\"example.tif\") as src:\n    print(src.name)\n    print(src.count, src.width, src.height)\n    print(src.crs)\n    print(src.transform)\n    print(src.bounds)\n\n    band1 = src.read(1)\n    masked_band1 = src.read(1, masked=True)\n```\n\nNotes:\n\n- Band indexes are 1-based, not 0-based.\n- `src.read()` returns an array shaped `(count, height, width)`.\n- `masked=True` is usually the safest read mode when nodata handling matters.\n\n### Write a derived raster\n\nThe official profiles guide recommends copying `src.profile`, updating only the fields that changed, and passing that profile back into `rasterio.open(..., \"w\", **profile)`.\n\n```python\nimport numpy as np\nimport rasterio\n\nwith rasterio.open(\"input.tif\") as src:\n    data = src.read().astype(\"float32\")\n    mean_band = data.mean(axis=0, dtype=\"float32\")\n\n    profile = src.profile.copy()\n    profile.update(\n        driver=\"GTiff\",\n        count=1,\n        dtype=\"float32\",\n        compress=\"deflate\",\n    )\n\n    with rasterio.open(\"mean.tif\", \"w\", **profile) as dst:\n        dst.write(mean_band, 1)\n```\n\nWhen output dimensions or georeferencing change, also update `width`, `height`, `transform`, and sometimes `crs`.\n\n### Read or write only a window\n\nUse windows to work on rasters larger than RAM or to process chunks in parallel.\n\n```python\nimport rasterio\nfrom rasterio.windows import Window\n\nwindow = Window(col_off=0, row_off=0, width=512, height=512)\n\nwith rasterio.open(\"big.tif\") as src:\n    tile = src.read(1, window=window, masked=True)\n    tile_transform = src.window_transform(window)\n```\n\nWindowing notes:\n\n- Windows are pixel subsets defined by offsets plus width and height.\n- Tiny windows do not guarantee tiny I/O. Rasterio reads full underlying GDAL blocks, so tiled rasters are much more efficient for window-heavy workloads.\n\n### Mask by geometry\n\nUse `rasterio.mask.mask()` when you need to crop to polygons or zero out pixels outside shapes.\n\n```python\nimport rasterio\nfrom rasterio.mask import mask\n\ngeometries = [\n    {\n        \"type\": \"Polygon\",\n        \"coordinates\": [[\n            (-123.3, 44.0),\n            (-123.3, 43.8),\n            (-123.0, 43.8),\n            (-123.0, 44.0),\n            (-123.3, 44.0),\n        ]],\n    }\n]\n\nwith rasterio.open(\"input.tif\") as src:\n    data, transform = mask(src, geometries, crop=True)\n    profile = src.profile.copy()\n    profile.update(\n        height=data.shape[1],\n        width=data.shape[2],\n        transform=transform,\n    )\n\n    with rasterio.open(\"clipped.tif\", \"w\", **profile) as dst:\n        dst.write(data)\n```\n\nWith `crop=True`, shape and transform change. Update them before writing output.\n\n### Reproject to another CRS\n\n`rasterio.warp.calculate_default_transform()` and `reproject()` are the standard path for GeoTIFF reprojection.\n\n```python\nimport rasterio\nfrom rasterio.warp import calculate_default_transform, reproject, Resampling\n\ndst_crs = \"EPSG:4326\"\n\nwith rasterio.open(\"input.tif\") as src:\n    transform, width, height = calculate_default_transform(\n        src.crs, dst_crs, src.width, src.height, *src.bounds\n    )\n\n    profile = src.profile.copy()\n    profile.update(\n        crs=dst_crs,\n        transform=transform,\n        width=width,\n        height=height,\n    )\n\n    with rasterio.open(\"reprojected.tif\", \"w\", **profile) as dst:\n        for band_index in range(1, src.count + 1):\n            reproject(\n                source=rasterio.band(src, band_index),\n                destination=rasterio.band(dst, band_index),\n                src_transform=src.transform,\n                src_crs=src.crs,\n                dst_transform=transform,\n                dst_crs=dst_crs,\n                resampling=Resampling.nearest,\n            )\n```\n\n## Configuration And Cloud Access\n\n### Use `rasterio.Env()` for GDAL and cloud settings\n\nRasterio wraps GDAL's global state with `rasterio.Env(...)`. Use it when you need GDAL config options, custom sessions, or cloud credentials.\n\n```python\nimport rasterio\n\nwith rasterio.Env(GDAL_CACHEMAX=128_000_000):\n    with rasterio.open(\"example.tif\") as src:\n        arr = src.read(1)\n```\n\nFor AWS-backed datasets, `Env` can take a session or AWS credential arguments and profile settings.\n\n```python\nimport rasterio\n\nwith rasterio.Env(profile_name=\"default\"):\n    with rasterio.open(\"s3://my-bucket/path/to/image.tif\") as src:\n        print(src.profile)\n```\n\n### Remote files and virtual filesystems\n\nRasterio maps normal URI schemes to GDAL virtual filesystems. Prefer standard URIs over raw `/vsi...` paths.\n\n```python\nimport rasterio\n\nwith rasterio.open(\"https://example.com/data/image.tif\") as src:\n    arr = src.read(1)\n\nwith rasterio.open(\"zip+https://example.com/archive/files.zip!image.tif\") as src:\n    arr = src.read(1)\n```\n\nS3 support is optional and requires the `s3` extra:\n\n```bash\npython -m pip install \"rasterio[s3]==1.5.0\"\n```\n\n### Use `MemoryFile` for bytes in memory\n\n`MemoryFile` is useful when your input is already in bytes from a network response or another in-memory source.\n\n```python\nimport requests\nfrom rasterio.io import MemoryFile\n\nresponse = requests.get(\"https://example.com/image.tif\", timeout=30)\nresponse.raise_for_status()\n\nwith MemoryFile(response.content) as memfile:\n    with memfile.open() as src:\n        arr = src.read(1)\n```\n\nImportant: a `MemoryFile` created from existing bytes cannot be extended later. Empty `MemoryFile()` instances and byte-initialized ones are different modes.\n\n## Common Pitfalls\n\n- Do not rebuild output metadata from scratch unless necessary. Start from `src.profile.copy()` and then update only what changed.\n- Remember that Rasterio band indexes are 1-based. `src.read(1)` is the first band.\n- `crop=True` in `rasterio.mask.mask()` changes extent, shape, and transform. If you write the result back out, update those fields in the destination profile.\n- Windowed reads operate at the raster block level. If the file is not tiled, small windows can still trigger large reads.\n- Base `pip install rasterio` does not include S3 extras. Install `rasterio[s3]` before assuming `s3://...` support works cleanly.\n- Keep file access inside context managers. Dataset handles own GDAL resources and should be closed promptly.\n- If you mix Rasterio wheels with a separately managed GIS stack, binary compatibility issues can look like runtime import errors or missing drivers rather than obvious install failures.\n- When writing arrays, ensure `dtype`, `count`, and band shapes match the destination profile. Silent mismatches are a common source of corrupted outputs or write errors.\n\n## Version-Sensitive Notes For `1.5.0`\n\n- `1.5.0` is the current PyPI release as of 2026-03-12 and was released on 2026-01-05.\n- The minimum supported versions were raised to Python 3.12+, GDAL 3.8+, and NumPy 2+.\n- The `1.5.0` release adds `float16` dtype support.\n- `rasterio.open()` gained a `thread_safe` parameter in `1.5.0`. If you are copying concurrency advice from older examples, re-check it against the current API and release notes.\n- `rasterio.warp.reproject()` now exposes `tolerance` as an argument, which matters if you tune warp precision.\n- Official wheels for `1.5.0` use GDAL `3.12.1`.\n- The stable docs site still shows `1.4.4`, so when a detail appears stale, prefer PyPI metadata and the `1.5.0` release notes over the docs page header.\n\n## Official Links\n\n- Docs root: `https://rasterio.readthedocs.io/en/stable/`\n- Installation: `https://rasterio.readthedocs.io/en/stable/installation.html`\n- Quickstart: `https://rasterio.readthedocs.io/en/stable/quickstart.html`\n- Profiles and writing: `https://rasterio.readthedocs.io/en/stable/topics/profiles.html`\n- Windowed I/O: `https://rasterio.readthedocs.io/en/stable/topics/windowed-rw.html`\n- Masking: `https://rasterio.readthedocs.io/en/stable/topics/masking-by-shapefile.html`\n- Reprojection: `https://rasterio.readthedocs.io/en/stable/topics/reproject.html`\n- GDAL/AWS environment API: `https://rasterio.readthedocs.io/en/stable/api/rasterio.env.html`\n- Virtual filesystems: `https://rasterio.readthedocs.io/en/stable/topics/vsi.html`\n- In-memory files: `https://rasterio.readthedocs.io/en/stable/topics/memory-files.html`\n- PyPI package: `https://pypi.org/project/rasterio/`\n- `1.5.0` release notes: `https://github.com/rasterio/rasterio/releases/tag/1.5.0`\n"
  },
  {
    "path": "content/ray/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Ray for Python: distributed tasks, actors, cluster connection, runtime environments, and jobs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.54.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ray,python,distributed-computing,parallelism,actors,tasks,clusters\"\n---\n\n# Ray Python Package Guide\n\n## What Ray Is For\n\n`ray` is a Python-first distributed execution framework. Use it when you need to:\n\n- parallelize Python functions with Ray tasks\n- keep state in distributed workers with Ray actors\n- scale the same code from local development to a Ray cluster\n- package code and Python dependencies for remote execution with `runtime_env`\n\nThe Python import is:\n\n```python\nimport ray\n```\n\n## Install\n\nUse the base package unless you specifically need the dashboard, cluster launcher, or higher-level libraries:\n\n```bash\npip install -U ray\n```\n\nUseful extras from the official install guide:\n\n```bash\npip install -U \"ray[default]\"\npip install -U \"ray[data]\"\npip install -U \"ray[train]\"\npip install -U \"ray[tune]\"\npip install -U \"ray[serve]\"\npip install -U \"ray[all]\"\n```\n\nNotes for `2.54.0`:\n\n- PyPI lists `Requires: Python >=3.10`.\n- The install docs list Python `3.10` through `3.13` as supported for prebuilt wheels.\n- Native Windows support is still marked beta, and multi-node support on Windows is not well tested.\n\n## Initialize Ray\n\n### Local runtime\n\nUse plain `ray.init()` during development or when you want a local in-process Ray runtime:\n\n```python\nimport ray\n\nray.init()\n\n@ray.remote\ndef square(x: int) -> int:\n    return x * x\n\nresult = ray.get(square.remote(12))\nprint(result)\n\nray.shutdown()\n```\n\n### Attach to an existing cluster\n\nIf a cluster is already running, connect explicitly instead of accidentally starting a new local runtime:\n\n```python\nimport ray\n\nray.init(address=\"auto\")\n```\n\nFor Ray Client connections, use the `ray://` scheme:\n\n```python\nimport ray\n\nray.init(\"ray://ray-head.example.com:10001\")\n```\n\nIf you need a quick local cluster for testing, the official CLI path is:\n\n```bash\nray start --head\n```\n\nThen connect with `ray.init(address=\"auto\")`.\n\n## Core Usage Patterns\n\n### Stateless parallel work with tasks\n\nDecorate a function with `@ray.remote`, call `.remote(...)`, and resolve the returned `ObjectRef` with `ray.get(...)`:\n\n```python\nimport ray\n\nray.init()\n\n@ray.remote\ndef transform(x: int) -> int:\n    return x * 10\n\nrefs = [transform.remote(i) for i in range(5)]\nresults = ray.get(refs)\nprint(results)  # [0, 10, 20, 30, 40]\n```\n\nTask options are set with `.options(...)` before `.remote(...)`:\n\n```python\nfast_ref = transform.options(num_cpus=1).remote(7)\nprint(ray.get(fast_ref))\n```\n\n### Stateful workers with actors\n\nUse actors when state must live on the worker:\n\n```python\nimport ray\n\nray.init()\n\n@ray.remote\nclass Counter:\n    def __init__(self):\n        self.value = 0\n\n    def increment(self):\n        self.value += 1\n        return self.value\n\ncounter = Counter.remote()\nprint(ray.get(counter.increment.remote()))  # 1\nprint(ray.get(counter.increment.remote()))  # 2\n```\n\n### Share large objects through the object store\n\nAvoid closing over large Python values in every task. Put them once, then pass the `ObjectRef`:\n\n```python\nimport ray\n\nray.init()\n\nlarge_lookup = {str(i): i for i in range(100_000)}\nlookup_ref = ray.put(large_lookup)\n\n@ray.remote\ndef read_key(table, key):\n    return table[key]\n\nprint(ray.get(read_key.remote(lookup_ref, \"42\")))\n```\n\n## Dependencies and Runtime Environment\n\nRemote workers need access to your code and Python dependencies. Ray’s `runtime_env` is the official way to package that execution environment.\n\nCommon pattern:\n\n```python\nimport ray\n\nray.init(\n    runtime_env={\n        \"working_dir\": \".\",\n        \"pip\": [\"requests==2.32.5\", \"pydantic>=2,<3\"],\n    }\n)\n```\n\nPractical guidance:\n\n- Use `working_dir` so workers can import your local project code.\n- Use `pip` in `runtime_env` for packages that are not already installed on every node.\n- Keep remote functions and actor classes importable from normal Python modules. Top-level definitions are safer than nested closures.\n- If you are already using a cluster image or container with dependencies preinstalled, keep `runtime_env` minimal and use it only for per-job differences.\n\n## Config and Auth\n\n### Address and cluster selection\n\nBe explicit about where code should run:\n\n- `ray.init()` starts or attaches to a local runtime.\n- `ray.init(address=\"auto\")` attaches to an already running cluster discovered from the local environment.\n- `ray.init(\"ray://host:10001\")` uses Ray Client to connect to a remote cluster.\n\n### Dashboard and jobs endpoint\n\nThe docs use `http://127.0.0.1:8265` as the default dashboard and jobs endpoint. That surface is commonly used for Ray Jobs submission and cluster inspection.\n\n### Token auth for jobs and dashboard APIs\n\nLocal development usually has no auth layer. For shared or remote clusters, newer Ray releases support token authentication for job and dashboard APIs.\n\nIf token auth is enabled on the cluster, the official docs show these environment variables:\n\n```bash\nexport RAY_JOB_HEADERS='{\"Authorization\": \"Bearer <token>\"}'\nexport RAY_AUTH_TOKEN=\"<token>\"\n```\n\nUse those only when the cluster is configured for auth. They are not required for a default local setup.\n\n## Common Pitfalls\n\n- `ObjectRef` is not the result value. Call `ray.get(...)` before using the actual data.\n- `ray.init()` without an explicit address can hide cluster-connection mistakes by starting a local runtime instead.\n- Workers do not automatically inherit all local imports or files. Use `runtime_env`, package your code properly, or preinstall dependencies on every node.\n- Large captured objects make tasks slower to serialize and schedule. Use `ray.put(...)`, files, or object storage instead of repeatedly closing over large data.\n- Actor methods are invoked with `.remote()`, just like tasks. `counter.increment()` is a normal Python method call and will not run remotely.\n- Re-running cells or scripts without cleanup can leave old Ray state around. `ray.shutdown()` is the safe reset when iterating locally.\n\n## Version-Sensitive Notes for `2.54.0`\n\n- The canonical docs root `https://docs.ray.io/en/latest/` currently serves the Ray `2.54.0` docs.\n- PyPI for `ray 2.54.0` requires Python `>=3.10`.\n- The install guide says support for Pydantic v1 will be dropped in Ray `2.56`, so prefer Pydantic v2-compatible code paths now.\n- Dashboard and jobs token auth is documented as available starting in Ray `2.52.0`; if you are upgrading older cluster tooling, check those auth assumptions explicitly.\n\n## Official Sources\n\n- Docs root: https://docs.ray.io/en/latest/\n- Installation: https://docs.ray.io/en/latest/ray-overview/installation.html\n- Getting started / tasks / actors: https://docs.ray.io/en/latest/ray-overview/getting-started.html\n- `ray.init()` API: https://docs.ray.io/en/latest/ray-core/api/doc/ray.init.html\n- Runtime environments: https://docs.ray.io/en/latest/ray-core/handling-dependencies.html\n- Ray Client: https://docs.ray.io/en/latest/cluster/running-applications/job-submission/ray-client.html\n- Jobs and dashboard auth: https://docs.ray.io/en/latest/cluster/running-applications/job-submission/security.html\n- PyPI package: https://pypi.org/project/ray/2.54.0/\n"
  },
  {
    "path": "content/razorpay/docs/payments/javascript/DOC.md",
    "content": "---\nname: payments\ndescription: \"Razorpay Node.js SDK coding guidelines for building payment systems with orders, payments, refunds, and subscriptions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.9.6\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"razorpay,payments,india,checkout,upi\"\n---\n\n# Razorpay Node.js Coding Guidelines\n\nYou are a Razorpay payment gateway coding expert. Help me with writing code using the Razorpay Node.js SDK for building payment systems with orders, payments, refunds, subscriptions, customers, and invoices.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://razorpay.com/docs/payments/server-integration/nodejs/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Razorpay Node.js SDK, which is the standard library for all Razorpay API interactions.\n\n**Library Name:** Razorpay Node.js SDK\n**NPM Package:** `razorpay`\n**Current Version:** 2.9.6\n**Supported Node.js Versions:** Node.js 10+\n\n**Installation:**\n- **Correct:** `npm install razorpay` or `yarn add razorpay`\n\n**APIs and Usage:**\n- **Correct:** `const Razorpay = require('razorpay')`\n- **Correct:** `const instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_KEY_SECRET' })`\n- **Correct:** `instance.orders.create({...})` for creating orders\n- **Correct:** `instance.payments.fetch(paymentId)` for fetching payments\n- **Incorrect:** Using unofficial Razorpay libraries or wrappers\n- **Incorrect:** Exposing credentials in front-end applications\n\n## Authentication and Initialization\n\nThe Razorpay Node.js library requires your Key ID and Key Secret for authentication. You can obtain these from the Razorpay Dashboard at Settings > API Keys.\n\n### Environment Variables (Recommended)\n\nSet up environment variables for secure credential management:\n\n```javascript\n// Load environment variables\nrequire('dotenv').config();\n\n// Initialize Razorpay instance\nconst Razorpay = require('razorpay');\n\nconst instance = new Razorpay({\n  key_id: process.env.RAZORPAY_KEY_ID,\n  key_secret: process.env.RAZORPAY_KEY_SECRET\n});\n```\n\n### Direct Initialization\n\n```javascript\nconst Razorpay = require('razorpay');\n\nconst instance = new Razorpay({\n  key_id: 'rzp_test_xxxxxxxxxx',\n  key_secret: 'your_key_secret_here'\n});\n```\n\n### Client Configuration Options\n\n```javascript\nconst instance = new Razorpay({\n  key_id: process.env.RAZORPAY_KEY_ID,\n  key_secret: process.env.RAZORPAY_KEY_SECRET,\n  headers: {\n    'X-Razorpay-Account': 'acc_xxxxxxxxxxxxx'  // Optional: For partner integrations\n  }\n});\n```\n\n## Orders API\n\n### Create Order\n\nCreate an order before accepting payments from customers:\n\n```javascript\nconst Razorpay = require('razorpay');\nconst instance = new Razorpay({\n  key_id: process.env.RAZORPAY_KEY_ID,\n  key_secret: process.env.RAZORPAY_KEY_SECRET\n});\n\nasync function createOrder() {\n  try {\n    const options = {\n      amount: 50000,  // Amount in paise (50000 paise = ₹500)\n      currency: \"INR\",\n      receipt: \"receipt_order_12345\",\n      notes: {\n        key1: \"value1\",\n        key2: \"value2\"\n      }\n    };\n\n    const order = await instance.orders.create(options);\n    console.log('Order ID:', order.id);\n    console.log('Order:', order);\n    return order;\n  } catch (error) {\n    console.error('Error creating order:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Order Details\n\n```javascript\nasync function fetchOrder(orderId) {\n  try {\n    const order = await instance.orders.fetch(orderId);\n    console.log('Order details:', order);\n    return order;\n  } catch (error) {\n    console.error('Error fetching order:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Orders\n\n```javascript\nasync function fetchAllOrders() {\n  try {\n    const options = {\n      count: 10,           // Number of orders to fetch (default: 10, max: 100)\n      skip: 0,             // Number of orders to skip (for pagination)\n      from: 1640995200,    // Unix timestamp (fetch orders from this time)\n      to: 1672531199       // Unix timestamp (fetch orders till this time)\n    };\n\n    const orders = await instance.orders.all(options);\n    console.log('Orders:', orders);\n    return orders;\n  } catch (error) {\n    console.error('Error fetching orders:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Payments for an Order\n\n```javascript\nasync function fetchOrderPayments(orderId) {\n  try {\n    const payments = await instance.orders.fetchPayments(orderId);\n    console.log('Payments for order:', payments);\n    return payments;\n  } catch (error) {\n    console.error('Error fetching order payments:', error);\n    throw error;\n  }\n}\n```\n\n## Payments API\n\n### Fetch Payment Details\n\n```javascript\nasync function fetchPayment(paymentId) {\n  try {\n    const payment = await instance.payments.fetch(paymentId);\n    console.log('Payment details:', payment);\n    return payment;\n  } catch (error) {\n    console.error('Error fetching payment:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Payments\n\n```javascript\nasync function fetchAllPayments() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0,\n      from: 1640995200,\n      to: 1672531199\n    };\n\n    const payments = await instance.payments.all(options);\n    console.log('Payments:', payments);\n    return payments;\n  } catch (error) {\n    console.error('Error fetching payments:', error);\n    throw error;\n  }\n}\n```\n\n### Capture Payment\n\nCapture an authorized payment:\n\n```javascript\nasync function capturePayment(paymentId, amount) {\n  try {\n    const payment = await instance.payments.capture(paymentId, amount, \"INR\");\n    console.log('Payment captured:', payment);\n    return payment;\n  } catch (error) {\n    console.error('Error capturing payment:', error);\n    throw error;\n  }\n}\n```\n\n### Update Payment\n\n```javascript\nasync function updatePayment(paymentId) {\n  try {\n    const notes = {\n      notes: {\n        note_key_1: \"updated value 1\",\n        note_key_2: \"updated value 2\"\n      }\n    };\n\n    const payment = await instance.payments.edit(paymentId, notes);\n    console.log('Payment updated:', payment);\n    return payment;\n  } catch (error) {\n    console.error('Error updating payment:', error);\n    throw error;\n  }\n}\n```\n\n## Refunds API\n\n### Create Refund\n\n```javascript\nasync function createRefund(paymentId) {\n  try {\n    const options = {\n      amount: 10000,  // Amount in paise to refund\n      speed: \"normal\",  // \"normal\" or \"optimum\"\n      notes: {\n        notes_key_1: \"Refund reason\"\n      },\n      receipt: \"Receipt No. 31\"\n    };\n\n    const refund = await instance.payments.refund(paymentId, options);\n    console.log('Refund created:', refund);\n    return refund;\n  } catch (error) {\n    console.error('Error creating refund:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Refund Details\n\n```javascript\nasync function fetchRefund(paymentId, refundId) {\n  try {\n    const refund = await instance.payments.fetchRefund(paymentId, refundId);\n    console.log('Refund details:', refund);\n    return refund;\n  } catch (error) {\n    console.error('Error fetching refund:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Refunds for a Payment\n\n```javascript\nasync function fetchPaymentRefunds(paymentId) {\n  try {\n    const refunds = await instance.payments.fetchMultipleRefund(paymentId);\n    console.log('Refunds:', refunds);\n    return refunds;\n  } catch (error) {\n    console.error('Error fetching refunds:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Refunds\n\n```javascript\nasync function fetchAllRefunds() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0,\n      from: 1640995200,\n      to: 1672531199\n    };\n\n    const refunds = await instance.refunds.all(options);\n    console.log('All refunds:', refunds);\n    return refunds;\n  } catch (error) {\n    console.error('Error fetching all refunds:', error);\n    throw error;\n  }\n}\n```\n\n## Customers API\n\n### Create Customer\n\n```javascript\nasync function createCustomer() {\n  try {\n    const customerData = {\n      name: \"John Doe\",\n      email: \"john.doe@example.com\",\n      contact: \"+919876543210\",\n      fail_existing: 0,  // 0 to return existing customer if exists, 1 to fail\n      notes: {\n        customer_type: \"premium\"\n      }\n    };\n\n    const customer = await instance.customers.create(customerData);\n    console.log('Customer created:', customer);\n    return customer;\n  } catch (error) {\n    console.error('Error creating customer:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Customer Details\n\n```javascript\nasync function fetchCustomer(customerId) {\n  try {\n    const customer = await instance.customers.fetch(customerId);\n    console.log('Customer details:', customer);\n    return customer;\n  } catch (error) {\n    console.error('Error fetching customer:', error);\n    throw error;\n  }\n}\n```\n\n### Update Customer\n\n```javascript\nasync function updateCustomer(customerId) {\n  try {\n    const updates = {\n      name: \"Jane Doe\",\n      email: \"jane.doe@example.com\",\n      contact: \"+919876543211\"\n    };\n\n    const customer = await instance.customers.edit(customerId, updates);\n    console.log('Customer updated:', customer);\n    return customer;\n  } catch (error) {\n    console.error('Error updating customer:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Customers\n\n```javascript\nasync function fetchAllCustomers() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0\n    };\n\n    const customers = await instance.customers.all(options);\n    console.log('Customers:', customers);\n    return customers;\n  } catch (error) {\n    console.error('Error fetching customers:', error);\n    throw error;\n  }\n}\n```\n\n## Subscriptions API\n\n### Create Subscription\n\n```javascript\nasync function createSubscription() {\n  try {\n    const subscriptionData = {\n      plan_id: \"plan_xxxxxxxxxxxxx\",\n      customer_notify: 1,\n      quantity: 1,\n      total_count: 12,\n      start_at: Math.floor(Date.now() / 1000) + 86400,  // Start after 1 day\n      addons: [\n        {\n          item: {\n            name: \"Extra Storage\",\n            amount: 5000,\n            currency: \"INR\"\n          }\n        }\n      ],\n      notes: {\n        subscription_type: \"premium\"\n      }\n    };\n\n    const subscription = await instance.subscriptions.create(subscriptionData);\n    console.log('Subscription created:', subscription);\n    return subscription;\n  } catch (error) {\n    console.error('Error creating subscription:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Subscription Details\n\n```javascript\nasync function fetchSubscription(subscriptionId) {\n  try {\n    const subscription = await instance.subscriptions.fetch(subscriptionId);\n    console.log('Subscription details:', subscription);\n    return subscription;\n  } catch (error) {\n    console.error('Error fetching subscription:', error);\n    throw error;\n  }\n}\n```\n\n### Cancel Subscription\n\n```javascript\nasync function cancelSubscription(subscriptionId) {\n  try {\n    const options = {\n      cancel_at_cycle_end: 0  // 0 to cancel immediately, 1 to cancel at end of cycle\n    };\n\n    const subscription = await instance.subscriptions.cancel(subscriptionId, options);\n    console.log('Subscription cancelled:', subscription);\n    return subscription;\n  } catch (error) {\n    console.error('Error cancelling subscription:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Subscriptions\n\n```javascript\nasync function fetchAllSubscriptions() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0\n    };\n\n    const subscriptions = await instance.subscriptions.all(options);\n    console.log('Subscriptions:', subscriptions);\n    return subscriptions;\n  } catch (error) {\n    console.error('Error fetching subscriptions:', error);\n    throw error;\n  }\n}\n```\n\n## Plans API\n\n### Create Plan\n\n```javascript\nasync function createPlan() {\n  try {\n    const planData = {\n      period: \"monthly\",\n      interval: 1,\n      item: {\n        name: \"Premium Plan\",\n        amount: 99900,  // Amount in paise\n        currency: \"INR\",\n        description: \"Premium monthly subscription\"\n      },\n      notes: {\n        plan_type: \"premium\"\n      }\n    };\n\n    const plan = await instance.plans.create(planData);\n    console.log('Plan created:', plan);\n    return plan;\n  } catch (error) {\n    console.error('Error creating plan:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Plan Details\n\n```javascript\nasync function fetchPlan(planId) {\n  try {\n    const plan = await instance.plans.fetch(planId);\n    console.log('Plan details:', plan);\n    return plan;\n  } catch (error) {\n    console.error('Error fetching plan:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Plans\n\n```javascript\nasync function fetchAllPlans() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0\n    };\n\n    const plans = await instance.plans.all(options);\n    console.log('Plans:', plans);\n    return plans;\n  } catch (error) {\n    console.error('Error fetching plans:', error);\n    throw error;\n  }\n}\n```\n\n## Invoices API\n\n### Create Invoice\n\n```javascript\nasync function createInvoice() {\n  try {\n    const invoiceData = {\n      type: \"invoice\",\n      description: \"Invoice for the month of January 2025\",\n      customer: {\n        name: \"John Doe\",\n        email: \"john.doe@example.com\",\n        contact: \"+919876543210\"\n      },\n      line_items: [\n        {\n          name: \"Premium Subscription\",\n          description: \"Monthly subscription\",\n          amount: 99900,\n          currency: \"INR\",\n          quantity: 1\n        }\n      ],\n      currency: \"INR\",\n      email_notify: 1,\n      sms_notify: 1,\n      date: Math.floor(Date.now() / 1000)\n    };\n\n    const invoice = await instance.invoices.create(invoiceData);\n    console.log('Invoice created:', invoice);\n    return invoice;\n  } catch (error) {\n    console.error('Error creating invoice:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Invoice Details\n\n```javascript\nasync function fetchInvoice(invoiceId) {\n  try {\n    const invoice = await instance.invoices.fetch(invoiceId);\n    console.log('Invoice details:', invoice);\n    return invoice;\n  } catch (error) {\n    console.error('Error fetching invoice:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch All Invoices\n\n```javascript\nasync function fetchAllInvoices() {\n  try {\n    const options = {\n      count: 10,\n      skip: 0\n    };\n\n    const invoices = await instance.invoices.all(options);\n    console.log('Invoices:', invoices);\n    return invoices;\n  } catch (error) {\n    console.error('Error fetching invoices:', error);\n    throw error;\n  }\n}\n```\n\n### Cancel Invoice\n\n```javascript\nasync function cancelInvoice(invoiceId) {\n  try {\n    const invoice = await instance.invoices.cancel(invoiceId);\n    console.log('Invoice cancelled:', invoice);\n    return invoice;\n  } catch (error) {\n    console.error('Error cancelling invoice:', error);\n    throw error;\n  }\n}\n```\n\n## Payment Verification\n\n### Verify Payment Signature\n\nVerify payment signatures to ensure payment authenticity:\n\n```javascript\nconst crypto = require('crypto');\nconst { validatePaymentVerification } = require('razorpay/dist/utils/razorpay-utils');\n\n// Method 1: Using Razorpay's built-in utility\nfunction verifyPaymentSignature(orderId, paymentId, signature) {\n  try {\n    const isValid = validatePaymentVerification(\n      { order_id: orderId, payment_id: paymentId },\n      signature,\n      process.env.RAZORPAY_KEY_SECRET\n    );\n\n    if (isValid) {\n      console.log('Payment signature verified successfully');\n      return true;\n    } else {\n      console.log('Invalid payment signature');\n      return false;\n    }\n  } catch (error) {\n    console.error('Error verifying payment signature:', error);\n    return false;\n  }\n}\n\n// Method 2: Manual verification\nfunction verifyPaymentSignatureManual(orderId, paymentId, signature) {\n  try {\n    const generatedSignature = crypto\n      .createHmac('sha256', process.env.RAZORPAY_KEY_SECRET)\n      .update(`${orderId}|${paymentId}`)\n      .digest('hex');\n\n    const isValid = generatedSignature === signature;\n\n    if (isValid) {\n      console.log('Payment signature verified successfully');\n      return true;\n    } else {\n      console.log('Invalid payment signature');\n      return false;\n    }\n  } catch (error) {\n    console.error('Error verifying payment signature:', error);\n    return false;\n  }\n}\n```\n\n## Webhook Handling and Validation\n\n### Express.js Webhook Integration\n\nHandle and validate incoming Razorpay webhooks:\n\n```javascript\nconst express = require('express');\nconst crypto = require('crypto');\nconst { validateWebhookSignature } = require('razorpay/dist/utils/razorpay-utils');\n\nconst app = express();\n\n// IMPORTANT: Use express.text() to get raw body for webhook signature validation\napp.use(express.json({\n  verify: (req, res, buf) => {\n    req.rawBody = buf.toString();\n  }\n}));\n\n// Webhook validation middleware\nfunction validateWebhook(req, res, next) {\n  const signature = req.headers['x-razorpay-signature'];\n  const webhookSecret = process.env.RAZORPAY_WEBHOOK_SECRET;\n\n  try {\n    const isValid = validateWebhookSignature(\n      req.rawBody,\n      signature,\n      webhookSecret\n    );\n\n    if (!isValid) {\n      return res.status(400).json({ error: 'Invalid signature' });\n    }\n\n    next();\n  } catch (error) {\n    console.error('Webhook validation error:', error);\n    return res.status(400).json({ error: 'Webhook validation failed' });\n  }\n}\n\n// Webhook endpoint\napp.post('/webhook', validateWebhook, (req, res) => {\n  const event = req.body;\n\n  console.log('Webhook event:', event.event);\n\n  switch (event.event) {\n    case 'payment.authorized':\n      handlePaymentAuthorized(event.payload.payment.entity);\n      break;\n\n    case 'payment.captured':\n      handlePaymentCaptured(event.payload.payment.entity);\n      break;\n\n    case 'payment.failed':\n      handlePaymentFailed(event.payload.payment.entity);\n      break;\n\n    case 'order.paid':\n      handleOrderPaid(event.payload.order.entity);\n      break;\n\n    case 'refund.created':\n      handleRefundCreated(event.payload.refund.entity);\n      break;\n\n    case 'subscription.activated':\n      handleSubscriptionActivated(event.payload.subscription.entity);\n      break;\n\n    case 'subscription.cancelled':\n      handleSubscriptionCancelled(event.payload.subscription.entity);\n      break;\n\n    case 'invoice.paid':\n      handleInvoicePaid(event.payload.invoice.entity);\n      break;\n\n    default:\n      console.log('Unhandled event:', event.event);\n  }\n\n  res.json({ status: 'ok' });\n});\n\nfunction handlePaymentAuthorized(payment) {\n  console.log('Payment authorized:', payment.id);\n  // Capture the payment or perform other actions\n}\n\nfunction handlePaymentCaptured(payment) {\n  console.log('Payment captured:', payment.id);\n  // Update order status, send confirmation email, etc.\n}\n\nfunction handlePaymentFailed(payment) {\n  console.log('Payment failed:', payment.id);\n  // Notify customer, update order status, etc.\n}\n\nfunction handleOrderPaid(order) {\n  console.log('Order paid:', order.id);\n  // Process order fulfillment\n}\n\nfunction handleRefundCreated(refund) {\n  console.log('Refund created:', refund.id);\n  // Update records, notify customer\n}\n\nfunction handleSubscriptionActivated(subscription) {\n  console.log('Subscription activated:', subscription.id);\n  // Grant access to subscription features\n}\n\nfunction handleSubscriptionCancelled(subscription) {\n  console.log('Subscription cancelled:', subscription.id);\n  // Revoke access, send cancellation email\n}\n\nfunction handleInvoicePaid(invoice) {\n  console.log('Invoice paid:', invoice.id);\n  // Update invoice status, send receipt\n}\n\napp.listen(3000, () => {\n  console.log('Webhook server listening on port 3000');\n});\n```\n\n### Manual Webhook Signature Validation\n\n```javascript\nconst crypto = require('crypto');\n\nfunction validateWebhookManual(webhookBody, signature, secret) {\n  try {\n    const generatedSignature = crypto\n      .createHmac('sha256', secret)\n      .update(webhookBody)\n      .digest('hex');\n\n    return generatedSignature === signature;\n  } catch (error) {\n    console.error('Error validating webhook:', error);\n    return false;\n  }\n}\n\n// Usage\napp.post('/webhook', (req, res) => {\n  const signature = req.headers['x-razorpay-signature'];\n  const isValid = validateWebhookManual(\n    req.rawBody,\n    signature,\n    process.env.RAZORPAY_WEBHOOK_SECRET\n  );\n\n  if (!isValid) {\n    return res.status(400).json({ error: 'Invalid signature' });\n  }\n\n  // Process webhook event\n  res.json({ status: 'ok' });\n});\n```\n\n## Transfers API (Route)\n\n### Create Transfer\n\nTransfer funds to linked accounts:\n\n```javascript\nasync function createTransfer(paymentId) {\n  try {\n    const transferData = {\n      transfers: [\n        {\n          account: \"acc_xxxxxxxxxxxxx\",\n          amount: 10000,  // Amount in paise\n          currency: \"INR\",\n          notes: {\n            name: \"Transfer to vendor\",\n            roll_no: \"IEC2011025\"\n          },\n          linked_account_notes: [\"branch\"],\n          on_hold: 0,  // 0 to transfer immediately, 1 to hold\n          on_hold_until: null\n        }\n      ]\n    };\n\n    const transfer = await instance.payments.transfer(paymentId, transferData);\n    console.log('Transfer created:', transfer);\n    return transfer;\n  } catch (error) {\n    console.error('Error creating transfer:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Transfer Details\n\n```javascript\nasync function fetchTransfer(transferId) {\n  try {\n    const transfer = await instance.transfers.fetch(transferId);\n    console.log('Transfer details:', transfer);\n    return transfer;\n  } catch (error) {\n    console.error('Error fetching transfer:', error);\n    throw error;\n  }\n}\n```\n\n## Virtual Accounts API\n\n### Create Virtual Account\n\n```javascript\nasync function createVirtualAccount() {\n  try {\n    const vaData = {\n      receivers: {\n        types: [\"bank_account\"]\n      },\n      description: \"Virtual Account for customer XYZ\",\n      customer_id: \"cust_xxxxxxxxxxxxx\",\n      close_by: Math.floor(Date.now() / 1000) + 86400 * 30,  // Close after 30 days\n      notes: {\n        purpose: \"Rent collection\"\n      }\n    };\n\n    const virtualAccount = await instance.virtualAccounts.create(vaData);\n    console.log('Virtual Account created:', virtualAccount);\n    return virtualAccount;\n  } catch (error) {\n    console.error('Error creating virtual account:', error);\n    throw error;\n  }\n}\n```\n\n### Fetch Virtual Account Details\n\n```javascript\nasync function fetchVirtualAccount(vaId) {\n  try {\n    const virtualAccount = await instance.virtualAccounts.fetch(vaId);\n    console.log('Virtual Account details:', virtualAccount);\n    return virtualAccount;\n  } catch (error) {\n    console.error('Error fetching virtual account:', error);\n    throw error;\n  }\n}\n```\n\n## Error Handling\n\n### Comprehensive Error Handling\n\n```javascript\nasync function safeApiCall() {\n  try {\n    const order = await instance.orders.create({\n      amount: 50000,\n      currency: \"INR\",\n      receipt: \"receipt_12345\"\n    });\n\n    return {\n      success: true,\n      data: order\n    };\n  } catch (error) {\n    console.error('Razorpay API Error:', {\n      statusCode: error.statusCode,\n      error: error.error,\n      description: error.error?.description,\n      field: error.error?.field,\n      reason: error.error?.reason\n    });\n\n    return {\n      success: false,\n      error: {\n        code: error.statusCode,\n        message: error.error?.description || 'An error occurred',\n        field: error.error?.field\n      }\n    };\n  }\n}\n```\n\n### Common Error Codes\n\nHandle specific error scenarios:\n\n```javascript\nasync function handleErrors() {\n  try {\n    const payment = await instance.payments.fetch('pay_xxxxxxxxxxxxx');\n    return payment;\n  } catch (error) {\n    switch (error.statusCode) {\n      case 400:\n        console.error('Bad Request - Invalid parameters');\n        break;\n      case 401:\n        console.error('Unauthorized - Invalid API credentials');\n        break;\n      case 404:\n        console.error('Not Found - Resource does not exist');\n        break;\n      case 500:\n        console.error('Internal Server Error - Razorpay issue');\n        break;\n      default:\n        console.error('Unknown error:', error);\n    }\n    throw error;\n  }\n}\n```\n\n## Complete Payment Flow Example\n\n### Server-Side Integration\n\n```javascript\nconst express = require('express');\nconst Razorpay = require('razorpay');\nconst crypto = require('crypto');\nconst { validatePaymentVerification } = require('razorpay/dist/utils/razorpay-utils');\n\nconst app = express();\napp.use(express.json());\n\nconst instance = new Razorpay({\n  key_id: process.env.RAZORPAY_KEY_ID,\n  key_secret: process.env.RAZORPAY_KEY_SECRET\n});\n\n// Step 1: Create order\napp.post('/create-order', async (req, res) => {\n  try {\n    const { amount, currency, receipt } = req.body;\n\n    const options = {\n      amount: amount * 100,  // Convert to paise\n      currency: currency || 'INR',\n      receipt: receipt || `receipt_${Date.now()}`,\n      notes: {\n        description: 'Order payment'\n      }\n    };\n\n    const order = await instance.orders.create(options);\n\n    res.json({\n      success: true,\n      order: {\n        id: order.id,\n        amount: order.amount,\n        currency: order.currency\n      },\n      key_id: process.env.RAZORPAY_KEY_ID\n    });\n  } catch (error) {\n    console.error('Error creating order:', error);\n    res.status(500).json({\n      success: false,\n      message: 'Failed to create order'\n    });\n  }\n});\n\n// Step 2: Verify payment\napp.post('/verify-payment', async (req, res) => {\n  try {\n    const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;\n\n    const isValid = validatePaymentVerification(\n      { order_id: razorpay_order_id, payment_id: razorpay_payment_id },\n      razorpay_signature,\n      process.env.RAZORPAY_KEY_SECRET\n    );\n\n    if (isValid) {\n      // Payment is successful, update database\n      const payment = await instance.payments.fetch(razorpay_payment_id);\n\n      res.json({\n        success: true,\n        message: 'Payment verified successfully',\n        payment: {\n          id: payment.id,\n          amount: payment.amount,\n          status: payment.status\n        }\n      });\n    } else {\n      res.status(400).json({\n        success: false,\n        message: 'Payment verification failed'\n      });\n    }\n  } catch (error) {\n    console.error('Error verifying payment:', error);\n    res.status(500).json({\n      success: false,\n      message: 'Payment verification error'\n    });\n  }\n});\n\n// Step 3: Fetch payment details\napp.get('/payment/:id', async (req, res) => {\n  try {\n    const payment = await instance.payments.fetch(req.params.id);\n    res.json({\n      success: true,\n      payment\n    });\n  } catch (error) {\n    console.error('Error fetching payment:', error);\n    res.status(500).json({\n      success: false,\n      message: 'Failed to fetch payment'\n    });\n  }\n});\n\napp.listen(3000, () => {\n  console.log('Server running on port 3000');\n});\n```\n\n## Security Best Practices\n\n### Never Expose Credentials\n\n```javascript\n// Good - Use environment variables\nconst instance = new Razorpay({\n  key_id: process.env.RAZORPAY_KEY_ID,\n  key_secret: process.env.RAZORPAY_KEY_SECRET\n});\n\n// Bad - Hardcoded credentials\nconst instance = new Razorpay({\n  key_id: 'rzp_test_xxxxxxxxxxxx',\n  key_secret: 'your_secret_here'\n});\n```\n\n### Always Validate Webhooks\n\n```javascript\n// Always verify webhook signatures before processing\nconst isValid = validateWebhookSignature(\n  req.rawBody,\n  req.headers['x-razorpay-signature'],\n  process.env.RAZORPAY_WEBHOOK_SECRET\n);\n\nif (!isValid) {\n  return res.status(400).json({ error: 'Invalid signature' });\n}\n```\n\n### Verify Payment Signatures\n\n```javascript\n// Always verify payment signatures on the server\nconst isValid = validatePaymentVerification(\n  { order_id: orderId, payment_id: paymentId },\n  signature,\n  process.env.RAZORPAY_KEY_SECRET\n);\n```\n\n## Useful Links\n\n- **Documentation:** https://razorpay.com/docs/\n- **API Reference:** https://razorpay.com/docs/api/\n- **Node.js SDK Docs:** https://razorpay.com/docs/payments/server-integration/nodejs/\n- **NPM Package:** https://www.npmjs.com/package/razorpay\n- **GitHub Repository:** https://github.com/razorpay/razorpay-node\n- **Dashboard:** https://dashboard.razorpay.com/\n- **Support:** https://razorpay.com/support/\n\n## Notes\n\nThis guide covers the core functionality of the Razorpay Node.js SDK. The SDK provides a promise-based API for all Razorpay services including payments, orders, refunds, subscriptions, customers, invoices, transfers, and virtual accounts. Always use environment variables for credentials and validate all payment signatures and webhook signatures to ensure security.\n"
  },
  {
    "path": "content/razorpay/docs/payments/python/DOC.md",
    "content": "---\nname: payments\ndescription: \"Razorpay Python SDK coding guidelines for building payment systems with orders, payments, refunds, and subscriptions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.2\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"razorpay,payments,india,checkout,upi\"\n---\n\n# Razorpay Python Coding Guidelines\n\nYou are a Razorpay payment gateway coding expert. Help me with writing code using the Razorpay Python SDK for building payment systems with orders, payments, refunds, subscriptions, customers, and invoices.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://razorpay.com/docs/payments/server-integration/python/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Razorpay Python SDK, which is the standard library for all Razorpay API interactions.\n\n**Library Name:** Razorpay Python SDK\n**Python Package:** `razorpay`\n**Current Version:** 1.4.2\n**Supported Python Versions:** Python 3.12+\n\n**Installation:**\n- **Correct:** `pip install razorpay`\n\n**APIs and Usage:**\n- **Correct:** `import razorpay`\n- **Correct:** `client = razorpay.Client(auth=(\"YOUR_KEY_ID\", \"YOUR_KEY_SECRET\"))`\n- **Correct:** `client.order.create(data={...})` for creating orders\n- **Correct:** `client.payment.fetch(payment_id)` for fetching payments\n- **Incorrect:** Using unofficial Razorpay libraries or wrappers\n- **Incorrect:** Exposing credentials in client-side applications\n\n## Authentication and Initialization\n\nThe Razorpay Python library requires your Key ID and Key Secret for authentication. You can obtain these from the Razorpay Dashboard at Settings > API Keys.\n\n### Environment Variables (Recommended)\n\nSet up environment variables for secure credential management:\n\n```python\nimport os\nimport razorpay\nfrom dotenv import load_dotenv\n\n# Load environment variables\nload_dotenv()\n\n# Initialize Razorpay client\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n```\n\n### Direct Initialization\n\n```python\nimport razorpay\n\n# Initialize client with credentials\nclient = razorpay.Client(auth=(\n    'rzp_test_xxxxxxxxxx',\n    'your_key_secret_here'\n))\n```\n\n### Client Configuration Options\n\n```python\nimport razorpay\n\n# Enable retry on network errors\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n\n# Enable automatic retry\nclient.enable_retry(True)\n\n# Set custom app details\nclient.set_app_details({\n    \"title\": \"My Application\",\n    \"version\": \"1.0.0\"\n})\n```\n\n## Orders API\n\n### Create Order\n\nCreate an order before accepting payments from customers:\n\n```python\nimport razorpay\nimport os\n\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n\ndef create_order():\n    try:\n        data = {\n            'amount': 50000,  # Amount in paise (50000 paise = ₹500)\n            'currency': 'INR',\n            'receipt': 'receipt_order_12345',\n            'notes': {\n                'key1': 'value1',\n                'key2': 'value2'\n            }\n        }\n\n        order = client.order.create(data=data)\n        print('Order ID:', order['id'])\n        print('Order:', order)\n        return order\n    except Exception as e:\n        print('Error creating order:', str(e))\n        raise\n```\n\n### Fetch Order Details\n\n```python\ndef fetch_order(order_id):\n    try:\n        order = client.order.fetch(order_id)\n        print('Order details:', order)\n        return order\n    except Exception as e:\n        print('Error fetching order:', str(e))\n        raise\n```\n\n### Fetch All Orders\n\n```python\ndef fetch_all_orders():\n    try:\n        options = {\n            'count': 10,           # Number of orders to fetch (default: 10, max: 100)\n            'skip': 0,             # Number of orders to skip (for pagination)\n            'from': 1640995200,    # Unix timestamp (fetch orders from this time)\n            'to': 1672531199       # Unix timestamp (fetch orders till this time)\n        }\n\n        orders = client.order.all(options)\n        print('Orders:', orders)\n        return orders\n    except Exception as e:\n        print('Error fetching orders:', str(e))\n        raise\n```\n\n### Fetch Payments for an Order\n\n```python\ndef fetch_order_payments(order_id):\n    try:\n        payments = client.order.payments(order_id)\n        print('Payments for order:', payments)\n        return payments\n    except Exception as e:\n        print('Error fetching order payments:', str(e))\n        raise\n```\n\n### Update Order\n\n```python\ndef update_order(order_id):\n    try:\n        data = {\n            'notes': {\n                'updated_key': 'updated_value'\n            }\n        }\n\n        order = client.order.edit(order_id, data)\n        print('Order updated:', order)\n        return order\n    except Exception as e:\n        print('Error updating order:', str(e))\n        raise\n```\n\n## Payments API\n\n### Fetch Payment Details\n\n```python\ndef fetch_payment(payment_id):\n    try:\n        payment = client.payment.fetch(payment_id)\n        print('Payment details:', payment)\n        return payment\n    except Exception as e:\n        print('Error fetching payment:', str(e))\n        raise\n```\n\n### Fetch All Payments\n\n```python\ndef fetch_all_payments():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0,\n            'from': 1640995200,\n            'to': 1672531199\n        }\n\n        payments = client.payment.all(options)\n        print('Payments:', payments)\n        return payments\n    except Exception as e:\n        print('Error fetching payments:', str(e))\n        raise\n```\n\n### Capture Payment\n\nCapture an authorized payment:\n\n```python\ndef capture_payment(payment_id, amount):\n    try:\n        data = {\n            'amount': amount,  # Amount in paise\n            'currency': 'INR'\n        }\n\n        payment = client.payment.capture(payment_id, amount)\n        print('Payment captured:', payment)\n        return payment\n    except Exception as e:\n        print('Error capturing payment:', str(e))\n        raise\n```\n\n### Update Payment\n\n```python\ndef update_payment(payment_id):\n    try:\n        data = {\n            'notes': {\n                'note_key_1': 'updated value 1',\n                'note_key_2': 'updated value 2'\n            }\n        }\n\n        payment = client.payment.edit(payment_id, data)\n        print('Payment updated:', payment)\n        return payment\n    except Exception as e:\n        print('Error updating payment:', str(e))\n        raise\n```\n\n### Fetch Card Details\n\n```python\ndef fetch_card_details(payment_id):\n    try:\n        card = client.payment.fetch_card_details(payment_id)\n        print('Card details:', card)\n        return card\n    except Exception as e:\n        print('Error fetching card details:', str(e))\n        raise\n```\n\n## Refunds API\n\n### Create Refund\n\n```python\ndef create_refund(payment_id):\n    try:\n        data = {\n            'amount': 10000,  # Amount in paise to refund\n            'speed': 'normal',  # 'normal' or 'optimum'\n            'notes': {\n                'notes_key_1': 'Refund reason'\n            },\n            'receipt': 'Receipt No. 31'\n        }\n\n        refund = client.payment.refund(payment_id, data)\n        print('Refund created:', refund)\n        return refund\n    except Exception as e:\n        print('Error creating refund:', str(e))\n        raise\n```\n\n### Fetch Refund Details\n\n```python\ndef fetch_refund(refund_id):\n    try:\n        refund = client.refund.fetch(refund_id)\n        print('Refund details:', refund)\n        return refund\n    except Exception as e:\n        print('Error fetching refund:', str(e))\n        raise\n```\n\n### Fetch All Refunds for a Payment\n\n```python\ndef fetch_payment_refunds(payment_id):\n    try:\n        refunds = client.payment.refunds(payment_id)\n        print('Refunds:', refunds)\n        return refunds\n    except Exception as e:\n        print('Error fetching refunds:', str(e))\n        raise\n```\n\n### Fetch All Refunds\n\n```python\ndef fetch_all_refunds():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0,\n            'from': 1640995200,\n            'to': 1672531199\n        }\n\n        refunds = client.refund.all(options)\n        print('All refunds:', refunds)\n        return refunds\n    except Exception as e:\n        print('Error fetching all refunds:', str(e))\n        raise\n```\n\n### Update Refund\n\n```python\ndef update_refund(refund_id):\n    try:\n        data = {\n            'notes': {\n                'updated_note': 'Updated refund note'\n            }\n        }\n\n        refund = client.refund.edit(refund_id, data)\n        print('Refund updated:', refund)\n        return refund\n    except Exception as e:\n        print('Error updating refund:', str(e))\n        raise\n```\n\n## Customers API\n\n### Create Customer\n\n```python\ndef create_customer():\n    try:\n        data = {\n            'name': 'John Doe',\n            'email': 'john.doe@example.com',\n            'contact': '+919876543210',\n            'fail_existing': 0,  # 0 to return existing customer if exists, 1 to fail\n            'notes': {\n                'customer_type': 'premium'\n            }\n        }\n\n        customer = client.customer.create(data)\n        print('Customer created:', customer)\n        return customer\n    except Exception as e:\n        print('Error creating customer:', str(e))\n        raise\n```\n\n### Fetch Customer Details\n\n```python\ndef fetch_customer(customer_id):\n    try:\n        customer = client.customer.fetch(customer_id)\n        print('Customer details:', customer)\n        return customer\n    except Exception as e:\n        print('Error fetching customer:', str(e))\n        raise\n```\n\n### Update Customer\n\n```python\ndef update_customer(customer_id):\n    try:\n        data = {\n            'name': 'Jane Doe',\n            'email': 'jane.doe@example.com',\n            'contact': '+919876543211'\n        }\n\n        customer = client.customer.edit(customer_id, data)\n        print('Customer updated:', customer)\n        return customer\n    except Exception as e:\n        print('Error updating customer:', str(e))\n        raise\n```\n\n### Fetch All Customers\n\n```python\ndef fetch_all_customers():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        customers = client.customer.all(options)\n        print('Customers:', customers)\n        return customers\n    except Exception as e:\n        print('Error fetching customers:', str(e))\n        raise\n```\n\n## Subscriptions API\n\n### Create Subscription\n\n```python\nimport time\n\ndef create_subscription():\n    try:\n        data = {\n            'plan_id': 'plan_xxxxxxxxxxxxx',\n            'customer_notify': 1,\n            'quantity': 1,\n            'total_count': 12,\n            'start_at': int(time.time()) + 86400,  # Start after 1 day\n            'addons': [\n                {\n                    'item': {\n                        'name': 'Extra Storage',\n                        'amount': 5000,\n                        'currency': 'INR'\n                    }\n                }\n            ],\n            'notes': {\n                'subscription_type': 'premium'\n            }\n        }\n\n        subscription = client.subscription.create(data)\n        print('Subscription created:', subscription)\n        return subscription\n    except Exception as e:\n        print('Error creating subscription:', str(e))\n        raise\n```\n\n### Fetch Subscription Details\n\n```python\ndef fetch_subscription(subscription_id):\n    try:\n        subscription = client.subscription.fetch(subscription_id)\n        print('Subscription details:', subscription)\n        return subscription\n    except Exception as e:\n        print('Error fetching subscription:', str(e))\n        raise\n```\n\n### Cancel Subscription\n\n```python\ndef cancel_subscription(subscription_id):\n    try:\n        data = {\n            'cancel_at_cycle_end': 0  # 0 to cancel immediately, 1 to cancel at end of cycle\n        }\n\n        subscription = client.subscription.cancel(subscription_id, data)\n        print('Subscription cancelled:', subscription)\n        return subscription\n    except Exception as e:\n        print('Error cancelling subscription:', str(e))\n        raise\n```\n\n### Fetch All Subscriptions\n\n```python\ndef fetch_all_subscriptions():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        subscriptions = client.subscription.all(options)\n        print('Subscriptions:', subscriptions)\n        return subscriptions\n    except Exception as e:\n        print('Error fetching subscriptions:', str(e))\n        raise\n```\n\n### Update Subscription\n\n```python\ndef update_subscription(subscription_id):\n    try:\n        data = {\n            'plan_id': 'plan_yyyyyyyyyyy',\n            'quantity': 2,\n            'remaining_count': 6\n        }\n\n        subscription = client.subscription.edit(subscription_id, data)\n        print('Subscription updated:', subscription)\n        return subscription\n    except Exception as e:\n        print('Error updating subscription:', str(e))\n        raise\n```\n\n## Plans API\n\n### Create Plan\n\n```python\ndef create_plan():\n    try:\n        data = {\n            'period': 'monthly',\n            'interval': 1,\n            'item': {\n                'name': 'Premium Plan',\n                'amount': 99900,  # Amount in paise\n                'currency': 'INR',\n                'description': 'Premium monthly subscription'\n            },\n            'notes': {\n                'plan_type': 'premium'\n            }\n        }\n\n        plan = client.plan.create(data)\n        print('Plan created:', plan)\n        return plan\n    except Exception as e:\n        print('Error creating plan:', str(e))\n        raise\n```\n\n### Fetch Plan Details\n\n```python\ndef fetch_plan(plan_id):\n    try:\n        plan = client.plan.fetch(plan_id)\n        print('Plan details:', plan)\n        return plan\n    except Exception as e:\n        print('Error fetching plan:', str(e))\n        raise\n```\n\n### Fetch All Plans\n\n```python\ndef fetch_all_plans():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        plans = client.plan.all(options)\n        print('Plans:', plans)\n        return plans\n    except Exception as e:\n        print('Error fetching plans:', str(e))\n        raise\n```\n\n## Invoices API\n\n### Create Invoice\n\n```python\nimport time\n\ndef create_invoice():\n    try:\n        data = {\n            'type': 'invoice',\n            'description': 'Invoice for the month of January 2025',\n            'customer': {\n                'name': 'John Doe',\n                'email': 'john.doe@example.com',\n                'contact': '+919876543210'\n            },\n            'line_items': [\n                {\n                    'name': 'Premium Subscription',\n                    'description': 'Monthly subscription',\n                    'amount': 99900,\n                    'currency': 'INR',\n                    'quantity': 1\n                }\n            ],\n            'currency': 'INR',\n            'email_notify': 1,\n            'sms_notify': 1,\n            'date': int(time.time())\n        }\n\n        invoice = client.invoice.create(data)\n        print('Invoice created:', invoice)\n        return invoice\n    except Exception as e:\n        print('Error creating invoice:', str(e))\n        raise\n```\n\n### Fetch Invoice Details\n\n```python\ndef fetch_invoice(invoice_id):\n    try:\n        invoice = client.invoice.fetch(invoice_id)\n        print('Invoice details:', invoice)\n        return invoice\n    except Exception as e:\n        print('Error fetching invoice:', str(e))\n        raise\n```\n\n### Fetch All Invoices\n\n```python\ndef fetch_all_invoices():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        invoices = client.invoice.all(options)\n        print('Invoices:', invoices)\n        return invoices\n    except Exception as e:\n        print('Error fetching invoices:', str(e))\n        raise\n```\n\n### Cancel Invoice\n\n```python\ndef cancel_invoice(invoice_id):\n    try:\n        invoice = client.invoice.cancel(invoice_id)\n        print('Invoice cancelled:', invoice)\n        return invoice\n    except Exception as e:\n        print('Error cancelling invoice:', str(e))\n        raise\n```\n\n### Issue Invoice\n\n```python\ndef issue_invoice(invoice_id):\n    try:\n        invoice = client.invoice.issue(invoice_id)\n        print('Invoice issued:', invoice)\n        return invoice\n    except Exception as e:\n        print('Error issuing invoice:', str(e))\n        raise\n```\n\n### Update Invoice\n\n```python\ndef update_invoice(invoice_id):\n    try:\n        data = {\n            'notes': {\n                'updated_note': 'Updated invoice note'\n            }\n        }\n\n        invoice = client.invoice.edit(invoice_id, data)\n        print('Invoice updated:', invoice)\n        return invoice\n    except Exception as e:\n        print('Error updating invoice:', str(e))\n        raise\n```\n\n## Payment Verification\n\n### Verify Payment Signature\n\nVerify payment signatures to ensure payment authenticity:\n\n```python\nimport hmac\nimport hashlib\n\n# Method 1: Using Razorpay's built-in utility\ndef verify_payment_signature(order_id, payment_id, signature):\n    try:\n        params_dict = {\n            'razorpay_order_id': order_id,\n            'razorpay_payment_id': payment_id,\n            'razorpay_signature': signature\n        }\n\n        # This will raise SignatureVerificationError if signature is invalid\n        client.utility.verify_payment_signature(params_dict)\n        print('Payment signature verified successfully')\n        return True\n    except razorpay.errors.SignatureVerificationError as e:\n        print('Invalid payment signature:', str(e))\n        return False\n    except Exception as e:\n        print('Error verifying payment signature:', str(e))\n        return False\n\n# Method 2: Manual verification\ndef verify_payment_signature_manual(order_id, payment_id, signature):\n    try:\n        key_secret = os.environ.get('RAZORPAY_KEY_SECRET')\n\n        # Create the expected signature\n        message = f\"{order_id}|{payment_id}\"\n        generated_signature = hmac.new(\n            key_secret.encode(),\n            message.encode(),\n            hashlib.sha256\n        ).hexdigest()\n\n        # Compare signatures\n        is_valid = hmac.compare_digest(generated_signature, signature)\n\n        if is_valid:\n            print('Payment signature verified successfully')\n            return True\n        else:\n            print('Invalid payment signature')\n            return False\n    except Exception as e:\n        print('Error verifying payment signature:', str(e))\n        return False\n```\n\n## Webhook Handling and Validation\n\n### Flask Webhook Integration\n\nHandle and validate incoming Razorpay webhooks:\n\n```python\nfrom flask import Flask, request, jsonify\nimport razorpay\nimport os\nimport hmac\nimport hashlib\n\napp = Flask(__name__)\n\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n\ndef validate_webhook_signature(webhook_body, signature, secret):\n    \"\"\"Validate webhook signature\"\"\"\n    try:\n        generated_signature = hmac.new(\n            secret.encode(),\n            webhook_body,\n            hashlib.sha256\n        ).hexdigest()\n\n        return hmac.compare_digest(generated_signature, signature)\n    except Exception as e:\n        print('Error validating webhook:', str(e))\n        return False\n\n@app.route('/webhook', methods=['POST'])\ndef handle_webhook():\n    # Get the webhook signature from headers\n    signature = request.headers.get('X-Razorpay-Signature')\n    webhook_secret = os.environ.get('RAZORPAY_WEBHOOK_SECRET')\n\n    # Get raw request body\n    webhook_body = request.get_data()\n\n    # Validate signature\n    is_valid = validate_webhook_signature(webhook_body, signature, webhook_secret)\n\n    if not is_valid:\n        return jsonify({'error': 'Invalid signature'}), 400\n\n    # Parse webhook event\n    event = request.get_json()\n\n    print('Webhook event:', event.get('event'))\n\n    # Handle different event types\n    event_type = event.get('event')\n\n    if event_type == 'payment.authorized':\n        handle_payment_authorized(event['payload']['payment']['entity'])\n    elif event_type == 'payment.captured':\n        handle_payment_captured(event['payload']['payment']['entity'])\n    elif event_type == 'payment.failed':\n        handle_payment_failed(event['payload']['payment']['entity'])\n    elif event_type == 'order.paid':\n        handle_order_paid(event['payload']['order']['entity'])\n    elif event_type == 'refund.created':\n        handle_refund_created(event['payload']['refund']['entity'])\n    elif event_type == 'subscription.activated':\n        handle_subscription_activated(event['payload']['subscription']['entity'])\n    elif event_type == 'subscription.cancelled':\n        handle_subscription_cancelled(event['payload']['subscription']['entity'])\n    elif event_type == 'invoice.paid':\n        handle_invoice_paid(event['payload']['invoice']['entity'])\n    else:\n        print('Unhandled event:', event_type)\n\n    return jsonify({'status': 'ok'}), 200\n\ndef handle_payment_authorized(payment):\n    print('Payment authorized:', payment['id'])\n    # Capture the payment or perform other actions\n\ndef handle_payment_captured(payment):\n    print('Payment captured:', payment['id'])\n    # Update order status, send confirmation email, etc.\n\ndef handle_payment_failed(payment):\n    print('Payment failed:', payment['id'])\n    # Notify customer, update order status, etc.\n\ndef handle_order_paid(order):\n    print('Order paid:', order['id'])\n    # Process order fulfillment\n\ndef handle_refund_created(refund):\n    print('Refund created:', refund['id'])\n    # Update records, notify customer\n\ndef handle_subscription_activated(subscription):\n    print('Subscription activated:', subscription['id'])\n    # Grant access to subscription features\n\ndef handle_subscription_cancelled(subscription):\n    print('Subscription cancelled:', subscription['id'])\n    # Revoke access, send cancellation email\n\ndef handle_invoice_paid(invoice):\n    print('Invoice paid:', invoice['id'])\n    # Update invoice status, send receipt\n\nif __name__ == '__main__':\n    app.run(port=3000, debug=True)\n```\n\n### Using Razorpay's Webhook Verification Utility\n\n```python\n@app.route('/webhook', methods=['POST'])\ndef handle_webhook_with_utility():\n    signature = request.headers.get('X-Razorpay-Signature')\n    webhook_secret = os.environ.get('RAZORPAY_WEBHOOK_SECRET')\n    webhook_body = request.get_data().decode('utf-8')\n\n    try:\n        # Verify webhook signature using Razorpay utility\n        client.utility.verify_webhook_signature(\n            webhook_body,\n            signature,\n            webhook_secret\n        )\n\n        # Process webhook event\n        event = request.get_json()\n        # Handle event...\n\n        return jsonify({'status': 'ok'}), 200\n    except razorpay.errors.SignatureVerificationError:\n        return jsonify({'error': 'Invalid signature'}), 400\n```\n\n## Transfers API (Route)\n\n### Create Transfer\n\nTransfer funds to linked accounts:\n\n```python\ndef create_transfer(payment_id):\n    try:\n        data = {\n            'transfers': [\n                {\n                    'account': 'acc_xxxxxxxxxxxxx',\n                    'amount': 10000,  # Amount in paise\n                    'currency': 'INR',\n                    'notes': {\n                        'name': 'Transfer to vendor',\n                        'roll_no': 'IEC2011025'\n                    },\n                    'linked_account_notes': ['branch'],\n                    'on_hold': 0,  # 0 to transfer immediately, 1 to hold\n                    'on_hold_until': None\n                }\n            ]\n        }\n\n        transfer = client.payment.transfer(payment_id, data)\n        print('Transfer created:', transfer)\n        return transfer\n    except Exception as e:\n        print('Error creating transfer:', str(e))\n        raise\n```\n\n### Fetch Transfer Details\n\n```python\ndef fetch_transfer(transfer_id):\n    try:\n        transfer = client.transfer.fetch(transfer_id)\n        print('Transfer details:', transfer)\n        return transfer\n    except Exception as e:\n        print('Error fetching transfer:', str(e))\n        raise\n```\n\n### Fetch All Transfers\n\n```python\ndef fetch_all_transfers():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        transfers = client.transfer.all(options)\n        print('Transfers:', transfers)\n        return transfers\n    except Exception as e:\n        print('Error fetching transfers:', str(e))\n        raise\n```\n\n## Virtual Accounts API\n\n### Create Virtual Account\n\n```python\nimport time\n\ndef create_virtual_account():\n    try:\n        data = {\n            'receivers': {\n                'types': ['bank_account']\n            },\n            'description': 'Virtual Account for customer XYZ',\n            'customer_id': 'cust_xxxxxxxxxxxxx',\n            'close_by': int(time.time()) + 86400 * 30,  # Close after 30 days\n            'notes': {\n                'purpose': 'Rent collection'\n            }\n        }\n\n        virtual_account = client.virtual_account.create(data)\n        print('Virtual Account created:', virtual_account)\n        return virtual_account\n    except Exception as e:\n        print('Error creating virtual account:', str(e))\n        raise\n```\n\n### Fetch Virtual Account Details\n\n```python\ndef fetch_virtual_account(va_id):\n    try:\n        virtual_account = client.virtual_account.fetch(va_id)\n        print('Virtual Account details:', virtual_account)\n        return virtual_account\n    except Exception as e:\n        print('Error fetching virtual account:', str(e))\n        raise\n```\n\n### Fetch All Virtual Accounts\n\n```python\ndef fetch_all_virtual_accounts():\n    try:\n        options = {\n            'count': 10,\n            'skip': 0\n        }\n\n        virtual_accounts = client.virtual_account.all(options)\n        print('Virtual Accounts:', virtual_accounts)\n        return virtual_accounts\n    except Exception as e:\n        print('Error fetching virtual accounts:', str(e))\n        raise\n```\n\n### Close Virtual Account\n\n```python\ndef close_virtual_account(va_id):\n    try:\n        virtual_account = client.virtual_account.close(va_id)\n        print('Virtual Account closed:', virtual_account)\n        return virtual_account\n    except Exception as e:\n        print('Error closing virtual account:', str(e))\n        raise\n```\n\n## Error Handling\n\n### Comprehensive Error Handling\n\n```python\nimport razorpay.errors as errors\n\ndef safe_api_call():\n    try:\n        data = {\n            'amount': 50000,\n            'currency': 'INR',\n            'receipt': 'receipt_12345'\n        }\n\n        order = client.order.create(data=data)\n\n        return {\n            'success': True,\n            'data': order\n        }\n    except errors.BadRequestError as e:\n        print('Bad Request Error:', e)\n        return {\n            'success': False,\n            'error': {\n                'code': 400,\n                'message': str(e)\n            }\n        }\n    except errors.UnauthorizedError as e:\n        print('Unauthorized Error:', e)\n        return {\n            'success': False,\n            'error': {\n                'code': 401,\n                'message': 'Invalid API credentials'\n            }\n        }\n    except errors.ServerError as e:\n        print('Server Error:', e)\n        return {\n            'success': False,\n            'error': {\n                'code': 500,\n                'message': 'Razorpay server error'\n            }\n        }\n    except errors.GatewayError as e:\n        print('Gateway Error:', e)\n        return {\n            'success': False,\n            'error': {\n                'code': 502,\n                'message': 'Gateway error occurred'\n            }\n        }\n    except Exception as e:\n        print('Unknown error:', e)\n        return {\n            'success': False,\n            'error': {\n                'code': 500,\n                'message': str(e)\n            }\n        }\n```\n\n### Specific Error Handling\n\n```python\ndef handle_specific_errors():\n    try:\n        payment = client.payment.fetch('pay_xxxxxxxxxxxxx')\n        return payment\n    except errors.BadRequestError as e:\n        print('Bad Request - Invalid parameters')\n        raise\n    except errors.UnauthorizedError as e:\n        print('Unauthorized - Invalid API credentials')\n        raise\n    except errors.NotFoundError as e:\n        print('Not Found - Resource does not exist')\n        raise\n    except errors.ServerError as e:\n        print('Internal Server Error - Razorpay issue')\n        raise\n    except Exception as e:\n        print('Unknown error:', str(e))\n        raise\n```\n\n## Complete Payment Flow Example\n\n### Flask Server Integration\n\n```python\nfrom flask import Flask, request, jsonify\nimport razorpay\nimport os\nimport time\n\napp = Flask(__name__)\n\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n\n# Step 1: Create order\n@app.route('/create-order', methods=['POST'])\ndef create_order():\n    try:\n        data = request.get_json()\n        amount = data.get('amount')\n        currency = data.get('currency', 'INR')\n\n        order_data = {\n            'amount': amount * 100,  # Convert to paise\n            'currency': currency,\n            'receipt': f\"receipt_{int(time.time())}\",\n            'notes': {\n                'description': 'Order payment'\n            }\n        }\n\n        order = client.order.create(data=order_data)\n\n        return jsonify({\n            'success': True,\n            'order': {\n                'id': order['id'],\n                'amount': order['amount'],\n                'currency': order['currency']\n            },\n            'key_id': os.environ.get('RAZORPAY_KEY_ID')\n        }), 200\n    except Exception as e:\n        print('Error creating order:', str(e))\n        return jsonify({\n            'success': False,\n            'message': 'Failed to create order'\n        }), 500\n\n# Step 2: Verify payment\n@app.route('/verify-payment', methods=['POST'])\ndef verify_payment():\n    try:\n        data = request.get_json()\n        razorpay_order_id = data.get('razorpay_order_id')\n        razorpay_payment_id = data.get('razorpay_payment_id')\n        razorpay_signature = data.get('razorpay_signature')\n\n        params_dict = {\n            'razorpay_order_id': razorpay_order_id,\n            'razorpay_payment_id': razorpay_payment_id,\n            'razorpay_signature': razorpay_signature\n        }\n\n        # Verify signature\n        client.utility.verify_payment_signature(params_dict)\n\n        # Payment is successful, fetch payment details\n        payment = client.payment.fetch(razorpay_payment_id)\n\n        return jsonify({\n            'success': True,\n            'message': 'Payment verified successfully',\n            'payment': {\n                'id': payment['id'],\n                'amount': payment['amount'],\n                'status': payment['status']\n            }\n        }), 200\n    except razorpay.errors.SignatureVerificationError:\n        return jsonify({\n            'success': False,\n            'message': 'Payment verification failed'\n        }), 400\n    except Exception as e:\n        print('Error verifying payment:', str(e))\n        return jsonify({\n            'success': False,\n            'message': 'Payment verification error'\n        }), 500\n\n# Step 3: Fetch payment details\n@app.route('/payment/<payment_id>', methods=['GET'])\ndef get_payment(payment_id):\n    try:\n        payment = client.payment.fetch(payment_id)\n        return jsonify({\n            'success': True,\n            'payment': payment\n        }), 200\n    except Exception as e:\n        print('Error fetching payment:', str(e))\n        return jsonify({\n            'success': False,\n            'message': 'Failed to fetch payment'\n        }), 500\n\nif __name__ == '__main__':\n    app.run(port=3000, debug=True)\n```\n\n## Security Best Practices\n\n### Never Expose Credentials\n\n```python\n# Good - Use environment variables\nimport os\n\nclient = razorpay.Client(auth=(\n    os.environ.get('RAZORPAY_KEY_ID'),\n    os.environ.get('RAZORPAY_KEY_SECRET')\n))\n\n# Bad - Hardcoded credentials\nclient = razorpay.Client(auth=(\n    'rzp_test_xxxxxxxxxxxx',\n    'your_secret_here'\n))\n```\n\n### Always Validate Webhooks\n\n```python\n# Always verify webhook signatures before processing\nis_valid = validate_webhook_signature(\n    webhook_body,\n    signature,\n    os.environ.get('RAZORPAY_WEBHOOK_SECRET')\n)\n\nif not is_valid:\n    return jsonify({'error': 'Invalid signature'}), 400\n```\n\n### Verify Payment Signatures\n\n```python\n# Always verify payment signatures on the server\nparams_dict = {\n    'razorpay_order_id': order_id,\n    'razorpay_payment_id': payment_id,\n    'razorpay_signature': signature\n}\n\nclient.utility.verify_payment_signature(params_dict)\n```\n\n## Useful Links\n\n- **Documentation:** https://razorpay.com/docs/\n- **API Reference:** https://razorpay.com/docs/api/\n- **Python SDK Docs:** https://razorpay.com/docs/payments/server-integration/python/\n- **PyPI Package:** https://pypi.org/project/razorpay/\n- **GitHub Repository:** https://github.com/razorpay/razorpay-python\n- **Dashboard:** https://dashboard.razorpay.com/\n- **Support:** https://razorpay.com/support/\n\n## Notes\n\nThis guide covers the core functionality of the Razorpay Python SDK. The SDK provides comprehensive support for all Razorpay services including payments, orders, refunds, subscriptions, customers, invoices, transfers, and virtual accounts. Always use environment variables for credentials and validate all payment signatures and webhook signatures to ensure security. The SDK requires Python 3.12 or higher and provides utilities for payment verification and webhook signature validation.\n"
  },
  {
    "path": "content/react/docs/react/javascript/DOC.md",
    "content": "---\nname: react\ndescription: \"React runtime for building component UIs in JavaScript with hooks, context, Suspense, and lazy loading.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.2.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"react,javascript,ui,components,hooks,context,suspense\"\n---\n\n# React Guide (JavaScript)\n\n## Golden Rule\n\nUse `react` for components, hooks, context, and rendering logic. Use `react-dom` separately when you need to mount React in a browser.\n\nFor browser apps, keep `react` and `react-dom` on the same React major line so the runtime and renderer stay compatible.\n\n## Install\n\nInstall `react` in every React app. Add `react-dom` for web apps that render into the DOM.\n\n```bash\nnpm install react\n\n# Browser apps\nnpm install react-dom\n```\n\nReact does not need API keys, environment variables, or client initialization.\n\nThis guide assumes your app uses a JSX-capable build step. In modern React projects, JSX is usually compiled with the automatic JSX transform, so you do not need `import React from \"react\"` just to write JSX.\n\n## Initialize a Browser App\n\n`react` does not mount itself into the page. For that, import `createRoot` from `react-dom/client`.\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>React App</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.jsx\"></script>\n  </body>\n</html>\n```\n\n```jsx\n// src/main.jsx\nimport { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { App } from \"./App.jsx\";\n\nconst container = document.getElementById(\"root\");\n\nif (!container) {\n  throw new Error(\"Missing #root container\");\n}\n\ncreateRoot(container).render(\n  <StrictMode>\n    <App />\n  </StrictMode>,\n);\n```\n\n```jsx\n// src/App.jsx\nimport { useState } from \"react\";\n\nexport function App() {\n  const [count, setCount] = useState(0);\n\n  return (\n    <main>\n      <h1>Hello, React</h1>\n      <button onClick={() => setCount((current) => current + 1)}>\n        Clicked {count} times\n      </button>\n    </main>\n  );\n}\n```\n\n## Common Workflows\n\n### Manage local component state with `useState`\n\nUse `useState` for local, render-driven state such as toggles, input values, and counters.\n\n```jsx\nimport { useState } from \"react\";\n\nexport function SignupForm() {\n  const [email, setEmail] = useState(\"\");\n  const [submitted, setSubmitted] = useState(false);\n\n  function handleSubmit(event) {\n    event.preventDefault();\n    setSubmitted(true);\n  }\n\n  if (submitted) {\n    return <p>Thanks. We will contact {email}.</p>;\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <label>\n        Email\n        <input\n          type=\"email\"\n          value={email}\n          onChange={(event) => setEmail(event.target.value)}\n          required\n        />\n      </label>\n\n      <button type=\"submit\">Sign up</button>\n    </form>\n  );\n}\n```\n\n### Synchronize with external systems using `useEffect`\n\nUse `useEffect` when code must run after React commits the UI, such as timers, subscriptions, or DOM integrations. Return a cleanup function when the effect starts work that must be undone.\n\n```jsx\nimport { useEffect, useState } from \"react\";\n\nexport function Clock() {\n  const [now, setNow] = useState(() => new Date());\n\n  useEffect(() => {\n    const intervalId = window.setInterval(() => {\n      setNow(new Date());\n    }, 1000);\n\n    return () => {\n      window.clearInterval(intervalId);\n    };\n  }, []);\n\n  return <time dateTime={now.toISOString()}>{now.toLocaleTimeString()}</time>;\n}\n```\n\n### Share app-level values with context\n\nCreate the context with `createContext`, provide it near the top of the tree, and read it with `useContext` in descendants.\n\nIn React 19, the context object itself can be used as the provider component.\n\n```jsx\nimport {\n  createContext,\n  useContext,\n  useMemo,\n  useState,\n} from \"react\";\n\nconst ThemeContext = createContext(null);\n\nexport function ThemeProvider({ children }) {\n  const [theme, setTheme] = useState(\"light\");\n\n  const value = useMemo(\n    () => ({\n      theme,\n      toggleTheme() {\n        setTheme((current) => (current === \"light\" ? \"dark\" : \"light\"));\n      },\n    }),\n    [theme],\n  );\n\n  return <ThemeContext value={value}>{children}</ThemeContext>;\n}\n\nexport function useTheme() {\n  const context = useContext(ThemeContext);\n\n  if (context === null) {\n    throw new Error(\"useTheme must be used within <ThemeProvider>\");\n  }\n\n  return context;\n}\n```\n\n### Memoize expensive derived values with `useMemo`\n\nUse `useMemo` when recalculating a value on every render is measurably expensive.\n\n```jsx\nimport { useMemo, useState } from \"react\";\n\nconst products = [\n  { id: \"1\", name: \"Keyboard\" },\n  { id: \"2\", name: \"Monitor\" },\n  { id: \"3\", name: \"Microphone\" },\n];\n\nexport function ProductSearch() {\n  const [query, setQuery] = useState(\"\");\n\n  const visibleProducts = useMemo(() => {\n    const normalizedQuery = query.trim().toLowerCase();\n\n    if (!normalizedQuery) {\n      return products;\n    }\n\n    return products.filter((product) =>\n      product.name.toLowerCase().includes(normalizedQuery),\n    );\n  }, [query]);\n\n  return (\n    <>\n      <input\n        value={query}\n        onChange={(event) => setQuery(event.target.value)}\n        placeholder=\"Search products\"\n      />\n\n      <ul>\n        {visibleProducts.map((product) => (\n          <li key={product.id}>{product.name}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\n`useMemo` is a performance optimization. Your code should still be correct if React recalculates the value.\n\n### Split code with `lazy` and `Suspense`\n\nUse `lazy` for component-level code splitting and wrap the lazy component in `Suspense` with a fallback UI.\n\n```jsx\nimport { Suspense, lazy, useState } from \"react\";\n\nconst SettingsPanel = lazy(() => import(\"./SettingsPanel.jsx\"));\n\nexport function SettingsPage() {\n  const [open, setOpen] = useState(false);\n\n  return (\n    <section>\n      <button onClick={() => setOpen(true)}>Open settings</button>\n\n      {open ? (\n        <Suspense fallback={<p>Loading settings…</p>}>\n          <SettingsPanel />\n        </Suspense>\n      ) : null}\n    </section>\n  );\n}\n```\n\n## Important Pitfalls\n\n- `react` does not create or hydrate browser roots. Import `createRoot` or `hydrateRoot` from `react-dom/client`.\n- In modern React projects, JSX does not require `import React from \"react\"`, but hooks and other APIs still must be imported explicitly.\n- `useEffect` is for synchronization with external systems, not for deriving values from props or state. Compute derived values during render instead.\n- When `StrictMode` is enabled, React may run an extra development-only setup and cleanup cycle for effects. Write cleanup logic so repeated setup is safe.\n- Use stable keys from your data when rendering lists. Avoid array indexes for reorderable or editable collections.\n- `createContext(defaultValue)` uses that default only when no matching provider exists above the component.\n- `useMemo`, `useCallback`, and `memo` help with performance, but they should not be required for correctness.\n\n## Version-Sensitive Notes\n\n- This guide targets `react==19.2.4`.\n- Pair `react` with a matching React 19 `react-dom` release in browser apps.\n- The React 19 reference documents context providers using the context object directly, for example `<ThemeContext value={theme}>`.\n- The React 19 reference also includes newer hooks such as `useActionState`, `useOptimistic`, and `use` in addition to the long-standing core hooks.\n\n## Official Sources\n\n- React package page: https://www.npmjs.com/package/react\n- React API reference: https://react.dev/reference/react\n- `useState`: https://react.dev/reference/react/useState\n- `useEffect`: https://react.dev/reference/react/useEffect\n- `createContext`: https://react.dev/reference/react/createContext\n- `useContext`: https://react.dev/reference/react/useContext\n- `useMemo`: https://react.dev/reference/react/useMemo\n- `lazy`: https://react.dev/reference/react/lazy\n- `Suspense`: https://react.dev/reference/react/Suspense\n- Browser root creation with `react-dom/client`: https://react.dev/reference/react-dom/client/createRoot\n"
  },
  {
    "path": "content/react/docs/react-dom/javascript/DOC.md",
    "content": "---\nname: react-dom\ndescription: \"React DOM runtime for browser roots, hydration, portals, synchronous DOM flushes, and server rendering in JavaScript apps.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.2.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"react,react-dom,dom,hydration,ssr,portal\"\n---\n\n# React DOM JavaScript Guide\n\n## Golden Rule\n\nInstall matching `react` and `react-dom` versions, import browser root APIs from `react-dom/client`, import DOM helpers such as `createPortal` and `flushSync` from `react-dom`, and import server rendering APIs from `react-dom/server`.\n\n## Install\n\n```bash\nnpm install react react-dom\n```\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe examples below use JSX, so your app needs a build setup that compiles JSX for the browser or server runtime you target.\n\n## Mount a Browser Root\n\nUse `createRoot` when the container is empty and React owns the full client-side render.\n\n**`index.html`**\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n```\n\n**`src/main.js`**\n\n```javascript\nimport { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport App from \"./App.js\";\n\nconst container = document.getElementById(\"root\");\n\nif (!container) {\n  throw new Error(\"Missing #root container\");\n}\n\ncreateRoot(container, {\n  onRecoverableError(error, errorInfo) {\n    console.error(\"recoverable render error\", error, errorInfo.componentStack);\n  },\n}).render(\n  <StrictMode>\n    <App />\n  </StrictMode>,\n);\n```\n\nIf your app removes the host node outside React, keep the returned root and call `root.unmount()` before the container disappears.\n\n## Hydrate Server-Rendered HTML\n\nUse `hydrateRoot` when the server already rendered markup into the same container.\n\n**`src/client.js`**\n\n```javascript\nimport { hydrateRoot } from \"react-dom/client\";\nimport App from \"./App.js\";\n\nconst container = document.getElementById(\"root\");\n\nif (!container) {\n  throw new Error(\"Missing #root container\");\n}\n\nhydrateRoot(container, <App />, {\n  identifierPrefix: \"app-\",\n  onRecoverableError(error, errorInfo) {\n    console.error(\"recoverable hydration error\", error, errorInfo.componentStack);\n  },\n});\n```\n\nWhen you use `hydrateRoot`, the server HTML should match the client render. If you use `useId`, pass the same `identifierPrefix` on the server and the client.\n\n## Render a Portal Outside the Main Container\n\nUse `createPortal` when a component should stay in the same React tree but render into a different DOM node, such as a modal or tooltip root.\n\n**`index.html`**\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <body>\n    <div id=\"root\"></div>\n    <div id=\"modal-root\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n```\n\n**`src/Modal.js`**\n\n```javascript\nimport { createPortal } from \"react-dom\";\n\nexport default function Modal({ children, open }) {\n  const modalRoot = document.getElementById(\"modal-root\");\n\n  if (!open || !modalRoot) {\n    return null;\n  }\n\n  return createPortal(\n    <div className=\"modal-backdrop\">\n      <div className=\"modal\">{children}</div>\n    </div>,\n    modalRoot,\n  );\n}\n```\n\nThe portal changes where the DOM nodes live, but events and context still follow the React tree.\n\n## Force a Synchronous DOM Update Only When Needed\n\n`flushSync` is a last-resort escape hatch when later code in the same tick must observe the DOM after a React update.\n\n```javascript\nimport { useRef, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\n\nexport default function TodoList() {\n  const [items, setItems] = useState([\"First item\"]);\n  const listRef = useRef(null);\n\n  function addItem() {\n    flushSync(() => {\n      setItems((currentItems) => [\n        ...currentItems,\n        `Item ${currentItems.length + 1}`,\n      ]);\n    });\n\n    listRef.current?.lastElementChild?.scrollIntoView({\n      block: \"nearest\",\n    });\n  }\n\n  return (\n    <>\n      <button onClick={addItem}>Add item</button>\n      <ul ref={listRef}>\n        {items.map((item) => (\n          <li key={item}>{item}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nDo not wrap normal app updates in `flushSync`. It can hurt performance and may force pending Suspense boundaries to show their fallback state.\n\n## Stream HTML from a Node Server\n\nUse `renderToPipeableStream` in Node runtimes that work with Node streams.\n\n**`server.js`**\n\n```javascript\nimport express from \"express\";\nimport { renderToPipeableStream } from \"react-dom/server\";\nimport App from \"./src/App.js\";\n\nconst app = express();\n\napp.use(express.static(\"public\"));\n\napp.get(\"/\", (_req, res) => {\n  let didError = false;\n\n  const { pipe, abort } = renderToPipeableStream(<App />, {\n    bootstrapScripts: [\"/client.js\"],\n    identifierPrefix: \"app-\",\n    onShellReady() {\n      res.statusCode = didError ? 500 : 200;\n      res.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n      res.write(\"<!doctype html>\");\n      pipe(res);\n    },\n    onShellError(error) {\n      console.error(error);\n      res.statusCode = 500;\n      res.end(\"<!doctype html><h1>Server render failed</h1>\");\n    },\n    onError(error) {\n      didError = true;\n      console.error(error);\n    },\n  });\n\n  setTimeout(() => abort(), 10000);\n});\n\napp.listen(3000, () => {\n  console.log(\"http://localhost:3000\");\n});\n```\n\nHydrate the resulting HTML on the client with `hydrateRoot(...)` and use the same `identifierPrefix` if your tree uses `useId`.\n\n## Stream HTML in Web Streams Runtimes\n\nUse `renderToReadableStream` in runtimes that return a standard `Response`, such as edge or worker-style servers.\n\n```javascript\nimport { renderToReadableStream } from \"react-dom/server\";\nimport App from \"./App.js\";\n\nexport default async function handleRequest() {\n  const stream = await renderToReadableStream(<App />, {\n    bootstrapScripts: [\"/client.js\"],\n    identifierPrefix: \"app-\",\n  });\n\n  await stream.allReady;\n\n  return new Response(stream, {\n    headers: {\n      \"content-type\": \"text/html; charset=utf-8\",\n    },\n  });\n}\n```\n\n## Important Pitfalls\n\n- Import `createRoot` and `hydrateRoot` from `react-dom/client`, not from the top-level `react-dom` entry point.\n- Use `hydrateRoot` for server-rendered HTML. `createRoot` is for a fresh client mount.\n- Keep the server render and the client render structurally identical during hydration.\n- Match `react` and `react-dom` versions in the same app.\n- Treat `flushSync` as an escape hatch, not a normal rendering pattern.\n\n## Version Notes\n\nThis guide covers the stable `react-dom` npm package at `19.2.4`.\n\nThe stable React DOM reference groups the runtime APIs by entry point:\n\n- `react-dom/client` for browser roots and hydration\n- `react-dom` for helpers such as `createPortal` and `flushSync`\n- `react-dom/server` for server rendering APIs such as `renderToPipeableStream` and `renderToReadableStream`\n"
  },
  {
    "path": "content/redis/docs/key-value/javascript/DOC.md",
    "content": "---\nname: key-value\ndescription: \"Redis JavaScript client (node-redis) for key-value storage, caching, and pub/sub messaging\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.9.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"redis,database,cache,key-value,pubsub\"\n---\n\n# Redis JavaScript Client (node-redis) - Complete Integration Guide\n\n## GOLDEN RULE\n\n**ALWAYS use the official `redis` npm package (node-redis) for Redis integration.**\n\n```bash\nnpm install redis\n```\n\n**DO NOT use:**\n- `ioredis` (alternative client, not official)\n- `redis-node` (unofficial package)\n- `node_redis` (deprecated naming)\n- Any other third-party Redis clients unless specifically required\n\nThe official `redis` package is maintained by Redis and is the recommended client for Node.js applications.\n\n---\n\n## Installation\n\n### Basic Installation\n\n```bash\nnpm install redis\n```\n\n### Installation with TypeScript Support\n\n```bash\nnpm install redis\nnpm install --save-dev @types/node\n```\n\nThe `redis` package includes built-in TypeScript definitions.\n\n### Environment Setup\n\nCreate a `.env` file in your project root:\n\n```env\nREDIS_HOST=localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=your_password_here\nREDIS_DB=0\nREDIS_URL=redis://username:password@localhost:6379\n```\n\nInstall dotenv to load environment variables:\n\n```bash\nnpm install dotenv\n```\n\n---\n\n## Initialization\n\n### Basic Connection (Localhost)\n\n```javascript\nimport { createClient } from 'redis';\n\nconst client = createClient();\n\nclient.on('error', (err) => {\n  console.error('Redis Client Error', err);\n});\n\nawait client.connect();\n\n// Use the client...\n\nawait client.quit();\n```\n\n### Connection with Environment Variables\n\n```javascript\nimport { createClient } from 'redis';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst client = createClient({\n  socket: {\n    host: process.env.REDIS_HOST || 'localhost',\n    port: parseInt(process.env.REDIS_PORT || '6379')\n  },\n  password: process.env.REDIS_PASSWORD,\n  database: parseInt(process.env.REDIS_DB || '0')\n});\n\nclient.on('error', (err) => {\n  console.error('Redis Client Error', err);\n});\n\nawait client.connect();\n```\n\n### Connection Using URL\n\n```javascript\nimport { createClient } from 'redis';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst client = createClient({\n  url: process.env.REDIS_URL || 'redis://localhost:6379'\n});\n\nclient.on('error', (err) => {\n  console.error('Redis Client Error', err);\n});\n\nawait client.connect();\n```\n\n### Connection with Authentication\n\n```javascript\nimport { createClient } from 'redis';\n\nconst client = createClient({\n  url: 'redis://alice:foobared@awesome.redis.server:6380'\n});\n\n// Or using socket configuration\nconst clientAlt = createClient({\n  socket: {\n    host: 'awesome.redis.server',\n    port: 6380\n  },\n  username: 'alice',\n  password: 'foobared'\n});\n\nawait client.connect();\n```\n\n### Connection with TLS/SSL\n\n```javascript\nimport { createClient } from 'redis';\nimport fs from 'fs';\n\nconst client = createClient({\n  socket: {\n    host: 'redis.example.com',\n    port: 6380,\n    tls: true,\n    key: fs.readFileSync('/path/to/client-key.pem'),\n    cert: fs.readFileSync('/path/to/client-cert.pem'),\n    ca: [fs.readFileSync('/path/to/ca-cert.pem')]\n  }\n});\n\nawait client.connect();\n```\n\n### Connection Status Checks\n\n```javascript\n// Check if client is ready to execute commands\nif (client.isReady) {\n  console.log('Client is ready');\n}\n\n// Check if underlying socket is open\nif (client.isOpen) {\n  console.log('Connection is open');\n}\n```\n\n### Duplicate Connection (for Pub/Sub)\n\n```javascript\nconst client = createClient();\nawait client.connect();\n\n// Create a duplicate connection for pub/sub\nconst subscriber = client.duplicate();\nawait subscriber.connect();\n```\n\n### Graceful Shutdown\n\n```javascript\n// Graceful disconnect\nawait client.quit();\n\n// Force disconnect\nawait client.disconnect();\n```\n\n---\n\n## Core API Surfaces\n\n## String Operations\n\n### Basic SET and GET\n\n```javascript\n// Set a string value\nawait client.set('key', 'value');\n\n// Get a string value\nconst value = await client.get('key');\nconsole.log(value); // 'value'\n```\n\n### SET with Options\n\n```javascript\n// Set with expiration (EX = seconds)\nawait client.set('session:123', 'user_data', {\n  EX: 3600 // expires in 1 hour\n});\n\n// Set with expiration (PX = milliseconds)\nawait client.set('temp:key', 'value', {\n  PX: 5000 // expires in 5 seconds\n});\n\n// Set only if key doesn't exist (NX)\nawait client.set('key', 'value', {\n  NX: true\n});\n\n// Set only if key exists (XX)\nawait client.set('key', 'new_value', {\n  XX: true\n});\n\n// Get old value and set new value\nconst oldValue = await client.set('key', 'new_value', {\n  GET: true\n});\n```\n\n### Multiple Keys\n\n```javascript\n// Set multiple keys at once\nawait client.mSet({\n  'key1': 'value1',\n  'key2': 'value2',\n  'key3': 'value3'\n});\n\n// Get multiple keys at once\nconst values = await client.mGet(['key1', 'key2', 'key3']);\nconsole.log(values); // ['value1', 'value2', 'value3']\n```\n\n### Increment and Decrement\n\n```javascript\n// Set initial value\nawait client.set('counter', 0);\n\n// Increment by 1\nawait client.incr('counter'); // Returns 1\n\n// Increment by specific amount\nawait client.incrBy('counter', 10); // Returns 11\n\n// Increment float\nawait client.incrByFloat('price', 2.5); // Increment by 2.5\n\n// Decrement by 1\nawait client.decr('counter');\n\n// Decrement by specific amount\nawait client.decrBy('counter', 5);\n```\n\n### String Manipulation\n\n```javascript\n// Append to string\nawait client.set('message', 'Hello');\nawait client.append('message', ' World'); // 'Hello World'\n\n// Get substring\nconst substr = await client.getRange('message', 0, 4); // 'Hello'\n\n// Get length\nconst len = await client.strLen('message'); // 11\n\n// Set range\nawait client.setRange('message', 6, 'Redis'); // 'Hello Redis'\n```\n\n---\n\n## Hash Operations\n\n### Basic Hash Operations\n\n```javascript\n// Set a single field in a hash\nawait client.hSet('user:1000', 'name', 'John Doe');\n\n// Get a single field from a hash\nconst name = await client.hGet('user:1000', 'name');\nconsole.log(name); // 'John Doe'\n\n// Set multiple fields at once\nawait client.hSet('user:1000', {\n  name: 'John Doe',\n  email: '[email protected]',\n  age: 30\n});\n\n// Get all fields and values\nconst user = await client.hGetAll('user:1000');\nconsole.log(user);\n// { name: 'John Doe', email: '[email protected]', age: '30' }\n```\n\n### Advanced Hash Operations\n\n```javascript\n// Check if field exists\nconst exists = await client.hExists('user:1000', 'email'); // true\n\n// Get all field names\nconst fields = await client.hKeys('user:1000');\n// ['name', 'email', 'age']\n\n// Get all values\nconst values = await client.hVals('user:1000');\n// ['John Doe', '[email protected]', '30']\n\n// Get number of fields\nconst count = await client.hLen('user:1000'); // 3\n\n// Get multiple fields\nconst userData = await client.hmGet('user:1000', ['name', 'email']);\n// ['John Doe', '[email protected]']\n\n// Delete fields\nawait client.hDel('user:1000', 'age');\n\n// Increment numeric field\nawait client.hSet('user:1000', 'loginCount', 0);\nawait client.hIncrBy('user:1000', 'loginCount', 1); // 1\n\n// Increment float field\nawait client.hIncrByFloat('user:1000', 'balance', 10.50);\n\n// Set only if field doesn't exist\nawait client.hSetNX('user:1000', 'created', Date.now());\n```\n\n### Scan Hash Fields\n\n```javascript\n// Scan hash fields (for large hashes)\nfor await (const { field, value } of client.hScanIterator('user:1000')) {\n  console.log(`${field}: ${value}`);\n}\n```\n\n---\n\n## List Operations\n\n### Basic List Operations\n\n```javascript\n// Push elements to the right (end) of list\nawait client.rPush('tasks', 'task1');\nawait client.rPush('tasks', ['task2', 'task3']); // Multiple values\n\n// Push elements to the left (beginning) of list\nawait client.lPush('tasks', 'urgent_task');\nawait client.lPush('tasks', ['task0', 'task-1']);\n\n// Get list length\nconst length = await client.lLen('tasks');\n\n// Get range of elements\nconst tasks = await client.lRange('tasks', 0, -1); // Get all\nconst firstThree = await client.lRange('tasks', 0, 2); // Get first 3\n\n// Get element by index\nconst task = await client.lIndex('tasks', 0);\n\n// Pop from right (end)\nconst lastTask = await client.rPop('tasks');\n\n// Pop from left (beginning)\nconst firstTask = await client.lPop('tasks');\n```\n\n### Advanced List Operations\n\n```javascript\n// Blocking pop (wait for element)\nconst task = await client.blPop('tasks', 10); // Wait up to 10 seconds\n// Returns: { key: 'tasks', element: 'task1' }\n\nconst taskRight = await client.brPop('tasks', 10);\n\n// Set element at index\nawait client.lSet('tasks', 0, 'updated_task');\n\n// Insert before/after element\nawait client.lInsert('tasks', 'BEFORE', 'task2', 'new_task');\nawait client.lInsert('tasks', 'AFTER', 'task2', 'another_task');\n\n// Remove elements\nawait client.lRem('tasks', 2, 'task1'); // Remove first 2 occurrences\nawait client.lRem('tasks', -1, 'task2'); // Remove last occurrence\nawait client.lRem('tasks', 0, 'task3'); // Remove all occurrences\n\n// Trim list to range\nawait client.lTrim('tasks', 0, 9); // Keep only first 10 elements\n\n// Move element between lists\nconst element = await client.rPopLPush('source', 'destination');\n\n// Blocking move\nconst moved = await client.brPopLPush('source', 'destination', 5);\n```\n\n---\n\n## Set Operations\n\n### Basic Set Operations\n\n```javascript\n// Add members to set\nawait client.sAdd('tags', 'javascript');\nawait client.sAdd('tags', ['nodejs', 'redis', 'database']);\n\n// Check if member exists\nconst exists = await client.sIsMember('tags', 'nodejs'); // true\n\n// Get all members\nconst allTags = await client.sMembers('tags');\n// ['javascript', 'nodejs', 'redis', 'database']\n\n// Get number of members\nconst count = await client.sCard('tags'); // 4\n\n// Remove members\nawait client.sRem('tags', 'database');\nawait client.sRem('tags', ['nodejs', 'redis']);\n\n// Pop random member\nconst randomTag = await client.sPop('tags');\n\n// Get random member without removing\nconst random = await client.sRandMember('tags');\nconst randomThree = await client.sRandMemberCount('tags', 3);\n```\n\n### Set Operations Between Multiple Sets\n\n```javascript\n// Create sets\nawait client.sAdd('set1', ['a', 'b', 'c']);\nawait client.sAdd('set2', ['b', 'c', 'd']);\nawait client.sAdd('set3', ['c', 'd', 'e']);\n\n// Union (combine all unique members)\nconst union = await client.sUnion(['set1', 'set2']);\n// ['a', 'b', 'c', 'd']\n\n// Store union in new set\nawait client.sUnionStore('result', ['set1', 'set2']);\n\n// Intersection (common members)\nconst inter = await client.sInter(['set1', 'set2']);\n// ['b', 'c']\n\n// Store intersection\nawait client.sInterStore('result', ['set1', 'set2']);\n\n// Difference (members in first set but not in others)\nconst diff = await client.sDiff(['set1', 'set2']);\n// ['a']\n\n// Store difference\nawait client.sDiffStore('result', ['set1', 'set2']);\n\n// Move member between sets\nawait client.sMove('set1', 'set2', 'a');\n```\n\n### Scan Set Members\n\n```javascript\n// Scan set members (for large sets)\nfor await (const member of client.sScanIterator('tags')) {\n  console.log(member);\n}\n```\n\n---\n\n## Sorted Set Operations\n\n### Basic Sorted Set Operations\n\n```javascript\n// Add members with scores\nawait client.zAdd('leaderboard', { score: 100, value: 'player1' });\nawait client.zAdd('leaderboard', [\n  { score: 200, value: 'player2' },\n  { score: 150, value: 'player3' }\n]);\n\n// Get rank (0-based, lowest to highest)\nconst rank = await client.zRank('leaderboard', 'player1'); // 0\n\n// Get reverse rank (highest to lowest)\nconst revRank = await client.zRevRank('leaderboard', 'player2'); // 0\n\n// Get score\nconst score = await client.zScore('leaderboard', 'player2'); // 200\n\n// Get number of members\nconst count = await client.zCard('leaderboard'); // 3\n\n// Increment score\nawait client.zIncrBy('leaderboard', 50, 'player1'); // 150\n```\n\n### Range Queries\n\n```javascript\n// Get range by rank (lowest to highest)\nconst bottom3 = await client.zRange('leaderboard', 0, 2);\n// ['player1', 'player3', 'player2']\n\n// Get range with scores\nconst withScores = await client.zRangeWithScores('leaderboard', 0, 2);\n// [{ value: 'player1', score: 150 }, ...]\n\n// Get range by rank (highest to lowest)\nconst top3 = await client.zRevRange('leaderboard', 0, 2);\n\n// Get range by score\nconst range = await client.zRangeByScore('leaderboard', 100, 200);\n\n// Get range by score with limit\nconst limited = await client.zRangeByScore('leaderboard', 100, 200, {\n  LIMIT: {\n    offset: 0,\n    count: 10\n  }\n});\n\n// Get reverse range by score\nconst revRange = await client.zRevRangeByScore('leaderboard', 200, 100);\n```\n\n### Advanced Sorted Set Operations\n\n```javascript\n// Count members in score range\nconst count = await client.zCount('leaderboard', 100, 200);\n\n// Count members by lexicographical range\nconst lexCount = await client.zLexCount('leaderboard', '[a', '[z');\n\n// Remove members\nawait client.zRem('leaderboard', 'player1');\nawait client.zRem('leaderboard', ['player2', 'player3']);\n\n// Remove by rank range\nawait client.zRemRangeByRank('leaderboard', 0, 1); // Remove bottom 2\n\n// Remove by score range\nawait client.zRemRangeByScore('leaderboard', 0, 100);\n\n// Pop highest/lowest scoring member\nconst highest = await client.zPopMax('leaderboard');\nconst lowest = await client.zPopMin('leaderboard');\n\n// Pop with count\nconst top3 = await client.zPopMax('leaderboard', 3);\n\n// Blocking pop\nconst member = await client.bzPopMax('leaderboard', 5); // Wait up to 5 sec\nconst minMember = await client.bzPopMin('leaderboard', 5);\n```\n\n### Sorted Set Operations Between Multiple Sets\n\n```javascript\n// Union of sorted sets\nawait client.zUnionStore('result', ['set1', 'set2']);\n\n// Union with weights\nawait client.zUnionStore('result', ['set1', 'set2'], {\n  WEIGHTS: [2, 3]\n});\n\n// Union with aggregate function\nawait client.zUnionStore('result', ['set1', 'set2'], {\n  AGGREGATE: 'MAX' // or 'MIN', 'SUM'\n});\n\n// Intersection\nawait client.zInterStore('result', ['set1', 'set2']);\n\n// Intersection with weights and aggregate\nawait client.zInterStore('result', ['set1', 'set2'], {\n  WEIGHTS: [1, 2],\n  AGGREGATE: 'SUM'\n});\n```\n\n### Scan Sorted Set\n\n```javascript\n// Scan sorted set members\nfor await (const member of client.zScanIterator('leaderboard')) {\n  console.log(member);\n}\n```\n\n---\n\n## Key Management Operations\n\n### Key Operations\n\n```javascript\n// Check if key exists\nconst exists = await client.exists('mykey'); // 1 if exists, 0 if not\nconst multiExists = await client.exists(['key1', 'key2']); // Count\n\n// Delete keys\nawait client.del('mykey');\nawait client.del(['key1', 'key2', 'key3']);\n\n// Set expiration in seconds\nawait client.expire('mykey', 60); // Expire in 60 seconds\n\n// Set expiration at specific timestamp\nconst timestamp = Math.floor(Date.now() / 1000) + 3600;\nawait client.expireAt('mykey', timestamp);\n\n// Set expiration in milliseconds\nawait client.pExpire('mykey', 60000); // 60 seconds\n\n// Get time to live in seconds\nconst ttl = await client.ttl('mykey'); // -1 if no expiration, -2 if not exists\n\n// Get time to live in milliseconds\nconst pttl = await client.pTtl('mykey');\n\n// Remove expiration\nawait client.persist('mykey');\n\n// Rename key\nawait client.rename('oldkey', 'newkey');\n\n// Rename only if new key doesn't exist\nconst renamed = await client.renameNX('oldkey', 'newkey');\n\n// Get key type\nconst type = await client.type('mykey'); // 'string', 'list', 'set', etc.\n\n// Get random key\nconst randomKey = await client.randomKey();\n```\n\n### Scanning Keys\n\n```javascript\n// Scan all keys (use instead of KEYS for production)\nconst keys = [];\nfor await (const key of client.scanIterator()) {\n  keys.push(key);\n}\n\n// Scan with pattern\nfor await (const key of client.scanIterator({\n  MATCH: 'user:*',\n  COUNT: 100\n})) {\n  console.log(key);\n}\n\n// Scan specific key type\nfor await (const key of client.scanIterator({\n  TYPE: 'string',\n  COUNT: 100\n})) {\n  console.log(key);\n}\n```\n\n---\n\n## Transactions\n\n### Basic Transaction (MULTI/EXEC)\n\n```javascript\n// Execute multiple commands atomically\nawait client.set('another-key', 'another-value');\n\nconst results = await client\n  .multi()\n  .set('key', 'value')\n  .get('another-key')\n  .incr('counter')\n  .exec();\n\nconsole.log(results); // ['OK', 'another-value', 1]\n```\n\n### Transaction with Error Handling\n\n```javascript\ntry {\n  const results = await client\n    .multi()\n    .set('key1', 'value1')\n    .set('key2', 'value2')\n    .get('key1')\n    .exec();\n\n  // Check each result\n  results.forEach((result, index) => {\n    if (result instanceof Error) {\n      console.error(`Command ${index} failed:`, result);\n    } else {\n      console.log(`Command ${index} result:`, result);\n    }\n  });\n} catch (error) {\n  console.error('Transaction failed:', error);\n}\n```\n\n### Transaction with WATCH (Optimistic Locking)\n\n```javascript\n// Watch a key for changes\nawait client.watch('balance');\n\nconst balance = parseInt(await client.get('balance'));\n\nif (balance >= 100) {\n  // This transaction will fail if 'balance' changed after WATCH\n  const results = await client\n    .multi()\n    .decrBy('balance', 100)\n    .incrBy('purchases', 1)\n    .exec();\n\n  if (results === null) {\n    console.log('Transaction aborted - balance was modified');\n  } else {\n    console.log('Purchase successful');\n  }\n} else {\n  await client.unwatch();\n  console.log('Insufficient balance');\n}\n```\n\n### Complex Transaction Example\n\n```javascript\nasync function transferMoney(fromAccount, toAccount, amount) {\n  await client.watch([fromAccount, toAccount]);\n\n  const fromBalance = parseFloat(await client.get(fromAccount));\n\n  if (fromBalance < amount) {\n    await client.unwatch();\n    throw new Error('Insufficient funds');\n  }\n\n  const results = await client\n    .multi()\n    .decrByFloat(fromAccount, amount)\n    .incrByFloat(toAccount, amount)\n    .exec();\n\n  if (results === null) {\n    throw new Error('Transaction failed - accounts modified during transfer');\n  }\n\n  return results;\n}\n\n// Usage\ntry {\n  await transferMoney('account:1', 'account:2', 50.00);\n  console.log('Transfer successful');\n} catch (error) {\n  console.error('Transfer failed:', error.message);\n}\n```\n\n---\n\n## Pipelining\n\n### Automatic Pipelining\n\nNode-redis automatically pipelines commands that are queued in the same tick:\n\n```javascript\n// These commands are automatically batched and sent together\nconst [result1, result2, result3] = await Promise.all([\n  client.set('key1', 'value1'),\n  client.set('key2', 'value2'),\n  client.get('key1')\n]);\n\nconsole.log(result1); // 'OK'\nconsole.log(result2); // 'OK'\nconsole.log(result3); // 'value1'\n```\n\n### Manual Pipelining with Multi (No Atomicity)\n\n```javascript\n// Execute commands as pipeline without transaction semantics\nconst results = await client\n  .multi()\n  .set('key1', 'value1')\n  .set('key2', 'value2')\n  .get('key1')\n  .mGet(['key1', 'key2'])\n  .exec();\n\nconsole.log(results);\n// ['OK', 'OK', 'value1', ['value1', 'value2']]\n```\n\n### Large Batch Operations\n\n```javascript\nasync function batchSetKeys(keyValuePairs) {\n  const pipeline = client.multi();\n\n  for (const [key, value] of Object.entries(keyValuePairs)) {\n    pipeline.set(key, value);\n  }\n\n  const results = await pipeline.exec();\n  return results;\n}\n\n// Usage\nconst data = {\n  'user:1': 'Alice',\n  'user:2': 'Bob',\n  'user:3': 'Charlie'\n};\n\nawait batchSetKeys(data);\n```\n\n---\n\n## Pub/Sub\n\n### Basic Subscriber\n\n```javascript\nimport { createClient } from 'redis';\n\nconst client = createClient();\nawait client.connect();\n\n// Create dedicated connection for subscribing\nconst subscriber = client.duplicate();\nawait subscriber.connect();\n\n// Subscribe to channel\nawait subscriber.subscribe('notifications', (message) => {\n  console.log('Received message:', message);\n});\n\nconsole.log('Subscribed to notifications channel');\n```\n\n### Basic Publisher\n\n```javascript\nimport { createClient } from 'redis';\n\nconst publisher = createClient();\nawait publisher.connect();\n\n// Publish messages\nawait publisher.publish('notifications', 'Hello, World!');\nawait publisher.publish('notifications', JSON.stringify({\n  type: 'alert',\n  message: 'System update'\n}));\n\nconsole.log('Messages published');\n```\n\n### Multiple Channels\n\n```javascript\n// Subscribe to multiple channels\nawait subscriber.subscribe('channel1', (message) => {\n  console.log('Channel1:', message);\n});\n\nawait subscriber.subscribe('channel2', (message) => {\n  console.log('Channel2:', message);\n});\n\nawait subscriber.subscribe('channel3', (message) => {\n  console.log('Channel3:', message);\n});\n```\n\n### Pattern-Based Subscription\n\n```javascript\n// Subscribe to channels matching pattern\nawait subscriber.pSubscribe('user:*', (message, channel) => {\n  console.log(`Message from ${channel}:`, message);\n});\n\n// Publish to matching channels\nawait publisher.publish('user:1000', 'User 1000 logged in');\nawait publisher.publish('user:2000', 'User 2000 logged out');\n```\n\n### Unsubscribe\n\n```javascript\n// Unsubscribe from specific channel\nawait subscriber.unsubscribe('channel1');\n\n// Unsubscribe from all channels\nawait subscriber.unsubscribe();\n\n// Unsubscribe from pattern\nawait subscriber.pUnsubscribe('user:*');\n```\n\n### Complete Pub/Sub Example\n\n```javascript\nimport { createClient } from 'redis';\n\n// Subscriber setup\nasync function setupSubscriber() {\n  const client = createClient();\n  await client.connect();\n\n  const subscriber = client.duplicate();\n  await subscriber.connect();\n\n  await subscriber.subscribe('chat:room1', (message) => {\n    const data = JSON.parse(message);\n    console.log(`${data.user}: ${data.text}`);\n  });\n\n  return subscriber;\n}\n\n// Publisher setup\nasync function setupPublisher() {\n  const publisher = createClient();\n  await publisher.connect();\n  return publisher;\n}\n\n// Usage\nconst subscriber = await setupSubscriber();\nconst publisher = await setupPublisher();\n\n// Publish chat messages\nawait publisher.publish('chat:room1', JSON.stringify({\n  user: 'Alice',\n  text: 'Hello everyone!'\n}));\n\nawait publisher.publish('chat:room1', JSON.stringify({\n  user: 'Bob',\n  text: 'Hi Alice!'\n}));\n```\n\n---\n\n## Redis Streams\n\n### Add to Stream (XADD)\n\n```javascript\n// Add entry to stream\nconst id = await client.xAdd('events', '*', {\n  user: 'alice',\n  action: 'login',\n  timestamp: Date.now()\n});\n\nconsole.log('Entry ID:', id); // '1234567890123-0'\n\n// Add with specific ID\nawait client.xAdd('events', '1234567890123-1', {\n  user: 'bob',\n  action: 'logout'\n});\n\n// Add with maxLen (limit stream size)\nawait client.xAdd('events', '*', {\n  user: 'charlie',\n  action: 'signup'\n}, {\n  TRIM: {\n    strategy: 'MAXLEN',\n    strategyModifier: '~', // Approximate\n    threshold: 1000\n  }\n});\n```\n\n### Read from Stream (XREAD)\n\n```javascript\n// Read new entries\nconst messages = await client.xRead(\n  { key: 'events', id: '0' },\n  { COUNT: 10 }\n);\n\nconsole.log(messages);\n// [{ name: 'events', messages: [{ id: '...', message: {...} }] }]\n\n// Read from multiple streams\nconst multiStream = await client.xRead([\n  { key: 'stream1', id: '0' },\n  { key: 'stream2', id: '0' }\n]);\n\n// Blocking read (wait for new entries)\nconst newMessages = await client.xRead(\n  { key: 'events', id: '$' }, // '$' means only new messages\n  { BLOCK: 5000 } // Wait up to 5 seconds\n);\n```\n\n### Stream Range Queries\n\n```javascript\n// Read all entries\nconst all = await client.xRange('events', '-', '+');\n\n// Read range with IDs\nconst range = await client.xRange('events', '1234567890000', '1234567899999');\n\n// Read with limit\nconst limited = await client.xRange('events', '-', '+', { COUNT: 100 });\n\n// Reverse range\nconst reverse = await client.xRevRange('events', '+', '-', { COUNT: 10 });\n```\n\n### Stream Length and Info\n\n```javascript\n// Get stream length\nconst length = await client.xLen('events');\n\n// Get stream info\nconst info = await client.xInfo('events');\n```\n\n### Consumer Groups\n\n```javascript\n// Create consumer group\nawait client.xGroupCreate('events', 'processors', '0', {\n  MKSTREAM: true // Create stream if it doesn't exist\n});\n\n// Read as consumer group\nconst messages = await client.xReadGroup(\n  'processors',\n  'consumer1',\n  { key: 'events', id: '>' }, // '>' means undelivered messages\n  { COUNT: 10, BLOCK: 5000 }\n);\n\n// Process messages and acknowledge\nfor (const stream of messages) {\n  for (const message of stream.messages) {\n    // Process message\n    console.log('Processing:', message.id, message.message);\n\n    // Acknowledge message\n    await client.xAck('events', 'processors', message.id);\n  }\n}\n```\n\n### Delete from Stream\n\n```javascript\n// Delete specific entries\nawait client.xDel('events', ['1234567890123-0', '1234567890123-1']);\n\n// Trim stream\nawait client.xTrim('events', 'MAXLEN', 1000);\n\n// Approximate trim\nawait client.xTrim('events', 'MAXLEN', { strategyModifier: '~', threshold: 1000 });\n```\n\n### Complete Stream Example\n\n```javascript\nimport { createClient } from 'redis';\n\nconst client = createClient();\nawait client.connect();\n\n// Producer\nasync function addEvent(eventData) {\n  return await client.xAdd('events', '*', eventData);\n}\n\n// Consumer with consumer group\nasync function processEvents() {\n  // Create group if not exists\n  try {\n    await client.xGroupCreate('events', 'workers', '0', { MKSTREAM: true });\n  } catch (err) {\n    // Group already exists\n  }\n\n  while (true) {\n    const messages = await client.xReadGroup(\n      'workers',\n      'worker1',\n      { key: 'events', id: '>' },\n      { COUNT: 10, BLOCK: 5000 }\n    );\n\n    if (messages && messages.length > 0) {\n      for (const stream of messages) {\n        for (const message of stream.messages) {\n          try {\n            // Process event\n            console.log('Processing event:', message.message);\n\n            // Acknowledge\n            await client.xAck('events', 'workers', message.id);\n          } catch (error) {\n            console.error('Error processing:', error);\n          }\n        }\n      }\n    }\n  }\n}\n\n// Usage\nawait addEvent({ type: 'user_login', user: 'alice' });\nawait addEvent({ type: 'user_logout', user: 'bob' });\n\n// Start consumer\nprocessEvents();\n```\n\n---\n\n## Scripting with Lua\n\n### Basic Script Execution (EVAL)\n\n```javascript\n// Execute Lua script\nconst result = await client.eval(\n  `return redis.call('SET', KEYS[1], ARGV[1])`,\n  {\n    keys: ['mykey'],\n    arguments: ['myvalue']\n  }\n);\n\nconsole.log(result); // 'OK'\n```\n\n### Script with Multiple Operations\n\n```javascript\nconst script = `\n  local current = redis.call('GET', KEYS[1])\n  if current == false then\n    current = 0\n  end\n  local new = tonumber(current) + tonumber(ARGV[1])\n  redis.call('SET', KEYS[1], new)\n  return new\n`;\n\nconst newValue = await client.eval(script, {\n  keys: ['counter'],\n  arguments: ['5']\n});\n\nconsole.log('New counter value:', newValue);\n```\n\n### Load and Execute Scripts (SCRIPT LOAD / EVALSHA)\n\n```javascript\n// Load script and get SHA1\nconst sha = await client.scriptLoad(`\n  return redis.call('GET', KEYS[1])\n`);\n\nconsole.log('Script SHA:', sha);\n\n// Execute by SHA1 (more efficient for repeated calls)\nconst value = await client.evalSha(sha, {\n  keys: ['mykey'],\n  arguments: []\n});\n```\n\n### Rate Limiting with Lua Script\n\n```javascript\nconst rateLimitScript = `\n  local key = KEYS[1]\n  local limit = tonumber(ARGV[1])\n  local window = tonumber(ARGV[2])\n  local current = redis.call('INCR', key)\n  if current == 1 then\n    redis.call('EXPIRE', key, window)\n  end\n  if current > limit then\n    return 0\n  else\n    return 1\n  end\n`;\n\nasync function checkRateLimit(userId, limit = 10, window = 60) {\n  const allowed = await client.eval(rateLimitScript, {\n    keys: [`ratelimit:${userId}`],\n    arguments: [limit.toString(), window.toString()]\n  });\n\n  return allowed === 1;\n}\n\n// Usage\nconst allowed = await checkRateLimit('user:1000', 10, 60);\nif (allowed) {\n  console.log('Request allowed');\n} else {\n  console.log('Rate limit exceeded');\n}\n```\n\n### Atomic Get and Delete\n\n```javascript\nconst getAndDelete = `\n  local value = redis.call('GET', KEYS[1])\n  if value then\n    redis.call('DEL', KEYS[1])\n  end\n  return value\n`;\n\nconst value = await client.eval(getAndDelete, {\n  keys: ['temp:key'],\n  arguments: []\n});\n```\n\n---\n\n## JSON Support (RedisJSON)\n\n### Basic JSON Operations\n\n```javascript\n// Set JSON document\nawait client.json.set('user:1', '$', {\n  name: 'John Doe',\n  email: '[email protected]',\n  age: 30,\n  tags: ['developer', 'redis']\n});\n\n// Get entire JSON document\nconst user = await client.json.get('user:1');\nconsole.log(user);\n\n// Get specific path\nconst name = await client.json.get('user:1', { path: '$.name' });\nconst age = await client.json.get('user:1', { path: '$.age' });\n```\n\n### Update JSON Fields\n\n```javascript\n// Set specific field\nawait client.json.set('user:1', '$.email', '\"[email protected]\"');\n\n// Update nested field\nawait client.json.set('user:1', '$.address.city', '\"New York\"');\n\n// Delete field\nawait client.json.del('user:1', '$.age');\n```\n\n### JSON Array Operations\n\n```javascript\n// Append to array\nawait client.json.arrAppend('user:1', '$.tags', '\"nodejs\"', '\"javascript\"');\n\n// Get array length\nconst length = await client.json.arrLen('user:1', '$.tags');\n\n// Pop from array\nawait client.json.arrPop('user:1', '$.tags', -1); // Pop last element\n\n// Insert into array\nawait client.json.arrInsert('user:1', '$.tags', 0, '\"beginner\"');\n```\n\n### JSON Numeric Operations\n\n```javascript\n// Increment numeric value\nawait client.json.numIncrBy('user:1', '$.loginCount', 1);\n\n// Multiply numeric value\nawait client.json.numMultBy('user:1', '$.score', 1.5);\n```\n\n---\n\n## Time Series (RedisTimeSeries)\n\n### Basic Time Series Operations\n\n```javascript\n// Create time series\nawait client.ts.create('temperature:sensor1', {\n  RETENTION: 86400000, // Retain for 24 hours\n  LABELS: { sensor: 'temp', location: 'room1' }\n});\n\n// Add data points\nawait client.ts.add('temperature:sensor1', '*', 22.5); // Current time\nawait client.ts.add('temperature:sensor1', Date.now(), 23.0); // Specific time\n\n// Add multiple data points\nawait client.ts.mAdd([\n  { key: 'temperature:sensor1', timestamp: '*', value: 22.8 },\n  { key: 'temperature:sensor2', timestamp: '*', value: 21.5 }\n]);\n```\n\n### Query Time Series\n\n```javascript\n// Get range of data\nconst data = await client.ts.range('temperature:sensor1', '-', '+');\n\n// Get range with aggregation\nconst hourlyAvg = await client.ts.range('temperature:sensor1', '-', '+', {\n  AGGREGATION: {\n    type: 'AVG',\n    timeBucket: 3600000 // 1 hour\n  }\n});\n\n// Get last value\nconst latest = await client.ts.get('temperature:sensor1');\n```\n\n---\n\n## Search and Query (RediSearch)\n\n### Create Index\n\n```javascript\n// Create index on hash\nawait client.ft.create('idx:users', {\n  '$.name': {\n    type: 'TEXT',\n    AS: 'name'\n  },\n  '$.age': {\n    type: 'NUMERIC',\n    AS: 'age'\n  },\n  '$.email': {\n    type: 'TAG',\n    AS: 'email'\n  }\n}, {\n  ON: 'HASH',\n  PREFIX: 'user:'\n});\n```\n\n### Search Documents\n\n```javascript\n// Search by text\nconst results = await client.ft.search('idx:users', 'John');\n\n// Search with filters\nconst filtered = await client.ft.search('idx:users', '@age:[25 35]');\n\n// Search with multiple conditions\nconst complex = await client.ft.search('idx:users', '@name:John @age:[20 40]');\n\n// Get search count\nconst count = await client.ft.search('idx:users', '*', { LIMIT: { from: 0, size: 0 } });\n```\n\n---\n\n## Geospatial Operations\n\n### Add Geo Points\n\n```javascript\n// Add location\nawait client.geoAdd('locations', {\n  longitude: -122.4194,\n  latitude: 37.7749,\n  member: 'San Francisco'\n});\n\n// Add multiple locations\nawait client.geoAdd('locations', [\n  { longitude: -118.2437, latitude: 34.0522, member: 'Los Angeles' },\n  { longitude: -73.9352, latitude: 40.7306, member: 'New York' }\n]);\n```\n\n### Query Geo Points\n\n```javascript\n// Get position\nconst position = await client.geoPos('locations', 'San Francisco');\nconsole.log(position); // [{ longitude: -122.4194, latitude: 37.7749 }]\n\n// Get distance between points\nconst distance = await client.geoDist('locations', 'San Francisco', 'Los Angeles', 'mi');\nconsole.log(`Distance: ${distance} miles`);\n\n// Search by radius\nconst nearby = await client.geoRadius('locations', {\n  longitude: -122.4194,\n  latitude: 37.7749\n}, 500, 'mi');\n\n// Search by member\nconst nearSF = await client.geoRadiusByMember('locations', 'San Francisco', 600, 'mi', {\n  WITHDIST: true,\n  WITHCOORD: true\n});\n```\n\n---\n\n## HyperLogLog (Cardinality Estimation)\n\n```javascript\n// Add elements\nawait client.pfAdd('unique:visitors', ['user1', 'user2', 'user3']);\nawait client.pfAdd('unique:visitors', ['user2', 'user4']); // user2 counted once\n\n// Get count\nconst count = await client.pfCount('unique:visitors'); // ~4\n\n// Merge multiple HyperLogLogs\nawait client.pfMerge('combined', ['unique:visitors:day1', 'unique:visitors:day2']);\n```\n\n---\n\n## Bitmap Operations\n\n```javascript\n// Set bit\nawait client.setBit('login:2024-01-15', 100, 1); // User 100 logged in\n\n// Get bit\nconst bit = await client.getBit('login:2024-01-15', 100); // 1\n\n// Count set bits\nconst count = await client.bitCount('login:2024-01-15');\n\n// Bitwise operations\nawait client.bitOp('AND', 'result', ['bitmap1', 'bitmap2']);\nawait client.bitOp('OR', 'result', ['bitmap1', 'bitmap2']);\nawait client.bitOp('XOR', 'result', ['bitmap1', 'bitmap2']);\n\n// Find first bit\nconst pos = await client.bitPos('login:2024-01-15', 1); // First set bit\n```\n\n---\n\n## Server and Connection Management\n\n### Server Information\n\n```javascript\n// Get server info\nconst info = await client.info();\nconsole.log(info);\n\n// Get specific section\nconst stats = await client.info('stats');\nconst memory = await client.info('memory');\n\n// Ping server\nconst pong = await client.ping(); // 'PONG'\n\n// Get server time\nconst time = await client.time();\n```\n\n### Database Management\n\n```javascript\n// Select database (0-15 by default)\nawait client.select(1);\n\n// Get database size\nconst size = await client.dbSize();\n\n// Flush current database\nawait client.flushDb();\n\n// Flush all databases\nawait client.flushAll();\n\n// Save database to disk\nawait client.save();\n\n// Background save\nawait client.bgSave();\n\n// Get last save time\nconst lastSave = await client.lastSave();\n```\n\n### Client Management\n\n```javascript\n// Get client list\nconst clients = await client.clientList();\n\n// Get client ID\nconst id = await client.clientId();\n\n// Set client name\nawait client.clientSetName('my-app');\n\n// Get client name\nconst name = await client.clientGetName();\n\n// Get client info\nconst clientInfo = await client.clientInfo();\n```\n\n---\n\n## Error Handling\n\n### Connection Errors\n\n```javascript\nimport { createClient } from 'redis';\n\nconst client = createClient({\n  socket: {\n    host: 'localhost',\n    port: 6379,\n    reconnectStrategy: (retries) => {\n      if (retries > 10) {\n        return new Error('Max retries reached');\n      }\n      return Math.min(retries * 100, 3000);\n    }\n  }\n});\n\nclient.on('error', (err) => {\n  console.error('Redis error:', err);\n});\n\nclient.on('connect', () => {\n  console.log('Connected to Redis');\n});\n\nclient.on('reconnecting', () => {\n  console.log('Reconnecting to Redis...');\n});\n\nclient.on('ready', () => {\n  console.log('Redis client ready');\n});\n\nawait client.connect();\n```\n\n### Command Errors\n\n```javascript\ntry {\n  await client.get('nonexistent');\n} catch (error) {\n  console.error('Command error:', error);\n}\n\n// Multiple operations with individual error handling\nconst results = await client.multi()\n  .set('key1', 'value1')\n  .incr('not-a-number') // This will error\n  .get('key1')\n  .exec();\n\nresults.forEach((result, i) => {\n  if (result instanceof Error) {\n    console.error(`Command ${i} failed:`, result.message);\n  } else {\n    console.log(`Command ${i} result:`, result);\n  }\n});\n```\n\n---\n\n## Connection Pooling and Performance\n\n### Configure Connection Pool\n\n```javascript\nconst client = createClient({\n  socket: {\n    host: 'localhost',\n    port: 6379,\n    connectTimeout: 5000,\n    keepAlive: 5000\n  },\n  password: 'your_password'\n});\n```\n\n### Readonly Replicas\n\n```javascript\nconst client = createClient({\n  socket: {\n    host: 'localhost',\n    port: 6379\n  }\n});\n\n// Send read commands to replicas\nawait client.sendCommand(['READONLY']);\n```\n\n---\n\n## Cluster Support\n\n### Connect to Cluster\n\n```javascript\nimport { createCluster } from 'redis';\n\nconst cluster = createCluster({\n  rootNodes: [\n    { url: 'redis://localhost:7000' },\n    { url: 'redis://localhost:7001' },\n    { url: 'redis://localhost:7002' }\n  ]\n});\n\ncluster.on('error', (err) => console.error('Cluster error:', err));\n\nawait cluster.connect();\n\n// Use cluster like regular client\nawait cluster.set('key', 'value');\nconst value = await cluster.get('key');\n\nawait cluster.quit();\n```\n\n---\n\n## Complete Application Example\n\n```javascript\nimport { createClient } from 'redis';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nclass RedisManager {\n  constructor() {\n    this.client = null;\n    this.subscriber = null;\n  }\n\n  async connect() {\n    this.client = createClient({\n      url: process.env.REDIS_URL || 'redis://localhost:6379',\n      password: process.env.REDIS_PASSWORD\n    });\n\n    this.client.on('error', (err) => {\n      console.error('Redis Client Error:', err);\n    });\n\n    await this.client.connect();\n    console.log('Connected to Redis');\n  }\n\n  async cacheGet(key) {\n    const value = await this.client.get(key);\n    return value ? JSON.parse(value) : null;\n  }\n\n  async cacheSet(key, value, ttl = 3600) {\n    await this.client.set(key, JSON.stringify(value), { EX: ttl });\n  }\n\n  async invalidateCache(pattern) {\n    const keys = [];\n    for await (const key of this.client.scanIterator({ MATCH: pattern })) {\n      keys.push(key);\n    }\n    if (keys.length > 0) {\n      await this.client.del(keys);\n    }\n  }\n\n  async trackUserActivity(userId, action) {\n    const key = `activity:${userId}:${new Date().toISOString().split('T')[0]}`;\n    await this.client.rPush(key, JSON.stringify({\n      action,\n      timestamp: Date.now()\n    }));\n    await this.client.expire(key, 86400 * 7); // Keep for 7 days\n  }\n\n  async getUserActivity(userId, date) {\n    const key = `activity:${userId}:${date}`;\n    const activities = await this.client.lRange(key, 0, -1);\n    return activities.map(a => JSON.parse(a));\n  }\n\n  async incrementPageView(pageId) {\n    await this.client.incr(`pageviews:${pageId}`);\n  }\n\n  async getPageViews(pageId) {\n    const views = await this.client.get(`pageviews:${pageId}`);\n    return parseInt(views || '0');\n  }\n\n  async addToLeaderboard(userId, score) {\n    await this.client.zAdd('leaderboard', { score, value: userId });\n  }\n\n  async getLeaderboard(count = 10) {\n    const results = await this.client.zRangeWithScores('leaderboard', 0, count - 1, {\n      REV: true\n    });\n    return results.map(r => ({ userId: r.value, score: r.score }));\n  }\n\n  async disconnect() {\n    if (this.subscriber) {\n      await this.subscriber.quit();\n    }\n    if (this.client) {\n      await this.client.quit();\n    }\n    console.log('Disconnected from Redis');\n  }\n}\n\n// Usage\nconst redis = new RedisManager();\nawait redis.connect();\n\n// Cache operations\nawait redis.cacheSet('user:1000', { name: 'John', email: '[email protected]' });\nconst user = await redis.cacheGet('user:1000');\nconsole.log(user);\n\n// Track activity\nawait redis.trackUserActivity('user:1000', 'login');\nawait redis.trackUserActivity('user:1000', 'view_profile');\n\n// Get activity\nconst today = new Date().toISOString().split('T')[0];\nconst activities = await redis.getUserActivity('user:1000', today);\nconsole.log(activities);\n\n// Leaderboard\nawait redis.addToLeaderboard('user:1000', 500);\nawait redis.addToLeaderboard('user:2000', 750);\nawait redis.addToLeaderboard('user:3000', 250);\n\nconst topUsers = await redis.getLeaderboard(3);\nconsole.log('Top users:', topUsers);\n\nawait redis.disconnect();\n```\n"
  },
  {
    "path": "content/redis/docs/key-value/python/DOC.md",
    "content": "---\nname: key-value\ndescription: \"Redis Python client (redis-py) for key-value storage, caching, and pub/sub messaging\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.0.1\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"redis,database,cache,key-value,pubsub\"\n---\n\n# Redis Python Client (redis-py) - Complete Integration Guide\n\n## GOLDEN RULE\n\n**ALWAYS use the official `redis` package (redis-py) for Redis integration.**\n\n```bash\npip install redis\n```\n\n**For enhanced performance, install with hiredis support:**\n\n```bash\npip install redis[hiredis]\n```\n\n**DO NOT use:**\n- `redis-py-cluster` (deprecated, functionality merged into redis-py)\n- `aioredis` (deprecated, async support now in redis-py)\n- `walrus` (third-party wrapper)\n- Any other unofficial Redis clients\n\nThe official `redis` package is maintained by Redis and supports both synchronous and asynchronous operations.\n\n---\n\n## Installation\n\n### Basic Installation\n\n```bash\npip install redis\n```\n\n### Installation with Performance Optimization\n\n```bash\npip install redis[hiredis]\n```\n\nThe hiredis library provides a compiled response parser that significantly improves performance.\n\n### Installation with All Optional Dependencies\n\n```bash\npip install redis[hiredis,cryptography]\n```\n\n### Environment Setup\n\nCreate a `.env` file in your project root:\n\n```env\nREDIS_HOST=localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=your_password_here\nREDIS_DB=0\nREDIS_URL=redis://username:password@localhost:6379/0\n```\n\nInstall python-dotenv to load environment variables:\n\n```bash\npip install python-dotenv\n```\n\n---\n\n## Initialization\n\n### Basic Connection (Localhost)\n\n```python\nimport redis\n\nr = redis.Redis(host='localhost', port=6379, decode_responses=True)\n\n# Test connection\nr.ping()  # Returns True\n\n# Use the client...\n\nr.close()\n```\n\n### Connection with Environment Variables\n\n```python\nimport redis\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nr = redis.Redis(\n    host=os.getenv('REDIS_HOST', 'localhost'),\n    port=int(os.getenv('REDIS_PORT', 6379)),\n    password=os.getenv('REDIS_PASSWORD'),\n    db=int(os.getenv('REDIS_DB', 0)),\n    decode_responses=True\n)\n\nr.ping()\n```\n\n### Connection Using URL\n\n```python\nimport redis\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nredis_url = os.getenv('REDIS_URL', 'redis://localhost:6379/0')\nr = redis.from_url(redis_url, decode_responses=True)\n\nr.ping()\n```\n\n### Connection with Authentication\n\n```python\nimport redis\n\nr = redis.Redis(\n    host='redis.example.com',\n    port=6379,\n    username='default',\n    password='your_password',\n    db=0,\n    decode_responses=True\n)\n```\n\n### Connection with TLS/SSL\n\n```python\nimport redis\nimport ssl\n\nr = redis.Redis(\n    host='redis.example.com',\n    port=6380,\n    password='your_password',\n    ssl=True,\n    ssl_certfile='/path/to/client-cert.pem',\n    ssl_keyfile='/path/to/client-key.pem',\n    ssl_ca_certs='/path/to/ca-cert.pem',\n    ssl_cert_reqs=ssl.CERT_REQUIRED,\n    decode_responses=True\n)\n```\n\n### Connection Pool\n\n```python\nimport redis\n\n# Create connection pool\npool = redis.ConnectionPool(\n    host='localhost',\n    port=6379,\n    password='your_password',\n    db=0,\n    max_connections=10,\n    decode_responses=True\n)\n\n# Create client from pool\nr = redis.Redis(connection_pool=pool)\n\n# Multiple clients can share the pool\nr2 = redis.Redis(connection_pool=pool)\n```\n\n### Context Manager (Auto-Close)\n\n```python\nimport redis\n\nwith redis.Redis(host='localhost', port=6379, decode_responses=True) as r:\n    r.set('key', 'value')\n    value = r.get('key')\n    print(value)\n# Connection automatically closed\n```\n\n### Decode Responses\n\n```python\n# Without decode_responses (default - returns bytes)\nr = redis.Redis(host='localhost', port=6379)\nvalue = r.get('key')  # Returns: b'value'\n\n# With decode_responses (returns strings)\nr = redis.Redis(host='localhost', port=6379, decode_responses=True)\nvalue = r.get('key')  # Returns: 'value'\n```\n\n---\n\n## Core API Surfaces\n\n## String Operations\n\n### Basic SET and GET\n\n```python\n# Set a string value\nr.set('key', 'value')\n\n# Get a string value\nvalue = r.get('key')\nprint(value)  # 'value'\n```\n\n### SET with Options\n\n```python\n# Set with expiration (seconds)\nr.set('session:123', 'user_data', ex=3600)  # Expires in 1 hour\n\n# Set with expiration (milliseconds)\nr.set('temp:key', 'value', px=5000)  # Expires in 5 seconds\n\n# Set only if key doesn't exist (NX)\nresult = r.set('key', 'value', nx=True)  # Returns True if set, None if exists\n\n# Set only if key exists (XX)\nresult = r.set('key', 'new_value', xx=True)  # Returns True if set, None if not exists\n\n# Get old value and set new value\nold_value = r.set('key', 'new_value', get=True)  # Returns old value\n\n# Set with multiple options\nr.set('key', 'value', ex=60, nx=True)\n```\n\n### Multiple Keys\n\n```python\n# Set multiple keys at once\nr.mset({\n    'key1': 'value1',\n    'key2': 'value2',\n    'key3': 'value3'\n})\n\n# Get multiple keys at once\nvalues = r.mget(['key1', 'key2', 'key3'])\nprint(values)  # ['value1', 'value2', 'value3']\n\n# Set multiple only if none exist\nresult = r.msetnx({\n    'key4': 'value4',\n    'key5': 'value5'\n})  # Returns True if all set, False if any exist\n```\n\n### Increment and Decrement\n\n```python\n# Set initial value\nr.set('counter', 0)\n\n# Increment by 1\nr.incr('counter')  # Returns 1\n\n# Increment by specific amount\nr.incrby('counter', 10)  # Returns 11\n\n# Increment float\nr.incrbyfloat('price', 2.5)  # Increment by 2.5\n\n# Decrement by 1\nr.decr('counter')\n\n# Decrement by specific amount\nr.decrby('counter', 5)\n```\n\n### String Manipulation\n\n```python\n# Append to string\nr.set('message', 'Hello')\nr.append('message', ' World')  # 'Hello World'\n\n# Get substring\nsubstr = r.getrange('message', 0, 4)  # 'Hello'\n\n# Get length\nlength = r.strlen('message')  # 11\n\n# Set range\nr.setrange('message', 6, 'Redis')  # 'Hello Redis'\n\n# Get and delete\nvalue = r.getdel('message')  # Returns value and deletes key\n\n# Get and set expiration\nvalue = r.getex('key', ex=60)  # Returns value and sets expiration\n```\n\n---\n\n## Hash Operations\n\n### Basic Hash Operations\n\n```python\n# Set a single field in a hash\nr.hset('user:1000', 'name', 'John Doe')\n\n# Get a single field from a hash\nname = r.hget('user:1000', 'name')\nprint(name)  # 'John Doe'\n\n# Set multiple fields at once\nr.hset('user:1000', mapping={\n    'name': 'John Doe',\n    'email': '[email protected]',\n    'age': 30\n})\n\n# Get all fields and values\nuser = r.hgetall('user:1000')\nprint(user)\n# {'name': 'John Doe', 'email': '[email protected]', 'age': '30'}\n```\n\n### Advanced Hash Operations\n\n```python\n# Check if field exists\nexists = r.hexists('user:1000', 'email')  # True\n\n# Get all field names\nfields = r.hkeys('user:1000')\n# ['name', 'email', 'age']\n\n# Get all values\nvalues = r.hvals('user:1000')\n# ['John Doe', '[email protected]', '30']\n\n# Get number of fields\ncount = r.hlen('user:1000')  # 3\n\n# Get multiple fields\nuser_data = r.hmget('user:1000', ['name', 'email'])\n# ['John Doe', '[email protected]']\n\n# Delete fields\nr.hdel('user:1000', 'age')\nr.hdel('user:1000', 'field1', 'field2', 'field3')  # Multiple fields\n\n# Increment numeric field\nr.hset('user:1000', 'login_count', 0)\nr.hincrby('user:1000', 'login_count', 1)  # 1\n\n# Increment float field\nr.hincrbyfloat('user:1000', 'balance', 10.50)\n\n# Set only if field doesn't exist\nr.hsetnx('user:1000', 'created', '2024-01-01')\n\n# Get random field\nfield = r.hrandfield('user:1000')  # Random field name\nfields_and_values = r.hrandfield('user:1000', 2, withvalues=True)\n# [('name', 'John Doe'), ('email', '[email protected]')]\n```\n\n### Scan Hash Fields\n\n```python\n# Scan hash fields (for large hashes)\ncursor = 0\nwhile True:\n    cursor, fields = r.hscan('user:1000', cursor, count=10)\n    for field, value in fields.items():\n        print(f\"{field}: {value}\")\n    if cursor == 0:\n        break\n\n# Using hscan_iter (simpler)\nfor field, value in r.hscan_iter('user:1000', count=10):\n    print(f\"{field}: {value}\")\n```\n\n---\n\n## List Operations\n\n### Basic List Operations\n\n```python\n# Push elements to the right (end) of list\nr.rpush('tasks', 'task1')\nr.rpush('tasks', 'task2', 'task3')  # Multiple values\n\n# Push elements to the left (beginning) of list\nr.lpush('tasks', 'urgent_task')\nr.lpush('tasks', 'task0', 'task-1')\n\n# Get list length\nlength = r.llen('tasks')\n\n# Get range of elements\ntasks = r.lrange('tasks', 0, -1)  # Get all\nfirst_three = r.lrange('tasks', 0, 2)  # Get first 3\n\n# Get element by index\ntask = r.lindex('tasks', 0)\n\n# Pop from right (end)\nlast_task = r.rpop('tasks')\n\n# Pop from left (beginning)\nfirst_task = r.lpop('tasks')\n\n# Pop multiple elements\ntasks = r.lpop('tasks', count=3)  # Pop 3 elements\n```\n\n### Advanced List Operations\n\n```python\n# Blocking pop (wait for element)\ntask = r.blpop('tasks', timeout=10)  # Wait up to 10 seconds\n# Returns: ('tasks', 'task1') or None if timeout\n\ntask_right = r.brpop('tasks', timeout=10)\n\n# Block on multiple lists\ntask = r.blpop(['queue1', 'queue2', 'queue3'], timeout=5)\n\n# Set element at index\nr.lset('tasks', 0, 'updated_task')\n\n# Insert before/after element\nr.linsert('tasks', 'BEFORE', 'task2', 'new_task')\nr.linsert('tasks', 'AFTER', 'task2', 'another_task')\n\n# Remove elements\nr.lrem('tasks', 2, 'task1')  # Remove first 2 occurrences\nr.lrem('tasks', -1, 'task2')  # Remove last occurrence\nr.lrem('tasks', 0, 'task3')  # Remove all occurrences\n\n# Trim list to range\nr.ltrim('tasks', 0, 9)  # Keep only first 10 elements\n\n# Move element between lists\nelement = r.rpoplpush('source', 'destination')\n\n# Blocking move\nmoved = r.brpoplpush('source', 'destination', timeout=5)\n\n# Move element (new command)\nmoved = r.lmove('source', 'destination', 'LEFT', 'RIGHT')\nmoved = r.blmove('source', 'destination', 'RIGHT', 'LEFT', timeout=5)\n```\n\n---\n\n## Set Operations\n\n### Basic Set Operations\n\n```python\n# Add members to set\nr.sadd('tags', 'javascript')\nr.sadd('tags', 'nodejs', 'redis', 'database')\n\n# Check if member exists\nexists = r.sismember('tags', 'nodejs')  # True\n\n# Get all members\nall_tags = r.smembers('tags')\n# {'javascript', 'nodejs', 'redis', 'database'}\n\n# Get number of members\ncount = r.scard('tags')  # 4\n\n# Remove members\nr.srem('tags', 'database')\nr.srem('tags', 'nodejs', 'redis')\n\n# Pop random member\nrandom_tag = r.spop('tags')\n\n# Pop multiple random members\nrandom_tags = r.spop('tags', count=2)\n\n# Get random member without removing\nrandom = r.srandmember('tags')\nrandom_three = r.srandmember('tags', 3)\n```\n\n### Set Operations Between Multiple Sets\n\n```python\n# Create sets\nr.sadd('set1', 'a', 'b', 'c')\nr.sadd('set2', 'b', 'c', 'd')\nr.sadd('set3', 'c', 'd', 'e')\n\n# Union (combine all unique members)\nunion = r.sunion('set1', 'set2')\n# {'a', 'b', 'c', 'd'}\n\n# Store union in new set\nr.sunionstore('result', 'set1', 'set2')\n\n# Intersection (common members)\ninter = r.sinter('set1', 'set2')\n# {'b', 'c'}\n\n# Store intersection\nr.sinterstore('result', 'set1', 'set2')\n\n# Intersection of multiple sets\ninter = r.sinter('set1', 'set2', 'set3')  # {'c'}\n\n# Difference (members in first set but not in others)\ndiff = r.sdiff('set1', 'set2')\n# {'a'}\n\n# Store difference\nr.sdiffstore('result', 'set1', 'set2')\n\n# Move member between sets\nr.smove('set1', 'set2', 'a')\n\n# Check multiple members\nresult = r.smismember('tags', 'nodejs', 'python', 'redis')\n# [True, False, True]\n```\n\n### Scan Set Members\n\n```python\n# Scan set members (for large sets)\ncursor = 0\nwhile True:\n    cursor, members = r.sscan('tags', cursor, count=10)\n    for member in members:\n        print(member)\n    if cursor == 0:\n        break\n\n# Using sscan_iter (simpler)\nfor member in r.sscan_iter('tags', match='node*', count=10):\n    print(member)\n```\n\n---\n\n## Sorted Set Operations\n\n### Basic Sorted Set Operations\n\n```python\n# Add members with scores\nr.zadd('leaderboard', {'player1': 100})\nr.zadd('leaderboard', {'player2': 200, 'player3': 150})\n\n# Add with options\nr.zadd('leaderboard', {'player4': 175}, nx=True)  # Only if doesn't exist\nr.zadd('leaderboard', {'player1': 120}, xx=True)  # Only if exists\nr.zadd('leaderboard', {'player1': 130}, gt=True)  # Only if new score greater\nr.zadd('leaderboard', {'player1': 110}, lt=True)  # Only if new score less\n\n# Get rank (0-based, lowest to highest)\nrank = r.zrank('leaderboard', 'player1')  # 0\n\n# Get reverse rank (highest to lowest)\nrev_rank = r.zrevrank('leaderboard', 'player2')  # 0\n\n# Get score\nscore = r.zscore('leaderboard', 'player2')  # 200.0\n\n# Get number of members\ncount = r.zcard('leaderboard')  # 3\n\n# Increment score\nr.zincrby('leaderboard', 50, 'player1')  # 150.0\n```\n\n### Range Queries\n\n```python\n# Get range by rank (lowest to highest)\nbottom3 = r.zrange('leaderboard', 0, 2)\n# ['player1', 'player3', 'player2']\n\n# Get range with scores\nwith_scores = r.zrange('leaderboard', 0, 2, withscores=True)\n# [('player1', 150.0), ('player3', 150.0), ('player2', 200.0)]\n\n# Get range by rank (highest to lowest)\ntop3 = r.zrevrange('leaderboard', 0, 2)\n\n# Get range with scores (descending)\ntop3_scores = r.zrevrange('leaderboard', 0, 2, withscores=True)\n\n# Get range by score\nrange_result = r.zrangebyscore('leaderboard', 100, 200)\n\n# Get range by score with limit\nlimited = r.zrangebyscore('leaderboard', 100, 200, start=0, num=10)\n\n# Get range by score with scores\nrange_scores = r.zrangebyscore('leaderboard', 100, 200, withscores=True)\n\n# Get reverse range by score\nrev_range = r.zrevrangebyscore('leaderboard', 200, 100)\n\n# Infinity boundaries\nhigh_scores = r.zrangebyscore('leaderboard', 150, '+inf')\nlow_scores = r.zrangebyscore('leaderboard', '-inf', 150)\n```\n\n### Advanced Sorted Set Operations\n\n```python\n# Count members in score range\ncount = r.zcount('leaderboard', 100, 200)\n\n# Count members by lexicographical range\nr.zadd('words', {'apple': 0, 'banana': 0, 'cherry': 0})\nlex_count = r.zlexcount('words', '[a', '[c')\n\n# Get lexicographical range\nlex_range = r.zrangebylex('words', '[a', '[c')\n\n# Remove members\nr.zrem('leaderboard', 'player1')\nr.zrem('leaderboard', 'player2', 'player3')\n\n# Remove by rank range\nr.zremrangebyrank('leaderboard', 0, 1)  # Remove bottom 2\n\n# Remove by score range\nr.zremrangebyscore('leaderboard', 0, 100)\n\n# Remove by lex range\nr.zremrangebylex('words', '[a', '[b')\n\n# Pop highest/lowest scoring member\nhighest = r.zpopmax('leaderboard')  # [('player2', 200.0)]\nlowest = r.zpopmin('leaderboard')  # [('player1', 100.0)]\n\n# Pop with count\ntop3 = r.zpopmax('leaderboard', count=3)\n\n# Blocking pop\nmember = r.bzpopmax('leaderboard', timeout=5)\n# ('leaderboard', 'player2', 200.0)\nmin_member = r.bzpopmin('leaderboard', timeout=5)\n\n# Block on multiple sorted sets\nmember = r.bzpopmax(['set1', 'set2', 'set3'], timeout=5)\n```\n\n### Sorted Set Operations Between Multiple Sets\n\n```python\n# Union of sorted sets\nr.zunionstore('result', ['set1', 'set2'])\n\n# Union with weights\nr.zunionstore('result', {'set1': 2, 'set2': 3})\n\n# Union with aggregate function\nr.zunionstore('result', ['set1', 'set2'], aggregate='MAX')  # or 'MIN', 'SUM'\n\n# Intersection\nr.zinterstore('result', ['set1', 'set2'])\n\n# Intersection with weights and aggregate\nr.zinterstore('result', {'set1': 1, 'set2': 2}, aggregate='SUM')\n\n# Get union without storing\nunion = r.zunion(['set1', 'set2'], withscores=True)\n\n# Get intersection without storing\ninter = r.zinter(['set1', 'set2'], withscores=True)\n\n# Difference between sorted sets\ndiff = r.zdiff(['set1', 'set2'])\ndiff_scores = r.zdiff(['set1', 'set2'], withscores=True)\n\n# Store difference\nr.zdiffstore('result', ['set1', 'set2'])\n```\n\n### Scan Sorted Set\n\n```python\n# Scan sorted set members\ncursor = 0\nwhile True:\n    cursor, members = r.zscan('leaderboard', cursor, count=10)\n    for member, score in members:\n        print(f\"{member}: {score}\")\n    if cursor == 0:\n        break\n\n# Using zscan_iter (simpler)\nfor member, score in r.zscan_iter('leaderboard', count=10):\n    print(f\"{member}: {score}\")\n```\n\n---\n\n## Key Management Operations\n\n### Key Operations\n\n```python\n# Check if key exists\nexists = r.exists('mykey')  # 1 if exists, 0 if not\nmulti_exists = r.exists('key1', 'key2', 'key3')  # Count\n\n# Delete keys\nr.delete('mykey')\nr.delete('key1', 'key2', 'key3')\n\n# Set expiration in seconds\nr.expire('mykey', 60)  # Expire in 60 seconds\n\n# Set expiration at specific timestamp\nimport time\ntimestamp = int(time.time()) + 3600\nr.expireat('mykey', timestamp)\n\n# Set expiration in milliseconds\nr.pexpire('mykey', 60000)  # 60 seconds\n\n# Set expiration at timestamp (milliseconds)\nr.pexpireat('mykey', int(time.time() * 1000) + 60000)\n\n# Get time to live in seconds\nttl = r.ttl('mykey')  # -1 if no expiration, -2 if not exists\n\n# Get time to live in milliseconds\npttl = r.pttl('mykey')\n\n# Remove expiration\nr.persist('mykey')\n\n# Rename key\nr.rename('oldkey', 'newkey')\n\n# Rename only if new key doesn't exist\nrenamed = r.renamenx('oldkey', 'newkey')  # Returns True if renamed\n\n# Get key type\nkey_type = r.type('mykey')  # 'string', 'list', 'set', etc.\n\n# Get random key\nrandom_key = r.randomkey()\n\n# Copy key\nr.copy('source', 'destination')\nr.copy('source', 'destination', replace=True)  # Overwrite if exists\n\n# Touch keys (update last access time)\nr.touch('key1', 'key2', 'key3')\n\n# Get object encoding\nencoding = r.object('encoding', 'mykey')\n\n# Get object idle time\nidle_time = r.object('idletime', 'mykey')\n```\n\n### Scanning Keys\n\n```python\n# Scan all keys (use instead of KEYS for production)\nkeys = []\ncursor = 0\nwhile True:\n    cursor, partial_keys = r.scan(cursor, count=100)\n    keys.extend(partial_keys)\n    if cursor == 0:\n        break\n\n# Using scan_iter (simpler)\nfor key in r.scan_iter(count=100):\n    print(key)\n\n# Scan with pattern\nfor key in r.scan_iter(match='user:*', count=100):\n    print(key)\n\n# Scan specific key type\nfor key in r.scan_iter(_type='string', count=100):\n    print(key)\n\n# Scan with pattern and type\nfor key in r.scan_iter(match='session:*', _type='hash', count=100):\n    print(key)\n```\n\n---\n\n## Transactions\n\n### Basic Transaction (MULTI/EXEC)\n\n```python\n# Execute multiple commands atomically\nr.set('another-key', 'another-value')\n\npipe = r.pipeline()\npipe.set('key', 'value')\npipe.get('another-key')\npipe.incr('counter')\nresults = pipe.execute()\n\nprint(results)  # [True, 'another-value', 1]\n```\n\n### Pipeline Without Transaction\n\n```python\n# Execute commands in pipeline without atomicity\npipe = r.pipeline(transaction=False)\npipe.set('key1', 'value1')\npipe.set('key2', 'value2')\npipe.get('key1')\nresults = pipe.execute()\n```\n\n### Transaction with Error Handling\n\n```python\ntry:\n    pipe = r.pipeline()\n    pipe.set('key1', 'value1')\n    pipe.set('key2', 'value2')\n    pipe.get('key1')\n    results = pipe.execute()\n\n    for i, result in enumerate(results):\n        print(f\"Command {i} result: {result}\")\nexcept redis.exceptions.ResponseError as e:\n    print(f\"Transaction failed: {e}\")\n```\n\n### Transaction with WATCH (Optimistic Locking)\n\n```python\n# Watch a key for changes\nwith r.pipeline() as pipe:\n    while True:\n        try:\n            pipe.watch('balance')\n            balance = int(pipe.get('balance') or 0)\n\n            if balance >= 100:\n                pipe.multi()\n                pipe.decrby('balance', 100)\n                pipe.incrby('purchases', 1)\n                pipe.execute()\n                print('Purchase successful')\n                break\n            else:\n                pipe.unwatch()\n                print('Insufficient balance')\n                break\n        except redis.WatchError:\n            print('Balance was modified, retrying...')\n            continue\n```\n\n### Complex Transaction Example\n\n```python\ndef transfer_money(r, from_account, to_account, amount):\n    \"\"\"Transfer money between accounts with optimistic locking\"\"\"\n    with r.pipeline() as pipe:\n        while True:\n            try:\n                pipe.watch(from_account, to_account)\n\n                from_balance = float(pipe.get(from_account) or 0)\n\n                if from_balance < amount:\n                    pipe.unwatch()\n                    raise ValueError('Insufficient funds')\n\n                pipe.multi()\n                pipe.incrbyfloat(from_account, -amount)\n                pipe.incrbyfloat(to_account, amount)\n                pipe.execute()\n                return True\n            except redis.WatchError:\n                # Another client modified the keys, retry\n                continue\n\n# Usage\ntry:\n    transfer_money(r, 'account:1', 'account:2', 50.00)\n    print('Transfer successful')\nexcept ValueError as e:\n    print(f'Transfer failed: {e}')\n```\n\n---\n\n## Pipelining\n\n### Basic Pipelining\n\n```python\n# Execute multiple commands in one round trip\npipe = r.pipeline(transaction=False)\npipe.set('key1', 'value1')\npipe.set('key2', 'value2')\npipe.get('key1')\npipe.mget(['key1', 'key2'])\nresults = pipe.execute()\n\nprint(results)  # [True, True, 'value1', ['value1', 'value2']]\n```\n\n### Large Batch Operations\n\n```python\ndef batch_set_keys(r, key_value_pairs):\n    \"\"\"Set many keys efficiently using pipeline\"\"\"\n    pipe = r.pipeline(transaction=False)\n\n    for key, value in key_value_pairs.items():\n        pipe.set(key, value)\n\n    results = pipe.execute()\n    return results\n\n# Usage\ndata = {\n    'user:1': 'Alice',\n    'user:2': 'Bob',\n    'user:3': 'Charlie'\n}\n\nbatch_set_keys(r, data)\n```\n\n### Chunked Pipeline\n\n```python\ndef batch_operation_chunked(r, operations, chunk_size=1000):\n    \"\"\"Execute operations in chunks to avoid memory issues\"\"\"\n    results = []\n\n    for i in range(0, len(operations), chunk_size):\n        chunk = operations[i:i + chunk_size]\n        pipe = r.pipeline(transaction=False)\n\n        for op in chunk:\n            getattr(pipe, op['command'])(*op['args'])\n\n        results.extend(pipe.execute())\n\n    return results\n\n# Usage\noperations = [\n    {'command': 'set', 'args': [f'key:{i}', f'value:{i}']}\n    for i in range(10000)\n]\n\nbatch_operation_chunked(r, operations, chunk_size=1000)\n```\n\n---\n\n## Pub/Sub\n\n### Basic Subscriber\n\n```python\nimport redis\n\nr = redis.Redis(host='localhost', port=6379, decode_responses=True)\n\n# Create PubSub object\npubsub = r.pubsub()\n\n# Subscribe to channel\npubsub.subscribe('notifications')\n\n# Listen for messages\nfor message in pubsub.listen():\n    if message['type'] == 'message':\n        print(f\"Received: {message['data']}\")\n```\n\n### Basic Publisher\n\n```python\nimport redis\n\nr = redis.Redis(host='localhost', port=6379, decode_responses=True)\n\n# Publish messages\nr.publish('notifications', 'Hello, World!')\nr.publish('notifications', 'System update')\n\nprint('Messages published')\n```\n\n### Multiple Channels\n\n```python\n# Subscribe to multiple channels\npubsub = r.pubsub()\npubsub.subscribe('channel1', 'channel2', 'channel3')\n\nfor message in pubsub.listen():\n    if message['type'] == 'message':\n        print(f\"Channel: {message['channel']}, Message: {message['data']}\")\n```\n\n### Pattern-Based Subscription\n\n```python\n# Subscribe to channels matching pattern\npubsub = r.pubsub()\npubsub.psubscribe('user:*')\n\nfor message in pubsub.listen():\n    if message['type'] == 'pmessage':\n        print(f\"Pattern: {message['pattern']}, Channel: {message['channel']}, Message: {message['data']}\")\n\n# Publish to matching channels\nr.publish('user:1000', 'User 1000 logged in')\nr.publish('user:2000', 'User 2000 logged out')\n```\n\n### Message Handler Functions\n\n```python\ndef message_handler(message):\n    \"\"\"Handle messages from channel\"\"\"\n    print(f\"Received: {message['data']}\")\n\ndef error_handler(message):\n    \"\"\"Handle errors\"\"\"\n    print(f\"Error: {message}\")\n\n# Subscribe with handler\npubsub = r.pubsub()\npubsub.subscribe(**{\n    'notifications': message_handler,\n    'errors': error_handler\n})\n\n# Run event loop\nthread = pubsub.run_in_thread(sleep_time=0.01)\n\n# Do other work...\n\n# Stop listening\nthread.stop()\n```\n\n### Unsubscribe\n\n```python\n# Unsubscribe from specific channel\npubsub.unsubscribe('channel1')\n\n# Unsubscribe from all channels\npubsub.unsubscribe()\n\n# Unsubscribe from pattern\npubsub.punsubscribe('user:*')\n```\n\n### Complete Pub/Sub Example\n\n```python\nimport redis\nimport json\nimport threading\nimport time\n\ndef subscriber_worker():\n    \"\"\"Subscriber in separate thread\"\"\"\n    r = redis.Redis(host='localhost', port=6379, decode_responses=True)\n    pubsub = r.pubsub()\n    pubsub.subscribe('chat:room1')\n\n    for message in pubsub.listen():\n        if message['type'] == 'message':\n            data = json.loads(message['data'])\n            print(f\"{data['user']}: {data['text']}\")\n\ndef publisher_worker():\n    \"\"\"Publisher in separate thread\"\"\"\n    r = redis.Redis(host='localhost', port=6379, decode_responses=True)\n\n    time.sleep(1)  # Wait for subscriber\n\n    # Publish chat messages\n    r.publish('chat:room1', json.dumps({\n        'user': 'Alice',\n        'text': 'Hello everyone!'\n    }))\n\n    r.publish('chat:room1', json.dumps({\n        'user': 'Bob',\n        'text': 'Hi Alice!'\n    }))\n\n# Start subscriber\nsub_thread = threading.Thread(target=subscriber_worker, daemon=True)\nsub_thread.start()\n\n# Start publisher\npub_thread = threading.Thread(target=publisher_worker)\npub_thread.start()\npub_thread.join()\n\ntime.sleep(2)  # Let subscriber process messages\n```\n\n---\n\n## Redis Streams\n\n### Add to Stream (XADD)\n\n```python\n# Add entry to stream\nentry_id = r.xadd('events', {\n    'user': 'alice',\n    'action': 'login',\n    'timestamp': time.time()\n})\n\nprint(f'Entry ID: {entry_id}')  # '1234567890123-0'\n\n# Add with specific ID\nr.xadd('events', {'user': 'bob', 'action': 'logout'}, id='1234567890123-1')\n\n# Add with maxlen (limit stream size)\nr.xadd('events', {'user': 'charlie', 'action': 'signup'}, maxlen=1000)\n\n# Add with approximate trimming\nr.xadd('events', {'user': 'dave', 'action': 'purchase'}, maxlen=1000, approximate=True)\n\n# Add with minid trimming\nr.xadd('events', {'data': 'value'}, minid='1234567890000-0')\n```\n\n### Read from Stream (XREAD)\n\n```python\n# Read entries from beginning\nmessages = r.xread({'events': '0'}, count=10)\n\nfor stream, entries in messages:\n    for entry_id, data in entries:\n        print(f\"ID: {entry_id}, Data: {data}\")\n\n# Read from multiple streams\nmessages = r.xread({'stream1': '0', 'stream2': '0'})\n\n# Blocking read (wait for new entries)\nmessages = r.xread({'events': '$'}, block=5000)  # Wait up to 5 seconds\n\n# Read only new messages\nmessages = r.xread({'events': '$'}, block=0)  # Block indefinitely\n```\n\n### Stream Range Queries\n\n```python\n# Read all entries\nall_entries = r.xrange('events', '-', '+')\n\n# Read range with IDs\nrange_entries = r.xrange('events', '1234567890000', '1234567899999')\n\n# Read with limit\nlimited = r.xrange('events', '-', '+', count=100)\n\n# Reverse range\nreverse = r.xrevrange('events', '+', '-', count=10)\n\n# Iterate through entries\nfor entry_id, data in r.xrange('events', '-', '+'):\n    print(f\"{entry_id}: {data}\")\n```\n\n### Stream Length and Info\n\n```python\n# Get stream length\nlength = r.xlen('events')\n\n# Get stream info\ninfo = r.xinfo_stream('events')\nprint(f\"Length: {info['length']}\")\nprint(f\"First entry: {info['first-entry']}\")\nprint(f\"Last entry: {info['last-entry']}\")\n```\n\n### Consumer Groups\n\n```python\n# Create consumer group\ntry:\n    r.xgroup_create('events', 'processors', '0', mkstream=True)\nexcept redis.exceptions.ResponseError:\n    # Group already exists\n    pass\n\n# Read as consumer group\nmessages = r.xreadgroup(\n    'processors',\n    'consumer1',\n    {'events': '>'},  # '>' means undelivered messages\n    count=10,\n    block=5000\n)\n\n# Process messages and acknowledge\nfor stream, entries in messages:\n    for entry_id, data in entries:\n        # Process message\n        print(f'Processing: {entry_id}, {data}')\n\n        # Acknowledge message\n        r.xack('events', 'processors', entry_id)\n\n# Get pending messages\npending = r.xpending('events', 'processors')\nprint(f\"Pending messages: {pending['pending']}\")\n\n# Get detailed pending info\npending_details = r.xpending_range('events', 'processors', '-', '+', count=10)\n\n# Claim pending messages (take over from another consumer)\nclaimed = r.xclaim('events', 'processors', 'consumer2', 3600000, ['1234567890123-0'])\n```\n\n### Delete from Stream\n\n```python\n# Delete specific entries\nr.xdel('events', '1234567890123-0', '1234567890123-1')\n\n# Trim stream\nr.xtrim('events', maxlen=1000)\n\n# Approximate trim\nr.xtrim('events', maxlen=1000, approximate=True)\n\n# Trim by minid\nr.xtrim('events', minid='1234567890000-0')\n```\n\n### Complete Stream Example\n\n```python\nimport redis\nimport time\nimport json\n\nr = redis.Redis(host='localhost', port=6379, decode_responses=True)\n\ndef add_event(event_data):\n    \"\"\"Add event to stream\"\"\"\n    return r.xadd('events', event_data)\n\ndef process_events():\n    \"\"\"Process events using consumer group\"\"\"\n    # Create group if not exists\n    try:\n        r.xgroup_create('events', 'workers', '0', mkstream=True)\n    except redis.exceptions.ResponseError:\n        pass\n\n    while True:\n        messages = r.xreadgroup(\n            'workers',\n            'worker1',\n            {'events': '>'},\n            count=10,\n            block=5000\n        )\n\n        if messages:\n            for stream, entries in messages:\n                for entry_id, data in entries:\n                    try:\n                        # Process event\n                        print(f'Processing event: {data}')\n\n                        # Acknowledge\n                        r.xack('events', 'workers', entry_id)\n                    except Exception as e:\n                        print(f'Error processing: {e}')\n\n# Add events\nadd_event({'type': 'user_login', 'user': 'alice'})\nadd_event({'type': 'user_logout', 'user': 'bob'})\n\n# Process events\nprocess_events()\n```\n\n---\n\n## Scripting with Lua\n\n### Basic Script Execution (EVAL)\n\n```python\n# Execute Lua script\nscript = \"return redis.call('SET', KEYS[1], ARGV[1])\"\nresult = r.eval(script, 1, 'mykey', 'myvalue')\nprint(result)  # b'OK' or 'OK' with decode_responses=True\n```\n\n### Script with Multiple Operations\n\n```python\nscript = \"\"\"\nlocal current = redis.call('GET', KEYS[1])\nif current == false then\n    current = 0\nend\nlocal new = tonumber(current) + tonumber(ARGV[1])\nredis.call('SET', KEYS[1], new)\nreturn new\n\"\"\"\n\nnew_value = r.eval(script, 1, 'counter', 5)\nprint(f'New counter value: {new_value}')\n```\n\n### Register Script (SCRIPT LOAD / EVALSHA)\n\n```python\n# Register script\nscript = \"return redis.call('GET', KEYS[1])\"\nsha = r.script_load(script)\nprint(f'Script SHA: {sha}')\n\n# Execute by SHA (more efficient for repeated calls)\nvalue = r.evalsha(sha, 1, 'mykey')\n\n# Check if script exists\nexists = r.script_exists(sha)\nprint(f'Script exists: {exists}')  # [True]\n\n# Flush all scripts\nr.script_flush()\n```\n\n### Rate Limiting with Lua Script\n\n```python\nrate_limit_script = \"\"\"\nlocal key = KEYS[1]\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal current = redis.call('INCR', key)\nif current == 1 then\n    redis.call('EXPIRE', key, window)\nend\nif current > limit then\n    return 0\nelse\n    return 1\nend\n\"\"\"\n\ndef check_rate_limit(user_id, limit=10, window=60):\n    \"\"\"Check if user is within rate limit\"\"\"\n    allowed = r.eval(\n        rate_limit_script,\n        1,\n        f'ratelimit:{user_id}',\n        limit,\n        window\n    )\n    return allowed == 1\n\n# Usage\nif check_rate_limit('user:1000', limit=10, window=60):\n    print('Request allowed')\nelse:\n    print('Rate limit exceeded')\n```\n\n### Atomic Get and Delete\n\n```python\nget_and_delete = \"\"\"\nlocal value = redis.call('GET', KEYS[1])\nif value then\n    redis.call('DEL', KEYS[1])\nend\nreturn value\n\"\"\"\n\nvalue = r.eval(get_and_delete, 1, 'temp:key')\nprint(f'Retrieved and deleted: {value}')\n```\n\n### Script Class for Reusability\n\n```python\nclass RedisScripts:\n    \"\"\"Reusable Redis Lua scripts\"\"\"\n\n    def __init__(self, redis_client):\n        self.r = redis_client\n\n        # Load scripts on initialization\n        self.rate_limit_sha = self.r.script_load(\"\"\"\n            local key = KEYS[1]\n            local limit = tonumber(ARGV[1])\n            local window = tonumber(ARGV[2])\n            local current = redis.call('INCR', key)\n            if current == 1 then\n                redis.call('EXPIRE', key, window)\n            end\n            return current <= limit and 1 or 0\n        \"\"\")\n\n        self.atomic_increment_sha = self.r.script_load(\"\"\"\n            local current = redis.call('GET', KEYS[1])\n            if not current then\n                current = 0\n            end\n            local new = tonumber(current) + tonumber(ARGV[1])\n            redis.call('SET', KEYS[1], new)\n            return new\n        \"\"\")\n\n    def rate_limit(self, key, limit, window):\n        return self.r.evalsha(self.rate_limit_sha, 1, key, limit, window) == 1\n\n    def atomic_increment(self, key, amount):\n        return self.r.evalsha(self.atomic_increment_sha, 1, key, amount)\n\n# Usage\nscripts = RedisScripts(r)\nallowed = scripts.rate_limit('user:1000', 10, 60)\nnew_value = scripts.atomic_increment('counter', 5)\n```\n\n---\n\n## Geospatial Operations\n\n### Add Geo Points\n\n```python\n# Add location\nr.geoadd('locations', -122.4194, 37.7749, 'San Francisco')\n\n# Add multiple locations\nr.geoadd('locations',\n    -118.2437, 34.0522, 'Los Angeles',\n    -73.9352, 40.7306, 'New York'\n)\n```\n\n### Query Geo Points\n\n```python\n# Get position\nposition = r.geopos('locations', 'San Francisco')\nprint(position)  # [(-122.4194, 37.7749)]\n\n# Get multiple positions\npositions = r.geopos('locations', 'San Francisco', 'Los Angeles')\n\n# Get distance between points\ndistance = r.geodist('locations', 'San Francisco', 'Los Angeles', unit='mi')\nprint(f'Distance: {distance} miles')\n\n# Available units: 'm', 'km', 'mi', 'ft'\n\n# Search by radius (from coordinates)\nnearby = r.georadius('locations', -122.4194, 37.7749, 500, unit='mi')\n\n# Search with additional info\ndetailed = r.georadius(\n    'locations', -122.4194, 37.7749, 500, unit='mi',\n    withdist=True,\n    withcoord=True,\n    withhash=True,\n    count=10,\n    sort='ASC'\n)\n\n# Search by member\nnear_sf = r.georadiusbymember('locations', 'San Francisco', 600, unit='mi')\n\n# Search by member with details\ndetailed = r.georadiusbymember(\n    'locations', 'San Francisco', 600, unit='mi',\n    withdist=True,\n    withcoord=True\n)\n\n# Get geohash\ngeohash = r.geohash('locations', 'San Francisco')\n```\n\n---\n\n## HyperLogLog (Cardinality Estimation)\n\n```python\n# Add elements\nr.pfadd('unique:visitors', 'user1', 'user2', 'user3')\nr.pfadd('unique:visitors', 'user2', 'user4')  # user2 counted once\n\n# Get count\ncount = r.pfcount('unique:visitors')  # ~4\nprint(f'Unique visitors: {count}')\n\n# Count multiple HyperLogLogs\ntotal = r.pfcount('unique:day1', 'unique:day2', 'unique:day3')\n\n# Merge multiple HyperLogLogs\nr.pfmerge('unique:combined', 'unique:day1', 'unique:day2')\n```\n\n---\n\n## Bitmap Operations\n\n```python\n# Set bit\nr.setbit('login:2024-01-15', 100, 1)  # User 100 logged in\n\n# Get bit\nbit = r.getbit('login:2024-01-15', 100)  # 1\n\n# Count set bits\ncount = r.bitcount('login:2024-01-15')\n\n# Count bits in range (bytes)\ncount = r.bitcount('login:2024-01-15', 0, 10)\n\n# Bitwise operations\nr.bitop('AND', 'result', 'bitmap1', 'bitmap2')\nr.bitop('OR', 'result', 'bitmap1', 'bitmap2')\nr.bitop('XOR', 'result', 'bitmap1', 'bitmap2')\nr.bitop('NOT', 'result', 'bitmap1')\n\n# Find first bit\npos = r.bitpos('login:2024-01-15', 1)  # First set bit\npos = r.bitpos('login:2024-01-15', 0)  # First unset bit\n\n# Find bit in range\npos = r.bitpos('login:2024-01-15', 1, 0, 10)\n```\n\n---\n\n## Server and Connection Management\n\n### Server Information\n\n```python\n# Get server info\ninfo = r.info()\nprint(info)\n\n# Get specific section\nstats = r.info('stats')\nmemory = r.info('memory')\nreplication = r.info('replication')\n\n# Ping server\npong = r.ping()  # True\n\n# Echo message\necho = r.echo('Hello Redis')\n\n# Get server time\nserver_time = r.time()  # (seconds, microseconds)\n```\n\n### Database Management\n\n```python\n# Select database (0-15 by default)\nr.execute_command('SELECT', 1)\n\n# Get database size\nsize = r.dbsize()\n\n# Flush current database\nr.flushdb()\n\n# Flush all databases\nr.flushall()\n\n# Save database to disk\nr.save()\n\n# Background save\nr.bgsave()\n\n# Get last save time\nlast_save = r.lastsave()  # Unix timestamp\n\n# Background rewrite AOF\nr.bgrewriteaof()\n```\n\n### Client Management\n\n```python\n# Get client list\nclients = r.client_list()\n\n# Get client ID\nclient_id = r.client_id()\n\n# Set client name\nr.client_setname('my-app')\n\n# Get client name\nname = r.client_getname()\n\n# Get client info\ninfo = r.client_info()\n\n# Kill client\nr.client_kill('127.0.0.1:6379')\n\n# Pause all clients\nr.client_pause(1000)  # Pause for 1000ms\n```\n\n### Memory Management\n\n```python\n# Get memory stats\nmemory_stats = r.memory_stats()\n\n# Get memory usage of key\nusage = r.memory_usage('mykey')\n\n# Purge memory\nr.memory_purge()\n```\n\n---\n\n## Async/Await Support\n\n### Async Redis Client\n\n```python\nimport asyncio\nimport redis.asyncio as aioredis\n\nasync def main():\n    # Create async client\n    r = await aioredis.from_url('redis://localhost:6379', decode_responses=True)\n\n    # Set value\n    await r.set('key', 'value')\n\n    # Get value\n    value = await r.get('key')\n    print(value)\n\n    # Close connection\n    await r.close()\n\n# Run async code\nasyncio.run(main())\n```\n\n### Async Pipeline\n\n```python\nasync def async_pipeline():\n    r = await aioredis.from_url('redis://localhost:6379', decode_responses=True)\n\n    async with r.pipeline(transaction=True) as pipe:\n        await pipe.set('key1', 'value1')\n        await pipe.set('key2', 'value2')\n        await pipe.get('key1')\n        results = await pipe.execute()\n\n    print(results)\n    await r.close()\n\nasyncio.run(async_pipeline())\n```\n\n### Async Pub/Sub\n\n```python\nasync def reader(channel: aioredis.client.PubSub):\n    while True:\n        message = await channel.get_message(ignore_subscribe_messages=True)\n        if message is not None:\n            print(f\"Received: {message['data']}\")\n\nasync def async_pubsub():\n    r = await aioredis.from_url('redis://localhost:6379', decode_responses=True)\n\n    async with r.pubsub() as pubsub:\n        await pubsub.subscribe('notifications')\n\n        # Create task to read messages\n        future = asyncio.create_task(reader(pubsub))\n\n        # Publish messages\n        await r.publish('notifications', 'Hello Async!')\n\n        await asyncio.sleep(1)\n        future.cancel()\n\n    await r.close()\n\nasyncio.run(async_pubsub())\n```\n\n---\n\n## Error Handling\n\n### Connection Errors\n\n```python\nimport redis\nfrom redis.exceptions import ConnectionError, TimeoutError, RedisError\n\ntry:\n    r = redis.Redis(\n        host='localhost',\n        port=6379,\n        socket_connect_timeout=5,\n        socket_timeout=5,\n        retry_on_timeout=True\n    )\n    r.ping()\nexcept ConnectionError as e:\n    print(f'Connection error: {e}')\nexcept TimeoutError as e:\n    print(f'Timeout error: {e}')\nexcept RedisError as e:\n    print(f'Redis error: {e}')\n```\n\n### Command Errors\n\n```python\nfrom redis.exceptions import ResponseError, DataError\n\ntry:\n    r.get('nonexistent')\nexcept ResponseError as e:\n    print(f'Command error: {e}')\nexcept DataError as e:\n    print(f'Data error: {e}')\n```\n\n### Pipeline Errors\n\n```python\npipe = r.pipeline()\npipe.set('key1', 'value1')\npipe.incr('not-a-number')  # Will error\npipe.get('key1')\n\ntry:\n    results = pipe.execute()\nexcept ResponseError as e:\n    print(f'Pipeline error: {e}')\n```\n\n### Retry Logic\n\n```python\nimport time\nfrom redis.exceptions import ConnectionError\n\ndef redis_operation_with_retry(operation, max_retries=3):\n    \"\"\"Execute Redis operation with retry logic\"\"\"\n    for attempt in range(max_retries):\n        try:\n            return operation()\n        except ConnectionError:\n            if attempt == max_retries - 1:\n                raise\n            time.sleep(2 ** attempt)  # Exponential backoff\n\n# Usage\nresult = redis_operation_with_retry(lambda: r.get('mykey'))\n```\n\n---\n\n## Connection Pooling\n\n### Configure Connection Pool\n\n```python\npool = redis.ConnectionPool(\n    host='localhost',\n    port=6379,\n    password='your_password',\n    db=0,\n    max_connections=50,\n    socket_timeout=5,\n    socket_connect_timeout=5,\n    socket_keepalive=True,\n    socket_keepalive_options={\n        1: 1,  # TCP_KEEPIDLE\n        2: 1,  # TCP_KEEPINTVL\n        3: 3   # TCP_KEEPCNT\n    },\n    decode_responses=True\n)\n\nr = redis.Redis(connection_pool=pool)\n```\n\n### Multiple Clients Sharing Pool\n\n```python\npool = redis.ConnectionPool(\n    host='localhost',\n    port=6379,\n    max_connections=20,\n    decode_responses=True\n)\n\n# Multiple clients share the pool\nclient1 = redis.Redis(connection_pool=pool)\nclient2 = redis.Redis(connection_pool=pool)\nclient3 = redis.Redis(connection_pool=pool)\n```\n\n---\n\n## Cluster Support\n\n### Connect to Cluster\n\n```python\nfrom redis.cluster import RedisCluster\n\n# Connect to cluster\ncluster = RedisCluster(\n    host='localhost',\n    port=7000,\n    decode_responses=True\n)\n\n# Use cluster like regular client\ncluster.set('key', 'value')\nvalue = cluster.get('key')\n\ncluster.close()\n```\n\n### Cluster with Multiple Nodes\n\n```python\nfrom redis.cluster import RedisCluster, ClusterNode\n\nstartup_nodes = [\n    ClusterNode('localhost', 7000),\n    ClusterNode('localhost', 7001),\n    ClusterNode('localhost', 7002)\n]\n\ncluster = RedisCluster(\n    startup_nodes=startup_nodes,\n    decode_responses=True\n)\n```\n\n---\n\n## Complete Application Example\n\n```python\nimport redis\nimport json\nimport time\nimport os\nfrom typing import Optional, List, Dict, Any\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nclass RedisManager:\n    \"\"\"Redis manager with common operations\"\"\"\n\n    def __init__(self):\n        self.pool = redis.ConnectionPool(\n            host=os.getenv('REDIS_HOST', 'localhost'),\n            port=int(os.getenv('REDIS_PORT', 6379)),\n            password=os.getenv('REDIS_PASSWORD'),\n            db=int(os.getenv('REDIS_DB', 0)),\n            max_connections=10,\n            decode_responses=True\n        )\n        self.client = redis.Redis(connection_pool=self.pool)\n\n    def cache_get(self, key: str) -> Optional[Any]:\n        \"\"\"Get value from cache\"\"\"\n        value = self.client.get(key)\n        return json.loads(value) if value else None\n\n    def cache_set(self, key: str, value: Any, ttl: int = 3600):\n        \"\"\"Set value in cache with TTL\"\"\"\n        self.client.set(key, json.dumps(value), ex=ttl)\n\n    def invalidate_cache(self, pattern: str):\n        \"\"\"Invalidate cache keys matching pattern\"\"\"\n        keys = list(self.client.scan_iter(match=pattern))\n        if keys:\n            self.client.delete(*keys)\n\n    def track_user_activity(self, user_id: str, action: str):\n        \"\"\"Track user activity\"\"\"\n        today = time.strftime('%Y-%m-%d')\n        key = f'activity:{user_id}:{today}'\n\n        self.client.rpush(key, json.dumps({\n            'action': action,\n            'timestamp': time.time()\n        }))\n        self.client.expire(key, 86400 * 7)  # Keep for 7 days\n\n    def get_user_activity(self, user_id: str, date: str) -> List[Dict]:\n        \"\"\"Get user activity for date\"\"\"\n        key = f'activity:{user_id}:{date}'\n        activities = self.client.lrange(key, 0, -1)\n        return [json.loads(a) for a in activities]\n\n    def increment_page_view(self, page_id: str) -> int:\n        \"\"\"Increment page view counter\"\"\"\n        return self.client.incr(f'pageviews:{page_id}')\n\n    def get_page_views(self, page_id: str) -> int:\n        \"\"\"Get page view count\"\"\"\n        views = self.client.get(f'pageviews:{page_id}')\n        return int(views) if views else 0\n\n    def add_to_leaderboard(self, user_id: str, score: float):\n        \"\"\"Add or update user score in leaderboard\"\"\"\n        self.client.zadd('leaderboard', {user_id: score})\n\n    def get_leaderboard(self, count: int = 10) -> List[Dict]:\n        \"\"\"Get top users from leaderboard\"\"\"\n        results = self.client.zrevrange('leaderboard', 0, count - 1, withscores=True)\n        return [{'user_id': user, 'score': score} for user, score in results]\n\n    def get_user_rank(self, user_id: str) -> Optional[int]:\n        \"\"\"Get user rank in leaderboard (1-based)\"\"\"\n        rank = self.client.zrevrank('leaderboard', user_id)\n        return rank + 1 if rank is not None else None\n\n    def rate_limit(self, key: str, limit: int = 10, window: int = 60) -> bool:\n        \"\"\"Check rate limit\"\"\"\n        pipe = self.client.pipeline()\n        now = int(time.time())\n        window_start = now - window\n\n        pipe.zremrangebyscore(key, 0, window_start)\n        pipe.zcard(key)\n        pipe.zadd(key, {str(now): now})\n        pipe.expire(key, window)\n\n        results = pipe.execute()\n        return results[1] < limit\n\n    def close(self):\n        \"\"\"Close connection\"\"\"\n        self.client.close()\n\n# Usage example\nif __name__ == '__main__':\n    redis_mgr = RedisManager()\n\n    # Cache operations\n    redis_mgr.cache_set('user:1000', {\n        'name': 'John',\n        'email': '[email protected]'\n    }, ttl=3600)\n\n    user = redis_mgr.cache_get('user:1000')\n    print(f'Cached user: {user}')\n\n    # Track activity\n    redis_mgr.track_user_activity('user:1000', 'login')\n    redis_mgr.track_user_activity('user:1000', 'view_profile')\n\n    # Get activity\n    today = time.strftime('%Y-%m-%d')\n    activities = redis_mgr.get_user_activity('user:1000', today)\n    print(f'Activities: {activities}')\n\n    # Page views\n    views = redis_mgr.increment_page_view('page:home')\n    print(f'Page views: {views}')\n\n    # Leaderboard\n    redis_mgr.add_to_leaderboard('user:1000', 500)\n    redis_mgr.add_to_leaderboard('user:2000', 750)\n    redis_mgr.add_to_leaderboard('user:3000', 250)\n\n    top_users = redis_mgr.get_leaderboard(3)\n    print(f'Top users: {top_users}')\n\n    rank = redis_mgr.get_user_rank('user:1000')\n    print(f'User rank: {rank}')\n\n    # Rate limiting\n    for i in range(12):\n        allowed = redis_mgr.rate_limit('api:user:1000', limit=10, window=60)\n        print(f'Request {i + 1}: {\"Allowed\" if allowed else \"Blocked\"}')\n\n    redis_mgr.close()\n```\n"
  },
  {
    "path": "content/redis/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"redis-py package guide for Python projects using Redis sync, asyncio, TLS, Sentinel, and cluster clients\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"redis,python,cache,key-value,pubsub,asyncio,cluster\"\n---\n\n# redis Python Package Guide\n\n## Golden Rule\n\nUse the official `redis` package (`redis-py`) for both synchronous and asynchronous Redis access. As of March 12, 2026, PyPI lists `redis 7.3.0`, requires Python `>=3.10`, and points to `https://redis.readthedocs.io/en/stable/` as the official docs root. The docs URL (`https://redis-py.readthedocs.io/en/stable/`) is stale and should not be used.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"redis==7.3.0\"\n```\n\nUseful extras:\n\n```bash\npython -m pip install \"redis[hiredis]==7.3.0\"\npython -m pip install \"redis[ocsp]==7.3.0\"\npython -m pip install \"redis[otel]==7.3.0\"\n```\n\n- `hiredis`: faster response parser\n- `ocsp`: OCSP validation for TLS connections\n- `otel`: OpenTelemetry instrumentation helpers\n\nIf your runtime is still on Python 3.9, `redis 7.3.0` will not install. PyPI notes that `redis 7.0.1` was the last version supporting Python 3.9.\n\n## Initialize A Client\n\n### Sync client\n\nPrefer a URL so local, TLS, ACL, and managed-service setups use the same entry point:\n\n```python\nimport os\nimport redis\n\nclient = redis.from_url(\n    os.environ.get(\"REDIS_URL\", \"redis://localhost:6379/0\"),\n    decode_responses=True,\n    health_check_interval=30,\n)\n\nclient.ping()\n```\n\nSupported URL schemes include:\n\n- `redis://` for plain TCP\n- `rediss://` for TLS\n- `unix://` for Unix domain sockets\n\n### Async client\n\nAsync support lives in the same package under `redis.asyncio`:\n\n```python\nimport os\nimport asyncio\nimport redis.asyncio as redis\n\nasync def main() -> None:\n    client = redis.from_url(\n        os.environ.get(\"REDIS_URL\", \"redis://localhost:6379/0\"),\n        decode_responses=True,\n        health_check_interval=30,\n    )\n    try:\n        await client.set(\"job:1\", \"queued\", ex=60)\n        print(await client.get(\"job:1\"))\n    finally:\n        await client.aclose()\n\nasyncio.run(main())\n```\n\nClose async clients explicitly with `await client.aclose()` so connection pools are released.\n\n### RESP3\n\n`redis-py` uses RESP2 unless you opt into RESP3:\n\n```python\nimport redis\n\nclient = redis.Redis(\n    host=\"localhost\",\n    port=6379,\n    decode_responses=True,\n    protocol=3,\n)\n```\n\nUse RESP3 only when your server and the features you need expect it.\n\n## Core Usage\n\n### Basic key-value operations\n\n```python\nimport redis\n\nclient = redis.from_url(\"redis://localhost:6379/0\", decode_responses=True)\n\nclient.set(\"session:42\", \"active\", ex=300)\nstatus = client.get(\"session:42\")\nttl = client.ttl(\"session:42\")\n\nclient.hset(\"user:42\", mapping={\"name\": \"Ada\", \"role\": \"admin\"})\nuser = client.hgetall(\"user:42\")\n```\n\n### Pipelines and transactions\n\nUse pipelines to batch commands. Use `transaction=True` when you need `MULTI/EXEC` semantics:\n\n```python\nimport redis\n\nclient = redis.Redis(decode_responses=True)\n\nwith client.pipeline(transaction=True) as pipe:\n    pipe.incr(\"counters:pageviews\")\n    pipe.expire(\"counters:pageviews\", 3600)\n    result = pipe.execute()\n\nprint(result)\n```\n\nFor optimistic locking, use `WATCH`:\n\n```python\nimport redis\n\nclient = redis.Redis(decode_responses=True)\n\nwith client.pipeline() as pipe:\n    while True:\n        try:\n            pipe.watch(\"inventory:sku-1\")\n            current = int(pipe.get(\"inventory:sku-1\") or 0)\n            pipe.multi()\n            pipe.set(\"inventory:sku-1\", current - 1)\n            pipe.execute()\n            break\n        except redis.WatchError:\n            continue\n```\n\n### Pub/Sub\n\n```python\nimport redis\n\nclient = redis.Redis(decode_responses=True)\npubsub = client.pubsub()\npubsub.subscribe(\"events\")\n\nfor message in pubsub.listen():\n    if message[\"type\"] == \"message\":\n        print(message[\"data\"])\n```\n\nDo not share one `PubSub` object across unrelated threads or long-lived app components.\n\n## Config And Auth\n\n### ACL username and password\n\n```python\nimport redis\n\nclient = redis.Redis(\n    host=\"redis.example.com\",\n    port=6379,\n    username=\"default\",\n    password=\"secret\",\n    decode_responses=True,\n)\n```\n\nThe equivalent URL form is:\n\n```text\nredis://default:secret@redis.example.com:6379/0\n```\n\n### Credential providers\n\nUse a credential provider when credentials are fetched dynamically:\n\n```python\nimport redis\nfrom redis.credentials import UsernamePasswordCredentialProvider\n\nprovider = UsernamePasswordCredentialProvider(\n    username=\"default\",\n    password=\"secret\",\n)\n\nclient = redis.Redis(\n    host=\"redis.example.com\",\n    port=6379,\n    credential_provider=provider,\n    decode_responses=True,\n)\n```\n\n### TLS\n\nFor managed Redis deployments, prefer a `rediss://` URL or explicit TLS settings:\n\n```python\nimport redis\nimport ssl\n\nclient = redis.Redis(\n    host=\"redis.example.com\",\n    port=6380,\n    username=\"default\",\n    password=\"secret\",\n    ssl=True,\n    ssl_cert_reqs=ssl.CERT_REQUIRED,\n    ssl_ca_certs=\"/etc/ssl/certs/ca-certificates.crt\",\n    decode_responses=True,\n)\n```\n\nRelevant connection settings in the upstream API reference include `socket_timeout`, `socket_connect_timeout`, `retry`, `retry_on_timeout`, `health_check_interval`, and TLS certificate options.\n\n## Sentinel And Cluster\n\n### Sentinel\n\n```python\nfrom redis.sentinel import Sentinel\n\nsentinel = Sentinel(\n    [(\"sentinel-1\", 26379), (\"sentinel-2\", 26379)],\n    socket_timeout=0.5,\n    username=\"default\",\n    password=\"secret\",\n)\n\nclient = sentinel.master_for(\"mymaster\", decode_responses=True)\nclient.ping()\n```\n\n### Cluster\n\nCluster support is built into `redis`; do not add `redis-py-cluster`:\n\n```python\nfrom redis.cluster import RedisCluster\n\nclient = RedisCluster(\n    host=\"redis-cluster.example.com\",\n    port=6379,\n    decode_responses=True,\n)\n\nclient.set(\"user-profile:{42}\", \"ready\")\nprint(client.get(\"user-profile:{42}\"))\n```\n\nUse hash tags like `{42}` when multi-key operations must land in the same slot.\n\n## Common Pitfalls\n\n- Responses are `bytes` by default. Set `decode_responses=True` if your app expects strings.\n- `redis.asyncio` is the supported async API. Do not add the deprecated standalone `aioredis` package.\n- Cluster support is built in. Do not add the deprecated `redis-py-cluster` package.\n- `SELECT` is not implemented on Redis client instances. Choose the database in the URL or connection parameters and create separate clients if you need different DB numbers.\n- RESP3 is opt-in with `protocol=3`; do not assume RESP3-only behavior on a default client.\n- Pub/Sub, pipelines, and pubsub listeners are stateful objects; keep their ownership explicit instead of sharing them broadly.\n- In cluster mode, multi-key commands only work when keys hash to the same slot. Hash tags are the usual fix.\n- Query, search, JSON, time series, and vector commands depend on server-side modules or Redis Stack features. Package install alone does not enable those commands.\n\n## Version-Sensitive Notes\n\n- `redis 7.3.0` is the current PyPI release as of March 12, 2026.\n- The official docs root is `https://redis.readthedocs.io/en/stable/`; the older `redis-py.readthedocs.io` URL is stale.\n- PyPI metadata for `7.3.0` requires Python `>=3.10`. That is the first constraint to check before suggesting an upgrade.\n- `redis-py` continues to unify sync, asyncio, Sentinel, and Cluster support in one package, so older package splits from blog posts are usually wrong.\n- If you use RediSearch helpers (`ft()` APIs), check the current query dialect behavior in the upstream docs instead of relying on older examples.\n\n## Official Sources\n\n- Docs root: `https://redis.readthedocs.io/en/stable/`\n- Examples: `https://redis.readthedocs.io/en/stable/examples.html`\n- Async examples: `https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html`\n- Connections API: `https://redis.readthedocs.io/en/stable/connections.html`\n- Advanced features: `https://redis.readthedocs.io/en/stable/advanced_features.html`\n- Cluster guide: `https://redis.readthedocs.io/en/stable/clustering.html`\n- PyPI registry: `https://pypi.org/project/redis/`\n"
  },
  {
    "path": "content/redux/docs/redux/javascript/DOC.md",
    "content": "---\nname: redux\ndescription: \"Core Redux APIs for creating stores, reducers, middleware, and subscriptions in JavaScript applications.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"redux,state,store,reducer,middleware,javascript\"\n---\n\n# Redux Core Guide\n\nThis guide covers the standalone `redux` core package.\n\nFor most new Redux application code, the Redux maintainers recommend `@reduxjs/toolkit` instead of building directly on `createStore`. Use the core `redux` package when you want the low-level store primitives directly, are learning the Redux data flow, or are integrating Redux into a library.\n\n## Install\n\n```bash\nnpm install redux\n```\n\n`redux` has no environment variables, credentials, or client initialization step.\n\n## Create a Store\n\nIn Redux 5, `createStore` is deprecated in favor of Redux Toolkit. If you intentionally want the core store API, import `legacy_createStore` and alias it locally.\n\n```javascript\nimport { legacy_createStore as createStore } from \"redux\";\n\nconst initialState = { count: 0 };\n\nfunction counterReducer(state = initialState, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    case \"counter/add\":\n      return { count: state.count + action.payload };\n    default:\n      return state;\n  }\n}\n\nconst store = createStore(counterReducer);\n\nconst unsubscribe = store.subscribe(() => {\n  console.log(\"state\", store.getState());\n});\n\nstore.dispatch({ type: \"counter/increment\" });\nstore.dispatch({ type: \"counter/add\", payload: 3 });\n\nunsubscribe();\n```\n\nUse `store.getState()` to read the current state, `store.dispatch()` to send actions, and `store.subscribe()` to react after every dispatch.\n\n## Hydrate Initial State\n\nPass a second argument when you need to restore serialized state from the server or boot from saved data.\n\n```javascript\nimport { legacy_createStore as createStore } from \"redux\";\n\nfunction counterReducer(state = { count: 0 }, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    default:\n      return state;\n  }\n}\n\nconst preloadedState = { count: 10 };\n\nconst store = createStore(counterReducer, preloadedState);\n```\n\nIf you use `combineReducers`, the `preloadedState` object must use the same top-level keys as your combined reducers.\n\n## Combine Multiple Reducers\n\n`combineReducers` turns a map of slice reducers into one root reducer.\n\n```javascript\nimport {\n  combineReducers,\n  legacy_createStore as createStore,\n} from \"redux\";\n\nfunction counterReducer(state = { count: 0 }, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    default:\n      return state;\n  }\n}\n\nfunction filterReducer(state = \"all\", action) {\n  switch (action.type) {\n    case \"filter/set\":\n      return action.payload;\n    default:\n      return state;\n  }\n}\n\nconst rootReducer = combineReducers({\n  counter: counterReducer,\n  filter: filterReducer,\n});\n\nconst store = createStore(rootReducer, {\n  counter: { count: 5 },\n  filter: \"completed\",\n});\n\nstore.dispatch({ type: \"filter/set\", payload: \"active\" });\n```\n\nEach slice reducer must return its initial state when called with `undefined`, and must return the previous state for unknown actions.\n\n## Add Middleware\n\nUse `applyMiddleware` to wrap `dispatch()`.\n\n```javascript\nimport {\n  applyMiddleware,\n  combineReducers,\n  legacy_createStore as createStore,\n} from \"redux\";\n\nfunction counterReducer(state = { count: 0 }, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    default:\n      return state;\n  }\n}\n\nconst rootReducer = combineReducers({\n  counter: counterReducer,\n});\n\nconst logger = (storeAPI) => (next) => (action) => {\n  console.log(\"dispatching\", action);\n  const result = next(action);\n  console.log(\"next state\", storeAPI.getState());\n  return result;\n};\n\nconst store = createStore(rootReducer, applyMiddleware(logger));\n\nstore.dispatch({ type: \"counter/increment\" });\n```\n\nIf you also need a preloaded state value, pass it as the second argument and the enhancer as the third:\n\n```javascript\nconst store = createStore(rootReducer, { counter: { count: 1 } }, applyMiddleware(logger));\n```\n\nMiddleware is the extension point you need when you want to dispatch values other than plain object actions.\n\n## Bind Action Creators\n\n`bindActionCreators` is a convenience helper that wraps action creators so they dispatch automatically.\n\n```javascript\nimport {\n  bindActionCreators,\n  legacy_createStore as createStore,\n} from \"redux\";\n\nfunction counterReducer(state = { count: 0 }, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    case \"counter/add\":\n      return { count: state.count + action.payload };\n    default:\n      return state;\n  }\n}\n\nconst store = createStore(counterReducer);\n\nconst actions = bindActionCreators(\n  {\n    increment: () => ({ type: \"counter/increment\" }),\n    add: (amount) => ({ type: \"counter/add\", payload: amount }),\n  },\n  store.dispatch,\n);\n\nactions.increment();\nactions.add(5);\n```\n\nThis is optional. Calling `store.dispatch(actionCreator())` directly is also valid.\n\n## Replace the Root Reducer\n\nUse `store.replaceReducer()` when the root reducer changes at runtime, such as after loading new reducer code.\n\n```javascript\nimport {\n  combineReducers,\n  legacy_createStore as createStore,\n} from \"redux\";\n\nfunction counterReducer(state = { count: 0 }, action) {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { count: state.count + 1 };\n    default:\n      return state;\n  }\n}\n\nfunction todosReducer(state = [], action) {\n  switch (action.type) {\n    case \"todos/add\":\n      return [...state, action.payload];\n    default:\n      return state;\n  }\n}\n\nconst store = createStore(\n  combineReducers({\n    counter: counterReducer,\n  }),\n);\n\nstore.replaceReducer(\n  combineReducers({\n    counter: counterReducer,\n    todos: todosReducer,\n  }),\n);\n```\n\nReplacing the reducer dispatches an internal action so newly added reducers can populate their initial state.\n\n## Important Pitfalls\n\n- Prefer `@reduxjs/toolkit` for new application code. The Redux maintainers describe it as the standard way to write Redux today.\n- `dispatch()` only accepts plain object actions by default. If you want to dispatch functions, promises, or other values, add middleware.\n- Action objects must have a defined `type`, and in Redux 5 that `type` must be a string.\n- Reducers must never return `undefined`. Return the previous state for unknown actions, and return the initial state when `state` is `undefined`.\n- Do not handle Redux private action types such as `@@redux/*` directly.\n- `combineReducers` validates each slice reducer. A single reducer that returns `undefined` will fail the whole store setup.\n- Do not call `store.getState()`, `store.subscribe()`, or unsubscribe a listener while a reducer is executing.\n\n## Version Notes for `redux@5`\n\n- `createStore` is intentionally marked deprecated; use `legacy_createStore` if you still need the core store API.\n- `redux@5` exports `isAction()` and `isPlainObject()` utility guards if you need to validate inputs in custom integrations.\n- The TypeScript `AnyAction` type is deprecated in the package declarations in favor of stricter action typing.\n"
  },
  {
    "path": "content/redux/docs/toolkit/javascript/DOC.md",
    "content": "---\nname: toolkit\ndescription: \"Redux Toolkit for configuring Redux stores, creating slice reducers, handling async logic, and using RTK Query in JavaScript apps\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.11.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"redux,redux-toolkit,state-management,rtk-query,javascript\"\n---\n\n# Redux Toolkit for JavaScript\n\nUse `@reduxjs/toolkit` to build Redux stores with `configureStore`, feature state with `createSlice`, async flows with `createAsyncThunk`, and data fetching with RTK Query. For React apps, pair it with `react-redux`.\n\n## Golden Rules\n\n- Install `@reduxjs/toolkit` for Redux logic, and add `react-redux` when the app uses React components.\n- Create stores with `configureStore` instead of `createStore`.\n- Put reducer logic and action creators in `createSlice`.\n- Use `createAsyncThunk` for request lifecycles you manage yourself, or RTK Query for API caching and generated hooks.\n- Keep Redux state and actions serializable unless you intentionally customize the default middleware checks.\n- Import RTK Query from `@reduxjs/toolkit/query/react` in React apps, or from `@reduxjs/toolkit/query` in non-React code.\n\n## Install\n\n```bash\nnpm install @reduxjs/toolkit\nnpm install react-redux\n```\n\n`react-redux` is only required if you render Redux state from React components.\n\n## Prerequisites\n\nRedux Toolkit is a local state-management library. It does not require API keys or built-in authentication.\n\nIf you use RTK Query against an HTTP API, set your app's API base URL however your runtime expects. For a Vite app, for example:\n\n```bash\nexport VITE_API_URL=\"https://api.example.com\"\n```\n\n## Create a Store and Slice\n\n`configureStore` is the standard entry point. When `reducer` is an object, it combines those slice reducers under the same keys. It also adds Redux Thunk and the default development middleware checks for immutable and serializable state, and enables Redux DevTools.\n\n`src/features/counter/counterSlice.js`\n\n```javascript\nimport { createSlice } from \"@reduxjs/toolkit\";\n\nconst counterSlice = createSlice({\n  name: \"counter\",\n  initialState: {\n    value: 0,\n  },\n  reducers: {\n    increment(state) {\n      state.value += 1;\n    },\n    decrement(state) {\n      state.value -= 1;\n    },\n    incrementByAmount(state, action) {\n      state.value += action.payload;\n    },\n    reset() {\n      return { value: 0 };\n    },\n  },\n});\n\nexport const { increment, decrement, incrementByAmount, reset } =\n  counterSlice.actions;\n\nexport default counterSlice.reducer;\n```\n\n`src/app/store.js`\n\n```javascript\nimport { configureStore } from \"@reduxjs/toolkit\";\nimport counterReducer from \"../features/counter/counterSlice\";\n\nexport const store = configureStore({\n  reducer: {\n    counter: counterReducer,\n  },\n});\n```\n\n## Connect Redux to React\n\nWrap the app with `Provider` from `react-redux`, then read and dispatch state from components.\n\n`src/main.jsx`\n\n```javascript\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport { Provider } from \"react-redux\";\nimport { store } from \"./app/store\";\nimport App from \"./App\";\n\nReactDOM.createRoot(document.getElementById(\"root\")).render(\n  <React.StrictMode>\n    <Provider store={store}>\n      <App />\n    </Provider>\n  </React.StrictMode>,\n);\n```\n\n`src/features/counter/Counter.jsx`\n\n```javascript\nimport { useDispatch, useSelector } from \"react-redux\";\nimport {\n  decrement,\n  increment,\n  incrementByAmount,\n} from \"./counterSlice\";\n\nexport function Counter() {\n  const value = useSelector((state) => state.counter.value);\n  const dispatch = useDispatch();\n\n  return (\n    <div>\n      <p>Count: {value}</p>\n      <button onClick={() => dispatch(decrement())}>-</button>\n      <button onClick={() => dispatch(increment())}>+</button>\n      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>\n    </div>\n  );\n}\n```\n\n## Handle Async Logic with `createAsyncThunk`\n\nUse `createAsyncThunk` when you want explicit `pending` / `fulfilled` / `rejected` action types and reducer cases.\n\n`src/features/users/usersSlice.js`\n\n```javascript\nimport { createAsyncThunk, createSlice } from \"@reduxjs/toolkit\";\n\nconst apiBaseUrl = import.meta.env.VITE_API_URL ?? \"http://localhost:3000\";\n\nexport const fetchUserById = createAsyncThunk(\n  \"users/fetchById\",\n  async (userId) => {\n    const response = await fetch(`${apiBaseUrl}/users/${userId}`);\n\n    if (!response.ok) {\n      throw new Error(`Request failed with status ${response.status}`);\n    }\n\n    return response.json();\n  },\n);\n\nconst usersSlice = createSlice({\n  name: \"users\",\n  initialState: {\n    entities: {},\n    status: \"idle\",\n    error: null,\n  },\n  reducers: {},\n  extraReducers: (builder) => {\n    builder\n      .addCase(fetchUserById.pending, (state) => {\n        state.status = \"loading\";\n        state.error = null;\n      })\n      .addCase(fetchUserById.fulfilled, (state, action) => {\n        state.status = \"succeeded\";\n        state.entities[action.payload.id] = action.payload;\n      })\n      .addCase(fetchUserById.rejected, (state, action) => {\n        state.status = \"failed\";\n        state.error = action.error.message ?? \"Request failed\";\n      });\n  },\n});\n\nexport default usersSlice.reducer;\n```\n\nAdd the reducer to the store so the slice state is available at `state.users`.\n\n```javascript\nimport { configureStore } from \"@reduxjs/toolkit\";\nimport counterReducer from \"../features/counter/counterSlice\";\nimport usersReducer from \"../features/users/usersSlice\";\n\nexport const store = configureStore({\n  reducer: {\n    counter: counterReducer,\n    users: usersReducer,\n  },\n});\n```\n\nWhen dispatching the thunk, call `.unwrap()` if you want the returned promise to resolve with the fulfilled payload or throw the rejected error.\n\n```javascript\nimport { useDispatch } from \"react-redux\";\nimport { fetchUserById } from \"./usersSlice\";\n\nexport function LoadUserButton() {\n  const dispatch = useDispatch();\n\n  async function handleClick() {\n    try {\n      const user = await dispatch(fetchUserById(42)).unwrap();\n      console.log(user.name);\n    } catch (error) {\n      console.error(error);\n    }\n  }\n\n  return <button onClick={handleClick}>Load user</button>;\n}\n```\n\n## Customize Default Middleware\n\n`configureStore` uses `getDefaultMiddleware()` unless you replace it. Use the callback form to keep the defaults and adjust their options.\n\n```javascript\nimport { configureStore } from \"@reduxjs/toolkit\";\nimport counterReducer from \"../features/counter/counterSlice\";\n\nexport const store = configureStore({\n  reducer: {\n    counter: counterReducer,\n  },\n  middleware: (getDefaultMiddleware) =>\n    getDefaultMiddleware({\n      serializableCheck: false,\n    }),\n});\n```\n\nOnly disable a check when your app really needs it. The defaults are helpful for catching accidental state mutations and non-serializable values during development.\n\n## Use RTK Query for API Data\n\nRTK Query is included in Redux Toolkit. In React apps, create an API slice with `createApi`, add its reducer and middleware to the store, call `setupListeners`, and use the generated hooks.\n\n`src/services/postsApi.js`\n\n```javascript\nimport { createApi, fetchBaseQuery } from \"@reduxjs/toolkit/query/react\";\n\nconst apiBaseUrl = import.meta.env.VITE_API_URL ?? \"http://localhost:3000\";\n\nexport const postsApi = createApi({\n  reducerPath: \"postsApi\",\n  baseQuery: fetchBaseQuery({\n    baseUrl: apiBaseUrl,\n  }),\n  endpoints: (builder) => ({\n    getPosts: builder.query({\n      query: () => \"/posts\",\n    }),\n    addPost: builder.mutation({\n      query: (body) => ({\n        url: \"/posts\",\n        method: \"POST\",\n        body,\n      }),\n    }),\n  }),\n});\n\nexport const { useGetPostsQuery, useAddPostMutation } = postsApi;\n```\n\n`src/app/store.js`\n\n```javascript\nimport { configureStore } from \"@reduxjs/toolkit\";\nimport { setupListeners } from \"@reduxjs/toolkit/query\";\nimport counterReducer from \"../features/counter/counterSlice\";\nimport { postsApi } from \"../services/postsApi\";\n\nexport const store = configureStore({\n  reducer: {\n    counter: counterReducer,\n    [postsApi.reducerPath]: postsApi.reducer,\n  },\n  middleware: (getDefaultMiddleware) =>\n    getDefaultMiddleware().concat(postsApi.middleware),\n});\n\nsetupListeners(store.dispatch);\n```\n\n`src/features/posts/PostsList.jsx`\n\n```javascript\nimport { useState } from \"react\";\nimport {\n  useAddPostMutation,\n  useGetPostsQuery,\n} from \"../../services/postsApi\";\n\nexport function PostsList() {\n  const { data: posts = [], isLoading, isError } = useGetPostsQuery();\n  const [addPost, { isLoading: isSaving }] = useAddPostMutation();\n  const [title, setTitle] = useState(\"\");\n\n  if (isLoading) {\n    return <p>Loading...</p>;\n  }\n\n  if (isError) {\n    return <p>Could not load posts.</p>;\n  }\n\n  async function handleSubmit(event) {\n    event.preventDefault();\n    await addPost({ title }).unwrap();\n    setTitle(\"\");\n  }\n\n  return (\n    <>\n      <ul>\n        {posts.map((post) => (\n          <li key={post.id}>{post.title}</li>\n        ))}\n      </ul>\n\n      <form onSubmit={handleSubmit}>\n        <input\n          value={title}\n          onChange={(event) => setTitle(event.target.value)}\n          placeholder=\"New post title\"\n        />\n        <button type=\"submit\" disabled={isSaving}>\n          {isSaving ? \"Saving...\" : \"Add post\"}\n        </button>\n      </form>\n    </>\n  );\n}\n```\n\nCall `setupListeners(store.dispatch)` once after store creation if you want RTK Query features such as `refetchOnFocus` and `refetchOnReconnect`.\n\n## Pitfalls\n\n- Reducers created with `createSlice` may appear to mutate state because Redux Toolkit uses Immer internally. That only applies inside reducer logic. Outside reducers, treat state as immutable.\n- Reassigning `state = someValue` inside a case reducer does not replace the current state. Return the new value instead.\n- Non-serializable values such as functions, class instances, DOM nodes, `Map`, `Set`, or promises can trigger the default middleware warnings.\n- RTK Query needs both `postsApi.reducer` and `postsApi.middleware` added to the store. Missing either one causes broken cache behavior.\n- Generated RTK Query hooks come from `@reduxjs/toolkit/query/react`. If you import from `@reduxjs/toolkit/query`, you do not get React hooks.\n"
  },
  {
    "path": "content/referencing/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python library for building registries of JSON resources and resolving references across JSON Schema and related specifications\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.37.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"referencing,jsonschema,refs,json,python\"\n---\n\n# referencing Python Package Guide\n\n## Golden Rule\n\nUse `referencing` to build an immutable `Registry` of `Resource` objects and resolve references with an explicit specification. For JSON Schema work, import the dialect you need from `referencing.jsonschema` instead of assuming the library can infer it from partial documents.\n\n`referencing` has no API key, auth flow, or environment-variable configuration. Everything is configured in Python code.\n\n## Install\n\n`referencing 0.37.0` requires Python 3.10 or newer.\n\n```bash\npython -m pip install \"referencing==0.37.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"referencing==0.37.0\"\npoetry add \"referencing==0.37.0\"\n```\n\n## Core Types\n\n- `Registry`: an immutable collection of resources, optionally with a retrieval callback\n- `Resource`: document contents plus the specification used to interpret IDs, anchors, and subresources\n- `Specification`: rules for how references behave, such as `DRAFT202012` or `DRAFT7`\n\nEvery mutating-looking operation returns a new registry. Reassign the result.\n\n## Initialize A Registry For JSON Schema\n\nIf your schema includes `$schema` and `$id`, `Resource.from_contents` can detect the correct behavior automatically:\n\n```python\nfrom referencing import Registry, Resource\n\nuser_schema = Resource.from_contents(\n    {\n        \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n        \"$id\": \"https://example.com/schemas/user\",\n        \"$defs\": {\n            \"id\": {\"type\": \"integer\"},\n        },\n        \"type\": \"object\",\n        \"properties\": {\n            \"id\": {\"$ref\": \"#/$defs/id\"},\n        },\n        \"required\": [\"id\"],\n    }\n)\n\nregistry = user_schema @ Registry()\n\nresolved = registry.resolver().lookup(\"https://example.com/schemas/user#/$defs/id\")\nprint(resolved.contents)  # {'type': 'integer'}\n```\n\nThe `@` operator adds a resource to a registry using its internal identifier. Use it only when the resource actually has an ID the specification can discover.\n\n## Add Schemas Without `$schema` Or `$id`\n\nIf your files omit `$schema`, pass the dialect explicitly. If they omit `$id`, store them under an external URI with `with_contents` or `with_resource`.\n\n```python\nfrom referencing import Registry\nfrom referencing.jsonschema import DRAFT202012\n\nregistry = Registry().with_contents(\n    [\n        (\n            \"urn:example:user\",\n            {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\"type\": \"integer\"},\n                    \"name\": {\"type\": \"string\"},\n                },\n                \"required\": [\"id\", \"name\"],\n            },\n        )\n    ],\n    default_specification=DRAFT202012,\n)\n\nprint(registry.contents(\"urn:example:user\"))\n```\n\nUse this pattern for test fixtures, generated schemas, or bundled documents that do not carry full metadata.\n\n## Retrieve Resources Lazily From Disk\n\n`referencing` does not automatically fetch over the network. The supported way to load missing resources is to provide a retrieval function. The docs show this pattern for filesystem, YAML, SQLite, HTTP, or package-backed resources.\n\n```python\nfrom pathlib import Path\n\nfrom referencing import Registry\nfrom referencing.exceptions import NoSuchResource\nfrom referencing.jsonschema import DRAFT202012\nfrom referencing.retrieval import to_cached_resource\n\nSCHEMA_DIR = Path(__file__).parent / \"schemas\"\n\n\n@to_cached_resource(from_contents=DRAFT202012.create_resource)\ndef retrieve_from_disk(uri: str):\n    name = uri.removeprefix(\"urn:schemas:\")\n    path = SCHEMA_DIR / f\"{name}.json\"\n    if not path.is_file():\n        raise NoSuchResource(uri)\n    return path.read_text(encoding=\"utf-8\")\n\n\nregistry = Registry(retrieve=retrieve_from_disk)\n\naddress = registry.resolver().lookup(\"urn:schemas:address\")\nprint(address.contents)\n```\n\n`to_cached_resource` is useful when your retrieval function returns serialized content. It decodes the content once and caches the resulting `Resource`.\n\n## Combine Registries\n\nIf your application has several independently-built registries, combine them before validation or reference lookup:\n\n```python\nfrom referencing import Registry\nfrom referencing.jsonschema import DRAFT202012\n\nproject_registry = Registry().with_contents(\n    [(\"urn:example:user\", {\"type\": \"object\"})],\n    default_specification=DRAFT202012,\n)\n\nshared_registry = Registry().with_contents(\n    [(\"urn:example:address\", {\"type\": \"object\"})],\n    default_specification=DRAFT202012,\n)\n\nregistry = project_registry.combine(shared_registry).crawl()\n```\n\nUse `crawl()` when you want the registry to eagerly discover nested subresources instead of waiting for lookups.\n\n## Common Pitfalls\n\n- Registries are immutable. `with_resource`, `with_contents`, `combine`, and similar calls do not modify the original object.\n- `Resource.from_contents(...)` needs a detectable specification. For JSON Schema, that usually means a `$schema` field. If it is missing, pass `default_specification=` or construct the resource explicitly.\n- The `@` operator only works when a resource has an internal ID. If a document does not declare one, store it under an external URI instead.\n- Automatic retrieval is opt-in. If a `$ref` points at an unknown URI and you did not configure `Registry(retrieve=...)`, lookup will fail.\n- Be careful with network retrieval. The JSON Schema specifications discourage automatically downloading schemas from the network.\n\n## Version-Sensitive Notes For 0.37.0\n\n- `0.37.0` adds Python 3.14 support and removes Python 3.9 support. The published package metadata requires Python 3.10+.\n- The project still describes itself as beta software and uses `0.x` versioning. Pin the package version if you are writing a library or long-lived service.\n- `referencing.retrieval.to_cached_resource` was added in `0.29.0`, and `referencing.jsonschema.EMPTY_REGISTRY` was added in `0.31.0`. Do not assume those helpers exist on older pins.\n\n## Official Sources\n\n- Maintainer docs root: https://referencing.readthedocs.io/en/stable/\n- Introduction: https://referencing.readthedocs.io/en/stable/intro/\n- JSON Schema integration: https://referencing.readthedocs.io/en/stable/jsonschema/\n- Schema packages and retrieval: https://referencing.readthedocs.io/en/stable/schema-package/\n- API reference: https://referencing.readthedocs.io/en/stable/api/\n- Changelog: https://referencing.readthedocs.io/en/stable/changes/\n- PyPI package: https://pypi.org/project/referencing/\n"
  },
  {
    "path": "content/reflex/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Reflex Python package guide for building full-stack web apps in pure Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.8.27\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"reflex,python,web,framework,ui,full-stack\"\n---\n\n# Reflex Python Package Guide\n\n## Golden Rule\n\nUse the official `reflex` package, import it as `import reflex as rx`, start new apps with `reflex init`, and let Reflex compile Python state and components into the frontend/backend runtime it manages for you. Do not mix in ad hoc React files unless you are intentionally extending Reflex with custom components.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"reflex==0.8.27\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"reflex==0.8.27\"\npoetry add \"reflex==0.8.27\"\n```\n\nPyPI currently publishes optional extras for database and monitoring features:\n\n```bash\npython -m pip install \"reflex[db]==0.8.27\"\npython -m pip install \"reflex[monitoring]==0.8.27\"\n```\n\n## Initialize A New App\n\nThe official installation flow uses `uv`, but the CLI also works from a normal virtualenv.\n\nUsing `uv`:\n\n```bash\nmkdir my_app\ncd my_app\nuv init\nuv add \"reflex==0.8.27\"\nuv run reflex init\nuv run reflex run\n```\n\nUsing `venv` + `pip`:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"reflex==0.8.27\"\nreflex init\nreflex run\n```\n\nImportant generated files:\n\n- `rxconfig.py`: app-level Reflex configuration\n- `<app_name>/<app_name>.py`: default app entry module created by `reflex init`\n- `.web/`: generated frontend build artifacts; treat this as generated output\n\n## Core Usage\n\nReflex apps are built from three main pieces:\n\n- components such as `rx.text`, `rx.button`, `rx.vstack`\n- state classes derived from `rx.State`\n- pages added to an `rx.App()`\n\nMinimal counter example:\n\n```python\nimport reflex as rx\n\nclass CounterState(rx.State):\n    count: int = 0\n\n    @rx.var\n    def parity(self) -> str:\n        return \"even\" if self.count % 2 == 0 else \"odd\"\n\n    def increment(self):\n        self.count += 1\n\ndef index() -> rx.Component:\n    return rx.vstack(\n        rx.heading(\"Counter\"),\n        rx.text(\"Count: \", CounterState.count),\n        rx.text(\"Parity: \", CounterState.parity),\n        rx.button(\"Increment\", on_click=CounterState.increment),\n        spacing=\"3\",\n        padding=\"2rem\",\n    )\n\napp = rx.App()\napp.add_page(index, route=\"/\")\n```\n\nPatterns the official docs lean on:\n\n- Use `@rx.var` for computed values derived from state.\n- Use event handlers on `rx.State` methods to mutate state.\n- Use `rx.cond(...)` for conditional rendering and `rx.foreach(...)` for list rendering instead of raw Python `if`/`for` inside the component tree.\n- Use the `@rx.page(...)` decorator when page metadata or `on_load` behavior belongs next to the page function.\n\n## Configuration, Environment Variables, And Auth\n\nReflex configuration lives in `rxconfig.py`:\n\n```python\nimport reflex as rx\n\nconfig = rx.Config(\n    app_name=\"my_app\",\n    api_url=\"http://localhost:8000\",\n    backend_port=8000,\n    frontend_port=3000,\n    db_url=\"sqlite:///reflex.db\",\n    env_file=\".env\",\n)\n```\n\nPractical rules:\n\n- Treat `rxconfig.py` as the source of truth for ports, URLs, database connection, and deployment-facing config.\n- Keep secrets out of source control. Put them in `.env` locally and in your hosting secret store for deployed apps.\n- The config reference says config values can be overridden with environment variables prefixed by `REFLEX_`, for example `REFLEX_API_URL` or `REFLEX_DB_URL`.\n- If you deploy to Reflex Cloud, authenticate the CLI with `reflex cloud login` before deploying or managing secrets.\n\nReflex itself is not your identity provider. For application auth, keep credentials in environment variables and run any session/bootstrap checks from page load hooks or state methods rather than hardcoding secrets into components.\n\n## Database Workflow\n\nIf your app uses the built-in database workflow, define models with `rx.Model` and run the database CLI explicitly.\n\nExample model:\n\n```python\nimport reflex as rx\n\nclass Todo(rx.Model, table=True):\n    title: str\n    done: bool = False\n```\n\nTypical commands:\n\n```bash\nreflex db init\nreflex db makemigrations --message \"create todo table\"\nreflex db migrate\n```\n\nUse a real database URL in `rxconfig.py` or via environment variables before running migrations in shared environments.\n\n## Common Commands\n\n```bash\nreflex init\nreflex run\nreflex run --env prod\nreflex export\nreflex db init\nreflex db makemigrations\nreflex db migrate\nreflex cloud login\nreflex deploy\n```\n\n## Common Pitfalls\n\n- Do not instantiate `rx.State` directly. Define a subclass and let Reflex manage it.\n- Do not mutate state from arbitrary helper code; mutate it from state event handlers so the framework can track updates correctly.\n- Raw Python control flow does not replace Reflex rendering helpers inside component trees. Use `rx.cond` and `rx.foreach`.\n- `reflex init` generates project structure and config. Running `reflex run` in an uninitialized directory is a common mistake.\n- `.web/` is generated output. Do not hand-edit it and expect changes to persist.\n- If pages or models are not discovered, make sure the relevant modules are imported by the app entrypoint before assuming the framework is broken.\n- Database migrations are not automatic. Define the model, then run `reflex db makemigrations` and `reflex db migrate`.\n- Self-hosting and exported frontend deployments need the frontend/backend URLs aligned, or browser calls will point at the wrong backend.\n\n## Version-Sensitive Notes For 0.8.27\n\n- PyPI currently lists `0.8.27` as the package version for `reflex`, with Python support `>=3.10,<4.0`.\n- The public docs site is a rolling documentation set rather than a version-pinned doc tree. For exact `0.8.27` behavior, prefer the generated project files and `reflex --help` over older blog posts or issue comments.\n- PyPI advertises `db` and `monitoring` extras. Keep install commands explicit when your project depends on those optional surfaces.\n- Inference from current upstream docs: configuration naming is slightly inconsistent across pages. The config reference documents `REFLEX_<FIELD>` overrides, while self-hosting examples still show legacy bare names such as `API_URL` and `FRONTEND_PORT`. Prefer the `REFLEX_` form in new code unless the specific deployment guide for your setup says otherwise.\n\n## Official Links\n\n- API reference: `https://reflex.dev/docs/api-reference/`\n- Getting started: `https://reflex.dev/docs/getting-started/introduction/`\n- Installation: `https://reflex.dev/docs/getting-started/installation/`\n- State overview: `https://reflex.dev/docs/state/overview/`\n- Config reference: `https://reflex.dev/docs/api-reference/config/reflex-conf/`\n- CLI reference: `https://reflex.dev/docs/api-reference/cli/`\n- Deploy quick start: `https://reflex.dev/docs/hosting/deploy-quick-start/`\n- Self hosting: `https://reflex.dev/docs/hosting/self-hosting/`\n"
  },
  {
    "path": "content/regex/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python regex package guide for enhanced regular expressions, fuzzy matching, repeated captures, and Unicode-aware text processing\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.28\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"regex,regular-expressions,pattern-matching,text-processing,unicode\"\n---\n\n# regex Python Package Guide\n\n## What This Package Is\n\n`regex` is a third-party regular-expression engine for Python. It is mostly compatible with the standard-library `re` module, but adds features that `re` does not have, including repeated captures, overlapped matches, fuzzy matching, partial matches, nested sets, and richer Unicode handling.\n\n- Ecosystem: `pypi`\n- Package: `regex`\n- Import: `import regex`\n- Covered version: `2026.2.28`\n- Upstream repo: `https://github.com/mrabarnett/mrab-regex`\n- Registry page: `https://pypi.org/project/regex/`\n\nAs of Thursday, March 12, 2026, PyPI shows `2026.2.28` as the current release, which matches the version covered here.\n\n## Installation\n\n```bash\npip install \"regex==2026.2.28\"\n```\n\n```bash\nuv add \"regex==2026.2.28\"\n```\n\n```bash\npoetry add \"regex==2026.2.28\"\n```\n\nPyPI lists `Requires: Python >=3.9` for `2026.2.28`.\n\n## Initialization And Drop-In Use\n\nFor most code, start with the same workflow you would use for `re`:\n\n```python\nimport regex\n\npattern = regex.compile(r\"\\b[a-z]+\\b\", flags=regex.IGNORECASE)\nmatches = pattern.findall(\"One two THREE\")\nprint(matches)  # ['One', 'two', 'THREE']\n```\n\nIf you are migrating code that already imports `re`, the lowest-friction change is often:\n\n```python\nimport regex as re\n\nif re.fullmatch(r\"[A-Z]{3}\\d{2}\", \"ABC12\"):\n    print(\"ok\")\n```\n\nCore entry points that map closely to `re`:\n\n- `regex.compile`\n- `regex.search`, `regex.match`, `regex.fullmatch`\n- `regex.findall`, `regex.finditer`\n- `regex.split`, `regex.sub`, `regex.subn`\n- `regex.escape`\n\n## Core Usage Patterns\n\n### Repeated Captures\n\nRepeated groups keep all captures, not just the last one:\n\n```python\nimport regex\n\nmatch = regex.search(r\"(\\w{2})+\", \"abcd\")\nprint(match.group(1))      # 'cd'\nprint(match.captures(1))   # ['ab', 'cd']\nprint(match.starts(1))     # [0, 2]\nprint(match.ends(1))       # [2, 4]\n```\n\n### Overlapped Matches\n\nUse `overlapped=True` when matches should slide over one another:\n\n```python\nimport regex\n\nprint(regex.findall(r\"aba\", \"ababa\", overlapped=True))\n# ['aba', 'aba']\n```\n\n### Fuzzy Matching\n\nFuzzy constraints allow insertions, deletions, and substitutions:\n\n```python\nimport regex\n\nmatch = regex.search(r\"(color){e<=1}\", \"colour\")\nprint(match.group(0))      # colour\nprint(match.fuzzy_counts)  # e.g. (0, 1, 0)\n```\n\nWhen there are several possible fuzzy matches, `regex.BESTMATCH` is often the safest starting flag.\n\n### Partial Matches\n\nUse `partial=True` for incremental validation or streaming input:\n\n```python\nimport regex\n\nmatch = regex.fullmatch(r\"\\d{4}\", \"12\", partial=True)\nprint(match is not None)  # True\nprint(match.partial)      # True\n```\n\n### Version 1 Features\n\nBe explicit when you rely on `regex`-specific behavior such as nested sets or full case-folding:\n\n```python\nimport regex\n\npattern = regex.compile(r\"[[a-z]--[aeiou]]+\", regex.VERSION1)\nprint(pattern.findall(\"alphabet soup\"))\n```\n\nIf a codebase mixes plain `re`-style patterns and `regex`-specific patterns, call out which ones require `regex.VERSION1` or inline `(?V1)`.\n\n## Configuration And Safety\n\n`regex` is a local library, so there is no service authentication or API credential setup.\n\nConfiguration that matters in practice:\n\n- Choose flags explicitly when behavior matters: `IGNORECASE`, `MULTILINE`, `DOTALL`, `BESTMATCH`, `VERSION1`.\n- Use `timeout=` for untrusted patterns or large inputs.\n- Use `concurrent=True` only when matching against built-in immutable strings that will not change during the operation.\n\nTimeout example:\n\n```python\nimport regex\n\ntry:\n    regex.search(r\"(a+)+$\", \"a\" * 50_000, timeout=0.2)\nexcept TimeoutError:\n    print(\"match timed out\")\n```\n\nConcurrent matching example:\n\n```python\nimport regex\n\nwords = regex.findall(r\"\\w+\", \"alpha beta gamma\", concurrent=True)\nprint(words)\n```\n\n## Common Pitfalls\n\n- `regex` is not part of the standard library. Only use it when the environment explicitly installs it.\n- The module is mostly `re`-compatible, not perfectly identical. Re-test patterns that depend on edge-case character classes, Unicode behavior, or backtracking details.\n- If you rely on nested sets, full Unicode case-folding, or other Version 1 behavior, set `regex.VERSION1` or `(?V1)` explicitly instead of assuming a default.\n- Fuzzy matching, POSIX matching, and catastrophic-backtracking patterns can be expensive. Add `timeout=` for production code that handles user input.\n- Match objects keep a reference to the searched string. If you keep many matches for large inputs, call `match.detach_string()` after extracting what you need.\n- The upstream README notes that PyPy stores strings as UTF-8 internally, so behavior outside ASCII is not expected to match CPython.\n- The GitHub default-branch README is current project documentation, not a release-pinned manual. For version-sensitive work, verify against the versioned PyPI page for `2026.2.28`.\n\n## Version-Sensitive Notes For `2026.2.28`\n\n- This doc is pinned to `2026.2.28`, the release published on PyPI on February 28, 2026.\n- PyPI marks this release as requiring Python 3.9 or newer.\n- The upstream project documents Unicode-focused behavior and Version 0 versus Version 1 semantics in the README; older blog posts often omit those distinctions.\n- If copied examples behave differently across environments, check whether they assumed the standard-library `re` module, an older `regex` release, or `VERSION1` semantics.\n\n## Practical Workflow For Agents\n\n1. Start with a normal `re`-style implementation using `import regex`.\n2. Only introduce `overlapped=True`, fuzzy constraints, `partial=True`, or `VERSION1` when the use case actually needs them.\n3. Add `timeout=` before using complex patterns against user-controlled text.\n4. If behavior is unclear, compare the versioned PyPI page for `2026.2.28` with the current upstream README instead of relying on third-party tutorials.\n\n## Official Sources\n\n- PyPI project page: `https://pypi.org/project/regex/`\n- Version-pinned PyPI page: `https://pypi.org/project/regex/2026.2.28/`\n- Upstream repository: `https://github.com/mrabarnett/mrab-regex`\n- Upstream README: `https://github.com/mrabarnett/mrab-regex/blob/master/README.rst`\n"
  },
  {
    "path": "content/replicate/docs/model-hosting/DOC.md",
    "content": "---\nname: model-hosting\ndescription: \"Replicate JavaScript SDK coding guide for running ML models via the official Replicate npm package\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.3.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"replicate,model-hosting,ml,inference,ai\"\n---\n\n# Replicate JavaScript SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Replicate SDK package:** `replicate` from npm. The GitHub repository is `replicate/replicate-javascript`.\n\n**Never use unofficial or deprecated libraries.** The `replicate` package is the only officially supported Node.js/JavaScript SDK maintained by Replicate. Do not use packages like `replicate-api` or other third-party alternatives.\n\n**Important version note:** This SDK requires Node.js 18 or later, as it uses the native `fetch` API available in modern Node.js environments.\n\n## 2. Installation\n\n### npm\n```bash\nnpm install replicate\n```\n\n### yarn\n```bash\nyarn add replicate\n```\n\n### pnpm\n```bash\npnpm add replicate\n```\n\n**Environment Variables (Required):**\n```bash\nREPLICATE_API_TOKEN=r8_your_api_token_here\n```\n\n**Optional Environment Variables:**\n```bash\nREPLICATE_API_BASE_URL=https://api.replicate.com/v1  # Custom API endpoint\n```\n\n**Security Best Practices:** Never hardcode API tokens in source code. Use environment variables or secure secret management services. Use different tokens for development, staging, and production. Refresh tokens periodically. Never commit tokens to version control. Replicate automatically scans GitHub for accidentally committed tokens and disables them.\n\n## 3. Initialization\n\n### Basic Initialization\n```javascript\nimport Replicate from \"replicate\";\n\nconst replicate = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n});\n```\n\n### Custom Configuration\n```javascript\nimport Replicate from \"replicate\";\n\nconst replicate = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n  userAgent: \"my-app/1.0.0\",\n  baseUrl: \"https://api.replicate.com/v1\",\n  fetch: customFetch, // Custom fetch implementation\n  fileEncodingStrategy: \"upload\", // \"upload\" or \"no-upload\"\n});\n```\n\n### TypeScript Usage\n```typescript\nimport Replicate from \"replicate\";\nimport type { Prediction, Model, Training } from \"replicate\";\n\nconst replicate = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n});\n```\n\n**File Encoding Strategy:** `\"upload\"` (default) automatically uploads file handles to Replicate's file storage. `\"no-upload\"` does not upload files and is useful when you want to manage file uploads manually.\n\n## 4. Core API Surfaces\n\n### Running Models with `replicate.run()`\n\n**Minimal Example:**\n```javascript\nconst output = await replicate.run(\n  \"black-forest-labs/flux-schnell\",\n  {\n    input: {\n      prompt: \"a 19th century portrait of a raccoon gentleman wearing a suit\"\n    }\n  }\n);\n\nconsole.log(output);\n```\n\n**Advanced Example with Version and Options:**\n```javascript\nconst output = await replicate.run(\n  \"stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  {\n    input: {\n      prompt: \"a futuristic cityscape at sunset\",\n      negative_prompt: \"blurry, low quality\",\n      num_inference_steps: 50,\n      guidance_scale: 7.5,\n      width: 1024,\n      height: 1024,\n      seed: 42\n    },\n    wait: {\n      mode: \"block\", // \"block\" or \"poll\"\n      interval: 500, // Polling interval in ms (default 500)\n    }\n  },\n  (progress) => {\n    console.log(\"Progress:\", progress);\n  }\n);\n```\n\n**Identifier Formats:**\n\nThe identifier parameter accepts three formats:\n\n1. **Model name only** (uses latest version):\n   ```javascript\n   \"black-forest-labs/flux-schnell\"\n   ```\n\n2. **Model name with version**:\n   ```javascript\n   \"stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\"\n   ```\n\n3. **Version ID only**:\n   ```javascript\n   \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\"\n   ```\n\n**Progress Callback:**\n```javascript\nconst output = await replicate.run(\n  \"meta/llama-2-70b-chat\",\n  {\n    input: {\n      prompt: \"Write a story about a brave knight\"\n    }\n  },\n  (prediction) => {\n    console.log(\"Status:\", prediction.status);\n    if (prediction.output) {\n      console.log(\"Partial output:\", prediction.output);\n    }\n  }\n);\n```\n\n### Streaming Output with `replicate.stream()`\n\n**Minimal Streaming Example:**\n```javascript\nfor await (const event of replicate.stream(\n  \"meta/llama-2-70b-chat\",\n  {\n    input: {\n      prompt: \"Tell me a story about a dragon\"\n    }\n  }\n)) {\n  process.stdout.write(event.toString());\n}\n```\n\n**Advanced Streaming with Event Handling:**\n```javascript\nconst stream = await replicate.stream(\n  \"meta/llama-2-70b-chat\",\n  {\n    input: {\n      prompt: \"Explain quantum computing\",\n      max_new_tokens: 500,\n      temperature: 0.7\n    }\n  }\n);\n\nlet fullOutput = \"\";\n\nfor await (const event of stream) {\n  if (event.event === \"output\") {\n    fullOutput += event.data;\n    process.stdout.write(event.data);\n  } else if (event.event === \"error\") {\n    console.error(\"Error:\", event.data);\n  } else if (event.event === \"done\") {\n    console.log(\"\\nGeneration complete\");\n  }\n}\n\nconsole.log(\"\\nFull output:\", fullOutput);\n```\n\n**Streaming with EventSource (Server-Sent Events):**\n```javascript\nimport Replicate from \"replicate\";\n\nconst replicate = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n});\n\n// Create a prediction with streaming enabled\nconst prediction = await replicate.predictions.create({\n  version: \"2c1608e18606fad2812020dc541930f2d0495ce32eee50074220b87300bc16e1\",\n  input: {\n    prompt: \"Tell me a story\"\n  },\n  stream: true,\n});\n\n// For browser environments\nif (typeof EventSource !== 'undefined') {\n  const source = new EventSource(prediction.urls.stream, {\n    withCredentials: true,\n  });\n\n  source.addEventListener(\"output\", (e) => {\n    console.log(\"Output:\", e.data);\n  });\n\n  source.addEventListener(\"error\", (e) => {\n    console.error(\"Error:\", JSON.parse(e.data));\n    source.close();\n  });\n\n  source.addEventListener(\"done\", (e) => {\n    console.log(\"Done:\", JSON.parse(e.data));\n    source.close();\n  });\n}\n```\n\n### Predictions API\n\n**Create a Prediction:**\n```javascript\nconst prediction = await replicate.predictions.create({\n  version: \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  input: {\n    prompt: \"a beautiful landscape\"\n  }\n});\n\nconsole.log(prediction.id);\nconsole.log(prediction.status); // \"starting\"\n```\n\n**Advanced Prediction with All Options:**\n```javascript\nconst prediction = await replicate.predictions.create({\n  version: \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  input: {\n    prompt: \"astronaut riding a horse on mars\",\n    width: 1024,\n    height: 1024,\n    num_inference_steps: 50\n  },\n  webhook: \"https://api.myapp.com/webhooks/replicate\",\n  webhook_events_filter: [\"start\", \"output\", \"logs\", \"completed\"],\n  stream: false,\n  wait: {\n    mode: \"poll\",\n    interval: 500\n  }\n});\n```\n\n**Get Prediction Status:**\n```javascript\nconst prediction = await replicate.predictions.get(\"gm3qorzdhgbfurvjtvhg6dckhu\");\n\nconsole.log(prediction.status); // \"succeeded\", \"processing\", \"failed\", \"canceled\"\nconsole.log(prediction.output);\nconsole.log(prediction.logs);\nconsole.log(prediction.metrics);\n```\n\n**Wait for Prediction to Complete:**\n```javascript\nlet prediction = await replicate.predictions.create({\n  version: \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  input: { prompt: \"a serene lake\" }\n});\n\n// Poll until completion\nprediction = await replicate.wait(prediction);\n\nconsole.log(prediction.status); // \"succeeded\" or \"failed\"\nconsole.log(prediction.output);\n```\n\n**Cancel a Prediction:**\n```javascript\nconst canceled = await replicate.predictions.cancel(\"gm3qorzdhgbfurvjtvhg6dckhu\");\n\nconsole.log(canceled.status); // \"canceled\"\n```\n\n**Important:** If you cancel a prediction before it starts, there's no charge. If you cancel after it starts, you're billed for the time used.\n\n**List Predictions:**\n```javascript\n// Automatic pagination\nfor await (const prediction of replicate.predictions.list()) {\n  console.log(prediction.id, prediction.status);\n}\n\n// Manual pagination\nlet page = await replicate.predictions.list();\nfor (const prediction of page.results) {\n  console.log(prediction.id);\n}\n\nwhile (page.next) {\n  page = await replicate.predictions.list({ cursor: page.next });\n  for (const prediction of page.results) {\n    console.log(prediction.id);\n  }\n}\n```\n\n### Models API\n\n**Get Model Information:**\n```javascript\nconst model = await replicate.models.get(\"stability-ai\", \"sdxl\");\n\nconsole.log(model.name);\nconsole.log(model.description);\nconsole.log(model.latest_version);\nconsole.log(model.visibility); // \"public\" or \"private\"\n```\n\n**List All Models:**\n```javascript\n// Automatic pagination\nconst allModels = [];\nfor await (const model of replicate.models.list()) {\n  allModels.push(model);\n}\n\n// Manual pagination\nlet page = await replicate.models.list();\nfor (const model of page.results) {\n  console.log(model.owner, model.name);\n}\n\nwhile (page.hasNextPage()) {\n  page = await page.getNextPage();\n  for (const model of page.results) {\n    console.log(model.owner, model.name);\n  }\n}\n```\n\n**Get Model Versions:**\n```javascript\nconst versions = await replicate.models.versions.list(\n  \"stability-ai\",\n  \"sdxl\"\n);\n\nfor await (const version of versions) {\n  console.log(version.id);\n  console.log(version.created_at);\n}\n```\n\n**Get Specific Version:**\n```javascript\nconst version = await replicate.models.versions.get(\n  \"stability-ai\",\n  \"sdxl\",\n  \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\"\n);\n\nconsole.log(version.openapi_schema); // Input/output schema\n```\n\n**Create a Model:**\n```javascript\nconst model = await replicate.models.create({\n  owner: \"your-username\",\n  name: \"my-custom-model\",\n  description: \"A custom model for specific tasks\",\n  visibility: \"private\", // \"public\" or \"private\"\n  hardware: \"gpu-a40-large\"\n});\n```\n\n### Collections API\n\n**Get Collection:**\n```javascript\nconst collection = await replicate.collections.get(\"text-to-image\");\n\nconsole.log(collection.name);\nconsole.log(collection.description);\n\nfor (const model of collection.models) {\n  console.log(model.owner, model.name);\n}\n```\n\n**List Featured Collections:**\n```javascript\n// Collections are curated lists of models available at replicate.com/collections\nconst collection = await replicate.collections.get(\"super-resolution\");\n\ncollection.models.forEach(model => {\n  console.log(`${model.owner}/${model.name}: ${model.description}`);\n});\n```\n\n### Deployments API\n\n**Create a Deployment:**\n```javascript\nconst deployment = await replicate.deployments.create({\n  name: \"my-production-deployment\",\n  model: \"stability-ai/sdxl\",\n  version: \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  hardware: \"gpu-a40-large\",\n  min_instances: 1,\n  max_instances: 5\n});\n\nconsole.log(deployment.url);\n```\n\n**Available Hardware SKUs:** To list all available hardware SKUs and their specifications programmatically, use `await replicate.hardware.list()`. Common options include `\"cpu\"`, `\"gpu-t4\"`, `\"gpu-a40-small\"`, `\"gpu-a40-large\"`, and `\"gpu-a100\"`. From the CLI, run `replicate hardware list` to see all available hardware types with their SKUs, names, and specifications.\n\n**Get Deployment:**\n```javascript\nconst deployment = await replicate.deployments.get(\n  \"your-username\",\n  \"my-production-deployment\"\n);\n\nconsole.log(deployment.current_version);\nconsole.log(deployment.hardware);\nconsole.log(deployment.min_instances);\nconsole.log(deployment.max_instances);\n```\n\n**Update Deployment:**\n```javascript\nconst updated = await replicate.deployments.update(\n  \"your-username\",\n  \"my-production-deployment\",\n  {\n    version: \"new-version-id\",\n    min_instances: 2,\n    max_instances: 10\n  }\n);\n```\n\n**List Deployments:**\n```javascript\nfor await (const deployment of replicate.deployments.list()) {\n  console.log(deployment.owner, deployment.name);\n}\n```\n\n**Run Prediction on Deployment:**\n```javascript\nconst prediction = await replicate.deployments.predictions.create(\n  \"your-username\",\n  \"my-production-deployment\",\n  {\n    input: {\n      prompt: \"a beautiful sunset\"\n    }\n  }\n);\n\nconsole.log(prediction.output);\n```\n\n**Delete Deployment:**\n```javascript\nawait replicate.deployments.delete(\n  \"your-username\",\n  \"my-production-deployment\"\n);\n```\n\n### Training API\n\n**Create Training:**\n```javascript\nconst training = await replicate.trainings.create(\n  \"stability-ai\",\n  \"sdxl\",\n  \"39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  {\n    destination: \"your-username/my-fine-tuned-model\",\n    input: {\n      input_images: \"https://example.com/training-data.zip\",\n      learning_rate: 1e-6,\n      num_train_epochs: 100\n    },\n    webhook: \"https://api.myapp.com/webhooks/training-complete\"\n  }\n);\n\nconsole.log(training.id);\nconsole.log(training.status); // \"starting\"\n```\n\n**Get Training Status:**\n```javascript\nconst training = await replicate.trainings.get(\"zz4ibbonubfz7carwiefibzgga\");\n\nconsole.log(training.status); // \"succeeded\", \"processing\", \"failed\", \"canceled\"\nconsole.log(training.output); // New model version created\nconsole.log(training.logs);\n```\n\n**Cancel Training:**\n```javascript\nconst canceled = await replicate.trainings.cancel(\"zz4ibbonubfz7carwiefibzgga\");\nconsole.log(canceled.status); // \"canceled\"\n```\n\n**List Trainings:**\n```javascript\nfor await (const training of replicate.trainings.list()) {\n  console.log(training.id, training.status);\n}\n```\n\n### Files API\n\n**Upload File:**\n```javascript\nimport fs from \"fs\";\n\nconst file = await replicate.files.create(\n  fs.readFileSync(\"path/to/image.png\")\n);\n\nconsole.log(file.id);\nconsole.log(file.urls.get); // URL to download the file\n```\n\n**Use File in Prediction:**\n```javascript\nimport fs from \"fs\";\n\n// Upload file first\nconst file = await replicate.files.create(\n  fs.readFileSync(\"input-image.png\")\n);\n\n// Use file handle in prediction\nconst prediction = await replicate.predictions.create({\n  version: \"image-to-image-model-version-id\",\n  input: {\n    image: file.urls.get,\n    prompt: \"turn this into a watercolor painting\"\n  }\n});\n```\n\n**File Encoding Strategy:**\n```javascript\n// Automatically upload files (default behavior)\nconst replicateAutoUpload = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n  fileEncodingStrategy: \"upload\"\n});\n\n// Manual file management (no automatic upload)\nconst replicateManual = new Replicate({\n  auth: process.env.REPLICATE_API_TOKEN,\n  fileEncodingStrategy: \"no-upload\"\n});\n```\n\n**Get File:**\n```javascript\nconst file = await replicate.files.get(\"file-id-here\");\nconsole.log(file.urls.get);\n```\n\n**List Files:**\n```javascript\nfor await (const file of replicate.files.list()) {\n  console.log(file.id, file.created_at);\n}\n```\n\n**Delete File:**\n```javascript\nawait replicate.files.delete(\"file-id-here\");\n```\n\n### Hardware API\n\n**List Available Hardware:**\n```javascript\nconst hardware = await replicate.hardware.list();\n\nfor (const sku of hardware) {\n  console.log(sku.name);\n  console.log(sku.sku);\n}\n```\n\n### Account API\n\n**Get Account Information:**\n```javascript\nconst account = await replicate.account.get();\n\nconsole.log(account.type); // \"user\" or \"organization\"\nconsole.log(account.username);\nconsole.log(account.name);\n```\n\n## 5. Webhooks\n\n### Setting Up Webhooks\n\n**Create Prediction with Webhook:**\n```javascript\nconst prediction = await replicate.predictions.create({\n  version: \"model-version-id\",\n  input: {\n    prompt: \"a painting of a cat\"\n  },\n  webhook: \"https://api.myapp.com/webhooks/replicate\",\n  webhook_events_filter: [\"start\", \"output\", \"logs\", \"completed\"]\n});\n```\n\n**Webhook Event Types:** `\"start\"` fires when prediction starts processing. `\"output\"` fires each time prediction generates output (throttled to max 1 per 500ms). `\"logs\"` fires each time log output is generated (throttled to max 1 per 500ms). `\"completed\"` fires when prediction reaches terminal state (succeeded/failed/canceled).\n\n**Webhook Payload Example:**\n```javascript\n{\n  \"id\": \"gm3qorzdhgbfurvjtvhg6dckhu\",\n  \"status\": \"succeeded\",\n  \"output\": [\"https://replicate.delivery/output.png\"],\n  \"created_at\": \"2024-01-15T10:30:00.000Z\",\n  \"started_at\": \"2024-01-15T10:30:01.000Z\",\n  \"completed_at\": \"2024-01-15T10:30:05.000Z\",\n  \"metrics\": {\n    \"predict_time\": 4.2\n  },\n  \"logs\": \"Processing complete\",\n  \"error\": null\n}\n```\n\n**Webhook Handler (Express.js):**\n```javascript\nimport express from \"express\";\nimport crypto from \"crypto\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/webhooks/replicate\", async (req, res) => {\n  const prediction = req.body;\n\n  console.log(\"Webhook received:\", prediction.id);\n  console.log(\"Status:\", prediction.status);\n\n  if (prediction.status === \"succeeded\") {\n    console.log(\"Output:\", prediction.output);\n    // Process the output\n    await processOutput(prediction.output);\n  } else if (prediction.status === \"failed\") {\n    console.error(\"Prediction failed:\", prediction.error);\n    // Handle failure\n  }\n\n  // Always respond quickly to webhooks\n  res.status(200).json({ received: true });\n});\n```\n\n**Webhook Best Practices:** Respond to webhooks within 30 seconds with 200 OK. Process webhook payloads asynchronously (don't block the response). Implement idempotency since webhooks may be retried. Replicate will retry failed webhooks automatically. Use HTTPS endpoints for webhooks. Validate webhook authenticity in production.\n\n### Webhook Security\n\n**Implement Webhook Signature Verification (recommended for production):**\n```javascript\n// Note: Replicate webhook signature verification details\n// Check Replicate's documentation for current signature scheme\n\napp.post(\"/webhooks/replicate\", (req, res) => {\n  const signature = req.headers['x-replicate-signature'];\n  const secret = process.env.WEBHOOK_SECRET;\n\n  // Verify signature (implementation depends on Replicate's scheme)\n  if (!verifySignature(signature, req.body, secret)) {\n    return res.status(401).json({ error: \"Invalid signature\" });\n  }\n\n  // Process webhook\n  const prediction = req.body;\n  processWebhook(prediction);\n\n  res.status(200).json({ received: true });\n});\n```\n\n## 6. Advanced Features\n\n### Error Handling\n\n**Comprehensive Error Handling:**\n```javascript\nimport Replicate from \"replicate\";\n\nasync function runModelSafely() {\n  try {\n    const output = await replicate.run(\n      \"stability-ai/sdxl\",\n      {\n        input: {\n          prompt: \"a beautiful landscape\"\n        }\n      }\n    );\n\n    return output;\n  } catch (error) {\n    // Handle specific error types\n    if (error.response) {\n      // API error response\n      console.error(\"Status:\", error.response.status);\n      console.error(\"Error:\", error.response.data);\n\n      if (error.response.status === 401) {\n        throw new Error(\"Invalid API token\");\n      } else if (error.response.status === 402) {\n        throw new Error(\"Insufficient credits\");\n      } else if (error.response.status === 429) {\n        throw new Error(\"Rate limit exceeded\");\n      } else if (error.response.status === 500) {\n        throw new Error(\"Replicate server error\");\n      }\n    } else if (error.request) {\n      // Network error\n      console.error(\"Network error:\", error.message);\n      throw new Error(\"Failed to connect to Replicate API\");\n    } else {\n      // Other errors\n      console.error(\"Error:\", error.message);\n      throw error;\n    }\n  }\n}\n```\n\n**Retry Logic with Exponential Backoff:**\n```javascript\nasync function runWithRetry(identifier, options, maxRetries = 3) {\n  let lastError;\n\n  for (let attempt = 0; attempt < maxRetries; attempt++) {\n    try {\n      const output = await replicate.run(identifier, options);\n      return output;\n    } catch (error) {\n      lastError = error;\n\n      // Only retry on transient errors\n      const isRetryable =\n        error.response?.status === 429 || // Rate limit\n        error.response?.status === 500 || // Server error\n        error.response?.status === 503 || // Service unavailable\n        !error.response; // Network error\n\n      if (!isRetryable || attempt === maxRetries - 1) {\n        throw error;\n      }\n\n      // Exponential backoff: 1s, 2s, 4s, etc.\n      const delay = Math.pow(2, attempt) * 1000;\n      console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);\n      await new Promise(resolve => setTimeout(resolve, delay));\n    }\n  }\n\n  throw lastError;\n}\n```\n\n### Polling vs Blocking\n\n**Blocking Mode (holds connection open):**\n```javascript\nconst output = await replicate.run(\n  \"meta/llama-2-70b-chat\",\n  {\n    input: { prompt: \"Hello\" },\n    wait: {\n      mode: \"block\", // Hold connection open\n      interval: 60000 // Fallback to polling after 60s\n    }\n  }\n);\n```\n\n**Polling Mode (repeated requests):**\n```javascript\nconst output = await replicate.run(\n  \"meta/llama-2-70b-chat\",\n  {\n    input: { prompt: \"Hello\" },\n    wait: {\n      mode: \"poll\", // Make repeated requests\n      interval: 500 // Check every 500ms\n    }\n  }\n);\n```\n\n### Async/Await Patterns\n\n**Parallel Predictions:**\n```javascript\nconst prompts = [\n  \"a sunset over mountains\",\n  \"a city at night\",\n  \"a forest in autumn\"\n];\n\nconst predictions = await Promise.all(\n  prompts.map(prompt =>\n    replicate.predictions.create({\n      version: \"model-version-id\",\n      input: { prompt }\n    })\n  )\n);\n\n// Wait for all to complete\nconst results = await Promise.all(\n  predictions.map(p => replicate.wait(p))\n);\n\nresults.forEach((result, i) => {\n  console.log(`Result ${i}:`, result.output);\n});\n```\n\n**Sequential Processing with Rate Limiting:**\n```javascript\nasync function processSequentially(prompts, delayMs = 1000) {\n  const results = [];\n\n  for (const prompt of prompts) {\n    const output = await replicate.run(\n      \"stability-ai/sdxl\",\n      { input: { prompt } }\n    );\n\n    results.push(output);\n\n    // Delay between requests\n    if (prompts.indexOf(prompt) < prompts.length - 1) {\n      await new Promise(resolve => setTimeout(resolve, delayMs));\n    }\n  }\n\n  return results;\n}\n```\n\n## 7. Best Practices\n\n### Request Structure\n\n**Always specify exact versions in production:**\n```javascript\n// Good - pinned version\nconst output = await replicate.run(\n  \"stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b\",\n  { input: { prompt: \"a cat\" } }\n);\n\n// Avoid - uses latest version (can change unexpectedly)\nconst output = await replicate.run(\n  \"stability-ai/sdxl\",\n  { input: { prompt: \"a cat\" } }\n);\n```\n\n**Validate inputs before sending:**\n```javascript\nfunction validateInput(input) {\n  if (!input.prompt || input.prompt.trim().length === 0) {\n    throw new Error(\"Prompt is required\");\n  }\n\n  if (input.width && (input.width < 256 || input.width > 2048)) {\n    throw new Error(\"Width must be between 256 and 2048\");\n  }\n\n  if (input.height && (input.height < 256 || input.height > 2048)) {\n    throw new Error(\"Height must be between 256 and 2048\");\n  }\n\n  return true;\n}\n\n// Use validation\nconst input = { prompt: \"a landscape\", width: 1024, height: 1024 };\nvalidateInput(input);\n\nconst output = await replicate.run(\"stability-ai/sdxl\", { input });\n```\n\n### Rate Limits and Retries\n\n**Implement exponential backoff:**\n```javascript\nasync function callWithBackoff(fn, maxRetries = 3) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fn();\n    } catch (error) {\n      if (error.response?.status === 429) {\n        const retryAfter = error.response.headers['retry-after'];\n        const delay = retryAfter\n          ? parseInt(retryAfter) * 1000\n          : Math.pow(2, i) * 1000;\n\n        console.log(`Rate limited. Retrying after ${delay}ms`);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw error;\n      }\n    }\n  }\n\n  throw new Error(\"Max retries exceeded\");\n}\n\n// Usage\nconst output = await callWithBackoff(() =>\n  replicate.run(\"model-name\", { input: { prompt: \"test\" } })\n);\n```\n\n**Respect Retry-After headers:**\n```javascript\ncatch (error) {\n  if (error.response?.status === 429) {\n    const retryAfter = error.response.headers['retry-after'];\n    if (retryAfter) {\n      const delaySeconds = parseInt(retryAfter);\n      console.log(`Waiting ${delaySeconds}s before retry`);\n      await new Promise(resolve => setTimeout(resolve, delaySeconds * 1000));\n    }\n  }\n}\n```\n\n### Safety and Compliance\n\n**Content moderation:**\n```javascript\nfunction checkContentSafety(prompt) {\n  // Implement your content policy\n  const blockedTerms = ['harmful', 'illegal'];\n\n  const normalized = prompt.toLowerCase();\n  for (const term of blockedTerms) {\n    if (normalized.includes(term)) {\n      throw new Error(\"Content policy violation\");\n    }\n  }\n\n  return true;\n}\n\n// Use before API calls\ntry {\n  checkContentSafety(userPrompt);\n  const output = await replicate.run(\"model\", { input: { prompt: userPrompt } });\n} catch (error) {\n  console.error(\"Safety check failed:\", error.message);\n}\n```\n\n**Monitor and log predictions:**\n```javascript\nasync function runWithLogging(identifier, options) {\n  const startTime = Date.now();\n\n  try {\n    const prediction = await replicate.predictions.create({\n      version: identifier,\n      input: options.input\n    });\n\n    console.log({\n      event: \"prediction_created\",\n      id: prediction.id,\n      model: identifier,\n      timestamp: new Date().toISOString()\n    });\n\n    const result = await replicate.wait(prediction);\n    const duration = Date.now() - startTime;\n\n    console.log({\n      event: \"prediction_completed\",\n      id: result.id,\n      status: result.status,\n      duration_ms: duration,\n      cost_estimate: result.metrics?.predict_time,\n      timestamp: new Date().toISOString()\n    });\n\n    return result.output;\n  } catch (error) {\n    console.error({\n      event: \"prediction_failed\",\n      error: error.message,\n      duration_ms: Date.now() - startTime,\n      timestamp: new Date().toISOString()\n    });\n    throw error;\n  }\n}\n```\n\n### Cost Management\n\n**Estimate costs before running:**\n```javascript\n// Pricing varies by hardware\nconst PRICING = {\n  \"cpu\": 0.0001, // $0.0001/sec\n  \"gpu-t4\": 0.000225, // $0.000225/sec for public models\n  \"gpu-a40-small\": 0.000575,\n  \"gpu-a40-large\": 0.00118,\n  \"gpu-a100\": 0.00385\n};\n\nfunction estimateCost(hardwareSku, estimatedSeconds) {\n  const pricePerSecond = PRICING[hardwareSku] || 0;\n  return pricePerSecond * estimatedSeconds;\n}\n\n// Use deployments for predictable costs\nconst deployment = await replicate.deployments.create({\n  name: \"cost-controlled-deployment\",\n  model: \"stability-ai/sdxl\",\n  version: \"version-id\",\n  hardware: \"gpu-t4\", // Choose appropriate hardware\n  min_instances: 0, // Scale to zero when not in use\n  max_instances: 2 // Cap maximum concurrent instances\n});\n```\n\n**Cancel long-running predictions:**\n```javascript\nconst prediction = await replicate.predictions.create({\n  version: \"model-version\",\n  input: { prompt: \"test\" }\n});\n\n// Set timeout to prevent excessive costs\nconst timeout = setTimeout(async () => {\n  console.log(\"Prediction taking too long, canceling...\");\n  await replicate.predictions.cancel(prediction.id);\n}, 60000); // Cancel after 60 seconds\n\ntry {\n  const result = await replicate.wait(prediction);\n  clearTimeout(timeout);\n  return result.output;\n} catch (error) {\n  clearTimeout(timeout);\n  throw error;\n}\n```\n\n## 8. Production Patterns\n\n### Checking SDK and Model Versions\n\nTo check the latest SDK version:\n```bash\nnpm view replicate version\n```\n\nTo list model versions programmatically:\n```javascript\nconst versions = await replicate.models.versions.list(\"owner\", \"model-name\");\n```\n\nTo check model schema and version details from CLI:\n```bash\nreplicate model schema owner/model-name\n```\n\n### Error Tracking Integration\n\n```javascript\nimport * as Sentry from \"@sentry/node\";\n\ntry {\n  const output = await replicate.run(identifier, options);\n} catch (error) {\n  Sentry.captureException(error, {\n    tags: {\n      service: \"replicate\",\n      model: identifier\n    },\n    contexts: {\n      prediction: {\n        input: options.input\n      }\n    }\n  });\n  throw error;\n}\n```\n\n### Account Information\n\n```javascript\nconst account = await replicate.account.get();\nconsole.log(account.type); // \"user\" or \"organization\"\nconsole.log(account.username);\nconsole.log(account.name);\n```\n\n### Testing with Mocks\n\n```javascript\nimport { jest } from '@jest/globals';\n\njest.mock('replicate');\n\ntest('handles prediction success', async () => {\n  const mockRun = jest.fn().mockResolvedValue(['output.png']);\n  const replicate = { run: mockRun };\n\n  const result = await myFunction(replicate);\n\n  expect(mockRun).toHaveBeenCalledWith(\n    expect.any(String),\n    expect.objectContaining({\n      input: expect.any(Object)\n    })\n  );\n  expect(result).toBeDefined();\n});\n```\n\n### Input Validation\n\nTo inspect a model's expected input/output schema:\n```javascript\nconst version = await replicate.models.versions.get(\"owner\", \"model\", \"version-id\");\nconsole.log(version.openapi_schema);\n```\n\nFrom CLI:\n```bash\nreplicate model schema owner/model-name\n```\n\nValidation example:\n```javascript\nimport validator from 'validator';\n\nfunction validatePredictionInput(input) {\n  if (!input.prompt || typeof input.prompt !== 'string') {\n    throw new Error('Invalid prompt');\n  }\n\n  if (input.prompt.length > 10000) {\n    throw new Error('Prompt too long');\n  }\n\n  if (input.image_url && !validator.isURL(input.image_url)) {\n    throw new Error('Invalid image URL');\n  }\n\n  return true;\n}\n```\n\n### Monitoring with Metrics\n\nList and monitor predictions:\n```javascript\nfor await (const prediction of replicate.predictions.list()) {\n  console.log(prediction.id, prediction.status);\n}\n```\n\nMonitor trainings:\n```javascript\nfor await (const training of replicate.trainings.list()) {\n  console.log(training.id, training.status);\n}\n```\n\nPrometheus integration:\n```javascript\nimport prometheus from 'prom-client';\n\nconst predictionCounter = new prometheus.Counter({\n  name: 'replicate_predictions_total',\n  help: 'Total number of predictions',\n  labelNames: ['model', 'status']\n});\n\nconst predictionDuration = new prometheus.Histogram({\n  name: 'replicate_prediction_duration_seconds',\n  help: 'Prediction duration in seconds',\n  labelNames: ['model']\n});\n\nasync function runWithMetrics(identifier, options) {\n  const startTime = Date.now();\n\n  try {\n    const output = await replicate.run(identifier, options);\n    predictionCounter.inc({ model: identifier, status: 'success' });\n    return output;\n  } catch (error) {\n    predictionCounter.inc({ model: identifier, status: 'error' });\n    throw error;\n  } finally {\n    const duration = (Date.now() - startTime) / 1000;\n    predictionDuration.observe({ model: identifier }, duration);\n  }\n}\n```\n\n### Deployment Management\n\nCreate deployment:\n```javascript\nconst deployment = await replicate.deployments.create({\n  name: \"production-deployment\",\n  model: \"stability-ai/sdxl\",\n  version: \"pinned-version-id\",\n  hardware: \"gpu-a40-large\",\n  min_instances: 2,\n  max_instances: 10\n});\n```\n\nUpdate deployment:\n```javascript\nconst updated = await replicate.deployments.update(\n  \"your-username\",\n  \"deployment-name\",\n  {\n    version: \"new-version-id\",\n    min_instances: 0,\n    max_instances: 5\n  }\n);\n```\n\nDelete deployment:\n```javascript\nawait replicate.deployments.delete(\"your-username\", \"deployment-name\");\n```\n\nList deployments:\n```javascript\nfor await (const deployment of replicate.deployments.list()) {\n  console.log(deployment.owner, deployment.name);\n}\n```\n\nFrom CLI:\n```bash\nreplicate model create yourname/model --private --hardware gpu-a40-small\n```\n\n### Canceling Predictions\n\nCancel programmatically:\n```javascript\nawait replicate.predictions.cancel(prediction_id);\n```\n\nFrom CLI:\n```bash\nreplicate prediction cancel <id>\n```\n"
  },
  {
    "path": "content/replicate/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Replicate Python SDK guide for running models, streaming output, and handling file inputs with the official replicate package\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"replicate,python,ml,inference,ai,predictions\"\n---\n\n# replicate Python Package Guide\n\n## Golden Rule\n\nUse the official PyPI package: `replicate`.\n\n- Import it as `import replicate`.\n- Use the Replicate API token from `REPLICATE_API_TOKEN` unless you are explicitly constructing a client with `api_token=...`.\n- Prefer pinned model versions for production workflows so output behavior does not change when a model owner updates their latest version.\n\n## Installation\n\n`replicate` 1.0.7 requires Python `>=3.8`.\n\n```bash\npip install replicate==1.0.7\n```\n\nWith Poetry:\n\n```bash\npoetry add replicate==1.0.7\n```\n\nWith uv:\n\n```bash\nuv add replicate==1.0.7\n```\n\n## Authentication And Setup\n\nThe simplest path is to export `REPLICATE_API_TOKEN` and use the module-level helpers.\n\n```bash\nexport REPLICATE_API_TOKEN=r8_...\n```\n\n```python\nimport replicate\n\noutput = replicate.run(\n    \"black-forest-labs/flux-schnell\",\n    input={\"prompt\": \"studio photo of a red fox in a blue jacket\"},\n)\n```\n\nIf you do not want to rely on process-global environment, construct a client explicitly:\n\n```python\nimport os\nimport replicate\n\nclient = replicate.Client(api_token=os.environ[\"REPLICATE_API_TOKEN\"])\n```\n\nUse an explicit client when you need clearer dependency injection, per-request auth separation, or custom transport setup.\n\n## Core Usage\n\n### Run a model and wait for output\n\n`replicate.run()` is the shortest path for \"submit a prediction and wait for the final output\".\n\n```python\nimport replicate\n\noutput = replicate.run(\n    \"black-forest-labs/flux-schnell\",\n    input={\n        \"prompt\": \"a watercolor postcard of San Francisco at sunrise\",\n    },\n)\n\nprint(output)\n```\n\nYou can pass either:\n\n- `owner/model`\n- `owner/model:version_id`\n- a raw version ID\n\nFor production code, prefer `owner/model:version_id`.\n\n### Create and inspect predictions directly\n\nUse the predictions API when you need prediction IDs, status polling, webhook support, or finer lifecycle control.\n\n```python\nimport replicate\n\nprediction = replicate.predictions.create(\n    model=\"black-forest-labs/flux-schnell\",\n    input={\"prompt\": \"architectural rendering of a small cabin in snow\"},\n)\n\nprint(prediction.id)\nprint(prediction.status)\n\nprediction = replicate.predictions.get(prediction.id)\nprint(prediction.status)\n```\n\n### Stream incremental output\n\nUse `replicate.stream()` for models that emit incremental tokens or events.\n\n```python\nimport replicate\n\nfor event in replicate.stream(\n    \"meta/meta-llama-3-70b-instruct\",\n    input={\"prompt\": \"List three practical uses for a vector database.\"},\n):\n    print(str(event), end=\"\")\n```\n\nStreaming is the better fit for chat or text-generation UX. `run()` is simpler for one-shot jobs such as image generation.\n\n## Async Usage\n\n`replicate` 1.x also exposes async helpers.\n\n```python\nimport asyncio\nimport replicate\n\nasync def main() -> None:\n    output = await replicate.async_run(\n        \"black-forest-labs/flux-schnell\",\n        input={\"prompt\": \"pixel art spaceship over a desert\"},\n    )\n    print(output)\n\nasyncio.run(main())\n```\n\nAsync streaming works the same way:\n\n```python\nimport asyncio\nimport replicate\n\nasync def main() -> None:\n    async for event in replicate.async_stream(\n        \"meta/meta-llama-3-70b-instruct\",\n        input={\"prompt\": \"Write a two-line haiku about Python packaging.\"},\n    ):\n        print(str(event), end=\"\")\n\nasyncio.run(main())\n```\n\nUse the async API if the rest of your app already uses `asyncio`. Do not wrap sync helpers inside thread executors unless you have to.\n\n## Files And Binary Outputs\n\nFile inputs can be passed as open binary file handles.\n\n```python\nimport replicate\n\nwith open(\"input.jpg\", \"rb\") as image_file:\n    output = replicate.run(\n        \"stability-ai/stable-diffusion\",\n        input={\n            \"image\": image_file,\n            \"prompt\": \"cinematic portrait lighting\",\n        },\n    )\n```\n\nMany image or media models return `FileOutput` objects instead of plain strings. Treat them like file-like objects and write them to disk.\n\n```python\nimport replicate\n\noutput = replicate.run(\n    \"black-forest-labs/flux-schnell\",\n    input={\"prompt\": \"minimalist poster of a mountain ridge\"},\n)\n\nfirst_file = output[0]\n\nwith open(\"poster.webp\", \"wb\") as f:\n    f.write(first_file.read())\n```\n\nIf a model returns text tokens, lists, or JSON-like structures, the output shape depends on the model. Check that model's schema before assuming the return type.\n\n## Transport Configuration\n\nIf you need custom connection pooling, proxies, or shared timeouts, `1.0.7` added support for passing your own `httpx.Client` or `httpx.AsyncClient`.\n\n```python\nimport httpx\nimport os\nimport replicate\n\nhttp_client = httpx.Client(timeout=30.0)\n\nclient = replicate.Client(\n    api_token=os.environ[\"REPLICATE_API_TOKEN\"],\n    http_client=http_client,\n)\n```\n\nThis is the supported way in `1.0.7` to control lower-level HTTP behavior.\n\n## Common Pitfalls\n\n- Module-level helpers such as `replicate.run()` use the default client. If `REPLICATE_API_TOKEN` is missing, auth will fail.\n- Do not assume `run()` always returns text. Image and media models commonly return `FileOutput` objects.\n- Do not assume model identifiers are stable when you omit the version suffix. Pin the version for reproducible builds and tests.\n- Use `predictions.create()` instead of `run()` when you need webhooks, IDs, or explicit polling.\n- Keep file handles open until the request is sent. Passing a closed file object will fail.\n- Check each model card for required input names. `replicate` is only the client; input schemas come from the specific model you call.\n\n## Version-Sensitive Notes For 1.0.7\n\n- The version used here for this entry is `1.0.7`, and the examples here are aligned to the `1.x` Python client surface.\n- Replicate's GitHub README tracks the repository and can move ahead of the pinned PyPI release. When examples disagree, prefer the `1.0.7` PyPI package page and the `v1.0.7` release note.\n- `1.0.7` specifically added support for custom `httpx` sync and async clients.\n\n## Official Sources\n\n- GitHub repository: https://github.com/replicate/replicate-python\n- PyPI package page for `1.0.7`: https://pypi.org/project/replicate/1.0.7/\n- `v1.0.7` release note: https://github.com/replicate/replicate-python/releases/tag/v1.0.7\n"
  },
  {
    "path": "content/reportlab/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ReportLab PDF toolkit for generating PDFs, Platypus documents, graphics, and charts in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.4.10\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"reportlab,pdf,documents,platypus,graphics,charts,python\"\n---\n\n# ReportLab Python Package Guide\n\n## Golden Rule\n\nUse the open-source `reportlab` package from PyPI, import from `reportlab.*`, and choose the API level deliberately:\n\n- Use `reportlab.pdfgen.canvas.Canvas` when you need low-level drawing control.\n- Use Platypus (`reportlab.platypus`) when you need layouted documents built from paragraphs, tables, images, and page templates.\n\nThe docs site also contains ReportLab PLUS and RML material. Do not mix those products into code meant for the open-source `reportlab` package.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"reportlab==4.4.10\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"reportlab==4.4.10\"\npoetry add \"reportlab==4.4.10\"\n```\n\nUpstream notes that matter during setup:\n\n- The open-source install docs describe `reportlab` as a Python library for creating PDFs and graphics.\n- The upstream install page says the open-source package supports Python `3.7` through `3.13`.\n- The user guide notes that `Pillow` is needed if you want to import images beyond the native JPEG support.\n\n## Choose The Right API\n\n### Low-level PDF generation with `pdfgen`\n\nUse `canvas.Canvas` when you want absolute positioning and full control over pages:\n\n```python\nfrom io import BytesIO\n\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.pdfgen import canvas\n\nbuffer = BytesIO()\npdf = canvas.Canvas(buffer, pagesize=letter)\n\npdf.setTitle(\"hello-reportlab\")\npdf.drawString(72, 720, \"Hello from ReportLab\")\npdf.drawString(72, 700, \"Use pdfgen when exact coordinates matter.\")\npdf.showPage()\npdf.save()\n\npdf_bytes = buffer.getvalue()\n```\n\nUse this style for invoices, labels, overlays, and other fixed-layout output.\n\n### Structured documents with Platypus\n\nUse Platypus when you want flow-based layout instead of manual coordinates:\n\n```python\nfrom pathlib import Path\n\nfrom reportlab.lib.styles import getSampleStyleSheet\nfrom reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table\n\noutput_path = Path(\"reportlab-guide.pdf\")\nstyles = getSampleStyleSheet()\n\nstory = [\n    Paragraph(\"ReportLab Platypus Example\", styles[\"Title\"]),\n    Spacer(1, 12),\n    Paragraph(\n        \"Platypus builds a document from flowables such as paragraphs, tables, \"\n        \"images, and page breaks.\",\n        styles[\"BodyText\"],\n    ),\n    Spacer(1, 12),\n    Table(\n        [[\"Package\", \"Version\"], [\"reportlab\", \"4.4.10\"]],\n        hAlign=\"LEFT\",\n    ),\n]\n\ndoc = SimpleDocTemplate(output_path)\ndoc.build(story)\n```\n\nThe Platypus chapter describes documents as a sequence of flowables, assembled into a `Story`, then built into the final PDF.\n\n### Vector graphics and charts\n\nThe user guide also documents `reportlab.graphics` for drawings and chart primitives. Use that layer when you need reusable vector graphics embedded in PDFs instead of manually drawing every shape on a canvas.\n\n## Core Patterns\n\n### Generate into memory for web responses\n\n`reportlab` writes binary PDF output cleanly to file-like objects, so `BytesIO` is the usual choice in web apps and background jobs:\n\n```python\nfrom io import BytesIO\n\nfrom reportlab.pdfgen import canvas\n\ndef build_pdf_bytes() -> bytes:\n    buffer = BytesIO()\n    pdf = canvas.Canvas(buffer)\n    pdf.drawString(72, 720, \"Generated in memory\")\n    pdf.showPage()\n    pdf.save()\n    return buffer.getvalue()\n```\n\n### Register a TrueType font before using it\n\nBase 14 PDF fonts work without extra setup, but non-default fonts should be registered explicitly:\n\n```python\nfrom reportlab.pdfbase import pdfmetrics\nfrom reportlab.pdfbase.ttfonts import TTFont\nfrom reportlab.pdfgen import canvas\n\npdfmetrics.registerFont(TTFont(\"Inter\", \"/absolute/path/Inter-Regular.ttf\"))\n\npdf = canvas.Canvas(\"font-demo.pdf\")\npdf.setFont(\"Inter\", 12)\npdf.drawString(72, 720, \"Custom font example\")\npdf.showPage()\npdf.save()\n```\n\nThis avoids fragile assumptions about what fonts are already known to the runtime.\n\n## Configuration And Asset Paths\n\nThe user guide documents `reportlab.rl_config` for package-level defaults. Useful settings include:\n\n- `defaultPageSize`\n- `defaultEncoding`\n- `T1SearchPath`\n- `TTFSearchPath`\n- `CMapSearchPath`\n- `showBoundary`\n- `shapeChecking`\n\nExample:\n\n```python\nfrom reportlab import rl_config\n\nrl_config.defaultPageSize = (595.27, 841.89)  # A4 in points\nrl_config.showBoundary = 0\nrl_config.shapeChecking = 1\nrl_config.TTFSearchPath.append(\"/app/fonts\")\n```\n\nPrefer explicit configuration in application startup instead of mutating these values ad hoc in random helper functions.\n\n## Common Pitfalls\n\n- The docs site includes commercial ReportLab products alongside the open-source toolkit. Stay within the open-source install guide and user guide when writing code for `pip install reportlab`.\n- `canvas.Canvas` output is incomplete until you call `showPage()` for the current page and `save()` for the document.\n- Platypus is flowable-based. Do not treat it like a thin wrapper over `canvas.drawString()`; build a `Story` from flowables and let the document template place them.\n- Complex fonts are not automatic. Register TrueType fonts yourself and verify glyph coverage before assuming Unicode text will render correctly.\n- Imported images beyond JPEG support rely on Pillow being available, so image-heavy code should be tested in the same environment it will run in.\n- Global `rl_config` changes affect the process. Keep environment-specific font paths and debug flags centralized.\n\n## Version-Sensitive Notes For `4.4.10`\n\n- The version used here `4.4.10` matches the current PyPI release for `reportlab` as of March 12, 2026.\n- ReportLab `4.x` uses modern packaging metadata (`pyproject.toml` was introduced in the 4.0 line), so older installation advice aimed at much earlier releases is not a good default.\n- The upstream `4.4.0` release notes mention experimental right-to-left and shaping support with `pyfribidi`. Treat complex-script output as version-sensitive and verify it visually instead of assuming older examples are still the best reference.\n\n## Official Sources\n\n- Docs root: https://docs.reportlab.com/\n- Open-source install guide: https://docs.reportlab.com/reportlab/install/open_source_package/\n- User guide: https://docs.reportlab.com/reportlab/userguide/\n- 4.4.0 release notes: https://docs.reportlab.com/releases/notes/whats-new-440/\n- PyPI: https://pypi.org/project/reportlab/\n"
  },
  {
    "path": "content/requests/docs/oauthlib/python/DOC.md",
    "content": "---\nname: oauthlib\ndescription: \"requests-oauthlib package guide for OAuth 1.0a and OAuth 2.0 flows with Requests in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,requests-oauthlib,oauth,oauth1,oauth2,requests\"\n---\n\n# requests-oauthlib Python Package Guide\n\n## What It Does\n\n`requests-oauthlib` adds OAuth support to `requests`.\n\nThe main entry points are:\n\n- `OAuth2Session` for OAuth 2.0 authorization URLs, token exchange, token refresh, and authenticated API requests\n- `OAuth1Session` for the OAuth 1.0a request-token → authorize → access-token flow\n- `OAuth1` when you already have OAuth 1 credentials and only need request signing\n\nUse provider-specific authorization, token, and API URLs from the provider's own documentation. This package does not discover endpoints for you.\n\n## Install\n\n```bash\npip install requests-oauthlib==2.0.0\n```\n\n`requests-oauthlib` depends on `requests>=2.0.0` and `oauthlib>=3.0.0`.\n\n## Shared Setup\n\nKeep client secrets and callback settings in environment variables:\n\n```bash\nexport APP_SECRET_KEY=\"replace-me\"\nexport OAUTH_CLIENT_ID=\"replace-me\"\nexport OAUTH_CLIENT_SECRET=\"replace-me\"\nexport OAUTH_REDIRECT_URI=\"http://localhost:8000/callback\"\nexport OAUTH_AUTHORIZATION_URL=\"https://provider.example.com/oauth/authorize\"\nexport OAUTH_TOKEN_URL=\"https://provider.example.com/oauth/token\"\nexport API_BASE_URL=\"https://provider.example.com/api\"\n```\n\nCommon rules:\n\n- register the redirect URI exactly as your provider expects\n- keep the `state` value between the authorization request and callback\n- persist the token dict returned by `fetch_token()` or `refresh_token()`\n- use HTTPS endpoints; `OAuth2Session` rejects insecure transport by default\n\n## OAuth 2.0 Authorization Code Flow\n\nThis is the default `OAuth2Session` flow. The session uses `WebApplicationClient` unless you pass a different OAuthlib client.\n\nThis example uses Flask only to show the login redirect and callback wiring.\n\n```python\nimport os\n\nfrom flask import Flask, jsonify, redirect, request, session\nfrom requests_oauthlib import OAuth2Session\n\napp = Flask(__name__)\napp.secret_key = os.environ[\"APP_SECRET_KEY\"]\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"OAUTH_CLIENT_SECRET\"]\nREDIRECT_URI = os.environ[\"OAUTH_REDIRECT_URI\"]\nAUTHORIZATION_URL = os.environ[\"OAUTH_AUTHORIZATION_URL\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\nAPI_BASE_URL = os.environ[\"API_BASE_URL\"]\nSCOPE = [\"profile\", \"email\"]\n\n\n@app.get(\"/login\")\ndef login():\n    oauth = OAuth2Session(\n        client_id=CLIENT_ID,\n        redirect_uri=REDIRECT_URI,\n        scope=SCOPE,\n    )\n    authorization_url, state = oauth.authorization_url(AUTHORIZATION_URL)\n    session[\"oauth_state\"] = state\n    return redirect(authorization_url)\n\n\n@app.get(\"/callback\")\ndef callback():\n    oauth = OAuth2Session(\n        client_id=CLIENT_ID,\n        redirect_uri=REDIRECT_URI,\n        state=session[\"oauth_state\"],\n    )\n    token = oauth.fetch_token(\n        TOKEN_URL,\n        authorization_response=request.url,\n        client_secret=CLIENT_SECRET,\n    )\n    session[\"oauth_token\"] = token\n    return redirect(\"/me\")\n\n\n@app.get(\"/me\")\ndef me():\n    oauth = OAuth2Session(\n        client_id=CLIENT_ID,\n        token=session[\"oauth_token\"],\n    )\n    response = oauth.get(f\"{API_BASE_URL}/userinfo\")\n    response.raise_for_status()\n    return jsonify(response.json())\n```\n\nIf you already have a token in storage, recreate the session with `token=...` and use the normal `requests.Session` methods:\n\n```python\nimport json\nimport os\nfrom pathlib import Path\n\nfrom requests_oauthlib import OAuth2Session\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nAPI_BASE_URL = os.environ[\"API_BASE_URL\"]\nstored_token = json.loads(Path(\"oauth-token.json\").read_text())\n\noauth = OAuth2Session(client_id=CLIENT_ID, token=stored_token)\n\nif oauth.authorized:\n    response = oauth.get(f\"{API_BASE_URL}/userinfo\")\n    response.raise_for_status()\n    profile = response.json()\n```\n\nThe token dict you pass back in should include at least `access_token` and `token_type`.\n\n## OAuth 2.0 PKCE\n\n`2.0.0` adds PKCE support through the `pkce` argument. Use `\"S256\"` unless your provider explicitly requires plain-text challenges.\n\nThis example keeps the authorization URL generation and token exchange on the same session object so the generated code verifier is available for `fetch_token()`:\n\n```python\nimport os\n\nfrom requests_oauthlib import OAuth2Session\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nREDIRECT_URI = os.environ[\"OAUTH_REDIRECT_URI\"]\nAUTHORIZATION_URL = os.environ[\"OAUTH_AUTHORIZATION_URL\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\n\noauth = OAuth2Session(\n    client_id=CLIENT_ID,\n    redirect_uri=REDIRECT_URI,\n    scope=[\"openid\", \"profile\", \"email\"],\n    pkce=\"S256\",\n)\n\nauthorization_url, state = oauth.authorization_url(AUTHORIZATION_URL)\nprint(\"Open this URL in a browser:\")\nprint(authorization_url)\n\nauthorization_response = input(\"Paste the full redirect URL: \").strip()\n\ntoken = oauth.fetch_token(\n    TOKEN_URL,\n    authorization_response=authorization_response,\n    include_client_id=True,\n)\n\nprint(token)\n```\n\nFor public clients, `include_client_id=True` is important because `fetch_token()` otherwise tries to build HTTP Basic auth from `client_id` and `client_secret` when no explicit `auth` object is provided.\n\n## Refreshing OAuth 2.0 Tokens\n\nUse `refresh_token()` when your provider issues refresh tokens:\n\n```python\nimport json\nimport os\nfrom pathlib import Path\n\nfrom requests.auth import HTTPBasicAuth\nfrom requests_oauthlib import OAuth2Session\n\nCLIENT_ID = os.environ[\"OAUTH_CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"OAUTH_CLIENT_SECRET\"]\nTOKEN_URL = os.environ[\"OAUTH_TOKEN_URL\"]\n\ntoken_path = Path(\"oauth-token.json\")\nstored_token = json.loads(token_path.read_text())\n\noauth = OAuth2Session(client_id=CLIENT_ID, token=stored_token)\n\nnew_token = oauth.refresh_token(\n    TOKEN_URL,\n    auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),\n)\n\ntoken_path.write_text(json.dumps(new_token))\n```\n\nIf you configure `auto_refresh_url`, expired protected-resource requests will refresh automatically. Provide `token_updater` to persist the new token; otherwise the session raises `TokenUpdated` with the refreshed token instead of saving it for you.\n\n## OAuth 1.0a Workflow\n\nUse `OAuth1Session` when a provider still requires OAuth 1.0a.\n\n```bash\nexport OAUTH1_CLIENT_KEY=\"replace-me\"\nexport OAUTH1_CLIENT_SECRET=\"replace-me\"\nexport OAUTH1_CALLBACK_URI=\"https://127.0.0.1/callback\"\nexport OAUTH1_REQUEST_TOKEN_URL=\"https://provider.example.com/oauth/request_token\"\nexport OAUTH1_AUTHORIZATION_URL=\"https://provider.example.com/oauth/authorize\"\nexport OAUTH1_ACCESS_TOKEN_URL=\"https://provider.example.com/oauth/access_token\"\nexport API_BASE_URL=\"https://provider.example.com/api\"\n```\n\n```python\nimport os\n\nfrom requests_oauthlib import OAuth1Session\n\noauth = OAuth1Session(\n    client_key=os.environ[\"OAUTH1_CLIENT_KEY\"],\n    client_secret=os.environ[\"OAUTH1_CLIENT_SECRET\"],\n    callback_uri=os.environ[\"OAUTH1_CALLBACK_URI\"],\n)\n\nrequest_token = oauth.fetch_request_token(os.environ[\"OAUTH1_REQUEST_TOKEN_URL\"])\nprint(request_token)\n\nauthorization_url = oauth.authorization_url(os.environ[\"OAUTH1_AUTHORIZATION_URL\"])\nprint(\"Open this URL in a browser:\")\nprint(authorization_url)\n\nredirect_response = input(\"Paste the full redirect URL: \").strip()\noauth.parse_authorization_response(redirect_response)\n\naccess_token = oauth.fetch_access_token(os.environ[\"OAUTH1_ACCESS_TOKEN_URL\"])\nprint(access_token)\n\nresponse = oauth.get(f\"{os.environ['API_BASE_URL']}/account/settings.json\")\nresponse.raise_for_status()\nprint(response.json())\n```\n\nIf you already have the OAuth 1 token and token secret, initialize the session with `resource_owner_key=...` and `resource_owner_secret=...` and use `get()`, `post()`, and other `requests.Session` methods directly.\n\n## Compliance Hooks For Non-Standard Providers\n\n`OAuth2Session.register_compliance_hook()` lets you patch token requests, refresh requests, protected-resource requests, or token responses when a provider is not fully RFC-compliant.\n\nAvailable hook types in `2.0.0` are:\n\n- `access_token_request`\n- `access_token_response`\n- `refresh_token_request`\n- `refresh_token_response`\n- `protected_request`\n\nUse hooks only when the provider's docs or behavior require request/response rewriting.\n\n## Important Pitfalls\n\n- `OAuth2Session` requires HTTPS for authorization, token, refresh, and protected-resource URLs; otherwise it raises `InsecureTransportError`.\n- `fetch_token()` accepts either `authorization_response=full_callback_url` or an explicit `code=...`.\n- For `LegacyApplicationClient`, `fetch_token()` requires both `username` and `password`.\n- For implicit/mobile flows, use `token_from_fragment(...)` instead of `fetch_token()`.\n- `OAuth1Session.fetch_access_token()` needs an OAuth verifier, usually set by `parse_authorization_response(...)`.\n- `OAuth1Session.authorized` and `OAuth2Session.authorized` are quick checks for whether the session currently has usable credentials.\n\n## Version Notes For 2.0.0\n\n- `OAuth2Session(..., pkce=\"S256\")` is available in `2.0.0`.\n- `access_token_request` and `refresh_token_request` compliance hooks are available in `2.0.0`.\n- `fetch_token()` and `refresh_token()` in `2.0.0` use the session's `verify` setting when you do not pass `verify=` explicitly.\n"
  },
  {
    "path": "content/requests/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Requests HTTP client for Python with practical guidance for sessions, auth, TLS, proxies, and common pitfalls\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.32.5\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"requests,http,python,client,auth,tls,proxies\"\n---\n\n# Requests Python Package Guide\n\n## What It Is\n\n`requests` is the standard synchronous HTTP client used in many Python projects. It is a blocking HTTP/1.1 client with:\n\n- per-method helpers like `get`, `post`, `put`, and `delete`\n- `Session` objects for shared headers, cookies, and connection pooling\n- built-in Basic and Digest auth support\n- TLS verification, proxies, multipart uploads, and streamed downloads\n\nUse it when you need straightforward synchronous HTTP calls from Python code.\n\n## Version Covered\n\n- Package: `requests`\n- Ecosystem: `pypi`\n- Version: `2.32.5`\n- Python support: `>=3.9`\n- Registry: https://pypi.org/project/requests/\n- Docs root used for this guide: https://requests.readthedocs.io/en/stable/\n\n## Install\n\n```bash\npython -m pip install requests==2.32.5\n```\n\nOptional SOCKS proxy support:\n\n```bash\npython -m pip install \"requests[socks]==2.32.5\"\n```\n\n## Core Usage\n\nPrefer the method helpers (`get`, `post`, `put`, `patch`, `delete`) and always set a timeout explicitly.\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://api.github.com/events\",\n    params={\"per_page\": 10},\n    timeout=(3.05, 30),\n)\nresponse.raise_for_status()\n\nevents = response.json()\nprint(events[0][\"type\"])\n```\n\nNotes:\n\n- `timeout` can be a float or a `(connect_timeout, read_timeout)` tuple.\n- `response.json()` can still succeed on an HTTP error response. Check `status_code` or call `raise_for_status()`.\n- If you omit `timeout`, Requests will wait indefinitely.\n\n### POST JSON\n\nUse `json=` for JSON APIs instead of manually serializing `data=`.\n\n```python\nimport requests\n\npayload = {\"name\": \"example\", \"enabled\": True}\n\nresponse = requests.post(\n    \"https://httpbin.org/post\",\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\n\nprint(response.json()[\"json\"])\n```\n\n`json=` is ignored if you also pass `data=` or `files=`.\n\n### Form Data And Files\n\n```python\nimport requests\n\nwith open(\"report.csv\", \"rb\") as fh:\n    response = requests.post(\n        \"https://httpbin.org/post\",\n        data={\"source\": \"daily-job\"},\n        files={\"file\": (\"report.csv\", fh, \"text/csv\")},\n        timeout=30,\n    )\n    response.raise_for_status()\n```\n\n## Sessions And Shared Configuration\n\nUse `Session` when you make multiple calls to the same service. A session persists cookies, reuses TCP connections through `urllib3`, and lets you centralize headers, auth, or TLS settings.\n\n```python\nimport requests\n\nwith requests.Session() as session:\n    session.headers.update(\n        {\n            \"User-Agent\": \"my-service/1.0\",\n            \"Accept\": \"application/json\",\n        }\n    )\n    session.params = {\"api_version\": \"2025-01-01\"}\n\n    response = session.get(\n        \"https://httpbin.org/get\",\n        timeout=(3.05, 30),\n    )\n    response.raise_for_status()\n```\n\nUse a session for:\n\n- shared headers or auth across many requests\n- cookie persistence\n- lower latency when repeatedly calling the same host\n\n## Authentication\n\n### Basic Auth\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://httpbin.org/basic-auth/user/pass\",\n    auth=(\"user\", \"pass\"),\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\n### Digest Auth\n\n```python\nimport requests\nfrom requests.auth import HTTPDigestAuth\n\nresponse = requests.get(\n    \"https://httpbin.org/digest-auth/auth/user/pass\",\n    auth=HTTPDigestAuth(\"user\", \"pass\"),\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\n### `netrc`\n\nIf you do not pass `auth=`, Requests can load Basic Auth credentials from `~/.netrc`, `~/_netrc`, or the file pointed to by `NETRC`.\n\nDisable that behavior when you need predictable credentials or want to avoid environment-derived auth:\n\n```python\nimport requests\n\nwith requests.Session() as session:\n    session.trust_env = False\n    response = session.get(\"https://example.com\", timeout=30)\n```\n\n## TLS, Certificates, And Proxies\n\n### TLS Verification\n\nTLS verification is enabled by default and should stay enabled in normal code.\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://example.com\",\n    verify=\"/path/to/ca-bundle.pem\",\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\nUseful options:\n\n- `verify=True`: default behavior\n- `verify=\"/path/to/ca-bundle.pem\"`: trust a custom CA bundle\n- `verify=False`: only for local testing; this disables certificate and hostname checks\n\nRequests also honors:\n\n- `REQUESTS_CA_BUNDLE`\n- `CURL_CA_BUNDLE`\n\nRequests uses `certifi` for trusted CA roots.\n\n### Client Certificates\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://example.com\",\n    cert=(\"/path/client.cert\", \"/path/client.key\"),\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\nThe client private key must be unencrypted.\n\n### Proxies\n\nPer-request proxy configuration is safer than relying on `session.proxies`, because environment proxy settings can override session-level proxy values.\n\n```python\nimport requests\n\nproxies = {\n    \"http\": \"http://proxy.internal:3128\",\n    \"https\": \"http://proxy.internal:3128\",\n}\n\nresponse = requests.get(\n    \"https://example.com\",\n    proxies=proxies,\n    timeout=30,\n)\nresponse.raise_for_status()\n```\n\nRequests also reads standard environment variables:\n\n- `HTTP_PROXY`\n- `HTTPS_PROXY`\n- `ALL_PROXY`\n- `NO_PROXY`\n\nFor SOCKS proxies, install `requests[socks]` and use `socks5://...` or `socks5h://...`. `socks5h` resolves DNS on the proxy side.\n\n## Streaming Downloads And Responses\n\nUse `stream=True` for large responses or streaming APIs.\n\n```python\nimport requests\n\nwith requests.get(\"https://httpbin.org/stream/20\", stream=True, timeout=30) as response:\n    response.raise_for_status()\n\n    if response.encoding is None:\n        response.encoding = \"utf-8\"\n\n    for line in response.iter_lines(decode_unicode=True):\n        if line:\n            print(line)\n```\n\nFor file downloads:\n\n```python\nimport requests\n\nwith requests.get(\"https://example.com/archive.tar.gz\", stream=True, timeout=30) as response:\n    response.raise_for_status()\n    with open(\"archive.tar.gz\", \"wb\") as fh:\n        for chunk in response.iter_content(chunk_size=1024 * 1024):\n            if chunk:\n                fh.write(chunk)\n```\n\nImportant details:\n\n- `iter_content()` is preferred over `response.raw` for most code.\n- With `stream=True`, consume the body or close the response, or the connection will not be returned to the pool.\n- `iter_lines()` is not reentrant safe. Create the iterator once and share that iterator if multiple consumers are involved.\n\n## Error Handling\n\nCatch `RequestException` for broad transport errors and narrower subclasses when you need to branch.\n\n```python\nimport requests\nfrom requests.exceptions import HTTPError, JSONDecodeError, RequestException, Timeout\n\ntry:\n    response = requests.get(\"https://api.github.com/events\", timeout=(3.05, 30))\n    response.raise_for_status()\n    data = response.json()\nexcept Timeout:\n    print(\"The server was too slow to respond.\")\nexcept HTTPError as exc:\n    print(f\"HTTP error: {exc.response.status_code}\")\nexcept JSONDecodeError:\n    print(\"The response body was not valid JSON.\")\nexcept RequestException as exc:\n    print(f\"Network or Requests error: {exc}\")\n```\n\nCommon exception families to remember:\n\n- `RequestException`: base class for Requests errors\n- `Timeout`: request took too long\n- `ConnectionError`: DNS, TCP, or connection failures\n- `HTTPError`: raised by `raise_for_status()`\n- `JSONDecodeError`: invalid JSON in `response.json()`\n- `SSLError`: TLS verification or certificate problems\n\n## Common Pitfalls\n\n- Always set `timeout`. Requests does not choose one for you.\n- Do not treat `response.json()` as an HTTP success check.\n- Do not use `verify=False` in production.\n- Do not assume Requests is non-blocking; response reading is blocking even when using streaming APIs.\n- Do not rely on `session.proxies` if environment proxies may be present.\n- When you hand-build a `PreparedRequest`, merge environment settings if you still need env-based proxies or CA bundle behavior.\n- If you partially read a streamed response and never close it, connection reuse suffers.\n- Custom `Authorization` headers can be overridden by `.netrc` or `auth=`.\n\n## Version-Sensitive Notes For 2.32.x\n\n- `2.32.5` is the current PyPI release as of 2026-03-11. It reverted the SSLContext caching behavior introduced in `2.32.0`, added Python `3.14` support, and dropped Python `3.8`.\n- `2.32.4` fixed `CVE-2024-47081`, where a malicious URL combined with trusted environment settings could pull `.netrc` credentials for the wrong host. If you are pinned below `2.32.4`, upgrade or set `session.trust_env = False` where appropriate.\n- `2.32.0` and `2.32.1` were yanked on PyPI because of issues related to the `CVE-2024-35195` mitigation. Avoid pinning those versions.\n- If you subclass `HTTPAdapter`, review the `2.32.2` change that introduced `get_connection_with_tls_context` and deprecated `get_connection` for adapters affected by the 2.32.0 TLS-related changes.\n- Requests `2.30.0+` supports `urllib3 2.x`. If an older project is tightly pinned to `urllib3 1.x`, test upgrades carefully.\n\n## Official Sources\n\n- Stable docs: https://requests.readthedocs.io/en/stable/\n- Quickstart: https://requests.readthedocs.io/en/stable/user/quickstart/\n- Advanced usage: https://requests.readthedocs.io/en/stable/user/advanced/\n- Authentication: https://requests.readthedocs.io/en/stable/user/authentication/\n- API reference: https://requests.readthedocs.io/en/stable/api/\n- PyPI: https://pypi.org/project/requests/\n- Releases: https://github.com/psf/requests/releases\n"
  },
  {
    "path": "content/resend/docs/email/DOC.md",
    "content": "---\nname: email\ndescription: \"Modern email API platform with React Email integration, batch sending, scheduling, webhooks, and domain management\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.2.2\"\n  updated-on: \"2025-10-26\"\n  source: maintainer\n  tags: \"resend,sdk,email,messaging\"\n---\n# Resend Node.js SDK\n\n## Golden Rule\n\n**Always use the official `resend` package from npm.** The current version is 6.2.2.\n\n```bash\nnpm install resend\n```\n\nDo not use unofficial or deprecated packages like `@philnash/resend` or `resend-client-sdk-python`. The official Resend Node.js SDK is maintained at https://github.com/resend/resend-node.\n\n## Installation\n\nInstall the Resend SDK using npm, yarn, or pnpm:\n\n```bash\nnpm install resend\n```\n\n## Environment Setup\n\nStore your API key in an environment variable:\n\n```bash\n# .env\nRESEND_API_KEY=re_xxxxxxxxx\n```\n\nYou can obtain an API key from the Resend Dashboard at https://resend.com/api-keys. The API key will only be shown once, so store it securely immediately.\n\n## Initialization\n\nInitialize the Resend client with your API key:\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n```\n\nOr with a hardcoded key (not recommended for production):\n\n```javascript\nconst resend = new Resend('re_xxxxxxxxx');\n```\n\n## Sending Emails\n\n### Basic Email\n\nSend a simple HTML email:\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['delivered@resend.dev'],\n  subject: 'Hello World',\n  html: '<p>Congrats on sending your <strong>first email</strong>!</p>',\n});\n\nif (error) {\n  console.error(error);\n  return;\n}\n\nconsole.log(data);\n// { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }\n```\n\n### Email with Plain Text\n\nSend both HTML and plain text versions:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Hello World',\n  html: '<p>This is the <strong>HTML</strong> version</p>',\n  text: 'This is the plain text version',\n});\n```\n\nIf you omit the `text` parameter, it will be auto-generated from the HTML.\n\n### Email with Multiple Recipients\n\nSend to up to 50 recipients:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user1@example.com', 'user2@example.com', 'user3@example.com'],\n  subject: 'Hello World',\n  html: '<p>Hello everyone!</p>',\n});\n```\n\n### Email with CC and BCC\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['primary@example.com'],\n  cc: ['cc1@example.com', 'cc2@example.com'],\n  bcc: ['bcc1@example.com', 'bcc2@example.com'],\n  subject: 'Hello World',\n  html: '<p>Email with CC and BCC</p>',\n});\n```\n\n### Email with Reply-To\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  replyTo: 'support@acme.com',\n  subject: 'Hello World',\n  html: '<p>Reply to this email!</p>',\n});\n```\n\nMultiple reply-to addresses:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  replyTo: ['support@acme.com', 'help@acme.com'],\n  subject: 'Hello World',\n  html: '<p>Reply to this email!</p>',\n});\n```\n\n### Email with Custom Headers\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Hello World',\n  html: '<p>Email with custom headers</p>',\n  headers: {\n    'X-Entity-Ref-ID': '123456789',\n    'X-Custom-Header': 'Custom Value',\n  },\n});\n```\n\n### Email with Tags\n\nTags are custom key/value pairs for tracking and categorizing emails:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Hello World',\n  html: '<p>Email with tags</p>',\n  tags: [\n    { name: 'category', value: 'confirm_email' },\n    { name: 'user_id', value: '12345' },\n  ],\n});\n```\n\n### Email with Attachments\n\nAttachments support up to 40MB per email after Base64 encoding:\n\n```javascript\nimport fs from 'fs';\n\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Invoice',\n  html: '<p>Please find your invoice attached</p>',\n  attachments: [\n    {\n      filename: 'invoice.pdf',\n      content: fs.readFileSync('./invoice.pdf'),\n    },\n  ],\n});\n```\n\nAttachment with custom content type:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Report',\n  html: '<p>Your report is attached</p>',\n  attachments: [\n    {\n      filename: 'report.csv',\n      content: 'Name,Email\\nJohn,john@example.com\\n',\n      contentType: 'text/csv',\n    },\n  ],\n});\n```\n\nMultiple attachments:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Multiple Files',\n  html: '<p>Multiple files attached</p>',\n  attachments: [\n    {\n      filename: 'document1.pdf',\n      content: fs.readFileSync('./document1.pdf'),\n    },\n    {\n      filename: 'document2.pdf',\n      content: fs.readFileSync('./document2.pdf'),\n    },\n  ],\n});\n```\n\n### Scheduled Email\n\nSchedule an email using natural language or ISO 8601 format. Emails can be scheduled up to 30 days in advance.\n\nNatural language examples:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Scheduled Email',\n  html: '<p>This email was scheduled</p>',\n  scheduledAt: 'in 1 hour',\n});\n```\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Scheduled Email',\n  html: '<p>This email was scheduled</p>',\n  scheduledAt: 'tomorrow at 9am',\n});\n```\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Scheduled Email',\n  html: '<p>This email was scheduled</p>',\n  scheduledAt: 'Friday at 3pm ET',\n});\n```\n\nISO 8601 format:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Scheduled Email',\n  html: '<p>This email was scheduled</p>',\n  scheduledAt: '2024-08-05T11:52:01.858Z',\n});\n```\n\n### Email with React Components\n\nThe Node.js SDK supports React components for email templates:\n\n```javascript\nimport { Resend } from 'resend';\nimport { EmailTemplate } from './email-template';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Welcome',\n  react: EmailTemplate({ firstName: 'John' }),\n});\n```\n\nExample React email component:\n\n```jsx\n// email-template.jsx\nimport * as React from 'react';\n\nexport const EmailTemplate = ({ firstName }) => (\n  <div>\n    <h1>Welcome, {firstName}!</h1>\n    <p>Thanks for signing up.</p>\n  </div>\n);\n```\n\nWith `@react-email/components`:\n\n```jsx\nimport { Html, Button } from '@react-email/components';\n\nexport const EmailTemplate = ({ url }) => (\n  <Html>\n    <Button href={url}>Click me</Button>\n  </Html>\n);\n```\n\n### Idempotency\n\nUse idempotency keys to prevent duplicate sends. Keys expire after 24 hours and must be max 256 characters:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Hello World',\n  html: '<p>This is idempotent</p>',\n}, {\n  headers: {\n    'Idempotency-Key': 'unique-key-123456',\n  },\n});\n```\n\n## Batch Emails\n\nSend up to 100 emails in a single API call. Note that `attachments` and `scheduledAt` are not supported in batch mode.\n\n### Basic Batch Send\n\n```javascript\nconst { data, error } = await resend.batch.send([\n  {\n    from: 'Acme <onboarding@resend.dev>',\n    to: ['user1@example.com'],\n    subject: 'Hello User 1',\n    html: '<p>Hello User 1</p>',\n  },\n  {\n    from: 'Acme <onboarding@resend.dev>',\n    to: ['user2@example.com'],\n    subject: 'Hello User 2',\n    html: '<p>Hello User 2</p>',\n  },\n  {\n    from: 'Acme <onboarding@resend.dev>',\n    to: ['user3@example.com'],\n    subject: 'Hello User 3',\n    html: '<p>Hello User 3</p>',\n  },\n]);\n\nconsole.log(data);\n// [\n//   { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' },\n//   { id: '5d3a4f2e-8f7b-4c1d-9a3e-2b6c1e8f9a0b' },\n//   { id: '7e9f1a3c-2d4b-5e6f-8a9c-3d4e5f6a7b8c' }\n// ]\n```\n\n### Batch with Tags\n\n```javascript\nconst { data, error } = await resend.batch.send([\n  {\n    from: 'Acme <onboarding@resend.dev>',\n    to: ['user1@example.com'],\n    subject: 'Hello',\n    html: '<p>Hello</p>',\n    tags: [{ name: 'category', value: 'welcome' }],\n  },\n  {\n    from: 'Acme <onboarding@resend.dev>',\n    to: ['user2@example.com'],\n    subject: 'Hello',\n    html: '<p>Hello</p>',\n    tags: [{ name: 'category', value: 'welcome' }],\n  },\n]);\n```\n\n### Permissive Validation Mode\n\nBy default, if any email in a batch is invalid, the entire batch fails. Use permissive mode to process valid emails and return errors for invalid ones:\n\n```javascript\nconst { data, error } = await resend.batch.send(\n  [\n    {\n      from: 'Acme <onboarding@resend.dev>',\n      to: ['valid@example.com'],\n      subject: 'Valid Email',\n      html: '<p>This is valid</p>',\n    },\n    {\n      from: 'invalid-email',\n      to: ['user@example.com'],\n      subject: 'Invalid Email',\n      html: '<p>This has invalid from address</p>',\n    },\n  ],\n  {\n    headers: {\n      'X-Resend-Validation-Mode': 'permissive',\n    },\n  }\n);\n\nconsole.log(data);\n// {\n//   data: [{ id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }],\n//   errors: [{ message: 'Invalid from address', index: 1 }]\n// }\n```\n\n## Managing Emails\n\n### Retrieve Email by ID\n\nGet details about a specific email:\n\n```javascript\nconst { data, error } = await resend.emails.get(\n  '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'\n);\n\nconsole.log(data);\n// {\n//   object: 'email',\n//   id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',\n//   to: ['delivered@resend.dev'],\n//   from: 'Acme <onboarding@resend.dev>',\n//   created_at: '2023-04-03T22:13:42.674981+00:00',\n//   subject: 'Hello World',\n//   html: 'Congrats on sending your <strong>first email</strong>!',\n//   text: null,\n//   bcc: [],\n//   cc: [],\n//   reply_to: [],\n//   last_event: 'delivered',\n//   scheduled_at: null\n// }\n```\n\n### Update Scheduled Email\n\nUpdate the scheduled time for a scheduled email:\n\n```javascript\nconst oneHourFromNow = new Date(Date.now() + 1000 * 60 * 60).toISOString();\n\nconst { data, error } = await resend.emails.update({\n  id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',\n  scheduledAt: oneHourFromNow,\n});\n\nconsole.log(data);\n// {\n//   object: 'email',\n//   id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'\n// }\n```\n\nWith natural language:\n\n```javascript\nconst { data, error } = await resend.emails.update({\n  id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',\n  scheduledAt: 'in 2 hours',\n});\n```\n\n### Cancel Scheduled Email\n\nCancel a scheduled email that hasn't been sent yet:\n\n```javascript\nconst { data, error } = await resend.emails.cancel(\n  '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'\n);\n\nconsole.log(data);\n// {\n//   object: 'email',\n//   id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'\n// }\n```\n\nNote: Once an email is canceled, it cannot be rescheduled.\n\n## Audiences\n\nAudiences allow you to group and manage contacts for broadcasting.\n\n### Create Audience\n\n```javascript\nconst { data, error } = await resend.audiences.create({\n  name: 'Registered Users',\n});\n\nconsole.log(data);\n// {\n//   object: 'audience',\n//   id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n//   name: 'Registered Users'\n// }\n```\n\n### Retrieve Audience\n\n```javascript\nconst { data, error } = await resend.audiences.get(\n  '78261eea-8f8b-4381-83c6-79fa7120f1cf'\n);\n```\n\n### List Audiences\n\n```javascript\nconst { data, error } = await resend.audiences.list();\n\nconsole.log(data);\n// {\n//   object: 'list',\n//   data: [\n//     {\n//       id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n//       name: 'Registered Users',\n//       created_at: '2023-10-06T23:47:56.678Z'\n//     }\n//   ]\n// }\n```\n\n### Delete Audience\n\n```javascript\nconst { data, error } = await resend.audiences.remove(\n  '78261eea-8f8b-4381-83c6-79fa7120f1cf'\n);\n```\n\n## Contacts\n\nManage individual contacts within audiences.\n\n### Create Contact\n\n```javascript\nconst { data, error } = await resend.contacts.create({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  email: 'user@example.com',\n  firstName: 'John',\n  lastName: 'Doe',\n  unsubscribed: false,\n});\n\nconsole.log(data);\n// {\n//   object: 'contact',\n//   id: '479e3145-dd38-476b-932c-529ceb705947'\n// }\n```\n\n### Create Contact (Minimal)\n\n```javascript\nconst { data, error } = await resend.contacts.create({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  email: 'user@example.com',\n});\n```\n\n### Retrieve Contact\n\n```javascript\nconst { data, error } = await resend.contacts.get({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  id: '479e3145-dd38-476b-932c-529ceb705947',\n});\n```\n\n### List Contacts\n\n```javascript\nconst { data, error } = await resend.contacts.list({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n});\n\nconsole.log(data);\n// {\n//   object: 'list',\n//   data: [\n//     {\n//       id: '479e3145-dd38-476b-932c-529ceb705947',\n//       email: 'user@example.com',\n//       first_name: 'John',\n//       last_name: 'Doe',\n//       created_at: '2023-10-06T23:47:56.678Z',\n//       unsubscribed: false\n//     }\n//   ]\n// }\n```\n\n### Update Contact\n\n```javascript\nconst { data, error } = await resend.contacts.update({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  id: '479e3145-dd38-476b-932c-529ceb705947',\n  firstName: 'Jane',\n  unsubscribed: true,\n});\n```\n\n### Delete Contact\n\n```javascript\nconst { data, error } = await resend.contacts.remove({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  id: '479e3145-dd38-476b-932c-529ceb705947',\n});\n```\n\n## Broadcasts\n\nBroadcasts allow you to send emails to entire audiences.\n\n### Create Broadcast\n\n```javascript\nconst { data, error } = await resend.broadcasts.create({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  from: 'Acme <newsletter@acme.com>',\n  subject: 'Monthly Newsletter',\n  html: 'Hi {{{FIRST_NAME|there}}}, you can unsubscribe here: {{{RESEND_UNSUBSCRIBE_URL}}}',\n  name: 'October Newsletter',\n});\n\nconsole.log(data);\n// {\n//   id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'\n// }\n```\n\n### Create Broadcast with React\n\n```javascript\nimport { NewsletterTemplate } from './newsletter-template';\n\nconst { data, error } = await resend.broadcasts.create({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  from: 'Acme <newsletter@acme.com>',\n  subject: 'Monthly Newsletter',\n  react: NewsletterTemplate(),\n});\n```\n\n### Broadcast Template Variables\n\nUse template variables in broadcasts:\n\n- `{{{FIRST_NAME}}}` - Contact's first name\n- `{{{LAST_NAME}}}` - Contact's last name\n- `{{{EMAIL}}}` - Contact's email\n- `{{{RESEND_UNSUBSCRIBE_URL}}}` - Unsubscribe URL\n\nWith fallback values:\n\n```javascript\nconst { data, error } = await resend.broadcasts.create({\n  audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  from: 'Acme <newsletter@acme.com>',\n  subject: 'Hello {{{FIRST_NAME|Friend}}}',\n  html: '<p>Hi {{{FIRST_NAME|there}}},</p><p>Thanks for subscribing!</p>',\n});\n```\n\n### Send Broadcast Immediately\n\n```javascript\nconst { data, error } = await resend.broadcasts.send(\n  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'\n);\n\nconsole.log(data);\n// {\n//   id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'\n// }\n```\n\n### Send Broadcast with Scheduling\n\n```javascript\nconst { data, error } = await resend.broadcasts.send(\n  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',\n  {\n    scheduledAt: 'tomorrow at 9am',\n  }\n);\n```\n\n```javascript\nconst { data, error } = await resend.broadcasts.send(\n  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',\n  {\n    scheduledAt: '2024-08-05T11:52:01.858Z',\n  }\n);\n```\n\n### Retrieve Broadcast\n\n```javascript\nconst { data, error } = await resend.broadcasts.get(\n  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'\n);\n```\n\n### List Broadcasts\n\n```javascript\nconst { data, error } = await resend.broadcasts.list();\n```\n\n### Update Broadcast\n\n```javascript\nconst { data, error } = await resend.broadcasts.update({\n  id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',\n  subject: 'Updated Newsletter Subject',\n  html: '<p>Updated content</p>',\n});\n```\n\n### Delete Broadcast\n\n```javascript\nconst { data, error } = await resend.broadcasts.remove(\n  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'\n);\n```\n\n## Domains\n\nManage domains for sending emails.\n\n### Create Domain\n\n```javascript\nconst { data, error } = await resend.domains.create({\n  name: 'example.com',\n});\n\nconsole.log(data);\n// {\n//   id: 'd91cd9bd-1176-453e-8fc1-35364d380206',\n//   name: 'example.com',\n//   status: 'not_started',\n//   records: [\n//     {\n//       record: 'SPF',\n//       name: 'example.com',\n//       type: 'TXT',\n//       value: 'v=spf1 include:_spf.resend.com ~all'\n//     },\n//     {\n//       record: 'DKIM',\n//       name: 'resend._domainkey.example.com',\n//       type: 'TXT',\n//       value: 'p=...'\n//     }\n//   ]\n// }\n```\n\n### Retrieve Domain\n\n```javascript\nconst { data, error } = await resend.domains.get(\n  'd91cd9bd-1176-453e-8fc1-35364d380206'\n);\n```\n\n### List Domains\n\n```javascript\nconst { data, error } = await resend.domains.list();\n\nconsole.log(data);\n// {\n//   object: 'list',\n//   data: [\n//     {\n//       id: 'd91cd9bd-1176-453e-8fc1-35364d380206',\n//       name: 'example.com',\n//       status: 'verified',\n//       created_at: '2023-04-03T22:13:42.674981+00:00'\n//     }\n//   ]\n// }\n```\n\n### Verify Domain\n\nAfter adding DNS records, verify the domain:\n\n```javascript\nconst { data, error } = await resend.domains.verify(\n  'd91cd9bd-1176-453e-8fc1-35364d380206'\n);\n\nconsole.log(data);\n// {\n//   object: 'domain',\n//   id: 'd91cd9bd-1176-453e-8fc1-35364d380206',\n//   status: 'verified'\n// }\n```\n\n### Update Domain\n\n```javascript\nconst { data, error } = await resend.domains.update({\n  id: 'd91cd9bd-1176-453e-8fc1-35364d380206',\n  clickTracking: true,\n  openTracking: true,\n});\n```\n\n### Delete Domain\n\n```javascript\nconst { data, error } = await resend.domains.remove(\n  'd91cd9bd-1176-453e-8fc1-35364d380206'\n);\n```\n\n## API Keys\n\nManage API keys programmatically.\n\n### Create API Key\n\n```javascript\nconst { data, error } = await resend.apiKeys.create({\n  name: 'Production',\n  permission: 'full_access',\n});\n\nconsole.log(data);\n// {\n//   id: 'b6d24b8e-af0b-4c3c-be0c-359bbd97381e',\n//   token: 're_xxxxxxxxx'\n// }\n```\n\nAvailable permissions:\n- `full_access` - Can create, delete, get, and update any resource\n- `sending_access` - Can only send emails\n\nCreate sending-only API key:\n\n```javascript\nconst { data, error } = await resend.apiKeys.create({\n  name: 'Sending Key',\n  permission: 'sending_access',\n});\n```\n\nRestrict to specific domain:\n\n```javascript\nconst { data, error } = await resend.apiKeys.create({\n  name: 'Domain-Specific Key',\n  permission: 'sending_access',\n  domainId: 'd91cd9bd-1176-453e-8fc1-35364d380206',\n});\n```\n\n### List API Keys\n\n```javascript\nconst { data, error } = await resend.apiKeys.list();\n\nconsole.log(data);\n// {\n//   object: 'list',\n//   has_more: false,\n//   data: [\n//     {\n//       id: '91f3200a-df72-4654-b0cd-f202395f5354',\n//       name: 'Production',\n//       created_at: '2023-04-08T00:11:13.110779+00:00'\n//     }\n//   ]\n// }\n```\n\n### Delete API Key\n\n```javascript\nconst { data, error } = await resend.apiKeys.remove(\n  'b6d24b8e-af0b-4c3c-be0c-359bbd97381e'\n);\n```\n\n## Error Handling\n\nAll API methods return an object with `data` and `error` properties:\n\n```javascript\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  subject: 'Hello',\n  html: '<p>Hello</p>',\n});\n\nif (error) {\n  console.error('Failed to send email:', error);\n  return;\n}\n\nconsole.log('Email sent successfully:', data.id);\n```\n\nCommon error scenarios:\n\n```javascript\n// Missing required fields\nconst { data, error } = await resend.emails.send({\n  from: 'Acme <onboarding@resend.dev>',\n  to: ['user@example.com'],\n  // Missing subject\n  html: '<p>Hello</p>',\n});\n// error: { message: 'Missing required parameter: subject' }\n\n// Invalid API key\nconst resend = new Resend('invalid_key');\nconst { data, error } = await resend.emails.send({...});\n// error: { message: 'Invalid API key' }\n\n// Unverified domain\nconst { data, error } = await resend.emails.send({\n  from: 'user@unverified-domain.com',\n  to: ['user@example.com'],\n  subject: 'Hello',\n  html: '<p>Hello</p>',\n});\n// error: { message: 'Domain not verified' }\n\n// Rate limit exceeded\n// error: { message: 'Rate limit exceeded' }\n```\n\n## Complete Examples\n\n### Basic Email Sending\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function sendWelcomeEmail(userEmail, userName) {\n  const { data, error } = await resend.emails.send({\n    from: 'Acme <welcome@acme.com>',\n    to: [userEmail],\n    subject: `Welcome to Acme, ${userName}!`,\n    html: `\n      <h1>Welcome, ${userName}!</h1>\n      <p>Thanks for signing up. We're excited to have you on board.</p>\n      <p>Get started by visiting your dashboard.</p>\n    `,\n  });\n\n  if (error) {\n    throw new Error(`Failed to send welcome email: ${error.message}`);\n  }\n\n  return data.id;\n}\n\n// Usage\nawait sendWelcomeEmail('user@example.com', 'John Doe');\n```\n\n### Scheduled Email with Attachment\n\n```javascript\nimport { Resend } from 'resend';\nimport fs from 'fs';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function sendScheduledReport(recipient, reportPath, sendTime) {\n  const { data, error } = await resend.emails.send({\n    from: 'Reports <reports@acme.com>',\n    to: [recipient],\n    subject: 'Weekly Report',\n    html: '<p>Your weekly report is attached.</p>',\n    attachments: [\n      {\n        filename: 'weekly-report.pdf',\n        content: fs.readFileSync(reportPath),\n        contentType: 'application/pdf',\n      },\n    ],\n    scheduledAt: sendTime,\n    tags: [\n      { name: 'type', value: 'report' },\n      { name: 'frequency', value: 'weekly' },\n    ],\n  });\n\n  if (error) {\n    throw new Error(`Failed to schedule report: ${error.message}`);\n  }\n\n  return data.id;\n}\n\n// Usage\nawait sendScheduledReport(\n  'manager@example.com',\n  './reports/weekly.pdf',\n  'Friday at 9am'\n);\n```\n\n### Newsletter Broadcast\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function sendNewsletter(audienceId, content) {\n  // Create broadcast\n  const { data: broadcast, error: createError } = await resend.broadcasts.create({\n    audienceId: audienceId,\n    from: 'Newsletter <newsletter@acme.com>',\n    subject: 'Monthly Update - October 2024',\n    html: `\n      <h1>Hi {{{FIRST_NAME|there}}}!</h1>\n      ${content}\n      <p><a href=\"{{{RESEND_UNSUBSCRIBE_URL}}}\">Unsubscribe</a></p>\n    `,\n    name: 'October 2024 Newsletter',\n  });\n\n  if (createError) {\n    throw new Error(`Failed to create broadcast: ${createError.message}`);\n  }\n\n  // Send immediately\n  const { data: sent, error: sendError } = await resend.broadcasts.send(\n    broadcast.id\n  );\n\n  if (sendError) {\n    throw new Error(`Failed to send broadcast: ${sendError.message}`);\n  }\n\n  return sent.id;\n}\n\n// Usage\nawait sendNewsletter(\n  '78261eea-8f8b-4381-83c6-79fa7120f1cf',\n  '<p>Here is what is new this month...</p>'\n);\n```\n\n### Batch Email with Error Handling\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function sendBatchNotifications(users) {\n  const emails = users.map(user => ({\n    from: 'Notifications <notifications@acme.com>',\n    to: [user.email],\n    subject: 'Important Update',\n    html: `<p>Hi ${user.name}, we have an important update for you.</p>`,\n    tags: [{ name: 'user_id', value: user.id }],\n  }));\n\n  const { data, error } = await resend.batch.send(emails, {\n    headers: {\n      'X-Resend-Validation-Mode': 'permissive',\n    },\n  });\n\n  if (error) {\n    throw new Error(`Batch send failed: ${error.message}`);\n  }\n\n  // Handle partial failures\n  if (data.errors && data.errors.length > 0) {\n    console.warn('Some emails failed:', data.errors);\n  }\n\n  return {\n    successful: data.data.length,\n    failed: data.errors?.length || 0,\n    emailIds: data.data.map(d => d.id),\n  };\n}\n\n// Usage\nconst users = [\n  { id: '1', email: 'user1@example.com', name: 'User 1' },\n  { id: '2', email: 'user2@example.com', name: 'User 2' },\n  { id: '3', email: 'user3@example.com', name: 'User 3' },\n];\n\nconst result = await sendBatchNotifications(users);\nconsole.log(`Sent ${result.successful} emails, ${result.failed} failed`);\n```\n\n### Managing Audience and Contacts\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function setupMarketingList(listName, contacts) {\n  // Create audience\n  const { data: audience, error: audienceError } = await resend.audiences.create({\n    name: listName,\n  });\n\n  if (audienceError) {\n    throw new Error(`Failed to create audience: ${audienceError.message}`);\n  }\n\n  console.log(`Created audience: ${audience.id}`);\n\n  // Add contacts\n  const results = [];\n  for (const contact of contacts) {\n    const { data, error } = await resend.contacts.create({\n      audienceId: audience.id,\n      email: contact.email,\n      firstName: contact.firstName,\n      lastName: contact.lastName,\n    });\n\n    if (error) {\n      console.error(`Failed to add ${contact.email}:`, error.message);\n    } else {\n      results.push(data.id);\n    }\n  }\n\n  return {\n    audienceId: audience.id,\n    contactsAdded: results.length,\n  };\n}\n\n// Usage\nconst contacts = [\n  { email: 'john@example.com', firstName: 'John', lastName: 'Doe' },\n  { email: 'jane@example.com', firstName: 'Jane', lastName: 'Smith' },\n];\n\nconst result = await setupMarketingList('Q4 Campaign', contacts);\nconsole.log(`Setup complete: ${result.contactsAdded} contacts added`);\n```\n\n### Cancel and Reschedule\n\n```javascript\nimport { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function rescheduleEmail(emailId, newTime) {\n  // Update scheduled time\n  const { data, error } = await resend.emails.update({\n    id: emailId,\n    scheduledAt: newTime,\n  });\n\n  if (error) {\n    throw new Error(`Failed to reschedule: ${error.message}`);\n  }\n\n  return data.id;\n}\n\nasync function cancelScheduledEmail(emailId) {\n  const { data, error } = await resend.emails.cancel(emailId);\n\n  if (error) {\n    throw new Error(`Failed to cancel: ${error.message}`);\n  }\n\n  return data.id;\n}\n\n// Usage\nconst emailId = '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794';\n\n// Reschedule for 2 hours later\nawait rescheduleEmail(emailId, 'in 2 hours');\n\n// Or cancel completely\nawait cancelScheduledEmail(emailId);\n```\n\n## TypeScript Support\n\nThe Resend SDK is written in TypeScript and includes full type definitions:\n\n```typescript\nimport { Resend } from 'resend';\nimport type { CreateEmailOptions, CreateEmailResponse } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nasync function sendEmail(\n  options: CreateEmailOptions\n): Promise<CreateEmailResponse> {\n  const { data, error } = await resend.emails.send(options);\n\n  if (error) {\n    throw error;\n  }\n\n  return data;\n}\n```\n\nType definitions for all API methods are included in the package.\n"
  },
  {
    "path": "content/resolve/docs/resolve/javascript/DOC.md",
    "content": "---\nname: resolve\ndescription: \"resolve package guide for Node-style module resolution from a chosen base directory\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.22.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"resolve,module-resolution,nodejs,require,cli\"\n---\n\n# resolve JavaScript Guide\n\n## Golden Rule\n\nUse `resolve` when you need Node's `require.resolve()` algorithm, but you need to run it on behalf of another file or directory. The package exposes an async API, a sync API, and a small CLI.\n\n`resolve` has no environment variables, no credentials, and no client initialization step. The only required setup is installing the package and passing an existing `basedir`.\n\n## Install\n\n```bash\nnpm install resolve\n```\n\nUse the entry point that matches your workflow:\n\n```javascript\nconst resolve = require('resolve');\nconst resolveAsync = require('resolve/async');\nconst resolveSync = require('resolve/sync');\n\nconst alsoSync = require('resolve').sync;\n```\n\n`require('resolve')` is the async API.\n\n## Resolve A Package From Another Directory\n\nAsync resolution returns `cb(err, resolvedPath, pkg)`.\n\n```javascript\nconst path = require('path');\nconst resolve = require('resolve');\n\nfunction resolveFrom(importerFile, specifier, callback) {\n  resolve(specifier, { basedir: path.dirname(importerFile) }, callback);\n}\n\nresolveFrom('/workspace/src/index.js', 'resolve', (err, resolvedPath, pkg) => {\n  if (err) throw err;\n\n  console.log(resolvedPath);\n  console.log(pkg && pkg.name);\n});\n```\n\nPass a directory, not a file path, as `basedir`. If `basedir` does not exist or is not a directory, `resolve` reports `INVALID_BASEDIR`.\n\n## Resolve Synchronously\n\n`resolve.sync()` returns the resolved path or throws.\n\n```javascript\nconst resolveSync = require('resolve/sync');\n\ntry {\n  const resolvedPath = resolveSync('resolve', { basedir: __dirname });\n  console.log(resolvedPath);\n} catch (err) {\n  if (err.code === 'MODULE_NOT_FOUND') {\n    console.error('Dependency not found');\n  } else {\n    throw err;\n  }\n}\n```\n\n## Common Options\n\n### Add File Extensions\n\nBy default, `resolve` checks `['.js']`. Add extensions explicitly when your project resolves other file types.\n\n```javascript\nconst resolve = require('resolve');\n\nresolve('./config', {\n  basedir: __dirname,\n  extensions: ['.js', '.json']\n}, (err, resolvedPath) => {\n  if (err) throw err;\n  console.log(resolvedPath);\n});\n```\n\n### Treat Core Modules As External\n\nWith the default `includeCoreModules: true`, core modules like `fs` resolve to the module id itself.\n\n```javascript\nconst resolveSync = require('resolve/sync');\n\nconsole.log(resolveSync('fs', { basedir: __dirname }));\n// => 'fs'\n```\n\nSet `includeCoreModules: false` when you want file-only resolution behavior.\n\n```javascript\nconst resolveSync = require('resolve/sync');\n\ntry {\n  resolveSync('fs', {\n    basedir: __dirname,\n    includeCoreModules: false\n  });\n} catch (err) {\n  console.error(err.code);\n}\n```\n\n### Search Custom Module Directories\n\n`moduleDirectory` defaults to `node_modules`, but it can be a string or an array.\n\n```javascript\nconst resolve = require('resolve');\n\nresolve('aaa', {\n  basedir: __dirname,\n  moduleDirectory: ['xmodules', 'node_modules']\n}, (err, resolvedPath) => {\n  if (err) throw err;\n  console.log(resolvedPath);\n});\n```\n\n### Rewrite `package.json` Before Resolution\n\nUse `packageFilter` when you need to override the parsed `package.json` before `resolve` reads its `main` field.\n\n```javascript\nconst resolve = require('resolve');\n\nresolve('./baz', {\n  basedir: __dirname,\n  packageFilter(pkg) {\n    pkg.main = 'server';\n    return pkg;\n  }\n}, (err, resolvedPath) => {\n  if (err) throw err;\n  console.log(resolvedPath);\n});\n```\n\nIn `1.x`, the async `packageFilter` receives `(pkg, pkgfile, dir)`. The sync API differs: in `1.x`, `resolve.sync()` passes `(pkg, dir)`, and the maintainer README notes that this argument shape changes in `v2`.\n\n### Rewrite Deep Package Paths\n\nUse `pathFilter` to map a subpath inside a package to a different relative file.\n\n```javascript\nconst resolve = require('resolve');\n\nresolve('deep/ref', {\n  basedir: __dirname,\n  pathFilter(pkg, fullPath, relativePath) {\n    if (relativePath === 'ref') {\n      return 'alt';\n    }\n  }\n}, (err, resolvedPath) => {\n  if (err) throw err;\n  console.log(resolvedPath);\n});\n```\n\nReturn a path relative to the package root. Do not return an absolute path from `pathFilter`.\n\n## CLI\n\nThe package publishes a `resolve` executable.\n\nResolve from the current working directory:\n\n```bash\nnpx resolve resolve\n```\n\nPreserve symlink paths explicitly:\n\n```bash\nnpx resolve --preserve-symlinks resolve\n```\n\nThe CLI accepts a single specifier and resolves it relative to `process.cwd()`.\n\n## Errors And Pitfalls\n\n- `MODULE_NOT_FOUND` means the specifier could not be resolved from the supplied base directory.\n- `INVALID_BASEDIR` means `opts.basedir` is missing, does not exist, or is not a directory.\n- `INVALID_PACKAGE_MAIN` means `resolve` found a `package.json` with a non-string `main` field.\n- `preserveSymlinks` defaults to `true` in `1.22.11`, even though the maintainer README says Node's default resolution behavior does not preserve symlinks. In monorepos or symlinked workspaces, set `preserveSymlinks: false` when you want behavior closer to normal Node resolution.\n- `paths` and `packageIterator` exist for advanced custom lookup flows, but most application code should prefer `basedir`, `extensions`, `moduleDirectory`, `packageFilter`, and `pathFilter`.\n\n## Practical Defaults\n\nUse this shape for most tool integrations:\n\n```javascript\nconst resolve = require('resolve');\n\nresolve('some-package', {\n  basedir: __dirname,\n  extensions: ['.js', '.json'],\n  includeCoreModules: true,\n  preserveSymlinks: false\n}, (err, resolvedPath) => {\n  if (err) throw err;\n  console.log(resolvedPath);\n});\n```\n\nUse `resolve.sync()` only when your code path must stay synchronous, such as inside a config loader or a synchronous build step.\n"
  },
  {
    "path": "content/responses/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"responses package guide for mocking requests-based HTTP calls in Python tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.26.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"responses,requests,http,mocking,testing,pytest\"\n---\n\n# responses Python Package Guide\n\n## Golden Rule\n\nUse `responses` only for code that goes through the `requests` stack. It monkey-patches `requests`, so it is the right tool for unit tests around `requests.Session`, retry adapters, redirect handling, and request validation, but it will not mock `httpx`, `aiohttp`, or raw sockets.\n\n## Install\n\n```bash\npython -m pip install \"responses==0.26.0\"\n```\n\nCommon project setups:\n\n```bash\nuv add --dev \"responses==0.26.0\"\npoetry add --group test \"responses==0.26.0\"\n```\n\nIf you want a pytest fixture instead of decorators or context managers, upstream points to the separate `pytest-responses` package:\n\n```bash\npython -m pip install pytest-responses\n```\n\n## Core Usage\n\n### Decorator-based test\n\n`responses.activate` is the fastest way to wrap a single test:\n\n```python\nimport requests\nimport responses\n\n@responses.activate\ndef test_fetch_user():\n    responses.get(\n        \"https://api.example.com/users/1\",\n        json={\"id\": 1, \"name\": \"Ada\"},\n        status=200,\n    )\n\n    resp = requests.get(\"https://api.example.com/users/1\")\n\n    assert resp.status_code == 200\n    assert resp.json()[\"name\"] == \"Ada\"\n    assert len(responses.calls) == 1\n    assert responses.calls[0].request.url == \"https://api.example.com/users/1\"\n```\n\nIf a request does not match a registered response, `responses` raises `requests.exceptions.ConnectionError`.\n\n### Context manager\n\nUse `RequestsMock` when you need scoped setup or per-test configuration:\n\n```python\nimport requests\nimport responses\n\ndef test_list_items():\n    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:\n        rsps.add(\n            responses.GET,\n            \"https://api.example.com/items\",\n            json=[{\"id\": 1}, {\"id\": 2}],\n            status=200,\n        )\n\n        resp = requests.get(\"https://api.example.com/items\")\n\n    assert resp.json() == [{\"id\": 1}, {\"id\": 2}]\n```\n\nOutside the decorator or context manager, requests go to the real network.\n\n### Match request bodies and query params\n\nPrefer matchers over deprecated URL/query-string flags:\n\n```python\nimport requests\nimport responses\nfrom responses import matchers\n\n@responses.activate\ndef test_create_widget():\n    responses.post(\n        \"https://api.example.com/widgets\",\n        json={\"ok\": True},\n        match=[\n            matchers.json_params_matcher({\"name\": \"demo\"}),\n            matchers.header_matcher({\"Authorization\": \"Bearer test-token\"}),\n        ],\n    )\n\n    resp = requests.post(\n        \"https://api.example.com/widgets\",\n        json={\"name\": \"demo\"},\n        headers={\"Authorization\": \"Bearer test-token\"},\n    )\n\n    assert resp.json() == {\"ok\": True}\n\n@responses.activate\ndef test_search():\n    responses.get(\n        \"https://api.example.com/search\",\n        body=\"ok\",\n        match=[matchers.query_param_matcher({\"q\": \"test\", \"page\": \"1\"})],\n    )\n\n    resp = requests.get(\n        \"https://api.example.com/search\",\n        params={\"q\": \"test\", \"page\": \"1\"},\n    )\n\n    assert resp.text == \"ok\"\n```\n\n### Dynamic callbacks\n\nUse callbacks when the response depends on request input:\n\n```python\nimport json\nimport requests\nimport responses\n\n@responses.activate\ndef test_sum_api():\n    def callback(request):\n        payload = json.loads(request.body)\n        total = sum(payload[\"numbers\"])\n        return (200, {\"Content-Type\": \"application/json\"}, json.dumps({\"total\": total}))\n\n    responses.add_callback(\n        responses.POST,\n        \"https://calc.example.com/sum\",\n        callback=callback,\n        content_type=\"application/json\",\n    )\n\n    resp = requests.post(\n        \"https://calc.example.com/sum\",\n        json={\"numbers\": [1, 2, 3]},\n    )\n\n    assert resp.json() == {\"total\": 6}\n```\n\n## Configuration And Test Setup\n\nThere is no auth configuration for `responses` itself. The main setup surface is how you configure the mock registry.\n\nUseful options and helpers:\n\n- `responses.RequestsMock(assert_all_requests_are_fired=True)` to fail if a declared mock is never used\n- `responses.RequestsMock(assert_all_requests_are_fired=False)` when a test intentionally leaves some mocks unused\n- `@responses.activate(registry=responses.registries.OrderedRegistry)` when the same URL should return different results on successive calls\n- `responses.add_passthru(\"https://real-host.example\")` to let unmatched requests for that prefix hit the real server\n- `responses.calls` to inspect captured requests and responses after execution\n- `responses.replace(...)`, `responses.upsert(...)`, and `responses.remove(...)` for mutating the active registry during a test\n\nOrdered retries example:\n\n```python\nimport requests\nimport responses\nfrom responses import registries\n\n@responses.activate(registry=registries.OrderedRegistry)\ndef test_ordered_responses():\n    responses.get(\"https://api.example.com/data\", status=500)\n    responses.get(\"https://api.example.com/data\", status=500)\n    responses.get(\"https://api.example.com/data\", json={\"ok\": True}, status=200)\n\n    first = requests.get(\"https://api.example.com/data\")\n    second = requests.get(\"https://api.example.com/data\")\n    third = requests.get(\"https://api.example.com/data\")\n\n    assert [first.status_code, second.status_code, third.status_code] == [500, 500, 200]\n    assert third.json() == {\"ok\": True}\n```\n\nIf your production code uses a configured `requests.Session` with retry adapters, create that session in the test and let `responses` serve the sequence you need.\n\n## Common Pitfalls\n\n- `responses` only intercepts `requests`. If the code under test switched to `httpx` or `aiohttp`, your mocks will silently stop applying.\n- Unmatched requests raise `ConnectionError`. That usually means the method, URL, query params, body matcher, or headers do not match exactly.\n- Do not keep query parameters embedded in the URL when using request matchers. Upstream explicitly recommends `matchers.query_param_matcher(...)` or `matchers.query_string_matcher(...)` instead of the deprecated `match_querystring`.\n- Header matching is loose by default because `requests` adds its own standard headers. If you set `strict_match=True`, use a prepared request or expect failures from extra headers.\n- When multiple responses match the same request, the default registry returns the first match and removes it. Use `OrderedRegistry` when request order is the point of the test.\n- A pass-through prefix only affects requests that are otherwise unmatched. A fully matched registered response still wins.\n- Upstream says coroutine and multithreading support exists, but access is locked on the `RequestMock` object so only one thread can use it at a time.\n\n## Version-Sensitive Notes For 0.26.0\n\n- PyPI and the upstream docs agree on `responses 0.26.0` as the current release as of March 12, 2026.\n- Current documented minimums are Python 3.8+ and `requests >= 2.30.0`.\n- Deprecated APIs still called out upstream:\n  - `responses.json_params_matcher` -> `responses.matchers.json_params_matcher`\n  - `responses.urlencoded_params_matcher` -> `responses.matchers.urlencoded_params_matcher`\n  - `stream=` on `Response` or `CallbackResponse` -> pass `stream` in the request instead\n  - `match_querystring=` -> `responses.matchers.query_param_matcher` or `query_string_matcher`\n  - module-level `responses.assert_all_requests_are_fired`, `responses.passthru_prefixes`, and `responses.target` -> use `responses.mock.*`\n- Recorder and replay helpers under `responses._recorder` and `responses._add_from_file(...)` are still documented as beta. Do not build stable internal tooling around them without pinning and verifying behavior first.\n\n## Official Sources\n\n- PyPI project: `https://pypi.org/project/responses/`\n- PyPI JSON metadata: `https://pypi.org/pypi/responses/json`\n- Maintainer repository: `https://github.com/getsentry/responses`\n- Changelog link from PyPI: `https://github.com/getsentry/responses/blob/master/CHANGES`\n"
  },
  {
    "path": "content/respx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"RESPX package guide for Python tests using HTTPX request mocking and route assertions\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.22.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"respx,httpx,testing,mocking,async,pytest\"\n---\n\n# RESPX Python Package Guide\n\n## Golden Rule\n\nUse `respx` to mock `httpx` traffic in tests, and keep routes specific. Prefer a configured router or the `respx_mock` pytest fixture over mutating the global default router with loose patterns.\n\nAs of March 12, 2026, PyPI still lists `0.22.0` as the current release, which matches the version used here. The 0.22.0 release also adds HTTPX 0.28 support and drops Python 3.7.\n\n## Install\n\nInstall RESPX together with the test tools you already use:\n\n```bash\npython -m pip install \"respx==0.22.0\" pytest\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"respx==0.22.0\"\npoetry add --group test \"respx==0.22.0\"\n```\n\nRESPX is for mocking `httpx`, not `requests`. For this version, the maintained compatibility target is HTTPX 0.25+, and the 0.22.0 release notes explicitly mention HTTPX 0.28 support.\n\n## Quick Start With `pytest`\n\nRESPX ships a `pytest` fixture named `respx_mock`. Add routes, then call your code that uses `httpx`.\n\n```python\nimport httpx\n\ndef fetch_user(user_id: str) -> dict:\n    response = httpx.get(f\"https://api.example.com/users/{user_id}\")\n    response.raise_for_status()\n    return response.json()\n\ndef test_fetch_user(respx_mock):\n    user_route = respx_mock.get(\"https://api.example.com/users/42\").mock(\n        return_value=httpx.Response(200, json={\"id\": \"42\", \"name\": \"Ada\"})\n    )\n\n    result = fetch_user(\"42\")\n\n    assert result[\"name\"] == \"Ada\"\n    assert user_route.called\n    assert user_route.call_count == 1\n```\n\nIf you want unused routes to fail the test, configure the router explicitly:\n\n```python\nimport httpx\nimport pytest\n\n@pytest.mark.respx(assert_all_called=True, base_url=\"https://api.example.com\")\ndef test_list_users(respx_mock):\n    respx_mock.get(\"/users\").mock(\n        return_value=httpx.Response(200, json=[{\"id\": \"42\"}])\n    )\n\n    response = httpx.get(\"https://api.example.com/users\")\n\n    assert response.status_code == 200\n```\n\n## Setup Patterns\n\n### Decorator or context manager\n\nUse `respx.mock(...)` when patching global `httpx` traffic is fine for the whole test body:\n\n```python\nimport httpx\nimport respx\n\n@respx.mock(base_url=\"https://api.example.com\", assert_all_called=True)\ndef test_create_user():\n    create_route = respx.post(\"/users\").mock(\n        return_value=httpx.Response(201, json={\"id\": \"123\"})\n    )\n\n    response = httpx.post(\"https://api.example.com/users\", json={\"name\": \"Ada\"})\n\n    assert response.status_code == 201\n    assert create_route.called\n```\n\nEquivalent context-manager style:\n\n```python\nimport httpx\nimport respx\n\nwith respx.mock(base_url=\"https://api.example.com\", assert_all_called=True) as router:\n    router.get(\"/health\").respond(200, json={\"ok\": True})\n    response = httpx.get(\"https://api.example.com/health\")\n    assert response.json() == {\"ok\": True}\n```\n\n### Async clients\n\nRESPX works with `httpx.AsyncClient` too:\n\n```python\nimport httpx\nimport pytest\nimport respx\n\n@pytest.mark.asyncio\n@respx.mock\nasync def test_async_lookup():\n    respx.get(\"https://api.example.com/items/1\").mock(\n        return_value=httpx.Response(200, json={\"id\": 1})\n    )\n\n    async with httpx.AsyncClient() as client:\n        response = await client.get(\"https://api.example.com/items/1\")\n\n    assert response.json() == {\"id\": 1}\n```\n\n### Mock without patching all HTTPX usage\n\nIf your code already accepts a transport or client, use RESPX transport classes instead of patching globally:\n\n```python\nimport httpx\nimport respx\n\nmock_transport = respx.SyncMockTransport(assert_all_called=True)\nuser_route = mock_transport.get(\"https://api.example.com/users/42\").respond(\n    200, json={\"id\": \"42\"}\n)\n\nwith httpx.Client(transport=mock_transport) as client:\n    response = client.get(\"https://api.example.com/users/42\")\n\nassert response.status_code == 200\nassert user_route.called\n```\n\nThis pattern is safer when tests run in parallel or when only one injected client should be mocked.\n\n## Matching Requests\n\nRESPX routes can be created with shorthand helpers like `respx.get(...)` or with `route(...)` plus lookups.\n\n```python\nimport httpx\nimport respx\n\n@respx.mock\ndef test_match_path_and_query():\n    route = respx.route(\n        method=\"GET\",\n        host=\"api.example.com\",\n        path__regex=r\"^/users/\\d+$\",\n        params__contains={\"expand\": \"teams\"},\n    ).mock(return_value=httpx.Response(200, json={\"ok\": True}))\n\n    response = httpx.get(\n        \"https://api.example.com/users/42\",\n        params={\"expand\": \"teams\", \"page\": \"1\"},\n    )\n\n    assert response.json() == {\"ok\": True}\n    assert route.called\n```\n\nUseful matching strategies:\n\n- Use `base_url=\"https://api.example.com\"` plus relative paths like `\"/users\"`.\n- Match on `method`, `host`, `path`, `params`, `headers`, `cookies`, `content`, `json`, or regex-based variants such as `path__regex`.\n- Name routes when you want later lookup or assertions: `router.get(..., name=\"users_list\")`.\n\n## Returning Responses And Side Effects\n\n### Static response\n\n```python\nimport httpx\nimport respx\n\n@respx.mock\ndef test_static_response():\n    respx.get(\"https://api.example.com/ping\").respond(204)\n\n    response = httpx.get(\"https://api.example.com/ping\")\n\n    assert response.status_code == 204\n```\n\n### Dynamic side effect\n\nUse a callback when the response depends on the incoming request:\n\n```python\nimport httpx\nimport respx\n\ndef echo_name(request: httpx.Request) -> httpx.Response:\n    payload = request.read().decode()\n    return httpx.Response(200, json={\"raw\": payload})\n\n@respx.mock\ndef test_dynamic_response():\n    respx.post(\"https://api.example.com/echo\").mock(side_effect=echo_name)\n\n    response = httpx.post(\"https://api.example.com/echo\", content=\"Ada\")\n\n    assert response.json() == {\"raw\": \"Ada\"}\n```\n\n### Sequential side effects\n\nYou can model retries or rate limits with an iterable:\n\n```python\nimport httpx\nimport respx\n\n@respx.mock\ndef test_retry_flow():\n    respx.get(\"https://api.example.com/data\").mock(\n        side_effect=[\n            httpx.Response(429),\n            httpx.Response(200, json={\"ok\": True}),\n        ]\n    )\n\n    first = httpx.get(\"https://api.example.com/data\")\n    second = httpx.get(\"https://api.example.com/data\")\n\n    assert first.status_code == 429\n    assert second.json() == {\"ok\": True}\n```\n\n## Configuration And Auth Notes\n\nRESPX itself has no credentials or auth configuration. The main configuration surface is the router:\n\n- `base_url` to avoid repeating the host for every route\n- `assert_all_mocked` to fail on unmatched requests\n- `assert_all_called` to fail when declared routes were never hit\n\nIf your application sends auth headers, tokens, or cookies through `httpx`, match them explicitly when they matter:\n\n```python\nimport httpx\nimport respx\n\n@respx.mock(base_url=\"https://api.example.com\")\ndef test_bearer_token():\n    respx.get(\n        \"/me\",\n        headers__contains={\"authorization\": \"Bearer test-token\"},\n    ).mock(return_value=httpx.Response(200, json={\"id\": \"me\"}))\n\n    response = httpx.get(\n        \"https://api.example.com/me\",\n        headers={\"authorization\": \"Bearer test-token\"},\n    )\n\n    assert response.json() == {\"id\": \"me\"}\n```\n\n## Common Pitfalls\n\n- `respx` mocks `httpx`, not `requests`. If the code under test uses `requests`, RESPX will never intercept it.\n- The API reference notes that the plain default router `respx.mock` has `assert_all_called` disabled unless you configure it. Set it explicitly when unused routes should fail the test.\n- If you disable `assert_all_mocked`, unmatched requests get an auto-generated `200 OK` response. That can hide missing mocks.\n- Very generic routes can shadow more specific ones. Add specific matches first and keep regexes tight.\n- Direct transports like `SyncMockTransport` or `AsyncMockTransport` do not give you the decorator/context-manager teardown around the whole test body, so assert on the returned route objects explicitly.\n- `pass_through()` sends the request to the real network. Only use it when an external call is intentional in the test.\n- RESPX call history is router state. Reset or recreate routers between tests instead of sharing mutable global routes.\n\n## Version-Sensitive Notes For `0.22.0`\n\n- `0.22.0` adds support for `httpx 0.28.0`.\n- `0.22.0` drops Python 3.7 support. Use Python 3.8+.\n- The docs site is mostly versionless. If a project is pinned to older RESPX or older HTTPX, check the GitHub release history before copying examples from the current docs.\n"
  },
  {
    "path": "content/retrying/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"retrying decorators for retry loops, backoff, and polling in synchronous Python code\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.4.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"retrying,retry,retries,python,decorators,backoff,polling\"\n---\n\n# retrying Python Package Guide\n\n## Golden Rule\n\nUse `retrying` to decorate your own synchronous functions when you need retry loops around transient failures or poll-until-ready workflows. The upstream README documents decorator-based usage only; there is no client object, auth flow, or package-specific environment configuration.\n\nThe most important default is easy to miss: if you call `@retry` with no arguments, the function retries forever with no wait between attempts.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"retrying==1.4.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"retrying==1.4.2\"\npoetry add \"retrying==1.4.2\"\n```\n\n`retrying 1.4.2` declares `Requires-Python >=3.6` on PyPI.\n\n## Core Model\n\nImport the decorator directly:\n\n```python\nfrom retrying import retry\n```\n\nThere is no initialization step. You control behavior with decorator keyword arguments:\n\n- Stop conditions such as `stop_max_attempt_number=...` and `stop_max_delay=...`\n- Wait strategies such as `wait_fixed=...`, `wait_random_min=...`, `wait_random_max=...`, `wait_exponential_multiplier=...`, and `wait_exponential_max=...`\n- Retry predicates such as `retry_on_exception=...` and `retry_on_result=...`\n\nImportant detail from the upstream examples: wait and delay values are in milliseconds.\n\n## Retry A Transient Exception\n\nUse `stop_max_attempt_number` with `wait_fixed` for the simplest bounded retry:\n\n```python\nimport requests\nfrom retrying import retry\n\n@retry(stop_max_attempt_number=5, wait_fixed=2000)\ndef fetch_json(url: str) -> dict:\n    response = requests.get(url, timeout=10)\n    response.raise_for_status()\n    return response.json()\n```\n\nThis makes up to five attempts and waits two seconds between failures.\n\n## Retry Only Selected Exceptions\n\nUse `retry_on_exception` when some failures are transient but others should stop immediately:\n\n```python\nimport requests\nfrom retrying import retry\n\ndef retry_if_connection_error(exc: Exception) -> bool:\n    return isinstance(\n        exc,\n        (requests.exceptions.ConnectionError, requests.exceptions.Timeout),\n    )\n\n@retry(\n    retry_on_exception=retry_if_connection_error,\n    stop_max_attempt_number=4,\n    wait_fixed=1000,\n)\ndef get_status(url: str) -> int:\n    response = requests.get(url, timeout=5)\n    response.raise_for_status()\n    return response.status_code\n```\n\nKeep the predicate narrow. If it returns `True`, `retrying` will retry that exception type.\n\n## Poll Until The Result Is Ready\n\nUse `retry_on_result` when the call succeeds but the result says \"not ready yet\":\n\n```python\nfrom retrying import retry\n\ndef retry_if_none(result) -> bool:\n    return result is None\n\n@retry(\n    retry_on_result=retry_if_none,\n    wait_fixed=1000,\n    stop_max_delay=10000,\n)\ndef load_report(report_store, report_id: str):\n    report = report_store.get(report_id)\n    if report is None or report[\"state\"] != \"ready\":\n        return None\n    return report\n```\n\nThis polls once per second and stops after about ten seconds total.\n\n## Exponential Backoff\n\nUse the exponential wait parameters when each retry should wait longer than the last:\n\n```python\nimport requests\nfrom retrying import retry\n\n@retry(\n    wait_exponential_multiplier=1000,\n    wait_exponential_max=10000,\n    stop_max_attempt_number=6,\n)\ndef fetch_text(url: str) -> str:\n    response = requests.get(url, timeout=10)\n    response.raise_for_status()\n    return response.text\n```\n\nThe upstream README describes this as sleeping `2^x * wait_exponential_multiplier` milliseconds between retries, capped by `wait_exponential_max`.\n\n## Common Pitfalls\n\n- `@retry` with no arguments retries forever and does not sleep between attempts.\n- Wait-related arguments use milliseconds, not seconds.\n- `retrying` wraps ordinary synchronous callables. The maintainer docs do not document asyncio usage.\n- `retry_on_result` is for return-value-based polling; your wrapped function should return a sentinel such as `None` when the work is not ready yet.\n- `wrap_exception=True` changes how errors are surfaced. Use it only if your calling code is prepared for `RetryError`.\n- `stop_max_delay` limits total retry time; `stop_max_attempt_number` limits the number of calls. Use one or both explicitly so retry behavior is bounded.\n\n## Version-Sensitive Notes\n\n- PyPI lists `1.4.2` as the current release, published on August 3, 2025.\n- PyPI metadata for `1.4.2` declares `Requires-Python >=3.6`.\n- The maintained project homepage for current releases is `https://github.com/groodt/retrying`. Older examples and search results may still point at the original `rholder/retrying` repository.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/groodt/retrying`\n- Maintainer README examples: `https://github.com/groodt/retrying/blob/master/README.rst`\n- PyPI project page: `https://pypi.org/project/retrying/`\n"
  },
  {
    "path": "content/rich/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Rich Python package guide for terminal formatting, tables, progress bars, logging, markdown, and tracebacks\"\nmetadata:\n  languages: \"python\"\n  versions: \"14.3.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"rich,python,terminal,cli,logging,progress,markdown\"\n---\n\n# Rich Python Package Guide\n\n## Golden Rule\n\nUse `rich` as a terminal rendering layer centered on `Console`, not as a grab bag of unrelated helpers. As of March 12, 2026, PyPI is at `14.3.3`, but the stable docs site still renders as `Rich 14.1.0 documentation`, so combine the stable guides with the upstream changelog for `14.3.x` behavior changes.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"rich==14.3.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"rich==14.3.3\"\npoetry add \"rich==14.3.3\"\n```\n\nOptional Jupyter extra:\n\n```bash\npython -m pip install \"rich[jupyter]==14.3.3\"\n```\n\nSanity-check terminal support:\n\n```bash\npython -m rich\n```\n\n## Initialize And Basic Setup\n\nFor one-off formatted output, `rich.print` is the fastest entry point:\n\n```python\nfrom rich import print\n\nprint(\"[bold green]Build passed[/bold green]\")\nprint({\"status\": \"ok\", \"items\": [1, 2, 3]})\n```\n\nFor anything non-trivial, create a shared `Console` instance and route output through it:\n\n```python\nfrom rich.console import Console\n\nconsole = Console()\nconsole.print(\"Hello, [bold magenta]Rich[/bold magenta]!\")\n```\n\nUse one shared console per output stream when possible. It keeps width detection, themes, recording, and progress rendering consistent.\n\n## Core Usage\n\n### Styled output, tables, and markdown\n\n```python\nfrom rich.console import Console\nfrom rich.markdown import Markdown\nfrom rich.table import Table\n\nconsole = Console()\n\ntable = Table(title=\"Deployments\", show_header=True, header_style=\"bold cyan\")\ntable.add_column(\"Service\")\ntable.add_column(\"Status\")\ntable.add_column(\"Latency\", justify=\"right\")\ntable.add_row(\"api\", \"[green]healthy[/green]\", \"43 ms\")\ntable.add_row(\"worker\", \"[yellow]degraded[/yellow]\", \"210 ms\")\n\nconsole.print(table)\nconsole.print(Markdown(\"## Notes\\nUse `Console` for multi-line output.\"))\n```\n\nRich markup is enabled by default on `Console.print()`. If your text contains literal square brackets from user input or logs, either escape it or disable markup for that call.\n\n### Logging and better tracebacks\n\nUse Rich's logging handler instead of manually colorizing log strings:\n\n```python\nimport logging\n\nfrom rich.logging import RichHandler\nfrom rich.traceback import install\n\ninstall(show_locals=True)\n\nlogging.basicConfig(\n    level=\"INFO\",\n    format=\"%(message)s\",\n    handlers=[RichHandler(rich_tracebacks=True)],\n)\n\nlog = logging.getLogger(\"app\")\nlog.info(\"server started\")\n```\n\n`RichHandler` integrates with the standard `logging` module. Keep `markup=False` unless you control the log message content, otherwise messages containing `[` and `]` can be interpreted as markup.\n\n### Progress bars and live status\n\nFor a single iterable, `track()` is the simplest choice:\n\n```python\nfrom rich.progress import track\n\nfor item in track(range(100), description=\"Processing\"):\n    process(item)\n```\n\nFor multiple tasks or custom columns, use `Progress`:\n\n```python\nfrom time import sleep\n\nfrom rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn\n\nwith Progress(\n    TextColumn(\"[progress.description]{task.description}\"),\n    BarColumn(),\n    TimeRemainingColumn(),\n    transient=True,\n) as progress:\n    task_id = progress.add_task(\"Uploading\", total=5)\n    for _ in range(5):\n        sleep(0.2)\n        progress.advance(task_id)\n```\n\nRich redirects `stdout` and `stderr` while a progress display is active so plain `print()` calls do not usually destroy the progress layout. Even so, prefer writing through the same `Console` or the `Progress` instance for predictable formatting.\n\n### Prompts and input\n\nUse the prompt helpers instead of hand-rolling validation:\n\n```python\nfrom rich.prompt import Confirm, IntPrompt, Prompt\n\nname = Prompt.ask(\"Project name\", default=\"demo\")\nretries = IntPrompt.ask(\"Retry count\", default=3)\ndeploy = Confirm.ask(\"Deploy now?\", default=False)\n```\n\n### Pretty-printing and debugging\n\nRich can improve the Python REPL and ad hoc object inspection:\n\n```python\nfrom rich import inspect, pretty\n\npretty.install()\n\ndata = {\"service\": \"api\", \"ports\": [8000, 8001]}\ninspect(data, methods=False)\n```\n\n## Configuration And Environment\n\nRich has no authentication model. Configuration is mostly terminal behavior and rendering defaults.\n\nUseful `Console` options:\n\n- `stderr=True`: send output to stderr instead of stdout\n- `force_terminal=True`: emit terminal control codes even when auto-detection says the output is not a TTY\n- `force_interactive=False`: disable interactive behaviors such as live animations\n- `record=True`: retain output so you can call `export_text()`, `export_svg()`, or `export_html()`\n- `soft_wrap=True`: disable cropping and let long text wrap naturally\n- `safe_box=True`: prefer legacy-safe box characters when output must render on old Windows terminals\n\nExample:\n\n```python\nfrom rich.console import Console\n\nconsole = Console(\n    stderr=True,\n    force_terminal=True,\n    force_interactive=False,\n    record=True,\n)\n\nconsole.print(\"[bold]Build report[/bold]\")\nhtml = console.export_html()\n```\n\nImportant environment variables from the console docs:\n\n- `NO_COLOR`: disables colors; it takes precedence over `FORCE_COLOR`\n- `FORCE_COLOR=1`: forces color output when Rich would otherwise disable it\n- `TTY_COMPATIBLE=1`: tells Rich the target can display terminal escape sequences\n- `TTY_INTERACTIVE=0`: disables interactive rendering such as animated progress bars\n- `COLUMNS` and `LINES`: override detected terminal size\n- `JUPYTER_COLUMNS` and `JUPYTER_LINES`: Jupyter-specific width and height defaults\n\nFor CI or GitHub Actions, the documented combination is:\n\n```bash\nexport TTY_COMPATIBLE=1\nexport TTY_INTERACTIVE=0\n```\n\n## Common Pitfalls\n\n- Do not mix `rich.print` and a separately configured `Console` indiscriminately. If your app depends on one theme, one output stream, or one recording buffer, use a shared `Console`.\n- Do not enable markup on untrusted text. Escape it first or call `console.print(text, markup=False)`.\n- `RichHandler` does not magically make file logs colorful. It is for terminal handlers; use plain structured logging for machine-readable log sinks.\n- If colors disappear in CI or when piping, set `force_terminal=True` or the `TTY_COMPATIBLE` and `TTY_INTERACTIVE` environment variables explicitly.\n- `record=True` is required before calling `export_text()`, `export_svg()`, or `export_html()`.\n- `safe_box=False` may render poorly on old Windows terminals that cannot display Unicode box-drawing characters correctly.\n- Progress and live displays are great for human-facing CLIs but usually wrong for non-interactive logs. Disable interactivity in CI.\n- Rich word-wraps output by default. If you are rendering preformatted text where spacing must remain exact, test with `soft_wrap`, `overflow`, or raw file output settings.\n\n## Version-Sensitive Notes For 14.3.x\n\n- PyPI currently publishes `14.3.3` from February 19, 2026. The stable docs site is still branded `14.1.0`, so patch-level behavior after `14.1.0` is better verified from the changelog.\n- `14.3.0` added better support for multi-codepoint glyphs, added the `UNICODE_VERSION` environment variable, exposed `locals_max_depth` and `locals_overflow` in `traceback.install()`, and changed Markdown header, table, and rule styling.\n- `14.3.1` through `14.3.3` fix Unicode-width and grapheme-splitting issues. If your CLI renders emoji, ZWJ sequences, or other complex Unicode, stay on `14.3.3` rather than copying behavior from older blog posts.\n- Since `14.1.0`, Live objects including `Progress` may be nested. If you see older guidance claiming nested live rendering is unsupported, that guidance is stale.\n\n## Canonical Sources\n\n- Stable docs: `https://rich.readthedocs.io/en/stable/`\n- Console docs: `https://rich.readthedocs.io/en/stable/console.html`\n- Progress docs: `https://rich.readthedocs.io/en/stable/progress.html`\n- Prompt docs: `https://rich.readthedocs.io/en/stable/prompt.html`\n- Logging docs: `https://rich.readthedocs.io/en/stable/logging.html`\n- Pretty docs: `https://rich.readthedocs.io/en/stable/pretty.html`\n- Traceback docs: `https://rich.readthedocs.io/en/stable/traceback.html`\n- PyPI package page: `https://pypi.org/project/rich/`\n- Upstream changelog: `https://github.com/Textualize/rich/blob/master/CHANGELOG.md`\n"
  },
  {
    "path": "content/rimraf/docs/rimraf/javascript/DOC.md",
    "content": "---\nname: rimraf\ndescription: \"JavaScript guide for `rimraf`, covering named imports, Promise-based deletion, CLI usage, glob opt-in, filters, and safe removal defaults.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.1.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"rimraf,javascript,node,filesystem,cli,deletion\"\n---\n\n# rimraf Guide for JavaScript\n\n## Golden Rule\n\nUse named exports from `rimraf`, prefer the async API in application code, and opt in to globbing only when you actually want pattern matching.\n\n`rimraf()` removes a path or an array of paths recursively and resolves to a boolean. `rimrafSync()` does the same work synchronously and returns a boolean directly.\n\nThere are no package-specific environment variables, credentials, or authentication steps.\n\n## Install\n\n```bash\nnpm install rimraf@6.1.3\n```\n\n`rimraf` is a Node.js package. You do not need to configure a client object before using it.\n\n## Imports and Initialization\n\n### ECMAScript modules\n\n```js\nimport { rimraf, rimrafSync, native, manual } from 'rimraf';\n```\n\n### CommonJS\n\n```js\nconst { rimraf, rimrafSync, native, manual } = require('rimraf');\n```\n\nUse named imports or named properties from `require()`. Do not rely on a default import.\n\n## Common Workflows\n\n### Remove build output asynchronously\n\nUse the async API by default. It accepts a single path or an array of paths.\n\n```js\nimport { rimraf } from 'rimraf';\n\nconst removed = await rimraf(['dist', 'coverage'], {\n  preserveRoot: true,\n});\n\nif (!removed) {\n  throw new Error('Some entries were kept by a filter.');\n}\n```\n\n### Remove a literal directory synchronously\n\nUse the sync API for short scripts or startup cleanup, not for the hot path of an app.\n\n```js\nimport { rimrafSync } from 'rimraf';\n\nconst removed = rimrafSync('.cache', {\n  preserveRoot: true,\n});\n\nconsole.log({ removed });\n```\n\n### Opt in to glob patterns\n\nGlobbing is not implicit. Set `glob: true` or pass a `glob` options object when you want pattern matching.\n\n```js\nimport { rimraf } from 'rimraf';\n\nawait rimraf('packages/*/dist', {\n  glob: true,\n});\n```\n\nIf you omit `glob`, the path is treated as a literal string.\n\n### Keep selected files with a filter\n\n`filter` lets you skip entries during deletion. When anything is kept, the return value can be `false` and parent directories may remain because they are no longer empty.\n\n```js\nimport { rimraf } from 'rimraf';\nimport { basename } from 'node:path';\n\nconst removed = await rimraf('build', {\n  filter: (entryPath) => basename(entryPath) !== '.gitkeep',\n});\n\nconsole.log({ removed });\n```\n\n### Cancel a long-running deletion\n\nPass an `AbortSignal` when you want to stop a large recursive delete.\n\n```js\nimport { rimraf } from 'rimraf';\n\nconst controller = new AbortController();\n\nsetTimeout(() => controller.abort(), 250);\n\nawait rimraf('tmp/large-tree', {\n  signal: controller.signal,\n});\n```\n\n### Force a specific implementation\n\n`rimraf()` chooses an implementation for you. If you need a specific strategy, call it explicitly.\n\n```js\nimport { native, manual } from 'rimraf';\n\nawait native('dist');\nawait manual('dist');\n```\n\nUse `native()` when you specifically want Node's built-in `fs.rm()` behavior. Use `manual()` when you want the JavaScript implementation chosen for the current platform.\n\n## CLI\n\nThe package also ships a CLI.\n\n```bash\nnpx rimraf dist coverage\nnpx rimraf --glob 'packages/*/dist'\nnpx rimraf --impl=manual .cache\n```\n\nUseful flags:\n\n- `--glob` or `--no-glob` to control pattern matching\n- `--impl=rimraf|native|manual|posix|windows|move-remove` to choose the implementation\n- `--preserve-root` or `--no-preserve-root` to control root-directory protection\n- `--` to stop option parsing before path arguments\n\nExample for a path that starts with `-`:\n\n```bash\nnpx rimraf -- --tmp-output\n```\n\n## Important Pitfalls\n\n### Use named exports\n\nCurrent `rimraf` releases export functions directly. Prefer:\n\n```js\nimport { rimraf } from 'rimraf';\n```\n\nnot:\n\n```js\nimport rimraf from 'rimraf';\n```\n\n### `glob` is opt-in\n\nThese two calls do different things:\n\n```js\nimport { rimraf } from 'rimraf';\n\nawait rimraf('build/*', { glob: true });\nawait rimraf('build/*');\n```\n\nThe first treats `build/*` as a pattern. The second treats it as a literal path string.\n\n### `filter` changes both behavior and return value\n\nIf your filter keeps any entry, `rimraf()` can resolve to `false`. Parent directories that still contain preserved entries are not removed.\n\n### `filter` and `signal` disable the native fast path\n\nWhen you pass `filter` or `signal`, `rimraf` cannot use Node's built-in `fs.rm()` implementation for that call because `fs.rm()` does not support those features.\n\n### Root deletion is protected by default\n\n`preserveRoot` is enabled unless you explicitly set `preserveRoot: false` or pass `--no-preserve-root` in the CLI.\n\n## Strategy Notes\n\nIf you need lower-level control, `rimraf` also exposes `posix()`, `windows()`, and `moveRemove()` alongside their sync variants.\n\n`moveRemove()` is the slowest strategy and is intended as a reliable Windows fallback. If you set `tmp` for that workflow, it must be on the same physical device as the path being deleted.\n"
  },
  {
    "path": "content/rollup/docs/rollup/javascript/DOC.md",
    "content": "---\nname: rollup\ndescription: \"JavaScript guide for installing Rollup 4, authoring a minimal config, using the CLI and JavaScript API, and handling watch mode and library externals.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.59.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"rollup,bundler,build,javascript,cli,node-api\"\n---\n\n# rollup for JavaScript\n\n`rollup` is the core bundler package. It provides the `rollup` CLI, config helpers such as `defineConfig`, and the JavaScript API for one-off builds, in-memory generation, and watch mode.\n\nThere is no authentication step and no required package-specific environment variable.\n\n## Prerequisites\n\n- Node.js. Use a current Node LTS for modern ESM-based build tooling.\n- `rollup@4.59.0`\n- Optional plugins such as TypeScript, CommonJS, or Node resolution plugins when your project needs them\n\n## Install\n\nInstall Rollup locally in the project that owns the build:\n\n```bash\nnpm install --save-dev rollup\n```\n\nRollup also supports a global install, but local project installs are easier to keep reproducible:\n\n```bash\nnpm install --global rollup\n```\n\n## Minimal project setup\n\nAdd scripts in `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"rollup -c\",\n    \"build:prod\": \"rollup -c --environment BUILD:production\",\n    \"watch\": \"rollup -c --watch\"\n  }\n}\n```\n\nCreate `rollup.config.mjs`:\n\n```javascript\nimport { defineConfig } from \"rollup\";\n\nconst isProduction = process.env.BUILD === \"production\";\n\nexport default defineConfig({\n  input: \"src/index.js\",\n  output: {\n    file: \"dist/bundle.js\",\n    format: \"es\",\n    sourcemap: !isProduction,\n  },\n});\n```\n\nCreate a matching entry file:\n\n```javascript\n// src/index.js\nexport function greet(name) {\n  return `Hello, ${name}`;\n}\n\nconsole.log(greet(\"Rollup\"));\n```\n\nRun the build:\n\n```bash\nnpm run build\n```\n\nIf you run `rollup -c` without a filename, Rollup looks for config files in this order: `rollup.config.mjs`, `rollup.config.cjs`, then `rollup.config.js`.\n\n## Run from the CLI\n\nFor simple bundles, you can skip the config file and pass options directly:\n\n```bash\nnpx rollup src/index.js --format es --file dist/bundle.js --sourcemap\n```\n\nCommon output formats:\n\n```bash\n# CommonJS output for Node.js consumers\nnpx rollup src/index.js --format cjs --file dist/bundle.cjs\n\n# Browser bundle that exposes a global name\nnpx rollup src/index.js --format iife --name MyBundle --file dist/bundle.iife.js\n\n# UMD bundle for browsers and module loaders\nnpx rollup src/index.js --format umd --name MyBundle --file dist/bundle.umd.js\n```\n\nFor config-driven builds, `--environment` sets variables on `process.env` inside the config file:\n\n```bash\nnpx rollup -c --environment INCLUDE_DEPS,BUILD:production\n```\n\nWith that command, `process.env.INCLUDE_DEPS === \"true\"` and `process.env.BUILD === \"production\"` inside `rollup.config.*`.\n\n## Use the JavaScript API\n\nUse `rollup(...)` when your app, dev server, or custom tool needs to control bundling directly.\n\n```javascript\nimport { rollup } from \"rollup\";\n\nconst bundle = await rollup({\n  input: \"src/index.js\",\n});\n\ntry {\n  await bundle.write({\n    file: \"dist/bundle.js\",\n    format: \"es\",\n    sourcemap: true,\n  });\n} finally {\n  await bundle.close();\n}\n```\n\n`bundle.write(...)` writes files to disk. Use `bundle.generate(...)` when you need the generated chunks and assets in memory instead:\n\n```javascript\nimport { rollup } from \"rollup\";\n\nconst bundle = await rollup({\n  input: \"src/index.js\",\n});\n\ntry {\n  const { output } = await bundle.generate({\n    format: \"es\",\n    sourcemap: true,\n  });\n\n  for (const item of output) {\n    if (item.type === \"chunk\") {\n      console.log(item.fileName, item.code.length);\n    } else {\n      console.log(item.fileName, item.source);\n    }\n  }\n} finally {\n  await bundle.close();\n}\n```\n\n## Watch builds from Node\n\nUse `watch(...)` when another Node process should manage rebuilds.\n\n```javascript\nimport { watch } from \"rollup\";\n\nconst watcher = watch({\n  input: \"src/index.js\",\n  output: {\n    file: \"dist/bundle.js\",\n    format: \"es\",\n    sourcemap: true,\n  },\n  watch: {\n    buildDelay: 200,\n  },\n});\n\nwatcher.on(\"event\", async (event) => {\n  switch (event.code) {\n    case \"START\":\n      console.log(\"starting build\");\n      break;\n    case \"BUNDLE_START\":\n      console.log(\"bundling\", event.output);\n      break;\n    case \"BUNDLE_END\":\n      console.log(`built in ${event.duration}ms`);\n      break;\n    case \"ERROR\":\n      console.error(event.error);\n      break;\n    case \"END\":\n      console.log(\"waiting for changes\");\n      break;\n  }\n\n  if (\"result\" in event && event.result) {\n    await event.result.close();\n  }\n});\n\nprocess.on(\"SIGINT\", async () => {\n  await watcher.close();\n  process.exit(0);\n});\n```\n\nThe watcher emits `START`, `BUNDLE_START`, `BUNDLE_END`, `END`, and `ERROR` events.\n\n## Common workflow: library build with externals\n\nFor libraries, mark peer dependencies or runtime-provided packages as external so they are not bundled.\n\n```javascript\nimport { defineConfig } from \"rollup\";\n\nexport default defineConfig({\n  input: \"src/index.js\",\n  external: [\"react\"],\n  output: {\n    file: \"dist/my-library.umd.js\",\n    format: \"umd\",\n    name: \"MyLibrary\",\n    globals: {\n      react: \"React\",\n    },\n    sourcemap: true,\n  },\n});\n```\n\nFor UMD and IIFE browser builds that expose exports, set `output.name` or pass `--name` on the CLI.\n\n## Important pitfalls\n\n- Use `output.file` for a single bundle and `output.dir` when Rollup needs to emit multiple chunks.\n- Call `await bundle.close()` after JavaScript API builds so plugins and file handles can clean up.\n- In watch mode, keep the watcher handle and call `await watcher.close()` during shutdown.\n- When handling `BUNDLE_END` events programmatically, close `event.result` after you are done with it.\n- When you pipe bundle output to stdout, only inline sourcemaps are supported.\n- `--environment` affects the config file process, not application code unless you inject values into the bundle yourself.\n\n## Version notes\n\n- This guide targets `rollup@4.59.0`.\n- The package exports `defineConfig`, `rollup`, and `watch` from `rollup`.\n- The package also exports `rollup/loadConfigFile`, `rollup/getLogFilter`, and `rollup/parseAst` as subpaths for tooling integrations.\n"
  },
  {
    "path": "content/rpds-py/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"rpds-py guide for immutable HashTrieMap, HashTrieSet, List, and Queue types in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.30.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"rpds-py,rpds,python,immutable,persistent-data-structures\"\n---\n\n# rpds-py Python Package Guide\n\n## Golden Rule\n\nInstall `rpds-py`, but import from `rpds`:\n\n```python\nfrom rpds import HashTrieMap, HashTrieSet, List, Queue\n```\n\n`rpds-py` provides immutable persistent data structures. Methods that look like updates return new values; they do not modify the original structure in place.\n\n## Install\n\n`rpds-py 0.30.0` on PyPI requires Python 3.10 or newer.\n\n```bash\npython -m pip install \"rpds-py==0.30.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"rpds-py==0.30.0\"\npoetry add \"rpds-py==0.30.0\"\n```\n\nIf a wheel is not available for your platform, building from source requires a Rust toolchain.\n\n## Initialization And Environment\n\nThere are no environment variables, credentials, or client objects to configure. Import the structure you need and create values directly:\n\n```python\nfrom rpds import HashTrieMap, HashTrieSet, List, Queue\n\nsettings = HashTrieMap({\"timeout\": 10, \"region\": \"us-west-2\"})\ntags = HashTrieSet([\"draft\", \"internal\"])\nstack = List()\njobs = Queue()\n```\n\n## Common Workflows\n\n### HashTrieMap\n\nUse `HashTrieMap` when you want immutable dictionary-like updates with structural sharing.\n\n```python\nfrom rpds import HashTrieMap\n\nconfig = HashTrieMap({\"timeout\": 10, \"region\": \"us-west-2\"})\n\nconfig2 = config.insert(\"retries\", 3)\nconfig3 = config2.update({\"timeout\": 30, \"endpoint\": \"https://api.example.com\"})\nconfig4 = config3.discard(\"region\")\n\ntimeout = config3[\"timeout\"]\nendpoint = config3.get(\"endpoint\")\n\nprint(dict(config3))\n```\n\n### HashTrieSet\n\nUse `HashTrieSet` for immutable set membership and add/remove flows.\n\n```python\nfrom rpds import HashTrieSet\n\nfeatures = HashTrieSet([\"billing\", \"search\"])\n\nfeatures = features.insert(\"audit-log\")\nfeatures = features.update([\"exports\", \"webhooks\"])\nfeatures = features.discard(\"search\")\n\nif \"billing\" in features:\n    print(\"billing enabled\")\n\nprint(set(features))\n```\n\n### List\n\n`List` is a persistent linked list. It is most natural for stack-style operations at the front.\n\n```python\nfrom rpds import List as RPDSList\n\nstack = RPDSList()\nstack = stack.push_front(\"third\")\nstack = stack.push_front(\"second\")\nstack = stack.push_front(\"first\")\n\nhead = stack.first\ntail = stack.drop_first()\n\nprint(head)\nprint(list(stack))\n```\n\nAlias the import if you also use Python's built-in `list`.\n\n### Queue\n\nUse `Queue` for FIFO workflows.\n\n```python\nfrom rpds import Queue\n\njobs = Queue()\njobs = jobs.enqueue(\"resize-image\")\njobs = jobs.enqueue(\"send-email\")\n\nnext_job = jobs.peek\n\nif not jobs.is_empty:\n    jobs = jobs.dequeue()\n\nprint(next_job)\nprint(list(jobs))\n```\n\n## Converting Back To Built-Ins\n\nConvert explicitly before handing values to code that expects standard Python containers:\n\n```python\nfrom rpds import HashTrieMap, HashTrieSet, List as RPDSList, Queue\n\nmapping = HashTrieMap({\"a\": 1, \"b\": 2})\ntags = HashTrieSet([\"x\", \"y\"])\nstack = RPDSList().push_front(\"b\").push_front(\"a\")\njobs = Queue().enqueue(\"first\").enqueue(\"second\")\n\nplain_dict = dict(mapping)\nplain_set = set(tags)\nplain_list = list(stack)\nplain_queue = list(jobs)\n```\n\n## Common Pitfalls\n\n- The distribution name is `rpds-py`, but the import path is `rpds`.\n- Every update returns a new structure. If you do not reassign the result, your change is lost.\n- `List` is not a drop-in replacement for Python's built-in `list`; use it when front-of-list operations and immutability matter.\n- The hosted docs site currently shows `0.18.1`, while PyPI publishes `0.30.0`. For install requirements and release version, trust the PyPI page for `0.30.0`; for the core API surface, cross-check the maintainer docs and source stubs.\n- PyPI metadata for `0.30.0` requires Python 3.10+, while the current source repository has already moved its development branch to Python 3.9+. Do not lower your runtime requirement unless you are targeting a release that actually publishes that change.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/rpds-py/0.30.0/\n- Maintainer repository: https://github.com/crate-py/rpds\n- README and packaging metadata in source: https://github.com/crate-py/rpds/tree/main\n- Hosted API docs: https://rpds.readthedocs.io/en/latest/\n"
  },
  {
    "path": "content/rq/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"rq package guide for Python background jobs with Redis or Valkey queues, workers, retries, scheduling, and 2.7.0 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"rq,redis,valkey,queue,background-jobs,worker,scheduler\"\n---\n\n# RQ Python Package Guide\n\n## Golden Rule\n\nUse `rq` when you want a small, explicit Redis- or Valkey-backed background job system in pure Python. Pass Redis connections explicitly to `Queue` and `Worker`, keep job functions importable by workers, and enable the scheduler whenever you rely on delayed jobs, repeated jobs, or retry intervals.\n\n## When To Use RQ\n\nReach for `rq` when:\n\n- your app is already comfortable depending on Redis or Valkey\n- jobs are plain Python functions and you do not need a large task orchestration layer\n- you want a separate worker process model instead of `asyncio` background tasks inside the web process\n- you want straightforward CLI and code APIs for enqueueing, retries, results, and simple scheduling\n\nRQ is usually a better fit than a heavier queue system when you want \"push a Python function onto a queue and let workers run it\" with minimal framework machinery.\n\n## Install\n\nInstall the package version your project expects:\n\n```bash\npython -m pip install \"rq==2.7.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"rq==2.7.0\"\npoetry add \"rq==2.7.0\"\n```\n\nRuntime prerequisites:\n\n- a running Redis or Valkey server\n- network access from producers and workers to that backend\n- the same application code available to the process that enqueues jobs and the process that runs workers\n\n## Basic Setup\n\nRQ does not handle application auth itself. The important configuration is the Redis or Valkey connection that backs your queues and workers.\n\nUse one explicit connection object and pass it everywhere:\n\n```python\nimport os\n\nfrom redis import Redis\nfrom rq import Queue\n\nredis_url = os.getenv(\"RQ_REDIS_URL\", \"redis://localhost:6379/0\")\nredis_conn = Redis.from_url(redis_url)\n\nqueue = Queue(\"default\", connection=redis_conn)\n```\n\nMinimal task module:\n\n```python\n# tasks.py\nimport requests\n\ndef fetch_status(url: str) -> int:\n    response = requests.get(url, timeout=10)\n    response.raise_for_status()\n    return response.status_code\n```\n\nProducer code:\n\n```python\nfrom redis import Redis\nfrom rq import Queue\n\nfrom tasks import fetch_status\n\nredis_conn = Redis.from_url(\"redis://localhost:6379/0\")\nqueue = Queue(\"default\", connection=redis_conn)\n\njob = queue.enqueue(fetch_status, \"https://python-rq.org\")\nprint(job.id)\n```\n\nStart a worker from the project directory so imports resolve the same way they do for your app:\n\n```bash\nrq worker default --url redis://localhost:6379/0\n```\n\nProgrammatic worker setup:\n\n```python\nfrom redis import Redis\nfrom rq import Queue, Worker\n\nredis_conn = Redis.from_url(\"redis://localhost:6379/0\")\nqueue = Queue(\"default\", connection=redis_conn)\nworker = Worker([queue], connection=redis_conn)\nworker.work()\n```\n\n## Core Usage\n\n### Enqueue jobs\n\nThe basic API is `queue.enqueue(callable, *args, **kwargs)`:\n\n```python\njob = queue.enqueue(fetch_status, \"https://python-rq.org\")\nprint(job.id)\n```\n\nUseful enqueue options from the official docs:\n\n- `job_timeout`: max runtime before the worker marks the job failed\n- `result_ttl`: how long successful job results stay in Redis, default `500`\n- `ttl`: max time a queued job may sit before it is discarded\n- `failure_ttl`: how long failed jobs stay in Redis, default `1 year`\n- `depends_on`: job or jobs that must complete first\n- `job_id`: stable custom job id\n- `at_front`: prioritize within a queue\n- `on_success`, `on_failure`, `on_stopped`: callbacks\n\nExample:\n\n```python\njob = queue.enqueue(\n    fetch_status,\n    \"https://python-rq.org\",\n    job_timeout=\"30s\",\n    result_ttl=3600,\n    failure_ttl=86400,\n    job_id=\"fetch-python-rq-homepage\",\n)\n```\n\n### Use multiple queues for priority\n\nRQ treats queue order as priority order for a worker:\n\n```python\nhigh = Queue(\"high\", connection=redis_conn)\ndefault = Queue(\"default\", connection=redis_conn)\nlow = Queue(\"low\", connection=redis_conn)\n\nhigh.enqueue(fetch_status, \"https://python-rq.org/docs/\")\nlow.enqueue(fetch_status, \"https://example.com\")\n```\n\n```bash\nrq worker high default low --url redis://localhost:6379/0\n```\n\nIf you want fair queue selection instead of strict priority, RQ also ships `RoundRobinWorker` and `RandomWorker`.\n\n### Fetch results and job state\n\nIn modern RQ, prefer `job.return_value()` and `job.latest_result()`:\n\n```python\nfrom rq.job import Job\n\njob = Job.fetch(job.id, connection=redis_conn)\nresult = job.latest_result()\n\nif result and result.type == result.Type.SUCCESSFUL:\n    print(result.return_value)\nelif result and result.type == result.Type.FAILED:\n    print(result.exc_string)\n```\n\nBlock for a result when needed:\n\n```python\nresult = job.latest_result(timeout=60)\nif result is not None:\n    print(result.type, result.return_value)\n```\n\nUse `job.results()` when a job may execute multiple times. RQ keeps up to the 10 latest execution results.\n\n### Retries\n\nRetry exceptions with `Retry(...)`:\n\n```python\nfrom rq import Retry\n\nqueue.enqueue(\n    fetch_status,\n    \"https://python-rq.org\",\n    retry=Retry(max=3, interval=[10, 30, 60]),\n)\n```\n\nImportant behavior:\n\n- `Retry(max=3)` retries immediately after failures\n- `Retry(max=3, interval=60)` or an interval list requires workers running with `--with-scheduler`\n\nRQ also supports returning `Retry(...)` from job code for application-level retry decisions:\n\n```python\nimport requests\nfrom rq import Retry\n\ndef fetch_with_soft_retry(url: str, max_attempts: int = 3):\n    try:\n        response = requests.get(url, timeout=10)\n        response.raise_for_status()\n        return response.text\n    except requests.exceptions.ConnectionError:\n        return Retry(max=max_attempts, interval=60)\n```\n\n### Schedule delayed and repeated jobs\n\nDelayed jobs:\n\n```python\nfrom datetime import datetime, timedelta\n\nqueue.enqueue_in(timedelta(minutes=5), fetch_status, \"https://python-rq.org/docs/\")\nqueue.enqueue_at(datetime(2026, 3, 12, 18, 0), fetch_status, \"https://python-rq.org/\")\n```\n\nRepeated jobs:\n\n```python\nfrom rq import Repeat\n\nqueue.enqueue(\n    fetch_status,\n    \"https://python-rq.org/docs/\",\n    repeat=Repeat(times=3, interval=[5, 10, 30]),\n)\n```\n\nImportant behavior:\n\n- scheduled jobs live in `ScheduledJobRegistry` until they are due\n- repeated jobs only repeat after successful completion\n- scheduling and repeating require workers started with `--with-scheduler`\n\nScheduler-enabled worker:\n\n```bash\nrq worker default --with-scheduler --url redis://localhost:6379/0\n```\n\nProgrammatic equivalent:\n\n```python\nif __name__ == \"__main__\":\n    worker = Worker([queue], connection=redis_conn)\n    worker.work(with_scheduler=True)\n```\n\nThat `if __name__ == \"__main__\"` guard matters when scheduler support is enabled because the scheduler uses a separate process.\n\n### Cron-style recurring enqueueing\n\nFor recurring jobs that should be registered outside normal queue producers, use RQ's built-in cron support:\n\n```python\n# cron_config.py\nfrom rq import cron\n\nfrom tasks import fetch_status\n\ncron.register(\n    fetch_status,\n    queue_name=\"maintenance\",\n    args=(\"https://python-rq.org/health\",),\n    cron=\"*/15 * * * *\",\n    job_timeout=30,\n    result_ttl=3600,\n)\n```\n\nRun it:\n\n```bash\nrq cron cron_config.py --url redis://localhost:6379/0\n```\n\nUse cron support when you want a dedicated scheduler process that enqueues recurring jobs; use `Repeat` when the next run should be chained off a job's own successful completion.\n\n## Worker Selection\n\nDefault production worker:\n\n- `Worker`: normal process-isolated execution\n\nUseful alternatives:\n\n- `SpawnWorker`: uses `os.spawn()` instead of `fork()`, useful on Windows or newer macOS environments where `fork()` is a problem\n- `SimpleWorker`: runs jobs in-process, useful for tests and debugging, but not recommended for normal production workloads because it has less isolation and no periodic heartbeat during job execution\n- `WorkerPool`: convenient CLI wrapper to launch multiple workers in one command\n\nExamples:\n\n```bash\nrq worker default --url redis://localhost:6379/0\nrq worker -w rq.worker.SpawnWorker default --url redis://localhost:6379/0\nrq worker-pool high default low -n 3 --url redis://localhost:6379/0\n```\n\n## Configuration Notes\n\n### Prefer explicit connections\n\nThe current docs recommend passing `connection=` explicitly to queues, workers, and jobs:\n\n```python\nredis_conn = Redis.from_url(\"redis://localhost:6379/0\")\nqueue = Queue(\"default\", connection=redis_conn)\nworker = Worker([queue], connection=redis_conn)\n```\n\nDo not build new code around the old `Connection` context manager. The connections docs mark it as deprecated.\n\n### Redis client options that matter\n\nCommon connection details belong in the Redis client, not in RQ:\n\n```python\nfrom redis import Redis\n\nredis_conn = Redis.from_url(\n    \"rediss://user:password@example.cache.local:6379/0\",\n    socket_timeout=500,\n)\n```\n\nPractical notes from the official docs:\n\n- if you set `socket_timeout` manually, keep it higher than the worker's dequeue timeout or workers can trip `TimeoutError`\n- `decode_responses=True` is not supported by RQ\n- Sentinel setups are supported, but the configuration lives at the Redis connection layer and RQ config layer rather than a separate RQ auth system\n\n### Serializer and custom classes\n\nRQ defaults to pickle serialization. If you switch to a custom serializer or custom `Job` / `Queue` classes, use the same serializer and classes on both the enqueueing side and the worker side.\n\n## Testing Patterns\n\n### Fast synchronous tests\n\nUse `is_async=False` when you want queue semantics without running a worker:\n\n```python\nfrom redis import Redis\nfrom rq import Queue\n\ntest_conn = Redis.from_url(\"redis://localhost:6379/15\")\nqueue = Queue(is_async=False, connection=test_conn)\njob = queue.enqueue(fetch_status, \"https://python-rq.org\")\nassert job.is_finished\n```\n\nUse a disposable Redis database or test instance so one test run does not leak state into another.\n\n### Worker-based tests\n\nUse `SimpleWorker` inside tests when the default worker's `fork()` behavior conflicts with the test environment:\n\n```python\nfrom redis import Redis\nfrom rq import Queue, SimpleWorker\n\nconn = Redis.from_url(\"redis://localhost:6379/15\")\nqueue = Queue(connection=conn)\nqueue.enqueue(fetch_status, \"https://python-rq.org\")\n\nworker = SimpleWorker([queue], connection=conn)\nworker.work(burst=True)\n```\n\nOn Windows test environments, the docs recommend subclassing `SimpleWorker` to use `TimerDeathPenalty`.\n\n## Common Pitfalls\n\n- Enqueued callables must be importable by workers. Do not enqueue functions defined only in `__main__`, and do not rely on request-local or process-local state.\n- Workers and producers must run the same code version. If you deploy new producer code before workers are updated, imports or argument shapes can drift.\n- Delayed jobs, repeated jobs, and retry intervals do not work correctly unless the scheduler component is running.\n- `SimpleWorker` is for testing, debugging, and niche cases. Use `Worker` or `SpawnWorker` for normal production isolation.\n- `job.result` appears in older examples, but the modern docs point to `job.return_value()` and `job.latest_result()`.\n- Result data expires by default after `500` seconds. If you need longer-lived inspection, set `result_ttl` deliberately.\n- Failed jobs stay around for a long time by default (`failure_ttl` defaults to one year). Set a lower value if that retention is too expensive for your Redis footprint.\n- `decode_responses=True` on the Redis client is not supported.\n- The old `Connection` context manager is deprecated; prefer explicit `connection=` wiring.\n- `CronScheduler` is still marked beta in the official docs. Treat it as useful but newer than the core queue and worker APIs.\n\n## Version-Sensitive Notes For `2.7.0`\n\n- `2.7.0` formally supports Python 3.14.\n- `2.7.0` improves `CronScheduler` monitoring so each cron job exposes better latest and next scheduled enqueue visibility.\n- `2.7.0` fixes `job.get_status()` inside `on_success` and `on_failure` callbacks so callback code sees the correct final state.\n- `2.5.0` added cron-string support to `CronScheduler`; older 2.4 examples may only show interval-based scheduling.\n- `2.4.0` introduced the `rq cron` CLI command and raised the package baseline to Python `>=3.9`.\n- `2.3.0` added official Valkey support and repeat jobs.\n- `2.2.0` added `SpawnWorker`, which matters if you need Windows-compatible worker execution.\n"
  },
  {
    "path": "content/rsa/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"rsa package guide for Python projects using the archived Python-RSA 4.x API\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.9.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"rsa,python,cryptography,signing,encryption,pem\"\n---\n\n# rsa Python Package Guide\n\n## Golden Rule\n\nUse the official `rsa` package for the archived Python-RSA 4.x API, and treat it as a PKCS#1 v1.5 toolkit for key generation, encryption/decryption, and detached signatures.\n\nThis library is pure Python, has no client object, and does not read environment variables itself. You import `rsa`, then generate or load keys and call the module functions directly.\n\nThe maintainer has archived the project on PyPI and GitHub. The public docs site is still published as Python-RSA 4.8, while PyPI's latest release is `4.9.1`.\n\n## Install\n\nUse a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"rsa==4.9.1\"\n```\n\n`pip install rsa` also installs the dependency needed for loading and saving PEM or DER keys.\n\n## Initialization\n\nThere is no SDK client to configure. Start by importing the package and either generating keys or loading existing PEM/DER files:\n\n```python\nimport rsa\n```\n\n## Generate And Save Keys\n\n`rsa.newkeys()` returns `(public_key, private_key)`. The docs note that larger keys take much longer to generate; if key generation is too slow, the maintainer recommends generating keys with OpenSSL and then loading them in Python.\n\n```python\nimport rsa\n\npublic_key, private_key = rsa.newkeys(2048)\n\nwith open(\"public.pem\", \"wb\") as public_file:\n    public_file.write(public_key.save_pkcs1(\"PEM\"))\n\nwith open(\"private.pem\", \"wb\") as private_file:\n    private_file.write(private_key.save_pkcs1(\"PEM\"))\n```\n\nTo load keys back from disk:\n\n```python\nimport rsa\n\nwith open(\"public.pem\", \"rb\") as public_file:\n    public_key = rsa.PublicKey.load_pkcs1(public_file.read())\n\nwith open(\"private.pem\", \"rb\") as private_file:\n    private_key = rsa.PrivateKey.load_pkcs1(private_file.read())\n```\n\n## Encrypt And Decrypt\n\n`rsa.encrypt()` and `rsa.decrypt()` operate on `bytes`, not Python strings. Encode text before encrypting and decode after decrypting.\n\n```python\nimport rsa\n\nwith open(\"public.pem\", \"rb\") as public_file:\n    public_key = rsa.PublicKey.load_pkcs1(public_file.read())\n\nwith open(\"private.pem\", \"rb\") as private_file:\n    private_key = rsa.PrivateKey.load_pkcs1(private_file.read())\n\nmessage = \"hello Bob!\".encode(\"utf-8\")\nciphertext = rsa.encrypt(message, public_key)\nplaintext = rsa.decrypt(ciphertext, private_key)\n\nprint(plaintext.decode(\"utf-8\"))\n```\n\nIf decryption fails, `rsa.decrypt()` raises `rsa.pkcs1.DecryptionError`. Catch that exception and return a generic failure instead of exposing a traceback:\n\n```python\nimport rsa\n\ntry:\n    plaintext = rsa.decrypt(ciphertext, private_key)\nexcept rsa.pkcs1.DecryptionError:\n    plaintext = None\n```\n\n## Sign And Verify\n\nUse `rsa.sign()` for detached signatures and `rsa.verify()` to confirm the message and recover the hash name used in the signature.\n\n```python\nimport rsa\n\nmessage = b\"ship release 2026-03-13\"\nsignature = rsa.sign(message, private_key, \"SHA-256\")\n\nhash_name = rsa.verify(message, signature, public_key)\nprint(hash_name)  # \"SHA-256\"\n```\n\nHandle signature failures with `rsa.pkcs1.VerificationError` and avoid printing the traceback:\n\n```python\nimport rsa\n\ntry:\n    rsa.verify(message, signature, public_key)\nexcept rsa.pkcs1.VerificationError:\n    is_valid = False\nelse:\n    is_valid = True\n```\n\nFor large files, `rsa.sign()` and `rsa.verify()` also accept file-like objects:\n\n```python\nimport rsa\n\nwith open(\"artifact.tar.gz\", \"rb\") as artifact:\n    signature = rsa.sign(artifact, private_key, \"SHA-256\")\n\nwith open(\"artifact.tar.gz\", \"rb\") as artifact:\n    rsa.verify(artifact, signature, public_key)\n```\n\nIf you need to hash elsewhere and sign later, use `rsa.compute_hash()` plus `rsa.sign_hash()`.\n\n## OpenSSL And PKCS#8 Interop\n\nPython-RSA stores keys as PKCS#1 PEM or DER. If you already have OpenSSL-generated material, use the documented conversion and loading paths instead of guessing at formats.\n\nOpenSSL public keys that start with `BEGIN PUBLIC KEY` should be loaded with `load_pkcs1_openssl_pem()`:\n\n```python\nimport rsa\n\nwith open(\"openssl-public.pem\", \"rb\") as public_file:\n    public_key = rsa.PublicKey.load_pkcs1_openssl_pem(public_file.read())\n```\n\nIf you have an OpenSSL private key and want a Python-RSA-compatible public key, the maintainer docs use:\n\n```bash\npyrsa-priv2pub -i myprivatekey.pem -o mypublickey.pem\n```\n\nPKCS#8 private keys are not loaded directly by Python-RSA. Convert them first:\n\n```bash\nopenssl rsa -in privatekey-pkcs8.pem -out privatekey.pem\n```\n\nThen load the converted file with `rsa.PrivateKey.load_pkcs1(...)`.\n\n## Common Pitfalls\n\n- `rsa.encrypt()`, `rsa.decrypt()`, `rsa.sign()`, and `rsa.verify()` work with bytes or file-like objects, not Python text strings.\n- RSA can only encrypt messages smaller than the key size minus PKCS#1 padding overhead. For larger payloads, the maintainer docs recommend hybrid encryption: encrypt the payload with a symmetric cipher such as AES, then encrypt that random symmetric key with RSA.\n- Python-RSA does not implement the AES part of that hybrid flow for you.\n- `VARBLOCK` helpers and `encrypt_bigfile()` / `decrypt_bigfile()` were deprecated and removed in Python-RSA 4.0. Do not build new code around them.\n- The project documentation explicitly warns not to display the traceback for `DecryptionError` or `VerificationError`, because it leaks information about the key.\n- The package is archived. Prefer very conservative usage and verify whether a maintained alternative is more appropriate before introducing it into a new security-sensitive system.\n\n## Version-Sensitive Notes\n\n- PyPI lists `rsa 4.9.1` as the latest release and marks the project as archived.\n- PyPI declares Python support as `>=3.6,<4`.\n- The maintainer documentation site is still published as Python-RSA 4.8. The API calls shown in this guide are taken from that maintainer documentation and the archived project metadata for the 4.x line.\n- Python-RSA implements PKCS#1 v1.5 encryption and signatures. It is not an OAEP or PSS wrapper.\n- The project README and PyPI page both warn that a pure-Python RSA implementation is difficult or impossible to make secure against timing attacks, so use it with care.\n\n## Official Sources\n\n- Maintainer docs root: https://stuvel.eu/python-rsa-doc/\n- Installation: https://stuvel.eu/python-rsa-doc/installation.html\n- Usage: https://stuvel.eu/python-rsa-doc/usage.html\n- Compatibility and OpenSSL / PKCS#8 interop: https://stuvel.eu/python-rsa-doc/compatibility.html\n- API reference: https://stuvel.eu/python-rsa-doc/reference.html\n- PyPI package page: https://pypi.org/project/rsa/4.9.1/\n- Archived repository: https://github.com/sybrenstuvel/python-rsa\n"
  },
  {
    "path": "content/ruff/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Ruff package guide for Python projects using the official Ruff docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.15.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ruff,python,linter,formatter,quality,pre-commit\"\n---\n\n# Ruff Python Package Guide\n\n## Golden Rule\n\nUse `ruff` as a project tool, not as a runtime library. Put configuration in `pyproject.toml` unless you have a strong reason to keep a separate `ruff.toml`, run `ruff check` before `ruff format`, and keep the enabled rule set explicit instead of turning on every rule at once.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"ruff==0.15.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"ruff==0.15.5\"\npoetry add --group dev \"ruff==0.15.5\"\n```\n\nTool-only install:\n\n```bash\nuv tool install \"ruff==0.15.5\"\npipx install \"ruff==0.15.5\"\n```\n\nConfirm the binary:\n\n```bash\nruff --version\n```\n\n## Initialize And Configure\n\nRuff reads configuration from the closest supported config file. Prefer `pyproject.toml` with a `[tool.ruff]` table so the project config stays in one place.\n\nMinimal starting point:\n\n```toml\n[tool.ruff]\nline-length = 100\ntarget-version = \"py311\"\n\n[tool.ruff.lint]\nselect = [\"E\", \"F\", \"I\", \"UP\"]\n\n[tool.ruff.format]\nquote-style = \"double\"\nindent-style = \"space\"\n```\n\nUseful setup command:\n\n```bash\nruff config\n```\n\nThat prints the available configuration keys for the installed version.\n\n## Core Workflow\n\n### Lint the repository\n\n```bash\nruff check .\n```\n\n### Apply safe auto-fixes\n\n```bash\nruff check . --fix\n```\n\nRuff distinguishes between safe fixes and unsafe fixes. Keep unsafe fixes opt-in:\n\n```bash\nruff check . --fix --unsafe-fixes\n```\n\n### Format code\n\n```bash\nruff format .\n```\n\n### Recommended CI order\n\n```bash\nruff check . --fix\nruff format .\n```\n\nIf you rely on import sorting, keep `I` enabled in lint rules. The formatter does not replace lint-driven import organization.\n\n### Inspect a specific rule\n\n```bash\nruff rule F401\nruff rule B008\n```\n\nThis is the fastest way to verify what a rule means before changing code to satisfy it.\n\n## Editor And Automation Setup\n\n### VS Code and LSP-style editor integration\n\nPrefer Ruff's built-in language server support over `ruff-lsp`. The official docs describe the native server as the direct replacement, and it has been stable since the `0.5.x` line.\n\nCommon editor flow:\n\n1. Install the `ruff` binary in the environment your editor can see.\n2. Enable Ruff linting and formatting in the editor extension.\n3. Disable `ruff-lsp` if it is still installed, to avoid duplicate diagnostics.\n\n### pre-commit\n\nUse the official `ruff-pre-commit` hooks:\n\n```yaml\nrepos:\n  - repo: https://github.com/astral-sh/ruff-pre-commit\n    rev: v0.15.5\n    hooks:\n      - id: ruff-check\n        args: [--fix]\n      - id: ruff-format\n```\n\nKeep the hook revision aligned with the package version you expect in CI and local development.\n\n## Configuration Notes\n\n- Supported config file names are `pyproject.toml`, `ruff.toml`, and `.ruff.toml`.\n- Ruff uses the closest config file for each analyzed file. Config files are not implicitly merged across directories. If you need inheritance, use the `extend` setting.\n- When Ruff can read a `requires-python` declaration from `pyproject.toml`, it can infer a default `target-version`, but setting `target-version` explicitly is safer for generated code and mixed-tooling repos.\n- By default Ruff respects `.gitignore`, `.git/info/exclude`, and global gitignore files.\n- There is no authentication model. Ruff is a local tool; the important setup surface is config files, editor wiring, and CI hooks.\n\n## Common Pitfalls\n\n- Do not `import ruff` in application code. For most projects Ruff is only a CLI tool in the dev toolchain.\n- Do not enable `select = [\"ALL\"]` unless you intend to review rule churn on upgrades. New Ruff releases can add rules, which changes lint output.\n- `ruff check --fix` does not imply formatting. Run `ruff format` separately.\n- Passing files directly on the command line can bypass exclusions you expected from config. Use `force-exclude = true` if you need excludes to apply consistently in scripted calls.\n- Notebook files can be linted and formatted too. If the repo contains `.ipynb` files and that is not intended, exclude them explicitly.\n- If a subdirectory has its own config file, Ruff uses that nearest config instead of the repo-root config. This surprises agents in monorepos.\n- Unsafe fixes can change behavior. Treat `--unsafe-fixes` as a deliberate review step, not the default path.\n\n## Version-Sensitive Notes For 0.15.5\n\n- Ruff uses a documented custom versioning scheme rather than strict SemVer. Minor releases can include breaking changes, so moving from `0.15.x` to `0.16.x` should be reviewed like a meaningful upgrade.\n- The built-in language server is the current path; older `ruff-lsp` guidance is stale for modern setups.\n- If you copy snippets from older blog posts, verify section names against the current config reference. Modern Ruff config is split across `[tool.ruff]`, `[tool.ruff.lint]`, and `[tool.ruff.format]`.\n\n## Official Sources\n\n- Ruff docs: https://docs.astral.sh/ruff/\n- Configuration: https://docs.astral.sh/ruff/configuration/\n- Linter: https://docs.astral.sh/ruff/linter/\n- Formatter: https://docs.astral.sh/ruff/formatter/\n- Editors: https://docs.astral.sh/ruff/editors/setup/\n- Versioning: https://docs.astral.sh/ruff/versioning/\n- PyPI: https://pypi.org/project/ruff/\n- Official pre-commit hooks: https://github.com/astral-sh/ruff-pre-commit\n"
  },
  {
    "path": "content/s3fs/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"s3fs package guide for Python projects using Amazon S3 and S3-compatible object storage\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"s3fs,s3,fsspec,aws,storage,python\"\n---\n\n# s3fs Python Package Guide\n\n## What It Is\n\n`s3fs` is the `fsspec` filesystem implementation for Amazon S3 and S3-compatible object stores. Use it when Python code needs filesystem-style operations such as listing objects, opening files, copying data, or passing `storage_options` into libraries like pandas.\n\n## Installation\n\n```bash\npip install s3fs==2026.2.0\n```\n\n```bash\nconda install -c conda-forge s3fs\n```\n\nProject notes from the upstream package metadata and changelog:\n\n- `2026.2.0` is the package version from PyPI.\n- Python 3.9 support was dropped in `2025.12.0`; target Python 3.10+ for current releases.\n- `s3fs` builds on `aiobotocore` under the hood, so async and credential behavior ultimately follows the botocore stack.\n\n## Initialize A Filesystem\n\n### Default AWS credential chain\n\nIf you do not pass credentials, `s3fs` uses the normal botocore credential resolution flow:\n\n- environment variables such as `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`\n- shared AWS config and credential files\n- IAM roles or other ambient AWS credentials\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem()\nprint(s3.ls(\"my-bucket\"))\n```\n\n### Use a named AWS profile\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem(profile=\"analytics\")\n```\n\n### Pass explicit credentials\n\nUse this for short-lived credentials in controlled code paths, not hard-coded long-term secrets.\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem(\n    key=\"AWS_ACCESS_KEY_ID\",\n    secret=\"AWS_SECRET_ACCESS_KEY\",\n    token=\"AWS_SESSION_TOKEN\",\n)\n```\n\n### Anonymous access for public buckets\n\n```python\nimport s3fs\n\npublic_s3 = s3fs.S3FileSystem(anon=True)\nprint(public_s3.ls(\"landsat-pds\"))\n```\n\n### S3-compatible endpoints such as MinIO\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem(\n    key=\"minioadmin\",\n    secret=\"minioadmin\",\n    endpoint_url=\"http://127.0.0.1:9000\",\n    client_kwargs={\n        \"region_name\": \"us-east-1\",\n    },\n)\n```\n\n## Core Usage\n\n### List, glob, and inspect objects\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem()\n\nprint(s3.ls(\"my-bucket/prefix\"))\nprint(s3.glob(\"my-bucket/prefix/*.parquet\"))\nprint(s3.info(\"my-bucket/prefix/data.parquet\"))\nprint(s3.exists(\"my-bucket/prefix/data.parquet\"))\n```\n\n### Read and write files\n\nUse binary modes with `s3.open()`.\n\n```python\nimport json\nimport s3fs\n\ns3 = s3fs.S3FileSystem()\n\nrecord = {\"id\": 1, \"status\": \"ok\"}\n\nwith s3.open(\"my-bucket/output/result.json\", \"wb\") as f:\n    f.write(json.dumps(record).encode(\"utf-8\"))\n\nwith s3.open(\"my-bucket/output/result.json\", \"rb\") as f:\n    loaded = json.loads(f.read().decode(\"utf-8\"))\n\nprint(loaded)\n```\n\n### Transfer local files\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem()\n\ns3.put(\"local-report.csv\", \"my-bucket/reports/local-report.csv\")\ns3.get(\"my-bucket/reports/local-report.csv\", \"downloaded-report.csv\")\ns3.cp(\"my-bucket/reports/local-report.csv\", \"my-bucket/archive/local-report.csv\")\ns3.rm(\"my-bucket/archive/local-report.csv\")\n```\n\n### Use `storage_options` with pandas\n\nThis is the common pattern when another library delegates I/O through `fsspec`.\n\n```python\nimport pandas as pd\n\ndf = pd.read_parquet(\n    \"s3://my-bucket/datasets/events.parquet\",\n    storage_options={\n        \"profile\": \"analytics\",\n        \"client_kwargs\": {\"region_name\": \"us-west-2\"},\n    },\n)\n```\n\n## Configuration And Auth\n\n`S3FileSystem` exposes several parameters that matter in real projects:\n\n- `anon=True` for public data only.\n- `profile=\"name\"` to use a named AWS profile.\n- `requester_pays=True` when reading Requester Pays buckets.\n- `version_aware=True` only when you need S3 object versioning.\n- `endpoint_url=\"...\"` for S3-compatible stores such as MinIO or Ceph.\n- `client_kwargs={...}` for botocore client options such as `region_name`.\n- `config_kwargs={...}` for botocore `Config` values such as retries or signature behavior.\n- `s3_additional_kwargs={...}` for per-request S3 options such as server-side encryption headers.\n\nExample with region, retries, and SSE-S3:\n\n```python\nimport s3fs\n\ns3 = s3fs.S3FileSystem(\n    profile=\"analytics\",\n    client_kwargs={\"region_name\": \"us-west-2\"},\n    config_kwargs={\"retries\": {\"max_attempts\": 10, \"mode\": \"standard\"}},\n    s3_additional_kwargs={\"ServerSideEncryption\": \"AES256\"},\n)\n```\n\nIf you need custom endpoints repeatedly, the upstream docs also support `FSSPEC_S3_ENDPOINT_URL`, `FSSPEC_S3_KEY`, and `FSSPEC_S3_SECRET` environment variables.\n\nFor distributed jobs, avoid shipping long-lived raw credentials between workers. The upstream docs point to `S3FileSystem.get_delegated_s3pars()` for temporary delegated credentials when you must fan work out across machines.\n\n## Async Usage\n\n`s3fs` is built on async infrastructure. For normal synchronous code, use the default API. For async applications, create the filesystem with `asynchronous=True`, initialize its session, and close it when finished.\n\n```python\nimport asyncio\nimport s3fs\n\nasync def main() -> None:\n    s3 = s3fs.S3FileSystem(asynchronous=True)\n    await s3.set_session()\n    try:\n        listing = await s3._ls(\"my-bucket/prefix\")\n        print(listing)\n    finally:\n        await s3._session.close()\n\nasyncio.run(main())\n```\n\n## Version-Sensitive Notes\n\n- PyPI lists `2026.2.0` as the latest release, published on February 5, 2026.\n- PyPI also shows the immediate prior releases `2026.1.0` on January 9, 2026 and `2025.12.0` on December 3, 2025.\n- The published docs site currently renders with a `2025.12.0+dirty` banner, and its visible changelog navigation stops at `2025.12.0`. Before relying on behavior changes introduced in 2026, verify them against the PyPI release history or the upstream repository.\n- Current PyPI metadata requires Python `>=3.10` and advertises classifiers through Python 3.14.\n\n## Common Pitfalls\n\n- `s3.open()` is primarily a binary file interface. Encode and decode text yourself, or let higher-level libraries like pandas handle it through `storage_options`.\n- `version_aware=True` is not free. It switches some listings to version APIs, increases permission requirements, and can be much slower on large prefixes.\n- On S3-compatible providers, failures are often endpoint or signature issues rather than path issues. Set `endpoint_url`, region, and any required signing config explicitly.\n- `fork` is unsafe because of open sockets and the async background machinery used by `s3fs`. Use `spawn` or `forkserver` for multiprocessing.\n- `anon=True` only works for genuinely public buckets and objects.\n- If the bucket is Requester Pays, most read operations fail until you set `requester_pays=True`.\n\n## Official Sources\n\n- Docs: https://s3fs.readthedocs.io/en/latest/\n- API reference: https://s3fs.readthedocs.io/en/latest/api.html\n- PyPI: https://pypi.org/project/s3fs/\n- Changelog source: https://raw.githubusercontent.com/fsspec/s3fs/main/docs/source/changelog.rst\n"
  },
  {
    "path": "content/safetensors/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"safetensors Python package guide for safe, zero-copy tensor serialization\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"safetensors,huggingface,tensors,serialization,model-weights,pytorch,numpy\"\n---\n\n# safetensors Python Package Guide\n\n## Golden Rule\n\nUse `safetensors` for tensor weights and arrays, not for arbitrary Python objects. The main value is avoiding `pickle`-style code execution while keeping fast, lazy, zero-copy friendly reads.\n\n## Install\n\n```bash\npip install safetensors==0.7.0\n```\n\nIf you do not need to pin exactly:\n\n```bash\npip install safetensors\n```\n\nPyPI metadata for `0.7.0` says `Requires: Python >=3.9`.\n\nBuild from source only if you need unreleased changes or local development. The upstream repository says source installs require Rust:\n\n```bash\ngit clone https://github.com/huggingface/safetensors\ncd safetensors/bindings/python\npip install setuptools_rust\npip install -e .\n```\n\n## What To Reach For First\n\n- `safe_open(...)`: lazy, selective reads from a `.safetensors` file\n- `safetensors.torch.save_file` / `load_file`: the common PyTorch file API\n- `safetensors.torch.save` / `load`: bytes-in-memory API\n- `safetensors.numpy.load_file` / `save_file`: NumPy file API\n- `safetensors.torch.save_model` / `load_model`: use these for `torch.nn.Module` objects with shared tensors\n\nThe official docs also expose Python modules for `tensorflow`, `flax`, and `paddle` in addition to `torch` and `numpy`.\n\n## Basic PyTorch Workflow\n\n### Save a state dict\n\n```python\nimport torch\nfrom safetensors.torch import save_file\n\ntensors = {\n    \"embedding\": torch.zeros((2, 2)),\n    \"attention\": torch.zeros((2, 3)),\n}\n\nsave_file(tensors, \"model.safetensors\")\n```\n\n### Load everything\n\n```python\nfrom safetensors.torch import load_file\n\nweights = load_file(\"model.safetensors\", device=\"cpu\")\nprint(weights[\"embedding\"].shape)\n```\n\n### Lazy-read selected tensors\n\nUse `safe_open` when you do not want to materialize the whole file immediately.\n\n```python\nfrom safetensors import safe_open\n\nwith safe_open(\"model.safetensors\", framework=\"pt\", device=\"cpu\") as f:\n    print(list(f.keys()))\n    embedding = f.get_tensor(\"embedding\")\n```\n\n### Slice without loading the full tensor first\n\n```python\nfrom safetensors import safe_open\n\nwith safe_open(\"model.safetensors\", framework=\"pt\", device=0) as f:\n    tensor_slice = f.get_slice(\"embedding\")\n    rows, cols = tensor_slice.get_shape()\n    shard = tensor_slice[:, : cols // 2]\n```\n\nThis pattern is useful for large model weights and sharded or distributed loading paths.\n\n## NumPy Workflow\n\n```python\nimport numpy as np\nfrom safetensors.numpy import save_file, load_file\n\narrays = {\n    \"x\": np.zeros((4, 4), dtype=np.float32),\n    \"y\": np.arange(8, dtype=np.int64),\n}\n\nsave_file(arrays, \"arrays.safetensors\")\nloaded = load_file(\"arrays.safetensors\")\n```\n\nIf you already have bytes in memory, use `safetensors.numpy.load(data)` or `safetensors.torch.load(data)`.\n\n## Metadata\n\n`save_file(..., metadata=...)` accepts a string-to-string dictionary only.\n\n```python\nimport torch\nfrom safetensors.torch import save_file\n\ntensors = {\"weight\": torch.zeros((8, 8))}\nmetadata = {\n    \"format\": \"pt\",\n    \"model_type\": \"demo\",\n}\n\nsave_file(tensors, \"model.safetensors\", metadata=metadata)\n```\n\nDo not store nested JSON, numbers, or booleans unless you serialize them to strings yourself. The format allows a special `__metadata__` map, but arbitrary JSON values are not allowed.\n\n## Model-Level Helpers For Shared Tensors\n\nPyTorch models sometimes share buffers, for example tied embeddings and LM heads. `safetensors` does not preserve shared tensors in the plain `Dict[str, Tensor]` file format. The official guidance is:\n\n```python\nfrom safetensors.torch import load_model, save_model\n\nsave_model(model, \"model.safetensors\")\nmissing, unexpected = load_model(model, \"model.safetensors\")\n```\n\nPrefer `save_model` / `load_model` over:\n\n```python\nsave_file(model.state_dict(), \"model.safetensors\")\nmodel.load_state_dict(load_file(\"model.safetensors\"))\n```\n\nwhen the model may have shared tensors. The upstream docs call this out explicitly as the supported workaround.\n\n## Config And Auth\n\nThere is no package-level authentication or global config file for local `.safetensors` reads and writes.\n\n- Local files: call the Python APIs directly.\n- Remote files: fetch bytes yourself with `requests`, `huggingface_hub`, or another client, then pass bytes to `load(...)` or save them locally first.\n- Private Hugging Face Hub assets: handle tokens and Hub auth in `huggingface_hub` or your HTTP client; `safetensors` itself is only the serialization layer.\n\nFor metadata-only inspection of remote weights, the official docs show using HTTP Range requests so you can parse header metadata without downloading the full file.\n\n## Common Pitfalls\n\n### `save_file` expects dense, contiguous tensors\n\nThe official API docs say tensors must be contiguous and dense. If you are working with views or non-contiguous tensors, call `.contiguous()` first in PyTorch before saving.\n\n### `.safetensors` files are weights, not Python objects\n\nDo not expect `safetensors` to serialize tokenizers, configs, callables, or arbitrary classes. Pair it with JSON, YAML, or framework-native config files for non-tensor metadata.\n\n### Metadata values must be strings\n\nThis fails conceptually:\n\n```python\nmetadata = {\"epoch\": 3, \"is_finetuned\": True}\n```\n\nDo this instead:\n\n```python\nmetadata = {\"epoch\": \"3\", \"is_finetuned\": \"true\"}\n```\n\n### `safe_open` is for file paths\n\nUse `safe_open` with an actual safetensors file path. If your data is already in memory, use the module-level `load(...)` function for that framework instead of trying to point `safe_open` at a directory or unrelated path.\n\n### Shared tensor keys can appear \"missing\"\n\nWhen using `save_model` / `load_model`, some keys may be dropped from the file because shared buffers are represented once. Review the returned `missing` and `unexpected` lists in `load_model(...)` instead of assuming exact `state_dict()` key symmetry.\n\n## Version-Sensitive Notes For 0.7.0\n\n- PyPI lists `0.7.0` as the current release on November 19, 2025.\n- The Hugging Face docs site currently exposes `main` plus stable docs labeled `v0.5.0-rc.0`. That docs version label lags the PyPI package version, so use the docs for API behavior but keep the package pin anchored to PyPI.\n- The docs banner says `main` requires installation from source. For normal package usage, prefer `pip install safetensors` unless you specifically need unreleased source changes.\n- PyPI metadata says `Python >=3.9`, even though some legacy classifiers and wheel tags still mention older interpreter compatibility. Follow the package metadata requirement for new project setup.\n\n## Practical Decision Rule\n\n- Need safe on-disk tensor exchange: use `save_file` / `load_file`.\n- Need lazy or partial reads from a large file: use `safe_open`.\n- Need in-memory bytes instead of files: use `save` / `load`.\n- Need PyTorch model save/load with tied weights: use `save_model` / `load_model`.\n\n## Official Sources\n\n- Docs landing page: `https://huggingface.co/docs/safetensors/en/index`\n- Torch API: `https://huggingface.co/docs/safetensors/en/api/torch`\n- NumPy API: `https://huggingface.co/docs/safetensors/en/api/numpy`\n- Tensor sharing notes: `https://huggingface.co/docs/safetensors/en/torch_shared_tensors`\n- Metadata parsing: `https://huggingface.co/docs/safetensors/en/metadata_parsing`\n- Package registry: `https://pypi.org/project/safetensors/`\n- Repository: `https://github.com/huggingface/safetensors`\n"
  },
  {
    "path": "content/safety/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Safety CLI for scanning Python dependencies for vulnerabilities and license issues\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.7.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"safety,security,vulnerability-scanning,license-compliance,python,cli,dependencies\"\n---\n\n# Safety Python Package Guide\n\n## Golden Rule\n\nUse `safety` as a CLI tool, not as an importable runtime library. For Safety `3.x`, the normal flow is authenticate first, then run `safety scan` against a project directory. Many older examples still use Safety `2.x` commands like `safety check -r requirements.txt`; treat those as migration material, not the default 3.x workflow.\n\n## Install\n\nPin the CLI version your workflow expects:\n\n```bash\npython -m pip install \"safety==3.7.0\"\n```\n\nUseful alternatives:\n\n```bash\npipx install \"safety==3.7.0\"\nuv tool install \"safety==3.7.0\"\n```\n\nUse `pipx` or `uv tool` when you want Safety isolated from the project environment. Install it into the project environment only if your CI or dev tooling expects that layout.\n\n## Authenticate And Initialize\n\nSafety 3 scans are tied to the Safety Platform account model. Start with interactive login on a developer machine:\n\n```bash\nsafety auth login\n```\n\nFor headless machines or SSH sessions without a browser:\n\n```bash\nsafety auth login --headless\n```\n\nFor CI or other non-interactive environments, use an API key:\n\n```bash\nexport SAFETY_API_KEY=\"your-api-key\"\nsafety auth login --key\n```\n\nPrefer an environment variable in CI so the key stays out of shell history and repo files.\n\n## Core Usage\n\n### Scan the current project\n\n```bash\nsafety scan\n```\n\nSafety 3 scans the current project directory and detects supported dependency files and Python environments automatically.\n\n### Scan a specific directory\n\n```bash\nsafety scan --target ./services/api\n```\n\nUse `--target` when the repository root is not the Python project root.\n\n### Save machine-readable output\n\n```bash\nsafety scan --output json --save-as safety-report.json\n```\n\nThe docs list multiple output formats, including `screen`, `text`, `json`, `html`, `bare`, `xunit`, `spdx-json`, and `gitlab-sast`.\n\n### Generate and validate a policy file\n\n```bash\nsafety generate policy_file\nsafety validate policy_file --path .safety-policy.yml\n```\n\nUse a policy file when you need to tune scan behavior, ignore rules, or reporting settings for a repository-level workflow.\n\n## Project Configuration\n\nSafety looks for a `.safety-policy.yml` file in the scan target or current working directory unless you point the CLI at a different file path.\n\nCommon policy uses from the official docs:\n\n- define `report` settings such as `dependency-vulnerabilities`, `licenses`, and `json-output`\n- set scan inputs such as `include-files`\n- manage ignores with IDs, expiration dates, and reasons\n\nIf you want deterministic automation, keep the policy file in the repo root and validate it in CI before relying on it.\n\n## CI And Automation Pattern\n\nA practical non-interactive pattern is:\n\n```bash\nexport SAFETY_API_KEY=\"$SAFETY_API_KEY\"\nsafety auth login --key\nsafety scan --target . --output json --save-as safety-report.json\n```\n\nIn CI, treat the scan report as an artifact and let the command's exit code fail the job when policy or vulnerability conditions require it. Safety documents command-specific exit codes, so do not assume every non-zero exit means the CLI crashed.\n\n## Common Pitfalls\n\n- Safety `3.x` is not the same CLI contract as Safety `2.x`. Old examples that use `safety check`, `--file`, or `-r requirements.txt` are usually outdated for the current docs.\n- `safety scan` targets directories, not a single requirements file. The official migration guide says to scan the project directory or use policy-file `include-files` if you need to narrow inputs.\n- Authentication is required for the main Safety 3 scan workflow. If `safety scan` behaves unexpectedly in CI, check auth state before debugging the project files.\n- Safety Platform project policy can override or supersede local policy behavior. The current docs discuss both local `.safety-policy.yml` usage and platform-managed policy, so verify the effective behavior in the account you are using.\n- Save reports explicitly with `--save-as` when another job step needs the results. Printing JSON to stdout is easy to lose in CI logs.\n\n## Version-Sensitive Notes For 3.7.0\n\n- The official docs banner and quickstart pages currently track Safety `3.7.0`, and PyPI also lists `3.7.0` for the package version used here.\n- The official migration guide says `safety check` from v2 should be replaced with `safety scan` in v3, and that `scan` no longer targets individual files directly.\n- Some official docs snippets still mention installing `safety==3.4.0` on authentication pages. Treat those as stale examples and pin `3.7.0` if you are matching this curated entry.\n- Safety 3.5.0 introduced the minimum version needed for Safety Firewall support according to the migration docs, so older 3.x examples may miss newer platform behavior.\n\n## Official Links\n\n- Docs root: `https://docs.safetycli.com/safety-docs/`\n- Quick start: `https://docs.safetycli.com/safety-docs/getting-started/quick-start`\n- Authentication: `https://docs.safetycli.com/safety-docs/getting-started/authenticate-yourself`\n- Policy files: `https://docs.safetycli.com/safety-docs/safety-cli/scanning-for-vulnerable-and-malicious-packages/using-a-safety-policy-file`\n- Output formats: `https://docs.safetycli.com/safety-docs/output/formats`\n- Exit codes: `https://docs.safetycli.com/safety-docs/support/exit-codes`\n- Migration guide: `https://docs.safetycli.com/safety-docs/miscellaneous/release-notes/breaking-changes-in-safety-3`\n- PyPI: `https://pypi.org/project/safety/`\n"
  },
  {
    "path": "content/salesforce/docs/crm/javascript/DOC.md",
    "content": "---\nname: crm\ndescription: \"Salesforce JavaScript SDK (JSforce) coding guidelines for Salesforce API interactions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.10.8\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"salesforce,crm,soql,enterprise,api\"\n---\n\n# Salesforce JavaScript SDK (JSforce) Coding Guidelines\n\nYou are a Salesforce API coding expert. Help me with writing code using the Salesforce API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://jsforce.github.io/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use JSforce to interact with Salesforce APIs. JSforce is the standard JavaScript library for all Salesforce API interactions, supporting both Node.js and browser environments.\n\n- **Library Name:** JSforce\n- **NPM Package:** `jsforce`\n- **Alternative Package:** `@jsforce/jsforce-node` (Node.js only, smaller bundle)\n- **Legacy Libraries**: Do not use deprecated or unofficial Salesforce JavaScript packages\n\n**Installation:**\n\n- **Correct:** `npm install jsforce`\n- **Node.js only:** `npm install @jsforce/jsforce-node`\n\n**APIs and Usage:**\n\n- **Correct:** `const jsforce = require('jsforce')`\n- **Correct:** `const conn = new jsforce.Connection()`\n- **Correct:** `await conn.query(...)`\n- **Correct:** `await conn.sobject('Account').create(...)`\n- **Incorrect:** Using unofficial Salesforce client libraries\n- **Incorrect:** Direct REST API calls without SDK\n\n## Installation\n\nInstall JSforce via npm:\n\n```bash\nnpm install jsforce\n```\n\nFor Node.js-only projects (smaller bundle):\n\n```bash\nnpm install @jsforce/jsforce-node\n```\n\nFor browser usage via CDN:\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/jsforce@3.2.2/dist/jsforce.min.js\"></script>\n```\n\n## Environment Variables\n\nSet up your Salesforce credentials using environment variables:\n\n```bash\nexport SALESFORCE_USERNAME=\"user@example.org\"\nexport SALESFORCE_PASSWORD=\"your_password\"\nexport SALESFORCE_SECURITY_TOKEN=\"your_security_token\"\nexport SALESFORCE_LOGIN_URL=\"https://login.salesforce.com\" # or https://test.salesforce.com for sandbox\n```\n\nOr create a `.env` file:\n\n```\nSALESFORCE_USERNAME=user@example.org\nSALESFORCE_PASSWORD=your_password\nSALESFORCE_SECURITY_TOKEN=your_security_token\nSALESFORCE_LOGIN_URL=https://login.salesforce.com\n```\n\n## Initialization\n\nJSforce requires creating a `Connection` instance for all API calls.\n\n### Basic Connection\n\n```javascript\nconst jsforce = require('jsforce');\n\n// Create connection\nconst conn = new jsforce.Connection();\n```\n\n### Connection with Login URL\n\n```javascript\nconst jsforce = require('jsforce');\n\n// Connect to sandbox\nconst conn = new jsforce.Connection({\n  loginUrl: 'https://test.salesforce.com'\n});\n```\n\n### Connection with Session ID (OAuth)\n\n```javascript\nconst jsforce = require('jsforce');\n\nconst conn = new jsforce.Connection({\n  instanceUrl: 'https://na1.salesforce.com',\n  accessToken: 'your_access_token'\n});\n```\n\n### Connection with Session ID and Server URL\n\n```javascript\nconst jsforce = require('jsforce');\n\nconst conn = new jsforce.Connection({\n  serverUrl: 'https://na1.salesforce.com',\n  sessionId: 'your_session_id'\n});\n```\n\n## Authentication\n\n### Username/Password Login\n\n```javascript\nconst jsforce = require('jsforce');\nconst conn = new jsforce.Connection();\n\nasync function login() {\n  try {\n    const userInfo = await conn.login(\n      process.env.SALESFORCE_USERNAME,\n      process.env.SALESFORCE_PASSWORD + process.env.SALESFORCE_SECURITY_TOKEN\n    );\n    console.log('User ID:', userInfo.id);\n    console.log('Org ID:', userInfo.organizationId);\n    console.log('Access Token:', conn.accessToken);\n    console.log('Instance URL:', conn.instanceUrl);\n  } catch (err) {\n    console.error('Login error:', err);\n  }\n}\n\nlogin();\n```\n\n### OAuth 2.0 Username-Password Flow\n\n```javascript\nconst jsforce = require('jsforce');\n\nasync function oauth2Login() {\n  const conn = new jsforce.Connection({\n    oauth2: {\n      loginUrl: 'https://login.salesforce.com',\n      clientId: 'your_client_id',\n      clientSecret: 'your_client_secret',\n      redirectUri: 'http://localhost:3000/oauth/callback'\n    }\n  });\n\n  try {\n    const userInfo = await conn.login(\n      process.env.SALESFORCE_USERNAME,\n      process.env.SALESFORCE_PASSWORD\n    );\n    console.log('Access Token:', conn.accessToken);\n    console.log('Refresh Token:', conn.refreshToken);\n  } catch (err) {\n    console.error('OAuth login error:', err);\n  }\n}\n\noauth2Login();\n```\n\n### OAuth 2.0 Authorization Code Flow\n\n```javascript\nconst jsforce = require('jsforce');\nconst express = require('express');\n\nconst oauth2 = new jsforce.OAuth2({\n  loginUrl: 'https://login.salesforce.com',\n  clientId: 'your_client_id',\n  clientSecret: 'your_client_secret',\n  redirectUri: 'http://localhost:3000/oauth/callback'\n});\n\nconst app = express();\n\napp.get('/oauth', (req, res) => {\n  res.redirect(oauth2.getAuthorizationUrl({ scope: 'api id web' }));\n});\n\napp.get('/oauth/callback', async (req, res) => {\n  const conn = new jsforce.Connection({ oauth2 });\n  const code = req.query.code;\n\n  try {\n    const userInfo = await conn.authorize(code);\n    console.log('Access Token:', conn.accessToken);\n    console.log('Refresh Token:', conn.refreshToken);\n    res.send('OAuth authentication successful!');\n  } catch (err) {\n    console.error('OAuth error:', err);\n    res.status(500).send('OAuth error');\n  }\n});\n\napp.listen(3000);\n```\n\n### OAuth 2.0 Client Credentials Flow\n\n```javascript\nconst jsforce = require('jsforce');\n\nasync function clientCredentialsFlow() {\n  const conn = new jsforce.Connection({\n    oauth2: {\n      loginUrl: 'https://login.salesforce.com',\n      clientId: 'your_client_id',\n      clientSecret: 'your_client_secret'\n    }\n  });\n\n  try {\n    await conn.oauth2.authenticate({\n      grant_type: 'client_credentials'\n    });\n    console.log('Access Token:', conn.accessToken);\n  } catch (err) {\n    console.error('Client credentials error:', err);\n  }\n}\n\nclientCredentialsFlow();\n```\n\n### JWT Bearer Flow\n\n```javascript\nconst jsforce = require('jsforce');\nconst fs = require('fs');\n\nconst privateKey = fs.readFileSync('private.key', 'utf8');\n\nasync function jwtBearerFlow() {\n  const conn = new jsforce.Connection({\n    oauth2: {\n      loginUrl: 'https://login.salesforce.com',\n      clientId: 'your_client_id',\n      privateKey: privateKey\n    }\n  });\n\n  try {\n    await conn.oauth2.authenticate({\n      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n      assertion: conn.oauth2.createJwtBearerToken({\n        iss: 'your_client_id',\n        sub: 'user@example.org',\n        aud: 'https://login.salesforce.com'\n      })\n    });\n    console.log('Access Token:', conn.accessToken);\n  } catch (err) {\n    console.error('JWT Bearer flow error:', err);\n  }\n}\n\njwtBearerFlow();\n```\n\n### Browser OAuth Initialization\n\n```javascript\njsforce.browser.init({\n  clientId: 'your_oauth2_client_id',\n  redirectUri: 'https://yourapp.example.com/oauth/callback'\n});\n\njsforce.browser.login();\n\njsforce.browser.on('connect', function(conn) {\n  console.log('Connected to Salesforce');\n  console.log('Access Token:', conn.accessToken);\n});\n```\n\n## SOQL Queries\n\n### Basic Query\n\n```javascript\nconst jsforce = require('jsforce');\nconst conn = new jsforce.Connection();\n\nasync function basicQuery() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.query('SELECT Id, Name FROM Account LIMIT 10');\n\n  console.log('Total records:', result.totalSize);\n  console.log('Records fetched:', result.records.length);\n\n  result.records.forEach(record => {\n    console.log('Account:', record.Name);\n  });\n}\n\nbasicQuery();\n```\n\n### Query with WHERE Clause\n\n```javascript\nasync function queryWithFilter() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.query(\n    \"SELECT Id, Name, Industry FROM Account WHERE Industry = 'Technology'\"\n  );\n\n  console.log('Found', result.totalSize, 'Technology accounts');\n}\n```\n\n### Query with Relationships\n\n```javascript\nasync function queryRelationships() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  // Parent to child relationship\n  const result = await conn.query(\n    'SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 5'\n  );\n\n  result.records.forEach(account => {\n    console.log('Account:', account.Name);\n    if (account.Contacts) {\n      account.Contacts.records.forEach(contact => {\n        console.log('  Contact:', contact.Name);\n      });\n    }\n  });\n}\n```\n\n### Query All Records (Including Deleted)\n\n```javascript\nasync function queryAll() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.queryAll(\n    'SELECT Id, Name, IsDeleted FROM Account WHERE IsDeleted = true'\n  );\n\n  console.log('Deleted accounts:', result.totalSize);\n}\n```\n\n### Query with Pagination\n\n```javascript\nasync function queryWithPagination() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  let result = await conn.query('SELECT Id, Name FROM Account');\n  let records = result.records;\n\n  while (!result.done) {\n    result = await conn.queryMore(result.nextRecordsUrl);\n    records = records.concat(result.records);\n  }\n\n  console.log('Total records retrieved:', records.length);\n}\n```\n\n### Query with Method Chaining\n\n```javascript\nasync function methodChainQuery() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const records = await conn.sobject('Account')\n    .select('Id, Name, Industry')\n    .where({ Industry: 'Technology' })\n    .limit(10)\n    .execute();\n\n  console.log('Records:', records);\n}\n```\n\n### Event-Driven Query\n\n```javascript\nasync function eventDrivenQuery() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  conn.query('SELECT Id, Name FROM Account')\n    .on('record', record => {\n      console.log('Account:', record.Name);\n    })\n    .on('end', () => {\n      console.log('Query completed');\n    })\n    .on('error', err => {\n      console.error('Query error:', err);\n    })\n    .run();\n}\n```\n\n## SOSL Search\n\n### Basic Search\n\n```javascript\nasync function basicSearch() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.search(\n    'FIND {United*} IN NAME FIELDS RETURNING Account(Id, Name), Contact(Id, Name)'\n  );\n\n  console.log('Search results:', result.searchRecords);\n}\n```\n\n## CRUD Operations\n\n### Create Single Record\n\n```javascript\nasync function createRecord() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.sobject('Account').create({\n    Name: 'New Account',\n    Industry: 'Technology',\n    BillingCity: 'San Francisco'\n  });\n\n  console.log('Created account ID:', result.id);\n  console.log('Success:', result.success);\n}\n```\n\n### Create Multiple Records\n\n```javascript\nasync function createMultipleRecords() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const results = await conn.sobject('Account').create([\n    { Name: 'Account 1', Industry: 'Technology' },\n    { Name: 'Account 2', Industry: 'Finance' },\n    { Name: 'Account 3', Industry: 'Healthcare' }\n  ]);\n\n  results.forEach(result => {\n    if (result.success) {\n      console.log('Created account ID:', result.id);\n    } else {\n      console.error('Error:', result.errors);\n    }\n  });\n}\n```\n\n### Retrieve Single Record\n\n```javascript\nasync function retrieveRecord() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const account = await conn.sobject('Account').retrieve('001XXXXXXXXXXXXXXX');\n\n  console.log('Account Name:', account.Name);\n  console.log('Industry:', account.Industry);\n}\n```\n\n### Retrieve Multiple Records\n\n```javascript\nasync function retrieveMultipleRecords() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const accounts = await conn.sobject('Account').retrieve([\n    '001XXXXXXXXXXXXXXX',\n    '001YYYYYYYYYYYYYYY'\n  ]);\n\n  accounts.forEach(account => {\n    console.log('Account:', account.Name);\n  });\n}\n```\n\n### Update Single Record\n\n```javascript\nasync function updateRecord() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.sobject('Account').update({\n    Id: '001XXXXXXXXXXXXXXX',\n    Name: 'Updated Account Name',\n    Industry: 'Media'\n  });\n\n  console.log('Updated:', result.success);\n}\n```\n\n### Update Multiple Records\n\n```javascript\nasync function updateMultipleRecords() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const results = await conn.sobject('Account').update([\n    { Id: '001XXXXXXXXXXXXXXX', Name: 'Updated Name 1' },\n    { Id: '001YYYYYYYYYYYYYYY', Name: 'Updated Name 2' }\n  ]);\n\n  results.forEach(result => {\n    if (result.success) {\n      console.log('Updated account ID:', result.id);\n    } else {\n      console.error('Error:', result.errors);\n    }\n  });\n}\n```\n\n### Upsert Records\n\n```javascript\nasync function upsertRecords() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const results = await conn.sobject('Account').upsert(\n    [\n      { ExternalId__c: 'EXT001', Name: 'Account 1', Industry: 'Technology' },\n      { ExternalId__c: 'EXT002', Name: 'Account 2', Industry: 'Finance' }\n    ],\n    'ExternalId__c'\n  );\n\n  results.forEach(result => {\n    if (result.success) {\n      console.log('Upserted account ID:', result.id);\n      console.log('Created:', result.created);\n    }\n  });\n}\n```\n\n### Delete Single Record\n\n```javascript\nasync function deleteRecord() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.sobject('Account').destroy('001XXXXXXXXXXXXXXX');\n\n  console.log('Deleted:', result.success);\n}\n```\n\n### Delete Multiple Records\n\n```javascript\nasync function deleteMultipleRecords() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const results = await conn.sobject('Account').destroy([\n    '001XXXXXXXXXXXXXXX',\n    '001YYYYYYYYYYYYYYY'\n  ]);\n\n  results.forEach(result => {\n    if (result.success) {\n      console.log('Deleted account ID:', result.id);\n    } else {\n      console.error('Error:', result.errors);\n    }\n  });\n}\n```\n\n## Bulk API\n\n### Bulk Query\n\n```javascript\nasync function bulkQuery() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const records = [];\n\n  conn.bulk.query('SELECT Id, Name FROM Account')\n    .on('record', record => {\n      records.push(record);\n    })\n    .on('end', () => {\n      console.log('Total records:', records.length);\n    })\n    .on('error', err => {\n      console.error('Bulk query error:', err);\n    });\n}\n```\n\n### Bulk Insert\n\n```javascript\nasync function bulkInsert() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const accounts = [];\n  for (let i = 0; i < 1000; i++) {\n    accounts.push({\n      Name: `Bulk Account ${i}`,\n      Industry: 'Technology'\n    });\n  }\n\n  conn.bulk.load('Account', 'insert', accounts, (err, results) => {\n    if (err) {\n      console.error('Bulk insert error:', err);\n      return;\n    }\n\n    results.forEach(result => {\n      if (result.success) {\n        console.log('Created ID:', result.id);\n      } else {\n        console.error('Error:', result.errors);\n      }\n    });\n  });\n}\n```\n\n### Bulk Update\n\n```javascript\nasync function bulkUpdate() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const updates = [\n    { Id: '001XXXXXXXXXXXXXXX', Industry: 'Finance' },\n    { Id: '001YYYYYYYYYYYYYYY', Industry: 'Healthcare' }\n  ];\n\n  conn.bulk.load('Account', 'update', updates, (err, results) => {\n    if (err) {\n      console.error('Bulk update error:', err);\n      return;\n    }\n\n    console.log('Updated records:', results.length);\n  });\n}\n```\n\n### Bulk Delete\n\n```javascript\nasync function bulkDelete() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const idsToDelete = [\n    { Id: '001XXXXXXXXXXXXXXX' },\n    { Id: '001YYYYYYYYYYYYYYY' }\n  ];\n\n  conn.bulk.load('Account', 'delete', idsToDelete, (err, results) => {\n    if (err) {\n      console.error('Bulk delete error:', err);\n      return;\n    }\n\n    console.log('Deleted records:', results.length);\n  });\n}\n```\n\n### Bulk 2.0 Query\n\n```javascript\nasync function bulk2Query() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const recordStream = await conn.bulk2.query('SELECT Id, Name FROM Account');\n\n  recordStream.on('record', record => {\n    console.log('Record:', record);\n  });\n\n  recordStream.on('end', () => {\n    console.log('Bulk 2.0 query completed');\n  });\n\n  recordStream.on('error', err => {\n    console.error('Bulk 2.0 query error:', err);\n  });\n}\n```\n\n## SObject Metadata\n\n### Describe SObject\n\n```javascript\nasync function describeSObject() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const metadata = await conn.sobject('Account').describe();\n\n  console.log('Label:', metadata.label);\n  console.log('Updateable:', metadata.updateable);\n  console.log('Fields:', metadata.fields.length);\n\n  metadata.fields.forEach(field => {\n    console.log(`  ${field.name} (${field.type})`);\n  });\n}\n```\n\n### Describe Global\n\n```javascript\nasync function describeGlobal() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.describeGlobal();\n\n  console.log('Available SObjects:');\n  result.sobjects.forEach(sobject => {\n    console.log(`  ${sobject.name} - ${sobject.label}`);\n  });\n}\n```\n\n### Describe Multiple SObjects\n\n```javascript\nasync function describeMultiple() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.describe(['Account', 'Contact', 'Opportunity']);\n\n  result.sobjects.forEach(sobject => {\n    console.log('SObject:', sobject.name);\n    console.log('Fields:', sobject.fields.length);\n  });\n}\n```\n\n## Metadata API\n\n### List Metadata Types\n\n```javascript\nasync function listMetadataTypes() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.metadata.describe();\n\n  console.log('API Version:', result.organizationNamespace);\n  result.metadataObjects.forEach(obj => {\n    console.log('Metadata Type:', obj.xmlName);\n  });\n}\n```\n\n### List Metadata\n\n```javascript\nasync function listMetadata() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.metadata.list([\n    { type: 'CustomObject' },\n    { type: 'ApexClass' }\n  ]);\n\n  result.forEach(item => {\n    console.log('Full Name:', item.fullName);\n    console.log('Type:', item.type);\n  });\n}\n```\n\n### Read Metadata\n\n```javascript\nasync function readMetadata() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.metadata.read('CustomObject', ['Account', 'Contact']);\n\n  result.forEach(metadata => {\n    console.log('Object:', metadata.fullName);\n    console.log('Label:', metadata.label);\n  });\n}\n```\n\n### Create Metadata\n\n```javascript\nasync function createMetadata() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const customField = {\n    fullName: 'Account.CustomField__c',\n    label: 'Custom Field',\n    type: 'Text',\n    length: 100\n  };\n\n  const result = await conn.metadata.create('CustomField', [customField]);\n\n  console.log('Created:', result[0].success);\n}\n```\n\n### Update Metadata\n\n```javascript\nasync function updateMetadata() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const customField = {\n    fullName: 'Account.CustomField__c',\n    label: 'Updated Custom Field',\n    type: 'Text',\n    length: 255\n  };\n\n  const result = await conn.metadata.update('CustomField', [customField]);\n\n  console.log('Updated:', result[0].success);\n}\n```\n\n### Delete Metadata\n\n```javascript\nasync function deleteMetadata() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.metadata.delete('CustomField', [\n    'Account.CustomField__c'\n  ]);\n\n  console.log('Deleted:', result[0].success);\n}\n```\n\n## Tooling API\n\n### Query with Tooling API\n\n```javascript\nasync function toolingQuery() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.tooling.query(\n    'SELECT Id, Name FROM ApexClass WHERE Name LIKE \\'Test%\\''\n  );\n\n  result.records.forEach(record => {\n    console.log('Apex Class:', record.Name);\n  });\n}\n```\n\n### Execute Anonymous Apex\n\n```javascript\nasync function executeAnonymous() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const apexCode = `\n    System.debug('Hello from anonymous Apex!');\n    Account acc = new Account(Name='Test Account');\n    insert acc;\n  `;\n\n  const result = await conn.tooling.executeAnonymous(apexCode);\n\n  console.log('Success:', result.success);\n  console.log('Compiled:', result.compiled);\n  console.log('Logs:', result.logs);\n}\n```\n\n### Create Apex Class\n\n```javascript\nasync function createApexClass() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.tooling.sobject('ApexClass').create({\n    Name: 'MyApexClass',\n    Body: 'public class MyApexClass { public static void hello() { System.debug(\\'Hello\\'); } }'\n  });\n\n  console.log('Created Apex Class ID:', result.id);\n}\n```\n\n## Analytics API\n\n### List Reports\n\n```javascript\nasync function listReports() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const reports = await conn.analytics.reports();\n\n  reports.forEach(report => {\n    console.log('Report:', report.name);\n    console.log('ID:', report.id);\n  });\n}\n```\n\n### Describe Report\n\n```javascript\nasync function describeReport() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const reportId = '00O1234567890ABCD';\n  const metadata = await conn.analytics.report(reportId).describe();\n\n  console.log('Report Metadata:', metadata.reportMetadata);\n  console.log('Report Type:', metadata.reportTypeMetadata);\n}\n```\n\n### Execute Report\n\n```javascript\nasync function executeReport() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const reportId = '00O1234567890ABCD';\n  const result = await conn.analytics.report(reportId).execute();\n\n  console.log('Report Results:', result.factMap);\n}\n```\n\n### List Dashboards\n\n```javascript\nasync function listDashboards() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const dashboards = await conn.analytics.dashboards();\n\n  dashboards.forEach(dashboard => {\n    console.log('Dashboard:', dashboard.name);\n    console.log('ID:', dashboard.id);\n  });\n}\n```\n\n## Chatter API\n\n### Get User Info\n\n```javascript\nasync function getUserInfo() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const user = await conn.chatter.resource('/users/me').retrieve();\n\n  console.log('Username:', user.username);\n  console.log('Email:', user.email);\n  console.log('Display Name:', user.displayName);\n}\n```\n\n### Post to Feed\n\n```javascript\nasync function postToFeed() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.chatter.resource('/feed-elements').create({\n    body: {\n      messageSegments: [\n        { type: 'Text', text: 'Hello from JSforce!' }\n      ]\n    },\n    feedElementType: 'FeedItem',\n    subjectId: 'me'\n  });\n\n  console.log('Posted feed item ID:', result.id);\n}\n```\n\n### Get Feed Items\n\n```javascript\nasync function getFeedItems() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.chatter.resource('/feeds/news/me/feed-elements').retrieve();\n\n  result.elements.forEach(element => {\n    console.log('Feed Item:', element.body.text);\n  });\n}\n```\n\n## Streaming API\n\n### Subscribe to PushTopic\n\n```javascript\nasync function subscribeToPushTopic() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  conn.streaming.topic('AllAccounts').subscribe((message) => {\n    console.log('Event received:', message);\n    console.log('Account ID:', message.sobject.Id);\n    console.log('Account Name:', message.sobject.Name);\n  });\n}\n```\n\n### Create PushTopic\n\n```javascript\nasync function createPushTopic() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.sobject('PushTopic').create({\n    Name: 'AllAccounts',\n    Query: 'SELECT Id, Name FROM Account',\n    ApiVersion: 58.0,\n    NotifyForOperationCreate: true,\n    NotifyForOperationUpdate: true,\n    NotifyForOperationDelete: true,\n    NotifyForFields: 'All'\n  });\n\n  console.log('PushTopic created:', result.id);\n}\n```\n\n### Platform Event Subscription\n\n```javascript\nasync function subscribeToEvent() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  conn.streaming.channel('/event/Custom_Event__e').subscribe((message) => {\n    console.log('Platform Event received:', message);\n  });\n}\n```\n\n### Change Data Capture\n\n```javascript\nasync function subscribeToChangeDataCapture() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  conn.streaming.channel('/data/AccountChangeEvent').subscribe((message) => {\n    console.log('Change Event:', message);\n    console.log('Change Type:', message.payload.ChangeEventHeader.changeType);\n  });\n}\n```\n\n## Apex REST\n\n### Call Custom Apex REST Endpoint\n\n```javascript\nasync function callApexRest() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.apex.get('/MyApexRestService');\n\n  console.log('Response:', result);\n}\n```\n\n### POST to Apex REST\n\n```javascript\nasync function postToApexRest() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.apex.post('/MyApexRestService', {\n    name: 'Test',\n    value: 123\n  });\n\n  console.log('Response:', result);\n}\n```\n\n### PUT to Apex REST\n\n```javascript\nasync function putToApexRest() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.apex.put('/MyApexRestService/001XXXXXXXXXXXXXXX', {\n    name: 'Updated Name'\n  });\n\n  console.log('Response:', result);\n}\n```\n\n### DELETE to Apex REST\n\n```javascript\nasync function deleteToApexRest() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const result = await conn.apex.del('/MyApexRestService/001XXXXXXXXXXXXXXX');\n\n  console.log('Response:', result);\n}\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\nconst jsforce = require('jsforce');\nconst conn = new jsforce.Connection();\n\nasync function handleErrors() {\n  try {\n    await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n    const result = await conn.sobject('Account').create({\n      Name: 'Test Account'\n    });\n\n    console.log('Success:', result.success);\n  } catch (err) {\n    console.error('Error Name:', err.name);\n    console.error('Error Message:', err.message);\n    console.error('Error Code:', err.errorCode);\n  }\n}\n```\n\n### CRUD Error Handling\n\n```javascript\nasync function handleCrudErrors() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const results = await conn.sobject('Account').create([\n    { Name: 'Account 1' },\n    { Name: '' } // This will fail validation\n  ]);\n\n  results.forEach((result, index) => {\n    if (result.success) {\n      console.log(`Record ${index} created:`, result.id);\n    } else {\n      console.error(`Record ${index} failed:`, result.errors);\n    }\n  });\n}\n```\n\n## Limits and Identity\n\n### Get API Limits\n\n```javascript\nasync function getApiLimits() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const limits = await conn.limits();\n\n  console.log('Daily API Requests:', limits.DailyApiRequests);\n  console.log('Max:', limits.DailyApiRequests.Max);\n  console.log('Remaining:', limits.DailyApiRequests.Remaining);\n}\n```\n\n### Get Identity Information\n\n```javascript\nasync function getIdentity() {\n  await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);\n\n  const identity = await conn.identity();\n\n  console.log('User ID:', identity.user_id);\n  console.log('Organization ID:', identity.organization_id);\n  console.log('Username:', identity.username);\n  console.log('Display Name:', identity.display_name);\n}\n```\n\n## Useful Links\n\n- Documentation: https://jsforce.github.io/\n- Getting Started: https://jsforce.github.io/start/\n- API Reference: https://jsforce.github.io/document/\n- GitHub: https://github.com/jsforce/jsforce\n- Salesforce Developer Docs: https://developer.salesforce.com/\n- Salesforce REST API Guide: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/\n"
  },
  {
    "path": "content/salesforce/docs/crm/python/DOC.md",
    "content": "---\nname: crm\ndescription: \"Salesforce Python SDK (simple-salesforce) coding guidelines for Salesforce REST API interactions\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.12.9\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"salesforce,crm,soql,enterprise,api\"\n---\n\n# Salesforce Python SDK (simple-salesforce) Coding Guidelines\n\nYou are a Salesforce API coding expert. Help me with writing code using the Salesforce API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://simple-salesforce.readthedocs.io/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use simple-salesforce to interact with Salesforce APIs. Simple-salesforce is the most widely used Python library for Salesforce REST API interactions.\n\n- **Library Name:** simple-salesforce\n- **PyPI Package:** `simple-salesforce`\n- **Alternative Library:** `salesforce-api` (less popular)\n- **Legacy Libraries**: Do not use deprecated or unofficial Salesforce Python packages\n\n**Installation:**\n\n- **Correct:** `pip install simple-salesforce`\n- **With environment variables support:** `pip install simple-salesforce python-dotenv`\n\n**APIs and Usage:**\n\n- **Correct:** `from simple_salesforce import Salesforce`\n- **Correct:** `sf = Salesforce(username='...', password='...', security_token='...')`\n- **Correct:** `sf.query(\"SELECT Id, Name FROM Account\")`\n- **Correct:** `sf.Account.create({'Name': 'Test'})`\n- **Incorrect:** Using unofficial Salesforce client libraries\n- **Incorrect:** Direct REST API calls without SDK\n\n## Installation\n\nInstall simple-salesforce via pip:\n\n```bash\npip install simple-salesforce\n```\n\nFor environment variable support:\n\n```bash\npip install simple-salesforce python-dotenv\n```\n\n## Environment Variables\n\nSet up your Salesforce credentials using environment variables:\n\n```bash\nexport SALESFORCE_USERNAME=\"user@example.org\"\nexport SALESFORCE_PASSWORD=\"your_password\"\nexport SALESFORCE_SECURITY_TOKEN=\"your_security_token\"\nexport SALESFORCE_DOMAIN=\"login\" # or \"test\" for sandbox\n```\n\nOr create a `.env` file:\n\n```\nSALESFORCE_USERNAME=user@example.org\nSALESFORCE_PASSWORD=your_password\nSALESFORCE_SECURITY_TOKEN=your_security_token\nSALESFORCE_DOMAIN=login\n```\n\nLoad environment variables in code:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nusername = os.getenv('SALESFORCE_USERNAME')\npassword = os.getenv('SALESFORCE_PASSWORD')\nsecurity_token = os.getenv('SALESFORCE_SECURITY_TOKEN')\n```\n\n## Initialization\n\nSimple-salesforce requires creating a `Salesforce` instance for all API calls.\n\n### Basic Connection (Username/Password/Token)\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token'\n)\n```\n\n### Connection with Environment Variables\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom simple_salesforce import Salesforce\n\nload_dotenv()\n\nsf = Salesforce(\n    username=os.getenv('SALESFORCE_USERNAME'),\n    password=os.getenv('SALESFORCE_PASSWORD'),\n    security_token=os.getenv('SALESFORCE_SECURITY_TOKEN')\n)\n```\n\n### Connection to Sandbox\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    domain='test'  # Use 'test' for sandbox\n)\n```\n\n### Connection with Custom Domain\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    domain='mydomain'  # Your My Domain\n)\n```\n\n## Authentication\n\n### Username/Password/Token Authentication\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token'\n)\n\nprint(f\"Session ID: {sf.session_id}\")\nprint(f\"Instance URL: {sf.sf_instance}\")\n```\n\n### SalesforceLogin (No Token Required)\n\n```python\nfrom simple_salesforce import Salesforce, SalesforceLogin\n\nsession_id, instance = SalesforceLogin(\n    username='user@example.org',\n    password='your_password'\n)\n\nsf = Salesforce(instance=instance, session_id=session_id)\n```\n\n### Session ID Authentication (OAuth)\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    instance='na1.salesforce.com',\n    session_id='your_session_id_from_oauth'\n)\n```\n\n### OAuth 2.0 Access Token\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    instance_url='https://na1.salesforce.com',\n    session_id='your_oauth_access_token'\n)\n```\n\n### Using Requests Session\n\n```python\nimport requests\nfrom simple_salesforce import Salesforce\n\nsession = requests.Session()\nsession.headers.update({'Custom-Header': 'value'})\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    session=session\n)\n```\n\n## SOQL Queries\n\n### Basic Query\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token'\n)\n\nresult = sf.query(\"SELECT Id, Name FROM Account LIMIT 10\")\n\nprint(f\"Total records: {result['totalSize']}\")\n\nfor record in result['records']:\n    print(f\"Account: {record['Name']}\")\n```\n\n### Query with WHERE Clause\n\n```python\nresult = sf.query(\n    \"SELECT Id, Name, Industry FROM Account WHERE Industry = 'Technology'\"\n)\n\nprint(f\"Found {result['totalSize']} Technology accounts\")\n\nfor record in result['records']:\n    print(f\"{record['Name']} - {record['Industry']}\")\n```\n\n### Query with Relationships\n\n```python\n# Parent to child relationship\nresult = sf.query(\n    \"SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 5\"\n)\n\nfor account in result['records']:\n    print(f\"Account: {account['Name']}\")\n    if account.get('Contacts'):\n        for contact in account['Contacts']['records']:\n            print(f\"  Contact: {contact['Name']}\")\n```\n\n### Query with Child to Parent Relationship\n\n```python\nresult = sf.query(\n    \"SELECT Id, Name, Account.Name FROM Contact LIMIT 10\"\n)\n\nfor contact in result['records']:\n    account_name = contact.get('Account', {}).get('Name', 'N/A')\n    print(f\"{contact['Name']} - Account: {account_name}\")\n```\n\n### Query All (Including Deleted Records)\n\n```python\nresult = sf.query_all(\n    \"SELECT Id, Name, IsDeleted FROM Account WHERE IsDeleted = true\"\n)\n\nprint(f\"Deleted accounts: {result['totalSize']}\")\n```\n\n### Query with Automatic Pagination\n\n```python\n# query_all handles pagination automatically\nresult = sf.query_all(\"SELECT Id, Name FROM Account\")\n\nprint(f\"Total records: {result['totalSize']}\")\n\nfor record in result['records']:\n    print(f\"Account: {record['Name']}\")\n```\n\n### Query All Iterator (Memory Efficient)\n\n```python\n# Use query_all_iter for large datasets\nfor record in sf.query_all_iter(\"SELECT Id, Name FROM Account\"):\n    print(f\"Account: {record['Name']}\")\n```\n\n### Manual Pagination\n\n```python\nresult = sf.query(\"SELECT Id, Name FROM Account\")\nall_records = result['records']\n\nwhile not result['done']:\n    result = sf.query_more(result['nextRecordsUrl'], identifier_is_url=True)\n    all_records.extend(result['records'])\n\nprint(f\"Total records retrieved: {len(all_records)}\")\n```\n\n### Safe Query with Parameter Formatting\n\n```python\nfrom simple_salesforce.format import format_soql\n\n# Safe parameter substitution\nlast_name = \"O'Brien\"\nquery = format_soql(\"SELECT Id, Email FROM Contact WHERE LastName = {}\", last_name)\nresult = sf.query(query)\n\n# LIKE queries\nname_pattern = \"John\"\nquery = format_soql(\n    \"SELECT Id, Name FROM Contact WHERE Name LIKE '{:like}%'\",\n    name_pattern\n)\nresult = sf.query(query)\n\n# Multiple parameters\nquery = format_soql(\n    \"SELECT Id, Name FROM Account WHERE Industry = {} AND AnnualRevenue > {}\",\n    \"Technology\",\n    1000000\n)\nresult = sf.query(query)\n```\n\n### Query with Date Filters\n\n```python\nfrom datetime import datetime, timedelta\n\n# Query records created in the last 7 days\nseven_days_ago = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%dT%H:%M:%SZ')\nquery = f\"SELECT Id, Name FROM Account WHERE CreatedDate > {seven_days_ago}\"\nresult = sf.query(query)\n```\n\n## SOSL Search\n\n### Basic Search\n\n```python\nresult = sf.search(\n    \"FIND {United*} IN NAME FIELDS RETURNING Account(Id, Name), Contact(Id, Name)\"\n)\n\nprint(f\"Search results: {result['searchRecords']}\")\n\nfor record in result['searchRecords']:\n    print(f\"{record['attributes']['type']}: {record['Name']}\")\n```\n\n## CRUD Operations\n\n### Create Single Record\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token'\n)\n\nresult = sf.Account.create({\n    'Name': 'New Account',\n    'Industry': 'Technology',\n    'BillingCity': 'San Francisco'\n})\n\nprint(f\"Created account ID: {result['id']}\")\nprint(f\"Success: {result['success']}\")\n```\n\n### Create with Error Handling\n\n```python\ntry:\n    result = sf.Account.create({\n        'Name': 'Test Account',\n        'Industry': 'Technology'\n    })\n    print(f\"Created: {result['id']}\")\nexcept Exception as e:\n    print(f\"Error creating account: {e}\")\n```\n\n### Retrieve Single Record by ID\n\n```python\naccount = sf.Account.get('001XXXXXXXXXXXXXXX')\n\nprint(f\"Account Name: {account['Name']}\")\nprint(f\"Industry: {account['Industry']}\")\nprint(f\"Created Date: {account['CreatedDate']}\")\n```\n\n### Retrieve Specific Fields\n\n```python\naccount = sf.Account.get('001XXXXXXXXXXXXXXX', fields=['Id', 'Name', 'Industry'])\n\nprint(f\"Name: {account['Name']}\")\nprint(f\"Industry: {account['Industry']}\")\n```\n\n### Update Single Record\n\n```python\nresult = sf.Account.update('001XXXXXXXXXXXXXXX', {\n    'Name': 'Updated Account Name',\n    'Industry': 'Media'\n})\n\nprint(f\"Updated: {result}\")\n```\n\n### Update Multiple Fields\n\n```python\nresult = sf.Account.update('001XXXXXXXXXXXXXXX', {\n    'Name': 'New Name',\n    'Industry': 'Finance',\n    'BillingCity': 'New York',\n    'Phone': '555-1234'\n})\n```\n\n### Upsert (Update or Insert)\n\n```python\n# Upsert using external ID\nresult = sf.Account.upsert('ExternalId__c/EXT001', {\n    'Name': 'Upserted Account',\n    'Industry': 'Technology',\n    'ExternalId__c': 'EXT001'\n})\n\nif result == 204:\n    print(\"Record updated\")\nelif result == 201:\n    print(\"Record created\")\n```\n\n### Upsert with Response Details\n\n```python\ntry:\n    result = sf.Contact.upsert('Email/[email protected]', {\n        'FirstName': 'John',\n        'LastName': 'Doe',\n        'Email': '[email protected]'\n    }, raw_response=True)\n\n    if result.status_code == 201:\n        print(\"Contact created\")\n    elif result.status_code == 204:\n        print(\"Contact updated\")\nexcept Exception as e:\n    print(f\"Upsert error: {e}\")\n```\n\n### Delete Single Record\n\n```python\nresult = sf.Account.delete('001XXXXXXXXXXXXXXX')\n\nprint(f\"Deleted: {result}\")\n```\n\n### Delete with Error Handling\n\n```python\ntry:\n    sf.Account.delete('001XXXXXXXXXXXXXXX')\n    print(\"Account deleted successfully\")\nexcept Exception as e:\n    print(f\"Error deleting account: {e}\")\n```\n\n## Bulk Operations\n\n### Bulk Insert\n\n```python\nfrom simple_salesforce import Salesforce\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token'\n)\n\n# Prepare data\naccounts = []\nfor i in range(1000):\n    accounts.append({\n        'Name': f'Bulk Account {i}',\n        'Industry': 'Technology'\n    })\n\n# Bulk insert using Bulk 2.0 API\nresult = sf.bulk2.Account.insert(accounts)\n\nprint(f\"Job ID: {result['job_id']}\")\nprint(f\"Records processed: {result['numberRecordsProcessed']}\")\n```\n\n### Bulk Insert from CSV\n\n```python\n# Insert from CSV file\nresult = sf.bulk2.Account.insert('./accounts.csv')\n\nprint(f\"Job ID: {result['job_id']}\")\nprint(f\"Records processed: {result['numberRecordsProcessed']}\")\n```\n\n### Bulk Update\n\n```python\n# Prepare update data\nupdates = []\nfor account_id in account_ids:\n    updates.append({\n        'Id': account_id,\n        'Industry': 'Finance'\n    })\n\nresult = sf.bulk2.Account.update(updates)\n\nprint(f\"Records updated: {result['numberRecordsProcessed']}\")\n```\n\n### Bulk Update from CSV\n\n```python\nresult = sf.bulk2.Account.update('./account_updates.csv')\n\nprint(f\"Job ID: {result['job_id']}\")\n```\n\n### Bulk Delete\n\n```python\n# Prepare delete data (IDs only)\ndeletes = []\nfor account_id in account_ids_to_delete:\n    deletes.append({'Id': account_id})\n\nresult = sf.bulk2.Account.delete(deletes)\n\nprint(f\"Records deleted: {result['numberRecordsProcessed']}\")\n```\n\n### Bulk Upsert\n\n```python\nupserts = []\nfor i in range(100):\n    upserts.append({\n        'ExternalId__c': f'EXT{i}',\n        'Name': f'Bulk Upsert Account {i}',\n        'Industry': 'Technology'\n    })\n\nresult = sf.bulk2.Account.upsert(upserts, 'ExternalId__c')\n\nprint(f\"Records processed: {result['numberRecordsProcessed']}\")\n```\n\n### Get Bulk Job Results\n\n```python\njob_id = 'bulk_job_id_from_insert_or_update'\n\n# Get successful records\nsuccessful = sf.bulk2.Account.get_successful_records(job_id)\nprint(f\"Successful records: {successful}\")\n\n# Get failed records\nfailed = sf.bulk2.Account.get_failed_records(job_id)\nprint(f\"Failed records: {failed}\")\n\n# Save failed records to CSV\nsf.bulk2.Account.get_failed_records(job_id, file='failed_records.csv')\n```\n\n### Bulk Query\n\n```python\n# Bulk 2.0 query for large datasets\nresult = sf.bulk2.Account.query(\"SELECT Id, Name, Industry FROM Account\")\n\nprint(f\"Job ID: {result['job_id']}\")\n\n# Get query results\nquery_results = sf.bulk2.Account.get_query_results(result['job_id'])\n\nfor record in query_results:\n    print(f\"Account: {record['Name']}\")\n```\n\n## SObject Metadata\n\n### Describe SObject\n\n```python\nmetadata = sf.Account.describe()\n\nprint(f\"Label: {metadata['label']}\")\nprint(f\"Updateable: {metadata['updateable']}\")\nprint(f\"Deletable: {metadata['deletable']}\")\nprint(f\"Number of fields: {len(metadata['fields'])}\")\n\nfor field in metadata['fields']:\n    print(f\"  {field['name']} ({field['type']})\")\n```\n\n### Describe All SObjects\n\n```python\nresult = sf.describe()\n\nfor sobject in result['sobjects']:\n    print(f\"{sobject['name']} - {sobject['label']}\")\n```\n\n### Get Field Information\n\n```python\nmetadata = sf.Contact.describe()\n\nfor field in metadata['fields']:\n    if field['name'] == 'Email':\n        print(f\"Type: {field['type']}\")\n        print(f\"Length: {field['length']}\")\n        print(f\"Required: {field['nillable'] == False}\")\n        print(f\"Updateable: {field['updateable']}\")\n```\n\n### Get Picklist Values\n\n```python\nmetadata = sf.Account.describe()\n\nfor field in metadata['fields']:\n    if field['name'] == 'Industry' and field['type'] == 'picklist':\n        print(\"Industry picklist values:\")\n        for value in field['picklistValues']:\n            print(f\"  - {value['value']}\")\n```\n\n## Apex REST API\n\n### Call Custom Apex REST Endpoint (GET)\n\n```python\n# Call GET endpoint\nresult = sf.apexecute('MyApexRestService', method='GET')\n\nprint(f\"Response: {result}\")\n```\n\n### Call Custom Apex REST Endpoint (POST)\n\n```python\npayload = {\n    'name': 'Test',\n    'value': 123,\n    'active': True\n}\n\nresult = sf.apexecute('MyApexRestService', method='POST', data=payload)\n\nprint(f\"Response: {result}\")\n```\n\n### Call Custom Apex REST Endpoint (PUT)\n\n```python\npayload = {\n    'name': 'Updated Name',\n    'value': 456\n}\n\nresult = sf.apexecute('MyApexRestService/recordId', method='PUT', data=payload)\n\nprint(f\"Response: {result}\")\n```\n\n### Call Custom Apex REST Endpoint (DELETE)\n\n```python\nresult = sf.apexecute('MyApexRestService/recordId', method='DELETE')\n\nprint(f\"Response: {result}\")\n```\n\n### Call with URL Parameters\n\n```python\nresult = sf.apexecute('MyApexRestService', method='GET', params={'filter': 'active'})\n\nprint(f\"Response: {result}\")\n```\n\n## Generic REST API Requests\n\n### GET Request\n\n```python\n# Make a generic GET request\nresult = sf.restful('sobjects/Account/001XXXXXXXXXXXXXXX')\n\nprint(f\"Account: {result}\")\n```\n\n### POST Request\n\n```python\ndata = {\n    'Name': 'New Account',\n    'Industry': 'Technology'\n}\n\nresult = sf.restful('sobjects/Account', method='POST', data=data)\n\nprint(f\"Created: {result}\")\n```\n\n### Custom API Endpoint\n\n```python\n# Call a custom REST endpoint\nresult = sf.restful('services/apexrest/CustomEndpoint', method='GET')\n\nprint(f\"Response: {result}\")\n```\n\n## Advanced Features\n\n### Set API Version\n\n```python\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    version='58.0'\n)\n```\n\n### Disable SSL Verification (Not Recommended)\n\n```python\nimport urllib3\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    security_token_bypass=True,\n    session=None\n)\n```\n\n### Custom Timeout\n\n```python\nimport requests\nfrom simple_salesforce import Salesforce\n\nsession = requests.Session()\nsession.timeout = 60  # 60 seconds\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    session=session\n)\n```\n\n### Proxies\n\n```python\nimport requests\nfrom simple_salesforce import Salesforce\n\nsession = requests.Session()\nsession.proxies = {\n    'http': 'http://proxy.example.com:8080',\n    'https': 'https://proxy.example.com:8080'\n}\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    session=session\n)\n```\n\n### Custom Headers\n\n```python\nimport requests\nfrom simple_salesforce import Salesforce\n\nsession = requests.Session()\nsession.headers.update({\n    'Custom-Header': 'value',\n    'Another-Header': 'another-value'\n})\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    session=session\n)\n```\n\n## Composite API\n\n### Composite Request\n\n```python\ncomposite_request = {\n    'compositeRequest': [\n        {\n            'method': 'POST',\n            'url': '/services/data/v58.0/sobjects/Account',\n            'referenceId': 'NewAccount',\n            'body': {\n                'Name': 'Composite Account'\n            }\n        },\n        {\n            'method': 'POST',\n            'url': '/services/data/v58.0/sobjects/Contact',\n            'referenceId': 'NewContact',\n            'body': {\n                'FirstName': 'John',\n                'LastName': 'Doe',\n                'AccountId': '@{NewAccount.id}'\n            }\n        }\n    ]\n}\n\nresult = sf.restful(\n    'composite',\n    method='POST',\n    data=composite_request\n)\n\nprint(f\"Composite results: {result}\")\n```\n\n## Working with Attachments\n\n### Upload Attachment\n\n```python\nimport base64\n\nwith open('document.pdf', 'rb') as f:\n    file_data = base64.b64encode(f.read()).decode()\n\nresult = sf.Attachment.create({\n    'Name': 'document.pdf',\n    'ParentId': '001XXXXXXXXXXXXXXX',  # Record ID\n    'Body': file_data,\n    'ContentType': 'application/pdf'\n})\n\nprint(f\"Attachment ID: {result['id']}\")\n```\n\n### Download Attachment\n\n```python\nimport base64\n\nattachment = sf.Attachment.get('00PXXXXXXXXXXXXXXX')\nfile_data = base64.b64decode(attachment['Body'])\n\nwith open('downloaded_file.pdf', 'wb') as f:\n    f.write(file_data)\n```\n\n## Working with ContentVersion (Files)\n\n### Upload File\n\n```python\nimport base64\n\nwith open('document.pdf', 'rb') as f:\n    file_data = base64.b64encode(f.read()).decode()\n\nresult = sf.ContentVersion.create({\n    'Title': 'My Document',\n    'PathOnClient': 'document.pdf',\n    'VersionData': file_data,\n    'FirstPublishLocationId': '001XXXXXXXXXXXXXXX'  # Record ID\n})\n\nprint(f\"ContentVersion ID: {result['id']}\")\n```\n\n### Query Files\n\n```python\nresult = sf.query(\n    \"SELECT Id, Title, FileType FROM ContentDocument WHERE Title LIKE '%Report%'\"\n)\n\nfor doc in result['records']:\n    print(f\"Document: {doc['Title']} ({doc['FileType']})\")\n```\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom simple_salesforce import Salesforce, SalesforceAuthenticationFailed\n\ntry:\n    sf = Salesforce(\n        username='user@example.org',\n        password='wrong_password',\n        security_token='token'\n    )\nexcept SalesforceAuthenticationFailed as e:\n    print(f\"Authentication failed: {e}\")\n```\n\n### CRUD Error Handling\n\n```python\nfrom simple_salesforce.exceptions import SalesforceError\n\ntry:\n    result = sf.Account.create({\n        'Name': ''  # Required field missing\n    })\nexcept SalesforceError as e:\n    print(f\"Error code: {e.status}\")\n    print(f\"Error message: {e.content}\")\n```\n\n### Query Error Handling\n\n```python\ntry:\n    result = sf.query(\"SELECT Id, InvalidField FROM Account\")\nexcept SalesforceError as e:\n    print(f\"Query error: {e}\")\n```\n\n### Generic Exception Handling\n\n```python\nimport requests\n\ntry:\n    result = sf.Account.update('001XXXXXXXXXXXXXXX', {\n        'Name': 'Updated Name'\n    })\nexcept requests.exceptions.Timeout:\n    print(\"Request timed out\")\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection error\")\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n## Best Practices\n\n### Batch Processing\n\n```python\ndef process_accounts_in_batches(account_ids, batch_size=200):\n    for i in range(0, len(account_ids), batch_size):\n        batch = account_ids[i:i + batch_size]\n\n        # Build query for batch\n        ids_str = \"','\".join(batch)\n        query = f\"SELECT Id, Name FROM Account WHERE Id IN ('{ids_str}')\"\n\n        result = sf.query(query)\n\n        for record in result['records']:\n            # Process each record\n            print(f\"Processing: {record['Name']}\")\n```\n\n### Retry Logic\n\n```python\nimport time\nfrom simple_salesforce.exceptions import SalesforceError\n\ndef create_with_retry(sobject, data, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            result = getattr(sf, sobject).create(data)\n            return result\n        except SalesforceError as e:\n            if attempt < max_retries - 1:\n                wait_time = 2 ** attempt  # Exponential backoff\n                print(f\"Retry {attempt + 1} after {wait_time}s\")\n                time.sleep(wait_time)\n            else:\n                raise\n```\n\n### Connection Pooling\n\n```python\nimport requests\nfrom requests.adapters import HTTPAdapter\nfrom urllib3.util.retry import Retry\nfrom simple_salesforce import Salesforce\n\ndef create_sf_session():\n    session = requests.Session()\n\n    retry_strategy = Retry(\n        total=3,\n        status_forcelist=[429, 500, 502, 503, 504],\n        method_whitelist=[\"HEAD\", \"GET\", \"OPTIONS\", \"POST\", \"PATCH\", \"PUT\"]\n    )\n\n    adapter = HTTPAdapter(max_retries=retry_strategy)\n    session.mount(\"https://\", adapter)\n    session.mount(\"http://\", adapter)\n\n    return session\n\nsf = Salesforce(\n    username='user@example.org',\n    password='your_password',\n    security_token='your_security_token',\n    session=create_sf_session()\n)\n```\n\n### Efficient Field Selection\n\n```python\n# Only query fields you need\nresult = sf.query(\n    \"SELECT Id, Name, Industry FROM Account LIMIT 100\"\n)\n\n# Instead of:\n# result = sf.query(\"SELECT Id, Name, Industry, ... (all fields) FROM Account LIMIT 100\")\n```\n\n### Use Bulk API for Large Data Sets\n\n```python\n# For < 2000 records, use regular API\nif len(records) < 2000:\n    for record in records:\n        sf.Account.create(record)\nelse:\n    # For >= 2000 records, use Bulk API\n    sf.bulk2.Account.insert(records)\n```\n\n## Complete Example Application\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom simple_salesforce import Salesforce, SalesforceAuthenticationFailed\nfrom simple_salesforce.exceptions import SalesforceError\n\n# Load environment variables\nload_dotenv()\n\ndef main():\n    try:\n        # Initialize connection\n        sf = Salesforce(\n            username=os.getenv('SALESFORCE_USERNAME'),\n            password=os.getenv('SALESFORCE_PASSWORD'),\n            security_token=os.getenv('SALESFORCE_SECURITY_TOKEN')\n        )\n\n        print(\"Connected to Salesforce successfully!\")\n\n        # Create account\n        account_result = sf.Account.create({\n            'Name': 'Example Corp',\n            'Industry': 'Technology',\n            'BillingCity': 'San Francisco'\n        })\n        account_id = account_result['id']\n        print(f\"Created account: {account_id}\")\n\n        # Create contact\n        contact_result = sf.Contact.create({\n            'FirstName': 'John',\n            'LastName': 'Doe',\n            'Email': '[email protected]',\n            'AccountId': account_id\n        })\n        contact_id = contact_result['id']\n        print(f\"Created contact: {contact_id}\")\n\n        # Query accounts with contacts\n        result = sf.query(f\"\"\"\n            SELECT Id, Name, Industry,\n                   (SELECT Id, Name, Email FROM Contacts)\n            FROM Account\n            WHERE Id = '{account_id}'\n        \"\"\")\n\n        for account in result['records']:\n            print(f\"\\nAccount: {account['Name']}\")\n            if account.get('Contacts'):\n                for contact in account['Contacts']['records']:\n                    print(f\"  Contact: {contact['Name']} - {contact['Email']}\")\n\n        # Update account\n        sf.Account.update(account_id, {\n            'Industry': 'Finance'\n        })\n        print(f\"\\nUpdated account industry\")\n\n        # Clean up - delete records\n        sf.Contact.delete(contact_id)\n        sf.Account.delete(account_id)\n        print(\"\\nCleaned up test data\")\n\n    except SalesforceAuthenticationFailed as e:\n        print(f\"Authentication failed: {e}\")\n    except SalesforceError as e:\n        print(f\"Salesforce API error: {e}\")\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n\nif __name__ == '__main__':\n    main()\n```\n\n## Useful Links\n\n- Documentation: https://simple-salesforce.readthedocs.io/\n- GitHub: https://github.com/simple-salesforce/simple-salesforce\n- PyPI: https://pypi.org/project/simple-salesforce/\n- Salesforce Developer Docs: https://developer.salesforce.com/\n- Salesforce REST API Guide: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/\n- SOQL Reference: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/\n"
  },
  {
    "path": "content/salt/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Salt package guide for Python infrastructure automation, master/minion setup, states, and Python API usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"3007.13\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"salt,python,configuration-management,orchestration,remote-execution,states\"\n---\n\n# Salt Python Package Guide\n\n## Golden Rule\n\nUse the official Salt packages for production `salt-master` and `salt-minion` installs, and treat `pip install salt` as development or embedded usage with only reasonable-effort support. When you use Salt's Python APIs, run them on the master or minion host they target, and on onedir installs use Salt's bundled Python runtime instead of the system interpreter.\n\n## Install\n\nPreferred production path: use Salt's official packages from the install guide so you get the supported service layout, bundled runtime, and service units.\n\nFor a virtualenv, CI image, or local tooling experiment, install from PyPI:\n\n```bash\npython -m pip install \"salt==3007.13\"\n```\n\nIf you want a clean isolated environment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"salt==3007.13\"\n```\n\nImportant install notes:\n\n- Salt's install guide says `pip` installs receive only reasonable-effort support.\n- Salt's official onedir packages ship their own Python runtime. In the 3007 STS line, the packaged runtime is Python `3.10.x`.\n- If you install extra Python dependencies into an onedir Salt install, use Salt's bundled tooling and runtime, not the system `pip`.\n\n## Initialize A Master And Minion\n\nSalt's standard deployment model is a master that publishes jobs and one or more minions that execute them.\n\nMaster configuration lives in:\n\n- `/etc/salt/master`\n- `/etc/salt/master.d/*.conf`\n\nMinion configuration lives in:\n\n- `/etc/salt/minion`\n- `/etc/salt/minion.d/*.conf`\n\nMinimal minion configuration:\n\n```yaml\n# /etc/salt/minion.d/master.conf\nmaster: salt-master.example.internal\nid: web-01\n```\n\nBy default, the master listens on ports `4505` and `4506` on all interfaces, so restrict network access accordingly.\n\nStart the services, then accept the minion key on the master:\n\n```bash\nsudo systemctl enable --now salt-master\nsudo systemctl enable --now salt-minion\n\nsudo salt-key -L\nsudo salt-key -a web-01\n```\n\nSmoke test the connection:\n\n```bash\nsudo salt \"*\" test.ping\n```\n\n## Masterless Setup\n\nFor local-only state application, use `salt-call --local` and set the minion to local file mode:\n\n```yaml\n# /etc/salt/minion.d/local.conf\nfile_client: local\nfile_roots:\n  base:\n    - /srv/salt\npillar_roots:\n  base:\n    - /srv/pillar\n```\n\nThen apply states directly on the host:\n\n```bash\nsudo salt-call --local state.apply\n```\n\nThis is the simplest way to use Salt as a local configuration engine without standing up a master.\n\n## Core Usage\n\n### Remote execution\n\n```bash\nsudo salt \"*\" test.ping\nsudo salt \"web-*\" cmd.run \"whoami\"\nsudo salt \"db-*\" pkg.version postgresql\n```\n\nTargeting is a major part of Salt. Start with simple glob targets, then move to grains, pillars, or compound targeting only when the simpler matchers are insufficient.\n\n### States\n\nSalt state files live under the state tree, typically `/srv/salt`. The top file maps targets to states:\n\n```yaml\n# /srv/salt/top.sls\nbase:\n  \"web-*\":\n    - nginx\n```\n\n```yaml\n# /srv/salt/nginx.sls\nnginx:\n  pkg.installed: []\n  service.running:\n    - enable: true\n```\n\nApply all matching states:\n\n```bash\nsudo salt \"*\" state.apply\n```\n\nApply a specific state:\n\n```bash\nsudo salt \"web-01\" state.apply nginx\n```\n\nDo not put pillar data under `file_roots`; keep it under `pillar_roots` so pillar targeting rules still apply.\n\n### Python API from the master\n\nThe most useful Python entry point for automation on the master is `salt.client.LocalClient`:\n\n```python\nimport salt.client\n\nclient = salt.client.LocalClient()\n\nping = client.cmd(\"web-*\", \"test.ping\")\nversions = client.cmd(\"web-*\", \"test.version\")\n\nprint(ping)\nprint(versions)\n```\n\nA state run from Python:\n\n```python\nimport salt.client\n\nclient = salt.client.LocalClient()\n\nresult = client.cmd(\"web-01\", \"state.apply\", [\"nginx\"])\nprint(result)\n```\n\n`LocalClient` talks to the master's publish and return system, so it should run on the master host and under the same user context as the master process.\n\n## Configuration And Authentication\n\nSalt has two distinct auth layers that agents often blur together:\n\n1. Master-to-minion trust uses key acceptance. A minion is not manageable until its key is accepted on the master.\n2. Human or service access to Salt interfaces uses external authentication (`external_auth`) for CLI, API, runner, and wheel access.\n\nMinimal `external_auth` example:\n\n```yaml\n# /etc/salt/master.d/eauth.conf\nexternal_auth:\n  pam:\n    ci-bot:\n      - \"web-*\":\n        - test.*\n        - state.apply\n```\n\nExample CLI call using external auth:\n\n```bash\nsalt -a pam \"web-*\" test.version\n```\n\nIf you expose a REST interface, configure auth and TLS explicitly. Salt's netapi docs distinguish lightweight WSGI integration from the more feature-complete CherryPy-based API app; do not expose either one with broad unauthenticated network access.\n\n## Common Pitfalls\n\n- `pip install salt` is not the primary supported deployment path for production daemons.\n- On onedir installs, Python scripts that import `salt.*` must run with Salt's bundled Python runtime.\n- `LocalClient` is a master-side API, not a general remote client you can run anywhere on the network.\n- New minions will show up in `salt-key` but cannot execute jobs until their keys are accepted.\n- The master listens on `4505` and `4506` on all interfaces by default. Do not leave those ports broadly exposed.\n- Salt loads configuration from the main file and every `*.conf` file under the matching `.d/` directory. Duplicate settings can override each other unexpectedly.\n- Keep pillar data in `pillar_roots`, not `file_roots`.\n- The installation docs warn against running an open master on the public internet because it is a vulnerability.\n\n## Version-Sensitive Notes For 3007.13\n\n- As of `2026-03-12`, PyPI lists `salt 3007.13`, released on `2026-02-12`.\n- The docs URL used `https://docs.saltproject.io/en/latest/ref/`, which is a moving stable-reference root. For this package doc, the canonical versioned docs root is `https://docs.saltproject.io/en/3007/`.\n- Salt's 3007 STS install guide documents official packages with a bundled Python `3.10.x` runtime. Do not assume that packaged installs follow your system Python version just because the PyPI package supports `>=3.8`.\n- Since `3006.0`, official Salt packages run the master as the `salt` user rather than `root`. Scripts, custom paths, and file permissions that assumed a root-owned master need to be checked on modern installs.\n- `cluster_id` is new in the 3007 line for clustered masters. If you are building HA or clustered topologies, use the 3007 docs instead of older cluster guides.\n\n## Official Sources\n\n- Salt reference docs: `https://docs.saltproject.io/en/3007/`\n- Salt install guide: `https://docs.saltproject.io/salt/install-guide/en/latest/`\n- Salt Python client API: `https://docs.saltproject.io/en/3007/ref/clients/index.html`\n- Salt master config reference: `https://docs.saltproject.io/en/3007/ref/configuration/master.html`\n- Salt minion config reference: `https://docs.saltproject.io/en/3007/ref/configuration/minion.html`\n- Salt states tutorial: `https://docs.saltproject.io/en/3007/topics/tutorials/starting_states.html`\n- Salt top file reference: `https://docs.saltproject.io/en/3007/ref/states/top.html`\n- Salt external auth tutorial: `https://docs.saltproject.io/en/latest/topics/eauth/index.html`\n- Salt netapi docs: `https://docs.saltproject.io/en/latest/ref/netapi/all/index.html`\n- PyPI package page: `https://pypi.org/project/salt/`\n"
  },
  {
    "path": "content/sanic/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Sanic package guide for Python async web servers, APIs, and websockets\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.12.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sanic,python,web,async,asgi,http,websocket\"\n---\n\n# Sanic Python Package Guide\n\n## What It Is\n\nSanic is an async Python web framework with its own production server. It is a good fit for HTTP APIs, websocket endpoints, background task orchestration, and ASGI-compatible deployment.\n\nThis entry is scoped to package version `25.12.0`. Sanic `25.12` is the current LTS line, and it raises the Python floor to `3.10+`.\n\n## Install\n\n```bash\npip install sanic==25.12.0\n```\n\n```bash\nuv add sanic==25.12.0\n```\n\n```bash\npoetry add sanic==25.12.0\n```\n\nSanic will use `uvloop` and `ujson` when available. If you need to build without them, set the install-time flags first:\n\n```bash\nexport SANIC_NO_UVLOOP=true\nexport SANIC_NO_UJSON=true\npip install --no-binary :all: sanic==25.12.0\n```\n\nOptional companion packages:\n\n- `pip install sanic-testing` for the official test client\n- `pip install sanic-ext` if you need extension features like validation, OpenAPI, or dependency injection\n\n## Minimal App\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import json\n\napp = Sanic(\"myapp\")\n\n@app.get(\"/health\")\nasync def health(_request):\n    return json({\"ok\": True})\n```\n\nRun it with the Sanic CLI:\n\n```bash\nsanic server:app --host=0.0.0.0 --port=8000 --reload\n```\n\nSanic's own server is the default deployment path the upstream docs recommend in most cases.\n\n## App Factory\n\nUse a factory when configuration or dependency setup depends on runtime state.\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import json\n\ndef create_app() -> Sanic:\n    app = Sanic(\"myapp\")\n\n    @app.get(\"/health\")\n    async def health(_request):\n        return json({\"ok\": True})\n\n    return app\n```\n\n```bash\nsanic server:create_app --factory --reload\n```\n\n## Core Request And Response Usage\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import html, json, redirect, text\n\napp = Sanic(\"api\")\n\n@app.get(\"/items/<item_id:int>\")\nasync def get_item(request, item_id: int):\n    expand = request.args.get(\"expand\")\n    return json({\"item_id\": item_id, \"expand\": expand})\n\n@app.post(\"/items\")\nasync def create_item(request):\n    payload = request.json or {}\n    if \"name\" not in payload:\n        return json({\"error\": \"name is required\"}, status=400)\n    return json({\"created\": payload[\"name\"]}, status=201)\n\n@app.post(\"/upload\")\nasync def upload(request):\n    file = request.files.get(\"file\")\n    if not file:\n        return text(\"missing file\", status=400)\n    return json({\"filename\": file.name, \"content_type\": file.type})\n\n@app.get(\"/docs\")\nasync def docs(_request):\n    return redirect(\"https://sanic.dev/\")\n\n@app.get(\"/status\")\nasync def status(_request):\n    return html(\"<strong>ok</strong>\")\n```\n\nRequest APIs you will use most:\n\n- `request.json` for parsed JSON bodies\n- `request.body` for raw bytes\n- `request.form` for form fields\n- `request.files` for multipart file uploads\n- `request.args` for query params\n- `request.ctx` for per-request state\n\n`request.args`, `request.form`, and `request.files` are multi-value containers. Use `.getlist()` when repeated keys matter.\n\n## Shared State And Lifecycle\n\nUse `app.ctx` for long-lived shared objects. Use `request.ctx` for request-local state.\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import json\n\napp = Sanic(\"svc\")\n\n@app.before_server_start\nasync def open_clients(app):\n    app.ctx.http = await make_http_client()\n    app.ctx.db = await make_db_pool()\n\n@app.after_server_stop\nasync def close_clients(app):\n    await app.ctx.http.aclose()\n    await app.ctx.db.close()\n\n@app.get(\"/users/<user_id:int>\")\nasync def get_user(request, user_id: int):\n    user = await request.app.ctx.db.fetch_user(user_id)\n    return json(user)\n```\n\nKeep database pools, caches, and shared HTTP clients on `app.ctx`. Avoid module-level mutable globals when running multiple workers.\n\n## Middleware And Auth Pattern\n\nSanic does not ship a full authentication framework. The common pattern is:\n\n1. read auth data from the request\n2. validate it in middleware or a decorator\n3. store the resolved principal on `request.ctx`\n\n`request.token` extracts `Authorization: Bearer ...` and `Authorization: Token ...` headers.\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import json\n\napp = Sanic(\"authapp\")\n\n@app.middleware(\"request\")\nasync def load_user(request):\n    token = request.token\n    request.ctx.user = await lookup_user_from_token(token) if token else None\n    if token and not request.ctx.user:\n        return json({\"error\": \"unauthorized\"}, status=401)\n\n@app.get(\"/me\")\nasync def me(request):\n    if not request.ctx.user:\n        return json({\"error\": \"unauthorized\"}, status=401)\n    return json({\"id\": request.ctx.user.id})\n```\n\nIf request middleware returns an `HTTPResponse`, Sanic stops processing and the handler does not run.\n\n## Configuration\n\nSanic configuration lives on `app.config`. Use uppercase keys.\n\n```python\nfrom sanic import Sanic\n\napp = Sanic(\"cfg\")\napp.config.REQUEST_TIMEOUT = 30\napp.config.RESPONSE_TIMEOUT = 30\napp.config.KEEP_ALIVE_TIMEOUT = 120\napp.config.FALLBACK_ERROR_FORMAT = \"json\"\n```\n\nEnvironment variables prefixed with `SANIC_` are loaded into config by default:\n\n```bash\nexport SANIC_REQUEST_TIMEOUT=10\nexport SANIC_RESPONSE_TIMEOUT=30\nexport SANIC_KEEP_ALIVE_TIMEOUT=60\n```\n\n```python\nfrom sanic import Sanic\n\napp = Sanic(\"cfg\")\nprint(app.config.REQUEST_TIMEOUT)\n```\n\nIf you do not want implicit env loading:\n\n```python\nfrom sanic import Sanic\n\napp = Sanic(\"cfg\", load_env=False)\n```\n\nSanic `25.12` extends config converters with `DetailedConverter`, which is useful if you need custom environment-to-config parsing beyond the default type coercion.\n\n## Blueprints, Websockets, And Background Tasks\n\nUse blueprints once routes start to split by feature area.\n\n```python\nfrom sanic import Blueprint, Sanic\nfrom sanic.response import json\n\nusers = Blueprint(\"users\", url_prefix=\"/users\")\n\n@users.get(\"/<user_id:int>\")\nasync def get_user(_request, user_id: int):\n    return json({\"user_id\": user_id})\n\napp = Sanic(\"svc\")\napp.blueprint(users)\n```\n\nWebsocket routes are first-class:\n\n```python\nfrom sanic import Sanic\n\napp = Sanic(\"ws\")\n\n@app.websocket(\"/ws\")\nasync def echo(_request, ws):\n    async for message in ws:\n        await ws.send(message)\n```\n\nFor app-managed tasks:\n\n```python\ntask = app.add_task(refresh_index())\n```\n\nIn `25.12`, `app.add_task()` returns the created task object, which makes later tracking or cancellation easier.\n\n## Running And Deployment\n\nPreferred server modes:\n\n```bash\nsanic server:app --host=0.0.0.0 --port=8000 --workers=4\n```\n\n```bash\nsanic server:app --fast\n```\n\nImportant deployment notes:\n\n- `--workers` uses Sanic's worker manager for multi-process serving\n- `--fast` chooses a maximum worker count automatically\n- `--single-process` disables the worker manager and some reload/process-management features\n- daemon mode is available in `25.12` if you need to detach the Sanic server process\n\nASGI deployment is also supported:\n\n```bash\nuvicorn myapp:app\nhypercorn myapp:app\n```\n\nIn ASGI mode, startup and shutdown semantics follow the ASGI server lifecycle instead of Sanic's native multi-process server lifecycle. Treat that as a deployment change, not a transparent drop-in.\n\n## Testing\n\nInstall the official test companion:\n\n```bash\npip install sanic-testing\n```\n\nTypical usage:\n\n```python\nfrom sanic import Sanic\nfrom sanic.response import json\n\napp = Sanic(\"test-app\")\n\n@app.get(\"/ping\")\nasync def ping(_request):\n    return json({\"pong\": True})\n\ndef test_ping():\n    _, response = app.test_client.get(\"/ping\")\n    assert response.status_code == 200\n    assert response.json == {\"pong\": True}\n```\n\nIf `app.test_client` or `app.asgi_client` is missing, you probably forgot to install `sanic-testing`.\n\n## Common Pitfalls\n\n- Do not use `https://sanic.readthedocs.io/en/stable/` as your primary reference for this package version. It still serves `23.12.0`.\n- Sanic `25.12.0` requires Python `3.10+`. Older project templates that still allow `3.8` or `3.9` are stale.\n- Do not put blocking work like `time.sleep()` or sync database clients inside handlers. Use async libraries or move work off the event loop.\n- `request.args`, `request.form`, and `request.files` can hold repeated values. Use `.getlist()` when shape matters.\n- Put shared resources on `app.ctx`, not `request.ctx`.\n- Returning a response from request middleware short-circuits the rest of the request pipeline.\n- `sanic-testing` is a separate package by design.\n- If you deploy through an ASGI server, verify lifecycle and websocket behavior in that mode instead of assuming Sanic's native server semantics.\n\n## Version-Sensitive Notes For `25.12.0`\n\n- `25.12` is the current LTS line.\n- Sanic `25.12` drops Python `3.9` and adds Python `3.14` support.\n- Daemon mode was added in `25.12`.\n- Configuration converters gained `DetailedConverter` in `25.12`.\n- Static file text responses now add `charset=UTF-8` automatically in `25.12`.\n- `app.add_task()` now returns the created task object.\n\n## Official Sources\n\n- User guide: `https://sanic.dev/en/guide/`\n- Running guide: `https://sanic.dev/en/guide/running/running.html`\n- Configuration guide: `https://sanic.dev/en/guide/running/configuration.html`\n- Request guide: `https://sanic.dev/en/guide/basics/request.html`\n- App guide: `https://sanic.dev/en/guide/basics/app.html`\n- Middleware guide: `https://sanic.dev/en/guide/basics/middleware.html`\n- Blueprints guide: `https://sanic.dev/en/guide/best-practices/blueprints.html`\n- Authentication guide: `https://sanic.dev/en/guide/how-to/authentication.html`\n- Testing guide: `https://sanic.dev/en/plugins/sanic-testing/clients.html`\n- `25.12` release notes: `https://sanic.dev/en/release-notes/2025/v25.12.html`\n- Changelog: `https://sanic.dev/en/release-notes/changelog.html`\n- PyPI release page: `https://pypi.org/project/sanic/25.12.0/`\n"
  },
  {
    "path": "content/schedule/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"schedule Python job scheduler for lightweight in-process recurring tasks\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"schedule,scheduler,jobs,cron,tasks,python\"\n---\n\n# schedule Python Package Guide\n\n## Golden Rule\n\nUse `schedule` for lightweight in-process recurring jobs that can run inside a single Python process. It does not provide persistence, distributed coordination, job retries, or true cron semantics, so use it for app-local automation loops, not as a replacement for Celery, APScheduler-backed stores, or system cron.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"schedule==1.2.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"schedule==1.2.2\"\npoetry add \"schedule==1.2.2\"\n```\n\nTimezone-aware `.at(..., timezone)` usage depends on `pytz`:\n\n```bash\npython -m pip install \"schedule==1.2.2\" pytz\n```\n\n## Initialize And Run Jobs\n\nMinimal recurring loop:\n\n```python\nimport time\n\nimport schedule\n\ndef job() -> None:\n    print(\"running task\")\n\nschedule.every(10).seconds.do(job)\nschedule.every().minute.do(job)\nschedule.every().hour.do(job)\nschedule.every().day.at(\"10:30\").do(job)\n\nwhile True:\n    schedule.run_pending()\n    time.sleep(1)\n```\n\nImportant behavior:\n\n- Jobs run only when your process calls `run_pending()`\n- Missed jobs are not replayed later; `run_pending()` intentionally runs each due job once\n- By default jobs run serially on the same thread\n\nIf you want the loop to sleep exactly until the next job, use `idle_seconds()`:\n\n```python\nimport time\n\nimport schedule\n\ndef job() -> None:\n    print(\"tick\")\n\nschedule.every(5).minutes.do(job)\n\nwhile True:\n    schedule.run_pending()\n    idle_for = schedule.idle_seconds()\n    time.sleep(idle_for if idle_for is not None else 1)\n```\n\n## Core Usage\n\n### Pass arguments to jobs\n\n```python\nimport schedule\n\ndef greet(name: str, punctuation: str = \"!\") -> None:\n    print(f\"hello {name}{punctuation}\")\n\nschedule.every().day.at(\"09:00\").do(greet, \"team\", punctuation=\".\")\n```\n\n### Use ranges and stop conditions\n\nRandomized intervals:\n\n```python\nimport schedule\n\ndef poll() -> None:\n    print(\"polling\")\n\nschedule.every(5).to(10).seconds.do(poll)\n```\n\nStop scheduling after a deadline:\n\n```python\nimport schedule\n\ndef reminder() -> None:\n    print(\"still active\")\n\nschedule.every().hour.until(\"18:30\").do(reminder)\nschedule.every().day.until(\"2030-01-01 00:00\").do(reminder)\n```\n\n### Cancel jobs explicitly or from inside a job\n\n```python\nimport schedule\n\ndef run_once():\n    print(\"only once\")\n    return schedule.CancelJob\n\njob = schedule.every().minute.do(run_once)\n\n# Later:\nschedule.cancel_job(job)\n```\n\n### Tag and clear jobs\n\n```python\nimport schedule\n\ndef sync() -> None:\n    print(\"sync\")\n\nschedule.every().minute.do(sync).tag(\"sync\", \"network\")\nschedule.every().hour.do(sync).tag(\"hourly\")\n\nschedule.clear(\"sync\")\n```\n\n### Keep separate schedulers\n\nUse `Scheduler()` when you need isolated job sets instead of the module-global default scheduler:\n\n```python\nimport time\n\nfrom schedule import Scheduler\n\nfast = Scheduler()\nslow = Scheduler()\n\nfast.every(5).seconds.do(lambda: print(\"fast\"))\nslow.every().hour.do(lambda: print(\"slow\"))\n\nwhile True:\n    fast.run_pending()\n    slow.run_pending()\n    time.sleep(1)\n```\n\n### Use the decorator helper\n\n`@repeat(...)` is a convenience wrapper for no-argument callables:\n\n```python\nimport time\n\nimport schedule\nfrom schedule import repeat, every\n\n@repeat(every(10).seconds)\ndef heartbeat() -> None:\n    print(\"alive\")\n\nwhile True:\n    schedule.run_pending()\n    time.sleep(1)\n```\n\nIt does not work on non-static class methods.\n\n## Time And Timezone Configuration\n\nBasic `.at()` examples:\n\n```python\nimport schedule\n\nschedule.every().day.at(\"12:42\").do(lambda: print(\"lunch\"))\nschedule.every().hour.at(\":17\").do(lambda: print(\"minute 17\"))\nschedule.every().minute.at(\":23\").do(lambda: print(\"second 23\"))\n```\n\nTimezone-aware scheduling:\n\n```python\nimport schedule\n\nschedule.every().day.at(\"12:42\", \"Europe/Amsterdam\").do(lambda: print(\"ams\"))\n```\n\nNotes:\n\n- Timezone support in `.at()` requires `pytz`\n- Internally, `schedule` stores naive datetimes in the process's local timezone\n- Relative schedules such as `every(4).hours` are not DST-aware; only `.at()` handles timezone conversions\n\n## Background Threads And Parallel Work\n\nIf your main thread is doing other work, run the scheduler loop in a background thread:\n\n```python\nimport threading\nimport time\n\nimport schedule\n\ndef job() -> None:\n    print(\"background\")\n\ndef run_scheduler() -> None:\n    while not stop_event.is_set():\n        schedule.run_pending()\n        time.sleep(1)\n\nschedule.every(30).seconds.do(job)\n\nstop_event = threading.Event()\nthread = threading.Thread(target=run_scheduler, daemon=True)\nthread.start()\n```\n\nFor parallel execution, the docs recommend moving each job into its own thread or queueing work yourself. Long-running jobs block later jobs when you use the default scheduler loop.\n\n## Error Handling And Logging\n\n`schedule` does not catch exceptions raised by your jobs. If a job can fail, wrap it yourself so one exception does not terminate the scheduling loop:\n\n```python\nimport functools\nimport logging\nimport time\n\nimport schedule\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\ndef catch_exceptions(cancel_on_failure: bool = False):\n    def decorator(job_func):\n        @functools.wraps(job_func)\n        def wrapper(*args, **kwargs):\n            try:\n                return job_func(*args, **kwargs)\n            except Exception:\n                logger.exception(\"scheduled job failed\")\n                if cancel_on_failure:\n                    return schedule.CancelJob\n\n        return wrapper\n\n    return decorator\n\n@catch_exceptions(cancel_on_failure=False)\ndef flaky_job() -> None:\n    raise RuntimeError(\"boom\")\n\nschedule.every(10).seconds.do(flaky_job)\n\nwhile True:\n    schedule.run_pending()\n    time.sleep(1)\n```\n\n## Common Pitfalls\n\n- `schedule` is an in-process scheduler. Jobs disappear when the process exits.\n- `run_pending()` does not \"catch up\" for missed intervals during downtime or long sleeps.\n- Jobs run serially unless you explicitly add threads or a work queue.\n- A blocking or slow job delays every later job on the same scheduler.\n- `.at(..., timezone)` needs `pytz`; without it you will hit import or timezone-resolution errors.\n- `@repeat` is convenient but limited; use `.do(...)` directly when you need arguments, methods, or more control.\n- Time-sensitive production workflows often need monitoring, persistence, and retries that `schedule` does not provide.\n\n## Version-Sensitive Notes For 1.2.2\n\n- PyPI currently lists `schedule 1.2.2`, while the stable ReadTheDocs site is still branded `1.2.0`. Use the docs for API behavior, but treat PyPI as the current package-version source.\n- The official history for `1.2.2` notes Python 3.12 support and timezone-related fixes; those changes are newer than the version banner shown on ReadTheDocs.\n- The docs say the project is tested on Python 3.7 through 3.11, but PyPI classifiers include Python 3.12 for the current package release.\n\n## Official Sources\n\n- Docs: `https://schedule.readthedocs.io/en/stable/`\n- Examples: `https://schedule.readthedocs.io/en/stable/examples.html`\n- Reference: `https://schedule.readthedocs.io/en/stable/reference.html`\n- Timezones: `https://schedule.readthedocs.io/en/stable/timezones.html`\n- Background execution: `https://schedule.readthedocs.io/en/stable/background-execution.html`\n- Parallel execution: `https://schedule.readthedocs.io/en/stable/parallel-execution.html`\n- Exception handling: `https://schedule.readthedocs.io/en/stable/exception-handling.html`\n- PyPI: `https://pypi.org/project/schedule/`\n- Repository and history: `https://github.com/dbader/schedule`\n"
  },
  {
    "path": "content/scikit-learn/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"scikit-learn package guide for Python - official machine learning toolkit usage and setup\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.8.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"scikit-learn,sklearn,machine-learning,data-science,python\"\n---\n\n# scikit-learn Python Package Guide\n\n## What It Is\n\n`scikit-learn` is the standard Python package for classical machine learning: preprocessing, model selection, pipelines, metrics, and estimators for classification, regression, clustering, and dimensionality reduction.\n\nAgent reminder:\n\n- PyPI package name: `scikit-learn`\n- Import namespace: `sklearn`\n- This package does not do authentication or remote API calls. Most setup work is dependency management, data preparation, and estimator configuration.\n\n## Install\n\nUse the package version your project expects. For the version covered here:\n\n```bash\npython -m pip install \"scikit-learn==1.8.0\"\n```\n\nUpgrade in place:\n\n```bash\npython -m pip install -U scikit-learn\n```\n\nCreate a fresh conda environment:\n\n```bash\nconda create -n sklearn-env -c conda-forge scikit-learn\nconda activate sklearn-env\n```\n\n`scikit-learn` `1.8.0` requires Python `>=3.11`. The install docs also list `numpy`, `scipy`, `joblib`, and `threadpoolctl` as core dependencies.\n\n## Initialize And Verify\n\n```python\nimport sklearn\nfrom sklearn import show_versions\n\nprint(sklearn.__version__)\nshow_versions()\n```\n\n`show_versions()` is useful when builds fail because of binary or BLAS/OpenMP issues.\n\n## Core Workflow\n\n### 1. Split data before training\n\n```python\nfrom sklearn.model_selection import train_test_split\n\nX_train, X_test, y_train, y_test = train_test_split(\n    X,\n    y,\n    test_size=0.2,\n    random_state=42,\n    stratify=y,\n)\n```\n\nSet `random_state` when you need reproducible results across runs.\n\n### 2. Build preprocessing and model steps in one pipeline\n\nUse a `Pipeline` so transforms learned on training data are applied consistently at predict time.\n\n```python\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.preprocessing import OneHotEncoder, StandardScaler\n\nnumeric_features = [\"age\", \"income\"]\ncategorical_features = [\"state\", \"segment\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\n            \"num\",\n            Pipeline(\n                steps=[\n                    (\"imputer\", SimpleImputer(strategy=\"median\")),\n                    (\"scaler\", StandardScaler()),\n                ]\n            ),\n            numeric_features,\n        ),\n        (\n            \"cat\",\n            Pipeline(\n                steps=[\n                    (\"imputer\", SimpleImputer(strategy=\"most_frequent\")),\n                    (\"encoder\", OneHotEncoder(handle_unknown=\"ignore\")),\n                ]\n            ),\n            categorical_features,\n        ),\n    ]\n)\n\nmodel = Pipeline(\n    steps=[\n        (\"preprocess\", preprocess),\n        (\"classifier\", LogisticRegression(max_iter=1000)),\n    ]\n)\n\nmodel.fit(X_train, y_train)\npredictions = model.predict(X_test)\nprobabilities = model.predict_proba(X_test)\n```\n\n### 3. Evaluate with metrics that match the task\n\n```python\nfrom sklearn.metrics import accuracy_score, classification_report, roc_auc_score\n\nprint(\"accuracy:\", accuracy_score(y_test, predictions))\nprint(\"roc_auc:\", roc_auc_score(y_test, probabilities[:, 1]))\nprint(classification_report(y_test, predictions))\n```\n\nFor regression, switch to regression metrics such as `mean_squared_error`, `mean_absolute_error`, or `r2_score`.\n\n### 4. Tune hyperparameters with cross-validation\n\n```python\nfrom sklearn.model_selection import GridSearchCV\n\nsearch = GridSearchCV(\n    estimator=model,\n    param_grid={\n        \"classifier__C\": [0.1, 1.0, 10.0],\n        \"classifier__solver\": [\"lbfgs\"],\n    },\n    cv=5,\n    n_jobs=-1,\n    scoring=\"roc_auc\",\n    refit=True,\n)\n\nsearch.fit(X_train, y_train)\n\nbest_model = search.best_estimator_\nbest_predictions = best_model.predict(X_test)\n```\n\nUse step-qualified parameter names like `classifier__C` when tuning inside a `Pipeline`.\n\n## Common Patterns\n\n### Tabular classification or regression\n\n- Start with `Pipeline` plus `ColumnTransformer`.\n- For linear models, scale numeric columns.\n- For tree-based models, scaling is usually unnecessary but train/test splitting and consistent preprocessing still matter.\n\n### Text features\n\n```python\nfrom sklearn.feature_extraction.text import TfidfVectorizer\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.svm import LinearSVC\n\ntext_model = Pipeline(\n    steps=[\n        (\"tfidf\", TfidfVectorizer()),\n        (\"classifier\", LinearSVC()),\n    ]\n)\n\ntext_model.fit(train_texts, train_labels)\npredicted_labels = text_model.predict(test_texts)\n```\n\n### Unsupervised learning\n\n```python\nfrom sklearn.cluster import KMeans\n\nkmeans = KMeans(n_clusters=8, random_state=42, n_init=\"auto\")\nlabels = kmeans.fit_predict(X)\n```\n\nFor clustering and dimensionality reduction, check whether scaling should happen before fitting.\n\n## Configuration And Performance\n\n## Authentication\n\nNone. `scikit-learn` is a local Python library.\n\n## Global configuration\n\nUse `sklearn.set_config()` for process-wide defaults and `sklearn.config_context()` for temporary overrides.\n\n```python\nfrom sklearn import config_context, set_config\n\nset_config(\n    transform_output=\"pandas\",\n    enable_metadata_routing=False,\n)\n\nwith config_context(assume_finite=True):\n    model.fit(X_train, y_train)\n```\n\nUseful options from the official API docs:\n\n- `transform_output`: return transformer output in `\"default\"`, `\"pandas\"`, or `\"polars\"` form when supported.\n- `working_memory`: cap temporary memory usage for some algorithms.\n- `enable_metadata_routing`: controls whether metadata-routing behavior is enabled for estimators that support it.\n\n## Parallelism\n\nMany estimators and tools expose `n_jobs`. Use:\n\n- `n_jobs=1` for predictable debugging\n- `n_jobs=-1` to use all CPUs when the estimator supports it\n\n`n_jobs` controls joblib-level parallelism. Native libraries used under NumPy, SciPy, or OpenMP may still use their own threads. If you see CPU oversubscription, explicitly limit threads with environment variables before Python starts:\n\n```bash\nOMP_NUM_THREADS=1\nOPENBLAS_NUM_THREADS=1\nMKL_NUM_THREADS=1\npython train.py\n```\n\n## Model Persistence\n\nFor trusted local artifacts, `joblib.dump()` and `joblib.load()` are common:\n\n```python\nimport joblib\n\njoblib.dump(best_model, \"model.joblib\")\nloaded_model = joblib.load(\"model.joblib\")\n```\n\nUse `skops.io` when you need a more inspectable and safer format than raw pickle-based persistence. Do not assume pickle or joblib artifacts are safe to load from untrusted sources.\n\n## Common Pitfalls\n\n## Inconsistent preprocessing\n\nDo not fit transforms on training data and then forget to apply the same transforms to test or production data. Put preprocessing and the estimator in one `Pipeline`.\n\n## Data leakage\n\nDo not fit scalers, imputers, feature selectors, or target-aware preprocessing on the full dataset before splitting. Split first, then fit the pipeline on training data only.\n\n## Wrong metric or split strategy\n\n- Classification with class imbalance often needs stratified splitting and metrics beyond raw accuracy.\n- Time series data should not use random shuffles unless the task genuinely allows it.\n\n## Sparse and dense mismatches\n\nSome preprocessing steps return sparse matrices while some estimators expect dense inputs. Check estimator requirements before forcing `.toarray()`, which can explode memory usage.\n\n## Version-Sensitive Notes For 1.8.0\n\n- `1.8.0` is the version currently shown on PyPI and on the main stable scikit-learn docs used for this guide.\n- `scikit-learn` `1.8.0` requires Python `3.11` or newer.\n- Serialized models are not a stable interchange format across scikit-learn versions. Rebuild or re-export artifacts when upgrading environments.\n- The package import remains `sklearn`, not `scikit_learn`.\n- Some config behavior, metadata routing support, and estimator defaults can change across releases. Recheck the official API page for the exact estimator you are using before copying older snippets.\n\n## Official Sources\n\n- Main docs: https://scikit-learn.org/stable/\n- Install guide: https://scikit-learn.org/stable/install.html\n- Getting started: https://scikit-learn.org/stable/getting_started.html\n- Common pitfalls: https://scikit-learn.org/stable/common_pitfalls.html\n- API reference: https://scikit-learn.org/stable/api/\n- `set_config` API: https://scikit-learn.org/stable/modules/generated/sklearn.set_config.html\n- Parallelism guide: https://scikit-learn.org/stable/computing/parallelism.html\n- Model persistence: https://scikit-learn.org/stable/model_persistence.html\n- PyPI package page: https://pypi.org/project/scikit-learn/\n"
  },
  {
    "path": "content/scipy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SciPy package guide for Python numerical computing, optimization, sparse data, and scientific algorithms\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"scipy,python,numerical-computing,optimization,linear-algebra,sparse\"\n---\n\n# SciPy Python Package Guide\n\n## Golden Rule\n\nUse **NumPy for arrays** and **SciPy for algorithms** built on top of those arrays.\n\nPrefer explicit public imports:\n\n```python\nimport numpy as np\nfrom scipy import integrate, linalg, optimize, sparse, stats\n```\n\nDo not rely on private modules such as `scipy._lib...`, and do not assume third-party blog examples match current SciPy behavior.\n\n## Installation\n\nInstall into a virtual environment and keep NumPy/SciPy aligned:\n\n```bash\npython -m pip install \"numpy>=1.25.2\" \"scipy==1.17.1\"\n```\n\nIf NumPy is already managed by the project, installing SciPy alone is usually enough:\n\n```bash\npython -m pip install \"scipy==1.17.1\"\n```\n\nVerify the runtime versions before writing code that depends on new APIs:\n\n```bash\npython - <<'PY'\nimport numpy as np\nimport scipy\n\nprint(\"numpy\", np.__version__)\nprint(\"scipy\", scipy.__version__)\nPY\n```\n\n## Initialization And Setup\n\nSciPy is a local numerical library. There is:\n\n- no API key\n- no service authentication\n- no global client object to initialize\n\nMost projects should start with:\n\n```python\nimport numpy as np\nfrom scipy import integrate, linalg, optimize, sparse, stats\n```\n\nUse NumPy arrays as the default input type:\n\n```python\nx = np.asarray([1.0, 2.0, 3.0], dtype=float)\n```\n\nIf your code receives Python lists, pandas objects, or mixed dtypes, normalize them before passing them into SciPy routines.\n\n## Choose The Right Module\n\n- `scipy.linalg`: dense linear algebra\n- `scipy.optimize`: minimization, root finding, curve fitting\n- `scipy.integrate`: quadrature and ODE solving\n- `scipy.sparse`: sparse matrices and sparse linear algebra helpers\n- `scipy.stats`: probability distributions and statistical tests\n- `scipy.signal`: filtering, transforms, spectral tools\n- `scipy.spatial`: distances, KD-trees, geometry helpers\n\n## Core Usage\n\n### Solve A Dense Linear System\n\n```python\nimport numpy as np\nfrom scipy import linalg\n\nA = np.array([[3.0, 2.0], [1.0, 2.0]])\nb = np.array([5.0, 5.0])\n\nx = linalg.solve(A, b)\nprint(x)  # [0.  2.5]\n```\n\nUse `scipy.linalg` when you need decompositions, matrix functions, or linear algebra routines beyond what plain `numpy.linalg` gives you.\n\n### Minimize An Objective Function\n\n```python\nimport numpy as np\nfrom scipy import optimize\n\ndef objective(x: np.ndarray) -> float:\n    return (x[0] - 1.5) ** 2 + (x[1] + 2.0) ** 2\n\nresult = optimize.minimize(objective, x0=np.array([0.0, 0.0]), method=\"BFGS\")\n\nprint(result.x)        # near [1.5, -2.0]\nprint(result.success)  # True on a successful solve\n```\n\nCheck `result.success`, `result.message`, and algorithm-specific fields instead of assuming convergence.\n\n### Solve An ODE\n\n```python\nimport numpy as np\nfrom scipy import integrate\n\ndef decay(t: float, y: np.ndarray) -> np.ndarray:\n    return -0.5 * y\n\nsolution = integrate.solve_ivp(\n    decay,\n    t_span=(0.0, 5.0),\n    y0=[1.0],\n    t_eval=np.linspace(0.0, 5.0, 6),\n)\n\nprint(solution.t)\nprint(solution.y[0])\n```\n\nUse `solve_ivp` for new ODE code; keep `t_span`, `y0`, tolerances, and event functions explicit.\n\n### Work With Sparse Data\n\n```python\nimport numpy as np\nfrom scipy import sparse\n\nA = sparse.csr_matrix([\n    [0.0, 1.0, 0.0],\n    [2.0, 0.0, 3.0],\n    [0.0, 0.0, 4.0],\n])\n\nx = np.array([1.0, 2.0, 3.0])\ny = A @ x\n\nprint(y)\nprint(A.nnz)  # number of stored nonzero entries\n```\n\nUse sparse structures when the matrix is mostly zeros. Dense conversions can erase the performance and memory benefit.\n\n### Use Statistical Distributions\n\n```python\nfrom scipy import stats\n\ndist = stats.norm(loc=0.0, scale=1.0)\n\nprint(dist.cdf(1.96))\nprint(dist.ppf(0.975))\n```\n\nFor statistical tests and distributions, check the docstring for parameterization details instead of guessing from distribution names.\n\n## Configuration And Environment\n\nSciPy has no auth configuration. The main setup concerns are runtime compatibility and native dependencies:\n\n- keep Python and NumPy inside the supported version range for the installed SciPy release\n- prefer standard wheels unless you intentionally need a source build\n- use a clean virtual environment when debugging binary import or ABI issues\n\nIf import errors mention compiled extensions, version skew between Python, NumPy, and SciPy is a more likely cause than application logic.\n\n## Common Pitfalls\n\n- **Passing loosely typed inputs:** many functions work best with explicit `ndarray` inputs. Normalize with `np.asarray(..., dtype=float)` when numeric precision matters.\n- **Importing private or undocumented symbols:** public submodules are stable entry points; private internals are not.\n- **Guessing algorithm defaults:** optimization, integration, interpolation, and statistics APIs often have important defaults for tolerances, bounds, axis handling, or NaN behavior.\n- **Shape mistakes:** SciPy routines often distinguish between `(n,)`, `(n, 1)`, and `(m, n)` inputs. Wrong shapes can change broadcasting or solver behavior.\n- **Accidental densification:** mixing sparse and dense operations can materialize large dense arrays unexpectedly.\n- **Overusing top-level `scipy` access:** explicit submodule imports are clearer and safer for agent-generated code.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `1.17.1` as the release covered here, published on **2026-02-23**.\n- The reference manual is still labeled `v1.17.0` on **2026-03-11**. That looks like an official docs lag, not a different major/minor API line.\n- PyPI metadata for `1.17.1` requires Python `>=3.12` and NumPy `>=1.25.2`. Do not assume older interpreter support.\n- SciPy `1.15.0` release notes call out lazy loading for submodules. In practice, write explicit imports such as `from scipy import optimize` or `from scipy.optimize import minimize` instead of relying on fragile access patterns.\n\n## Official Sources\n\n- SciPy package on PyPI: https://pypi.org/project/scipy/\n- SciPy reference manual: https://docs.scipy.org/doc/scipy/reference/\n- SciPy API overview: https://docs.scipy.org/doc/scipy/reference/api.html\n- SciPy 1.15.0 release notes: https://docs.scipy.org/doc/scipy/reference/release.1.15.0.html\n"
  },
  {
    "path": "content/scrapy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Scrapy package guide for Python web crawling and scraping projects using the official Scrapy 2.14 docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.14.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"scrapy,python,web-scraping,crawler,spider,twisted,asyncio\"\n---\n\n# Scrapy Python Package Guide\n\n## Golden Rule\n\nUse `Scrapy` for structured crawlers and spiders, not ad hoc `requests` loops. Build a spider, yield `Request` and item objects, and let Scrapy manage scheduling, retries, throttling, cookies, exports, and concurrency.\n\nAs of March 12, 2026, the assigned package version for this entry is `2.14.1`, while the upstream `latest` docs root already identifies as `2.14.2`. The `2.14.2` release notes include security fixes, so prefer upgrading to `2.14.2` unless your project is explicitly pinned to `2.14.1`.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"Scrapy==2.14.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"Scrapy==2.14.1\"\npoetry add \"Scrapy==2.14.1\"\n```\n\nVerify the installed CLI:\n\n```bash\nscrapy version -v\n```\n\n## Initialize A Project\n\nCreate a project scaffold when you want settings, middleware, pipelines, and multiple spiders:\n\n```bash\nscrapy startproject tutorial\ncd tutorial\nscrapy genspider quotes quotes.toscrape.com\n```\n\nImportant generated files:\n\n- `scrapy.cfg`: project entry point for `scrapy crawl ...`\n- `tutorial/settings.py`: project-wide settings\n- `tutorial/spiders/`: spider modules\n- `tutorial/items.py`: item definitions when you want typed scraped output\n- `tutorial/pipelines.py`: post-processing and persistence hooks\n\nFor a one-file spider without a full project:\n\n```bash\nscrapy runspider quotes_spider.py -O quotes.jsonl\n```\n\n## Core Usage\n\n### Minimal spider\n\n```python\nimport scrapy\n\nclass QuotesSpider(scrapy.Spider):\n    name = \"quotes\"\n    allowed_domains = [\"quotes.toscrape.com\"]\n    start_urls = [\"https://quotes.toscrape.com/\"]\n\n    def parse(self, response):\n        for quote in response.css(\"div.quote\"):\n            yield {\n                \"text\": quote.css(\"span.text::text\").get(),\n                \"author\": quote.css(\"small.author::text\").get(),\n                \"tags\": quote.css(\"div.tags a.tag::text\").getall(),\n            }\n\n        next_page = response.css(\"li.next a::attr(href)\").get()\n        if next_page:\n            yield response.follow(next_page, callback=self.parse)\n```\n\nRun it and export newline-delimited JSON:\n\n```bash\nscrapy crawl quotes -O quotes.jsonl\n```\n\nRules that matter:\n\n- `allowed_domains` should contain hostnames only, not schemes or paths.\n- `start_urls` is for simple GET requests. If you need headers, cookies, auth, or POST bodies, override `start_requests()`.\n- Use `response.follow(...)` for pagination and link traversal so Scrapy resolves relative URLs correctly.\n\n### Requests, selectors, and item output\n\nScrapy callbacks receive `Response` objects. The common extraction methods are:\n\n- `response.css(\"selector\").get()` for one value\n- `response.css(\"selector\").getall()` for lists\n- `response.xpath(\"//...\").get()` when XPath is easier than CSS\n- `response.follow(url_or_selector, callback=...)` to enqueue more work\n\nItems can be plain dicts, `scrapy.Item`, or dataclasses you convert before yielding. Dicts are usually enough unless you need pipeline validation.\n\n### Run from Python code\n\nUse `CrawlerProcess` when you need to start Scrapy from a Python script instead of the CLI:\n\n```python\nfrom scrapy.crawler import CrawlerProcess\nfrom scrapy.utils.project import get_project_settings\n\nfrom tutorial.spiders.quotes import QuotesSpider\n\nprocess = CrawlerProcess(get_project_settings())\nprocess.crawl(QuotesSpider)\nprocess.start()\n```\n\nThis is the simplest route for embedding Scrapy in a script. If you are integrating with an already-running Twisted reactor or another event loop, read the asyncio/reactor notes before trying to start a second loop.\n\n## Configuration And Auth\n\nMost project configuration lives in `settings.py`. Common settings agents usually need first:\n\n```python\nBOT_NAME = \"tutorial\"\n\nROBOTSTXT_OBEY = True\nUSER_AGENT = \"tutorial-bot/1.0 (+https://example.com/bot)\"\nDOWNLOAD_DELAY = 1.0\nCONCURRENT_REQUESTS = 8\n\nFEEDS = {\n    \"quotes.jsonl\": {\n        \"format\": \"jsonlines\",\n        \"overwrite\": True,\n    }\n}\n```\n\nIf a spider needs per-spider settings, prefer `update_settings()` over `custom_settings` when you need to merge or modify dict settings such as `FEEDS`:\n\n```python\nimport scrapy\n\nclass QuotesSpider(scrapy.Spider):\n    name = \"quotes\"\n\n    @classmethod\n    def update_settings(cls, settings):\n        super().update_settings(settings)\n        settings.set(\n            \"FEEDS\",\n            {\n                \"quotes.jsonl\": {\n                    \"format\": \"jsonlines\",\n                    \"overwrite\": True,\n                }\n            },\n            priority=\"spider\",\n        )\n```\n\n### Auth, headers, cookies, proxies\n\nScrapy itself does not have a package-level auth flow. Site auth is request-driven:\n\n```python\nimport scrapy\n\nclass PrivateSpider(scrapy.Spider):\n    name = \"private\"\n\n    def start_requests(self):\n        yield scrapy.Request(\n            \"https://example.com/api/items\",\n            headers={\"Authorization\": \"Bearer TOKEN\"},\n            cookies={\"sessionid\": \"cookie-value\"},\n            callback=self.parse_items,\n        )\n\n    def parse_items(self, response):\n        yield {\"status\": response.status}\n```\n\nUseful built-in patterns:\n\n- Basic HTTP auth: set `HTTPAUTH_USER` and `HTTPAUTH_PASS`\n- Proxies: set `request.meta[\"proxy\"] = \"http://proxy:port\"` or configure proxy middleware\n- Browser-like headers: set `DEFAULT_REQUEST_HEADERS` or pass `headers=...` on each `Request`\n- Robots compliance: set `ROBOTSTXT_OBEY = True` unless you intentionally have permission to bypass it\n\n## Async And Concurrency Notes\n\nScrapy is built on Twisted. In modern Scrapy, callbacks can also be defined as coroutines:\n\n```python\nimport scrapy\n\nclass AsyncSpider(scrapy.Spider):\n    name = \"async-spider\"\n    start_urls = [\"https://quotes.toscrape.com/\"]\n\n    async def parse(self, response):\n        yield {\"title\": response.css(\"title::text\").get()}\n```\n\nIf you need asyncio-compatible libraries inside Scrapy, use the asyncio reactor:\n\n```python\nTWISTED_REACTOR = \"twisted.internet.asyncioreactor.AsyncioSelectorReactor\"\n```\n\nNotes:\n\n- Set the reactor before starting crawlers; changing it too late causes hard-to-debug runtime failures.\n- Async callbacks do not remove Scrapy's concurrency controls; `CONCURRENT_REQUESTS`, delays, AutoThrottle, and downloader middleware still matter.\n- Avoid blocking code inside callbacks. Blocking I/O defeats Scrapy's concurrency model.\n\n## Common Commands\n\n```bash\nscrapy startproject tutorial\nscrapy genspider quotes quotes.toscrape.com\nscrapy crawl quotes\nscrapy crawl quotes -O quotes.jsonl\nscrapy runspider quotes_spider.py -O quotes.jsonl\nscrapy shell https://quotes.toscrape.com/\nscrapy list\nscrapy check\n```\n\n`scrapy shell <url>` is the fastest way to debug selectors before you edit a spider.\n\n## Common Pitfalls\n\n- Do not put `https://` or `/path` in `allowed_domains`; keep it to hostnames like `example.com`.\n- `start_urls` only issues GET requests. For login flows, POST requests, custom headers, or cookies, implement `start_requests()`.\n- `scrapy crawl ... -O file.json` overwrites the target file. Use `-o` if you want append semantics where supported.\n- If you override settings inside a spider, prefer `update_settings()` when you need to merge dictionaries like `FEEDS`; `custom_settings` is static and less flexible.\n- Be explicit about `USER_AGENT`, delays, concurrency, and robots behavior. Default settings are rarely appropriate for production crawling.\n- If you embed Scrapy in another Python process, do not try to start multiple reactors. One process gets one active Twisted reactor.\n- When selectors look wrong, debug in `scrapy shell` first; many spider bugs are selector bugs, not downloader bugs.\n\n## Version-Sensitive Notes For Scrapy 2.14.x\n\n- An earlier version reference used `2.14.1`, but the upstream docs root on March 12, 2026 already reports `2.14.2`.\n- The `2.14.2` release notes mention security fixes. If you are free to move within the same patch line, prefer `2.14.2`.\n- The official docs recommend `update_settings()` for spider-level settings and support coroutine callbacks, which matters when adapting older pre-async examples from blog posts.\n- When working from older tutorials, verify reactor and asyncio guidance against the current docs before mixing Scrapy with async libraries.\n\n## Official Sources\n\n- Docs root: https://docs.scrapy.org/en/latest/\n- Tutorial and commands: https://docs.scrapy.org/en/latest/intro/tutorial.html and https://docs.scrapy.org/en/latest/intro/commands.html\n- Request/response and spiders: https://docs.scrapy.org/en/latest/topics/request-response.html and https://docs.scrapy.org/en/latest/topics/spiders.html\n- Settings, feed exports, practices, and asyncio: https://docs.scrapy.org/en/latest/topics/settings.html, https://docs.scrapy.org/en/latest/topics/feed-exports.html, https://docs.scrapy.org/en/latest/topics/practices.html, https://docs.scrapy.org/en/latest/topics/asyncio.html, and https://docs.scrapy.org/en/latest/topics/coroutines.html\n- Release notes: https://docs.scrapy.org/en/latest/news.html\n- PyPI: https://pypi.org/project/scrapy/\n"
  },
  {
    "path": "content/seaborn/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"seaborn package guide for Python statistical visualization with matplotlib and pandas\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.13.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"seaborn,python,visualization,plotting,matplotlib,pandas,statistics\"\n---\n\n# seaborn Python Package Guide\n\n## What It Is\n\n`seaborn` is a high-level statistical visualization library for Python. It builds on top of `matplotlib`, works closely with `pandas`-style tabular data, and gives you two main ways to work:\n\n- function-based plotting such as `scatterplot`, `relplot`, `displot`, `catplot`, and `heatmap`\n- the newer declarative `seaborn.objects` interface via `seaborn.objects.Plot`\n\nFor coding agents, the safe default is:\n\n1. Install `seaborn` into the same environment as `matplotlib`, `pandas`, and `numpy`.\n2. Import it as `import seaborn as sns`.\n3. Use a tidy `DataFrame` with named columns.\n4. Call `sns.set_theme()` once near startup if you want seaborn defaults.\n5. In scripts or terminals, call `matplotlib.pyplot.show()` or save the figure explicitly.\n\n## Installation\n\nUse the interpreter-targeted install form when possible:\n\n```bash\npython -m pip install \"seaborn==0.13.2\"\n```\n\nInclude optional statistical dependencies when needed:\n\n```bash\npython -m pip install \"seaborn[stats]==0.13.2\"\n```\n\nConda options from the official install page:\n\n```bash\nconda install seaborn\nconda install seaborn -c conda-forge\n```\n\nVerify the installed version:\n\n```bash\npython -c \"import seaborn; print(seaborn.__version__)\"\n```\n\nIf import succeeds but plotting fails, the problem is usually in a compiled dependency such as `matplotlib`, `pandas`, or `scipy`, not in seaborn itself.\n\n## Initialize And First Plot\n\nThe docs generally assume these imports:\n\n```python\nimport numpy as np\nimport pandas as pd\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nimport seaborn as sns\nimport seaborn.objects as so\n```\n\nMinimal example:\n\n```python\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nsns.set_theme()\n\npenguins = sns.load_dataset(\"penguins\")\n\ng = sns.relplot(\n    data=penguins,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    hue=\"species\",\n    col=\"sex\",\n)\n\ng.figure.tight_layout()\nplt.show()\n```\n\nNotes:\n\n- `sns.set_theme()` changes global `matplotlib` rcParams, including non-seaborn plots.\n- `sns.load_dataset()` pulls example data from seaborn's online repository, so it requires internet access.\n- In notebooks, plots often display automatically. In scripts and terminals, call `plt.show()` yourself.\n\n## Core Usage Patterns\n\n### Axes-level vs figure-level functions\n\nSeaborn has both axes-level and figure-level APIs:\n\n- axes-level functions draw on one matplotlib axes and usually return an `Axes`\n- figure-level functions create a larger layout and usually return a seaborn grid object such as `FacetGrid`\n\nUse axes-level functions when you already have `fig, ax = plt.subplots()`:\n\n```python\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\nfig, ax = plt.subplots(figsize=(6, 4))\n\nsns.scatterplot(\n    data=penguins,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    hue=\"species\",\n    style=\"species\",\n    ax=ax,\n)\n\nax.set_title(\"Penguin bills\")\nfig.tight_layout()\n```\n\nUse figure-level functions when you want faceting or a higher-level layout:\n\n```python\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\ng = sns.relplot(\n    data=penguins,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    hue=\"species\",\n    col=\"island\",\n    kind=\"scatter\",\n)\n\ng.set_axis_labels(\"Bill length (mm)\", \"Bill depth (mm)\")\ng.set_titles(\"{col_name}\")\ng.despine(trim=True)\n```\n\n### Distribution plots\n\nUse `displot()` for distribution-focused figures and `histplot()`/`kdeplot()` when you want one axes.\n\n```python\nimport seaborn as sns\n\ntips = sns.load_dataset(\"tips\")\n\ng = sns.displot(\n    data=tips,\n    x=\"total_bill\",\n    col=\"time\",\n    hue=\"smoker\",\n    kind=\"hist\",\n    kde=True,\n)\n```\n\n### Categorical plots\n\n`catplot()` is the figure-level entry point for strip, swarm, box, violin, boxen, point, bar, and count plots:\n\n```python\nimport seaborn as sns\n\ntips = sns.load_dataset(\"tips\")\n\ng = sns.catplot(\n    data=tips,\n    kind=\"violin\",\n    x=\"day\",\n    y=\"total_bill\",\n    hue=\"smoker\",\n    split=True,\n)\n```\n\nIn `0.13.x`, categorical plots can keep numeric or datetime spacing with `native_scale=True`:\n\n```python\nimport seaborn as sns\n\ntips = sns.load_dataset(\"tips\")\n\nsns.stripplot(\n    data=tips,\n    x=\"size\",\n    y=\"tip\",\n    native_scale=True,\n)\n```\n\n### Matrix plots\n\nUse `heatmap()` for already-aggregated matrix-like data:\n\n```python\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\ntable = penguins.pivot_table(\n    index=\"species\",\n    columns=\"sex\",\n    values=\"body_mass_g\",\n    aggfunc=\"mean\",\n)\n\nax = sns.heatmap(table, annot=True, fmt=\".0f\", cmap=\"crest\")\nax.set_title(\"Mean body mass\")\n```\n\nUse `clustermap()` only when you have the optional clustering dependencies and actually want hierarchical clustering.\n\n### Pairwise summaries\n\n`pairplot()` is a fast high-level way to inspect relationships across several numeric columns:\n\n```python\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\ng = sns.pairplot(\n    data=penguins,\n    hue=\"species\",\n    corner=True,\n)\n```\n\nWhen you need more control, build the same kind of figure with `PairGrid`.\n\n### Declarative objects interface\n\nThe `objects` interface is useful when you want a composable, chainable API:\n\n```python\nimport seaborn as sns\nimport seaborn.objects as so\n\npenguins = sns.load_dataset(\"penguins\")\n\np = (\n    so.Plot(penguins, x=\"bill_length_mm\", y=\"bill_depth_mm\", color=\"species\")\n    .add(so.Dots())\n    .facet(col=\"sex\")\n    .label(\n        title=\"Penguin bills\",\n        x=\"Bill length (mm)\",\n        y=\"Bill depth (mm)\",\n    )\n)\n\np.show()\n```\n\n`so.Plot` methods return a copy of the plot specification, so build plots through chaining instead of expecting in-place mutation.\n\n## Configuration And Environment\n\n### Themes and rcParams\n\nUse `set_theme()` as the preferred global theme API:\n\n```python\nimport seaborn as sns\n\nsns.set_theme(\n    style=\"whitegrid\",\n    context=\"talk\",\n    palette=\"deep\",\n    rc={\"figure.dpi\": 110},\n)\n```\n\nImportant related APIs from the reference:\n\n- `sns.set_theme()`\n- `sns.set_style()` / `sns.axes_style()`\n- `sns.set_context()` / `sns.plotting_context()`\n- `sns.set_palette()` / `sns.color_palette()`\n- `sns.despine()`\n\nAvoid starting new code with `sns.set(...)`; it is only an alias for `set_theme()` and may be removed in the future.\n\n### Saving figures\n\nSeaborn uses matplotlib for rendering, so save from the returned matplotlib or grid object:\n\n```python\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\nax = sns.histplot(data=penguins, x=\"flipper_length_mm\")\nax.figure.savefig(\"histogram.png\", dpi=150, bbox_inches=\"tight\")\n```\n\nFor figure-level objects:\n\n```python\nimport seaborn as sns\n\npenguins = sns.load_dataset(\"penguins\")\n\ng = sns.relplot(data=penguins, x=\"bill_length_mm\", y=\"bill_depth_mm\")\ng.figure.savefig(\"relplot.png\", dpi=150, bbox_inches=\"tight\")\n```\n\nFor the objects API:\n\n```python\np.save(\"objects-plot.png\")\n```\n\n### Data shape expectations\n\nSeaborn works best with long-form or tidy tabular data:\n\n- one row per observation\n- one column per variable\n- reference columns by name in plotting calls\n\nSome functions also accept wide-form data or raw vectors, but semantics can change. If a plot needs reliable `hue`, `style`, `col`, `row`, or grouping behavior, use a named `DataFrame`.\n\n### Example datasets\n\n`sns.load_dataset()` is for examples, tests, and quick experiments. It is not a general project data loader:\n\n- it requires network access\n- dataset availability comes from seaborn's example-data repository\n- production code should usually load real data with `pandas.read_csv`, SQL, parquet readers, or project-specific I/O\n\n## Common Pitfalls\n\n### Plot does not appear\n\nIn scripts, IDE consoles, and terminals, seaborn follows normal matplotlib behavior. If nothing displays, call:\n\n```python\nimport matplotlib.pyplot as plt\nplt.show()\n```\n\n### Treating figure-level return values like `Axes`\n\n`relplot()`, `displot()`, `catplot()`, `jointplot()`, and `pairplot()` do not return a plain `Axes`. They return grid objects. Use methods such as `g.set_axis_labels(...)`, `g.set_titles(...)`, `g.despine(...)`, or access `g.figure`.\n\n### Forgetting that `set_theme()` changes global matplotlib defaults\n\nTheme changes apply to all later matplotlib and seaborn plots in the process. If you only want a local style change, use matplotlib context managers or limit the change to a controlled section of code.\n\n### Optional dependencies missing\n\nTypical failures:\n\n- advanced regression plotting without `statsmodels`\n- clustering workflows such as `clustermap()` without `scipy`\n- import/runtime issues caused by compiled dependencies rather than seaborn itself\n\nInstall the missing dependency instead of trying to work around the seaborn API.\n\n### Example data loader in offline environments\n\n`sns.load_dataset(\"penguins\")` is convenient but not offline-safe. For reproducible automation, ship a local dataset or load from a known project path.\n\n### Using deprecated or changed older examples\n\n- `distplot()` is deprecated\n- `sns.set()` is only an alias for `set_theme()`\n- many older categorical-plot examples predate the `0.13` rewrite and may not match current defaults\n\n## Version-Sensitive Notes For 0.13.2\n\n- `0.13.2` is the current stable release shown by the official docs and PyPI as of March 12, 2026.\n- The `0.13.2` release note says it contains internal changes to adapt to upcoming pandas deprecations, and upstream recommends updating.\n- `0.13.0` was a major release for categorical plots. Existing code can change appearance or behavior because:\n  - categorical functions now default to a single main color unless `hue` is assigned\n  - passing `palette` without `hue` is deprecated\n  - `native_scale=True` can preserve numeric or datetime spacing on the categorical axis\n  - `log_scale`, `legend`, `formatter`, `fill`, and other parameters were added or broadened\n- `0.13.0` also added provisional support for alternate dataframe libraries through the dataframe exchange protocol, though seaborn still converts inputs to pandas internally.\n- The `objects.Plot` interface in `0.13.x` has additional configuration controls for default theme and notebook display behavior.\n\n## Official Sources\n\n- Installation and dependencies: https://seaborn.pydata.org/installing\n- API reference: https://seaborn.pydata.org/api.html\n- Introduction/tutorial: https://seaborn.pydata.org/tutorial/introduction.html\n- FAQ: https://seaborn.pydata.org/faq.html\n- `set_theme()` reference: https://seaborn.pydata.org/generated/seaborn.set_theme.html\n- `objects.Plot` reference: https://seaborn.pydata.org/generated/seaborn.objects.Plot.html\n- `scatterplot()` reference: https://seaborn.pydata.org/generated/seaborn.scatterplot.html\n- `displot()` reference: https://seaborn.pydata.org/generated/seaborn.displot.html\n- `catplot()` reference: https://seaborn.pydata.org/generated/seaborn.catplot.html\n- Release notes index: https://seaborn.pydata.org/whatsnew/index.html\n- `v0.13.2` release notes: https://seaborn.pydata.org/whatsnew/v0.13.2.html\n- `v0.13.0` release notes: https://seaborn.pydata.org/whatsnew/v0.13.0.html\n- PyPI project page: https://pypi.org/project/seaborn/\n"
  },
  {
    "path": "content/selenium/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Selenium Python bindings for browser automation, WebDriver sessions, waits, actions, cookies, and remote grid usage\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.41.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"selenium,python,webdriver,browser-automation,testing,e2e\"\n---\n\n# Selenium Python Package Guide\n\n## Golden Rule\n\nUse the official `selenium` package and the W3C WebDriver APIs exposed by the Python bindings. For local development on Chrome, Firefox, or Edge, let Selenium Manager find or download the matching driver when possible, but remember that Selenium still needs the actual browser installed on the machine.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"selenium==4.41.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"selenium==4.41.0\"\npoetry add \"selenium==4.41.0\"\n```\n\nYou still need a supported browser installed locally. For the common Chrome, Firefox, and Edge flows, Selenium Manager handles driver discovery and download automatically.\n\n## Initialize A Local Browser Session\n\nChrome or Chromium:\n\n```python\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\noptions = Options()\noptions.add_argument(\"--headless=new\")\noptions.add_argument(\"--window-size=1440,900\")\n\ndriver = webdriver.Chrome(options=options)\n\ntry:\n    driver.get(\"https://www.selenium.dev/selenium/web/web-form.html\")\n    print(driver.title)\nfinally:\n    driver.quit()\n```\n\nFirefox:\n\n```python\nfrom selenium import webdriver\nfrom selenium.webdriver.firefox.options import Options\n\noptions = Options()\noptions.add_argument(\"-headless\")\n\ndriver = webdriver.Firefox(options=options)\n\ntry:\n    driver.get(\"https://www.selenium.dev/\")\nfinally:\n    driver.quit()\n```\n\nUseful option patterns:\n\n- `options.add_argument(...)` for headless mode, window size, proxies, and browser flags\n- `options.binary_location = \"/path/to/browser\"` when the browser binary is not on the default path\n- separate option classes per browser: `chrome.options.Options`, `firefox.options.Options`, `edge.options.Options`\n\n## Core Usage\n\n### Navigate, locate, fill, and click\n\nPrefer `By` locators plus explicit waits:\n\n```python\nfrom selenium import webdriver\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom selenium.webdriver.support.ui import WebDriverWait\n\ndriver = webdriver.Chrome()\n\ntry:\n    driver.get(\"https://www.selenium.dev/selenium/web/web-form.html\")\n\n    text_box = WebDriverWait(driver, 10).until(\n        EC.visibility_of_element_located((By.NAME, \"my-text\"))\n    )\n    text_box.clear()\n    text_box.send_keys(\"Selenium docs\")\n\n    submit_button = driver.find_element(By.CSS_SELECTOR, \"button\")\n    submit_button.click()\n\n    message = WebDriverWait(driver, 10).until(\n        EC.visibility_of_element_located((By.ID, \"message\"))\n    )\n    print(message.text)\nfinally:\n    driver.quit()\n```\n\n### Wait for page state instead of sleeping\n\nUse `WebDriverWait(...).until(...)` with `expected_conditions` for elements, titles, alerts, frames, and URL changes:\n\n```python\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom selenium.webdriver.support.ui import WebDriverWait\n\nwait = WebDriverWait(driver, 10)\nsubmit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, \"button\")))\nsubmit.click()\n\nwait.until(EC.url_contains(\"submitted\"))\n```\n\nSelenium supports implicit waits, but the official waits guidance warns that mixing implicit and explicit waits can produce longer and confusing timeouts. Prefer explicit waits for most test and automation code.\n\n### Interact with complex gestures\n\nUse `ActionChains` for hover, drag and drop, click-and-hold, and keyboard combinations:\n\n```python\nfrom selenium import webdriver\nfrom selenium.webdriver.common.action_chains import ActionChains\nfrom selenium.webdriver.common.by import By\n\ndriver = webdriver.Chrome()\n\ntry:\n    driver.get(\"https://www.selenium.dev/selenium/web/mouse_interaction.html\")\n\n    draggable = driver.find_element(By.ID, \"draggable\")\n    target = driver.find_element(By.ID, \"droppable\")\n\n    ActionChains(driver).drag_and_drop(draggable, target).perform()\nfinally:\n    driver.quit()\n```\n\n### Switch context when the page is not the top document\n\nCommon context switches agents miss:\n\n- iframes: `driver.switch_to.frame(...)` before locating elements inside the frame\n- top document: `driver.switch_to.default_content()`\n- new tabs or windows: `driver.switch_to.window(driver.window_handles[-1])`\n- alerts: `driver.switch_to.alert`\n\n## Remote WebDriver And Grid\n\nUse `webdriver.Remote(...)` when the browser runs outside the current machine, such as Selenium Grid, containers, or hosted browser providers:\n\n```python\nimport os\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\noptions = Options()\noptions.add_argument(\"--headless=new\")\n\ndriver = webdriver.Remote(\n    command_executor=os.environ[\"SELENIUM_REMOTE_URL\"],\n    options=options,\n)\n\ntry:\n    driver.get(\"https://www.selenium.dev/\")\n    print(driver.title)\nfinally:\n    driver.quit()\n```\n\nConfiguration notes:\n\n- Keep the remote URL in an environment variable such as `SELENIUM_REMOTE_URL`\n- Provider-specific credentials or vendor capabilities are usually attached through that remote URL or extra capabilities\n- Match your browser options to the remote environment instead of assuming local defaults\n\nInference from the Selenium client-server model: Selenium itself does not have a package-level API key or auth step. The auth surface is normally the application under test or the remote WebDriver service you connect to.\n\n## Cookies, Session State, And Login Flows\n\nSelenium can persist and restore browser state with cookies:\n\n```python\nfrom selenium import webdriver\n\ndriver = webdriver.Chrome()\n\ntry:\n    driver.get(\"https://example.com\")\n    driver.add_cookie({\"name\": \"sessionid\", \"value\": \"abc123\"})\n    driver.refresh()\n    print(driver.get_cookies())\nfinally:\n    driver.quit()\n```\n\nPractical rules:\n\n- load a page on the target domain before calling `add_cookie(...)`\n- use cookies or normal UI login flows for application auth\n- keep secrets and session tokens in environment variables or your test secret store, not inline in test code\n\n## Common Pitfalls\n\n- Selenium Manager handles drivers, not browser installation. A missing browser binary is still a setup failure.\n- `time.sleep(...)` is a poor substitute for `WebDriverWait`; it makes tests slower and more flaky.\n- Mixing implicit waits and explicit waits can create surprising timeout behavior.\n- Headless flags are browser-specific. `--headless=new` is a Chrome or Chromium pattern, while Firefox commonly uses `-headless`.\n- Elements inside frames, shadow DOM, or newly opened windows require an explicit context change.\n- Avoid brittle absolute XPath selectors when stable IDs, names, labels, or CSS selectors exist.\n- Local and remote browsers can behave differently on downloads, certificates, and sandboxing; reproduce failures in the same environment class.\n\n## Version-Sensitive Notes For `selenium 4.41.0`\n\n- PyPI metadata shows `requires_python >=3.10`.\n- The official bindings and WebDriver documentation remain the right source for APIs and behavior, even though the Python API docs landing page still shows `4.40.0`.\n- Selenium 4.x includes Selenium Manager, which changes the old setup advice from \"manually download chromedriver/geckodriver first\" to \"try the built-in manager first, then fall back to explicit driver or browser configuration only when needed.\"\n\n## Official Sources Used\n\n- Selenium Python API docs: `https://www.selenium.dev/selenium/docs/api/py/`\n- Selenium Python API module index: `https://www.selenium.dev/selenium/docs/api/py/api`\n- Selenium first-script guide: `https://www.selenium.dev/documentation/webdriver/getting_started/first_script/`\n- Selenium waits guidance: `https://www.selenium.dev/documentation/webdriver/waits/`\n- Selenium Manager docs: `https://www.selenium.dev/documentation/selenium_manager/`\n- Selenium remote WebDriver docs: `https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/`\n- Selenium actions API docs: `https://www.selenium.dev/documentation/webdriver/actions_api/`\n- Selenium cookies docs: `https://www.selenium.dev/documentation/webdriver/interactions/cookies/`\n- Selenium PyPI page: `https://pypi.org/project/selenium/`\n- Selenium PyPI JSON API: `https://pypi.org/pypi/selenium/json`\n"
  },
  {
    "path": "content/semantic-kernel/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"semantic-kernel package guide for Python - Microsoft Semantic Kernel SDK\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.40.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"semantic-kernel,ai,agents,llm,openai,azure\"\n---\n\n# semantic-kernel Python Package Guide\n\n## What It Is\n\n`semantic-kernel` is Microsoft's orchestration SDK for building LLM-powered Python applications with chat-completion services, prompt invocation, plugins, vector memory connectors, and higher-level agent patterns.\n\n- Package name: `semantic-kernel`\n- Import root: `semantic_kernel`\n- Language: `python`\n- Version covered: `1.40.0`\n- Python requirement: `>=3.10`\n\n## Install\n\nInstall the pinned package version:\n\n```bash\npip install \"semantic-kernel==1.40.0\"\n```\n\nIf you need optional integrations, install the matching PyPI extra or use the broad setup:\n\n```bash\npip install \"semantic-kernel[all]==1.40.0\"\n```\n\n## Choose A Chat Service\n\nThe Python SDK centers on registering one or more AI services with a `Kernel`. The common starting points are:\n\n- `OpenAIChatCompletion` for OpenAI-hosted models\n- `AzureChatCompletion` for Azure OpenAI deployments\n\nThe maintainer docs and samples assume you create `Kernel()` directly and then add services and plugins. There is no separate builder step for Python.\n\n## Configuration And Auth\n\n### OpenAI\n\nCommon environment variables:\n\n```env\nOPENAI_API_KEY=...\nOPENAI_CHAT_MODEL_ID=gpt-4o-mini\n```\n\nOptional variables supported by the SDK include `OPENAI_BASE_URL`, `OPENAI_API_VERSION`, and `OPENAI_ORG_ID`.\n\n### Azure OpenAI\n\nCommon environment variables:\n\n```env\nAZURE_OPENAI_API_KEY=...\nAZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/\nAZURE_OPENAI_CHAT_DEPLOYMENT_NAME=your-chat-deployment\nAZURE_OPENAI_API_VERSION=2024-10-21\n```\n\nThe SDK also supports loading settings from a `.env` file via connector constructor arguments such as `env_file_path`.\n\n## Minimal Setup\n\n### OpenAI-backed kernel\n\n```python\nfrom semantic_kernel import Kernel\nfrom semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n\nkernel = Kernel()\nkernel.add_service(OpenAIChatCompletion(service_id=\"chat\"))\n```\n\nIf you set `OPENAI_API_KEY` and `OPENAI_CHAT_MODEL_ID`, the connector can read them from the environment. You can also pass `api_key=...`, `ai_model_id=...`, and related options directly.\n\n### Azure OpenAI-backed kernel\n\n```python\nfrom semantic_kernel import Kernel\nfrom semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n\nkernel = Kernel()\nkernel.add_service(AzureChatCompletion(service_id=\"chat\"))\n```\n\nIf you rely on environment loading, make sure the Azure-specific variables match the deployment you actually created. Azure uses deployment names, not raw OpenAI model ids, for chat completion routing.\n\n## Core Usage\n\n### 1. Invoke a prompt directly\n\n```python\nimport asyncio\n\nfrom semantic_kernel import Kernel\nfrom semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n\nasync def main() -> None:\n    kernel = Kernel()\n    kernel.add_service(OpenAIChatCompletion(service_id=\"chat\"))\n\n    result = await kernel.invoke_prompt(\n        \"Write a three-bullet release note for a Python SDK update.\"\n    )\n    print(result)\n\nasyncio.run(main())\n```\n\nUse `service_id` when you register multiple chat services and need to control which connector executes a prompt.\n\n### 2. Add a plugin for tool/function calling\n\n```python\nimport asyncio\n\nfrom semantic_kernel import Kernel\nfrom semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior\nfrom semantic_kernel.connectors.ai.open_ai import (\n    OpenAIChatCompletion,\n    OpenAIChatPromptExecutionSettings,\n)\nfrom semantic_kernel.functions import KernelArguments, kernel_function\n\nclass MathPlugin:\n    @kernel_function(description=\"Add two integers and return the sum.\")\n    def add(self, a: int, b: int) -> int:\n        return a + b\n\nasync def main() -> None:\n    kernel = Kernel()\n    kernel.add_service(OpenAIChatCompletion(service_id=\"chat\"))\n    kernel.add_plugin(MathPlugin(), plugin_name=\"math\")\n\n    settings = OpenAIChatPromptExecutionSettings()\n    settings.function_choice_behavior = FunctionChoiceBehavior.Auto()\n\n    result = await kernel.invoke_prompt(\n        \"What is 18 + 27? Use the math plugin.\",\n        arguments=KernelArguments(settings=settings),\n    )\n    print(result)\n\nasyncio.run(main())\n```\n\nFor function calling to work reliably:\n\n- decorate callable methods with `@kernel_function`\n- give functions and parameters clear names and descriptions\n- use execution settings that enable automatic function choice\n\n### 3. Move to agents when you need orchestration\n\nThe current maintainer docs position agents as a layer on top of services, prompts, plugins, and memory. Start with a working `Kernel` and service registration first, then add agent abstractions once the base prompt flow is stable.\n\n## Version-Sensitive Notes For `1.40.0`\n\n- The version used here `1.40.0` matches the official Python release published on March 2, 2026.\n- The official Learn documentation is a moving target and may describe features added after `1.40.0`; use the release notes when you need to confirm whether a capability existed at this exact version.\n- The Python `1.40.0` release specifically called out support for the OpenAI realtime API with GPT-4o Realtime and GPT-4o mini Realtime audio models.\n\n## Common Pitfalls\n\n- Install/import mismatch: install `semantic-kernel`, but import from `semantic_kernel`.\n- Wrong Python version: the package requires Python 3.10 or newer.\n- Connector env mismatch: `OpenAIChatCompletion` and `AzureChatCompletion` use different environment variable sets.\n- Azure deployment confusion: Azure chat connectors need your deployment name, not just a model family name.\n- Async execution: most useful examples are `async`, so use `asyncio.run(...)` or integrate into the app's existing event loop.\n- Direct service calls need matching settings: if you invoke a service without registering it on a `Kernel`, create the service-specific prompt execution settings explicitly.\n- Function calling depends on metadata: vague plugin descriptions and poorly typed parameters reduce tool selection quality.\n- Latest-doc drift: Microsoft Learn pages can outpace the exact pinned package version; prefer release notes when a feature looks new.\n\n## Recommended Workflow For Agents\n\n1. Pin `semantic-kernel==1.40.0` unless the project already uses a newer vetted version.\n2. Confirm the provider first: OpenAI, Azure OpenAI, or another supported connector.\n3. Set provider-specific environment variables before writing orchestration code.\n4. Start with `Kernel()` plus one chat-completion service and a direct `invoke_prompt(...)` call.\n5. Add plugins only after the base prompt path works.\n6. Reach for agents after prompts and plugins are already stable in the target app.\n\n## Official Sources\n\n- Overview: https://learn.microsoft.com/en-us/semantic-kernel/overview/\n- Python getting started and quickstarts: https://learn.microsoft.com/en-us/semantic-kernel/get-started/quick-start-guide?pivots=programming-language-python\n- Python README and package examples: https://github.com/microsoft/semantic-kernel/blob/main/python/README.md\n- Python settings reference: https://raw.githubusercontent.com/microsoft/semantic-kernel/main/python/samples/concepts/setup/ALL_SETTINGS.env.example\n- Release notes for `1.40.0`: https://github.com/microsoft/semantic-kernel/releases/tag/python-1.40.0\n- PyPI package page: https://pypi.org/project/semantic-kernel/\n"
  },
  {
    "path": "content/semver/docs/semver/javascript/DOC.md",
    "content": "---\nname: semver\ndescription: \"Semantic version parsing, comparison, range matching, and CLI utilities for JavaScript\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.7.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,semver,versioning,npm,cli\"\n---\n\n# semver for JavaScript\n\nUse `semver` to validate version strings, compare releases, evaluate ranges, and increment versions in Node.js tools and release automation.\n\n## Install\n\n```bash\nnpm install semver\n```\n\nThe package metadata for `7.7.4` declares `node: \">=10\"`.\n\n## Import and setup\n\n`semver` does not require environment variables, authentication, or client initialization.\n\nThe maintainer README documents CommonJS usage:\n\n```js\nconst semver = require(\"semver\");\n```\n\nIf you only need one helper or class, load a documented subpath directly:\n\n```js\nconst Range = require(\"semver/classes/range\");\nconst coerce = require(\"semver/functions/coerce\");\n```\n\n## Validate and normalize versions\n\nUse `clean()` when inputs may contain surrounding whitespace or compatibility prefixes such as `=` or `v`. Use `parse()` when you need the structured `SemVer` fields.\n\n```js\nconst semver = require(\"semver\");\n\nfunction normalizeVersion(input) {\n  const cleaned = semver.clean(input);\n  if (!cleaned) {\n    throw new Error(`Invalid semantic version: ${input}`);\n  }\n\n  const parsed = semver.parse(cleaned);\n  if (!parsed) {\n    throw new Error(`Could not parse semantic version: ${cleaned}`);\n  }\n\n  return {\n    version: parsed.version,\n    major: parsed.major,\n    minor: parsed.minor,\n    patch: parsed.patch,\n    prerelease: parsed.prerelease,\n    build: parsed.build,\n  };\n}\n\nconsole.log(normalizeVersion(\" =v1.2.3   \"));\n```\n\n`semver` strips a leading `v` for compatibility, but the README says that form should not be used anymore. Prefer storing and emitting canonical versions such as `1.2.3`.\n\n## Compare and sort versions\n\nUse the boolean helpers for direct comparisons and `sort()` or `rsort()` for lists.\n\n```js\nconst semver = require(\"semver\");\n\nconst versions = [\"1.2.4\", \"1.2.3\", \"1.2.3+build.2\"];\n\nconsole.log(semver.gt(\"1.2.4\", \"1.2.3\"));\nconsole.log(semver.sort(versions));\nconsole.log(semver.rsort(versions));\n```\n\nWhen build metadata matters, use `compareBuild()` instead of `compare()`:\n\n```js\nconst semver = require(\"semver\");\n\nconsole.log(semver.compare(\"1.2.3+build.1\", \"1.2.3+build.2\"));\nconsole.log(semver.compareBuild(\"1.2.3+build.1\", \"1.2.3+build.2\"));\n```\n\n`compare()` follows normal semver precedence and treats those two versions as equal. `compareBuild()` also considers build metadata.\n\n## Match version ranges\n\nUse `satisfies()` for one-off checks and `maxSatisfying()` or `minVersion()` when selecting from an available set.\n\n```js\nconst semver = require(\"semver\");\n\nconst supportedRange = \"^7.0.0\";\nconst requestedVersion = \"7.7.4\";\nconst availableVersions = [\"6.9.0\", \"7.5.4\", \"7.7.4\", \"8.0.0\"];\n\nif (!semver.satisfies(requestedVersion, supportedRange)) {\n  throw new Error(`${requestedVersion} does not satisfy ${supportedRange}`);\n}\n\nconsole.log(semver.minVersion(supportedRange)?.version);\nconsole.log(semver.maxSatisfying(availableVersions, supportedRange));\n\nconst range = new semver.Range(\"^7.0.0 || ^8.0.0\");\nconsole.log(range.test(\"7.7.4\"));\nconsole.log(range.test(\"9.0.0\"));\n```\n\n### Prerelease range behavior\n\nBy default, prerelease versions are excluded from range matching unless the comparator set explicitly opts into the same `[major, minor, patch]` prerelease line, or you pass `includePrerelease: true`.\n\n```js\nconst semver = require(\"semver\");\n\nconsole.log(semver.satisfies(\"1.2.4-beta.1\", \"^1.2.3\"));\nconsole.log(\n  semver.satisfies(\"1.2.4-beta.1\", \"^1.2.3\", { includePrerelease: true }),\n);\n```\n\nIf you are evaluating release candidates or beta builds, make that behavior explicit in code.\n\n## Increment versions\n\nUse `inc()` to bump stable releases and prerelease lines.\n\n```js\nconst semver = require(\"semver\");\n\nconsole.log(semver.inc(\"1.2.3\", \"patch\"));\nconsole.log(semver.inc(\"1.2.3\", \"prerelease\", \"beta\"));\nconsole.log(semver.inc(\"1.2.3\", \"prerelease\", \"beta\", \"1\"));\nconsole.log(semver.inc(\"1.2.3\", \"prerelease\", \"beta\", false));\nconsole.log(semver.inc(\"1.2.4-beta.1\", \"release\"));\n```\n\nUse `RELEASE_TYPES` to validate user input before passing it into `inc()`:\n\n```js\nconst semver = require(\"semver\");\n\nfunction assertReleaseType(value) {\n  if (!semver.RELEASE_TYPES.includes(value)) {\n    throw new Error(`Unsupported release type: ${value}`);\n  }\n}\n```\n\n## Coerce non-standard input\n\n`coerce()` is intentionally forgiving. Use it when a filename, tag, or label contains a version, not when you need strict validation.\n\n```js\nconst semver = require(\"semver\");\n\nconsole.log(semver.coerce(\"release-7.7\")?.version);\nconsole.log(semver.coerce(\"1.2.3.4\", { rtl: true })?.version);\n\nconst prerelease = semver.coerce(\"release-1.2.3-rc.1+rev.2\", {\n  includePrerelease: true,\n});\n\nconsole.log(prerelease?.version);\nconsole.log(prerelease?.build);\n```\n\nImportant behavior from the README:\n\n- `coerce()` ignores surrounding text and looks for the first coercible version tuple.\n- Extra numeric segments can be truncated rather than preserved.\n- `rtl: true` searches from the right-most coercible tuple instead of the default left-to-right behavior.\n\nFor input that must already be valid semver, prefer `valid()`, `clean()`, or `parse()`.\n\n## Use the CLI\n\nThe package installs a `semver` command. Use `npx` if you do not install it globally.\n\nFilter versions by range:\n\n```bash\nnpx semver -r \"^7.0.0\" 7.6.3 7.7.4 8.0.0\n```\n\nIncrement prereleases:\n\n```bash\nnpx semver 1.2.3 -i prerelease --preid beta\nnpx semver 1.2.4-beta.1 -i release\nnpx semver 1.2.3 -i prerelease --preid beta -n false\n```\n\nCoerce loose input:\n\n```bash\nnpx semver \"release-7.7\" -c\n```\n\nThe CLI exits successfully if any valid version satisfies all supplied ranges. If no satisfying version is found, it exits with failure, which makes it useful in shell scripts and CI checks.\n\n## Practical notes\n\n- Use `satisfies()` to answer yes or no questions. Range helpers such as `gtr()` and `ltr()` answer different questions and ranges can have gaps.\n- Use `compareBuild()` when build metadata should affect ordering; use `compare()` for normal semver precedence.\n- Use `coerce()` only at the boundary where input is messy. Do not treat it as strict validation.\n- Keep prerelease handling explicit. The default range semantics intentionally exclude most prerelease versions.\n"
  },
  {
    "path": "content/sendgrid/docs/email-api/javascript/DOC.md",
    "content": "---\nname: email-api\ndescription: \"SendGrid Node.js library for sending transactional and marketing emails via the SendGrid API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.1.6\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"sendgrid,email,transactional,templates,delivery\"\n---\n\n# SendGrid Node.js API Coding Guidelines (JavaScript/TypeScript)\n\nYou are a SendGrid Node.js API coding expert. Help me with writing code using the SendGrid Node.js library for email sending and API interactions. Please follow the following guidelines when generating code.\n\nYou can find the official documentation and code samples here: https://docs.sendgrid.com/for-developers/sending-email/nodejs\n\n## Golden Rule: Use the Correct and Current Packages\n\nAlways use the official SendGrid Node.js packages, which are organized as a monorepo with specialized packages for different use cases. \n\n- **Main Email Package:** `@sendgrid/mail`\n- **Full API Client:** `@sendgrid/client`\n- **Helper Classes:** `@sendgrid/helpers`\n- **Contact Management:** `@sendgrid/contact-importer`\n- **Webhook Processing:** `@sendgrid/eventwebhook`\n- **Inbound Email Parsing:** `@sendgrid/inbound-mail-parser`\n- **Subscription Widget:** `@sendgrid/subscription-widget`\n\n**Installation:**\n\n- **For Email Sending Only:** `npm install @sendgrid/mail`\n- **For Full API Access:** `npm install @sendgrid/client`\n- **For Helper Classes:** `npm install @sendgrid/helpers`\n\n**APIs and Usage:**\n\n- **Incorrect:** `const sendgrid = require('sendgrid')` (legacy v2/v3 library)\n- **Correct:** `const sgMail = require('@sendgrid/mail')`\n- **Incorrect:** `sendgrid.send(...)` -> **Correct:** `sgMail.send(...)`\n- **Incorrect:** `const client = require('@sendgrid/client')` without setup -> **Correct:** Set API key first\n\n## Prerequisites and Setup\n\nBefore using SendGrid Node.js library, ensure you have:\n\n- Node.js 18 or higher\n- A Twilio SendGrid account (sign up for free to send up to 40,000 emails for the first 30 days)\n- A verified sender identity \n\n## API Key Configuration\n\n**Never hardcode your API key.** Always use environment variables: \n\n```bash\necho \"export SENDGRID_API_KEY='YOUR_API_KEY'\" > sendgrid.env\necho \"sendgrid.env\" >> .gitignore\nsource ./sendgrid.env\n```\n\n## Basic Email Sending\n\n### Simple Email\n\nHere's how to send a basic email: \n\n```javascript\nconst sgMail = require('@sendgrid/mail');\nsgMail.setApiKey(process.env.SENDGRID_API_KEY);\n\nconst msg = {\n  to: 'test@example.com',\n  from: 'test@example.com', // Use the email address or domain you verified\n  subject: 'Sending with Twilio SendGrid is Fun',\n  text: 'and easy to do anywhere, even with Node.js',\n  html: '<strong>and easy to do anywhere, even with Node.js</strong>',\n};\n\n// ES6 Promise approach\nsgMail\n  .send(msg)\n  .then(() => {\n    console.log('Email sent successfully');\n  }, error => {\n    console.error(error);\n    if (error.response) {\n      console.error(error.response.body);\n    }\n  });\n\n// ES8 async/await approach\n(async () => {\n  try {\n    await sgMail.send(msg);\n    console.log('Email sent successfully');\n  } catch (error) {\n    console.error(error);\n    if (error.response) {\n      console.error(error.response.body);\n    }\n  }\n})();\n```\n\n### Multiple Recipients\n\nSend to multiple recipients: \n\n```javascript\nsgMail.send({\n  to: ['recipient1@example.org', 'recipient2@example.org'],\n  from: 'sender@example.org',\n  subject: 'Hello world',\n  text: 'Hello plain world!',\n  html: '<p>Hello HTML world!</p>',\n});\n```\n\n### Send Multiple (Individual Emails)\n\nUse `sendMultiple` to send individual emails to each recipient: \n\n```javascript\nsgMail.sendMultiple({\n  to: ['recipient1@example.org', 'recipient2@example.org'],\n  from: 'sender@example.org',\n  subject: 'Hello world',\n  text: 'Hello plain world!',\n  html: '<p>Hello HTML world!</p>',\n});\n```\n\n## Advanced Email Features\n\n### Personalizations with Substitutions\n\nSend personalized emails with dynamic content: \n\n```javascript\nconst sgMail = require('@sendgrid/mail');\nsgMail.setApiKey(process.env.SENDGRID_API_KEY);\n\nconst msg = {\n  from: 'sender1@example.org',\n  subject: 'Ahoy!',\n  text: 'Ahoy {{name}}!',\n  html: '<p>Ahoy {{name}}!</p>',\n  personalizations: [\n    {\n      to: 'recipient1@example.org',\n      substitutions: {\n        name: 'Jon'\n      }\n    },\n    {\n      to: 'recipient2@example.org',\n      substitutions: {\n        name: 'Jane'\n      }\n    }\n  ],\n};\n\nsgMail.send(msg);\n```\n\n### CC and BCC Recipients\n\nInclude CC and BCC recipients: \n\n```javascript\nsgMail.send({\n  to: 'recipient@example.org',\n  cc: 'someone@example.org',\n  bcc: ['me@example.org', 'you@example.org'],\n  from: 'sender@example.org',\n  replyTo: 'othersender@example.org',\n  subject: 'Hello world',\n  text: 'Hello plain world!',\n  html: '<p>Hello HTML world!</p>',\n});\n```\n\n## Client Configuration\n\n### MailService Configuration\n\nThe MailService class provides various configuration options: \n\n```javascript\nconst sgMail = require('@sendgrid/mail');\n\n// Set API key\nsgMail.setApiKey(process.env.SENDGRID_API_KEY);\n\n// Set timeout (in milliseconds)\nsgMail.setTimeout(10000);\n\n// Set substitution wrappers (default is {{ and }})\nsgMail.setSubstitutionWrappers('{{', '}}');\n\n// Use custom client instance\nconst {Client} = require('@sendgrid/client');\nconst customClient = new Client();\ncustomClient.setApiKey(process.env.SENDGRID_API_KEY);\nsgMail.setClient(customClient);\n```\n\n### Data Residency\n\nSet data residency for EU compliance: \n\n```javascript\nconst client = require('@sendgrid/client');\nconst sgMail = require('@sendgrid/mail');\n\n// Send to EU region\nclient.setDataResidency('eu');\nsgMail.setClient(client);\n\nconst msg = {\n  to: 'recipient@example.org',\n  from: 'sender@example.org',\n  subject: 'Hello world',\n  text: 'Hello plain world!',\n  html: '<p>Hello HTML world!</p>',\n};\n\nsgMail.send(msg);\n```\n\n## Direct API Client Usage\n\nFor accessing SendGrid's full v3 Web API: \n\n```javascript\nconst client = require('@sendgrid/client');\nclient.setApiKey(process.env.SENDGRID_API_KEY);\n\nconst request = {\n  method: 'GET',\n  url: '/v3/api_keys'\n};\n\nclient.request(request)\n.then(([response, body]) => {\n  console.log(response.statusCode);\n  console.log(body);\n})\n```\n\n### Custom Headers and Requests\n\nAdd custom headers and modify request defaults: \n\n```javascript\n// Add custom default header\nclient.setDefaultHeader('User-Agent', 'Some user agent string');\n// or\nclient.setDefaultHeader({'User-Agent': 'Some user agent string'});\n\n// Change request defaults\nclient.setDefaultRequest('baseUrl', 'https://api.sendgrid.com/');\n// or\nclient.setDefaultRequest({baseUrl: 'https://api.sendgrid.com/'});\n```\n\n### Multiple Client Instances\n\nCreate multiple client instances for different API keys: \n\n```javascript\nconst {Client} = require('@sendgrid/client');\nconst sgClient1 = new Client();\nconst sgClient2 = new Client();\nsgClient1.setApiKey('KEY1');\nsgClient2.setApiKey('KEY2');\n```\n\n## Error Handling\n\nHandle SendGrid API errors properly: \n\n```javascript\ntry {\n  await sgMail.send(msg);\n  console.log('Email sent successfully');\n} catch (error) {\n  console.error('SendGrid Error:', error);\n  \n  if (error.response) {\n    console.error('Response Status:', error.response.status);\n    console.error('Response Body:', error.response.body);\n    \n    // Handle specific error codes\n    if (error.response.status === 401) {\n      console.error('Invalid API key');\n    } else if (error.response.status === 403) {\n      console.error('Sender not verified or insufficient permissions');\n    }\n  }\n}\n```\n\n## Package Architecture\n\nThe SendGrid Node.js library follows a modular architecture: \n\n- **@sendgrid/mail** depends on **@sendgrid/client** and **@sendgrid/helpers**\n- **@sendgrid/client** handles HTTP communication with SendGrid's API \n- **@sendgrid/helpers** provides utility classes for email construction \n\n## TypeScript Support\n\nAll packages include TypeScript definitions: \n\n```typescript\nimport { MailService, MailDataRequired, ClientResponse, ResponseError } from '@sendgrid/mail';\n\nconst sgMail: MailService = require('@sendgrid/mail');\nsgMail.setApiKey(process.env.SENDGRID_API_KEY!);\n\nconst msg: MailDataRequired = {\n  to: 'test@example.com',\n  from: 'test@example.com',\n  subject: 'Sending with TypeScript',\n  text: 'Hello TypeScript world!',\n  html: '<strong>Hello TypeScript world!</strong>',\n};\n\nsgMail.send(msg)\n  .then(([response]: [ClientResponse, {}]) => {\n    console.log('Email sent, status:', response.statusCode);\n  })\n  .catch((error: ResponseError) => {\n    console.error('Error:', error);\n  });\n```\n\n## Development and Testing\n\nFor development setup: \n\n```bash\ngit clone https://github.com/sendgrid/sendgrid-nodejs.git\ncd sendgrid-nodejs\nnpm install\n```\n\nRun tests with Docker: \n\n```bash\nmake test-docker\n```\n\n## Useful Links\n\n- **Documentation:** https://docs.sendgrid.com/for-developers/sending-email/nodejs\n- **API Reference:** https://docs.sendgrid.com/api-reference/\n- **GitHub Repository:** https://github.com/sendgrid/sendgrid-nodejs\n- **Support:** https://support.sendgrid.com\n- **Pricing:** https://sendgrid.com/pricing\n\n## Notes\n\nThis SendGrid Node.js library is a monorepo containing seven specialized packages. The modular design allows you to install only the packages you need while maintaining consistency across the entire SDK. Always verify sender identities before sending emails to avoid 403 Forbidden responses.\n\n### Wiki Pages\n\n- [Monorepo Architecture (sendgrid/sendgrid-nodejs)](/wiki/sendgrid/sendgrid-nodejs#1.1)\n- [Getting Started (sendgrid/sendgrid-nodejs)](/wiki/sendgrid/sendgrid-nodejs#1.2)\n"
  },
  {
    "path": "content/sendgrid/docs/email-api/python/DOC.md",
    "content": "---\nname: email-api\ndescription: \"SendGrid Python SDK for sending emails and managing email communications via the SendGrid API.\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.12.5\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"sendgrid,email,transactional,templates,delivery\"\n---\n\n# SendGrid API Coding Guidelines (Python)\n\nYou are a SendGrid API coding expert. Help me with writing code using the SendGrid Python SDK for sending emails and managing email communications.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://sendgrid.com/docs/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official SendGrid Python SDK to send emails and interact with SendGrid's Web API v3. \n\n- **Library Name:** SendGrid Python SDK\n- **Python Package:** `sendgrid`\n- **GitHub Repository:** sendgrid/sendgrid-python\n\n**Installation:**\n\n- **Correct:** `pip install sendgrid`\n\n**APIs and Usage:**\n\n- **Correct:** `from sendgrid import SendGridAPIClient`\n- **Correct:** `from sendgrid.helpers.mail import Mail`\n- **Correct:** `sg = SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))`\n\n## Initialization and API Key\n\nThe SendGrid Python library requires creating a client object for all API calls. \n\n- Always use `SendGridAPIClient()` to create a client object.\n- Set `SENDGRID_API_KEY` environment variable, which will be picked up automatically.\n- API key can also be passed directly to the constructor.\n\n## Environment Setup\n\n### Setting API Key Environment Variable\n\n**Mac/Linux:**\n```bash\nexport SENDGRID_API_KEY='YOUR_API_KEY'\n# Or create a .env file\necho \"SENDGRID_API_KEY='YOUR_API_KEY'\" > .env\n```\n\n**Windows:**\n```bash\nset SENDGRID_API_KEY=YOUR_API_KEY\n# Or permanently:\nsetx SENDGRID_API_KEY \"YOUR_API_KEY\"\n``` \n\n## Basic Email Sending\n\n### Simple Email with Mail Helper Class\n\nHere's how to send a basic email using the Mail helper class:\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\n# Create the email message\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com',\n    subject='Sending with SendGrid is Fun',\n    html_content='<strong>and easy to do anywhere, even with Python</strong>'\n)\n\n# Send the email\ntry:\n    sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n    response = sg.send(message)\n    print(response.status_code)\n    print(response.body)\n    print(response.headers)\nexcept Exception as e:\n    print(e)\n``` \n\n### Email with Both HTML and Plain Text Content\n\n```python\nfrom sendgrid.helpers.mail import Mail, Content\nfrom sendgrid import SendGridAPIClient\nimport os\n\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com',\n    subject='Multi-format Email'\n)\n\n# Add plain text content\nmessage.add_content(Content(\"text/plain\", \"Hello, this is plain text!\"))\n\n# Add HTML content  \nmessage.add_content(Content(\"text/html\", \"<strong>Hello, this is HTML!</strong>\"))\n\nsg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\nresponse = sg.send(message)\n``` \n\n## Advanced Email Features\n\n### Using Dynamic Templates\n\nFor emails with dynamic content using SendGrid templates:\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com'\n)\n\n# Set template ID and dynamic data\nmessage.template_id = 'd-your-template-id-here'\nmessage.dynamic_template_data = {\n    'subject': 'Testing Templates',\n    'name': 'John Doe',\n    'city': 'San Francisco'\n}\n\nsg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\nresponse = sg.send(message)\n``` \n\n### Multiple Recipients\n\n```python\nfrom sendgrid.helpers.mail import Mail, To\n\n# Multiple recipients in to_emails list\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails=['user1@example.com', 'user2@example.com', 'user3@example.com'],\n    subject='Email to Multiple Recipients',\n    html_content='<strong>Hello everyone!</strong>'\n)\n``` \n\n### Adding Attachments\n\n```python\nfrom sendgrid.helpers.mail import Mail, Attachment\nimport base64\n\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com',\n    subject='Email with Attachment',\n    html_content='<strong>Please see attached file</strong>'\n)\n\n# Add attachment\nwith open('path/to/file.pdf', 'rb') as f:\n    data = f.read()\n    f.close()\n\nencoded_file = base64.b64encode(data).decode()\nattachment = Attachment(\n    file_content=encoded_file,\n    file_name='attachment.pdf',\n    file_type='application/pdf',\n    disposition='attachment'\n)\n\nmessage.add_attachment(attachment)\n``` \n\n### Personalizations for Individual Recipients\n\n```python\nfrom sendgrid.helpers.mail import Mail, Personalization, To, Subject\n\nmessage = Mail()\nmessage.from_email = 'from@example.com'\n\n# Create separate personalization for each recipient\npersonalization1 = Personalization()\npersonalization1.add_to(To('user1@example.com', 'User One'))\npersonalization1.subject = 'Personal message for User One'\n\npersonalization2 = Personalization() \npersonalization2.add_to(To('user2@example.com', 'User Two'))\npersonalization2.subject = 'Personal message for User Two'\n\nmessage.add_personalization(personalization1)\nmessage.add_personalization(personalization2)\n``` \n\n## API Client Usage\n\n### General Web API Usage (Fluent Interface)\n\nFor accessing other SendGrid APIs beyond mail sending:\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n\n# Get bounce suppressions\nresponse = sg.client.suppression.bounces.get()\nprint(response.status_code)\nprint(response.body)\n\n# Get API keys\nresponse = sg.client.api_keys.get()\nprint(response.status_code)\n``` \n\n### Alternative API Usage (Non-Fluent Interface)\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n\n# Using string path instead of fluent interface\nresponse = sg.client._(\"suppression/bounces\").get()\nprint(response.status_code)\n``` \n\n## Configuration Options\n\n### Data Residency\n\nFor EU data residency compliance:\n\n```python\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(api_key='your-api-key')\nsg.set_sendgrid_data_residency('eu')  # 'eu' or 'global'\n``` \n\n### Subuser Impersonation\n\nTo send emails on behalf of a subuser:\n\n```python\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(\n    api_key='your-api-key',\n    impersonate_subuser='subuser@example.com'\n)\n``` \n\n## Error Handling\n\nAlways wrap SendGrid API calls in try-catch blocks:\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com',\n    subject='Test Email',\n    html_content='<strong>Test</strong>'\n)\n\ntry:\n    sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n    response = sg.send(message)\n    \n    # Check response status\n    if response.status_code >= 200 and response.status_code < 300:\n        print(\"Email sent successfully!\")\n    else:\n        print(f\"Failed to send email. Status: {response.status_code}\")\n        print(f\"Response: {response.body}\")\n        \nexcept Exception as e:\n    print(f\"Error occurred: {e}\")\n``` \n\n## Best Practices\n\n### Mail Helper Class vs Raw JSON\n\n- **Recommended:** Use the Mail helper class for building emails as it provides validation and easier syntax\n- **Alternative:** Raw JSON can be used but requires manual construction of the payload \n\n### Content Ordering\n\nWhen adding multiple content types, follow this order:\n1. Plain text (`text/plain`)\n2. AMP HTML (`text/x-amp-html`) \n3. HTML (`text/html`) \n\n### Environment Variables\n\n- Always use environment variables for API keys, never hardcode them\n- Use `.env` files for local development and add them to `.gitignore` \n\n## Common Mail Helper Classes\n\nKey classes from `sendgrid.helpers.mail`:\n\n- `Mail` - Main email builder class\n- `From` - Sender email address\n- `To`, `Cc`, `Bcc` - Recipient email addresses  \n- `Content` - Email content (HTML/plain text)\n- `Attachment` - File attachments\n- `Personalization` - Individual recipient customization\n- `TemplateId` - Dynamic template reference \n\n## Useful Links\n\n- **Documentation:** https://sendgrid.com/docs/\n- **API Reference:** https://sendgrid.com/docs/API_Reference/index.html\n- **Library Documentation:** https://github.com/sendgrid/sendgrid-python\n- **Use Cases:** https://github.com/sendgrid/sendgrid-python/tree/main/use_cases\n- **Troubleshooting:** https://github.com/sendgrid/sendgrid-python/blob/main/TROUBLESHOOTING.md\n\n## Notes\n\nThis SendGrid Python SDK provides full support for SendGrid Web API v3 endpoints. The library uses the Mail helper class as the primary interface for building and sending emails, with the SendGridAPIClient handling the actual API communication. Always ensure proper error handling and use environment variables for sensitive data like API keys.\n\n## Official Documentation\n\n**This library allows you to quickly and easily use the SendGrid Web API v3 via Python.**\n\nVersion 3.X.X+ of this library provides full support for all SendGrid [Web API v3](https://sendgrid.com/docs/API_Reference/Web_API_v3/index.html) endpoints, including the new [v3 /mail/send](https://sendgrid.com/blog/introducing-v3mailsend-sendgrids-new-mail-endpoint).\n\n### Alternative Environment Setup Methods\n\n#### Mac\n\nUpdate the development environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys) (more info [here](https://sendgrid.com/docs/User_Guide/Settings/api_keys.html)), for example:\n\n```bash\necho \"export SENDGRID_API_KEY='YOUR_API_KEY'\" > sendgrid.env\necho \"sendgrid.env\" >> .gitignore\nsource ./sendgrid.env\n```\nSendGrid also supports local environment file `.env`. Copy or rename `.env_sample` into `.env` and update [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys) with your key.\n\n#### Windows\nTemporarily set the environment variable(accessible only during the current cli session):\n```bash\nset SENDGRID_API_KEY=YOUR_API_KEY\n```\nPermanently set the environment variable(accessible in all subsequent cli sessions):\n```bash\nsetx SENDGRID_API_KEY \"YOUR_API_KEY\"\n```\n## Code Examples\n\n### With Mail Helper Class\n\n```python\nimport sendgrid\nimport os\nfrom sendgrid.helpers.mail import *\n\nsg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))\nfrom_email = Email(\"test@example.com\")\nto_email = To(\"test@example.com\")\nsubject = \"Sending with SendGrid is Fun\"\ncontent = Content(\"text/plain\", \"and easy to do anywhere, even with Python\")\nmail = Mail(from_email, to_email, subject, content)\nresponse = sg.client.mail.send.post(request_body=mail.get())\nprint(response.status_code)\nprint(response.body)\nprint(response.headers)\n```\n\n### Fluent API Usage\n\n```python\nimport sendgrid\nimport os\n\nsg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))\nresponse = sg.client.suppression.bounces.get()\nprint(response.status_code)\nprint(response.body)\nprint(response.headers)\n```\n\n### Non-Fluent API Usage\n\n```python\nimport sendgrid\nimport os\n\nsg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))\nresponse = sg.client._(\"suppression/bounces\").get()\nprint(response.status_code)\nprint(response.body)\nprint(response.headers)\n```\n## SendGridAPIClient Constructor\n\n```python\ndef __init__(\n        self,\n        api_key=None,\n        host='https://api.sendgrid.com',\n        impersonate_subuser=None):\n    \"\"\"\n    Construct the Twilio SendGrid v3 API object.\n    Note that the underlying client is being set up during initialization,\n    therefore changing attributes in runtime will not affect HTTP client\n    behaviour.\n\n    :param api_key: Twilio SendGrid API key to use. If not provided, value\n                    will be read from environment variable \"SENDGRID_API_KEY\"\n    :type api_key: string\n    :param impersonate_subuser: the subuser to impersonate. Will be passed\n                                by \"On-Behalf-Of\" header by underlying\n                                client. See\n                                https://sendgrid.com/docs/User_Guide/Settings/subusers.html\n                                for more details\n    :type impersonate_subuser: string\n    :param host: base URL for API calls\n    :type host: string\n    \"\"\"\n    self.api_key = api_key or os.environ.get('SENDGRID_API_KEY')\n    auth = 'Bearer {}'.format(self.api_key)\n\n    super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser)\n```\n\n## Helper Class Imports\n\n```python\nfrom .bcc_email import Bcc\nfrom .cc_email import Cc\nfrom .content import Content\nfrom .custom_arg import CustomArg\nfrom .dynamic_template_data import DynamicTemplateData\nfrom .email import Email\nfrom .from_email import From\nfrom .header import Header\nfrom .mime_type import MimeType\nfrom .personalization import Personalization\nfrom .reply_to import ReplyTo\nfrom .send_at import SendAt\nfrom .subject import Subject\nfrom .substitution import Substitution\nfrom .template_id import TemplateId\nfrom .to_email import To\n```\n\n## Mail Methods\n\n### Add Personalization\n\n```python\ndef add_personalization(self, personalization, index=0):\n    \"\"\"Add a Personalization object\n\n    :param personalization: Add a Personalization object\n    :type personalization: Personalization\n    :param index: The index where to add the Personalization\n    :type index: int\n    \"\"\"\n    self._personalizations = self._ensure_append(\n        personalization, self._personalizations, index)\n```\n\n### Add To Recipients\n\n```python\ndef add_to(\n        self, to_email, global_substitutions=None, is_multiple=False, p=0):\n    \"\"\"Adds a To object to the Personalization object\n\n    :param to_email: A To object\n    :type to_email: To, str, tuple, list(str), list(tuple), list(To)\n    :param global_substitutions: A dict of substitutions for all recipients\n    :type global_substitutions: dict\n    :param is_multiple: Create a new personalization for each recipient\n    :type is_multiple: bool\n    :param p: p is the Personalization object or Personalization object\n              index\n    :type p: Personalization, integer, optional\n    \"\"\"\n\n    if isinstance(to_email, list):\n        for email in to_email:\n            if isinstance(email, str):\n                email = To(email, None)\n            elif isinstance(email, tuple):\n                email = To(email[0], email[1])\n            elif not isinstance(email, Email):\n                raise ValueError(\n                    'Please use a To/Cc/Bcc, tuple, or a str for a to_email list.'\n                )\n            self._set_emails(email, global_substitutions, is_multiple, p)\n    else:\n        if isinstance(to_email, str):\n            to_email = To(to_email, None)\n        if isinstance(to_email, tuple):\n            to_email = To(to_email[0], to_email[1])\n        if isinstance(to_email, Email):\n            p = to_email.personalization\n        self._set_emails(to_email, global_substitutions, is_multiple, p)\n```\n\n### Add Content\n\n```python\ndef add_content(self, content, mime_type=None):\n    \"\"\"Add content to the email\n\n    :param contents: Content to be added to the email\n    :type contents: Content\n    :param mime_type: Override the mime type\n    :type mime_type: MimeType, str\n    \"\"\"\n    if isinstance(content, str):\n        content = Content(mime_type, content)\n    # Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html\n    if content.mime_type == MimeType.text:\n        self._contents = self._ensure_insert(content, self._contents)\n    elif content.mime_type == MimeType.amp:\n        if self._contents:\n            for _content in self._contents:\n                # this is written in the context that plain text content will always come earlier than the html content\n                if _content.mime_type == MimeType.text:\n                    index = 1\n                    break\n                elif _content.mime_type == MimeType.html:\n                    index = 0\n                    break\n        else:\n            index = 0\n        self._contents = self._ensure_append(\n            content, self._contents, index=index)\n    else:\n        if self._contents:\n            index = len(self._contents)\n        else:\n            index = 0\n        self._contents = self._ensure_append(\n            content, self._contents, index=index)\n```\n\n### Add Attachment\n\n```python\ndef add_attachment(self, attachment):\n    \"\"\"Add an attachment to this email\n\n    :param attachment: Add an attachment to this email\n    :type attachment: Attachment\n    \"\"\"\n    self._attachments = self._ensure_append(attachment, self._attachments)\n```\n\n## Template Usage Example\n\n```python\nmessage = Mail(\n    from_email='from_email@example.com',\n    to_emails='to@example.com',\n    html_content='<strong>and easy to do anywhere, even with Python</strong>')\nmessage.dynamic_template_data = {\n    'subject': 'Testing Templates',\n    'name': 'Some One',\n    'city': 'Denver'\n}\nmessage.template_id = 'd-f43daeeaef504760851f727007e0b5d0'\ntry:\n    sendgrid_client = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n    response = sendgrid_client.send(message)\n    print(response.status_code)\n    print(response.body)\n    print(response.headers)\nexcept Exception as e:\n    print(e.message)\n```\n\n## SendGridAPIClient Methods\n\n### Send Method\n\n```python\ndef send(self, message):\n    \"\"\"Make a Twilio SendGrid v3 API request with the request body generated by\n       the Mail object\n\n    :param message: The Twilio SendGrid v3 API request body generated by the Mail\n                    object\n    :type message: Mail\n    \"\"\"\n    if not isinstance(message, dict):\n        message = message.get()\n\n    return self.client.mail.send.post(request_body=message)\n```\n\n### Data Residency Method\n\n```python\ndef set_sendgrid_data_residency(self, region):\n    \"\"\"\n    Client libraries contain setters for specifying region/edge.\n    This supports global and eu regions only. This set will likely expand in the future.\n    Global is the default residency (or region)\n    Global region means the message will be sent through https://api.sendgrid.com\n    EU region means the message will be sent through https://api.eu.sendgrid.com\n    :param region: string\n    :return:\n    \"\"\"\n    if region in region_host_dict.keys():\n        self.host = region_host_dict[region]\n        if self._default_headers is not None:\n            self.client = python_http_client.Client(\n                host=self.host,\n                request_headers=self._default_headers,\n                version=3)\n    else:\n        raise ValueError(\"region can only be \\\"eu\\\" or \\\"global\\\"\")\n```\n\n## Final Error Handling Example\n\n```python\ntry:\n    sendgrid_client = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n    response = sendgrid_client.send(message)\n    print(response.status_code)\n    print(response.body)\n    print(response.headers)\nexcept Exception as e:\n    print(e)\n```\n"
  },
  {
    "path": "content/sendgrid/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Twilio SendGrid Python SDK for sending email and calling the SendGrid Web API v3\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.12.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sendgrid,twilio,email,transactional-email,templates,delivery\"\n---\n\n# SendGrid Python Package Guide\n\n## Golden Rule\n\nUse `sendgrid` for Twilio SendGrid Web API v3 access in Python. Authenticate with an API key, verify your sender identity before sending mail, use the `Mail` helper for normal email sends, and drop to `sg.client` when you need endpoints outside the helper surface.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"sendgrid==6.12.5\"\n```\n\nUse a virtual environment for local work:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"sendgrid==6.12.5\"\n```\n\nThe package depends on `python-http-client` and `cryptography`.\n\n## Authentication And Setup\n\nTwilio SendGrid's Mail Send API uses bearer-token authentication. Create a restricted API key in the SendGrid console and keep it in `SENDGRID_API_KEY`.\n\n```bash\nexport SENDGRID_API_KEY=\"SG...\"\n```\n\nBasic client setup:\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\n```\n\nSender verification is required before delivery will work:\n\n- `Single Sender Verification` is fine for proofs of concept and testing.\n- `Domain Authentication` is the preferred production setup and lets you send from any address on the authenticated domain.\n\n## Core Usage\n\n### Send a basic HTML email\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email=\"from@example.com\",\n    to_emails=\"to@example.com\",\n    subject=\"Sending with Twilio SendGrid is Fun\",\n    html_content=\"<strong>and easy to do anywhere, even with Python</strong>\",\n)\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\nresponse = sg.send(message)\n\nprint(response.status_code)  # 202 on accepted live sends\nprint(response.headers)\n```\n\nUse `sg.send(message)` for the common case. This is the path shown in Twilio's Python quickstart.\n\n### Send with a dynamic template\n\nDynamic templates use a `template_id` beginning with `d-` and data supplied through `dynamic_template_data`.\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email=\"billing@example.com\",\n    to_emails=\"customer@example.com\",\n)\nmessage.template_id = \"d-1234567890abcdef1234567890abcdef\"\nmessage.dynamic_template_data = {\n    \"first_name\": \"Ada\",\n    \"invoice_total\": \"$42.00\",\n    \"invoice_url\": \"https://example.com/invoices/42\",\n}\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\nsg.send(message)\n```\n\n### Add an attachment\n\nThe Mail Send API expects attachment content to be Base64-encoded.\n\n```python\nimport base64\nimport os\n\nfrom sendgrid import SendGridAPIClient\n\nwith open(\"invoice.pdf\", \"rb\") as fh:\n    encoded = base64.b64encode(fh.read()).decode()\n\npayload = {\n    \"personalizations\": [\n        {\n            \"to\": [{\"email\": \"to@example.com\"}],\n        }\n    ],\n    \"from\": {\"email\": \"from@example.com\"},\n    \"subject\": \"Invoice\",\n    \"content\": [\n        {\n            \"type\": \"text/plain\",\n            \"value\": \"See attached.\",\n        }\n    ],\n    \"attachments\": [\n        {\n            \"content\": encoded,\n            \"filename\": \"invoice.pdf\",\n            \"type\": \"application/pdf\",\n            \"disposition\": \"attachment\",\n        }\n    ],\n}\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\nsg.client.mail.send.post(request_body=payload)\n```\n\n### Call non-mail endpoints with the fluent client\n\nThe package exposes the full Web API v3 via `sg.client`, which is useful for suppressions, stats, templates, marketing, and admin APIs.\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\n\nresponse = sg.client.suppression.bounces.get()\nprint(response.status_code)\nprint(response.body)\n```\n\n## Validation And Safe Testing\n\nUse SendGrid sandbox mode when you want request validation without real delivery. Sandbox requests return `200 OK`; successful live Mail Send requests return `202 Accepted`.\n\n```python\nimport os\nfrom sendgrid import SendGridAPIClient\n\npayload = {\n    \"personalizations\": [\n        {\n            \"to\": [{\"email\": \"to@example.com\"}],\n        }\n    ],\n    \"from\": {\"email\": \"from@example.com\"},\n    \"subject\": \"Sandbox test\",\n    \"content\": [\n        {\n            \"type\": \"text/plain\",\n            \"value\": \"This request should validate without sending.\",\n        }\n    ],\n    \"mail_settings\": {\n        \"sandbox_mode\": {\n            \"enable\": True,\n        }\n    },\n}\n\nsg = SendGridAPIClient(api_key=os.environ[\"SENDGRID_API_KEY\"])\nresponse = sg.client.mail.send.post(request_body=payload)\nprint(response.status_code)  # 200 in sandbox mode\n```\n\n## Common Pitfalls\n\n- A `202 Accepted` response means the API accepted the request. It does not prove inbox delivery. Twilio's Event Webhook docs distinguish `processed` from `delivered`, so use event tracking or Email Activity when delivery status matters.\n- The `from` address must be a verified sender. The Mail Send API reference calls this out explicitly.\n- `Single Sender Verification` is for testing. Complete `Domain Authentication` before production sending.\n- Dynamic templates require `template_id` values starting with `d-`; older standard templates use `substitutions` instead of `dynamic_template_data`.\n- Attachment content must be Base64-encoded before you send it.\n- The `on-behalf-of` header does not work with the Mail Send API. Use it only for supported parent-account and subuser admin endpoints.\n- EU regional subusers must target `https://api.eu.sendgrid.com` instead of the global base URL.\n\n## Version-Sensitive Notes\n\n- The version used here `6.12.5` matches the current stable PyPI release as of March 12, 2026.\n- PyPI also lists `7.0.0rc1` and `7.0.0rc2` as pre-releases. Do not assume 7.x examples apply to the stable package.\n- PyPI's project description says the `6.x` line is a breaking change from `5.x`; do not copy `5.x` tutorials into a `6.12.5` project without checking release notes.\n- The Twilio quickstart page is stale in two places: it still says the SDK supports Python `2.7, 3.5, 3.6, 3.7, and 3.8`, and its sample install output still shows `sendgrid-6.4.6`. PyPI classifiers for `6.12.5` include Python `3.12` and `3.13`, and the upstream changelog says `6.12.0` added Python `3.12` and `3.13` support.\n\n## Official Sources\n\n- Twilio SendGrid Python quickstart: `https://www.twilio.com/docs/sendgrid/for-developers/sending-email/quickstart-python`\n- Twilio SendGrid Mail Send API reference: `https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send`\n- Twilio SendGrid Sender Identity guide: `https://www.twilio.com/docs/sendgrid/for-developers/sending-email/sender-identity`\n- Twilio SendGrid Sandbox Mode guide: `https://www.twilio.com/docs/sendgrid/for-developers/sending-email/sandbox-mode`\n- Twilio SendGrid Event Webhook reference: `https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event`\n- Twilio SendGrid On Behalf Of reference: `https://www.twilio.com/docs/sendgrid/api-reference/how-to-use-the-sendgrid-v3-api/on-behalf-of`\n- PyPI package page: `https://pypi.org/project/sendgrid/`\n- Upstream changelog: `https://raw.githubusercontent.com/sendgrid/sendgrid-python/main/CHANGELOG.md`\n"
  },
  {
    "path": "content/sentence-transformers/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"sentence-transformers package guide for Python embeddings, retrieval, reranking, and Hugging Face model loading\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.2.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sentence-transformers,embeddings,retrieval,reranking,semantic-search,hugging-face,transformers\"\n---\n\n# sentence-transformers Python Package Guide\n\n## What It Is\n\n`sentence-transformers` is the maintainer-supported Python library for:\n\n- dense embeddings with `SentenceTransformer`\n- reranking and pair scoring with `CrossEncoder`\n- sparse retrieval models with `SparseEncoder`\n\nIt is a local Python package, not a hosted API. In normal use it downloads models from the Hugging Face Hub or loads them from a local path.\n\n## Golden Rules\n\n- Install `sentence-transformers` and load an explicit model ID such as `all-MiniLM-L6-v2` or `cross-encoder/ms-marco-MiniLM-L-6-v2`.\n- Use `encode_query()` and `encode_document()` for retrieval tasks in v5 when you have a real query/document split.\n- Use `CrossEncoder` for reranking or pair classification, not for precomputing reusable embeddings.\n- Treat `trust_remote_code=True` as code execution. Only enable it for repositories you trust.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"sentence-transformers==5.2.3\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sentence-transformers==5.2.3\"\npoetry add \"sentence-transformers==5.2.3\"\n```\n\nUseful extras from the official installation docs and package metadata:\n\n```bash\npython -m pip install \"sentence-transformers[train]==5.2.3\"\npython -m pip install \"sentence-transformers[onnx]==5.2.3\"\npython -m pip install \"sentence-transformers[onnx-gpu]==5.2.3\"\npython -m pip install \"sentence-transformers[openvino]==5.2.3\"\n```\n\nInstall notes:\n\n- The project recommends Python `3.10+` and PyTorch `1.11.0+`.\n- PyPI metadata for `5.2.3` requires `transformers>=4.41.0,<6.0.0`.\n- If you need CUDA, install the matching PyTorch build first from the official PyTorch instructions, then install `sentence-transformers`.\n\n## Model Loading And Setup\n\nBasic embedding model:\n\n```python\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\"all-MiniLM-L6-v2\")\n```\n\nUseful constructor options for real projects:\n\n```python\nimport os\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\n    \"BAAI/bge-base-en-v1.5\",\n    device=\"cuda\",\n    token=os.getenv(\"HF_TOKEN\"),\n    revision=\"main\",\n    cache_folder=\"/tmp/sentence-transformers-cache\",\n)\n```\n\nConfiguration points that matter:\n\n- `token=` is the supported auth argument for private or gated Hugging Face models.\n- `use_auth_token=` is deprecated; use `token=` instead.\n- `revision=` can pin a branch, tag, or commit on the Hugging Face Hub.\n- `cache_folder=` overrides the model cache path. You can also set `SENTENCE_TRANSFORMERS_HOME`.\n- `local_files_only=True` avoids network calls and only loads already-downloaded local artifacts.\n- `backend=` can be `torch`, `onnx`, or `openvino`; the non-`torch` backends require the matching extra.\n\n## Core Usage\n\n### Create embeddings\n\nUse `SentenceTransformer` for semantic similarity, clustering, search indexing, and retrieval.\n\n```python\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\"all-MiniLM-L6-v2\")\n\nsentences = [\n    \"The weather is lovely today.\",\n    \"It is sunny outside.\",\n    \"He drove to the stadium.\",\n]\n\nembeddings = model.encode(\n    sentences,\n    normalize_embeddings=True,\n    convert_to_numpy=True,\n)\n\nprint(embeddings.shape)\n```\n\nIf you need pairwise similarity after encoding:\n\n```python\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\"all-MiniLM-L6-v2\")\nembeddings = model.encode([\"A cat sits outside.\", \"A dog plays in the yard.\"])\nsimilarities = model.similarity(embeddings, embeddings)\nprint(similarities)\n```\n\n### Retrieval: use `encode_query()` and `encode_document()`\n\nIn v5, these methods are the preferred path for information retrieval because they can apply saved prompts and Router task routing when the model supports them.\n\n```python\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\"mixedbread-ai/mxbai-embed-large-v1\")\n\nquery = \"How do I export a model to ONNX?\"\ndocuments = [\n    \"Use the export_dynamic_quantized_onnx_model helper for dynamic quantization.\",\n    \"CrossEncoder models score query-document pairs directly.\",\n    \"OpenVINO can improve CPU inference latency.\",\n]\n\nquery_embedding = model.encode_query(query, normalize_embeddings=True)\ndocument_embeddings = model.encode_document(documents, normalize_embeddings=True)\n\nscores = model.similarity(query_embedding, document_embeddings)\nbest_index = scores[0].argmax().item()\nprint(documents[best_index])\n```\n\nUse plain `encode()` when you do not have a query/document distinction, or when you are doing clustering, deduplication, or semantic similarity between peers.\n\n### Rerank with `CrossEncoder`\n\nUse a cross-encoder after retrieval when you need higher-quality ranking on a smaller candidate set.\n\n```python\nfrom sentence_transformers.cross_encoder import CrossEncoder\n\nquery = \"How many people live in Berlin?\"\ndocuments = [\n    \"Berlin had a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.\",\n    \"Berlin is known for its museums.\",\n]\n\nmodel = CrossEncoder(\"cross-encoder/ms-marco-MiniLM-L-6-v2\")\nscores = model.predict([(query, doc) for doc in documents])\n\nranked = sorted(zip(documents, scores), key=lambda item: item[1], reverse=True)\nprint(ranked[0])\n```\n\nRule of thumb:\n\n- `SentenceTransformer`: fast embeddings you can precompute and index\n- `CrossEncoder`: slower but better scoring for query-document pairs\n\n### Faster inference backends\n\nIf you installed the matching extra, you can load the same model with a non-default backend:\n\n```python\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\"all-MiniLM-L6-v2\", backend=\"onnx\")\nembeddings = model.encode([\"hello world\"])\n```\n\nUse this when the deployment target is inference-only and you have already validated that the backend-specific export path works for the chosen model.\n\n## Auth And Configuration\n\nThis package does not use API keys of its own. Authentication is only relevant when the underlying model is private or gated on the Hugging Face Hub.\n\nPrivate model example:\n\n```python\nimport os\nfrom sentence_transformers import SentenceTransformer\n\nmodel = SentenceTransformer(\n    \"my-org/private-embedding-model\",\n    token=os.environ[\"HF_TOKEN\"],\n)\n```\n\nOperational settings agents often need:\n\n- `device=\"cpu\"`, `\"cuda\"`, or `\"mps\"` for explicit hardware selection\n- `similarity_fn_name=\"cosine\"` or `\"dot\"` when you want an explicit similarity mode\n- `batch_size=` for throughput tuning\n- `truncate_dim=` when using Matryoshka-style models and you want smaller embeddings\n- `prompt_name=` or `prompt=` when the model expects prompt-specific encoding behavior\n\n## Common Pitfalls\n\n- The package name is not a model name. `pip install sentence-transformers` does not give you a default embedding model; you still need to load one.\n- `CrossEncoder` and `SentenceTransformer` are not interchangeable. Cross-encoders score pairs directly and do not produce reusable corpus embeddings.\n- Retrieval models in the v5 line may behave better with `encode_query()` and `encode_document()` than with plain `encode()`, especially when prompts or Router modules are saved with the model.\n- `trust_remote_code=True` runs repository-defined code from the model source. Keep it off unless you have reviewed the model repo.\n- Offline or air-gapped runs need either a local model path or a warm cache plus `local_files_only=True`.\n- Embedding scores are only comparable when you use the same model family and a consistent normalization/similarity setup.\n- `encode_multi_process()` is deprecated in the v5 migration guide. Prefer `encode(..., device=[...], chunk_size=...)` for multi-process encoding.\n\n## Version-Sensitive Notes\n\n- This guide covers the package version used here `5.2.3`.\n- PyPI now lists `5.3.0` as the latest release on `2026-03-12`, so there is already upstream version drift relative to the pinned package version.\n- The v5 line introduced `SparseEncoder`, `encode_query()`, `encode_document()`, Router-based asymmetric routing, and the deprecation of older `encode_multi_process()`-style flows.\n- The official docs homepage still foregrounds the `v5.2` release train, while PyPI has already moved to `5.3.0`. When exact patch behavior matters, check both the current docs and the package release history before copying older snippets.\n"
  },
  {
    "path": "content/sentry/docs/error-tracking/javascript/DOC.md",
    "content": "---\nname: error-tracking\ndescription: \"Sentry JavaScript SDK for error tracking, performance monitoring, and distributed tracing in Node.js and browser applications.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"10.23.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"sentry,monitoring,error-tracking,performance,tracing\"\n---\n\n# Sentry JavaScript SDK (10.23.0)\n\n## Golden Rule\n\n**ALWAYS use `@sentry/node` for Node.js applications or `@sentry/browser` for browser applications.**\n\nThe current stable version is **10.23.0**. Do not use deprecated packages like `raven` or `raven-js`.\n\nFor framework-specific applications, use the appropriate package:\n- `@sentry/react` for React\n- `@sentry/nextjs` for Next.js\n- `@sentry/vue` for Vue\n- `@sentry/angular` for Angular\n\n## Installation\n\n### Node.js Applications\n\n```bash\nnpm install @sentry/node --save\n```\n\n### Browser Applications\n\n```bash\nnpm install @sentry/browser --save\n```\n\n### Framework-Specific\n\n```bash\nnpm install @sentry/react --save\nnpm install @sentry/nextjs --save\nnpm install @sentry/vue --save\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file:\n\n```env\nSENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0\nSENTRY_ENVIRONMENT=production\nSENTRY_RELEASE=my-project@1.0.0\n```\n\n## Initialization\n\n### Node.js Initialization\n\nCreate an `instrument.js` file and import it **before** any other modules:\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\nconst { nodeProfilingIntegration } = require(\"@sentry/profiling-node\");\n\nSentry.init({\n  dsn: process.env.SENTRY_DSN,\n  environment: process.env.SENTRY_ENVIRONMENT || \"development\",\n  release: process.env.SENTRY_RELEASE,\n\n  // Performance Monitoring\n  tracesSampleRate: 1.0, // Capture 100% of transactions for performance\n\n  // Profiling\n  integrations: [\n    nodeProfilingIntegration(),\n  ],\n  profilesSampleRate: 1.0,\n\n  // Send user IP and cookies\n  sendDefaultPii: true,\n\n  // Enable logging to Sentry\n  enableLogs: true,\n});\n\nmodule.exports = Sentry;\n```\n\nThen import it first in your main file:\n\n```javascript\nrequire('./instrument');\n\nconst express = require('express');\nconst app = express();\n\n// Your application code\n```\n\n### Browser Initialization\n\n```javascript\nimport * as Sentry from \"@sentry/browser\";\n\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  // Environment and release tracking\n  environment: \"production\",\n  release: \"my-project@2.3.12\",\n\n  // Performance Monitoring\n  tracesSampleRate: 1.0,\n  integrations: [\n    Sentry.browserTracingIntegration(),\n  ],\n\n  // Session Replay\n  replaysSessionSampleRate: 0.1, // 10% of sessions\n  replaysOnErrorSampleRate: 1.0, // 100% of sessions with errors\n\n  // Send user PII\n  sendDefaultPii: true,\n});\n```\n\n### React Initialization\n\n```javascript\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport * as Sentry from \"@sentry/react\";\nimport App from \"./App\";\n\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.browserTracingIntegration(),\n    Sentry.replayIntegration(),\n  ],\n  tracesSampleRate: 1.0,\n  replaysSessionSampleRate: 0.1,\n  replaysOnErrorSampleRate: 1.0,\n});\n\nReactDOM.render(<App />, document.getElementById(\"root\"));\n```\n\n## Error Tracking\n\n### Capture Exceptions\n\n**Automatic Error Capture:**\n\nSentry automatically captures unhandled exceptions and promise rejections.\n\n```javascript\n// This error will be automatically captured\nthrow new Error(\"Something went wrong!\");\n```\n\n**Manual Error Capture:**\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\ntry {\n  someFailingFunction();\n} catch (error) {\n  Sentry.captureException(error);\n}\n```\n\n**Capture with Context:**\n\n```javascript\ntry {\n  processPayment(userId);\n} catch (error) {\n  Sentry.withScope((scope) => {\n    scope.setTag(\"payment_method\", \"credit_card\");\n    scope.setUser({ id: userId });\n    scope.setLevel(\"error\");\n    Sentry.captureException(error);\n  });\n}\n```\n\n### Capture Messages\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\n// Simple message\nSentry.captureMessage(\"User completed checkout\");\n\n// Message with severity level\nSentry.captureMessage(\"Payment processing slow\", \"warning\");\n\n// Available levels: \"fatal\", \"error\", \"warning\", \"log\", \"info\", \"debug\"\nSentry.captureMessage(\"Critical system failure\", \"fatal\");\n```\n\n### Message with Context\n\n```javascript\nSentry.withScope((scope) => {\n  scope.setTag(\"section\", \"checkout\");\n  scope.setExtra(\"cart_total\", 129.99);\n  Sentry.captureMessage(\"Checkout completed\", \"info\");\n});\n```\n\n## Enriching Error Data\n\n### Set User Information\n\n```javascript\nSentry.setUser({\n  id: \"12345\",\n  email: \"user@example.com\",\n  username: \"john_doe\",\n  ip_address: \"{{auto}}\", // Automatically capture IP\n});\n\n// Clear user data\nSentry.setUser(null);\n```\n\n### Set Tags\n\nTags are searchable key-value pairs:\n\n```javascript\n// Set single tag\nSentry.setTag(\"page_locale\", \"en-us\");\nSentry.setTag(\"environment\", \"staging\");\n\n// Set multiple tags\nSentry.setTags({\n  page_locale: \"en-us\",\n  user_type: \"premium\",\n  platform: \"web\",\n});\n```\n\n### Set Context\n\nContext adds structured data to events:\n\n```javascript\nSentry.setContext(\"character\", {\n  name: \"Mighty Fighter\",\n  age: 19,\n  attack_type: \"melee\",\n  level: 42,\n});\n\nSentry.setContext(\"order\", {\n  id: \"ORD-12345\",\n  total: 249.99,\n  items: 5,\n  shipping_method: \"express\",\n});\n```\n\n### Set Extra Data\n\n```javascript\nSentry.setExtra(\"debug_data\", {\n  last_query: \"SELECT * FROM users\",\n  response_time: 1234,\n});\n```\n\n### Add Breadcrumbs\n\nBreadcrumbs create a trail of events leading to an error:\n\n```javascript\nimport * as Sentry from \"@sentry/browser\";\n\n// Manual breadcrumb\nSentry.addBreadcrumb({\n  category: \"auth\",\n  message: \"User logged in\",\n  level: \"info\",\n});\n\nSentry.addBreadcrumb({\n  category: \"api\",\n  message: \"API request to /users\",\n  level: \"info\",\n  data: {\n    url: \"/api/users\",\n    method: \"GET\",\n    status_code: 200,\n  },\n});\n\nSentry.addBreadcrumb({\n  category: \"navigation\",\n  message: \"User navigated to checkout\",\n  level: \"info\",\n  data: {\n    from: \"/cart\",\n    to: \"/checkout\",\n  },\n});\n```\n\n**Automatic Breadcrumbs:**\n\nThe SDK automatically captures:\n- DOM clicks and key presses\n- XHR/fetch requests\n- Console API calls\n- Navigation/location changes\n\n**Filter Breadcrumbs:**\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  beforeBreadcrumb(breadcrumb, hint) {\n    // Filter out UI click events\n    if (breadcrumb.category === \"ui.click\") {\n      return null;\n    }\n\n    // Modify breadcrumb\n    if (breadcrumb.category === \"console\") {\n      breadcrumb.level = \"debug\";\n    }\n\n    return breadcrumb;\n  },\n});\n```\n\n## Scopes\n\nScopes contain data that is attached to events.\n\n### Global Scope\n\n```javascript\n// Set data on global scope (affects all events)\nSentry.getGlobalScope().setTag(\"app_version\", \"1.0.0\");\nSentry.getGlobalScope().setExtras({\n  shared: \"global\",\n  global: \"data\",\n});\n```\n\n### Isolation Scope\n\n```javascript\n// Set data on isolation scope (default scope for most operations)\nSentry.setTag(\"my-tag\", \"my value\");\n\n// Equivalent to:\nSentry.getIsolationScope().setTag(\"my-tag\", \"my value\");\n```\n\n### Current Scope\n\n```javascript\n// Set data on current scope\nSentry.getCurrentScope().setTag(\"request_id\", \"abc123\");\n```\n\n### Temporary Scope with withScope\n\n```javascript\n// Create temporary scope for specific error\nSentry.withScope((scope) => {\n  scope.setTag(\"section\", \"payment\");\n  scope.setLevel(\"warning\");\n  scope.setUser({ id: \"12345\" });\n  Sentry.captureException(new Error(\"Payment failed\"));\n});\n\n// This error won't have the above tags\nSentry.captureException(new Error(\"Another error\"));\n```\n\n**Multiple Scopes:**\n\n```javascript\nSentry.withScope((scope) => {\n  scope.setTag(\"my-tag\", \"my value\");\n  scope.setLevel(\"warning\");\n  Sentry.captureException(new Error(\"my error\")); // Has tag and level\n});\n\nSentry.captureException(new Error(\"my other error\")); // No tag or level\n```\n\n### Scope Data Precedence\n\n```javascript\n// Global scope (lowest priority)\nSentry.getGlobalScope().setExtras({\n  shared: \"global\",\n  global: \"data\",\n});\n\n// Isolation scope (medium priority)\nSentry.getIsolationScope().setExtras({\n  shared: \"isolation\",\n  isolation: \"data\",\n});\n\n// Current scope (highest priority)\nSentry.getCurrentScope().setExtras({\n  shared: \"current\",\n  current: \"data\",\n});\n\n// Event will have: { shared: \"current\", global: \"data\", isolation: \"data\", current: \"data\" }\nSentry.captureException(new Error(\"my error\"));\n```\n\n## Performance Monitoring\n\n### Basic Transaction\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\n// Synchronous operation\nconst result = Sentry.startSpan(\n  {\n    name: \"Process Order\",\n    op: \"task\",\n  },\n  () => {\n    return processOrder();\n  }\n);\n```\n\n### Async Transaction\n\n```javascript\nconst result = await Sentry.startSpan(\n  {\n    name: \"Fetch User Data\",\n    op: \"http.client\",\n  },\n  async () => {\n    const response = await fetch(\"https://api.example.com/users\");\n    const data = await response.json();\n    return data;\n  }\n);\n```\n\n### Nested Spans\n\n```javascript\nawait Sentry.startSpan(\n  {\n    name: \"Handle Request\",\n    op: \"http.server\",\n  },\n  async () => {\n    // Child span 1\n    await Sentry.startSpan(\n      {\n        name: \"Database Query\",\n        op: \"db.query\",\n      },\n      async () => {\n        return await db.query(\"SELECT * FROM users\");\n      }\n    );\n\n    // Child span 2\n    await Sentry.startSpan(\n      {\n        name: \"Process Results\",\n        op: \"task\",\n      },\n      async () => {\n        return await processResults();\n      }\n    );\n  }\n);\n```\n\n### Manual Span Management\n\nFor cases where automatic span ending doesn't work:\n\n```javascript\nfunction middleware(_req, res, next) {\n  return Sentry.startSpanManual(\n    {\n      name: \"middleware\",\n      op: \"middleware\",\n    },\n    (span) => {\n      res.once(\"finish\", () => {\n        span.setHttpStatus(res.status);\n        span.end();\n      });\n      return next();\n    }\n  );\n}\n```\n\n### Add Span Attributes\n\n```javascript\nSentry.startSpan(\n  {\n    name: \"Process Payment\",\n    op: \"payment\",\n    attributes: {\n      payment_method: \"credit_card\",\n      amount: 99.99,\n      currency: \"USD\",\n      user_id: \"12345\",\n    },\n  },\n  () => {\n    return processPayment();\n  }\n);\n```\n\n### Span Operations\n\nUse standard operation names:\n\n```javascript\n// HTTP requests\nSentry.startSpan({ name: \"GET /api/users\", op: \"http.client\" }, fetchUsers);\n\n// Database queries\nSentry.startSpan({ name: \"SELECT users\", op: \"db.query\" }, queryUsers);\n\n// Cache operations\nSentry.startSpan({ name: \"Get from cache\", op: \"cache.get\" }, getCache);\n\n// File operations\nSentry.startSpan({ name: \"Read file\", op: \"file.read\" }, readFile);\n\n// Custom tasks\nSentry.startSpan({ name: \"Process data\", op: \"task\" }, processData);\n```\n\n### Access Current Span\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\nfunction processItem(item) {\n  const span = Sentry.getActiveSpan();\n\n  if (span) {\n    span.setAttribute(\"item_id\", item.id);\n    span.setAttribute(\"item_type\", item.type);\n  }\n\n  // Process item\n}\n```\n\n### Express.js Integration\n\n```javascript\nconst express = require(\"express\");\nconst Sentry = require(\"./instrument\");\n\nconst app = express();\n\n// RequestHandler creates a separate execution context\napp.use(Sentry.expressIntegration());\n\napp.get(\"/\", function rootHandler(req, res) {\n  res.end(\"Hello world!\");\n});\n\napp.get(\"/debug-sentry\", function mainHandler(req, res) {\n  throw new Error(\"My first Sentry error!\");\n});\n\n// ErrorHandler must be registered before any other error middleware\napp.use(Sentry.expressErrorHandler());\n\n// Optional fallthrough error handler\napp.use(function onError(err, req, res, next) {\n  res.statusCode = 500;\n  res.end(res.sentry + \"\\n\");\n});\n\napp.listen(3000);\n```\n\n## Session Replay\n\nSession Replay captures user interactions for debugging.\n\n### Basic Session Replay Setup\n\n```javascript\nimport * as Sentry from \"@sentry/browser\";\n\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  integrations: [\n    Sentry.replayIntegration({\n      maskAllText: true,\n      blockAllMedia: true,\n    }),\n  ],\n\n  // Sample 10% of all sessions\n  replaysSessionSampleRate: 0.1,\n\n  // Sample 100% of sessions with errors\n  replaysOnErrorSampleRate: 1.0,\n});\n```\n\n### Session Replay Configuration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  integrations: [\n    Sentry.replayIntegration({\n      // Privacy settings\n      maskAllText: true,\n      maskAllInputs: true,\n      blockAllMedia: true,\n\n      // Network details\n      networkDetailAllowUrls: [\"https://api.example.com\"],\n      networkRequestHeaders: [\"X-Custom-Header\"],\n      networkResponseHeaders: [\"X-Custom-Header\"],\n\n      // Performance\n      networkCaptureBodies: true,\n\n      // Canvas recording (experimental)\n      // Note: No PII scrubbing for canvas!\n    }),\n\n    // Optional: Canvas recording\n    Sentry.replayCanvasIntegration(),\n  ],\n\n  replaysSessionSampleRate: 0.1,\n  replaysOnErrorSampleRate: 1.0,\n});\n```\n\n### Lazy-Load Session Replay\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [],\n});\n\n// Load replay later (e.g., after user interaction)\nimport(\"@sentry/browser\").then((lazyLoadedSentry) => {\n  Sentry.addIntegration(\n    lazyLoadedSentry.replayIntegration({\n      maskAllText: true,\n      blockAllMedia: true,\n    })\n  );\n});\n```\n\n## Source Maps\n\nUpload source maps to see readable stack traces:\n\n### Install Sentry CLI\n\n```bash\nnpm install @sentry/cli --save-dev\n```\n\n### Configure Source Maps Upload\n\nCreate `.sentryclirc`:\n\n```ini\n[auth]\ntoken=YOUR_AUTH_TOKEN\n\n[defaults]\nurl=https://sentry.io/\norg=your-organization\nproject=your-project\n```\n\n### Upload with Webpack\n\n```javascript\nconst SentryWebpackPlugin = require(\"@sentry/webpack-plugin\");\n\nmodule.exports = {\n  // ... other webpack config\n\n  plugins: [\n    new SentryWebpackPlugin({\n      authToken: process.env.SENTRY_AUTH_TOKEN,\n      org: \"your-organization\",\n      project: \"your-project\",\n      include: \"./dist\",\n      ignore: [\"node_modules\", \"webpack.config.js\"],\n    }),\n  ],\n};\n```\n\n### Manual Upload\n\n```bash\nsentry-cli releases files VERSION upload-sourcemaps /path/to/files\n```\n\n## Event Filtering\n\n### Before Send Hook\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  beforeSend(event, hint) {\n    // Don't send events in development\n    if (process.env.NODE_ENV === \"development\") {\n      return null;\n    }\n\n    // Filter out specific errors\n    if (event.exception) {\n      const error = hint.originalException;\n      if (error && error.message && error.message.match(/network error/i)) {\n        return null;\n      }\n    }\n\n    // Modify event\n    if (event.user) {\n      delete event.user.ip_address;\n    }\n\n    return event;\n  },\n});\n```\n\n### Before Send Transaction Hook\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  tracesSampleRate: 1.0,\n\n  beforeSendTransaction(event, hint) {\n    // Don't send health check transactions\n    if (event.transaction === \"GET /health\") {\n      return null;\n    }\n\n    // Add custom data to all spans\n    if (event.spans) {\n      event.spans.forEach((span) => {\n        span.data = span.data || {};\n        span.data.custom_field = \"custom_value\";\n      });\n    }\n\n    return event;\n  },\n});\n```\n\n## Sampling\n\n### Error Sampling\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  // Sample 50% of errors\n  sampleRate: 0.5,\n});\n```\n\n### Performance Sampling\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  // Sample 25% of transactions\n  tracesSampleRate: 0.25,\n\n  // Or use dynamic sampling\n  tracesSampler(samplingContext) {\n    // Sample critical paths at 100%\n    if (samplingContext.transactionContext.name.includes(\"/checkout\")) {\n      return 1.0;\n    }\n\n    // Sample health checks at 10%\n    if (samplingContext.transactionContext.name.includes(\"/health\")) {\n      return 0.1;\n    }\n\n    // Default to 25%\n    return 0.25;\n  },\n});\n```\n\n### Profile Sampling\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n  integrations: [nodeProfilingIntegration()],\n\n  // Profile 10% of transactions\n  profilesSampleRate: 0.1,\n});\n```\n\n## Releases and Deploys\n\n### Set Release\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  release: \"my-project@1.2.3\",\n  environment: \"production\",\n});\n```\n\n### Create Release with CLI\n\n```bash\n# Create release\nsentry-cli releases new my-project@1.2.3\n\n# Associate commits\nsentry-cli releases set-commits my-project@1.2.3 --auto\n\n# Finalize release\nsentry-cli releases finalize my-project@1.2.3\n\n# Create deploy\nsentry-cli releases deploys my-project@1.2.3 new -e production\n```\n\n## Testing Sentry Setup\n\n### Test Error\n\n```javascript\nsetTimeout(() => {\n  throw new Error(\"Sentry Test Error - This is intentional!\");\n}, 1000);\n```\n\n### Test Message\n\n```javascript\nSentry.captureMessage(\"Sentry is configured correctly!\", \"info\");\n```\n\n### Test Transaction\n\n```javascript\nSentry.startSpan(\n  {\n    name: \"Test Transaction\",\n    op: \"test\",\n  },\n  () => {\n    console.log(\"Testing Sentry performance monitoring\");\n  }\n);\n```\n\n## Browser Integrations\n\n### Breadcrumbs Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.breadcrumbsIntegration({\n      console: true,  // Console logs\n      dom: true,      // DOM events\n      fetch: true,    // Fetch requests\n      history: true,  // Navigation\n      xhr: true,      // XHR requests\n    }),\n  ],\n});\n```\n\n### HTTP Client Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.httpClientIntegration({\n      failedRequestStatusCodes: [[400, 599]],\n      failedRequestTargets: [\"https://api.example.com\"],\n    }),\n  ],\n});\n```\n\n### Context Lines Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.contextLinesIntegration({\n      frameContextLines: 5,\n    }),\n  ],\n});\n```\n\n## Advanced Configuration\n\n### Multiple Sentry Instances\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\n// Create hub for primary app\nconst primaryHub = new Sentry.Hub(new Sentry.Client({\n  dsn: \"https://primary@sentry.io/0\",\n}));\n\n// Create hub for background jobs\nconst jobsHub = new Sentry.Hub(new Sentry.Client({\n  dsn: \"https://jobs@sentry.io/1\",\n}));\n\n// Use specific hub\nprimaryHub.withScope((scope) => {\n  primaryHub.captureException(new Error(\"Primary app error\"));\n});\n\njobsHub.withScope((scope) => {\n  jobsHub.captureException(new Error(\"Background job error\"));\n});\n```\n\n### Custom Transport\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  transport: Sentry.makeNodeTransport,\n  transportOptions: {\n    headers: {\n      \"X-Custom-Header\": \"custom-value\",\n    },\n  },\n});\n```\n\n### Debug Mode\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  debug: true, // Enable debug logging\n});\n```\n\n### Maximum Breadcrumbs\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  maxBreadcrumbs: 50, // Default is 100\n});\n```\n\n### Shutdown\n\n```javascript\n// Flush events and close transport\nawait Sentry.close(2000); // Wait up to 2 seconds\n\n// Or just flush without closing\nawait Sentry.flush(2000);\n```\n\n## Node.js Integrations\n\n### HTTP Integration\n\n```javascript\nconst Sentry = require(\"@sentry/node\");\n\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.httpIntegration({\n      tracing: true,\n      breadcrumbs: true,\n    }),\n  ],\n});\n```\n\n### Console Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.consoleIntegration({\n      levels: [\"error\", \"warn\"],\n    }),\n  ],\n});\n```\n\n### Modules Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.modulesIntegration(),\n  ],\n});\n```\n\n### Context Integration\n\n```javascript\nSentry.init({\n  dsn: \"https://examplePublicKey@o0.ingest.sentry.io/0\",\n  integrations: [\n    Sentry.contextIntegration(),\n  ],\n});\n```\n"
  },
  {
    "path": "content/sentry/docs/error-tracking/python/DOC.md",
    "content": "---\nname: error-tracking\ndescription: \"Sentry Python SDK for error tracking, performance monitoring, and distributed tracing in Python applications.\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.43.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"sentry,monitoring,error-tracking,performance,tracing\"\n---\n\n# Sentry Python SDK (2.43.0)\n\n## Golden Rule\n\n**ALWAYS use `sentry-sdk` for Python applications.**\n\nThe current stable version is **2.43.0**. Do not use deprecated packages like `raven`.\n\n## Installation\n\n```bash\npip install sentry-sdk\n```\n\n### With Framework Support\n\n```bash\n# Django\npip install sentry-sdk[django]\n\n# Flask\npip install sentry-sdk[flask]\n\n# FastAPI\npip install sentry-sdk[fastapi]\n\n# Celery\npip install sentry-sdk[celery]\n\n# SQLAlchemy\npip install sentry-sdk[sqlalchemy]\n```\n\n### Environment Variables Setup\n\nCreate a `.env` file:\n\n```env\nSENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0\nSENTRY_ENVIRONMENT=production\nSENTRY_RELEASE=my-project@1.0.0\n```\n\nLoad environment variables:\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nSENTRY_DSN = os.getenv(\"SENTRY_DSN\")\nSENTRY_ENVIRONMENT = os.getenv(\"SENTRY_ENVIRONMENT\", \"development\")\nSENTRY_RELEASE = os.getenv(\"SENTRY_RELEASE\")\n```\n\n## Initialization\n\n### Basic Initialization\n\nConfiguration should happen as **early as possible** in your application's lifecycle.\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Environment and release tracking\n    environment=\"production\",\n    release=\"my-project@1.0.0\",\n\n    # Performance Monitoring\n    traces_sample_rate=1.0,  # Capture 100% of transactions\n\n    # Profiling\n    profiles_sample_rate=1.0,  # Profile 100% of transactions\n\n    # Send user IP and cookies\n    send_default_pii=True,\n\n    # Enable logging to Sentry\n    enable_logs=True,\n)\n```\n\n### Django Initialization\n\nIn `settings.py`:\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Performance Monitoring\n    traces_sample_rate=1.0,\n\n    # Profiling\n    profiles_sample_rate=1.0,\n\n    # Send user PII\n    send_default_pii=True,\n)\n```\n\n### Flask Initialization\n\n```python\nfrom flask import Flask\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    profiles_sample_rate=1.0,\n    send_default_pii=True,\n)\n\napp = Flask(__name__)\n```\n\n### FastAPI Initialization\n\n```python\nfrom fastapi import FastAPI\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    profiles_sample_rate=1.0,\n    send_default_pii=True,\n)\n\napp = FastAPI()\n```\n\n### Async Application Initialization\n\nFor async applications, initialize within an async function:\n\n```python\nimport asyncio\nimport sentry_sdk\n\nasync def main():\n    sentry_sdk.init(\n        dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n        traces_sample_rate=1.0,\n    )\n\n    # Your async code here\n    await run_application()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## Error Tracking\n\n### Capture Exceptions\n\n**Automatic Error Capture:**\n\nSentry automatically captures unhandled exceptions.\n\n```python\n# This error will be automatically captured\nraise Exception(\"Something went wrong!\")\n```\n\n**Manual Error Capture:**\n\n```python\nimport sentry_sdk\n\ntry:\n    some_failing_function()\nexcept Exception as e:\n    sentry_sdk.capture_exception(e)\n```\n\n**Capture with Context:**\n\n```python\ntry:\n    process_payment(user_id)\nexcept Exception as e:\n    with sentry_sdk.push_scope() as scope:\n        scope.set_tag(\"payment_method\", \"credit_card\")\n        scope.set_user({\"id\": user_id})\n        scope.set_level(\"error\")\n        sentry_sdk.capture_exception(e)\n```\n\n### Capture Messages\n\n```python\nimport sentry_sdk\n\n# Simple message\nsentry_sdk.capture_message(\"User completed checkout\")\n\n# Message with severity level\nsentry_sdk.capture_message(\"Payment processing slow\", \"warning\")\n\n# Available levels: \"fatal\", \"error\", \"warning\", \"log\", \"info\", \"debug\"\nsentry_sdk.capture_message(\"Critical system failure\", \"fatal\")\n```\n\n### Message with Context\n\n```python\nwith sentry_sdk.push_scope() as scope:\n    scope.set_tag(\"section\", \"checkout\")\n    scope.set_extra(\"cart_total\", 129.99)\n    sentry_sdk.capture_message(\"Checkout completed\", \"info\")\n```\n\n### Capture from Try-Except\n\n```python\nimport sentry_sdk\n\ndef process_data(data):\n    try:\n        result = risky_operation(data)\n        return result\n    except ValueError as e:\n        sentry_sdk.capture_exception(e)\n        return None\n    except Exception as e:\n        sentry_sdk.capture_exception(e)\n        raise\n```\n\n## Enriching Error Data\n\n### Set User Information\n\n```python\nsentry_sdk.set_user({\n    \"id\": \"12345\",\n    \"email\": \"user@example.com\",\n    \"username\": \"john_doe\",\n    \"ip_address\": \"{{auto}}\",  # Automatically capture IP\n})\n\n# Clear user data\nsentry_sdk.set_user(None)\n```\n\n### Set Tags\n\nTags are searchable key-value pairs:\n\n```python\nimport sentry_sdk\n\n# Set single tag\nsentry_sdk.set_tag(\"page_locale\", \"en-us\")\nsentry_sdk.set_tag(\"environment\", \"staging\")\n\n# Set multiple tags using scope\nwith sentry_sdk.push_scope() as scope:\n    scope.set_tag(\"user_type\", \"premium\")\n    scope.set_tag(\"platform\", \"web\")\n    sentry_sdk.capture_message(\"User action\")\n```\n\n### Set Context\n\nContext adds structured data to events:\n\n```python\nimport sentry_sdk\n\nsentry_sdk.set_context(\"character\", {\n    \"name\": \"Mighty Fighter\",\n    \"age\": 19,\n    \"attack_type\": \"melee\",\n    \"level\": 42\n})\n\nsentry_sdk.set_context(\"order\", {\n    \"id\": \"ORD-12345\",\n    \"total\": 249.99,\n    \"items\": 5,\n    \"shipping_method\": \"express\"\n})\n```\n\n### Set Extra Data\n\n```python\nsentry_sdk.set_extra(\"debug_data\", {\n    \"last_query\": \"SELECT * FROM users\",\n    \"response_time\": 1234,\n})\n\n# Or using scope\nwith sentry_sdk.push_scope() as scope:\n    scope.set_extra(\"additional_info\", {\"key\": \"value\"})\n    sentry_sdk.capture_exception(Exception(\"Error with extra data\"))\n```\n\n### Add Breadcrumbs\n\nBreadcrumbs create a trail of events leading to an error:\n\n```python\nimport sentry_sdk\n\n# Manual breadcrumb\nsentry_sdk.add_breadcrumb(\n    category='auth',\n    message='User logged in',\n    level='info',\n)\n\nsentry_sdk.add_breadcrumb(\n    category='api',\n    message='API request to /users',\n    level='info',\n    data={\n        'url': '/api/users',\n        'method': 'GET',\n        'status_code': 200,\n    }\n)\n\nsentry_sdk.add_breadcrumb(\n    category='navigation',\n    message='User navigated to checkout',\n    level='info',\n    data={\n        'from': '/cart',\n        'to': '/checkout',\n    }\n)\n```\n\n**Automatic Breadcrumbs:**\n\nThe SDK automatically captures:\n- HTTP requests\n- Database queries\n- Logging calls\n- Framework-specific events\n\n**Filter Breadcrumbs:**\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.types import Breadcrumb, BreadcrumbHint\n\ndef before_breadcrumb(crumb: Breadcrumb, hint: BreadcrumbHint):\n    # Filter out spammy breadcrumbs\n    if crumb.get('category') == 'a.spammy.Logger':\n        return None\n\n    # Modify breadcrumb\n    if crumb.get('category') == 'console':\n        crumb['level'] = 'debug'\n\n    return crumb\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    before_breadcrumb=before_breadcrumb,\n)\n```\n\n## Scopes\n\nScopes contain data that is attached to events.\n\n### Push Scope\n\n```python\nimport sentry_sdk\n\n# Create temporary scope for specific error\nwith sentry_sdk.push_scope() as scope:\n    scope.set_tag(\"section\", \"payment\")\n    scope.set_level(\"warning\")\n    scope.set_user({\"id\": \"12345\"})\n    sentry_sdk.capture_exception(Exception(\"Payment failed\"))\n\n# This error won't have the above tags\nsentry_sdk.capture_exception(Exception(\"Another error\"))\n```\n\n### Configure Scope\n\n```python\nimport sentry_sdk\n\ndef process_request(request):\n    with sentry_sdk.configure_scope() as scope:\n        scope.set_tag(\"request_id\", request.id)\n        scope.set_user({\n            \"id\": request.user.id,\n            \"email\": request.user.email,\n        })\n        scope.set_extra(\"request_data\", request.data)\n```\n\n### Global Scope\n\n```python\nimport sentry_sdk\n\n# Set data on global scope (affects all events)\nwith sentry_sdk.configure_scope() as scope:\n    scope.set_tag(\"app_version\", \"1.0.0\")\n    scope.set_context(\"app_info\", {\n        \"name\": \"My App\",\n        \"version\": \"1.0.0\"\n    })\n```\n\n### Isolation Scope\n\n```python\nimport sentry_sdk\n\n# Get isolation scope\nscope = sentry_sdk.get_isolation_scope()\nscope.set_tag(\"isolation_tag\", \"value\")\n```\n\n### Current Scope\n\n```python\nimport sentry_sdk\n\n# Get current scope\nscope = sentry_sdk.get_current_scope()\nscope.set_tag(\"current_tag\", \"value\")\n```\n\n## Performance Monitoring\n\n### Basic Transaction\n\n```python\nimport sentry_sdk\n\ndef eat_pizza(pizza):\n    with sentry_sdk.start_transaction(op=\"task\", name=\"Eat Pizza\"):\n        while pizza.slices > 0:\n            eat_slice(pizza.slices.pop())\n```\n\n### Transaction with Spans\n\n```python\nimport sentry_sdk\n\ndef eat_pizza(pizza):\n    with sentry_sdk.start_transaction(op=\"task\", name=\"Eat Pizza\"):\n        while pizza.slices > 0:\n            with sentry_sdk.start_span(name=\"Eat Slice\"):\n                eat_slice(pizza.slices.pop())\n```\n\n### Nested Spans\n\n```python\nimport sentry_sdk\n\ndef chew():\n    # Chewing logic\n    pass\n\ndef eat_slice(slice):\n    with sentry_sdk.start_span(name=\"Eat Slice\"):\n        with sentry_sdk.start_span(name=\"Chew\"):\n            chew()\n```\n\n### Using Decorators\n\n```python\nimport sentry_sdk\n\n@sentry_sdk.trace\ndef eat_slice(slice):\n    # This function is automatically traced\n    pass\n\ndef eat_pizza(pizza):\n    with sentry_sdk.start_transaction(op=\"task\", name=\"Eat Pizza\"):\n        while pizza.slices > 0:\n            eat_slice(pizza.slices.pop())\n```\n\n### Nested Decorators\n\n```python\nimport sentry_sdk\n\n@sentry_sdk.trace\ndef chew():\n    # Chewing logic\n    pass\n\n@sentry_sdk.trace\ndef eat_slice(slice):\n    chew()\n\n@sentry_sdk.trace\ndef eat_pizza(pizza):\n    while pizza.slices > 0:\n        eat_slice(pizza.slices.pop())\n\n# Start transaction\nwith sentry_sdk.start_transaction(op=\"task\", name=\"Lunch\"):\n    eat_pizza(pizza)\n```\n\n### Manual Span Management\n\n```python\nimport sentry_sdk\n\ndef eat_slice(slice):\n    pass\n\ndef eat_pizza(pizza):\n    with sentry_sdk.start_transaction(op=\"task\", name=\"Eat Pizza\"):\n        while pizza.slices > 0:\n            span = sentry_sdk.start_span(name=\"Eat Slice\")\n            eat_slice(pizza.slices.pop())\n            span.finish()\n```\n\n### Manual Nested Spans\n\n```python\nimport sentry_sdk\n\ndef chew():\n    pass\n\ndef eat_slice(slice):\n    parent_span = sentry_sdk.start_span(name=\"Eat Slice\")\n\n    child_span = parent_span.start_child(name=\"Chew\")\n    chew()\n    child_span.finish()\n\n    parent_span.finish()\n```\n\n### Decorator with Custom Parameters\n\n```python\nimport sentry_sdk\n\n@sentry_sdk.trace(op=\"my_op\", name=\"ProcessItem\", attributes={\"x\": True})\ndef my_function(i):\n    # Function logic\n    pass\n\n@sentry_sdk.trace\ndef root_function():\n    for i in range(3):\n        my_function(i)\n\n# Start transaction\nwith sentry_sdk.start_transaction(op=\"task\", name=\"Root\"):\n    root_function()\n```\n\n### Decorator with Template\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.consts import SPANTEMPLATE\n\n@sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT)\ndef my_ai_function(i):\n    # AI logic\n    pass\n\n@sentry_sdk.trace\ndef root_function():\n    for i in range(3):\n        my_ai_function(i)\n\n# Start transaction\nwith sentry_sdk.start_transaction(op=\"task\", name=\"AI Processing\"):\n    root_function()\n```\n\n### Centralized Function Tracing\n\n```python\nimport sentry_sdk\n\nfunctions_to_trace = [\n    {\"qualified_name\": \"mymodule.eat_slice\"},\n    {\"qualified_name\": \"mymodule.swallow\"},\n    {\"qualified_name\": \"mymodule.chew\"},\n    {\"qualified_name\": \"mymodule.submodule.another.some_function\"},\n    {\"qualified_name\": \"mymodule.SomePizzaClass.some_method\"},\n]\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    functions_to_trace=functions_to_trace,\n)\n```\n\n### Access Current Transaction\n\n```python\nimport sentry_sdk\n\ndef eat_pizza(pizza):\n    transaction = sentry_sdk.get_current_scope().transaction\n\n    if transaction is not None:\n        transaction.set_tag(\"num_of_slices\", len(pizza.slices))\n        transaction.set_data(\"pizza_type\", pizza.type)\n\n    while pizza.slices > 0:\n        eat_slice(pizza.slices.pop())\n```\n\n### Access Current Span\n\n```python\nimport sentry_sdk\n\n@sentry_sdk.trace\ndef eat_slice(slice):\n    span = sentry_sdk.get_current_span()\n\n    if span is not None:\n        span.set_tag(\"slice_id\", slice.id)\n        span.set_data(\"slice_size\", slice.size)\n```\n\n### Add Data to Transactions\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.start_transaction(name=\"my-transaction\") as transaction:\n    transaction.set_data(\"my-data-attribute-1\", \"value1\")\n    transaction.set_data(\"my-data-attribute-2\", 42)\n    transaction.set_data(\"my-data-attribute-3\", True)\n\n    transaction.set_data(\"my-data-attribute-4\", [\"value1\", \"value2\", \"value3\"])\n    transaction.set_data(\"my-data-attribute-5\", [42, 43, 44])\n    transaction.set_data(\"my-data-attribute-6\", [True, False, True])\n```\n\n### Add Data to Spans\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.start_span(name=\"my-span\") as span:\n    span.set_data(\"my-data-attribute-1\", \"value1\")\n    span.set_data(\"my-data-attribute-2\", 42)\n    span.set_data(\"my-data-attribute-3\", True)\n\n    span.set_data(\"my-data-attribute-4\", [\"value1\", \"value2\", \"value3\"])\n    span.set_data(\"my-data-attribute-5\", [42, 43, 44])\n    span.set_data(\"my-data-attribute-6\", [True, False, True])\n```\n\n### Update Current Span\n\n```python\nimport sentry_sdk\n\n@sentry_sdk.trace(op=\"my_op\", name=\"Paul\", attributes={\"x\": True})\ndef my_function(i):\n    sentry_sdk.update_current_span(\n        op=\"myOp\",\n        name=f\"Paul{i}\",\n        attributes={\"y\": i},\n    )\n\n@sentry_sdk.trace\ndef root_function():\n    for i in range(3):\n        my_function(i)\n\n# Start transaction\nwith sentry_sdk.start_transaction(op=\"task\", name=\"Root\"):\n    root_function()\n```\n\n### Async Transactions\n\n```python\nimport asyncio\nimport sentry_sdk\n\nasync def fetch_data():\n    # Async data fetching\n    await asyncio.sleep(1)\n    return {\"data\": \"value\"}\n\nasync def process_request():\n    with sentry_sdk.start_transaction(op=\"http.server\", name=\"Process Request\"):\n        with sentry_sdk.start_span(name=\"Fetch Data\"):\n            data = await fetch_data()\n\n        with sentry_sdk.start_span(name=\"Process Data\"):\n            result = process_data(data)\n\n        return result\n\n# Run async function\nasyncio.run(process_request())\n```\n\n## Event Filtering\n\n### Before Send Hook\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.types import Event, Hint\n\ndef before_send(event: Event, hint: Hint):\n    # Don't send events in development\n    if event.get(\"environment\") == \"development\":\n        return None\n\n    # Filter out specific errors\n    if \"exc_info\" in hint:\n        exc_type, exc_value, tb = hint[\"exc_info\"]\n        if isinstance(exc_value, ConnectionError):\n            return None\n\n    # Modify event\n    if event.get(\"user\"):\n        event[\"user\"].pop(\"ip_address\", None)\n\n    return event\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    before_send=before_send,\n)\n```\n\n### Before Send Transaction Hook\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.types import Event, Hint\n\ndef before_send_transaction(event: Event, hint: Hint):\n    # Don't send health check transactions\n    if event.get(\"transaction\") == \"GET /health\":\n        return None\n\n    # Add custom data to all spans\n    for span in event.get(\"spans\", []):\n        span[\"data\"] = span.get(\"data\", {})\n        span[\"data\"][\"foo\"] = \"bar\"\n\n    # Add data to root transaction\n    if \"contexts\" in event and \"trace\" in event[\"contexts\"]:\n        event[\"contexts\"][\"trace\"][\"data\"] = event[\"contexts\"][\"trace\"].get(\"data\", {})\n        event[\"contexts\"][\"trace\"][\"data\"][\"foo\"] = \"bar\"\n\n    return event\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    before_send_transaction=before_send_transaction,\n)\n```\n\n### Event Processors\n\n```python\nimport sentry_sdk\n\ndef strip_sensitive_data(event, hint):\n    # Remove sensitive data from event\n    if \"request\" in event:\n        if \"headers\" in event[\"request\"]:\n            event[\"request\"][\"headers\"].pop(\"Authorization\", None)\n            event[\"request\"][\"headers\"].pop(\"Cookie\", None)\n\n    return event\n\n# Add globally\nsentry_sdk.add_event_processor(strip_sensitive_data)\n\n# Or add to specific scope\nwith sentry_sdk.push_scope() as scope:\n    scope.add_event_processor(strip_sensitive_data)\n    sentry_sdk.capture_exception(Exception(\"Error\"))\n```\n\n## Sampling\n\n### Error Sampling\n\n```python\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Sample 50% of errors\n    sample_rate=0.5,\n)\n```\n\n### Performance Sampling\n\n```python\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Sample 25% of transactions\n    traces_sample_rate=0.25,\n)\n```\n\n### Dynamic Performance Sampling\n\n```python\ndef traces_sampler(sampling_context):\n    # Sample critical paths at 100%\n    if \"/checkout\" in sampling_context.get(\"wsgi_environ\", {}).get(\"PATH_INFO\", \"\"):\n        return 1.0\n\n    # Sample health checks at 10%\n    if \"/health\" in sampling_context.get(\"wsgi_environ\", {}).get(\"PATH_INFO\", \"\"):\n        return 0.1\n\n    # Default to 25%\n    return 0.25\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sampler=traces_sampler,\n)\n```\n\n### Profile Sampling\n\n```python\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Profile 10% of transactions\n    profiles_sample_rate=0.1,\n)\n```\n\n## Releases and Deploys\n\n### Set Release\n\n```python\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    release=\"my-project@1.2.3\",\n    environment=\"production\",\n)\n```\n\n### Automatic Release Detection\n\n```python\nimport sentry_sdk\n\n# Sentry can auto-detect from environment variables:\n# SENTRY_RELEASE\n# HEROKU_SLUG_COMMIT\n# SOURCE_VERSION\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n)\n```\n\n## Testing Sentry Setup\n\n### Test Error\n\n```python\nimport sentry_sdk\n\n# Must be run from a file, not Python shell\ndef test_sentry():\n    sentry_sdk.init(\n        dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    )\n\n    raise Exception(\"Sentry Test Error - This is intentional!\")\n\nif __name__ == \"__main__\":\n    test_sentry()\n```\n\n### Test Message\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n)\n\nsentry_sdk.capture_message(\"Sentry is configured correctly!\", \"info\")\n```\n\n### Test Transaction\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n)\n\nwith sentry_sdk.start_transaction(op=\"test\", name=\"Test Transaction\"):\n    print(\"Testing Sentry performance monitoring\")\n```\n\n## Django Integration\n\n### Settings Configuration\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Performance Monitoring\n    traces_sample_rate=1.0,\n\n    # Send user PII\n    send_default_pii=True,\n\n    # Environment\n    environment=\"production\",\n)\n```\n\n### Capture User Info\n\nDjango integration automatically captures user information from `request.user`.\n\n```python\n# User info is automatically captured in Django views\nfrom django.http import JsonResponse\n\ndef my_view(request):\n    # User from request.user is automatically sent to Sentry\n    if request.user.is_authenticated:\n        # Sentry will capture user.id, user.email, user.username\n        pass\n\n    return JsonResponse({\"status\": \"ok\"})\n```\n\n### Custom Transaction Names\n\n```python\nfrom django.http import JsonResponse\nimport sentry_sdk\n\ndef my_view(request):\n    with sentry_sdk.start_transaction(op=\"http.server\", name=\"Custom View Name\"):\n        # View logic\n        return JsonResponse({\"status\": \"ok\"})\n```\n\n## Flask Integration\n\n### Basic Setup\n\n```python\nfrom flask import Flask\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    send_default_pii=True,\n)\n\napp = Flask(__name__)\n\n@app.route(\"/\")\ndef index():\n    return \"Hello World!\"\n\n@app.route(\"/error\")\ndef error():\n    raise Exception(\"Test error\")\n\nif __name__ == \"__main__\":\n    app.run()\n```\n\n### Capture User Info\n\n```python\nfrom flask import Flask, request\nimport sentry_sdk\n\napp = Flask(__name__)\n\n@app.before_request\ndef set_user_info():\n    user = get_current_user()  # Your user retrieval logic\n    if user:\n        sentry_sdk.set_user({\n            \"id\": user.id,\n            \"email\": user.email,\n            \"username\": user.username,\n        })\n```\n\n## FastAPI Integration\n\n### Basic Setup\n\n```python\nfrom fastapi import FastAPI, Request\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n    send_default_pii=True,\n)\n\napp = FastAPI()\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n\n@app.get(\"/error\")\nasync def error():\n    raise Exception(\"Test error\")\n```\n\n### Capture User Info\n\n```python\nfrom fastapi import FastAPI, Request, Depends\nimport sentry_sdk\n\napp = FastAPI()\n\ndef get_current_user(request: Request):\n    # Your user retrieval logic\n    return {\"id\": \"12345\", \"email\": \"user@example.com\"}\n\n@app.middleware(\"http\")\nasync def add_user_to_sentry(request: Request, call_next):\n    user = get_current_user(request)\n    sentry_sdk.set_user(user)\n    response = await call_next(request)\n    return response\n```\n\n## Celery Integration\n\n### Basic Setup\n\n```python\nfrom celery import Celery\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sample_rate=1.0,\n)\n\napp = Celery(\"tasks\", broker=\"redis://localhost:6379\")\n\n@app.task\ndef process_data(data):\n    # Task logic\n    return result\n```\n\n### Task Error Handling\n\n```python\nfrom celery import Celery\nimport sentry_sdk\n\napp = Celery(\"tasks\", broker=\"redis://localhost:6379\")\n\n@app.task(bind=True)\ndef process_data(self, data):\n    try:\n        # Task logic\n        result = risky_operation(data)\n        return result\n    except Exception as e:\n        sentry_sdk.capture_exception(e)\n        raise self.retry(exc=e, countdown=60)\n```\n\n## Logging Integration\n\n### Basic Logging Setup\n\n```python\nimport logging\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    enable_logs=True,\n)\n\n# Configure logging\nlogging.basicConfig(level=logging.INFO)\n\n# Logs will automatically be sent to Sentry\nlogging.error(\"This is an error log\")\nlogging.warning(\"This is a warning log\")\nlogging.info(\"This is an info log\")\n```\n\n### Custom Log Handler\n\n```python\nimport logging\nimport sentry_sdk\nfrom sentry_sdk.integrations.logging import LoggingIntegration\n\n# Configure Sentry with logging\nsentry_logging = LoggingIntegration(\n    level=logging.INFO,       # Capture info and above as breadcrumbs\n    event_level=logging.ERROR # Send errors as events\n)\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    integrations=[sentry_logging],\n)\n\nlogger = logging.getLogger(__name__)\nlogger.error(\"This will be sent to Sentry as an event\")\nlogger.info(\"This will be captured as a breadcrumb\")\n```\n\n## Advanced Configuration\n\n### Custom Client Options\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n\n    # Maximum breadcrumbs\n    max_breadcrumbs=50,  # Default is 100\n\n    # Attach stack traces to messages\n    attach_stacktrace=True,\n\n    # Server name\n    server_name=\"server-001\",\n\n    # Debug mode\n    debug=True,\n\n    # Transport options\n    transport=sentry_sdk.transports.HttpTransport,\n\n    # Shutdown timeout\n    shutdown_timeout=2,\n)\n```\n\n### Multiple Sentry Instances\n\n```python\nimport sentry_sdk\n\n# Create client for primary app\nprimary_client = sentry_sdk.Client(\n    dsn=\"https://primary@sentry.io/0\",\n)\n\n# Create client for background jobs\njobs_client = sentry_sdk.Client(\n    dsn=\"https://jobs@sentry.io/1\",\n)\n\n# Use specific client\nwith sentry_sdk.Hub(primary_client):\n    sentry_sdk.capture_exception(Exception(\"Primary app error\"))\n\nwith sentry_sdk.Hub(jobs_client):\n    sentry_sdk.capture_exception(Exception(\"Background job error\"))\n```\n\n### Custom Integrations\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.integrations.logging import LoggingIntegration\nfrom sentry_sdk.integrations.redis import RedisIntegration\nfrom sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    integrations=[\n        LoggingIntegration(\n            level=logging.INFO,\n            event_level=logging.ERROR\n        ),\n        RedisIntegration(),\n        SqlalchemyIntegration(),\n    ],\n)\n```\n\n### Disable Default Integrations\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    default_integrations=False,  # Disable all default integrations\n)\n```\n\n### Flush and Shutdown\n\n```python\nimport sentry_sdk\n\n# Flush events (wait up to 2 seconds)\nsentry_sdk.flush(timeout=2)\n\n# Close and flush (wait up to 2 seconds)\nsentry_sdk.close(timeout=2)\n```\n\n## Context Managers\n\n### Hub Context\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.Hub(sentry_sdk.Hub.current):\n    # Operations in isolated hub\n    sentry_sdk.capture_message(\"Isolated message\")\n```\n\n### Configure Scope Context\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.configure_scope() as scope:\n    scope.set_tag(\"section\", \"api\")\n    scope.set_user({\"id\": \"12345\"})\n    # All events in this block will have these tags\n```\n\n### Push Scope Context\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.push_scope() as scope:\n    scope.set_tag(\"temporary\", \"yes\")\n    sentry_sdk.capture_exception(Exception(\"Scoped error\"))\n\n# Tag is not present in subsequent errors\nsentry_sdk.capture_exception(Exception(\"Unscoped error\"))\n```\n"
  },
  {
    "path": "content/sentry-sdk/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Official Sentry Python SDK for error monitoring, tracing, profiling, structured logs, and framework integrations\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.54.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sentry,observability,error-monitoring,tracing,profiling,logging\"\n---\n\n# sentry-sdk Python Package Guide\n\n## Golden Rule\n\nInitialize `sentry-sdk` as early as possible in process startup, set a real DSN, and turn on tracing, profiling, and logs deliberately instead of copying `1.0` sample rates from quickstarts into production. Sentry auto-enables many integrations when their libraries are installed, so be explicit if you need to disable or override defaults.\n\n## Install\n\nPin the stable 2.x release your project expects:\n\n```bash\npython -m pip install \"sentry-sdk==2.54.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sentry-sdk==2.54.0\"\npoetry add \"sentry-sdk==2.54.0\"\n```\n\nInstall an extra when you want Sentry's optional integration dependencies packaged with the SDK:\n\n```bash\npython -m pip install \"sentry-sdk[django]==2.54.0\"\npython -m pip install \"sentry-sdk[fastapi]==2.54.0\"\npython -m pip install \"sentry-sdk[flask]==2.54.0\"\npython -m pip install \"sentry-sdk[sqlalchemy]==2.54.0\"\npython -m pip install \"sentry-sdk[openai]==2.54.0\"\n```\n\nThe PyPI release exposes many extras, including `django`, `fastapi`, `flask`, `sqlalchemy`, `httpx`, `aiohttp`, `celery`, `openai`, `anthropic`, `langchain`, `langgraph`, `mcp`, and `loguru`.\n\n## Initialize And Configure\n\nSentry reads `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, and `SENTRY_RELEASE` automatically, but explicit arguments still win. A practical setup looks like this:\n\n```python\nimport os\nimport sentry_sdk\n\nsentry_sdk.init(\n    dsn=os.environ[\"SENTRY_DSN\"],\n    release=os.getenv(\"SENTRY_RELEASE\"),\n    environment=os.getenv(\"SENTRY_ENVIRONMENT\", \"development\"),\n    send_default_pii=False,\n    traces_sample_rate=0.1,\n    profiles_sample_rate=0.1,\n    enable_logs=False,\n)\n```\n\nImportant options to know:\n\n- `dsn`: without it, the SDK initializes but does not send data.\n- `release`: set this explicitly so regressions line up with deploys.\n- `environment`: defaults to `production`; set it yourself if you use `development`, `staging`, and `production`.\n- `send_default_pii`: off by default; only enable it if you actually want integrations to send user/request PII.\n- `ignore_errors`: fastest way to suppress known exception classes.\n- `before_send`, `before_send_transaction`, `before_send_log`: last-chance hooks to redact or drop outgoing events, transactions, or logs.\n- `shutdown_timeout`: important for CLI jobs and other short-lived processes because events are drained from a background queue.\n\nIf you need async auto-instrumentation, initialize inside the first async entrypoint instead of at module import time:\n\n```python\nimport asyncio\nimport sentry_sdk\n\nasync def main() -> None:\n    sentry_sdk.init(\n        dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n        traces_sample_rate=0.1,\n    )\n\nasyncio.run(main())\n```\n\n## Core Usage\n\n### Capture exceptions and messages\n\n```python\nimport sentry_sdk\n\nsentry_sdk.init(dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\")\n\ntry:\n    1 / 0\nexcept ZeroDivisionError as exc:\n    sentry_sdk.capture_exception(exc)\n\nsentry_sdk.capture_message(\"cache warmed\")\n```\n\n### Add custom spans around important work\n\n```python\nimport sentry_sdk\n\nwith sentry_sdk.start_span(op=\"task\", name=\"sync customer record\"):\n    sync_customer()\n```\n\nUse custom spans for expensive internal work that auto-instrumentation will not see clearly.\n\n### Send structured logs to Sentry\n\nStructured logs require `enable_logs=True`:\n\n```python\nimport sentry_sdk\nfrom sentry_sdk import logger as sentry_logger\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    enable_logs=True,\n)\n\nsentry_logger.info(\n    \"Processed order {order_id}\",\n    order_id=\"ord_123\",\n)\n\nsentry_logger.error(\"Payment failed\")\n```\n\n### Filter noisy events before they leave the process\n\n```python\nimport sentry_sdk\n\ndef before_send(event, hint):\n    if hint.get(\"exc_info\", [None])[0] == ZeroDivisionError:\n        return None\n    event.setdefault(\"extra\", {})[\"service\"] = \"billing\"\n    return event\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    before_send=before_send,\n)\n```\n\nFor transaction filtering, use `traces_sampler` or `before_send_transaction`. For log filtering, use `before_send_log`.\n\n## Sampling, Tracing, And Profiling\n\nError event sampling:\n\n- `sample_rate` applies one uniform rate to errors.\n- `error_sampler` lets you decide per event and overrides `sample_rate`.\n\nTracing:\n\n- Set `traces_sample_rate` for a uniform transaction sample rate.\n- Use `traces_sampler` when you need route-aware or tenant-aware sampling.\n- `traces_sampler` and `traces_sample_rate` are mutually exclusive.\n- `trace_propagation_targets` controls which outgoing HTTP requests receive `sentry-trace` and `baggage` headers.\n- `traces_sample_rate=0` still allows continuation of inbound distributed traces; use `None` if you want tracing fully off.\n\nProfiling:\n\n- Profiling depends on tracing being enabled.\n- Current Python docs expose both `profiles_sample_rate` / `profiles_sampler` in options and `profile_session_sample_rate` with `profile_lifecycle=\"trace\"` in the quick start.\n- Stay consistent with one style inside a codebase and prefer the current official docs over blog posts when choosing profiling knobs.\n\nExample with dynamic tracing and trace-linked profiling:\n\n```python\nimport sentry_sdk\nfrom sentry_sdk.types import SamplingContext\n\ndef traces_sampler(ctx: SamplingContext) -> float:\n    parent = ctx.get(\"parent_sampled\")\n    if parent is not None:\n        return float(parent)\n\n    transaction_context = ctx.get(\"transaction_context\") or {}\n    name = transaction_context.get(\"name\", \"\")\n    if name.endswith(\"/healthcheck\"):\n        return 0.0\n    return 0.1\n\nsentry_sdk.init(\n    dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\",\n    traces_sampler=traces_sampler,\n    profiles_sample_rate=0.5,\n)\n```\n\n## Integrations\n\nSentry has broad Python integration coverage and many integrations are auto-enabled when the matching library is installed. The official integrations index marks common frameworks like Django, Flask, FastAPI, AIOHTTP, Quart, Sanic, Starlette, SQLAlchemy, Redis, MongoDB, and asyncpg as auto-enabled.\n\nUseful control switches:\n\n- `integrations=[...]`: add or override integration config explicitly.\n- `disabled_integrations=[...]`: turn off specific auto-enabled integrations.\n- `auto_enabling_integrations=False`: stop library-detected integrations from activating automatically.\n- `default_integrations=False`: disables both default integrations and auto-enabling integrations unless you add them back manually.\n\nAI-specific note:\n\n- The OpenAI integration is auto-enabled when `openai` is installed.\n- For streaming OpenAI token accounting, Sentry docs call out an extra `tiktoken` dependency.\n\n## Common Pitfalls\n\n- Initializing too late means you miss startup exceptions, early breadcrumbs, and some framework instrumentation.\n- Copying `traces_sample_rate=1.0` or profiling sample rates from quickstarts into production usually creates unnecessary volume.\n- Enabling `send_default_pii=True` without reviewing data scrubbing is risky for user IDs, request headers, IPs, and request bodies.\n- Changing scope state inside `before_send` is too late; modify the event payload directly there.\n- Setting `default_integrations=False` turns off more than most users expect, including auto-enabled framework hooks.\n- Short-lived scripts may exit before events flush; raise `shutdown_timeout` or flush explicitly when reliability matters.\n- `enable_logs=True` is required for Sentry structured logs and for automatic capture from supported logging integrations.\n- If you do not want any tracing at all, do not rely on `traces_sample_rate=0`; set tracing options to `None`.\n\n## Version-Sensitive Notes For 2.54.0\n\n- On March 12, 2026, the version used here `2.54.0` matched the live latest stable PyPI release.\n- PyPI already shows `3.0.0` alpha releases. If your project is pinned to `2.54.0`, avoid mixing prerelease `3.x` examples into this code path.\n- Structured logs are only supported in stable form from SDK `2.35.0` onward; older blog posts may still describe them as experimental.\n- The default `max_value_length` increased in `2.34.0` from `1024` to `100000`, which changes truncation behavior for large payload fields.\n- The `2.54.0` release added top-level `set_attribute` and `remove_attribute` helpers for logs and metrics telemetry.\n- The same `2.54.0` release includes OpenAI streaming fixes, so if you rely on Sentry's OpenAI integration, prefer `2.54.0` or newer in the `2.x` line.\n\n## Official Sources\n\n- Docs root: `https://docs.sentry.io/platforms/python/`\n- Options: `https://docs.sentry.io/platforms/python/configuration/options/`\n- Filtering: `https://docs.sentry.io/platforms/python/configuration/filtering/`\n- Logs: `https://docs.sentry.io/platforms/python/logs/`\n- Tracing: `https://docs.sentry.io/platforms/python/tracing/`\n- Integrations: `https://docs.sentry.io/platforms/python/integrations/`\n- OpenAI integration: `https://docs.sentry.io/platforms/python/integrations/openai/`\n- PyPI project: `https://pypi.org/project/sentry-sdk/`\n- Exact PyPI release: `https://pypi.org/project/sentry-sdk/2.54.0/`\n- Release notes: `https://github.com/getsentry/sentry-python/releases/tag/2.54.0`\n"
  },
  {
    "path": "content/setuptools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"setuptools packaging backend and build configuration guide for Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"82.0.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"setuptools,python,packaging,build,pyproject,wheel,sdist\"\n---\n\n# `setuptools`\n\nUse `setuptools` as the packaging backend for building Python source distributions and wheels. For new projects, prefer declarative configuration in `pyproject.toml` with `setuptools.build_meta`; keep `setup.py` only when you truly need imperative build logic.\n\n## Install\n\nFor local packaging work:\n\n```bash\npython -m pip install --upgrade setuptools\n```\n\nFor building distributions in a project:\n\n```bash\npython -m pip install --upgrade build setuptools\npython -m build\n```\n\nWhen `setuptools` is your build backend, declare it in `pyproject.toml` so isolated builds install the right version automatically:\n\n```toml\n[build-system]\nrequires = [\"setuptools>=82.0.1\"]\nbuild-backend = \"setuptools.build_meta\"\n```\n\n## Golden Rule\n\n- Put standard package metadata in `[project]`.\n- Put `setuptools`-specific behavior in `[tool.setuptools]`.\n- Prefer a `src/` layout unless you have a strong reason not to.\n- Do not introduce new runtime dependencies on `pkg_resources`; use `importlib.metadata` or `importlib.resources` instead.\n\n## Minimal Modern Setup\n\nThis is the most useful starting point for a new package:\n\n```toml\n[build-system]\nrequires = [\"setuptools>=82.0.1\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"example-package\"\nversion = \"0.1.0\"\ndescription = \"Example package\"\nreadme = \"README.md\"\nrequires-python = \">=3.9\"\ndependencies = [\n  \"requests>=2.32\",\n]\n\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\n```\n\nRecommended layout:\n\n```text\npyproject.toml\nREADME.md\nsrc/\n  example_package/\n    __init__.py\n    cli.py\ntests/\n```\n\nWhy this shape matters:\n\n- `src/` layout reduces accidental imports from the repository root during development.\n- `package-dir = {\"\" = \"src\"}` keeps package discovery aligned with that layout.\n- `setuptools.build_meta` is the modern PEP 517 backend entry point.\n\n## Core Usage\n\n### Build an sdist and wheel\n\n```bash\npython -m build\n```\n\nThis reads `pyproject.toml`, creates an isolated build environment, and asks `setuptools.build_meta` to produce `dist/*.tar.gz` and `dist/*.whl`.\n\n### Install your project in editable mode\n\n```bash\npython -m pip install -e .\n```\n\nIf you want editable installs to behave more like a regular wheel and catch missing files earlier, use strict editable mode:\n\n```bash\npython -m pip install -e . --config-settings editable_mode=strict\n```\n\n### Add a console script\n\nUse standard project metadata for CLI entry points:\n\n```toml\n[project.scripts]\nexample-cli = \"example_package.cli:main\"\n```\n\nWith:\n\n```python\ndef main() -> int:\n    print(\"hello\")\n    return 0\n```\n\nAfter installation, `example-cli` is available on the command line.\n\n### Add plugin entry points\n\nFor plugin ecosystems, use named entry point groups:\n\n```toml\n[project.entry-points.\"pytest11\"]\nexample_plugin = \"example_package.pytest_plugin\"\n```\n\nThis is the standard way to register plugins for tools that discover entry points.\n\n## Configuration\n\n`setuptools` still supports configuration in `setup.py` and `setup.cfg`, but new work should center on `pyproject.toml`.\n\nPreferred split:\n\n- `[project]`: name, version, dependencies, optional dependencies, scripts, entry points, classifiers\n- `[tool.setuptools]`: package discovery, package data, namespace package behavior, dynamic metadata helpers\n- `setup.py`: only for edge cases where values must be computed in Python\n\nIf you must keep a `setup.py`, keep it minimal:\n\n```python\nfrom setuptools import setup\n\nsetup()\n```\n\nThat lets `pyproject.toml` remain the source of truth.\n\n## Package Discovery\n\nTwo safe patterns:\n\n1. Use `src/` layout with discovery scoped to `src`.\n2. In flat layouts, explicitly control what gets included.\n\nFor a `src/` layout:\n\n```toml\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\ninclude = [\"example_package*\"]\n```\n\nWhy this matters:\n\n- Automatic discovery in a flat repository can pick up unintended packages.\n- `src/` layout is the less error-prone default for published libraries.\n- If your package name and import package differ, discovery rules need to reflect the import package, not just the distribution name.\n\n## Package Data\n\nIf your wheel needs non-Python files, configure them explicitly. A common pattern is:\n\n```toml\n[tool.setuptools.package-data]\nexample_package = [\"py.typed\", \"templates/*.html\"]\n```\n\nTreat `MANIFEST.in` as sdist-focused. Do not assume that adding files there alone guarantees they land in the wheel you install from.\n\n## No Auth Layer\n\n`setuptools` is a local build backend, not a hosted API client. There is no package-specific authentication flow.\n\nThe practical \"configuration surface\" is:\n\n- `pyproject.toml`\n- optionally `setup.cfg`\n- optionally `setup.py`\n- environment/tooling around the build, such as `pip`, `build`, and publishing tools like `twine`\n\n## Common Pitfalls\n\n- Missing `[build-system]`: build isolation can fail or use a different backend path than you expect.\n- Relying on flat-layout auto-discovery: extra directories can be packaged accidentally.\n- Using `pkg_resources` in runtime code: it is deprecated for new usage and often slower than stdlib replacements.\n- Keeping important wheel files only in `MANIFEST.in`: source archives and wheels do not include files the same way.\n- Treating `setuptools` as an installer: use `pip` to install packages and `build` to create artifacts; `setuptools` is the backend underneath.\n\n## Version-Sensitive Notes For `82.0.1`\n\n- The target version for this doc is `82.0.1`, but PyPI had already published `82.0.2` by 2026-03-08. The upstream docs root uses `/latest/`, so examples there may reflect the newer patch release.\n- `easy_install` and `package_index` were removed in `82.0.0`. Do not use legacy `easy_install` workflows or `setup.py develop`; use `pip install -e .` instead.\n- Modern `setuptools` guidance prefers `importlib`-based runtime APIs over `pkg_resources`. If older examples rely on `pkg_resources`, treat them as migration candidates rather than new patterns to copy.\n\n## Practical Decision Rules For Agents\n\n- If you are packaging a normal library or CLI, start with `pyproject.toml` and `setuptools.build_meta`.\n- If package discovery behaves strangely, switch to `src/` layout before adding more custom exclusions.\n- If a project mixes `setup.py`, `setup.cfg`, and `pyproject.toml`, treat `pyproject.toml` as the target end state and minimize imperative `setup.py`.\n- If docs or blog posts mention `easy_install`, `pkg_resources`, or direct `setup.py` commands, assume they may be stale until confirmed against current upstream docs.\n\n## Official Sources\n\n- Docs root: https://setuptools.pypa.io/en/latest/\n- Quickstart: https://setuptools.pypa.io/en/latest/userguide/quickstart.html\n- Package discovery: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html\n- Entry points: https://setuptools.pypa.io/en/latest/userguide/entry_point.html\n- Build backend: https://setuptools.pypa.io/en/latest/build_meta.html\n- Supported interfaces and deprecations: https://setuptools.pypa.io/en/latest/userguide/interfaces.html\n- Changelog: https://setuptools.pypa.io/en/latest/history.html\n- PyPI registry: https://pypi.org/project/setuptools/\n"
  },
  {
    "path": "content/sgqlc/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"sgqlc GraphQL client for Python with typed operations, HTTP endpoints, schema introspection, and code generation\"\nmetadata:\n  languages: \"python\"\n  versions: \"18\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sgqlc,graphql,python,codegen,http,client\"\n---\n\n# sgqlc for Python\n\n`sgqlc` is a Python GraphQL client built around three core pieces:\n\n- `sgqlc.endpoint.http.HTTPEndpoint` to send GraphQL requests over HTTP.\n- `sgqlc.operation.Operation` to build GraphQL queries and mutations in Python.\n- the introspection/codegen tools to generate Python types from a server schema.\n\nFor application code, the most maintainable setup is:\n\n1. introspect the remote schema once\n2. generate a Python schema module\n3. build operations with `Operation(...)`\n4. execute them through `HTTPEndpoint`\n\n## Install\n\n```bash\npip install sgqlc\n```\n\nSet the GraphQL endpoint and any auth token in environment variables:\n\n```bash\nexport GRAPHQL_URL=\"https://api.github.com/graphql\"\nexport GRAPHQL_TOKEN=\"your-token\"\n```\n\n`sgqlc` does not manage auth for you. Pass the headers your API expects when you create the endpoint.\n\n## Generate Python types from a GraphQL schema\n\nIf your API exposes GraphQL introspection, generate a local schema module first.\n\n```bash\nsgqlc-introspection \\\n  -H \"Authorization: bearer ${GRAPHQL_TOKEN}\" \\\n  \"${GRAPHQL_URL}\" \\\n  schema.json\n\nsgqlc-codegen schema schema.json schema.py\n```\n\nThis gives you a `schema.py` module with Python classes for your GraphQL types, including `Query`, `Mutation`, and any object types your server exposes.\n\nKeep the generated file checked in if your app depends on a stable server schema. Regenerate it whenever the upstream GraphQL schema changes.\n\n## Initialize an HTTP endpoint\n\nUse `HTTPEndpoint` for normal HTTP-based GraphQL APIs:\n\n```python\nimport os\n\nfrom sgqlc.endpoint.http import HTTPEndpoint\n\n\nGRAPHQL_URL = os.environ[\"GRAPHQL_URL\"]\nGRAPHQL_TOKEN = os.environ[\"GRAPHQL_TOKEN\"]\n\nendpoint = HTTPEndpoint(\n    GRAPHQL_URL,\n    {\n        \"Authorization\": f\"bearer {GRAPHQL_TOKEN}\",\n    },\n)\n```\n\nThe second argument is the default header mapping for every request sent through that endpoint.\n\n## Build and execute a typed query\n\nAfter generating `schema.py`, import it and build operations from the generated root types.\n\n```python\nimport os\n\nfrom sgqlc.endpoint.http import HTTPEndpoint\nfrom sgqlc.operation import Operation\n\nimport schema\n\n\nendpoint = HTTPEndpoint(\n    os.environ[\"GRAPHQL_URL\"],\n    {\"Authorization\": f\"bearer {os.environ['GRAPHQL_TOKEN']}\"},\n)\n\nop = Operation(schema.Query)\nrepository = op.repository(owner=\"octocat\", name=\"Hello-World\")\nrepository.id()\nrepository.name()\nrepository.description()\n\nowner = repository.owner()\nowner.login()\n\nissues = repository.issues(first=5)\nnodes = issues.nodes()\nnodes.number()\nnodes.title()\n\ndata = endpoint(op)\n\nif data.get(\"errors\"):\n    raise RuntimeError(data[\"errors\"])\n\nresult = op + data\n\nprint(result.repository.name)\nprint(result.repository.owner.login)\nfor issue in result.repository.issues.nodes:\n    print(issue.number, issue.title)\n```\n\nKey points:\n\n- Only the fields you select are requested. If you do not call `repository.description()` or `owner.login()`, those values will not be present in the result.\n- `endpoint(op)` returns the decoded GraphQL JSON payload.\n- `op + data` maps that payload back into typed Python objects based on the selections in the operation.\n\n## Execute a raw query string\n\nIf you do not want typed response objects yet, you can send a raw GraphQL document and work with the JSON response directly:\n\n```python\nimport os\n\nfrom sgqlc.endpoint.http import HTTPEndpoint\n\n\nendpoint = HTTPEndpoint(\n    os.environ[\"GRAPHQL_URL\"],\n    {\"Authorization\": f\"bearer {os.environ['GRAPHQL_TOKEN']}\"},\n)\n\nquery = '''\nquery Repository($owner: String!, $name: String!) {\n  repository(owner: $owner, name: $name) {\n    id\n    name\n    owner {\n      login\n    }\n  }\n}\n'''\n\ndata = endpoint(\n    query,\n    variables={\"owner\": \"octocat\", \"name\": \"Hello-World\"},\n)\n\nif data.get(\"errors\"):\n    raise RuntimeError(data[\"errors\"])\n\nprint(data[\"data\"][\"repository\"][\"name\"])\nprint(data[\"data\"][\"repository\"][\"owner\"][\"login\"])\n```\n\nThis is useful for quick scripts, but you lose the typed-object mapping that makes `sgqlc` most valuable in larger codebases.\n\n## Generate Python operations from `.gql` files\n\nIf you keep GraphQL documents in source control, generate Python wrappers for them instead of constructing every operation inline.\n\n```bash\nsgqlc-codegen operation schema schema.py repo_query.gql repo_query.py\n```\n\nThat workflow is useful when:\n\n- your team already keeps queries and fragments in `.gql` files\n- you want code review on the exact GraphQL document text\n- you want schema-aware generated Python code without rebuilding selections in application code\n\n## Common workflow for a new API\n\n```bash\npip install sgqlc\n\nexport GRAPHQL_URL=\"https://your-graphql-server.example/graphql\"\nexport GRAPHQL_TOKEN=\"your-token\"\n\nsgqlc-introspection \\\n  -H \"Authorization: bearer ${GRAPHQL_TOKEN}\" \\\n  \"${GRAPHQL_URL}\" \\\n  schema.json\n\nsgqlc-codegen schema schema.json schema.py\n```\n\nThen in application code:\n\n```python\nfrom sgqlc.endpoint.http import HTTPEndpoint\nfrom sgqlc.operation import Operation\n\nimport os\nimport schema\n\n\nendpoint = HTTPEndpoint(\n    os.environ[\"GRAPHQL_URL\"],\n    {\"Authorization\": f\"bearer {os.environ['GRAPHQL_TOKEN']}\"},\n)\n\nop = Operation(schema.Query)\nviewer = op.viewer()\nviewer.login()\n\ndata = endpoint(op)\n\nif data.get(\"errors\"):\n    raise RuntimeError(data[\"errors\"])\n\nresult = op + data\nprint(result.viewer.login)\n```\n\nAdapt the root field names and arguments to your own schema.\n\n## Pitfalls\n\n- `sgqlc` is schema-driven. If the generated schema is stale, your selections can drift from the server and fail at runtime.\n- GraphQL APIs often return HTTP 200 with an `errors` array. Check `data.get(\"errors\")` before assuming the response succeeded.\n- Auth is just HTTP headers. If your API requires bearer tokens, API keys, cookies, or custom headers, pass them explicitly in `HTTPEndpoint(...)`.\n- Typed results only contain the fields you selected in the operation. Missing fields usually mean they were never requested.\n- Regenerate `schema.py` after server-side schema changes, especially before adding new fields, arguments, or mutations.\n\n## When to use inline operations vs generated operation modules\n\nUse inline `Operation(...)` code when:\n\n- the query is small and local to one call site\n- you want normal Python control flow around field selection\n\nUse generated operation modules when:\n\n- queries are shared across modules\n- you already keep GraphQL documents in `.gql` files\n- you want application code to import a generated operation instead of rebuilding it\n"
  },
  {
    "path": "content/shapely/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Shapely Python package for planar geometry creation, predicates, overlays, serialization, and spatial indexing\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"shapely,geometry,geospatial,gis,geos,spatial\"\n---\n\n# Shapely Python Package Guide\n\n## Golden Rule\n\nUse `shapely` for in-process planar geometry work, not for CRS management, map rendering, or file I/O. Distances, areas, and buffers are only as correct as your input coordinates, so reproject to an appropriate projected CRS before doing metric operations.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"shapely==2.1.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"shapely==2.1.2\"\npoetry add \"shapely==2.1.2\"\n```\n\nNotes:\n\n- Prefer wheels unless you specifically need a source build. The 2.1.2 wheels bundle GEOS for typical Linux, macOS, and Windows installs.\n- If you must build from source, the installation docs call out a recent GEOS C library and NumPy as build requirements.\n\n## Initialize And Basic Geometry Creation\n\nShapely 2.x exposes both geometry classes and vectorized functions from the top-level package.\n\n```python\nfrom shapely import LineString, Point, Polygon\n\npt = Point(0, 0)\nroad = LineString([(0, 0), (2, 2), (4, 2)])\nparcel = Polygon([(0, 0), (4, 0), (4, 3), (0, 3)])\n\nprint(pt.geom_type)      # Point\nprint(parcel.area)       # 12.0\nprint(road.length)       # 4.82842712474619\n```\n\nUse geometry objects when working with one or a few shapes, and use top-level `shapely.*` functions when you want NumPy-friendly bulk operations.\n\n## Core Usage\n\n### Predicates, buffers, and overlays\n\n```python\nfrom shapely import Point, Polygon\n\nparcel = Polygon([(0, 0), (8, 0), (8, 6), (0, 6)])\nwell = Point(3, 2)\nprotected_zone = well.buffer(1.5)\n\nprint(parcel.contains(well))               # True\nprint(parcel.intersects(protected_zone))   # True\n\noverlap = parcel.intersection(protected_zone)\nremaining = parcel.difference(protected_zone)\n\nprint(round(overlap.area, 2))\nprint(round(remaining.area, 2))\n```\n\nUse methods on geometry objects for one-off operations. Most binary operations also have top-level ufunc-style equivalents such as `shapely.intersection()` and `shapely.contains()`.\n\n### Vectorized operations over many geometries\n\nShapely 2.x integrates PyGEOS-style ufuncs, which are the right choice when you have arrays of geometries.\n\n```python\nimport numpy as np\nimport shapely\nfrom shapely import Point, box\n\nwindow = box(0, 0, 10, 10)\npoints = np.array([Point(1, 1), Point(5, 5), Point(11, 11)], dtype=object)\n\nmask = shapely.contains(window, points)\nclipped = shapely.intersection(shapely.buffer(points, 0.5), window)\n\nprint(mask.tolist())          # [True, True, False]\nprint(clipped[0].geom_type)   # Polygon\n```\n\nFor repeated predicate tests against the same geometry, prepare it first:\n\n```python\nimport shapely\nfrom shapely import Point, box\n\nwindow = box(0, 0, 10, 10)\nshapely.prepare(window)\n\nhits = shapely.contains(window, [Point(1, 1), Point(20, 20)])\nprint(hits.tolist())          # [True, False]\n```\n\n### Read and write common interchange formats\n\nUse WKT, WKB, and GeoJSON helpers when you need to cross process boundaries or store shapes in text/binary form.\n\n```python\nfrom shapely import from_wkt, to_wkt\nfrom shapely.geometry import mapping, shape\n\ngeom = from_wkt(\"POINT (1 2)\")\nas_wkt = to_wkt(geom)\n\ngeojson_mapping = mapping(geom)\nroundtrip = shape(geojson_mapping)\n\nprint(as_wkt)\nprint(roundtrip.equals(geom))\n```\n\n`shape()` and `mapping()` work with GeoJSON-like Python mappings. If you need CRS transforms, use `pyproj` or another CRS library outside Shapely.\n\n### Build a spatial index with `STRtree`\n\n`STRtree` is the built-in immutable spatial index for many-geometry lookup.\n\n```python\nfrom shapely import Point, STRtree, box\n\ngeometries = [Point(0, 0), Point(2, 2), Point(5, 5)]\ntree = STRtree(geometries)\n\nquery_geom = box(1, 1, 3, 3)\nmatches = tree.query(query_geom)\n\nprint(matches.tolist())  # array of matching geometry indices\nfor idx in matches:\n    print(idx, geometries[idx])\n```\n\nUse `predicate=` when you want the tree to filter by a spatial relationship instead of only bounding-box overlap.\n\n### Validate and repair invalid geometries\n\nInvalid polygons are common when input rings self-intersect or collapse. Check validity before assuming overlay results are trustworthy.\n\n```python\nimport shapely\nfrom shapely import Polygon\n\ngeom = Polygon([(0, 0), (2, 2), (0, 2), (2, 0), (0, 0)])\n\nprint(shapely.is_valid(geom))         # False\nfixed = shapely.make_valid(geom)\n\nprint(fixed.geom_type)\nprint(shapely.is_valid(fixed))        # True\n```\n\n`make_valid()` can return a different geometry type than the input, including collections. Keep downstream code defensive.\n\n## Configuration And Environment\n\nShapely has no service auth, API keys, or network configuration. The main setup decisions are about coordinates, dependencies, and performance.\n\n- Coordinate systems: Shapely does not manage CRS metadata or reprojection. Put geometries into the same CRS yourself before comparing or combining them.\n- Units: `length`, `area`, `distance`, and `buffer()` use the raw coordinate units. Latitude/longitude degrees are not meters.\n- Native library: Wheels include GEOS for normal installs. Source builds depend on the local GEOS toolchain.\n- Bulk workflows: NumPy arrays of geometry objects work well with top-level `shapely.*` functions for vectorized processing.\n\n## Common Pitfalls\n\n- Shapely is planar. Z values may be preserved on coordinates, but most analysis is still 2D and ignores height for predicates and measurements.\n- `==` compares object equality semantics, not spatial equality. Use `geom.equals(other)` or `shapely.equals(a, b)` when you mean topological equality.\n- Multipart geometries in 2.x are not general Python sequences. Use `.geoms` instead of assuming list-like iteration or indexing behavior.\n- Geometry objects are immutable in 2.x. Build new geometries instead of trying to mutate coordinates in place or attach ad hoc attributes.\n- `STRtree.query()` returns indices into the original geometry sequence, not geometry objects.\n- `make_valid()` may change the geometry type. A broken polygon can become a `MultiPolygon` or `GeometryCollection`.\n- GeoJSON helpers operate on geometry content only. They do not preserve feature properties, CRS metadata, or application-specific wrappers.\n\n## Version-Sensitive Notes For 2.1.x\n\n- Shapely 2.1.2 is a patch release. Use it for the packaging fixes and GEOS wheel refresh, but expect most API behavior to match the 2.1.0 and 2.1.1 user-manual content.\n- The 2.1.0 release added initial support for geometries with M or ZM values, coverage validation and simplification helpers, and a new `orient_polygons()` helper. These are 2.1-era features that older 2.0-focused examples will miss.\n- The 2.1.x docs deprecate passing several optional parameters positionally in top-level functions. Prefer explicit keywords such as `grid_size=...`, `include_z=...`, and `indices=...` for forward compatibility.\n- Some Read the Docs manual pages still surface as `2.1.1` even while the installation page and release notes are published under `2.1.2`. For package-version facts, trust the 2.1.2 install and release pages first.\n\n## Official Sources\n\n- Docs root: https://shapely.readthedocs.io/en/2.1.2/\n- Installation: https://shapely.readthedocs.io/en/2.1.2/installation.html\n- Migration guide: https://shapely.readthedocs.io/en/2.1.2/migration.html\n- Release notes: https://shapely.readthedocs.io/en/2.1.2/release/2.x.html\n- User manual: https://shapely.readthedocs.io/en/2.1.1/manual.html\n- API reference index: https://shapely.readthedocs.io/en/stable/_reference.html\n- PyPI: https://pypi.org/project/shapely/2.1.2/\n"
  },
  {
    "path": "content/shopify/docs/storefront/DOC.md",
    "content": "---\nname: storefront\ndescription: \"Shopify Storefront API library for building ecommerce integrations with OAuth and the official JavaScript SDK\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.1.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"shopify,storefront,ecommerce,api,oauth\"\n---\n\n# Shopify API Library - Comprehensive Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official `@shopify/shopify-api` package.** \n\n**Installation command:**\n```bash\npnpm add @shopify/shopify-api\n```\n\n**Warning:** Do not use deprecated packages like `shopify-api-node` or unofficial alternatives. This library is the official TypeScript/JavaScript SDK for Shopify's Admin API. \n\n## 2. Installation\n\n### Package Installation\n\n```bash\n# npm\nnpm install @shopify/shopify-api\n\n# yarn  \nyarn add @shopify/shopify-api\n\n# pnpm (recommended)\npnpm add @shopify/shopify-api\n``` \n\n### Environment Variables\n\n```bash\n# Required environment variables\nSHOPIFY_API_KEY=your_api_key_from_partners_dashboard\nSHOPIFY_API_SECRET=your_api_secret_from_partners_dashboard\nSHOPIFY_APP_URL=https://your-app-domain.com\nSHOPIFY_SCOPES=read_products,write_products\n``` \n\n## 3. Initialization\n\n### Runtime Adapter Import (Required First Step)\n\n**Critical:** Import the appropriate runtime adapter before using the library.\n\n```typescript\n// Node.js\nimport '@shopify/shopify-api/adapters/node';\n\n// Cloudflare Workers\nimport '@shopify/shopify-api/adapters/cf-worker';\n\n// Web API (generic runtimes)\nimport '@shopify/shopify-api/adapters/web-api';\n``` \n\n### Basic Configuration\n\n```typescript\nimport '@shopify/shopify-api/adapters/node';\nimport { shopifyApi, ApiVersion } from '@shopify/shopify-api';\n\nconst shopify = shopifyApi({\n  apiKey: process.env.SHOPIFY_API_KEY,\n  apiSecretKey: process.env.SHOPIFY_API_SECRET,\n  scopes: ['read_products', 'write_products'],\n  hostName: process.env.SHOPIFY_APP_URL,\n  apiVersion: ApiVersion.July25,\n});\n``` \n\n### Custom Store App Configuration\n\n```typescript\nconst shopify = shopifyApi({\n  apiSecretKey: \"App_API_secret_key\",\n  apiVersion: ApiVersion.April23,\n  isCustomStoreApp: true,\n  adminApiAccessToken: \"Admin_API_Access_Token\",\n  isEmbeddedApp: false,\n  hostName: \"my-shop.myshopify.com\",\n});\n```\n\n## 4. Core API Surfaces\n\n### Authentication & OAuth\n\n#### Minimal Example - Begin OAuth\n```typescript\nawait shopify.auth.begin({\n  shop: 'my-shop.myshopify.com',\n  callbackPath: '/auth/callback',\n  isOnline: true,\n  rawRequest: req,\n  rawResponse: res,\n});\n``` \n\n#### Advanced Example - OAuth Callback\n```typescript\nconst callbackResponse = await shopify.auth.callback({\n  rawRequest: req,\n  rawResponse: res,\n});\n\nconst { session } = callbackResponse;\n// Store session for future API calls\n```\n\n### REST API Client\n\n#### Minimal Example\n```typescript\nconst client = new shopify.clients.Rest({ session });\nconst response = await client.get({\n  path: 'products',\n});\n```\n\n#### Advanced Example with REST Resources\n```typescript\nimport { restResources } from '@shopify/shopify-api/rest/admin/2023-07';\n\nconst shopify = shopifyApi({\n  // ... other config\n  restResources,\n});\n\n// Using REST resources\nconst products = await shopify.rest.Product.all({\n  session,\n  limit: 50,\n  status: 'active',\n});\n``` \n\n### GraphQL API Client\n\n#### Minimal Example\n```typescript\nconst client = new shopify.clients.Graphql({ session });\nconst response = await client.request(`\n  query getProducts($first: Int!) {\n    products(first: $first) {\n      edges {\n        node {\n          id\n          title\n        }\n      }\n    }\n  }\n`, {\n  variables: { first: 10 }\n});\n```  \n\n#### Advanced Example with Types\n```typescript\nconst response = await client.request(\n  `#graphql\n  query productHandles($first: Int!) {\n    products(first: $first) {\n      edges {\n        node {\n          handle\n        }\n      }\n    }\n  }`,\n  {\n    variables: {\n      first: 10,\n    },\n  },\n);\n``` \n\n### Webhooks\n\n#### Minimal Example - Registration\n```typescript\nawait shopify.webhooks.register({\n  session,\n});\n```\n\n#### Advanced Example - Processing\n```typescript\nconst handleWebhookRequest = async (\n  topic: string,\n  shop: string,\n  webhookRequestBody: string,\n  webhookId: string,\n  apiVersion: string,\n) => {\n  // Process webhook event\n};\n\nshopify.webhooks.addHandlers({\n  PRODUCTS_CREATE: [\n    {\n      deliveryMethod: DeliveryMethod.Http,\n      callbackUrl: '/webhooks',\n      callback: handleWebhookRequest,\n    },\n  ],\n});\n``` \n\n### Billing\n\n#### Minimal Example - Check Billing\n```typescript\nconst billingCheck = await shopify.billing.check({\n  session,\n  plans: ['Basic Plan'],\n  isTest: true,\n});\n```\n\n#### Advanced Example - Request Payment\n```typescript\nconst billingResponse = await shopify.billing.request({\n  session,\n  plan: 'Premium Plan',\n  isTest: true,\n  returnUrl: 'https://myapp.com/billing/callback',\n});\n``` \n\n## 5. Advanced Features\n\n### Error Handling\n\n```typescript\nimport { \n  ShopifyError, \n  HttpResponseError, \n  BillingError \n} from '@shopify/shopify-api';\n\ntry {\n  const response = await client.request(query);\n} catch (error) {\n  if (error instanceof HttpResponseError) {\n    console.log('HTTP Error:', error.response.status);\n  } else if (error instanceof BillingError) {\n    console.log('Billing Error:', error.message);\n  }\n}\n```\n\n### Retries and Timeouts\n\n```typescript\nconst client = new shopify.clients.Graphql({\n  session,\n  retries: 3,\n});\n\nconst response = await client.request(query, {\n  retries: 2,\n});\n```  \n\n### Logging and Debugging\n\n```typescript\nconst shopify = shopifyApi({\n  // ... other config\n  logger: {\n    level: LogSeverity.Debug,\n    timestamps: true,\n    httpRequests: true,\n    log: async (severity, message) => {\n      console.log(`[${severity}] ${message}`);\n    },\n  },\n});\n```\n\n### Pagination\n\n```typescript\nlet pageInfo;\ndo {\n  const response = await shopify.rest.Product.all({\n    ...pageInfo?.nextPage?.query,\n    session,\n    limit: 10,\n  });\n\n  const pageProducts = response.data;\n  pageInfo = response.pageInfo;\n} while (pageInfo?.nextPage);\n``` \n\n## 6. TypeScript Usage\n\n### Type Imports\n\n```typescript\nimport {\n  Session,\n  ApiVersion,\n  BillingInterval,\n  DeliveryMethod,\n  LogSeverity,\n} from '@shopify/shopify-api';\n```\n\n### Type-Safe GraphQL\n\n```typescript\n// Install codegen preset\n// pnpm add --save-dev @shopify/api-codegen-preset\n\n// After running graphql-codegen, queries are automatically typed\nconst response = await client.request(\n  `#graphql\n  query getProduct($id: ID!) {\n    product(id: $id) {\n      id\n      title\n      handle\n    }\n  }`,\n  {\n    variables: { id: \"gid://shopify/Product/123\" }\n  }\n);\n\n// response.data.product is now fully typed\n```\n\n### Session Types\n\n```typescript\nconst session: Session = {\n  id: 'session-id',\n  shop: 'my-shop.myshopify.com',\n  state: 'state-value',\n  isOnline: true,\n  accessToken: 'access-token',\n  scope: 'read_products,write_products',\n};\n```\n\n## 7. Best Practices\n\n### Session Management\n\n```typescript\n// Always validate sessions before API calls\nconst sessionId = await shopify.session.getCurrentId({\n  isOnline: true,\n  rawRequest: req,\n  rawResponse: res,\n});\n\nconst session = await getSessionFromStorage(sessionId);\nif (!session) {\n  // Redirect to OAuth\n  return;\n}\n``` \n\n### Rate Limit Handling\n\n```typescript\n// Use built-in retry logic\nconst client = new shopify.clients.Graphql({\n  session,\n  retries: 3, // Will retry on rate limit errors\n});\n```\n\n### Custom Store Apps\n\n```typescript\n// For custom store apps, create sessions manually\nconst session = shopify.session.customAppSession(\"my-shop.myshopify.com\");\n\nconst productCount = await shopify.rest.Product.count({ session });\n``` \n\n## 8. Production Checklist\n\n### Pin SDK Version\n\n```json\n{\n  \"dependencies\": {\n    \"@shopify/shopify-api\": \"^12.0.0\"\n  }\n}\n``` \n\n### Robust Error Handling\n\n```typescript\ntry {\n  const response = await client.request(query);\n  return response.data;\n} catch (error) {\n  if (error instanceof HttpResponseError) {\n    // Log and handle HTTP errors\n    logger.error('API Error:', error.response.status);\n    throw new Error('API request failed');\n  }\n  throw error;\n}\n```\n\n### Environment Configuration\n\n```typescript\nconst shopify = shopifyApi({\n  apiKey: process.env.SHOPIFY_API_KEY!,\n  apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n  scopes: process.env.SHOPIFY_SCOPES!.split(','),\n  hostName: process.env.SHOPIFY_APP_URL!,\n  apiVersion: ApiVersion.July25, // Use stable versions\n  logger: {\n    level: process.env.NODE_ENV === 'production' \n      ? LogSeverity.Error \n      : LogSeverity.Debug,\n  },\n});\n```\n\n### Webhook Security\n\n```typescript\n// Always validate webhook HMAC\nawait shopify.webhooks.process({\n  rawBody: req.body,\n  rawRequest: req,\n  rawResponse: res,\n});\n```\n\n## Notes\n\nThis guide covers the `@shopify/shopify-api` library which provides comprehensive TypeScript/JavaScript support for Shopify's Admin API, including OAuth flows, REST/GraphQL clients, webhook processing, and billing functionality.  The library uses a factory pattern centered around `shopifyApi()` and requires runtime adapters for cross-platform compatibility. "
  },
  {
    "path": "content/shortuuid/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"shortuuid package guide for generating, encoding, and decoding compact UUID-based identifiers in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.13\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"shortuuid,python,uuid,identifiers,tokens\"\n---\n\n# shortuuid Python Package Guide\n\n## Golden Rule\n\nUse `shortuuid` when your application needs shorter UUID-based identifiers as strings. Generate new IDs with `shortuuid.uuid()`, round-trip existing `uuid.UUID` values with `shortuuid.encode()` and `shortuuid.decode()`, and keep any custom alphabet consistent anywhere you create or decode IDs.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"shortuuid==1.0.13\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"shortuuid==1.0.13\"\npoetry add \"shortuuid==1.0.13\"\n```\n\nNotes:\n\n- The PyPI package is `shortuuid`, and the main import is also `shortuuid`.\n- `shortuuid` is a pure Python utility package. It has no service client, no auth flow, and no required environment variables.\n- If your app wants a custom alphabet, treat that as app configuration and initialize one `ShortUUID` instance with it.\n\n## Initialize\n\nThe package works without setup, but creating one configured `ShortUUID` instance is the cleanest pattern when your app needs a custom alphabet for all generated IDs.\n\n```python\nimport os\n\nimport shortuuid\n\nalphabet = os.getenv(\"SHORTUUID_ALPHABET\")\nids = shortuuid.ShortUUID(alphabet=alphabet) if alphabet else shortuuid.ShortUUID()\n\nnew_id = ids.uuid()\ninvite_code = ids.random(length=10)\n\nprint(new_id)\nprint(invite_code)\n```\n\nUse the default instance when you do not need custom behavior:\n\n```python\nimport shortuuid\n\norder_id = shortuuid.uuid()\nprint(order_id)\n```\n\n## Core Workflows\n\n### Generate a new short UUID\n\n`shortuuid.uuid()` returns a compact string identifier derived from a UUID.\n\n```python\nimport shortuuid\n\nuser_id = shortuuid.uuid()\nsession_id = shortuuid.uuid()\n\nprint(user_id)\nprint(session_id)\n```\n\nUse this when your application wants a shorter string ID but still wants UUID-style uniqueness.\n\n### Encode and decode standard UUID values\n\nUse `encode()` when you already have a `uuid.UUID` value and want the short form. Use `decode()` when another part of your system needs the standard UUID object again.\n\n```python\nimport uuid\n\nimport shortuuid\n\ncanonical = uuid.uuid4()\nshort_value = shortuuid.encode(canonical)\ndecoded = shortuuid.decode(short_value)\n\nprint(canonical)\nprint(short_value)\nprint(decoded)\nassert decoded == canonical\n```\n\nThis is the safest pattern when one system stores compact IDs but another expects standard UUID objects.\n\n### Generate a deterministic value from a name\n\nPass `name=` when you need the same input name to produce the same short UUID string.\n\n```python\nimport shortuuid\n\ncustomer_key = shortuuid.uuid(name=\"customer:42\")\nsame_customer_key = shortuuid.uuid(name=\"customer:42\")\n\nassert customer_key == same_customer_key\n```\n\nUse this for stable derived identifiers, not for secrets or one-time tokens.\n\n### Generate fixed-length random tokens\n\nUse `ShortUUID().random(length=...)` when you need a short random string and do not need UUID decode/encode round-tripping.\n\n```python\nimport shortuuid\n\nids = shortuuid.ShortUUID()\n\ninvite_code = ids.random(length=8)\nreset_code = ids.random(length=12)\n\nprint(invite_code)\nprint(reset_code)\n```\n\nThis is a better fit for user-facing codes than manually truncating a UUID string.\n\n### Use a custom alphabet\n\nIf you want IDs with a restricted character set, configure a dedicated instance and use that same alphabet everywhere you generate or decode values.\n\n```python\nimport uuid\n\nimport shortuuid\n\nids = shortuuid.ShortUUID(alphabet=\"23456789ABCDEFGHJKLMNPQRSTUVWXYZ\")\n\nticket_id = ids.uuid()\nencoded = ids.encode(uuid.uuid4())\ndecoded = ids.decode(encoded)\n\nprint(ticket_id)\nprint(encoded)\nprint(decoded)\n```\n\nKeep custom alphabets stable across services, workers, and scripts that share these IDs.\n\n## Important Pitfalls\n\n- `shortuuid.uuid()` returns a string, not a `uuid.UUID` object.\n- `ShortUUID().random(length=...)` gives you a random string, not an encoded UUID value you can round-trip with `decode()`.\n- If you customize the alphabet, use the same alphabet for both encoding and decoding.\n- Prefer a dedicated `ShortUUID(alphabet=...)` instance over changing global behavior in reusable library code.\n- Use standard `uuid.UUID` values when an external API or database field requires canonical UUID formatting.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/skorokithakis/shortuuid`\n- PyPI package page: `https://pypi.org/project/shortuuid/`\n"
  },
  {
    "path": "content/simmer/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Connect AI agents to prediction markets (Polymarket, Kalshi) through one Python SDK. Paper trade with virtual $SIM, graduate to real USDC/USD. Self-custody wallets, safety rails, heartbeat pattern.\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.9.12\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"prediction-markets,polymarket,kalshi,trading,ai-agents,betting,forecasting,simmer,sdk\"\n---\n\n# Simmer SDK\n\nThe prediction market interface for AI agents. One SDK connects your agent to Polymarket (USDC) and Kalshi (USD), with a built-in paper trading venue ($SIM) to practice first.\n\n- **Install:** `pip install simmer-sdk`\n- **Source:** https://github.com/SpartanLabsXyz/simmer-sdk\n- **Full docs:** https://docs.simmer.markets/llms-full.txt\n- **Support:** https://t.me/+DykggGXL67E4MGE9\n\n## Quick Start\n\n```bash\n# Register (no auth required)\ncurl -X POST https://api.simmer.markets/api/sdk/agents/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"my-agent\", \"description\": \"My trading agent\"}'\n# Save the api_key from the response — shown only once\n```\n\n```python\nfrom simmer_sdk import SimmerClient\n\nclient = SimmerClient(api_key=\"sk_live_...\")\n\n# Find markets\nmarkets = client.find_markets(\"weather\")\n\n# Check context before trading\ncontext = client.get_market_context(markets[0].id)\n\n# Trade — always include reasoning\nresult = client.trade(\n    market_id=markets[0].id,\n    side=\"yes\",\n    amount=10.0,\n    venue=\"sim\",\n    reasoning=\"NOAA forecast 80%, market at 45%\"\n)\nprint(f\"Bought {result.shares_bought} shares for {result.cost}\")\n```\n\n## Constructor\n\n```python\nSimmerClient(\n    api_key: str,                              # sk_live_...\n    base_url: str = \"https://api.simmer.markets\",\n    venue: str = \"sim\",                        # \"sim\", \"polymarket\", or \"kalshi\"\n    private_key: Optional[str] = None,         # 0x... EVM key (or set WALLET_PRIVATE_KEY env)\n    live: bool = True                          # False = simulated trades with real prices\n)\n```\n\nEnvironment variables: `WALLET_PRIVATE_KEY` (Polygon/EVM), `SOLANA_PRIVATE_KEY` (Kalshi), `SIMMER_API_KEY`.\n\n## Core Methods\n\n```python\n# Heartbeat — call periodically, returns full portfolio state + opportunities\nbriefing = client.get_briefing(since=\"2026-03-11T00:00:00Z\")\n\n# Markets\nmarkets = client.get_markets(status=\"active\", import_source=\"polymarket\", limit=50)\nmarkets = client.find_markets(\"bitcoin\")  # client-side text search\nmarket = client.get_market_by_id(\"uuid\")\ncontext = client.get_market_context(\"uuid\")  # warnings, slippage, position info\n\n# Trading\nresult = client.trade(\n    market_id=\"uuid\",\n    side=\"yes\",              # \"yes\" or \"no\"\n    amount=10.0,             # USD/SIM to spend (buys)\n    action=\"buy\",            # \"buy\" or \"sell\"\n    shares=0,                # number of shares (sells)\n    venue=\"sim\",             # \"sim\", \"polymarket\", or \"kalshi\"\n    reasoning=\"My thesis\",   # displayed publicly\n    source=\"sdk:my-strategy\",\n    allow_rebuy=False        # skip if already holding (default)\n)\n\n# Positions\npositions = client.get_positions(venue=\"sim\")\n\n# Import external markets\nresult = client.import_market(\"https://polymarket.com/event/...\")\n```\n\n## Venues\n\n| Venue | Currency | Notes |\n|-------|----------|-------|\n| `sim` | $SIM (virtual) | Paper trading. Default. 10,000 $SIM on signup. |\n| `polymarket` | USDC.e (real) | Requires wallet setup (see below) |\n| `kalshi` | USD (real) | Requires Solana wallet + KYC |\n\nAll venues use the same `client.trade()` interface. Start on `sim`, graduate when profitable.\n\n## Wallet Setup (Polymarket)\n\n```python\nclient = SimmerClient(api_key=\"sk_live_...\", venue=\"polymarket\")\n# WALLET_PRIVATE_KEY env var must be set (0x-prefixed)\n\nclient.link_wallet()       # one-time: register wallet with Simmer\nclient.set_approvals()     # one-time: set Polymarket contract approvals\n\n# Then trade normally\nclient.trade(market_id=\"uuid\", side=\"yes\", amount=10.0, venue=\"polymarket\")\n\n# Redeem resolved positions (external wallets must call this explicitly)\nresults = client.auto_redeem()\n```\n\nRequires USDC.e (bridged USDC) + small POL for gas on Polygon.\n\n## Heartbeat Pattern\n\nOne call returns everything your agent needs each cycle:\n\n```python\nbriefing = client.get_briefing()\n# briefing contains:\n#   venues.sim / venues.polymarket / venues.kalshi — balance, pnl, positions, actions\n#   opportunities.new_markets — markets since last check\n#   risk_alerts — expiring positions, concentration warnings\n#   performance — pnl, win rate\n```\n\n## Full Reference\n\nFor the complete API (alerts, webhooks, risk monitors, order management, Kalshi trading, error handling), see https://docs.simmer.markets/llms-full.txt\n"
  },
  {
    "path": "content/simplejson/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"simplejson Python package guide for JSON serialization and parsing with stdlib-style APIs and Decimal-friendly workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.20.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"simplejson,json,serialization,deserialization,python,decimal\"\n---\n\n# simplejson Python Package Guide\n\n## Golden Rule\n\nUse `simplejson` when a Python project already depends on it or when you want a JSON library with the familiar `json` module API plus explicit helpers for workflows like `Decimal` serialization. It is a local encoding and decoding library, not a network client, so there is no authentication, service endpoint, or client object to configure.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"simplejson==3.20.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"simplejson==3.20.2\"\npoetry add \"simplejson==3.20.2\"\n```\n\nQuick verification:\n\n```bash\npython - <<'PY'\nfrom importlib.metadata import version\nimport simplejson\n\nprint(version(\"simplejson\"))\nprint(simplejson.__version__)\nPY\n```\n\n## Environment And Initialization\n\n`simplejson` does not use environment variables.\n\nThere is no client initialization step. Import the module and call `dump()`, `dumps()`, `load()`, or `loads()` directly.\n\nIf you want code that reads like the standard library `json` module, alias it during import:\n\n```python\nimport simplejson as json\n```\n\n## Core Usage\n\n### Serialize a Python object to a JSON string\n\n```python\nimport simplejson as json\n\npayload = {\n    \"name\": \"Ada\",\n    \"active\": True,\n    \"scores\": [3, 7, 11],\n}\n\nbody = json.dumps(payload)\nprint(body)\n```\n\n### Parse a JSON string\n\n```python\nimport simplejson as json\n\nraw = '{\"name\": \"Ada\", \"active\": true, \"scores\": [3, 7, 11]}'\ndata = json.loads(raw)\n\nprint(data[\"name\"])\nprint(data[\"scores\"][0])\n```\n\n### Read and write JSON files\n\n```python\nfrom pathlib import Path\nimport simplejson as json\n\npayload = {\n    \"ok\": True,\n    \"items\": [1, 2, 3],\n}\n\npath = Path(\"data.json\")\n\nwith path.open(\"w\", encoding=\"utf-8\") as f:\n    json.dump(payload, f, indent=2, ensure_ascii=False)\n\nwith path.open(\"r\", encoding=\"utf-8\") as f:\n    loaded = json.load(f)\n\nprint(loaded)\n```\n\nUse text mode with an explicit UTF-8 encoding unless you have a reason to manage bytes separately.\n\n## Preserve Decimal Values\n\nOne of the most common reasons to choose `simplejson` is explicit `Decimal` support.\n\n```python\nfrom decimal import Decimal\nimport simplejson as json\n\npayload = {\n    \"subtotal\": Decimal(\"19.99\"),\n    \"tax\": Decimal(\"1.50\"),\n}\n\nbody = json.dumps(payload, use_decimal=True)\nparsed = json.loads(body, use_decimal=True)\n\nprint(body)\nprint(parsed[\"subtotal\"], type(parsed[\"subtotal\"]))\n```\n\nWhen precision matters for money or rates, prefer `Decimal` values in application code instead of converting through binary floating point.\n\n## Serialize Custom Python Objects\n\nUse `default=` to convert unsupported objects into standard JSON-compatible data structures.\n\n```python\nfrom dataclasses import asdict, dataclass\nimport simplejson as json\n\n@dataclass\nclass User:\n    id: int\n    email: str\n\ndef to_jsonable(obj):\n    if isinstance(obj, User):\n        return asdict(obj)\n    raise TypeError(f\"Unsupported type: {type(obj)!r}\")\n\nbody = json.dumps(User(id=1, email=\"ada@example.com\"), default=to_jsonable)\nprint(body)\n```\n\nIf your application already has dataclasses, Pydantic models, or ORM objects, keep the conversion logic close to the serialization call so it is obvious which JSON shape is produced.\n\n## Control Output Format\n\nThe most useful output options for application code are the same ones most Python developers already know from the standard library:\n\n- `indent` for pretty-printing\n- `sort_keys=True` for stable key order\n- `ensure_ascii=False` for readable UTF-8 output\n- `separators=(\",\", \":\")` for compact JSON when payload size matters\n\n```python\nimport simplejson as json\n\npayload = {\n    \"title\": \"café\",\n    \"url\": \"https://example.com/docs\",\n}\n\nbody = json.dumps(\n    payload,\n    ensure_ascii=False,\n    indent=2,\n    sort_keys=True,\n)\n\nprint(body)\n```\n\n## Decode Hooks\n\nIf you need to shape decoded objects during parsing, use the same hook pattern you would use with the standard library.\n\n```python\nimport simplejson as json\n\ndef as_user(obj):\n    if {\"id\", \"email\"} <= obj.keys():\n        return {\"kind\": \"user\", **obj}\n    return obj\n\nraw = '{\"id\": 1, \"email\": \"ada@example.com\"}'\nparsed = json.loads(raw, object_hook=as_user)\n\nprint(parsed)\n```\n\nUse `object_hook` only when every object at that parse boundary should be examined. For one-off transformations, parse to normal dictionaries first and then map them in plain Python.\n\n## Error Handling\n\nHandle malformed JSON close to the parse boundary:\n\n```python\nimport simplejson as json\n\ntry:\n    json.loads('{\"broken\": }')\nexcept json.JSONDecodeError as exc:\n    print(f\"Invalid JSON: {exc}\")\n```\n\nIf your code accepts untrusted JSON from files, queues, or HTTP requests, catch decode errors before the data reaches the rest of your application.\n\n## Common Pitfalls\n\n- `simplejson` is local-only. Do not design configuration around API keys, hosts, or retry settings.\n- Importing `simplejson as json` is often the cleanest migration path, but do not assume every project-wide `json` call can be swapped blindly without checking tests.\n- `default=` only affects values the encoder does not already know how to serialize. It is not a general post-processing hook.\n- Use `ensure_ascii=False` if you want readable UTF-8 output instead of escaped non-ASCII characters.\n- When exact numeric precision matters, pass `use_decimal=True` and keep values as `Decimal` in your own code.\n\n## Minimal Drop-In Pattern\n\nFor applications that already use the stdlib interface, this is the smallest practical integration pattern:\n\n```python\nimport simplejson as json\n\ndef encode_payload(payload: dict) -> str:\n    return json.dumps(payload, ensure_ascii=False)\n\ndef decode_payload(raw: str) -> dict:\n    return json.loads(raw)\n```\n\nUse this style when you want the package change to stay narrow and obvious.\n"
  },
  {
    "path": "content/singer-python/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Singer Python utility library for building Singer taps and targets that emit schemas, records, state, and metadata\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.4.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"singer,etl,elt,tap,target,json-schema,state\"\n---\n\n# singer-python Python Package Guide\n\n## Golden Rule\n\nUse `singer-python` as a helper library inside a Singer tap or target, import it as `import singer`, and keep the Singer message stream clean on stdout. Use `singer` write helpers for `SCHEMA`, `RECORD`, `STATE`, and version messages, and send logs through `singer.get_logger()` so they go to stderr instead of corrupting the stream.\n\n## Install\n\nUse an isolated environment and pin the version you actually want:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"singer-python==6.4.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"singer-python==6.4.0\"\npoetry add \"singer-python==6.4.0\"\n```\n\nThe upstream README still shows a source checkout plus `make install`, but for normal tap or target development the PyPI package is the practical starting point.\n\n## Standard CLI Setup\n\n`parse_args(required_config_keys)` is the main setup helper for Singer taps. It handles the standard Singer CLI flags, loads JSON files for you, and validates that required config keys are present.\n\nSupported standard flags:\n\n- `--config` / `-c`: required JSON config file\n- `--state` / `-s`: optional JSON state file, defaulting to an empty dict\n- `--catalog`: optional catalog file, loaded into a `Catalog` object\n- `--properties` / `-p`: deprecated legacy selection file\n- `--discover` / `-d`: discovery mode\n- `--dev`: dev mode flag\n\nMinimal tap skeleton:\n\n```python\nimport singer\nfrom singer import metadata\n\nLOGGER = singer.get_logger()\nREQUIRED_CONFIG_KEYS = [\"api_token\", \"start_date\"]\n\ndef user_schema() -> dict:\n    return {\n        \"type\": \"object\",\n        \"properties\": {\n            \"id\": {\"type\": [\"null\", \"integer\"]},\n            \"email\": {\"type\": [\"null\", \"string\"]},\n            \"updated_at\": {\"type\": [\"null\", \"string\"], \"format\": \"date-time\"},\n        },\n    }\n\ndef discover() -> None:\n    schema = user_schema()\n    singer.write_schema(\n        \"users\",\n        schema,\n        key_properties=[\"id\"],\n        bookmark_properties=[\"updated_at\"],\n    )\n\ndef sync(config: dict, state: dict) -> None:\n    schema = user_schema()\n    raw_metadata = metadata.get_standard_metadata(\n        schema=schema,\n        key_properties=[\"id\"],\n        valid_replication_keys=[\"updated_at\"],\n        replication_method=\"INCREMENTAL\",\n    )\n    compiled_metadata = metadata.to_map(raw_metadata)\n\n    bookmark = singer.get_bookmark(state, \"users\", \"updated_at\") or config[\"start_date\"]\n\n    for raw_record in fetch_users_since(config[\"api_token\"], bookmark):\n        record = singer.transform(raw_record, schema, metadata=compiled_metadata)\n        singer.write_record(\"users\", record)\n\n        if record.get(\"updated_at\"):\n            singer.set_bookmark(state, \"users\", \"updated_at\", record[\"updated_at\"])\n\n    singer.write_state(state)\n\n@singer.utils.handle_top_exception(LOGGER)\ndef main() -> None:\n    args = singer.parse_args(REQUIRED_CONFIG_KEYS)\n\n    if args.discover:\n        discover()\n        return\n\n    sync(args.config, args.state)\n\nif __name__ == \"__main__\":\n    main()\n```\n\nImplementation notes:\n\n- `args.config` is already parsed JSON, not a file path string.\n- `args.state` is already parsed JSON and defaults to `{}` when no state file is provided.\n- `args.catalog` is already loaded as a `Catalog` object when `--catalog` is passed.\n\n## Core Message Writing\n\nThe most common helpers are exported at the package top level:\n\n- `singer.write_schema(stream_name, schema, key_properties, bookmark_properties=None)`\n- `singer.write_record(stream_name, record, stream_alias=None, time_extracted=None)`\n- `singer.write_records(stream_name, records)`\n- `singer.write_state(state_dict)`\n- `singer.write_version(stream_name, version)`\n\nTypical flow:\n\n1. Emit one `SCHEMA` message per stream before records.\n2. Emit `RECORD` messages as dictionaries.\n3. Emit periodic `STATE` messages, especially after successful bookmark updates.\n\nExample:\n\n```python\nimport singer\n\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\"type\": [\"null\", \"integer\"]},\n        \"name\": {\"type\": [\"null\", \"string\"]},\n    },\n}\n\nsinger.write_schema(\"users\", schema, [\"id\"])\nsinger.write_record(\"users\", {\"id\": 1, \"name\": \"Ada\"})\nsinger.write_state({\"bookmarks\": {\"users\": {\"updated_at\": \"2026-03-12T00:00:00Z\"}}})\n```\n\nIf you need experimental versioned streams, `RecordMessage` supports a `version` field, but `write_record()` itself does not take a `version` argument. In that case, build a `RecordMessage` and pass it to `write_message()` directly.\n\n## Metadata And Catalog Selection\n\nThe metadata helpers live in the `singer.metadata` module, not as top-level functions.\n\nThe common pattern is:\n\n1. Build raw metadata with `metadata.get_standard_metadata(...)`\n2. Convert it with `metadata.to_map(...)`\n3. Pass the compiled metadata into `singer.transform(...)`\n\nExample:\n\n```python\nfrom singer import metadata\nimport singer\n\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\"type\": [\"null\", \"integer\"]},\n        \"email\": {\"type\": [\"null\", \"string\"]},\n    },\n}\n\nraw_metadata = metadata.get_standard_metadata(\n    schema=schema,\n    key_properties=[\"id\"],\n)\ncompiled_metadata = metadata.to_map(raw_metadata)\n\nrecord = singer.transform(\n    {\"id\": \"123\", \"email\": \"user@example.com\"},\n    schema,\n    metadata=compiled_metadata,\n)\n```\n\n`metadata.get_standard_metadata(...)` marks key fields as `automatic` and regular fields as `available`, which is what `singer.transform(...)` uses when it filters fields by selection metadata.\n\n## Record Transformation And Type Coercion\n\n`singer.transform(...)` and `Transformer` are useful when your source payload needs to be coerced to the schema you are about to emit.\n\nUseful behaviors in `6.4.0`:\n\n- strings can be coerced to `integer`, `number`, and `boolean`\n- schema `anyOf` handling is supported\n- arrays and nested objects are transformed recursively\n- unsupported or unselected fields can be filtered via metadata\n- `format: singer.decimal` is handled specially\n\nExample:\n\n```python\nimport singer\n\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\"type\": [\"null\", \"integer\"]},\n        \"active\": {\"type\": [\"null\", \"boolean\"]},\n        \"amount\": {\"type\": [\"null\", \"number\"]},\n    },\n}\n\nrecord = singer.transform(\n    {\"id\": \"42\", \"active\": \"false\", \"amount\": \"19.95\"},\n    schema,\n)\n\nassert record == {\"id\": 42, \"active\": False, \"amount\": 19.95}\n```\n\n## State And Bookmark Management\n\nFor incremental syncs, use the exported state helpers instead of mutating nested state structures ad hoc.\n\nCommon helpers:\n\n- `singer.get_bookmark(state, stream, key)`\n- `singer.set_bookmark(state, stream, key, value)`\n- `singer.clear_bookmark(state, stream, key)`\n- `singer.reset_stream(state, stream)`\n- `singer.get_offset(state, stream)`\n- `singer.set_offset(state, stream, value)`\n- `singer.clear_offset(state, stream)`\n- `singer.get_currently_syncing(state)`\n- `singer.set_currently_syncing(state, stream)`\n- `singer.get_version(state, stream)`\n- `singer.set_version(state, stream, version)`\n- `singer.clear_version(state, stream)`\n\nTypical incremental pattern:\n\n```python\nbookmark = singer.get_bookmark(state, \"users\", \"updated_at\") or config[\"start_date\"]\n\nfor record in fetch_users_since(config[\"api_token\"], bookmark):\n    singer.write_record(\"users\", record)\n    singer.set_bookmark(state, \"users\", \"updated_at\", record[\"updated_at\"])\n\nsinger.write_state(state)\n```\n\n## Config And Auth\n\n`singer-python` does not implement authentication for you. Your tap owns auth, retries, request signing, and API-specific pagination behavior. The library helps with argument parsing, state, metadata, and message emission.\n\nPractical config rules:\n\n- keep credentials in the JSON config file or inject them into that file from environment variables before execution\n- validate required keys through `parse_args(REQUIRED_CONFIG_KEYS)`\n- never emit credentials in `RECORD`, `STATE`, or log output\n- keep transient request headers and tokens out of Singer state unless they are part of a durable resume strategy\n\nTypical config shape:\n\n```json\n{\n  \"api_token\": \"env-or-secret-manager-value\",\n  \"start_date\": \"2026-01-01T00:00:00Z\",\n  \"base_url\": \"https://api.example.com\"\n}\n```\n\n## Logging, Errors, And Output Hygiene\n\nUse `singer.get_logger()` and `@singer.utils.handle_top_exception(LOGGER)` for top-level error handling. That decorator logs each exception line at critical level and re-raises the error.\n\nImportant rule:\n\n- do not use plain `print()` for diagnostics in a tap or target unless you are deliberately writing Singer messages\n\nSinger messages belong on stdout. Operational logs, warnings, and tracebacks must stay off the data stream.\n\n## Common Pitfalls\n\n- `--config` must be JSON. `parse_args()` uses `json.load`, so YAML or dotenv files will fail unless your own wrapper converts them first.\n- `--properties` is deprecated. Prefer `--catalog` for field selection.\n- `metadata.get_standard_metadata(...)` returns a list form. Convert it with `metadata.to_map(...)` before passing it into `singer.transform(...)`.\n- `write_schema()` requires `key_properties` to be a string or list of strings. `bookmark_properties` follows the same expectation.\n- If you pass `time_extracted`, it must be a timezone-aware `datetime`.\n- Do not interleave log lines with Singer messages on stdout. That is one of the easiest ways to break downstream targets.\n- `singer.strptime()` is deprecated in the utility module. Prefer `singer.utils.strptime_to_utc(...)` or your own timezone-safe parsing.\n- `write_record()` does not expose the experimental `version` field. Use `RecordMessage` plus `write_message()` if you truly need versioned streams.\n\n## Version-Sensitive Notes\n\nFor installable `6.4.0`:\n\n- `clear_offset` behavior was updated in `6.4.0` to remove the offset key from the bookmark structure.\n- `allow_nan` support in message JSON output landed in `6.3.0`.\n- JSON schema generation landed in `6.2.0`, with several fixes in `6.2.1` through `6.2.3` for dates, empty arrays, `anyOf`, and non-standard data types.\n\nFor newer code that may be visible in the maintainer repo but not yet on PyPI:\n\n- `6.5.0`: `bookmarks.py` is deprecated and functions move to `state.py`; activate-version state helpers are added.\n- `6.6.0`: state helper functions are exported from `singer`, and `write_bookmark` is renamed to `set_bookmark` with a backward-compatible alias.\n- `6.7.0`: `set_version`, `get_version`, and `clear_version` remove the `key` parameter.\n- `6.8.0`: the state key `activate_versions` is renamed to `versions`.\n\nIf you are working against a project pin that really is newer than `6.4.0`, verify the installed package version before copying state-management examples from older taps.\n\n## Official Sources\n\n- Maintainer repository: `https://github.com/singer-io/singer-python`\n- Package registry: `https://pypi.org/project/singer-python/`\n- Singer specification context: `https://github.com/singer-io/getting-started`\n"
  },
  {
    "path": "content/six/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"six package guide for Python 2 and 3 compatibility helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.17.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"python,six,compatibility,python2,python3,stdlib\"\n---\n\n# six Python Package Guide\n\n## Golden Rule\n\nUse `six` only when the code must stay compatible across Python 2.7 and Python 3, or when an older dependency surface still expects `six` helpers. For Python 3-only code, prefer native Python 3 syntax and the standard library instead of adding new `six` usage.\n\n## Installation\n\n```bash\npip install six==1.17.0\n```\n\n```bash\nuv add six==1.17.0\n```\n\n```bash\npoetry add six==1.17.0\n```\n\n## Setup And Initialization\n\n`six` has no service initialization, credentials, or config files.\n\n```python\nimport six\nfrom six.moves import urllib_parse\n```\n\nNotes:\n\n- The package name and import name are both `six`.\n- Upstream documents `six` as a single Python file, so vendoring is possible if a project deliberately embeds it. Keep the license notice if you do that.\n\n## Core Usage\n\n### Runtime Compatibility Checks And Shared Types\n\nUse the built-in type tuples and flags instead of spelling out Python 2 and 3 branches yourself.\n\n```python\nimport six\n\ndef normalize_value(value):\n    if isinstance(value, six.string_types):\n        return six.ensure_text(value).strip()\n    if isinstance(value, six.integer_types):\n        return value\n    raise TypeError(\"unsupported value type\")\n\nif six.PY3:\n    mode = \"python3\"\nelse:\n    mode = \"python2\"\n```\n\nUseful helpers:\n\n- `six.string_types`, `six.text_type`, `six.binary_type`\n- `six.integer_types`, `six.class_types`\n- `six.PY2`, `six.PY3`\n\n### Text And Binary Normalization\n\nWhen code must behave the same across Python 2 and 3, normalize at the boundary.\n\n```python\nimport six\n\ndef to_wire_bytes(value):\n    return six.ensure_binary(value, encoding=\"utf-8\")\n\ndef to_text(value):\n    return six.ensure_text(value, encoding=\"utf-8\")\n\ndef to_native_str(value):\n    return six.ensure_str(value, encoding=\"utf-8\")\n```\n\nPractical guidance:\n\n- `ensure_binary()` returns `six.binary_type`\n- `ensure_text()` returns `six.text_type`\n- `ensure_str()` returns native `str`\n- Prefer explicit encoding arguments at I/O boundaries\n\n### Dictionary Iteration\n\nFor code that still has to run on Python 2 and Python 3, use the iterator helpers instead of version-specific methods.\n\n```python\nimport six\n\ndef serialize_headers(headers):\n    return {six.ensure_text(k): six.ensure_text(v) for k, v in six.iteritems(headers)}\n```\n\nCommon helpers:\n\n- `six.iteritems()`\n- `six.iterkeys()`\n- `six.itervalues()`\n- `six.viewitems()`, `six.viewkeys()`, `six.viewvalues()`\n\n### Standard-Library Renames With `six.moves`\n\n`six.moves` gives one import surface for stdlib modules that moved between Python 2 and 3.\n\n```python\nfrom six.moves import configparser, reload_module\nfrom six.moves.urllib.parse import urlencode\nfrom six.moves.urllib.request import urlopen\n\ndef fetch(url, params):\n    query = urlencode(params)\n    with urlopen(f\"{url}?{query}\") as response:\n        return response.read()\n```\n\nReach for `six.moves` for cases like:\n\n- `configparser`\n- `copyreg`\n- `html_parser`\n- `queue`\n- `urllib.parse`, `urllib.request`, `urllib.error`, `urllib.response`\n- `reload_module`\n\n### Metaclasses And Decorators\n\nIf a shared library must support both runtimes and still needs metaclasses, use the helpers instead of branching class syntax.\n\n```python\nimport six\n\nclass Meta(type):\n    pass\n\nclass Base(object):\n    pass\n\nclass Example(six.with_metaclass(Meta, Base)):\n    pass\n```\n\nAlso useful:\n\n- `six.add_metaclass()`\n- `six.wraps()`\n- `six.raise_from()`\n- `six.reraise()`\n\n## Config And Auth\n\n`six` does not define auth, environment variables, or global runtime configuration.\n\nAgent guidance:\n\n- There is nothing to initialize beyond importing the module.\n- Any configuration comes from the application code that uses `six`, not from `six` itself.\n\n## Common Pitfalls\n\n- Do not add new `six` dependencies to Python 3-only code unless you specifically need to preserve a shared compatibility layer. Most helpers only matter when maintaining cross-version code.\n- The Read the Docs site is still published as `six 1.15.0` even though PyPI's latest release is `1.17.0`. Treat the docs as the API reference, then check the changelog for deltas introduced after `1.15.0`.\n- `six.moves` uses lazy proxy modules in `sys.modules`. Code that blindly inspects every module object can trip over those proxies.\n- `six.u()` is only safe with ASCII literals on Python 2 because it does not know the source literal encoding.\n- Prefer importing the exact thing you need from `six.moves` instead of mixing direct Python-version-specific stdlib imports with `six` shims in the same module.\n\n## Version-Sensitive Notes For 1.17.0\n\n- `1.17.0` removed `URLopener` and `FancyURLopener` from `six.moves.urllib.request` when running on Python `3.14+`. Do not write new code against those classes.\n- `1.17.0` changed `six.moves.UserDict` on Python 2 to point at `UserDict.IterableUserDict` instead of `UserDict.UserDict`.\n- `1.16.0` previously updated `_SixMetaPathImporter` for Python `3.10`, so older blog posts about import-hook breakage may no longer apply.\n- `1.15.0` optimized `ensure_str()` and `ensure_binary()`, and the published docs site still reflects that doc build generation.\n\n## When To Reach For `six`\n\nUse `six` when:\n\n- a library still supports Python 2.7 and Python 3\n- a dependency or vendored codebase already uses `six`\n- you need `six.moves` imports instead of hand-written Python 2/3 import branches\n\nAvoid new `six` usage when:\n\n- the project is Python 3-only\n- standard library names already match your supported interpreter range\n- compatibility branches can be deleted rather than preserved\n\n## Official Sources\n\n- Docs: https://six.readthedocs.io/\n- PyPI: https://pypi.org/project/six/\n- Repository: https://github.com/benjaminp/six\n- Changelog: https://raw.githubusercontent.com/benjaminp/six/master/CHANGES\n"
  },
  {
    "path": "content/slack/docs/workspace/javascript/DOC.md",
    "content": "---\nname: workspace\ndescription: \"Slack Node SDK for building bots, handling workspace events, and messaging integrations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.12.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"slack,bot,workspace,messaging,events-api\"\n---\n\n# Slack Node SDK Examples\n\nExamples demonstrating the official Slack Node SDK packages for JavaScript/TypeScript applications.\n\n## Examples\n\n- **[example/](./example/)** - Production-Ready Slack Bot\n  - Socket Mode real-time events with WebSocket connection\n  - Message echo and pattern matching\n  - User info retrieval (`users.info`)\n  - Channel listing (`conversations.list`)\n  - Automatic token refresh with OAuth v2\n  - Auto-join channels on `not_in_channel` error\n  - Comprehensive error handling with retry logic\n  - Bot message filtering to prevent infinite loops\n  - App mention handling\n  - Environment variable validation\n  - Graceful shutdown handlers\n\n## Slack Node SDK Guidelines\n\n<cite>\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Slack Node SDK packages, which are the standard libraries for all Slack API interactions. Do not use legacy or deprecated packages.\n\n- **Primary Package:** `@slack/web-api` - Official library for using the Slack Platform's Web API\n- **OAuth Package:** `@slack/oauth` - For app installation and authentication flows  \n- **Socket Mode Package:** `@slack/socket-mode` - For real-time WebSocket connections\n- **Legacy/Deprecated Packages:** `@slack/events-api`, `@slack/interactive-messages`, `@slack/client` should not be used\n\n**Installation:**\n- **Correct:** `npm install @slack/web-api`\n- **Correct:** `npm install @slack/socket-mode @slack/oauth`\n- **Deprecated:** `npm install @slack/events-api` (End-of-Life as of May 31st, 2021)\n- **Deprecated:** `npm install @slack/interactive-messages` (End-of-Life as of May 31st, 2021)\n\n**APIs and Usage:**\n- **Correct:** `import { WebClient } from '@slack/web-api'`\n- **Correct:** `const web = new WebClient(token)`\n- **Correct:** `await web.chat.postMessage({ ... })`\n- **Correct:** `import { SocketModeClient } from '@slack/socket-mode'`\n- **Correct:** `import { InstallProvider } from '@slack/oauth'`\n\n## System Requirements\n\nThe Slack Node SDK requires:\n- Node.js v18 or higher\n- npm v8.6.0 or higher\n\n## Initialization and Authentication\n\n### Web API Client\n\nThe `@slack/web-api` package provides the `WebClient` class for all Web API interactions.\n\n```javascript\nimport { WebClient } from '@slack/web-api';\n\n// Initialize with bot token\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);\n\n// Or with user token\nconst web = new WebClient(process.env.SLACK_USER_TOKEN);\n```\n\n### Socket Mode Client\n\nFor real-time events without exposing public endpoints:\n\n```javascript\nimport { SocketModeClient } from '@slack/socket-mode';\n\nconst socketMode = new SocketModeClient({\n  appToken: process.env.SLACK_APP_TOKEN,\n  socketMode: true\n});\n```\n\n## Core API Methods\n\n### Sending Messages\n\n```javascript\nimport { WebClient } from '@slack/web-api';\n\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);\n\nasync function sendMessage() {\n  try {\n    const result = await web.chat.postMessage({\n      channel: 'C1234567890',\n      text: 'Hello world!',\n      blocks: [\n        {\n          type: 'section',\n          text: {\n            type: 'mrkdwn',\n            text: 'Hello *world*!'\n          }\n        }\n      ]\n    });\n    console.log(`Message sent: ${result.ts}`);\n  } catch (error) {\n    console.error('Error sending message:', error);\n  }\n}\n```\n\n### File Uploads\n\n```javascript\nimport { WebClient } from '@slack/web-api';\nimport fs from 'fs';\n\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);\n\nasync function uploadFile() {\n  try {\n    const result = await web.files.uploadV2({\n      channel_id: 'C1234567890',\n      file: fs.createReadStream('./document.pdf'),\n      filename: 'document.pdf',\n      initial_comment: 'Here is the document you requested.'\n    });\n    console.log('File uploaded:', result.file.id);\n  } catch (error) {\n    console.error('Error uploading file:', error);\n  }\n}\n```\n\n### Getting User Information\n\n```javascript\nasync function getUserInfo(userId) {\n  try {\n    const result = await web.users.info({\n      user: userId\n    });\n    return result.user;\n  } catch (error) {\n    console.error('Error getting user info:', error);\n  }\n}\n```\n\n### Listing Conversations\n\n```javascript\nasync function listChannels() {\n  try {\n    const result = await web.conversations.list({\n      types: 'public_channel,private_channel',\n      limit: 100\n    });\n    return result.channels;\n  } catch (error) {\n    console.error('Error listing channels:', error);\n  }\n}\n```\n\n## Socket Mode for Real-time Events\n\nSocket Mode enables real-time event handling without public endpoints. Always acknowledge events immediately.\n\n### Basic Setup\n\n```javascript\nimport { SocketModeClient } from '@slack/socket-mode';\nimport { WebClient } from '@slack/web-api';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\n// Validate required environment variables\nif (!process.env.SLACK_BOT_TOKEN || !process.env.SLACK_APP_TOKEN) {\n  console.error('Missing required tokens');\n  process.exit(1);\n}\n\nlet currentBotToken = process.env.SLACK_BOT_TOKEN;\nlet web = new WebClient(currentBotToken);\n\nconst socketMode = new SocketModeClient({\n  appToken: process.env.SLACK_APP_TOKEN\n});\n```\n\n### Message Event Handling\n\nFilter bot messages and handle app mentions properly:\n\n```javascript\nsocketMode.on('message', async ({ event, ack }) => {\n  try {\n    await ack(); // Always acknowledge first\n\n    // Skip bot messages and subtypes\n    if (event.type === 'message' && !event.bot_id && event.text && event.subtype !== 'bot_message') {\n      // Skip app mentions (handled by app_mention handler)\n      if (event.subtype === 'app_mention' || (event.text && event.text.match(/<@[A-Z0-9]+>/))) {\n        return;\n      }\n\n      console.log(`Message received: \"${event.text}\" from user: ${event.user}`);\n\n      // Process message\n      await web.chat.postMessage({\n        channel: event.channel,\n        text: `You said: \"${event.text}\"`\n      });\n    }\n  } catch (error) {\n    console.error('Error handling message event:', error);\n  }\n});\n```\n\n### App Mention Handling\n\n```javascript\nsocketMode.on('app_mention', async ({ event, ack }) => {\n  try {\n    await ack();\n\n    console.log(`App mention: \"${event.text}\" from user: ${event.user}`);\n\n    await web.chat.postMessage({\n      channel: event.channel,\n      text: `<@${event.user}> Hello!`\n    });\n  } catch (error) {\n    console.error('Error handling app mention:', error);\n  }\n});\n```\n\n### Error Handling and Startup\n\n```javascript\nsocketMode.on('error', (error) => {\n  console.error('Socket Mode error:', error);\n});\n\nasync function startBot() {\n  try {\n    console.log('Starting Slack bot...');\n\n    // Test authentication first\n    const auth = await web.auth.test();\n    console.log(`Connected as: ${auth.user} (${auth.team})`);\n\n    // Start socket mode\n    await socketMode.start();\n    console.log('Bot is running successfully!');\n  } catch (error) {\n    console.error('Error starting bot:', error);\n\n    if (error.data?.error === 'invalid_auth') {\n      console.error('Authentication failed. Check your SLACK_BOT_TOKEN.');\n    } else if (error.data?.error === 'token_expired') {\n      console.error('Token expired. Attempting refresh...');\n      // Implement token refresh logic here\n    }\n\n    process.exit(1);\n  }\n}\n\n// Graceful shutdown\nprocess.on('SIGINT', async () => {\n  console.log('Shutting down bot...');\n  await socketMode.disconnect();\n  process.exit(0);\n});\n\nprocess.on('SIGTERM', async () => {\n  console.log('Shutting down bot...');\n  await socketMode.disconnect();\n  process.exit(0);\n});\n\nstartBot();\n```\n\n## OAuth Installation Flow\n\n```javascript\nimport { InstallProvider } from '@slack/oauth';\nimport { WebClient } from '@slack/web-api';\n\nconst installer = new InstallProvider({\n  clientId: process.env.SLACK_CLIENT_ID,\n  clientSecret: process.env.SLACK_CLIENT_SECRET,\n  stateSecret: 'my-state-secret',\n  installationStore: {\n    storeInstallation: async (installation) => {\n      // Store installation data in your database\n      console.log('Installation:', installation);\n    },\n    fetchInstallation: async (installQuery) => {\n      // Fetch installation data from your database\n      return installation;\n    }\n  }\n});\n\n// Generate install URL\nconst installUrl = await installer.generateInstallUrl({\n  scopes: ['chat:write', 'channels:read'],\n  userScopes: ['chat:write']\n});\n\n// Handle OAuth callback\napp.get('/slack/oauth_redirect', async (req, res) => {\n  try {\n    const installation = await installer.handleCallback(req, res);\n    console.log('Installation successful:', installation);\n  } catch (error) {\n    console.error('OAuth error:', error);\n  }\n});\n```\n\n## Error Handling and Resilience\n\n### Basic Error Handling\n\nAll API responses follow a consistent structure:\n\n```javascript\nimport { WebClient } from '@slack/web-api';\n\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);\n\nasync function handleApiCall() {\n  try {\n    const result = await web.chat.postMessage({\n      channel: 'C1234567890',\n      text: 'Hello!'\n    });\n\n    if (result.ok) {\n      console.log('Success:', result.ts);\n    } else {\n      console.error('API Error:', result.error);\n    }\n  } catch (error) {\n    if (error.code === 'slack_webapi_platform_error') {\n      console.error('Slack API Error:', error.data);\n    } else {\n      console.error('Network/Other Error:', error);\n    }\n  }\n}\n```\n\n### Token Refresh Pattern\n\nImplement automatic token refresh for OAuth apps:\n\n```javascript\nimport fs from 'fs';\n\nasync function refreshBotToken() {\n  try {\n    console.log('Refreshing bot token...');\n    const response = await fetch('https://slack.com/api/oauth.v2.access', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n      },\n      body: new URLSearchParams({\n        client_id: process.env.SLACK_CLIENT_ID,\n        client_secret: process.env.SLACK_CLIENT_SECRET,\n        grant_type: 'refresh_token',\n        refresh_token: process.env.SLACK_BOT_REFRESH_TOKEN,\n      }),\n    });\n\n    const data = await response.json();\n\n    if (data.ok) {\n      currentBotToken = data.access_token;\n      web = new WebClient(currentBotToken);\n\n      // Update .env file with new token\n      const envContent = fs.readFileSync('.env', 'utf8');\n      const updatedContent = envContent.replace(\n        /SLACK_BOT_TOKEN=.*/,\n        `SLACK_BOT_TOKEN=${currentBotToken}`\n      );\n      fs.writeFileSync('.env', updatedContent);\n\n      console.log('Bot token refreshed successfully');\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error('Error refreshing token:', error);\n    return false;\n  }\n}\n```\n\n### Retry Pattern for Token Errors\n\nAutomatically retry API calls after token refresh:\n\n```javascript\nasync function sendMessage(channel, text) {\n  try {\n    const result = await web.chat.postMessage({\n      channel: channel,\n      text: text\n    });\n    console.log(`Message sent: ${text}`);\n    return result;\n  } catch (error) {\n    console.error('Error sending message:', error);\n\n    // Handle token-related errors with refresh and retry\n    if (error.data?.error === 'invalid_auth' ||\n        error.data?.error === 'token_revoked' ||\n        error.data?.error === 'token_expired') {\n      console.log('Token appears invalid, attempting refresh...');\n      const refreshed = await refreshBotToken();\n      if (refreshed) {\n        // Retry the message after token refresh\n        try {\n          const result = await web.chat.postMessage({\n            channel: channel,\n            text: text\n          });\n          console.log(`Message sent after token refresh: ${result.ts}`);\n          return result;\n        } catch (retryError) {\n          console.error('Failed to send message even after token refresh:', retryError);\n        }\n      }\n    }\n\n    throw error;\n  }\n}\n```\n\n### Auto-Join Channel Pattern\n\nHandle `not_in_channel` errors by joining automatically:\n\n```javascript\nasync function ensureBotInChannel(channel) {\n  try {\n    const result = await web.conversations.join({ channel });\n    if (result.ok) {\n      console.log(`Joined channel ${channel} before sending message`);\n      return true;\n    }\n  } catch (error) {\n    if (error.data?.error === 'already_in_channel') {\n      return true;\n    }\n    if (error.data?.error === 'method_not_supported_for_channel_type') {\n      console.warn(`Cannot join channel type for ${channel}; proceeding without join.`);\n    } else {\n      console.error('Error joining channel:', error);\n    }\n  }\n  return false;\n}\n\nasync function sendMessage(channel, text) {\n  try {\n    return await web.chat.postMessage({ channel, text });\n  } catch (error) {\n    // Handle not_in_channel error\n    if (error.data?.error === 'not_in_channel') {\n      console.log(`Bot is not in channel ${channel}, attempting to join...`);\n      const joined = await ensureBotInChannel(channel);\n      if (joined) {\n        try {\n          const result = await web.chat.postMessage({ channel, text });\n          console.log(`Message sent after joining channel: ${result.ts}`);\n          return result;\n        } catch (retryError) {\n          console.error('Failed to send message even after joining channel:', retryError);\n        }\n      }\n    }\n    throw error;\n  }\n}\n```\n\n### Combined Error Handling Pattern\n\nApply retry logic to all API methods:\n\n```javascript\nasync function getUserInfo(userId) {\n  try {\n    const result = await web.users.info({ user: userId });\n    return result.user;\n  } catch (error) {\n    console.error('Error getting user info:', error);\n\n    // Retry with token refresh if needed\n    if (error.data?.error === 'invalid_auth' ||\n        error.data?.error === 'token_revoked' ||\n        error.data?.error === 'token_expired') {\n      console.log('Token appears invalid, attempting refresh...');\n      const refreshed = await refreshBotToken();\n      if (refreshed) {\n        try {\n          const result = await web.users.info({ user: userId });\n          return result.user;\n        } catch (retryError) {\n          console.error('Failed to get user info even after token refresh:', retryError);\n        }\n      }\n    }\n  }\n}\n\nasync function listChannels() {\n  try {\n    const result = await web.conversations.list({\n      types: 'public_channel,private_channel',\n      limit: 100\n    });\n    return result.channels;\n  } catch (error) {\n    console.error('Error listing channels:', error);\n\n    // Retry with token refresh if needed\n    if (error.data?.error === 'invalid_auth' ||\n        error.data?.error === 'token_revoked' ||\n        error.data?.error === 'token_expired') {\n      console.log('Token appears invalid, attempting refresh...');\n      const refreshed = await refreshBotToken();\n      if (refreshed) {\n        try {\n          const result = await web.conversations.list({\n            types: 'public_channel,private_channel',\n            limit: 100\n          });\n          return result.channels;\n        } catch (retryError) {\n          console.error('Failed to list channels even after token refresh:', retryError);\n        }\n      }\n    }\n  }\n}\n```\n\n## Pagination\n\n```javascript\nasync function getAllChannels() {\n  const channels = [];\n  let cursor;\n  \n  do {\n    const result = await web.conversations.list({\n      types: 'public_channel,private_channel',\n      limit: 200,\n      cursor: cursor\n    });\n    \n    channels.push(...result.channels);\n    cursor = result.response_metadata?.next_cursor;\n  } while (cursor);\n  \n  return channels;\n}\n```\n\n## Rate Limiting\n\nThe SDK automatically handles rate limiting with built-in retry logic:\n\n```javascript\nimport { WebClient } from '@slack/web-api';\n\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN, {\n  retryConfig: {\n    retries: 3,\n    factor: 2\n  }\n});\n```\n\n## TypeScript Support\n\nThe SDK includes full TypeScript definitions:\n\n```typescript\nimport { WebClient, ChatPostMessageResponse } from '@slack/web-api';\n\nconst web = new WebClient(process.env.SLACK_BOT_TOKEN);\n\nasync function sendTypedMessage(): Promise<ChatPostMessageResponse> {\n  return await web.chat.postMessage({\n    channel: 'C1234567890',\n    text: 'Hello TypeScript!'\n  });\n}\n```\n\n## Webhook Usage\n\n```javascript\nimport { IncomingWebhook } from '@slack/webhook';\n\nconst webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL);\n\nasync function sendWebhookMessage() {\n  await webhook.send({\n    text: 'Hello from webhook!',\n    attachments: [\n      {\n        color: 'good',\n        text: 'This is an attachment'\n      }\n    ]\n  });\n}\n```\n\n## Block Kit Messages\n\n```javascript\nasync function sendRichMessage() {\n  await web.chat.postMessage({\n    channel: 'C1234567890',\n    blocks: [\n      {\n        type: 'header',\n        text: {\n          type: 'plain_text',\n          text: 'Welcome!'\n        }\n      },\n      {\n        type: 'section',\n        text: {\n          type: 'mrkdwn',\n          text: 'This is a *rich* message with buttons.'\n        },\n        accessory: {\n          type: 'button',\n          text: {\n            type: 'plain_text',\n            text: 'Click Me'\n          },\n          action_id: 'button_click'\n        }\n      }\n    ]\n  });\n}\n```\n\n## Production Best Practices\n\n### Environment Variable Validation\n\nAlways validate required environment variables at startup:\n\n```javascript\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\n// Validate required environment variables\nif (!process.env.SLACK_BOT_TOKEN) {\n  console.error('❌ SLACK_BOT_TOKEN is required. Please check your .env file.');\n  process.exit(1);\n}\n\nif (!process.env.SLACK_APP_TOKEN) {\n  console.error('❌ SLACK_APP_TOKEN is required. Please check your .env file.');\n  process.exit(1);\n}\n```\n\n### Token Management\n\nUse mutable references for tokens that may need refreshing:\n\n```javascript\nlet currentBotToken = process.env.SLACK_BOT_TOKEN;\nlet web = new WebClient(currentBotToken);\n\n// After refresh, reassign both:\ncurrentBotToken = data.access_token;\nweb = new WebClient(currentBotToken);\n```\n\n### Comprehensive Startup Flow\n\nTest authentication before starting Socket Mode:\n\n```javascript\nasync function startBot() {\n  try {\n    console.log('🤖 Starting Slack bot...');\n\n    // Test authentication first\n    console.log('🔐 Testing authentication...');\n    const auth = await web.auth.test();\n    console.log(`✅ Connected as: ${auth.user} (${auth.team})`);\n\n    // Start socket mode connection\n    console.log('🔌 Starting Socket Mode connection...');\n    await socketMode.start();\n\n    console.log('🚀 Bot is running successfully!');\n    console.log('📝 Available commands:');\n    console.log('   - Send messages containing: \"hello\", \"info\", \"channels\"');\n    console.log('   - Mention the bot in any channel');\n\n  } catch (error) {\n    console.error('❌ Error starting bot:', error);\n\n    // Provide helpful error messages based on error type\n    if (error.data?.error === 'invalid_auth') {\n      console.error('🔑 Authentication failed. Please check your SLACK_BOT_TOKEN.');\n    } else if (error.data?.error === 'token_revoked') {\n      console.error('🔑 Token has been revoked. Please generate a new SLACK_BOT_TOKEN.');\n    } else if (error.data?.error === 'token_expired') {\n      console.error('🔑 Token has expired. Attempting to refresh...');\n      const refreshed = await refreshBotToken();\n      if (refreshed) {\n        console.log('✅ Token refreshed successfully. Restarting bot...');\n        return startBot(); // Restart with new token\n      }\n    } else if (error.message?.includes('invalid_app_token')) {\n      console.error('🔑 Invalid app token. Please check your SLACK_APP_TOKEN.');\n    } else if (error.code === 'ENOTFOUND') {\n      console.error('🌐 Network error. Please check your internet connection.');\n    }\n\n    console.log('\\n💡 Make sure you have:');\n    console.log('   1. Created a .env file with valid tokens');\n    console.log('   2. Enabled Socket Mode in your Slack app');\n    console.log('   3. Added the required OAuth scopes');\n\n    process.exit(1);\n  }\n}\n\nstartBot();\n```\n\n### Graceful Shutdown Handlers\n\nAlways disconnect Socket Mode cleanly:\n\n```javascript\nprocess.on('SIGINT', async () => {\n  console.log('\\nShutting down bot...');\n  await socketMode.disconnect();\n  process.exit(0);\n});\n\nprocess.on('SIGTERM', async () => {\n  console.log('\\nShutting down bot...');\n  await socketMode.disconnect();\n  process.exit(0);\n});\n```\n\n### Message Filtering Best Practices\n\nPrevent infinite loops and duplicate processing:\n\n```javascript\nsocketMode.on('message', async ({ event, ack }) => {\n  try {\n    await ack(); // Always acknowledge first\n\n    // Filter out bot messages, subtypes, and app mentions\n    if (event.type === 'message' &&\n        !event.bot_id &&\n        event.text &&\n        event.subtype !== 'bot_message') {\n\n      // Skip app mentions (handled by app_mention handler)\n      if (event.subtype === 'app_mention' ||\n          (event.text && event.text.match(/<@[A-Z0-9]+>/))) {\n        return;\n      }\n\n      // Process the message\n      // ...\n    }\n  } catch (error) {\n    console.error('Error handling message event:', error);\n  }\n});\n```\n\n### Error Recovery Strategies\n\nImplement comprehensive error recovery:\n\n```javascript\nasync function sendMessage(channel, text) {\n  try {\n    const result = await web.chat.postMessage({\n      channel: channel,\n      text: text\n    });\n    console.log(`Message sent: ${text}`);\n    return result;\n  } catch (error) {\n    console.error('Error sending message:', error);\n\n    // 1. Handle token errors\n    if (error.data?.error === 'invalid_auth' ||\n        error.data?.error === 'token_revoked' ||\n        error.data?.error === 'token_expired') {\n      const refreshed = await refreshBotToken();\n      if (refreshed) {\n        return await web.chat.postMessage({ channel, text });\n      }\n    }\n    // 2. Handle channel access errors\n    else if (error.data?.error === 'not_in_channel') {\n      const joined = await ensureBotInChannel(channel);\n      if (joined) {\n        return await web.chat.postMessage({ channel, text });\n      }\n    }\n\n    // Don't try to send error messages for auth/channel errors\n    if (!['invalid_auth', 'token_revoked', 'token_expired', 'not_in_channel'].includes(error.data?.error)) {\n      try {\n        await web.chat.postMessage({\n          channel: channel,\n          text: `⚠️ Error occurred: ${error.message}`\n        });\n      } catch (secondError) {\n        console.error('Failed to send error message to channel:', secondError);\n      }\n    }\n\n    throw error;\n  }\n}\n```\n\n## Notes\n\nThe Slack Node SDK is modular and designed for specific use cases. <cite/> The `@slack/web-api` package is the primary interface for most Slack API interactions, while `@slack/socket-mode` enables real-time communication without exposing public endpoints. <cite/> Legacy packages like `@slack/events-api` and `@slack/interactive-messages` reached End-of-Life on May 31st, 2021 and should be migrated to Socket Mode or the Bolt framework. <cite/> The SDK includes comprehensive TypeScript support and handles rate limiting, retries, and pagination automatically. <cite/>\n\nWiki pages you might want to explore:\n- [Overview (slackapi/node-slack-sdk)](/wiki/slackapi/node-slack-sdk#1)\n\n### Citations\n\n```json\n  \"name\": \"@slack/web-api\",\n  \"version\": \"7.9.2\",\n  \"description\": \"Official library for using the Slack Platform's Web API\",\n```\n\n```json\n  \"types\": \"./dist/index.d.ts\",\n```\n\n```json\n  \"engines\": {\n    \"node\": \">= 18\",\n    \"npm\": \">= 8.6.0\"\n  },\n```\n\n```json\n  \"version\": \"2.0.2\",\n  \"description\": \"Official library for using the Slack Platform's Interactive Buttons, Menus, Dialogs, Actions, and Block Actions\",\n  \"author\": \"Slack Technologies, LLC\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"slack\",\n    \"interactive\",\n    \"interactive-messages\",\n    \"interactive-components\",\n    \"dialog\",\n    \"button\",\n    \"menu\",\n    \"action\",\n    \"block-kit\",\n    \"block-actions\",\n    \"bot\",\n    \"server\",\n    \"http\",\n    \"api\",\n    \"verify\",\n    \"signature\",\n    \"request-signing\"\n  ],\n```\n\n```typescript\nimport type { WebAPICallResult } from '../../WebClient';\nexport type AuthTeamsListResponse = WebAPICallResult & {\n  error?: string;\n  needed?: string;\n  ok?: boolean;\n  provided?: string;\n  response_metadata?: ResponseMetadata;\n  teams?: Team[];\n};\n```\n"
  },
  {
    "path": "content/slack/docs/workspace/python/DOC.md",
    "content": "---\nname: workspace\ndescription: \"Slack Python SDK for building Slack apps, bots, and workspace integrations\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.37.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"slack,bot,workspace,messaging,events-api\"\n---\n\n# Slack Python SDK Coding Guidelines\n\nYou are a Slack SDK coding expert. Help me with writing code using the Slack\nPython SDK for building Slack apps and integrations.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://docs.slack.dev/tools/python-slack-sdk/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Slack Python SDK (`slack_sdk`) for all Slack integrations. Do not use the legacy `slackclient` library which is in maintenance mode.\n\n- **Library Name:** Slack Python SDK\n- **Python Package:** `slack_sdk`\n- **Legacy Library:** `slackclient` is deprecated and in maintenance mode\n\n**Installation:**\n\n- **Incorrect:** `pip install slackclient`\n- **Correct:** `pip install slack_sdk`\n\n**APIs and Usage:**\n\n- **Incorrect:** `from slackclient import SlackClient` -> **Correct:** `from slack_sdk import WebClient`\n- **Incorrect:** `import slackclient` -> **Correct:** `import slack_sdk`\n- **Incorrect:** `from slack_sdk.web_client import WebClient` -> **Correct:** `from slack_sdk import WebClient`\n- **Incorrect:** `from slack_sdk.errors import SlackApiError` -> **Correct:** `from slack_sdk.errors import SlackApiError`\n\n## Initialization and Authentication\n\nThe `slack_sdk` library supports multiple authentication methods. For Web API calls, always use the `WebClient` class.\n\n- Always use `client = WebClient(token='your-token')` to create a client object\n- Set `SLACK_BOT_TOKEN` or `SLACK_API_TOKEN` environment variable for security\n- Use Bot User OAuth tokens (`xoxb-*`) for most integrations\n- Use User tokens (`xoxp-*`) only when user-specific actions are required\n\n## Basic Web API Usage\n\nHere's how to send a message to Slack using the Web API:\n\n```python\nimport os\nfrom slack_sdk import WebClient\nfrom slack_sdk.errors import SlackApiError\n\nclient = WebClient(token=os.environ['SLACK_BOT_TOKEN'])\n\ntry:\n    response = client.chat_postMessage(channel='#general', text=\"Hello world!\")\n    assert response[\"ok\"]\nexcept SlackApiError as e:\n    print(f\"Error posting message: {e.response['error']}\")\n```\n\n## File Uploads\n\nFor uploading files to Slack, use the `files_upload_v2` method:\n\n```python\nimport os\nfrom slack_sdk import WebClient\nfrom slack_sdk.errors import SlackApiError\n\nclient = WebClient(token=os.environ['SLACK_BOT_TOKEN'])\n\ntry:\n    response = client.files_upload_v2(\n        channel='C0123456789',\n        file='./document.pdf',\n        title='Document Upload'\n    )\n    assert response[\"file\"]\nexcept SlackApiError as e:\n    print(f\"Error uploading file: {e.response['error']}\")\n```\n\n## Async Usage\n\nFor asynchronous operations, use `AsyncWebClient`:\n\n```python\nimport asyncio\nimport os\nfrom slack_sdk.web.async_client import AsyncWebClient\nfrom slack_sdk.errors import SlackApiError\n\nclient = AsyncWebClient(token=os.environ['SLACK_BOT_TOKEN'])\n\nasync def post_message():\n    try:\n        response = await client.chat_postMessage(\n            channel='#general', \n            text=\"Hello from async!\"\n        )\n        assert response[\"ok\"]\n    except SlackApiError as e:\n        print(f\"Error: {e.response['error']}\")\n\nasyncio.run(post_message())\n```\n\n## Block Kit and Rich Messages\n\nUse Block Kit to create rich, interactive messages:\n\n```python\nfrom slack_sdk import WebClient\nfrom slack_sdk.models.blocks import SectionBlock, DividerBlock, ActionsBlock\nfrom slack_sdk.models.block_elements import ButtonElement\n\nclient = WebClient(token=os.environ['SLACK_BOT_TOKEN'])\n\nblocks = [\n    SectionBlock(text=\"Hello from Block Kit!\"),\n    DividerBlock(),\n    ActionsBlock(elements=[\n        ButtonElement(text=\"Click me\", action_id=\"button_click\")\n    ])\n]\n\nresponse = client.chat_postMessage(\n    channel='#general',\n    text=\"Fallback text\",\n    blocks=blocks\n)\n```\n\n## Error Handling\n\nAlways handle `SlackApiError` exceptions for robust error handling:\n\n```python\nfrom slack_sdk import WebClient\nfrom slack_sdk.errors import SlackApiError\n\nclient = WebClient(token=os.environ['SLACK_BOT_TOKEN'])\n\ntry:\n    response = client.chat_postMessage(channel='#general', text=\"Hello!\")\nexcept SlackApiError as e:\n    if e.response[\"error\"] == \"channel_not_found\":\n        print(\"Channel does not exist\")\n    elif e.response[\"error\"] == \"invalid_auth\":\n        print(\"Invalid token\")\n    else:\n        print(f\"Slack API Error: {e.response['error']}\")\n    print(f\"Status code: {e.response.status_code}\")\n```\n\n## Webhooks\n\nFor simple webhook-based integrations:\n\n```python\nfrom slack_sdk.webhook import WebhookClient\n\nwebhook = WebhookClient(\"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX\")\n\nresponse = webhook.send(\n    text=\"Hello from webhook!\",\n    blocks=[\n        {\n            \"type\": \"section\",\n            \"text\": {\"type\": \"mrkdwn\", \"text\": \"Hello from webhook!\"}\n        }\n    ]\n)\n```\n\n## Socket Mode (Real-time Events)\n\nFor real-time event handling using Socket Mode:\n\n```python\nimport os\nfrom slack_sdk.socket_mode import SocketModeClient\nfrom slack_sdk import WebClient\n\ndef process_event(client: SocketModeClient, req):\n    if req.type == \"events_api\":\n        # Handle events here\n        client.send_socket_mode_response(req.envelope_id)\n\nsocket_client = SocketModeClient(\n    app_token=os.environ[\"SLACK_APP_TOKEN\"],\n    web_client=WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n)\n\nsocket_client.socket_mode_request_listeners.append(process_event)\nsocket_client.connect()\n```\n\n## Available SDK Modules\n\nThe Python Slack SDK provides several specialized modules:\n\n- `slack_sdk.web`: Web API client for most Slack API interactions\n- `slack_sdk.webhook`: Webhook client for incoming webhooks\n- `slack_sdk.socket_mode`: Socket Mode client for real-time events\n- `slack_sdk.oauth`: OAuth flow implementation\n- `slack_sdk.audit_logs`: Audit Logs API client\n- `slack_sdk.scim`: SCIM API client for user management\n- `slack_sdk.models`: Block Kit and message models\n- `slack_sdk.signature`: Request signature verification\n\n## Advanced Configuration\n\nConfigure SSL, proxies, and other advanced options:\n\n```python\nimport ssl\nfrom slack_sdk import WebClient\n\nssl_context = ssl.create_default_context()\nproxy = \"http://proxy.company.com:8080\"\n\nclient = WebClient(\n    token=os.environ['SLACK_BOT_TOKEN'],\n    ssl=ssl_context,\n    proxy=proxy,\n    timeout=60\n)\n```\n\n## Migration from Legacy Libraries\n\nIf migrating from `slackclient` v1 or v2:\n- Replace `slackclient` imports with `slack_sdk`\n- Update authentication patterns to use `WebClient(token=...)`\n- Review method signatures as some parameters may have changed\n- Update error handling to use `SlackApiError`\n\n## Best Practices\n\n1. **Always handle errors**: Use try/except blocks with `SlackApiError`\n2. **Use environment variables**: Store tokens securely in environment variables\n3. **Validate responses**: Check `response[\"ok\"]` before processing results\n4. **Use appropriate token types**: Bot tokens for bot actions, user tokens only when necessary\n5. **Implement rate limiting**: Be aware of Slack's rate limits and implement backoff strategies\n6. **Use Block Kit**: Prefer Block Kit over legacy attachments for rich messages\n\n## Requirements\n\n- Python 3.9 or higher\n- For async usage: Install with `pip install slack_sdk[optional]` for performance improvements\n\n## Useful Links\n\n- Documentation: https://docs.slack.dev/tools/python-slack-sdk/\n- API Methods: https://api.slack.com/methods\n- Block Kit Builder: https://app.slack.com/block-kit-builder/\n- GitHub Issues: https://github.com/slackapi/python-slack-sdk/issues\n- Slack Community: https://slackcommunity.com/\n\n## Notes\n\nThis SDK is the official and recommended way to interact with Slack APIs from Python. Always use the latest version and refer to the official documentation for the most up-to-date examples and best practices. For building full Slack apps with event handling, consider using the Bolt for Python framework which builds on top of this SDK.\n"
  },
  {
    "path": "content/slack-sdk/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Slack Python SDK for Web API calls, webhooks, OAuth installs, Socket Mode, and request verification\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.40.1,3.41.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"slack,slack-sdk,python,chat,web-api,oauth,webhooks,socket-mode\"\n---\n\n# Slack Python SDK Package Guide\n\n## Golden Rule\n\nUse `slack-sdk` from PyPI, import it as `slack_sdk`, and choose the client that matches the integration shape:\n\n- `WebClient` for Slack Web API calls\n- `AsyncWebClient` for async code\n- `WebhookClient` for incoming webhooks and `response_url`\n- `SocketModeClient` for WebSocket-based app connections\n\nDo not start from the deprecated `slack` / `slackclient` package. The current package is `slack-sdk`, and most current examples should use `slack_sdk.*` imports.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"slack-sdk==3.40.1\"\n```\n\nIf you want the latest current patch validated during this session:\n\n```bash\npython -m pip install \"slack-sdk==3.41.0\"\n```\n\nIf you use async clients, install `aiohttp` explicitly:\n\n```bash\npython -m pip install \"slack-sdk==3.40.1\" aiohttp\n```\n\nFor Socket Mode with alternate transports, add the corresponding library yourself:\n\n```bash\npython -m pip install \"slack-sdk==3.40.1\" websocket-client\npython -m pip install \"slack-sdk==3.40.1\" aiohttp\npython -m pip install \"slack-sdk==3.40.1\" websockets\n```\n\n## Authentication And Setup\n\n### Token types you will actually use\n\n- Bot token: starts with `xoxb-`; the usual token for `WebClient`\n- User token: starts with `xoxp-`; use only when a method must act as a user\n- App-level token: starts with `xapp-`; required for Socket Mode connections\n- Signing secret: used to verify inbound HTTP requests from Slack\n\nCommon environment variables:\n\n```bash\nexport SLACK_BOT_TOKEN=\"xoxb-...\"\nexport SLACK_APP_TOKEN=\"xapp-...\"\nexport SLACK_SIGNING_SECRET=\"...\"\nexport SLACK_CLIENT_ID=\"...\"\nexport SLACK_CLIENT_SECRET=\"...\"\n```\n\n### Single-workspace install\n\nFor an internal app installed to one workspace, install the app from the Slack app settings and keep the bot token in environment variables or a secret manager.\n\n```python\nimport os\nfrom slack_sdk import WebClient\n\nclient = WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n```\n\n### Multi-workspace OAuth\n\nFor distributed apps, start the OAuth flow at `https://slack.com/oauth/v2/authorize`, then exchange the returned `code` with `oauth_v2_access`.\n\n```python\nimport os\nfrom slack_sdk import WebClient\n\nclient = WebClient()\n\noauth_response = client.oauth_v2_access(\n    client_id=os.environ[\"SLACK_CLIENT_ID\"],\n    client_secret=os.environ[\"SLACK_CLIENT_SECRET\"],\n    code=\"temporary-code-from-redirect\",\n)\n\nbot_token = oauth_response[\"access_token\"]\n```\n\nIf you enable token rotation, Slack access tokens expire every 12 hours and must be refreshed with the rotation flow. Bolt handles this more conveniently than raw SDK code.\n\n## Core Usage\n\n### Send a message with `WebClient`\n\nUse channel IDs when possible. If the bot is not in the target channel, Slack will typically return `not_in_channel` or `channel_not_found` unless you have `chat:write.public` for public channels.\n\n```python\nimport os\nfrom slack_sdk import WebClient\nfrom slack_sdk.errors import SlackApiError\n\nclient = WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n\ntry:\n    response = client.chat_postMessage(\n        channel=\"C0123456789\",\n        text=\"Deployment finished successfully.\",\n    )\n    print(response[\"ts\"])\nexcept SlackApiError as exc:\n    print(exc.response[\"error\"])\n    raise\n```\n\n### Upload a file\n\nUse `files_upload_v2` in current examples:\n\n```python\nimport os\nfrom slack_sdk import WebClient\n\nclient = WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n\nclient.files_upload_v2(\n    channel=\"C0123456789\",\n    file=\"./build.log\",\n    title=\"Build log\",\n)\n```\n\n### Read workspace data\n\nMost workspace reads are direct Web API wrappers with Pythonic method names:\n\n```python\nimport os\nfrom slack_sdk import WebClient\n\nclient = WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n\ninfo = client.conversations_info(\n    channel=\"C0123456789\",\n    include_num_members=True,\n)\n\nprint(info[\"channel\"][\"name\"])\n```\n\n### Use `AsyncWebClient`\n\n`AsyncWebClient` requires `aiohttp` and should be used only inside an async application.\n\n```python\nimport os\nimport asyncio\nfrom slack_sdk.web.async_client import AsyncWebClient\n\nclient = AsyncWebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\n\nasync def main() -> None:\n    response = await client.chat_postMessage(\n        channel=\"C0123456789\",\n        text=\"Hello from async code.\",\n    )\n    print(response[\"ts\"])\n\nasyncio.run(main())\n```\n\n### Send via incoming webhook or `response_url`\n\nUse `WebhookClient` when you already have a webhook URL or a `response_url` from a slash command or interactive payload.\n\n```python\nfrom slack_sdk.webhook import WebhookClient\n\nwebhook = WebhookClient(\"https://hooks.slack.com/services/...\")\nwebhook.send(text=\"Build completed.\")\n```\n\n### Verify inbound Slack requests\n\nWhen handling slash commands, interactivity, or Events API callbacks over HTTP, verify the request before processing it. Use the raw request body and original headers, not a reconstructed JSON body.\n\n```python\nimport os\nfrom flask import Flask, request, abort\nfrom slack_sdk.signature import SignatureVerifier\n\napp = Flask(__name__)\nsignature_verifier = SignatureVerifier(os.environ[\"SLACK_SIGNING_SECRET\"])\n\n@app.post(\"/slack/events\")\ndef slack_events():\n    body = request.get_data()\n    if not signature_verifier.is_valid_request(body, request.headers):\n        abort(401)\n    return \"\", 200\n```\n\n### Use Socket Mode\n\nSocket Mode requires both:\n\n- `SLACK_APP_TOKEN` with `connections:write`\n- a Web API token such as `SLACK_BOT_TOKEN`\n\n```python\nimport os\nfrom threading import Event\nfrom slack_sdk.web import WebClient\nfrom slack_sdk.socket_mode import SocketModeClient\nfrom slack_sdk.socket_mode.request import SocketModeRequest\nfrom slack_sdk.socket_mode.response import SocketModeResponse\n\nclient = SocketModeClient(\n    app_token=os.environ[\"SLACK_APP_TOKEN\"],\n    web_client=WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"]),\n)\n\ndef process(socket_client: SocketModeClient, req: SocketModeRequest) -> None:\n    if req.type == \"events_api\":\n        socket_client.send_socket_mode_response(\n            SocketModeResponse(envelope_id=req.envelope_id)\n        )\n\nclient.socket_mode_request_listeners.append(process)\nclient.connect()\nEvent().wait()\n```\n\nIf you use `slack_sdk.socket_mode.aiohttp.SocketModeClient` or `slack_sdk.socket_mode.websockets.SocketModeClient`, keep the transport library installed and pair it with `AsyncWebClient`.\n\n## Configuration Notes\n\n### Retries and rate limits\n\nThe default client only enables a connection-error retry handler. If you want automatic retries for Slack rate limits (`HTTP 429`), add `RateLimitErrorRetryHandler` yourself.\n\n```python\nimport os\nfrom slack_sdk.web import WebClient\nfrom slack_sdk.http_retry.builtin_handlers import RateLimitErrorRetryHandler\n\nclient = WebClient(token=os.environ[\"SLACK_BOT_TOKEN\"])\nclient.retry_handlers.append(RateLimitErrorRetryHandler(max_retry_count=1))\n```\n\n### Secrets handling\n\n- Keep tokens and signing secrets out of source control.\n- Prefer environment variables or a secret manager.\n- If you support OAuth installations across many workspaces, persist installations in your own store instead of keeping tokens only in process memory.\n\n### When to use Bolt instead\n\n`slack-sdk` is the right package when you want direct API clients and low-level control. If you are building a full Slack app with slash commands, Events API listeners, interactivity, OAuth persistence, or token rotation, `slack-bolt` is often the better top-level framework and still uses this SDK underneath.\n\n## Common Pitfalls\n\n- The PyPI project is `slack-sdk`, but the import package is `slack_sdk`. Old `import slack` examples are migration leftovers.\n- `slackclient` is in maintenance mode. Do not add new code against it.\n- Async support is not bundled automatically in v3. Install `aiohttp` yourself before using `AsyncWebClient`, `AsyncWebhookClient`, or asyncio-based Socket Mode clients.\n- Verify Slack signatures against the raw request body before deserializing it. Reading parsed JSON first can break signature validation.\n- Socket Mode needs an app-level `xapp-` token for the connection and a bot or user token for API calls. One token is not enough.\n- Prefer channel IDs over channel names. Names can be ambiguous or change.\n- A bot must usually be in the channel to post there unless the app has the appropriate public-posting scope.\n- Use `WebhookClient` only for webhook URLs or `response_url`. For normal Web API methods, use `WebClient`.\n\n## Version-Sensitive Notes\n\n- As of Thursday, March 12, 2026, PyPI lists `3.41.0` as the latest release, while the initial package metadata was `3.40.1` from Tuesday, February 18, 2026.\n- The current Slack docs still describe Python `3.7+` support and the same client surface used here.\n- Since SDK v3, the project name is `slack_sdk` / `slack-sdk`, not `slackclient`, and async-related dependencies are no longer installed automatically.\n- Current docs and PyPI examples use `files_upload_v2`; prefer that over older file-upload examples.\n"
  },
  {
    "path": "content/slowapi/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SlowAPI rate limiting for FastAPI and Starlette applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.1.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"slowapi,python,fastapi,starlette,rate-limiting,redis\"\n---\n\n# SlowAPI Python Package Guide\n\n## Golden Rule\n\nUse `slowapi` as request-time middleware and decorators inside a FastAPI or Starlette app. The limiter only works when your endpoint signature and decorator order match the package's documented requirements.\n\n`slowapi` 0.1.9 supports Python `>=3.7,<4.0` and ships an optional `redis` extra.\n\n## Install\n\nInstall the package version your app expects:\n\n```bash\npython -m pip install \"slowapi==0.1.9\"\n```\n\nIf you want Redis-backed limits instead of in-memory storage:\n\n```bash\npython -m pip install \"slowapi[redis]==0.1.9\"\n```\n\nOptional environment variables for a Redis-backed setup:\n\n```env\nREDIS_URL=redis://localhost:6379/0\n```\n\n## FastAPI Setup\n\nCreate one `Limiter`, attach it to `app.state`, and register the built-in 429 handler:\n\n```python\nimport os\n\nfrom fastapi import FastAPI, Request, Response\nfrom slowapi import Limiter, _rate_limit_exceeded_handler\nfrom slowapi.errors import RateLimitExceeded\nfrom slowapi.util import get_remote_address\n\nlimiter = Limiter(\n    key_func=get_remote_address,\n    headers_enabled=True,\n    storage_uri=os.getenv(\"REDIS_URL\"),\n)\n\napp = FastAPI()\napp.state.limiter = limiter\napp.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)\n\n\n@app.get(\"/health\")\n@limiter.limit(\"5/minute\")\nasync def healthcheck(request: Request) -> dict[str, str]:\n    return {\"status\": \"ok\"}\n\n\n@app.get(\"/items/{item_id}\")\n@limiter.limit(\"30/minute\")\nasync def read_item(\n    request: Request,\n    response: Response,\n    item_id: str,\n) -> dict[str, str]:\n    return {\"item_id\": item_id}\n```\n\nTwo details matter:\n\n- The route decorator must be above `@limiter.limit(...)`.\n- `request: Request` must be in the endpoint signature or SlowAPI cannot check the limit.\n\nIf you enable `headers_enabled=True` and return a plain dict that FastAPI turns into a response later, include `response: Response` in the function signature so SlowAPI can write the rate-limit headers.\n\n## Starlette Setup\n\nThe same initialization pattern works for Starlette:\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.requests import Request\nfrom starlette.responses import PlainTextResponse\n\nfrom slowapi import Limiter, _rate_limit_exceeded_handler\nfrom slowapi.errors import RateLimitExceeded\nfrom slowapi.util import get_remote_address\n\nlimiter = Limiter(key_func=get_remote_address)\n\napp = Starlette()\napp.state.limiter = limiter\napp.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)\n\n\n@limiter.limit(\"5/minute\")\nasync def homepage(request: Request) -> PlainTextResponse:\n    return PlainTextResponse(\"ok\")\n\n\napp.add_route(\"/\", homepage)\n```\n\n## Common Workflows\n\n### Add a per-route limit\n\nUse `limit()` on individual endpoints:\n\n```python\n@app.get(\"/login\")\n@limiter.limit(\"10/minute\")\nasync def login(request: Request, response: Response) -> dict[str, str]:\n    return {\"result\": \"allowed\"}\n```\n\n`limit()` also supports `methods`, `per_method`, `error_message`, `exempt_when`, and `override_defaults`.\n\n### Share one limit across multiple routes\n\nUse `shared_limit()` when several endpoints should draw from the same bucket:\n\n```python\nshared_search_limit = limiter.shared_limit(\"20/minute\", scope=\"search\")\n\n\n@app.get(\"/search\")\n@shared_search_limit\nasync def search(request: Request) -> dict[str, str]:\n    return {\"route\": \"search\"}\n\n\n@app.get(\"/search/advanced\")\n@shared_search_limit\nasync def advanced_search(request: Request) -> dict[str, str]:\n    return {\"route\": \"advanced\"}\n```\n\n### Apply default global limits\n\nFor app-wide defaults, configure `default_limits` and add the SlowAPI middleware:\n\n```python\nfrom slowapi.middleware import SlowAPIMiddleware\n\nlimiter = Limiter(\n    key_func=get_remote_address,\n    default_limits=[\"100/minute\"],\n)\n\napp = FastAPI()\napp.state.limiter = limiter\napp.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)\napp.add_middleware(SlowAPIMiddleware)\n```\n\nRoutes can opt out:\n\n```python\n@app.get(\"/metrics\")\n@limiter.exempt\nasync def metrics(request: Request) -> dict[str, bool]:\n    return {\"ok\": True}\n```\n\nIf you want a route-specific limit in addition to the defaults instead of replacing them, set `override_defaults=False`.\n\n### Disable limiting entirely\n\nThis is useful in tests or local development:\n\n```python\nlimiter = Limiter(key_func=get_remote_address, enabled=False)\n```\n\nYou can also toggle it later:\n\n```python\nlimiter.enabled = False\n```\n\n## Storage And Client Identity\n\nBy default, SlowAPI can use in-memory storage. For multi-process or multi-instance deployments, use a shared backend such as Redis:\n\n```python\nlimiter = Limiter(\n    key_func=get_remote_address,\n    storage_uri=\"redis://localhost:6379/0\",\n    headers_enabled=True,\n)\n```\n\nThe utility functions differ:\n\n- `get_remote_address(request)` uses the request's client address.\n- `get_ipaddr(request)` reads `X-Forwarded-For`; the API reference notes that Uvicorn's `ProxyHeadersMiddleware` is a more robust way to determine client IPs behind a proxy.\n\nChoose the key function that matches your deployment topology. If your app sits behind a reverse proxy or load balancer, configure trusted proxy handling before basing limits on forwarded headers.\n\n## Important Pitfalls\n\n- `request` is mandatory in limited endpoints. Without it, the decorator cannot hook into the request lifecycle.\n- Decorator order is mandatory: put `@app.get(...)` or `@router.get(...)` above `@limiter.limit(...)`.\n- WebSocket endpoints are not supported.\n- If you need `X-RateLimit-*` headers on FastAPI routes that return dicts, include `response: Response` in the signature and set `headers_enabled=True`.\n- Global defaults require middleware. The docs example uses `SlowAPIMiddleware` together with `default_limits`.\n- Redis is optional. If you pass a Redis `storage_uri`, install the `redis` extra as well.\n\n## Version Notes For 0.1.9\n\n- The maintainer's changelog for `0.1.9` lists type-hint fixes for `limit()` and `shared_limit()`, plus a fix so Starlette `Config` only receives `\".env\"` when that file exists.\n- The latest published changelog in the repo also includes `0.1.10` as a later release. This guide is pinned to the requested `0.1.9` package version.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/slowapi/\n- Documentation root: https://slowapi.readthedocs.io/en/latest/\n- Quick start and limitations: https://slowapi.readthedocs.io/en/latest/\n- Examples: https://slowapi.readthedocs.io/en/latest/examples/\n- API reference: https://slowapi.readthedocs.io/en/latest/api/\n- Source repository: https://github.com/laurentS/slowapi\n- `pyproject.toml` for package metadata and extras: https://raw.githubusercontent.com/laurentS/slowapi/master/pyproject.toml\n- Changelog: https://raw.githubusercontent.com/laurentS/slowapi/master/CHANGELOG.md\n"
  },
  {
    "path": "content/smart-open/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"smart-open streams local and remote files through a single file-like open() API for Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"7.5.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,smart-open,streaming,files,s3\"\n---\n\n# smart-open Python Package Guide\n\n`smart_open` gives Python code one `open()`-style API for local files and URI-based backends. Use `smart_open.open()` when your application should read or write text and bytes the same way regardless of where the object lives.\n\nThis guide focuses on the common `smart_open.open()` workflow and the S3-backed configuration pattern most apps need.\n\n## Install\n\nInstall `smart-open` and the SDK for any remote backend you use.\n\n```bash\npip install smart-open boto3\n```\n\nFor S3-compatible storage such as MinIO or LocalStack, keep using `boto3`; configure the endpoint on the client you pass to `smart_open`.\n\n## Import And Core API\n\nPrefer the module-qualified call in new code so it is obvious when you are using `smart_open` instead of Python's built-in `open`:\n\n```python\nimport smart_open\n\nwith smart_open.open(\"/tmp/example.txt\", \"r\", encoding=\"utf-8\") as fin:\n    print(fin.read())\n```\n\nUse text modes (`\"r\"`, `\"w\"`, `\"rt\"`, `\"wt\"`) with `encoding=` for strings, and binary modes (`\"rb\"`, `\"wb\"`) for bytes.\n\n## Read Local And HTTP Resources\n\nLocal paths and HTTP(S) URLs use the same API surface:\n\n```python\nimport smart_open\n\nwith smart_open.open(\"/tmp/input.jsonl\", \"r\", encoding=\"utf-8\") as fin:\n    for line in fin:\n        print(line.rstrip())\n\nwith smart_open.open(\"https://example.com/data.txt\", \"r\", encoding=\"utf-8\") as fin:\n    print(fin.readline())\n```\n\nFor large payloads, iterate over the stream instead of calling `read()` unless you actually need the full body in memory.\n\n## Read And Write S3 With Default Credentials\n\nFor S3, `smart_open` relies on the normal `boto3` credential chain. In practice that means you should configure credentials the same way you would for any `boto3` application:\n\n- `AWS_ACCESS_KEY_ID`\n- `AWS_SECRET_ACCESS_KEY`\n- `AWS_SESSION_TOKEN` when using temporary credentials\n- `AWS_DEFAULT_REGION`\n\nPrefer IAM roles or your platform's standard AWS credential source over hard-coded keys.\n\n```python\nimport os\nimport smart_open\n\nbucket = os.environ[\"APP_BUCKET\"]\nuri = f\"s3://{bucket}/reports/daily.txt\"\n\nwith smart_open.open(uri, \"w\", encoding=\"utf-8\") as fout:\n    fout.write(\"hello from smart-open\\n\")\n\nwith smart_open.open(uri, \"r\", encoding=\"utf-8\") as fin:\n    print(fin.read())\n```\n\n## Pass An Explicit Boto3 Client\n\nPass a preconfigured client through `transport_params` when you need a specific profile, region, retry policy, or custom S3-compatible endpoint.\n\n```python\nimport os\n\nimport boto3\nimport smart_open\n\nsession = boto3.Session(\n    profile_name=os.getenv(\"AWS_PROFILE\"),\n    region_name=os.getenv(\"AWS_DEFAULT_REGION\", \"us-east-1\"),\n)\n\ns3_client = session.client(\n    \"s3\",\n    endpoint_url=os.getenv(\"S3_ENDPOINT_URL\"),\n)\n\nuri = f\"s3://{os.environ['APP_BUCKET']}/exports/items.jsonl\"\n\nwith smart_open.open(\n    uri,\n    \"w\",\n    encoding=\"utf-8\",\n    transport_params={\"client\": s3_client},\n) as fout:\n    fout.write('{\"id\": 1, \"name\": \"example\"}\\n')\n\nwith smart_open.open(\n    uri,\n    \"r\",\n    encoding=\"utf-8\",\n    transport_params={\"client\": s3_client},\n) as fin:\n    print(fin.readline().rstrip())\n```\n\nThis pattern is the right place to set `endpoint_url` for MinIO or LocalStack and to keep auth, retries, and region selection centralized in one client object.\n\n## Work With Compressed Files\n\n`smart_open` can transparently handle common compressed filenames, so the same `open()` call works for streaming compressed text.\n\n```python\nimport smart_open\n\nuri = \"s3://my-bucket/events/2026-03-12.jsonl.gz\"\n\nwith smart_open.open(uri, \"wt\", encoding=\"utf-8\") as fout:\n    fout.write('{\"event\": \"started\"}\\n')\n    fout.write('{\"event\": \"finished\"}\\n')\n\nwith smart_open.open(uri, \"rt\", encoding=\"utf-8\") as fin:\n    for line in fin:\n        print(line.rstrip())\n```\n\nUse binary mode if you need raw compressed bytes rather than decompressed text.\n\n## Common Pitfalls\n\n- Prefer `smart_open.open()` in new code. Older examples may use legacy helper names.\n- Always close the stream with a `with` block; remote writes are finalized when the handle closes.\n- Do not mix text data with binary modes. If you write strings, use text mode and set `encoding`.\n- When auth fails on cloud backends, debug the underlying SDK configuration first; `smart_open` depends on that provider client.\n- Treat object storage writes as whole-object writes. If your workflow needs in-place mutation or true append semantics, write a new object instead.\n\n## Official Sources\n\n- Maintainer documentation: https://github.com/piskvorky/smart_open\n- Package registry: https://pypi.org/project/smart-open/\n"
  },
  {
    "path": "content/smolagents/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"smolagents package guide for Python agents with CodeAgent, ToolCallingAgent, models, tools, and secure execution\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.24.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"smolagents,python,agents,llm,huggingface,tool-calling,code-agents\"\n---\n\n# smolagents Python Package Guide\n\n## What It Is\n\n`smolagents` is Hugging Face's lightweight agent framework for Python. It gives you:\n\n- agent classes such as `CodeAgent` and `ToolCallingAgent`\n- model wrappers for Hugging Face Inference, OpenAI-compatible APIs, LiteLLM, and local Transformers\n- a `@tool` decorator and `Tool` base class for exposing callable tools to agents\n- optional secure execution backends for code-generating agents\n\nUse it when you need a Python agent loop that can call tools, generate code, or orchestrate other agents without pulling in a large framework.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to `smolagents==1.24.0`.\n- The current Hugging Face docs \"stable\" version and the current PyPI release both resolve to `1.24.0`, so the version used here matches upstream as of March 12, 2026.\n- The upstream docs describe `CodeAgent` as the code-writing agent and `ToolCallingAgent` as the JSON/tool-calling variant; choose deliberately because they execute tasks differently.\n- `CodeAgent` can execute model-generated Python. For untrusted prompts or networked tasks, review the secure execution guide before running it on your machine.\n- Agent loops are multi-step by default. The docs show `max_steps=20` as the default, so tune that down for bounded tasks or up for more complex workflows.\n\n## Install\n\nBasic install:\n\n```bash\npython -m pip install \"smolagents==1.24.0\"\n```\n\nThe official docs also show the plain install form:\n\n```bash\npip install smolagents\n```\n\n## Core Mental Model\n\n`smolagents` is built around three pieces:\n\n1. A model wrapper object such as `InferenceClientModel` or `OpenAIServerModel`\n2. An agent such as `CodeAgent` or `ToolCallingAgent`\n3. Zero or more tools the agent is allowed to call\n\nDo not pass just a model name string to an agent. Instantiate a model object first, then pass it as `model=...`.\n\n## Minimal Setup\n\nThis is the smallest useful pattern from the official docs: create a model object, create an agent, then call `run(...)`.\n\n```python\nfrom smolagents import CodeAgent, InferenceClientModel\n\nmodel = InferenceClientModel(\n    model_id=\"Qwen/Qwen2.5-Coder-32B-Instruct\",\n)\n\nagent = CodeAgent(\n    tools=[],\n    model=model,\n    max_steps=20,\n)\n\nresult = agent.run(\"Write a Python function that returns the first 10 Fibonacci numbers.\")\nprint(result)\n```\n\nUse `CodeAgent` when you want the model to solve tasks by writing Python snippets during the loop.\n\n## Choosing A Model Backend\n\nThe model guide documents several wrappers. The ones you are most likely to reach for are:\n\n- `InferenceClientModel`: Hugging Face Inference providers and hosted inference endpoints\n- `OpenAIServerModel`: OpenAI-compatible APIs such as OpenAI or other providers that expose an OpenAI-style endpoint\n- `LiteLLMModel`: when you already standardize provider access through LiteLLM\n- `TransformersModel`: local model inference through `transformers`\n\n### OpenAI-Compatible Models\n\nUse `OpenAIServerModel` when your provider exposes an OpenAI-style API.\n\n```python\nimport os\n\nfrom smolagents import CodeAgent, OpenAIServerModel\n\nmodel = OpenAIServerModel(\n    model_id=\"gpt-4.1-mini\",\n    api_base=\"https://api.openai.com/v1\",\n    api_key=os.environ[\"OPENAI_API_KEY\"],\n)\n\nagent = CodeAgent(tools=[], model=model)\nprint(agent.run(\"Summarize what a Python context manager does in two sentences.\"))\n```\n\nThe official model guide also shows `OpenAIServerModel` as the path for other OpenAI-compatible backends such as Ollama and third-party hosted providers. When you switch providers, keep the same pattern and change the base URL, model id, and credentials to match that provider.\n\n### Hugging Face Inference\n\nUse `InferenceClientModel` when you want Hugging Face-hosted or provider-routed inference.\n\n```python\nfrom smolagents import CodeAgent, InferenceClientModel\n\nmodel = InferenceClientModel(\n    model_id=\"Qwen/Qwen2.5-Coder-32B-Instruct\",\n    provider=\"together\",\n)\n\nagent = CodeAgent(tools=[], model=model)\nprint(agent.run(\"Give me a 3-item Python code review checklist.\"))\n```\n\nAuth for this path depends on the inference provider you choose. Configure the provider credentials before running the agent, then instantiate the model once and reuse it.\n\n## Building Tools\n\nFor most projects, define tools with `@tool`. The tool docs require:\n\n- typed function parameters\n- a return type annotation\n- a descriptive docstring so the agent can understand when to call it\n\n```python\nfrom smolagents import ToolCallingAgent, InferenceClientModel, tool\n\n@tool\ndef get_weather(city: str) -> str:\n    \"\"\"\n    Return the current weather summary for a city.\n\n    Args:\n        city: The city name to look up.\n    \"\"\"\n    return f\"The weather in {city} is sunny.\"\n\nmodel = InferenceClientModel(model_id=\"Qwen/Qwen2.5-Coder-32B-Instruct\")\nagent = ToolCallingAgent(tools=[get_weather], model=model)\n\nprint(agent.run(\"What is the weather in Paris?\"))\n```\n\nUse `ToolCallingAgent` when the model/provider has reliable tool-calling support and you want structured tool invocations instead of code execution.\n\n## Secure Code Execution\n\n`CodeAgent` can run generated Python code. The secure execution guide matters if prompts, tools, or retrieved content are not fully trusted.\n\nPractical guidance:\n\n- local execution is convenient for trusted internal tasks, prototypes, and tests\n- for untrusted tasks, prefer an isolated executor rather than running generated code on your workstation or CI host\n- the official guide documents isolated execution options including E2B, Docker, Modal, and a Pyodide+Deno WebAssembly path\n\nIf the task only needs tool calls and not arbitrary generated Python, consider `ToolCallingAgent` instead of `CodeAgent`.\n\n## Common Usage Patterns\n\n### Constrain The Loop\n\nSet `max_steps` explicitly for tasks that must stop quickly:\n\n```python\nfrom smolagents import CodeAgent, InferenceClientModel\n\nagent = CodeAgent(\n    tools=[],\n    model=InferenceClientModel(model_id=\"Qwen/Qwen2.5-Coder-32B-Instruct\"),\n    max_steps=6,\n)\n```\n\nThis avoids long agent loops when the task should be answerable in a few reasoning/tool steps.\n\n### Reuse Long-Lived Objects\n\nInstantiate the model and agent once for a workflow instead of rebuilding them for every prompt:\n\n```python\nfrom smolagents import CodeAgent, InferenceClientModel\n\nmodel = InferenceClientModel(model_id=\"Qwen/Qwen2.5-Coder-32B-Instruct\")\nagent = CodeAgent(tools=[], model=model)\n\nfor task in [\n    \"Generate a regex for ISO dates.\",\n    \"Explain why raw strings help with regexes in Python.\",\n]:\n    print(agent.run(task))\n```\n\n## Authentication And Configuration Notes\n\n- `smolagents` itself is the agent framework. Authentication usually comes from the model backend you choose.\n- For OpenAI-compatible APIs, the official docs show passing `api_key=` and `api_base=` to `OpenAIServerModel`.\n- For Hugging Face inference, configure the chosen provider's credentials first, then create `InferenceClientModel(...)`.\n- Keep provider secrets in environment variables or your platform secret manager, not inline in source files.\n- If a model does not support the behavior you need, switch model backends before changing agent logic. Tool calling, vision, and provider-specific capabilities come from the selected underlying model.\n\n## Common Pitfalls\n\n- Passing `model=\"gpt-4.1-mini\"` directly into an agent. `smolagents` expects a model wrapper instance, not a bare string.\n- Using `CodeAgent` for untrusted work without isolation. It may execute model-generated Python locally.\n- Decorating a tool without full type hints or without a useful docstring. The agent uses that schema to decide whether the tool is callable.\n- Debugging the wrong layer. Provider auth failures, unsupported tool calling, or missing vision support usually come from the selected model backend, not from the agent class itself.\n- Letting loops run too long. Set `max_steps` intentionally for bounded tasks.\n\n## Recommended Starting Points\n\nPick one path and keep it simple:\n\n- If you want Python-code actions: start with `CodeAgent` plus a single trusted model backend.\n- If you want structured tool calls: start with `ToolCallingAgent` plus one or two well-typed tools.\n- If you are exposing external systems: define tools first, then let the agent orchestrate them.\n- If prompts are untrusted: choose a sandboxed execution strategy before using `CodeAgent`.\n\n## Official URLs Used For This Guide\n\n- Docs home: `https://huggingface.co/docs/smolagents/`\n- Versioned docs index: `https://huggingface.co/docs/smolagents/v1.24.0/en/index`\n- Agents guide: `https://huggingface.co/docs/smolagents/v1.24.0/en/conceptual_guides/intro_agents`\n- Models guide: `https://huggingface.co/docs/smolagents/v1.24.0/en/reference/models`\n- Tools guide: `https://huggingface.co/docs/smolagents/v1.24.0/en/tutorials/tools`\n- Secure code execution guide: `https://huggingface.co/docs/smolagents/v1.24.0/en/tutorials/secure_code_execution`\n- PyPI: `https://pypi.org/project/smolagents/1.24.0/`\n- GitHub repository: `https://github.com/huggingface/smolagents`\n- `v1.24.0` release notes: `https://github.com/huggingface/smolagents/releases/tag/v1.24.0`\n"
  },
  {
    "path": "content/sniffio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"sniffio for Python - detect the active async library in shared async code\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.3.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sniffio,python,asyncio,trio,curio,async,contextvars\"\n---\n\n# sniffio Python Package Guide\n\n## What It Does\n\n`sniffio` is a tiny compatibility helper for async Python libraries. Its main API, `current_async_library()`, tells you which async library is currently running so shared code can branch correctly.\n\nUse it when you are writing reusable async helpers or adapters that need to work under more than one runtime. It does not create an event loop, run tasks, or replace `asyncio`, Trio, or Curio.\n\n## Install\n\nInstall the package version your project expects:\n\n```bash\npython -m pip install \"sniffio==1.3.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sniffio==1.3.1\"\npoetry add \"sniffio==1.3.1\"\n```\n\nPyPI metadata for `1.3.1` declares `Requires-Python >=3.7`.\n\n## Imports\n\nTypical application or library code only needs:\n\n```python\nfrom sniffio import current_async_library, AsyncLibraryNotFoundError\n```\n\nIf you are writing framework integration code, `sniffio` also exports these advanced hooks:\n\n```python\nfrom sniffio import current_async_library_cvar, thread_local\n```\n\n## Environment And Initialization\n\n- No environment variables are required.\n- No auth, credentials, or service endpoints are involved.\n- There is no client object and no startup initialization step.\n- The important setup rule is simple: call `current_async_library()` from running async code, or set one of the exported override hooks in integration code.\n\n## Basic Detection\n\n### `asyncio`\n\n```python\nimport asyncio\n\nfrom sniffio import current_async_library\n\n\nasync def main() -> None:\n    library = current_async_library()\n    print(library)  # asyncio\n\n\nasyncio.run(main())\n```\n\n### Trio\n\n```python\nimport trio\n\nfrom sniffio import current_async_library\n\n\nasync def main() -> None:\n    library = current_async_library()\n    print(library)  # trio\n\n\ntrio.run(main)\n```\n\n## Branch On The Current Runtime\n\nThis is the core pattern when you maintain one async API that has runtime-specific implementations underneath:\n\n```python\nfrom sniffio import current_async_library\n\n\nasync def sleep_for(seconds: float) -> None:\n    library = current_async_library()\n\n    if library == \"trio\":\n        import trio\n\n        await trio.sleep(seconds)\n    elif library == \"asyncio\":\n        import asyncio\n\n        await asyncio.sleep(seconds)\n    elif library == \"curio\":\n        import curio\n\n        await curio.sleep(seconds)\n    else:\n        raise RuntimeError(f\"Unsupported async library: {library!r}\")\n```\n\nIn `1.3.1`, the documented built-in magic strings are `\"trio\"`, `\"curio\"`, and `\"asyncio\"`.\n\n## Handle Synchronous Call Sites\n\n`current_async_library()` raises `AsyncLibraryNotFoundError` when it is called outside a recognized async context.\n\nCatch that exception if the same code path might be used from synchronous startup, tests, or CLI utilities:\n\n```python\nfrom sniffio import AsyncLibraryNotFoundError, current_async_library\n\n\ndef get_current_library() -> str | None:\n    try:\n        return current_async_library()\n    except AsyncLibraryNotFoundError:\n        return None\n```\n\n## Integration Hooks For Framework Authors\n\nIf you are adapting a custom async runner or bridging another framework into `sniffio`, the public `ContextVar` hook is the cleanest way to declare the active runtime for the current context:\n\n```python\nfrom sniffio import current_async_library, current_async_library_cvar\n\n\ndef mark_runtime(name: str) -> None:\n    token = current_async_library_cvar.set(name)\n    try:\n        print(current_async_library())\n    finally:\n        current_async_library_cvar.reset(token)\n\n\nmark_runtime(\"my-runtime\")\n```\n\n`thread_local` is also a public fallback hook:\n\n```python\nfrom sniffio import current_async_library, thread_local\n\n\nold_name, thread_local.name = thread_local.name, \"my-runtime\"\ntry:\n    print(current_async_library())\nfinally:\n    thread_local.name = old_name\n```\n\nPrefer `current_async_library_cvar` for async integrations. It follows normal `contextvars` scoping and reset semantics.\n\n## Common Pitfalls\n\n- `current_async_library()` returns a plain string, not an enum or runtime object.\n- `sniffio` only detects the active library; it does not provide sleep, task, or event-loop APIs.\n- If the runtime is unknown and you have not set `current_async_library_cvar` or `thread_local.name`, `current_async_library()` raises `AsyncLibraryNotFoundError`.\n- `thread_local.name` is checked before `current_async_library_cvar`, so a thread-local override wins if both are set.\n- For `trio-asyncio`, the documented return value is still `\"trio\"` or `\"asyncio\"` depending on the current mode, not a separate combined string.\n\n## Version-Sensitive Notes\n\n- `1.3.1` publishes `Requires-Python >=3.7` in package metadata.\n- The `1.3.1` source docstring documents support for Trio `0.6+` and `trio-asyncio` `0.8.2+`.\n- The bundled upstream tests in `1.3.1` skip Curio on Python `3.12+` because Curio is noted there as broken on Python `3.12`.\n\n## Official Links\n\n- Documentation: `https://sniffio.readthedocs.io/en/latest/`\n- PyPI: `https://pypi.org/project/sniffio/`\n- Repository: `https://github.com/python-trio/sniffio`\n- Changelog: `https://sniffio.readthedocs.io/en/latest/history.html`\n"
  },
  {
    "path": "content/snowflake/docs/cortex-ai-functions/DOC.md",
    "content": "---\nname: cortex-ai-functions\ndescription: \"Snowflake Cortex AI Functions — SQL and Python functions for text generation, classification, sentiment analysis, extraction, summarization, translation, embedding, and document parsing\"\nmetadata:\n  languages: \"sql,python\"\n  versions: \"2026-03\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,cortex,ai,llm,sql,functions,nlp,embeddings,rag,document-processing\"\n---\n\n# Cortex AI Functions\n\nSnowflake Cortex AI Functions are SQL-callable AI functions that run LLMs directly inside Snowflake. No external APIs, no data movement — call them in SQL or Python on your Snowflake data.\n\n## Access Control\n\n```sql\n-- Required role (run as ACCOUNTADMIN)\nGRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE my_role;\n```\n\n## Function Reference\n\n### AI_COMPLETE — Text Generation\n\nGenerate text from a prompt using your choice of model.\n\n```sql\n-- Simple completion\nSELECT AI_COMPLETE('claude-4-sonnet', 'Summarize: ' || my_text) FROM documents;\n\n-- With system prompt and options\nSELECT AI_COMPLETE(\n  'claude-4-sonnet',\n  [\n    {'role': 'system', 'content': 'You are a helpful assistant.'},\n    {'role': 'user', 'content': 'Analyze this data trend.'}\n  ],\n  {'temperature': 0.7, 'max_tokens': 1024, 'guardrails': TRUE}\n);\n```\n\n**Options**: `temperature` (0-1), `top_p` (0-1), `max_tokens` (default 4096, max 8192), `guardrails` (TRUE/FALSE — uses Cortex Guard), `response_format` (JSON schema for structured output).\n\n**Supported models**: `claude-4-opus`, `claude-4-sonnet`, `claude-3-7-sonnet`, `claude-3-5-sonnet`, `deepseek-r1`, `llama3.1-8b`, `llama3.1-70b`, `llama3.1-405b`, `llama3.3-70b`, `llama4-maverick`, `llama4-scout`, `mistral-large2`, `openai-gpt-4.1`, `openai-o4-mini`, `snowflake-llama-3.3-70b`, and more.\n\n### AI_CLASSIFY — Text/Image Classification\n\nCategorize text into predefined buckets with zero training data.\n\n```sql\nSELECT\n  feedback_text,\n  AI_CLASSIFY(\n    feedback_text,\n    ['billing issue', 'product bug', 'feature request', 'praise', 'other']\n  ) AS category\nFROM customer_feedback;\n```\n\n### AI_SENTIMENT — Sentiment Analysis\n\nReturns a score from -1 (negative) to 1 (positive).\n\n```sql\nSELECT\n  review_text,\n  AI_SENTIMENT(review_text) AS score,\n  CASE\n    WHEN AI_SENTIMENT(review_text) > 0.3 THEN 'Positive'\n    WHEN AI_SENTIMENT(review_text) < -0.3 THEN 'Negative'\n    ELSE 'Neutral'\n  END AS label\nFROM product_reviews;\n\n-- Multi-dimension sentiment\nSELECT AI_SENTIMENT(call_text, ['Professionalism', 'Resolution', 'Wait Time'])\nFROM support_calls;\n```\n\n### AI_EXTRACT — Structured Extraction\n\nPull specific fields from unstructured text, images, or documents.\n\n```sql\nSELECT AI_EXTRACT(\n  invoice_text,\n  {'vendor_name': 'STRING', 'total_amount': 'NUMBER', 'invoice_date': 'DATE'}\n) AS extracted\nFROM invoices;\n```\n\n### AI_SUMMARIZE — Text Summarization\n\n```sql\nSELECT AI_SUMMARIZE(article_content) AS summary FROM articles;\n```\n\n### AI_TRANSLATE — Translation\n\n```sql\nSELECT AI_TRANSLATE(description, 'en', 'fr') AS french_description\nFROM products;\n```\n\nSupports dozens of language pairs. Specify source and target language codes.\n\n### AI_EMBED — Vector Embeddings\n\nCreate embeddings for semantic search, similarity, and RAG.\n\n```sql\nSELECT AI_EMBED('snowflake-arctic-embed-l-v2.0', product_description)\nFROM products;\n```\n\n### AI_FILTER — Boolean Condition Check\n\nEvaluate text/images against a condition, returning TRUE/FALSE.\n\n```sql\nSELECT * FROM emails\nWHERE AI_FILTER(body, 'Contains a meeting request') = TRUE;\n```\n\n### AI_AGG — Aggregate Insights\n\nAggregate text across rows and generate insights.\n\n```sql\nSELECT AI_AGG(feedback_text, 'Summarize the top 3 themes') AS themes\nFROM customer_feedback\nGROUP BY product_id;\n```\n\n### AI_PARSE_DOCUMENT — Document Intelligence\n\nExtract text and structured data from PDF, images, and documents stored in stages.\n\n```sql\nSELECT AI_PARSE_DOCUMENT(\n  TO_FILE('@my_stage', 'contract.pdf'),\n  {'mode': 'LAYOUT'}\n) AS parsed\nFROM DUAL;\n```\n\n### AI_REDACT — PII Redaction\n\nRedact personally identifiable information from text.\n\n```sql\nSELECT AI_REDACT(customer_notes) AS redacted FROM support_tickets;\n```\n\n## Cortex REST API\n\nAccess the same models via REST for application integration.\n\n### Chat Completions API (OpenAI-compatible)\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=\"<SNOWFLAKE_PAT>\",\n    base_url=\"https://<account>.snowflakecomputing.com/api/v2/cortex/v1\"\n)\n\nresponse = client.chat.completions.create(\n    model=\"claude-sonnet-4-5\",\n    messages=[{\"role\": \"user\", \"content\": \"How does a snowflake form?\"}]\n)\nprint(response.choices[0].message.content)\n```\n\n### Messages API (Anthropic-compatible, Claude models only)\n\n```python\nimport httpx, anthropic\n\nPAT = \"<SNOWFLAKE_PAT>\"\nhttp_client = httpx.Client(headers={\"Authorization\": f\"Bearer {PAT}\"})\n\nclient = anthropic.Anthropic(\n    api_key=\"not-used\",\n    base_url=\"https://<account>.snowflakecomputing.com/api/v2/cortex\",\n    http_client=http_client,\n    default_headers={\"Authorization\": f\"Bearer {PAT}\"}\n)\n\nresponse = client.messages.create(\n    model=\"claude-sonnet-4-5\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"How does a snowflake form?\"}]\n)\n```\n\n### curl\n\n```bash\ncurl \"https://<account>.snowflakecomputing.com/api/v2/cortex/v1/chat/completions\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer $SNOWFLAKE_PAT\" \\\n  -d '{\"model\": \"claude-sonnet-4-5\", \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]}'\n```\n\nBoth APIs support **streaming** via `stream: true` / `\"stream\": true`.\n\n## Python SDK\n\n```python\nfrom snowflake.cortex import Complete, Sentiment, Summarize, Translate, ExtractAnswer\n\n# In a Snowpark session\nresult = Complete(\"claude-4-sonnet\", \"Write a brief intro about Snowflake Cortex\")\nscore = Sentiment(\"I really enjoyed this. Fantastic service!\")\nsummary = Summarize(long_text)\ntranslated = Translate(text, \"en\", \"fr\")\n```\n\n## Cross-Region Inference\n\n```sql\n-- Enable access to models not in your region (run as ACCOUNTADMIN)\nALTER ACCOUNT SET CORTEX_ENABLED_CROSS_REGION = 'AWS_US';\n```\n\nOptions: `AWS_US`, `AWS_EU`, `AWS_APJ`, `ANY_REGION`.\n\n## Cost and Billing\n\n- Token-based billing: input + output tokens for generative functions (AI_COMPLETE, AI_SUMMARIZE, AI_TRANSLATE); input tokens only for extraction functions (AI_SENTIMENT, AI_EXTRACT)\n- Monitor usage:\n  ```sql\n  SELECT * FROM SNOWFLAKE.ACCOUNT_USAGE.METERING_DAILY_HISTORY\n  WHERE SERVICE_TYPE = 'AI_SERVICES';\n  ```\n\n## Limitations\n\n- Cortex AI Functions do not support dynamic tables\n- Usage quotas apply per account\n- Model availability varies by region — use cross-region inference for full access\n"
  },
  {
    "path": "content/snowflake/docs/cortex-analyst/DOC.md",
    "content": "---\nname: cortex-analyst\ndescription: \"Snowflake Cortex Analyst — natural language to SQL engine powered by semantic views for self-serve analytics, REST API integration, and multi-turn conversations\"\nmetadata:\n  languages: \"sql,python\"\n  versions: \"2026-03\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,cortex,analyst,natural-language,sql,semantic-model,analytics,rest-api\"\n---\n\n# Cortex Analyst\n\nCortex Analyst is a fully managed Snowflake Cortex feature that converts natural language questions into accurate SQL queries against your structured data. Business users ask questions in plain English and get direct answers — no SQL required.\n\n## How It Works\n\n1. User asks a question in natural language\n2. Cortex Analyst uses a **semantic model** (or **semantic view**) to understand your data's business context\n3. It generates and executes a SQL query against Snowflake\n4. Results are returned to the user\n\n## Access Control\n\n```sql\n-- Required: one of these database roles (run as ACCOUNTADMIN)\nGRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE my_role;\n-- OR for Analyst-only access:\nGRANT DATABASE ROLE SNOWFLAKE.CORTEX_ANALYST_USER TO ROLE my_role;\n```\n\nAdditional requirements:\n- `READ` or `WRITE` on the stage containing the semantic model YAML (if stage-based)\n- `USAGE` on any Cortex Search services referenced in the model\n- `SELECT` on tables referenced in the model\n\n## Semantic Views (Recommended)\n\nSemantic Views are schema-level objects that define business concepts over your data. They are the recommended approach for Cortex Analyst.\n\n### What Semantic Views Define\n\n- **Logical tables**: Business entities (customers, orders, products)\n- **Dimensions**: Categorical context (customer name, product category, order date)\n- **Facts**: Row-level quantitative data (sale amounts, quantities)\n- **Metrics**: Aggregated KPIs (total revenue, average order value)\n- **Relationships**: How tables join together\n\n### Why Use Semantic Views\n\n- **Rich metadata**: Descriptions, synonyms, and data types help the LLM understand your data\n- **Business logic**: Metrics capture correct aggregation formulas\n- **Predefined joins**: Relationship paths ensure correct multi-table queries\n- **Verified examples**: Sample questions and SQL answers guide generation\n- **Native Snowflake integration**: Full RBAC, privileges, governance, and sharing\n- **Derived metrics**: Combine data from multiple tables\n- **Access modifiers**: Mark facts/metrics as public or private\n\n### Creating a Semantic View\n\n```sql\nCREATE OR REPLACE SEMANTIC VIEW revenue_analytics\n  COMMENT = 'Revenue analytics for sales team'\n  AS\n  TABLES (\n    orders_table AS (\n      SELECT * FROM analytics.public.orders\n    )\n      PRIMARY KEY (order_id)\n      WITH DIMENSIONS (\n        order_id COMMENT 'Unique order identifier',\n        customer_name COMMENT 'Customer full name',\n        order_date COMMENT 'Date the order was placed'\n      )\n      WITH FACTS (\n        amount COMMENT 'Order total in USD',\n        quantity COMMENT 'Number of items'\n      )\n      WITH METRICS (\n        total_revenue AS SUM(amount) COMMENT 'Total revenue in USD',\n        avg_order_value AS AVG(amount) COMMENT 'Average order value'\n      )\n  );\n```\n\n## Legacy Semantic Model (YAML)\n\nStage-based YAML files are still supported for backward compatibility. Upload a YAML file defining tables, dimensions, time dimensions, measures, and sample queries to a Snowflake stage.\n\n## REST API\n\nCortex Analyst is accessed via REST API for integration into any application.\n\n### Endpoint\n\n```\nPOST https://<account>.snowflakecomputing.com/api/v2/cortex/analyst/message\n```\n\n### Request Body\n\n```json\n{\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": [\n        {\"type\": \"text\", \"text\": \"What was total revenue last month?\"}\n      ]\n    }\n  ],\n  \"semantic_model_file\": \"@my_stage/revenue_model.yaml\"\n}\n```\n\nOr with a semantic view:\n\n```json\n{\n  \"messages\": [...],\n  \"semantic_view\": \"my_db.my_schema.revenue_analytics\"\n}\n```\n\n### Response\n\nThe response contains either:\n- A SQL query (type `sql`) that answers the question\n- A text explanation (type `text`) if the question cannot be answered with SQL\n- A suggestion list if the question is ambiguous\n\n### Multi-Turn Conversations\n\nPass conversation history in the `messages` array to enable follow-up questions:\n\n```json\n{\n  \"messages\": [\n    {\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"What is revenue by region for 2024?\"}]},\n    {\"role\": \"analyst\", \"content\": [{\"type\": \"sql\", \"statement\": \"SELECT ...\"}]},\n    {\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"What about just North America?\"}]}\n  ]\n}\n```\n\n## Python Integration (Streamlit Example)\n\n```python\nimport streamlit as st\nfrom snowflake.snowpark.context import get_active_session\nimport json\n\nsession = get_active_session()\n\ndef query_analyst(question, messages):\n    messages.append({\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": question}]})\n    response = session.sql(f\"\"\"\n        SELECT SNOWFLAKE.CORTEX.ANALYST(\n            '{json.dumps({\"messages\": messages, \"semantic_view\": \"MY_DB.ANALYTICS.REVENUE\"})}'\n        )\n    \"\"\").collect()\n    return response\n\nst.title(\"Revenue Analytics\")\nquestion = st.text_input(\"Ask a question about revenue:\")\nif question:\n    result = query_analyst(question, st.session_state.get(\"messages\", []))\n    st.write(result)\n```\n\n## Using Cortex Analyst from Cortex Code\n\nIn Cortex Code (CLI or Snowsight), you can query semantic models directly:\n\n```\nUse the @models/revenue.yaml semantic model to answer \"What was revenue last month?\"\n```\n\n```bash\n# CLI\ncortex analyst query \"Top customers by spend\" --view=ANALYTICS.CORE.REVENUE_METRICS\n```\n\n## Key Features\n\n- **Automatic model selection**: If multiple semantic models exist, Cortex Analyst picks the right one\n- **Security**: No data leaves Snowflake's governance boundary; full RBAC enforcement\n- **No model training**: Cortex Analyst does not train on customer data\n- **Powered by frontier LLMs**: Uses Snowflake-hosted models from Mistral, Meta, and others\n\n## Limiting Access\n\n```sql\n-- Revoke broad access and grant to specific roles\nREVOKE DATABASE ROLE SNOWFLAKE.CORTEX_USER FROM ROLE PUBLIC;\n\nCREATE ROLE cortex_analyst_role;\nGRANT DATABASE ROLE SNOWFLAKE.CORTEX_ANALYST_USER TO ROLE cortex_analyst_role;\nGRANT ROLE cortex_analyst_role TO USER analyst_user;\n```\n\n## Prerequisites\n\n- Snowflake account with `CORTEX_USER` or `CORTEX_ANALYST_USER` database role\n- A semantic view or semantic model YAML file defining your data\n- SELECT privileges on underlying tables\n- Cross-region inference enabled if needed\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code/DOC.md",
    "content": "---\nname: cortex-code\ndescription: \"Snowflake Cortex Code CLI — AI-powered coding assistant with native Snowflake integration, SQL execution, semantic views, MCP support, skills, and subagents\"\nmetadata:\n  languages: \"bash\"\n  versions: \"1.0.36\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,cortex,cli,ai,coding-assistant,sql,mcp,agents,skills\"\n---\n\n# Cortex Code CLI\n\nCortex Code (CoCo) is Snowflake's AI-powered coding assistant CLI. It connects directly to your Snowflake account and orchestrates SQL execution, object discovery, semantic views, Cortex Analyst, MCP integrations, skills, and subagents from your terminal.\n\n## Install\n\n```bash\n# Linux / macOS / WSL\ncurl -LsS https://ai.snowflake.com/static/cc-scripts/install.sh | sh\n\n# Windows (PowerShell)\nirm https://ai.snowflake.com/static/cc-scripts/install.ps1 | iex\n```\n\nThe `cortex` binary installs to `~/.local/bin` (Linux/macOS) or `%LOCALAPPDATA%\\cortex` (Windows).\n\n## Connect to Snowflake\n\nRun `cortex` to launch the setup wizard. It reads connections from `~/.snowflake/connections.toml`:\n\n```toml\n[default]\naccount = \"myaccount\"\nuser = \"myuser\"\nauthenticator = \"externalbrowser\"\ndatabase = \"MYDB\"\nschema = \"PUBLIC\"\nwarehouse = \"COMPUTE_WH\"\nrole = \"DEVELOPER\"\n```\n\nSupported auth methods: `externalbrowser` (SSO), `snowflake_jwt` (key-pair), `snowflake` (password), `oauth`, `PROGRAMMATIC_ACCESS_TOKEN`.\n\n## Quick Start\n\n```bash\ncortex                              # Start interactive REPL\ncortex -p \"summarize README.md\"     # Non-interactive (print) mode\ncortex --resume last                # Resume last session\ncortex -c my-connection             # Use specific Snowflake connection\ncortex --plan                       # Start in plan mode\n```\n\n## Core Concepts\n\n### Special Input Syntax\n\n| Syntax | Action | Example |\n|--------|--------|---------|\n| `@path` | Include file context | `@src/app.ts` |\n| `@path$N-M` | Include line range | `@src/app.ts$10-50` |\n| `$skill` | Invoke a skill | `$ml-guide help` |\n| `#TABLE` | Inject Snowflake table metadata | `#MY_DB.PUBLIC.USERS` |\n| `!cmd` | Run bash (output goes to agent) | `!git status` |\n| `/cmd` | Slash command | `/help` |\n| `?` | Quick help overlay | `?` |\n\n### Operational Modes\n\n| Mode | Activate | Description |\n|------|----------|-------------|\n| Confirm Actions | default | Normal with permission checks |\n| Plan Mode | `/plan` or `Ctrl+P` | Review actions before execution |\n| Bypass Safeguards | `/bypass` | Auto-approve all tool calls |\n\nCycle modes with `Shift+Tab`.\n\n### Essential Keyboard Shortcuts\n\n| Shortcut | Action |\n|----------|--------|\n| `Enter` | Submit message |\n| `Ctrl+J` | Insert newline |\n| `Ctrl+C` | Cancel / Exit |\n| `Shift+Tab` | Cycle operational modes |\n| `Ctrl+P` | Toggle plan mode |\n| `Ctrl+O` | Cycle display mode |\n| `Ctrl+R` | Search prompt history |\n| `Ctrl+B` | Background bash process |\n| `Ctrl+D` | Fullscreen todo view |\n| `Ctrl+T` | SQL table view |\n| `Escape` | Cancel streaming |\n\n## Snowflake Integration\n\nCortex Code connects natively to Snowflake. No separate SDK needed.\n\n### #TABLE Context Injection\n\nType `#` followed by a fully-qualified table name to auto-inject metadata (columns, types, sample rows):\n\n```\nAnalyze the data in #MY_DB.PUBLIC.USERS\n```\n\n### SQL Execution\n\n```\n/sql SELECT COUNT(*) FROM my_table\n```\n\nUse `/table` to view results in a fullscreen table. The agent also executes SQL autonomously when needed.\n\n### Object Search\n\n```bash\ncortex search object \"user activity tables\"\n```\n\nSemantic search across databases, schemas, tables, views, and functions.\n\n### Cortex Analyst\n\n```bash\ncortex analyst query \"What was revenue last month?\" --model=revenue.yaml\ncortex analyst query \"Top customers by spend\" --view=ANALYTICS.CORE.REVENUE_METRICS\ncortex reflect revenue.yaml    # Validate semantic model\n```\n\n### Semantic Views\n\n```bash\ncortex semantic-views discover          # Find all semantic views\ncortex semantic-views describe <view>   # Show dimensions, facts, metrics\ncortex semantic-views search \"revenue\"  # Search by keyword\n```\n\n### Product Docs Search\n\n```bash\ncortex search docs \"how to create a stored procedure\"\n```\n\n## Session Management\n\n| Command | Description |\n|---------|-------------|\n| `/resume` | Resume a previous session |\n| `/fork` | Fork conversation from a specific point |\n| `/rewind` | Roll back to a previous state |\n| `/compact` | Summarize and clear history (frees context) |\n| `/rename <name>` | Name the session for easy retrieval |\n| `/diff` | Fullscreen git diff viewer |\n\n```bash\ncortex -r last                  # Resume last session from CLI\ncortex resume                   # Interactive session picker\n```\n\n## Key Slash Commands\n\n| Command | Description |\n|---------|-------------|\n| `/help` | Show help |\n| `/status` | Session status |\n| `/model <name>` | Switch model |\n| `/sql <query>` | Execute SQL |\n| `/settings` | Interactive settings editor |\n| `/connections` | Connection manager |\n| `/mcp` | MCP server manager |\n| `/skill` | Skill manager |\n| `/hooks` | Hook manager |\n| `/agents` | Subagent manager |\n| `/theme` | Theme selector |\n\n## Skills\n\nSkills are reusable instruction sets invoked with the `$` prefix:\n\n```\n$developing-with-streamlit build a dashboard for my sales data\n```\n\nSkill locations (priority order): project (`.cortex/skills/`) > global (`~/.snowflake/cortex/skills/`) > remote > bundled.\n\n## Subagents\n\nCortex Code spawns autonomous child agents for complex tasks:\n\n| Agent Type | Description |\n|------------|-------------|\n| `general-purpose` | Full tool access for multi-step tasks |\n| `Explore` | Fast read-only codebase exploration |\n| `Plan` | Architecture and implementation planning (read-only) |\n\nAgents can run in background. Use `/agents` to manage them.\n\n## MCP (Model Context Protocol)\n\nExtend Cortex Code by connecting external services:\n\n```bash\ncortex mcp add github -e GITHUB_TOKEN=$GITHUB_TOKEN -- npx -y @modelcontextprotocol/server-github\ncortex mcp list\n```\n\nConfig: `~/.snowflake/cortex/mcp.json`. Supports `stdio`, `sse`, and `http` transports.\n\n## Supported Models\n\n| Model | Identifier |\n|-------|------------|\n| Auto (recommended) | `auto` |\n| Claude Opus 4.6 | `claude-opus-4-6` |\n| Claude Sonnet 4.6 | `claude-sonnet-4-6` |\n| Claude Opus 4.5 | `claude-opus-4-5` |\n| Claude Sonnet 4.5 | `claude-sonnet-4-5` |\n| Claude Sonnet 4.0 | `claude-4-sonnet` |\n| OpenAI GPT 5.2 | `openai-gpt-5.2` |\n\nSwitch models: `/model claude-opus-4-6`\n\n## Prerequisites\n\n- Snowflake account with `SNOWFLAKE.CORTEX_USER` database role\n- At least one supported model available in your account\n- Supported platforms: macOS (arm64/x64), Linux (x64/arm64), Windows WSL, Windows native (preview)\n- If your model is not in-region, enable cross-region inference:\n  ```sql\n  ALTER ACCOUNT SET CORTEX_ENABLED_CROSS_REGION = 'AWS_US';\n  ```\n\n## Reference Files\n\nFor detailed documentation, see:\n\n- `references/commands.md` — Full CLI commands, slash commands, and flags\n- `references/snowflake-tools.md` — SQL execution, #TABLE, object search, Cortex Analyst, semantic views, artifacts\n- `references/mcp-and-agents.md` — MCP configuration, transport types, subagent system, custom agents\n- `references/configuration.md` — Settings, environment variables, connections, skills, hooks\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code/references/commands.md",
    "content": "# Commands Reference\n\nFull reference for Cortex Code CLI commands, slash commands, and flags.\n\n## CLI Entry Points\n\n```bash\ncortex                              # Start interactive REPL\ncortex -p \"query\"                   # Non-interactive print mode\ncortex resume                       # Interactive session picker\ncortex -r last                      # Resume last session\ncortex -r <session_id>              # Resume specific session\n```\n\n## CLI Subcommands\n\n| Command | Description |\n|---------|-------------|\n| `cortex mcp list\\|add\\|remove\\|show` | Manage MCP servers |\n| `cortex skill list\\|add\\|remove` | Manage skills |\n| `cortex resume [id]` | Resume session |\n| `cortex update` | Update CLI |\n| `cortex versions` | List available versions |\n| `cortex worktree list\\|create\\|switch\\|delete` | Git worktrees |\n| `cortex completion install\\|generate` | Shell tab-completion (bash/zsh/fish) |\n| `cortex connections list\\|set` | Snowflake connections |\n| `cortex env detect` | Detect Python environment |\n| `cortex source <conn> -- <cmd>` | Run command with Snowflake credentials as env vars |\n| `cortex ctx` | Long-term AI memory and task management |\n| `cortex browser` | Browser automation (Playwright MCP) |\n| `cortex search object \"<query>\"` | Search Snowflake objects |\n| `cortex search docs \"<query>\"` | Search Snowflake product docs |\n| `cortex reflect <file.yaml>` | Validate semantic model YAML |\n| `cortex semantic-views list\\|discover\\|describe\\|search\\|ddl\\|query` | Semantic view operations |\n| `cortex analyst query \"<question>\"` | Query via Cortex Analyst |\n| `cortex artifact create notebook\\|file <name> <path>` | Upload to Snowflake Workspace |\n| `cortex agents discover\\|list\\|describe\\|search` | Cortex Agent operations |\n\n## CLI Flags\n\n| Flag | Short | Description |\n|------|-------|-------------|\n| `--resume <id\\|last>` | `-r` | Resume session |\n| `--print <query>` | `-p` | Non-interactive mode |\n| `--workdir <dir>` | `-w` | Working directory |\n| `--worktree <name>` | | Git worktree |\n| `--connection <name>` | `-c` | Snowflake connection |\n| `--model <name>` | `-m` | Model override |\n| `--plan` | | Start in plan mode |\n| `--bypass` | | Start in bypass mode |\n| `--config <path>` | | Custom settings.json |\n| `--no-mcp` | | Disable MCP servers |\n| `--version` | `-V` | Show version |\n\n## Slash Commands — Session\n\n| Command | Description |\n|---------|-------------|\n| `/quit`, `/q` | Exit |\n| `/clear` | Clear screen |\n| `/new` | New session |\n| `/fork [name]` | Fork conversation from a chosen point |\n| `/resume` | Session picker |\n| `/rename <name>` | Rename session |\n| `/rewind [N]` | Rewind N user messages (or interactive) |\n| `/compact [instructions]` | Summarize context and clear history |\n\n## Slash Commands — Information\n\n| Command | Description |\n|---------|-------------|\n| `/help` | Show help |\n| `/status` | Session status |\n| `/commands` | List all commands |\n\n## Slash Commands — Modes\n\n| Command | Description |\n|---------|-------------|\n| `/plan` | Enable plan mode |\n| `/plan-off` | Disable plan mode |\n| `/bypass` | Enable bypass mode |\n| `/bypass-off` | Disable bypass mode |\n| `/model <name>` | Switch model |\n\n## Slash Commands — Configuration\n\n| Command | Description |\n|---------|-------------|\n| `/settings` | Interactive settings editor |\n| `/mcp` | MCP server manager |\n| `/skill` | Skill manager |\n| `/hooks` | Hook manager |\n| `/theme` | Theme selector |\n| `/connections` | Connection manager |\n\n## Slash Commands — Development\n\n| Command | Description |\n|---------|-------------|\n| `/add-dir <path>` | Add working directory |\n| `/sh <cmd>` | Execute shell command |\n| `/sql <query>` | Execute SQL |\n| `/table` | Fullscreen SQL results view |\n| `/diff` | Fullscreen git diff viewer |\n| `/tasks` | Active background tasks |\n| `/worktree` | Worktree manager |\n| `/sandbox` | Sandbox settings |\n\n## Slash Commands — Utilities\n\n| Command | Description |\n|---------|-------------|\n| `/fdbt` | dbt operations |\n| `/lineage <model>` | Model lineage |\n| `/agents` | Subagent manager |\n| `/setup-jupyter` | Setup Jupyter |\n| `/feedback` | Submit feedback |\n| `/clear-cache` | Clear caches |\n| `/doctor` | Diagnose environment issues |\n| `/update` | Update Cortex Code CLI |\n\n## Custom Slash Commands\n\nDefine custom commands as Markdown files. Loaded in priority order:\n\n1. **Project** — `.cortex/commands/`, `.claude/commands/`\n2. **Global** — `~/.snowflake/cortex/commands/`\n3. **User** — `~/.claude/commands/`\n\nEach `.md` file becomes a `/command` named after the file.\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code/references/configuration.md",
    "content": "# Configuration Reference\n\nSettings, environment variables, connections, skills, and hooks for Cortex Code.\n\n## Directory Structure\n\n```\n~/.snowflake/cortex/\n├── settings.json           # Main configuration\n├── skills.json             # Skills configuration\n├── permissions.json        # Permission history (auto-generated)\n├── hooks.json              # Hook configurations\n├── mcp.json                # MCP server configurations\n├── skills/                 # Global skills\n│   └── my-skill/\n│       └── SKILL.md\n├── agents/                 # Custom agent definitions\n├── commands/               # Custom slash commands\n└── conversations/          # Session history\n```\n\n## settings.json\n\nMain configuration file at `~/.snowflake/cortex/settings.json`:\n\n```json\n{\n  \"env\": {\n    \"CORTEX_AGENT_MODEL\": \"claude-sonnet-4-5\",\n    \"CORTEX_AGENT_ENABLE_SUBAGENTS\": true,\n    \"SNOVA_DEBUG\": false,\n    \"CORTEX_CHANNEL\": \"stable\"\n  },\n  \"diffDisplayMode\": \"unified\",\n  \"compactMode\": false,\n  \"bashDefaultTimeoutMs\": 180000,\n  \"theme\": \"dark\"\n}\n```\n\n| Key | Type | Description |\n|-----|------|-------------|\n| `diffDisplayMode` | `\"unified\"` \\| `\"side_by_side\"` | Diff display style |\n| `compactMode` | boolean | Start in compact UI mode |\n| `bashDefaultTimeoutMs` | number | Default bash timeout (ms) |\n| `theme` | `\"dark\"` \\| `\"light\"` \\| `\"pro\"` | UI color theme |\n\n## Environment Variables\n\n### Core\n\n| Variable | Description |\n|----------|-------------|\n| `CORTEX_CODE_STREAMING` | Enable live streaming mode |\n| `CORTEX_ENABLE_MEMORY` | Enable memory tool |\n| `CORTEX_ENABLE_EXPERIMENTAL_SKILLS` | Enable experimental skills |\n| `CORTEX_AGENT_ENABLE_SUBAGENTS` | Enable subagent spawning |\n\n### Snowflake\n\n| Variable | Description |\n|----------|-------------|\n| `SNOWFLAKE_CONNECTION` | Default connection name |\n| `SNOWFLAKE_ACCOUNT` | Snowflake account |\n| `SNOWFLAKE_USER` | Snowflake username |\n| `SNOWFLAKE_WAREHOUSE` | Default warehouse |\n| `SNOWFLAKE_DATABASE` | Default database |\n| `SNOWFLAKE_SCHEMA` | Default schema |\n\n### Priority Order\n\n1. **CLI flags** (highest)\n2. **Environment variables**\n3. **settings.json**\n4. **Built-in defaults** (lowest)\n\n## Skills System\n\nSkills are reusable instruction sets that guide the agent. Invoked with `$skill-name`.\n\n### Skill Locations (Priority Order)\n\n| Priority | Location |\n|----------|----------|\n| 1 | `.cortex/skills/`, `.claude/skills/` (project) |\n| 2 | `~/.snowflake/cortex/skills/` (global) |\n| 3 | Remote (cached from repositories) |\n| 4 | Bundled (shipped with Cortex Code) |\n\n### SKILL.md Format\n\n```markdown\n---\nname: my-skill\ndescription: \"Purpose. Use when: situations. Triggers: keywords.\"\ntools: [\"bash\", \"edit\"]\n---\n\n# My Skill\n\n## Workflow\n1. Step one\n2. Step two\n```\n\n### Remote Skills\n\nConfigure in `~/.snowflake/cortex/skills.json`:\n\n```json\n{\n  \"paths\": [\"/path/to/additional/skills\"],\n  \"remote\": [\n    {\n      \"source\": \"https://github.com/org/skills-repo\",\n      \"ref\": \"main\",\n      \"skills\": [{ \"name\": \"skill-name\" }]\n    }\n  ]\n}\n```\n\n### Managing Skills\n\n```\n/skill                              # Interactive skill manager\n```\n\nPress `a` to add, view conflicts, sync project skills to global, or delete.\n\n## Hooks System\n\nHooks run custom code at specific points during execution.\n\n### Hook Events\n\n| Event | When | Use Case |\n|-------|------|----------|\n| `PreToolUse` | Before tool execution | Validate, block, modify tool calls |\n| `PostToolUse` | After tool execution | Log, validate outputs |\n| `UserPromptSubmit` | User submits prompt | Validate or transform input |\n| `Stop` | Agent stops | Verify completion |\n| `SessionStart` | Session begins | Initialize context |\n| `SessionEnd` | Session ends | Cleanup |\n| `PreCompact` | Before compaction | Inject context |\n\n### Configuration\n\nHooks are configured in `~/.snowflake/cortex/hooks.json`:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          { \"type\": \"command\", \"command\": \"/path/to/validator.sh\", \"timeout\": 30 }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Matchers\n\n| Pattern | Matches |\n|---------|---------|\n| `Bash` | Exact tool name |\n| `Bash\\|Edit` | Bash or Edit |\n| `.*` or `*` | All tools |\n| `snowflake_.*` | All Snowflake tools |\n| `mcp__github__.*` | All GitHub MCP tools |\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success, continue |\n| 2 | Block the operation (stderr sent to agent) |\n| Other | Non-blocking error (shown to user) |\n\n### Hook Input\n\nHooks receive JSON on stdin with fields: `session_id`, `transcript_path`, `cwd`, `permission_mode`, `hook_event_name`. Tool events add `tool_name`, `tool_input`.\n\n### Managing Hooks\n\n```\n/hooks                              # Interactive hook manager\n```\n\n## Theme Configuration\n\n```\n/theme                              # Interactive theme selector\n/theme dark                         # Set dark theme\n/theme light                        # Set light theme\n```\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code/references/mcp-and-agents.md",
    "content": "# MCP and Agents Reference\n\nExtending Cortex Code with MCP servers and autonomous subagents.\n\n## MCP (Model Context Protocol)\n\nMCP connects Cortex Code to external services, databases, APIs, and tools.\n\n### Managing Servers\n\n```bash\ncortex mcp add <name> <command>         # Add server\ncortex mcp list                         # List all servers\ncortex mcp remove <name>                # Remove server\ncortex mcp show <name>                  # Show server details\n/mcp                                    # Interactive manager\n```\n\n### Configuration\n\nMCP servers are configured in `~/.snowflake/cortex/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"github\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-github\"],\n      \"env\": { \"GITHUB_TOKEN\": \"${GITHUB_TOKEN}\" },\n      \"transport\": \"stdio\",\n      \"timeout\": 60000\n    }\n  }\n}\n```\n\n### Config Fields\n\n| Field | Description |\n|-------|-------------|\n| `command` | Command to start server |\n| `args` | Command arguments |\n| `env` | Environment variables (`${VAR}` for expansion) |\n| `transport` | `stdio` (default), `sse`, or `http` |\n| `timeout` | Connection timeout in ms |\n| `url` | Server URL (for SSE/HTTP) |\n| `headers` | HTTP headers (for SSE/HTTP) |\n\n### Transport Types\n\n| Type | Use Case | Key Config |\n|------|----------|------------|\n| `stdio` | Local process | `command`, `args` |\n| `sse` | Remote SSE server | `url`, `headers` |\n| `http` | Remote HTTP API | `url`, `headers` |\n\n### Adding Servers\n\n```bash\n# stdio\ncortex mcp add my-server -- npx -y @scope/mcp-server\n\n# With env vars\ncortex mcp add my-server -e API_KEY=secret -- npx -y @scope/mcp-server\n\n# SSE\ncortex mcp add my-server --transport sse https://example.com/sse\n\n# HTTP with auth header\ncortex mcp add my-server --transport http -H \"Authorization: Bearer token\" https://example.com/api\n```\n\n### Common MCP Servers\n\n```bash\n# GitHub\ncortex mcp add github -e GITHUB_TOKEN=$GITHUB_TOKEN -- npx -y @modelcontextprotocol/server-github\n\n# Filesystem\ncortex mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem ~/Documents\n\n# PostgreSQL\ncortex mcp add postgres -e DATABASE_URL=$DATABASE_URL -- npx -y @modelcontextprotocol/server-postgres\n```\n\n### MCP Tool Naming\n\nTools follow the pattern `mcp__<server>__<tool>`. Example: `mcp__github__create_issue`.\n\n### Disabling MCP\n\n```bash\ncortex --no-mcp                         # Start without MCP\n```\n\n## Subagents\n\nCortex Code spawns autonomous child agents for complex, multi-step tasks.\n\n### Built-in Agent Types\n\n| Type | Description | Capabilities |\n|------|-------------|--------------|\n| `general-purpose` | Multi-step tasks, code changes | All tools |\n| `Explore` | Fast codebase exploration | Read-only |\n| `Plan` | Architecture and implementation planning | Read-only |\n| `feedback` | Collect and process user feedback | Ask questions |\n| `dbt-verify` | dbt project verification | All tools |\n\n### Explore Agent Thoroughness\n\nWhen asking for exploration, specify a level:\n- `\"quick\"` — basic file/keyword search\n- `\"medium\"` — moderate exploration across related files\n- `\"very thorough\"` — comprehensive multi-location analysis\n\n### Background Execution\n\nAgents can run in background while you continue working:\n- Use `/agents` to view status and manage running agents\n- Background agents return an `agent_id` for retrieving results later\n- Background agents cannot spawn other background agents\n\n### Custom Agents\n\nDefine custom agents as Markdown files with YAML frontmatter:\n\n```markdown\n---\nname: my-agent\ndescription: \"What this agent does. Triggers: relevant keywords.\"\ntools: [\"Bash\", \"Read\", \"Edit\"]\n---\n\n# My Agent\n\nInstructions for the agent (used as the system prompt).\n```\n\n### Loading Locations (Priority Order)\n\n| Priority | Location |\n|----------|----------|\n| 1 | `~/.snowflake/cortex/agents/` (global) |\n| 2 | `~/.claude/agents/` (global, compatibility) |\n| 3 | `.cortex/agents/` (project-local) |\n| 4 | `.claude/agents/` (project-local, compatibility) |\n\n### Worktree Isolation\n\nFor parallel agent work without file conflicts:\n\n```bash\ncortex worktree create <name>           # Create worktree\ncortex worktree list                    # List worktrees\ncortex --worktree <name>               # Start session in worktree\n```\n\n### /agents Command\n\n```\n/agents\n```\n\nOpens a fullscreen tabbed interface showing available agent types, active sessions, and management options.\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code/references/snowflake-tools.md",
    "content": "# Snowflake-Native Tools Reference\n\nCortex Code integrates directly with Snowflake for SQL execution, object discovery, semantic analysis, and artifact management.\n\n## #TABLE Context Injection\n\nType `#` followed by a fully-qualified 3-part table name to auto-inject metadata into your prompt:\n\n```\nAnalyze the data in #MY_DB.PUBLIC.USERS\n```\n\nThis fetches and injects:\n- Column metadata (name, type, nullable, default, comment)\n- Primary keys\n- Approximate row count\n- Up to 3 sample rows\n\nAutocomplete is available after typing `#`. Names are case-insensitive.\n\n## SQL Execution\n\n### /sql Slash Command\n\n```\n/sql SELECT COUNT(*) FROM my_table\n```\n\nRuns SQL inline. Use `/table` or `Ctrl+T` for a fullscreen table view of results.\n\n### Agent SQL Execution\n\nThe agent executes SQL autonomously when needed via the `snowflake_sql_execute` tool:\n- Runs on the active Snowflake connection\n- Handles large result sets with truncation\n- Auto-refreshes expired tokens\n- Supports `only_compile` mode for validation without execution\n\n## Object Search\n\nSearch for Snowflake objects using semantic (natural language) search:\n\n```bash\ncortex search object \"user activity tables\"\ncortex search object \"revenue\" --types=table,view\n```\n\nSearches across databases, schemas, tables, views, semantic views, and functions.\n\n## Cortex Analyst\n\nConvert natural language questions to SQL using semantic models or semantic views:\n\n```bash\n# Using a local YAML semantic model\ncortex analyst query \"What were total sales last quarter?\" --model=sales_model.yaml\n\n# Using a semantic view\ncortex analyst query \"Top customers by spend\" --view=ANALYTICS.CORE.REVENUE_METRICS\n\n# Validate a semantic model file\ncortex reflect revenue.yaml\ncortex reflect revenue.yaml --target-schema DB.SCHEMA\n```\n\nReturns generated SQL, explanation, and suggested follow-up questions.\n\n## Semantic Views\n\nSemantic views are curated data models with business-friendly definitions built on top of raw tables.\n\n```bash\ncortex semantic-views discover              # Find all semantic views in account\ncortex semantic-views list [--limit=N]      # List views\ncortex semantic-views describe <view>       # Show dimensions, facts, metrics\ncortex semantic-views search \"revenue\"      # Search by keyword\ncortex semantic-views ddl <view>            # Show SQL DDL definition\ncortex semantic-views query <view>          # Execute query against view\n```\n\n**Best practice:** Before writing complex SQL for business analytics, check if a semantic view exists. Semantic views provide verified business definitions more reliable than raw SQL.\n\n## Cortex Agent Discovery\n\nCortex Agents contain curated instructions about which data sources to use:\n\n```bash\ncortex agents discover                      # Find all agents in account\ncortex agents list [--database DB]          # List agents in scope\ncortex agents describe <agent>              # Show instructions, tools, data sources\ncortex agents search \"revenue\"              # Search by domain\n```\n\n## Product Docs Search\n\n```bash\ncortex search docs \"how to create a stored procedure\"\ncortex search docs \"dynamic tables target lag\"\n```\n\nSearches Snowflake product documentation and returns relevant results.\n\n## Artifact Creation\n\nUpload files to Snowflake Workspace:\n\n```bash\ncortex artifact create notebook my_analysis ./analysis.ipynb\ncortex artifact create file my_report ./report.csv\n```\n\nSupports notebooks (`.ipynb`) and generic files. Default workspace: `USER$.PUBLIC.DEFAULT$`.\n\n## Connection Management\n\n### CLI\n\n```bash\ncortex connections list             # List configured connections\ncortex connections set <name>       # Switch active connection\ncortex --connection <name>          # Start with specific connection\n```\n\n### /connections\n\nOpens an interactive fullscreen connection manager.\n\n### connections.toml\n\nConnections are defined in `~/.snowflake/connections.toml`:\n\n```toml\n[default]\naccount = \"myaccount\"\nuser = \"myuser\"\nauthenticator = \"externalbrowser\"\ndatabase = \"MYDB\"\nschema = \"PUBLIC\"\nwarehouse = \"COMPUTE_WH\"\nrole = \"DEVELOPER\"\n\n[prod]\naccount = \"myaccount\"\nuser = \"myuser\"\nauthenticator = \"snowflake_jwt\"\nprivate_key_path = \"~/.snowflake/rsa_key.p8\"\ndatabase = \"PROD_DB\"\nschema = \"PUBLIC\"\nwarehouse = \"PROD_WH\"\nrole = \"ANALYST\"\n```\n\n### Authentication Methods\n\n| Method | Value |\n|--------|-------|\n| Browser SSO | `externalbrowser` |\n| Key-pair | `snowflake_jwt` |\n| Password | `snowflake` |\n| OAuth | `oauth` |\n| Programmatic access token | `PROGRAMMATIC_ACCESS_TOKEN` |\n\n## Source Command\n\nRun a command with Snowflake credentials injected as environment variables:\n\n```bash\ncortex source <connection> --map account=SF_ACCOUNT --map user=SF_USER -- python myscript.py\ncortex source myconn --map password=SNOWFLAKE_PASS -- dbt run\n```\n\nAvailable fields: `account`, `user`, `password`, `authenticator`, `warehouse`, `database`, `schema`, `role`, `host`, `token`.\n"
  },
  {
    "path": "content/snowflake/docs/cortex-code-snowsight/DOC.md",
    "content": "---\nname: cortex-code-snowsight\ndescription: \"Cortex Code in Snowsight — Snowflake's agentic AI assistant embedded in the web UI for SQL authoring, code review, data exploration, and account administration\"\nmetadata:\n  languages: \"sql\"\n  versions: \"2026-03\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,cortex,snowsight,ai,coding-assistant,sql,workspaces,code-review\"\n---\n\n# Cortex Code in Snowsight\n\nCortex Code is an agentic AI assistant embedded directly in Snowsight (Snowflake's web UI). It translates natural language instructions into executable actions across SQL development, data exploration, and account administration — all without leaving the browser.\n\n## Access\n\n1. Sign in to Snowsight.\n2. Select the **Cortex Code** icon in the lower-right corner.\n3. Type a natural language prompt and press Enter.\n\nIf the response includes SQL, you can execute it directly or copy to clipboard.\n\n## Access Control\n\n| Database Role | Notes |\n|---------------|-------|\n| `SNOWFLAKE.COPILOT_USER` | Required for all users |\n| `SNOWFLAKE.CORTEX_USER` or `SNOWFLAKE.CORTEX_AGENT_USER` | At least one required; `CORTEX_AGENT_USER` enables agentic workflows |\n\n```sql\n-- Grant access (run as ACCOUNTADMIN)\nGRANT DATABASE ROLE SNOWFLAKE.COPILOT_USER TO ROLE my_role;\nGRANT DATABASE ROLE SNOWFLAKE.CORTEX_AGENT_USER TO ROLE my_role;\n```\n\n## Key Capabilities\n\n### Agentic Coding in Workspaces\n\n- **Code generation**: Generate SQL queries, create files, build data pipeline logic\n- **Code modification**: Refine SQL, identify errors, suggest performance optimizations\n- **Change review**: Preview AI changes using a diff view before applying\n- **Code explanation**: Request explanations of existing SQL for understanding or collaboration\n- **Follow-up questions**: Continue conversations for clarifying or deeper analysis\n- **Inline catalog context**: Type `@` in the message box to search for and add catalog objects (tables, schemas, views) as context\n- **Quick actions**: Highlight SQL text to access Quick Edit, Format, Add to Chat, and Explain\n- **Fix SQL errors**: Use the Fix button in the results grid when a SQL statement fails\n\n### AI Code Suggestions (Preview)\n\nContext-aware inline SQL suggestions displayed as gray text at cursor position. Cortex Code uses query history, workspace content, table schemas, and recent executed queries.\n\n- **Accept**: `Shift + Enter`\n- **Dismiss**: `Esc`, `Delete`, `Backspace`, or keep typing\n- **Disable**: Workspaces → SQL file → Settings → User preferences → AI code suggestions toggle\n\n### Data and Catalog Discovery\n\n- **Natural language schema search**: Find database objects using plain language\n- **Integrated Q&A**: Get answers about Snowflake features and SQL syntax from official docs\n- **Marketplace discovery**: Search and return listings from Snowflake Marketplace\n- **Tag, masking policy, and lineage context** included when available\n\n### Account Administration\n\n- **Governance & security**: User and role access, data ownership, PII identification\n- **Cost management**: Credit consumption, high-cost warehouses and queries\n\n## Example Prompts\n\n### SQL Development\n\n| Use Case | Prompt |\n|----------|--------|\n| Logic explanation | \"What does this SQL script do?\" |\n| Generation | \"Write a query for top 10 customers by revenue and a 7-day moving average.\" |\n| Query refinement | \"Update the top performers query to show the top 100.\" |\n| Performance optimization | \"Explain why this query is slow and optimize it.\" |\n| Data synthesis | \"Generate synthetic data for 30 days of sales for an e-commerce site in the SAMPLEDATA.SALES table.\" |\n\n### Data Discovery and Governance\n\n| Use Case | Prompt |\n|----------|--------|\n| Access discovery | \"What databases do I have access to?\" |\n| Security auditing | \"Find all tables that have PII in them.\" |\n| Tag discovery | \"List every table tagged PII = TRUE in ANALYTICS_DB.\" |\n| Lineage and tagging | \"Show the lineage from RAW_DB.ORDERS to downstream dashboards.\" |\n| Metadata search | \"Where can I find tables related to customer churn and subscription status?\" |\n\n### Notebooks and ML\n\n| Use Case | Prompt |\n|----------|--------|\n| EDA & ML | \"Build me a notebook for customer churn prediction using pandas, matplotlib, seaborn, and scikit-learn.\" |\n| Deep learning | \"Create a new notebook and build a CNN for the MNIST dataset.\" |\n| Pipeline engineering | \"Create a dbt project to transform raw sales data.\" |\n\n### Semantic Models\n\n| Use Case | Prompt |\n|----------|--------|\n| Semantic queries | \"Use the @models/revenue.yaml semantic model to answer 'What was revenue last month?'\" |\n| Model debugging | \"Identify errors in my semantic model at @models/revenue.yaml\" |\n\n### Administration\n\n| Use Case | Prompt |\n|----------|--------|\n| Resource monitoring | \"Which 5 service types are using the most credits? Show me a visualization and how to reduce costs.\" |\n\n## Supported Models\n\n- **Claude Opus 4.6** (`claude-opus-4-6`) — recommended\n- Claude Opus 4.5 (`claude-opus-4-5`)\n- Claude Sonnet 4.5 (`claude-sonnet-4-5`)\n- Claude Sonnet 4.0 (`claude-4-sonnet`)\n\n## Cross-Region Inference\n\nCortex Code works in any region when cross-region inference is enabled:\n\n```sql\n-- Run as ACCOUNTADMIN\nALTER ACCOUNT SET CORTEX_ENABLED_CROSS_REGION = 'AWS_US';\n```\n\nReplace `AWS_US` with: `AWS_EU`, `AWS_APJ`, or `ANY_REGION`.\n\n## Web Search\n\nAn ACCOUNTADMIN can enable web search for Cortex Code:\n\n1. Navigate to **AI/ML → Agents**\n2. Select **Settings**\n3. Toggle **Web search** to enable\n\n## Cortex Code vs Snowflake Intelligence vs Copilot (Legacy)\n\n| Feature | Cortex Code | Snowflake Intelligence | Copilot (Legacy) |\n|---------|-------------|----------------------|------------------|\n| Use case | SQL authoring, data exploration, admin tasks | Natural language data analysis and insights | Basic SQL assistance (deprecated) |\n| Integration | Snowsight Workspaces | Intelligence UI, Cortex Agents API | Separate copilot panel |\n| Key capabilities | Code gen/modify, diff review, code explanation | Data analysis, summaries, NL interactions | Contextual SQL suggestions |\n\n## Prerequisites\n\n- Snowflake account (Commercial — not Gov, VPS, or Sovereign)\n- Required database roles: `SNOWFLAKE.COPILOT_USER` + `SNOWFLAKE.CORTEX_USER` or `SNOWFLAKE.CORTEX_AGENT_USER`\n- Cross-region inference enabled if your model is not available in your region\n"
  },
  {
    "path": "content/snowflake/docs/cortex-search/DOC.md",
    "content": "---\nname: cortex-search\ndescription: \"Snowflake Cortex Search — managed hybrid search service for RAG applications, enterprise search, with automatic indexing and refresh\"\nmetadata:\n  languages: \"sql,python\"\n  versions: \"2026-03\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,cortex,search,rag,hybrid-search,vector-search,embeddings,retrieval\"\n---\n\n# Cortex Search\n\nCortex Search is a fully managed hybrid (vector + keyword) search engine for Snowflake data. It powers RAG applications and enterprise search with automatic embedding, index management, and refresh — no infrastructure to maintain.\n\n## Use Cases\n\n- **RAG engine for LLM chatbots**: Semantic retrieval for grounding LLM responses in your data\n- **Enterprise search**: High-quality search bar backend for applications\n\n## Quick Start\n\n### 1. Create Source Data\n\n```sql\nCREATE DATABASE IF NOT EXISTS cortex_search_db;\nCREATE OR REPLACE SCHEMA cortex_search_db.services;\n\nCREATE OR REPLACE TABLE support_transcripts (\n  transcript_text VARCHAR,\n  region VARCHAR,\n  agent_id VARCHAR\n);\n\nINSERT INTO support_transcripts VALUES\n  ('My internet has been down since yesterday, can you help?', 'North America', 'AG1001'),\n  ('I was overcharged for my last bill, need an explanation.', 'Europe', 'AG1002'),\n  ('How do I reset my password? The email link is not working.', 'Asia', 'AG1003'),\n  ('I received a faulty router, can I get it replaced?', 'North America', 'AG1004');\n```\n\n### 2. Create Search Service\n\n```sql\nCREATE OR REPLACE CORTEX SEARCH SERVICE transcript_search_service\n  ON transcript_text\n  ATTRIBUTES region\n  WAREHOUSE = cortex_search_wh\n  TARGET_LAG = '1 day'\n  EMBEDDING_MODEL = 'snowflake-arctic-embed-l-v2.0'\n  AS (\n    SELECT transcript_text, region, agent_id\n    FROM support_transcripts\n  );\n```\n\nKey parameters:\n- `ON`: Column to search against\n- `ATTRIBUTES`: Columns available as filter attributes and returned in results\n- `TARGET_LAG`: How often the index refreshes from base data (e.g., `'1 hour'`, `'1 day'`)\n- `EMBEDDING_MODEL`: Model used to generate embeddings\n- `WAREHOUSE`: Used for materializing the source query\n\n### 3. Grant Access\n\n```sql\nGRANT USAGE ON DATABASE cortex_search_db TO ROLE customer_support;\nGRANT USAGE ON SCHEMA services TO ROLE customer_support;\nGRANT USAGE ON CORTEX SEARCH SERVICE transcript_search_service TO ROLE customer_support;\n```\n\n### 4. Preview Results (SQL)\n\n```sql\nSELECT PARSE_JSON(\n  SNOWFLAKE.CORTEX.SEARCH_PREVIEW(\n    'cortex_search_db.services.transcript_search_service',\n    '{\n      \"query\": \"internet issues\",\n      \"columns\": [\"transcript_text\", \"region\"],\n      \"filter\": {\"@eq\": {\"region\": \"North America\"}},\n      \"limit\": 1\n    }'\n  )\n)['results'] AS results;\n```\n\n### 5. Query from Python\n\n```python\nfrom snowflake.core import Root\nfrom snowflake.snowpark import Session\n\nsession = Session.builder.configs(CONNECTION_PARAMS).create()\nroot = Root(session)\n\nsearch_service = (\n    root\n    .databases[\"cortex_search_db\"]\n    .schemas[\"services\"]\n    .cortex_search_services[\"transcript_search_service\"]\n)\n\nresults = search_service.search(\n    query=\"internet issues\",\n    columns=[\"transcript_text\", \"region\"],\n    filter={\"@eq\": {\"region\": \"North America\"}},\n    limit=5\n)\nprint(results.to_json())\n```\n\n## Creating via Snowsight\n\n1. Navigate to **AI & ML → AI Studio**\n2. Select **+ Create** from the Cortex Search Service box\n3. Choose role, warehouse, database, and schema\n4. Select the source table and search columns\n5. Set filter columns and target lag\n6. Create the service\n\n## Query Filters\n\nFilter search results using attribute columns:\n\n```json\n{\n  \"query\": \"billing problem\",\n  \"columns\": [\"transcript_text\", \"region\", \"agent_id\"],\n  \"filter\": {\n    \"@and\": [\n      {\"@eq\": {\"region\": \"North America\"}},\n      {\"@eq\": {\"agent_id\": \"AG1001\"}}\n    ]\n  },\n  \"limit\": 10\n}\n```\n\nSupported operators: `@eq`, `@and`, `@or`, `@not`, `@gte`, `@lte`, `@gt`, `@lt`.\n\n## Inspecting Service Data\n\n```sql\nSELECT * FROM TABLE(\n  CORTEX_SEARCH_DATA_SCAN(SERVICE_NAME => 'transcript_search_service')\n);\n```\n\n## RAG Architecture\n\nCombine Cortex Search with Cortex AI Functions for RAG:\n\n```python\n# 1. Retrieve relevant context\nresults = search_service.search(query=user_question, columns=[\"text\"], limit=5)\ncontext = \"\\n\".join([r[\"text\"] for r in results.results])\n\n# 2. Generate grounded response\nfrom snowflake.cortex import Complete\nresponse = Complete(\"claude-4-sonnet\", f\"Answer based on this context:\\n{context}\\n\\nQuestion: {user_question}\")\n```\n\n## Access Control\n\n- Creating a service requires `SNOWFLAKE.CORTEX_USER` database role\n- The warehouse specified is used during index build and refresh\n- Grant `USAGE` on the service to allow other roles to query it\n\n## Key Considerations\n\n- Index build time depends on dataset size and warehouse size (use dedicated warehouse, size MEDIUM or smaller)\n- `TARGET_LAG` controls freshness vs. cost tradeoff\n- Columns in `ATTRIBUTES` must be included in the source query\n- Services automatically refresh when base data changes\n- Supports both SQL and Python query interfaces\n\n## Prerequisites\n\n- Snowflake account with `SNOWFLAKE.CORTEX_USER` database role\n- A warehouse for index materialization\n- Source table with text data to search\n"
  },
  {
    "path": "content/snowflake/docs/snowflake-notebooks/DOC.md",
    "content": "---\nname: snowflake-notebooks\ndescription: \"Snowflake Notebooks — interactive cell-based development environment for SQL, Python, and Markdown with Snowpark integration, ML workflows, and scheduled pipelines\"\nmetadata:\n  languages: \"sql,python\"\n  versions: \"2026-03\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,notebooks,python,sql,data-science,ml,snowpark,visualization,pipelines\"\n---\n\n# Snowflake Notebooks\n\nSnowflake Notebooks is an interactive, cell-based development environment in Snowsight for SQL, Python, and Markdown. Build data pipelines, train ML models, create visualizations, and schedule automated workflows — all on Snowflake compute.\n\n## Key Features\n\n- **Multi-language cells**: SQL, Python, and Markdown in the same notebook\n- **Cross-cell references**: Use SQL results in Python cells and vice versa\n- **Built-in visualizations**: Streamlit, Altair, Matplotlib, seaborn\n- **Git integration**: Sync notebooks with Git repositories (Preview)\n- **Scheduling**: Run notebooks as automated tasks on a schedule (Preview)\n- **Role-based access**: Leverage Snowflake RBAC for collaboration\n- **File uploads**: Load data from local files, cloud storage, or Snowflake Marketplace\n\n## Notebook Runtimes\n\n| Feature | Warehouse Runtime | Container Runtime |\n|---------|-------------------|-------------------|\n| Compute | Notebook warehouse | Compute pool node |\n| Python version | 3.9, 3.10 (Preview) | 3.10 |\n| Base image | Streamlit + Snowpark | Container Runtime (CPU/GPU with pre-installed ML packages) |\n| Package install | Snowflake Anaconda or stage | pip, conda, or stage |\n| Best for | SQL analytics, Snowpark | ML, deep learning, custom packages |\n\nBoth runtimes execute SQL and Snowpark queries on the warehouse.\n\n### Choose Warehouse Runtime When\n\n- Doing SQL analytics and data engineering\n- Using Snowpark DataFrames and UDFs\n- Standard Python packages available in Snowflake Anaconda suffice\n\n### Choose Container Runtime When\n\n- Training ML/deep learning models (GPU support)\n- Need custom pip/conda packages not in Anaconda\n- Running compute-intensive Python workloads\n\n## Getting Started\n\n### Create a Notebook\n\n1. Sign in to Snowsight\n2. Navigate to **Projects → Notebooks** (Legacy) or **Projects → Workspaces** (New)\n3. Select **+ Notebook**\n4. Choose a database, schema, warehouse, and runtime\n\n### Cell Types\n\n**SQL Cell**:\n```sql\n-- Results available as a DataFrame in Python cells\nSELECT region, SUM(revenue) AS total_revenue\nFROM sales\nGROUP BY region\nORDER BY total_revenue DESC;\n```\n\n**Python Cell**:\n```python\n# Reference SQL cell results\nimport streamlit as st\n\n# cell1 refers to the SQL cell above\ndf = cell1.to_pandas()\nst.bar_chart(df.set_index(\"REGION\"))\n```\n\n**Markdown Cell**:\n```markdown\n## Analysis Summary\nKey findings from the revenue analysis...\n```\n\n### Cross-Cell References\n\nSQL cell results are automatically available as Snowpark DataFrames in Python cells:\n\n```python\n# If a SQL cell named \"revenue_query\" exists:\ndf = revenue_query.to_pandas()\nprint(df.head())\n```\n\nPython variables can be referenced in SQL cells:\n\n```sql\n-- Reference Python variable\nSELECT * FROM my_table WHERE date > '{{start_date}}'\n```\n\n## Python Packages\n\n### Warehouse Runtime\n\n```python\n# Use the package selector in the toolbar, or:\n# Install from Snowflake Anaconda channel\n# Available packages: pandas, numpy, scikit-learn, matplotlib, seaborn, etc.\n```\n\n### Container Runtime\n\n```python\n!pip install transformers torch\n```\n\n## Visualizations\n\n### Streamlit (Built-in)\n\n```python\nimport streamlit as st\n\nst.title(\"Sales Dashboard\")\nst.bar_chart(df)\nst.line_chart(df.set_index(\"date\")[\"revenue\"])\nst.dataframe(df)\n```\n\n### Matplotlib / Seaborn\n\n```python\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfig, ax = plt.subplots()\nsns.barplot(data=df, x=\"region\", y=\"revenue\", ax=ax)\nst.pyplot(fig)\n```\n\n### Altair\n\n```python\nimport altair as alt\n\nchart = alt.Chart(df).mark_bar().encode(x=\"region\", y=\"revenue\")\nst.altair_chart(chart)\n```\n\n## ML Workflows\n\n### Training with scikit-learn\n\n```python\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\n\n# Get data from SQL cell\ndf = training_data.to_pandas()\nX = df[[\"feature1\", \"feature2\", \"feature3\"]]\ny = df[\"label\"]\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\nmodel = RandomForestClassifier(n_estimators=100)\nmodel.fit(X_train, y_train)\n\naccuracy = accuracy_score(y_test, model.predict(X_test))\nst.metric(\"Model Accuracy\", f\"{accuracy:.2%}\")\n```\n\n### Using Snowpark ML\n\n```python\nfrom snowflake.ml.modeling.ensemble import RandomForestClassifier as SnowRF\n\nmodel = SnowRF(input_cols=[\"F1\", \"F2\", \"F3\"], label_cols=[\"LABEL\"])\nmodel.fit(snowpark_df)\npredictions = model.predict(test_df)\n```\n\n## Scheduling\n\nRun notebooks on a schedule as Snowflake tasks:\n\n1. Select the **Scheduler** icon in the notebook toolbar\n2. Set a CRON schedule (e.g., daily at 6 AM)\n3. The notebook runs as a task using the notebook's warehouse\n\n```sql\n-- Or create via SQL\nCREATE OR REPLACE TASK run_etl_notebook\n  WAREHOUSE = COMPUTE_WH\n  SCHEDULE = 'USING CRON 0 6 * * * America/Los_Angeles'\nAS\n  EXECUTE NOTEBOOK mydb.myschema.etl_notebook;\n```\n\n## Notebooks in Workspaces (New)\n\nThe next generation of Snowflake Notebooks lives in **Workspaces** with:\n- Full Jupyter compatibility\n- Workspace integration alongside SQL files, Python files, and dbt projects\n- Enhanced collaboration features\n\nLegacy Notebooks will be migrated to Workspaces over the coming quarters.\n\n## Toolbar Controls\n\n| Control | Description |\n|---------|-------------|\n| **Package selector** | Install Python packages |\n| **Start / Active** | Start session or view session details |\n| **Run All / Stop** | Execute all cells or stop execution |\n| **Scheduler** | Set automated run schedule |\n| **Collapse results** | Toggle code/output visibility |\n\n## Git Integration (Preview)\n\nSync notebooks with a Git repository for version control:\n\n1. Connect your Git provider in Snowsight\n2. Link the notebook to a repository\n3. Push/pull changes to keep notebooks in sync\n\n## Prerequisites\n\n- Snowflake account with access to Snowsight\n- Warehouse for compute (Warehouse Runtime) or compute pool (Container Runtime)\n- Appropriate role with CREATE NOTEBOOK privileges\n- For Container Runtime: SPCS compute pool configured\n"
  },
  {
    "path": "content/snowflake/docs/snowpark-python/DOC.md",
    "content": "---\nname: snowpark-python\ndescription: \"Snowpark Python — DataFrame API, UDFs, stored procedures, and pandas on Snowflake for building data pipelines and ML workflows without moving data\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.x\"\n  revision: 1\n  updated-on: \"2026-03-17\"\n  source: community\n  tags: \"snowflake,snowpark,python,dataframe,udf,stored-procedure,pandas,ml,data-engineering\"\n---\n\n# Snowpark Python\n\nSnowpark provides a Python API for querying and processing data in Snowflake without moving data out of the platform. Build data pipelines, write UDFs, create stored procedures, and run pandas code directly on Snowflake compute.\n\n## Setup\n\n### Install\n\n```bash\npip install snowflake-snowpark-python\n```\n\n### Create a Session\n\n```python\nfrom snowflake.snowpark import Session\n\nconnection_params = {\n    \"account\": \"myaccount\",\n    \"user\": \"myuser\",\n    \"password\": \"mypassword\",\n    \"warehouse\": \"COMPUTE_WH\",\n    \"database\": \"MYDB\",\n    \"schema\": \"PUBLIC\",\n    \"role\": \"DEVELOPER\"\n}\n\nsession = Session.builder.configs(connection_params).create()\n```\n\nAuthentication supports password, key-pair, SSO (`externalbrowser`), OAuth, and programmatic access tokens.\n\n## DataFrames\n\nSnowpark DataFrames are lazily evaluated — transformations build a query plan that executes on Snowflake when you trigger an action.\n\n### Basic Operations\n\n```python\n# Read a table\ndf = session.table(\"customers\")\n\n# Select, filter, aggregate\nresult = (\n    df.select(\"name\", \"region\", \"revenue\")\n      .filter(df[\"revenue\"] > 1000)\n      .group_by(\"region\")\n      .agg(sum(\"revenue\").alias(\"total_revenue\"))\n      .sort(\"total_revenue\", ascending=False)\n)\n\nresult.show()\n```\n\n### Joins\n\n```python\norders = session.table(\"orders\")\ncustomers = session.table(\"customers\")\n\njoined = orders.join(customers, orders[\"customer_id\"] == customers[\"id\"])\njoined.select(\"order_id\", \"name\", \"amount\").show()\n```\n\n### Writing Data\n\n```python\n# Write DataFrame to a table\ndf.write.mode(\"overwrite\").save_as_table(\"output_table\")\n\n# Append\ndf.write.mode(\"append\").save_as_table(\"output_table\")\n```\n\n### SQL Interop\n\n```python\n# Run raw SQL and get a DataFrame\ndf = session.sql(\"SELECT * FROM my_table WHERE date > '2024-01-01'\")\ndf.show()\n```\n\n## User-Defined Functions (UDFs)\n\n### Inline UDF\n\n```python\nfrom snowflake.snowpark.functions import udf\nfrom snowflake.snowpark.types import StringType\n\n@udf(name=\"categorize_amount\", return_type=StringType(), replace=True)\ndef categorize_amount(amount: float) -> str:\n    if amount > 10000:\n        return \"high\"\n    elif amount > 1000:\n        return \"medium\"\n    else:\n        return \"low\"\n\n# Use in a query\ndf = session.table(\"orders\")\ndf.select(\"order_id\", categorize_amount(\"amount\").alias(\"category\")).show()\n```\n\n### Vectorized UDF (Batch Processing)\n\n```python\nfrom snowflake.snowpark.functions import pandas_udf\nfrom snowflake.snowpark.types import IntegerType\nimport pandas as pd\n\n@pandas_udf(name=\"double_values\", return_type=IntegerType(), replace=True)\ndef double_values(series: pd.Series) -> pd.Series:\n    return series * 2\n```\n\n## User-Defined Table Functions (UDTFs)\n\n```python\nfrom snowflake.snowpark.functions import udtf\nfrom snowflake.snowpark.types import StructType, StructField, StringType\n\n@udtf(\n    name=\"split_words\",\n    output_schema=StructType([StructField(\"word\", StringType())]),\n    replace=True\n)\nclass SplitWords:\n    def process(self, text: str):\n        for word in text.split():\n            yield (word,)\n\n# Use it\nsession.table_function(\"split_words\", lit(\"hello world\")).show()\n```\n\n## Stored Procedures\n\n```python\nfrom snowflake.snowpark import Session\n\ndef process_data(session: Session, input_table: str, output_table: str) -> str:\n    df = session.table(input_table)\n    result = df.filter(df[\"status\"] == \"active\").group_by(\"region\").count()\n    result.write.mode(\"overwrite\").save_as_table(output_table)\n    return f\"Wrote {result.count()} rows to {output_table}\"\n\n# Register as stored procedure\nsession.sproc.register(\n    func=process_data,\n    name=\"process_data_sp\",\n    replace=True,\n    packages=[\"snowflake-snowpark-python\"]\n)\n\n# Call it\nsession.call(\"process_data_sp\", \"raw_customers\", \"processed_customers\")\n```\n\n### Schedule as a Task\n\n```sql\nCREATE OR REPLACE TASK daily_processing\n  WAREHOUSE = COMPUTE_WH\n  SCHEDULE = 'USING CRON 0 6 * * * America/Los_Angeles'\nAS\n  CALL process_data_sp('raw_customers', 'processed_customers');\n```\n\n## pandas on Snowflake\n\nRun pandas code that executes on Snowflake compute (not locally):\n\n```python\nimport modin.pandas as pd\nimport snowflake.snowpark.modin.plugin\n\n# Read from Snowflake\ndf = pd.read_snowflake(\"customers\")\n\n# Standard pandas operations — executed on Snowflake\nresult = df.groupby(\"region\")[\"revenue\"].mean()\nresult.to_snowflake(\"avg_revenue_by_region\", if_exists=\"replace\")\n```\n\n## Machine Learning\n\n### Train Models with Stored Procedures\n\n```python\nfrom snowflake.snowpark import Session\nfrom sklearn.linear_model import LogisticRegression\nimport pandas as pd\n\ndef train_model(session: Session) -> str:\n    df = session.table(\"training_data\").to_pandas()\n    X = df[[\"feature1\", \"feature2\", \"feature3\"]]\n    y = df[\"label\"]\n\n    model = LogisticRegression()\n    model.fit(X, y)\n\n    # Save model to stage\n    import joblib\n    joblib.dump(model, \"/tmp/model.pkl\")\n    session.file.put(\"/tmp/model.pkl\", \"@models\", auto_compress=False, overwrite=True)\n    return \"Model trained and saved\"\n\nsession.sproc.register(func=train_model, name=\"train_model_sp\", replace=True,\n    packages=[\"snowflake-snowpark-python\", \"scikit-learn\", \"joblib\", \"pandas\"])\n```\n\n## File Operations\n\n```python\n# Upload to stage\nsession.file.put(\"local_file.csv\", \"@my_stage\", auto_compress=False)\n\n# Read from stage\ndf = session.read.csv(\"@my_stage/data.csv\")\ndf = session.read.parquet(\"@my_stage/data.parquet\")\ndf = session.read.json(\"@my_stage/data.json\")\n```\n\n## Logging and Troubleshooting\n\n```python\n# View the generated SQL for any DataFrame\nprint(df.queries)\n\n# Enable logging\nimport logging\nlogging.basicConfig(level=logging.DEBUG)\n```\n\nRecord log messages and trace events to an event table for production monitoring.\n\n## Key Concepts\n\n- **Lazy evaluation**: DataFrame transformations build a plan; actions (`.show()`, `.collect()`, `.save_as_table()`) trigger execution\n- **Server-side execution**: UDFs and stored procedures run on Snowflake compute, not locally\n- **pandas on Snowflake**: Uses Modin + Snowpark to push pandas operations to Snowflake\n- **No data movement**: Data stays in Snowflake throughout the pipeline\n\n## Prerequisites\n\n- `pip install snowflake-snowpark-python`\n- Python 3.9+ (3.10 for some features)\n- Snowflake account with appropriate roles and warehouse access\n- For pandas on Snowflake: `pip install \"snowflake-snowpark-python[modin]\"`\n"
  },
  {
    "path": "content/soda-core/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Soda Core Python package and CLI guide for local data contract verification and data quality checks\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.0.7\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"soda,soda-core,data-quality,data-contracts,cli,validation\"\n---\n\n# Soda Core Python Package Guide\n\n## Golden Rule\n\nUse the current Soda v4 docs for workflow and syntax, but treat package naming carefully:\n\n- the Python import namespace is still `soda_core`\n- the CLI command is `soda`\n- current Soda v4 docs tell you to install `soda` or `soda-<data_source>` from Soda's public package index\n- the public PyPI page for `soda-core` is sparse and, as of March 12, 2026, exposes `4.0.7`, not the previous `4.1.1`\n\nIf a project is already pinned to `soda-core`, keep that pin consistent. For new v4 setups, prefer the official `soda` or `soda-<data_source>` install flow from the Soda docs.\n\n## Install\n\nCreate and activate a virtual environment first:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\n```\n\n### Recommended v4 install flow\n\nThe current Soda docs recommend installing from Soda's public package index and picking the package that matches your data source:\n\n```bash\npython -m pip install --index-url https://pypi.cloud.soda.io/simple \"soda-postgres>=4,<5\"\n```\n\nIf you want the general umbrella package described in the v4 docs:\n\n```bash\npython -m pip install --index-url https://pypi.cloud.soda.io/simple \"soda>=4,<5\"\n```\n\nNotes:\n\n- `soda` is the current v4 \"umbrella\" package in Soda's public index.\n- `soda-<data_source>` packages such as `soda-postgres`, `soda-bigquery`, and `soda-duckdb` are the practical installs for real work.\n- The docs say the public package index hosts the open-source Soda Core packages.\n\n### If the project explicitly depends on `soda-core`\n\nUse the public PyPI artifact that is actually available:\n\n```bash\npython -m pip install \"soda-core==4.0.7\"\n```\n\nUse this only when the environment is already pinned to `soda-core` or you intentionally want the package published on `pypi.org`. For new v4 automation, the official docs are written around the `soda` and `soda-<data_source>` names.\n\n## Initialize And Configure\n\nGenerate a starter data-source config:\n\n```bash\nsoda data-source create -f ds_config.yml\n```\n\nBy default, the generated template is for PostgreSQL. A minimal PostgreSQL config looks like:\n\n```yaml\ntype: postgres\nname: my_postgres\nconnection:\n  user: ${env.POSTGRES_USER}\n  host: ${env.POSTGRES_HOST}\n  port: 5432\n  password: ${env.POSTGRES_PW}\n  database: ${env.POSTGRES_DB}\n```\n\nTest the connection before writing or running contracts:\n\n```bash\nsoda data-source test --data-source ds_config.yml\n```\n\nSoda's data-source reference expects each config file to include:\n\n- `type`\n- `name`\n- `connection`\n\nUse environment variables for credentials rather than hardcoding secrets in YAML.\n\n## Connect To Soda Cloud\n\nSoda Cloud is optional for local verification, but required if you want to publish contracts or push verification results.\n\nCreate the config file:\n\n```bash\nsoda cloud create -f sc_config.yml\n```\n\nThen fill in the generated file with the API key material from Soda Cloud. The official docs say to create these keys from your avatar menu under `Profile > API Keys`.\n\nA minimal config shape looks like this:\n\n```yaml\nsoda_cloud:\n  host: cloud.us.soda.io\n  api_key_id: ${env.SODA_CLOUD_API_KEY_ID}\n  api_key_secret: ${env.SODA_CLOUD_API_KEY_SECRET}\n```\n\nUse `cloud.us.soda.io` for US-region organizations and the region-specific host your Soda tenant uses.\n\n## Core Usage\n\n### 1. Write a contract\n\nSoda v4 centers the CLI and Python API around data contracts. A minimal contract needs:\n\n- a top-level `dataset:` key\n- a `checks:` block, a `columns:` list, or both\n\nExample:\n\n```yaml\ndataset: my_postgres/analytics/orders\n\nchecks:\n  - schema:\n  - row_count:\n\ncolumns:\n  - name: id\n    checks:\n      - missing:\n  - name: status\n    checks:\n      - invalid:\n          valid_values: [\"pending\", \"paid\", \"failed\"]\n```\n\n### 2. Verify a contract with the CLI\n\nRun the contract locally with Soda Core:\n\n```bash\nsoda contract verify --data-source ds_config.yml --contract contract.yaml\n```\n\nYou can override variables defined in the contract at runtime:\n\n```bash\nsoda contract verify \\\n  --data-source ds_config.yml \\\n  --contract contract.yaml \\\n  --set START_DATE=2026-03-01 \\\n  --set COUNTRY=US\n```\n\nIf you only want a subset of checks, the CLI also supports `--check-paths` for local execution.\n\n### 3. Verify a contract with the Python API\n\nThe current v4 Python API is contract-oriented:\n\n```python\nfrom soda_core import configure_logging\nfrom soda_core.contracts import verify_contract_locally\n\nconfigure_logging(verbose=True)\n\nresult = verify_contract_locally(\n    data_source_file_path=\"ds_config.yml\",\n    contract_file_path=\"contract.yaml\",\n    publish=False,\n)\n\nif result.has_errors:\n    raise RuntimeError(result.get_errors_str())\n\nprint(result.is_ok)\nprint(result.get_logs_str())\n```\n\nImportant result properties from the official Python API:\n\n- `is_ok`: true when verification has no failed checks and no execution errors\n- `is_failed`: true when one or more checks failed\n- `has_errors`: true when execution itself failed\n- `get_logs_str()` and `get_errors_str()` for readable diagnostics\n\n### 4. Publish or verify against Soda Cloud\n\nPublishing requires a Soda Cloud config file and the matching permissions:\n\n```python\nfrom soda_core.contracts import publish_contract\n\nresult = publish_contract(\n    contract_file_path=\"contract.yaml\",\n    soda_cloud_file_path=\"sc_config.yml\",\n)\n```\n\nOr verify locally and publish the results:\n\n```python\nfrom soda_core.contracts import verify_contract_locally\n\nresult = verify_contract_locally(\n    data_source_file_path=\"ds_config.yml\",\n    contract_file_path=\"contract.yaml\",\n    soda_cloud_file_path=\"sc_config.yml\",\n    publish=True,\n)\n```\n\n## In-Memory And DataFrame Workflows\n\nOne of Soda Core's practical strengths is local execution for in-memory data. The v4 docs show DuckDB-based verification for Pandas and Polars data frames.\n\nPandas example:\n\n```python\nimport duckdb\nimport pandas as pd\nfrom soda_core.contracts import verify_contract_locally\nfrom soda_duckdb import DuckDBDataSource\n\ndf = pd.read_parquet(\"orders.parquet\")\nconn = duckdb.connect(database=\":memory:\")\ncursor = conn.cursor()\ncursor.register(view_name=\"orders\", python_object=df)\n\nresult = verify_contract_locally(\n    data_sources=[DuckDBDataSource.from_existing_cursor(cursor, name=\"duckdb\")],\n    contract_file_path=\"orders.contract.yaml\",\n)\n```\n\nUse this pattern when the dataset is already materialized in Python and you want contract verification without creating a durable warehouse table first.\n\n## Common Pitfalls\n\n- Do not assume `pip install soda-core` is the preferred v4 install path. Current official docs are written around `soda` and `soda-<data_source>` from `https://pypi.cloud.soda.io/simple`.\n- Do not confuse the package name with the import namespace. The package name may be `soda-core` or `soda-postgres`, but the documented contract API imports come from `soda_core`.\n- Run `soda data-source test --data-source ds_config.yml` before debugging contract syntax. Connection issues are a separate class of failure.\n- Keep the `name` in `ds_config.yml` aligned with the Soda Cloud data source name if you want local Soda Core verification and Soda Agent / Soda Cloud results to map to the same source.\n- Avoid hardcoding passwords or API keys in YAML. The official data-source docs explicitly support `${env.VAR_NAME}` interpolation.\n- Contract verification is not the same as observability. The v4 docs describe Soda Core as local contract execution without observability features.\n- GitHub release tags are not a reliable source for current v4 package selection. The public repo's release page still exposes `v3.5.6` as latest even though current v4 docs and PyPI artifacts exist.\n\n## Version-Sensitive Notes\n\n- On March 12, 2026, the official public PyPI page for `soda-core` shows `4.0.7` as the latest visible release.\n- Current Soda v4 docs have shifted package naming from old v3-style `soda-core-<datasource>` guidance toward `soda` and `soda-<data_source>`.\n- Current official docs state support for Python `3.9` through `3.12`, and note that Python `3.13+` has no known constraints even though `3.12` is the highest officially supported version.\n- If you are maintaining an older v3-era codebase, expect older docs and examples to use `configuration.yml`, `checks.yml`, and older package naming. Re-check every command against the v4 CLI reference before copying it into production code.\n\n## Official Sources\n\n- Docs root: https://docs.soda.io/\n- Soda Python Libraries: https://docs.soda.io/deployment-options/soda-python-libraries\n- CLI reference: https://docs.soda.io/reference/cli-reference\n- Python API: https://docs.soda.io/reference/python-api\n- Contract language reference: https://docs.soda.io/reference/contract-language-reference\n- Data source reference: https://docs.soda.io/reference/data-source-reference-for-soda-core\n- PostgreSQL data source example: https://docs.soda.io/soda-v4/reference/data-source-reference-for-soda-core/postgresql\n- DuckDB advanced usage: https://docs.soda.io/reference/data-source-reference-for-soda-core/duckdb/duckdb-advanced-usage\n- Generate API keys: https://docs.soda.io/reference/generate-api-keys\n- PyPI package page: https://pypi.org/project/soda-core/\n- Source repository: https://github.com/sodadata/soda-core\n"
  },
  {
    "path": "content/solara/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Solara Python package guide for building reactive web apps and Jupyter UIs with pure Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.57.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"solara,python,web,ui,jupyter,ipywidgets,reactive\"\n---\n\n# Solara Python Package Guide\n\n## Golden Rule\n\nUse `solara` when you want one Python codebase that can run as a Jupyter UI and as a standalone web app. Keep the app entry point centered on a `Page` component, use reactive state instead of imperative DOM-style updates, and run production deployments with `solara run ... --production` or the Starlette/Flask integration paths from the official deployment docs.\n\nAs of March 12, 2026, the version used here `1.57.3` does not appear on the official registry. PyPI and the official changelog both show `1.57.2` as the latest published release, so this guide is pinned to `1.57.2`.\n\n## Install\n\nUse a virtual environment unless you already have an isolated Python environment:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"solara==1.57.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"solara==1.57.2\"\npoetry add \"solara==1.57.2\"\n```\n\nImportant install details from the official docs:\n\n- `solara` is a meta package that pins compatible `solara-ui` and `solara-server` versions.\n- If you only need Solara inside Jupyter, `solara-ui` can be enough.\n- If you only need server deployment control, install `solara-server[...]` directly.\n- For air-gapped or firewalled environments, use `solara[assets]` so static assets do not need to be fetched from a CDN at runtime.\n\nExamples:\n\n```bash\npython -m pip install \"solara-ui[all]\"\npython -m pip install \"solara-server[starlette]\"\npython -m pip install \"solara[assets]==1.57.2\"\n```\n\n## Initialize A Solara App\n\nThe usual entry point is a Python file with a `Page` component:\n\n```python\nimport solara\n\nsentence = solara.reactive(\"Solara makes Python UIs simpler.\")\nword_limit = solara.reactive(8)\n\n@solara.component\ndef Page():\n    word_count = len(sentence.value.split())\n\n    solara.SliderInt(\"Word limit\", value=word_limit, min=2, max=20)\n    solara.InputText(\"Sentence\", value=sentence, continuous_update=True)\n\n    if word_count > word_limit.value:\n        solara.Error(f\"{word_count} words is over the limit of {word_limit.value}.\")\n    else:\n        solara.Success(\"Within the limit.\")\n```\n\nRun it locally:\n\n```bash\nsolara run myapp.py\n```\n\nFor production mode:\n\n```bash\nsolara run myapp.py --production\n```\n\nSolara can generate a starter file for you:\n\n```bash\nsolara create button\n```\n\n## Reuse The Same UI In Jupyter\n\nIf the app file exposes `Page`, you can render it inside a notebook:\n\n```python\nfrom myapp import Page\n\nPage()\n```\n\nIf notebook rendering fails, check whether the notebook server and the kernel are using different Python environments. The official troubleshooting docs call this the most common Jupyter issue, and `solara.check_jupyter()` can help detect it.\n\n## Core Usage Patterns\n\n### Use reactive state intentionally\n\nUse `solara.reactive(...)` for app-level or shared state and `solara.use_reactive(...)` or `solara.use_state(...)` inside components.\n\n`use_reactive` is usually the most ergonomic hook when you want a reactive object:\n\n```python\nimport solara\n\n@solara.component\ndef Counter():\n    count = solara.use_reactive(0)\n\n    def increment():\n        count.value += 1\n\n    solara.Button(\"Increment\", on_click=increment)\n    solara.Text(f\"Count: {count.value}\")\n```\n\nUse `use_state` when you explicitly want a `(value, setter)` tuple:\n\n```python\nimport solara\n\n@solara.component\ndef Counter():\n    count, set_count = solara.use_state(0)\n    solara.Button(\"Increment\", on_click=lambda: set_count(lambda prev: prev + 1))\n    solara.Text(f\"Count: {count}\")\n```\n\n### Avoid blocking the UI thread\n\nFor medium or long running work, use `solara.use_thread(...)` so the render loop stays responsive:\n\n```python\nimport solara\nimport time\n\n@solara.component\ndef Page():\n    result = solara.use_thread(lambda: (time.sleep(2), \"done\")[1], dependencies=[])\n\n    if result.state.name in {\"STARTING\", \"WAITING\", \"RUNNING\"}:\n        solara.Info(\"Working...\")\n    elif result.error:\n        solara.Error(str(result.error))\n    else:\n        solara.Success(result.value)\n```\n\n### Routing and multipage apps\n\nFor a simple app, exporting a single `Page` is enough. For multipage apps:\n\n- define a `routes = [...]` tree with `solara.Route(...)`, or\n- point Solara at a directory or package and let it generate routes automatically\n\nExample manual route setup:\n\n```python\nimport solara\n\n@solara.component\ndef Home():\n    solara.Markdown(\"Home\")\n\n@solara.component\ndef About():\n    solara.Markdown(\"About\")\n\nroutes = [\n    solara.Route(path=\"/\", component=Home, label=\"Home\"),\n    solara.Route(path=\"about\", component=About, label=\"About\"),\n]\n```\n\nWhen navigating, use `solara.Link(...)`, `solara.resolve_path(...)`, or `solara.use_router().push(...)`. Do not build navigation from `route.path` alone because route paths are relative.\n\n## Deployment, Config, And Auth\n\n### Default deployment path\n\nThe most direct deployment path is:\n\n```bash\nsolara run myapp.py --production\n```\n\nUnder the hood this uses Starlette. For framework-managed hosting, set `SOLARA_APP` and run your server normally:\n\n```bash\nexport SOLARA_APP=myapp.py\nuvicorn solara.server.starlette:app\n```\n\nOr:\n\n```bash\nexport SOLARA_APP=myapp.py\ngunicorn solara.server.flask:app\n```\n\nSolara can also be mounted inside existing Flask, Starlette, or FastAPI apps.\n\n### Reverse proxies and subpaths\n\nIf Solara is behind Nginx, Traefik, Caddy, or another proxy:\n\n- forward `Host` and `X-Forwarded-Proto`\n- if the app is mounted under a subpath, use `X-Script-Name` or uvicorn `--root-path`\n- configure `FORWARDED_ALLOW_IPS` so uvicorn trusts the proxy headers\n\nThese settings matter for URL generation, cookies, and OAuth redirects.\n\n### Auth\n\nOpen-source Solara itself is a UI framework, not a general auth system. Official OAuth support is documented under Solara Enterprise and currently centers on `solara-enterprise[auth]`.\n\nTypical enterprise auth setup uses environment variables such as:\n\n```bash\nSOLARA_SESSION_SECRET_KEY=change-me\nSOLARA_OAUTH_CLIENT_ID=...\nSOLARA_OAUTH_CLIENT_SECRET=...\nSOLARA_OAUTH_API_BASE_URL=...\nSOLARA_OAUTH_PRIVATE=True\n```\n\nIf redirects come back to the wrong URL, the official docs point to `SOLARA_BASE_URL`, `SOLARA_ROOT_PATH`, forwarded `Host`, and forwarded `X-Forwarded-Proto` as the first things to verify.\n\n## Testing And Debugging\n\nThe official testing guidance is to prefer tests without a browser when possible. Use plain `pytest` for application logic and only bring in browser testing when you are validating new frontend behavior, CSS, or custom components.\n\nRelevant packages:\n\n```bash\npython -m pip install pytest\npython -m pip install \"pytest-ipywidgets\"\n```\n\nDebugging options from the official docs:\n\n- `breakpoint()` works inside Solara callbacks\n- PyCharm and VS Code debugger launch configs are supported\n- development mode gives hot reloading; production mode disables file watching\n\n## Common Pitfalls\n\n### Do not mutate reactive values in place\n\nLists, dicts, and custom objects can be mutated without Solara noticing. Reassign a new value instead of mutating in place.\n\nPrefer:\n\n```python\nitems.value = [*items.value, \"new\"]\n```\n\nAvoid:\n\n```python\nitems.value.append(\"new\")\n```\n\n### Keep hooks at the top level\n\nHooks such as `use_state`, `use_reactive`, and `use_thread` must not be called inside loops, conditions, or nested functions. Solara warns today, and the docs say Solara 2.0 will turn these cases into errors.\n\n### Be careful with `use_reactive` and objects without equality\n\nThe official `use_reactive` docs warn that objects without usable equality semantics can trigger render loops. If you need a stable object instance, combine `use_reactive(...)` with `use_memo(...)`.\n\n### Notebook server and kernel environments can differ\n\nIf Solara works in one environment but not another, confirm the Python executable used by the notebook server and the kernel. This mismatch is a frequent cause of missing widget assets in Jupyter environments.\n\n### Multi-worker deployments need planning\n\n## Version-Sensitive Notes\n\n- `1.57.2` includes a security fix for a path-boundary traversal issue and a memory leak fix.\n- `1.56.0` dropped Python 3.7 support, so do not assume older runtime compatibility if you are upgrading from older Solara deployments.\n- The roadmap says Solara 2.0 is expected to tighten state-mutation and hook-misuse enforcement. Keep current code free of those warnings now to avoid avoidable upgrade churn later.\n\n## Official Sources\n\n- Docs root: https://solara.dev/documentation\n- Quickstart: https://solara.dev/documentation/getting_started\n- Installation: https://solara.dev/docs/installing\n- State management: https://solara.dev/documentation/getting_started/fundamentals/state-management\n- Hooks: https://solara.dev/documentation/api/hooks/use_reactive and https://solara.dev/documentation/api/hooks/use_state\n- Routing: https://solara.dev/documentation/advanced/understanding/routing\n- Deployment: https://solara.dev/documentation/getting_started/deploying/self-hosted\n- Testing: https://solara.dev/documentation/advanced/howto/testing\n- Debugging: https://solara.dev/documentation/advanced/howto/debugging\n- OAuth: https://solara.dev/documentation/advanced/enterprise/oauth\n- Changelog: https://solara.dev/changelog/\n- Registry: https://pypi.org/project/solara/\n"
  },
  {
    "path": "content/sourceparts/docs/parts-mcp/python/DOC.md",
    "content": "---\nname: parts-mcp\ndescription: \"MCP server for electronic parts sourcing — search components, compare prices, check availability, process BOMs, read datasheets, submit DFM analysis, and integrate with KiCad\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.1.3\"\n  revision: 1\n  updated-on: \"2026-03-15\"\n  source: maintainer\n  tags: \"mcp,electronics,parts,sourcing,bom,kicad,pcb,components,eda,datasheet,dfm,manufacturing\"\n---\n\n# Parts MCP\n\nMCP server for sourcing electronic components. Thin client wrapping the [Source Parts API](https://api.source.parts) — search, pricing, availability, BOM processing, datasheet reading, DFM analysis, and KiCad integration happen server-side. Local tools handle filesystem access (BOM uploads, KiCad project discovery, datasheet PDFs).\n\n## Installation\n\n```bash\npip install parts-mcp\n```\n\nRequires Python 3.10+.\n\n## Configuration\n\n### Environment Variables\n\n```bash\nSOURCE_PARTS_API_KEY=your_api_key      # Required — get from source.parts\nSOURCE_PARTS_API_URL=https://api.source.parts/v1  # Optional, default shown\nKICAD_SEARCH_PATHS=/path/to/projects   # Optional, for find_kicad_projects\nPARTS_CACHE_DIR=~/.cache/parts-mcp     # Optional\nCACHE_EXPIRY_HOURS=24                  # Optional\n```\n\n### Claude Desktop\n\n```json\n{\n  \"mcpServers\": {\n    \"parts\": {\n      \"command\": \"parts-mcp\",\n      \"env\": {\n        \"SOURCE_PARTS_API_KEY\": \"your_api_key\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code\n\n```json\n{\n  \"mcpServers\": {\n    \"parts\": {\n      \"command\": \"parts-mcp\",\n      \"env\": {\n        \"SOURCE_PARTS_API_KEY\": \"your_api_key\"\n      }\n    }\n  }\n}\n```\n\n## Tools Quick Reference\n\n### Search\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `search_parts` | Search by keyword, part number, or description | `query`, `category?`, `filters?`, `limit?` |\n| `search_by_parameters` | Parametric search within a category | `parameters`, `category`, `limit?` |\n| `get_part_details` | Full details for a specific part | `part_number`, `manufacturer?` |\n\n### Sourcing\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `compare_prices` | Price comparison across suppliers | `part_number`, `quantity?`, `suppliers?` |\n| `check_availability` | Stock check for multiple parts | `part_numbers`, `quantities?` |\n| `find_alternatives` | Find compatible replacements | `part_number`, `parameters?` |\n| `calculate_bom_cost` | Total cost for a bill of materials | `bom`, `quantity?`, `preferred_suppliers?` |\n| `estimate_cost` | Quick cost estimate for a parts list | `parts`, `currency?` |\n\n### Manufacturing\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `upload_bom` | Upload BOM file for processing | `file_path` (local only) |\n| `check_bom_status` | Poll BOM processing, get matched/unmatched | `job_id` |\n| `submit_dfm` | Queue DFM analysis | `project_id`, `bom_id?`, `priority?` |\n| `check_dfm_status` | Poll DFM job status | `job_id` |\n| `quote_fabrication` | Get PCB fab quote | `project_id`, `quantity?`, `layers?`, etc. |\n| `upload_gerbers_for_quote` | Upload gerbers for fab quote | `file_path`, `quantity?`, etc. (local only) |\n| `quote_assembly` | Combined fab + assembly quote | `gerber_path`, `bom_path`, etc. (local only) |\n| `check_manufacturing_status` | Poll any manufacturing job | `job_id` |\n\n### Datasheet\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `list_datasheet_sections` | Get TOC without reading full content | `file_path?`, `sku?` |\n| `read_datasheet` | Read/chunk datasheet with optional filtering | `file_path?`, `sku?`, `query?`, `chunk_pages?` |\n\n### KiCad (local mode only)\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `find_kicad_projects` | Discover projects in search paths | (none) |\n| `extract_bom_from_kicad` | Extract BOM from .kicad_pro | `project_path` |\n| `analyze_kicad_project` | File counts and structure analysis | `project_path` |\n| `extract_netlist_from_project` | Connectivity analysis | `project_path` |\n| `match_components_to_parts` | Match KiCad components to real parts | `components`, `auto_search?` |\n| `export_parts_to_kicad` | Export sourced parts as CSV/JSON | `parts`, `output_path`, `format?` |\n| `highlight_net_traces` | Render highlighted nets as PDFs | `project_path`, `net_names`, `colors?`, `mode?` |\n| `open_in_kicad` | Launch KiCad with a project | `project_path` |\n\n### Identification\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `identify_pcb` | Identify PCB/component from photo | `file_path`, `project_id?` (local only) |\n| `check_identification_status` | Poll identification job | `job_id` |\n| `get_identified_item` | Get identified item details | `short_code` |\n\n## Core Workflow: Search to Source\n\n```python\n# 1. Search for a part\nresult = search_parts(query=\"STM32F411CEU6\")\n\n# 2. Get detailed specs\ndetails = get_part_details(part_number=\"STM32F411CEU6\", manufacturer=\"STMicroelectronics\")\n\n# 3. Compare prices across suppliers\nprices = compare_prices(part_number=\"STM32F411CEU6\", quantity=100)\n\n# 4. Check if it's in stock\navailability = check_availability(\n    part_numbers=[\"STM32F411CEU6\"],\n    quantities=[100]\n)\n\n# 5. If unavailable or expensive, find alternatives\nalternatives = find_alternatives(\n    part_number=\"STM32F411CEU6\",\n    parameters={\"core\": \"ARM Cortex-M4\", \"flash\": \"512KB\"}\n)\n```\n\n## BOM Processing\n\nBOM upload is asynchronous — upload, poll, then review results.\n\n```python\n# 1. Upload BOM file (CSV, XLSX, XLS, JSON, or XML)\nupload = upload_bom(file_path=\"/path/to/bom.csv\")\njob_id = upload[\"job_id\"]\n\n# 2. Poll until complete\nstatus = check_bom_status(job_id=job_id)\n# status[\"status\"] will be \"in_progress\", \"complete\", or \"failed\"\n\n# 3. When complete, review matches\nmatched = status[\"matched_parts\"]      # Successfully identified parts\nunmatched = status[\"unknown_parts\"]    # Parts needing manual resolution\n\n# 4. Calculate total cost\ncost = calculate_bom_cost(\n    bom=[{\"part_number\": p[\"mpn\"], \"quantity\": p[\"quantity\"]} for p in matched],\n    quantity=100\n)\n```\n\nSupported BOM formats: CSV, XLSX, XLS, JSON, XML. Max file size: 50 MB.\n\nSix EDA tools supported: KiCad, Altium Designer, Autodesk Fusion 360, Eagle, PADS, Protel 99.\n\n## KiCad Integration\n\n```python\n# 1. Discover projects\nprojects = find_kicad_projects()\n\n# 2. Extract BOM from a project\nbom = extract_bom_from_kicad(project_path=\"/path/to/project.kicad_pro\")\n\n# 3. Match components to real parts\nmatches = match_components_to_parts(\n    components=bom[\"bom_files\"][0][\"analysis\"][\"components\"],\n    auto_search=True\n)\n\n# 4. Export sourced parts back to KiCad format\nexport_parts_to_kicad(\n    parts=matches[\"suggestions\"],\n    output_path=\"/path/to/sourced_parts.csv\",\n    format=\"csv\"\n)\n```\n\nKiCad tools require local mode (stdio transport). Set `KICAD_SEARCH_PATHS` to directories containing your `.kicad_pro` files.\n\n## Datasheet Reading\n\nDatasheets can be large. Use `list_datasheet_sections` first to see what's available, then `read_datasheet` with a `query` to filter relevant chunks.\n\n```python\n# 1. See what sections exist (lightweight, no content returned)\nsections = list_datasheet_sections(sku=\"STM32F411CEU6\")\n# Returns: [{\"title\": \"Electrical Characteristics\", \"page\": 42}, ...]\n\n# 2. Read only relevant chunks\ndata = read_datasheet(\n    sku=\"STM32F411CEU6\",\n    query=\"maximum input voltage absolute ratings\",\n    chunk_pages=5\n)\n# Returns filtered chunks matching the query keywords\n# context_savings shows reduction (e.g., \"reduction_pct\": 75)\n```\n\nTwo input modes: `file_path` (upload local PDF) or `sku` (fetch cached chunks from API). Using `sku` is faster when parts have been previously processed.\n\n## Manufacturing\n\n```python\n# DFM analysis\ndfm = submit_dfm(project_id=\"proj_123\", priority=\"high\")\ndfm_result = check_dfm_status(job_id=dfm[\"job_id\"])\n\n# Fabrication quote\nfab = quote_fabrication(\n    project_id=\"proj_123\",\n    quantity=10,\n    layers=4,\n    thickness=1.6,\n    surface_finish=\"ENIG\",\n    color=\"black\"\n)\nfab_result = check_manufacturing_status(job_id=fab[\"job_id\"])\n\n# Combined fab + assembly quote (local mode)\nassembly = quote_assembly(\n    gerber_path=\"/path/to/gerbers.zip\",\n    bom_path=\"/path/to/bom.csv\",\n    quantity=10,\n    layers=4\n)\n```\n\nAll manufacturing operations are asynchronous. Use `check_manufacturing_status` or the specific status tools (`check_dfm_status`, `check_bom_status`) to poll for results.\n\n## Hosted vs Local Mode\n\n| Capability | Local (stdio) | Hosted (HTTP) |\n|-----------|---------------|---------------|\n| Search, pricing, availability | Yes | Yes |\n| BOM cost calculation | Yes | Yes |\n| DFM, fab quoting (by project ID) | Yes | Yes |\n| Manufacturing status checks | Yes | Yes |\n| Datasheet reading (by SKU) | Yes | Yes |\n| Datasheet reading (local PDF) | Yes | No |\n| BOM file upload | Yes | No |\n| Gerber file upload | Yes | No |\n| KiCad integration | Yes | No |\n| PCB identification (photo) | Yes | No |\n| Assembly quoting (file upload) | Yes | No |\n\nLocal mode runs via `parts-mcp` (stdio). Hosted mode runs as an HTTP server with OAuth authentication.\n\n## Common Pitfalls\n\n**Missing API key**: All tools except KiCad project discovery require `SOURCE_PARTS_API_KEY`. Set it in your environment or MCP config.\n\n**KiCad CLI not in PATH**: `extract_bom_from_kicad` and `extract_netlist_from_project` invoke `kicad-cli` if no existing BOM/netlist files are found. Ensure KiCad 8+ is installed and `kicad-cli` is accessible.\n\n**Context-heavy datasheet reads**: Always call `list_datasheet_sections` before `read_datasheet`. Use the `query` parameter to filter chunks — an unfiltered read of a 200-page datasheet will consume significant context.\n\n**BOM status polling**: `check_bom_status` should be called repeatedly until `status` is `\"complete\"` or `\"failed\"`. Processing time depends on BOM size and part matching complexity.\n\n**File size limits**: BOM and gerber uploads are limited to 50 MB. Image uploads for identification accept: jpg, jpeg, png, gif, heic, webp.\n\n## Resources\n\n- [Source Parts](https://source.parts) — Main platform\n- [GitHub](https://github.com/SourceParts/parts-mcp) — Source code\n- [PyPI](https://pypi.org/project/parts-mcp/) — Package\n- [API Documentation](https://source.parts/docs/api) — API reference\n\nSee [tools.md](./references/tools.md) for complete parameter reference and [workflows.md](./references/workflows.md) for multi-step workflow recipes.\n"
  },
  {
    "path": "content/sourceparts/docs/parts-mcp/python/references/tools.md",
    "content": "# Parts MCP — Tool Parameter Reference\n\nComplete parameter reference for all parts-mcp tools. Grouped by category.\n\n## Search Tools\n\n### search_parts\n\nSearch for electronic parts across suppliers.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `query` | `str` | required | Search query — part number, description, or keywords |\n| `category` | `str \\| None` | `None` | Category filter (e.g., \"resistor\", \"capacitor\", \"microcontroller\") |\n| `filters` | `dict \\| None` | `None` | Parametric filters (e.g., `{\"resistance\": \"10k\", \"tolerance\": \"1%\"}`) |\n| `limit` | `int` | `20` | Maximum results to return |\n\n**Returns:**\n\n```json\n{\n  \"query\": \"STM32F411\",\n  \"category\": null,\n  \"filters\": {},\n  \"results\": [\n    {\n      \"part_number\": \"STM32F411CEU6\",\n      \"manufacturer\": \"STMicroelectronics\",\n      \"description\": \"ARM Cortex-M4 MCU, 512KB Flash, 128KB RAM\",\n      \"category\": \"microcontroller\"\n    }\n  ],\n  \"total_results\": 15,\n  \"success\": true\n}\n```\n\n### search_by_parameters\n\nParametric search within a specific category.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `parameters` | `dict` | required | Search criteria (e.g., `{\"capacitance\": \"100nF\", \"voltage\": \"50V\", \"package\": \"0402\"}`) |\n| `category` | `str` | required | Part category |\n| `limit` | `int` | `20` | Maximum results |\n\n**Returns:**\n\n```json\n{\n  \"category\": \"capacitor\",\n  \"parameters\": {\"capacitance\": \"100nF\", \"voltage\": \"50V\"},\n  \"results\": [...],\n  \"total_results\": 42,\n  \"success\": true\n}\n```\n\n### get_part_details\n\nGet detailed information about a specific part.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `part_number` | `str` | required | Part number to look up |\n| `manufacturer` | `str \\| None` | `None` | Manufacturer name (disambiguates when multiple manufacturers use same part number) |\n\n**Returns:**\n\n```json\n{\n  \"part_number\": \"STM32F411CEU6\",\n  \"manufacturer\": \"STMicroelectronics\",\n  \"details\": {\n    \"description\": \"...\",\n    \"specifications\": {...},\n    \"datasheet_url\": \"...\",\n    \"lifecycle_status\": \"active\"\n  },\n  \"success\": true\n}\n```\n\n## Sourcing Tools\n\n### compare_prices\n\nCompare prices across multiple suppliers.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `part_number` | `str` | required | Part number to price |\n| `quantity` | `int` | `1` | Quantity needed (affects price breaks) |\n| `suppliers` | `list[str] \\| None` | `None` | Specific suppliers to check (checks all if omitted) |\n\n**Returns:**\n\n```json\n{\n  \"part_number\": \"STM32F411CEU6\",\n  \"quantity\": 100,\n  \"suppliers_checked\": 5,\n  \"prices\": [\n    {\n      \"supplier\": \"LCSC\",\n      \"sku\": \"C478234\",\n      \"unit_price\": 3.42,\n      \"total_price\": 342.00,\n      \"stock\": 15000,\n      \"lead_time\": \"3-5 days\"\n    }\n  ],\n  \"best_price\": {\"supplier\": \"LCSC\", \"unit_price\": 3.42},\n  \"success\": true\n}\n```\n\n### check_availability\n\nCheck stock levels for multiple parts at once.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `part_numbers` | `list[str]` | required | List of part numbers to check |\n| `quantities` | `list[int] \\| None` | `None` | Quantities needed per part (defaults to 1 each) |\n\n**Returns:**\n\n```json\n{\n  \"parts\": [\"STM32F411CEU6\", \"LM1117-3.3\"],\n  \"quantities\": [100, 100],\n  \"availability\": [\n    {\n      \"part_number\": \"STM32F411CEU6\",\n      \"quantity_needed\": 100,\n      \"available\": true,\n      \"total_stock\": 15000,\n      \"in_stock_suppliers\": 3,\n      \"manufacturer\": \"STMicroelectronics\",\n      \"description\": \"ARM Cortex-M4 MCU\"\n    }\n  ],\n  \"all_available\": true,\n  \"success\": true\n}\n```\n\n### find_alternatives\n\nFind drop-in or compatible replacement parts.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `part_number` | `str` | required | Original part number |\n| `parameters` | `dict \\| None` | `None` | Key parameters to match (narrows alternatives) |\n\n**Returns:**\n\n```json\n{\n  \"original_part\": \"STM32F411CEU6\",\n  \"match_parameters\": {\"core\": \"ARM Cortex-M4\"},\n  \"alternatives\": [\n    {\n      \"part_number\": \"STM32F401CEU6\",\n      \"manufacturer\": \"STMicroelectronics\",\n      \"compatibility\": \"pin-compatible\",\n      \"differences\": [\"256KB Flash vs 512KB\"]\n    }\n  ],\n  \"total_alternatives\": 8,\n  \"success\": true\n}\n```\n\n### calculate_bom_cost\n\nCalculate total cost for a complete bill of materials.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `bom` | `list[dict]` | required | BOM items (see format below) |\n| `quantity` | `int` | `1` | Number of boards/assemblies |\n| `preferred_suppliers` | `list[str] \\| None` | `None` | Preferred supplier list |\n\n**BOM item format:**\n\n```json\n{\n  \"part_number\": \"STM32F411CEU6\",\n  \"quantity\": 1,\n  \"reference\": \"U1\",\n  \"description\": \"Main MCU\"\n}\n```\n\nFields `part_number` (or `mpn`) and `quantity` are required. `reference` and `description`/`value` are optional.\n\n**Returns:**\n\n```json\n{\n  \"bom_items\": 25,\n  \"priced_items\": 23,\n  \"quantity\": 100,\n  \"total_cost\": 1250.00,\n  \"cost_breakdown\": [\n    {\n      \"reference\": \"U1\",\n      \"part_number\": \"STM32F411CEU6\",\n      \"description\": \"Main MCU\",\n      \"quantity\": 100,\n      \"unit_price\": 3.42,\n      \"line_total\": 342.00,\n      \"supplier\": \"LCSC\",\n      \"sku\": \"C478234\"\n    }\n  ],\n  \"errors\": [{\"part_number\": \"CUSTOM-PART-1\", \"error\": \"not found\"}],\n  \"currency\": \"USD\",\n  \"success\": true\n}\n```\n\n### estimate_cost\n\nQuick cost estimate without full BOM processing.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `parts` | `list[dict]` | required | Parts list with `part_number` and `quantity` |\n| `currency` | `str` | `\"USD\"` | Currency code |\n\n## Manufacturing Tools\n\n### upload_bom\n\nUpload a BOM file for processing and part matching. **Local mode only.**\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `file_path` | `str` | required | Local path to BOM file |\n\nSupported formats: CSV, XLSX, XLS, JSON, XML. Max size: 50 MB.\n\n**Returns:** `job_id` for polling with `check_bom_status`.\n\n### check_bom_status\n\nPoll BOM processing status. When complete, returns matched and unmatched parts.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `job_id` | `str` | required | Job ID from `upload_bom` |\n\n**Returns (when complete):**\n\n```json\n{\n  \"job_id\": \"bom_abc123\",\n  \"status\": \"complete\",\n  \"bom_id\": \"bom_def456\",\n  \"summary\": {\"total_lines\": 25, \"matched\": 23, \"unmatched\": 2},\n  \"matched_parts\": [...],\n  \"unknown_parts\": [\n    {\n      \"reference\": \"U3\",\n      \"value\": \"CUSTOM-IC\",\n      \"footprint\": \"QFP-48\",\n      \"manufacturer\": \"\",\n      \"mpn\": \"\",\n      \"status\": \"unmatched\"\n    }\n  ],\n  \"success\": true\n}\n```\n\n### submit_dfm\n\nQueue a Design for Manufacturability analysis.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_id` | `str` | required | Project ID to analyze |\n| `bom_id` | `str \\| None` | `None` | BOM ID to include |\n| `revision` | `str \\| None` | `None` | Revision identifier |\n| `notes` | `str \\| None` | `None` | Analysis notes |\n| `priority` | `str` | `\"normal\"` | `\"low\"`, `\"normal\"`, or `\"high\"` |\n\n### check_dfm_status\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `job_id` | `str` | required | Job ID from `submit_dfm` |\n\n### quote_fabrication\n\nGet a PCB fabrication quote.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_id` | `str` | required | Project ID |\n| `quantity` | `int` | `5` | Number of boards |\n| `layers` | `int` | `2` | PCB layer count |\n| `thickness` | `float` | `1.6` | Board thickness in mm |\n| `surface_finish` | `str` | `\"HASL\"` | Surface finish (HASL, ENIG, OSP) |\n| `color` | `str` | `\"green\"` | Solder mask color (green, red, blue, black, white, yellow) |\n| `priority` | `str` | `\"normal\"` | `\"low\"`, `\"normal\"`, or `\"high\"` |\n\n### upload_gerbers_for_quote\n\nUpload gerber zip for fab quoting. **Local mode only.** Same parameters as `quote_fabrication` except uses `file_path` instead of `project_id`.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `file_path` | `str` | required | Path to gerber zip file |\n| `quantity` | `int` | `5` | Number of boards |\n| `layers` | `int` | `2` | PCB layer count |\n| `thickness` | `float` | `1.6` | Board thickness in mm |\n| `surface_finish` | `str` | `\"HASL\"` | Surface finish |\n| `color` | `str` | `\"green\"` | Solder mask color |\n| `priority` | `str` | `\"normal\"` | Priority level |\n\n### quote_assembly\n\nCombined fabrication + assembly quote. **Local mode only.** Uploads gerbers for fab and BOM for assembly costing. Polls BOM status internally to get `bom_id`, then calculates COGS.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `gerber_path` | `str` | required | Path to gerber zip |\n| `bom_path` | `str` | required | Path to BOM file |\n| `quantity` | `int` | `5` | Number of assemblies |\n| `layers` | `int` | `2` | PCB layer count |\n| `thickness` | `float` | `1.6` | Board thickness in mm |\n| `surface_finish` | `str` | `\"HASL\"` | Surface finish |\n| `color` | `str` | `\"green\"` | Solder mask color |\n| `priority` | `str` | `\"normal\"` | Priority level |\n\n### check_manufacturing_status\n\nPoll status of any manufacturing job (fab, DFM, AOI, QC).\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `job_id` | `str` | required | Job ID from any manufacturing submission |\n\n## Datasheet Tools\n\n### list_datasheet_sections\n\nLightweight TOC extraction. Returns section titles and page numbers without reading content.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `file_path` | `str \\| None` | `None` | Local PDF path (local mode) |\n| `sku` | `str \\| None` | `None` | Part SKU for cached data |\n\nOne of `file_path` or `sku` is required.\n\n**Returns:**\n\n```json\n{\n  \"source\": \"STM32F411CEU6\",\n  \"total_pages\": 196,\n  \"sections\": [\n    {\"title\": \"Features\", \"page\": 1},\n    {\"title\": \"Electrical Characteristics\", \"page\": 42},\n    {\"title\": \"Absolute Maximum Ratings\", \"page\": 55}\n  ],\n  \"section_count\": 28,\n  \"success\": true\n}\n```\n\n### read_datasheet\n\nRead and chunk a datasheet PDF with optional keyword filtering.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `file_path` | `str \\| None` | `None` | Local PDF path |\n| `sku` | `str \\| None` | `None` | Part SKU for cached chunks |\n| `query` | `str \\| None` | `None` | Keywords to filter chunks (e.g., \"maximum input voltage\") |\n| `chunk_pages` | `int` | `5` | Pages per chunk |\n\nOne of `file_path` or `sku` is required.\n\n**Returns:**\n\n```json\n{\n  \"source\": \"STM32F411CEU6\",\n  \"total_pages\": 196,\n  \"method\": \"cached\",\n  \"toc\": [{\"title\": \"Features\", \"page\": 1}],\n  \"chunks\": [\n    {\n      \"text\": \"...chunk content...\",\n      \"start_page\": 51,\n      \"end_page\": 55\n    }\n  ],\n  \"query\": \"maximum input voltage\",\n  \"context_savings\": {\n    \"total_chunks\": 40,\n    \"returned_chunks\": 3,\n    \"total_chars\": 250000,\n    \"returned_chars\": 18000,\n    \"reduction_pct\": 92.8\n  },\n  \"success\": true\n}\n```\n\n## KiCad Tools (Local Mode Only)\n\n### find_kicad_projects\n\nDiscover `.kicad_pro` files in configured search paths. No parameters.\n\n**Returns:**\n\n```json\n{\n  \"projects\": [\n    {\n      \"name\": \"my-board\",\n      \"path\": \"/home/user/projects/my-board/my-board.kicad_pro\",\n      \"modified\": \"2026-03-10T14:30:00\"\n    }\n  ],\n  \"total\": 5,\n  \"search_paths\": [\"/home/user/projects\"]\n}\n```\n\n### extract_bom_from_kicad\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_path` | `str` | required | Path to `.kicad_pro` file |\n\n### analyze_kicad_project\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_path` | `str` | required | Path to `.kicad_pro` file |\n\nReturns file counts: total, schematics, PCBs, data files.\n\n### extract_netlist_from_project\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_path` | `str` | required | Path to `.kicad_pro` file |\n\n### match_components_to_parts\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `components` | `list[dict]` | required | Components from KiCad BOM extraction |\n| `auto_search` | `bool` | `True` | Auto-search for matching parts |\n\n### export_parts_to_kicad\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `parts` | `list[dict]` | required | Parts with: `reference`, `value`, `footprint`, `manufacturer`, `part_number`, `supplier`, `quantity`, `unit_price` |\n| `output_path` | `str` | required | Output file path |\n| `format` | `str` | `\"csv\"` | `\"csv\"` or `\"json\"` |\n\n### highlight_net_traces\n\nRender highlighted net traces as vector PDFs.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_path` | `str` | required | Path to `.kicad_pro` or `.kicad_pcb` |\n| `net_names` | `list[str]` | required | Net names to highlight |\n| `colors` | `dict \\| None` | `None` | Color mapping `{\"net_name\": \"#rrggbb\"}` |\n| `mode` | `str` | `\"both\"` | `\"overlay\"`, `\"traces_only\"`, or `\"both\"` |\n| `output_dir` | `str \\| None` | `None` | Output directory (defaults to project dir) |\n\n### open_in_kicad\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `project_path` | `str` | required | Path to KiCad project file |\n\n## Identification Tools\n\n### identify_pcb\n\nIdentify PCB or component from a photo. **Local mode only.**\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `file_path` | `str` | required | Image path (jpg, jpeg, png, gif, heic, webp) |\n| `project_id` | `str \\| None` | `None` | Project to associate |\n| `box_id` | `str \\| None` | `None` | Box/shipment to associate |\n\n### check_identification_status\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `job_id` | `str` | required | Job ID from `identify_pcb` |\n\n### get_identified_item\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `short_code` | `str` | required | Item short code (e.g., `SP-XXXXXX`) |\n\n## Error Patterns\n\nAll tools return `{\"success\": false, \"error\": \"message\"}` on failure. Common errors:\n\n| Error | Cause | Resolution |\n|-------|-------|------------|\n| `\"API key not configured\"` | Missing `SOURCE_PARTS_API_KEY` | Set env var |\n| `\"File not found\"` | Invalid `file_path` | Check path exists |\n| `\"Unsupported file format\"` | Wrong BOM extension | Use CSV, XLSX, XLS, JSON, or XML |\n| `\"File too large\"` | Exceeds 50 MB limit | Split or compress file |\n| `\"Part not found\"` | No match for part number | Try broader search or check spelling |\n| `\"KiCad CLI not found\"` | `kicad-cli` not in PATH | Install KiCad 8+ |\n"
  },
  {
    "path": "content/sourceparts/docs/parts-mcp/python/references/workflows.md",
    "content": "# Parts MCP — Workflow Recipes\n\nMulti-step workflows for common electronic sourcing tasks.\n\n## End-to-End PCB Sourcing (KiCad to Priced BOM)\n\nComplete workflow from a KiCad project to a fully priced bill of materials.\n\n```\n1. find_kicad_projects()\n   → Pick project from results\n\n2. extract_bom_from_kicad(project_path=\"...\")\n   → Get component list from the project\n\n3. match_components_to_parts(components=bom_components, auto_search=True)\n   → Each component matched to real supplier parts\n\n4. For unmatched components:\n   search_parts(query=component_value)\n   → Manual search with value/footprint keywords\n\n5. check_availability(part_numbers=[all_matched_mpns], quantities=[all_quantities])\n   → Verify everything is in stock\n\n6. For unavailable parts:\n   find_alternatives(part_number=unavailable_mpn)\n   → Get drop-in replacements\n\n7. calculate_bom_cost(bom=final_parts_list, quantity=100)\n   → Total cost at production quantity\n\n8. export_parts_to_kicad(parts=sourced_parts, output_path=\"sourced_bom.csv\")\n   → Export back for KiCad integration\n```\n\n## Obsolete Part Replacement\n\nWhen a part is end-of-life or unavailable, find and validate a replacement.\n\n```\n1. get_part_details(part_number=\"OBSOLETE-PART\")\n   → Get specifications of the original part\n\n2. find_alternatives(\n     part_number=\"OBSOLETE-PART\",\n     parameters={\"package\": \"TSSOP-20\", \"voltage\": \"3.3V\"}\n   )\n   → Find parts matching critical parameters\n\n3. For each alternative:\n   get_part_details(part_number=alternative_mpn)\n   → Verify specs match requirements\n\n4. compare_prices(part_number=best_alternative, quantity=needed_qty)\n   → Check pricing for the replacement\n\n5. check_availability(part_numbers=[best_alternative], quantities=[needed_qty])\n   → Confirm stock levels\n```\n\n## Multi-Board Assembly Quoting\n\nGet combined fab + assembly quotes for a multi-board product.\n\n```\nFor each board:\n\n1. quote_assembly(\n     gerber_path=\"/path/to/board_gerbers.zip\",\n     bom_path=\"/path/to/board_bom.csv\",\n     quantity=100,\n     layers=4,\n     surface_finish=\"ENIG\"\n   )\n   → Returns fab_job_id, bom_job_id\n\n2. check_manufacturing_status(job_id=fab_job_id)\n   → Poll until fab quote ready\n\n3. check_bom_status(job_id=bom_job_id)\n   → Poll until BOM processed, note unmatched parts\n\n4. For unmatched parts:\n   search_parts(query=part_description)\n   → Resolve manually\n\nAggregate COGS across all boards for total assembly cost.\n```\n\n## Parametric Search with Filtering\n\nFind parts matching specific electrical parameters.\n\n```\n1. search_by_parameters(\n     parameters={\n       \"capacitance\": \"100nF\",\n       \"voltage_rating\": \"50V\",\n       \"package\": \"0402\",\n       \"dielectric\": \"X7R\"\n     },\n     category=\"capacitor\"\n   )\n   → Parts matching all criteria\n\n2. For top candidates:\n   compare_prices(part_number=candidate, quantity=1000)\n   → Price at volume\n\n3. check_availability(part_numbers=top_3_candidates, quantities=[1000, 1000, 1000])\n   → Stock check across candidates\n\n4. Pick the best available option by price and stock.\n```\n\n## Datasheet Deep-Dive\n\nExtract specific parameters from a datasheet efficiently.\n\n```\n1. list_datasheet_sections(sku=\"LM1117-3.3\")\n   → Get table of contents with page numbers\n   → Identify relevant sections (e.g., \"Electrical Characteristics\" on page 5)\n\n2. read_datasheet(\n     sku=\"LM1117-3.3\",\n     query=\"dropout voltage output current thermal\",\n     chunk_pages=5\n   )\n   → Returns only chunks matching keywords\n   → context_savings shows how much context was saved\n\n3. If you need a specific section not returned by query:\n   read_datasheet(\n     sku=\"LM1117-3.3\",\n     query=\"absolute maximum ratings\",\n     chunk_pages=3\n   )\n   → Targeted follow-up read\n```\n\n## DFM and Fabrication Pipeline\n\nFull manufacturing preparation workflow.\n\n```\n1. submit_dfm(project_id=\"proj_123\", bom_id=\"bom_456\", priority=\"high\")\n   → Queue DFM analysis\n\n2. check_dfm_status(job_id=dfm_job_id)\n   → Poll until complete\n   → Review issues and warnings\n\n3. If DFM passes:\n   quote_fabrication(\n     project_id=\"proj_123\",\n     quantity=10,\n     layers=2,\n     surface_finish=\"HASL\",\n     color=\"green\"\n   )\n   → Get fab pricing\n\n4. check_manufacturing_status(job_id=fab_job_id)\n   → Poll until quote ready\n\n5. For local gerber files:\n   upload_gerbers_for_quote(\n     file_path=\"/path/to/gerbers.zip\",\n     quantity=10,\n     layers=2\n   )\n   → Alternative: upload gerbers directly\n```\n\n## PCB Identification and Cataloging\n\nIdentify components on a physical PCB from photos.\n\n```\n1. identify_pcb(\n     file_path=\"/path/to/pcb_photo.jpg\",\n     project_id=\"proj_123\"\n   )\n   → Submits image for barcode/QR detection, OCR, component ID\n\n2. check_identification_status(job_id=id_job_id)\n   → Poll until identification complete\n\n3. For each identified item:\n   get_identified_item(short_code=\"SP-ABC123\")\n   → Get full details including barcodes, OCR text, metadata\n\n4. For identified part numbers:\n   get_part_details(part_number=identified_mpn)\n   → Cross-reference with parts database\n```\n\n## BOM File Upload and Review\n\nUpload a BOM from any supported EDA tool and review matching results.\n\n```\n1. upload_bom(file_path=\"/path/to/altium_bom.xlsx\")\n   → Accepts CSV, XLSX, XLS, JSON, XML\n   → Supports KiCad, Altium, Eagle, PADS, Fusion 360, Protel 99\n\n2. check_bom_status(job_id=bom_job_id)\n   → Poll until \"complete\"\n   → Returns matched_parts and unknown_parts\n\n3. For each unknown part:\n   search_parts(query=unknown[\"value\"] + \" \" + unknown[\"footprint\"])\n   → Try to resolve manually\n\n4. calculate_bom_cost(\n     bom=[\n       {\"part_number\": p[\"mpn\"], \"quantity\": p[\"quantity\"]}\n       for p in all_resolved_parts\n     ],\n     quantity=50,\n     preferred_suppliers=[\"LCSC\", \"Mouser\"]\n   )\n   → Get total cost with supplier preferences\n```\n"
  },
  {
    "path": "content/sourceparts/skills/electronics-sourcing/SKILL.md",
    "content": "---\nname: electronics-sourcing\ndescription: \"Guide for AI agents to source electronic components using parts-mcp — tool sequencing, decision patterns, and multi-step workflows\"\nmetadata:\n  revision: 1\n  updated-on: \"2026-03-15\"\n  source: maintainer\n  tags: \"electronics,sourcing,bom,components,pcb,manufacturing,workflow\"\n---\n\n# Electronics Sourcing Skill\n\nThis skill teaches you how to source electronic components effectively using parts-mcp tools. It covers tool sequencing, decision patterns, and how to handle common scenarios.\n\n## When to Use Which Search Tool\n\n**`search_parts`** — Use when you have a part number, description, or general keywords. This is your default starting point.\n\n```\n\"Find me a 100nF capacitor\" → search_parts(query=\"100nF capacitor\")\n\"Look up STM32F411\" → search_parts(query=\"STM32F411\")\n```\n\n**`search_by_parameters`** — Use when you need to match specific electrical parameters within a category. More precise than keyword search.\n\n```\n\"I need a 50V 100nF X7R 0402 cap\" → search_by_parameters(\n  parameters={\"capacitance\": \"100nF\", \"voltage\": \"50V\", \"dielectric\": \"X7R\", \"package\": \"0402\"},\n  category=\"capacitor\"\n)\n```\n\n**Decision rule**: If the user gives you 3+ specific parameters, use `search_by_parameters`. For part numbers or general queries, use `search_parts`.\n\n## The Search → Price → Availability → Alternative Pattern\n\nThis is the core sourcing workflow. Follow this sequence:\n\n```\n1. SEARCH → Find the part\n2. DETAILS → Get full specifications (if needed for validation)\n3. PRICE → Compare across suppliers\n4. AVAILABILITY → Check stock levels\n5. ALTERNATIVE → Find replacements (only if price is too high or stock is insufficient)\n```\n\nDo not skip steps 3 and 4. A part that exists in the database may be out of stock or prohibitively expensive.\n\nWhen the user asks to \"source\" or \"find\" a part, they expect pricing and availability — not just search results. Always follow through to at least step 4.\n\n## BOM Processing Pattern\n\nBOM processing is asynchronous. Always follow this exact sequence:\n\n```\n1. upload_bom(file_path=path)           → Get job_id\n2. check_bom_status(job_id=job_id)      → Poll until status is \"complete\"\n3. Review matched_parts and unknown_parts\n4. For unmatched: search_parts() to resolve manually\n5. calculate_bom_cost() with all resolved parts\n```\n\n**Polling**: Call `check_bom_status` and check the `status` field. If `\"in_progress\"`, wait and poll again. Do not assume instant completion.\n\n**Handling unmatched parts**: When `unknown_parts` is not empty, try `search_parts` with the `value` and `footprint` fields as the query. If still unmatched, report them to the user — do not silently skip them.\n\n## Datasheet Reading Strategy\n\nDatasheets can be hundreds of pages. Always use this two-step approach:\n\n```\n1. list_datasheet_sections(sku=\"PART-NUMBER\")\n   → See the table of contents\n   → Identify which sections contain what you need\n\n2. read_datasheet(sku=\"PART-NUMBER\", query=\"relevant keywords\")\n   → Read only matching chunks\n   → Saves significant context window\n```\n\n**Never** call `read_datasheet` without a `query` parameter unless the datasheet is short (< 20 pages). An unfiltered read of a 200-page datasheet will consume excessive context.\n\n**Keyword tips**: Use specific technical terms. \"maximum input voltage absolute ratings\" is better than \"voltage\". Multiple keywords narrow the results.\n\n## Manufacturing Pipeline\n\nManufacturing operations (DFM, fab quoting, assembly) are all asynchronous:\n\n```\nsubmit_dfm() → check_dfm_status()       # DFM analysis\nquote_fabrication() → check_manufacturing_status()  # Fab quote\nquote_assembly() → polls internally      # Combined fab + assembly\n```\n\n**DFM first**: Always run DFM analysis before requesting a fabrication quote. DFM may reveal issues that affect manufacturability or cost.\n\n**Assembly quotes** combine fabrication and BOM costing in one call. Use `quote_assembly` when the user wants a complete per-unit cost including both PCB fabrication and component assembly.\n\n## Handling Partial Failures\n\nReal-world sourcing often has partial results. Handle gracefully:\n\n**Some parts not found in BOM**:\n- Report the unmatched count clearly\n- Attempt `search_parts` for each unmatched part\n- If still unmatched, list them for the user with their reference designators and values\n- Calculate cost for matched parts, noting the incomplete total\n\n**Some parts unavailable**:\n- Report which parts are out of stock\n- Automatically call `find_alternatives` for each unavailable part\n- Present alternatives with their specifications and pricing\n- Let the user decide on substitutions\n\n**Price comparison with missing suppliers**:\n- Report how many suppliers were checked\n- Note if key suppliers (the user's preferred ones) returned no results\n- Present available pricing data without waiting for all suppliers\n\n## KiCad Project Workflow\n\nWhen working with KiCad projects:\n\n```\n1. find_kicad_projects()                    → Discover available projects\n2. analyze_kicad_project(project_path=...)  → Understand project structure\n3. extract_bom_from_kicad(project_path=...) → Get component list\n4. match_components_to_parts(components=...) → Match to real parts\n5. Follow the BOM processing pattern above for unmatched components\n```\n\n**KiCad CLI requirement**: BOM extraction may invoke `kicad-cli` if no existing BOM file is found in the project. Ensure KiCad 8+ is installed.\n\n**Local mode only**: All KiCad tools require local mode (stdio transport). They are not available in hosted/HTTP mode.\n\n## Cost Optimization Tips\n\nWhen helping users optimize costs:\n\n1. **Check quantity breaks**: Call `compare_prices` with different quantities (1, 10, 100, 1000) to show price break curves\n2. **Suggest alternatives**: If a part is expensive, call `find_alternatives` and compare pricing\n3. **Preferred suppliers**: Use `preferred_suppliers` in `calculate_bom_cost` to bias toward the user's existing supplier relationships\n4. **Consolidation**: When multiple parts come from the same supplier, note the potential for consolidated shipping\n\n## Response Patterns\n\n**When a user asks to \"source a part\"**:\n→ `search_parts` → `get_part_details` → `compare_prices` → `check_availability`\nPresent: part details, best price, stock status, and any concerns.\n\n**When a user provides a BOM file**:\n→ `upload_bom` → poll `check_bom_status` → report matched/unmatched → `calculate_bom_cost`\nPresent: match rate, unmatched items, total cost, per-line breakdown.\n\n**When a user asks \"is this in stock?\"**:\n→ `check_availability` with quantities\nPresent: stock levels, number of suppliers with stock, whether quantity is meetable.\n\n**When a user asks about a datasheet**:\n→ `list_datasheet_sections` → `read_datasheet` with targeted query\nPresent: the specific information requested, citing page numbers.\n\n**When a user asks for a manufacturing quote**:\n→ `submit_dfm` (if not already done) → `quote_fabrication` or `quote_assembly`\nPresent: DFM issues (if any), estimated cost, lead time.\n"
  },
  {
    "path": "content/spacy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"spacy package guide for Python with installation, model setup, pipeline usage, serialization, config, and version-sensitive spaCy v3.8 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.8.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"spacy,nlp,python,tokenization,ner,lemmatization,transformers\"\n---\n\n# spacy Python Package Guide\n\n## Golden Rule\n\n- Install `spacy` and a compatible trained pipeline separately.\n- Use `spacy.load(...)` when you want a maintained pipeline package, and `spacy.blank(...)` when you are assembling a custom pipeline from scratch.\n- Batch work with `nlp.pipe(...)` instead of calling `nlp(text)` in a tight loop.\n- Keep model and pipeline compatibility explicit after upgrades by running `python -m spacy validate`.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `3.8.11`.\n- PyPI currently lists `spacy 3.8.11` as the latest release, published on `2025-11-17`, so the version used here matches current upstream.\n- Current PyPI package metadata requires Python `>=3.9,<3.15`.\n- The install docs and long PyPI description still include older compatibility text such as Python `3.7+`; for environment decisions, trust the current package metadata and available wheels for `3.8.11`.\n- spaCy v3 uses registered component factories. `nlp.add_pipe(...)` takes a string factory name such as `\"sentencizer\"` or `\"entity_ruler\"`, not a bare callable.\n- Pipeline packages have their own versions and must stay compatible with your spaCy minor version. After upgrading spaCy, re-run `python -m spacy download ...` or `python -m spacy validate`.\n- In spaCy `v3.7+`, transformer pipelines use `spacy-curated-transformers` and `doc._.trf_data` is no longer the older `TransformerData` object used by older `spacy-transformers` examples.\n- spaCy `v3.8` added `Language.memory_zone()` for long-running services. Any `Doc`, `Token`, `Span`, or lexeme-backed data created inside the block must not be used after the block exits.\n\n## Install\n\nUse a virtual environment and pin the version when you need reproducible behavior:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install -U pip setuptools wheel\npython -m pip install \"spacy==3.8.11\"\npython -m spacy download en_core_web_sm\n```\n\nUseful extras from the official install docs and current PyPI metadata:\n\n- `spacy[lookups]`: install lookup tables for lemmatization and lexeme normalization when you are building blank pipelines or training your own models.\n- `spacy[transformers]`: install transformer integration for transformer-based workflows.\n- `spacy[cuda12x]` or another CUDA extra: install GPU support when the runtime has a compatible CUDA stack.\n- `spacy[apple]`: install Apple-optimized ops for Apple Silicon performance improvements.\n\nIf you prefer conda:\n\n```bash\nconda install -c conda-forge spacy\n```\n\n## Recommended Setup\n\nStart with a trained pipeline unless you have a reason to build a blank one:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\ndoc = nlp(\"Apple is looking at buying a U.K. startup for $1 billion.\")\n\nprint([(ent.text, ent.label_) for ent in doc.ents])\nprint([sent.text for sent in doc.sents])\n```\n\nUse a blank language object when you only need tokenization or you are building a custom pipeline:\n\n```python\nimport spacy\n\nnlp = spacy.blank(\"en\")\nnlp.add_pipe(\"sentencizer\")\n\ndoc = nlp(\"First sentence. Second sentence.\")\nprint([sent.text for sent in doc.sents])\n```\n\n## Core Usage\n\n### Add Built-In Components\n\nIn spaCy v3, add built-ins by registered name:\n\n```python\nimport spacy\n\nnlp = spacy.blank(\"en\")\nnlp.add_pipe(\"sentencizer\")\nruler = nlp.add_pipe(\"entity_ruler\")\nruler.add_patterns(\n    [\n        {\"label\": \"PRODUCT\", \"pattern\": \"spaCy\"},\n        {\"label\": \"ORG\", \"pattern\": \"Explosion\"},\n    ]\n)\n\ndoc = nlp(\"spaCy is built by Explosion.\")\nprint([(ent.text, ent.label_) for ent in doc.ents])\n```\n\nIf you are writing a custom component, register it with `@Language.component` or `@Language.factory` before adding it to the pipeline.\n\n### Process Text In Batches\n\nFor large workloads, stream texts with `nlp.pipe(...)`:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\ntexts = [\n    \"spaCy is fast.\",\n    \"Batch processing is usually better than one text at a time.\",\n]\n\nfor doc in nlp.pipe(texts, batch_size=64):\n    print(doc.text, [ent.text for ent in doc.ents])\n```\n\nIf you need to preserve request metadata alongside each document, use `as_tuples=True`:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\nitems = [\n    (\"The team uses package docs.\", {\"id\": 1}),\n    (\"spaCy can stream documents.\", {\"id\": 2}),\n]\n\nfor doc, meta in nlp.pipe(items, as_tuples=True):\n    print(meta[\"id\"], doc.text)\n```\n\nIf you only need part of a trained pipeline for a block of work, disable components temporarily:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\n\nwith nlp.select_pipes(disable=[\"parser\", \"tagger\", \"attribute_ruler\", \"lemmatizer\"]):\n    for doc in nlp.pipe([\"Apple released a new product.\"]):\n        print([(ent.text, ent.label_) for ent in doc.ents])\n```\n\nFor non-transformer pipelines, this is a good pattern when you only need NER. For transformer pipelines, keep the `transformer` component enabled because downstream components depend on it.\n\n### Rule-Based Matching\n\nThe `Matcher` must share the same vocab as the `Doc` objects it will process:\n\n```python\nimport spacy\nfrom spacy.matcher import Matcher\n\nnlp = spacy.blank(\"en\")\nmatcher = Matcher(nlp.vocab)\nmatcher.add(\"HELLO_WORLD\", [[{\"LOWER\": \"hello\"}, {\"LOWER\": \"world\"}]])\n\ndoc = nlp(\"hello world from spaCy\")\nmatches = matcher(doc)\nprint(matches)\n```\n\n### Save Pipelines And Serialized Docs\n\nUse `to_disk` and `from_disk` for pipeline state:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\nnlp.to_disk(\"./artifact/spacy-pipeline\")\n\nloaded = spacy.load(\"./artifact/spacy-pipeline\")\ndoc = loaded(\"Reloaded pipeline.\")\nprint(doc.ents)\n```\n\nUse `DocBin` when you need to serialize many docs efficiently:\n\n```python\nimport spacy\nfrom spacy.tokens import DocBin\n\nnlp = spacy.load(\"en_core_web_sm\")\ndocbin = DocBin(store_user_data=True)\n\nfor doc in nlp.pipe([\"one document\", \"another document\"]):\n    docbin.add(doc)\n\ndocbin.to_disk(\"docs.spacy\")\n```\n\n## Config And Runtime Setup\n\nspaCy itself does not require API keys or remote authentication. Configuration is local:\n\n- runtime configuration lives in the pipeline package and its `config.cfg`\n- custom training and custom components should keep `config.cfg` in version control\n- model selection is a local package choice such as `en_core_web_sm` vs `en_core_web_trf`\n\nFor training or custom packaged pipelines, use the spaCy CLI instead of ad hoc scripts:\n\n```bash\npython -m spacy init fill-config base.cfg config.cfg\npython -m spacy debug config config.cfg\n```\n\nIf you are starting from a partial config or a quickstart-generated config, fill it before training so the effective settings are explicit and reproducible.\n\n## Long-Running Services\n\nFor persistent services that process unbounded traffic, spaCy `v3.8` adds `memory_zone()`:\n\n```python\nimport spacy\n\nnlp = spacy.load(\"en_core_web_sm\")\n\nwith nlp.memory_zone():\n    doc = nlp(\"Process this request inside a bounded memory scope.\")\n    print(doc.ents)\n```\n\nThis reduces cache growth in `Vocab` and `StringStore`, but anything created inside the block must be treated as invalid once the block exits.\n\n## Common Pitfalls\n\n- Installing `spacy` does not install English or other pretrained pipelines. You still need `python -m spacy download en_core_web_sm` or another explicit model install.\n- `nlp.pipe(...)` returns a generator, not a list. Wrap it with `list(...)` only if you actually need all docs in memory.\n- Do not copy spaCy v2 examples that pass component callables directly to `nlp.add_pipe(...)`; spaCy v3 expects registered factory names.\n- Disabling or reordering components can break dependent annotations. In many languages, the lemmatizer depends on POS information from `tagger` plus `attribute_ruler` or from `morphologizer`.\n- When you only need sentence segmentation, prefer `senter` or `sentencizer` over running the full dependency parser.\n- Multiprocessing with `n_process` can add noticeable startup and copy overhead on macOS and Windows because Python uses `spawn`.\n- If you install or upgrade spaCy from source on a platform without suitable wheels, build constraints may be required to avoid `numpy` ABI mismatches.\n- `Matcher` and other rule-based objects should be created with `nlp.vocab`, not a separate vocab.\n- Docs created inside `memory_zone()` must not escape that context manager.\n\n## Official Links\n\n- API reference: `https://spacy.io/api`\n- Usage docs: `https://spacy.io/usage`\n- Models directory: `https://spacy.io/models`\n- Install docs: `https://spacy.io/usage`\n- Processing pipelines guide: `https://spacy.io/usage/processing-pipelines`\n- Saving and loading guide: `https://spacy.io/usage/saving-loading`\n- Memory management guide: `https://spacy.io/usage/memory-management`\n- Registry: `https://pypi.org/project/spacy/`\n- Releases: `https://github.com/explosion/spaCy/releases`\n"
  },
  {
    "path": "content/sphinx/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Sphinx package guide for building Python project documentation and API references\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sphinx,python,documentation,autodoc,docs\"\n---\n\n# Sphinx Python Package Guide\n\n## Golden Rule\n\nUse Sphinx as a build tool for checked-in documentation, with project configuration in `docs/conf.py` and repeatable builds through `sphinx-build`. For Python API docs, treat `sphinx.ext.autodoc` as an import-time integration: the package being documented and its import-time dependencies must be available in the same environment as Sphinx.\n\nSphinx works with reStructuredText out of the box. If your project prefers Markdown, add a parser extension explicitly instead of assuming Sphinx reads Markdown by default.\n\n## Install\n\nCreate a virtual environment and pin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"sphinx==9.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"sphinx==9.1.0\"\npoetry add --group docs \"sphinx==9.1.0\"\n```\n\nSphinx does not use API keys, tokens, or service credentials. The main configuration surface is `docs/conf.py` plus the extensions you enable there.\n\n## Minimal Project Layout\n\nThis is a small layout that works well for package docs and autodoc-based API references:\n\n```text\nyour-project/\n  docs/\n    conf.py\n    index.rst\n    api.rst\n  src/\n    example_pkg/\n      __init__.py\n      api.py\n```\n\nYou can scaffold a docs directory with `sphinx-quickstart`, or create the files directly.\n\n## Minimal Configuration\n\n`docs/conf.py`\n\n```python\nfrom pathlib import Path\nimport sys\n\nROOT = Path(__file__).resolve().parents[1]\nsys.path.insert(0, str(ROOT / \"src\"))\n\nproject = \"Example Package\"\nauthor = \"Your Team\"\nrelease = \"0.1.0\"\nroot_doc = \"index\"\n\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.napoleon\",\n    \"sphinx.ext.intersphinx\",\n]\n\ntemplates_path = [\"_templates\"]\nexclude_patterns = [\"_build\", \"Thumbs.db\", \".DS_Store\"]\n\nhtml_theme = \"alabaster\"\n\nintersphinx_mapping = {\n    \"python\": (\"https://docs.python.org/3\", None),\n}\n```\n\nWhy this config matters:\n\n- `sys.path.insert(...)` makes a `src/` layout importable for autodoc\n- `sphinx.ext.autodoc` pulls API documentation from Python objects and docstrings\n- `sphinx.ext.napoleon` lets Sphinx read Google-style and NumPy-style docstrings\n- `sphinx.ext.intersphinx` enables cross-project references such as Python standard library types\n\n## Write Pages And API Docs\n\n`src/example_pkg/api.py`\n\n```python\ndef greet(name: str) -> str:\n    \"\"\"Return a greeting.\n\n    Args:\n        name: Person or system name.\n\n    Returns:\n        Greeting text.\n    \"\"\"\n    return f\"Hello, {name}!\"\n```\n\n`docs/index.rst`\n\n```rst\nExample Package\n===============\n\n.. toctree::\n   :maxdepth: 2\n\n   api\n```\n\n`docs/api.rst`\n\n```rst\nAPI Reference\n=============\n\n.. automodule:: example_pkg.api\n   :members:\n   :undoc-members:\n```\n\nBuild the HTML output:\n\n```bash\nsphinx-build -b html docs docs/_build/html\n```\n\nOpen `docs/_build/html/index.html` in a browser to inspect the generated site.\n\n## Common Workflows\n\n### Generate API stub files from a package\n\nIf you want Sphinx to generate `.rst` stubs for a package tree, use `sphinx-apidoc`:\n\n```bash\nsphinx-apidoc -o docs/reference src/example_pkg\n```\n\nThat command writes reStructuredText files under `docs/reference/`. Add the generated `modules` page, or individual generated pages, to your `toctree`.\n\n### Make warnings fail CI\n\nSphinx does not fail the build on ordinary warnings unless you ask it to. For CI, use `-W` and keep building long enough to collect the full warning set:\n\n```bash\nsphinx-build -W --keep-going -b html docs docs/_build/html\n```\n\n### Check external links\n\nUse the `linkcheck` builder separately from normal HTML builds:\n\n```bash\nsphinx-build -b linkcheck docs docs/_build/linkcheck\n```\n\n### Cross-reference Python docs\n\nWith `intersphinx_mapping` configured, you can reference external objects directly in reStructuredText:\n\n```rst\nSee :py:class:`pathlib.Path` for path handling.\n```\n\n## Common Pitfalls\n\n### `autodoc` imports your code\n\n`sphinx.ext.autodoc` imports the documented modules during the build. If module import has side effects, reaches for unavailable services, or depends on optional packages that are missing in the docs environment, the build can fail.\n\nPractical fixes:\n\n- keep import-time side effects out of module top level\n- install your package and docs dependencies into the same virtual environment\n- if needed, mock unavailable imports with `autodoc_mock_imports` in `conf.py`\n\n### `src/` layouts need an import path or editable install\n\nIf your package lives under `src/`, autodoc will not find it unless you either:\n\n- add the `src` directory to `sys.path` in `conf.py`, or\n- install the package into the docs environment, usually with `python -m pip install -e .`\n\nWithout one of those, `.. automodule:: your_package.module` usually fails with an import error.\n\n### Markdown is not built in\n\nSphinx reads reStructuredText directly. Markdown support requires an additional parser extension. If you add Markdown source files without a parser, Sphinx will not treat them as documentation pages.\n\n### Third-party themes are separate packages\n\nThemes such as `furo` or `sphinx-rtd-theme` are not part of the `sphinx` package itself. Install them separately and set `html_theme` only after the theme package is present in the docs environment.\n\n### `make html` is just a wrapper\n\nProjects created with `sphinx-quickstart` usually include `Makefile` and `make.bat` helpers, but the underlying command is still `sphinx-build`. In CI and automation, use `sphinx-build` directly so the invoked builder and output path are explicit.\n\n## Version-Sensitive Notes For 9.1.0\n\n- This guide pins `sphinx==9.1.0`, while the official docs root for current guidance is the rolling `master` documentation tree. If your project is strictly pinned, check the Sphinx release notes before relying on behavior added after 9.1.0.\n- Prefer `root_doc` in new configuration examples. Older posts and snippets may still use the legacy `master_doc` name.\n- The core command-line tools remain `sphinx-build`, `sphinx-quickstart`, and `sphinx-apidoc`; older examples that shell out through wrappers are usually just convenience layers over those commands.\n\n## Official Sources\n\n- Docs root: `https://www.sphinx-doc.org/en/master/`\n- Quickstart: `https://www.sphinx-doc.org/en/master/usage/quickstart.html`\n- Configuration: `https://www.sphinx-doc.org/en/master/usage/configuration.html`\n- reStructuredText primer: `https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html`\n- `autodoc`: `https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html`\n- `napoleon`: `https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html`\n- `intersphinx`: `https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html`\n- `sphinx-build`: `https://www.sphinx-doc.org/en/master/man/sphinx-build.html`\n- `sphinx-apidoc`: `https://www.sphinx-doc.org/en/master/man/sphinx-apidoc.html`\n- PyPI package page: `https://pypi.org/project/sphinx/9.1.0/`\n"
  },
  {
    "path": "content/sphinx-rtd-theme/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Read the Docs Sphinx theme package guide for Python documentation projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"sphinx,readthedocs,theme,docs,python\"\n---\n\n# sphinx-rtd-theme Python Package Guide\n\n## Golden Rule\n\nUse the PyPI package `sphinx-rtd-theme`, but configure it in Sphinx as `sphinx_rtd_theme`.\n\n- Install name: `sphinx-rtd-theme`\n- Sphinx extension name: `sphinx_rtd_theme`\n- Theme name in `conf.py`: `sphinx_rtd_theme`\n\nFor `3.1.0`, the maintainer docs list support for Python 3.8+, Sphinx 6+, and docutils `>0.18, <0.23`.\n\n## Install\n\nNo environment variables or authentication are required. This package only changes HTML output for a Sphinx docs build.\n\nIf you are pinning the version documented here:\n\n```bash\npython -m pip install \"Sphinx>=6\" \"sphinx-rtd-theme==3.1.0\"\n```\n\nIf your project already pins Sphinx separately, add just the theme:\n\n```bash\npython -m pip install \"sphinx-rtd-theme==3.1.0\"\n```\n\n## Minimal Sphinx Setup\n\nAdd the theme to `docs/conf.py`:\n\n```python\n# docs/conf.py\nextensions = [\n    \"sphinx_rtd_theme\",\n]\n\nhtml_theme = \"sphinx_rtd_theme\"\n```\n\nThe theme docs explicitly recommend adding `sphinx_rtd_theme` to `extensions` because it activates `sphinxcontrib-jquery`, which the theme still uses for search, smooth scrolling, and the flyout menu.\n\nBuild the HTML output:\n\n```bash\nsphinx-build -b html docs docs/_build/html\n```\n\n## Common Theme Configuration\n\nStart from a small `html_theme_options` block and only add options you need:\n\n```python\n# docs/conf.py\nhtml_theme = \"sphinx_rtd_theme\"\nhtml_theme_options = {\n    \"logo_only\": True,\n    \"collapse_navigation\": False,\n    \"navigation_depth\": 4,\n    \"sticky_navigation\": True,\n    \"includehidden\": True,\n    \"titles_only\": False,\n    \"prev_next_buttons_location\": \"bottom\",\n    \"style_external_links\": True,\n    \"style_nav_header_background\": \"#2980B9\",\n}\n```\n\nOptions that matter most in practice:\n\n- `navigation_depth`: controls how many heading levels appear in the left nav. `-1` means unlimited depth.\n- `collapse_navigation`: when `False`, nested sections stay expanded instead of collapsing to the current branch.\n- `sticky_navigation`: keeps the left nav fixed while scrolling.\n- `prev_next_buttons_location`: `bottom`, `top`, `both`, or `None`.\n- `style_external_links`: adds an external-link icon style.\n- `logo_only`: shows the logo without repeating the project name in the sidebar.\n\nIf you want a logo, set Sphinx's standard `html_logo` option:\n\n```python\nhtml_logo = \"_static/logo.svg\"\n```\n\n## Read the Docs Selectors\n\nThe theme exposes `version_selector` and `language_selector`, but the maintainer docs state these only work for documentation hosted or served on Read the Docs.\n\n```python\nhtml_theme_options = {\n    \"version_selector\": True,\n    \"language_selector\": True,\n}\n```\n\nDo not expect those selectors to appear in a plain local `sphinx-build` output unless your docs are being served by Read the Docs with its Addons integration.\n\n## Repository Links And Page Metadata\n\nFor repository links in the upper-right corner, use `html_context` with the keys documented by the theme:\n\n```python\nhtml_context = {\n    \"display_github\": True,\n    \"github_user\": \"acme\",\n    \"github_repo\": \"my-project\",\n    \"github_version\": \"main\",\n    \"conf_py_path\": \"/docs/\",\n}\n```\n\nThe theme also supports file-wide metadata keys such as `github_url`, `gitlab_url`, and `bitbucket_url` when you need a per-page override.\n\n## Common Pitfalls\n\n- Do not copy old examples that import `sphinx_rtd_theme` and set `html_theme_path`. Current docs only require `extensions` plus `html_theme`, and the 3.x changelog says defining `html_theme_path` now raises a warning.\n- The package name uses dashes, but Sphinx config uses underscores. `pip install sphinx-rtd-theme` is correct; `html_theme = \"sphinx_rtd_theme\"` is also correct.\n- If you skip `extensions = [\"sphinx_rtd_theme\"]`, the theme's jQuery-dependent features are not activated correctly.\n- `version_selector` and `language_selector` are not general-purpose local widgets. They are documented as Read the Docs-only features.\n- `analytics_id` and `analytics_anonymize_ip` are deprecated in 3.x. Use `sphinxcontrib-googleanalytics` instead of adding those theme options to new configs.\n- `flyout_display: \"attached\"` requires disabling the default Read the Docs flyout, otherwise you can end up with duplicated flyout UI.\n\n## Version-Sensitive Notes For 3.1.0\n\n- `3.1.0` was released on September 17, 2024.\n- The `3.1.0` changelog adds support for docutils `0.22` and Sphinx `9.x`.\n- The broader support matrix in the maintainer docs still lists Python 3.8+, Sphinx 6+, and docutils `>0.18, <0.23`.\n\n## Official Sources\n\n- PyPI package: https://pypi.org/project/sphinx-rtd-theme/\n- Install guide: https://sphinx-rtd-theme.readthedocs.io/en/stable/installing.html\n- Configuration guide: https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html\n- Changelog: https://sphinx-rtd-theme.readthedocs.io/en/stable/changelog.html\n- Supported dependencies: https://sphinx-rtd-theme.readthedocs.io/en/stable/development.html\n- Sphinx HTML config reference: https://www.sphinx-doc.org/en/master/usage/configuration.html\n"
  },
  {
    "path": "content/splitio-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Split Python SDK (`splitio-client`) guide for feature flags, treatments, and event tracking\"\nmetadata:\n  languages: \"python\"\n  versions: \"10.6.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"split,harness,feature-flags,experimentation,python,sdk\"\n---\n\n# Split Python SDK Package Guide\n\n## Golden Rule\n\nUse `splitio-client` for server-side Split Feature Management and Experimentation in Python, initialize it once per process with a server-side SDK key, wait for readiness before evaluating flags, and always destroy the factory on shutdown so impressions, events, and telemetry can flush cleanly.\n\nThe docs URL (`https://help.split.io/hc/en-us/articles/360020359652`) now redirects to Harness's canonical Python SDK page. Use the Harness page for current behavior and config details.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"splitio-client==10.6.0\"\n```\n\nThe official docs commonly recommend the `cpphash` extra:\n\n```bash\npython -m pip install \"splitio-client[cpphash]==10.6.0\"\n```\n\nExtras from the official package metadata:\n\n```bash\npython -m pip install \"splitio-client[asyncio]==10.6.0\"\npython -m pip install \"splitio-client[redis]==10.6.0\"\n```\n\nUse the extra that matches your runtime:\n\n- `cpphash`: preferred default from the official docs\n- `asyncio`: required if you use the SDK's asyncio support\n- `redis`: required for Redis-backed synchronization in multi-process deployments\n\n## Authentication And Initialization\n\nThe SDK uses a Split server-side SDK key, not an end-user credential. Put it in an environment variable and construct the factory once per process:\n\n```bash\nexport SPLIT_SDK_KEY=\"your-server-side-sdk-key\"\n```\n\n```python\nimport os\nfrom splitio import get_factory\n\nsdk_key = os.environ[\"SPLIT_SDK_KEY\"]\n\nfactory = get_factory(\n    sdk_key,\n    config={\n        \"impressionsMode\": \"OPTIMIZED\",\n        \"labelsEnabled\": False,\n    },\n)\n\nready = factory.block_until_ready(timeout=5)\nif not ready:\n    raise RuntimeError(\"Split SDK did not become ready in time\")\n\nclient = factory.client()\nmanager = factory.manager()\n```\n\nNotes:\n\n- `factory.block_until_ready()` is the safe gate before evaluating treatments.\n- Keep a singleton factory instead of rebuilding clients per request.\n- Call `factory.destroy()` during process shutdown to flush pending work and stop SDK threads.\n\n## Core Usage\n\n### Evaluate a treatment\n\nUse a stable matching key. The simplest server-side form is a string key:\n\n```python\ntreatment = client.get_treatment(\"customer-123\", \"checkout_redesign\")\n\nif treatment == \"on\":\n    enable_new_checkout()\nelse:\n    enable_legacy_checkout()\n```\n\n### Evaluate with attributes\n\nPass attributes when your targeting rules depend on them:\n\n```python\ntreatment = client.get_treatment(\n    \"customer-123\",\n    \"checkout_redesign\",\n    attributes={\n        \"plan\": \"pro\",\n        \"account_age_days\": 420,\n        \"region\": \"us\",\n    },\n)\n```\n\n### Read treatment config\n\nIf the flag uses dynamic config, fetch both the treatment and the config payload:\n\n```python\ntreatment, config = client.get_treatment_with_config(\n    \"customer-123\",\n    \"checkout_redesign\",\n)\n\nif treatment == \"on\" and config:\n    apply_checkout_config(config)\n```\n\n### Track an event\n\nUse `track()` for conversion or business events tied to a key and traffic type:\n\n```python\nok = client.track(\n    \"customer-123\",\n    \"user\",\n    \"checkout_completed\",\n    value=149.0,\n    properties={\n        \"currency\": \"USD\",\n        \"plan\": \"pro\",\n    },\n)\n\nif not ok:\n    raise RuntimeError(\"Split track() returned False\")\n```\n\n### Inspect flag metadata\n\nThe manager exposes split definitions and metadata without evaluating treatments:\n\n```python\nsplit_view = manager.split(\"checkout_redesign\")\nif split_view is None:\n    raise LookupError(\"Unknown split\")\n\nprint(split_view.name)\nprint(split_view.killed)\nprint(split_view.change_number)\n```\n\n### Shutdown cleanly\n\n```python\ntry:\n    run_application(client)\nfinally:\n    factory.destroy()\n```\n\n## Configuration Notes\n\nThe Python SDK accepts a `config` dictionary when you create the factory. Common settings agents tend to need first:\n\n- `impressionsMode`: choose the impression collection mode explicitly if your org has guidance for optimized vs debug-style visibility\n- `labelsEnabled`: disable labels when you do not need them, especially if you want less verbose impression data\n- `localhost`: use local override files for offline development or tests\n- Redis-backed settings: use these only for supported multi-process deployments and install the `redis` extra first\n\nPractical setup guidance from the official docs:\n\n- Use one SDK instance per process.\n- Keep the SDK warm in long-lived processes instead of recreating it per request or job.\n- In web apps and workers, own initialization and teardown at process lifespan boundaries.\n- For async runtimes, install the `asyncio` extra and follow the SDK's async-specific setup instead of mixing sync examples into an async event loop.\n\n## Localhost Mode\n\nFor local development or tests, the SDK supports localhost mode with file-based flag definitions. This is useful when you want deterministic flag behavior without a live Split environment.\n\nUse localhost mode when:\n\n- CI should not depend on live flag state\n- local development needs fixed treatments\n- you want predictable unit or integration tests around flag branches\n\nTreat localhost mode as a local override, not as a substitute for validating real targeting rules in a live environment.\n\n## Multi-Process And Async Notes\n\nThe official docs call out deployment-specific behavior that matters in Python:\n\n- Django and other pre-fork or multi-process servers need multi-process-aware setup; do not assume a single in-memory SDK instance is shared across workers.\n- Redis consumer mode requires the `redis` extra and a supported Redis-backed architecture.\n- Async support was added in the `10.x` line and requires Python `3.7.16+` plus the `asyncio` extra.\n- If you are on `uWSGI`, follow the Python SDK's dedicated guidance instead of a generic WSGI startup pattern.\n\n## Common Pitfalls\n\n- Do not use the SDK before readiness. If you skip `block_until_ready()`, early evaluations can return fallback or `control` behavior.\n- Do not recreate the factory on every request. The SDK maintains background synchronization and telemetry workers.\n- Do not forget `factory.destroy()`. Losing shutdown flushes can drop impressions or events.\n- Keep matching keys stable and deterministic. Random or per-request keys make treatments inconsistent.\n- Use the correct traffic type in `track()`. The event can fail or become misleading if the traffic type does not match your Split definitions.\n- Prefer the canonical Harness docs over older `help.split.io` links; the old Help Center URL is a redirect, not the maintained source.\n- For offline testing, use localhost mode rather than monkey-patching SDK internals.\n\n## Version-Sensitive Notes For `10.6.0`\n\n- PyPI and the current docs both align on `splitio-client 10.6.0` as of 2026-03-12.\n- `8.0.0` moved `block_until_ready` to the factory, so older examples that call readiness methods elsewhere are stale.\n- `10.0.0` introduced asyncio support; async projects should prefer the async-specific installation and initialization guidance from the official docs.\n- The maintained documentation is now under Harness Developer Hub, even though the package name and many examples still use the older Split branding.\n\n## Official Sources\n\n- Harness Python SDK docs: `https://developer.harness.io/docs/feature-management-experimentation/sdks-and-infrastructure/client-side-sdks/python-sdk/`\n- Redirecting docs URL: `https://help.split.io/hc/en-us/articles/360020359652`\n- PyPI package page: `https://pypi.org/project/splitio-client/`\n"
  },
  {
    "path": "content/sqladmin/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SQLAdmin package guide for FastAPI and Starlette apps using SQLAlchemy model admins, authentication, and custom views\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.23.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"sqladmin,sqlalchemy,fastapi,starlette,admin,python\"\n---\n\n# SQLAdmin Python Package Guide\n\n## What It Is\n\n`sqladmin` adds an admin UI for SQLAlchemy models in Starlette and FastAPI applications. The maintainer docs describe support for sync and async SQLAlchemy engines, WTForms-based form generation, and SQLModel-backed models.\n\nBy default, the admin UI is mounted at `/admin`.\n\nThis guide covers `0.23.0`.\n\n## Install\n\nInstall the package version this guide covers:\n\n```bash\npython -m pip install \"sqladmin==0.23.0\"\n```\n\nPyPI also publishes a `full` extra for optional dependencies:\n\n```bash\npython -m pip install \"sqladmin[full]==0.23.0\"\n```\n\nFor the FastAPI examples below you also need your ASGI framework, SQLAlchemy, and a server:\n\n```bash\npython -m pip install \"fastapi>=0.110\" \"sqlalchemy>=2.0\" \"uvicorn[standard]\"\n```\n\nIf you use PostgreSQL, MySQL, or async SQLite, install the matching SQLAlchemy driver separately.\n\n### Example environment variables\n\nSQLAdmin does not define env var names itself; these are app-level values used by the examples in this guide:\n\n```env\nDATABASE_URL=sqlite:///./app.db\nADMIN_SECRET_KEY=change-me\nADMIN_USERNAME=admin\nADMIN_PASSWORD=change-me\n```\n\n## Minimal FastAPI Setup\n\nThis is the smallest useful setup: define a SQLAlchemy model, create the `Admin` object, register a `ModelView`, and run the app.\n\n```python\nimport os\n\nfrom fastapi import FastAPI\nfrom sqlalchemy import Boolean, Column, Integer, String, create_engine\nfrom sqlalchemy.orm import declarative_base\nfrom sqladmin import Admin, ModelView\n\nDATABASE_URL = os.getenv(\"DATABASE_URL\", \"sqlite:///./app.db\")\n\nBase = declarative_base()\nengine = create_engine(\n    DATABASE_URL,\n    connect_args={\"check_same_thread\": False} if DATABASE_URL.startswith(\"sqlite\") else {},\n)\n\n\nclass User(Base):\n    __tablename__ = \"users\"\n\n    id = Column(Integer, primary_key=True)\n    email = Column(String, nullable=False, unique=True)\n    is_active = Column(Boolean, default=True, nullable=False)\n\n\nBase.metadata.create_all(engine)\n\napp = FastAPI()\nadmin = Admin(app, engine, base_url=\"/admin\", title=\"Backoffice\")\n\n\nclass UserAdmin(ModelView, model=User):\n    name = \"User\"\n    name_plural = \"Users\"\n    column_list = [User.id, User.email, User.is_active]\n    column_searchable_list = [User.email]\n    column_sortable_list = [User.id, User.email]\n    can_view_details = True\n    can_export = True\n\n\nadmin.add_view(UserAdmin)\n```\n\nRun it:\n\n```bash\nuvicorn main:app --reload\n```\n\nOpen `http://127.0.0.1:8000/admin`.\n\nImportant default: if you do not set `column_list`, SQLAdmin only shows the model primary key in the list page.\n\n## Use Your Existing `sessionmaker`\n\n`Admin(...)` accepts either `engine=` or `session_maker=`. Use `session_maker=` when your app already has a configured session factory, when you need async sessions, or when one session is bound to multiple databases.\n\n```python\nimport os\n\nfrom fastapi import FastAPI\nfrom sqlalchemy.ext.asyncio import AsyncSession, create_async_engine\nfrom sqlalchemy.orm import sessionmaker\nfrom sqladmin import Admin\n\nengine = create_async_engine(os.environ[\"DATABASE_URL\"])\nSession = sessionmaker(bind=engine, class_=AsyncSession)\n\napp = FastAPI()\nadmin = Admin(app=app, session_maker=Session)\n```\n\nThis preserves your own session configuration instead of letting SQLAdmin build a session factory from an engine.\n\n## Authentication\n\nSQLAdmin does not enforce authentication by itself. The documented way to protect the admin is to provide an `AuthenticationBackend`.\n\n`AuthenticationBackend` requires `itsdangerous`. Install it directly or use `sqladmin[full]`.\n\n```python\nimport os\n\nfrom sqladmin.authentication import AuthenticationBackend\nfrom starlette.requests import Request\n\n\nclass AdminAuth(AuthenticationBackend):\n    async def login(self, request: Request) -> bool:\n        form = await request.form()\n        username = form[\"username\"]\n        password = form[\"password\"]\n\n        if (\n            username != os.environ[\"ADMIN_USERNAME\"]\n            or password != os.environ[\"ADMIN_PASSWORD\"]\n        ):\n            return False\n\n        request.session.update({\"admin_token\": \"authenticated\"})\n        return True\n\n    async def logout(self, request: Request) -> bool:\n        request.session.clear()\n        return True\n\n    async def authenticate(self, request: Request) -> bool:\n        return bool(request.session.get(\"admin_token\"))\n\n\nauthentication_backend = AdminAuth(secret_key=os.environ[\"ADMIN_SECRET_KEY\"])\nadmin = Admin(app=app, engine=engine, authentication_backend=authentication_backend)\n```\n\nFor OAuth-style flows, the upstream docs show adding Starlette `SessionMiddleware` and returning a redirect from `authenticate(...)` when the user is not logged in.\n\n## Common `ModelView` Configuration\n\nMost day-to-day customization happens on the `ModelView` class.\n\n```python\nfrom sqladmin import ModelView\n\n\nclass UserAdmin(ModelView, model=User):\n    can_create = True\n    can_edit = True\n    can_delete = False\n    can_view_details = True\n\n    column_list = [User.id, User.email, User.is_active]\n    column_searchable_list = [User.email]\n    column_sortable_list = [User.id, User.email]\n    column_labels = {User.email: \"Email\"}\n\n    page_size = 25\n    page_size_options = [25, 50, 100]\n\n    form_excluded_columns = []\n```\n\nUseful documented options:\n\n- `column_searchable_list` enables list-page search.\n- `column_sortable_list` enables sortable columns.\n- `page_size` and `page_size_options` control list pagination.\n- `form_ajax_refs` loads related models asynchronously for large relationship tables.\n- `can_export`, `column_export_list`, and `export_max_rows` control list exports.\n\nThe configuration guide says export support is currently CSV-only.\n\n## Custom Admin Pages\n\nUse `BaseView` and `@expose(...)` when you need a dashboard or a non-model page inside the admin UI.\n\n```python\nfrom sqladmin import BaseView, expose\nfrom starlette.requests import Request\n\n\nclass ReportView(BaseView):\n    name = \"Reports\"\n    icon = \"fa-solid fa-chart-line\"\n\n    @expose(\"/reports\", methods=[\"GET\"])\n    async def reports(self, request: Request):\n        return await self.templates.TemplateResponse(request, \"report.html\")\n\n\nadmin.add_view(ReportView)\n```\n\nBy default SQLAdmin looks for templates in a `templates` directory. If your app keeps them elsewhere, pass `templates_dir=\"my_templates\"` to `Admin(...)`.\n\n## Sensitive Fields And Form Rules\n\nThe upstream password example uses three SQLAdmin features together:\n\n- `column_labels` to rename a stored field like `hashed_password` to a friendlier label\n- `form_create_rules` and `form_edit_rules` to show different fields on create vs edit\n- `on_model_change(...)` to transform data before saving it\n\nUse that pattern for password hashing or other write-time transformations.\n\nImportant constraint from the API reference: `form_create_rules` and `form_edit_rules` cannot be combined with `form_rules`.\n\n## Common Pitfalls\n\n- SQLAdmin does not secure your app automatically. If you do not pass `authentication_backend=...`, `/admin` is available without a login flow.\n- `AuthenticationBackend` needs `itsdangerous`; install it explicitly or use the `full` extra.\n- Only the primary key is shown by default in list pages. Set `column_list` on every `ModelView` you care about.\n- Use `session_maker=` instead of `engine=` if your app already has a configured session factory or multiple binds.\n- `form_create_rules` and `form_edit_rules` are mutually exclusive with `form_rules`.\n- Use `form_ajax_refs` for relationships with many rows; otherwise admin forms can become unwieldy.\n\n## Official Sources\n\n- Maintainer docs root: https://aminalaee.github.io/sqladmin/\n- Quickstart: https://aminalaee.github.io/sqladmin/\n- Configuration guide: https://aminalaee.github.io/sqladmin/configurations/\n- Authentication guide: https://aminalaee.github.io/sqladmin/authentication/\n- Custom views: https://aminalaee.github.io/sqladmin/writing_custom_views/\n- Multiple databases / `session_maker`: https://aminalaee.github.io/sqladmin/cookbook/multiple_databases/\n- Password workflow example: https://aminalaee.github.io/sqladmin/cookbook/working_with_passwords/\n- Application API reference: https://aminalaee.github.io/sqladmin/api_reference/application/\n- `ModelView` API reference: https://aminalaee.github.io/sqladmin/api_reference/model_view/\n- PyPI package page: https://pypi.org/project/sqladmin/\n"
  },
  {
    "path": "content/sqlalchemy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SQLAlchemy package guide for Python 2.0.48, covering engine setup, ORM/Core usage, transactions, and asyncio\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.48\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"sqlalchemy,orm,sql,database,python,asyncio\"\n---\n\n# SQLAlchemy Python Package Guide\n\n## What It Is\n\n`SQLAlchemy` is the main Python database toolkit and ORM. In 2.0, the intended style is:\n\n- Core for SQL expression construction and connection-level work\n- ORM for mapped classes and unit-of-work persistence\n- `select()` plus `Session.execute()` / `Session.scalars()` instead of legacy `Query`-first patterns\n\nThis guide is for SQLAlchemy `2.0.48`, using the official 2.0 docs at `https://docs.sqlalchemy.org/en/20/`.\n\n## Install\n\nInstall the package itself:\n\n```bash\npip install SQLAlchemy==2.0.48\n```\n\nSQLAlchemy also needs a DBAPI driver for the database you actually use. Common choices:\n\n```bash\npip install psycopg[binary]\npip install PyMySQL\npip install aiosqlite\n```\n\nPyPI also exposes extras for several backends and async support, for example:\n\n```bash\npip install \"SQLAlchemy[asyncio]==2.0.48\"\npip install \"SQLAlchemy[postgresql-asyncpg]==2.0.48\"\n```\n\nNotes:\n\n- `pip install SQLAlchemy` installs SQLAlchemy itself, not every database driver.\n- SQLAlchemy's `asyncio` support depends on `greenlet`; this is installed automatically on common platforms but may need extra attention on less common architectures.\n- If your project is already pinned, match that version instead of blindly taking latest examples from the web.\n\n## Choose the Right Surface\n\nUse Core when you want direct SQL expression work:\n\n```python\nfrom sqlalchemy import create_engine, text\n\nengine = create_engine(\"sqlite:///app.db\")\n\nwith engine.begin() as conn:\n    conn.execute(text(\"CREATE TABLE IF NOT EXISTS ping (id integer primary key)\"))\n```\n\nUse ORM when you want typed mapped classes, sessions, and identity tracking:\n\n```python\nfrom typing import Optional\n\nfrom sqlalchemy import String, create_engine, select\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column\n\nclass Base(DeclarativeBase):\n    pass\n\nclass User(Base):\n    __tablename__ = \"user_account\"\n\n    id: Mapped[int] = mapped_column(primary_key=True)\n    name: Mapped[str] = mapped_column(String(50))\n    fullname: Mapped[Optional[str]]\n\nengine = create_engine(\"sqlite:///app.db\")\nBase.metadata.create_all(engine)\n\nwith Session(engine) as session:\n    session.add(User(name=\"squidward\", fullname=\"Squidward Tentacles\"))\n    session.commit()\n\nwith Session(engine) as session:\n    user = session.scalar(select(User).where(User.name == \"squidward\"))\n    print(user)\n```\n\n## Engine and Connection Setup\n\nCreate one long-lived `Engine` per database configuration and reuse it across the app. `create_engine()` does not open a real DBAPI connection immediately; the first connection is established on first use.\n\nTypical URL forms:\n\n```python\nfrom sqlalchemy import create_engine\n\nsqlite_engine = create_engine(\"sqlite:///app.db\")\npostgres_engine = create_engine(\"postgresql://user:password@localhost/app\")\nmysql_engine = create_engine(\"mysql+pymysql://user:password@localhost/app\")\n```\n\nIf credentials contain characters like `@` or `/`, either URL-encode them or build the URL programmatically:\n\n```python\nfrom sqlalchemy import URL, create_engine\n\nurl = URL.create(\n    \"postgresql+psycopg\",\n    username=\"dbuser\",\n    password=\"kx@jj5/g\",\n    host=\"db.internal\",\n    database=\"appdb\",\n)\n\nengine = create_engine(url)\n```\n\nUseful setup options:\n\n```python\nengine = create_engine(\n    \"postgresql://user:password@localhost/app\",\n    echo=False,\n    pool_pre_ping=True,\n)\n```\n\nUse `echo=True` only for local debugging; it logs SQL and parameters to stdout.\n\n## ORM Model Setup\n\nFor new 2.0 code, prefer typed declarative mappings with:\n\n- `DeclarativeBase`\n- `Mapped[...]`\n- `mapped_column()`\n- `relationship()` for ORM links\n\nExample with a one-to-many relationship:\n\n```python\nfrom __future__ import annotations\n\nfrom typing import List, Optional\n\nfrom sqlalchemy import ForeignKey, String\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship\n\nclass Base(DeclarativeBase):\n    pass\n\nclass User(Base):\n    __tablename__ = \"user_account\"\n\n    id: Mapped[int] = mapped_column(primary_key=True)\n    name: Mapped[str] = mapped_column(String(30))\n    fullname: Mapped[Optional[str]]\n    addresses: Mapped[List[\"Address\"]] = relationship(back_populates=\"user\")\n\nclass Address(Base):\n    __tablename__ = \"address\"\n\n    id: Mapped[int] = mapped_column(primary_key=True)\n    email_address: Mapped[str]\n    user_id: Mapped[int] = mapped_column(ForeignKey(\"user_account.id\"))\n    user: Mapped[User] = relationship(back_populates=\"addresses\")\n```\n\nFor prototypes and tests, create tables directly:\n\n```python\nBase.metadata.create_all(engine)\n```\n\nFor production schema evolution, use migrations instead of relying on repeated `create_all()` calls.\n\n## Sessions and Transactions\n\nCreate one shared `sessionmaker` in application setup, then create short-lived `Session` objects per request, job, or command.\n\n```python\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker\n\nengine = create_engine(\"postgresql://user:password@localhost/app\")\nSessionLocal = sessionmaker(engine, expire_on_commit=False)\n```\n\nPreferred transaction shape:\n\n```python\nfrom sqlalchemy import select\n\nwith SessionLocal.begin() as session:\n    session.add(User(name=\"patrick\", fullname=\"Patrick Star\"))\n\nwith SessionLocal() as session:\n    user = session.scalar(select(User).where(User.name == \"patrick\"))\n    print(user)\n```\n\nPractical rules:\n\n- Keep the session lifecycle outside helper functions when possible.\n- Put the main `begin` / `commit` boundary at the outermost layer.\n- Reuse the `sessionmaker`; do not recreate it on every query.\n- Call `Session.rollback()` after a flush or commit failure before trying to reuse that session.\n\n## Querying in 2.0 Style\n\nPrefer `select()` everywhere for new code.\n\nLoad ORM rows:\n\n```python\nfrom sqlalchemy import select\n\nstmt = select(User).where(User.name.in_([\"sandy\", \"patrick\"]))\n\nwith SessionLocal() as session:\n    users = session.scalars(stmt).all()\n```\n\nLoad one object:\n\n```python\nwith SessionLocal() as session:\n    user = session.scalar(select(User).where(User.id == 1))\n```\n\nGet by primary key:\n\n```python\nwith SessionLocal() as session:\n    user = session.get(User, 1)\n```\n\nJoin across relationships:\n\n```python\nstmt = (\n    select(Address)\n    .join(Address.user)\n    .where(User.name == \"sandy\")\n)\n\nwith SessionLocal() as session:\n    addresses = session.scalars(stmt).all()\n```\n\nWhen you use joined eager loading for collections, call `.unique()` before materializing ORM objects:\n\n```python\nfrom sqlalchemy.orm import joinedload\n\nstmt = select(User).options(joinedload(User.addresses))\n\nwith SessionLocal() as session:\n    users = session.scalars(stmt).unique().all()\n```\n\n## Core SQL Execution\n\nFor raw SQL or expression-language work, execute against a `Connection`, not the `Engine` directly:\n\n```python\nfrom sqlalchemy import create_engine, select, table, column, text\n\nengine = create_engine(\"sqlite:///app.db\")\nfoo = table(\"foo\", column(\"id\"))\n\nwith engine.begin() as conn:\n    conn.execute(text(\"CREATE TABLE IF NOT EXISTS foo (id integer primary key)\"))\n    conn.execute(text(\"INSERT INTO foo (id) VALUES (1)\"))\n\nwith engine.connect() as conn:\n    rows = conn.execute(select(foo.c.id)).fetchall()\n```\n\nIf you need textual SQL, wrap it in `text(...)`.\n\n## AsyncIO Setup\n\nUse the async extension only with an async-compatible dialect/driver such as `postgresql+asyncpg` or `sqlite+aiosqlite`.\n\n```python\nfrom sqlalchemy import select\nfrom sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine\n\nengine = create_async_engine(\"sqlite+aiosqlite:///app.db\")\nAsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)\n\nasync with AsyncSessionLocal() as session:\n    result = await session.execute(select(User))\n    users = result.scalars().all()\n```\n\nCreating tables from async code:\n\n```python\nasync with engine.begin() as conn:\n    await conn.run_sync(Base.metadata.create_all)\n```\n\nAsync rules that matter:\n\n- Use a separate `AsyncSession` per concurrent task.\n- Avoid implicit lazy loading under asyncio.\n- Prefer eager loading such as `selectinload(...)` when you know related data is needed.\n- `expire_on_commit=False` is usually the safer default for async ORM usage.\n- If you need awaitable relationship access, use `AsyncAttrs` and `awaitable_attrs`.\n\nExample eager load:\n\n```python\nfrom sqlalchemy import select\nfrom sqlalchemy.orm import selectinload\n\nstmt = select(User).options(selectinload(User.addresses))\n\nasync with AsyncSessionLocal() as session:\n    result = await session.execute(stmt)\n    users = result.scalars().all()\n```\n\n## Configuration and Auth Notes\n\nTreat the database URL as configuration, not hardcoded source text.\n\n```python\nimport os\nfrom sqlalchemy import create_engine\n\nDATABASE_URL = os.environ[\"DATABASE_URL\"]\nengine = create_engine(DATABASE_URL, pool_pre_ping=True)\n```\n\nCommon examples:\n\n```text\npostgresql://user:password@localhost/app\npostgresql+psycopg://user:password@localhost/app\nmysql+pymysql://user:password@localhost/app\nsqlite:///./app.db\nsqlite+aiosqlite:///./app.db\n```\n\nNotes:\n\n- SQLAlchemy handles connection logic; actual auth support comes from the driver and database backend.\n- Backend-specific SSL, token auth, and socket options usually go in the URL query string, `connect_args`, or dialect-specific options.\n- If passwords include reserved URL characters, prefer `URL.create(...)`.\n\n## Common Pitfalls\n\n### Mixing 1.x and 2.0 Query Patterns\n\nFor new code, prefer:\n\n- `select(User)` instead of building everything around `session.query(User)`\n- `session.execute(...)`, `session.scalars(...)`, `session.scalar(...)`\n\nLegacy `Query` APIs still exist in parts of 2.0, but the official migration target is the unified `select()` pattern.\n\n### Using `engine.execute()`\n\nDo not generate new code with `engine.execute()`. In 2.0, statement execution belongs on:\n\n- `Connection.execute()` for Core\n- `Session.execute()` for ORM\n\n### Forgetting Rollback After Flush Failure\n\nIf a flush fails, the underlying transaction is already rolled back, but the `Session` still must be explicitly rolled back before reuse:\n\n```python\ntry:\n    session.flush()\nexcept Exception:\n    session.rollback()\n    raise\n```\n\n### Unexpected SQL from Autoflush\n\n`Session.execute()`, lazy loads, refreshes, and commit boundaries can trigger flushes automatically. If you are constructing graphs of related objects and need a short protected window, use `session.no_autoflush`.\n\n### Object Expiration After Commit\n\n`Session.commit()` expires ORM objects by default. If your code needs to read recently committed attributes without issuing more SQL, set `expire_on_commit=False` on the `Session` or `sessionmaker`.\n\n### Treating `create_all()` as Migrations\n\n`Base.metadata.create_all()` is useful for bootstrapping or tests. It is not a schema migration system for production change management.\n\n### Async Lazy Loading\n\nAsync ORM code fails when attribute access tries to emit implicit IO. Solve this by:\n\n- eager loading with `selectinload(...)`\n- setting `lazy=\"raise\"` where appropriate\n- using `AsyncAttrs.awaitable_attrs` when you intentionally want awaitable attribute access\n\n## Version-Sensitive Notes for 2.0.48\n\n- The docs root `https://docs.sqlalchemy.org/en/20/` is the correct stable series for `2.0.48`.\n- PyPI shows `2.0.48` as the latest stable release on `2026-03-11`, released on `2026-03-02`.\n- PyPI also lists `2.1.0b1` as a prerelease. Do not mix 2.1 beta examples into a project pinned to `2.0.48`.\n- `create_engine(..., future=True)` is a legacy 1.4 transition flag. In 2.0 it stays at the default and should not be added to new examples.\n- Async `AsyncAttrs.awaitable_attrs` was added in `2.0.13`; it is available in `2.0.48`.\n- SQLAlchemy 2.0 removed legacy autocommit and connectionless patterns. Use explicit transactions with `Session.begin()` / `engine.begin()` and execute statements via `Session` or `Connection`.\n\n## Minimal Working Patterns\n\n### Fast ORM Bootstrap\n\n```python\nfrom sqlalchemy import String, create_engine, select\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column\n\nclass Base(DeclarativeBase):\n    pass\n\nclass Item(Base):\n    __tablename__ = \"item\"\n\n    id: Mapped[int] = mapped_column(primary_key=True)\n    name: Mapped[str] = mapped_column(String(100))\n\nengine = create_engine(\"sqlite:///items.db\")\nBase.metadata.create_all(engine)\n\nwith Session(engine) as session:\n    session.add(Item(name=\"example\"))\n    session.commit()\n\nwith Session(engine) as session:\n    items = session.scalars(select(Item)).all()\n    print(items)\n```\n\n### Fast Core Bootstrap\n\n```python\nfrom sqlalchemy import create_engine, text\n\nengine = create_engine(\"sqlite:///items.db\")\n\nwith engine.begin() as conn:\n    conn.execute(text(\"CREATE TABLE IF NOT EXISTS item (id integer primary key, name text)\"))\n    conn.execute(text(\"INSERT INTO item (name) VALUES (:name)\"), {\"name\": \"example\"})\n```\n\n## Official Sources\n\n- SQLAlchemy 2.0 docs: `https://docs.sqlalchemy.org/en/20/`\n- Overview and installation: `https://docs.sqlalchemy.org/en/20/intro.html`\n- Engine configuration and database URLs: `https://docs.sqlalchemy.org/en/20/core/engines.html`\n- ORM quick start: `https://docs.sqlalchemy.org/en/20/orm/quickstart.html`\n- AsyncIO extension: `https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html`\n- 2.0 migration guide: `https://docs.sqlalchemy.org/en/20/changelog/migration_20.html`\n- PyPI package page: `https://pypi.org/project/SQLAlchemy/`\n"
  },
  {
    "path": "content/sqlalchemy-utils/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SQLAlchemy-Utils package guide for Python projects using custom data types, listeners, generic relationships, aggregates, and database helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.42.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"sqlalchemy,sqlalchemy-utils,python,orm,database,types\"\n---\n\n# SQLAlchemy-Utils Python Package Guide\n\n## Golden Rule\n\nUse `sqlalchemy-utils` to extend normal SQLAlchemy models, not as a separate client layer. Import the helpers you need directly into your model module, and call `force_auto_coercion()` before defining models if you want supported custom types to coerce plain Python values automatically.\n\n## Install\n\nBase package:\n\n```bash\npython -m pip install \"sqlalchemy-utils==0.42.1\"\n```\n\nCommon optional extras published on PyPI:\n\n```bash\npython -m pip install \"sqlalchemy-utils[phone]==0.42.1\"\npython -m pip install \"sqlalchemy-utils[encrypted]==0.42.1\"\n```\n\nUse the `phone` extra if you need `PhoneNumberType`. Use the `encrypted` extra if you need encrypted column types. The package has no service-side authentication; the only runtime configuration you usually need is your SQLAlchemy database URL and, for encrypted columns, an application-managed encryption key.\n\n```bash\nexport DATABASE_URL=\"postgresql+psycopg://app:secret@localhost/appdb\"\nexport APP_ENCRYPTION_KEY=\"replace-this-with-a-real-secret\"\n```\n\n## Minimal Setup\n\nThis is the smallest practical setup for a SQLAlchemy app that uses `sqlalchemy-utils` types and coercion:\n\n```python\nimport os\nimport uuid\n\nimport sqlalchemy as sa\nfrom sqlalchemy.orm import declarative_base, sessionmaker\nfrom sqlalchemy_utils import EmailType, UUIDType, force_auto_coercion\n\nDATABASE_URL = os.environ[\"DATABASE_URL\"]\n\nengine = sa.create_engine(DATABASE_URL)\nSession = sessionmaker(bind=engine)\nBase = declarative_base()\n\n# Enable automatic coercion for supported SQLAlchemy-Utils scalar types.\nforce_auto_coercion()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n    id = sa.Column(UUIDType(binary=False), primary_key=True, default=uuid.uuid4)\n    email = sa.Column(EmailType, nullable=False, unique=True)\n\n\nBase.metadata.create_all(engine)\n\nwith Session() as session:\n    user = User(email=\"person@example.com\")\n    session.add(user)\n    session.commit()\n```\n\n`UUIDType` stores `uuid.UUID` values and can use native UUID support where the backend provides it. `EmailType` normalizes email values through SQLAlchemy-Utils instead of leaving them as plain strings.\n\n## Common Workflows\n\n### Use typed columns for UUIDs, phone numbers, and encrypted values\n\n```python\nimport os\nimport uuid\n\nimport sqlalchemy as sa\nfrom sqlalchemy.orm import declarative_base\nfrom sqlalchemy_utils import PhoneNumberType, StringEncryptedType, UUIDType, force_auto_coercion\nfrom sqlalchemy_utils.types.encrypted.encrypted_type import AesGcmEngine\n\nBase = declarative_base()\nforce_auto_coercion()\n\n\nclass Contact(Base):\n    __tablename__ = \"contact\"\n\n    id = sa.Column(UUIDType(binary=False), primary_key=True, default=uuid.uuid4)\n    phone = sa.Column(PhoneNumberType(region=\"US\"))\n    api_token = sa.Column(\n        StringEncryptedType(\n            sa.String(),\n            key=os.environ[\"APP_ENCRYPTION_KEY\"],\n            engine=AesGcmEngine,\n        ),\n        nullable=False,\n    )\n```\n\n`PhoneNumberType` stores `PhoneNumber` objects and accepts a default region. `StringEncryptedType` is the maintained encrypted type; upstream marks `EncryptedType` as deprecated since `0.36.6`.\n\n### Add created/updated timestamps automatically\n\n```python\nimport sqlalchemy as sa\nfrom sqlalchemy.orm import declarative_base\nfrom sqlalchemy_utils import Timestamp\n\nBase = declarative_base()\n\n\nclass Article(Base, Timestamp):\n    __tablename__ = \"article\"\n\n    id = sa.Column(sa.Integer, primary_key=True)\n    title = sa.Column(sa.Unicode(255), nullable=False)\n```\n\n`Timestamp` adds `created` and `updated` columns. The mixin updates `updated` automatically on flush when the row changes.\n\n### Use generic relationships when a row can point at different model types\n\n```python\nimport sqlalchemy as sa\nfrom sqlalchemy.orm import declarative_base\nfrom sqlalchemy_utils import generic_relationship\n\nBase = declarative_base()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n    id = sa.Column(sa.Integer, primary_key=True)\n\n\nclass Organization(Base):\n    __tablename__ = \"organization\"\n    id = sa.Column(sa.Integer, primary_key=True)\n\n\nclass Event(Base):\n    __tablename__ = \"event\"\n\n    id = sa.Column(sa.Integer, primary_key=True)\n    object_type = sa.Column(sa.Unicode(255))\n    object_id = sa.Column(sa.Integer, nullable=False)\n    object = generic_relationship(object_type, object_id)\n```\n\nAssign either model directly:\n\n```python\nevent.object = user\nevent.object = organization\n```\n\nFilter by the related object or by model type:\n\n```python\nsession.query(Event).filter_by(object=user).first()\nsession.query(Event).filter(Event.object.is_type(User)).all()\n```\n\n### Keep denormalized counters in sync with `aggregated`\n\nUse `aggregated()` when a parent row needs a value derived from related rows:\n\n```python\nimport sqlalchemy as sa\nfrom sqlalchemy.orm import declarative_base, relationship\nfrom sqlalchemy_utils import aggregated\n\nBase = declarative_base()\n\n\nclass Thread(Base):\n    __tablename__ = \"thread\"\n\n    id = sa.Column(sa.Integer, primary_key=True)\n    comment_count = sa.Column(sa.Integer, default=0)\n    comments = relationship(\"Comment\", back_populates=\"thread\")\n\n    @aggregated(\"comments\", sa.Column(sa.Integer))\n    def comment_count(self):\n        return sa.func.count(\"1\")\n\n\nclass Comment(Base):\n    __tablename__ = \"comment\"\n\n    id = sa.Column(sa.Integer, primary_key=True)\n    thread_id = sa.Column(sa.Integer, sa.ForeignKey(\"thread.id\"))\n    thread = relationship(\"Thread\", back_populates=\"comments\")\n```\n\nUpstream positions `aggregated()` as the efficient option for aggregate values over large collections, while `observes()` is more suitable for simple object-graph updates.\n\n### Create a database before building tables\n\n```python\nimport os\n\nimport sqlalchemy as sa\nfrom sqlalchemy_utils import create_database, database_exists\n\nurl = os.environ[\"DATABASE_URL\"]\n\nif not database_exists(url):\n    create_database(url)\n\nengine = sa.create_engine(url)\n```\n\nThe same helper module also provides `drop_database()` for teardown scripts.\n\n## Important Pitfalls\n\n- Call `force_auto_coercion()` before mapping models. If you forget it, custom types still work, but you lose automatic Python-value coercion for supported types.\n- `StringEncryptedType` needs a stable application key. Rotating the key without a migration plan makes existing encrypted values unreadable.\n- Upstream notes that the `AesGcmEngine` and `FernetEngine` backends are more secure, but encrypted values cannot be searched with SQL operators because the ciphertext changes every time.\n- If you encrypt `Date` or `DateTime` values, upstream requires `python-dateutil` so encrypted datetime values can be processed correctly.\n- `PhoneNumberType` depends on the optional `phonenumbers` package; install the `phone` extra or the import will fail.\n- Generic relationships trade away database-level foreign keys. Use them only when one association really can target multiple tables.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `0.42.1`, while the Read the Docs pages still identify themselves as `0.42.0` documentation. The core APIs in the maintainer docs and source still match the `0.42.1` package line.\n- PyPI metadata for `0.42.1` requires Python `>=3.9`.\n- Upstream deprecates `EncryptedType` in favor of `StringEncryptedType`; new code should use `StringEncryptedType`.\n\n## Official Sources\n\n- Maintainer docs root: https://sqlalchemy-utils.readthedocs.io/en/latest/\n- Data types: https://sqlalchemy-utils.readthedocs.io/en/latest/data_types.html\n- Listeners: https://sqlalchemy-utils.readthedocs.io/en/latest/listeners.html\n- Generic relationships: https://sqlalchemy-utils.readthedocs.io/en/latest/generic_relationship.html\n- Aggregates: https://sqlalchemy-utils.readthedocs.io/en/latest/aggregates.html\n- Database helpers: https://sqlalchemy-utils.readthedocs.io/en/latest/database_helpers.html\n- Models and mixins: https://sqlalchemy-utils.readthedocs.io/en/latest/models.html\n- Stable PDF index with API signatures: https://sqlalchemy-utils.readthedocs.io/_/downloads/en/stable/pdf/\n- PyPI package metadata and extras: https://pypi.org/project/sqlalchemy-utils/\n- Maintainer source repository: https://github.com/kvesteri/sqlalchemy-utils\n"
  },
  {
    "path": "content/sqlmodel/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SQLModel package guide for Python projects using the official SQLModel docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.0.37\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sqlmodel,python,sqlalchemy,pydantic,fastapi,orm,sqlite\"\n---\n\n# SQLModel Python Package Guide\n\n## Golden Rule\n\nUse `sqlmodel` when you want one typed model layer that works as both a Pydantic data model and a SQLAlchemy ORM mapping. For `0.0.37`, the important compatibility floor is Python `>=3.10`, and support for Pydantic v1 is already gone.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"sqlmodel==0.0.37\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sqlmodel==0.0.37\"\npoetry add \"sqlmodel==0.0.37\"\n```\n\nIf you are not using SQLite, you also need a SQLAlchemy-compatible database driver for your backend.\n\n## Initialize An Engine And Table Model\n\nThe official docs start with `Field`, `SQLModel`, `create_engine`, and `Session`. A minimal setup looks like this:\n\n```python\nimport os\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\nDATABASE_URL = os.getenv(\"DATABASE_URL\", \"sqlite:///database.db\")\n\nconnect_args = {\"check_same_thread\": False} if DATABASE_URL.startswith(\"sqlite\") else {}\nengine = create_engine(DATABASE_URL, echo=False, connect_args=connect_args)\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\ndef create_db_and_tables() -> None:\n    SQLModel.metadata.create_all(engine)\n```\n\nNotes:\n\n- `table=True` is what makes the model a mapped table instead of only a data model.\n- `Field(default=None, primary_key=True)` is the standard pattern for auto-generated integer primary keys.\n- `SQLModel.metadata.create_all(engine)` is fine for quickstarts and tests; it is not a replacement for migrations.\n\n## Core CRUD Pattern\n\nThe normal synchronous workflow is \"open session, add or query models, commit, refresh when needed\":\n\n```python\ndef create_hero() -> Hero:\n    hero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\", age=32)\n    with Session(engine) as session:\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        return hero\n\ndef read_hero_by_name(name: str) -> Hero | None:\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == name)\n        return session.exec(statement).first()\n\ndef list_heroes(offset: int = 0, limit: int = 100) -> list[Hero]:\n    with Session(engine) as session:\n        statement = select(Hero).offset(offset).limit(limit)\n        return list(session.exec(statement))\n```\n\nUseful patterns from the official tutorial:\n\n- Use `session.exec(select(...))` for queries instead of raw `session.execute(...)` in normal SQLModel code.\n- Use `session.get(Model, primary_key)` when loading one row by primary key.\n- Call `session.refresh(obj)` after `commit()` when you need generated fields like `id`.\n\n## FastAPI Integration\n\nSQLModel is designed to work directly with FastAPI. The official docs use separate models for request input, public output, and the table model:\n\n```python\nfrom fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\nsqlite_url = \"sqlite:///database.db\"\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\nclass HeroCreate(HeroBase):\n    pass\n\nclass HeroPublic(HeroBase):\n    id: int\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\napp = FastAPI()\n\n@app.on_event(\"startup\")\ndef on_startup() -> None:\n    SQLModel.metadata.create_all(engine)\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(*, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate):\n    db_hero = session.get(Hero, hero_id)\n    if not db_hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    db_hero.sqlmodel_update(hero_data)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    *, session: Session = Depends(get_session), offset: int = 0, limit: int = Query(default=100, le=100)\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n```\n\nAgent guidance:\n\n- Use `Hero.model_validate(hero_in)` to convert input models into table models.\n- Use `hero.model_dump(exclude_unset=True)` plus `db_obj.sqlmodel_update(...)` for PATCH-style updates.\n- Keep response models separate from table models when you need to hide internal columns.\n\n## Relationships\n\nRelationships use both a foreign-key column and `Relationship(...)` attributes:\n\n```python\nfrom sqlmodel import Field, Relationship, SQLModel\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n    team: Team | None = Relationship(back_populates=\"heroes\")\n```\n\nUse this pattern when you want ORM-style navigation like `hero.team` or `team.heroes`, not just raw foreign-key ids.\n\n## Configuration\n\nSQLModel itself does not have an auth layer or package-specific credential system. The main configuration surfaces are:\n\n- database URL\n- SQLAlchemy engine arguments\n- app-level model boundaries for create/update/read flows\n\nExample environment setup:\n\n```bash\nexport DATABASE_URL=\"sqlite:///./app.db\"\n```\n\nImportant engine notes:\n\n- The FastAPI tutorial uses `connect_args = {\"check_same_thread\": False}` for SQLite.\n- Only use that SQLite-specific argument when the URL is SQLite.\n- `echo=True` is useful while debugging SQL locally, but usually too noisy for production.\n\n## Common Pitfalls\n\n- Do not forget `table=True`. Without it, you created a data model, not a mapped table.\n- `SQLModel.metadata.create_all()` only creates missing tables. It does not generate or apply schema migrations.\n- If you expose table models directly from an API, you can leak fields you did not intend to return. Prefer dedicated public models.\n- Relationship attributes do not replace the foreign key column; you still need fields like `team_id` with `foreign_key=\"team.id\"`.\n- For SQLite in FastAPI examples, the docs use `check_same_thread=False`; copying that blindly to other databases is unnecessary.\n\n## Version-Sensitive Notes\n\n- The official SQLModel release notes include `0.0.37` as the current documented release in this line.\n- `0.0.37` itself is an internal release; the main user-visible compatibility shifts happened earlier in the same line.\n- `0.0.36` dropped support for `sqlmodel-slim`. Use `sqlmodel`.\n- `0.0.35` dropped Python 3.9, which matches the current PyPI requirement of Python `>=3.10`.\n- `0.0.31` dropped support for Pydantic v1. If your project still depends on Pydantic v1, do not upgrade to `0.0.37` without a broader migration plan.\n- `0.0.32` fixed support for `Annotated` fields with Pydantic 2.12+, so older blog posts about `Annotated` breakage may be stale.\n- The official docs examples use Python 3.10+ syntax such as `int | None` and `list[Hero]`.\n\n## Practical Production Note\n\nThe official quickstarts create tables at app startup. That is reasonable for tutorials, local scripts, and tests. For deployed systems, treat schema changes as a separate migration workflow. The SQLModel advanced guide explicitly says migration guidance is still growing, so production migration setup still requires SQLAlchemy ecosystem tooling and project-specific decisions.\n\n## Official Sources\n\n- Docs root: `https://sqlmodel.tiangolo.com/`\n- FastAPI session dependency tutorial: `https://sqlmodel.tiangolo.com/tutorial/fastapi/session-with-dependency/`\n- Relationships tutorial: `https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/`\n- Advanced guide: `https://sqlmodel.tiangolo.com/advanced/`\n- Release notes: `https://sqlmodel.tiangolo.com/release-notes/`\n- PyPI: `https://pypi.org/project/sqlmodel/`\n- Repository: `https://github.com/fastapi/sqlmodel`\n"
  },
  {
    "path": "content/sqlparse/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"sqlparse Python package guide for parsing, splitting, formatting, and inspecting SQL statements\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.5.5\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sqlparse,sql,parser,formatter,python,linting\"\n---\n\n# sqlparse Python Package Guide\n\n## Golden Rule\n\nUse `sqlparse` when you need lightweight SQL splitting, formatting, or token inspection inside Python. It is intentionally non-validating, so do not treat it as a full SQL parser, a query planner, or a safety check for untrusted SQL semantics.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"sqlparse==0.5.5\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sqlparse==0.5.5\"\npoetry add \"sqlparse==0.5.5\"\n```\n\nIf you only need the CLI formatter in CI or pre-commit, the same package install is enough; there is no separate formatter package.\n\n## Initialize And Setup\n\n`sqlparse` is a pure Python library. There is no network setup, database connection, or authentication step.\n\nTypical import:\n\n```python\nimport sqlparse\n```\n\nImportant behavior to remember before writing code around it:\n\n- `sqlparse` is non-validating. It tries to analyze SQL-like text without enforcing full dialect correctness.\n- The top-level API is small: `split()`, `format()`, and `parse()`.\n- `parse()` returns `Statement` objects backed by token trees, not AST nodes with semantic validation.\n\n## Core Usage\n\n### Split a script into individual statements\n\nUse `split()` when you want statement boundaries without writing your own semicolon logic:\n\n```python\nimport sqlparse\n\nraw_sql = \"\"\"\nBEGIN TRANSACTION;\nINSERT INTO users (id, email) VALUES (1, 'a@example.com');\nCOMMIT;\nSELECT * FROM users;\n\"\"\"\n\nstatements = sqlparse.split(raw_sql)\n\nfor statement in statements:\n    print(repr(statement))\n```\n\nIf your downstream consumer does not want trailing semicolons, use `strip_semicolon=True`:\n\n```python\nstatements = sqlparse.split(raw_sql, strip_semicolon=True)\n```\n\n### Format SQL for readability or normalization\n\n`format()` is the main entry point for SQL pretty-printing:\n\n```python\nimport sqlparse\n\nsql = \"select id,name from users where active=1 order by created_at desc\"\n\nformatted = sqlparse.format(\n    sql,\n    reindent=True,\n    keyword_case=\"upper\",\n    use_space_around_operators=True,\n)\n\nprint(formatted)\n```\n\nCommon formatting options from the official API docs:\n\n- `keyword_case=\"upper\" | \"lower\" | \"capitalize\"`\n- `identifier_case=\"upper\" | \"lower\" | \"capitalize\"`\n- `strip_comments=True`\n- `truncate_strings=<int>`\n- `truncate_char=\"[...]\"`\n- `reindent=True`\n- `reindent_aligned=True`\n- `use_space_around_operators=True`\n- `indent_tabs=True`\n- `indent_width=2`\n- `wrap_after=<column_count>`\n- `compact=True`\n- `output_format=\"python\" | \"php\"`\n- `comma_first=True`\n\nExample tuned for embedding SQL into Python source:\n\n```python\nimport sqlparse\n\nsql = \"select id, email from users where active = 1 order by created_at desc\"\n\npython_literal = sqlparse.format(\n    sql,\n    reindent=True,\n    keyword_case=\"upper\",\n    output_format=\"python\",\n)\n\nprint(python_literal)\n```\n\n### Parse SQL into statements and inspect tokens\n\nUse `parse()` when you need structural inspection rather than just formatting:\n\n```python\nimport sqlparse\n\nstatement = sqlparse.parse(\n    \"select u.id, u.email from users u where u.active = 1\"\n)[0]\n\nprint(statement.get_type())  # SELECT\n\nfor token in statement.tokens:\n    print(type(token).__name__, repr(str(token)))\n```\n\nThe official docs describe `Token` and `TokenList` as the base classes. Useful methods for agent-written code include:\n\n- `Statement.get_type()`\n- `TokenList.flatten()`\n- `TokenList.token_first()`\n- `TokenList.token_next()` / `token_prev()`\n- `TokenList.get_alias()`\n- `TokenList.get_name()`\n- `TokenList.get_real_name()`\n- `IdentifierList.get_identifiers()`\n- `Token.match(...)`\n- `Token.within(...)`\n\nExample: walk identifiers from a simple `SELECT` list.\n\n```python\nimport sqlparse\nfrom sqlparse.sql import IdentifierList, Identifier\n\nstatement = sqlparse.parse(\n    \"select u.id, u.email, count(*) as total from users u\"\n)[0]\n\nfor token in statement.tokens:\n    if isinstance(token, IdentifierList):\n        for identifier in token.get_identifiers():\n            print(identifier.get_name(), identifier.get_real_name())\n    elif isinstance(token, Identifier):\n        print(token.get_name(), token.get_real_name())\n```\n\n### Convert parsed fragments back to strings\n\nParsed objects preserve the original token values, so `str(...)` is the normal way to reconstruct fragments:\n\n```python\nimport sqlparse\n\nstatement = sqlparse.parse(\n    'select * from \"public\".\"users\" where id = 1'\n)[0]\n\nwhere_clause = statement.tokens[-1]\n\nprint(str(statement))\nprint(str(where_clause))\n```\n\n## CLI And Pre-commit Usage\n\nThe package ships the `sqlformat` CLI:\n\n```bash\nsqlformat --help\n```\n\nFormat one or more SQL files in place:\n\n```bash\nsqlformat --in-place --reindent --keywords upper queries/report.sql\n```\n\nThe docs also describe a `pre-commit` hook:\n\n```yaml\nrepos:\n  - repo: https://github.com/andialbrecht/sqlparse\n    rev: 0.5.5\n    hooks:\n      - id: sqlformat\n        args: [--in-place, --reindent, --keywords, upper]\n```\n\nIf you override hook args, keep `--in-place` first or the hook will not rewrite files.\n\n## Dialect Customization\n\n`sqlparse` supports many SQL dialects loosely, but the lexer can be customized when a project uses dialect-specific keywords or operators.\n\nThe official extension docs describe configuring the singleton lexer by clearing the defaults, loading the default regex/keyword tables, and then appending custom keywords or regex rules. Use this only when formatting or parsing fails because your dialect uses syntax `sqlparse` does not know yet.\n\nThis is an advanced escape hatch. Prefer upstream defaults unless you have a narrow, repeatable dialect need.\n\n## Configuration And Safety Notes\n\n- There is no auth configuration. Any \"setup\" beyond installation is local process behavior only.\n- `encoding` is optional on `split()`, `format()`, and `parse()`. If omitted, the docs say `sqlparse` assumes the input is UTF-8 or Latin-1.\n- For large or untrusted SQL inputs, `sqlparse` now includes grouping limits intended to reduce DoS risk:\n  - `sqlparse.engine.grouping.MAX_GROUPING_DEPTH = 100`\n  - `sqlparse.engine.grouping.MAX_GROUPING_TOKENS = 10000`\n- You can raise or disable those limits, but the docs explicitly warn that doing so can reintroduce denial-of-service risk for untrusted input.\n\nExample of controlled limit tuning:\n\n```python\nimport sqlparse.engine.grouping\n\nsqlparse.engine.grouping.MAX_GROUPING_DEPTH = 200\nsqlparse.engine.grouping.MAX_GROUPING_TOKENS = 50000\n```\n\nOnly do that for trusted inputs that are legitimately large.\n\n## Common Pitfalls\n\n- Do not assume `sqlparse` validates SQL. Invalid or dialect-specific SQL can still tokenize into something that looks usable.\n- `parse()` returns a tuple of `Statement` instances, not a single object.\n- Token lists include whitespace and comments unless you explicitly skip them with helpers like `token_first(skip_ws=True, skip_cm=True)`.\n- `strip_comments=True` does not mean \"also normalize whitespace\". Since `0.5.1`, some cases that previously looked cleaned up may still need `strip_whitespace=True`.\n- If you override `pre-commit` hook args, include `--in-place` or the hook will not modify files.\n- The docs examples still show `rev: 0.5.4` in the pre-commit snippet. For a project pinned to `0.5.5`, use `rev: 0.5.5`.\n- `split()` is much safer than manual `sql.split(\";\")`, especially around `BEGIN ... END` style blocks.\n- If you inspect identifiers, remember that aliases and real object names differ. Use `get_name()` and `get_real_name()` intentionally.\n\n## Version-Sensitive Notes For 0.5.x\n\n- `0.5.5` fixes DoS protection so grouping-limit failures raise `SQLParseError` instead of silently returning `None`, and it fixes splitting of `BEGIN TRANSACTION` statements.\n- `0.5.4` added Python 3.14 support, top-level type annotations with a `py.typed` marker, pre-commit hook support, CLI multi-file handling, and the `--in-place` formatter flag.\n- `0.5.4` also introduced documented grouping limits for token processing to harden parsing of very large inputs.\n- `0.5.3` broadened protection against recursion-related DoS for deeply nested statements.\n- `0.5.1` added the `compact=True` formatter option and changed some `strip_comments` behavior, so older formatting snippets can differ from current output.\n- `0.5.0` dropped Python 3.5, 3.6, and 3.7 support. For `0.5.5`, PyPI declares `Requires-Python >=3.8`.\n\n## Practical Guidance For Agents\n\n- Use `split()` for statement boundaries, `format()` for normalization, and `parse()` only when you actually need token-level inspection.\n- Prefer matching on token classes and helper methods instead of raw string slicing.\n- If you need exact SQL semantics, query planning, or dialect validation, pair `sqlparse` with a database engine or a stricter parser rather than stretching it beyond its design.\n"
  },
  {
    "path": "content/square/docs/payments/javascript/DOC.md",
    "content": "---\nname: payments\ndescription: \"Square SDK coding guide for payments, POS, and commerce checkout\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"43.2.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"square,payments,pos,commerce,checkout\"\n---\n\n# Square SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Square SDK package:**\n- Package name: `square` (Node.js/TypeScript library for Square API)\n- Official repository: https://github.com/square/square-nodejs-sdk\n\n**Never use deprecated libraries:**\n- `square-connect` (DEPRECATED - replaced by `square`)\n- `connect-nodejs-sdk` (DEPRECATED - replaced by `square`)\n\n**Current SDK Version:** v43.2.0\n\n**API Versioning:** Square uses date-based API versioning (e.g., 2025-08-20). Your account is automatically pinned to an API version. You can override this when initializing the client or in the Square Dashboard.\n\n## 2. Installation\n\n```bash\nnpm install square\n```\n\n```bash\nyarn add square\n```\n\n```bash\npnpm add square\n```\n\n**Requirements:** Node.js 16+ (Node.js 18+ recommended for production)\n\n### Environment Variables\n\n```bash\n# Required\nSQUARE_ACCESS_TOKEN=EAAAl...  # Your Square access token\nSQUARE_ENVIRONMENT=sandbox    # or \"production\"\n\n# Optional\nSQUARE_LOCATION_ID=L88917...  # Default location ID for operations\n```\n\n**CRITICAL:** Never commit access tokens to version control. Use environment variables or secure secret management systems. Use sandbox tokens for development and testing.\n\n## 3. Initialization\n\n### Basic Initialization\n\n```javascript\nconst { SquareClient, SquareEnvironment } = require(\"square\");\n\nconst client = new SquareClient({\n  token: process.env.SQUARE_ACCESS_TOKEN,\n  environment: SquareEnvironment.Sandbox,\n});\n```\n\n### TypeScript Initialization\n\n```typescript\nimport { SquareClient, SquareEnvironment, SquareError } from \"square\";\n\nconst client = new SquareClient({\n  token: process.env.SQUARE_ACCESS_TOKEN!,\n  environment: SquareEnvironment.Production,\n});\n```\n\n### Advanced Configuration\n\n```javascript\nconst { SquareClient, SquareEnvironment } = require(\"square\");\n\nconst client = new SquareClient({\n  token: process.env.SQUARE_ACCESS_TOKEN,\n  environment: SquareEnvironment.Production,\n  timeout: 60000,              // 60 second timeout\n  squareVersion: \"2025-08-20\", // Override API version\n  additionalHeaders: {\n    \"User-Agent\": \"MyApp/1.0.0\",\n  },\n});\n```\n\n### ES Module Import\n\n```javascript\nimport { SquareClient, SquareEnvironment } from \"square\";\n\nconst client = new SquareClient({\n  token: process.env.SQUARE_ACCESS_TOKEN,\n  environment: SquareEnvironment.Sandbox,\n});\n```\n\n### Error Handling Setup\n\n```javascript\nconst { SquareClient, SquareError } = require(\"square\");\n\nasync function makeSquareRequest() {\n  try {\n    // Make API calls here\n  } catch (error) {\n    if (error instanceof SquareError) {\n      // Handle Square-specific errors\n      error.errors.forEach(e => {\n        console.log(`Category: ${e.category}`);\n        console.log(`Code: ${e.code}`);\n        console.log(`Detail: ${e.detail}`);\n      });\n    } else {\n      console.log(\"Unexpected error:\", error);\n    }\n  }\n}\n```\n\n## 4. Core API Surfaces\n\n### Locations API\n\nGet information about business locations.\n\n**List All Locations:**\n\n```javascript\nasync function listLocations() {\n  try {\n    const response = await client.locations.list();\n    const locations = response.locations;\n\n    locations.forEach(location => {\n      console.log(`${location.id}: ${location.name}`);\n      console.log(`Address: ${location.address.addressLine1}`);\n      console.log(`City: ${location.address.locality}`);\n    });\n\n    return locations;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing locations:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Single Location:**\n\n```javascript\nasync function getLocation(locationId) {\n  try {\n    const response = await client.locations.retrieve(locationId);\n    return response.location;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving location:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Payments API\n\nProcess and manage payments.\n\n**Create Payment (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createPayment(sourceId, amountMoney, locationId) {\n  try {\n    const response = await client.payments.create({\n      sourceId: sourceId,\n      idempotencyKey: randomUUID(),\n      amountMoney: {\n        amount: BigInt(amountMoney),\n        currency: \"USD\",\n      },\n      locationId: locationId,\n    });\n\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Payment error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Payment (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedPayment(paymentData) {\n  try {\n    const response = await client.payments.create({\n      sourceId: paymentData.sourceId,\n      idempotencyKey: randomUUID(),\n      amountMoney: {\n        amount: BigInt(paymentData.amount),\n        currency: paymentData.currency || \"USD\",\n      },\n      locationId: paymentData.locationId,\n      customerId: paymentData.customerId,\n      referenceId: paymentData.referenceId,\n      note: paymentData.note,\n      autocomplete: true,\n      buyerEmailAddress: paymentData.email,\n      billingAddress: {\n        addressLine1: paymentData.addressLine1,\n        locality: paymentData.city,\n        administrativeDistrictLevel1: paymentData.state,\n        postalCode: paymentData.postalCode,\n        country: paymentData.country || \"US\",\n      },\n    });\n\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Payment creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Payments:**\n\n```javascript\nasync function listPayments(locationId, beginTime, endTime) {\n  try {\n    const response = await client.payments.list({\n      locationId: locationId,\n      beginTime: beginTime,\n      endTime: endTime,\n      sortOrder: \"DESC\",\n      limit: 100,\n    });\n\n    return response.payments;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing payments:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Get Payment:**\n\n```javascript\nasync function getPayment(paymentId) {\n  try {\n    const response = await client.payments.retrieve(paymentId);\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving payment:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Complete Payment (for delayed capture):**\n\n```javascript\nasync function completePayment(paymentId) {\n  try {\n    const response = await client.payments.complete(paymentId);\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error completing payment:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Cancel Payment:**\n\n```javascript\nasync function cancelPayment(paymentId) {\n  try {\n    const response = await client.payments.cancel(paymentId);\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error canceling payment:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Refunds API\n\nManage payment refunds.\n\n**Create Refund (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createRefund(paymentId, amountMoney, currency) {\n  try {\n    const response = await client.refunds.create({\n      idempotencyKey: randomUUID(),\n      paymentId: paymentId,\n      amountMoney: {\n        amount: BigInt(amountMoney),\n        currency: currency || \"USD\",\n      },\n    });\n\n    return response.refund;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Refund error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Refund (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedRefund(refundData) {\n  try {\n    const response = await client.refunds.create({\n      idempotencyKey: randomUUID(),\n      paymentId: refundData.paymentId,\n      amountMoney: {\n        amount: BigInt(refundData.amount),\n        currency: refundData.currency || \"USD\",\n      },\n      reason: refundData.reason,\n      locationId: refundData.locationId,\n    });\n\n    return response.refund;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Refund creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Get Refund:**\n\n```javascript\nasync function getRefund(refundId) {\n  try {\n    const response = await client.refunds.retrieve(refundId);\n    return response.refund;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving refund:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Refunds:**\n\n```javascript\nasync function listRefunds(locationId, beginTime, endTime) {\n  try {\n    const response = await client.refunds.list({\n      locationId: locationId,\n      beginTime: beginTime,\n      endTime: endTime,\n      sortOrder: \"DESC\",\n    });\n\n    return response.refunds;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing refunds:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Orders API\n\nCreate and manage orders.\n\n**Create Order (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createOrder(locationId) {\n  try {\n    const response = await client.orders.create({\n      idempotencyKey: randomUUID(),\n      order: {\n        locationId: locationId,\n        lineItems: [\n          {\n            name: \"Item Name\",\n            quantity: \"1\",\n            basePriceMoney: {\n              amount: BigInt(1000),\n              currency: \"USD\",\n            },\n          },\n        ],\n      },\n    });\n\n    return response.order;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Order creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Order (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedOrder(orderData) {\n  try {\n    const response = await client.orders.create({\n      idempotencyKey: randomUUID(),\n      order: {\n        locationId: orderData.locationId,\n        referenceId: orderData.referenceId,\n        customerId: orderData.customerId,\n        lineItems: orderData.lineItems.map(item => ({\n          name: item.name,\n          quantity: item.quantity.toString(),\n          basePriceMoney: {\n            amount: BigInt(item.price),\n            currency: item.currency || \"USD\",\n          },\n          note: item.note,\n        })),\n        taxes: [\n          {\n            name: \"Sales Tax\",\n            percentage: \"8.5\",\n            scope: \"ORDER\",\n          },\n        ],\n        discounts: orderData.discounts?.map(discount => ({\n          name: discount.name,\n          percentage: discount.percentage,\n          scope: \"ORDER\",\n        })) || [],\n      },\n    });\n\n    return response.order;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Order creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Order:**\n\n```javascript\nasync function retrieveOrder(orderId) {\n  try {\n    const response = await client.orders.retrieve(orderId);\n    return response.order;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving order:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Update Order:**\n\n```javascript\nasync function updateOrder(orderId, updates) {\n  try {\n    const response = await client.orders.update(orderId, {\n      order: updates,\n    });\n\n    return response.order;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error updating order:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Search Orders:**\n\n```javascript\nasync function searchOrders(locationIds, query) {\n  try {\n    const response = await client.orders.search({\n      locationIds: locationIds,\n      query: {\n        filter: {\n          stateFilter: {\n            states: [\"OPEN\", \"COMPLETED\"],\n          },\n          dateTimeFilter: query.dateTimeFilter,\n          customerFilter: query.customerId ? {\n            customerIds: [query.customerId],\n          } : undefined,\n        },\n        sort: {\n          sortField: \"CREATED_AT\",\n          sortOrder: \"DESC\",\n        },\n      },\n      limit: query.limit || 100,\n    });\n\n    return response.orders;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error searching orders:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Customers API\n\nManage customer profiles.\n\n**Create Customer (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createCustomer(emailAddress, givenName, familyName) {\n  try {\n    const response = await client.customers.create({\n      idempotencyKey: randomUUID(),\n      emailAddress: emailAddress,\n      givenName: givenName,\n      familyName: familyName,\n    });\n\n    return response.customer;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Customer creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Customer (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedCustomer(customerData) {\n  try {\n    const response = await client.customers.create({\n      idempotencyKey: randomUUID(),\n      givenName: customerData.givenName,\n      familyName: customerData.familyName,\n      emailAddress: customerData.emailAddress,\n      phoneNumber: customerData.phoneNumber,\n      address: {\n        addressLine1: customerData.addressLine1,\n        addressLine2: customerData.addressLine2,\n        locality: customerData.city,\n        administrativeDistrictLevel1: customerData.state,\n        postalCode: customerData.postalCode,\n        country: customerData.country || \"US\",\n      },\n      referenceId: customerData.referenceId,\n      note: customerData.note,\n      birthday: customerData.birthday,\n      companyName: customerData.companyName,\n    });\n\n    return response.customer;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Customer creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Customers:**\n\n```javascript\nasync function listCustomers(cursor = null, limit = 100) {\n  try {\n    const response = await client.customers.list({\n      cursor: cursor,\n      limit: limit,\n      sortField: \"CREATED_AT\",\n      sortOrder: \"DESC\",\n    });\n\n    return {\n      customers: response.customers,\n      cursor: response.cursor,\n    };\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing customers:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Customer:**\n\n```javascript\nasync function retrieveCustomer(customerId) {\n  try {\n    const response = await client.customers.retrieve(customerId);\n    return response.customer;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving customer:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Update Customer:**\n\n```javascript\nasync function updateCustomer(customerId, updates) {\n  try {\n    const response = await client.customers.update(customerId, updates);\n    return response.customer;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error updating customer:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Delete Customer:**\n\n```javascript\nasync function deleteCustomer(customerId) {\n  try {\n    const response = await client.customers.delete(customerId);\n    return response;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error deleting customer:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Search Customers:**\n\n```javascript\nasync function searchCustomers(query) {\n  try {\n    const response = await client.customers.search({\n      query: {\n        filter: {\n          emailAddress: query.email ? {\n            exact: query.email,\n          } : undefined,\n          phoneNumber: query.phone ? {\n            exact: query.phone,\n          } : undefined,\n          createdAt: query.createdAt,\n        },\n      },\n      limit: query.limit || 100,\n    });\n\n    return response.customers;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error searching customers:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Catalog API\n\nManage items, categories, taxes, and modifiers.\n\n**Create Catalog Item (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createCatalogItem(name, price) {\n  try {\n    const response = await client.catalog.upsertCatalogObject({\n      idempotencyKey: randomUUID(),\n      object: {\n        type: \"ITEM\",\n        id: `#${name.replace(/\\s/g, '_')}`,\n        itemData: {\n          name: name,\n          variations: [\n            {\n              type: \"ITEM_VARIATION\",\n              id: `#${name.replace(/\\s/g, '_')}_variation`,\n              itemVariationData: {\n                name: \"Regular\",\n                pricingType: \"FIXED_PRICING\",\n                priceMoney: {\n                  amount: BigInt(price),\n                  currency: \"USD\",\n                },\n              },\n            },\n          ],\n        },\n      },\n    });\n\n    return response.catalogObject;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Catalog item creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Catalog Item (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedCatalogItem(itemData) {\n  try {\n    const response = await client.catalog.upsertCatalogObject({\n      idempotencyKey: randomUUID(),\n      object: {\n        type: \"ITEM\",\n        id: `#${itemData.name.replace(/\\s/g, '_')}`,\n        itemData: {\n          name: itemData.name,\n          description: itemData.description,\n          categoryId: itemData.categoryId,\n          taxIds: itemData.taxIds,\n          variations: itemData.variations.map((variation, index) => ({\n            type: \"ITEM_VARIATION\",\n            id: `#${itemData.name.replace(/\\s/g, '_')}_var_${index}`,\n            itemVariationData: {\n              name: variation.name,\n              sku: variation.sku,\n              pricingType: \"FIXED_PRICING\",\n              priceMoney: {\n                amount: BigInt(variation.price),\n                currency: variation.currency || \"USD\",\n              },\n              trackInventory: variation.trackInventory || false,\n            },\n          })),\n        },\n      },\n    });\n\n    return response.catalogObject;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Catalog item creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Catalog:**\n\n```javascript\nasync function listCatalog(types = [\"ITEM\"], cursor = null) {\n  try {\n    const response = await client.catalog.list({\n      cursor: cursor,\n      types: types,\n    });\n\n    return {\n      objects: response.objects,\n      cursor: response.cursor,\n    };\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing catalog:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Catalog Object:**\n\n```javascript\nasync function retrieveCatalogObject(objectId) {\n  try {\n    const response = await client.catalog.retrieve(objectId, {\n      includeRelatedObjects: true,\n    });\n\n    return response.object;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving catalog object:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Search Catalog Items:**\n\n```javascript\nasync function searchCatalogItems(query) {\n  try {\n    const response = await client.catalog.searchCatalogItems({\n      textFilter: query.text,\n      categoryIds: query.categoryIds,\n      stockLevels: query.stockLevels,\n      enabledLocationIds: query.locationIds,\n      limit: query.limit || 100,\n    });\n\n    return response.items;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error searching catalog:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Delete Catalog Object:**\n\n```javascript\nasync function deleteCatalogObject(objectId) {\n  try {\n    const response = await client.catalog.deleteCatalogObject(objectId);\n    return response;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error deleting catalog object:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Batch Upsert Catalog Objects:**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function batchUpsertCatalogObjects(objects) {\n  try {\n    const response = await client.catalog.batchUpsertCatalogObjects({\n      idempotencyKey: randomUUID(),\n      batches: [\n        {\n          objects: objects,\n        },\n      ],\n    });\n\n    return response.objects;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Batch upsert error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Inventory API\n\nTrack and manage inventory.\n\n**Retrieve Inventory Count:**\n\n```javascript\nasync function retrieveInventoryCount(catalogObjectId, locationIds) {\n  try {\n    const response = await client.inventory.retrieveInventoryCount(\n      catalogObjectId,\n      {\n        locationIds: locationIds.join(','),\n      }\n    );\n\n    return response.counts;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving inventory:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Batch Retrieve Inventory Counts:**\n\n```javascript\nasync function batchRetrieveInventoryCounts(catalogObjectIds, locationIds) {\n  try {\n    const response = await client.inventory.batchRetrieveInventoryCounts({\n      catalogObjectIds: catalogObjectIds,\n      locationIds: locationIds,\n    });\n\n    return response.counts;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving inventory counts:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Adjust Inventory:**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function adjustInventory(catalogObjectId, locationId, adjustment) {\n  try {\n    const response = await client.inventory.batchChangeInventory({\n      idempotencyKey: randomUUID(),\n      changes: [\n        {\n          type: \"ADJUSTMENT\",\n          adjustment: {\n            catalogObjectId: catalogObjectId,\n            locationId: locationId,\n            quantity: adjustment.quantity.toString(),\n            fromState: \"IN_STOCK\",\n            toState: \"IN_STOCK\",\n            occurredAt: new Date().toISOString(),\n          },\n        },\n      ],\n    });\n\n    return response.counts;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error adjusting inventory:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Invoices API\n\nCreate and manage invoices.\n\n**Create Invoice (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createInvoice(locationId, customerId, orderId) {\n  try {\n    const response = await client.invoices.create({\n      invoice: {\n        locationId: locationId,\n        orderId: orderId,\n        primaryRecipient: {\n          customerId: customerId,\n        },\n        paymentRequests: [\n          {\n            requestType: \"BALANCE\",\n            dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)\n              .toISOString()\n              .split('T')[0],\n          },\n        ],\n      },\n      idempotencyKey: randomUUID(),\n    });\n\n    return response.invoice;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Invoice creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Invoice (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedInvoice(invoiceData) {\n  try {\n    const response = await client.invoices.create({\n      invoice: {\n        locationId: invoiceData.locationId,\n        orderId: invoiceData.orderId,\n        primaryRecipient: {\n          customerId: invoiceData.customerId,\n          givenName: invoiceData.givenName,\n          familyName: invoiceData.familyName,\n          emailAddress: invoiceData.emailAddress,\n        },\n        paymentRequests: [\n          {\n            requestType: \"BALANCE\",\n            dueDate: invoiceData.dueDate,\n            fixedAmountRequestedMoney: invoiceData.fixedAmount ? {\n              amount: BigInt(invoiceData.fixedAmount),\n              currency: invoiceData.currency || \"USD\",\n            } : undefined,\n            reminders: [\n              {\n                relativeScheduledDays: -1,\n                message: \"Payment reminder\",\n              },\n            ],\n          },\n        ],\n        deliveryMethod: \"EMAIL\",\n        invoiceNumber: invoiceData.invoiceNumber,\n        title: invoiceData.title,\n        description: invoiceData.description,\n      },\n      idempotencyKey: randomUUID(),\n    });\n\n    return response.invoice;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Invoice creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Publish Invoice:**\n\n```javascript\nasync function publishInvoice(invoiceId) {\n  try {\n    const response = await client.invoices.publish(invoiceId, {\n      version: 0,\n    });\n\n    return response.invoice;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error publishing invoice:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Get Invoice:**\n\n```javascript\nasync function getInvoice(invoiceId) {\n  try {\n    const response = await client.invoices.retrieve(invoiceId);\n    return response.invoice;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving invoice:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Search Invoices:**\n\n```javascript\nasync function searchInvoices(locationIds, query) {\n  try {\n    const response = await client.invoices.search({\n      query: {\n        locationIds: locationIds,\n        filter: {\n          customerIds: query.customerIds,\n          stateFilter: query.states,\n        },\n        sort: {\n          field: \"INVOICE_SORT_DATE\",\n          order: \"DESC\",\n        },\n      },\n      limit: query.limit || 100,\n    });\n\n    return response.invoices;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error searching invoices:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Subscriptions API\n\nManage recurring payments and subscriptions.\n\n**Create Subscription (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createSubscription(locationId, customerId, planId) {\n  try {\n    const response = await client.subscriptions.create({\n      idempotencyKey: randomUUID(),\n      locationId: locationId,\n      planId: planId,\n      customerId: customerId,\n    });\n\n    return response.subscription;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Subscription creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Subscription (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedSubscription(subscriptionData) {\n  try {\n    const response = await client.subscriptions.create({\n      idempotencyKey: randomUUID(),\n      locationId: subscriptionData.locationId,\n      planId: subscriptionData.planId,\n      customerId: subscriptionData.customerId,\n      startDate: subscriptionData.startDate,\n      taxPercentage: subscriptionData.taxPercentage,\n      priceOverrideMoney: subscriptionData.priceOverride ? {\n        amount: BigInt(subscriptionData.priceOverride),\n        currency: subscriptionData.currency || \"USD\",\n      } : undefined,\n      cardId: subscriptionData.cardId,\n    });\n\n    return response.subscription;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Subscription creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Subscription:**\n\n```javascript\nasync function retrieveSubscription(subscriptionId) {\n  try {\n    const response = await client.subscriptions.retrieve(subscriptionId, {\n      include: \"actions\",\n    });\n\n    return response.subscription;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving subscription:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Cancel Subscription:**\n\n```javascript\nasync function cancelSubscription(subscriptionId) {\n  try {\n    const response = await client.subscriptions.cancel(subscriptionId);\n    return response.subscription;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error canceling subscription:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Search Subscriptions:**\n\n```javascript\nasync function searchSubscriptions(query) {\n  try {\n    const response = await client.subscriptions.search({\n      query: {\n        filter: {\n          customerIds: query.customerIds,\n          locationIds: query.locationIds,\n        },\n      },\n      limit: query.limit || 100,\n    });\n\n    return response.subscriptions;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error searching subscriptions:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Checkout API\n\nCreate hosted checkout pages.\n\n**Create Checkout (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createCheckout(locationId, orderId) {\n  try {\n    const response = await client.checkout.create(locationId, {\n      idempotencyKey: randomUUID(),\n      order: {\n        orderId: orderId,\n      },\n    });\n\n    return response.checkout.checkoutPageUrl;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Checkout creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Checkout (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedCheckout(locationId, checkoutData) {\n  try {\n    const response = await client.checkout.create(locationId, {\n      idempotencyKey: randomUUID(),\n      order: {\n        orderId: checkoutData.orderId,\n        locationId: locationId,\n      },\n      askForShippingAddress: checkoutData.askForShippingAddress || false,\n      merchantSupportEmail: checkoutData.merchantEmail,\n      prePopulateBuyerEmail: checkoutData.buyerEmail,\n      redirectUrl: checkoutData.redirectUrl,\n      additionalRecipients: checkoutData.additionalRecipients,\n    });\n\n    return response.checkout;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Checkout creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Bookings API\n\nManage appointments and bookings.\n\n**Create Booking (Minimal):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createBooking(locationId, customerId, startAt, serviceVariationId, teamMemberId) {\n  try {\n    const response = await client.bookings.create({\n      idempotencyKey: randomUUID(),\n      booking: {\n        locationId: locationId,\n        customerId: customerId,\n        startAt: startAt,\n        appointmentSegments: [\n          {\n            durationMinutes: 60,\n            serviceVariationId: serviceVariationId,\n            teamMemberId: teamMemberId,\n          },\n        ],\n      },\n    });\n\n    return response.booking;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Booking creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Create Booking (Advanced):**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createAdvancedBooking(bookingData) {\n  try {\n    const response = await client.bookings.create({\n      idempotencyKey: randomUUID(),\n      booking: {\n        locationId: bookingData.locationId,\n        customerId: bookingData.customerId,\n        customerNote: bookingData.customerNote,\n        sellerNote: bookingData.sellerNote,\n        startAt: bookingData.startAt,\n        appointmentSegments: bookingData.appointmentSegments.map(segment => ({\n          durationMinutes: segment.durationMinutes,\n          serviceVariationId: segment.serviceVariationId,\n          teamMemberId: segment.teamMemberId,\n        })),\n      },\n    });\n\n    return response.booking;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Booking creation failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Bookings:**\n\n```javascript\nasync function listBookings(locationId, startAtMin, startAtMax) {\n  try {\n    const response = await client.bookings.list({\n      locationId: locationId,\n      startAtMin: startAtMin,\n      startAtMax: startAtMax,\n      limit: 100,\n    });\n\n    return response.bookings;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing bookings:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Retrieve Booking:**\n\n```javascript\nasync function retrieveBooking(bookingId) {\n  try {\n    const response = await client.bookings.retrieve(bookingId);\n    return response.booking;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving booking:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Cancel Booking:**\n\n```javascript\nasync function cancelBooking(bookingId) {\n  try {\n    const response = await client.bookings.cancel(bookingId, {\n      idempotencyKey: randomUUID(),\n    });\n\n    return response.booking;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error canceling booking:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Terminal API\n\nCreate checkouts for Square Terminal devices.\n\n**Create Terminal Checkout:**\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function createTerminalCheckout(deviceId, amountMoney, locationId) {\n  try {\n    const response = await client.terminal.createTerminalCheckout({\n      idempotencyKey: randomUUID(),\n      checkout: {\n        amountMoney: {\n          amount: BigInt(amountMoney),\n          currency: \"USD\",\n        },\n        deviceOptions: {\n          deviceId: deviceId,\n        },\n      },\n    });\n\n    return response.checkout;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Terminal checkout error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Get Terminal Checkout:**\n\n```javascript\nasync function getTerminalCheckout(checkoutId) {\n  try {\n    const response = await client.terminal.getTerminalCheckout(checkoutId);\n    return response.checkout;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error retrieving terminal checkout:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Cancel Terminal Checkout:**\n\n```javascript\nasync function cancelTerminalCheckout(checkoutId) {\n  try {\n    const response = await client.terminal.cancelTerminalCheckout(checkoutId);\n    return response.checkout;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error canceling terminal checkout:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Webhooks\n\nHandle webhook notifications from Square.\n\n**Create Webhook Subscription:**\n\n```javascript\nasync function createWebhookSubscription(notificationUrl, eventTypes) {\n  try {\n    const response = await client.webhookSubscriptions.create({\n      subscription: {\n        name: \"My Webhook\",\n        notificationUrl: notificationUrl,\n        eventTypes: eventTypes,\n      },\n    });\n\n    return response.subscription;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Webhook creation error:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**List Webhook Subscriptions:**\n\n```javascript\nasync function listWebhookSubscriptions() {\n  try {\n    const response = await client.webhookSubscriptions.list();\n    return response.subscriptions;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Error listing webhooks:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n**Verify Webhook Signature:**\n\n```javascript\nconst crypto = require('crypto');\n\nfunction verifyWebhookSignature(body, signature, signatureKey, notificationUrl) {\n  const hmac = crypto.createHmac('sha256', signatureKey);\n  hmac.update(notificationUrl + body);\n  const hash = hmac.digest('base64');\n\n  return hash === signature;\n}\n```\n\n**Handle Webhook (Express):**\n\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.post('/webhooks/square', express.raw({ type: 'application/json' }), (req, res) => {\n  const signature = req.headers['x-square-hmacsha256-signature'];\n  const body = req.body.toString('utf8');\n\n  const isValid = verifyWebhookSignature(\n    body,\n    signature,\n    process.env.SQUARE_WEBHOOK_SECRET,\n    'https://yourdomain.com/webhooks/square'\n  );\n\n  if (!isValid) {\n    return res.status(400).send('Invalid signature');\n  }\n\n  const event = JSON.parse(body);\n\n  switch (event.type) {\n    case 'payment.created':\n      console.log('Payment created:', event.data.object.payment);\n      break;\n    case 'order.created':\n      console.log('Order created:', event.data.object.order);\n      break;\n    case 'customer.created':\n      console.log('Customer created:', event.data.object.customer);\n      break;\n    default:\n      console.log('Unhandled event type:', event.type);\n  }\n\n  res.status(200).send('OK');\n});\n```\n\n### Common Webhook Events\n\n```javascript\n// Payment events\n\"payment.created\"\n\"payment.updated\"\n\n// Order events\n\"order.created\"\n\"order.updated\"\n\"order.fulfillment.updated\"\n\n// Customer events\n\"customer.created\"\n\"customer.updated\"\n\"customer.deleted\"\n\n// Invoice events\n\"invoice.created\"\n\"invoice.published\"\n\"invoice.payment_made\"\n\n// Subscription events\n\"subscription.created\"\n\"subscription.started\"\n\"subscription.canceled\"\n\n// Booking events\n\"booking.created\"\n\"booking.updated\"\n\n// Inventory events\n\"inventory.count.updated\"\n\n// Catalog events\n\"catalog.version.updated\"\n```\n\n### Pagination\n\nHandle paginated results with cursor-based pagination.\n\n```javascript\nasync function getAllCustomers() {\n  const allCustomers = [];\n  let cursor = null;\n\n  do {\n    const response = await client.customers.list({\n      cursor: cursor,\n      limit: 100,\n    });\n\n    if (response.customers) {\n      allCustomers.push(...response.customers);\n    }\n\n    cursor = response.cursor;\n  } while (cursor);\n\n  return allCustomers;\n}\n```\n\n### Idempotency\n\nUse idempotency keys to prevent duplicate operations.\n\n```javascript\nimport { randomUUID } from 'crypto';\n\nasync function idempotentPayment(sourceId, amount, locationId) {\n  const idempotencyKey = randomUUID();\n\n  try {\n    const response = await client.payments.create({\n      sourceId: sourceId,\n      idempotencyKey: idempotencyKey,\n      amountMoney: {\n        amount: BigInt(amount),\n        currency: \"USD\",\n      },\n      locationId: locationId,\n    });\n\n    return response.payment;\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Payment failed:\", error.errors);\n    }\n    throw error;\n  }\n}\n```\n\n### Error Categories\n\n```javascript\n// Common Square error categories:\n// - API_ERROR: API-level error\n// - AUTHENTICATION_ERROR: Authentication failure\n// - INVALID_REQUEST_ERROR: Invalid request parameters\n// - RATE_LIMIT_ERROR: Too many requests\n// - PAYMENT_METHOD_ERROR: Payment method issue\n// - REFUND_ERROR: Refund processing error\n```\n\n### Testing with Sandbox\n\n```javascript\nconst { SquareClient, SquareEnvironment } = require(\"square\");\n\n// Always use sandbox for development\nconst client = new SquareClient({\n  token: process.env.SQUARE_SANDBOX_TOKEN,\n  environment: SquareEnvironment.Sandbox,\n});\n\n// Test payment source IDs for sandbox:\n// cnon:card-nonce-ok - successful charge\n// cnon:card-nonce-declined - declined charge\n// cnon:card-nonce-dishonoured - card verification failed\n```\n\n### Complete Example: Process Payment with Customer\n\n```javascript\nconst { SquareClient, SquareEnvironment, SquareError } = require(\"square\");\nconst { randomUUID } = require('crypto');\n\nconst client = new SquareClient({\n  token: process.env.SQUARE_ACCESS_TOKEN,\n  environment: SquareEnvironment.Sandbox,\n});\n\nasync function processPaymentWithCustomer(paymentDetails) {\n  try {\n    // 1. Create or retrieve customer\n    let customer;\n    try {\n      const customerResponse = await client.customers.create({\n        idempotencyKey: randomUUID(),\n        givenName: paymentDetails.givenName,\n        familyName: paymentDetails.familyName,\n        emailAddress: paymentDetails.emailAddress,\n      });\n      customer = customerResponse.customer;\n    } catch (error) {\n      console.log(\"Customer already exists, using existing\");\n    }\n\n    // 2. Create order\n    const orderResponse = await client.orders.create({\n      idempotencyKey: randomUUID(),\n      order: {\n        locationId: paymentDetails.locationId,\n        customerId: customer.id,\n        lineItems: [\n          {\n            name: paymentDetails.itemName,\n            quantity: \"1\",\n            basePriceMoney: {\n              amount: BigInt(paymentDetails.amount),\n              currency: \"USD\",\n            },\n          },\n        ],\n      },\n    });\n\n    // 3. Create payment\n    const paymentResponse = await client.payments.create({\n      sourceId: paymentDetails.sourceId,\n      idempotencyKey: randomUUID(),\n      amountMoney: {\n        amount: BigInt(paymentDetails.amount),\n        currency: \"USD\",\n      },\n      orderId: orderResponse.order.id,\n      customerId: customer.id,\n      locationId: paymentDetails.locationId,\n      autocomplete: true,\n    });\n\n    return {\n      payment: paymentResponse.payment,\n      order: orderResponse.order,\n      customer: customer,\n    };\n  } catch (error) {\n    if (error instanceof SquareError) {\n      console.error(\"Transaction failed:\");\n      error.errors.forEach(e => {\n        console.log(`  ${e.category}: ${e.code}`);\n        console.log(`  ${e.detail}`);\n      });\n    }\n    throw error;\n  }\n}\n\n// Usage\nprocessPaymentWithCustomer({\n  sourceId: \"cnon:card-nonce-ok\",\n  amount: 1000,\n  locationId: \"L88917AVBK2S5\",\n  givenName: \"John\",\n  familyName: \"Doe\",\n  emailAddress: \"john.doe@example.com\",\n  itemName: \"Premium Service\",\n}).then(result => {\n  console.log(\"Payment successful!\");\n  console.log(\"Payment ID:\", result.payment.id);\n  console.log(\"Order ID:\", result.order.id);\n  console.log(\"Customer ID:\", result.customer.id);\n});\n```\n"
  },
  {
    "path": "content/square/docs/payments/python/DOC.md",
    "content": "---\nname: payments\ndescription: \"Square Python SDK coding guide for payments, POS, and commerce checkout\"\nmetadata:\n  languages: \"python\"\n  versions: \"43.2.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"square,payments,pos,commerce,checkout\"\n---\n\n# Square Python SDK Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Square Python SDK package:**\n- Package name: `squareup` (Python library for Square API)\n- Official repository: https://github.com/square/square-python-sdk\n\n**Never use deprecated libraries:**\n- `squareconnect` (DEPRECATED - replaced by `squareup`)\n- `squareup_legacy` (legacy version for migration purposes only)\n\n**Current SDK Version:** v43.2.0\n\n**API Versioning:** Square uses date-based API versioning (e.g., 2025-08-20). Your account is automatically pinned to an API version. You can override this when initializing the client.\n\n## 2. Installation\n\n```bash\npip install squareup\n```\n\n```bash\npoetry add squareup\n```\n\n```bash\nuv add squareup\n```\n\n**Requirements:** Python 3.8+ (Python 3.10+ recommended for production)\n\n### Environment Variables\n\n```bash\n# Required\nSQUARE_TOKEN=EAAAl...          # Your Square access token\nSQUARE_ENVIRONMENT=sandbox     # or \"production\"\n\n# Optional\nSQUARE_LOCATION_ID=L88917...  # Default location ID for operations\n```\n\n**CRITICAL:** Never commit access tokens to version control. Use environment variables or secure secret management systems. Use sandbox tokens for development and testing.\n\n## 3. Initialization\n\n### Basic Initialization\n\n```python\nimport os\nfrom square import Square\n\nclient = Square(\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n)\n```\n\n### With Environment Specification\n\n```python\nimport os\nfrom square import Square\nfrom square.environment import Environment\n\nclient = Square(\n    environment=Environment.SANDBOX,\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n)\n```\n\n### Advanced Configuration\n\n```python\nimport os\nfrom square import Square\nfrom square.environment import Environment\n\nclient = Square(\n    environment=Environment.PRODUCTION,\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n    timeout=60,                    # 60 second timeout\n    max_retries=3,                 # Maximum retry attempts\n    square_version=\"2025-08-20\",   # Override API version\n    user_agent_detail=\"MyApp/1.0.0\",\n)\n```\n\n### Async Client Initialization\n\n```python\nimport os\nfrom square import AsyncSquare\nfrom square.environment import Environment\n\nasync_client = AsyncSquare(\n    environment=Environment.SANDBOX,\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n)\n```\n\n### Error Handling Setup\n\n```python\nfrom square import Square\nfrom square.core.api_error import ApiError\n\nclient = Square(\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n)\n\ntry:\n    # Make API calls here\n    pass\nexcept ApiError as e:\n    for error in e.errors:\n        print(f\"Category: {error.category}\")\n        print(f\"Code: {error.code}\")\n        print(f\"Detail: {error.detail}\")\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n## 4. Core API Surfaces\n\n### Locations API\n\nGet information about business locations.\n\n**List All Locations:**\n\n```python\ntry:\n    response = client.locations.list()\n    locations = response.locations\n\n    for location in locations:\n        print(f\"{location.id}: {location.name}\")\n        print(f\"Address: {location.address.address_line_1}\")\n        print(f\"City: {location.address.locality}\")\n\nexcept ApiError as e:\n    print(\"Error listing locations:\", e.errors)\n```\n\n**Retrieve Single Location:**\n\n```python\ndef get_location(location_id: str):\n    try:\n        response = client.locations.retrieve(location_id)\n        return response.location\n    except ApiError as e:\n        print(\"Error retrieving location:\", e.errors)\n        raise\n```\n\n**Async List Locations:**\n\n```python\nimport asyncio\n\nasync def list_locations_async():\n    try:\n        response = await async_client.locations.list()\n        return response.locations\n    except ApiError as e:\n        print(\"Error listing locations:\", e.errors)\n        raise\n\n# Usage\nlocations = asyncio.run(list_locations_async())\n```\n\n### Payments API\n\nProcess and manage payments.\n\n**Create Payment (Minimal):**\n\n```python\nimport uuid\n\ndef create_payment(source_id: str, amount: int, location_id: str):\n    try:\n        response = client.payments.create(\n            source_id=source_id,\n            idempotency_key=str(uuid.uuid4()),\n            amount_money={\n                \"amount\": amount,\n                \"currency\": \"USD\",\n            },\n            location_id=location_id,\n        )\n        return response.payment\n    except ApiError as e:\n        print(\"Payment error:\", e.errors)\n        raise\n```\n\n**Create Payment (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_payment(payment_data: dict):\n    try:\n        response = client.payments.create(\n            source_id=payment_data[\"source_id\"],\n            idempotency_key=str(uuid.uuid4()),\n            amount_money={\n                \"amount\": payment_data[\"amount\"],\n                \"currency\": payment_data.get(\"currency\", \"USD\"),\n            },\n            location_id=payment_data[\"location_id\"],\n            customer_id=payment_data.get(\"customer_id\"),\n            reference_id=payment_data.get(\"reference_id\"),\n            note=payment_data.get(\"note\"),\n            autocomplete=True,\n            buyer_email_address=payment_data.get(\"email\"),\n            billing_address={\n                \"address_line_1\": payment_data.get(\"address_line_1\"),\n                \"locality\": payment_data.get(\"city\"),\n                \"administrative_district_level_1\": payment_data.get(\"state\"),\n                \"postal_code\": payment_data.get(\"postal_code\"),\n                \"country\": payment_data.get(\"country\", \"US\"),\n            },\n        )\n        return response.payment\n    except ApiError as e:\n        print(\"Payment creation failed:\", e.errors)\n        raise\n```\n\n**List Payments:**\n\n```python\ndef list_payments(location_id: str, begin_time: str, end_time: str):\n    try:\n        response = client.payments.list(\n            location_id=location_id,\n            begin_time=begin_time,\n            end_time=end_time,\n            sort_order=\"DESC\",\n            limit=100,\n        )\n        return response.payments\n    except ApiError as e:\n        print(\"Error listing payments:\", e.errors)\n        raise\n```\n\n**Get Payment:**\n\n```python\ndef get_payment(payment_id: str):\n    try:\n        response = client.payments.retrieve(payment_id)\n        return response.payment\n    except ApiError as e:\n        print(\"Error retrieving payment:\", e.errors)\n        raise\n```\n\n**Complete Payment:**\n\n```python\ndef complete_payment(payment_id: str):\n    try:\n        response = client.payments.complete(payment_id)\n        return response.payment\n    except ApiError as e:\n        print(\"Error completing payment:\", e.errors)\n        raise\n```\n\n**Cancel Payment:**\n\n```python\ndef cancel_payment(payment_id: str):\n    try:\n        response = client.payments.cancel(payment_id)\n        return response.payment\n    except ApiError as e:\n        print(\"Error canceling payment:\", e.errors)\n        raise\n```\n\n**Async Create Payment:**\n\n```python\nimport asyncio\nimport uuid\n\nasync def create_payment_async(source_id: str, amount: int, location_id: str):\n    try:\n        response = await async_client.payments.create(\n            source_id=source_id,\n            idempotency_key=str(uuid.uuid4()),\n            amount_money={\n                \"amount\": amount,\n                \"currency\": \"USD\",\n            },\n            location_id=location_id,\n        )\n        return response.payment\n    except ApiError as e:\n        print(\"Payment error:\", e.errors)\n        raise\n```\n\n### Refunds API\n\nManage payment refunds.\n\n**Create Refund (Minimal):**\n\n```python\nimport uuid\n\ndef create_refund(payment_id: str, amount: int, currency: str = \"USD\"):\n    try:\n        response = client.refunds.create(\n            idempotency_key=str(uuid.uuid4()),\n            payment_id=payment_id,\n            amount_money={\n                \"amount\": amount,\n                \"currency\": currency,\n            },\n        )\n        return response.refund\n    except ApiError as e:\n        print(\"Refund error:\", e.errors)\n        raise\n```\n\n**Create Refund (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_refund(refund_data: dict):\n    try:\n        response = client.refunds.create(\n            idempotency_key=str(uuid.uuid4()),\n            payment_id=refund_data[\"payment_id\"],\n            amount_money={\n                \"amount\": refund_data[\"amount\"],\n                \"currency\": refund_data.get(\"currency\", \"USD\"),\n            },\n            reason=refund_data.get(\"reason\"),\n            location_id=refund_data.get(\"location_id\"),\n        )\n        return response.refund\n    except ApiError as e:\n        print(\"Refund creation failed:\", e.errors)\n        raise\n```\n\n**Get Refund:**\n\n```python\ndef get_refund(refund_id: str):\n    try:\n        response = client.refunds.retrieve(refund_id)\n        return response.refund\n    except ApiError as e:\n        print(\"Error retrieving refund:\", e.errors)\n        raise\n```\n\n**List Refunds:**\n\n```python\ndef list_refunds(location_id: str, begin_time: str, end_time: str):\n    try:\n        response = client.refunds.list(\n            location_id=location_id,\n            begin_time=begin_time,\n            end_time=end_time,\n            sort_order=\"DESC\",\n        )\n        return response.refunds\n    except ApiError as e:\n        print(\"Error listing refunds:\", e.errors)\n        raise\n```\n\n### Orders API\n\nCreate and manage orders.\n\n**Create Order (Minimal):**\n\n```python\nimport uuid\n\ndef create_order(location_id: str):\n    try:\n        response = client.orders.create(\n            idempotency_key=str(uuid.uuid4()),\n            order={\n                \"location_id\": location_id,\n                \"line_items\": [\n                    {\n                        \"name\": \"Item Name\",\n                        \"quantity\": \"1\",\n                        \"base_price_money\": {\n                            \"amount\": 1000,\n                            \"currency\": \"USD\",\n                        },\n                    },\n                ],\n            },\n        )\n        return response.order\n    except ApiError as e:\n        print(\"Order creation error:\", e.errors)\n        raise\n```\n\n**Create Order (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_order(order_data: dict):\n    try:\n        line_items = [\n            {\n                \"name\": item[\"name\"],\n                \"quantity\": str(item[\"quantity\"]),\n                \"base_price_money\": {\n                    \"amount\": item[\"price\"],\n                    \"currency\": item.get(\"currency\", \"USD\"),\n                },\n                \"note\": item.get(\"note\"),\n            }\n            for item in order_data[\"line_items\"]\n        ]\n\n        taxes = [\n            {\n                \"name\": \"Sales Tax\",\n                \"percentage\": \"8.5\",\n                \"scope\": \"ORDER\",\n            }\n        ]\n\n        discounts = [\n            {\n                \"name\": discount[\"name\"],\n                \"percentage\": discount[\"percentage\"],\n                \"scope\": \"ORDER\",\n            }\n            for discount in order_data.get(\"discounts\", [])\n        ]\n\n        response = client.orders.create(\n            idempotency_key=str(uuid.uuid4()),\n            order={\n                \"location_id\": order_data[\"location_id\"],\n                \"reference_id\": order_data.get(\"reference_id\"),\n                \"customer_id\": order_data.get(\"customer_id\"),\n                \"line_items\": line_items,\n                \"taxes\": taxes,\n                \"discounts\": discounts,\n            },\n        )\n        return response.order\n    except ApiError as e:\n        print(\"Order creation failed:\", e.errors)\n        raise\n```\n\n**Retrieve Order:**\n\n```python\ndef retrieve_order(order_id: str):\n    try:\n        response = client.orders.retrieve(order_id)\n        return response.order\n    except ApiError as e:\n        print(\"Error retrieving order:\", e.errors)\n        raise\n```\n\n**Update Order:**\n\n```python\ndef update_order(order_id: str, updates: dict):\n    try:\n        response = client.orders.update(\n            order_id=order_id,\n            order=updates,\n        )\n        return response.order\n    except ApiError as e:\n        print(\"Error updating order:\", e.errors)\n        raise\n```\n\n**Search Orders:**\n\n```python\ndef search_orders(location_ids: list, query: dict):\n    try:\n        search_query = {\n            \"filter\": {\n                \"state_filter\": {\n                    \"states\": [\"OPEN\", \"COMPLETED\"],\n                },\n            },\n            \"sort\": {\n                \"sort_field\": \"CREATED_AT\",\n                \"sort_order\": \"DESC\",\n            },\n        }\n\n        if query.get(\"date_time_filter\"):\n            search_query[\"filter\"][\"date_time_filter\"] = query[\"date_time_filter\"]\n\n        if query.get(\"customer_id\"):\n            search_query[\"filter\"][\"customer_filter\"] = {\n                \"customer_ids\": [query[\"customer_id\"]],\n            }\n\n        response = client.orders.search(\n            location_ids=location_ids,\n            query=search_query,\n            limit=query.get(\"limit\", 100),\n        )\n        return response.orders\n    except ApiError as e:\n        print(\"Error searching orders:\", e.errors)\n        raise\n```\n\n### Customers API\n\nManage customer profiles.\n\n**Create Customer (Minimal):**\n\n```python\nimport uuid\n\ndef create_customer(email: str, given_name: str, family_name: str):\n    try:\n        response = client.customers.create(\n            idempotency_key=str(uuid.uuid4()),\n            email_address=email,\n            given_name=given_name,\n            family_name=family_name,\n        )\n        return response.customer\n    except ApiError as e:\n        print(\"Customer creation error:\", e.errors)\n        raise\n```\n\n**Create Customer (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_customer(customer_data: dict):\n    try:\n        response = client.customers.create(\n            idempotency_key=str(uuid.uuid4()),\n            given_name=customer_data[\"given_name\"],\n            family_name=customer_data[\"family_name\"],\n            email_address=customer_data.get(\"email_address\"),\n            phone_number=customer_data.get(\"phone_number\"),\n            address={\n                \"address_line_1\": customer_data.get(\"address_line_1\"),\n                \"address_line_2\": customer_data.get(\"address_line_2\"),\n                \"locality\": customer_data.get(\"city\"),\n                \"administrative_district_level_1\": customer_data.get(\"state\"),\n                \"postal_code\": customer_data.get(\"postal_code\"),\n                \"country\": customer_data.get(\"country\", \"US\"),\n            },\n            reference_id=customer_data.get(\"reference_id\"),\n            note=customer_data.get(\"note\"),\n            birthday=customer_data.get(\"birthday\"),\n            company_name=customer_data.get(\"company_name\"),\n        )\n        return response.customer\n    except ApiError as e:\n        print(\"Customer creation failed:\", e.errors)\n        raise\n```\n\n**List Customers with Pagination:**\n\n```python\ndef list_customers(cursor: str = None, limit: int = 100):\n    try:\n        response = client.customers.list(\n            cursor=cursor,\n            limit=limit,\n            sort_field=\"CREATED_AT\",\n            sort_order=\"DESC\",\n        )\n        return {\n            \"customers\": response.customers,\n            \"cursor\": response.cursor,\n        }\n    except ApiError as e:\n        print(\"Error listing customers:\", e.errors)\n        raise\n```\n\n**List All Customers with Auto-Pagination:**\n\n```python\ndef list_all_customers():\n    try:\n        all_customers = []\n        response = client.customers.list(limit=100)\n\n        # Auto-pagination: iterate over all pages\n        for customer in response:\n            all_customers.append(customer)\n\n        return all_customers\n    except ApiError as e:\n        print(\"Error listing customers:\", e.errors)\n        raise\n```\n\n**Retrieve Customer:**\n\n```python\ndef retrieve_customer(customer_id: str):\n    try:\n        response = client.customers.retrieve(customer_id)\n        return response.customer\n    except ApiError as e:\n        print(\"Error retrieving customer:\", e.errors)\n        raise\n```\n\n**Update Customer:**\n\n```python\ndef update_customer(customer_id: str, updates: dict):\n    try:\n        response = client.customers.update(\n            customer_id=customer_id,\n            **updates\n        )\n        return response.customer\n    except ApiError as e:\n        print(\"Error updating customer:\", e.errors)\n        raise\n```\n\n**Delete Customer:**\n\n```python\ndef delete_customer(customer_id: str):\n    try:\n        response = client.customers.delete(customer_id)\n        return response\n    except ApiError as e:\n        print(\"Error deleting customer:\", e.errors)\n        raise\n```\n\n**Search Customers:**\n\n```python\ndef search_customers(query: dict):\n    try:\n        search_query = {\n            \"filter\": {},\n        }\n\n        if query.get(\"email\"):\n            search_query[\"filter\"][\"email_address\"] = {\n                \"exact\": query[\"email\"],\n            }\n\n        if query.get(\"phone\"):\n            search_query[\"filter\"][\"phone_number\"] = {\n                \"exact\": query[\"phone\"],\n            }\n\n        if query.get(\"created_at\"):\n            search_query[\"filter\"][\"created_at\"] = query[\"created_at\"]\n\n        response = client.customers.search(\n            query=search_query,\n            limit=query.get(\"limit\", 100),\n        )\n        return response.customers\n    except ApiError as e:\n        print(\"Error searching customers:\", e.errors)\n        raise\n```\n\n### Catalog API\n\nManage items, categories, taxes, and modifiers.\n\n**Create Catalog Item (Minimal):**\n\n```python\nimport uuid\n\ndef create_catalog_item(name: str, price: int):\n    try:\n        item_id = f\"#{name.replace(' ', '_')}\"\n\n        response = client.catalog.upsert_catalog_object(\n            idempotency_key=str(uuid.uuid4()),\n            object={\n                \"type\": \"ITEM\",\n                \"id\": item_id,\n                \"item_data\": {\n                    \"name\": name,\n                    \"variations\": [\n                        {\n                            \"type\": \"ITEM_VARIATION\",\n                            \"id\": f\"{item_id}_variation\",\n                            \"item_variation_data\": {\n                                \"name\": \"Regular\",\n                                \"pricing_type\": \"FIXED_PRICING\",\n                                \"price_money\": {\n                                    \"amount\": price,\n                                    \"currency\": \"USD\",\n                                },\n                            },\n                        },\n                    ],\n                },\n            },\n        )\n        return response.catalog_object\n    except ApiError as e:\n        print(\"Catalog item creation error:\", e.errors)\n        raise\n```\n\n**Create Catalog Item (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_catalog_item(item_data: dict):\n    try:\n        item_id = f\"#{item_data['name'].replace(' ', '_')}\"\n\n        variations = [\n            {\n                \"type\": \"ITEM_VARIATION\",\n                \"id\": f\"{item_id}_var_{i}\",\n                \"item_variation_data\": {\n                    \"name\": var[\"name\"],\n                    \"sku\": var.get(\"sku\"),\n                    \"pricing_type\": \"FIXED_PRICING\",\n                    \"price_money\": {\n                        \"amount\": var[\"price\"],\n                        \"currency\": var.get(\"currency\", \"USD\"),\n                    },\n                    \"track_inventory\": var.get(\"track_inventory\", False),\n                },\n            }\n            for i, var in enumerate(item_data[\"variations\"])\n        ]\n\n        response = client.catalog.upsert_catalog_object(\n            idempotency_key=str(uuid.uuid4()),\n            object={\n                \"type\": \"ITEM\",\n                \"id\": item_id,\n                \"item_data\": {\n                    \"name\": item_data[\"name\"],\n                    \"description\": item_data.get(\"description\"),\n                    \"category_id\": item_data.get(\"category_id\"),\n                    \"tax_ids\": item_data.get(\"tax_ids\"),\n                    \"variations\": variations,\n                },\n            },\n        )\n        return response.catalog_object\n    except ApiError as e:\n        print(\"Catalog item creation failed:\", e.errors)\n        raise\n```\n\n**List Catalog:**\n\n```python\ndef list_catalog(types: list = None, cursor: str = None):\n    try:\n        if types is None:\n            types = [\"ITEM\"]\n\n        response = client.catalog.list(\n            cursor=cursor,\n            types=\",\".join(types),\n        )\n        return {\n            \"objects\": response.objects,\n            \"cursor\": response.cursor,\n        }\n    except ApiError as e:\n        print(\"Error listing catalog:\", e.errors)\n        raise\n```\n\n**Retrieve Catalog Object:**\n\n```python\ndef retrieve_catalog_object(object_id: str):\n    try:\n        response = client.catalog.retrieve(\n            object_id=object_id,\n            include_related_objects=True,\n        )\n        return response.object\n    except ApiError as e:\n        print(\"Error retrieving catalog object:\", e.errors)\n        raise\n```\n\n**Search Catalog Items:**\n\n```python\ndef search_catalog_items(query: dict):\n    try:\n        response = client.catalog.search_catalog_items(\n            text_filter=query.get(\"text\"),\n            category_ids=query.get(\"category_ids\"),\n            stock_levels=query.get(\"stock_levels\"),\n            enabled_location_ids=query.get(\"location_ids\"),\n            limit=query.get(\"limit\", 100),\n        )\n        return response.items\n    except ApiError as e:\n        print(\"Error searching catalog:\", e.errors)\n        raise\n```\n\n**Delete Catalog Object:**\n\n```python\ndef delete_catalog_object(object_id: str):\n    try:\n        response = client.catalog.delete_catalog_object(object_id)\n        return response\n    except ApiError as e:\n        print(\"Error deleting catalog object:\", e.errors)\n        raise\n```\n\n**Batch Upsert Catalog Objects:**\n\n```python\nimport uuid\n\ndef batch_upsert_catalog_objects(objects: list):\n    try:\n        response = client.catalog.batch_upsert_catalog_objects(\n            idempotency_key=str(uuid.uuid4()),\n            batches=[\n                {\n                    \"objects\": objects,\n                },\n            ],\n        )\n        return response.objects\n    except ApiError as e:\n        print(\"Batch upsert error:\", e.errors)\n        raise\n```\n\n### Inventory API\n\nTrack and manage inventory.\n\n**Retrieve Inventory Count:**\n\n```python\ndef retrieve_inventory_count(catalog_object_id: str, location_ids: list):\n    try:\n        response = client.inventory.retrieve_inventory_count(\n            catalog_object_id=catalog_object_id,\n            location_ids=\",\".join(location_ids),\n        )\n        return response.counts\n    except ApiError as e:\n        print(\"Error retrieving inventory:\", e.errors)\n        raise\n```\n\n**Batch Retrieve Inventory Counts:**\n\n```python\ndef batch_retrieve_inventory_counts(catalog_object_ids: list, location_ids: list):\n    try:\n        response = client.inventory.batch_retrieve_inventory_counts(\n            catalog_object_ids=catalog_object_ids,\n            location_ids=location_ids,\n        )\n        return response.counts\n    except ApiError as e:\n        print(\"Error retrieving inventory counts:\", e.errors)\n        raise\n```\n\n**Adjust Inventory:**\n\n```python\nimport uuid\nfrom datetime import datetime\n\ndef adjust_inventory(catalog_object_id: str, location_id: str, adjustment: dict):\n    try:\n        response = client.inventory.batch_change_inventory(\n            idempotency_key=str(uuid.uuid4()),\n            changes=[\n                {\n                    \"type\": \"ADJUSTMENT\",\n                    \"adjustment\": {\n                        \"catalog_object_id\": catalog_object_id,\n                        \"location_id\": location_id,\n                        \"quantity\": str(adjustment[\"quantity\"]),\n                        \"from_state\": \"IN_STOCK\",\n                        \"to_state\": \"IN_STOCK\",\n                        \"occurred_at\": datetime.utcnow().isoformat(),\n                    },\n                },\n            ],\n        )\n        return response.counts\n    except ApiError as e:\n        print(\"Error adjusting inventory:\", e.errors)\n        raise\n```\n\n### Invoices API\n\nCreate and manage invoices.\n\n**Create Invoice (Minimal):**\n\n```python\nimport uuid\nfrom datetime import datetime, timedelta\n\ndef create_invoice(location_id: str, customer_id: str, order_id: str):\n    try:\n        due_date = (datetime.now() + timedelta(days=7)).strftime(\"%Y-%m-%d\")\n\n        response = client.invoices.create(\n            invoice={\n                \"location_id\": location_id,\n                \"order_id\": order_id,\n                \"primary_recipient\": {\n                    \"customer_id\": customer_id,\n                },\n                \"payment_requests\": [\n                    {\n                        \"request_type\": \"BALANCE\",\n                        \"due_date\": due_date,\n                    },\n                ],\n            },\n            idempotency_key=str(uuid.uuid4()),\n        )\n        return response.invoice\n    except ApiError as e:\n        print(\"Invoice creation error:\", e.errors)\n        raise\n```\n\n**Create Invoice (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_invoice(invoice_data: dict):\n    try:\n        payment_requests = [\n            {\n                \"request_type\": \"BALANCE\",\n                \"due_date\": invoice_data[\"due_date\"],\n                \"reminders\": [\n                    {\n                        \"relative_scheduled_days\": -1,\n                        \"message\": \"Payment reminder\",\n                    },\n                ],\n            }\n        ]\n\n        if invoice_data.get(\"fixed_amount\"):\n            payment_requests[0][\"fixed_amount_requested_money\"] = {\n                \"amount\": invoice_data[\"fixed_amount\"],\n                \"currency\": invoice_data.get(\"currency\", \"USD\"),\n            }\n\n        response = client.invoices.create(\n            invoice={\n                \"location_id\": invoice_data[\"location_id\"],\n                \"order_id\": invoice_data[\"order_id\"],\n                \"primary_recipient\": {\n                    \"customer_id\": invoice_data[\"customer_id\"],\n                    \"given_name\": invoice_data.get(\"given_name\"),\n                    \"family_name\": invoice_data.get(\"family_name\"),\n                    \"email_address\": invoice_data.get(\"email_address\"),\n                },\n                \"payment_requests\": payment_requests,\n                \"delivery_method\": \"EMAIL\",\n                \"invoice_number\": invoice_data.get(\"invoice_number\"),\n                \"title\": invoice_data.get(\"title\"),\n                \"description\": invoice_data.get(\"description\"),\n            },\n            idempotency_key=str(uuid.uuid4()),\n        )\n        return response.invoice\n    except ApiError as e:\n        print(\"Invoice creation failed:\", e.errors)\n        raise\n```\n\n**Publish Invoice:**\n\n```python\ndef publish_invoice(invoice_id: str):\n    try:\n        response = client.invoices.publish(\n            invoice_id=invoice_id,\n            version=0,\n        )\n        return response.invoice\n    except ApiError as e:\n        print(\"Error publishing invoice:\", e.errors)\n        raise\n```\n\n**Get Invoice:**\n\n```python\ndef get_invoice(invoice_id: str):\n    try:\n        response = client.invoices.retrieve(invoice_id)\n        return response.invoice\n    except ApiError as e:\n        print(\"Error retrieving invoice:\", e.errors)\n        raise\n```\n\n**Search Invoices:**\n\n```python\ndef search_invoices(location_ids: list, query: dict):\n    try:\n        search_query = {\n            \"location_ids\": location_ids,\n            \"filter\": {},\n            \"sort\": {\n                \"field\": \"INVOICE_SORT_DATE\",\n                \"order\": \"DESC\",\n            },\n        }\n\n        if query.get(\"customer_ids\"):\n            search_query[\"filter\"][\"customer_ids\"] = query[\"customer_ids\"]\n\n        if query.get(\"states\"):\n            search_query[\"filter\"][\"state_filter\"] = query[\"states\"]\n\n        response = client.invoices.search(\n            query=search_query,\n            limit=query.get(\"limit\", 100),\n        )\n        return response.invoices\n    except ApiError as e:\n        print(\"Error searching invoices:\", e.errors)\n        raise\n```\n\n### Subscriptions API\n\nManage recurring payments and subscriptions.\n\n**Create Subscription (Minimal):**\n\n```python\nimport uuid\n\ndef create_subscription(location_id: str, customer_id: str, plan_id: str):\n    try:\n        response = client.subscriptions.create(\n            idempotency_key=str(uuid.uuid4()),\n            location_id=location_id,\n            plan_id=plan_id,\n            customer_id=customer_id,\n        )\n        return response.subscription\n    except ApiError as e:\n        print(\"Subscription creation error:\", e.errors)\n        raise\n```\n\n**Create Subscription (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_subscription(subscription_data: dict):\n    try:\n        price_override = None\n        if subscription_data.get(\"price_override\"):\n            price_override = {\n                \"amount\": subscription_data[\"price_override\"],\n                \"currency\": subscription_data.get(\"currency\", \"USD\"),\n            }\n\n        response = client.subscriptions.create(\n            idempotency_key=str(uuid.uuid4()),\n            location_id=subscription_data[\"location_id\"],\n            plan_id=subscription_data[\"plan_id\"],\n            customer_id=subscription_data[\"customer_id\"],\n            start_date=subscription_data.get(\"start_date\"),\n            tax_percentage=subscription_data.get(\"tax_percentage\"),\n            price_override_money=price_override,\n            card_id=subscription_data.get(\"card_id\"),\n        )\n        return response.subscription\n    except ApiError as e:\n        print(\"Subscription creation failed:\", e.errors)\n        raise\n```\n\n**Retrieve Subscription:**\n\n```python\ndef retrieve_subscription(subscription_id: str):\n    try:\n        response = client.subscriptions.retrieve(\n            subscription_id=subscription_id,\n            include=\"actions\",\n        )\n        return response.subscription\n    except ApiError as e:\n        print(\"Error retrieving subscription:\", e.errors)\n        raise\n```\n\n**Cancel Subscription:**\n\n```python\ndef cancel_subscription(subscription_id: str):\n    try:\n        response = client.subscriptions.cancel(subscription_id)\n        return response.subscription\n    except ApiError as e:\n        print(\"Error canceling subscription:\", e.errors)\n        raise\n```\n\n**Search Subscriptions:**\n\n```python\ndef search_subscriptions(query: dict):\n    try:\n        search_query = {\n            \"filter\": {},\n        }\n\n        if query.get(\"customer_ids\"):\n            search_query[\"filter\"][\"customer_ids\"] = query[\"customer_ids\"]\n\n        if query.get(\"location_ids\"):\n            search_query[\"filter\"][\"location_ids\"] = query[\"location_ids\"]\n\n        response = client.subscriptions.search(\n            query=search_query,\n            limit=query.get(\"limit\", 100),\n        )\n        return response.subscriptions\n    except ApiError as e:\n        print(\"Error searching subscriptions:\", e.errors)\n        raise\n```\n\n### Checkout API\n\nCreate hosted checkout pages.\n\n**Create Checkout (Minimal):**\n\n```python\nimport uuid\n\ndef create_checkout(location_id: str, order_id: str):\n    try:\n        response = client.checkout.create(\n            location_id=location_id,\n            idempotency_key=str(uuid.uuid4()),\n            order={\n                \"order_id\": order_id,\n            },\n        )\n        return response.checkout.checkout_page_url\n    except ApiError as e:\n        print(\"Checkout creation error:\", e.errors)\n        raise\n```\n\n**Create Checkout (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_checkout(location_id: str, checkout_data: dict):\n    try:\n        response = client.checkout.create(\n            location_id=location_id,\n            idempotency_key=str(uuid.uuid4()),\n            order={\n                \"order_id\": checkout_data[\"order_id\"],\n                \"location_id\": location_id,\n            },\n            ask_for_shipping_address=checkout_data.get(\"ask_for_shipping_address\", False),\n            merchant_support_email=checkout_data.get(\"merchant_email\"),\n            pre_populate_buyer_email=checkout_data.get(\"buyer_email\"),\n            redirect_url=checkout_data.get(\"redirect_url\"),\n            additional_recipients=checkout_data.get(\"additional_recipients\"),\n        )\n        return response.checkout\n    except ApiError as e:\n        print(\"Checkout creation failed:\", e.errors)\n        raise\n```\n\n### Bookings API\n\nManage appointments and bookings.\n\n**Create Booking (Minimal):**\n\n```python\nimport uuid\n\ndef create_booking(location_id: str, customer_id: str, start_at: str,\n                   service_variation_id: str, team_member_id: str):\n    try:\n        response = client.bookings.create(\n            idempotency_key=str(uuid.uuid4()),\n            booking={\n                \"location_id\": location_id,\n                \"customer_id\": customer_id,\n                \"start_at\": start_at,\n                \"appointment_segments\": [\n                    {\n                        \"duration_minutes\": 60,\n                        \"service_variation_id\": service_variation_id,\n                        \"team_member_id\": team_member_id,\n                    },\n                ],\n            },\n        )\n        return response.booking\n    except ApiError as e:\n        print(\"Booking creation error:\", e.errors)\n        raise\n```\n\n**Create Booking (Advanced):**\n\n```python\nimport uuid\n\ndef create_advanced_booking(booking_data: dict):\n    try:\n        appointment_segments = [\n            {\n                \"duration_minutes\": segment[\"duration_minutes\"],\n                \"service_variation_id\": segment[\"service_variation_id\"],\n                \"team_member_id\": segment[\"team_member_id\"],\n            }\n            for segment in booking_data[\"appointment_segments\"]\n        ]\n\n        response = client.bookings.create(\n            idempotency_key=str(uuid.uuid4()),\n            booking={\n                \"location_id\": booking_data[\"location_id\"],\n                \"customer_id\": booking_data[\"customer_id\"],\n                \"customer_note\": booking_data.get(\"customer_note\"),\n                \"seller_note\": booking_data.get(\"seller_note\"),\n                \"start_at\": booking_data[\"start_at\"],\n                \"appointment_segments\": appointment_segments,\n            },\n        )\n        return response.booking\n    except ApiError as e:\n        print(\"Booking creation failed:\", e.errors)\n        raise\n```\n\n**List Bookings:**\n\n```python\ndef list_bookings(location_id: str, start_at_min: str, start_at_max: str):\n    try:\n        response = client.bookings.list(\n            location_id=location_id,\n            start_at_min=start_at_min,\n            start_at_max=start_at_max,\n            limit=100,\n        )\n        return response.bookings\n    except ApiError as e:\n        print(\"Error listing bookings:\", e.errors)\n        raise\n```\n\n**Retrieve Booking:**\n\n```python\ndef retrieve_booking(booking_id: str):\n    try:\n        response = client.bookings.retrieve(booking_id)\n        return response.booking\n    except ApiError as e:\n        print(\"Error retrieving booking:\", e.errors)\n        raise\n```\n\n**Cancel Booking:**\n\n```python\nimport uuid\n\ndef cancel_booking(booking_id: str):\n    try:\n        response = client.bookings.cancel(\n            booking_id=booking_id,\n            idempotency_key=str(uuid.uuid4()),\n        )\n        return response.booking\n    except ApiError as e:\n        print(\"Error canceling booking:\", e.errors)\n        raise\n```\n\n### Terminal API\n\nCreate checkouts for Square Terminal devices.\n\n**Create Terminal Checkout:**\n\n```python\nimport uuid\n\ndef create_terminal_checkout(device_id: str, amount: int, location_id: str):\n    try:\n        response = client.terminal.create_terminal_checkout(\n            idempotency_key=str(uuid.uuid4()),\n            checkout={\n                \"amount_money\": {\n                    \"amount\": amount,\n                    \"currency\": \"USD\",\n                },\n                \"device_options\": {\n                    \"device_id\": device_id,\n                },\n            },\n        )\n        return response.checkout\n    except ApiError as e:\n        print(\"Terminal checkout error:\", e.errors)\n        raise\n```\n\n**Get Terminal Checkout:**\n\n```python\ndef get_terminal_checkout(checkout_id: str):\n    try:\n        response = client.terminal.get_terminal_checkout(checkout_id)\n        return response.checkout\n    except ApiError as e:\n        print(\"Error retrieving terminal checkout:\", e.errors)\n        raise\n```\n\n**Cancel Terminal Checkout:**\n\n```python\ndef cancel_terminal_checkout(checkout_id: str):\n    try:\n        response = client.terminal.cancel_terminal_checkout(checkout_id)\n        return response.checkout\n    except ApiError as e:\n        print(\"Error canceling terminal checkout:\", e.errors)\n        raise\n```\n\n### Webhooks\n\nHandle webhook notifications from Square.\n\n**Create Webhook Subscription:**\n\n```python\ndef create_webhook_subscription(notification_url: str, event_types: list):\n    try:\n        response = client.webhook_subscriptions.create(\n            subscription={\n                \"name\": \"My Webhook\",\n                \"notification_url\": notification_url,\n                \"event_types\": event_types,\n            },\n        )\n        return response.subscription\n    except ApiError as e:\n        print(\"Webhook creation error:\", e.errors)\n        raise\n```\n\n**List Webhook Subscriptions:**\n\n```python\ndef list_webhook_subscriptions():\n    try:\n        response = client.webhook_subscriptions.list()\n        return response.subscriptions\n    except ApiError as e:\n        print(\"Error listing webhooks:\", e.errors)\n        raise\n```\n\n**Verify Webhook Signature:**\n\n```python\nimport hmac\nimport hashlib\n\ndef verify_webhook_signature(body: str, signature: str, signature_key: str, notification_url: str) -> bool:\n    message = notification_url + body\n    hmac_obj = hmac.new(\n        signature_key.encode('utf-8'),\n        message.encode('utf-8'),\n        hashlib.sha256\n    )\n    expected_signature = hmac_obj.digest().hex()\n\n    return hmac.compare_digest(expected_signature, signature)\n```\n\n**Handle Webhook (Flask):**\n\n```python\nfrom flask import Flask, request\n\napp = Flask(__name__)\n\n@app.route('/webhooks/square', methods=['POST'])\ndef handle_square_webhook():\n    signature = request.headers.get('x-square-hmacsha256-signature')\n    body = request.get_data(as_text=True)\n\n    is_valid = verify_webhook_signature(\n        body,\n        signature,\n        os.environ.get('SQUARE_WEBHOOK_SECRET'),\n        'https://yourdomain.com/webhooks/square'\n    )\n\n    if not is_valid:\n        return 'Invalid signature', 400\n\n    event = request.json\n\n    if event['type'] == 'payment.created':\n        print('Payment created:', event['data']['object']['payment'])\n    elif event['type'] == 'order.created':\n        print('Order created:', event['data']['object']['order'])\n    elif event['type'] == 'customer.created':\n        print('Customer created:', event['data']['object']['customer'])\n    else:\n        print('Unhandled event type:', event['type'])\n\n    return 'OK', 200\n```\n\n### Common Webhook Events\n\n```python\n# Payment events\nPAYMENT_CREATED = \"payment.created\"\nPAYMENT_UPDATED = \"payment.updated\"\n\n# Order events\nORDER_CREATED = \"order.created\"\nORDER_UPDATED = \"order.updated\"\nORDER_FULFILLMENT_UPDATED = \"order.fulfillment.updated\"\n\n# Customer events\nCUSTOMER_CREATED = \"customer.created\"\nCUSTOMER_UPDATED = \"customer.updated\"\nCUSTOMER_DELETED = \"customer.deleted\"\n\n# Invoice events\nINVOICE_CREATED = \"invoice.created\"\nINVOICE_PUBLISHED = \"invoice.published\"\nINVOICE_PAYMENT_MADE = \"invoice.payment_made\"\n\n# Subscription events\nSUBSCRIPTION_CREATED = \"subscription.created\"\nSUBSCRIPTION_STARTED = \"subscription.started\"\nSUBSCRIPTION_CANCELED = \"subscription.canceled\"\n\n# Booking events\nBOOKING_CREATED = \"booking.created\"\nBOOKING_UPDATED = \"booking.updated\"\n\n# Inventory events\nINVENTORY_COUNT_UPDATED = \"inventory.count.updated\"\n\n# Catalog events\nCATALOG_VERSION_UPDATED = \"catalog.version.updated\"\n```\n\n### Pagination\n\nHandle paginated results with auto-pagination.\n\n```python\ndef get_all_customers():\n    try:\n        all_customers = []\n        response = client.customers.list(limit=100)\n\n        # Auto-pagination using iterator\n        for customer in response:\n            all_customers.append(customer)\n\n        return all_customers\n    except ApiError as e:\n        print(\"Error fetching customers:\", e.errors)\n        raise\n```\n\n### Manual Pagination\n\n```python\ndef get_all_customers_manual():\n    all_customers = []\n    cursor = None\n\n    while True:\n        try:\n            response = client.customers.list(\n                cursor=cursor,\n                limit=100,\n            )\n\n            if response.customers:\n                all_customers.extend(response.customers)\n\n            cursor = response.cursor\n            if not cursor:\n                break\n\n        except ApiError as e:\n            print(\"Error fetching customers:\", e.errors)\n            raise\n\n    return all_customers\n```\n\n### Idempotency\n\nUse idempotency keys to prevent duplicate operations.\n\n```python\nimport uuid\n\ndef idempotent_payment(source_id: str, amount: int, location_id: str):\n    idempotency_key = str(uuid.uuid4())\n\n    try:\n        response = client.payments.create(\n            source_id=source_id,\n            idempotency_key=idempotency_key,\n            amount_money={\n                \"amount\": amount,\n                \"currency\": \"USD\",\n            },\n            location_id=location_id,\n        )\n        return response.payment\n    except ApiError as e:\n        print(\"Payment failed:\", e.errors)\n        raise\n```\n\n### Testing with Sandbox\n\n```python\nimport os\nfrom square import Square\nfrom square.environment import Environment\n\n# Always use sandbox for development\nclient = Square(\n    environment=Environment.SANDBOX,\n    token=os.environ.get(\"SQUARE_SANDBOX_TOKEN\"),\n)\n\n# Test payment source IDs for sandbox:\n# cnon:card-nonce-ok - successful charge\n# cnon:card-nonce-declined - declined charge\n# cnon:card-nonce-dishonoured - card verification failed\n```\n\n### Complete Example: Process Payment with Customer\n\n```python\nimport os\nimport uuid\nfrom square import Square\nfrom square.core.api_error import ApiError\nfrom square.environment import Environment\n\nclient = Square(\n    environment=Environment.SANDBOX,\n    token=os.environ.get(\"SQUARE_TOKEN\"),\n)\n\ndef process_payment_with_customer(payment_details: dict):\n    try:\n        # 1. Create or retrieve customer\n        customer = None\n        try:\n            customer_response = client.customers.create(\n                idempotency_key=str(uuid.uuid4()),\n                given_name=payment_details[\"given_name\"],\n                family_name=payment_details[\"family_name\"],\n                email_address=payment_details[\"email_address\"],\n            )\n            customer = customer_response.customer\n        except ApiError:\n            print(\"Customer already exists, using existing\")\n\n        # 2. Create order\n        order_response = client.orders.create(\n            idempotency_key=str(uuid.uuid4()),\n            order={\n                \"location_id\": payment_details[\"location_id\"],\n                \"customer_id\": customer.id if customer else None,\n                \"line_items\": [\n                    {\n                        \"name\": payment_details[\"item_name\"],\n                        \"quantity\": \"1\",\n                        \"base_price_money\": {\n                            \"amount\": payment_details[\"amount\"],\n                            \"currency\": \"USD\",\n                        },\n                    },\n                ],\n            },\n        )\n\n        # 3. Create payment\n        payment_response = client.payments.create(\n            source_id=payment_details[\"source_id\"],\n            idempotency_key=str(uuid.uuid4()),\n            amount_money={\n                \"amount\": payment_details[\"amount\"],\n                \"currency\": \"USD\",\n            },\n            order_id=order_response.order.id,\n            customer_id=customer.id if customer else None,\n            location_id=payment_details[\"location_id\"],\n            autocomplete=True,\n        )\n\n        return {\n            \"payment\": payment_response.payment,\n            \"order\": order_response.order,\n            \"customer\": customer,\n        }\n\n    except ApiError as e:\n        print(\"Transaction failed:\")\n        for error in e.errors:\n            print(f\"  {error.category}: {error.code}\")\n            print(f\"  {error.detail}\")\n        raise\n\n# Usage\nresult = process_payment_with_customer({\n    \"source_id\": \"cnon:card-nonce-ok\",\n    \"amount\": 1000,\n    \"location_id\": \"L88917AVBK2S5\",\n    \"given_name\": \"John\",\n    \"family_name\": \"Doe\",\n    \"email_address\": \"john.doe@example.com\",\n    \"item_name\": \"Premium Service\",\n})\n\nprint(\"Payment successful!\")\nprint(f\"Payment ID: {result['payment'].id}\")\nprint(f\"Order ID: {result['order'].id}\")\nif result['customer']:\n    print(f\"Customer ID: {result['customer'].id}\")\n```\n"
  },
  {
    "path": "content/starlette/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Starlette ASGI framework for Python with routing, middleware, websockets, auth, and testing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.52.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"starlette,python,asgi,web,async,websockets,middleware,testing\"\n---\n\n# Starlette Python Package Guide\n\n## Golden Rule\n\nUse Starlette for ASGI application structure, but run it with an ASGI server such as `uvicorn`. `starlette` gives you the app, routing, middleware, request/response, auth, and test primitives. It is not the server process by itself.\n\n## Installation\n\n### Base install\n\n```bash\npip install starlette==0.52.1\npip install \"uvicorn[standard]\"\n```\n\n### With common optional dependencies\n\n```bash\npip install \"starlette[full]==0.52.1\"\npip install \"uvicorn[standard]\"\n```\n\n`starlette[full]` is the safest default when you expect forms, templates, sessions, or other commonly used extras.\n\n## Minimal App\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import Route\n\nasync def homepage(request):\n    return JSONResponse({\"ok\": True, \"path\": request.url.path})\n\napp = Starlette(\n    debug=False,\n    routes=[Route(\"/\", homepage)],\n)\n```\n\nRun it with:\n\n```bash\nuvicorn app:app --reload\n```\n\n## Recommended App Setup\n\nUse `lifespan=` for startup and shutdown work. In current Starlette, this is the preferred style over `on_startup` and `on_shutdown`.\n\n```python\nfrom collections.abc import AsyncIterator\nfrom contextlib import asynccontextmanager\nfrom typing import TypedDict\n\nimport httpx\nfrom starlette.applications import Starlette\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import Route\n\nclass AppState(TypedDict):\n    http_client: httpx.AsyncClient\n\n@asynccontextmanager\nasync def lifespan(app: Starlette) -> AsyncIterator[AppState]:\n    async with httpx.AsyncClient(timeout=10.0) as client:\n        yield {\"http_client\": client}\n\nasync def healthcheck(request: Request[AppState]):\n    client = request.state[\"http_client\"]\n    upstream = await client.get(\"https://example.com/health\")\n    return JSONResponse({\"status\": upstream.status_code})\n\napp = Starlette(\n    routes=[Route(\"/health\", healthcheck)],\n    lifespan=lifespan,\n)\n```\n\n## Core Usage\n\n### Routing\n\nStarlette’s routing is explicit and lightweight:\n\n```python\nfrom starlette.responses import PlainTextResponse\nfrom starlette.routing import Route\n\nasync def user_detail(request):\n    user_id = request.path_params[\"user_id\"]\n    return PlainTextResponse(f\"user={user_id}\")\n\nroutes = [\n    Route(\"/users/{user_id:int}\", user_detail, methods=[\"GET\"]),\n]\n```\n\nUse named routes plus `request.url_for(...)` when you need reverse lookups instead of hard-coding paths.\n\n### Requests and responses\n\n`Request` exposes parsed URL parts, headers, query params, cookies, body readers, and `request.state`.\n\n```python\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse\n\nasync def create_item(request: Request):\n    payload = await request.json()\n    return JSONResponse(\n        {\n            \"item\": payload,\n            \"query\": dict(request.query_params),\n            \"client\": request.client.host if request.client else None,\n        },\n        status_code=201,\n    )\n```\n\nUseful response classes:\n\n- `JSONResponse` for API payloads\n- `PlainTextResponse` and `HTMLResponse` for simple text or HTML\n- `RedirectResponse` for redirects\n- `StreamingResponse` for async generators and large streams\n- `FileResponse` for file downloads and range requests\n\n### Multipart forms and uploads\n\nStarlette’s `request.form()` supports limits for files, fields, and part size. Keep them explicit when handling uploads.\n\n```python\nasync def upload(request):\n    async with request.form(\n        max_files=20,\n        max_fields=50,\n        max_part_size=4 * 1024 * 1024,\n    ) as form:\n        uploaded = form[\"file\"]\n        contents = await uploaded.read()\n    return JSONResponse({\"bytes\": len(contents)})\n```\n\n### WebSockets\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.routing import WebSocketRoute\nfrom starlette.websockets import WebSocket, WebSocketDisconnect\n\nasync def ws_endpoint(websocket: WebSocket):\n    await websocket.accept()\n    try:\n        async for message in websocket.iter_text():\n            await websocket.send_json({\"echo\": message})\n    except WebSocketDisconnect:\n        pass\n\napp = Starlette(routes=[WebSocketRoute(\"/ws\", ws_endpoint)])\n```\n\nUse `send_json(..., mode=\"binary\")` and `receive_json(mode=\"binary\")` only if you intentionally want JSON over binary frames. Text frames are the default.\n\n## Configuration and Auth\n\n### Environment-based config\n\nStarlette ships a `Config` helper for environment variables and `.env` files.\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.config import Config\nfrom starlette.datastructures import CommaSeparatedStrings, Secret\n\nconfig = Config(\".env\")\n\nDEBUG = config(\"DEBUG\", cast=bool, default=False)\nSECRET_KEY = config(\"SECRET_KEY\", cast=Secret)\nALLOWED_HOSTS = config(\"ALLOWED_HOSTS\", cast=CommaSeparatedStrings, default=\"\")\n\napp = Starlette(debug=DEBUG)\n```\n\nRead order is: environment variable, then `.env`, then default. Keep secrets out of source control.\n\n### Sessions, host checks, CORS\n\nCommon middleware choices:\n\n- `SessionMiddleware(secret_key=...)` for signed cookie-backed sessions\n- `TrustedHostMiddleware(allowed_hosts=[...])` to reject unexpected host headers\n- `HTTPSRedirectMiddleware()` to force HTTPS\n- `CORSMiddleware(...)` for browser API access\n\nWhen `allow_credentials=True` in `CORSMiddleware`, do not use `[\"*\"]` for origins, methods, or headers. Use explicit lists.\n\nFor APIs that must return CORS headers even on unhandled 500 responses, wrap the entire application:\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.middleware.cors import CORSMiddleware\n\ninner = Starlette(routes=routes, middleware=middleware, lifespan=lifespan)\napp = CORSMiddleware(\n    app=inner,\n    allow_origins=[\"https://app.example.com\"],\n    allow_methods=[\"GET\", \"POST\"],\n    allow_headers=[\"Authorization\", \"Content-Type\"],\n    allow_credentials=True,\n)\n```\n\n### Authentication\n\nInstall `AuthenticationMiddleware` with a backend. Then use `request.user`, `request.auth`, and the `@requires(...)` decorator.\n\n```python\nimport base64\nimport binascii\n\nfrom starlette.applications import Starlette\nfrom starlette.authentication import (\n    AuthCredentials,\n    AuthenticationBackend,\n    AuthenticationError,\n    SimpleUser,\n    requires,\n)\nfrom starlette.middleware import Middleware\nfrom starlette.middleware.authentication import AuthenticationMiddleware\nfrom starlette.responses import PlainTextResponse\nfrom starlette.routing import Route\n\nclass BasicAuthBackend(AuthenticationBackend):\n    async def authenticate(self, conn):\n        if \"Authorization\" not in conn.headers:\n            return None\n\n        try:\n            scheme, credentials = conn.headers[\"Authorization\"].split()\n            if scheme.lower() != \"basic\":\n                return None\n            decoded = base64.b64decode(credentials).decode(\"ascii\")\n        except (ValueError, UnicodeDecodeError, binascii.Error) as exc:\n            raise AuthenticationError(\"Invalid basic auth credentials\") from exc\n\n        username, _, _password = decoded.partition(\":\")\n        return AuthCredentials([\"authenticated\"]), SimpleUser(username)\n\n@requires(\"authenticated\")\nasync def dashboard(request):\n    return PlainTextResponse(f\"hello {request.user.display_name}\")\n\napp = Starlette(\n    routes=[Route(\"/dashboard\", dashboard)],\n    middleware=[Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())],\n)\n```\n\nIf your auth backend raises `AuthenticationError`, provide `on_error=...` to return a consistent JSON or redirect response.\n\n## Testing\n\nUse `TestClient` for sync-style tests and keep it in a `with` block when your app has lifespan logic.\n\n```python\nfrom starlette.testclient import TestClient\n\ndef test_homepage():\n    with TestClient(app, raise_server_exceptions=True) as client:\n        response = client.get(\"/\")\n        assert response.status_code == 200\n```\n\nImportant details:\n\n- `TestClient(app)` uses `httpx` semantics.\n- Lifespan handlers only run when `TestClient` is used as a context manager.\n- `backend=\"trio\"` is supported.\n- WebSocket tests must use `with client.websocket_connect(\"/ws\") as websocket: ...`.\n- `websocket_connect()` does not support `params=`; put query params directly in the URL.\n\n## Common Pitfalls\n\n- Starlette is not the process manager or server. Run it under `uvicorn`, `hypercorn`, or another ASGI server.\n- Prefer `lifespan=` for startup and shutdown. Do not mix it with older startup/shutdown hooks in the same app.\n- `BaseHTTPMiddleware` has known `ContextVar` propagation limitations. If you depend on contextvars or need lower-level control, write pure ASGI middleware instead.\n- If you need CORS headers on error responses, wrap the whole app with `CORSMiddleware`, not only inner middleware lists.\n- Upload parsing can become a CPU and memory sink if you leave limits too broad. Set `max_files`, `max_fields`, and `max_part_size`.\n- For tests that inspect 500 responses, set `raise_server_exceptions=False`.\n- `request.state` is for app/request-scoped state, not global mutable shared state across workers.\n\n## Version-Sensitive Notes\n\n- `0.52.1` is the current PyPI release and includes a fix to only use `typing_extensions` on older Python versions.\n- `0.52.0` added dictionary-style typed access for lifespan state, so `request.state[\"http_client\"]` is now a first-class pattern.\n- `0.51.0` added `allow_private_network` to `CORSMiddleware`.\n- `0.50.0` dropped Python 3.9 support. For `0.52.1`, require Python `>=3.10`.\n- `0.49.1` fixed a security issue in `FileResponse` range header parsing. Do not copy older examples that pin earlier vulnerable releases.\n- `0.44.0` added `max_part_size` to `Request.form()`. Older code snippets may omit it.\n\n## Official Sources\n\n- Docs root: https://starlette.dev/\n- Applications: https://www.starlette.dev/applications/\n- Routing: https://www.starlette.dev/routing/\n- Requests: https://www.starlette.dev/requests/\n- Responses: https://www.starlette.dev/responses/\n- Middleware: https://www.starlette.dev/middleware/\n- Authentication: https://www.starlette.dev/authentication/\n- Lifespan: https://www.starlette.dev/lifespan/\n- TestClient: https://www.starlette.dev/testclient/\n- Release notes: https://www.starlette.dev/release-notes/\n- PyPI package page: https://pypi.org/project/starlette/\n"
  },
  {
    "path": "content/statsmodels/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"statsmodels package guide for Python statistical modeling, regression, hypothesis testing, and time series analysis\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.14.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"statsmodels,python,statistics,regression,time-series,econometrics,glm,arima\"\n---\n\n# statsmodels Python Package Guide\n\n## What It Is\n\n`statsmodels` is the main Python package for statistical modeling and inference: linear models, generalized linear models, discrete-choice models, mixed models, robust statistics, hypothesis tests, and classical time-series analysis.\n\nAgent reminders:\n\n- PyPI package name: `statsmodels`\n- Import namespace: `statsmodels`\n- Common convenience imports: `import statsmodels.api as sm` and `import statsmodels.formula.api as smf`\n- This is a local numerical/statistical library. There is no API key, service auth, or remote client setup.\n\n## Install\n\nInstall the exact version covered here:\n\n```bash\npython -m pip install \"statsmodels==0.14.6\"\n```\n\nFor a fresh scientific-Python environment, it is reasonable to install the common core stack together:\n\n```bash\npython -m pip install \"numpy\" \"scipy\" \"pandas\" \"patsy\" \"statsmodels==0.14.6\"\n```\n\nWith Conda:\n\n```bash\nconda install statsmodels\n```\n\nVerify the runtime package version before writing code against version-sensitive APIs:\n\n```bash\npython - <<'PY'\nimport statsmodels\nprint(statsmodels.__version__)\nPY\n```\n\n## Initialize And Choose An API Style\n\nMost projects use one of these import patterns:\n\n```python\nimport statsmodels.api as sm\nimport statsmodels.formula.api as smf\n```\n\nUse the **array/matrix API** when your code already has prepared `numpy` arrays or `pandas` columns:\n\n```python\nimport statsmodels.api as sm\n```\n\nUse the **formula API** when your data is in a `pandas.DataFrame` and you want Patsy formulas such as `y ~ x1 + x2 + C(group)`:\n\n```python\nimport statsmodels.formula.api as smf\n```\n\nFor time series, import directly from the relevant module or the time-series API namespace:\n\n```python\nfrom statsmodels.tsa.arima.model import ARIMA\n```\n\n## Core Usage\n\n### Ordinary Least Squares With Explicit Design Matrix\n\nFor `sm.OLS`, add the intercept yourself unless your design matrix already contains one:\n\n```python\nimport pandas as pd\nimport statsmodels.api as sm\n\ndf = pd.DataFrame(\n    {\n        \"y\": [2.2, 2.8, 3.6, 4.5, 5.1],\n        \"x1\": [1.0, 2.0, 3.0, 4.0, 5.0],\n        \"x2\": [5.0, 4.0, 3.0, 2.0, 1.0],\n    }\n)\n\nX = sm.add_constant(df[[\"x1\", \"x2\"]])\ny = df[\"y\"]\n\nmodel = sm.OLS(y, X, missing=\"raise\")\nresults = model.fit()\n\nprint(results.params)\nprint(results.rsquared)\nprint(results.summary())\n```\n\nUse `missing=\"raise\"` or clean the data before fitting. The docs explicitly warn that silent missing-data handling can produce invalid all-`NaN` parameters.\n\n### OLS With The Formula API\n\nThe formula API is usually the easiest path when your input is already a DataFrame:\n\n```python\nimport pandas as pd\nimport statsmodels.formula.api as smf\n\ndf = pd.DataFrame(\n    {\n        \"y\": [2.2, 2.8, 3.6, 4.5, 5.1],\n        \"x1\": [1.0, 2.0, 3.0, 4.0, 5.0],\n        \"group\": [\"a\", \"a\", \"b\", \"b\", \"b\"],\n    }\n)\n\nresults = smf.ols(\"y ~ x1 + C(group)\", data=df, missing=\"raise\").fit()\n\nprint(results.params)\nprint(results.conf_int())\n```\n\nFormula models include an intercept by default. Use `0 +` or `- 1` in the formula only when you intentionally want a no-intercept model.\n\n### Predictions And Robust Standard Errors\n\n```python\nrobust_results = smf.ols(\"y ~ x1\", data=df, missing=\"raise\").fit(cov_type=\"HC3\")\n\nprediction = robust_results.get_prediction(df[[\"x1\"]]).summary_frame()\nprint(prediction.head())\n```\n\nWhen you care about inference, check the covariance estimator you need instead of relying on defaults. `HC3` is a common heteroskedasticity-robust choice for linear models.\n\n### Time-Series Forecasting With ARIMA\n\n```python\nimport pandas as pd\nfrom statsmodels.tsa.arima.model import ARIMA\n\nseries = pd.Series(\n    [120, 128, 133, 142, 150, 160],\n    index=pd.date_range(\"2025-01-01\", periods=6, freq=\"MS\"),\n)\n\nmodel = ARIMA(series, order=(1, 1, 1))\nresults = model.fit()\n\nforecast = results.forecast(steps=3)\nprint(forecast)\n```\n\nFor date-based forecasting, give the series a proper datetime-like index with a frequency. Otherwise forecast output can be harder to align and interpret.\n\n## Common Modeling Surfaces\n\nUse the API reference to jump to the right family:\n\n- `sm.OLS`, `sm.WLS`, `sm.GLS`: classical linear regression\n- `sm.GLM`: generalized linear models\n- `sm.Logit`, `sm.Probit`, `sm.MNLogit`: discrete-choice models\n- `sm.MixedLM`: mixed-effects models\n- `sm.tsa`: ARIMA, state-space, exponential smoothing, seasonal decomposition, and related time-series tools\n- `sm.stats`: tests, confidence intervals, and diagnostics\n\nIf you are unsure where a model lives, start from `statsmodels.api` or the official API reference instead of guessing import paths from blog posts.\n\n## Configuration And Environment Notes\n\n## Authentication\n\nNone. `statsmodels` runs locally.\n\n## Environment And Dependencies\n\nPractical setup issues are usually about the scientific Python stack, not package-level configuration:\n\n- keep `numpy`, `scipy`, `pandas`, and `statsmodels` compatible inside one virtual environment\n- install `patsy` if you use the formula API\n- use `matplotlib` separately if your workflow needs plotting from examples or diagnostics\n- prefer wheels over source builds unless you intentionally need a local compiled build\n\nIf import errors mention binary compatibility, check the versions of `numpy`, `scipy`, and Python before debugging application code.\n\n## Common Pitfalls\n\n### Missing data defaults\n\nThe official missing-data guide shows that default handling can let `NaN` values propagate into unusable parameter estimates. Use `missing=\"raise\"` during development or clean/drop missing rows explicitly before fitting.\n\n### Forgetting the intercept in matrix-based models\n\n`sm.OLS(y, X)` does not add a constant automatically. Use `sm.add_constant(X)` unless the design matrix already includes one.\n\n### Reusing a model instance across multiple fits\n\nThe pitfalls guide warns that fitting the same model instance repeatedly with different fit arguments can invalidate result objects because some model attributes are shared. Create separate model instances when you need multiple fits for comparison.\n\n### Assuming rank-deficient or highly collinear data will raise\n\nLinear-model code may silently proceed with generalized inverses. Check diagnostics such as condition numbers, singular design matrices, and warnings when coefficients look unstable.\n\n### Treating convergence warnings as ignorable\n\nLikelihood-based models can stop without clean convergence. Check `results.mle_retvals`, warnings, and parameter plausibility before trusting output from `Logit`, `GLM`, state-space, or other iterative estimators.\n\n### Mixing stable and dev docs\n\n`statsmodels` publishes both `stable` and `dev` docs. For `0.14.6`, prefer `https://www.statsmodels.org/stable/`. The `dev` docs reflect the in-progress `0.15.x` line and are not safe as a drop-in reference for `0.14.6`.\n\n## Version-Sensitive Notes\n\n- `0.14.6` is a maintenance release in the `0.14.x` line. The official release note highlights compatibility fixes for NumPy `2.4+` and pandas `3+`.\n- PyPI currently lists Python `>=3.9` for `0.14.6`.\n- The install page still includes older prose saying current support is Python `3.8`, `3.9`, and `3.10`. Treat that as stale documentation text rather than the release requirement for `0.14.6`.\n- If you are diagnosing example differences, confirm whether the source you copied used the formula API or the matrix API. Intercept handling and categorical encoding differ between those entry points.\n\n## Official Sources\n\n- statsmodels package on PyPI: https://pypi.org/project/statsmodels/\n- statsmodels stable docs root: https://www.statsmodels.org/stable/\n- statsmodels install guide: https://www.statsmodels.org/stable/install.html\n- statsmodels getting started guide: https://www.statsmodels.org/stable/gettingstarted.html\n- statsmodels API reference: https://www.statsmodels.org/stable/api.html\n- statsmodels import paths and structure: https://www.statsmodels.org/stable/api-structure.html\n- statsmodels missing-data guide: https://www.statsmodels.org/stable/missing.html\n- statsmodels pitfalls guide: https://www.statsmodels.org/stable/pitfalls.html\n- statsmodels 0.14.6 release notes: https://www.statsmodels.org/stable/release/version0.14.6.html\n"
  },
  {
    "path": "content/strawberry-graphql/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Strawberry package guide for Python GraphQL schemas, resolvers, mutations, and ASGI or FastAPI integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.311.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"strawberry,graphql,python,asgi,fastapi,api\"\n---\n\n# Strawberry Python Package Guide\n\n## What It Is\n\nStrawberry is a Python GraphQL library that builds a schema from Python type hints and decorators. Use it when you want a code-first GraphQL API with explicit object types, input types, sync or async resolvers, and framework integrations such as ASGI and FastAPI.\n\n## Install\n\nInstall the core package and an ASGI server:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install \"strawberry-graphql==0.311.1\" \"uvicorn[standard]\"\n```\n\nIf you are mounting Strawberry inside FastAPI, install the FastAPI extra as well:\n\n```bash\npip install \"strawberry-graphql[fastapi]==0.311.1\" fastapi\n```\n\nStrawberry does not require a package-specific API key or environment variable. Keep app settings such as host, port, debug mode, and auth secrets in your framework config or `.env` file.\n\nExample local environment:\n\n```bash\nexport HOST=127.0.0.1\nexport PORT=8000\nexport RELOAD=true\n```\n\n## Minimal ASGI App\n\nThis is the smallest useful Strawberry app: define a query type, build a schema, and expose it as an ASGI application.\n\n```python\nimport os\n\nimport strawberry\nfrom strawberry.asgi import GraphQL\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def hello(self) -> str:\n        return \"Hello, world!\"\n\n\nschema = strawberry.Schema(query=Query)\ngraphql_app = GraphQL(schema)\n\n\nif __name__ == \"__main__\":\n    import uvicorn\n\n    uvicorn.run(\n        \"app:graphql_app\",\n        host=os.getenv(\"HOST\", \"127.0.0.1\"),\n        port=int(os.getenv(\"PORT\", \"8000\")),\n        reload=os.getenv(\"RELOAD\", \"\").lower() == \"true\",\n    )\n```\n\nYou can also run the same app from the shell:\n\n```bash\nuvicorn app:graphql_app --host \"$HOST\" --port \"$PORT\" --reload\n```\n\nSend a GraphQL request with a normal HTTP POST:\n\n```python\nimport os\n\nimport requests\n\n\nresponse = requests.post(\n    f\"http://{os.getenv('HOST', '127.0.0.1')}:{os.getenv('PORT', '8000')}\",\n    json={\"query\": \"{ hello }\"},\n    timeout=30,\n)\n\nprint(response.json())\n```\n\n## Define Types And Fields\n\nStrawberry uses decorators plus type hints to generate the GraphQL schema. Use `@strawberry.type` for output objects and `@strawberry.field` for resolver-backed fields.\n\n```python\nimport strawberry\nfrom strawberry.types import Info\n\n\n@strawberry.type\nclass User:\n    id: strawberry.ID\n    name: str\n\n\nUSERS = {\n    \"1\": User(id=\"1\", name=\"Ada\"),\n    \"2\": User(id=\"2\", name=\"Linus\"),\n}\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def user(self, info: Info, id: strawberry.ID) -> User | None:\n        return USERS.get(str(id))\n\n\nschema = strawberry.Schema(query=Query)\n```\n\nExample query:\n\n```graphql\nquery GetUser($id: ID!) {\n  user(id: $id) {\n    id\n    name\n  }\n}\n```\n\nVariables:\n\n```json\n{\n  \"id\": \"1\"\n}\n```\n\n## Mutations And Input Types\n\nUse `@strawberry.input` for GraphQL input objects and `@strawberry.mutation` for write operations.\n\n```python\nimport strawberry\n\n\n@strawberry.type\nclass User:\n    id: strawberry.ID\n    name: str\n\n\n@strawberry.input\nclass CreateUserInput:\n    name: str\n\n\nUSERS: dict[str, User] = {}\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def users(self) -> list[User]:\n        return list(USERS.values())\n\n\n@strawberry.type\nclass Mutation:\n    @strawberry.mutation\n    def create_user(self, input: CreateUserInput) -> User:\n        user_id = str(len(USERS) + 1)\n        user = User(id=user_id, name=input.name)\n        USERS[user_id] = user\n        return user\n\n\nschema = strawberry.Schema(query=Query, mutation=Mutation)\n```\n\nExample mutation:\n\n```graphql\nmutation CreateUser($input: CreateUserInput!) {\n  createUser(input: $input) {\n    id\n    name\n  }\n}\n```\n\nVariables:\n\n```json\n{\n  \"input\": {\n    \"name\": \"Grace\"\n  }\n}\n```\n\n## Async Resolvers\n\nResolvers can be synchronous or asynchronous. Use `async def` when the resolver awaits database or network work.\n\n```python\nfrom datetime import datetime, timezone\n\nimport strawberry\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    async def server_time(self) -> str:\n        return datetime.now(timezone.utc).isoformat()\n\n\nschema = strawberry.Schema(query=Query)\n```\n\nKeep blocking I/O out of async resolvers. If your database client or SDK is synchronous, either keep the resolver synchronous too or move the blocking call behind an executor or framework-specific background strategy.\n\n## FastAPI Integration And Request Context\n\nUse `GraphQLRouter` when Strawberry lives inside a FastAPI app. Put request-scoped auth and other per-request values into the GraphQL context instead of module globals.\n\n```python\nfrom fastapi import FastAPI, Request\nimport strawberry\nfrom strawberry.fastapi import GraphQLRouter\nfrom strawberry.types import Info\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def viewer(self, info: Info) -> str:\n        return info.context[\"user_id\"] or \"anonymous\"\n\n\nasync def get_context(request: Request) -> dict[str, object]:\n    auth_header = request.headers.get(\"authorization\")\n    user_id = None\n\n    if auth_header and auth_header.startswith(\"Bearer \"):\n        user_id = auth_header.removeprefix(\"Bearer \").strip()\n\n    return {\n        \"request\": request,\n        \"user_id\": user_id,\n    }\n\n\nschema = strawberry.Schema(query=Query)\ngraphql_router = GraphQLRouter(schema, context_getter=get_context)\n\napp = FastAPI()\napp.include_router(graphql_router, prefix=\"/graphql\")\n```\n\nCall the mounted FastAPI endpoint with the same GraphQL JSON body format:\n\n```python\nimport requests\n\n\nresponse = requests.post(\n    \"http://127.0.0.1:8000/graphql\",\n    headers={\"Authorization\": \"Bearer user-123\"},\n    json={\"query\": \"{ viewer }\"},\n    timeout=30,\n)\n\nprint(response.json())\n```\n\n## Common Pitfalls\n\n- Install the matching integration extra before importing framework adapters such as `strawberry.fastapi`.\n- Use `@strawberry.input` for mutation inputs. `@strawberry.type` defines output object types.\n- Keep request data in `info.context` rather than using module-level globals for auth or tenant state.\n- Treat Python type hints as part of the public GraphQL contract. Changing a field type changes the schema your clients see.\n- Mount paths matter. If you include the router at `/graphql`, clients must post to `/graphql`, not `/`.\n- Mix sync and async resolvers deliberately. Do not block the event loop inside `async def` resolvers.\n\n## When To Reach For More Docs\n\nThe official Strawberry docs also cover subscriptions, schema configuration, framework-specific integrations, Django support, and testing patterns. Use those sections when you need features beyond a basic query or mutation API.\n"
  },
  {
    "path": "content/streamlit/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Streamlit package guide for Python apps with installation, execution flow, configuration, connections, and auth\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.55.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"streamlit,python,web,ui,dashboard,data-app,chat\"\n---\n\n# Streamlit Python Package Guide\n\n## Golden Rule\n\nUse `streamlit` for Python-first interactive apps, run the app with the Streamlit CLI instead of `python app.py`, and design with Streamlit's rerun model in mind. Every widget interaction reruns your script unless you deliberately batch work with forms or isolate work with fragments.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"streamlit==1.55.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"streamlit==1.55.0\"\npoetry add \"streamlit==1.55.0\"\n```\n\nUseful CLI commands from the official docs:\n\n```bash\nstreamlit hello\nstreamlit config show\nstreamlit version\n```\n\nIf you want Streamlit to scaffold a new app:\n\n```bash\nstreamlit init\n```\n\n## Create And Run An App\n\nMinimal app:\n\n```python\nimport streamlit as st\n\nst.set_page_config(\n    page_title=\"Demo\",\n    page_icon=\":material/rocket_launch:\",\n    layout=\"wide\",\n)\n\nst.title(\"Hello, Streamlit\")\nname = st.text_input(\"Name\", value=\"Ada\")\n\nif st.button(\"Greet\"):\n    st.success(f\"Hello, {name}!\")\n```\n\nRun it:\n\n```bash\nstreamlit run app.py\n```\n\nNotes:\n\n- If you run `streamlit run` with no file argument, Streamlit looks for `streamlit_app.py` in the current working directory.\n- Your working directory matters because `.streamlit/config.toml` and `.streamlit/secrets.toml` are resolved relative to wherever you call `streamlit run`.\n- `streamlit run` also accepts a directory; in that case Streamlit looks for `streamlit_app.py` inside that directory.\n\n## Core Usage Patterns\n\n### 1. Accept the rerun model\n\nBy default, Streamlit reruns the whole script on each interaction. This is normal, not a bug.\n\nUse these tools when reruns become expensive or awkward:\n\n- `st.form` to batch related widget updates behind a submit button\n- `st.fragment` to rerun only part of the app\n- `st.rerun()` to trigger an immediate rerun\n- `st.stop()` to end the current run early\n\nExample with a form:\n\n```python\nimport streamlit as st\n\nwith st.form(\"filters\"):\n    city = st.text_input(\"City\")\n    limit = st.number_input(\"Rows\", min_value=1, max_value=100, value=10)\n    submitted = st.form_submit_button(\"Apply\")\n\nif submitted:\n    st.write({\"city\": city, \"limit\": limit})\n```\n\nExample with an independently rerunning fragment:\n\n```python\nimport streamlit as st\nimport pandas as pd\nimport numpy as np\n\n@st.fragment(run_every=\"10s\")\ndef live_chart() -> None:\n    df = pd.DataFrame(np.random.randn(20, 3), columns=[\"a\", \"b\", \"c\"])\n    st.line_chart(df)\n\nlive_chart()\n```\n\n### 2. Keep per-user state in `st.session_state`\n\nUse Session State for values that must survive reruns for one user session.\n\n```python\nimport streamlit as st\n\nif \"messages\" not in st.session_state:\n    st.session_state.messages = []\n\nprompt = st.chat_input(\"Say something\")\nif prompt:\n    st.session_state.messages.append({\"role\": \"user\", \"text\": prompt})\n\nfor message in st.session_state.messages:\n    with st.chat_message(message[\"role\"]):\n        st.write(message[\"text\"])\n```\n\nImportant behavior:\n\n- Session State persists across reruns and across pages in a multipage app.\n- Session State is tied to the WebSocket session, so a browser reload or Markdown-link navigation resets it.\n- Inside forms, only `st.form_submit_button` supports callbacks.\n- Do not mutate a widget's value through Session State after that widget has already been instantiated in the same run.\n\n### 3. Cache data and resources intentionally\n\nUse `@st.cache_data` for data results that should be copied per caller:\n\n```python\nimport streamlit as st\nimport pandas as pd\n\n@st.cache_data(ttl=\"10m\")\ndef load_csv(path: str) -> pd.DataFrame:\n    return pd.read_csv(path)\n```\n\nUse `@st.cache_resource` for shared global resources such as clients, engines, or models:\n\n```python\nimport streamlit as st\nfrom sqlalchemy import create_engine\n\n@st.cache_resource\ndef get_engine():\n    return create_engine(st.secrets.database.url)\n```\n\nRules that matter in practice:\n\n- `@st.cache_data` stores return values in pickled form, so returns must be pickleable.\n- `@st.cache_resource` returns shared objects and those objects must be thread-safe if they are global.\n- If an argument should not participate in cache hashing, prefix that parameter name with `_`.\n- Widgets inside cached functions are supported but still experimental and can create excessive cache growth.\n- Async objects are not a safe caching target; keep cached values sync-friendly.\n\n### 4. Use Streamlit-native UI and data primitives\n\nThe practical center of most apps is:\n\n- display: `st.write`, `st.markdown`, `st.dataframe`, `st.metric`, `st.json`\n- input: `st.text_input`, `st.selectbox`, `st.multiselect`, `st.slider`, `st.file_uploader`, `st.chat_input`\n- layout: `st.sidebar`, `st.columns`, `st.tabs`, `st.expander`, `st.container`, `st.popover`\n- long-running work: `st.spinner`, `st.status`, `st.progress`, `st.toast`\n\nFor LLM or assistant-style apps, the native chat elements are usually the right default:\n\n```python\nimport streamlit as st\n\nwith st.chat_message(\"assistant\"):\n    st.write(\"How can I help?\")\n\nprompt = st.chat_input(\"Ask a question\")\nif prompt:\n    with st.chat_message(\"user\"):\n        st.write(prompt)\n```\n\n### 5. Prefer built-in navigation for multipage apps\n\nModern multipage apps should prefer `st.Page` and `st.navigation` in the entrypoint file:\n\n```python\nimport streamlit as st\n\ndef home():\n    st.title(\"Home\")\n\ndef reports():\n    st.title(\"Reports\")\n\npage = st.navigation(\n    [\n        st.Page(home, title=\"Home\", icon=\":material/home:\", default=True),\n        st.Page(reports, title=\"Reports\", icon=\":material/assessment:\"),\n    ],\n    position=\"sidebar\",\n)\n\npage.run()\n```\n\nImportant behavior:\n\n- The entrypoint file becomes a router and reruns on every app interaction.\n- Once any session executes `st.navigation`, the app ignores the `pages/` directory across all sessions.\n- In `1.55.0`, `st.Page` adds a `visibility` parameter so pages can be hidden from navigation while staying routable.\n\n## Configuration, Secrets, And Connections\n\n### `config.toml`\n\nPer-project config lives at `.streamlit/config.toml` in the working directory:\n\n```toml\n[server]\nport = 8501\nheadless = true\nmaxUploadSize = 400\n\n[theme]\nprimaryColor = \"#ff4b4b\"\nbase = \"light\"\n```\n\nGlobal config lives at `~/.streamlit/config.toml`.\n\nPrecedence is:\n\n1. CLI flags like `--server.port=8502`\n2. `STREAMLIT_*` environment variables\n3. Per-project `.streamlit/config.toml`\n4. Global `~/.streamlit/config.toml`\n\nUseful facts:\n\n- Theme changes in `config.toml` apply live while the app is running.\n- Non-theme config changes usually require a server restart.\n- `streamlit config show` prints available config keys and current values.\n- `server.maxUploadSize` defaults to 200 MB unless you raise it.\n\n### `secrets.toml`\n\nPer-project secrets live at `.streamlit/secrets.toml`:\n\n```toml\nOPENAI_API_KEY = \"...\"\n\n[database]\nurl = \"sqlite:///app.db\"\n\n[connections.analytics]\nurl = \"postgresql+psycopg://user:pass@host/db\"\n```\n\nAccess them from code:\n\n```python\nimport streamlit as st\n\napi_key = st.secrets[\"OPENAI_API_KEY\"]\ndb_url = st.secrets.database.url\n```\n\nGlobal secrets live at `~/.streamlit/secrets.toml`. Project secrets override duplicate global keys.\n\n### `st.connection`\n\nUse `st.connection()` when a built-in or custom connection fits your data source:\n\n```python\nimport streamlit as st\n\nconn = st.connection(\"analytics\", type=\"sql\")\ndf = conn.query(\"select * from events limit 50\")\nst.dataframe(df)\n```\n\nNotes:\n\n- Streamlit reads connection secrets from `[connections.<name>]` in `secrets.toml`.\n- Returned connections are internally cached with `st.cache_resource`.\n- Built-in connection types include SQL and Snowflake.\n\n## Authentication\n\nStreamlit has native OIDC auth. For package version `1.55.0`, the relevant API is `st.login()`, `st.user`, and `st.logout()`.\n\nInstall the auth extra when needed:\n\n```bash\npython -m pip install \"streamlit[auth]==1.55.0\"\n```\n\nOr install the required dependency directly:\n\n```bash\npython -m pip install \"Authlib>=1.3.2\"\n```\n\nExample `.streamlit/secrets.toml`:\n\n```toml\n[auth]\nredirect_uri = \"http://localhost:8501/oauth2callback\"\ncookie_secret = \"replace-with-a-long-random-value\"\nclient_id = \"your-client-id\"\nclient_secret = \"your-client-secret\"\nserver_metadata_url = \"https://accounts.google.com/.well-known/openid-configuration\"\n```\n\nExample app code:\n\n```python\nimport streamlit as st\n\nif not st.user.is_logged_in:\n    if st.button(\"Log in\"):\n        st.login()\nelse:\n    st.write(f\"Signed in as {st.user.name}\")\n    if st.button(\"Log out\"):\n        st.logout()\n```\n\nAuth constraints that matter:\n\n- Streamlit supports OIDC providers, not generic OAuth providers.\n- `redirect_uri` and `cookie_secret` are required in `[auth]`.\n- URLs in auth settings must be absolute.\n- Auth is not supported for embedded apps.\n- The identity cookie lasts 30 days if the user closes the app without logging out.\n- `st.user` is read at session start, so other open tabs will not update until they start a new session.\n\n## Common Pitfalls\n\n- Do not launch a Streamlit app with `python app.py`. Use `streamlit run`.\n- Do not assume widgets mutate state in place. They trigger reruns and you must rebuild the UI from current state.\n- Do not put non-thread-safe global clients inside `@st.cache_resource`.\n- Do not store secrets in code or commit `.streamlit/secrets.toml`.\n- Do not expect Session State to survive browser reloads or Markdown-link navigation.\n- Do not mix older `pages/` directory routing with `st.navigation` and expect both to be active.\n- Do not copy old examples that use `st.experimental_user` or `st.experimental_*_query_params`; those are removed in current releases.\n- If a widget change should not rerun expensive work immediately, move the widgets into `st.form` or isolate the expensive section in `st.fragment`.\n- `st.file_uploader` and `st.camera_input` are not supported inside cached functions.\n\n## Version-Sensitive Notes For `1.55.0`\n\n- PyPI lists `streamlit 1.55.0` as released on March 3, 2026.\n- `1.55.0` adds dynamic container reruns: `st.tabs`, `st.popover`, and `st.expander` can use `on_change` so open and close events can trigger reruns.\n- `1.55.0` adds widget binding so most non-trigger widgets can use a `bind` parameter to sync more directly with query parameters.\n- `st.Page` in `1.55.0` adds `visibility`, which is useful for hidden-but-routable pages.\n- Since `1.54.0`, `st.experimental_user` is removed. Use `st.user`.\n- Since `1.54.0`, `st.experimental_get_query_params` and `st.experimental_set_query_params` are removed. Use `st.query_params`.\n- Since modern `1.4x+` releases, `st.set_page_config()` is additive and can be called multiple times. Older blog posts that require a single first call are outdated.\n- Since `1.51.0`, Python 3.9 is no longer supported. `1.55.0` requires Python 3.10+.\n\n## Official Sources\n\n- Streamlit API reference: `https://docs.streamlit.io/develop/api-reference`\n- Installation guide: `https://docs.streamlit.io/get-started/installation`\n- CLI reference: `https://docs.streamlit.io/develop/api-reference/cli`\n- Release notes: `https://docs.streamlit.io/develop/quick-reference/release-notes/2026`\n- PyPI package page: `https://pypi.org/project/streamlit/`\n"
  },
  {
    "path": "content/stripe/docs/api/DOC.md",
    "content": "---\nname: api\ndescription: \"Payment processing platform with comprehensive payment and billing features including Payment Intents, Subscriptions, Checkout, customer management, webhooks, and Connect for marketplaces\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.1.0\"\n  revision: 1\n  updated-on: \"2025-10-28\"\n  source: maintainer\n  tags: \"stripe,api,payments,billing\"\n---\n# Stripe API Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Stripe SDK packages:**\n- Server-side: `stripe` (Node.js library for Stripe API)\n- Client-side: `@stripe/stripe-js` (ES module for browser)\n- React: `@stripe/react-stripe-js` (React components and hooks)\n\n**Never use deprecated or unofficial libraries.** These are the only supported Stripe packages maintained by Stripe, Inc.\n\n**Current SDK Version:** v19.1.0 (Node.js server library)\n\n**API Version:** Stripe uses date-based API versioning (e.g., 2025-02-24). Your account is automatically pinned to the API version from your first request. You can override this per-request or upgrade in the Stripe Dashboard.\n\n## 2. Installation\n\n### Server-Side (Node.js)\n\n```bash\nnpm install stripe\n```\n\n```bash\nyarn add stripe\n```\n\n```bash\npnpm add stripe\n```\n\n**Requirements:** Node.js 16+ (support for Node 16 is deprecated; use Node 18+ for production)\n\n### Client-Side (Browser)\n\n```bash\nnpm install @stripe/stripe-js\n```\n\n```bash\nyarn add @stripe/stripe-js\n```\n\n### React Applications\n\n```bash\nnpm install @stripe/stripe-js @stripe/react-stripe-js\n```\n\n```bash\nyarn add @stripe/stripe-js @stripe/react-stripe-js\n```\n\n### Environment Variables\n\n```bash\n# Required\nSTRIPE_SECRET_KEY=sk_test_51H...  # Server-side only, NEVER expose in browser\nSTRIPE_PUBLISHABLE_KEY=pk_test_51H...  # Safe for client-side use\n\n# Optional\nSTRIPE_WEBHOOK_SECRET=whsec_...  # For webhook signature verification\nSTRIPE_API_VERSION=2025-02-24  # Override default API version\n```\n\n**CRITICAL:** Never commit secret keys to version control. Use environment variables or secure secret management systems.\n\n## 3. Initialization\n\n### Server-Side Initialization (Node.js)\n\n```javascript\nconst Stripe = require('stripe');\nconst stripe = Stripe(process.env.STRIPE_SECRET_KEY);\n```\n\n**With TypeScript:**\n\n```typescript\nimport Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {\n  apiVersion: '2025-02-24',\n});\n```\n\n**Advanced Configuration:**\n\n```javascript\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {\n  apiVersion: '2025-02-24',\n  maxNetworkRetries: 2,\n  timeout: 80000, // 80 seconds\n  telemetry: true,\n  appInfo: {\n    name: 'MyApp',\n    version: '1.0.0',\n    url: 'https://myapp.com',\n  },\n});\n```\n\n### Client-Side Initialization (Browser)\n\n```javascript\nimport { loadStripe } from '@stripe/stripe-js';\n\n// Load Stripe.js asynchronously\nconst stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);\n\n// Later, when you need to use it\nconst stripe = await stripePromise;\n```\n\n**Advanced Loading Options:**\n\n```javascript\nconst stripePromise = loadStripe(\n  process.env.STRIPE_PUBLISHABLE_KEY,\n  {\n    locale: 'en',\n    betas: ['some_beta_feature'],\n    apiVersion: '2025-02-24',\n  }\n);\n```\n\n### React Initialization\n\n```javascript\nimport { Elements } from '@stripe/react-stripe-js';\nimport { loadStripe } from '@stripe/stripe-js';\n\nconst stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);\n\nfunction App() {\n  return (\n    <Elements stripe={stripePromise}>\n      {/* Your payment components here */}\n    </Elements>\n  );\n}\n```\n\n**With Options:**\n\n```javascript\nfunction App() {\n  const options = {\n    mode: 'payment',\n    amount: 1099,\n    currency: 'usd',\n    appearance: {\n      theme: 'stripe',\n      variables: {\n        colorPrimary: '#0570de',\n      },\n    },\n  };\n\n  return (\n    <Elements stripe={stripePromise} options={options}>\n      <CheckoutForm />\n    </Elements>\n  );\n}\n```\n\n## 4. Core API Surfaces\n\n### Payment Intents\n\nPayment Intents are the recommended way to handle payments. They track the entire payment lifecycle and support Strong Customer Authentication (SCA).\n\n**Minimal Server-Side Example:**\n\n```javascript\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 1099, // Amount in cents ($10.99)\n  currency: 'usd',\n  payment_method_types: ['card'],\n});\n\n// Send clientSecret to client\nres.json({ clientSecret: paymentIntent.client_secret });\n```\n\n**Advanced Server-Side Example:**\n\n```javascript\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 2000,\n  currency: 'usd',\n  payment_method_types: ['card', 'us_bank_account'],\n  customer: 'cus_123456789',\n  description: 'Software subscription',\n  metadata: {\n    order_id: '6735',\n    customer_email: 'customer@example.com',\n  },\n  statement_descriptor: 'MYCOMPANY SUB',\n  receipt_email: 'customer@example.com',\n  automatic_payment_methods: {\n    enabled: true,\n    allow_redirects: 'never',\n  },\n  capture_method: 'manual', // For later capture\n});\n```\n\n**Client-Side Confirmation (React):**\n\n```javascript\nimport { PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';\n\nfunction CheckoutForm({ clientSecret }) {\n  const stripe = useStripe();\n  const elements = useElements();\n\n  const handleSubmit = async (event) => {\n    event.preventDefault();\n\n    if (!stripe || !elements) {\n      return;\n    }\n\n    const { error, paymentIntent } = await stripe.confirmPayment({\n      elements,\n      confirmParams: {\n        return_url: 'https://example.com/order/complete',\n      },\n      redirect: 'if_required',\n    });\n\n    if (error) {\n      console.error(error.message);\n    } else if (paymentIntent.status === 'succeeded') {\n      console.log('Payment successful!');\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <PaymentElement />\n      <button disabled={!stripe}>Submit</button>\n    </form>\n  );\n}\n```\n\n**Vanilla JavaScript Confirmation:**\n\n```javascript\nconst stripe = await stripePromise;\n\nconst { error, paymentIntent } = await stripe.confirmCardPayment(\n  clientSecret,\n  {\n    payment_method: {\n      card: cardElement,\n      billing_details: {\n        name: 'John Doe',\n        email: 'john@example.com',\n      },\n    },\n  }\n);\n\nif (error) {\n  console.error(error.message);\n} else if (paymentIntent.status === 'succeeded') {\n  console.log('Payment successful!');\n}\n```\n\n### Checkout Sessions\n\nStripe Checkout provides a pre-built, hosted payment page.\n\n**Minimal Server-Side Example:**\n\n```javascript\nconst session = await stripe.checkout.sessions.create({\n  line_items: [\n    {\n      price_data: {\n        currency: 'usd',\n        product_data: {\n          name: 'T-shirt',\n        },\n        unit_amount: 2000,\n      },\n      quantity: 1,\n    },\n  ],\n  mode: 'payment',\n  success_url: 'https://example.com/success',\n  cancel_url: 'https://example.com/cancel',\n});\n\n// Redirect to Checkout\nres.redirect(303, session.url);\n```\n\n**Advanced Server-Side Example:**\n\n```javascript\nconst session = await stripe.checkout.sessions.create({\n  line_items: [\n    {\n      price: 'price_1234567890', // Existing price ID\n      quantity: 2,\n    },\n  ],\n  mode: 'payment',\n  customer: 'cus_123456789',\n  customer_email: 'customer@example.com',\n  client_reference_id: 'order_12345',\n  success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',\n  cancel_url: 'https://example.com/cancel',\n  automatic_tax: { enabled: true },\n  allow_promotion_codes: true,\n  billing_address_collection: 'required',\n  shipping_address_collection: {\n    allowed_countries: ['US', 'CA'],\n  },\n  payment_method_types: ['card', 'us_bank_account'],\n  metadata: {\n    order_id: '6735',\n  },\n  invoice_creation: {\n    enabled: true,\n  },\n});\n```\n\n**Client-Side Redirect:**\n\n```javascript\nimport { loadStripe } from '@stripe/stripe-js';\n\nconst stripe = await loadStripe(publishableKey);\n\n// Redirect to Checkout\nconst { error } = await stripe.redirectToCheckout({\n  sessionId: session.id,\n});\n\nif (error) {\n  console.error(error.message);\n}\n```\n\n### Customers\n\nCustomers represent your users in Stripe.\n\n**Minimal Example:**\n\n```javascript\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n});\n```\n\n**Advanced Example:**\n\n\n```javascript\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n  name: 'John Doe',\n  phone: '+15555551234',\n  description: 'Premium customer',\n  metadata: {\n    user_id: 'user_12345',\n    plan: 'premium',\n  },\n  address: {\n    line1: '510 Townsend St',\n    city: 'San Francisco',\n    state: 'CA',\n    postal_code: '94103',\n    country: 'US',\n  },\n  payment_method: 'pm_card_visa',\n  invoice_settings: {\n    default_payment_method: 'pm_card_visa',\n  },\n});\n```\n\n**Retrieve and Update:**\n\n```javascript\n// Retrieve customer\nconst customer = await stripe.customers.retrieve('cus_123456789');\n\n// Update customer\nconst updatedCustomer = await stripe.customers.update('cus_123456789', {\n  metadata: { vip: 'true' },\n  email: 'newemail@example.com',\n});\n\n// List customers\nconst customers = await stripe.customers.list({\n  limit: 100,\n  email: 'customer@example.com',\n});\n```\n\n**Attach Payment Method to Customer:**\n\n```javascript\nconst paymentMethod = await stripe.paymentMethods.attach(\n  'pm_card_visa',\n  { customer: 'cus_123456789' }\n);\n\n// Set as default payment method\nawait stripe.customers.update('cus_123456789', {\n  invoice_settings: {\n    default_payment_method: 'pm_card_visa',\n  },\n});\n```\n\n### Subscriptions\n\nSubscriptions bill customers on a recurring basis.\n\n**Minimal Example:**\n\n```javascript\nconst subscription = await stripe.subscriptions.create({\n  customer: 'cus_123456789',\n  items: [\n    { price: 'price_1234567890' },\n  ],\n});\n```\n\n**Advanced Example:**\n\n```javascript\nconst subscription = await stripe.subscriptions.create({\n  customer: 'cus_123456789',\n  items: [\n    {\n      price: 'price_1234567890',\n      quantity: 1,\n    },\n  ],\n  payment_behavior: 'default_incomplete',\n  payment_settings: {\n    payment_method_types: ['card', 'us_bank_account'],\n    save_default_payment_method: 'on_subscription',\n  },\n  expand: ['latest_invoice.payment_intent'],\n  trial_period_days: 14,\n  metadata: {\n    user_id: 'user_12345',\n  },\n  proration_behavior: 'create_prorations',\n  billing_cycle_anchor_config: {\n    day_of_month: 1,\n  },\n  automatic_tax: {\n    enabled: true,\n  },\n});\n\n// Return client secret for payment confirmation\nconst clientSecret = subscription.latest_invoice.payment_intent.client_secret;\n```\n\n**Update Subscription:**\n\n```javascript\nconst updatedSubscription = await stripe.subscriptions.update(\n  'sub_1234567890',\n  {\n    items: [\n      {\n        id: 'si_1234567890',\n        price: 'price_new_plan',\n      },\n    ],\n    proration_behavior: 'always_invoice',\n  }\n);\n```\n\n**Cancel Subscription:**\n\n```javascript\n// Cancel at period end\nconst subscription = await stripe.subscriptions.update('sub_1234567890', {\n  cancel_at_period_end: true,\n});\n\n// Cancel immediately\nconst canceledSubscription = await stripe.subscriptions.cancel('sub_1234567890');\n```\n\n### Products and Prices\n\nProducts represent what you sell, Prices define how you charge for products.\n\n**Create Product:**\n\n```javascript\nconst product = await stripe.products.create({\n  name: 'Premium Subscription',\n  description: 'Access to all premium features',\n  metadata: {\n    category: 'subscription',\n  },\n});\n```\n\n**Create Price (One-Time):**\n\n```javascript\nconst price = await stripe.prices.create({\n  product: 'prod_1234567890',\n  unit_amount: 2000,\n  currency: 'usd',\n});\n```\n\n**Create Price (Recurring):**\n\n```javascript\nconst recurringPrice = await stripe.prices.create({\n  product: 'prod_1234567890',\n  unit_amount: 1500,\n  currency: 'usd',\n  recurring: {\n    interval: 'month',\n    interval_count: 1,\n    usage_type: 'licensed',\n  },\n  billing_scheme: 'per_unit',\n  tax_behavior: 'exclusive',\n});\n```\n\n**Advanced Pricing (Tiered):**\n\n```javascript\nconst tieredPrice = await stripe.prices.create({\n  product: 'prod_1234567890',\n  currency: 'usd',\n  recurring: {\n    interval: 'month',\n    usage_type: 'metered',\n  },\n  billing_scheme: 'tiered',\n  tiers_mode: 'graduated',\n  tiers: [\n    {\n      up_to: 10,\n      unit_amount: 1000,\n    },\n    {\n      up_to: 100,\n      unit_amount: 800,\n    },\n    {\n      up_to: 'inf',\n      unit_amount: 500,\n    },\n  ],\n});\n```\n\n### Payment Methods\n\nPayment Methods represent customer payment details.\n\n**Create Payment Method (Server-Side):**\n\n```javascript\nconst paymentMethod = await stripe.paymentMethods.create({\n  type: 'card',\n  card: {\n    token: 'tok_visa',\n  },\n});\n```\n\n**Create Payment Method (Client-Side with Elements):**\n\n```javascript\nconst stripe = await stripePromise;\nconst elements = stripe.elements();\nconst cardElement = elements.create('card');\ncardElement.mount('#card-element');\n\n// When form is submitted\nconst { error, paymentMethod } = await stripe.createPaymentMethod({\n  type: 'card',\n  card: cardElement,\n  billing_details: {\n    name: 'John Doe',\n    email: 'john@example.com',\n  },\n});\n\nif (error) {\n  console.error(error.message);\n} else {\n  console.log('PaymentMethod created:', paymentMethod.id);\n}\n```\n\n**List Customer Payment Methods:**\n\n```javascript\nconst paymentMethods = await stripe.paymentMethods.list({\n  customer: 'cus_123456789',\n  type: 'card',\n});\n```\n\n**Detach Payment Method:**\n\n```javascript\nconst detachedPM = await stripe.paymentMethods.detach('pm_1234567890');\n```\n\n### Refunds\n\n**Create Refund:**\n\n```javascript\n// Full refund\nconst refund = await stripe.refunds.create({\n  payment_intent: 'pi_1234567890',\n});\n\n// Partial refund\nconst partialRefund = await stripe.refunds.create({\n  payment_intent: 'pi_1234567890',\n  amount: 500, // Refund $5.00 of original charge\n  reason: 'requested_by_customer',\n  metadata: {\n    reason_detail: 'Customer changed mind',\n  },\n});\n```\n\n**Retrieve Refund:**\n\n```javascript\nconst refund = await stripe.refunds.retrieve('re_1234567890');\n```\n\n### Webhooks\n\nWebhooks notify your application when events occur in your Stripe account.\n\n**Setup Webhook Endpoint (Express.js):**\n\n```javascript\nconst express = require('express');\nconst app = express();\n\n// CRITICAL: Use raw body for webhook signature verification\napp.post(\n  '/webhook',\n  express.raw({ type: 'application/json' }),\n  async (req, res) => {\n    const sig = req.headers['stripe-signature'];\n    const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;\n\n    let event;\n\n    try {\n      event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n    } catch (err) {\n      console.error(`Webhook signature verification failed: ${err.message}`);\n      return res.status(400).send(`Webhook Error: ${err.message}`);\n    }\n\n    // Handle the event\n    switch (event.type) {\n      case 'payment_intent.succeeded':\n        const paymentIntent = event.data.object;\n        console.log('PaymentIntent succeeded:', paymentIntent.id);\n        // Fulfill the order\n        break;\n      case 'payment_intent.payment_failed':\n        const failedPayment = event.data.object;\n        console.log('Payment failed:', failedPayment.id);\n        // Notify customer\n        break;\n      case 'customer.subscription.created':\n        const subscription = event.data.object;\n        console.log('Subscription created:', subscription.id);\n        break;\n      case 'customer.subscription.updated':\n        const updatedSub = event.data.object;\n        console.log('Subscription updated:', updatedSub.id);\n        break;\n      case 'customer.subscription.deleted':\n        const canceledSub = event.data.object;\n        console.log('Subscription canceled:', canceledSub.id);\n        break;\n      default:\n        console.log(`Unhandled event type ${event.type}`);\n    }\n\n    res.json({ received: true });\n  }\n);\n```\n\n**Advanced Webhook Handling:**\n\n```javascript\napp.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {\n  const sig = req.headers['stripe-signature'];\n  const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;\n\n  let event;\n\n  try {\n    event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n  } catch (err) {\n    console.error(`Webhook Error: ${err.message}`);\n    return res.status(400).send(`Webhook Error: ${err.message}`);\n  }\n\n  // Handle event asynchronously to respond quickly\n  processWebhookEvent(event)\n    .then(() => console.log('Event processed successfully'))\n    .catch((err) => console.error('Event processing failed:', err));\n\n  // Respond immediately\n  res.json({ received: true });\n});\n\nasync function processWebhookEvent(event) {\n  const eventData = event.data.object;\n\n  switch (event.type) {\n    case 'checkout.session.completed':\n      const session = eventData;\n      // Fulfill order based on session\n      if (session.mode === 'payment') {\n        await fulfillOrder(session);\n      } else if (session.mode === 'subscription') {\n        await activateSubscription(session);\n      }\n      break;\n\n    case 'invoice.paid':\n      // Handle successful payment of invoice\n      await handleInvoicePaid(eventData);\n      break;\n\n    case 'invoice.payment_failed':\n      // Handle failed payment\n      await notifyCustomerPaymentFailed(eventData);\n      break;\n\n    default:\n      console.log(`Unhandled event type: ${event.type}`);\n  }\n}\n```\n\n### Invoices\n\n**Create Invoice:**\n\n```javascript\n// Create invoice item\nawait stripe.invoiceItems.create({\n  customer: 'cus_123456789',\n  amount: 2500,\n  currency: 'usd',\n  description: 'One-time setup fee',\n});\n\n// Create and finalize invoice\nconst invoice = await stripe.invoices.create({\n  customer: 'cus_123456789',\n  auto_advance: true, // Auto-finalize\n  collection_method: 'charge_automatically',\n});\n\n// Finalize invoice (if not auto-advance)\nconst finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id);\n\n// Pay invoice\nconst paidInvoice = await stripe.invoices.pay(invoice.id);\n```\n\n### Customer Portal\n\nThe Customer Portal allows customers to manage their subscription and billing information.\n\n**Create Portal Session:**\n\n```javascript\nconst portalSession = await stripe.billingPortal.sessions.create({\n  customer: 'cus_123456789',\n  return_url: 'https://example.com/account',\n});\n\n// Redirect customer to portal\nres.redirect(303, portalSession.url);\n```\n\n**Advanced Portal Configuration:**\n\n```javascript\n// Create a portal configuration\nconst configuration = await stripe.billingPortal.configurations.create({\n  business_profile: {\n    headline: 'Manage your subscription',\n  },\n  features: {\n    customer_update: {\n      enabled: true,\n      allowed_updates: ['email', 'address', 'shipping', 'phone', 'tax_id'],\n    },\n    invoice_history: {\n      enabled: true,\n    },\n    payment_method_update: {\n      enabled: true,\n    },\n    subscription_cancel: {\n      enabled: true,\n      mode: 'at_period_end',\n      cancellation_reason: {\n        enabled: true,\n        options: [\n          'too_expensive',\n          'missing_features',\n          'switched_service',\n          'unused',\n          'other',\n        ],\n      },\n    },\n    subscription_update: {\n      enabled: true,\n      default_allowed_updates: ['price', 'quantity', 'promotion_code'],\n      proration_behavior: 'always_invoice',\n      products: [\n        {\n          product: 'prod_basic',\n          prices: ['price_basic_monthly', 'price_basic_yearly'],\n        },\n        {\n          product: 'prod_premium',\n          prices: ['price_premium_monthly', 'price_premium_yearly'],\n        },\n      ],\n    },\n  },\n});\n\n// Use custom configuration\nconst portalSession = await stripe.billingPortal.sessions.create({\n  customer: 'cus_123456789',\n  return_url: 'https://example.com/account',\n  configuration: configuration.id,\n});\n```\n\n### Charges (Legacy - Use Payment Intents Instead)\n\n**Note:** Charges API is legacy. Use Payment Intents for new integrations.\n\n```javascript\n// Only use if you have a specific reason not to use Payment Intents\nconst charge = await stripe.charges.create({\n  amount: 2000,\n  currency: 'usd',\n  source: 'tok_visa',\n  description: 'Legacy charge',\n});\n```\n\n## 5. Best Practices\n\n### Idempotency\n\nStripe supports idempotency to safely retry requests without performing the same operation twice.\n\n```javascript\n// Generate unique idempotency key\nconst { v4: uuidv4 } = require('uuid');\n\nconst paymentIntent = await stripe.paymentIntents.create(\n  {\n    amount: 1000,\n    currency: 'usd',\n  },\n  {\n    idempotencyKey: uuidv4(), // Unique key per request\n  }\n);\n```\n\n**Automatic Retries with Idempotency:**\n\n```javascript\nasync function createPaymentWithRetry(paymentData, maxRetries = 3) {\n  const idempotencyKey = uuidv4();\n\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      const paymentIntent = await stripe.paymentIntents.create(\n        paymentData,\n        { idempotencyKey }\n      );\n      return paymentIntent;\n    } catch (err) {\n      if (attempt === maxRetries) throw err;\n\n      // Only retry on network errors or rate limits\n      if (err.type === 'StripeConnectionError' || err.statusCode === 429) {\n        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw err; // Don't retry on other errors\n      }\n    }\n  }\n}\n```\n\n### Error Handling\n\nStripe errors include specific types for targeted handling.\n\n```javascript\nasync function handleStripeOperation() {\n  try {\n    const paymentIntent = await stripe.paymentIntents.create({\n      amount: 1000,\n      currency: 'usd',\n    });\n    return paymentIntent;\n  } catch (err) {\n    switch (err.type) {\n      case 'StripeCardError':\n        // Card was declined\n        console.error('Card declined:', err.message);\n        return { error: 'Your card was declined.' };\n\n      case 'StripeRateLimitError':\n        // Too many requests\n        console.error('Rate limit hit');\n        return { error: 'Too many requests. Please try again later.' };\n\n      case 'StripeInvalidRequestError':\n        // Invalid parameters\n        console.error('Invalid request:', err.message);\n        return { error: 'Invalid payment information.' };\n\n      case 'StripeAPIError':\n        // Stripe API error\n        console.error('API error:', err.message);\n        return { error: 'Payment processing error. Please try again.' };\n\n      case 'StripeConnectionError':\n        // Network error\n        console.error('Network error:', err.message);\n        return { error: 'Network error. Please check your connection.' };\n\n      case 'StripeAuthenticationError':\n        // Authentication error\n        console.error('Authentication failed:', err.message);\n        return { error: 'Payment system error.' };\n\n      default:\n        console.error('Unknown error:', err);\n        return { error: 'An unexpected error occurred.' };\n    }\n  }\n}\n```\n\n**Comprehensive Error Handler:**\n\n```javascript\nclass StripeErrorHandler {\n  static async execute(operation, options = {}) {\n    const { maxRetries = 3, retryDelay = 1000 } = options;\n\n    for (let attempt = 1; attempt <= maxRetries; attempt++) {\n      try {\n        return await operation();\n      } catch (err) {\n        const shouldRetry = this.shouldRetry(err, attempt, maxRetries);\n\n        if (!shouldRetry) {\n          throw this.formatError(err);\n        }\n\n        const delay = retryDelay * Math.pow(2, attempt - 1);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      }\n    }\n  }\n\n  static shouldRetry(err, attempt, maxRetries) {\n    if (attempt >= maxRetries) return false;\n\n    return (\n      err.type === 'StripeConnectionError' ||\n      err.type === 'StripeAPIError' ||\n      err.statusCode === 429 ||\n      err.statusCode === 503\n    );\n  }\n\n  static formatError(err) {\n    return {\n      type: err.type,\n      message: err.message,\n      statusCode: err.statusCode,\n      code: err.code,\n      decline_code: err.decline_code,\n      param: err.param,\n    };\n  }\n}\n\n// Usage\nconst paymentIntent = await StripeErrorHandler.execute(\n  () => stripe.paymentIntents.create({ amount: 1000, currency: 'usd' }),\n  { maxRetries: 3, retryDelay: 1000 }\n);\n```\n\n### Rate Limit Handling\n\nStripe enforces rate limits to ensure API stability.\n\n```javascript\nasync function rateLimitedRequest(requestFn, maxRetries = 5) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await requestFn();\n    } catch (err) {\n      if (err.statusCode === 429) {\n        // Rate limited - use exponential backoff\n        const delay = Math.min(1000 * Math.pow(2, i), 32000);\n        console.log(`Rate limited. Retrying in ${delay}ms...`);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw err;\n      }\n    }\n  }\n  throw new Error('Max retries exceeded for rate limit');\n}\n\n// Usage\nconst customer = await rateLimitedRequest(() =>\n  stripe.customers.create({ email: 'customer@example.com' })\n);\n```\n\n**Advanced Rate Limit Strategy:**\n\n```javascript\nclass RateLimiter {\n  constructor(requestsPerSecond = 100) {\n    this.requestsPerSecond = requestsPerSecond;\n    this.queue = [];\n    this.processing = false;\n  }\n\n  async execute(fn) {\n    return new Promise((resolve, reject) => {\n      this.queue.push({ fn, resolve, reject });\n      this.processQueue();\n    });\n  }\n\n  async processQueue() {\n    if (this.processing || this.queue.length === 0) return;\n\n    this.processing = true;\n    const { fn, resolve, reject } = this.queue.shift();\n\n    try {\n      const result = await fn();\n      resolve(result);\n    } catch (err) {\n      if (err.statusCode === 429) {\n        // Re-queue with higher priority\n        this.queue.unshift({ fn, resolve, reject });\n        await new Promise(r => setTimeout(r, 2000));\n      } else {\n        reject(err);\n      }\n    } finally {\n      this.processing = false;\n      const delay = 1000 / this.requestsPerSecond;\n      setTimeout(() => this.processQueue(), delay);\n    }\n  }\n}\n\nconst limiter = new RateLimiter(100); // 100 requests per second\n\n// Usage\nconst customer = await limiter.execute(() =>\n  stripe.customers.create({ email: 'customer@example.com' })\n);\n```\n\n### Pagination\n\nMany Stripe API methods return paginated results.\n\n```javascript\n// Manual pagination\nconst customers = await stripe.customers.list({\n  limit: 100,\n});\n\n// Iterate through pages\nlet hasMore = customers.has_more;\nlet startingAfter = customers.data[customers.data.length - 1].id;\n\nwhile (hasMore) {\n  const nextPage = await stripe.customers.list({\n    limit: 100,\n    starting_after: startingAfter,\n  });\n\n  customers.data.push(...nextPage.data);\n  hasMore = nextPage.has_more;\n\n  if (hasMore) {\n    startingAfter = nextPage.data[nextPage.data.length - 1].id;\n  }\n}\n```\n\n**Auto-Pagination:**\n\n```javascript\n// Stripe SDK provides auto-pagination\nconst allCustomers = [];\n\nfor await (const customer of stripe.customers.list({ limit: 100 })) {\n  allCustomers.push(customer);\n\n  // Process customer\n  console.log(customer.email);\n\n  // Optional: Stop after certain condition\n  if (allCustomers.length >= 500) break;\n}\n```\n\n### Testing\n\nStripe provides test mode with test API keys and test card numbers.\n\n**Test Card Numbers:**\n\n```javascript\n// Use these in test mode\nconst testCards = {\n  visa: '4242424242424242',\n  visaDebit: '4000056655665556',\n  mastercard: '5555555555554444',\n  amex: '378282246310005',\n  discover: '6011111111111117',\n  dinersClub: '3056930009020004',\n  jcb: '3566002020360505',\n  unionPay: '6200000000000005',\n\n  // Cards that trigger specific scenarios\n  declined: '4000000000000002',\n  insufficientFunds: '4000000000009995',\n  lostCard: '4000000000009987',\n  stolenCard: '4000000000009979',\n  expiredCard: '4000000000000069',\n  incorrectCvc: '4000000000000127',\n  processingError: '4000000000000119',\n\n  // 3D Secure authentication required\n  authRequired: '4000002500003155',\n  authRequiredDeclined: '4000008400001629',\n};\n```\n\n**Test Mode Detection:**\n\n```javascript\nconst isTestMode = process.env.STRIPE_SECRET_KEY.startsWith('sk_test_');\n\nif (isTestMode) {\n  console.log('Running in TEST mode');\n} else {\n  console.log('Running in LIVE mode');\n}\n```\n\n**Mock Stripe for Unit Tests:**\n\n```javascript\n// Using jest\njest.mock('stripe', () => {\n  return jest.fn().mockImplementation(() => ({\n    paymentIntents: {\n      create: jest.fn().mockResolvedValue({\n        id: 'pi_test_123',\n        client_secret: 'pi_test_123_secret',\n        status: 'requires_payment_method',\n      }),\n      retrieve: jest.fn().mockResolvedValue({\n        id: 'pi_test_123',\n        status: 'succeeded',\n      }),\n    },\n    customers: {\n      create: jest.fn().mockResolvedValue({\n        id: 'cus_test_123',\n        email: 'test@example.com',\n      }),\n    },\n  }));\n});\n\n// Test\nconst stripe = require('stripe')();\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 1000,\n  currency: 'usd',\n});\nexpect(paymentIntent.id).toBe('pi_test_123');\n```\n\n### Security Best Practices\n\n**1. Never Expose Secret Keys:**\n\n```javascript\n// NEVER do this\nconst stripe = require('stripe')('sk_live_actual_secret_key_hardcoded');\n\n// ALWAYS do this\nconst stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);\n```\n\n**2. Validate Webhook Signatures:**\n\n```javascript\n// ALWAYS verify webhook signatures\ntry {\n  const event = stripe.webhooks.constructEvent(\n    req.body,\n    req.headers['stripe-signature'],\n    process.env.STRIPE_WEBHOOK_SECRET\n  );\n} catch (err) {\n  // Signature verification failed - reject the request\n  return res.status(400).send(`Webhook Error: ${err.message}`);\n}\n```\n\n**3. Use HTTPS in Production:**\n\n```javascript\n// Ensure your server uses HTTPS\nif (process.env.NODE_ENV === 'production' && !req.secure) {\n  return res.redirect('https://' + req.headers.host + req.url);\n}\n```\n\n**4. Server-Side Validation:**\n\n```javascript\n// NEVER trust client-side data\napp.post('/create-payment-intent', async (req, res) => {\n  // Don't use amount from client\n  // const { amount } = req.body; // UNSAFE\n\n  // Calculate amount server-side based on cart/order\n  const order = await getOrderFromDatabase(req.body.orderId);\n  const amount = calculateOrderTotal(order);\n\n  const paymentIntent = await stripe.paymentIntents.create({\n    amount,\n    currency: 'usd',\n  });\n\n  res.json({ clientSecret: paymentIntent.client_secret });\n});\n```\n\n**5. PCI Compliance:**\n\n```javascript\n// NEVER handle raw card data on your server\n// ALWAYS use Stripe.js or Elements to collect card information\n\n// DON'T do this:\napp.post('/charge', async (req, res) => {\n  const { cardNumber, cvc, expMonth, expYear } = req.body; // NEVER\n  // ...\n});\n\n// DO this instead:\n// Use Stripe.js on client to create PaymentMethod\n// Only send PaymentMethod ID to server\napp.post('/charge', async (req, res) => {\n  const { paymentMethodId } = req.body; // Safe\n  const paymentIntent = await stripe.paymentIntents.create({\n    amount: 1000,\n    currency: 'usd',\n    payment_method: paymentMethodId,\n  });\n});\n```\n\n### Metadata Best Practices\n\nMetadata helps you store additional information on Stripe objects.\n\n```javascript\n// Use metadata to link Stripe objects to your system\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n  metadata: {\n    user_id: '12345',\n    account_type: 'premium',\n    signup_date: new Date().toISOString(),\n  },\n});\n\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 2000,\n  currency: 'usd',\n  metadata: {\n    order_id: 'order_789',\n    customer_id: '12345',\n    product_ids: 'prod_1,prod_2,prod_3',\n    campaign: 'summer_sale',\n  },\n});\n\n// Search using metadata\nconst orders = await stripe.paymentIntents.search({\n  query: 'metadata[\"order_id\"]:\"order_789\"',\n});\n```\n\n### Logging and Monitoring\n\n```javascript\n// Create a logging wrapper\nclass StripeClient {\n  constructor(apiKey) {\n    this.stripe = require('stripe')(apiKey);\n    this.logger = console; // Replace with your logger\n  }\n\n  async createPaymentIntent(params) {\n    const startTime = Date.now();\n\n    try {\n      this.logger.info('Creating payment intent', { params });\n\n      const paymentIntent = await this.stripe.paymentIntents.create(params);\n\n      const duration = Date.now() - startTime;\n      this.logger.info('Payment intent created', {\n        id: paymentIntent.id,\n        amount: paymentIntent.amount,\n        duration,\n      });\n\n      return paymentIntent;\n    } catch (err) {\n      const duration = Date.now() - startTime;\n      this.logger.error('Payment intent creation failed', {\n        error: err.message,\n        type: err.type,\n        code: err.code,\n        duration,\n      });\n\n      throw err;\n    }\n  }\n}\n\nconst stripeClient = new StripeClient(process.env.STRIPE_SECRET_KEY);\n```\n\n### Production Deployment Checklist\n\n**Environment Configuration:**\n\n```javascript\n// config.js\nmodule.exports = {\n  stripe: {\n    secretKey: process.env.STRIPE_SECRET_KEY,\n    publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,\n    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n    apiVersion: '2025-02-24',\n  },\n\n  // Validate required environment variables\n  validate: () => {\n    const required = [\n      'STRIPE_SECRET_KEY',\n      'STRIPE_PUBLISHABLE_KEY',\n      'STRIPE_WEBHOOK_SECRET',\n    ];\n\n    for (const key of required) {\n      if (!process.env[key]) {\n        throw new Error(`Missing required environment variable: ${key}`);\n      }\n    }\n\n    // Ensure production uses live keys\n    if (process.env.NODE_ENV === 'production') {\n      if (!process.env.STRIPE_SECRET_KEY.startsWith('sk_live_')) {\n        throw new Error('Production must use live Stripe keys');\n      }\n    }\n  },\n};\n```\n\n**Webhook Endpoint Security:**\n\n```javascript\n// Dedicated webhook handler with security\napp.post(\n  '/webhook',\n  express.raw({ type: 'application/json' }),\n  rateLimitMiddleware({ max: 100, windowMs: 60000 }), // Rate limiting\n  async (req, res) => {\n    const sig = req.headers['stripe-signature'];\n\n    let event;\n\n    try {\n      // Verify signature\n      event = stripe.webhooks.constructEvent(\n        req.body,\n        sig,\n        process.env.STRIPE_WEBHOOK_SECRET\n      );\n    } catch (err) {\n      logger.error('Webhook signature verification failed', {\n        error: err.message,\n        ip: req.ip,\n      });\n      return res.status(400).send(`Webhook Error: ${err.message}`);\n    }\n\n    // Log webhook received\n    logger.info('Webhook received', {\n      type: event.type,\n      id: event.id,\n    });\n\n    // Process asynchronously\n    processWebhook(event).catch(err => {\n      logger.error('Webhook processing failed', {\n        type: event.type,\n        id: event.id,\n        error: err.message,\n      });\n    });\n\n    // Respond immediately\n    res.json({ received: true });\n  }\n);\n```\n\n### Performance Optimization\n\n**Parallel Requests:**\n\n```javascript\n// Execute multiple independent requests in parallel\nconst [customer, product, price] = await Promise.all([\n  stripe.customers.retrieve('cus_123'),\n  stripe.products.retrieve('prod_123'),\n  stripe.prices.retrieve('price_123'),\n]);\n```\n\n**Expand Related Objects:**\n\n```javascript\n// Instead of multiple requests\nconst subscription = await stripe.subscriptions.retrieve('sub_123');\nconst customer = await stripe.customers.retrieve(subscription.customer);\nconst invoice = await stripe.invoices.retrieve(subscription.latest_invoice);\n\n// Do this - single request with expand\nconst subscription = await stripe.subscriptions.retrieve('sub_123', {\n  expand: [\n    'customer',\n    'latest_invoice',\n    'latest_invoice.payment_intent',\n    'default_payment_method',\n  ],\n});\n\n// Access expanded objects\nconsole.log(subscription.customer.email);\nconsole.log(subscription.latest_invoice.amount_paid);\n```\n\n**Batch Operations:**\n\n```javascript\n// Create multiple objects efficiently\nasync function createMultipleCustomers(customerData) {\n  const BATCH_SIZE = 10;\n  const results = [];\n\n  for (let i = 0; i < customerData.length; i += BATCH_SIZE) {\n    const batch = customerData.slice(i, i + BATCH_SIZE);\n    const batchPromises = batch.map(data =>\n      stripe.customers.create(data)\n    );\n\n    const batchResults = await Promise.allSettled(batchPromises);\n    results.push(...batchResults);\n\n    // Small delay between batches to avoid rate limits\n    if (i + BATCH_SIZE < customerData.length) {\n      await new Promise(resolve => setTimeout(resolve, 100));\n    }\n  }\n\n  return results;\n}\n```\n\n### TypeScript Usage\n\n**Complete Type Safety:**\n\n```typescript\nimport Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {\n  apiVersion: '2025-02-24',\n});\n\n// Full type inference\nasync function createSubscription(\n  customerId: string,\n  priceId: string\n): Promise<Stripe.Subscription> {\n  const subscription = await stripe.subscriptions.create({\n    customer: customerId,\n    items: [{ price: priceId }],\n    payment_behavior: 'default_incomplete',\n    expand: ['latest_invoice.payment_intent'],\n  });\n\n  return subscription;\n}\n\n// Type-safe event handling\nasync function handleWebhook(\n  body: string | Buffer,\n  signature: string\n): Promise<void> {\n  const event = stripe.webhooks.constructEvent(\n    body,\n    signature,\n    process.env.STRIPE_WEBHOOK_SECRET!\n  );\n\n  switch (event.type) {\n    case 'payment_intent.succeeded': {\n      const paymentIntent = event.data.object as Stripe.PaymentIntent;\n      console.log(`PaymentIntent ${paymentIntent.id} succeeded`);\n      break;\n    }\n    case 'customer.subscription.updated': {\n      const subscription = event.data.object as Stripe.Subscription;\n      console.log(`Subscription ${subscription.id} updated`);\n      break;\n    }\n    default:\n      console.log(`Unhandled event type: ${event.type}`);\n  }\n}\n\n// Custom types for your domain\ninterface CreatePaymentParams {\n  amount: number;\n  currency: string;\n  customerId?: string;\n  metadata?: Record<string, string>;\n}\n\nasync function createPayment(\n  params: CreatePaymentParams\n): Promise<Stripe.PaymentIntent> {\n  return await stripe.paymentIntents.create({\n    amount: params.amount,\n    currency: params.currency,\n    customer: params.customerId,\n    metadata: params.metadata,\n  });\n}\n```\n\n## 6. Production Checklist\n\n### Pre-Launch Verification\n\n- [ ] Switched from test keys to live keys\n- [ ] Environment variables properly configured in production\n- [ ] Webhook endpoints registered and verified in Stripe Dashboard\n- [ ] Webhook signature verification implemented\n- [ ] HTTPS enabled on all endpoints\n- [ ] Error handling and logging configured\n- [ ] Rate limiting implemented\n- [ ] Idempotency keys used for critical operations\n- [ ] Payment confirmation flow tested end-to-end\n- [ ] Refund process tested\n- [ ] Subscription lifecycle tested (create, update, cancel)\n- [ ] Tax calculation configured (if applicable)\n- [ ] Email receipts enabled\n- [ ] Monitoring and alerting set up\n- [ ] PCI compliance requirements met\n- [ ] Terms of service and privacy policy updated\n- [ ] Customer support process for payment issues established\n\n### Monitoring\n\n```javascript\n// Monitor key metrics\nconst metrics = {\n  paymentIntentsCreated: 0,\n  paymentIntentsSucceeded: 0,\n  paymentIntentsFailed: 0,\n  webhooksProcessed: 0,\n  webhooksFailed: 0,\n  apiErrors: 0,\n};\n\n// Increment metrics in your code\napp.post('/create-payment', async (req, res) => {\n  metrics.paymentIntentsCreated++;\n\n  try {\n    const paymentIntent = await stripe.paymentIntents.create({\n      amount: req.body.amount,\n      currency: 'usd',\n    });\n\n    return res.json(paymentIntent);\n  } catch (err) {\n    metrics.apiErrors++;\n    logger.error('Payment creation failed', { error: err });\n    return res.status(500).json({ error: 'Payment failed' });\n  }\n});\n\n// Expose metrics endpoint\napp.get('/metrics', (req, res) => {\n  res.json(metrics);\n});\n```\n\n### Disaster Recovery\n\n```javascript\n// Implement graceful degradation\nasync function createPaymentWithFallback(params) {\n  try {\n    return await stripe.paymentIntents.create(params);\n  } catch (err) {\n    // Log error\n    logger.error('Stripe API error', { error: err });\n\n    // If Stripe is down, queue for later processing\n    if (err.type === 'StripeAPIError' || err.type === 'StripeConnectionError') {\n      await queuePaymentForLater(params);\n      return { status: 'queued', message: 'Payment will be processed shortly' };\n    }\n\n    throw err;\n  }\n}\n```\n\n---\n\n**Notes**\n\nThe Stripe API provides a comprehensive platform for payment processing, subscription management, and billing. The Node.js library (`stripe`) offers server-side functionality, while `@stripe/stripe-js` and `@stripe/react-stripe-js` provide client-side integration capabilities. Stripe uses date-based API versioning to ensure long-term compatibility while continuously adding new features. All payment data must be transmitted securely using HTTPS, and sensitive card information should only be handled by Stripe.js on the client side to maintain PCI compliance. Webhooks are essential for production deployments as they provide reliable event notifications independent of user sessions. The platform supports multiple payment methods, currencies, and billing models, making it suitable for businesses of all sizes. Always use test mode during development and thoroughly test your integration before switching to live mode.\n"
  },
  {
    "path": "content/stripe/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Stripe Python package guide for authenticating, calling the Stripe API, handling webhooks, and working with StripeClient\"\nmetadata:\n  languages: \"python\"\n  versions: \"14.4.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"stripe,payments,billing,api,webhooks,checkout\"\n---\n\n# Stripe Python Package Guide\n\n## Golden Rule\n\nUse the official `stripe` PyPI package, initialize it with a secret key from the Stripe Dashboard, and prefer `StripeClient` over the older global `stripe.api_key` pattern. For webhook verification, always use the raw request body. For testing, keep integrations on test keys or Stripe sandboxes until the full payment and webhook flow is verified.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"stripe==14.4.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"stripe==14.4.1\"\npoetry add \"stripe==14.4.1\"\n```\n\nIf you plan to use the async client helpers, install the async extra:\n\n```bash\npython -m pip install \"stripe[async]==14.4.1\"\n```\n\n## Authentication And Setup\n\nStripe authenticates with API keys. Secret keys start with `sk_test_` or `sk_live_`. Keep them in environment variables or a secrets manager, never in client-side code or committed files.\n\n```bash\nexport STRIPE_SECRET_KEY=\"sk_test_...\"\nexport STRIPE_WEBHOOK_SECRET=\"whsec_...\"\n```\n\nRecommended setup with `StripeClient`:\n\n```python\nimport os\nfrom stripe import StripeClient\n\nclient = StripeClient(\n    api_key=os.environ[\"STRIPE_SECRET_KEY\"],\n    max_network_retries=2,\n)\n```\n\nNotes:\n\n- `max_network_retries=2` is a sensible default for transient network failures.\n- Stripe automatically adds idempotency keys for safe retries when it needs to retry requests.\n- If you need a proxy, pass `proxy=\"https://user:pass@example.com:1234\"` to `StripeClient(...)`.\n\nLegacy global configuration still works, but it is not the preferred pattern for new code:\n\n```python\nimport os\nimport stripe\n\nstripe.api_key = os.environ[\"STRIPE_SECRET_KEY\"]\ncustomer = stripe.Customer.retrieve(\"cus_123\")\n```\n\n## Core Usage\n\n### Create or retrieve customers\n\n```python\nfrom stripe import StripeClient\n\nclient = StripeClient(\"sk_test_...\")\n\ncustomer = client.v1.customers.create(\n    {\n        \"email\": \"customer@example.com\",\n        \"name\": \"Jenny Rosen\",\n        \"metadata\": {\"internal_user_id\": \"user_123\"},\n    }\n)\n\nsame_customer = client.v1.customers.retrieve(customer.id)\nprint(same_customer.email)\n```\n\nUse `client.v1...` for standard Stripe API resources. Older examples on blogs or Stack Overflow often show only the legacy global pattern.\n\n### Create a PaymentIntent\n\nUse one PaymentIntent per order or checkout attempt.\n\n```python\nfrom stripe import StripeClient\n\nclient = StripeClient(\"sk_test_...\")\n\npayment_intent = client.v1.payment_intents.create(\n    {\n        \"amount\": 2000,\n        \"currency\": \"usd\",\n        \"customer\": \"cus_123\",\n        \"automatic_payment_methods\": {\"enabled\": True},\n        \"metadata\": {\"order_id\": \"order_6735\"},\n    }\n)\n\nprint(payment_intent.id)\nprint(payment_intent.client_secret)\n```\n\nPractical notes:\n\n- Amounts are usually in the currency's smallest unit, such as cents for USD.\n- `automatic_payment_methods={\"enabled\": True}` is the simplest starting point for many server-side integrations.\n- For client confirmation flows, return the `client_secret` to trusted frontend code only.\n\n### List resources with auto-pagination\n\nStripe list calls return a page object. Use `auto_paging_iter()` when you need all results:\n\n```python\nfrom stripe import StripeClient\n\nclient = StripeClient(\"sk_test_...\")\ncustomers = client.v1.customers.list({\"limit\": 3})\n\nfor customer in customers.auto_paging_iter():\n    print(customer.id, customer.email)\n```\n\n### Per-request options\n\nUse the `options` argument when you need a connected account, a different API key, or a per-request Stripe version:\n\n```python\nfrom stripe import StripeClient\n\nclient = StripeClient(\"sk_test_platform_...\")\n\ncharges = client.v1.charges.list(\n    options={\n        \"stripe_account\": \"acct_123\",\n        \"stripe_version\": \"2026-02-25.clover\",\n    }\n)\n```\n\nThis is common in Connect integrations and during controlled API-version rollouts.\n\n### Access response metadata for debugging\n\n```python\nfrom stripe import StripeClient\n\nclient = StripeClient(\"sk_test_...\")\ncustomer = client.v1.customers.retrieve(\"cus_123\")\n\nprint(customer.last_response.code)\nprint(customer.last_response.headers.get(\"Request-Id\"))\n```\n\nStripe request IDs are useful when checking Dashboard logs or contacting Stripe support.\n\n## Async Usage\n\nAsync methods use the `_async` suffix.\n\n```python\nimport stripe\nfrom stripe import StripeClient\n\nhttp_client = stripe.HTTPXClient()\nclient = StripeClient(\"sk_test_...\", http_client=http_client)\n\ncustomer = await client.v1.customers.retrieve_async(\"cus_123\")\nprint(customer.email)\n```\n\nNotes:\n\n- The default async transport uses `httpx`.\n- `stripe.AIOHTTPClient()` is also available.\n- `HTTPXClient()` will reject sync calls unless you set `allow_sync_methods=True`.\n- There is no `.save_async`; use the explicit create, modify, delete, and retrieve methods instead.\n\n## Webhooks\n\nVerify signatures with the raw body and the webhook signing secret. Do not parse or mutate the body before verification.\n\n```python\nimport os\nimport stripe\nfrom django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\n\nendpoint_secret = os.environ[\"STRIPE_WEBHOOK_SECRET\"]\n\n@csrf_exempt\ndef stripe_webhook(request):\n    payload = request.body\n    sig_header = request.headers.get(\"Stripe-Signature\")\n\n    try:\n        event = stripe.Webhook.construct_event(\n            payload,\n            sig_header,\n            endpoint_secret,\n        )\n    except ValueError:\n        return HttpResponse(status=400)\n    except stripe.error.SignatureVerificationError:\n        return HttpResponse(status=400)\n\n    if event.type == \"payment_intent.succeeded\":\n        payment_intent = event.data.object\n        print(payment_intent.id)\n\n    return HttpResponse(status=200)\n```\n\nWebhook rules that matter in practice:\n\n- Keep the raw request body intact or signature verification fails.\n- Return a `2xx` response quickly before slow business logic.\n- Use the endpoint secret from the Dashboard or `stripe listen`, not your API secret key.\n- For local testing, Stripe recommends the Stripe CLI to forward events to your machine.\n\n## Configuration Notes\n\n- Enable SDK logging with `STRIPE_LOG=info` or `STRIPE_LOG=debug` when you need wire-level troubleshooting.\n- The package sends telemetry by default; disable it with `stripe.enable_telemetry = False` if your environment requires that.\n- You can swap the HTTP client with `stripe.RequestsClient()`, `stripe.PycurlClient()`, `stripe.UrllibClient()`, `stripe.HTTPXClient()`, or `stripe.AIOHTTPClient()` depending on sync or async needs.\n- Use `stripe.set_app_info(...)` if you are building a reusable plugin or integration layer on top of Stripe.\n\n## Common Pitfalls\n\n- Do not send secret keys to browsers, mobile apps, or public repos.\n- Do not use parsed JSON instead of the raw body for webhook signature verification.\n- Do not assume old `stripe.Customer.create(...)` examples represent the preferred modern style; `StripeClient` is the forward path.\n- Do not rely on a single list page if you need all records; use pagination or `auto_paging_iter()`.\n- Do not mix account-level API version assumptions with SDK defaults. Webhook payload shapes and typed objects can differ if your endpoint or request overrides the Stripe version.\n- Do not treat test mode and live mode objects as interchangeable; IDs and data are isolated by environment.\n\n## Version-Sensitive Notes For `14.4.1`\n\n- PyPI lists `14.4.1` as the current release as of March 12, 2026, so the version used here does not appear stale.\n- The `14.4.1` changelog entry is a patch release on top of `14.4.0`. The `14.4.0` release changed the SDK's pinned API version to `2026-02-25.clover`.\n- That means `14.4.1` code examples should assume the post-`2026-02-25.clover` API surface unless you explicitly override `stripe_version`.\n- Stripe's Python wiki notes that the `v1` namespace on `StripeClient` arrived in major version `13`, so pre-v13 upgrade guides and older blog posts can have materially different call shapes.\n- Stripe's type annotations can change in minor releases even when runtime behavior remains semver-compatible. If strict type checking matters, pin to a minor line such as `~=14.4`.\n\n## Official Sources\n\n- Stripe API reference: `https://docs.stripe.com/api?lang=python`\n- Stripe authentication docs: `https://docs.stripe.com/api/authentication?lang=python`\n- Stripe auto-pagination docs: `https://docs.stripe.com/api/pagination/auto?lang=python`\n- Stripe webhook docs: `https://docs.stripe.com/webhooks?lang=python`\n- Stripe server-side SDK docs: `https://docs.stripe.com/sdks/server-side`\n- Stripe SDK versioning policy: `https://docs.stripe.com/sdks/versioning?lang=python`\n- Stripe testing docs: `https://docs.stripe.com/testing-use-cases`\n- Stripe Python package on PyPI: `https://pypi.org/project/stripe/`\n- Stripe Python changelog: `https://raw.githubusercontent.com/stripe/stripe-python/master/CHANGELOG.md`\n- Stripe Python README: `https://raw.githubusercontent.com/stripe/stripe-python/master/README.md`\n"
  },
  {
    "path": "content/stripe/docs/payments/DOC.md",
    "content": "---\nname: payments\ndescription: \"Payment processing platform with comprehensive payment and billing features including Payment Intents, Subscriptions, Checkout, customer management, webhooks, and Connect for marketplaces\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"19.1.0\"\n  updated-on: \"2025-10-28\"\n  source: maintainer\n  tags: \"stripe,api,payments,billing\"\n---\n# Stripe API Coding Guide\n\n## 1. Golden Rule\n\n**Always use the official Stripe SDK packages:**\n- Server-side: `stripe` (Node.js library for Stripe API)\n- Client-side: `@stripe/stripe-js` (ES module for browser)\n- React: `@stripe/react-stripe-js` (React components and hooks)\n\n**Never use deprecated or unofficial libraries.** These are the only supported Stripe packages maintained by Stripe, Inc.\n\n**Current SDK Version:** v19.1.0 (Node.js server library)\n\n**API Version:** Stripe uses date-based API versioning (e.g., 2025-02-24). Your account is automatically pinned to the API version from your first request. You can override this per-request or upgrade in the Stripe Dashboard.\n\n## 2. Installation\n\n### Server-Side (Node.js)\n\n```bash\nnpm install stripe\n```\n\n```bash\nyarn add stripe\n```\n\n```bash\npnpm add stripe\n```\n\n**Requirements:** Node.js 16+ (support for Node 16 is deprecated; use Node 18+ for production)\n\n### Client-Side (Browser)\n\n```bash\nnpm install @stripe/stripe-js\n```\n\n```bash\nyarn add @stripe/stripe-js\n```\n\n### React Applications\n\n```bash\nnpm install @stripe/stripe-js @stripe/react-stripe-js\n```\n\n```bash\nyarn add @stripe/stripe-js @stripe/react-stripe-js\n```\n\n### Environment Variables\n\n```bash\n# Required\nSTRIPE_SECRET_KEY=sk_test_51H...  # Server-side only, NEVER expose in browser\nSTRIPE_PUBLISHABLE_KEY=pk_test_51H...  # Safe for client-side use\n\n# Optional\nSTRIPE_WEBHOOK_SECRET=whsec_...  # For webhook signature verification\nSTRIPE_API_VERSION=2025-02-24  # Override default API version\n```\n\n**CRITICAL:** Never commit secret keys to version control. Use environment variables or secure secret management systems.\n\n## 3. Initialization\n\n### Server-Side Initialization (Node.js)\n\n```javascript\nconst Stripe = require('stripe');\nconst stripe = Stripe(process.env.STRIPE_SECRET_KEY);\n```\n\n**With TypeScript:**\n\n```typescript\nimport Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {\n  apiVersion: '2025-02-24',\n});\n```\n\n**Advanced Configuration:**\n\n```javascript\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {\n  apiVersion: '2025-02-24',\n  maxNetworkRetries: 2,\n  timeout: 80000, // 80 seconds\n  telemetry: true,\n  appInfo: {\n    name: 'MyApp',\n    version: '1.0.0',\n    url: 'https://myapp.com',\n  },\n});\n```\n\n### Client-Side Initialization (Browser)\n\n```javascript\nimport { loadStripe } from '@stripe/stripe-js';\n\n// Load Stripe.js asynchronously\nconst stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);\n\n// Later, when you need to use it\nconst stripe = await stripePromise;\n```\n\n**Advanced Loading Options:**\n\n```javascript\nconst stripePromise = loadStripe(\n  process.env.STRIPE_PUBLISHABLE_KEY,\n  {\n    locale: 'en',\n    betas: ['some_beta_feature'],\n    apiVersion: '2025-02-24',\n  }\n);\n```\n\n### React Initialization\n\n```javascript\nimport { Elements } from '@stripe/react-stripe-js';\nimport { loadStripe } from '@stripe/stripe-js';\n\nconst stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);\n\nfunction App() {\n  return (\n    <Elements stripe={stripePromise}>\n      {/* Your payment components here */}\n    </Elements>\n  );\n}\n```\n\n**With Options:**\n\n```javascript\nfunction App() {\n  const options = {\n    mode: 'payment',\n    amount: 1099,\n    currency: 'usd',\n    appearance: {\n      theme: 'stripe',\n      variables: {\n        colorPrimary: '#0570de',\n      },\n    },\n  };\n\n  return (\n    <Elements stripe={stripePromise} options={options}>\n      <CheckoutForm />\n    </Elements>\n  );\n}\n```\n\n## 4. Core API Surfaces\n\n### Payment Intents\n\nPayment Intents are the recommended way to handle payments. They track the entire payment lifecycle and support Strong Customer Authentication (SCA).\n\n**Minimal Server-Side Example:**\n\n```javascript\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 1099, // Amount in cents ($10.99)\n  currency: 'usd',\n  payment_method_types: ['card'],\n});\n\n// Send clientSecret to client\nres.json({ clientSecret: paymentIntent.client_secret });\n```\n\n**Advanced Server-Side Example:**\n\n```javascript\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 2000,\n  currency: 'usd',\n  payment_method_types: ['card', 'us_bank_account'],\n  customer: 'cus_123456789',\n  description: 'Software subscription',\n  metadata: {\n    order_id: '6735',\n    customer_email: 'customer@example.com',\n  },\n  statement_descriptor: 'MYCOMPANY SUB',\n  receipt_email: 'customer@example.com',\n  automatic_payment_methods: {\n    enabled: true,\n    allow_redirects: 'never',\n  },\n  capture_method: 'manual', // For later capture\n});\n```\n\n**Client-Side Confirmation (React):**\n\n```javascript\nimport { PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';\n\nfunction CheckoutForm({ clientSecret }) {\n  const stripe = useStripe();\n  const elements = useElements();\n\n  const handleSubmit = async (event) => {\n    event.preventDefault();\n\n    if (!stripe || !elements) {\n      return;\n    }\n\n    const { error, paymentIntent } = await stripe.confirmPayment({\n      elements,\n      confirmParams: {\n        return_url: 'https://example.com/order/complete',\n      },\n      redirect: 'if_required',\n    });\n\n    if (error) {\n      console.error(error.message);\n    } else if (paymentIntent.status === 'succeeded') {\n      console.log('Payment successful!');\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <PaymentElement />\n      <button disabled={!stripe}>Submit</button>\n    </form>\n  );\n}\n```\n\n**Vanilla JavaScript Confirmation:**\n\n```javascript\nconst stripe = await stripePromise;\n\nconst { error, paymentIntent } = await stripe.confirmCardPayment(\n  clientSecret,\n  {\n    payment_method: {\n      card: cardElement,\n      billing_details: {\n        name: 'John Doe',\n        email: 'john@example.com',\n      },\n    },\n  }\n);\n\nif (error) {\n  console.error(error.message);\n} else if (paymentIntent.status === 'succeeded') {\n  console.log('Payment successful!');\n}\n```\n\n### Checkout Sessions\n\nStripe Checkout provides a pre-built, hosted payment page.\n\n**Minimal Server-Side Example:**\n\n```javascript\nconst session = await stripe.checkout.sessions.create({\n  line_items: [\n    {\n      price_data: {\n        currency: 'usd',\n        product_data: {\n          name: 'T-shirt',\n        },\n        unit_amount: 2000,\n      },\n      quantity: 1,\n    },\n  ],\n  mode: 'payment',\n  success_url: 'https://example.com/success',\n  cancel_url: 'https://example.com/cancel',\n});\n\n// Redirect to Checkout\nres.redirect(303, session.url);\n```\n\n**Advanced Server-Side Example:**\n\n```javascript\nconst session = await stripe.checkout.sessions.create({\n  line_items: [\n    {\n      price: 'price_1234567890', // Existing price ID\n      quantity: 2,\n    },\n  ],\n  mode: 'payment',\n  customer: 'cus_123456789',\n  customer_email: 'customer@example.com',\n  client_reference_id: 'order_12345',\n  success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',\n  cancel_url: 'https://example.com/cancel',\n  automatic_tax: { enabled: true },\n  allow_promotion_codes: true,\n  billing_address_collection: 'required',\n  shipping_address_collection: {\n    allowed_countries: ['US', 'CA'],\n  },\n  payment_method_types: ['card', 'us_bank_account'],\n  metadata: {\n    order_id: '6735',\n  },\n  invoice_creation: {\n    enabled: true,\n  },\n});\n```\n\n**Client-Side Redirect:**\n\n```javascript\nimport { loadStripe } from '@stripe/stripe-js';\n\nconst stripe = await loadStripe(publishableKey);\n\n// Redirect to Checkout\nconst { error } = await stripe.redirectToCheckout({\n  sessionId: session.id,\n});\n\nif (error) {\n  console.error(error.message);\n}\n```\n\n### Customers\n\nCustomers represent your users in Stripe.\n\n**Minimal Example:**\n\n```javascript\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n});\n```\n\n**Advanced Example:**\n\n\n```javascript\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n  name: 'John Doe',\n  phone: '+15555551234',\n  description: 'Premium customer',\n  metadata: {\n    user_id: 'user_12345',\n    plan: 'premium',\n  },\n  address: {\n    line1: '510 Townsend St',\n    city: 'San Francisco',\n    state: 'CA',\n    postal_code: '94103',\n    country: 'US',\n  },\n  payment_method: 'pm_card_visa',\n  invoice_settings: {\n    default_payment_method: 'pm_card_visa',\n  },\n});\n```\n\n**Retrieve and Update:**\n\n```javascript\n// Retrieve customer\nconst customer = await stripe.customers.retrieve('cus_123456789');\n\n// Update customer\nconst updatedCustomer = await stripe.customers.update('cus_123456789', {\n  metadata: { vip: 'true' },\n  email: 'newemail@example.com',\n});\n\n// List customers\nconst customers = await stripe.customers.list({\n  limit: 100,\n  email: 'customer@example.com',\n});\n```\n\n**Attach Payment Method to Customer:**\n\n```javascript\nconst paymentMethod = await stripe.paymentMethods.attach(\n  'pm_card_visa',\n  { customer: 'cus_123456789' }\n);\n\n// Set as default payment method\nawait stripe.customers.update('cus_123456789', {\n  invoice_settings: {\n    default_payment_method: 'pm_card_visa',\n  },\n});\n```\n\n### Subscriptions\n\nSubscriptions bill customers on a recurring basis.\n\n**Minimal Example:**\n\n```javascript\nconst subscription = await stripe.subscriptions.create({\n  customer: 'cus_123456789',\n  items: [\n    { price: 'price_1234567890' },\n  ],\n});\n```\n\n**Advanced Example:**\n\n```javascript\nconst subscription = await stripe.subscriptions.create({\n  customer: 'cus_123456789',\n  items: [\n    {\n      price: 'price_1234567890',\n      quantity: 1,\n    },\n  ],\n  payment_behavior: 'default_incomplete',\n  payment_settings: {\n    payment_method_types: ['card', 'us_bank_account'],\n    save_default_payment_method: 'on_subscription',\n  },\n  expand: ['latest_invoice.payment_intent'],\n  trial_period_days: 14,\n  metadata: {\n    user_id: 'user_12345',\n  },\n  proration_behavior: 'create_prorations',\n  billing_cycle_anchor_config: {\n    day_of_month: 1,\n  },\n  automatic_tax: {\n    enabled: true,\n  },\n});\n\n// Return client secret for payment confirmation\nconst clientSecret = subscription.latest_invoice.payment_intent.client_secret;\n```\n\n**Update Subscription:**\n\n```javascript\nconst updatedSubscription = await stripe.subscriptions.update(\n  'sub_1234567890',\n  {\n    items: [\n      {\n        id: 'si_1234567890',\n        price: 'price_new_plan',\n      },\n    ],\n    proration_behavior: 'always_invoice',\n  }\n);\n```\n\n**Cancel Subscription:**\n\n```javascript\n// Cancel at period end\nconst subscription = await stripe.subscriptions.update('sub_1234567890', {\n  cancel_at_period_end: true,\n});\n\n// Cancel immediately\nconst canceledSubscription = await stripe.subscriptions.cancel('sub_1234567890');\n```\n\n### Products and Prices\n\nProducts represent what you sell, Prices define how you charge for products.\n\n**Create Product:**\n\n```javascript\nconst product = await stripe.products.create({\n  name: 'Premium Subscription',\n  description: 'Access to all premium features',\n  metadata: {\n    category: 'subscription',\n  },\n});\n```\n\n**Create Price (One-Time):**\n\n```javascript\nconst price = await stripe.prices.create({\n  product: 'prod_1234567890',\n  unit_amount: 2000,\n  currency: 'usd',\n});\n```\n\n**Create Price (Recurring):**\n\n```javascript\nconst recurringPrice = await stripe.prices.create({\n  product: 'prod_1234567890',\n  unit_amount: 1500,\n  currency: 'usd',\n  recurring: {\n    interval: 'month',\n    interval_count: 1,\n    usage_type: 'licensed',\n  },\n  billing_scheme: 'per_unit',\n  tax_behavior: 'exclusive',\n});\n```\n\n**Advanced Pricing (Tiered):**\n\n```javascript\nconst tieredPrice = await stripe.prices.create({\n  product: 'prod_1234567890',\n  currency: 'usd',\n  recurring: {\n    interval: 'month',\n    usage_type: 'metered',\n  },\n  billing_scheme: 'tiered',\n  tiers_mode: 'graduated',\n  tiers: [\n    {\n      up_to: 10,\n      unit_amount: 1000,\n    },\n    {\n      up_to: 100,\n      unit_amount: 800,\n    },\n    {\n      up_to: 'inf',\n      unit_amount: 500,\n    },\n  ],\n});\n```\n\n### Payment Methods\n\nPayment Methods represent customer payment details.\n\n**Create Payment Method (Server-Side):**\n\n```javascript\nconst paymentMethod = await stripe.paymentMethods.create({\n  type: 'card',\n  card: {\n    token: 'tok_visa',\n  },\n});\n```\n\n**Create Payment Method (Client-Side with Elements):**\n\n```javascript\nconst stripe = await stripePromise;\nconst elements = stripe.elements();\nconst cardElement = elements.create('card');\ncardElement.mount('#card-element');\n\n// When form is submitted\nconst { error, paymentMethod } = await stripe.createPaymentMethod({\n  type: 'card',\n  card: cardElement,\n  billing_details: {\n    name: 'John Doe',\n    email: 'john@example.com',\n  },\n});\n\nif (error) {\n  console.error(error.message);\n} else {\n  console.log('PaymentMethod created:', paymentMethod.id);\n}\n```\n\n**List Customer Payment Methods:**\n\n```javascript\nconst paymentMethods = await stripe.paymentMethods.list({\n  customer: 'cus_123456789',\n  type: 'card',\n});\n```\n\n**Detach Payment Method:**\n\n```javascript\nconst detachedPM = await stripe.paymentMethods.detach('pm_1234567890');\n```\n\n### Refunds\n\n**Create Refund:**\n\n```javascript\n// Full refund\nconst refund = await stripe.refunds.create({\n  payment_intent: 'pi_1234567890',\n});\n\n// Partial refund\nconst partialRefund = await stripe.refunds.create({\n  payment_intent: 'pi_1234567890',\n  amount: 500, // Refund $5.00 of original charge\n  reason: 'requested_by_customer',\n  metadata: {\n    reason_detail: 'Customer changed mind',\n  },\n});\n```\n\n**Retrieve Refund:**\n\n```javascript\nconst refund = await stripe.refunds.retrieve('re_1234567890');\n```\n\n### Webhooks\n\nWebhooks notify your application when events occur in your Stripe account.\n\n**Setup Webhook Endpoint (Express.js):**\n\n```javascript\nconst express = require('express');\nconst app = express();\n\n// CRITICAL: Use raw body for webhook signature verification\napp.post(\n  '/webhook',\n  express.raw({ type: 'application/json' }),\n  async (req, res) => {\n    const sig = req.headers['stripe-signature'];\n    const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;\n\n    let event;\n\n    try {\n      event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n    } catch (err) {\n      console.error(`Webhook signature verification failed: ${err.message}`);\n      return res.status(400).send(`Webhook Error: ${err.message}`);\n    }\n\n    // Handle the event\n    switch (event.type) {\n      case 'payment_intent.succeeded':\n        const paymentIntent = event.data.object;\n        console.log('PaymentIntent succeeded:', paymentIntent.id);\n        // Fulfill the order\n        break;\n      case 'payment_intent.payment_failed':\n        const failedPayment = event.data.object;\n        console.log('Payment failed:', failedPayment.id);\n        // Notify customer\n        break;\n      case 'customer.subscription.created':\n        const subscription = event.data.object;\n        console.log('Subscription created:', subscription.id);\n        break;\n      case 'customer.subscription.updated':\n        const updatedSub = event.data.object;\n        console.log('Subscription updated:', updatedSub.id);\n        break;\n      case 'customer.subscription.deleted':\n        const canceledSub = event.data.object;\n        console.log('Subscription canceled:', canceledSub.id);\n        break;\n      default:\n        console.log(`Unhandled event type ${event.type}`);\n    }\n\n    res.json({ received: true });\n  }\n);\n```\n\n**Advanced Webhook Handling:**\n\n```javascript\napp.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {\n  const sig = req.headers['stripe-signature'];\n  const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;\n\n  let event;\n\n  try {\n    event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n  } catch (err) {\n    console.error(`Webhook Error: ${err.message}`);\n    return res.status(400).send(`Webhook Error: ${err.message}`);\n  }\n\n  // Handle event asynchronously to respond quickly\n  processWebhookEvent(event)\n    .then(() => console.log('Event processed successfully'))\n    .catch((err) => console.error('Event processing failed:', err));\n\n  // Respond immediately\n  res.json({ received: true });\n});\n\nasync function processWebhookEvent(event) {\n  const eventData = event.data.object;\n\n  switch (event.type) {\n    case 'checkout.session.completed':\n      const session = eventData;\n      // Fulfill order based on session\n      if (session.mode === 'payment') {\n        await fulfillOrder(session);\n      } else if (session.mode === 'subscription') {\n        await activateSubscription(session);\n      }\n      break;\n\n    case 'invoice.paid':\n      // Handle successful payment of invoice\n      await handleInvoicePaid(eventData);\n      break;\n\n    case 'invoice.payment_failed':\n      // Handle failed payment\n      await notifyCustomerPaymentFailed(eventData);\n      break;\n\n    default:\n      console.log(`Unhandled event type: ${event.type}`);\n  }\n}\n```\n\n### Invoices\n\n**Create Invoice:**\n\n```javascript\n// Create invoice item\nawait stripe.invoiceItems.create({\n  customer: 'cus_123456789',\n  amount: 2500,\n  currency: 'usd',\n  description: 'One-time setup fee',\n});\n\n// Create and finalize invoice\nconst invoice = await stripe.invoices.create({\n  customer: 'cus_123456789',\n  auto_advance: true, // Auto-finalize\n  collection_method: 'charge_automatically',\n});\n\n// Finalize invoice (if not auto-advance)\nconst finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id);\n\n// Pay invoice\nconst paidInvoice = await stripe.invoices.pay(invoice.id);\n```\n\n### Customer Portal\n\nThe Customer Portal allows customers to manage their subscription and billing information.\n\n**Create Portal Session:**\n\n```javascript\nconst portalSession = await stripe.billingPortal.sessions.create({\n  customer: 'cus_123456789',\n  return_url: 'https://example.com/account',\n});\n\n// Redirect customer to portal\nres.redirect(303, portalSession.url);\n```\n\n**Advanced Portal Configuration:**\n\n```javascript\n// Create a portal configuration\nconst configuration = await stripe.billingPortal.configurations.create({\n  business_profile: {\n    headline: 'Manage your subscription',\n  },\n  features: {\n    customer_update: {\n      enabled: true,\n      allowed_updates: ['email', 'address', 'shipping', 'phone', 'tax_id'],\n    },\n    invoice_history: {\n      enabled: true,\n    },\n    payment_method_update: {\n      enabled: true,\n    },\n    subscription_cancel: {\n      enabled: true,\n      mode: 'at_period_end',\n      cancellation_reason: {\n        enabled: true,\n        options: [\n          'too_expensive',\n          'missing_features',\n          'switched_service',\n          'unused',\n          'other',\n        ],\n      },\n    },\n    subscription_update: {\n      enabled: true,\n      default_allowed_updates: ['price', 'quantity', 'promotion_code'],\n      proration_behavior: 'always_invoice',\n      products: [\n        {\n          product: 'prod_basic',\n          prices: ['price_basic_monthly', 'price_basic_yearly'],\n        },\n        {\n          product: 'prod_premium',\n          prices: ['price_premium_monthly', 'price_premium_yearly'],\n        },\n      ],\n    },\n  },\n});\n\n// Use custom configuration\nconst portalSession = await stripe.billingPortal.sessions.create({\n  customer: 'cus_123456789',\n  return_url: 'https://example.com/account',\n  configuration: configuration.id,\n});\n```\n\n### Charges (Legacy - Use Payment Intents Instead)\n\n**Note:** Charges API is legacy. Use Payment Intents for new integrations.\n\n```javascript\n// Only use if you have a specific reason not to use Payment Intents\nconst charge = await stripe.charges.create({\n  amount: 2000,\n  currency: 'usd',\n  source: 'tok_visa',\n  description: 'Legacy charge',\n});\n```\n\n## 5. Best Practices\n\n### Idempotency\n\nStripe supports idempotency to safely retry requests without performing the same operation twice.\n\n```javascript\n// Generate unique idempotency key\nconst { v4: uuidv4 } = require('uuid');\n\nconst paymentIntent = await stripe.paymentIntents.create(\n  {\n    amount: 1000,\n    currency: 'usd',\n  },\n  {\n    idempotencyKey: uuidv4(), // Unique key per request\n  }\n);\n```\n\n**Automatic Retries with Idempotency:**\n\n```javascript\nasync function createPaymentWithRetry(paymentData, maxRetries = 3) {\n  const idempotencyKey = uuidv4();\n\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      const paymentIntent = await stripe.paymentIntents.create(\n        paymentData,\n        { idempotencyKey }\n      );\n      return paymentIntent;\n    } catch (err) {\n      if (attempt === maxRetries) throw err;\n\n      // Only retry on network errors or rate limits\n      if (err.type === 'StripeConnectionError' || err.statusCode === 429) {\n        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw err; // Don't retry on other errors\n      }\n    }\n  }\n}\n```\n\n### Error Handling\n\nStripe errors include specific types for targeted handling.\n\n```javascript\nasync function handleStripeOperation() {\n  try {\n    const paymentIntent = await stripe.paymentIntents.create({\n      amount: 1000,\n      currency: 'usd',\n    });\n    return paymentIntent;\n  } catch (err) {\n    switch (err.type) {\n      case 'StripeCardError':\n        // Card was declined\n        console.error('Card declined:', err.message);\n        return { error: 'Your card was declined.' };\n\n      case 'StripeRateLimitError':\n        // Too many requests\n        console.error('Rate limit hit');\n        return { error: 'Too many requests. Please try again later.' };\n\n      case 'StripeInvalidRequestError':\n        // Invalid parameters\n        console.error('Invalid request:', err.message);\n        return { error: 'Invalid payment information.' };\n\n      case 'StripeAPIError':\n        // Stripe API error\n        console.error('API error:', err.message);\n        return { error: 'Payment processing error. Please try again.' };\n\n      case 'StripeConnectionError':\n        // Network error\n        console.error('Network error:', err.message);\n        return { error: 'Network error. Please check your connection.' };\n\n      case 'StripeAuthenticationError':\n        // Authentication error\n        console.error('Authentication failed:', err.message);\n        return { error: 'Payment system error.' };\n\n      default:\n        console.error('Unknown error:', err);\n        return { error: 'An unexpected error occurred.' };\n    }\n  }\n}\n```\n\n**Comprehensive Error Handler:**\n\n```javascript\nclass StripeErrorHandler {\n  static async execute(operation, options = {}) {\n    const { maxRetries = 3, retryDelay = 1000 } = options;\n\n    for (let attempt = 1; attempt <= maxRetries; attempt++) {\n      try {\n        return await operation();\n      } catch (err) {\n        const shouldRetry = this.shouldRetry(err, attempt, maxRetries);\n\n        if (!shouldRetry) {\n          throw this.formatError(err);\n        }\n\n        const delay = retryDelay * Math.pow(2, attempt - 1);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      }\n    }\n  }\n\n  static shouldRetry(err, attempt, maxRetries) {\n    if (attempt >= maxRetries) return false;\n\n    return (\n      err.type === 'StripeConnectionError' ||\n      err.type === 'StripeAPIError' ||\n      err.statusCode === 429 ||\n      err.statusCode === 503\n    );\n  }\n\n  static formatError(err) {\n    return {\n      type: err.type,\n      message: err.message,\n      statusCode: err.statusCode,\n      code: err.code,\n      decline_code: err.decline_code,\n      param: err.param,\n    };\n  }\n}\n\n// Usage\nconst paymentIntent = await StripeErrorHandler.execute(\n  () => stripe.paymentIntents.create({ amount: 1000, currency: 'usd' }),\n  { maxRetries: 3, retryDelay: 1000 }\n);\n```\n\n### Rate Limit Handling\n\nStripe enforces rate limits to ensure API stability.\n\n```javascript\nasync function rateLimitedRequest(requestFn, maxRetries = 5) {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await requestFn();\n    } catch (err) {\n      if (err.statusCode === 429) {\n        // Rate limited - use exponential backoff\n        const delay = Math.min(1000 * Math.pow(2, i), 32000);\n        console.log(`Rate limited. Retrying in ${delay}ms...`);\n        await new Promise(resolve => setTimeout(resolve, delay));\n      } else {\n        throw err;\n      }\n    }\n  }\n  throw new Error('Max retries exceeded for rate limit');\n}\n\n// Usage\nconst customer = await rateLimitedRequest(() =>\n  stripe.customers.create({ email: 'customer@example.com' })\n);\n```\n\n**Advanced Rate Limit Strategy:**\n\n```javascript\nclass RateLimiter {\n  constructor(requestsPerSecond = 100) {\n    this.requestsPerSecond = requestsPerSecond;\n    this.queue = [];\n    this.processing = false;\n  }\n\n  async execute(fn) {\n    return new Promise((resolve, reject) => {\n      this.queue.push({ fn, resolve, reject });\n      this.processQueue();\n    });\n  }\n\n  async processQueue() {\n    if (this.processing || this.queue.length === 0) return;\n\n    this.processing = true;\n    const { fn, resolve, reject } = this.queue.shift();\n\n    try {\n      const result = await fn();\n      resolve(result);\n    } catch (err) {\n      if (err.statusCode === 429) {\n        // Re-queue with higher priority\n        this.queue.unshift({ fn, resolve, reject });\n        await new Promise(r => setTimeout(r, 2000));\n      } else {\n        reject(err);\n      }\n    } finally {\n      this.processing = false;\n      const delay = 1000 / this.requestsPerSecond;\n      setTimeout(() => this.processQueue(), delay);\n    }\n  }\n}\n\nconst limiter = new RateLimiter(100); // 100 requests per second\n\n// Usage\nconst customer = await limiter.execute(() =>\n  stripe.customers.create({ email: 'customer@example.com' })\n);\n```\n\n### Pagination\n\nMany Stripe API methods return paginated results.\n\n```javascript\n// Manual pagination\nconst customers = await stripe.customers.list({\n  limit: 100,\n});\n\n// Iterate through pages\nlet hasMore = customers.has_more;\nlet startingAfter = customers.data[customers.data.length - 1].id;\n\nwhile (hasMore) {\n  const nextPage = await stripe.customers.list({\n    limit: 100,\n    starting_after: startingAfter,\n  });\n\n  customers.data.push(...nextPage.data);\n  hasMore = nextPage.has_more;\n\n  if (hasMore) {\n    startingAfter = nextPage.data[nextPage.data.length - 1].id;\n  }\n}\n```\n\n**Auto-Pagination:**\n\n```javascript\n// Stripe SDK provides auto-pagination\nconst allCustomers = [];\n\nfor await (const customer of stripe.customers.list({ limit: 100 })) {\n  allCustomers.push(customer);\n\n  // Process customer\n  console.log(customer.email);\n\n  // Optional: Stop after certain condition\n  if (allCustomers.length >= 500) break;\n}\n```\n\n### Testing\n\nStripe provides test mode with test API keys and test card numbers.\n\n**Test Card Numbers:**\n\n```javascript\n// Use these in test mode\nconst testCards = {\n  visa: '4242424242424242',\n  visaDebit: '4000056655665556',\n  mastercard: '5555555555554444',\n  amex: '378282246310005',\n  discover: '6011111111111117',\n  dinersClub: '3056930009020004',\n  jcb: '3566002020360505',\n  unionPay: '6200000000000005',\n\n  // Cards that trigger specific scenarios\n  declined: '4000000000000002',\n  insufficientFunds: '4000000000009995',\n  lostCard: '4000000000009987',\n  stolenCard: '4000000000009979',\n  expiredCard: '4000000000000069',\n  incorrectCvc: '4000000000000127',\n  processingError: '4000000000000119',\n\n  // 3D Secure authentication required\n  authRequired: '4000002500003155',\n  authRequiredDeclined: '4000008400001629',\n};\n```\n\n**Test Mode Detection:**\n\n```javascript\nconst isTestMode = process.env.STRIPE_SECRET_KEY.startsWith('sk_test_');\n\nif (isTestMode) {\n  console.log('Running in TEST mode');\n} else {\n  console.log('Running in LIVE mode');\n}\n```\n\n**Mock Stripe for Unit Tests:**\n\n```javascript\n// Using jest\njest.mock('stripe', () => {\n  return jest.fn().mockImplementation(() => ({\n    paymentIntents: {\n      create: jest.fn().mockResolvedValue({\n        id: 'pi_test_123',\n        client_secret: 'pi_test_123_secret',\n        status: 'requires_payment_method',\n      }),\n      retrieve: jest.fn().mockResolvedValue({\n        id: 'pi_test_123',\n        status: 'succeeded',\n      }),\n    },\n    customers: {\n      create: jest.fn().mockResolvedValue({\n        id: 'cus_test_123',\n        email: 'test@example.com',\n      }),\n    },\n  }));\n});\n\n// Test\nconst stripe = require('stripe')();\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 1000,\n  currency: 'usd',\n});\nexpect(paymentIntent.id).toBe('pi_test_123');\n```\n\n### Security Best Practices\n\n**1. Never Expose Secret Keys:**\n\n```javascript\n// NEVER do this\nconst stripe = require('stripe')('sk_live_actual_secret_key_hardcoded');\n\n// ALWAYS do this\nconst stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);\n```\n\n**2. Validate Webhook Signatures:**\n\n```javascript\n// ALWAYS verify webhook signatures\ntry {\n  const event = stripe.webhooks.constructEvent(\n    req.body,\n    req.headers['stripe-signature'],\n    process.env.STRIPE_WEBHOOK_SECRET\n  );\n} catch (err) {\n  // Signature verification failed - reject the request\n  return res.status(400).send(`Webhook Error: ${err.message}`);\n}\n```\n\n**3. Use HTTPS in Production:**\n\n```javascript\n// Ensure your server uses HTTPS\nif (process.env.NODE_ENV === 'production' && !req.secure) {\n  return res.redirect('https://' + req.headers.host + req.url);\n}\n```\n\n**4. Server-Side Validation:**\n\n```javascript\n// NEVER trust client-side data\napp.post('/create-payment-intent', async (req, res) => {\n  // Don't use amount from client\n  // const { amount } = req.body; // UNSAFE\n\n  // Calculate amount server-side based on cart/order\n  const order = await getOrderFromDatabase(req.body.orderId);\n  const amount = calculateOrderTotal(order);\n\n  const paymentIntent = await stripe.paymentIntents.create({\n    amount,\n    currency: 'usd',\n  });\n\n  res.json({ clientSecret: paymentIntent.client_secret });\n});\n```\n\n**5. PCI Compliance:**\n\n```javascript\n// NEVER handle raw card data on your server\n// ALWAYS use Stripe.js or Elements to collect card information\n\n// DON'T do this:\napp.post('/charge', async (req, res) => {\n  const { cardNumber, cvc, expMonth, expYear } = req.body; // NEVER\n  // ...\n});\n\n// DO this instead:\n// Use Stripe.js on client to create PaymentMethod\n// Only send PaymentMethod ID to server\napp.post('/charge', async (req, res) => {\n  const { paymentMethodId } = req.body; // Safe\n  const paymentIntent = await stripe.paymentIntents.create({\n    amount: 1000,\n    currency: 'usd',\n    payment_method: paymentMethodId,\n  });\n});\n```\n\n### Metadata Best Practices\n\nMetadata helps you store additional information on Stripe objects.\n\n```javascript\n// Use metadata to link Stripe objects to your system\nconst customer = await stripe.customers.create({\n  email: 'customer@example.com',\n  metadata: {\n    user_id: '12345',\n    account_type: 'premium',\n    signup_date: new Date().toISOString(),\n  },\n});\n\nconst paymentIntent = await stripe.paymentIntents.create({\n  amount: 2000,\n  currency: 'usd',\n  metadata: {\n    order_id: 'order_789',\n    customer_id: '12345',\n    product_ids: 'prod_1,prod_2,prod_3',\n    campaign: 'summer_sale',\n  },\n});\n\n// Search using metadata\nconst orders = await stripe.paymentIntents.search({\n  query: 'metadata[\"order_id\"]:\"order_789\"',\n});\n```\n\n### Logging and Monitoring\n\n```javascript\n// Create a logging wrapper\nclass StripeClient {\n  constructor(apiKey) {\n    this.stripe = require('stripe')(apiKey);\n    this.logger = console; // Replace with your logger\n  }\n\n  async createPaymentIntent(params) {\n    const startTime = Date.now();\n\n    try {\n      this.logger.info('Creating payment intent', { params });\n\n      const paymentIntent = await this.stripe.paymentIntents.create(params);\n\n      const duration = Date.now() - startTime;\n      this.logger.info('Payment intent created', {\n        id: paymentIntent.id,\n        amount: paymentIntent.amount,\n        duration,\n      });\n\n      return paymentIntent;\n    } catch (err) {\n      const duration = Date.now() - startTime;\n      this.logger.error('Payment intent creation failed', {\n        error: err.message,\n        type: err.type,\n        code: err.code,\n        duration,\n      });\n\n      throw err;\n    }\n  }\n}\n\nconst stripeClient = new StripeClient(process.env.STRIPE_SECRET_KEY);\n```\n\n### Production Deployment Checklist\n\n**Environment Configuration:**\n\n```javascript\n// config.js\nmodule.exports = {\n  stripe: {\n    secretKey: process.env.STRIPE_SECRET_KEY,\n    publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,\n    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n    apiVersion: '2025-02-24',\n  },\n\n  // Validate required environment variables\n  validate: () => {\n    const required = [\n      'STRIPE_SECRET_KEY',\n      'STRIPE_PUBLISHABLE_KEY',\n      'STRIPE_WEBHOOK_SECRET',\n    ];\n\n    for (const key of required) {\n      if (!process.env[key]) {\n        throw new Error(`Missing required environment variable: ${key}`);\n      }\n    }\n\n    // Ensure production uses live keys\n    if (process.env.NODE_ENV === 'production') {\n      if (!process.env.STRIPE_SECRET_KEY.startsWith('sk_live_')) {\n        throw new Error('Production must use live Stripe keys');\n      }\n    }\n  },\n};\n```\n\n**Webhook Endpoint Security:**\n\n```javascript\n// Dedicated webhook handler with security\napp.post(\n  '/webhook',\n  express.raw({ type: 'application/json' }),\n  rateLimitMiddleware({ max: 100, windowMs: 60000 }), // Rate limiting\n  async (req, res) => {\n    const sig = req.headers['stripe-signature'];\n\n    let event;\n\n    try {\n      // Verify signature\n      event = stripe.webhooks.constructEvent(\n        req.body,\n        sig,\n        process.env.STRIPE_WEBHOOK_SECRET\n      );\n    } catch (err) {\n      logger.error('Webhook signature verification failed', {\n        error: err.message,\n        ip: req.ip,\n      });\n      return res.status(400).send(`Webhook Error: ${err.message}`);\n    }\n\n    // Log webhook received\n    logger.info('Webhook received', {\n      type: event.type,\n      id: event.id,\n    });\n\n    // Process asynchronously\n    processWebhook(event).catch(err => {\n      logger.error('Webhook processing failed', {\n        type: event.type,\n        id: event.id,\n        error: err.message,\n      });\n    });\n\n    // Respond immediately\n    res.json({ received: true });\n  }\n);\n```\n\n### Performance Optimization\n\n**Parallel Requests:**\n\n```javascript\n// Execute multiple independent requests in parallel\nconst [customer, product, price] = await Promise.all([\n  stripe.customers.retrieve('cus_123'),\n  stripe.products.retrieve('prod_123'),\n  stripe.prices.retrieve('price_123'),\n]);\n```\n\n**Expand Related Objects:**\n\n```javascript\n// Instead of multiple requests\nconst subscription = await stripe.subscriptions.retrieve('sub_123');\nconst customer = await stripe.customers.retrieve(subscription.customer);\nconst invoice = await stripe.invoices.retrieve(subscription.latest_invoice);\n\n// Do this - single request with expand\nconst subscription = await stripe.subscriptions.retrieve('sub_123', {\n  expand: [\n    'customer',\n    'latest_invoice',\n    'latest_invoice.payment_intent',\n    'default_payment_method',\n  ],\n});\n\n// Access expanded objects\nconsole.log(subscription.customer.email);\nconsole.log(subscription.latest_invoice.amount_paid);\n```\n\n**Batch Operations:**\n\n```javascript\n// Create multiple objects efficiently\nasync function createMultipleCustomers(customerData) {\n  const BATCH_SIZE = 10;\n  const results = [];\n\n  for (let i = 0; i < customerData.length; i += BATCH_SIZE) {\n    const batch = customerData.slice(i, i + BATCH_SIZE);\n    const batchPromises = batch.map(data =>\n      stripe.customers.create(data)\n    );\n\n    const batchResults = await Promise.allSettled(batchPromises);\n    results.push(...batchResults);\n\n    // Small delay between batches to avoid rate limits\n    if (i + BATCH_SIZE < customerData.length) {\n      await new Promise(resolve => setTimeout(resolve, 100));\n    }\n  }\n\n  return results;\n}\n```\n\n### TypeScript Usage\n\n**Complete Type Safety:**\n\n```typescript\nimport Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {\n  apiVersion: '2025-02-24',\n});\n\n// Full type inference\nasync function createSubscription(\n  customerId: string,\n  priceId: string\n): Promise<Stripe.Subscription> {\n  const subscription = await stripe.subscriptions.create({\n    customer: customerId,\n    items: [{ price: priceId }],\n    payment_behavior: 'default_incomplete',\n    expand: ['latest_invoice.payment_intent'],\n  });\n\n  return subscription;\n}\n\n// Type-safe event handling\nasync function handleWebhook(\n  body: string | Buffer,\n  signature: string\n): Promise<void> {\n  const event = stripe.webhooks.constructEvent(\n    body,\n    signature,\n    process.env.STRIPE_WEBHOOK_SECRET!\n  );\n\n  switch (event.type) {\n    case 'payment_intent.succeeded': {\n      const paymentIntent = event.data.object as Stripe.PaymentIntent;\n      console.log(`PaymentIntent ${paymentIntent.id} succeeded`);\n      break;\n    }\n    case 'customer.subscription.updated': {\n      const subscription = event.data.object as Stripe.Subscription;\n      console.log(`Subscription ${subscription.id} updated`);\n      break;\n    }\n    default:\n      console.log(`Unhandled event type: ${event.type}`);\n  }\n}\n\n// Custom types for your domain\ninterface CreatePaymentParams {\n  amount: number;\n  currency: string;\n  customerId?: string;\n  metadata?: Record<string, string>;\n}\n\nasync function createPayment(\n  params: CreatePaymentParams\n): Promise<Stripe.PaymentIntent> {\n  return await stripe.paymentIntents.create({\n    amount: params.amount,\n    currency: params.currency,\n    customer: params.customerId,\n    metadata: params.metadata,\n  });\n}\n```\n\n## 6. Production Checklist\n\n### Pre-Launch Verification\n\n- [ ] Switched from test keys to live keys\n- [ ] Environment variables properly configured in production\n- [ ] Webhook endpoints registered and verified in Stripe Dashboard\n- [ ] Webhook signature verification implemented\n- [ ] HTTPS enabled on all endpoints\n- [ ] Error handling and logging configured\n- [ ] Rate limiting implemented\n- [ ] Idempotency keys used for critical operations\n- [ ] Payment confirmation flow tested end-to-end\n- [ ] Refund process tested\n- [ ] Subscription lifecycle tested (create, update, cancel)\n- [ ] Tax calculation configured (if applicable)\n- [ ] Email receipts enabled\n- [ ] Monitoring and alerting set up\n- [ ] PCI compliance requirements met\n- [ ] Terms of service and privacy policy updated\n- [ ] Customer support process for payment issues established\n\n### Monitoring\n\n```javascript\n// Monitor key metrics\nconst metrics = {\n  paymentIntentsCreated: 0,\n  paymentIntentsSucceeded: 0,\n  paymentIntentsFailed: 0,\n  webhooksProcessed: 0,\n  webhooksFailed: 0,\n  apiErrors: 0,\n};\n\n// Increment metrics in your code\napp.post('/create-payment', async (req, res) => {\n  metrics.paymentIntentsCreated++;\n\n  try {\n    const paymentIntent = await stripe.paymentIntents.create({\n      amount: req.body.amount,\n      currency: 'usd',\n    });\n\n    return res.json(paymentIntent);\n  } catch (err) {\n    metrics.apiErrors++;\n    logger.error('Payment creation failed', { error: err });\n    return res.status(500).json({ error: 'Payment failed' });\n  }\n});\n\n// Expose metrics endpoint\napp.get('/metrics', (req, res) => {\n  res.json(metrics);\n});\n```\n\n### Disaster Recovery\n\n```javascript\n// Implement graceful degradation\nasync function createPaymentWithFallback(params) {\n  try {\n    return await stripe.paymentIntents.create(params);\n  } catch (err) {\n    // Log error\n    logger.error('Stripe API error', { error: err });\n\n    // If Stripe is down, queue for later processing\n    if (err.type === 'StripeAPIError' || err.type === 'StripeConnectionError') {\n      await queuePaymentForLater(params);\n      return { status: 'queued', message: 'Payment will be processed shortly' };\n    }\n\n    throw err;\n  }\n}\n```\n\n---\n\n**Notes**\n\nThe Stripe API provides a comprehensive platform for payment processing, subscription management, and billing. The Node.js library (`stripe`) offers server-side functionality, while `@stripe/stripe-js` and `@stripe/react-stripe-js` provide client-side integration capabilities. Stripe uses date-based API versioning to ensure long-term compatibility while continuously adding new features. All payment data must be transmitted securely using HTTPS, and sensitive card information should only be handled by Stripe.js on the client side to maintain PCI compliance. Webhooks are essential for production deployments as they provide reliable event notifications independent of user sessions. The platform supports multiple payment methods, currencies, and billing models, making it suitable for businesses of all sizes. Always use test mode during development and thoroughly test your integration before switching to live mode.\n"
  },
  {
    "path": "content/structlog/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"structlog package guide for Python projects using structured logging with structlog 25.5.0\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"structlog,logging,structured-logging,json,observability,python\"\n---\n\n# structlog Python Package Guide\n\n## Golden Rule\n\nUse `structlog` to build structured event dictionaries and configure it explicitly during application startup. Pick one rendering strategy per environment: colorful `ConsoleRenderer` for local development, or JSON / stdlib integration for production. Do not treat the zero-config defaults as a stable production contract.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"structlog==25.5.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"structlog==25.5.0\"\npoetry add \"structlog==25.5.0\"\n```\n\nOptional development helpers from the official docs:\n\n```bash\npython -m pip install rich\npython -m pip install better-exceptions\n```\n\nIf you want colored console output on Windows, also install:\n\n```bash\npython -m pip install colorama\n```\n\n## Authentication And Environment\n\n`structlog` is a logging library, so there is no authentication setup. The practical environment choices are:\n\n- where logs are written: stdout, stderr, files, or stdlib handlers\n- how logs are rendered: console, JSON, or stdlib formatter output\n- whether request-scoped context is carried using `contextvars`\n\n## Quick Start\n\nThe default configuration is intentionally convenient:\n\n```python\nimport structlog\n\nlog = structlog.get_logger()\nlog.info(\"user_login\", user_id=42, plan=\"pro\")\n```\n\nThat is useful for quick experiments, but for real applications you should configure processors, log level filtering, timestamps, exception rendering, and the output path yourself.\n\n## Recommended Explicit Setup\n\nThis is a good production baseline when you want JSON logs directly from structlog:\n\n```python\nimport logging\n\nimport structlog\n\nstructlog.configure(\n    cache_logger_on_first_use=True,\n    wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),\n    processors=[\n        structlog.contextvars.merge_contextvars,\n        structlog.processors.add_log_level,\n        structlog.processors.format_exc_info,\n        structlog.processors.TimeStamper(fmt=\"iso\", utc=True),\n        structlog.processors.JSONRenderer(),\n    ],\n    logger_factory=structlog.WriteLoggerFactory(),\n)\n\nlog = structlog.get_logger().bind(service=\"billing-api\")\nlog.info(\"startup_complete\", version=\"2026.03.12\")\n```\n\nWhat this gives you:\n\n- per-request context support via `contextvars`\n- cheap level filtering before expensive rendering work\n- ISO 8601 UTC timestamps\n- exceptions serialized into an `exception` field\n- JSON log lines written directly by structlog\n\nIf you switch `JSONRenderer` to a serializer that returns `bytes` such as `orjson.dumps`, use `structlog.BytesLoggerFactory()` instead of `WriteLoggerFactory()`.\n\n## Core Usage\n\n### Bind context once and reuse the logger\n\n```python\nimport structlog\n\nlog = structlog.get_logger().bind(service=\"api\", region=\"us-west-2\")\n\ndef create_user(user_id: str) -> None:\n    user_log = log.bind(user_id=user_id)\n    user_log.info(\"create_user_started\")\n    user_log.info(\"create_user_finished\")\n```\n\n`bind()` returns a new logger with extra context. Keep the returned logger if you want those fields on later log lines.\n\n### Log exceptions\n\n```python\nimport structlog\n\nlog = structlog.get_logger()\n\ntry:\n    1 / 0\nexcept ZeroDivisionError:\n    log.exception(\"calculation_failed\", operation=\"divide\")\n```\n\nFor machine-readable output, keep `structlog.processors.format_exc_info` or `structlog.processors.dict_tracebacks` in the processor chain. Use `dict_tracebacks` when downstream systems want structured traceback data instead of a flat string.\n\n### Async logging methods\n\n```python\nimport asyncio\nimport structlog\n\nlog = structlog.get_logger()\n\nasync def main() -> None:\n    await log.ainfo(\"job_started\", job_id=\"sync-users\")\n\nasyncio.run(main())\n```\n\nThe `a...` methods offload log processing to a thread pool so your event loop does not block on formatting, but they add overhead. Use them deliberately, not everywhere by default.\n\n## Request Context With `contextvars`\n\nFor web apps and async services, follow the official `contextvars` flow:\n\n```python\nimport structlog\nfrom structlog.contextvars import bind_contextvars, clear_contextvars\n\nlog = structlog.get_logger()\n\ndef handle_request(request_id: str) -> None:\n    clear_contextvars()\n    bind_contextvars(request_id=request_id)\n\n    log.info(\"request_started\")\n```\n\nImportant behavior from the official docs:\n\n- `structlog.contextvars.merge_contextvars` should be the first processor\n- clear context at the start of each request or job\n- prefer `bind_contextvars()` / `unbind_contextvars()` for global request context\n- sync and async contexts are isolated in hybrid apps, so values bound in one may not appear in the other\n\n## Standard Library Integration\n\nIf the application already depends on `logging`, the quickest official path is `structlog.stdlib.recreate_defaults()`:\n\n```python\nimport logging\nimport sys\n\nimport structlog\n\nlogging.basicConfig(\n    format=\"%(message)s\",\n    stream=sys.stdout,\n    level=logging.INFO,\n)\n\nstructlog.stdlib.recreate_defaults()\n\nlog = structlog.get_logger(__name__)\nlog.info(\"service_ready\", port=8080)\n```\n\nFor more control, build a stdlib-specific processor chain and end it with `structlog.stdlib.render_to_log_kwargs`. When you do that, the stdlib formatter must render the extra fields, otherwise you will only see the event text and it will look like structlog \"lost\" your context.\n\nUse `structlog.stdlib.get_logger()` when you want stdlib-compatible type hints on the returned logger.\n\n## Console Output For Development\n\n`structlog.dev.ConsoleRenderer` is the default development renderer. In `25.5.0`, the active renderer became easier to inspect and mutate:\n\n```python\nimport structlog\n\ncr = structlog.dev.ConsoleRenderer.get_active()\ncr.exception_formatter = structlog.dev.plain_traceback\n```\n\nUse this only for local development ergonomics. If you want pretty exceptions with Rich or `better-exceptions`, do not keep `structlog.processors.format_exc_info` in the processor chain, because `ConsoleRenderer` expects to format `exc_info` itself.\n\n## Common Pitfalls\n\n- Do not rely on the default configuration for long-lived application behavior. The maintainers explicitly reserve the right to improve defaults and `structlog.dev`.\n- `bind()` returns a new logger. If you ignore the return value, your new context is not retained.\n- If you use `cache_logger_on_first_use=True`, later `structlog.configure()` calls do not affect already-cached loggers.\n- Cached loggers are not pickleable, so avoid that option if you pass loggers through `multiprocessing`.\n- `structlog.threadlocal` is deprecated. Prefer `structlog.contextvars` for new code.\n- In stdlib integration, `render_to_log_kwargs` only prepares `extra`; your `logging` formatter still has to output it.\n- Pretty console exception formatting and `format_exc_info` conflict. Use one strategy or the other.\n- Async `a...` logging methods prevent event-loop blocking but cost more per log entry.\n\n## Version-Sensitive Notes For `25.5.0`\n\n- `25.5.0` adds the newer `ConsoleRenderer.get_active()` ergonomics and mutable console-renderer configuration for development workflows.\n- The `ConsoleRenderer(width=-1)` convention is deprecated in `25.5.0`; use `None` instead.\n- `structlog.stdlib.AsyncBoundLogger` remains deprecated. Prefer the `await logger.ainfo(...)` style async methods on normal bound loggers.\n- `structlog.threadlocal` has been deprecated since `22.1.0` in favor of `contextvars`, but the module still exists in `25.5.0` as a compatibility fallback.\n\n## Official References\n\n- Stable docs: `https://www.structlog.org/en/stable/`\n- Getting started: `https://www.structlog.org/en/stable/getting-started.html`\n- Standard library logging: `https://www.structlog.org/en/stable/standard-library.html`\n- Context variables: `https://www.structlog.org/en/stable/contextvars.html`\n- Console output: `https://www.structlog.org/en/stable/console-output.html`\n- Exceptions: `https://www.structlog.org/en/stable/exceptions.html`\n- Performance: `https://www.structlog.org/en/stable/performance.html`\n- Deprecated thread-local API: `https://www.structlog.org/en/stable/thread-local.html`\n- PyPI: `https://pypi.org/project/structlog/`\n"
  },
  {
    "path": "content/styled-components/docs/styled-components/javascript/DOC.md",
    "content": "---\nname: styled-components\ndescription: \"CSS-in-JS for React with styled elements, theming, global styles, and server-side rendering support.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.3.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"styled-components,react,css-in-js,styling,theme,ssr\"\n---\n\n# styled-components Guide (JavaScript)\n\n## Golden Rule\n\nUse `styled-components` to create styled React components with tagged template literals. Define styled components at module scope, not inside render functions, so React does not recreate component classes on every render.\n\n`styled-components` does not need API keys, environment variables, or client initialization. Install it, import the APIs you need, and render your components normally.\n\n## Install\n\nInstall `styled-components` in the same app that renders your React components.\n\n```bash\nnpm install styled-components\n```\n\nFor web apps, you also need React and React DOM:\n\n```bash\nnpm install react react-dom styled-components\n```\n\n## Basic usage\n\nImport the default `styled` factory and create styled elements or wrappers around your own React components.\n\n```jsx\nimport styled from \"styled-components\";\n\nconst Page = styled.main`\n  max-width: 48rem;\n  margin: 0 auto;\n  padding: 2rem;\n`;\n\nconst Button = styled.button`\n  border: 0;\n  border-radius: 9999px;\n  padding: 0.75rem 1rem;\n  font: inherit;\n  color: white;\n  background: #7c3aed;\n  cursor: pointer;\n\n  &:hover {\n    background: #6d28d9;\n  }\n`;\n\nexport function App() {\n  return (\n    <Page>\n      <h1>styled-components</h1>\n      <Button>Save changes</Button>\n    </Page>\n  );\n}\n```\n\n## Pass styling props safely\n\nFor props that only exist to control styling, use transient props with a `$` prefix. They are available in your styles but are not forwarded to the underlying DOM element.\n\n```jsx\nimport styled from \"styled-components\";\n\nconst Alert = styled.div`\n  padding: 1rem;\n  border-radius: 0.5rem;\n  color: white;\n  background: ${({ $tone }) => ($tone === \"danger\" ? \"#dc2626\" : \"#2563eb\")};\n`;\n\nexport function Banner() {\n  return <Alert $tone=\"danger\">Something went wrong.</Alert>;\n}\n```\n\nThis is the simplest way to avoid React warnings about unknown DOM props in `styled-components` v6.\n\n## Theme an app with `ThemeProvider`\n\nWrap your app with `ThemeProvider` to expose a shared theme object to styled components.\n\n```jsx\nimport styled, { ThemeProvider } from \"styled-components\";\n\nconst theme = {\n  colors: {\n    background: \"#111827\",\n    surface: \"#1f2937\",\n    text: \"#f9fafb\",\n    accent: \"#22c55e\",\n  },\n  space: {\n    sm: \"0.5rem\",\n    md: \"1rem\",\n    lg: \"1.5rem\",\n  },\n};\n\nconst Card = styled.section`\n  padding: ${({ theme }) => theme.space.lg};\n  border-radius: 0.75rem;\n  color: ${({ theme }) => theme.colors.text};\n  background: ${({ theme }) => theme.colors.surface};\n`;\n\nconst AccentText = styled.span`\n  color: ${({ theme }) => theme.colors.accent};\n`;\n\nexport function App() {\n  return (\n    <ThemeProvider theme={theme}>\n      <Card>\n        Status: <AccentText>healthy</AccentText>\n      </Card>\n    </ThemeProvider>\n  );\n}\n```\n\n## Add global CSS with `createGlobalStyle`\n\nUse `createGlobalStyle` for resets, font rules, and app-wide CSS variables.\n\n```jsx\nimport styled, { ThemeProvider, createGlobalStyle } from \"styled-components\";\n\nconst theme = {\n  colors: {\n    background: \"#0f172a\",\n    text: \"#e2e8f0\",\n  },\n};\n\nconst GlobalStyle = createGlobalStyle`\n  * {\n    box-sizing: border-box;\n  }\n\n  html,\n  body,\n  #root {\n    min-height: 100%;\n  }\n\n  body {\n    margin: 0;\n    font-family: Inter, system-ui, sans-serif;\n    color: ${({ theme }) => theme.colors.text};\n    background: ${({ theme }) => theme.colors.background};\n  }\n`;\n\nconst Layout = styled.main`\n  padding: 2rem;\n`;\n\nexport function App() {\n  return (\n    <ThemeProvider theme={theme}>\n      <GlobalStyle />\n      <Layout>Dashboard</Layout>\n    </ThemeProvider>\n  );\n}\n```\n\n## Reuse style fragments with `css`, `keyframes`, and `attrs`\n\nUse helpers when you want shared fragments, animations, or default props.\n\n```jsx\nimport styled, { css, keyframes } from \"styled-components\";\n\nconst interactive = css`\n  border: 0;\n  border-radius: 0.5rem;\n  font: inherit;\n  cursor: pointer;\n`;\n\nconst fadeIn = keyframes`\n  from {\n    opacity: 0;\n    transform: translateY(4px);\n  }\n\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n`;\n\nconst Input = styled.input.attrs({\n  type: \"email\",\n  autoComplete: \"email\",\n})`\n  ${interactive}\n  width: 100%;\n  padding: 0.75rem 1rem;\n  border: 1px solid #cbd5e1;\n  background: white;\n`;\n\nconst Toast = styled.div`\n  ${interactive}\n  padding: 0.75rem 1rem;\n  color: white;\n  background: #0f766e;\n  animation: ${fadeIn} 160ms ease-out;\n`;\n```\n\n## Server-side rendering with `ServerStyleSheet`\n\nFor classic server rendering, collect styles during `renderToString(...)`, inject them into the HTML response, and always call `sheet.seal()` in a `finally` block.\n\n```jsx\nimport React from \"react\";\nimport { renderToString } from \"react-dom/server\";\nimport { ServerStyleSheet } from \"styled-components\";\nimport { App } from \"./App.jsx\";\n\nexport function renderPage() {\n  const sheet = new ServerStyleSheet();\n\n  try {\n    const html = renderToString(sheet.collectStyles(<App />));\n    const styleTags = sheet.getStyleTags();\n\n    return `<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    ${styleTags}\n    <title>styled-components SSR</title>\n  </head>\n  <body>\n    <div id=\"root\">${html}</div>\n  </body>\n</html>`;\n  } finally {\n    sheet.seal();\n  }\n}\n```\n\nIf you need React elements instead of raw HTML strings, use `sheet.getStyleElement()`.\n\n## Restore v5-style prop filtering or vendor prefixes with `StyleSheetManager`\n\nIn v6, `styled-components` no longer automatically filters unknown props for DOM elements, and vendor prefixes are omitted by default. Use `StyleSheetManager` when you need to customize either behavior.\n\n```jsx\nimport isPropValid from \"@emotion/is-prop-valid\";\nimport { StyleSheetManager } from \"styled-components\";\n\nfunction shouldForwardProp(propName, target) {\n  if (typeof target === \"string\") {\n    return isPropValid(propName);\n  }\n\n  return true;\n}\n\nexport function AppProviders({ children }) {\n  return (\n    <StyleSheetManager\n      enableVendorPrefixes\n      shouldForwardProp={shouldForwardProp}\n    >\n      {children}\n    </StyleSheetManager>\n  );\n}\n```\n\nInstall `@emotion/is-prop-valid` only if you choose this prop-filtering approach:\n\n```bash\nnpm install @emotion/is-prop-valid\n```\n\nPrefer transient props like `$tone` and `$size` when you only need to prevent style-only props from reaching the DOM.\n\n## Important pitfalls\n\n- Define styled components outside React render functions.\n- Use transient props or `StyleSheetManager.shouldForwardProp` for style-only props on DOM elements.\n- Call `sheet.seal()` after SSR collection, even when rendering throws.\n- If you use Stylis plugins in v6, make sure they are compatible with Stylis v4.\n- Use `styled-components/native` instead of `styled-components` when styling React Native primitives.\n\n## Version notes\n\n- This guide targets `styled-components@6.3.11`.\n- In v6, automatic DOM prop filtering is no longer the default.\n- In v6, vendor prefixes are disabled by default and can be re-enabled with `StyleSheetManager enableVendorPrefixes`.\n"
  },
  {
    "path": "content/stytch/docs/auth/javascript/DOC.md",
    "content": "---\nname: auth\ndescription: \"Stytch Node.js SDK authentication guide for passwordless and OTP-based authentication\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.43.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"stytch,auth,authentication,passwordless,otp\"\n---\n\n# Stytch Node.js SDK - Authentication Guide\n\n## Golden Rule\n\n**ALWAYS use the official `stytch` package from npm.**\n\n```bash\nnpm install stytch\n```\n\n**Current version: 12.43.0**\n\n**DO NOT use:**\n- Deprecated `@stytch/stytch-js` (deprecated in favor of `@stytch/vanilla-js` for frontend)\n- Any unofficial or outdated Stytch packages\n- Frontend packages (`@stytch/vanilla-js`, `@stytch/react`, `@stytch/nextjs`) when building backend services\n\nThe `stytch` package is the official backend SDK for Node.js applications. It supports TypeScript and all current LTS versions of Node.js (18+).\n\n---\n\n## Installation\n\n### Install the SDK\n\n```bash\nnpm install stytch\n```\n\nor\n\n```bash\nyarn add stytch\n```\n\n### Environment Variables\n\nSet up your Stytch credentials in your environment:\n\n```bash\nSTYTCH_PROJECT_ID=project-live-your-project-id\nSTYTCH_SECRET=secret-live-your-secret-key\n```\n\n**Get credentials from:** [Stytch Dashboard](https://stytch.com/dashboard)\n\nFor testing, use test environment credentials:\n\n```bash\nSTYTCH_PROJECT_ID=project-test-your-project-id\nSTYTCH_SECRET=secret-test-your-secret-key\n```\n\n### .env File Example\n\n```env\nSTYTCH_PROJECT_ID=project-live-c60c0abe-c25a-4472-a9ed-320c6667d317\nSTYTCH_SECRET=secret-live-80JASucyk7z_G8Z-7dVwZVGXL5NT_qGAQ2I=\n```\n\n---\n\n## Initialization\n\n### Basic B2C Client\n\n```javascript\nconst stytch = require('stytch');\n\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n});\n```\n\n### ES6 Module Import\n\n```javascript\nimport * as stytch from 'stytch';\n\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n});\n```\n\n### B2B Client (for organizations)\n\n```javascript\nconst stytch = require('stytch');\n\nconst b2bClient = new stytch.B2BClient({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n});\n```\n\n### Client with Environment Override\n\n```javascript\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n  environment: 'test', // or 'live' (default)\n});\n```\n\n### Full Configuration Options\n\n```javascript\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n  environment: 'live',\n  timeout: 30000, // Request timeout in milliseconds\n});\n```\n\n---\n\n## Core API Surfaces\n\n### 1. Magic Links\n\nMagic links provide passwordless authentication via email.\n\n#### Send Magic Link (Login or Create)\n\n```javascript\n// Minimal example\nconst response = await client.magicLinks.email.loginOrCreate({\n  email: 'user@example.com',\n});\n\nconsole.log(response.user_id);\nconsole.log(response.email_id);\n```\n\n#### Send Magic Link with Custom URLs\n\n```javascript\nconst response = await client.magicLinks.email.loginOrCreate({\n  email: 'user@example.com',\n  login_magic_link_url: 'https://example.com/authenticate?token={{token}}',\n  signup_magic_link_url: 'https://example.com/authenticate?token={{token}}',\n  login_expiration_minutes: 15,\n  signup_expiration_minutes: 60,\n});\n```\n\n#### Advanced Magic Link with Options\n\n```javascript\nconst response = await client.magicLinks.email.loginOrCreate({\n  email: 'user@example.com',\n  login_magic_link_url: 'https://example.com/authenticate',\n  signup_magic_link_url: 'https://example.com/authenticate',\n  login_expiration_minutes: 15,\n  signup_expiration_minutes: 60,\n  login_template_id: 'custom-login-template',\n  signup_template_id: 'custom-signup-template',\n  attributes: {\n    ip_address: '192.168.1.1',\n  },\n  code_challenge: 'challenge_string', // For PKCE flow\n  user_id: 'user-123', // Associate with existing user\n  session_duration_minutes: 60,\n});\n```\n\n#### Authenticate Magic Link\n\n```javascript\n// Minimal example\nconst response = await client.magicLinks.authenticate({\n  token: 'DOYoip3rvIMMW5lgItikFK-Ak1CfMsgjuiCyI7uuU94=',\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\nconsole.log(response.session_jwt);\n```\n\n#### Authenticate with Session Options\n\n```javascript\nconst response = await client.magicLinks.authenticate({\n  token: 'DOYoip3rvIMMW5lgItikFK-Ak1CfMsgjuiCyI7uuU94=',\n  session_duration_minutes: 60,\n  session_custom_claims: {\n    custom_claim: 'value',\n  },\n  attributes: {\n    ip_address: '192.168.1.1',\n    user_agent: 'Mozilla/5.0...',\n  },\n});\n```\n\n#### Send Magic Link Only (No Auto-Create)\n\n```javascript\nconst response = await client.magicLinks.email.send({\n  email: 'user@example.com',\n  login_magic_link_url: 'https://example.com/authenticate',\n  login_expiration_minutes: 15,\n});\n```\n\n#### Create Embeddable Magic Link\n\n```javascript\nconst response = await client.magicLinks.email.createEmbeddable({\n  user_id: 'user-live-123',\n  embeddable_magic_link_url: 'https://example.com/authenticate',\n  expiration_minutes: 10,\n});\n\nconsole.log(response.token); // Use in your own emails\n```\n\n---\n\n### 2. One-Time Passcodes (OTP)\n\n#### SMS OTP\n\n**Send OTP via SMS:**\n\n```javascript\n// Minimal example\nconst response = await client.otps.sms.send({\n  phone_number: '+15555555555',\n});\n\nconsole.log(response.phone_id);\n```\n\n**Send OTP with Options:**\n\n```javascript\nconst response = await client.otps.sms.send({\n  phone_number: '+15555555555',\n  expiration_minutes: 10,\n  attributes: {\n    ip_address: '192.168.1.1',\n  },\n  user_id: 'user-123', // Associate with existing user\n});\n```\n\n**Authenticate SMS OTP:**\n\n```javascript\n// Minimal example\nconst response = await client.otps.authenticate({\n  method_id: 'phone-id-123',\n  code: '123456',\n});\n```\n\n**Authenticate with Session:**\n\n```javascript\nconst response = await client.otps.authenticate({\n  method_id: 'phone-id-123',\n  code: '123456',\n  session_duration_minutes: 60,\n  attributes: {\n    ip_address: '192.168.1.1',\n  },\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n#### Email OTP\n\n**Send OTP via Email:**\n\n```javascript\n// Minimal example\nconst response = await client.otps.email.send({\n  email: 'user@example.com',\n});\n```\n\n**Send with Options:**\n\n```javascript\nconst response = await client.otps.email.send({\n  email: 'user@example.com',\n  expiration_minutes: 10,\n  login_template_id: 'custom-template',\n  user_id: 'user-123',\n});\n```\n\n**Authenticate Email OTP:**\n\n```javascript\nconst response = await client.otps.authenticate({\n  method_id: 'email-id-123',\n  code: '123456',\n  session_duration_minutes: 60,\n});\n```\n\n#### WhatsApp OTP\n\n**Send OTP via WhatsApp:**\n\n```javascript\nconst response = await client.otps.whatsapp.send({\n  phone_number: '+15555555555',\n});\n```\n\n**Authenticate WhatsApp OTP:**\n\n```javascript\nconst response = await client.otps.authenticate({\n  method_id: 'phone-id-123',\n  code: '123456',\n});\n```\n\n#### Login or Create User with SMS\n\n```javascript\nconst response = await client.otps.sms.loginOrCreate({\n  phone_number: '+15555555555',\n  expiration_minutes: 10,\n});\n```\n\n#### Login or Create User with Email\n\n```javascript\nconst response = await client.otps.email.loginOrCreate({\n  email: 'user@example.com',\n  expiration_minutes: 10,\n});\n```\n\n---\n\n### 3. OAuth\n\nOAuth enables authentication via third-party providers.\n\n#### Start OAuth Flow\n\n```javascript\n// Get OAuth authorization URL\nconst response = await client.oauth.start({\n  provider: 'google',\n  signup_redirect_url: 'https://example.com/authenticate',\n  login_redirect_url: 'https://example.com/authenticate',\n});\n\nconsole.log(response.oauth_url); // Redirect user here\n```\n\n#### Start OAuth with Options\n\n```javascript\nconst response = await client.oauth.start({\n  provider: 'google',\n  signup_redirect_url: 'https://example.com/authenticate',\n  login_redirect_url: 'https://example.com/authenticate',\n  custom_scopes: ['https://www.googleapis.com/auth/calendar.readonly'],\n  provider_params: {\n    access_type: 'offline',\n  },\n  code_challenge: 'challenge_string', // For PKCE\n});\n```\n\n#### Authenticate OAuth\n\n```javascript\n// Minimal example\nconst response = await client.oauth.authenticate({\n  token: 'oauth-token-from-callback',\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n#### Authenticate with Session Options\n\n```javascript\nconst response = await client.oauth.authenticate({\n  token: 'oauth-token-from-callback',\n  session_duration_minutes: 60,\n  session_custom_claims: {\n    custom_claim: 'value',\n  },\n});\n```\n\n#### Supported OAuth Providers\n\n- `google`\n- `microsoft`\n- `facebook`\n- `github`\n- `gitlab`\n- `slack`\n- `linkedin`\n- `amazon`\n- `bitbucket`\n- `coinbase`\n- `discord`\n- `figma`\n- `hubspot`\n- `salesforce`\n- `shopify`\n- `snapchat`\n- `tiktok`\n- `twitch`\n- `twitter`\n- `yahoo`\n\n---\n\n### 4. Sessions\n\nSessions manage authenticated user state.\n\n#### Authenticate Session\n\n```javascript\n// Minimal example\nconst response = await client.sessions.authenticate({\n  session_token: 'session-token-here',\n});\n\nconsole.log(response.user);\nconsole.log(response.session); // Contains session data\n```\n\n#### Authenticate with JWT\n\n```javascript\nconst response = await client.sessions.authenticateJwt({\n  session_jwt: 'jwt-token-here',\n});\n```\n\n#### Authenticate Session with Refresh\n\n```javascript\nconst response = await client.sessions.authenticate({\n  session_token: 'session-token-here',\n  session_duration_minutes: 60, // Extend session\n});\n\n// Store new token\nconst newSessionToken = response.session_token;\n```\n\n#### Get Session\n\n```javascript\nconst response = await client.sessions.get({\n  user_id: 'user-123',\n});\n\nconsole.log(response.sessions); // All active sessions\n```\n\n#### Revoke Session\n\n```javascript\nawait client.sessions.revoke({\n  session_token: 'session-token-to-revoke',\n});\n```\n\n#### Revoke Session by ID\n\n```javascript\nawait client.sessions.revoke({\n  session_id: 'session-id-123',\n});\n```\n\n#### Migrate Session\n\n```javascript\nconst response = await client.sessions.migrate({\n  session_token: 'old-session-token',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.session_token); // New token\n```\n\n---\n\n### 5. Users\n\nManage user accounts and data.\n\n#### Get User\n\n```javascript\nconst response = await client.users.get({\n  user_id: 'user-123',\n});\n\nconsole.log(response.user);\nconsole.log(response.user.emails);\nconsole.log(response.user.phone_numbers);\n```\n\n#### Create User\n\n```javascript\nconst response = await client.users.create({\n  email: 'user@example.com',\n  name: {\n    first_name: 'John',\n    last_name: 'Doe',\n  },\n});\n```\n\n#### Create User with Multiple Methods\n\n```javascript\nconst response = await client.users.create({\n  email: 'user@example.com',\n  phone_number: '+15555555555',\n  name: {\n    first_name: 'John',\n    last_name: 'Doe',\n  },\n  attributes: {\n    custom_attribute: 'value',\n  },\n});\n```\n\n#### Update User\n\n```javascript\nconst response = await client.users.update({\n  user_id: 'user-123',\n  name: {\n    first_name: 'Jane',\n    last_name: 'Smith',\n  },\n  attributes: {\n    custom_field: 'new_value',\n  },\n});\n```\n\n#### Delete User\n\n```javascript\nawait client.users.delete({\n  user_id: 'user-123',\n});\n```\n\n#### Search Users\n\n```javascript\n// Basic search\nconst response = await client.users.search({\n  query: {\n    operator: 'AND',\n    operands: [\n      {\n        filter_name: 'status',\n        filter_value: ['active'],\n      },\n    ],\n  },\n});\n\nconsole.log(response.results);\n```\n\n#### Advanced User Search\n\n```javascript\nconst response = await client.users.search({\n  query: {\n    operator: 'AND',\n    operands: [\n      {\n        filter_name: 'email_verified',\n        filter_value: [true],\n      },\n      {\n        filter_name: 'created_at',\n        filter_value: {\n          greater_than: '2024-01-01T00:00:00Z',\n        },\n      },\n    ],\n  },\n  limit: 100,\n  cursor: 'cursor-from-previous-request',\n});\n```\n\n#### Delete Email\n\n```javascript\nawait client.users.deleteEmail({\n  email_id: 'email-id-123',\n});\n```\n\n#### Delete Phone Number\n\n```javascript\nawait client.users.deletePhoneNumber({\n  phone_id: 'phone-id-123',\n});\n```\n\n---\n\n### 6. Passwords\n\nTraditional password authentication.\n\n#### Create Password\n\n```javascript\nconst response = await client.passwords.create({\n  email: 'user@example.com',\n  password: 'SecurePassword123!',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n#### Authenticate Password\n\n```javascript\n// Minimal example\nconst response = await client.passwords.authenticate({\n  email: 'user@example.com',\n  password: 'SecurePassword123!',\n});\n```\n\n#### Authenticate with Session\n\n```javascript\nconst response = await client.passwords.authenticate({\n  email: 'user@example.com',\n  password: 'SecurePassword123!',\n  session_duration_minutes: 60,\n  session_custom_claims: {\n    custom_claim: 'value',\n  },\n});\n\nconsole.log(response.session_token);\n```\n\n#### Strength Check\n\n```javascript\nconst response = await client.passwords.strengthCheck({\n  email: 'user@example.com',\n  password: 'password-to-check',\n});\n\nconsole.log(response.valid_password);\nconsole.log(response.score);\nconsole.log(response.breached_password);\nconsole.log(response.strength_policy);\nconsole.log(response.breach_detection_on_create);\n```\n\n#### Initiate Password Reset\n\n```javascript\nconst response = await client.passwords.email.resetStart({\n  email: 'user@example.com',\n  reset_password_redirect_url: 'https://example.com/reset',\n  reset_password_expiration_minutes: 30,\n});\n```\n\n#### Reset Password by Email\n\n```javascript\nconst response = await client.passwords.email.reset({\n  token: 'reset-token-from-email',\n  password: 'NewSecurePassword123!',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n#### Reset Password by Session\n\n```javascript\nconst response = await client.passwords.session.reset({\n  session_token: 'active-session-token',\n  password: 'NewSecurePassword123!',\n});\n```\n\n#### Migrate Password (from existing system)\n\n```javascript\nconst response = await client.passwords.migrate({\n  email: 'user@example.com',\n  hash: '$2a$10$...', // bcrypt hash\n  hash_type: 'bcrypt',\n  name: {\n    first_name: 'John',\n    last_name: 'Doe',\n  },\n});\n```\n\n---\n\n### 7. WebAuthn\n\nPasswordless authentication using biometrics or security keys.\n\n#### Register WebAuthn Start\n\n```javascript\nconst response = await client.webauthn.registerStart({\n  user_id: 'user-123',\n  domain: 'example.com',\n  authenticator_type: 'platform', // or 'cross-platform'\n});\n\nconsole.log(response.public_key_credential_creation_options);\n```\n\n#### Register WebAuthn Finish\n\n```javascript\nconst response = await client.webauthn.register({\n  user_id: 'user-123',\n  public_key_credential: 'credential-from-client',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.webauthn_registration_id);\nconsole.log(response.session_token);\n```\n\n#### Authenticate WebAuthn Start\n\n```javascript\nconst response = await client.webauthn.authenticateStart({\n  domain: 'example.com',\n  user_id: 'user-123', // Optional\n});\n\nconsole.log(response.public_key_credential_request_options);\n```\n\n#### Authenticate WebAuthn Finish\n\n```javascript\nconst response = await client.webauthn.authenticate({\n  public_key_credential: 'credential-from-client',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n#### Update WebAuthn\n\n```javascript\nconst response = await client.webauthn.update({\n  webauthn_registration_id: 'webauthn-reg-id-123',\n  name: 'My Fingerprint',\n});\n```\n\n---\n\n### 8. TOTP (Time-based One-Time Passwords)\n\n#### Create TOTP\n\n```javascript\nconst response = await client.totps.create({\n  user_id: 'user-123',\n  expiration_minutes: 10,\n});\n\nconsole.log(response.secret);\nconsole.log(response.qr_code); // URL for QR code image\nconsole.log(response.recovery_codes);\n```\n\n#### Authenticate TOTP\n\n```javascript\nconst response = await client.totps.authenticate({\n  user_id: 'user-123',\n  totp_code: '123456',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.session_token);\n```\n\n#### Get TOTPs\n\n```javascript\nconst response = await client.totps.get({\n  user_id: 'user-123',\n});\n\nconsole.log(response.totps);\n```\n\n#### Recover TOTP\n\n```javascript\nconst response = await client.totps.recoveryCodes({\n  user_id: 'user-123',\n  recovery_code: 'recovery-code-string',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.session_token);\n```\n\n---\n\n### 9. Crypto Wallets (Web3)\n\n#### Authenticate Wallet Start\n\n```javascript\nconst response = await client.cryptoWallets.authenticateStart({\n  crypto_wallet_address: '0x1234...',\n  crypto_wallet_type: 'ethereum',\n});\n\nconsole.log(response.challenge);\n```\n\n#### Authenticate Wallet Finish\n\n```javascript\nconst response = await client.cryptoWallets.authenticate({\n  crypto_wallet_address: '0x1234...',\n  crypto_wallet_type: 'ethereum',\n  signature: 'signed-challenge',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.user);\nconsole.log(response.session_token);\n```\n\n---\n\n### 10. M2M (Machine-to-Machine)\n\n#### Authenticate M2M Token\n\n```javascript\nconst response = await client.m2m.authenticateToken({\n  access_token: 'm2m-access-token',\n});\n\nconsole.log(response.member_id);\nconsole.log(response.scopes);\n```\n\n#### Get M2M Client\n\n```javascript\nconst response = await client.m2m.clients.get({\n  client_id: 'client-id-123',\n});\n\nconsole.log(response.m2m_client);\n```\n\n---\n\n## B2B API Surfaces\n\n### 1. Organizations\n\n#### Create Organization\n\n```javascript\nconst response = await b2bClient.organizations.create({\n  organization_name: 'Acme Corp',\n  organization_slug: 'acme',\n  email_allowed_domains: ['acme.com'],\n});\n\nconsole.log(response.organization);\n```\n\n#### Get Organization\n\n```javascript\nconst response = await b2bClient.organizations.get({\n  organization_id: 'org-123',\n});\n\nconsole.log(response.organization);\n```\n\n#### Update Organization\n\n```javascript\nconst response = await b2bClient.organizations.update({\n  organization_id: 'org-123',\n  organization_name: 'Acme Corporation',\n});\n```\n\n#### Delete Organization\n\n```javascript\nawait b2bClient.organizations.delete({\n  organization_id: 'org-123',\n});\n```\n\n---\n\n### 2. Members\n\n#### Create Member\n\n```javascript\nconst response = await b2bClient.organizations.members.create({\n  organization_id: 'org-123',\n  email_address: 'member@acme.com',\n  name: 'John Doe',\n  is_breakglass: false,\n});\n\nconsole.log(response.member);\n```\n\n#### Get Member\n\n```javascript\nconst response = await b2bClient.organizations.members.get({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n});\n\nconsole.log(response.member);\n```\n\n#### Update Member\n\n```javascript\nconst response = await b2bClient.organizations.members.update({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n  name: 'Jane Doe',\n});\n```\n\n#### Delete Member\n\n```javascript\nawait b2bClient.organizations.members.delete({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n});\n```\n\n---\n\n### 3. B2B Magic Links\n\n#### Send B2B Magic Link\n\n```javascript\nconst response = await b2bClient.magicLinks.email.loginOrSignup({\n  organization_id: 'org-123',\n  email_address: 'member@acme.com',\n  login_redirect_url: 'https://acme.com/authenticate',\n  signup_redirect_url: 'https://acme.com/authenticate',\n});\n```\n\n#### Authenticate B2B Magic Link\n\n```javascript\nconst response = await b2bClient.magicLinks.authenticate({\n  magic_links_token: 'token-from-email',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.member);\nconsole.log(response.organization);\nconsole.log(response.session_token);\n```\n\n---\n\n### 4. B2B Sessions\n\n#### Authenticate B2B Session\n\n```javascript\nconst response = await b2bClient.sessions.authenticate({\n  session_token: 'session-token-here',\n});\n\nconsole.log(response.member);\nconsole.log(response.organization);\nconsole.log(response.session);\n```\n\n#### Authenticate B2B JWT\n\n```javascript\nconst response = await b2bClient.sessions.authenticateJwt({\n  session_jwt: 'jwt-token-here',\n});\n```\n\n#### Get B2B Session\n\n```javascript\nconst response = await b2bClient.sessions.get({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n});\n\nconsole.log(response.sessions);\n```\n\n#### Revoke B2B Session\n\n```javascript\nawait b2bClient.sessions.revoke({\n  session_token: 'session-token-to-revoke',\n});\n```\n\n---\n\n### 5. B2B OAuth\n\n#### Start B2B OAuth\n\n```javascript\nconst response = await b2bClient.oauth.start({\n  organization_id: 'org-123',\n  provider: 'google',\n  login_redirect_url: 'https://acme.com/authenticate',\n  signup_redirect_url: 'https://acme.com/authenticate',\n});\n\nconsole.log(response.oauth_url);\n```\n\n#### Authenticate B2B OAuth\n\n```javascript\nconst response = await b2bClient.oauth.authenticate({\n  oauth_token: 'token-from-callback',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.member);\nconsole.log(response.organization);\nconsole.log(response.session_token);\n```\n\n---\n\n### 6. B2B SMS OTP\n\n#### Send B2B SMS OTP\n\n```javascript\nconst response = await b2bClient.otps.sms.send({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n  phone_number: '+15555555555',\n});\n```\n\n#### Authenticate B2B SMS OTP\n\n```javascript\nconst response = await b2bClient.otps.sms.authenticate({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n  code: '123456',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.member);\nconsole.log(response.session_token);\n```\n\n---\n\n### 7. SSO (Single Sign-On)\n\n#### Start SSO\n\n```javascript\nconst response = await b2bClient.sso.start({\n  connection_id: 'sso-connection-123',\n  login_redirect_url: 'https://acme.com/authenticate',\n  signup_redirect_url: 'https://acme.com/authenticate',\n});\n\nconsole.log(response.sso_url);\n```\n\n#### Authenticate SSO\n\n```javascript\nconst response = await b2bClient.sso.authenticate({\n  sso_token: 'token-from-sso-provider',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.member);\nconsole.log(response.organization);\n```\n\n#### Get SSO Connections\n\n```javascript\nconst response = await b2bClient.sso.getConnections({\n  organization_id: 'org-123',\n});\n\nconsole.log(response.saml_connections);\nconsole.log(response.oidc_connections);\n```\n\n#### Create SAML Connection\n\n```javascript\nconst response = await b2bClient.sso.saml.createConnection({\n  organization_id: 'org-123',\n  display_name: 'Acme SAML',\n});\n\nconsole.log(response.connection);\n```\n\n#### Update SAML Connection\n\n```javascript\nconst response = await b2bClient.sso.saml.updateConnection({\n  organization_id: 'org-123',\n  connection_id: 'saml-connection-123',\n  idp_entity_id: 'https://idp.acme.com/entity',\n  idp_sso_url: 'https://idp.acme.com/sso',\n  attribute_mapping: {\n    email: 'email',\n    first_name: 'firstName',\n    last_name: 'lastName',\n  },\n  x509_certificate: 'certificate-string',\n});\n```\n\n#### Create OIDC Connection\n\n```javascript\nconst response = await b2bClient.sso.oidc.createConnection({\n  organization_id: 'org-123',\n  display_name: 'Acme OIDC',\n});\n\nconsole.log(response.connection);\n```\n\n#### Update OIDC Connection\n\n```javascript\nconst response = await b2bClient.sso.oidc.updateConnection({\n  organization_id: 'org-123',\n  connection_id: 'oidc-connection-123',\n  issuer: 'https://idp.acme.com',\n  client_id: 'client-id',\n  client_secret: 'client-secret',\n  authorization_url: 'https://idp.acme.com/authorize',\n  token_url: 'https://idp.acme.com/token',\n  userinfo_url: 'https://idp.acme.com/userinfo',\n});\n```\n\n---\n\n### 8. Discovery\n\nDiscovery allows users to find and join organizations.\n\n#### Create Organization via Discovery\n\n```javascript\nconst response = await b2bClient.discovery.organizations.create({\n  intermediate_session_token: 'token-from-discovery',\n  organization_name: 'New Org',\n  organization_slug: 'new-org',\n  session_duration_minutes: 60,\n});\n\nconsole.log(response.organization);\nconsole.log(response.session_token);\n```\n\n#### List Discovered Organizations\n\n```javascript\nconst response = await b2bClient.discovery.organizations.list({\n  intermediate_session_token: 'token-from-discovery',\n});\n\nconsole.log(response.discovered_organizations);\n```\n\n---\n\n### 9. RBAC (Role-Based Access Control)\n\n#### Check Member Permissions\n\n```javascript\nconst response = await b2bClient.rbac.policy({\n  organization_id: 'org-123',\n  member_id: 'member-123',\n  resource_id: 'document-123',\n  action: 'read',\n});\n\nconsole.log(response.authorized);\n```\n\n---\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\ntry {\n  const response = await client.magicLinks.email.loginOrCreate({\n    email: 'user@example.com',\n  });\n  console.log(response.user_id);\n} catch (error) {\n  console.error('Error:', error.error_type);\n  console.error('Message:', error.error_message);\n  console.error('URL:', error.error_url);\n}\n```\n\n### Detailed Error Handling\n\n```javascript\nconst response = await client.magicLinks.authenticate({\n  token: token,\n}).catch((error) => {\n  if (error.error_type === 'unable_to_auth_magic_link') {\n    // Token invalid, expired, or already used\n    return { error: 'Invalid or expired magic link' };\n  } else if (error.error_type === 'invalid_token') {\n    // Malformed token\n    return { error: 'Invalid token format' };\n  } else {\n    // Other errors\n    return { error: 'Authentication failed' };\n  }\n});\n```\n\n### Common Error Types\n\n- `unable_to_auth_magic_link` - Magic link token invalid, expired, or used\n- `invalid_token` - Token format is invalid\n- `session_not_found` - Session doesn't exist\n- `user_not_found` - User doesn't exist\n- `duplicate_email` - Email already exists\n- `invalid_credentials` - Password authentication failed\n- `rate_limit_exceeded` - Too many requests\n- `unauthorized` - API credentials invalid\n\n---\n\n## Express.js Integration Example\n\n### Complete Auth Flow\n\n```javascript\nconst express = require('express');\nconst stytch = require('stytch');\nconst session = require('express-session');\n\nconst app = express();\napp.use(express.json());\napp.use(session({\n  secret: 'your-session-secret',\n  resave: false,\n  saveUninitialized: false,\n}));\n\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID,\n  secret: process.env.STYTCH_SECRET,\n});\n\n// Login endpoint\napp.post('/login', async (req, res) => {\n  try {\n    const { email } = req.body;\n    const response = await client.magicLinks.email.loginOrCreate({\n      email,\n      login_magic_link_url: `${process.env.BASE_URL}/authenticate`,\n      signup_magic_link_url: `${process.env.BASE_URL}/authenticate`,\n    });\n    res.json({ success: true, user_id: response.user_id });\n  } catch (error) {\n    res.status(400).json({ error: error.error_message });\n  }\n});\n\n// Authentication callback\napp.get('/authenticate', async (req, res) => {\n  try {\n    const { token } = req.query;\n    const response = await client.magicLinks.authenticate({\n      token,\n      session_duration_minutes: 60,\n    });\n\n    req.session.stytchSessionToken = response.session_token;\n    req.session.userId = response.user.user_id;\n\n    res.redirect('/dashboard');\n  } catch (error) {\n    res.status(400).send('Authentication failed');\n  }\n});\n\n// Protected route middleware\nasync function authenticateSession(req, res, next) {\n  const sessionToken = req.session.stytchSessionToken;\n\n  if (!sessionToken) {\n    return res.status(401).json({ error: 'Not authenticated' });\n  }\n\n  try {\n    const response = await client.sessions.authenticate({\n      session_token: sessionToken,\n    });\n\n    req.session.stytchSessionToken = response.session_token;\n    req.user = response.user;\n    next();\n  } catch (error) {\n    req.session.destroy();\n    res.status(401).json({ error: 'Session expired' });\n  }\n}\n\n// Protected route\napp.get('/dashboard', authenticateSession, (req, res) => {\n  res.json({ user: req.user });\n});\n\n// Logout\napp.post('/logout', async (req, res) => {\n  try {\n    await client.sessions.revoke({\n      session_token: req.session.stytchSessionToken,\n    });\n    req.session.destroy();\n    res.json({ success: true });\n  } catch (error) {\n    res.status(400).json({ error: error.error_message });\n  }\n});\n\napp.listen(3000);\n```\n\n---\n\n## TypeScript Support\n\nThe SDK includes full TypeScript definitions.\n\n### TypeScript Example\n\n```typescript\nimport * as stytch from 'stytch';\n\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_PROJECT_ID!,\n  secret: process.env.STYTCH_SECRET!,\n});\n\nasync function loginUser(email: string): Promise<string> {\n  const response = await client.magicLinks.email.loginOrCreate({\n    email,\n  });\n  return response.user_id;\n}\n\nasync function authenticateToken(token: string): Promise<stytch.User> {\n  const response = await client.magicLinks.authenticate({\n    token,\n  });\n  return response.user;\n}\n```\n\n### Request/Response Types\n\nTypes follow the pattern: `$Vertical$Product$Method(Request|Response)`\n\n```typescript\nimport type {\n  MagicLinksEmailLoginOrCreateRequest,\n  MagicLinksEmailLoginOrCreateResponse,\n  MagicLinksAuthenticateRequest,\n  MagicLinksAuthenticateResponse,\n} from 'stytch';\n\nconst request: MagicLinksEmailLoginOrCreateRequest = {\n  email: 'user@example.com',\n  login_magic_link_url: 'https://example.com/authenticate',\n};\n\nconst response: MagicLinksEmailLoginOrCreateResponse =\n  await client.magicLinks.email.loginOrCreate(request);\n```\n\n---\n\n## Testing\n\n### Using Test Environment\n\n```javascript\nconst client = new stytch.Client({\n  project_id: process.env.STYTCH_TEST_PROJECT_ID,\n  secret: process.env.STYTCH_TEST_SECRET,\n  environment: 'test',\n});\n```\n\n### Test Mode Magic Links\n\nIn test mode, use these special test emails:\n- `sandbox@stytch.com` - Always succeeds\n\n### Mock Testing\n\n```javascript\nconst mockClient = {\n  magicLinks: {\n    email: {\n      loginOrCreate: jest.fn().mockResolvedValue({\n        user_id: 'user-test-123',\n        email_id: 'email-test-123',\n      }),\n    },\n    authenticate: jest.fn().mockResolvedValue({\n      user: {\n        user_id: 'user-test-123',\n        emails: [{ email: 'test@example.com' }],\n      },\n      session_token: 'test-session-token',\n    }),\n  },\n};\n```\n\n---\n\n## Webhooks\n\n### Verify Webhook Signature\n\n```javascript\nconst crypto = require('crypto');\n\nfunction verifyWebhookSignature(payload, signature, secret) {\n  const expectedSignature = crypto\n    .createHmac('sha256', secret)\n    .update(payload)\n    .digest('hex');\n\n  return signature === expectedSignature;\n}\n\n// Express webhook endpoint\napp.post('/webhooks/stytch', express.raw({ type: 'application/json' }), (req, res) => {\n  const signature = req.headers['stytch-signature'];\n  const isValid = verifyWebhookSignature(\n    req.body,\n    signature,\n    process.env.STYTCH_WEBHOOK_SECRET\n  );\n\n  if (!isValid) {\n    return res.status(401).send('Invalid signature');\n  }\n\n  const event = JSON.parse(req.body);\n  console.log('Webhook event:', event.event_type);\n\n  res.json({ received: true });\n});\n```\n\n### Webhook Event Types\n\n- `user.created` - New user created\n- `user.updated` - User data updated\n- `user.deleted` - User deleted\n- `session.created` - New session created\n- `session.revoked` - Session revoked\n- `magic_link.sent` - Magic link sent\n- `otp.sent` - OTP sent\n- `password.strength_check_failed` - Weak password detected\n\n---\n\n## Session Management Patterns\n\n### Session Token in Cookie\n\n```javascript\napp.get('/authenticate', async (req, res) => {\n  const { token } = req.query;\n  const response = await client.magicLinks.authenticate({\n    token,\n    session_duration_minutes: 60,\n  });\n\n  res.cookie('stytch_session', response.session_token, {\n    httpOnly: true,\n    secure: true,\n    maxAge: 60 * 60 * 1000, // 1 hour\n  });\n\n  res.redirect('/dashboard');\n});\n\n// Middleware\nasync function authenticate(req, res, next) {\n  const sessionToken = req.cookies.stytch_session;\n  if (!sessionToken) {\n    return res.status(401).json({ error: 'Not authenticated' });\n  }\n\n  try {\n    const response = await client.sessions.authenticate({\n      session_token: sessionToken,\n    });\n    req.user = response.user;\n    next();\n  } catch (error) {\n    res.status(401).json({ error: 'Invalid session' });\n  }\n}\n```\n\n### Session Token in Authorization Header\n\n```javascript\n// Middleware\nasync function authenticate(req, res, next) {\n  const authHeader = req.headers.authorization;\n  if (!authHeader) {\n    return res.status(401).json({ error: 'No token provided' });\n  }\n\n  const sessionToken = authHeader.replace('Bearer ', '');\n\n  try {\n    const response = await client.sessions.authenticate({\n      session_token: sessionToken,\n    });\n    req.user = response.user;\n    next();\n  } catch (error) {\n    res.status(401).json({ error: 'Invalid token' });\n  }\n}\n```\n\n---\n\n## Advanced Use Cases\n\n### Multi-Factor Authentication Flow\n\n```javascript\n// Step 1: Primary authentication (password)\napp.post('/login', async (req, res) => {\n  const { email, password } = req.body;\n\n  try {\n    const response = await client.passwords.authenticate({\n      email,\n      password,\n      session_duration_minutes: 5, // Short session for MFA\n    });\n\n    // Return intermediate session\n    res.json({\n      requires_mfa: true,\n      intermediate_session_token: response.session_token,\n      user_id: response.user_id,\n    });\n  } catch (error) {\n    res.status(401).json({ error: 'Invalid credentials' });\n  }\n});\n\n// Step 2: MFA with TOTP\napp.post('/verify-totp', async (req, res) => {\n  const { user_id, totp_code } = req.body;\n\n  try {\n    const response = await client.totps.authenticate({\n      user_id,\n      totp_code,\n      session_duration_minutes: 60, // Full session after MFA\n    });\n\n    res.json({\n      session_token: response.session_token,\n      user: response.user,\n    });\n  } catch (error) {\n    res.status(401).json({ error: 'Invalid TOTP code' });\n  }\n});\n```\n\n### Account Linking\n\n```javascript\n// Link OAuth account to existing user\napp.post('/link-oauth', authenticateSession, async (req, res) => {\n  const { oauth_token } = req.body;\n\n  try {\n    const response = await client.oauth.authenticate({\n      token: oauth_token,\n      session_token: req.session.stytchSessionToken,\n    });\n\n    res.json({ success: true, user: response.user });\n  } catch (error) {\n    res.status(400).json({ error: error.error_message });\n  }\n});\n```\n\n### Custom Email Templates\n\n```javascript\nconst response = await client.magicLinks.email.loginOrCreate({\n  email: 'user@example.com',\n  login_magic_link_url: 'https://example.com/authenticate',\n  login_template_id: 'custom-login-template-id',\n  signup_template_id: 'custom-signup-template-id',\n});\n```\n\n### IP and User Agent Matching\n\n```javascript\nconst response = await client.magicLinks.authenticate({\n  token,\n  attributes: {\n    ip_address: req.ip,\n    user_agent: req.headers['user-agent'],\n  },\n});\n```\n\n---\n\n## Rate Limiting\n\nStytch implements rate limiting on authentication endpoints. Handle rate limit errors:\n\n```javascript\ntry {\n  await client.otps.sms.send({ phone_number });\n} catch (error) {\n  if (error.error_type === 'rate_limit_exceeded') {\n    const retryAfter = error.retry_after; // seconds\n    res.status(429).json({\n      error: 'Too many requests',\n      retry_after: retryAfter,\n    });\n  }\n}\n```\n\n---\n\n## Migration from Other Auth Systems\n\n### Import Users with Passwords\n\n```javascript\n// Migrate user from bcrypt-based system\nawait client.passwords.migrate({\n  email: 'user@example.com',\n  hash: '$2a$10$existing_bcrypt_hash',\n  hash_type: 'bcrypt',\n  name: {\n    first_name: 'John',\n    last_name: 'Doe',\n  },\n});\n```\n\n### Supported Hash Types\n\n- `bcrypt`\n- `md_5`\n- `argon_2i`\n- `argon_2id`\n- `sha_1`\n- `scrypt`\n- `phpass`\n- `pbkdf_2`\n\n---\n\n## Async/Await vs Promises\n\nAll SDK methods support both patterns:\n\n### Async/Await\n\n```javascript\nasync function authenticateUser(token) {\n  const response = await client.magicLinks.authenticate({ token });\n  return response.user;\n}\n```\n\n### Promises\n\n```javascript\nfunction authenticateUser(token) {\n  return client.magicLinks.authenticate({ token })\n    .then(response => response.user)\n    .catch(error => {\n      console.error(error);\n      throw error;\n    });\n}\n```\n\n---\n\n## Resources\n\n- **Documentation:** https://stytch.com/docs\n- **API Reference:** https://stytch.com/docs/api\n- **GitHub:** https://github.com/stytchauth/stytch-node\n- **npm Package:** https://www.npmjs.com/package/stytch\n- **Dashboard:** https://stytch.com/dashboard\n- **Support:** support@stytch.com\n"
  },
  {
    "path": "content/stytch/docs/auth/python/DOC.md",
    "content": "---\nname: auth\ndescription: \"Stytch Python SDK authentication guide for passwordless and OTP-based authentication\"\nmetadata:\n  languages: \"python\"\n  versions: \"13.28.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"stytch,auth,authentication,passwordless,otp\"\n---\n\n# Stytch Python SDK - Authentication Guide\n\n## Golden Rule\n\n**ALWAYS use the official `stytch` package from PyPI.**\n\n```bash\npip install stytch\n```\n\n**Current version: 13.28.0**\n\n**DO NOT use:**\n- Any unofficial or outdated Stytch packages\n- Frontend JavaScript packages when building backend services\n\nThe `stytch` package is the official backend SDK for Python applications. It supports Python 3.8+ and includes full async/await support.\n\n---\n\n## Installation\n\n### Install the SDK\n\n```bash\npip install stytch\n```\n\nor with poetry:\n\n```bash\npoetry add stytch\n```\n\nor with uv:\n\n```bash\nuv pip install stytch\n```\n\n### Environment Variables\n\nSet up your Stytch credentials in your environment:\n\n```bash\nSTYTCH_PROJECT_ID=project-live-your-project-id\nSTYTCH_SECRET=secret-live-your-secret-key\n```\n\n**Get credentials from:** [Stytch Dashboard](https://stytch.com/dashboard)\n\nFor testing, use test environment credentials:\n\n```bash\nSTYTCH_PROJECT_ID=project-test-your-project-id\nSTYTCH_SECRET=secret-test-your-secret-key\n```\n\n### .env File Example\n\n```env\nSTYTCH_PROJECT_ID=project-live-c60c0abe-c25a-4472-a9ed-320c6667d317\nSTYTCH_SECRET=secret-live-80JASucyk7z_G8Z-7dVwZVGXL5NT_qGAQ2I=\n```\n\n---\n\n## Initialization\n\n### Basic B2C Client\n\n```python\nimport stytch\nimport os\n\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n```\n\n### Client with Environment Override\n\n```python\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n    environment=\"test\",  # or \"live\" (default)\n)\n```\n\n### B2B Client (for organizations)\n\n```python\nimport stytch\n\nb2b_client = stytch.B2BClient(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n```\n\n### Client with Custom Base URL\n\n```python\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n    custom_base_url=\"https://api.custom-domain.com/\",\n)\n```\n\n### Async Client Usage\n\nAll methods have async versions by appending `_async`:\n\n```python\nimport asyncio\n\nasync def main():\n    client = stytch.Client(\n        project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n        secret=os.getenv(\"STYTCH_SECRET\"),\n    )\n    \n    response = await client.magic_links.email.login_or_create_async(\n        email=\"user@example.com\"\n    )\n    print(response.user_id)\n\nasyncio.run(main())\n```\n\n---\n\n## Core API Surfaces\n\n### 1. Magic Links\n\nMagic links provide passwordless authentication via email.\n\n#### Send Magic Link (Login or Create)\n\n```python\n# Minimal example\nresponse = client.magic_links.email.login_or_create(\n    email=\"user@example.com\",\n)\n\nprint(response.user_id)\nprint(response.email_id)\n```\n\n#### Send Magic Link with Custom URLs\n\n```python\nresponse = client.magic_links.email.login_or_create(\n    email=\"user@example.com\",\n    login_magic_link_url=\"https://example.com/authenticate\",\n    signup_magic_link_url=\"https://example.com/authenticate\",\n    login_expiration_minutes=15,\n    signup_expiration_minutes=60,\n)\n```\n\n#### Advanced Magic Link with Options\n\n```python\nresponse = client.magic_links.email.login_or_create(\n    email=\"user@example.com\",\n    login_magic_link_url=\"https://example.com/authenticate\",\n    signup_magic_link_url=\"https://example.com/authenticate\",\n    login_expiration_minutes=15,\n    signup_expiration_minutes=60,\n    login_template_id=\"custom-login-template\",\n    signup_template_id=\"custom-signup-template\",\n    attributes=stytch.Attributes(\n        ip_address=\"192.168.1.1\",\n    ),\n    code_challenge=\"challenge_string\",  # For PKCE flow\n    user_id=\"user-123\",  # Associate with existing user\n    session_duration_minutes=60,\n)\n```\n\n#### Authenticate Magic Link\n\n```python\n# Minimal example\nresponse = client.magic_links.authenticate(\n    token=\"DOYoip3rvIMMW5lgItikFK-Ak1CfMsgjuiCyI7uuU94=\",\n)\n\nprint(response.user)\nprint(response.session_token)\nprint(response.session_jwt)\n```\n\n#### Authenticate with Session Options\n\n```python\nresponse = client.magic_links.authenticate(\n    token=\"DOYoip3rvIMMW5lgItikFK-Ak1CfMsgjuiCyI7uuU94=\",\n    session_duration_minutes=60,\n    session_custom_claims={\"custom_claim\": \"value\"},\n    attributes=stytch.Attributes(\n        ip_address=\"192.168.1.1\",\n        user_agent=\"Mozilla/5.0...\",\n    ),\n)\n```\n\n#### Send Magic Link Only (No Auto-Create)\n\n```python\nresponse = client.magic_links.email.send(\n    email=\"user@example.com\",\n    login_magic_link_url=\"https://example.com/authenticate\",\n    login_expiration_minutes=15,\n)\n```\n\n#### Create Embeddable Magic Link\n\n```python\nresponse = client.magic_links.email.create_embeddable(\n    user_id=\"user-live-123\",\n    embeddable_magic_link_url=\"https://example.com/authenticate\",\n    expiration_minutes=10,\n)\n\nprint(response.token)  # Use in your own emails\n```\n\n#### Async Magic Link Example\n\n```python\nasync def send_magic_link(email: str):\n    response = await client.magic_links.email.login_or_create_async(\n        email=email,\n        login_magic_link_url=\"https://example.com/authenticate\",\n    )\n    return response.user_id\n```\n\n---\n\n### 2. One-Time Passcodes (OTP)\n\n#### SMS OTP\n\n**Send OTP via SMS:**\n\n```python\n# Minimal example\nresponse = client.otps.sms.send(\n    phone_number=\"+15555555555\",\n)\n\nprint(response.phone_id)\n```\n\n**Send OTP with Options:**\n\n```python\nresponse = client.otps.sms.send(\n    phone_number=\"+15555555555\",\n    expiration_minutes=10,\n    attributes=stytch.Attributes(ip_address=\"192.168.1.1\"),\n    user_id=\"user-123\",  # Associate with existing user\n)\n```\n\n**Authenticate SMS OTP:**\n\n```python\n# Minimal example\nresponse = client.otps.authenticate(\n    method_id=\"phone-id-123\",\n    code=\"123456\",\n)\n```\n\n**Authenticate with Session:**\n\n```python\nresponse = client.otps.authenticate(\n    method_id=\"phone-id-123\",\n    code=\"123456\",\n    session_duration_minutes=60,\n    attributes=stytch.Attributes(ip_address=\"192.168.1.1\"),\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n#### Email OTP\n\n**Send OTP via Email:**\n\n```python\n# Minimal example\nresponse = client.otps.email.send(\n    email=\"user@example.com\",\n)\n```\n\n**Send with Options:**\n\n```python\nresponse = client.otps.email.send(\n    email=\"user@example.com\",\n    expiration_minutes=10,\n    login_template_id=\"custom-template\",\n    user_id=\"user-123\",\n)\n```\n\n**Authenticate Email OTP:**\n\n```python\nresponse = client.otps.authenticate(\n    method_id=\"email-id-123\",\n    code=\"123456\",\n    session_duration_minutes=60,\n)\n```\n\n#### WhatsApp OTP\n\n**Send OTP via WhatsApp:**\n\n```python\nresponse = client.otps.whatsapp.send(\n    phone_number=\"+15555555555\",\n)\n```\n\n**Authenticate WhatsApp OTP:**\n\n```python\nresponse = client.otps.authenticate(\n    method_id=\"phone-id-123\",\n    code=\"123456\",\n)\n```\n\n#### Login or Create User with SMS\n\n```python\nresponse = client.otps.sms.login_or_create(\n    phone_number=\"+15555555555\",\n    expiration_minutes=10,\n)\n```\n\n#### Login or Create User with Email\n\n```python\nresponse = client.otps.email.login_or_create(\n    email=\"user@example.com\",\n    expiration_minutes=10,\n)\n```\n\n---\n\n### 3. OAuth\n\nOAuth enables authentication via third-party providers.\n\n#### Start OAuth Flow\n\n```python\n# Get OAuth authorization URL\nresponse = client.oauth.start(\n    provider=\"google\",\n    signup_redirect_url=\"https://example.com/authenticate\",\n    login_redirect_url=\"https://example.com/authenticate\",\n)\n\nprint(response.oauth_url)  # Redirect user here\n```\n\n#### Start OAuth with Options\n\n```python\nresponse = client.oauth.start(\n    provider=\"google\",\n    signup_redirect_url=\"https://example.com/authenticate\",\n    login_redirect_url=\"https://example.com/authenticate\",\n    custom_scopes=[\"https://www.googleapis.com/auth/calendar.readonly\"],\n    provider_params={\"access_type\": \"offline\"},\n    code_challenge=\"challenge_string\",  # For PKCE\n)\n```\n\n#### Authenticate OAuth\n\n```python\n# Minimal example\nresponse = client.oauth.authenticate(\n    token=\"oauth-token-from-callback\",\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n#### Authenticate with Session Options\n\n```python\nresponse = client.oauth.authenticate(\n    token=\"oauth-token-from-callback\",\n    session_duration_minutes=60,\n    session_custom_claims={\"custom_claim\": \"value\"},\n)\n```\n\n#### Supported OAuth Providers\n\n- `google`\n- `microsoft`\n- `facebook`\n- `github`\n- `gitlab`\n- `slack`\n- `linkedin`\n- `amazon`\n- `bitbucket`\n- `coinbase`\n- `discord`\n- `figma`\n- `hubspot`\n- `salesforce`\n- `shopify`\n- `snapchat`\n- `tiktok`\n- `twitch`\n- `twitter`\n- `yahoo`\n\n---\n\n### 4. Sessions\n\nSessions manage authenticated user state.\n\n#### Authenticate Session\n\n```python\n# Minimal example\nresponse = client.sessions.authenticate(\n    session_token=\"session-token-here\",\n)\n\nprint(response.user)\nprint(response.session)  # Contains session data\n```\n\n#### Authenticate with JWT\n\n```python\nresponse = client.sessions.authenticate_jwt(\n    session_jwt=\"jwt-token-here\",\n)\n```\n\n#### Authenticate Session with Refresh\n\n```python\nresponse = client.sessions.authenticate(\n    session_token=\"session-token-here\",\n    session_duration_minutes=60,  # Extend session\n)\n\n# Store new token\nnew_session_token = response.session_token\n```\n\n#### Get Sessions\n\n```python\nresponse = client.sessions.get(\n    user_id=\"user-123\",\n)\n\nprint(response.sessions)  # All active sessions\n```\n\n#### Revoke Session\n\n```python\nclient.sessions.revoke(\n    session_token=\"session-token-to-revoke\",\n)\n```\n\n#### Revoke Session by ID\n\n```python\nclient.sessions.revoke(\n    session_id=\"session-id-123\",\n)\n```\n\n#### Migrate Session\n\n```python\nresponse = client.sessions.migrate(\n    session_token=\"old-session-token\",\n    session_duration_minutes=60,\n)\n\nprint(response.session_token)  # New token\n```\n\n---\n\n### 5. Users\n\nManage user accounts and data.\n\n#### Get User\n\n```python\nresponse = client.users.get(\n    user_id=\"user-123\",\n)\n\nprint(response.user)\nprint(response.user.emails)\nprint(response.user.phone_numbers)\n```\n\n#### Create User\n\n```python\nresponse = client.users.create(\n    email=\"user@example.com\",\n    name={\"first_name\": \"John\", \"last_name\": \"Doe\"},\n)\n```\n\n#### Create User with Multiple Methods\n\n```python\nresponse = client.users.create(\n    email=\"user@example.com\",\n    phone_number=\"+15555555555\",\n    name={\"first_name\": \"John\", \"last_name\": \"Doe\"},\n    attributes={\"custom_attribute\": \"value\"},\n)\n```\n\n#### Update User\n\n```python\nresponse = client.users.update(\n    user_id=\"user-123\",\n    name={\"first_name\": \"Jane\", \"last_name\": \"Smith\"},\n    attributes={\"custom_field\": \"new_value\"},\n)\n```\n\n#### Delete User\n\n```python\nclient.users.delete(\n    user_id=\"user-123\",\n)\n```\n\n#### Search Users\n\n```python\n# Basic search\nresponse = client.users.search(\n    query={\n        \"operator\": \"AND\",\n        \"operands\": [\n            {\n                \"filter_name\": \"status\",\n                \"filter_value\": [\"active\"],\n            },\n        ],\n    },\n)\n\nprint(response.results)\n```\n\n#### Advanced User Search\n\n```python\nresponse = client.users.search(\n    query={\n        \"operator\": \"AND\",\n        \"operands\": [\n            {\n                \"filter_name\": \"email_verified\",\n                \"filter_value\": [True],\n            },\n            {\n                \"filter_name\": \"created_at\",\n                \"filter_value\": {\n                    \"greater_than\": \"2024-01-01T00:00:00Z\",\n                },\n            },\n        ],\n    },\n    limit=100,\n    cursor=\"cursor-from-previous-request\",\n)\n```\n\n#### Delete Email\n\n```python\nclient.users.delete_email(\n    email_id=\"email-id-123\",\n)\n```\n\n#### Delete Phone Number\n\n```python\nclient.users.delete_phone_number(\n    phone_id=\"phone-id-123\",\n)\n```\n\n---\n\n### 6. Passwords\n\nTraditional password authentication.\n\n#### Create Password\n\n```python\nresponse = client.passwords.create(\n    email=\"user@example.com\",\n    password=\"SecurePassword123!\",\n    session_duration_minutes=60,\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n#### Authenticate Password\n\n```python\n# Minimal example\nresponse = client.passwords.authenticate(\n    email=\"user@example.com\",\n    password=\"SecurePassword123!\",\n)\n```\n\n#### Authenticate with Session\n\n```python\nresponse = client.passwords.authenticate(\n    email=\"user@example.com\",\n    password=\"SecurePassword123!\",\n    session_duration_minutes=60,\n    session_custom_claims={\"custom_claim\": \"value\"},\n)\n\nprint(response.session_token)\n```\n\n#### Strength Check\n\n```python\nresponse = client.passwords.strength_check(\n    email=\"user@example.com\",\n    password=\"password-to-check\",\n)\n\nprint(response.valid_password)\nprint(response.score)\nprint(response.breached_password)\nprint(response.strength_policy)\nprint(response.breach_detection_on_create)\n```\n\n#### Initiate Password Reset\n\n```python\nresponse = client.passwords.email.reset_start(\n    email=\"user@example.com\",\n    reset_password_redirect_url=\"https://example.com/reset\",\n    reset_password_expiration_minutes=30,\n)\n```\n\n#### Reset Password by Email\n\n```python\nresponse = client.passwords.email.reset(\n    token=\"reset-token-from-email\",\n    password=\"NewSecurePassword123!\",\n    session_duration_minutes=60,\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n#### Reset Password by Session\n\n```python\nresponse = client.passwords.session.reset(\n    session_token=\"active-session-token\",\n    password=\"NewSecurePassword123!\",\n)\n```\n\n#### Migrate Password (from existing system)\n\n```python\nresponse = client.passwords.migrate(\n    email=\"user@example.com\",\n    hash=\"$2a$10$...\",  # bcrypt hash\n    hash_type=\"bcrypt\",\n    name={\"first_name\": \"John\", \"last_name\": \"Doe\"},\n)\n```\n\n---\n\n### 7. WebAuthn\n\nPasswordless authentication using biometrics or security keys.\n\n#### Register WebAuthn Start\n\n```python\nresponse = client.webauthn.register_start(\n    user_id=\"user-123\",\n    domain=\"example.com\",\n    authenticator_type=\"platform\",  # or \"cross-platform\"\n)\n\nprint(response.public_key_credential_creation_options)\n```\n\n#### Register WebAuthn Finish\n\n```python\nresponse = client.webauthn.register(\n    user_id=\"user-123\",\n    public_key_credential=\"credential-from-client\",\n    session_duration_minutes=60,\n)\n\nprint(response.webauthn_registration_id)\nprint(response.session_token)\n```\n\n#### Authenticate WebAuthn Start\n\n```python\nresponse = client.webauthn.authenticate_start(\n    domain=\"example.com\",\n    user_id=\"user-123\",  # Optional\n)\n\nprint(response.public_key_credential_request_options)\n```\n\n#### Authenticate WebAuthn Finish\n\n```python\nresponse = client.webauthn.authenticate(\n    public_key_credential=\"credential-from-client\",\n    session_duration_minutes=60,\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n#### Update WebAuthn\n\n```python\nresponse = client.webauthn.update(\n    webauthn_registration_id=\"webauthn-reg-id-123\",\n    name=\"My Fingerprint\",\n)\n```\n\n---\n\n### 8. TOTP (Time-based One-Time Passwords)\n\n#### Create TOTP\n\n```python\nresponse = client.totps.create(\n    user_id=\"user-123\",\n    expiration_minutes=10,\n)\n\nprint(response.secret)\nprint(response.qr_code)  # URL for QR code image\nprint(response.recovery_codes)\n```\n\n#### Authenticate TOTP\n\n```python\nresponse = client.totps.authenticate(\n    user_id=\"user-123\",\n    totp_code=\"123456\",\n    session_duration_minutes=60,\n)\n\nprint(response.session_token)\n```\n\n#### Get TOTPs\n\n```python\nresponse = client.totps.get(\n    user_id=\"user-123\",\n)\n\nprint(response.totps)\n```\n\n#### Recover TOTP\n\n```python\nresponse = client.totps.recovery_codes(\n    user_id=\"user-123\",\n    recovery_code=\"recovery-code-string\",\n    session_duration_minutes=60,\n)\n\nprint(response.session_token)\n```\n\n---\n\n### 9. Crypto Wallets (Web3)\n\n#### Authenticate Wallet Start\n\n```python\nresponse = client.crypto_wallets.authenticate_start(\n    crypto_wallet_address=\"0x1234...\",\n    crypto_wallet_type=\"ethereum\",\n)\n\nprint(response.challenge)\n```\n\n#### Authenticate Wallet Finish\n\n```python\nresponse = client.crypto_wallets.authenticate(\n    crypto_wallet_address=\"0x1234...\",\n    crypto_wallet_type=\"ethereum\",\n    signature=\"signed-challenge\",\n    session_duration_minutes=60,\n)\n\nprint(response.user)\nprint(response.session_token)\n```\n\n---\n\n### 10. M2M (Machine-to-Machine)\n\n#### Authenticate M2M Token\n\n```python\nresponse = client.m2m.authenticate_token(\n    access_token=\"m2m-access-token\",\n)\n\nprint(response.member_id)\nprint(response.scopes)\n```\n\n#### Get M2M Client\n\n```python\nresponse = client.m2m.clients.get(\n    client_id=\"client-id-123\",\n)\n\nprint(response.m2m_client)\n```\n\n---\n\n## B2B API Surfaces\n\n### 1. Organizations\n\n#### Create Organization\n\n```python\nresponse = b2b_client.organizations.create(\n    organization_name=\"Acme Corp\",\n    organization_slug=\"acme\",\n    email_allowed_domains=[\"acme.com\"],\n)\n\nprint(response.organization)\n```\n\n#### Get Organization\n\n```python\nresponse = b2b_client.organizations.get(\n    organization_id=\"org-123\",\n)\n\nprint(response.organization)\n```\n\n#### Update Organization\n\n```python\nresponse = b2b_client.organizations.update(\n    organization_id=\"org-123\",\n    organization_name=\"Acme Corporation\",\n)\n```\n\n#### Delete Organization\n\n```python\nb2b_client.organizations.delete(\n    organization_id=\"org-123\",\n)\n```\n\n---\n\n### 2. Members\n\n#### Create Member\n\n```python\nresponse = b2b_client.organizations.members.create(\n    organization_id=\"org-123\",\n    email_address=\"member@acme.com\",\n    name=\"John Doe\",\n    is_breakglass=False,\n)\n\nprint(response.member)\n```\n\n#### Get Member\n\n```python\nresponse = b2b_client.organizations.members.get(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n)\n\nprint(response.member)\n```\n\n#### Update Member\n\n```python\nresponse = b2b_client.organizations.members.update(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n    name=\"Jane Doe\",\n)\n```\n\n#### Delete Member\n\n```python\nb2b_client.organizations.members.delete(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n)\n```\n\n---\n\n### 3. B2B Magic Links\n\n#### Send B2B Magic Link\n\n```python\nresponse = b2b_client.magic_links.email.login_or_signup(\n    organization_id=\"org-123\",\n    email_address=\"member@acme.com\",\n    login_redirect_url=\"https://acme.com/authenticate\",\n    signup_redirect_url=\"https://acme.com/authenticate\",\n)\n```\n\n#### Authenticate B2B Magic Link\n\n```python\nresponse = b2b_client.magic_links.authenticate(\n    magic_links_token=\"token-from-email\",\n    session_duration_minutes=60,\n)\n\nprint(response.member)\nprint(response.organization)\nprint(response.session_token)\n```\n\n---\n\n### 4. B2B Sessions\n\n#### Authenticate B2B Session\n\n```python\nresponse = b2b_client.sessions.authenticate(\n    session_token=\"session-token-here\",\n)\n\nprint(response.member)\nprint(response.organization)\nprint(response.session)\n```\n\n#### Authenticate B2B JWT\n\n```python\nresponse = b2b_client.sessions.authenticate_jwt(\n    session_jwt=\"jwt-token-here\",\n)\n```\n\n#### Get B2B Sessions\n\n```python\nresponse = b2b_client.sessions.get(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n)\n\nprint(response.sessions)\n```\n\n#### Revoke B2B Session\n\n```python\nb2b_client.sessions.revoke(\n    session_token=\"session-token-to-revoke\",\n)\n```\n\n---\n\n### 5. B2B OAuth\n\n#### Start B2B OAuth\n\n```python\nresponse = b2b_client.oauth.start(\n    organization_id=\"org-123\",\n    provider=\"google\",\n    login_redirect_url=\"https://acme.com/authenticate\",\n    signup_redirect_url=\"https://acme.com/authenticate\",\n)\n\nprint(response.oauth_url)\n```\n\n#### Authenticate B2B OAuth\n\n```python\nresponse = b2b_client.oauth.authenticate(\n    oauth_token=\"token-from-callback\",\n    session_duration_minutes=60,\n)\n\nprint(response.member)\nprint(response.organization)\nprint(response.session_token)\n```\n\n---\n\n### 6. B2B SMS OTP\n\n#### Send B2B SMS OTP\n\n```python\nresponse = b2b_client.otps.sms.send(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n    phone_number=\"+15555555555\",\n)\n```\n\n#### Authenticate B2B SMS OTP\n\n```python\nresponse = b2b_client.otps.sms.authenticate(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n    code=\"123456\",\n    session_duration_minutes=60,\n)\n\nprint(response.member)\nprint(response.session_token)\n```\n\n---\n\n### 7. SSO (Single Sign-On)\n\n#### Start SSO\n\n```python\nresponse = b2b_client.sso.start(\n    connection_id=\"sso-connection-123\",\n    login_redirect_url=\"https://acme.com/authenticate\",\n    signup_redirect_url=\"https://acme.com/authenticate\",\n)\n\nprint(response.sso_url)\n```\n\n#### Authenticate SSO\n\n```python\nresponse = b2b_client.sso.authenticate(\n    sso_token=\"token-from-sso-provider\",\n    session_duration_minutes=60,\n)\n\nprint(response.member)\nprint(response.organization)\n```\n\n#### Get SSO Connections\n\n```python\nresponse = b2b_client.sso.get_connections(\n    organization_id=\"org-123\",\n)\n\nprint(response.saml_connections)\nprint(response.oidc_connections)\n```\n\n#### Create SAML Connection\n\n```python\nresponse = b2b_client.sso.saml.create_connection(\n    organization_id=\"org-123\",\n    display_name=\"Acme SAML\",\n)\n\nprint(response.connection)\n```\n\n#### Update SAML Connection\n\n```python\nresponse = b2b_client.sso.saml.update_connection(\n    organization_id=\"org-123\",\n    connection_id=\"saml-connection-123\",\n    idp_entity_id=\"https://idp.acme.com/entity\",\n    idp_sso_url=\"https://idp.acme.com/sso\",\n    attribute_mapping={\n        \"email\": \"email\",\n        \"first_name\": \"firstName\",\n        \"last_name\": \"lastName\",\n    },\n    x509_certificate=\"certificate-string\",\n)\n```\n\n#### Create OIDC Connection\n\n```python\nresponse = b2b_client.sso.oidc.create_connection(\n    organization_id=\"org-123\",\n    display_name=\"Acme OIDC\",\n)\n\nprint(response.connection)\n```\n\n#### Update OIDC Connection\n\n```python\nresponse = b2b_client.sso.oidc.update_connection(\n    organization_id=\"org-123\",\n    connection_id=\"oidc-connection-123\",\n    issuer=\"https://idp.acme.com\",\n    client_id=\"client-id\",\n    client_secret=\"client-secret\",\n    authorization_url=\"https://idp.acme.com/authorize\",\n    token_url=\"https://idp.acme.com/token\",\n    userinfo_url=\"https://idp.acme.com/userinfo\",\n)\n```\n\n---\n\n### 8. Discovery\n\nDiscovery allows users to find and join organizations.\n\n#### Create Organization via Discovery\n\n```python\nresponse = b2b_client.discovery.organizations.create(\n    intermediate_session_token=\"token-from-discovery\",\n    organization_name=\"New Org\",\n    organization_slug=\"new-org\",\n    session_duration_minutes=60,\n)\n\nprint(response.organization)\nprint(response.session_token)\n```\n\n#### List Discovered Organizations\n\n```python\nresponse = b2b_client.discovery.organizations.list(\n    intermediate_session_token=\"token-from-discovery\",\n)\n\nprint(response.discovered_organizations)\n```\n\n---\n\n### 9. RBAC (Role-Based Access Control)\n\n#### Check Member Permissions\n\n```python\nresponse = b2b_client.rbac.policy(\n    organization_id=\"org-123\",\n    member_id=\"member-123\",\n    resource_id=\"document-123\",\n    action=\"read\",\n)\n\nprint(response.authorized)\n```\n\n---\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom stytch.core.response_base import StytchError\n\ntry:\n    response = client.magic_links.email.login_or_create(\n        email=\"user@example.com\",\n    )\n    print(response.user_id)\nexcept StytchError as error:\n    print(\"Error:\", error.details.error_type)\n    print(\"Message:\", error.details.error_message)\n    print(\"URL:\", error.details.error_url)\n```\n\n### Detailed Error Handling\n\n```python\nfrom stytch.core.response_base import StytchError\n\ntry:\n    response = client.magic_links.authenticate(token=token)\nexcept StytchError as error:\n    if error.details.error_type == \"unable_to_auth_magic_link\":\n        # Token invalid, expired, or already used\n        print(\"Invalid or expired magic link\")\n    elif error.details.error_type == \"invalid_token\":\n        # Malformed token\n        print(\"Invalid token format\")\n    else:\n        # Other errors\n        print(\"Authentication failed\")\n```\n\n### Common Error Types\n\n- `unable_to_auth_magic_link` - Magic link token invalid, expired, or used\n- `invalid_token` - Token format is invalid\n- `session_not_found` - Session doesn't exist\n- `user_not_found` - User doesn't exist\n- `duplicate_email` - Email already exists\n- `invalid_credentials` - Password authentication failed\n- `rate_limit_exceeded` - Too many requests\n- `unauthorized` - API credentials invalid\n\n---\n\n## Flask Integration Example\n\n### Complete Auth Flow\n\n```python\nfrom flask import Flask, request, session, redirect, jsonify\nfrom stytch import Client\nfrom stytch.core.response_base import StytchError\nimport os\n\napp = Flask(__name__)\napp.secret_key = os.getenv(\"FLASK_SECRET_KEY\")\n\nstytch_client = Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n\n@app.route(\"/login\", methods=[\"POST\"])\ndef login():\n    try:\n        email = request.json.get(\"email\")\n        response = stytch_client.magic_links.email.login_or_create(\n            email=email,\n            login_magic_link_url=f\"{os.getenv('BASE_URL')}/authenticate\",\n            signup_magic_link_url=f\"{os.getenv('BASE_URL')}/authenticate\",\n        )\n        return jsonify({\"success\": True, \"user_id\": response.user_id})\n    except StytchError as error:\n        return jsonify({\"error\": error.details.error_message}), 400\n\n@app.route(\"/authenticate\")\ndef authenticate():\n    try:\n        token = request.args.get(\"token\")\n        response = stytch_client.magic_links.authenticate(\n            token=token,\n            session_duration_minutes=60,\n        )\n        \n        session[\"stytch_session_token\"] = response.session_token\n        session[\"user_id\"] = response.user.user_id\n        \n        return redirect(\"/dashboard\")\n    except StytchError:\n        return \"Authentication failed\", 400\n\ndef authenticate_session():\n    \"\"\"Middleware to authenticate session\"\"\"\n    session_token = session.get(\"stytch_session_token\")\n    \n    if not session_token:\n        return None\n    \n    try:\n        response = stytch_client.sessions.authenticate(\n            session_token=session_token,\n        )\n        session[\"stytch_session_token\"] = response.session_token\n        return response.user\n    except StytchError:\n        session.clear()\n        return None\n\n@app.route(\"/dashboard\")\ndef dashboard():\n    user = authenticate_session()\n    if not user:\n        return jsonify({\"error\": \"Not authenticated\"}), 401\n    return jsonify({\"user\": user})\n\n@app.route(\"/logout\", methods=[\"POST\"])\ndef logout():\n    try:\n        stytch_client.sessions.revoke(\n            session_token=session.get(\"stytch_session_token\"),\n        )\n        session.clear()\n        return jsonify({\"success\": True})\n    except StytchError as error:\n        return jsonify({\"error\": error.details.error_message}), 400\n\nif __name__ == \"__main__\":\n    app.run(port=3000)\n```\n\n---\n\n## FastAPI Integration Example\n\n### Complete Auth Flow with FastAPI\n\n```python\nfrom fastapi import FastAPI, HTTPException, Depends, Request, Response\nfrom fastapi.responses import RedirectResponse\nfrom pydantic import BaseModel\nimport stytch\nimport os\n\napp = FastAPI()\n\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n\nclass LoginRequest(BaseModel):\n    email: str\n\n@app.post(\"/login\")\nasync def login(data: LoginRequest):\n    try:\n        response = client.magic_links.email.login_or_create(\n            email=data.email,\n            login_magic_link_url=f\"{os.getenv('BASE_URL')}/authenticate\",\n        )\n        return {\"success\": True, \"user_id\": response.user_id}\n    except stytch.core.response_base.StytchError as error:\n        raise HTTPException(\n            status_code=400,\n            detail=error.details.error_message\n        )\n\n@app.get(\"/authenticate\")\nasync def authenticate(token: str, response: Response):\n    try:\n        auth_response = client.magic_links.authenticate(\n            token=token,\n            session_duration_minutes=60,\n        )\n        \n        response.set_cookie(\n            key=\"stytch_session\",\n            value=auth_response.session_token,\n            httponly=True,\n            secure=True,\n            max_age=3600,\n        )\n        \n        return RedirectResponse(url=\"/dashboard\")\n    except stytch.core.response_base.StytchError:\n        raise HTTPException(status_code=400, detail=\"Authentication failed\")\n\nasync def get_current_user(request: Request):\n    session_token = request.cookies.get(\"stytch_session\")\n    \n    if not session_token:\n        raise HTTPException(status_code=401, detail=\"Not authenticated\")\n    \n    try:\n        response = client.sessions.authenticate(\n            session_token=session_token,\n        )\n        return response.user\n    except stytch.core.response_base.StytchError:\n        raise HTTPException(status_code=401, detail=\"Invalid session\")\n\n@app.get(\"/dashboard\")\nasync def dashboard(user=Depends(get_current_user)):\n    return {\"user\": user}\n\n@app.post(\"/logout\")\nasync def logout(request: Request, response: Response):\n    session_token = request.cookies.get(\"stytch_session\")\n    \n    if session_token:\n        try:\n            client.sessions.revoke(session_token=session_token)\n        except stytch.core.response_base.StytchError:\n            pass\n    \n    response.delete_cookie(\"stytch_session\")\n    return {\"success\": True}\n```\n\n---\n\n## Django Integration Example\n\n### Django Middleware for Stytch\n\n```python\n# middleware.py\nimport stytch\nimport os\nfrom django.utils.functional import SimpleLazyObject\n\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n\ndef get_user(request):\n    session_token = request.session.get(\"stytch_session_token\")\n    \n    if not session_token:\n        return None\n    \n    try:\n        response = client.sessions.authenticate(\n            session_token=session_token,\n        )\n        request.session[\"stytch_session_token\"] = response.session_token\n        return response.user\n    except stytch.core.response_base.StytchError:\n        return None\n\nclass StytchAuthenticationMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        request.stytch_user = SimpleLazyObject(lambda: get_user(request))\n        response = self.get_response(request)\n        return response\n```\n\n### Django Views\n\n```python\n# views.py\nfrom django.http import JsonResponse, HttpResponseRedirect\nfrom django.views.decorators.http import require_http_methods\nfrom stytch.core.response_base import StytchError\nimport json\n\n@require_http_methods([\"POST\"])\ndef login(request):\n    try:\n        data = json.loads(request.body)\n        email = data.get(\"email\")\n        \n        response = client.magic_links.email.login_or_create(\n            email=email,\n            login_magic_link_url=f\"{os.getenv('BASE_URL')}/authenticate\",\n        )\n        \n        return JsonResponse({\n            \"success\": True,\n            \"user_id\": response.user_id\n        })\n    except StytchError as error:\n        return JsonResponse({\n            \"error\": error.details.error_message\n        }, status=400)\n\ndef authenticate(request):\n    try:\n        token = request.GET.get(\"token\")\n        response = client.magic_links.authenticate(\n            token=token,\n            session_duration_minutes=60,\n        )\n        \n        request.session[\"stytch_session_token\"] = response.session_token\n        request.session[\"user_id\"] = response.user.user_id\n        \n        return HttpResponseRedirect(\"/dashboard\")\n    except StytchError:\n        return JsonResponse({\"error\": \"Authentication failed\"}, status=400)\n\n@require_http_methods([\"POST\"])\ndef logout(request):\n    try:\n        session_token = request.session.get(\"stytch_session_token\")\n        if session_token:\n            client.sessions.revoke(session_token=session_token)\n        request.session.flush()\n        return JsonResponse({\"success\": True})\n    except StytchError as error:\n        return JsonResponse({\n            \"error\": error.details.error_message\n        }, status=400)\n```\n\n---\n\n## Async/Await Support\n\nAll SDK methods support async by appending `_async`:\n\n### Async Example with asyncio\n\n```python\nimport asyncio\nimport stytch\nimport os\n\nasync def main():\n    client = stytch.Client(\n        project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n        secret=os.getenv(\"STYTCH_SECRET\"),\n    )\n    \n    # Send magic link\n    response = await client.magic_links.email.login_or_create_async(\n        email=\"user@example.com\",\n        login_magic_link_url=\"https://example.com/authenticate\",\n    )\n    print(f\"Magic link sent to user: {response.user_id}\")\n    \n    # Authenticate (in a real app, this would happen after user clicks link)\n    auth_response = await client.magic_links.authenticate_async(\n        token=\"token-from-email\",\n    )\n    print(f\"User authenticated: {auth_response.user.user_id}\")\n    \n    # Validate session\n    session_response = await client.sessions.authenticate_async(\n        session_token=auth_response.session_token,\n    )\n    print(f\"Session valid for: {session_response.user.emails}\")\n\nasyncio.run(main())\n```\n\n### Async with FastAPI\n\n```python\nfrom fastapi import FastAPI\nimport stytch\nimport os\n\napp = FastAPI()\n\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_SECRET\"),\n)\n\n@app.post(\"/login\")\nasync def login(email: str):\n    response = await client.magic_links.email.login_or_create_async(\n        email=email,\n        login_magic_link_url=\"https://example.com/authenticate\",\n    )\n    return {\"user_id\": response.user_id}\n\n@app.get(\"/authenticate\")\nasync def authenticate(token: str):\n    response = await client.magic_links.authenticate_async(\n        token=token,\n        session_duration_minutes=60,\n    )\n    return {\"session_token\": response.session_token}\n```\n\n---\n\n## Testing\n\n### Using Test Environment\n\n```python\nclient = stytch.Client(\n    project_id=os.getenv(\"STYTCH_TEST_PROJECT_ID\"),\n    secret=os.getenv(\"STYTCH_TEST_SECRET\"),\n    environment=\"test\",\n)\n```\n\n### Test Mode Magic Links\n\nIn test mode, use these special test emails:\n- `sandbox@stytch.com` - Always succeeds\n\n### Mock Testing with pytest\n\n```python\nimport pytest\nfrom unittest.mock import Mock, patch\nimport stytch\n\n@pytest.fixture\ndef mock_stytch_client():\n    with patch('stytch.Client') as mock:\n        client = mock.return_value\n        \n        # Mock magic links\n        client.magic_links.email.login_or_create = Mock(\n            return_value=Mock(\n                user_id=\"user-test-123\",\n                email_id=\"email-test-123\",\n            )\n        )\n        \n        client.magic_links.authenticate = Mock(\n            return_value=Mock(\n                user=Mock(\n                    user_id=\"user-test-123\",\n                    emails=[{\"email\": \"test@example.com\"}],\n                ),\n                session_token=\"test-session-token\",\n            )\n        )\n        \n        yield client\n\ndef test_login(mock_stytch_client):\n    response = mock_stytch_client.magic_links.email.login_or_create(\n        email=\"test@example.com\"\n    )\n    assert response.user_id == \"user-test-123\"\n```\n\n---\n\n## Webhooks\n\n### Verify Webhook Signature\n\n```python\nimport hmac\nimport hashlib\n\ndef verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:\n    expected_signature = hmac.new(\n        secret.encode(),\n        payload,\n        hashlib.sha256\n    ).hexdigest()\n    \n    return signature == expected_signature\n\n# Flask webhook endpoint\n@app.route(\"/webhooks/stytch\", methods=[\"POST\"])\ndef stytch_webhook():\n    signature = request.headers.get(\"stytch-signature\")\n    payload = request.get_data()\n    \n    is_valid = verify_webhook_signature(\n        payload,\n        signature,\n        os.getenv(\"STYTCH_WEBHOOK_SECRET\")\n    )\n    \n    if not is_valid:\n        return \"Invalid signature\", 401\n    \n    event = request.json\n    print(f\"Webhook event: {event['event_type']}\")\n    \n    return jsonify({\"received\": True})\n```\n\n### FastAPI Webhook Handler\n\n```python\nfrom fastapi import FastAPI, Request, HTTPException\nimport hmac\nimport hashlib\n\n@app.post(\"/webhooks/stytch\")\nasync def stytch_webhook(request: Request):\n    signature = request.headers.get(\"stytch-signature\")\n    payload = await request.body()\n    \n    expected_signature = hmac.new(\n        os.getenv(\"STYTCH_WEBHOOK_SECRET\").encode(),\n        payload,\n        hashlib.sha256\n    ).hexdigest()\n    \n    if signature != expected_signature:\n        raise HTTPException(status_code=401, detail=\"Invalid signature\")\n    \n    event = await request.json()\n    print(f\"Webhook event: {event['event_type']}\")\n    \n    return {\"received\": True}\n```\n\n### Webhook Event Types\n\n- `user.created` - New user created\n- `user.updated` - User data updated\n- `user.deleted` - User deleted\n- `session.created` - New session created\n- `session.revoked` - Session revoked\n- `magic_link.sent` - Magic link sent\n- `otp.sent` - OTP sent\n- `password.strength_check_failed` - Weak password detected\n\n---\n\n## Advanced Use Cases\n\n### Multi-Factor Authentication Flow\n\n```python\n# Step 1: Primary authentication (password)\n@app.post(\"/login\")\ndef login():\n    email = request.json.get(\"email\")\n    password = request.json.get(\"password\")\n    \n    try:\n        response = client.passwords.authenticate(\n            email=email,\n            password=password,\n            session_duration_minutes=5,  # Short session for MFA\n        )\n        \n        return jsonify({\n            \"requires_mfa\": True,\n            \"intermediate_session_token\": response.session_token,\n            \"user_id\": response.user_id,\n        })\n    except StytchError:\n        return jsonify({\"error\": \"Invalid credentials\"}), 401\n\n# Step 2: MFA with TOTP\n@app.post(\"/verify-totp\")\ndef verify_totp():\n    user_id = request.json.get(\"user_id\")\n    totp_code = request.json.get(\"totp_code\")\n    \n    try:\n        response = client.totps.authenticate(\n            user_id=user_id,\n            totp_code=totp_code,\n            session_duration_minutes=60,  # Full session after MFA\n        )\n        \n        return jsonify({\n            \"session_token\": response.session_token,\n            \"user\": response.user,\n        })\n    except StytchError:\n        return jsonify({\"error\": \"Invalid TOTP code\"}), 401\n```\n\n### Custom Email Templates\n\n```python\nresponse = client.magic_links.email.login_or_create(\n    email=\"user@example.com\",\n    login_magic_link_url=\"https://example.com/authenticate\",\n    login_template_id=\"custom-login-template-id\",\n    signup_template_id=\"custom-signup-template-id\",\n)\n```\n\n### IP and User Agent Matching\n\n```python\nresponse = client.magic_links.authenticate(\n    token=token,\n    attributes=stytch.Attributes(\n        ip_address=request.remote_addr,\n        user_agent=request.headers.get(\"User-Agent\"),\n    ),\n)\n```\n\n---\n\n## Rate Limiting\n\nStytch implements rate limiting on authentication endpoints. Handle rate limit errors:\n\n```python\nfrom stytch.core.response_base import StytchError\n\ntry:\n    client.otps.sms.send(phone_number=phone_number)\nexcept StytchError as error:\n    if error.details.error_type == \"rate_limit_exceeded\":\n        retry_after = error.details.retry_after  # seconds\n        return jsonify({\n            \"error\": \"Too many requests\",\n            \"retry_after\": retry_after,\n        }), 429\n```\n\n---\n\n## Migration from Other Auth Systems\n\n### Import Users with Passwords\n\n```python\n# Migrate user from bcrypt-based system\nclient.passwords.migrate(\n    email=\"user@example.com\",\n    hash=\"$2a$10$existing_bcrypt_hash\",\n    hash_type=\"bcrypt\",\n    name={\"first_name\": \"John\", \"last_name\": \"Doe\"},\n)\n```\n\n### Supported Hash Types\n\n- `bcrypt`\n- `md_5`\n- `argon_2i`\n- `argon_2id`\n- `sha_1`\n- `scrypt`\n- `phpass`\n- `pbkdf_2`\n\n---\n\n## Type Hints\n\nThe SDK includes comprehensive type hints for all methods:\n\n```python\nfrom typing import Optional\nimport stytch\n\ndef authenticate_user(token: str) -> stytch.User:\n    client = stytch.Client(\n        project_id=os.getenv(\"STYTCH_PROJECT_ID\"),\n        secret=os.getenv(\"STYTCH_SECRET\"),\n    )\n    \n    response = client.magic_links.authenticate(token=token)\n    return response.user\n\ndef get_user_email(user: stytch.User) -> Optional[str]:\n    if user.emails:\n        return user.emails[0].email\n    return None\n```\n\n---\n\n## Resources\n\n- **Documentation:** https://stytch.com/docs\n- **API Reference:** https://stytch.com/docs/api\n- **GitHub:** https://github.com/stytchauth/stytch-python\n- **PyPI Package:** https://pypi.org/project/stytch/\n- **Dashboard:** https://stytch.com/dashboard\n- **Support:** support@stytch.com\n"
  },
  {
    "path": "content/supabase/docs/client/DOC.md",
    "content": "---\nname: client\ndescription: \"Open-source Firebase alternative with PostgreSQL backend, authentication, storage, realtime subscriptions, and edge functions\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.76.1\"\n  updated-on: \"2025-10-26\"\n  source: maintainer\n  tags: \"supabase,sdk,database,auth,storage,realtime\"\n---\n# Supabase JavaScript SDK Coding Guidelines\n\nYou are a Supabase coding expert. Help me write code using the Supabase JavaScript SDK, which provides a complete backend-as-a-service solution with authentication, database, storage, realtime subscriptions, and edge functions.\n\nYou can find the official SDK documentation here:\nhttps://supabase.com/docs/reference/javascript/introduction\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Supabase JavaScript SDK (`@supabase/supabase-js`) for all Supabase interactions. Do not use deprecated libraries or unofficial packages.\n\n- **Library Name:** Supabase JavaScript SDK\n- **NPM Package:** `@supabase/supabase-js`\n- **Current Version:** 2.76.1\n- **Legacy Libraries:** Do not use `@supabase/auth-js`, `@supabase/postgrest-js`, `@supabase/storage-js`, or other individual packages directly - these are bundled in the main SDK\n\n**Installation:**\n\n```bash\nnpm install @supabase/supabase-js\n```\n\n**APIs and Usage:**\n\n- **Correct:** `import { createClient } from '@supabase/supabase-js'`\n- **Correct:** `const supabase = createClient(url, anonKey)`\n- **Correct:** `await supabase.from('table').select()`\n- **Correct:** `await supabase.auth.signInWithPassword()`\n- **Incorrect:** Using individual package imports\n- **Incorrect:** `new Supabase()` or `SupabaseClient()`\n\n## Initialization\n\nThe Supabase SDK requires your project URL and public anon key for initialization.\n\n### Basic Client Setup\n\n```javascript\nimport { createClient } from '@supabase/supabase-js'\n\nconst supabaseUrl = process.env.SUPABASE_URL\nconst supabaseAnonKey = process.env.SUPABASE_ANON_KEY\n\nconst supabase = createClient(supabaseUrl, supabaseAnonKey)\n```\n\n### Environment Variables\n\nSet these environment variables in your `.env` file:\n\n```bash\nSUPABASE_URL=https://xyzcompany.supabase.co\nSUPABASE_ANON_KEY=your-anon-key-here\n```\n\n### Client Initialization with Options\n\n```javascript\nimport { createClient } from '@supabase/supabase-js'\n\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  auth: {\n    autoRefreshToken: true,\n    persistSession: true,\n    detectSessionInUrl: true\n  },\n  db: {\n    schema: 'public'\n  },\n  global: {\n    headers: { 'x-my-custom-header': 'my-app-name' }\n  }\n})\n```\n\n### Server-Side Client (No Session Persistence)\n\n```javascript\nimport { createClient } from '@supabase/supabase-js'\n\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  auth: {\n    autoRefreshToken: false,\n    persistSession: false,\n    detectSessionInUrl: false\n  }\n})\n```\n\n## Authentication\n\nThe Supabase SDK provides comprehensive authentication through `supabase.auth`.\n\n### Sign Up with Email and Password\n\n```javascript\nconst { data, error } = await supabase.auth.signUp({\n  email: 'user@example.com',\n  password: 'secure-password-123'\n})\n\nif (error) {\n  console.error('Error signing up:', error.message)\n} else {\n  console.log('User created:', data.user)\n}\n```\n\n### Sign Up with Additional User Metadata\n\n```javascript\nconst { data, error } = await supabase.auth.signUp({\n  email: 'user@example.com',\n  password: 'secure-password-123',\n  options: {\n    data: {\n      first_name: 'John',\n      age: 27\n    }\n  }\n})\n```\n\n### Sign In with Email and Password\n\n```javascript\nconst { data, error } = await supabase.auth.signInWithPassword({\n  email: 'user@example.com',\n  password: 'secure-password-123'\n})\n\nif (error) {\n  console.error('Error signing in:', error.message)\n} else {\n  console.log('User signed in:', data.user)\n  console.log('Session:', data.session)\n}\n```\n\n### Sign In with OAuth\n\n```javascript\nconst { data, error } = await supabase.auth.signInWithOAuth({\n  provider: 'google'\n})\n\n// Available providers: google, github, gitlab, bitbucket, azure,\n// facebook, twitter, discord, slack, spotify, twitch, linkedin, etc.\n```\n\n### Sign In with OAuth and Options\n\n```javascript\nconst { data, error } = await supabase.auth.signInWithOAuth({\n  provider: 'google',\n  options: {\n    redirectTo: 'https://example.com/auth/callback',\n    scopes: 'https://www.googleapis.com/auth/calendar',\n    queryParams: {\n      access_type: 'offline',\n      prompt: 'consent'\n    }\n  }\n})\n```\n\n### Sign In with Magic Link (OTP)\n\n```javascript\nconst { data, error } = await supabase.auth.signInWithOtp({\n  email: 'user@example.com',\n  options: {\n    emailRedirectTo: 'https://example.com/welcome'\n  }\n})\n```\n\n### Sign In with Phone OTP\n\n```javascript\n// Send OTP\nconst { data, error } = await supabase.auth.signInWithOtp({\n  phone: '+1234567890'\n})\n\n// Verify OTP\nconst { data, error } = await supabase.auth.verifyOtp({\n  phone: '+1234567890',\n  token: '123456',\n  type: 'sms'\n})\n```\n\n### Anonymous Sign In\n\n```javascript\nconst { data, error } = await supabase.auth.signInAnonymously()\n\nconsole.log('Anonymous user:', data.user)\n```\n\n### Get Current User\n\n```javascript\nconst { data: { user } } = await supabase.auth.getUser()\n\nif (user) {\n  console.log('Current user:', user)\n} else {\n  console.log('No user logged in')\n}\n```\n\n### Get Current Session\n\n```javascript\nconst { data: { session } } = await supabase.auth.getSession()\n\nif (session) {\n  console.log('Access token:', session.access_token)\n  console.log('Refresh token:', session.refresh_token)\n  console.log('Expires at:', session.expires_at)\n}\n```\n\n### Update User\n\n```javascript\nconst { data, error } = await supabase.auth.updateUser({\n  email: 'newemail@example.com',\n  password: 'new-password-456',\n  data: {\n    first_name: 'Jane',\n    age: 28\n  }\n})\n```\n\n### Sign Out\n\n```javascript\nconst { error } = await supabase.auth.signOut()\n\nif (error) {\n  console.error('Error signing out:', error.message)\n} else {\n  console.log('User signed out successfully')\n}\n```\n\n### Password Reset\n\n```javascript\n// Send password reset email\nconst { data, error } = await supabase.auth.resetPasswordForEmail(\n  'user@example.com',\n  {\n    redirectTo: 'https://example.com/reset-password'\n  }\n)\n```\n\n### Auth State Changes Listener\n\n```javascript\nconst { data: { subscription } } = supabase.auth.onAuthStateChange(\n  (event, session) => {\n    console.log('Auth event:', event)\n    console.log('Session:', session)\n\n    if (event === 'SIGNED_IN') {\n      console.log('User signed in!')\n    }\n    if (event === 'SIGNED_OUT') {\n      console.log('User signed out!')\n    }\n  }\n)\n\n// Unsubscribe when done\nsubscription.unsubscribe()\n```\n\n### Refresh Session\n\n```javascript\nconst { data, error } = await supabase.auth.refreshSession()\n\nconsole.log('New session:', data.session)\n```\n\n### Exchange Auth Code (OAuth Flow)\n\n```javascript\nconst { data, error } = await supabase.auth.exchangeCodeForSession(code)\n```\n\n## Database Queries\n\nThe Supabase SDK uses PostgREST for database operations with a chainable API.\n\n### Select All Rows\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n\nif (error) {\n  console.error('Error fetching data:', error.message)\n} else {\n  console.log('Countries:', data)\n}\n```\n\n### Select Specific Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('id, name, capital')\n```\n\n### Select with Column Alias\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('country_name:name, country_id:id')\n```\n\n### Select with Foreign Table Relations\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select(`\n    name,\n    cities (\n      name,\n      population\n    )\n  `)\n```\n\n### Select with Multiple Foreign Key References\n\n```javascript\nconst { data, error } = await supabase\n  .from('messages')\n  .select(`\n    content,\n    from:sender_id(name),\n    to:receiver_id(name)\n  `)\n```\n\n### Select with Nested Foreign Tables\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select(`\n    name,\n    cities (\n      name,\n      buildings (\n        name,\n        floors\n      )\n    )\n  `)\n```\n\n### Select with Filters\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .eq('name', 'United States')\n```\n\n### Filtering Operators\n\n```javascript\n// Equals\n.eq('column', 'value')\n\n// Not equals\n.neq('column', 'value')\n\n// Greater than\n.gt('column', 10)\n\n// Greater than or equal\n.gte('column', 10)\n\n// Less than\n.lt('column', 10)\n\n// Less than or equal\n.lte('column', 10)\n\n// Pattern matching (case-sensitive)\n.like('column', '%pattern%')\n\n// Pattern matching (case-insensitive)\n.ilike('column', '%pattern%')\n\n// Is null\n.is('column', null)\n\n// In array\n.in('column', ['value1', 'value2', 'value3'])\n\n// Contains (for arrays)\n.contains('column', ['value1', 'value2'])\n\n// Contained by (for arrays)\n.containedBy('column', ['value1', 'value2', 'value3'])\n\n// Range overlap\n.overlaps('column', [start, end])\n\n// Full text search\n.textSearch('column', 'search terms')\n```\n\n### Multiple Filters (AND)\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .eq('continent', 'Europe')\n  .gt('population', 1000000)\n```\n\n### OR Filters\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .or('continent.eq.Europe,continent.eq.Asia')\n```\n\n### Filter on Foreign Table Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('name, cities(*)')\n  .eq('cities.name', 'Paris')\n```\n\n### Inner Join (Only Return Rows with Matches)\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('name, cities!inner(name)')\n  .eq('cities.name', 'Paris')\n```\n\n### Ordering Results\n\n```javascript\n// Ascending order\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .order('name', { ascending: true })\n\n// Descending order\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .order('population', { ascending: false })\n```\n\n### Ordering with Nulls\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .order('name', { ascending: true, nullsFirst: false })\n```\n\n### Order Foreign Table Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('name, cities(name)')\n  .order('name', { foreignTable: 'cities' })\n```\n\n### Limit Results\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .limit(10)\n```\n\n### Limit Foreign Table Rows\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('name, cities(name)')\n  .limit(5, { foreignTable: 'cities' })\n```\n\n### Pagination with Range\n\n```javascript\n// Get rows 0-9\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .range(0, 9)\n\n// Get rows 10-19\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .range(10, 19)\n```\n\n### Get Single Row\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .eq('id', 1)\n  .single()\n\n// Returns single object instead of array\n```\n\n### Maybe Single (No Error if Not Found)\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n  .eq('id', 1)\n  .maybeSingle()\n```\n\n### Count Rows\n\n```javascript\nconst { count, error } = await supabase\n  .from('countries')\n  .select('*', { count: 'exact', head: true })\n\nconsole.log('Total countries:', count)\n```\n\n### Query JSON Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('users')\n  .select('id, name, address->city, address->country')\n```\n\n### Query Array Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('users')\n  .select('*')\n  .contains('tags', ['developer', 'designer'])\n```\n\n### Use Different Schema\n\n```javascript\nconst { data, error } = await supabase\n  .schema('private')\n  .from('employees')\n  .select('*')\n```\n\n## Insert Data\n\n### Insert Single Row\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .insert({\n    name: 'Canada',\n    capital: 'Ottawa',\n    population: 38000000\n  })\n```\n\n### Insert Single Row and Return Data\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .insert({\n    name: 'Canada',\n    capital: 'Ottawa'\n  })\n  .select()\n\nconsole.log('Inserted row:', data)\n```\n\n### Insert Multiple Rows\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .insert([\n    { name: 'Canada', capital: 'Ottawa' },\n    { name: 'Mexico', capital: 'Mexico City' },\n    { name: 'Brazil', capital: 'Brasilia' }\n  ])\n  .select()\n```\n\n### Insert and Return Specific Columns\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .insert({ name: 'Canada', capital: 'Ottawa' })\n  .select('id, name')\n```\n\n## Update Data\n\n### Update Matching Rows\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .update({ capital: 'New Capital' })\n  .eq('name', 'Canada')\n```\n\n### Update with Multiple Filters\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .update({ population: 39000000 })\n  .eq('name', 'Canada')\n  .lt('population', 40000000)\n```\n\n### Update and Return Data\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .update({ capital: 'New Capital' })\n  .eq('id', 1)\n  .select()\n```\n\n### Update JSON Column\n\n```javascript\nconst { data, error } = await supabase\n  .from('users')\n  .update({\n    settings: { theme: 'dark', language: 'en' }\n  })\n  .eq('id', 1)\n```\n\n## Upsert Data\n\n### Upsert (Insert or Update)\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .upsert({\n    id: 1,\n    name: 'Canada',\n    capital: 'Ottawa'\n  })\n```\n\n### Upsert Multiple Rows\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .upsert([\n    { id: 1, name: 'Canada', capital: 'Ottawa' },\n    { id: 2, name: 'Mexico', capital: 'Mexico City' }\n  ])\n```\n\n### Upsert with Conflict Resolution\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .upsert(\n    { id: 1, name: 'Canada' },\n    { onConflict: 'id' }\n  )\n```\n\n### Upsert and Ignore Duplicates\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .upsert(\n    { name: 'Canada', capital: 'Ottawa' },\n    { onConflict: 'name', ignoreDuplicates: true }\n  )\n```\n\n## Delete Data\n\n### Delete Matching Rows\n\n```javascript\nconst { error } = await supabase\n  .from('countries')\n  .delete()\n  .eq('name', 'Canada')\n```\n\n### Delete with Multiple Filters\n\n```javascript\nconst { error } = await supabase\n  .from('countries')\n  .delete()\n  .eq('continent', 'Europe')\n  .lt('population', 100000)\n```\n\n### Delete and Return Data\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .delete()\n  .eq('id', 1)\n  .select()\n```\n\n## RPC (Call Postgres Functions)\n\n### Call Function Without Parameters\n\n```javascript\nconst { data, error } = await supabase.rpc('hello_world')\n\nconsole.log('Function result:', data)\n```\n\n### Call Function with Parameters\n\n```javascript\nconst { data, error } = await supabase.rpc('add_numbers', {\n  a: 5,\n  b: 10\n})\n\nconsole.log('Sum:', data)\n```\n\n### Call Function with Array Parameter\n\n```javascript\nconst { data, error } = await supabase.rpc('add_one_each', {\n  arr: [1, 2, 3, 4, 5]\n})\n\nconsole.log('Result:', data)\n```\n\n### Chain Filters with RPC\n\n```javascript\nconst { data, error } = await supabase\n  .rpc('get_countries')\n  .eq('continent', 'Europe')\n  .order('population', { ascending: false })\n  .limit(10)\n```\n\n### RPC with Single Result\n\n```javascript\nconst { data, error } = await supabase\n  .rpc('get_country_by_id', { country_id: 1 })\n  .single()\n```\n\n### Call Function on Read Replica\n\n```javascript\nconst { data, error } = await supabase.rpc(\n  'get_data',\n  {},\n  { get: true }\n)\n```\n\n## Realtime Subscriptions\n\nThe Supabase SDK provides realtime functionality through channels.\n\n### Subscribe to Database Changes\n\n```javascript\nconst channel = supabase\n  .channel('db-changes')\n  .on(\n    'postgres_changes',\n    {\n      event: '*',\n      schema: 'public',\n      table: 'countries'\n    },\n    (payload) => {\n      console.log('Change received!', payload)\n    }\n  )\n  .subscribe()\n```\n\n### Subscribe to INSERT Events\n\n```javascript\nconst channel = supabase\n  .channel('db-inserts')\n  .on(\n    'postgres_changes',\n    {\n      event: 'INSERT',\n      schema: 'public',\n      table: 'countries'\n    },\n    (payload) => {\n      console.log('New record:', payload.new)\n    }\n  )\n  .subscribe()\n```\n\n### Subscribe to UPDATE Events\n\n```javascript\nconst channel = supabase\n  .channel('db-updates')\n  .on(\n    'postgres_changes',\n    {\n      event: 'UPDATE',\n      schema: 'public',\n      table: 'countries'\n    },\n    (payload) => {\n      console.log('Old record:', payload.old)\n      console.log('New record:', payload.new)\n    }\n  )\n  .subscribe()\n```\n\n### Subscribe to DELETE Events\n\n```javascript\nconst channel = supabase\n  .channel('db-deletes')\n  .on(\n    'postgres_changes',\n    {\n      event: 'DELETE',\n      schema: 'public',\n      table: 'countries'\n    },\n    (payload) => {\n      console.log('Deleted record:', payload.old)\n    }\n  )\n  .subscribe()\n```\n\n### Subscribe with Row-Level Filter\n\n```javascript\nconst channel = supabase\n  .channel('specific-row')\n  .on(\n    'postgres_changes',\n    {\n      event: '*',\n      schema: 'public',\n      table: 'countries',\n      filter: 'id=eq.1'\n    },\n    (payload) => {\n      console.log('Change to specific row:', payload)\n    }\n  )\n  .subscribe()\n```\n\n### Subscribe to Multiple Tables\n\n```javascript\nconst channel = supabase\n  .channel('multi-table')\n  .on(\n    'postgres_changes',\n    { event: '*', schema: 'public', table: 'countries' },\n    handleCountryChange\n  )\n  .on(\n    'postgres_changes',\n    { event: '*', schema: 'public', table: 'cities' },\n    handleCityChange\n  )\n  .subscribe()\n```\n\n### Unsubscribe from Changes\n\n```javascript\nconst channel = supabase.channel('my-channel')\n\n// ... set up subscriptions\n\n// Later, unsubscribe\nawait supabase.removeChannel(channel)\n```\n\n### Broadcast Messages\n\n```javascript\n// Send broadcast\nconst channel = supabase.channel('room-1')\n\nchannel.subscribe((status) => {\n  if (status === 'SUBSCRIBED') {\n    channel.send({\n      type: 'broadcast',\n      event: 'cursor-pos',\n      payload: { x: 100, y: 200 }\n    })\n  }\n})\n\n// Receive broadcast\nchannel.on('broadcast', { event: 'cursor-pos' }, (payload) => {\n  console.log('Cursor position:', payload)\n})\n```\n\n### Presence Tracking\n\n```javascript\nconst channel = supabase.channel('room-1')\n\n// Track user presence\nchannel.on('presence', { event: 'sync' }, () => {\n  const state = channel.presenceState()\n  console.log('Online users:', state)\n})\n\nchannel.on('presence', { event: 'join' }, ({ key, newPresences }) => {\n  console.log('User joined:', newPresences)\n})\n\nchannel.on('presence', { event: 'leave' }, ({ key, leftPresences }) => {\n  console.log('User left:', leftPresences)\n})\n\n// Subscribe and track current user\nchannel.subscribe(async (status) => {\n  if (status === 'SUBSCRIBED') {\n    await channel.track({\n      user_id: 1,\n      online_at: new Date().toISOString()\n    })\n  }\n})\n```\n\n### Untrack Presence\n\n```javascript\nawait channel.untrack()\n```\n\n### Channel Status Callbacks\n\n```javascript\nconst channel = supabase\n  .channel('my-channel')\n  .subscribe((status, err) => {\n    if (status === 'SUBSCRIBED') {\n      console.log('Connected!')\n    }\n    if (status === 'CHANNEL_ERROR') {\n      console.error('Connection error:', err)\n    }\n    if (status === 'TIMED_OUT') {\n      console.log('Connection timed out')\n    }\n    if (status === 'CLOSED') {\n      console.log('Channel closed')\n    }\n  })\n```\n\n## Storage\n\nThe Supabase SDK provides file storage through `supabase.storage`.\n\n### List Buckets\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .listBuckets()\n\nconsole.log('Buckets:', data)\n```\n\n### Get Bucket\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .getBucket('avatars')\n\nconsole.log('Bucket:', data)\n```\n\n### Create Bucket\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .createBucket('avatars', {\n    public: false,\n    fileSizeLimit: 1024000\n  })\n```\n\n### Update Bucket\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .updateBucket('avatars', {\n    public: true\n  })\n```\n\n### Delete Bucket\n\n```javascript\n// Must empty bucket first\nconst { data: files } = await supabase\n  .storage\n  .from('avatars')\n  .list()\n\nawait supabase\n  .storage\n  .from('avatars')\n  .remove(files.map(file => file.name))\n\n// Then delete bucket\nconst { data, error } = await supabase\n  .storage\n  .deleteBucket('avatars')\n```\n\n### Empty Bucket\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .emptyBucket('avatars')\n```\n\n### Upload File\n\n```javascript\nconst file = event.target.files[0]\n\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .upload('public/avatar1.png', file, {\n    cacheControl: '3600',\n    upsert: false\n  })\n\nif (error) {\n  console.error('Error uploading:', error.message)\n} else {\n  console.log('File path:', data.path)\n}\n```\n\n### Upload File with Content Type\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .upload('folder/file.pdf', file, {\n    contentType: 'application/pdf'\n  })\n```\n\n### Upload and Overwrite Existing File\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .upload('public/avatar1.png', file, {\n    upsert: true\n  })\n```\n\n### Upload from Base64\n\n```javascript\nconst base64 = 'data:image/png;base64,iVBORw0KGgoAAAANS...'\n\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .upload('public/avatar1.png', base64, {\n    contentType: 'image/png'\n  })\n```\n\n### Download File\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .download('folder/avatar1.png')\n\nif (error) {\n  console.error('Error downloading:', error.message)\n} else {\n  // data is a Blob\n  const url = URL.createObjectURL(data)\n  console.log('File URL:', url)\n}\n```\n\n### Get Public URL\n\n```javascript\nconst { data } = supabase\n  .storage\n  .from('avatars')\n  .getPublicUrl('folder/avatar1.png')\n\nconsole.log('Public URL:', data.publicUrl)\n```\n\n### Get Public URL with Transform\n\n```javascript\nconst { data } = supabase\n  .storage\n  .from('avatars')\n  .getPublicUrl('folder/avatar1.png', {\n    transform: {\n      width: 200,\n      height: 200,\n      resize: 'cover'\n    }\n  })\n```\n\n### Create Signed URL\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .createSignedUrl('folder/avatar1.png', 3600)\n\nconsole.log('Signed URL:', data.signedUrl)\nconsole.log('Expires at:', new Date(Date.now() + 3600 * 1000))\n```\n\n### Create Signed URLs (Multiple)\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 3600)\n\nconsole.log('Signed URLs:', data)\n```\n\n### Create Signed Upload URL\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .createSignedUploadUrl('folder/avatar1.png')\n\nconsole.log('Upload URL:', data.signedUrl)\nconsole.log('Upload token:', data.token)\n```\n\n### Upload to Signed URL\n\n```javascript\nconst { data: signedData } = await supabase\n  .storage\n  .from('avatars')\n  .createSignedUploadUrl('folder/avatar1.png')\n\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .uploadToSignedUrl(signedData.path, signedData.token, file)\n```\n\n### List Files in Bucket\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .list('folder', {\n    limit: 100,\n    offset: 0,\n    sortBy: { column: 'name', order: 'asc' }\n  })\n\nconsole.log('Files:', data)\n```\n\n### Search Files\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .list('folder', {\n    search: 'avatar'\n  })\n```\n\n### Move File\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .move('old/path/avatar.png', 'new/path/avatar.png')\n```\n\n### Copy File\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .copy('original/avatar.png', 'backup/avatar.png')\n```\n\n### Delete Files\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .remove(['folder/avatar1.png', 'folder/avatar2.png'])\n```\n\n### Get File Metadata\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .list('folder', {\n    limit: 1\n  })\n\nconsole.log('Metadata:', data[0])\n```\n\n## Edge Functions\n\nThe Supabase SDK allows invoking Edge Functions.\n\n### Invoke Function\n\n```javascript\nconst { data, error } = await supabase.functions.invoke('hello-world')\n\nif (error) {\n  console.error('Error invoking function:', error.message)\n} else {\n  console.log('Function response:', data)\n}\n```\n\n### Invoke Function with Body\n\n```javascript\nconst { data, error } = await supabase.functions.invoke('hello-world', {\n  body: {\n    name: 'JavaScript',\n    message: 'Hello from client'\n  }\n})\n\nconsole.log('Response:', data)\n```\n\n### Invoke Function with Custom Headers\n\n```javascript\nconst { data, error } = await supabase.functions.invoke('hello-world', {\n  headers: {\n    'X-Custom-Header': 'my-value'\n  },\n  body: { name: 'JavaScript' }\n})\n```\n\n### Invoke Function with Method\n\n```javascript\nconst { data, error } = await supabase.functions.invoke('hello-world', {\n  method: 'POST',\n  body: { data: 'test' }\n})\n```\n\n### Invoke Function on Specific Region\n\n```javascript\nconst { data, error } = await supabase.functions.invoke('hello-world', {\n  region: 'us-west-1'\n})\n```\n\n## Error Handling\n\nAll Supabase operations return an object with `data` and `error` properties.\n\n### Basic Error Handling\n\n```javascript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n\nif (error) {\n  console.error('Database error:', error.message)\n  console.error('Error details:', error.details)\n  console.error('Error hint:', error.hint)\n} else {\n  console.log('Data:', data)\n}\n```\n\n### Error Properties\n\n```javascript\nif (error) {\n  console.log('Message:', error.message)\n  console.log('Details:', error.details)\n  console.log('Hint:', error.hint)\n  console.log('Code:', error.code)\n}\n```\n\n### Try-Catch with Async/Await\n\n```javascript\ntry {\n  const { data, error } = await supabase\n    .from('countries')\n    .select('*')\n\n  if (error) throw error\n\n  console.log('Data:', data)\n} catch (error) {\n  console.error('Error:', error.message)\n}\n```\n\n### Auth Error Handling\n\n```javascript\nconst { data, error } = await supabase.auth.signInWithPassword({\n  email: 'user@example.com',\n  password: 'wrong-password'\n})\n\nif (error) {\n  if (error.message.includes('Invalid login credentials')) {\n    console.log('Wrong email or password')\n  } else if (error.message.includes('Email not confirmed')) {\n    console.log('Please verify your email')\n  } else {\n    console.error('Auth error:', error.message)\n  }\n}\n```\n\n### Storage Error Handling\n\n```javascript\nconst { data, error } = await supabase\n  .storage\n  .from('avatars')\n  .upload('file.png', file)\n\nif (error) {\n  if (error.message.includes('Duplicate')) {\n    console.log('File already exists')\n  } else if (error.message.includes('Size')) {\n    console.log('File too large')\n  } else {\n    console.error('Storage error:', error.message)\n  }\n}\n```\n\n## TypeScript Support\n\nThe Supabase SDK has full TypeScript support with automatic type inference.\n\n### Define Database Types\n\n```typescript\nimport { createClient } from '@supabase/supabase-js'\n\ninterface Database {\n  public: {\n    Tables: {\n      countries: {\n        Row: {\n          id: number\n          name: string\n          capital: string | null\n          population: number | null\n        }\n        Insert: {\n          id?: number\n          name: string\n          capital?: string | null\n          population?: number | null\n        }\n        Update: {\n          id?: number\n          name?: string\n          capital?: string | null\n          population?: number | null\n        }\n      }\n    }\n  }\n}\n\nconst supabase = createClient<Database>(supabaseUrl, supabaseAnonKey)\n```\n\n### Type-Safe Queries\n\n```typescript\nconst { data, error } = await supabase\n  .from('countries')\n  .select('*')\n\n// data is automatically typed as Database['public']['Tables']['countries']['Row'][]\n```\n\n### Generate Types from Database\n\nUse the Supabase CLI to generate types:\n\n```bash\nsupabase gen types typescript --project-id your-project-id > types/supabase.ts\n```\n\nThen import and use:\n\n```typescript\nimport { Database } from './types/supabase'\n\nconst supabase = createClient<Database>(supabaseUrl, supabaseAnonKey)\n```\n\n## Advanced Configuration\n\n### Custom Fetch Implementation\n\n```javascript\nimport { createClient } from '@supabase/supabase-js'\n\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  global: {\n    fetch: customFetch\n  }\n})\n```\n\n### Custom Headers\n\n```javascript\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  global: {\n    headers: {\n      'x-application-name': 'my-app'\n    }\n  }\n})\n```\n\n### Schema Configuration\n\n```javascript\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  db: {\n    schema: 'private'\n  }\n})\n```\n\n### Auth Configuration\n\n```javascript\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  auth: {\n    autoRefreshToken: true,\n    persistSession: true,\n    detectSessionInUrl: true,\n    storage: customStorageAdapter,\n    storageKey: 'my-app-auth-token',\n    flowType: 'pkce'\n  }\n})\n```\n\n### Realtime Configuration\n\n```javascript\nconst supabase = createClient(supabaseUrl, supabaseAnonKey, {\n  realtime: {\n    params: {\n      eventsPerSecond: 10\n    }\n  }\n})\n```\n\n## Useful Links\n\n- Documentation: https://supabase.com/docs\n- JavaScript SDK Reference: https://supabase.com/docs/reference/javascript/introduction\n- API Reference: https://supabase.com/docs/guides/api\n- Auth Documentation: https://supabase.com/docs/guides/auth\n- Database Documentation: https://supabase.com/docs/guides/database\n- Storage Documentation: https://supabase.com/docs/guides/storage\n- Realtime Documentation: https://supabase.com/docs/guides/realtime\n- Edge Functions: https://supabase.com/docs/guides/functions\n"
  },
  {
    "path": "content/supabase/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Supabase Python client for Postgres queries, auth, storage, edge functions, and realtime\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.28.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"supabase,postgres,auth,storage,realtime,edge-functions,python\"\n---\n\n# Supabase Python Client\n\n## Golden Rule\n\nUse the official `supabase` package, initialize it with your project URL and key, and treat database and storage access as policy-controlled operations. Most \"it returned nothing\" or \"permission denied\" problems come from row-level security (RLS), missing filters, or using the wrong key for the job.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"supabase==2.28.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"supabase==2.28.0\"\npoetry add \"supabase==2.28.0\"\n```\n\nVersion note:\n\n- The Supabase install page still says Python `>3.8`, but PyPI metadata for `2.28.0` requires Python `>=3.9`. Follow PyPI for the package constraint you actually install.\n\n## Initialize The Client\n\nSet your project URL and key in the environment:\n\n```bash\nexport SUPABASE_URL=\"https://your-project-ref.supabase.co\"\nexport SUPABASE_KEY=\"your-anon-or-service-role-key\"\n```\n\nCreate the client:\n\n```python\nimport os\n\nfrom supabase import Client, create_client\n\nurl = os.environ[\"SUPABASE_URL\"]\nkey = os.environ[\"SUPABASE_KEY\"]\n\nsupabase: Client = create_client(url, key)\n```\n\nKey selection matters:\n\n- Use the `anon` or publishable key for user-scoped access governed by RLS.\n- Use the `service_role` key only in trusted backend code for admin workflows.\n- Do not ship a `service_role` key in client-visible code, notebooks you do not control, or shared scripts.\n\n## Core Database Usage\n\nAll table operations build a query and then execute it with `.execute()`.\n\n### Select rows\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .select(\"id, name, section_id\")\n    .eq(\"name\", \"violin\")\n    .execute()\n)\n\nprint(response.data)\n```\n\n### Insert rows\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .insert({\"id\": 1, \"name\": \"violin\"})\n    .execute()\n)\n```\n\n### Update rows\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .update({\"name\": \"piano\"})\n    .eq(\"id\", 1)\n    .execute()\n)\n```\n\n### Upsert rows\n\n`upsert()` is for insert-or-update behavior. Include primary key columns in the payload.\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .upsert({\"id\": 1, \"name\": \"violin\"})\n    .execute()\n)\n```\n\n### Delete rows\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .delete()\n    .eq(\"id\", 1)\n    .execute()\n)\n```\n\n### Use filters deliberately\n\nFilters chain onto the builder before `.execute()`:\n\n```python\nresponse = (\n    supabase.table(\"instruments\")\n    .select(\"*\")\n    .eq(\"section_id\", 10)\n    .order(\"name\")\n    .limit(20)\n    .execute()\n)\n```\n\n### Call a Postgres function\n\nUse `rpc()` for stored procedures and SQL functions exposed through PostgREST:\n\n```python\nresponse = supabase.rpc(\"hello_world\").execute()\nprint(response.data)\n```\n\n## Auth\n\n### Sign up a user\n\n```python\nresponse = supabase.auth.sign_up(\n    {\n        \"email\": \"alice@example.com\",\n        \"password\": \"strong-password\",\n    }\n)\n```\n\n### Sign in with email and password\n\n```python\nresponse = supabase.auth.sign_in_with_password(\n    {\n        \"email\": \"alice@example.com\",\n        \"password\": \"strong-password\",\n    }\n)\n```\n\n### Sign out\n\n```python\nsupabase.auth.sign_out()\n```\n\n### Prefer `get_user()` when identity must be trusted\n\n`auth.get_session()` reads the current session from the client-side storage layer. The Supabase docs warn that, in insecure storage contexts such as request cookies, this value should not be treated as authoritative for authorization decisions. Prefer `auth.get_user()` when you need the Auth server to validate the user represented by the access token.\n\n## Storage\n\nUpload to a bucket:\n\n```python\nwith open(\"avatar.png\", \"rb\") as file_obj:\n    response = supabase.storage.from_(\"avatars\").upload(\n        \"public/avatar.png\",\n        file_obj,\n    )\n```\n\nGet a public URL:\n\n```python\npublic_url = supabase.storage.from_(\"avatars\").get_public_url(\"public/avatar.png\")\nprint(public_url)\n```\n\nCreate a signed URL for a private object:\n\n```python\nsigned = supabase.storage.from_(\"avatars\").create_signed_url(\n    \"private/avatar.png\",\n    60,\n)\nprint(signed)\n```\n\nStorage access is also policy-driven. Bucket permissions and object policies can block uploads or reads even when the Python code is correct.\n\n## Edge Functions\n\nInvoke a deployed Supabase Edge Function:\n\n```python\nresponse = supabase.functions.invoke(\n    \"hello-world\",\n    invoke_options={\"body\": {\"name\": \"Supabase\"}},\n)\n```\n\nUse this for backend logic that should not run in the client or that needs privileged server-side behavior.\n\n## Realtime\n\nSubscribe to a channel:\n\n```python\nchannel = supabase.channel(\"room1\")\n\nchannel.subscribe()\n```\n\nClean up channels when they are no longer needed:\n\n```python\nawait supabase.remove_channel(channel)\nawait supabase.remove_all_channels()\n```\n\nThe Realtime docs note that Supabase cleans up disconnected channels automatically after about 30 seconds, but explicit cleanup reduces unnecessary server load and open subscriptions in long-lived processes.\n\n## Server-Only Admin Workflows\n\nAdmin Auth APIs require a client initialized with the `service_role` key.\n\n```python\nimport os\n\nfrom supabase import create_client\n\nadmin = create_client(\n    os.environ[\"SUPABASE_URL\"],\n    os.environ[\"SUPABASE_SERVICE_ROLE_KEY\"],\n)\n\nresponse = admin.auth.admin.create_user(\n    {\n        \"email\": \"admin-created@example.com\",\n        \"password\": \"temporary-password\",\n        \"email_confirm\": True,\n    }\n)\n```\n\nUse a separate admin client rather than reusing a user-scoped client with mixed credentials.\n\n## Common Pitfalls\n\n- RLS is usually the first thing to check. `select`, `update`, `delete`, storage reads, and uploads can all fail or return no rows when policies do not allow the action.\n- The Python builder does nothing until `.execute()` runs. Forgetting `.execute()` leaves you with a query object, not a result.\n- Add filters before destructive operations. A bare `.delete()` or `.update()` without the intended `.eq(...)` or other filter is an easy mistake.\n- Supabase recommends keeping result sizes small. By default, projects return at most 1,000 rows per request, so use `limit()` and pagination or ranges for larger scans.\n- `upsert()` needs conflict keys already present in the payload. If the primary key or unique key is missing, it cannot behave like the insert-or-update you expect.\n- Use `auth.get_user()` for trusted identity checks. Do not make authorization decisions from `get_session()` alone when the underlying storage can be tampered with.\n- Realtime subscriptions should be removed explicitly in workers, daemons, and async applications instead of relying only on server-side cleanup.\n- Keep `service_role` keys strictly on the backend. The admin API bypasses normal end-user constraints and should be treated as a secret.\n\n## Version-Sensitive Notes For 2.28.0\n\n- PyPI lists `2.28.0` as the current release and requires Python `>=3.9`.\n- The release history shows several yanked `2.19.0` to `2.23.3` builds because of dependency issues or minor breaking auth changes. If you find examples pinned in that range, prefer `2.24.0` or later unless the project is already locked to an older wheel.\n- The `auth.get_user()` reference for `2.28.0` documents additional user fields such as `is_anonymous`, `factors`, `app_metadata`, `user_metadata`, and `identities`. If your code inspects user objects from older examples, re-check the returned shape before relying on it.\n\n## Official Sources\n\n- Python reference root: `https://supabase.com/docs/reference/python`\n- Installing: `https://supabase.com/docs/reference/python/installing`\n- Initializing: `https://supabase.com/docs/reference/python/initializing`\n- Select and filters: `https://supabase.com/docs/reference/python/select`\n- Insert: `https://supabase.com/docs/reference/python/insert`\n- Upsert: `https://supabase.com/docs/reference/python/upsert`\n- Delete: `https://supabase.com/docs/reference/python/delete`\n- Auth signup: `https://supabase.com/docs/reference/python/auth-signup`\n- Auth sign-in: `https://supabase.com/docs/reference/python/auth-signinwithpassword`\n- Auth get user/session: `https://supabase.com/docs/reference/python/auth-getuser`, `https://supabase.com/docs/reference/python/auth-getsession`\n- Auth admin create user: `https://supabase.com/docs/reference/python/auth-admin-createuser`\n- Storage upload/public URL/signed URL: `https://supabase.com/docs/reference/python/storage-from-upload`, `https://supabase.com/docs/reference/python/storage-from-getpublicurl`, `https://supabase.com/docs/reference/python/storage-from-createsignedurl`\n- Functions invoke: `https://supabase.com/docs/reference/python/functions-invoke`\n- Realtime subscribe: `https://supabase.com/docs/reference/python/subscribe`\n- PyPI package metadata and release history: `https://pypi.org/project/supabase/`\n"
  },
  {
    "path": "content/supervisor/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Supervisor Python package guide for managing long-running UNIX processes with supervisord and supervisorctl\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"supervisor,process-manager,unix,daemon,xml-rpc,supervisord,supervisorctl\"\n---\n\n# Supervisor Python Package Guide\n\n## Golden Rule\n\nUse `supervisor` when you need a process-control system for long-running UNIX processes, and make sure the managed command stays in the foreground. Supervisor expects to own process lifecycle itself; if the child daemonizes, forks away, or double-backgrounds, Supervisor will treat it as a failed start.\n\n## Install\n\nPin the version you expect:\n\n```bash\npython -m pip install \"supervisor==4.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"supervisor==4.3.0\"\npoetry add \"supervisor==4.3.0\"\n```\n\nUseful verification:\n\n```bash\nsupervisord --version\necho_supervisord_conf | head\n```\n\nVersion-sensitive packaging note:\n\n- The `4.3.0` release notes say Python `<3.8` may still require `setuptools` to be installed, while Python `>=3.8` no longer needs it at runtime.\n\n## Initialize And Start\n\nGenerate a starting config and edit it:\n\n```bash\nmkdir -p .supervisor\necho_supervisord_conf > .supervisor/supervisord.conf\n```\n\nMinimal practical config:\n\n```ini\n[unix_http_server]\nfile=/tmp/supervisor.sock\nchmod=0700\n\n[supervisord]\nlogfile=/tmp/supervisord.log\npidfile=/tmp/supervisord.pid\nchildlogdir=/tmp\n\n[rpcinterface:supervisor]\nsupervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface\n\n[supervisorctl]\nserverurl=unix:///tmp/supervisor.sock\n\n[program:web]\ncommand=/Users/me/app/.venv/bin/gunicorn myapp.wsgi:application --bind 127.0.0.1:8000\ndirectory=/Users/me/app\nautostart=true\nautorestart=unexpected\nstartsecs=5\nstopasgroup=true\nkillasgroup=true\nstdout_logfile=/Users/me/app/logs/web.stdout.log\nstderr_logfile=/Users/me/app/logs/web.stderr.log\nenvironment=APP_ENV=\"production\",PYTHONUNBUFFERED=\"1\"\n```\n\nStart Supervisor with an explicit config path:\n\n```bash\nsupervisord -c \"$PWD/.supervisor/supervisord.conf\"\n```\n\nCheck status:\n\n```bash\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" status\n```\n\nWhy the explicit `-c` matters:\n\n- Supervisor searches several default config locations if `-c` is omitted.\n- The docs warn that using a config in the current directory without `-c` is a security risk when running as root.\n- Agents should use an absolute path and keep the `supervisord` and `supervisorctl` config path aligned.\n\n## Core Usage\n\n### Manage one or more programs\n\nSupervisor controls processes declared in `[program:x]` sections:\n\n```ini\n[program:worker]\ncommand=/Users/me/app/.venv/bin/python worker.py\ndirectory=/Users/me/app\nuser=appuser\nautostart=true\nautorestart=unexpected\nstartretries=3\nredirect_stderr=true\nstdout_logfile=/Users/me/app/logs/worker.log\n```\n\nKey behaviors:\n\n- `command` should start exactly one long-running foreground process.\n- `directory` sets the child working directory.\n- `user` drops privileges for the child process if `supervisord` has permission to do so.\n- `autorestart=unexpected` is usually safer than unconditional `true` for services that deliberately exit on certain conditions.\n- `stopasgroup=true` and `killasgroup=true` help when the child spawns subprocesses and you want signals to reach the whole process group.\n\n### Apply config changes correctly\n\nAfter editing config:\n\n```bash\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" reread\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" update\n```\n\nCommon control commands:\n\n```bash\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" status\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" start web\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" restart worker\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" tail -f web\nsupervisorctl -c \"$PWD/.supervisor/supervisord.conf\" shutdown\n```\n\nImportant distinction:\n\n- `reread` detects added, changed, or removed program config.\n- `update` applies those changes.\n- Editing the file alone does not restart running processes.\n\n### Group related processes\n\nWhen you want several named processes of the same shape, use `numprocs` and templates:\n\n```ini\n[program:queue]\nprocess_name=%(program_name)s_%(process_num)02d\nnumprocs=2\ncommand=/Users/me/app/.venv/bin/python worker.py --queue=%(process_num)s\ndirectory=/Users/me/app\nautostart=true\nautorestart=unexpected\nstdout_logfile=/Users/me/app/logs/queue_%(process_num)s.log\nredirect_stderr=true\n```\n\n## XML-RPC API\n\nSupervisor exposes an XML-RPC interface through the control socket or HTTP server. The default RPC namespace is `supervisor`.\n\nIf you need Python-side automation from another process, an HTTP listener is the simplest transport:\n\n```ini\n[inet_http_server]\nport=127.0.0.1:9001\nusername=admin\npassword=change-me\n\n[supervisorctl]\nserverurl=http://127.0.0.1:9001\nusername=admin\npassword=change-me\n```\n\nThen call the API at `/RPC2`:\n\n```python\nfrom xmlrpc.client import ServerProxy\n\nserver = ServerProxy(\"http://admin:change-me@127.0.0.1:9001/RPC2\")\n\nprint(server.supervisor.getSupervisorVersion())\nprint(server.supervisor.getState())\nprint(server.supervisor.getAllProcessInfo())\nserver.supervisor.startProcess(\"web\", False)\nserver.supervisor.stopProcess(\"web\", False)\n```\n\nCommon useful methods from the official API docs:\n\n- `getSupervisorVersion()`\n- `getState()`\n- `getAllProcessInfo()`\n- `startProcess(name, wait)`\n- `stopProcess(name, wait)`\n- `tailProcessStdoutLog(name, offset, length)`\n- `tailProcessStderrLog(name, offset, length)`\n\n## Config And Auth Notes\n\nPrefer a UNIX domain socket for local control:\n\n```ini\n[unix_http_server]\nfile=/tmp/supervisor.sock\nchmod=0700\n```\n\nUse `inet_http_server` only when you specifically need TCP access. If you enable it:\n\n- Bind to `127.0.0.1`, not `0.0.0.0`, unless you have a separate trusted tunnel or network boundary.\n- Set `username` and `password`.\n- Keep `supervisorctl` pointed at the same server URL and credentials.\n- Treat the listener as administrative access to process control, not as a public endpoint.\n\nEnvironment handling details that matter in practice:\n\n- Child processes inherit Supervisor's environment plus values from the `environment=` setting.\n- Use absolute paths for `command`, log files, and `directory` to avoid surprises when running under init systems or containers.\n- If the child buffers logs heavily, set `PYTHONUNBUFFERED=1` or equivalent in `environment=`.\n\n## Common Pitfalls\n\n- Do not point Supervisor at a daemonizing command unless you pass that program's foreground flag such as `--nodaemon`, `--foreground`, or the equivalent for that service.\n- Do not assume `reread` alone reloads changed processes; use `update` after it.\n- Do not expose `[inet_http_server]` on a public interface. The official docs describe it as intended only for trusted environments.\n- Do not forget `[rpcinterface:supervisor]`; XML-RPC clients and `supervisorctl` rely on that interface existing.\n- Do not use mismatched socket settings between `[unix_http_server]` and `[supervisorctl]`; `supervisorctl` will fail to connect even when `supervisord` is healthy.\n- The XML-RPC endpoint path is `/RPC2`, not `/`.\n- If a process exits immediately with `spawnerr`, inspect the command path, working directory, file permissions, and whether the target program is trying to daemonize itself.\n\n## Version-Sensitive Notes For 4.3.0\n\n- `4.3.0` fixes an issue where a spawned process that exited immediately could incorrectly produce `spawnerr: unknown error making dispatchers for 'process_name': EINVAL` on Python `3.13`.\n- The same release notes clarify that Python `<3.8` may still need `setuptools` at runtime, while Python `>=3.8` does not.\n- The docs URL points directly at the API page. For package docs, the more useful canonical docs set is the root docs plus the running, configuration, subprocess, and API pages:\n  - `https://supervisord.org/`\n  - `https://supervisord.org/running.html`\n  - `https://supervisord.org/configuration.html`\n  - `https://supervisord.org/subprocess.html`\n  - `https://supervisord.org/api.html`\n"
  },
  {
    "path": "content/svelte/docs/svelte/javascript/DOC.md",
    "content": "---\nname: svelte\ndescription: \"Svelte JavaScript package guide for building reactive UI with Svelte 5 components, runes, stores, and Vite\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.53.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"svelte,javascript,ui,frontend,components,vite\"\n---\n\n# Svelte JavaScript Package Guide\n\n## Golden Rule\n\nFor new Svelte 5 code, use the rune-based APIs documented in the current Svelte docs: `$props()` for component inputs, `$state(...)` for mutable reactive state, `$derived(...)` for computed values, and `$effect(...)` for side effects. Mount client-rendered apps with `mount(...)`, and use `hydrate(...)` only when you are attaching to HTML that was already rendered on the server.\n\nSvelte itself is the component compiler and runtime. It does not add routing, server rendering, or app conventions on its own. If you need those, use SvelteKit. If you only need a client-rendered app, pair `svelte` with Vite and `@sveltejs/vite-plugin-svelte`.\n\n## Install\n\nFor a new browser app, the simplest starting point is the official Vite Svelte template:\n\n```bash\nnpm create vite@latest my-app -- --template svelte\ncd my-app\nnpm install\nnpm run dev\n```\n\nTo add Svelte to an existing Vite project manually:\n\n```bash\nnpm install -D svelte@5.53.10 vite @sveltejs/vite-plugin-svelte\n```\n\nSvelte has no package-specific authentication step and no required environment variables.\n\n## Minimal Vite Setup\n\n`vite.config.js`:\n\n```js\nimport { defineConfig } from 'vite'\nimport { svelte } from '@sveltejs/vite-plugin-svelte'\n\nexport default defineConfig({\n  plugins: [svelte()],\n})\n```\n\n`svelte.config.js`:\n\n```js\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte'\n\nexport default {\n  preprocess: vitePreprocess(),\n}\n```\n\n`src/main.js`:\n\n```js\nimport { mount } from 'svelte'\nimport App from './App.svelte'\nimport './app.css'\n\nmount(App, {\n  target: document.getElementById('app'),\n})\n```\n\nTypical app scripts:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\"\n  }\n}\n```\n\n## Core Component Pattern\n\n`App.svelte`:\n\n```svelte\n<script>\n  let count = $state(0)\n  const doubled = $derived(count * 2)\n\n  $effect(() => {\n    console.log(`count changed to ${count}`)\n  })\n\n  function increment() {\n    count += 1\n  }\n</script>\n\n<main>\n  <button onclick={increment}>Count: {count}</button>\n  <p>Doubled: {doubled}</p>\n</main>\n```\n\nThis is the baseline Svelte 5 mental model:\n\n- Put mutable component state in `$state(...)`\n- Derive computed values with `$derived(...)`\n- Put DOM or external side effects in `$effect(...)`\n- Use normal JavaScript functions for event handlers and attach them with `onclick`, `oninput`, and similar attributes\n\n## Props And Parent Callbacks\n\nUse `$props()` in rune-based components instead of `export let`.\n\n`src/lib/TodoItem.svelte`:\n\n```svelte\n<script>\n  let { todo, onremove } = $props()\n</script>\n\n<li>\n  <span>{todo.text}</span>\n  <button onclick={() => onremove?.(todo.id)}>Remove</button>\n</li>\n```\n\n`App.svelte`:\n\n```svelte\n<script>\n  import TodoItem from './lib/TodoItem.svelte'\n\n  let todos = $state([\n    { id: 1, text: 'Ship docs' },\n    { id: 2, text: 'Review UI' },\n  ])\n\n  function removeTodo(id) {\n    todos = todos.filter(todo => todo.id !== id)\n  }\n</script>\n\n<ul>\n  {#each todos as todo (todo.id)}\n    <TodoItem {todo} onremove={removeTodo} />\n  {/each}\n</ul>\n```\n\nIn Svelte 5, parent-to-child communication is still props, and child-to-parent communication is usually a callback prop like `onremove` rather than `createEventDispatcher`.\n\n## Form Binding And Conditional UI\n\nTwo-way bindings still use `bind:`.\n\n```svelte\n<script>\n  let email = $state('')\n  let subscribed = $state(false)\n</script>\n\n<label>\n  Email\n  <input type=\"email\" bind:value={email} />\n</label>\n\n<label>\n  <input type=\"checkbox\" bind:checked={subscribed} />\n  Subscribe to updates\n</label>\n\n{#if subscribed && email}\n  <p>Saving newsletter preference for {email}</p>\n{:else}\n  <p>Enter an email and opt in to subscribe.</p>\n{/if}\n```\n\n`bind:value`, `bind:checked`, `bind:files`, and the other `bind:` forms are the normal way to keep DOM state and component state in sync.\n\n## Fetch Data In The Browser\n\nUse `onMount(...)` for browser-only work such as `fetch`, `window`, or `localStorage` access.\n\n```svelte\n<script>\n  import { onMount } from 'svelte'\n\n  let users = $state([])\n  let loading = $state(true)\n  let error = $state('')\n\n  onMount(() => {\n    const controller = new AbortController()\n\n    async function loadUsers() {\n      try {\n        const response = await fetch('/api/users', {\n          signal: controller.signal,\n        })\n\n        if (!response.ok) {\n          throw new Error(`Request failed: ${response.status}`)\n        }\n\n        users = await response.json()\n      } catch (err) {\n        if (err.name !== 'AbortError') {\n          error = err.message\n        }\n      } finally {\n        loading = false\n      }\n    }\n\n    loadUsers()\n\n    return () => controller.abort()\n  })\n</script>\n\n{#if loading}\n  <p>Loading...</p>\n{:else if error}\n  <p>{error}</p>\n{:else}\n  <ul>\n    {#each users as user (user.id)}\n      <li>{user.name}</li>\n    {/each}\n  </ul>\n{/if}\n```\n\n`onMount(...)` only runs in the browser. If the same component is rendered on the server, code inside `onMount(...)` is skipped there.\n\n## Shared State With Stores\n\nRune state is the default inside components, but Svelte stores are still useful when state must live in a separate module or be shared across unrelated components.\n\n`src/lib/theme.js`:\n\n```js\nimport { writable } from 'svelte/store'\n\nexport const theme = writable('light')\n```\n\n`src/lib/ThemePicker.svelte`:\n\n```svelte\n<script>\n  import { theme } from './theme.js'\n</script>\n\n<select bind:value={$theme}>\n  <option value=\"light\">Light</option>\n  <option value=\"dark\">Dark</option>\n</select>\n\n<p>Current theme: {$theme}</p>\n```\n\nInside a component, prefixing a store with `$` subscribes to it and gives you the current value. That auto-subscription syntax only works in Svelte component code, not in plain `.js` modules.\n\n## Hydration For Server-Rendered HTML\n\nUse `mount(...)` for a normal client-rendered app. Use `hydrate(...)` only if your page already contains HTML for the component tree and you want Svelte to attach event listeners and take over that markup.\n\n```js\nimport { hydrate } from 'svelte'\nimport App from './App.svelte'\n\nhydrate(App, {\n  target: document.getElementById('app'),\n})\n```\n\nIf you call `hydrate(...)` on empty markup, or `mount(...)` on server-rendered markup you expected to preserve, the DOM work will not line up with your intent.\n\n## Common Pitfalls\n\n- In current Svelte 5 docs, event handlers are written as properties such as `onclick={...}` rather than the older `on:click={...}` directive style.\n- In rune-based components, use `$props()` for inputs and callback props for parent notifications. Older patterns like `export let` and `createEventDispatcher` are compatibility patterns, not the preferred new style.\n- Only values created with `$state(...)` are mutable reactive state. Plain local variables do not automatically become rune state.\n- `onMount(...)` is browser-only. Do not read `window`, `document`, or `localStorage` at module evaluation time if the component can also render on the server.\n- Store auto-subscriptions like `$theme` only work inside `.svelte` files.\n\n## Version Notes For 5.53.10\n\nThis guide targets `svelte@5.53.10` and the Svelte 5 rune APIs. If you are maintaining older Svelte 4 code, you may still see legacy syntax in existing apps, but new Svelte 5 code should follow the rune-based patterns shown here.\n"
  },
  {
    "path": "content/sympy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"SymPy symbolic mathematics library for Python: expressions, algebra, calculus, solving, matrices, and numeric code generation\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.14.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"sympy,python,symbolic-math,cas,algebra,calculus,matrices\"\n---\n\n# SymPy Python Package Guide\n\n## Golden Rule\n\nUse SymPy objects end-to-end for symbolic work. Create symbols explicitly, represent equations with `Eq(...)`, keep values exact with SymPy numbers like `Integer`, `Rational`, and `pi`, and only convert to numeric code at the edge with `evalf()` or `lambdify()`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"sympy==1.14.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"sympy==1.14.0\"\npoetry add \"sympy==1.14.0\"\n```\n\nNotes:\n\n- `pip install sympy` already installs `mpmath`, which SymPy depends on.\n- `gmpy2` is a useful optional speedup for heavy integer and rational arithmetic workloads.\n- Install `matplotlib` if you need plotting.\n- Use `ipython` or Jupyter for a better interactive workflow.\n\n## Initialize And Set Up\n\nFor scripts, prefer a normal module import:\n\n```python\nimport sympy as sp\n\nx, y = sp.symbols(\"x y\", real=True)\nexpr = (x + y) ** 3\n\nprint(sp.expand(expr))\n```\n\nFor notebooks or REPL use, enable pretty printing:\n\n```python\nimport sympy as sp\n\nsp.init_printing()\nx = sp.symbols(\"x\")\n```\n\nFor an interactive shell with common imports preloaded, use:\n\n```bash\nisympy\n```\n\n## Core Usage\n\n### Define symbols with assumptions\n\nAssumptions materially affect simplification and integration behavior, so add them when they are known.\n\n```python\nimport sympy as sp\n\nx = sp.symbols(\"x\", positive=True)\nn = sp.symbols(\"n\", integer=True)\n\nprint(sp.sqrt(x**2))  # x\n```\n\n### Build and transform expressions\n\nPrefer targeted transforms like `expand()`, `factor()`, `cancel()`, and `collect()` when behavior needs to be predictable.\n\n```python\nimport sympy as sp\n\nx = sp.symbols(\"x\")\nexpr = (x + 1) ** 2\n\nprint(sp.expand(expr))   # x**2 + 2*x + 1\nprint(sp.factor(x**2 + 2*x + 1))  # (x + 1)**2\n```\n\n### Solve equations\n\nUse `Eq()` for explicit equations, pass the variable you want solved, and use `dict=True` if you need stable programmatic output.\n\n```python\nimport sympy as sp\n\nx, y = sp.symbols(\"x y\")\n\nsolutions = sp.solve(sp.Eq(x**2, y), x, dict=True)\nprint(solutions)\n# [{x: -sqrt(y)}, {x: sqrt(y)}]\n```\n\nUse `solveset()` when you want a mathematical set result with an explicit domain:\n\n```python\nimport sympy as sp\n\nx = sp.symbols(\"x\")\nroots = sp.solveset(sp.sin(x), x, domain=sp.Interval(-sp.pi, sp.pi))\nprint(roots)  # {0, -pi, pi}\n```\n\nUse `nsolve()` when you need a numeric root or when exact solving is not implemented:\n\n```python\nimport sympy as sp\n\nx = sp.symbols(\"x\")\nroot = sp.nsolve(sp.cos(x) - x, x, 0.5)\nprint(root)  # 0.739085...\n```\n\n### Calculus\n\n```python\nimport sympy as sp\n\nx = sp.symbols(\"x\")\nf = sp.sin(x) * sp.exp(x)\n\nprint(sp.diff(f, x))\nprint(sp.integrate(f, (x, 0, sp.pi)))\n```\n\n### Matrices and linear algebra\n\n```python\nimport sympy as sp\n\nA = sp.Matrix([[1, 2], [3, 4]])\n\nprint(A.det())\nprint(A.eigenvals())\nprint(A.inv())\n```\n\n### Move from symbolic to numeric code with `lambdify()`\n\nKeep symbolic and numeric code separate. Convert symbolic expressions into numeric callables explicitly.\n\n```python\nimport numpy as np\nimport sympy as sp\n\nx = sp.symbols(\"x\")\nexpr = sp.diff(sp.sin(x) * sp.exp(x**2), x)\n\nf = sp.lambdify(x, expr, modules=\"numpy\")\nxs = np.linspace(0, 2, 5)\nprint(f(xs))\n```\n\nSet `modules=` explicitly for reproducible behavior. If you omit it, SymPy chooses a backend based on what is installed in the environment.\n\n## Configuration And Environment Notes\n\nSymPy does not use API keys or service auth. The main setup concerns are environment consistency and optional tooling:\n\n- Use a virtual environment so `sympy`, `numpy`, `scipy`, and notebook tooling stay version-aligned.\n- Prefer `import sympy as sp` in real code over `from sympy import *`.\n- Use `sp.init_printing()` in notebooks for readable output.\n- Use `lambdify(..., modules=\"numpy\")`, `modules=\"mpmath\"`, or another explicit backend instead of relying on backend auto-detection.\n- Keep symbolic computation in SymPy and numeric array computation in NumPy/SciPy; bridge between them with `lambdify()`.\n\n## Common Pitfalls\n\n- `=` is Python assignment, not an equation. Use `sp.Eq(x, y)` when you mean mathematical equality.\n- `==` checks structural equality, not symbolic equivalence. `(x + 1)**2 == x**2 + 2*x + 1` is `False`.\n- Python numbers are not always SymPy numbers. Use `sp.Rational(1, 2)` or `sp.S(1) / 2` when exactness matters.\n- Do not mix `math` with symbolic expressions. Use `sp.pi`, `sp.sin`, and `expr.evalf()` instead of `math.pi`, `math.sin`, or implicit float conversions.\n- SymPy expressions are immutable. `expr.subs(...)` returns a new expression; it does not mutate the original.\n- Always pass the variable to `solve()` and `solveset()` when there is any ambiguity.\n- `solve()` returns different shapes depending on the problem. Use `dict=True` for stable programmatic handling.\n- `simplify()` is heuristic. In production code, prefer targeted transforms like `expand()`, `factor()`, `cancel()`, `collect()`, or `trigsimp()`.\n- Do not pass SymPy expressions back into functions produced by `lambdify()`. Those functions are for numeric inputs.\n\n## Version-Sensitive Notes For 1.14.0\n\n- PyPI lists `sympy 1.14.0` with `Requires: Python >=3.9` and classifiers for Python `3.9` through `3.13`.\n- The official docs are already versioned as `SymPy 1.14.0`, so the version used here and current upstream docs match.\n- The install docs still call out older code that imports `sympy.mpmath`; in current code, import `mpmath` directly.\n- `lambdify()` backend selection depends on installed numeric libraries. In one environment it may prefer SciPy or NumPy, and in another it may fall back to `math`/`cmath`/`mpmath`, so explicit `modules=` is safer for agent-generated code.\n\n## Official Links\n\n- Docs root: `https://docs.sympy.org/latest/`\n- Reference root: `https://docs.sympy.org/latest/reference/`\n- Install guide: `https://docs.sympy.org/latest/install.html`\n- Best practices: `https://docs.sympy.org/latest/explanation/best-practices.html`\n- Gotchas: `https://docs.sympy.org/latest/explanation/gotchas.html`\n- Solving guidance: `https://docs.sympy.org/latest/guides/solving/solving-guidance.html`\n- `lambdify()` reference: `https://docs.sympy.org/latest/modules/utilities/lambdify.html`\n- PyPI: `https://pypi.org/project/sympy/`\n"
  },
  {
    "path": "content/tabula-py/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tabula-py Python package for extracting tabular data from PDFs into pandas DataFrames or CSV/TSV/JSON outputs\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tabula-py,pdf,tables,pandas,java,csv,json\"\n---\n\n# tabula-py Python Package Guide\n\n## Golden Rule\n\nUse `tabula-py` only for text-based PDFs and make the Java runtime requirement explicit in setup. Import it as `import tabula`, expect `read_pdf()` to return table data derived from `tabula-java`, and treat JVM setup, `pages`, and extraction mode (`lattice` vs `stream`) as the first things to verify when results look wrong.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"tabula-py==2.10.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"tabula-py==2.10.0\"\npoetry add \"tabula-py==2.10.0\"\n```\n\nIf you want the faster `jpype` execution path and your Python version supports it:\n\n```bash\npython -m pip install \"tabula-py[jpype]==2.10.0\"\n```\n\nBefore installing or running the package, make sure `java` is available on `PATH`:\n\n```bash\njava -version\n```\n\nThe upstream docs explicitly recommend `pip` for current releases. The maintainer notes that the `conda-forge` recipe is not maintained by them.\n\n## Initialize And Basic Setup\n\n`tabula-py` has no client object and no authentication step. The main setup requirement is a working Java runtime.\n\n```python\nimport tabula\n```\n\nUseful environment-level controls:\n\n- `TABULA_JAR`: point at a custom `tabula-java` JAR if you need to override the bundled/default JAR choice\n- `PATH`: must include the Java runtime so `tabula-py` can launch `java`\n\nQuick health check when setup is failing:\n\n```python\nimport tabula\n\nprint(tabula.environment_info())\n```\n\nUse that before debugging extraction options. The upstream FAQ recommends it when `tabula-py` cannot find or launch Java correctly.\n\n## Core Usage\n\n### Extract tables from a local PDF\n\n`read_pdf()` defaults to `pages=1` and `multiple_tables=True`, so the common result is a list of DataFrames.\n\n```python\nimport tabula\n\ntables = tabula.read_pdf(\"reports/sales.pdf\", pages=1)\n\nif tables:\n    df = tables[0]\n    print(df.head())\n```\n\nIf the PDF uses all pages:\n\n```python\ntables = tabula.read_pdf(\"reports/sales.pdf\", pages=\"all\")\n```\n\n### Extract from a remote PDF URL\n\n`input_path` can be a local path, file-like object, or URL.\n\n```python\nimport tabula\n\ntables = tabula.read_pdf(\n    \"https://example.com/report.pdf\",\n    pages=\"all\",\n    user_agent=\"my-agent/1.0\",\n)\n```\n\n### Choose `lattice` or `stream`\n\nUse `lattice=True` when the PDF has visible ruling lines. Use `stream=True` when tables are aligned by whitespace instead of borders.\n\n```python\nimport tabula\n\ntables = tabula.read_pdf(\n    \"reports/statement.pdf\",\n    pages=2,\n    lattice=True,\n)\n```\n\n```python\nimport tabula\n\ntables = tabula.read_pdf(\n    \"reports/statement.pdf\",\n    pages=2,\n    stream=True,\n)\n```\n\n`guess=True` is the default. The upstream API docs note that `guess` can be combined with `lattice` or `stream`.\n\n### Restrict extraction to a known page area\n\nWhen the automatic detector picks up headers, footers, or adjacent text blocks, pass a fixed extraction area.\n\n```python\nimport tabula\n\ntables = tabula.read_pdf(\n    \"reports/sales.pdf\",\n    pages=1,\n    area=[80, 30, 560, 560],\n    multiple_tables=False,\n)\n```\n\nUse `columns=[...]` when you know vertical split positions. Use `relative_area=True` or `relative_columns=True` only when you intentionally want percentage-based coordinates instead of absolute PDF points.\n\n### Export directly to CSV, TSV, or JSON\n\nUse `convert_into()` when you want a file on disk instead of DataFrames in memory.\n\n```python\nimport tabula\n\ntabula.convert_into(\n    \"reports/sales.pdf\",\n    \"reports/sales.csv\",\n    output_format=\"csv\",\n    pages=\"all\",\n)\n```\n\nBatch conversion across a directory:\n\n```python\nimport tabula\n\ntabula.convert_into_by_batch(\n    \"incoming-pdfs\",\n    output_format=\"json\",\n    pages=\"all\",\n)\n```\n\n### Use a saved Tabula App template\n\nIf you already tuned extraction in the Tabula desktop/web app, reuse the exported template JSON instead of re-encoding the area and column settings by hand.\n\n```python\nimport tabula\n\ntables = tabula.read_pdf_with_template(\n    \"reports/sales.pdf\",\n    \"templates/sales.tabula-template.json\",\n    pages=\"all\",\n)\n```\n\nThis is the most stable route when the same PDF layout repeats regularly.\n\n## Configuration Notes\n\n- No auth: `tabula-py` does not use API keys, tokens, or service credentials.\n- JVM options: use `java_options` for heap size, file encoding, or headless mode, for example `[\"-Xmx1g\"]` or `[\"-Djava.awt.headless=true\"]`.\n- Sticky JVM startup: the FAQ notes that `java_options` are applied when the VM starts. If you need different Java options on later calls in the same Python process, use `force_subprocess=True` or run a fresh process.\n- `multiple_tables=True` is the default in modern releases. The API docs warn that this changes how `pandas_options` is applied: with `multiple_tables=True`, options go to `pandas.DataFrame`; otherwise they go to `pandas.read_csv()`.\n- Remote input: pass `user_agent=` when a remote PDF host rejects default urllib user agents.\n- Encoding: `encoding=\"utf-8\"` is the default. Windows-specific encoding problems may still require matching terminal and JVM encoding settings.\n\n## Common Pitfalls\n\n- Image-only PDFs do not work. `tabula-py` extracts text-based tables through `tabula-java`; scanned PDFs usually need OCR first.\n- `pages` defaults to the first page. Agents often forget `pages=\"all\"` and then think extraction failed.\n- Installing `tabula` instead of `tabula-py` breaks `from tabula import ...` imports because the package names conflict. The FAQ recommends uninstalling `tabula` and reinstalling `tabula-py`.\n- Empty or malformed DataFrames usually mean the wrong extraction mode, wrong area, or a PDF layout that is not actually tabular.\n- `ParserError` or `CSVParseError` often happens when multiple tables with different shapes are parsed as one table. The FAQ recommends `multiple_tables=True` for that case.\n- On macOS, Java UI focus stealing can happen. The FAQ suggests `java_options=[\"-Djava.awt.headless=true\"]`.\n- On Windows, file paths with spaces, terminal encoding, and Java `PATH` setup are common failure points.\n- If you change JVM flags after the first extraction call and nothing happens, you are likely hitting the one-time VM initialization behavior rather than a bad option value.\n\n## Version-Sensitive Notes For 2.10.0\n\n- PyPI still lists `2.10.0` as the latest published release as of March 12, 2026.\n- The maintainer release note for `v2.10.0` says this version adds Python 3.13 support and drops Python 3.8.\n- That same `v2.10.0` release note warns that the optional `jpype` path does not support Python 3.13 yet. On Python 3.13, prefer the base package install and expect subprocess-backed execution unless upstream `jpype` support has caught up.\n- The `v2.9.0` release made `jpype` optional so newer Python versions can still use `tabula-py` even when `jpype` lags behind CPython releases.\n- If older examples assume pre-2.0 behavior, re-check `multiple_tables` handling. The docs note that `read_pdf()` has defaulted to `multiple_tables=True` since `2.0.0`.\n"
  },
  {
    "path": "content/tabulate/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tabulate Python package for formatting iterables and tabular data as plain-text, Markdown, HTML, and LaTeX tables\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tabulate,tables,markdown,html,cli,formatting\"\n---\n\n# tabulate Python Package Guide\n\n## Golden Rule\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"tabulate==0.10.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"tabulate==0.10.0\"\npoetry add \"tabulate==0.10.0\"\n```\n\nIf the output includes full-width characters, install the optional wide-character support:\n\n```bash\npython -m pip install \"tabulate[widechars]==0.10.0\"\n```\n\nOn Unix-like systems and Windows, the upstream docs also describe a library-only install path that skips the CLI wrapper:\n\n```bash\nTABULATE_INSTALL=lib-only python -m pip install \"tabulate==0.10.0\"\n```\n\n## Initialize And Basic Setup\n\nThere is no client object, environment configuration, or authentication step.\n\n```python\nfrom tabulate import tabulate\n```\n\nThe main API is:\n\n```python\ntabulate(tabular_data, headers=(), tablefmt=\"simple\", **formatting_options)\n```\n\n`tabular_data` can be a list of rows, a list of dictionaries, a dictionary of iterables, a dataclass sequence, a NumPy array, or a pandas `DataFrame`.\n\n## Core Usage\n\n### Format a list of rows\n\n```python\nfrom tabulate import tabulate\n\nrows = [\n    [\"Ada\", 36, \"admin\"],\n    [\"Linus\", 55, \"maintainer\"],\n]\n\nprint(tabulate(rows, headers=[\"name\", \"age\", \"role\"], tablefmt=\"github\"))\n```\n\nUse an explicit format such as `github`, `pipe`, `grid`, `rounded_grid`, `html`, or `latex` when your downstream consumer expects a specific shape.\n\n### Format dictionaries by key\n\n```python\nfrom tabulate import tabulate\n\nrows = [\n    {\"name\": \"Ada\", \"age\": 36, \"active\": True},\n    {\"name\": \"Linus\", \"age\": 55, \"active\": False},\n]\n\nprint(tabulate(rows, headers=\"keys\", tablefmt=\"github\"))\n```\n\n`headers=\"keys\"` is the simplest path for list-of-dicts input. If you need a stable column order across varying dictionaries, normalize the keys before calling `tabulate`.\n\n### Control numeric formatting and alignment\n\nBy default, `tabulate` tries to detect and align numbers. Override that when strings should stay strings.\n\n```python\nfrom tabulate import tabulate\n\nrows = [\n    [\"00123\", 3.14159, 12000],\n    [\"00007\", 9.5, 42],\n]\n\nprint(\n    tabulate(\n        rows,\n        headers=[\"code\", \"ratio\", \"count\"],\n        tablefmt=\"github\",\n        disable_numparse=[0],\n        floatfmt=\".2f\",\n        intfmt=\",\",\n        numalign=\"right\",\n        stralign=\"left\",\n    )\n)\n```\n\nUseful options:\n\n- `disable_numparse=True` disables numeric parsing for every column\n- `disable_numparse=[0, 2]` disables parsing for specific columns\n- `floatfmt` controls float precision\n- `intfmt` adds integer separators such as `,`\n- `numalign` and `stralign` control alignment\n- `colalign` sets per-column alignment overrides\n\n### Handle missing values and long text\n\n```python\nfrom tabulate import tabulate\n\nrows = [\n    [\"ok\", \"short note\"],\n    [None, \"A much longer note that should wrap into multiple lines for narrow output.\"],\n]\n\nprint(\n    tabulate(\n        rows,\n        headers=[\"status\", \"note\"],\n        tablefmt=\"grid\",\n        missingval=\"\",\n        maxcolwidths=[None, 24],\n    )\n)\n```\n\nUse `missingval` to control how `None` renders. Use `maxcolwidths` when you need predictable wrapping instead of one very wide cell.\n\n### Use with pandas DataFrames\n\n`tabulate` accepts a pandas `DataFrame` directly:\n\n```python\nfrom tabulate import tabulate\nimport pandas as pd\n\ndf = pd.DataFrame(\n    [\n        {\"name\": \"Ada\", \"score\": 9.75},\n        {\"name\": \"Linus\", \"score\": 8.25},\n    ]\n)\n\nprint(tabulate(df, headers=\"keys\", tablefmt=\"psql\", showindex=False))\n```\n\nSet `showindex=True` or a custom iterable when the index needs to appear in the rendered table.\n\n### Command-line usage\n\nThe package installs a `tabulate` command that reads tabular input files and prints a formatted table. Example:\n\n```bash\ntabulate -1 -f github data.tsv\n```\n\nThis is useful for quick local conversions, but most agent workflows should call the Python API so formatting is explicit in code.\n\n## Configuration Notes\n\n- No auth: `tabulate` is a pure formatting library and does not use API keys, credentials, or network configuration.\n- No global initialization is required for normal usage.\n- Install `tabulate[widechars]` when tables include CJK full-width characters and column width must stay visually correct.\n- Choose `tablefmt` explicitly for generated Markdown, HTML, LaTeX, or terminal output. Relying on the default `simple` format can cause avoidable diffs across tools.\n\n## Common Pitfalls\n\n- Numeric-looking strings such as ZIP codes, IDs, or zero-padded codes may be auto-parsed and right-aligned. Use `disable_numparse` for those columns.\n- `headers=\"keys\"` follows the input structure. If your dictionaries do not all share the same keys or order, normalize them before rendering.\n- DataFrame index handling is easy to miss. Use `showindex=False` when you do not want the index column in the output.\n- Wide-character alignment is not automatic unless the optional `wcwidth` dependency is installed through the `widechars` extra.\n- `tabulate` renders tables; it does not paginate, truncate huge datasets efficiently, or stream rows incrementally. Slice or aggregate large results before formatting.\n- Plain-text table formats are for display, not round-trip parsing. If another tool needs machine-readable output, emit CSV/JSON separately and use `tabulate` only for presentation.\n\n## Version-Sensitive Notes For 0.10.0\n\n- PyPI currently lists `0.10.0` as the latest release, published on March 4, 2026.\n- The published `0.10.0` package metadata on PyPI says `Requires-Python >=3.9`.\n- The current `master` branch `pyproject.toml` in the maintainer repo already says `>=3.10`. Treat that as repo-head drift, not as the requirement for the published `0.10.0` wheel and sdist.\n- The maintainer changelog for `0.10.0` calls out new alignment controls (`headersglobalalign`, `headersalign`, `colglobalalign`) and the `colon_grid` table format.\n- The same `0.10.0` changelog entry notes dropped support for Python 3.7 and 3.8, so older runtime targets need an earlier package version.\n"
  },
  {
    "path": "content/tailwindcss/docs/tailwindcss/javascript/DOC.md",
    "content": "---\nname: tailwindcss\ndescription: \"Tailwind CSS v4 utility framework for styling JavaScript applications with official Vite or PostCSS integrations\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"tailwindcss,css,postcss,vite,javascript,npm\"\n---\n\n# tailwindcss JavaScript Guide\n\n## Golden Rule\n\nInstall `tailwindcss` together with the integration package for your build tool.\n\n- Use `@tailwindcss/vite` with Vite.\n- Use `@tailwindcss/postcss` with PostCSS.\n- Do not configure `tailwindcss` itself as a PostCSS plugin in v4.\n\nTailwind CSS is a build-time dependency. There are no API keys, accounts, authentication steps, or application runtime environment variables to configure. The only environment-sensitive behavior in the official integrations is CSS optimization: the Vite and PostCSS plugins check `NODE_ENV` to decide whether Lightning CSS optimization should run by default.\n\n## Install with Vite\n\n```bash\nnpm install tailwindcss @tailwindcss/vite\n```\n\n`vite.config.ts`:\n\n```ts\nimport { defineConfig } from 'vite';\nimport tailwindcss from '@tailwindcss/vite';\n\nexport default defineConfig({\n  plugins: [tailwindcss()],\n});\n```\n\nYour main stylesheet only needs the Tailwind import:\n\n`src/style.css`:\n\n```css\n@import \"tailwindcss\";\n```\n\nImport that stylesheet from your app entrypoint:\n\n`src/main.ts`:\n\n```ts\nimport './style.css';\n```\n\n## Install with PostCSS\n\n```bash\nnpm install tailwindcss @tailwindcss/postcss postcss\n```\n\n`postcss.config.mjs`:\n\n```js\nimport tailwindcss from '@tailwindcss/postcss';\n\nexport default {\n  plugins: [tailwindcss()],\n};\n```\n\n`src/app.css`:\n\n```css\n@import \"tailwindcss\";\n```\n\n`@tailwindcss/postcss` handles Tailwind's `@import` processing itself, so you do not need a separate `postcss-import` plugin just to load Tailwind.\n\n## Common Workflows\n\n### Change where PostCSS scans for source files\n\nThe PostCSS plugin searches from the current working directory by default. Set `base` when your frontend code lives in a subdirectory or workspace package.\n\n```js\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tailwindcss from '@tailwindcss/postcss';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport default {\n  plugins: [\n    tailwindcss({\n      base: path.resolve(__dirname, './src'),\n    }),\n  ],\n};\n```\n\n### Control CSS optimization explicitly\n\nBoth official integrations use Lightning CSS and infer production mode from `NODE_ENV`. Set `optimize` when you want deterministic behavior instead of environment-based defaults.\n\nVite example:\n\n```ts\nimport { defineConfig } from 'vite';\nimport tailwindcss from '@tailwindcss/vite';\n\nexport default defineConfig({\n  plugins: [\n    tailwindcss({\n      optimize: { minify: false },\n    }),\n  ],\n});\n```\n\nPostCSS example:\n\n```js\nimport tailwindcss from '@tailwindcss/postcss';\n\nexport default {\n  plugins: [\n    tailwindcss({\n      optimize: false,\n    }),\n  ],\n};\n```\n\n### Disable automatic `url(...)` rewriting in PostCSS\n\nLeave `transformAssetUrls` enabled unless your framework or bundler already rewrites asset URLs for imported CSS.\n\n```js\nimport tailwindcss from '@tailwindcss/postcss';\n\nexport default {\n  plugins: [\n    tailwindcss({\n      transformAssetUrls: false,\n    }),\n  ],\n};\n```\n\n### Import Tailwind helper modules from JavaScript\n\nThe `tailwindcss` package exports JavaScript helpers and CSS entrypoints in addition to the main stylesheet.\n\n```js\nimport colors from 'tailwindcss/colors';\nimport defaultTheme from 'tailwindcss/defaultTheme';\nimport plugin from 'tailwindcss/plugin';\n\nconsole.log(colors.sky[500]);\nconsole.log(defaultTheme.fontFamily.sans);\nconsole.log(typeof plugin);\n```\n\nIf you need the distributed CSS entrypoints separately, the package also exports `tailwindcss/theme`, `tailwindcss/preflight`, and `tailwindcss/utilities`.\n\n## Important Pitfalls\n\n- `tailwindcss` is not the PostCSS plugin in v4. If you add it directly to `postcss.config.*`, Tailwind throws an error telling you to install `@tailwindcss/postcss` instead.\n- Vite and PostCSS integration packages decide whether to optimize CSS by checking `NODE_ENV`. Set `optimize` yourself if you need stable behavior across local builds, CI, and preview environments.\n- `@tailwindcss/postcss` rewrites `url(...)` references by default because it also handles `@import`. Disable `transformAssetUrls` only when your framework already owns that step.\n- When your app source is not rooted at the current working directory, set the PostCSS plugin's `base` option or Tailwind can scan the wrong place.\n- Prefer current v4 setup docs over older Tailwind examples that show `tailwindcss` directly in PostCSS configuration.\n"
  },
  {
    "path": "content/taskiq/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Taskiq Python package guide for async background jobs, workers, scheduling, and testing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"taskiq,python,async,background-jobs,workers,scheduler,queues\"\n---\n\n# Taskiq Python Package Guide\n\n## Golden Rule\n\n`taskiq` is the core task framework, not a complete production queue stack by itself. Use `taskiq` for task definitions, workers, scheduling, dependency injection, and testing, then pair it with an actual broker package and usually a result backend package for real deployments. `InMemoryBroker` is for local development and tests, not for multi-process or multi-host production work.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"taskiq==0.12.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"taskiq==0.12.1\"\npoetry add \"taskiq==0.12.1\"\n```\n\nUseful extras from the maintainer docs and PyPI metadata:\n\n```bash\npython -m pip install \"taskiq[reload]==0.12.1\"\npython -m pip install \"taskiq[zmq]==0.12.1\"\npython -m pip install \"taskiq[opentelemetry]==0.12.1\"\n```\n\nProduction deployments usually also need integration packages, for example:\n\n```bash\npython -m pip install \"taskiq-aio-pika\" \"taskiq-redis\"\n```\n\nThat combination gives you a RabbitMQ broker plus a Redis result backend. The exact transport and backend packages depend on the infrastructure your app already uses.\n\n## Core Model\n\nTaskiq has a few concepts agents need to keep straight:\n\n- `broker`: where tasks are published and where workers consume them from\n- `result backend`: where task return values and errors are stored if you need them later\n- `worker`: long-running process that executes tasks\n- `scheduler`: separate process that enqueues due tasks; it does not execute them\n- `TaskiqDepends`: lightweight dependency injection for task arguments\n- labels: task metadata used for schedules, timeouts, retries, and routing-related behavior\n\nIf you only install `taskiq`, you still need to choose how tasks move between processes. The in-memory broker works only inside the current process.\n\n## Initialize A Broker\n\n### Minimal local setup\n\nThis is the fastest way to define and run a task in one process:\n\n```python\nimport asyncio\n\nfrom taskiq import InMemoryBroker\n\nbroker = InMemoryBroker()\n\n@broker.task\nasync def add(a: int, b: int) -> int:\n    return a + b\n\nasync def main() -> None:\n    await broker.startup()\n    try:\n        task = await add.kiq(2, 3)\n        result = await task.wait_result(timeout=5)\n        print(result.return_value)\n    finally:\n        await broker.shutdown()\n\nasyncio.run(main())\n```\n\nUse this for tests, local experiments, and examples. Do not treat it as a distributed queue.\n\n### Typical production shape\n\nTaskiq’s official docs expect you to expose a broker object from an importable module and point the worker CLI at it:\n\n```python\n# worker.py\nfrom taskiq_aio_pika import AioPikaBroker\nfrom taskiq_redis import RedisAsyncResultBackend\n\nbroker = AioPikaBroker(\"amqp://guest:guest@localhost:5672/\")\nbroker = broker.with_result_backend(\n    RedisAsyncResultBackend(\"redis://localhost:6379/0\"),\n)\n\n@broker.task\nasync def add(a: int, b: int) -> int:\n    return a + b\n```\n\nRun the worker:\n\n```bash\ntaskiq worker worker:broker\n```\n\nIf your project uses filesystem discovery instead of importing every module directly:\n\n```bash\ntaskiq worker worker:broker --fs-discover\n```\n\n## Sending And Awaiting Tasks\n\n### Enqueue a task\n\n```python\ntask = await add.kiq(40, 2)\n```\n\n`kiq()` sends the task to the configured broker and returns an async task handle.\n\n### Read the result\n\n```python\nresult = await task.wait_result(timeout=10)\n\nif result.is_err:\n    raise result.error\n\nprint(result.return_value)\n```\n\nResult retrieval only works when the broker is configured with a real result backend. Without one, Taskiq uses a dummy backend and you should not expect persisted return values.\n\n### Add labels\n\nLabels attach metadata that middlewares and schedulers can use:\n\n```python\ntask = await add.kicker().with_labels(timeout=30).kiq(1, 2)\n```\n\nUse labels when the integration you picked documents behavior tied to them. Task schedules also come from task labels.\n\n## Dependencies And Context\n\nTaskiq has its own DI mechanism. Use `TaskiqDepends`, not FastAPI’s `Depends`.\n\n```python\nfrom taskiq import Context, TaskiqDepends\n\ndef get_prefix() -> str:\n    return \"processed\"\n\n@broker.task\nasync def format_name(\n    name: str,\n    prefix: str = TaskiqDepends(get_prefix),\n    context: Context = TaskiqDepends(),\n) -> str:\n    return f\"{prefix}:{name}:{context.message.task_id}\"\n```\n\nImportant behavior from the official docs:\n\n- The dependency graph is prepared during broker startup, so startup hooks matter.\n- Event handlers can add objects into broker state for later injection.\n- Framework integrations such as `taskiq-fastapi` bridge request-app state into tasks, but Taskiq’s dependency wrapper is still the task-side API.\n\n## Scheduling\n\nRun the scheduler as a separate process:\n\n```python\nfrom taskiq import TaskiqScheduler\nfrom taskiq.schedule_sources import LabelScheduleSource\n\nscheduler = TaskiqScheduler(broker, [LabelScheduleSource(broker)])\n```\n\nThen start it:\n\n```bash\ntaskiq scheduler worker:scheduler\n```\n\nUse label-based schedules for simple cron or interval jobs declared on tasks. Keep these constraints in mind:\n\n- You still need workers running; the scheduler only publishes tasks.\n- Run only one scheduler instance unless your chosen schedule source explicitly supports coordination.\n- Taskiq defaults scheduler time handling to UTC in the official docs.\n- If you persist schedules outside task labels, use the appropriate schedule-source package and its storage settings.\n\n## Testing\n\nThe maintainer docs strongly recommend `InMemoryBroker` for tests.\n\n```python\nimport pytest\n\nfrom taskiq import InMemoryBroker\n\nbroker = InMemoryBroker()\n\n@broker.task\nasync def add(a: int, b: int) -> int:\n    return a + b\n\n@pytest.mark.anyio\nasync def test_add() -> None:\n    await broker.startup()\n    try:\n        task = await add.kiq(2, 5)\n        result = await task.wait_result(timeout=5)\n        assert result.return_value == 7\n    finally:\n        await broker.shutdown()\n```\n\nUseful testing patterns from the official testing guide:\n\n- use `InMemoryBroker(await_inplace=True)` when you want tasks to execute immediately in-process\n- use `broker.wait_all()` when you need to wait until queued tasks finish\n- populate dependency context explicitly in tests when the code depends on injected state\n\n## Configuration And Auth\n\n`taskiq` itself does not define one universal auth scheme. Connection details and credentials live in the broker and result-backend integrations you choose.\n\nCommon configuration points:\n\n- AMQP / Redis / NATS / Kafka DSNs or connection kwargs belong to the transport package, not Taskiq core\n- result backend URLs and serialization settings belong to the backend package\n- hot reload support requires the `reload` extra\n- ZeroMQ support requires the `zmq` extra\n- OpenTelemetry integration requires the `opentelemetry` extra and compatible middleware/instrumentation setup\n\nA practical environment-variable pattern looks like this:\n\n```python\nimport os\n\nfrom taskiq_aio_pika import AioPikaBroker\nfrom taskiq_redis import RedisAsyncResultBackend\n\nbroker = AioPikaBroker(os.environ[\"TASKIQ_BROKER_URL\"])\nbroker = broker.with_result_backend(\n    RedisAsyncResultBackend(os.environ[\"TASKIQ_RESULT_BACKEND_URL\"]),\n)\n```\n\n## Common Pitfalls\n\n- Forgetting `await broker.startup()` before publishing or testing tasks. Dependency graphs and broker internals are initialized there.\n- Expecting task return values without configuring a real result backend.\n- Running only `taskiq scheduler ...` and forgetting that a separate worker process must actually execute the task.\n- Running more than one scheduler instance and accidentally publishing duplicate scheduled jobs.\n- Using `InMemoryBroker` for production or cross-process communication.\n- Using framework-specific dependency helpers inside tasks. Taskiq tasks should use `TaskiqDepends`.\n- Assuming sync task time limits can always kill underlying work immediately. Enforced timeout behavior depends on how the worker executes the callable.\n- If you use the built-in ZeroMQ broker, keep the worker count at `1`; the maintainer docs call out duplicate execution problems with higher counts.\n\n## Version-Sensitive Notes For 0.12.x\n\n- `0.12.0` dropped Python 3.9 support. If a project still targets 3.9, this package line is not a fit.\n- `0.12.0` added interval-based scheduling and OpenTelemetry support, so examples written for `0.11.x` may miss features now available in `0.12.x`.\n- `0.12.1` adds Python 3.14 support and includes fixes around sync decorators and ZeroMQ behavior. If you use sync tasks or the built-in ZMQ broker, prefer `0.12.1` over earlier `0.12.0` examples.\n\n## Official Sources Used\n\n- Documentation root: `https://taskiq-python.github.io/`\n- Getting started: `https://taskiq-python.github.io/guide/getting-started.html`\n- State and dependencies: `https://taskiq-python.github.io/guide/state-and-deps.html`\n- Scheduling tasks: `https://taskiq-python.github.io/guide/scheduling-tasks.html`\n- Testing guide: `https://taskiq-python.github.io/guide/testing-taskiq.html`\n- Available brokers: `https://taskiq-python.github.io/available-components/brokers.html`\n- PyPI package page: `https://pypi.org/project/taskiq/`\n- GitHub releases: `https://github.com/taskiq-python/taskiq/releases`\n"
  },
  {
    "path": "content/tavily/docs/sdk/javascript/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Web search API for AI agents with search, extract, crawl, map, and research endpoints\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.7.2\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"tavily,search,extract,crawl,research,ai,agents,rag,web-search,web-scraping\"\n---\n# Tavily JavaScript SDK\n\nWeb search API built for AI agents and RAG pipelines. Provides search, extract, crawl, map, and research through a single SDK. The client is async by default.\n\n**Package:** `@tavily/core` on npm\n**Repo:** github.com/tavily-ai/tavily-js\n\n## Installation\n\n```bash\nnpm install @tavily/core\n```\n\n## Initialization\n\nSet `TAVILY_API_KEY` in your environment, or pass it directly.\n\n```javascript\nconst { tavily } = require(\"@tavily/core\");\n\nconst client = tavily({ apiKey: \"tvly-YOUR_API_KEY\" });\n```\n\nOr with ES modules:\n\n```javascript\nimport { tavily } from \"@tavily/core\";\n\nconst client = tavily({ apiKey: \"tvly-YOUR_API_KEY\" });\n```\n\n### Project Tracking\n\nAttach a project ID to organize usage:\n\n```javascript\nconst client = tavily({\n  apiKey: \"tvly-YOUR_API_KEY\",\n  projectId: \"my-project\"\n});\n```\n\nOr set `TAVILY_PROJECT` environment variable.\n\n## Search\n\nThe core endpoint. Returns ranked web results with content snippets.\n\n```javascript\nconst response = await client.search(\"latest developments in quantum computing\");\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `query` **(required)** | `string` | — | Search query (keep under 400 chars) |\n| `searchDepth` | `string` | `\"basic\"` | `\"ultra-fast\"`, `\"fast\"`, `\"basic\"`, or `\"advanced\"` |\n| `topic` | `string` | `\"general\"` | `\"general\"`, `\"news\"`, or `\"finance\"` |\n| `maxResults` | `number` | `5` | Number of results (0–20) |\n| `chunksPerSource` | `number` | `3` | Chunks per result (1–3, only with `\"fast\"` or `\"advanced\"` depth) |\n| `includeAnswer` | `boolean`/`string` | `false` | `true`/`\"basic\"` for quick answer, `\"advanced\"` for detailed |\n| `includeRawContent` | `boolean`/`string` | `false` | `true`/`\"markdown\"` for markdown, `\"text\"` for plain text |\n| `includeImages` | `boolean` | `false` | Include query-related images |\n| `includeImageDescriptions` | `boolean` | `false` | AI-generated descriptions for images |\n| `includeFavicon` | `boolean` | `false` | Favicon URL per result |\n| `includeDomains` | `string[]` | `[]` | Restrict to specific domains (max 300, supports wildcards like `*.com`) |\n| `excludeDomains` | `string[]` | `[]` | Exclude specific domains (max 150) |\n| `timeRange` | `string` | — | `\"day\"`, `\"week\"`, `\"month\"`, `\"year\"` |\n| `startDate` | `string` | — | Filter from date (`YYYY-MM-DD`) |\n| `endDate` | `string` | — | Filter until date (`YYYY-MM-DD`) |\n| `country` | `string` | — | Boost results from a country (general topic only) |\n| `autoParameters` | `boolean` | `false` | Auto-configure params based on query intent (may upgrade depth) |\n| `exactMatch` | `boolean` | `false` | Require exact quoted phrases in results |\n| `includeUsage` | `boolean` | `false` | Include credit usage info in response |\n\n**Search depth tradeoffs:**\n\n| Depth | Latency | Content Type | Credits |\n|-------|---------|--------------|---------|\n| `ultra-fast` | Lowest | NLP content summary | 1 |\n| `fast` | Low | Reranked chunks | 1 |\n| `basic` | Medium | NLP content summary | 1 |\n| `advanced` | Higher | Reranked chunks | 2 |\n\n### Response\n\n```javascript\n{\n  query: \"latest developments in quantum computing\",\n  results: [\n    {\n      title: \"...\",\n      url: \"https://...\",\n      content: \"Most relevant snippet...\",\n      score: 0.99,\n      rawContent: \"...\",          // if includeRawContent\n      publishedDate: \"...\",       // if topic=\"news\"\n      favicon: \"...\",             // if includeFavicon\n    }\n  ],\n  answer: \"...\",          // if includeAnswer\n  images: [...],          // if includeImages\n  responseTime: 1.09,\n  requestId: \"...\",\n  usage: { credits: 1 }  // if includeUsage\n}\n```\n\n### Advanced Search Example\n\n```javascript\nconst response = await client.search(\"How many countries use Daylight Saving Time?\", {\n  searchDepth: \"advanced\",\n  maxResults: 10,\n  includeAnswer: \"advanced\",\n  includeRawContent: true,\n  chunksPerSource: 3\n});\n\nconsole.log(response.answer);\nfor (const result of response.results) {\n  console.log(`${result.title} (${result.score.toFixed(2)})`);\n  console.log(`  ${result.url}`);\n}\n```\n\n### Domain Filtering\n\n```javascript\n// Restrict to specific sources\nconst response = await client.search(\"CEO background at Google\", {\n  includeDomains: [\"linkedin.com/in\"]\n});\n\n// Exclude irrelevant domains\nconst response2 = await client.search(\"US economy trends\", {\n  excludeDomains: [\"espn.com\", \"vogue.com\"]\n});\n```\n\n### News Search\n\n```javascript\nconst response = await client.search(\"AI regulation updates\", {\n  topic: \"news\",\n  timeRange: \"week\",\n  maxResults: 10\n});\n\nfor (const result of response.results) {\n  console.log(`${result.title} - ${result.publishedDate || \"N/A\"}`);\n}\n```\n\n## Extract\n\nExtract content from specific URLs. Returns cleaned markdown or plain text.\n\n```javascript\nconst response = await client.extract([\"https://en.wikipedia.org/wiki/Quantum_computing\"]);\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `urls` **(required)** | `string[]` | — | URLs to extract (max 20) |\n| `extractDepth` | `string` | `\"basic\"` | `\"basic\"` or `\"advanced\"` (JS-heavy pages, tables) |\n| `format` | `string` | `\"markdown\"` | `\"markdown\"` or `\"text\"` |\n| `query` | `string` | — | Rerank chunks by relevance to this query |\n| `chunksPerSource` | `number` | `3` | Chunks per URL (1–5, requires `query`) |\n| `includeImages` | `boolean` | `false` | Include extracted image URLs |\n| `includeFavicon` | `boolean` | `false` | Favicon URL per result |\n| `timeout` | `number` | — | Timeout in seconds (1.0–60.0) |\n| `includeUsage` | `boolean` | `false` | Include credit usage info in response |\n\n### Example with Query Filtering\n\n```javascript\nconst response = await client.extract(\n  [\"https://en.wikipedia.org/wiki/FA_Cup\", \"https://en.wikipedia.org/wiki/UEFA_Champions_League\"],\n  {\n    query: \"past champions\",\n    chunksPerSource: 2,\n    extractDepth: \"advanced\"\n  }\n);\n\nfor (const result of response.results) {\n  console.log(`URL: ${result.url}`);\n  console.log(`Content: ${result.rawContent.slice(0, 200)}...`);\n}\n\nfor (const failed of response.failedResults) {\n  console.log(`Failed: ${failed.url} - ${failed.error}`);\n}\n```\n\n## Crawl\n\nIntelligently traverse a website and extract content from discovered pages.\n\n```javascript\nconst response = await client.crawl(\"https://docs.tavily.com\", {\n  instructions: \"Find all pages about the JavaScript SDK\"\n});\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` **(required)** | `string` | — | Starting URL |\n| `maxDepth` | `number` | `1` | Levels deep to crawl (1–5, each level increases time exponentially) |\n| `maxBreadth` | `number` | `20` | Max links to follow per page (1–500) |\n| `limit` | `number` | `50` | Total max pages to crawl |\n| `instructions` | `string` | — | Natural language guidance to focus the crawl |\n| `chunksPerSource` | `number` | `3` | Chunks per page (1–5, requires `instructions`) |\n| `selectPaths` | `string[]` | — | Regex patterns for paths to include |\n| `excludePaths` | `string[]` | — | Regex patterns for paths to exclude |\n| `selectDomains` | `string[]` | — | Regex patterns for domains to include |\n| `excludeDomains` | `string[]` | — | Regex patterns for domains to exclude |\n| `allowExternal` | `boolean` | `true` | Include links to external domains |\n| `extractDepth` | `string` | `\"basic\"` | `\"basic\"` or `\"advanced\"` |\n| `format` | `string` | `\"markdown\"` | `\"markdown\"` or `\"text\"` |\n| `includeImages` | `boolean` | `false` | Include extracted image URLs |\n| `includeFavicon` | `boolean` | `false` | Favicon URL per result |\n| `timeout` | `number` | `150` | Max wait time in seconds (10–150) |\n| `includeUsage` | `boolean` | `false` | Include credit usage info in response |\n\n### Focused Crawl Example\n\n```javascript\nconst response = await client.crawl(\"https://docs.tavily.com\", {\n  maxDepth: 2,\n  limit: 100,\n  instructions: \"Find all pages about the JavaScript SDK\",\n  selectPaths: [\"/docs/.*\", \"/api/.*\"],\n  excludePaths: [\"/private/.*\", \"/admin/.*\"],\n  extractDepth: \"advanced\"\n});\n\nfor (const page of response.results) {\n  console.log(`${page.url}: ${page.rawContent.length} chars`);\n}\n```\n\n## Map\n\nDiscover site structure without extracting content. Returns a list of URLs.\n\n```javascript\nconst response = await client.map(\"https://docs.tavily.com\", {\n  instructions: \"Find all pages on the JavaScript SDK\"\n});\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` **(required)** | `string` | — | Starting URL |\n| `maxDepth` | `number` | `1` | Levels deep to map (1–5) |\n| `maxBreadth` | `number` | `20` | Max links per page (1–500) |\n| `limit` | `number` | `50` | Total max URLs |\n| `instructions` | `string` | — | Focus the mapping with natural language |\n| `selectPaths` | `string[]` | — | Regex path patterns to include |\n| `excludePaths` | `string[]` | — | Regex path patterns to exclude |\n| `selectDomains` | `string[]` | — | Regex patterns for domains to include |\n| `excludeDomains` | `string[]` | — | Regex patterns for domains to exclude |\n| `allowExternal` | `boolean` | `true` | Include links to external domains |\n| `timeout` | `number` | `150` | Max wait time in seconds (10–150) |\n| `includeUsage` | `boolean` | `false` | Include credit usage info in response |\n\n### Response\n\n```javascript\n{\n  baseUrl: \"https://docs.tavily.com\",\n  results: [\n    \"https://docs.tavily.com/sdk/javascript/reference\",\n    \"https://docs.tavily.com/sdk/javascript/quick-start\"\n  ],\n  responseTime: 8.43,\n  requestId: \"...\"\n}\n```\n\n**Tip:** Use Map first to discover structure, then Crawl with discovered paths for focused extraction.\n\n## Research\n\nEnd-to-end AI-powered research with automatic source gathering and synthesis. Research tasks are asynchronous — start with `research()`, poll with `getResearch()`.\n\n```javascript\nconst result = await client.research({\n  input: \"Analyze competitive landscape for AI search APIs in 2026\",\n  model: \"pro\"\n});\n\nconst requestId = result.requestId;\n\nlet response = await client.getResearch(requestId);\nwhile (![\"completed\", \"failed\"].includes(response.status)) {\n  await new Promise(r => setTimeout(r, 10000));\n  response = await client.getResearch(requestId);\n}\n\nconsole.log(response.content);\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `input` **(required)** | `string` | — | The research topic or question |\n| `model` | `string` | `\"auto\"` | `\"mini\"` (focused), `\"pro\"` (comprehensive), or `\"auto\"` |\n| `stream` | `boolean` | `false` | Enable streaming responses (SSE) |\n| `outputSchema` | `object` | — | JSON Schema for structured output |\n| `citationFormat` | `string` | `\"numbered\"` | `\"numbered\"`, `\"mla\"`, `\"apa\"`, or `\"chicago\"` |\n\n**Credits:** 4–110 per request (mini), 15–250 per request (pro).\n\n## Search Then Extract Pattern\n\nA common RAG pattern: search to find URLs, then extract full content from the best ones.\n\n```javascript\nasync function searchThenExtract(topic) {\n  // 1. Search for relevant URLs\n  const searchResponse = await client.search(topic, {\n    searchDepth: \"advanced\",\n    maxResults: 10\n  });\n\n  // 2. Filter by relevance score\n  const urls = searchResponse.results\n    .filter(r => r.score > 0.5)\n    .map(r => r.url)\n    .slice(0, 20);\n\n  // 3. Extract full content\n  const extractResponse = await client.extract(urls, {\n    query: topic,\n    chunksPerSource: 3,\n    extractDepth: \"advanced\"\n  });\n\n  return extractResponse.results;\n}\n\nconst results = await searchThenExtract(\"AI in healthcare diagnostics\");\n```\n\n## Parallel Searches\n\nRun multiple independent searches concurrently:\n\n```javascript\nconst queries = [\"latest AI trends\", \"quantum computing breakthroughs\"];\n\nconst responses = await Promise.allSettled(\n  queries.map(q => client.search(q))\n);\n\nfor (const response of responses) {\n  if (response.status === \"fulfilled\") {\n    console.log(`Results: ${response.value.results.length}`);\n  } else {\n    console.log(`Failed: ${response.reason}`);\n  }\n}\n```\n\n## Error Handling\n\n```javascript\ntry {\n  const response = await client.search(\"test query\");\n} catch (error) {\n  if (error.message.includes(\"API key\")) {\n    console.log(\"Invalid or missing API key\");\n  } else if (error.message.includes(\"rate limit\")) {\n    console.log(\"Rate limit exceeded, retry later\");\n  } else {\n    console.log(`Error: ${error.message}`);\n  }\n}\n```\n"
  },
  {
    "path": "content/tavily/docs/sdk/python/DOC.md",
    "content": "---\nname: sdk\ndescription: \"Web search API for AI agents with search, extract, crawl, map, and research endpoints\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.7.23\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"tavily,search,extract,crawl,research,ai,agents,rag,web-search,web-scraping\"\n---\n# Tavily Python SDK\n\nWeb search API built for AI agents and RAG pipelines. Provides search, extract, crawl, map, and research through a single SDK.\n\n**Package:** `tavily-python` on PyPI\n**Repo:** github.com/tavily-ai/tavily-python\n\n## Installation\n\n```bash\npip install tavily-python\n```\n\nIf using `uv`, you can add the package to your project with:\n```bash\nuv add tavily-python\n```\n\n## Initialization\n\nSet `TAVILY_API_KEY` in your environment, or pass it directly.\n\n### Synchronous Client\n\n```python\nfrom tavily import TavilyClient\n\nclient = TavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n```\n\n### Asynchronous Client\n\n```python\nfrom tavily import AsyncTavilyClient\n\nclient = AsyncTavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n```\n\n### Project Tracking\n\nAttach a project ID to organize usage across projects:\n\n```python\nclient = TavilyClient(api_key=\"tvly-YOUR_API_KEY\", project_id=\"my-project\")\n```\n\nOr set `TAVILY_PROJECT` environment variable.\n\n## Search\n\nThe core endpoint. Returns ranked web results with content snippets.\n\n```python\nresponse = client.search(\"latest developments in quantum computing\")\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `query` **(required)** | `str` | — | Search query (keep under 400 chars) |\n| `search_depth` | `str` | `\"basic\"` | `\"ultra-fast\"`, `\"fast\"`, `\"basic\"`, or `\"advanced\"` |\n| `topic` | `str` | `\"general\"` | `\"general\"`, `\"news\"`, or `\"finance\"` |\n| `max_results` | `int` | `5` | Number of results (0–20) |\n| `chunks_per_source` | `int` | `3` | Chunks per result (1–3, only with `\"fast\"` or `\"advanced\"` depth) |\n| `include_answer` | `bool`/`str` | `False` | `True`/`\"basic\"` for quick answer, `\"advanced\"` for detailed |\n| `include_raw_content` | `bool`/`str` | `False` | `True`/`\"markdown\"` for markdown, `\"text\"` for plain text |\n| `include_images` | `bool` | `False` | Include query-related images |\n| `include_image_descriptions` | `bool` | `False` | AI-generated descriptions for images |\n| `include_favicon` | `bool` | `False` | Favicon URL per result |\n| `include_domains` | `list[str]` | `[]` | Restrict to specific domains (max 300, supports wildcards like `*.com`) |\n| `exclude_domains` | `list[str]` | `[]` | Exclude specific domains (max 150) |\n| `time_range` | `str` | — | `\"day\"`, `\"week\"`, `\"month\"`, `\"year\"` |\n| `start_date` | `str` | — | Filter from date (`YYYY-MM-DD`) |\n| `end_date` | `str` | — | Filter until date (`YYYY-MM-DD`) |\n| `country` | `str` | — | Boost results from a country (general topic only) |\n| `auto_parameters` | `bool` | `False` | Auto-configure params based on query intent (may upgrade depth) |\n| `exact_match` | `bool` | `False` | Require exact quoted phrases in results |\n| `include_usage` | `bool` | `False` | Include credit usage info in response |\n\n**Search depth tradeoffs:**\n\n| Depth | Latency | Content Type | Credits |\n|-------|---------|--------------|---------|\n| `ultra-fast` | Lowest | NLP content summary | 1 |\n| `fast` | Low | Reranked chunks | 1 |\n| `basic` | Medium | NLP content summary | 1 |\n| `advanced` | Higher | Reranked chunks | 2 |\n\n### Response\n\n```python\n{\n    \"query\": \"latest developments in quantum computing\",\n    \"results\": [\n        {\n            \"title\": \"...\",\n            \"url\": \"https://...\",\n            \"content\": \"Most relevant snippet...\",\n            \"score\": 0.99,\n            \"raw_content\": \"...\",         # if include_raw_content\n            \"published_date\": \"...\",       # if topic=\"news\"\n            \"favicon\": \"...\",             # if include_favicon\n        }\n    ],\n    \"answer\": \"...\",          # if include_answer\n    \"images\": [...],          # if include_images\n    \"response_time\": 1.09,\n    \"request_id\": \"...\",\n    \"usage\": {\"credits\": 1}  # if include_usage\n}\n```\n\n### Advanced Search Example\n\n```python\nresponse = client.search(\n    query=\"How many countries use Daylight Saving Time?\",\n    search_depth=\"advanced\",\n    max_results=10,\n    include_answer=\"advanced\",\n    include_raw_content=True,\n    chunks_per_source=3\n)\n\nprint(response[\"answer\"])\nfor result in response[\"results\"]:\n    print(f\"{result['title']} ({result['score']:.2f})\")\n    print(f\"  {result['url']}\")\n```\n\n### Domain Filtering\n\n```python\n# Restrict to specific sources\nresponse = client.search(\n    query=\"CEO background at Google\",\n    include_domains=[\"linkedin.com/in\"]\n)\n\n# Exclude irrelevant domains\nresponse = client.search(\n    query=\"US economy trends\",\n    exclude_domains=[\"espn.com\", \"vogue.com\"]\n)\n```\n\n### News Search\n\n```python\nresponse = client.search(\n    query=\"AI regulation updates\",\n    topic=\"news\",\n    time_range=\"week\",\n    max_results=10\n)\n\nfor result in response[\"results\"]:\n    print(f\"{result['title']} - {result.get('published_date', 'N/A')}\")\n```\n\n## Extract\n\nExtract content from specific URLs. Returns cleaned markdown or plain text.\n\n```python\nresponse = client.extract(urls=[\"https://en.wikipedia.org/wiki/Quantum_computing\"])\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `urls` **(required)** | `list[str]` | — | URLs to extract (max 20) |\n| `extract_depth` | `str` | `\"basic\"` | `\"basic\"` or `\"advanced\"` (JS-heavy pages, tables) |\n| `format` | `str` | `\"markdown\"` | `\"markdown\"` or `\"text\"` |\n| `query` | `str` | — | Rerank chunks by relevance to this query |\n| `chunks_per_source` | `int` | `3` | Chunks per URL (1–5, requires `query`) |\n| `include_images` | `bool` | `False` | Include extracted image URLs |\n| `include_favicon` | `bool` | `False` | Favicon URL per result |\n| `timeout` | `float` | — | Timeout in seconds (1.0–60.0) |\n| `include_usage` | `bool` | `False` | Include credit usage info in response |\n\n### Example with Query Filtering\n\n```python\nresponse = client.extract(\n    urls=[\n        \"https://en.wikipedia.org/wiki/FA_Cup\",\n        \"https://en.wikipedia.org/wiki/UEFA_Champions_League\"\n    ],\n    query=\"past champions\",\n    chunks_per_source=2,\n    extract_depth=\"advanced\"\n)\n\nfor result in response[\"results\"]:\n    print(f\"URL: {result['url']}\")\n    print(f\"Content: {result['raw_content'][:200]}...\")\n\nfor failed in response[\"failed_results\"]:\n    print(f\"Failed: {failed['url']} - {failed['error']}\")\n```\n\n## Crawl\n\nIntelligently traverse a website and extract content from discovered pages.\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.tavily.com\",\n    instructions=\"Find all pages about the Python SDK\"\n)\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` **(required)** | `str` | — | Starting URL |\n| `max_depth` | `int` | `1` | Levels deep to crawl (1–5, each level increases time exponentially) |\n| `max_breadth` | `int` | `20` | Max links to follow per page (1–500) |\n| `limit` | `int` | `50` | Total max pages to crawl |\n| `instructions` | `str` | — | Natural language guidance to focus the crawl |\n| `chunks_per_source` | `int` | `3` | Chunks per page (1–5, requires `instructions`) |\n| `select_paths` | `list[str]` | — | Regex patterns for paths to include |\n| `exclude_paths` | `list[str]` | — | Regex patterns for paths to exclude |\n| `select_domains` | `list[str]` | — | Regex patterns for domains to include |\n| `exclude_domains` | `list[str]` | — | Regex patterns for domains to exclude |\n| `allow_external` | `bool` | `True` | Include links to external domains |\n| `extract_depth` | `str` | `\"basic\"` | `\"basic\"` or `\"advanced\"` |\n| `format` | `str` | `\"markdown\"` | `\"markdown\"` or `\"text\"` |\n| `include_images` | `bool` | `False` | Include extracted image URLs |\n| `include_favicon` | `bool` | `False` | Favicon URL per result |\n| `timeout` | `float` | `150` | Max wait time in seconds (10–150) |\n| `include_usage` | `bool` | `False` | Include credit usage info in response |\n\n### Focused Crawl Example\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.tavily.com\",\n    max_depth=2,\n    limit=100,\n    instructions=\"Find all pages about the Python SDK\",\n    select_paths=[\"/docs/.*\", \"/api/.*\"],\n    extract_depth=\"advanced\"\n)\n\nfor page in response[\"results\"]:\n    print(f\"{page['url']}: {len(page['raw_content'])} chars\")\n```\n\n## Map\n\nDiscover site structure without extracting content. Returns a list of URLs.\n\n```python\nresponse = client.map(\n    url=\"https://docs.tavily.com\",\n    instructions=\"Find all pages on the Python SDK\"\n)\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` **(required)** | `str` | — | Starting URL |\n| `max_depth` | `int` | `1` | Levels deep to map (1–5) |\n| `max_breadth` | `int` | `20` | Max links per page (1–500) |\n| `limit` | `int` | `50` | Total max URLs |\n| `instructions` | `str` | — | Focus the mapping with natural language |\n| `select_paths` | `list[str]` | — | Regex path patterns to include |\n| `exclude_paths` | `list[str]` | — | Regex path patterns to exclude |\n| `select_domains` | `list[str]` | — | Regex patterns for domains to include |\n| `exclude_domains` | `list[str]` | — | Regex patterns for domains to exclude |\n| `allow_external` | `bool` | `True` | Include links to external domains |\n| `timeout` | `float` | `150` | Max wait time in seconds (10–150) |\n| `include_usage` | `bool` | `False` | Include credit usage info in response |\n\n### Response\n\n```python\n{\n    \"base_url\": \"https://docs.tavily.com\",\n    \"results\": [\n        \"https://docs.tavily.com/sdk/python/reference\",\n        \"https://docs.tavily.com/sdk/python/quick-start\"\n    ],\n    \"response_time\": 8.43,\n    \"request_id\": \"...\"\n}\n```\n\n**Tip:** Use Map first to discover structure, then Crawl with discovered paths for focused extraction.\n\n## Research\n\nEnd-to-end AI-powered research with automatic source gathering and synthesis. Research tasks are asynchronous — start with `research()`, poll with `get_research()`.\n\n```python\nimport time\n\nresult = client.research(\n    input=\"Analyze competitive landscape for AI search APIs in 2026\",\n    model=\"pro\"\n)\nrequest_id = result[\"request_id\"]\n\nresponse = client.get_research(request_id)\nwhile response[\"status\"] not in [\"completed\", \"failed\"]:\n    time.sleep(10)\n    response = client.get_research(request_id)\n\nprint(response[\"content\"])\n```\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `input` **(required)** | `str` | — | The research topic or question |\n| `model` | `str` | `\"auto\"` | `\"mini\"` (focused), `\"pro\"` (comprehensive), or `\"auto\"` |\n| `stream` | `bool` | `False` | Enable streaming responses (SSE) |\n| `output_schema` | `dict` | — | JSON Schema for structured output |\n| `citation_format` | `str` | `\"numbered\"` | `\"numbered\"`, `\"mla\"`, `\"apa\"`, or `\"chicago\"` |\n\n### Streaming\n\n```python\nstream = client.research(\n    input=\"Latest developments in quantum computing\",\n    model=\"pro\",\n    stream=True\n)\n\nfor chunk in stream:\n    print(chunk.decode('utf-8'))\n```\n\n**Credits:** 4–110 per request (mini), 15–250 per request (pro).\n\n## Async Usage\n\nUse `AsyncTavilyClient` for concurrent requests:\n\n```python\nimport asyncio\nfrom tavily import AsyncTavilyClient\n\nclient = AsyncTavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n\nasync def parallel_search():\n    queries = [\"latest AI trends\", \"quantum computing breakthroughs\"]\n    responses = await asyncio.gather(\n        *(client.search(q) for q in queries),\n        return_exceptions=True\n    )\n    for response in responses:\n        if isinstance(response, Exception):\n            print(f\"Failed: {response}\")\n        else:\n            print(f\"Results: {len(response['results'])}\")\n\nasyncio.run(parallel_search())\n```\n\n## Search Then Extract Pattern\n\nA common RAG pattern: search to find URLs, then extract full content from the best ones.\n\n```python\nimport asyncio\nfrom tavily import AsyncTavilyClient\n\nclient = AsyncTavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n\nasync def search_then_extract(topic):\n    # 1. Search for relevant URLs\n    search_response = await client.search(\n        query=topic,\n        search_depth=\"advanced\",\n        max_results=10\n    )\n\n    # 2. Filter by relevance score\n    urls = [\n        r[\"url\"] for r in search_response[\"results\"]\n        if r[\"score\"] > 0.5\n    ][:20]\n\n    # 3. Extract full content\n    extract_response = await client.extract(\n        urls=urls,\n        query=topic,\n        chunks_per_source=3,\n        extract_depth=\"advanced\"\n    )\n\n    return extract_response[\"results\"]\n\nresults = asyncio.run(search_then_extract(\"AI in healthcare diagnostics\"))\n```\n\n## Error Handling\n\n```python\nfrom tavily import TavilyClient, MissingAPIKeyError, InvalidAPIKeyError, UsageLimitExceededError\n\ntry:\n    client = TavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n    response = client.search(\"test query\")\nexcept MissingAPIKeyError:\n    print(\"API key not provided\")\nexcept InvalidAPIKeyError:\n    print(\"Invalid API key\")\nexcept UsageLimitExceededError:\n    print(\"API credit limit exceeded\")\n```\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/SKILL.md",
    "content": "---\nname: tavily-best-practices\ndescription: \"Build production-ready Tavily integrations with best practices for web search, content extraction, crawling, and research in agentic workflows, RAG systems, and autonomous agents\"\nmetadata:\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"tavily,search,extract,crawl,research,ai,agents,rag,web-search,web-scraping,best-practices\"\n---\n\n# Tavily\n\nTavily is a search API designed for LLMs, enabling AI applications to access real-time web data.\n\n## Installation\n\n**Python:**\n```bash\npip install tavily-python\n```\n\n**JavaScript:**\n```bash\nnpm install @tavily/core\n```\n\nSee **[references/sdk.md](references/sdk.md)** for complete SDK reference.\n\n## Client Initialization\n\n```python\nfrom tavily import TavilyClient\n\n# Uses TAVILY_API_KEY env var (recommended)\nclient = TavilyClient()\n\n#With project tracking (for usage organization)\nclient = TavilyClient(project_id=\"your-project-id\")\n\n# Async client for parallel queries\nfrom tavily import AsyncTavilyClient\nasync_client = AsyncTavilyClient()\n```\n\n## Choosing the Right Method\n\n**For custom agents/workflows:**\n\n| Need | Method |\n|------|--------|\n| Web search results | `search()` |\n| Content from specific URLs | `extract()` |\n| Content from entire site | `crawl()` |\n| URL discovery from site | `map()` |\n\n**For out-of-the-box research:**\n\n| Need | Method |\n|------|--------|\n| End-to-end research with AI synthesis | `research()` |\n\n## Quick Reference\n\n### search() - Web Search\n\n```python\nresponse = client.search(\n    query=\"quantum computing breakthroughs\",  # Keep under 400 chars\n    max_results=10,\n    search_depth=\"advanced\"\n)\nprint(response)\n```\nKey parameters: `query`, `max_results`, `search_depth` (ultra-fast/fast/basic/advanced), `include_domains`, `exclude_domains`, `time_range`\n\nSee **[references/search.md](references/search.md)** for complete search reference.\n\n### extract() - URL Content Extraction\n\n```python\n# Simple one-step extraction\nresponse = client.extract(\n    urls=[\"https://docs.example.com\"],\n    extract_depth=\"advanced\"\n)\nprint(response)\n```\nKey parameters: `urls` (max 20), `extract_depth`, `query`, `chunks_per_source` (1-5)\n\nSee **[references/extract.md](references/extract.md)** for complete extract reference.\n\n### crawl() - Site-Wide Extraction\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    instructions=\"Find API documentation pages\",  # Semantic focus\n    extract_depth=\"advanced\"\n)\nprint(response)\n```\nKey parameters: `url`, `max_depth`, `max_breadth`, `limit`, `instructions`, `chunks_per_source`, `select_paths`, `exclude_paths`\n\nSee **[references/crawl.md](references/crawl.md)** for complete crawl reference.\n\n### map() - URL Discovery\n\n```python\nresponse = client.map(\n    url=\"https://docs.example.com\"\n)\nprint(response)\n```\n\n### research() - AI-Powered Research\n\n```python\nimport time\n\n# For comprehensive multi-topic research\nresult = client.research(\n    input=\"Analyze competitive landscape for X in SMB market\",\n    model=\"pro\"  # or \"mini\" for focused queries, \"auto\" when unsure\n)\nrequest_id = result[\"request_id\"]\n\n# Poll until completed\nresponse = client.get_research(request_id)\nwhile response[\"status\"] not in [\"completed\", \"failed\"]:\n    time.sleep(10)\n    response = client.get_research(request_id)\n\nprint(response[\"content\"])  # The research report\n```\n\nKey parameters: `input`, `model` (\"mini\"/\"pro\"/\"auto\"), `stream`, `output_schema`, `citation_format`\n\nSee **[references/research.md](references/research.md)** for complete research reference.\n\n## Detailed Guides\n\nFor complete parameters, response fields, patterns, and examples:\n\n- **[references/sdk.md](references/sdk.md)** - Python & JavaScript SDK reference, async patterns, Hybrid RAG\n- **[references/search.md](references/search.md)** - Query optimization, search depth selection, domain filtering, async patterns, post-filtering\n- **[references/extract.md](references/extract.md)** - One-step vs two-step extraction, query/chunks for targeting, advanced mode\n- **[references/crawl.md](references/crawl.md)** - Crawl vs Map, instructions for semantic focus, use cases, Map-then-Extract pattern\n- **[references/research.md](references/research.md)** - Prompting best practices, model selection, streaming, structured output schemas\n- **[references/integrations.md](references/integrations.md)** - LangChain, LlamaIndex, CrewAI, Vercel AI SDK, and framework integrations\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/crawl.md",
    "content": "# Crawl & Map API Reference\n\n## Table of Contents\n\n- [Crawl vs Map](#crawl-vs-map)\n- [Key Parameters](#key-parameters)\n- [Instructions and Chunks](#instructions-and-chunks)\n- [Path and Domain Filtering](#path-and-domain-filtering)\n- [Use Cases](#use-cases)\n- [Map then Extract Pattern](#map-then-extract-pattern)\n- [Performance Optimization](#performance-optimization)\n- [Common Pitfalls](#common-pitfalls)\n- [Response Fields](#response-fields)\n- [Summary](#summary)\n\n---\n\n## Crawl vs Map\n\n| Feature | Crawl | Map |\n|---------|-------|-----|\n| **Returns** | Full content | URLs only |\n| **Speed** | Slower | Faster |\n| **Best for** | RAG, deep analysis, documentation | Site structure discovery, URL collection |\n\n**Use Crawl when:**\n- Full content extraction needed\n- Building RAG systems\n- Processing paginated/nested content\n- Integration with knowledge bases\n\n**Use Map when:**\n- Quick site structure discovery\n- URL collection without content\n- Planning before crawling\n- Sitemap generation\n\n---\n\n## Key Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` | string | Required | Root URL to begin |\n| `max_depth` | integer | 1 | Levels deep to crawl (1-5). **Start with 1-2** |\n| `max_breadth` | integer | 20 | Links per page. 50-100 for focused crawls |\n| `limit` | integer | 50 | Total pages cap |\n| `instructions` | string | null | Natural language guidance (2 credits/10 pages) |\n| `chunks_per_source` | integer | 3 | Chunks per page (1-5). Only with `instructions` |\n| `extract_depth` | enum | `\"basic\"` | `\"basic\"` (1 credit/5 URLs) or `\"advanced\"` (2 credits/5 URLs) |\n| `format` | enum | `\"markdown\"` | `\"markdown\"` or `\"text\"` |\n| `select_paths` | array | null | Regex patterns to include |\n| `exclude_paths` | array | null | Regex patterns to exclude |\n| `select_domains` | array | null | Regex for domains to include |\n| `exclude_domains` | array | null | Regex for domains to exclude |\n| `allow_external` | boolean | true (crawl) / false (map) | Include external domain links |\n| `include_images` | boolean | false | Include images (crawl only) |\n| `include_favicon` | boolean | false | Include favicon URL (crawl only) |\n| `include_usage` | boolean | false | Include credit usage info |\n| `timeout` | float | 150 | Max wait (10-150 seconds) |\n\n---\n\n## Instructions and Chunks\n\nUse `instructions` and `chunks_per_source` for semantic focus and token optimization:\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    max_depth=2,\n    instructions=\"Find all documentation about authentication and security\",\n    chunks_per_source=3  # Only top 3 relevant chunks per page\n)\n```\n\n**Key benefits:**\n- `instructions` guides crawler semantically, focusing on relevant content\n- `chunks_per_source` returns only relevant snippets (max 500 chars each)\n- Prevents context window explosion in agentic use cases\n- Chunks appear in `raw_content` as: `<chunk 1> [...] <chunk 2> [...] <chunk 3>`\n\n**Note:** `chunks_per_source` only works when `instructions` is provided.\n\n---\n\n## Path and Domain Filtering\n\n### Path patterns (regex)\n\n```python\n# Target specific sections\nresponse = client.crawl(\n    url=\"https://example.com\",\n    select_paths=[\"/docs/.*\", \"/api/.*\", \"/guides/.*\"],\n    exclude_paths=[\"/blog/.*\", \"/changelog/.*\", \"/private/.*\"]\n)\n\n# Paginated content\nresponse = client.crawl(\n    url=\"https://example.com/blog\",\n    max_depth=2,\n    select_paths=[\"/blog/.*\", \"/blog/page/.*\"],\n    exclude_paths=[\"/blog/tag/.*\"]\n)\n```\n\n### Domain control (regex)\n\n```python\n# Stay within subdomain\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    select_domains=[\"^docs.example.com$\"],\n    max_depth=2\n)\n\n# Exclude specific domains\nresponse = client.crawl(\n    url=\"https://example.com\",\n    exclude_domains=[\"^ads.example.com$\", \"^tracking.example.com$\"]\n)\n```\n\n---\n\n## Use Cases\n\n### 1. Deep/Unlinked Content\nDeeply nested pages, paginated archives, internal search-only content.\n\n```python\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=3,\n    max_breadth=50,\n    limit=200,\n    select_paths=[\"/blog/.*\", \"/changelog/.*\"],\n    exclude_paths=[\"/private/.*\", \"/admin/.*\"]\n)\n```\n\n### 2. Documentation/Structured Content\nDocumentation, changelogs, FAQs with nonstandard markup.\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    max_depth=2,\n    extract_depth=\"advanced\",\n    select_paths=[\"/docs/.*\"]\n)\n```\n\n### 3. Multi-modal/Cross-referencing\nCombining information from multiple sections.\n\n```python\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=2,\n    instructions=\"Find all documentation pages that link to API reference docs\",\n    extract_depth=\"advanced\"\n)\n```\n\n### 4. Rapidly Changing Content\nAPI docs, product announcements, news sections.\n\n```python\nresponse = client.crawl(\n    url=\"https://api.example.com\",\n    max_depth=1,\n    max_breadth=100\n)\n```\n\n### 5. RAG/Knowledge Base Integration\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    max_depth=2,\n    extract_depth=\"advanced\",\n    include_images=True,\n    instructions=\"Extract all technical documentation and code examples\"\n)\n```\n\n### 6. Compliance/Auditing\nComprehensive content analysis for legal checks.\n\n```python\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=3,\n    max_breadth=100,\n    limit=1000,\n    extract_depth=\"advanced\",\n    instructions=\"Find all mentions of GDPR and data protection policies\"\n)\n```\n\n### 7. Known URL Patterns\nSitemap-based crawling, section-specific extraction.\n\n```python\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=1,\n    select_paths=[\"/docs/.*\", \"/api/.*\", \"/guides/.*\"],\n    exclude_paths=[\"/private/.*\", \"/admin/.*\"]\n)\n```\n\n---\n\n## Map then Extract Pattern\n\nConsider using Map before Crawl/Extract to plan your strategy:\n\n1. **Use Map** to get site structure\n2. **Analyze** paths and patterns\n3. **Configure** Crawl or Extract with discovered paths\n4. **Execute** focused extraction\n\n```python\n# Step 1: Map to discover structure\nmap_result = client.map(\n    url=\"https://docs.example.com\",\n    max_depth=2,\n    instructions=\"Find all API docs and guides\"\n)\n\n# Step 2: Filter discovered URLs\napi_docs = [url for url in map_result[\"results\"] if \"/api/\" in url]\nguides = [url for url in map_result[\"results\"] if \"/guides/\" in url]\nprint(f\"Found {len(api_docs)} API docs, {len(guides)} guides\")\n\n# Step 3: Extract from filtered URLs\ntarget_urls = api_docs + guides\nresponse = client.extract(\n    urls=target_urls[:20],  # Max 20 per extract call\n    extract_depth=\"advanced\",\n    query=\"API endpoints and usage examples\",\n    chunks_per_source=3\n)\n```\n\n**Benefits:**\n- Discover site structure before committing to full crawl\n- Identify relevant path patterns\n- Avoid unnecessary extraction\n- More control over what gets extracted\n\n---\n\n## Performance Optimization\n\n### Depth vs Performance\n\nEach depth level increases crawl time exponentially:\n\n| Depth | Typical Pages | Time |\n|-------|---------------|------|\n| 1 | 10-50 | Seconds |\n| 2 | 50-500 | Minutes |\n| 3 | 500-5000 | Many minutes |\n\n**Best practices:**\n- Start with `max_depth=1` and increase only if needed\n- Use `max_breadth` to control horizontal expansion\n- Set appropriate `limit` to prevent excessive crawling\n- Process results incrementally rather than waiting for full crawl\n\n### Rate Limiting\n\n- Respect site's robots.txt\n- Monitor API usage and limits\n- Use appropriate error handling for rate limits\n- Consider delays between large crawl operations\n\n### Conservative vs Comprehensive\n\n```python\n# Conservative (start here)\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=1,\n    max_breadth=20,\n    limit=20\n)\n\n# Comprehensive (use carefully)\nresponse = client.crawl(\n    url=\"https://example.com\",\n    max_depth=3,\n    max_breadth=100,\n    limit=500\n)\n```\n\n---\n\n## Common Pitfalls\n\n| Problem | Impact | Solution |\n|---------|--------|----------|\n| Excessive depth (`max_depth=4+`) | Exponential time, unnecessary pages | Start with 1-2, increase if needed |\n| Unfocused crawling | Wasted resources, irrelevant content, context explosion | Use `instructions` to focus semantically |\n| Missing limits | Runaway crawls, unexpected costs | Always set reasonable `limit` value |\n| Ignoring `failed_results` | Incomplete data, missed content | Monitor and adjust parameters |\n| Full content without chunks | Context window explosion | Use `instructions` + `chunks_per_source` |\n\n---\n\n## Response Fields\n\n### Crawl Response\n\n| Field | Description |\n|-------|-------------|\n| `base_url` | The URL you started the crawl from |\n| `results` | List of crawled pages |\n| `results[].url` | Page URL |\n| `results[].raw_content` | Extracted content (or chunks if instructions provided) |\n| `results[].images` | Image URLs extracted from the page |\n| `results[].favicon` | Favicon URL (if `include_favicon=True`) |\n| `response_time` | Time in seconds |\n| `request_id` | Unique identifier for support reference |\n\n### Map Response\n\n| Field | Description |\n|-------|-------------|\n| `base_url` | The URL you started the mapping from |\n| `results` | List of discovered URLs |\n| `response_time` | Time in seconds |\n| `request_id` | Unique identifier for support reference |\n\n---\n\n## Summary\n\n1. **Use instructions and chunks_per_source** for focused, relevant results in agentic use cases\n2. **Start conservative** (`max_depth=1`, `max_breadth=20`) and scale up as needed\n3. **Use path patterns** to focus crawling on relevant content\n4. **Choose appropriate extract_depth** based on content complexity\n5. **Always set a limit** to prevent runaway crawls and unexpected costs\n6. **Monitor failed_results** and adjust patterns accordingly\n7. **Use Map first** to understand site structure before committing to full crawl\n8. **Implement error handling** for rate limits and failures\n9. **Respect robots.txt** and site policies\n\n> Crawling is powerful but resource-intensive. Focus your crawls, start small, monitor results, and scale gradually based on actual needs.\n\nFor more details, see the [full API reference](https://docs.tavily.com/documentation/api-reference/endpoint/crawl)\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/extract.md",
    "content": "# Extract API Reference\n\n## Table of Contents\n\n- [Extraction Approaches](#extraction-approaches)\n- [Key Parameters](#key-parameters)\n- [Query and Chunks](#query-and-chunks)\n- [Extract Depth](#extract-depth)\n- [Advanced Filtering Strategies](#advanced-filtering-strategies)\n- [Response Fields](#response-fields)\n- [Summary](#summary)\n\n---\n\n## Extraction Approaches\n\n### Search with include_raw_content\n\nGet search results and content in one call:\n\n```python\nresponse = client.search(\n    query=\"AI healthcare applications\",\n    include_raw_content=True,\n    max_results=5\n)\n```\n\n**When to use:**\n- Quick prototyping\n- Simple queries where search results are likely relevant\n- Single API call convenience\n\n### Direct Extract API (Recommended)\n\nTwo-step pattern for more control:\n\n```python\n# Step 1: Search\nsearch_results = client.search(\n    query=\"Python async best practices\",\n    max_results=10\n)\n\n# Step 2: Filter by relevance score\nrelevant_urls = [\n    r[\"url\"] for r in search_results[\"results\"]\n    if r[\"score\"] > 0.5\n]\n\n# Step 3: Extract with targeting\nextracted = client.extract(\n    urls=relevant_urls[:20],\n    query=\"async patterns and concurrency\",  # Reranks chunks\n    chunks_per_source=3  # Prevents context explosion\n)\n\nfor item in extracted[\"results\"]:\n    print(f\"URL: {item['url']}\")\n    print(f\"Content: {item['raw_content'][:500]}...\")\n```\n\n**When to use:**\n- You want control over which URLs to extract\n- You need to filter/curate URLs before extraction\n- You want targeted extraction with query and chunks_per_source\n\n---\n\n## Key Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `urls` | string/array | Required | Single URL or list (max 20) |\n| `extract_depth` | enum | `\"basic\"` | `\"basic\"` or `\"advanced\"` (for complex/JS pages) |\n| `query` | string | null | Reranks chunks by relevance to this query |\n| `chunks_per_source` | integer | 3 | Chunks per source (1-5, max 500 chars each). Only with `query` |\n| `format` | enum | `\"markdown\"` | Output: `\"markdown\"` or `\"text\"` |\n| `include_images` | boolean | false | Include image URLs |\n| `include_favicon` | boolean | false | Include favicon URL |\n| `include_usage` | boolean | false | Include credit consumption data in response |\n| `timeout` | float | varies | Max wait time (1.0-60.0 seconds) |\n\n---\n\n## Query and Chunks\n\nUse `query` and `chunks_per_source` to get only relevant content and prevent context window explosion:\n\n```python\nextracted = client.extract(\n    urls=[\n        \"https://example.com/ml-healthcare\",\n        \"https://example.com/ai-diagnostics\",\n        \"https://example.com/medical-ai\"\n    ],\n    query=\"AI diagnostic tools accuracy\",\n    chunks_per_source=2  # 2 most relevant chunks per URL\n)\n```\n\n**When to use query:**\n- To extract only relevant portions of long documents\n- When you need focused content instead of full page extraction\n- For targeted information retrieval from specific URLs\n\n**Key benefits of chunks_per_source:**\n- Returns only relevant snippets (max 500 chars each) instead of full page\n- Chunks appear in `raw_content` as: `<chunk 1> [...] <chunk 2> [...] <chunk 3>`\n- Prevents context window from exploding in agentic use cases\n\n**Note:** `chunks_per_source` only works when `query` is provided.\n\n---\n\n## Extract Depth\n\n| Depth | When to use |\n|-------|-------------|\n| `basic` (default) | Simple text extraction, faster |\n| `advanced` | Dynamic/JS-rendered pages, tables, structured data, embedded media |\n\n```python\n# For complex pages\nextracted = client.extract(\n    urls=[\"https://example.com/complex-page\"],\n    extract_depth=\"advanced\"\n)\n```\n\n**Fallback strategy:** If `basic` fails, retry with `advanced`:\n\n```python\nresult = client.extract(urls=[url], extract_depth=\"basic\")\nif url in [f[\"url\"] for f in result.get(\"failed_results\", [])]:\n    result = client.extract(urls=[url], extract_depth=\"advanced\")\n```\n\n**Timeout tuning:** If latency isn't critical, set `timeout=60.0` for better success on slow pages.\n\n---\n\n## Advanced Filtering Strategies\n\nBeyond query-based filtering, consider these approaches before extraction:\n\n| Strategy | When to use |\n|----------|-------------|\n| Score-based | Filter search results by relevance score |\n| Domain-based | Filter by trusted domains |\n| Re-ranking | Use dedicated re-ranking models for precision |\n| LLM-based | Let an LLM assess relevance before extraction |\n| Clustering | Group similar documents, extract from clusters |\n\n### Optimal Workflow\n\n1. **Search** to discover relevant URLs\n2. **Filter** by relevance score, domain, or content snippet\n3. **Re-rank** if needed using specialized models\n4. **Extract** from top-ranked sources with query and chunks_per_source\n5. **Validate** extracted content quality\n6. **Process** for your AI application\n\n### Example: Complete Pipeline\n\n```python\nimport asyncio\nfrom tavily import AsyncTavilyClient\n\nclient = AsyncTavilyClient()\n\nasync def content_pipeline(topic):\n    # 1. Search with sub-queries for breadth\n    queries = [\n        f\"{topic} overview\",\n        f\"{topic} best practices\",\n        f\"{topic} recent developments\"\n    ]\n    responses = await asyncio.gather(\n        *(client.search(q, search_depth=\"advanced\", max_results=10) for q in queries)\n    )\n\n    # 2. Filter and aggregate by score\n    urls = []\n    for response in responses:\n        urls.extend([\n            r['url'] for r in response['results']\n            if r['score'] > 0.5\n        ])\n\n    # 3. Deduplicate\n    urls = list(set(urls))[:20]\n\n    # 4. Extract with error handling\n    extracted = await asyncio.gather(\n        *(client.extract(urls=[url], query=topic, extract_depth=\"advanced\")\n          for url in urls),\n        return_exceptions=True\n    )\n\n    # 5. Filter successful extractions\n    return [e for e in extracted if not isinstance(e, Exception)]\n\nasyncio.run(content_pipeline(\"machine learning in healthcare\"))\n```\n\n---\n\n## Response Fields\n\n**Top-level response:**\n\n| Field | Description |\n|-------|-------------|\n| `results` | Array of successfully extracted content |\n| `failed_results` | Array of URLs that failed extraction |\n| `response_time` | Time in seconds |\n| `request_id` | Unique identifier for support reference |\n| `usage` | Credit usage info (if `include_usage=True`) |\n\n**Each result object:**\n\n| Field | Description |\n|-------|-------------|\n| `url` | The URL extracted from |\n| `raw_content` | Full content, or top-ranked chunks joined by `[...]` when `query` provided |\n| `images` | Array of image URLs (if `include_images=true`) |\n| `favicon` | Favicon URL (if `include_favicon=true`) |\n\n**Each failed_results object:**\n\n| Field | Description |\n|-------|-------------|\n| `url` | The URL that failed |\n| `error` | Error message |\n\n---\n\n## Summary\n\n1. **Use query and chunks_per_source** for targeted, focused extraction\n2. **Choose Extract API** when you need control over which URLs to extract from\n3. **Filter URLs** before extraction using scores, re-ranking, or domain trust\n4. **Choose appropriate extract_depth** based on content complexity\n5. **Process URLs concurrently** with async operations for better performance\n6. **Implement error handling** to manage failed extractions gracefully\n7. **Validate extracted content** before downstream processing\n\nFor more details, see the [full API reference](https://docs.tavily.com/documentation/api-reference/endpoint/extract)\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/integrations.md",
    "content": "# Framework Integrations\n\n## Table of Contents\n\n- [LangChain](#langchain)\n- [Pydantic AI](#pydantic-ai)\n- [LlamaIndex](#llamaindex)\n- [Agno](#agno)\n- [OpenAI Function Calling](#openai-function-calling)\n- [Anthropic Tool Calling](#anthropic-tool-calling)\n- [Google ADK](#google-adk)\n- [Vercel AI SDK](#vercel-ai-sdk)\n- [CrewAI](#crewai)\n- [No-Code Platforms](#no-code-platforms)\n\n---\n\n## LangChain\n\nWe recommend the official `langchain-tavily` package for LangChain integrations.\n\n> Warning: `langchain_community.tools.tavily_search.tool` is deprecated. Migrate to `langchain-tavily` for actively maintained Search, Extract, Map, Crawl, and Research tools.\n\n### Installation\n\n```bash\npip install -U langchain-tavily\n```\n\n### Credentials\n\n```python\nimport getpass\nimport os\n\nif not os.environ.get(\"TAVILY_API_KEY\"):\n    os.environ[\"TAVILY_API_KEY\"] = getpass.getpass(\"Tavily API key:\\n\")\n```\n\n### Tavily Search\n\n**Available parameters**\n- `max_results` (default: `5`)\n- `topic` (`\"general\"`, `\"news\"`, `\"finance\"`)\n- `include_answer`\n- `include_raw_content`\n- `include_images`\n- `include_image_descriptions`\n- `search_depth` (`\"basic\"` or `\"advanced\"`)\n- `time_range` (`\"day\"`, `\"week\"`, `\"month\"`, `\"year\"`)\n- `start_date` (`YYYY-MM-DD`)\n- `end_date` (`YYYY-MM-DD`)\n- `include_domains`\n- `exclude_domains`\n- `include_usage`\n\n**Instantiation**\n\n```python\nfrom langchain_tavily import TavilySearch\n\ntavily_search = TavilySearch(\n    max_results=5,\n    topic=\"general\"\n)\n```\n\n**Invoke directly with args**\n- Required: `query`\n- Can also be overridden at invocation: `include_images`, `search_depth`, `time_range`, `include_domains`, `exclude_domains`, `start_date`, `end_date`\n- `include_answer` and `include_raw_content` should be set at instantiation time for predictable response sizes\n\n```python\nresult = tavily_search.invoke({\"query\": \"What happened at the last Wimbledon?\"})\n```\n\n**Use with agent**\n\n```python\nfrom langchain.agents import create_agent\nfrom langchain_openai import ChatOpenAI\n\nagent = create_agent(\n    model=ChatOpenAI(model=\"gpt-5\"),\n    tools=[tavily_search],\n    system_prompt=\"You are a helpful research assistant. Use web search to find accurate, up-to-date information.\",\n)\nresponse = agent.invoke({\n    \"messages\": [{\n        \"role\": \"user\",\n        \"content\": \"What is the most popular sport in the world? Include only Wikipedia sources.\",\n    }]\n})\n```\n\nTip: include today's date in the system prompt for time-aware queries.\n\n### Tavily Extract\n\n**Available parameters**\n- `extract_depth` (`\"basic\"` or `\"advanced\"`)\n- `include_images`\n\n```python\nfrom langchain_tavily import TavilyExtract\n\ntavily_extract = TavilyExtract(\n    extract_depth=\"basic\",  # or \"advanced\"\n    # include_images=False,\n)\n\nresult = tavily_extract.invoke({\n    \"urls\": [\"https://en.wikipedia.org/wiki/Lionel_Messi\"]\n})\n```\n\n### Tavily Map/Crawl\n\n```python\nfrom langchain_tavily import TavilyMap\n\ntavily_map = TavilyMap()\n\nresult = tavily_map.invoke({\n    \"url\": \"https://docs.example.com\",\n    \"instructions\": \"Find all documentation and tutorial pages\"\n})\n# Returns: {\"base_url\": ..., \"results\": [urls...], \"response_time\": ...}\n```\n\n```python\nfrom langchain_tavily import TavilyCrawl\n\ntavily_crawl = TavilyCrawl()\n\nresult = tavily_crawl.invoke({\n    \"url\": \"https://docs.example.com\",\n    \"instructions\": \"Extract API documentation and code examples\"\n})\n# Returns: {\"base_url\": ..., \"results\": [{url, raw_content}...], \"response_time\": ...}\n```\n\n### Tavily Research\n\n**Available parameters**\n- `input` (required)\n- `model` (`\"mini\"`, `\"pro\"`, `\"auto\"`)\n- `output_schema`\n- `stream`\n- `citation_format` (`\"numbered\"`, `\"mla\"`, `\"apa\"`, `\"chicago\"`)\n\n```python\nfrom langchain_tavily import TavilyResearch\n\ntavily_research = TavilyResearch()\n\nresult = tavily_research.invoke({\n    \"input\": \"Research the latest developments in AI and summarize key trends.\",\n    \"model\": \"mini\",\n    \"citation_format\": \"apa\"\n})\n```\n\n### Tavily Get Research\n\n```python\nfrom langchain_tavily import TavilyGetResearch\n\ntavily_get_research = TavilyGetResearch()\nfinal = tavily_get_research.invoke({\"request_id\": result[\"request_id\"]})\n```\n\n---\n\n## Pydantic AI\n\nTavily is available for integration through Pydantic AI.\n\n### Introduction\n\nIntegrate Tavily with Pydantic AI to enhance your AI agents with powerful web search capabilities. Pydantic AI provides a framework for building AI agents with tools, making it easy to incorporate real-time web search and data extraction into your applications.\n\n### Step-by-Step Integration Guide\n\n#### Step 1: Install Required Packages\n\nInstall the necessary Python packages:\n\n```bash\npip install \"pydantic-ai-slim[tavily]\"\n```\n\n#### Step 2: Set Up API Keys\n\n- Tavily API Key: [Get your Tavily API key](https://app.tavily.com/home)\n\nSet this as an environment variable:\n\n```bash\nexport TAVILY_API_KEY=your_tavily_api_key\n```\n\n#### Step 3: Initialize Pydantic AI Agent with Tavily Tools\n\n```python\nimport os\nfrom pydantic_ai.agent import Agent\nfrom pydantic_ai.common_tools.tavily import tavily_search_tool\n\n# Get API key from environment\napi_key = os.getenv(\"TAVILY_API_KEY\")\nassert api_key is not None\n\n# Initialize the agent with Tavily tools\nagent = Agent(\n    \"openai:o3-mini\",\n    tools=[tavily_search_tool(api_key)],\n    system_prompt=\"Search Tavily for the given query and return the results.\",\n)\n```\n\n#### Step 4: Example Use Cases\n\n```python\n# Example 1: Basic search for news\nresult = agent.run_sync(\"Tell me the top news in the GenAI world, give me links.\")\nprint(result.output)\n```\n\n---\n\n## LlamaIndex\n\n```python\nfrom llama_index.tools.tavily_research import TavilyToolSpec\n\n# Initialize tools\ntavily_tool = TavilyToolSpec(api_key=\"tvly-YOUR_API_KEY\")\ntools = tavily_tool.to_tool_list()\n\n# Use with agent\nfrom llama_index.agent.openai import OpenAIAgent\n\nagent = OpenAIAgent.from_tools(tools)\nresponse = agent.chat(\"What are the latest AI developments?\")\n```\n\n---\n\n## Agno\n\nTavily is available for integration through Agno, a lightweight framework for building agents with tools, memory, and reasoning.\n\n### Introduction\n\nIntegrate Tavily with Agno to enhance your AI agents with powerful web search capabilities. Agno makes it easy to incorporate real-time web search and data extraction into your AI applications.\n\n### Step-by-Step Integration Guide\n\n#### Step 1: Install Required Packages\n\n```bash\npip install agno tavily-python\n```\n\n#### Step 2: Set Up API Keys\n\n- Tavily API Key: [Get your Tavily API key](https://app.tavily.com/home)\n- OpenAI API Key: [Get your OpenAI API key](https://platform.openai.com/api-keys)\n\nSet these as environment variables:\n\n```bash\nexport TAVILY_API_KEY=your_tavily_api_key\nexport OPENAI_API_KEY=your_openai_api_key\n```\n\n#### Step 3: Initialize Agno Agent with Tavily Tools\n\n```python\nfrom agno.agent import Agent\nfrom agno.tools.tavily import TavilyTools\n\n# Initialize the agent with Tavily tools\nagent = Agent(\n    tools=[\n        TavilyTools(\n            search=True,             # Enable search functionality\n            max_tokens=8000,         # Increase max tokens for detailed results\n            search_depth=\"advanced\", # Use advanced search for comprehensive results\n            format=\"markdown\",       # Format results as markdown\n        )\n    ],\n    show_tool_calls=True,\n)\n```\n\n#### Step 4: Example Use Cases\n\n```python\n# Example 1: Basic search with default parameters\nagent.print_response(\"Latest developments in quantum computing\", markdown=True)\n\n# Example 2: Market research with multiple parameters\nagent.print_response(\n    \"Analyze the competitive landscape of AI-powered customer service solutions in 2026, \"\n    \"focusing on market leaders and emerging trends\",\n    markdown=True,\n)\n\n# Example 3: Technical documentation search\nagent.print_response(\n    \"Find the latest documentation and tutorials about Python async programming, \"\n    \"focusing on asyncio and FastAPI\",\n    markdown=True,\n)\n\n# Example 4: News aggregation\nagent.print_response(\n    \"Gather the latest news about artificial intelligence from tech news websites \"\n    \"published in the last week\",\n    markdown=True,\n)\n```\n\n### Additional Use Cases\n\n- Content curation: Gather and organize information from multiple sources\n- Real-time data integration: Keep your AI agents up to date with the latest information\n- Technical documentation: Search and analyze technical documentation\n- Market analysis: Conduct comprehensive market research and analysis\n\n---\n\n## OpenAI Function Calling\n\nDefine Tavily as an OpenAI function:\n\n```python\nfrom openai import OpenAI\nfrom tavily import TavilyClient\nimport json\n\nopenai_client = OpenAI()\ntavily_client = TavilyClient()\n\ntools = [{\n    \"type\": \"function\",\n    \"function\": {\n        \"name\": \"web_search\",\n        \"description\": \"Search the web for current information\",\n        \"parameters\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"query\": {\n                    \"type\": \"string\",\n                    \"description\": \"The search query\"\n                }\n            },\n            \"required\": [\"query\"]\n        }\n    }\n}]\n\ndef handle_tool_call(tool_call):\n    if tool_call.function.name == \"web_search\":\n        args = json.loads(tool_call.function.arguments)\n        return tavily_client.search(args[\"query\"])\n\n# Chat completion with tools\nresponse = openai_client.chat.completions.create(\n    model=\"gpt-4.1\",\n    messages=[{\"role\": \"user\", \"content\": \"What are the latest AI trends?\"}],\n    tools=tools\n)\n\nif response.choices[0].message.tool_calls:\n    tool_call = response.choices[0].message.tool_calls[0]\n    search_results = handle_tool_call(tool_call)\n\n    # Continue conversation with results\n    messages = [\n        {\"role\": \"user\", \"content\": \"What are the latest AI trends?\"},\n        response.choices[0].message,\n        {\"role\": \"tool\", \"tool_call_id\": tool_call.id, \"content\": json.dumps(search_results)}\n    ]\n    final = openai_client.chat.completions.create(\n        model=\"gpt-4.1\",\n        messages=messages\n    )\n```\n\n---\n\n## Anthropic Tool Calling\n\nIntegrate Tavily with Anthropic Claude to add real-time web search in tool-calling workflows.\n\n### Installation\n\n```bash\npip install anthropic tavily-python\n```\n\n### Setup\n\n```bash\nexport ANTHROPIC_API_KEY=\"your-anthropic-api-key\"\nexport TAVILY_API_KEY=\"your-tavily-api-key\"\n```\n\n### Using Tavily With Anthropic Tool Calling\n\n```python\nimport json\nimport os\nfrom anthropic import Anthropic\nfrom tavily import TavilyClient\n\nclient = Anthropic(api_key=os.environ[\"ANTHROPIC_API_KEY\"])\ntavily_client = TavilyClient(api_key=os.environ[\"TAVILY_API_KEY\"])\nMODEL_NAME = \"claude-sonnet\"\n```\n\n### Implementation\n\n#### System prompt\n\n```python\nSYSTEM_PROMPT = (\n    \"You are a research assistant. Use the tavily_search tool when needed. \"\n    \"After tools run and tool results are provided back to you, produce a concise, \"\n    \"well-structured summary with key bullets and a Sources section listing URLs.\"\n)\n```\n\n#### Tool schema\n\n```python\ntools = [\n    {\n        \"name\": \"tavily_search\",\n        \"description\": \"Search the web using Tavily and return relevant links and summaries.\",\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"query\": {\"type\": \"string\", \"description\": \"Search query string.\"},\n                \"max_results\": {\"type\": \"integer\", \"default\": 5},\n                \"search_depth\": {\n                    \"type\": \"string\",\n                    \"enum\": [\"basic\", \"advanced\"],\n                    \"default\": \"basic\",\n                },\n            },\n            \"required\": [\"query\"],\n        },\n    }\n]\n```\n\n#### Tool execution\n\n```python\ndef tavily_search(**kwargs):\n    return tavily_client.search(**kwargs)\n\ndef process_tool_call(name, args):\n    if name == \"tavily_search\":\n        return tavily_search(**args)\n    raise ValueError(f\"Unknown tool: {name}\")\n```\n\n#### Main chat function\n\n```python\ndef chat_with_claude(user_message: str):\n    # Call 1: allow tool use\n    initial_response = client.messages.create(\n        model=MODEL_NAME,\n        max_tokens=4096,\n        system=SYSTEM_PROMPT,\n        messages=[{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": user_message}]}],\n        tools=tools,\n    )\n\n    # If Claude answers without tools, return text directly\n    if initial_response.stop_reason != \"tool_use\":\n        return \"\".join(\n            block.text for block in initial_response.content\n            if getattr(block, \"type\", None) == \"text\"\n        )\n\n    # Execute all requested tools\n    tool_result_blocks = []\n    for block in initial_response.content:\n        if getattr(block, \"type\", None) == \"tool_use\":\n            result = process_tool_call(block.name, block.input)\n            tool_result_blocks.append(\n                {\n                    \"type\": \"tool_result\",\n                    \"tool_use_id\": block.id,\n                    \"content\": json.dumps(result),\n                }\n            )\n\n    # Call 2: send tool results and ask Claude for final synthesis\n    final_response = client.messages.create(\n        model=MODEL_NAME,\n        max_tokens=4096,\n        system=SYSTEM_PROMPT,\n        messages=[\n            {\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": user_message}]},\n            {\"role\": \"assistant\", \"content\": initial_response.content},\n            {\"role\": \"user\", \"content\": tool_result_blocks},\n            {\n                \"role\": \"user\",\n                \"content\": [{\n                    \"type\": \"text\",\n                    \"text\": \"Please synthesize the final answer now based on the tool results above. Include 3-7 bullets and a Sources section with URLs.\",\n                }],\n            },\n        ],\n    )\n\n    return \"\".join(\n        block.text for block in final_response.content\n        if getattr(block, \"type\", None) == \"text\"\n    )\n```\n\n### Usage example\n\n```python\nchat_with_claude(\"What is trending now in the agents space in 2026?\")\n```\n\nReference: https://docs.tavily.com/documentation/integrations/anthropic\n\n---\n\n## Google ADK\n\nGoogle ADK can connect to Tavily through Tavily's remote MCP server, giving your Gemini-based agent live search, extraction, and site exploration capabilities.\n\n### Prerequisites\n\n- Python 3.9+\n- Tavily API key: https://app.tavily.com/home\n- Gemini API key: https://aistudio.google.com/app/apikey\n\n### Installation\n\n```bash\npip install google-adk mcp\n```\n\n### Agent Setup\n\n```python\nimport os\nfrom google.adk.agents import Agent\nfrom google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPServerParams\nfrom google.adk.tools.mcp_tool.mcp_toolset import MCPToolset\n\ntavily_api_key = os.getenv(\"TAVILY_API_KEY\")\n\nroot_agent = Agent(\n    model=\"gemini-2.5-pro\",\n    name=\"tavily_agent\",\n    instruction=(\n        \"You are a helpful assistant that uses Tavily to search the web, \"\n        \"extract content, and explore websites. Use Tavily tools to provide \"\n        \"up-to-date information.\"\n    ),\n    tools=[\n        MCPToolset(\n            connection_params=StreamableHTTPServerParams(\n                url=\"https://mcp.tavily.com/mcp/\",\n                headers={\"Authorization\": f\"Bearer {tavily_api_key}\"},\n            )\n        )\n    ],\n)\n```\n\n### Environment Variables\n\n```bash\nexport GOOGLE_API_KEY=\"your_gemini_api_key_here\"\nexport TAVILY_API_KEY=\"your_tavily_api_key_here\"\n```\n\n### Run\n\n```bash\nadk create my_agent\nadk run my_agent\n# Optional web UI:\nadk web --port 8000\n```\n\n### Available Tavily MCP tools\n\n- `tavily-search`\n- `tavily-extract`\n- `tavily-map`\n- `tavily-crawl`\n\nReference: https://docs.tavily.com/documentation/integrations/google-adk\n\n---\n\n## Vercel AI SDK\n\nThe `@tavily/ai-sdk` package provides pre-built tools for Vercel AI SDK v5.\n\n### Installation\n\n```bash\nnpm install ai @ai-sdk/openai @tavily/ai-sdk\n```\n\n### Usage\n\n```typescript\nimport { tavilySearch, tavilyCrawl } from \"@tavily/ai-sdk\";\nimport { generateText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\n// Search\nconst result = await generateText({\n  model: openai(\"gpt-4.1\"),\n  prompt: \"What are the latest AI developments?\",\n  tools: {\n    tavilySearch: tavilySearch({\n      maxResults: 5,\n      searchDepth: \"advanced\",\n    }),\n  },\n});\n\n// Crawl\nconst crawlResult = await generateText({\n  model: openai(\"gpt-4.1\"),\n  prompt: \"Crawl tavily.com and summarize their features\",\n  tools: {\n    tavilyCrawl: tavilyCrawl({\n      maxDepth: 2,\n      limit: 50,\n    }),\n  },\n});\n```\n\n**Available tools:** `tavilySearch`, `tavilyExtract`, `tavilyCrawl`, `tavilyMap`\n\n---\n\n## CrewAI\n\nCrewAI provides built-in Tavily tools for multi-agent workflows.\n\n### Installation\n\n```bash\npip install 'crewai[tools]'\n```\n\n### Usage\n\n```python\nimport os\nfrom crewai import Agent, Task, Crew\nfrom crewai_tools import TavilySearchTool, TavilyExtractTool\n\nos.environ[\"TAVILY_API_KEY\"] = \"your-api-key\"\n\n# Search tool\nsearch_tool = TavilySearchTool()\n\n# Create agent with Tavily\nresearcher = Agent(\n    role=\"Research Analyst\",\n    goal=\"Find and analyze information on given topics\",\n    tools=[search_tool],\n    backstory=\"Expert at finding relevant information online\"\n)\n\ntask = Task(\n    description=\"Research the latest developments in quantum computing\",\n    expected_output=\"A comprehensive summary with sources\",\n    agent=researcher\n)\n\ncrew = Crew(agents=[researcher], tasks=[task])\nresult = crew.kickoff()\n```\n\n---\n\n## No-Code Platforms\n\nTavily integrates with popular no-code automation platforms:\n\n| Platform | Features | Best For |\n|----------|----------|----------|\n| **Zapier** | Search, Extract | CRM enrichment, automated research |\n| **Make** | Search, Extract | Complex workflows, multi-step automations |\n| **n8n** | Search, Extract, AI Agent tool | Self-hosted, AI agent workflows |\n| **Dify** | Search, Extract | No-code AI apps, chatflows |\n| **FlowiseAI** | Search | Visual LLM builders, RAG systems |\n| **Langflow** | Search, Extract | Visual agent building |\n\n---\n\n## Additional Integrations\nSee the [full integrations documentation](https://docs.tavily.com/documentation/integrations) for complete guides.\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/research.md",
    "content": "# Research API Reference\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Prompting Best Practices](#prompting-best-practices)\n- [Model Selection](#model-selection)\n- [Key Parameters](#key-parameters)\n- [Basic Usage](#basic-usage)\n- [Streaming vs Polling](#streaming-vs-polling)\n- [Structured Output vs Report](#structured-output-vs-report)\n- [Response Fields](#response-fields)\n- [Summary](#summary)\n\n---\n\n## Overview\n\nThe Research API conducts comprehensive research on any topic with automatic source gathering, analysis, and response generation with citations. It's an end-to-end solution when you need AI-powered research without building your own pipeline.\n\n---\n\n## Prompting Best Practices\n\nDefine a **clear goal** with all **details** and **direction**.\n\n**Guidelines:**\n- **Be specific when you can.** Include known details: target market, competitors, geography, constraints\n- **Stay open-ended only for discovery.** Make it explicit: \"tell me about the most impactful AI innovations in healthcare in 2025\"\n- **Avoid contradictions.** Don't include conflicting constraints or goals\n- **Share what's already known.** Include prior assumptions so research doesn't repeat existing knowledge\n- **Keep prompts clean and directed.** Clear task + essential context + desired output format\n\n### Example Queries\n\n**Company research:**\n```\nResearch the company ____ and its 2026 outlook. Provide a brief overview\nof the company, its products, services, and market position.\n```\n\n**Competitive analysis:**\n```\nConduct a competitive analysis of ____ in 2026. Identify their main\ncompetitors, compare market positioning, and analyze key differentiators.\n```\n\n**With prior context:**\n```\nWe're evaluating Notion as a potential partner. We already know they\nprimarily serve SMB and mid-market teams, expanded their AI features\nsignificantly in 2025, and most often compete with Confluence and ClickUp.\nResearch Notion's 2026 outlook, including market position, growth risks,\nand where a partnership could be most valuable. Include citations.\n```\n\n---\n\n## Model Selection\n\n| Model | Best For |\n|-------|----------|\n| `pro` | Comprehensive, multi-agent research for complex, multi-domain topics |\n| `mini` | Targeted, efficient research for narrow or well-scoped questions |\n| `auto` | When unsure how complex research will be (default) |\n\n### Pro Model\n\nMulti-agent research suited for complex topics spanning multiple subtopics or domains. Use for deeper analysis, thorough reports, or maximum accuracy.\n\n```python\nresult = client.research(\n    input=\"Analyze the competitive landscape for ____ in the SMB market, \"\n          \"including key competitors, positioning, pricing models, customer \"\n          \"segments, recent product moves, and defensible advantages or risks \"\n          \"over the next 2-3 years.\",\n    model=\"pro\"\n)\n```\n\n### Mini Model\n\nOptimized for targeted, efficient research. Best for narrow or well-scoped questions where you still benefit from agentic searching and synthesis.\n\n```python\nresult = client.research(\n    input=\"What are the top 5 competitors to ____ in the SMB market, and how do they differentiate?\",\n    model=\"mini\"\n)\n```\n\n---\n\n## Key Parameters\n\n### research()\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `input` | string | Required | The research topic or question |\n| `model` | enum | `\"auto\"` | `\"mini\"`, `\"pro\"`, or `\"auto\"` |\n| `stream` | boolean | false | Enable streaming responses |\n| `output_schema` | object | null | JSON Schema for structured output |\n| `citation_format` | enum | `\"numbered\"` | `\"numbered\"`, `\"mla\"`, `\"apa\"`, `\"chicago\"` |\n\n### get_research()\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `request_id` | string | Task ID from `research()` response |\n\n---\n\n## Basic Usage\n\nResearch tasks are two-step: initiate with `research()`, retrieve with `get_research()`.\n\n```python\nimport time\nfrom tavily import TavilyClient\n\nclient = TavilyClient()\n\n# Step 1: Start research task\nresult = client.research(\n    input=\"Latest developments in quantum computing and their practical applications\",\n    model=\"pro\"\n)\nrequest_id = result[\"request_id\"]\n\n# Step 2: Poll until completed\nresponse = client.get_research(request_id)\nwhile response[\"status\"] not in [\"completed\", \"failed\"]:\n    print(f\"Status: {response['status']}... polling again in 10 seconds\")\n    time.sleep(10)\n    response = client.get_research(request_id)\n\n# Step 3: Handle result\nif response[\"status\"] == \"failed\":\n    raise RuntimeError(f\"Research failed: {response.get('error', 'Unknown error')}\")\n\nreport = response[\"content\"]\nsources = response[\"sources\"]\n```\n\n---\n\n## Streaming vs Polling\n\n**Streaming** — Best for user interfaces where you want real-time updates.\n**Polling** — Best for background processes where you check status periodically.\n\n### Streaming\n\nEnable real-time progress monitoring with `stream=True`.\n\n```python\nstream = client.research(\n    input=\"Latest developments in quantum computing\",\n    model=\"pro\",\n    stream=True\n)\n\nfor chunk in stream:\n    print(chunk.decode('utf-8'))\n```\n\n### Event Types\n\n| Event Type | Description |\n|------------|-------------|\n| **Tool Call** | Agent initiates action (Planning, WebSearch, etc.) |\n| **Tool Response** | Results after tool execution with sources |\n| **Content** | Research report streamed as markdown (or JSON with `output_schema`) |\n| **Sources** | Complete list of sources, emitted after content |\n| **Done** | Signals completion |\n\n### Tool Types\n\n| Tool | Description | Models |\n|------|-------------|--------|\n| `Planning` | Initializes research strategy | mini, pro |\n| `WebSearch` | Executes web searches | mini, pro |\n| `Generating` | Creates final report | mini, pro |\n| `ResearchSubtopic` | Deep research on subtopics | pro only |\n\n### Typical Flow\n\n1. `Planning` tool_call → tool_response\n2. `WebSearch` tool_call → tool_response (with sources)\n3. `ResearchSubtopic` cycles (Pro mode only)\n4. `Generating` tool_call → tool_response\n5. `Content` chunks (markdown or structured JSON)\n6. `Sources` event\n7. `Done` event\n\nSee [streaming cookbook](https://github.com/tavily-ai/tavily-cookbook/blob/main/cookbooks/research/streaming.ipynb) and [polling cookbook](https://github.com/tavily-ai/tavily-cookbook/blob/main/cookbooks/research/polling.ipynb) for complete examples.\n\n---\n\n## Structured Output vs. Report\n\n| Format | Best For |\n|--------|----------|\n| **Report** (default) | Reading, sharing, or displaying verbatim (chat interfaces, briefs, newsletters) |\n| **Structured Output** | Data enrichment, pipelines, or powering UIs with specific fields |\n\n## Structured Output\n\nUse `output_schema` to receive research in a predefined JSON structure.\n\n```python\nschema = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"summary\": {\n            \"type\": \"string\",\n            \"description\": \"Executive summary of findings\"\n        },\n        \"key_points\": {\n            \"type\": \"array\",\n            \"items\": {\"type\": \"string\"},\n            \"description\": \"Main takeaways from the research\"\n        },\n        \"metrics\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"market_size\": {\"type\": \"string\", \"description\": \"Total market size\"},\n                \"growth_rate\": {\"type\": \"number\", \"description\": \"Annual growth percentage\"}\n            }\n        }\n    },\n    \"required\": [\"summary\", \"key_points\"]\n}\n\nresult = client.research(\n    input=\"Electric vehicle market analysis 2024\",\n    output_schema=schema\n)\n```\n\n### Schema Best Practices\n\n- **Write clear field descriptions.** 1-3 sentences explaining what the field should contain\n- **Match the structure you need.** Use arrays, objects, enums appropriately (e.g., `competitors: string[]`, not `\"A, B, C\"`)\n- **Avoid duplicate fields.** Keep each field unique and specific\n- **Use `required` arrays** to enforce mandatory fields at any nesting level\n\n**Supported types:** `object`, `string`, `integer`, `number`, `array`\n\n### Streaming with Structured Output\n\nWhen `output_schema` is provided, content arrives as structured JSON:\n\n```python\nstream = client.research(\n    input=\"AI agent frameworks comparison\",\n    model=\"mini\",\n    stream=True,\n    output_schema={\n        \"type\": \"object\",\n        \"properties\": {\n            \"summary\": {\"type\": \"string\", \"description\": \"Executive summary\"},\n            \"key_points\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n        },\n        \"required\": [\"summary\", \"key_points\"]\n    }\n)\n\nfor chunk in stream:\n    data = chunk.decode('utf-8')\n    print(data)  # Content chunks will be structured JSON\n```\n\n---\n\n## Response Fields\n\n### research() Response\n\n| Field | Description |\n|-------|-------------|\n| `request_id` | Unique identifier for tracking |\n| `created_at` | Timestamp when task was created |\n| `status` | Initial status |\n| `input` | The research topic submitted |\n| `model` | Model used by research agent |\n\n### get_research() Response\n\n| Field | Description |\n|-------|-------------|\n| `status` | `\"pending\"`, `\"processing\"`, `\"completed\"`, `\"failed\"` |\n| `content` | Generated research report (when completed) |\n| `sources` | Array of source citations |\n| `response_time` | Time in seconds |\n\n### Source Object\n\n| Field | Description |\n|-------|-------------|\n| `url` | Source URL |\n| `title` | Source title |\n| `citation` | Formatted citation string |\n\n---\n\n## Summary\n\n1. **Be specific in prompts** — Include known details: target market, competitors, geography, constraints\n2. **Share prior context** — Include what you already know to avoid repetition\n3. **Choose the right model** — `mini` for focused queries, `pro` for comprehensive multi-domain analysis\n4. **Use streaming for UX** — Display real-time progress during long research tasks\n5. **Use structured output for pipelines** — Define schemas for consistent, parseable responses\n6. **Use reports for reading** — Default format is best for chat interfaces and sharing\n\nFor more examples, see the [Tavily Cookbook](https://github.com/tavily-ai/tavily-cookbook/tree/main/research) and [live demo](https://chat-research.tavily.com/).\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/sdk.md",
    "content": "# SDK Reference\n\n## Table of Contents\n\n- [Python SDK](#python-sdk)\n- [JavaScript SDK](#javascript-sdk)\n- [Async Patterns](#async-patterns)\n- [Hybrid RAG](#hybrid-rag)\n\n---\n\n## Python SDK\n\n### Installation\n\n```bash\npip install tavily-python\n```\n\n### Client Initialization\n\n```python\nfrom tavily import TavilyClient\n\n# Uses TAVILY_API_KEY env var (recommended)\nclient = TavilyClient()\n\n# Explicit API key\nclient = TavilyClient(api_key=\"tvly-YOUR_API_KEY\")\n\n# With project tracking\nclient = TavilyClient(api_key=\"tvly-YOUR_API_KEY\", project_id=\"your-project-id\")\n\n# With proxies\nproxies = {\"http\": \"<proxy>\", \"https\": \"<proxy>\"}\nclient = TavilyClient(api_key=\"tvly-YOUR_API_KEY\", proxies=proxies)\n```\n\n### Async Client\n\n```python\nfrom tavily import AsyncTavilyClient\n\nasync_client = AsyncTavilyClient()\n\n# Parallel queries\nimport asyncio\nresponses = await asyncio.gather(\n    async_client.search(\"query 1\"),\n    async_client.search(\"query 2\"),\n    async_client.search(\"query 3\")\n)\n```\n\n### Methods\n\n#### search()\n\n```python\nresponse = client.search(\n    query=\"quantum computing breakthroughs\",\n    search_depth=\"advanced\",      # \"ultra-fast\" | \"fast\" | \"basic\" | \"advanced\"\n    topic=\"general\",              # \"general\" | \"news\" | \"finance\"\n    max_results=10,               # 0-20\n    chunks_per_source=3,          # 1-3, fast/advanced depth only\n    include_answer=False,         # bool | \"basic\" | \"advanced\"\n    include_raw_content=False,    # bool | \"markdown\" | \"text\"\n    include_images=False,\n    include_image_descriptions=False,\n    include_favicon=False,\n    time_range=\"week\",            # \"day\" | \"week\" | \"month\" | \"year\"\n    include_domains=[\"arxiv.org\"],\n    exclude_domains=[\"reddit.com\"],\n    country=\"united states\",\n    exact_match=False,\n    include_usage=False\n)\n```\n\n#### extract()\n\n```python\nresponse = client.extract(\n    urls=[\"https://example.com/page1\", \"https://example.com/page2\"],\n    extract_depth=\"basic\",        # \"basic\" | \"advanced\"\n    format=\"markdown\",            # \"markdown\" | \"text\"\n    query=\"focus query\",          # Reranks chunks by relevance\n    chunks_per_source=3,          # 1-5, requires query\n    include_images=False,\n    include_favicon=False,\n    include_usage=False\n)\n```\n\n#### crawl()\n\n```python\nresponse = client.crawl(\n    url=\"https://docs.example.com\",\n    max_depth=2,                  # 1-5\n    max_breadth=20,               # 1-500\n    limit=50,\n    instructions=\"Find API documentation\",\n    chunks_per_source=3,          # 1-5, requires instructions\n    select_paths=[\"/docs/.*\"],\n    exclude_paths=[\"/blog/.*\"],\n    extract_depth=\"basic\",        # \"basic\" | \"advanced\"\n    format=\"markdown\",            # \"markdown\" | \"text\"\n    allow_external=True,\n    include_images=False,\n    include_favicon=False,\n    timeout=150,                  # 10-150 seconds\n    include_usage=False\n)\n```\n\n#### map()\n\n```python\nresponse = client.map(\n    url=\"https://docs.example.com\",\n    max_depth=2,                  # 1-5\n    max_breadth=20,               # 1-500\n    limit=50,\n    instructions=\"Find all API pages\",\n    select_paths=[\"/api/.*\"],\n    allow_external=False,\n    timeout=150,                  # 10-150 seconds\n    include_usage=False\n)\n```\n\n#### research()\n\n```python\n# Start research task\nresult = client.research(\n    input=\"Analyze competitive landscape for X\",\n    model=\"pro\",                  # \"mini\" | \"pro\" | \"auto\"\n    stream=False,\n    output_schema=None,           # JSON schema for structured output\n    citation_format=\"numbered\"    # \"numbered\" | \"mla\" | \"apa\" | \"chicago\"\n)\n\n# Poll for results\nimport time\nresponse = client.get_research(result[\"request_id\"])\nwhile response[\"status\"] not in [\"completed\", \"failed\"]:\n    time.sleep(10)\n    response = client.get_research(result[\"request_id\"])\n```\n\n---\n\n## JavaScript SDK\n\n### Installation\n\n```bash\nnpm install @tavily/core\n```\n\n### Client Initialization\n\n```javascript\nconst { tavily } = require(\"@tavily/core\");\n\n// Basic initialization\nconst client = tavily({ apiKey: \"tvly-YOUR_API_KEY\" });\n\n// With project tracking\nconst client = tavily({\n  apiKey: \"tvly-YOUR_API_KEY\",\n  projectId: \"your-project-id\"\n});\n\n// With proxies\nconst client = tavily({\n  apiKey: \"tvly-YOUR_API_KEY\",\n  proxies: {\n    http: \"<proxy>\",\n    https: \"<proxy>\"\n  }\n});\n```\n\n### Methods\n\n#### search()\n\n```javascript\nconst response = await client.search(\"quantum computing\", {\n  searchDepth: \"advanced\",      // \"ultra-fast\" | \"fast\" | \"basic\" | \"advanced\"\n  topic: \"general\",             // \"general\" | \"news\" | \"finance\"\n  maxResults: 10,               // 0-20\n  chunksPerSource: 3,           // 1-3, fast/advanced depth only\n  includeAnswer: false,         // boolean | \"basic\" | \"advanced\"\n  includeRawContent: false,     // boolean | \"markdown\" | \"text\"\n  includeImages: false,\n  includeImageDescriptions: false,\n  includeFavicon: false,\n  timeRange: \"week\",            // \"day\" | \"week\" | \"month\" | \"year\"\n  includeDomains: [\"arxiv.org\"],\n  excludeDomains: [\"reddit.com\"],\n  country: \"united states\",\n  exactMatch: false,\n  includeUsage: false\n});\n```\n\n#### extract()\n\n```javascript\nconst response = await client.extract([\n  \"https://example.com/page1\",\n  \"https://example.com/page2\"\n], {\n  extractDepth: \"basic\",        // \"basic\" | \"advanced\"\n  format: \"markdown\",           // \"markdown\" | \"text\"\n  query: \"focus query\",         // Reranks chunks\n  chunksPerSource: 3,           // 1-5, requires query\n  includeImages: false,\n  includeFavicon: false,\n  includeUsage: false\n});\n```\n\n#### crawl()\n\n```javascript\nconst response = await client.crawl(\"https://docs.example.com\", {\n  maxDepth: 2,                  // 1-5\n  maxBreadth: 20,               // 1-500\n  limit: 50,\n  instructions: \"Find API documentation\",\n  chunksPerSource: 3,           // 1-5, requires instructions\n  selectPaths: [\"/docs/.*\"],\n  excludePaths: [\"/blog/.*\"],\n  extractDepth: \"basic\",        // \"basic\" | \"advanced\"\n  format: \"markdown\",           // \"markdown\" | \"text\"\n  allowExternal: true,\n  includeImages: false,\n  includeFavicon: false,\n  timeout: 150,                 // 10-150 seconds\n  includeUsage: false\n});\n```\n\n#### map()\n\n```javascript\nconst response = await client.map(\"https://docs.example.com\", {\n  maxDepth: 2,                  // 1-5\n  maxBreadth: 20,               // 1-500\n  limit: 50,\n  instructions: \"Find all API pages\",\n  selectPaths: [\"/api/.*\"],\n  allowExternal: false,\n  timeout: 150,                 // 10-150 seconds\n  includeUsage: false\n});\n```\n\n---\n\n## Async Patterns\n\n### Python Parallel Queries\n\n```python\nimport asyncio\nfrom tavily import AsyncTavilyClient\n\nclient = AsyncTavilyClient()\n\nasync def parallel_search():\n    queries = [\n        \"AI trends 2025\",\n        \"machine learning best practices\",\n        \"LLM deployment strategies\"\n    ]\n\n    responses = await asyncio.gather(\n        *(client.search(q, search_depth=\"advanced\") for q in queries),\n        return_exceptions=True\n    )\n\n    for query, response in zip(queries, responses):\n        if isinstance(response, Exception):\n            print(f\"Failed: {query}\")\n        else:\n            print(f\"{query}: {len(response['results'])} results\")\n\nasyncio.run(parallel_search())\n```\n\n### JavaScript Parallel Queries\n\n```javascript\nconst queries = [\"AI trends\", \"ML practices\", \"LLM strategies\"];\n\nconst responses = await Promise.all(\n  queries.map(q => client.search(q, { searchDepth: \"advanced\" }))\n);\n\nresponses.forEach((response, i) => {\n  console.log(`${queries[i]}: ${response.results.length} results`);\n});\n```\n\n---\n\n## Hybrid RAG\n\nCombine web search with local database retrieval.\n\n### Python\n\n```python\nfrom tavily import TavilyHybridClient\nfrom pymongo import MongoClient\n\n# Connect to MongoDB\ndb = MongoClient(\"mongodb+srv://URI\")[\"DB_NAME\"]\n\n# Initialize hybrid client\nhybrid_client = TavilyHybridClient(\n    api_key=\"tvly-YOUR_API_KEY\",\n    db_provider=\"mongodb\",\n    collection=db.get_collection(\"documents\"),\n    embeddings_field=\"embeddings\",\n    content_field=\"content\"\n)\n\n# Search across web + local DB\nresults = hybrid_client.search(\n    query=\"quantum computing advances\",\n    max_results=10,\n    max_local=5,      # Results from local DB\n    max_foreign=5,    # Results from web\n    save_foreign=True # Store web results in DB\n)\n```\n\n**Environment Variables:**\n- `TAVILY_PROJECT`: Default project ID\n- `TAVILY_HTTP_PROXY` / `TAVILY_HTTPS_PROXY`: Proxy configuration\n- `CO_API_KEY`: Cohere API key for embeddings\n\n---\n\n## Response Structures\n\n### Search Response\n\n```python\n{\n    \"query\": str,\n    \"results\": [\n        {\n            \"title\": str,\n            \"url\": str,\n            \"content\": str,\n            \"score\": float,\n            \"favicon\": str\n        }\n    ],\n    \"response_time\": float,\n    \"request_id\": str,\n    \"answer\": str,      # if include_answer\n    \"images\": list      # if include_images\n}\n```\n\n### Extract Response\n\n```python\n{\n    \"results\": [\n        {\n            \"url\": str,\n            \"raw_content\": str,\n            \"images\": list,\n            \"favicon\": str\n        }\n    ],\n    \"failed_results\": [\n        {\"url\": str, \"error\": str}\n    ],\n    \"response_time\": float,\n    \"request_id\": str\n}\n```\n\n### Crawl Response\n\n```python\n{\n    \"base_url\": str,\n    \"results\": [\n        {\n            \"url\": str,\n            \"raw_content\": str,\n            \"images\": list,\n            \"favicon\": str\n        }\n    ],\n    \"response_time\": float,\n    \"request_id\": str\n}\n```\n\n### Map Response\n\n```python\n{\n    \"base_url\": str,\n    \"results\": [str],  # List of URLs\n    \"response_time\": float,\n    \"request_id\": str\n}\n```\n\n---\n\nFor full API documentation, see:\n- [Python SDK Reference](https://docs.tavily.com/sdk/python/reference)\n- [JavaScript SDK Reference](https://docs.tavily.com/sdk/javascript/reference)\n"
  },
  {
    "path": "content/tavily/skills/tavily-best-practices/references/search.md",
    "content": "# Search API Reference\n\n## Table of Contents\n\n- [Query Optimization](#query-optimization)\n- [Search Depth](#search-depth)\n- [Key Parameters](#key-parameters)\n- [Basic Usage](#basic-usage)\n- [Filtering Results](#filtering-results)\n- [Async Patterns](#async-patterns)\n- [Response Fields](#response-fields)\n- [Post-Filtering Strategies](#post-filtering-strategies)\n\n---\n\n## Query Optimization\n\n**Keep queries under 400 characters.** Think search query, not long-form prompt.\n\n**Break complex queries into sub-queries:**\n```python\n# Instead of one massive query, break it down:\nqueries = [\n    \"Competitors of company ABC\",\n    \"Financial performance of company ABC\",\n    \"Recent developments of company ABC\"\n]\nresponses = await asyncio.gather(*(client.search(q) for q in queries))\n```\n\n## Search Depth\n\nControls the latency vs. relevance tradeoff:\n\n| Depth | Latency | Relevance | Content Type |\n|-------|---------|-----------|--------------|\n| `ultra-fast` | Lowest | Lower | Content (NLP summary) |\n| `fast` | Low | Good | Chunks |\n| `basic` | Medium | High | Content (NLP summary) |\n| `advanced` | Higher | Highest | Chunks |\n\n**Content types:**\n- **Content**: NLP-based summary of the page, providing general context\n- **Chunks**: Short snippets (max 500 chars) reranked by relevance to your query\n\n**When to use each:** \n- `ultra-fast`: Latency-critical (real-time chat, autocomplete)\n- `fast`: Need chunks but latency matters\n- `basic`: General-purpose, balanced relevance and latency\n- `advanced`: Specific information queries, precision matters (still fast and suitable for almost all use cases) \n\n## Key Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `query` | string | Required | Search query (keep under 400 chars) |\n| `search_depth` | enum | `\"basic\"` | `\"ultra-fast\"`, `\"fast\"`, `\"basic\"`, `\"advanced\"` |\n| `topic` | enum | `\"general\"` | `\"general\"`, `\"news\"`, or `\"finance\"` |\n| `chunks_per_source` | integer | 3 | Chunks per source (1–3, fast/advanced depth only) |\n| `max_results` | integer | 5 | Maximum results (0-20) |\n| `time_range` | enum | null | `\"day\"`, `\"week\"`, `\"month\"`, `\"year\"` |\n| `start_date` | string | null | Results after date (YYYY-MM-DD) |\n| `end_date` | string | null | Results before date (YYYY-MM-DD) |\n| `include_domains` | array | [] | Domains to include (max 300, supports wildcards like `*.com`) |\n| `exclude_domains` | array | [] | Domains to exclude (max 150) |\n| `country` | enum | null | Boost results from country (general topic only) |\n| `include_answer` | bool/enum | false | `true`/`\"basic\"` or `\"advanced\"` for LLM answer |\n| `include_raw_content` | bool/enum | false | `true`/`\"markdown\"` or `\"text\"` for full page |\n| `include_images` | boolean | false | Include image results |\n| `include_image_descriptions` | boolean | false | AI descriptions for images |\n| `include_favicon` | boolean | false | Favicon URL per result |\n| `auto_parameters` | boolean | false | Auto-configure based on query intent |\n| `exact_match` | boolean | false | Require exact quoted phrases in results |\n| `include_usage` | boolean | false | Include credit usage info |\n\n**Notes:**\n\n- **`include_answer`**: Only use if you don't want to bring your own LLM. Most users bring their own model.\n\n- **`auto_parameters`**: May set `search_depth=\"advanced\"` (2 credits). Set `search_depth` manually to control cost.\n\n\n## Basic Usage\n\n```python\nfrom tavily import TavilyClient\n\nclient = TavilyClient()\n\nresponse = client.search(\n    query=\"latest developments in quantum computing\",\n    max_results=10,\n    search_depth=\"advanced\",\n    chunks_per_source=5\n)\n\nfor result in response[\"results\"]:\n    print(f\"{result['title']}: {result['url']}\")\n    print(f\"Score: {result['score']}\")\n```\n\n\n## Filtering Results\n\n### By domain\n\n```python\n# Only search trusted sources\nresponse = client.search(\n    query=\"machine learning best practices\",\n    include_domains=[\"arxiv.org\", \"github.com\", \"pytorch.org\"],\n)\n\n# Exclude specific domains\nresponse = client.search(\n    query=\"openai product reviews\",\n    exclude_domains=[\"reddit.com\", \"quora.com\"]\n)\n\n# Restrict to LinkedIn profiles\nresponse = client.search(\n    query=\"CEO background at Google\",\n    include_domains=[\"linkedin.com/in\"]\n)\n```\n\n### By date\n\n```python\n# Relative time range\nresponse = client.search(query=\"latest ML trends\", time_range=\"month\")\n\n# Specific date range\nresponse = client.search(\n    query=\"AI news\",\n    start_date=\"2025-01-01\",\n    end_date=\"2025-02-01\"\n)\n```\n\n### By country\n\n```python\n# Boost results from specific country\nresponse = client.search(query=\"tech startup funding\", country=\"united states\")\n```\n\n## Async Patterns\n\nLeveraging the async client enables scaled search with higher breadth and reach by running multiple queries in parallel. This is the best practice for agentic systems where you need to gather comprehensive information quickly before passing it to a model for analysis.\n\n```python\nimport asyncio\nfrom tavily import AsyncTavilyClient\n\n# Initialize Tavily client\ntavily_client = AsyncTavilyClient(\"tvly-YOUR_API_KEY\")\n\nasync def fetch_and_gather():\n    queries = [\"latest AI trends\", \"future of quantum computing\"]\n\n    # Perform search and continue even if one query fails (using return_exceptions=True)\n    try:\n        responses = await asyncio.gather(*(tavily_client.search(q) for q in queries), return_exceptions=True)\n\n        # Handle responses and print\n        for response in responses:\n            if isinstance(response, Exception):\n                print(f\"Search query failed: {response}\")\n            else:\n                print(response)\n\n    except Exception as e:\n        print(f\"Error during search queries: {e}\")\n\n# Run the function\nasyncio.run(fetch_and_gather())\n```\n\n\n## Response Fields\n\n**Top-level response:**\n\n| Field | Description |\n|-------|-------------|\n| `query` | The original search query |\n| `answer` | AI-generated answer (if `include_answer` enabled) |\n| `results` | Array of search result objects |\n| `images` | Array of image results (if `include_images=True`) |\n\n**Each result object:**\n\n| Field | Description |\n|-------|-------------|\n| `title` | Page title |\n| `url` | Source URL |\n| `content` | Extracted text snippet(s) |\n| `score` | Semantic relevance score (0-1) |\n| `raw_content` | Full page content (if `include_raw_content` enabled) |\n| `favicon` | Favicon URL (if `include_favicon=True`) |\n\n**Top-level response also includes:**\n\n| Field | Description |\n|-------|-------------|\n| `request_id` | Unique identifier for support reference |\n| `response_time` | Response time in seconds |\n\n**Each image object (if `include_images=True`):**\n\n| Field | Description |\n|-------|-------------|\n| `url` | Image URL |\n| `description` | AI-generated description (if `include_image_descriptions=True`) |\n\n---\n\n## Post-Filtering Strategies\n\nSince Tavily provides raw web data, you have full configurability to implement filtering and post-processing to meet your specific requirements.\n\nThe `score` field measures query relevance, but doesn't guarantee the result matches specific criteria (e.g., correct person, exact product, specific company). Use post-filtering to validate results against strict requirements.\n\n### Score-Based Filtering\n\nSimple threshold filtering based on relevance score:\n\n```python\nresults = response[\"results\"]\n\n# Filter by score threshold\nhigh_quality = [r for r in results if r[\"score\"] > 0.7]\n\n# Sort by score\nsorted_results = sorted(results, key=lambda x: x[\"score\"], reverse=True)\n\n# Top N above threshold\ntop_relevant = sorted(\n    [r for r in results if r[\"score\"] > 0.5],\n    key=lambda x: x[\"score\"],\n    reverse=True\n)[:3]\n```\n\n**Limitation:** Score indicates relevance to query, not accuracy of match to specific criteria.\n\n### Regex Filtering\n\nFast, deterministic filtering using pattern matching. Use for:\n- URL pattern validation\n- Required keywords/phrases\n- Structural requirements\n\n```python\nimport re\n\ndef regex_filter(result, criteria: dict) -> dict:\n    \"\"\"\n    Filter a search result using regex checks.\n\n    Args:\n        result: Search result dict with url, content, title, raw_content\n        criteria: Dict with patterns to match:\n            - url_pattern: Regex for URL validation\n            - required_terms: List of terms that must appear in content\n            - excluded_terms: List of terms that must NOT appear\n\n    Returns:\n        dict with check results and validity\n    \"\"\"\n    url = result.get(\"url\", \"\")\n    content = result.get(\"content\", \"\") or \"\"\n    title = result.get(\"title\", \"\") or \"\"\n    raw_content = result.get(\"raw_content\", \"\") or \"\"\n\n    full_text = f\"{content} {title} {raw_content}\".lower()\n\n    checks = {}\n\n    # URL pattern check\n    if \"url_pattern\" in criteria:\n        checks[\"url_valid\"] = bool(re.search(criteria[\"url_pattern\"], url.lower()))\n\n    # Required terms check\n    if \"required_terms\" in criteria:\n        checks[\"required_found\"] = all(\n            re.search(re.escape(term.lower()), full_text)\n            for term in criteria[\"required_terms\"]\n        )\n\n    # Excluded terms check\n    if \"excluded_terms\" in criteria:\n        checks[\"excluded_absent\"] = not any(\n            re.search(re.escape(term.lower()), full_text)\n            for term in criteria[\"excluded_terms\"]\n        )\n\n    # Valid if all checks pass\n    is_valid = all(checks.values()) if checks else True\n\n    return {\"checks\": checks, \"is_valid\": is_valid, \"url\": url}\n```\n\n**Example: LinkedIn Profile Search**\n\n```python\ncriteria = {\n    \"url_pattern\": r\"linkedin\\.com/in/\",  # Profile URL, not company page\n    \"required_terms\": [\"Jane Smith\", \"Acme Corp\"],\n    \"excluded_terms\": [\"job posting\", \"careers\"]\n}\n\nfor result in response[\"results\"]:\n    validation = regex_filter(result, criteria)\n    if validation[\"is_valid\"]:\n        print(f\"Valid: {validation['url']}\")\n```\n\n**Example: GitHub Repository Search**\n\n```python\ncriteria = {\n    \"url_pattern\": r\"github\\.com/[\\w-]+/[\\w-]+$\",  # Repo URL, not file\n    \"required_terms\": [\"MIT License\"],\n    \"excluded_terms\": [\"archived\", \"deprecated\"]\n}\n```\n\n### LLM Verification\n\nSemantic validation using an LLM. Use for:\n- Synonym/abbreviation matching (\"FDE\" = \"Forward Deployed Engineer\")\n- Context-aware validation\n- Confidence scoring with reasoning\n\n```python\nfrom openai import OpenAI\nimport json\n\ndef llm_verify(result, target_description: str, validation_criteria: list[str]) -> dict:\n    \"\"\"\n    Use LLM to verify if a search result matches target criteria.\n\n    Args:\n        result: Search result dict\n        target_description: What you're looking for\n        validation_criteria: List of criteria to check\n\n    Returns:\n        dict with is_match, confidence (high/medium/low), reasoning\n    \"\"\"\n    content = result.get(\"content\", \"\") or \"\"\n    title = result.get(\"title\", \"\") or \"\"\n    url = result.get(\"url\", \"\")\n\n    criteria_text = \"\\n\".join(f\"- {c}\" for c in validation_criteria)\n\n    prompt = f\"\"\"Verify if this search result matches the target.\n\nTarget: {target_description}\n\nValidation Criteria:\n{criteria_text}\n\nSearch Result:\nURL: {url}\nTitle: {title}\nContent: {content}\n\nDoes this result match ALL criteria?\n\nRespond with JSON only:\n{{\"is_match\": true/false, \"confidence\": \"high/medium/low\", \"reasoning\": \"brief explanation\"}}\"\"\"\n\n    client = OpenAI()\n    response = client.chat.completions.create(\n        model=\"gpt-4o-mini\",\n        messages=[{\"role\": \"user\", \"content\": prompt}],\n        response_format={\"type\": \"json_object\"}\n    )\n\n    return json.loads(response.choices[0].message.content)\n```\n\n**Example: Profile Verification**\n\n```python\nresult = llm_verify(\n    result=search_result,\n    target_description=\"Jane Smith, Software Engineer at Acme Corp\",\n    validation_criteria=[\n        \"Name matches Jane Smith\",\n        \"Currently works at Acme Corp (or recently)\",\n        \"Role is software engineering related\",\n        \"Professional customer-facing experience\"\n    ]\n)\n\nif result[\"is_match\"] and result[\"confidence\"] in [\"high\", \"medium\"]:\n    print(f\"Verified: {result['reasoning']}\")\n```\n\nFor more details, please read the [full API reference](https://docs.tavily.com/documentation/api-reference/endpoint/search)"
  },
  {
    "path": "content/tenacity/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Tenacity retrying library for Python with decorator, Retrying, and AsyncRetrying patterns\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.1.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tenacity,retry,retries,backoff,async,resilience\"\n---\n\n# Tenacity Python Package Guide\n\n## Golden Rule\n\nUse `tenacity` with an explicit retry policy. A bare `@retry` retries forever with no wait between attempts, which is usually the wrong production default. In practice, specify `stop=...`, `wait=...`, and usually `reraise=True`.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"tenacity==9.1.4\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"tenacity==9.1.4\"\npoetry add \"tenacity==9.1.4\"\n```\n\nPyPI also publishes `doc` and `test` extras, but normal application use does not need them.\n\n## Core Usage\n\n### Retry flaky exceptions with bounded attempts and backoff\n\n```python\nfrom tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_random_exponential\n\nclass TransientError(Exception):\n    pass\n\n@retry(\n    retry=retry_if_exception_type(TransientError),\n    stop=stop_after_attempt(5),\n    wait=wait_random_exponential(multiplier=1, max=30),\n    reraise=True,\n)\ndef fetch_data() -> str:\n    value = call_remote_service()\n    if value is None:\n        raise TransientError(\"empty response\")\n    return value\n```\n\nUse this pattern for network or service-call retries. `reraise=True` makes the final failure raise the original exception instead of `RetryError`.\n\n### Retry on returned results, not only exceptions\n\n```python\nfrom tenacity import retry, retry_if_result, stop_after_attempt, wait_fixed\n\n@retry(\n    retry=retry_if_result(lambda value: value is None),\n    stop=stop_after_attempt(3),\n    wait=wait_fixed(1),\n    reraise=True,\n)\ndef read_from_cache_or_peer() -> str | None:\n    return maybe_get_value()\n```\n\nUse `retry_if_result(...)` when the function succeeds technically but returns an unacceptable value such as `None`, `False`, or an incomplete payload.\n\n### Trigger a retry explicitly with `TryAgain`\n\n```python\nfrom tenacity import TryAgain, retry, stop_after_attempt, wait_fixed\n\n@retry(stop=stop_after_attempt(4), wait=wait_fixed(0.5), reraise=True)\ndef poll_until_ready() -> dict:\n    payload = get_status()\n    if payload[\"state\"] != \"ready\":\n        raise TryAgain\n    return payload\n```\n\n`TryAgain` is useful when you want retry behavior without manufacturing a fake exception type.\n\n### Retry a shared code block with `Retrying`\n\nUse `Retrying(...)` when you do not want to wrap the whole function:\n\n```python\nfrom tenacity import Retrying, stop_after_attempt, wait_fixed\n\nfor attempt in Retrying(stop=stop_after_attempt(3), wait=wait_fixed(1), reraise=True):\n    with attempt:\n        response = call_remote_service()\n        validate_response(response)\n```\n\nThis is useful inside larger functions where only one block should be retried.\n\n### Async retries with `AsyncRetrying`\n\n```python\nfrom tenacity import AsyncRetrying, retry_if_exception_type, stop_after_attempt, wait_fixed\n\nclass TemporaryAPIError(Exception):\n    pass\n\nasync def fetch_json() -> dict:\n    async for attempt in AsyncRetrying(\n        retry=retry_if_exception_type(TemporaryAPIError),\n        stop=stop_after_attempt(5),\n        wait=wait_fixed(1),\n        reraise=True,\n    ):\n        with attempt:\n            return await call_async_api()\n\n    raise RuntimeError(\"unreachable\")\n```\n\nFor async block retries, use `async for attempt in AsyncRetrying(...)`. Do not use the synchronous `for` pattern in async code.\n\n## Policy Building Blocks\n\nTenacity policies are built from a few composable pieces:\n\n- `stop=...`: when to give up, such as `stop_after_attempt(5)`, `stop_after_delay(30)`, or `stop_before_delay(30)`\n- `wait=...`: how long to sleep, such as `wait_fixed(1)`, `wait_exponential(...)`, or `wait_random_exponential(...)`\n- `retry=...`: what should trigger another attempt, such as `retry_if_exception_type(...)` or `retry_if_result(...)`\n- `before=...`, `after=...`, `before_sleep=...`: hooks for logging or instrumentation\n- `retry_error_callback=...`: return a fallback value after final failure instead of raising\n- `retry_with(...)`: override a decorated function's retry settings per call\n\nExample: combine hard bounds with jitter:\n\n```python\nfrom tenacity import retry, stop_after_attempt, stop_after_delay, wait_fixed, wait_random\n\n@retry(\n    stop=stop_after_delay(20) | stop_after_attempt(5),\n    wait=wait_fixed(1) + wait_random(0, 2),\n    reraise=True,\n)\ndef write_with_backoff() -> None:\n    store_record()\n```\n\n`wait_random_exponential(...)` is usually the better default for distributed services. Fixed waits are more appropriate for short local polling loops.\n\n## Logging, Fallbacks, And Per-Call Overrides\n\nAdd logging before each sleep:\n\n```python\nimport logging\n\nfrom tenacity import before_sleep_log, retry, stop_after_attempt, wait_fixed\n\nlogger = logging.getLogger(__name__)\n\n@retry(\n    stop=stop_after_attempt(3),\n    wait=wait_fixed(1),\n    before_sleep=before_sleep_log(logger, logging.WARNING),\n    reraise=True,\n)\ndef call_with_logs() -> None:\n    do_work()\n```\n\nReturn a fallback instead of raising:\n\n```python\nfrom tenacity import retry, retry_if_result, stop_after_attempt\n\ndef return_last_value(retry_state):\n    return retry_state.outcome.result()\n\n@retry(\n    stop=stop_after_attempt(3),\n    retry=retry_if_result(lambda value: value is None),\n    retry_error_callback=return_last_value,\n)\ndef eventually_returns_none() -> str | None:\n    return None\n```\n\nOverride policy at the call site:\n\n```python\nresult = fetch_data.retry_with(stop=stop_after_attempt(2))()\n```\n\nThis is useful in tests or in short-lived CLI commands where you want fewer retries than production.\n\n## Configuration And Auth\n\nTenacity is a local utility library. There is no auth flow, client initialization, or environment-variable contract that the package requires at runtime.\n\nConfiguration lives in Python code:\n\n- choose retry conditions explicitly\n- choose backoff and jitter explicitly\n- decide whether final failure should raise or return a fallback\n- attach logging or metrics callbacks where you need them\n\nFor shared application defaults, wrap Tenacity in your own helper decorator or helper function so the retry policy stays consistent across the codebase.\n\n## Common Pitfalls\n\n- Bare `@retry` retries forever with no waiting. Always bound retries in production code.\n- If you omit `reraise=True`, final failure usually raises `RetryError` instead of the original exception.\n- Do not retry broad exceptions unless you are sure they are transient. Restrict the retry predicate to the failures you actually want to recover from.\n- Prefer exponential backoff plus jitter for remote services; constant one-second polling is a thundering-herd footgun.\n- When retrying async blocks, use `AsyncRetrying` and `async for`; older snippets that behave synchronously are stale.\n- If you use `retry_if_result(...)` with `Retrying` or `AsyncRetrying` code blocks, set the attempt result explicitly with `attempt.retry_state.set_result(result)` after the block succeeds.\n- `retry_with(...)` is good for per-call overrides; do not duplicate multiple decorators just to change attempt counts in tests.\n- Some older Tenacity examples on the web show a direct `.statistics` attribute on the wrapped function. The 9.0.0 release notes call out an API breakage around statistics, and current official docs surfaces are inconsistent, so verify the access pattern against the installed version before relying on it.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `9.1.4` as the latest release, published on February 7, 2026.\n- PyPI metadata currently requires Python `>=3.10`.\n- The Read the Docs changelog page currently only shows up to the `8.2.x` series even though PyPI and GitHub releases include `9.x`. For recent changes, check PyPI release history and GitHub releases in addition to the docs site.\n- The `9.0.0` GitHub release explicitly warns about API breakage on the statistics attribute. Re-check any statistics or instrumentation snippets copied from older articles or older Tenacity docs.\n\n## Official Sources\n\n- Docs root: `https://tenacity.readthedocs.io/en/latest/`\n- API reference: `https://tenacity.readthedocs.io/en/latest/api.html`\n- Changelog: `https://tenacity.readthedocs.io/en/latest/changelog.html`\n- PyPI: `https://pypi.org/project/tenacity/`\n- Releases: `https://github.com/jd/tenacity/releases`\n"
  },
  {
    "path": "content/tensorflow/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"TensorFlow Python package guide for installing, configuring, training, and exporting models with TensorFlow 2.21.0\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.21.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"tensorflow,machine-learning,deep-learning,keras,tf.data,gpu\"\n---\n\n# TensorFlow Python Package Guide\n\n## Golden Rule\n\nUse the `tensorflow` PyPI package for TensorFlow 2.x work, install from PyPI with `pip`, and verify platform support before assuming GPU behavior.\n\nFor package version `2.21.0`, PyPI is the best version anchor. The official TensorFlow install and API pages are useful, but parts of the site still show older version labels.\n\n## Installation\n\nTensorFlow officially recommends installing from PyPI with `pip`, not `conda`.\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install tensorflow==2.21.0\n```\n\n### Optional extras\n\nInstall the base package unless you specifically need an extra:\n\n```bash\npython -m pip install \"tensorflow[and-cuda]==2.21.0\"\npython -m pip install \"tensorflow[gcs-filesystem]==2.21.0\"\n```\n\n- `and-cuda`: CUDA-enabled Linux install path published by TensorFlow.\n- `gcs-filesystem`: add the Google Cloud Storage filesystem integration when your input pipeline reads from GCS.\n\n### Verify the install\n\n```bash\npython - <<'PY'\nimport tensorflow as tf\nprint(tf.__version__)\nprint(tf.config.list_physical_devices(\"GPU\"))\nPY\n```\n\n## Platform And Version Notes\n\n- PyPI for `2.21.0` says `Requires: Python >=3.10` and publishes wheels for Python `3.10` through `3.13`.\n- The TensorFlow install page explicitly warns that Python `3.9` is not supported as of TensorFlow `2.21`.\n- Native Windows GPU support ended at TensorFlow `2.10`. For `2.21.0`, use WSL2 if you need GPU acceleration on Windows.\n- macOS has no official GPU support on the TensorFlow install page. Treat macOS as CPU-only unless you have a separate Apple-specific stack you already know you need.\n- On Linux ARM64, installing `tensorflow` can resolve to AWS-maintained CPU wheels (`tensorflow-cpu-aws`), so do not assume the same wheel provenance as x86 Linux.\n- The public TensorFlow Python API site currently renders as `v2.16.1`, even though PyPI has `2.21.0`. Use PyPI and the install matrix as the version source of truth for packaging decisions.\n\n## Initialization And Basic Setup\n\nStart with a plain import and device check:\n\n```python\nimport tensorflow as tf\n\nprint(tf.__version__)\nprint(tf.config.list_physical_devices(\"CPU\"))\nprint(tf.config.list_physical_devices(\"GPU\"))\n```\n\nIf you want to limit TensorFlow to one GPU, or enable memory growth, do it before the runtime initializes the devices:\n\n```python\nimport tensorflow as tf\n\ngpus = tf.config.list_physical_devices(\"GPU\")\nif gpus:\n    tf.config.set_visible_devices(gpus[0], \"GPU\")\n    tf.config.experimental.set_memory_growth(gpus[0], True)\n```\n\nIf you call `set_visible_devices()` or `set_memory_growth()` after TensorFlow has already initialized the GPU, TensorFlow raises a runtime error.\n\n## Core Usage\n\n### Tensors, variables, and autodiff\n\nUse `tf.Tensor` for values and `tf.Variable` for mutable state such as trainable weights.\n\n```python\nimport tensorflow as tf\n\nx = tf.constant([[1.0, 2.0], [3.0, 4.0]])\nw = tf.Variable([[0.5], [1.0]])\n\nwith tf.GradientTape() as tape:\n    y = tf.matmul(x, w)\n    loss = tf.reduce_sum(y)\n\ngrads = tape.gradient(loss, [w])\nprint(y)\nprint(grads[0])\n```\n\nUse `GradientTape` when you need a custom training step or want direct control over differentiation.\n\n### Build datasets with `tf.data`\n\nUse `tf.data.Dataset` as the default input pipeline abstraction.\n\n```python\nimport tensorflow as tf\n\nfeatures = tf.random.normal((1000, 10))\nlabels = tf.random.uniform((1000,), maxval=2, dtype=tf.int32)\n\ndataset = tf.data.Dataset.from_tensor_slices((features, labels))\ndataset = dataset.shuffle(1000).batch(32).prefetch(tf.data.AUTOTUNE)\n\nfor batch_x, batch_y in dataset.take(1):\n    print(batch_x.shape, batch_y.shape)\n```\n\nUseful defaults for training pipelines:\n\n- use `from_tensor_slices()` for in-memory arrays and tensors\n- use `map()` for preprocessing\n- use `batch()` before `fit()`\n- end the pipeline with `prefetch(tf.data.AUTOTUNE)`\n- add `num_parallel_calls=tf.data.AUTOTUNE` to expensive `map()` or `interleave()` stages when input work is CPU- or I/O-bound\n\n### Train a Keras model\n\nFor standard supervised training, `tf.keras` is the fastest path from data to a working model.\n\n```python\nimport tensorflow as tf\n\nmodel = tf.keras.Sequential(\n    [\n        tf.keras.layers.Input(shape=(10,)),\n        tf.keras.layers.Dense(64, activation=\"relu\"),\n        tf.keras.layers.Dense(1, activation=\"sigmoid\"),\n    ]\n)\n\nmodel.compile(\n    optimizer=\"adam\",\n    loss=\"binary_crossentropy\",\n    metrics=[\"accuracy\"],\n)\n\nfeatures = tf.random.normal((1000, 10))\nlabels = tf.cast(tf.random.uniform((1000,), maxval=2, dtype=tf.int32), tf.float32)\ndataset = (\n    tf.data.Dataset.from_tensor_slices((features, labels))\n    .shuffle(1000)\n    .batch(32)\n    .prefetch(tf.data.AUTOTUNE)\n)\n\nhistory = model.fit(dataset, epochs=3)\n```\n\nUse `Sequential` only for a plain stack of single-input, single-output layers. Switch to the Functional API or subclassing for multiple inputs, multiple outputs, shared layers, or non-linear topology.\n\n### Compile hot paths with `tf.function`\n\nWrap stable tensor-heavy code in `@tf.function` when you need graph execution and reduced Python overhead.\n\n```python\nimport tensorflow as tf\n\n@tf.function(reduce_retracing=True)\ndef score_batch(x):\n    return tf.reduce_sum(x, axis=-1)\n\nprint(score_batch(tf.ones((4, 8))))\n```\n\n`tf.function` can retrace when shapes, dtypes, or Python arguments vary. Prefer tensor inputs, consistent shapes, and `reduce_retracing=True` when you expect some input variation.\n\n### Save and export models\n\nFor Keras models, prefer the high-level `.keras` format for normal save/load workflows:\n\n```python\nmodel.save(\"classifier.keras\")\nreloaded = tf.keras.models.load_model(\"classifier.keras\")\n```\n\nUse `SavedModel` export when you need a serving artifact:\n\n```python\nmodel.export(\"exported_model\")\n```\n\nIf you are working with lower-level TensorFlow modules instead of Keras models:\n\n```python\nimport tensorflow as tf\n\nclass Doubler(tf.Module):\n    @tf.function\n    def __call__(self, x):\n        return x * 2\n\nmodule = Doubler()\ntf.saved_model.save(module, \"saved_module\")\nloaded = tf.saved_model.load(\"saved_module\")\nprint(loaded(tf.constant([1, 2, 3])))\n```\n\n## Configuration And External Access\n\nTensorFlow itself does not require package-level authentication.\n\n- Local tensors, local files, and local training require no auth setup.\n- Authentication only matters when your pipeline touches external systems such as cloud storage, model registries, or hosted serving systems.\n- If you need Google Cloud Storage access from TensorFlow file APIs, install the `gcs-filesystem` extra and configure your cloud credentials outside TensorFlow using the normal provider flow for that environment.\n\n## Common Pitfalls\n\n- Do not assume the docs site version label matches the PyPI package version. For this package, the API site is still labeled `v2.16.1` while PyPI has `2.21.0`.\n- Do not use `conda` as the primary install path for current stable TensorFlow. TensorFlow explicitly recommends `pip` because official releases land on PyPI.\n- Do not configure visible GPUs or memory growth after the first TensorFlow GPU call.\n- Do not use `tf.Tensor` when you need mutation. Use `tf.Variable` for trainable or mutable state.\n- Do not overuse `@tf.function` on code with highly variable Python arguments; retracing can erase the expected performance benefit.\n- Do not use `Sequential` for branching or multi-input models.\n- Do not assume native Windows GPU support exists for TensorFlow `2.21.0`; it does not.\n- Do not default to `SavedModel` for ordinary Keras checkpointing. TensorFlow’s SavedModel guide recommends the newer `.keras` format plus `tf.keras.Model.export()` for Keras objects.\n\n## Version-Sensitive Notes For `2.21.0`\n\n- PyPI shows `2.21.0` released on `2026-03-06`.\n- PyPI metadata for `2.21.0` requires Python `>=3.10`.\n- The install matrix on TensorFlow.org shows `2.21.0` wheels for Python `3.10` to `3.13`.\n- The public API reference currently still renders under TensorFlow `v2.16.1`, so newer symbols or packaging details may lag there.\n- The install page warns that Python `3.9` is no longer supported as of TensorFlow `2.21`.\n\n## Official Sources Used\n\n- TensorFlow install guide: https://www.tensorflow.org/install/pip\n- TensorFlow Python API root: https://www.tensorflow.org/api_docs/python/\n- TensorFlow basics guide: https://www.tensorflow.org/guide/basics\n- Keras Sequential guide: https://www.tensorflow.org/guide/keras/sequential_model\n- `tf.data` guide: https://www.tensorflow.org/guide/data\n- `tf.data` performance guide: https://www.tensorflow.org/guide/data_performance\n- GPU guide: https://www.tensorflow.org/guide/gpu\n- SavedModel guide: https://www.tensorflow.org/guide/saved_model\n- PyPI release page: https://pypi.org/project/tensorflow/2.21.0/\n"
  },
  {
    "path": "content/textual/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Textual framework for building terminal and browser UIs in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"textual,python,tui,terminal-ui,async,css,widgets\"\n---\n\n# Textual Python Package Guide\n\n## Golden Rule\n\nBuild Textual apps by subclassing `App`, declaring widgets in `compose()`, styling with Textual CSS, and moving slow I/O into workers. If you update the UI in response to network or blocking calls directly inside a message handler, the app will feel frozen.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"textual==8.1.1\"\n```\n\nFor local app development, install the separate devtools package too:\n\n```bash\npython -m pip install \"textual==8.1.1\" textual-dev\n```\n\nUseful variants:\n\n```bash\npython -m pip install \"textual[syntax]==8.1.1\"\nuv add \"textual==8.1.1\"\npoetry add \"textual==8.1.1\"\n```\n\nNotes:\n\n- `textual-dev` provides the `textual` CLI used for `textual run`, `textual serve`, and the dev console.\n- The `syntax` extra enables syntax highlighting in `TextArea`.\n- Textual runs on Linux, macOS, and Windows. On macOS, the official docs recommend a modern terminal such as iTerm2, Ghostty, Kitty, or WezTerm instead of the default Terminal app.\n\n## Minimal App\n\nThis is a practical starting point that shows the core Textual patterns: `App`, `compose()`, CSS, DOM queries, and reactivity.\n\n```python\nfrom textual.app import App, ComposeResult\nfrom textual.containers import Vertical\nfrom textual.reactive import reactive\nfrom textual.widgets import Footer, Header, Input, Static\n\nclass Greeting(Static):\n    name = reactive(\"world\")\n\n    def watch_name(self, name: str) -> None:\n        self.update(f\"Hello, {name or 'world'}!\")\n\nclass GreetingApp(App[None]):\n    CSS = \"\"\"\n    Screen {\n        align: center middle;\n    }\n\n    Vertical {\n        width: 40;\n    }\n\n    Input {\n        margin-bottom: 1;\n    }\n\n    Greeting {\n        height: 3;\n        border: round $accent;\n        content-align: center middle;\n    }\n    \"\"\"\n\n    def compose(self) -> ComposeResult:\n        yield Header()\n        with Vertical():\n            yield Input(placeholder=\"Type your name\")\n            yield Greeting()\n        yield Footer()\n\n    def on_mount(self) -> None:\n        self.query_one(Input).focus()\n\n    def on_input_changed(self, event: Input.Changed) -> None:\n        self.query_one(Greeting).name = event.value.strip()\n\nif __name__ == \"__main__\":\n    GreetingApp().run()\n```\n\nRun it with Python:\n\n```bash\npython greeting_app.py\n```\n\nOr with devtools:\n\n```bash\ntextual run greeting_app.py\ntextual run --dev greeting_app.py\n```\n\n## Core Usage Patterns\n\n### App structure\n\nMost Textual apps follow this shape:\n\n1. Subclass `App`.\n2. Yield widgets from `compose()`.\n3. Handle events with `on_<widget>_<message>()` methods such as `on_button_pressed` or `on_input_changed`.\n4. Use `query_one(...)` or `query(...)` to find widgets in the DOM when you need to update them.\n\n`App.run()` enters terminal application mode and Textual handles keyboard and mouse input until the app exits. Textual defines default bindings including `ctrl+q` to quit.\n\n### Styling with Textual CSS\n\nPrefer `CSS_PATH` for real apps and inline `CSS` only for short scripts or examples.\n\n```python\nfrom textual.app import App, ComposeResult\nfrom textual.widgets import Button, Label\n\nclass QuestionApp(App[str]):\n    CSS_PATH = \"question.tcss\"\n\n    def compose(self) -> ComposeResult:\n        yield Label(\"Do you love Textual?\", id=\"question\")\n        yield Button(\"Yes\", id=\"yes\", variant=\"primary\")\n        yield Button(\"No\", id=\"no\", variant=\"error\")\n```\n\nExample `question.tcss`:\n\n```css\n#question {\n    text-style: bold;\n    content-align: center middle;\n}\n\nButton {\n    width: 1fr;\n}\n\n.danger {\n    background: red;\n    color: white;\n}\n```\n\nWhat matters operationally:\n\n- Textual selectors work on widget type names, `#id`, `.class`, and combinators.\n- Widgets accept `id=` and `classes=` in constructors so CSS and DOM queries can target them consistently.\n- Inline `CSS` is loaded after `CSS_PATH`, so inline rules win on equivalent specificity.\n- `textual run --dev my_app.py` live-reloads CSS changes and connects to the dev console.\n\n### Reactive state\n\nUse `reactive(...)` for UI state that should automatically refresh or trigger watchers.\n\n```python\nfrom textual.reactive import reactive\nfrom textual.widget import Widget\n\nclass Counter(Widget):\n    count = reactive(0)\n\n    def watch_count(self, old_value: int, new_value: int) -> None:\n        self.log(f\"count changed from {old_value} to {new_value}\")\n\n    def render(self) -> str:\n        return f\"Count: {self.count}\"\n```\n\nPractical guidance:\n\n- `watch_<name>` is the simplest way to keep dependent widgets in sync.\n- `validate_<name>` is useful for clamping or normalizing state before it is stored.\n- If a reactive holds a mutable object like `list` or `dict`, mutating it in place does not trigger the reactive machinery; use `mutate_reactive(...)` or assign a new value.\n\n### Workers for async and blocking work\n\nDo not wait on remote I/O inside input handlers, button handlers, or other high-frequency message handlers. Use workers.\n\nAsync API pattern:\n\n```python\nimport httpx\n\nfrom textual import work\nfrom textual.app import App, ComposeResult\nfrom textual.widgets import Input, Static\n\nclass SearchApp(App[None]):\n    def compose(self) -> ComposeResult:\n        yield Input(placeholder=\"Search\")\n        yield Static(id=\"results\")\n\n    def on_input_changed(self, event: Input.Changed) -> None:\n        self.fetch_results(event.value)\n\n    @work(exclusive=True)\n    async def fetch_results(self, query: str) -> None:\n        if not query:\n            self.query_one(\"#results\", Static).update(\"\")\n            return\n\n        async with httpx.AsyncClient() as client:\n            response = await client.get(\"https://example.com/search\", params={\"q\": query})\n        self.query_one(\"#results\", Static).update(response.text)\n```\n\nBlocking library pattern:\n\n```python\nfrom textual import work\n\n@work(exclusive=True, thread=True)\ndef load_blocking(self) -> None:\n    result = some_blocking_call()\n    self.call_from_thread(self.query_one(\"#status\").update, result)\n```\n\nRules that prevent hard-to-debug UI bugs:\n\n- Use `exclusive=True` for \"latest input wins\" workloads such as search boxes and autocomplete.\n- `@work` on a regular `def` requires `thread=True`; Textual raises an exception otherwise.\n- Thread workers must not update the UI directly. Use `call_from_thread(...)` or post messages back to the app.\n- By default, worker exceptions exit the app. Set `exit_on_error=False` only when you are explicitly handling worker failures.\n\n### Screens, modes, and bindings\n\nFor multi-view apps, define persistent screens on `SCREENS` and switch with `push_screen(...)` or modes.\n\n```python\nfrom textual.app import App\nfrom textual.binding import Binding\nfrom textual.screen import Screen\n\nclass HelpScreen(Screen[None]):\n    pass\n\nclass MyApp(App[None]):\n    BINDINGS = [Binding(\"ctrl+s\", \"save\", \"Save\")]\n    SCREENS = {\n        \"help\": HelpScreen,\n    }\n\n    def action_save(self) -> None:\n        ...\n```\n\nThis is cleaner than conditionally mounting and removing large parts of the UI by hand.\n\n## Devtools, Browser Serving, and Testing\n\nIf you installed `textual-dev`, the most useful commands are:\n\n```bash\ntextual --help\ntextual run my_app.py\ntextual run --dev my_app.py\ntextual serve my_app.py\n```\n\nUse `textual serve` when you want to access the app in a browser. That serves the Textual app over the web, but Textual itself does not provide application-level authentication, TLS termination, or deployment policy for you. Treat browser exposure as a deployment concern, not a widget concern.\n\nFor automated tests, use `run_test()` and the `Pilot` object:\n\n```python\nimport pytest\n\n@pytest.mark.asyncio\nasync def test_submit():\n    app = GreetingApp()\n    async with app.run_test() as pilot:\n        await pilot.press(\"A\", \"l\", \"i\", \"c\", \"e\")\n        assert app.query_one(Greeting).name == \"Alice\"\n```\n\nUseful test capabilities from the official guide:\n\n- `pilot.press(...)` simulates keyboard input.\n- `pilot.click(...)` simulates widget clicks by selector.\n- `app.run_test(size=(100, 50))` lets you verify layout-sensitive behavior at a specific terminal size.\n- `pytest-textual-snapshot` is the official snapshot plugin if you need visual regression coverage.\n\n## Configuration and Environment\n\nTextual itself does not require credentials or environment variables. Configuration is mostly Python class attributes and your own app settings.\n\nCommon app-level configuration surfaces:\n\n- `CSS_PATH`: stylesheet files for production apps.\n- `CSS`: inline stylesheet for small examples.\n- `BINDINGS`: keyboard shortcuts and command labels.\n- `SCREENS` and `MODES`: screen routing and multi-view navigation.\n- `AUTO_FOCUS`: selector for what should gain focus when a screen activates.\n\nIf your Textual app talks to external services, handle API keys and environment-specific configuration exactly as you would in any other Python app. Textual does not wrap secret management for you.\n\n## Common Pitfalls\n\n- Missing `textual` CLI: install `textual-dev`; the framework package alone does not guarantee the devtools command is on your path.\n- Querying widgets too early: `query_one(...)` raises `NoMatches` if the widget is not mounted yet.\n- Mounting is async: if you `mount()` and immediately query descendants in the same handler, make the handler `async` and `await self.mount(...)`.\n- Blocking the UI loop: direct network or filesystem work inside message handlers makes input laggy; use `run_worker(...)` or `@work`.\n- Threaded workers touching UI state: use `call_from_thread(...)` or messages, not direct widget mutation from the worker thread.\n- Mutable reactives: changing a list or dict in place will not trigger watchers or refresh logic unless you explicitly notify Textual.\n- Old examples using `renderable=`: modern Textual uses `content` for `Label` and `Static` APIs after the `6.0.0` breaking change.\n- Browser exposure assumptions: `textual serve` is not a substitute for your auth, proxy, and deployment controls.\n\n## Version-Sensitive Notes\n\n- `8.1.1` is the current PyPI release as of `2026-03-12`; the version used here is current.\n- PyPI currently lists support for Python `3.9` through `3.14` and requires `>=3.9,<4.0`.\n- The Textual `6.3.0` release dropped Python `3.8`. If you are migrating an older app or CI image, upgrade Python first.\n- The Textual `6.0.0` release renamed `Static.renderable` to `Static.content` and changed the `Label` constructor argument from `renderable` to `content`. Old blog posts and gists may still use the pre-6.0 names.\n- If you upgrade Textual and rely on devtools, update `textual-dev` at the same time to avoid mismatched CLI behavior.\n\n## Official Sources\n\n- Documentation root: https://textual.textualize.io/\n- Getting started: https://textual.textualize.io/getting_started/\n- App guide: https://textual.textualize.io/guide/app/\n- CSS guide: https://textual.textualize.io/guide/CSS/\n- Reactivity guide: https://textual.textualize.io/guide/reactivity/\n- Workers guide: https://textual.textualize.io/guide/workers/\n- Testing guide: https://textual.textualize.io/guide/testing/\n- Devtools guide: https://textual.textualize.io/guide/devtools/\n- App API reference: https://textual.textualize.io/api/app/\n- PyPI package page: https://pypi.org/project/textual/\n- Official release notes: https://github.com/Textualize/textual/releases\n"
  },
  {
    "path": "content/tiktoken/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tiktoken package guide for Python with model-aware encodings, token counting, cache setup, special tokens, and custom encoding notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.12.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"openai,tiktoken,python,tokens,tokenizer,bpe,llm\"\n---\n\n# tiktoken Python Package Guide\n\n## Golden Rule\n\n- Use `tiktoken` when you need exact tokenizer behavior for OpenAI encodings, not rough token estimates.\n- Prefer `tiktoken.encoding_for_model(...)` when you know the target model name.\n- Prefer `tiktoken.get_encoding(...)` when you need a fixed encoding that should not change with future model-to-encoding remaps.\n\n## Version-Sensitive Notes\n\n- This entry is pinned to the version used here `0.12.0`.\n- PyPI currently shows `0.12.0` as the latest published version as of `2026-03-12`, so the version used here matches current upstream.\n- `tiktoken` `0.12.0` requires Python `>=3.9`.\n- Upstream's `0.12.0` changelog notes add the `o200k_harmony` encoding, improve plugin type annotations, remove the need for `blobfile` when reading local files, and drop Python `3.8`.\n- `encoding_for_model(...)` depends on model-name mappings shipped in the package. If you upgrade `tiktoken`, a newer release can change which encoding a model name resolves to. Pin the package version if token accounting must stay stable across deployments.\n\n## Install\n\nPin the version when token counts need to be reproducible:\n\n```bash\npython -m pip install \"tiktoken==0.12.0\"\n```\n\nWith `uv`:\n\n```bash\nuv add \"tiktoken==0.12.0\"\n```\n\nIf a compatible wheel is unavailable for your platform, `pip` may need to build the Rust extension from source.\n\n## Recommended Setup\n\nStart by choosing whether your code should follow a model name or a fixed encoding name.\n\nUse a fixed encoding when you want stable behavior independent of model remaps:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"cl100k_base\")\n```\n\nUse a model name when your code should follow OpenAI's model mapping in this package version:\n\n```python\nimport tiktoken\n\nenc = tiktoken.encoding_for_model(\"gpt-4o-mini\")\n```\n\nTo inspect what encodings are available in the installed package:\n\n```python\nimport tiktoken\n\nprint(tiktoken.list_encoding_names())\n```\n\n## Core Usage\n\n### Count Tokens\n\n```python\nimport tiktoken\n\nenc = tiktoken.encoding_for_model(\"gpt-4o-mini\")\ntext = \"Context matters.\"\n\ntoken_ids = enc.encode(text)\nprint(token_ids)\nprint(len(token_ids))\n```\n\nFor plain string token counting, `len(enc.encode(text))` is the common pattern.\n\n### Decode Tokens Back To Text\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"cl100k_base\")\ntoken_ids = enc.encode(\"hello world\")\n\ndecoded = enc.decode(token_ids)\nprint(decoded)\n```\n\n### Work With Single Tokens Safely\n\nSingle tokens do not always align to UTF-8 character boundaries. Use `decode_single_token_bytes(...)` for per-token inspection:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"cl100k_base\")\ntoken_id = enc.encode(\"hello\")[0]\n\nprint(enc.decode_single_token_bytes(token_id))\n```\n\n### Encode Multiple Strings\n\nUse batch encoding when you already have many strings to tokenize:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"o200k_base\")\n\nrows = [\"alpha\", \"beta\", \"gamma\"]\nencoded_rows = enc.encode_batch(rows)\nprint(encoded_rows)\n```\n\n### Ignore Special Tokens In Ordinary Text\n\n`encode_ordinary(...)` is useful when you want normal tokenization without special-token handling:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"cl100k_base\")\ntoken_ids = enc.encode_ordinary(\"plain text only\")\nprint(token_ids)\n```\n\n### Allow Specific Special Tokens\n\nBy default, special tokens are rejected. Allow them explicitly when you intend to preserve them:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"gpt2\")\ntext = \"hello <|endoftext|>\"\n\ntoken_ids = enc.encode(text, allowed_special={\"<|endoftext|>\"})\nprint(token_ids)\n```\n\n## Choosing The Right Encoding\n\nReach for these APIs in this order:\n\n- `encoding_for_model(model_name)`: best when you are counting tokens for a known OpenAI model.\n- `get_encoding(encoding_name)`: best when you need a stable base encoding such as `cl100k_base` or `o200k_base`.\n- `list_encoding_names()`: best when debugging or validating what the installed package exposes.\n\nHandle unknown model names defensively:\n\n```python\nimport tiktoken\n\nmodel_name = \"my-unknown-model\"\n\ntry:\n    enc = tiktoken.encoding_for_model(model_name)\nexcept KeyError:\n    enc = tiktoken.get_encoding(\"o200k_base\")\n```\n\nThat fallback should be a deliberate choice. Do not assume every unknown model belongs to `o200k_base`.\n\n## Config And Environment\n\n`tiktoken` does not require API keys or service authentication. Most usage is local once the encoding assets are available.\n\nFor built-in encodings, the package caches tokenizer data on first use. Relevant environment variables from upstream source:\n\n- `TIKTOKEN_CACHE_DIR`: preferred cache location\n- `DATA_GYM_CACHE_DIR`: legacy fallback cache location\n\nIf neither variable is set, `tiktoken` falls back to the system temp directory.\n\n```bash\nexport TIKTOKEN_CACHE_DIR=\"$HOME/.cache/tiktoken\"\n```\n\nIn CI, containers, or other restricted environments, prewarming this cache can avoid repeated downloads.\n\nIf `TIKTOKEN_CACHE_DIR` is set to the empty string, upstream disables caching rather than writing files.\n\n## Offline And Restricted Environments\n\n- The first load of a built-in encoding may need to fetch encoding data and cache it locally.\n- If your runtime cannot reach public package assets, prewarm the cache during image build or ship the needed encoding files with your environment.\n- If you build custom extension packages that load encodings from non-HTTP blob URLs, upstream may require the optional `blobfile` dependency for those paths.\n\n## Custom Encodings\n\nThe maintainers expose `tiktoken.Encoding(...)` plus a plugin mechanism under the `tiktoken_ext` namespace.\n\nUse this only when you need custom merge ranks or custom special tokens. For most agent tasks, built-in encodings are the right choice.\n\nThe README's extension guidance matters:\n\n- custom plugin packages live under `tiktoken_ext`\n- the namespace package should omit `tiktoken_ext/__init__.py`\n- the package exposes `ENCODING_CONSTRUCTORS`\n\nIf you only need extra special tokens, it is usually simpler to derive from an existing encoding than to build a new tokenizer from scratch.\n\n## Common Pitfalls\n\n- `encoding_for_model(...)` can raise `KeyError` for new or private model names. Catch it and choose an explicit fallback.\n- Token counts from `tiktoken` are for the text you pass in. Full API request overhead for message wrappers, tool schemas, or structured payloads is outside the tokenizer itself.\n- `decode()` on individual tokens can be misleading because a token may contain partial UTF-8 bytes. Use `decode_single_token_bytes(...)` when inspecting one token at a time.\n- Special tokens are disallowed by default. If your input intentionally contains them, pass `allowed_special=...` instead of stripping them silently.\n- Do not hard-code a model-to-encoding assumption copied from an old blog post. Use the installed package's mapping or pin a known encoding name.\n- First-use cache misses can look like random latency in ephemeral environments. Prewarm the cache if startup consistency matters.\n\n## Practical Patterns\n\n### Count A Prompt Before Sending It Elsewhere\n\n```python\nimport tiktoken\n\ndef count_tokens(model: str, text: str) -> int:\n    enc = tiktoken.encoding_for_model(model)\n    return len(enc.encode(text))\n\nprint(count_tokens(\"gpt-4o-mini\", \"Summarize this file.\"))\n```\n\n### Reuse One Encoding Object\n\nCreate the encoding once and reuse it across many strings:\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"cl100k_base\")\n\ndef count_many(texts: list[str]) -> list[int]:\n    return [len(tokens) for tokens in enc.encode_batch(texts)]\n```\n\n### Inspect Why Two Strings Tokenize Differently\n\n```python\nimport tiktoken\n\nenc = tiktoken.get_encoding(\"o200k_base\")\n\nfor text in [\"camelCase\", \"camel case\"]:\n    token_ids = enc.encode(text)\n    print(text, token_ids, len(token_ids))\n```\n\n## Official Source URLs\n\n- Repository: `https://github.com/openai/tiktoken`\n- README: `https://github.com/openai/tiktoken/blob/main/README.md`\n- Changelog: `https://github.com/openai/tiktoken/blob/main/CHANGELOG.md`\n- PyPI release: `https://pypi.org/project/tiktoken/0.12.0/`\n"
  },
  {
    "path": "content/time-machine/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"time-machine package guide for Python tests that need deterministic time travel and pytest integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"time-machine,python,testing,datetime,time,pytest,mocking\"\n---\n\n# time-machine Python Package Guide\n\n## Golden Rule\n\nUse `time-machine` only in test code or tightly scoped development helpers. It patches interpreter-level time functions, so treat every travel block as global process state and keep the scope as small as possible.\n\n## Install\n\nPin the package version your test environment expects:\n\n```bash\npython -m pip install \"time-machine==3.2.0\"\n```\n\nOptional extras published by the maintainer:\n\n```bash\npython -m pip install \"time-machine[dateutil]==3.2.0\"\npython -m pip install \"time-machine[cli]==3.2.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"time-machine==3.2.0\"\npoetry add --group test \"time-machine==3.2.0\"\n```\n\n## Core Usage\n\n`time_machine.travel()` is the main API. You can use it as a context manager, decorator, or manual controller.\n\n### Freeze time in a context manager\n\n```python\nfrom datetime import datetime, timezone\n\nimport time_machine\n\nwith time_machine.travel(datetime(2024, 5, 1, 12, 0, tzinfo=timezone.utc), tick=False):\n    assert datetime.now(timezone.utc).isoformat() == \"2024-05-01T12:00:00+00:00\"\n```\n\nUse `tick=False` when your assertions need a fixed instant. The default is `tick=True`, which means time advances from the destination after travel starts.\n\n### Use as a decorator\n\n```python\nimport datetime as dt\n\nimport time_machine\n\n@time_machine.travel(dt.datetime(2024, 7, 4, 9, 30, tzinfo=dt.timezone.utc), tick=False)\ndef test_report_timestamp() -> None:\n    assert dt.date.today().isoformat() == \"2024-07-04\"\n```\n\n### Manual start/stop when setup spans multiple assertions\n\n```python\nimport datetime as dt\n\nimport time_machine\n\ntraveller = time_machine.travel(dt.datetime(2025, 1, 1, tzinfo=dt.timezone.utc), tick=False)\ntraveller.start()\ntry:\n    # multiple calls share the same travelled time\n    ...\nfinally:\n    traveller.stop()\n```\n\n## Moving During A Test\n\nThe started traveller object exposes `move_to()` and `shift()` so a single test can advance through multiple moments.\n\n```python\nfrom datetime import datetime, timedelta, timezone\n\nimport time_machine\n\ntraveller = time_machine.travel(datetime(2024, 1, 1, tzinfo=timezone.utc), tick=False)\ntraveller.start()\ntry:\n    traveller.shift(timedelta(hours=2))\n    traveller.move_to(datetime(2024, 1, 2, tzinfo=timezone.utc))\nfinally:\n    traveller.stop()\n```\n\nThis is usually cleaner than nesting multiple travel blocks.\n\n## Accepted Destination Types\n\nThe maintainer docs allow several destination forms:\n\n- A timezone-aware `datetime`\n- A `date`\n- A Unix timestamp (`int` or `float`)\n- A `timedelta` offset from the current time\n- A string parsed by `dateutil`, if you install the `dateutil` extra\n- A callable or generator that yields destinations for repeated test setup\n\nPrefer timezone-aware `datetime` values for deterministic tests. They make the intended zone explicit and avoid local-time surprises.\n\n## Pytest Integration\n\nThe package ships a pytest plugin with:\n\n- a `time_machine` fixture that returns a started traveller\n- a `@pytest.mark.time_machine(...)` marker for per-test travel\n\nExample fixture usage:\n\n```python\nfrom datetime import datetime, timezone\n\ndef test_expiry(time_machine) -> None:\n    time_machine.move_to(datetime(2024, 9, 1, tzinfo=timezone.utc), tick=False)\n    ...\n```\n\nExample marker usage:\n\n```python\nfrom datetime import datetime, timezone\n\nimport pytest\n\n@pytest.mark.time_machine(datetime(2024, 9, 1, tzinfo=timezone.utc), tick=False)\ndef test_marker_example() -> None:\n    ...\n```\n\nIf your tests already rely on fixture setup, the fixture is usually easier to compose than decorators.\n\n## Configuration And Environment\n\nThere is no auth or external service setup. The important configuration choices are behavioral:\n\n- `tick`: defaults to `True`; set `False` when you need a frozen clock\n- destination timezone: prefer aware UTC datetimes unless local time is the behavior under test\n- `naive_mode`: controls how naive datetimes are interpreted; use the default only if you understand your project’s local-time assumptions\n\nOn Unix, time travel also updates the process timezone via `time.tzset()` when needed. That matters if your code reads local time or timezone-dependent formatting.\n\n## Escape Hatch\n\nThe package exposes `time_machine.escape_hatch` for code that must read the real clock while travel is active.\n\n```python\nimport time_machine\n\nreal_now = time_machine.escape_hatch.datetime.datetime.now()\ntravel_active = time_machine.escape_hatch.is_travelling()\n```\n\nUse this sparingly. If production code needs real time while tests are travelling, that is often a design smell worth isolating behind a clock abstraction.\n\n## Common Pitfalls\n\n- Travel state is global within the current process. Threads and concurrent tasks see the travelled time too.\n- Child processes, external services, databases, and other machines do not inherit the travelled clock.\n- Default `tick=True` can make equality assertions flaky. Freeze time with `tick=False` unless advancing time is intentional.\n- Naive datetimes are easy to misread. Use timezone-aware datetimes when possible.\n- String destinations require `python-dateutil`; without the extra installed, parsing helpers are unavailable.\n- Class decorators are primarily for `unittest.TestCase` classes. For pytest, prefer the fixture or marker.\n\n## Version-Sensitive Notes\n\n- PyPI currently lists `3.2.0` and requires Python `>=3.10`.\n- The project is CPython-only because it patches C-level time functions for speed and broader coverage.\n- If you are migrating from `freezegun`, check the maintainer migration guide before doing a drop-in replacement. `time-machine` defaults and behavior differ in a few places, especially around ticking and parser-backed string destinations.\n\n## Official Sources\n\n- PyPI: https://pypi.org/project/time-machine/\n- Docs: https://time-machine.readthedocs.io/en/latest/\n- Installation: https://time-machine.readthedocs.io/en/latest/installation.html\n- Usage: https://time-machine.readthedocs.io/en/latest/usage.html\n- Pytest plugin: https://time-machine.readthedocs.io/en/latest/pytest_plugin.html\n- Migration guide: https://time-machine.readthedocs.io/en/latest/migration.html\n- Comparison: https://time-machine.readthedocs.io/en/latest/comparison.html\n- Repository: https://github.com/adamchainz/time-machine\n"
  },
  {
    "path": "content/timm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"timm package guide for Python projects using pretrained vision models, feature extraction, fine-tuning, and Hugging Face Hub integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.0.25\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"timm,pytorch,vision,image-classification,feature-extraction,huggingface\"\n---\n\n# timm Python Package Guide\n\n## Golden Rule\n\nUse `timm.create_model(...)` plus the model-specific preprocessing config from `resolve_data_config()` and `create_transform()`. For pretrained inference, put the model in eval mode before calling it. Do not assume every `timm` checkpoint uses the same input size, crop percent, interpolation, or normalization values.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"timm==1.0.25\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"timm==1.0.25\"\npoetry add \"timm==1.0.25\"\n```\n\nNotes:\n\n- `timm` installs against PyTorch and torchvision. If your environment needs a specific CUDA, ROCm, or CPU-only PyTorch build, choose that PyTorch install deliberately before pinning `timm`.\n- The packaged release is for library use. The official training and validation scripts are not included in the wheel, so clone the repository and install from source if you need `train.py`, `validate.py`, `inference.py`, or the shell wrappers.\n\nSource install when you need the repo scripts:\n\n```bash\ngit clone https://github.com/huggingface/pytorch-image-models\ncd pytorch-image-models\npython -m pip install -e .\n```\n\n## Initialize And Inspect Models\n\nList available pretrained model names:\n\n```python\nimport timm\n\nmodels = timm.list_models(pretrained=True)\nprint(models[:20])\n```\n\nCreate a pretrained classifier:\n\n```python\nimport timm\n\nmodel = timm.create_model(\n    \"vit_base_patch16_224.augreg_in21k_ft_in1k\",\n    pretrained=True,\n)\nmodel.eval()\n```\n\nUseful constructor flags from the official reference:\n\n- `pretrained=True`: load pretrained weights\n- `num_classes=...`: replace the classifier head when fine-tuning\n- `in_chans=...`: change expected input channels\n- `features_only=True`: return intermediate feature maps instead of logits\n- `cache_dir=...`: override the default model download cache location\n\n## Preprocessing And Basic Inference\n\nBuild transforms from the model's own pretrained config instead of hard-coding ImageNet defaults:\n\n```python\nfrom PIL import Image\nimport torch\nimport timm\nfrom timm.data import resolve_data_config\nfrom timm.data.transforms_factory import create_transform\n\nmodel = timm.create_model(\n    \"vit_base_patch16_224.augreg_in21k_ft_in1k\",\n    pretrained=True,\n)\nmodel.eval()\n\ndata_config = resolve_data_config(model.pretrained_cfg, model=model)\ntransform = create_transform(**data_config, is_training=False)\n\nimage = Image.open(\"example.jpg\").convert(\"RGB\")\ninputs = transform(image).unsqueeze(0)\n\nwith torch.inference_mode():\n    logits = model(inputs)\n    probs = logits.softmax(dim=-1)\n```\n\nImportant details:\n\n- `transform(image)` returns `CHW`; add a batch dimension with `unsqueeze(0)`.\n- Use `torch.inference_mode()` or `torch.no_grad()` for inference.\n- Many checkpoints expose labels through the associated model card or Hub repo rather than directly from the model object.\n\n## Feature Extraction\n\n### Get the backbone output before the classifier\n\n```python\nimport timm\nimport torch\n\nmodel = timm.create_model(\"resnet50.a1_in1k\", pretrained=True)\nmodel.eval()\n\nx = torch.randn(1, 3, 224, 224)\nfeatures = model.forward_features(x)\nprint(features.shape)\n```\n\n### Get pooled embeddings instead of logits\n\n```python\nimport timm\n\nmodel = timm.create_model(\n    \"resnet50.a1_in1k\",\n    pretrained=True,\n    num_classes=0,\n    global_pool=\"avg\",\n)\nmodel.eval()\n```\n\nFor an already-created model, the reference docs also expose `reset_classifier(num_classes, global_pool)`.\n\n### Get multi-scale feature maps\n\n```python\nimport timm\n\nbackbone = timm.create_model(\n    \"resnet50.a1_in1k\",\n    pretrained=True,\n    features_only=True,\n    out_indices=(1, 2, 3, 4),\n)\n\nfeature_maps = backbone(torch.randn(1, 3, 224, 224))\nfor fmap in feature_maps:\n    print(fmap.shape)\n```\n\n`features_only=True` is the right choice for detection, segmentation, or other tasks that need pyramid-style intermediate activations.\n\n## Fine-Tuning\n\nFor standard transfer learning, replace the classifier head at construction time:\n\n```python\nimport timm\n\nmodel = timm.create_model(\n    \"resnet50.a1_in1k\",\n    pretrained=True,\n    num_classes=10,\n)\n```\n\nIf you already built the model, update the head in place:\n\n```python\nmodel.reset_classifier(num_classes=10)\n```\n\nKeep the pretrained transform pipeline unless you intentionally change image size or augmentation behavior for training:\n\n```python\nfrom timm.data import resolve_data_config\nfrom timm.data.transforms_factory import create_transform\n\ndata_config = resolve_data_config(model.pretrained_cfg, model=model)\ntrain_transform = create_transform(**data_config, is_training=True)\nval_transform = create_transform(**data_config, is_training=False)\n```\n\n## Hugging Face Hub Integration\n\n`timm` integrates with Hugging Face Hub for loading and sharing model weights. For a public Hub model, load directly by prefixing the repo id:\n\n```python\nimport timm\n\nmodel = timm.create_model(\"hf-hub:timm/eca_nfnet_l0\", pretrained=True)\nmodel.eval()\n```\n\nUse `cache_dir` when you need a deterministic or project-local cache path:\n\n```python\nmodel = timm.create_model(\n    \"hf-hub:timm/eca_nfnet_l0\",\n    pretrained=True,\n    cache_dir=\".cache/huggingface\",\n)\n```\n\nAuthentication notes:\n\n- Public pretrained weights do not require auth.\n- Private or gated Hub repos do require a token.\n- The current Hugging Face auth flow is:\n\n```bash\nhf auth login\n```\n\nAfter authentication, the same `hf-hub:...` loading pattern works for repos your token can access.\n\n## Official Training Scripts\n\nThe repo ships ready-made training, validation, and inference scripts, but the maintainer docs explicitly note these are not included in the pip release package. If your task requires:\n\n- distributed training\n- EMA, AMP, advanced augmentation, mixup, or RandAugment defaults\n- reproducing official benchmark commands\n- bulk validation across checkpoints\n\nuse the GitHub repository checkout instead of expecting those scripts to be available after `pip install timm`.\n\n## Common Pitfalls\n\n- Do not reuse a generic torchvision normalization pipeline unless you have checked the model's `pretrained_cfg`. `timm` models vary by image size, crop percentage, interpolation, mean, and std.\n- Do not skip `model.eval()` for pretrained inference; dropout and batchnorm behavior will be wrong.\n- `forward_features()` does not always return the same shape across architectures. CNNs commonly return feature maps; transformers may return token or spatial representations depending on the model.\n- `features_only=True` changes the model output to a list of intermediate tensors, not classifier logits.\n- `num_classes=0` removes the classifier head for embedding extraction. If you still need logits, keep a positive `num_classes`.\n- The wheel does not include the repo scripts. If an example references `train.py` or shell launchers, you need a source checkout.\n- Current Hugging Face Hub docs use the `hf-hub:` prefix. Older `timm` docs pages and snippets may show `hf_hub:` instead; prefer the current `hf-hub:` form when writing new code.\n\n## Version-Sensitive Notes For `1.0.25`\n\n- The version used here `1.0.25` matches the current PyPI release history and the Hugging Face docs navigation, which marks `v1.0.25` as the stable branch.\n- PyPI's `1.0.25` release notes call out two recent loading-related changes that matter when copying older examples: `create_model` accepts `cache_dir`, and the Hugging Face Hub loading path passes through `trust_remote_code`.\n- Some docs pages default to `main`, which can describe behavior newer than the wheel you have pinned. For a project locked to `1.0.25`, prefer the stable docs branch over `main` when examples conflict.\n- The project lives under the Hugging Face-maintained `huggingface/pytorch-image-models` repository. Older blog posts may still refer to the previous `rwightman/pytorch-image-models` location.\n\n## Official Sources Used For This Entry\n\n- `https://huggingface.co/docs/timm/`\n- `https://huggingface.co/docs/timm/quickstart`\n- `https://huggingface.co/docs/timm/installation`\n- `https://huggingface.co/docs/timm/feature_extraction`\n- `https://huggingface.co/docs/timm/reference/models`\n- `https://huggingface.co/docs/hub/en/timm`\n- `https://pypi.org/project/timm/`\n- `https://github.com/huggingface/pytorch-image-models`\n- `https://raw.githubusercontent.com/huggingface/pytorch-image-models/main/pyproject.toml`\n"
  },
  {
    "path": "content/together/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Together Python SDK for chat, completions, embeddings, images, rerank, and fine-tuning\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.3.2\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"together,python,llm,chat,embeddings,images,rerank,fine-tuning\"\n---\n\n# together Python Package Guide\n\n## What This Package Is\n\n`together` is Together AI's official Python SDK. Use it when you need Together-hosted chat/completions models, embeddings, image generation, reranking, file upload, or fine-tuning from Python.\n\n## Install\n\n```bash\npip install together==2.3.2\n```\n\nCommon project-tool variants:\n\n```bash\npoetry add together==2.3.2\nuv add together==2.3.2\n```\n\n## Authentication\n\nTogether uses an API key. The SDK reads `TOGETHER_API_KEY` by default.\n\n```bash\nexport TOGETHER_API_KEY=\"your-api-key\"\n```\n\nYou can also pass the key explicitly:\n\n```python\nfrom together import Together\n\nclient = Together(api_key=\"your-api-key\")\n```\n\nIf you already exported `TOGETHER_API_KEY`, this is enough:\n\n```python\nfrom together import Together\n\nclient = Together()\n```\n\n## Core Usage\n\n### Chat Completions\n\nUse `client.chat.completions.create(...)` for the OpenAI-style chat flow.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.chat.completions.create(\n    model=\"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"Answer briefly and clearly.\"},\n        {\"role\": \"user\", \"content\": \"Write a haiku about distributed systems.\"},\n    ],\n    temperature=0.7,\n    max_tokens=128,\n)\n\nprint(response.choices[0].message.content)\n```\n\n### Text Completions\n\nOlder prompt-style models use `client.completions.create(...)`.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.completions.create(\n    model=\"your-completions-model-id\",\n    prompt=\"Write three commit message options for fixing a flaky test.\",\n    max_tokens=80,\n)\n\nprint(response.choices[0].text)\n```\n\n### Streaming Chat Output\n\nSet `stream=True` and iterate over chunks.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nstream = client.chat.completions.create(\n    model=\"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\",\n    messages=[{\"role\": \"user\", \"content\": \"Summarize event-driven architecture in 3 bullets.\"}],\n    stream=True,\n)\n\nfor chunk in stream:\n    delta = chunk.choices[0].delta.content\n    if delta:\n        print(delta, end=\"\", flush=True)\nprint()\n```\n\n### Structured Output / JSON Mode\n\nThe Together docs show `response_format` support on chat completions. Use it when your caller expects machine-readable JSON.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.chat.completions.create(\n    model=\"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\",\n    messages=[{\"role\": \"user\", \"content\": \"Return a JSON object with keys title and priority.\"}],\n    response_format={\"type\": \"json_object\"},\n)\n\nprint(response.choices[0].message.content)\n```\n\n### Embeddings\n\nUse `client.embeddings.create(...)` for vector search or retrieval pipelines.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.embeddings.create(\n    model=\"togethercomputer/m2-bert-80M-32k-retrieval\",\n    input=[\"Package docs help coding assistants answer questions.\"],\n)\n\nembedding = response.data[0].embedding\nprint(len(embedding))\n```\n\n### Image Generation\n\nUse `client.images.generate(...)` for text-to-image generation.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.images.generate(\n    model=\"black-forest-labs/FLUX.1-schnell-Free\",\n    prompt=\"A pencil sketch of a robot reading API docs\",\n)\n\nprint(response.data[0].url)\n```\n\n### Reranking\n\nUse `client.rerank.create(...)` to score a set of candidate documents against a query.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nresponse = client.rerank.create(\n    model=\"Salesforce/Llama-Rank-V1\",\n    query=\"python sdk authentication\",\n    documents=[\n        \"Set TOGETHER_API_KEY before creating the client.\",\n        \"Use rerank for semantic document sorting.\",\n        \"Image generation is available through client.images.generate.\",\n    ],\n)\n\nfor item in response.results:\n    print(item.index, item.relevance_score)\n```\n\n## Async Usage\n\nUse `AsyncTogether` inside async apps, workers, or FastAPI endpoints.\n\n```python\nimport asyncio\nfrom together import AsyncTogether\n\nasync def main() -> None:\n    client = AsyncTogether()\n    response = await client.chat.completions.create(\n        model=\"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo\",\n        messages=[{\"role\": \"user\", \"content\": \"Say hello in one sentence.\"}],\n    )\n    print(response.choices[0].message.content)\n\nasyncio.run(main())\n```\n\n## Files And Fine-Tuning\n\nThe SDK also exposes file upload and fine-tuning APIs. The official repo examples use `client.files.upload(...)` followed by `client.fine_tuning.create(...)`.\n\n```python\nfrom together import Together\n\nclient = Together()\n\nwith open(\"training.jsonl\", \"rb\") as handle:\n    uploaded = client.files.upload(file=handle)\n\njob = client.fine_tuning.create(\n    training_file=uploaded.id,\n    model=\"your-fine-tunable-base-model\",\n    n_epochs=1,\n    n_checkpoints=1,\n)\n\nprint(job.id)\n```\n\nUse the current Together fine-tuning docs before copying this flow into production. File purpose requirements and accepted training formats can change.\n\n## Configuration Notes\n\n- `Together()` reads `TOGETHER_API_KEY` automatically.\n- `api_key=` is the simplest override for multi-tenant or per-request key routing.\n- The official SDK examples also show `base_url=` support, which is useful for proxying or local compatibility layers.\n- Model names are string IDs; do not guess them. Pull them from current Together docs or your account's supported-model list.\n- Response objects are OpenAI-style for chat/completions, but endpoint-specific fields differ for images, embeddings, files, rerank, and fine-tuning.\n\n## Common Pitfalls\n\n- Do not import `OpenAI` from this package. The Together SDK uses `Together` and `AsyncTogether`.\n- Do not assume every endpoint is available on every model. Chat, embeddings, rerank, image generation, and fine-tuning use different model families.\n- Do not hardcode stale model IDs from blog posts. Together's docs and catalog change frequently.\n- Streaming responses are iterators of chunks, not one final response object.\n- Rerank expects a query plus candidate documents; it is not the same API shape as embeddings.\n- Fine-tuning examples often require JSONL training data and uploaded file IDs. Validate the file format first.\n\n## Version-Sensitive Notes\n\n- This doc is pinned to the version used here `2.3.2`.\n- The PyPI page showed `2.4.0` as the current latest release on 2026-03-11, so some upstream examples may reflect behavior newer than `2.3.2`.\n- The Together docs are not version-pinned per SDK release. Treat the docs site as current-product guidance and verify any newly documented arguments against the installed package if code fails.\n- The docs site is organized around Together's current v2 platform docs. For package work, prefer the Python SDK page and quickstart over the broader REST reference landing page.\n\n## Official Source URLs\n\n- Python SDK docs: `https://docs.together.ai/docs/python-sdk`\n- Quickstart and auth: `https://docs.together.ai/docs/quickstart`\n- API reference landing page: `https://docs.together.ai/reference/`\n- PyPI package: `https://pypi.org/project/together/`\n- Official repository: `https://github.com/togethercomputer/together-python`\n"
  },
  {
    "path": "content/tokenizers/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tokenizers for Python - fast Hugging Face tokenization, tokenizer.json pipelines, training, padding, truncation, and alignment\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.22.2\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tokenizers,huggingface,nlp,bpe,wordpiece,tokenization\"\n---\n\n# tokenizers Python Package Guide\n\n## What It Is\n\n`tokenizers` is Hugging Face's low-level fast tokenizer engine for Python, backed by the Rust implementation. Use it when you need to:\n\n- load or save a full `tokenizer.json`\n- train a tokenizer from files or iterators\n- customize normalization, pre-tokenization, model, decoding, and post-processing\n- inspect token alignment data such as `offsets` and `word_ids`\n- run high-throughput batch tokenization outside the higher-level `transformers` API\n\nIf you need model-aware defaults for a pretrained model family, `transformers.AutoTokenizer` is often the higher-level entry point. Use `tokenizers` when you need direct control over the tokenizer pipeline itself.\n\n## Installation\n\n```bash\npip install tokenizers==0.22.2\n```\n\n```bash\nuv add tokenizers==0.22.2\n```\n\nPython requirement for `tokenizers` 0.22.2: Python 3.9+.\n\nThe Hugging Face installation page currently says Tokenizers is tested on Python 3.5+, but the current PyPI release metadata for `0.22.2` requires Python `>=3.9`. Treat PyPI as authoritative for install constraints.\n\n## Imports At A Glance\n\n```python\nfrom tokenizers import Tokenizer, models, normalizers, pre_tokenizers, decoders, trainers, processors\nfrom tokenizers.pre_tokenizers import Whitespace\nfrom tokenizers.processors import TemplateProcessing\nfrom tokenizers.trainers import BpeTrainer\n```\n\n## Setup Notes\n\n- No auth or remote service setup is required for local files or in-memory training.\n- A `Tokenizer` runs a pipeline of normalization, pre-tokenization, model, and post-processing.\n- Use `Tokenizer.save(...)` to persist the full tokenizer configuration, not just the vocabulary files.\n- `Tokenizer.from_pretrained(identifier, revision=\"...\", token=\"...\")` loads from a Hugging Face Hub repo that contains `tokenizer.json`.\n- For private Hub repos, pass the access token with the `token=` argument.\n- If you pass pre-tokenized input like `[\"already\", \"split\"]`, set `is_pretokenized=True`.\n\n## Core Usage\n\n### Load A Saved Or Hub-Hosted Tokenizer\n\n```python\nfrom tokenizers import Tokenizer\n\nlocal_tokenizer = Tokenizer.from_file(\"tokenizer.json\")\n\nhub_tokenizer = Tokenizer.from_pretrained(\n    \"bert-base-cased\",\n    revision=\"main\",\n)\n```\n\n`from_pretrained(...)` only works when the Hub repo includes a `tokenizer.json` file.\n\n### Encode, Pad, Truncate, And Inspect Alignments\n\n```python\nfrom tokenizers import Tokenizer\n\ntokenizer = Tokenizer.from_pretrained(\"bert-base-cased\")\n\ntokenizer.enable_truncation(max_length=16)\ntokenizer.enable_padding(\n    direction=\"right\",\n    pad_token=\"[PAD]\",\n    pad_id=0,\n)\n\nencoding = tokenizer.encode(\"Hello, y'all! How are you?\")\n\nprint(encoding.tokens)\nprint(encoding.ids)\nprint(encoding.attention_mask)\nprint(encoding.offsets)\nprint(encoding.word_ids)\n\ndecoded = tokenizer.decode(encoding.ids)\nprint(decoded)\n```\n\nUse alignment fields when you need to map model output back to source text spans:\n\n- `offsets` maps tokens back to character spans in the original text\n- `word_ids` maps tokens back to word positions, especially useful for pre-tokenized inputs and token classification tasks\n\n### Encode Batches\n\n```python\nbatch = tokenizer.encode_batch(\n    [\n        \"Hello, y'all!\",\n        \"How are you?\",\n        (\"Question?\", \"Answer.\"),\n    ]\n)\n\nfor item in batch:\n    print(item.tokens)\n```\n\n`encode_batch(...)` is the main high-throughput path. Padding applies across the batch once `enable_padding(...)` is active.\n\n### Train A BPE Tokenizer From Files\n\n```python\nfrom tokenizers import Tokenizer\nfrom tokenizers.models import BPE\nfrom tokenizers.pre_tokenizers import Whitespace\nfrom tokenizers.trainers import BpeTrainer\n\ntokenizer = Tokenizer(BPE(unk_token=\"[UNK]\"))\ntokenizer.pre_tokenizer = Whitespace()\n\ntrainer = BpeTrainer(\n    vocab_size=30_000,\n    min_frequency=2,\n    special_tokens=[\"[UNK]\", \"[CLS]\", \"[SEP]\", \"[PAD]\", \"[MASK]\"],\n)\n\ntokenizer.train(\n    [\"data/train.txt\", \"data/valid.txt\"],\n    trainer=trainer,\n)\n\ntokenizer.save(\"tokenizer.json\")\n```\n\nThe special token order matters during training. If you list `\"[UNK]\"` first, it gets the first special-token ID.\n\n### Train From An Iterator Instead Of Files\n\n```python\nfrom tokenizers import Tokenizer, models, trainers\nfrom tokenizers.pre_tokenizers import ByteLevel\n\ntokenizer = Tokenizer(models.BPE())\ntokenizer.pre_tokenizer = ByteLevel()\n\ntrainer = trainers.BpeTrainer(\n    vocab_size=20_000,\n    initial_alphabet=ByteLevel.alphabet(),\n    special_tokens=[\"<PAD>\", \"<BOS>\", \"<EOS>\"],\n)\n\ndef batch_iterator():\n    for batch in [\n        [\"first example\", \"second example\"],\n        [\"third example\"],\n    ]:\n        yield batch\n\ntokenizer.train_from_iterator(batch_iterator(), trainer=trainer, length=3)\ntokenizer.save(\"tokenizer.json\")\n```\n\nUse `train_from_iterator(...)` when your corpus already lives in memory, comes from a streaming dataset, or is too awkward to materialize as training files.\n\n### Add A Post-Processor For Model-Specific Special Tokens\n\n```python\nfrom tokenizers.processors import TemplateProcessing\n\ncls_id = tokenizer.token_to_id(\"[CLS]\")\nsep_id = tokenizer.token_to_id(\"[SEP]\")\n\ntokenizer.post_processor = TemplateProcessing(\n    single=\"[CLS] $A [SEP]\",\n    pair=\"[CLS] $A [SEP] $B:1 [SEP]:1\",\n    special_tokens=[\n        (\"[CLS]\", cls_id),\n        (\"[SEP]\", sep_id),\n    ],\n)\n```\n\nAfter this, `tokenizer.encode(...)` automatically inserts the configured special tokens.\n\n## Custom Pipeline Components\n\nWhen you need full control, compose the tokenizer from components directly:\n\n```python\nfrom tokenizers import Tokenizer, decoders, models, normalizers, pre_tokenizers\n\ntokenizer = Tokenizer(models.Unigram())\ntokenizer.normalizer = normalizers.NFKC()\ntokenizer.pre_tokenizer = pre_tokenizers.ByteLevel()\ntokenizer.decoder = decoders.ByteLevel()\n```\n\nThe main component families are:\n\n- `normalizers` for cleanup such as Unicode normalization or lowercasing\n- `pre_tokenizers` for splitting text before model tokenization\n- `models` for the actual tokenization algorithm, such as BPE or Unigram\n- `processors` for adding model-specific wrapping like `[CLS]` / `[SEP]`\n- `decoders` for converting token IDs back to readable text\n\n## Config And Auth\n\n### Local Usage\n\n- No config files are required.\n- No auth is needed for `from_file(...)`, `train(...)`, `train_from_iterator(...)`, `encode(...)`, or `decode(...)`.\n\n### Hugging Face Hub Usage\n\n```python\nfrom tokenizers import Tokenizer\n\ntokenizer = Tokenizer.from_pretrained(\n    \"org/private-tokenizer\",\n    revision=\"main\",\n    token=\"hf_...\",\n)\n```\n\n- `identifier` is the Hub repo ID.\n- `revision` can be a branch or commit.\n- `token` is only needed for private repositories.\n\nPin `revision` when reproducibility matters.\n\n## Common Pitfalls\n\n- The public docs site currently surfaces `main v0.20.3` pages. Some examples and install claims are older than the current PyPI release.\n- Do not assume the padding token exists. Add it during training or via special tokens before calling `enable_padding(...)`.\n- Do not hardcode special-token IDs unless you control tokenizer creation. Use `token_to_id(...)`.\n- `Tokenizer.save(...)` writes the full tokenizer pipeline. If you only keep `vocab.json` and `merges.txt`, you can lose processor or normalization details.\n- `from_pretrained(...)` needs a Hub repo that actually contains `tokenizer.json`.\n- When feeding pre-tokenized input, remember `is_pretokenized=True`; otherwise the input shape is interpreted differently.\n- Batch padding is stateful on the tokenizer instance. Call `no_padding()` or reconfigure padding if later calls should not inherit it.\n- Truncation is also stateful. Call `no_truncation()` if a later code path expects full sequences.\n\n## Version-Sensitive Notes For 0.22.x\n\n- Version used here `0.22.2` matches the current PyPI latest release.\n- PyPI shows `tokenizers 0.22.2` released on January 5, 2026.\n- Hugging Face's docs site still exposes a selector headed by `main v0.20.3`, so the usage docs are helpful but not fully synchronized with the newest package release.\n- The `0.22.0` release notes mention new stream work and native async binding work.\n- The `0.22.2` release notes focus on added-token deserialization, typing stub updates, and a PyO3 0.26 bump.\n- If you rely on behavior added in `0.22.x`, verify against the exact release notes or repository code instead of assuming the docs site reflects the latest package state.\n\n## Official Sources\n\n- Docs root: https://huggingface.co/docs/tokenizers/index\n- Quicktour: https://huggingface.co/docs/tokenizers/quicktour\n- Installation: https://huggingface.co/docs/tokenizers/installation\n- Pipeline: https://huggingface.co/docs/tokenizers/pipeline\n- Components: https://huggingface.co/docs/tokenizers/components\n- Tokenizer API: https://huggingface.co/docs/tokenizers/api/tokenizer\n- Encoding API: https://huggingface.co/docs/tokenizers/api/encoding\n- Trainers API: https://huggingface.co/docs/tokenizers/api/trainers\n- Training from memory: https://huggingface.co/docs/tokenizers/training_from_memory\n- PyPI: https://pypi.org/project/tokenizers/\n- GitHub releases: https://github.com/huggingface/tokenizers/releases/tag/v0.22.0 and https://github.com/huggingface/tokenizers/releases/tag/v0.22.2\n"
  },
  {
    "path": "content/toml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Python toml package guide for parsing and writing TOML files and strings\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.10.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"toml,python,config,serialization,parser\"\n---\n\n# toml Python Package Guide\n\n## Golden Rule\n\nUse the official `toml` package APIs:\n\n- `toml.load()` to parse TOML from a file path, file object, or list of file paths\n- `toml.loads()` to parse TOML from a string\n- `toml.dump()` to write TOML to a writable file object\n- `toml.dumps()` to produce a TOML string\n\nAs of March 13, 2026, PyPI still lists `0.10.2` as the latest release for `toml`.\n\nThis package does not need environment variables, authentication, or client initialization. Import the module and call its functions directly.\n\n## Install\n\nCreate a virtual environment and pin the package version your project expects:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"toml==0.10.2\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"toml==0.10.2\"\npoetry add \"toml==0.10.2\"\n```\n\nPyPI metadata for `0.10.2` declares `Python >=2.6` and excludes Python `3.0` through `3.2`. In modern projects, the practical question is whether you need `toml` at all:\n\n- If you need both parsing and writing TOML, `toml` provides both.\n- If you only need parsing on Python 3.11+, the standard library `tomllib` can parse TOML but does not write it.\n\n## Initialize\n\nThere is no client object:\n\n```python\nimport toml\n```\n\nIf your app expects a specific mapping type, pass `_dict` when loading:\n\n```python\nfrom collections import OrderedDict\nimport toml\n\ndata = toml.loads(\n    \"\"\"\n    [tool.black]\n    line-length = 88\n    \"\"\",\n    _dict=OrderedDict,\n)\n```\n\n## Parse TOML\n\n### Parse a string\n\n```python\nimport toml\n\ntoml_text = \"\"\"\ntitle = \"demo\"\n\n[database]\nserver = \"db.internal\"\nports = [8001, 8002]\nenabled = true\n\"\"\"\n\ndata = toml.loads(toml_text)\n\nprint(data[\"title\"])\nprint(data[\"database\"][\"server\"])\n```\n\n### Parse a file path\n\n```python\nimport toml\n\nconfig = toml.load(\"pyproject.toml\")\nprint(config[\"build-system\"][\"requires\"])\n```\n\n### Parse an already opened file\n\n```python\nimport toml\n\nwith open(\"settings.toml\", \"r\", encoding=\"utf-8\") as f:\n    settings = toml.load(f)\n```\n\n### Parse multiple files into one object\n\n`toml.load()` also accepts a list of file paths:\n\n```python\nimport toml\n\nconfig = toml.load([\"base.toml\", \"local.toml\"])\n```\n\nThe maintainer API reference documents this as reading multiple TOML files into a single returned object. Do not assume comment, formatting, or source-file boundaries are preserved.\n\n## Write TOML\n\n### Serialize a Python object to a string\n\n```python\nimport toml\n\npayload = {\n    \"title\": \"demo\",\n    \"database\": {\n        \"server\": \"db.internal\",\n        \"ports\": [8001, 8002],\n        \"enabled\": True,\n    },\n}\n\ntoml_text = toml.dumps(payload)\nprint(toml_text)\n```\n\n### Write TOML to a file\n\n```python\nimport toml\n\npayload = {\n    \"tool\": {\n        \"pytest\": {\n            \"ini_options\": {\n                \"testpaths\": [\"tests\"],\n            }\n        }\n    }\n}\n\nwith open(\"generated.toml\", \"w\", encoding=\"utf-8\") as f:\n    toml.dump(payload, f)\n```\n\n`toml.dump()` writes to the file object and also returns the TOML string it wrote.\n\n### Values the encoder handles directly\n\nThe encoder source handles these Python types directly:\n\n- `str`\n- `list`\n- `bool`\n- `int`\n- `float`\n- `decimal.Decimal`\n- `datetime.datetime`\n- `datetime.date`\n- `datetime.time`\n- nested `dict`-like objects\n\nExample with dates and decimals:\n\n```python\nfrom datetime import date\nfrom decimal import Decimal\nimport toml\n\npayload = {\n    \"price\": Decimal(\"19.99\"),\n    \"released\": date(2026, 3, 13),\n}\n\nprint(toml.dumps(payload))\n```\n\n## Common Workflows\n\n### Load, update, and write a TOML config file\n\n```python\nimport toml\n\nconfig = toml.load(\"pyproject.toml\")\nconfig.setdefault(\"tool\", {})\nconfig[\"tool\"][\"example\"] = {\"enabled\": True, \"retries\": 3}\n\nwith open(\"pyproject.toml\", \"w\", encoding=\"utf-8\") as f:\n    toml.dump(config, f)\n```\n\n### Serialize NumPy values\n\nPyPI documents `TomlNumpyEncoder` for NumPy float and integer dtypes:\n\n```python\nimport numpy as np\nimport toml\n\npayload = {\"values\": np.arange(0, 3, dtype=np.double)}\ntoml_text = toml.dumps(payload, encoder=toml.TomlNumpyEncoder())\nprint(toml_text)\n```\n\nWithout that encoder, the project description notes that NumPy float types are emitted as strings.\n\n### Serialize `pathlib.Path` objects\n\nThe encoder module also includes `TomlPathlibEncoder`:\n\n```python\nfrom pathlib import Path\nimport toml\nfrom toml.encoder import TomlPathlibEncoder\n\npayload = {\n    \"paths\": {\n        \"build_dir\": Path(\"dist\"),\n        \"config_file\": Path(\"config/app.toml\"),\n    }\n}\n\ntoml_text = toml.dumps(payload, encoder=TomlPathlibEncoder())\nprint(toml_text)\n```\n\n### Control array formatting\n\nUse `TomlArraySeparatorEncoder` if you need a specific separator style in arrays:\n\n```python\nimport toml\nfrom toml.encoder import TomlArraySeparatorEncoder\n\npayload = {\"ports\": [8001, 8002, 8003]}\n\ntoml_text = toml.dumps(\n    payload,\n    encoder=TomlArraySeparatorEncoder(separator=\", \"),\n)\nprint(toml_text)\n```\n\nThe encoder source only accepts separators composed of commas and whitespace. Other values raise `ValueError`.\n\n## Common Pitfalls\n\n- `toml.dump()` expects a writable file object, not a path string. `toml.dump(data, \"file.toml\")` raises `TypeError`; open the file first.\n- `toml.loads()` only accepts a TOML string. Use `toml.load()` for file paths, file objects, or lists of paths.\n- Re-serializing data does not preserve the original text layout. The PyPI quick tutorial shows arrays rewritten with trailing commas and datetime output rendered differently from the original input text.\n- If your application only needs TOML parsing on Python 3.11+, `tomllib` is simpler and built in. Keep `toml` when you need write support or compatibility with an existing `toml`-based code path.\n\n## Version Notes\n\n- PyPI lists `0.10.2` as the latest release, published on November 1, 2020.\n- The public API documented on PyPI for `0.10.2` is the four-function surface: `load`, `loads`, `dump`, and `dumps`.\n- The package source also exposes encoder classes for specialized serialization, including NumPy arrays, custom array separators, inline-table preservation, comment preservation, and `pathlib.Path` values.\n\n## Official Sources\n\n- PyPI project page: https://pypi.org/project/toml/\n- PyPI `0.10.2` page and API reference: https://pypi.org/project/toml/0.10.2/\n- Maintainer repository: https://github.com/uiri/toml\n- Encoder source: https://raw.githubusercontent.com/uiri/toml/master/toml/encoder.py\n- Python `tomllib` docs: https://docs.python.org/3.11/library/tomllib.html\n"
  },
  {
    "path": "content/tomli/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tomli package guide for parsing TOML in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.4.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tomli,toml,configuration,parser,python,tomllib\"\n---\n\n# tomli Python Package Guide\n\n## Golden Rule\n\nUse `tomli` when you need a TOML parser dependency that works on Python 3.8-3.10, or when you want one parser dependency across mixed Python versions.\n\nFor Python 3.11 and newer, the standard library `tomllib` module is the built-in equivalent API for the common `load()` and `loads()` workflow. `tomli` remains useful as the PyPI backport and may also be chosen explicitly for consistency or wheel performance.\n\n`tomli` is read-only. It parses TOML into Python objects, but it does not write TOML back out.\n\n## Install\n\nInstall a pinned version:\n\n```bash\npip install tomli==2.4.0\n```\n\nWith `uv`:\n\n```bash\nuv add tomli\n```\n\nWith Poetry:\n\n```bash\npoetry add tomli\n```\n\nFor libraries that should only depend on `tomli` when `tomllib` is unavailable:\n\n```toml\n[project]\ndependencies = [\n  'tomli>=1.1.0; python_version < \"3.11\"',\n]\n```\n\nEquivalent `requirements.txt` entry:\n\n```text\ntomli>=1.1.0; python_version < \"3.11\"\n```\n\n## Initialization And Setup\n\n### Standard compatibility import\n\nUse the stdlib on Python 3.11+ and fall back to `tomli` elsewhere:\n\n```python\nimport sys\n\nif sys.version_info >= (3, 11):\n    import tomllib\nelse:\n    import tomli as tomllib\n```\n\nThis lets the rest of your code call `tomllib.load()` and `tomllib.loads()` on every supported version.\n\n### Reading TOML files\n\n`load()` requires a binary file object:\n\n```python\nfrom pathlib import Path\nimport sys\n\nif sys.version_info >= (3, 11):\n    import tomllib\nelse:\n    import tomli as tomllib\n\nwith Path(\"pyproject.toml\").open(\"rb\") as f:\n    data = tomllib.load(f)\n```\n\nIf you already have TOML text in memory, use `loads()` instead:\n\n```python\nimport tomli\n\nconfig = tomli.loads(\"\"\"\n[server]\nhost = \"127.0.0.1\"\nport = 8080\n\"\"\")\n```\n\n## Core Usage\n\n### Parse a TOML string\n\n```python\nimport tomli\n\ntoml_text = \"\"\"\n[[players]]\nname = \"Lehtinen\"\nnumber = 26\n\n[[players]]\nname = \"Numminen\"\nnumber = 27\n\"\"\"\n\ndata = tomli.loads(toml_text)\nassert data[\"players\"][0][\"name\"] == \"Lehtinen\"\n```\n\n### Parse a TOML file\n\n```python\nimport tomli\n\nwith open(\"settings.toml\", \"rb\") as f:\n    settings = tomli.load(f)\n\ndebug = settings[\"app\"][\"debug\"]\n```\n\n### Handle invalid TOML\n\n```python\nimport tomli\n\ntry:\n    tomli.loads(\"]] this is invalid TOML [[\")\nexcept tomli.TOMLDecodeError as exc:\n    print(f\"Invalid TOML: {exc}\")\n```\n\nTreat `TOMLDecodeError` messages as human-readable diagnostics, not stable API output.\n\n### Parse floats as `Decimal`\n\n```python\nfrom decimal import Decimal\nimport tomli\n\ndata = tomli.loads(\"price = 19.99\", parse_float=Decimal)\nassert data[\"price\"] == Decimal(\"19.99\")\n```\n\n`parse_float` must return a scalar numeric-like value. Returning `dict` or `list` raises `ValueError`.\n\n### Read `pyproject.toml`\n\n```python\nfrom pathlib import Path\nimport sys\n\nif sys.version_info >= (3, 11):\n    import tomllib\nelse:\n    import tomli as tomllib\n\nwith Path(\"pyproject.toml\").open(\"rb\") as f:\n    pyproject = tomllib.load(f)\n\nproject = pyproject.get(\"project\", {})\nname = project.get(\"name\")\ndependencies = project.get(\"dependencies\", [])\n```\n\n## Config And Environment Notes\n\n- `tomli` has no network layer, credentials, auth flow, or service configuration.\n- The main setup choice is whether your project should import `tomllib`, `tomli`, or a compatibility alias.\n- `load()` is for binary file objects. `loads()` is for already-decoded strings.\n- If you need to write TOML, pair `tomli` with a separate writer such as `tomli-w`.\n\n## Common Pitfalls\n\n### Opening files in text mode\n\nThis is wrong:\n\n```python\nimport tomli\n\nwith open(\"settings.toml\", \"r\", encoding=\"utf-8\") as f:\n    data = tomli.load(f)\n```\n\nUse binary mode instead:\n\n```python\nimport tomli\n\nwith open(\"settings.toml\", \"rb\") as f:\n    data = tomli.load(f)\n```\n\n### Expecting write support\n\n`tomli` does not provide `dump()`, `dumps()`, or file-writing helpers. Use `tomli-w` or another TOML writer when you need round-trip output.\n\n### Building logic around error message text\n\nDo not assert exact `TOMLDecodeError` message strings in tests or production logic. Upstream treats them as informational and they may change across releases.\n\n### Mixing version assumptions\n\n`tomli 2.4.0` and later are compatible with TOML `v1.1.0`. Older `tomli` releases were only TOML `v1.0.0` compatible. If you copy older examples or review older bug reports, make sure the syntax matches the installed parser version.\n\n## Version-Sensitive Notes\n\n- `2.4.0` is the current version specified for this doc and is published on PyPI as of January 11, 2026.\n- PyPI metadata for `2.4.0` requires Python `>=3.8`.\n- Python `3.11+` includes `tomllib` in the standard library, but `tomli` still has the same familiar parsing API and publishes compiled wheels for common platforms.\n- If your codebase only targets Python `3.11+` and does not need an external dependency, `tomllib` is usually the simpler default.\n- If your codebase spans Python `3.8+`, the compatibility import pattern above avoids branching the rest of your TOML parsing code.\n\n## Official Sources\n\n- Repository: https://github.com/hukkin/tomli\n- README: https://github.com/hukkin/tomli/blob/master/README.md\n- Changelog: https://github.com/hukkin/tomli/blob/master/CHANGELOG.md\n- PyPI: https://pypi.org/project/tomli/\n"
  },
  {
    "path": "content/tomli-w/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tomli-w guide for writing TOML documents from Python data structures\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"tomli-w,toml,python,serialization,config\"\n---\n\n# tomli-w Python Package Guide\n\n## Golden Rule\n\nUse `tomli-w` when you need to serialize Python data to TOML 1.0.0. The import name is `tomli_w`, and the two public entry points are:\n\n- `tomli_w.dumps(obj, *, multiline_strings=False, indent=4)` -> `str`\n- `tomli_w.dump(obj, fp, *, multiline_strings=False, indent=4)` -> writes `bytes` to a binary file object\n\n`tomli-w` is a writer only. It does not read TOML and it does not require environment variables, authentication, or client initialization.\n\n## Install\n\nFor the released `1.2.0` package, PyPI requires Python 3.9 or newer:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"tomli-w==1.2.0\"\n```\n\nIf you also want to parse the generated TOML in the same project, install a parser separately:\n\n```bash\npython -m pip install \"tomli-w==1.2.0\" tomli\n```\n\n## Basic Usage\n\nImport the module and pass a Python mapping to `dumps()`:\n\n```python\nfrom datetime import date\n\nimport tomli_w\n\ndata = {\n    \"title\": \"example\",\n    \"enabled\": True,\n    \"ports\": [8000, 8001],\n    \"release_date\": date(2026, 3, 13),\n    \"database\": {\n        \"host\": \"db.internal\",\n        \"port\": 5432,\n    },\n}\n\ntoml_text = tomli_w.dumps(data)\nprint(toml_text)\n```\n\nTypical output:\n\n```toml\ntitle = \"example\"\nenabled = true\nports = [\n    8000,\n    8001,\n]\nrelease_date = 2026-03-13\n\n[database]\nhost = \"db.internal\"\nport = 5432\n```\n\n## Write To A File\n\n`dump()` writes encoded TOML bytes, so open the target file in binary mode:\n\n```python\nimport tomli_w\n\npyproject_data = {\n    \"project\": {\n        \"name\": \"demo-app\",\n        \"version\": \"0.1.0\",\n    }\n}\n\nwith open(\"pyproject.generated.toml\", \"wb\") as f:\n    tomli_w.dump(pyproject_data, f)\n```\n\nIf you open the file with `\"w\"` instead of `\"wb\"`, `dump()` will fail because it writes bytes, not text.\n\n## Common Workflows\n\n### Arrays and nested tables\n\nLists become TOML arrays, and nested mappings become tables:\n\n```python\nimport tomli_w\n\ndata = {\n    \"service\": {\n        \"name\": \"billing\",\n        \"replicas\": 3,\n    },\n    \"allowed_hosts\": [\"api.internal\", \"worker.internal\"],\n}\n\nprint(tomli_w.dumps(data))\n```\n\n### Control array indentation\n\nThe `indent` argument controls how many spaces are used for array items:\n\n```python\nimport tomli_w\n\ndata = {\"values\": [[1, 2], [3, 4]]}\n\nprint(tomli_w.dumps(data, indent=2))\n```\n\n### Emit multiline basic strings\n\nBy default, `tomli-w` escapes newline characters instead of using TOML multiline strings. Enable `multiline_strings=True` when you want triple-quoted output:\n\n```python\nimport tomli_w\n\ndata = {\n    \"message\": \"line one\\nline two\\n\",\n}\n\nprint(tomli_w.dumps(data, multiline_strings=True))\n```\n\nThis is useful for generated config files, but leave it off if exact newline-byte preservation matters.\n\n### Write `Decimal` values\n\n`1.2.0` preserves `Decimal` values in parse round trips instead of converting them to plain `float` strings:\n\n```python\nfrom decimal import Decimal\n\nimport tomli_w\n\ndata = {\n    \"price\": Decimal(\"19.99\"),\n}\n\nprint(tomli_w.dumps(data))\n```\n\n## Validate The Output\n\nThe maintainer README explicitly recommends validating generated TOML if your input might contain unusual values. A simple pattern is:\n\n```python\nimport sys\n\nimport tomli_w\n\nif sys.version_info >= (3, 11):\n    import tomllib\n\n    parse_toml = tomllib.loads\nelse:\n    import tomli\n\n    parse_toml = tomli.loads\n\ndata = {\n    \"title\": \"example\",\n    \"count\": 3,\n}\n\ntoml_text = tomli_w.dumps(data)\nparsed = parse_toml(toml_text)\nprint(parsed[\"title\"])\n```\n\n## Supported Value Shapes\n\n`tomli-w` is designed to serialize standard TOML-compatible Python values:\n\n- `str`, `bool`, `int`, `float`\n- `datetime.date`, `datetime.datetime`, and `datetime.time`\n- `decimal.Decimal`\n- `list` and `tuple`\n- nested mappings with string keys\n\nUse plain built-in values where possible. The maintainer docs warn that the library does not guarantee valid TOML for arbitrary subclasses or other exotic inputs.\n\n## Important Pitfalls\n\n- Install with `pip install tomli-w`, but import with `import tomli_w`.\n- `dump()` needs a binary file object opened with `\"wb\"`.\n- `tomli-w` only writes TOML. Use `tomli` or `tomllib` separately if you also need to parse TOML.\n- `multiline_strings` is `False` by default because converting embedded newlines to triple-quoted strings can change the exact byte representation.\n- Offset `datetime.time` values are not supported by TOML 1.0 and raise `ValueError`.\n- Comments are not part of the input model. `tomli-w` generates TOML from data structures; it does not preserve comments from an existing file.\n- If you need a specific output order, construct your mappings in that order before calling `dumps()`. `tomli-w` does not sort keys for you.\n\n## Version Notes For 1.2.0\n\n- PyPI metadata for `tomli-w 1.2.0` requires Python `>=3.9`.\n- `1.2.0` improves parse round trips so `Decimal` values stay `Decimal`.\n- Earlier `1.1.0` releases already dropped Python 3.7 and 3.8, so older runtimes are out of scope for the entire `1.2.x` line.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/hukkin/tomli-w\n- Maintainer README: https://github.com/hukkin/tomli-w#readme\n- PyPI release page: https://pypi.org/project/tomli-w/\n- Changelog: https://github.com/hukkin/tomli-w/blob/master/CHANGELOG.md\n"
  },
  {
    "path": "content/toolz/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"toolz Python package guide for functional utilities, iterable pipelines, and dictionary transforms\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"toolz,python,functional,iterators,pipelines,dictionaries\"\n---\n\n# toolz Python Package Guide\n\n## Golden Rule\n\nUse `toolz` when you need small, composable functional helpers over normal Python iterables, callables, and dictionaries. Favor `pipe()` for readable left-to-right pipelines, use `toolz.curried` when you want partial application inside a pipeline, and remember that many iterable helpers are lazy iterators that need to be consumed explicitly.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"toolz==1.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"toolz==1.1.0\"\npoetry add \"toolz==1.1.0\"\n```\n\n`toolz` is pure Python. If a codebase explicitly wants the compiled sibling package for speed, that is usually `cytoolz`, but do not swap dependencies silently if the project is pinned to `toolz`.\n\n## Setup And Import Patterns\n\n`toolz` is a local utility library. There is no auth, service config, or runtime initialization step beyond installation and imports.\n\nCommon import styles:\n\n```python\nfrom toolz import compose, pipe\nfrom toolz.dicttoolz import assoc_in, update_in, valmap\nfrom toolz.itertoolz import groupby, pluck, reduceby\n```\n\nFor pipeline-heavy code, the curried namespace is often cleaner:\n\n```python\nfrom toolz.curried import filter, map, partition_all, pipe\n```\n\nUse narrow imports in application code when you want clearer ownership of helpers. Use `toolz.curried` when the code is intentionally pipeline-oriented.\n\n## Core Usage\n\n### Build readable pipelines with `pipe`\n\n`pipe(value, f, g, h)` applies functions left to right and is usually easier to read than nested calls.\n\n```python\nfrom toolz import pipe\nfrom toolz.curried import filter, map, take\n\nresult = pipe(\n    [1, 2, 3, 4, 5, 6],\n    filter(lambda x: x % 2 == 0),\n    map(lambda x: x * 10),\n    take(2),\n    list,\n)\n\nprint(result)  # [20, 40]\n```\n\n### Reuse logic with `compose` and `curry`\n\nUse `compose()` when you need a reusable function object. Composition runs right to left.\n\n```python\nfrom toolz import compose, curry\n\n@curry\ndef clamp(low, high, value):\n    return max(low, min(high, value))\n\nnormalize_score = compose(clamp(0, 100), int)\n\nprint(normalize_score(\"104\"))  # 100\n```\n\nUse `pipe()` for one-off flows and `compose()` for reusable transformations.\n\n### Prefer `reduceby` over `groupby` for large streams\n\n`groupby()` collects every matching item into lists. That is convenient for small inputs, but it materializes the whole grouping in memory.\n\n```python\nfrom toolz.itertoolz import reduceby\n\nrows = [\n    {\"team\": \"red\", \"points\": 3},\n    {\"team\": \"blue\", \"points\": 5},\n    {\"team\": \"red\", \"points\": 7},\n]\n\ntotals = reduceby(\n    key=lambda row: row[\"team\"],\n    binop=lambda acc, row: acc + row[\"points\"],\n    seq=rows,\n    init=0,\n)\n\nprint(totals)  # {'red': 10, 'blue': 5}\n```\n\nFor log-style or iterator-driven workloads, `reduceby()` is usually the safer default.\n\n### Update nested dictionaries without manual copying\n\n`dicttoolz` is useful when you want immutable-style updates to nested structures.\n\n```python\nfrom toolz.dicttoolz import assoc_in, update_in\n\nconfig = {\n    \"db\": {\"host\": \"localhost\", \"port\": 5432},\n    \"features\": {\"beta\": False},\n}\n\nnext_config = assoc_in(config, [\"db\", \"host\"], \"db.internal\")\nnext_config = update_in(next_config, [\"db\", \"port\"], lambda port: port + 1)\n\nprint(next_config)\n```\n\nUseful dictionary helpers:\n\n- `assoc()` and `assoc_in()` return updated copies\n- `update_in()` transforms an existing nested value\n- `merge()` performs a shallow merge\n- `valmap()` and `itemmap()` transform dictionary values or items\n\n### Work with iterables lazily\n\nMany `toolz.itertoolz` and `toolz.curried` helpers return iterators. Consume them with `list()`, `tuple()`, `set()`, `dict()`, `next()`, or a loop when you need actual values.\n\n```python\nfrom toolz.curried import map, partition_all, pipe\n\nbatches = pipe(\n    range(10),\n    map(lambda x: x + 1),\n    partition_all(4),\n    list,\n)\n\nprint(batches)  # [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10)]\n```\n\nCommon iterable helpers agents reach for:\n\n- `pluck(\"field\", rows)` for extracting a key from each mapping\n- `partition_all(n, seq)` for batching\n- `concat(seqs)` and `concatv(*seqs)` for flattening\n- `unique(seq)` for preserving first-seen order\n- `frequencies(seq)` for counting values\n\n## Configuration Notes\n\n- There is no global runtime configuration file.\n- The important setup decision is import style: plain namespace imports for explicitness, or `toolz.curried` for partial-application-heavy pipelines.\n- `toolz` is synchronous. It works fine inside async code for local data transforms, but it does not provide async iterators, IO helpers, or scheduler integration.\n\n## Common Pitfalls\n\n- `compose()` runs functions right to left. If the code needs left-to-right readability, use `pipe()`.\n- Helpers imported from `toolz.curried` often return lazy iterators. Materialize them before indexing, serializing, or reusing them twice.\n- `groupby()` can consume large amounts of memory because it stores full lists per key. Use `reduceby()` or explicit streaming reductions for large inputs.\n- `merge()` is shallow. For nested updates, use `assoc_in()` or `update_in()` instead of expecting a deep merge.\n- Generators are one-shot. If a pipeline consumes an iterator once, later stages cannot replay it unless you re-create or cache it.\n- `join()` is not a database engine. Be deliberate about which side is smaller and whether materialization is acceptable.\n- `curry` changes call style. That is useful, but it can make debugging signatures less obvious if overused across a large codebase.\n\n## Version-Sensitive Notes For `1.1.0`\n\n- The version used here `1.1.0` matches the live PyPI release as of March 12, 2026.\n- The repository metadata for `1.1.0` requires Python `>=3.9`, so older Python 3.8 environments need an older `toolz` release.\n- `toolz` remains a lightweight utility package with stable core namespaces (`functoolz`, `itertoolz`, `dicttoolz`, and `curried`). For most code generation tasks, the bigger risk is copying examples that accidentally mix eager Python built-ins with lazy `toolz` iterators.\n\n## Official Sources\n\n- Docs root: https://toolz.readthedocs.io/en/latest/\n- Installation docs: https://toolz.readthedocs.io/en/latest/install.html\n- API index: https://toolz.readthedocs.io/en/latest/api.html\n- Curry and curried namespace docs: https://toolz.readthedocs.io/en/latest/curry.html\n- Streaming analytics notes: https://toolz.readthedocs.io/en/latest/streaming-analytics.html\n- PyPI package page: https://pypi.org/project/toolz/\n- Repository metadata: https://github.com/pytoolz/toolz/blob/master/pyproject.toml\n"
  },
  {
    "path": "content/torch/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"PyTorch torch package guide for tensors, autograd, modules, device placement, and model save/load workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"torch,pytorch,python,deep-learning,tensors,autograd,nn,training\"\n---\n\n# PyTorch `torch` Python Package Guide\n\n## Golden Rule\n\nUse the official `torch` package, import it as `import torch`, choose the execution device explicitly, and prefer `state_dict` save/load flows over pickled whole-model checkpoints. For accelerator installs, use the official PyTorch install selector instead of guessing wheel indexes from older blog posts.\n\n## Install\n\nBase install with an exact pin:\n\n```bash\npython -m pip install \"torch==2.10.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"torch==2.10.0\"\npoetry add \"torch==2.10.0\"\n```\n\nImportant install note:\n\n- CPU-only and many local development flows can start from the pinned PyPI package above.\n- CUDA or ROCm installs may require an official PyTorch wheel index and a command generated from `https://pytorch.org/get-started/locally/`.\n- On Apple Silicon, check `mps` availability after install instead of assuming GPU support is active.\n\nVerify the runtime you actually got:\n\n```python\nimport torch\n\nprint(torch.__version__)\nprint(\"cuda:\", torch.cuda.is_available())\nprint(\"mps:\", torch.backends.mps.is_available())\n```\n\n## Initialize And Set Up\n\nPick a device once and move both models and tensors onto it:\n\n```python\nimport torch\n\nif torch.cuda.is_available():\n    device = torch.device(\"cuda\")\nelif torch.backends.mps.is_available():\n    device = torch.device(\"mps\")\nelse:\n    device = torch.device(\"cpu\")\n\ntorch.manual_seed(0)\n```\n\nCreate tensors directly on the target device when practical:\n\n```python\nx = torch.randn(4, 3, device=device)\ny = torch.zeros(4, 3, device=device)\n```\n\nIf you already have a tensor or module on CPU, move it explicitly:\n\n```python\nx = x.to(device)\nmodel = model.to(device)\n```\n\n## Core Usage\n\n### Tensors And Basic Ops\n\n```python\nimport torch\n\nx = torch.tensor([[1.0, 2.0], [3.0, 4.0]])\ny = torch.tensor([[5.0, 6.0], [7.0, 8.0]])\n\nprint(x + y)\nprint(x @ y)\nprint(x.shape, x.dtype)\n```\n\n### Autograd\n\n```python\nimport torch\n\nx = torch.tensor([2.0], requires_grad=True)\ny = x**2 + 3 * x\ny.backward()\n\nprint(x.grad)  # dy/dx = 2x + 3\n```\n\n### Define And Train A Small Model\n\n```python\nimport torch\nfrom torch import nn\nfrom torch.utils.data import DataLoader, TensorDataset\n\nif torch.cuda.is_available():\n    device = torch.device(\"cuda\")\nelif torch.backends.mps.is_available():\n    device = torch.device(\"mps\")\nelse:\n    device = torch.device(\"cpu\")\n\nfeatures = torch.randn(256, 10)\nlabels = torch.randint(0, 2, (256,))\nloader = DataLoader(TensorDataset(features, labels), batch_size=32, shuffle=True)\n\nmodel = nn.Sequential(\n    nn.Linear(10, 32),\n    nn.ReLU(),\n    nn.Linear(32, 2),\n).to(device)\n\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\n\nmodel.train()\nfor batch_x, batch_y in loader:\n    batch_x = batch_x.to(device)\n    batch_y = batch_y.to(device)\n\n    optimizer.zero_grad()\n    logits = model(batch_x)\n    loss = loss_fn(logits, batch_y)\n    loss.backward()\n    optimizer.step()\n```\n\n### Inference\n\nUse `eval()` plus `torch.inference_mode()` for prediction code:\n\n```python\nmodel.eval()\n\nwith torch.inference_mode():\n    sample = torch.randn(1, 10, device=device)\n    probs = torch.softmax(model(sample), dim=-1)\n    predicted_class = probs.argmax(dim=-1).item()\n```\n\n### Save And Load Weights\n\nPrefer `state_dict` checkpoints:\n\n```python\nimport torch\nfrom torch import nn\n\nmodel = nn.Linear(10, 2)\ntorch.save(model.state_dict(), \"model.pt\")\n\nrestored = nn.Linear(10, 2)\nstate_dict = torch.load(\"model.pt\", map_location=\"cpu\", weights_only=True)\nrestored.load_state_dict(state_dict)\nrestored.eval()\n```\n\n## Configuration Notes\n\nThere is no service authentication layer in `torch`. The main configuration decisions are runtime and execution behavior:\n\n- Device selection: `cpu`, `cuda`, or `mps`\n- Numeric precision and dtype choices\n- Batch size and `DataLoader` worker count\n- Checkpoint device mapping during `torch.load(...)`\n\nPractical defaults:\n\n- Keep device selection explicit with `torch.device(...)` and `.to(device)`.\n- Use `map_location=\"cpu\"` when loading checkpoints on machines that may not have the original accelerator.\n- Start with small `num_workers` values in `DataLoader`; worker behavior differs by platform and environment.\n- Only introduce `torch.compile(...)` after the model works correctly in eager mode.\n\n## Common Pitfalls\n\n- Model parameters and input tensors must be on the same device. Mixed-device mistakes are one of the most common `RuntimeError` causes.\n- Move the model to GPU before creating the optimizer if the optimizer should track GPU parameters.\n- `model.train()` and `model.eval()` are not interchangeable. Dropout and batch normalization behave differently.\n- Use `torch.inference_mode()` or `torch.no_grad()` for inference; otherwise PyTorch keeps autograd bookkeeping you do not need.\n- Prefer `DistributedDataParallel` over `DataParallel` for multi-GPU training.\n- Cross-GPU tensor ops are not generally allowed except for explicit copy-like operations such as `to(...)`, `copy_()`, or `cuda(...)`.\n- Save and load `state_dict`s rather than whole module objects when you want safer, more portable checkpoints.\n\n## Version-Sensitive Notes For `2.10.0`\n\n- PyPI lists `torch 2.10.0` and Python `>=3.10` for this package version.\n- The official PyTorch install-helper pages were not fully in sync on 2026-03-12: `get-started/locally` still surfaced `Stable (2.7.0)` and `previous-versions` still highlighted `v2.9.1`. Do not treat those labels as the package-version source of truth when pinning `2.10.0`.\n- The stable serialization notes say that starting in `2.6`, `torch.load()` uses `weights_only=True` by default when `pickle_module` is not passed. Keeping `weights_only=True` explicit is still the clearest choice in agent-written code.\n- The stable CUDA notes deprecate older `torch.cuda.amp.autocast(...)` and `torch.cpu.amp.autocast(...)` entry points in favor of `torch.amp.autocast(\"cuda\", ...)` and `torch.amp.autocast(\"cpu\", ...)`.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/torch/`\n- PyPI JSON API: `https://pypi.org/pypi/torch/json`\n- PyTorch stable docs: `https://docs.pytorch.org/docs/stable/`\n- PyTorch quickstart tutorial: `https://docs.pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html`\n- PyTorch CUDA notes: `https://docs.pytorch.org/docs/stable/notes/cuda.html`\n- PyTorch serialization notes: `https://docs.pytorch.org/docs/stable/notes/serialization.html`\n- PyTorch install selector: `https://pytorch.org/get-started/locally/`\n"
  },
  {
    "path": "content/torchaudio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"torchaudio for Python: PyTorch-native audio transforms, datasets, and pretrained speech pipelines\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.10.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"torchaudio,pytorch,audio,speech,ml,asr\"\n---\n\n# torchaudio Python Package Guide\n\n## What It Is\n\n`torchaudio` is the PyTorch audio library. In current releases it is primarily for:\n\n- audio transforms and signal features\n- speech and audio models/pipelines\n- dataset wrappers for common public audio corpora\n- PyTorch-native tensor workflows on CPU or CUDA\n\nDo not treat it as a general-purpose media I/O library anymore. Since `torchaudio` 2.9, audio decode/encode convenience APIs are implemented through TorchCodec, and TorchAudio is in a maintenance phase focused on its core ML strengths.\n\n## Installation\n\n## Golden Rule\n\nInstall `torchaudio` and `torch` from the same release line. Do not mix `torchaudio==2.10.0` with an older or newer PyTorch build.\n\nThe official install page still links to the PyTorch install selector and correctly says `torchaudio` is compiled against a specific `torch` version, but the compatibility table visible under `/audio/stable/installation.html` is stale and only lists versions through `2.6.0`. For `2.10.0`, confirm the package version on PyPI and keep the `torch` release aligned.\n\n### Typical install\n\n```bash\npip install torch==2.10.0 torchaudio==2.10.0\n```\n\nIf you need the correct CUDA or platform-specific wheel, start from the PyTorch selector:\n\n- `https://pytorch.org/get-started/locally/`\n\n### Optional dependencies called out by the official docs\n\n```bash\npip install sentencepiece\npip install deep-phonemizer\n```\n\n- `sentencepiece` is required for Emformer RNN-T ASR examples.\n- `deep-phonemizer` is required for Tacotron2 text-to-speech examples.\n\n### Audio I/O in 2.9+\n\nIf you call `torchaudio.load()` or `torchaudio.save()` in new code, also install TorchCodec:\n\n```bash\npip install torchcodec\n```\n\n`torchaudio.load()` and `torchaudio.save()` now delegate to TorchCodec. TorchCodec uses FFmpeg under the hood for media decode/encode, so keep that dependency in mind when debugging runtime failures.\n\n## Basic Setup\n\n```python\nimport torch\nimport torchaudio\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nprint(torch.__version__)\nprint(torchaudio.__version__)\nprint(device)\n```\n\nFor package-sensitive code paths, fail early on mismatched versions:\n\n```python\nimport torch\nimport torchaudio\n\nif not torch.__version__.startswith(\"2.10.\"):\n    raise RuntimeError(f\"Expected torch 2.10.x, got {torch.__version__}\")\n\nif not torchaudio.__version__.startswith(\"2.10.\"):\n    raise RuntimeError(f\"Expected torchaudio 2.10.x, got {torchaudio.__version__}\")\n```\n\n## Core Usage\n\n## Load a waveform\n\n```python\nimport torchaudio\n\nwaveform, sample_rate = torchaudio.load(\"speech.wav\")\nprint(waveform.shape)  # [channels, time]\nprint(sample_rate)\n```\n\nCurrent behavior to remember:\n\n- `torchaudio.load()` returns `float32` tensors.\n- `normalize=False` no longer restores old integer semantics; TorchCodec always returns normalized float32.\n- `backend` and `buffer_size` are accepted for compatibility but ignored.\n- `uri` can be a path, URL, or file-like object.\n\nFor new performance-sensitive decode paths, prefer native TorchCodec decoders instead of treating `torchaudio.load()` as the long-term primary API.\n\n## Resample audio\n\nUse the functional API for one-off resampling:\n\n```python\nimport torchaudio\n\nwaveform_16k = torchaudio.functional.resample(waveform, sample_rate, 16_000)\n```\n\nUse the transform when you will reuse the same sample-rate conversion repeatedly:\n\n```python\nimport torchaudio\n\nresample = torchaudio.transforms.Resample(orig_freq=48_000, new_freq=16_000)\nwaveform_16k = resample(waveform)\n```\n\nImportant precision note from the official `Resample` docs:\n\n- `torchaudio.transforms.Resample` caches its kernel and may lose a small amount of precision for inputs above `float32`.\n- If high precision matters, use `torchaudio.functional.resample(...)` or configure the transform to cache a higher-precision kernel.\n\n## Extract audio features\n\n```python\nimport torchaudio\n\nmel = torchaudio.transforms.MelSpectrogram(\n    sample_rate=16_000,\n    n_fft=400,\n    hop_length=160,\n    n_mels=80,\n)\n\nfeatures = mel(waveform_16k)  # [channels, n_mels, time]\n```\n\n`MelSpectrogram` is one of the core transforms that remains squarely in TorchAudio’s supported ML-focused surface area.\n\n## Run a pretrained ASR pipeline\n\n```python\nimport torch\nimport torchaudio\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nbundle = torchaudio.pipelines.WAV2VEC2_ASR_BASE_960H\nmodel = bundle.get_model().to(device)\n\nwaveform, sample_rate = torchaudio.load(\"speech.wav\")\nwaveform = waveform.to(device)\n\nif sample_rate != bundle.sample_rate:\n    waveform = torchaudio.functional.resample(\n        waveform, sample_rate, bundle.sample_rate\n    )\n\nwith torch.inference_mode():\n    emissions, _ = model(waveform)\n\nlabels = bundle.get_labels()\nprint(bundle.sample_rate)\nprint(labels[:8])\nprint(emissions.shape)\n```\n\nWhat the bundle gives you:\n\n- `bundle.sample_rate`\n- `bundle.get_labels()`\n- `bundle.get_model()`\n\nThe official tutorial also shows a simple greedy CTC decoder built from `bundle.get_labels()`.\n\n## Use built-in datasets\n\n```python\nimport torchaudio\n\ndataset = torchaudio.datasets.YESNO(\"./data/yesno\", download=True)\nwaveform, sample_rate, labels = dataset[0]\n```\n\nDataset wrappers are still a first-class use case. The dataset APIs typically return waveform tensors plus metadata such as sample rate, labels, transcripts, or speaker identifiers depending on the dataset.\n\n## Save audio\n\n```python\nimport torch\nimport torchaudio\n\naudio = torch.clamp(waveform_16k, -1.0, 1.0).to(torch.float32)\ntorchaudio.save(\"out.wav\", audio, sample_rate=16_000)\n```\n\nCurrent save behavior:\n\n- `torchaudio.save()` uses TorchCodec’s `AudioEncoder`.\n- input must be `float32` in `[-1, 1]`\n- output format is determined by the filename extension\n- old parameters like `format`, `encoding`, `bits_per_sample`, and `backend` are compatibility shims and should not be the basis of new code\n\n## Config And Auth\n\nThere is no package-level auth or service configuration model.\n\nWhat usually matters instead:\n\n- model bundles may download weights on first use\n- dataset helpers may download public archives when `download=True`\n- your runtime needs outbound network access and writable cache/storage paths for those downloads\n- pretrained models and datasets can have separate licenses or usage restrictions; check the dataset/model notes before shipping them in a product\n\n## Common Pitfalls\n\n- Version mismatch: `torchaudio` wheels are built against specific PyTorch releases. If import or extension loading fails, check that `torch` and `torchaudio` are on the same release line first.\n- Assuming old backend behavior: code that depends on `sox_io`, `soundfile`, explicit backend selection, or old integer decode behavior is likely from pre-2.9 assumptions.\n- Relying on ignored parameters: in current `load()` and `save()` implementations, several legacy parameters are accepted but ignored because TorchCodec is underneath.\n- Forgetting TorchCodec: a missing `torchcodec` installation now causes `ImportError` for `torchaudio.load()` and `torchaudio.save()`.\n- Forgetting sample-rate alignment: many pretrained pipelines expect a fixed sample rate. Resample before inference.\n- Treating it like a general multimedia toolkit: the project is intentionally narrower now. Prefer TorchCodec for media decode/encode primitives and keep TorchAudio for transforms, models, pipelines, and datasets.\n\n## Version-Sensitive Notes For 2.10.0\n\n- PyPI shows `torchaudio 2.10.0` released on `2026-01-21`.\n- The maintainers’ 2026-01-22 update on issue `pytorch/audio#3902` says `2.10` completes the migration to the maintenance-phase scope.\n- Most of `transforms`, `functional`, `compliance.kaldi`, `models`, and `pipelines` remain part of the supported surface.\n- The same maintainer update says `lfilter`, `RNNTLoss`, `CUCT`, `forced_align`, and `overdrive` were preserved even though they were originally planned for removal.\n- Parts of the official docs site chrome under `/audio/stable/` are inconsistent: some pages still display stale \"Old version\" or `2.8.0a0` navigation labels while their API bodies document the newer behavior. Trust the page body plus PyPI release history when checking `2.10.0` specifics.\n\n## Official Sources\n\n- Docs root: `https://docs.pytorch.org/audio/stable/`\n- Install guide: `https://docs.pytorch.org/audio/stable/installation.html`\n- `torchaudio.load`: `https://docs.pytorch.org/audio/stable/generated/torchaudio.load.html`\n- `torchaudio.save`: `https://docs.pytorch.org/audio/stable/generated/torchaudio.save.html`\n- `torchaudio.transforms.Resample`: `https://docs.pytorch.org/audio/stable/generated/torchaudio.transforms.Resample.html`\n- `torchaudio.transforms.MelSpectrogram`: `https://docs.pytorch.org/audio/stable/generated/torchaudio.transforms.MelSpectrogram.html`\n- Speech recognition tutorial: `https://docs.pytorch.org/audio/stable/tutorials/speech_recognition_pipeline_tutorial.html`\n- Audio datasets tutorial: `https://docs.pytorch.org/audio/stable/tutorials/audio_datasets_tutorial.html`\n- YESNO dataset reference: `https://docs.pytorch.org/audio/stable/generated/torchaudio.datasets.YESNO.html`\n- PyPI package page: `https://pypi.org/project/torchaudio/`\n- Upstream repository: `https://github.com/pytorch/audio`\n- Maintainer migration note: `https://github.com/pytorch/audio/issues/3902`\n- TorchCodec install docs: `https://github.com/pytorch/torchcodec#installing-torchcodec`\n"
  },
  {
    "path": "content/torchmetrics/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"TorchMetrics package guide for Python - metric modules and functional metrics for PyTorch and Lightning\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"torchmetrics,pytorch,lightning,metrics,evaluation,ml\"\n---\n\n# torchmetrics Python Package Guide\n\n## Golden Rule\n\nUse `torchmetrics` when you need metrics that work with PyTorch tensors, streaming updates, distributed reduction, and PyTorch Lightning logging.\n\n- Use **module metrics** such as `MulticlassAccuracy` when you need stateful accumulation across batches or epochs.\n- Use **functional metrics** for one-off batch calculations where you do not need internal state.\n\n## Install\n\n`torchmetrics` is an add-on to PyTorch. Install the PyTorch build your environment needs first, then install `torchmetrics`.\n\n```bash\npip install torchmetrics==1.9.0\n```\n\n`uv` and Poetry equivalents:\n\n```bash\nuv add torchmetrics==1.9.0\npoetry add torchmetrics==1.9.0\n```\n\nOptional extras from the upstream package metadata:\n\n```bash\npip install \"torchmetrics[audio]==1.9.0\"\npip install \"torchmetrics[image]==1.9.0\"\npip install \"torchmetrics[text]==1.9.0\"\npip install \"torchmetrics[visual]==1.9.0\"\npip install \"torchmetrics[all]==1.9.0\"\n```\n\n## Core Usage\n\n### Functional metrics\n\nUse the functional API when you already have a batch of predictions and targets and only need the result for that batch.\n\n```python\nimport torch\nfrom torchmetrics.functional.classification import multiclass_accuracy\n\npreds = torch.tensor([[0.05, 0.95, 0.0], [0.1, 0.8, 0.1], [0.7, 0.2, 0.1]])\ntarget = torch.tensor([1, 0, 0])\n\nacc = multiclass_accuracy(preds, target, num_classes=3)\nprint(acc)  # tensor(0.6667)\n```\n\n### Module metrics\n\nUse metric classes when you need streaming updates across many batches.\n\n```python\nimport torch\nfrom torchmetrics.classification import MulticlassAccuracy\n\nmetric = MulticlassAccuracy(num_classes=3)\n\nfor preds, target in [\n    (torch.tensor([[0.05, 0.95, 0.0], [0.1, 0.8, 0.1]]), torch.tensor([1, 0])),\n    (torch.tensor([[0.7, 0.2, 0.1]]), torch.tensor([0])),\n]:\n    metric.update(preds, target)\n\nepoch_acc = metric.compute()\nprint(epoch_acc)\n\nmetric.reset()\n```\n\n### Metric collections\n\nUse `MetricCollection` when you want to share updates across several metrics and compute them together.\n\n```python\nimport torch\nfrom torchmetrics import MetricCollection\nfrom torchmetrics.classification import MulticlassAccuracy, MulticlassF1Score\n\nmetrics = MetricCollection({\n    \"acc\": MulticlassAccuracy(num_classes=3),\n    \"f1\": MulticlassF1Score(num_classes=3),\n})\n\npreds = torch.tensor([[0.1, 0.8, 0.1], [0.7, 0.2, 0.1]])\ntarget = torch.tensor([1, 0])\n\nmetrics.update(preds, target)\nprint(metrics.compute())\nmetrics.reset()\n```\n\n## PyTorch Lightning Setup\n\nKeep metric objects as module attributes so Lightning moves them with the model and resets them at the right epoch boundaries when logged correctly.\n\n```python\nimport torch\nfrom torch import nn\nimport lightning as L\nfrom torchmetrics.classification import MulticlassAccuracy\n\nclass Classifier(L.LightningModule):\n    def __init__(self, in_features: int, num_classes: int) -> None:\n        super().__init__()\n        self.net = nn.Linear(in_features, num_classes)\n        self.train_acc = MulticlassAccuracy(num_classes=num_classes)\n        self.val_acc = MulticlassAccuracy(num_classes=num_classes)\n\n    def forward(self, x: torch.Tensor) -> torch.Tensor:\n        return self.net(x)\n\n    def training_step(self, batch, _batch_idx: int) -> torch.Tensor:\n        x, y = batch\n        logits = self(x)\n        loss = nn.functional.cross_entropy(logits, y)\n        self.train_acc.update(logits, y)\n        self.log(\"train_acc\", self.train_acc, on_step=False, on_epoch=True)\n        self.log(\"train_loss\", loss, on_step=True, on_epoch=True)\n        return loss\n\n    def validation_step(self, batch, _batch_idx: int) -> None:\n        x, y = batch\n        logits = self(x)\n        self.val_acc.update(logits, y)\n        self.log(\"val_acc\", self.val_acc, on_step=False, on_epoch=True)\n```\n\nUse separate metric instances for train, validation, and test. Do not reuse one metric object across phases unless you manually control resets.\n\n## Configuration\n\n`torchmetrics` has no auth or service-level configuration. Most setup is metric-specific constructor arguments.\n\nCommon knobs to set explicitly:\n\n- `task` for generic classification APIs such as `Accuracy`\n- `num_classes` or `num_labels`\n- `average`, `top_k`, `threshold`, `ignore_index`\n- `sync_on_compute` and distributed settings when you are running DDP\n\nIf you need device placement outside Lightning, move the metric to the same device as the model:\n\n```python\nmetric = metric.to(device)\n```\n\n## Common Pitfalls\n\n### Prefer task-specific metric classes\n\nIn current TorchMetrics releases, classification APIs are task-oriented. `Accuracy(task=\"binary\" | \"multiclass\" | \"multilabel\", ...)` and task-specific classes such as `MulticlassAccuracy` are the safe defaults. If you omit required task-specific arguments like `num_classes`, your code will fail or behave differently than older examples.\n\n### Understand how floating predictions are interpreted\n\nFor classification metrics, TorchMetrics will often convert floating predictions before scoring:\n\n- binary and multilabel metrics treat floats outside `[0, 1]` as logits and apply sigmoid before thresholding\n- multiclass metrics apply `argmax` across the class dimension when you pass floating tensors\n\nThis is convenient, but it can hide bugs if your tensor shape, threshold, or `top_k` setting is wrong.\n\n### Reset stateful metrics\n\nMetric modules accumulate internal state. Call `reset()` after `compute()` when you are managing the lifecycle yourself. Reusing a metric instance across epochs or dataset splits without a reset will leak state.\n\n### Keep metrics inside registered modules\n\nPlain Python lists and dicts do not move contained metrics to the correct device. Use `ModuleList`, `ModuleDict`, or `MetricCollection` if you need multiple metrics attached to a model.\n\n### Non-scalar metrics are not direct `self.log` drop-ins\n\nPyTorch Lightning logging expects scalar outputs for direct metric logging. Metrics such as confusion matrices, ROC curves, mean average precision, or ROUGE variants often return tensors or dictionaries and usually need manual `compute()` handling.\n\n### Distributed test evaluation can be slightly biased\n\nThe upstream docs call out a DDP edge case: if the dataset size is not divisible by the number of ranks, PyTorch may replicate some samples so each rank has equal work. Metrics computed over those replicated samples can be slightly biased. For exact benchmarking, prefer a single device or use PyTorch's join-context approach for uneven inputs.\n\n### Large list states can grow memory\n\nSome metrics keep list-based states and can grow with every update. If memory usage climbs over a long epoch, inspect `metric.metric_state` and prefer metrics or settings that reduce retained history.\n\n### State is not saved unless you opt in\n\nMetric states are not persisted in `state_dict` by default. If you need checkpoint persistence for metric state, call `metric.persistent(True)`.\n\n## Version-Sensitive Notes For 1.9.0\n\n- The upstream stable docs and PyPI package currently both point at `1.9.0`, so the version used here matches the live package version as of 2026-03-12.\n- The official 1.9.0 changelog notes that support for Python 3.9 was removed. Verify your runtime before pinning this version into older projects.\n- The 1.9.0 changelog also notes a change to `DiceScore`: the default `average` changed from `\"micro\"` to `\"macro\"`. Set `average=` explicitly if you need stable behavior across upgrades.\n- A 1.9.0 fix addressed a device mismatch issue in the base `Metric` class when states were updated across devices. If you were working around device placement bugs in older releases, re-test those workarounds before keeping them.\n\n## Minimal Custom Metric Pattern\n\nSubclass `Metric`, declare state with `add_state`, mutate it in `update`, and return the final tensor in `compute`.\n\n```python\nimport torch\nfrom torchmetrics import Metric\n\nclass RunningMean(Metric):\n    def __init__(self) -> None:\n        super().__init__()\n        self.add_state(\"total\", default=torch.tensor(0.0), dist_reduce_fx=\"sum\")\n        self.add_state(\"count\", default=torch.tensor(0), dist_reduce_fx=\"sum\")\n\n    def update(self, values: torch.Tensor) -> None:\n        self.total += values.sum()\n        self.count += values.numel()\n\n    def compute(self) -> torch.Tensor:\n        return self.total / self.count\n```\n\nPrefer `add_state` over manual attributes so distributed reduction, reset behavior, and device moves keep working.\n"
  },
  {
    "path": "content/torchvision/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"torchvision package guide for Python computer vision workflows with models, datasets, transforms, and image I/O\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.25.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"torchvision,pytorch,computer-vision,images,transforms,datasets,models\"\n---\n\n# torchvision Python Package Guide\n\n## Golden Rule\n\nInstall `torch` and `torchvision` together, use pretrained-model `weights=` enums plus `weights.transforms()` for inference, and prefer `torchvision.transforms.v2` for new preprocessing pipelines. If `torch` and `torchvision` wheels are out of sync, image ops and custom C++ operators such as NMS are the first things that usually break.\n\n## Install\n\nFor CPU-only environments and many local macOS setups, the basic install is:\n\n```bash\npython -m pip install torch torchvision\n```\n\nIf your project is already pinned, install both packages together instead of upgrading `torchvision` by itself:\n\n```bash\npython -m pip install \"torch==<exact-version>\" \"torchvision==0.25.0\"\n```\n\nFor Linux/Windows GPU or ROCm builds, generate the exact command from the official selector:\n\n- https://pytorch.org/get-started/locally/\n\nVerify the environment immediately after install:\n\n```python\nimport torch\nimport torchvision\n\nprint(torch.__version__)\nprint(torchvision.__version__)\n```\n\nIf the import step fails with missing operators or image extension errors, reinstall a matching `torch` and `torchvision` pair in a clean virtual environment.\n\n## Setup Pattern\n\nMost projects use these pieces:\n\n```python\nimport torch\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets\nfrom torchvision.transforms import v2\nfrom torchvision.models import resnet50, ResNet50_Weights\n```\n\nUse `torch.inference_mode()` for inference, and put the model and tensors on the same device:\n\n```python\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n```\n\n## Core Usage\n\n### Run inference with pretrained weights\n\nUse weight enums instead of hard-coded preprocessing constants. The enum carries the canonical normalization, resize, crop, and category metadata for that checkpoint.\n\n```python\nfrom PIL import Image\nimport torch\nfrom torchvision.models import resnet50, ResNet50_Weights\n\nweights = ResNet50_Weights.DEFAULT\nmodel = resnet50(weights=weights).to(\"cpu\").eval()\npreprocess = weights.transforms()\n\nimage = Image.open(\"cat.jpg\").convert(\"RGB\")\nbatch = preprocess(image).unsqueeze(0)\n\nwith torch.inference_mode():\n    probs = model(batch).softmax(dim=1)\n\ntop_idx = int(probs.argmax(dim=1))\nlabel = weights.meta[\"categories\"][top_idx]\nscore = float(probs[0, top_idx])\n\nprint(label, score)\n```\n\nNotes:\n\n- Call `.eval()` before inference so dropout and batch norm behave correctly.\n- `weights.transforms()` already handles resize/crop/normalization for the selected checkpoint. Do not normalize the same image twice.\n- For GPU inference, move both `model` and `batch` to the same CUDA device.\n\n### Build training transforms with `transforms.v2`\n\nThe official docs now treat `v2` as the modern transforms API. Use it for new pipelines, especially when you may later handle bounding boxes, masks, or videos.\n\n```python\nimport torch\nfrom torchvision.transforms import v2\n\ntrain_transforms = v2.Compose(\n    [\n        v2.ToImage(),\n        v2.RandomResizedCrop((224, 224), antialias=True),\n        v2.RandomHorizontalFlip(p=0.5),\n        v2.ToDtype(torch.float32, scale=True),\n        v2.Normalize(\n            mean=(0.485, 0.456, 0.406),\n            std=(0.229, 0.224, 0.225),\n        ),\n    ]\n)\n```\n\nFor classification datasets, pass the transform as usual. For older detection/segmentation datasets, the docs expose `torchvision.datasets.wrap_dataset_for_transforms_v2` to adapt targets for `v2`.\n\n### Load an image dataset\n\n```python\nimport torch\nfrom torch.utils.data import DataLoader\nfrom torchvision.datasets import CIFAR10\n\n# Reuse the v2 pipeline defined above.\ntrain_dataset = CIFAR10(\n    root=\"data/cifar10\",\n    train=True,\n    download=True,\n    transform=train_transforms,\n)\n\ntrain_loader = DataLoader(\n    train_dataset,\n    batch_size=64,\n    shuffle=True,\n    num_workers=4,\n    pin_memory=torch.cuda.is_available(),\n)\n\nimages, labels = next(iter(train_loader))\nprint(images.shape, labels.shape)\n```\n\nNotes:\n\n- Keep the dataset `root` stable across runs or you will redownload data into multiple cache trees.\n- `download=True` is convenient for local development, but production or CI flows often pre-stage datasets instead.\n- Some datasets download from third-party mirrors and have their own licenses or manual-download requirements.\n\n### Fine-tune a pretrained classifier\n\n```python\nimport torch.nn as nn\nfrom torchvision.models import resnet18, ResNet18_Weights\n\nmodel = resnet18(weights=ResNet18_Weights.DEFAULT)\nmodel.fc = nn.Linear(model.fc.in_features, 10)\n```\n\nThis pattern is common across many `torchvision.models` architectures: load weights, replace the task-specific head, and train only the layers you need.\n\n### Decode images with `torchvision.io`\n\nIf you need a tensor directly from bytes on disk, use the `io` helpers:\n\n```python\nfrom torchvision.io import decode_image, read_file\n\nimage = decode_image(read_file(\"cat.jpg\"))\nprint(image.shape, image.dtype)  # CHW uint8 tensor\n```\n\nThis is useful when you want tensor-first ingestion without a PIL dependency in the read path.\n\n## Configuration Notes\n\n- Match the wheel family across `torch`, `torchvision`, Python version, OS, and accelerator backend.\n- Use `weights.transforms()` for inference and your own explicit `v2.Compose(...)` pipeline for training.\n- `pin_memory=True` is mainly useful when you are training on CUDA and moving batches from host RAM to the GPU.\n- Many torchvision examples assume channels-first tensors shaped `[C, H, W]` or `[N, C, H, W]`.\n- Detection and segmentation models often expect a list of images and per-image target dicts, not a single batched tensor and flat labels.\n\n## Common Pitfalls\n\n- `RuntimeError` around missing ops such as `torchvision::nms` usually means the `torch` and `torchvision` binaries do not match.\n- Reusing blog-era `pretrained=True` snippets is brittle. Prefer the current `weights=` enums from the official docs.\n- Mixing `weights.transforms()` with your own normalization step often double-normalizes inputs and hurts inference quality.\n- Forgetting `.eval()` and `torch.inference_mode()` makes inference slower and can produce unstable results.\n- Legacy `torchvision.transforms` examples often assume PIL images only. `transforms.v2` is the safer default for new work.\n- The `torchvision.io` docs explicitly deprecate video decoding and encoding in favor of TorchCodec. Do not start new video pipelines on the legacy video APIs.\n\n## Version-Sensitive Notes For `0.25.0`\n\n- As of `2026-03-12`, the official stable torchvision docs root and the PyPI project page both show `0.25.0`.\n- Upstream install metadata is not fully synchronized: the PyPI page's compatibility table still stops at `torch 2.9` / `torchvision 0.24`, and the PyTorch \"Get Started\" selector page still renders a `Stable (2.7.0)` default. Treat both as drift signals rather than authoritative pairing guidance for `0.25.0`.\n- Because of that drift, the safest upgrade path is to install `torch` and `torchvision` together in a fresh environment, verify import success, and run a minimal model + image-op smoke test before rolling the upgrade into production.\n- The `transforms.v2` docs and the stable models docs are current enough to use as the API baseline for new code.\n\n## Official Source URLs\n\n- Docs root: https://docs.pytorch.org/vision/stable/\n- Models: https://docs.pytorch.org/vision/stable/models.html\n- Datasets: https://docs.pytorch.org/vision/stable/datasets.html\n- Transforms: https://docs.pytorch.org/vision/stable/transforms.html\n- V2 start here: https://docs.pytorch.org/vision/stable/auto_examples/transforms/plot_transforms_getting_started.html\n- V1 or V2 comparison: https://docs.pytorch.org/vision/stable/auto_examples/transforms/plot_v2_e2e.html\n- I/O: https://docs.pytorch.org/vision/stable/io.html\n- Install selector: https://pytorch.org/get-started/locally/\n- PyPI: https://pypi.org/project/torchvision/\n- Repository: https://github.com/pytorch/vision\n"
  },
  {
    "path": "content/tornado/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Tornado async web framework and networking library for Python HTTP services, clients, and WebSockets\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.5.5\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tornado,python,asyncio,web,http,websocket,server\"\n---\n\n# Tornado Python Package Guide\n\n## Golden Rule\n\nUse Tornado as an `asyncio`-based networking framework and keep request handlers non-blocking.\n\n- Start new apps with `asyncio.run(...)`.\n- Use `async def` handlers and `AsyncHTTPClient` for network I/O.\n- Offload blocking work to threads or worker processes.\n- Re-check release notes before copying older `IOLoop.start()` or callback-style examples.\n\n## Installation\n\n```bash\npip install \"tornado==6.5.5\"\n```\n\n```bash\npoetry add \"tornado==6.5.5\"\n```\n\n```bash\nuv add tornado==6.5.5\n```\n\nVerify the installed version:\n\n```bash\npython -c \"import tornado; print(tornado.version)\"\n```\n\n## Initialize And Run\n\nTornado 6.x runs on top of `asyncio`. A minimal app looks like this:\n\n```python\nimport asyncio\n\nimport tornado.escape\nimport tornado.httpserver\nimport tornado.web\n\nclass HealthHandler(tornado.web.RequestHandler):\n    async def get(self) -> None:\n        self.write({\"ok\": True})\n\nclass EchoHandler(tornado.web.RequestHandler):\n    async def post(self) -> None:\n        payload = tornado.escape.json_decode(self.request.body or b\"{}\")\n        self.set_status(201)\n        self.write({\"received\": payload})\n\ndef make_app() -> tornado.web.Application:\n    return tornado.web.Application(\n        [\n            (r\"/healthz\", HealthHandler),\n            (r\"/echo\", EchoHandler),\n        ],\n        cookie_secret=\"replace-me\",\n        xsrf_cookies=True,\n        debug=False,\n    )\n\nasync def main() -> None:\n    server = tornado.httpserver.HTTPServer(make_app())\n    server.listen(8888, address=\"127.0.0.1\")\n    await asyncio.Event().wait()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nPractical rules:\n\n- `Application.listen(...)` is fine for small apps; use `HTTPServer(...)` when you need SSL, `xheaders`, or explicit socket control.\n- `debug=True` enables autoreload and extra checks, but it is a development setting.\n- Keep one `Application` per process and initialize shared clients during startup, not inside every request.\n\n## Core Request Handling\n\nPrefer `async def` handlers whenever a request performs I/O:\n\n```python\nimport tornado.escape\nimport tornado.web\n\nclass UserHandler(tornado.web.RequestHandler):\n    async def get(self, user_id: str) -> None:\n        verbose = self.get_query_argument(\"verbose\", \"0\") == \"1\"\n        self.write({\"user_id\": user_id, \"verbose\": verbose})\n\n    async def post(self, user_id: str) -> None:\n        payload = tornado.escape.json_decode(self.request.body or b\"{}\")\n        self.set_status(201)\n        self.write({\"user_id\": user_id, \"payload\": payload})\n\napp = tornado.web.Application([\n    (r\"/users/([^/]+)\", UserHandler),\n])\n```\n\nUse the right helper for the right input source:\n\n- `get_query_argument(...)` for query string values only\n- `get_body_argument(...)` for form fields in the request body\n- `get_argument(...)` only when it is acceptable to merge query and body values\n- `tornado.escape.json_decode(self.request.body)` for JSON request bodies\n\n`self.write(dict_or_list)` serializes JSON automatically and sets the content type.\n\n## Outbound HTTP\n\nUse `AsyncHTTPClient` inside handlers and background tasks.\n\n```python\nimport tornado.escape\nimport tornado.httpclient\nimport tornado.web\n\nclass UpstreamHandler(tornado.web.RequestHandler):\n    async def get(self) -> None:\n        client = tornado.httpclient.AsyncHTTPClient()\n        response = await client.fetch(\n            \"https://httpbin.org/json\",\n            request_timeout=10.0,\n        )\n        data = tornado.escape.json_decode(response.body)\n        self.write({\"title\": data[\"slideshow\"][\"title\"]})\n```\n\nNotes:\n\n- `AsyncHTTPClient.fetch(...)` raises `HTTPClientError` on non-2xx responses unless you pass `raise_error=False`.\n- `HTTPClient` is synchronous and should not run on the main event-loop thread.\n- Reuse clients for repeated upstream calls instead of constructing a new one for every operation-heavy code path.\n\n## WebSockets\n\nUse `tornado.websocket.WebSocketHandler` for browser or service-to-service sockets:\n\n```python\nimport tornado.websocket\n\nclass EchoSocket(tornado.websocket.WebSocketHandler):\n    def check_origin(self, origin: str) -> bool:\n        return origin == \"https://app.example.com\"\n\n    def open(self) -> None:\n        self.write_message(\"connected\")\n\n    def on_message(self, message: str) -> None:\n        self.write_message(f\"echo: {message}\")\n```\n\n```python\napp = tornado.web.Application(\n    [(r\"/ws\", EchoSocket)],\n    websocket_ping_interval=30,\n    websocket_ping_timeout=30,\n)\n```\n\nGuidance:\n\n- The default `check_origin` rejects cross-origin browser connections. Override it narrowly.\n- Keep ping settings explicit when connections sit behind proxies or load balancers.\n- If you still have callback-style `websocket_connect(..., callback=...)` code, treat it as deprecated and migrate to `await tornado.websocket.websocket_connect(...)`.\n\n## Auth And Security Configuration\n\nSigned cookies plus `@authenticated` are the standard built-in pattern:\n\n```python\nimport tornado.web\n\nclass BaseHandler(tornado.web.RequestHandler):\n    def get_current_user(self) -> str | None:\n        value = self.get_signed_cookie(\"user\")\n        return value.decode() if value else None\n\nclass LoginHandler(BaseHandler):\n    async def post(self) -> None:\n        username = self.get_body_argument(\"username\")\n        self.set_signed_cookie(\n            \"user\",\n            username,\n            secure=True,\n            httponly=True,\n            samesite=\"Lax\",\n        )\n        self.write({\"ok\": True})\n\nclass AccountHandler(BaseHandler):\n    @tornado.web.authenticated\n    async def get(self) -> None:\n        self.write({\"user\": self.current_user})\n```\n\n```python\napp = tornado.web.Application(\n    [\n        (r\"/login\", LoginHandler),\n        (r\"/account\", AccountHandler),\n    ],\n    cookie_secret=\"long-random-secret\",\n    login_url=\"/login\",\n    xsrf_cookies=True,\n    xsrf_cookie_kwargs={\"secure\": True, \"samesite\": \"Strict\"},\n)\n```\n\nImportant behavior:\n\n- `cookie_secret` is required for signed cookies.\n- `login_url` is required when using `@tornado.web.authenticated`.\n- For `GET` and `HEAD`, `@authenticated` redirects to `login_url`; for other methods, it returns `403`.\n- Keep `xsrf_cookies=True` for forms or browser-driven mutation endpoints.\n\n### Multipart form limits in 6.5.5\n\nTornado `6.5.5` adds process-wide multipart limits to reduce risk from requests with huge numbers of files or parts. If your app legitimately accepts large multipart requests, raise the limit deliberately:\n\n```python\nfrom tornado.httputil import (\n    ParseBodyConfig,\n    ParseMultipartConfig,\n    set_parse_body_config,\n)\n\nset_parse_body_config(\n    ParseBodyConfig(\n        multipart=ParseMultipartConfig(max_parts=500)\n    )\n)\n```\n\nTreat this as a global server setting and keep the limit as low as your workload allows.\n\n## Blocking Code And Threads\n\nTornado request handling runs on a single-threaded event loop. Blocking work must move off that thread.\n\n```python\nimport asyncio\n\nimport tornado.web\n\ndef blocking_lookup(user_id: str) -> dict[str, str]:\n    return {\"user_id\": user_id, \"source\": \"thread\"}\n\nclass ReportHandler(tornado.web.RequestHandler):\n    async def get(self, user_id: str) -> None:\n        result = await asyncio.to_thread(blocking_lookup, user_id)\n        self.write(result)\n```\n\nPractical rules:\n\n- Use native async clients for network I/O whenever they exist.\n- Use `asyncio.to_thread(...)` or an executor for blocking libraries.\n- Do not mutate Tornado request or application objects from worker threads.\n- If another thread needs to signal the IOLoop, use `IOLoop.add_callback(...)`.\n\n## Deployment Notes\n\nFor production:\n\n- run Tornado behind a reverse proxy such as nginx or Envoy\n- enable `xheaders=True` only when all traffic comes through a trusted proxy layer\n- use one process per CPU core for I/O-heavy workloads\n- prefer Tornado's documented multi-process socket pattern instead of ad hoc forking\n\nTypical multi-process pattern:\n\n```python\nimport asyncio\n\nimport tornado.httpserver\nimport tornado.netutil\nimport tornado.process\n\nsockets = tornado.netutil.bind_sockets(8888)\ntornado.process.fork_processes(0)\n\nserver = tornado.httpserver.HTTPServer(make_app())\nserver.add_sockets(sockets)\n\nasyncio.run(asyncio.Event().wait())\n```\n\nNotes:\n\n- `fork_processes(...)` is not available on Windows.\n- Do not create event-loop-bound objects before forking worker processes.\n- If you are already using a process manager or container platform, compare this pattern with `reuse_port=True` and your platform's normal process model.\n\n## Common Pitfalls\n\n- Do not call `requests`, synchronous database drivers, or filesystem-heavy code directly in handlers.\n- Do not parse JSON request bodies with `get_argument(...)`; decode `self.request.body`.\n- Do not return `True` from `check_origin` blindly for WebSocket handlers.\n- Do not trust `xheaders=True` outside a controlled proxy boundary.\n- Do not assume old Tornado blog posts match 6.5.x startup, WebSocket, or multipart parsing behavior.\n\n## Version-Sensitive Notes For 6.5.5\n\n- `6.5.0` raised the minimum supported Python version to `3.9` and added Python `3.14` support.\n- `6.5.0` deprecated `websocket_connect(..., callback=...)`; use `await` instead.\n- `6.5.2` fixed `websocket_ping_interval` and `websocket_ping_timeout` behavior in some reconnection cases.\n- `6.5.3` fixed a security issue around repeated HTTP headers with mixed `Content-Length` and `Transfer-Encoding`.\n- `6.5.5` fixed more security issues in `set_status`, `set_cookie`, and multipart parsing, and added `ParseMultipartConfig(max_parts=...)`.\n\nIf you upgrade from `6.4.x`, review the 6.5 release notes before reusing old auth, WebSocket, or request-parsing code unchanged.\n\n## Official Sources\n\n- Stable docs root: https://www.tornadoweb.org/en/stable/\n- User guide: https://www.tornadoweb.org/en/stable/guide.html\n- Async and blocking-code guide: https://www.tornadoweb.org/en/stable/guide/async.html\n- Running and deployment guide: https://www.tornadoweb.org/en/stable/guide/running.html\n- Web framework reference: https://www.tornadoweb.org/en/stable/web.html\n- HTTP client reference: https://www.tornadoweb.org/en/stable/httpclient.html\n- WebSocket reference: https://www.tornadoweb.org/en/stable/websocket.html\n- HTTP utility reference: https://www.tornadoweb.org/en/stable/httputil.html\n- Release notes index: https://www.tornadoweb.org/en/stable/releases.html\n- 6.5.0 release notes: https://www.tornadoweb.org/en/stable/releases/v6.5.0.html\n- 6.5.2 release notes: https://www.tornadoweb.org/en/stable/releases/v6.5.2.html\n- 6.5.3 release notes: https://www.tornadoweb.org/en/stable/releases/v6.5.3.html\n- 6.5.5 release notes: https://www.tornadoweb.org/en/stable/releases/v6.5.5.html\n- PyPI package page: https://pypi.org/project/tornado/6.5.5/\n"
  },
  {
    "path": "content/tortoise-orm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Tortoise ORM async Python ORM for SQLite, PostgreSQL, MySQL, MSSQL, and Oracle\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.1.6\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tortoise-orm,python,orm,async,database,sqlite,postgresql,mysql\"\n---\n\n# Tortoise ORM Python Package Guide\n\n## Golden Rule\n\nUse `tortoise-orm` for async ORM access, initialize it once per app lifecycle, and close connections explicitly on shutdown. For schema changes on `1.x`, use the built-in `tortoise` migration CLI rather than older Aerich-based guides unless you are maintaining legacy code.\n\n## Install\n\nPick the extra that matches your database driver:\n\n```bash\npython -m pip install \"tortoise-orm==1.1.6\"\npython -m pip install \"tortoise-orm[asyncpg]==1.1.6\"\npython -m pip install \"tortoise-orm[psycopg]==1.1.6\"\npython -m pip install \"tortoise-orm[asyncmy]==1.1.6\"\npython -m pip install \"tortoise-orm[aiomysql]==1.1.6\"\npython -m pip install \"tortoise-orm[asyncodbc]==1.1.6\"\n```\n\nUseful extras:\n\n```bash\npython -m pip install \"tortoise-orm[accel]==1.1.6\"\npython -m pip install \"tortoise-orm[ipython]==1.1.6\"\n```\n\nNotes:\n\n- No extra is needed for SQLite.\n- `[accel]` installs optional performance helpers such as `orjson`, `uvloop`, and `ciso8601`.\n- Supported databases are SQLite, PostgreSQL, MySQL/MariaDB, MSSQL, and Oracle, but production usage is usually SQLite for local/dev and PostgreSQL or MySQL for deployed services.\n\n## Initialize And Configure\n\n### Minimal script or local development setup\n\nUse `run_async()` for simple scripts. `generate_schemas()` is for empty databases and development only.\n\n```python\nfrom tortoise import Tortoise, fields, run_async\nfrom tortoise.models import Model\n\nclass User(Model):\n    id = fields.IntField(primary_key=True)\n    email = fields.CharField(max_length=255, unique=True)\n    is_active = fields.BooleanField(default=True)\n\nasync def main() -> None:\n    await Tortoise.init(\n        db_url=\"sqlite://db.sqlite3\",\n        modules={\"models\": [\"__main__\"]},\n    )\n    await Tortoise.generate_schemas()\n\n    user = await User.create(email=\"a@example.com\")\n    print(user.id)\n\nrun_async(main())\n```\n\n### Production-style config dict\n\nUse dict config when you need multiple connections, per-app routing, or passwords that are awkward to encode safely into a URL.\n\n```python\nfrom tortoise import Tortoise\n\nTORTOISE_ORM = {\n    \"connections\": {\n        \"default\": {\n            \"engine\": \"tortoise.backends.asyncpg\",\n            \"credentials\": {\n                \"host\": \"127.0.0.1\",\n                \"port\": 5432,\n                \"user\": \"app\",\n                \"password\": \"secret\",\n                \"database\": \"appdb\",\n                \"minsize\": 1,\n                \"maxsize\": 10,\n            },\n        }\n    },\n    \"apps\": {\n        \"models\": {\n            \"models\": [\"app.models\"],\n            \"default_connection\": \"default\",\n            \"migrations\": \"app.migrations\",\n        }\n    },\n}\n\nasync def init_orm() -> None:\n    await Tortoise.init(config=TORTOISE_ORM)\n```\n\n### DB URL examples\n\n```text\nsqlite://db.sqlite3\nsqlite://:memory:\nasyncpg://user:password@127.0.0.1:5432/appdb\npsycopg://user:password@127.0.0.1:5432/appdb\nmysql://user:password@127.0.0.1:3306/appdb\n```\n\nIf the password contains `%`, `+`, `/`, or other special characters, prefer dict config or URL-encode the password first.\n\n## App Lifecycle And Cleanup\n\nTortoise keeps async DB connections open until you close them.\n\n```python\nfrom tortoise import Tortoise\n\nasync def startup() -> None:\n    await Tortoise.init(config=TORTOISE_ORM)\n\nasync def shutdown() -> None:\n    await Tortoise.close_connections()\n```\n\nIf initialization happens in a different task from the code that runs queries, enable global fallback:\n\n```python\nawait Tortoise.init(\n    db_url=\"sqlite://db.sqlite3\",\n    modules={\"models\": [\"app.models\"]},\n    _enable_global_fallback=True,\n)\n```\n\nThat is commonly needed in ASGI lifespan handlers, framework setup tasks, and some test harnesses. Only one global fallback context can be active at a time.\n\n## Define Models\n\n```python\nfrom tortoise import fields\nfrom tortoise.models import Model\nfrom tortoise.expressions import RawSQL\n\nclass Team(Model):\n    id = fields.IntField(primary_key=True)\n    name = fields.CharField(max_length=255, unique=True)\n\nclass Tournament(Model):\n    id = fields.IntField(primary_key=True)\n    name = fields.CharField(max_length=255)\n\nclass Event(Model):\n    id = fields.IntField(primary_key=True)\n    name = fields.CharField(max_length=255)\n    tournament = fields.ForeignKeyField(\"models.Tournament\", related_name=\"events\")\n    participants = fields.ManyToManyField(\"models.Team\", related_name=\"events\")\n    created_at = fields.DatetimeField(db_default=RawSQL(\"CURRENT_TIMESTAMP\"))\n```\n\nNotes:\n\n- String relations use `\"app_label.ModelName\"`.\n- `ForeignKeyField()` and `ManyToManyField()` can also accept model classes directly on `1.x`.\n- Use `db_default` for database-level defaults. Plain `default=` is Python-side only.\n\n## Core CRUD\n\n```python\nfrom tortoise.exceptions import DoesNotExist\n\ntournament = await Tournament.create(name=\"Spring Cup\")\nteam = await Team.create(name=\"Blue Team\")\n\nevent = await Event.create(name=\"Opening Match\", tournament=tournament)\nawait event.participants.add(team)\n\nsame_event = await Event.get(id=event.id)\nawait Event.filter(id=event.id).update(name=\"Updated Match\")\n\ntry:\n    fetched = await Event.get(name=\"Updated Match\")\nexcept DoesNotExist:\n    fetched = None\n\nall_events = await Event.filter(tournament__name=\"Spring Cup\").order_by(\"-id\")\nlightweight_rows = await Event.filter(id__in=[event.id]).values(\"id\", \"name\")\n```\n\nUse:\n\n- `.create()` or `.save()` to insert\n- `.filter()`, `.get()`, `.get_or_none()`, `.first()` for reads\n- `.update()` for bulk updates without loading objects first\n- `.values()` or `.values_list()` when you want dict/tuple output and fewer ORM objects\n\n## Relations And Query Shaping\n\n`prefetch_related()` is the normal way to load related objects:\n\n```python\nevents = await Event.all().prefetch_related(\"tournament\", \"participants\")\n```\n\nFor foreign keys, `select_related()` can fetch related objects in one joined query:\n\n```python\nevents = await Event.all().select_related(\"tournament\")\n```\n\nPerformance notes:\n\n- Each `prefetch_related()` depth adds more queries. `events__participants` means one extra query per relation depth.\n- When you only need flattened fields, prefer `values()` or `values_list()` instead of full ORM instances.\n- Many-to-many relations require both sides to be saved before `.add()` works.\n\n## Transactions\n\nUse `in_transaction()` when several writes must succeed or fail together.\n\n```python\nfrom tortoise.transactions import in_transaction\n\nasync with in_transaction() as connection:\n    event = await Event.create(name=\"Transactional\", tournament=tournament, using_db=connection)\n    await Event.filter(id=event.id).using_db(connection).update(name=\"Committed\")\n```\n\nUse `select_for_update()` inside a transaction when row locking matters:\n\n```python\nasync with in_transaction():\n    event = await Event.filter(id=event.id).select_for_update().get()\n    event.name = \"Locked update\"\n    await event.save()\n```\n\n## Migrations\n\nThe built-in migration system is the current recommended path.\n\n```python\nTORTOISE_ORM = {\n    \"connections\": {\"default\": \"sqlite://db.sqlite3\"},\n    \"apps\": {\n        \"models\": {\n            \"models\": [\"app.models\"],\n            \"default_connection\": \"default\",\n            \"migrations\": \"app.migrations\",\n        }\n    },\n}\n```\n\n```bash\ntortoise init\ntortoise makemigrations\ntortoise migrate\ntortoise sqlmigrate models 0001_initial\n```\n\nThe CLI resolves config from `-c/--config`, `--config-file`, or `[tool.tortoise]` in `pyproject.toml`.\n\nUse `generate_schemas()` only for empty local databases, tests, or throwaway prototypes. Do not mix it into normal production deployments after real schema history exists.\n\n## Pydantic Serialization\n\nTortoise ships a Pydantic plugin for output serialization:\n\n```python\nfrom tortoise.contrib.pydantic import pydantic_model_creator\n\nEventOut = pydantic_model_creator(Event, name=\"EventOut\")\n\nevent = await Event.get(id=1).prefetch_related(\"participants\")\npayload = await EventOut.from_tortoise_orm(event)\n```\n\nImportant limitation:\n\n- The plugin is for serialization. It does not generate deserialization/write models for you.\n\n## Framework Usage\n\nFor FastAPI, Starlette, Sanic, AIOHTTP, and similar frameworks, treat Tortoise as app-lifecycle state:\n\n- initialize once on startup or lifespan entry\n- close connections on shutdown\n- enable `_enable_global_fallback=True` when the framework runs startup work in a different task and queries later fail with `No TortoiseContext is currently active`\n\nIf you are writing plain scripts, `run_async()` already handles connection cleanup.\n\n## Common Pitfalls\n\n- Do not use `generate_schemas()` as your migration strategy for an app with real data.\n- Do not forget `await Tortoise.close_connections()` on shutdown.\n- `use_tz` defaults to `True` on `1.x`. If your project expects naive datetimes, set `use_tz=False` explicitly.\n- `default=` is not the same as `db_default=`. Use `db_default` when the database itself should own the default clause.\n- Older blog posts still point to Aerich. The upstream docs now recommend the built-in `tortoise` migration system.\n- If queries run in a different task from initialization, you can hit `RuntimeError: No TortoiseContext is currently active`.\n- If your DB password contains special URL characters, URL parsing can break. Prefer dict config in that case.\n- `prefetch_related()` can turn into many queries. Use `select_related()` for foreign keys and `values()` when you only need a projection.\n- Pydantic support is output-focused. You still need explicit request/write schemas in web apps.\n\n## Version-Sensitive Notes For 1.1.6\n\n- `1.0.0` was a breaking release: Python `3.10+` is required, `use_tz=True` became the default, and `Tortoise.init()` moved to a context-first architecture.\n- `1.0.0` also introduced the native migration framework and deprecated `from tortoise import connections` in favor of `get_connection()` / `get_connections()`.\n- `1.1.0` added `db_default`, which is now the correct way to emit database `DEFAULT` clauses in schemas and migrations.\n- `1.1.1` clarified that `Field(default=...)` and `auto_now` / `auto_now_add` are Python-side behavior, not DB-level defaults.\n- `1.1.6` fixes migration ordering for indexes and constraints, `db_default` handling in `CreateModel`, `max_length` change detection in `AlterField`, MySQL timezone handling when `use_tz=True`, and `+` in DB URL passwords.\n\n## Official Sources\n\n- Docs root: `https://tortoise.github.io/`\n- Getting started: `https://tortoise.github.io/getting_started.html`\n- Setup: `https://tortoise.github.io/setup.html`\n- Databases: `https://tortoise.github.io/databases.html`\n- Query API: `https://tortoise.github.io/query.html`\n- Models: `https://tortoise.github.io/models.html`\n- Migrations: `https://tortoise.github.io/migration.html`\n- Pydantic serialization: `https://tortoise.github.io/contrib/pydantic.html`\n- Changelog: `https://tortoise.github.io/CHANGELOG.html`\n- PyPI: `https://pypi.org/project/tortoise-orm/`\n"
  },
  {
    "path": "content/tox/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tox package guide for Python test environment orchestration and automation\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.49.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"tox,python,testing,virtualenv,ci,pytest\"\n---\n\n# tox Python Package Guide\n\n## Golden Rule\n\nUse `tox` 4 as a config-driven CLI for repeatable local and CI automation across multiple Python interpreters and tool environments. As of March 12, 2026, official upstream sources show `tox 4.49.1` on PyPI, released on March 9, 2026, with current documentation at `https://tox.wiki/en/stable/`.\n\n## Install\n\n`tox` is primarily a CLI tool, so install it as a developer tool instead of bundling it into your runtime dependencies.\n\nRecommended install from the official docs:\n\n```bash\npipx install tox\ntox --help\n```\n\nAlternative install with `pip`:\n\n```bash\npython -m pip install \"tox==4.49.1\"\npython -m tox --help\n```\n\nIf you want shell completion support, PyPI publishes the `completion` extra:\n\n```bash\npython -m pip install \"tox[completion]==4.49.1\"\n```\n\nVerify the actual executable on your path before debugging config issues:\n\n```bash\ntox --version\ntox --help\n```\n\n## Initialize And Configure A Project\n\nGenerate a starter config:\n\n```bash\ntox quickstart\n```\n\nFor tox 4 projects, prefer native TOML when you do not need older INI-only features:\n\n- `tox.toml`\n- `pyproject.toml` with `[tool.tox]`\n\ntox still supports these config locations, in priority order:\n\n1. `tox.ini`\n2. `setup.cfg`\n3. `pyproject.toml` with `tool.tox.legacy_tox_ini`\n4. native `pyproject.toml` under `tool.tox`\n5. `tox.toml`\n\nMinimal `tox.toml`:\n\n```toml\nrequires = [\"tox>=4.49\"]\nenv_list = [\"3.12\", \"3.11\", \"lint\"]\n\n[env_run_base]\ndescription = \"run the test suite\"\ndeps = [\"pytest>=8\"]\ncommands = [[\"pytest\", \"-q\", \"tests\"]]\n\n[env.lint]\ndescription = \"lint with ruff\"\nlabels = [\"check\"]\nskip_install = true\ndeps = [\"ruff>=0.9\"]\ncommands = [[\"ruff\", \"check\", \".\"]]\n```\n\nWhat matters here:\n\n- `env_list` defines what plain `tox` runs by default\n- `[env_run_base]` is shared configuration for normal run environments\n- `skip_install = true` avoids building and installing your package for tool-only environments\n- `labels` lets you group environments under a stable name such as `check`\n\n## Core Usage\n\nRun the default environment list:\n\n```bash\ntox\n```\n\nRun one environment:\n\n```bash\ntox run -e 3.12\n```\n\nRun multiple environments explicitly:\n\n```bash\ntox run -e 3.12,3.11,lint\n```\n\nRun by label:\n\n```bash\ntox run -m check\n```\n\nInspect resolved config for an environment:\n\n```bash\ntox config -e 3.12\n```\n\nList known environments:\n\n```bash\ntox list\n```\n\nRun a one-off command inside a tox environment:\n\n```bash\ntox exec -e 3.12 -- python -V\n```\n\nRun environments in parallel:\n\n```bash\ntox run-parallel -e 3.12,3.11\n```\n\nRecreate an environment after interpreter, dependency, or packaging changes:\n\n```bash\ntox run -e 3.12 -r\n```\n\nStop early after the first failing environment when you want faster CI feedback:\n\n```bash\ntox run -e 3.12,3.11,lint --fail-fast\n```\n\n## Configuration Notes\n\n### TOML vs INI\n\ntox 4 supports both INI and TOML. Current docs describe native TOML as more robust, but note that some advanced features still remain stronger in INI. Do not paste multiline INI syntax directly into `[tool.tox]`; native TOML uses structured arrays and tables.\n\nFor example, TOML `commands` is a list of argument lists:\n\n```toml\ncommands = [[\"pytest\", \"-q\", \"tests\"]]\n```\n\nnot:\n\n```ini\ncommands = pytest -q tests\n```\n\n### Packaging behavior\n\ntox normally creates an environment, installs dependencies, then builds and installs your package before running commands. That is what you want for real test environments that should exercise the installed package.\n\nFor tool-only environments such as lint, docs, or formatting, prefer:\n\n- `skip_install = true` when you do not need the project package installed\n- `package = \"skip\"` when you want packaging disabled explicitly\n\n### Dependency groups\n\ntox 4 supports `dependency_groups`, which maps cleanly to PEP 735 dependency groups defined in `pyproject.toml`. Use this when your project already declares grouped dependencies and you want to avoid repeating them in `tox`.\n\n### Environment selection\n\ntox infers Python versions from environment names such as `3.12` or `py312`. If you declare environments for interpreters that are not installed locally, runs will fail unless you configure missing-interpreter behavior intentionally.\n\n## Config And Credentials\n\ntox does not have its own auth model. The practical issue is environment isolation.\n\nCommands run inside tox-managed environments, and only selected host environment variables are passed through. If your tests need credentials, private index settings, or CI flags, pass them deliberately.\n\nExample:\n\n```toml\n[env_run_base]\npass_env = [\"CI\", \"PIP_*\", \"UV_*\", \"AWS_*\", \"GITHUB_*\"]\nset_env = { PYTHONUTF8 = \"1\" }\n```\n\nCommon cases that need `pass_env`:\n\n- private package indexes such as `PIP_INDEX_URL` and `PIP_EXTRA_INDEX_URL`\n- cloud credentials used by integration tests\n- CI-only feature flags or tokens\n\nIf a command calls an executable that is not installed inside the tox environment, declare it with `allowlist_externals`; otherwise tox may block it as an external command.\n\n## Common Patterns\n\nTest multiple Python versions:\n\n```toml\nenv_list = [\"3.11\", \"3.12\", \"3.13\"]\n```\n\nSeparate tooling from package-installing test envs:\n\n```toml\n[env.format]\nskip_install = true\ndeps = [\"ruff>=0.9\"]\ncommands = [[\"ruff\", \"format\", \"--check\", \".\"]]\n```\n\nUse labels for CI groupings:\n\n```toml\n[env.typecheck]\nlabels = [\"check\"]\nskip_install = true\ndeps = [\"mypy>=1.11\"]\ncommands = [[\"mypy\", \"src\"]]\n```\n\nUse config output for debugging:\n\n```bash\ntox config -e 3.12 --format json\n```\n\n## Common Pitfalls\n\n- Missing interpreters are the most common cause of environment creation failures. Keep `env_list` aligned with the Python versions actually available on the host or CI image.\n- Tool-only environments should usually set `skip_install = true` or `package = \"skip\"`. Otherwise a packaging failure can block lint or docs jobs that do not need an installed package.\n- TOML syntax is not a copy-paste replacement for `tox.ini`; `commands`, tables, and nested structures use different shapes.\n- Secrets from the parent shell are not automatically available everywhere you expect. Pass needed variables explicitly with `pass_env`.\n- External commands are restricted unless they are installed in the tox environment or allowlisted.\n- Stale environments can hide dependency or interpreter changes. Use `tox run -e <env> -r` after changing package metadata, build backend settings, or Python versions.\n- tox is a CLI orchestrator, not your test runner itself. Put the real work in `commands`, `deps`, `dependency_groups`, and packaging settings.\n\n## Version-Sensitive Notes For tox 4.49.1\n\n- tox 4 is not a small update over tox 3. Many older blog posts still use removed or renamed concepts such as `whitelist_externals` instead of `allowlist_externals`, or assume INI-only configuration.\n- Native TOML support is now first-class. Current docs recommend TOML unless you specifically need advanced features that TOML still does not support yet.\n- The `schema` command was added in tox `4.24.0`, which is useful for tooling that wants machine-readable tox configuration schema output.\n- tox `4.26.0` dropped Python 3.8 support for running tox itself and added support for free-threaded Python builds.\n- tox `4.28.0` deprecated `min_version` in favor of `requires`, and added `constraints` support.\n- tox `4.33.0` added conditional `set_env` support with environment markers.\n- tox `4.48.0` added machine-readable formatting options for `tox config`, including `--format` and `--output-file`.\n- tox `4.49.0` added TOML factor-label substitution support, and `4.49.1` is the current patch release on PyPI.\n\n## Official Links\n\n- Stable docs: `https://tox.wiki/en/stable/`\n- User guide: `https://tox.wiki/en/stable/user_guide.html`\n- Configuration reference: `https://tox.wiki/en/stable/config.html`\n- CLI reference: `https://tox.wiki/en/stable/cli_interface.html`\n- Changelog: `https://tox.wiki/en/stable/changelog.html`\n- PyPI: `https://pypi.org/project/tox/`\n"
  },
  {
    "path": "content/tqdm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"tqdm progress bar and CLI for Python loops, async tasks, pandas operations, notebooks, and shell pipelines\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.67.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"tqdm,python,progress-bar,cli,asyncio,pandas,jupyter\"\n---\n\n# `tqdm` Python Package Guide\n\nUse `tqdm` to add low-overhead progress bars around iterables, manual counters, async workloads, pandas operations, and shell pipelines. For mixed terminal and notebook environments, prefer `tqdm.auto` as the default import.\n\n## Install\n\n```bash\npip install tqdm==4.67.3\n```\n\nCommon alternatives:\n\n```bash\nuv add tqdm\npoetry add tqdm\n```\n\nNotebook/widget support can require the optional notebook extra:\n\n```bash\npip install \"tqdm[notebook]\"\n```\n\nPackage metadata for `4.67.3` requires Python `>=3.7`.\n\n## Choose the Right Import\n\nUse these imports intentionally:\n\n```python\nfrom tqdm.auto import tqdm, trange\n```\n\n- `tqdm.auto`: best default for code that may run in terminals or notebooks.\n- `tqdm`: standard console progress bar.\n- `tqdm.notebook`: notebook widget UI when you know the runtime is Jupyter.\n- `tqdm.asyncio`: async helpers such as `gather` and `as_completed`.\n\n## Basic Iterable Usage\n\nWrap the iterable directly:\n\n```python\nfrom time import sleep\nfrom tqdm.auto import tqdm\n\nfor item in tqdm(range(100), desc=\"Processing\", unit=\"item\"):\n    sleep(0.02)\n```\n\nUse `trange()` when you just need `range()` with a bar:\n\n```python\nfrom tqdm.auto import trange\n\nfor _ in trange(10, desc=\"Epoch\"):\n    ...\n```\n\nIf the iterable does not expose a length, provide `total=` yourself so ETA and completion percentages work:\n\n```python\nfrom tqdm.auto import tqdm\n\ndef stream_rows():\n    for i in range(500):\n        yield i\n\nfor row in tqdm(stream_rows(), total=500, desc=\"Rows\"):\n    ...\n```\n\n## Manual Progress Updates\n\nFor downloads, queues, callbacks, or APIs where work completes in chunks, manage the counter explicitly:\n\n```python\nfrom tqdm.auto import tqdm\n\nwith tqdm(total=1024, unit=\"B\", unit_scale=True, desc=\"Download\") as bar:\n    for chunk in chunks:\n        write_chunk(chunk)\n        bar.update(len(chunk))\n```\n\nUseful runtime updates:\n\n```python\nbar.set_description(\"Phase 2\")\nbar.set_postfix(errors=3, cached=True)\nbar.update(1)\n```\n\nUse `leave=False` for short-lived nested or repeated bars that should disappear after completion.\n\n## Async and Concurrent Workloads\n\nFor `asyncio`, use the dedicated helpers instead of manually updating a bar around awaited tasks:\n\n```python\nimport asyncio\nfrom tqdm.asyncio import tqdm_asyncio\n\nasync def fetch(i: int) -> int:\n    await asyncio.sleep(0.1)\n    return i\n\nresults = asyncio.run(\n    tqdm_asyncio.gather(*(fetch(i) for i in range(50)), desc=\"Fetching\")\n)\n```\n\nFor thread or process pools, the contrib helpers are usually simpler than wiring your own executor progress tracking:\n\n```python\nfrom tqdm.contrib.concurrent import thread_map\n\nresults = thread_map(render_item, items, desc=\"Rendering\", max_workers=8)\n```\n\n## Pandas Integration\n\nEnable pandas hooks once, then call the progress-aware methods:\n\n```python\nimport pandas as pd\nfrom tqdm.auto import tqdm\n\ntqdm.pandas(desc=\"Transform\")\n\ndf = pd.DataFrame({\"x\": range(1000)})\ndf[\"y\"] = df[\"x\"].progress_apply(lambda value: value * 2)\n```\n\nThis requires pandas separately; `tqdm` does not install pandas for you.\n\n## Notebook Usage\n\nIf you know the code runs in Jupyter and want notebook widgets explicitly:\n\n```python\nfrom tqdm.notebook import tqdm\n```\n\nFor shared code that runs in both notebooks and terminals, keep using:\n\n```python\nfrom tqdm.auto import tqdm\n```\n\nThat avoids the `autonotebook` warning path while still choosing the right frontend.\n\n## CLI Usage\n\n`tqdm` also ships a command-line interface that reads from `stdin`, writes the original stream to `stdout`, and renders progress on `stderr`.\n\n```bash\npython -m tqdm --help\n```\n\nExample pipeline:\n\n```bash\nfind . -type f | python -m tqdm --unit files > /tmp/files.txt\n```\n\nUse CLI flags such as `--total`, `--unit`, `--unit_scale`, and `--bytes` when the input stream size is known or byte-oriented.\n\n## Configuration and Environment\n\n`tqdm` does not need authentication or service credentials.\n\nConfiguration is usually done through constructor arguments:\n\n```python\nfrom tqdm.auto import tqdm\n\nfor item in tqdm(\n    items,\n    desc=\"Jobs\",\n    total=len(items),\n    mininterval=0.5,\n    smoothing=0.1,\n    dynamic_ncols=True,\n):\n    ...\n```\n\nThe project also supports environment-variable overrides for many constructor options using the `TQDM_` prefix. The official docs explicitly show `TQDM_MININTERVAL=5` as an example.\n\nPractical options:\n\n- `desc`: label shown before the bar.\n- `total`: required for accurate percentage and ETA when length is unknown.\n- `disable`: turn bars off in logs, tests, or non-interactive environments.\n- `leave`: keep or clear completed bars.\n- `position`: place nested bars on separate lines.\n- `dynamic_ncols`: adapt width to the current terminal.\n- `unit`, `unit_scale`, `unit_divisor`: useful for bytes, files, or records.\n\n## Common Pitfalls\n\n- Prefer `from tqdm.auto import tqdm` in reusable application code. Hard-coding `tqdm.notebook` or plain `tqdm` is more brittle across environments.\n- Wrap the real iterable, not `enumerate()` or `zip()` unless you also pass `total=`. Otherwise `tqdm` may not know the length.\n- Use `tqdm.write(...)` instead of `print(...)` while a bar is active to avoid corrupting the display.\n- Close manual bars with `with tqdm(...) as bar:` or `bar.close()`, especially in long-running services or tests.\n- For erratic workloads, set `miniters=1` or tune `mininterval` if the bar appears stale.\n- In CI, some IDE consoles, or plain log collectors, carriage-return updates may render poorly. Use `disable=True`, `ascii=True`, or less frequent refreshes in those environments.\n- Nested bars need distinct `position` values if you manage them manually.\n\n## Version-Sensitive Notes\n\n- This guide covers PyPI version `4.67.3`.\n- The upstream docs site is package-wide rather than version-pinned, so examples generally reflect the current `4.67.x` behavior instead of a frozen `4.67.3` snapshot.\n- PyPI metadata for `4.67.3` lists Python `>=3.7`; check the package page before assuming support for older interpreters.\n- If you depend on notebook widgets, contrib helpers, or CLI flags in automation, verify against the current release history because those surfaces change more often than the basic `tqdm(range(...))` API.\n\n## Official Sources\n\n- Docs: https://tqdm.github.io/\n- API docs index: https://tqdm.github.io/docs/\n- PyPI package: https://pypi.org/project/tqdm/\n- Repository: https://github.com/tqdm/tqdm\n"
  },
  {
    "path": "content/transformers/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hugging Face Transformers Python package for loading, running, fine-tuning, and publishing pretrained transformer models\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.3.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"transformers,hugging-face,python,ml,llm,nlp,vision,audio,pytorch\"\n---\n\n# Hugging Face Transformers Python Package Guide\n\n## Golden Rule\n\nUse `transformers` for model loading, tokenization, pipelines, and training workflows, but match the checkpoint to the correct task-specific class. In `5.3.0`, prefer current Hugging Face Hub auth and cache settings (`hf auth login`, `HF_TOKEN`, `HF_HOME`, `HF_HUB_CACHE`) instead of copying older blog snippets blindly.\n\n## Install\n\nFor most Python projects, install the package pinned to the version you expect and include the PyTorch extra:\n\n```bash\npython -m pip install \"transformers[torch]==5.3.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"transformers[torch]==5.3.0\"\npoetry add \"transformers[torch]==5.3.0\"\n```\n\nIf you manage your deep-learning stack separately, install your hardware-specific PyTorch build first, then install `transformers`:\n\n```bash\npython -m pip install torch\npython -m pip install \"transformers==5.3.0\"\n```\n\nPackages commonly needed around `transformers` workflows:\n\n```bash\npython -m pip install datasets evaluate accelerate\n```\n\nAdd `sentencepiece`, `timm`, or other model-specific dependencies only when the checkpoint or processor you picked requires them.\n\n## Authentication And Cache Setup\n\nPublic model downloads usually work without login. Use authentication when you need gated or private repos, or when your organization rate-limits anonymous access.\n\nInteractive login:\n\n```bash\nhf auth login\n```\n\nEnvironment-based setup:\n\n```bash\nexport HF_TOKEN=\"hf_your_token\"\nexport HF_HOME=\"$HOME/.cache/huggingface\"\nexport HF_HUB_CACHE=\"$HF_HOME/hub\"\n```\n\nNotes:\n\n- `HF_TOKEN` overrides the token saved on disk.\n- `HF_HOME` changes the Hugging Face local data root.\n- `HF_HUB_CACHE` changes where downloaded models, tokenizers, and configs are cached.\n- Pass `token=...` to `from_pretrained()` when you need explicit per-call auth.\n\n## Core Usage\n\n### Fastest path: pipeline\n\n`pipeline()` is the shortest path for common inference tasks:\n\n```python\nfrom transformers import pipeline\n\nclassifier = pipeline(\n    task=\"sentiment-analysis\",\n    model=\"distilbert/distilbert-base-uncased-finetuned-sst-2-english\",\n)\n\nresult = classifier(\"The new setup makes agent handoff faster.\")\nprint(result)\n```\n\nUse this when you want working inference quickly and do not need fine control over tokenization, batching, or generation config.\n\n### Explicit model and tokenizer loading\n\nUse Auto classes when you need predictable control over the model class, device placement, or preprocessing:\n\n```python\nimport torch\nfrom transformers import AutoModelForSequenceClassification, AutoTokenizer\n\ncheckpoint = \"distilbert/distilbert-base-uncased-finetuned-sst-2-english\"\n\ntokenizer = AutoTokenizer.from_pretrained(checkpoint)\nmodel = AutoModelForSequenceClassification.from_pretrained(\n    checkpoint,\n    device_map=\"auto\",\n    dtype=\"auto\",\n)\n\ninputs = tokenizer(\"Transformers handles tokenization for you.\", return_tensors=\"pt\")\n\nwith torch.inference_mode():\n    outputs = model(**inputs)\n\npredicted_label_id = int(outputs.logits.argmax(dim=-1))\nprint(model.config.id2label[predicted_label_id])\n```\n\nRules that matter:\n\n- Use the task head that matches the checkpoint and task, such as `AutoModelForCausalLM`, `AutoModelForSeq2SeqLM`, or `AutoModelForSequenceClassification`.\n- `device_map=\"auto\"` is the easiest way to place large models on available hardware.\n- `dtype=\"auto\"` lets the library choose a sensible model dtype for the checkpoint and backend.\n\n### Loading a gated or private model\n\n```python\nimport os\nfrom transformers import AutoTokenizer, AutoModelForCausalLM\n\ncheckpoint = \"meta-llama/Llama-4-Scout-17B-16E-Instruct\"\ntoken = os.environ[\"HF_TOKEN\"]\n\ntokenizer = AutoTokenizer.from_pretrained(checkpoint, token=token)\nmodel = AutoModelForCausalLM.from_pretrained(\n    checkpoint,\n    token=token,\n    device_map=\"auto\",\n    dtype=\"auto\",\n)\n```\n\nIf the repo is gated, logging in alone is not enough unless the account has been granted access to that checkpoint.\n\n### Fine-tuning with Trainer\n\nThe current quicktour uses `Trainer` and `TrainingArguments` for the standard PyTorch fine-tuning path:\n\n```python\nfrom datasets import load_dataset\nfrom transformers import (\n    AutoModelForSequenceClassification,\n    AutoTokenizer,\n    DataCollatorWithPadding,\n    Trainer,\n    TrainingArguments,\n)\n\ncheckpoint = \"distilbert/distilbert-base-uncased\"\ntokenizer = AutoTokenizer.from_pretrained(checkpoint)\n\ndataset = load_dataset(\"yelp_review_full\")\n\ndef preprocess(batch):\n    return tokenizer(batch[\"text\"], truncation=True)\n\ntokenized = dataset.map(preprocess, batched=True)\ndata_collator = DataCollatorWithPadding(tokenizer=tokenizer)\n\nmodel = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=5)\n\ntraining_args = TrainingArguments(\n    output_dir=\"checkpoints\",\n    eval_strategy=\"epoch\",\n    learning_rate=2e-5,\n    per_device_train_batch_size=8,\n    per_device_eval_batch_size=8,\n    num_train_epochs=1,\n    weight_decay=0.01,\n)\n\ntrainer = Trainer(\n    model=model,\n    args=training_args,\n    train_dataset=tokenized[\"train\"].select(range(1000)),\n    eval_dataset=tokenized[\"test\"].select(range(500)),\n    processing_class=tokenizer,\n    data_collator=data_collator,\n)\n\ntrainer.train()\n```\n\nInstall `accelerate` before using `Trainer` seriously. For larger jobs, verify mixed precision, checkpointing, and distributed-launch settings explicitly instead of relying on defaults.\n\n### Save locally and reload later\n\n```python\nfrom transformers import AutoModel, AutoTokenizer\n\ncheckpoint = \"distilbert/distilbert-base-uncased\"\n\ntokenizer = AutoTokenizer.from_pretrained(checkpoint)\nmodel = AutoModel.from_pretrained(checkpoint)\n\ntokenizer.save_pretrained(\"./artifacts/distilbert\")\nmodel.save_pretrained(\"./artifacts/distilbert\")\n\nreloaded_tokenizer = AutoTokenizer.from_pretrained(\"./artifacts/distilbert\")\nreloaded_model = AutoModel.from_pretrained(\"./artifacts/distilbert\")\n```\n\nUse `save_pretrained()` and `from_pretrained()` instead of manually copying config and weight files.\n\n## Configuration Notes\n\n- Prefer environment variables or `hf auth login` for tokens; do not hardcode access tokens in source.\n- Keep the cache on local SSD when possible. Network-mounted caches are a common cause of slow or flaky loads.\n- For reproducible revisions, pass a model repo commit or tag with `revision=...` to `from_pretrained()`.\n- Use `local_files_only=True` when you need offline-only behavior after the model is already cached.\n\n## Common Pitfalls\n\n- Wrong class for the task: base classes like `LlamaModel` or `BertModel` do not include task heads. Use the `AutoModelFor...` variant that matches generation, classification, token classification, seq2seq, or QA.\n- Missing model dependencies: some checkpoints need optional packages such as `sentencepiece`, `timm`, or audio/image extras. Read the checkpoint card if `from_pretrained()` fails on an import.\n- Assuming login grants access: gated models still require approval on the model page.\n- Device mismatch bugs: tokenized tensors and model weights must live on compatible devices. `pipeline()` or `device_map=\"auto\"` reduces this friction.\n- Old auth examples: prefer `hf auth login` and the `token=` argument. Many older snippets use deprecated or stale patterns.\n- Docs-version drift: the Hugging Face docs site can default to `main` or an older stable selector. Check the version picker when behavior differs from your installed `5.3.0`.\n\n## Version-Sensitive Notes For 5.3.0\n\n- PyPI lists `transformers 5.3.0` with Python `>=3.10`.\n- The installation docs still emphasize that `main` requires installation from source and separately call out the latest stable docs series, so do not assume the first docs page you land on matches your installed package exactly.\n- For new code, prefer current v5-era APIs and examples from the Hugging Face docs instead of older 4.x-era tutorials or issue comments.\n\n## Official Source URLs\n\n- Hugging Face Transformers docs root: https://huggingface.co/docs/transformers/\n- Installation: https://huggingface.co/docs/transformers/main/en/installation\n- Quicktour: https://huggingface.co/docs/transformers/main/en/quicktour\n- Model loading API: https://huggingface.co/docs/transformers/main/en/main_classes/model\n- Hugging Face Hub authentication: https://huggingface.co/docs/huggingface_hub/en/package_reference/authentication\n- Hugging Face Hub environment variables: https://huggingface.co/docs/huggingface_hub/en/package_reference/environment_variables\n- PyPI package page: https://pypi.org/project/transformers/\n"
  },
  {
    "path": "content/trio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Trio structured concurrency runtime for Python async applications\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.33.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"trio,async,structured-concurrency,concurrency,testing\"\n---\n\n# Trio Python Package Guide\n\n## Golden Rule\n\nUse Trio as a structured-concurrency runtime, not as a drop-in `asyncio` clone.\n\n- Start programs with `trio.run(...)`.\n- Group sibling tasks inside `async with trio.open_nursery() as nursery:`.\n- Use Trio deadlines and cancellation scopes (`fail_after`, `move_on_after`, `CancelScope`) instead of ad hoc sleep-and-poll logic.\n- Offload blocking sync work with `trio.to_thread.run_sync(...)`.\n\nThis entry targets Trio `0.33.0`. As of `2026-03-12`, the official docs are split:\n\n- `https://trio.readthedocs.io/en/stable/` still serves Trio `0.32.0` docs.\n- `https://trio.readthedocs.io/en/latest/` and the GitHub `v0.33.0` release notes cover the current `0.33.0` changes.\n\nFor package-pinned `0.33.0` work, use the stable tutorial/reference pages for the enduring APIs, then verify `0.33.0`-specific behavior against PyPI and the `v0.33.0` release notes.\n\n## Installation\n\nInstall the pinned package version:\n\n```bash\npip install \"trio==0.33.0\"\n```\n\n```bash\npoetry add \"trio==0.33.0\"\n```\n\n```bash\nuv add trio==0.33.0\n```\n\nVerify the installed version:\n\n```bash\npython -c \"import trio; print(trio.__version__)\"\n```\n\nIf the project still runs on Python `3.9`, Trio `0.33.0` is not compatible. Either upgrade Python or keep the older Trio line intentionally.\n\n## Initialize And Run\n\nEvery Trio program starts by handing one async entry point to `trio.run(...)`:\n\n```python\nimport trio\n\nasync def main() -> None:\n    print(\"hello from trio\")\n    await trio.sleep(1)\n\nif __name__ == \"__main__\":\n    trio.run(main)\n```\n\nPractical rules:\n\n- `trio.run()` creates and owns the Trio runtime for that call.\n- Do not call `trio.run()` from inside another Trio task.\n- If you need sync setup code, do it before `trio.run(...)` or offload it into a thread once Trio is running.\n\n## Core Usage Pattern: Nurseries\n\nUse a nursery for every group of sibling tasks. Trio waits for child tasks before leaving the nursery and propagates failures through structured cancellation.\n\n```python\nimport trio\n\nasync def worker(name: str, delay: float) -> None:\n    while True:\n        print(f\"{name} tick\")\n        await trio.sleep(delay)\n\nasync def main() -> None:\n    async with trio.open_nursery() as nursery:\n        nursery.start_soon(worker, \"fast\", 0.5)\n        nursery.start_soon(worker, \"slow\", 1.0)\n\n        await trio.sleep(3)\n        nursery.cancel_scope.cancel()\n\ntrio.run(main)\n```\n\nUse `nursery.start(...)` when the parent must wait for the child task to signal readiness:\n\n```python\nimport trio\n\nasync def start_service(*, task_status=trio.TASK_STATUS_IGNORED) -> None:\n    await trio.sleep(0.1)\n    task_status.started(\"ready\")\n    await trio.sleep_forever()\n\nasync def main() -> None:\n    async with trio.open_nursery() as nursery:\n        state = await nursery.start(start_service)\n        print(state)\n        nursery.cancel_scope.cancel()\n\ntrio.run(main)\n```\n\nUse `start_soon(...)` for fire-and-run sibling work. Use `start(...)` for boot sequences, listeners, or background services that must confirm they started cleanly.\n\n## Timeouts, Cancellation, And Shutdown\n\nTrio cancellation is explicit and scoped. Prefer Trio's timeout helpers over manual deadline bookkeeping.\n\n```python\nimport trio\n\nasync def fetch_with_timeout() -> bytes:\n    with trio.fail_after(5):\n        await trio.sleep(1)\n        return b\"done\"\n\nasync def optional_work() -> None:\n    with trio.move_on_after(2) as scope:\n        await trio.sleep(10)\n\n    if scope.cancelled_caught:\n        print(\"timed out without raising\")\n\nasync def main() -> None:\n    print(await fetch_with_timeout())\n    await optional_work()\n\ntrio.run(main)\n```\n\nGuidance:\n\n- `fail_after(...)` raises `TooSlowError` when the deadline expires.\n- `move_on_after(...)` cancels enclosed work but suppresses the timeout exception.\n- Nursery shutdown is driven by `nursery.cancel_scope.cancel()`.\n- These are synchronous context managers inside async code: use `with trio.fail_after(...):`, not `async with`.\n\n## Channels And Task Coordination\n\n`trio.open_memory_channel()` is Trio's in-process queue primitive.\n\n```python\nimport trio\n\nasync def producer(send_channel: trio.MemorySendChannel[int]) -> None:\n    async with send_channel:\n        for value in range(3):\n            await send_channel.send(value)\n\nasync def consumer(receive_channel: trio.MemoryReceiveChannel[int]) -> None:\n    async with receive_channel:\n        async for value in receive_channel:\n            print(value)\n\nasync def main() -> None:\n    send_channel, receive_channel = trio.open_memory_channel[int](0)\n\n    async with trio.open_nursery() as nursery:\n        nursery.start_soon(producer, send_channel.clone())\n        nursery.start_soon(consumer, receive_channel)\n        await send_channel.aclose()\n\ntrio.run(main)\n```\n\nImportant channel semantics:\n\n- Capacity `0` gives backpressure; positive capacities add buffering.\n- Use `.clone()` when multiple tasks need the same endpoint.\n- Close every clone. Receivers only see end-of-stream after every send endpoint is closed.\n\n## Networking, Processes, And Blocking Code\n\nTrio includes practical primitives for low-level networking, subprocesses, and thread offloading.\n\nTCP client:\n\n```python\nimport trio\n\nasync def main() -> None:\n    stream = await trio.open_tcp_stream(\"example.com\", 80)\n    async with stream:\n        await stream.send_all(\n            b\"GET / HTTP/1.1\\r\\n\"\n            b\"Host: example.com\\r\\n\"\n            b\"Connection: close\\r\\n\\r\\n\"\n        )\n        response = await stream.receive_some(4096)\n        print(response.decode(\"ascii\", errors=\"replace\"))\n\ntrio.run(main)\n```\n\nRun blocking sync code safely:\n\n```python\nimport time\nimport trio\n\ndef blocking_lookup() -> str:\n    time.sleep(2)\n    return \"ok\"\n\nasync def main() -> None:\n    result = await trio.to_thread.run_sync(blocking_lookup)\n    print(result)\n\ntrio.run(main)\n```\n\nRun a subprocess:\n\n```python\nimport trio\n\nasync def main() -> None:\n    completed = await trio.run_process(\n        [\"python\", \"-c\", \"print('hello from child')\"],\n        capture_stdout=True,\n    )\n    print(completed.stdout.decode().strip())\n\ntrio.run(main)\n```\n\n## Configuration / Auth\n\nTrio itself has no package-level authentication layer and no global client object.\n\n- Configure behavior at the call site: deadlines, nursery layout, channel capacity, socket settings, subprocess options, and thread-offload boundaries.\n- Network authentication belongs to the higher-level protocol library you are using on top of Trio, not to Trio itself.\n- Prefer explicit arguments and task-local state over mutable globals shared across tasks.\n- If you need ecosystem portability between Trio and `asyncio`, consider an adapter layer such as AnyIO instead of mixing runtime-specific APIs directly.\n\n## Testing\n\nTrio ships dedicated test helpers in `trio.testing`.\n\n- Import `trio.testing` explicitly; it is not imported automatically by `import trio`.\n- Use `trio.testing.MockClock` when you need deterministic time control or auto-jumping sleeps.\n- Confirm the project's runner before authoring fixtures. Common choices are `pytest-trio` or AnyIO's pytest plugin.\n\nExample:\n\n```python\nimport trio\nimport trio.testing\n\nasync def main() -> None:\n    await trio.sleep(10)\n\nclock = trio.testing.MockClock(autojump_threshold=0)\ntrio.run(main, clock=clock)\n```\n\n## Common Pitfalls\n\n- Do not create unmanaged background tasks. Trio expects task lifetimes to be scoped by a nursery.\n- Do not block inside async functions with `time.sleep()`, sync DB drivers, or CPU-heavy work. Use `trio.to_thread.run_sync(...)` or a process boundary.\n- Do not forget to close channel clones. Hanging receives usually mean one send endpoint is still open.\n- Use `nursery.start(...)` for readiness handshakes. `start_soon(...)` does not tell you when startup finished.\n- Do not assume `asyncio`-only libraries will work under Trio. Use AnyIO-compatible libraries or explicit bridges.\n- Import `trio.testing` explicitly before using `MockClock`, memory stream pairs, or other test helpers.\n\n## Version-Sensitive Notes For 0.33.0\n\n- Trio `0.33.0` was released on `2026-02-14` and requires Python `>=3.10`.\n- The official `stable` docs currently lag at Trio `0.32.0`. For `0.33.0`-specific behavior, cross-check PyPI and the GitHub `v0.33.0` release notes.\n- `trio.testing.RaisesGroup` and `trio.testing.Matcher` are deprecated in `0.33.0`; prefer `pytest.RaisesGroup` and `pytest.RaisesExc` in new tests.\n- Android's `sys.platform == \"android\"` support was added in `0.33.0`.\n\n## Official Sources\n\n- Stable docs root: https://trio.readthedocs.io/en/stable/\n- Stable tutorial: https://trio.readthedocs.io/en/stable/tutorial.html\n- Stable core reference: https://trio.readthedocs.io/en/stable/reference-core.html\n- Stable I/O reference: https://trio.readthedocs.io/en/stable/reference-io.html\n- Stable testing reference: https://trio.readthedocs.io/en/stable/reference-testing.html\n- Latest docs root: https://trio.readthedocs.io/en/latest/\n- Latest history / release notes: https://trio.readthedocs.io/en/latest/history.html\n- PyPI project page: https://pypi.org/project/trio/\n- PyPI release metadata: https://pypi.org/pypi/trio\n- GitHub release notes: https://github.com/python-trio/trio/releases/tag/v0.33.0\n"
  },
  {
    "path": "content/trl/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Hugging Face TRL for Python post-training workflows: SFT, preference optimization, reward modeling, and RL trainers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.29.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"trl,huggingface,rlhf,alignment,fine-tuning,llm,training\"\n---\n\n# trl Python Package Guide\n\n## What It Is\n\n`trl` is Hugging Face's training library for LLM post-training workflows in Python. It sits on top of the Hugging Face stack (`transformers`, `datasets`, `accelerate`, optional `peft`) and gives you trainer classes and CLIs for:\n\n- supervised fine-tuning with `SFTTrainer`\n- preference optimization with trainers such as `DPOTrainer`\n- reward modeling\n- RL-style trainers such as GRPO, PPO, RLOO, and KTO\n\nUse it when you already have a Transformers-compatible model and want training loops that match current alignment and post-training patterns.\n\n## Installation\n\nPin to the version you are documenting or reproducing:\n\n```bash\npip install \"trl==0.29.0\"\n```\n\nCommon surrounding packages in real projects:\n\n```bash\npip install \"transformers\" \"datasets\" \"accelerate\"\n```\n\nIf you use parameter-efficient tuning or quantization, install the matching extras in your project environment as well, for example `peft` and hardware-specific dependencies.\n\nPyPI classifiers for `0.29.0` indicate Python `3.10` through `3.14`.\n\n## Setup Checklist\n\nBefore writing code, confirm these pieces:\n\n1. A supported base model or checkpoint is available through `transformers`.\n2. Your dataset shape matches the trainer you plan to use.\n3. `accelerate` is configured if you need multi-GPU or distributed runs.\n4. Any optional integrations you rely on, such as PEFT or experiment tracking, are installed and configured in the environment.\n\nFor distributed training, TRL follows the Hugging Face `accelerate` workflow:\n\n```bash\naccelerate config\n```\n\n## Trainer Picker\n\n- Use `SFTTrainer` for instruction tuning or standard supervised fine-tuning.\n- Use `DPOTrainer` when your dataset contains paired preference examples such as `chosen` and `rejected`.\n- Use reward trainers when you are fitting a reward model from preference data.\n- Use GRPO, PPO, RLOO, or KTO only when you specifically need RL-style post-training and understand the data and rollout requirements.\n\nIf the task is ordinary instruction tuning, start with `SFTTrainer`.\n\n## Minimal SFT Example\n\nThis is the safest starting point for most coding tasks:\n\n```python\nfrom datasets import load_dataset\nfrom trl import SFTConfig, SFTTrainer\n\ndataset = load_dataset(\"trl-lib/Capybara\", split=\"train\")\n\ntrainer = SFTTrainer(\n    model=\"Qwen/Qwen2-0.5B-Instruct\",\n    train_dataset=dataset,\n    args=SFTConfig(\n        output_dir=\"qwen2-sft\",\n    ),\n)\n\ntrainer.train()\ntrainer.save_model()\n```\n\nWhat this assumes:\n\n- the model identifier can be loaded by `transformers`\n- the dataset format is accepted by `SFTTrainer`\n- your runtime has the right CUDA, PyTorch, and accelerator setup if you are training on GPU\n\n## Common Dataset Shapes\n\nTRL documents several supported dataset formats. The ones that matter most in practice are:\n\n- plain text examples for language modeling\n- prompt/completion style examples\n- conversational examples using message arrays\n- preference datasets with `prompt`, `chosen`, and `rejected`\n- tool-calling datasets that include tool schemas and tool interactions\n\nFor coding agents, the main rule is: match your dataset columns to the trainer's expected format instead of forcing one trainer to accept another trainer's schema.\n\nExamples:\n\n- `SFTTrainer`: use text, prompt/completion, or conversational records\n- `DPOTrainer`: use paired preference records\n- reward training: use labeled preference data appropriate for a reward model\n\n## Conversational Training Notes\n\nIf you are fine-tuning an instruction or chat model:\n\n- prefer chat-capable base models\n- keep dataset examples in the conversational structure the tokenizer expects\n- ensure the tokenizer's chat template is compatible with your data\n\nIf generations look malformed, inspect the rendered prompt after chat templating before changing training code.\n\n## CLI Workflows\n\nTRL ships command-line entry points for common training flows. The docs list commands including:\n\n- `trl sft`\n- `trl dpo`\n- `trl grpo`\n- `trl reward`\n- `trl kto`\n- `trl rloo`\n- `trl env`\n- `trl vllm-serve`\n\nStart with:\n\n```bash\ntrl sft --help\n```\n\nUse the CLI when you want a reproducible config-driven run. Use the Python API when you need custom callbacks, preprocessing, or trainer composition inside your codebase.\n\n## Distributed and Large-Model Training\n\nTRL relies on the Hugging Face training stack for scaling:\n\n- `accelerate` for launching distributed runs\n- `transformers` training arguments and model loading\n- optional PEFT adapters for lighter-weight fine-tuning\n- optional vLLM integrations for some workflows\n\nPractical rule: if the launch strategy, mixed precision mode, or sharding approach is unclear, resolve that in `accelerate` and `transformers` first. TRL usually layers on top of those systems rather than replacing them.\n\n## Auth and Configuration\n\nTRL does not introduce a separate package-specific authentication model. In practice:\n\n- public Hub models and datasets can often be loaded directly by name\n- private Hugging Face Hub assets require the usual Hugging Face authentication available to the process\n- experiment tracking integrations, if enabled, require their own environment setup\n\nTreat auth as coming from the surrounding Hugging Face and tooling ecosystem, not from `trl` itself.\n\nUseful environment and setup checks:\n\n- confirm the process can read the model and dataset you reference\n- confirm output directories are writable\n- confirm tracker environment variables are present before enabling reporting\n- confirm `accelerate` config matches the hardware you intend to use\n\n## Saving and Reusing a Trained Model\n\nAfter training, save the output and load it through the normal Transformers APIs:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nmodel = AutoModelForCausalLM.from_pretrained(\"qwen2-sft\")\ntokenizer = AutoTokenizer.from_pretrained(\"qwen2-sft\")\n```\n\nFor chat models, apply the tokenizer's chat template during inference instead of manually concatenating role prefixes unless you know the model format exactly.\n\n## Common Pitfalls\n\n- Installing `trl` without aligning the surrounding `transformers`, `datasets`, `accelerate`, and PyTorch environment.\n- Using the wrong trainer for the dataset shape.\n- Copying examples from `main` docs into a `0.29.0` environment without checking for API drift.\n- Passing conversational data without validating the chat template the tokenizer uses.\n- Treating `trl` as a complete training platform when launch behavior still depends on `accelerate` and `transformers`.\n- Expecting preference or RL trainers to work with ordinary SFT text datasets.\n- Forgetting that large-model workflows may also require PEFT, quantization, or launcher configuration outside TRL.\n\nFor vision-language training, the official docs call out a specific gotcha: set `max_length=None` in `SFTConfig` to avoid truncating image tokens.\n\n## Version-Sensitive Notes For 0.29.0\n\n- The Hugging Face docs expose both `main` and versioned documentation. For `trl==0.29.0`, prefer the `v0.29.0` docs when available.\n- Trainer names and configuration fields can drift across releases. Do not assume examples from older blog posts still match `0.29.0`.\n- CLI coverage is broad in `0.29.0`, but command options can change across releases. Check `--help` against the installed package before scripting runs.\n\n## Recommended Workflow For Agents\n\n1. Pin `trl` to the project's expected version.\n2. Choose the trainer from the dataset shape, not from the model family.\n3. Validate model loading and tokenization with a tiny sample before starting a long run.\n4. Resolve `accelerate`, PEFT, quantization, and tracker setup outside the training loop first.\n5. Save and reload the trained output with standard Transformers APIs.\n\n## Official Sources Used\n\n- TRL docs root: https://huggingface.co/docs/trl/\n- TRL installation docs: https://huggingface.co/docs/trl/installation\n- TRL SFT trainer docs: https://huggingface.co/docs/trl/sft_trainer\n- TRL dataset formats docs: https://huggingface.co/docs/trl/dataset_formats\n- TRL distributed training docs: https://huggingface.co/docs/trl/distributing_training\n- TRL CLI docs: https://huggingface.co/docs/trl/clis\n- PyPI package page: https://pypi.org/project/trl/\n"
  },
  {
    "path": "content/turso/docs/libsql/javascript/DOC.md",
    "content": "---\nname: libsql\ndescription: \"Turso libSQL client for JavaScript/TypeScript with embedded replicas, batch queries, transactions, and ORM integration\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"0.17.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: community\n  tags: \"turso,libsql,sqlite,database,embedded-replicas,edge\"\n---\n\n# Turso libSQL Client Coding Guidelines (JavaScript/TypeScript)\n\nYou are a Turso database expert. Help write code using the official `@libsql/client` SDK for Turso and libSQL databases.\n\n## Golden Rule: Use @libsql/client\n\n**Package:** `@libsql/client` (npm)\n\n**Installation:**\n```bash\nnpm install @libsql/client\n```\n\n**CRITICAL:** Do NOT use these packages:\n- `better-sqlite3` — No remote database or embedded replica support\n- `sql.js` — No Turso integration, no sync capabilities\n- `libsql-client` — Deprecated, old API surface\n\n**What is libSQL:** An open-source fork of SQLite that extends it with remote database access, embedded replicas, and edge-native features while maintaining full backward compatibility with SQLite.\n\n## Client Initialization\n\n### Remote Database\n\n```typescript\nimport { createClient } from \"@libsql/client\";\n\nconst client = createClient({\n  url: \"libsql://my-database-username.turso.tech\",\n  authToken: process.env.TURSO_AUTH_TOKEN,\n});\n```\n\n### Local SQLite File\n\n```typescript\nconst client = createClient({\n  url: \"file:local.db\",\n});\n```\n\n### Embedded Replica (Local + Remote Sync)\n\n```typescript\nconst client = createClient({\n  url: \"file:local-replica.db\",\n  syncUrl: \"libsql://my-database-username.turso.tech\",\n  authToken: process.env.TURSO_AUTH_TOKEN,\n  syncInterval: 60, // Auto-sync every 60 seconds\n});\n\n// Manual sync on demand\nawait client.sync();\n```\n\n### In-Memory Database\n\n```typescript\nconst client = createClient({\n  url: \":memory:\",\n});\n```\n\n### Configuration Options\n\n```typescript\nconst client = createClient({\n  url: \"libsql://...\",\n  authToken: \"...\",\n  concurrency: 20,       // Max concurrent requests (default: 20)\n  intMode: \"number\",     // How to return integers: \"number\" | \"bigint\" | \"string\"\n  encryptionKey: \"...\",   // Encrypt local database file\n});\n```\n\n## Execute Queries\n\n### Basic Queries\n\n```typescript\n// Simple query\nconst result = await client.execute(\"SELECT * FROM users\");\n\n// Positional parameters\nconst result = await client.execute({\n  sql: \"SELECT * FROM users WHERE id = ? AND active = ?\",\n  args: [1, true],\n});\n\n// Named parameters\nconst result = await client.execute({\n  sql: \"SELECT * FROM users WHERE name = :name AND role = :role\",\n  args: { name: \"Alice\", role: \"admin\" },\n});\n```\n\n### Result Shape\n\n```typescript\nconst result = await client.execute(\"INSERT INTO users (name, email) VALUES (?, ?)\", [\"Alice\", \"alice@example.com\"]);\n\nconsole.log(result.columns);         // [\"id\", \"name\", \"email\"]\nconsole.log(result.rows);            // Array of row objects\nconsole.log(result.rowsAffected);    // Number of rows changed (INSERT/UPDATE/DELETE)\nconsole.log(result.lastInsertRowid); // bigint — last auto-increment ID\n\n// Row access\nconst firstRow = result.rows[0];\nconsole.log(firstRow[0]);            // By index\nconsole.log(firstRow.name);          // By column name\n```\n\n### Write Operations\n\n```typescript\n// Insert\nconst { lastInsertRowid } = await client.execute({\n  sql: \"INSERT INTO posts (title, content, author_id) VALUES (?, ?, ?)\",\n  args: [\"Hello World\", \"My first post\", 1],\n});\n\n// Update\nconst { rowsAffected } = await client.execute({\n  sql: \"UPDATE posts SET title = ? WHERE id = ?\",\n  args: [\"Updated Title\", lastInsertRowid],\n});\n\n// Delete\nawait client.execute({\n  sql: \"DELETE FROM posts WHERE id = ?\",\n  args: [postId],\n});\n```\n\n## Batch Operations\n\nBatch executes multiple statements as an implicit transaction (all-or-nothing):\n\n```typescript\nconst results = await client.batch(\n  [\n    {\n      sql: \"INSERT INTO users (name, email) VALUES (?, ?)\",\n      args: [\"Alice\", \"alice@example.com\"],\n    },\n    {\n      sql: \"INSERT INTO users (name, email) VALUES (?, ?)\",\n      args: [\"Bob\", \"bob@example.com\"],\n    },\n    {\n      sql: \"SELECT COUNT(*) as count FROM users\",\n      args: [],\n    },\n  ],\n  \"write\"  // Transaction mode: \"write\" | \"read\" | \"deferred\"\n);\n\n// results is an array of ResultSet objects\nconst count = results[2].rows[0].count;\n```\n\n**Transaction modes:**\n- `\"write\"` — Acquires a write lock immediately. Use for INSERT/UPDATE/DELETE.\n- `\"read\"` — Read-only, concurrent safe. Use for SELECT-only batches.\n- `\"deferred\"` — Acquires lock lazily on first write. Default if omitted.\n\n**Performance:** Batching 1000 inserts completes in ~1.7s vs ~5.3s for sequential `execute()` calls.\n\n## Interactive Transactions\n\nUse when you need application logic between queries:\n\n```typescript\nconst tx = await client.transaction(\"write\");\n\ntry {\n  const { rows } = await tx.execute(\"SELECT balance FROM accounts WHERE id = ?\", [fromId]);\n  const balance = rows[0].balance as number;\n\n  if (balance < amount) {\n    await tx.rollback();\n    throw new Error(\"Insufficient funds\");\n  }\n\n  await tx.execute({\n    sql: \"UPDATE accounts SET balance = balance - ? WHERE id = ?\",\n    args: [amount, fromId],\n  });\n  await tx.execute({\n    sql: \"UPDATE accounts SET balance = balance + ? WHERE id = ?\",\n    args: [amount, toId],\n  });\n\n  await tx.commit();\n} catch (err) {\n  await tx.rollback();\n  throw err;\n} finally {\n  tx.close();\n}\n```\n\n**IMPORTANT:** Always call `tx.close()` in a `finally` block to release the connection. Prefer `batch()` over `transaction()` when you don't need interleaved application logic — it has lower latency.\n\n## Schema Management\n\n```typescript\n// Create table\nawait client.execute(`\n  CREATE TABLE IF NOT EXISTS posts (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    title TEXT NOT NULL,\n    content TEXT,\n    author_id INTEGER REFERENCES users(id),\n    created_at TEXT DEFAULT (datetime('now')),\n    updated_at TEXT\n  )\n`);\n\n// Add index\nawait client.execute(\"CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(author_id)\");\n\n// Migrations via batch (atomic)\nawait client.batch([\n  { sql: \"ALTER TABLE posts ADD COLUMN slug TEXT\", args: [] },\n  { sql: \"CREATE UNIQUE INDEX idx_posts_slug ON posts(slug)\", args: [] },\n], \"write\");\n```\n\n## Embedded Replicas\n\nEmbedded replicas store a local SQLite copy that syncs with the remote Turso database, providing zero-latency reads.\n\n### Architecture\n\n- **Reads:** Served from the local SQLite file (microsecond latency)\n- **Writes:** Sent to the remote primary database\n- **Sync:** Periodic or manual — pulls changes from remote to local\n\n```typescript\nconst client = createClient({\n  url: \"file:./data/replica.db\",\n  syncUrl: \"libsql://my-db-username.turso.tech\",\n  authToken: process.env.TURSO_AUTH_TOKEN,\n  syncInterval: 60, // Auto-sync every 60 seconds\n});\n\n// Initial sync on startup\nawait client.sync();\n\n// Reads are instant (local file)\nconst users = await client.execute(\"SELECT * FROM users\");\n\n// Writes go to remote primary\nawait client.execute({\n  sql: \"INSERT INTO users (name) VALUES (?)\",\n  args: [\"Alice\"],\n});\n\n// Sync to pull latest changes\nconst syncResult = await client.sync();\n```\n\n**Use cases:** VPS/VM deployments, containerized apps, offline-capable applications, read-heavy workloads.\n\n## ORM Integration\n\n### Drizzle ORM\n\n```bash\nnpm install drizzle-orm\nnpm install -D drizzle-kit\n```\n\n```typescript\nimport { drizzle } from \"drizzle-orm/libsql\";\nimport { createClient } from \"@libsql/client\";\nimport { sqliteTable, integer, text } from \"drizzle-orm/sqlite-core\";\n\nconst client = createClient({\n  url: process.env.TURSO_DATABASE_URL!,\n  authToken: process.env.TURSO_AUTH_TOKEN,\n});\n\nconst db = drizzle(client);\n\n// Schema\nconst users = sqliteTable(\"users\", {\n  id: integer(\"id\").primaryKey({ autoIncrement: true }),\n  name: text(\"name\").notNull(),\n  email: text(\"email\").unique(),\n});\n\n// Queries\nconst allUsers = await db.select().from(users);\nconst user = await db.select().from(users).where(eq(users.id, 1));\nawait db.insert(users).values({ name: \"Alice\", email: \"alice@example.com\" });\n```\n\n### Prisma\n\n```bash\nnpm install @prisma/adapter-libsql @libsql/client\n```\n\n```typescript\nimport { PrismaClient } from \"@prisma/client\";\nimport { PrismaLibSQL } from \"@prisma/adapter-libsql\";\n\nconst adapter = new PrismaLibSQL({\n  url: process.env.TURSO_DATABASE_URL!,\n  authToken: process.env.TURSO_AUTH_TOKEN,\n});\n\nconst prisma = new PrismaClient({ adapter });\n\nconst users = await prisma.user.findMany();\n```\n\n## Error Handling\n\n```typescript\nimport { LibsqlError } from \"@libsql/client\";\n\ntry {\n  await client.execute({\n    sql: \"INSERT INTO users (email) VALUES (?)\",\n    args: [\"duplicate@example.com\"],\n  });\n} catch (err) {\n  if (err instanceof LibsqlError) {\n    switch (err.code) {\n      case \"SQLITE_CONSTRAINT\":\n        console.error(\"Constraint violation:\", err.message);\n        break;\n      case \"HRANA_WEBSOCKET_ERROR\":\n        console.error(\"Connection error — retrying...\");\n        break;\n      case \"URL_INVALID\":\n        console.error(\"Invalid database URL\");\n        break;\n      case \"AUTH_ERROR\":\n        console.error(\"Invalid or expired auth token\");\n        break;\n      default:\n        console.error(\"Database error:\", err.code, err.message);\n    }\n  }\n  throw err;\n}\n```\n\n**Retry pattern for transient errors:**\n\n```typescript\nasync function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {\n  for (let attempt = 0; attempt < maxRetries; attempt++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (err instanceof LibsqlError && err.code === \"HRANA_WEBSOCKET_ERROR\" && attempt < maxRetries - 1) {\n        await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));\n        continue;\n      }\n      throw err;\n    }\n  }\n  throw new Error(\"Unreachable\");\n}\n```\n\n## TypeScript Usage\n\n```typescript\n// Type-safe row results\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n  created_at: string;\n}\n\nconst result = await client.execute(\"SELECT * FROM users WHERE id = ?\", [1]);\nconst user = result.rows[0] as unknown as User;\n```\n\n**Column type mapping:**\n\n| SQLite Type | JavaScript Type | Notes |\n|-------------|----------------|-------|\n| INTEGER | `number` or `bigint` | Controlled by `intMode` option |\n| REAL | `number` | |\n| TEXT | `string` | |\n| BLOB | `ArrayBuffer` | |\n| NULL | `null` | |\n\n## Useful Links\n\n- Turso documentation: https://docs.turso.tech/\n- @libsql/client on npm: https://www.npmjs.com/package/@libsql/client\n- libSQL GitHub: https://github.com/tursodatabase/libsql\n- Turso CLI reference: https://docs.turso.tech/cli/introduction\n- Embedded replicas guide: https://docs.turso.tech/features/embedded-replicas/introduction\n- Drizzle + Turso: https://orm.drizzle.team/docs/get-started/turso-existing\n- Prisma + Turso: https://docs.turso.tech/sdk/ts/orm/prisma\n"
  },
  {
    "path": "content/turso/docs/libsql/python/DOC.md",
    "content": "---\nname: libsql\ndescription: \"Turso libSQL client for Python with embedded replicas, batch queries, transactions, and SQLAlchemy integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.1.11\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: community\n  tags: \"turso,libsql,sqlite,database,embedded-replicas,python\"\n---\n\n# Turso libSQL Client Coding Guidelines (Python)\n\nYou are a Turso database expert. Help write Python code using the official `libsql` package for Turso and libSQL databases.\n\n## Golden Rule: Use the libsql Package\n\n**Package:** `libsql` (PyPI)\n\n**Installation:**\n```bash\npip install libsql\n```\n\n**CRITICAL:** Do NOT use these deprecated packages:\n- `libsql-experimental` — Deprecated since June 2025, replaced by `libsql`\n- `libsql-client` — Old HTTP-only client, deprecated API surface\n- `libsql_client` — Same as above (underscore variant)\n\n**What is libSQL:** An open-source fork of SQLite with remote database access, embedded replicas, and edge-native features. The Python SDK provides a DB-API 2.0 compatible interface.\n\n## Client Initialization\n\n### Remote Database\n\n```python\nimport libsql\nimport os\n\nconn = libsql.connect(\n    \"libsql://my-database-username.turso.tech\",\n    auth_token=os.environ[\"TURSO_AUTH_TOKEN\"]\n)\n```\n\n### Local SQLite File\n\n```python\nconn = libsql.connect(\"local.db\")\n```\n\n### Embedded Replica (Local + Remote Sync)\n\n```python\nconn = libsql.connect(\n    \"local-replica.db\",\n    sync_url=\"libsql://my-database-username.turso.tech\",\n    auth_token=os.environ[\"TURSO_AUTH_TOKEN\"],\n    sync_interval=60  # Auto-sync every 60 seconds\n)\n\n# Initial sync on startup\nconn.sync()\n```\n\n### In-Memory Database\n\n```python\nconn = libsql.connect(\":memory:\")\n```\n\n## Execute Queries\n\n### Basic Queries\n\n```python\n# Simple query\ncursor = conn.execute(\"SELECT * FROM users\")\nrows = cursor.fetchall()\n\n# Positional parameters\ncursor = conn.execute(\n    \"SELECT * FROM users WHERE id = ? AND active = ?\",\n    [1, True]\n)\nuser = cursor.fetchone()\n\n# Named parameters (dict)\ncursor = conn.execute(\n    \"SELECT * FROM users WHERE name = :name AND role = :role\",\n    {\"name\": \"Alice\", \"role\": \"admin\"}\n)\n```\n\n### Result Access\n\n```python\ncursor = conn.execute(\"SELECT id, name, email FROM users\")\n\n# Fetch all rows (list of tuples)\nall_rows = cursor.fetchall()\nfor row in all_rows:\n    print(row[0], row[1], row[2])  # By index\n\n# Fetch one row\none_row = cursor.fetchone()\n\n# Column names\nprint(cursor.description)  # List of (name, type_code, ...) tuples\ncolumn_names = [desc[0] for desc in cursor.description]\n```\n\n### Write Operations\n\n```python\n# Insert\ncursor = conn.execute(\n    \"INSERT INTO posts (title, content, author_id) VALUES (?, ?, ?)\",\n    [\"Hello World\", \"My first post\", 1]\n)\nlast_id = cursor.lastrowid\nconn.commit()\n\n# Update\ncursor = conn.execute(\n    \"UPDATE posts SET title = ? WHERE id = ?\",\n    [\"Updated Title\", last_id]\n)\naffected = cursor.rowcount\nconn.commit()\n\n# Delete\nconn.execute(\"DELETE FROM posts WHERE id = ?\", [post_id])\nconn.commit()\n```\n\n**IMPORTANT:** Always call `conn.commit()` after write operations. Without commit, changes are not persisted.\n\n### Bulk Insert\n\n```python\nconn.executemany(\n    \"INSERT INTO users (name, email) VALUES (?, ?)\",\n    [\n        (\"Alice\", \"alice@example.com\"),\n        (\"Bob\", \"bob@example.com\"),\n        (\"Charlie\", \"charlie@example.com\"),\n    ]\n)\nconn.commit()\n```\n\n## Transactions\n\n### Explicit Transactions\n\n```python\nconn.execute(\"BEGIN\")\ntry:\n    conn.execute(\n        \"UPDATE accounts SET balance = balance - ? WHERE id = ?\",\n        [amount, from_id]\n    )\n    conn.execute(\n        \"UPDATE accounts SET balance = balance + ? WHERE id = ?\",\n        [amount, to_id]\n    )\n    conn.commit()\nexcept Exception:\n    conn.rollback()\n    raise\n```\n\n### Context Manager\n\n```python\n# Auto-commits on success, auto-rollbacks on exception\nwith conn:\n    conn.execute(\n        \"INSERT INTO users (name) VALUES (?)\",\n        [\"Alice\"]\n    )\n    conn.execute(\n        \"INSERT INTO users (name) VALUES (?)\",\n        [\"Bob\"]\n    )\n# Changes are committed automatically here\n```\n\n## Schema Management\n\n```python\n# Create table\nconn.execute(\"\"\"\n    CREATE TABLE IF NOT EXISTS posts (\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        title TEXT NOT NULL,\n        content TEXT,\n        author_id INTEGER REFERENCES users(id),\n        created_at TEXT DEFAULT (datetime('now')),\n        updated_at TEXT\n    )\n\"\"\")\n\n# Add index\nconn.execute(\"CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(author_id)\")\n\n# Multi-statement DDL\nconn.executescript(\"\"\"\n    ALTER TABLE posts ADD COLUMN slug TEXT;\n    CREATE UNIQUE INDEX idx_posts_slug ON posts(slug);\n\"\"\")\n\nconn.commit()\n```\n\n## Embedded Replicas\n\nEmbedded replicas store a local SQLite copy synced with the remote Turso database.\n\n### Architecture\n\n- **Reads:** Served from the local SQLite file (microsecond latency)\n- **Writes:** Sent to the remote primary database\n- **Sync:** Periodic or manual — pulls changes from remote to local\n\n```python\nimport libsql\nimport os\n\nconn = libsql.connect(\n    \"replica.db\",\n    sync_url=\"libsql://my-db-username.turso.tech\",\n    auth_token=os.environ[\"TURSO_AUTH_TOKEN\"],\n    sync_interval=60  # Auto-sync every 60 seconds\n)\n\n# Initial sync\nconn.sync()\n\n# Reads are instant (local file)\ncursor = conn.execute(\"SELECT * FROM users\")\nusers = cursor.fetchall()\n\n# Writes go to remote primary\nconn.execute(\"INSERT INTO users (name) VALUES (?)\", [\"Alice\"])\nconn.commit()\n\n# Pull latest changes\nconn.sync()\n```\n\n**Use cases:** Server deployments, containerized apps, offline-capable applications, read-heavy workloads.\n\n## ORM Integration\n\n### SQLAlchemy\n\n```bash\npip install sqlalchemy-libsql\n```\n\n```python\nfrom sqlalchemy import create_engine, Column, Integer, String\nfrom sqlalchemy.orm import declarative_base, Session\n\n# Remote Turso database\nengine = create_engine(\n    \"sqlite+libsql://my-database-username.turso.tech\",\n    connect_args={\"auth_token\": os.environ[\"TURSO_AUTH_TOKEN\"]},\n)\n\n# Local SQLite\nengine = create_engine(\"sqlite+libsql:///local.db\")\n\nBase = declarative_base()\n\nclass User(Base):\n    __tablename__ = \"users\"\n    id = Column(Integer, primary_key=True)\n    name = Column(String, nullable=False)\n    email = Column(String, unique=True)\n\n# Create tables\nBase.metadata.create_all(engine)\n\n# Query\nwith Session(engine) as session:\n    users = session.query(User).all()\n    session.add(User(name=\"Alice\", email=\"alice@example.com\"))\n    session.commit()\n```\n\n### Django\n\n```bash\npip install django-turso\n```\n\n```python\n# settings.py\nDATABASES = {\n    \"default\": {\n        \"ENGINE\": \"django_turso\",\n        \"NAME\": \"libsql://my-database-username.turso.tech\",\n        \"OPTIONS\": {\n            \"auth_token\": os.environ[\"TURSO_AUTH_TOKEN\"],\n        },\n    }\n}\n```\n\n## Error Handling\n\n```python\nimport libsql\n\ntry:\n    conn.execute(\n        \"INSERT INTO users (email) VALUES (?)\",\n        [\"duplicate@example.com\"]\n    )\n    conn.commit()\nexcept libsql.IntegrityError as e:\n    # Constraint violation (unique, foreign key, NOT NULL)\n    print(f\"Constraint error: {e}\")\n    conn.rollback()\nexcept libsql.OperationalError as e:\n    # Connection, SQL syntax, or table not found errors\n    if \"no such table\" in str(e):\n        print(\"Table does not exist\")\n    elif \"network\" in str(e).lower():\n        print(\"Network error — check connection\")\n    else:\n        print(f\"Operational error: {e}\")\n    conn.rollback()\nexcept libsql.ProgrammingError as e:\n    # Misuse of the API (e.g., executing after close)\n    print(f\"Programming error: {e}\")\n```\n\n**Retry pattern for transient errors:**\n\n```python\nimport time\n\ndef with_retry(fn, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            return fn()\n        except libsql.OperationalError as e:\n            if \"network\" in str(e).lower() and attempt < max_retries - 1:\n                time.sleep(2 ** attempt)\n                continue\n            raise\n```\n\n## Async Usage\n\n```python\nimport libsql\nimport asyncio\n\nasync def main():\n    conn = libsql.connect(\n        \"libsql://my-database-username.turso.tech\",\n        auth_token=os.environ[\"TURSO_AUTH_TOKEN\"]\n    )\n\n    cursor = conn.execute(\"SELECT * FROM users\")\n    users = cursor.fetchall()\n\n    conn.execute(\"INSERT INTO users (name) VALUES (?)\", [\"Alice\"])\n    conn.commit()\n\n    conn.close()\n\nasyncio.run(main())\n```\n\n**IMPORTANT:** The Python `libsql` package uses synchronous I/O internally. For async web frameworks (FastAPI, Starlette), run database operations in a thread pool:\n\n```python\nfrom fastapi import FastAPI\nfrom concurrent.futures import ThreadPoolExecutor\nimport asyncio\n\napp = FastAPI()\nexecutor = ThreadPoolExecutor(max_workers=4)\n\ndef query_users():\n    cursor = conn.execute(\"SELECT * FROM users\")\n    return cursor.fetchall()\n\n@app.get(\"/users\")\nasync def get_users():\n    loop = asyncio.get_event_loop()\n    users = await loop.run_in_executor(executor, query_users)\n    return {\"users\": users}\n```\n\n## Useful Links\n\n- Turso documentation: https://docs.turso.tech/\n- libsql on PyPI: https://pypi.org/project/libsql/\n- libSQL GitHub: https://github.com/tursodatabase/libsql\n- Turso CLI reference: https://docs.turso.tech/cli/introduction\n- Embedded replicas guide: https://docs.turso.tech/features/embedded-replicas/introduction\n- SQLAlchemy dialect: https://github.com/libsql/sqlalchemy-libsql\n- Django backend: https://github.com/nichochar/django-turso\n"
  },
  {
    "path": "content/twilio/docs/messaging/python/DOC.md",
    "content": "---\nname: messaging\ndescription: \"Cloud communications platform for SMS, voice, video, and WhatsApp messaging with programmable APIs\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.8.4\"\n  updated-on: \"2025-09-25\"\n  source: maintainer\n  tags: \"twilio,sdk,sms,voice,communications\"\n---\n# Twilio Python Library Coding Guidelines\n\nYou are a Twilio Python SDK expert. Help me with writing code using the Twilio Python library to interact with Twilio's communication APIs.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://www.twilio.com/docs/libraries/python\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Twilio Python library to interact with Twilio APIs, which is the standard and actively maintained library for all Twilio API interactions.\n\n- **Library Name:** Twilio Python Helper Library\n- **Python Package:** `twilio`\n- **Current Version:** 9.6.0+\n\n**Installation:**\n\n- **Correct:** `pip3 install twilio`\n- **Incorrect:** `pip install twilio-sdk` or other unofficial packages\n\n**APIs and Usage:**\n\n- **Correct:** `from twilio.rest import Client`\n- **Incorrect:** `import twilio` (doesn't expose the Client directly)\n- **Correct:** `client = Client(account_sid, auth_token)`\n- **Correct:** `client.messages.create(...)`\n- **Correct:** `from twilio.base.exceptions import TwilioRestException`\n\n## Supported Python Versions\n\nThe library supports the following Python versions:\n\n- Python 3.7\n- Python 3.8\n- Python 3.9\n- Python 3.10\n- Python 3.11\n\n## Installation and Setup\n\nInstall using pip:\n\n```bash\npip3 install twilio\n```\n\nFor development, you can also install from source:\n\n```bash\npython3 setup.py install\n```\n\n## Initialization and Authentication\n\nThe Twilio client supports multiple authentication methods:\n\n### Account SID and Auth Token Authentication\n\n```python\nfrom twilio.rest import Client\n\naccount_sid = \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\nauth_token = \"your_auth_token\"\nclient = Client(account_sid, auth_token)\n```\n\n### API Key and Secret Authentication\n\n```python\nfrom twilio.rest import Client\n\napi_key = \"XXXXXXXXXXXXXXXXX\"\napi_secret = \"YYYYYYYYYYYYYYYYYY\"\naccount_sid = \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\nclient = Client(api_key, api_secret, account_sid)\n```\n\n### Environment Variables\n\nUse environment variables for security:\n\n```python\nfrom twilio.rest import Client\n# Looks for TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN\nclient = Client()\n```\n\n### Regional Configuration\n\nFor global infrastructure, specify region and edge:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(region='au1', edge='sydney')\n# Or set after initialization\nclient.region = 'au1'\nclient.edge = 'sydney'\n```\n\n## Core Messaging Features\n\n### Send SMS Messages\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(account_sid, auth_token)\n\nmessage = client.messages.create(\n    to=\"+15558675309\",\n    from_=\"+15017250604\",\n    body=\"Hello from Python!\"\n)\n\nprint(message.sid)\n```\n\n### Send MMS with Media\n\n```python\nmessage = client.messages.create(\n    to=\"+15558675309\",\n    from_=\"+15017250604\",\n    body=\"Check out this image!\",\n    media_url=[\"https://example.com/image.jpg\"]\n)\n```\n\n### Retrieve Message Information\n\n```python\n# Get specific message\nmessage = client.messages.get(\"MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\")\nprint(f\"Status: {message.status}\")\nprint(f\"Direction: {message.direction}\")\nprint(f\"Error Code: {message.error_code}\")\n```\n\n## Voice Features\n\n### Make Phone Calls\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(account_sid, auth_token)\n\ncall = client.calls.create(\n    to=\"+15558675309\",\n    from_=\"+15017250604\",\n    url=\"http://demo.twilio.com/docs/voice.xml\"\n)\n\nprint(call.sid)\n```\n\n### Get Call Information\n\n```python\ncall = client.calls.get(\"CA42ed11f93dc08b952027ffbc406d0868\")\nprint(f\"Duration: {call.duration}\")\nprint(f\"Status: {call.status}\")\n```\n\n## Data Iteration and Pagination\n\nThe library handles pagination automatically:\n\n### Using List Method\n\n```python\n# Get all messages (automatically handles pagination)\nfor message in client.messages.list():\n    print(f\"To: {message.to}, Body: {message.body}\")\n\n# With limits and page size\nmessages = client.messages.list(limit=20, page_size=10)\n```\n\n### Using Stream Method\n\n```python\n# Lazy loading with iterator\nfor message in client.messages.stream(limit=100):\n    print(message.sid)\n```\n\n## TwiML Generation\n\nGenerate TwiML responses for webhooks:\n\n### Voice TwiML\n\n```python\nfrom twilio.twiml.voice_response import VoiceResponse\n\nresponse = VoiceResponse()\nresponse.say(\"Hello! Welcome to our service.\")\nresponse.play(\"https://api.twilio.com/cowbell.mp3\")\n\n# For call forwarding\nresponse.dial(\"+15551234567\")\n\nprint(str(response))\n```\n\n### Messaging TwiML\n\n```python\nfrom twilio.twiml.messaging_response import MessagingResponse\n\nresponse = MessagingResponse()\nresponse.message(\"Thanks for your message! We'll get back to you soon.\")\n\nprint(str(response))\n```\n\n### Advanced Voice TwiML\n\n```python\nfrom twilio.twiml.voice_response import VoiceResponse, Gather\n\nresponse = VoiceResponse()\n\ngather = Gather(input='speech dtmf', timeout=3, action='/process-input')\ngather.say(\"Please say your name or press a key\")\nresponse.append(gather)\n\n# Fallback if no input\nresponse.say(\"We didn't receive any input. Goodbye!\")\n```\n\n## Asynchronous Operations\n\nFor non-blocking requests, use async client:\n\n```python\nimport asyncio\nfrom twilio.http.async_http_client import AsyncTwilioHttpClient\nfrom twilio.rest import Client\n\nasync def send_message_async():\n    account_sid = \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n    auth_token = \"your_auth_token\"\n\n    http_client = AsyncTwilioHttpClient()\n    client = Client(account_sid, auth_token, http_client=http_client)\n\n    message = await client.messages.create_async(\n        to=\"+12316851234\",\n        from_=\"+15555555555\",\n        body=\"Hello there!\"\n    )\n\n    return message.sid\n\n# Run the async function\nresult = asyncio.run(send_message_async())\n```\n\n## Error Handling\n\nHandle Twilio-specific exceptions:\n\n```python\nfrom twilio.rest import Client\nfrom twilio.base.exceptions import TwilioRestException\n\nclient = Client(account_sid, auth_token)\n\ntry:\n    message = client.messages.create(\n        to=\"+12316851234\",\n        from_=\"+15555555555\",\n        body=\"Hello there!\"\n    )\nexcept TwilioRestException as e:\n    print(f\"Twilio Error {e.status}: {e.msg}\")\n    print(f\"Error Code: {e.code}\")\n    print(f\"More info: https://www.twilio.com/docs/errors/{e.code}\")\nexcept Exception as e:\n    print(f\"Other error: {e}\")\n```\n\n## Webhook Validation\n\nValidate incoming webhook requests:\n\n```python\nfrom twilio.request_validator import RequestValidator\n\ndef validate_twilio_request(request):\n    validator = RequestValidator(\"your_auth_token\")\n\n    # Get the URL and signature from request\n    url = request.url\n    params = request.form  # or request.json for JSON requests\n    signature = request.headers.get('X-Twilio-Signature', '')\n\n    if validator.validate(url, params, signature):\n        return True\n    else:\n        return False\n\n# Example with Flask\nfrom flask import Flask, request\n\napp = Flask(__name__)\n\n@app.route(\"/webhook\", methods=['POST'])\ndef handle_webhook():\n    if not validate_twilio_request(request):\n        return \"Unauthorized\", 401\n\n    # Process the webhook\n    return \"OK\", 200\n```\n\n## Advanced Features\n\n### Custom HTTP Client\n\nCreate custom HTTP client for proxy support:\n\n```python\nfrom twilio.http.http_client import TwilioHttpClient\nfrom twilio.rest import Client\nimport os\n\nclass ProxyHttpClient(TwilioHttpClient):\n    def request(self, method, url, params=None, data=None, headers=None,\n                auth=None, timeout=None, allow_redirects=False):\n        # Customize the request here\n        session = self._build_session()\n        session.proxies.update({\n            'http': os.environ.get('HTTP_PROXY'),\n            'https': os.environ.get('HTTPS_PROXY')\n        })\n\n        response = session.request(\n            method=method,\n            url=url,\n            params=params,\n            data=data,\n            headers=headers,\n            auth=auth,\n            timeout=timeout,\n            allow_redirects=allow_redirects\n        )\n\n        return self._build_response(response)\n\n# Use custom client\ncustom_client = ProxyHttpClient()\nclient = Client(account_sid, auth_token, http_client=custom_client)\n```\n\n### Debug Logging\n\nEnable request/response logging:\n\n```python\nimport logging\nfrom twilio.rest import Client\n\nclient = Client(account_sid, auth_token)\n\n# Log to console\nlogging.basicConfig()\nclient.http_client.logger.setLevel(logging.INFO)\n\n# Log to file\nlogging.basicConfig(filename='./twilio_log.txt')\nclient.http_client.logger.setLevel(logging.INFO)\n```\n\n### Advanced Service Access\n\nAccess specific Twilio services directly:\n\n```python\n# Video API\nrooms = client.video.rooms.list()\n\n# Verify API\nverification = client.verify.services(\"VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\") \\\n    .verifications.create(to=\"+15017122661\", channel=\"sms\")\n\n# Sync API\nsync_service = client.sync.services.create(friendly_name=\"My Service\")\n\n# Studio API\nexecutions = client.studio.flows(\"FWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\") \\\n    .executions.list()\n```\n\n## Best Practices\n\n### Security\n- Always use environment variables for credentials\n- Validate webhook requests\n- Use API keys instead of Auth Tokens when possible\n- Implement proper error handling\n\n### Performance\n- Use pagination limits for large datasets\n- Consider async operations for high-volume applications\n- Implement retry logic for network failures\n- Use connection pooling for multiple requests\n\n### Error Handling\n- Always catch `TwilioRestException` for API errors\n- Check response status codes\n- Log errors with context for debugging\n- Implement graceful fallbacks\n\n### Resource Management\n- Close async clients properly\n- Use context managers when appropriate\n- Monitor API usage and rate limits\n- Cache frequently accessed data\n\n## Available APIs and Services\n\nThe Twilio Python library provides access to numerous APIs:\n\n- **Messaging**: SMS, MMS, WhatsApp, Facebook Messenger\n- **Voice**: Calls, conferences, recordings, transcriptions\n- **Video**: Rooms, participants, compositions\n- **Verify**: Phone verification, TOTP, email verification\n- **Sync**: Real-time synchronization\n- **Chat**: Programmable chat (legacy)\n- **Conversations**: Next-generation chat and messaging\n- **Studio**: Visual workflow builder\n- **Functions**: Serverless runtime\n- **Flex**: Contact center platform\n- **TaskRouter**: Workflow and task distribution\n- **Proxy**: Phone number masking\n- **Notify**: Push notifications and messaging\n- **Authy**: Two-factor authentication (via Verify)\n- **Lookup**: Phone number intelligence\n- **Pricing**: Cost information\n- **Usage**: Account usage statistics\n\n## Useful Links\n\n- Documentation: https://www.twilio.com/docs/libraries/python\n- API Reference: https://www.twilio.com/docs/api\n- TwiML Reference: https://www.twilio.com/docs/voice/twiml\n- Console: https://console.twilio.com\n- Status Page: https://status.twilio.com\n- Support: https://support.twilio.com\n\n## Notes\n\nThe Twilio Python library is auto-generated from OpenAPI specifications, ensuring it stays current with Twilio's APIs. Always refer to the official documentation for the most up-to-date API parameters and responses. The library provides both synchronous and asynchronous interfaces, comprehensive error handling, and extensive webhook validation capabilities for building robust communication applications.\n"
  },
  {
    "path": "content/twilio/docs/messaging/typescript/DOC.md",
    "content": "---\nname: messaging\ndescription: \"Cloud communications platform for SMS, voice, video, and WhatsApp messaging with programmable APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.10.3\"\n  updated-on: \"2025-09-25\"\n  source: maintainer\n  tags: \"twilio,sdk,sms,voice,communications\"\n---\n# Twilio Node.js Coding Guidelines\n\nYou are a Twilio API coding expert. Help me with writing code using the Twilio Node.js library for building communication applications with SMS, voice calls, WhatsApp, and other messaging channels.\n\nPlease follow the following guidelines when generating code.\n\nYou can find the official SDK documentation and code samples here:\nhttps://www.twilio.com/docs/libraries/reference/twilio-node/\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the official Twilio Node.js library, which is the standard library for all Twilio API interactions.\n\n**Library Name:** Twilio Node.js Helper Library\n**NPM Package:** `twilio`\n**Supported Node.js Versions:** Node.js 18, 20, 22 (LTS)\n\n**Installation:**\n- **Correct:** `npm install twilio` or `yarn add twilio`\n\n**APIs and Usage:**\n- **Correct:** `const client = require('twilio')(accountSid, authToken)`\n- **Correct:** `client.messages.create({...})` for SMS/MMS\n- **Correct:** `client.calls.create({...})` for voice calls\n- **Incorrect:** Using legacy or unofficial Twilio libraries\n- **Incorrect:** Exposing credentials in front-end applications\n\n## Authentication and Initialization\n\nThe Twilio Node.js library requires your Account SID and Auth Token for authentication.\n\n### Environment Variables (Recommended)\n\nSet up environment variables for secure credential management:\n\n```javascript\n// Uses TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN environment variables\nconst client = require('twilio')();\n\n// Or explicitly pass credentials\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\nconst client = require('twilio')(accountSid, authToken);\n```\n\n### Client Configuration Options\n\nThe Twilio client supports various configuration options:\n\n```javascript\nconst client = require('twilio')(accountSid, authToken, {\n  lazyLoading: false,        // Disable lazy loading for faster initial loads\n  autoRetry: true,           // Enable automatic retry with exponential backoff\n  maxRetries: 3,             // Maximum number of retries\n  timeout: 30000,            // HTTPS agent socket timeout in milliseconds\n  keepAlive: true,           // Enable connection reuse\n  keepAliveMsecs: 1000,      // Keep-alive timeout\n  maxSockets: 20,            // Maximum number of sockets\n  region: 'au1',             // Specify region for Global Infrastructure\n  edge: 'sydney',            // Specify edge location\n  logLevel: 'debug'          // Enable debug logging\n});\n```\n\n## Core Messaging (SMS/MMS)\n\n### Basic SMS Messaging\n\nSend SMS messages using the Messages API:\n\n```javascript\nconst client = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);\n\nasync function sendSMS() {\n  try {\n    const message = await client.messages.create({\n      body: 'Hello from Twilio!',\n      to: '+1234567890',     // Recipient's phone number in E.164 format\n      from: '+0987654321'    // Your Twilio phone number\n    });\n    console.log(`Message sent with SID: ${message.sid}`);\n  } catch (error) {\n    console.error('Error sending SMS:', error);\n  }\n}\n```\n\n### MMS with Media\n\nSend MMS messages with media attachments:\n\n```javascript\nasync function sendMMS() {\n  const message = await client.messages.create({\n    body: 'Check out this image!',\n    to: '+1234567890',\n    from: '+0987654321',\n    mediaUrl: [\n      'https://example.com/image.jpg',\n      'https://example.com/video.mp4'\n    ]\n  });\n  console.log(`MMS sent with SID: ${message.sid}`);\n}\n```\n\n### WhatsApp Messaging\n\nSend WhatsApp messages using channel addressing:\n\n```javascript\nasync function sendWhatsApp() {\n  const message = await client.messages.create({\n    body: 'Hello via WhatsApp!',\n    to: 'whatsapp:+1234567890',\n    from: 'whatsapp:+0987654321'\n  });\n  console.log(`WhatsApp message sent: ${message.sid}`);\n}\n```\n\n### Using Messaging Services\n\nUse Messaging Services for better delivery and sender pool management:\n\n```javascript\nasync function sendWithMessagingService() {\n  const message = await client.messages.create({\n    body: 'Hello from Messaging Service!',\n    to: '+1234567890',\n    messagingServiceSid: 'MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'\n    // 'from' parameter is optional when using Messaging Service\n  });\n}\n```\n\n## Voice Calls\n\n### Making Phone Calls\n\nCreate outbound calls using the Calls API:\n\n```javascript\nasync function makeCall() {\n  try {\n    const call = await client.calls.create({\n      to: '+1234567890',                    // Number to call\n      from: '+0987654321',                  // Your Twilio number\n      url: 'https://example.com/twiml',     // TwiML instructions URL\n      method: 'POST',                       // HTTP method for TwiML URL\n      statusCallback: 'https://example.com/status',\n      statusCallbackEvent: ['initiated', 'ringing', 'answered', 'completed'],\n      timeout: 30,                          // Ring timeout in seconds\n      record: true                          // Record the call\n    });\n    console.log(`Call initiated with SID: ${call.sid}`);\n  } catch (error) {\n    console.error('Error making call:', error);\n  }\n}\n```\n\n### Using TwiML Directly\n\nPass TwiML instructions directly without external URLs:\n\n```javascript\nconst twilio = require('twilio');\nconst VoiceResponse = twilio.twiml.VoiceResponse;\n\nasync function makeCallWithTwiML() {\n  const twiml = new VoiceResponse();\n  twiml.say('Hello! This is a call from Twilio.');\n  twiml.hangup();\n\n  const call = await client.calls.create({\n    to: '+1234567890',\n    from: '+0987654321',\n    twiml: twiml.toString()\n  });\n}\n```\n\n## TwiML Generation\n\n### Voice TwiML\n\nGenerate TwiML for voice applications:\n\n```javascript\nconst twilio = require('twilio');\nconst VoiceResponse = twilio.twiml.VoiceResponse;\n\nfunction generateVoiceTwiML() {\n  const twiml = new VoiceResponse();\n\n  // Text-to-speech\n  twiml.say({\n    voice: 'alice',\n    language: 'en-US'\n  }, 'Hello, thanks for calling!');\n\n  // Play audio file\n  twiml.play('https://example.com/welcome.mp3');\n\n  // Gather user input\n  const gather = twiml.gather({\n    numDigits: 1,\n    action: '/process-input',\n    method: 'POST'\n  });\n  gather.say('Press 1 for sales, 2 for support');\n\n  // Dial another number\n  twiml.dial('+1234567890');\n\n  return twiml.toString();\n}\n```\n\n### Advanced Voice Features\n\nUse advanced voice capabilities:\n\n```javascript\nfunction advancedVoiceTwiML() {\n  const twiml = new VoiceResponse();\n\n  // Conference calling\n  const dial = twiml.dial();\n  dial.conference('Customer Support Conference');\n\n  // Record call\n  twiml.record({\n    action: '/handle-recording',\n    method: 'POST',\n    maxLength: 30,\n    transcribe: true\n  });\n\n  // Connect to client/browser\n  const dial2 = twiml.dial();\n  dial2.client('john');\n\n  return twiml.toString();\n}\n```\n\n### Messaging TwiML\n\nGenerate TwiML responses for incoming messages:\n\n```javascript\nconst MessagingResponse = twilio.twiml.MessagingResponse;\n\nfunction generateMessagingTwiML() {\n  const twiml = new MessagingResponse();\n  twiml.message('Thanks for your message! We will get back to you soon.');\n  return twiml.toString();\n}\n```\n\n## Webhook Handling and Validation\n\n### Express.js Webhook Integration\n\nHandle and validate incoming Twilio webhooks:\n\n```javascript\nconst express = require('express');\nconst twilio = require('twilio');\n\nconst app = express();\napp.use(express.urlencoded({ extended: false }));\n\n// Webhook validation\nfunction validateTwilioSignature(req, res, next) {\n  const twilioSignature = req.headers['x-twilio-signature'];\n  const params = req.body;\n  const url = `https://${req.headers.host}${req.originalUrl}`;\n\n  const isValid = twilio.validateRequest(\n    process.env.TWILIO_AUTH_TOKEN,\n    twilioSignature,\n    url,\n    params\n  );\n\n  if (!isValid) {\n    return res.status(403).send('Forbidden');\n  }\n  next();\n}\n\n// Handle incoming calls\napp.post('/voice', validateTwilioSignature, (req, res) => {\n  const twiml = new twilio.twiml.VoiceResponse();\n  twiml.say('Hello from your webhook!');\n  res.type('text/xml');\n  res.send(twiml.toString());\n});\n\n// Handle incoming messages\napp.post('/sms', validateTwilioSignature, (req, res) => {\n  const twiml = new twilio.twiml.MessagingResponse();\n  const incomingMessage = req.body.Body;\n\n  if (incomingMessage.toLowerCase() === 'hello') {\n    twiml.message('Hi there! How can I help you?');\n  } else {\n    twiml.message('Thanks for your message!');\n  }\n\n  res.type('text/xml');\n  res.send(twiml.toString());\n});\n```\n\n### Webhook Validation Utilities\n\nUse built-in validation helpers:\n\n```javascript\n// For Express.js\nconst isValid = twilio.validateExpressRequest(req, authToken);\n\n// For general request validation\nconst isValid = twilio.validateRequest(\n  authToken,\n  twilioSignature,\n  url,\n  params\n);\n\n// Validate request with body\nconst isValid = twilio.validateRequestWithBody(\n  authToken,\n  twilioSignature,\n  url,\n  body\n);\n```\n\n## Error Handling and Debugging\n\n### Exception Handling\n\nHandle Twilio API errors gracefully:\n\n```javascript\n// With promises\nclient.messages.create({\n  body: 'Hello from Node',\n  to: '+12345678901',\n  from: '+12345678901',\n})\n.then((message) => console.log(message))\n.catch((error) => {\n  console.log(error.code);     // Twilio error code\n  console.log(error.message);  // Error message\n  console.log(error.status);   // HTTP status code\n});\n\n// With async/await\ntry {\n  const message = await client.messages.create({\n    body: 'Hello from Node',\n    to: '+12345678901',\n    from: '+12345678901',\n  });\n  console.log(message);\n} catch (error) {\n  console.error('Twilio Error:', error.code, error.message);\n}\n```\n\n### Debug Logging\n\nEnable debug logging to troubleshoot issues:\n\n```javascript\n// Via environment variable\nprocess.env.TWILIO_LOG_LEVEL = 'debug';\n\n// Via client configuration\nconst client = require('twilio')(accountSid, authToken, {\n  logLevel: 'debug'\n});\n\n// Set after client creation\nclient.logLevel = 'debug';\n```\n\n### Request/Response Debugging\n\nAccess underlying request and response details:\n\n```javascript\nclient.messages.create({\n  to: '+14158675309',\n  from: '+14258675310',\n  body: 'Ahoy!',\n})\n.then(() => {\n  // Access request details\n  console.log(client.lastRequest.method);\n  console.log(client.lastRequest.url);\n  console.log(client.lastRequest.auth);\n  console.log(client.lastRequest.params);\n  console.log(client.lastRequest.headers);\n  console.log(client.lastRequest.data);\n\n  // Access response details\n  console.log(client.httpClient.lastResponse.statusCode);\n  console.log(client.httpClient.lastResponse.body);\n});\n```\n\n## Advanced Features\n\n### Pagination and Resource Iteration\n\nHandle large result sets efficiently:\n\n```javascript\n// List all messages (with automatic pagination)\nconst messages = await client.messages.list({\n  from: '+1234567890',\n  limit: 100\n});\n\n// Stream through messages efficiently\nclient.messages.each({\n  from: '+1234567890',\n  pageSize: 50\n}, (message) => {\n  console.log(`Message: ${message.sid} - ${message.body}`);\n});\n\n// Manual pagination\nlet messages = await client.messages.page({\n  from: '+1234567890',\n  pageSize: 20\n});\n\nwhile (messages.instances.length > 0) {\n  messages.instances.forEach(message => {\n    console.log(message.body);\n  });\n\n  if (messages.nextPageUrl) {\n    messages = await messages.nextPage();\n  } else {\n    break;\n  }\n}\n```\n\n### Subaccount Management\n\nWork with main accounts and subaccounts:\n\n```javascript\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\nconst subaccountSid = process.env.TWILIO_SUBACCOUNT_SID;\n\nconst client = require('twilio')(accountSid, authToken);\n\n// Operations on main account (default)\nconst mainAccountCalls = await client.api.v2010.account.calls.list();\n\n// Operations on subaccount\nconst subaccountCalls = await client.api.v2010.account(subaccountSid).calls.list();\n```\n\n### Auto-Retry Configuration\n\nConfigure automatic retry with exponential backoff:\n\n```javascript\nconst client = require('twilio')(accountSid, authToken, {\n  autoRetry: true,           // Enable auto-retry on 429 errors\n  maxRetries: 3              // Maximum number of retries\n});\n```\n\n### Connection Management\n\nConfigure HTTP agent options for connection reuse:\n\n```javascript\nconst client = require('twilio')(accountSid, authToken, {\n  timeout: 30000,            // Socket timeout in milliseconds\n  keepAlive: true,           // Enable connection reuse\n  keepAliveMsecs: 1000,      // Keep-alive timeout\n  maxSockets: 20,            // Maximum number of sockets\n  maxTotalSockets: 100,      // Maximum total sockets\n  maxFreeSockets: 5,         // Maximum free sockets\n  scheduling: \"lifo\"         // Socket scheduling\n});\n```\n\n### Global Infrastructure\n\nTarget specific regions and edges:\n\n```javascript\n// Set during client initialization\nconst client = require('twilio')(accountSid, authToken, {\n  region: 'au1',\n  edge: 'sydney'\n});\n\n// Or set after client creation\nclient.region = 'au1';\nclient.edge = 'sydney';\n```\n\n## Security Best Practices\n\n### Environment Variables\n\nNever hardcode credentials in your application:\n\n```javascript\n//  Good - Use environment variables\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\n\n//  Bad - Hardcoded credentials\nconst accountSid = 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\nconst authToken = 'your_auth_token';\n```\n\n### SSL Certificate Validation\n\nConfigure SSL bundle if needed:\n\n```javascript\n// Set CA bundle path via environment variable\nprocess.env.TWILIO_CA_BUNDLE = '/path/to/ca-bundle.crt';\n```\n\n### Frontend Security Warning\n\nNever use this library in frontend applications:\n\n## Common Integration Patterns\n\n### Message Status Tracking\n\nTrack message delivery status:\n\n```javascript\nasync function sendAndTrackMessage() {\n  const message = await client.messages.create({\n    body: 'Hello World!',\n    to: '+1234567890',\n    from: '+0987654321',\n    statusCallback: 'https://yourapp.com/sms-status'\n  });\n\n  // Later, check message status\n  const updatedMessage = await client.messages(message.sid).fetch();\n  console.log(`Message status: ${updatedMessage.status}`);\n}\n```\n\n### Call Recording and Transcription\n\nRecord and transcribe calls:\n\n```javascript\nasync function makeRecordedCall() {\n  const call = await client.calls.create({\n    to: '+1234567890',\n    from: '+0987654321',\n    url: 'https://yourapp.com/twiml',\n    record: true,\n    recordingStatusCallback: 'https://yourapp.com/recording-status'\n  });\n}\n```\n\n## OAuth Support (Beta)\n\nThe library supports OAuth 2.0 authentication:\n\n```javascript\n// OAuth with Client Credentials Flow\nconst client = twilio.ClientCredentialProviderBuilder()\n  .username('your_api_key')\n  .password('your_api_secret')\n  .accountSid('your_account_sid')\n  .build();\n```\n\n## TypeScript Support\n\nThe library includes TypeScript definitions:\n\n```typescript\nimport twilio from 'twilio';\n\nconst client = twilio(process.env.TWILIO_ACCOUNT_SID!, process.env.TWILIO_AUTH_TOKEN!);\n\ninterface MessageOptions {\n  body: string;\n  to: string;\n  from: string;\n}\n\nasync function sendTypedMessage(options: MessageOptions): Promise<string> {\n  const message = await client.messages.create(options);\n  return message.sid;\n}\n```\n\n## Error Codes and Troubleshooting\n\nCommon error scenarios to handle:\n\n- **20003**: Authentication failed - check credentials\n- **21211**: Invalid phone number format - use E.164 format\n- **21608**: Phone number not verified - verify number first\n- **30034**: Message delivery failed - recipient carrier issue\n\n## Useful Links\n\n- **Documentation**: https://www.twilio.com/docs/libraries/reference/twilio-node/\n- **API Reference**: https://www.twilio.com/docs/api\n- **Console**: https://console.twilio.com\n- **TwiML Reference**: https://www.twilio.com/docs/voice/twiml\n- **Error Codes**: https://www.twilio.com/docs/api/errors\n- **Support**: https://support.twilio.com\n\n## Notes\n\nThis guide covers the core functionality of the Twilio Node.js library. The library is auto-generated from Twilio's OpenAPI specifications, ensuring it stays current with API changes. For the most up-to-date information and additional services not covered here, refer to the official documentation.\n\n## Official Documentation\n\n# twilio-node\n\nThis library supports the following Node.js implementations:\n\n- Node.js 14\n- Node.js 16\n- Node.js 18\n- Node.js 20\n- Node.js lts(22)\n\nTypeScript is supported for TypeScript version 2.9 and above.\n\n> **Warning**\n> Do not use this Node.js library in a front-end application. Doing so can expose your Twilio credentials to end-users as part of the bundled HTML/JavaScript sent to their browser.\n\n`npm install twilio` or `yarn add twilio`\n\n```javascript\n// Your AccountSID and Auth Token from console.twilio.com\nconst accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';\nconst authToken = 'your_auth_token';\n```\n\n```javascript\nconst client = require('twilio')(accountSid, authToken);\n```\n\n```javascript\nclient.messages\n  .create({\n    body: 'Hello from twilio-node',\n    to: '+12345678901', // Text your number\n    from: '+12345678901', // From a valid Twilio number\n  })\n  .then((message) => console.log(message.sid));\n```\n\n> **Warning**\n> It's okay to hardcode your credentials when testing locally, but you should use environment variables to keep them secret before committing any code or deploying to production. Check out [How to Set Environment Variables](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html) for more information.\n\n## OAuth Feature for Twilio APIs\nWe are introducing Client Credentials Flow-based OAuth 2.0 authentication. This feature is currently in beta and its implementation is subject to change.\n\nAPI examples [here](https://github.com/twilio/twilio-node/blob/main/examples/public_oauth.js)\n\nOrganisation API examples [here](https://github.com/twilio/twilio-node/blob/main/examples/orgs_api.js)\n\n`twilio-node` supports credential storage in environment variables. If no credentials are provided when instantiating the Twilio client (e.g., `const client = require('twilio')();`), the values in following env vars will be used: `TWILIO_ACCOUNT_SID` and `TWILIO_AUTH_TOKEN`.\n\nIf your environment requires SSL decryption, you can set the path to CA bundle in the env var `TWILIO_CA_BUNDLE`.\n\nIf you invoke any V2010 operations without specifying an account SID, `twilio-node` will automatically use the `TWILIO_ACCOUNT_SID` value that the client was initialized with. This is useful for when you'd like to, for example, fetch resources for your main account but also your subaccount. See below:\n\n```javascript\n// Your Account SID, Subaccount SID Auth Token from console.twilio.com\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\nconst subaccountSid = process.env.TWILIO_ACCOUNT_SUBACCOUNT_SID;\n\nconst client = require('twilio')(accountSid, authToken);\nconst mainAccountCalls = client.api.v2010.account.calls.list; // SID not specified, so defaults to accountSid\nconst subaccountCalls = client.api.v2010.account(subaccountSid).calls.list; // SID specified as subaccountSid\n```\n\n```javascript\nconst client = require('twilio')(accountSid, authToken, {\n  lazyLoading: false,\n});\n```\n\n### Enable Auto-Retry with Exponential Backoff\n\n`twilio-node` supports automatic retry with exponential backoff when API requests receive an [Error 429 response](https://support.twilio.com/hc/en-us/articles/360044308153-Twilio-API-response-Error-429-Too-Many-Requests-). This retry with exponential backoff feature is disabled by default. To enable this feature, instantiate the Twilio client with the `autoRetry` flag set to `true`.\n\nOptionally, the maximum number of retries performed by this feature can be set with the `maxRetries` flag. The default maximum number of retries is `3`.\n\n```javascript\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\n\nconst client = require('twilio')(accountSid, authToken, {\n  autoRetry: true,\n  maxRetries: 3,\n});\n```\n\n```\n### Set HTTP Agent Options\n\n`twilio-node` allows you to set HTTP Agent Options in the Request Client. This feature allows you to re-use your connections. To enable this feature, instantiate the Twilio client with the `keepAlive` flag set to `true`.\n\nOptionally, the socket timeout and maximum number of sockets can also be set. See the example below:\n\n```javascript\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\n\nconst client = require('twilio')(accountSid, authToken, {\n    timeout: 30000, // HTTPS agent's socket timeout in milliseconds, default is 30000\n    keepAlive: true, // https.Agent keepAlive option, default is false\n    keepAliveMsecs: 1000, // https.Agent keepAliveMsecs option in milliseconds, default is 1000\n    maxSockets: 20, // https.Agent maxSockets option, default is 20\n    maxTotalSockets: 100, // https.Agent maxTotalSockets option, default is 100\n    maxFreeSockets: 5, // https.Agent maxFreeSockets option, default is 5\n    scheduling: \"lifo\", // https.Agent scheduling option, default is 'lifo'\n});\n```\n```\n\n```\n### Specify Region and/or Edge\n\nTo take advantage of Twilio's [Global Infrastructure](https://www.twilio.com/docs/global-infrastructure), specify the target Region and/or Edge for the client:\n\n```javascript\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\n\nconst client = require('twilio')(accountSid, authToken, {\n  region: 'au1',\n  edge: 'sydney',\n});\n```\n\nAlternatively, specify the edge and/or region after constructing the Twilio client:\n\n```javascript\nconst client = require('twilio')(accountSid, authToken);\nclient.region = 'au1';\nclient.edge = 'sydney';\n```\n\nThis will result in the `hostname` transforming from `api.twilio.com` to `api.sydney.au1.twilio.com`.\n```\n\n```\n### Iterate through records\n\nThe library automatically handles paging for you. Collections, such as `calls` and `messages`, have `list` and `each` methods that page under the hood. With both `list` and `each`, you can specify the number of records you want to receive (`limit`) and the maximum size you want each page fetch to be (`pageSize`). The library will then handle the task for you.\n\n`list` eagerly fetches all records and returns them as a list, whereas `each` streams records and lazily retrieves pages of records as you iterate over the collection. You can also page manually using the `page` method.\n\nFor more information about these methods, view the [auto-generated library docs](https://www.twilio.com/docs/libraries/reference/twilio-node/).\n```\n\n```\n### Enable Debug Logging\n\nThere are two ways to enable debug logging in the default HTTP client. You can create an environment variable called `TWILIO_LOG_LEVEL` and set it to `debug` or you can set the logLevel variable on the client as debug:\n\n```javascript\nconst accountSid = process.env.TWILIO_ACCOUNT_SID;\nconst authToken = process.env.TWILIO_AUTH_TOKEN;\n\nconst client = require('twilio')(accountSid, authToken, {\n  logLevel: 'debug',\n});\n```\n\nYou can also set the logLevel variable on the client after constructing the Twilio client:\n\n```javascript\nconst client = require('twilio')(accountSid, authToken);\nclient.logLevel = 'debug';\n```\n```\n\n```\nconst accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';\nconst authToken = 'your_auth_token';\n\nconst client = require('twilio')(accountSid, authToken);\n\nclient.messages\n  .create({\n    to: '+14158675309',\n    from: '+14258675310',\n    body: 'Ahoy!',\n  })\n  .then(() => {\n    // Access details about the last request\n    console.log(client.lastRequest.method);\n    console.log(client.lastRequest.url);\n    console.log(client.lastRequest.auth);\n    console.log(client.lastRequest.params);\n    console.log(client.lastRequest.headers);\n    console.log(client.lastRequest.data);\n\n    // Access details about the last response\n    console.log(client.httpClient.lastResponse.statusCode);\n    console.log(client.httpClient.lastResponse.body);\n  });\n```\n```\n\n```\nIf the Twilio API returns a 400 or a 500 level HTTP response, `twilio-node` will throw an error including relevant information, which you can then `catch`:\n\n```js\nclient.messages\n  .create({\n    body: 'Hello from Node',\n    to: '+12345678901',\n    from: '+12345678901',\n  })\n  .then((message) => console.log(message))\n  .catch((error) => {\n    // You can implement your fallback code here\n    console.log(error);\n  });\n```\n```\n\n```\n## Contributing\n\nBug fixes, docs, and library improvements are always welcome. Please refer to our [Contributing Guide](CONTRIBUTING.md) for detailed information on how you can contribute.\n\n>  Please be aware that a large share of the files are auto-generated by our backend tool. You are welcome to suggest changes and submit PRs illustrating the changes. However, we'll have to make the changes in the underlying tool. You can find more info about this in the [Contributing Guide](CONTRIBUTING.md).\n```\n\n```typescript\n  /** The recipient\\'s phone number in [E.164](https://www.twilio.com/docs/glossary/what-e164) format (for SMS/MMS) or [channel address](https://www.twilio.com/docs/messaging/channels), e.g. `whatsapp:+15552229999`. */\n  to: string;\n```\n\n```typescript\n  /** The SID of the [Messaging Service](https://www.twilio.com/docs/messaging/services) you want to associate with the Message. When this parameter is provided and the `from` parameter is omitted, Twilio selects the optimal sender from the Messaging Service\\'s Sender Pool. You may also provide a `from` parameter if you want to use a specific Sender from the Sender Pool. */\n  messagingServiceSid?: string;\n```\n\n```typescript\n  /** The URL of media to include in the Message content. `jpeg`, `jpg`, `gif`, and `png` file types are fully supported by Twilio and content is formatted for delivery on destination devices. The media size limit is 5 MB for supported file types (`jpeg`, `jpg`, `png`, `gif`) and 500 KB for [other types](https://www.twilio.com/docs/messaging/guides/accepted-mime-types) of accepted media. To send more than one image in the message, provide multiple `media_url` parameters in the POST request. You can include up to ten `media_url` parameters per message. [International](https://support.twilio.com/hc/en-us/articles/223179808-Sending-and-receiving-MMS-messages) and [carrier](https://support.twilio.com/hc/en-us/articles/223133707-Is-MMS-supported-for-all-carriers-in-US-and-Canada-) limits apply. */\n  mediaUrl?: Array<string>;\n```\n\n```typescript\nexport interface CallListInstanceCreateOptions {\n  /** The phone number, SIP address, or client identifier to call. */\n  to: string;\n  /** The phone number or client identifier to use as the caller id. If using a phone number, it must be a Twilio number or a Verified [outgoing caller id](https://www.twilio.com/docs/voice/api/outgoing-caller-ids) for your account. If the `to` parameter is a phone number, `From` must also be a phone number. */\n  from: string;\n```\n\n```typescript\n  /** TwiML instructions for the call Twilio will use without fetching Twiml from url parameter. If both `twiml` and `url` are provided then `twiml` parameter will be ignored. Max 4000 characters. */\n  twiml?: TwiML | string;\n```\n\n```typescript\nclass VoiceResponse extends TwiML {\n  /**\n   * <Response> TwiML for Voice\n   */\n  constructor() {\n    super();\n    this._propertyName = \"response\";\n  }\n```\n\n```typescript\n  connect(attributes?: VoiceResponse.ConnectAttributes): VoiceResponse.Connect {\n    return new VoiceResponse.Connect(this.response.ele(\"Connect\", attributes));\n```\n\n```typescript\n    export type MessagingResponse = IMessagingResponse;\n    export const MessagingResponse = IMessagingResponse;\n```\n\n```typescript\n  export type validateBody = typeof webhooks.validateBody;\n  export const validateBody = webhooks.validateBody;\n  export type validateRequest = typeof webhooks.validateRequest;\n  export const validateRequest = webhooks.validateRequest;\n  export type validateRequestWithBody = typeof webhooks.validateRequestWithBody;\n  export const validateRequestWithBody = webhooks.validateRequestWithBody;\n  export type validateExpressRequest = typeof webhooks.validateExpressRequest;\n  export const validateExpressRequest = webhooks.validateExpressRequest;\n  export type validateIncomingRequest = typeof webhooks.validateIncomingRequest;\n  export const validateIncomingRequest = webhooks.validateIncomingRequest;\n```\n\n```typescript\nexport interface Request {\n  protocol: string;\n  header(name: string): string | undefined;\n  headers: IncomingHttpHeaders;\n  originalUrl: string;\n  rawBody?: any;\n  body: any;\n}\n```\n"
  },
  {
    "path": "content/twilio/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Twilio Python helper library for REST API access, messaging, voice, and TwiML generation\"\nmetadata:\n  languages: \"python\"\n  versions: \"9.10.3\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"twilio,communications,sms,voice,twiml,oauth\"\n---\n\n# Twilio Python Package Guide\n\n## Golden Rule\n\nUse the official `twilio` helper library, import the REST client as `from twilio.rest import Client`, and authenticate with environment variables or server-side credentials. When routing through Twilio Global Infrastructure, set both `region` and `edge`; setting only `region` still targets `US1`. Pin at least the major version because Twilio's versioning policy allows minor releases to include small breaking changes.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"twilio==9.10.3\"\n```\n\nFor a general install without a pin:\n\n```bash\npython -m pip install twilio\n```\n\nTwilio's PyPI metadata for `9.10.3` declares support for Python `3.7` through `3.13`.\n\n## Authentication And Setup\n\n### Account SID and Auth Token\n\nPrefer environment variables in application code:\n\n```bash\nexport TWILIO_ACCOUNT_SID=\"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\nexport TWILIO_AUTH_TOKEN=\"your_auth_token\"\n```\n\n```python\nfrom twilio.rest import Client\n\nclient = Client()\n```\n\nExplicit credentials also work:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(\n    \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n    \"your_auth_token\",\n)\n```\n\n### API key and secret\n\nUse an API key and secret when you do not want to ship the account auth token to a service:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(\n    \"SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n    \"your_api_secret\",\n    \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n)\n```\n\n### OAuth client credentials\n\nTwilio documents a beta OAuth 2.0 client-credentials flow for some APIs. Treat it as opt-in and verify API support before switching an existing integration:\n\n```python\nfrom twilio.credential_provider import ClientCredentialProvider\nfrom twilio.rest import Client\n\nprovider = ClientCredentialProvider(\n    \"client_sid\",\n    \"client_secret\",\n)\n\nclient = Client(\n    credential_provider=provider,\n    account_sid=\"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n)\n```\n\n## Core Usage\n\n### Send an SMS or WhatsApp message\n\nUse E.164 phone numbers. For WhatsApp, prefix the addresses with `whatsapp:`.\n\n```python\nfrom twilio.rest import Client\n\nclient = Client()\n\nmessage = client.messages.create(\n    body=\"Hello from Twilio Python\",\n    from_=\"+15017122661\",\n    to=\"+15558675310\",\n)\n\nprint(message.sid)\n```\n\n### Make an outbound call\n\nPass either a hosted TwiML URL or inline TwiML:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client()\n\ncall = client.calls.create(\n    to=\"+15558675310\",\n    from_=\"+15017122661\",\n    url=\"https://demo.twilio.com/docs/voice.xml\",\n)\n\nprint(call.sid)\n```\n\n### List resources without over-fetching\n\n`list()` materializes results eagerly. Prefer `stream()` for large collections:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client()\n\nfor message in client.messages.stream(limit=50):\n    print(message.sid, message.status)\n```\n\n### Generate TwiML in Python\n\n```python\nfrom twilio.twiml.voice_response import VoiceResponse\n\nresponse = VoiceResponse()\nresponse.say(\"Hello from Twilio\")\nresponse.play(\"https://api.twilio.com/cowbell.mp3\")\n\nprint(str(response))\n```\n\n### Use the async HTTP client\n\nAsync operations require `AsyncTwilioHttpClient` plus the `_async` methods:\n\n```python\nimport asyncio\n\nfrom twilio.http.async_http_client import AsyncTwilioHttpClient\nfrom twilio.rest import Client\n\nasync def main() -> None:\n    http_client = AsyncTwilioHttpClient()\n    client = Client(http_client=http_client)\n\n    message = await client.messages.create_async(\n        body=\"Hello from async Twilio\",\n        from_=\"+15017122661\",\n        to=\"+15558675310\",\n    )\n    print(message.sid)\n\nasyncio.run(main())\n```\n\n## Configuration Notes\n\n### Region and edge\n\nSet these together when you need Twilio Global Infrastructure routing:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(region=\"au1\", edge=\"sydney\")\n```\n\nEquivalent environment variables:\n\n```bash\nexport TWILIO_REGION=\"au1\"\nexport TWILIO_EDGE=\"sydney\"\n```\n\nIf you set `region` without `edge`, the request still goes to `api.twilio.com` and uses `US1`.\n\n### Retries for rate-limited requests\n\nTwilio supports automatic retry for HTTP `429` responses:\n\n```python\nfrom twilio.rest import Client\n\nclient = Client(\n    account_sid=\"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n    auth_token=\"your_auth_token\",\n    auto_retry=True,\n    max_retries=3,\n)\n```\n\n### Error handling\n\nCatch `TwilioRestException` for API errors:\n\n```python\nfrom twilio.base.exceptions import TwilioRestException\nfrom twilio.rest import Client\n\nclient = Client()\n\ntry:\n    client.messages.create(\n        body=\"Hello\",\n        from_=\"+15017122661\",\n        to=\"+15558675310\",\n    )\nexcept TwilioRestException as exc:\n    print(exc.status)\n    print(exc.code)\n    print(exc.msg)\n```\n\n## Common Pitfalls\n\n- Import `Client` from `twilio.rest`; `import twilio` alone is not the normal entry point for REST usage.\n- Message and call APIs use `from_`, not `from`, because `from` is a Python keyword.\n- Keep credentials server-side. Do not embed Twilio secrets in frontend or mobile bundles.\n- Use E.164 numbers such as `+15558675310`; local or formatted numbers often fail validation.\n- `list()` can issue multiple page fetches and grow memory use quickly. Prefer `stream()` when you only need iteration.\n- Async usage is not automatic. You need `AsyncTwilioHttpClient` and the `_async` resource methods.\n- Region routing is easy to misconfigure. Set both `region` and `edge` together or stay on the default `US1`.\n- OAuth client credentials are still beta and not a universal replacement for account credentials.\n\n## Version-Sensitive Notes For 9.10.3\n\n- PyPI and Twilio's official helper-library docs both list `9.10.3` as the current package version as of March 12, 2026.\n- Twilio's `9.0.0` upgrade guide says the helper library moved to OpenAPI-generated code and added JSON request-body support; most high-level resource patterns stayed compatible, but older code that relied on undocumented internals is riskier on `9.x`.\n- Twilio's versioning policy explicitly recommends pinning at least the major version because minor releases can require manual code changes.\n- The published versioning matrix says the current major version supports Python `3.7` through `3.13`. If your runtime is older than `3.7`, `9.10.3` is out of range.\n"
  },
  {
    "path": "content/twine/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Twine package guide for building, checking, and uploading Python distributions to PyPI and TestPyPI\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"twine,pypi,packaging,publishing,python\"\n---\n\n# Twine Python Package Guide\n\n## Golden Rule\n\nUse `twine` only for checking and uploading already-built distribution artifacts. Do not use `python setup.py upload`; the Python Packaging User Guide treats `python setup.py` as a deprecated command-line interface and recommends `python -m build`, `python -m twine check`, and `python -m twine upload` instead.\n\n## Install\n\nInstall Twine into the environment that will publish your package:\n\n```bash\npython -m pip install \"twine==6.2.0\"\n```\n\nIn most real workflows you also want `build` in the same environment:\n\n```bash\npython -m pip install \"build\" \"twine==6.2.0\"\n```\n\n## What Twine Does\n\nTwine does not build wheels or source distributions. It uploads files you already created, usually from `dist/`.\n\nTypical artifact workflow:\n\n```bash\npython -m build\nls dist/\n```\n\nYou should normally publish both:\n\n- a wheel: `dist/*.whl`\n- a source distribution: `dist/*.tar.gz`\n\n## Recommended Release Flow\n\n### 1. Build distributions\n\nRun this from the directory containing `pyproject.toml`:\n\n```bash\npython -m build\n```\n\n### 2. Validate package metadata and README rendering\n\n`twine check` catches broken long-description rendering before upload. Use `--strict` so warnings fail CI:\n\n```bash\npython -m twine check --strict dist/*\n```\n\n### 3. Upload to TestPyPI first\n\n```bash\npython -m twine upload --repository testpypi dist/*\n```\n\nTestPyPI is a separate index with separate accounts and separate API tokens.\n\n### 4. Verify the uploaded package\n\nInstall from TestPyPI before publishing to real PyPI:\n\n```bash\npython -m pip install \\\n  --index-url https://test.pypi.org/simple/ \\\n  --extra-index-url https://pypi.org/simple/ \\\n  your-package-name\n```\n\nThe extra index is often necessary so dependencies still resolve from PyPI.\n\n### 5. Upload to PyPI\n\n```bash\npython -m twine upload dist/*\n```\n\n## Authentication And Configuration\n\nTwine can take configuration from:\n\n1. Command-line flags\n2. Environment variables\n3. `.pypirc`\n4. Keyring\n\nThe Twine docs state that command-line flags take precedence over environment variables. Twine also ships with default repository entries for `pypi` and `testpypi`, so you usually do not need to define those URLs yourself unless you want custom credentials or additional indexes.\n\n### Environment variables\n\nUseful variables for CI and other non-interactive environments:\n\n```bash\nexport TWINE_USERNAME=__token__\nexport TWINE_PASSWORD=pypi-xxxxxxxxxxxxxxxxxxxxxxxxxxxx\nexport TWINE_NON_INTERACTIVE=1\n```\n\nIf you need a non-default index:\n\n```bash\nexport TWINE_REPOSITORY=testpypi\n# or\nexport TWINE_REPOSITORY_URL=https://example.internal/legacy/\n```\n\nUse `TWINE_CERT` when uploading to an index that requires a custom CA bundle.\n\n### `.pypirc`\n\nFor local publishing, a minimal `~/.pypirc` using API tokens looks like:\n\n```ini\n[pypi]\nusername = __token__\npassword = pypi-...\n\n[testpypi]\nusername = __token__\npassword = pypi-...\n```\n\nIf you add private indexes, include the full `distutils` index list and a section per repository:\n\n```ini\n[distutils]\nindex-servers =\n    pypi\n    testpypi\n    private-repository\n\n[pypi]\nusername = __token__\npassword = pypi-...\n\n[testpypi]\nusername = __token__\npassword = pypi-...\n\n[private-repository]\nrepository = https://packages.example.com/legacy/\nusername = my-user\npassword = my-password\n```\n\nSecurity notes:\n\n- `.pypirc` stores credentials in plain text.\n- On macOS and Linux, lock it down with `chmod 600 ~/.pypirc`.\n- Prefer environment variables, keyring, or Trusted Publishing when possible.\n\n### Keyring\n\nTwine supports `keyring` and the Twine docs say it is installed with Twine. This avoids storing tokens directly in `.pypirc`.\n\nStore PyPI and TestPyPI tokens like this:\n\n```bash\nkeyring set https://upload.pypi.org/legacy/ __token__\nkeyring set https://test.pypi.org/legacy/ __token__\n```\n\nIf keyring causes unwanted prompts, disable it:\n\n```bash\nkeyring --disable\n```\n\n### Trusted Publishing for GitHub Actions\n\nFor GitHub-hosted releases, PyPA now recommends Trusted Publishing instead of long-lived `PYPI_API_TOKEN` secrets. The Packaging guide recommends a workflow that:\n\n- builds distributions with `python -m build`\n- uses GitHub environments such as `pypi` and `testpypi`\n- grants `permissions: id-token: write`\n- publishes with `pypa/gh-action-pypi-publish@release/v1`\n\nUse Twine locally or in CI when you need direct uploads with explicit credentials, custom repository URLs, or non-GitHub automation. Prefer Trusted Publishing for GitHub Actions release jobs.\n\n## Core Commands\n\nCheck a build:\n\n```bash\npython -m twine check --strict dist/*\n```\n\nUpload to PyPI:\n\n```bash\npython -m twine upload dist/*\n```\n\nUpload to TestPyPI:\n\n```bash\npython -m twine upload --repository testpypi dist/*\n```\n\nUpload to a custom repository URL:\n\n```bash\npython -m twine upload --repository-url https://packages.example.com/legacy/ dist/*\n```\n\nSign uploads with GPG:\n\n```bash\npython -m twine upload --sign dist/*\n```\n\nUse pre-generated `.asc` signatures:\n\n```bash\ngpg --detach-sign -a dist/my_package-1.2.3.tar.gz\npython -m twine upload dist/my_package-1.2.3.tar.gz dist/my_package-1.2.3.tar.gz.asc\n```\n\nFail fast in CI when credentials are missing:\n\n```bash\npython -m twine upload --non-interactive dist/*\n```\n\n## Common Pitfalls\n\n### Twine does not build artifacts\n\nIf `dist/` is empty, Twine will not help. Build first with `python -m build`.\n\n### `register` is not part of normal PyPI publishing\n\n`twine register` exists for repositories that still require pre-registration, but the Twine docs explicitly say pre-registration is not supported on PyPI. Do not add `register` to normal PyPI release automation.\n\n### TestPyPI and PyPI credentials are separate\n\nTestPyPI has a separate account database and separate API tokens. A working PyPI token will not upload to TestPyPI.\n\n### Use `__token__` for PyPI and TestPyPI\n\nAs of Twine `6.0.0`, workflows that explicitly pass a PyPI or TestPyPI username other than `__token__` fail. Either omit the username or use `__token__`.\n\n### `--repository-url` overrides `--repository`\n\nIf both are set, `--repository-url` wins. This is a common source of confusion when `.pypirc` and CI environment variables both exist.\n\n### `--skip-existing` is not a general-purpose safety net\n\nIn Twine `6.2.0`, support hacks for `--skip-existing` on indexes other than PyPI and TestPyPI were removed. Do not assume private indexes behave like PyPI here.\n\n### `.tar.bz2`, `egg`, and `wininst` are no longer supported\n\nTwine `6.1.0` removed support for `egg`, `wininst`, and `.tar.bz2` uploads. Expect modern `wheel` and `.tar.gz` artifacts instead.\n\n### Hidden password input is normal\n\nTwine intentionally does not echo credentials while prompting. On Windows terminals, standard paste shortcuts may not work in the prompt.\n\n## Version-Sensitive Notes For 6.2.0\n\n- `6.2.0` refreshes short-lived PyPI Trusted Publishing tokens during long-running uploads.\n- `6.2.0` enforces `keyring >= 21.2.0`.\n- `6.2.0` removes old compatibility hacks for `--skip-existing` on non-PyPI indexes.\n- `6.1.0` added preliminary built-in Trusted Publishing support.\n- `6.1.0` removed support for `egg`, `wininst`, and `.tar.bz2`.\n- `6.0.0` changed PyPI/TestPyPI username handling so non-`__token__` usernames now fail.\n\n## Official Sources\n\n- Twine docs: https://twine.readthedocs.io/en/stable/\n- Twine changelog: https://twine.readthedocs.io/en/stable/changelog.html\n- PyPI project page: https://pypi.org/project/twine/\n- `.pypirc` spec: https://packaging.python.org/en/latest/specifications/pypirc/\n- TestPyPI guide: https://packaging.python.org/en/latest/guides/using-testpypi/\n- GitHub Actions Trusted Publishing guide: https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/\n- `setup.py` deprecation guidance: https://packaging.python.org/en/latest/discussions/setup-py-deprecated/\n"
  },
  {
    "path": "content/twisted/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Twisted package guide for Python event-driven networking, Deferreds, reactors, and protocol services\"\nmetadata:\n  languages: \"python\"\n  versions: \"25.5.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"twisted,python,async,networking,reactor,deferred,protocols\"\n---\n\n# Twisted Python Package Guide\n\n## What It Is\n\n`Twisted` is an event-driven networking framework for Python. Use it when you need protocol servers or clients, long-lived connections, TLS-enabled networking, or a mature callback-based async runtime that can also interoperate with `asyncio`.\n\n- Package name on PyPI: `Twisted`\n- Import namespace: `twisted.*`\n- Version covered: `25.5.0`\n- Python requirement on PyPI: `>=3.8`\n\nTwisted code is usually organized around:\n\n- one reactor per process\n- `Deferred` values for async results\n- protocol and transport objects for socket-level work\n- endpoints for portable listener and connector setup\n\n## Installation\n\nInstall the version your project expects:\n\n```bash\npython -m pip install \"Twisted==25.5.0\"\n```\n\nCommon extras from the official installation docs:\n\n```bash\npython -m pip install \"Twisted[tls]==25.5.0\"\npython -m pip install \"Twisted[http2]==25.5.0\"\npython -m pip install \"Twisted[websocket]==25.5.0\"\npython -m pip install \"Twisted[conch]==25.5.0\"\n```\n\n- `tls`: TLS client and server support\n- `http2`: HTTP/2 support\n- `websocket`: Twisted Web websocket support\n- `conch`: SSH and Telnet features\n\nIf you need several optional stacks on a non-platform-specific deployment target, Twisted also documents `all-non-platform`.\n\n## Initialization And Setup\n\n### Pick The Reactor Before Importing `reactor`\n\nIf you want Twisted to run on top of `asyncio`, install the asyncio reactor before importing `twisted.internet.reactor` or any module that may import it implicitly:\n\n```python\nimport asyncio\n\nfrom twisted.internet import asyncioreactor\n\nloop = asyncio.new_event_loop()\nasyncio.set_event_loop(loop)\nasyncioreactor.install(loop)\n\nfrom twisted.internet import reactor\n```\n\nWindows note: the official `AsyncioSelectorReactor` docs say Python 3.8+ on Windows needs `asyncio.WindowsSelectorEventLoopPolicy()` before creating the event loop.\n\n```python\nimport asyncio\n\nasyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())\n```\n\nIf you are not integrating with `asyncio`, the platform default reactor is usually fine.\n\n### Prefer Endpoints Over Manual Socket Setup\n\nEndpoint strings are Twisted's portable way to describe listeners and outbound connections:\n\n```python\nfrom twisted.internet import endpoints, protocol, reactor\n\nclass Echo(protocol.Protocol):\n    def dataReceived(self, data: bytes) -> None:\n        self.transport.write(data)\n\nendpoint = endpoints.serverFromString(\n    reactor,\n    \"tcp:1234:interface=127.0.0.1\",\n)\nendpoint.listen(protocol.Factory.forProtocol(Echo))\nreactor.run()\n```\n\nFor outbound connections, use `clientFromString`:\n\n```python\nfrom twisted.internet import endpoints, protocol, reactor\n\nclass Client(protocol.Protocol):\n    def connectionMade(self) -> None:\n        self.transport.write(b\"ping\")\n\nfactory = protocol.ClientFactory.forProtocol(Client)\nendpoint = endpoints.clientFromString(reactor, \"tcp:host=127.0.0.1:port=1234\")\nendpoint.connect(factory)\nreactor.run()\n```\n\n### Prefer `task.react()` For One-Shot Programs\n\nThe official task API recommends `task.react()` instead of calling `reactor.run()` directly for scripts and clients with a clear completion condition:\n\n```python\nfrom twisted.internet import task\n\nasync def main(reactor, name):\n    print(f\"hello {name}\")\n\ntask.react(main, (\"twisted\",))\n```\n\n`task.react()` stops the reactor exactly once, logs failures, and exits with a non-zero code on failure.\n\n## Core Usage\n\n### `Deferred` Basics\n\nTwisted's primary async primitive is `Deferred`. Attach callbacks and errbacks to handle completion:\n\n```python\nfrom twisted.internet import defer\n\ndef load_config():\n    return defer.succeed({\"workers\": 4})\n\ndef show_config(config):\n    print(config[\"workers\"])\n    return config\n\nd = load_config()\nd.addCallback(show_config)\nd.addErrback(lambda failure: failure.printTraceback())\n```\n\n### Prefer `Deferred.fromCoroutine` When Bridging `async def`\n\nThe current Twisted docs say `Deferred.fromCoroutine` is intended to replace the more type-ambiguous `ensureDeferred` in this role:\n\n```python\nfrom twisted.internet.defer import Deferred\nfrom twisted.internet import task\n\nasync def compute_total():\n    return 42\n\ndef main(reactor):\n    d = Deferred.fromCoroutine(compute_total())\n    d.addCallback(print)\n    return d\n\ntask.react(main)\n```\n\n### `inlineCallbacks` Still Works\n\nIf a codebase already uses `inlineCallbacks`, keep it consistent rather than mixing styles arbitrarily:\n\n```python\nfrom twisted.internet import defer, task\n\ndef read_settings():\n    return defer.succeed({\"debug\": True})\n\n@defer.inlineCallbacks\ndef main(reactor):\n    settings = yield read_settings()\n    print(settings[\"debug\"])\n\ntask.react(main)\n```\n\n### HTTP Client Requests With `Agent`\n\n`twisted.web.client.Agent` is the low-level official HTTP client. Its `request()` method takes byte strings for the method and URI:\n\n```python\nfrom twisted.internet import task\nfrom twisted.web.client import Agent, readBody\n\ndef main(reactor):\n    agent = Agent(reactor)\n    d = agent.request(\n        b\"GET\",\n        b\"https://example.com/\",\n    )\n\n    def got_response(response):\n        return readBody(response)\n\n    def got_body(body):\n        print(body.decode(\"utf-8\")[:120])\n\n    d.addCallback(got_response)\n    d.addCallback(got_body)\n    return d\n\ntask.react(main)\n```\n\n### Move Blocking Work Off The Reactor\n\nTwisted's threading guide is explicit: do not call blocking code in the reactor thread. Use `threads.deferToThread()` when you need a result back as a `Deferred`:\n\n```python\nfrom twisted.internet import task, threads\n\ndef blocking_read():\n    with open(\"payload.bin\", \"rb\") as fh:\n        return fh.read()\n\ndef main(reactor):\n    d = threads.deferToThread(blocking_read)\n    d.addCallback(lambda data: print(len(data)))\n    return d\n\ntask.react(main)\n```\n\nIf another thread needs to schedule work on the reactor, use `reactor.callFromThread(...)` instead of calling Twisted APIs directly from that thread.\n\n## Configuration And Auth\n\nTwisted does not have a package-wide config file or global auth model. In practice, configuration lives in:\n\n- which reactor you install\n- endpoint strings for listener and connector setup\n- TLS context and certificate settings\n- protocol-specific settings in your application\n- optional extras such as `tls`, `http2`, `websocket`, or `conch`\n\nHTTP auth is handled in your request code. For example, attach headers explicitly:\n\n```python\nfrom twisted.internet import reactor\nfrom twisted.web.client import Agent\nfrom twisted.web.http_headers import Headers\n\nagent = Agent(reactor)\nheaders = Headers(\n    {\n        b\"authorization\": [b\"Bearer token-value\"],\n        b\"user-agent\": [b\"my-app/1.0\"],\n    }\n)\n```\n\nFor HTTPS customization, stay within `twisted.web.client` policy/context APIs instead of mixing in unrelated SSL setup code.\n\n## Common Pitfalls\n\n### Installing A Reactor Too Late\n\nImport order matters. If you need `asyncioreactor`, install it before importing `reactor`.\n\n### Assuming The Reactor Is Restartable\n\nTwisted reactors are meant to start once per process. If you stop a reactor and try to run it again, Twisted raises `ReactorNotRestartable`.\n\n### Blocking The Reactor Thread\n\nAvoid `time.sleep()`, synchronous HTTP clients, direct blocking database calls, or large filesystem operations on the reactor thread.\n\n### Calling Twisted APIs From Worker Threads\n\nMost Twisted objects are not thread-safe. Use `reactor.callFromThread()` to get back onto the reactor thread.\n\n### Forgetting That Many APIs Want `bytes`\n\nProtocol payloads and APIs such as `Agent.request()` operate on bytes. Encode and decode at boundaries instead of mixing `str` and `bytes` ad hoc.\n\n### Using Manual Socket Setup When Endpoints Already Solve It\n\nEndpoints are the documented portability layer. Prefer `serverFromString()` and `clientFromString()` over custom socket setup code.\n\n## Version-Sensitive Notes For 25.5.0\n\n- The version used here is `25.5.0`, released on `2025-06-07`.\n- The official stable docs matched `25.5.0` when checked on `2026-03-12`, but the stable URL is not permanently version-pinned. Re-check if you curate this package later.\n- PyPI reports `Requires: Python >=3.8.0` and lists extras including `tls`, `http2`, `websocket`, `conch`, and `serial`.\n- The `25.5.0` release removed `twisted.internet.defer.waitForDeferred`. Older recipes using it should be rewritten with native coroutines, `Deferred.fromCoroutine`, or existing `inlineCallbacks` patterns.\n- The `25.5.0` release also removed or privatized `twisted.trial.unittest.TestCase.deferSetUp`, `deferTestMethod`, `deferTearDown`, and `deferRunCleanups`. Older Trial examples that depend on those hooks are stale.\n- The websocket extra is worth checking explicitly in `25.5.0` because current Twisted Web websocket docs require `Twisted[websocket]` or a bundle that includes it.\n\n## Official Sources\n\n- Docs root: https://docs.twisted.org/en/stable/\n- Installation: https://docs.twisted.org/en/stable/installation.html\n- Deferred intro: https://docs.twisted.org/en/latest/core/howto/defer-intro.html\n- Endpoints: https://docs.twisted.org/en/stable/core/howto/endpoints.html\n- Threading: https://docs.twisted.org/en/stable/core/howto/threading.html\n- `task.react`: https://docs.twisted.org/en/stable/api/twisted.internet.task.html\n- `Agent`: https://docs.twisted.org/en/stable/api/twisted.web.client.Agent.html\n- `AsyncioSelectorReactor`: https://docs.twisted.org/en/stable/api/twisted.internet.asyncioreactor.AsyncioSelectorReactor.html\n- PyPI: https://pypi.org/project/Twisted/25.5.0/\n- Release notes: https://github.com/twisted/twisted/releases/tag/twisted-25.5.0\n"
  },
  {
    "path": "content/typer/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Typer package guide for Python CLIs with commands, options, packaging, testing, and 0.24.1 notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.24.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"typer,python,cli,click,terminal,developer-tools\"\n---\n\n# Typer Python Package Guide\n\n## When To Use Typer\n\nUse `typer` when you want a Python CLI with:\n\n- type-hint driven arguments and options\n- good help output without hand-writing `argparse` boilerplate\n- subcommands and shared global options\n- shell completion and prompt/confirm helpers\n- direct interoperability with Click's runtime model\n\n`typer` is built on Click. Reach for it when the CLI should feel like a normal Python program first, with types and functions driving the interface.\n\n## Install\n\nPin the version if the project is already standardized on it:\n\n```bash\npython -m pip install \"typer==0.24.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"typer==0.24.1\"\npoetry add \"typer==0.24.1\"\n```\n\nVersion-sensitive install note:\n\n- `0.24.0` dropped Python 3.9 support.\n- `0.24.1` is the first release where the project explicitly says to use `typer` only; `typer-slim` and `typer-cli` are no longer supported release targets.\n\n## Fast Start\n\nFor a single-command CLI, `typer.run()` is the shortest path:\n\n```python\nfrom typing import Annotated\n\nimport typer\n\ndef main(\n    name: Annotated[str, typer.Argument(help=\"Who to greet\")],\n    formal: Annotated[bool, typer.Option(\"--formal\", help=\"Use a formal greeting\")] = False,\n) -> None:\n    if formal:\n        print(f\"Hello, {name}.\")\n    else:\n        print(f\"Hi, {name}!\")\n\nif __name__ == \"__main__\":\n    typer.run(main)\n```\n\nRun it:\n\n```bash\npython main.py Alice\npython main.py Alice --formal\npython main.py --help\n```\n\nTyper derives the CLI from the function signature:\n\n- required parameters become arguments by default\n- defaulted parameters become options by default\n- `bool` options become flag-style switches\n\n## Build A Multi-Command App\n\nUse `Typer()` when the CLI needs subcommands, callbacks, or shared state:\n\n```python\nfrom pathlib import Path\nfrom typing import Annotated\n\nimport typer\n\napp = typer.Typer(no_args_is_help=True)\n\n@app.command()\ndef greet(\n    name: Annotated[str, typer.Argument(help=\"Person to greet\")],\n    times: Annotated[int, typer.Option(\"--times\", min=1)] = 1,\n) -> None:\n    for _ in range(times):\n        typer.echo(f\"Hello {name}\")\n\n@app.command()\ndef init(\n    config: Annotated[Path, typer.Option(\"--config\", help=\"Config file path\")],\n) -> None:\n    config.parent.mkdir(parents=True, exist_ok=True)\n    config.write_text(\"debug = false\\n\", encoding=\"utf-8\")\n    typer.echo(f\"Created {config}\")\n\nif __name__ == \"__main__\":\n    app()\n```\n\nRun it:\n\n```bash\npython app.py greet Ada --times 2\npython app.py init --config ~/.config/myapp/config.toml\n```\n\nUseful app-level settings:\n\n- `no_args_is_help=True` makes an empty invocation print help instead of silently exiting\n- `add_completion=False` disables completion management commands when you do not want them\n- callbacks are the right place for global options that should run before subcommands\n\n## Preferred Parameter Style\n\nUse `typing.Annotated` with `typer.Argument(...)` and `typer.Option(...)` for new code:\n\n```python\nfrom typing import Annotated\n\nimport typer\n\ndef main(\n    user_id: Annotated[int, typer.Argument(help=\"Numeric user id\")],\n    output: Annotated[str, typer.Option(\"--output\", \"-o\")] = \"text\",\n) -> None:\n    typer.echo(f\"{user_id=} {output=}\")\n```\n\nThat keeps the Python type separate from CLI metadata and matches the current docs and examples.\n\n## Configuration And Environment\n\nTyper does not have authentication features of its own. For CLI projects, \"config\" usually means:\n\n- command-line options and arguments\n- environment-backed defaults\n- app-specific config files stored in a standard user directory\n\n### Use environment variables for defaults\n\n```python\nfrom typing import Annotated\n\nimport typer\n\ndef main(\n    token: Annotated[\n        str,\n        typer.Option(\"--token\", envvar=\"MYAPP_TOKEN\", help=\"API token\"),\n    ],\n    region: Annotated[\n        str,\n        typer.Option(\"--region\", envvar=\"MYAPP_REGION\"),\n    ] = \"us-west-2\",\n) -> None:\n    typer.echo(f\"token length={len(token)} region={region}\")\n```\n\nBehavior to rely on:\n\n- explicit CLI values win over environment variables\n- the environment variable is used when the option is omitted\n- missing required env-backed values still raise a normal usage error\n\n### Store config files in the app directory\n\nTyper exposes `typer.get_app_dir()` for OS-appropriate config locations:\n\n```python\nfrom pathlib import Path\n\nimport typer\n\nAPP_DIR = Path(typer.get_app_dir(\"myapp\"))\nCONFIG_PATH = APP_DIR / \"config.toml\"\n```\n\nThis avoids hard-coding `~/.config` or platform-specific paths.\n\n## Shared State With `Context`\n\nUse a callback plus `typer.Context` when several subcommands need the same setup:\n\n```python\nfrom typing import Annotated\n\nimport typer\n\napp = typer.Typer()\n\n@app.callback()\ndef main(\n    ctx: typer.Context,\n    verbose: Annotated[bool, typer.Option(\"--verbose\", \"-v\")] = False,\n) -> None:\n    ctx.obj = {\"verbose\": verbose}\n\n@app.command()\ndef sync(ctx: typer.Context) -> None:\n    typer.echo(f\"verbose={ctx.obj['verbose']}\")\n\nif __name__ == \"__main__\":\n    app()\n```\n\nKeep `ctx.obj` small and explicit. It is fine for settings, handles, and precomputed state, but avoid turning it into an untyped global bag.\n\n## Prompts, Confirmation, And Exit Codes\n\nTyper includes Click-style interactive helpers:\n\n```python\nimport typer\n\ndef main(force: bool = False) -> None:\n    if not force and not typer.confirm(\"Proceed?\"):\n        raise typer.Abort()\n\n    typer.echo(\"Working...\")\n\n    if force:\n        raise typer.Exit(code=0)\n\nif __name__ == \"__main__\":\n    typer.run(main)\n```\n\nUse:\n\n- `typer.prompt()` to ask for a value\n- `typer.confirm()` for yes/no checks\n- `raise typer.Exit(code=...)` for controlled termination\n- `raise typer.Abort()` for user-cancelled flows\n\nIf Rich exception rendering causes trouble in your environment, the docs note `TYPER_USE_RICH=0` as an escape hatch.\n\n## Packaging And Entry Points\n\nFor a real CLI, install it as a console script instead of always running `python file.py`:\n\n```toml\n[project]\nname = \"myapp\"\nversion = \"0.1.0\"\ndependencies = [\"typer==0.24.1\"]\n\n[project.scripts]\nmyapp = \"myapp.cli:app\"\n```\n\nWith package code like:\n\n```python\n# myapp/cli.py\nimport typer\n\napp = typer.Typer()\n\n@app.command()\ndef version() -> None:\n    typer.echo(\"0.1.0\")\n```\n\nAfter installation:\n\n```bash\nmyapp version\nmyapp --help\n```\n\n## Shell Completion\n\nTyper can install or print shell completion scripts through the generated CLI:\n\n```bash\nmyapp --install-completion\nmyapp --show-completion\n```\n\nCompletion support is convenient for packaged CLIs, but it is less useful for ad hoc single-file scripts that are never installed.\n\n## Testing\n\nUse the official testing helper built on Click's runner:\n\n```python\nimport typer\nfrom typer.testing import CliRunner\n\napp = typer.Typer()\n\n@app.command()\ndef hello(name: str) -> None:\n    typer.echo(f\"Hello {name}\")\n\nrunner = CliRunner()\n\ndef test_hello() -> None:\n    result = runner.invoke(app, [\"hello\", \"Ada\"])\n    assert result.exit_code == 0\n    assert \"Hello Ada\" in result.stdout\n```\n\nPractical testing notes:\n\n- use `runner.invoke(...)` for stdout, exit code, and usage-error assertions\n- keep command bodies in normal functions so core logic is testable without the CLI wrapper\n- prefer explicit argument lists over shell strings in tests\n\n## Common Pitfalls\n\n- Do not mix old default-value style and `Annotated` style in confusing ways; prefer one clear convention for new code.\n- If your app has exactly one command, `typer.run(main)` is usually simpler than building a full `Typer()` app.\n- If your app has multiple commands, define them on `Typer()` and call `app()`. Do not keep stacking `typer.run(...)` wrappers.\n- Remember that path arguments and options arrive as Python objects only if you annotate them that way, for example `Path`, `int`, or `bool`.\n- Interactive prompts block automation. Provide non-interactive flags or env vars for CI and agent workflows.\n- Shell completion commands are generated by the app itself, so they are easiest to use after packaging the CLI as an installed command.\n- Since Typer rides on Click, some behavior changes can come from Click compatibility updates, not only Typer's own code.\n\n## Version-Sensitive Notes For `0.24.x`\n\n- `0.24.0` added support for Click `8.3.0` and removed Python 3.9 support.\n- `0.24.1` formally stops supporting `typer-slim` and `typer-cli`; use the main `typer` package.\n- The PyPI metadata for `0.24.1` declares `Requires-Python >=3.10`, so do not reuse older blog examples written for 3.8 or 3.9 without checking annotations and dependency behavior.\n- Current upstream docs center the `Annotated` style. If you copy older Typer examples that pass `typer.Option(...)` as a default value, keep them consistent and verify they still match your Python version and type-checking expectations.\n"
  },
  {
    "path": "content/types-pyyaml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"types-PyYAML stub package for static typing of PyYAML in Python projects\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.12.20250915\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typeshed,pyyaml,yaml,typing,mypy,pyright,python\"\n---\n\n# types-PyYAML Python Package Guide\n\n## What It Is\n\n`types-PyYAML` is the typeshed stub package for the runtime package `PyYAML`.\n\n- Install name: `types-PyYAML`\n- Runtime package: `PyYAML`\n- Runtime import: `import yaml`\n- Covered runtime version in this stub release: `PyYAML 6.0.*`\n\nThis package is for static type checking only. It does not replace `PyYAML`, and it does not add a new runtime import.\n\n## Install\n\nInstall the runtime package and the stub package into the same environment used by your type checker:\n\n```bash\npython -m pip install \"PyYAML==6.0.3\" \"types-PyYAML==6.0.12.20250915\"\n```\n\nIf you use `mypy`, install it in that environment too:\n\n```bash\npython -m pip install mypy\npython -m mypy app.py\n```\n\nIf `mypy` reports missing stubs for `yaml`, its docs support:\n\n```bash\npython -m mypy --install-types\n```\n\n## Initialization And Setup\n\nThere are no environment variables, credentials, or client initialization steps.\n\nThe important setup rules are:\n\n- keep using the runtime import `import yaml`\n- install `types-PyYAML` where `mypy` or another PEP 561 type checker runs\n- keep `PyYAML` and `types-PyYAML` aligned with the `PyYAML 6.0.*` line this stub release targets\n\nMinimal example:\n\n```python\nfrom __future__ import annotations\n\nfrom pathlib import Path\nfrom typing import TypedDict, cast\n\nimport yaml\n\n\nclass AppConfig(TypedDict):\n    debug: bool\n    port: int\n\n\nraw = yaml.safe_load(Path(\"config.yaml\").read_text())\nconfig = cast(AppConfig, raw)\n\nprint(config[\"port\"])\n```\n\nThe stubs give your checker signatures for `yaml` APIs, but YAML input is still dynamic. Keep using `TypedDict`, dataclass conversion, or explicit validation for application-specific shapes.\n\n## Common Workflows\n\n### Type-check existing PyYAML code\n\nYour application code does not change:\n\n```python\nimport yaml\n\ndocument = \"\"\"\ndebug: true\nport: 8080\n\"\"\"\n\ndata = yaml.safe_load(document)\nprint(data)\n```\n\nInstall the stubs, then run your checker:\n\n```bash\npython -m mypy app.py\n```\n\nIf you already use Pyright, install `types-PyYAML` in the project environment and run:\n\n```bash\npyright app.py\n```\n\n### Keep YAML parsing on the safe APIs\n\nThe stub package tracks the `yaml` module, so normal `PyYAML` guidance still applies. Prefer the safe loader and dumper entry points in application code:\n\n```python\nimport yaml\n\npayload = yaml.safe_load(\"enabled: true\\n\")\ntext = yaml.safe_dump(payload, sort_keys=False)\n```\n\n### Add stubs as a development dependency\n\n`types-PyYAML` is usually a dev-only dependency. Keep `PyYAML` in the runtime dependency set and keep the stub package in the environment used for CI and local type checking.\n\n## Common Pitfalls\n\n### Do Not Import The Stub Package\n\nUse:\n\n```python\nimport yaml\n```\n\nDo not try to import `types_pyyaml` or `types_PyYAML`. The stub package augments the `yaml` import that comes from `PyYAML`.\n\n### The Stub Package Does Not Install PyYAML\n\nYou still need the runtime dependency:\n\n```bash\npython -m pip install PyYAML\n```\n\n### Install The Stubs In The Checker Environment\n\n`mypy` only sees PEP 561 packages installed in the Python environment where `mypy` runs. If your editor or CI uses a different interpreter, install `types-PyYAML` there too.\n\n### Stub-Only Packages Do Not Need `py.typed`\n\nPEP 561 treats stub-only packages differently from inline-typed runtime packages. Do not look for a `py.typed` marker inside `PyYAML` when you are depending on `types-PyYAML`.\n\n### Expect Broad Types Around Parsed YAML\n\nThe stubs improve editor support and type checking for the `yaml` API surface, but parsed YAML is still data-driven. For non-trivial schemas, you will still need casts or validation after `safe_load()`.\n\n## Version-Sensitive Notes For 6.0.12.20250915\n\n- PyPI describes this release as type stubs generated from typeshed for `PyYAML 6.0.*`.\n- PyPI lists `Requires: Python >=3.9` for `types-PyYAML 6.0.12.20250915`.\n- The PyPI page lists the checked type checkers for this release as `mypy 1.18.1` and `pyright 1.1.405`.\n- If your project type-checks against a different `PyYAML` major or minor line, do not assume this stub release is the right match.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/types-PyYAML/\n- typeshed README: https://github.com/python/typeshed/blob/main/README.md\n- typeshed source repository: https://github.com/python/typeshed\n- Typing spec for distributing type information: https://typing.python.org/en/latest/spec/distributing.html\n- mypy docs on using installed packages: https://mypy.readthedocs.io/en/stable/installed_packages.html\n- PyYAML package page: https://pypi.org/project/PyYAML/\n"
  },
  {
    "path": "content/types-requests/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Type stubs for the requests HTTP client, published from typeshed for Python type checkers\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.32.4.20260107\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"python,typing,stubs,requests,mypy,pyright\"\n---\n\n# types-requests\n\n`types-requests` is the `typeshed` stub package for `requests`. Install it when your project uses `requests` and you want mypy, pyright, or another type checker to understand the `requests` API.\n\nThis package does not add a new runtime client and it does not change how you import `requests`. Keep using `import requests` in application code.\n\n## Install\n\nInstall `types-requests` alongside the runtime package:\n\n```bash\npython -m pip install \"requests==2.32.*\" \"types-requests==2.32.4.20260107\"\n```\n\nIf you also want a CLI type checker:\n\n```bash\npython -m pip install mypy\n# or\npython -m pip install pyright\n```\n\n`types-requests` is a PEP 561 stub package, so supported type checkers pick it up automatically once it is installed.\n\n## No Separate Initialization\n\nThere are no package-specific environment variables, authentication steps, or client constructors for `types-requests`.\n\n- Do not import `types_requests`\n- Do not create a special stub client\n- Continue using the normal `requests` module and `requests.Session()`\n\n## Basic Typed Requests\n\nUse the same `requests` API you already use at runtime:\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://api.github.com/repos/psf/requests\",\n    headers={\"Accept\": \"application/vnd.github+json\"},\n    timeout=(5, 30),\n)\nresponse.raise_for_status()\n\nprint(response.status_code)\nprint(response.headers[\"content-type\"])\nprint(response.text)\n```\n\nThe stubs cover the top-level request helpers, including `requests.request()`, `get()`, `post()`, `put()`, `patch()`, `delete()`, `head()`, and `options()`.\n\nCommon typed keyword arguments include:\n\n- `params`\n- `data`\n- `json`\n- `headers`\n- `cookies`\n- `files`\n- `auth`\n- `timeout`\n- `proxies`\n- `stream`\n- `verify`\n- `cert`\n\n## Reuse A Typed Session\n\nFor applications that keep base URLs or tokens in environment variables, use `requests.Session()` exactly as you would without stubs:\n\n```python\nimport os\n\nimport requests\n\nAPI_BASE_URL = os.environ[\"API_BASE_URL\"]\nAPI_TOKEN = os.environ[\"API_TOKEN\"]\n\nsession = requests.Session()\nsession.headers.update(\n    {\n        \"Authorization\": f\"Bearer {API_TOKEN}\",\n        \"Accept\": \"application/json\",\n    }\n)\n\nresponse = session.post(\n    f\"{API_BASE_URL}/users\",\n    json={\"name\": \"Ada Lovelace\", \"role\": \"admin\"},\n    timeout=(5, 30),\n)\nresponse.raise_for_status()\n\nprint(response.status_code)\nprint(response.json())\n```\n\nFor error handling, catch the normal `requests` exceptions:\n\n```python\nimport requests\n\ntry:\n    response = requests.get(\"https://api.example.com/health\", timeout=5)\n    response.raise_for_status()\nexcept requests.Timeout:\n    print(\"request timed out\")\nexcept requests.RequestException as exc:\n    print(f\"request failed: {exc}\")\n```\n\n## Treat `response.json()` As A Typed Boundary\n\nThe stubs model `Response.json()` as returning `Any`. That is useful and intentional: the checker cannot know the schema your service returns.\n\nIf you know the expected shape, cast or validate the result at the boundary:\n\n```python\nfrom typing import TypedDict, cast\n\nimport requests\n\n\nclass UserRecord(TypedDict):\n    id: int\n    login: str\n\n\nresponse = requests.get(\"https://api.github.com/users/octocat\", timeout=30)\nresponse.raise_for_status()\n\nuser = cast(UserRecord, response.json())\nprint(user[\"login\"])\n```\n\nFor stricter code, replace `cast()` with schema validation in your application layer.\n\n## Version Notes\n\n`typeshed` uses stub versions with a date suffix. For `types-requests==2.32.4.20260107`:\n\n- `2.32.4` tracks the targeted `requests` runtime version\n- `20260107` is the stub release date\n\nTwo safe dependency strategies from the `typeshed` guidance are:\n\n- keep stub bounds aligned with your `requests` bounds, for example `requests>=2.32,<2.33` and `types-requests>=2.32,<2.33`\n- pin an exact `types-requests` version if you need stable type-checking results across dependency updates\n\n## Important Pitfalls\n\n- `types-requests` is only for static typing; it is not a replacement for installing `requests`\n- keep importing `requests`, not `types_requests`\n- `response.json()` is not strongly typed for you; validate or cast it yourself\n- `types-requests` has required `urllib3>=2` since `2.31.0.7`; if your environment must stay on `urllib3<2`, use `types-requests<2.31.0.7`\n- stub packages can change type-checking results even when runtime behavior is unchanged, so pin when you need repeatable CI output\n"
  },
  {
    "path": "content/types-setuptools/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Typeshed typing stubs for setuptools, for static checking of setup.py files and setuptools-based build helpers\"\nmetadata:\n  languages: \"python\"\n  versions: \"82.0.0.20260210\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"python,setuptools,typing,typeshed,packaging,stubs\"\n---\n\n# types-setuptools Python Package Guide\n\n## Golden Rule\n\nInstall `types-setuptools` as a typing dependency alongside the real `setuptools` package. It is a stub-only package for static analysis; your code still imports `setuptools` at runtime, not `types_setuptools`.\n\nThis release, `types-setuptools==82.0.0.20260210`, is published from typeshed and targets `setuptools==82.0.*`.\n\n## Install\n\nUse the stubs in the same virtual environment as your type checker and your `setuptools`-based build code:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"setuptools>=82,<83\" \"types-setuptools==82.0.0.20260210\" mypy\n```\n\nIf your project already pins `setuptools`, match the stub package to that runtime line instead of upgrading blindly.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to initialize.\n\nThe stubs become available when:\n\n- `types-setuptools` is installed in the environment used by your type checker\n- your code imports APIs from `setuptools`\n\n## Common Workflows\n\n### Type-check a `setup.py`\n\n`types-setuptools` is useful when you still maintain a `setup.py`, custom build hooks, or helper modules that import `setuptools` directly.\n\n```python\nfrom setuptools import Extension, find_packages, setup\n\nextensions = [\n    Extension(\"demo._speedups\", sources=[\"src/demo/_speedups.c\"]),\n]\n\nsetup(\n    name=\"demo-package\",\n    version=\"0.1.0\",\n    package_dir={\"\": \"src\"},\n    packages=find_packages(where=\"src\"),\n    ext_modules=extensions,\n)\n```\n\nRun your type checker against the file:\n\n```bash\npython -m mypy setup.py\n```\n\n### Type-check namespace package discovery\n\nUse `find_namespace_packages()` when you intentionally rely on implicit namespace packages.\n\n```python\nfrom setuptools import find_namespace_packages, setup\n\nsetup(\n    name=\"acme-plugins\",\n    version=\"0.1.0\",\n    package_dir={\"\": \"src\"},\n    packages=find_namespace_packages(where=\"src\", include=[\"acme.*\"]),\n)\n```\n\n### Type-check a custom setuptools command\n\nSetuptools documents custom commands as `setuptools.Command` subclasses that implement `initialize_options()`, `finalize_options()`, and `run()`.\n\n```python\nfrom setuptools import Command, setup\n\n\nclass LintCommand(Command):\n    description = \"run lint checks\"\n    user_options = []\n\n    def initialize_options(self) -> None:\n        pass\n\n    def finalize_options(self) -> None:\n        pass\n\n    def run(self) -> None:\n        print(\"lint passed\")\n\n\nsetup(\n    name=\"demo-package\",\n    version=\"0.1.0\",\n    cmdclass={\"lint\": LintCommand},\n)\n```\n\n## Important Pitfalls\n\n- Do not add `import types_setuptools` to application code. This package exists for type checkers, not runtime imports.\n- Keep the stubs aligned with the `setuptools` version family you actually use. Typeshed stub versions encode the targeted runtime version plus a date suffix.\n- `pkg_resources` is not bundled in `types-setuptools`; the PyPI package notes that `setuptools >= 71.1` already ships typing for `pkg_resources`.\n- `find_namespace_packages()` scans implicit namespaces. In flat layouts this can include unwanted directories; prefer a `src/` layout or explicit `include`/`exclude` patterns.\n\n## Version-Sensitive Notes\n\n- PyPI lists `types-setuptools 82.0.0.20260210` as a February 10, 2026 release targeting `setuptools==82.0.*`.\n- The package page says this release was tested with `mypy 1.19.1` and `pyright 1.1.408`.\n- Typeshed documents that third-party stub package versions follow the runtime package version and use the final date segment to indicate when the stub package was published.\n\n## Official Sources\n\n- PyPI package page: https://pypi.org/project/types-setuptools/\n- typeshed repository: https://github.com/python/typeshed\n- typeshed README usage and versioning notes: https://github.com/python/typeshed/blob/main/README.md\n- setuptools package discovery guide: https://setuptools.pypa.io/en/stable/userguide/package_discovery.html\n- setuptools extension modules guide: https://setuptools.pypa.io/en/stable/userguide/ext_modules.html\n- setuptools command customization guide: https://setuptools.pypa.io/en/stable/userguide/extension.html\n"
  },
  {
    "path": "content/typescript/docs/async/typescript/DOC.md",
    "content": "---\nname: async\ndescription: \"TypeScript declarations for async collection helpers, control-flow utilities, and queue-style workflows used through the `async` runtime package.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.2.25\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,async,node,callbacks,promises,types,definitelytyped\"\n---\n\n# Async TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/async` alongside the real `async` runtime package.\n\n`@types/async` only provides TypeScript declarations. Your application imports and executes `async`; the declaration package supplies types for collection helpers such as `mapLimit()` and `forEachOf()`, control-flow helpers such as `parallel()` and `auto()`, and the callback-optional promise forms documented for the v3 runtime.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package.\n\n```bash\nnpm install async\nnpm install -D typescript @types/async @types/node\n```\n\nIf your project already depends on `async`, add only the missing declarations:\n\n```bash\nnpm install -D @types/async @types/node\n```\n\n`@types/async` does not require credentials, API keys, or package-specific environment variables.\n\n## Initialization\n\nThe important setup points are your import style, your compiler options, and whether you use callback-based or promise-based call sites.\n\n### Import `async`\n\nThe safest import form for these declarations is:\n\n```typescript\nimport async = require(\"async\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport async from \"async\";\n```\n\nImport from `async`, never from `@types/async`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you restrict ambient type packages with `compilerOptions.types`, include `async` and any platform types your app needs:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"async\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Limit concurrency with `mapLimit()`\n\nThe maintainer docs describe `mapLimit(coll, limit, iteratee, callback)` as a bounded variant of `map()`. When you omit the final callback, it returns a promise, which is usually the cleanest TypeScript boundary.\n\n```typescript\nimport async = require(\"async\");\n\ntype UserJob = {\n  userId: string;\n};\n\ntype UserSummary = {\n  userId: string;\n  ok: boolean;\n  status: number;\n};\n\nconst apiBaseUrl = process.env.API_BASE_URL ?? \"https://example.internal\";\nconst concurrency = Number(process.env.ASYNC_CONCURRENCY ?? \"4\");\n\nexport async function fetchUsers(jobs: UserJob[]): Promise<UserSummary[]> {\n  return async.mapLimit(jobs, concurrency, async (job) => {\n    const response = await fetch(`${apiBaseUrl}/users/${job.userId}`);\n\n    return {\n      userId: job.userId,\n      ok: response.ok,\n      status: response.status,\n    };\n  });\n}\n```\n\n`API_BASE_URL` and `ASYNC_CONCURRENCY` are normal application settings, not package requirements.\n\n### Run independent tasks with `parallel()`\n\n`parallel()` accepts either an array or an object of tasks. The object form is usually easier to work with in TypeScript because the result stays keyed by task name.\n\n```typescript\nimport async = require(\"async\");\n\ntype FeatureFlags = {\n  auditLogs: boolean;\n  betaSearch: boolean;\n};\n\ntype CurrentUser = {\n  id: string;\n  email: string;\n};\n\nexport async function loadDashboardData(): Promise<{\n  flags: FeatureFlags;\n  currentUser: CurrentUser;\n}> {\n  return async.parallel({\n    flags: async () => {\n      return {\n        auditLogs: true,\n        betaSearch: false,\n      } satisfies FeatureFlags;\n    },\n    currentUser: async () => {\n      return {\n        id: \"u_123\",\n        email: \"ada@example.com\",\n      } satisfies CurrentUser;\n    },\n  });\n}\n```\n\nThis keeps the typed integration boundary small: the rest of your app can consume `flags` and `currentUser` directly instead of indexing into an array result.\n\n### Iterate keyed objects with `forEachOf()`\n\n`forEachOf()` is the right choice when the key matters. The maintainer README uses it for environment-specific config loading, and the type declarations model the `item`, `key`, and completion callback parameters together.\n\n```typescript\nimport async = require(\"async\");\nimport { readFile } from \"node:fs\";\n\nconst configFiles = {\n  dev: \"./config/dev.json\",\n  test: \"./config/test.json\",\n  prod: \"./config/prod.json\",\n};\n\ntype AppConfig = {\n  baseUrl: string;\n};\n\nexport function loadConfigs(): Promise<Record<string, AppConfig>> {\n  const loaded: Record<string, AppConfig> = {};\n\n  return async.forEachOf(configFiles, (filePath, environment, callback) => {\n    readFile(filePath, \"utf8\", (error, contents) => {\n      if (error) {\n        callback(error);\n        return;\n      }\n\n      try {\n        loaded[environment] = JSON.parse(contents) as AppConfig;\n        callback(null);\n      } catch (parseError) {\n        callback(parseError as Error);\n      }\n    });\n  }).then(() => loaded);\n}\n```\n\nThis is a practical pattern when your project still uses Node-style callbacks at the file-system boundary but wants promise-based composition at the function boundary.\n\n### Build dependency-aware steps with `auto()`\n\n`auto()` lets you declare task dependencies by name. Omit the final callback and `await` the result object when you want a typed pipeline output.\n\n```typescript\nimport async = require(\"async\");\n\ntype UserRecord = {\n  id: string;\n};\n\nexport async function buildUserReport(): Promise<{\n  settings: { timeoutMs: number };\n  users: UserRecord[];\n  summary: { timeoutMs: number; userCount: number };\n}> {\n  return async.auto({\n    settings(callback) {\n      callback(null, { timeoutMs: 5_000 });\n    },\n    users(callback) {\n      callback(null, [{ id: \"u_1\" }, { id: \"u_2\" }]);\n    },\n    summary: [\"settings\", \"users\", (results, callback) => {\n      callback(null, {\n        timeoutMs: results.settings.timeoutMs,\n        userCount: results.users.length,\n      });\n    }],\n  });\n}\n```\n\nUse `auto()` when later steps depend on earlier results by name. Use `parallel()` when tasks are independent.\n\n## Minimal End-to-End Example\n\nThis example reads an app-specific concurrency setting from the environment, processes jobs with `mapLimit()`, and returns plain typed results.\n\n```typescript\nimport async = require(\"async\");\n\ntype EmailJob = {\n  email: string;\n};\n\ntype EmailCheck = {\n  email: string;\n  accepted: boolean;\n};\n\nconst concurrency = Number(process.env.ASYNC_CONCURRENCY ?? \"3\");\n\nasync function verifyEmails(jobs: EmailJob[]): Promise<EmailCheck[]> {\n  return async.mapLimit(jobs, concurrency, async (job) => {\n    return {\n      email: job.email,\n      accepted: job.email.endsWith(\"@example.com\"),\n    };\n  });\n}\n\nasync function main(): Promise<void> {\n  const results = await verifyEmails([\n    { email: \"ada@example.com\" },\n    { email: \"grace@example.org\" },\n    { email: \"linus@example.com\" },\n  ]);\n\n  console.log(results);\n}\n\nmain().catch((error) => {\n  console.error(error);\n  process.exitCode = 1;\n});\n```\n\nRun the built file with an optional concurrency override:\n\n```bash\nASYNC_CONCURRENCY=5 node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/async` is a declaration package only. Install `async` separately for the runtime.\n- Import from `async`, not from `@types/async`.\n- `import async from \"async\"` depends on `esModuleInterop` or `allowSyntheticDefaultImports`; `import async = require(\"async\")` is the most portable form.\n- If you use `compilerOptions.types`, include `async` or TypeScript will not automatically load the package declarations.\n- Prefer one completion style per call site: either pass the final callback, or omit it and `await` the returned promise.\n- Keep your runtime on the async v3 API surface these declarations describe.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/async==3.2.25`.\n- The examples here follow the async v3 runtime documentation and README examples for `mapLimit()`, `parallel()`, `forEachOf()`, and `auto()`.\n"
  },
  {
    "path": "content/typescript/docs/aws-lambda/typescript/DOC.md",
    "content": "---\nname: aws-lambda\ndescription: \"TypeScript declarations for AWS Lambda handlers, event payloads, context objects, and common integrations such as API Gateway, SQS, and EventBridge.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.10.161\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,aws,lambda,serverless,types,definitelytyped\"\n---\n\n# AWS Lambda TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/aws-lambda` for type checking only, then import types from `aws-lambda` in your code.\n\nThis package does not deploy functions, invoke Lambda, or provide a runtime client. It supplies declaration files for handler signatures such as `Handler`, `APIGatewayProxyHandlerV2`, `SQSHandler`, `EventBridgeEvent`, `Context`, and the event payload shapes used by AWS Lambda integrations.\n\n## Install\n\nAdd the Lambda declarations and Node.js declarations to your TypeScript project:\n\n```bash\nnpm install -D typescript @types/aws-lambda @types/node\n```\n\nIf your project already has TypeScript and Node.js types, add only the Lambda declarations:\n\n```bash\nnpm install -D @types/aws-lambda\n```\n\nYour application code imports from `aws-lambda`, not from `@types/aws-lambda`:\n\n```typescript\nimport type { Handler, Context } from \"aws-lambda\";\n```\n\n## Initialization\n\nThere is no client object, credential setup, or package-specific environment variable.\n\nThe practical setup is your TypeScript compiler configuration and your handler type imports.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\", \"aws-lambda\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you do not use `compilerOptions.types`, TypeScript can usually discover the package automatically. If you do restrict `types`, include both `node` and `aws-lambda` in the project that compiles your Lambda code.\n\n### Type Lambda environment variables\n\nLambda environment variables are normal `process.env` values. Type them with declaration merging in a `.d.ts` file that is included in your project.\n\n```typescript\ndeclare namespace NodeJS {\n  interface ProcessEnv {\n    RECEIPT_BUCKET: string;\n    LOG_LEVEL?: \"debug\" | \"info\" | \"warn\" | \"error\";\n  }\n}\n```\n\nThen use them in your handler code:\n\n```typescript\nconst receiptBucket = process.env.RECEIPT_BUCKET;\n```\n\n## Common Workflows\n\n### Type a custom Lambda handler with `Handler`\n\nUse the generic `Handler<TEvent, TResult>` type when your function is invoked by a custom payload or a wrapper framework.\n\n```typescript\nimport type { Handler } from \"aws-lambda\";\n\ntype HealthEvent = {\n  name?: string;\n};\n\ntype HealthResponse = {\n  ok: true;\n  message: string;\n};\n\nexport const handler: Handler<HealthEvent, HealthResponse> = async (event, context) => {\n  const name = event.name ?? \"world\";\n\n  return {\n    ok: true,\n    message: `hello ${name} from ${context.awsRequestId}`,\n  };\n};\n```\n\n### Type an API Gateway HTTP API handler\n\nFor HTTP API v2 events and Lambda Function URLs, use the v2 API Gateway types.\n\n```typescript\nimport type { APIGatewayProxyHandlerV2 } from \"aws-lambda\";\n\nexport const handler: APIGatewayProxyHandlerV2 = async (event) => {\n  const name = event.queryStringParameters?.name ?? \"world\";\n\n  return {\n    statusCode: 200,\n    headers: {\n      \"content-type\": \"application/json\",\n    },\n    body: JSON.stringify({\n      message: `hello ${name}`,\n      path: event.requestContext.http.path,\n      requestId: event.requestContext.requestId,\n    }),\n  };\n};\n```\n\nIf your integration is the older API Gateway REST API event shape, use `APIGatewayProxyHandler` and `APIGatewayProxyResult` instead of the v2 types.\n\n### Type an SQS consumer with partial batch failures\n\nUse `SQSHandler` for the function signature and return `SQSBatchResponse` when you want Lambda to retry only failed records.\n\n```typescript\nimport type { SQSBatchResponse, SQSHandler } from \"aws-lambda\";\n\ntype OrderMessage = {\n  orderId: string;\n};\n\nasync function processOrder(message: OrderMessage): Promise<void> {\n  console.log(`processing ${message.orderId}`);\n}\n\nexport const handler: SQSHandler = async (event) => {\n  const batchItemFailures: SQSBatchResponse[\"batchItemFailures\"] = [];\n\n  for (const record of event.Records) {\n    try {\n      const message = JSON.parse(record.body) as OrderMessage;\n      await processOrder(message);\n    } catch {\n      batchItemFailures.push({ itemIdentifier: record.messageId });\n    }\n  }\n\n  return { batchItemFailures };\n};\n```\n\n### Type an EventBridge event handler\n\nUse `EventBridgeEvent<TDetailType, TDetail>` when your function consumes custom EventBridge events and you want a typed `event.detail` payload.\n\n```typescript\nimport type { EventBridgeEvent } from \"aws-lambda\";\n\ntype OrderPlacedDetail = {\n  orderId: string;\n  customerId: string;\n  total: number;\n};\n\nexport async function handler(\n  event: EventBridgeEvent<\"OrderPlaced\", OrderPlacedDetail>\n): Promise<void> {\n  console.log(`received ${event[\"detail-type\"]} for ${event.detail.orderId}`);\n\n  if (process.env.LOG_LEVEL === \"debug\") {\n    console.log(JSON.stringify(event.detail));\n  }\n}\n```\n\n## Common Pitfalls\n\n- Install `@types/aws-lambda` in addition to your runtime dependencies; it does not provide any Lambda runtime code.\n- Import from `aws-lambda`, not from `@types/aws-lambda`.\n- Prefer `import type` so your compiled JavaScript does not contain a runtime import for a types-only package.\n- If `compilerOptions.types` is set, include `aws-lambda` there or the handler and event declarations will appear to be missing.\n- Match the handler type to the actual integration. API Gateway REST API (`APIGatewayProxyHandler`) and HTTP API v2 (`APIGatewayProxyHandlerV2`) are different event shapes.\n- Use `SQSBatchResponse` only when your Lambda is configured for partial batch failure handling; otherwise return nothing and let the whole batch fail together.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/aws-lambda\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda\n- https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html\n- https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html\n- https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-events.html\n"
  },
  {
    "path": "content/typescript/docs/axios/typescript/DOC.md",
    "content": "---\nname: axios\ndescription: \"TypeScript setup for Axios. `@types/axios@0.14.4` is a stub package, so install `axios` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.14.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,axios,http,client,api,types,definitelytyped,npm\"\n---\n\n# Axios TypeScript Guide\n\n## Golden Rule\n\n`@types/axios@0.14.4` is a stub package.\n\nThe npm package page for `@types/axios` says it is a stub entry for `axios`, which provides its own type definitions. For application code, install `axios`, import from `\"axios\"`, and remove `@types/axios` if you added it directly.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install axios\nnpm install -D typescript\n```\n\nIf your project uses Node.js APIs such as `process.env`, streams, or the built-in `http`/`https` modules elsewhere in the app, add `@types/node` too:\n\n```bash\nnpm install -D @types/node\n```\n\nIf your project already depends on the old stub package directly, remove it:\n\n```bash\nnpm uninstall @types/axios\n```\n\nThere are no package-specific environment variables. For app configuration, define your API base URL and any auth token in your own environment:\n\n```bash\nexport API_BASE_URL=\"https://api.example.com\"\nexport API_TOKEN=\"replace-me\"\n```\n\n## TypeScript Setup\n\nImport both runtime APIs and types from `axios` itself:\n\n```typescript\nimport axios, {\n  AxiosError,\n  AxiosInstance,\n  AxiosRequestConfig,\n  AxiosResponse,\n} from \"axios\";\n```\n\nIf you use the common default import style, enable `esModuleInterop` or `allowSyntheticDefaultImports` in your TypeScript config:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, you do not need to list `axios` there. Its declarations come from the runtime package import, not from a global ambient package.\n\n## Initialization\n\nCreate a reusable client with `axios.create()` and keep environment-driven configuration at the app boundary:\n\n```typescript\nimport axios, { AxiosInstance } from \"axios\";\n\nconst apiBaseUrl = process.env.API_BASE_URL ?? \"https://api.example.com\";\nconst apiToken = process.env.API_TOKEN;\n\nexport const apiClient: AxiosInstance = axios.create({\n  baseURL: apiBaseUrl,\n  timeout: 10_000,\n  headers: apiToken\n    ? {\n        Authorization: `Bearer ${apiToken}`,\n        \"Content-Type\": \"application/json\",\n      }\n    : {\n        \"Content-Type\": \"application/json\",\n      },\n});\n```\n\nThere is no separate authentication setup in `@types/axios`. Auth configuration is part of the normal Axios request config you pass to the runtime client.\n\n## Common Workflows\n\n### Send a typed `GET` request\n\nPass the expected response body type as the generic argument to `get<T>()`. The typed payload is then available on `response.data`.\n\n```typescript\nimport { apiClient } from \"./client\";\n\ntype User = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\nexport async function getUser(userId: string): Promise<User> {\n  const response = await apiClient.get<User>(`/users/${userId}`);\n  return response.data;\n}\n```\n\nUse this pattern at the HTTP boundary so the rest of your application works with plain domain objects instead of raw Axios response wrappers.\n\n### Send a typed `POST` request\n\nKeep request and response types separate when your write operation accepts one shape and returns another.\n\n```typescript\nimport { apiClient } from \"./client\";\n\ntype CreateUserInput = {\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\ntype CreateUserResponse = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n  createdAt: string;\n};\n\nexport async function createUser(input: CreateUserInput): Promise<CreateUserResponse> {\n  const response = await apiClient.post<CreateUserResponse>(\"/users\", input);\n  return response.data;\n}\n```\n\nThe response generic controls the type of `response.data`. Your request body type still comes from the `input` variable you pass to `post()`.\n\n### Share request config with `AxiosRequestConfig`\n\nType reusable config fragments as `AxiosRequestConfig` when you want compile-time checks for headers, query parameters, timeouts, or other request options.\n\n```typescript\nimport { apiClient } from \"./client\";\nimport type { AxiosRequestConfig } from \"axios\";\n\ntype SearchUsersResponse = {\n  items: Array<{\n    id: string;\n    email: string;\n  }>;\n};\n\nconst searchConfig: AxiosRequestConfig = {\n  params: {\n    limit: 25,\n    active: true,\n  },\n  timeout: 5_000,\n};\n\nexport async function searchUsers(): Promise<SearchUsersResponse> {\n  const response = await apiClient.get<SearchUsersResponse>(\"/users\", searchConfig);\n  return response.data;\n}\n```\n\nThis is the practical type boundary when you build wrappers around Axios instead of inlining every config object at the call site.\n\n### Narrow HTTP errors with `axios.isAxiosError`\n\nUse `axios.isAxiosError()` in `catch` blocks so you can safely inspect `response`, `request`, and Axios-specific metadata.\n\n```typescript\nimport axios from \"axios\";\nimport { apiClient } from \"./client\";\n\ntype ApiErrorBody = {\n  message: string;\n  code?: string;\n};\n\nexport async function deleteUser(userId: string): Promise<void> {\n  try {\n    await apiClient.delete(`/users/${userId}`);\n  } catch (error) {\n    if (axios.isAxiosError<ApiErrorBody>(error)) {\n      const status = error.response?.status;\n      const message = error.response?.data?.message ?? error.message;\n      throw new Error(`Delete failed (${status ?? \"network\"}): ${message}`);\n    }\n\n    throw error;\n  }\n}\n```\n\n`error.response` can still be `undefined` for network failures or timeouts, so keep those checks optional even after narrowing.\n\n## Important Pitfalls\n\n- Do not import from `@types/axios`; import from `axios`.\n- Do not keep only `@types/axios` in `devDependencies`. `axios` is the runtime package your app actually executes.\n- If an older lockfile still includes `@types/axios`, remove the stub package before troubleshooting duplicate or stale type behavior.\n- `AxiosResponse<T>` is the full HTTP response wrapper; `response.data` is the typed payload your application usually wants.\n- `axios.isAxiosError()` narrows Axios errors, but transport failures can still leave `error.response` undefined.\n- There are no package-specific environment variables or initialization steps beyond normal Axios client configuration.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/axios==0.14.4`.\n- For this package version, the npm package entry is a stub package that points TypeScript users to `axios`.\n- Install and import `axios` itself for both runtime behavior and TypeScript declarations.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/axios\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/axios\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/axios/index.d.ts\n- https://www.npmjs.com/package/axios\n- https://axios-http.com/docs/intro\n- https://axios-http.com/docs/instance\n- https://axios-http.com/docs/handling_errors\n"
  },
  {
    "path": "content/typescript/docs/babel-core/typescript/DOC.md",
    "content": "---\nname: babel-core\ndescription: \"TypeScript declarations for @babel/core transforms, parsing, plugins, config loading, and AST tooling.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.20.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,babel,babel-core,compiler,ast,types,definitelytyped\"\n---\n\n# Babel Core TypeScript Guide\n\n`@types/babel__core` provides the TypeScript declarations for the `@babel/core` runtime package. Install it when you call Babel programmatically from TypeScript, inspect Babel ASTs, or author Babel plugins and config helpers in TypeScript.\n\nThis package only ships types. It does not compile code by itself, it does not install Babel presets or plugins, and it does not replace the `@babel/core` runtime package.\n\n## Install\n\nInstall TypeScript, the Babel runtime, and the declaration package together:\n\n```bash\nnpm install --save-dev typescript @babel/core @types/babel__core\n```\n\nIf you want Babel to parse or transform TypeScript syntax, install the preset separately:\n\n```bash\nnpm install --save-dev @babel/preset-typescript\n```\n\nAdd any Babel plugins or presets you reference in `plugins` or `presets` as normal runtime dependencies. `@types/babel__core` only covers the type layer.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup is:\n\n- install `@babel/core` for the runtime API\n- install `@types/babel__core` for compile-time declarations\n- configure Babel behavior with `TransformOptions` and separately installed presets or plugins\n\n## TypeScript Setup\n\nUse a normal strict TypeScript configuration for tooling code that calls Babel:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/babel__core@7.20.5` declares `typeScriptVersion: \"4.5\"`, so use TypeScript 4.5 or newer.\n\nImport from `@babel/core`, not from `@types/babel__core`:\n\n```typescript\nimport * as babel from \"@babel/core\";\nimport type { TransformOptions } from \"@babel/core\";\n```\n\nUsing a namespace import is a practical default because `@babel/core` is published as a CommonJS package and the declarations expose the runtime API off the same module.\n\n## Common Workflows\n\n### Transform source code with typed options\n\n`TransformOptions` covers the options you pass into `transformSync`, `transformAsync`, `transformFileSync`, and related APIs.\n\n```typescript\nimport * as babel from \"@babel/core\";\nimport type { TransformOptions } from \"@babel/core\";\n\nconst options: TransformOptions = {\n  filename: \"src/example.ts\",\n  presets: [\"@babel/preset-typescript\"],\n  sourceMaps: true,\n};\n\nconst result = babel.transformSync(\"const answer: number = 42;\", options);\n\nif (!result?.code) {\n  throw new Error(\"Babel returned no compiled output\");\n}\n\nconsole.log(result.code);\nconsole.log(result.map);\n```\n\nUse this pattern when a build script, codemod, test helper, or custom compiler step needs a typed Babel call instead of a config file only.\n\n### Parse, traverse, and reprint an AST\n\nThe declarations re-export `traverse`, `types`, `template`, `NodePath`, `Visitor`, `ParserOptions`, and `GeneratorOptions` from the Babel packages that `@babel/core` uses internally.\n\n```typescript\nimport * as babel from \"@babel/core\";\n\nconst source = \"const answer = 42;\";\n\nconst ast = babel.parseSync(source, {\n  filename: \"src/example.js\",\n  sourceType: \"module\",\n});\n\nif (!ast) {\n  throw new Error(\"Babel returned no AST\");\n}\n\nbabel.traverse(ast, {\n  VariableDeclarator(path) {\n    if (babel.types.isIdentifier(path.node.id) && path.node.id.name === \"answer\") {\n      path.node.id = babel.types.identifier(\"result\");\n    }\n  },\n});\n\nconst output = babel.transformFromAstSync(ast, source, {});\n\nif (!output?.code) {\n  throw new Error(\"Babel returned no transformed code\");\n}\n\nconsole.log(output.code);\n```\n\nThis is the core pattern for codemods and custom source transforms.\n\n### Type a Babel plugin\n\nUse `PluginObj` and `PluginPass` to keep visitor code and plugin options typed.\n\n```typescript\nimport * as babel from \"@babel/core\";\n\ntype RenameOptions = {\n  from: string;\n  to: string;\n};\n\ntype RenamePass = babel.PluginPass & {\n  opts: RenameOptions;\n};\n\nexport function renameIdentifier(): babel.PluginObj<RenamePass> {\n  return {\n    name: \"rename-identifier\",\n    visitor: {\n      Identifier(path) {\n        if (path.node.name === this.opts.from) {\n          path.node.name = this.opts.to;\n        }\n      },\n    },\n  };\n}\n\nconst result = babel.transformSync(\"const oldName = 1;\", {\n  plugins: [[renameIdentifier, { from: \"oldName\", to: \"newName\" }]],\n});\n\nconsole.log(result?.code);\n```\n\nThe typed plugin shape helps when you publish internal Babel plugins or share them across multiple packages.\n\n### Inspect resolved config or prebuild config items\n\n`createConfigItem` and `loadPartialConfig` are useful in build tools that need Babel to resolve config exactly once and then reuse it.\n\n```typescript\nimport * as babel from \"@babel/core\";\n\nconst typescriptPreset = babel.createConfigItem(\"@babel/preset-typescript\", {\n  type: \"preset\",\n});\n\nconst partial = babel.loadPartialConfig({\n  filename: \"src/example.ts\",\n  presets: [typescriptPreset],\n});\n\nif (!partial) {\n  throw new Error(\"Babel did not resolve a config\");\n}\n\nconsole.log(partial.hasFilesystemConfig());\nconsole.log(partial.options.presets?.length ?? 0);\n```\n\nUse `loadOptions()` instead when you need Babel to flatten presets and plugins into a fully resolved options object.\n\n## Important Pitfalls\n\n- Do not import from `@types/babel__core` in application or tooling code. Import from `@babel/core` and let TypeScript pick up the declarations automatically.\n- `@types/babel__core` does not install the Babel CLI, presets, or plugins. If you reference `@babel/preset-typescript` or any plugin by name, install that package separately.\n- The core transform and parse APIs are typed as nullable: `transformSync`, `transformAsync`, `transformFromAstSync`, `parseSync`, `loadOptions`, and `loadPartialConfig` can all return `null`. Check for `null` before reading `.code`, `.ast`, or `.options`.\n- `DEFAULT_EXTENSIONS` only includes `.js`, `.jsx`, `.es6`, `.es`, and `.mjs`. TypeScript file handling comes from preset or plugin configuration, not from Babel core's default extension list.\n- These definitions come from DefinitelyTyped rather than the `@babel/core` package itself. New Babel runtime options can appear before the corresponding declaration update is published.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/babel__core==7.20.5`.\n- The package metadata lists `@babel/parser`, `@babel/types`, `@types/babel__generator`, `@types/babel__template`, and `@types/babel__traverse` as dependencies, so npm installs the related declaration packages automatically.\n- Pair this package with the Babel 7 runtime family. If your `@babel/core` runtime is much newer than the declaration package, verify newer options against the current Babel docs before depending on them in TypeScript.\n\n## Official Sources\n\n- npm package page for `@types/babel__core`: https://www.npmjs.com/package/@types/babel__core\n- DefinitelyTyped source for `@types/babel__core`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__core\n- npm package page for `@babel/core`: https://www.npmjs.com/package/@babel/core\n- Babel core package docs: https://babeljs.io/docs/babel-core\n- Babel options reference: https://babeljs.io/docs/options\n- Babel config files and config function API: https://babeljs.io/docs/config-files\n"
  },
  {
    "path": "content/typescript/docs/babel-generator/typescript/DOC.md",
    "content": "---\nname: babel-generator\ndescription: \"TypeScript declarations for @babel/generator code printing, source maps, and generator options for Babel ASTs.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.27.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,babel,babel-generator,ast,codegen,types,definitelytyped\"\n---\n\n# babel-generator TypeScript Guide\n\n`@types/babel__generator` provides the TypeScript declarations for the `@babel/generator` runtime package. Use it when your TypeScript code prints Babel ASTs back to JavaScript, configures output with `GeneratorOptions`, or reads the generated source map.\n\nThis package only ships declarations. Install `@babel/generator` for the runtime API.\n\n## Install\n\nInstall TypeScript, the generator runtime, and the declaration package together:\n\n```bash\nnpm install --save-dev typescript @babel/generator @types/babel__generator\n```\n\nIf your code parses source text or builds AST nodes directly, add the adjacent Babel packages you import from:\n\n```bash\nnpm install --save-dev @babel/parser @babel/types\n```\n\n`@types/babel__generator@7.27.0` declares `typeScriptVersion: \"5.1\"`, so use TypeScript 5.1 or newer.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup is:\n\n- install `@babel/generator` for the runtime API\n- install `@types/babel__generator` for compile-time declarations\n- pass a Babel AST into `generate()` or `new CodeGenerator()`\n- pass the original source string as the third argument when you need source maps tied to real input\n\n## TypeScript Setup\n\nNo package-specific compiler flags are required beyond normal TypeScript module resolution. A minimal strict setup looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nImport from `@babel/generator`, never from `@types/babel__generator`:\n\n```typescript\nimport { CodeGenerator, generate, type GeneratorOptions } from \"@babel/generator\";\n```\n\nThe declarations also provide a default export, but the named `generate()` export is a clear default for TypeScript examples.\n\n## Common Workflows\n\n### Generate code from a parsed AST\n\n`@babel/generator` prints the AST you give it. A common workflow is parse → edit AST → generate.\n\n```typescript\nimport { parse } from \"@babel/parser\";\nimport { generate, type GeneratorOptions } from \"@babel/generator\";\nimport * as t from \"@babel/types\";\n\nconst source = \"const answer = 41;\";\nconst ast = parse(source, { sourceType: \"module\" });\nconst statement = ast.program.body[0];\n\nif (statement?.type === \"VariableDeclaration\") {\n  const declarator = statement.declarations[0];\n\n  if (\n    t.isVariableDeclarator(declarator) &&\n    t.isIdentifier(declarator.id) &&\n    t.isNumericLiteral(declarator.init)\n  ) {\n    declarator.id = t.identifier(\"result\");\n    declarator.init = t.numericLiteral(42);\n  }\n}\n\nconst options: GeneratorOptions = {\n  comments: true,\n  compact: false,\n};\n\nconst output = generate(ast, options);\n\nconsole.log(output.code);\n```\n\nUse this pattern in codemods, build scripts, and Babel plugins that need typed code generation after AST changes.\n\n### Generate code and a source map\n\nSet `sourceMaps: true` and pass the original source string as the third argument when you want a populated `map` result.\n\n```typescript\nimport { parse } from \"@babel/parser\";\nimport { generate, type GeneratorOptions } from \"@babel/generator\";\n\nconst source = \"export const answer = 42;\\n\";\nconst ast = parse(source, { sourceType: \"module\" });\n\nconst options: GeneratorOptions = {\n  sourceMaps: true,\n  sourceFileName: \"src/answer.ts\",\n  sourceRoot: \"/workspace\",\n};\n\nconst result = generate(ast, options, source);\n\nconsole.log(result.code);\nconsole.log(result.map?.sources);\n```\n\nThe declaration signature also allows the third argument to be a filename-to-source map object when your generation step needs more than one source input.\n\n### Build a small AST manually with `@babel/types`\n\nIf you already have Babel node objects, you can generate code without parsing text first.\n\n```typescript\nimport { generate } from \"@babel/generator\";\nimport * as t from \"@babel/types\";\n\nconst ast = t.file(\n  t.program([\n    t.variableDeclaration(\"const\", [\n      t.variableDeclarator(t.identifier(\"answer\"), t.numericLiteral(42)),\n    ]),\n    t.expressionStatement(\n      t.callExpression(\n        t.memberExpression(t.identifier(\"console\"), t.identifier(\"log\")),\n        [t.identifier(\"answer\")],\n      ),\n    ),\n  ]),\n);\n\nconst result = generate(ast, { concise: true });\n\nconsole.log(result.code);\n```\n\nThis is the direct integration boundary when your tool creates Babel nodes programmatically.\n\n### Use the `CodeGenerator` class directly\n\nThe function form is enough for most code, but the declarations also expose the class API.\n\n```typescript\nimport { CodeGenerator } from \"@babel/generator\";\nimport * as t from \"@babel/types\";\n\nconst ast = t.file(t.program([\n  t.expressionStatement(t.stringLiteral(\"©\")),\n]));\n\nconst generator = new CodeGenerator(ast, {\n  jsonCompatibleStrings: true,\n});\n\nconst result = generator.generate();\n\nconsole.log(result.code);\n```\n\nUse `CodeGenerator` when a class instance fits your abstraction better than a single helper call.\n\n## Important Pitfalls\n\n- Install `@babel/generator` separately. `@types/babel__generator` does not include the runtime printer.\n- Import from `@babel/generator`, not from `@types/babel__generator`.\n- `generate()` prints the AST as-is. Parsing and generating alone does not transform code unless you change the AST first.\n- `GeneratorResult.map` is `null` unless you enable `sourceMaps`.\n- `sourceFileName` is only used when the third `code` argument is a string, so pass the original source text when you want meaningful source-map metadata.\n- `comments: false` does not automatically remove `@license` or `@preserve` comments, because the default `shouldPrintComment()` behavior still keeps those markers in non-minified output.\n- Runtime printer options can appear in `@babel/generator` before the corresponding DefinitelyTyped package adds them to `GeneratorOptions`.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/babel__generator==7.27.0`.\n- The published package metadata depends on `@babel/types` and declares a minimum TypeScript version of `5.1`.\n- The declarations expose `GeneratorOptions`, `CodeGenerator`, a named `generate()` export, and a default export.\n- The published `@babel/generator@7.28.5` runtime normalizes options including `experimental_preserveFormat`, `topicToken`, and `recordAndTupleSyntaxType` in `lib/index.js`, but those fields are not declared in `@types/babel__generator@7.27.0`. If you need those newer options, augment the type locally or verify that a newer declaration publish includes them before relying on them in strict TypeScript code.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/babel__generator\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__generator\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/babel__generator/index.d.ts\n- https://www.npmjs.com/package/@babel/generator\n- https://babeljs.io/docs/babel-generator\n"
  },
  {
    "path": "content/typescript/docs/babel-template/typescript/DOC.md",
    "content": "---\nname: babel-template\ndescription: \"TypeScript declarations for @babel/template AST builders, placeholders, and parser options when generating Babel nodes from code snippets.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.4.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,babel,babel-template,ast,codegen,types,definitelytyped\"\n---\n\n# babel-template TypeScript Guide\n\n`@types/babel__template` provides the TypeScript declarations for the `@babel/template` runtime package. Use it when your TypeScript code builds Babel AST nodes from code snippets, placeholder substitutions, or parser-enabled templates inside codemods, Babel plugins, and compiler tooling.\n\nThis package only ships declarations. Install `@babel/template` for the runtime API.\n\n## Install\n\nInstall TypeScript, the Babel template runtime, and the declaration package together:\n\n```bash\nnpm install --save-dev typescript @babel/template @types/babel__template\n```\n\nMost real usage also imports Babel node builders or prints generated ASTs back to code, so add the adjacent Babel packages you use directly:\n\n```bash\nnpm install --save-dev @babel/types @babel/generator\n```\n\nIf you parse or template syntax that needs extra parser plugins, keep the related Babel packages on the same Babel 7 line as the rest of your toolchain.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup is:\n\n- install `@babel/template` for the runtime builder API\n- install `@types/babel__template` for compile-time declarations\n- import `template` from `@babel/template`\n- pass Babel AST nodes from `@babel/types` as placeholder replacements\n- enable parser plugins in template options when the snippet includes TypeScript, JSX, or other non-default syntax\n\n## TypeScript Setup\n\nNo package-specific compiler flags are required beyond normal TypeScript module resolution. A minimal strict setup looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nImport from `@babel/template`, never from `@types/babel__template`:\n\n```typescript\nimport template from \"@babel/template\";\nimport * as t from \"@babel/types\";\n```\n\nIn TypeScript, prefer the shape-specific builders such as `template.statement(...)`, `template.statements(...)`, `template.expression(...)`, and `template.program(...)`. They produce narrower result types than the generic builder APIs and usually avoid extra casts.\n\n## Common Workflows\n\n### Build one statement with identifier and literal placeholders\n\n`template.statement(...)` is the practical default when your snippet should produce exactly one Babel `Statement`.\n\n```typescript\nimport template from \"@babel/template\";\nimport * as t from \"@babel/types\";\n\nconst buildRequire = template.statement(`const IMPORT_NAME = require(SOURCE);`);\n\nconst declaration = buildRequire({\n  IMPORT_NAME: t.identifier(\"fs\"),\n  SOURCE: t.stringLiteral(\"node:fs\"),\n});\n\nconsole.log(declaration.type);\n```\n\nUse this pattern when a codemod or plugin needs to inject a declaration without manually assembling every AST node by hand.\n\n### Build an expression and embed it elsewhere\n\n`template.expression(...)` is the narrowest choice when you need a single Babel `Expression`.\n\n```typescript\nimport template from \"@babel/template\";\nimport * as t from \"@babel/types\";\n\nconst buildCall = template.expression(`console.log(MESSAGE)`);\n\nconst expression = buildCall({\n  MESSAGE: t.stringLiteral(\"ready\"),\n});\n\nconst statement = t.expressionStatement(expression);\n\nconsole.log(statement.type);\n```\n\nThis keeps the builder result precise, which is useful when the next API expects an `Expression` instead of a generic node union.\n\n### Generate multiple statements or a full program\n\nWhen a snippet expands to more than one statement, use `template.statements(...)` or `template.program(...)` instead of casting the result from a looser builder.\n\n```typescript\nimport template from \"@babel/template\";\nimport { generate } from \"@babel/generator\";\n\nconst buildProgram = template.program(\n  `\n  const answer: number = 42;\n  export default answer;\n`,\n  {\n    plugins: [\"typescript\"],\n  },\n);\n\nconst program = buildProgram();\n\nconsole.log(generate(program).code);\n```\n\nPass parser plugins whenever the template string contains syntax such as TypeScript annotations or JSX that the default parser configuration would reject.\n\n### Use syntactic placeholders for clearer replacements\n\nSyntactic placeholders are useful when you want placeholder names that are visually distinct from the code around them.\n\n```typescript\nimport template from \"@babel/template\";\nimport * as t from \"@babel/types\";\n\nconst buildExport = template.statement(\n  `export const %%name%% = %%value%%;`,\n  {\n    syntacticPlaceholders: true,\n  },\n);\n\nconst declaration = buildExport({\n  name: t.identifier(\"answer\"),\n  value: t.numericLiteral(42),\n});\n\nconsole.log(declaration.type);\n```\n\nThis is often easier to read than relying on all-caps identifier placeholders inside larger templates.\n\n### Parse a one-off AST fragment directly\n\nUse `template.ast(...)` when you want the parsed AST result immediately and do not need a reusable builder function.\n\n```typescript\nimport template from \"@babel/template\";\n\nconst fileAst = template.ast(`export default 42;`);\n\nconsole.log(fileAst.type);\n```\n\nThis is convenient in tests and small tooling helpers where you only need to parse one snippet once.\n\n## Important Pitfalls\n\n- Install `@babel/template` separately. `@types/babel__template` does not include runtime JavaScript.\n- Import from `@babel/template`, not from `@types/babel__template`.\n- Placeholder replacements are Babel AST nodes, not raw JavaScript values. Use builders such as `t.identifier(...)`, `t.stringLiteral(...)`, and `t.numericLiteral(...)` from `@babel/types`.\n- If the template string includes TypeScript, JSX, decorators, or other non-default syntax, pass the required parser plugins in the template options.\n- Prefer `template.statement(...)`, `template.statements(...)`, `template.expression(...)`, and `template.program(...)` in TypeScript. They give you narrower result types than the generic builder forms.\n- `@babel/template` creates AST nodes. It does not traverse, transform, or print code by itself; pair it with `@babel/traverse`, `@babel/core`, or `@babel/generator` when you need those steps.\n- The runtime package can add new parser or template options before the separate DefinitelyTyped package reflects them. In strict TypeScript code, verify option names against the published declaration package for the version you install.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/babel__template==7.4.4`.\n- The published package metadata for `@types/babel__template@7.4.4` depends on `@babel/parser` `^7.1.0` and `@babel/types` `^7.0.0`.\n- The current `@babel/template` npm package metadata does not declare bundled `types` or `typings`, which is why the separate `@types/babel__template` package remains relevant for Babel 7 TypeScript projects.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/babel__template\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__template\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/babel__template/index.d.ts\n- https://www.npmjs.com/package/@babel/template\n- https://babeljs.io/docs/babel-template\n- https://www.npmjs.com/package/@babel/types\n- https://www.npmjs.com/package/@babel/generator\n"
  },
  {
    "path": "content/typescript/docs/babel-traverse/typescript/DOC.md",
    "content": "---\nname: babel-traverse\ndescription: \"TypeScript declarations for @babel/traverse AST visitors, NodePath helpers, scope APIs, and traversal utilities.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.28.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,babel,babel-traverse,ast,codemod,compiler,types,definitelytyped\"\n---\n\n# Babel Traverse TypeScript Guide\n\n`@types/babel__traverse` provides TypeScript declarations for the `@babel/traverse` runtime package.\n\nInstall it when you write Babel transforms, codemods, lint-style AST checks, or build tooling in TypeScript and want typed access to `traverse(...)`, `Visitor`, `NodePath`, `Scope`, and the related traversal helpers.\n\nThis package only ships declarations. Your code still imports and runs `@babel/traverse`.\n\n## Install\n\nInstall the runtime package together with the declaration package. If you parse source text yourself or build replacement nodes, install the parser and types packages you use in code:\n\n```bash\nnpm install --save-dev typescript @babel/traverse @babel/parser @babel/types\nnpm install --save-dev @types/babel__traverse@7.28.0\n```\n\nIf your project already receives ASTs from `@babel/core` or another Babel tool, you may not need `@babel/parser` directly.\n\nThere are no package-specific environment variables, credentials, tokens, or client objects to configure.\n\n## TypeScript Setup\n\n`@types/babel__traverse@7.28.0` declares `typeScriptVersion: \"5.1\"`, so use TypeScript 5.1 or newer.\n\nImport runtime values and types from `@babel/traverse`, not from `@types/babel__traverse`:\n\n```ts\nimport traverse, { type NodePath, type Visitor } from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\nimport * as t from \"@babel/types\";\n```\n\nIf your project restricts global type loading with `compilerOptions.types`, include `babel__traverse` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"babel__traverse\"]\n  }\n}\n```\n\nIf you do not restrict `compilerOptions.types`, TypeScript usually discovers the declarations automatically.\n\n## Common Workflows\n\n### Traverse a parsed AST with typed visitors\n\nThe main API is the default `traverse(...)` function. It accepts a Babel AST node and a `Visitor` object whose keys are node types or aliases.\n\n```ts\nimport traverse, { type Visitor } from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\nimport * as t from \"@babel/types\";\n\nconst source = `\n  const answer = count + 1;\n  console.log(answer);\n`;\n\nconst ast = parse(source, {\n  sourceType: \"module\",\n});\n\nconst visitor: Visitor = {\n  Identifier(path) {\n    if (path.node.name === \"answer\") {\n      path.node.name = \"total\";\n    }\n  },\n  BinaryExpression(path) {\n    if (t.isIdentifier(path.node.left, { name: \"count\" })) {\n      console.log(path.get(\"right\").isNumericLiteral());\n    }\n  },\n};\n\ntraverse(ast, visitor);\n```\n\nUse this pattern for codemods, custom lint rules, and build-time analysis.\n\n### Carry typed traversal state with `Visitor<S>`\n\nThe declarations type visitor state as a generic, so your traversal callbacks can share a structured accumulator without falling back to `any`.\n\n```ts\nimport traverse, { type Visitor } from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\n\ntype IdentifierStats = {\n  counts: Map<string, number>;\n};\n\nconst ast = parse(\"const a = b + c; console.log(a);\", {\n  sourceType: \"module\",\n});\n\nconst state: IdentifierStats = {\n  counts: new Map(),\n};\n\nconst visitor: Visitor<IdentifierStats> = {\n  Identifier(path, currentState) {\n    const nextCount = (currentState.counts.get(path.node.name) ?? 0) + 1;\n    currentState.counts.set(path.node.name, nextCount);\n  },\n};\n\ntraverse(ast, visitor, undefined, state);\n\nconsole.log(state.counts);\n```\n\nThis is the practical way to collect names, references, or findings across one traversal pass.\n\n### Rename bindings with `Scope`\n\n`NodePath#scope` gives you the typed Babel scope API, including binding lookups and safe renaming.\n\n```ts\nimport traverse from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\n\nconst ast = parse(\n  `\n  function compute(input) {\n    const answer = input + 1;\n    return answer * 2;\n  }\n`,\n  { sourceType: \"module\" },\n);\n\ntraverse(ast, {\n  FunctionDeclaration(path) {\n    if (path.node.id?.name !== \"compute\") {\n      return;\n    }\n\n    if (path.scope.hasBinding(\"answer\")) {\n      path.scope.rename(\"answer\", \"result\");\n    }\n  },\n});\n```\n\nPrefer `scope.rename(...)` over manual string replacement when a transform changes identifiers across references in the same scope.\n\n### Evaluate and replace nodes through `NodePath`\n\nThe declarations cover common `NodePath` helpers such as `evaluate()`, `replaceWith(...)`, `remove()`, `skip()`, `stop()`, and `get(...)`.\n\n```ts\nimport traverse from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\nimport * as t from \"@babel/types\";\n\nconst ast = parse(\"const value = 2 + 3; const keep = input + 1;\", {\n  sourceType: \"module\",\n});\n\ntraverse(ast, {\n  BinaryExpression(path) {\n    const evaluated = path.evaluate();\n\n    if (evaluated.confident && typeof evaluated.value === \"number\") {\n      path.replaceWith(t.numericLiteral(evaluated.value));\n    }\n  },\n});\n```\n\nThis is useful when you want a conservative constant-folding step before a later transform or analysis pass.\n\n### Check AST structure with top-level helpers\n\nThe default export also exposes traversal utilities such as `hasType(...)`, `removeProperties(...)`, `clearNode(...)`, `visitors.verify(...)`, and `visitors.explode(...)`.\n\n```ts\nimport traverse from \"@babel/traverse\";\nimport { parse } from \"@babel/parser\";\n\nconst ast = parse(\"await fetch(url)\", {\n  sourceType: \"module\",\n  plugins: [\"topLevelAwait\"],\n});\n\nif (traverse.hasType(ast, \"AwaitExpression\")) {\n  console.log(\"The file contains an await expression.\");\n}\n```\n\nUse these helpers for quick preflight checks before you commit to a full visitor.\n\n## Important Pitfalls\n\n- Install `@babel/traverse` as well as `@types/babel__traverse`; the type package does not include runtime JavaScript.\n- Import from `@babel/traverse`, not from `@types/babel__traverse`.\n- If your code imports `@babel/types` directly for builders or guards such as `t.numericLiteral(...)` or `t.isIdentifier(...)`, list `@babel/types` as a direct dependency in your project.\n- `@babel/traverse` traverses an existing AST. It does not parse source text; use `@babel/parser` or `@babel/core` when you need to create the AST first.\n- The runtime throws when you traverse a node other than `Program` or `File` without passing both `scope` and `parentPath`. For partial-node traversal, either keep the original `NodePath` context or use `noScope: true` only when scope data is not needed.\n- If `compilerOptions.types` is restricted and `babel__traverse` is missing from the list, the declarations will not load even if the package is installed.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/babel__traverse==7.28.0`.\n- The package metadata declares `typeScriptVersion: \"5.1\"`.\n- The declaration package depends on `@babel/types` with range `^7.28.2`.\n- The Babel 7.28.x `@babel/traverse` package is published as CommonJS and its package metadata does not declare bundled TypeScript types, which is why the separate `@types/babel__traverse` package is relevant for this version line.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/babel__traverse\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__traverse\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/babel__traverse/index.d.ts\n- https://www.npmjs.com/package/@babel/traverse\n- https://babel.dev/docs/babel-traverse\n- https://www.npmjs.com/package/@babel/parser\n- https://babel.dev/docs/babel-parser\n- https://www.npmjs.com/package/@babel/types\n"
  },
  {
    "path": "content/typescript/docs/bcrypt/typescript/DOC.md",
    "content": "---\nname: bcrypt\ndescription: \"TypeScript declarations for bcrypt password hashing in Node.js, including async and sync hashing, salt generation, password comparison, and work-factor inspection\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,bcrypt,passwords,hashing,security,node,types,definitelytyped\"\n---\n\n# bcrypt TypeScript Guide\n\n`@types/bcrypt` adds TypeScript declarations for the `bcrypt` runtime package. Install it when your Node.js app hashes passwords with `bcrypt` and you want typed access to the async and sync APIs for `genSalt`, `hash`, `compare`, and `getRounds`.\n\nThis package only provides declarations. Import and execute code from `bcrypt`, not from `@types/bcrypt`.\n\n## Golden Rule\n\nInstall `@types/bcrypt` alongside the real `bcrypt` runtime package.\n\n`@types/bcrypt` does not include hashing code, native bindings, or any password-storage behavior by itself. It only describes the runtime API to TypeScript.\n\n## Install\n\nInstall the runtime package first, then add the declaration package and standard Node.js TypeScript support:\n\n```bash\nnpm install bcrypt\nnpm install -D typescript @types/bcrypt @types/node\n```\n\nIf `bcrypt` is already in your app, add only the missing declarations:\n\n```bash\nnpm install -D @types/bcrypt\n```\n\n`bcrypt` does not require API keys, service credentials, or package-defined environment variables.\n\nIf you want the work factor to be configurable across environments, define an application variable such as:\n\n```bash\nexport BCRYPT_SALT_ROUNDS=12\n```\n\n## TypeScript Setup\n\nThe declaration package uses `export =`, so the most portable import form is:\n\n```typescript\nimport bcrypt = require(\"bcrypt\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport bcrypt from \"bcrypt\";\n```\n\nRecommended `tsconfig.json` settings for a Node.js app:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts loaded global type packages, keep `node` available to the same project that imports `bcrypt`.\n\n## Initialization\n\nThere is no client object to create and no authentication step.\n\nThe practical setup is choosing a cost factor and deciding whether to use the async Promise-based API or the sync API.\n\nFor server request handlers, prefer the async functions so password hashing does not block the event loop.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nconst saltRounds = Number.parseInt(process.env.BCRYPT_SALT_ROUNDS ?? \"12\", 10);\n\nif (!Number.isInteger(saltRounds) || saltRounds <= 0) {\n  throw new Error(\"BCRYPT_SALT_ROUNDS must be a positive integer\");\n}\n```\n\n## Common Workflows\n\n### Hash a password with a cost factor\n\nPass a number as the second argument to `hash()` when you want `bcrypt` to generate the salt for you.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nconst saltRounds = Number.parseInt(process.env.BCRYPT_SALT_ROUNDS ?? \"12\", 10);\n\nexport async function hashPassword(password: string) {\n  return bcrypt.hash(password, saltRounds);\n}\n```\n\nThis is the simplest typed integration for application code that stores a full bcrypt hash string in a database.\n\n### Compare a candidate password to a stored hash\n\nUse `compare()` during sign-in or password verification.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nexport async function verifyPassword(\n  candidatePassword: string,\n  storedHash: string,\n) {\n  return bcrypt.compare(candidatePassword, storedHash);\n}\n```\n\nStore the full hash returned by `hash()` and pass that stored value back into `compare()`.\n\n### Generate a salt explicitly\n\nUse `genSalt()` when you want to separate salt generation from hashing.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nconst saltRounds = 12;\n\nexport async function hashWithExplicitSalt(password: string) {\n  const salt = await bcrypt.genSalt(saltRounds);\n  return bcrypt.hash(password, salt);\n}\n```\n\nThe same API shape also supports callback-based usage, but Promise-returning calls are the most practical fit for modern TypeScript apps.\n\n### Use the sync API in scripts or one-off tools\n\nThe declarations also cover the synchronous helpers.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nconst salt = bcrypt.genSaltSync(12);\nconst passwordHash = bcrypt.hashSync(\"correct horse battery staple\", salt);\nconst matches = bcrypt.compareSync(\"correct horse battery staple\", passwordHash);\n\nconsole.log({ passwordHash, matches });\n```\n\nUse the sync functions carefully in long-lived servers because they block the Node.js event loop while hashing work is in progress.\n\n### Inspect the work factor on an existing hash\n\nUse `getRounds()` when you need to see whether an older stored hash should be replaced with a stronger cost factor.\n\n```typescript\nimport bcrypt from \"bcrypt\";\n\nexport function needsRehash(storedHash: string, minimumRounds: number) {\n  return bcrypt.getRounds(storedHash) < minimumRounds;\n}\n```\n\nThis is useful when you want to rehash on successful login after increasing your application's target cost factor.\n\n## Important Pitfalls\n\n- `@types/bcrypt` does not install or execute the runtime package. Install `bcrypt` itself.\n- Import from `bcrypt`, not from `@types/bcrypt`.\n- Without TypeScript interop flags, prefer `import bcrypt = require(\"bcrypt\")` over a default import.\n- Prefer async `genSalt()`, `hash()`, and `compare()` in server code; the sync variants block the event loop.\n- Store the full bcrypt hash string returned by `hash()`; later verification and round inspection expect that complete value.\n- If you read the cost factor from an environment variable, parse and validate it before passing it to `genSalt()` or `hash()`.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/bcrypt==6.0.0`.\n- The declaration package models the `bcrypt` runtime API with Promise-based, callback-based, and synchronous overloads for salt generation, hashing, and comparison.\n- The declaration entrypoint uses `export =`, so your import style depends on your TypeScript interop settings.\n- These declarations are for the `bcrypt` package. They do not replace the runtime package and do not apply to other bcrypt-compatible libraries unless those libraries document the same API.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/bcrypt\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bcrypt\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/bcrypt/index.d.ts\n- https://www.npmjs.com/package/bcrypt\n- https://github.com/kelektiv/node.bcrypt.js\n"
  },
  {
    "path": "content/typescript/docs/bcryptjs/typescript/DOC.md",
    "content": "---\nname: bcryptjs\ndescription: \"TypeScript guidance for `bcryptjs`, including the `@types/bcryptjs` package boundary, imports, password hashing, hash verification, and browser fallback setup.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,bcryptjs,bcrypt,passwords,hashing,security,node,browser,npm\"\n---\n\n# bcryptjs TypeScript Guide\n\n## Golden Rule\n\nFor a current TypeScript project, install and import `bcryptjs`.\n\n`@types/bcryptjs` is not the package you import in application code. The practical runtime boundary is `bcryptjs`, which exposes the hashing APIs you call from Node.js or browser-oriented code.\n\nIn practice:\n\n- install `bcryptjs`\n- remove `@types/bcryptjs` if it was added directly to your project\n- import from `bcryptjs`, never from `@types/bcryptjs`\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install bcryptjs\nnpm install -D typescript @types/node\n```\n\nIf your project already added `@types/bcryptjs` directly, remove it:\n\n```bash\nnpm uninstall @types/bcryptjs\n```\n\n`bcryptjs` does not require credentials, API keys, or service initialization.\n\nIf you want the bcrypt cost factor to vary by environment, define an application variable such as:\n\n```bash\nexport BCRYPT_SALT_ROUNDS=12\n```\n\n## TypeScript Setup\n\n`bcryptjs` is commonly used as a module object in the official runtime examples, so a practical TypeScript import is:\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n```\n\nRecommended `tsconfig.json` settings for a Node.js project:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your code reads `process.env`, keep `@types/node` available to that project. If your framework injects config another way, replace the environment-variable examples with your framework's config API.\n\nDo not add `bcryptjs` or `@types/bcryptjs` to `compilerOptions.types`. Importing from `bcryptjs` is enough.\n\n## Initialization\n\nThere is no client object to create and no authentication step.\n\nThe practical setup is choosing a cost factor and deciding whether to use the async API or the sync API. The official README notes that the async API splits work into small chunks and places the next chunk on the event loop queue, which is the safer choice for request-driven server code.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nconst saltRounds = Number.parseInt(process.env.BCRYPT_SALT_ROUNDS ?? \"12\", 10);\n\nif (!Number.isInteger(saltRounds) || saltRounds <= 0) {\n  throw new Error(\"BCRYPT_SALT_ROUNDS must be a positive integer\");\n}\n\nexport { bcrypt, saltRounds };\n```\n\n## Common Workflows\n\n### Hash a password with an application-defined cost factor\n\nPass a number as the second argument to `hash()` when you want `bcryptjs` to generate the salt for you.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nconst saltRounds = Number.parseInt(process.env.BCRYPT_SALT_ROUNDS ?? \"12\", 10);\n\nexport async function hashPassword(password: string): Promise<string> {\n  return bcrypt.hash(password, saltRounds);\n}\n```\n\nStore the returned 60-character hash string in your database and reuse that stored value during verification.\n\n### Compare a plaintext password with a stored hash\n\nUse `compare()` during sign-in or password verification.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nexport async function verifyPassword(\n  candidatePassword: string,\n  storedHash: string,\n): Promise<boolean> {\n  return bcrypt.compare(candidatePassword, storedHash);\n}\n```\n\nThe README documents both callback-based and Promise-based async forms. In TypeScript application code, the Promise-returning form is usually the simplest fit.\n\n### Generate a salt explicitly\n\nUse `genSalt()` when you want to separate salt generation from hashing.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nexport async function hashWithExplicitSalt(password: string): Promise<string> {\n  const salt = await bcrypt.genSalt(12);\n  return bcrypt.hash(password, salt);\n}\n```\n\n### Use the sync API in scripts or one-off tools\n\nThe runtime also exposes synchronous helpers.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nconst salt = bcrypt.genSaltSync(12);\nconst passwordHash = bcrypt.hashSync(\"correct horse battery staple\", salt);\nconst matches = bcrypt.compareSync(\"correct horse battery staple\", passwordHash);\n\nconsole.log({ passwordHash, matches });\n```\n\nPrefer the async functions in long-lived servers. The sync variants block the event loop while hashing work is in progress.\n\n### Inspect the rounds or salt in an existing hash\n\nUse `getRounds()` when you need to decide whether to rehash with a stronger cost factor, and `getSalt()` when you need the salt portion from a valid stored hash.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\nexport function inspectHash(storedHash: string) {\n  return {\n    rounds: bcrypt.getRounds(storedHash),\n    salt: bcrypt.getSalt(storedHash),\n  };\n}\n```\n\n`getSalt()` expects a valid 60-character bcrypt hash string.\n\n### Provide a secure random fallback in constrained runtimes\n\nThe runtime uses Node's `crypto` module on Node.js and Web Crypto in browsers. If your host has neither source available, configure `setRandomFallback()` with a cryptographically secure byte generator provided by that host.\n\n```typescript\nimport * as bcrypt from \"bcryptjs\";\n\ndeclare function secureRandomBytes(length: number): number[];\n\nbcrypt.setRandomFallback((length: number) => secureRandomBytes(length));\n```\n\nOnly use this with a cryptographically secure source of randomness. The maintainer README explicitly warns against weak fallback generators.\n\n## Important Pitfalls\n\n- Do not import from `@types/bcryptjs`; import from `bcryptjs`.\n- Remove a direct `@types/bcryptjs` dependency from modern projects before debugging duplicate or stale types.\n- Prefer async `genSalt()`, `hash()`, and `compare()` in server code; the sync variants block the event loop.\n- BCrypt only uses the first 72 bytes of input. Multi-byte UTF-8 characters count toward that byte limit.\n- Store the full hash returned by `hash()`; later calls to `compare()`, `getRounds()`, and `getSalt()` expect that stored bcrypt hash string.\n- `setRandomFallback()` must use a cryptographically secure source. Do not substitute `Math.random()` or other non-cryptographic generators.\n\n## Version Notes\n\n- This guide targets `@types/bcryptjs==3.0.0`.\n- The relevant runtime package is `bcryptjs`.\n- The documented API surface includes async and sync helpers for `genSalt`, `hash`, and `compare`, plus `getRounds`, `getSalt`, and `setRandomFallback`.\n- The official runtime README documents Promise-returning async calls when the callback argument is omitted.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/bcryptjs\n- https://www.npmjs.com/package/bcryptjs\n- https://github.com/dcodeIO/bcrypt.js\n- https://github.com/dcodeIO/bcrypt.js/blob/master/README.md\n"
  },
  {
    "path": "content/typescript/docs/bluebird/typescript/DOC.md",
    "content": "---\nname: bluebird\ndescription: \"TypeScript declarations for the Bluebird runtime package, including Bluebird-specific promise methods, collection helpers, promisification, and inspection APIs.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.5.42\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,bluebird,promises,async,types,definitelytyped\"\n---\n\n# Bluebird TypeScript Guide\n\n`@types/bluebird` provides the TypeScript declarations for the `bluebird` runtime package. Use it when your project depends on Bluebird-specific promise APIs such as `map()`, `props()`, `delay()`, `timeout()`, `reflect()`, `promisify()`, and `asCallback()`.\n\nThis package only ships `.d.ts` files. Install the `bluebird` runtime separately.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install bluebird\nnpm install --save-dev typescript @types/bluebird @types/node\n```\n\nIf your project already depends on `bluebird`, add only the missing declarations:\n\n```bash\nnpm install --save-dev @types/bluebird\n```\n\n`@types/node` is only needed when your TypeScript code uses Node.js APIs such as `fs`, `process.env`, or callback-based core modules.\n\n## Initialization\n\nThere is no authentication, service client, or package-specific account setup.\n\nThe practical setup is your import style, TypeScript compiler configuration, and any optional Bluebird runtime debugging flags.\n\n### Import Bluebird in TypeScript\n\nThe declaration package targets the CommonJS `bluebird` module. The safest import form is:\n\n```ts\nimport Bluebird = require(\"bluebird\");\n```\n\nIf your compiler enables `esModuleInterop`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport Bluebird from \"bluebird\";\n```\n\nUse `import Bluebird = require(\"bluebird\")` when you want an import form that does not depend on TypeScript interop flags.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"bluebird\"]\n  }\n}\n```\n\nIf you do not restrict `compilerOptions.types`, TypeScript usually discovers `@types/bluebird` automatically. If you do restrict `types`, include `bluebird` in the project that compiles Bluebird-based code.\n\n### Optional runtime debugging and warnings\n\nBluebird does not require environment variables for normal usage, but it reads several optional runtime flags:\n\n```bash\nBLUEBIRD_DEBUG=1 BLUEBIRD_WARNINGS=1 node dist/server.js\nBLUEBIRD_LONG_STACK_TRACES=1 node dist/server.js\nBLUEBIRD_W_FORGOTTEN_RETURN=1 node dist/server.js\n```\n\nYou can also configure the same behaviors in code:\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\nBluebird.config({\n  warnings: { wForgottenReturn: true },\n  longStackTraces: process.env.NODE_ENV !== \"production\",\n  cancellation: true,\n});\n```\n\nEnable `cancellation: true` before Bluebird promises are already in use. The runtime throws if you try to turn cancellation on after promises have been created.\n\n## Common Workflows\n\n### Return `Bluebird<T>` when you need Bluebird instance methods\n\nKeep the return type as `Bluebird<T>` when callers will use methods such as `delay()` or `timeout()`.\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\nfunction fetchLabel(id: string): Bluebird<string> {\n  return Bluebird.resolve(`item-${id}`)\n    .delay(50)\n    .timeout(1000)\n    .then((value) => value.toUpperCase());\n}\n\nconst label = await fetchLabel(\"42\");\n```\n\nIf you annotate the function as plain `Promise<string>`, TypeScript hides Bluebird-only instance methods from downstream code.\n\n### Resolve object-shaped work with `Bluebird.props`\n\n`Bluebird.props()` resolves every value in an object and preserves the original keys in the resolved result.\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\ntype User = {\n  id: string;\n  name: string;\n};\n\ntype Stats = {\n  uploads: number;\n  downloads: number;\n};\n\nfunction loadUser(id: string): Bluebird<User> {\n  return Bluebird.resolve({ id, name: \"Ada\" });\n}\n\nfunction loadStats(_id: string): Bluebird<Stats> {\n  return Bluebird.resolve({ uploads: 12, downloads: 3 });\n}\n\nasync function loadDashboard(id: string) {\n  const result = await Bluebird.props({\n    user: loadUser(id),\n    stats: loadStats(id),\n    loadedAt: Bluebird.resolve(new Date().toISOString()),\n  });\n\n  return result;\n}\n```\n\nThis is the most practical typed pattern when your async work naturally produces a named object instead of an array.\n\n### Process arrays with `Bluebird.map` and bounded concurrency\n\n`Bluebird.map()` accepts an optional `{ concurrency: number }` option for controlled parallelism.\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\ntype Row = {\n  id: string;\n  text: string;\n};\n\nasync function hydrateRows(ids: string[]): Promise<Row[]> {\n  return Bluebird.map(\n    ids,\n    async (id, index, length) => ({\n      id,\n      text: `${index + 1}/${length}: ${id}`,\n    }),\n    { concurrency: 5 },\n  );\n}\n```\n\nUse this when you want typed results from many async tasks without launching the entire batch at once.\n\n### Wrap Node-style callbacks with `Bluebird.fromCallback`\n\n`Bluebird.fromCallback()` is the most direct bridge when you already have a callback-based API and want a typed `Bluebird<T>` result.\n\n```ts\nimport Bluebird = require(\"bluebird\");\nimport { readFile } from \"node:fs\";\n\nfunction readTextFile(path: string): Bluebird<string> {\n  return Bluebird.fromCallback<string>((callback) => {\n    readFile(path, \"utf8\", callback);\n  });\n}\n\nasync function loadConfig(path: string) {\n  const raw = await readTextFile(path);\n  return JSON.parse(raw) as { enabled: boolean };\n}\n```\n\nWhen you need a reusable wrapper for a callback-style function, `Bluebird.promisify()` and `Bluebird.promisifyAll()` expose the same runtime family of conversions.\n\n### Bridge a promise back to a callback API with `asCallback`\n\n`asCallback()` and `nodeify()` let you keep Bluebird internally while still supporting Node-style callbacks at your integration boundary.\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\nfunction loadUserName(id: string): Bluebird<string> {\n  return Bluebird.resolve(`user-${id}`);\n}\n\nfunction getUserName(\n  id: string,\n  callback: (error: Error | null, value?: string) => void,\n) {\n  loadUserName(id).asCallback(callback);\n}\n```\n\nThis is useful when you are gradually migrating an older callback-based codebase to promise-based internals.\n\n### Inspect mixed outcomes with `reflect`\n\nUse `reflect()` when you want every operation to finish and then inspect which ones fulfilled or rejected.\n\n```ts\nimport Bluebird = require(\"bluebird\");\n\nfunction maybeFetch(id: string): Bluebird<string> {\n  return id === \"bad\"\n    ? Bluebird.reject(new Error(\"missing\"))\n    : Bluebird.resolve(`value:${id}`);\n}\n\nasync function loadMany(ids: string[]) {\n  const inspections = await Bluebird.map(ids, (id) => maybeFetch(id).reflect());\n\n  return inspections.map((inspection) => {\n    if (inspection.isFulfilled()) {\n      return { ok: true as const, value: inspection.value() };\n    }\n\n    return { ok: false as const, reason: inspection.reason() };\n  });\n}\n```\n\nPrefer `reflect()` for this pattern. The Bluebird runtime still exposes `Promise.settle()`, but marks it deprecated in favor of `reflect()`.\n\n## Common Pitfalls\n\n- Install `bluebird` as well as `@types/bluebird`; the `@types` package does not include the runtime.\n- Prefer `import Bluebird = require(\"bluebird\")` unless your TypeScript configuration explicitly supports default-import interop.\n- If you restrict `compilerOptions.types`, include `bluebird` or TypeScript will not load these declarations for the project.\n- Keep functions typed as `Bluebird<T>` until the point where you intentionally want the narrower native `Promise<T>` surface.\n- Call `Bluebird.config({ cancellation: true })` before Bluebird promises are already in use.\n- Use `reflect()` instead of `Promise.settle()` for new code.\n- `BLUEBIRD_DEBUG`, `BLUEBIRD_WARNINGS`, `BLUEBIRD_LONG_STACK_TRACES`, and `BLUEBIRD_W_FORGOTTEN_RETURN` change runtime diagnostics only; they do not affect the type system.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/bluebird\n- https://www.npmjs.com/package/bluebird\n- https://github.com/petkaantonov/bluebird\n"
  },
  {
    "path": "content/typescript/docs/body-parser/typescript/DOC.md",
    "content": "---\nname: body-parser\ndescription: \"TypeScript definitions for body-parser middleware factories, parser options, and Express request-body integration\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.19.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,body-parser,express,http,middleware,types,definitelytyped\"\n---\n\n# body-parser TypeScript Guide\n\n## Golden Rule\n\nInstall `body-parser` for runtime behavior and `@types/body-parser` for TypeScript declarations.\n\n`@types/body-parser` only adds `.d.ts` files for the `body-parser` module. Your application still imports and runs `body-parser` itself.\n\n## Install\n\nFor a typical Express app, install the runtime packages first, then the TypeScript declarations:\n\n```bash\nnpm install express body-parser\nnpm install -D typescript @types/node @types/express @types/body-parser\n```\n\nNo environment variables, credentials, or client initialization are required.\n\n## Initialize In TypeScript\n\n`@types/body-parser` uses `export = bodyParser`, so the most portable import form is:\n\n```typescript\nimport bodyParser = require(\"body-parser\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport bodyParser from \"body-parser\";\n```\n\nIf you restrict loaded declaration packages with `compilerOptions.types`, keep the relevant Node and Express types available to the server project:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"express\", \"body-parser\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Parse JSON Bodies With A Typed Handler\n\nUse `bodyParser.json()` for JSON requests, then give your Express handler an explicit `ReqBody` type.\n\n```typescript\nimport express, { type RequestHandler } from \"express\";\nimport bodyParser from \"body-parser\";\n\ntype CreateUserBody = {\n  email: string;\n  name: string;\n};\n\nfunction isCreateUserBody(value: unknown): value is CreateUserBody {\n  if (!value || typeof value !== \"object\") {\n    return false;\n  }\n\n  const body = value as Record<string, unknown>;\n\n  return typeof body.email === \"string\" && typeof body.name === \"string\";\n}\n\nconst app = express();\nconst jsonParser = bodyParser.json({\n  limit: \"1mb\",\n  strict: true,\n});\n\nconst createUser: RequestHandler<{}, {}, CreateUserBody> = (req, res) => {\n  if (!isCreateUserBody(req.body)) {\n    res.status(400).json({ error: \"invalid request body\" });\n    return;\n  }\n\n  res.status(201).json({\n    email: req.body.email,\n    name: req.body.name,\n  });\n};\n\napp.post(\"/users\", jsonParser, createUser);\n```\n\nThe generic type tells TypeScript what your route expects. It does not validate untrusted input at runtime, so keep a guard or validation step before using `req.body`.\n\n### Parse URL-Encoded Form Bodies\n\nUse `bodyParser.urlencoded()` for HTML forms and other `application/x-www-form-urlencoded` requests.\n\n```typescript\nimport express, { type RequestHandler } from \"express\";\nimport bodyParser from \"body-parser\";\n\ntype LoginForm = {\n  username?: string;\n  password?: string;\n};\n\nconst app = express();\nconst formParser = bodyParser.urlencoded({\n  extended: false,\n  limit: \"50kb\",\n  parameterLimit: 100,\n});\n\nconst login: RequestHandler<{}, {}, LoginForm> = (req, res) => {\n  if (typeof req.body.username !== \"string\" || typeof req.body.password !== \"string\") {\n    res.status(400).json({ error: \"username and password are required\" });\n    return;\n  }\n\n  res.json({ ok: true, username: req.body.username });\n};\n\napp.post(\"/login\", formParser, login);\n```\n\nThe declarations expose `extended` and `parameterLimit`, which are the main form-parsing options you will usually configure in TypeScript apps.\n\n### Model `text()` And `raw()` With Express Generics\n\nThe parser you choose determines the runtime shape of `req.body`. Reflect that in the `ReqBody` generic you give the handler.\n\n```typescript\nimport express, { type RequestHandler } from \"express\";\nimport bodyParser from \"body-parser\";\n\nconst app = express();\n\nconst textParser = bodyParser.text({\n  type: \"text/plain\",\n  limit: \"100kb\",\n});\n\nconst receiveText: RequestHandler<{}, {}, string> = (req, res) => {\n  res.json({ length: req.body.length });\n};\n\nconst rawParser = bodyParser.raw({\n  type: \"application/octet-stream\",\n  limit: \"10mb\",\n});\n\nconst receiveBinary: RequestHandler<{}, {}, Buffer> = (req, res) => {\n  res.json({ bytes: req.body.byteLength });\n};\n\napp.post(\"/plain-text\", textParser, receiveText);\napp.post(\"/upload\", rawParser, receiveBinary);\n```\n\nThis is the most important integration boundary for `@types/body-parser`: the middleware factory is typed here, but your handler decides the application-specific `req.body` shape.\n\n### Use `type` And `verify` When Content Negotiation Matters\n\nAll parser option types include `type`, `limit`, `inflate`, and `verify`.\n\n```typescript\nimport bodyParser from \"body-parser\";\n\nconst webhookJson = bodyParser.json({\n  type: [\"application/json\", \"application/*+json\"],\n  limit: \"256kb\",\n  verify: (req, _res, buf, encoding) => {\n    if (buf.length === 0) {\n      throw new Error(\"request body is required\");\n    }\n\n    console.log(req.headers[\"content-type\"], encoding);\n  },\n});\n```\n\nIn the published declaration file, `type` accepts a string, an array of strings, or a function that receives `http.IncomingMessage`. `verify` receives the raw `Buffer` and request encoding before parsing completes.\n\n## Important Pitfalls\n\n- Install `body-parser` as well as `@types/body-parser`; the declaration package contains no executable code.\n- Import from `body-parser`, never from `@types/body-parser`.\n- Prefer `bodyParser.json()`, `bodyParser.urlencoded()`, `bodyParser.text()`, or `bodyParser.raw()`; the top-level callable signature is marked deprecated in `@types/body-parser`.\n- Register the middleware before the routes that read `req.body`.\n- Treat `req.body` as untrusted input even when TypeScript says it has a specific shape.\n- Do not stack multiple body readers on the same request unless you know exactly which middleware reads the stream first; the runtime docs describe `stream.not.readable` as a common failure mode when the body was already consumed.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/body-parser==1.19.6`.\n- The published package depends on `@types/connect` and `@types/node`.\n- The published package metadata declares `typeScriptVersion: 5.1`.\n- The declaration package exposes `json`, `raw`, `text`, and `urlencoded` parser factories, plus a deprecated top-level callable signature.\n- The current `body-parser` runtime README documents additional options that are not present in `@types/body-parser@1.19.6`, including `defaultCharset` for `json`, plus `defaultCharset`, `charsetSentinel`, `interpretNumericEntities`, and `depth` for `urlencoded`. If you use those runtime options, you will need a local type assertion or declaration patch.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/body-parser\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/body-parser\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/body-parser/index.d.ts\n- https://www.npmjs.com/package/body-parser\n- https://github.com/expressjs/body-parser#readme\n"
  },
  {
    "path": "content/typescript/docs/chai/typescript/DOC.md",
    "content": "---\nname: chai\ndescription: \"TypeScript definitions for Chai's expect, assert, should, and plugin extension APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,chai,testing,assertions,types\"\n---\n\n# Chai TypeScript Guide\n\n`@types/chai` adds TypeScript declarations for the `chai` runtime package. Install it with `chai` when your tests or helper code import `expect`, `assert`, `should`, `use`, or other Chai APIs from `\"chai\"`.\n\nThis package only ships `.d.ts` files. It does not provide the runtime assertion library by itself.\n\n## Install\n\nInstall the runtime library and the type package together:\n\n```bash\nnpm install --save-dev chai @types/chai\n```\n\n`@types/chai` package metadata declares `typeScriptVersion: \"5.2\"`, so use TypeScript 5.2 or newer.\n\nNo environment variables, authentication, or client initialization are required.\n\n## TypeScript Setup\n\nIn a normal TypeScript project, installing `@types/chai` is enough. The package points TypeScript at `index.d.ts` automatically.\n\nOnly add `chai` to `compilerOptions.types` when your project already restricts loaded type packages:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"chai\", \"mocha\"]\n  }\n}\n```\n\nIf you do not restrict `compilerOptions.types`, you usually do not need this snippet.\n\n## Import The Main Assertion Styles\n\nUse named imports from `chai`:\n\n```ts\nimport { assert, expect, should } from \"chai\";\n\nexpect([1, 2, 3]).to.have.length(3);\nassert.strictEqual(2 + 2, 4);\n\nshould();\n(\"chai\" as string).should.be.a(\"string\");\n```\n\nThe type package exposes named exports such as `expect`, `assert`, `should`, `use`, `config`, `Assertion`, and `AssertionError`.\n\nDo not use a default import such as `import chai from \"chai\"`; these typings do not declare a default export.\n\n## Use `assert` For Type Narrowing\n\nSeveral `assert` signatures are useful at the TypeScript boundary because they use `asserts ...` return types.\n\nThe top-level `assert()` call narrows truthy values:\n\n```ts\nimport { assert } from \"chai\";\n\nfunction normalizeName(input: string | undefined) {\n  assert(input, \"name is required\");\n  return input.trim().toLowerCase();\n}\n```\n\nSpecialized helpers can narrow more precisely:\n\n```ts\nimport { assert } from \"chai\";\n\nfunction readPort(port: number | null | undefined, enabled: boolean | undefined) {\n  assert.exists(port, \"PORT is required\");\n  assert.isTrue(enabled, \"feature flag must be enabled\");\n\n  return port;\n}\n```\n\nThis is the main place where `@types/chai` affects application code beyond test ergonomics: the assertion signatures can improve type safety after runtime checks.\n\n## Use `should` Style\n\nFor `should` style, either call `should()` yourself or import the side-effect helper that augments `Object` globally.\n\n### Explicit setup\n\n```ts\nimport { should } from \"chai\";\n\nshould();\n\nconst result = { ok: true };\nresult.should.have.property(\"ok\", true);\n```\n\n### Bootstrap import\n\n```ts\nimport \"chai/register-should\";\n\nconst values = [1, 2, 3];\nvalues.should.have.length(3);\n```\n\nUse `should` carefully in shared code: it modifies `Object.prototype`, which is convenient in tests but broader in effect than `expect` or `assert` imports.\n\n## Type A Custom Chai Plugin\n\nThe declarations expose the global `Chai` namespace and the `Chai.ChaiPlugin` type, which is the extension point for custom plugins.\n\n```ts\nimport { expect, use } from \"chai\";\n\ndeclare global {\n  namespace Chai {\n    interface Assertion {\n      even: Assertion;\n    }\n  }\n}\n\nconst evenPlugin: Chai.ChaiPlugin = (chai) => {\n  chai.Assertion.addProperty(\"even\", function (this: Chai.AssertionStatic) {\n    const value = this._obj as number;\n\n    this.assert(\n      value % 2 === 0,\n      \"expected #{this} to be even\",\n      \"expected #{this} not to be even\",\n    );\n  });\n};\n\nuse(evenPlugin);\n\nexpect(4).to.be.even;\n```\n\nThis pattern matters when you maintain local test helpers or a reusable plugin package: extend `Chai.Assertion` with declaration merging, then register the plugin with `use()`.\n\n## Common Pitfalls\n\n- Install `chai` as well as `@types/chai`; the type package does not contain runtime JavaScript.\n- Prefer named imports from `chai`; these typings do not declare a default export.\n- If your `tsconfig.json` uses `compilerOptions.types`, include `chai` there or the declarations will not load.\n- `@types/chai` includes `register-should.d.ts`, but it does not ship matching declaration files for `chai/register-assert` or `chai/register-expect`. For `assert` and `expect`, prefer direct named imports from `chai`.\n- `should` style mutates `Object.prototype`; use it intentionally, especially in larger test suites.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/chai\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/chai\n- https://www.npmjs.com/package/chai\n- http://chaijs.com/guide/styles/\n"
  },
  {
    "path": "content/typescript/docs/chalk/typescript/DOC.md",
    "content": "---\nname: chalk\ndescription: \"TypeScript declarations for Chalk's CommonJS terminal styling API\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.2.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,chalk,terminal,cli,ansi,types\"\n---\n\n# Chalk TypeScript Guide\n\n`@types/chalk` adds TypeScript declarations for the `chalk` runtime package so TypeScript can understand Chalk's chainable color and style APIs.\n\nThis package only ships `.d.ts` files. It does not provide the Chalk runtime itself.\n\n## Install\n\nInstall Chalk and the matching type package together:\n\n```bash\nnpm install chalk\nnpm install --save-dev @types/chalk@2.2.4\n```\n\nIf you are maintaining an older Chalk 2.x codebase, keeping the runtime and declaration majors aligned avoids the most common type mismatches.\n\nNo authentication, environment variables, or client initialization are required to use the type package.\n\n## TypeScript Setup\n\nIn a normal TypeScript project, installing `@types/chalk` is enough.\n\nOnly add `chalk` to `compilerOptions.types` if your project already restricts which declaration packages TypeScript loads:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"chalk\"]\n  }\n}\n```\n\nIf you do not restrict `compilerOptions.types`, you usually do not need this snippet.\n\n## Import Chalk Correctly\n\nThese declarations model Chalk as a CommonJS `export =` module.\n\nUse `import = require()` when you want the import form that matches the declarations directly:\n\n```ts\nimport chalk = require(\"chalk\");\n\nconsole.log(chalk.green(\"ready\"));\nconsole.log(chalk.bold.red(\"failed\"));\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport chalk from \"chalk\";\n\nconsole.log(chalk.blue(\"hello\"));\n```\n\nDo not import from `\"@types/chalk\"` in application code.\n\n## Style Text With Chainable APIs\n\nThe declarations type Chalk's fluent style builder, so chained modifiers and color functions stay available as you compose output.\n\n```ts\nimport chalk = require(\"chalk\");\n\nconst title = chalk.bold.underline(\"Project Atlas\");\nconst ok = chalk.green(\"ok\");\nconst warning = chalk.bgYellow.black(\" warning \");\nconst error = chalk.redBright.bold(\"error\");\n\nconsole.log(title);\nconsole.log(ok, warning, error);\n```\n\nOrder does not matter for compatible chained styles, and later conflicting color choices take precedence.\n\n## Use RGB, Hex, And Background Helpers\n\nThe package also types Chalk's color helper methods for 24-bit and palette-based formatting:\n\n```ts\nimport chalk = require(\"chalk\");\n\nconst accent = chalk.hex(\"#2563eb\")(\"info\");\nconst badge = chalk.bgHex(\"#1f2937\").white(\" build \");\nconst metric = chalk.rgb(255, 131, 0)(\"73%\");\n\nconsole.log(accent, badge, metric);\n```\n\nUse these helpers when fixed named colors are not enough for your CLI or log output.\n\n## Reuse Styled Formatters\n\nBecause styled chains are callable, a common pattern is to build a formatter once and reuse it across your app.\n\n```ts\nimport chalk = require(\"chalk\");\n\nconst info = chalk.cyan;\nconst success = chalk.green.bold;\nconst failure = chalk.white.bgRed.bold;\n\nexport function logResult(name: string, passed: boolean) {\n  if (passed) {\n    console.log(success(\"PASS\"), info(name));\n    return;\n  }\n\n  console.error(failure(\"FAIL\"), info(name));\n}\n```\n\nThis keeps formatting consistent without losing type information.\n\n## Use Chalk As A Tagged Template\n\nChalk can also format tagged template literals:\n\n```ts\nimport chalk = require(\"chalk\");\n\nconst percent = 82;\n\nconsole.log(chalk`CPU: {green ${percent}%}`);\nconsole.log(chalk.red.bgBlack`status: {bold degraded}`);\n```\n\nThis is convenient when a single log line mixes plain text and multiple styles.\n\n## Control Color Output Deliberately\n\nAt runtime, Chalk detects terminal color support automatically. You can still branch on support in application code:\n\n```ts\nimport chalk = require(\"chalk\");\n\nif (chalk.supportsColor) {\n  console.log(chalk.green(\"color output enabled\"));\n} else {\n  console.log(\"color output disabled\");\n}\n```\n\nFor command-line runs, `FORCE_COLOR` is the main environment override:\n\n```bash\nFORCE_COLOR=0 node dist/cli.js\nFORCE_COLOR=3 node dist/cli.js\n```\n\nThis affects Chalk's runtime behavior; `@types/chalk` only provides the TypeScript declarations.\n\n## Common Pitfalls\n\n- Install `chalk` as well as `@types/chalk`; the type package does not contain runtime JavaScript.\n- Import from `\"chalk\"`, not from `\"@types/chalk\"`.\n- If your `tsconfig.json` uses `compilerOptions.types`, include `chalk` there or the declarations will not load.\n- These declarations use CommonJS `export =` semantics, so `import { red } from \"chalk\"` is not the right import form.\n- Newer Chalk releases ship their own declarations. If your installed `chalk` package already includes a `types` entry, you usually should not install `@types/chalk` alongside it.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/chalk\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/chalk\n- https://www.npmjs.com/package/chalk\n- https://github.com/chalk/chalk\n"
  },
  {
    "path": "content/typescript/docs/cheerio/typescript/DOC.md",
    "content": "---\nname: cheerio\ndescription: \"TypeScript guidance for using Cheerio in typed Node.js projects, including the runtime package's built-in declarations.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,cheerio,html,xml,scraping,dom,types\"\n---\n\n# Cheerio TypeScript Guide\n\n## Golden Rule\n\nInstall and import the runtime package `cheerio`.\n\nFor TypeScript code, the practical integration boundary is still `\"cheerio\"`, not `\"@types/cheerio\"`. Current Cheerio releases publish declaration files through the package `types` field and `exports` map, so your application code imports runtime functions and type-only helpers from the runtime package.\n\n`@types/cheerio` does not provide the parser or DOM traversal runtime by itself.\n\n## Install\n\nFor a normal Node.js TypeScript project:\n\n```bash\nnpm install cheerio\nnpm install -D typescript @types/node\n```\n\nIf TypeScript is already present, add only the missing packages.\n\n`cheerio`'s declarations reference Node types such as `Buffer` and `node:stream`, so `@types/node` is the practical companion package for most TypeScript setups.\n\nThere are no environment variables, credentials, or client initialization steps.\n\n## TypeScript Setup\n\nUse a standard Node-oriented compiler setup:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true\n  }\n}\n```\n\nIf your project restricts ambient type packages with `compilerOptions.types`, include `node` so `Buffer` and other Node globals stay available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\nImport from `\"cheerio\"`, not from `\"@types/cheerio\"`:\n\n```ts\nimport * as cheerio from \"cheerio\";\nimport type { CheerioAPI, CheerioOptions } from \"cheerio\";\n```\n\nUse a namespace import or named exports. Do not rely on a default import unless your toolchain explicitly synthesizes one.\n\n## Common Workflows\n\n### Load HTML and query the document\n\n`cheerio.load()` returns the document-bound query function that you use for traversal and extraction.\n\n```ts\nimport * as cheerio from \"cheerio\";\n\nconst html = `\n  <article>\n    <h1 class=\"title\">Project Atlas</h1>\n    <a href=\"/docs\">Docs</a>\n  </article>\n`;\n\nconst $ = cheerio.load(html);\n\nconst title = $(\"h1.title\").text().trim();\nconst href = $(\"a\").attr(\"href\");\n\nconsole.log({ title, href });\n```\n\n### Reuse `CheerioOptions` and `CheerioAPI` in helpers\n\nUse the exported types when you wrap document loading in shared utilities.\n\n```ts\nimport * as cheerio from \"cheerio\";\nimport type { CheerioAPI, CheerioOptions } from \"cheerio\";\n\nconst defaultOptions: CheerioOptions = {\n  baseURI: \"https://example.com/\",\n};\n\nexport function loadDocument(\n  markup: string,\n  options: CheerioOptions = defaultOptions,\n): CheerioAPI {\n  return cheerio.load(markup, options);\n}\n\nconst $ = loadDocument(`<a href=\"/guide\">Guide</a>`);\nconst url = $(\"a\").prop(\"href\");\n\nconsole.log(url);\n```\n\n`baseURI` matters when you read resolved properties such as `href` and `src`.\n\n### Parse XML explicitly\n\nWhen you need XML parsing behavior, set the `xml` option.\n\n```ts\nimport * as cheerio from \"cheerio\";\n\nconst xml = `\n  <feed>\n    <item id=\"1\">First</item>\n  </feed>\n`;\n\nconst $ = cheerio.load(xml, {\n  xml: true,\n});\n\nconst firstItem = $(\"item\").text();\n\nconsole.log(firstItem);\n```\n\nPrefer `xml` over `xmlMode`; the declarations mark `xmlMode` as deprecated.\n\n### Convert a selection into a typed array result\n\nUse Cheerio traversal methods for selection, then call `.get()` when you want a normal JavaScript array.\n\n```ts\nimport * as cheerio from \"cheerio\";\n\nconst $ = cheerio.load(`\n  <ul>\n    <li data-id=\"a\">Alpha</li>\n    <li data-id=\"b\">Beta</li>\n  </ul>\n`);\n\nconst items = $(\"li\")\n  .map((_, element) => ({\n    id: $(element).attr(\"data-id\") ?? \"\",\n    label: $(element).text().trim(),\n  }))\n  .get();\n\nconsole.log(items);\n```\n\nThis is the simplest way to move from a Cheerio collection to a normal array that the rest of your TypeScript code can consume.\n\n## Common Pitfalls\n\n- Install `cheerio`; `@types/cheerio` does not provide the runtime JavaScript.\n- Import from `cheerio`, not from `@types/cheerio`.\n- If your `tsconfig.json` uses `compilerOptions.types`, include `node` or Cheerio's Node-related types can appear to be missing.\n- Prefer `xml` over `xmlMode` for XML configuration.\n- Avoid a default import such as `import cheerio from \"cheerio\"` unless your compiler or bundler is configured to synthesize default imports.\n- Do not add a custom `declare module \"cheerio\"` shim in current projects; the runtime package already ships its own declarations.\n\n## Version Notes\n\nThe important version boundary for TypeScript users is that the runtime package now publishes its own `.d.ts` files. In current projects, manage the runtime dependency as `cheerio` and keep your imports and type references on that package.\n\nIf a starter template or older lockfile still mentions `@types/cheerio`, verify whether your project already compiles with `cheerio` alone before keeping the extra type-package dependency.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/cheerio\n- https://www.npmjs.com/package/cheerio\n- https://cheerio.js.org/\n- https://github.com/cheeriojs/cheerio\n"
  },
  {
    "path": "content/typescript/docs/classnames/typescript/DOC.md",
    "content": "---\nname: classnames\ndescription: \"TypeScript setup for `classnames`. `@types/classnames@2.3.4` is a stub package, so install `classnames` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.3.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,classnames,css,react,types,definitelytyped,npm\"\n---\n\n# classnames TypeScript Guide\n\n## Golden Rule\n\n`@types/classnames@2.3.4` is a stub package.\n\nThe npm package page for `@types/classnames` says that `classnames` provides its own type definitions. For current projects, install `classnames`, import from `\"classnames\"` or `\"classnames/bind\"`, and remove `@types/classnames` if you added it directly.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install classnames\nnpm install -D typescript\n```\n\nIf your project already depends on the old stub package directly, remove it:\n\n```bash\nnpm uninstall @types/classnames\n```\n\nIf this is a React project, keep React and React's type packages installed separately. `classnames` only builds class name strings.\n\n```bash\nnpm install react react-dom\nnpm install -D @types/react @types/react-dom\n```\n\n## Initialization\n\nThere are no package-specific environment variables, auth steps, or client objects.\n\nThe important setup point is importing the runtime package directly so TypeScript reads the declarations bundled with `classnames`.\n\n### Import from `classnames`\n\nIf your project uses `esModuleInterop` or a bundler setup that supports default imports from CommonJS packages, use:\n\n```typescript\nimport classNames from \"classnames\";\n```\n\nIf you want the configuration-independent TypeScript import for a CommonJS export, use:\n\n```typescript\nimport classNames = require(\"classnames\");\n```\n\nDo not import from `@types/classnames`.\n\n### Default-import TypeScript config\n\nIf you prefer `import classNames from \"classnames\"`, enable `esModuleInterop` or `allowSyntheticDefaultImports`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, you do not need to list `classnames` there. Its declarations come from the imported runtime package.\n\n## Common Workflows\n\n### Build conditional class strings\n\nPass strings, object maps, arrays, and optional values to a single `classNames()` call.\n\n```typescript\nimport classNames from \"classnames\";\n\ntype ButtonClassNameOptions = {\n  intent: \"primary\" | \"secondary\";\n  disabled?: boolean;\n  loading?: boolean;\n  className?: string;\n};\n\nexport function getButtonClassName({\n  intent,\n  disabled = false,\n  loading = false,\n  className,\n}: ButtonClassNameOptions): string {\n  return classNames(\n    \"button\",\n    `button-${intent}`,\n    {\n      \"is-disabled\": disabled,\n      \"is-loading\": loading,\n    },\n    className,\n  );\n}\n```\n\nObject keys are included only when their values are truthy. Standalone falsy arguments are ignored.\n\n### Combine arrays and nested values\n\n`classnames` accepts arrays, including nested arrays, so you can compose reusable class fragments.\n\n```typescript\nimport classNames from \"classnames\";\n\nconst sharedAlertClasses = [\"is-interactive\", \"has-outline\"];\n\nexport function getAlertClassName(compact: boolean, tone: \"info\" | \"error\"): string {\n  return classNames(\n    \"alert\",\n    sharedAlertClasses,\n    [compact && \"alert-compact\"],\n    {\n      \"alert-info\": tone === \"info\",\n      \"alert-error\": tone === \"error\",\n    },\n  );\n}\n```\n\nThis is the practical boundary with application code: `classnames` always returns a plain `string`, ready to pass into a `className` prop or template.\n\n### Merge a component's own classes with an incoming `className`\n\nThis is the most common integration pattern in React components.\n\n```tsx\nimport classNames from \"classnames\";\nimport type { ReactNode } from \"react\";\n\ntype BadgeProps = {\n  tone: \"neutral\" | \"success\" | \"warning\";\n  className?: string;\n  children: ReactNode;\n};\n\nexport function Badge({ tone, className, children }: BadgeProps) {\n  return (\n    <span\n      className={classNames(\"badge\", `badge-${tone}`, className)}\n    >\n      {children}\n    </span>\n  );\n}\n```\n\nKeeping `className?: string` at the component boundary works well because `classnames` already handles missing or falsy values cleanly.\n\n### Use `classnames/bind` with CSS Modules\n\nThe package documents a separate `bind` build for CSS Modules-style lookups.\n\n```typescript\nimport classNames from \"classnames/bind\";\nimport styles from \"./Button.module.css\";\n\nconst cx = classNames.bind(styles);\n\ntype ButtonStyleOptions = {\n  pressed?: boolean;\n  disabled?: boolean;\n};\n\nexport function getModuleButtonClassName({\n  pressed = false,\n  disabled = false,\n}: ButtonStyleOptions): string {\n  return cx(\"root\", {\n    pressed,\n    disabled,\n  });\n}\n```\n\nWith `bind`, the object keys are the local CSS Module keys, and the returned string contains the mapped class names from `styles`.\n\n## Important Pitfalls\n\n- `@types/classnames` does not replace the `classnames` runtime package.\n- Do not import from `@types/classnames`; import from `classnames` or `classnames/bind`.\n- Standalone falsy values such as `false`, `null`, `undefined`, `0`, and `\"\"` are ignored. If `\"0\"` needs to be a class token, pass it as a string.\n- If a default import fails under your TypeScript config, switch to `import classNames = require(\"classnames\")` or enable `esModuleInterop`.\n- `classnames` returns a plain `string`. It does not validate whether a class actually exists in your CSS.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/classnames` package entry at version `2.3.4`.\n- For this version, the npm package entry is a stub package that points TypeScript users to `classnames`.\n- For new work, the relevant package is `classnames`, because it provides both the runtime behavior and the bundled TypeScript declarations.\n\n## Official Sources\n\n- npm package page for `@types/classnames`: https://www.npmjs.com/package/@types/classnames\n- DefinitelyTyped source for `@types/classnames`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/classnames\n- npm package page for `classnames`: https://www.npmjs.com/package/classnames\n- `classnames` README and API reference: https://github.com/JedWatson/classnames/blob/master/README.md\n"
  },
  {
    "path": "content/typescript/docs/clean-css/typescript/DOC.md",
    "content": "---\nname: clean-css\ndescription: \"TypeScript declarations for the CommonJS `clean-css` CSS minifier. Install the runtime package too, import from `clean-css`, and use the typed constructor and `minify()` results for CSS strings, file inputs, and source-map workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.2.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,clean-css,css,minification,types,definitelytyped,npm\"\n---\n\n# clean-css TypeScript Guide\n\n## Golden Rule\n\nInstall `clean-css` and `@types/clean-css`, but import and execute the runtime package from `\"clean-css\"`.\n\n`@types/clean-css` only provides TypeScript declarations. The runtime entry point is CommonJS (`module.exports = require('./lib/clean')`), so the safest TypeScript import form is `import CleanCSS = require(\"clean-css\");`.\n\n## Install\n\nInstall the runtime package first, then the declaration package:\n\n```bash\nnpm install clean-css\nnpm install -D typescript @types/clean-css\n```\n\nNo package-specific environment variables, credentials, or authentication steps are required.\n\nIf your project already uses Node.js globals or built-in modules elsewhere, keep your usual `@types/node` setup. You do not need to add `clean-css` to `compilerOptions.types`.\n\n## Initialization\n\nA minimal strict `tsconfig.json` for Node-based build scripts works well:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"Node16\",\n    \"moduleResolution\": \"Node16\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nThis keeps the `import = require()` form working without turning on `esModuleInterop`.\n\n### Create a typed minifier\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst minifier = new CleanCSS({\n  level: 1,\n});\n\nconst output = minifier.minify(`\n  a {\n    color: blue;\n  }\n  div {\n    margin: 5px;\n  }\n`);\n\nconsole.log(output.styles);\nconsole.log(output.errors);\nconsole.log(output.warnings);\nconsole.log(output.stats.originalSize);\nconsole.log(output.stats.minifiedSize);\n```\n\nThe main typed integration boundary is the constructor options object and the `minify()` result, which exposes `styles`, `errors`, `warnings`, `inlinedStylesheets`, and `stats`.\n\n## Common Workflows\n\n### Format CSS instead of fully minifying it\n\nThe README documents `format: \"beautify\"` and `format: \"keep-breaks\"`. Use `level: 0` when you want formatting, import inlining, or URL rebasing without optimization passes.\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst source = `\n  .card {\n    padding: 16px;\n    color: rgb(0, 0, 255);\n  }\n`;\n\nconst output = new CleanCSS({\n  format: \"beautify\",\n  level: 0,\n}).minify(source);\n\nconsole.log(output.styles);\n```\n\n### Use fine-grained optimization settings\n\nThe `level` option can be `0`, `1`, `2`, or a nested configuration object.\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst output = new CleanCSS({\n  level: {\n    1: {\n      specialComments: 0,\n      tidySelectors: true,\n    },\n    2: {\n      mergeAdjacentRules: true,\n      removeDuplicateFontRules: true,\n    },\n  },\n}).minify(`\n  .button {\n    margin: 0px 0px 0px 0px;\n  }\n  .button {\n    color: #0000ff;\n  }\n`);\n\nconsole.log(output.styles);\n```\n\nUse this shape when you want type-checked control over a few optimizations instead of relying on the default presets.\n\n### Minify a CSS file by path\n\n`minify()` can read files directly when you pass an array of file paths.\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst output = new CleanCSS({\n  rebaseTo: \"dist\",\n}).minify([\"src/styles/app.css\"]);\n\nconsole.log(output.styles);\nconsole.log(output.inlinedStylesheets);\nconsole.log(output.warnings);\n```\n\nSet `rebaseTo` to the directory where the optimized file will live when your stylesheet contains relative URLs.\n\n### Generate a source map\n\nEnable `sourceMap: true` and use the callback form when you want `output.sourceMap`.\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst source = `\n  .hero {\n    background-image: url(\"../images/hero.png\");\n  }\n`;\n\nnew CleanCSS({\n  sourceMap: true,\n  rebaseTo: \"dist\",\n}).minify(source, (error, output) => {\n  if (error) {\n    console.error(error);\n    return;\n  }\n\n  console.log(output.styles);\n  console.log(output.sourceMap && output.sourceMap.toString());\n});\n```\n\nThe runtime README documents `output.sourceMap` as a `SourceMapGenerator` object when source maps are enabled.\n\n### Inline remote `@import` rules\n\nRemote `@import` inlining is asynchronous. Pass a callback when `inline` includes remote URLs.\n\n```typescript\nimport CleanCSS = require(\"clean-css\");\n\nconst source = '@import url(\"https://example.com/base.css\");';\n\nnew CleanCSS({\n  inline: [\"remote\"],\n}).minify(source, (error, output) => {\n  if (error) {\n    console.error(error);\n    return;\n  }\n\n  console.log(output.styles);\n});\n```\n\nIf you do not provide a callback, remote `@import` rules are left as-is.\n\n## Important Pitfalls\n\n- Install `clean-css` itself. `@types/clean-css` is declarations only.\n- Import from `\"clean-css\"`, not from `\"@types/clean-css\"`.\n- The runtime export is CommonJS, so `import CleanCSS = require(\"clean-css\")` is the most predictable TypeScript import form.\n- `minify()` can return warnings and still produce valid `styles`; always inspect both `output.errors` and `output.warnings` when minifying user or generated CSS.\n- If you set `rebase: true` without also setting `rebaseTo`, the runtime adds a warning because URL rebasing then defaults to the current working directory.\n- Remote `@import` processing requires the callback form of `minify()`.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/clean-css==4.2.11`.\n- The `clean-css` README documents these 4.2 additions: `CleanCSS.process()` compatibility for `optimize-css-assets-webpack-plugin`, `/* clean-css ignore:start */` and `/* clean-css ignore:end */` preservation, selector-aware `transform` filtering, and `format: { breakWith: \"lf\" }`.\n- The same upstream README also documents later 5.x changes, including additional features and changed defaults. Verify your installed `clean-css` runtime version before relying on 5.x-only behavior in a project pinned to these 4.2.11 declarations.\n- Optimization level `1` is the documented default, and turning on level `2` applies level `1` optimizations as well unless you disable them explicitly in the nested config.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/clean-css\n- https://www.npmjs.com/package/clean-css\n- https://github.com/clean-css/clean-css\n- https://github.com/clean-css/clean-css/blob/master/README.md\n- https://github.com/clean-css/clean-css/blob/master/lib/clean.js\n"
  },
  {
    "path": "content/typescript/docs/color/typescript/DOC.md",
    "content": "---\nname: color\ndescription: \"TypeScript declarations for the `color` CommonJS API for parsing, converting, and manipulating CSS colors.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,color,css,colors,conversion,accessibility,types,definitelytyped,npm\"\n---\n\n# color TypeScript Guide\n\n`@types/color` adds TypeScript declarations for the `color` runtime package.\n\nInstall the runtime package separately. Application code imports from `\"color\"`, not from `\"@types/color\"`.\n\n## Install\n\nInstall `color`, TypeScript, and the declaration package together:\n\n```bash\nnpm install color\nnpm install -D typescript @types/color@4.2.0\n```\n\nThe `color` runtime package metadata for the current 4.x line declares `node >= 12.5.0`.\n\nThere are no package-specific environment variables, auth steps, or client objects.\n\n## Import The Runtime Package\n\nThe maintainer README documents `color` as a CommonJS package:\n\n```js\nconst Color = require(\"color\");\n```\n\nFor TypeScript, the safest import is the matching CommonJS form:\n\n```ts\nimport Color = require(\"color\");\n```\n\nDo not import from `@types/color` in application code.\n\n## Create Color Values\n\nThe package accepts CSS color strings, channel objects, and static constructors such as `Color.rgb()`:\n\n```ts\nimport Color = require(\"color\");\n\nconst fromCss = Color(\"#7743CE\");\nconst fromRgbObject = Color({ r: 255, g: 255, b: 255 });\nconst fromStaticRgb = Color.rgb(255, 255, 255);\nconst fromStaticRgbArray = Color.rgb([255, 255, 255]);\n```\n\nString parsing is handled by `color-string`, so CSS-style inputs such as hex, `rgb(...)`, and named colors are accepted when the runtime can parse them.\n\n## Convert And Serialize Colors\n\nUse conversion helpers such as `.rgb()`, `.hsl()`, or `.cmyk()`, then serialize with `.string()`, `.array()`, `.object()`, `.hex()`, or `.hexa()`.\n\n```ts\nimport Color = require(\"color\");\n\nconst accent = Color(\"#7743CE\").alpha(0.5);\n\nconst hslCss = accent.hsl().string();\nconst rgbArray = accent.rgb().array();\nconst rgbObject = accent.rgb().object();\nconst cmykRounded = accent.cmyk().round().array();\nconst hex = accent.hex();\nconst hexWithAlpha = accent.hexa();\nconst rgbNumber = accent.rgbNumber();\n\nconsole.log({ hslCss, rgbArray, rgbObject, cmykRounded, hex, hexWithAlpha, rgbNumber });\n```\n\nUse `.hex()` when you only need RGB output. Use `.hexa()` or `.string()` when the alpha channel must be preserved.\n\n## Manipulate Colors Immutably\n\nThe runtime is documented as immutable. Each manipulation returns a new color value instead of mutating the existing one.\n\n```ts\nimport Color = require(\"color\");\n\nconst base = Color(\"rgb(32, 99, 244)\");\n\nconst lighter = base.lighten(0.2);\nconst darker = base.darken(0.2);\nconst lessSaturated = base.desaturate(0.3);\nconst rotated = base.rotate(180);\nconst blended = base.mix(Color(\"yellow\"), 0.3);\n\nconsole.log(base.hex());\nconsole.log(lighter.hex());\nconsole.log(darker.hex());\nconsole.log(lessSaturated.hex());\nconsole.log(rotated.hex());\nconsole.log(blended.hex());\n```\n\nKeep the returned value when chaining operations:\n\n```ts\nimport Color = require(\"color\");\n\nconst badge = Color(\"#2563eb\")\n  .alpha(0.85)\n  .lighten(0.1)\n  .rotate(-10);\n\nconsole.log(badge.hsl().string());\n```\n\n## Read And Update Individual Channels\n\nChannel helpers act as getters when you call them without an argument and setters when you pass a value.\n\n```ts\nimport Color = require(\"color\");\n\nconst base = Color(\"#2563eb\");\n\nconst redChannel = base.red();\nconst transparent = base.alpha(0.7);\nconst greener = base.green(140);\n\nconsole.log(redChannel);\nconsole.log(transparent.rgb().string());\nconsole.log(greener.rgb().string());\n```\n\n## Check Contrast And Brightness\n\n`color` includes helpers for brightness checks and WCAG-style contrast math.\n\n```ts\nimport Color = require(\"color\");\n\nconst background = Color(\"white\");\nconst foreground = Color(\"#1f2937\");\n\nconst contrast = foreground.contrast(background);\nconst foregroundLuminosity = foreground.luminosity();\nconst useDarkText = background.isLight();\n\nconsole.log({ contrast, foregroundLuminosity, useDarkText });\n```\n\nThese helpers are useful when you need to choose text colors or verify theme combinations before rendering them.\n\n## Important Pitfalls\n\n- Install `color` separately. `@types/color` only provides declarations.\n- Import from `\"color\"`, never from `\"@types/color\"`.\n- The documented module form is CommonJS `require(\"color\")`, so `import Color = require(\"color\")` is the least surprising TypeScript import.\n- Color operations return new values. Reassign or capture the result of `.alpha()`, `.lighten()`, `.mix()`, and similar methods.\n- `.hex()` drops alpha information. Use `.hexa()` or `.string()` when transparency matters.\n- `.mix()` expects another `Color(...)` value, not a plain string or raw object.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/color==4.2.0`.\n- The examples follow the `color` 4.x API documented by the maintainer README and package metadata.\n- If your project is pinned to an older or patched `color` runtime, verify that the installed declaration package still matches the methods you call.\n\n## Official Sources\n\n- npm package page for `@types/color`: https://www.npmjs.com/package/@types/color\n- DefinitelyTyped source for `@types/color`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/color\n- `@types/color` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/color/index.d.ts\n- npm package page for `color`: https://www.npmjs.com/package/color\n- `color` source repository: https://github.com/Qix-/color\n"
  },
  {
    "path": "content/typescript/docs/color-convert/typescript/DOC.md",
    "content": "---\nname: color-convert\ndescription: \"TypeScript declarations for the `color-convert` CommonJS API for converting between RGB, HSL, HSV, HWB, CMYK, hex, ANSI, keywords, and related color models.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,color,color-convert,conversion,colors,commonjs,definitelytyped,npm\"\n---\n\n# color-convert TypeScript Guide\n\n`@types/color-convert` adds TypeScript declarations for the `color-convert` runtime package.\n\nInstall the runtime package separately. Application code imports from `\"color-convert\"`, not from `\"@types/color-convert\"`.\n\nThis guide covers the 2.x CommonJS API surface used by `color-convert` and typed by `@types/color-convert@2.0.4`.\n\n## Install\n\nInstall the runtime package, TypeScript, and the declaration package together:\n\n```bash\nnpm install color-convert\nnpm install -D typescript @types/color-convert@2.0.4\n```\n\nIf your project already uses TypeScript, add only the missing declarations:\n\n```bash\nnpm install -D @types/color-convert@2.0.4\n```\n\nThe `color-convert` 2.x package metadata declares `node >= 7.0.0`.\n\nThere are no package-specific environment variables, auth steps, or client objects to initialize.\n\n## Import The Runtime Package\n\nThe maintainer README documents `color-convert` as a CommonJS package:\n\n```js\nvar convert = require(\"color-convert\");\n```\n\nIn TypeScript, the matching import form is the safest default:\n\n```ts\nimport convert = require(\"color-convert\");\n```\n\nUse that form unless your project already has a deliberate CommonJS/ESM interop setup.\n\n## Common Workflows\n\n### Convert between common color models\n\nRead the API as `convert.<fromModel>.<toModel>(...)`.\n\n```ts\nimport convert = require(\"color-convert\");\n\nconst rgbToHsl = convert.rgb.hsl(140, 200, 100);\nconst keywordToRgb = convert.keyword.rgb(\"blue\");\nconst hexToLab = convert.hex.lab(\"DEADBF\");\nconst rgbToCmyk = convert.rgb.cmyk(167, 255, 4);\n\nconsole.log({ rgbToHsl, keywordToRgb, hexToLab, rgbToCmyk });\n```\n\nThe runtime supports conversions across `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `xyz`, `lab`, `lch`, `hex`, `keyword`, `ansi16`, `ansi256`, `hcg`, `apple`, and `gray`.\n\n### Get unrounded values with `.raw`\n\nRounded results are the default. Add `.raw` when you need the unrounded channel values.\n\n```ts\nimport convert = require(\"color-convert\");\n\nconst roundedLab = convert.hex.lab(\"DEADBF\");\nconst rawLab = convert.hex.lab.raw(\"DEADBF\");\n\nconst roundedCmyk = convert.rgb.cmyk(167, 255, 4);\nconst rawCmyk = convert.rgb.cmyk.raw(167, 255, 4);\n\nconsole.log({ roundedLab, rawLab, roundedCmyk, rawCmyk });\n```\n\nUse `.raw` when you need the full float output for later calculations instead of presentation-ready rounded values.\n\n### Pass arrays for multi-channel inputs\n\nConversions that normally take multiple channel arguments also accept an array.\n\n```ts\nimport convert = require(\"color-convert\");\n\nconst rgb: [number, number, number] = [123, 45, 67];\n\nconst hex = convert.rgb.hex(rgb);\nconst hsl = convert.rgb.hsl(rgb);\n\nconsole.log({ hex, hsl });\n```\n\nThis array shortcut does not apply to one-value source models such as `hex`, `keyword`, or `ansi256`.\n\n### Inspect expected channel counts\n\nEach source model exposes a `.channels` property so you can build validators or generic wrappers around the runtime API.\n\n```ts\nimport convert = require(\"color-convert\");\n\nconsole.log(convert.rgb.channels);     // 3\nconsole.log(convert.cmyk.channels);    // 4\nconsole.log(convert.ansi16.channels);  // 1\n```\n\nThis is useful when your app accepts dynamic model names from configuration or user input.\n\n### Add your own typed boundary around conversions\n\nThe runtime works with numbers and arrays. In application code, define tuple-shaped inputs at your own boundary and pass them through the library.\n\n```ts\nimport convert = require(\"color-convert\");\n\ntype RGB = [red: number, green: number, blue: number];\n\nexport function rgbToHex(rgb: RGB) {\n  return convert.rgb.hex(rgb);\n}\n\nexport function rgbToHslObject(rgb: RGB) {\n  const [hue, saturation, lightness] = convert.rgb.hsl(rgb);\n\n  return { hue, saturation, lightness };\n}\n```\n\nThis keeps the rest of your codebase explicit about what each numeric position means without changing how `color-convert` itself works.\n\n## Important Pitfalls\n\n- Install `color-convert` as well as `@types/color-convert`; the type package does not ship runtime code.\n- Import from `\"color-convert\"`, not from `\"@types/color-convert\"`.\n- The documented runtime API is CommonJS. In TypeScript, `import convert = require(\"color-convert\")` is the least surprising option.\n- Default conversion methods round numeric array results; use `.raw` when precision matters.\n- Array arguments work for multi-channel source models only. Single-value inputs such as `hex`, `keyword`, and `ansi256` should stay single values.\n- Some conversions are routed through intermediate color models when there is no direct implementation, which can introduce precision loss.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/color-convert\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/color-convert\n- https://www.npmjs.com/package/color-convert\n- https://github.com/Qix-/color-convert\n"
  },
  {
    "path": "content/typescript/docs/color-name/typescript/DOC.md",
    "content": "---\nname: color-name\ndescription: \"TypeScript declarations for the `color-name` package, which exports CSS named colors as RGB tuples.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,color-name,css,colors,types,definitelytyped\"\n---\n\n# Color Name TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/color-name` for compile-time declarations only.\n\nYour application code reads from the `color-name` runtime package, which exports a single object whose keys are CSS color keywords and whose values are RGB arrays such as `red: [255, 0, 0]`.\n\n`@types/color-name` adds TypeScript coverage for that module. It does not install the runtime package.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install color-name\nnpm install -D typescript @types/color-name\n```\n\nIf TypeScript is already present in your project, add just the missing declarations:\n\n```bash\nnpm install -D @types/color-name\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to initialize.\n\nThe `color-name` package is a plain data module. The runtime package uses CommonJS and exports the color table directly.\n\n## Common Workflows\n\n### Import the color table and read RGB values\n\nThe package API is a single object. Read named colors from that object and destructure the RGB tuple when needed.\n\n```typescript\nimport colorName = require(\"color-name\");\n\nconst tomato = colorName.tomato;\nconst [red, green, blue] = colorName.rebeccapurple;\n\nconsole.log(tomato); // [255, 99, 71]\nconsole.log({ red, green, blue });\n```\n\nThis mirrors the runtime package's documented usage, which is a direct module import followed by property access such as `colors.red`.\n\n### Restrict your API to supported color names\n\nWhen you accept a named color from the rest of your app, derive the allowed names from the imported module instead of maintaining your own string union.\n\n```typescript\nimport colorName = require(\"color-name\");\n\ntype NamedColor = keyof typeof colorName;\n\nexport function rgbFromNamedColor(name: NamedColor) {\n  const [red, green, blue] = colorName[name];\n\n  return { red, green, blue };\n}\n\nrgbFromNamedColor(\"aliceblue\");\nrgbFromNamedColor(\"tomato\");\n```\n\nThis keeps your accepted values aligned with the package data.\n\n### Narrow untyped input at the boundary\n\nIf input starts as an arbitrary string, narrow it before indexing into the color table.\n\n```typescript\nimport colorName = require(\"color-name\");\n\ntype NamedColor = keyof typeof colorName;\n\nexport function isNamedColor(value: string): value is NamedColor {\n  return value in colorName;\n}\n\nexport function parseNamedColor(value: string) {\n  if (!isNamedColor(value)) {\n    throw new Error(`Unsupported CSS named color: ${value}`);\n  }\n\n  return colorName[value];\n}\n```\n\nThis is the safest pattern when names come from HTTP input, CLI flags, or config files.\n\n### Iterate all available color names\n\nUse `Object.keys()` when you need to build a picker, autocomplete list, or validation set.\n\n```typescript\nimport colorName = require(\"color-name\");\n\ntype NamedColor = keyof typeof colorName;\n\nconst allColorNames = Object.keys(colorName) as NamedColor[];\n\nfor (const name of allColorNames) {\n  const [red, green, blue] = colorName[name];\n  console.log(name, red, green, blue);\n}\n```\n\n## Important Pitfalls\n\n- Install `color-name` as well as `@types/color-name`; the type package does not provide runtime code.\n- The package exports a static lookup table, not a color parser or format-conversion API.\n- The runtime package is CommonJS, so ESM-only projects may need their normal CommonJS interop boundary.\n- If you index with a plain `string`, TypeScript cannot guarantee the key exists; narrow to `keyof typeof colorName` first.\n- The values are RGB tuples. If your app needs hex, HSL, ANSI, or other color spaces, convert the tuple yourself or hand it to a dedicated color-conversion library.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/color-name\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/color-name\n- https://www.npmjs.com/package/color-name\n- https://github.com/colorjs/color-name\n"
  },
  {
    "path": "content/typescript/docs/commander/typescript/DOC.md",
    "content": "---\nname: commander\ndescription: \"TypeScript declarations for legacy Commander.js CLIs, including CommonJS imports, option parsing, subcommands, and practical typing boundaries.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.12.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,commander,cli,node,types,definitelytyped\"\n---\n\n# Commander TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/commander` only for legacy `commander` runtimes that do not already ship their own TypeScript declarations.\n\n`@types/commander@2.12.5` is a declaration-only package. Your app still imports and runs the real `commander` package at runtime. The type package gives TypeScript definitions for the legacy CommonJS API shape exported by `commander`.\n\nIf your installed `commander` package already publishes its own `types` or `typings`, prefer the bundled declarations from the runtime package instead of adding `@types/commander`.\n\n## Install\n\nFor a legacy Commander 2.x CLI, install the runtime package, TypeScript, Node.js types, and this declaration package together.\n\n```bash\nnpm install commander@2\nnpm install -D typescript @types/commander@2.12.5 @types/node\n```\n\nIf `commander` is already in the project, add only the missing declaration packages:\n\n```bash\nnpm install -D @types/commander@2.12.5 @types/node\n```\n\nThere are no environment variables, credentials, or client objects to configure.\n\n## Initialization\n\n### Use the `export =` import form\n\nThese declarations export the module with `export = commander`, so the most portable TypeScript import is:\n\n```ts\nimport commander = require(\"commander\");\n\nconst program = commander;\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import may also work:\n\n```ts\nimport commander from \"commander\";\n\nconst program = commander;\n```\n\nFor legacy CLI code that must compile across different compiler settings, prefer `import commander = require(\"commander\")`.\n\n### Recommended `tsconfig.json`\n\nUse CommonJS module output unless you already have a different Node.js build setup.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2019\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"esModuleInterop\": false,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient types with `compilerOptions.types`, include both `node` and `commander`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"commander\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Parse top-level options\n\nThe legacy declarations model Commander as a mutable command object. After `.parse(process.argv)`, option values are available as properties on `program`.\n\n```ts\nimport commander = require(\"commander\");\n\nconst program = commander;\n\nprogram\n  .version(\"1.0.0\")\n  .option(\"-c, --config <path>\", \"path to config file\")\n  .option(\"-d, --debug\", \"enable debug logging\")\n  .option(\"--dry-run\", \"print work without changing anything\")\n  .option(\"--no-color\", \"disable ANSI colors\")\n  .parse(process.argv);\n\nconst configPath = program.config as string | undefined;\nconst debug = Boolean(program.debug);\nconst dryRun = Boolean(program.dryRun);\nconst colorEnabled = Boolean(program.color);\n\nconsole.log({ configPath, debug, dryRun, colorEnabled, args: program.args });\n```\n\nFlag names from long options become properties on the command object. For example:\n\n- `--dry-run` becomes `program.dryRun`\n- `--no-color` controls `program.color`\n\n### Define subcommands\n\nSubcommands return another `Command` instance, so you can attach command-specific options and an action handler.\n\n```ts\nimport commander = require(\"commander\");\n\nconst program = commander;\n\nprogram.version(\"1.0.0\");\n\nprogram\n  .command(\"deploy <env>\")\n  .description(\"deploy the current build\")\n  .option(\"-t, --tag <name>\", \"release tag\")\n  .option(\"--force\", \"skip confirmation\")\n  .action((env: string, cmd: commander.Command) => {\n    const tag = cmd.tag as string | undefined;\n    const force = Boolean(cmd.force);\n\n    console.log(`deploying to ${env}`, { tag, force });\n  });\n\nprogram.parse(process.argv);\n```\n\nIn this API family, the action handler receives declared command arguments first, followed by the command object for command-specific options.\n\n### Create an isolated `Command` instance\n\nUse `commander.Command` when you want to build a CLI in a separate module instead of mutating the shared default export.\n\n```ts\nimport commander = require(\"commander\");\n\nconst cli = new commander.Command(\"acme\");\n\ncli\n  .version(\"1.0.0\")\n  .usage(\"[options] <file>\")\n  .option(\"-o, --output <path>\", \"write output to a file\")\n  .action((file: string) => {\n    console.log(\"processing\", file);\n  });\n\ncli.parse(process.argv);\n```\n\nThis pattern is useful when you export a configured CLI from a library module or when you want to avoid sharing global state between tests.\n\n### Read parsed options through your own interface\n\nThe legacy declarations intentionally allow dynamic properties with `[key: string]: any`. That matches how Commander 2.x stores option values, but it does not give strong inference for specific flags.\n\nDefine your own interface at the boundary where you read parsed options:\n\n```ts\nimport commander = require(\"commander\");\n\ntype CliOptions = {\n  config?: string;\n  debug?: boolean;\n  dryRun?: boolean;\n};\n\nconst program = commander;\n\nprogram\n  .option(\"-c, --config <path>\", \"path to config file\")\n  .option(\"-d, --debug\", \"enable debug logging\")\n  .option(\"--dry-run\", \"print work without changing anything\")\n  .parse(process.argv);\n\nconst options = program.opts() as CliOptions;\n\nif (options.debug) {\n  console.log(\"debug mode enabled\");\n}\n```\n\nUse the same approach for subcommands if you want a small, explicit typed surface in the rest of your code.\n\n### Show help when no arguments were passed\n\nThe legacy API exposes `.outputHelp()` to print usage without exiting and `.help()` to print usage and exit immediately.\n\n```ts\nimport commander = require(\"commander\");\n\nconst program = commander;\n\nprogram\n  .version(\"1.0.0\")\n  .option(\"-f, --force\", \"skip confirmation\")\n  .parse(process.argv);\n\nif (!process.argv.slice(2).length) {\n  program.outputHelp();\n}\n```\n\nYou can also customize help output with the built-in `--help` event:\n\n```ts\nprogram.on(\"--help\", () => {\n  console.log(\"\");\n  console.log(\"Examples:\");\n  console.log(\"  $ acme deploy production --tag 2026.03.13\");\n});\n```\n\n## Common Pitfalls\n\n- Install `commander` as well as `@types/commander`; the `@types` package does not include runtime JavaScript.\n- Prefer `import commander = require(\"commander\")` unless your compiler is explicitly configured for synthetic default imports.\n- Add `@types/node` because the declarations depend on Node.js types such as `NodeJS.EventEmitter`.\n- If `tsconfig.json` sets `compilerOptions.types`, include `commander` there or TypeScript will not load the package declarations.\n- Expect weak option inference: these declarations expose dynamic option properties and `opts(): { [key: string]: any }`, so define your own interface when you cross from CLI parsing into application logic.\n- Check the runtime package before adding this dependency. Current Commander releases publish declaration files in the runtime package metadata, so `@types/commander` is mainly for older projects.\n\n## Version Notes\n\n- This guide covers `@types/commander@2.12.5`, which matches the older CommonJS-style Commander API family used with legacy CLI code.\n- The legacy declaration shape exports a singleton command object plus constructors such as `commander.Command` and `commander.Option`.\n- Newer Commander releases have evolved beyond this older typing model and may expose different import styles and stronger built-in typings.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/commander\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/commander\n- https://www.npmjs.com/package/commander\n- https://github.com/tj/commander.js\n"
  },
  {
    "path": "content/typescript/docs/compression/typescript/DOC.md",
    "content": "---\nname: compression\ndescription: \"TypeScript declarations for the compression Express middleware factory, option objects, filter callbacks, and streamed response flushing\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.8.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,compression,express,node,http,middleware,types,definitelytyped\"\n---\n\n# compression TypeScript Guide\n\n## Golden Rule\n\nInstall `compression` for runtime behavior and `@types/compression` for TypeScript declarations.\n\n`@types/compression` only adds `.d.ts` files for the `compression` module. Your application still imports and runs `compression` itself.\n\nThe declaration package covers the middleware factory, `compression.CompressionOptions`, the `filter` callback shape, the default `compression.filter()` helper, and the `res.flush()` method added to Express responses for streaming use cases.\n\n## Install\n\nFor a typical Express app, install the runtime packages first, then the TypeScript declarations:\n\n```bash\nnpm install express compression\nnpm install -D typescript @types/node @types/express @types/compression\n```\n\nIf your project already has `express` and `compression`, add only the missing declaration packages:\n\n```bash\nnpm install -D @types/node @types/express @types/compression\n```\n\nNo credentials or package-specific environment variables are required. If you want environment-driven configuration, define your own app settings:\n\n```bash\nexport PORT=3000\nexport COMPRESSION_THRESHOLD=1kb\n```\n\n## TypeScript Setup\n\n`@types/compression` uses `export = compression`, so the most portable import form is:\n\n```typescript\nimport compression = require(\"compression\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport compression from \"compression\";\n```\n\nUse the runtime import as the namespace for option and callback types:\n\n```typescript\nimport compression from \"compression\";\n\nconst options: compression.CompressionOptions = {\n  threshold: process.env.COMPRESSION_THRESHOLD ?? \"1kb\",\n};\n```\n\nIf your project restricts ambient declaration packages with `compilerOptions.types`, keep the relevant server-side packages available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\", \"express\", \"compression\"]\n  }\n}\n```\n\nIncluding `compression` in that list matters when you want the Express `Response` augmentation for `res.flush()`.\n\n## Common Workflows\n\n### Enable compression for the whole app\n\nThe standard Express setup is to register the middleware near the top of your app so later routes can send compressed responses.\n\n```typescript\nimport express from \"express\";\nimport compression from \"compression\";\n\nconst app = express();\n\napp.use(compression());\napp.use(express.json());\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n\napp.listen(Number(process.env.PORT ?? 3000), () => {\n  console.log(\"server started\");\n});\n```\n\nMount `compression()` before routes or static middleware that you want it to wrap.\n\n### Type a custom filter and options object\n\nUse a typed `CompressionOptions` object when you want per-request control over whether a response should be compressed.\n\n```typescript\nimport express from \"express\";\nimport compression from \"compression\";\n\nconst app = express();\n\nconst shouldCompress: compression.CompressionFilter = (req, res) => {\n  if (req.headers[\"x-no-compression\"]) {\n    return false;\n  }\n\n  return compression.filter(req, res);\n};\n\nconst compressionOptions: compression.CompressionOptions = {\n  threshold: process.env.COMPRESSION_THRESHOLD ?? \"1kb\",\n  filter: shouldCompress,\n};\n\napp.use(compression(compressionOptions));\n\napp.get(\"/report\", (_req, res) => {\n  res.json({ generatedAt: new Date().toISOString() });\n});\n```\n\nCalling `compression.filter(req, res)` inside your custom filter keeps the runtime package's normal content-type checks and only adds your application-specific rule.\n\n### Stream Server-Sent Events and flush chunks\n\nThe `compression` middleware adds `res.flush()` to Express responses. Use it when you stream data and want buffered compressed output sent to the client before the response ends.\n\n```typescript\nimport express from \"express\";\nimport compression from \"compression\";\n\nconst app = express();\n\napp.use(compression());\n\napp.get(\"/events\", (req, res) => {\n  res.setHeader(\"Content-Type\", \"text/event-stream; charset=utf-8\");\n  res.setHeader(\"Cache-Control\", \"no-cache\");\n  res.setHeader(\"Connection\", \"keep-alive\");\n\n  const timer = setInterval(() => {\n    res.write(`data: ${JSON.stringify({ time: new Date().toISOString() })}\\n\\n`);\n    res.flush();\n  }, 1000);\n\n  req.on(\"close\", () => {\n    clearInterval(timer);\n    res.end();\n  });\n});\n```\n\nIf your project restricts `compilerOptions.types` and you do not include `compression`, TypeScript can report that `flush` does not exist on `Response` even though the middleware adds it at runtime.\n\n### Use `compression` with `express.static()`\n\n`compression()` returns ordinary Express middleware, so it composes normally with built-in static-file serving.\n\n```typescript\nimport express from \"express\";\nimport compression from \"compression\";\n\nconst app = express();\n\napp.use(compression());\napp.use(\"/assets\", express.static(\"public\"));\n\napp.listen(3000);\n```\n\nRegister compression first if you want static responses to go through the middleware.\n\n## Common Pitfalls\n\n- Install `compression` as well as `@types/compression`; the type package does not include runtime code.\n- Import from `\"compression\"`, never from `\"@types/compression\"`.\n- Use `import compression = require(\"compression\")` unless your project enables `esModuleInterop` or `allowSyntheticDefaultImports`.\n- Mount `compression()` before the routes or `express.static()` handlers whose responses you want compressed.\n- When you write a custom filter, call `compression.filter(req, res)` unless you intentionally want to replace the package's default filtering logic.\n- If you use `compilerOptions.types`, include `\"compression\"` so the `Response.flush()` augmentation is visible to TypeScript.\n\n## Version Notes\n\n- This guide targets `@types/compression==1.8.1`.\n- The declaration package models the standalone `compression` middleware package. It does not replace the runtime dependency.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/compression\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/compression\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/compression/index.d.ts\n- https://www.npmjs.com/package/compression\n- https://github.com/expressjs/compression\n"
  },
  {
    "path": "content/typescript/docs/connect/typescript/DOC.md",
    "content": "---\nname: connect\ndescription: \"TypeScript declarations for Connect middleware servers, request handlers, mount paths, and error-handling callbacks.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.4.38\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,connect,node,http,middleware,types,definitelytyped\"\n---\n\n# connect TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/connect` alongside the real `connect` runtime package.\n\n`@types/connect` only provides TypeScript declarations. Your application imports and runs `connect`; the declaration package supplies the types for `connect()`, `app.use()`, `app.listen()`, `connect.IncomingMessage`, and the middleware callback signatures.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and Node.js type declarations.\n\n```bash\nnpm install connect\nnpm install --save-dev typescript @types/connect @types/node\n```\n\nIf your project already has `connect`, add only the missing type packages:\n\n```bash\nnpm install --save-dev @types/connect @types/node\n```\n\nNo package-specific credentials or authentication setup are required. If you want a configurable port, use a normal app-level environment variable:\n\n```bash\nexport PORT=3000\n```\n\n## TypeScript Setup\n\n`@types/connect` uses `export = createServer`, so the most portable import form is CommonJS-style:\n\n```ts\nimport connect = require(\"connect\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```ts\nimport connect from \"connect\";\n```\n\nIf your project restricts ambient declaration packages with `compilerOptions.types`, include both Node.js and Connect:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\", \"connect\"]\n  }\n}\n```\n\nThe published package metadata declares `@types/node` as a dependency and sets a TypeScript support floor of `4.5`.\n\n## Create A Typed Connect App\n\nThe declaration entrypoint is the `connect()` factory. It returns a `Server` value that is both callable as a Node request handler and exposes middleware methods such as `use()`, `handle()`, and `listen()`.\n\n```ts\nimport http from \"node:http\";\nimport connect = require(\"connect\");\n\nconst app = connect();\nconst port = Number(process.env.PORT ?? 3000);\n\napp.use((req, res, next) => {\n  res.setHeader(\"x-request-id\", req.headers[\"x-request-id\"] ?? \"generated\");\n  next();\n});\n\napp.use(\"/health\", (_req, res) => {\n  res.statusCode = 200;\n  res.end(\"ok\");\n});\n\nhttp.createServer(app).listen(port, () => {\n  console.log(`listening on http://localhost:${port}`);\n});\n```\n\nBecause the `Server` type is also a request handler, you can pass `app` directly to `http.createServer(app)`. The declarations also expose `app.listen(...)` with the same overload shapes as Node's `http.Server#listen()`.\n\n## Type Middleware Explicitly\n\nThe package exports three middleware function aliases that match the classic Connect callback forms:\n\n- `connect.SimpleHandleFunction`: `(req, res) => void`\n- `connect.NextHandleFunction`: `(req, res, next) => void`\n- `connect.ErrorHandleFunction`: `(err, req, res, next) => void`\n\nUse them when you want reusable middleware values with stable, checked signatures.\n\n```ts\nimport connect = require(\"connect\");\n\nconst logger: connect.NextHandleFunction = (req, _res, next) => {\n  console.log(req.method, req.originalUrl ?? req.url);\n  next();\n};\n\nconst notFound: connect.SimpleHandleFunction = (_req, res) => {\n  res.statusCode = 404;\n  res.end(\"Not found\");\n};\n\nconst onError: connect.ErrorHandleFunction = (err, _req, res, _next) => {\n  res.statusCode = 500;\n  res.end(err instanceof Error ? err.message : \"Internal Server Error\");\n};\n\nconst app = connect();\n\napp.use(logger);\napp.use(\"/boom\", (_req, _res, next) => {\n  next(new Error(\"unexpected failure\"));\n});\napp.use(notFound);\napp.use(onError);\n```\n\nThe error-handling form is the four-argument callback. Keep it after middleware that may call `next(err)`.\n\n## Use Mount Paths Correctly\n\n`app.use(route, fn)` is typed for a string mount path plus a middleware function. The declaration comments describe prefix matching: mounting at `/admin` applies to `/admin` and `/admin/settings`, but not to `/` or `/posts`.\n\n```ts\nimport connect = require(\"connect\");\n\nconst app = connect();\n\napp.use(\"/admin\", (req, res, next) => {\n  if (req.headers.authorization !== `Bearer ${process.env.ADMIN_TOKEN}`) {\n    res.statusCode = 401;\n    res.end(\"Unauthorized\");\n    return;\n  }\n\n  next();\n});\n\napp.use(\"/admin/users\", (_req, res) => {\n  res.setHeader(\"content-type\", \"application/json\");\n  res.end(JSON.stringify({ users: [] }));\n});\n```\n\nThis is the simplest typed pattern for grouping middleware by URL prefix without introducing a larger framework.\n\n## Work With `connect.IncomingMessage`\n\n`connect.IncomingMessage` extends Node's `http.IncomingMessage` and adds an optional `originalUrl` property. Use that type when you need helpers that know about Connect's request shape.\n\n```ts\nimport type { ServerResponse } from \"node:http\";\nimport connect = require(\"connect\");\n\nfunction auditRequest(req: connect.IncomingMessage, res: ServerResponse) {\n  const url = req.originalUrl ?? req.url ?? \"/\";\n\n  res.setHeader(\"x-audited-url\", url);\n}\n\nconst app = connect();\n\napp.use((req, res, next) => {\n  auditRequest(req, res);\n  next();\n});\n```\n\nIf you only need standard Node request fields, `req` and `res` are still compatible with `http.IncomingMessage` and `http.ServerResponse`.\n\n## Common Workflows\n\n### Listen directly from the Connect app\n\nUse `app.listen(...)` when you only need one HTTP server:\n\n```ts\nimport connect = require(\"connect\");\n\nconst app = connect();\n\napp.use(\"/health\", (_req, res) => {\n  res.end(\"ok\");\n});\n\napp.listen(Number(process.env.PORT ?? 3000), () => {\n  console.log(\"server started\");\n});\n```\n\n### Reuse the same app with multiple Node servers\n\nThe declaration comments call out that a Connect app is just a JavaScript function, so you can wrap it with different Node servers.\n\n```ts\nimport http from \"node:http\";\nimport https from \"node:https\";\nimport fs from \"node:fs\";\nimport connect = require(\"connect\");\n\nconst app = connect();\n\napp.use((_req, res) => {\n  res.end(\"hello\");\n});\n\nhttp.createServer(app).listen(80);\n\nhttps\n  .createServer(\n    {\n      key: fs.readFileSync(\"./certs/server.key\"),\n      cert: fs.readFileSync(\"./certs/server.crt\"),\n    },\n    app,\n  )\n  .listen(443);\n```\n\n### Call `handle()` from a custom server\n\nUse `handle(req, res, next)` when you need a fallback inside your own Node server wiring.\n\n```ts\nimport http from \"node:http\";\nimport connect = require(\"connect\");\n\nconst app = connect();\n\napp.use(\"/api\", (_req, res) => {\n  res.end(\"from connect\");\n});\n\nhttp\n  .createServer((req, res) => {\n    app.handle(req, res, () => {\n      res.statusCode = 404;\n      res.end(\"no matching middleware\");\n    });\n  })\n  .listen(3000);\n```\n\n## Important Pitfalls\n\n- `@types/connect` does not include runtime code. Install `connect` itself.\n- Import from `connect`, not from `@types/connect`.\n- Without TypeScript interop settings, prefer `import connect = require(\"connect\")` over a default import.\n- If you use `compilerOptions.types`, include both `node` and `connect` or TypeScript may not load the declarations you expect.\n- Error middleware is the four-argument form. A normal `(req, res, next)` function is not typed as an error handler.\n- `req.originalUrl` is optional in the declarations, so handle the undefined case.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/connect==3.4.38`.\n- The published package metadata lists `typeScriptVersion: 4.5`.\n- The current declaration entrypoint models the classic CommonJS API with `export = createServer`.\n- The published declarations depend only on `@types/node`.\n\n## Official Sources\n\n- npm package page for `@types/connect`: https://www.npmjs.com/package/@types/connect\n- DefinitelyTyped source for `@types/connect`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/connect\n- `@types/connect` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/connect/index.d.ts\n"
  },
  {
    "path": "content/typescript/docs/cookie-parser/typescript/DOC.md",
    "content": "---\nname: cookie-parser\ndescription: \"TypeScript definitions for cookie-parser middleware, signed cookies, and Express request cookie properties\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.4.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,cookie-parser,express,cookies,middleware,types\"\n---\n\n# cookie-parser TypeScript Guide\n\n`@types/cookie-parser` adds TypeScript declarations for the `cookie-parser` runtime package. Use it in Express apps that parse the `Cookie` header, read `req.cookies`, or validate signed cookies through `req.signedCookies`.\n\nThis package only provides `.d.ts` files. Install `cookie-parser` itself for runtime behavior.\n\n## Install\n\nInstall the Express runtime, the cookie parser middleware, and the type packages together:\n\n```bash\nnpm install express cookie-parser\nnpm install --save-dev typescript @types/express @types/cookie-parser\n```\n\nNo remote service setup or authentication is required. If you use signed cookies, configure an application secret in your environment:\n\n```bash\nexport COOKIE_SECRET='current-secret,previous-secret'\n```\n\n## TypeScript Setup\n\n`cookie-parser` is a CommonJS module. The most portable import form is:\n\n```typescript\nimport cookieParser = require(\"cookie-parser\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport cookieParser from \"cookie-parser\";\n```\n\nIn a normal project, installing `@types/cookie-parser` is enough. Only add it to `compilerOptions.types` when your project already restricts which declaration packages TypeScript loads:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"express\", \"cookie-parser\"]\n  }\n}\n```\n\n## Add The Middleware\n\nThe middleware factory accepts an optional signing secret and an optional options object that is forwarded to `cookie.parse`.\n\n```typescript\nimport express from \"express\";\nimport cookieParser = require(\"cookie-parser\");\n\nconst app = express();\n\nconst secrets = process.env.COOKIE_SECRET\n  ?.split(\",\")\n  .map((value) => value.trim())\n  .filter(Boolean);\n\napp.use(\n  cookieParser(secrets && secrets.length > 0 ? secrets : undefined)\n);\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n```\n\nAfter this middleware runs:\n\n- `req.cookies` contains parsed cookies keyed by cookie name.\n- `req.signedCookies` contains cookies that were successfully unsigned.\n- `req.secret` is set when you pass a signing secret.\n\nIf you pass an array of secrets, `cookie-parser` tries each secret in order when unsigning cookies, and `req.secret` is set to the first secret in the array.\n\n## Read Plain Cookies Safely\n\nCookie values are dynamic at runtime, so guard the value before using it as a string or object.\n\n```typescript\nimport express, { Request, Response } from \"express\";\nimport cookieParser = require(\"cookie-parser\");\n\nconst app = express();\n\napp.use(cookieParser());\n\napp.get(\"/preferences\", (req: Request, res: Response) => {\n  const theme = typeof req.cookies.theme === \"string\"\n    ? req.cookies.theme\n    : \"light\";\n\n  res.json({ theme });\n});\n```\n\nIf a cookie value has the `j:` prefix and contains valid JSON, the middleware parses it with `JSON.parse` before exposing it on `req.cookies`.\n\n## Read Signed Cookies Safely\n\nSigned cookies are removed from `req.cookies` and moved to `req.signedCookies`. When signature validation fails, the value becomes `false`.\n\n```typescript\nimport express, { Request, Response } from \"express\";\nimport cookieParser = require(\"cookie-parser\");\n\ntype SessionCookie = {\n  userId: string;\n  role: \"admin\" | \"member\";\n};\n\nfunction isSessionCookie(value: unknown): value is SessionCookie {\n  if (!value || typeof value !== \"object\") {\n    return false;\n  }\n\n  const session = value as Record<string, unknown>;\n\n  return typeof session.userId === \"string\"\n    && (session.role === \"admin\" || session.role === \"member\");\n}\n\nconst app = express();\n\napp.use(cookieParser(process.env.COOKIE_SECRET));\n\napp.get(\"/me\", (req: Request, res: Response) => {\n  const session = req.signedCookies.session;\n\n  if (session === false) {\n    res.status(400).json({ error: \"invalid signed cookie\" });\n    return;\n  }\n\n  if (!isSessionCookie(session)) {\n    res.status(401).json({ error: \"missing session\" });\n    return;\n  }\n\n  res.json({\n    userId: session.userId,\n    role: session.role,\n  });\n});\n```\n\nThis pattern keeps the TypeScript boundary explicit: treat cookie data as untrusted input until you check its shape.\n\n## Use The Helper Exports\n\nThe runtime package also exports helper functions, and the type package includes declarations for them.\n\n```typescript\nimport cookieParser = require(\"cookie-parser\");\n\nconst parsedJson = cookieParser.JSONCookie('j:{\"darkMode\":true}');\n\nconst unsigned = cookieParser.signedCookie(\n  \"s:example-value.signature\",\n  process.env.COOKIE_SECRET ?? \"dev-secret\"\n);\n\nif (unsigned === false) {\n  throw new Error(\"Cookie signature is invalid\");\n}\n\nconsole.log(parsedJson, unsigned);\n```\n\nUse these helpers when you need to parse or unsign cookie values outside the normal Express middleware flow.\n\n## Common Pitfalls\n\n- Install `cookie-parser` as well as `@types/cookie-parser`; the type package does not include runtime code.\n- Register `app.use(cookieParser(...))` before routes that read `req.cookies` or `req.signedCookies`.\n- Guard signed cookie values against `false`; that value means signature verification failed.\n- Guard cookie values before treating them as strings or structured objects.\n- Add `\"cookie-parser\"` to `compilerOptions.types` only if your project already restricts loaded type packages.\n"
  },
  {
    "path": "content/typescript/docs/cors/typescript/DOC.md",
    "content": "---\nname: cors\ndescription: \"TypeScript declarations for the cors middleware factory, CORS option objects, and per-request policy callbacks\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.8.19\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,cors,express,node,http,middleware,types,definitelytyped\"\n---\n\n# cors TypeScript Guide\n\n`@types/cors` provides TypeScript declarations for the `cors` runtime package. Install `cors` for runtime behavior, then use the types exposed by the runtime import for configuration objects and request-aware callbacks.\n\nThe declaration package models the middleware factory, `cors.CorsOptions`, `cors.CorsOptionsDelegate`, and the minimal `cors.CorsRequest` shape used by request-based policies.\n\n## Install\n\nInstall the runtime middleware first, then add TypeScript and the declaration packages your server project needs:\n\n```bash\nnpm install express cors\nnpm install --save-dev typescript @types/cors @types/express @types/node\n```\n\nIf your project already has `express` and `cors`, add only the missing type packages:\n\n```bash\nnpm install --save-dev @types/cors @types/express @types/node\n```\n\nNo credentials or service-specific environment variables are required. If you want environment-driven policy, define the allowed origin values in your app configuration:\n\n```bash\nexport CORS_ORIGIN='https://app.example.com'\nexport CORS_ORIGINS='https://app.example.com,https://admin.example.com'\n```\n\n## TypeScript Setup\n\n`@types/cors` uses `export =`, so the most portable import form is CommonJS-style:\n\n```typescript\nimport cors = require(\"cors\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport cors from \"cors\";\n```\n\nUse the runtime import as the namespace for the exported types:\n\n```typescript\nimport cors from \"cors\";\nimport type { Request } from \"express\";\n\nconst corsOptions: cors.CorsOptions = {\n  origin: process.env.CORS_ORIGIN ?? \"*\",\n  credentials: true,\n};\n\nconst corsOptionsDelegate: cors.CorsOptionsDelegate<Request> = (req, callback) => {\n  callback(null, { origin: req.headers.origin ?? false });\n};\n```\n\nIf your project restricts ambient declaration packages with `compilerOptions.types`, include the server-side packages you expect TypeScript to load:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\", \"express\", \"cors\"]\n  }\n}\n```\n\n## Enable CORS For All Routes\n\nThe default middleware enables CORS with the package defaults: `origin: \"*\"`, `methods: \"GET,HEAD,PUT,PATCH,POST,DELETE\"`, `preflightContinue: false`, and `optionsSuccessStatus: 204`.\n\n```typescript\nimport express from \"express\";\nimport cors from \"cors\";\n\nconst app = express();\n\napp.use(cors());\napp.use(express.json());\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n\napp.listen(3000);\n```\n\nThis is the simplest setup when every route can be called cross-origin.\n\n## Configure A Static Policy\n\nType your options object as `cors.CorsOptions` when you want TypeScript to verify supported fields such as `origin`, `methods`, `allowedHeaders`, `exposedHeaders`, `credentials`, `maxAge`, `preflightContinue`, and `optionsSuccessStatus`.\n\n```typescript\nimport express from \"express\";\nimport cors from \"cors\";\n\nconst app = express();\n\nconst corsOptions: cors.CorsOptions = {\n  origin: process.env.CORS_ORIGIN ?? \"https://app.example.com\",\n  methods: [\"GET\", \"POST\", \"DELETE\"],\n  allowedHeaders: [\"Content-Type\", \"Authorization\"],\n  exposedHeaders: [\"Content-Range\"],\n  credentials: true,\n  maxAge: 86400,\n  optionsSuccessStatus: 200,\n};\n\napp.use(cors(corsOptions));\n```\n\nSet `optionsSuccessStatus` to `200` when you need a successful `OPTIONS` response code that works better with older browsers or embedded clients that do not handle `204` well.\n\nIf you omit `allowedHeaders`, the runtime reflects the request's `Access-Control-Request-Headers` header.\n\n## Use A Request-Aware Policy\n\nFor allowlists or tenant-specific rules, type the callback as `cors.CorsOptionsDelegate<Request>` so the request parameter stays compatible with Express.\n\n```typescript\nimport express, { type Request } from \"express\";\nimport cors from \"cors\";\n\nconst app = express();\n\nconst allowedOrigins = new Set(\n  (process.env.CORS_ORIGINS ?? \"\")\n    .split(\",\")\n    .map((value) => value.trim())\n    .filter(Boolean)\n);\n\nconst corsOptionsDelegate: cors.CorsOptionsDelegate<Request> = (req, callback) => {\n  const requestOrigin = req.headers.origin;\n\n  if (!requestOrigin || allowedOrigins.has(requestOrigin)) {\n    callback(null, {\n      origin: true,\n      credentials: true,\n    });\n    return;\n  }\n\n  callback(null, { origin: false });\n};\n\napp.use(cors(corsOptionsDelegate));\n```\n\nIn the `cors` runtime, `origin: true` reflects the request origin back in the response, while `origin: false` disables CORS for that request.\n\nIf you prefer to keep the request-aware logic inside `CorsOptions`, the `origin` field also accepts a callback:\n\n```typescript\nimport cors from \"cors\";\n\nconst allowedOrigins = new Set([\"https://app.example.com\"]);\n\nconst corsOptions: cors.CorsOptions = {\n  origin(origin, callback) {\n    if (!origin || allowedOrigins.has(origin)) {\n      callback(null, true);\n      return;\n    }\n\n    callback(new Error(\"Not allowed by CORS\"));\n  },\n};\n```\n\n## Handle Preflight Requests\n\nComplex cross-origin requests often need an `OPTIONS` preflight route. Register `cors()` on the `OPTIONS` handler before the corresponding route handler.\n\n```typescript\nimport express from \"express\";\nimport cors from \"cors\";\n\nconst app = express();\n\napp.options(\"/products/:id\", cors());\n\napp.delete(\"/products/:id\", cors(), (req, res) => {\n  res.json({ deleted: req.params.id });\n});\n```\n\nTo enable preflight across the whole app, add a global `OPTIONS` handler before other routes:\n\n```typescript\napp.options(\"*\", cors());\n```\n\nSet `preflightContinue: true` only when you want the preflight request to continue to the next middleware instead of ending inside `cors`.\n\n## Type Reusable Middleware Helpers\n\nWhen you wrap CORS setup in an application helper, keep the config typed as `cors.CorsOptions` and return normal Express middleware.\n\n```typescript\nimport type { RequestHandler } from \"express\";\nimport cors from \"cors\";\n\nexport function createCorsMiddleware(origin: string): RequestHandler {\n  const options: cors.CorsOptions = {\n    origin,\n    credentials: true,\n  };\n\n  return cors(options);\n}\n```\n\nThis keeps your code importing from `\"cors\"` while still getting the declaration package's type checking.\n\n## Common Pitfalls\n\n- Install `cors` as well as `@types/cors`; the declaration package does not include runtime code.\n- Import from `\"cors\"`, not from `\"@types/cors\"`.\n- Use `cors.CorsOptionsDelegate<Request>` when you want the request callback typed as an Express request instead of the minimal `cors.CorsRequest` interface.\n- If your project sets `compilerOptions.types`, include `node`, `cors`, and `express` in the project that compiles your server.\n- `optionsSuccessStatus` defaults to `204`; set it explicitly when you need a different successful preflight status.\n\n## Version Notes For `@types/cors` 2.8.19\n\n`@types/cors@2.8.19` depends on `@types/node`, and its package metadata declares `typeScriptVersion: 5.1`. Keep your compiler and Node.js type packages aligned with that declaration release.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/cors\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cors\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cors/index.d.ts\n- https://www.npmjs.com/package/cors\n- https://github.com/expressjs/cors#readme\n"
  },
  {
    "path": "content/typescript/docs/cross-spawn/typescript/DOC.md",
    "content": "---\nname: cross-spawn\ndescription: \"TypeScript declarations for cross-spawn's drop-in spawn and spawnSync APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"6.0.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,cross-spawn,node,child-process,spawn,types\"\n---\n\n# cross-spawn TypeScript Guide\n\n`@types/cross-spawn` adds TypeScript declarations for the `cross-spawn` runtime package. Use it when your Node.js project imports `cross-spawn` and you want typed access to the same `spawn()` and `spawn.sync()` API shape described in the runtime package README.\n\n`cross-spawn` is documented as a drop-in replacement for Node's `child_process.spawn()` and `child_process.spawnSync()` with cross-platform fixes for Windows command resolution, shebang handling, and related quoting issues.\n\nThis package only provides `.d.ts` files. It does not install the `cross-spawn` runtime.\n\n## Install\n\nInstall the runtime package, the declaration package, and Node.js types together:\n\n```bash\nnpm install cross-spawn\nnpm install --save-dev @types/cross-spawn @types/node typescript\n```\n\nThere are no package-specific environment variables, authentication steps, or client initialization calls.\n\n## TypeScript Setup\n\n`cross-spawn` runs in Node.js and returns the same kinds of objects as the built-in `child_process` APIs, so `@types/node` is part of the practical setup.\n\nA typical `tsconfig.json` for Node code looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient type packages with `compilerOptions.types`, include at least `node` in that list:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n## Import `cross-spawn`\n\nThe runtime package exports a CommonJS function with extra properties attached to it. The safest configuration-independent import form in TypeScript is:\n\n```ts\nimport spawn = require(\"cross-spawn\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, this default import style may also be convenient:\n\n```ts\nimport spawn from \"cross-spawn\";\n```\n\nFor Node child-process option and return types, import from `node:child_process`:\n\n```ts\nimport spawn = require(\"cross-spawn\");\nimport type {\n  SpawnOptions,\n  SpawnSyncOptionsWithStringEncoding,\n} from \"node:child_process\";\n```\n\n## Spawn A Process\n\nUse `spawn()` exactly as you would use Node's `child_process.spawn()`.\n\n```ts\nimport spawn = require(\"cross-spawn\");\n\nconst child = spawn(\"npm\", [\"run\", \"build\"], {\n  cwd: process.cwd(),\n  env: {\n    ...process.env,\n    FORCE_COLOR: \"1\",\n  },\n  stdio: \"inherit\",\n});\n\nchild.on(\"error\", (error) => {\n  console.error(\"Failed to start command\", error);\n});\n\nchild.on(\"close\", (code) => {\n  if (code !== 0) {\n    console.error(`Build exited with code ${code}`);\n  }\n});\n```\n\nThis is the main integration boundary for the type package: the returned child process and the option objects follow Node's child-process typings, while `cross-spawn` handles the cross-platform command launching behavior.\n\n## Use `spawn.sync()` For Blocking Commands\n\nUse the `.sync()` property when you need a blocking call.\n\n```ts\nimport spawn = require(\"cross-spawn\");\nimport type { SpawnSyncOptionsWithStringEncoding } from \"node:child_process\";\n\nconst options: SpawnSyncOptionsWithStringEncoding = {\n  cwd: process.cwd(),\n  encoding: \"utf8\",\n};\n\nconst result = spawn.sync(\"node\", [\"--version\"], options);\n\nif (result.error) {\n  throw result.error;\n}\n\nif (result.status !== 0) {\n  throw new Error(result.stderr || `Command failed with status ${result.status}`);\n}\n\nconsole.log(result.stdout.trim());\n```\n\nUsing a string encoding keeps `stdout` and `stderr` typed as strings instead of raw buffers.\n\n## Reuse Node Spawn Option Types\n\nWhen you write helpers around `cross-spawn`, type the options with Node's built-in child-process types.\n\n```ts\nimport spawn = require(\"cross-spawn\");\nimport type { SpawnOptions } from \"node:child_process\";\n\nexport function run(command: string, args: string[], options: SpawnOptions = {}) {\n  return spawn(command, args, {\n    stdio: \"inherit\",\n    ...options,\n  });\n}\n```\n\nThis keeps your wrapper aligned with the runtime contract documented for Node's `spawn()` API.\n\n## Common Pitfalls\n\n- Install `cross-spawn` as well as `@types/cross-spawn`; the type package does not include executable runtime code.\n- Add `@types/node` in Node.js projects, because the process, options, and return types come from Node's child-process declarations.\n- Prefer `import spawn = require(\"cross-spawn\")` if you want an import form that does not depend on `esModuleInterop`.\n- Treat `options.shell` carefully. The `cross-spawn` README states that when `shell` is used, its extra enhancements are disabled and behavior intentionally follows Node's shell spawning behavior.\n- Keep Windows shebang expectations modest. The runtime README documents support for `#!/usr/bin/env <program>` shebangs, but not shebangs that include extra arguments.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/cross-spawn\n- https://www.npmjs.com/package/cross-spawn\n- https://github.com/moxystudio/node-cross-spawn\n- https://nodejs.org/api/child_process.html#child_processspawncommand-args-options\n- https://nodejs.org/api/child_process.html#child_processspawnsynccommand-args-options\n"
  },
  {
    "path": "content/typescript/docs/crypto-js/typescript/DOC.md",
    "content": "---\nname: crypto-js\ndescription: \"TypeScript guidance for `crypto-js`, including installation of `@types/crypto-js`, CommonJS-friendly imports, and practical hashing, AES, and PBKDF2 workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.2.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,crypto-js,crypto,hashing,aes,pbkdf2,types,definitelytyped,npm\"\n---\n\n# crypto-js TypeScript Guide\n\n## Golden Rule\n\nInstall `crypto-js` for runtime behavior and `@types/crypto-js` for TypeScript declarations.\n\nImport from `\"crypto-js\"` in application code. Do not import from `\"@types/crypto-js\"` directly.\n\nThere is no client object, authentication flow, or package-specific initialization step.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install crypto-js\nnpm install -D typescript @types/crypto-js@4.2.2\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/crypto-js@4.2.2\n```\n\nIf you read encryption material from `process.env` in a Node.js app, add Node's type declarations too:\n\n```bash\nnpm install -D @types/node\n```\n\n`@types/crypto-js` does not define any environment variables. In real applications, you usually provide your own passphrase or key material through your app configuration:\n\n```bash\nexport CRYPTO_SECRET_PASSPHRASE=\"replace-me\"\nexport CRYPTO_KEY_HEX=\"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\"\nexport CRYPTO_IV_HEX=\"0102030405060708090a0b0c0d0e0f10\"\n```\n\n## Import Style And `tsconfig.json`\n\n`crypto-js` is published in a CommonJS/UMD style. The configuration-independent TypeScript import form is:\n\n```typescript\nimport CryptoJS = require(\"crypto-js\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport CryptoJS from \"crypto-js\";\n```\n\nPick one import style and use it consistently.\n\n## Common Workflows\n\n### Hash text and serialize the digest explicitly\n\nThe hash helpers return a `WordArray`. Convert it to a string in the encoding your application expects.\n\n```typescript\nimport CryptoJS = require(\"crypto-js\");\n\nexport function sha256Hex(value: string): string {\n  return CryptoJS.SHA256(value).toString(CryptoJS.enc.Hex);\n}\n\nexport function sha256Base64(value: string): string {\n  return CryptoJS.SHA256(value).toString(CryptoJS.enc.Base64);\n}\n\nexport function hmacSha256Hex(value: string, secret: string): string {\n  return CryptoJS.HmacSHA256(value, secret).toString(CryptoJS.enc.Hex);\n}\n```\n\nThis is the practical TypeScript boundary: application code usually wants a plain `string`, while `crypto-js` works internally with `WordArray` values.\n\n### Encrypt and decrypt text with a passphrase\n\nPassphrase-based encryption is the shortest path when your app already manages a shared secret string.\n\n```typescript\nimport CryptoJS = require(\"crypto-js\");\n\nfunction loadPassphrase(): string {\n  const passphrase = process.env.CRYPTO_SECRET_PASSPHRASE;\n\n  if (!passphrase) {\n    throw new Error(\"CRYPTO_SECRET_PASSPHRASE is required\");\n  }\n\n  return passphrase;\n}\n\nexport function encryptText(plaintext: string): string {\n  const passphrase = loadPassphrase();\n  return CryptoJS.AES.encrypt(plaintext, passphrase).toString();\n}\n\nexport function decryptText(ciphertext: string): string {\n  const passphrase = loadPassphrase();\n  const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase);\n  return bytes.toString(CryptoJS.enc.Utf8);\n}\n```\n\n`AES.decrypt()` returns bytes, not a JavaScript string. Use `CryptoJS.enc.Utf8` when you expect UTF-8 plaintext.\n\n### Encrypt structured data with an explicit key and IV\n\nWhen your application already manages raw key material, parse it into `WordArray` values and pass the same options to both `encrypt()` and `decrypt()`.\n\n```typescript\nimport CryptoJS = require(\"crypto-js\");\n\ntype SessionToken = {\n  sub: string;\n  scope: string[];\n};\n\nfunction requireEnv(name: string): string {\n  const value = process.env[name];\n\n  if (!value) {\n    throw new Error(`${name} is required`);\n  }\n\n  return value;\n}\n\nfunction loadKeyMaterial() {\n  return {\n    key: CryptoJS.enc.Hex.parse(requireEnv(\"CRYPTO_KEY_HEX\")),\n    iv: CryptoJS.enc.Hex.parse(requireEnv(\"CRYPTO_IV_HEX\")),\n  };\n}\n\nexport function encryptToken(token: SessionToken): string {\n  const { key, iv } = loadKeyMaterial();\n  const plaintext = JSON.stringify(token);\n\n  return CryptoJS.AES.encrypt(plaintext, key, {\n    iv,\n    mode: CryptoJS.mode.CBC,\n    padding: CryptoJS.pad.Pkcs7,\n  }).toString();\n}\n\nexport function decryptToken(ciphertext: string): SessionToken {\n  const { key, iv } = loadKeyMaterial();\n  const bytes = CryptoJS.AES.decrypt(ciphertext, key, {\n    iv,\n    mode: CryptoJS.mode.CBC,\n    padding: CryptoJS.pad.Pkcs7,\n  });\n\n  return JSON.parse(bytes.toString(CryptoJS.enc.Utf8)) as SessionToken;\n}\n```\n\nThis pattern keeps the key and IV parsing in one place and returns normal TypeScript values at your application boundary.\n\n### Derive a key with PBKDF2\n\nUse `PBKDF2()` when your input is a passphrase but the rest of your application expects a fixed-length symmetric key.\n\n```typescript\nimport CryptoJS = require(\"crypto-js\");\n\ntype DerivedKey = {\n  saltHex: string;\n  keyHex: string;\n};\n\nexport function deriveAes256Key(passphrase: string): DerivedKey {\n  const salt = CryptoJS.lib.WordArray.random(16);\n  const key = CryptoJS.PBKDF2(passphrase, salt, {\n    keySize: 256 / 32,\n    iterations: 100000,\n    hasher: CryptoJS.algo.SHA256,\n  });\n\n  return {\n    saltHex: salt.toString(CryptoJS.enc.Hex),\n    keyHex: key.toString(CryptoJS.enc.Hex),\n  };\n}\n```\n\n`PBKDF2()` also returns a `WordArray`, so serialize the result before storing it in configuration, a database record, or a transport payload.\n\n## Important Pitfalls\n\n- `@types/crypto-js` is a declaration package only. Keep `crypto-js` installed as a normal runtime dependency.\n- Import from `crypto-js`, not from `@types/crypto-js`.\n- `SHA256()`, `HmacSHA256()`, `PBKDF2()`, and `AES.decrypt()` produce `WordArray` values. Convert them explicitly with `CryptoJS.enc.Hex`, `CryptoJS.enc.Base64`, or `CryptoJS.enc.Utf8`.\n- `WordArray.random(16)` uses a byte count. For a 16-byte IV or salt, pass `16`, not `128`.\n- Passphrase-based `AES.encrypt(plaintext, passphrase)` and key-based `AES.encrypt(plaintext, key, { iv })` are different call patterns. Decrypt with the matching form and the same options.\n- If you rely on `process.env` in TypeScript, include `@types/node` or another runtime-specific source of environment typings.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/crypto-js==4.2.2`.\n- The declarations are for the `crypto-js` runtime package, so application imports stay `crypto-js`.\n- If your project uses a default import such as `import CryptoJS from \"crypto-js\"`, enable `esModuleInterop` or use `import CryptoJS = require(\"crypto-js\")` instead.\n\n## Official Sources\n\n- npm package page for `@types/crypto-js`: https://www.npmjs.com/package/@types/crypto-js\n- DefinitelyTyped source for `@types/crypto-js`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/crypto-js\n- `@types/crypto-js` declaration entrypoint: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/crypto-js/index.d.ts\n- npm package page for `crypto-js`: https://www.npmjs.com/package/crypto-js\n- `crypto-js` upstream repository and README: https://github.com/brix/crypto-js\n"
  },
  {
    "path": "content/typescript/docs/cssnano/typescript/DOC.md",
    "content": "---\nname: cssnano\ndescription: \"TypeScript guidance for `cssnano` 5.1.x. The `@types/cssnano` 5.1.3 package entry is not the runtime integration boundary; current projects should install `cssnano`, rely on its bundled declarations, and use it through PostCSS or a build script.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.1.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,cssnano,postcss,css,minification,types,definitelytyped,npm\"\n---\n\n# cssnano TypeScript Guide\n\n## Golden Rule\n\nFor current `cssnano` 5.1.x projects, install `cssnano` and `postcss`, then import from `\"cssnano\"`.\n\n`@types/cssnano` `5.1.3` is not the package you should target in application code. The published `cssnano` runtime package includes its own `types/index.d.ts` in the `5.1.x` line, and that runtime export is the TypeScript surface you actually use.\n\nIn practice:\n\n- install `cssnano`\n- install `postcss`\n- import from `cssnano`, never from `@types/cssnano`\n- remove `@types/cssnano` if your project added it directly\n\n## Install\n\nInstall the runtime package and its PostCSS peer dependency:\n\n```bash\nnpm install cssnano postcss\nnpm install -D typescript\n```\n\nIf your project already added the old declaration package directly, remove it:\n\n```bash\nnpm uninstall @types/cssnano\n```\n\nNo credentials, API keys, service accounts, or package-specific environment variables are required.\n\n## Initialization\n\nThe important setup points are:\n\n- import the runtime package directly\n- keep `postcss` installed, because `cssnano` runs as a PostCSS processor/plugin creator\n- decide whether you want inline options or a config file discovered from the current working directory\n\n### Import from `cssnano`\n\nThe bundled declaration file uses `export =`, so the most portable TypeScript import is:\n\n```typescript\nimport cssnano = require(\"cssnano\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport cssnano from \"cssnano\";\n```\n\nDo not import anything from `@types/cssnano`.\n\n### Recommended `tsconfig.json`\n\nIf you prefer the default-import form, enable `esModuleInterop`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nYou do not need to add `cssnano` to `compilerOptions.types`. Its declarations are loaded from the imported runtime package.\n\n### Create a typed processor\n\nThe bundled declarations expose `cssnano.Options`, and calling `cssnano()` returns a `postcss.Processor`.\n\n```typescript\nimport type { Processor } from \"postcss\";\nimport cssnano = require(\"cssnano\");\n\nconst options: cssnano.Options = {\n  preset: \"default\",\n};\n\nconst processor: Processor = cssnano(options);\n```\n\nThis is the most useful TypeScript boundary in real projects: treat `cssnano()` as something that builds a configured PostCSS processor.\n\n## Common Workflows\n\n### Minify CSS directly in a Node or build script\n\n`cssnano()` returns a processor with the normal PostCSS `.process()` API.\n\n```typescript\nimport cssnano = require(\"cssnano\");\n\nasync function minifyCss(inputCss: string): Promise<string> {\n  const processor = cssnano({ preset: \"default\" });\n\n  const result = await processor.process(inputCss, {\n    from: \"src/app.css\",\n    to: \"dist/app.css\",\n  });\n\n  return result.css;\n}\n```\n\nPassing `from` and `to` gives PostCSS the file paths it uses for source-map and warning context.\n\n### Use `cssnano` inside a broader PostCSS pipeline\n\nThe PostCSS type definitions accept a `Processor` in the plugin list, so `cssnano({ ... })` can be composed into a normal pipeline.\n\n```typescript\nimport postcss from \"postcss\";\nimport cssnano from \"cssnano\";\n\nasync function optimizeCss(inputCss: string): Promise<string> {\n  const result = await postcss([\n    cssnano({ preset: \"default\" }),\n  ]).process(inputCss, {\n    from: \"src/app.css\",\n    to: \"dist/app.css\",\n  });\n\n  return result.css;\n}\n```\n\nIf your build already assembles a PostCSS plugin list, this is the cleanest integration point.\n\n### Load configuration automatically from the current project\n\nIf you call `cssnano()` without a `preset`, the runtime searches the current working directory for one of these files:\n\n- `package.json`\n- `.cssnanorc`\n- `.cssnanorc.json`\n- `.cssnanorc.yaml`\n- `.cssnanorc.yml`\n- `.cssnanorc.js`\n- `cssnano.config.js`\n\nFor a simple JSON config, create `.cssnanorc.json`:\n\n```json\n{\n  \"preset\": \"default\"\n}\n```\n\nThen let `cssnano` discover it:\n\n```typescript\nimport cssnano = require(\"cssnano\");\n\nconst processor = cssnano();\n```\n\nIf no config file is found, `cssnano` falls back to the built-in `default` preset.\n\n### Pin a specific config file\n\nUse `configFile` when the config is not in the current working directory or when a monorepo package needs an explicit path.\n\n```typescript\nimport cssnano = require(\"cssnano\");\n\nconst processor = cssnano({\n  configFile: \"config/cssnano.config.js\",\n});\n```\n\n`configFile` is resolved relative to `process.cwd()`, so pass the path you want from the current process root.\n\n### Reuse the option type in app code\n\nBecause the runtime package exports the namespace type, you can type reusable helpers without importing internal declaration files.\n\n```typescript\nimport cssnano = require(\"cssnano\");\n\nexport function createCssnanoOptions(prod: boolean): cssnano.Options {\n  return {\n    preset: \"default\",\n    configFile: prod ? \"config/cssnano.prod.js\" : \"config/cssnano.dev.js\",\n  };\n}\n```\n\nThis keeps your code aligned with the installed runtime package instead of duplicating option shapes manually.\n\n## Important Pitfalls\n\n- Install `postcss` as well as `cssnano`. The published `cssnano` package declares `postcss` as a peer dependency.\n- Import from `cssnano`, not from `@types/cssnano`.\n- If `import cssnano from \"cssnano\"` fails, enable `esModuleInterop` or switch to `import cssnano = require(\"cssnano\")`.\n- `cssnano()` without a `preset` reads config from `process.cwd()`, not from the source file that imports it.\n- `configFile` is also resolved from `process.cwd()`, so a relative path can point at the wrong file in monorepos or custom build runners.\n- The bundled `cssnano.Options` type is intentionally broad: `preset` is `any` and `plugins` is `any[]`, so TypeScript will not deeply validate every preset-specific option you write.\n- The published `cssnano` `5.1.15` package metadata has no `bin` entry. Use `cssnano` from PostCSS or from a Node build script rather than expecting a standalone `cssnano` CLI command.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/cssnano` package entry at version `5.1.3`.\n- Cached official npm registry metadata for `cssnano` shows no `types` field in `5.0.x`, and `types: \"types/index.d.ts\"` starting in `5.1.0`.\n- The `cssnano` `5.1.x` runtime line exposes a merged namespace type with `Options` and exports a function that returns a `postcss.Processor`.\n- The published `cssnano` `5.1.15` package metadata declares `postcss@^8.2.15` as its peer dependency.\n\n## Official Sources\n\n- npm package page for `@types/cssnano`: https://www.npmjs.com/package/@types/cssnano\n- npm package page for `cssnano`: https://www.npmjs.com/package/cssnano\n- `cssnano` repository: https://github.com/cssnano/cssnano\n- `cssnano` package metadata endpoint: https://registry.npmjs.org/cssnano\n- Published `cssnano` `5.1.15` tarball: https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz\n"
  },
  {
    "path": "content/typescript/docs/d3/typescript/DOC.md",
    "content": "---\nname: d3\ndescription: \"TypeScript declarations for the D3 umbrella package, including installation with the `d3` runtime, DOM-aware compiler setup, typed selections, scales, and data parsing.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.4.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,d3,visualization,svg,types,definitelytyped,npm\"\n---\n\n# D3 TypeScript Guide\n\n## Golden Rule\n\nInstall the real `d3` runtime package for code execution and `@types/d3` for TypeScript declarations.\n\nImport from `\"d3\"` in application code. Do not import from `\"@types/d3\"` directly.\n\n`@types/d3` is the umbrella declaration package for the `d3` bundle. It depends on the individual `@types/d3-*` packages that describe the modules re-exported by `d3` such as selections, scales, shapes, transitions, and time utilities.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declarations:\n\n```bash\nnpm install d3\nnpm install -D typescript @types/d3@7.4.3\n```\n\nIf your project already has `typescript`, add only the missing declarations:\n\n```bash\nnpm install -D @types/d3@7.4.3\n```\n\nThere is no package-specific environment variable, API key, or client initialization step.\n\n## TypeScript Setup\n\nTypeScript picks up `@types/d3` automatically after installation.\n\nFor browser or SVG work, include the DOM library so D3 selection types can refer to `Element`, `Document`, `Window`, `SVGSVGElement`, and related browser types:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nUse normal module imports from the runtime package:\n\n```typescript\nimport * as d3 from \"d3\";\n```\n\nIf your project targets only specific D3 submodules such as `d3-selection` or `d3-scale`, keep the runtime import path aligned with the package you actually install.\n\n## Common Workflows\n\n### Start with the umbrella `d3` import\n\nThe `d3` runtime re-exports the common D3 modules, so one namespace import is enough for many apps.\n\n```typescript\nimport * as d3 from \"d3\";\n\nconst values = [12, 28, 35, 44, 52];\n\nconst x = d3.scaleLinear([0, d3.max(values) ?? 0], [0, 480]);\nconst histogram = d3.bin().thresholds(5)(values);\n\nconsole.log(x(20));\nconsole.log(histogram.length);\n```\n\nThis is the main workflow `@types/d3` is designed for: the umbrella runtime package plus typed access to the re-exported module APIs.\n\n### Type SVG selections and bound data\n\nD3 selections are heavily generic. Supply the selected element type and the datum type to keep callback parameters accurate.\n\n```typescript\nimport * as d3 from \"d3\";\n\ntype Point = {\n  x: number;\n  y: number;\n  r: number;\n  label: string;\n};\n\nconst points: Point[] = [\n  { x: 40, y: 50, r: 6, label: \"A\" },\n  { x: 120, y: 90, r: 8, label: \"B\" },\n  { x: 220, y: 70, r: 5, label: \"C\" },\n];\n\nconst svg = d3.select<SVGSVGElement, unknown>(\"#chart\");\n\nsvg\n  .selectAll<SVGCircleElement, Point>(\"circle\")\n  .data(points)\n  .join(\"circle\")\n  .attr(\"cx\", (d) => d.x)\n  .attr(\"cy\", (d) => d.y)\n  .attr(\"r\", (d) => d.r);\n\nsvg\n  .selectAll<SVGTextElement, Point>(\"text\")\n  .data(points)\n  .join(\"text\")\n  .attr(\"x\", (d) => d.x + 10)\n  .attr(\"y\", (d) => d.y)\n  .text((d) => d.label);\n```\n\nWithout the generic arguments, element and datum types fall back to looser defaults and callback typing becomes less useful.\n\n### Build typed scales and line generators\n\nScale factories and shape generators carry type information through accessors and outputs.\n\n```typescript\nimport * as d3 from \"d3\";\n\ntype Sample = {\n  at: Date;\n  value: number;\n};\n\nconst samples: Sample[] = [\n  { at: new Date(\"2026-03-01\"), value: 18 },\n  { at: new Date(\"2026-03-02\"), value: 25 },\n  { at: new Date(\"2026-03-03\"), value: 21 },\n];\n\nconst width = 640;\nconst height = 240;\n\nconst x = d3.scaleTime(\n  d3.extent(samples, (d) => d.at) as [Date, Date],\n  [0, width],\n);\n\nconst y = d3.scaleLinear([0, d3.max(samples, (d) => d.value) ?? 0], [height, 0]);\n\nconst line = d3\n  .line<Sample>()\n  .x((d) => x(d.at))\n  .y((d) => y(d.value));\n\nconst pathData = line(samples);\n\nconsole.log(pathData);\n```\n\nThe explicit `line<Sample>()` call makes each accessor receive a strongly typed `Sample`.\n\n### Parse CSV into a typed application shape\n\nUse a row conversion function to move from string-based CSV input to a typed domain model.\n\n```typescript\nimport * as d3 from \"d3\";\n\ntype RevenuePoint = {\n  day: Date;\n  revenue: number;\n};\n\nconst csv = `day,revenue\n2026-03-01,42\n2026-03-02,48`;\n\nconst rows = d3.csvParse(csv, (row): RevenuePoint => ({\n  day: new Date(row.day),\n  revenue: Number(row.revenue),\n}));\n\nconsole.log(rows[0]?.revenue);\n```\n\nThis is usually better than relying on untyped string fields throughout the rest of the visualization code.\n\n## Important Pitfalls\n\n- Install `d3` separately. `@types/d3` only provides declarations.\n- Import from `\"d3\"`, not from `\"@types/d3\"`.\n- Include `\"DOM\"` in `compilerOptions.lib` for browser and SVG projects, because D3 selection declarations depend on browser element types.\n- The `d3` runtime package does not ship its own `.d.ts` files in the published package, so TypeScript projects still need `@types/d3` when importing the umbrella `d3` package.\n- The umbrella package metadata declares TypeScript `4.5`, but the bundled `@types/d3-*` dependencies can require newer compiler baselines. If TypeScript reports parse or declaration errors inside `node_modules/@types/d3-*`, upgrade to a current TypeScript 5.x release.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/d3\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/d3\n- https://github.com/d3/d3/blob/main/package.json\n- https://github.com/d3/d3/blob/main/src/index.js\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/d3-selection\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/d3-scale\n"
  },
  {
    "path": "content/typescript/docs/debug/typescript/DOC.md",
    "content": "---\nname: debug\ndescription: \"TypeScript declarations for the debug runtime package, including typed loggers, namespace control, and formatter extension\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.1.12\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,debug,logging,npm,types,definitelytyped\"\n---\n\n# debug TypeScript Guide\n\n`@types/debug` provides the TypeScript declarations for the `debug` runtime package. Use it when your project creates namespaced loggers with `debug(\"app:http\")`, enables them through `DEBUG`, and wants typed access to helpers such as `enable()`, `disable()`, `extend()`, and `formatters`.\n\nThis package only ships `.d.ts` files. Install the `debug` runtime separately.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install debug\nnpm install --save-dev @types/debug\n```\n\n`@types/debug@4.1.12` depends on `@types/ms` and declares `typeScriptVersion: \"4.5\"`, so use TypeScript 4.5 or newer.\n\nNo authentication or service initialization is required. In Node.js, logging is usually controlled with the `DEBUG` environment variable:\n\n```bash\nDEBUG=app:* node dist/server.js\nDEBUG=app:*,-app:sql node dist/server.js\n```\n\nPowerShell uses different syntax:\n\n```powershell\n$env:DEBUG = \"app:*,-app:sql\"\nnode dist/server.js\n```\n\n## Import `debug` In TypeScript\n\nThe declaration file uses `export = debug`, so the configuration-independent import style is:\n\n```ts\nimport debug = require(\"debug\");\n```\n\nIf your `tsconfig.json` enables `esModuleInterop`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport debug from \"debug\";\n```\n\nUse the `import = require()` form when you want the same code to work without TypeScript interop flags.\n\n## Create Namespaced Loggers\n\n```ts\nimport debug = require(\"debug\");\n\nconst httpLog = debug(\"app:http\");\nconst workerLog = debug(\"app:worker\");\n\nhttpLog(\"starting server on port %d\", 3000);\nworkerLog(\"picked job %O\", { id: \"job_123\", state: \"queued\" });\n```\n\nCalling `debug(namespace)` returns a `debug.Debugger`. The logger itself is a callable function, and the type surface also includes properties such as `enabled`, `namespace`, `color`, `log`, `extend()`, and `destroy()`.\n\n## Pass Typed Loggers Through Your Code\n\n```ts\nimport debug = require(\"debug\");\n\ntype Logger = debug.Debugger;\n\nexport function runJob(log: Logger, jobId: string, payload: unknown) {\n  if (!log.enabled) {\n    return;\n  }\n\n  log(\"running %s with payload %O\", jobId, payload);\n}\n\nconst jobsLog = debug(\"app:jobs\");\nrunJob(jobsLog, \"job_123\", { priority: \"high\" });\n```\n\nChecking `log.enabled` before building expensive debug data is the main typed integration boundary most applications need.\n\n## Enable, Disable, And Restore Namespaces\n\n```ts\nimport debug = require(\"debug\");\n\nconst jobsLog = debug(\"app:jobs\");\nconst sqlLog = debug(\"app:sql\");\n\ndebug.enable(\"app:*,-app:sql\");\n\njobsLog(\"visible\");\nsqlLog(\"hidden\");\n\nconst previousNamespaces = debug.disable();\n\ndebug.enable(previousNamespaces);\njobsLog(\"visible again\");\n```\n\n`debug.enable()` replaces the current namespace configuration; it does not merge with the existing `DEBUG` value. `debug.disable()` returns a namespace string that you can store and re-enable later.\n\n## Extend A Namespace\n\n```ts\nimport debug = require(\"debug\");\n\nconst authLog = debug(\"app:auth\");\nconst signLog = authLog.extend(\"sign\");\nconst loginLog = authLog.extend(\"login\");\n\nauthLog(\"starting auth flow\");\nsignLog(\"signing token for %s\", \"user_123\");\nloginLog(\"login accepted for %s\", \"user_123\");\n```\n\n`extend()` keeps the parent's output function and creates a child namespace such as `app:auth:sign`.\n\n## Add Custom Formatters\n\n```ts\nimport debug = require(\"debug\");\n\ndebug.formatters.k = (value: { kind: string }) => value.kind;\n\nconst log = debug(\"app:cache\");\nlog(\"event=%k\", { kind: \"miss\" });\n```\n\nThe type definition models `debug.formatters` as a string-keyed map of functions that return strings. Use this when you want a project-specific placeholder such as `%k`.\n\n## Browser Usage\n\nIn browsers, `debug` persists the enabled namespaces in `localStorage`. Set `localStorage.debug` before reloading the page:\n\n```ts\nlocalStorage.debug = \"app:*\";\n```\n\nThe factory and `Debugger` types are the same, but enabling output happens through browser storage instead of a shell environment variable.\n\n## Common Pitfalls\n\n- Install `debug` as well as `@types/debug`; the `@types` package does not include runtime JavaScript.\n- Prefer `import debug = require(\"debug\")` unless your compiler is explicitly configured for default-import interop.\n- `debug.enable()` overwrites the current namespace list instead of adding to it.\n- `debug.destroy()` is still present in the type surface, but the runtime marks it deprecated and it no longer does anything.\n- Custom formatter functions must return strings.\n- `DEBUG_COLORS`, `DEBUG_DEPTH`, `DEBUG_HIDE_DATE`, and `DEBUG_SHOW_HIDDEN` change Node.js formatting behavior.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/debug\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/debug\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/debug/index.d.ts\n- https://www.npmjs.com/package/debug\n- https://github.com/debug-js/debug/blob/master/README.md\n- https://github.com/debug-js/debug/blob/master/src/common.js\n- https://github.com/debug-js/debug/blob/master/src/node.js\n"
  },
  {
    "path": "content/typescript/docs/ejs/typescript/DOC.md",
    "content": "---\nname: ejs\ndescription: \"TypeScript declarations for EJS template rendering, compiled template functions, file-based rendering, and runtime options.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.1.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,ejs,templates,node,html,views,types,definitelytyped\"\n---\n\n# EJS TypeScript Guide\n\n`@types/ejs` provides TypeScript declarations for the `ejs` runtime package. Install it when your TypeScript code renders `.ejs` templates, compiles reusable template functions, or calls file-based helpers such as `renderFile()`.\n\nThis package only ships declarations. Your application still installs and imports the real `ejs` runtime.\n\n## Install\n\nInstall the runtime package first, then add the type package for TypeScript:\n\n```bash\nnpm install ejs\nnpm install -D typescript @types/ejs\n```\n\nNo environment variables, credentials, or client initialization are required.\n\nIf the same files also import Node built-ins such as `node:path`, install Node.js types too:\n\n```bash\nnpm install -D @types/node\n```\n\n## Import `ejs`\n\n`ejs` is published as a CommonJS module. The safest import form without interop flags is:\n\n```typescript\nimport ejs = require(\"ejs\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, you can use the more common default import:\n\n```typescript\nimport ejs from \"ejs\";\n```\n\nImport from `ejs`, not from `@types/ejs`.\n\n## Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n## Common Workflows\n\n### Render a template string with typed locals\n\nEJS types the function signatures, but it does not infer required template locals from the EJS markup itself. In practice, define a TypeScript type for the data you pass to `render()`.\n\n```typescript\nimport ejs from \"ejs\";\n\ntype WelcomeTemplateData = {\n  productName: string;\n  user: {\n    name: string;\n  };\n};\n\nconst template = `\n  <h1>Welcome to <%= productName %></h1>\n  <p>Hello, <%= user.name %>.</p>\n`;\n\nconst locals: WelcomeTemplateData = {\n  productName: \"Project Atlas\",\n  user: { name: \"Ada\" },\n};\n\nconst html = ejs.render(template, locals);\n```\n\nThis keeps the locals object checked in TypeScript while still using EJS's normal runtime API.\n\n### Compile once and wrap the result with a typed helper\n\n`compile()` is useful when the same template is rendered repeatedly.\n\n```typescript\nimport ejs from \"ejs\";\n\ntype ReceiptLocals = {\n  orderId: string;\n  total: number;\n};\n\nconst compiled = ejs.compile(`\n  <h1>Receipt</h1>\n  <p>Order: <%= orderId %></p>\n  <p>Total: $<%= total.toFixed(2) %></p>\n`);\n\nexport function renderReceipt(locals: ReceiptLocals): string {\n  return compiled(locals);\n}\n```\n\nWrapping the compiled function is the simplest way to keep a stable, typed boundary in application code.\n\n### Render a file and resolve includes\n\nUse `renderFile()` when you want file-based templates and relative include resolution.\n\n```typescript\nimport path from \"node:path\";\nimport ejs from \"ejs\";\n\ntype AccountPageLocals = {\n  user: {\n    name: string;\n  };\n};\n\nasync function renderAccountPage(locals: AccountPageLocals) {\n  const viewsDir = path.join(process.cwd(), \"views\");\n  const templatePath = path.join(viewsDir, \"account.ejs\");\n\n  return await ejs.renderFile(templatePath, locals, {\n    views: [viewsDir],\n    rmWhitespace: true,\n  });\n}\n```\n\nThis works cleanly with includes such as:\n\n```ejs\n<%- include(\"partials/header\") %>\n<h1><%= user.name %></h1>\n```\n\n### Use `filename` when rendering strings that include partials or use cache\n\nWhen you call `render()` or `compile()` directly, EJS does not know the template path unless you provide one. That path is also required when `cache: true` is enabled.\n\n```typescript\nimport path from \"node:path\";\nimport ejs from \"ejs\";\n\nconst template = `<%- include(\"partials/header\") %><h1><%= title %></h1>`;\n\nconst html = ejs.render(\n  template,\n  { title: \"Dashboard\" },\n  {\n    filename: path.join(process.cwd(), \"views\", \"dashboard.ejs\"),\n    cache: true,\n    views: [path.join(process.cwd(), \"views\")],\n  }\n);\n```\n\nIf you omit `filename`, includes and cache lookups do not have a stable file key.\n\n### Render async templates\n\nSet `async: true` when template code uses `await`. This changes the return type from `string` to `Promise<string>`.\n\n```typescript\nimport ejs from \"ejs\";\n\ntype InvoiceLocals = {\n  invoiceId: string;\n  loadTotal: (invoiceId: string) => Promise<number>;\n};\n\nconst renderInvoice = ejs.compile(\n  `<p>Total: $<%= await loadTotal(invoiceId) %></p>`,\n  { async: true }\n);\n\nconst html = await renderInvoice({\n  invoiceId: \"inv_123\",\n  loadTotal: async () => 42,\n});\n```\n\nUse this only in runtimes that support `async` and `await`.\n\n### Use strict mode with an explicit locals object name\n\nWhen `strict: true` is enabled, EJS also disables `with`, so template variables should be read from the locals object name you configure.\n\n```typescript\nimport ejs from \"ejs\";\n\nconst html = ejs.render(\n  `<h1><%= view.title %></h1><p><%= view.user.name %></p>`,\n  {\n    title: \"Settings\",\n    user: { name: \"Ada\" },\n  },\n  {\n    strict: true,\n    localsName: \"view\",\n  }\n);\n```\n\nThis avoids implicit variable lookup and makes the template's data boundary more explicit.\n\n## Important Pitfalls\n\n- Install `ejs` separately; `@types/ejs` does not include the runtime.\n- Import from `ejs`, not from `@types/ejs`.\n- `cache: true` requires a `filename` option.\n- Includes need a resolvable file context: use `renderFile()`, or pass `filename` plus `views` or `root` when rendering strings.\n- In EJS 3.x, the old preprocessor include syntax `<% include partial %>` is not supported; use `<%- include(\"partial\") %>`.\n- The one-object `render(dataAndOptions)` shortcut is documented but not recommended because option names can collide with template data keys.\n- `strict: true` disables `with`, so bare identifiers in templates no longer work unless you expose them through `localsName` or `destructuredLocals`.\n- `async: true` changes the render result to a promise-returning workflow.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/ejs==3.1.5`.\n- The runtime behavior described here matches the EJS 3.x API documented by the maintainer project.\n- Include preprocessor directives are unsupported in EJS 3.0 and later.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/ejs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ejs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ejs/index.d.ts\n- https://github.com/mde/ejs/blob/main/README.md\n- https://github.com/mde/ejs/blob/main/docs/syntax.md\n- https://github.com/mde/ejs/blob/main/lib/ejs.js\n"
  },
  {
    "path": "content/typescript/docs/electron/typescript/DOC.md",
    "content": "---\nname: electron\ndescription: \"TypeScript setup for Electron apps. `@types/electron@1.6.12` is the legacy DefinitelyTyped package; current projects should install `electron` and use its bundled declarations.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.6.12\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,electron,desktop,nodejs,types,definitelytyped\"\n---\n\n# Electron TypeScript Guide\n\n## Golden Rule\n\n`@types/electron@1.6.12` is a legacy package entry, not the package most current Electron apps should add.\n\nThe npm package page for `@types/electron` says Electron provides its own type definitions. In practice, install `electron`, import both runtime APIs and TypeScript types from `\"electron\"`, and remove `@types/electron` from modern projects.\n\nKeep `@types/electron` only when you are maintaining an older codebase that is intentionally pinned to a historical Electron toolchain.\n\n## Install\n\nFor a current Electron TypeScript project, install the Electron runtime plus your normal TypeScript and Node.js toolchain:\n\n```bash\nnpm install -D electron typescript @types/node\n```\n\nIf your project still lists the old DefinitelyTyped package directly, remove it:\n\n```bash\nnpm uninstall @types/electron\n```\n\nIf you are maintaining a legacy branch that still depends on the historical package entry, pin that package explicitly:\n\n```bash\nnpm install -D @types/electron@1.6.12\n```\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\n## Initialization\n\nThe important setup points are your compiler configuration, your import style, and the boundary between Electron's main process, preload script, and renderer code.\n\n### Recommended `tsconfig.json`\n\nFor a Node-based Electron main process or preload script, a practical baseline is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"lib\": [\"ES2022\", \"DOM\"],\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project explicitly restricts ambient type packages with `compilerOptions.types` and you still rely on the legacy `@types/electron` package, include `electron` there as well:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"electron\"]\n  }\n}\n```\n\nImport from `\"electron\"`, not from `\"@types/electron\"`.\n\n## Common Workflows\n\n### Create a typed main-process window\n\nImport both runtime values and types from `electron` and keep your browser-window options typed instead of redefining them locally.\n\n```ts\nimport { app, BrowserWindow, type BrowserWindowConstructorOptions } from \"electron\";\nimport { join } from \"node:path\";\n\nlet mainWindow: BrowserWindow | null = null;\n\nasync function createMainWindow(): Promise<void> {\n  const windowOptions: BrowserWindowConstructorOptions = {\n    width: 1200,\n    height: 800,\n    webPreferences: {\n      preload: join(__dirname, \"preload.js\"),\n      contextIsolation: true,\n      nodeIntegration: false,\n    },\n  };\n\n  mainWindow = new BrowserWindow(windowOptions);\n  await mainWindow.loadFile(join(__dirname, \"../renderer/index.html\"));\n}\n\napp.whenReady().then(() => {\n  void createMainWindow();\n\n  app.on(\"activate\", () => {\n    if (BrowserWindow.getAllWindows().length === 0) {\n      void createMainWindow();\n    }\n  });\n});\n\napp.on(\"window-all-closed\", () => {\n  if (process.platform !== \"darwin\") {\n    app.quit();\n  }\n});\n```\n\nThis keeps the runtime API and the option types in sync with the Electron package you actually ship.\n\n### Share typed IPC contracts between main and preload\n\nKeep channel names and payload types in a shared module, then use Electron's typed IPC APIs from both sides of the boundary.\n\n```ts\nexport type Settings = {\n  theme: \"light\" | \"dark\";\n};\n\nexport const settingsChannel = \"settings:read\";\n```\n\n```ts\nimport { ipcMain, type IpcMainInvokeEvent } from \"electron\";\n\nimport { settingsChannel, type Settings } from \"./shared/settings\";\n\nipcMain.handle(\n  settingsChannel,\n  async (_event: IpcMainInvokeEvent): Promise<Settings> => {\n    return { theme: \"dark\" };\n  },\n);\n```\n\n```ts\nimport { contextBridge, ipcRenderer } from \"electron\";\n\nimport { settingsChannel, type Settings } from \"./shared/settings\";\n\nexport type SettingsApi = {\n  read(): Promise<Settings>;\n};\n\nconst settingsApi: SettingsApi = {\n  read: () => ipcRenderer.invoke(settingsChannel) as Promise<Settings>,\n};\n\ncontextBridge.exposeInMainWorld(\"settings\", settingsApi);\n\ndeclare global {\n  interface Window {\n    settings: SettingsApi;\n  }\n}\n```\n\nThis is the most practical TypeScript pattern for Electron apps that use `contextIsolation` and do not expose Node APIs directly to the renderer.\n\n### Use the preload API from the renderer with a typed `window` surface\n\nOnce the preload script exposes a typed object, renderer code can consume it without `any` casts.\n\n```ts\ntype Settings = {\n  theme: \"light\" | \"dark\";\n};\n\nasync function applyTheme(): Promise<void> {\n  const settings: Settings = await window.settings.read();\n  document.documentElement.dataset.theme = settings.theme;\n}\n\nvoid applyTheme();\n```\n\nThe `Window` augmentation belongs in the preload-facing type layer for your app, not in ad hoc renderer assertions.\n\n## Important Pitfalls\n\n- `@types/electron` only affects TypeScript. It does not install or run Electron itself.\n- For current Electron versions, do not keep `@types/electron` installed next to `electron` unless you intentionally need that legacy setup; duplicate or conflicting declarations are the common failure mode.\n- Import values and types from `electron`, not from `@types/electron`.\n- If you use `compilerOptions.types`, remember that the legacy package is filtered out unless `electron` is listed there.\n- Main-process and preload code usually need Node.js types in addition to Electron types. Renderer code usually also needs DOM libs.\n- Keep shared IPC payload types in one module so the main process, preload script, and renderer stay aligned.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/electron` package entry at version `1.6.12`.\n- The npm package entry is a legacy path. For new work, the important package is `electron`, because that package provides the runtime and its own declarations.\n- If you are maintaining a truly old Electron codebase, check the matching Electron API documentation before copying newer patterns. APIs such as `contextBridge` and `ipcMain.handle` are modern Electron patterns, not universal across the oldest releases.\n\n## Official Sources\n\n- npm package page for `@types/electron`: https://www.npmjs.com/package/@types/electron\n- DefinitelyTyped source for `@types/electron`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/electron\n- Electron TypeScript documentation: https://www.electronjs.org/docs/latest/tutorial/typescript\n- Electron `app` API: https://www.electronjs.org/docs/latest/api/app\n- Electron `BrowserWindow` API: https://www.electronjs.org/docs/latest/api/browser-window\n- Electron `contextBridge` API: https://www.electronjs.org/docs/latest/api/context-bridge\n- Electron `ipcMain` API: https://www.electronjs.org/docs/latest/api/ipc-main\n"
  },
  {
    "path": "content/typescript/docs/eslint/typescript/DOC.md",
    "content": "---\nname: eslint\ndescription: \"TypeScript setup for ESLint, including when to use the built-in `eslint` types instead of `@types/eslint`, typed config files, Node API usage, and custom rule typing.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.6.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,eslint,linting,types,definitelytyped,node,npm\"\n---\n\n# ESLint TypeScript Guide\n\n## Golden Rule\n\nThis entry tracks `@types/eslint@9.6.1`, but current ESLint 9 releases already publish their own declaration files from the `eslint` runtime package.\n\nIn practice, that means most TypeScript projects should install `eslint` and import types from `\"eslint\"`, not from `\"@types/eslint\"`. The separate `@types/eslint` package is the DefinitelyTyped declaration package for the `eslint` module, but it does not cover newer runtime subpath entry points such as `\"eslint/config\"`.\n\nIf your project already depends on `@types/eslint`, keep imports pointed at `\"eslint\"` while you migrate. Do not write `import ... from \"@types/eslint\"`.\n\n## Install\n\nFor a current project using ESLint 9, install the runtime package and TypeScript:\n\n```bash\nnpm install -D eslint typescript\n```\n\nIf your repo is already pinned to the separate declaration package, add it as a dev dependency:\n\n```bash\nnpm install -D eslint @types/eslint typescript\n```\n\n`@types/eslint` also pulls in `@types/estree` and `@types/json-schema` automatically. No environment variables, credentials, or service initialization steps are required.\n\n## TypeScript Setup\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/eslint@9.6.1` declares a minimum TypeScript version of 4.8. Use TypeScript 4.8 or newer when this package is in your dependency graph.\n\n### Import Types From `eslint`\n\nUse the runtime module name as the TypeScript import boundary:\n\n```typescript\nimport { ESLint } from \"eslint\";\nimport type { Linter, Rule } from \"eslint\";\n```\n\nIf you only need types, use `import type`. Do not import from `@types/eslint` in source files.\n\n## Common Workflows\n\n### Type a flat config file\n\nFor ESLint 9 flat config files, type config objects from the `eslint` module and use the runtime helper from `eslint/config`:\n\n```typescript\nimport { defineConfig } from \"eslint/config\";\nimport type { Linter } from \"eslint\";\n\nconst appConfig: Linter.Config = {\n  files: [\"src/**/*.js\"],\n  rules: {\n    eqeqeq: \"error\",\n    \"no-console\": [\"warn\", { allow: [\"warn\", \"error\"] }],\n  },\n};\n\nexport default defineConfig([appConfig]);\n```\n\nThis is the safest setup for modern ESLint because the `eslint` runtime package publishes types for both `\"eslint\"` and `\"eslint/config\"`.\n\n### Run ESLint programmatically\n\n```typescript\nimport { ESLint } from \"eslint\";\n\nconst eslint = new ESLint({\n  overrideConfig: [\n    {\n      files: [\"src/**/*.js\"],\n      rules: {\n        eqeqeq: \"error\",\n        \"no-console\": \"warn\",\n      },\n    },\n  ],\n});\n\nconst results = await eslint.lintText(\"console.log(answer == 42)\\n\", {\n  filePath: \"src/example.js\",\n});\n\nconst formatter = await eslint.loadFormatter(\"stylish\");\nconsole.log(await formatter.format(results));\n```\n\n`ESLint.Options`, `ESLint.LintResult`, and related types are available from the same module when you need reusable annotations in tooling code.\n\n### Reuse the built-in core rule option types\n\nThe `eslint/rules` subpath exports typed rule entries for ESLint core rules.\n\n```typescript\nimport type { Linter } from \"eslint\";\nimport type { ESLintRules } from \"eslint/rules\";\n\ntype NoConsoleRule = ESLintRules[\"no-console\"];\n\nconst noConsole: NoConsoleRule = [\"error\", { allow: [\"warn\", \"error\"] }];\n\nconst rules: Linter.RulesRecord = {\n  \"no-console\": noConsole,\n};\n```\n\nThis is useful when you want reusable, precisely typed rule tuples instead of anonymous arrays.\n\n### Type a custom rule module\n\n```typescript\nimport type { Rule } from \"eslint\";\n\nexport const noFoo: Rule.RuleModule = {\n  meta: {\n    type: \"problem\",\n    docs: {\n      description: \"Disallow foo identifiers\",\n    },\n    schema: [],\n    messages: {\n      unexpected: \"Unexpected foo identifier.\",\n    },\n  },\n  create(context) {\n    return {\n      Identifier(node) {\n        if (node.name === \"foo\") {\n          context.report({ node, messageId: \"unexpected\" });\n        }\n      },\n    };\n  },\n};\n```\n\n`Rule.RuleModule`, `Rule.RuleListener`, and `Rule.RuleMetaData` are the key types when authoring plugins or internal rule packs.\n\n## Important Pitfalls\n\n- Current ESLint 9 releases already publish their own declaration files. For most ESLint 9 projects, installing `eslint` is enough.\n- Do not import from `@types/eslint` in code. Even when you install the declaration package, your imports should still target `\"eslint\"` or the documented `eslint` subpath.\n- `@types/eslint@9.6.1` exports types for `\"eslint\"`, `\"eslint/rules\"`, and `\"eslint/use-at-your-own-risk\"`. It does not export the newer `\"eslint/config\"` or `\"eslint/universal\"` entry points that the current runtime package types provide.\n- The `eslint/use-at-your-own-risk` types include deprecated APIs such as `FlatESLint`, `LegacyESLint`, `builtinRules`, and `shouldUseFlatConfig()`. Prefer the stable `ESLint` class and the flat config API.\n- `@types/eslint` is types only. It does not install the ESLint CLI or runtime.\n- `@types/eslint@9.6.1` requires TypeScript 4.8 or newer.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/eslint==9.6.1`.\n- The package metadata lists `@types/estree` and `@types/json-schema` as dependencies, so you usually do not add them manually.\n- Current ESLint 9 runtime packages ship their own types; if you are starting fresh, prefer the runtime package's declarations.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/eslint\n- DefinitelyTyped source for `@types/eslint`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/eslint\n- ESLint npm package page: https://www.npmjs.com/package/eslint\n- ESLint repository: https://github.com/eslint/eslint\n- ESLint configuration docs: https://eslint.org/docs/latest/use/configure\n- ESLint getting started guide: https://eslint.org/docs/latest/use/getting-started#prerequisites\n- ESLint `no-console` rule reference: https://eslint.org/docs/latest/rules/no-console\n"
  },
  {
    "path": "content/typescript/docs/estree/typescript/DOC.md",
    "content": "---\nname: estree\ndescription: \"TypeScript declarations for ESTree AST nodes, including how to import the `estree` module, type AST traversal code, and handle parser-specific extensions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.0.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,estree,ast,types,definitelytyped,npm\"\n---\n\n# ESTree TypeScript Guide\n\n## What This Package Provides\n\n`@types/estree` is the DefinitelyTyped declaration package for the `estree` module. It gives you TypeScript interfaces and unions for ESTree-compatible abstract syntax trees, including `Program`, `Node`, `Statement`, `Expression`, `Identifier`, `Literal`, `Comment`, and `SourceLocation`.\n\nThis package is declarations only:\n\n- It does not parse source code.\n- It does not walk or transform ASTs.\n- It does not require environment variables, credentials, or runtime initialization.\n\nInstall a parser or traversal library separately when you need runtime behavior.\n\n## Install\n\nInstall the declarations as a development dependency:\n\n```bash\nnpm install -D typescript @types/estree\n```\n\nThe published package metadata declares a minimum TypeScript version of `5.1`, so use TypeScript 5.1 or newer.\n\nWhen you use the package in source code, import from `\"estree\"`:\n\n```typescript\nimport type { Expression, Node, Program } from \"estree\";\n```\n\nDo not try to import from `\"@types/estree\"` in application code.\n\n## TypeScript Setup\n\nNo package-specific compiler configuration is required beyond normal `node_modules` resolution. A minimal strict setup looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nUse `import type` for AST-only dependencies so the declarations stay on the type side of your program.\n\n## Common Workflows\n\n### Narrow node unions with `type`\n\nThe definitions are built around discriminated unions, so checking `node.type` narrows to the matching ESTree interface.\n\n```typescript\nimport type { Expression } from \"estree\";\n\nexport function describeExpression(expression: Expression): string {\n  switch (expression.type) {\n    case \"Identifier\":\n      return `identifier:${expression.name}`;\n    case \"Literal\":\n      return `literal:${String(expression.value)}`;\n    case \"CallExpression\":\n      return `call:${expression.callee.type}`;\n    default:\n      return expression.type;\n  }\n}\n```\n\nThis is the main reason to use the package directly instead of treating AST values as loose objects.\n\n### Type AST traversal code\n\nLibraries that consume ESTree nodes commonly type against the `estree` module. For example, `estree-walker`'s published types use `import(\"estree\").Node`.\n\n```typescript\nimport { walk } from \"estree-walker\";\nimport type { Program } from \"estree\";\n\nexport function collectIdentifiers(program: Program): string[] {\n  const names: string[] = [];\n\n  walk(program, {\n    enter(node) {\n      if (node.type === \"Identifier\") {\n        names.push(node.name);\n      }\n    },\n  });\n\n  return names;\n}\n```\n\nIf your parser returns an ESTree-compatible AST, typing the boundary as `Program` or `Node` makes walker callbacks narrow correctly.\n\n### Type AST fixtures and test data\n\nUse `satisfies` or an explicit annotation when building AST fixtures by hand.\n\n```typescript\nimport type { Program } from \"estree\";\n\nexport const emptyModule = {\n  type: \"Program\",\n  sourceType: \"module\",\n  body: [],\n} satisfies Program;\n```\n\nThis catches misspelled node kinds and missing required fields without widening everything to `any`.\n\n### Add parser-specific fields at the integration boundary\n\n`@types/estree` models the shared ESTree node surface. If your parser or tool attaches extra metadata, extend the base types locally.\n\n```typescript\nimport type { Program } from \"estree\";\n\ntype ParsedProgram = Program & {\n  tokens?: unknown[];\n};\n\nexport function getTokenCount(program: ParsedProgram): number {\n  return program.tokens?.length ?? 0;\n}\n```\n\nKeep the core AST typed as ESTree, then layer tool-specific fields on top instead of rewriting the whole node model.\n\n## Common Pitfalls\n\n- `@types/estree` does not ship a runtime parser. Pair it with a parser or AST tool when you need to create or traverse nodes.\n- Import types from `\"estree\"`, not from the `@types` package name.\n- `Program.body` is not only statements. In the published definitions it is `Array<Directive | Statement | ModuleDeclaration>`, so module code can contain imports and exports at the top level.\n- The base node types include optional location and comment data such as `loc`, `range`, `leadingComments`, `trailingComments`, and `Program.comments`, but parser-specific fields outside that surface are not guaranteed.\n- `1.0.8` includes newer ESTree shapes such as `ChainExpression`, `ImportExpression`, `PrivateIdentifier`, `PropertyDefinition`, `StaticBlock`, and `VariableDeclaration.kind` values `\"using\"` and `\"await using\"`. Your parser or downstream tooling may support a narrower syntax set even though the type package includes them.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/estree\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/estree/index.d.ts\n- https://github.com/Rich-Harris/estree-walker#readme\n"
  },
  {
    "path": "content/typescript/docs/exceljs/typescript/DOC.md",
    "content": "---\nname: exceljs\ndescription: \"TypeScript setup for `exceljs`. `@types/exceljs@1.3.2` is a deprecated stub package, so install `exceljs` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,exceljs,xlsx,node,types,definitelytyped,npm\"\n---\n\n# ExcelJS TypeScript Guide\n\n## Golden Rule\n\n`@types/exceljs@1.3.2` is not the package you should add to a modern TypeScript project.\n\nThe npm package page for `@types/exceljs` marks it as a stub package and says that `exceljs` provides its own type definitions. Install the real `exceljs` runtime package and import both runtime APIs and TypeScript types from `exceljs`.\n\nIf an older project still has `@types/exceljs` in its lockfile, remove it unless that project is intentionally pinned to a historical setup.\n\n## Install\n\nInstall `exceljs` and the normal TypeScript toolchain for a Node.js application:\n\n```bash\nnpm install exceljs\nnpm install -D typescript @types/node\n```\n\nIf your project already added the old stub package directly, remove it:\n\n```bash\nnpm uninstall @types/exceljs\n```\n\n## Initialization\n\nThere are no package-specific credentials, auth steps, environment variables, or client objects to configure.\n\nThe practical setup points are your TypeScript compiler options, your import style, and whether your runtime code reads or writes `.xlsx` files from Node.js.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`esModuleInterop` lets you use a default import. If your project does not enable it, use the CommonJS-style import form shown below.\n\n### Import `exceljs`\n\nWith `esModuleInterop` enabled:\n\n```typescript\nimport ExcelJS from \"exceljs\";\n\nconst excelFile = new ExcelJS.Workbook();\n```\n\nWithout `esModuleInterop`, use:\n\n```typescript\nimport ExcelJS = require(\"exceljs\");\n\nconst excelFile = new ExcelJS.Workbook();\n```\n\nImport from `exceljs`, never from `@types/exceljs`.\n\n## Common Workflows\n\n### Create an `.xlsx` file from typed row data\n\nDefine the row shape in your own application code, then map those objects into sheet rows.\n\n```typescript\nimport ExcelJS from \"exceljs\";\n\ntype UserRow = {\n  id: number;\n  name: string;\n  email: string;\n};\n\nconst rows: UserRow[] = [\n  { id: 1, name: \"Ada\", email: \"ada@example.com\" },\n  { id: 2, name: \"Linus\", email: \"linus@example.com\" },\n];\n\nconst excelFile = new ExcelJS.Workbook();\nconst sheet = excelFile.addWorksheet(\"Users\");\n\nsheet.columns = [\n  { header: \"ID\", key: \"id\", width: 10 },\n  { header: \"Name\", key: \"name\", width: 24 },\n  { header: \"Email\", key: \"email\", width: 32 },\n];\n\nrows.forEach((row) => {\n  sheet.addRow(row);\n});\n\nawait excelFile.xlsx.writeFile(\"users.xlsx\");\n```\n\nThe type safety comes from your `UserRow` interface and your own app logic. `exceljs` does not infer a strict row schema from `sheet.columns`.\n\n### Read a file and narrow cell values before using them\n\nCell values are typed as a union, so narrow them before calling string, number, or date-specific APIs.\n\n```typescript\nimport ExcelJS from \"exceljs\";\n\nconst excelFile = new ExcelJS.Workbook();\nawait excelFile.xlsx.readFile(\"users.xlsx\");\n\nconst sheet = excelFile.getWorksheet(\"Users\");\n\nif (!sheet) {\n  throw new Error(\"Users sheet not found\");\n}\n\nsheet.eachRow((row, rowNumber) => {\n  if (rowNumber === 1) {\n    return;\n  }\n\n  const idValue = row.getCell(1).value;\n  const nameValue = row.getCell(2).value;\n  const emailValue = row.getCell(3).value;\n\n  if (\n    typeof idValue === \"number\" &&\n    typeof nameValue === \"string\" &&\n    typeof emailValue === \"string\"\n  ) {\n    console.log({ id: idValue, name: nameValue, email: emailValue });\n  }\n});\n```\n\nThis is the main TypeScript boundary when reading cell data: treat `.value` as a union and narrow it deliberately.\n\n### Use file paths from Node helpers\n\nWhen your code loads or saves files from a script, CLI, or server process, resolve paths explicitly instead of relying on the current working directory.\n\n```typescript\nimport ExcelJS from \"exceljs\";\nimport { join } from \"node:path\";\n\nconst excelFile = new ExcelJS.Workbook();\nconst outputPath = join(process.cwd(), \"artifacts\", \"report.xlsx\");\n\nconst sheet = excelFile.addWorksheet(\"Report\");\nsheet.addRow([\"status\", \"ok\"]);\n\nawait excelFile.xlsx.writeFile(outputPath);\n```\n\nThis keeps Node-based file handling predictable in tests, CLIs, and monorepos.\n\n## Important Pitfalls\n\n- `@types/exceljs` is a deprecated stub package. Install `exceljs` instead.\n- Import from `exceljs`, not from `@types/exceljs`.\n- If `import ExcelJS from \"exceljs\"` fails in your project, enable `esModuleInterop` or switch to `import ExcelJS = require(\"exceljs\")`.\n- `getWorksheet()` can return `undefined`; guard that result before reading rows or cells.\n- Cell `.value` is a union type. Narrow it before using string, number, or date-specific operations.\n- Node file helpers such as `readFile()` and `writeFile()` assume filesystem access; use the runtime APIs that match your environment.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/exceljs==1.3.2`.\n- The published `@types/exceljs` package is a stub entry, not the recommended installation path for new projects.\n- For modern TypeScript code, depend on `exceljs` and use the declarations bundled with that runtime package.\n- If you maintain an older lockfile that still contains `@types/exceljs`, remove the stub package before troubleshooting import or duplicate-type issues.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/exceljs\n- https://www.npmjs.com/package/exceljs\n- https://github.com/exceljs/exceljs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/exceljs\n"
  },
  {
    "path": "content/typescript/docs/express/typescript/DOC.md",
    "content": "---\nname: express\ndescription: \"TypeScript declarations for Express applications, routers, middleware, request and response generics, and declaration merging.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.0.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,express,node,http,middleware,types,definitelytyped\"\n---\n\n# Express TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/express` alongside the real `express` runtime package.\n\n`@types/express` only provides TypeScript declarations. Your application imports and runs `express`; the declaration package supplies the types for `express()`, `Router()`, `Request`, `Response`, `RequestHandler`, built-in middleware such as `express.json()`, and the global `Express` namespace used for declaration merging.\n\n## Install\n\nInstall the runtime package in your app, then add the declaration package and Node.js types for TypeScript.\n\n```bash\nnpm install express\nnpm install -D typescript @types/express @types/node\n```\n\nIf your project already has `express`, add only the missing declarations:\n\n```bash\nnpm install -D @types/express @types/node\n```\n\n`@types/express` pulls in its own related declaration dependencies, including `@types/express-serve-static-core`, `@types/body-parser`, and `@types/serve-static`.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup points are your import style, your TypeScript compiler options, and how you type route handlers.\n\n### Import `express`\n\nThe declaration package uses `export =`, so the safest CommonJS-style import is:\n\n```typescript\nimport express = require(\"express\");\n\nconst app = express();\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, you can use the more common default import form:\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n```\n\nFor type-only imports in handlers and helpers, import from `express`, not from `@types/express`:\n\n```typescript\nimport type { NextFunction, Request, Response } from \"express\";\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict loaded ambient type packages with `compilerOptions.types`, include at least `node` and `express` in the list used by the project that compiles your server code:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"express\"]\n  }\n}\n```\n\n### Create an app and enable built-in middleware\n\nThe declarations expose the built-in middleware helpers on the top-level `express` export.\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\napp.use(\"/public\", express.static(\"public\"));\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n```\n\n## Common Workflows\n\n### Use route literal inference for `req.params`\n\nThe core typings infer route parameters from string literal paths passed directly to `app.get()`, `app.post()`, and other router methods.\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n\napp.get(\"/users/:userId/books/:bookId\", (req, res) => {\n  const { userId, bookId } = req.params;\n\n  res.json({ userId, bookId });\n});\n```\n\nIn this pattern, `req.params.userId` and `req.params.bookId` are typed as `string`.\n\n### Add explicit generics for params, body, query, and response\n\nWhen you need stronger typing than the defaults, use the generics on `Request` and `Response`.\n\nThe generic order is:\n\n`Request<Params, ResBody, ReqBody, ReqQuery, Locals>`\n\n```typescript\nimport express, { type Request, type Response } from \"express\";\n\nconst app = express();\napp.use(express.json());\n\ntype CreateUserParams = {\n  orgId: string;\n};\n\ntype CreateUserBody = {\n  email: string;\n  displayName: string;\n};\n\ntype CreateUserQuery = {\n  invite?: \"true\" | \"false\";\n};\n\ntype CreateUserResponse = {\n  id: string;\n  email: string;\n};\n\napp.post(\n  \"/orgs/:orgId/users\",\n  (\n    req: Request<CreateUserParams, CreateUserResponse, CreateUserBody, CreateUserQuery>,\n    res: Response<CreateUserResponse>,\n  ) => {\n    const { orgId } = req.params;\n    const { email, displayName } = req.body;\n    const shouldInvite = req.query.invite === \"true\";\n\n    res.status(201).json({\n      id: `${orgId}-${displayName}`,\n      email: shouldInvite ? email.toLowerCase() : email,\n    });\n  },\n);\n```\n\nThis is the most useful pattern when your route body or query shape matters to the rest of your app.\n\n### Type middleware and `res.locals`\n\n`RequestHandler` and `Response` both accept a `Locals` generic so middleware can populate `res.locals` in a typed way.\n\n```typescript\nimport express, {\n  type RequestHandler,\n  type Response,\n} from \"express\";\n\nconst app = express();\n\ntype AuthLocals = {\n  requestId: string;\n  userId: string;\n};\n\nconst requireAuth: RequestHandler<any, any, any, any, AuthLocals> = (\n  req,\n  res,\n  next,\n) => {\n  const userId = req.header(\"x-user-id\");\n\n  if (!userId) {\n    res.status(401).json({ error: \"missing x-user-id\" });\n    return;\n  }\n\n  res.locals.requestId = req.header(\"x-request-id\") ?? \"generated-request-id\";\n  res.locals.userId = userId;\n  next();\n};\n\napp.get(\n  \"/me\",\n  requireAuth,\n  (_req, res: Response<{ userId: string; requestId: string }, AuthLocals>) => {\n    res.json({\n      userId: res.locals.userId,\n      requestId: res.locals.requestId,\n    });\n  },\n);\n```\n\nUse this when multiple middleware layers need to share typed request-scoped state without falling back to `any`.\n\n### Extend `Express.Request` or `Express.Locals` with declaration merging\n\nThe core declarations intentionally expose open interfaces in the global `Express` namespace so applications can add their own fields.\n\nCreate a `.d.ts` file that your TypeScript project includes, for example `src/types/express.d.ts`:\n\n```typescript\nexport {};\n\ndeclare global {\n  namespace Express {\n    interface Request {\n      authToken?: string;\n    }\n\n    interface Locals {\n      tenantId?: string;\n    }\n  }\n}\n```\n\nThen use the merged fields in middleware and handlers:\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n\napp.use((req, res, next) => {\n  req.authToken = req.header(\"authorization\") ?? undefined;\n  res.locals.tenantId = req.header(\"x-tenant-id\") ?? undefined;\n  next();\n});\n\napp.get(\"/context\", (req, res) => {\n  res.json({\n    authToken: req.authToken ?? null,\n    tenantId: res.locals.tenantId ?? null,\n  });\n});\n```\n\nThis is usually the cleanest option for application-wide request or locals extensions.\n\n### Type error-handling middleware\n\nThe package also exposes `ErrorRequestHandler` with the same generic order as `RequestHandler`.\n\n```typescript\nimport express, { type ErrorRequestHandler } from \"express\";\n\nconst app = express();\n\nconst onError: ErrorRequestHandler = (err, _req, res, _next) => {\n  const message = err instanceof Error ? err.message : \"unexpected error\";\n  res.status(500).json({ error: message });\n};\n\napp.use(onError);\n```\n\nThis keeps your terminal error middleware compatible with Express while preserving typed access to `req`, `res`, and `res.locals` when you need it.\n\n## Important Pitfalls\n\n- `@types/express` is a declaration package only. Install and import `express` at runtime.\n- Import code and types from `express`, not from `@types/express`.\n- The default import form depends on TypeScript interop settings. Without interop, use `import express = require(\"express\")`.\n- Route-param inference works best when the route path is an inline string literal. If you widen the path to a plain `string`, TypeScript can no longer infer named params from it.\n- `req.query` defaults to the parsed query-object type from `qs`; if you want an application-specific query shape, pass the `ReqQuery` generic explicitly.\n- `req.body` is not validated by these declarations. The generic only tells TypeScript what shape your handler expects.\n- If you rely on custom `req` or `res.locals` properties across the whole app, prefer declaration merging over repeated local type assertions.\n- If your project uses `compilerOptions.types`, make sure `node` and `express` are still included or the declarations may appear to disappear.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/express==5.0.6`.\n- The published package declares a minimum TypeScript version of `5.2`.\n- `@types/express==5.0.6` depends on `@types/express-serve-static-core` `^5.0.0`, `@types/body-parser`, and `@types/serve-static`.\n- The top-level export includes typed helpers for `express.json()`, `express.raw()`, `express.text()`, `express.urlencoded()`, `express.static()`, and `express.Router()`.\n- The core router typings include string-literal route parameter inference and open `Express.Request` / `Express.Locals` interfaces for declaration merging.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/express\n- DefinitelyTyped source for `@types/express`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/express\n- `@types/express` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts\n- DefinitelyTyped source for `@types/express-serve-static-core`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/express-serve-static-core\n- Express runtime documentation: https://expressjs.com/\n"
  },
  {
    "path": "content/typescript/docs/express-session/typescript/DOC.md",
    "content": "---\nname: express-session\ndescription: \"TypeScript declarations for express-session middleware, request augmentation, SessionData merging, cookie options, and store APIs.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.18.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,express,express-session,cookies,node,authentication,types,definitelytyped\"\n---\n\n# express-session TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/express-session` alongside the real `express-session` runtime package.\n\n`@types/express-session` only provides TypeScript declarations. Your application still imports and runs `express-session`; the declaration package adds typings for:\n\n- the `session()` middleware factory\n- `Express.Request` properties such as `req.session`, `req.sessionID`, and `req.sessionStore`\n- `SessionData`, which is the intended extension point for your app-specific session fields\n- session cookie options and store interfaces\n\n## Install\n\nInstall the runtime package first, then the declaration packages your server code depends on:\n\n```bash\nnpm install express express-session\nnpm install --save-dev typescript @types/express @types/express-session @types/node\n```\n\nThe middleware itself does not create credentials, but most apps should provide a secret through the environment rather than hard-coding it:\n\n```bash\nexport SESSION_SECRET=\"replace-this-with-a-long-random-secret\"\nexport NODE_ENV=\"development\"\n```\n\nThe declarations document that `secret` can be a single value or an array of values, and note that HMAC-256 signing means the secret should contain at least 32 bytes of entropy.\n\n## TypeScript Setup\n\n`express-session` uses `export =` in its type declarations.\n\nWithout `esModuleInterop`, use the CommonJS-compatible import form:\n\n```ts\nimport session = require(\"express-session\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import works:\n\n```ts\nimport session from \"express-session\";\n```\n\nIf your project restricts ambient type loading with `compilerOptions.types`, include `express-session` explicitly and make sure your custom `.d.ts` files are part of the compilation:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"express\", \"express-session\"]\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\"]\n}\n```\n\nImport runtime values and types from `express-session`, not from `@types/express-session`.\n\n## Initialize The Middleware\n\nThere is no client object to create. The practical setup is an Express app with `express-session` middleware configured before the routes that use `req.session`.\n\n```ts\nimport express from \"express\";\nimport session from \"express-session\";\n\nconst sessionSecret = process.env.SESSION_SECRET;\n\nif (!sessionSecret) {\n  throw new Error(\"SESSION_SECRET is required\");\n}\n\nconst app = express();\n\napp.use(express.json());\n\napp.use(\n  session({\n    name: \"sid\",\n    secret: sessionSecret,\n    resave: false,\n    saveUninitialized: false,\n    proxy: process.env.NODE_ENV === \"production\",\n    cookie: {\n      httpOnly: true,\n      sameSite: \"lax\",\n      secure: process.env.NODE_ENV === \"production\" ? \"auto\" : false,\n      maxAge: 1000 * 60 * 60 * 24 * 7,\n    },\n  }),\n);\n```\n\nChoose `resave` and `saveUninitialized` explicitly. In the declarations, both still describe a default of `true`, but also mark relying on that default as deprecated because it may change.\n\nIf you run behind a reverse proxy and rely on secure cookies, configure proxy handling before assuming `cookie.secure` will work the way you expect. The type declarations support both the middleware's `proxy` option and `cookie.secure: \"auto\"`.\n\n## Add Application Fields To `SessionData`\n\n`SessionData` is the supported extension point for your app's own session values.\n\nCreate a declaration file such as `src/types/express-session.d.ts`:\n\n```ts\ndeclare module \"express-session\" {\n  interface SessionData {\n    userId?: string;\n    returnTo?: string;\n    flash?: {\n      type: \"error\" | \"success\";\n      message: string;\n    };\n  }\n}\n\nexport {};\n```\n\nThis follows the declaration-merging pattern documented directly in the package's `SessionData` comments.\n\nAfter the merge, `req.session.userId`, `req.session.returnTo`, and `req.session.flash` become known to TypeScript anywhere the augmentation file is included.\n\nOne important detail from the request typing: `req.session` is declared as `session.Session & Partial<session.SessionData>`. That means custom fields still need normal undefined checks until your code initializes them.\n\n## Common Workflows\n\n### Read And Write Typed Session Values\n\nOnce you augment `SessionData`, route handlers can read and write those fields through `req.session`.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.get(\"/me\", (req, res) => {\n  if (!req.session.userId) {\n    res.status(401).json({ error: \"not signed in\" });\n    return;\n  }\n\n  res.json({\n    userId: req.session.userId,\n    expiresAt: req.session.cookie.expires,\n  });\n});\n```\n\n`req.session.cookie` is always available on the typed session object, even when your own merged fields are still unset.\n\n### Regenerate The Session Before Setting Identity\n\nThe `Session` class exposes callback-based lifecycle methods including `regenerate()`, `save()`, `reload()`, and `destroy()`.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.post(\"/login\", (req, res, next) => {\n  const userId = \"user_123\";\n\n  req.session.regenerate((err) => {\n    if (err) {\n      next(err);\n      return;\n    }\n\n    req.session.userId = userId;\n\n    req.session.save((saveErr) => {\n      if (saveErr) {\n        next(saveErr);\n        return;\n      }\n\n      res.status(204).end();\n    });\n  });\n});\n```\n\nThe type declarations document `save()` as useful for cases such as redirects and other flows where you do not want to rely only on the automatic save at the end of the HTTP response.\n\n### Destroy The Session On Logout\n\n`destroy()` is also callback-based and unsets `req.session` when it completes.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.post(\"/logout\", (req, res, next) => {\n  req.session.destroy((err) => {\n    if (err) {\n      next(err);\n      return;\n    }\n\n    res.clearCookie(\"sid\");\n    res.status(204).end();\n  });\n});\n```\n\nIf you customize the cookie name with the `name` option, clear the same cookie name on logout.\n\n### Adjust Cookie Settings With Typed Literals\n\nThe declarations model cookie settings directly on `req.session.cookie`, including `maxAge`, `httpOnly`, `secure`, `sameSite`, `domain`, `path`, `priority`, and `partitioned`.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.post(\"/remember-me\", (req, res) => {\n  req.session.cookie.maxAge = 1000 * 60 * 60 * 24 * 30;\n  req.session.cookie.sameSite = \"lax\";\n  req.session.cookie.priority = \"high\";\n  req.session.touch();\n\n  res.status(204).end();\n});\n```\n\nUse `maxAge` rather than setting `expires` directly. In the declarations, `expires` is marked deprecated in favor of `maxAge`.\n\n## Integration Boundary\n\n`@types/express-session` covers the shared TypeScript layer around the runtime middleware. In a typical app you still need:\n\n- `express-session` for the actual middleware behavior\n- `express` and `@types/express` for the request/response types that get augmented\n- your own `.d.ts` file to define the shape of application-specific session data\n- a separate store package if you do not want the default in-memory store\n\nThe type declarations expose `session.Store` and `session.MemoryStore`, and model store methods such as `get()`, `set()`, `destroy()`, and optional helpers like `touch()`.\n\n## Important Pitfalls\n\n- Install `express-session` as well as `@types/express-session`; the type package does not include runtime JavaScript.\n- Do not import from `@types/express-session`; import from `express-session`.\n- If you restrict `compilerOptions.types`, include `express-session` or the `Express.Request` augmentation will not load.\n- Keep your `declare module \"express-session\"` file inside the paths matched by your project's `include` or `files` settings.\n- `req.session`, `req.sessionID`, and `req.sessionStore` are only present at runtime after the middleware has run.\n- Because `req.session` includes `Partial<SessionData>`, your custom properties are usually optional until you initialize them.\n- `MemoryStore` is typed, but the declarations explicitly warn that it is only meant for debugging and development and is not suitable for production.\n- If you change the `secret`, existing signed cookies stop validating; provide an array when you need secret rotation without immediately invalidating existing cookies.\n- If multiple apps share the same hostname, set a distinct `name` instead of relying on the default `connect.sid` cookie name.\n\n## Version-Sensitive Notes\n\n- `@types/express-session@1.18.2` declares `typeScriptVersion: \"5.1\"` in its package metadata.\n- In this version, `CookieOptions` includes modern attributes such as `partitioned`, `priority`, `sameSite`, and `secure: \"auto\"`.\n- In this version, `req.sessionStore` is typed as `session.Store & { generate: (req: Request) => void }`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/express-session\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/express-session\n- https://github.com/expressjs/session\n- https://www.typescriptlang.org/docs/handbook/declaration-merging.html\n"
  },
  {
    "path": "content/typescript/docs/fs-extra/typescript/DOC.md",
    "content": "---\nname: fs-extra\ndescription: \"TypeScript declarations for fs-extra's extended filesystem helpers, promise-based workflows, and Node fs-compatible imports.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"11.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,fs-extra,nodejs,filesystem,types,definitelytyped\"\n---\n\n# fs-extra TypeScript Guide\n\n`@types/fs-extra` adds TypeScript declarations for the `fs-extra` runtime package.\n\nInstall it when your project imports `fs-extra` for helpers such as `copy`, `ensureDir`, `move`, `outputFile`, `readJson`, `writeJson`, `pathExists`, and `remove`.\n\nThis package only provides `.d.ts` files. Your application code still runs the real `fs-extra` package.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install fs-extra\nnpm install -D typescript @types/fs-extra\n```\n\nIf `fs-extra` and TypeScript are already present, add only the missing declarations:\n\n```bash\nnpm install -D @types/fs-extra\n```\n\nImport runtime code from `\"fs-extra\"`, not from `\"@types/fs-extra\"`.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe important setup points are your import style and your TypeScript compiler options.\n\n### Import `fs-extra`\n\nThe safest import form for CommonJS-style typings is:\n\n```typescript\nimport fs = require(\"fs-extra\");\n```\n\nIf your project enables interoperability for default imports from CommonJS packages, you can use:\n\n```typescript\nimport fs from \"fs-extra\";\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you prefer `import fs = require(\"fs-extra\")`, `esModuleInterop` is not required for this package.\n\n## Common Workflows\n\n### Ensure a directory and persist JSON\n\n`fs-extra` adds filesystem helpers on top of Node's `fs` API. A common pattern is creating a directory, writing a JSON file, then loading it later.\n\n```typescript\nimport fs from \"fs-extra\";\nimport { join } from \"node:path\";\n\ntype AppConfig = {\n  outDir: string;\n  retries: number;\n};\n\nconst configDir = join(process.cwd(), \".example-app\");\nconst configPath = join(configDir, \"config.json\");\n\nexport async function writeDefaultConfig() {\n  const config = {\n    outDir: \"dist\",\n    retries: 3,\n  } satisfies AppConfig;\n\n  await fs.ensureDir(configDir);\n  await fs.writeJson(configPath, config);\n}\n\nexport async function loadConfig(): Promise<AppConfig | null> {\n  if (!(await fs.pathExists(configPath))) {\n    return null;\n  }\n\n  return (await fs.readJson(configPath)) as AppConfig;\n}\n```\n\nAt the type boundary, treat data loaded from JSON as untrusted runtime input and narrow or validate it in your own code before relying on its shape.\n\n### Copy generated files and clean up build output\n\nThe extra helpers are promise-friendly when you omit a callback, so they fit naturally into `async` build and setup scripts.\n\n```typescript\nimport fs from \"fs-extra\";\nimport { join } from \"node:path\";\n\nconst sourceDir = join(process.cwd(), \"public\");\nconst outputDir = join(process.cwd(), \"dist\", \"public\");\nconst cacheDir = join(process.cwd(), \".cache\");\n\nexport async function publishAssets() {\n  await fs.copy(sourceDir, outputDir);\n}\n\nexport async function clearLocalCache() {\n  await fs.remove(cacheDir);\n}\n```\n\n### Use Node `fs` methods from the same import\n\nThe main `fs-extra` package re-exports Node `fs` methods, so a single import can cover both standard operations and the extra helpers.\n\n```typescript\nimport fs from \"fs-extra\";\n\nexport async function readBanner(path: string): Promise<string> {\n  return fs.readFile(path, \"utf8\");\n}\n\nexport async function writeBanner(path: string, banner: string) {\n  await fs.outputFile(path, banner);\n}\n```\n\nThis is usually the simplest import pattern for Node scripts, CLIs, and server-side tooling.\n\n### Prefer promise-returning overloads in TypeScript\n\n`fs-extra` supports callbacks and promise-returning calls. In TypeScript, the promise overload is usually easier to compose and infer.\n\n```typescript\nimport fs = require(\"fs-extra\");\n\nexport async function backupFile(sourcePath: string, backupPath: string) {\n  await fs.copy(sourcePath, backupPath);\n}\n\nexport function backupFileWithCallback(\n  sourcePath: string,\n  backupPath: string,\n  done: (error: Error | null) => void,\n) {\n  fs.copy(sourcePath, backupPath, (error) => {\n    done(error ?? null);\n  });\n}\n```\n\nUse the callback form only when you need to integrate with an older API that already expects callbacks.\n\n## Common Pitfalls\n\n- Install `fs-extra` as well as `@types/fs-extra`; the declaration package does not include the runtime implementation.\n- Import from `\"fs-extra\"`, not from `\"@types/fs-extra\"`.\n- If you use `import fs from \"fs-extra\"`, enable `esModuleInterop` or `allowSyntheticDefaultImports`; otherwise use `import fs = require(\"fs-extra\")`.\n- The main `fs-extra` import includes Node `fs` methods, but the runtime docs note that `fs-extra/esm` does not include those `fs` methods.\n- Async helpers return promises when you omit the callback; if you pass a callback, use the callback-based overload consistently.\n- JSON helper methods load runtime data, not validated application types; add your own narrowing or validation where the shape matters.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/fs-extra\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fs-extra\n- https://www.npmjs.com/package/fs-extra\n- https://github.com/jprichardson/node-fs-extra\n"
  },
  {
    "path": "content/typescript/docs/geojson/typescript/DOC.md",
    "content": "---\nname: geojson\ndescription: \"TypeScript declarations for RFC 7946 GeoJSON objects, geometries, features, and feature collections.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7946.0.16\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,geojson,spatial,types,definitelytyped,npm\"\n---\n\n# GeoJSON TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/geojson` for compile-time declarations only, then import types from `\"geojson\"` in your TypeScript code.\n\n`@types/geojson` does not ship a parser, serializer, validator, map renderer, or coordinate utilities. It describes RFC 7946 GeoJSON shapes such as `GeoJsonObject`, `Geometry`, `Feature<G, P>`, and `FeatureCollection<G, P>` so your code, JSON boundaries, and integration points stay typed.\n\n## Install\n\nAdd the declaration package to your project:\n\n```bash\nnpm install -D typescript @types/geojson@7946.0.16\n```\n\nIf TypeScript is already installed, add only the GeoJSON declarations:\n\n```bash\nnpm install -D @types/geojson@7946.0.16\n```\n\nThere are no package-specific environment variables, credentials, authentication steps, or runtime clients to initialize.\n\nThe published package metadata declares `typeScriptVersion: \"5.0\"`, so use TypeScript 5.0 or newer.\n\n## Initialization\n\nThe important setup is your compiler configuration and your import style.\n\n### Use type-only imports\n\nImport declarations from `\"geojson\"`, never from `\"@types/geojson\"`.\n\nPrefer `import type` so the import is erased from emitted JavaScript:\n\n```typescript\nimport type {\n  Feature,\n  FeatureCollection,\n  GeoJsonObject,\n  Geometry,\n  Point,\n  Polygon,\n  Position,\n} from \"geojson\";\n```\n\nThis matters because `@types/geojson` is a declaration package only. A runtime import that survives compilation can fail if your app tries to load a `geojson` module at runtime.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project explicitly restricts ambient type packages with `compilerOptions.types`, include `\"geojson\"`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"geojson\"]\n  }\n}\n```\n\n`node` is only needed there if the same project also uses Node.js APIs.\n\n## Common Workflows\n\n### Type a feature collection with custom properties\n\nUse the generic parameters on `FeatureCollection<G, P>` and `Feature<G, P>` to keep geometry and properties explicit.\n\n```typescript\nimport type { FeatureCollection, Point } from \"geojson\";\n\ntype CityProperties = {\n  id: string;\n  name: string;\n  population: number;\n};\n\nexport const cities: FeatureCollection<Point, CityProperties> = {\n  type: \"FeatureCollection\",\n  features: [\n    {\n      type: \"Feature\",\n      geometry: {\n        type: \"Point\",\n        coordinates: [-122.4194, 37.7749],\n      },\n      properties: {\n        id: \"sf\",\n        name: \"San Francisco\",\n        population: 808988,\n      },\n    },\n  ],\n};\n```\n\nThis is the most common way to use the package in application code: type the GeoJSON value at the boundary where you construct or receive it.\n\n### Type helper functions that produce GeoJSON\n\nKeep function boundaries generic so downstream code preserves the exact geometry and properties types.\n\n```typescript\nimport type { Feature, Geometry, GeoJsonProperties } from \"geojson\";\n\nexport function makeFeature<G extends Geometry, P extends GeoJsonProperties>(\n  geometry: G,\n  properties: P\n): Feature<G, P> {\n  return {\n    type: \"Feature\",\n    geometry,\n    properties,\n  };\n}\n\nconst office = makeFeature(\n  {\n    type: \"Point\",\n    coordinates: [-73.9851, 40.7589],\n  },\n  {\n    name: \"Midtown Office\",\n    open: true,\n  }\n);\n```\n\nThis avoids falling back to `Feature<Geometry, GeoJsonProperties>` too early.\n\n### Narrow a geometry union by `type`\n\nThe declaration package models GeoJSON geometries as a discriminated union. Check `geometry.type` before reading geometry-specific fields.\n\n```typescript\nimport type { Feature, Geometry } from \"geojson\";\n\ntype PlaceProperties = {\n  name: string;\n};\n\nexport function summarize(feature: Feature<Geometry, PlaceProperties>): string {\n  if (feature.geometry === null) {\n    return `${feature.properties.name}: no geometry`;\n  }\n\n  switch (feature.geometry.type) {\n    case \"Point\":\n      return `${feature.properties.name}: point at ${feature.geometry.coordinates.join(\", \")}`;\n    case \"Polygon\":\n      return `${feature.properties.name}: polygon with ${feature.geometry.coordinates.length} rings`;\n    case \"GeometryCollection\":\n      return `${feature.properties.name}: ${feature.geometry.geometries.length} geometries`;\n    default:\n      return `${feature.properties.name}: ${feature.geometry.type}`;\n  }\n}\n```\n\nThis is the safe way to work with the `Geometry` union in reducers, validators, renderers, and API handlers.\n\n### Validate external JSON at the boundary\n\nThese declarations do not validate unknown input at runtime. Guard the shape you need before asserting the type.\n\n```typescript\nimport { readFileSync } from \"node:fs\";\nimport type { FeatureCollection, Geometry, GeoJsonProperties } from \"geojson\";\n\nfunction isFeatureCollection(\n  value: unknown\n): value is FeatureCollection<Geometry, GeoJsonProperties> {\n  return (\n    typeof value === \"object\" &&\n    value !== null &&\n    (value as { type?: unknown }).type === \"FeatureCollection\" &&\n    Array.isArray((value as { features?: unknown }).features)\n  );\n}\n\nconst raw = JSON.parse(readFileSync(\"./data/cities.json\", \"utf8\")) as unknown;\n\nif (!isFeatureCollection(raw)) {\n  throw new Error(\"Expected a GeoJSON FeatureCollection\");\n}\n\nconsole.log(raw.features.length);\n```\n\nUse this pattern whenever GeoJSON comes from files, APIs, databases, or user input.\n\n### Work with nullable geometry and properties\n\nThe declarations allow `Feature[\"geometry\"]` to be `null`, and the default properties type can also be `null`. Handle both when your data source allows incomplete features.\n\n```typescript\nimport type { Feature } from \"geojson\";\n\ntype ParcelProperties = {\n  parcelId: string;\n} | null;\n\nconst placeholder: Feature<null, ParcelProperties> = {\n  type: \"Feature\",\n  geometry: null,\n  properties: null,\n};\n```\n\nIf your application requires non-null properties, provide a stricter properties type parameter instead of relying on the default.\n\n## Important Pitfalls\n\n- `@types/geojson` is types only. It does not load, validate, transform, or render GeoJSON.\n- Import from `\"geojson\"`, not from `\"@types/geojson\"`.\n- Prefer `import type` for type-only usage so emitted JavaScript does not keep a runtime import.\n- `Feature[\"geometry\"]` can be `null`, so guard it before reading `geometry.type` or `coordinates`.\n- The default `GeoJsonProperties` type can be `null`. If your code assumes a fixed object shape, pass an explicit properties type parameter.\n- `Position` and `bbox` are numeric arrays. The declarations do not enforce tuple length, longitude/latitude ordering, ring closure, or polygon validity.\n- RFC 7946 uses longitude, latitude coordinate order in WGS 84. TypeScript types do not enforce that semantic rule for you.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/geojson==7946.0.16`.\n- The package metadata declares `typeScriptVersion: \"5.0\"`.\n- The declarations model the GeoJSON object system from RFC 7946; this package is typically used as a type-only dependency alongside your own JSON parsing or mapping runtime.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/geojson\n- DefinitelyTyped source for `@types/geojson`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/geojson\n- `@types/geojson` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/geojson/index.d.ts\n- GeoJSON specification (RFC 7946): https://datatracker.ietf.org/doc/html/rfc7946\n"
  },
  {
    "path": "content/typescript/docs/glob/typescript/DOC.md",
    "content": "---\nname: glob\ndescription: \"TypeScript guide for the `glob` package: install the runtime package, import its bundled types, and use typed glob patterns, options, and results correctly.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,glob,node,filesystem,types,definitelytyped\"\n---\n\n# glob TypeScript Guide\n\n## Golden Rule\n\nUse `glob` as the runtime package and import all values and types from `\"glob\"`.\n\nThe maintained `glob` package publishes its own TypeScript declarations and typed export map. In application code, the practical boundary is the runtime package: `glob`, `globSync`, `globStream`, `globIterate`, `Glob`, and `GlobOptions` all come from `glob`.\n\nDo not import anything from `@types/glob` in source files.\n\n## Install\n\nInstall the runtime package, then add TypeScript and Node.js declarations for your project:\n\n```bash\nnpm install glob\nnpm install -D typescript @types/node\n```\n\nIf your project previously added `@types/glob` directly, remove that direct dependency and keep `glob`:\n\n```bash\nnpm uninstall @types/glob\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup is your TypeScript compiler configuration and the way you import from `glob`.\n\n### Recommended `tsconfig.json`\n\nFor Node.js projects, a Node-oriented compiler setup keeps the module boundary clear:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, include `node`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n### Import values and types from `glob`\n\nUse named imports from the runtime package:\n\n```typescript\nimport {\n  glob,\n  globSync,\n  globStream,\n  Glob,\n  type GlobOptions,\n} from \"glob\";\n```\n\nCommonJS works as documented as well:\n\n```typescript\nconst { glob, globSync, globStream, Glob } = require(\"glob\");\n```\n\n## Common Workflows\n\n### Find files asynchronously\n\n`glob()` returns a `Promise<string[]>` when `withFileTypes` is not enabled.\n\n```typescript\nimport { glob } from \"glob\";\n\nconst sourceFiles = await glob(\"src/**/*.ts\", {\n  cwd: process.cwd(),\n  ignore: [\"dist/**\", \"node_modules/**\"],\n  nodir: true,\n});\n\nconsole.log(sourceFiles);\n```\n\nThis is the most common integration point for build scripts, CLIs, and code generation tasks.\n\n### Reuse typed options in helpers\n\n`GlobOptions` is exported from `glob`, so helper functions can share one typed options object.\n\n```typescript\nimport { glob, type GlobOptions } from \"glob\";\n\nconst commonOptions: GlobOptions = {\n  cwd: new URL(\"../\", import.meta.url),\n  nodir: true,\n  ignore: [\"coverage/**\", \"dist/**\"],\n};\n\nexport function findMarkdownFiles() {\n  return glob(\"**/*.md\", commonOptions);\n}\n```\n\nThe `cwd` option accepts either a string path or a `file://` URL.\n\n### Return typed `Path` objects with `withFileTypes: true`\n\nWhen you need richer filesystem data, enable `withFileTypes`. The return type switches from `string[]` to `Path[]`.\n\n```typescript\nimport { glob } from \"glob\";\n\nconst entries = await glob(\"src/**/*\", {\n  withFileTypes: true,\n  stat: true,\n});\n\nfor (const entry of entries) {\n  console.log({\n    path: entry.fullpath(),\n    isDirectory: entry.isDirectory(),\n    modifiedAtMs: entry.mtimeMs,\n  });\n}\n```\n\nThis is the right mode when you need `Dirent`-like behavior or file metadata while keeping the result type precise.\n\n### Use sync and stream APIs when they fit better\n\nThe package ships separate sync and stream entry points with matching declarations.\n\n```typescript\nimport { globStream, globSync } from \"glob\";\n\nconst configFiles = globSync(\"{src,test}/**/*.json\", {\n  nodir: true,\n});\n\nconsole.log(configFiles);\n\nconst stream = globStream(\"logs/**/*.log\");\nstream.on(\"data\", match => {\n  console.log(match);\n});\n```\n\nUse `globSync()` for setup code and small directory walks. Use `globStream()` when you want incremental results instead of collecting the full match list first.\n\n### Reuse caches with `Glob`\n\nIf you walk similar directory trees repeatedly, construct a `Glob` instance and reuse it.\n\n```typescript\nimport { Glob } from \"glob\";\n\nconst shared = new Glob(\"src/**/*.ts\", {\n  ignore: \"dist/**\",\n});\n\nconst sourceFiles = await shared.walk();\n\nconst tests = new Glob(\"test/**/*.ts\", shared);\nconst testFiles = tests.walkSync();\n\nconsole.log({ sourceFiles, testFiles });\n```\n\nThe documented constructor pattern lets a later `Glob` reuse the earlier instance's settings and caches.\n\n### Cancel a long-running walk\n\n`GlobOptions` accepts an `AbortSignal`, so cancellation is typed at the call site.\n\n```typescript\nimport { glob } from \"glob\";\n\nconst controller = new AbortController();\nconst timer = setTimeout(() => controller.abort(), 100);\n\ntry {\n  const matches = await glob(\"**/*.css\", {\n    signal: controller.signal,\n  });\n\n  console.log(matches);\n} finally {\n  clearTimeout(timer);\n}\n```\n\n## CLI Boundary\n\nThe command-line tool comes from the `glob` runtime package, not from `@types/glob`.\n\nQuote patterns so your shell does not expand them before `glob` receives them:\n\n```bash\nnpx glob \"src/**/*.ts\" --ignore \"dist/**\" --ignore \"node_modules/**\"\n```\n\nIf you intentionally want `glob` itself to treat every positional argument as a glob expression even when it already matches a file on disk, use `--all`:\n\n```bash\nnpx glob --all \"app/*.ts\"\n```\n\n## Important Pitfalls\n\n- Import from `glob`, not from `@types/glob`.\n- `withFileTypes: true` changes the return type to `Path[]` and conflicts with `absolute`, `mark`, and `posix`.\n- `ignore` patterns are always evaluated in dot mode, even if your main pattern does not set `dot: true`.\n- `root` changes where absolute `/...` patterns start, but it does not sandbox traversal; patterns containing `..` can still walk outside that root.\n- On Windows, only enable `windowsPathsNoEscape` when you explicitly want backslashes treated as path separators instead of escape characters.\n"
  },
  {
    "path": "content/typescript/docs/got/typescript/DOC.md",
    "content": "---\nname: got\ndescription: \"TypeScript declarations for `got` 9.x, including CommonJS imports, typed JSON responses, reusable instances, and HTTP error handling.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.6.12\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,got,http,request,types,definitelytyped\"\n---\n\n# got TypeScript Guide\n\n## Golden Rule\n\nInstall `got` for runtime behavior and `@types/got` for compile-time declarations.\n\n`@types/got@9.6.12` is the DefinitelyTyped declaration package for the `got` 9.x runtime module. Your application imports and executes `got`; the `@types` package supplies the TypeScript surface for the request function, HTTP method helpers, reusable instances from `got.extend()`, `Response<T>`, and `got.HTTPError`.\n\nImport from `\"got\"`, never from `\"@types/got\"`.\n\n## Install\n\nInstall the runtime package, TypeScript, and Node.js types:\n\n```bash\nnpm install got@^9\nnpm install -D typescript @types/got@9.6.12 @types/node\n```\n\nThere are no package-specific environment variables, credentials, or auth steps for `@types/got` itself.\n\n### Recommended `tsconfig.json`\n\nThe published declarations use CommonJS export syntax, so the most convenient setup is enabling interop:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2019\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you prefer not to enable `esModuleInterop`, use the `import = require()` form shown below.\n\n## Initialization\n\nThe important setup points are your import style and how you share a configured `got` instance.\n\n### Import `got`\n\nThe most portable import form is:\n\n```typescript\nimport got = require(\"got\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport got from \"got\";\n```\n\n### Create a reusable client\n\n`got` does not have a separate authentication client. Read your own application settings from environment variables and pass them through request options.\n\n```bash\nexport API_BASE_URL=https://api.example.com\nexport API_TOKEN=your-token\n```\n\n```typescript\nimport got = require(\"got\");\n\nconst apiBaseUrl = process.env.API_BASE_URL;\nconst apiToken = process.env.API_TOKEN;\n\nif (!apiBaseUrl) {\n  throw new Error(\"API_BASE_URL is required\");\n}\n\nif (!apiToken) {\n  throw new Error(\"API_TOKEN is required\");\n}\n\nexport const api = got.extend({\n  headers: {\n    authorization: `Bearer ${apiToken}`,\n    accept: \"application/json\",\n    \"user-agent\": \"my-app/1.0\",\n  },\n  timeout: 5_000,\n});\n\nexport { apiBaseUrl };\n```\n\n`API_BASE_URL` and `API_TOKEN` are ordinary application settings, not something required by the type package.\n\n## Common Workflows\n\n### Make a typed JSON `GET` request\n\nPass the expected response body type as the generic argument and enable JSON parsing with `json: true`.\n\n```typescript\nimport got = require(\"got\");\nimport { api, apiBaseUrl } from \"./client\";\n\ntype User = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\nexport async function getUser(userId: string): Promise<User> {\n  const response: got.Response<User> = await api.get<User>(`${apiBaseUrl}/users/${userId}`, {\n    json: true,\n  });\n\n  return response.body;\n}\n```\n\nWith `json: true`, the response body is parsed as JSON. If you omit that option, `response.body` is typed as a string.\n\n### Send query parameters in a typed request\n\nUse the `query` option when the upstream API expects URL query parameters.\n\n```typescript\nimport { api, apiBaseUrl } from \"./client\";\n\ntype SearchUsersResponse = {\n  items: Array<{\n    id: string;\n    email: string;\n  }>;\n  nextCursor?: string;\n};\n\nexport async function searchUsers(role: \"admin\" | \"member\"): Promise<SearchUsersResponse> {\n  const response = await api.get<SearchUsersResponse>(`${apiBaseUrl}/users`, {\n    json: true,\n    query: {\n      limit: 25,\n      role,\n    },\n  });\n\n  return response.body;\n}\n```\n\nThis keeps the HTTP boundary typed while still using normal query-string parameters.\n\n### Post JSON and type the response body\n\nTypeScript can describe both the request input you send and the response shape you expect back.\n\n```typescript\nimport { api, apiBaseUrl } from \"./client\";\n\ntype CreateUserInput = {\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\ntype CreateUserResponse = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n  createdAt: string;\n};\n\nexport async function createUser(input: CreateUserInput): Promise<CreateUserResponse> {\n  const response = await api.post<CreateUserResponse>(`${apiBaseUrl}/users`, {\n    body: JSON.stringify(input),\n    headers: {\n      \"content-type\": \"application/json\",\n    },\n    json: true,\n  });\n\n  return response.body;\n}\n```\n\nThe generic argument controls the response type. Your request body type still comes from the `input` variable you pass into the function.\n\n### Narrow `HTTPError` in a `catch` block\n\n`got` throws `got.HTTPError` for HTTP status failures by default, so use that class when you need status-aware error handling.\n\n```typescript\nimport got = require(\"got\");\nimport { api, apiBaseUrl } from \"./client\";\n\nexport async function deleteUser(userId: string): Promise<void> {\n  try {\n    await api.delete(`${apiBaseUrl}/users/${userId}`);\n  } catch (error) {\n    if (error instanceof got.HTTPError) {\n      throw new Error(\n        `Delete failed (${error.response.statusCode}): ${error.response.body}`\n      );\n    }\n\n    throw error;\n  }\n}\n```\n\nIf your application wants to inspect non-2xx responses without throwing, set `throwHttpErrors: false` on that request and branch on `response.statusCode` yourself.\n\n## Important Pitfalls\n\n- `@types/got` is declarations only. Install `got` itself for runtime behavior.\n- Import from `got`, not from `@types/got`.\n- These declarations target the `got` 9.x API surface. Do not assume they match newer `got` majors.\n- Without `json: true`, `response.body` is a string.\n- `got` throws `got.HTTPError` on HTTP status failures by default. Use `throwHttpErrors: false` only when your code is prepared to handle status codes manually.\n- Response generics help at compile time, but they do not validate JSON payloads at runtime.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/got==9.6.12`.\n- The package is maintained in DefinitelyTyped for the `got` runtime module.\n- The published declarations use CommonJS export syntax (`export = got`), which is why import style depends on your TypeScript interop settings.\n- Current `got` releases publish their own type definitions, so `@types/got@9.6.12` is the guide to follow when your project is intentionally using the older 9.x runtime line.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/got\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/got\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/got/index.d.ts\n- https://www.npmjs.com/package/got\n"
  },
  {
    "path": "content/typescript/docs/graphql/typescript/DOC.md",
    "content": "---\nname: graphql\ndescription: \"TypeScript declarations for GraphQL.js schema construction, query execution, parsing, validation, and shared GraphQL types.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"14.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,graphql,graphql-js,types,definitelytyped,schema,validation\"\n---\n\n# GraphQL TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/graphql` alongside the real `graphql` runtime package.\n\n`@types/graphql` only provides TypeScript declarations. Your application imports and executes code from `graphql`; the declaration package supplies the types for schema objects, execution results, parser utilities, validation helpers, errors, and resolver signatures.\n\n## Install\n\nFor the version this guide targets, install matching `graphql` and `@types/graphql` packages:\n\n```bash\nnpm install graphql@14.5.0\nnpm install -D typescript @types/graphql@14.5.0 @types/node\n```\n\nIf your project already depends on `graphql`, add only the missing TypeScript packages:\n\n```bash\nnpm install -D @types/graphql@14.5.0 @types/node\n```\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to configure.\n\nThe practical setup points are your TypeScript compiler settings, your import style, and the boundary between the declaration package and the runtime library.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/graphql` works best when `strict` mode is on, because GraphQL execution results can contain partial data and optional errors.\n\n### Import from `graphql`, not `@types/graphql`\n\nUse the runtime package name in both value imports and type-only imports:\n\n```typescript\nimport {\n  graphql,\n  GraphQLObjectType,\n  GraphQLSchema,\n  GraphQLString,\n} from \"graphql\";\n\nimport type { ExecutionResult, GraphQLError } from \"graphql\";\n```\n\nDo not write application imports like `import type { GraphQLSchema } from \"@types/graphql\"`.\n\n## Common Workflows\n\n### Define a schema with typed resolver context\n\n```typescript\nimport {\n  GraphQLObjectType,\n  GraphQLSchema,\n  GraphQLString,\n} from \"graphql\";\n\ntype Context = {\n  requestId: string;\n};\n\nexport const schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: \"Query\",\n    fields: {\n      hello: {\n        type: GraphQLString,\n        resolve: (_source, _args, context: Context) => {\n          return `hello ${context.requestId}`;\n        },\n      },\n    },\n  }),\n});\n```\n\nThis is the simplest way to keep your resolver context typed without introducing framework-specific abstractions.\n\n### Execute a query and handle `ExecutionResult`\n\n```typescript\nimport { graphql } from \"graphql\";\nimport type { ExecutionResult } from \"graphql\";\n\nconst result: ExecutionResult = await graphql({\n  schema,\n  source: \"{ hello }\",\n  contextValue: { requestId: \"req_123\" },\n});\n\nif (result.errors) {\n  for (const error of result.errors) {\n    console.error(error.message);\n  }\n}\n\nconsole.log(result.data);\n```\n\nTreat both `result.data` and `result.errors` as optional. GraphQL execution can return partial data with one or more errors.\n\n### Parse and validate before execution\n\n```typescript\nimport {\n  buildSchema,\n  parse,\n  specifiedRules,\n  validate,\n} from \"graphql\";\n\nconst schema = buildSchema(`\n  type Query {\n    user(id: ID!): String\n  }\n`);\n\nconst document = parse(`\n  query GetUser($id: ID!) {\n    user(id: $id)\n  }\n`);\n\nconst errors = validate(schema, document, specifiedRules);\n\nif (errors.length > 0) {\n  throw new Error(errors.map((error) => error.message).join(\"\\n\"));\n}\n```\n\nUse this split workflow when you need to reject invalid documents before they reach execution, or when you are building tooling around GraphQL documents.\n\n### Build a schema from SDL\n\n```typescript\nimport { buildSchema, graphql } from \"graphql\";\n\nconst schema = buildSchema(`\n  type Query {\n    greet(name: String): String!\n  }\n`);\n\nconst rootValue = {\n  greet: ({ name }: { name?: string }) => `Hello ${name ?? \"world\"}`,\n};\n\nconst result = await graphql({\n  schema,\n  source: '{ greet(name: \"Ada\") }',\n  rootValue,\n});\n\nconsole.log(result.data);\n```\n\nThis pattern is useful for small services, tests, and examples where SDL is easier to maintain than constructor-based type definitions.\n\n### Reuse GraphQL types at application boundaries\n\n```typescript\nimport type {\n  DocumentNode,\n  ExecutionResult,\n  GraphQLError,\n  GraphQLResolveInfo,\n  GraphQLSchema,\n} from \"graphql\";\n\ntype ResolverContext = {\n  userId?: string;\n};\n\nexport type CompiledOperation = {\n  document: DocumentNode;\n  schema: GraphQLSchema;\n};\n\nexport function logErrors(result: ExecutionResult) {\n  const errors: readonly GraphQLError[] = result.errors ?? [];\n\n  for (const error of errors) {\n    console.error(error.message);\n  }\n}\n\nexport function describeResolver(_info: GraphQLResolveInfo, context: ResolverContext) {\n  return context.userId ?? \"anonymous\";\n}\n```\n\nUse these exported types in service helpers, test utilities, and framework adapters instead of inventing your own parallel interfaces.\n\n## Minimal End-to-End Example\n\nThis example builds a schema in code, reads an optional app-specific query string from the environment, and executes it through `graphql()`.\n\n```typescript\nimport {\n  graphql,\n  GraphQLObjectType,\n  GraphQLSchema,\n  GraphQLString,\n} from \"graphql\";\n\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: \"Query\",\n    fields: {\n      status: {\n        type: GraphQLString,\n        resolve: () => \"ok\",\n      },\n    },\n  }),\n});\n\nconst source = process.env.GRAPHQL_QUERY ?? \"{ status }\";\n\nconst result = await graphql({ schema, source });\n\nconsole.log(JSON.stringify(result, null, 2));\n```\n\nRun the compiled file with an optional query override:\n\n```bash\nGRAPHQL_QUERY='{ status }' node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/graphql` is a declaration package only. Install `graphql` separately for runtime behavior.\n- Import from `graphql`, not from `@types/graphql`.\n- Keep the runtime package and declaration package on the same GraphQL 14 API surface.\n- Prefer named imports from `graphql`; do not rely on a default import.\n- Check both `result.data` and `result.errors` after execution, because GraphQL responses can contain partial success.\n- Use explicit resolver functions when you need typed context, custom argument handling, or behavior that should not depend on the default field resolver.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/graphql==14.5.0`.\n- The declarations are intended for GraphQL.js usage through the `graphql` package.\n- If you upgrade the GraphQL runtime to a different major version, review the matching declarations and execution signatures together.\n"
  },
  {
    "path": "content/typescript/docs/handlebars/typescript/DOC.md",
    "content": "---\nname: handlebars\ndescription: \"TypeScript declarations for Handlebars template compilation, helpers, partials, runtime-only rendering, and CommonJS import patterns\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,handlebars,templates,html,views,types,definitelytyped\"\n---\n\n# Handlebars TypeScript Guide\n\n`@types/handlebars` adds TypeScript declarations for the `handlebars` runtime package. Use it in projects that still rely on the separate declaration package and want typed access to `compile()`, `template()`, `precompile()`, `registerHelper()`, `registerPartial()`, and `SafeString`.\n\nThis package only provides `.d.ts` files. Your application imports and executes `handlebars`, not `@types/handlebars`.\n\n## Golden Rule\n\nInstall `@types/handlebars` alongside the real `handlebars` runtime package.\n\nIf you are starting a new project on current Handlebars releases, check whether the runtime package already provides the declarations you need. The published `handlebars` package includes a `types/index.d.ts` entrypoint, so many current projects do not need a separate `@types/handlebars` dependency.\n\n## Install\n\nFor a project pinned to the separate declaration package:\n\n```bash\nnpm install handlebars\nnpm install -D typescript @types/handlebars\n```\n\nIf your app already depends on `handlebars`, add only the missing declaration package:\n\n```bash\nnpm install -D @types/handlebars\n```\n\nThere are no package-defined environment variables, credentials, or service initialization steps.\n\n## TypeScript Setup\n\nThe declaration entrypoint uses `export =`, so the most portable import form is:\n\n```typescript\nimport Handlebars = require(\"handlebars\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport Handlebars from \"handlebars\";\n```\n\nRecommended `tsconfig.json` settings for a Node.js project that renders templates:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict ambient types with `compilerOptions.types`, keep the packages that your template-rendering project actually needs available there.\n\n## Common Workflows\n\n### Compile a template with a typed context\n\n`compile<T>()` returns a template function whose first argument is typed as your context object.\n\n```typescript\nimport Handlebars from \"handlebars\";\n\ntype InvoiceContext = {\n  customerName: string;\n  total: number;\n  items: Array<{\n    name: string;\n    quantity: number;\n  }>;\n};\n\nconst source = `\n  <h1>{{customerName}}</h1>\n  <ul>\n    {{#items}}\n      <li>{{name}} × {{quantity}}</li>\n    {{/items}}\n  </ul>\n  <p>Total: {{total}}</p>\n`;\n\nconst renderInvoice = Handlebars.compile<InvoiceContext>(source);\n\nconst html = renderInvoice({\n  customerName: \"Ada Lovelace\",\n  total: 42,\n  items: [\n    { name: \"Notebook\", quantity: 2 },\n    { name: \"Pen\", quantity: 4 },\n  ],\n});\n\nconsole.log(html);\n```\n\nThe generic type protects the data you pass into the compiled template function. It does not statically validate placeholder names inside the template string.\n\n### Register a helper and guard inputs\n\nThe published helper typings are intentionally broad. Treat helper arguments as runtime input and validate them before using them.\n\n```typescript\nimport Handlebars from \"handlebars\";\n\nHandlebars.registerHelper(\"currency\", (value) => {\n  if (typeof value !== \"number\") {\n    return \"\";\n  }\n\n  return new Handlebars.SafeString(`$${value.toFixed(2)}`);\n});\n\nconst template = Handlebars.compile(`Price: {{{currency amount}}}`);\n\nconsole.log(template({ amount: 12.5 }));\n```\n\nUse triple-stash output only when the helper returns content you intend to render without escaping.\n\n### Register and use partials\n\nPartials can be registered from strings or from compiled template delegates.\n\n```typescript\nimport Handlebars from \"handlebars\";\n\nHandlebars.registerPartial(\"lineItem\", \"<li>{{name}} × {{quantity}}</li>\");\n\nconst renderList = Handlebars.compile<{\n  items: Array<{ name: string; quantity: number }>;\n}>(`\n  <ul>\n    {{#items}}\n      {{> lineItem}}\n    {{/items}}\n  </ul>\n`);\n\nconsole.log(\n  renderList({\n    items: [\n      { name: \"Notebook\", quantity: 2 },\n      { name: \"Pen\", quantity: 4 },\n    ],\n  }),\n);\n```\n\nIf you want isolated helper and partial registries, create a fresh instance with `Handlebars.create()` instead of mutating the shared top-level registry.\n\n### Precompile templates and render with the runtime build\n\nThe declarations expose both `precompile()` and the `handlebars/runtime` module for runtime-only rendering.\n\n```typescript\nimport HandlebarsRuntime = require(\"handlebars/runtime\");\n\ndeclare const precompiledInvoice: TemplateSpecification;\n\ntype InvoiceContext = {\n  customerName: string;\n  total: number;\n};\n\nconst renderInvoice = HandlebarsRuntime.template<InvoiceContext>(\n  precompiledInvoice,\n);\n\nconsole.log(\n  renderInvoice({\n    customerName: \"Ada Lovelace\",\n    total: 42,\n  }),\n);\n```\n\nUse the full `handlebars` package when you need to compile templates at runtime. Use `handlebars/runtime` when templates were precompiled earlier in your build pipeline.\n\n### Parse a template to an AST\n\nThe declarations include typed `parse()` and `parseWithoutProcessing()` entrypoints that return `hbs.AST.Program`.\n\n```typescript\nimport Handlebars from \"handlebars\";\n\nconst ast = Handlebars.parse(\"{{#if user}}Hello, {{user.name}}{{/if}}\");\n\nconsole.log(ast.type);\nconsole.log(ast.body.length);\n```\n\nThis is useful when you need to inspect templates in custom tooling instead of rendering them immediately.\n\n## Important Pitfalls\n\n- `@types/handlebars` only adds declarations. Install `handlebars` itself for runtime behavior.\n- Import from `handlebars` or `handlebars/runtime`, never from `@types/handlebars` in application code.\n- The declaration entrypoint uses `export =`, so your import style depends on your TypeScript interop settings.\n- The generic on `compile<T>()` types the context object you pass at render time, but it does not type-check the Handlebars template string itself.\n- Helper arguments and `options.hash` are broadly typed, so validate values inside helpers before assuming a shape.\n- `SafeString` bypasses escaping for the returned content. Use it only for content you trust.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/handlebars==4.1.0`.\n- The separate declaration package is for the `handlebars` runtime package and models the CommonJS module shape with `export = Handlebars`.\n- The declarations cover the main runtime workflow: `compile`, `template`, `precompile`, helper registration, partial registration, and `handlebars/runtime`.\n- Current published `handlebars` releases include their own `types/index.d.ts`, so fresh projects often rely on the runtime package's bundled declarations instead of adding `@types/handlebars` separately.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/handlebars\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/handlebars\n- https://www.npmjs.com/package/handlebars\n- https://github.com/handlebars-lang/handlebars.js\n- https://github.com/handlebars-lang/handlebars.js/blob/master/types/index.d.ts\n- https://handlebarsjs.com/\n"
  },
  {
    "path": "content/typescript/docs/hapi-hapi/typescript/DOC.md",
    "content": "---\nname: hapi-hapi\ndescription: \"TypeScript declarations for @hapi/hapi server creation, routes, handlers, plugins, and request/response types.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"21.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,hapi,node,http,server,types,definitelytyped\"\n---\n\n# @hapi/hapi TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/hapi__hapi` alongside the real `@hapi/hapi` runtime package.\n\n`@types/hapi__hapi` only provides TypeScript declarations. Your application still imports and runs `@hapi/hapi`; the declaration package adds typings for server creation, route definitions, handlers, plugins, requests, responses, and related configuration objects.\n\n## Install\n\nInstall the runtime package first, then the TypeScript packages your project depends on:\n\n```bash\nnpm install @hapi/hapi\nnpm install --save-dev typescript @types/hapi__hapi @types/node\n```\n\nThe type package does not require authentication or any external service setup. Typical server settings come from environment variables:\n\n```bash\nexport HOST=\"127.0.0.1\"\nexport PORT=\"3000\"\n```\n\n## TypeScript Setup\n\nImport runtime values and types from `@hapi/hapi`, not from `@types/hapi__hapi`.\n\nThe declaration package follows the standard DefinitelyTyped naming convention for scoped packages:\n\n- runtime package: `@hapi/hapi`\n- declaration package: `@types/hapi__hapi`\n- `compilerOptions.types` entry: `hapi__hapi`\n\n`@hapi/hapi` uses a CommonJS-compatible export style in the declaration package.\n\nWithout TypeScript interop flags, use:\n\n```ts\nimport Hapi = require(\"@hapi/hapi\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```ts\nimport Hapi from \"@hapi/hapi\";\n```\n\nIf your project restricts ambient type loading with `compilerOptions.types`, include `hapi__hapi` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"hapi__hapi\"]\n  },\n  \"include\": [\"src/**/*.ts\"]\n}\n```\n\n## Create And Start A Typed Server\n\nThere is no client object or credentials to configure. The practical setup is creating a server with `Hapi.server(...)`, adding routes, and then calling `await server.start()`.\n\n```ts\nimport Hapi from \"@hapi/hapi\";\n\nconst port = Number.parseInt(process.env.PORT ?? \"3000\", 10);\nconst host = process.env.HOST ?? \"127.0.0.1\";\n\nif (!Number.isInteger(port) || port <= 0) {\n  throw new Error(\"PORT must be a positive integer\");\n}\n\nasync function main() {\n  const server = Hapi.server({\n    port,\n    host,\n  });\n\n  server.route({\n    method: \"GET\",\n    path: \"/health\",\n    handler: () => ({ ok: true }),\n  });\n\n  await server.start();\n  console.log(`Server running at ${server.info.uri}`);\n}\n\nvoid main();\n```\n\n## Common Workflows\n\n### Reuse typed route objects\n\nUse `Hapi.ServerRoute` when you want to define routes outside the `server.route(...)` call site.\n\n```ts\nimport Hapi from \"@hapi/hapi\";\n\nconst healthRoute: Hapi.ServerRoute = {\n  method: \"GET\",\n  path: \"/health\",\n  handler: (_request, h) => {\n    return h.response({ ok: true }).code(200);\n  },\n};\n\nconst echoRoute: Hapi.ServerRoute = {\n  method: \"POST\",\n  path: \"/echo\",\n  handler: (request) => {\n    return { payload: request.payload ?? null };\n  },\n};\n\nconst server = Hapi.server({ port: 3000 });\nserver.route([healthRoute, echoRoute]);\n```\n\nThis keeps route configuration reusable while still letting TypeScript check the supported route fields.\n\n### Type handler parameters explicitly when needed\n\nWhen a handler is extracted into a separate function, annotate `Hapi.Request` and `Hapi.ResponseToolkit` directly.\n\n```ts\nimport Hapi = require(\"@hapi/hapi\");\n\nconst helloRoute: Hapi.ServerRoute = {\n  method: \"GET\",\n  path: \"/hello/{name}\",\n  handler: (request: Hapi.Request, h: Hapi.ResponseToolkit) => {\n    const params = request.params as { name: string };\n\n    return h.response({\n      message: `Hello, ${params.name}`,\n    });\n  },\n};\n```\n\nRequest params, query values, and payloads are runtime data. Narrow or validate them before treating them as application-specific types.\n\n### Register a plugin with typed server access\n\nPlugins receive the same `Hapi.Server` type as the main application.\n\n```ts\nimport Hapi from \"@hapi/hapi\";\n\nasync function buildServer() {\n  const server = Hapi.server({ port: 3000 });\n\n  await server.register({\n    name: \"health-routes\",\n    register: async (registeredServer: Hapi.Server) => {\n      registeredServer.route({\n        method: \"GET\",\n        path: \"/ready\",\n        handler: () => ({ ready: true }),\n      });\n    },\n  });\n\n  return server;\n}\n```\n\nThis is a straightforward pattern when you want plugin code to stay type-safe without importing internal app helpers.\n\n## Important Pitfalls\n\n- `@types/hapi__hapi` does not install or run the server framework. Install `@hapi/hapi` itself.\n- Import from `@hapi/hapi`, not from `@types/hapi__hapi`.\n- Without `esModuleInterop` or `allowSyntheticDefaultImports`, prefer `import Hapi = require(\"@hapi/hapi\")`.\n- If your project uses `compilerOptions.types`, include `hapi__hapi` or TypeScript may not load the declarations.\n- Route inputs such as `request.params`, `request.query`, and `request.payload` come from runtime data; narrow or validate them before using application-specific fields.\n- Parse and validate `PORT` before passing it to `Hapi.server(...)` so your configuration stays typed and predictable.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/hapi__hapi==21.0.0`.\n- The package name uses the standard DefinitelyTyped mapping for scoped packages: `@types/hapi__hapi` describes imports from `@hapi/hapi`.\n- Use `@hapi/hapi` in application code and reserve `hapi__hapi` for TypeScript configuration that refers to declaration package names.\n- The declarations are published separately from the runtime package, so keep `@hapi/hapi` and `@types/hapi__hapi` aligned to the same major API you want to use.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/hapi__hapi\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hapi__hapi\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/hapi__hapi/index.d.ts\n- https://www.npmjs.com/package/@hapi/hapi\n"
  },
  {
    "path": "content/typescript/docs/helmet/typescript/DOC.md",
    "content": "---\nname: helmet\ndescription: \"TypeScript guidance for Helmet projects that encounter the @types/helmet 4.0.0 stub package\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,helmet,express,security,middleware,types\"\n---\n\n# Helmet TypeScript Guide\n\n`@types/helmet@4.0.0` is the type-package entry point many projects still encounter in dependency history, but current application code should install and import the `helmet` runtime package itself.\n\nFor TypeScript users, the practical rule is simple: import from `\"helmet\"`, not from `\"@types/helmet\"`.\n\n## Install\n\nInstall Helmet with Express, then add the TypeScript and Express declarations your server needs:\n\n```bash\nnpm install express helmet\nnpm install --save-dev typescript @types/express @types/node\n```\n\nIf your project still lists `@types/helmet`, remove it and keep `helmet`:\n\n```bash\nnpm uninstall @types/helmet\nnpm install helmet\n```\n\nHelmet does not require credentials, API keys, or environment variables.\n\n## TypeScript Setup\n\nNo special Helmet-specific `tsconfig.json` settings are required. In a normal server project, importing `helmet` is enough.\n\nA typical strict Node.js setup looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient type packages with `compilerOptions.types`, keep the server-side types that your app actually uses:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"express\"]\n  }\n}\n```\n\nYou still import Helmet from `\"helmet\"`; there is no separate runtime import path for `@types/helmet`.\n\n## Add Helmet To An Express App\n\nUse the middleware returned by `helmet()` near the top of your middleware stack so security headers are applied to most responses.\n\n```typescript\nimport express from \"express\";\nimport helmet from \"helmet\";\n\nconst app = express();\n\napp.use(helmet());\napp.use(express.json());\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n\napp.listen(3000);\n```\n\nThis is the main integration point for TypeScript code: `helmet()` returns Express-compatible middleware, so you compose it with `app.use()` just like other request handlers.\n\n## Reuse Helmet As Typed Middleware\n\nWhen you wrap middleware setup in helpers, type the return value as an Express `RequestHandler` instead of reaching into any declaration-package internals.\n\n```typescript\nimport type { RequestHandler } from \"express\";\nimport helmet from \"helmet\";\n\nexport function createSecurityHeaders(): RequestHandler {\n  return helmet();\n}\n```\n\nThis keeps your application boundary stable even if your project upgrades the runtime package later.\n\n## Apply Helmet To Part Of An App\n\nYou can create the middleware once and mount it on a sub-path or router.\n\n```typescript\nimport express from \"express\";\nimport helmet from \"helmet\";\n\nconst app = express();\nconst apiSecurity = helmet();\n\napp.use(\"/api\", apiSecurity);\n\napp.get(\"/\", (_req, res) => {\n  res.send(\"public landing page\");\n});\n\napp.get(\"/api/users\", (_req, res) => {\n  res.json([{ id: 1, name: \"Ada\" }]);\n});\n```\n\n## Common Pitfalls\n\n- Install `helmet` for runtime behavior; `@types/helmet` is not a runtime library.\n- Import from `\"helmet\"`, not from `\"@types/helmet\"`.\n- If TypeScript cannot resolve Express symbols such as `RequestHandler`, add `@types/express` and `@types/node` to the project that compiles your server.\n- If older project docs tell you to install both `helmet` and `@types/helmet`, prefer the runtime package first and keep your imports pointed at `helmet`.\n\n## Version Note For `@types/helmet` 4.0.0\n\nFor this package version, the useful TypeScript workflow is centered on the `helmet` runtime package rather than on a standalone declaration API. Treat `@types/helmet` as a transitional declaration package you may still see in older dependency trees, not as the package your application code should import.\n"
  },
  {
    "path": "content/typescript/docs/highlight.js/typescript/DOC.md",
    "content": "---\nname: highlight.js\ndescription: \"TypeScript declarations for highlight.js syntax-highlighting APIs, language registration, and browser helpers\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"10.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,highlight.js,syntax-highlighting,types,definitelytyped\"\n---\n\n# highlight.js TypeScript Guide\n\n`@types/highlight.js` provides TypeScript declarations for the `highlight.js` runtime package.\n\nThis package only adds `.d.ts` files. It does not include the highlighter runtime, language grammars, or CSS themes.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install highlight.js\nnpm install --save-dev typescript @types/highlight.js@10.1.0\n```\n\nNo package-specific environment variables, credentials, or client initialization are required.\n\n## TypeScript Setup\n\nIn most projects, installing `@types/highlight.js` is enough.\n\nOnly add `highlight.js` to `compilerOptions.types` if your project already restricts which declaration packages TypeScript loads:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"highlight.js\"]\n  }\n}\n```\n\n## Import The Runtime Package, Not The Type Package\n\nThese declarations model `highlight.js` as a CommonJS `export =` module, so the most portable TypeScript import form is:\n\n```ts\nimport hljs = require(\"highlight.js\");\n```\n\nFor the smaller core build:\n\n```ts\nimport hljs = require(\"highlight.js/lib/core\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport hljs from \"highlight.js\";\n```\n\nDo not import from `@types/highlight.js` directly in application code.\n\n## Highlight Code With A Known Language\n\nUse `highlight()` when you already know the language name. The returned object includes the generated HTML in `.value`.\n\n```ts\nimport hljs = require(\"highlight.js\");\n\nconst source = `const total = items.reduce((sum, item) => sum + item.price, 0);`;\nconst result = hljs.highlight(source, { language: \"javascript\" });\n\nconsole.log(result.language);\nconsole.log(result.value);\n```\n\nUse the `.value` field when you need the highlighted HTML string for server rendering or template output.\n\n## Auto-Detect A Language\n\nUse `highlightAuto()` when the input language is not known ahead of time.\n\n```ts\nimport hljs = require(\"highlight.js\");\n\nconst source = `SELECT id, email FROM users WHERE active = true;`;\nconst result = hljs.highlightAuto(source, [\"sql\", \"javascript\", \"typescript\"]);\n\nconsole.log(result.language);\nconsole.log(result.relevance);\nconsole.log(result.value);\n```\n\nPassing a language subset is useful when you want more predictable detection results.\n\n## Register Only The Languages You Need\n\nFor smaller bundles, import the core build and register specific languages explicitly.\n\n```ts\nimport hljs = require(\"highlight.js/lib/core\");\nimport typescript from \"highlight.js/lib/languages/typescript\";\nimport json from \"highlight.js/lib/languages/json\";\n\nhljs.registerLanguage(\"typescript\", typescript);\nhljs.registerLanguage(\"json\", json);\n\nconst tsResult = hljs.highlight(\"const ready: boolean = true;\", {\n  language: \"typescript\",\n});\n\nconsole.log(tsResult.value);\nconsole.log(hljs.listLanguages());\n```\n\nThis is the main integration boundary that matters in TypeScript projects: the declaration package types the `registerLanguage()` call and the `highlight.js/lib/languages/*` modules, but the runtime package still provides the actual language implementations.\n\n## Highlight Browser Code Blocks\n\nFor browser code, load a theme stylesheet from `highlight.js/styles/*`, register languages if you use the core build, then highlight DOM elements.\n\n```ts\nimport hljs = require(\"highlight.js/lib/core\");\nimport xml from \"highlight.js/lib/languages/xml\";\nimport \"highlight.js/styles/github.css\";\n\nhljs.registerLanguage(\"xml\", xml);\n\ndocument.querySelectorAll<HTMLElement>(\"pre code\").forEach((block) => {\n  hljs.highlightElement(block);\n});\n```\n\nIf your page uses the standard `<pre><code>` structure and the full browser build, `hljs.highlightAll()` is the simplest entrypoint:\n\n```ts\nimport hljs = require(\"highlight.js\");\n\nhljs.highlightAll();\n```\n\n## Configure Runtime Behavior\n\nUse `configure()` to set options such as the CSS class prefix, tab replacement, and language subset.\n\n```ts\nimport hljs = require(\"highlight.js\");\n\nhljs.configure({\n  classPrefix: \"hljs-\",\n  tabReplace: \"  \",\n  useBR: false,\n  languages: [\"typescript\", \"javascript\", \"json\"],\n});\n```\n\nThese options affect the runtime highlighter. `@types/highlight.js` only makes those options type-safe.\n\n## Common Pitfalls\n\n- Install `highlight.js` as well as `@types/highlight.js`; the type package does not include runtime JavaScript.\n- Import from `\"highlight.js\"` or `\"highlight.js/lib/core\"`, not from `\"@types/highlight.js\"`.\n- If your project restricts `compilerOptions.types`, include `highlight.js` there or TypeScript will not load the declarations.\n- These declarations use CommonJS `export =` semantics, so `import { highlight } from \"highlight.js\"` is not the right import form.\n- When you use the core build, call `registerLanguage()` before `highlight()` or `highlightElement()` for those languages.\n- Theme CSS comes from the runtime package, not from the type package.\n\n## Version Notes\n\n`@types/highlight.js` `10.1.0` is useful for projects that still rely on the DefinitelyTyped package for `highlight.js` typings.\n\nCheck your installed `highlight.js` version before adding it. The official `highlight.js` npm package for `10.7.3` publishes its own typings via a `types` entry in `package.json`, so newer runtime installs may not need `@types/highlight.js` at all.\n\nIf your runtime package already ships declarations, prefer the runtime package's built-in types and avoid installing both sets of typings together.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/highlight.js\n- https://www.npmjs.com/package/highlight.js\n- https://github.com/highlightjs/highlight.js\n- https://highlightjs.readthedocs.io/en/latest/api.html\n"
  },
  {
    "path": "content/typescript/docs/html-minifier-terser/typescript/DOC.md",
    "content": "---\nname: html-minifier-terser\ndescription: \"TypeScript guidance for `html-minifier-terser`, including installation of `@types/html-minifier-terser`, the typed `minify()` API, and practical HTML minification workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.0.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,html-minifier-terser,html,minify,build,types,definitelytyped\"\n---\n\n# html-minifier-terser TypeScript Guide\n\n## Golden Rule\n\nInstall `html-minifier-terser` for the runtime and `@types/html-minifier-terser` for compile-time types.\n\n`@types/html-minifier-terser` only provides TypeScript declarations. Your application imports and executes `html-minifier-terser`; the declaration package adds the `minify()` signature and the `Options` interface.\n\n## Install\n\nFor programmatic TypeScript use, install the runtime package first and then the declarations.\n\n```bash\nnpm install html-minifier-terser\nnpm install -D typescript @types/html-minifier-terser @types/node\n```\n\nIf your project already has TypeScript and Node types, add only the missing declaration package:\n\n```bash\nnpm install -D @types/html-minifier-terser\n```\n\nIf you also want the command-line tool globally, the runtime README documents:\n\n```bash\nnpm install -g html-minifier-terser\n```\n\n`html-minifier-terser` does not require credentials, API keys, package-specific environment variables, or client initialization.\n\n## Initialization\n\nThe practical setup is your import style and the options object you pass to `minify()`.\n\n### Import the runtime package\n\nThe declaration package exposes a small surface: `minify(value: string, options?: Options): Promise<string>` and the `Options` interface.\n\nThis namespace import is a practical TypeScript default for the CommonJS runtime package:\n\n```typescript\nimport * as htmlMinifierTerser from \"html-minifier-terser\";\n```\n\nImport from `html-minifier-terser`, never from `@types/html-minifier-terser`.\n\n### `tsconfig.json`\n\nNo package-specific compiler setting is required. A normal TypeScript project setup is enough because the declaration package publishes its module entrypoint through the package `types` field.\n\nIf you use Node APIs such as `fs/promises` in your build scripts, keep `@types/node` installed for those imports.\n\n## Common Workflows\n\n### Minify an HTML string with typed options\n\nUse the exported `Options` interface to make your build settings explicit and catch misspelled option names at compile time.\n\n```typescript\nimport * as htmlMinifierTerser from \"html-minifier-terser\";\n\nconst options: htmlMinifierTerser.Options = {\n  collapseWhitespace: true,\n  removeComments: true,\n  removeRedundantAttributes: true,\n  removeScriptTypeAttributes: true,\n  removeStyleLinkTypeAttributes: true,\n  useShortDoctype: true,\n  minifyCSS: true,\n  minifyJS: true,\n};\n\nexport async function minifyMarkup(input: string): Promise<string> {\n  return htmlMinifierTerser.minify(input, options);\n}\n```\n\nThe upstream README notes that almost all options are disabled by default, so set the behaviors you actually want instead of assuming an aggressive preset.\n\n### Minify HTML files in a build step\n\nThis package is commonly used at the output boundary of a static-site or server-rendered build. The environment variables here are optional application settings, not package requirements.\n\n```typescript\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport * as htmlMinifierTerser from \"html-minifier-terser\";\n\nconst inputPath = process.env.HTML_INPUT_PATH ?? \"./dist/index.html\";\nconst outputPath = process.env.HTML_OUTPUT_PATH ?? inputPath;\n\nconst options: htmlMinifierTerser.Options = {\n  collapseWhitespace: true,\n  removeComments: true,\n  removeOptionalTags: true,\n  removeRedundantAttributes: true,\n  removeScriptTypeAttributes: true,\n  removeStyleLinkTypeAttributes: true,\n  useShortDoctype: true,\n  minifyCSS: true,\n  minifyJS: true,\n};\n\nexport async function minifyHtmlFile(): Promise<void> {\n  const html = await readFile(inputPath, \"utf8\");\n  const minified = await htmlMinifierTerser.minify(html, options);\n\n  await writeFile(outputPath, minified, \"utf8\");\n}\n```\n\n### Preserve template fragments and custom script blocks\n\nThe declarations include regex-based escape hatches for templating systems and nonstandard script blocks. Use them when your HTML contains server-side or client-side template syntax that should survive minification.\n\n```typescript\nimport * as htmlMinifierTerser from \"html-minifier-terser\";\n\nconst options: htmlMinifierTerser.Options = {\n  collapseWhitespace: true,\n  minifyCSS: true,\n  minifyJS: true,\n  ignoreCustomFragments: [\n    /<%[\\s\\S]*?%>/,\n    /\\{\\{[\\s\\S]*?\\}\\}/,\n  ],\n  processScripts: [\"text/x-handlebars-template\", \"text/ng-template\"],\n};\n\nconst template = `\n  <div class=\"card\">\n    {{ title }}\n  </div>\n  <script type=\"text/x-handlebars-template\">\n    <span>{{ value }}</span>\n  </script>\n`;\n\nconst result = await htmlMinifierTerser.minify(template, options);\nconsole.log(result);\n```\n\nThe type comments document `ignoreCustomFragments` for fragments such as `<% ... %>` and `<? ... ?>`, and `processScripts` for script types such as `text/ng-template`.\n\n### Run the CLI with the same minification choices\n\nThe CLI comes from the `html-minifier-terser` runtime package, not from the `@types` package. The runtime README's sample command line is:\n\n```bash\nhtml-minifier-terser --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype --minify-css true --minify-js true\n```\n\nUse the typed `Options` object in application code and the CLI flags in scripts when you need the same behavior in both places.\n\n## Important Pitfalls\n\n- Install `html-minifier-terser` separately; `@types/html-minifier-terser` does not ship executable JavaScript.\n- Import from `html-minifier-terser`, not from `@types/html-minifier-terser`.\n- Almost all minifier options are disabled by default.\n- `collapseInlineTagWhitespace`, `conservativeCollapse`, and `preserveLineBreaks` are documented as options that must be used together with `collapseWhitespace: true`.\n- `removeTagWhitespace` is explicitly documented as producing invalid HTML.\n- Use `ignoreCustomFragments`, `customAttrAssign`, `customAttrSurround`, and `processScripts` when your markup includes template syntax or custom script content.\n- The CLI binary is installed by `html-minifier-terser`; the declaration package has no effect on command-line behavior.\n\n## Version Note\n\nThis guide targets the `@types/html-minifier-terser` `7.0.2` package entry on npm.\n\nThe public type surface you use in real projects is small: an async `minify()` function plus the `Options` interface that describes the runtime minifier configuration.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/html-minifier-terser\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/html-minifier-terser\n- https://www.npmjs.com/package/html-minifier-terser\n- https://github.com/terser/html-minifier-terser#readme\n- https://terser.org/html-minifier-terser/\n"
  },
  {
    "path": "content/typescript/docs/http-errors/typescript/DOC.md",
    "content": "---\nname: http-errors\ndescription: \"TypeScript declarations for the http-errors runtime package, including the error factory, named HTTP constructors, and error narrowing with isHttpError.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.0.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,http-errors,node,http,express,errors,types,definitelytyped\"\n---\n\n# http-errors TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/http-errors` alongside the real `http-errors` runtime package.\n\n`@types/http-errors` only provides TypeScript declarations. Your application imports and runs `http-errors`; the declaration package adds types for the callable `createError()` factory, status-specific constructors such as `NotFound` and `Unauthorized`, and the `isHttpError()` type guard.\n\n## Install\n\nInstall the runtime package first, then add the declaration package for TypeScript:\n\n```bash\nnpm install http-errors\nnpm install -D typescript @types/http-errors\n```\n\nIf your server project does not already include Node.js types, add them as well:\n\n```bash\nnpm install -D @types/node\n```\n\n`@types/http-errors@2.0.5` declares `typeScriptVersion: \"5.1\"`, so use TypeScript 5.1 or newer.\n\nThere are no environment variables, credentials, or client objects to initialize.\n\n## Initialization\n\nThe practical setup points are your import style and how you model custom error fields in your own code.\n\n### Import `http-errors`\n\nThe declaration entrypoint uses `export =`, so the configuration-independent import form is:\n\n```typescript\nimport createHttpError = require(\"http-errors\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport createHttpError from \"http-errors\";\n```\n\nFor example:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\nImport runtime code from `\"http-errors\"`, not from `\"@types/http-errors\"`.\n\n## Common Workflows\n\n### Create errors with status-specific types\n\nThe main factory infers the status code literal when the first argument is a numeric literal.\n\n```typescript\nimport createHttpError = require(\"http-errors\");\n\nconst notFound = createHttpError(404, \"User not found\");\nconst tooManyRequests = createHttpError(429, \"Slow down\", {\n  expose: true,\n  headers: {\n    \"retry-after\": \"60\",\n  },\n});\n\nconst status: 404 = notFound.status;\nconst statusCode: 429 = tooManyRequests.statusCode;\n```\n\nThe runtime documents `status`, `statusCode`, `message`, `expose`, and optional `headers` on the resulting error object. When you set `headers`, keep the header names lower-cased.\n\n### Use named constructors\n\nThe declarations expose named constructors and numeric constructor properties for the documented 4xx and 5xx status codes.\n\n```typescript\nimport createHttpError = require(\"http-errors\");\n\nconst unauthorized = new createHttpError.Unauthorized(\"Sign in required\");\nconst conflict = createHttpError[409](\"Version conflict\");\n\nconst unauthorizedStatus: 401 = unauthorized.status;\nconst conflictStatus: 409 = conflict.status;\n```\n\nUse named constructors when the status is fixed and you want that literal type to follow the error value.\n\n### Wrap an existing error\n\nYou can turn an existing `Error` into an HTTP error and attach extra properties in the same call.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport createHttpError = require(\"http-errors\");\n\nexport async function loadTemplate(): Promise<string> {\n  try {\n    return await readFile(\"email.html\", \"utf8\");\n  } catch (error) {\n    throw createHttpError(500, error as Error, {\n      expose: false,\n      operation: \"loadTemplate\",\n    });\n  }\n}\n```\n\nThe runtime README documents this as extending the given error object with `HttpError` properties such as `status`, `statusCode`, and `expose`.\n\n### Narrow `unknown` with `isHttpError`\n\nUse `createHttpError.isHttpError()` at the boundary where your code catches `unknown` values.\n\n```typescript\nimport createHttpError = require(\"http-errors\");\n\nexport function toHttpResponse(error: unknown) {\n  if (createHttpError.isHttpError(error)) {\n    return {\n      status: error.status,\n      body: {\n        error: error.expose ? error.message : \"Internal Server Error\",\n      },\n    };\n  }\n\n  return {\n    status: 500,\n    body: {\n      error: \"Internal Server Error\",\n    },\n  };\n}\n```\n\nThe type guard narrows the value to `createHttpError.HttpError`, which includes `status`, `statusCode`, `expose`, `headers`, and an index signature for additional fields.\n\n### Model application-specific fields explicitly\n\nThe declarations allow arbitrary extra properties on `HttpError`, but your own code is easier to maintain if you define an app-specific intersection type.\n\n```typescript\nimport createHttpError = require(\"http-errors\");\n\ntype ApiError<Code extends number = number> = createHttpError.HttpError<Code> & {\n  code: \"USER_NOT_FOUND\" | \"PLAN_REQUIRED\";\n  details?: Record<string, unknown>;\n};\n\nexport function userNotFound(userId: string): ApiError<404> {\n  return createHttpError(404, `User ${userId} not found`, {\n    code: \"USER_NOT_FOUND\",\n    details: { userId },\n  }) as ApiError<404>;\n}\n```\n\nThis keeps the useful literal status type from the package while making your own `code` and `details` fields explicit to the compiler.\n\n### Use `http-errors` in Express middleware\n\n`http-errors` is commonly used with Express error handling.\n\n```typescript\nimport express, {\n  type NextFunction,\n  type Request,\n  type Response,\n} from \"express\";\nimport createHttpError from \"http-errors\";\n\nconst app = express();\n\napp.get(\"/users/:userId\", async (req: Request, res: Response, next: NextFunction) => {\n  try {\n    const user = await findUser(req.params.userId);\n\n    if (!user) {\n      next(createHttpError.NotFound(\"User not found\"));\n      return;\n    }\n\n    res.json(user);\n  } catch (error) {\n    next(createHttpError(500, error as Error));\n  }\n});\n\napp.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {\n  if (!createHttpError.isHttpError(error)) {\n    res.status(500).json({ error: \"Internal Server Error\" });\n    return;\n  }\n\n  if (error.headers) {\n    res.set(error.headers);\n  }\n\n  res.status(error.status).json({\n    error: error.expose ? error.message : \"Internal Server Error\",\n  });\n});\n\nasync function findUser(userId: string) {\n  return userId === \"123\"\n    ? { id: \"123\", name: \"Ada\" }\n    : null;\n}\n```\n\nThis example uses default imports, so it assumes `esModuleInterop` or `allowSyntheticDefaultImports` is enabled.\n\n## Version Notes\n\n- This guide targets `@types/http-errors==2.0.5`.\n- The declaration package has no dependencies and points to the DefinitelyTyped source tree at `types/http-errors`.\n- The exported API shape is a callable CommonJS factory with attached constructor properties and `isHttpError()`.\n- In `@types/http-errors@2.0.5`, the 511 constructor name is declared as `NetworkAuthenticationRequire` in `index.d.ts`, while the runtime README lists `NetworkAuthenticationRequired`. If you need a 511 error, prefer `createHttpError(511, ...)` or `createHttpError[511](...)`.\n\n## Common Pitfalls\n\n- Install `http-errors` as well as `@types/http-errors`; the type package does not include runtime code.\n- Import from `\"http-errors\"`, not from `\"@types/http-errors\"`.\n- Without TypeScript interop flags, prefer `import createHttpError = require(\"http-errors\")` over a default import.\n- Use 4xx or 5xx status codes. The runtime README documents constructors for those ranges, and the runtime source falls back to `500` for invalid values.\n- Treat `headers` as string-valued response headers and keep the keys lower-cased.\n- `createHttpError.isHttpError()` narrows to the library's `HttpError` type, not to your app-specific extra fields; add your own intersection type or custom guard when you need stronger typing.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/http-errors\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/http-errors\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/http-errors/index.d.ts\n- https://www.npmjs.com/package/http-errors\n- https://github.com/jshttp/http-errors\n- https://github.com/jshttp/http-errors/blob/master/README.md\n"
  },
  {
    "path": "content/typescript/docs/inquirer/typescript/DOC.md",
    "content": "---\nname: inquirer\ndescription: \"TypeScript setup for Inquirer. `@types/inquirer@9.0.9` is a stub package; install `inquirer` itself because it ships its own type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.0.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,inquirer,cli,prompts,types,definitelytyped\"\n---\n\n# Inquirer TypeScript Guide\n\n## Golden Rule\n\n`@types/inquirer@9.0.9` is not the package you should install for a modern Inquirer application.\n\nThe npm package page for `@types/inquirer` marks it as a stub package and says that `inquirer` provides its own type definitions. Install the real `inquirer` runtime package and import both runtime APIs and TypeScript types from `inquirer`.\n\nIf an older project still has `@types/inquirer` in its lockfile, remove it unless that project is intentionally pinned to an older Inquirer setup that still depended on DefinitelyTyped declarations.\n\n## Install\n\nInstall the runtime package plus the normal TypeScript toolchain for a Node.js CLI or terminal app:\n\n```bash\nnpm install inquirer\nnpm install -D typescript @types/node\n```\n\nIf your project already added the old stub package, remove it:\n\n```bash\nnpm uninstall @types/inquirer\n```\n\nThere are no package-specific credentials, auth steps, or environment variables. The practical setup points are your TypeScript compiler and how you type the answers returned by `inquirer.prompt()`.\n\n## Initialization\n\nUse a Node-aware TypeScript config so the compiler understands the runtime environment around your prompts.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/node` matters in CLI code because prompt scripts commonly use `process`, `stdin`, `stdout`, and other Node globals around Inquirer.\n\n## Common Workflows\n\n### Prompt for a typed answer object\n\nPass a TypeScript interface to `inquirer.prompt<Answers>()` so the returned answers object has the shape your application expects.\n\n```ts\nimport inquirer from \"inquirer\";\n\ninterface InitAnswers {\n  projectName: string;\n  useTypeScript: boolean;\n}\n\nconst answers = await inquirer.prompt<InitAnswers>([\n  {\n    type: \"input\",\n    name: \"projectName\",\n    message: \"Project name?\",\n  },\n  {\n    type: \"confirm\",\n    name: \"useTypeScript\",\n    message: \"Use TypeScript?\",\n    default: true,\n  },\n]);\n\nconsole.log(answers.projectName);\nconsole.log(answers.useTypeScript);\n```\n\nThis is the main TypeScript boundary for Inquirer: define the answer shape once, then let `prompt()` return that typed object.\n\n### Use literal unions for constrained answers\n\nWhen a prompt should only return a small set of known values, model that field with a union type in your answers interface.\n\n```ts\nimport inquirer from \"inquirer\";\n\ntype PackageManager = \"npm\" | \"pnpm\" | \"yarn\";\n\ninterface SetupAnswers {\n  packageManager: PackageManager;\n  initializeGit: boolean;\n}\n\nconst answers = await inquirer.prompt<SetupAnswers>([\n  {\n    type: \"list\",\n    name: \"packageManager\",\n    message: \"Package manager?\",\n    choices: [\"npm\", \"pnpm\", \"yarn\"],\n    default: \"npm\",\n  },\n  {\n    type: \"confirm\",\n    name: \"initializeGit\",\n    message: \"Initialize a Git repository?\",\n    default: true,\n  },\n]);\n\nif (answers.packageManager === \"pnpm\") {\n  console.log(\"Run pnpm install after scaffolding\");\n}\n```\n\nThis keeps downstream branching logic typed instead of falling back to unstructured string handling.\n\n### Wrap prompts in a reusable helper\n\nReturn a typed promise from your prompt helper so the rest of your CLI code can work with a stable answer shape.\n\n```ts\nimport inquirer from \"inquirer\";\n\ninterface CreateAppAnswers {\n  appName: string;\n  installDependencies: boolean;\n}\n\nexport async function askCreateAppQuestions(): Promise<CreateAppAnswers> {\n  return inquirer.prompt<CreateAppAnswers>([\n    {\n      type: \"input\",\n      name: \"appName\",\n      message: \"App name?\",\n    },\n    {\n      type: \"confirm\",\n      name: \"installDependencies\",\n      message: \"Install dependencies now?\",\n      default: true,\n    },\n  ]);\n}\n```\n\nThis is usually cleaner than threading loosely typed answer objects through multiple setup steps.\n\n## Important Pitfalls\n\n- Do not import from `@types/inquirer`; import from `inquirer`.\n- Do not keep both `inquirer` and `@types/inquirer` installed in a modern project unless you are intentionally maintaining an older setup.\n- `@types/inquirer` does not include the runtime prompt implementation. You still need the real `inquirer` package.\n- The active type surface now comes from the `inquirer` version in your application, not from DefinitelyTyped.\n- Add `@types/node` for CLI projects so surrounding Node.js globals are typed cleanly.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/inquirer==9.0.9`.\n- `@types/inquirer@9.0.9` is a stub package; the runtime package you actually use is `inquirer`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/inquirer\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/inquirer\n- https://www.npmjs.com/package/inquirer\n- https://github.com/SBoudrias/Inquirer.js\n"
  },
  {
    "path": "content/typescript/docs/jest/typescript/DOC.md",
    "content": "---\nname: jest\ndescription: \"TypeScript definitions for Jest's global test APIs, matchers, mocks, spies, and utility types\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"30.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,jest,testing,mocks,types\"\n---\n\n# Jest TypeScript Guide\n\n`@types/jest` adds TypeScript declarations for Jest's global test APIs and helper types. Install it when your TypeScript tests use ambient names such as `describe`, `it`, `test`, `expect`, `beforeEach`, `afterEach`, or the `jest` namespace.\n\nThis package only ships `.d.ts` files. It does not provide the Jest runtime, it does not execute tests, and it does not transpile `.ts` files for Jest.\n\n## Install\n\nInstall the runtime package and the type package together:\n\n```bash\nnpm install --save-dev jest @types/jest\n```\n\nNo environment variables, authentication, or client initialization are required.\n\nIf your test files are written in TypeScript, you also need a TypeScript-aware Jest execution setup such as a transform step or a compile step. `@types/jest` only affects the compiler and editor.\n\n## TypeScript Setup\n\nIf your project does not restrict `compilerOptions.types`, installing `@types/jest` is usually enough.\n\nIf you already restrict loaded type packages, add `jest` explicitly so the ambient globals stay available in test files:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n```\n\nIn mixed projects, a test-only TypeScript config avoids leaking Jest globals into non-test code:\n\n```json\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"src\", \"**/*.test.ts\", \"**/*.spec.ts\"]\n}\n```\n\nDo not import `@types/jest` in code. TypeScript loads the declarations automatically.\n\n## Write Tests With Jest Globals\n\nWith Jest's default global injection, your test files can use the test API without imports:\n\n```typescript\nfunction sum(a: number, b: number) {\n  return a + b;\n}\n\ndescribe(\"sum\", () => {\n  test(\"adds two numbers\", () => {\n    expect(sum(2, 3)).toBe(5);\n  });\n});\n```\n\nThis is the simplest setup when you want `describe`, `test`, and `expect` available globally in test files.\n\n## Use Explicit Imports When `injectGlobals` Is Disabled\n\nIf you set Jest's `injectGlobals` option to `false`, import the runtime APIs from `@jest/globals` instead of relying on ambient globals.\n\n```typescript\nimport type { Config } from \"jest\";\n\nconst config: Config = {\n  injectGlobals: false,\n  testEnvironment: \"node\",\n};\n\nexport default config;\n```\n\nThen write tests like this:\n\n```typescript\nimport { describe, expect, test } from \"@jest/globals\";\n\ndescribe(\"sum\", () => {\n  test(\"adds two numbers\", () => {\n    expect(2 + 3).toBe(5);\n  });\n});\n```\n\nThis runtime choice does not change how `@types/jest` is installed, but it does change whether your tests depend on injected globals.\n\n## Type Mock Functions And Mocked Objects\n\nThe `jest` namespace includes utility types that matter at the TypeScript boundary.\n\n### Mock a function with the real parameter and return types\n\n```typescript\ntype FetchUser = (id: string) => Promise<{ id: string; name: string }>;\n\nconst fetchUser = jest.fn<ReturnType<FetchUser>, Parameters<FetchUser>>();\n\nfetchUser.mockResolvedValue({ id: \"u_1\", name: \"Ada\" });\n\ntest(\"loads a user\", async () => {\n  await expect(fetchUser(\"u_1\")).resolves.toEqual({\n    id: \"u_1\",\n    name: \"Ada\",\n  });\n});\n```\n\nThis keeps the mock aligned with the real function signature so `mockResolvedValue`, call arguments, and return values stay typed.\n\n### Mock an object dependency with `jest.Mocked<T>`\n\n```typescript\ninterface UserApi {\n  getUser(id: string): Promise<{ id: string; name: string }>;\n  deleteUser(id: string): Promise<void>;\n}\n\nconst api: jest.Mocked<UserApi> = {\n  getUser: jest.fn(),\n  deleteUser: jest.fn(),\n};\n\napi.getUser.mockResolvedValue({ id: \"u_1\", name: \"Ada\" });\napi.deleteUser.mockResolvedValue();\n```\n\nUse `jest.Mocked<T>` when you want an object-shaped mock where each function gains Jest mock methods.\n\n### Spy on an existing method\n\n```typescript\nafterEach(() => {\n  jest.restoreAllMocks();\n});\n\ntest(\"warns for deprecated input\", () => {\n  const warnSpy = jest.spyOn(console, \"warn\").mockImplementation(() => {});\n\n  console.warn(\"deprecated\");\n\n  expect(warnSpy).toHaveBeenCalledWith(\"deprecated\");\n});\n```\n\n`jest.spyOn()` preserves the target method's argument and return types, so the spy usually infers cleanly without extra annotations.\n\n## Add Typed Custom Matchers\n\nWhen you extend `expect`, also extend Jest's matcher interface so TypeScript recognizes the new assertion.\n\nRegister the matcher in a setup file:\n\n```typescript\nexport {};\n\ndeclare global {\n  namespace jest {\n    interface Matchers<R> {\n      toBeWithinRange(floor: number, ceiling: number): R;\n    }\n  }\n}\n\nexpect.extend({\n  toBeWithinRange(received: number, floor: number, ceiling: number) {\n    const pass = received >= floor && received <= ceiling;\n\n    return {\n      pass,\n      message: () => `expected ${received} to be within range ${floor}-${ceiling}`,\n    };\n  },\n});\n```\n\nLoad that file with `setupFilesAfterEnv`:\n\n```typescript\nimport type { Config } from \"jest\";\n\nconst config: Config = {\n  testEnvironment: \"node\",\n  setupFilesAfterEnv: [\"<rootDir>/jest.setup.ts\"],\n};\n\nexport default config;\n```\n\nNow the matcher is typed in tests:\n\n```typescript\ntest(\"range matcher\", () => {\n  expect(10).toBeWithinRange(8, 12);\n});\n```\n\n## Important Pitfalls\n\n- `@types/jest` is a declaration package only. Install `jest` separately for the runtime.\n- Do not import `@types/jest` from application or test files.\n- If `compilerOptions.types` is set, include `\"jest\"` there or TypeScript may stop seeing Jest globals.\n- Keep Jest types out of non-test TypeScript configs when your project also uses other test runners or other global `expect` implementations.\n- If you disable `injectGlobals`, import from `@jest/globals` because `describe`, `test`, and `expect` are no longer injected at runtime.\n- Keep the `jest` runtime and `@types/jest` on the same major version so the declared API surface matches the runtime you execute.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/jest==30.0.0`.\n- The package supplies type declarations for Jest's testing APIs; align it with the Jest major version used in the same project.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/jest\n- DefinitelyTyped source for `@types/jest`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jest\n- `@types/jest` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts\n- Jest TypeScript guide: https://jestjs.io/docs/getting-started#using-typescript\n- Jest configuration reference (`injectGlobals`): https://jestjs.io/docs/configuration#injectglobals-boolean\n- Jest mock function API: https://jestjs.io/docs/mock-function-api\n- Jest `expect.extend` reference: https://jestjs.io/docs/expect#expectextendmatchers\n"
  },
  {
    "path": "content/typescript/docs/jimp/typescript/DOC.md",
    "content": "---\nname: jimp\ndescription: \"TypeScript declarations for the classic Jimp image-processing API, including `Jimp.read()`, chainable transforms, MIME constants, and callback-based output helpers.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.2.28\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,jimp,images,nodejs,types,definitelytyped\"\n---\n\n# Jimp TypeScript Guide\n\n## Golden Rule\n\nInstall `jimp` for the runtime image-processing implementation and `@types/jimp` for compile-time declarations.\n\n`@types/jimp` does not process images by itself. Import from `jimp`, not from `@types/jimp`.\n\nThese declarations target the older CommonJS Jimp API shape centered on `Jimp.read()`, chainable image methods, and callback-based helpers such as `getBuffer()` and `getBase64()`.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install jimp\nnpm install -D typescript @types/jimp @types/node\n```\n\nIf your project already has TypeScript and Node.js types, add only the Jimp declarations:\n\n```bash\nnpm install -D @types/jimp\n```\n\nImport the runtime package in your application code:\n\n```typescript\nimport Jimp = require(\"jimp\");\n```\n\n## Initialization\n\nThere is no client object, authentication flow, or package-specific environment variable.\n\nThe practical setup is your TypeScript compiler configuration plus the CommonJS-style import that matches these declarations.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2019\",\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project uses `compilerOptions.types`, keep `\"node\"` there so `Buffer` and filesystem types remain available to Jimp-based code.\n\n## Common Workflows\n\n### Read an image from a file path, URL, or `Buffer`\n\n`Jimp.read()` is the main entry point for loading image data.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport Jimp = require(\"jimp\");\n\nconst fromDisk = await Jimp.read(\"./input.jpg\");\nconst fromUrl = await Jimp.read(\"https://example.com/image.jpg\");\n\nconst bytes = await readFile(\"./input.jpg\");\nconst fromBuffer = await Jimp.read(bytes);\n\nconsole.log(fromDisk.getWidth(), fromDisk.getHeight());\nconsole.log(fromUrl.getWidth(), fromUrl.getHeight());\nconsole.log(fromBuffer.getWidth(), fromBuffer.getHeight());\n```\n\n### Resize and apply common transforms\n\nMost image operations mutate the current image and return the same `Jimp` instance, so chaining is the common pattern.\n\n```typescript\nimport Jimp = require(\"jimp\");\n\nconst image = await Jimp.read(\"./input.jpg\");\n\nimage\n  .resize(256, 256)\n  .quality(80)\n  .greyscale();\n\nimage.write(\"./output.jpg\");\n```\n\n### Convert the image to a `Buffer`\n\nThe old Jimp API exposes buffer conversion through a callback. Wrap it in a `Promise` when you want to use `await`.\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport Jimp = require(\"jimp\");\n\nconst image = await Jimp.read(\"./input.jpg\");\nimage.resize(512, 512);\n\nconst pngBuffer = await new Promise<Buffer>((resolve, reject) => {\n  image.getBuffer(Jimp.MIME_PNG, (error, buffer) => {\n    if (error) {\n      reject(error);\n      return;\n    }\n\n    resolve(buffer);\n  });\n});\n\nawait writeFile(\"./output.png\", pngBuffer);\n```\n\nUse `Jimp.MIME_PNG` or `Jimp.MIME_JPEG` so the buffer format matches the file or upload target you need.\n\n### Generate a base64 data URL\n\n`getBase64()` follows the same callback pattern and is useful when you need to embed image output into an HTML response or JSON payload.\n\n```typescript\nimport Jimp = require(\"jimp\");\n\nconst image = await Jimp.read(\"./input.jpg\");\n\nconst dataUrl = await new Promise<string>((resolve, reject) => {\n  image.getBase64(Jimp.MIME_PNG, (error, value) => {\n    if (error) {\n      reject(error);\n      return;\n    }\n\n    resolve(value);\n  });\n});\n\nconsole.log(dataUrl.slice(0, 64));\n```\n\n## Minimal End-to-End Example\n\nThis script reads an image path from the environment, resizes it, and writes a PNG file using Node's filesystem APIs.\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport Jimp = require(\"jimp\");\n\nconst inputPath = process.env.INPUT_IMAGE ?? \"./input.jpg\";\nconst outputPath = process.env.OUTPUT_IMAGE ?? \"./output.png\";\n\nconst image = await Jimp.read(inputPath);\n\nimage\n  .resize(320, 320)\n  .quality(80);\n\nconst output = await new Promise<Buffer>((resolve, reject) => {\n  image.getBuffer(Jimp.MIME_PNG, (error, buffer) => {\n    if (error) {\n      reject(error);\n      return;\n    }\n\n    resolve(buffer);\n  });\n});\n\nawait writeFile(outputPath, output);\n```\n\nRun it with app-specific environment variables if you want configurable paths:\n\n```bash\nINPUT_IMAGE=./photo.jpg OUTPUT_IMAGE=./photo-small.png node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/jimp` is a declaration package only. Install `jimp` separately for the runtime.\n- Do not import from `@types/jimp` in application code.\n- Prefer `import Jimp = require(\"jimp\")` with these older CommonJS declarations.\n- `Jimp.read()` is promise-based, but `getBuffer()` and `getBase64()` use callbacks; wrap them when you need `await`.\n- Chainable image methods mutate the loaded image instance. If you need both the original and a transformed copy, duplicate the image before applying changes.\n- If you restrict ambient types with `compilerOptions.types`, keep `\"node\"` available so `Buffer` and Node filesystem helpers stay typed.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/jimp==0.2.28`.\n- Keep the `jimp` runtime aligned with the API surface exposed by these declarations.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/jimp\n- DefinitelyTyped source for `@types/jimp`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jimp\n- `@types/jimp` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jimp/index.d.ts\n- Jimp README: https://github.com/oliver-moran/jimp#readme\n"
  },
  {
    "path": "content/typescript/docs/jsdom/typescript/DOC.md",
    "content": "---\nname: jsdom\ndescription: \"TypeScript definitions for jsdom's JSDOM, DOMWindow, virtual console, and resource loading APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"28.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,jsdom,dom,node,testing,types\"\n---\n\n# jsdom TypeScript Guide\n\n`@types/jsdom` provides TypeScript declarations for the `jsdom` runtime package. Install it when your code imports `JSDOM`, `DOMWindow`, `VirtualConsole`, `ResourceLoader`, or `CookieJar` from `\"jsdom\"`.\n\nThis package only ships `.d.ts` files. It does not include the `jsdom` runtime.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install jsdom\nnpm install --save-dev typescript @types/jsdom\n```\n\n`@types/jsdom` declares dependencies on `@types/node`, `@types/tough-cookie`, and `parse5`, so npm installs those automatically.\n\nThere are no required environment variables, credentials, or initialization steps.\n\n## TypeScript Setup\n\nImport from `\"jsdom\"`, not from `\"@types/jsdom\"`:\n\n```typescript\nimport { JSDOM } from \"jsdom\";\nimport type { ConstructorOptions, DOMWindow } from \"jsdom\";\n```\n\nIn a normal TypeScript project, installing the package is enough. If you explicitly replace `compilerOptions.lib`, keep DOM libraries available because the declarations reference `dom` and `dom.iterable`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n    \"strict\": true\n  }\n}\n```\n\n`jsdom` is a Node-side library. Use it in Node.js tools, tests, scraping utilities, or server-side HTML processing code.\n\n## Create A Typed DOM\n\nUse `ConstructorOptions` and `DOMWindow` when you want reusable helpers around a `JSDOM` instance:\n\n```typescript\nimport { JSDOM } from \"jsdom\";\nimport type { ConstructorOptions, DOMWindow } from \"jsdom\";\n\nconst options: ConstructorOptions = {\n  url: \"https://example.test/\",\n  contentType: \"text/html\",\n  pretendToBeVisual: true,\n};\n\nconst dom = new JSDOM(\n  `<!doctype html><p class=\"greeting\">Hello from jsdom</p>`,\n  options,\n);\n\nfunction readGreeting(window: DOMWindow) {\n  return window.document.querySelector(\".greeting\")?.textContent ?? \"\";\n}\n\nconsole.log(readGreeting(dom.window));\n\ndom.window.close();\n```\n\n`window.close()` is useful in long-running test suites or scripts because jsdom timers keep the Node.js process alive until the window is closed.\n\n## Parse Bytes And Read Node Locations\n\nThe constructor accepts HTML strings, `Buffer`s, and other binary data. When you already have bytes, passing them directly lets jsdom perform its own encoding sniffing.\n\n`nodeLocation()` only works when `includeNodeLocations` is enabled.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport { JSDOM } from \"jsdom\";\n\nconst html = await readFile(\"fixtures/page.html\");\n\nconst dom = new JSDOM(html, {\n  includeNodeLocations: true,\n});\n\nconst heading = dom.window.document.querySelector(\"h1\");\n\nif (heading) {\n  const location = dom.nodeLocation(heading);\n  console.log(location?.startLine, location?.startCol);\n}\n```\n\nIf you do not need source locations, leave `includeNodeLocations` unset for better performance.\n\n## Use `fragment()` For Small HTML Snippets\n\nWhen you only need a `DocumentFragment`, `JSDOM.fragment()` avoids creating a full window:\n\n```typescript\nimport { JSDOM } from \"jsdom\";\n\nconst fragment = JSDOM.fragment(`\n  <li data-id=\"1\">First</li>\n  <li data-id=\"2\">Second</li>\n`);\n\nconst items = [...fragment.querySelectorAll(\"li\")].map((item) => ({\n  id: item.getAttribute(\"data-id\"),\n  text: item.textContent,\n}));\n\nconsole.log(items);\n```\n\n`fragment()` does not create a browsing context. Its nodes do not have a live `window`, subresources do not load, and you cannot pass constructor options to it.\n\n## Run Scripts Deliberately\n\nThe declarations expose the `runScripts` option as `\"dangerously\" | \"outside-only\"`.\n\nUse `\"outside-only\"` when you want to evaluate code yourself against the jsdom window without executing inline `<script>` tags automatically:\n\n```typescript\nimport { JSDOM } from \"jsdom\";\n\nconst dom = new JSDOM(`<div id=\"root\"></div>`, {\n  runScripts: \"outside-only\",\n});\n\ndom.window.eval(`\n  document.getElementById(\"root\").textContent = \"ready\";\n`);\n\nconsole.log(dom.window.document.getElementById(\"root\")?.textContent);\ndom.window.close();\n```\n\nOnly use `runScripts: \"dangerously\"` with HTML you trust. jsdom documents that embedded scripts can escape the sandbox and reach the Node.js environment.\n\n## Load Resources And Capture Console Output\n\nBy default, jsdom does not load subresources. For relative URLs to resolve, set `url` to something other than `\"about:blank\"`.\n\nUse `ResourceLoader` and `VirtualConsole` when you need typed configuration around networked resources or jsdom's internal warnings:\n\n```typescript\nimport { JSDOM, ResourceLoader, VirtualConsole } from \"jsdom\";\n\nconst proxy = process.env.HTTP_PROXY ?? undefined;\n\nconst virtualConsole = new VirtualConsole()\n  .on(\"jsdomError\", (error) => {\n    console.error(error.message);\n  })\n  .forwardTo(console, {\n    jsdomErrors: [\"not-implemented\", \"unhandled-exception\"],\n  });\n\nconst resources = new ResourceLoader({\n  proxy,\n  userAgent: \"my-app/1.0\",\n});\n\nconst dom = new JSDOM(`<!doctype html><img src=\"/logo.png\">`, {\n  url: \"https://example.test/\",\n  resources,\n  virtualConsole,\n});\n\ndom.window.close();\n```\n\n`HTTP_PROXY` in this example is optional application configuration, not a jsdom requirement.\n\n## Use `fromFile()` And `fromURL()` When Input Already Has A Location\n\nThe declarations include these convenience factories:\n\n```typescript\nimport { JSDOM } from \"jsdom\";\n\nconst fromDisk = await JSDOM.fromFile(\"templates/email.html\", {\n  includeNodeLocations: true,\n});\n\nconst fromWeb = await JSDOM.fromURL(\"https://example.test/\", {\n  referrer: \"https://app.example.test/\",\n});\n\nconsole.log(fromDisk.serialize());\nconsole.log(fromWeb.window.location.href);\n\nfromDisk.window.close();\nfromWeb.window.close();\n```\n\nFor `fromURL()`, jsdom documents that the resulting DOM gets its URL, content type, referrer, and cookies from the HTTP response. For `fromFile()`, the default URL becomes a `file:` URL based on the filename.\n\n## Practical Pitfalls\n\n- `@types/jsdom` is declarations only. Install `jsdom` itself for runtime behavior.\n- Import from `\"jsdom\"`; do not import from `\"@types/jsdom\"` in application code.\n- `nodeLocation()` throws unless the instance was created with `includeNodeLocations: true`.\n- Relative resources fail against the default `url: \"about:blank\"`.\n- `fragment()` is intentionally limited: no options, no window, and no resource loading.\n- Call `window.close()` when you are done with a window to stop timers and release listeners.\n"
  },
  {
    "path": "content/typescript/docs/jsonwebtoken/typescript/DOC.md",
    "content": "---\nname: jsonwebtoken\ndescription: \"TypeScript declarations for jsonwebtoken signing, verification, decoded JWT payloads, error classes, and callback-based key lookup in Node.js.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.0.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,jsonwebtoken,jwt,auth,nodejs,types,definitelytyped\"\n---\n\n# jsonwebtoken TypeScript Guide\n\n`@types/jsonwebtoken` adds TypeScript declarations for the `jsonwebtoken` runtime package.\n\nInstall it when your Node.js app signs, verifies, or decodes JWTs with `jsonwebtoken` and you want typed access to `sign()`, `verify()`, `decode()`, JWT option objects, and error classes such as `TokenExpiredError`.\n\nThis package only ships declarations. Your application still runs the real `jsonwebtoken` package.\n\n## Golden Rule\n\nInstall `@types/jsonwebtoken` alongside `jsonwebtoken`.\n\nImport runtime code from `\"jsonwebtoken\"`, not from `\"@types/jsonwebtoken\"`.\n\n## Install\n\nInstall the runtime package first, then add TypeScript support:\n\n```bash\nnpm install jsonwebtoken\nnpm install -D typescript @types/jsonwebtoken @types/node\n```\n\nIf `jsonwebtoken` and TypeScript are already present, add only the missing declarations:\n\n```bash\nnpm install -D @types/jsonwebtoken\n```\n\n`@types/jsonwebtoken` depends on `@types/ms` and `@types/node`, so duration strings used in options such as `expiresIn` and `notBefore` are typed in TypeScript.\n\n## TypeScript Setup\n\nThe `jsonwebtoken` runtime package is CommonJS. A portable TypeScript import style is a namespace import:\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\nimport type { JwtPayload, Secret } from \"jsonwebtoken\";\n```\n\nIf your project compiles to CommonJS, named imports from `\"jsonwebtoken\"` can also be convenient, but the namespace import is the safest default across Node.js module setups.\n\nRecommended `tsconfig.json` settings for a Node app:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts `compilerOptions.types`, keep `node` in that list so `Buffer`, `process.env`, and Node crypto key types remain available.\n\n## Initialization\n\nThere is no client object and no package-specific authentication step.\n\nThe practical setup is loading your signing secret or key material from application configuration and typing it as a `Secret`.\n\n```bash\nexport JWT_SECRET='replace-with-a-long-random-secret'\nexport JWT_ISSUER='example-app'\nexport JWT_AUDIENCE='web'\n```\n\n```typescript\nimport type { Secret } from \"jsonwebtoken\";\n\nfunction requiredEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) {\n    throw new Error(`${name} is required`);\n  }\n\n  return value;\n}\n\nexport const jwtSecret: Secret = requiredEnv(\"JWT_SECRET\");\nexport const jwtIssuer = requiredEnv(\"JWT_ISSUER\");\nexport const jwtAudience = requiredEnv(\"JWT_AUDIENCE\");\n```\n\nFor asymmetric algorithms such as `RS256` or `ES256`, the key parameter types also accept Node crypto key input or a `KeyObject`.\n\n## Common Workflows\n\n### Sign a token with typed claims\n\n`sign()` accepts `string`, `Buffer`, or object payloads. Use an object payload when you want JWT claims like `exp`, `nbf`, `iss`, `sub`, or `aud` to be managed through the payload or options object.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\nimport type { JwtPayload } from \"jsonwebtoken\";\n\ntype SessionClaims = JwtPayload & {\n  sub: string;\n  role: \"admin\" | \"member\";\n};\n\nexport function issueAccessToken(userId: string, role: SessionClaims[\"role\"]) {\n  const payload: SessionClaims = {\n    sub: userId,\n    role,\n  };\n\n  return jwt.sign(payload, jwtSecret, {\n    algorithm: \"HS256\",\n    issuer: jwtIssuer,\n    audience: jwtAudience,\n    expiresIn: \"15m\",\n  });\n}\n```\n\nThe declaration package types `algorithm`, `expiresIn`, `notBefore`, `issuer`, `audience`, `subject`, and `jwtid` for the runtime `sign()` call.\n\n### Verify a token and narrow the payload shape\n\nThe synchronous `verify()` overload returns `JwtPayload | string` unless you request `complete: true`. Narrow the result before reading custom claims.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\nimport type { JwtPayload } from \"jsonwebtoken\";\n\ntype SessionClaims = JwtPayload & {\n  sub: string;\n  role: \"admin\" | \"member\";\n};\n\nfunction isSessionClaims(value: string | JwtPayload): value is SessionClaims {\n  return (\n    typeof value !== \"string\" &&\n    typeof value.sub === \"string\" &&\n    (value.role === \"admin\" || value.role === \"member\")\n  );\n}\n\nexport function readAccessToken(token: string): SessionClaims {\n  const decoded = jwt.verify(token, jwtSecret, {\n    algorithms: [\"HS256\"],\n    issuer: jwtIssuer,\n    audience: jwtAudience,\n  });\n\n  if (!isSessionClaims(decoded)) {\n    throw new Error(\"Unexpected token payload\");\n  }\n\n  return decoded;\n}\n```\n\nThis is the main type boundary in everyday use: TypeScript can tell you the return type is a union, but your application still needs a runtime check for the payload shape it expects.\n\n### Handle `verify()` errors explicitly\n\nThe declarations expose the runtime error classes so you can branch on expiration, activation time, or general verification failures.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\n\nexport function tryReadAccessToken(token: string) {\n  try {\n    return readAccessToken(token);\n  } catch (error) {\n    if (error instanceof jwt.TokenExpiredError) {\n      return null;\n    }\n\n    if (error instanceof jwt.NotBeforeError) {\n      throw new Error(\"Token is not active yet\");\n    }\n\n    if (error instanceof jwt.JsonWebTokenError) {\n      throw new Error(\"Token verification failed\");\n    }\n\n    throw error;\n  }\n}\n```\n\nThis works with the synchronous `verify()` overloads, which throw on invalid input or failed validation.\n\n### Inspect the full token with `complete: true`\n\nWhen you need the JWT header as well as the payload, use `complete: true`. The return type becomes `Jwt`, which includes `header`, `payload`, and `signature`.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\n\nexport function inspectToken(token: string) {\n  const decoded = jwt.verify(token, jwtSecret, {\n    algorithms: [\"HS256\"],\n    complete: true,\n  });\n\n  console.log(decoded.header.alg);\n  console.log(decoded.header.kid);\n\n  if (typeof decoded.payload !== \"string\") {\n    console.log(decoded.payload.sub);\n  }\n}\n```\n\nThis is useful when your app needs header fields such as `kid` during key rotation or debugging.\n\n### Fetch the verification key asynchronously\n\nThe asynchronous `verify()` forms are callback-based. They matter when your app selects a public key from the token header before verification.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\nimport { createPublicKey } from \"node:crypto\";\nimport type { GetPublicKeyOrSecret, JwtPayload } from \"jsonwebtoken\";\n\nconst publicKeys = new Map<string, string>([\n  [\"current\", process.env.JWT_PUBLIC_KEY ?? \"\"],\n]);\n\nconst getKey: GetPublicKeyOrSecret = (header, done) => {\n  const kid = header.kid;\n  const pem = kid ? publicKeys.get(kid) : undefined;\n\n  if (!pem) {\n    done(new Error(\"Unknown signing key\"));\n    return;\n  }\n\n  done(null, createPublicKey(pem));\n};\n\nexport function verifyWithKeyLookup(token: string) {\n  return new Promise<JwtPayload | string>((resolve, reject) => {\n    jwt.verify(token, getKey, { algorithms: [\"RS256\"] }, (error, decoded) => {\n      if (error) {\n        reject(error);\n        return;\n      }\n\n      resolve(decoded as JwtPayload | string);\n    });\n  });\n}\n```\n\nThe package types the `header` parameter, the signing-key callback, and the callback result. There is no Promise-returning `verify()` overload in this package; wrap the callback form yourself if you want `await` in application code.\n\n### Decode a token without verifying it\n\n`decode()` is typed separately from `verify()` and returns `null` when the token cannot be decoded.\n\n```typescript\nimport * as jwt from \"jsonwebtoken\";\n\nexport function readTokenBody(token: string) {\n  return jwt.decode(token, { json: true });\n}\n```\n\nUse `decode()` only for non-authentication tasks such as logging or debugging. It does not validate the signature.\n\n## Common Pitfalls\n\n- Install `jsonwebtoken` as well as `@types/jsonwebtoken`; the declaration package does not include signing or verification code.\n- Import from `jsonwebtoken`, never from `@types/jsonwebtoken`.\n- Prefer object payloads when using `expiresIn`, `notBefore`, `issuer`, `subject`, `audience`, or `jwtid`; the runtime rejects those options for string or `Buffer` payloads.\n- Do not set both `payload.exp` and `options.expiresIn`, or both `payload.nbf` and `options.notBefore`; the runtime treats those combinations as errors.\n- `verify()` returns a union type, so narrow `string | JwtPayload` before reading custom claims.\n- `decode()` does not verify a signature and must not be used as an authentication check.\n- The async `sign()` and `verify()` APIs are callback-based, not Promise-based.\n- If you use `maxAge` during verification, the runtime requires an `iat` claim to be present.\n- Keep the runtime package on the same major line as the declaration package; `@types/jsonwebtoken@9.0.10` is written for the `jsonwebtoken` v9 API surface.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/jsonwebtoken\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jsonwebtoken\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jsonwebtoken/index.d.ts\n- https://www.npmjs.com/package/jsonwebtoken\n- https://github.com/auth0/node-jsonwebtoken\n"
  },
  {
    "path": "content/typescript/docs/koa/typescript/DOC.md",
    "content": "---\nname: koa\ndescription: \"TypeScript declarations for Koa applications, middleware, context, state, and module augmentation.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,koa,node,http,middleware,types,definitelytyped\"\n---\n\n# Koa TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/koa` alongside the real `koa` runtime package.\n\n`@types/koa` only provides TypeScript declarations. Your application imports and runs `koa`; the declaration package supplies the types for `new Koa()`, `app.use()`, `ctx`, `ctx.state`, `app.context`, `Middleware`, `Next`, and `ParameterizedContext`.\n\n## Install\n\nInstall the runtime package first, then add the declaration package and Node.js types for TypeScript.\n\n```bash\nnpm install koa\nnpm install -D typescript @types/koa @types/node\n```\n\nIf your project already has `koa`, add only the missing declarations:\n\n```bash\nnpm install -D @types/koa @types/node\n```\n\nNo credentials, API keys, or framework-specific environment variables are required for `@types/koa` itself.\n\n## Initialization\n\nThe important setup points are your import style, your TypeScript compiler options, and how you model app-wide state and context.\n\n### Import `koa`\n\nThe declaration package uses `export =`, so the most portable import form is:\n\n```typescript\nimport Koa = require(\"koa\");\n\nconst app = new Koa();\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport Koa from \"koa\";\n\nconst app = new Koa();\n```\n\nImport from `koa`, never from `@types/koa`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict ambient type packages with `compilerOptions.types`, include at least `node` and `koa` in the server project that compiles your Koa app:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"koa\"]\n  }\n}\n```\n\n### Create an app and return a response\n\n```typescript\nimport Koa = require(\"koa\");\n\nconst app = new Koa();\n\napp.use(async (ctx) => {\n  ctx.status = 200;\n  ctx.body = {\n    ok: true,\n    path: ctx.path,\n  };\n});\n\nconst port = Number(process.env.PORT ?? 3000);\napp.listen(port);\n```\n\n`PORT` is a normal application setting, not something required by the type package.\n\n## Common Workflows\n\n### Type app state, custom context, and response bodies\n\nThe main Koa generics are:\n\n- `new Koa<StateT, ContextT>()`\n- `Koa.Middleware<StateT, ContextT, ResponseBodyT>`\n- `Koa.ParameterizedContext<StateT, ContextT, ResponseBodyT>`\n\nUse them when request-scoped state or response body shape matters to the rest of your app.\n\n```typescript\nimport Koa = require(\"koa\");\n\ntype State = {\n  requestId: string;\n  userId?: string;\n};\n\ntype Context = {\n  startTime: number;\n};\n\ntype HealthResponse = {\n  ok: true;\n  requestId: string;\n};\n\nconst app = new Koa<State, Context>();\n\nconst assignRequestMetadata: Koa.Middleware<State, Context> = async (ctx, next) => {\n  ctx.state.requestId = ctx.get(\"x-request-id\") || \"generated-request-id\";\n  ctx.startTime = Date.now();\n  await next();\n};\n\nconst healthcheck: Koa.Middleware<State, Context, HealthResponse> = async (ctx) => {\n  ctx.body = {\n    ok: true,\n    requestId: ctx.state.requestId,\n  };\n};\n\napp.use(assignRequestMetadata);\napp.use(healthcheck);\n```\n\nThis is the most direct way to make `ctx.state`, extra `ctx` properties, and `ctx.body` line up with your application code.\n\n### Reuse strongly typed middleware in helpers\n\n`Koa.ParameterizedContext` is useful when a helper or standalone function needs the same typed `ctx` shape as your middleware pipeline.\n\n```typescript\nimport Koa = require(\"koa\");\n\ntype State = {\n  userId?: string;\n};\n\ntype ResponseBody = {\n  id: string;\n  email: string;\n};\n\nasync function loadCurrentUser(\n  ctx: Koa.ParameterizedContext<State, Koa.DefaultContext, ResponseBody>,\n): Promise<ResponseBody | null> {\n  if (!ctx.state.userId) {\n    return null;\n  }\n\n  return {\n    id: ctx.state.userId,\n    email: `${ctx.state.userId}@example.com`,\n  };\n}\n\nconst app = new Koa<State>();\n\napp.use(async (ctx) => {\n  const user = await loadCurrentUser(ctx);\n\n  if (!user) {\n    ctx.status = 401;\n    ctx.body = { id: \"anonymous\", email: \"anonymous@example.com\" };\n    return;\n  }\n\n  ctx.body = user;\n});\n```\n\nUse this pattern when you want helper functions to stay aligned with the same `ctx.state` and response-body types as your middleware.\n\n### Extend `DefaultState` and `DefaultContext` for app-wide fields\n\nFor fields that should exist across the whole application, module augmentation is usually simpler than threading generics through every file.\n\nCreate a declaration file such as `src/types/koa.d.ts`:\n\n```typescript\nimport \"koa\";\n\ninterface Services {\n  audit(message: string): Promise<void>;\n}\n\ndeclare module \"koa\" {\n  interface DefaultState {\n    requestId: string;\n    userId?: string;\n  }\n\n  interface DefaultContext {\n    services: Services;\n  }\n}\n```\n\nMake sure the file is included by your TypeScript project, for example:\n\n```json\n{\n  \"include\": [\"src/**/*.ts\", \"src/types/**/*.d.ts\"]\n}\n```\n\nThen populate the runtime property and use it in middleware:\n\n```typescript\nimport Koa from \"koa\";\n\nconst app = new Koa();\n\napp.context.services = {\n  async audit(message) {\n    console.log(message);\n  },\n};\n\napp.use(async (ctx, next) => {\n  ctx.state.requestId = ctx.get(\"x-request-id\") || \"generated-request-id\";\n  await ctx.services.audit(`${ctx.method} ${ctx.path}`);\n  await next();\n});\n```\n\nThis is the most practical pattern when every handler needs the same custom `ctx.state` or `ctx` fields.\n\n### Handle errors with typed `ctx`\n\nKoa applications commonly centralize errors in top-level middleware and on the app error event.\n\n```typescript\nimport Koa = require(\"koa\");\n\nconst app = new Koa();\n\napp.use(async (ctx, next) => {\n  try {\n    await next();\n  } catch (err) {\n    ctx.status = 500;\n    ctx.body = { error: \"internal_server_error\" };\n    ctx.app.emit(\"error\", err as Error, ctx);\n  }\n});\n\napp.on(\"error\", (err, ctx) => {\n  console.error(err.message, ctx.path);\n});\n```\n\nThe declaration package types both the `error` event callback and the middleware `ctx` object, so you can centralize logging without dropping to `any`.\n\n## Important Pitfalls\n\n- Install `koa` as well as `@types/koa`; the declaration package contains no executable code.\n- Import from `koa`, not from `@types/koa`.\n- If you want to write `import Koa from \"koa\"`, enable `esModuleInterop` or `allowSyntheticDefaultImports`; otherwise use `import Koa = require(\"koa\")`.\n- `ctx.request.body` is not part of Koa core. If you add request-body parsing middleware, that middleware package controls the runtime behavior and any extra typings.\n- TypeScript generics describe your application contracts, but they do not validate headers, bodies, or authentication at runtime.\n- The `use<NewStateT, NewContextT>()` signature returns a widened `Application` type. If you rely on that widening, keep the returned type in a chained expression or use module augmentation for app-wide fields.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/koa==3.0.1`.\n- The package is a DefinitelyTyped declaration package for the `koa` runtime module.\n- The published declarations use `export =`, which is why import style depends on your TypeScript interop settings.\n- The declarations cover application, middleware, request, response, context, and context-parameterization types; request-body parsing still comes from separate runtime middleware.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/koa\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/koa\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa/index.d.ts\n- https://www.npmjs.com/package/koa\n- https://github.com/koajs/koa#readme\n"
  },
  {
    "path": "content/typescript/docs/leaflet/typescript/DOC.md",
    "content": "---\nname: leaflet\ndescription: \"TypeScript declarations for Leaflet maps, tile layers, markers, events, bounds, and browser-based map initialization.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.9.21\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,leaflet,maps,browser,geojson,types,definitelytyped\"\n---\n\n# Leaflet TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/leaflet` alongside the real `leaflet` runtime package.\n\n`@types/leaflet` only provides TypeScript declarations. Your application imports and runs `leaflet`; the declaration package supplies types for `L.map()`, `L.tileLayer()`, `L.marker()`, `MapOptions`, `LatLngExpression`, `LeafletMouseEvent`, and the rest of the Leaflet 1.9 API surface.\n\n## Install\n\nInstall the Leaflet runtime first, then add TypeScript and the declaration package:\n\n```bash\nnpm install leaflet\nnpm install -D typescript @types/leaflet\n```\n\nIf your project already depends on `leaflet`, add only the missing declarations:\n\n```bash\nnpm install -D @types/leaflet\n```\n\nImport from `leaflet`, never from `@types/leaflet`.\n\n## Initialization\n\nThere are no credentials or package-specific environment variables.\n\nThe practical setup points are your browser-oriented TypeScript configuration, the Leaflet CSS import, and creating the map after the container element exists.\n\n### Recommended `tsconfig.json`\n\nLeaflet targets the browser, so keep DOM library types enabled in the project that compiles your map code.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"lib\": [\"ES2022\", \"DOM\"],\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your app has separate server and browser builds, keep Leaflet code in the browser/client build that includes `\"DOM\"`.\n\n### Import `leaflet` and its CSS\n\nIn TypeScript module code, import from `leaflet` itself:\n\n```typescript\nimport * as L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\n```\n\n### Provide a map container\n\nLeaflet needs a real DOM element with a non-zero height.\n\n```html\n<div id=\"map\"></div>\n```\n\n```css\n#map {\n  height: 320px;\n}\n```\n\n## Common Workflows\n\n### Create a typed map and add a tile layer\n\nThis is the smallest practical browser setup.\n\n```typescript\nimport * as L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\n\nconst container = document.getElementById(\"map\");\n\nif (!container) {\n  throw new Error(\"Missing #map container\");\n}\n\nconst map = L.map(container, {\n  center: [51.505, -0.09],\n  zoom: 13,\n});\n\nL.tileLayer(\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\", {\n  maxZoom: 19,\n  attribution:\n    '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>',\n}).addTo(map);\n```\n\nThis gives you a typed `L.Map` instance with methods such as `setView()`, `fitBounds()`, `on()`, `off()`, and `remove()`.\n\n### Add a marker and handle click events with typed coordinates\n\nUse `LatLngExpression` for coordinate inputs and `LeafletMouseEvent` for map click handlers.\n\n```typescript\nimport * as L from \"leaflet\";\n\nconst map = L.map(\"map\", {\n  center: [51.505, -0.09],\n  zoom: 13,\n});\n\nconst office: L.LatLngExpression = [51.5, -0.09];\n\nconst marker = L.marker(office)\n  .addTo(map)\n  .bindPopup(\"Office\");\n\nmap.on(\"click\", (event: L.LeafletMouseEvent) => {\n  marker\n    .setLatLng(event.latlng)\n    .setPopupContent(\n      `Selected ${event.latlng.lat.toFixed(5)}, ${event.latlng.lng.toFixed(5)}`,\n    )\n    .openPopup();\n});\n```\n\n`LatLngExpression` is useful when your coordinates may be a tuple, an `L.LatLng` instance, or another supported Leaflet coordinate shape.\n\n### Fit the viewport to typed route points\n\nAnnotate coordinate collections with `L.LatLngExpression[]` and let Leaflet compute bounds from runtime layer objects.\n\n```typescript\nimport * as L from \"leaflet\";\n\nconst map = L.map(\"map\", {\n  center: [51.505, -0.09],\n  zoom: 13,\n});\n\nconst route: L.LatLngExpression[] = [\n  [51.509, -0.08],\n  [51.503, -0.06],\n  [51.51, -0.047],\n];\n\nconst polyline = L.polyline(route, {\n  color: \"#2563eb\",\n  weight: 4,\n}).addTo(map);\n\nmap.fitBounds(polyline.getBounds(), {\n  padding: [24, 24],\n});\n```\n\nThis is a common TypeScript boundary in Leaflet apps: provide flexible coordinate inputs up front, then use concrete Leaflet objects such as `L.Polyline` and `L.LatLngBounds` afterward.\n\n### Clean up a map instance in client-side app code\n\nIf a framework mounts and unmounts the same view repeatedly, keep the map instance typed and call `remove()` during cleanup.\n\n```typescript\nimport * as L from \"leaflet\";\n\nlet map: L.Map | undefined;\n\nexport function mountMap(container: HTMLElement) {\n  map = L.map(container, {\n    center: [51.505, -0.09],\n    zoom: 13,\n  });\n\n  return map;\n}\n\nexport function unmountMap() {\n  map?.remove();\n  map = undefined;\n}\n```\n\n## Important Pitfalls\n\n- `@types/leaflet` does not include the Leaflet runtime or CSS. Install `leaflet` separately.\n- Import from `leaflet`, not from `@types/leaflet`.\n- Create the map only after the container exists in the DOM. Leaflet is a browser library, not a server-side renderer.\n- Give the container an explicit height. A zero-height element produces an empty map area.\n- Keep the runtime package and the declaration package aligned around the same Leaflet API generation. This guide targets `@types/leaflet` `1.9.21`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/leaflet\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/leaflet\n- https://leafletjs.com/examples/quick-start/\n- https://leafletjs.com/reference.html\n"
  },
  {
    "path": "content/typescript/docs/less/typescript/DOC.md",
    "content": "---\nname: less\ndescription: \"TypeScript declarations for the `less` compiler, covering installation with the runtime package, portable imports, typed `less.render()` usage, and plugin hooks.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,less,css,stylesheets,build-tools,types,definitelytyped\"\n---\n\n# less TypeScript Guide\n\n`@types/less` adds TypeScript declarations for the `less` runtime package. Install it when your project compiles `.less` source and you want typed access to `less.render()`, `Less.Options`, `Less.RenderOutput`, `Less.RenderError`, and plugin-related interfaces.\n\nThis package only provides declarations. Import and execute code from `less`, not from `@types/less`.\n\n## Golden Rule\n\nInstall `less` and `@types/less` together.\n\n`@types/less` does not include the Less compiler, file loading, or the `lessc` executable. It only describes the API exposed by the real `less` package.\n\n## Install\n\nIf Less is only part of your build pipeline, install the runtime compiler and typings as development dependencies:\n\n```bash\nnpm install -D less @types/less typescript @types/node\n```\n\nIf your application calls `less.render()` at runtime, keep `less` in regular dependencies and install the declarations separately:\n\n```bash\nnpm install less\nnpm install -D @types/less typescript @types/node\n```\n\n`less` and `@types/less` do not require API keys, service credentials, or package-specific environment variables.\n\n## TypeScript Setup\n\nThe declaration package uses `export =`, so the most portable import form is:\n\n```typescript\nimport less = require(\"less\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport less from \"less\";\n```\n\nRecommended `tsconfig.json` settings for a Node.js project that compiles Less:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nYou do not need to add `less` to `compilerOptions.types`. The package is resolved from the normal module import.\n\nIf you use the browser-facing `less` APIs such as `sheets`, `refresh()`, or `watch()`, keep the `DOM` library enabled in that TypeScript project.\n\n## Initialization\n\nThere is no client object to configure and no authentication step.\n\nThe practical setup is:\n\n- read Less source from disk or another input\n- build a `Less.Options` object\n- call `less.render()`\n\nWhen your stylesheet uses relative `@import`s, set `filename` and usually `paths` so Less can resolve them correctly.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport less = require(\"less\");\n\nexport async function compileLess(entryFile: string): Promise<Less.RenderOutput> {\n  const absoluteEntry = resolve(entryFile);\n  const source = await readFile(absoluteEntry, \"utf8\");\n\n  const options: Less.Options = {\n    filename: absoluteEntry,\n    paths: [dirname(absoluteEntry)],\n    sourceMap: {\n      sourceMapFileInline: true,\n    },\n  };\n\n  return less.render(source, options);\n}\n\nconst output = await compileLess(\"src/styles/app.less\");\nconsole.log(output.css);\nconsole.log(output.imports);\n```\n\n`less.render()` accepts Less source text, not a file path. Reading the file yourself and passing `filename` is the important integration boundary for Node.js code.\n\n## Common Workflows\n\n### Compile an inline Less string with typed options\n\nUse `Less.Options` when you want the compiler options checked by TypeScript.\n\n```typescript\nimport less = require(\"less\");\n\nconst source = `\n@brand: #2563eb;\n\n.button {\n  color: @brand;\n}\n`;\n\nconst options: Less.Options = {\n  filename: \"inline.less\",\n  math: \"parens-division\",\n  rewriteUrls: \"off\",\n  sourceMap: {\n    sourceMapFileInline: true,\n  },\n};\n\nconst result = await less.render(source, options);\n\nconsole.log(result.css);\nconsole.log(result.map);\n```\n\nThe typings model `sourceMap` as an object, and `rewriteUrls` as `\"off\"`, `\"all\"`, or `\"local\"`.\n\n### Surface typed render errors\n\nThe callback overload exposes a typed `Less.RenderError` with line, column, and filename information.\n\n```typescript\nimport less = require(\"less\");\n\nless.render(\n  \".card { color: @missing; }\",\n  { filename: \"broken.less\" },\n  (error, output) => {\n    if (error) {\n      console.error(`${error.filename}:${error.line}:${error.column}`);\n      console.error(error.message);\n      console.error(error.extract.join(\"\\n\"));\n      return;\n    }\n\n    console.log(output!.css);\n  },\n);\n```\n\nThis is the simplest way to keep error handling strongly typed without writing your own `unknown` narrowing around a rejected Promise.\n\n### Register a typed plugin\n\nThe declarations include `Less.Plugin`, `Less.PluginManager`, and `Less.PreProcessor` for plugin authoring.\n\n```typescript\nimport less = require(\"less\");\n\nconst bannerPlugin: Less.Plugin = {\n  install(_less, pluginManager) {\n    pluginManager.addPreProcessor({\n      process(src) {\n        return `/* generated by less */\\n${src}`;\n      },\n    });\n  },\n};\n\nconst result = await less.render(\".box { color: red; }\", {\n  filename: \"plugin-example.less\",\n  plugins: [bannerPlugin],\n});\n\nconsole.log(result.css);\n```\n\nIf you need custom import resolution, the same package also types `Less.FileManager` and `Less.AbstractFileManager`.\n\n## Important Pitfalls\n\n- Install `less` as well as `@types/less`; the declaration package does not compile anything by itself.\n- Import from `less`, not from `@types/less`.\n- Prefer `import less = require(\"less\")` unless your project already enables `esModuleInterop`.\n- Pass source text into `less.render()`. If you start from a file on disk, read it first and set `filename` so relative `@import`s and diagnostics resolve correctly.\n- Treat `sourceMap` as an options object, not a boolean flag.\n- `compress`, `color`, `ieCompat`, and `javascriptEnabled` are marked deprecated in `Less.Options`.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/less==3.0.8`.\n- The published declaration package sets `typeScriptVersion` to `5.0`.\n- The `less` package metadata does not advertise bundled TypeScript declarations, so `@types/less` remains the package that supplies types for `import \"less\"`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/less\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/less\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/less/index.d.ts\n- https://www.npmjs.com/package/less\n"
  },
  {
    "path": "content/typescript/docs/lodash/typescript/DOC.md",
    "content": "---\nname: lodash\ndescription: \"TypeScript declarations for Lodash 4, including safe installation, CommonJS-friendly imports, typed utility helpers, and the boundary between the `lodash` runtime and `@types/lodash`.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.17.24\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,utility,types,definitelytyped,npm\"\n---\n\n# lodash TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash` for runtime behavior and `@types/lodash` for compile-time declarations.\n\nImport from `\"lodash\"` in application code. Do not import from `\"@types/lodash\"` directly.\n\nThis package tracks the Lodash 4 API surface. Use it when your project calls helpers such as `_.groupBy()`, `_.keyBy()`, `_.pick()`, `_.debounce()`, and `_.get()` from the `lodash` runtime package.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash\nnpm install -D typescript @types/lodash@4.17.24\n```\n\nIf your project already has TypeScript, add only the Lodash declarations:\n\n```bash\nnpm install -D @types/lodash@4.17.24\n```\n\nThere is no client object, authentication flow, or package-specific environment variable.\n\n## Import Style And `tsconfig.json`\n\nThe declaration package is designed for the `lodash` module, not for a separate `@types/lodash` import path.\n\nThe most direct import form in TypeScript is the CommonJS-compatible syntax:\n\n```typescript\nimport _ = require(\"lodash\");\n```\n\nIf your project already enables interop for default imports, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport _ from \"lodash\";\n```\n\nUse one import style consistently across the project.\n\n## Common Workflows\n\n### Group, index, and reshape collections\n\nLodash's collection helpers preserve useful type information for common array-to-object and array-to-array transforms.\n\n```typescript\nimport _ = require(\"lodash\");\n\ntype User = {\n  id: string;\n  orgId: string;\n  email: string;\n  active: boolean;\n};\n\nconst users: User[] = [\n  { id: \"u_1\", orgId: \"org_a\", email: \"ada@example.com\", active: true },\n  { id: \"u_2\", orgId: \"org_a\", email: \"grace@example.com\", active: false },\n  { id: \"u_3\", orgId: \"org_b\", email: \"linus@example.com\", active: true },\n];\n\nconst usersById = _.keyBy(users, \"id\");\nconst usersByOrg = _.groupBy(users, \"orgId\");\nconst activeEmails = _.map(_.filter(users, { active: true }), \"email\");\n\nconsole.log(usersById.u_1.email);\nconsole.log(usersByOrg.org_a.length);\nconsole.log(activeEmails);\n```\n\n### Read nested values with a typed fallback\n\n`_.get()` is most useful in TypeScript when you provide a default value for optional nested data.\n\n```typescript\nimport _ = require(\"lodash\");\n\ntype AppConfig = {\n  cache?: {\n    ttlSeconds?: number;\n  };\n  flags?: {\n    auditLogs?: boolean;\n  };\n};\n\nconst config: AppConfig = {};\n\nconst ttlSeconds = _.get(config, \"cache.ttlSeconds\", 60);\nconst auditLogsEnabled = _.get(config, \"flags.auditLogs\", false);\n\nconsole.log(ttlSeconds);\nconsole.log(auditLogsEnabled);\n```\n\nWithout a fallback, nested lookups often include `undefined` in the result type and require an extra runtime check.\n\n### Create smaller payloads with `pick()` and `omit()`\n\nThese helpers are convenient at API boundaries where you need to shape data before sending it to another layer.\n\n```typescript\nimport _ = require(\"lodash\");\n\ntype UserRecord = {\n  id: string;\n  email: string;\n  passwordHash: string;\n  createdAt: string;\n};\n\nconst user: UserRecord = {\n  id: \"u_1\",\n  email: \"ada@example.com\",\n  passwordHash: \"hashed\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst publicUser = _.pick(user, [\"id\", \"email\", \"createdAt\"]);\nconst safeForLogs = _.omit(user, [\"passwordHash\"]);\n\nconsole.log(publicUser);\nconsole.log(safeForLogs);\n```\n\n### Debounce event-driven work\n\n`_.debounce()` is a common place where the Lodash types matter in real apps because the returned function also exposes `cancel()` and `flush()`.\n\n```typescript\nimport _ = require(\"lodash\");\n\ntype SearchInput = {\n  query: string;\n};\n\nconst sendSearch = _.debounce((input: SearchInput) => {\n  console.log(`Searching for ${input.query}`);\n}, 250, { maxWait: 1000 });\n\nsendSearch({ query: \"typescript lodash\" });\nsendSearch.flush();\nsendSearch.cancel();\n```\n\n## Minimal End-to-End Example\n\nThis example uses a small in-memory dataset, reads a search prefix from the environment, and returns grouped results with Lodash helpers.\n\n```typescript\nimport _ = require(\"lodash\");\n\ntype PackageRow = {\n  name: string;\n  scope: \"runtime\" | \"types\";\n};\n\nconst rows: PackageRow[] = [\n  { name: \"lodash\", scope: \"runtime\" },\n  { name: \"@types/lodash\", scope: \"types\" },\n  { name: \"lodash-es\", scope: \"runtime\" },\n];\n\nconst prefix = process.env.PACKAGE_PREFIX ?? \"lod\";\n\nconst grouped = _.groupBy(\n  rows.filter((row) => row.name.startsWith(prefix)),\n  \"scope\",\n);\n\nconsole.log(grouped);\n```\n\nRun it with an app-specific environment variable if you want a different filter:\n\n```bash\nPACKAGE_PREFIX=@types node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/lodash` is a declaration package only. Install `lodash` separately for the runtime.\n- Do not import from `@types/lodash` in application code.\n- `import _ = require(\"lodash\")` is the safest import form when you want to match the CommonJS-oriented declarations directly.\n- If you prefer `import _ from \"lodash\"`, enable `compilerOptions.esModuleInterop` in TypeScript.\n- `_.get()` without a default value often produces a type that still includes `undefined`.\n- Keep the Lodash runtime on the Lodash 4 API surface that these declarations describe.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash==4.17.24`.\n- These declarations are intended for the `lodash` package, not as a standalone runtime.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/lodash\n- DefinitelyTyped source for `@types/lodash`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash\n- `@types/lodash` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/index.d.ts\n- Lodash documentation: https://lodash.com/docs/\n- TypeScript `esModuleInterop` reference: https://www.typescriptlang.org/tsconfig#esModuleInterop\n"
  },
  {
    "path": "content/typescript/docs/lodash.clonedeep/typescript/DOC.md",
    "content": "---\nname: lodash.clonedeep\ndescription: \"TypeScript guidance for `lodash.clonedeep`, including installation of the runtime package and `@types/lodash.clonedeep`, CommonJS-friendly imports, and practical `cloneDeep()` workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.5.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,clonedeep,types,definitelytyped,npm\"\n---\n\n# lodash.clonedeep TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.clonedeep` for runtime behavior and `@types/lodash.clonedeep` for TypeScript declarations.\n\nImport from `\"lodash.clonedeep\"` in application code. Do not import from `\"@types/lodash.clonedeep\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.clonedeep\nnpm install -D typescript @types/lodash.clonedeep@4.5.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.clonedeep@4.5.9\n```\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport cloneDeep = require(\"lodash.clonedeep\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport cloneDeep from \"lodash.clonedeep\";\n```\n\nPick one import style and use it consistently.\n\n## Common Workflows\n\n### Clone nested configuration before mutation\n\n`cloneDeep()` is most useful when you need a writable copy of nested application data without changing the original value.\n\n```typescript\nimport cloneDeep = require(\"lodash.clonedeep\");\n\ntype FeatureFlags = {\n  auditLogs: boolean;\n  exports: {\n    csv: boolean;\n    json: boolean;\n  };\n};\n\ntype AppConfig = {\n  region: string;\n  retries: number;\n  flags: FeatureFlags;\n};\n\nconst baseConfig: AppConfig = {\n  region: \"us-east-1\",\n  retries: 3,\n  flags: {\n    auditLogs: false,\n    exports: { csv: true, json: false },\n  },\n};\n\nconst previewConfig = cloneDeep(baseConfig);\npreviewConfig.flags.auditLogs = true;\npreviewConfig.flags.exports.json = true;\n\nconsole.log(baseConfig.flags.auditLogs);\nconsole.log(previewConfig.flags.auditLogs);\n```\n\nThe cloned value keeps the same static TypeScript shape as the original value.\n\n### Return updated state from helper functions\n\nWhen you want immutable-style updates in service code or reducers, clone first and then update the copy.\n\n```typescript\nimport cloneDeep = require(\"lodash.clonedeep\");\n\ntype CartItem = {\n  sku: string;\n  quantity: number;\n};\n\ntype Cart = {\n  customerId: string;\n  items: CartItem[];\n  metadata: {\n    currency: \"USD\" | \"EUR\";\n    updatedBy: string;\n  };\n};\n\nfunction addItem(cart: Cart, item: CartItem, updatedBy: string): Cart {\n  const next = cloneDeep(cart);\n  next.items.push(item);\n  next.metadata.updatedBy = updatedBy;\n  return next;\n}\n\nconst original: Cart = {\n  customerId: \"cus_123\",\n  items: [{ sku: \"starter\", quantity: 1 }],\n  metadata: {\n    currency: \"USD\",\n    updatedBy: \"system\",\n  },\n};\n\nconst updated = addItem(original, { sku: \"pro\", quantity: 1 }, \"agent\");\n\nconsole.log(original.items.length);\nconsole.log(updated.items.length);\n```\n\nThis pattern works well when your application types already describe the nested data you want to copy.\n\n### Wrap `cloneDeep()` in typed utilities\n\nThe declaration package preserves the input type, so local helpers can stay generic.\n\n```typescript\nimport cloneDeep = require(\"lodash.clonedeep\");\n\nfunction duplicateTemplate<T>(value: T): T {\n  return cloneDeep(value);\n}\n\nconst template = {\n  id: \"tmpl_1\",\n  schedule: {\n    cron: \"0 * * * *\",\n    enabled: true,\n  },\n};\n\nconst copy = duplicateTemplate(template);\ncopy.schedule.enabled = false;\n```\n\nThis is the main type-system benefit in day-to-day use: the cloned value flows through your code as the same `T` you passed in.\n\n## Important Pitfalls\n\n- `@types/lodash.clonedeep` does not provide runtime code. Keep `lodash.clonedeep` in your production dependencies.\n- Do not import from `@types/lodash.clonedeep`; import from `lodash.clonedeep`.\n- If `import cloneDeep from \"lodash.clonedeep\"` fails, enable `esModuleInterop` or switch to `import cloneDeep = require(\"lodash.clonedeep\")`.\n- `cloneDeep()` preserves the static TypeScript type you supply, but it does not validate unknown input. Parse or validate untrusted data before relying on its shape.\n- If your project already uses the full `lodash` package, keep your imports consistent across the codebase instead of mixing full-package and single-function module styles casually.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.clonedeep==4.5.9`.\n- The declarations are maintained in DefinitelyTyped and are intended for the standalone `lodash.clonedeep` npm module.\n- In application code, the important module specifier is still `lodash.clonedeep`; the `@types` package only adds compile-time information.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.clonedeep\n- https://www.npmjs.com/package/lodash.clonedeep\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.clonedeep\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash.clonedeep/index.d.ts\n- https://lodash.com/docs/#cloneDeep\n"
  },
  {
    "path": "content/typescript/docs/lodash.debounce/typescript/DOC.md",
    "content": "---\nname: lodash.debounce\ndescription: \"TypeScript guidance for `lodash.debounce`, including installation of the runtime package and `@types/lodash.debounce`, CommonJS-friendly imports, and practical debouncing workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.0.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.debounce,debounce,types,definitelytyped,npm\"\n---\n\n# lodash.debounce TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.debounce` for runtime behavior and `@types/lodash.debounce` for TypeScript declarations.\n\nImport from `\"lodash.debounce\"` in application code. Do not import from `\"@types/lodash.debounce\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.debounce\nnpm install -D typescript @types/lodash.debounce@4.0.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.debounce@4.0.9\n```\n\nIf your codebase already depends on the full `lodash` package and calls `_.debounce()`, keep using `lodash` with `@types/lodash` instead of mixing full-package and standalone-module styles casually.\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport debounce from \"lodash.debounce\";\n```\n\nPick one import style and use it consistently.\n\nDo not use a named import such as `import { debounce } from \"lodash.debounce\"`; this package exports a single debouncing function.\n\n## Common Workflows\n\n### Debounce a typed callback\n\n`debounce()` is most useful when you want to wait for a pause in user or system activity while keeping the original callback parameter types.\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n\ntype SearchRequest = {\n  query: string;\n  limit: number;\n};\n\nasync function fetchSuggestions(request: SearchRequest): Promise<void> {\n  console.log(`Fetching suggestions for ${request.query} (limit ${request.limit})`);\n}\n\nconst scheduleSuggestions = debounce(\n  (request: SearchRequest) => {\n    void fetchSuggestions(request);\n  },\n  250,\n  {\n    leading: false,\n    trailing: true,\n  },\n);\n\nscheduleSuggestions({ query: \"lod\", limit: 10 });\nscheduleSuggestions({ query: \"loda\", limit: 10 });\nscheduleSuggestions({ query: \"lodash\", limit: 10 });\n```\n\nThe debounced function keeps the same parameter shape as the original callback and also exposes `cancel()` and `flush()`.\n\n### Bound burst latency with `maxWait`\n\nUse `maxWait` when frequent calls should still trigger periodic work during a long burst of activity.\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n\ntype PresenceUpdate = {\n  userId: string;\n  activeDocumentId: string;\n};\n\nconst publishPresence = debounce(\n  (update: PresenceUpdate) => {\n    console.log(`Publishing presence for ${update.userId} in ${update.activeDocumentId}`);\n  },\n  300,\n  {\n    maxWait: 2000,\n    trailing: true,\n  },\n);\n\npublishPresence({ userId: \"user_1\", activeDocumentId: \"doc_1\" });\npublishPresence({ userId: \"user_1\", activeDocumentId: \"doc_1\" });\npublishPresence({ userId: \"user_1\", activeDocumentId: \"doc_1\" });\n```\n\nThis matches the Lodash `debounce(func, wait?, options?)` behavior, where `maxWait` limits how long the callback can be deferred.\n\n### Flush or cancel pending work during cleanup\n\nThe returned debounced function includes lifecycle helpers that matter in real applications.\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n\ntype Draft = {\n  id: string;\n  body: string;\n};\n\nconst saveDraft = debounce(\n  (draft: Draft) => {\n    console.log(`Saving draft ${draft.id}: ${draft.body}`);\n  },\n  1000,\n  {\n    leading: false,\n    trailing: true,\n  },\n);\n\nsaveDraft({ id: \"draft_1\", body: \"first edit\" });\nsaveDraft({ id: \"draft_1\", body: \"final edit\" });\n\nsaveDraft.flush();\nsaveDraft.cancel();\n```\n\nCall `flush()` when pending trailing work must run before shutdown or teardown. Call `cancel()` when queued work must be dropped.\n\n### Reuse one debounced function across calls\n\nCreate the debounced wrapper once, then reuse it. Re-wrapping the callback on every event defeats the debounce window.\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n\nconst sendSearchAnalytics = debounce((query: string) => {\n  console.log(`Sending analytics for ${query}`);\n}, 400);\n\nfunction onSearchInput(query: string): void {\n  sendSearchAnalytics(query);\n}\n\nonSearchInput(\"lod\");\nonSearchInput(\"loda\");\nonSearchInput(\"lodash\");\n```\n\n## Minimal End-to-End Example\n\nThis example uses an app-defined environment variable to control the debounce window for search requests. The package itself does not require any environment variables.\n\n```typescript\nimport debounce = require(\"lodash.debounce\");\n\ntype SearchRequest = {\n  query: string;\n};\n\nconst searchDebounceMs = Number(process.env.SEARCH_DEBOUNCE_MS ?? \"300\");\n\nasync function requestSuggestions(request: SearchRequest): Promise<void> {\n  console.log(`Requesting suggestions for ${request.query}`);\n}\n\nconst scheduleSuggestions = debounce(\n  (request: SearchRequest) => {\n    void requestSuggestions(request);\n  },\n  searchDebounceMs,\n  {\n    leading: false,\n    trailing: true,\n    maxWait: 1500,\n  },\n);\n\nexport function onSearchInput(query: string): void {\n  scheduleSuggestions({ query });\n}\n\nonSearchInput(\"lod\");\nonSearchInput(\"loda\");\nonSearchInput(\"lodash\");\n\nscheduleSuggestions.flush();\n```\n\nRun the compiled program with an app-specific debounce interval if you want a different window:\n\n```bash\nSEARCH_DEBOUNCE_MS=500 node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/lodash.debounce` is a declaration package only. Install `lodash.debounce` separately for the runtime.\n- Do not import from `@types/lodash.debounce` in application code.\n- `lodash.debounce` exports a single function. Use `import debounce = require(\"lodash.debounce\")` or enable `esModuleInterop` and use a default import.\n- Recreating the debounced wrapper on every call resets the timing window and defeats debouncing.\n- If `leading` and `trailing` are both `true`, the trailing invocation runs only when the debounced function is called more than once during the wait window.\n- If `wait` is `0` and `leading` is `false`, invocation is deferred to the next tick rather than running immediately.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.debounce==4.0.9`.\n- The declarations describe the Lodash 4 `debounce()` API used by the standalone `lodash.debounce` runtime package.\n- The practical options surface is `leading`, `trailing`, and `maxWait`, and the returned debounced function exposes `cancel()` and `flush()`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.debounce\n- https://www.npmjs.com/package/lodash.debounce\n- https://lodash.com/docs/4.17.21#debounce\n"
  },
  {
    "path": "content/typescript/docs/lodash.flatten/typescript/DOC.md",
    "content": "---\nname: lodash.flatten\ndescription: \"TypeScript guidance for `lodash.flatten`, including installation of the standalone runtime package and `@types/lodash.flatten`, CommonJS-friendly imports, and practical shallow `flatten()` workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.4.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.flatten,flatten,arrays,types,definitelytyped,npm\"\n---\n\n# lodash.flatten TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.flatten` for runtime behavior and `@types/lodash.flatten` for TypeScript declarations.\n\nImport from `\"lodash.flatten\"` in application code. Do not import from `\"@types/lodash.flatten\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.flatten\nnpm install -D typescript @types/lodash.flatten@4.4.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.flatten@4.4.9\n```\n\nIf your codebase already depends on the full `lodash` package and calls `_.flatten()`, keep using `lodash` with `@types/lodash` instead of mixing full-package and standalone-module imports casually.\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport flatten from \"lodash.flatten\";\n```\n\nPick one import style and use it consistently.\n\nDo not use a named import such as `import { flatten } from \"lodash.flatten\"`; this package exports a single function.\n\n## Common Workflows\n\n### Flatten arrays returned from `map()`\n\n`flatten()` is most useful when one step of your pipeline produces a `T[][]` shape and the next step wants a simple `T[]`.\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n\ntype Route = {\n  method: \"GET\" | \"POST\";\n  path: string;\n};\n\ntype Service = {\n  name: string;\n  routes: Route[];\n};\n\nconst services: Service[] = [\n  {\n    name: \"billing\",\n    routes: [\n      { method: \"GET\", path: \"/invoices\" },\n      { method: \"POST\", path: \"/invoices\" },\n    ],\n  },\n  {\n    name: \"identity\",\n    routes: [{ method: \"GET\", path: \"/users\" }],\n  },\n];\n\nconst routes = flatten(services.map((service) => service.routes));\n\nconsole.log(routes);\n```\n\nHere, TypeScript infers `routes` as `Route[]`.\n\n### Normalize values that may be single items or arrays\n\nThis package works well when your application accepts `T | T[]` and you want to normalize that input once.\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n\ntype HeaderRule = {\n  key: string;\n  value: string;\n};\n\ntype HeaderRuleInput = HeaderRule | HeaderRule[];\n\nconst ruleInputs: HeaderRuleInput[] = [\n  { key: \"x-request-id\", value: \"req_123\" },\n  [\n    { key: \"x-region\", value: \"us-east-1\" },\n    { key: \"x-service\", value: \"billing\" },\n  ],\n];\n\nconst rules = flatten(ruleInputs);\n\nconsole.log(rules);\n```\n\nThis keeps the runtime normalization simple while giving the rest of your code a stable `HeaderRule[]` shape.\n\n### Flatten exactly one level\n\n`flatten()` is shallow. It removes only one nesting level.\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n\nconst nested: Array<number | number[] | number[][]> = [\n  1,\n  [2, 3],\n  [[4, 5]],\n];\n\nconst flattenedOnce = flatten(nested);\n\nconsole.log(flattenedOnce);\n```\n\nThe result is `[1, 2, 3, [4, 5]]`, not `[1, 2, 3, 4, 5]`. If your data is nested more deeply than one level, you need a different flattening strategy.\n\n### Flatten filtered groups into a single work list\n\nThe package does not define environment variables, but it is common to flatten application data that has already been filtered using `process.env`.\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n\ntype Task = {\n  id: string;\n  internal: boolean;\n};\n\ntype TaskGroup = {\n  name: string;\n  tasks: Task[];\n};\n\nconst includeInternalTasks = process.env.INCLUDE_INTERNAL_TASKS === \"1\";\n\nconst groups: TaskGroup[] = [\n  {\n    name: \"default\",\n    tasks: [\n      { id: \"task_public_1\", internal: false },\n      { id: \"task_internal_1\", internal: true },\n    ],\n  },\n  {\n    name: \"reports\",\n    tasks: [{ id: \"task_public_2\", internal: false }],\n  },\n];\n\nconst visibleTasks = flatten(\n  groups.map((group) =>\n    group.tasks.filter((task) => includeInternalTasks || !task.internal),\n  ),\n);\n\nconsole.log(visibleTasks.map((task) => task.id));\n```\n\n## Minimal End-to-End Example\n\nThis example builds a list of tags from grouped records, filters by an app-defined environment variable, and flattens the remaining arrays into one typed result.\n\n```typescript\nimport flatten = require(\"lodash.flatten\");\n\ntype Article = {\n  slug: string;\n  tags: string[];\n  archived: boolean;\n};\n\ntype Category = {\n  name: string;\n  articles: Article[];\n};\n\nconst includeArchived = process.env.INCLUDE_ARCHIVED_ARTICLES === \"1\";\n\nconst categories: Category[] = [\n  {\n    name: \"typescript\",\n    articles: [\n      { slug: \"flatten-arrays\", tags: [\"typescript\", \"arrays\"], archived: false },\n      { slug: \"legacy-imports\", tags: [\"typescript\", \"commonjs\"], archived: true },\n    ],\n  },\n  {\n    name: \"runtime\",\n    articles: [\n      { slug: \"lodash-workflows\", tags: [\"lodash\", \"utility\"], archived: false },\n    ],\n  },\n];\n\nconst tags = flatten(\n  categories.map((category) =>\n    category.articles\n      .filter((article) => includeArchived || !article.archived)\n      .map((article) => article.tags),\n  ),\n);\n\nconsole.log(tags);\n```\n\nRun the compiled program with an app-specific flag if you want archived articles included:\n\n```bash\nINCLUDE_ARCHIVED_ARTICLES=1 node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/lodash.flatten` is a declaration package only. Keep `lodash.flatten` in your runtime dependencies.\n- Do not import from `@types/lodash.flatten`; import from `lodash.flatten`.\n- `lodash.flatten` exports a single function. Use `import flatten = require(\"lodash.flatten\")` or enable `esModuleInterop` and use a default import.\n- `flatten()` removes only one array nesting level. It does not recursively flatten arbitrarily deep structures.\n- If your data comes from untyped JSON or another untrusted source, validate it before relying on the inferred `flatten()` result type.\n- If your project already uses the full `lodash` package, keep import style consistent across the codebase instead of mixing per-method modules and full-package imports casually.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.flatten==4.4.9`.\n- The declarations are maintained in DefinitelyTyped and are intended for the standalone `lodash.flatten` npm module.\n- The documented runtime behavior is the Lodash 4 shallow `flatten(array)` helper: one level only.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.flatten\n- https://www.npmjs.com/package/lodash.flatten\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.flatten\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash.flatten/index.d.ts\n- https://lodash.com/docs/#flatten\n- https://www.typescriptlang.org/tsconfig#esModuleInterop\n"
  },
  {
    "path": "content/typescript/docs/lodash.isequal/typescript/DOC.md",
    "content": "---\nname: lodash.isequal\ndescription: \"TypeScript guidance for `lodash.isequal`, including the `@types/lodash.isequal` stub package, imports, deep equality checks, and common integration pitfalls.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.5.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.isequal,deep-equality,types,definitelytyped,npm\"\n---\n\n# lodash.isequal TypeScript Guide\n\n## Golden Rule\n\n`@types/lodash.isequal` `4.5.8` is a stub declaration package. The published package entry points TypeScript users to `lodash.isequal`, which provides the declarations you should use in application code.\n\nInstall and import `lodash.isequal`. Do not import anything from `@types/lodash.isequal`.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install lodash.isequal\nnpm install -D typescript @types/node\n```\n\nIf your project added `@types/lodash.isequal` directly, remove it:\n\n```bash\nnpm uninstall @types/lodash.isequal\n```\n\nIf a transitive dependency still installs `@types/lodash.isequal`, you usually do not need to do anything. Import from `lodash.isequal`, and let TypeScript resolve the declarations from the runtime package.\n\n## Initialization\n\nThere are no environment variables, credentials, client objects, or service initialization steps for this package.\n\nThe practical setup steps are:\n\n- install `lodash.isequal`\n- import from `lodash.isequal`\n- use a TypeScript module configuration that matches your runtime\n\n### Recommended `tsconfig.json`\n\nIf you want a default import in a typical Node.js project, enable interop:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n## Import Patterns\n\nWith `esModuleInterop`, use a default import:\n\n```typescript\nimport isEqual from \"lodash.isequal\";\n```\n\nIn CommonJS-oriented TypeScript without interop, use:\n\n```typescript\nimport isEqual = require(\"lodash.isequal\");\n```\n\nDo not import from `@types/lodash.isequal`.\n\n## Common Workflows\n\n### Compare typed settings before writing updates\n\n`isEqual()` is most useful when you want to skip an update unless a nested object actually changed.\n\n```typescript\nimport isEqual from \"lodash.isequal\";\n\ntype FeatureFlags = {\n  auditLogs: boolean;\n  exports: {\n    csv: boolean;\n    json: boolean;\n  };\n};\n\ntype AppSettings = {\n  region: string;\n  retries: number;\n  flags: FeatureFlags;\n};\n\nconst previous: AppSettings = {\n  region: \"us-east-1\",\n  retries: 3,\n  flags: {\n    auditLogs: true,\n    exports: { csv: true, json: false },\n  },\n};\n\nconst next: AppSettings = {\n  region: \"us-east-1\",\n  retries: 3,\n  flags: {\n    auditLogs: true,\n    exports: { csv: true, json: false },\n  },\n};\n\nif (isEqual(previous, next)) {\n  console.log(\"No settings update required\");\n} else {\n  console.log(\"Persist updated settings\");\n}\n```\n\nThis avoids false positives from reference inequality when two separately created objects contain the same values.\n\n### Detect nested payload changes in API code\n\nWhen your code receives JSON-like data from requests or queues, define the shape in your app and compare values with that type.\n\n```typescript\nimport isEqual from \"lodash.isequal\";\n\ntype LineItem = {\n  sku: string;\n  quantity: number;\n};\n\ntype OrderPayload = {\n  orderId: string;\n  customerId: string;\n  items: LineItem[];\n  metadata?: Record<string, string>;\n};\n\nfunction shouldRebuildInvoice(\n  previousPayload: OrderPayload,\n  nextPayload: OrderPayload,\n): boolean {\n  return !isEqual(previousPayload, nextPayload);\n}\n\nconsole.log(\n  shouldRebuildInvoice(\n    {\n      orderId: \"ord_1\",\n      customerId: \"cus_1\",\n      items: [{ sku: \"starter\", quantity: 1 }],\n    },\n    {\n      orderId: \"ord_1\",\n      customerId: \"cus_1\",\n      items: [{ sku: \"starter\", quantity: 2 }],\n    },\n  ),\n);\n```\n\nThe type safety comes from your `OrderPayload` definition. `isEqual()` checks values at runtime, but it does not validate unknown input against a schema.\n\n### Compare optional nested values safely\n\nIf a field is optional, model that in TypeScript and compare the fully typed objects directly.\n\n```typescript\nimport isEqual from \"lodash.isequal\";\n\ntype CacheConfig = {\n  provider: \"memory\" | \"redis\";\n  ttlSeconds?: number;\n};\n\nconst baseline: CacheConfig = {\n  provider: \"memory\",\n};\n\nconst candidate: CacheConfig = {\n  provider: \"memory\",\n  ttlSeconds: undefined,\n};\n\nconsole.log(isEqual(baseline, candidate));\n```\n\nKeep the compared values typed at the application boundary so that missing and optional properties are visible in your editor and compiler.\n\n## Important Pitfalls\n\n- `@types/lodash.isequal` is a stub package. Install `lodash.isequal` instead.\n- Import from `lodash.isequal`, not from `@types/lodash.isequal`.\n- If `import isEqual from \"lodash.isequal\"` fails, enable `esModuleInterop` or switch to `import isEqual = require(\"lodash.isequal\")`.\n- `isEqual()` returns only `boolean`. It does not narrow union types or validate untrusted data.\n- Deep equality is not the same as schema validation. Parse and validate external input before relying on its shape.\n- If you are comparing large nested objects on hot paths, measure the cost in your application instead of assuming it is free.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.isequal==4.5.8`.\n- The published `@types/lodash.isequal` package is a stub entry, not the recommended direct dependency for new projects.\n- For modern TypeScript code, depend on `lodash.isequal` and use the declarations resolved from that runtime package.\n- If an older lockfile still includes `@types/lodash.isequal`, remove the stub package before debugging duplicate or stale type issues.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.isequal\n- https://www.npmjs.com/package/lodash.isequal\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.isequal\n"
  },
  {
    "path": "content/typescript/docs/lodash.merge/typescript/DOC.md",
    "content": "---\nname: lodash.merge\ndescription: \"TypeScript guidance for `lodash.merge`, including installation of the runtime package and `@types/lodash.merge`, CommonJS-friendly imports, and practical `merge()` workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.6.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.merge,merge,types,definitelytyped,npm\"\n---\n\n# lodash.merge TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.merge` for runtime behavior and `@types/lodash.merge` for TypeScript declarations.\n\nImport from `\"lodash.merge\"` in application code. Do not import from `\"@types/lodash.merge\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.merge\nnpm install -D typescript @types/lodash.merge@4.6.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.merge@4.6.9\n```\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport merge = require(\"lodash.merge\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport merge from \"lodash.merge\";\n```\n\nPick one import style and use it consistently.\n\n## Common Workflows\n\n### Merge layered configuration without mutating the inputs\n\n`merge()` mutates its first argument. Pass `{}` as the destination when you want a new merged object instead of changing an existing value.\n\n```typescript\nimport merge = require(\"lodash.merge\");\n\ntype AppConfig = {\n  region: string;\n  retries: {\n    maxAttempts: number;\n    backoffMs: number;\n  };\n  features: {\n    auditLogs: boolean;\n    exports: {\n      csv: boolean;\n      json: boolean;\n    };\n  };\n};\n\nconst defaults: AppConfig = {\n  region: \"us-east-1\",\n  retries: {\n    maxAttempts: 3,\n    backoffMs: 250,\n  },\n  features: {\n    auditLogs: false,\n    exports: {\n      csv: true,\n      json: false,\n    },\n  },\n};\n\nconst environmentOverrides = {\n  retries: {\n    maxAttempts: 5,\n  },\n};\n\nconst requestOverrides = {\n  features: {\n    auditLogs: true,\n  },\n};\n\nconst effectiveConfig = merge({}, defaults, environmentOverrides, requestOverrides);\n\nconsole.log(effectiveConfig.retries.maxAttempts);\nconsole.log(effectiveConfig.features.auditLogs);\nconsole.log(defaults.features.auditLogs);\n```\n\nThis is the most practical day-to-day pattern: keep your source objects typed, and merge them into a fresh object at the boundary where you assemble configuration.\n\n### Apply nested overrides in helper functions\n\nFor typed application settings, `merge()` is useful when an override only updates part of a nested object.\n\n```typescript\nimport merge = require(\"lodash.merge\");\n\ntype NotificationSettings = {\n  email: {\n    enabled: boolean;\n    fromAddress: string;\n  };\n  webhooks: {\n    enabled: boolean;\n    endpoint: string;\n  };\n};\n\ntype NotificationOverride = {\n  email?: {\n    enabled?: boolean;\n    fromAddress?: string;\n  };\n  webhooks?: {\n    enabled?: boolean;\n    endpoint?: string;\n  };\n};\n\nfunction applyOverride(\n  current: NotificationSettings,\n  override: NotificationOverride,\n): NotificationSettings {\n  return merge({}, current, override);\n}\n\nconst settings = applyOverride(\n  {\n    email: {\n      enabled: true,\n      fromAddress: \"noreply@example.com\",\n    },\n    webhooks: {\n      enabled: false,\n      endpoint: \"https://example.com/hooks/default\",\n    },\n  },\n  {\n    webhooks: {\n      enabled: true,\n      endpoint: \"https://example.com/hooks/orders\",\n    },\n  },\n);\n\nconsole.log(settings.webhooks.enabled);\nconsole.log(settings.email.fromAddress);\n```\n\nThe important integration boundary is still your own application type. `merge()` combines values at runtime, but the safety comes from the types you define for `current` and `override`.\n\n### Be careful when merging arrays\n\n`merge()` recursively merges arrays by index. It does not concatenate them.\n\n```typescript\nimport merge = require(\"lodash.merge\");\n\nconst defaults = {\n  stages: [\"draft\", \"review\", \"publish\"],\n};\n\nconst override = {\n  stages: [\"queued\"],\n};\n\nconst result = merge({}, defaults, override);\n\nconsole.log(result.stages);\n```\n\nThe result is `['queued', 'review', 'publish']`, not `['queued']` and not a concatenated array. If you want replacement or concatenation semantics, handle arrays explicitly before or after the merge.\n\n## Important Pitfalls\n\n- `@types/lodash.merge` does not provide runtime code. Keep `lodash.merge` in your production dependencies.\n- Do not import from `@types/lodash.merge`; import from `lodash.merge`.\n- `merge()` mutates the first argument. Use `merge({}, ...)` when you need an immutable-style result.\n- Later source properties with value `undefined` do not clear an existing destination value.\n- Arrays are merged by index, which is often surprising when you expected replacement.\n- `merge()` preserves the static TypeScript types you provide, but it does not validate untrusted input.\n- If your project already uses the full `lodash` package, keep imports consistent across the codebase instead of mixing full-package and single-function module styles casually.\n\n## Minimal End-to-End Example\n\n```typescript\nimport merge = require(\"lodash.merge\");\n\ntype ServerConfig = {\n  host: string;\n  port: number;\n  cors: {\n    enabled: boolean;\n    origins: string[];\n  };\n};\n\nconst defaults: ServerConfig = {\n  host: \"127.0.0.1\",\n  port: 3000,\n  cors: {\n    enabled: true,\n    origins: [\"http://localhost:3000\"],\n  },\n};\n\nconst envOverrides = {\n  port: process.env.PORT ? Number(process.env.PORT) : undefined,\n};\n\nconst userOverrides = {\n  cors: {\n    enabled: false,\n  },\n};\n\nconst config = merge({}, defaults, envOverrides, userOverrides);\n\nconsole.log(config.host);\nconsole.log(config.port);\nconsole.log(config.cors.enabled);\n```\n\nThis is the practical boundary for `@types/lodash.merge`: install the runtime package, let TypeScript resolve the declarations automatically, and call `merge()` on typed objects in your own application code.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.merge==4.6.9`.\n- The declarations are maintained in DefinitelyTyped for the standalone `lodash.merge` npm module.\n- In application code, the important module specifier is still `lodash.merge`; the `@types` package only adds compile-time information.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.merge\n- https://www.npmjs.com/package/lodash.merge\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.merge\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash.merge/index.d.ts\n- https://lodash.com/docs/#merge\n"
  },
  {
    "path": "content/typescript/docs/lodash.omit/typescript/DOC.md",
    "content": "---\nname: lodash.omit\ndescription: \"TypeScript guidance for `lodash.omit`, including installation of the standalone runtime package and `@types/lodash.omit`, CommonJS-friendly imports, and practical object-redaction workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.5.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.omit,omit,object-shaping,types,definitelytyped,npm\"\n---\n\n# lodash.omit TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.omit` for runtime behavior and `@types/lodash.omit` for TypeScript declarations.\n\nImport from `\"lodash.omit\"` in application code. Do not import from `\"@types/lodash.omit\"` directly.\n\nThere is no client initialization step, authentication flow, CLI, or package-defined environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.omit\nnpm install -D typescript @types/lodash.omit@4.5.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.omit@4.5.9\n```\n\n## Initialization And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport omit = require(\"lodash.omit\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport omit from \"lodash.omit\";\n```\n\nPick one import style and use it consistently.\n\n## Common Workflows\n\n### Remove sensitive fields before logging or returning data\n\n`omit()` is most useful at API and logging boundaries where one or two fields must be stripped from an otherwise valid object.\n\n```typescript\nimport omit = require(\"lodash.omit\");\n\ntype UserRecord = {\n  id: string;\n  email: string;\n  passwordHash: string;\n  refreshToken: string;\n  createdAt: string;\n};\n\nconst user: UserRecord = {\n  id: \"u_123\",\n  email: \"ada@example.com\",\n  passwordHash: \"hashed-value\",\n  refreshToken: \"rt_123\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst safeForLogs = omit(user, [\"passwordHash\", \"refreshToken\"]);\n\nconsole.log(safeForLogs.email);\nconsole.log(safeForLogs.createdAt);\n```\n\n### Strip generated fields before inserts or updates\n\nThis pattern is useful when your application keeps a full database record in memory but needs a smaller write payload.\n\n```typescript\nimport omit = require(\"lodash.omit\");\n\ntype InvoiceRow = {\n  id: string;\n  customerId: string;\n  amountCents: number;\n  status: \"draft\" | \"sent\";\n  createdAt: string;\n  updatedAt: string;\n};\n\nconst invoice: InvoiceRow = {\n  id: \"inv_001\",\n  customerId: \"cus_123\",\n  amountCents: 2500,\n  status: \"draft\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n  updatedAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst insertableInvoice = omit(invoice, [\"id\", \"createdAt\", \"updatedAt\"]);\n\nconsole.log(insertableInvoice.customerId);\nconsole.log(insertableInvoice.status);\n```\n\n### Wrap `omit()` in a typed redaction helper\n\nIf you remove the same fields in many places, centralize the call in a helper so the runtime behavior and the type boundary stay together.\n\n```typescript\nimport omit = require(\"lodash.omit\");\n\nfunction redactKeys<T extends object, K extends keyof T>(value: T, keys: K[]) {\n  return omit(value, keys);\n}\n\ntype ApiSecret = {\n  id: string;\n  label: string;\n  apiKey: string;\n  createdAt: string;\n};\n\nconst secret: ApiSecret = {\n  id: \"sec_123\",\n  label: \"production\",\n  apiKey: \"sk_live_123\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst safeSecret = redactKeys(secret, [\"apiKey\"]);\n\nconsole.log(safeSecret.label);\n```\n\nUse literal key arrays when possible. They are the clearest fit for `omit()` and keep the callsite easy to read.\n\n## Minimal End-to-End Example\n\nThis example uses an app-defined environment variable to add extra redacted fields before writing an audit event. The package itself does not require any environment variables.\n\n```typescript\nimport omit = require(\"lodash.omit\");\n\ntype AuditEvent = {\n  id: string;\n  actorEmail: string;\n  apiKey: string;\n  sessionToken: string;\n  action: \"create\" | \"update\" | \"delete\";\n  createdAt: string;\n};\n\nconst extraFields = (process.env.AUDIT_REDACT_FIELDS ?? \"\")\n  .split(\",\")\n  .map((field) => field.trim())\n  .filter(Boolean);\n\nconst event: AuditEvent = {\n  id: \"evt_123\",\n  actorEmail: \"ops@example.com\",\n  apiKey: \"sk_live_123\",\n  sessionToken: \"sess_123\",\n  action: \"update\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst safeEvent = omit(event, [\"apiKey\", \"sessionToken\", ...extraFields]);\n\nconsole.log(JSON.stringify(safeEvent, null, 2));\n```\n\nRun the compiled program with an extra application-specific redaction field if needed:\n\n```bash\nAUDIT_REDACT_FIELDS=actorEmail node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/lodash.omit` is a declaration package only. Install `lodash.omit` separately for runtime behavior.\n- Do not import from `@types/lodash.omit` in application code.\n- If `import omit from \"lodash.omit\"` fails, enable `esModuleInterop` or switch to `import omit = require(\"lodash.omit\")`.\n- `omit()` returns a new object; it does not mutate the original input.\n- Lodash documents `omit()` as slower than `pick()`. If you already know the fields to keep, prefer `pick()` or another allowlist-style transform.\n- If your project already uses the full `lodash` package, keep imports consistent across the codebase instead of mixing `_.omit()` and `lodash.omit` without a reason.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.omit==4.5.9`.\n- The declarations are maintained in DefinitelyTyped and are intended for the standalone `lodash.omit` npm module.\n- In application code, the important module specifier is `lodash.omit`; the `@types` package only adds compile-time information.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.omit\n- https://www.npmjs.com/package/lodash.omit\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.omit\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash.omit/index.d.ts\n- https://lodash.com/docs/4.17.21#omit\n"
  },
  {
    "path": "content/typescript/docs/lodash.pick/typescript/DOC.md",
    "content": "---\nname: lodash.pick\ndescription: \"TypeScript guidance for `lodash.pick`, including installation of the standalone runtime package and `@types/lodash.pick`, CommonJS-friendly imports, and practical object-shaping workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.4.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.pick,pick,object-shaping,types,definitelytyped,npm\"\n---\n\n# lodash.pick TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.pick` for runtime behavior and `@types/lodash.pick` for TypeScript declarations.\n\nImport from `\"lodash.pick\"` in application code. Do not import from `\"@types/lodash.pick\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.pick\nnpm install -D typescript @types/lodash.pick@4.4.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.pick@4.4.9\n```\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport pick = require(\"lodash.pick\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport pick from \"lodash.pick\";\n```\n\nPick one import style and use it consistently.\n\n## Common Workflows\n\n### Return a public subset of a wider record\n\n`pick()` is most useful at API boundaries where you want an allowlist of fields instead of manually rebuilding a new object.\n\n```typescript\nimport pick = require(\"lodash.pick\");\n\ntype UserRecord = {\n  id: string;\n  email: string;\n  passwordHash: string;\n  createdAt: string;\n  updatedAt: string;\n};\n\nconst user: UserRecord = {\n  id: \"u_123\",\n  email: \"ada@example.com\",\n  passwordHash: \"hashed-value\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n  updatedAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst publicUser = pick(user, [\"id\", \"email\", \"createdAt\"]);\n\nconsole.log(publicUser.id);\nconsole.log(publicUser.email);\n```\n\nThis keeps the code focused on the fields you want to keep instead of the fields you want to remove.\n\n### Build typed payloads for downstream helpers\n\n`pick()` works well when another layer expects a smaller object shape.\n\n```typescript\nimport pick = require(\"lodash.pick\");\n\ntype Invoice = {\n  id: string;\n  customerId: string;\n  amountCents: number;\n  status: \"draft\" | \"sent\" | \"paid\";\n  createdAt: string;\n};\n\nfunction sendInvoiceSummary(summary: Pick<Invoice, \"id\" | \"customerId\" | \"status\">): void {\n  console.log(summary);\n}\n\nconst invoice: Invoice = {\n  id: \"inv_001\",\n  customerId: \"cus_123\",\n  amountCents: 2500,\n  status: \"sent\",\n  createdAt: \"2026-03-13T00:00:00Z\",\n};\n\nconst summary = pick(invoice, [\"id\", \"customerId\", \"status\"]);\n\nsendInvoiceSummary(summary);\n```\n\nIn practice, this is the main integration boundary: `lodash.pick` shapes the runtime object while TypeScript checks that the picked result still matches the smaller contract you pass onward.\n\n### Expose only safe application config\n\nThe package does not define environment variables, but it is common to use `pick()` on application config built from `process.env`.\n\n```typescript\nimport pick = require(\"lodash.pick\");\n\ntype AppConfig = {\n  NODE_ENV: \"development\" | \"test\" | \"production\";\n  API_BASE_URL: string;\n  INTERNAL_TOKEN: string;\n};\n\nconst config: AppConfig = {\n  NODE_ENV: (process.env.NODE_ENV as AppConfig[\"NODE_ENV\"] | undefined) ?? \"development\",\n  API_BASE_URL: process.env.API_BASE_URL ?? \"http://localhost:3000\",\n  INTERNAL_TOKEN: process.env.INTERNAL_TOKEN ?? \"\",\n};\n\nconst clientConfig = pick(config, [\"NODE_ENV\", \"API_BASE_URL\"]);\n\nconsole.log(clientConfig);\n```\n\nThis keeps secret or server-only values out of payloads intended for browsers, logs, or templates.\n\n## Minimal End-to-End Example\n\nThis example reads an incoming request body, keeps only the fields your update path accepts, and forwards the smaller typed object.\n\n```typescript\nimport pick = require(\"lodash.pick\");\n\ntype ProfileRecord = {\n  id: string;\n  email: string;\n  displayName: string;\n  timezone: string;\n  role: \"member\" | \"admin\";\n};\n\ntype ProfileUpdate = Pick<ProfileRecord, \"displayName\" | \"timezone\">;\n\nfunction persistProfileUpdate(userId: string, update: ProfileUpdate): void {\n  console.log(userId, update);\n}\n\nconst requestBody: ProfileRecord = {\n  id: \"u_123\",\n  email: \"ada@example.com\",\n  displayName: \"Ada\",\n  timezone: \"UTC\",\n  role: \"admin\",\n};\n\nconst update = pick(requestBody, [\"displayName\", \"timezone\"]);\n\npersistProfileUpdate(requestBody.id, update);\n```\n\n## Important Pitfalls\n\n- `@types/lodash.pick` is a declaration package only. Keep `lodash.pick` in your runtime dependencies.\n- Do not import from `@types/lodash.pick`; import from `lodash.pick`.\n- If `import pick from \"lodash.pick\"` fails, enable `esModuleInterop` or switch to `import pick = require(\"lodash.pick\")`.\n- `pick()` shapes a value you already trust; it does not validate unknown input or coerce untyped data into a safe schema.\n- If your key list comes from a generic `string[]`, TypeScript usually has less precise information than when you pass explicit property names.\n- If your project already uses the full `lodash` package, decide whether to standardize on full-package imports or standalone per-method modules instead of mixing styles casually.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.pick==4.4.9`.\n- The declarations are maintained in DefinitelyTyped and are intended for the standalone `lodash.pick` npm module.\n- In application code, the important module specifier is still `lodash.pick`; the `@types` package only adds compile-time information.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.pick\n- https://www.npmjs.com/package/lodash.pick\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.pick\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash.pick/index.d.ts\n- https://lodash.com/docs/#pick\n- https://www.typescriptlang.org/tsconfig#esModuleInterop\n"
  },
  {
    "path": "content/typescript/docs/lodash.throttle/typescript/DOC.md",
    "content": "---\nname: lodash.throttle\ndescription: \"TypeScript guidance for `lodash.throttle`, including installation of the runtime package and `@types/lodash.throttle`, CommonJS-friendly imports, and practical throttling workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.1.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,lodash,lodash.throttle,throttle,types,definitelytyped,npm\"\n---\n\n# lodash.throttle TypeScript Guide\n\n## Golden Rule\n\nInstall `lodash.throttle` for runtime behavior and `@types/lodash.throttle` for TypeScript declarations.\n\nImport from `\"lodash.throttle\"` in application code. Do not import from `\"@types/lodash.throttle\"` directly.\n\nThere is no client initialization step, authentication flow, CLI setup, or package-specific environment variable.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install lodash.throttle\nnpm install -D typescript @types/lodash.throttle@4.1.9\n```\n\nIf your project already uses TypeScript, add just the declarations:\n\n```bash\nnpm install -D @types/lodash.throttle@4.1.9\n```\n\nIf your codebase already depends on the full `lodash` package and calls `_.throttle()`, keep using `lodash` with `@types/lodash` instead of mixing full-package and standalone-module styles casually.\n\n## Import Style And `tsconfig.json`\n\nThe published module uses CommonJS-style exports. The most direct TypeScript import form is:\n\n```typescript\nimport throttle = require(\"lodash.throttle\");\n```\n\nIf your project already enables default-import interop, this also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```typescript\nimport throttle from \"lodash.throttle\";\n```\n\nPick one import style and use it consistently.\n\nDo not use a named import such as `import { throttle } from \"lodash.throttle\"`; this package exports a single throttling function.\n\n## Common Workflows\n\n### Throttle a typed callback\n\n`throttle()` is most useful when you want a function to run at most once per time window while keeping the original parameter types.\n\n```typescript\nimport throttle = require(\"lodash.throttle\");\n\ntype MetricsEvent = {\n  route: string;\n  durationMs: number;\n};\n\nconst publishMetrics = throttle(\n  (event: MetricsEvent) => {\n    console.log(`Publishing metrics for ${event.route}: ${event.durationMs}ms`);\n  },\n  1000,\n  {\n    leading: true,\n    trailing: true,\n  },\n);\n\npublishMetrics({ route: \"/search\", durationMs: 42 });\npublishMetrics({ route: \"/search\", durationMs: 45 });\n```\n\nThe throttled function keeps the same parameter shape as the original callback and also exposes `cancel()` and `flush()`.\n\n### Flush or cancel trailing work during cleanup\n\nThe returned throttled function includes lifecycle helpers that matter in real applications.\n\n```typescript\nimport throttle = require(\"lodash.throttle\");\n\ntype Draft = {\n  id: string;\n  body: string;\n};\n\nconst saveDraft = throttle(\n  (draft: Draft) => {\n    console.log(`Saving draft ${draft.id}: ${draft.body}`);\n  },\n  1500,\n  {\n    leading: false,\n    trailing: true,\n  },\n);\n\nsaveDraft({ id: \"draft_1\", body: \"first edit\" });\nsaveDraft({ id: \"draft_1\", body: \"final edit\" });\n\nsaveDraft.flush();\nsaveDraft.cancel();\n```\n\nCall `flush()` when pending trailing work must run before shutdown or teardown. Call `cancel()` when queued work must be dropped.\n\n### Reuse one throttled function across calls\n\nCreate the throttled wrapper once, then reuse it. Re-wrapping the callback on every event defeats the throttle window.\n\n```typescript\nimport throttle = require(\"lodash.throttle\");\n\ntype SearchPayload = {\n  query: string;\n};\n\nconst sendSearchAnalytics = throttle((payload: SearchPayload) => {\n  console.log(`Sending analytics for ${payload.query}`);\n}, 500);\n\nfunction onSearchInput(query: string): void {\n  sendSearchAnalytics({ query });\n}\n\nonSearchInput(\"lod\");\nonSearchInput(\"loda\");\nonSearchInput(\"lodash\");\n```\n\n## Minimal End-to-End Example\n\nThis example uses an app-defined environment variable to control the throttle window for draft persistence. The package itself does not require any environment variables.\n\n```typescript\nimport throttle = require(\"lodash.throttle\");\n\ntype Draft = {\n  id: string;\n  body: string;\n  updatedAt: string;\n};\n\nconst draftSaveThrottleMs = Number(process.env.DRAFT_SAVE_THROTTLE_MS ?? \"1000\");\n\nasync function persistDraft(draft: Draft): Promise<void> {\n  console.log(`Persisting ${draft.id} at ${draft.updatedAt}`);\n}\n\nconst scheduleDraftSave = throttle(\n  (draft: Draft) => {\n    void persistDraft(draft);\n  },\n  draftSaveThrottleMs,\n  {\n    leading: false,\n    trailing: true,\n  },\n);\n\nscheduleDraftSave({\n  id: \"draft_1\",\n  body: \"hello\",\n  updatedAt: \"2026-03-13T00:00:00Z\",\n});\n\nscheduleDraftSave({\n  id: \"draft_1\",\n  body: \"hello world\",\n  updatedAt: \"2026-03-13T00:00:01Z\",\n});\n\nscheduleDraftSave.flush();\n```\n\nRun the compiled program with an app-specific throttle interval if you want a different window:\n\n```bash\nDRAFT_SAVE_THROTTLE_MS=1500 node dist/index.js\n```\n\n## Important Pitfalls\n\n- `@types/lodash.throttle` is a declaration package only. Install `lodash.throttle` separately for the runtime.\n- Do not import from `@types/lodash.throttle` in application code.\n- `lodash.throttle` exports a single function. Use `import throttle = require(\"lodash.throttle\")` or enable `esModuleInterop` and use a default import.\n- Recreating the throttled wrapper on every call resets the timing window and defeats throttling.\n- Use `flush()` before teardown when trailing work must run, or `cancel()` when it must not.\n- If your project already uses the full `lodash` package, keep imports consistent across the codebase instead of mixing `_.throttle()` and `lodash.throttle` without a reason.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/lodash.throttle==4.1.9`.\n- The declarations describe the Lodash 4 `throttle()` API used by the standalone `lodash.throttle` runtime package.\n- The practical options surface is the standard Lodash `leading` and `trailing` configuration, and the returned throttled function exposes `cancel()` and `flush()`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/lodash.throttle\n- https://www.npmjs.com/package/lodash.throttle\n- https://lodash.com/docs/4.17.21#throttle\n"
  },
  {
    "path": "content/typescript/docs/luxon/typescript/DOC.md",
    "content": "---\nname: luxon\ndescription: \"TypeScript declarations for Luxon date, time, duration, and interval APIs, including zone-aware parsing, formatting, and invalid-value handling.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.7.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,luxon,date,time,timezone,intl,types,definitelytyped\"\n---\n\n# Luxon TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/luxon` alongside the real `luxon` runtime package, then import runtime values from `\"luxon\"`.\n\n`@types/luxon` only provides TypeScript declarations. Your application still runs the `luxon` package at runtime. The Luxon 3.x package metadata does not advertise bundled declaration files, so `@types/luxon` is the package that provides editor and compiler support for TypeScript projects using this runtime line.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install luxon\nnpm install -D typescript @types/luxon\n```\n\nIf the same files also read Node.js globals such as `process.env`, add Node.js types too:\n\n```bash\nnpm install -D @types/node\n```\n\nNo environment variables, API keys, or client initialization are required.\n\n## Initialization\n\nImport the runtime exports you use:\n\n```typescript\nimport { DateTime, Duration, Interval, Settings } from \"luxon\";\n```\n\nLuxon relies on the platform `Intl` APIs for locale and time zone support, so there is no separate locale or tzdata package to configure for normal usage.\n\n## Common Workflows\n\n### Parse ISO timestamps and format output\n\n```typescript\nimport { DateTime } from \"luxon\";\n\nconst createdAt = DateTime.fromISO(\"2026-03-13T15:30:00Z\");\n\nif (!createdAt.isValid) {\n  throw new Error(\n    createdAt.invalidExplanation ?? createdAt.invalidReason ?? \"Invalid timestamp\"\n  );\n}\n\nconsole.log(createdAt.toISO());\nconsole.log(createdAt.toLocaleString(DateTime.DATETIME_MED));\nconsole.log(createdAt.toFormat(\"yyyy-LL-dd HH:mm\"));\n```\n\n`fromISO()`, `toISO()`, `toLocaleString()`, and `toFormat()` are the core parse-and-format methods you will use most often when a TypeScript app receives or emits timestamps.\n\n### Preserve or change zones explicitly\n\n```typescript\nimport { DateTime } from \"luxon\";\n\nconst meeting = DateTime.fromISO(\"2026-03-13T09:00:00-04:00\", {\n  setZone: true,\n});\n\nconst utcMeeting = meeting.toUTC();\nconst parisMeeting = meeting.setZone(\"Europe/Paris\");\n\nconsole.log(meeting.zoneName);\nconsole.log(utcMeeting.toISO());\nconsole.log(parisMeeting.toISO());\n```\n\nUse `setZone: true` when the incoming ISO string already contains an offset and you want Luxon to keep that zone on the resulting `DateTime`. Use `setZone()` or `toUTC()` when your app needs a normalized output zone.\n\n### Build typed helpers with `DateTime`\n\n```typescript\nimport { DateTime } from \"luxon\";\n\nexport function formatDeadline(deadline: DateTime): string {\n  if (!deadline.isValid) {\n    throw new Error(\"Deadline must be a valid Luxon DateTime\");\n  }\n\n  return deadline.toUTC().toFormat(\"yyyy-LL-dd HH:mm 'UTC'\");\n}\n\nconst deadline = DateTime.fromObject(\n  { year: 2026, month: 4, day: 1, hour: 17, minute: 0 },\n  { zone: \"America/New_York\" }\n);\n\nconsole.log(formatDeadline(deadline));\n```\n\nFor most application code, the practical type boundary is the runtime class itself: accept `DateTime` in function signatures and return strings, native `Date` objects, or application-specific types at the edge.\n\n### Convert between Luxon and native `Date`\n\n```typescript\nimport { DateTime } from \"luxon\";\n\nconst jsDate = new Date(\"2026-03-13T15:30:00Z\");\n\nconst dt = DateTime.fromJSDate(jsDate, { zone: \"utc\" });\n\nif (!dt.isValid) {\n  throw new Error(\"Could not convert Date into DateTime\");\n}\n\nconst backToDate = dt.plus({ hours: 2 }).toJSDate();\n\nconsole.log(dt.toISO(), backToDate.toISOString());\n```\n\nUse `fromJSDate()` when browser, database, or platform APIs give you a native `Date`, and `toJSDate()` when another library expects one.\n\n### Work with `Duration` and `Interval`\n\n```typescript\nimport { DateTime, Duration, Interval } from \"luxon\";\n\nconst start = DateTime.fromISO(\"2026-03-13T09:00:00\", {\n  zone: \"America/New_York\",\n});\nconst end = start.plus({ minutes: 90 });\n\nconst interval = Interval.fromDateTimes(start, end);\nconst duration = Duration.fromObject({ hours: 1, minutes: 30 });\n\nconsole.log(\n  interval.contains(\n    DateTime.fromISO(\"2026-03-13T09:30:00\", {\n      zone: \"America/New_York\",\n    })\n  )\n);\nconsole.log(interval.toDuration([\"hours\", \"minutes\"]).toObject());\nconsole.log(duration.toISO());\nconsole.log(duration.shiftTo(\"minutes\").toObject());\n```\n\nUse `Interval` for start/end windows and `Duration` for reusable amounts of time. Keep them distinct in your own types and helper names.\n\n### Fail fast on invalid values\n\n```typescript\nimport { DateTime, Settings } from \"luxon\";\n\nSettings.throwOnInvalid = true;\n\ntry {\n  const impossible = DateTime.fromObject({\n    year: 2026,\n    month: 2,\n    day: 30,\n  });\n\n  console.log(impossible.toISO());\n} finally {\n  Settings.throwOnInvalid = false;\n}\n```\n\nIf you prefer not to set a global flag, keep the default behavior and check `isValid`, `invalidReason`, and `invalidExplanation` on each `DateTime`, `Duration`, or `Interval` value.\n\n### Set application-wide defaults carefully\n\n```typescript\nimport { DateTime, Settings } from \"luxon\";\n\nSettings.defaultZone = \"UTC\";\nSettings.defaultLocale = \"en-US\";\n\nconst createdAt = DateTime.now();\nconst publishedAt = DateTime.fromISO(\"2026-03-13T15:30:00\");\n\nconsole.log(createdAt.toISO());\nconsole.log(publishedAt.toLocaleString(DateTime.DATE_FULL));\n```\n\n`Settings.defaultZone` and `Settings.defaultLocale` only affect instances created after you set them.\n\n## Minimal End-to-End Example\n\n```typescript\nimport { DateTime, Interval, Settings } from \"luxon\";\n\nSettings.defaultZone = \"UTC\";\n\nconst input = \"2026-03-13T09:00:00-04:00\";\n\nconst start = DateTime.fromISO(input, { setZone: true });\n\nif (!start.isValid) {\n  throw new Error(\n    start.invalidExplanation ?? start.invalidReason ?? \"Invalid start time\"\n  );\n}\n\nconst end = start.plus({ hours: 2 });\nconst window = Interval.fromDateTimes(start, end);\n\nconsole.log({\n  input,\n  startIso: start.toISO(),\n  startUtc: start.toUTC().toISO(),\n  endIso: end.toISO(),\n  minutes: window.toDuration(\"minutes\").as(\"minutes\"),\n});\n```\n\nThis is the typical `@types/luxon` boundary: import classes from `luxon`, let TypeScript track `DateTime` and `Interval` values through your code, and convert to strings or native `Date` objects only when another API requires them.\n\n## Common Pitfalls\n\n- Install `luxon` as well as `@types/luxon`; the `@types` package does not include runtime code.\n- Import from `\"luxon\"`, not from `\"@types/luxon\"`.\n- Check `isValid` before assuming a parsed or constructed value is usable, unless you intentionally enable `Settings.throwOnInvalid`.\n- Do not treat `plus({ days: 1 })` and `plus({ hours: 24 })` as interchangeable across DST boundaries; Luxon distinguishes calendar shifts from exact elapsed time.\n- Treat `Settings` as global process-wide state. Reset or isolate it in tests so one suite does not leak defaults into another.\n- Keep runtime and declaration versions aligned to the same Luxon major when you upgrade.\n\n## Version Notes\n\n- This guide targets `@types/luxon@3.7.1`.\n- The documented runtime API is Luxon 3.x, including named exports such as `DateTime`, `Duration`, `Interval`, and `Settings`.\n- Luxon's maintainer README links the install guide, quick tour, and API reference at `moment.github.io/luxon`.\n- The current Luxon 3.x package metadata does not advertise bundled TypeScript declaration files, so `@types/luxon` remains the declaration package to install for TypeScript support.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/luxon\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/luxon\n- https://www.npmjs.com/package/luxon\n- https://github.com/moment/luxon\n- https://moment.github.io/luxon/#/install\n- https://moment.github.io/luxon/#/tour\n- https://moment.github.io/luxon/api-docs/index.html\n"
  },
  {
    "path": "content/typescript/docs/mapbox-gl/typescript/DOC.md",
    "content": "---\nname: mapbox-gl\ndescription: \"TypeScript declarations for Mapbox GL JS maps, layers, sources, events, and typed GeoJSON integration.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.5.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mapbox,mapbox-gl,maps,geojson,browser,types,definitelytyped\"\n---\n\n# Mapbox GL JS TypeScript Guide\n\nInstall `@types/mapbox-gl` alongside the real `mapbox-gl` runtime package.\n\n`@types/mapbox-gl` provides TypeScript declarations only. Your application imports and runs `mapbox-gl`; the declaration package supplies types for `Map`, `MapboxOptions`, `Marker`, `Popup`, `LngLatLike`, GeoJSON sources, layer definitions, and map event handlers.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install mapbox-gl\nnpm install -D typescript @types/mapbox-gl\n```\n\nIf your project already depends on `mapbox-gl`, add only the missing declarations:\n\n```bash\nnpm install -D @types/mapbox-gl\n```\n\n## Credentials And Environment Variables\n\n`@types/mapbox-gl` does not read environment variables itself.\n\nIf your app uses Mapbox-hosted styles such as `mapbox://styles/...`, expose your token through your app build tool and assign it to `mapboxgl.accessToken` before creating a map.\n\nExample `.env` for a Vite app:\n\n```bash\nVITE_MAPBOX_ACCESS_TOKEN=pk.your-public-token\n```\n\nOptional `src/vite-env.d.ts` if you want the variable to be strongly typed:\n\n```typescript\ninterface ImportMetaEnv {\n  readonly VITE_MAPBOX_ACCESS_TOKEN: string;\n}\n\ninterface ImportMeta {\n  readonly env: ImportMetaEnv;\n}\n```\n\n## TypeScript Setup\n\nThe declarations are for the `mapbox-gl` module itself. Import from `\"mapbox-gl\"`, never from `\"@types/mapbox-gl\"`.\n\n### Import `mapbox-gl`\n\nWith `esModuleInterop` or a bundler-oriented TypeScript setup, use the default import form:\n\n```typescript\nimport mapboxgl from \"mapbox-gl\";\nimport \"mapbox-gl/dist/mapbox-gl.css\";\n```\n\nIf your project keeps CommonJS-style imports, use `import = require()`:\n\n```typescript\nimport mapboxgl = require(\"mapbox-gl\");\n```\n\n### Recommended `tsconfig.json`\n\nMapbox GL JS runs in the browser, so keep DOM library types enabled.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"lib\": [\"ES2022\", \"DOM\"],\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your app already has a working front-end `tsconfig.json`, the important part is that the project includes browser DOM libs and resolves the `mapbox-gl` module normally.\n\n## Create A Map\n\nThis is the smallest practical setup for a typed map instance.\n\n```typescript\nimport mapboxgl from \"mapbox-gl\";\nimport \"mapbox-gl/dist/mapbox-gl.css\";\n\nmapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;\n\nconst container = document.getElementById(\"map\");\n\nif (!container) {\n  throw new Error(\"Missing #map container\");\n}\n\nconst map = new mapboxgl.Map({\n  container,\n  style: \"mapbox://styles/mapbox/streets-v12\",\n  center: [-74.5, 40],\n  zoom: 9,\n  attributionControl: true,\n});\n\nmap.addControl(new mapboxgl.NavigationControl(), \"top-right\");\n```\n\nThis pattern gives you a typed `mapboxgl.Map` instance that exposes the overloaded `on()`, `addSource()`, `addLayer()`, `flyTo()`, `queryRenderedFeatures()`, and cleanup APIs.\n\n## Add Markers And Popups\n\n`Marker` and `Popup` are part of the runtime API and fully typed by the declaration package.\n\n```typescript\nconst popup = new mapboxgl.Popup({ offset: 24 }).setHTML(`\n  <strong>Lower Manhattan</strong><br />New York City\n`);\n\nnew mapboxgl.Marker({ color: \"#2563eb\" })\n  .setLngLat([-74.006, 40.7128])\n  .setPopup(popup)\n  .addTo(map);\n```\n\n## Add A Typed GeoJSON Source And Layer\n\nFor application data, type the GeoJSON payload at the boundary where your code constructs it.\n\n```typescript\nimport type { FeatureCollection, Point } from \"geojson\";\nimport mapboxgl from \"mapbox-gl\";\n\ntype StoreProperties = {\n  id: string;\n  name: string;\n  sales: number;\n};\n\nconst stores: FeatureCollection<Point, StoreProperties> = {\n  type: \"FeatureCollection\",\n  features: [\n    {\n      type: \"Feature\",\n      geometry: {\n        type: \"Point\",\n        coordinates: [-73.9851, 40.7589],\n      },\n      properties: {\n        id: \"store-1\",\n        name: \"Times Square\",\n        sales: 125000,\n      },\n    },\n  ],\n};\n\nmap.on(\"load\", () => {\n  map.addSource(\"stores\", {\n    type: \"geojson\",\n    data: stores,\n  });\n\n  map.addLayer({\n    id: \"stores-circle\",\n    type: \"circle\",\n    source: \"stores\",\n    paint: {\n      \"circle-radius\": 8,\n      \"circle-color\": \"#2563eb\",\n      \"circle-stroke-width\": 2,\n      \"circle-stroke-color\": \"#ffffff\",\n    },\n  });\n});\n```\n\nWhen you know a source ID refers to a GeoJSON source, assert that type before calling `setData()`:\n\n```typescript\nconst storesSource = map.getSource(\"stores\") as mapboxgl.GeoJSONSource | undefined;\n\nstoresSource?.setData(stores);\n```\n\n## Use Typed Event Handlers\n\nThe `map.on()` overloads type event callbacks from the event name and, for layer-bound handlers, the layer ID you pass.\n\n```typescript\nmap.on(\"click\", \"stores-circle\", (event) => {\n  const feature = event.features?.[0];\n\n  if (!feature || feature.geometry.type !== \"Point\") {\n    return;\n  }\n\n  const [lng, lat] = feature.geometry.coordinates;\n\n  new mapboxgl.Popup()\n    .setLngLat([lng, lat])\n    .setHTML(`<strong>${feature.properties?.name ?? \"Store\"}</strong>`)\n    .addTo(map);\n});\n\nmap.on(\"mouseenter\", \"stores-circle\", () => {\n  map.getCanvas().style.cursor = \"pointer\";\n});\n\nmap.on(\"mouseleave\", \"stores-circle\", () => {\n  map.getCanvas().style.cursor = \"\";\n});\n```\n\nFor generic coordinate inputs, use the `LngLatLike` type instead of manually accepting multiple shapes.\n\n```typescript\nfunction focusMap(target: mapboxgl.LngLatLike) {\n  map.flyTo({\n    center: target,\n    zoom: 12,\n  });\n}\n\nfocusMap([-73.9851, 40.7589]);\nfocusMap({ lng: -122.4194, lat: 37.7749 });\n```\n\n## Clean Up The Map Instance\n\nWhen a view unmounts or a page-level controller is torn down, call `remove()`.\n\n```typescript\nmap.remove();\n```\n\nThis releases event listeners, DOM bindings, and WebGL resources associated with the map instance.\n\n## Common Pitfalls\n\n- Install `mapbox-gl` as well as `@types/mapbox-gl`; the declaration package does not include runtime JavaScript.\n- Import from `\"mapbox-gl\"`, not from `\"@types/mapbox-gl\"`.\n- Keep browser DOM libs enabled in `tsconfig.json`; Mapbox GL JS uses browser types such as `HTMLElement` and canvas-related APIs.\n- Set `mapboxgl.accessToken` before using Mapbox-hosted styles; the library does not load your token from `.env` automatically.\n- Import `\"mapbox-gl/dist/mapbox-gl.css\"` or built-in controls, popups, and default marker styling will be missing.\n- Call `map.remove()` when tearing down a map view so the WebGL context and listeners are released cleanly.\n\n## Version Notes For `@types/mapbox-gl` 3.5.0\n\nThis guide targets `@types/mapbox-gl==3.5.0`.\n\nThe practical integration boundary is the `mapbox-gl` runtime module. Keep application imports, access-token setup, map construction, source and layer registration, and event handling centered on `mapbox-gl`, and use `@types/mapbox-gl` to supply TypeScript declarations for that runtime API.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/mapbox-gl\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mapbox-gl\n- https://www.npmjs.com/package/mapbox-gl\n- https://docs.mapbox.com/mapbox-gl-js/api/\n- https://docs.mapbox.com/mapbox-gl-js/example/simple-map/\n- https://docs.mapbox.com/help/glossary/access-token/\n"
  },
  {
    "path": "content/typescript/docs/marked/typescript/DOC.md",
    "content": "---\nname: marked\ndescription: \"TypeScript setup for `marked`. `@types/marked@6.0.0` is a stub package, so install `marked` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,marked,markdown,html,types,definitelytyped\"\n---\n\n# Marked TypeScript Guide\n\n## Golden Rule\n\n`@types/marked@6.0.0` is a stub package.\n\nThe npm package page for `@types/marked` says it is a stub entry for `marked`, and the published `marked` runtime package includes its own `types` entry. In practice, install `marked`, import from `\"marked\"`, and remove `@types/marked` if you added it directly.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install marked\nnpm install -D typescript\n```\n\nIf your project also needs Node.js globals or built-in module types, add `@types/node`:\n\n```bash\nnpm install -D @types/node\n```\n\nIf you previously installed the stub package directly, remove it:\n\n```bash\nnpm uninstall @types/marked\n```\n\n## Initialization\n\nThere are no package-specific environment variables, auth steps, or client objects.\n\nThe important setup is importing the runtime package directly so TypeScript reads the declarations bundled with `marked`:\n\n```ts\nimport { Marked, marked, type MarkedOptions } from \"marked\";\n```\n\nFor a Node.js TypeScript project, a practical compiler setup is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n## Common Workflows\n\n### Parse Markdown to HTML\n\nUse `marked.parse()` for the standard markdown-to-HTML flow.\n\n```ts\nimport { marked } from \"marked\";\n\nconst markdown = `# Release notes\n\n- Added typed markdown parsing\n- Kept custom rendering support`;\n\nconst html = marked.parse(markdown);\n\nconsole.log(html);\n```\n\n### Keep Parser Configuration in an Isolated Instance\n\nThe runtime package exports a `Marked` class, so you can create a configured parser instance instead of relying only on module-level helpers.\n\n```ts\nimport { Marked } from \"marked\";\n\nconst parser = new Marked({\n  gfm: true,\n  breaks: true,\n});\n\nconst html = parser.parse(\"first line\\nsecond line\");\n\nconsole.log(html);\n```\n\nThe declarations document that `breaks` only works when `gfm` is `true`.\n\n### Reuse Typed Option Objects\n\nUse `MarkedOptions` when you want shared parser settings to stay type-safe.\n\n```ts\nimport { marked, type MarkedOptions } from \"marked\";\n\nconst options: MarkedOptions = {\n  gfm: true,\n  breaks: true,\n  pedantic: false,\n  silent: false,\n};\n\nconst html = marked.parse(\"## Hello\\n\\nThis is **typed**.\", options);\n\nconsole.log(html);\n```\n\n### Customize HTML Output With a Typed Renderer\n\nPass a `renderer` object when you need to override how specific markdown constructs become HTML.\n\n```ts\nimport { marked } from \"marked\";\n\nconst html = marked.parse(\"# API Reference\", {\n  renderer: {\n    heading(text, level) {\n      const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n      return `<h${level} id=\"${slug}\">${text}</h${level}>`;\n    },\n  },\n});\n\nconsole.log(html);\n```\n\nThis is the practical TypeScript boundary for custom rendering: the runtime package exports the renderer API, and the bundled declarations type each override signature.\n\n### Inspect and Rewrite Tokens With `walkTokens`\n\n`Token` is a discriminated union. Checking `token.type` lets TypeScript narrow to the correct token shape.\n\n```ts\nimport { marked } from \"marked\";\n\nconst headings: string[] = [];\n\nconst html = marked.parse(\"# Docs\\n\\n[Guide](/docs/guide)\", {\n  walkTokens(token) {\n    if (token.type === \"heading\") {\n      headings.push(token.text);\n    }\n\n    if (token.type === \"link\" && token.href.startsWith(\"/\")) {\n      token.href = new URL(token.href, \"https://example.com\").toString();\n    }\n  },\n});\n\nconsole.log(headings);\nconsole.log(html);\n```\n\nThe `walkTokens` option receives tokens by reference, so changes such as rewriting `href` values are preserved when the parser renders the final HTML.\n\nIf you want explicit token annotations in helper functions, the runtime package also exports the `Token` union and the `Tokens` namespace.\n\n### Parse Inline Markdown Fragments\n\nUse `marked.parseInline()` when the input is a short fragment instead of a full markdown document.\n\n```ts\nimport { marked } from \"marked\";\n\nconst html = marked.parseInline(\"Use **bold** inside a sentence.\");\n\nconsole.log(html);\n```\n\n### Sanitize Untrusted Output Before Inserting It Into the DOM\n\nThe `marked` README explicitly warns that the package does not sanitize the generated HTML.\n\n```bash\nnpm install marked dompurify\n```\n\n```ts\nimport DOMPurify from \"dompurify\";\nimport { marked } from \"marked\";\n\nconst source = `<img src=\"x\" onerror=\"alert('xss')\">`;\nconst unsafeHtml = marked.parse(source);\nconst safeHtml = DOMPurify.sanitize(unsafeHtml);\n\ndocument.querySelector(\"#preview\")!.innerHTML = safeHtml;\n```\n\nIf you render user-supplied markdown in a browser, sanitize the HTML output before assigning it to `innerHTML`.\n\n### Use the CLI From the Runtime Package\n\nThe usable CLI comes from `marked`, not from `@types/marked`.\n\n```bash\nnpx marked -i README.md -o README.html --gfm\nnpx marked --help\n```\n\n## Important Pitfalls\n\n- `@types/marked` is a stub package; it does not give you a separate runtime or a package you should import from.\n- Import from `marked`, never from `@types/marked`.\n- `marked` does not sanitize output HTML. Sanitize untrusted output before inserting it into a page.\n- `breaks` only takes effect when `gfm` is enabled.\n- If you set `async: true` or add async extensions, `marked.parse()` and `marked.parseInline()` can return `Promise<string>` instead of `string`.\n- The CLI examples and programmatic APIs both come from the `marked` runtime package.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/marked` package entry at version `6.0.0`.\n- For this version, the important practical behavior is that `@types/marked` exists as a stub package that points TypeScript users to `marked`.\n- The API surface you actually program against comes from the installed `marked` runtime and its bundled declarations.\n\n## Official Sources\n\n- npm package page for `@types/marked`: https://www.npmjs.com/package/@types/marked\n- DefinitelyTyped source for `@types/marked`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/marked\n- npm package page for `marked`: https://www.npmjs.com/package/marked\n- `marked` homepage and documentation: https://marked.js.org/\n- `marked` README and package metadata: https://github.com/markedjs/marked\n"
  },
  {
    "path": "content/typescript/docs/minimatch/typescript/DOC.md",
    "content": "---\nname: minimatch\ndescription: \"TypeScript guidance for `minimatch`, including the deprecated `@types/minimatch` stub, imports, typed glob matching, and common option pitfalls.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,minimatch,glob,node,types,npm\"\n---\n\n# Minimatch TypeScript Guide\n\n## Golden Rule\n\n`@types/minimatch` `6.0.0` is a deprecated stub package. The published package description says it is a stub entry for `minimatch`, and its deprecation notice says that `minimatch` provides its own type definitions.\n\nIn practice, install and import `minimatch`. Do not import anything from `@types/minimatch`.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install minimatch\nnpm install -D typescript @types/node\n```\n\nIf your application already added `@types/minimatch` directly, remove it:\n\n```bash\nnpm uninstall @types/minimatch\n```\n\nIf a transitive dependency still pulls in `@types/minimatch`, you usually do not need to do anything. Import from `minimatch`, and let TypeScript read the declarations bundled with that runtime package.\n\n## Initialization\n\nThere are no environment variables, credentials, client objects, or service initialization steps for this package.\n\nThe important setup points are:\n\n- install `minimatch`\n- import from `minimatch`\n- use TypeScript module settings that match your Node.js runtime\n\n### Recommended `tsconfig.json`\n\n`minimatch` publishes typed ESM and CommonJS entry points. A practical Node.js setup is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n## Import Patterns\n\nUse named imports from `minimatch` in TypeScript:\n\n```ts\nimport {\n  Minimatch,\n  escape,\n  filter,\n  makeRe,\n  match,\n  minimatch,\n  type MinimatchOptions,\n} from \"minimatch\";\n```\n\nIn CommonJS, require the runtime package:\n\n```ts\nconst { minimatch, Minimatch } = require(\"minimatch\");\n```\n\n## Common Workflows\n\n### Match a path with typed options\n\n`MinimatchOptions` is exported by the runtime package, so you can type reusable option objects directly.\n\n```ts\nimport { minimatch, type MinimatchOptions } from \"minimatch\";\n\nconst options: MinimatchOptions = {\n  dot: true,\n  matchBase: true,\n};\n\nconsole.log(minimatch(\"src/index.ts\", \"*.ts\", options));\nconsole.log(minimatch(\"src/index.ts\", \"*.js\", options));\n```\n\n`matchBase` only applies when the pattern does not contain a slash. In the example above, `*.ts` matches against the basename of `src/index.ts`.\n\n### Filter or select from a list\n\nThe runtime package exports both `filter()` and `match()`.\n\n```ts\nimport { filter, match } from \"minimatch\";\n\nconst files = [\n  \"src/index.ts\",\n  \"src/index.test.ts\",\n  \"README.md\",\n  \".eslintrc.cjs\",\n];\n\nconst tsFilter = filter(\"**/*.ts\", { dot: true });\n\nconsole.log(files.filter(tsFilter));\nconsole.log(match(files, \"**/*.test.ts\", { dot: true }));\n```\n\nIf you use `match()` with `nonull: true`, a no-match result returns the original pattern string instead of an empty array.\n\n### Precompile a pattern with `Minimatch`\n\nUse the class when you want to reuse a parsed pattern, inspect whether it contains glob magic, or generate a regular expression.\n\n```ts\nimport { Minimatch } from \"minimatch\";\n\nconst mm = new Minimatch(\"src/**/*.{ts,tsx}\", {\n  dot: true,\n  magicalBraces: true,\n});\n\nconsole.log(mm.hasMagic());\nconsole.log(mm.match(\"src/components/Button.tsx\"));\n\nconst regexp = mm.makeRe();\n\nif (!regexp) {\n  throw new Error(\"Invalid glob pattern\");\n}\n\nconsole.log(regexp.test(\"src/index.ts\"));\n```\n\nThe type of `makeRe()` is `false | MMRegExp`, so handle the `false` case before using the returned value as a `RegExp`.\n\n### Escape user input before building a glob\n\nIf part of a pattern comes from user input, escape it first so special glob characters are treated literally.\n\n```ts\nimport { escape, minimatch, unescape } from \"minimatch\";\n\nconst literalSegment = \"[draft]\";\nconst pattern = `notes/${escape(literalSegment)}.md`;\n\nconsole.log(pattern);\nconsole.log(minimatch(\"notes/[draft].md\", pattern));\nconsole.log(unescape(escape(literalSegment)));\n```\n\nSlashes cannot be escaped or unescaped. In `windowsPathsNoEscape` mode, backslashes also act as path separators rather than escapes.\n\n### Use `partial` during directory walking\n\n`partial: true` is useful when you are traversing a tree and need to know whether a prefix could still become a match.\n\n```ts\nimport { minimatch } from \"minimatch\";\n\nconsole.log(minimatch(\"/a/b\", \"/a/*/c/d\", { partial: true }));\nconsole.log(minimatch(\"/a/b\", \"/**/d\", { partial: true }));\nconsole.log(minimatch(\"/x/y/z\", \"/a/**/z\", { partial: true }));\n```\n\n## Important Pitfalls\n\n### Use forward slashes in patterns\n\nThe `minimatch` README explicitly warns to use forward slashes in glob expressions, even on Windows. Backslashes in patterns are treated as escapes, not as path separators.\n\n```ts\nimport { minimatch } from \"minimatch\";\n\nminimatch(\"src\\\\index.ts\", \"src/*.ts\");\n```\n\nIf you need compatibility with patterns built by `path.join()` or `path.resolve()` on Windows, `windowsPathsNoEscape: true` changes backslashes into separators. Use it carefully: this mode makes it impossible to match literal glob metacharacters in a path.\n\n### `makeRe()` and aggressive optimization are different APIs\n\n`optimizationLevel: 2` is designed for file-walking scenarios. The README notes that `Minimatch.match()` optimizes file paths to stay aligned with that mode, but a raw regular expression from `makeRe()` may not match the unprocessed path string the same way.\n\nIf you only need a boolean path check, prefer `minimatch()` or `mm.match()` over building your own `RegExp` pipeline.\n\n### `hasMagic()` does not mean the pattern is a literal path\n\n`hasMagic()` returns `false` for fully escaped patterns such as `\\\\*` or `[*]`, because they match the literal `*` character. If you need the literal text back, use `unescape()`.\n\n## Version Note\n\nThis guide is written for the `@types/minimatch` `6.0.0` package entry on npm.\n\nFor this version, the relevant practical behavior is simple:\n\n- `@types/minimatch` is deprecated\n- it exists as a stub package\n- it depends on `minimatch`\n- `minimatch` is the package that provides the usable TypeScript declarations\n"
  },
  {
    "path": "content/typescript/docs/mkdirp/typescript/DOC.md",
    "content": "---\nname: mkdirp\ndescription: \"TypeScript setup for `mkdirp`, including imports, Node.js compiler settings, and migrating off separate `@types/mkdirp` installs in modern projects.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mkdirp,node,filesystem,directories,types,npm\"\n---\n\n# mkdirp TypeScript Guide\n\n## Golden Rule\n\nThis entry tracks `@types/mkdirp@2.0.0`, but modern TypeScript projects should install and import `mkdirp` itself.\n\nCurrent `mkdirp` npm metadata publishes declaration files from the runtime package through its `types` field and typed `exports` entry points. In practice, that means application code should import from `\"mkdirp\"`, not from `\"@types/mkdirp\"`.\n\nIf an older project still lists `@types/mkdirp`, remove it when that project is using a modern `mkdirp` runtime release.\n\n## Install\n\nFor a current Node.js project, install the runtime package plus the normal TypeScript toolchain:\n\n```bash\nnpm install mkdirp\nnpm install -D typescript @types/node\n```\n\nIf your project already added the separate type package, remove it:\n\n```bash\nnpm uninstall @types/mkdirp\n```\n\nThere are no package-specific credentials, API keys, or service initialization steps.\n\n## Initialization\n\nThe practical setup points are your Node.js compiler settings and your import style.\n\n### Recommended `tsconfig.json`\n\n`mkdirp` publishes typed import and require entry points. A practical Node.js setup is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/node` matters here because `mkdirp`'s declarations reference Node's `fs` types and `NodeJS.ErrnoException`.\n\nIf your project does not restrict `compilerOptions.types`, installing `@types/node` is usually enough.\n\n### Import `mkdirp`\n\nUse the runtime package as the TypeScript import boundary:\n\n```ts\nimport { mkdirp } from \"mkdirp\";\n```\n\nIn CommonJS code, require the runtime package:\n\n```ts\nconst { mkdirp } = require(\"mkdirp\");\n```\n\nDo not import from `@types/mkdirp` in application code.\n\n## Common Workflows\n\n### Create an application data directory before writing files\n\n`mkdirp()` returns a promise that resolves to the first directory created, or `undefined` when the path already exists.\n\n```ts\nimport { mkdirp } from \"mkdirp\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nconst appDataDir = process.env.APP_DATA_DIR ?? \"./var/app-data\";\n\nawait mkdirp(appDataDir);\n\nawait writeFile(\n  join(appDataDir, \"settings.json\"),\n  JSON.stringify({ theme: \"dark\" }, null, 2),\n  \"utf8\",\n);\n```\n\nThis is the most common TypeScript integration point: ensure a directory exists, then continue with normal Node.js file operations.\n\n### Create directories synchronously during startup\n\nUse `mkdirp.sync()` when startup code must finish directory creation before proceeding.\n\n```ts\nimport { mkdirp } from \"mkdirp\";\nimport { createWriteStream } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst logDir = process.env.LOG_DIR ?? \"./var/log\";\n\nmkdirp.sync(logDir);\n\nconst stream = createWriteStream(join(logDir, \"app.log\"), { flags: \"a\" });\nstream.write(\"server started\\n\");\nstream.end();\n```\n\n### Reuse a typed options object\n\nThe package root exports the functions you call directly. When you want a reusable options type in app code, derive it from the function signature instead of reaching into internal declaration files.\n\n```ts\nimport { mkdirp } from \"mkdirp\";\n\ntype MkdirpOptions = NonNullable<Parameters<typeof mkdirp>[1]>;\n\nconst options: MkdirpOptions = {\n  mode: 0o755,\n};\n\nawait mkdirp(\"./var/cache\", options);\n```\n\nThis keeps your code coupled to the public function surface rather than to internal file paths inside the package.\n\n### Force the native or manual implementation\n\nThe runtime package also exposes explicit `native` and `manual` variants.\n\n```ts\nimport { mkdirp } from \"mkdirp\";\n\nawait mkdirp.native(\"./var/native-cache\");\nawait mkdirp.manual(\"./var/manual-cache\");\n```\n\nUse these only when you specifically need to choose one implementation path. The default `mkdirp()` entry point is the usual choice.\n\n## Important Pitfalls\n\n- Install and import `mkdirp`; do not point application imports at `@types/mkdirp`.\n- If your project is intentionally pinned to older `mkdirp` 0.x or 1.x releases, verify that runtime line before removing older type-package setup. Current `mkdirp` 2.x and 3.x metadata publishes declarations, while older 1.x metadata does not.\n- `mkdirp()` resolves to the first directory actually created, not always to the full target path.\n- If `compilerOptions.types` is set, keep `node` in the list or Node-specific declarations used by `mkdirp` may disappear.\n- Prefer inline option objects or `Parameters<typeof mkdirp>[1]` for reusable option typing instead of importing internal declaration paths.\n\n## Version Note For `@types/mkdirp` 2.0.0\n\nFor the package version tracked here, the useful TypeScript workflow is centered on the `mkdirp` runtime package rather than on a separate declaration import path.\n\nFor modern projects, install `mkdirp`, import from `\"mkdirp\"`, and let TypeScript read the declarations published by that runtime package.\n"
  },
  {
    "path": "content/typescript/docs/mocha/typescript/DOC.md",
    "content": "---\nname: mocha\ndescription: \"TypeScript declarations for Mocha's test globals, hooks, async callbacks, and test context APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"10.0.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mocha,testing,types,definitelytyped,ambient-types\"\n---\n\n# Mocha TypeScript Guide\n\n`@types/mocha` adds TypeScript declarations for the `mocha` test runner. Install it when your TypeScript tests use Mocha globals such as `describe`, `it`, `beforeEach`, and `after`, or when you import those helpers from the `mocha` runtime package.\n\nThis package only ships type declarations. It does not include the Mocha runtime.\n\n## Install\n\nInstall the runtime package and the type package together:\n\n```bash\nnpm install --save-dev mocha @types/mocha\n```\n\nIf you run `.ts` test files directly with Mocha, also install TypeScript and a loader such as `ts-node`:\n\n```bash\nnpm install --save-dev mocha @types/mocha typescript ts-node\n```\n\nNo environment variables, authentication, or client initialization are required.\n\n## TypeScript Setup\n\nIn many projects, installing `@types/mocha` is enough.\n\nIf your project restricts ambient type packages with `compilerOptions.types`, add `mocha` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"mocha\"]\n  }\n}\n```\n\nWhen your application code and test code use different ambient globals, keep a separate test config so Mocha types only load for tests:\n\n```json\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"mocha\"]\n  },\n  \"include\": [\"test/**/*.ts\"]\n}\n```\n\nIf TypeScript reports `Cannot find name 'describe'` or `Cannot find name 'it'`, the usual fix is installing `@types/mocha` and ensuring the active `tsconfig` includes `mocha` in `compilerOptions.types` when that field is present.\n\n## Run TypeScript Tests With Mocha\n\nFor a common `ts-node` setup, add a test script that registers the TypeScript loader before Mocha loads your test files:\n\n```json\n{\n  \"scripts\": {\n    \"test\": \"mocha --require ts-node/register --extension ts \\\"test/**/*.spec.ts\\\"\"\n  }\n}\n```\n\nThis runtime setup is separate from `@types/mocha`, but it is the practical boundary most TypeScript projects need: `mocha` runs the tests, `ts-node` transpiles them, and `@types/mocha` gives the compiler the test API types.\n\n## Use Mocha Globals In Test Files\n\nOnce the declarations are loaded, Mocha's test globals are available in TypeScript test files.\n\n```ts\nimport { strict as assert } from \"node:assert\";\n\ndescribe(\"sum\", () => {\n  it(\"adds two numbers\", () => {\n    assert.equal(2 + 3, 5);\n  });\n});\n```\n\nThis is the simplest setup when your test runner provides globals and your `tsconfig` loads the `mocha` type package.\n\n## Import Test Helpers Explicitly\n\nIf you prefer module-local imports over ambient globals, import the helpers from the `mocha` runtime package.\n\n```ts\nimport { beforeEach, describe, it } from \"mocha\";\nimport { strict as assert } from \"node:assert\";\n\ndescribe(\"user service\", () => {\n  let userId = \"\";\n\n  beforeEach(() => {\n    userId = \"user_123\";\n  });\n\n  it(\"uses imported test helpers\", () => {\n    assert.equal(userId, \"user_123\");\n  });\n});\n```\n\nUse this pattern when you want the test file to declare its dependencies directly instead of relying on globally injected names.\n\n## Use `function` Callbacks For Mocha Context\n\nMocha's context APIs such as `this.timeout()`, `this.retries()`, and `this.currentTest` depend on `function` callbacks. Arrow functions do not bind Mocha's `this` value.\n\n```ts\nimport { beforeEach, it } from \"mocha\";\nimport { strict as assert } from \"node:assert\";\n\nbeforeEach(function () {\n  this.timeout(2_000);\n});\n\nit(\"can access the current test\", function () {\n  assert.equal(this.test?.title, \"can access the current test\");\n});\n```\n\nThis is one of the most important TypeScript boundaries in Mocha tests: the declarations give `this` a useful type only when the callback shape matches Mocha's API.\n\n## Use Callback-Style Async Tests With `Mocha.Done`\n\nMocha supports callback-style async tests. `@types/mocha` exposes the callback type through the `Mocha` namespace.\n\n```ts\nimport { it } from \"mocha\";\n\nit(\"waits for a callback\", function (done: Mocha.Done) {\n  setTimeout(() => {\n    done();\n  }, 10);\n});\n```\n\nIf the test is promise-based, return the promise or use `async` instead of mixing both patterns in the same test.\n\n## Extend The Test Context Safely\n\nWhen you store custom values on Mocha's test context, narrow `this` at the usage boundary.\n\n```ts\nimport { beforeEach, it } from \"mocha\";\nimport { strict as assert } from \"node:assert\";\n\ntype TestContext = Mocha.Context & {\n  requestId: string;\n};\n\nbeforeEach(function () {\n  (this as TestContext).requestId = \"req_123\";\n});\n\nit(\"reads custom context values\", function () {\n  const ctx = this as TestContext;\n  assert.equal(ctx.requestId, \"req_123\");\n});\n```\n\nThis keeps the extension local and explicit. For larger suites, put the shared context type in a test helper module.\n\n## Important Pitfalls\n\n- `@types/mocha` does not install or run Mocha; install `mocha` separately.\n- Do not import from `@types/mocha` in application code or tests. Import from `mocha`, or rely on the globals after TypeScript loads the declarations.\n- If your project uses `compilerOptions.types`, omit `mocha` there and the globals will appear to vanish.\n- Use `function () {}` rather than arrow functions whenever the test or hook uses Mocha's `this` context.\n- Avoid loading multiple global test-runner type packages into the same compilation when possible. `@types/mocha`, `@types/jest`, and similar packages all declare globals such as `describe` and `it`, so a dedicated test `tsconfig` is the safest setup.\n- Keep your test files inside the `include` patterns for the `tsconfig` that loads Mocha types, or TypeScript will not see the declarations for those files.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/mocha\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mocha\n- https://mochajs.org/\n"
  },
  {
    "path": "content/typescript/docs/mongodb/typescript/DOC.md",
    "content": "---\nname: mongodb\ndescription: \"TypeScript setup for the MongoDB Node.js driver. `@types/mongodb@4.0.7` is a stub package; install `mongodb` itself because it ships its own type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.0.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mongodb,nodejs,types,definitelytyped,database\"\n---\n\n# MongoDB TypeScript Guide\n\n## Golden Rule\n\n`@types/mongodb@4.0.7` is not the package you should install for a modern MongoDB Node.js application.\n\nThe npm package page for `@types/mongodb` marks it as a stub package and says that `mongodb` provides its own type definitions. Install the real `mongodb` driver and import both runtime APIs and TypeScript types from `mongodb`.\n\nIf an older project still has `@types/mongodb` in its lockfile, remove it unless that project is intentionally pinned to a historical driver setup that depended on DefinitelyTyped declarations.\n\n## Install\n\nInstall the MongoDB Node.js driver plus the normal TypeScript toolchain for a Node.js app:\n\n```bash\nnpm install mongodb\nnpm install -D typescript @types/node\n```\n\nIf your project already added the old stub package, remove it:\n\n```bash\nnpm uninstall @types/mongodb\n```\n\nThere are no package-specific credentials beyond your MongoDB connection string. The practical setup points are your `MONGODB_URI`, your database name, and your TypeScript compiler.\n\n## Initialization\n\nCreate the client from a connection string and keep the database name in configuration instead of hard-coding it throughout your app.\n\n```ts\nimport { MongoClient } from \"mongodb\";\n\nconst mongoUri = process.env.MONGODB_URI;\nconst databaseName = process.env.MONGODB_DB ?? \"app\";\n\nif (!mongoUri) {\n  throw new Error(\"Set MONGODB_URI before starting the app\");\n}\n\nconst client = new MongoClient(mongoUri);\n\nawait client.connect();\n\nexport const db = client.db(databaseName);\n```\n\nIf your `tsconfig.json` limits ambient types with `compilerOptions.types`, include `node` so `process.env` and other Node globals stay typed:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\n## Common Workflows\n\n### Use a typed collection\n\nPass your document interface to `db.collection<TSchema>()` so CRUD calls are checked against your application model.\n\n```ts\nimport { MongoClient, type Collection } from \"mongodb\";\n\ntype User = {\n  email: string;\n  displayName: string;\n  active: boolean;\n};\n\nconst client = new MongoClient(process.env.MONGODB_URI!);\nawait client.connect();\n\nconst db = client.db(\"app\");\nconst users: Collection<User> = db.collection<User>(\"users\");\n\nconst user = await users.findOne({ email: \"ada@example.com\" });\n\nif (user) {\n  console.log(user.displayName);\n}\n```\n\nThis is the main TypeScript boundary for the driver: the collection generic controls the document shape used by inserts, queries, and returned results.\n\n### Insert documents without requiring `_id` in input\n\nIf your model does not include `_id`, or you want MongoDB to generate it, type insert payloads with `OptionalId<T>`.\n\n```ts\nimport {\n  MongoClient,\n  type OptionalId,\n  type WithId,\n} from \"mongodb\";\n\ntype User = {\n  email: string;\n  displayName: string;\n  active: boolean;\n};\n\nconst client = new MongoClient(process.env.MONGODB_URI!);\nawait client.connect();\n\nconst users = client.db(\"app\").collection<User>(\"users\");\n\nconst newUser: OptionalId<User> = {\n  email: \"ada@example.com\",\n  displayName: \"Ada\",\n  active: true,\n};\n\nawait users.insertOne(newUser);\n\nconst stored: WithId<User> | null = await users.findOne({ email: newUser.email });\n```\n\n`OptionalId<T>` is the usual choice for create operations when `_id` is generated by the server, and `WithId<T>` reflects the shape you read back from the collection.\n\n### Model `_id` explicitly with `ObjectId`\n\nWhen your application code works with document identifiers directly, declare `_id` as `ObjectId` and import that type from `mongodb`.\n\n```ts\nimport { MongoClient, ObjectId } from \"mongodb\";\n\ntype Project = {\n  _id: ObjectId;\n  name: string;\n  ownerId: ObjectId;\n};\n\nconst client = new MongoClient(process.env.MONGODB_URI!);\nawait client.connect();\n\nconst projects = client.db(\"app\").collection<Project>(\"projects\");\n\nconst projectId = new ObjectId(\"65f1a1938f8b6c6d4b6a9f10\");\nconst project = await projects.findOne({ _id: projectId });\n```\n\nUse the driver's `ObjectId` type and constructor instead of treating `_id` as an arbitrary string unless your collection actually stores string IDs.\n\n### Reuse typed filters and update documents\n\nWhen you move query logic into helpers, type the inputs with `Filter<TSchema>` and `UpdateFilter<TSchema>` so callers pass valid field names and operator shapes.\n\n```ts\nimport {\n  MongoClient,\n  type Filter,\n  type UpdateFilter,\n} from \"mongodb\";\n\ntype User = {\n  email: string;\n  displayName: string;\n  active: boolean;\n  loginCount: number;\n};\n\nfunction buildActiveUserFilter(email: string): Filter<User> {\n  return {\n    email,\n    active: true,\n  };\n}\n\nfunction recordLogin(): UpdateFilter<User> {\n  return {\n    $inc: { loginCount: 1 },\n  };\n}\n\nconst client = new MongoClient(process.env.MONGODB_URI!);\nawait client.connect();\n\nconst users = client.db(\"app\").collection<User>(\"users\");\n\nawait users.updateOne(buildActiveUserFilter(\"ada@example.com\"), recordLogin());\n```\n\nThis keeps shared data-access helpers typed against the same collection model instead of falling back to unstructured objects.\n\n## Important Pitfalls\n\n- Do not import from `@types/mongodb`; import from `mongodb`.\n- Do not keep both `mongodb` and `@types/mongodb` installed in a modern project unless you are intentionally maintaining an older dependency tree.\n- `Collection<TSchema>` only types your application code. It does not validate documents already stored in the database.\n- If your interface includes `_id`, inserts may require `_id` unless you use `OptionalId<T>` for create payloads.\n- If your project restricts ambient types with `compilerOptions.types`, include `node` or your MongoDB setup code may lose `process.env` typings.\n\n## Minimal End-to-End Example\n\n```ts\nimport {\n  MongoClient,\n  type OptionalId,\n  type WithId,\n} from \"mongodb\";\n\ntype Todo = {\n  title: string;\n  done: boolean;\n};\n\nconst mongoUri = process.env.MONGODB_URI;\nconst databaseName = process.env.MONGODB_DB ?? \"app\";\n\nif (!mongoUri) {\n  throw new Error(\"Set MONGODB_URI before running this script\");\n}\n\nconst client = new MongoClient(mongoUri);\n\nawait client.connect();\n\nconst todos = client.db(databaseName).collection<Todo>(\"todos\");\n\nconst created: OptionalId<Todo> = {\n  title: \"write docs\",\n  done: false,\n};\n\nawait todos.insertOne(created);\n\nconst openTodos: WithId<Todo>[] = await todos.find({ done: false }).toArray();\n\nconsole.log(openTodos.map((todo) => todo.title));\n\nawait client.close();\n```\n\nThis is the practical boundary for `@types/mongodb`: install `mongodb`, connect with `MongoClient`, type collections with `collection<T>()`, and import the driver's helper types from the same package.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/mongodb@4.0.7`.\n- `@types/mongodb@4.0.7` is a stub package; the runtime package you actually use is `mongodb`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/mongodb\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mongodb\n- https://www.npmjs.com/package/mongodb\n- https://www.mongodb.com/docs/drivers/node/v4.11/fundamentals/typescript/\n- https://mongodb.github.io/node-mongodb-native/4.0/\n"
  },
  {
    "path": "content/typescript/docs/mongoose/typescript/DOC.md",
    "content": "---\nname: mongoose\ndescription: \"TypeScript setup for Mongoose. `@types/mongoose@5.11.97` is a stub package; install `mongoose` itself because it ships its own type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.11.97\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mongoose,mongodb,types,definitelytyped,schemas\"\n---\n\n# Mongoose TypeScript Guide\n\n## Golden Rule\n\n`@types/mongoose@5.11.97` is not the package you should use for new Mongoose applications.\n\nThe npm page for `@types/mongoose` marks it as a stub package and says that `mongoose` provides its own type definitions. Install the runtime `mongoose` package and import both runtime APIs and TypeScript types from `mongoose`.\n\nIf an older project still has `@types/mongoose` in its lockfile, remove it unless that project is pinned to a historical Mongoose setup that still depended on DefinitelyTyped declarations.\n\n## Install\n\nInstall Mongoose itself plus the normal TypeScript toolchain for a Node.js app:\n\n```bash\nnpm install mongoose\nnpm install -D typescript @types/node\n```\n\nIf your project already added the old stub package, remove it:\n\n```bash\nnpm uninstall @types/mongoose\n```\n\nThere are no package-specific credentials or auth steps. The practical setup is your MongoDB connection string and your TypeScript compiler.\n\n## Initialization\n\nUse your application's MongoDB connection string, commonly provided through `MONGODB_URI`, and connect with `mongoose.connect()`.\n\n```ts\nimport { connect } from \"mongoose\";\n\nconst mongoUri = process.env.MONGODB_URI;\n\nif (!mongoUri) {\n  throw new Error(\"Set MONGODB_URI before starting the app\");\n}\n\nawait connect(mongoUri, {\n  dbName: \"app\",\n});\n```\n\nIf your `tsconfig.json` uses `compilerOptions.types`, include `node` so `process.env` is typed:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Define a schema and infer the document type\n\nFor straightforward schemas, define the schema inline and let Mongoose infer the TypeScript shape from it.\n\n```ts\nimport {\n  InferSchemaType,\n  Schema,\n  model,\n  type HydratedDocument,\n} from \"mongoose\";\n\nconst userSchema = new Schema(\n  {\n    email: { type: String, required: true },\n    displayName: { type: String, required: true },\n    tags: { type: [String], default: [] },\n  },\n  {\n    timestamps: true,\n  },\n);\n\ntype User = InferSchemaType<typeof userSchema>;\ntype UserDocument = HydratedDocument<User>;\n\nconst UserModel = model(\"User\", userSchema);\n\nconst created: UserDocument = await UserModel.create({\n  email: \"ada@example.com\",\n  displayName: \"Ada\",\n  tags: [\"admin\"],\n});\n\nconst loaded = await UserModel.findOne({ email: \"ada@example.com\" });\n```\n\n`InferSchemaType<typeof userSchema>` gives you the plain document shape, and `HydratedDocument<T>` represents the document instance you get back from Mongoose model operations.\n\n### Use an explicit interface when inference is not enough\n\nMongoose's TypeScript guide recommends automatic inference for the common case, but an explicit interface is safer when your schema definition is built separately, changed after construction, or otherwise stops matching what Mongoose can infer cleanly.\n\n```ts\nimport { Schema, model } from \"mongoose\";\n\ninterface InventoryItem {\n  sku: string;\n  quantity: number;\n  archived?: boolean;\n}\n\nconst inventorySchema = new Schema<InventoryItem>({\n  sku: { type: String, required: true },\n  quantity: { type: Number, required: true },\n  archived: { type: Boolean, default: false },\n});\n\nconst InventoryModel = model<InventoryItem>(\"InventoryItem\", inventorySchema);\n\nawait InventoryModel.updateOne(\n  { sku: \"A-100\" },\n  { $inc: { quantity: 1 } },\n  { upsert: true },\n);\n```\n\nKeep the interface aligned with the real schema. Mongoose does not automatically verify that your interface exactly matches every later schema change.\n\n### Type `ObjectId` correctly\n\nUse `Types.ObjectId` in your TypeScript document interface, and `Schema.Types.ObjectId` in the schema definition.\n\n```ts\nimport { Schema, Types, model } from \"mongoose\";\n\ninterface Post {\n  title: string;\n  author: Types.ObjectId;\n}\n\nconst postSchema = new Schema<Post>({\n  title: { type: String, required: true },\n  author: {\n    type: Schema.Types.ObjectId,\n    ref: \"User\",\n    required: true,\n  },\n});\n\nconst PostModel = model<Post>(\"Post\", postSchema);\n\nawait PostModel.create({\n  title: \"Hello\",\n  author: new Types.ObjectId(),\n});\n```\n\nThis split is important because `Types.ObjectId` is the TypeScript type for values in your documents, while `Schema.Types.ObjectId` is the schema-path constructor Mongoose expects in the schema definition.\n\n## Pitfalls\n\n- Do not import from `@types/mongoose`; import from `mongoose`.\n- Do not keep both `mongoose` and `@types/mongoose` installed in a modern project unless you are intentionally maintaining an old setup.\n- Prefer inline schema definitions when you want the cleanest automatic inference.\n- When you use a manual interface, keep it synchronized with the schema because Mongoose cannot guarantee they stay consistent.\n- Use `Types.ObjectId` for TypeScript fields and `Schema.Types.ObjectId` for schema paths.\n\n## Minimal End-to-End Example\n\n```ts\nimport {\n  Schema,\n  connect,\n  disconnect,\n  model,\n  type InferSchemaType,\n} from \"mongoose\";\n\nconst mongoUri = process.env.MONGODB_URI;\n\nif (!mongoUri) {\n  throw new Error(\"Set MONGODB_URI before running this script\");\n}\n\nawait connect(mongoUri, { dbName: \"app\" });\n\nconst todoSchema = new Schema({\n  title: { type: String, required: true },\n  done: { type: Boolean, default: false },\n});\n\ntype Todo = InferSchemaType<typeof todoSchema>;\n\nconst TodoModel = model<Todo>(\"Todo\", todoSchema);\n\nconst created = await TodoModel.create({ title: \"write docs\" });\nconst todos = await TodoModel.find({ done: false }).lean();\n\nconsole.log(created.title);\nconsole.log(todos.map((todo) => todo.title));\n\nawait disconnect();\n```\n\nThis is the practical boundary for `@types/mongoose`: install `mongoose`, connect with `connect()`, define schemas with `Schema`, and import the TypeScript helpers you need from the same package.\n"
  },
  {
    "path": "content/typescript/docs/morgan/typescript/DOC.md",
    "content": "---\nname: morgan\ndescription: \"TypeScript declarations for Morgan HTTP request logging middleware, built-in formats, custom tokens, custom formatters, and logging options.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.9.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,morgan,express,node,http,middleware,logging,types,definitelytyped\"\n---\n\n# Morgan TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/morgan` alongside the real `morgan` runtime package.\n\n`@types/morgan` only provides TypeScript declarations. Your application imports and runs `morgan`; the declaration package adds types for the middleware factory, built-in format names, custom tokens, custom format functions, and options such as `skip`, `stream`, and `immediate`.\n\n## Install\n\nFor a typical Express app, install the runtime packages first and then add the TypeScript declarations:\n\n```bash\nnpm install express morgan\nnpm install -D typescript @types/express @types/morgan @types/node\n```\n\nIf your project already has `morgan` and TypeScript set up, add only the missing declaration package:\n\n```bash\nnpm install -D @types/morgan\n```\n\nImport code from `morgan`, not from `@types/morgan`.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup points are your import style, your TypeScript compiler options, and your middleware order.\n\n### Import `morgan`\n\nThe declaration package uses `export =`, so the safest import form is:\n\n```typescript\nimport morgan = require(\"morgan\");\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, you can use the default import form:\n\n```typescript\nimport morgan from \"morgan\";\n```\n\nIf you are using Express in the same file, import it normally from `express`:\n\n```typescript\nimport express from \"express\";\nimport morgan from \"morgan\";\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project already restricts loaded type packages with `compilerOptions.types`, keep `node` available to the same project that compiles your server code.\n\n### Register request logging middleware\n\n`morgan` is standard Express middleware. Choose a built-in format name or pass your own format function.\n\n```typescript\nimport express from \"express\";\nimport morgan from \"morgan\";\n\nconst app = express();\n\napp.use(\n  morgan(process.env.NODE_ENV === \"production\" ? \"combined\" : \"dev\"),\n);\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n```\n\nThe built-in format names documented by `morgan` are `combined`, `common`, `dev`, `short`, and `tiny`.\n\n## Common Workflows\n\n### Skip noisy requests and write to a custom stream\n\nUse `skip` to suppress logs for routes you do not care about, and `stream` when you want to forward access logs somewhere other than the default output.\n\n```typescript\nimport express from \"express\";\nimport morgan from \"morgan\";\n\nconst app = express();\n\nconst accessLogStream = {\n  write(message: string) {\n    process.stdout.write(message);\n  },\n};\n\napp.use(\n  morgan(\"combined\", {\n    skip: (req) => req.url === \"/health\",\n    stream: accessLogStream,\n  }),\n);\n\napp.get(\"/health\", (_req, res) => {\n  res.status(200).send(\"ok\");\n});\n```\n\nThis is the simplest typed pattern when you want one-line access logs but do not want probes or load-balancer checks to flood the output.\n\n### Add a custom token\n\nCustom tokens let you pull values from the request or response into a format string.\n\n```typescript\nimport express from \"express\";\nimport morgan from \"morgan\";\n\nconst app = express();\n\nmorgan.token(\"request-id\", (req) => {\n  const value = req.headers[\"x-request-id\"];\n\n  if (Array.isArray(value)) {\n    return value[0] ?? \"-\";\n  }\n\n  return value ?? \"-\";\n});\n\napp.use(morgan(\":request-id :method :url :status :response-time ms\"));\n\napp.get(\"/users/:userId\", (req, res) => {\n  res.json({ userId: req.params.userId });\n});\n```\n\nThis keeps the integration boundary simple: your token reads the same Node/Express request object that the rest of your middleware stack sees.\n\n### Use a custom format function\n\nWhen a format string is not enough, pass a formatter callback. The token indexer exposes the same token helpers used by the built-in string formats.\n\n```typescript\nimport express from \"express\";\nimport morgan from \"morgan\";\n\nconst app = express();\n\napp.use(\n  morgan((tokens, req, res) => {\n    const method = tokens.method(req, res) ?? \"-\";\n    const url = tokens.url(req, res) ?? \"-\";\n    const status = tokens.status(req, res) ?? \"-\";\n    const responseTime = tokens[\"response-time\"](req, res) ?? \"-\";\n\n    return JSON.stringify({\n      method,\n      url,\n      status,\n      responseTimeMs: responseTime,\n    });\n  }),\n);\n```\n\nThis pattern is useful when you want structured output but still want to reuse Morgan's request and response token helpers.\n\n## Important Pitfalls\n\n- `@types/morgan` does not include runtime code. Install `morgan` itself.\n- Import from `morgan`, not from `@types/morgan`.\n- Without TypeScript interop settings, prefer `import morgan = require(\"morgan\")` over a default import.\n- Middleware order matters. Register any middleware that attaches request-specific data before `morgan` if your custom tokens depend on it.\n- `skip` returns `true` to suppress a log line, not to force one.\n- `morgan` logs every matched request unless you filter it, so health checks and readiness probes often need an explicit `skip` rule.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/morgan==1.9.10`.\n- The published declaration package models the classic `morgan` middleware API: `morgan(format, options)`, `morgan.token(...)`, `morgan.format(...)`, and `morgan.compile(...)`.\n- The declaration entrypoint uses `export =`, so your preferred import form depends on your TypeScript interop settings.\n\n## Official Sources\n\n- npm package page for `@types/morgan`: https://www.npmjs.com/package/@types/morgan\n- DefinitelyTyped source for `@types/morgan`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/morgan\n- `@types/morgan` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/morgan/index.d.ts\n- Morgan runtime documentation: https://expressjs.com/en/resources/middleware/morgan.html\n- Morgan runtime package page: https://www.npmjs.com/package/morgan\n"
  },
  {
    "path": "content/typescript/docs/ms/typescript/DOC.md",
    "content": "---\nname: ms\ndescription: \"TypeScript declarations for the ms runtime package, including typed duration strings, parsing, and formatting\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,ms,duration,time,npm,types\"\n---\n\n# ms TypeScript Guide\n\n`@types/ms` provides the TypeScript declarations for the `ms` runtime package. Use it when your project imports `ms` to parse human-readable duration strings such as `\"5m\"` or `\"2 days\"`, or to format millisecond values back into short or long strings.\n\nThis package only ships `.d.ts` files. It does not install the `ms` runtime.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install ms\nnpm install --save-dev @types/ms\n```\n\n`@types/ms@2.1.0` declares `typeScriptVersion: \"5.0\"`, so use TypeScript 5.0 or newer.\n\nNo environment variables, authentication, or client initialization are required.\n\n## Import `ms` In TypeScript\n\nThe declaration file ends with `export = ms`, so the configuration-independent import style is:\n\n```ts\nimport ms = require(\"ms\");\n```\n\nThe package also declares the namespace types `ms.StringValue`, `ms.Unit`, and `ms.UnitAnyCase`, which are useful when you want config objects to accept only valid duration strings.\n\n## Parse Duration Strings\n\n`ms()` returns a `number` when you pass a typed duration string.\n\n```ts\nimport ms = require(\"ms\");\n\nconst retryDelay: ms.StringValue = \"5s\";\nconst lockTtl: ms.StringValue = \"2 days\";\nconst rawMilliseconds: ms.StringValue = \"100\";\n\nconst retryDelayMs = ms(retryDelay);\nconst lockTtlMs = ms(lockTtl);\nconst rawValueMs = ms(rawMilliseconds);\n\nconsole.log({ retryDelayMs, lockTtlMs, rawValueMs });\n```\n\n`ms.StringValue` accepts:\n\n- Bare numeric strings such as `\"100\"`\n- Numeric strings followed by a unit such as `\"15m\"`\n- Numeric strings followed by a space and a unit such as `\"2 days\"`\n\nThe declared units cover years, weeks, days, hours, minutes, seconds, and milliseconds in multiple spellings and letter case combinations.\n\n## Format Milliseconds Back To Strings\n\n`ms()` returns a `string` when you pass a `number`.\n\n```ts\nimport ms = require(\"ms\");\n\nconst short = ms(7_200_000);\nconst long = ms(7_200_000, { long: true });\nconst negative = ms(-180_000, { long: true });\n\nconsole.log(short);\nconsole.log(long);\nconsole.log(negative);\n```\n\nUse the optional `{ long: true }` flag only with the numeric overload. It switches formatted output from compact values such as `\"2h\"` to written-out values such as `\"2 hours\"`.\n\n## Use `ms.StringValue` In Application Config\n\nIf your own config is static or checked at compile time, prefer `ms.StringValue` instead of plain `string`.\n\n```ts\nimport ms = require(\"ms\");\n\ntype CacheConfig = {\n  ttl: ms.StringValue;\n  revalidateAfter: ms.StringValue;\n};\n\nconst cacheConfig = {\n  ttl: \"15m\",\n  revalidateAfter: \"1h\",\n} satisfies CacheConfig;\n\nexport const cacheTtlMs = ms(cacheConfig.ttl);\nexport const revalidateAfterMs = ms(cacheConfig.revalidateAfter);\n```\n\nThis catches misspelled units during type checking instead of waiting for runtime input to fail.\n\n## Handle Environment Variables And Other Untyped Strings\n\nThe main integration boundary is `string` input that comes from `process.env`, CLI flags, JSON, or user input. Those values are not automatically `ms.StringValue`, even if they happen to be valid at runtime.\n\nIf you accept untyped input, validate it before narrowing it to `ms.StringValue`.\n\n```ts\nimport ms = require(\"ms\");\n\nconst durationPattern = /^-?(?:\\d+)?\\.?\\d+(?: ?(?:milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y))?$/i;\n\nfunction isDurationString(value: string): value is ms.StringValue {\n  return value.length <= 100 && durationPattern.test(value);\n}\n\nexport function readDuration(\n  value: string | undefined,\n  fallback: ms.StringValue,\n): number {\n  const candidate = value ?? fallback;\n\n  if (!isDurationString(candidate)) {\n    throw new Error(`Invalid duration: ${candidate}`);\n  }\n\n  return ms(candidate);\n}\n\nconst ttlMs = readDuration(process.env.CACHE_TTL, \"10m\");\n```\n\nThis keeps the type system honest while still working with the runtime package's string parser.\n\n## Version Notes\n\n- This guide targets `@types/ms==2.1.0`.\n- The declaration package includes `ms.Unit`, `ms.UnitAnyCase`, and `ms.StringValue`, with comments noting that those types are backported from `ms@3`.\n- The runtime API described here is still the single `ms(value, options?)` function with parse and format overloads.\n\n## Common Pitfalls\n\n- `@types/ms` is declarations only. Install `ms` separately for runtime code.\n- Import from `\"ms\"`, not from `\"@types/ms\"`.\n- Because the declarations use `export = ms`, `import ms = require(\"ms\")` is the safest import style across TypeScript configurations.\n- `ms.StringValue` is narrower than `string`. Treat env vars and user input as untrusted strings until you validate them.\n- The return type changes with the input type: strings parse to `number`, while numbers format to `string`.\n- The numeric overload only accepts `{ long: boolean }`; the string overload does not take formatting options.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/ms\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ms\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ms/index.d.ts\n- https://github.com/vercel/ms\n- https://github.com/vercel/ms/blob/main/readme.md\n"
  },
  {
    "path": "content/typescript/docs/multer/typescript/DOC.md",
    "content": "---\nname: multer\ndescription: \"TypeScript declarations for Multer's Express multipart middleware, including request augmentation, storage options, and typed upload handlers.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,multer,express,file-upload,multipart,types,definitelytyped\"\n---\n\n# Multer TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/multer` alongside the real `multer` runtime package. The type package only provides declarations for TypeScript; your application still imports and runs `multer`.\n\nThese declarations matter most in three places:\n\n- creating a typed `multer()` instance with `storage`, `limits`, and `fileFilter`\n- reading `req.file` or `req.files` in Express handlers\n- referring to uploaded files with `Express.Multer.File`\n\n## Install\n\nInstall the runtime package as a production dependency and the declarations in the same project as TypeScript and Express.\n\n```bash\nnpm install express multer\nnpm install -D typescript @types/express @types/multer @types/node\n```\n\nIf your project already has `multer`, add only the missing declaration package:\n\n```bash\nnpm install -D @types/multer\n```\n\nKeep the declarations in the same environment as the TypeScript compiler or language server that checks your Express app.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe main setup points are your import style and your TypeScript compiler options.\n\n### Import `multer`\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, use a default import:\n\n```typescript\nimport multer from \"multer\";\n```\n\nWithout interop, use the CommonJS import form:\n\n```typescript\nimport multer = require(\"multer\");\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict ambient type packages with `compilerOptions.types`, include `multer` so the Express request augmentation stays visible:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"express\", \"multer\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Single-file upload with `req.file`\n\n`upload.single(\"field\")` adds one optional file to `req.file`.\n\n```typescript\nimport express from \"express\";\nimport multer from \"multer\";\n\nconst app = express();\nconst upload = multer({ dest: \"uploads/\" });\n\napp.post(\"/avatar\", upload.single(\"avatar\"), (req, res) => {\n  if (!req.file) {\n    res.status(400).json({ error: \"avatar is required\" });\n    return;\n  }\n\n  res.json({\n    field: req.file.fieldname,\n    originalName: req.file.originalname,\n    mimeType: req.file.mimetype,\n    size: req.file.size,\n    storedPath: req.file.path,\n  });\n});\n```\n\nUse `Express.Multer.File` when you want a standalone file type:\n\n```typescript\nfunction summarizeUpload(file: Express.Multer.File) {\n  return {\n    name: file.originalname,\n    size: file.size,\n    mimeType: file.mimetype,\n  };\n}\n```\n\n### Multiple files from one field with `req.files`\n\n`upload.array(\"photos\", maxCount)` produces an array on `req.files`.\n\n```typescript\nimport express from \"express\";\nimport multer from \"multer\";\n\nconst app = express();\nconst upload = multer({ dest: \"uploads/\" });\n\napp.post(\"/photos\", upload.array(\"photos\", 8), (req, res) => {\n  const files = Array.isArray(req.files) ? req.files : [];\n\n  if (files.length === 0) {\n    res.status(400).json({ error: \"at least one photo is required\" });\n    return;\n  }\n\n  res.json({\n    count: files.length,\n    first: files[0].originalname,\n  });\n});\n```\n\n### Multiple named fields with typed field access\n\n`upload.fields()` changes `req.files` to an object keyed by field name. Guard the union before reading named properties.\n\n```typescript\nimport express from \"express\";\nimport multer from \"multer\";\n\nconst app = express();\nconst upload = multer({ dest: \"uploads/\" });\n\nconst profileUpload = upload.fields([\n  { name: \"avatar\", maxCount: 1 },\n  { name: \"gallery\", maxCount: 8 },\n]);\n\napp.post(\"/profile\", profileUpload, (req, res) => {\n  const files = req.files;\n\n  if (!files || Array.isArray(files)) {\n    res.status(400).json({ error: \"expected named upload fields\" });\n    return;\n  }\n\n  const avatar = files.avatar?.[0];\n  const gallery = files.gallery ?? [];\n\n  res.json({\n    avatar: avatar?.originalname ?? null,\n    galleryCount: gallery.length,\n  });\n});\n```\n\n### Typed storage, limits, and `fileFilter`\n\nUse `multer.diskStorage()` or `multer.memoryStorage()` from the runtime package, and type custom options from the declaration package.\n\n```typescript\nimport express from \"express\";\nimport multer from \"multer\";\n\nconst app = express();\n\nconst storage = multer.diskStorage({\n  destination(_req, _file, cb) {\n    cb(null, \"uploads/avatars\");\n  },\n  filename(_req, file, cb) {\n    const safeName = file.originalname.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n    cb(null, `${Date.now()}-${safeName}`);\n  },\n});\n\nconst imageOnly: multer.Options[\"fileFilter\"] = (_req, file, cb) => {\n  if (!file.mimetype.startsWith(\"image/\")) {\n    cb(new Error(\"Only image uploads are allowed\"));\n    return;\n  }\n\n  cb(null, true);\n};\n\nconst uploadAvatar = multer({\n  storage,\n  fileFilter: imageOnly,\n  limits: {\n    fileSize: 5 * 1024 * 1024,\n    files: 1,\n  },\n});\n\napp.post(\"/avatars\", uploadAvatar.single(\"avatar\"), (req, res) => {\n  res.status(204).end();\n});\n```\n\n### Memory storage when another SDK needs a `Buffer`\n\nFor integrations that upload the received file somewhere else, `memoryStorage()` keeps the file in memory so your handler can read `buffer`.\n\n```typescript\nimport express from \"express\";\nimport multer from \"multer\";\n\nconst app = express();\n\nconst upload = multer({\n  storage: multer.memoryStorage(),\n  limits: { fileSize: 10 * 1024 * 1024 },\n});\n\napp.post(\"/attachments\", upload.single(\"attachment\"), async (req, res) => {\n  if (!req.file) {\n    res.status(400).json({ error: \"attachment is required\" });\n    return;\n  }\n\n  const bytes = req.file.buffer.length;\n  res.json({ receivedBytes: bytes, mimeType: req.file.mimetype });\n});\n```\n\n### Narrow `req.file` after middleware\n\nThe Express request augmentation keeps `file` optional, so reusable helpers often need a narrow type.\n\n```typescript\nimport type { Request } from \"express\";\n\ntype RequestWithFile = Request & {\n  file: Express.Multer.File;\n};\n\nfunction requireFile(req: Request): asserts req is RequestWithFile {\n  if (!req.file) {\n    throw new Error(\"Expected a file upload\");\n  }\n}\n```\n\nThis pattern is useful when you want a helper function to work with `req.file.buffer`, `req.file.path`, or other file properties without repeating null checks everywhere.\n\n## Important Pitfalls\n\n- `@types/multer` is a declaration package only. Import `multer`, not `@types/multer`.\n- Multer handles `multipart/form-data`; `express.json()` and `express.urlencoded()` do not parse file uploads.\n- `req.file` and `req.files` are optional in the types because the middleware can reject a file, skip a field, or not run on a route.\n- The shape of uploaded data depends on the middleware you choose: `single()` uses `req.file`, `array()` uses `req.files` as an array, and `fields()` uses `req.files` as a field-name map.\n- `memoryStorage()` and `diskStorage()` expose different runtime properties in practice. Use `buffer` for in-memory uploads and `path`/`filename` for disk-backed uploads.\n- If you set `compilerOptions.types`, make sure `multer` is still included or the Express request augmentation may appear to disappear.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/multer==2.1.0`.\n- The package supplies TypeScript declarations for the `multer` runtime package; keep your declaration package aligned with the runtime API surface you use in the same project.\n- The import style depends on your TypeScript compiler settings because the declarations are consumed as a CommonJS-style module.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/multer\n- DefinitelyTyped source for `@types/multer`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/multer\n- `@types/multer` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/multer/index.d.ts\n- Multer runtime documentation: https://github.com/expressjs/multer#readme\n"
  },
  {
    "path": "content/typescript/docs/mysql/typescript/DOC.md",
    "content": "---\nname: mysql\ndescription: \"TypeScript declarations for the callback-based mysql client, including connections, pools, transactions, query configuration, and result packet types.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.15.27\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,mysql,nodejs,sql,types,definitelytyped\"\n---\n\n# MySQL TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/mysql` for compile-time declarations only.\n\nYour application still runs the real `mysql` package at runtime. `@types/mysql` adds TypeScript definitions for `createConnection()`, `createPool()`, `query()`, transaction methods such as `beginTransaction()` and `commit()`, connection and pool config, `MysqlError`, `OkPacket`, and `FieldInfo`.\n\nImport code from `mysql`, not from `@types/mysql`.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration packages:\n\n```bash\nnpm install mysql\nnpm install -D typescript @types/mysql @types/node\n```\n\nIf your project already uses `mysql`, add only the missing declarations:\n\n```bash\nnpm install -D @types/mysql\n```\n\n`@types/mysql@2.15.27` depends on `@types/node` and declares `typeScriptVersion: \"5.0\"`, so use TypeScript 5.0 or newer with this version.\n\n## Initialization\n\nThere are no package-defined environment variables or credentials.\n\nIn practice, most apps load connection settings from their own environment variables and pass them into `mysql.createConnection()` or `mysql.createPool()`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient types with `compilerOptions.types`, keep `node` available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n### Define connection settings in the environment\n\nThese variable names are application-defined, but they map directly to `ConnectionConfig` fields such as `host`, `port`, `user`, `password`, and `database`.\n\n```bash\nexport MYSQL_HOST=127.0.0.1\nexport MYSQL_PORT=3306\nexport MYSQL_USER=app_user\nexport MYSQL_PASSWORD=secret\nexport MYSQL_DATABASE=app_db\n```\n\n### Import `mysql` and create a pool\n\nUse a namespace import so the runtime module and exported types stay aligned.\n\n```typescript\nimport * as mysql from \"mysql\";\n\nconst database = process.env.MYSQL_DATABASE;\nconst user = process.env.MYSQL_USER;\n\nif (!database || !user) {\n  throw new Error(\"MYSQL_DATABASE and MYSQL_USER are required\");\n}\n\nexport const pool = mysql.createPool({\n  host: process.env.MYSQL_HOST ?? \"127.0.0.1\",\n  port: Number(process.env.MYSQL_PORT ?? \"3306\"),\n  user,\n  password: process.env.MYSQL_PASSWORD,\n  database,\n  waitForConnections: true,\n  connectionLimit: 10,\n  queueLimit: 0,\n  supportBigNumbers: true,\n  bigNumberStrings: true,\n  dateStrings: [\"DATE\", \"DATETIME\", \"TIMESTAMP\"],\n});\n```\n\n`createConnection()` accepts the same config shape and also accepts a connection URI string.\n\n## Common Workflows\n\n### Run a parameterized `SELECT`\n\n`query()` is callback-based in these declarations. The `results` value is typed as `any`, so define your row shape at the application boundary and cast or validate there.\n\n```typescript\nimport * as mysql from \"mysql\";\n\ntype UserRow = {\n  id: number;\n  email: string;\n  created_at: string;\n};\n\nconst connection = mysql.createConnection({\n  host: process.env.MYSQL_HOST ?? \"127.0.0.1\",\n  port: Number(process.env.MYSQL_PORT ?? \"3306\"),\n  user: process.env.MYSQL_USER,\n  password: process.env.MYSQL_PASSWORD,\n  database: process.env.MYSQL_DATABASE,\n});\n\nconnection.connect((err) => {\n  if (err) {\n    throw err;\n  }\n\n  connection.query(\n    \"SELECT id, email, created_at FROM users WHERE id = ?\",\n    [42],\n    (queryError, results, fields) => {\n      if (queryError) {\n        throw queryError;\n      }\n\n      const rows = results as UserRow[];\n\n      console.log(rows[0]?.email);\n      console.log(fields?.map((field) => field.name));\n\n      connection.end();\n    },\n  );\n});\n```\n\nThe callback's `fields` argument is typed as `mysql.FieldInfo[]` when it is present.\n\n### Handle `INSERT`, `UPDATE`, and `DELETE` results with `OkPacket`\n\nFor write queries, cast the result to `mysql.OkPacket` so you can read `affectedRows`, `insertId`, and `changedRows` explicitly.\n\n```typescript\nimport * as mysql from \"mysql\";\n\nconst connection = mysql.createConnection({\n  host: process.env.MYSQL_HOST ?? \"127.0.0.1\",\n  user: process.env.MYSQL_USER,\n  password: process.env.MYSQL_PASSWORD,\n  database: process.env.MYSQL_DATABASE,\n});\n\nconnection.query(\n  \"INSERT INTO users (email) VALUES (?)\",\n  [\"ada@example.com\"],\n  (err, results) => {\n    if (err) {\n      throw err;\n    }\n\n    const packet = results as mysql.OkPacket;\n\n    console.log(packet.insertId);\n    console.log(packet.affectedRows);\n\n    connection.end();\n  },\n);\n```\n\n### Use transactions with `beginTransaction()`, `commit()`, and `rollback()`\n\nThe transaction API is also callback-based. Roll back before releasing or ending the connection when a step fails.\n\n```typescript\nimport * as mysql from \"mysql\";\n\nconst connection = mysql.createConnection({\n  host: process.env.MYSQL_HOST ?? \"127.0.0.1\",\n  user: process.env.MYSQL_USER,\n  password: process.env.MYSQL_PASSWORD,\n  database: process.env.MYSQL_DATABASE,\n});\n\nconnection.beginTransaction((transactionError) => {\n  if (transactionError) {\n    throw transactionError;\n  }\n\n  connection.query(\n    \"UPDATE accounts SET balance = balance - ? WHERE id = ?\",\n    [50, 1],\n    (debitError) => {\n      if (debitError) {\n        connection.rollback(() => connection.end());\n        return;\n      }\n\n      connection.query(\n        \"UPDATE accounts SET balance = balance + ? WHERE id = ?\",\n        [50, 2],\n        (creditError) => {\n          if (creditError) {\n            connection.rollback(() => connection.end());\n            return;\n          }\n\n          connection.commit((commitError) => {\n            if (commitError) {\n              connection.rollback(() => connection.end());\n              return;\n            }\n\n            connection.end();\n          });\n        },\n      );\n    },\n  );\n});\n```\n\n### Get a pooled connection for multi-step work\n\nUse `pool.getConnection()` when several statements must run on the same underlying connection.\n\n```typescript\nimport * as mysql from \"mysql\";\n\nconst pool = mysql.createPool({\n  host: process.env.MYSQL_HOST ?? \"127.0.0.1\",\n  user: process.env.MYSQL_USER,\n  password: process.env.MYSQL_PASSWORD,\n  database: process.env.MYSQL_DATABASE,\n  connectionLimit: 10,\n});\n\npool.getConnection((err, connection) => {\n  if (err) {\n    throw err;\n  }\n\n  connection.query(\"SELECT NOW() AS now\", (queryError, results) => {\n    connection.release();\n\n    if (queryError) {\n      throw queryError;\n    }\n\n    console.log(results);\n  });\n});\n```\n\nCall `connection.release()` for pooled connections, and `pool.end()` during application shutdown.\n\n### Format values and identifiers safely\n\nThe declarations expose `format()`, `escape()`, and `escapeId()` for the same SQL templating API as the runtime package.\n\n```typescript\nimport * as mysql from \"mysql\";\n\nconst sql = mysql.format(\n  \"SELECT ?? FROM ?? WHERE id = ?\",\n  [\"email\", \"users\", 42],\n);\n\nconsole.log(sql);\n```\n\nPrefer placeholders and `format()` over manual string concatenation.\n\n## Common Pitfalls\n\n- `@types/mysql` is a declaration package only. Install `mysql` separately for the runtime.\n- Do not import from `@types/mysql` in application code.\n- These declarations model the callback-based API. They do not add promise-returning query methods.\n- `query()` results are not generic in this package; the callback result is `any`, so cast or validate rows at your application boundary.\n- If your project restricts ambient types with `compilerOptions.types`, include `node` or the Node dependency types used by this package will disappear.\n- `multipleStatements` is available in `ConnectionConfig`, but its declaration comment warns that enabling it increases SQL injection risk.\n- If you provide a custom `typeCast` function, the declaration comment requires calling exactly one of `field.string()`, `field.buffer()`, or `field.geometry()` when parsing a value.\n- Use `supportBigNumbers`, `bigNumberStrings`, and `dateStrings` deliberately when you need predictable handling for `BIGINT`, `DECIMAL`, `DATE`, `DATETIME`, or `TIMESTAMP` values.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/mysql\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mysql\n"
  },
  {
    "path": "content/typescript/docs/node/typescript/DOC.md",
    "content": "---\nname: node\ndescription: \"TypeScript declarations for Node.js built-in modules, globals, environment variables, and Node-specific compiler setup.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"25.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,node,nodejs,types,definitelytyped,ambient-types\"\n---\n\n# Node.js TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/node` for compile-time declarations only.\n\nYour application code imports Node built-ins such as `node:fs`, `node:path`, and `node:module`. The `@types/node` package supplies the TypeScript definitions for those modules and for Node globals such as `process`, `Buffer`, `fetch`, and the `NodeJS` namespace.\n\nIt does not install the Node.js runtime itself.\n\n## Install\n\nAdd TypeScript and the Node declaration package to your project:\n\n```bash\nnpm install -D typescript @types/node\n```\n\nIf TypeScript is already installed, add only the missing Node declarations:\n\n```bash\nnpm install -D @types/node\n```\n\n`@types/node@25.4.0` depends on `undici-types`, so modern Node web-platform globals such as `fetch`, `Headers`, `Request`, and `Response` come from the package setup automatically.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup is your TypeScript compiler configuration and the way you import Node built-ins.\n\n### Recommended `tsconfig.json`\n\nUse Node-oriented module settings for Node applications:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project explicitly restricts ambient type packages with `compilerOptions.types`, include `node`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n`@types/node@25.4.0` declares `typeScriptVersion: \"5.2\"` and ships `typesVersions` mappings for TypeScript `<=5.6` and `<=5.7`, so use TypeScript 5.2 or newer and let the compiler select the matching declaration tree.\n\n## Common Workflows\n\n### Import built-in modules and use Node globals\n\nImport runtime APIs from Node module specifiers such as `node:fs/promises` and `node:path`. Globals such as `process` and `Buffer` are available through the installed declarations.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\ntype PackageJson = {\n  name: string;\n  version: string;\n};\n\nexport async function readPackageJson(): Promise<PackageJson> {\n  const packageJsonPath = join(process.cwd(), \"package.json\");\n  const raw = await readFile(packageJsonPath, \"utf8\");\n\n  return JSON.parse(raw) as PackageJson;\n}\n\nconst bytes = Buffer.from(\"context-hub\", \"utf8\");\nconsole.log(bytes.toString(\"hex\"));\n```\n\nThe declarations also cover bare specifiers such as `fs`, but `node:` imports make the runtime boundary explicit.\n\n### Type `process.env` with declaration merging\n\nExtend `NodeJS.ProcessEnv` in a `.d.ts` file that is included in your project compilation.\n\n```typescript\ndeclare namespace NodeJS {\n  interface ProcessEnv {\n    DATABASE_URL: string;\n    PORT?: `${number}`;\n    NODE_ENV?: \"development\" | \"test\" | \"production\";\n  }\n}\n```\n\nThen consume the variables with normal Node globals:\n\n```typescript\nconst databaseUrl = process.env.DATABASE_URL;\nconst port = Number(process.env.PORT ?? \"3000\");\n\nexport const config = {\n  databaseUrl,\n  port,\n};\n```\n\nThis is the main customization point most Node TypeScript apps use with `@types/node`.\n\n### Use Node's `fetch` types without DOM imports\n\nThe package includes web-platform fetch declarations and models them through `undici-types`, so you can type helper functions against `RequestInit`, `Response`, and related globals in Node code.\n\n```typescript\ntype Healthcheck = {\n  ok: boolean;\n};\n\nexport async function getHealthcheck(url: string, init?: RequestInit): Promise<Healthcheck> {\n  const response = await fetch(url, {\n    ...init,\n    headers: {\n      accept: \"application/json\",\n      ...init?.headers,\n    },\n  });\n\n  if (!response.ok) {\n    throw new Error(`Request failed with ${response.status}`);\n  }\n\n  return (await response.json()) as Healthcheck;\n}\n```\n\n### Bridge ESM code to CommonJS with `createRequire`\n\nWhen an ESM file still needs `require()` semantics, use `createRequire()` from `node:module`.\n\n```typescript\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\ntype PackageJson = {\n  name: string;\n  version: string;\n};\n\nconst packageJson = require(\"../package.json\") as PackageJson;\n\nconsole.log(`${packageJson.name}@${packageJson.version}`);\n```\n\n### Use Node timer types explicitly\n\nNode timers return `NodeJS.Timeout`, not the browser's numeric timer ID.\n\n```typescript\nlet heartbeat: NodeJS.Timeout | undefined;\n\nexport function startHeartbeat() {\n  heartbeat = setInterval(() => {\n    process.stdout.write(\".\");\n  }, 1000);\n\n  heartbeat.unref();\n}\n\nexport function stopHeartbeat() {\n  if (heartbeat) {\n    clearInterval(heartbeat);\n    heartbeat = undefined;\n  }\n}\n```\n\n## Common Pitfalls\n\n- Install the real Node.js runtime separately; `@types/node` only provides declarations.\n- Import from runtime module specifiers such as `node:fs` or `node:module`, not from `@types/node`.\n- If your `tsconfig.json` uses `compilerOptions.types`, include `node` there or Node globals and built-in module typings will appear to disappear.\n- `@types/node@25.4.0` requires TypeScript 5.2 or newer.\n- Modern fetch-related globals in this package are modeled through the `undici-types` dependency.\n- Keep custom `.d.ts` files such as your `ProcessEnv` augmentation inside the files matched by your project's `include` or `files` settings.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/node\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node\n- https://nodejs.org/api/fs.html\n- https://nodejs.org/api/module.html\n- https://nodejs.org/api/process.html\n- https://nodejs.org/api/globals.html#fetch\n"
  },
  {
    "path": "content/typescript/docs/node-fetch/typescript/DOC.md",
    "content": "---\nname: node-fetch\ndescription: \"TypeScript declarations for `node-fetch` 2.x, including CommonJS imports, typed requests and responses, and Node-specific fetch extensions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.6.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,node-fetch,fetch,http,types,definitelytyped\"\n---\n\n# node-fetch TypeScript Guide\n\n## Golden Rule\n\nInstall `node-fetch` for runtime behavior and `@types/node-fetch` for compile-time declarations.\n\nThis package describes the `node-fetch` 2.x API. It exports a CommonJS `fetch` function plus typed classes and helpers such as `Request`, `Response`, `Headers`, `FetchError`, and `fetch.isRedirect()`.\n\nImport from `\"node-fetch\"` in application code. Do not import from `\"@types/node-fetch\"` directly.\n\n## Install\n\nInstall the runtime package and the matching declaration package:\n\n```bash\nnpm install node-fetch@^2\nnpm install -D typescript @types/node-fetch@2.6.13\n```\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\n`@types/node-fetch@2.6.13` depends on `@types/node` and `form-data`, and its published metadata declares `typeScriptVersion: \"5.1\"`.\n\nIf your project is pinned to an older TypeScript compiler, use the matching npm dist-tagged release instead of `2.6.13`. The npm registry maps `ts4.9` and `ts5.0` to `@types/node-fetch@2.6.12`.\n\n## Imports And Type Usage\n\nThe published declarations use `export = fetch`, so `import = require()` is the most direct TypeScript import form:\n\n```typescript\nimport fetch = require(\"node-fetch\");\n```\n\nUse the namespace to reference exported types:\n\n```typescript\nimport fetch = require(\"node-fetch\");\n\nconst init: fetch.RequestInit = {\n  method: \"POST\",\n  headers: { \"content-type\": \"application/json\" },\n  body: JSON.stringify({ hello: \"world\" }),\n  compress: true,\n  follow: 5,\n  timeout: 5_000,\n};\n```\n\n`@types/node-fetch` references Node types directly and defines its own `AbortSignal` interface in `externals.d.ts`, so you do not need the DOM library just to type the `signal` option.\n\n## Common Workflows\n\n### Make A Typed JSON Request\n\nCheck `response.ok` yourself. `node-fetch` documents that `3xx`-`5xx` responses do not throw automatically.\n\n```typescript\nimport fetch = require(\"node-fetch\");\n\ntype GitHubUser = {\n  id: number;\n  login: string;\n};\n\nexport async function getGitHubUser(login: string): Promise<GitHubUser> {\n  const response = await fetch(`https://api.github.com/users/${login}`, {\n    headers: {\n      accept: \"application/json\",\n    },\n  });\n\n  if (!response.ok) {\n    throw new Error(`GitHub returned ${response.status} ${response.statusText}`);\n  }\n\n  return (await response.json()) as GitHubUser;\n}\n```\n\n### Pass Authentication Headers From Environment Variables\n\nThere is no built-in auth layer. If the upstream HTTP service expects a token, read it from your own environment variable and send it through `headers`.\n\n```bash\nexport API_TOKEN=your-token\n```\n\n```typescript\nimport fetch = require(\"node-fetch\");\n\nconst token = process.env.API_TOKEN;\n\nif (!token) {\n  throw new Error(\"API_TOKEN is required\");\n}\n\nconst response = await fetch(\"https://api.example.com/me\", {\n  headers: {\n    authorization: `Bearer ${token}`,\n    accept: \"application/json\",\n  },\n});\n```\n\n### Post JSON Or URL-Encoded Data\n\n`RequestInit.body` accepts strings, `ArrayBuffer`, `ArrayBufferView`, Node readable streams, `URLSearchParams`, and `FormData`.\n\n```typescript\nimport fetch = require(\"node-fetch\");\nimport { URLSearchParams } from \"node:url\";\n\nasync function createJson() {\n  const response = await fetch(\"https://httpbin.org/post\", {\n    method: \"POST\",\n    headers: {\n      \"content-type\": \"application/json\",\n    },\n    body: JSON.stringify({ a: 1 }),\n  });\n\n  return response.json();\n}\n\nasync function createForm() {\n  const params = new URLSearchParams();\n  params.append(\"a\", \"1\");\n\n  const response = await fetch(\"https://httpbin.org/post\", {\n    method: \"POST\",\n    body: params,\n  });\n\n  return response.json();\n}\n```\n\nThe `node-fetch` README notes that `Content-Type: application/x-www-form-urlencoded` is set automatically only when the body is an actual `URLSearchParams` instance.\n\n### Cancel A Request With `AbortSignal`\n\n`node-fetch` 2.x supports request cancellation with an `AbortSignal`. The v2 README suggests the `abort-controller` package when you need a controller implementation.\n\n```bash\nnpm install abort-controller\n```\n\n```typescript\nimport fetch = require(\"node-fetch\");\n\nconst AbortController = require(\"abort-controller\");\n\nconst controller = new AbortController();\nconst timeout = setTimeout(() => {\n  controller.abort();\n}, 150);\n\ntry {\n  const response = await fetch(\"https://api.example.com/slow\", {\n    signal: controller.signal,\n  });\n\n  console.log(response.status);\n} catch (error) {\n  if (error instanceof Error && error.name === \"AbortError\") {\n    console.error(\"request aborted\");\n  } else {\n    throw error;\n  }\n} finally {\n  clearTimeout(timeout);\n}\n```\n\n### Use The Node-Specific Extensions\n\n`node-fetch` 2.x adds request options and response helpers that are not part of the browser Fetch API.\n\n```typescript\nimport http = require(\"node:http\");\nimport https = require(\"node:https\");\nimport fetch = require(\"node-fetch\");\n\nconst httpAgent = new http.Agent({ keepAlive: true });\nconst httpsAgent = new https.Agent({ keepAlive: true });\n\nconst response = await fetch(\"https://example.com/download\", {\n  agent: (parsedUrl) => {\n    return parsedUrl.protocol === \"http:\" ? httpAgent : httpsAgent;\n  },\n  follow: 10,\n  compress: true,\n  size: 2 * 1024 * 1024,\n  timeout: 5_000,\n});\n\nif (fetch.isRedirect(response.status)) {\n  console.log(\"redirect response\");\n}\n\nconst bytes = await response.buffer();\nconst setCookies = response.headers.raw()[\"set-cookie\"];\n\nconsole.log(bytes.length, setCookies);\n```\n\n`response.body` is typed as a Node.js `Readable` stream, not a WHATWG `ReadableStream`.\n\n## Practical Pitfalls\n\n- `@types/node-fetch` is declarations only. Install `node-fetch` itself for runtime behavior.\n- These declarations target `node-fetch` 2.x. Do not pair them with `node-fetch` 3.x, which is ESM-only and already ships its own `types` entry.\n- The v2 types expose Node-specific extensions such as `agent`, `compress`, `follow`, `timeout`, `size`, `Headers.raw()`, `Body.buffer()`, and `Body.textConverted()`.\n- The README documents `mode`, `credentials`, and `cache` as unsupported request features in `node-fetch` 2.x.\n- The README also documents `body.formData()` as not implemented in `node-fetch` 2.x.\n- `Body.textConverted()` requires the optional `encoding` package to be installed manually.\n- Do not rely on `Response.error()` or `Response.redirect()` in `node-fetch` 2.x. The v2 README lists both as not implemented.\n"
  },
  {
    "path": "content/typescript/docs/nodemailer/typescript/DOC.md",
    "content": "---\nname: nodemailer\ndescription: \"TypeScript declarations for Nodemailer transports, message options, SMTP configuration, and typed sendMail workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.0.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,nodemailer,email,smtp,types,definitelytyped\"\n---\n\n# Nodemailer TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/nodemailer` alongside the real `nodemailer` runtime package.\n\n`@types/nodemailer` only provides declarations. Your application imports and runs `nodemailer`; the declaration package adds types for `createTransport()`, `sendMail()`, `verify()`, `createTestAccount()`, transport option objects, and message payloads.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration packages you need.\n\n```bash\nnpm install nodemailer\nnpm install -D typescript @types/node @types/nodemailer\n```\n\nIf `nodemailer` is already in your app, add only the missing declarations:\n\n```bash\nnpm install -D @types/node @types/nodemailer\n```\n\n`@types/nodemailer` depends on Node.js types. If your project restricts loaded ambient types with `compilerOptions.types`, include `node` in that list.\n\n## Recommended `tsconfig.json`\n\nThe declaration package is Node-oriented, so keep Node types available and use normal strict TypeScript settings.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\"]\n  }\n}\n```\n\nIf your app uses CommonJS settings instead, keep those settings. The important parts here are strict checking and including Node types.\n\n## Import and Initialize\n\nThe declarations expose named exports from `nodemailer`, so a portable TypeScript import looks like this:\n\n```typescript\nimport { createTransport, type SendMailOptions } from \"nodemailer\";\n```\n\n### Create an SMTP transporter\n\n```typescript\nimport { createTransport, type SendMailOptions } from \"nodemailer\";\n\nfunction requireEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) {\n    throw new Error(`Missing environment variable: ${name}`);\n  }\n  return value;\n}\n\nconst port = Number(process.env.SMTP_PORT ?? \"587\");\nconst secure = process.env.SMTP_SECURE === \"true\";\n\nexport const transporter = createTransport(\n  {\n    host: requireEnv(\"SMTP_HOST\"),\n    port,\n    secure,\n    auth: {\n      user: requireEnv(\"SMTP_USER\"),\n      pass: requireEnv(\"SMTP_PASS\"),\n    },\n  },\n  {\n    from: requireEnv(\"SMTP_FROM\"),\n  },\n);\n\nawait transporter.verify();\n\nconst message: SendMailOptions = {\n  to: \"recipient@example.com\",\n  subject: \"Hello\",\n  text: \"Plain-text body\",\n  html: \"<p>HTML body</p>\",\n};\n\nconst info = await transporter.sendMail(message);\n\nconsole.log(info.messageId);\nconsole.log(info.accepted);\nconsole.log(info.rejected);\nconsole.log(info.response);\n```\n\nThe second `createTransport()` argument is a defaults object. A common pattern is to keep `from` there so each message only supplies recipients and content.\n\n## Common Workflows\n\n### Send attachments and inline images\n\n`SendMailOptions` includes `attachments`, `html`, `text`, `cc`, `bcc`, `replyTo`, `headers`, `priority`, `icalEvent`, and other message fields.\n\n```typescript\nimport { createTransport, type SendMailOptions } from \"nodemailer\";\n\nconst transporter = createTransport({\n  host: process.env.SMTP_HOST,\n  port: Number(process.env.SMTP_PORT ?? \"587\"),\n  secure: process.env.SMTP_SECURE === \"true\",\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASS,\n  },\n});\n\nconst message: SendMailOptions = {\n  from: process.env.SMTP_FROM,\n  to: \"recipient@example.com\",\n  subject: \"Monthly report\",\n  text: \"See the attached report.\",\n  html: '<p>See the attached report.</p><img src=\"cid:logo@example.com\" />',\n  attachments: [\n    {\n      filename: \"report.csv\",\n      content: Buffer.from(\"id,total\\n1,42\\n\", \"utf8\"),\n      contentType: \"text/csv\",\n    },\n    {\n      filename: \"invoice.pdf\",\n      path: \"./invoices/invoice-42.pdf\",\n    },\n    {\n      filename: \"logo.png\",\n      path: \"./public/logo.png\",\n      cid: \"logo@example.com\",\n    },\n  ],\n};\n\nawait transporter.sendMail(message);\n```\n\nAttachment `content` accepts a `string`, `Buffer`, or `Readable` stream. Attachment `path` is typed for file paths and URLs.\n\n### Reuse pooled SMTP connections\n\nFor workers or bulk mail senders, the SMTP pool overload adds pool-specific options such as `maxConnections`, `maxMessages`, `rateDelta`, and `rateLimit`.\n\n```typescript\nimport { createTransport } from \"nodemailer\";\n\nconst transporter = createTransport({\n  pool: true,\n  host: process.env.SMTP_HOST,\n  port: Number(process.env.SMTP_PORT ?? \"587\"),\n  secure: process.env.SMTP_SECURE === \"true\",\n  auth: {\n    user: process.env.SMTP_USER,\n    pass: process.env.SMTP_PASS,\n  },\n  maxConnections: 5,\n  maxMessages: 100,\n  rateDelta: 1000,\n  rateLimit: 25,\n});\n\nif (transporter.isIdle()) {\n  await transporter.sendMail({\n    from: process.env.SMTP_FROM,\n    to: \"recipient@example.com\",\n    subject: \"Queued message\",\n    text: \"Sent through a pooled transporter.\",\n  });\n}\n\ntransporter.close();\n```\n\n### Create a test account and preview URL\n\nThe declarations include `createTestAccount()` and `getTestMessageUrl()` for typed test-account flows.\n\n```typescript\nimport {\n  createTestAccount,\n  createTransport,\n  getTestMessageUrl,\n} from \"nodemailer\";\n\nconst account = await createTestAccount();\n\nconst transporter = createTransport({\n  host: account.smtp.host,\n  port: account.smtp.port,\n  secure: account.smtp.secure,\n  auth: {\n    user: account.user,\n    pass: account.pass,\n  },\n});\n\nconst info = await transporter.sendMail({\n  from: account.user,\n  to: \"recipient@example.com\",\n  subject: \"Preview message\",\n  text: \"Open the preview URL returned by Nodemailer.\",\n});\n\nconst previewUrl = getTestMessageUrl(info);\n\nif (previewUrl) {\n  console.log(previewUrl);\n}\n```\n\nThe returned account object includes `user`, `pass`, `smtp`, `imap`, `pop3`, and `web` fields.\n\n## TypeScript-Specific Patterns\n\n### Type the SMTP config explicitly\n\nIf you want the concrete SMTP option interface instead of an inferred object literal, import the transport submodule type and pass it to `createTransport()`.\n\n```typescript\nimport { createTransport } from \"nodemailer\";\nimport SMTPTransport = require(\"nodemailer/lib/smtp-transport\");\n\nconst transport: SMTPTransport.Options = {\n  host: process.env.SMTP_HOST,\n  port: Number(process.env.SMTP_PORT ?? \"587\"),\n  secure: process.env.SMTP_SECURE === \"true\",\n  auth: {\n    user: process.env.SMTP_USER ?? \"\",\n    pass: process.env.SMTP_PASS ?? \"\",\n  },\n  connectionTimeout: 10_000,\n  greetingTimeout: 10_000,\n  socketTimeout: 30_000,\n  requireTLS: true,\n};\n\nconst transporter = createTransport(transport);\n```\n\nThe `SMTPTransport.Options` type includes the connection fields most apps need in practice: `host`, `port`, `secure`, `auth`, `ignoreTLS`, `requireTLS`, `connectionTimeout`, `greetingTimeout`, `socketTimeout`, `logger`, `debug`, and `tls`.\n\n### Rely on inferred send results\n\nWhen you create an SMTP transporter with the SMTP overload, `sendMail()` returns a typed SMTP result. You can use its fields directly without adding your own result interface.\n\n```typescript\nconst info = await transporter.sendMail({\n  from: process.env.SMTP_FROM,\n  to: \"recipient@example.com\",\n  subject: \"Typed result\",\n  text: \"This result is inferred from the selected transport.\",\n});\n\ninfo.messageId;\ninfo.accepted;\ninfo.rejected;\ninfo.pending;\ninfo.response;\n```\n\n## Common Pitfalls\n\n- Install `nodemailer` separately. `@types/nodemailer` does not include the runtime.\n- Import from `nodemailer`, not from `@types/nodemailer`.\n- If your project uses `compilerOptions.types`, include `node` or Node.js globals such as `Buffer`, `Readable`, and `process` will not be available to these declarations.\n- `verify()` checks the selected transport configuration and resolves to `true`; it does not send a message.\n- `pool: true` switches you to the pooled SMTP transport overload. Close pooled transporters when the process is shutting down.\n- Message options can disable file-backed or URL-backed content with `disableFileAccess` and `disableUrlAccess`. That affects attachments and other message parts loaded from files or URLs.\n- The submodule transport declarations such as `nodemailer/lib/smtp-transport` use `export =`. `import SMTPTransport = require(\"nodemailer/lib/smtp-transport\")` is the safe form when you need those exact types.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/nodemailer\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/nodemailer\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemailer/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemailer/lib/mailer/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemailer/lib/smtp-transport/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemailer/lib/smtp-connection/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemailer/lib/smtp-pool/index.d.ts\n"
  },
  {
    "path": "content/typescript/docs/nunjucks/typescript/DOC.md",
    "content": "---\nname: nunjucks\ndescription: \"TypeScript declarations for configuring Nunjucks environments, rendering templates, and typing the integration boundary with the Nunjucks runtime.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.2.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,nunjucks,templates,node,express,types,definitelytyped\"\n---\n\n# Nunjucks TypeScript Guide\n\nInstall `@types/nunjucks` alongside the real `nunjucks` runtime package.\n\n`@types/nunjucks` provides TypeScript declarations only. Your application imports and runs `nunjucks`; the declaration package supplies types for `configure()`, `Environment`, loaders, filters, globals, `render()`, and `renderString()`.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install nunjucks\nnpm install -D typescript @types/node @types/nunjucks\n```\n\nIf your project already depends on `nunjucks`, add only the missing declarations:\n\n```bash\nnpm install -D @types/node @types/nunjucks\n```\n\nNunjucks does not require API keys, credentials, or package-specific environment variables.\n\n## TypeScript Setup\n\nThe declarations are for the `nunjucks` module itself. Import from `\"nunjucks\"`, never from `\"@types/nunjucks\"`.\n\n### Import `nunjucks`\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, use the default import form:\n\n```typescript\nimport nunjucks from \"nunjucks\";\n```\n\nIf your project keeps CommonJS-style imports, use `import = require()`:\n\n```typescript\nimport nunjucks = require(\"nunjucks\");\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient type packages with `compilerOptions.types`, include the packages used by the code that renders templates:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n## Create A Reusable Environment\n\nUse `configure()` when you want a simple file-based setup for server-side templates.\n\n```typescript\nimport path from \"node:path\";\nimport nunjucks from \"nunjucks\";\n\nconst viewsDir = path.join(process.cwd(), \"views\");\n\nexport const env = nunjucks.configure(viewsDir, {\n  autoescape: true,\n  noCache: process.env.NODE_ENV !== \"production\",\n  watch: process.env.NODE_ENV === \"development\",\n  throwOnUndefined: true,\n  trimBlocks: true,\n  lstripBlocks: true,\n});\n```\n\nThis returns a typed `Environment` instance that you can reuse across route handlers, email rendering helpers, and background jobs.\n\nIf you want explicit loader construction, create the loader yourself and pass it to `Environment`:\n\n```typescript\nimport nunjucks from \"nunjucks\";\n\nconst loader = new nunjucks.FileSystemLoader([\"views\", \"shared/views\"], {\n  noCache: process.env.NODE_ENV !== \"production\",\n});\n\nexport const env = new nunjucks.Environment(loader, {\n  autoescape: true,\n  throwOnUndefined: true,\n});\n```\n\n## Render Templates\n\n### Render a template file\n\n```typescript\nimport { env } from \"./nunjucks-env\";\n\nconst html = env.render(\"emails/welcome.njk\", {\n  user: {\n    firstName: \"Ada\",\n  },\n  productName: \"Project Atlas\",\n});\n```\n\n### Render from a string\n\n```typescript\nimport { env } from \"./nunjucks-env\";\n\nconst preview = env.renderString(\"Hello {{ name }}!\", {\n  name: \"Ada\",\n});\n```\n\nIf you already have an `Environment`, prefer `env.render()` and `env.renderString()` so your configured loaders, globals, and filters are used consistently.\n\n## Type The Data You Pass Into Templates\n\nThe declaration package types the Nunjucks API surface, not the contents of your template files. The safest pattern is to type each view model at the application boundary.\n\n```typescript\nimport { env } from \"./nunjucks-env\";\n\ninterface WelcomeEmailView {\n  user: {\n    firstName: string;\n  };\n  productName: string;\n  loginUrl: string;\n}\n\nexport function renderWelcomeEmail(view: WelcomeEmailView): string {\n  return env.render(\"emails/welcome.njk\", view);\n}\n```\n\nThis keeps the data you send to templates checked by TypeScript even though template variable names are not statically verified.\n\n## Add Custom Filters And Globals\n\nRegister filters and globals on the shared environment before rendering.\n\n```typescript\nimport { env } from \"./nunjucks-env\";\n\nenv.addFilter(\"currency\", (amountCents: number) => {\n  return `$${(amountCents / 100).toFixed(2)}`;\n});\n\nenv.addGlobal(\"cdnBaseUrl\", process.env.CDN_BASE_URL ?? \"\");\n\nconst html = env.renderString(\n  \"<img src=\\\"{{ cdnBaseUrl }}/logo.svg\\\"> {{ total | currency }}\",\n  { total: 2599 },\n);\n```\n\nFor asynchronous filters, use Nunjucks' callback-based async filter API and pass `true` as the third argument to `addFilter()`.\n\n```typescript\nimport { env } from \"./nunjucks-env\";\n\nenv.addFilter(\n  \"loadDisplayName\",\n  (userId: string, callback: (err: Error | null, result?: string) => void) => {\n    lookupDisplayName(userId)\n      .then((displayName) => callback(null, displayName))\n      .catch((error: unknown) => {\n        callback(error instanceof Error ? error : new Error(\"lookup failed\"));\n      });\n  },\n  true,\n);\n\nasync function lookupDisplayName(userId: string): Promise<string> {\n  return `user:${userId}`;\n}\n```\n\n## Use Nunjucks With Express\n\nWhen you integrate Nunjucks into an Express app, pass the app instance in the `express` option during configuration.\n\n```typescript\nimport express from \"express\";\nimport nunjucks from \"nunjucks\";\n\nconst app = express();\n\nnunjucks.configure(\"views\", {\n  autoescape: true,\n  express: app,\n});\n\napp.get(\"/hello\", (_req, res) => {\n  res.render(\"hello.njk\", { name: \"Ada\" });\n});\n```\n\nKeep the rendering import pointed at `nunjucks`; `@types/nunjucks` is only there so TypeScript understands the runtime API.\n\n## Common Pitfalls\n\n- Install both `nunjucks` and `@types/nunjucks`; the declaration package is not a runtime dependency by itself.\n- Import from `\"nunjucks\"`, not from `\"@types/nunjucks\"`.\n- If `esModuleInterop` is off, switch to `import nunjucks = require(\"nunjucks\")`.\n- TypeScript checks the objects you pass into `render()` and `renderString()`, but it does not validate template variable names inside `.njk` files.\n- Register async filters with the third `true` argument or Nunjucks treats them as synchronous filters.\n\n## Version Notes For `@types/nunjucks` 3.2.6\n\nFor this declaration-package version, the practical integration boundary is the `nunjucks` runtime module. Keep application imports, environment setup, filters, and rendering calls centered on `nunjucks`, and use `@types/nunjucks` only to supply TypeScript declarations for that runtime API.\n"
  },
  {
    "path": "content/typescript/docs/papaparse/typescript/DOC.md",
    "content": "---\nname: papaparse\ndescription: \"TypeScript declarations for Papa Parse CSV parsing and serialization workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.5.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,papaparse,csv,parsing,serialization,types,definitelytyped\"\n---\n\n# Papa Parse TypeScript Guide\n\n`@types/papaparse` adds TypeScript declarations for the `papaparse` runtime package. Install it when your project uses Papa Parse and your compiler does not already see bundled types.\n\nThis package only provides types. Your code imports and runs `papaparse`, not `@types/papaparse`.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install papaparse\nnpm install -D typescript @types/papaparse\n```\n\nNo environment variables, credentials, or client initialization are required.\n\n## TypeScript Setup\n\nIn most projects, installing `@types/papaparse` is enough.\n\nIf your project uses default imports, enable interop in `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict ambient types with `compilerOptions.types`, include `papaparse`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"papaparse\"]\n  }\n}\n```\n\n## Import The Runtime Correctly\n\nWith `esModuleInterop` enabled, use a default import:\n\n```ts\nimport Papa from \"papaparse\";\n```\n\nWithout interop, use the CommonJS-compatible form:\n\n```ts\nimport Papa = require(\"papaparse\");\n```\n\nDo not import from `\"@types/papaparse\"` in application code.\n\n## Common Workflows\n\n### Parse A CSV String Into Typed Rows\n\nWhen your CSV includes a header row, pass a row type to `Papa.parse<T>()` and set `header: true`.\n\n```ts\nimport Papa from \"papaparse\";\n\ntype UserRow = {\n  id: string;\n  email: string;\n  role: string;\n};\n\nconst csv = `id,email,role\n1,ada@example.com,admin\n2,grace@example.com,editor`;\n\nconst result = Papa.parse<UserRow>(csv, {\n  header: true,\n  skipEmptyLines: true,\n});\n\nif (result.errors.length > 0) {\n  console.error(result.errors);\n}\n\nfor (const row of result.data) {\n  console.log(row.email, row.role);\n}\n```\n\n`result.data` is typed as `UserRow[]`, while parse problems are available on `result.errors`.\n\n### Parse Headerless CSV As Arrays\n\nIf the input does not have headers, use an array row type instead of an object type.\n\n```ts\nimport Papa from \"papaparse\";\n\nconst csv = `Ada,admin\nGrace,editor`;\n\nconst result = Papa.parse<[string, string]>(csv, {\n  header: false,\n  skipEmptyLines: true,\n});\n\nfor (const [name, role] of result.data) {\n  console.log(name, role);\n}\n```\n\nUse tuples when each column has a fixed position, or `string[]` when row length can vary.\n\n### Parse A Browser `File`\n\nPapa Parse can also parse a browser `File` object. The declaration package types the same `parse()` call so your callbacks stay typed.\n\n```ts\nimport Papa from \"papaparse\";\n\ntype UploadRow = {\n  name: string;\n  email: string;\n};\n\nfunction parseUpload(file: File) {\n  Papa.parse<UploadRow>(file, {\n    header: true,\n    skipEmptyLines: true,\n    complete(results) {\n      console.log(results.data);\n      console.log(results.errors);\n    },\n  });\n}\n```\n\nUse the `File` overload in browser code. On the server, the most portable path is usually to read CSV content into a string first and parse that string.\n\n### Process Large Inputs Row By Row\n\nFor large inputs, use `step` so you can handle each row incrementally instead of waiting for the full result.\n\n```ts\nimport Papa from \"papaparse\";\n\ntype AuditRow = {\n  id: string;\n  status: string;\n};\n\nPapa.parse<AuditRow>(`id,status\n1,ok\n2,failed`, {\n  header: true,\n  step(result, parser) {\n    console.log(result.data.id, result.data.status);\n\n    if (result.data.status === \"failed\") {\n      parser.abort();\n    }\n  },\n});\n```\n\nThis pattern matters most when you want early termination or incremental validation.\n\n### Generate CSV With `Papa.unparse`\n\nThe same package also types `Papa.unparse()` for turning arrays or object rows back into CSV.\n\n```ts\nimport Papa from \"papaparse\";\n\nconst csv = Papa.unparse([\n  { id: \"1\", email: \"ada@example.com\" },\n  { id: \"2\", email: \"grace@example.com\" },\n]);\n\nconsole.log(csv);\n```\n\nWhen you pass object rows, Papa Parse derives the output columns from the object keys.\n\n## Useful Type Imports\n\nImport helper types from `papaparse` when you want explicit annotations around parse results or config objects.\n\n```ts\nimport Papa from \"papaparse\";\n\ntype Row = {\n  id: string;\n  email: string;\n};\n\nconst config: Papa.ParseConfig<Row> = {\n  header: true,\n  skipEmptyLines: true,\n};\n\nconst result: Papa.ParseResult<Row> = Papa.parse<Row>(\n  \"id,email\\n1,ada@example.com\",\n  config,\n);\nconst errors: Papa.ParseError[] = result.errors;\n\nconsole.log(errors.length);\n```\n\nThese explicit imports are most useful in shared utilities and wrapper functions.\n\n## Pitfalls\n\n- Install `papaparse` as well as `@types/papaparse`; the declaration package does not include the runtime.\n- Import from `papaparse`, never `@types/papaparse`.\n- Match your generic row type to the actual CSV shape: object rows with `header: true`, array or tuple rows with `header: false`.\n- Treat generics as compile-time help, not runtime validation. TypeScript will not verify that the CSV really contains the columns or value formats you declared.\n- If you rely on numeric or boolean output, configure Papa Parse accordingly and keep your row type aligned with the runtime conversion you expect.\n\n## Version Notes\n\nThis guide targets `@types/papaparse` version `5.5.2`. The package provides TypeScript declarations for Papa Parse's parsing and serialization APIs and is intended to be used alongside the `papaparse` runtime package.\n"
  },
  {
    "path": "content/typescript/docs/passport/typescript/DOC.md",
    "content": "---\nname: passport\ndescription: \"TypeScript declarations for Passport's core middleware, request helpers, session hooks, and Express user augmentation.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.0.17\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,passport,authentication,express,sessions,types,definitelytyped\"\n---\n\n# Passport TypeScript Guide\n\n`@types/passport` adds TypeScript declarations for the `passport` runtime package. In practice, it matters most in three places:\n\n- typing the `passport` module itself\n- augmenting `Express.Request` with `req.user`, `req.login()`, `req.logout()`, and `req.isAuthenticated()`\n- letting your app define the actual shape of `Express.User`\n\nThis package only ships `.d.ts` files. Install `passport` itself for runtime behavior.\n\n## Install\n\nInstall the runtime package and the type package together:\n\n```bash\nnpm install passport\nnpm install --save-dev @types/passport\n```\n\nIf you use Passport with Express sessions, install the surrounding runtime and type packages as well:\n\n```bash\nnpm install express express-session passport\nnpm install --save-dev typescript @types/express @types/express-session @types/passport\n```\n\nPassport itself does not require environment variables, but session-based apps usually do. A minimal local setup is:\n\n```bash\nexport SESSION_SECRET=\"replace-this-with-a-long-random-secret\"\n```\n\n## TypeScript Setup\n\n`passport` is a CommonJS package. If your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, use a default import:\n\n```ts\nimport passport from \"passport\";\n```\n\nOtherwise use the CommonJS-compatible import form:\n\n```ts\nimport passport = require(\"passport\");\n```\n\nIf your `tsconfig.json` restricts loaded ambient type packages with `compilerOptions.types`, include `passport` there:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"express\", \"express-session\", \"passport\"]\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\"]\n}\n```\n\nIf you do not restrict `compilerOptions.types`, you usually do not need this snippet.\n\n## Define Your `Express.User` Shape\n\n`@types/passport` intentionally leaves `Express.User` open so your app can describe the authenticated user object it stores on `req.user`.\n\nCreate a project declaration file such as `src/types/express-passport.d.ts`:\n\n```ts\ndeclare global {\n  namespace Express {\n    interface User {\n      id: string;\n      email: string;\n      displayName: string;\n    }\n  }\n}\n\nexport {};\n```\n\nMake sure this `.d.ts` file is included by TypeScript. After that, `req.user` and Passport callbacks use your application-specific user type.\n\n## Initialize Passport In An Express App\n\nFor session-based authentication, wire `express-session`, `passport.initialize()`, and `passport.session()` in that order:\n\n```ts\nimport express from \"express\";\nimport session from \"express-session\";\nimport passport from \"passport\";\n\nconst sessionSecret = process.env.SESSION_SECRET;\n\nif (!sessionSecret) {\n  throw new Error(\"SESSION_SECRET is required\");\n}\n\nconst app = express();\n\napp.use(express.json());\n\napp.use(\n  session({\n    secret: sessionSecret,\n    resave: false,\n    saveUninitialized: false,\n  }),\n);\n\napp.use(passport.initialize());\napp.use(passport.session());\n```\n\nIf you are using Passport without sessions, omit `passport.session()` and pass `{ session: false }` where appropriate in `passport.authenticate()`.\n\n## Common Workflows\n\n### Narrow `req.user` with `req.isAuthenticated()`\n\nThe declaration package types `req.isAuthenticated()` as a type guard. After the check passes, `req.user` is treated as a defined `Express.User`.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.get(\"/me\", (req, res) => {\n  if (!req.isAuthenticated()) {\n    res.status(401).json({ error: \"authentication required\" });\n    return;\n  }\n\n  res.json({\n    id: req.user.id,\n    email: req.user.email,\n    displayName: req.user.displayName,\n  });\n});\n```\n\nThis is the safest way to read `req.user` in route handlers without extra non-null assertions.\n\n### Log a user in with `req.login()`\n\nUse `req.login()` after your own credential or token verification step when you want Passport to establish a login session.\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.post(\"/session-login\", async (req, res, next) => {\n  const user = await verifyCredentials(req.body.email, req.body.password);\n\n  if (!user) {\n    res.status(401).json({ error: \"invalid credentials\" });\n    return;\n  }\n\n  req.login(user, (err) => {\n    if (err) {\n      next(err);\n      return;\n    }\n\n    res.status(204).end();\n  });\n});\n\nasync function verifyCredentials(email: string, password: string): Promise<Express.User | null> {\n  if (email === \"demo@example.com\" && password === \"correct-horse-battery-staple\") {\n    return {\n      id: \"user_123\",\n      email,\n      displayName: \"Demo User\",\n    };\n  }\n\n  return null;\n}\n```\n\nThe callback is part of the typed API. Handle errors there instead of assuming a synchronous return value.\n\n### Log a user out with `req.logout()`\n\n`@types/passport` models logout as a callback-based API as well:\n\n```ts\nimport express from \"express\";\n\nconst app = express();\n\napp.post(\"/logout\", (req, res, next) => {\n  req.logout((err) => {\n    if (err) {\n      next(err);\n      return;\n    }\n\n    res.status(204).end();\n  });\n});\n```\n\n### Serialize and deserialize session users\n\nWhen you enable session support, define how Passport stores a user identifier in the session and how it rebuilds `req.user` on later requests.\n\n```ts\nimport passport from \"passport\";\n\npassport.serializeUser((user, done) => {\n  done(null, user.id);\n});\n\npassport.deserializeUser((id: string, done) => {\n  findUserById(id)\n    .then((user) => done(null, user ?? false))\n    .catch((err: unknown) => done(err));\n});\n\nasync function findUserById(id: string): Promise<Express.User | null> {\n  if (id === \"user_123\") {\n    return {\n      id,\n      email: \"demo@example.com\",\n      displayName: \"Demo User\",\n    };\n  }\n\n  return null;\n}\n```\n\nBecause `Express.User` is your own merged interface, the same type flows through `serializeUser()`, `deserializeUser()`, and authenticated route handlers.\n\n### Use `passport.authenticate()` as Express middleware\n\nCore Passport types include `passport.authenticate()`, but strategy names and strategy-specific options come from the runtime strategy package you install.\n\n```ts\nimport express from \"express\";\nimport passport from \"passport\";\n\nconst app = express();\n\napp.post(\n  \"/login\",\n  passport.authenticate(\"local\", {\n    failureRedirect: \"/login\",\n    successReturnToOrRedirect: \"/account\",\n  }),\n);\n```\n\nFor a real app, install the matching strategy package as well, for example `passport-local` plus its type package if it publishes separate typings.\n\n## Integration Boundary\n\n`@types/passport` covers Passport core. You often need additional packages around it:\n\n- `passport` for the runtime middleware and request helpers\n- `express` and `express-session` when you use session-based login flows\n- a strategy package such as `passport-local`, `passport-jwt`, or `passport-google-oauth20`\n- that strategy package's own type definitions when they are separate from the runtime package\n\nUse `@types/passport` for the shared core layer, then add strategy-specific typings separately.\n\n## Important Pitfalls\n\n- Install `passport` as well as `@types/passport`; the type package does not include runtime JavaScript.\n- Define `Express.User` yourself or `req.user` stays too generic to be useful in application code.\n- Include your custom `.d.ts` file in TypeScript compilation or the `Express.User` merge will not take effect.\n- If you restrict `compilerOptions.types`, add `passport` or the request augmentation will not load.\n- `passport` uses CommonJS export syntax; without `esModuleInterop`, prefer `import passport = require(\"passport\")`.\n- Handle `req.login()` and `req.logout()` through their callbacks rather than treating them as synchronous helpers.\n- `passport.authenticate()` does not install a strategy for you; add the runtime strategy package separately.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/passport\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/passport\n- https://www.npmjs.com/package/passport\n- https://www.passportjs.org/\n"
  },
  {
    "path": "content/typescript/docs/pdfkit/typescript/DOC.md",
    "content": "---\nname: pdfkit\ndescription: \"TypeScript declarations for the PDFKit runtime package, including imports, Node.js compiler setup, and typed document-generation workflows\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.17.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,pdfkit,pdf,documents,npm,types,definitelytyped\"\n---\n\n# pdfkit TypeScript Guide\n\n`@types/pdfkit` provides the TypeScript declarations for the `pdfkit` runtime package. Use it when your project creates PDF documents in Node.js and you want typed access to the `PDFDocument` constructor, document options, stream integration, and common drawing methods such as `text()`, `image()`, `addPage()`, and `registerFont()`.\n\nThis package only ships `.d.ts` files. Install the `pdfkit` runtime separately.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install pdfkit\nnpm install --save-dev typescript @types/node @types/pdfkit\n```\n\nNo authentication or service initialization is required. PDF generation is local to your process.\n\n## Recommended `tsconfig.json`\n\n`pdfkit` is usually used from Node.js code that writes to files or HTTP responses, so a practical setup is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project does not restrict `compilerOptions.types`, installing `@types/node` is usually enough.\n\n## Import `pdfkit` In TypeScript\n\nThe declaration package is designed for the `pdfkit` runtime module, not for direct imports from `@types/pdfkit`.\n\nUse the configuration-independent import style when you want code that works without interop flags:\n\n```ts\nimport PDFDocument = require(\"pdfkit\");\n```\n\nIf your `tsconfig.json` enables `esModuleInterop`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport PDFDocument from \"pdfkit\";\n```\n\n## Create A PDF And Write It To Disk\n\nThe main runtime workflow is: create a `PDFDocument`, pipe it to a writable stream, write content, then call `end()`.\n\n```ts\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport PDFDocument = require(\"pdfkit\");\n\ntype PDFDocumentOptions = ConstructorParameters<typeof PDFDocument>[0];\n\nconst outputPath = process.env.PDF_OUTPUT_PATH ?? \"./output/hello.pdf\";\n\nawait mkdir(dirname(outputPath), { recursive: true });\n\nconst options: PDFDocumentOptions = {\n  size: \"A4\",\n  margin: 50,\n};\n\nconst doc = new PDFDocument(options);\nconst file = createWriteStream(outputPath);\n\nawait new Promise<void>((resolve, reject) => {\n  file.on(\"finish\", resolve);\n  file.on(\"error\", reject);\n  doc.on(\"error\", reject);\n\n  doc.pipe(file);\n\n  doc.fontSize(18).text(\"Hello from PDFKit\");\n  doc.moveDown();\n  doc.text(\"This file was generated from TypeScript.\");\n  doc.addPage().fontSize(14).text(\"Second page\");\n\n  doc.end();\n});\n```\n\n`PDF_OUTPUT_PATH` is only an application-level example. `pdfkit` itself does not require any environment variables.\n\n## Common Workflows\n\n### Reuse typed text options\n\nWhen you want a reusable text-layout object, derive the type from the public method signature instead of reaching into internal declaration paths.\n\n```ts\nimport PDFDocument = require(\"pdfkit\");\n\ntype PdfDocument = InstanceType<typeof PDFDocument>;\ntype TextOptions = NonNullable<Parameters<PdfDocument[\"text\"]>[2]>;\n\nconst bodyText: TextOptions = {\n  width: 410,\n  align: \"left\",\n};\n\nconst doc = new PDFDocument();\n\ndoc.text(\n  \"PDFKit uses the current font, font size, and cursor position unless you override them.\",\n  72,\n  72,\n  bodyText,\n);\n\ndoc.end();\n```\n\nThis is useful when multiple helpers in your app share the same wrapping or alignment rules.\n\n### Register a custom font before writing text\n\n`registerFont()` lets you give a font file a stable name, then switch to it with `font()`.\n\n```ts\nimport { createWriteStream } from \"node:fs\";\nimport PDFDocument = require(\"pdfkit\");\n\nconst doc = new PDFDocument();\ndoc.pipe(createWriteStream(\"./output/invoice.pdf\"));\n\ndoc.registerFont(\"body\", \"./fonts/Inter-Regular.ttf\");\n\ndoc\n  .font(\"body\")\n  .fontSize(12)\n  .text(\"Invoice #1001\", 72, 72);\n\ndoc.end();\n```\n\nUse this pattern when your application ships brand fonts or when a report generator needs consistent typography across pages.\n\n### Place an image with typed options\n\nYou can also derive image-option types from the public `image()` signature.\n\n```ts\nimport { createWriteStream } from \"node:fs\";\nimport PDFDocument = require(\"pdfkit\");\n\ntype PdfDocument = InstanceType<typeof PDFDocument>;\ntype ImageOptions = NonNullable<Parameters<PdfDocument[\"image\"]>[2]>;\n\nconst imageOptions: ImageOptions = {\n  width: 120,\n};\n\nconst doc = new PDFDocument();\ndoc.pipe(createWriteStream(\"./output/with-logo.pdf\"));\n\ndoc.image(\"./assets/logo.png\", 72, 72, imageOptions);\ndoc.text(\"Quarterly report\", 72, 220);\n\ndoc.end();\n```\n\nThis keeps helpers for logos, charts, or signatures tied to the public document API instead of to internal declaration names.\n\n## Important Pitfalls\n\n- Install `pdfkit` as well as `@types/pdfkit`; the `@types` package does not include the runtime JavaScript.\n- Import from `\"pdfkit\"`, not from `\"@types/pdfkit\"`.\n- If `compilerOptions.types` is set, keep `\"node\"` in the list or TypeScript may stop seeing the stream and buffer types that `pdfkit` uses.\n- Pipe the document to a writable destination before writing content, and call `doc.end()` when you are done so the stream can finish.\n- If you want a default import, enable `esModuleInterop`; otherwise `import PDFDocument = require(\"pdfkit\")` is the no-surprises form.\n- Keep the `pdfkit` runtime and `@types/pdfkit` on compatible releases so the declared API surface matches the runtime you execute.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/pdfkit==0.17.5`.\n- The declaration package describes the `pdfkit` module surface published through DefinitelyTyped. If your project is pinned to a substantially older or newer runtime line, verify any method differences against the PDFKit runtime documentation.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/pdfkit\n- DefinitelyTyped source for `@types/pdfkit`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/pdfkit\n- `@types/pdfkit` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/pdfkit/index.d.ts\n- PDFKit getting started guide: https://pdfkit.org/docs/getting_started.html\n- PDFKit text guide: https://pdfkit.org/docs/text.html\n- PDFKit images guide: https://pdfkit.org/docs/images.html\n"
  },
  {
    "path": "content/typescript/docs/pg/typescript/DOC.md",
    "content": "---\nname: pg\ndescription: \"TypeScript declarations for node-postgres, covering Pool and Client configuration, typed queries, transactions, notifications, and database errors.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.18.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,postgresql,pg,nodejs,sql,types,definitelytyped\"\n---\n\n# pg TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/pg` for compile-time declarations only.\n\nYour application still needs the real `pg` package at runtime. Import from `\"pg\"`, not from `\"@types/pg\"`.\n\nThe declarations cover the main `pg` APIs you use in app code: `Pool`, `Client`, `PoolClient`, `ClientConfig`, `PoolConfig`, `QueryConfig`, `QueryResult`, `QueryResultRow`, `Notification`, and `DatabaseError`.\n\n## Install\n\nInstall the runtime client first, then add TypeScript and declaration packages:\n\n```bash\nnpm install pg\nnpm install -D typescript @types/node @types/pg\n```\n\nIf your project already uses `pg`, add only the missing declarations:\n\n```bash\nnpm install -D @types/pg\n```\n\nThe package metadata for current `8.x` releases points to the `DefinitelyTyped` `types/pg` definitions and depends on `@types/node`, `pg-types`, and `pg-protocol`.\n\n## Initialization\n\n`@types/pg` does not define environment variables or credentials.\n\nIn practice, applications read their own environment variables and map them into `ClientConfig` or `PoolConfig` fields such as `connectionString`, `host`, `port`, `user`, `password`, `database`, `ssl`, `max`, `idleTimeoutMillis`, and `connectionTimeoutMillis`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient types with `compilerOptions.types`, keep `node` available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n### Define connection settings in the environment\n\nThese names are application-defined. They map cleanly to `PoolConfig` or `ClientConfig` fields.\n\n```bash\nexport DATABASE_URL=postgres://app_user:secret@127.0.0.1:5432/app_db\nexport PGPOOL_MAX=10\nexport PGPOOL_IDLE_TIMEOUT_MS=30000\nexport PGCONNECT_TIMEOUT_MS=5000\n```\n\n### Import `pg` and create a pool\n\n```typescript\nimport * as pg from \"pg\";\n\nconst connectionString = process.env.DATABASE_URL;\n\nif (!connectionString) {\n  throw new Error(\"DATABASE_URL is required\");\n}\n\nexport const pool = new pg.Pool({\n  connectionString,\n  max: Number(process.env.PGPOOL_MAX ?? \"10\"),\n  idleTimeoutMillis: Number(process.env.PGPOOL_IDLE_TIMEOUT_MS ?? \"30000\"),\n  connectionTimeoutMillis: Number(process.env.PGCONNECT_TIMEOUT_MS ?? \"5000\"),\n});\n```\n\n### Use an async password callback\n\n`ClientConfig.password` and `PoolConfig.password` accept either a string or a function that returns a string or `Promise<string>`. This is the typed integration point to use when your app fetches short-lived database credentials from another system.\n\n```typescript\nimport * as pg from \"pg\";\n\nasync function getDatabasePassword(): Promise<string> {\n  const password = process.env.PGPASSWORD;\n\n  if (!password) {\n    throw new Error(\"PGPASSWORD is required\");\n  }\n\n  return password;\n}\n\nexport const pool = new pg.Pool({\n  host: process.env.PGHOST ?? \"127.0.0.1\",\n  port: Number(process.env.PGPORT ?? \"5432\"),\n  user: process.env.PGUSER ?? \"app_user\",\n  database: process.env.PGDATABASE ?? \"app_db\",\n  password: getDatabasePassword,\n});\n```\n\n## Common Workflows\n\n### Run a typed query\n\nUse the query generic for the row shape, and optionally a second generic for the parameter tuple.\n\n```typescript\nimport * as pg from \"pg\";\n\ntype UserRow = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\nconst pool = new pg.Pool({\n  connectionString: process.env.DATABASE_URL,\n});\n\nexport async function getUser(userId: string): Promise<UserRow | null> {\n  const result = await pool.query<UserRow, [string]>(\n    `\n      select id, email, role\n      from app_user\n      where id = $1\n    `,\n    [userId],\n  );\n\n  return result.rows[0] ?? null;\n}\n```\n\n`QueryResultRow` itself is an index signature (`[column: string]: any`), so the useful TypeScript pattern is to define explicit row types at the application boundary.\n\n### Run a transaction with `PoolClient`\n\n`pool.connect()` resolves to a `PoolClient`, which adds `release()` on top of the base client query API.\n\n```typescript\nimport * as pg from \"pg\";\n\nconst pool = new pg.Pool({\n  connectionString: process.env.DATABASE_URL,\n});\n\nexport async function transferCredits(\n  fromUserId: string,\n  toUserId: string,\n  amount: number,\n): Promise<void> {\n  const client = await pool.connect();\n\n  try {\n    await client.query(\"BEGIN\");\n\n    await client.query(\n      \"update account set credits = credits - $1 where user_id = $2\",\n      [amount, fromUserId],\n    );\n\n    await client.query(\n      \"update account set credits = credits + $1 where user_id = $2\",\n      [amount, toUserId],\n    );\n\n    await client.query(\"COMMIT\");\n  } catch (error) {\n    await client.query(\"ROLLBACK\");\n    throw error;\n  } finally {\n    client.release();\n  }\n}\n```\n\n### Return tuple rows with `rowMode: \"array\"`\n\nWhen you pass a `QueryArrayConfig`, the result rows are typed as arrays instead of object maps.\n\n```typescript\nimport * as pg from \"pg\";\n\nconst pool = new pg.Pool({\n  connectionString: process.env.DATABASE_URL,\n});\n\nexport async function getUserTuple(userId: string): Promise<[string, string] | null> {\n  const result = await pool.query<[string, string], [string]>({\n    text: \"select id, email from app_user where id = $1\",\n    values: [userId],\n    rowMode: \"array\",\n  });\n\n  return result.rows[0] ?? null;\n}\n```\n\nThis is useful when you want positional tuples instead of column-name objects.\n\n### Listen for PostgreSQL notifications\n\nThe client emits a typed `notification` event with `processId`, `channel`, and optional `payload`.\n\n```typescript\nimport * as pg from \"pg\";\n\nconst client = new pg.Client({\n  connectionString: process.env.DATABASE_URL,\n});\n\nexport async function startNotificationListener(): Promise<void> {\n  await client.connect();\n\n  client.on(\"notification\", (message) => {\n    console.log(\"channel\", message.channel);\n    console.log(\"payload\", message.payload ?? \"\");\n    console.log(\"process\", message.processId);\n  });\n\n  await client.query(\"LISTEN app_events\");\n}\n```\n\n### Narrow database errors\n\n`pg` re-exports `DatabaseError` from `pg-protocol`, so you can narrow error handling without reaching into internal modules.\n\n```typescript\nimport * as pg from \"pg\";\n\nconst pool = new pg.Pool({\n  connectionString: process.env.DATABASE_URL,\n});\n\nexport async function createUser(email: string): Promise<void> {\n  try {\n    await pool.query(\"insert into app_user (email) values ($1)\", [email]);\n  } catch (error) {\n    if (error instanceof pg.DatabaseError) {\n      console.error(\"postgres error\", {\n        code: error.code,\n        detail: error.detail,\n        table: error.table,\n        constraint: error.constraint,\n      });\n    }\n\n    throw error;\n  }\n}\n```\n\n## Common Pitfalls\n\n- Install `pg` for runtime behavior; `@types/pg` only provides declarations.\n- Import from `\"pg\"`, never from `\"@types/pg\"`.\n- Treat query generics as compile-time help only; they do not validate selected columns or runtime values.\n- Prefer explicit row interfaces over raw `QueryResultRow`, which allows any column name and any value type.\n- If you set `compilerOptions.types`, keep `@types/node` active so the Node-based declarations resolve cleanly.\n- Do not import `index.d.ts`, `index.d.mts`, or other declaration files directly; let TypeScript resolve the package through `\"pg\"`.\n"
  },
  {
    "path": "content/typescript/docs/prettier/typescript/DOC.md",
    "content": "---\nname: prettier\ndescription: \"TypeScript guide for Prettier 3, including built-in types, configuration, CLI usage, and programmatic formatting without `@types/prettier`.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,prettier,formatting,code-style,types,definitelytyped\"\n---\n\n# Prettier TypeScript Guide\n\n## Golden Rule\n\nFor Prettier 3, install `prettier` and import from `\"prettier\"`.\n\n`@types/prettier@3.0.0` is not a runtime package and is not the package you should target in application code. The npm package page for `@types/prettier` exists to point users at the real `prettier` package, which ships its own TypeScript declarations.\n\nIn practice:\n\n- install `prettier`\n- remove `@types/prettier` if it is still in your project\n- import values and types from `prettier`, never from `@types/prettier`\n\n## Install\n\nInstall Prettier as a development dependency:\n\n```bash\nnpm install -D prettier typescript\n```\n\nIf your project already has the deprecated stub package, remove it:\n\n```bash\nnpm uninstall @types/prettier\n```\n\nNo authentication, API keys, service accounts, or package-specific environment variables are required.\n\n## Recommended Project Setup\n\n### Add formatter scripts\n\n```json\n{\n  \"scripts\": {\n    \"format\": \"prettier . --write\",\n    \"format:check\": \"prettier . --check\"\n  }\n}\n```\n\n`prettier . --write` rewrites matching files in place. `prettier . --check` is the safer CI command because it exits non-zero when formatting is needed.\n\n### Add a Prettier config file\n\nCreate `.prettierrc.json` in your project root:\n\n```json\n{\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}\n```\n\nPrettier will load this config automatically from the current project.\n\n### Use a normal TypeScript module setup\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nYou do not need to add `prettier` to `compilerOptions.types`. That setting is for ambient type packages such as many `@types/*` packages. Prettier exposes its declarations through the `prettier` module itself.\n\n## Import And Use Prettier In TypeScript\n\nUse the real runtime package in your imports:\n\n```typescript\nimport * as prettier from \"prettier\";\n```\n\nThis gives you both the runtime API and the package's bundled TypeScript types.\n\n### Format a TypeScript file with the project config\n\n```typescript\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport * as prettier from \"prettier\";\n\nexport async function formatFile(filePath: string): Promise<void> {\n  const input = await readFile(filePath, \"utf8\");\n  const options = (await prettier.resolveConfig(filePath)) ?? {};\n\n  const output = await prettier.format(input, {\n    ...options,\n    filepath: filePath,\n  });\n\n  if (output !== input) {\n    await writeFile(filePath, output, \"utf8\");\n  }\n}\n```\n\nPassing `filepath` lets Prettier infer the parser from the file name and extension, which is usually the safest choice for application code.\n\n### Check whether code is already formatted\n\n```typescript\nimport * as prettier from \"prettier\";\n\nexport async function isFormatted(source: string, filePath: string): Promise<boolean> {\n  const options = (await prettier.resolveConfig(filePath)) ?? {};\n\n  return prettier.check(source, {\n    ...options,\n    filepath: filePath,\n  });\n}\n```\n\nThis is useful in pre-commit hooks, CI checks, and custom build tooling.\n\n### Reuse Prettier's option types from the runtime package\n\n```typescript\nimport * as prettier from \"prettier\";\n\ntype FormatOptions = Parameters<typeof prettier.format>[1];\n\nconst baseOptions: FormatOptions = {\n  singleQuote: true,\n  trailingComma: \"all\",\n};\n\nexport async function formatSnippet(source: string): Promise<string> {\n  return prettier.format(source, {\n    ...baseOptions,\n    parser: \"typescript\",\n  });\n}\n```\n\nThis pattern is useful when you want local type safety without depending on a separate `@types` package.\n\n## Common Workflows\n\n### Run Prettier from the CLI\n\nFormat the whole project:\n\n```bash\nnpx prettier . --write\n```\n\nCheck formatting without rewriting files:\n\n```bash\nnpx prettier . --check\n```\n\nFormat one TypeScript file explicitly:\n\n```bash\nnpx prettier src/index.ts --write\n```\n\n### Use Prettier in Node-based tooling\n\nIf your app generates source files, call Prettier before writing them to disk:\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport * as prettier from \"prettier\";\n\nexport async function writeGeneratedModule(filePath: string, source: string): Promise<void> {\n  const output = await prettier.format(source, {\n    filepath: filePath,\n  });\n\n  await writeFile(filePath, output, \"utf8\");\n}\n```\n\nUsing `filepath` keeps generated `.ts`, `.tsx`, `.json`, and other supported files aligned with Prettier's parser inference.\n\n## Important Pitfalls\n\n- Do not import from `@types/prettier`; import from `prettier`.\n- Do not keep `@types/prettier` in `devDependencies` for a Prettier 3 setup unless you have a very specific legacy constraint.\n- Use `await prettier.format(...)` and `await prettier.resolveConfig(...)` in Prettier 3 code.\n- Prefer `filepath` when formatting files so Prettier can infer the correct parser from the extension.\n- If your project restricts `compilerOptions.types`, that does not replace importing from `prettier`; the module's own declarations are still the source of truth.\n\n## Version Notes\n\n- This guide targets `@types/prettier==3.0.0`.\n- For this version, the practical recommendation from the maintainer package page is to use `prettier`'s bundled type definitions instead of installing `@types/prettier`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/prettier\n- https://www.npmjs.com/package/prettier\n- https://prettier.io/docs/install.html\n- https://prettier.io/docs/api/\n- https://prettier.io/docs/configuration\n"
  },
  {
    "path": "content/typescript/docs/prismjs/typescript/DOC.md",
    "content": "---\nname: prismjs\ndescription: \"TypeScript declarations for PrismJS syntax-highlighting APIs, grammars, hooks, and browser integration\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.26.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,prismjs,syntax-highlighting,types,definitelytyped\"\n---\n\n# PrismJS TypeScript Guide\n\n`@types/prismjs` provides TypeScript declarations for the `prismjs` runtime package.\n\nThis package only adds `.d.ts` files. Install `prismjs` separately for the actual syntax-highlighting runtime, language components, plugins, and theme CSS.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install prismjs\nnpm install --save-dev typescript @types/prismjs@1.26.6\n```\n\nNo package-specific environment variables, credentials, or client initialization are required.\n\n## TypeScript Setup\n\nIn most projects, installing `@types/prismjs` is enough.\n\nOnly add `prismjs` to `compilerOptions.types` if your project already restricts which declaration packages TypeScript loads:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"prismjs\"]\n  }\n}\n```\n\nThese declarations model PrismJS as a CommonJS `export =` module, so the most portable import form is:\n\n```ts\nimport Prism = require(\"prismjs\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport Prism from \"prismjs\";\n```\n\nDo not import from `@types/prismjs` directly in application code.\n\n## Highlight A String\n\nUse `Prism.highlight()` when you already know which grammar to apply.\n\nThe default `prismjs` entry includes the core bundle plus the default grammars listed in the runtime component manifest: `markup`, `css`, `clike`, and `javascript`.\n\n```ts\nimport Prism = require(\"prismjs\");\n\nconst source = `const total = items.reduce((sum, item) => sum + item.price, 0);`;\nconst html = Prism.highlight(source, Prism.languages.javascript, \"javascript\");\n\nconsole.log(html);\n```\n\n`Prism.highlight()` returns the highlighted HTML string. Use it for server rendering, template output, or static-site generation.\n\n## Load Additional Languages\n\nLanguages outside the default bundle come from PrismJS runtime components. For example, TypeScript is provided by the `prism-typescript` component, not by the main `prismjs` entry.\n\nUse the runtime loader to add the extra grammars you need before calling `highlight()` or `highlightElement()`:\n\n```ts\nimport Prism = require(\"prismjs\");\nimport loadLanguages = require(\"prismjs/components/\");\n\nloadLanguages([\"typescript\"]);\n\nconst source = `const ready: boolean = true;`;\nconst html = Prism.highlight(source, Prism.languages.typescript, \"typescript\");\n\nconsole.log(html);\n```\n\nThe loader accepts a single language id, an array of ids, or no argument to load all available languages.\n\n## Highlight Browser Code Blocks\n\nFor browser use, load a theme stylesheet from the runtime package, load any non-default languages you need, then highlight the matching elements.\n\n```ts\nimport Prism = require(\"prismjs\");\nimport loadLanguages = require(\"prismjs/components/\");\nimport \"prismjs/themes/prism.css\";\n\nloadLanguages([\"typescript\"]);\n\ndocument\n  .querySelectorAll<HTMLElement>(\"pre code.language-typescript\")\n  .forEach((element) => {\n    Prism.highlightElement(element);\n  });\n```\n\nYour HTML needs a Prism language class on the `<code>` element, for example:\n\n```html\n<pre><code class=\"language-typescript\">const ready: boolean = true;</code></pre>\n```\n\nIf you want Prism to scan the whole document, call `Prism.highlightAll()` instead:\n\n```ts\nimport Prism = require(\"prismjs\");\n\nPrism.highlightAll();\n```\n\n## Tokenize Code And Inspect Tokens\n\nUse `Prism.tokenize()` when you need the parsed token stream instead of the final HTML string.\n\n```ts\nimport Prism = require(\"prismjs\");\n\nconst tokens = Prism.tokenize(\n  \"const answer = 42;\",\n  Prism.languages.javascript,\n);\n\nfor (const token of tokens) {\n  if (token instanceof Prism.Token && token.type === \"number\") {\n    console.log(token.content);\n  }\n}\n```\n\nThis is the most useful low-level API when you want to inspect or transform highlighted output before rendering it.\n\n## Extend Or Patch A Grammar\n\nUse `Prism.languages.extend()` to clone an existing grammar and add new tokens, or `Prism.languages.insertBefore()` to control token order in an existing grammar.\n\n```ts\nimport Prism = require(\"prismjs\");\n\nPrism.languages.todoJavascript = Prism.languages.extend(\"javascript\", {\n  \"todo-comment\": /\\/\\/\\s*TODO:.*/,\n});\n\nPrism.languages.insertBefore(\"javascript\", \"keyword\", {\n  decorator: {\n    pattern: /@\\w+/,\n    alias: \"function\",\n  },\n});\n```\n\n`insertBefore()` returns the new grammar object after the insertion, which is useful when you want to keep a reference to the updated grammar.\n\n## Customize Output With Hooks\n\nUse `Prism.hooks.add()` to modify tokens or generated markup during highlighting.\n\n```ts\nimport Prism = require(\"prismjs\");\n\nPrism.hooks.add(\"wrap\", (env) => {\n  if (env.type === \"keyword\") {\n    env.classes.push(\"token-keyword-emphasis\");\n  }\n});\n\nconst html = Prism.highlight(\n  \"return true;\",\n  Prism.languages.javascript,\n  \"javascript\",\n);\n\nconsole.log(html);\n```\n\nHooks run synchronously in registration order.\n\n## Important Pitfalls\n\n- `@types/prismjs` is a declaration package only. Install `prismjs` separately for the runtime.\n- Import from `\"prismjs\"`, not from `\"@types/prismjs\"`.\n- If your project restricts `compilerOptions.types`, include `\"prismjs\"` there or TypeScript will not load the declarations.\n- The main `prismjs` entry does not include every grammar. Load non-default languages such as `typescript` before using `Prism.languages.typescript` or `Prism.highlight(..., ..., \"typescript\")`.\n- `Prism.highlight()` throws when the requested language has no loaded grammar.\n- Browser styling comes from the runtime package's theme CSS, not from `@types/prismjs`.\n- `Prism.manual` has to be set before Prism executes if you want to disable the automatic browser highlighting pass.\n\n## Version Notes\n\n- This guide targets `@types/prismjs==1.26.6`.\n- The declaration package tracks the PrismJS 1.x runtime API surface. Keep `prismjs` and `@types/prismjs` aligned closely enough that the declarations match the runtime features you call.\n- The PrismJS runtime package version `1.30.0` still publishes `main: \"prism.js\"` without a `types` field in `package.json`, so TypeScript projects still rely on `@types/prismjs` for static typing.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/prismjs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/prismjs\n- https://www.npmjs.com/package/prismjs\n- https://github.com/PrismJS/prism\n- https://prismjs.com/docs/prism\n"
  },
  {
    "path": "content/typescript/docs/prop-types/typescript/DOC.md",
    "content": "---\nname: prop-types\ndescription: \"TypeScript declarations for the prop-types runtime package, including validators, inferred prop shapes, and manual runtime checks\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"15.7.15\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,prop-types,react,validation,types,definitelytyped\"\n---\n\n# prop-types TypeScript Guide\n\n`@types/prop-types` provides the TypeScript declarations for the `prop-types` runtime package. Use it when your project defines `propTypes` on React components or calls `PropTypes.checkPropTypes()` for runtime validation outside React.\n\nThis package only ships `.d.ts` files. Install the `prop-types` runtime separately.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install prop-types\nnpm install --save-dev typescript @types/prop-types\n```\n\n`@types/prop-types@15.7.15` declares `typeScriptVersion: \"5.1\"`, so use TypeScript 5.1 or newer.\n\nNo environment variables, credentials, or client initialization are required.\n\n## Import `prop-types` In TypeScript\n\nThe declaration file uses `export = PropTypes`, so the configuration-independent import form is:\n\n```ts\nimport PropTypes = require(\"prop-types\");\n```\n\nIf your `tsconfig.json` enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport PropTypes from \"prop-types\";\n```\n\nIf your project restricts `compilerOptions.types`, include `prop-types` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"prop-types\"]\n  }\n}\n```\n\n## Define `propTypes` For A Typed Component\n\nUse `PropTypes.ValidationMap<Props>` to keep your runtime validators aligned with your TypeScript props type.\n\n```tsx\nimport PropTypes = require(\"prop-types\");\n\ntype BannerProps = {\n  title: string;\n  tone?: \"info\" | \"warning\";\n  dismissible?: boolean;\n};\n\nexport function Banner({\n  title,\n  tone = \"info\",\n  dismissible = false,\n}: BannerProps) {\n  return (\n    <section data-tone={tone} data-dismissible={dismissible}>\n      {title}\n    </section>\n  );\n}\n\nBanner.propTypes = {\n  title: PropTypes.string.isRequired,\n  tone: PropTypes.oneOf([\"info\", \"warning\"] as const),\n  dismissible: PropTypes.bool,\n} satisfies PropTypes.ValidationMap<BannerProps>;\n```\n\nThis is the most practical integration boundary for mixed TypeScript and PropTypes codebases: TypeScript checks the static `BannerProps` shape, while `prop-types` still validates values at runtime in development.\n\n## Infer A Props Type From A Validator Map\n\nThe type package exposes `PropTypes.InferProps<T>` so you can derive a TypeScript type from a validator object.\n\n```ts\nimport PropTypes = require(\"prop-types\");\n\nconst cardPropTypes = {\n  id: PropTypes.string.isRequired,\n  count: PropTypes.number,\n  tags: PropTypes.arrayOf(PropTypes.string).isRequired,\n  owner: PropTypes.exact({\n    name: PropTypes.string.isRequired,\n    active: PropTypes.bool,\n  }).isRequired,\n};\n\ntype CardProps = PropTypes.InferProps<typeof cardPropTypes>;\n\nconst exampleCard: CardProps = {\n  id: \"card_123\",\n  tags: [\"featured\", \"pinned\"],\n  owner: {\n    name: \"Ada\",\n    active: true,\n  },\n};\n```\n\n`InferProps` treats validators with `.isRequired` as required properties and other validators as optional properties.\n\n## Use Nested Validators\n\nThe declarations cover the standard validator helpers exported by the runtime package, including `arrayOf`, `objectOf`, `oneOf`, `oneOfType`, `shape`, `exact`, `element`, `elementType`, `instanceOf`, and `node`.\n\n```tsx\nimport PropTypes = require(\"prop-types\");\n\nclass Message {\n  constructor(public text: string) {}\n}\n\nconst feedPropTypes = {\n  items: PropTypes.arrayOf(\n    PropTypes.shape({\n      id: PropTypes.string.isRequired,\n      message: PropTypes.instanceOf(Message).isRequired,\n    }).isRequired,\n  ).isRequired,\n  layout: PropTypes.oneOf([\"grid\", \"list\"] as const),\n  footer: PropTypes.node,\n  as: PropTypes.elementType,\n};\n\ntype FeedProps = PropTypes.InferProps<typeof feedPropTypes>;\n```\n\nUse `shape()` when extra object properties are acceptable, and `exact()` when you want runtime warnings for extra properties.\n\n## Validate Plain Objects Outside React\n\nThe runtime package documents `PropTypes.checkPropTypes()` for manual validation. The type declarations include that API too.\n\n```ts\nimport PropTypes = require(\"prop-types\");\n\nconst searchOptionsPropTypes = {\n  query: PropTypes.string.isRequired,\n  page: PropTypes.number,\n  mode: PropTypes.oneOf([\"all\", \"open\"] as const),\n};\n\nconst input = {\n  query: \"status:active\",\n  page: \"1\",\n  mode: \"all\",\n};\n\nPropTypes.checkPropTypes(\n  searchOptionsPropTypes,\n  input,\n  \"prop\",\n  \"SearchOptions\",\n);\n```\n\nDo not call validator functions directly such as `PropTypes.string(...)`. The runtime package documents that direct validator calls are not supported; use `checkPropTypes()` for manual checks.\n\n## Reset Cached Warnings In Tests\n\n`PropTypes.checkPropTypes()` only reports a given warning once. In tests, reset that cache between cases when you need to assert repeated failures.\n\n```ts\nimport PropTypes = require(\"prop-types\");\n\nbeforeEach(() => {\n  PropTypes.resetWarningCache();\n});\n```\n\n## React 19 Migration Helper Types\n\nThe declarations expose both `ValidationMap<T>` and `WeakValidationMap<T>`. The package comments describe `WeakValidationMap<T>` as a migration path because React 19 removed that type from React itself.\n\n```ts\nimport PropTypes = require(\"prop-types\");\n\ntype LegacyProps = {\n  title?: string | null;\n  count: number;\n};\n\nconst legacyPropTypes: PropTypes.WeakValidationMap<LegacyProps> = {\n  title: PropTypes.string,\n  count: PropTypes.number.isRequired,\n};\n```\n\nUse `ValidationMap<T>` for new component props. Reach for `WeakValidationMap<T>` when you are matching older React prop-type patterns where `null`, `undefined`, and optional properties are intentionally treated the same.\n\n## Common Pitfalls\n\n- Install `prop-types` as well as `@types/prop-types`; the `@types` package has no runtime JavaScript.\n- Prefer `import PropTypes = require(\"prop-types\")` unless your compiler is already configured for default-import interop.\n- If your `tsconfig.json` uses `compilerOptions.types`, include `prop-types` there or the declarations will not load.\n- `@types/prop-types@15.7.15` does not declare `PropTypes.bigint`, even though newer `prop-types` runtime documentation includes that validator.\n- Do not call validators directly. Use `propTypes` on a component or `PropTypes.checkPropTypes()` for manual validation.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/prop-types\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/prop-types\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/prop-types/index.d.ts\n- https://www.npmjs.com/package/prop-types\n- https://github.com/facebook/prop-types/blob/main/README.md\n"
  },
  {
    "path": "content/typescript/docs/pug/typescript/DOC.md",
    "content": "---\nname: pug\ndescription: \"TypeScript declarations for the `pug` template engine, including typed imports for template compilation and rendering helpers.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.0.10\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,pug,templates,node,types,definitelytyped\"\n---\n\n# Pug TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/pug` alongside the real `pug` runtime package.\n\n`@types/pug` only provides TypeScript declarations. Your application imports and runs `pug`; the declaration package adds types for the module import and the main template compilation and rendering helpers.\n\n## Install\n\nInstall the runtime package first, then add the declaration package and Node.js types for file-path helpers and Node-based template rendering code.\n\n```bash\nnpm install pug\nnpm install -D typescript @types/pug @types/node\n```\n\nIf your project already depends on `pug`, add only the missing declarations:\n\n```bash\nnpm install -D @types/pug @types/node\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup points are your import style, your TypeScript compiler options, and how you type the locals objects you pass into templates.\n\n### Import `pug`\n\nThe declaration package models the CommonJS `pug` module export. The safest import form is:\n\n```typescript\nimport pug = require(\"pug\");\n\nconst html = pug.render(\"p Hello #{name}\", { name: \"Ada\" });\n```\n\nWith `esModuleInterop` or `allowSyntheticDefaultImports`, you can use a default import:\n\n```typescript\nimport pug from \"pug\";\n\nconst html = pug.render(\"p Hello #{name}\", { name: \"Ada\" });\n```\n\nImport from `pug`, not from `@types/pug`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you prefer `import pug = require(\"pug\")`, you do not need `esModuleInterop` for this package.\n\n## Common Workflows\n\n### Render a small inline template\n\nUse `render()` when the template source is already in memory.\n\n```typescript\nimport pug from \"pug\";\n\nconst html = pug.render(\"h1= title\\np Welcome, #{userName}\", {\n  title: \"Dashboard\",\n  userName: \"Ada\",\n});\n\nconsole.log(html);\n```\n\n### Compile once and wrap with app-specific locals types\n\nThe declaration package does not infer your template locals from the `.pug` file. Define the locals shape in your application code and wrap the compiled template with that type.\n\n```typescript\nimport pug from \"pug\";\nimport { join } from \"node:path\";\n\ntype ProfileLocals = {\n  title: string;\n  user: {\n    name: string;\n    email: string;\n  };\n};\n\nconst template = pug.compileFile(join(process.cwd(), \"views\", \"profile.pug\"));\n\nexport function renderProfile(locals: ProfileLocals) {\n  return template(locals);\n}\n```\n\n### Pass `filename` when a string template uses `include` or `extends`\n\nRelative template references are resolved from `filename`. When you render or compile a template string that uses `include` or `extends`, pass a real filename.\n\n```typescript\nimport pug from \"pug\";\nimport { join } from \"node:path\";\n\nconst filename = join(process.cwd(), \"views\", \"page.pug\");\n\nconst html = pug.render(\n  `extends ./layout.pug\nblock content\n  p Hello`,\n  { filename },\n);\n```\n\n### Render a file directly\n\nUse `renderFile()` when you already have a `.pug` file path and want the final HTML string in one call.\n\n```typescript\nimport pug from \"pug\";\nimport { join } from \"node:path\";\n\nconst html = pug.renderFile(join(process.cwd(), \"views\", \"email.pug\"), {\n  subject: \"Password reset\",\n  resetUrl: \"https://example.com/reset/abc123\",\n});\n```\n\n### Use Pug with Express\n\nExpress uses the runtime `pug` package as the view engine. `@types/pug` matters when your code imports `pug` directly or your toolchain resolves the module's TypeScript declarations.\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n\napp.set(\"view engine\", \"pug\");\napp.set(\"views\", \"views\");\n\napp.get(\"/\", (_req, res) => {\n  res.render(\"index\", { title: \"Home\" });\n});\n```\n\n## Common Pitfalls\n\n- Install `pug`; `@types/pug` does not include the template engine runtime.\n- Import from `pug`, never from `@types/pug`.\n- If `import pug from \"pug\"` fails, enable `esModuleInterop` or switch to `import pug = require(\"pug\")`.\n- When a string template uses `include` or `extends`, pass `filename` or the relative lookup base is missing.\n- Define your own locals type in app code. The declarations do not infer the variable names used inside a `.pug` template.\n- Resolve template file paths explicitly with `node:path` in CLIs, tests, and monorepos instead of assuming the current working directory is always correct.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/pug\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/pug\n- https://pugjs.org/api/getting-started.html\n- https://pugjs.org/api/reference.html\n"
  },
  {
    "path": "content/typescript/docs/puppeteer/typescript/DOC.md",
    "content": "---\nname: puppeteer\ndescription: \"TypeScript guidance for `puppeteer`, including how to handle `@types/puppeteer@7.0.4` in legacy projects, import the runtime package correctly, and use typed browser and page workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.0.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,puppeteer,browser,automation,types,definitelytyped,npm\"\n---\n\n# Puppeteer TypeScript Guide\n\n## Golden Rule\n\nApplication code imports from `puppeteer`, not from `@types/puppeteer`.\n\n`@types/puppeteer` is only a declaration package. The runtime integration boundary is the `puppeteer` package that you actually install and execute. Current Puppeteer package metadata also publishes a `types` entry, so new projects should start from `puppeteer` itself and only keep `@types/puppeteer@7.0.4` when you are maintaining an older dependency tree that still expects it.\n\nIn practice:\n\n- install `puppeteer`\n- import from `\"puppeteer\"`\n- add `typescript` and `@types/node` for a normal Node.js TypeScript app\n- if a legacy project already pins `@types/puppeteer@7.0.4`, leave your imports unchanged and keep using `puppeteer` as the runtime package\n\n## Install\n\nFor a current TypeScript project, install the runtime package and your TypeScript toolchain:\n\n```bash\nnpm install puppeteer\nnpm install -D typescript @types/node\n```\n\nThe Puppeteer README notes that `puppeteer` downloads a compatible Chrome during installation.\n\nIf you must keep the legacy declaration package in an older codebase, add it as a development dependency:\n\n```bash\nnpm install -D @types/puppeteer@7.0.4\n```\n\nIf your environment provides its own browser binary, skip the bundled browser download during install:\n\n```bash\nPUPPETEER_SKIP_DOWNLOAD=1 npm install puppeteer\n```\n\nNo API keys or service credentials are required.\n\n## Initialization\n\nThe important setup points are:\n\n- import from `puppeteer`\n- keep Node.js types available if you use `process.env`\n- choose whether Puppeteer should use its downloaded browser or a browser executable you provide\n\n### Import from `puppeteer`\n\nUse the runtime package for both values and type-only imports:\n\n```typescript\nimport puppeteer, {\n  type Browser,\n  type LaunchOptions,\n  type Page,\n} from \"puppeteer\";\n```\n\nDo not import anything from `@types/puppeteer`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\"]\n  }\n}\n```\n\nYou do not need to add `puppeteer` to `compilerOptions.types`. TypeScript reads its declarations from the imported runtime package.\n\n### Optional environment variables\n\nPuppeteer supports environment-based browser configuration.\n\n```bash\nexport PUPPETEER_EXECUTABLE_PATH=\"/path/to/chrome-or-chromium\"\nexport PUPPETEER_SKIP_DOWNLOAD=1\n```\n\n`PUPPETEER_EXECUTABLE_PATH` points Puppeteer at a browser binary you manage yourself. In current Puppeteer configuration, setting `PUPPETEER_EXECUTABLE_PATH` also causes download skipping unless you override it.\n\n## Common Workflows\n\n### Launch a browser with typed `Browser` and `Page` handles\n\nUse `puppeteer.launch()` to create a browser, then open pages from that browser instance.\n\n```typescript\nimport puppeteer, { type Browser, type Page } from \"puppeteer\";\n\nexport async function openHomePage(url: string): Promise<string> {\n  const browser: Browser = await puppeteer.launch({\n    headless: true,\n  });\n\n  try {\n    const page: Page = await browser.newPage();\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n    return await page.title();\n  } finally {\n    await browser.close();\n  }\n}\n```\n\nThis is the normal TypeScript boundary: `Browser` owns lifecycle, and `Page` exposes navigation, DOM interaction, screenshots, PDF generation, and evaluation APIs.\n\n### Centralize launch configuration with `LaunchOptions`\n\nType reusable launch settings with `LaunchOptions`, especially when your app optionally uses a system browser.\n\n```typescript\nimport puppeteer, {\n  type Browser,\n  type LaunchOptions,\n} from \"puppeteer\";\n\nfunction createLaunchOptions(): LaunchOptions {\n  return {\n    headless: true,\n    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,\n  };\n}\n\nexport async function createBrowser(): Promise<Browser> {\n  return await puppeteer.launch(createLaunchOptions());\n}\n```\n\nUsing `process.env.PUPPETEER_EXECUTABLE_PATH || undefined` avoids passing an empty string into `executablePath`.\n\n### Wait for elements and extract typed page data\n\nThe most common scraping or automation flow is: navigate, wait for a selector, then read structured data from the DOM.\n\n```typescript\nimport puppeteer, { type Page } from \"puppeteer\";\n\ntype ProductCard = {\n  title: string;\n  price: string;\n};\n\nexport async function readProducts(page: Page): Promise<ProductCard[]> {\n  await page.waitForSelector(\".product-card\", {\n    visible: true,\n    timeout: 30_000,\n  });\n\n  return await page.$$eval(\".product-card\", (cards) => {\n    return cards.map((card) => {\n      const title = card.querySelector(\"h2\")?.textContent?.trim() ?? \"\";\n      const price = card.querySelector(\".price\")?.textContent?.trim() ?? \"\";\n\n      return { title, price };\n    });\n  });\n}\n```\n\n`waitForSelector()` is the right place to express visibility and timeout rules. `$$eval()` is a practical way to return plain serializable data instead of leaking DOM types back into Node.js code.\n\n### Reuse a typed page helper in test or worker code\n\nAccept `Page` as an argument when you want helper functions that work in scripts, jobs, or test runners.\n\n```typescript\nimport { type Page } from \"puppeteer\";\n\nexport async function login(page: Page, email: string, password: string): Promise<void> {\n  await page.goto(\"https://example.com/login\", { waitUntil: \"networkidle2\" });\n  await page.type('input[name=\"email\"]', email);\n  await page.type('input[name=\"password\"]', password);\n  await page.click('button[type=\"submit\"]');\n  await page.waitForSelector(\"[data-test='account-home']\", {\n    visible: true,\n  });\n}\n```\n\nThis keeps your automation helpers easy to compose without hiding the real Puppeteer page object behind an untyped wrapper.\n\n## Important Pitfalls\n\n- Do not import from `@types/puppeteer`; import from `puppeteer`.\n- Treat `@types/puppeteer@7.0.4` as a compile-time package only. It does not provide browser automation at runtime.\n- For new projects, check the `puppeteer` package you actually install before keeping an extra `@types/puppeteer` dependency; current Puppeteer releases publish their own `types` entry.\n- `puppeteer` downloads a browser by default during installation. If you skip the download, also provide a usable browser executable.\n- `waitForSelector()` can time out or resolve only after the element becomes available. Keep explicit timeout and visibility settings in code that depends on DOM readiness.\n- If your project restricts ambient type packages with `compilerOptions.types`, include `node` when you reference `process.env` in launch configuration.\n\n## Minimal End-to-End Example\n\n```typescript\nimport puppeteer, {\n  type Browser,\n  type LaunchOptions,\n  type Page,\n} from \"puppeteer\";\n\ntype SearchResult = {\n  title: string;\n  href: string;\n};\n\nfunction getLaunchOptions(): LaunchOptions {\n  return {\n    headless: true,\n    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,\n  };\n}\n\nexport async function fetchFirstResults(url: string): Promise<SearchResult[]> {\n  const browser: Browser = await puppeteer.launch(getLaunchOptions());\n\n  try {\n    const page: Page = await browser.newPage();\n\n    await page.setViewport({ width: 1280, height: 800 });\n    await page.goto(url, { waitUntil: \"networkidle2\" });\n    await page.waitForSelector(\"a\", { visible: true, timeout: 30_000 });\n\n    return await page.$$eval(\"a\", (anchors) => {\n      return anchors.slice(0, 5).map((anchor) => ({\n        title: anchor.textContent?.trim() ?? \"\",\n        href: anchor.getAttribute(\"href\") ?? \"\",\n      }));\n    });\n  } finally {\n    await browser.close();\n  }\n}\n```\n\nThis example shows the practical TypeScript boundary for Puppeteer projects:\n\n- environment-aware launch options\n- `Browser` and `Page` type imports from the runtime package\n- explicit DOM waiting\n- returning plain JSON-safe data from page evaluation\n\n## Version Note\n\nThis guide is written for the `@types/puppeteer` `7.0.4` package entry on npm.\n\nFor that package entry, the practical rules are:\n\n- your code still imports from `puppeteer`\n- the declaration package is only for compile-time typing\n- current Puppeteer releases publish their own `types` entry, so avoid duplicate type-package installs in new projects unless you are intentionally maintaining a legacy dependency set\n"
  },
  {
    "path": "content/typescript/docs/qs/typescript/DOC.md",
    "content": "---\nname: qs\ndescription: \"TypeScript declarations for the qs querystring parser, including typed parse and stringify options, recursive ParsedQs results, and CommonJS import patterns.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"6.15.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,qs,querystring,urlencoded,npm,types\"\n---\n\n# qs TypeScript Guide\n\n`@types/qs` provides the TypeScript declarations for the `qs` runtime package. Use it when your application needs to parse or build nested query strings such as `filter[status]=open`, repeated keys for arrays, or dot-notation query keys.\n\nThis package only ships `.d.ts` files. It does not install the `qs` runtime.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install qs\nnpm install --save-dev typescript @types/qs\n```\n\nNo environment variables, authentication, or client initialization are required.\n\n## Import `qs` In TypeScript\n\nThe declaration file uses `export = QueryString`, so the configuration-independent import style is:\n\n```ts\nimport qs = require(\"qs\");\n```\n\nImport from `\"qs\"`, not from `\"@types/qs\"`.\n\n## Parse Query Strings As `qs.ParsedQs`\n\nThe default `parse()` overload returns `qs.ParsedQs`, a recursive object shape where each property can be:\n\n- `undefined`\n- `string`\n- another `qs.ParsedQs`\n- an array of `string | qs.ParsedQs`\n\nThat means application code usually needs to narrow values before treating them as plain strings.\n\n```ts\nimport qs = require(\"qs\");\n\ntype ParsedValue = undefined | string | qs.ParsedQs | (string | qs.ParsedQs)[];\n\nfunction readFirstString(value: ParsedValue): string | undefined {\n  if (typeof value === \"string\") {\n    return value;\n  }\n\n  if (Array.isArray(value)) {\n    return value.find((item): item is string => typeof item === \"string\");\n  }\n\n  return undefined;\n}\n\nconst query = qs.parse(\"?page=2&filter[status]=open&tag=typescript&tag=agents\", {\n  ignoreQueryPrefix: true,\n  duplicates: \"combine\",\n});\n\nconst page = Number(readFirstString(query.page) ?? \"1\");\nconst firstTag = readFirstString(query.tag);\n\nconst tags = Array.isArray(query.tag)\n  ? query.tag.filter((item): item is string => typeof item === \"string\")\n  : firstTag\n    ? [firstTag]\n    : [];\n\nconst filter = query.filter;\nconst status =\n  filter\n  && !Array.isArray(filter)\n  && typeof filter !== \"string\"\n  && typeof filter.status === \"string\"\n    ? filter.status\n    : \"all\";\n\nconsole.log({ page, status, tags });\n```\n\nBy default, `qs` does not coerce numbers, booleans, or `null`. Parsed values stay as strings unless you add your own conversion step.\n\n## Use Bounded Parse Options For Untrusted Input\n\nWhen you parse user-controlled query strings or `application/x-www-form-urlencoded` bodies, prefer explicit limits.\n\n```ts\nimport qs = require(\"qs\");\n\nconst parsed = qs.parse(\"filters[owner]=alice&filters[tag]=docs&ids[]=1&ids[]=2\", {\n  depth: 3,\n  strictDepth: true,\n  parameterLimit: 50,\n  arrayLimit: 20,\n  throwOnLimitExceeded: true,\n  plainObjects: true,\n});\n\nconsole.log(parsed);\n```\n\nPractical notes:\n\n- `depth`, `parameterLimit`, and `arrayLimit` help bound parser work on untrusted input.\n- `throwOnLimitExceeded: true` turns silent truncation into a normal error path you can handle.\n- `plainObjects: true` returns null-prototype objects, so methods such as `hasOwnProperty` are not present on parsed objects.\n- `allowPrototypes` exists, but the runtime README warns that enabling it is generally a bad idea.\n\n## Stringify Nested Objects For Requests\n\nUse `stringify()` when you need stable query strings for fetch calls, SDK clients, or server-side redirects.\n\n```ts\nimport qs = require(\"qs\");\n\nconst queryString = qs.stringify(\n  {\n    filter: { status: \"open\", owner: \"alice\" },\n    tag: [\"typescript\", \"agents\"],\n    includeArchived: false,\n  },\n  {\n    addQueryPrefix: true,\n    allowDots: true,\n    arrayFormat: \"repeat\",\n    encodeValuesOnly: true,\n  }\n);\n\nconsole.log(queryString);\n// ?filter.status=open&filter.owner=alice&tag=typescript&tag=agents&includeArchived=false\n```\n\nThe typed `arrayFormat` values are:\n\n- `\"indices\"`\n- `\"brackets\"`\n- `\"repeat\"`\n- `\"comma\"`\n\nUse `allowDots: true` when the receiving API expects dotted keys such as `filter.status=open` instead of bracket syntax.\n\n## Type Option Objects With `qs.IParseOptions` And `qs.IStringifyOptions`\n\nIf you keep parser settings in shared config, type them directly from the package.\n\n```ts\nimport qs = require(\"qs\");\n\nconst parseOptions = {\n  allowDots: true,\n  decodeDotInKeys: true,\n  ignoreQueryPrefix: true,\n  duplicates: \"combine\",\n} satisfies qs.IParseOptions<true>;\n\nconst stringifyOptions = {\n  allowDots: true,\n  encodeDotInKeys: true,\n  arrayFormat: \"repeat\",\n  addQueryPrefix: true,\n} satisfies qs.IStringifyOptions<true>;\n\nconst parsed = qs.parse(\"name%252Eobj.first=John\", parseOptions);\nconst serialized = qs.stringify({ \"name.obj\": { first: \"John\" } }, stringifyOptions);\n\nconsole.log(parsed, serialized);\n```\n\nThe generic parameter matters when you use `decodeDotInKeys` or `encodeDotInKeys`. Those options are only enabled in the declaration types when `allowDots` is typed as `true`.\n\n## Custom Decoders Widen The Return Type\n\nIf you pass a custom `decoder`, the return type widens from `qs.ParsedQs` to `{ [key: string]: unknown }` because your decoder can return any value.\n\n```ts\nimport qs = require(\"qs\");\n\nconst parsed = qs.parse(\"enabled=true&count=2\", {\n  decoder(str, defaultDecoder, charset, type) {\n    const value = defaultDecoder(str, defaultDecoder, charset);\n\n    if (type === \"value\" && value === \"true\") {\n      return true;\n    }\n\n    if (type === \"value\" && value === \"false\") {\n      return false;\n    }\n\n    return value;\n  },\n});\n\nconst enabled = parsed.enabled;\n\nif (typeof enabled !== \"boolean\") {\n  throw new Error(\"enabled must be a boolean\");\n}\n```\n\nThis is the main type boundary in advanced `qs` usage: once you customize decoding, validate or narrow the result before using it as application data.\n\n## Common Pitfalls\n\n- Install `qs` as well as `@types/qs`; the type package does not include runtime code.\n- Import from `\"qs\"`, not from `\"@types/qs\"`.\n- The declaration file uses CommonJS `export =`; `import qs = require(\"qs\")` works without TypeScript interop flags.\n- `qs.parse()` keeps primitive-looking values as strings by default.\n- `plainObjects: true` returns null-prototype objects, so instance methods are unavailable on parsed values.\n- Using a custom `decoder` widens the parse result to `unknown` values that you must narrow yourself.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/qs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/qs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/qs/index.d.ts\n- https://www.npmjs.com/package/qs\n- https://github.com/ljharb/qs\n- https://github.com/ljharb/qs/blob/main/README.md\n"
  },
  {
    "path": "content/typescript/docs/react/typescript/DOC.md",
    "content": "---\nname: react\ndescription: \"TypeScript declarations for React components, JSX, hooks, refs, and release-channel entry points.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"19.2.14\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,jsx,hooks,refs,types,definitelytyped\"\n---\n\n# React TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react` alongside the real `react` runtime package. `@types/react` only provides TypeScript declarations; it does not include the React runtime.\n\nFor browser apps, keep `react`, `react-dom`, `@types/react`, and `@types/react-dom` on the same React major line so JSX, refs, DOM props, and renderer-specific types stay compatible.\n\n## Install\n\nInstall the runtime first. Add `react-dom` only when this project renders to the DOM.\n\n```bash\nnpm install react\nnpm install -D typescript @types/react\n\n# Browser apps\nnpm install react-dom\nnpm install -D @types/react-dom\n```\n\nIf your app already depends on `react`, add only the missing type package:\n\n```bash\nnpm install -D @types/react\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nTypeScript picks up `@types/react` automatically once it is installed.\n\n### Browser JSX projects\n\nFor a normal browser app, make sure your compiler is set up for JSX and DOM types:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\n`@types/react` exports `react/jsx-runtime` and `react/jsx-dev-runtime`, which are the type entry points used by the automatic JSX runtime.\n\n### If you restrict `compilerOptions.types`\n\nIf your project uses `compilerOptions.types`, include `react` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\nOmit `react-dom` in React Native or other non-DOM projects.\n\n### DOM-less projects\n\nThe package also includes empty DOM interface fallbacks so React projects can compile without the DOM library. That is useful for React Native or other DOM-less targets, but browser-only properties stay unavailable until you add `\"DOM\"` to `compilerOptions.lib`.\n\n### Opt into `canary` or `experimental` declarations\n\nRelease-channel types are opt-in. Add the entry point to `compilerOptions.types`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react/canary\"]\n  }\n}\n```\n\nOr load it once from a TypeScript file:\n\n```ts\nimport {} from \"react/canary\";\n```\n\nUse `react/experimental` the same way when your runtime React channel matches the experimental declarations.\n\n## Common Workflows\n\n### Type component props and children\n\nUse `PropsWithChildren` when `children` is optional, or use `ReactNode` directly when it must be present.\n\n```tsx\nimport { type PropsWithChildren } from \"react\";\n\ntype PanelProps = PropsWithChildren<{\n  title: string;\n}>;\n\nexport function Panel({ title, children }: PanelProps) {\n  return (\n    <section aria-label={title}>\n      <h2>{title}</h2>\n      {children}\n    </section>\n  );\n}\n```\n\n`PropsWithChildren<P>` is equivalent to `P & { children?: ReactNode }`.\n\n### Reuse intrinsic element props and forward refs\n\n`ComponentPropsWithoutRef` and `ComponentRef` are the most practical helpers for wrapper components.\n\n```tsx\nimport {\n  forwardRef,\n  useId,\n  type ComponentPropsWithoutRef,\n  type ComponentRef,\n} from \"react\";\n\ntype TextInputProps = ComponentPropsWithoutRef<\"input\"> & {\n  label: string;\n};\n\nexport const TextInput = forwardRef<HTMLInputElement, TextInputProps>(\n  function TextInput({ label, id, ...props }, ref) {\n    const generatedId = useId();\n    const inputId = id ?? generatedId;\n\n    return (\n      <label htmlFor={inputId}>\n        <span>{label}</span>\n        <input id={inputId} ref={ref} {...props} />\n      </label>\n    );\n  },\n);\n\nexport type TextInputRef = ComponentRef<typeof TextInput>;\n```\n\nThis keeps the wrapper aligned with the real `<input>` prop and ref types instead of duplicating them by hand.\n\n### Type context with a guarded hook\n\n`createContext` requires a default value. When there is no sensible fallback, use `null` and guard access in a custom hook.\n\n```tsx\nimport {\n  createContext,\n  useContext,\n  type PropsWithChildren,\n} from \"react\";\n\ntype Session = {\n  userId: string;\n  signOut(): void;\n};\n\nconst SessionContext = createContext<Session | null>(null);\n\nexport function SessionProvider({\n  value,\n  children,\n}: PropsWithChildren<{ value: Session }>) {\n  return <SessionContext value={value}>{children}</SessionContext>;\n}\n\nexport function useSession() {\n  const session = useContext(SessionContext);\n\n  if (session === null) {\n    throw new Error(\"useSession must be used within <SessionProvider>\");\n  }\n\n  return session;\n}\n```\n\nIn the current React 19 declaration line, the context object itself is callable as the provider component, so `<SessionContext value={...}>` is typed directly.\n\n### Use React 19 action and optimistic state helpers\n\nThe declarations include typed tuples for `useActionState` and `useOptimistic`, so the dispatch function is inferred from your action signature.\n\n```tsx\nimport { useActionState, useOptimistic } from \"react\";\n\ntype Comment = {\n  id: string;\n  body: string;\n};\n\nasync function saveComment(\n  currentComments: Comment[],\n  formData: FormData,\n): Promise<Comment[]> {\n  const body = String(formData.get(\"body\") ?? \"\").trim();\n\n  if (!body) {\n    return currentComments;\n  }\n\n  return [\n    ...currentComments,\n    { id: `saved-${currentComments.length + 1}`, body },\n  ];\n}\n\nexport function CommentComposer({\n  initialComments,\n}: {\n  initialComments: Comment[];\n}) {\n  const [comments, submitComment, isPending] = useActionState(\n    saveComment,\n    initialComments,\n  );\n  const [optimisticComments, addOptimisticComment] = useOptimistic(\n    comments,\n    (current, body: string) => [\n      ...current,\n      { id: `optimistic-${current.length + 1}`, body },\n    ],\n  );\n\n  return (\n    <>\n      <ul>\n        {optimisticComments.map((comment) => (\n          <li key={comment.id}>{comment.body}</li>\n        ))}\n      </ul>\n\n      <form\n        action={(formData) => {\n          const body = String(formData.get(\"body\") ?? \"\").trim();\n\n          if (body) {\n            addOptimisticComment(body);\n          }\n\n          submitComment(formData);\n        }}\n      >\n        <input name=\"body\" />\n        <button disabled={isPending}>Post</button>\n      </form>\n    </>\n  );\n}\n```\n\n## Important Pitfalls\n\n- `@types/react` is declarations only. Install `react` separately.\n- Import runtime values and types from `react`, not from `@types/react`.\n- If you set `compilerOptions.types`, include `react` there or the package can appear to disappear.\n- `react/canary` and `react/experimental` declarations are not loaded unless you reference them explicitly.\n- If your project omits the DOM library, the fallback DOM interfaces are intentionally empty. Add `\"DOM\"` to `compilerOptions.lib` before relying on browser-only properties such as `HTMLInputElement.value`.\n- `createContext` requires a default value. Use `null` or `undefined` in the context type when there is no real fallback.\n- Keep `@types/react`, `react`, and `@types/react-dom` on compatible React versions.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/react==19.2.14`.\n- The current React 19 declaration line exports typed entry points for `react`, `react/canary`, `react/experimental`, `react/jsx-runtime`, `react/jsx-dev-runtime`, and `react/compiler-runtime`.\n- The published package README lists `csstype` as a dependency.\n- The React 19 declaration surface includes typed hooks and helpers such as `useActionState`, `useOptimistic`, `use`, `act`, `cache`, and `cacheSignal`.\n- `react/compiler-runtime` is present for compiler integration; its declaration file does not expose a public API for normal application imports.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/react\n- DefinitelyTyped source for `@types/react`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react\n- `@types/react` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts\n- `@types/react` canary declarations: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/canary.d.ts\n- React runtime reference: https://react.dev/reference/react\n- React `createContext` reference: https://react.dev/reference/react/createContext\n"
  },
  {
    "path": "content/typescript/docs/react-beautiful-dnd/typescript/DOC.md",
    "content": "---\nname: react-beautiful-dnd\ndescription: \"TypeScript declarations for react-beautiful-dnd components, render-prop helpers, and drag responder types used to build typed drag-and-drop lists in React.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"13.1.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,drag-and-drop,types,definitelytyped\"\n---\n\n# react-beautiful-dnd TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react-beautiful-dnd` for type checking, but import both components and types from `react-beautiful-dnd` in application code.\n\n`@types/react-beautiful-dnd` does not provide drag-and-drop behavior by itself. It supplies declarations for the runtime package's public API, including `DragDropContext`, `Droppable`, `Draggable`, `DropResult`, and the render-prop helper types.\n\n## Install\n\nInstall the runtime package plus React, then add the declaration package to your TypeScript dev dependencies:\n\n```bash\nnpm install react react-dom react-beautiful-dnd\nnpm install -D typescript @types/react @types/react-dom @types/react-beautiful-dnd\n```\n\nIf your project already has TypeScript and the React type packages, add only the drag-and-drop pieces:\n\n```bash\nnpm install react-beautiful-dnd\nnpm install -D @types/react-beautiful-dnd\n```\n\nImport from the runtime module:\n\n```ts\nimport { DragDropContext, Droppable, Draggable } from \"react-beautiful-dnd\";\nimport type { DropResult, DraggableProvided, DroppableProvided } from \"react-beautiful-dnd\";\n```\n\nDo not import from `@types/react-beautiful-dnd` in application code.\n\n## Initialization\n\nThere is no client object, authentication step, or package-specific environment variable.\n\nThe setup work is a normal React + TypeScript project plus the correct module imports.\n\n### Practical `tsconfig.json`\n\nIf you already have a working React TypeScript config, no package-specific compiler flag is required. A practical baseline looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"jsx\": \"react-jsx\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your app uses a different module setup such as `NodeNext`, keep that existing project configuration. The important boundary is that your code imports from `\"react-beautiful-dnd\"` and that TypeScript can see the installed declaration package.\n\n## Common Workflows\n\n### Type `onDragEnd` and reorder a list\n\nThe most common TypeScript workflow is typing the `onDragEnd` callback with `DropResult` and guarding against a missing destination.\n\n```tsx\nimport { useState } from \"react\";\nimport { DragDropContext, Droppable, Draggable } from \"react-beautiful-dnd\";\nimport type { DropResult } from \"react-beautiful-dnd\";\n\ntype Task = {\n  id: string;\n  content: string;\n};\n\nfunction reorder<T>(list: T[], startIndex: number, endIndex: number): T[] {\n  const next = [...list];\n  const [moved] = next.splice(startIndex, 1);\n  next.splice(endIndex, 0, moved);\n  return next;\n}\n\nexport function TaskList() {\n  const [tasks, setTasks] = useState<Task[]>([\n    { id: \"task-1\", content: \"Write guide\" },\n    { id: \"task-2\", content: \"Review reorder logic\" },\n    { id: \"task-3\", content: \"Ship changes\" },\n  ]);\n\n  const onDragEnd = (result: DropResult) => {\n    const { destination, source } = result;\n\n    if (!destination) {\n      return;\n    }\n\n    if (\n      destination.droppableId === source.droppableId &&\n      destination.index === source.index\n    ) {\n      return;\n    }\n\n    setTasks((current) => reorder(current, source.index, destination.index));\n  };\n\n  return (\n    <DragDropContext onDragEnd={onDragEnd}>\n      <Droppable droppableId=\"tasks\">\n        {(provided) => (\n          <ul ref={provided.innerRef} {...provided.droppableProps}>\n            {tasks.map((task, index) => (\n              <Draggable key={task.id} draggableId={task.id} index={index}>\n                {(provided) => (\n                  <li\n                    ref={provided.innerRef}\n                    {...provided.draggableProps}\n                    {...provided.dragHandleProps}\n                  >\n                    {task.content}\n                  </li>\n                )}\n              </Draggable>\n            ))}\n            {provided.placeholder}\n          </ul>\n        )}\n      </Droppable>\n    </DragDropContext>\n  );\n}\n```\n\n### Type drag lifecycle responders\n\nWhen you need more than `onDragEnd`, use the responder types exported by the same runtime module.\n\n```tsx\nimport { DragDropContext } from \"react-beautiful-dnd\";\nimport type {\n  DragStart,\n  DragUpdate,\n  DropResult,\n  ResponderProvided,\n} from \"react-beautiful-dnd\";\n\nconst onDragStart = (start: DragStart, provided: ResponderProvided) => {\n  console.log(\"starting\", start.draggableId, provided);\n};\n\nconst onDragUpdate = (update: DragUpdate) => {\n  console.log(\"updating\", update.destination);\n};\n\nconst onDragEnd = (result: DropResult) => {\n  console.log(\"finished\", result.reason);\n};\n\nexport function Board() {\n  return (\n    <DragDropContext\n      onDragStart={onDragStart}\n      onDragUpdate={onDragUpdate}\n      onDragEnd={onDragEnd}\n    >\n      <div />\n    </DragDropContext>\n  );\n}\n```\n\nThese types are useful when you want callback signatures in shared helpers, test utilities, or custom hooks.\n\n### Type extracted draggable and droppable render helpers\n\nWhen you move JSX out of inline render-prop functions, import the provided and snapshot helper types explicitly.\n\n```tsx\nimport type { ReactNode } from \"react\";\nimport type {\n  DraggableProvided,\n  DraggableStateSnapshot,\n  DroppableProvided,\n  DroppableStateSnapshot,\n} from \"react-beautiful-dnd\";\n\ntype Task = {\n  id: string;\n  content: string;\n};\n\ntype TaskItemProps = {\n  task: Task;\n  provided: DraggableProvided;\n  snapshot: DraggableStateSnapshot;\n};\n\nfunction TaskItem({ task, provided, snapshot }: TaskItemProps) {\n  return (\n    <li\n      ref={provided.innerRef}\n      {...provided.draggableProps}\n      {...provided.dragHandleProps}\n      data-dragging={snapshot.isDragging}\n    >\n      {task.content}\n    </li>\n  );\n}\n\ntype ColumnProps = {\n  provided: DroppableProvided;\n  snapshot: DroppableStateSnapshot;\n  children: ReactNode;\n};\n\nfunction Column({ provided, snapshot, children }: ColumnProps) {\n  return (\n    <section\n      ref={provided.innerRef}\n      {...provided.droppableProps}\n      data-dragging-over={snapshot.isDraggingOver}\n    >\n      {children}\n      {provided.placeholder}\n    </section>\n  );\n}\n```\n\nThis keeps render-prop extraction strongly typed without reaching into internal declaration files.\n\n## Important Pitfalls\n\n- Install the runtime package `react-beautiful-dnd` as well as `@types/react-beautiful-dnd`; the type package alone does not add runtime behavior.\n- Import from `react-beautiful-dnd`, not from `@types/react-beautiful-dnd`.\n- Treat `result.destination` as optional in `onDragEnd`; a drop outside a valid destination should not try to reorder state.\n- Keep `draggableId` and `droppableId` as strings, and pass a numeric `index` to each `Draggable`.\n- Always attach `provided.innerRef` and spread the matching props on the DOM element that participates in dragging or dropping.\n- Render `provided.placeholder` inside each droppable area so layout can update correctly while dragging.\n- If TypeScript reports missing exports or mismatched prop types, verify that the installed `react-beautiful-dnd` runtime package matches the declaration package you added.\n\n## Version Note For `@types/react-beautiful-dnd` 13.1.8\n\nThis guide tracks the declaration package version `13.1.8`.\n\nFor application code, the practical import surface is still the runtime package `react-beautiful-dnd`. Install that package, import from that module path, and use `@types/react-beautiful-dnd` only to supply TypeScript declarations.\n"
  },
  {
    "path": "content/typescript/docs/react-color/typescript/DOC.md",
    "content": "---\nname: react-color\ndescription: \"TypeScript declarations for react-color picker components, color change results, and typed wrapper props\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-color,color-picker,ui,types,definitelytyped\"\n---\n\n# react-color TypeScript Guide\n\n`@types/react-color` adds TypeScript declarations for the `react-color` runtime package. Use it when your React app renders picker components such as `SketchPicker` or `ChromePicker` and you want typed color values, typed change handlers, and typed component props.\n\nThis package only ships `.d.ts` files. Your application imports and renders `react-color`; the declaration package gives TypeScript the module and component types.\n\n## Install\n\nInstall the runtime package in your React app, then add the TypeScript declarations.\n\n```bash\nnpm install react react-dom react-color\nnpm install -D typescript @types/react @types/react-dom @types/react-color\n```\n\nIf your app already has React set up, add only the missing packages:\n\n```bash\nnpm install react-color\nnpm install -D @types/react-color\n```\n\nThere are no environment variables, authentication settings, or client objects to configure.\n\n## TypeScript Setup\n\nImport from `react-color`, not from `@types/react-color`.\n\nFor a browser React app, keep JSX and DOM libraries enabled:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nTypeScript usually discovers the declarations automatically once `@types/react-color` is installed.\n\nIf you restrict `compilerOptions.types`, keep your React packages listed there so JSX and React component types remain available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Render a controlled picker and store the selected hex value\n\n`ColorResult` is the practical type to use in change handlers. It gives you the selected color in multiple formats.\n\n```tsx\nimport { useState } from \"react\";\nimport { SketchPicker, type ColorResult } from \"react-color\";\n\nexport function BrandColorField() {\n  const [color, setColor] = useState(\"#2563eb\");\n\n  function handleChangeComplete(result: ColorResult) {\n    setColor(result.hex);\n  }\n\n  return (\n    <div>\n      <SketchPicker color={color} onChangeComplete={handleChangeComplete} />\n      <output>{color}</output>\n    </div>\n  );\n}\n```\n\nUse `onChangeComplete` when you want to commit the final value after a drag or interaction finishes.\n\n### Keep alpha information instead of flattening to hex\n\nIf your UI allows transparency, store `ColorResult[\"rgb\"]` or `ColorResult[\"hsl\"]` instead of only `result.hex`.\n\n```tsx\nimport { useMemo, useState } from \"react\";\nimport { ChromePicker, type ColorResult } from \"react-color\";\n\nexport function OverlayColorField() {\n  const [color, setColor] = useState<ColorResult[\"rgb\"]>({\n    r: 37,\n    g: 99,\n    b: 235,\n    a: 0.7,\n  });\n\n  const preview = useMemo(() => {\n    const alpha = color.a ?? 1;\n    return `rgba(${color.r}, ${color.g}, ${color.b}, ${alpha})`;\n  }, [color]);\n\n  return (\n    <div>\n      <ChromePicker color={color} onChange={(result: ColorResult) => setColor(result.rgb)} />\n      <div\n        style={{\n          width: 64,\n          height: 32,\n          marginTop: 12,\n          borderRadius: 6,\n          background: preview,\n        }}\n      />\n    </div>\n  );\n}\n```\n\nThis pattern avoids losing the alpha channel when a user chooses semi-transparent colors.\n\n### Reuse picker props when you build a wrapper component\n\nWhen you wrap a picker in your own component, derive the prop type from the runtime component so your wrapper stays aligned with the installed declarations.\n\n```tsx\nimport { SketchPicker, type ColorResult } from \"react-color\";\n\ntype BrandColorPickerProps = Omit<\n  React.ComponentProps<typeof SketchPicker>,\n  \"color\" | \"onChangeComplete\"\n> & {\n  value: string;\n  onChange: (nextColor: string) => void;\n};\n\nexport function BrandColorPicker({ value, onChange, ...rest }: BrandColorPickerProps) {\n  function handleChangeComplete(result: ColorResult) {\n    onChange(result.hex);\n  }\n\n  return <SketchPicker {...rest} color={value} onChangeComplete={handleChangeComplete} />;\n}\n```\n\nThis is the safest way to expose a narrower app-specific API without manually re-declaring the picker's prop surface.\n\n### Use the full change result in form helpers\n\nThe change result already contains hex, RGB, and HSL representations, so you can normalize once and pass a single typed object through your form code.\n\n```tsx\nimport { TwitterPicker, type ColorResult } from \"react-color\";\n\ntype ThemeColor = {\n  hex: string;\n  rgb: ColorResult[\"rgb\"];\n  hsl: ColorResult[\"hsl\"];\n};\n\nexport function ThemeSwatchPicker(props: {\n  value: string;\n  onChange: (next: ThemeColor) => void;\n}) {\n  return (\n    <TwitterPicker\n      color={props.value}\n      onChangeComplete={(result: ColorResult) => {\n        props.onChange({\n          hex: result.hex,\n          rgb: result.rgb,\n          hsl: result.hsl,\n        });\n      }}\n    />\n  );\n}\n```\n\n## Important Pitfalls\n\n- Install `react-color` separately; `@types/react-color` only provides TypeScript declarations.\n- Import components and types from `react-color`, never from `@types/react-color`.\n- If your browser app uses JSX, keep the DOM library and React JSX compiler settings enabled in `tsconfig.json`.\n- `result.hex` is convenient, but it can be the wrong storage format when transparency matters; keep `result.rgb` or `result.hsl` if alpha must round-trip.\n- Picker callbacks can fire repeatedly while a user drags a control. Use `onChange` for live preview and `onChangeComplete` for state you do not want to update on every intermediate event.\n- Keep `react`, `react-dom`, `@types/react`, and `@types/react-color` aligned with the React app you actually compile.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/react-color==3.0.13`.\n- The declaration package describes the `react-color` runtime API; if your app is pinned to an older or patched runtime release, verify that the installed declaration package still matches the picker components and callback props you use.\n\n## Official Sources\n\n- npm package page for `@types/react-color`: https://www.npmjs.com/package/@types/react-color\n- DefinitelyTyped source for `@types/react-color`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-color\n- `@types/react-color` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-color/index.d.ts\n- npm package page for `react-color`: https://www.npmjs.com/package/react-color\n- `react-color` source repository: https://github.com/casesandberg/react-color\n"
  },
  {
    "path": "content/typescript/docs/react-datepicker/typescript/DOC.md",
    "content": "---\nname: react-datepicker\ndescription: \"TypeScript setup for `react-datepicker`. `@types/react-datepicker@7.0.0` is a stub package, so install `react-datepicker` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-datepicker,date-picker,ui,types,definitelytyped\"\n---\n\n# react-datepicker TypeScript Guide\n\n## Golden Rule\n\n`@types/react-datepicker@7.0.0` is a stub package.\n\nThe npm package page for `@types/react-datepicker` says that `react-datepicker` provides its own type definitions. For application code, install `react-datepicker`, import from `\"react-datepicker\"`, and remove `@types/react-datepicker` if you added it directly.\n\n## Install\n\nInstall the runtime package with React and your normal TypeScript toolchain:\n\n```bash\nnpm install react react-dom react-datepicker\nnpm install -D typescript @types/react @types/react-dom\n```\n\nIf your project already uses React, add only the missing runtime package:\n\n```bash\nnpm install react-datepicker\n```\n\nIf you installed the old stub package directly, remove it:\n\n```bash\nnpm uninstall @types/react-datepicker\n```\n\nThere are no package-specific environment variables, credentials, or client objects to configure.\n\n## TypeScript Setup\n\nImport both the component and any inferred types from `react-datepicker`, not from `@types/react-datepicker`.\n\nFor a browser React app, keep JSX and DOM libraries enabled:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nTypeScript picks up the declarations automatically from the `react-datepicker` package once it is installed.\n\nIf your project restricts ambient packages with `compilerOptions.types`, keep your React entries listed there so JSX and DOM renderer types remain available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\nYou do not need to list `react-datepicker` in `compilerOptions.types`; its declarations come from the runtime module import.\n\n## Initialization\n\nThere is no SDK client or authentication step. Runtime setup usually means importing the component and its stylesheet where your app renders it.\n\n```tsx\nimport { useState } from \"react\";\nimport DatePicker from \"react-datepicker\";\nimport \"react-datepicker/dist/react-datepicker.css\";\n\nexport function PublishDateField() {\n  const [value, setValue] = useState<Date | null>(new Date());\n\n  return (\n    <DatePicker\n      selected={value}\n      onChange={(nextDate) => setValue(nextDate)}\n      dateFormat=\"yyyy-MM-dd\"\n    />\n  );\n}\n```\n\nIn the common single-date workflow, the selected value is `Date | null`, so model component state the same way.\n\n## Common Workflows\n\n### Render a controlled date picker\n\nUse React state for the selected `Date | null` value, and convert it to an application-specific string only at the boundary where you submit or persist data.\n\n```tsx\nimport { useState } from \"react\";\nimport DatePicker from \"react-datepicker\";\n\ntype FormValues = {\n  publishAt: string | null;\n};\n\nexport function PublishForm() {\n  const [publishAt, setPublishAt] = useState<Date | null>(null);\n\n  function buildPayload(): FormValues {\n    return {\n      publishAt: publishAt ? publishAt.toISOString() : null,\n    };\n  }\n\n  return (\n    <form\n      onSubmit={(event) => {\n        event.preventDefault();\n        console.log(buildPayload());\n      }}\n    >\n      <DatePicker\n        selected={publishAt}\n        onChange={(nextDate) => setPublishAt(nextDate)}\n        placeholderText=\"Choose a publish date\"\n        isClearable\n      />\n\n      <button type=\"submit\">Save</button>\n    </form>\n  );\n}\n```\n\nKeep the picker state as a `Date` in UI code. Serialize to ISO strings only when sending data to an API or storing it.\n\n### Reuse the runtime component's prop types in a wrapper\n\nWhen you build a design-system wrapper, derive the prop surface from the real component instead of duplicating prop names manually.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport DatePicker from \"react-datepicker\";\n\ntype BaseDatePickerProps = ComponentProps<typeof DatePicker>;\n\ntype BookingDateFieldProps = Omit<\n  BaseDatePickerProps,\n  \"selected\" | \"onChange\"\n> & {\n  value: Date | null;\n  onValueChange(value: Date | null): void;\n  label: string;\n};\n\nexport function BookingDateField({\n  value,\n  onValueChange,\n  label,\n  ...props\n}: BookingDateFieldProps) {\n  return (\n    <label>\n      <span>{label}</span>\n      <DatePicker\n        {...props}\n        selected={value}\n        onChange={(nextDate) => onValueChange(nextDate)}\n      />\n    </label>\n  );\n}\n```\n\nThis keeps wrapper props aligned with the installed `react-datepicker` version and avoids importing a separate prop type package.\n\n## Important Pitfalls\n\n- `@types/react-datepicker` does not provide the runtime component. Install `react-datepicker` itself.\n- Import from `react-datepicker`, not from `@types/react-datepicker`.\n- If your app does not load `react-datepicker/dist/react-datepicker.css`, the picker still type-checks but will render without the package's default styles.\n- If you restrict `compilerOptions.types`, keep `react` and `react-dom` listed there or JSX-related types can appear to disappear.\n- The common single-date flow uses `Date | null`; keep your form state compatible with that shape instead of forcing everything to strings too early.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/react-datepicker` package entry at version `7.0.0`.\n- The important package for real application code is `react-datepicker`, because that package provides both the runtime component and its type declarations.\n- When your installed `react-datepicker` version changes, rely on that package's bundled declarations as the source of truth for prop and callback types.\n\n## Official Sources\n\n- npm package page for `@types/react-datepicker`: https://www.npmjs.com/package/@types/react-datepicker\n- DefinitelyTyped source for `@types/react-datepicker`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-datepicker\n- npm package page for `react-datepicker`: https://www.npmjs.com/package/react-datepicker\n- `react-datepicker` repository: https://github.com/Hacker0x01/react-datepicker\n- `react-datepicker` documentation site: https://reactdatepicker.com/\n"
  },
  {
    "path": "content/typescript/docs/react-dom/typescript/DOC.md",
    "content": "---\nname: react-dom\ndescription: \"TypeScript declarations for React DOM client, server, static, and test-utils entry points.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"19.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-dom,dom,ssr,types,definitelytyped\"\n---\n\n# React DOM TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react-dom` alongside the real `react-dom` runtime package. This package only provides TypeScript declarations; it does not include the React DOM runtime.\n\nFor `19.2.3`, the package metadata declares:\n\n- a peer dependency on `@types/react@^19.2.0`\n- a minimum TypeScript version of `5.2`\n- type entry points for `react-dom`, `react-dom/client`, `react-dom/server`, `react-dom/static`, `react-dom/test-utils`, `react-dom/canary`, and `react-dom/experimental`\n\n## Install\n\nInstall the runtime packages in your app, then add the type packages to the same TypeScript project:\n\n```bash\nnpm install react react-dom\nnpm install -D typescript @types/react @types/react-dom\n```\n\nIf your app already depends on `react` and `react-dom`, add only the missing types:\n\n```bash\nnpm install -D @types/react @types/react-dom\n```\n\nKeep `@types/react` and `@types/react-dom` on the same React 19 line so the client, server, and form-related types stay compatible.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe main setup points are your import paths and your TypeScript compiler configuration.\n\nIn a normal TypeScript project, installing the package is usually enough. The package metadata points TypeScript at `index.d.ts` automatically, and the `exports` map provides typed subpaths such as `react-dom/client` and `react-dom/server`.\n\n### If you restrict `compilerOptions.types`\n\nIf your project restricts ambient type packages with `compilerOptions.types`, include `react` and `react-dom`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\n### Opt into `canary` or `experimental` declarations\n\n`@types/react-dom` ships optional declaration entry points for React canary and experimental builds.\n\nIf you already use a `types` array, add the entry point explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\", \"react-dom/canary\"]\n  }\n}\n```\n\nOr load the declarations once from a TypeScript file:\n\n```ts\nimport {} from \"react-dom/canary\";\n```\n\nUse `react-dom/experimental` the same way when your project is on an experimental React build.\n\nOnly opt into these declarations when your runtime React channel matches them.\n\n## Common Workflows\n\n### Mount a browser root with `react-dom/client`\n\n`createRoot` and `hydrateRoot` are declared in `react-dom/client`, not the top-level `react-dom` entry point.\n\n```tsx\nimport { StrictMode } from \"react\";\nimport {\n  createRoot,\n  hydrateRoot,\n  type RootOptions,\n} from \"react-dom/client\";\nimport { App } from \"./App\";\n\nconst rootOptions: RootOptions = {\n  identifierPrefix: \"app-\",\n  onRecoverableError(error, errorInfo) {\n    console.error(\"recoverable render error\", error, errorInfo.componentStack);\n  },\n};\n\nconst container = document.getElementById(\"root\");\n\nif (!container) {\n  throw new Error(\"Missing #root container\");\n}\n\ncreateRoot(container, rootOptions).render(\n  <StrictMode>\n    <App />\n  </StrictMode>,\n);\n\n// For SSR hydration instead of a fresh client mount:\nhydrateRoot(container, <App />, { identifierPrefix: \"app-\" });\n```\n\nThe client declarations also expose the `Root`, `RootOptions`, `HydrationOptions`, and `ErrorInfo` types when you want explicit annotations in framework code.\n\n### Use top-level DOM helpers from `react-dom`\n\nThe top-level entry point declares APIs such as `createPortal`, `flushSync`, resource hints, and form helpers.\n\n```tsx\nimport { createPortal } from \"react-dom\";\n\ntype ModalProps = {\n  children: React.ReactNode;\n  open: boolean;\n};\n\nexport function Modal({ children, open }: ModalProps) {\n  if (!open) {\n    return null;\n  }\n\n  return createPortal(children, document.body);\n}\n```\n\nIn `19.2.3`, the top-level declarations also include `flushSync`, resource hint APIs such as `preconnect` and `preload`, plus form-related APIs such as `useFormStatus`, `useFormState`, and `requestFormReset`.\n\n### Server-render HTML in Node with `react-dom/server.node`\n\nUse the Node-specific server entry point when you want the stream APIs typed around `NodeJS.WritableStream`.\n\n```tsx\nimport express from \"express\";\nimport { renderToPipeableStream } from \"react-dom/server.node\";\nimport { App } from \"./App\";\n\nconst app = express();\n\napp.get(\"/\", (_req, res) => {\n  let didError = false;\n\n  const { pipe, abort } = renderToPipeableStream(<App />, {\n    bootstrapScripts: [\"/client.js\"],\n    onShellReady() {\n      res.statusCode = didError ? 500 : 200;\n      res.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n      pipe(res);\n    },\n    onShellError(error) {\n      console.error(error);\n      res.statusCode = 500;\n      res.end(\"<!doctype html><h1>Server render failed</h1>\");\n    },\n    onError(error) {\n      didError = true;\n      console.error(error);\n    },\n  });\n\n  setTimeout(() => abort(), 10_000);\n});\n```\n\n`react-dom/server` also declares `renderToString`, `renderToStaticMarkup`, `renderToReadableStream`, `resume`, and `resumeToPipeableStream`. The environment-specific subpaths narrow that surface:\n\n- `react-dom/server.node` exports `renderToPipeableStream`, `renderToReadableStream`, `renderToString`, `renderToStaticMarkup`, `resume`, and `resumeToPipeableStream`\n- `react-dom/server.browser` exports `renderToReadableStream`, `renderToString`, and `renderToStaticMarkup`\n- `react-dom/server.edge` exports `renderToReadableStream`, `renderToString`, `renderToStaticMarkup`, and `resume`\n- `react-dom/server.bun` exports `renderToReadableStream`, `renderToString`, and `renderToStaticMarkup`\n\n### Render HTML streams in edge runtimes with `react-dom/server.edge`\n\nUse the edge or browser server entry points when your runtime works with Web Streams instead of Node streams.\n\n```tsx\nimport { renderToReadableStream } from \"react-dom/server.edge\";\nimport { App } from \"./App\";\n\nexport default async function handleRequest() {\n  const stream = await renderToReadableStream(<App />, {\n    bootstrapScripts: [\"/client.js\"],\n  });\n\n  await stream.allReady;\n\n  return new Response(stream, {\n    headers: {\n      \"content-type\": \"text/html; charset=utf-8\",\n    },\n  });\n}\n```\n\n### Use the static prerender APIs from `react-dom/static`\n\nThe `19.2.3` declarations include the newer static entry points for pre-render and resume workflows.\n\n```tsx\nimport { prerender } from \"react-dom/static.browser\";\nimport { App } from \"./App\";\n\nconst { prelude, postponed } = await prerender(<App />, {\n  bootstrapScripts: [\"/client.js\"],\n});\n\nconsole.log(postponed);\n\nreturn new Response(prelude, {\n  headers: {\n    \"content-type\": \"text/html; charset=utf-8\",\n  },\n});\n```\n\nThe static subpaths are also environment-sensitive:\n\n- `react-dom/static.node` exports `prerender`, `prerenderToNodeStream`, `resumeAndPrerender`, and `resumeAndPrerenderToNodeStream`\n- `react-dom/static.edge` exports `prerender` and `resumeAndPrerender`\n- `react-dom/static.browser` exports `prerender`\n\n### Prefer `act` from `react` in tests\n\n`react-dom/test-utils` is still typed, but the declaration marks its `act` export as deprecated and re-exports `act` from `react`.\n\n```tsx\nimport { act } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { App } from \"./App\";\n\nconst container = document.createElement(\"div\");\nconst root = createRoot(container);\n\nawait act(async () => {\n  root.render(<App />);\n});\n```\n\n## Important Pitfalls\n\n- Do not install `@types/react-dom` by itself and expect a working renderer. You still need `react-dom`.\n- Import client rendering APIs from `react-dom/client`, not from `react-dom`.\n- Keep `@types/react` compatible with the React 19 declarations expected by this package.\n- Use the environment-specific server or static subpath when you want the narrowest type surface for Node, edge, browser, or Bun code.\n- If you restrict `compilerOptions.types`, add `react-dom/canary` or `react-dom/experimental` explicitly before using those release-channel-only declarations.\n\n## Version Notes\n\nThis guide is for `@types/react-dom` `19.2.3`.\n\nAt this version, the declarations include:\n\n- React 19 form-related top-level APIs such as `useFormStatus`, `useFormState`, and `requestFormReset`\n- server resume APIs such as `resume` and `resumeToPipeableStream`\n- static pre-render APIs such as `prerender`, `resumeAndPrerender`, and their Node-specific variants\n\nIf your installed `react-dom` runtime is older than the API surface described here, align the runtime package and the type packages before relying on these declarations.\n"
  },
  {
    "path": "content/typescript/docs/react-modal/typescript/DOC.md",
    "content": "---\nname: react-modal\ndescription: \"TypeScript declarations for react-modal, including typed modal props, accessibility setup, and style configuration\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.16.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-modal,modal,accessibility,ui,types,definitelytyped\"\n---\n\n# react-modal TypeScript Guide\n\n`@types/react-modal` provides the TypeScript declarations for the `react-modal` runtime package. Use it in browser-based React apps when you want typed modal props, typed accessibility setup, and typed style objects for modal overlays and content.\n\nThis package only ships `.d.ts` files. Install the `react-modal` runtime separately, and import from `react-modal`, not from `@types/react-modal`.\n\n## Install\n\nInstall the runtime package, React dependencies, and the declaration package together:\n\n```bash\nnpm install react react-dom react-modal\nnpm install -D typescript @types/react @types/react-dom @types/react-modal\n```\n\nIf your app already has React and TypeScript configured, add only the missing modal packages:\n\n```bash\nnpm install react-modal\nnpm install -D @types/react-modal\n```\n\nNo environment variables, credentials, or client initialization are required.\n\n## TypeScript Setup\n\n`react-modal` is a browser React library, so keep JSX and DOM libraries enabled in your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, use the default import form:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```tsx\nimport Modal from \"react-modal\";\n```\n\nIf your compiler does not allow synthetic default imports, use the CommonJS-compatible import form instead:\n\n```tsx\nimport Modal = require(\"react-modal\");\n```\n\nTypeScript usually discovers the declarations automatically once `@types/react-modal` is installed.\n\n## Initialize Accessibility Support\n\nCall `Modal.setAppElement()` once so `react-modal` can hide the rest of the app from assistive technologies while the modal is open.\n\nIn a client-rendered app, calling it during startup is enough:\n\n```tsx\nimport Modal from \"react-modal\";\n\nModal.setAppElement(\"#root\");\n```\n\nIf your framework renders on the server, do the setup in a browser-only path after mount:\n\n```tsx\nimport { useEffect } from \"react\";\nimport Modal from \"react-modal\";\n\nexport function AppModalA11ySetup() {\n  useEffect(() => {\n    Modal.setAppElement(\"#__next\");\n  }, []);\n\n  return null;\n}\n```\n\nUse the selector that matches your real application root.\n\n## Common Workflows\n\n### Render a controlled modal\n\nThe main integration boundary is the `Modal` component from `react-modal`. Pass `isOpen`, `onRequestClose`, and an accessible label such as `contentLabel`.\n\n```tsx\nimport { type FormEvent, useState } from \"react\";\nimport Modal from \"react-modal\";\n\nModal.setAppElement(\"#root\");\n\nexport function RenameProjectDialog() {\n  const [isOpen, setIsOpen] = useState(false);\n  const [name, setName] = useState(\"Project Atlas\");\n\n  function openDialog() {\n    setIsOpen(true);\n  }\n\n  function closeDialog() {\n    setIsOpen(false);\n  }\n\n  function handleSubmit(event: FormEvent<HTMLFormElement>) {\n    event.preventDefault();\n    closeDialog();\n  }\n\n  return (\n    <>\n      <button onClick={openDialog}>Rename project</button>\n\n      <Modal\n        isOpen={isOpen}\n        onRequestClose={closeDialog}\n        contentLabel=\"Rename project\"\n        shouldCloseOnOverlayClick\n      >\n        <form onSubmit={handleSubmit}>\n          <h2>Rename project</h2>\n\n          <label>\n            Name\n            <input\n              value={name}\n              onChange={(event) => setName(event.currentTarget.value)}\n            />\n          </label>\n\n          <div>\n            <button type=\"button\" onClick={closeDialog}>\n              Cancel\n            </button>\n            <button type=\"submit\">Save</button>\n          </div>\n        </form>\n      </Modal>\n    </>\n  );\n}\n```\n\n### Type a custom `style` object from the modal props\n\nIf you keep styles inline, derive the type from the component props instead of maintaining your own style shape.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport Modal from \"react-modal\";\n\ntype ModalStyle = NonNullable<ComponentProps<typeof Modal>[\"style\"]>;\n\nconst modalStyle: ModalStyle = {\n  overlay: {\n    backgroundColor: \"rgba(15, 23, 42, 0.7)\",\n    zIndex: 1000,\n  },\n  content: {\n    inset: \"4rem auto auto 50%\",\n    width: \"min(32rem, calc(100vw - 2rem))\",\n    transform: \"translateX(-50%)\",\n    borderRadius: \"0.75rem\",\n    padding: \"1.5rem\",\n  },\n};\n\nexport function StyledDialog(props: { isOpen: boolean; onClose(): void }) {\n  return (\n    <Modal\n      isOpen={props.isOpen}\n      onRequestClose={props.onClose}\n      contentLabel=\"Styled dialog\"\n      style={modalStyle}\n    >\n      <p>Styled modal content</p>\n    </Modal>\n  );\n}\n```\n\nThis keeps the object aligned with the package's `style` prop instead of duplicating the shape by hand.\n\n### Mount the modal into a specific portal container\n\nUse `parentSelector` when your app needs the portal to render into a dedicated element instead of the default `document.body`.\n\n```tsx\nimport Modal from \"react-modal\";\n\nexport function DrawerLikeModal(props: { isOpen: boolean; onClose(): void }) {\n  return (\n    <Modal\n      isOpen={props.isOpen}\n      onRequestClose={props.onClose}\n      contentLabel=\"Activity details\"\n      parentSelector={() => document.getElementById(\"modal-root\") ?? document.body}\n    >\n      <p>Activity details</p>\n    </Modal>\n  );\n}\n```\n\nReturning `document.body` as a fallback keeps the callback typed as an `HTMLElement`.\n\n## Important Pitfalls\n\n- Install both packages: `@types/react-modal` does not include the `react-modal` runtime.\n- Import from `react-modal`: do not import declarations from `@types/react-modal` directly.\n- Set the app element once: `Modal.setAppElement()` is part of the accessibility setup, not a per-dialog call.\n- Use a browser-only setup path for SSR frameworks: `setAppElement()` needs access to the real DOM.\n- Keep your React DOM types available: `react-modal` depends on normal React and browser DOM typing to type JSX and portal behavior correctly.\n\n## Minimal Checklist\n\n1. Install `react-modal` and `@types/react-modal`.\n2. Enable JSX and DOM libraries in `tsconfig.json`.\n3. Import `Modal` from `react-modal` with the import style your compiler supports.\n4. Call `Modal.setAppElement()` for your app root.\n5. Render `<Modal isOpen={...} onRequestClose={...} contentLabel=\"...\">` in your React component.\n"
  },
  {
    "path": "content/typescript/docs/react-redux/typescript/DOC.md",
    "content": "---\nname: react-redux\ndescription: \"TypeScript declarations for React Redux Provider, hooks, connect, and prop inference in react-redux 7.x applications.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.1.34\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react-redux,react,redux,provider,hooks,connect,types,definitelytyped\"\n---\n\n# React Redux TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react-redux` alongside the real `react-redux` runtime package.\n\n`@types/react-redux` only provides TypeScript declarations. Your application imports `Provider`, `connect`, `useDispatch`, `useSelector`, `shallowEqual`, and the related helper types from `react-redux`, not from `@types/react-redux`.\n\nThis declaration package is for the `react-redux` 7.x line. The `react-redux` 7.2.x packages depend on `@types/react-redux`, while `react-redux` 8.0.0 and later publish their own `.d.ts` files. If you upgrade the runtime to 8 or newer, remove `@types/react-redux` and use the bundled runtime types instead.\n\n## Install\n\nInstall the runtime packages first, then add the declaration packages your TypeScript project needs.\n\n```bash\nnpm install react react-redux redux\nnpm install -D typescript @types/react @types/react-redux\n\n# Browser apps that render with react-dom\nnpm install react-dom\nnpm install -D @types/react-dom\n```\n\nIf your project already has `react-redux` 7.x installed, add only the missing declaration package:\n\n```bash\nnpm install -D @types/react-redux\n```\n\nDo not install `@types/react-redux` with `react-redux` 8+.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe setup that matters is your store type, your React `Provider`, and a TypeScript config that compiles JSX.\n\n### Minimal `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nIf your project uses the older React JSX transform, keep the JSX setting that matches that toolchain.\n\n### Create a typed Redux store\n\n```typescript\nimport { combineReducers, createStore } from \"redux\";\n\ntype CounterAction =\n  | { type: \"counter/increment\" }\n  | { type: \"counter/add\"; payload: number };\n\ntype CounterState = {\n  value: number;\n};\n\nconst initialCounterState: CounterState = {\n  value: 0,\n};\n\nfunction counterReducer(\n  state: CounterState = initialCounterState,\n  action: CounterAction,\n): CounterState {\n  switch (action.type) {\n    case \"counter/increment\":\n      return { value: state.value + 1 };\n    case \"counter/add\":\n      return { value: state.value + action.payload };\n    default:\n      return state;\n  }\n}\n\nconst rootReducer = combineReducers({\n  counter: counterReducer,\n});\n\nexport const store = createStore(rootReducer);\n\nexport type RootState = ReturnType<typeof store.getState>;\nexport type AppDispatch = typeof store.dispatch;\n```\n\n### Wrap the app with `Provider`\n\n```tsx\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport { Provider } from \"react-redux\";\nimport { App } from \"./App\";\nimport { store } from \"./store\";\n\nconst rootElement = document.getElementById(\"root\");\n\nif (!rootElement) {\n  throw new Error(\"Missing #root element\");\n}\n\nReactDOM.createRoot(rootElement).render(\n  <Provider store={store}>\n    <App />\n  </Provider>,\n);\n```\n\n## Common Workflows\n\n### Create typed selector and dispatch hooks\n\n`TypedUseSelectorHook<TState>` lets you declare your root state once instead of repeating it in every selector.\n\n```typescript\nimport {\n  type TypedUseSelectorHook,\n  useDispatch,\n  useSelector,\n} from \"react-redux\";\nimport type { AppDispatch, RootState } from \"./store\";\n\nexport const useAppDispatch = () => useDispatch<AppDispatch>();\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;\n```\n\nUse those helpers from components:\n\n```tsx\nimport { useAppDispatch, useAppSelector } from \"./hooks\";\n\nexport function CounterButton() {\n  const value = useAppSelector((state) => state.counter.value);\n  const dispatch = useAppDispatch();\n\n  return (\n    <button onClick={() => dispatch({ type: \"counter/increment\" })}>\n      Count: {value}\n    </button>\n  );\n}\n```\n\n### Pass `shallowEqual` when selecting an object\n\nIf a selector returns a fresh object, pass `shallowEqual` as the equality function so React Redux compares the selected fields instead of the object identity.\n\n```tsx\nimport { shallowEqual } from \"react-redux\";\nimport { useAppSelector } from \"./hooks\";\n\nexport function CounterSummary() {\n  const counter = useAppSelector(\n    (state) => ({ value: state.counter.value }),\n    shallowEqual,\n  );\n\n  return <p>Current value: {counter.value}</p>;\n}\n```\n\n### Infer injected props from `connect`\n\nWhen you still use `connect`, prefer `ConnectedProps<typeof connector>` instead of manually duplicating the injected prop types.\n\n```tsx\nimport React from \"react\";\nimport { connect, type ConnectedProps } from \"react-redux\";\nimport type { RootState } from \"./store\";\n\ntype OwnProps = {\n  label: string;\n};\n\nconst mapState = (state: RootState) => ({\n  value: state.counter.value,\n});\n\nconst mapDispatch = {\n  increment: () => ({ type: \"counter/increment\" as const }),\n};\n\nconst connector = connect(mapState, mapDispatch);\n\ntype PropsFromRedux = ConnectedProps<typeof connector>;\ntype CounterCardProps = PropsFromRedux & OwnProps;\n\nfunction CounterCard({ label, value, increment }: CounterCardProps) {\n  return (\n    <button onClick={increment}>\n      {label}: {value}\n    </button>\n  );\n}\n\nexport default connector(CounterCard);\n```\n\nThis keeps `mapStateToProps` and `mapDispatchToProps` as the source of truth for injected props.\n\n## Important Pitfalls\n\n- `@types/react-redux` is a declaration package only. Install `react-redux`, `react`, and `redux` separately.\n- Import everything from `react-redux`. Do not import runtime values or helper types from `@types/react-redux`.\n- `@types/react-redux` `7.1.34` is for the runtime line before bundled types. Remove it when upgrading to `react-redux` `8+` to avoid duplicate or conflicting declarations.\n- Keep `@types/react` aligned with your installed React major so context, JSX, and component types match the runtime.\n"
  },
  {
    "path": "content/typescript/docs/react-router/typescript/DOC.md",
    "content": "---\nname: react-router\ndescription: \"TypeScript declarations for React Router 5 core routers, route props, hooks, path helpers, and history-based navigation.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.1.20\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react-router,routing,history,react,types,definitelytyped\"\n---\n\n# React Router TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react-router` for React Router 5.x projects that use the core `react-router` package.\n\nThis package only provides TypeScript declarations. It does not install the runtime router.\n\nThe `5.1.20` declarations describe the React Router 5 API surface, including `Route`, `Switch`, `Redirect`, `withRouter`, `useHistory`, `useLocation`, `useParams`, and `useRouteMatch`.\n\nIf your app uses `react-router-dom@5`, install `@types/react-router-dom@5` for the DOM-specific APIs. That package already depends on `@types/react-router`.\n\n## Install\n\n### Core `react-router` usage\n\nInstall the runtime package, React, and the matching type packages:\n\n```bash\nnpm install react react-router@5\nnpm install -D typescript @types/react @types/react-router@5.1.20\n```\n\nInstall `history@4` only when your app imports from `history` directly, such as a custom router setup:\n\n```bash\nnpm install history@4\n```\n\n### Browser apps with `react-router-dom`\n\nFor browser apps, install the DOM runtime and its type package instead of installing `@types/react-router` separately:\n\n```bash\nnpm install react react-router-dom@5\nnpm install -D typescript @types/react @types/react-router-dom@5\n```\n\n`@types/react-router-dom@5.3.3` depends on `@types/react-router`, so it brings in the core route and history types automatically.\n\n## TypeScript Setup\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup is your compiler configuration and your runtime package versions.\n\n`@types/react-router@5.1.20` declares `typeScriptVersion: \"4.2\"`, so use TypeScript 4.2 or newer.\n\nThe package also ships a `typesVersions` mapping for TypeScript `<=4.6`. Older compilers load the `ts4.6/` declaration tree automatically, while newer compilers use the root declarations.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"jsx\": \"react-jsx\",\n    \"strict\": true,\n    \"lib\": [\"ES2020\", \"DOM\"]\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, include `react-router` explicitly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-router\"]\n  }\n}\n```\n\nFor DOM apps that import `react-router-dom`, include that package instead:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-router-dom\"]\n  }\n}\n```\n\n## Imports And Runtime Boundary\n\nImport the core router APIs from `react-router`:\n\n```ts\nimport {\n  MemoryRouter,\n  Redirect,\n  Route,\n  StaticRouter,\n  Switch,\n  generatePath,\n  matchPath,\n  useHistory,\n  useLocation,\n  useParams,\n  useRouteMatch,\n  withRouter,\n  type RouteComponentProps,\n  type StaticRouterContext,\n} from \"react-router\";\n```\n\nBrowser-only components such as `BrowserRouter`, `HashRouter`, `Link`, and `NavLink` are not declared by this package. They belong to `react-router-dom`.\n\n## Common Workflows\n\n### Type route params and location state\n\nUse `RouteComponentProps` for component props and `useParams` / `useLocation` in hook-based components.\n\n```tsx\nimport React from \"react\";\nimport {\n  Route,\n  useLocation,\n  useParams,\n  type RouteComponentProps,\n} from \"react-router\";\n\ntype UserParams = {\n  userId: string;\n};\n\ntype LocationState = {\n  referrer?: \"/teams\" | \"/search\";\n};\n\nexport function UserScreen() {\n  const { userId } = useParams<UserParams>();\n  const location = useLocation<LocationState>();\n\n  return <div>{userId} {location.state?.referrer ?? \"direct\"}</div>;\n}\n\ntype UserRouteProps = RouteComponentProps<UserParams, {}, LocationState>;\n\nexport function UserRoute({ match, location }: UserRouteProps) {\n  return <div>{match.params.userId} {location.state?.referrer ?? \"direct\"}</div>;\n}\n\nexport function AppRoutes() {\n  return <Route path=\"/users/:userId\" component={UserRoute} />;\n}\n```\n\n`RouteComponentProps<Params, C, S>` uses three generics:\n\n- `Params` for route params\n- `C` for `staticContext` in server rendering\n- `S` for `location.state`\n\n### Type imperative navigation with `useHistory`\n\n`useHistory<S>()` returns `History<S>`, so navigation state stays typed when you push or replace locations.\n\n```tsx\nimport { useHistory } from \"react-router\";\n\ntype CheckoutState = {\n  from: \"/cart\" | \"/shipping\";\n};\n\nexport function ContinueButton() {\n  const history = useHistory<CheckoutState>();\n\n  return (\n    <button\n      onClick={() => {\n        history.push(\"/checkout/review\", { from: \"/shipping\" });\n      }}\n    >\n      Continue\n    </button>\n  );\n}\n```\n\n`useLocation<S>()` reads the same state shape on the destination route.\n\n### Generate URLs from typed path patterns\n\n`generatePath()` uses the `ExtractRouteParams` helper type, so inline string literals produce a typed params object.\n\n```ts\nimport { generatePath } from \"react-router\";\n\nconst userRoute = \"/users/:userId\" as const;\nconst teamMemberRoute = \"/teams/:teamId/members/:memberId\" as const;\n\nconst userUrl = generatePath(userRoute, { userId: \"42\" });\nconst memberUrl = generatePath(teamMemberRoute, {\n  teamId: \"a-team\",\n  memberId: \"u-17\",\n});\n```\n\nKeep route patterns as string literals or `as const`. If a path value widens to plain `string`, TypeScript can no longer infer the expected params.\n\n### Match routes outside a `<Route>` component\n\nUse `matchPath()` for manual checks and `useRouteMatch()` when a component needs the current match.\n\n```tsx\nimport { matchPath, useRouteMatch } from \"react-router\";\n\ntype TeamParams = {\n  teamId: string;\n};\n\nexport function isTeamPath(pathname: string) {\n  return matchPath<TeamParams>(pathname, {\n    path: \"/teams/:teamId\",\n    exact: true,\n  });\n}\n\nexport function TeamBadge() {\n  const match = useRouteMatch<TeamParams>(\"/teams/:teamId\");\n\n  if (!match) {\n    return null;\n  }\n\n  return <span>{match.params.teamId}</span>;\n}\n```\n\n`useRouteMatch()` without arguments returns the nearest current match. With a path or route props object, it returns `match | null`.\n\n### Wrap legacy class components with `withRouter`\n\n`withRouter()` is the main compatibility path for class components and older function components that still expect injected route props.\n\n```tsx\nimport React from \"react\";\nimport { withRouter, type RouteComponentProps } from \"react-router\";\n\ntype Params = {\n  projectId: string;\n};\n\ntype OwnProps = {\n  title: string;\n};\n\ntype Props = OwnProps & RouteComponentProps<Params>;\n\nclass ProjectPage extends React.Component<Props> {\n  render() {\n    return <h1>{this.props.title}: {this.props.match.params.projectId}</h1>;\n  }\n}\n\nexport default withRouter(ProjectPage);\n```\n\nThe declaration file documents a known TypeScript limitation for decorators: use `withRouter(Component)` on a separate line instead of `@withRouter`.\n\n### Type test renders with `MemoryRouter`\n\n`MemoryRouter` is the practical test router because the type package covers `initialEntries`, `initialIndex`, and custom confirmation callbacks.\n\n```tsx\nimport React from \"react\";\nimport { MemoryRouter, Route } from \"react-router\";\n\nexport function TestApp() {\n  return (\n    <MemoryRouter initialEntries={[\"/users/42\"]}>\n      <Route path=\"/users/:userId\" render={() => <div>ready</div>} />\n    </MemoryRouter>\n  );\n}\n```\n\n### Type server-rendered routing with `StaticRouter`\n\n`StaticRouterContext` lets server code read redirects and status from the render pass.\n\n```tsx\nimport React from \"react\";\nimport { StaticRouter, type StaticRouterContext } from \"react-router\";\n\nconst context: StaticRouterContext = {};\n\nexport function ServerApp({ url }: { url: string }) {\n  return (\n    <StaticRouter location={url} context={context}>\n      <div>server render</div>\n    </StaticRouter>\n  );\n}\n\nif (context.url) {\n  console.log(\"redirect to\", context.url);\n}\n```\n\nThe typed context surface includes `url`, `action`, `location`, and the base `statusCode` field from `StaticContext`.\n\n## Important Pitfalls\n\n- `@types/react-router@5.1.20` is for React Router 5.x, not the v6 or v7 API.\n- These declarations include `Switch`, `Redirect`, `withRouter`, and `useHistory`; they do not declare `Routes`, `Navigate`, or `useNavigate`.\n- This package covers the core router only. DOM-specific components live in `react-router-dom`.\n- The package depends on `@types/history` and models the `history` v4 API shape used by React Router 5.\n- Install the runtime packages separately. Type packages alone do not make routes work at runtime.\n\n## Version Notes\n\n- Package version `5.1.20` was published from DefinitelyTyped and points to the `types/react-router` source tree.\n- The declaration package depends on `@types/history@^4.7.11` and `@types/react`.\n- The runtime `react-router` package has moved on to newer major versions, so use this type package only when your app still targets the 5.x router API.\n"
  },
  {
    "path": "content/typescript/docs/react-router-dom/typescript/DOC.md",
    "content": "---\nname: react-router-dom\ndescription: \"TypeScript declarations for React Router DOM v5 routers, route props, hooks, navigation helpers, and server-side routing helpers.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.3.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-router,react-router-dom,routing,types,definitelytyped\"\n---\n\n# React Router DOM TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/react-router-dom` alongside the real `react-router-dom` runtime package.\n\n`@types/react-router-dom` only provides TypeScript declarations. Your app imports and runs `react-router-dom`; the declaration package adds types for the v5 DOM router API, including `BrowserRouter`, `HashRouter`, `MemoryRouter`, `StaticRouter`, `Route`, `Switch`, `Redirect`, `Link`, `NavLink`, `Prompt`, `generatePath`, `matchPath`, `withRouter`, `useHistory`, `useLocation`, `useParams`, and `useRouteMatch`.\n\n## Install\n\nInstall the runtime packages first, then add the declaration packages to the same TypeScript project.\n\n```bash\nnpm install react react-dom react-router-dom@5\nnpm install -D typescript @types/react @types/react-dom @types/react-router-dom\n```\n\nIf your app already depends on `react`, `react-dom`, and `react-router-dom@5`, add only the missing declarations:\n\n```bash\nnpm install -D @types/react @types/react-dom @types/react-router-dom\n```\n\n`@types/react-router-dom` pulls in the related router and history declarations it needs through its own package dependencies.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe main setup points are your runtime package version, your imports, and your TypeScript compiler settings.\n\n### Import from `react-router-dom`\n\nAlways import runtime values and exported types from `react-router-dom`, not from `@types/react-router-dom`.\n\n```tsx\nimport {\n  BrowserRouter,\n  Link,\n  Route,\n  Switch,\n  useHistory,\n} from \"react-router-dom\";\nimport type { RouteComponentProps } from \"react-router-dom\";\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"jsx\": \"react-jsx\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your app still uses the classic React JSX transform, `\"jsx\": \"react\"` also works.\n\n## Common Workflows\n\n### Type route params with `RouteComponentProps`\n\nUse `RouteComponentProps<Params>` when a component is rendered through a v5 `Route` and reads `match`, `location`, or `history` from route props.\n\n```tsx\nimport {\n  BrowserRouter,\n  Redirect,\n  Route,\n  Switch,\n} from \"react-router-dom\";\nimport type { RouteComponentProps } from \"react-router-dom\";\n\ntype ProjectRouteParams = {\n  projectId: string;\n};\n\nfunction ProjectPage({ match }: RouteComponentProps<ProjectRouteParams>) {\n  return <h1>Project {match.params.projectId}</h1>;\n}\n\nexport function AppRouter() {\n  return (\n    <BrowserRouter>\n      <Switch>\n        <Route exact path=\"/\" render={() => <Redirect to=\"/projects/alpha\" />} />\n        <Route path=\"/projects/:projectId\" component={ProjectPage} />\n      </Switch>\n    </BrowserRouter>\n  );\n}\n```\n\nThis pattern matches the v5 `Route` API where `component`, `render`, and `children` are the main render strategies.\n\n### Type hooks for params, location state, and navigation\n\nThe hook APIs let function components work directly with typed route params and navigation state.\n\n```tsx\nimport {\n  useHistory,\n  useLocation,\n  useParams,\n  useRouteMatch,\n} from \"react-router-dom\";\n\ntype UserParams = {\n  userId: string;\n};\n\ntype AppLocationState = {\n  from?: string;\n};\n\nexport function UserToolbar() {\n  const history = useHistory<AppLocationState>();\n  const location = useLocation<AppLocationState>();\n  const { userId } = useParams<UserParams>();\n  const settingsMatch = useRouteMatch<UserParams>(\"/users/:userId/settings\");\n\n  function goToCheckout() {\n    history.push(\"/checkout\", { from: location.pathname });\n  }\n\n  return (\n    <div>\n      <p>Current user: {userId}</p>\n      <p>Settings route active: {settingsMatch ? \"yes\" : \"no\"}</p>\n      <button onClick={goToCheckout}>Checkout</button>\n    </div>\n  );\n}\n```\n\nUse the same state shape generic anywhere you read or write `location.state` so `history.push()` and `useLocation()` stay aligned.\n\n### Build and match typed URLs with `generatePath` and `matchPath`\n\nUse the helper functions when you want route-aware strings without duplicating path templates.\n\n```tsx\nimport { generatePath, matchPath } from \"react-router-dom\";\n\nconst detailsPath = generatePath(\"/orgs/:orgId/users/:userId\", {\n  orgId: \"acme\",\n  userId: \"42\",\n});\n\nconst match = matchPath<{ orgId: string; userId: string }>(detailsPath, {\n  path: \"/orgs/:orgId/users/:userId\",\n  exact: true,\n});\n\nif (match) {\n  console.log(match.params.orgId, match.params.userId);\n}\n```\n\nThis is useful in helpers, menu builders, and tests where you want the route pattern and the generated URL to stay consistent.\n\n### Keep older class components working with `withRouter`\n\n`withRouter` is still useful in v5 codebases that use class components or higher-order components instead of hooks.\n\n```tsx\nimport React from \"react\";\nimport { withRouter } from \"react-router-dom\";\nimport type { RouteComponentProps } from \"react-router-dom\";\n\ntype AccountParams = {\n  accountId: string;\n};\n\ntype Props = RouteComponentProps<AccountParams> & {\n  loadAccount(id: string): void;\n};\n\nclass AccountScreen extends React.Component<Props> {\n  componentDidMount() {\n    this.props.loadAccount(this.props.match.params.accountId);\n  }\n\n  render() {\n    return <div>Account {this.props.match.params.accountId}</div>;\n  }\n}\n\nexport default withRouter(AccountScreen);\n```\n\n`withRouter` injects the same route props you would otherwise receive from a `Route` render.\n\n### Use `MemoryRouter` in tests and `StaticRouter` on the server\n\nThe declarations cover the non-browser routers too, so you can type components consistently across tests and server rendering.\n\n```tsx\nimport { MemoryRouter, Route, StaticRouter } from \"react-router-dom\";\n\nexport function TestHarness() {\n  return (\n    <MemoryRouter initialEntries={[\"/projects/alpha\"]}>\n      <Route path=\"/projects/:projectId\" render={() => <div>ok</div>} />\n    </MemoryRouter>\n  );\n}\n\nexport function ServerRouter({ location }: { location: string }) {\n  const context: { url?: string } = {};\n\n  return (\n    <StaticRouter location={location} context={context}>\n      <Route path=\"/login\" render={() => <div>Login</div>} />\n    </StaticRouter>\n  );\n}\n```\n\nUse `MemoryRouter` for isolated tests and `StaticRouter` when a server render needs to capture redirects through the `context` object.\n\n## Important Pitfalls\n\n- `@types/react-router-dom@5.3.3` is for the v5 API surface. Do not pair it with `react-router-dom` v6 or v7.\n- Import from `react-router-dom`, never from `@types/react-router-dom`.\n- URL params from `RouteComponentProps`, `useParams()`, and `matchPath()` are strings. Convert them yourself if your app uses numeric IDs.\n- Keep your `location.state` generic consistent across `useHistory()`, `useLocation()`, route props, and redirect flows.\n- `Switch`, `Redirect`, `withRouter`, and `useHistory` are v5-specific patterns. If your runtime code uses `Routes`, `Navigate`, or `useNavigate`, you are on a newer React Router line and should not use this declaration package.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/react-router-dom\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-router-dom\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-router-dom/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-router-dom/react-router-dom-tests.tsx\n"
  },
  {
    "path": "content/typescript/docs/react-select/typescript/DOC.md",
    "content": "---\nname: react-select\ndescription: \"TypeScript setup for `react-select`. `@types/react-select@5.0.1` is a stub package, so install `react-select` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-select,select,forms,ui,types,definitelytyped\"\n---\n\n# react-select TypeScript Guide\n\n## Golden Rule\n\n`@types/react-select@5.0.1` is a stub package.\n\nThe npm package page for `@types/react-select` says that `react-select` provides its own type definitions. For application code, install `react-select`, import from `\"react-select\"`, and remove `@types/react-select` if you added it directly.\n\n## Install\n\nInstall the runtime package with React and your normal TypeScript toolchain:\n\n```bash\nnpm install react react-dom react-select\nnpm install -D typescript @types/react @types/react-dom\n```\n\nIf your project already uses React, add only the missing runtime package:\n\n```bash\nnpm install react-select\n```\n\nIf you installed the old stub package directly, remove it:\n\n```bash\nnpm uninstall @types/react-select\n```\n\nThere are no package-specific environment variables, credentials, or client objects to configure.\n\n## TypeScript Setup\n\nImport both the component and its public types from `react-select`, not from `@types/react-select`.\n\nFor a browser React app, keep JSX and DOM libraries enabled:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nTypeScript picks up the declarations automatically from the `react-select` package once it is installed.\n\nIf your project restricts ambient packages with `compilerOptions.types`, keep your React entries listed there so JSX and DOM renderer types remain available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\nYou do not need to list `react-select` in `compilerOptions.types`; its declarations come from the runtime module import.\n\n## Initialization\n\nThere is no SDK client or authentication step. Runtime setup usually means importing `Select` and rendering it with typed options.\n\n```tsx\nimport { useState } from \"react\";\nimport Select, { type SingleValue } from \"react-select\";\n\ntype ColorOption = {\n  value: string;\n  label: string;\n};\n\nconst colorOptions: ColorOption[] = [\n  { value: \"blue\", label: \"Blue\" },\n  { value: \"green\", label: \"Green\" },\n  { value: \"purple\", label: \"Purple\" },\n];\n\nexport function FavoriteColorField() {\n  const [value, setValue] = useState<ColorOption | null>(null);\n\n  function handleChange(nextValue: SingleValue<ColorOption>) {\n    setValue(nextValue ?? null);\n  }\n\n  return (\n    <Select<ColorOption>\n      inputId=\"favorite-color\"\n      options={colorOptions}\n      value={value}\n      onChange={handleChange}\n      isClearable\n    />\n  );\n}\n```\n\nIn the common single-select flow, `SingleValue<Option>` maps to `Option | null`, so keep component state compatible with that shape.\n\n## Common Workflows\n\n### Model `isMulti` values correctly\n\nWhen `isMulti` is enabled, the change value becomes `MultiValue<Option>` instead of `SingleValue<Option>`.\n\n```tsx\nimport { useState } from \"react\";\nimport Select, { type MultiValue } from \"react-select\";\n\ntype UserOption = {\n  value: string;\n  label: string;\n};\n\nconst userOptions: UserOption[] = [\n  { value: \"ada\", label: \"Ada\" },\n  { value: \"grace\", label: \"Grace\" },\n  { value: \"linus\", label: \"Linus\" },\n];\n\nexport function AssigneeField() {\n  const [value, setValue] = useState<UserOption[]>([]);\n\n  function handleChange(nextValue: MultiValue<UserOption>) {\n    setValue([...nextValue]);\n  }\n\n  return (\n    <Select<UserOption, true>\n      inputId=\"assignees\"\n      isMulti\n      options={userOptions}\n      value={value}\n      onChange={handleChange}\n      closeMenuOnSelect={false}\n    />\n  );\n}\n```\n\n`MultiValue<Option>` is a readonly array type, so spread it into a new array when your local state expects a mutable `Option[]`.\n\n### Reuse the runtime component's prop types in a wrapper\n\nWhen you build a design-system wrapper, derive the prop surface from `react-select` instead of copying prop names by hand.\n\n```tsx\nimport Select, {\n  type GroupBase,\n  type Props as SelectProps,\n} from \"react-select\";\n\ntype StatusOption = {\n  value: string;\n  label: string;\n};\n\ntype StatusSelectProps = SelectProps<\n  StatusOption,\n  false,\n  GroupBase<StatusOption>\n> & {\n  label: string;\n};\n\nexport function StatusSelect({\n  label,\n  inputId = \"status\",\n  ...props\n}: StatusSelectProps) {\n  return (\n    <label htmlFor={inputId}>\n      <span>{label}</span>\n      <Select<StatusOption>\n        {...props}\n        inputId={inputId}\n      />\n    </label>\n  );\n}\n```\n\nThis keeps wrapper props aligned with the installed `react-select` version and avoids inventing a second prop contract.\n\n### Type style overrides with `StylesConfig`\n\nStyle callbacks can stay fully typed by parameterizing `StylesConfig` with your option shape and `isMulti` mode.\n\n```tsx\nimport Select, {\n  type GroupBase,\n  type StylesConfig,\n} from \"react-select\";\n\ntype StatusOption = {\n  value: string;\n  label: string;\n  color: string;\n};\n\nconst options: StatusOption[] = [\n  { value: \"todo\", label: \"Todo\", color: \"#6b7280\" },\n  { value: \"doing\", label: \"Doing\", color: \"#2563eb\" },\n  { value: \"done\", label: \"Done\", color: \"#16a34a\" },\n];\n\nconst styles: StylesConfig<\n  StatusOption,\n  false,\n  GroupBase<StatusOption>\n> = {\n  control: (base, state) => ({\n    ...base,\n    borderColor: state.isFocused ? \"#2563eb\" : base.borderColor,\n    boxShadow: state.isFocused ? \"0 0 0 1px #2563eb\" : base.boxShadow,\n  }),\n  option: (base, state) => ({\n    ...base,\n    color: state.data.color,\n    fontWeight: state.isSelected ? 600 : 400,\n  }),\n};\n\nexport function StatusField() {\n  return (\n    <Select<StatusOption>\n      inputId=\"status\"\n      options={options}\n      styles={styles}\n    />\n  );\n}\n```\n\nThe callback state stays connected to your option type, so `state.data` is strongly typed inside style functions.\n\n## Important Pitfalls\n\n- `@types/react-select` does not provide the runtime component. Install `react-select` itself.\n- Import from `react-select`, not from `@types/react-select`.\n- If an older lockfile still includes `@types/react-select`, remove the stub package before troubleshooting duplicate or stale type behavior.\n- `Select<Option, true>` and `Select<Option, false>` produce different callback value shapes; keep the `isMulti` generic aligned with the real component usage.\n- `MultiValue<Option>` is readonly, so copy it before storing it in mutable application state.\n- If you restrict `compilerOptions.types`, keep `react` and `react-dom` listed there or JSX-related types can appear to disappear.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/react-select` package entry at version `5.0.1`.\n- The important package for real application code is `react-select`, because that package provides both the runtime component and its type declarations.\n- When your installed `react-select` version changes, rely on that package's bundled declarations as the source of truth for props, callback values, and style helper types.\n\n## Official Sources\n\n- npm package page for `@types/react-select`: https://www.npmjs.com/package/@types/react-select\n- DefinitelyTyped source for `@types/react-select`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-select\n- npm package page for `react-select`: https://www.npmjs.com/package/react-select\n- `react-select` repository: https://github.com/JedWatson/react-select\n- `react-select` documentation site: https://react-select.com/\n"
  },
  {
    "path": "content/typescript/docs/react-transition-group/typescript/DOC.md",
    "content": "---\nname: react-transition-group\ndescription: \"TypeScript setup for react-transition-group, including installation, JSX compiler settings, typed transition components, and StrictMode-safe refs.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.4.12\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,transitions,animation,react-transition-group,types,definitelytyped\"\n---\n\n# react-transition-group TypeScript Guide\n\n`@types/react-transition-group` provides the TypeScript declarations for the `react-transition-group` runtime package. Install it when your React app uses components such as `Transition`, `CSSTransition`, `TransitionGroup`, or `SwitchTransition` and you want typed props, callbacks, refs, and transition-state inference.\n\nThis package only ships declaration files. Install the real `react-transition-group` runtime separately.\n\n## Install\n\nInstall the runtime package, React, and the matching type packages together:\n\n```bash\nnpm install react react-dom react-transition-group\nnpm install --save-dev typescript @types/react @types/react-dom @types/react-transition-group\n```\n\nIf the project already has `react`, `react-dom`, and `react-transition-group`, add only the missing declarations:\n\n```bash\nnpm install --save-dev @types/react-transition-group\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nTypeScript uses these declarations automatically when you import from `\"react-transition-group\"`.\n\nFor browser React apps, keep JSX and DOM libraries enabled in `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nIf your project restricts `compilerOptions.types`, include the React packages there. You do not import from `@types/react-transition-group` directly.\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"react\", \"react-dom\"]\n  }\n}\n```\n\n## Import The Runtime Package\n\nImport the components from `react-transition-group` itself:\n\n```tsx\nimport {\n  CSSTransition,\n  SwitchTransition,\n  Transition,\n  TransitionGroup,\n} from \"react-transition-group\";\n```\n\nDo not write application imports against `@types/react-transition-group`.\n\n## Common Workflows\n\n### Animate a single element with `CSSTransition`\n\n`CSSTransition` is the most common entry point for class-based enter and exit animations.\n\n```tsx\nimport { useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\n\nexport function SaveNotice() {\n  const [open, setOpen] = useState(false);\n  const nodeRef = useRef<HTMLDivElement>(null);\n\n  return (\n    <>\n      <button onClick={() => setOpen((value) => !value)}>Toggle</button>\n\n      <CSSTransition\n        in={open}\n        nodeRef={nodeRef}\n        timeout={200}\n        classNames=\"fade\"\n        unmountOnExit\n      >\n        <div ref={nodeRef}>Saved</div>\n      </CSSTransition>\n    </>\n  );\n}\n```\n\nMatch the `classNames` prefix with CSS that covers the same timeout:\n\n```css\n.fade-enter {\n  opacity: 0;\n}\n\n.fade-enter-active {\n  opacity: 1;\n  transition: opacity 200ms ease-in;\n}\n\n.fade-exit {\n  opacity: 1;\n}\n\n.fade-exit-active {\n  opacity: 0;\n  transition: opacity 200ms ease-out;\n}\n```\n\n### Render from transition state with `Transition`\n\nUse `Transition` when you want inline styles or custom rendering logic instead of CSS class management.\n\n```tsx\nimport { type CSSProperties, useRef, useState } from \"react\";\nimport { Transition } from \"react-transition-group\";\n\nconst duration = 180;\n\nconst defaultStyle: CSSProperties = {\n  opacity: 0,\n  transition: `opacity ${duration}ms ease-in-out`,\n};\n\nconst transitionStyles: Record<string, CSSProperties> = {\n  entering: { opacity: 1 },\n  entered: { opacity: 1 },\n  exiting: { opacity: 0 },\n  exited: { opacity: 0 },\n};\n\nexport function InlineFade() {\n  const [open, setOpen] = useState(false);\n  const nodeRef = useRef<HTMLDivElement>(null);\n\n  return (\n    <>\n      <button onClick={() => setOpen((value) => !value)}>Toggle</button>\n\n      <Transition in={open} timeout={duration} nodeRef={nodeRef} mountOnEnter unmountOnExit>\n        {(state) => (\n          <div ref={nodeRef} style={{ ...defaultStyle, ...(transitionStyles[state] ?? {}) }}>\n            Animated content\n          </div>\n        )}\n      </Transition>\n    </>\n  );\n}\n```\n\nThe `state` render-prop value is inferred from the transition lifecycle, so TypeScript can help keep your style map aligned with the runtime states.\n\n### Animate list items with `TransitionGroup`\n\nUse `TransitionGroup` when items enter and leave a collection. Keep a stable `key` and a separate `nodeRef` for each keyed child.\n\n```tsx\nimport { createRef, type RefObject, useRef } from \"react\";\nimport { CSSTransition, TransitionGroup } from \"react-transition-group\";\n\ntype Todo = {\n  id: string;\n  label: string;\n};\n\nexport function TodoList({ items }: { items: Todo[] }) {\n  const nodeRefs = useRef<Record<string, RefObject<HTMLLIElement | null>>>({});\n\n  const getNodeRef = (id: string) => {\n    nodeRefs.current[id] ??= createRef<HTMLLIElement>();\n    return nodeRefs.current[id];\n  };\n\n  return (\n    <TransitionGroup component=\"ul\">\n      {items.map((item) => {\n        const nodeRef = getNodeRef(item.id);\n\n        return (\n          <CSSTransition key={item.id} nodeRef={nodeRef} timeout={150} classNames=\"todo\">\n            <li ref={nodeRef}>{item.label}</li>\n          </CSSTransition>\n        );\n      })}\n    </TransitionGroup>\n  );\n}\n```\n\n### Replace one child with another using `SwitchTransition`\n\n`SwitchTransition` is useful when exactly one child is shown at a time and the child changes by key.\n\n```tsx\nimport { useRef, useState } from \"react\";\nimport { CSSTransition, SwitchTransition } from \"react-transition-group\";\n\nexport function StatusBadge() {\n  const [state, setState] = useState<\"saved\" | \"saving\">(\"saved\");\n  const nodeRef = useRef<HTMLSpanElement>(null);\n\n  return (\n    <>\n      <button onClick={() => setState((value) => (value === \"saved\" ? \"saving\" : \"saved\"))}>\n        Toggle status\n      </button>\n\n      <SwitchTransition mode=\"out-in\">\n        <CSSTransition key={state} nodeRef={nodeRef} timeout={180} classNames=\"fade\">\n          <span ref={nodeRef}>{state}</span>\n        </CSSTransition>\n      </SwitchTransition>\n    </>\n  );\n}\n```\n\n## Important Pitfalls\n\n- `@types/react-transition-group` does not include runtime JavaScript. Install `react-transition-group` itself.\n- Import from `\"react-transition-group\"`, not from `\"@types/react-transition-group\"`.\n- Use `nodeRef` in modern React apps, especially under `StrictMode`, so the library does not fall back to `findDOMNode`.\n- When you pass `nodeRef`, transition callbacks no longer receive the DOM node argument; read from the ref you supplied instead.\n- Keep the `timeout` prop aligned with your real CSS durations or the transition state and class cleanup will not match the visual animation.\n- In `TransitionGroup`, each keyed child should keep its own stable ref object. Reusing one ref across different keys causes incorrect typing and incorrect runtime behavior.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/react-transition-group==4.4.12`.\n- The declaration package is for the `react-transition-group` runtime API, so keep the types aligned with the runtime major version used in the same project.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/react-transition-group\n- DefinitelyTyped source for `@types/react-transition-group`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-transition-group\n- `@types/react-transition-group` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-transition-group/index.d.ts\n- `Transition` docs: https://reactcommunity.org/react-transition-group/transition/\n- `CSSTransition` docs: https://reactcommunity.org/react-transition-group/css-transition/\n- `TransitionGroup` docs: https://reactcommunity.org/react-transition-group/transition-group/\n- `SwitchTransition` docs: https://reactcommunity.org/react-transition-group/switch-transition/\n"
  },
  {
    "path": "content/typescript/docs/react-virtualized/typescript/DOC.md",
    "content": "---\nname: react-virtualized\ndescription: \"TypeScript declarations for react-virtualized lists, tables, AutoSizer, InfiniteLoader, and CellMeasurer workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"9.22.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,react,react-virtualized,virtualization,list,table,types,definitelytyped\"\n---\n\n# react-virtualized TypeScript Guide\n\n`@types/react-virtualized` provides the TypeScript declarations for the `react-virtualized` runtime package. Install it when your React app renders virtualized lists, tables, or measurement helpers and you want typed component props and callback signatures.\n\nThis package only ships `.d.ts` files. Your application imports from `react-virtualized`; TypeScript reads the declarations from `@types/react-virtualized`.\n\n## Install\n\nInstall the runtime package first, then add the declaration package and the React TypeScript dependencies.\n\n```bash\nnpm install react react-dom react-virtualized\nnpm install -D typescript @types/react @types/react-dom @types/react-virtualized\n```\n\nIf your app already has React and `react-virtualized`, add only the missing type package:\n\n```bash\nnpm install -D @types/react-virtualized\n```\n\nKeep `react-virtualized` and `@types/react-virtualized` aligned when you upgrade.\n\nThere are no environment variables, authentication settings, or client initialization objects to configure.\n\n## TypeScript Setup\n\nImport from `react-virtualized`, not from `@types/react-virtualized`.\n\nFor a browser React app, keep JSX and DOM libraries enabled:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"ES2022\", \"DOM\"]\n  }\n}\n```\n\nTypeScript usually discovers the declarations automatically once `@types/react-virtualized` is installed.\n\n## Common Workflows\n\n### Render a typed virtualized list\n\nDerive callback argument types from the component props when you want the declaration package to drive your local helper signatures.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport { AutoSizer, List } from \"react-virtualized\";\n\ntype TodoRow = {\n  id: string;\n  title: string;\n};\n\ntype ListRowRendererProps = Parameters<\n  NonNullable<ComponentProps<typeof List>[\"rowRenderer\"]>\n>[0];\n\nexport function TodoList({ rows }: { rows: TodoRow[] }) {\n  function rowRenderer({ index, key, style }: ListRowRendererProps) {\n    const row = rows[index];\n\n    return (\n      <div key={key} style={style}>\n        {row.title}\n      </div>\n    );\n  }\n\n  return (\n    <div style={{ height: 400 }}>\n      <AutoSizer>\n        {({ height, width }) => (\n          <List\n            height={height}\n            width={width}\n            rowCount={rows.length}\n            rowHeight={48}\n            rowRenderer={rowRenderer}\n          />\n        )}\n      </AutoSizer>\n    </div>\n  );\n}\n```\n\n`AutoSizer` measures its parent, so the wrapper element must have a real height and width at render time.\n\n### Type custom table cells\n\nFor `Table` and `Column`, derive the renderer argument type from the `Column` props so your custom cell logic stays aligned with the installed declarations.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport { Column, Table } from \"react-virtualized\";\n\ntype UserRow = {\n  id: string;\n  email: string;\n  logins: number;\n};\n\ntype ColumnCellRendererProps = Parameters<\n  NonNullable<ComponentProps<typeof Column>[\"cellRenderer\"]>\n>[0];\n\nfunction renderLoginsCell({ cellData }: ColumnCellRendererProps) {\n  return <strong>{cellData}</strong>;\n}\n\nexport function UsersTable({ rows }: { rows: UserRow[] }) {\n  return (\n    <Table\n      width={720}\n      height={320}\n      headerHeight={40}\n      rowHeight={44}\n      rowCount={rows.length}\n      rowGetter={({ index }) => rows[index]}\n    >\n      <Column label=\"Email\" dataKey=\"email\" width={420} />\n      <Column\n        label=\"Logins\"\n        dataKey=\"logins\"\n        width={120}\n        cellRenderer={renderLoginsCell}\n      />\n    </Table>\n  );\n}\n```\n\nKeep the `dataKey` values in sync with the object shape returned by `rowGetter()`.\n\n### Type incremental loading with `InfiniteLoader`\n\n`InfiniteLoader` is a practical place to derive request ranges from the declaration package instead of duplicating `{ startIndex, stopIndex }` shapes by hand.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport { InfiniteLoader, List } from \"react-virtualized\";\n\ntype TodoRow = {\n  id: string;\n  title: string;\n};\n\ntype LoadMoreRowsArgs = Parameters<\n  NonNullable<ComponentProps<typeof InfiniteLoader>[\"loadMoreRows\"]>\n>[0];\n\ntype IsRowLoadedArgs = Parameters<\n  NonNullable<ComponentProps<typeof InfiniteLoader>[\"isRowLoaded\"]>\n>[0];\n\ntype ListRowRendererProps = Parameters<\n  NonNullable<ComponentProps<typeof List>[\"rowRenderer\"]>\n>[0];\n\ntype RemoteListProps = {\n  rowCount: number;\n  rows: TodoRow[];\n  loadRange: (startIndex: number, stopIndex: number) => Promise<void>;\n};\n\nexport function RemoteTodoList({ rowCount, rows, loadRange }: RemoteListProps) {\n  function isRowLoaded({ index }: IsRowLoadedArgs) {\n    return index < rows.length;\n  }\n\n  async function loadMoreRows({ startIndex, stopIndex }: LoadMoreRowsArgs) {\n    await loadRange(startIndex, stopIndex);\n  }\n\n  function rowRenderer({ index, key, style }: ListRowRendererProps) {\n    const row = rows[index];\n\n    return (\n      <div key={key} style={style}>\n        {row ? row.title : \"Loading...\"}\n      </div>\n    );\n  }\n\n  return (\n    <InfiniteLoader\n      isRowLoaded={isRowLoaded}\n      loadMoreRows={loadMoreRows}\n      rowCount={rowCount}\n    >\n      {({ onRowsRendered, registerChild }) => (\n        <List\n          ref={registerChild}\n          height={400}\n          width={720}\n          rowCount={rowCount}\n          rowHeight={48}\n          onRowsRendered={onRowsRendered}\n          rowRenderer={rowRenderer}\n        />\n      )}\n    </InfiniteLoader>\n  );\n}\n```\n\n### Measure dynamic row heights with `CellMeasurer`\n\nFor variable-height content, pair `CellMeasurer` with `CellMeasurerCache` and pass the cache back into `List`.\n\n```tsx\nimport { type ComponentProps } from \"react\";\nimport {\n  AutoSizer,\n  CellMeasurer,\n  CellMeasurerCache,\n  List,\n} from \"react-virtualized\";\n\ntype ArticleRow = {\n  id: string;\n  title: string;\n  summary: string;\n};\n\ntype ListRowRendererProps = Parameters<\n  NonNullable<ComponentProps<typeof List>[\"rowRenderer\"]>\n>[0];\n\nconst cache = new CellMeasurerCache({\n  defaultHeight: 80,\n  fixedWidth: true,\n});\n\nexport function ArticleList({ rows }: { rows: ArticleRow[] }) {\n  function rowRenderer({ index, key, parent, style }: ListRowRendererProps) {\n    const row = rows[index];\n\n    return (\n      <CellMeasurer\n        cache={cache}\n        columnIndex={0}\n        key={key}\n        parent={parent}\n        rowIndex={index}\n      >\n        <div style={style}>\n          <h3>{row.title}</h3>\n          <p>{row.summary}</p>\n        </div>\n      </CellMeasurer>\n    );\n  }\n\n  return (\n    <div style={{ height: 480 }}>\n      <AutoSizer>\n        {({ height, width }) => (\n          <List\n            deferredMeasurementCache={cache}\n            height={height}\n            rowCount={rows.length}\n            rowHeight={cache.rowHeight}\n            rowRenderer={rowRenderer}\n            width={width}\n          />\n        )}\n      </AutoSizer>\n    </div>\n  );\n}\n```\n\n## Common Pitfalls\n\n- Install `react-virtualized` separately; `@types/react-virtualized` does not include runtime JavaScript.\n- Import components from `react-virtualized`, not from `@types/react-virtualized`.\n- Give `AutoSizer` a parent element with a non-zero size or it will pass unusable dimensions.\n- Pass concrete numeric `height`, `width`, `rowCount`, and row sizing values into `List` and `Table`.\n- Keep JSX and DOM libraries enabled in browser projects so React element and style types resolve normally.\n- Reuse a `CellMeasurerCache` instance instead of recreating it during each render.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/react-virtualized\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-virtualized\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-virtualized/index.d.ts\n- https://www.npmjs.com/package/react-virtualized\n- https://github.com/bvaughn/react-virtualized\n- https://github.com/bvaughn/react-virtualized/blob/master/docs/README.md\n"
  },
  {
    "path": "content/typescript/docs/redis/typescript/DOC.md",
    "content": "---\nname: redis\ndescription: \"TypeScript guidance for Redis projects, including when `@types/redis` matters and when the `redis` runtime package already provides the types you need\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.0.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,redis,node-redis,types,definitelytyped\"\n---\n\n# Redis TypeScript Guide\n\n`@types/redis` is a declaration package for Redis usage in TypeScript, but modern Node Redis projects should write application code against the `redis` runtime package itself.\n\nUse this rule in practice:\n\n- Install `redis` when your app actually connects to Redis.\n- Import from `\"redis\"`, not from `\"@types/redis\"`.\n- Add `@types/redis@4.0.11` only when an existing codebase, dependency, or build setup explicitly requires that separate declaration package.\n\nThe declaration package does not install a Redis server or the Node Redis runtime client.\n\n## Install\n\nFor a normal TypeScript application, install the runtime package and the Node declarations your project usually needs:\n\n```bash\nnpm install redis\nnpm install --save-dev typescript @types/node\n```\n\nOnly add the separate declaration package when you have a specific compatibility reason to keep it:\n\n```bash\nnpm install --save-dev @types/redis@4.0.11\n```\n\nIf you are starting a new project on current `redis`, prefer the runtime package's own TypeScript support and skip the extra `@types/redis` dependency.\n\n## TypeScript Setup\n\nNo special Redis-specific `tsconfig.json` setting is required just to consume the client types.\n\nIf your project restricts loaded global type packages, keep Node globals available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"types\": [\"node\"]\n  }\n}\n```\n\nThe important boundary is that module typings come from the `redis` package you import in application code.\n\n## Initialization\n\nLoad connection settings from the environment and create the client from `redis`:\n\n```env\nREDIS_URL=redis://default:secret@localhost:6379/0\n```\n\n```ts\nimport \"dotenv/config\";\nimport { createClient } from \"redis\";\n\nconst client = createClient({\n  url: process.env.REDIS_URL ?? \"redis://localhost:6379/0\",\n});\n\nclient.on(\"error\", (err) => {\n  console.error(\"Redis Client Error\", err);\n});\n\nawait client.connect();\n```\n\nDo not import anything from `@types/redis` directly. The package exists for declarations only.\n\n## Common Workflow: Typed JSON Helpers\n\nRedis stores strings and binary values. In TypeScript code, the practical pattern is to add small typed wrappers at the application boundary.\n\n```ts\nimport \"dotenv/config\";\nimport { createClient } from \"redis\";\n\ntype Session = {\n  userId: string;\n  roles: string[];\n};\n\nconst client = createClient({\n  url: process.env.REDIS_URL ?? \"redis://localhost:6379/0\",\n});\n\nclient.on(\"error\", (err) => {\n  console.error(\"Redis Client Error\", err);\n});\n\nawait client.connect();\n\nasync function setJson(key: string, value: unknown, ttlSeconds?: number) {\n  const payload = JSON.stringify(value);\n\n  if (ttlSeconds !== undefined) {\n    await client.set(key, payload, { EX: ttlSeconds });\n    return;\n  }\n\n  await client.set(key, payload);\n}\n\nasync function getJson<T>(key: string): Promise<T | null> {\n  const value = await client.get(key);\n\n  return value ? (JSON.parse(value) as T) : null;\n}\n\nawait setJson(\"session:123\", { userId: \"u_123\", roles: [\"admin\"] }, 900);\n\nconst session = await getJson<Session>(\"session:123\");\n\nif (session) {\n  console.log(session.userId);\n  console.log(session.roles.includes(\"admin\"));\n}\n\nawait client.quit();\n```\n\nThis keeps Redis calls simple while preserving strong types in the rest of your code.\n\n## Common Workflow: Narrow Command Results Before Use\n\nRedis command results are often nullable. Guard them before passing values deeper into your app.\n\n```ts\nimport { createClient } from \"redis\";\n\nconst client = createClient();\nawait client.connect();\n\nconst rawCount = await client.get(\"retry-count\");\n\nconst retryCount = rawCount === null ? 0 : Number.parseInt(rawCount, 10);\n\nif (Number.isNaN(retryCount)) {\n  throw new Error(\"retry-count is not an integer\");\n}\n\nawait client.quit();\n```\n\nTreat `string | null` and parsed JSON as boundary types. Convert them once and keep the rest of your code strongly typed.\n\n## Pitfalls\n\n### Do not import from `@types/redis`\n\nThis is wrong:\n\n```ts\nimport \"@types/redis\";\n```\n\nUse the runtime package instead:\n\n```ts\nimport { createClient } from \"redis\";\n```\n\n### Do not install the type package instead of the runtime package\n\nThis package does not create network connections, expose Redis commands at runtime, or start a Redis server. Your app still needs the `redis` dependency.\n\n### Avoid duplicate type sources\n\nIf your project already uses a `redis` release that ships its own declarations, adding `@types/redis` can create unnecessary duplication. Prefer the runtime package's bundled typings for new work.\n\n## Version Notes\n\nThis guide is scoped to `@types/redis@4.0.11`.\n\nFor current application code, the practical TypeScript integration point is still the `redis` package API:\n\n- `createClient()` to create a client\n- `client.connect()` before issuing commands\n- `client.get()` and `client.set()` for key-value access\n- `client.quit()` for graceful shutdown\n\nIf you are updating an older project that still carries `@types/redis`, keep your imports and runtime usage centered on `redis`, then remove the extra declaration package once the project no longer depends on it.\n"
  },
  {
    "path": "content/typescript/docs/request/typescript/DOC.md",
    "content": "---\nname: request\ndescription: \"TypeScript guide for the `request` HTTP client declarations, including installation, CommonJS imports, typed callbacks, shared defaults, and JSON response handling.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.48.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,request,http,nodejs,types,definitelytyped\"\n---\n\n# request TypeScript Guide\n\n## Golden Rule\n\nInstall `request` for runtime behavior and `@types/request` for TypeScript declarations.\n\n`@types/request` only provides `.d.ts` files for the `request` module. Your code still imports and executes `request` itself.\n\n## Install\n\nInstall the runtime package first, then the TypeScript declarations your Node.js app needs:\n\n```bash\nnpm install request\nnpm install -D typescript @types/node @types/request\n```\n\n`request` does not require package-level initialization, credentials, or environment variables. Authentication is configured per request or through a shared `request.defaults(...)` wrapper.\n\n## Initialize In TypeScript\n\n`@types/request` uses CommonJS-style exports, so the most portable import form is:\n\n```typescript\nimport request = require(\"request\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport request from \"request\";\n```\n\nIf you restrict loaded declaration packages with `compilerOptions.types`, keep the Node and request types available to the project:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"module\": \"commonjs\",\n    \"esModuleInterop\": true,\n    \"types\": [\"node\", \"request\"]\n  }\n}\n```\n\n## Common Workflows\n\n### Fetch JSON And Narrow The Response Body\n\n`json: true` tells `request` to parse JSON responses, but it does not prove that the remote API returned the shape your app expects. Validate or narrow the result before using it.\n\n```typescript\nimport request = require(\"request\");\n\ntype Todo = {\n  userId: number;\n  id: number;\n  title: string;\n  completed: boolean;\n};\n\nfunction isTodo(value: unknown): value is Todo {\n  if (!value || typeof value !== \"object\") {\n    return false;\n  }\n\n  const record = value as Record<string, unknown>;\n\n  return (\n    typeof record.userId === \"number\" &&\n    typeof record.id === \"number\" &&\n    typeof record.title === \"string\" &&\n    typeof record.completed === \"boolean\"\n  );\n}\n\nrequest.get(\n  {\n    url: \"https://jsonplaceholder.typicode.com/todos/1\",\n    json: true,\n    timeout: 10_000,\n    headers: {\n      \"user-agent\": \"my-app/1.0\",\n    },\n  },\n  (error, response, body) => {\n    if (error) {\n      throw error;\n    }\n\n    if (response.statusCode !== 200) {\n      throw new Error(`Unexpected status: ${response.statusCode}`);\n    }\n\n    if (!isTodo(body)) {\n      throw new Error(\"Response body did not match Todo\");\n    }\n\n    console.log(body.title);\n  }\n);\n```\n\n### Reuse Auth And Base Settings With `request.defaults`\n\nFor applications that talk to the same API repeatedly, create a preconfigured requester instead of copying headers and timeouts into every call.\n\n```typescript\nimport request = require(\"request\");\n\nconst { API_BASE_URL, API_TOKEN } = process.env;\n\nif (!API_BASE_URL || !API_TOKEN) {\n  throw new Error(\"Set API_BASE_URL and API_TOKEN before starting the app\");\n}\n\nconst api = request.defaults({\n  baseUrl: API_BASE_URL,\n  json: true,\n  timeout: 10_000,\n  headers: {\n    authorization: `Bearer ${API_TOKEN}`,\n    \"user-agent\": \"my-app/1.0\",\n  },\n});\n\napi.get(\"/v1/users/me\", (error, response, body) => {\n  if (error) {\n    throw error;\n  }\n\n  if (response.statusCode !== 200) {\n    throw new Error(`Unexpected status: ${response.statusCode}`);\n  }\n\n  console.log(body);\n});\n```\n\nThis is the closest thing `request` has to client initialization. The runtime stays callback-based, but you can centralize auth headers, JSON mode, proxies, timeouts, and other shared options in one place.\n\n### Send JSON In A POST Request\n\nWhen you pass `json: true`, `request` will JSON-encode object request bodies and parse JSON responses.\n\n```typescript\nimport request = require(\"request\");\n\ntype CreateUserInput = {\n  email: string;\n  name: string;\n};\n\nconst payload: CreateUserInput = {\n  email: \"alice@example.com\",\n  name: \"Alice\",\n};\n\nrequest.post(\n  {\n    url: `${process.env.API_BASE_URL}/v1/users`,\n    json: true,\n    body: payload,\n    headers: {\n      authorization: `Bearer ${process.env.API_TOKEN}`,\n      \"user-agent\": \"my-app/1.0\",\n    },\n  },\n  (error, response, body) => {\n    if (error) {\n      throw error;\n    }\n\n    if (response.statusCode !== 201) {\n      throw new Error(`Unexpected status: ${response.statusCode}`);\n    }\n\n    console.log(body);\n  }\n);\n```\n\nIf your environment variables are required, check them once during startup and fail early instead of relying on non-null assertions throughout the codebase.\n\n### Keep Session Cookies In A Jar\n\nUse `request.jar()` when you need a shared cookie store across multiple requests.\n\n```typescript\nimport request = require(\"request\");\n\nconst { APP_ORIGIN } = process.env;\n\nif (!APP_ORIGIN) {\n  throw new Error(\"Set APP_ORIGIN before starting the app\");\n}\n\nconst jar = request.jar();\njar.setCookie(request.cookie(\"session=abc123\"), APP_ORIGIN);\n\nrequest.get(\n  {\n    url: `${APP_ORIGIN}/account`,\n    jar,\n    followRedirect: true,\n  },\n  (error, response, body) => {\n    if (error) {\n      throw error;\n    }\n\n    console.log(response.statusCode, body);\n  }\n);\n```\n\nThis pattern matters in TypeScript because the cookie jar comes from the `request` runtime surface, not from a separate client instance.\n\n### Wrap `request` At The Promise Boundary\n\nThe declaration package types the callback-based API. If the rest of your app uses `async` and `await`, wrap `request` once and return typed promises from your own helper.\n\n```typescript\nimport request = require(\"request\");\n\nasync function getJson<T>(url: string): Promise<T> {\n  return await new Promise<T>((resolve, reject) => {\n    request.get({ url, json: true }, (error, response, body) => {\n      if (error) {\n        reject(error);\n        return;\n      }\n\n      if (response.statusCode !== 200) {\n        reject(new Error(`Unexpected status: ${response.statusCode}`));\n        return;\n      }\n\n      resolve(body as T);\n    });\n  });\n}\n\ntype HealthResponse = {\n  status: string;\n};\n\nconst health = await getJson<HealthResponse>(\"https://example.com/health\");\nconsole.log(health.status);\n```\n\nThis keeps the untyped network boundary small. Your application code can then work with `Promise<T>` while still using the published `request` API surface underneath.\n\n## Common Pitfalls\n\n- Install `request` as well as `@types/request`; the type package does not include runtime code.\n- Import from `\"request\"`, not from `\"@types/request\"`.\n- Prefer `import request = require(\"request\")` unless your project already enables TypeScript interop flags for default imports.\n- `json: true` changes runtime parsing, but it does not validate third-party API responses against your TypeScript interfaces.\n- If you use `compilerOptions.types`, include both `node` and `request` so the module and Node globals resolve correctly.\n- `request` is callback-first. If your codebase is promise-first, wrap it at one boundary instead of mixing callback logic throughout the app.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/request\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/request\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/request/index.d.ts\n- https://www.npmjs.com/package/request\n- https://github.com/request/request\n"
  },
  {
    "path": "content/typescript/docs/restify/typescript/DOC.md",
    "content": "---\nname: restify\ndescription: \"TypeScript declarations for Restify servers, requests, responses, plugins, and application-level request augmentation.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.5.12\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,restify,node,http,server,types,definitelytyped\"\n---\n\n# Restify TypeScript Guide\n\n`@types/restify` adds TypeScript declarations for the `restify` runtime package. In practice, it matters most in four places:\n\n- creating and configuring a Restify server with `restify.createServer()`\n- typing handlers with `Request`, `Response`, `Next`, and `Server`\n- using the built-in plugins namespace such as `restify.plugins.queryParser()` and `restify.plugins.bodyParser()`\n- extending the request shape in your own app with module augmentation\n\nThis package only ships `.d.ts` files. Install `restify` itself for runtime behavior.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declarations:\n\n```bash\nnpm install restify\nnpm install -D typescript @types/node @types/restify\n```\n\nIf your project already has `restify`, add only the missing type packages:\n\n```bash\nnpm install -D @types/node @types/restify\n```\n\n`@types/restify` does not require package-specific environment variables or credentials. A typical local setup still uses application-level network settings:\n\n```bash\nexport PORT=8080\nexport HOST=0.0.0.0\n```\n\n## TypeScript Setup\n\nThe declaration package models a CommonJS-style export. If your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import is fine:\n\n```typescript\nimport restify from \"restify\";\n```\n\nWithout interop, use the CommonJS-compatible import form:\n\n```typescript\nimport restify = require(\"restify\");\n```\n\nIf your project restricts loaded type packages with `compilerOptions.types`, include the packages your server build depends on:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\", \"restify\"]\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\"]\n}\n```\n\nIf you do not use `compilerOptions.types`, you usually do not need to add anything special.\n\n## Initialize A Restify Server\n\nThere is no separate client or auth object to initialize. The runtime boundary is the `restify` server itself.\n\n```typescript\nimport restify = require(\"restify\");\n\nconst port = Number(process.env.PORT ?? \"8080\");\nconst host = process.env.HOST ?? \"0.0.0.0\";\n\nconst server = restify.createServer({\n  name: \"example-api\",\n  version: \"1.0.0\",\n});\n\nserver.use(restify.plugins.queryParser());\nserver.use(restify.plugins.bodyParser());\n\nserver.get(\"/health\", (_req, res, next) => {\n  res.send({ ok: true });\n  return next();\n});\n\nserver.listen(port, host, () => {\n  console.log(\"%s listening at %s\", server.name, server.url);\n});\n```\n\nThis is the basic pattern the declarations are designed around: create a server, register plugins, add routes, and listen.\n\n## Common Workflows\n\n### Type route params and request bodies at the app boundary\n\nRestify request data is dynamic at runtime. A practical pattern is to define your application types and narrow `req.params` or `req.body` before using them.\n\n```typescript\nimport restify = require(\"restify\");\n\ntype CreateUserBody = {\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\nfunction isCreateUserBody(value: unknown): value is CreateUserBody {\n  if (!value || typeof value !== \"object\") {\n    return false;\n  }\n\n  const body = value as Record<string, unknown>;\n\n  return typeof body.email === \"string\"\n    && (body.role === \"admin\" || body.role === \"member\");\n}\n\nconst server = restify.createServer();\n\nserver.use(restify.plugins.bodyParser());\n\nserver.post(\"/accounts/:accountId/users\", (req, res, next) => {\n  const { accountId } = req.params as { accountId: string };\n  const body = req.body as unknown;\n\n  if (!isCreateUserBody(body)) {\n    return next(new restify.errors.BadRequestError(\"Invalid request body\"));\n  }\n\n  res.send(201, {\n    accountId,\n    email: body.email,\n    role: body.role,\n  });\n\n  return next();\n});\n```\n\nThis keeps the type boundary explicit: Restify parses the request, and your application decides when the parsed data is trustworthy enough to use.\n\n### Augment `Request` for app-specific middleware\n\nWhen middleware attaches data to the request object, extend the exported `Request` interface in a project `.d.ts` file.\n\nCreate a declaration file such as `src/types/restify.d.ts`:\n\n```typescript\ndeclare module \"restify\" {\n  interface Request {\n    requestId?: string;\n  }\n}\n\nexport {};\n```\n\nThen use the augmented property in middleware and handlers:\n\n```typescript\nimport { randomUUID } from \"node:crypto\";\nimport restify = require(\"restify\");\n\nconst server = restify.createServer();\n\nserver.use((req, _res, next) => {\n  const headerValue = req.headers[\"x-request-id\"];\n  const requestId = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n\n  req.requestId = requestId ?? randomUUID();\n  return next();\n});\n\nserver.get(\"/ping\", (req, res, next) => {\n  res.send({ requestId: req.requestId });\n  return next();\n});\n```\n\nThis is the main customization point most Restify TypeScript apps need.\n\n### Use the typed plugin namespace\n\nThe declarations include the built-in plugin helpers exposed under `restify.plugins`.\n\n```typescript\nimport restify = require(\"restify\");\n\nconst server = restify.createServer();\n\nserver.use(restify.plugins.acceptParser(server.acceptable));\nserver.use(restify.plugins.queryParser());\nserver.use(restify.plugins.bodyParser());\n```\n\nRegister only the parsers your routes depend on. For example, `req.query` is only useful if your app enables query parsing, and `req.body` depends on the body parser running before the route.\n\n## Important Pitfalls\n\n- Install `restify` as well as `@types/restify`; the declaration package does not include runtime code.\n- Import from `restify`, not from `@types/restify`.\n- Without TypeScript interop settings, prefer `import restify = require(\"restify\")` over a default import.\n- Keep your project `.d.ts` files inside the paths matched by `tsconfig.json` `include` or `files`, or module augmentation will appear not to work.\n- Treat `req.params`, `req.query`, and `req.body` as application input, not as already-validated domain objects.\n- The request properties available at runtime depend on the Restify plugins and options you register before your routes.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/restify==8.5.12`.\n- The published declarations model the classic Restify server API built around `createServer()`, route handlers, the `plugins` namespace, and the exported request and response types.\n- The declaration package is separate from the `restify` runtime, so keep your runtime version aligned with the API surface the typings model.\n- The declaration entrypoint uses a CommonJS export style, so your preferred import form depends on your TypeScript interop settings.\n\n## Official Sources\n\n- npm package page for `@types/restify`: https://www.npmjs.com/package/@types/restify\n- DefinitelyTyped source for `@types/restify`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/restify\n- `@types/restify` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/restify/index.d.ts\n- Restify runtime package page: https://www.npmjs.com/package/restify\n- Restify documentation home: https://restify.com/docs/home/\n- Restify server API: https://restify.com/docs/server-api/\n- Restify plugins API: https://restify.com/docs/plugins-api/\n"
  },
  {
    "path": "content/typescript/docs/rimraf/typescript/DOC.md",
    "content": "---\nname: rimraf\ndescription: \"TypeScript guidance for `rimraf`, including the `@types/rimraf` package entry, typed imports, Promise-based deletion, and opt-in glob usage.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.0.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,rimraf,node,filesystem,types,npm\"\n---\n\n# rimraf TypeScript Guide\n\n## Golden Rule\n\nUse `rimraf` in application code.\n\nThe practical TypeScript integration boundary is the runtime package: current `rimraf` publishes its own declarations, a `types` entry, and typed ESM/CommonJS exports. Import values and types from `\"rimraf\"`, not from `@types/rimraf`.\n\n## Install\n\nInstall the runtime package and the normal TypeScript toolchain for a Node.js project:\n\n```bash\nnpm install rimraf\nnpm install -D typescript @types/node\n```\n\nIf your project already lists `@types/rimraf` directly, you usually do not need to import or reference it in code. The important dependency for current projects is `rimraf` itself.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe setup that matters is your TypeScript compiler configuration and your import style.\n\n### Recommended `tsconfig.json`\n\n`rimraf` publishes typed ESM and CommonJS entry points. For a Node.js project, a practical compiler setup is:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, include `node`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n## Import Patterns\n\nUse named imports from `rimraf`:\n\n```ts\nimport {\n  rimraf,\n  rimrafSync,\n  native,\n  type RimrafAsyncOptions,\n  type RimrafSyncOptions,\n} from \"rimraf\";\n```\n\nIn CommonJS, require the runtime package:\n\n```ts\nconst { rimraf, rimrafSync, native } = require(\"rimraf\");\n```\n\nDo not rely on a default import for current `rimraf` releases.\n\n## Common Workflows\n\n### Remove build output asynchronously\n\n`rimraf()` accepts a path or an array of paths and returns a `Promise<boolean>`.\n\n```ts\nimport { rimraf, type RimrafAsyncOptions } from \"rimraf\";\n\nconst options: RimrafAsyncOptions = {\n  glob: false,\n  preserveRoot: true,\n};\n\nconst removed = await rimraf([\"dist\", \"coverage\"], options);\n\nif (!removed) {\n  throw new Error(\"Some paths were preserved by a filter\");\n}\n```\n\nFor normal deletions without a `filter`, the resolved value is typically `true`.\n\n### Opt in to glob patterns\n\nSince `rimraf` v4, globbing is not implicit. Set `glob: true` or pass a `glob` options object when you want pattern matching.\n\n```ts\nimport { rimraf } from \"rimraf\";\n\nawait rimraf(\"packages/*/dist\", { glob: true });\n```\n\nIf you do not opt in to globbing, treat the path as literal.\n\n### Keep selected files with a typed filter\n\nThe async API accepts a typed `filter` callback. When a filter keeps some entries, the returned boolean can be `false`.\n\n```ts\nimport { rimraf, type RimrafAsyncOptions } from \"rimraf\";\n\nconst options: RimrafAsyncOptions = {\n  filter: (path, entry) => {\n    if (entry.isDirectory()) {\n      return true;\n    }\n\n    return !path.endsWith(\".keep\");\n  },\n};\n\nconst removedAll = await rimraf(\"tmp\", options);\n\nconsole.log({ removedAll });\n```\n\nThe filter receives the path plus a `Dirent` or `Stats` object for that entry.\n\n### Use the synchronous API in scripts\n\n`rimrafSync()` uses the same path and options model, but returns a boolean directly.\n\n```ts\nimport { rimrafSync, type RimrafSyncOptions } from \"rimraf\";\n\nconst options: RimrafSyncOptions = {\n  glob: false,\n};\n\nconst removed = rimrafSync(\".cache\", options);\n\nconsole.log({ removed });\n```\n\nUse the async API when possible. The README notes that synchronous recursive deletion is typically slower than async deletion.\n\n### Run the CLI from package scripts\n\nThe package also ships a CLI.\n\n```bash\nnpx rimraf dist coverage\nnpx rimraf --glob \"packages/*/dist\"\n```\n\nQuote glob patterns so your shell does not expand them before `rimraf` receives them.\n\n## Important Pitfalls\n\n### Old callback examples are for pre-v4 code\n\nIf you find examples such as `rimraf(path, callback)`, they are from older versions. The v4+ API returns a `Promise` for async use instead of taking a callback.\n\n### Globbing is opt-in\n\n`rimraf(\"build/*\")` does not mean \"delete matching directories\" unless you also enable `glob`.\n\nUse one of these forms explicitly:\n\n```ts\nawait rimraf(\"build/*\", { glob: true });\nawait rimraf(\"build/output\", { glob: false });\n```\n\n### `filter` and `signal` can change the implementation path\n\nThe README notes that using `filter` or `signal` prevents `rimraf` from using Node's built-in `fs.rm`, because that implementation does not support those features.\n\nIf you need filtering or abort support, that is expected behavior.\n\n### Treat root deletion overrides with care\n\nThe CLI preserves `/` by default, and the API also protects root deletion unless you explicitly disable that safeguard with `preserveRoot: false`.\n\nOnly override this when you fully control the target path.\n\n## Version Note\n\nThis guide is written for the `@types/rimraf` `4.0.5` package entry on npm.\n\nFor practical TypeScript use, the important version-sensitive points are:\n\n- current `rimraf` publishes the declarations your project consumes\n- current `rimraf` uses named exports rather than a default export\n- v4 changed async removal from callback style to `Promise` style\n- v4 requires explicit glob opt-in\n- as documented in the maintainer README, the return value is boolean starting in `4.3`\n"
  },
  {
    "path": "content/typescript/docs/sass/typescript/DOC.md",
    "content": "---\nname: sass\ndescription: \"TypeScript guidance for Sass projects that encounter the @types/sass 1.45.0 package, covering built-in types, CLI setup, and programmatic compilation from TypeScript.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.45.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,sass,scss,css,build-tools,types\"\n---\n\n# Sass TypeScript Guide\n\n## Golden Rule\n\nFor application code, install `sass` and import from `\"sass\"`.\n\n`@types/sass@1.45.0` is not a runtime package. The practical TypeScript workflow is centered on the real `sass` package, which is the package your build scripts and application code should use.\n\nIn practice:\n\n- install `sass`\n- remove `@types/sass` if it is still listed in your project\n- import values and types from `sass`, never from `@types/sass`\n\n## Install\n\nInstall Sass with TypeScript as a development dependency:\n\n```bash\nnpm install -D sass typescript\n```\n\nIf your project already includes `@types/sass`, remove it:\n\n```bash\nnpm uninstall @types/sass\n```\n\nSass does not require credentials, API keys, service accounts, or package-specific environment variables.\n\n## Recommended Project Setup\n\n### Add Sass build scripts\n\nAdd scripts to `package.json` so local development and CI use the same commands:\n\n```json\n{\n  \"scripts\": {\n    \"build:css\": \"sass src/styles/app.scss public/app.css\",\n    \"watch:css\": \"sass --watch src/styles:public/styles\"\n  }\n}\n```\n\n`build:css` compiles one entry file to one output file. `watch:css` watches a source directory and writes compiled CSS files into a destination directory.\n\n### Use a normal TypeScript module setup\n\nYou do not need any Sass-specific `tsconfig.json` settings.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nYou also do not need to add `sass` to `compilerOptions.types`. The package exposes module declarations through `\"sass\"` itself.\n\n## Import And Use Sass In TypeScript\n\nUse the runtime package directly:\n\n```typescript\nimport * as sass from \"sass\";\n```\n\nThat import gives you the runtime compiler API and the package's bundled TypeScript declarations.\n\n### Compile an SCSS entry file\n\nUse `sass.compile()` when you have a file on disk and want a typed result object back.\n\n```typescript\nimport * as sass from \"sass\";\n\nexport function compileAppStyles(entryFile: string): sass.CompileResult {\n  return sass.compile(entryFile, {\n    loadPaths: [\"src/styles\"],\n    style: \"expanded\",\n    sourceMap: true,\n  });\n}\n\nconst result = compileAppStyles(\"src/styles/app.scss\");\n\nconsole.log(result.css);\nconsole.log(result.loadedUrls);\n```\n\n`loadPaths` lets Sass resolve `@use` and `@forward` from additional directories. `result.css` contains the compiled stylesheet string.\n\n### Compile a generated SCSS string\n\nUse `sass.compileString()` when your application builds SCSS dynamically.\n\n```typescript\nimport * as sass from \"sass\";\n\ntype Theme = \"light\" | \"dark\";\n\nexport function compileTheme(theme: Theme): string {\n  const result = sass.compileString(\n    `$theme: ${theme};\n\n    .card {\n      color: if($theme == light, #111827, #f9fafb);\n      background: if($theme == light, #ffffff, #111827);\n    }\n    `,\n    {\n      syntax: \"scss\",\n      style: \"compressed\",\n    },\n  );\n\n  return result.css;\n}\n```\n\nThis is the main TypeScript boundary for generated styles: your app controls the input string and configuration, while Sass returns compiled CSS.\n\n### Write compiled CSS from a TypeScript build script\n\nThis example reads app-specific environment variables, compiles one entry file, and writes both CSS and the source map.\n\n```typescript\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport * as sass from \"sass\";\n\nconst entryFile = process.env.SASS_ENTRY ?? \"src/styles/app.scss\";\nconst outFile = process.env.SASS_OUT ?? \"public/app.css\";\nconst style: \"expanded\" | \"compressed\" =\n  process.env.SASS_STYLE === \"compressed\" ? \"compressed\" : \"expanded\";\n\nexport async function buildStyles(): Promise<void> {\n  const result = sass.compile(entryFile, {\n    loadPaths: [\"src/styles\"],\n    style,\n    sourceMap: true,\n  });\n\n  await mkdir(dirname(outFile), { recursive: true });\n  await writeFile(outFile, result.css, \"utf8\");\n\n  if (result.sourceMap) {\n    await writeFile(`${outFile}.map`, JSON.stringify(result.sourceMap), \"utf8\");\n  }\n}\n```\n\nRun the build with app-defined environment variables if you want a different output path or CSS style:\n\n```bash\nSASS_ENTRY=src/styles/admin.scss SASS_OUT=public/admin.css SASS_STYLE=compressed node dist/build-styles.js\n```\n\nThese variables are your own build-script inputs, not settings required by Sass itself.\n\n## Common TypeScript Patterns\n\n### Type a helper around the compile result\n\nIf you wrap Sass in your own build utilities, return `sass.CompileResult` from the wrapper instead of reaching into internal declaration details.\n\n```typescript\nimport * as sass from \"sass\";\n\nexport function compileFile(entryFile: string, compressed = false): sass.CompileResult {\n  return sass.compile(entryFile, {\n    style: compressed ? \"compressed\" : \"expanded\",\n  });\n}\n```\n\nThis keeps the application boundary small and makes later Sass upgrades easier to localize.\n\n### Keep imports pointed at the runtime package\n\nEven for type-only imports, use `sass` as the module specifier.\n\n```typescript\nimport * as sass from \"sass\";\nimport type { CompileResult } from \"sass\";\n\nexport function readCss(result: CompileResult): string {\n  return result.css;\n}\n\nexport function compileAndRead(entryFile: string): string {\n  const result: sass.CompileResult = sass.compile(entryFile);\n  return readCss(result);\n}\n```\n\n## Important Pitfalls\n\n- `@types/sass` is not the package your application should import.\n- Install `sass` for both the compiler runtime and the bundled TypeScript declarations.\n- Import from `\"sass\"`, never from `\"@types/sass\"`.\n- You do not need to add `sass` to `compilerOptions.types`.\n- If your project shells out to the Sass CLI instead of importing the module, keep the typing boundary in your own Node or TypeScript wrapper code.\n- `loadPaths` affects how Sass resolves imports during compilation; if your stylesheet graph depends on extra lookup directories, define them explicitly.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/sass` package entry at version `1.45.0`.\n- For this package version, the practical TypeScript workflow is centered on the `sass` runtime package rather than on a standalone declaration package import path.\n\n## Official Sources\n\n- npm package page for `@types/sass`: https://www.npmjs.com/package/@types/sass\n- DefinitelyTyped source for `@types/sass`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/sass\n- npm package page for `sass`: https://www.npmjs.com/package/sass\n- Sass JavaScript API reference: https://sass-lang.com/documentation/js-api/\n- Sass JavaScript API for compiling files and strings: https://sass-lang.com/documentation/js-api/modules/\n"
  },
  {
    "path": "content/typescript/docs/selenium-webdriver/typescript/DOC.md",
    "content": "---\nname: selenium-webdriver\ndescription: \"TypeScript declarations for Selenium WebDriver sessions, locators, waits, and page-object-style helpers in Node.js automation code.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"4.35.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,selenium,webdriver,browser-automation,testing,types,definitelytyped\"\n---\n\n# Selenium WebDriver TypeScript Guide\n\n## Golden Rule\n\nInstall `selenium-webdriver` for runtime behavior and `@types/selenium-webdriver` for compile-time declarations.\n\nYour application imports from `\"selenium-webdriver\"`. The `@types/selenium-webdriver` package supplies TypeScript types for public APIs such as `Builder`, `By`, `Key`, `until`, `WebDriver`, `WebElement`, and `Condition`.\n\nDo not import from `\"@types/selenium-webdriver\"` in application code.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install selenium-webdriver\nnpm install -D typescript @types/selenium-webdriver @types/node\n```\n\nIf your project already has TypeScript and the runtime package, add only the missing declarations:\n\n```bash\nnpm install -D @types/selenium-webdriver @types/node\n```\n\n`@types/selenium-webdriver` does not configure browsers, browser drivers, or a Selenium server. Those are runtime concerns handled by `selenium-webdriver` and your local or remote test environment.\n\n## Initialization\n\nThere are no package-specific credentials, API keys, or required environment variables for `@types/selenium-webdriver` itself.\n\nThe practical setup points are:\n\n- installing the real `selenium-webdriver` package\n- using imports from `\"selenium-webdriver\"`\n- writing your browser-session code with `async` and `await`\n\n### Recommended `tsconfig.json`\n\nNo special Selenium-specific compiler options are required. A normal strict Node.js TypeScript setup works well:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n### Import the public API from `selenium-webdriver`\n\nUse named imports for the runtime helpers and `type` imports for annotation-only symbols:\n\n```typescript\nimport {\n  Builder,\n  By,\n  Key,\n  until,\n  type WebDriver,\n  type WebElement,\n} from \"selenium-webdriver\";\n```\n\n## Common Workflows\n\n### Start a typed browser session\n\nCreate a `WebDriver` with `Builder`, navigate to a page, then always close the session in `finally`.\n\nThis example uses an app-defined `SELENIUM_BROWSER` variable so the same code can switch browsers without changing the source file:\n\n```bash\nexport SELENIUM_BROWSER=chrome\n```\n\n```typescript\nimport { Builder, By, Key, until, type WebDriver } from \"selenium-webdriver\";\n\nexport async function createDriver(): Promise<WebDriver> {\n  return new Builder()\n    .forBrowser(process.env.SELENIUM_BROWSER ?? \"chrome\")\n    .build();\n}\n\nasync function main(): Promise<void> {\n  const driver = await createDriver();\n\n  try {\n    await driver.get(\"https://www.selenium.dev/selenium/web/web-form.html\");\n\n    const textBox = await driver.findElement(By.name(\"my-text\"));\n    await textBox.sendKeys(\"context hub\", Key.TAB);\n\n    const button = await driver.findElement(By.css(\"button\"));\n    await button.click();\n\n    await driver.wait(until.elementLocated(By.id(\"message\")), 10_000);\n  } finally {\n    await driver.quit();\n  }\n}\n\nvoid main();\n```\n\n### Wait for typed conditions\n\nThe `until` helpers are the usual way to model asynchronous page state. They work cleanly with TypeScript because the declaration package exposes condition types for common element and driver waits.\n\n```typescript\nimport { By, until, type WebDriver, type WebElement } from \"selenium-webdriver\";\n\nexport async function waitForMessage(driver: WebDriver): Promise<WebElement> {\n  const message = await driver.wait(\n    until.elementLocated(By.id(\"message\")),\n    10_000,\n  );\n\n  await driver.wait(until.elementIsVisible(message), 10_000);\n\n  return message;\n}\n```\n\nUse `until.titleContains()`, `until.urlContains()`, `until.elementLocated()`, and `until.elementIsVisible()` when you want the return type to stay close to the runtime operation you are performing.\n\n### Model helper functions with `WebDriver` and `WebElement`\n\nFor page-object-style code, keep the browser session typed as `WebDriver` and element handles typed as `WebElement`.\n\n```typescript\nimport { By, until, type WebDriver } from \"selenium-webdriver\";\n\nexport class WebFormPage {\n  constructor(private readonly driver: WebDriver) {}\n\n  async open(): Promise<void> {\n    await this.driver.get(\"https://www.selenium.dev/selenium/web/web-form.html\");\n  }\n\n  async submitText(value: string): Promise<string> {\n    const input = await this.driver.wait(\n      until.elementLocated(By.name(\"my-text\")),\n      10_000,\n    );\n\n    await input.clear();\n    await input.sendKeys(value);\n    await this.driver.findElement(By.css(\"button\")).click();\n\n    const message = await this.driver.wait(\n      until.elementLocated(By.id(\"message\")),\n      10_000,\n    );\n\n    return message.getText();\n  }\n}\n```\n\nThis is the main type boundary most projects need: helpers accept a `WebDriver`, perform browser actions, and return plain application values such as strings or booleans.\n\n### Connect to a remote Selenium server or Grid\n\nWhen you run browsers on a remote Selenium server, configure the builder with `usingServer()` and keep the rest of the typing the same.\n\nThis example uses an app-defined `SELENIUM_REMOTE_URL` variable:\n\n```bash\nexport SELENIUM_REMOTE_URL=http://127.0.0.1:4444/wd/hub\n```\n\n```typescript\nimport { Builder, type WebDriver } from \"selenium-webdriver\";\n\nexport async function createRemoteDriver(): Promise<WebDriver> {\n  return new Builder()\n    .usingServer(process.env.SELENIUM_REMOTE_URL ?? \"http://127.0.0.1:4444/wd/hub\")\n    .forBrowser(\"firefox\")\n    .build();\n}\n```\n\nIf your project chooses the browser or remote URL through environment variables, keep those variables in your own app configuration. `@types/selenium-webdriver` does not define them.\n\n## Important Pitfalls\n\n- Install both `selenium-webdriver` and `@types/selenium-webdriver`; the declaration package does not include runtime JavaScript.\n- Import from `\"selenium-webdriver\"`, not from `\"@types/selenium-webdriver\"`.\n- Browser drivers, local browser binaries, and Selenium Grid setup are runtime concerns outside this type package.\n- Keep session teardown explicit with `await driver.quit()` so your test process does not leave browser sessions open.\n- `driver.wait()` is the typed boundary for asynchronous page state; prefer explicit `until.*` helpers over ad-hoc polling loops.\n\n## Version Note For `@types/selenium-webdriver` 4.35.5\n\n`@types/selenium-webdriver` is published independently from the `selenium-webdriver` runtime package, so the declaration version does not need to match the runtime version exactly.\n\nFor TypeScript application code, the stable rule is to keep imports pointed at `\"selenium-webdriver\"` and treat `@types/selenium-webdriver` as the declaration layer for the runtime package.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/selenium-webdriver\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/selenium-webdriver\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/selenium-webdriver/index.d.ts\n- https://www.npmjs.com/package/selenium-webdriver\n- https://www.selenium.dev/selenium/docs/api/javascript/\n"
  },
  {
    "path": "content/typescript/docs/semver/typescript/DOC.md",
    "content": "---\nname: semver\ndescription: \"TypeScript declarations for the semver runtime package, including typed parsing, comparison, ranges, and SemVer classes\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.7.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,semver,versioning,npm,types\"\n---\n\n# semver TypeScript Guide\n\n`@types/semver` provides the declaration files for the `semver` runtime package. Install it when your TypeScript project imports `semver` and you want typed access to helpers such as `valid`, `clean`, `compare`, `satisfies`, `coerce`, `inc`, `Range`, and `SemVer`.\n\nThis package only adds `.d.ts` files. It does not install the runtime library or the `semver` CLI by itself.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install semver\nnpm install --save-dev @types/semver\n```\n\nThe published `@types/semver` package declares `typeScriptVersion: \"5.2\"`, so use TypeScript 5.2 or newer.\n\nNo environment variables, authentication, or client initialization are required.\n\n## Import `semver` In TypeScript\n\nUse a namespace import for the top-level runtime package:\n\n```ts\nimport * as semver from \"semver\";\nimport type { ReleaseType } from \"semver\";\n```\n\nThe declaration package exports named symbols from `\"semver\"`, including `SemVer`, `Range`, `Comparator`, `RELEASE_TYPES`, `SEMVER_SPEC_VERSION`, and the standard comparison and range helpers.\n\nAvoid relying on a default import if you want configuration-independent typings; the published declarations do not declare a default export.\n\n## Validate And Parse Versions\n\nMost application code starts by normalizing a user-provided version string, then working with the parsed `SemVer` object.\n\n```ts\nimport * as semver from \"semver\";\n\nexport function parseVersion(input: string) {\n  const cleaned = semver.clean(input);\n  if (!cleaned) {\n    throw new Error(`Invalid semantic version: ${input}`);\n  }\n\n  const parsed = semver.parse(cleaned);\n  if (!parsed) {\n    throw new Error(`Could not parse semantic version: ${cleaned}`);\n  }\n\n  return {\n    normalized: parsed.version,\n    major: parsed.major,\n    minor: parsed.minor,\n    patch: parsed.patch,\n    prerelease: parsed.prerelease,\n    build: parsed.build,\n  };\n}\n```\n\nThe important typing detail is that `clean()` returns `string | null`, and `parse()` returns `SemVer | null` unless you use its throwing overload. Guard both results before reading `.version`, `.major`, or `.prerelease`.\n\n## Compare And Sort Versions\n\nThe top-level helpers are typed for both string inputs and `SemVer` instances.\n\n```ts\nimport * as semver from \"semver\";\n\nconst releases = [\"7.6.3\", \"7.7.1\", \"7.7.1-beta.1\", \"7.7.0\"];\n\nconst stable = releases.filter((version) => semver.prerelease(version) === null);\nconst newest = semver.rsort(stable)[0];\n\nif (semver.gt(newest, \"7.7.0\")) {\n  console.log(`${newest} is newer than 7.7.0`);\n}\n```\n\nUse `compareBuild()` when build metadata must participate in the comparison. Use `compare()` when you want standard precedence without build metadata.\n\n## Check Version Ranges\n\nThe declaration package includes both function helpers and the `Range` class.\n\n```ts\nimport * as semver from \"semver\";\n\nconst supportedRange = \"^7.0.0\";\nconst requestedVersion = \"7.7.1\";\n\nif (!semver.satisfies(requestedVersion, supportedRange)) {\n  throw new Error(`Expected ${requestedVersion} to satisfy ${supportedRange}`);\n}\n\nconst floor = semver.minVersion(supportedRange);\nconst newestSupported = semver.maxSatisfying(\n  [\"6.9.0\", \"7.5.4\", \"7.7.1\", \"8.0.0\"],\n  supportedRange,\n);\n\nconsole.log({\n  floor: floor?.version ?? null,\n  newestSupported,\n});\n```\n\nWhen you want to reuse a parsed range, instantiate `Range` directly:\n\n```ts\nimport * as semver from \"semver\";\n\nconst range = new semver.Range(\"^7.0.0 || ^8.0.0\");\n\nconsole.log(range.test(\"7.7.1\"));\nconsole.log(range.test(\"9.0.0\"));\n```\n\nFor prerelease-aware checks, pass `includePrerelease` in the options object:\n\n```ts\nimport * as semver from \"semver\";\n\nconst allowed = semver.satisfies(\"7.8.0-rc.1\", \"^7.8.0-0\", {\n  includePrerelease: true,\n});\n\nconsole.log(allowed);\n```\n\n## Coerce Non-Standard Input\n\n`coerce()` is useful at the boundary where tags, filenames, or release labels contain a version but are not already valid semver strings.\n\n```ts\nimport * as semver from \"semver\";\n\nconst coerced = semver.coerce(\"release-7.7\");\n\nif (coerced) {\n  console.log(coerced.version);\n}\n\nconst withPrerelease = semver.coerce(\"1.2.3.4-rc.1+rev.2\", {\n  includePrerelease: true,\n});\n\nconsole.log(withPrerelease?.version ?? null);\n```\n\nThe declarations type `coerce()` as returning `SemVer | null`, not a string. The `CoerceOptions` interface in `@types/semver` includes both `rtl` and `includePrerelease`.\n\n## Use Typed Release Increments\n\nThe package exports the `ReleaseType` union and `RELEASE_TYPES` constant for safe increment logic.\n\n```ts\nimport * as semver from \"semver\";\nimport type { ReleaseType } from \"semver\";\n\nexport function bump(version: string, release: ReleaseType) {\n  return semver.inc(version, release);\n}\n\nconst nextPatch = bump(\"7.7.1\", \"patch\");\nconst nextBeta = semver.inc(\"7.7.1\", \"prerelease\", \"beta\");\n\nconsole.log({ nextPatch, nextBeta });\n```\n\nIf you accept release types from user input, validate them before passing them to `inc()`:\n\n```ts\nimport * as semver from \"semver\";\nimport type { ReleaseType } from \"semver\";\n\nfunction isReleaseType(value: string): value is ReleaseType {\n  return (semver.RELEASE_TYPES as readonly string[]).includes(value);\n}\n```\n\n## Deep Imports For Narrower Usage\n\nThe `semver` README documents subpath entry points, and `@types/semver` ships matching declarations for them.\n\n```ts\nimport Range = require(\"semver/classes/range\");\nimport coerce = require(\"semver/functions/coerce\");\n\nconst range = new Range(\"^7.0.0\");\nconst version = coerce(\"v7\");\n\nconsole.log(range.test(version?.version ?? \"0.0.0\"));\n```\n\nUse the top-level `semver` import unless you have a specific reason to depend on a subpath.\n\n## CLI Boundary\n\nThe `semver` command-line tool comes from the runtime package, not from `@types/semver`. After installing `semver`, you can run the CLI with `npx`:\n\n```bash\nnpx semver -r \"^7.0.0\" 7.6.3 7.7.1 8.0.0\n```\n\nKeep this distinction in mind when a project needs both compile-time types and a local version-checking command in scripts.\n\n## Practical Pitfalls\n\n- Install `semver` as the runtime dependency; `@types/semver` only provides declarations.\n- Use TypeScript 5.2 or newer, which is the minimum version declared by `@types/semver` 7.7.1.\n- Guard `clean()`, `parse()`, `coerce()`, `validRange()`, `maxSatisfying()`, and other nullable results before using them.\n- Prefer `import * as semver from \"semver\"` or explicit subpath imports instead of a default import.\n"
  },
  {
    "path": "content/typescript/docs/serve-static/typescript/DOC.md",
    "content": "---\nname: serve-static\ndescription: \"TypeScript declarations for the serve-static middleware factory, option objects, and Express-compatible static file handlers\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,serve-static,express,node,http,middleware,static-files,types,definitelytyped\"\n---\n\n# serve-static TypeScript Guide\n\n`@types/serve-static` provides TypeScript declarations for the `serve-static` runtime package. It models the `serveStatic(root, options?)` factory, the `serveStatic.ServeStaticOptions` object, and the middleware types used directly by `serve-static` and indirectly by `express.static()`.\n\nInstall the runtime package for actual static-file behavior. `@types/serve-static` only adds declarations for the TypeScript compiler.\n\n## Install\n\nIf your app imports `serve-static` directly, install the runtime package and the declarations together:\n\n```bash\nnpm install serve-static\nnpm install --save-dev typescript @types/node @types/serve-static\n```\n\nIf you are using Express, install the server packages you actually compile against:\n\n```bash\nnpm install express serve-static\nnpm install --save-dev typescript @types/express @types/node\n```\n\n`@types/express` already depends on `@types/serve-static`, so `express.static()` is usually typed without adding a separate direct dependency on `@types/serve-static`.\n\nNo credentials or service-specific environment variables are required. A typical app-level setup is just the static directory and port:\n\n```bash\nexport STATIC_DIR=public\nexport PORT=3000\n```\n\n## TypeScript Setup\n\n`@types/serve-static` 2.2.0 is published with `typeScriptVersion: \"5.2\"`, so use TypeScript 5.2 or newer.\n\nThe declarations use `export = serveStatic`. If your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import works:\n\n```typescript\nimport serveStatic from \"serve-static\";\n```\n\nWithout those interop settings, use the CommonJS-style import form:\n\n```typescript\nimport serveStatic = require(\"serve-static\");\n```\n\nA strict Node.js setup that works well with `serve-static` looks like this:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false,\n    \"types\": [\"node\", \"express\"]\n  }\n}\n```\n\nIf your project does not use Express, omit `\"express\"` from `compilerOptions.types`.\n\n## Mount Static Files In Express\n\nThe main API is `serveStatic(root, options?)`. It returns middleware that you mount with `app.use()`.\n\n```typescript\nimport express from \"express\";\nimport path from \"node:path\";\nimport serveStatic from \"serve-static\";\n\nconst app = express();\nconst staticDir = path.resolve(process.env.STATIC_DIR ?? \"public\");\nconst port = Number(process.env.PORT ?? \"3000\");\n\napp.use(\n  \"/assets\",\n  serveStatic(staticDir, {\n    index: [\"index.html\"],\n    maxAge: \"1d\",\n    fallthrough: true,\n  }),\n);\n\napp.listen(port);\n```\n\nBy default, missing files fall through to the next middleware instead of producing a 404 immediately, which makes this pattern work well in layered Express apps.\n\n## Type Options And Middleware Explicitly\n\nWhen you want compile-time checks on the options object, annotate it as `serveStatic.ServeStaticOptions`. The declarations also export `serveStatic.RequestHandler` if you want a named middleware type.\n\n```typescript\nimport path from \"node:path\";\nimport type { ServerResponse } from \"node:http\";\nimport serveStatic from \"serve-static\";\n\nconst staticOptions: serveStatic.ServeStaticOptions<ServerResponse> = {\n  dotfiles: \"ignore\",\n  extensions: [\"html\", \"htm\"],\n  fallthrough: false,\n  index: [\"index.html\", \"index.htm\"],\n  maxAge: \"1d\",\n  redirect: true,\n  setHeaders(res, filePath) {\n    if (path.extname(filePath) === \".html\") {\n      res.setHeader(\"Cache-Control\", \"public, max-age=0\");\n    }\n  },\n};\n\nexport const servePublic: serveStatic.RequestHandler<ServerResponse> = serveStatic(\n  path.resolve(process.env.STATIC_DIR ?? \"public\"),\n  staticOptions,\n);\n```\n\nThe published declarations type `maxAge` as `number | string`, so both milliseconds and `ms`-style strings such as `\"1d\"` are valid.\n\n## Stack Multiple Static Roots\n\nBecause the default `fallthrough` behavior is `true`, you can mount more than one static directory and let later middleware act as a fallback.\n\n```typescript\nimport express from \"express\";\nimport path from \"node:path\";\nimport serveStatic from \"serve-static\";\n\nconst app = express();\n\napp.use(serveStatic(path.resolve(\"public-optimized\")));\napp.use(serveStatic(path.resolve(\"public\")));\n\napp.listen(3000);\n```\n\nThis serves files from `public-optimized` first and uses `public` only when the earlier middleware does not find a matching file.\n\n## Express Integration Boundary\n\nIf you call `express.static()` instead of importing `serve-static` yourself, you are still using these declarations. `@types/express` references `serve-static` and types `express.static` as a `serveStatic.RequestHandlerConstructor<Response>`.\n\n```typescript\nimport express from \"express\";\n\nconst app = express();\n\napp.use(\n  express.static(process.env.STATIC_DIR ?? \"public\", {\n    immutable: true,\n    maxAge: \"1y\",\n  }),\n);\n```\n\nUse a direct `serve-static` import when you want to share middleware factories outside Express-specific setup code. Use `express.static()` when you prefer the framework convenience API.\n\n## Common Pitfalls\n\n- Install `serve-static` for runtime behavior; `@types/serve-static` does not serve files by itself.\n- Import from `\"serve-static\"`, never from `\"@types/serve-static\"`.\n- If you rely on a default import, enable `esModuleInterop` or `allowSyntheticDefaultImports`; otherwise use `import serveStatic = require(\"serve-static\")`.\n- `setHeaders` must update headers synchronously.\n- `immutable: true` should be paired with a non-zero `maxAge`.\n- `fallthrough: false` changes missing-file handling from `next()` to `next(err)`, including 404-style misses.\n- For `dotfiles`, stick to the documented runtime values `\"allow\"`, `\"deny\"`, or `\"ignore\"`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/serve-static\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/serve-static\n- https://www.npmjs.com/package/serve-static\n- https://github.com/expressjs/serve-static#readme\n"
  },
  {
    "path": "content/typescript/docs/sharp/typescript/DOC.md",
    "content": "---\nname: sharp\ndescription: \"TypeScript guide for using the `sharp` image-processing package with its bundled declarations in Node.js projects.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.32.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,sharp,images,node,image-processing,types\"\n---\n\n# sharp TypeScript Guide\n\n## Golden Rule\n\nUse `sharp` as the runtime package and import application code from `\"sharp\"`.\n\nIn practice, the TypeScript boundary that matters is the maintained `sharp` package itself. Its published package metadata includes a `types` entry pointing at bundled declarations, so new TypeScript projects should center their setup around `sharp`, not around imports from `@types/sharp`.\n\n## Install\n\nInstall the runtime package plus your project's TypeScript and Node.js declarations:\n\n```bash\nnpm install sharp\nnpm install -D typescript @types/node\n```\n\nIf an older project still has a direct dependency on `@types/sharp`, keep application imports pointed at `sharp`. When your installed `sharp` package already publishes its own declarations, you can remove the extra type package:\n\n```bash\nnpm uninstall @types/sharp\n```\n\nThere are no API keys, credentials, or package-specific environment variables to configure.\n\nMost modern macOS, Windows, and Linux systems do not require extra runtime dependencies, but `sharp` installation can still be platform-specific. If `npm install sharp` needs additional setup, follow the official install guide instead of treating it like a pure `.d.ts` package.\n\n## TypeScript Setup\n\n### Recommended `tsconfig.json`\n\nFor Node.js applications, a Node-oriented compiler setup keeps the runtime boundary clear:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, include `node` because `sharp`'s declarations use Node types such as `Buffer` and `stream.Duplex`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n### Import `sharp` correctly\n\nThe published declarations use CommonJS `export = sharp` semantics.\n\nUse `import = require()` when you want the import form that matches the declarations directly:\n\n```ts\nimport sharp = require(\"sharp\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```json\n{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true\n  }\n}\n```\n\n```ts\nimport sharp from \"sharp\";\n```\n\nDo not import values from `\"@types/sharp\"` in application code.\n\n## Common Workflows\n\n### Resize an image and write it to disk\n\n`toFile()` returns a typed `sharp.OutputInfo` object with the output format, size, dimensions, and channel count.\n\n```ts\nimport sharp = require(\"sharp\");\n\nconst info = await sharp(\"input.jpg\")\n  .rotate()\n  .resize(320, 240)\n  .webp()\n  .toFile(\"output.webp\");\n\nconsole.log({\n  format: info.format,\n  width: info.width,\n  height: info.height,\n  size: info.size,\n  channels: info.channels,\n});\n```\n\nThis is the most common integration point for web upload pipelines, image preprocessing jobs, and server-side thumbnail generation.\n\n### Read typed image metadata before processing\n\n`metadata()` resolves to `sharp.Metadata`, which lets you branch on image format, dimensions, alpha support, and animation details without falling back to `any`.\n\n```ts\nimport sharp = require(\"sharp\");\n\nconst metadata: sharp.Metadata = await sharp(\"input.png\").metadata();\n\nif (metadata.hasAlpha) {\n  console.log(\"image contains transparency\");\n}\n\nconsole.log({\n  format: metadata.format,\n  width: metadata.width,\n  height: metadata.height,\n  pages: metadata.pages,\n});\n```\n\nUse this when your resize logic, encoder choice, or validation rules depend on the input image shape.\n\n### Get a buffer and output info together\n\nWhen you need the transformed bytes in memory and also want the output metadata, call `toBuffer({ resolveWithObject: true })`.\n\n```ts\nimport { writeFile } from \"node:fs/promises\";\nimport sharp = require(\"sharp\");\n\nconst resizeOptions: sharp.ResizeOptions = {\n  width: 800,\n  height: 800,\n  fit: \"inside\",\n  withoutEnlargement: true,\n};\n\nconst { data, info } = await sharp(\"input.jpg\")\n  .resize(resizeOptions)\n  .png()\n  .toBuffer({ resolveWithObject: true });\n\nawait writeFile(\"output.png\", data);\n\nconsole.log({\n  width: info.width,\n  height: info.height,\n  size: info.size,\n  format: info.format,\n});\n```\n\nThis is the right shape for HTTP handlers, queue workers, and storage adapters that upload buffers instead of writing local files.\n\n### Create an image and composite overlays\n\nThe `sharp` namespace also exports the option types you need for composing helper functions.\n\n```ts\nimport sharp = require(\"sharp\");\n\nconst overlays: sharp.OverlayOptions[] = [\n  {\n    input: {\n      create: {\n        width: 180,\n        height: 180,\n        channels: 4,\n        background: { r: 37, g: 99, b: 235, alpha: 1 },\n      },\n    },\n    top: 24,\n    left: 24,\n    blend: \"over\",\n  },\n];\n\nawait sharp({\n  create: {\n    width: 1200,\n    height: 630,\n    channels: 4,\n    background: { r: 17, g: 24, b: 39, alpha: 1 },\n  },\n})\n  .composite(overlays)\n  .png()\n  .toFile(\"card.png\");\n```\n\nThis pattern is useful when you build typed helpers for social cards, badges, watermarking, or image assembly pipelines.\n\n## Important Pitfalls\n\n- Install `sharp`; `@types/sharp` does not provide the image-processing runtime.\n- Import from `\"sharp\"`, not from `\"@types/sharp\"`.\n- If you restrict `compilerOptions.types`, include `node` or TypeScript will miss the Node declarations that `sharp` references.\n- The declaration package uses CommonJS `export =` semantics, so `import sharp = require(\"sharp\")` is the no-surprises form.\n- If installation fails on a specific platform, use the official `sharp` install guide rather than guessing at native build flags or system packages.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/sharp\n- https://www.npmjs.com/package/sharp\n- https://sharp.pixelplumbing.com/install\n- https://sharp.pixelplumbing.com/api-constructor\n- https://github.com/lovell/sharp\n"
  },
  {
    "path": "content/typescript/docs/shelljs/typescript/DOC.md",
    "content": "---\nname: shelljs\ndescription: \"TypeScript declarations for ShellJS's portable Unix-like file, process, environment, and configuration APIs.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.10.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,shelljs,nodejs,build-scripts,shell,types,definitelytyped\"\n---\n\n# shelljs TypeScript Guide\n\n`@types/shelljs` adds TypeScript declarations for the `shelljs` runtime package.\n\nUse it in Node.js scripts, CLIs, and build tooling that call ShellJS helpers such as `cp`, `exec`, `grep`, `mkdir`, `rm`, `sed`, and `which` from TypeScript.\n\nThis package only provides `.d.ts` files. Your code still runs the real `shelljs` package.\n\n## Install\n\nInstall the runtime package and the declaration package together:\n\n```bash\nnpm install shelljs\nnpm install -D typescript @types/shelljs @types/node\n```\n\nIf your project already has `shelljs` and TypeScript, add only the missing declarations:\n\n```bash\nnpm install -D @types/shelljs @types/node\n```\n\nImport runtime code from `\"shelljs\"`, not from `\"@types/shelljs\"`.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to initialize.\n\nThe practical setup is your import style and your TypeScript compiler options.\n\n### Import `shelljs`\n\nThe maintainer README uses CommonJS `require(\"shelljs\")`. In TypeScript, the lowest-friction typed import form is:\n\n```typescript\nimport shell = require(\"shelljs\");\n```\n\nIf your project enables interop for CommonJS default imports, this is also convenient:\n\n```typescript\nimport shell from \"shelljs\";\n```\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you prefer `import shell = require(\"shelljs\")`, `esModuleInterop` is not required for this package.\n\n## Common Workflows\n\n### Run file and directory commands from a build script\n\nShellJS exposes synchronous Unix-like helpers as regular Node.js functions.\n\n```typescript\nimport shell = require(\"shelljs\");\n\nshell.set(\"-e\");\n\nif (!shell.which(\"git\")) {\n  shell.echo(\"This script requires git\");\n  shell.exit(1);\n}\n\nshell.rm(\"-rf\", \"dist\");\nshell.mkdir(\"-p\", \"dist/assets\");\nshell.cp(\"-R\", \"public/.\", \"dist\");\nshell.cd(\"dist\");\n\nfor (const file of shell.ls(\"*.html\")) {\n  shell.sed(\"-i\", /BUILD_VERSION/g, process.env.APP_VERSION ?? \"dev\", file);\n}\n```\n\nPer the maintainer README, commands run synchronously unless the command documentation says otherwise.\n\n### Run external processes and capture typed output\n\n`exec()` is synchronous by default and returns a `ShellString`-compatible result with `code`, `stdout`, and `stderr`.\n\n```typescript\nimport shell = require(\"shelljs\");\n\nconst result = shell.exec(\"node --version\", { silent: true });\n\nif (result.code !== 0) {\n  throw new Error(result.stderr);\n}\n\nconsole.log(result.stdout.trim());\n```\n\nFor long-running processes, opt in to async mode:\n\n```typescript\nimport shell = require(\"shelljs\");\n\nconst child = shell.exec(\"npm run watch\", {\n  async: true,\n  silent: true,\n});\n\nchild.stdout?.on(\"data\", (chunk) => {\n  process.stdout.write(chunk);\n});\n```\n\nThe maintainer docs also note that `exec()` runs through `sh` by default, or `cmd.exe` on Windows. If you need Bash-specific behavior, pass the `shell` option explicitly.\n\n### Write files with `ShellString` results\n\nShellJS commands such as `cat`, `echo`, and `grep` return `ShellString` objects that support `.to()` and `.toEnd()`.\n\n```typescript\nimport shell = require(\"shelljs\");\n\nshell.cat(\"README.md\").to(\"dist/README.txt\");\nshell.echo(`APP_VERSION=${process.env.APP_VERSION ?? \"dev\"}`).toEnd(\"dist/.env\");\n```\n\nUse `.to()` when you want overwrite behavior similar to `>`, and `.toEnd()` when you want append behavior similar to `>>`.\n\n### Control shell configuration and environment variables\n\nShellJS exposes configuration through `shell.config` and environment variables through `shell.env`, which the README documents as a shortcut to `process.env`.\n\n```typescript\nimport shell = require(\"shelljs\");\n\nconst oldSilent = shell.config.silent;\n\nshell.config.silent = true;\nshell.env[\"NODE_ENV\"] = \"production\";\n\ntry {\n  shell.exec(\"node scripts/build.js\");\n} finally {\n  shell.config.silent = oldSilent;\n  shell.config.reset();\n}\n```\n\nThis is the main initialization boundary for most TypeScript projects using ShellJS: configure failure or logging behavior once, then run the commands you need.\n\n## Common Pitfalls\n\n- Install `shelljs` as well as `@types/shelljs`; the declaration package does not include the runtime implementation.\n- Import from `\"shelljs\"`, not from `\"@types/shelljs\"`.\n- If you use `import shell from \"shelljs\"`, enable `esModuleInterop` or `allowSyntheticDefaultImports`; otherwise use `import shell = require(\"shelljs\")`.\n- The maintainer README no longer recommends `require(\"shelljs/global\")`; prefer a local import so your TypeScript module scope stays explicit.\n- `exec()` is synchronous unless you pass `{ async: true }` or use the callback form.\n- `exec()` does not imply Bash semantics; by default it runs through `sh` or `cmd.exe`, so Bash-only syntax should use the `shell` option explicitly.\n- If your `tsconfig.json` restricts ambient type packages with `compilerOptions.types`, include `node` there or `process`, `require`, and child-process-related types can appear to disappear.\n- If you only need cross-platform shell commands in `package.json` scripts, the ShellJS README points to `shx`; `@types/shelljs` is for the programmatic Node API.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/shelljs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/shelljs\n- https://www.npmjs.com/package/shelljs\n- https://github.com/shelljs/shelljs\n"
  },
  {
    "path": "content/typescript/docs/sinon/typescript/DOC.md",
    "content": "---\nname: sinon\ndescription: \"TypeScript definitions for Sinon spies, stubs, sandboxes, assertions, and fake timers\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"21.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,sinon,testing,mocks,stubs,types\"\n---\n\n# Sinon TypeScript Guide\n\n`@types/sinon` adds TypeScript declarations for the `sinon` runtime package. Install it when your tests or helper code import `sinon` from TypeScript.\n\nThis package only ships type declarations. It does not include the Sinon runtime.\n\n## Install\n\nInstall the runtime library and the type package together:\n\n```bash\nnpm install --save-dev sinon @types/sinon\n```\n\nNo environment variables, authentication, or client initialization are required.\n\n## TypeScript Setup\n\nIn most projects, installing both packages is enough.\n\nIf your `tsconfig.json` already restricts loaded type packages with `compilerOptions.types`, add `sinon`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"sinon\"]\n  }\n}\n```\n\nChoose an import form that matches your compiler settings:\n\n```ts\nimport sinon from \"sinon\";\n```\n\nIf your project does not enable default CommonJS interop, use:\n\n```ts\nimport sinon = require(\"sinon\");\n```\n\n## Spy On Existing Methods\n\nUse `spy()` when the real implementation should still run but the test also needs typed call assertions.\n\n```ts\nimport sinon from \"sinon\";\n\nconst logger = {\n  info(message: string) {\n    console.log(message);\n  },\n};\n\nconst infoSpy = sinon.spy(logger, \"info\");\n\nlogger.info(\"saved\");\n\nsinon.assert.calledOnce(infoSpy);\nsinon.assert.calledWithExactly(infoSpy, \"saved\");\n\ninfoSpy.restore();\n```\n\n## Stub Async Methods\n\n`stub()` keeps the original method signature connected to the test double, so TypeScript still checks arguments and resolved values.\n\n```ts\nimport sinon from \"sinon\";\n\nconst userService = {\n  async fetchUser(id: string) {\n    return { id, name: \"real-user\" };\n  },\n};\n\nconst fetchUser = sinon\n  .stub(userService, \"fetchUser\")\n  .resolves({ id: \"u_123\", name: \"test-user\" });\n\nconst user = await userService.fetchUser(\"u_123\");\n\nsinon.assert.calledOnce(fetchUser);\nsinon.assert.calledWithExactly(fetchUser, \"u_123\");\nconsole.log(user.name);\n\nfetchUser.restore();\n```\n\n## Create A Sandbox Per Test\n\n`createSandbox()` is the safest default for larger tests because one `restore()` call cleans up every stub, spy, and fake created through the sandbox.\n\n```ts\nimport sinon from \"sinon\";\nimport { afterEach, test } from \"node:test\";\n\nconst sandbox = sinon.createSandbox();\n\nafterEach(() => {\n  sandbox.restore();\n});\n\ntest(\"sends audit log entry\", () => {\n  const audit = {\n    write(event: string) {\n      console.log(event);\n    },\n  };\n\n  const write = sandbox.spy(audit, \"write\");\n\n  audit.write(\"user.created\");\n\n  sinon.assert.calledOnce(write);\n});\n```\n\n## Stub Class Instances\n\nUse `createStubInstance()` when production code depends on a class but a test only needs stubbed methods.\n\n```ts\nimport sinon from \"sinon\";\n\nclass EmailClient {\n  async send(to: string, subject: string) {\n    return `sent:${to}:${subject}`;\n  }\n}\n\nconst emailClient = sinon.createStubInstance(EmailClient);\nemailClient.send.resolves(\"sent:test@example.com:Welcome\");\n\nawait emailClient.send(\"test@example.com\", \"Welcome\");\n\nsinon.assert.calledOnce(emailClient.send);\nsinon.assert.calledWithExactly(emailClient.send, \"test@example.com\", \"Welcome\");\n```\n\n## Use Fake Timers\n\nFake timers let tests drive `setTimeout`, `setInterval`, and `Date` deterministically.\n\n```ts\nimport sinon from \"sinon\";\n\nconst clock = sinon.useFakeTimers(Date.UTC(2026, 0, 1));\nconst job = {\n  run() {\n    console.log(\"ran\");\n  },\n};\nconst run = sinon.spy(job, \"run\");\n\nsetTimeout(() => job.run(), 1_000);\n\nclock.tick(1_000);\n\nsinon.assert.calledOnce(run);\n\nrun.restore();\nclock.restore();\n```\n\n## Common Pitfalls\n\n- Install both `sinon` and `@types/sinon`. The type package does not include runtime code.\n- Restore stubs, spies, sandboxes, and fake timers after each test so state does not leak between tests.\n- If `import sinon from \"sinon\"` fails under your compiler settings, switch to `import sinon = require(\"sinon\")` instead of forcing a cast.\n- If `tsconfig.json` sets `compilerOptions.types`, the entry name is `\"sinon\"`, not `\"@types/sinon\"`.\n\n## Version Notes For 21.0.0\n\n- This guide targets `@types/sinon` version `21.0.0`.\n- `@types/sinon` is a declaration-only companion to the `sinon` runtime package, so install it alongside the runtime package your test suite uses.\n- Prefer stubbing or spying on real object methods instead of manually cast test doubles so the declaration package can keep argument and return types aligned with the runtime surface.\n\n## Official Sources\n\n- Package page: `https://www.npmjs.com/package/@types/sinon`\n- Sinon documentation: `https://sinonjs.org/`\n- Spies: `https://sinonjs.org/releases/latest/spies/`\n- Stubs: `https://sinonjs.org/releases/latest/stubs/`\n- Sandboxes: `https://sinonjs.org/releases/latest/sandbox/`\n- Fake timers: `https://sinonjs.org/releases/latest/fake-timers/`\n- DefinitelyTyped source tree: `https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/sinon`\n"
  },
  {
    "path": "content/typescript/docs/socket.io/typescript/DOC.md",
    "content": "---\nname: socket.io\ndescription: \"TypeScript usage for Socket.IO. For application code, install and import `socket.io`; `@types/socket.io@3.0.2` is the package entry tied to this guide.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.0.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,socket.io,websocket,realtime,node,events,types\"\n---\n\n# Socket.IO TypeScript Guide\n\n## Golden Rule\n\nFor TypeScript application code, install and import `socket.io`.\n\n`@types/socket.io` is not a runtime package. Your server imports `Server` and related types from `\"socket.io\"`, while TypeScript reads the declarations that the runtime package publishes.\n\nIf an older project still lists `@types/socket.io` directly, treat it as packaging history rather than the place your code should import from.\n\n## Install\n\nInstall the Socket.IO server package plus the normal Node.js TypeScript toolchain:\n\n```bash\nnpm install socket.io\nnpm install -D typescript @types/node\n```\n\nIf you also keep a Node-based client, tests, or integration scripts in the same repo, add the official client package separately:\n\n```bash\nnpm install socket.io-client\n```\n\nIf your project already added `@types/socket.io` directly, remove it before troubleshooting duplicate or stale type behavior:\n\n```bash\nnpm uninstall @types/socket.io\n```\n\nThere are no package-level credentials. In practice, Socket.IO auth is application-defined and usually sent as handshake `auth` data from the client.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\"]\n  }\n}\n```\n\nIf you use `compilerOptions.types`, include `node` there. Socket.IO's own types are loaded from the normal `import \"socket.io\"` boundary, not from a separate ambient package name.\n\n## Initialize a Typed Server\n\nThis is the smallest practical setup for a typed Socket.IO server.\n\nUse `PORT` for the HTTP listener and `CORS_ORIGIN` for browser clients during development:\n\n```bash\nexport PORT=3000\nexport CORS_ORIGIN=http://localhost:5173\n```\n\n```ts\nimport { createServer } from \"node:http\";\nimport { Server } from \"socket.io\";\n\ninterface ClientToServerEvents {\n  \"room:join\": (roomId: string, ack: (response: { joined: boolean }) => void) => void;\n  \"chat:send\": (\n    payload: { roomId: string; body: string },\n    ack: (response: { ok: true }) => void,\n  ) => void;\n}\n\ninterface ServerToClientEvents {\n  \"room:joined\": (roomId: string) => void;\n  \"chat:message\": (payload: { roomId: string; body: string; from: string }) => void;\n}\n\nconst port = Number(process.env.PORT ?? \"3000\");\nconst corsOrigin = process.env.CORS_ORIGIN ?? \"http://localhost:5173\";\n\nconst httpServer = createServer();\n\nconst io = new Server<ClientToServerEvents, ServerToClientEvents>(httpServer, {\n  cors: {\n    origin: corsOrigin,\n    credentials: true,\n  },\n});\n\nio.use((socket, next) => {\n  const token = socket.handshake.auth.token;\n\n  if (typeof token !== \"string\" || token.length === 0) {\n    return next(new Error(\"unauthorized\"));\n  }\n\n  next();\n});\n\nio.on(\"connection\", (socket) => {\n  socket.on(\"room:join\", async (roomId, ack) => {\n    await socket.join(roomId);\n    socket.emit(\"room:joined\", roomId);\n    ack({ joined: true });\n  });\n\n  socket.on(\"chat:send\", async ({ roomId, body }, ack) => {\n    const from = String(socket.handshake.auth.userId ?? \"anonymous\");\n\n    await socket.join(roomId);\n\n    io.to(roomId).emit(\"chat:message\", {\n      roomId,\n      body,\n      from,\n    });\n\n    ack({ ok: true });\n  });\n});\n\nhttpServer.listen(port, () => {\n  console.log(`Socket.IO listening on http://localhost:${port}`);\n});\n```\n\nThe important type boundary is the `Server<ClientToServerEvents, ServerToClientEvents>` generic. Once you define the event maps there, `socket.on(...)`, `socket.emit(...)`, acknowledgement callbacks, and room broadcasts stay checked against those declarations.\n\n## Common Workflows\n\n### Define event contracts once and reuse them\n\nKeep shared event contracts in a file that both server and client can import.\n\n```ts\nexport interface ClientToServerEvents {\n  \"presence:ping\": (ack: (response: { ok: true; at: string }) => void) => void;\n}\n\nexport interface ServerToClientEvents {\n  \"presence:pong\": (payload: { at: string }) => void;\n}\n```\n\nUse those interfaces when you create the server:\n\n```ts\nimport { createServer } from \"node:http\";\nimport { Server } from \"socket.io\";\n\nimport type {\n  ClientToServerEvents,\n  ServerToClientEvents,\n} from \"./socket-contracts\";\n\nconst io = new Server<ClientToServerEvents, ServerToClientEvents>(createServer());\n\nio.on(\"connection\", (socket) => {\n  socket.on(\"presence:ping\", (ack) => {\n    const at = new Date().toISOString();\n\n    socket.emit(\"presence:pong\", { at });\n    ack({ ok: true, at });\n  });\n});\n```\n\nThis is the main TypeScript workflow that matters in practice: define the event names and payload shapes once, then let the compiler enforce them across handlers and emitters.\n\n### Use handshake auth, but narrow the values yourself\n\nSocket.IO exposes client-provided auth data on `socket.handshake.auth`.\n\n```ts\nio.use((socket, next) => {\n  const projectId = socket.handshake.auth.projectId;\n\n  if (typeof projectId !== \"string\") {\n    return next(new Error(\"projectId is required\"));\n  }\n\n  next();\n});\n```\n\nThe auth object is key-value data, not a strongly typed app-specific schema. Check types at runtime before using the values in authorization or room selection logic.\n\n### Use namespaces when parts of the app have separate concerns\n\nNamespaces let you split event handlers, middleware, and rooms over one shared connection.\n\n```ts\nimport { createServer } from \"node:http\";\nimport { Server } from \"socket.io\";\n\ninterface AdminClientToServerEvents {\n  \"audit:request\": () => void;\n}\n\ninterface AdminServerToClientEvents {\n  \"audit:ready\": (payload: { generatedAt: string }) => void;\n}\n\nconst io = new Server(createServer());\nconst admin = io.of<AdminClientToServerEvents, AdminServerToClientEvents>(\"/admin\");\n\nadmin.use((socket, next) => {\n  if (socket.handshake.auth.role !== \"admin\") {\n    return next(new Error(\"forbidden\"));\n  }\n\n  next();\n});\n\nadmin.on(\"connection\", (socket) => {\n  socket.on(\"audit:request\", () => {\n    socket.emit(\"audit:ready\", {\n      generatedAt: new Date().toISOString(),\n    });\n  });\n});\n```\n\nRooms are namespace-scoped. A room named `alerts` in `/admin` is separate from a room named `alerts` in `/`.\n\n### Connect a typed client\n\nIf your TypeScript repo also contains a Node client, tests, or a shared integration example, type the client socket against the same event maps.\n\nUse `SOCKET_URL` and `SOCKET_TOKEN` for local development:\n\n```bash\nexport SOCKET_URL=http://localhost:3000\nexport SOCKET_TOKEN=dev-token\n```\n\n```ts\nimport { io, type Socket } from \"socket.io-client\";\n\ninterface ClientToServerEvents {\n  \"room:join\": (roomId: string, ack: (response: { joined: boolean }) => void) => void;\n}\n\ninterface ServerToClientEvents {\n  \"room:joined\": (roomId: string) => void;\n}\n\nconst socket: Socket<ServerToClientEvents, ClientToServerEvents> = io(\n  process.env.SOCKET_URL ?? \"http://localhost:3000\",\n  {\n    auth: {\n      token: process.env.SOCKET_TOKEN ?? \"\",\n    },\n  },\n);\n\nsocket.on(\"room:joined\", (roomId) => {\n  console.log(`joined ${roomId}`);\n});\n\nsocket.emit(\"room:join\", \"room-1\", ({ joined }) => {\n  console.log({ joined });\n});\n```\n\nThe client generic order is the reverse of the server's mental model: the client listens for server-to-client events and emits client-to-server events.\n\n## Important Pitfalls\n\n- Install `socket.io` itself. `@types/socket.io` is not the runtime your application executes.\n- Import from `\"socket.io\"` or `\"socket.io-client\"`, never from `\"@types/socket.io\"`.\n- If you set `compilerOptions.types`, include `node`; do not expect bundled package types to appear there by package name.\n- `socket.handshake.auth` is flexible key-value data. Narrow or validate values before using them.\n- Rooms belong to a namespace. Reusing the same room name in two namespaces does not create one shared audience.\n- Keep your server and client packages on compatible Socket.IO major versions when you wire them together.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/socket.io` package entry at version `3.0.2`.\n- For TypeScript application code, the practical package to install and import is `socket.io`.\n- If an older dependency tree still includes `@types/socket.io`, prefer the runtime package's own declarations when updating or troubleshooting TypeScript behavior.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/socket.io\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/socket.io\n- https://www.npmjs.com/package/socket.io\n- https://socket.io/docs/v4/server-initialization/\n- https://socket.io/docs/v4/typescript/\n- https://socket.io/docs/v4/middlewares/\n- https://socket.io/docs/v4/namespaces/\n- https://socket.io/docs/v4/rooms/\n"
  },
  {
    "path": "content/typescript/docs/stylus/typescript/DOC.md",
    "content": "---\nname: stylus\ndescription: \"TypeScript declarations for the Stylus CSS preprocessor, including typed imports for the Node.js compile API and middleware helpers.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.48.43\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,stylus,css,preprocessor,node,types,definitelytyped\"\n---\n\n# Stylus TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/stylus` alongside the real `stylus` runtime package.\n\n`@types/stylus` only provides TypeScript declarations. Your build script, server, or middleware still imports and runs `stylus`; the declaration package adds types for the CommonJS module export, the renderer chain, and helpers such as `stylus.middleware()`.\n\n## Install\n\nInstall the runtime package first, then add TypeScript and the declaration package:\n\n```bash\nnpm install stylus\nnpm install -D typescript @types/stylus @types/node\n```\n\nIf your project already uses `stylus`, add only the missing declarations:\n\n```bash\nnpm install -D @types/stylus @types/node\n```\n\nThere are no package-specific environment variables, credentials, or client objects to configure.\n\n## Initialization\n\nThe practical setup points are your import style, your TypeScript compiler options, and how you bridge Stylus's callback-based render API into the rest of your app.\n\n### Import `stylus`\n\nThe declaration package models the CommonJS `stylus` export. The most portable import form is:\n\n```typescript\nimport stylus = require(\"stylus\");\n\nconst renderer = stylus(\"body\\n  color: #333\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, a default import also works:\n\n```typescript\nimport stylus from \"stylus\";\n\nconst renderer = stylus(\"body\\n  color: #333\");\n```\n\nImport from `stylus`, never from `@types/stylus`.\n\n### Recommended `tsconfig.json`\n\nFor Node-based compilation scripts, middleware, or server-side rendering, a Node-oriented config works well:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you prefer `import stylus = require(\"stylus\")`, you do not need `esModuleInterop` for this package.\n\n## Common Workflows\n\n### Compile a `.styl` entry file to CSS\n\nUse the renderer chain when you want to control options such as `filename` and `compress` before rendering.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport stylus = require(\"stylus\");\n\nexport async function compileStylus(entryFile: string): Promise<string> {\n  const source = await readFile(entryFile, \"utf8\");\n\n  return await new Promise<string>((resolve, reject) => {\n    stylus(source)\n      .set(\"filename\", entryFile)\n      .set(\"compress\", process.env.NODE_ENV === \"production\")\n      .render((error, css) => {\n        if (error) {\n          reject(error);\n          return;\n        }\n\n        resolve(css);\n      });\n  });\n}\n\nasync function main() {\n  const entryFile = join(process.cwd(), \"styles\", \"main.styl\");\n  const css = await compileStylus(entryFile);\n  console.log(css);\n}\n\nvoid main();\n```\n\nSetting `filename` is the important part when your Stylus source uses relative `@import`s.\n\n### Resolve relative imports predictably\n\nWhen you compile a string from memory instead of passing a real file path into a CLI, set `filename` to the source file you want Stylus to treat as the import base.\n\n```typescript\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport stylus = require(\"stylus\");\n\nconst entryFile = join(process.cwd(), \"styles\", \"app.styl\");\nconst source = await readFile(entryFile, \"utf8\");\n\nstylus(source)\n  .set(\"filename\", entryFile)\n  .render((error, css) => {\n    if (error) {\n      throw error;\n    }\n\n    console.log(css);\n  });\n```\n\nWithout `filename`, relative imports and error locations are harder to resolve.\n\n### Wrap Stylus rendering for `async` / `await`\n\nThe render API is callback-based. In TypeScript applications, the simplest boundary is a small Promise wrapper that returns `Promise<string>`.\n\n```typescript\nimport stylus = require(\"stylus\");\n\nexport function renderStylus(source: string, filename = \"inline.styl\"): Promise<string> {\n  return new Promise((resolve, reject) => {\n    stylus(source)\n      .set(\"filename\", filename)\n      .render((error, css) => {\n        if (error) {\n          reject(error);\n          return;\n        }\n\n        resolve(css);\n      });\n  });\n}\n```\n\nThis keeps the rest of your build code Promise-based without changing how Stylus itself is typed.\n\n### Use Stylus middleware in an Express app\n\n`stylus.middleware()` is useful when your server compiles Stylus from a source directory into a public CSS directory.\n\n```typescript\nimport express from \"express\";\nimport { join } from \"node:path\";\nimport stylus = require(\"stylus\");\n\nconst app = express();\nconst rootDir = process.cwd();\n\napp.use(\n  stylus.middleware({\n    src: join(rootDir, \"styles\"),\n    dest: join(rootDir, \"public\"),\n    compile(source: string, filename: string) {\n      return stylus(source)\n        .set(\"filename\", filename)\n        .set(\"compress\", app.get(\"env\") === \"production\");\n    },\n  }),\n);\n\napp.use(express.static(join(rootDir, \"public\")));\n\napp.listen(3000);\n```\n\nThe middleware example still depends on the real `stylus` package at runtime; `@types/stylus` only makes the middleware and compile callback shapes available to the TypeScript compiler.\n\n## Important Pitfalls\n\n- Install `stylus` as well as `@types/stylus`; the declaration package does not compile anything by itself.\n- Import from `stylus`, not from `@types/stylus`.\n- If `import stylus from \"stylus\"` fails, enable `esModuleInterop` or switch to `import stylus = require(\"stylus\")`.\n- Set `filename` before calling `.render()` when your stylesheet uses relative `@import`s or when you want accurate error locations.\n- Treat `.render()` as callback-based. Do not assume it returns a `Promise`.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/stylus==0.48.43`.\n- The package is a DefinitelyTyped declaration package for the `stylus` runtime module.\n- The declarations cover the Node-side JavaScript API surface and middleware helpers; they do not replace installation of the runtime compiler.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/stylus\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/stylus\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/stylus/index.d.ts\n- https://stylus-lang.com/docs/js.html\n- https://stylus-lang.com/docs/middleware.html\n"
  },
  {
    "path": "content/typescript/docs/superagent/typescript/DOC.md",
    "content": "---\nname: superagent\ndescription: \"TypeScript declarations for SuperAgent, including installation with the runtime package, CommonJS-friendly imports, request/auth patterns, multipart uploads, and the JSON typing boundary.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.1.9\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,superagent,http,api,requests,node,browser,npm,types,definitelytyped\"\n---\n\n# superagent TypeScript Guide\n\n`@types/superagent` provides the TypeScript declarations for the `superagent` runtime package. Install it when your project uses `superagent` from TypeScript, and import from `\"superagent\"`, not from `\"@types/superagent\"`.\n\nThis package only ships declaration files. It does not install the HTTP client runtime.\n\n## Install\n\nInstall the runtime package and the declarations together:\n\n```bash\nnpm install superagent\nnpm install --save-dev typescript @types/superagent\n```\n\nIf your Node.js code uses `process.env`, `fs`, streams, or other built-in modules in the same codepath, add Node's declarations too:\n\n```bash\nnpm install --save-dev @types/node\n```\n\nThere are no package-specific environment variables. For application configuration, define your own API base URL and token:\n\n```bash\nexport API_BASE_URL=\"https://api.example.com\"\nexport API_TOKEN=\"replace-me\"\n```\n\n## Choose An Import Style\n\nThe declarations target the `superagent` module itself. The configuration-independent TypeScript import style is:\n\n```typescript\nimport request = require(\"superagent\");\n```\n\nIf you prefer default imports, enable `esModuleInterop` or `allowSyntheticDefaultImports` in `tsconfig.json` and then import `superagent` normally.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"types\": [\"node\"]\n  }\n}\n```\n\nIf your project uses `compilerOptions.types`, you usually only need `\"node\"` for Node.js APIs. You do not import or list `\"@types/superagent\"` directly in application code.\n\n## Initialization And Auth\n\nSuperAgent does not require a separate client constructor. In most TypeScript apps, keep configuration at the application boundary and build requests from environment-driven values.\n\n```typescript\nimport request = require(\"superagent\");\n\nconst apiBaseUrl = process.env.API_BASE_URL ?? \"https://api.example.com\";\nconst apiToken = process.env.API_TOKEN;\n\nfunction apiUrl(path: string): string {\n  return new URL(path, apiBaseUrl).toString();\n}\n\nexport async function getCurrentUser() {\n  if (!apiToken) {\n    throw new Error(\"API_TOKEN is required\");\n  }\n\n  const response = await request\n    .get(apiUrl(\"/me\"))\n    .auth(apiToken, { type: \"bearer\" })\n    .accept(\"json\");\n\n  return response.body;\n}\n```\n\nFor services that expect an explicit header instead of bearer auth, use `.set(\"Authorization\", \"Bearer ...\")`.\n\n## Common Workflows\n\n### Send A JSON `GET` Request\n\nUse `.query()` for URL parameters, `.set()` for headers, and `.accept(\"json\")` when you expect JSON back.\n\n```typescript\nimport request = require(\"superagent\");\n\nconst apiBaseUrl = process.env.API_BASE_URL ?? \"https://api.example.com\";\n\nasync function listUsers() {\n  const response = await request\n    .get(new URL(\"/users\", apiBaseUrl).toString())\n    .query({ role: \"admin\", limit: 20 })\n    .set(\"x-request-id\", \"req_123\")\n    .accept(\"json\");\n\n  return response.body;\n}\n```\n\n### Post A JSON Body\n\nUse `.send()` with a plain object for JSON request bodies.\n\n```typescript\nimport request = require(\"superagent\");\n\ntype CreateUserInput = {\n  email: string;\n  name: string;\n};\n\nasync function createUser(input: CreateUserInput) {\n  const response = await request\n    .post(\"https://api.example.com/users\")\n    .send(input)\n    .accept(\"json\");\n\n  return response.body;\n}\n```\n\n### Upload Files With Multipart Form Data\n\nFor file uploads in Node.js, combine `.field()` and `.attach()`.\n\n```typescript\nimport fs from \"node:fs\";\nimport request = require(\"superagent\");\n\nasync function uploadAvatar(filePath: string) {\n  const response = await request\n    .post(\"https://api.example.com/uploads\")\n    .field(\"folder\", \"avatars\")\n    .attach(\"file\", fs.createReadStream(filePath), \"avatar.png\")\n    .accept(\"json\");\n\n  return response.body;\n}\n```\n\n### Reuse Cookies With `request.agent()`\n\nUse an agent when a workflow depends on cookies or other request state shared across multiple calls.\n\n```typescript\nimport request = require(\"superagent\");\n\nconst apiBaseUrl = process.env.API_BASE_URL ?? \"https://api.example.com\";\n\nasync function readProfileAfterLogin(email: string, password: string) {\n  const agent = request.agent();\n\n  await agent\n    .post(new URL(\"/login\", apiBaseUrl).toString())\n    .send({ email, password });\n\n  const response = await agent\n    .get(new URL(\"/me\", apiBaseUrl).toString())\n    .accept(\"json\");\n\n  return response.body;\n}\n```\n\nCreate a fresh agent per login flow or per test when you need isolation.\n\n### Accept Expected Non-2xx Responses\n\nBy default, SuperAgent treats non-2xx responses as errors. Use `.ok()` when your application expects statuses such as `404` or `409` in a normal control flow.\n\n```typescript\nimport request = require(\"superagent\");\n\nasync function findUser(userId: string) {\n  const response = await request\n    .get(`https://api.example.com/users/${userId}`)\n    .ok((res) => res.status < 500)\n    .accept(\"json\");\n\n  if (response.status === 404) {\n    return null;\n  }\n\n  return response.body;\n}\n```\n\n## Type The JSON Boundary Explicitly\n\n`@types/superagent` describes the request and response APIs, but your application's JSON schema still needs its own types. Narrow `response.body` at the boundary where HTTP data enters your app.\n\n```typescript\nimport request = require(\"superagent\");\n\ntype User = {\n  id: string;\n  email: string;\n  role: \"admin\" | \"member\";\n};\n\nfunction isUser(value: unknown): value is User {\n  return (\n    typeof value === \"object\" &&\n    value !== null &&\n    \"id\" in value &&\n    typeof (value as { id: unknown }).id === \"string\" &&\n    \"email\" in value &&\n    typeof (value as { email: unknown }).email === \"string\" &&\n    \"role\" in value &&\n    ((value as { role: unknown }).role === \"admin\" ||\n      (value as { role: unknown }).role === \"member\")\n  );\n}\n\nasync function getUser(userId: string): Promise<User> {\n  const response = await request\n    .get(`https://api.example.com/users/${userId}`)\n    .accept(\"json\");\n\n  const body: unknown = response.body;\n\n  if (!isUser(body)) {\n    throw new Error(\"Unexpected response body\");\n  }\n\n  return body;\n}\n```\n\nThis keeps transport concerns in SuperAgent and schema validation in your application code.\n\n## Common Pitfalls\n\n- Install both `superagent` and `@types/superagent`; the type package does not include runtime code.\n- Import from `\"superagent\"`, not from `\"@types/superagent\"`.\n- Prefer `import request = require(\"superagent\")` unless your `tsconfig` enables interop for default imports.\n- `response.body` is not a substitute for your application's own response types; narrow or validate it before use.\n- Use `request.agent()` only when you need shared cookies or state across multiple requests.\n- Use `.ok()` when non-2xx statuses belong in a normal code path instead of being treated as failures.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/superagent\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/superagent\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/superagent/index.d.ts\n- https://www.npmjs.com/package/superagent\n- https://github.com/ladjs/superagent\n- https://github.com/ladjs/superagent/blob/master/README.md\n"
  },
  {
    "path": "content/typescript/docs/supertest/typescript/DOC.md",
    "content": "---\nname: supertest\ndescription: \"TypeScript declarations for SuperTest request builders, agents, and response objects when testing Node HTTP servers and Express apps.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,supertest,testing,node,http,express,superagent,types,definitelytyped\"\n---\n\n# SuperTest TypeScript Guide\n\n## Golden Rule\n\nInstall the real `supertest` runtime package and the `@types/supertest` declaration package together.\n\n`@types/supertest` only provides TypeScript declarations. Your test code imports and executes `supertest`; the declaration package gives the compiler and editor type information for `request()`, `request.agent()`, chained request builders such as `.get()`, `.post()`, `.query()`, `.set()`, `.send()`, `.expect()`, and the response object you get back from awaited requests.\n\n## Install\n\n```bash\nnpm install --save-dev supertest\nnpm install --save-dev typescript @types/supertest @types/node\n```\n\nIf your project already has `supertest`, add only the missing declarations:\n\n```bash\nnpm install --save-dev @types/supertest @types/node\n```\n\nIf you are testing an Express app, you usually also want the framework types in the same project:\n\n```bash\nnpm install --save-dev @types/express\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup points are your import style, your TypeScript compiler options, and whether you target an in-process app or a real server.\n\n### Import `supertest`\n\nThe declaration package uses `export =`, so the safest import form is:\n\n```typescript\nimport request = require(\"supertest\");\n```\n\nIf your project enables `esModuleInterop` or `allowSyntheticDefaultImports`, the more common default import form also works:\n\n```typescript\nimport request from \"supertest\";\n```\n\nImport code from `supertest`, not from `@types/supertest`.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\n`@types/supertest` does not need any runtime bootstrap. Once the package is installed, importing `supertest` is enough.\n\n## Common Workflows\n\n### Test an in-process Express app\n\nThe usual SuperTest pattern is to pass your app directly to `request(app)` instead of listening on a port.\n\n```typescript\nimport express from \"express\";\nimport request from \"supertest\";\n\nconst app = express();\n\napp.use(express.json());\n\napp.get(\"/health\", (_req, res) => {\n  res.json({ ok: true });\n});\n\nasync function checkHealth() {\n  await request(app)\n    .get(\"/health\")\n    .expect(\"Content-Type\", /json/)\n    .expect(200);\n}\n```\n\nThis keeps tests fast and avoids managing a separate port for simple integration tests.\n\n### Send headers, query parameters, and JSON bodies\n\nSuperTest request builders are chainable, so common HTTP setup reads naturally in TypeScript.\n\n```typescript\nimport express from \"express\";\nimport request from \"supertest\";\n\nconst app = express();\n\napp.use(express.json());\n\napp.post(\"/users\", (req, res) => {\n  res.status(201).json({\n    id: \"user_123\",\n    email: req.body.email,\n    admin: req.query.admin === \"true\",\n    requestId: req.header(\"x-request-id\") ?? null,\n  });\n});\n\nasync function createUser() {\n  const res = await request(app)\n    .post(\"/users\")\n    .query({ admin: \"true\" })\n    .set(\"x-request-id\", \"req_123\")\n    .send({ email: \"ada@example.com\" })\n    .expect(201);\n\n  return res.body;\n}\n```\n\nUse `.query()` for URL parameters, `.set()` for headers, and `.send()` for request bodies.\n\n### Reuse cookies with `request.agent()`\n\nUse an agent when a test flow depends on cookies or other session state carried across requests.\n\n```typescript\nimport express from \"express\";\nimport request from \"supertest\";\n\nconst app = express();\n\napp.use(express.json());\n\napp.post(\"/login\", (_req, res) => {\n  res.cookie(\"session\", \"s_123\").status(204).end();\n});\n\napp.get(\"/me\", (req, res) => {\n  const authenticated = req.header(\"cookie\")?.includes(\"session=s_123\");\n\n  if (!authenticated) {\n    res.status(401).json({ error: \"unauthorized\" });\n    return;\n  }\n\n  res.json({ id: \"user_123\" });\n});\n\nasync function readSessionBack() {\n  const agent = request.agent(app);\n\n  await agent.post(\"/login\").expect(204);\n\n  const res = await agent.get(\"/me\").expect(200);\n  return res.body;\n}\n```\n\nUse a fresh agent per test when you want isolation between test cases.\n\n### Type your response bodies at the application boundary\n\nSuperTest can describe the HTTP interaction, but it cannot infer your app's JSON schema automatically. Narrow `res.body` in your test code when the response shape matters.\n\n```typescript\nimport express from \"express\";\nimport request from \"supertest\";\n\ntype MeResponse = {\n  id: string;\n};\n\nfunction isMeResponse(value: unknown): value is MeResponse {\n  return (\n    typeof value === \"object\" &&\n    value !== null &&\n    \"id\" in value &&\n    typeof (value as { id: unknown }).id === \"string\"\n  );\n}\n\nconst app = express();\n\napp.get(\"/me\", (_req, res) => {\n  res.json({ id: \"user_123\" });\n});\n\nasync function getCurrentUser() {\n  const res = await request(app).get(\"/me\").expect(200);\n  const body: unknown = res.body;\n\n  if (!isMeResponse(body)) {\n    throw new Error(\"Unexpected response shape\");\n  }\n\n  return body.id;\n}\n```\n\nThis keeps transport assertions and application-shape checks separate, which is usually the cleanest TypeScript boundary.\n\n### Target a real `http.Server` when needed\n\nIf your app must be initialized exactly as production code starts it, you can pass a server object instead of an app instance.\n\n```typescript\nimport express from \"express\";\nimport { createServer } from \"node:http\";\nimport request from \"supertest\";\n\nconst app = express();\nconst server = createServer(app);\n\napp.get(\"/health\", (_req, res) => {\n  res.status(200).end();\n});\n\nasync function checkServer() {\n  try {\n    await request(server).get(\"/health\").expect(200);\n  } finally {\n    server.close();\n  }\n}\n```\n\nUse this form only when you need server-level behavior; `request(app)` is simpler for most tests.\n\n## Important Pitfalls\n\n- `@types/supertest` is a declaration package only. Install `supertest` separately for the runtime.\n- Import from `supertest`, not from `@types/supertest`.\n- If you do not enable `esModuleInterop` or `allowSyntheticDefaultImports`, prefer `import request = require(\"supertest\")` over a default import.\n- `request(app)` usually does not need `app.listen()`. Starting a real listener unnecessarily can slow tests and leave open handles.\n- `request.agent()` persists cookies across calls. Reuse it only when you want shared session state.\n- `res.body` is not automatically narrowed to your application's JSON type. Add a local interface, schema, or type guard when response shape matters.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/supertest==7.2.0`.\n- The package documents TypeScript declarations only; the runtime behavior still comes from the `supertest` package you execute in tests.\n- Keep `supertest` and `@types/supertest` current together so the declared request-builder surface matches the runtime you are actually using.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/supertest\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/supertest\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/supertest/index.d.ts\n- https://www.npmjs.com/package/supertest\n- https://github.com/ladjs/supertest\n"
  },
  {
    "path": "content/typescript/docs/tar/typescript/DOC.md",
    "content": "---\nname: tar\ndescription: \"TypeScript guide for the `tar` package: install the Node runtime package, import its exported types from `tar`, and use typed archive create, extract, and list workflows correctly.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"7.0.87\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,tar,node,archive,filesystem,types,npm\"\n---\n\n# tar TypeScript Guide\n\n## Golden Rule\n\nUse the runtime package `tar` in your code and import values and types from `\"tar\"`.\n\nThe current `tar` 7.x package publishes TypeScript declaration files in its export map for both `import` and `require` entry points. In practice, your TypeScript boundary is the runtime package: `create`, `extract`, `list`, `update`, `replace`, `ReadEntry`, and the exported `TarOptionsWithAliases*` types all come from `\"tar\"`.\n\nDo not import anything from `@types/tar` in application source files.\n\n## Install\n\n`tar` is a Node.js package. The published runtime package declares `node: >=18`.\n\n```bash\nnpm install tar\nnpm install -D typescript @types/node\n```\n\nIf your dependency graph already includes `@types/tar`, keep `tar` installed as the runtime dependency your app actually executes.\n\n## Initialization\n\nThere are no environment variables, credentials, or client objects to configure.\n\nThe practical setup is your TypeScript compiler configuration and the way you import from `tar`.\n\n### Recommended `tsconfig.json`\n\n`tar` uses Node built-in modules and a conditional export map. A Node-oriented compiler configuration keeps module resolution predictable:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project does not restrict `compilerOptions.types`, you can omit the `types` field entirely.\n\n### Import values and types from `tar`\n\nUse named imports from the runtime package:\n\n```typescript\nimport {\n  create,\n  extract,\n  list,\n  update,\n  type ReadEntry,\n  type TarOptionsWithAliasesAsyncFile,\n} from \"tar\";\n```\n\n## Common Workflows\n\n### Create a gzipped archive file\n\nUse `create()` with a `file` option when you want a `Promise<void>` that resolves after the archive is written.\n\n```typescript\nimport {\n  create,\n  type TarOptionsWithAliasesAsyncFile,\n} from \"tar\";\n\nconst archiveOptions: TarOptionsWithAliasesAsyncFile = {\n  cwd: \"dist\",\n  file: \"artifacts/app.tar.gz\",\n  gzip: true,\n  portable: true,\n};\n\nawait create(archiveOptions, [\"server.js\", \"package.json\", \"public\"]);\n```\n\n`portable: true` omits system-specific metadata and is useful when you want archives that are less dependent on the machine that created them.\n\n### Extract into a target directory\n\nUse `extract()` with `cwd` and `strip` to control where files land, and `filter` to skip entries you do not want to write.\n\n```typescript\nimport { extract } from \"tar\";\n\nawait extract({\n  file: \"artifacts/app.tar.gz\",\n  cwd: \"vendor/app\",\n  strip: 1,\n  filter: (path, entry) => {\n    return !path.startsWith(\"node_modules/\") && entry.type !== \"SymbolicLink\";\n  },\n});\n```\n\n### List entries and capture typed metadata\n\n`onReadEntry` receives `ReadEntry` objects, so you can safely work with `path`, `size`, `type`, and other entry metadata.\n\n```typescript\nimport { list, type ReadEntry } from \"tar\";\n\nconst entries: Array<Pick<ReadEntry, \"path\" | \"size\" | \"type\">> = [];\n\nawait list({\n  file: \"artifacts/app.tar.gz\",\n  onReadEntry(entry) {\n    entries.push({\n      path: entry.path,\n      size: entry.size,\n      type: entry.type,\n    });\n  },\n});\n\nconsole.log(entries);\n```\n\n### Update an existing archive only when files are newer\n\nUse `update()` when the archive already exists and you only want to append changed files.\n\n```typescript\nimport { update } from \"tar\";\n\nawait update(\n  {\n    file: \"artifacts/app.tar\",\n    cwd: \"dist\",\n  },\n  [\"package.json\", \"templates\"],\n);\n```\n\n### Pipe a tarball stream into the extractor\n\nWithout a `file` option, `extract()` returns a writable `Unpack` stream.\n\n```typescript\nimport { createReadStream } from \"node:fs\";\nimport { extract } from \"tar\";\n\ncreateReadStream(\"downloads/package.tgz\").pipe(\n  extract({\n    cwd: \"tmp/package\",\n    strip: 1,\n  }),\n);\n```\n\n## Important Pitfalls\n\n- Import from `tar`, not from `@types/tar`.\n- `file` changes the return type. Async calls with `file` return `Promise<void>`, while calls without `file` return streams.\n- `update()` and `replace()` only work on existing archive files and require the `file` option.\n- Leave `preservePaths` off for untrusted archives. The maintainer docs explicitly warn that it is almost always unsafe on untrusted input.\n- `noResume: true` on listing or parsing means you must consume or resume entry streams yourself, or the operation will not finish.\n- `noMtime: true` disables `mtime`-based behaviors such as `update()` and extraction with `newer`.\n"
  },
  {
    "path": "content/typescript/docs/terser/typescript/DOC.md",
    "content": "---\nname: terser\ndescription: \"TypeScript setup for Terser minification scripts and build pipelines. `@types/terser@3.12.0` is compile-time only; import and run `terser` itself.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.12.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,terser,minify,build,source-maps,types,npm\"\n---\n\n# Terser TypeScript Guide\n\n## Golden Rule\n\n`@types/terser` only provides TypeScript declarations. The runtime API and CLI come from `terser`.\n\nIn application code and build scripts, import from `\"terser\"`. Current `terser` releases publish their own declarations through `tools/terser.d.ts`, and the official README documents both `require(\"terser\")` and `import { minify } from \"terser\"`.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install terser\nnpm install -D typescript\n```\n\nIf your minification script runs in Node.js and uses built-in modules such as `node:fs` or `process.env`, add Node's declarations too:\n\n```bash\nnpm install -D @types/node\n```\n\nIf you are maintaining an older project that explicitly pins the DefinitelyTyped package, keep it as a dev dependency only:\n\n```bash\nnpm install -D @types/terser\n```\n\nThere are no required credentials, auth flows, or service-specific environment variables.\n\n## TypeScript Setup\n\nUse a normal Node-oriented `tsconfig.json` for build scripts and tooling:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project uses `compilerOptions.types`, include only ambient packages such as `node` there. Do not add `terser` to `types`; its declarations are module exports resolved from the runtime package import.\n\nImport runtime functions and types from `terser` itself:\n\n```typescript\nimport {\n  minify,\n  minify_sync,\n  type MinifyOptions,\n  type MinifyOutput,\n} from \"terser\";\n```\n\nDo not import anything from `@types/terser` in application code.\n\n## Initialization\n\nThere is no client object or one-time initialization step.\n\nThe practical setup boundary is the options object you pass to `minify()` or `minify_sync()`, plus your own file-system code for reading inputs and writing outputs.\n\nTerser also documents one optional environment variable for debugging calls made by other tools:\n\n```bash\nexport TERSER_DEBUG_DIR=\"/tmp/terser-debug\"\n```\n\nWhen this variable is set, Terser writes debug logs containing the input code and options for each `minify()` call.\n\n## Common Workflows\n\n### Minify ES module input with typed options\n\n`minify()` accepts a string, a string array, or a `{ [fileName]: code }` object and returns `Promise<MinifyOutput>`.\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport { minify, type MinifyOptions } from \"terser\";\n\nconst options: MinifyOptions = {\n  module: true,\n  compress: {\n    passes: 2,\n    drop_console: true,\n  },\n  mangle: true,\n  format: {\n    comments: false,\n  },\n  sourceMap: {\n    filename: \"dist/app.min.js\",\n    url: \"app.min.js.map\",\n  },\n};\n\nconst result = await minify(\n  {\n    \"src/app.js\": \"export function add(first, second) { return first + second; }\",\n  },\n  options,\n);\n\nif (!result.code) {\n  throw new Error(\"Terser did not return output code\");\n}\n\nawait writeFile(\"dist/app.min.js\", result.code, \"utf8\");\n\nif (result.map) {\n  const mapText = typeof result.map === \"string\"\n    ? result.map\n    : JSON.stringify(result.map);\n\n  await writeFile(\"dist/app.min.js.map\", mapText, \"utf8\");\n}\n```\n\nUse `module: true` when the input is an ES module. The README notes that this implies strict mode and enables top-level mangling when compression or mangling is active.\n\n### Reuse `MinifyOptions` in a helper\n\nThe runtime package exports the option interfaces, so you can centralize your Terser configuration without duplicating option shapes by hand.\n\n```typescript\nimport { type MinifyOptions } from \"terser\";\n\nexport function makeTerserOptions(isProduction: boolean): MinifyOptions {\n  return {\n    module: true,\n    compress: isProduction\n      ? {\n          passes: 2,\n          drop_debugger: true,\n        }\n      : false,\n    mangle: isProduction,\n    format: {\n      comments: false,\n    },\n  };\n}\n```\n\nThis keeps your build pipeline aligned with Terser's actual TypeScript surface, including nested options such as `compress`, `mangle`, `format`, and `sourceMap`.\n\n### Persist `nameCache` across multiple minify runs\n\nTerser documents `nameCache` as a read/write object. Reuse the same object across calls and persist it yourself if you want stable mangled names between runs.\n\n```typescript\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { minify, type MinifyOptions } from \"terser\";\n\nconst cachePath = \".cache/terser-name-cache.json\";\nconst nameCache: Record<string, unknown> = existsSync(cachePath)\n  ? (JSON.parse(readFileSync(cachePath, \"utf8\")) as Record<string, unknown>)\n  : {};\n\nconst options: MinifyOptions = {\n  mangle: {\n    properties: true,\n  },\n  nameCache,\n};\n\nconst first = await minify({\n  \"part1.js\": \"function add(first, second) { return first + second; }\",\n}, options);\n\nconst second = await minify({\n  \"part2.js\": \"console.log(add(1 + 2, 3 + 4));\",\n}, options);\n\nwriteFileSync(\"dist/part1.min.js\", first.code ?? \"\", \"utf8\");\nwriteFileSync(\"dist/part2.min.js\", second.code ?? \"\", \"utf8\");\nwriteFileSync(cachePath, JSON.stringify(nameCache), \"utf8\");\n```\n\nBecause the type of `nameCache` is just `object`, it is common to keep the local variable as `Record<string, unknown>` and pass that object through `MinifyOptions`.\n\n### Use `minify_sync()` in a synchronous build script\n\nThe declarations export both `minify()` and `minify_sync()`.\n\n```typescript\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { minify_sync, type MinifyOptions } from \"terser\";\n\nconst input = readFileSync(\"dist/server.js\", \"utf8\");\n\nconst options: MinifyOptions = {\n  compress: true,\n  mangle: true,\n  sourceMap: true,\n};\n\nconst result = minify_sync({ \"dist/server.js\": input }, options);\n\nif (!result.code) {\n  throw new Error(\"Terser did not return output code\");\n}\n\nwriteFileSync(\"dist/server.min.js\", result.code, \"utf8\");\n\nif (typeof result.map === \"string\") {\n  writeFileSync(\"dist/server.min.js.map\", result.map, \"utf8\");\n}\n```\n\nUse the synchronous API only when your surrounding tool is already synchronous. For most Node build scripts, `await minify(...)` is easier to compose with file I/O.\n\n### Run the CLI from a package script\n\nThe Terser CLI is part of the `terser` package, not `@types/terser`.\n\n```json\n{\n  \"scripts\": {\n    \"build:minify\": \"terser dist/app.js -o dist/app.min.js -c -m --source-map\"\n  }\n}\n```\n\nThe README states that `--source-map --output output.js` writes the map to `output.js.map`. If you need an explicit source-map URL, use the documented option form:\n\n```bash\nnpx terser dist/app.js \\\n  -o dist/app.min.js \\\n  -c -m \\\n  --source-map \"url='app.min.js.map'\"\n```\n\n## Important Pitfalls\n\n- `minify()` is asynchronous and returns `Promise<MinifyOutput>`.\n- `MinifyOutput.code` is optional in the type definitions, so check it before writing files.\n- `sourceMap: true` or `sourceMap: { ... }` returns map data in `result.map`; it does not save the map for you.\n- `nameCache` is mutated in place. Reuse the same object across calls if you want stable mangled names.\n- `module: true` changes minification behavior for ES module input and enables top-level mangling when compression or mangling is enabled.\n- `MinifyOptions.output` is marked deprecated in the declarations. Prefer `format`.\n- Import from `terser`, not from `@types/terser`.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/terser` package entry at version `3.12.0`.\n- The practical runtime boundary is still the `terser` package: its package metadata exports both runtime entry points and `tools/terser.d.ts` for TypeScript consumers.\n- The official README documents both CommonJS and ESM imports: `require(\"terser\")` and `import { minify } from \"terser\"`.\n- The exported declaration surface includes `minify`, `minify_sync`, `MinifyOptions`, `MinifyOutput`, `CompressOptions`, `MangleOptions`, `FormatOptions`, and `SourceMapOptions`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/terser\n- https://www.npmjs.com/package/terser\n- https://github.com/terser/terser/blob/master/README.md\n- https://github.com/terser/terser/blob/master/tools/terser.d.ts\n"
  },
  {
    "path": "content/typescript/docs/three/typescript/DOC.md",
    "content": "---\nname: three\ndescription: \"TypeScript setup for the three runtime package, including the bundled declarations that replace direct @types/three installs in modern projects.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.183.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,three,webgl,3d,browser,types,definitelytyped\"\n---\n\n# Three TypeScript Guide\n\n## Golden Rule\n\nUse the `three` runtime package as both your JavaScript dependency and your TypeScript type source.\n\nModern `three` releases publish their own declarations. The `@types/three` package exists on npm, but for new projects you import from `\"three\"`, not from `\"@types/three\"`.\n\n## Install\n\nInstall `three` and TypeScript:\n\n```bash\nnpm install three\nnpm install -D typescript\n```\n\nIf an older template or lockfile added `@types/three` directly, remove it and keep `three` as the single source of declarations:\n\n```bash\nnpm uninstall @types/three\n```\n\n## Initialization\n\nThere are no environment variables, credentials, or client singletons to configure.\n\nThe practical setup is:\n\n- a browser-oriented TypeScript configuration\n- a canvas element in your page\n- imports from `three`\n\n### Recommended `tsconfig.json`\n\nFor a browser app, keep ES and DOM library types enabled:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"lib\": [\"ES2022\", \"DOM\"],\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your app already has a working front-end TypeScript config, the important part is that the project resolves the `three` module normally and includes browser DOM types for canvas and renderer APIs.\n\n### If you restrict `compilerOptions.types`\n\n`three` is a normal module package, not an ambient `@types` package you load through `compilerOptions.types`.\n\nIf your project sets `compilerOptions.types`, keep the entries you need for your tooling, but continue importing `three` normally:\n\n```typescript\nimport { Scene, WebGLRenderer } from \"three\";\n```\n\n## Create A Typed Scene\n\nThis is the smallest practical browser setup with typed scene, camera, geometry, material, mesh, and renderer objects.\n\n```typescript\nimport {\n  BoxGeometry,\n  Mesh,\n  MeshNormalMaterial,\n  PerspectiveCamera,\n  Scene,\n  WebGLRenderer,\n} from \"three\";\n\nconst canvas = document.querySelector<HTMLCanvasElement>(\"#app\");\n\nif (!canvas) {\n  throw new Error(\"Missing #app canvas\");\n}\n\nconst scene = new Scene();\n\nconst camera = new PerspectiveCamera(\n  75,\n  canvas.clientWidth / canvas.clientHeight,\n  0.1,\n  1000,\n);\ncamera.position.z = 5;\n\nconst geometry = new BoxGeometry(1, 1, 1);\nconst material = new MeshNormalMaterial();\nconst cube = new Mesh(geometry, material);\n\nscene.add(cube);\n\nconst renderer = new WebGLRenderer({ canvas, antialias: true });\nrenderer.setSize(canvas.clientWidth, canvas.clientHeight, false);\n\nfunction frame() {\n  cube.rotation.x += 0.01;\n  cube.rotation.y += 0.02;\n\n  renderer.render(scene, camera);\n  requestAnimationFrame(frame);\n}\n\nframe();\n```\n\nAll constructor arguments and instance methods in this example are typed from the `three` package itself.\n\n## Use `import type` For Shared APIs\n\nWhen a file only needs compile-time names, use type-only imports from `three`.\n\n```typescript\nimport type { Camera, Object3D, Scene, WebGLRenderer } from \"three\";\n\nexport function addObject(scene: Scene, object: Object3D) {\n  scene.add(object);\n}\n\nexport function renderScene(\n  renderer: WebGLRenderer,\n  scene: Scene,\n  camera: Camera,\n) {\n  renderer.render(scene, camera);\n}\n```\n\nThis keeps the runtime boundary explicit while still using the same exported declaration set.\n\n## Type Browser Elements At The DOM Boundary\n\nThe most common typing issue in `three` apps is not the scene graph itself; it is the DOM element you pass into the renderer or use for sizing.\n\nUse generic DOM queries so the compiler knows you are working with a canvas:\n\n```typescript\nconst canvas = document.querySelector<HTMLCanvasElement>(\"#app\");\n\nif (!canvas) {\n  throw new Error(\"Missing canvas\");\n}\n\nconst renderer = new WebGLRenderer({ canvas });\n```\n\nThis is usually better than broad casts such as `document.getElementById(\"app\") as HTMLCanvasElement` because the null check remains visible in the control flow.\n\n## Keep Reusable Helpers Typed With `three` Exports\n\nFor library code inside your app, accept the types that `three` already exports instead of widening everything to plain objects.\n\n```typescript\nimport { Vector3 } from \"three\";\nimport type { Object3D } from \"three\";\n\nexport function placeAt(object: Object3D, x: number, y: number, z: number) {\n  object.position.copy(new Vector3(x, y, z));\n}\n```\n\nThat keeps helpers aligned with the runtime API surface you actually call.\n\n## Common Pitfalls\n\n- For new projects, install `three`, not `@types/three`.\n- Import from `\"three\"`, never from `\"@types/three\"`.\n- Keep `\"DOM\"` in `compilerOptions.lib` for browser renderer code; `WebGLRenderer` works with browser canvas and WebGL APIs.\n- If your `tsconfig.json` restricts `compilerOptions.types`, remember that `three` still resolves through normal module imports, not through that ambient package list.\n- Keep your code examples and runtime package version aligned with the `three` release you actually ship.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/three\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/three\n- https://www.npmjs.com/package/three\n- https://threejs.org/manual/#en/installation\n- https://threejs.org/manual/#en/creating-a-scene\n- https://threejs.org/docs/#api/en/renderers/WebGLRenderer\n- https://www.typescriptlang.org/tsconfig/#types\n"
  },
  {
    "path": "content/typescript/docs/topojson-specification/typescript/DOC.md",
    "content": "---\nname: topojson-specification\ndescription: \"TypeScript declarations for TopoJSON topology documents, including installation, type-only imports, compiler setup, and working with named objects, arcs, and transforms.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.0.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,topojson,geojson,cartography,types,definitelytyped,npm\"\n---\n\n# TopoJSON Specification TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/topojson-specification` for type checking, then import types from `\"topojson-specification\"` in your code.\n\n`@types/topojson-specification` is a declaration package only. It describes the shape of TopoJSON topology documents such as `Topology`, named objects under `topology.objects`, the shared `arcs` array, and optional fields like `transform` and `bbox`. It does not parse files, convert TopoJSON to GeoJSON, or provide a runtime client.\n\n## Install\n\nAdd the declaration package to your TypeScript project:\n\n```bash\nnpm install -D typescript @types/topojson-specification@1.0.5\n```\n\nIf your project already has TypeScript, add only the declarations:\n\n```bash\nnpm install -D @types/topojson-specification@1.0.5\n```\n\nThere are no package-specific environment variables, credentials, or authentication steps.\n\n## Initialization\n\nThe important setup is your compiler configuration and your import style.\n\n### Use type-only imports\n\nImport from `\"topojson-specification\"`, never from `\"@types/topojson-specification\"`.\n\nPrefer `import type` so TypeScript erases the import in emitted JavaScript when you only need declarations:\n\n```typescript\nimport type { Topology } from \"topojson-specification\";\n```\n\nThis is the safest default for application code that only needs static types.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you explicitly restrict ambient packages with `compilerOptions.types`, include `\"topojson-specification\"` in the project that compiles your TopoJSON-related code:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"topojson-specification\"]\n  }\n}\n```\n\n`node` is only needed there if the same project also uses Node.js APIs such as `fs`.\n\n## Common Workflows\n\n### Parse and type a TopoJSON file\n\nUse the declarations to annotate parsed JSON before the rest of your code touches `objects`, `arcs`, or `transform`.\n\n```typescript\nimport { readFileSync } from \"node:fs\";\nimport type { Topology } from \"topojson-specification\";\n\nfunction parseTopologyFile(path: string): Topology {\n  const value = JSON.parse(readFileSync(path, \"utf8\")) as Partial<Topology>;\n\n  if (value.type !== \"Topology\" || value.objects === undefined || value.arcs === undefined) {\n    throw new Error(\"Expected a Topology document\");\n  }\n\n  return value as Topology;\n}\n\nconst topology = parseTopologyFile(\"./data/world.topojson\");\n\nconsole.log(topology.type);\nconsole.log(Object.keys(topology.objects));\nconsole.log(topology.arcs.length);\n```\n\nThis keeps the JSON boundary explicit and makes it easier to guard malformed input before it spreads through the rest of your app.\n\n### Access named objects safely\n\n`topology.objects` is a map of named TopoJSON objects. Pull the object out once, guard that it exists, then narrow by `type` before using geometry-specific fields.\n\n```typescript\nimport type { Topology } from \"topojson-specification\";\n\ntype NamedObject = Topology[\"objects\"][string];\n\nfunction requireObject(topology: Topology, name: string): NamedObject {\n  const object = topology.objects[name];\n\n  if (!object) {\n    throw new Error(`Missing topology object: ${name}`);\n  }\n\n  return object;\n}\n\nconst counties = requireObject(topology, \"counties\");\n\nif (counties.type === \"GeometryCollection\") {\n  console.log(counties.geometries.length);\n} else if (\"arcs\" in counties) {\n  console.log(counties.arcs);\n}\n```\n\nThis pattern works well when a single topology file contains multiple named layers such as counties, states, or land boundaries.\n\n### Guard optional transforms\n\nThe TopoJSON `transform` member is optional. Check for it before reading `scale` or `translate`.\n\n```typescript\nimport type { Topology } from \"topojson-specification\";\n\nfunction hasTransform(\n  topology: Topology,\n): topology is Topology & { transform: NonNullable<Topology[\"transform\"]> } {\n  return topology.transform !== undefined;\n}\n\nif (hasTransform(topology)) {\n  const [scaleX, scaleY] = topology.transform.scale;\n  const [translateX, translateY] = topology.transform.translate;\n\n  console.log(scaleX, scaleY, translateX, translateY);\n}\n```\n\nApply the same pattern to other optional fields such as `bbox`, `id`, or `properties` when your code depends on them.\n\n### Keep function boundaries typed with `Topology`\n\nWhen you pass topology data between parsing, validation, and rendering code, keep the boundary typed so downstream code does not fall back to `any`.\n\n```typescript\nimport type { Topology } from \"topojson-specification\";\n\nexport function listObjectNames(topology: Topology): string[] {\n  return Object.keys(topology.objects);\n}\n\nexport function hasObject(topology: Topology, name: string): boolean {\n  return topology.objects[name] !== undefined;\n}\n```\n\nThis is especially useful when your runtime code later hands the topology to another package for conversion or rendering. The declaration package covers the TopoJSON document shape up to that boundary.\n\n## Important Pitfalls\n\n- `@types/topojson-specification` contains declarations only. It does not provide a parser, a converter, or rendering utilities.\n- Import from `\"topojson-specification\"`, not from `\"@types/topojson-specification\"`.\n- Prefer `import type` for type-only usage so your emitted JavaScript does not keep an unnecessary runtime import.\n- `topology.transform`, `bbox`, `id`, and `properties` can be absent. Guard optional fields before reading them.\n- TopoJSON line and polygon objects use `arcs`, not GeoJSON `coordinates`. Do not treat a TopoJSON geometry object as if it were already plain GeoJSON.\n- If you set `compilerOptions.types`, include `\"topojson-specification\"` or TypeScript may stop discovering the declarations in that project.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/topojson-specification==1.0.5`.\n- The package models the TopoJSON specification as TypeScript declarations and is typically used as a type-only dependency in projects that read or exchange TopoJSON documents.\n\n## Official Sources\n\n- npm package page: https://www.npmjs.com/package/@types/topojson-specification\n- DefinitelyTyped source for `@types/topojson-specification`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/topojson-specification\n- `@types/topojson-specification` declaration file: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/topojson-specification/index.d.ts\n- TopoJSON specification: https://github.com/topojson/topojson-specification\n"
  },
  {
    "path": "content/typescript/docs/tslib/typescript/DOC.md",
    "content": "---\nname: tslib\ndescription: \"Runtime helper library that TypeScript imports for emitted helpers such as __assign, __extends, __awaiter, and decorator support\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"2.8.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,tslib,compiler,helpers,tsconfig,runtime\"\n---\n\n# tslib TypeScript Guide\n\n`tslib` is the runtime package that contains the helper functions TypeScript emits for transformed code, including helpers such as `__assign`, `__extends`, `__awaiter`, `__decorate`, and related module interop helpers.\n\nUse `tslib` when you enable `importHelpers` so TypeScript imports shared helpers from the package instead of inlining the same helper implementation into every compiled file.\n\n`tslib` is not a replacement for the TypeScript compiler. Install `typescript` separately, and keep `tslib` available at runtime anywhere your compiled JavaScript imports it.\n\nNo environment variables, authentication, or client initialization are required.\n\n## Install\n\nInstall `tslib` as a runtime dependency and `typescript` as a development dependency:\n\n```bash\nnpm install tslib\nnpm install --save-dev typescript\n```\n\nThis guide targets `tslib 2.8.1`. The upstream `tslib` README says:\n\n- use the current `tslib` line for TypeScript `3.9.2` or later\n- use `tslib@^1` for TypeScript `3.8.4` or earlier\n- use `tslib@1.6.1` for TypeScript `2.3.2` or earlier\n\nIf your application or published library runs compiled JavaScript that imports `tslib`, do not move `tslib` to `devDependencies`.\n\n## Configure TypeScript To Import Helpers\n\nTurn on `importHelpers` in `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2019\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"importHelpers\": true,\n    \"outDir\": \"dist\"\n  },\n  \"include\": [\"src/**/*.ts\"]\n}\n```\n\nTypeScript documents `importHelpers` as: \"Allow importing helper functions from tslib once per project, instead of including them per-file.\"\n\nCompile normally:\n\n```bash\n./node_modules/.bin/tsc -p tsconfig.json\n```\n\nYou usually do not import `tslib` yourself in application code. The compiler inserts the helper imports in emitted JavaScript when your source code and compiler target require them.\n\n## What Changes In The Emitted JavaScript\n\nThe `tslib` README shows the core behavior of `importHelpers`.\n\nGiven TypeScript source like this:\n\n```ts\nexport const x = {};\nexport const y = { ...x };\n```\n\nTypeScript can emit helper code inline in every file, or, with `importHelpers`, emit an import from `tslib` instead. A representative CommonJS output looks like this:\n\n```js\nvar tslib_1 = require(\"tslib\");\nexports.x = {};\nexports.y = tslib_1.__assign({}, exports.x);\n```\n\nWhich helpers appear depends on the language features in your source and the compiler options you use. Typical helpers include object spread, class inheritance, async/await downleveling, decorator support, and CommonJS/ES module interop helpers.\n\n## Common Workflows\n\n### Publish compiled JavaScript that depends on `tslib`\n\nIf you publish a library that compiles TypeScript to JavaScript with `importHelpers`, keep `tslib` in `dependencies` so consumers get the runtime helper package automatically.\n\n```json\n{\n  \"name\": \"my-library\",\n  \"version\": \"1.0.0\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"dependencies\": {\n    \"tslib\": \"^2.8.1\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.0.0\"\n  }\n}\n```\n\nThis is the most important runtime boundary for `tslib`: the compiler emits the import, but Node.js, your bundler, or your browser build still has to resolve the `tslib` package at runtime.\n\n### Import a helper directly when you really need one\n\nMost projects should let TypeScript emit helper imports automatically. If you are writing generated code, runtime glue, or another tool that wants the helpers directly, import them from the package root:\n\n```ts\nimport { __assign } from \"tslib\";\n\nconst defaults = { region: \"us-east-1\", retries: 2 };\nconst overrides = { retries: 5 };\n\nexport const config = __assign({}, defaults, overrides);\n```\n\n`tslib 2.8.1` publishes its type declarations from the package itself, so no separate `@types` package is needed.\n\n### Use the package root, not internal files\n\n`tslib 2.8.1` publishes conditional exports for CommonJS, ESM, and type declarations. Import from `\"tslib\"`, not from internal paths such as `tslib/tslib.js` or `tslib/modules/index.js`.\n\n```ts\nimport { __awaiter, __generator } from \"tslib\";\n```\n\nUsing the package root lets Node.js, bundlers, and TypeScript resolve the correct entrypoint from the package `exports` map.\n\n## Important Pitfalls\n\n- `importHelpers: true` does not install `tslib` for you. If the package is missing, emitted JavaScript can fail with a module resolution error for `tslib`.\n- `tslib` is a runtime package. Keep it in `dependencies` when built output imports it.\n- `tslib` does not replace `typescript`; you still need the compiler in your toolchain.\n- `noEmitHelpers` is a different compiler option. TypeScript describes it as disabling generated helpers like `__extends` in emitted output, so do not turn it on unless your runtime or build pipeline is supplying those helpers another way.\n- Manual helper imports are an advanced case. In normal application code, let the compiler decide which helpers to emit.\n- The upstream README documents older compatibility lines. If you are pinned to TypeScript `3.8.4` or earlier, use the older `tslib` version it recommends instead of `2.8.1`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/tslib\n- https://github.com/microsoft/tslib\n- https://github.com/microsoft/tslib/blob/main/README.md\n- https://www.typescriptlang.org/tsconfig/importHelpers.html\n- https://www.typescriptlang.org/tsconfig/noEmitHelpers.html\n- https://www.typescriptlang.org/docs/\n"
  },
  {
    "path": "content/typescript/docs/typescript/typescript/DOC.md",
    "content": "---\nname: typescript\ndescription: \"Install, configure, type-check, compile, and automate TypeScript projects with the official compiler and compiler API.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.9.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,tsc,compiler,tsconfig,language,javascript\"\n---\n\n# TypeScript Compiler Guide\n\n## Golden Rule\n\nInstall `typescript` when you need the TypeScript compiler, the `tsc` CLI, or the compiler API from `\"typescript\"`.\n\nThe package type-checks and compiles your code. It does not run the emitted JavaScript, install runtime libraries, or provide environment-specific globals on its own.\n\n## Install\n\nAdd TypeScript as a development dependency:\n\n```bash\nnpm install -D typescript\n```\n\nCheck the installed compiler version:\n\n```bash\nnpx tsc --version\n```\n\n`typescript@5.9.3` declares `node >=14.17` in its package metadata.\n\n## Initialization\n\nThere are no package-specific environment variables, credentials, or client objects to configure.\n\nStart by generating a `tsconfig.json` file:\n\n```bash\nnpx tsc --init\n```\n\nFor a Node-based application, this is a practical minimal starting point:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"module\": \"nodenext\",\n    \"moduleResolution\": \"nodenext\",\n    \"strict\": true,\n    \"outDir\": \"dist\",\n    \"sourceMap\": true\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\"]\n}\n```\n\nAdjust the config for your runtime boundary:\n\n- Use `\"lib\"` to describe the runtime environment, for example browser code usually needs `\"dom\"` in addition to an ECMAScript library.\n- Use `\"jsx\"` when compiling `.tsx` files.\n- Use `\"types\"` only when you want to explicitly control which ambient type packages are included.\n\nTo inspect the fully resolved compiler configuration:\n\n```bash\nnpx tsc --showConfig -p tsconfig.json\n```\n\n## Common Workflows\n\n### Type-check a project without emitting JavaScript\n\nUse this in CI or before a production build when another tool handles the final bundle:\n\n```bash\nnpx tsc -p tsconfig.json --noEmit\n```\n\n`--noEmit` disables output generation and keeps the compiler focused on diagnostics.\n\n### Compile a project and watch for changes\n\nCompile once:\n\n```bash\nnpx tsc -p tsconfig.json\n```\n\nRecompile on file changes:\n\n```bash\nnpx tsc -p tsconfig.json --watch\n```\n\nIf you omit `-p`, `tsc` uses the `tsconfig.json` in the working directory.\n\n### Emit declaration files for a library package\n\nWhen you are publishing a library, declaration output is usually the important artifact for downstream TypeScript users:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"module\": \"es2022\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"emitDeclarationOnly\": true,\n    \"outDir\": \"dist/types\"\n  },\n  \"include\": [\"src/**/*.ts\"]\n}\n```\n\nThen build with:\n\n```bash\nnpx tsc -p tsconfig.json\n```\n\n### Type-check JavaScript files with JSDoc annotations\n\nTypeScript can check `.js` files when you enable `allowJs` and `checkJs`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"noEmit\": true\n  },\n  \"include\": [\"src/**/*.js\"]\n}\n```\n\nExample JavaScript file:\n\n```javascript\n/** @param {string} name */\nexport function greet(name) {\n  return name.toUpperCase();\n}\n\ngreet(42);\n```\n\nRunning `npx tsc -p tsconfig.json` reports the incorrect call without requiring a `.ts` conversion first.\n\n### Transpile one in-memory source string\n\nFor tooling, generators, or quick transforms, use `transpileModule` from the compiler API:\n\n```typescript\nimport * as ts from \"typescript\";\n\nconst source = `export const answer: number = 42;`;\n\nconst result = ts.transpileModule(source, {\n  fileName: \"example.ts\",\n  reportDiagnostics: true,\n  compilerOptions: {\n    target: ts.ScriptTarget.ES2022,\n    module: ts.ModuleKind.ES2022,\n    sourceMap: true,\n  },\n});\n\nif (result.diagnostics?.length) {\n  console.error(result.diagnostics.map((diagnostic) => diagnostic.messageText));\n}\n\nconsole.log(result.outputText);\n```\n\n`transpileModule` is useful for single-file transforms. It does not replace a full project build when you need cross-file type-checking.\n\n### Build from `tsconfig.json` programmatically\n\nIf you are writing custom tooling, read the config and create a `Program` explicitly:\n\n```typescript\nimport { dirname } from \"node:path\";\nimport * as ts from \"typescript\";\n\nconst formatHost: ts.FormatDiagnosticsHost = {\n  getCanonicalFileName: (fileName) => fileName,\n  getCurrentDirectory: () => process.cwd(),\n  getNewLine: () => ts.sys.newLine,\n};\n\nconst configPath = ts.findConfigFile(process.cwd(), ts.sys.fileExists, \"tsconfig.json\");\n\nif (!configPath) {\n  throw new Error(\"Could not find tsconfig.json\");\n}\n\nconst configFile = ts.readConfigFile(configPath, ts.sys.readFile);\n\nif (configFile.error) {\n  throw new Error(\n    ts.formatDiagnosticsWithColorAndContext([configFile.error], formatHost),\n  );\n}\n\nconst parsed = ts.parseJsonConfigFileContent(\n  configFile.config,\n  ts.sys,\n  dirname(configPath),\n  undefined,\n  configPath,\n);\n\nconst program = ts.createProgram({\n  rootNames: parsed.fileNames,\n  options: parsed.options,\n});\n\nconst emitResult = program.emit();\nconst diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);\n\nif (diagnostics.length > 0) {\n  console.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, formatHost));\n}\n\nprocess.exitCode = emitResult.emitSkipped ? 1 : 0;\n```\n\nThis is the right boundary when you need compiler diagnostics or output inside a build tool, code generator, or framework integration.\n\n## Important Pitfalls\n\n- `tsc app.ts` and other explicit file arguments ignore your `tsconfig.json` and compile those files with default compiler options. Use bare `tsc` or `tsc -p ...` for project builds.\n- `typescript` does not install runtime-specific type packages such as Node, Jest, or browser framework types. Add the relevant packages separately when your runtime does not ship its own declarations.\n- If you set `compilerOptions.types`, TypeScript only includes the listed type packages automatically.\n- Keep `module`, `moduleResolution`, and your runtime or bundler aligned. For modern Node projects, `nodenext` is usually the safest starting point.\n- `emitDeclarationOnly` writes `.d.ts` output but skips JavaScript output; `noEmit` skips both. Pick one deliberately.\n- `tsc --build` is for composite and project-reference builds. Use normal project compilation unless you actually maintain referenced subprojects.\n\n## Version-Sensitive Notes\n\n- This guide targets `typescript==5.9.3`.\n- `typescript@5.9.3` exposes the `tsc` and `tsserver` binaries and the compiler API from the `typescript` package entry point.\n- The package metadata requires Node `>=14.17`.\n- The CLI in 5.9.3 supports the workflows used here, including `--init`, `--showConfig`, `--watch`, `--build`, `--noEmit`, `--declaration`, and `--emitDeclarationOnly`.\n\n## Official Sources\n\n- https://www.npmjs.com/package/typescript\n- https://www.typescriptlang.org/docs/\n- https://aka.ms/tsc\n- https://aka.ms/tsconfig\n- https://www.typescriptlang.org/tsconfig/\n- https://github.com/microsoft/TypeScript/blob/v5.9.3/README.md\n- https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API\n"
  },
  {
    "path": "content/typescript/docs/unzipper/typescript/DOC.md",
    "content": "---\nname: unzipper\ndescription: \"TypeScript declarations for the Node.js unzipper runtime, including archive extraction, entry parsing, and archive inspection workflows.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.10.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,unzipper,zip,archive,node,streams,types,definitelytyped\"\n---\n\n# unzipper TypeScript Guide\n\n## Golden Rule\n\nInstall `unzipper` for the runtime and `@types/unzipper` for compile-time declarations.\n\nImport from `unzipper`, not from `@types/unzipper`:\n\n```typescript\nimport unzipper from \"unzipper\";\n```\n\n`@types/unzipper` only supplies TypeScript declarations for the `unzipper` package. It does not install the runtime, and it is meant for Node.js code that works with streams and the filesystem.\n\n## Install\n\nAdd the runtime package and the TypeScript declarations:\n\n```bash\nnpm install unzipper\nnpm install -D typescript @types/unzipper @types/node\n```\n\nIf TypeScript is already configured in the project, add only the missing declarations:\n\n```bash\nnpm install -D @types/unzipper @types/node\n```\n\n## Initialization\n\nThere is no package-specific auth flow, API key, or client object for `@types/unzipper`.\n\nThe practical setup is:\n\n- install the `unzipper` runtime package\n- let TypeScript load `@types/unzipper`\n- use Node.js stream and filesystem APIs alongside `unzipper`\n\n### Recommended `tsconfig.json`\n\nIf you want `import unzipper from \"unzipper\";`, enable interop for the CommonJS runtime package:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you do not enable `esModuleInterop`, use the CommonJS-compatible import form instead:\n\n```typescript\nimport unzipper = require(\"unzipper\");\n```\n\n### Optional environment variables for app code\n\n`@types/unzipper` has no package-defined environment variables. For scripts and services, it is common to make the archive path and output path configurable:\n\n```bash\nZIP_FILE=./fixtures/archive.zip\nUNZIP_OUTPUT_DIR=./tmp/unpacked\n```\n\n## Common Workflows\n\n### Extract a whole archive to disk\n\nUse `Extract({ path })` when you want to unpack the entire archive into a directory.\n\n```typescript\nimport { createReadStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport unzipper from \"unzipper\";\n\nasync function extractArchive(): Promise<void> {\n  const zipFile = process.env.ZIP_FILE ?? \"./fixtures/archive.zip\";\n  const outputDir = process.env.UNZIP_OUTPUT_DIR ?? \"./tmp/unpacked\";\n\n  await mkdir(outputDir, { recursive: true });\n\n  await createReadStream(zipFile)\n    .pipe(unzipper.Extract({ path: outputDir }))\n    .promise();\n}\n\nawait extractArchive();\n```\n\nThis is the simplest path when you do not need to inspect entries individually.\n\n### Parse entries and keep only selected files\n\nUse `Parse()` when you need to inspect each entry, route files to different destinations, or skip unwanted members.\n\n```typescript\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport unzipper from \"unzipper\";\n\nasync function extractReadme(zipFile: string, outputFile: string): Promise<boolean> {\n  return await new Promise<boolean>((resolve, reject) => {\n    let matched = false;\n\n    const parser = unzipper.Parse();\n\n    parser.on(\"entry\", (entry) => {\n      if (entry.type === \"File\" && entry.path === \"README.md\") {\n        matched = true;\n\n        entry\n          .pipe(createWriteStream(outputFile))\n          .on(\"finish\", () => resolve(true))\n          .on(\"error\", reject);\n\n        return;\n      }\n\n      entry.autodrain();\n    });\n\n    parser.on(\"close\", () => {\n      if (!matched) {\n        resolve(false);\n      }\n    });\n\n    parser.on(\"error\", reject);\n\n    createReadStream(zipFile)\n      .on(\"error\", reject)\n      .pipe(parser);\n  });\n}\n\nconst found = await extractReadme(\"./fixtures/archive.zip\", \"./tmp/README.md\");\n\nif (!found) {\n  console.error(\"README.md was not present in the archive\");\n}\n```\n\nWhen you skip an entry, call `entry.autodrain()` so the archive stream can continue.\n\n### Inspect archive contents before extracting\n\nUse `Open.file()` when you want to inspect the central directory first and then read a specific member.\n\n```typescript\nimport unzipper from \"unzipper\";\n\ntype PackageJson = {\n  name: string;\n  version: string;\n};\n\nasync function readPackagedManifest(zipFile: string): Promise<PackageJson> {\n  const directory = await unzipper.Open.file(zipFile);\n  const manifest = directory.files.find((entry) => entry.path === \"package.json\");\n\n  if (!manifest) {\n    throw new Error(\"package.json was not found in the archive\");\n  }\n\n  const raw = await manifest.buffer();\n  return JSON.parse(raw.toString(\"utf8\")) as PackageJson;\n}\n\nconst packageJson = await readPackagedManifest(\"./fixtures/archive.zip\");\nconsole.log(packageJson.name, packageJson.version);\n```\n\nFor large members, prefer `entry.stream()` over `buffer()` so you do not load the whole file into memory at once.\n\n## Important Pitfalls\n\n- `@types/unzipper` does not include the `unzipper` runtime; keep `unzipper` in regular dependencies.\n- `unzipper` is a Node.js package built around streams and filesystem access, not a browser package.\n- If you process entries manually with `Parse()`, drain every entry you do not consume.\n- `entry.buffer()` is convenient for small files; use streaming for large archive members.\n- Choose the import form that matches your compiler settings: default import with `esModuleInterop`, or `import unzipper = require(\"unzipper\")` without it.\n\n## Version Notes\n\nThis guide covers the declaration package version `@types/unzipper@0.10.11`.\n\nThe examples focus on the typed `unzipper` APIs that matter most in application code: `Extract()`, `Parse()`, and `Open.file()`.\n"
  },
  {
    "path": "content/typescript/docs/uuid/typescript/DOC.md",
    "content": "---\nname: uuid\ndescription: \"TypeScript setup for `uuid`. `@types/uuid@11.0.0` is a stub package, so install `uuid` itself and use its bundled type definitions.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"11.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,uuid,types,definitelytyped,npm\"\n---\n\n# UUID TypeScript Guide\n\n## Golden Rule\n\n`@types/uuid@11.0.0` is a stub package.\n\nThe npm package page for `@types/uuid` says that `uuid` provides its own type definitions. For modern TypeScript projects, install `uuid`, import from `\"uuid\"`, and remove `@types/uuid` if you added it directly.\n\n## Install\n\nInstall the runtime package and your normal TypeScript toolchain:\n\n```bash\nnpm install uuid\nnpm install -D typescript\n```\n\nIf you are writing a Node.js app and need Node globals or built-in module types elsewhere in the project, add `@types/node` too:\n\n```bash\nnpm install -D @types/node\n```\n\nIf your project already depends on the stub package directly, remove it:\n\n```bash\nnpm uninstall @types/uuid\n```\n\n## Initialization\n\nThere are no package-specific environment variables, auth steps, or client objects.\n\nThe important setup point is importing the runtime package directly so TypeScript reads the declarations bundled with `uuid`.\n\n### Import from `uuid`\n\nUse named imports from the runtime package:\n\n```typescript\nimport { parse, stringify, v4 as uuidv4, validate, version } from \"uuid\";\n```\n\nIn CommonJS, require the runtime package instead:\n\n```typescript\nconst { v4: uuidv4, validate, version, parse, stringify } = require(\"uuid\");\n```\n\nDo not import from `@types/uuid`.\n\n## Common Workflows\n\n### Generate random IDs for application records\n\nUse `v4()` when you need a random UUID string for a database record, queue item, or request identifier.\n\n```typescript\nimport { v4 as uuidv4 } from \"uuid\";\n\ntype User = {\n  id: string;\n  email: string;\n};\n\nexport function createUser(email: string): User {\n  return {\n    id: uuidv4(),\n    email,\n  };\n}\n```\n\nThe return type is a normal string, so keep any stronger application-level ID rules in your own types and validation layer.\n\n### Validate inbound UUID strings\n\nUse `validate()` before trusting input from an API route, message payload, or CLI argument.\n\n```typescript\nimport { validate, version } from \"uuid\";\n\nexport function assertUuidV4(value: string): void {\n  if (!validate(value) || version(value) !== 4) {\n    throw new Error(\"Expected a UUIDv4 string\");\n  }\n}\n```\n\n`validate()` checks that the string is a UUID. If your application requires a specific UUID version, also check `version()`.\n\n### Convert UUID strings to bytes and back\n\nUse `parse()` and `stringify()` when you need to move between the string form and the 16-byte representation.\n\n```typescript\nimport { parse, stringify, v4 as uuidv4 } from \"uuid\";\n\nconst id = uuidv4();\nconst bytes = parse(id);\nconst roundTrip = stringify(bytes);\n\nconsole.log({ id, bytes, roundTrip });\n```\n\nThis is the practical boundary when your app stores UUIDs in a binary field or passes them through a protocol that uses raw bytes.\n\n## Important Pitfalls\n\n- `@types/uuid` does not replace the `uuid` runtime package.\n- For current projects, do not import anything from `@types/uuid`; import from `uuid`.\n- Prefer named imports such as `import { v4 as uuidv4 } from \"uuid\"`; the documented API surface is exposed from the runtime package.\n- `validate()` only tells you whether a string is a valid UUID. If your contract requires a specific UUID version, also check `version()`.\n- If an older lockfile still includes `@types/uuid` transitively, your application code should still depend on `uuid` for both runtime behavior and declarations.\n\n## Version-Sensitive Notes\n\n- This guide targets the `@types/uuid` package entry at version `11.0.0`.\n- For this version, the npm package entry is a stub package that points TypeScript users to `uuid`.\n- For new work, the relevant package is `uuid`, because that package provides both the runtime helpers and the bundled TypeScript declarations.\n\n## Official Sources\n\n- npm package page for `@types/uuid`: https://www.npmjs.com/package/@types/uuid\n- DefinitelyTyped source for `@types/uuid`: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/uuid\n- npm package page for `uuid`: https://www.npmjs.com/package/uuid\n- `uuid` README and API reference: https://github.com/uuidjs/uuid/blob/main/README.md\n"
  },
  {
    "path": "content/typescript/docs/webpack/typescript/DOC.md",
    "content": "---\nname: webpack\ndescription: \"TypeScript guide for webpack configuration, CLI setup, and Node API usage, with practical guidance for webpack's built-in declarations instead of importing from `@types/webpack`.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"5.28.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,webpack,webpack-cli,bundler,configuration,types,definitelytyped\"\n---\n\n# webpack TypeScript Guide\n\n## Golden Rule\n\nFor current webpack 5 projects, import values and types from `webpack`, not from `@types/webpack`.\n\nThe practical TypeScript boundary is the runtime `webpack` package itself: it publishes `types.d.ts`, exports types such as `Configuration`, `RuleSetRule`, `Compiler`, and `Stats`, and exposes the callable `webpack(...)` Node API from the same module.\n\nIn practice:\n\n- install `webpack` and `webpack-cli`\n- import from `webpack`\n- use a TypeScript loader such as `ts-node` if your config file itself is `webpack.config.ts`\n\n## Install\n\nFor a typical TypeScript + webpack project:\n\n```bash\nnpm install -D webpack webpack-cli typescript ts-loader\n```\n\nIf your webpack config file is also written in TypeScript, add `ts-node` so `webpack-cli` can load `webpack.config.ts`:\n\n```bash\nnpm install -D ts-node\n```\n\nNo authentication, API keys, service accounts, or package-specific environment variables are required.\n\nThe only environment variable that matters in the TypeScript-config path is `NODE_OPTIONS` when you load an ESM `.mts` config file:\n\n```bash\nNODE_OPTIONS=\"--loader ts-node/esm\" npx webpack --config ./webpack.config.mts\n```\n\n## Recommended Project Setup\n\n### Use a normal Node-oriented `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nYou do not need to add `webpack` to `compilerOptions.types`. That setting is for ambient packages; webpack's declarations come from the `webpack` module itself.\n\n### Type a `webpack.config.ts`\n\n```typescript\nimport path from \"node:path\";\nimport type { Configuration, RuleSetRule } from \"webpack\";\n\nconst rules: RuleSetRule[] = [\n  {\n    test: /\\.ts$/,\n    exclude: /node_modules/,\n    use: \"ts-loader\",\n  },\n];\n\nconst config: Configuration = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(process.cwd(), \"dist\"),\n    clean: true,\n  },\n  resolve: {\n    extensions: [\".ts\", \".js\"],\n  },\n  module: {\n    rules,\n  },\n};\n\nexport default config;\n```\n\nThis keeps your config aligned with the real webpack option surface instead of duplicating shapes by hand.\n\n## CLI Workflow\n\nRun a typed TypeScript config through `webpack-cli`:\n\n```bash\nnpx webpack --config ./webpack.config.ts\n```\n\n`webpack-cli` loads config files through its `interpret` integration. For `.ts` and `.cts` configs, installing `ts-node` is the straightforward setup. For ESM `.mts`, use the explicit Node loader form:\n\n```bash\nNODE_OPTIONS=\"--loader ts-node/esm\" npx webpack --config ./webpack.config.mts\n```\n\nIf you do not want runtime TypeScript config loading, keep the webpack config in JavaScript and continue using webpack's types only in application or tooling code.\n\n## Common Workflows\n\n### Reuse webpack option types in helpers\n\nUse the exported config types to keep shared helpers aligned with webpack's real option shapes.\n\n```typescript\nimport type { Configuration, RuleSetRule } from \"webpack\";\n\nexport function makeTypescriptRules(): RuleSetRule[] {\n  return [\n    {\n      test: /\\.ts$/,\n      exclude: /node_modules/,\n      use: \"ts-loader\",\n    },\n  ];\n}\n\nexport function makeConfig(mode: Configuration[\"mode\"]): Configuration {\n  return {\n    mode,\n    entry: \"./src/index.ts\",\n    resolve: {\n      extensions: [\".ts\", \".js\"],\n    },\n    module: {\n      rules: makeTypescriptRules(),\n    },\n  };\n}\n```\n\nUsing `Configuration[\"mode\"]` and `RuleSetRule[]` avoids hand-written string unions and ad hoc rule shapes.\n\n### Run webpack programmatically from Node\n\nThe `webpack` module exports the callable compiler factory and the related result types.\n\n```typescript\nimport webpack, { type Configuration } from \"webpack\";\n\nconst config: Configuration = {\n  mode: \"production\",\n  entry: \"./src/index.ts\",\n  output: {\n    filename: \"bundle.js\",\n  },\n};\n\nconst compiler = webpack(config);\n\ncompiler.run((error, stats) => {\n  if (error) {\n    throw error;\n  }\n\n  if (!stats) {\n    return;\n  }\n\n  console.log(\n    stats.toString({\n      colors: true,\n      modules: false,\n    }),\n  );\n\n  compiler.close((closeError) => {\n    if (closeError) {\n      throw closeError;\n    }\n  });\n});\n```\n\nFor a single config object, `webpack(config)` returns a `Compiler`. If you pass an array of configs, the return type changes to `MultiCompiler`.\n\n### Type plugin usage from the same module\n\nPlugin classes and plugin instance types come from `webpack` too.\n\n```typescript\nimport webpack, {\n  type Configuration,\n  type WebpackPluginInstance,\n} from \"webpack\";\n\nconst plugins: WebpackPluginInstance[] = [\n  new webpack.DefinePlugin({\n    __BUILD_TARGET__: JSON.stringify(\"web\"),\n  }),\n];\n\nconst config: Configuration = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  plugins,\n};\n\nexport default config;\n```\n\nThis is the cleanest way to keep plugin arrays and plugin constructor calls typed from the same source.\n\n## Important Pitfalls\n\n- Do not import from `@types/webpack` in source files. Import from `webpack`.\n- `webpack` provides the compiler and types, but normal CLI usage depends on `webpack-cli`.\n- A `webpack.config.ts` file is not executed by Node by itself; `webpack-cli` relies on `interpret`, so you still need a supported loader such as `ts-node` for `.ts` and `.cts` configs.\n- ESM `.mts` configs are a separate path: use `NODE_OPTIONS=\"--loader ts-node/esm\"` when invoking `webpack-cli`.\n- If your project sets `compilerOptions.types`, that does not replace normal module imports. Keep importing `Configuration`, `RuleSetRule`, and other types from `webpack`.\n- `webpack(config)` has different return types for single and multi-config inputs. Helper code that accepts both should type that boundary deliberately.\n\n## Version Notes\n\n- This guide targets `@types/webpack==5.28.5`.\n- Current webpack 5 publishes its own declarations through the `webpack` package's `types.d.ts` entry.\n- `webpack-cli` currently supports TypeScript config loading through its `interpret` integration for `.ts` and `.cts` configs, with explicit `ts-node/esm` loader usage for `.mts` configs.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/webpack\n- https://www.npmjs.com/package/webpack\n- https://www.npmjs.com/package/webpack-cli\n- https://github.com/webpack/webpack\n- https://github.com/webpack/webpack-cli\n- https://webpack.js.org/api/node/\n- https://webpack.js.org/configuration/configuration-languages/\n"
  },
  {
    "path": "content/typescript/docs/webpack-env/typescript/DOC.md",
    "content": "---\nname: webpack-env\ndescription: \"TypeScript definitions for webpack-specific runtime APIs such as HMR, require.context, and webpack module variables\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"1.18.8\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,webpack,hmr,hot-module-replacement,types\"\n---\n\n# webpack-env TypeScript Guide\n\n`@types/webpack-env` adds ambient TypeScript declarations for webpack-only runtime features such as `module.hot`, `import.meta.webpackHot`, `require.context()`, and globals like `__webpack_public_path__`.\n\nThis package only provides `.d.ts` files. It does not install webpack, it does not turn on hot reloading, and it does not provide a runtime by itself.\n\n## Install\n\nIf your project already uses webpack, install the declaration package as a development dependency:\n\n```bash\nnpm install --save-dev @types/webpack-env\n```\n\nIf you are setting up a minimal TypeScript + webpack development stack for the examples in this guide, install the runtime tooling alongside it:\n\n```bash\nnpm install --save-dev webpack webpack-cli webpack-dev-server typescript ts-loader @types/webpack-env\n```\n\nNo environment variables, authentication, or client initialization are required for this package.\n\n## TypeScript Setup\n\nDo not import `@types/webpack-env` in application code. TypeScript loads the declarations automatically after installation.\n\nIf your project restricts loaded ambient packages with `compilerOptions.types`, add `webpack-env` explicitly. Most webpack projects that also use Node-style globals keep `node` there too:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"types\": [\"webpack-env\", \"node\"]\n  }\n}\n```\n\nIf you use `import.meta.webpackHot`, keep a module target that preserves `import.meta` for webpack to handle, such as `ES2020` or `ESNext`.\n\n## Enable HMR In Webpack\n\nThe typings make HMR APIs available to TypeScript, but webpack still has to enable hot updates at runtime.\n\n```typescript\nimport webpack from \"webpack\";\nimport type { Configuration } from \"webpack\";\n\nconst config: Configuration = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  devtool: \"inline-source-map\",\n  resolve: {\n    extensions: [\".ts\", \".js\"],\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.ts$/,\n        exclude: /node_modules/,\n        use: \"ts-loader\",\n      },\n    ],\n  },\n  devServer: {\n    hot: true,\n  },\n  plugins: [new webpack.HotModuleReplacementPlugin()],\n};\n\nexport default config;\n```\n\nWithout webpack HMR enabled, the types still exist in the compiler, but `module.hot` or `import.meta.webpackHot` will be absent at runtime.\n\n## Accept Updates With `module.hot`\n\n`module.hot` is the common webpack HMR entry point in codebases that compile to webpack-managed modules.\n\n```typescript\nimport { renderApp } from \"./render-app\";\n\nrenderApp();\n\nif (module.hot) {\n  module.hot.accept(\"./render-app\", async () => {\n    const next = await import(\"./render-app\");\n    next.renderApp();\n  });\n\n  module.hot.dispose(() => {\n    document.body.replaceChildren();\n  });\n}\n```\n\nGuard the HMR block with `if (module.hot)` so production builds and non-HMR runs do not assume the runtime hook exists.\n\n## Accept Updates With `import.meta.webpackHot`\n\nIn ESM-oriented webpack code, use `import.meta.webpackHot` instead of `module.hot`.\n\n```typescript\nimport { renderApp } from \"./render-app\";\n\nrenderApp();\n\nimport.meta.webpackHot?.accept(\"./render-app\", async () => {\n  const next = await import(\"./render-app\");\n  next.renderApp();\n});\n```\n\nThis pattern is useful when your app already uses `import.meta` and you want to avoid relying on CommonJS-style module state.\n\n## Load Groups Of Modules With `require.context()`\n\n`require.context()` lets webpack build a module context from a directory, a recursion flag, and a file-matching expression.\n\n```typescript\nconst context = require.context(\"./features\", false, /\\.ts$/);\n\nconst features = context.keys().map((key) => {\n  const featureModule = context<{ default: string }>(key);\n  return featureModule.default;\n});\n\nconsole.log(features);\n```\n\nThis is useful for plugin registration, file-based routing, and test harnesses that need webpack to include a known set of files at build time.\n\n## Set `__webpack_public_path__` Before App Startup\n\nUse `__webpack_public_path__` when your app needs webpack to resolve assets from a runtime-defined base URL.\n\nCreate a small bootstrap module that runs first:\n\n```typescript\nconst runtimeConfig = globalThis as typeof globalThis & {\n  __ASSET_BASE_URL__?: string;\n};\n\n__webpack_public_path__ = runtimeConfig.__ASSET_BASE_URL__ ?? \"/assets/\";\n```\n\nThen import that module before the rest of your app:\n\n```typescript\nimport \"./set-public-path\";\nimport \"./app\";\n```\n\nThis ordering matters because webpack resolves later asset URLs relative to the public path.\n\n## Important Pitfalls\n\n- `@types/webpack-env` only adds TypeScript declarations. Install and configure `webpack` separately.\n- Do not import from `@types/webpack-env`; the package is meant to be loaded ambiently by the compiler.\n- If `compilerOptions.types` is present and omits `webpack-env`, names like `module.hot` and `require.context()` will appear to be missing.\n- `module.hot` and `import.meta.webpackHot` are runtime-optional. Guard them so non-HMR builds still run.\n- `require.context()` is webpack-specific. Code that depends on it is not portable to non-webpack bundlers unless they provide a compatible feature.\n- `__webpack_public_path__` must be set before modules that rely on webpack-generated asset URLs run.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/webpack-env==1.18.8`.\n- The declarations cover webpack runtime APIs and globals; they do not guarantee a matching webpack configuration.\n- `require.ensure()` remains part of webpack's older module-loading surface, but modern webpack guidance prefers standard `import()` for code splitting in new code.\n- `import.meta.webpackHot` is the ESM-facing HMR hook; use `module.hot` in older CommonJS-oriented patterns.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/webpack-env\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/webpack-env\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/webpack-env/index.d.ts\n- https://webpack.js.org/api/hot-module-replacement/\n- https://webpack.js.org/guides/dependency-management/#requirecontext\n- https://webpack.js.org/guides/public-path/\n"
  },
  {
    "path": "content/typescript/docs/webpack-sources/typescript/DOC.md",
    "content": "---\nname: webpack-sources\ndescription: \"TypeScript declarations for webpack-sources Source objects, source maps, code replacement, and build-time asset composition.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"3.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,webpack,webpack-sources,source-map,build-tools,types,definitelytyped\"\n---\n\n# webpack-sources TypeScript Guide\n\n## Golden Rule\n\nInstall `@types/webpack-sources` for compile-time declarations only, and import the runtime APIs from `webpack-sources`.\n\nThe runtime package exposes the classes you actually use in build tooling: `Source`, `RawSource`, `OriginalSource`, `SourceMapSource`, `CachedSource`, `ConcatSource`, `ReplaceSource`, `PrefixSource`, and `CompatSource`. The declaration package supplies the TypeScript shapes for those exports.\n\n## Install\n\n`webpack-sources` is a Node-oriented build-time library. Its type declarations reference `Buffer`, so most TypeScript projects should also keep Node types available.\n\n```bash\nnpm install webpack-sources\nnpm install -D typescript @types/webpack-sources @types/node\n```\n\nIf TypeScript and Node types are already installed, add only the missing declaration package:\n\n```bash\nnpm install -D @types/webpack-sources\n```\n\nNo environment variables, credentials, or client initialization are required.\n\n## Initialization\n\nThe main setup is your TypeScript compiler configuration and your import style.\n\n### Recommended `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf your project restricts ambient packages with `compilerOptions.types`, include `node` so the `Buffer` references used by `webpack-sources` stay available:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  }\n}\n```\n\n### Import from `webpack-sources`\n\nThe declarations use `export =`, so the most portable TypeScript import form is:\n\n```typescript\nimport webpackSources = require(\"webpack-sources\");\n```\n\nUse the runtime package name in imports, never `@types/webpack-sources`.\n\n## Common Workflows\n\n### Create generated assets with `RawSource`, `OriginalSource`, and `ConcatSource`\n\nUse `RawSource` for generated content that has no source map, `OriginalSource` when the content maps back to a real file name, and `ConcatSource` when you need to assemble a final asset from multiple pieces.\n\n```typescript\nimport webpackSources = require(\"webpack-sources\");\n\nconst asset = new webpackSources.ConcatSource(\n  new webpackSources.RawSource(\"/* generated during build */\\n\"),\n  new webpackSources.OriginalSource(\n    \"export const answer = 42;\\n\",\n    \"src/answer.ts\",\n  ),\n);\n\nconst { source, map } = asset.sourceAndMap({ columns: true });\nconst text = typeof source === \"string\" ? source : source.toString(\"utf8\");\n\nconsole.log(text);\nconsole.log(map);\n```\n\nIf you need both the emitted content and its source map, prefer `sourceAndMap()` over separate `source()` and `map()` calls.\n\n### Wrap generated code with an existing source map\n\nUse `SourceMapSource` when you already have generated output plus a source map and want to keep that mapping information typed.\n\n```typescript\nimport webpackSources = require(\"webpack-sources\");\n\nconst generatedCode = \"const answer = 42;\\n\";\nconst originalCode = \"export const answer = 42;\\n\";\n\nconst sourceMap: webpackSources.RawSourceMap = {\n  version: 3,\n  file: \"dist/answer.js\",\n  sources: [\"src/answer.ts\"],\n  names: [],\n  sourcesContent: [originalCode],\n  mappings: \"AAAA\",\n};\n\nconst asset = new webpackSources.SourceMapSource(\n  generatedCode,\n  \"src/answer.ts\",\n  sourceMap,\n  originalCode,\n);\n\nconst result = asset.sourceAndMap({ columns: true });\n\nconsole.log(result.map?.sources);\n```\n\nThe `name` argument is the original file name that should appear in the mapping data.\n\n### Patch source text with `ReplaceSource`\n\n`ReplaceSource` is the main editing API when a plugin or loader needs to replace or insert text while preserving source-map-aware behavior.\n\n```typescript\nimport webpackSources = require(\"webpack-sources\");\n\nconst code = \"export const answer = 41;\\n\";\nconst original = new webpackSources.OriginalSource(code, \"src/answer.ts\");\nconst patched = new webpackSources.ReplaceSource(original, \"src/answer.ts\");\n\nconst start = code.indexOf(\"41\");\nconst end = start + \"41\".length - 1;\n\npatched.replace(start, end, \"42\");\npatched.insert(0, \"// rewritten by a build step\\n\");\n\nconst output = patched.source();\nconsole.log(typeof output === \"string\" ? output : output.toString(\"utf8\"));\n```\n\nReplacement and insertion positions are based on the original source, not on text that earlier edits already changed.\n\n### Reuse expensive results with `CachedSource`\n\nEvery `Source` method can require computation. Wrap expensive sources in `CachedSource` when you will ask for `source()`, `map()`, `size()`, or `sourceAndMap()` more than once.\n\n```typescript\nimport webpackSources = require(\"webpack-sources\");\n\nconst original = new webpackSources.OriginalSource(\n  \"export const answer = 42;\\n\",\n  \"src/answer.ts\",\n);\n\nconst cached = new webpackSources.CachedSource(original);\n\nconst firstRead = cached.sourceAndMap({ columns: false });\nconst secondRead = cached.sourceAndMap({ columns: false });\nconst snapshot = cached.getCachedData();\n\nconsole.log(firstRead.map);\nconsole.log(secondRead.map);\nconsole.log(snapshot.size);\n```\n\n`CachedSource` caches `map`, `source`, `buffer`, `size`, and `sourceAndMap` results in memory. `updateHash()` is not cached.\n\n## Important Pitfalls\n\n- Import from `webpack-sources`, not from `@types/webpack-sources`.\n- `Source.source()` returns `string | Buffer`; handle both when your code may process text and binary assets.\n- `ReplaceSource.replace(start, end, value)` uses zero-based indexes and an inclusive `end` position.\n- `Source` methods can be expensive; prefer `sourceAndMap()` when you need both outputs and use `CachedSource` for repeated reads.\n- If `compilerOptions.types` is set, include `node` so the package's `Buffer` references resolve correctly.\n- Official `webpack-sources@2.3.1` publishes only `lib/`, while official `webpack-sources@3.3.3` publishes both a `types` field and `types.d.ts`. If your installed runtime already ships declarations, do not keep a second copy of `@types/webpack-sources` unless you intentionally need the external package.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/webpack-sources\n- https://www.npmjs.com/package/webpack-sources\n- https://github.com/webpack/webpack-sources#readme\n- https://github.com/webpack/webpack-sources/blob/main/types.d.ts\n"
  },
  {
    "path": "content/typescript/docs/ws/typescript/DOC.md",
    "content": "---\nname: ws\ndescription: \"TypeScript declarations for the ws Node.js WebSocket runtime, including WebSocket, WebSocketServer, message payload types, and stream interop.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.18.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,ws,websocket,node,types,definitelytyped\"\n---\n\n# ws TypeScript Guide\n\n## Golden Rule\n\nInstall `ws` for the runtime and `@types/ws` for compile-time declarations.\n\nImport from `ws`, not from `@types/ws`:\n\n```typescript\nimport WebSocket, { WebSocketServer, createWebSocketStream } from \"ws\";\n```\n\n`@types/ws` supplies the TypeScript declarations for the Node.js `ws` client and server APIs. It does not install the `ws` runtime, and it is not the browser `WebSocket` API.\n\n## Install\n\nAdd the runtime package, TypeScript, and the declaration package:\n\n```bash\nnpm install ws\nnpm install -D typescript @types/ws @types/node\n```\n\nIf TypeScript is already configured in the project, add only the missing declarations:\n\n```bash\nnpm install -D @types/ws @types/node\n```\n\n`@types/ws@8.18.1` depends on `@types/node` and declares `typeScriptVersion: \"5.1\"`, so use TypeScript 5.1 or newer.\n\n## Initialization\n\nThere is no package-specific auth flow, API key, or client initialization for `@types/ws` itself.\n\nThe practical setup is:\n\n- install the `ws` runtime package\n- let TypeScript load `@types/ws`\n- initialize `WebSocket` or `WebSocketServer` from `ws`\n\n### Recommended `tsconfig.json`\n\nFor Node.js applications, use Node-style module settings so the ESM import examples line up with the package exports:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"strict\": true,\n    \"types\": [\"node\"],\n    \"skipLibCheck\": false\n  }\n}\n```\n\nIf you emit CommonJS or use older import rules, use the CommonJS-style TypeScript import instead:\n\n```typescript\nimport WebSocket = require(\"ws\");\n\nconst wss = new WebSocket.Server({ port: 8080 });\n```\n\n### Optional runtime environment variables\n\n`@types/ws` has no package-specific environment variables.\n\nThe `ws` runtime documentation does define two optional environment variables for disabling native addons when those addons are installed in the environment:\n\n```bash\nWS_NO_BUFFER_UTIL=1\nWS_NO_UTF_8_VALIDATE=1\n```\n\n`WS_NO_UTF_8_VALIDATE` is part of the legacy addon path that `ws` documents for older Node.js releases.\n\n## Common Workflows\n\n### Create a typed WebSocket client\n\nUse the runtime client from `ws`, and type message payloads with `WebSocket.RawData`.\n\n```typescript\nimport WebSocket from \"ws\";\n\nconst socketUrl = process.env.WS_URL ?? \"ws://127.0.0.1:8080\";\n\nfunction rawDataToBuffer(data: WebSocket.RawData): Buffer {\n  if (Array.isArray(data)) {\n    return Buffer.concat(data);\n  }\n\n  return data instanceof ArrayBuffer ? Buffer.from(data) : data;\n}\n\nconst ws = new WebSocket(socketUrl, {\n  headers: process.env.WS_TOKEN\n    ? { authorization: `Bearer ${process.env.WS_TOKEN}` }\n    : undefined,\n  perMessageDeflate: false,\n});\n\nws.on(\"error\", (error) => {\n  console.error(error);\n});\n\nws.on(\"open\", () => {\n  ws.send(JSON.stringify({ type: \"ping\" }));\n});\n\nws.on(\"message\", (data, isBinary) => {\n  const body = rawDataToBuffer(data);\n  console.log(isBinary ? body : body.toString(\"utf8\"));\n});\n```\n\nApplication auth is server-specific. When a server expects headers during the HTTP upgrade request, pass them through `ClientOptions.headers`.\n\n### Create a typed WebSocket server\n\n`WebSocketServer` is the named server export from `ws`. Its options include values such as `port`, `server`, `path`, `noServer`, `perMessageDeflate`, and `maxPayload`.\n\n```typescript\nimport { createServer } from \"node:http\";\nimport { WebSocketServer } from \"ws\";\n\nconst server = createServer();\n\nconst wss = new WebSocketServer({\n  server,\n  path: \"/socket\",\n  perMessageDeflate: false,\n  maxPayload: 64 * 1024,\n});\n\nwss.on(\"connection\", (ws, request) => {\n  const ip = request.socket.remoteAddress;\n\n  ws.on(\"error\", console.error);\n\n  ws.on(\"message\", (data) => {\n    const text = Array.isArray(data)\n      ? Buffer.concat(data).toString(\"utf8\")\n      : data instanceof ArrayBuffer\n        ? Buffer.from(data).toString(\"utf8\")\n        : data.toString(\"utf8\");\n\n    ws.send(JSON.stringify({ ip, echo: text }));\n  });\n});\n\nserver.listen(8080);\n```\n\n### Add custom socket state for heartbeat logic\n\nThe `ws` README heartbeat example stores `isAlive` directly on each socket. That property is not part of the published `WebSocket` type, so model it explicitly in your app.\n\n```typescript\nimport { WebSocketServer, WebSocket } from \"ws\";\n\ntype HeartbeatSocket = WebSocket & {\n  isAlive: boolean;\n};\n\nconst wss = new WebSocketServer({ port: 8080 });\n\nfunction heartbeat(this: HeartbeatSocket) {\n  this.isAlive = true;\n}\n\nwss.on(\"connection\", (socket) => {\n  const ws = socket as HeartbeatSocket;\n  ws.isAlive = true;\n\n  ws.on(\"pong\", heartbeat);\n});\n\nconst interval = setInterval(() => {\n  wss.clients.forEach((socket) => {\n    const ws = socket as HeartbeatSocket;\n\n    if (!ws.isAlive) {\n      ws.terminate();\n      return;\n    }\n\n    ws.isAlive = false;\n    ws.ping();\n  });\n}, 30_000);\n\nwss.on(\"close\", () => {\n  clearInterval(interval);\n});\n```\n\nThis pattern keeps the runtime example from `ws` and makes the extra property visible to TypeScript.\n\n### Use the Node.js streams API\n\n`@types/ws` also covers `createWebSocketStream()`, which returns a Node `Duplex`.\n\n```typescript\nimport WebSocket, { createWebSocketStream } from \"ws\";\n\nconst ws = new WebSocket(\"ws://127.0.0.1:8080\");\nconst duplex = createWebSocketStream(ws, { encoding: \"utf8\" });\n\nduplex.on(\"error\", console.error);\nduplex.write(\"hello from a stream\\n\");\nduplex.pipe(process.stdout);\n```\n\n## Important Pitfalls\n\n- `@types/ws` only provides declarations. Install `ws` separately for runtime behavior.\n- Import from `ws`, not from `@types/ws`.\n- `ws` is a Node.js library. The upstream README explicitly says it does not work in the browser; browser clients should use the native `WebSocket` object or a wrapper designed for both environments.\n- The event-emitter `\"message\"` callback uses `WebSocket.RawData`, so decode `Buffer`, `ArrayBuffer`, and `Buffer[]` values explicitly instead of assuming `string`.\n- If you copy the upstream heartbeat example, add a local extended type or cast for `isAlive`; that property is not declared on `WebSocket`.\n- If ESM default and named imports do not resolve in your compiler setup, switch to `module: \"NodeNext\"` and `moduleResolution: \"NodeNext\"`, or use `import WebSocket = require(\"ws\")` in CommonJS-oriented code.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/ws\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ws\n- https://www.npmjs.com/package/ws\n- https://github.com/websockets/ws\n"
  },
  {
    "path": "content/typescript/docs/xml2js/typescript/DOC.md",
    "content": "---\nname: xml2js\ndescription: \"TypeScript declarations for the xml2js XML parser and builder, including CommonJS imports, parser options, built-in processors, and the typed boundary around parsed results.\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"0.4.14\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,xml2js,xml,parsing,builder,npm,types,definitelytyped\"\n---\n\n# xml2js TypeScript Guide\n\n`@types/xml2js` provides the TypeScript declarations for the `xml2js` runtime package.\n\nUse it when your application parses XML into JavaScript objects or builds XML from plain objects in TypeScript. The type package only supplies declarations. It does not install the `xml2js` runtime.\n\n## Install\n\nInstall the runtime and the declarations together:\n\n```bash\nnpm install xml2js\nnpm install --save-dev typescript @types/xml2js\n```\n\nNo environment variables, credentials, or client initialization are required.\n\n## Import `xml2js` In TypeScript\n\nThe runtime is CommonJS-based. The declaration-matching import style is:\n\n```ts\nimport xml2js = require(\"xml2js\");\n```\n\nImport from `\"xml2js\"`, not from `\"@types/xml2js\"`.\n\n## Parse XML At A Typed Boundary\n\nThe parser does not infer your XML schema. Parsed results need an application-defined type at the boundary where XML becomes domain data.\n\n```ts\nimport xml2js = require(\"xml2js\");\n\ntype Catalog = {\n  catalog: {\n    book: {\n      $: { id: string };\n      title: string;\n      price: number;\n      available: boolean;\n    };\n  };\n};\n\nfunction parseXml<T>(xml: string, options?: xml2js.ParserOptions): Promise<T> {\n  return new Promise((resolve, reject) => {\n    xml2js.parseString(xml, options ?? {}, (error, result) => {\n      if (error) {\n        reject(error);\n        return;\n      }\n\n      resolve(result as T);\n    });\n  });\n}\n\nconst xml = `\n  <catalog>\n    <book id=\"bk101\">\n      <title>XML Developer's Guide</title>\n      <price>44.95</price>\n      <available>true</available>\n    </book>\n  </catalog>\n`;\n\nasync function main() {\n  const result = await parseXml<Catalog>(xml, {\n    explicitArray: false,\n    trim: true,\n    valueProcessors: [\n      xml2js.processors.parseNumbers,\n      xml2js.processors.parseBooleans,\n    ],\n  });\n\n  console.log(result.catalog.book.$.id);\n  console.log(result.catalog.book.price.toFixed(2));\n}\n\nvoid main();\n```\n\nPractical notes:\n\n- `explicitArray` is `true` by default, so repeated or singular elements normally come back as arrays unless you set `explicitArray: false`.\n- Attributes are stored under `$` by default.\n- Character data is stored under `_` by default when it needs its own property.\n- Built-in processors such as `parseNumbers` and `parseBooleans` help convert XML text before you use it in app code.\n\n## Normalize Names And Values During Parse\n\n`xml2js.processors` exposes small helpers you can compose into parser options.\n\n```ts\nimport xml2js = require(\"xml2js\");\n\nconst parserOptions: xml2js.ParserOptions = {\n  explicitArray: false,\n  tagNameProcessors: [xml2js.processors.stripPrefix],\n  valueProcessors: [xml2js.processors.parseNumbers],\n  attrValueProcessors: [xml2js.processors.parseBooleans],\n};\n\nxml2js.parseString(\n  `\n    <ns:feed enabled=\"true\">\n      <ns:item>\n        <ns:id>42</ns:id>\n      </ns:item>\n    </ns:feed>\n  `,\n  parserOptions,\n  (error, result) => {\n    if (error) {\n      throw error;\n    }\n\n    console.log(result.feed.$.enabled);\n    console.log(result.feed.item.id);\n  }\n);\n```\n\nThe built-in processor helpers are:\n\n- `xml2js.processors.normalize`\n- `xml2js.processors.firstCharLowerCase`\n- `xml2js.processors.stripPrefix`\n- `xml2js.processors.parseNumbers`\n- `xml2js.processors.parseBooleans`\n\n## Reuse Shared Parser Options With `Parser`\n\nIf your application parses many documents with the same settings, create a `Parser` instance with typed options.\n\n```ts\nimport xml2js = require(\"xml2js\");\n\nconst parser = new xml2js.Parser({\n  explicitArray: false,\n  trim: true,\n  ignoreAttrs: false,\n});\n\nparser.parseString(\"<response><status>ok</status></response>\", (error, result) => {\n  if (error) {\n    throw error;\n  }\n\n  console.log(result.response.status);\n});\n```\n\nUse the top-level `parseString()` helper when you only need a one-off parse. Use `new Parser(...)` when you want to keep one shared option set in a reusable object.\n\n## Build XML From Plain Objects\n\n`xml2js` also includes a `Builder` class for turning plain objects into XML strings.\n\n```ts\nimport xml2js = require(\"xml2js\");\n\nconst builder = new xml2js.Builder({\n  headless: true,\n  rootName: \"catalog\",\n  renderOpts: {\n    pretty: true,\n    indent: \"  \",\n    newline: \"\\n\",\n  },\n});\n\nconst xml = builder.buildObject({\n  book: {\n    $: { id: \"bk101\", available: \"true\" },\n    title: \"XML Developer's Guide\",\n    price: \"44.95\",\n  },\n});\n\nconsole.log(xml);\n```\n\nThe builder uses the same default structural keys as the parser:\n\n- `$` for attributes\n- `_` for character content\n\nIf you customize `attrkey` or `charkey` in parser or builder options, keep the object shape consistent on both sides.\n\n## Common Pitfalls\n\n- Install `xml2js` as well as `@types/xml2js`; the type package does not include runtime code.\n- Import from `\"xml2js\"`, not from `\"@types/xml2js\"`.\n- Treat parsed output as an untyped boundary. The declarations do not infer your XML schema for you.\n- `explicitArray` defaults to `true`, which changes property shapes unless you set it explicitly.\n- Default parsed attributes live under `$`, and text content can live under `_`.\n- Builder input uses the same `$` and `_` conventions.\n\n## Version-Sensitive Notes\n\n- This guide targets `@types/xml2js==0.4.14`.\n- These declarations are for the `xml2js` runtime package and are not a standalone parser.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/xml2js\n- https://www.npmjs.com/package/xml2js\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/xml2js\n- https://github.com/Leonidas-from-XIV/node-xml2js\n"
  },
  {
    "path": "content/typescript/docs/yargs/typescript/DOC.md",
    "content": "---\nname: yargs\ndescription: \"TypeScript definitions for yargs command parsers, option builders, and command modules\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"17.0.35\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,yargs,cli,arguments,types\"\n---\n\n# yargs TypeScript Guide\n\n`@types/yargs` adds TypeScript declarations for the `yargs` runtime package. Install it when your application or CLI imports `yargs` or `yargs/helpers` and you want typed option builders, typed command handlers, and typed parsed arguments.\n\nThis package only provides `.d.ts` files. It does not include the `yargs` runtime.\n\n## Install\n\nInstall the runtime package and the type package together:\n\n```bash\nnpm install yargs\nnpm install --save-dev typescript @types/yargs @types/node\n```\n\n`@types/node` is usually needed in CLI projects because the common entrypoint pattern uses `process.argv`.\n\nNo package-specific environment variables, authentication, or service initialization are required.\n\n## Import The Runtime Package, Not The Type Package\n\nImport from `yargs` and `yargs/helpers`:\n\n```ts\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n```\n\nDo not import from `@types/yargs` directly. The type package is picked up automatically by TypeScript after installation.\n\n`hideBin(process.argv)` is the documented helper for removing the Node executable and script path before parsing arguments.\n\n## Parse Typed Options\n\nUse `option()` calls to describe the CLI interface, then parse once and use the inferred result.\n\n```ts\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nconst argv = yargs(hideBin(process.argv))\n  .scriptName(\"imgtool\")\n  .usage(\"$0 --input <file> --format <json|yaml>\")\n  .option(\"input\", {\n    type: \"string\",\n    demandOption: true,\n    describe: \"Path to the source file\",\n  })\n  .option(\"format\", {\n    choices: [\"json\", \"yaml\"] as const,\n    default: \"json\",\n    describe: \"Output format\",\n  })\n  .option(\"watch\", {\n    type: \"boolean\",\n    default: false,\n    describe: \"Rebuild when files change\",\n  })\n  .strict()\n  .help()\n  .parseSync();\n\nconsole.log(argv.input);\nconsole.log(argv.format);\nconsole.log(argv.watch);\n```\n\nThis is the main day-to-day `@types/yargs` workflow: the declarations follow the builder chain so parsed values carry useful TypeScript types into the rest of your CLI code.\n\n## Type Reusable Command Modules\n\nFor larger CLIs, model each subcommand as a `CommandModule`.\n\n```ts\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport type { CommandModule } from \"yargs\";\n\ntype GlobalFlags = {\n  cwd?: string;\n};\n\ntype BuildFlags = GlobalFlags & {\n  outDir: string;\n  watch: boolean;\n};\n\nconst buildCommand: CommandModule<GlobalFlags, BuildFlags> = {\n  command: \"build\",\n  describe: \"Compile the project\",\n  builder: (cli) =>\n    cli\n      .option(\"cwd\", {\n        type: \"string\",\n        describe: \"Working directory\",\n      })\n      .option(\"outDir\", {\n        type: \"string\",\n        demandOption: true,\n        describe: \"Build output directory\",\n      })\n      .option(\"watch\", {\n        type: \"boolean\",\n        default: false,\n        describe: \"Rebuild on changes\",\n      }),\n  handler: (argv) => {\n    console.log(argv.cwd);\n    console.log(argv.outDir);\n    console.log(argv.watch);\n  },\n};\n\nyargs(hideBin(process.argv))\n  .command(buildCommand)\n  .demandCommand(1)\n  .strict()\n  .help()\n  .parseSync();\n```\n\nThis matters when you split commands across files: `CommandModule` keeps the builder and handler in sync, so required options stay required inside the handler.\n\n## Type Shared Builder Helpers\n\nIf you wrap common flags in helper functions, accept and return `Argv<T>` so the fluent builder keeps its generic state.\n\n```ts\nimport type { Argv } from \"yargs\";\n\ntype CommonFlags = {\n  config?: string;\n};\n\nfunction withCommonFlags<T>(cli: Argv<T>) {\n  return cli.option(\"config\", {\n    type: \"string\",\n    describe: \"Path to a config file\",\n  });\n}\n```\n\nUse this pattern for local helper modules that add the same options to multiple commands.\n\n## Common Pitfalls\n\n- Install `yargs` as well as `@types/yargs`; the type package does not provide executable code.\n- Import from `yargs` and `yargs/helpers`, never from `@types/yargs`.\n- Pass `hideBin(process.argv)` to `yargs()` in Node CLI entrypoints instead of parsing raw `process.argv` directly.\n- If your project restricts `compilerOptions.types`, keep `node` in that list when your CLI code uses `process.argv` and other Node globals.\n- Keep the runtime `yargs` package on the same major line as the type package; `@types/yargs@17.0.35` is written for yargs 17 APIs.\n\n## Official Sources\n\n- https://www.npmjs.com/package/@types/yargs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/yargs\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/yargs/index.d.ts\n- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/yargs/helpers.d.ts\n- https://www.npmjs.com/package/yargs\n- https://yargs.js.org/\n"
  },
  {
    "path": "content/typescript-eslint/docs/eslint-plugin/typescript/DOC.md",
    "content": "---\nname: eslint-plugin\ndescription: \"TypeScript-specific ESLint rules and preset configs for flat config and legacy ESLint setups, including typed linting\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.57.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,eslint,typescript-eslint,linting,plugin\"\n---\n\n# @typescript-eslint/eslint-plugin\n\n`@typescript-eslint/eslint-plugin` adds TypeScript-specific rules and shareable configs for ESLint.\n\nInstall it with `@typescript-eslint/parser`. There is no runtime client, no API key, no environment variable, and no authentication step. All setup happens in your ESLint config.\n\n## Install\n\nFor a TypeScript project using ESLint flat config:\n\n```bash\nnpm install --save-dev eslint @eslint/js typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin\n```\n\nKeep `@typescript-eslint/eslint-plugin` and `@typescript-eslint/parser` on matching versions.\n\n## Flat config (`eslint.config.mjs`)\n\nThe package exports flat presets under `configs['flat/...']`.\n\n### Recommended preset\n\nUse this for a TypeScript-first repo that wants the maintained baseline rules.\n\n```js\nimport js from '@eslint/js';\nimport tseslint from '@typescript-eslint/eslint-plugin';\n\nexport default [\n  js.configs.recommended,\n  ...tseslint.configs['flat/recommended'],\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    rules: {\n      '@typescript-eslint/consistent-type-imports': 'error',\n    },\n  },\n];\n```\n\n`flat/recommended` already registers the TypeScript parser and the `@typescript-eslint` plugin for you.\n\n### Typed linting\n\nUse a `*-type-checked` preset when you want rules that need real TypeScript type information, such as `@typescript-eslint/no-floating-promises`.\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport js from '@eslint/js';\nimport tseslint from '@typescript-eslint/eslint-plugin';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  js.configs.recommended,\n  ...tseslint.configs['flat/recommended-type-checked'],\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: __dirname,\n      },\n    },\n  },\n];\n```\n\nThe preset alone is not enough for typed rules. Add `parserOptions.projectService: true` or `parserOptions.project` so the parser can build TypeScript program services.\n\n### Manual rule setup\n\nUse the plugin object directly when you want a small custom rule set instead of a preset.\n\n```js\nimport tsParser from '@typescript-eslint/parser';\nimport tseslint from '@typescript-eslint/eslint-plugin';\n\nexport default [\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: {\n        ecmaVersion: 'latest',\n        sourceType: 'module',\n      },\n    },\n    plugins: {\n      '@typescript-eslint': tseslint,\n    },\n    rules: {\n      'no-unused-vars': 'off',\n      '@typescript-eslint/no-unused-vars': [\n        'error',\n        {\n          argsIgnorePattern: '^_',\n          varsIgnorePattern: '^_',\n        },\n      ],\n      'no-shadow': 'off',\n      '@typescript-eslint/no-shadow': 'error',\n      '@typescript-eslint/consistent-type-imports': 'error',\n    },\n  },\n];\n```\n\nWhen you enable a TypeScript extension rule such as `@typescript-eslint/no-unused-vars` or `@typescript-eslint/no-shadow`, turn off the overlapping core rule first.\n\n## Legacy config (`.eslintrc.cjs`)\n\nUse the legacy `plugin:@typescript-eslint/...` presets only in `.eslintrc*` files.\n\n### Recommended preset\n\n```js\nmodule.exports = {\n  parser: '@typescript-eslint/parser',\n  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],\n};\n```\n\n### Typed linting in legacy config\n\n```js\nmodule.exports = {\n  parser: '@typescript-eslint/parser',\n  extends: [\n    'eslint:recommended',\n    'plugin:@typescript-eslint/recommended-type-checked',\n  ],\n  parserOptions: {\n    projectService: true,\n    tsconfigRootDir: __dirname,\n  },\n};\n```\n\nThe package also exports the legacy config name `recommended-requiring-type-checking`.\n\n## Preset families\n\nUse these preset groups depending on how opinionated and type-aware you want linting to be:\n\n- `recommended`, `strict`, `stylistic`, and `all`\n- `recommended-type-checked`, `strict-type-checked`, and `stylistic-type-checked`\n- `recommended-type-checked-only`, `strict-type-checked-only`, and `stylistic-type-checked-only`\n- `disable-type-checked` when you need to turn type-aware rules back off for a file set\n\nFlat config uses `configs['flat/...']`. Legacy config uses `plugin:@typescript-eslint/...`.\n\n## Common workflows\n\n### Enable typed linting only for TypeScript files\n\nIf a repo contains both JavaScript and TypeScript, enable typed presets for TypeScript and disable them for JavaScript overrides.\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport js from '@eslint/js';\nimport tseslint from '@typescript-eslint/eslint-plugin';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  js.configs.recommended,\n  ...tseslint.configs['flat/recommended-type-checked'],\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: __dirname,\n      },\n    },\n  },\n  {\n    ...tseslint.configs['flat/disable-type-checked'],\n    files: ['**/*.{js,mjs,cjs}'],\n  },\n];\n```\n\n### Use `project` for monorepos\n\nUse `project` when you need to point linting at specific `tsconfig.json` files.\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tseslint from '@typescript-eslint/eslint-plugin';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  ...tseslint.configs['flat/recommended-type-checked'],\n  {\n    files: ['packages/*/src/**/*.{ts,tsx}'],\n    languageOptions: {\n      parserOptions: {\n        project: ['./packages/*/tsconfig.json'],\n        tsconfigRootDir: __dirname,\n      },\n    },\n  },\n];\n```\n\n### Run ESLint\n\nLint the whole repo:\n\n```bash\nnpx eslint .\n```\n\nOr lint only TypeScript source files:\n\n```bash\nnpx eslint \"src/**/*.{ts,tsx,mts,cts}\"\n```\n\n## Important pitfalls\n\n- Install `@typescript-eslint/parser` alongside the plugin. The plugin package does not parse TypeScript by itself.\n- Use `configs['flat/...']` only in flat config and `plugin:@typescript-eslint/...` only in legacy config.\n- Typed presets need `projectService` or `project`; otherwise type-aware rules cannot get TypeScript program information.\n- Turn off overlapping core rules such as `no-unused-vars`, `no-shadow`, `dot-notation`, or `require-await` when you replace them with `@typescript-eslint/*` extension rules.\n- `disable-type-checked` is useful when a typed preset is enabled broadly but some file groups should lint without type information.\n\n## Version-sensitive notes\n\n- This guide targets `@typescript-eslint/eslint-plugin@8.57.0`.\n- The package exports classic presets in `configs` and flat-config presets in `configs['flat/...']`.\n- The package exports the legacy alias `recommended-requiring-type-checking` alongside `recommended-type-checked`.\n\n## Official sources\n\n- https://typescript-eslint.io/packages/eslint-plugin/\n- https://typescript-eslint.io/getting-started\n- https://typescript-eslint.io/users/configs\n- https://typescript-eslint.io/getting-started/typed-linting\n- https://www.npmjs.com/package/@typescript-eslint/eslint-plugin\n"
  },
  {
    "path": "content/typescript-eslint/docs/parser/typescript/DOC.md",
    "content": "---\nname: parser\ndescription: \"ESLint parser for TypeScript with flat config setup, typed linting options, JSX support, and direct AST parsing APIs\"\nmetadata:\n  languages: \"typescript\"\n  versions: \"8.57.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"typescript,eslint,typescript-eslint,parser,linting\"\n---\n\n# @typescript-eslint/parser\n\n`@typescript-eslint/parser` lets ESLint parse TypeScript source files and, when you enable project-aware parsing, expose TypeScript program services to rules that need type information.\n\nThis package is only the parser. It does not include lint rules by itself. Pair it with ESLint core rules, `@typescript-eslint/eslint-plugin`, or the `typescript-eslint` meta package when you want recommended configs and TypeScript-specific rules.\n\n## Install\n\nInstall the parser with ESLint and TypeScript:\n\n```bash\nnpm install --save-dev eslint @eslint/js typescript @typescript-eslint/parser\n```\n\nIf you also want the maintained TypeScript ESLint presets and plugin exports, install the meta package instead of wiring the plugin by hand:\n\n```bash\nnpm install --save-dev eslint @eslint/js typescript typescript-eslint\n```\n\nThere is no auth or required environment variable for normal ESLint usage.\n\n## Minimal flat config\n\nUse the parser directly in `eslint.config.mjs` or `eslint.config.js`:\n\n```js\nimport js from '@eslint/js';\nimport tsParser from '@typescript-eslint/parser';\n\nexport default [\n  js.configs.recommended,\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: {\n        ecmaVersion: 'latest',\n        sourceType: 'module',\n      },\n    },\n  },\n];\n```\n\nSet `sourceType: 'module'` explicitly for ESM code. The parser falls back to `'script'` when ESLint does not provide `sourceType`.\n\n## Typed linting with project service\n\nUse project-aware parsing when your rules need real TypeScript type information. The parser option types call out `projectService` as the preferred choice over `project`.\n\nWith the `typescript-eslint` meta package, a practical flat config looks like this:\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport js from '@eslint/js';\nimport tseslint from 'typescript-eslint';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  js.configs.recommended,\n  ...tseslint.configs.recommendedTypeChecked,\n  {\n    files: ['**/*.{ts,tsx,mts,cts}'],\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: __dirname,\n      },\n    },\n  },\n];\n```\n\nUse `tsconfigRootDir` whenever your ESLint config is not guaranteed to run from the repository root.\n\n## When to use `project`\n\nUse `parserOptions.project` when you need to point the parser at specific `tsconfig.json` files, such as in a monorepo. The option accepts `true`, a single path, multiple paths, or globs.\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tsParser from '@typescript-eslint/parser';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  {\n    files: ['packages/*/src/**/*.{ts,tsx}'],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: {\n        project: ['./packages/*/tsconfig.json'],\n        tsconfigRootDir: __dirname,\n        sourceType: 'module',\n      },\n    },\n  },\n];\n```\n\nIf you use wide globs, you can narrow what gets scanned:\n\n```js\nparserOptions: {\n  project: ['./packages/*/tsconfig.json'],\n  projectFolderIgnoreList: ['**/node_modules/**', '**/dist/**'],\n  tsconfigRootDir: __dirname,\n}\n```\n\n## Legacy `.eslintrc`\n\nFor legacy ESLint config, the parser is configured by package name:\n\n```js\nmodule.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module',\n    projectService: true,\n    tsconfigRootDir: __dirname,\n  },\n};\n```\n\nIf you are not using type-aware rules, remove `projectService`.\n\n## JSX and extra file extensions\n\nFor known TypeScript and JavaScript extensions such as `.tsx`, `.ts`, `.jsx`, and `.js`, TypeScript already understands the file type. `ecmaFeatures.jsx` matters most when ESLint parses JSX from a non-standard extension.\n\n```js\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tsParser from '@typescript-eslint/parser';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport default [\n  {\n    files: ['**/*.{ts,tsx,vue}'],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: {\n        ecmaFeatures: {\n          jsx: true,\n        },\n        extraFileExtensions: ['.vue'],\n        projectService: true,\n        tsconfigRootDir: __dirname,\n      },\n    },\n  },\n];\n```\n\nWhen `extraFileExtensions` is combined with `projectService`, the parser option docs warn that full project reloads may occur.\n\n## Programmatic parsing API\n\nThe package also exports parsing helpers for custom tooling:\n\n```ts\nimport {\n  parse,\n  parseForESLint,\n  createProgram,\n  withoutProjectParserOptions,\n} from '@typescript-eslint/parser';\n\nconst code = 'export const answer: number = 42;';\n\nconst ast = parse(code, {\n  ecmaVersion: 'latest',\n  sourceType: 'module',\n});\n\nconst isolated = parseForESLint(\n  code,\n  withoutProjectParserOptions({\n    filePath: 'src/example.ts',\n    projectService: true,\n    sourceType: 'module',\n  }),\n);\n\nconst program = createProgram('./tsconfig.json', process.cwd());\n\nconst typed = parseForESLint(code, {\n  filePath: 'src/example.ts',\n  programs: [program],\n  sourceType: 'module',\n});\n\nconsole.log(ast.body.length);\nconsole.log(isolated.scopeManager.scopes.length);\nconsole.log(typed.services.program?.getTypeChecker());\n```\n\n`parseForESLint()` returns the AST, `scopeManager`, `visitorKeys`, and `services`. When type information is enabled, `services.program` exposes the backing `ts.Program`.\n\nIf you pass `project`, provide a matching `filePath`. The parser option types mark `filePath` as required for project-backed parsing because the file path is used to look up the file in the TypeScript compiler cache.\n\n## Optional environment variable\n\nIf you embed the parser in custom tooling, `TSESTREE_SINGLE_RUN` can force the parser's single-run inference on or off:\n\n```bash\nTSESTREE_SINGLE_RUN=true eslint .\n```\n\nLeave it unset unless you have a reason to override the default heuristic. The parser option docs describe this as a performance control for one-shot CLI runs versus long-lived sessions.\n\n## Common pitfalls\n\n- The parser only parses; it does not enable rules by itself.\n- Type-aware rules need `projectService`, `project`, or `programs`; otherwise `services.program` is `null`.\n- Use `tsconfigRootDir` in monorepos and tool wrappers so relative `project` paths resolve predictably.\n- Set `sourceType: 'module'` for ESM code instead of relying on the parser fallback.\n- Use `withoutProjectParserOptions()` when parsing isolated snippets so custom tools do not accidentally pay for full project analysis.\n\n## Useful exports\n\nThe package entry point exports these commonly used members:\n\n- `parse`\n- `parseForESLint`\n- `createProgram`\n- `clearCaches`\n- `withoutProjectParserOptions`\n- `version`\n- `meta`\n"
  },
  {
    "path": "content/typing-extensions/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"typing-extensions package guide for Python backported and experimental typing features\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.15.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"typing,type-hints,backports,static-analysis,python\"\n---\n\n# typing-extensions Python Package Guide\n\n## Golden Rule\n\nUse the PyPI package `typing-extensions`, but import it as `typing_extensions`.\n\nReach for this package when you need typing features that are:\n\n- not available in your minimum supported Python version\n- newer than the stdlib `typing` module on some interpreters\n- still incubating outside the standard library\n\nFor cross-version library code, prefer importing the needed symbol from `typing_extensions` instead of writing Python-version branches around `typing`.\n\n## Installation\n\nInstall the exact version you want in an application or lockfile:\n\n```bash\npip install \"typing-extensions==4.15.0\"\n```\n\nCommon dependency managers:\n\n```bash\nuv add \"typing-extensions==4.15.0\"\npoetry add \"typing-extensions==4.15.0\"\n```\n\nFor a reusable library, do not depend on patch-level compatibility. The maintainers document SemVer expectations and explicitly recommend a range based on the first feature you need:\n\n```toml\n[project]\ndependencies = [\n  \"typing-extensions>=4.15,<5\",\n]\nrequires-python = \">=3.9\"\n```\n\nIf you only need an older feature, set the lower bound to that first required version instead of forcing `4.15.0`.\n\n## Setup\n\n`typing_extensions` has no runtime initialization, auth, service clients, or environment variables.\n\nTypical setup is only:\n\n1. add it to project dependencies\n2. import the needed symbols from `typing_extensions`\n3. run a type checker such as `mypy`, `pyright`, or `pyre`\n\nIf your codebase targets only newer Python versions and every needed symbol already exists in `typing`, you may not need this package at runtime. Many libraries still keep it for uniform imports across supported versions.\n\n## Core Usage\n\n### Backport newer typing features\n\nThis is the main use case: write one import path that works across supported Python versions.\n\n```python\nfrom typing_extensions import NotRequired, ReadOnly, Self, TypedDict, override\n\nclass UserPatch(TypedDict, total=False):\n    display_name: str\n    email: NotRequired[str]\n    user_id: ReadOnly[int]\n\nclass Builder:\n    def set_name(self, name: str) -> Self:\n        self.name = name\n        return self\n\nclass BaseHandler:\n    def handle(self, payload: UserPatch) -> None:\n        raise NotImplementedError\n\nclass Handler(BaseHandler):\n    @override\n    def handle(self, payload: UserPatch) -> None:\n        print(payload)\n```\n\nUseful symbols commonly imported from `typing_extensions` include `TypedDict`, `Required`, `NotRequired`, `ReadOnly`, `Literal`, `Final`, `TypeAliasType`, `Self`, `override`, `Protocol`, and `runtime_checkable`.\n\n### Runtime protocols\n\n`Protocol` and `runtime_checkable` are useful when code needs structural typing at runtime as well as in static analysis.\n\n```python\nfrom typing_extensions import Protocol, runtime_checkable\n\n@runtime_checkable\nclass SupportsClose(Protocol):\n    def close(self) -> None: ...\n\ndef shutdown(resource: SupportsClose) -> None:\n    if not isinstance(resource, SupportsClose):\n        raise TypeError(\"resource must define close()\")\n    resource.close()\n```\n\n### Annotation introspection\n\nRecent versions add helpers for inspecting annotations in a version-tolerant way.\n\n```python\nfrom typing_extensions import Format, get_annotations\n\nclass Node:\n    next: \"Node | None\"\n\nannotations = get_annotations(Node, format=Format.FORWARDREF)\nprint(annotations[\"next\"])\n```\n\nUse this when you need consistent behavior across Python versions for forward references and annotation formats.\n\n## Config And Auth\n\nThere is no config file, auth flow, or network setup.\n\nThe only configuration that usually matters is package metadata in `pyproject.toml`:\n\n- choose a lower bound that matches the first feature you use\n- keep `requires-python` aligned with the package's supported versions\n- lock exact versions in applications, but use feature-based version ranges in reusable libraries\n\n## Common Pitfalls\n\n### Package name vs import name\n\nInstall `typing-extensions`, import `typing_extensions`.\n\n### Mixing `typing` and `typing_extensions` carelessly\n\nIf a symbol exists in both modules, choose one import strategy per feature in shared code. This avoids brittle runtime checks and inconsistent annotation objects across Python versions.\n\nFor runtime introspection code, the upstream docs recommend checking against both stdlib and `typing_extensions` variants when necessary.\n\n### Evaluating annotations can run code\n\nThe docs warn that `typing_extensions.get_annotations()`, `typing_extensions.evaluate_forward_ref()`, and stdlib helpers such as `typing.get_type_hints()` may execute code contained in annotations. Do not run them on untrusted code or untrusted annotation strings.\n\n### Old `TypedDict` functional syntax\n\nThe keyword-argument form is obsolete:\n\n```python\n# Avoid\nOldStyle = TypedDict(\"OldStyle\", name=str)\n```\n\nPrefer the dictionary form:\n\n```python\nfrom typing_extensions import TypedDict\n\nNewStyle = TypedDict(\"NewStyle\", {\"name\": str})\n```\n\nThis matters more on Python 3.13+, where the old form is no longer supported by `typing_extensions`.\n\n### Pre-releases are not compatibility promises\n\nThe maintainers do not guarantee backward compatibility for pre-releases. Use stable releases for production code and copy examples from stable docs or tagged releases, not release candidates.\n\n## Version-Sensitive Notes\n\n- `4.15.0` adds `@typing_extensions.disjoint_base`, adds `typing_extensions.type_repr()`, and fixes `evaluate_forward_ref()` handling for type parameters after PEP 695.\n- `4.14.0` ended Python 3.8 support. For `4.15.0`, assume Python `>=3.9`.\n- `4.13.0` added `get_annotations()`, `evaluate_forward_ref()`, and the `Format` enum; use these instead of ad hoc forward-ref parsing when you need runtime annotation inspection.\n- The docs root at `latest/` is the canonical starting point, but its page title may lag behind the newest release. Use the GitHub releases page for exact per-version change notes.\n\n## Official Sources\n\n- Documentation: `https://typing-extensions.readthedocs.io/en/latest/`\n- PyPI: `https://pypi.org/project/typing-extensions/`\n- Repository: `https://github.com/python/typing_extensions`\n- Releases: `https://github.com/python/typing_extensions/releases`\n"
  },
  {
    "path": "content/ujson/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ujson Python package guide for fast JSON serialization and parsing with the UltraJSON C extension\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.11.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ujson,json,serialization,parsing,python,c-extension\"\n---\n\n# ujson Python Package Guide\n\n## Golden Rule\n\nUse `ujson` only when a project explicitly wants the UltraJSON C extension for fast local JSON encode/decode and can tolerate behavior differences from the standard library `json` module. For new dependencies, the maintainers explicitly describe `ujson` as maintenance-only and recommend `orjson` instead.\n\n## What It Is For\n\n`ujson` is a C extension that exposes fast JSON serialization and parsing for Python:\n\n- `ujson.dumps()` and `ujson.dump()` for encoding Python objects to JSON\n- `ujson.loads()` and `ujson.load()` for decoding JSON text from strings or file-like objects\n- `ujson.JSONDecodeError` for parse failures in supported releases\n\nThis package is local-only. There is no service client, no network transport, and no authentication layer.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"ujson==5.11.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"ujson==5.11.0\"\npoetry add \"ujson==5.11.0\"\n```\n\nQuick verification:\n\n```bash\npython - <<'PY'\nfrom importlib.metadata import version\nimport ujson\n\nprint(version(\"ujson\"))\nprint(ujson.__version__)\nPY\n```\n\n## Core Usage\n\n### Serialize a Python object\n\n```python\nimport ujson\n\npayload = {\n    \"name\": \"Ada\",\n    \"active\": True,\n    \"scores\": [3, 7, 11],\n}\n\nbody = ujson.dumps(payload)\nprint(body)\n```\n\nBy default, `ujson` emits compact JSON without spaces.\n\n### Parse JSON text\n\n```python\nimport ujson\n\nraw = '{\"name\":\"Ada\",\"active\":true,\"scores\":[3,7,11]}'\ndata = ujson.loads(raw)\n\nprint(data[\"name\"])\nprint(data[\"scores\"][0])\n```\n\n`loads()` accepts `str`, `bytes`, and `bytearray`.\n\n### Read and write files\n\n```python\nfrom pathlib import Path\nimport ujson\n\npayload = {\"ok\": True, \"items\": [1, 2, 3]}\npath = Path(\"data.json\")\n\nwith path.open(\"w\", encoding=\"utf-8\") as f:\n    ujson.dump(payload, f, ensure_ascii=False, indent=2)\n\nwith path.open(\"r\", encoding=\"utf-8\") as f:\n    loaded = ujson.load(f)\n\nprint(loaded)\n```\n\n### Work with custom types\n\nUse `default=` when an object is not JSON-serializable by default:\n\n```python\nfrom dataclasses import asdict, dataclass\nimport ujson\n\n@dataclass\nclass User:\n    id: int\n    email: str\n\ndef to_jsonable(obj):\n    if isinstance(obj, User):\n        return asdict(obj)\n    raise TypeError(f\"Unsupported type: {type(obj)!r}\")\n\nbody = ujson.dumps(User(id=1, email=\"a@example.com\"), default=to_jsonable)\nprint(body)\n```\n\n## Output Controls\n\nThe upstream README documents these encoding behaviors directly:\n\n- `ensure_ascii=True` by default, so non-ASCII characters are escaped unless you pass `ensure_ascii=False`\n- `escape_forward_slashes=True` by default, so `/` becomes `\\/` unless you disable it\n- `encode_html_chars=True` escapes characters such as `<`, `>`, and `&`\n- `indent` must be an integer and controls pretty-print output\n\nExample:\n\n```python\nimport ujson\n\nbody = ujson.dumps(\n    {\"url\": \"https://example.com\", \"title\": \"café\"},\n    ensure_ascii=False,\n    escape_forward_slashes=False,\n    indent=2,\n    sort_keys=True,\n)\n\nprint(body)\n```\n\nThe official type stubs for current upstream also expose these `dumps()` and `dump()` options:\n\n- `sort_keys`\n- `allow_nan`\n- `reject_bytes`\n- `default`\n- `separators`\n\n## Standard Library Compatibility Notes\n\n`ujson` is close enough for many simple `json.dumps()` and `json.loads()` call sites, but it is not a full `json` drop-in:\n\n- The maintainers say it is a drop-in replacement for most other JSON parsers, not all usage.\n- The official stub signature for `loads()` is just `loads(s: str | bytes | bytearray) -> Any`; stdlib decoder hooks such as `object_hook`, `parse_float`, and `parse_int` are not part of the exposed `ujson.loads()` API.\n- The official stub signature for `dumps()` does not expose stdlib custom encoder class parameters like `cls`.\n- `indent` is typed as `int`; do not pass the string-style indentation patterns that stdlib `json.dumps()` accepts.\n\nIf a codebase depends on exact stdlib JSON semantics, validate behavior before swapping imports globally.\n\n## Error Handling\n\n```python\nimport ujson\n\ntry:\n    ujson.loads('{\"broken\": }')\nexcept ujson.JSONDecodeError as exc:\n    print(f\"Invalid JSON: {exc}\")\n```\n\nFor `5.11.0`, the release notes explicitly call out a fix where nested invalid JSON now raises `JSONDecodeError` instead of `SystemError`.\n\n## Common Pitfalls\n\n- Do not treat `ujson` as the safest default new dependency. Upstream marks it as maintenance-only and recommends `orjson` for new work.\n- `ensure_ascii=True` is the default. If you expect human-readable UTF-8 output, pass `ensure_ascii=False`.\n- `escape_forward_slashes=True` is also the default. This surprises agents comparing output against stdlib `json`.\n- `ujson` is fast for simple encode/decode paths, but the official benchmark table on the project page is old and compares against `ujson 5.7.1.dev26` on CPython `3.11.3`. Do not treat those numbers as current `5.11.0` production guidance.\n- Do not assume every stdlib `json` keyword is supported. Check the exposed `ujson` signature before forwarding kwargs from shared helpers.\n- If you need schema validation, streaming JSON parsing, or custom decoder hooks, `ujson` is usually the wrong layer.\n\n## Version-Sensitive Notes\n\n- `5.11.0` adds inline type stubs, which makes editor and type-checker support better than older `ujson` releases.\n- `5.11.0` supports Python `3.9+` and drops Python `3.8`.\n- `5.11.0` adds Python `3.14`, PyPy 3.11, and Windows ARM64 support in the release notes.\n- As of March 12, 2026, the current PyPI project page has moved to `5.12.0` and raises the Python floor to `>=3.10`. If your project follows latest instead of pinning `5.11.0`, verify interpreter compatibility before upgrading.\n\n## When To Reach For Something Else\n\n- Use stdlib `json` when dependency minimization and broad compatibility matter more than throughput.\n- Use `orjson` when you are choosing a fresh high-performance JSON dependency and can adopt its API and bytes-returning behavior where relevant.\n- Stay on `ujson` when a codebase is already pinned to it and its behavior is part of the existing contract.\n"
  },
  {
    "path": "content/ultralytics/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Ultralytics package guide for Python: install, predict, train, export, and configure YOLO workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.4.21\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"ultralytics,yolo,computer-vision,object-detection,training,inference,export\"\n---\n\n# ultralytics Python Package Guide\n\n## Golden Rule\n\nUse the official `ultralytics` package for Python YOLO workflows, and prefer the current Ultralytics docs over older YOLOv8 blog posts or examples. In the current upstream docs for `8.4.21`, the standard Python entry point is `from ultralytics import YOLO`, and current examples center on the YOLO26 model family.\n\n## Installation\n\n### Recommended install\n\n```bash\npip install ultralytics==8.4.21\n```\n\n### Upgrade to the latest stable release\n\n```bash\npip install -U ultralytics\n```\n\n### Headless servers and containers\n\nIf you are running on a VM, CI runner, Docker container, or other environment without display libraries, use the headless package variant:\n\n```bash\npip install ultralytics-opencv-headless\n```\n\nThis keeps the same API but avoids OpenCV GUI dependencies that can cause `libGL` and display-related failures.\n\n### CUDA and PyTorch note\n\nUltralytics documents `Python>=3.8` and `PyTorch>=1.8`. If you need a CUDA-specific setup, install the PyTorch build for your OS and CUDA version first, then install `ultralytics`.\n\n## Initialize and run your first prediction\n\n```python\nfrom ultralytics import YOLO\n\n# Load a pretrained model\nmodel = YOLO(\"yolo26n.pt\")\n\n# Run inference on an image URL\nresults = model(\"https://ultralytics.com/images/bus.jpg\")\n\nfor result in results:\n    print(result.boxes.xyxy)\n    print(result.boxes.conf)\n    print(result.boxes.cls)\n```\n\nYou can also call `predict()` explicitly when you want to pass more arguments:\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"yolo26n.pt\")\nmodel.predict(\n    source=\"https://ultralytics.com/images/bus.jpg\",\n    save=True,\n    imgsz=320,\n    conf=0.25,\n)\n```\n\n## Core Python workflows\n\n### Build from YAML or load pretrained weights\n\n```python\nfrom ultralytics import YOLO\n\n# New model from YAML\nmodel = YOLO(\"yolo26n.yaml\")\n\n# Recommended starting point for most training workflows\nmodel = YOLO(\"yolo26n.pt\")\n```\n\n### Train on a dataset\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"yolo26n.pt\")\nresults = model.train(\n    data=\"path/to/dataset.yaml\",\n    epochs=100,\n    imgsz=640,\n    device=\"cpu\",\n)\n```\n\nThe docs also support:\n\n- `device=[0, 1]` for explicit multi-GPU training\n- `device=-1` or `device=[-1, -1]` for auto-selecting the most idle GPU(s)\n- `device=\"mps\"` for Apple silicon\n\n### Resume an interrupted run\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"path/to/last.pt\")\nresults = model.train(resume=True)\n```\n\nResume requires a real saved checkpoint such as `last.pt`; upstream docs note that you need at least one completed epoch for resume to work.\n\n### Validate\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"yolo26n.yaml\")\nmodel.train(data=\"path/to/dataset.yaml\", epochs=5)\nmetrics = model.val()\n```\n\n### Predict on larger sources without loading everything into memory\n\nFor directories, long videos, streams, webcams, or segmentation-heavy runs, use `stream=True` so prediction returns a generator instead of a full in-memory list:\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"yolo26n.pt\")\nresults = model.predict(source=\"path/to/video.mp4\", stream=True)\n\nfor result in results:\n    print(result.boxes.xyxy)\n```\n\n### Export for deployment\n\n```python\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"path/to/best.pt\")\nonnx_path = model.export(format=\"onnx\", dynamic=True)\n```\n\nUltralytics supports many export targets. For coding-agent work, ONNX is usually the safest first deployment format because it is well documented and the upstream export examples are straightforward.\n\n## CLI parity\n\nThe documented command format is:\n\n```bash\nyolo TASK MODE ARGS\n```\n\nExamples:\n\n```bash\nyolo detect train data=path/to/dataset.yaml model=yolo26n.pt epochs=100 imgsz=640\nyolo predict model=yolo26n.pt source='https://ultralytics.com/images/bus.jpg'\nyolo export model=path/to/best.pt format=onnx dynamic=True\nyolo settings\n```\n\nThe Python API and CLI use the same core modes and largely the same argument names.\n\n## Configuration and auth\n\nUltralytics exposes a settings manager for local experiment paths and optional platform integrations.\n\n### Inspect settings\n\n```python\nfrom ultralytics import settings\n\nprint(settings)\nprint(settings[\"runs_dir\"])\n```\n\n### Update settings\n\n```python\nfrom ultralytics import settings\n\nsettings.update({\n    \"datasets_dir\": \"/absolute/path/to/datasets\",\n    \"runs_dir\": \"/absolute/path/to/runs\",\n})\n```\n\n### CLI settings management\n\n```bash\nyolo settings\nyolo settings runs_dir='/absolute/path/to/runs'\nyolo settings reset\n```\n\n### What matters in practice\n\n- `datasets_dir` controls where datasets are stored\n- `weights_dir` controls where model weights are stored\n- `runs_dir` controls where experiment outputs are written\n- `sync` controls analytics/crash syncing to Ultralytics Platform\n- `api_key` is the Ultralytics Platform API key field\n\nLocal prediction, validation, training, and export do not require an API key. Auth only becomes relevant if you are using Ultralytics Platform features or other enabled integrations.\n\n## Common pitfalls\n\n- Current upstream docs and examples use YOLO26 model names like `yolo26n.pt` and `yolo26n.yaml`. Do not blindly mix those with older YOLOv8-era snippets unless your project already depends on older checkpoints.\n- `predict()` returns a list by default. On large folders, streams, or long videos, use `stream=True` to avoid unnecessary memory growth.\n- On headless Linux servers, prefer `ultralytics-opencv-headless` instead of debugging GUI-linked OpenCV errors after the fact.\n- If outputs or dataset lookups are landing in unexpected locations, inspect `settings[\"datasets_dir\"]`, `settings[\"weights_dir\"]`, and `settings[\"runs_dir\"]` first.\n- Resume training only from a real checkpoint such as `last.pt`, not from an arbitrary exported model.\n- Export behavior is format-specific. If the deployment target needs variable input sizes, prefer `dynamic=True` for ONNX export.\n\n## Version-sensitive notes for 8.4.21\n\n- `ultralytics 8.4.21` was released on `2026-03-05`.\n- The official `v8.4.21` release notes call out a Rockchip RKNN export path fix as the main package change in this release.\n- The same release also mentions improved Ray Tune trial isolation and clearer YOLO26 optimizer guidance.\n- The current official docs emphasize YOLO26 for new examples, while some release notes and older examples still reference YOLOv8-family compatibility. For new code, follow the current docs; for existing projects, match the checkpoint family already in use.\n\n## Official Sources\n\n- Quickstart: `https://docs.ultralytics.com/quickstart/`\n- Python usage: `https://docs.ultralytics.com/usage/python/`\n- Configuration: `https://docs.ultralytics.com/usage/cfg/`\n- Training mode: `https://docs.ultralytics.com/modes/train/`\n- Prediction mode: `https://docs.ultralytics.com/modes/predict/`\n- Export mode: `https://docs.ultralytics.com/modes/export/`\n- API reference root: `https://docs.ultralytics.com/reference/`\n- PyPI version page: `https://pypi.org/project/ultralytics/8.4.21/`\n- Release notes: `https://github.com/ultralytics/ultralytics/releases/tag/v8.4.21`\n"
  },
  {
    "path": "content/undici/docs/undici/javascript/DOC.md",
    "content": "---\nname: undici\ndescription: \"Node.js HTTP client with fetch, request, connection pooling, proxy support, and request mocking\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.22.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"undici,http,fetch,nodejs\"\n---\n\n# Undici HTTP Client for Node.js\n\nUse `undici` when you want Node-focused HTTP client features beyond the built-in `fetch`, including `request()`, custom dispatchers, proxy agents, and test mocks.\n\n## Installation and version choice\n\n`undici@7.22.0` requires Node.js `>=20.18.1`.\n\n```bash\nnpm install undici\n```\n\nNode.js already ships a built-in `fetch()` powered by a bundled version of Undici. Install the package when you need a newer Undici release or APIs that are not exposed through the built-in runtime fetch.\n\n```js\nconsole.log(process.versions.undici)\n```\n\nUse built-in `fetch` when you want zero dependencies and only need standard Web API behavior. Install `undici` when you need package-level version control, `request()`, `Agent`, `ProxyAgent`, `EnvHttpProxyAgent`, or `MockAgent`.\n\n## Environment variables\n\nUndici does not handle application auth for you. Set headers yourself for the upstream API you are calling.\n\n```bash\nAPI_BASE_URL=https://api.example.com\nAPI_TOKEN=replace-me\n\n# Optional: only used with EnvHttpProxyAgent\nHTTP_PROXY=http://proxy.internal:8080\nHTTPS_PROXY=http://proxy.internal:8443\nNO_PROXY=localhost,127.0.0.1\n```\n\n## Initialize a reusable client\n\nFor most apps, create one dispatcher and reuse it across requests.\n\n```js\nimport { Agent, fetch, setGlobalDispatcher } from 'undici'\n\nconst baseUrl = process.env.API_BASE_URL ?? 'https://api.example.com'\nconst token = process.env.API_TOKEN\n\nconst dispatcher = new Agent({\n  keepAliveTimeout: 10_000,\n  keepAliveMaxTimeout: 10_000,\n  autoSelectFamily: true\n})\n\nsetGlobalDispatcher(dispatcher)\n\nconst response = await fetch(`${baseUrl}/v1/items`, {\n  headers: token\n    ? { authorization: `Bearer ${token}` }\n    : undefined\n})\n\nif (!response.ok) {\n  throw new Error(`HTTP ${response.status}: ${await response.text()}`)\n}\n\nconst items = await response.json()\nconsole.log(items)\n\nawait dispatcher.close()\n```\n\n`autoSelectFamily: true` can help when a host resolves to IPv6 first and you see `UND_ERR_CONNECT_TIMEOUT` on networks with broken IPv6 connectivity.\n\n## Make JSON requests with `fetch()`\n\nUse `fetch()` when you want the familiar WHATWG API.\n\n```js\nimport { fetch } from 'undici'\n\nconst baseUrl = process.env.API_BASE_URL ?? 'https://api.example.com'\nconst token = process.env.API_TOKEN\n\nconst response = await fetch(`${baseUrl}/v1/items`, {\n  method: 'POST',\n  headers: {\n    'content-type': 'application/json',\n    ...(token ? { authorization: `Bearer ${token}` } : {})\n  },\n  body: JSON.stringify({\n    name: 'example',\n    enabled: true\n  })\n})\n\nif (!response.ok) {\n  throw new Error(`HTTP ${response.status}: ${await response.text()}`)\n}\n\nconst item = await response.json()\nconsole.log(item)\n```\n\nYou can also pass a dispatcher per request instead of setting it globally:\n\n```js\nimport { Agent, fetch } from 'undici'\n\nconst dispatcher = new Agent({\n  keepAliveTimeout: 10_000,\n  keepAliveMaxTimeout: 10_000\n})\n\nconst response = await fetch('https://api.example.com/health', {\n  dispatcher\n})\n\nconsole.log(response.status)\n\nawait dispatcher.close()\n```\n\n## Use `request()` for lower-overhead calls\n\n`request()` is the fastest common Undici API and returns a Node-style readable body.\n\n```js\nimport { request } from 'undici'\n\nconst baseUrl = process.env.API_BASE_URL ?? 'https://api.example.com'\nconst token = process.env.API_TOKEN\n\nconst { statusCode, body } = await request(`${baseUrl}/v1/items`, {\n  method: 'POST',\n  headers: {\n    'content-type': 'application/json',\n    ...(token ? { authorization: `Bearer ${token}` } : {})\n  },\n  body: JSON.stringify({\n    name: 'example',\n    enabled: true\n  })\n})\n\nif (statusCode !== 201) {\n  throw new Error(`HTTP ${statusCode}: ${await body.text()}`)\n}\n\nconst item = await body.json()\nconsole.log(item)\n```\n\n`request().body` supports body mixins such as `.json()` and `.text()`, but each body can only be consumed once.\n\n## Stream downloads and uploads\n\n`fetch().body` is a web stream. Convert it to a Node stream when you need filesystem or stream pipeline APIs.\n\n```js\nimport { fetch } from 'undici'\nimport { createWriteStream } from 'node:fs'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\n\nconst response = await fetch('https://example.com/archive.tar.gz')\n\nif (!response.ok || !response.body) {\n  throw new Error(`Download failed: ${response.status}`)\n}\n\nawait pipeline(\n  Readable.fromWeb(response.body),\n  createWriteStream('./archive.tar.gz')\n)\n```\n\nIf you send an `AsyncIterable` or `ReadableStream` body with `fetch()`, set `duplex: 'half'`.\n\n```js\nimport { fetch } from 'undici'\n\nconst body = {\n  async *[Symbol.asyncIterator] () {\n    yield '{\"chunk\":1}\\n'\n    yield '{\"chunk\":2}\\n'\n  }\n}\n\nconst response = await fetch('https://api.example.com/import', {\n  method: 'POST',\n  headers: {\n    'content-type': 'application/x-ndjson'\n  },\n  body,\n  duplex: 'half'\n})\n\nconsole.log(response.status)\n```\n\n## Upload files with `FormData`\n\n```js\nimport { fetch, FormData } from 'undici'\nimport { openAsBlob } from 'node:fs'\n\nconst file = await openAsBlob('./big.csv')\nconst form = new FormData()\n\nform.set('file', file, 'big.csv')\nform.set('purpose', 'import')\n\nconst response = await fetch('https://api.example.com/uploads', {\n  method: 'POST',\n  body: form\n})\n\nif (!response.ok) {\n  throw new Error(`Upload failed: ${response.status}`)\n}\n```\n\n## Configure proxies\n\nUse `EnvHttpProxyAgent` when you want proxy settings from environment variables.\n\n```js\nimport { EnvHttpProxyAgent, fetch } from 'undici'\n\nconst dispatcher = new EnvHttpProxyAgent()\n\nconst response = await fetch('https://example.com/data', {\n  dispatcher\n})\n\nconsole.log(response.status)\n\nawait dispatcher.close()\n```\n\n`EnvHttpProxyAgent` reads `http_proxy`, `https_proxy`, and `no_proxy`. Uppercase variants are also supported, but if both lowercase and uppercase versions are set, the lowercase values win.\n\nUse `ProxyAgent` when you want to set the proxy explicitly in code, including proxy authentication.\n\n```js\nimport { ProxyAgent, request } from 'undici'\n\nconst dispatcher = new ProxyAgent({\n  uri: 'http://proxy.internal:8080',\n  token: `Basic ${Buffer.from('username:password').toString('base64')}`\n})\n\nconst { statusCode, body } = await request('http://example.com', {\n  dispatcher\n})\n\nconsole.log(statusCode)\nconsole.log(await body.text())\n\nawait dispatcher.close()\n```\n\n## Mock HTTP calls in tests\n\nUse `MockAgent` to intercept requests without opening real network connections.\n\n```js\nimport { MockAgent, fetch, setGlobalDispatcher } from 'undici'\n\nconst mockAgent = new MockAgent()\nmockAgent.disableNetConnect()\n\nconst mockPool = mockAgent.get('https://api.example.com')\nmockPool\n  .intercept({\n    path: '/v1/items',\n    method: 'GET'\n  })\n  .reply(200, {\n    items: [{ id: 'item_123', name: 'example' }]\n  })\n\nsetGlobalDispatcher(mockAgent)\n\nconst response = await fetch('https://api.example.com/v1/items')\nconst json = await response.json()\n\nconsole.log(json.items[0].id)\n\nmockAgent.assertNoPendingInterceptors()\nawait mockAgent.close()\n```\n\n`disableNetConnect()` is useful in tests because unmatched requests fail immediately instead of silently making real HTTP calls.\n\n## Install Undici globals\n\nIf you want Undici's WHATWG classes on `globalThis`, call `install()` once at process startup.\n\n```js\nimport { install } from 'undici'\n\ninstall()\n\nconst response = await fetch('https://example.com')\nconst text = await response.text()\nconsole.log(text)\n```\n\nThis installs `fetch`, `Headers`, `Response`, `Request`, `FormData`, `WebSocket`, and `EventSource` globally.\n\n## Important notes and pitfalls\n\n- Undici does not perform browser-style CORS checks. Server-side requests are allowed unless your own code blocks them.\n- Always consume or cancel response bodies. Do not rely on garbage collection to free connections.\n- If you only need headers, prefer `HEAD` instead of issuing a `GET` and ignoring the body.\n- `fetch().body` is a web stream; convert it with `Readable.fromWeb()` if you need a Node stream.\n- `request().body` does not implement `.formData()`.\n- Once you call a body mixin such as `.json()` or `.text()`, you cannot reuse that same body again.\n\n## Official references\n\n- Main docs: `https://undici.nodejs.org/`\n- Package README: `https://github.com/nodejs/undici/blob/v7.22.0/README.md`\n- API docs in the package: `https://github.com/nodejs/undici/tree/v7.22.0/docs/docs/api`\n"
  },
  {
    "path": "content/unsloth/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Unsloth Python package guide for fast LLM fine-tuning, inference, and export workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.3.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"unsloth,python,llm,fine-tuning,inference,lora,trl,transformers\"\n---\n\n# Unsloth Python Package Guide\n\n## What It Is\n\n`unsloth` is a Python package for faster, lower-memory LLM workflows on top of the Hugging Face stack. The maintainer docs center on:\n\n- supervised fine-tuning with LoRA or QLoRA\n- accelerated inference for supported models\n- reinforcement learning workflows such as GRPO, GSPO, DPO, ORPO, PPO, and reward modeling\n- model export to merged Hugging Face weights or GGUF for `llama.cpp`-style runtimes\n\nFor `2026.3.4`, the practical reference points are the official docs site, the PyPI package metadata, and the maintainer GitHub README examples.\n\n## Installation\n\nInstall the package directly from PyPI:\n\n```bash\npip install unsloth==2026.3.4\n```\n\nIf you are not pinning the version used here:\n\n```bash\npip install unsloth\n```\n\n### Environment expectations\n\n- The official docs are oriented around NVIDIA GPU setups and hosted notebook environments such as Colab, Kaggle, RunPod, AWS, Azure, and GCP.\n- The official FAQ says Windows users should run Unsloth through WSL instead of native Windows.\n- Plan the rest of the stack together: `unsloth` works with `transformers`, `trl`, `datasets`, and PEFT-style adapter training.\n\n## Core Setup\n\nThe maintainer README uses `FastLanguageModel` as the stable entry point for text-model loading, adapter attachment, training, and inference.\n\n```python\nfrom unsloth import FastLanguageModel\n\nmax_seq_length = 2048\n\nmodel, tokenizer = FastLanguageModel.from_pretrained(\n    model_name=\"unsloth/Llama-3.2-1B\",\n    max_seq_length=max_seq_length,\n    dtype=None,\n    load_in_4bit=True,\n    token=None,  # supply a Hugging Face token only for gated models\n)\n```\n\nImportant knobs from the official examples:\n\n- `max_seq_length`: sets the target context window and is part of Unsloth's long-context handling.\n- `dtype=None`: lets the loader auto-detect a sensible dtype for the current hardware.\n- `load_in_4bit=True`: cuts VRAM use for QLoRA-style workflows.\n- `token=...`: needed when the base model is gated on Hugging Face.\n\n## Attach LoRA Adapters\n\nAfter loading the base model, the maintainer workflow adds adapters with `get_peft_model`:\n\n```python\nmodel = FastLanguageModel.get_peft_model(\n    model,\n    r=16,\n    target_modules=[\n        \"q_proj\",\n        \"k_proj\",\n        \"v_proj\",\n        \"o_proj\",\n        \"gate_proj\",\n        \"up_proj\",\n        \"down_proj\",\n    ],\n    lora_alpha=16,\n    lora_dropout=0,\n    bias=\"none\",\n    use_gradient_checkpointing=\"unsloth\",\n)\n```\n\nPractical defaults from the official example:\n\n- `r=16` and `lora_alpha=16` are the starter values shown by the maintainer.\n- `lora_dropout=0` and `bias=\"none\"` are the optimized path used in the reference flow.\n- `use_gradient_checkpointing=\"unsloth\"` is the maintainer-recommended setting for longer contexts and tighter memory budgets.\n\n## Supervised Fine-Tuning\n\nThe common training path uses TRL's `SFTTrainer` and `SFTConfig`:\n\n```python\nfrom datasets import load_dataset\nfrom trl import SFTConfig, SFTTrainer\nfrom unsloth import is_bfloat16_supported\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\ntrainer = SFTTrainer(\n    model=model,\n    tokenizer=tokenizer,\n    train_dataset=dataset,\n    args=SFTConfig(\n        dataset_text_field=\"text\",\n        max_seq_length=max_seq_length,\n        per_device_train_batch_size=2,\n        gradient_accumulation_steps=4,\n        warmup_steps=5,\n        max_steps=60,\n        learning_rate=2e-4,\n        logging_steps=1,\n        optim=\"adamw_8bit\",\n        weight_decay=0.01,\n        lr_scheduler_type=\"linear\",\n        fp16=not is_bfloat16_supported(),\n        bf16=is_bfloat16_supported(),\n        output_dir=\"outputs\",\n        seed=3407,\n    ),\n)\n\ntrainer.train()\n```\n\nUse this as the base pattern when you need a minimal, reproducible SFT loop. Then swap in your own dataset and trainer settings.\n\n## Chat Datasets And Templates\n\nFor chat or instruction tuning, keep the tokenizer chat template aligned with your dataset format before training or inference.\n\nThe official docs show this pattern:\n\n```python\nfrom unsloth.chat_templates import get_chat_template\n\ntokenizer = get_chat_template(\n    tokenizer,\n    chat_template=\"llama-3.1\",\n)\n```\n\nThen apply the template to your messages before generation:\n\n```python\nmessages = [\n    {\"role\": \"user\", \"content\": \"Continue the Fibonacci sequence.\"},\n]\n\ninputs = tokenizer.apply_chat_template(\n    messages,\n    tokenize=True,\n    add_generation_prompt=True,\n    return_tensors=\"pt\",\n).to(\"cuda\")\n```\n\nIf you train on conversational data but only want loss on assistant outputs, the maintainer tooling also exposes `train_on_responses_only`.\n\n## Inference\n\nBefore generation, switch the model into the inference-optimized path:\n\n```python\nFastLanguageModel.for_inference(model)\n\ninputs = tokenizer(\n    [\"Continue the Fibonacci sequence: 1, 1, 2, 3, 5, 8,\"],\n    return_tensors=\"pt\",\n).to(\"cuda\")\n\noutputs = model.generate(**inputs, max_new_tokens=64)\nprint(tokenizer.batch_decode(outputs))\n```\n\nFor instruct models, prefer `apply_chat_template(...)` over raw prompt strings so the runtime prompt matches the fine-tuning format.\n\n## Saving And Export\n\nThe maintainer README documents three common persistence paths:\n\n### Save LoRA adapters only\n\n```python\nmodel.save_pretrained(\"lora_model\")\ntokenizer.save_pretrained(\"lora_model\")\n```\n\n### Save or push merged 16-bit weights\n\n```python\nmodel.save_pretrained_merged(\n    \"merged_model\",\n    tokenizer,\n    save_method=\"merged_16bit\",\n)\n\nmodel.push_to_hub_merged(\n    \"your-hf-user/merged_model\",\n    tokenizer,\n    save_method=\"merged_16bit\",\n    token=\"hf_...\",\n)\n```\n\n### Export GGUF for `llama.cpp`\n\n```python\nmodel.save_pretrained_gguf(\n    \"model\",\n    tokenizer,\n    quantization_method=\"q4_k_m\",\n)\n```\n\nChoose the output format based on the next runtime:\n\n- adapters only for continued PEFT training\n- merged weights for standard Hugging Face serving or conversion steps\n- GGUF when targeting `llama.cpp`-compatible local inference\n\n## Config And Auth Notes\n\n- Hugging Face auth is not a general Unsloth API key flow. Use the `token` argument only when loading gated models or pushing artifacts to the Hugging Face Hub.\n- Keep `max_seq_length` explicit in code instead of relying on hidden defaults.\n- Decide early whether you want 4-bit loading. It affects VRAM usage, training strategy, and downstream export choices.\n- Use `is_bfloat16_supported()` from Unsloth when copying the official trainer setup so BF16 and FP16 follow the current GPU capability.\n\n## Common Pitfalls\n\n- Native Windows is not the recommended path. The official FAQ points Windows users to WSL.\n- Do not mix raw string prompting and chat-template prompting for the same instruct model. Keep the dataset template and inference template consistent.\n- Many examples online assume a plain `transformers` or PEFT flow. When using Unsloth helpers such as `FastLanguageModel`, follow the maintainer method names and argument shapes rather than mixing in third-party wrappers.\n- Newer official docs pages sometimes demonstrate broader abstractions such as `FastModel`, while the maintainer README still uses `FastLanguageModel` for text LLM workflows. For text fine-tuning on this package version, the README flow is the safest baseline.\n- Export format matters. `save_pretrained`, `save_pretrained_merged`, and `save_pretrained_gguf` produce different artifacts for different runtimes.\n\n## Version-Sensitive Notes For `2026.3.4`\n\n- The package version is date-based, not semver-like. Pin the exact PyPI version when you need reproducible trainer behavior.\n- PyPI metadata for `2026.3.4` declares Python support from `3.9` up to but excluding `3.14`.\n- The official docs and README cover a broad surface area, including text, vision, TTS, and RL workflows. Start with the text-model loading and SFT path above unless your task clearly needs a different trainer family.\n\n## Official Sources\n\n- Docs root: `https://docs.unsloth.ai/`\n- FAQ: `https://docs.unsloth.ai/basics/troubleshooting-and-faqs`\n- Chat templates guide: `https://docs.unsloth.ai/basics/chat-templates`\n- PyPI package page: `https://pypi.org/project/unsloth/`\n- PyPI metadata JSON: `https://pypi.org/pypi/unsloth/json`\n- Maintainer README: `https://github.com/unslothai/unsloth`\n"
  },
  {
    "path": "content/urllib3/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"urllib3 package guide for Python: connection pooling, retries, TLS verification, proxies, and streaming HTTP\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.6.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"urllib3,http,https,python,retries,tls,proxies\"\n---\n\n# urllib3 Python Package Guide\n\n## Golden Rule\n\nUse a dedicated `urllib3.PoolManager(...)` in application code and reuse it. Use top-level `urllib3.request(...)` only for short scripts, CLIs, or REPL work.\n\n`urllib3` 2.x is the low-level HTTP client layer focused on connection pooling, retries, TLS, proxies, and streaming. It is synchronous, thread-safe at the pool level, and a good fit when you want direct control over request behavior without a higher-level client wrapper.\n\n## Version Snapshot\n\n- Package: `urllib3`\n- Ecosystem: `pypi`\n- Version covered here: `2.6.3`\n- Python requirement for 2.x: `3.9+`\n- TLS baseline in 2.x: OpenSSL `1.1.1+`, TLS `1.2+` by default\n\n## Installation\n\nInstall the package version you expect to run:\n\n```bash\npython -m pip install urllib3==2.6.3\n```\n\nCommon optional extras:\n\n```bash\npython -m pip install \"urllib3[socks]\"\npython -m pip install \"urllib3[brotli]\"\npython -m pip install \"urllib3[zstd]\"\n```\n\nUse the `socks` extra only if you need SOCKS proxies. Prefer the official extras for compression support so you pick compatible decoder packages.\n\n## Initialize a Reusable Client\n\nStart with one long-lived `PoolManager`. It handles connection pooling and thread safety for you.\n\n```python\nimport urllib3\nfrom urllib3.util import Retry, Timeout\n\nhttp = urllib3.PoolManager(\n    num_pools=20,\n    maxsize=10,\n    block=True,\n    timeout=Timeout(connect=2.0, read=10.0),\n    retries=Retry(\n        total=5,\n        connect=3,\n        read=2,\n        status=3,\n        backoff_factor=0.2,\n        status_forcelist={429, 500, 502, 503, 504},\n        allowed_methods={\"DELETE\", \"GET\", \"HEAD\", \"OPTIONS\", \"PUT\"},\n        respect_retry_after_header=True,\n    ),\n    headers={\n        \"User-Agent\": \"my-service/1.0\",\n        \"Accept\": \"application/json\",\n    },\n)\n```\n\nNotes:\n\n- `num_pools` controls how many host-specific pools are cached.\n- `maxsize` controls how many reusable connections are kept per host.\n- With `block=True`, at most `maxsize` connections are open per host; callers wait instead of creating unbounded extra connections.\n- Pool-level `timeout` and `retries` become defaults and can still be overridden per request.\n\n## Quick Requests\n\n### GET with query parameters\n\nFor `GET`, `HEAD`, and `DELETE`, pass query params with `fields=...`:\n\n```python\nresp = http.request(\n    \"GET\",\n    \"https://api.example.com/items\",\n    fields={\"page\": 1, \"limit\": 50},\n)\n\nprint(resp.status)\ndata = resp.json()\n```\n\n### POST JSON\n\nUse `json=...` instead of manually encoding JSON. `urllib3` sets `Content-Type: application/json` if you have not already set it.\n\n```python\nresp = http.request(\n    \"POST\",\n    \"https://api.example.com/items\",\n    json={\"name\": \"demo\", \"enabled\": True},\n)\n\npayload = resp.json()\n```\n\n### Form-encoded POST\n\nFor `POST` or `PUT`, a dict in `fields=...` becomes form data:\n\n```python\nresp = http.request(\n    \"POST\",\n    \"https://api.example.com/login\",\n    fields={\"username\": \"alice\", \"password\": \"secret\"},\n)\n```\n\n### Raw bytes upload\n\n```python\nwith open(\"report.pdf\", \"rb\") as fp:\n    resp = http.request(\n        \"PUT\",\n        \"https://api.example.com/upload\",\n        body=fp.read(),\n        headers={\"Content-Type\": \"application/pdf\"},\n    )\n```\n\n## Response Handling\n\n`request()` returns an `HTTPResponse`. The fields agents usually need are:\n\n- `resp.status`\n- `resp.headers`\n- `resp.data`\n- `resp.json()` for JSON responses\n\nExample:\n\n```python\nresp = http.request(\"GET\", \"https://api.example.com/health\")\n\nif resp.status != 200:\n    raise RuntimeError(f\"unexpected status: {resp.status}\")\n\nprint(resp.headers.get(\"Content-Type\"))\nprint(resp.data)\n```\n\nUse `resp.json()` only when the response is actually JSON. Otherwise parse `resp.data` yourself.\n\n## Timeouts and Retries\n\nAlways set explicit timeouts in production code.\n\n```python\nimport urllib3\n\nresp = http.request(\n    \"GET\",\n    \"https://api.example.com/slow-endpoint\",\n    timeout=urllib3.Timeout(connect=1.0, read=5.0),\n)\n```\n\nRetry guidance:\n\n- `urllib3` retries idempotent methods by default.\n- Passing an integer like `retries=3` mainly covers connection errors and redirects.\n- Use `urllib3.util.Retry(...)` when you need status-code-based retry behavior, `Retry-After` support, or custom allowed methods.\n- Do not blindly retry non-idempotent operations like `POST` unless the upstream API explicitly guarantees safety.\n\n## Streaming Large Responses\n\nUse `preload_content=False` for large or unknown-size responses. When you do this, you must release the connection back to the pool.\n\n```python\nresp = http.request(\n    \"GET\",\n    \"https://api.example.com/export\",\n    preload_content=False,\n)\n\ntry:\n    with open(\"export.bin\", \"wb\") as fp:\n        while chunk := resp.read(64 * 1024):\n            fp.write(chunk)\nfinally:\n    resp.release_conn()\n```\n\nIf you stop reading early, call `resp.drain_conn()` before `resp.release_conn()` so the connection can be safely reused.\n\n## Headers and Basic Authentication\n\n`urllib3` does not maintain a higher-level auth system. In most cases you send auth as headers.\n\nBearer token example:\n\n```python\nresp = http.request(\n    \"GET\",\n    \"https://api.example.com/me\",\n    headers={\"Authorization\": f\"Bearer {token}\"},\n)\n```\n\nBasic auth helper:\n\n```python\nimport urllib3\n\nheaders = urllib3.util.make_headers(basic_auth=\"username:password\")\nresp = http.request(\"GET\", \"https://api.example.com/me\", headers=headers)\n```\n\n## TLS Verification and Certificates\n\nHTTPS certificate verification is on by default in modern urllib3. Leave it on unless you are debugging a trusted internal environment.\n\nCross-platform CA bundle example with `certifi`:\n\n```python\nimport certifi\nimport urllib3\n\nhttp = urllib3.PoolManager(\n    cert_reqs=\"CERT_REQUIRED\",\n    ca_certs=certifi.where(),\n)\n```\n\nPrivate CA bundle:\n\n```python\nhttp = urllib3.PoolManager(\n    cert_reqs=\"CERT_REQUIRED\",\n    ca_certs=\"/path/to/ca-bundle.pem\",\n)\n```\n\nClient certificate / mutual TLS:\n\n```python\nhttp = urllib3.PoolManager(\n    cert_file=\"/path/to/client-cert.pem\",\n    key_file=\"/path/to/client-key.pem\",\n    key_password=\"optional-password\",\n    cert_reqs=\"CERT_REQUIRED\",\n    ca_certs=\"/path/to/ca-bundle.pem\",\n)\n```\n\nIf you must connect to an older server, you can lower the minimum TLS version explicitly, but treat that as a compatibility exception, not the default.\n\n## Proxies\n\n### HTTP or HTTPS proxy\n\n```python\nimport urllib3\n\nproxy = urllib3.ProxyManager(\"http://proxy.internal:8080\")\nresp = proxy.request(\"GET\", \"https://api.example.com/data\")\n```\n\nIf your proxy only speaks HTTP, the proxy URL must start with `http://`, not `https://`.\n\nFor HTTPS proxies, `use_forwarding_for_https=True` gives the proxy full visibility into HTTPS requests. Use it only with trusted corporate proxies.\n\n### SOCKS proxy\n\nInstall the extra first:\n\n```bash\npython -m pip install \"urllib3[socks]\"\n```\n\nThen:\n\n```python\nfrom urllib3.contrib.socks import SOCKSProxyManager\n\nproxy = SOCKSProxyManager(\"socks5h://proxy.example.com:1080\")\nresp = proxy.request(\"GET\", \"https://api.example.com/data\")\n```\n\nPrefer `socks5h://` or `socks4a://` so DNS resolution happens on the proxy side instead of the client side.\n\n## Common Pitfalls\n\n- Do not build application code around top-level `urllib3.request(...)` if shared process state matters. It uses a module-global pool.\n- Do not forget `resp.release_conn()` when using `preload_content=False`.\n- For `POST` and `PUT`, query parameters are not auto-encoded from `fields`; encode them into the URL yourself if the API expects query params.\n- Cookies sent via the `Cookie` header are stripped on redirects to a different host.\n- Prefer `resp.headers` and `resp.headers.get(...)` over `getheaders()` / `getheader()`. Those methods were removed in `2.6.0` and restored in `2.6.1`.\n- Do not disable certificate verification in production just to make TLS errors disappear. Fix CA bundles, hostnames, proxy config, or TLS versions instead.\n\n## Version-Sensitive Notes for 2.x\n\n- `urllib3` 2.x requires Python `3.9+`.\n- `urllib3` 2.x requires OpenSSL `1.1.1+` and defaults to TLS `1.2+`.\n- `urllib3.request(...)` and `HTTPResponse.json()` are available in 2.x and are useful for scripts, but `PoolManager` is still the safer default for services.\n- `2.6.3` includes a security fix for redirects plus streamed compressed responses and caps `Retry-After` values above 6 hours by default.\n- `2.6.0` tightened compressed-response decoding. If you use Brotli support, prefer the official `urllib3[brotli]` extra and keep Brotli libraries current.\n- HTTP/2 support exists in 2.x but is still marked experimental upstream. Do not assume it is a drop-in replacement for mature HTTP/1.1 production paths.\n\n## Migration Clues\n\nIf you are upgrading from 1.26.x and hit errors, these usually indicate a dependency or import-path problem rather than a broken urllib3 install:\n\n- `ImportError: cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_'`\n- `AttributeError: module 'urllib3.connectionpool' has no attribute 'VerifiedHTTPSConnection'`\n- `AttributeError: 'HTTPResponse' object has no attribute 'strict'`\n\nWhen these appear, check whether another dependency in the environment still expects urllib3 1.26.x or old private import paths.\n\n## Official Sources\n\n- Docs root: https://urllib3.readthedocs.io/en/stable/\n- User guide: https://urllib3.readthedocs.io/en/stable/user-guide.html\n- Advanced usage: https://urllib3.readthedocs.io/en/stable/advanced-usage.html\n- API reference: https://urllib3.readthedocs.io/en/stable/reference/index.html\n- v2 migration guide: https://urllib3.readthedocs.io/en/2.6.3/v2-migration-guide.html\n- Changelog: https://urllib3.readthedocs.io/en/2.6.3/changelog.html\n- PyPI: https://pypi.org/project/urllib3/\n"
  },
  {
    "path": "content/uuid/docs/uuid/javascript/DOC.md",
    "content": "---\nname: uuid\ndescription: \"Install and use the `uuid` package in JavaScript to generate, validate, and transform UUID values.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"13.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"javascript,uuid,utility,identifiers,npm\"\n---\n\n# uuid JavaScript Guide\n\n`uuid` generates UUID strings and provides helpers for validation, deterministic IDs, and byte conversion.\n\n## Install\n\nInstall the package into your app:\n\n```bash\nnpm install uuid\n```\n\n## Initialization\n\nThere are no package-specific environment variables, auth steps, or client objects.\n\nUse top-level named imports from `uuid` in application code:\n\n```javascript\nimport {\n  NIL,\n  parse as uuidParse,\n  stringify as uuidStringify,\n  v4 as uuidv4,\n  v5 as uuidv5,\n  validate as uuidValidate,\n  version as uuidVersion,\n} from \"uuid\";\n```\n\n## Common Workflows\n\n### Generate random IDs with `v4()`\n\nUse `v4()` when you need a random UUID for a database record, job, or request identifier.\n\n```javascript\nimport { v4 as uuidv4 } from \"uuid\";\n\nexport function createJob(payload) {\n  return {\n    id: uuidv4(),\n    payload,\n    status: \"queued\",\n  };\n}\n```\n\n### Generate deterministic IDs with `v5()`\n\nUse `v5()` when the same input should always produce the same UUID within a namespace.\n\n```javascript\nimport { v5 as uuidv5 } from \"uuid\";\n\nconst APP_NAMESPACE = \"1b671a64-40d5-491e-99b0-da01ff1f3341\";\n\nexport function customerUuid(customerKey) {\n  return uuidv5(customerKey, APP_NAMESPACE);\n}\n\nconst pageUuid = uuidv5(\"https://example.com/users/42\", uuidv5.URL);\n```\n\nThe built-in RFC namespaces are exposed as `uuidv5.URL` and `uuidv5.DNS`.\n\n### Validate inbound UUID strings\n\nUse `validate()` before trusting values from API routes, CLI flags, or message payloads. If your code requires a specific UUID version, check `version()` too.\n\n```javascript\nimport { validate as uuidValidate, version as uuidVersion } from \"uuid\";\n\nexport function assertUuidV4(value) {\n  if (!uuidValidate(value) || uuidVersion(value) !== 4) {\n    throw new Error(\"Expected a UUIDv4 string\");\n  }\n}\n```\n\n### Convert between UUID strings and raw bytes\n\nUse `parse()` and `stringify()` when your storage layer or protocol uses a 16-byte UUID representation.\n\n```javascript\nimport {\n  parse as uuidParse,\n  stringify as uuidStringify,\n  v4 as uuidv4,\n} from \"uuid\";\n\nconst id = uuidv4();\nconst bytes = uuidParse(id);\nconst roundTrip = uuidStringify(bytes);\n\nconsole.log({ id, bytes, roundTrip });\n```\n\n### Use `NIL` as an all-zero sentinel UUID\n\n`NIL` is the all-zero UUID string.\n\n```javascript\nimport { NIL } from \"uuid\";\n\nif (sessionId === NIL) {\n  throw new Error(\"Session has not been assigned a UUID yet\");\n}\n```\n\n## React Native and Expo\n\nIf your runtime does not provide `crypto.getRandomValues()`, add the React Native polyfill before importing `uuid`.\n\n```bash\nnpm install uuid react-native-get-random-values\n```\n\n```javascript\nimport \"react-native-get-random-values\";\nimport { v4 as uuidv4 } from \"uuid\";\n\nconst id = uuidv4();\n```\n\nImport the polyfill before `uuid` so random UUID generation works reliably.\n\n## Important Pitfalls\n\n- `validate()` only tells you whether a value is a valid UUID. If your contract requires a specific version such as v4, also check `version()`.\n- `version()` throws when the input is not a valid UUID, so validate the string first.\n- `parse()` throws when the input string is not a valid UUID.\n- `stringify()` expects a 16-byte array and preserves the left-to-right byte order used in UUID strings.\n- Prefer top-level named imports from `uuid` rather than deep subpath imports.\n\n## Version-Sensitive Notes\n\n- This guide targets `uuid@13.0.0`.\n- The package still requires no service configuration: install it, import the helpers you need, and call them directly.\n- If your codebase depends on APIs beyond the helpers shown here, check the upstream README for the exact release you ship.\n\n## Official Sources\n\n- https://github.com/uuidjs/uuid\n- https://github.com/uuidjs/uuid/blob/main/README.md\n- https://www.npmjs.com/package/uuid\n"
  },
  {
    "path": "content/uv/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"uv package guide for Python projects using Astral's package, project, tool, and Python management workflows\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.10.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"uv,python,packaging,virtualenv,dependency-management,cli\"\n---\n\n# uv Python Package Guide\n\n## Golden Rule\n\nUse `uv` as the entry point for Python environment, dependency, script, tool, and interpreter management instead of mixing ad hoc `pip`, `venv`, `pip-tools`, `pipx`, and `pyenv` workflows inside the same project. For a managed project, keep dependencies in `pyproject.toml`, let `uv lock` and `uv sync` own the environment state, and treat private indexes as an explicit configuration and authentication step.\n\n## Install\n\nThe maintainer docs prefer the standalone installer or an OS package manager for end-user CLI installs. Installing from PyPI is still valid when you need `uv` inside an existing Python environment.\n\n```bash\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n```\n\n```bash\npython -m pip install \"uv==0.10.9\"\n```\n\nCommon alternatives:\n\n```bash\nbrew install uv\nwinget install --id=astral-sh.uv -e\n```\n\nCheck the installed version:\n\n```bash\nuv --version\n```\n\n## Initialize And Manage A Project\n\nCreate a new project:\n\n```bash\nuv init my-app\ncd my-app\n```\n\nAdd dependencies and run code through the managed environment:\n\n```bash\nuv add httpx\nuv run python -c \"import httpx; print(httpx.__version__)\"\n```\n\nImportant project files:\n\n- `pyproject.toml`: project metadata, dependencies, and `tool.uv` settings\n- `uv.lock`: lockfile generated by `uv lock`\n- `.venv/`: project virtual environment created and updated by `uv sync` and `uv run`\n\n`uv run ...` will create the project virtual environment if needed before running the command. `uv sync` installs the lockfile state into the environment, and it is exact by default, so packages not declared in the lockfile are removed unless you opt into `--inexact`.\n\n## Core Workflows\n\n### Add, remove, lock, and sync dependencies\n\n```bash\nuv add pydantic\nuv remove pydantic\nuv lock\nuv sync\n```\n\nUse `uv lock --check` in CI when you want to fail on lock drift instead of rewriting the lockfile.\n\n### Run a single script with inline metadata\n\nFor one-file scripts, `uv` supports inline script metadata and can manage script dependencies directly:\n\n```bash\nuv add --script main.py httpx\nuv run main.py\n```\n\nThis is useful when the repo does not need a full project layout but still needs reproducible dependencies.\n\n### Use the pip-compatible interface when a project is not uv-managed\n\n`uv` also exposes a `pip`-compatible surface:\n\n```bash\nuv venv\nuv pip install ruff\nuv pip freeze\n```\n\nPrefer the project commands (`uv add`, `uv lock`, `uv sync`, `uv run`) for applications with a `pyproject.toml`. Reach for `uv pip ...` when you explicitly need pip-style behavior or are operating on an environment that is not managed through uv's project model. By default, `uv pip` expects a virtual environment, so create one first with `uv venv` or activate an existing environment.\n\n### Install and run developer tools\n\nFor global or user-level CLI tools, use the tool workflow instead of adding those packages to your app dependencies:\n\n```bash\nuv tool install ruff\nuv tool run ruff check .\nuvx pycowsay \"hello\"\n```\n\n`uvx` is an alias for `uv tool run` and is the fast path for one-off tool execution.\n\n### Manage Python interpreters\n\n`uv` can install and select Python versions directly:\n\n```bash\nuv python install 3.12\nuv python pin 3.12\n```\n\nThis is useful when bootstrapping a project on a machine without the expected interpreter already available.\n\n## Configuration And Auth\n\nProject-level configuration usually lives in `pyproject.toml` under `[tool.uv]`. A sibling `uv.toml` file is also supported and takes precedence over `[tool.uv]` when both exist.\n\nExample project settings:\n\n```toml\n[tool.uv]\nmanaged = true\n\n[[tool.uv.index]]\nname = \"internal\"\nurl = \"https://packages.example.com/simple\"\n\n[tool.uv.sources]\nmy-lib = { index = \"internal\" }\n```\n\nUse `[[tool.uv.index]]` to define alternative or private package indexes. If you want an index to replace PyPI as the default, set `default = true` on that index.\n\nFor credentials, prefer external auth instead of embedding secrets in `pyproject.toml`:\n\n- HTTP credentials can be supplied in the URL, though that is usually the least safe option\n- `uv` can read credentials from `.netrc`\n- `uv` supports a keyring subprocess provider\n- Native secret-store auth exists behind the preview feature `native-auth`\n\nFor index-specific environment variables, derive the variable name from the index name:\n\n```bash\nexport UV_INDEX_INTERNAL_USERNAME=\"scott\"\nexport UV_INDEX_INTERNAL_PASSWORD=\"tiger\"\n```\n\nWhen using private indexes, verify both pieces separately:\n\n1. The index configuration is correct.\n2. Authentication is available in the environment where `uv` runs.\n\n## Common Pitfalls\n\n- Do not mix `uv add` and manual `pip install` into the same managed `.venv` and assume the lockfile still reflects reality.\n- `uv sync` is exact by default. If a package disappears after sync, it was probably not declared in the lockfile or project metadata.\n- `uv tool install` is for developer tools like `ruff` or `pytest`, not for project runtime dependencies.\n- `uv pip ...` is not the best default for a uv-managed application. It bypasses part of the higher-level project workflow.\n- A `uv.toml` file overrides `[tool.uv]` settings in `pyproject.toml`; check both when behavior seems inconsistent.\n- `managed = false` disables uv's project environment management for that project. Use it only when another workflow is intentionally responsible for the environment.\n- Private package indexes need both index configuration and credentials. One without the other leads to misleading resolution failures.\n\n## Version-Sensitive Notes For 0.10.9\n\n- `uv` follows a release policy that is not strict Semantic Versioning. Minor releases may still include breaking changes, so read the changelog and migration notes before assuming any `0.x` upgrade is trivial.\n- Preview functionality is opt-in. If a workflow depends on features such as `native-auth`, make the preview requirement explicit in automation and onboarding docs.\n- As of March 12, 2026, PyPI and the maintainer docs agree on `uv 0.10.9`.\n\n## Official Sources\n\n- Docs root: https://docs.astral.sh/uv/\n- Installation: https://docs.astral.sh/uv/getting-started/installation/\n- Projects guide: https://docs.astral.sh/uv/guides/projects/\n- Scripts guide: https://docs.astral.sh/uv/guides/scripts/\n- Tools guide: https://docs.astral.sh/uv/guides/tools/\n- Alternative indexes: https://docs.astral.sh/uv/guides/integration/alternative-indexes/\n- Authentication: https://docs.astral.sh/uv/concepts/authentication/\n- Versioning policy: https://docs.astral.sh/uv/policies/versioning/\n- PyPI: https://pypi.org/project/uv/\n"
  },
  {
    "path": "content/uvicorn/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Uvicorn 0.41.0 package guide for serving ASGI apps in Python.\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.41.0\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"uvicorn,asgi,python,server,fastapi,starlette,websockets\"\n---\n\n# `uvicorn` Python package\n\nUse `uvicorn` when you need to run an ASGI app such as FastAPI, Starlette, or a plain ASGI callable. For `0.41.0`, treat it as the HTTP/WebSocket server layer, not the application framework.\n\n## Install\n\n`0.41.0` requires Python `>=3.10`.\n\nMinimal install:\n\n```bash\npip install uvicorn==0.41.0\n```\n\nWith the commonly useful optional runtime extras:\n\n```bash\npip install 'uvicorn[standard]==0.41.0'\n```\n\nWith `uv`:\n\n```bash\nuv add uvicorn==0.41.0\nuv add 'uvicorn[standard]==0.41.0'\n```\n\n`uvicorn[standard]` is usually the better default for local development and most production installs because it adds:\n\n- `uvloop` for a faster event loop where supported\n- `httptools` for HTTP parsing\n- `websockets` for WebSocket handling\n- `watchfiles` for better `--reload`\n- `python-dotenv` for `--env-file`\n- `PyYAML` for YAML log config\n\n## Initialize and run\n\n### Plain ASGI app\n\n```python\nasync def app(scope, receive, send):\n    assert scope[\"type\"] == \"http\"\n    await send(\n        {\n            \"type\": \"http.response.start\",\n            \"status\": 200,\n            \"headers\": [\n                (b\"content-type\", b\"text/plain\"),\n                (b\"content-length\", b\"13\"),\n            ],\n        }\n    )\n    await send({\"type\": \"http.response.body\", \"body\": b\"Hello, world!\"})\n```\n\nRun it:\n\n```bash\nuvicorn main:app\n```\n\n### Common development command\n\n```bash\nuvicorn main:app --reload --host 0.0.0.0 --port 8000\n```\n\nUse `main:app` style import strings for CLI runs and for any setup that needs reload or multiple workers.\n\n### Programmatic startup\n\n```python\nimport uvicorn\n\nif __name__ == \"__main__\":\n    uvicorn.run(\"main:app\", host=\"127.0.0.1\", port=8000, log_level=\"info\")\n```\n\nIf you need direct lifecycle control:\n\n```python\nimport asyncio\nimport uvicorn\n\nasync def main():\n    config = uvicorn.Config(\"main:app\", host=\"127.0.0.1\", port=8000, log_level=\"info\")\n    server = uvicorn.Server(config)\n    await server.serve()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n### Application factory\n\n```python\ndef create_app():\n    app = ...\n    return app\n```\n\n```bash\nuvicorn --factory main:create_app\n```\n\nUse `--factory` when your app is created at runtime instead of exported as a module-level object.\n\n## Configuration model\n\nUvicorn supports three configuration paths, in this precedence order:\n\n1. CLI flags\n2. `uvicorn.run(...)` keyword arguments\n3. `UVICORN_*` environment variables\n\nTypical examples:\n\n```bash\nexport UVICORN_HOST=0.0.0.0\nexport UVICORN_PORT=8000\nuvicorn main:app\n```\n\nUseful options for agents:\n\n- `--host` and `--port` for bind address\n- `--reload` for local development\n- `--workers` for multiple processes\n- `--loop auto|asyncio|uvloop`\n- `--http auto|h11|httptools`\n- `--ws auto|websockets|websockets-sansio|wsproto`\n- `--lifespan auto|on|off`\n- `--proxy-headers` and `--forwarded-allow-ips`\n- `--root-path` when mounted behind a path prefix\n- `--env-file` for app environment variables\n- `--log-config`, `--log-level`, `--no-access-log`\n- `--ssl-keyfile` and `--ssl-certfile` for direct TLS termination\n\n## FastAPI and Starlette usage\n\nFastAPI and Starlette projects typically expose an `app` object and run the same way:\n\n```python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n@app.get(\"/health\")\nasync def health():\n    return {\"ok\": True}\n```\n\n```bash\nuvicorn main:app --reload\n```\n\nIf the module is not in the current working directory, add `--app-dir` or run from the correct project root.\n\n## Proxies, TLS, and auth boundaries\n\nUvicorn can read forwarded headers and can terminate TLS itself, but many deployments place it behind Nginx, a load balancer, or a CDN.\n\nCommon reverse-proxy setup:\n\n```bash\nuvicorn main:app --proxy-headers --forwarded-allow-ips='127.0.0.1'\n```\n\nAdjust `--forwarded-allow-ips` to the actual trusted proxy addresses. Do not set `'*'` unless you intentionally trust every upstream hop.\n\nFor self-hosted production, common patterns are:\n\n- Uvicorn behind Nginx using a UNIX socket or local TCP port\n- Uvicorn behind a platform load balancer\n- Uvicorn managed by a process manager or Gunicorn-compatible worker setup\n\nAuth is not a Uvicorn feature. Handle authentication, authorization, sessions, and CSRF in the ASGI app or in upstream infrastructure. This is an inference from Uvicorn's role as an ASGI server rather than an app framework.\n\n## Production patterns\n\nSingle-process:\n\n```bash\nuvicorn main:app --host 0.0.0.0 --port 8000\n```\n\nBuilt-in multiprocess manager:\n\n```bash\nuvicorn main:app --workers 4 --host 0.0.0.0 --port 8000\n```\n\nRelevant production controls:\n\n- `--workers` defaults from `WEB_CONCURRENCY` when set\n- `--limit-concurrency` can shed load with HTTP 503 responses\n- `--limit-max-requests` can recycle workers after N requests\n- `--limit-max-requests-jitter` was added in `0.41.0` to stagger those restarts\n- `--timeout-graceful-shutdown` controls shutdown wait time\n- `--timeout-worker-healthcheck` controls worker healthcheck timeout\n\nUvicorn's built-in process manager uses `spawn`, not pre-fork. That keeps multiprocess mode usable on Windows, but it also means your startup code must be import-safe.\n\n## Common pitfalls\n\n- `--reload` and `--workers` are mutually exclusive.\n- Passing an app object directly to `uvicorn.run(app, ...)` only works when you are not using reload or multiprocessing. Prefer `\"module:app\"` import strings for reusable startup code.\n- Put `uvicorn.run(...)` inside `if __name__ == \"__main__\":` when using reload or workers.\n- `--env-file` is for the application environment. It does not configure Uvicorn itself, and `UVICORN_*` variables are not loaded from that file.\n- `--reload-include` and `--reload-exclude` only take effect when `watchfiles` is installed. Without it, reload falls back to polling Python files.\n- `--proxy-headers` is not enough for every proxy chain. Complex multi-proxy setups may need explicit ASGI middleware to derive client IP and scheme correctly.\n- If imports fail on startup, verify the `APP` import string and use `--app-dir` when the module root is not on `PYTHONPATH`.\n\n## Version-sensitive notes for `0.41.0`\n\n- PyPI marks `0.41.0` as requiring Python `>=3.10`.\n- Current docs expose `--ws websockets-sansio`; that protocol option was added in `0.35.0`, so older blog posts may not match current WebSocket configuration.\n- `0.41.0` adds `--limit-max-requests-jitter` for staggered worker recycling.\n- The `uvicorn.workers` module is deprecated in the official docs and scheduled for removal in a future release. For Gunicorn-managed deployments, the docs now recommend the separate `uvicorn-worker` package.\n- The official docs site is current, not version-pinned. When behavior matters, prefer examples that still match the `0.41.0` CLI and release notes.\n\n## Official references\n\n- Docs root: https://www.uvicorn.org/\n- Canonical docs link advertised by upstream: https://uvicorn.dev/\n- Installation: https://www.uvicorn.org/installation/\n- Settings and CLI options: https://www.uvicorn.org/settings/\n- Deployment: https://www.uvicorn.org/deployment/\n- Release notes: https://www.uvicorn.org/release-notes/\n- PyPI package: https://pypi.org/project/uvicorn/\n"
  },
  {
    "path": "content/uvloop/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"uvloop Python package guide for replacing the default asyncio event loop with the libuv-based implementation\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.22.1\"\n  revision: 2\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"uvloop,asyncio,event-loop,async,libuv,performance\"\n---\n\n# uvloop Python Package Guide\n\n## Golden Rule\n\nUse `uvloop` only as an event-loop implementation choice for applications you control at process startup. Prefer `uvloop.run(...)` or `asyncio.Runner(loop_factory=uvloop.new_event_loop)` over policy hacks in new code.\n\nAfter setup, write standard `asyncio` code. `uvloop` does not change the coroutine API.\n\n## What It Is\n\n`uvloop` is a drop-in implementation of `asyncio.AbstractEventLoop` built on top of `libuv`. It is mainly useful for network-heavy async services that already use normal `asyncio` primitives and want a faster event loop without rewriting application code.\n\nUse it when:\n\n- the app already uses `asyncio`\n- you can choose the process event loop at startup\n- you run on supported POSIX or macOS targets\n\nSkip it when:\n\n- the runtime is Windows\n- the host framework or platform already owns loop setup in a way you cannot safely replace\n- code depends on old `asyncio.get_event_loop()` fallback behavior\n\n## Installation\n\n`uvloop` 0.22.1 requires CPython and Python `>=3.8.1`.\n\nInstall the pinned version:\n\n```bash\npip install uvloop==0.22.1\n```\n\nWith `uv`:\n\n```bash\nuv add uvloop==0.22.1\n```\n\nFor projects that resolve latest allowed versions:\n\n```bash\nuv pip install uvloop\n```\n\nPractical install notes:\n\n- Wheels are published for common CPython builds, so most macOS and Linux installs should not need a local compile toolchain.\n- Package metadata lists `MacOS :: MacOS X` and `POSIX`; do not assume Windows support.\n- If pip falls back to building from source, upgrade `pip` first as upstream recommends.\n\n## Initialize At Startup\n\n### Preferred: `uvloop.run(...)`\n\nFor top-level application entry points, use `uvloop.run(...)`.\n\n```python\nimport asyncio\nimport uvloop\n\nasync def main() -> None:\n    await asyncio.sleep(0.1)\n    print(\"running on uvloop\")\n\nif __name__ == \"__main__\":\n    uvloop.run(main())\n```\n\nThis is the current upstream-recommended pattern.\n\n### When You Need Runner Options\n\nIf you need `debug=True` or other `asyncio.Runner` control, pass `uvloop.new_event_loop` as the loop factory.\n\n```python\nimport asyncio\nimport uvloop\n\nasync def main() -> None:\n    await asyncio.sleep(0.1)\n\nwith asyncio.Runner(loop_factory=uvloop.new_event_loop, debug=True) as runner:\n    runner.run(main())\n```\n\n### Global Policy Installation\n\nUse policy installation only when some other part of startup still calls `asyncio.run(...)` or otherwise expects the process-wide loop policy to be set first.\n\n```python\nimport asyncio\nimport uvloop\n\nasyncio.set_event_loop_policy(uvloop.EventLoopPolicy())\n\nasync def main() -> None:\n    await asyncio.sleep(0.1)\n\nasyncio.run(main())\n```\n\n`uvloop.install()` is a shorthand for setting the event loop policy:\n\n```python\nimport uvloop\n\nuvloop.install()\n```\n\nPrefer explicit startup ownership instead of scattering `install()` calls across library code.\n\n## Core Usage\n\nOnce active, use normal `asyncio` APIs.\n\n### Concurrent Work\n\n```python\nimport asyncio\nimport uvloop\n\nasync def work(name: str, delay: float) -> str:\n    await asyncio.sleep(delay)\n    return f\"{name} done\"\n\nasync def main() -> None:\n    results = await asyncio.gather(\n        work(\"a\", 0.05),\n        work(\"b\", 0.10),\n        work(\"c\", 0.02),\n    )\n    print(results)\n\nuvloop.run(main())\n```\n\n### TCP Server\n\n```python\nimport asyncio\nimport uvloop\n\nasync def handle_echo(\n    reader: asyncio.StreamReader,\n    writer: asyncio.StreamWriter,\n) -> None:\n    data = await reader.read(1024)\n    writer.write(data)\n    await writer.drain()\n    writer.close()\n    await writer.wait_closed()\n\nasync def main() -> None:\n    server = await asyncio.start_server(handle_echo, \"127.0.0.1\", 9000)\n    async with server:\n        await server.serve_forever()\n\nuvloop.run(main())\n```\n\n### Explicit Loop Ownership\n\nUse `uvloop.new_event_loop()` only when code needs direct loop ownership.\n\n```python\nimport asyncio\nimport uvloop\n\nloop = uvloop.new_event_loop()\nasyncio.set_event_loop(loop)\n\ntry:\n    loop.run_until_complete(asyncio.sleep(0.1))\nfinally:\n    loop.close()\n```\n\n## Config And Auth\n\n`uvloop` has no auth model, credentials, service endpoints, or package-specific environment variables.\n\nThe configuration surface is mainly:\n\n- which startup pattern you use: `uvloop.run`, `asyncio.Runner(..., loop_factory=...)`, or policy install\n- whether asyncio debug mode is enabled\n- whether the process should use `uvloop` globally or only for one owned runner\n\nRecommended defaults:\n\n- app entry point you control: `uvloop.run(main())`\n- app entry point with explicit debug or runner settings: `asyncio.Runner(loop_factory=uvloop.new_event_loop, ...)`\n- legacy bootstrap needing a global loop policy: `asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())`\n\n## Common Pitfalls\n\n- Install or select `uvloop` before creating the first long-lived loop, transport, server, or client.\n- Do not call `uvloop.run()` from inside an already-running loop. In notebooks, REPLs, and some test runners, let the host manage the loop.\n- Do not assume Windows support. Package metadata still advertises macOS and POSIX targets only.\n- Avoid setting loop policy from reusable library code. That is an application-startup decision.\n- If code still calls `asyncio.get_event_loop()` with no current loop, test carefully on `0.22.1`; policy-installed `uvloop` may raise instead of lazily creating one.\n- Benchmark the real workload before forcing `uvloop` everywhere. Blocking code, heavy CPU work, or framework-specific behavior can erase the benefit.\n\n## Version-Sensitive Notes For 0.22.1\n\n- PyPI lists `0.22.1` as the current release, published on `2025-10-16`.\n- The maintainer GitHub release for `v0.22.1` says it is identical to `0.22.0` and was re-run with CI fixes. Treat the functional changes as the `0.22.0` line.\n- The `v0.22.0` release notes call out Python `3.14` fixes and free-threading support work.\n- The old Read the Docs user guide is stale for current usage: it still mentions Python `3.5` and older policy-based setup. For modern code, prefer the PyPI/GitHub README guidance built around `uvloop.run(...)`.\n- The maintainer issue tracker currently has an open `0.22.1` report that `asyncio.get_event_loop()` after `uvloop.install()` raises when no current loop exists. Write code against `asyncio.run(...)`, `asyncio.Runner(...)`, or explicit `new_event_loop()` instead of depending on implicit loop creation.\n\n## Official Sources Used\n\n- Docs landing page: https://uvloop.readthedocs.io/\n- User guide: https://uvloop.readthedocs.io/user/\n- PyPI package page: https://pypi.org/project/uvloop/\n- PyPI JSON metadata: https://pypi.org/pypi/uvloop/json\n- GitHub repository: https://github.com/MagicStack/uvloop\n- GitHub README: https://github.com/MagicStack/uvloop/blob/master/README.rst\n- GitHub releases: https://github.com/MagicStack/uvloop/releases\n- Maintainer issue about `get_event_loop()` behavior: https://github.com/MagicStack/uvloop/issues/702\n"
  },
  {
    "path": "content/vcrpy/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"VCR.py package guide for recording and replaying HTTP interactions in Python tests\"\nmetadata:\n  languages: \"python\"\n  versions: \"8.1.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"vcrpy,python,testing,http,requests,httpx,aiohttp,cassettes\"\n---\n\n# VCR.py Python Package Guide\n\n## Golden Rule\n\nUse `vcrpy` to make HTTP-heavy tests deterministic, but import it as `vcr` and scrub secrets before you commit cassette files. As of March 12, 2026, PyPI lists `vcrpy 8.1.1`, while the official Read the Docs site still renders as `8.0.0`, so prefer PyPI metadata for version and Python compatibility and use the maintainer docs for behavior and APIs.\n\n## Install\n\nPin the package in test dependencies so cassette behavior stays stable across CI and local runs:\n\n```bash\npython -m pip install \"vcrpy==8.1.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add --dev \"vcrpy==8.1.1\"\npoetry add --group test \"vcrpy==8.1.1\"\n```\n\n`vcrpy` works by patching supported HTTP stacks. The official docs cover `requests`, `urllib3`, `urllib`, `httpx`, `httpcore`, `aiohttp`, `boto3`, and Tornado integrations.\n\n## Minimal Setup\n\nUse a shared `VCR` instance instead of sprinkling one-off defaults across tests:\n\n```python\nfrom pathlib import Path\n\nimport requests\nimport vcr\n\nmy_vcr = vcr.VCR(\n    cassette_library_dir=str(Path(\"tests/cassettes\")),\n    path_transformer=vcr.VCR.ensure_suffix(\".yaml\"),\n    record_mode=\"once\",\n    match_on=[\"method\", \"scheme\", \"host\", \"port\", \"path\", \"query\"],\n    filter_headers=[(\"authorization\", \"DUMMY\")],\n    filter_query_parameters=[(\"api_key\", \"DUMMY\")],\n)\n\ndef test_list_users():\n    with my_vcr.use_cassette(\"users/list\"):\n        response = requests.get(\n            \"https://api.example.com/users\",\n            headers={\"Authorization\": \"Bearer super-secret-token\"},\n            params={\"api_key\": \"super-secret-key\"},\n            timeout=10,\n        )\n        response.raise_for_status()\n        assert response.json()\n```\n\nWhat this setup buys you:\n\n- cassettes stay under `tests/cassettes/`\n- every cassette gets a `.yaml` suffix automatically\n- `record_mode=\"once\"` reuses existing cassettes and fails loudly when requests drift\n- auth headers and query tokens are scrubbed before writing to disk\n\n## One-Off Usage\n\nFor a single test module, the top-level helper is enough:\n\n```python\nimport requests\nimport vcr\n\n@vcr.use_cassette(\"tests/cassettes/github.yaml\")\ndef test_github_status():\n    response = requests.get(\"https://api.github.com/rate_limit\", timeout=10)\n    response.raise_for_status()\n    assert \"resources\" in response.json()\n```\n\nWhen you omit the cassette path, VCR.py can auto-generate one from the test name, but explicit paths are easier to manage in larger suites.\n\n## Core Configuration\n\n### `record_mode`\n\nPick this deliberately:\n\n- `once`: record once, replay afterwards, and raise if a new unmatched request appears\n- `new_episodes`: append new requests to an existing cassette\n- `none`: never hit the network; fail if the cassette does not satisfy the request\n- `all`: always hit the real network and rewrite the cassette\n\nFor CI, `once` or `none` is usually the safest choice.\n\n### Request matching\n\nVCR.py matches on request attributes, not just URL text. The default matcher list includes method, scheme, host, port, path, and query. If your API legitimately varies on headers or body, extend `match_on` rather than weakening assertions globally.\n\nExample for JSON POSTs that should also match on body:\n\n```python\nimport vcr\n\napi_vcr = vcr.VCR(\n    match_on=[\"method\", \"scheme\", \"host\", \"port\", \"path\", \"query\", \"body\"],\n)\n```\n\n### Cassette storage and naming\n\nCommon options:\n\n- `cassette_library_dir`: base directory for cassette files\n- `path_transformer=vcr.VCR.ensure_suffix(\".yaml\")`: normalize file suffixes\n- `func_path_generator`: customize auto-generated cassette names for decorators\n\nIf you want every test file to keep its own cassette tree, centralize that naming policy in one helper instead of duplicating it per test.\n\n### Filtering sensitive data\n\nVCR.py does not manage credentials for you. It records whatever your application sends unless you filter it.\n\nUse these options aggressively:\n\n- `filter_headers=[(\"authorization\", \"DUMMY\")]`\n- `filter_query_parameters=[(\"token\", \"DUMMY\")]`\n- `filter_post_data_parameters=[(\"client_secret\", \"DUMMY\")]`\n- `before_record_request` for custom request scrubbing\n- `before_record_response` for response-body cleanup\n\nExample custom request filter:\n\n```python\nimport vcr\n\ndef drop_healthcheck(request):\n    if request.uri.endswith(\"/health\"):\n        return None\n    return request\n\nfiltered_vcr = vcr.VCR(\n    before_record_request=drop_healthcheck,\n    filter_headers=[(\"authorization\", \"DUMMY\")],\n)\n```\n\nReturning `None` from `before_record_request` skips that interaction entirely.\n\n### Compressed responses\n\nSet `decode_compressed_response=True` when you want readable cassette bodies. Leave it off if your test needs to preserve the exact compressed payload behavior.\n\n## Test Framework Integration\n\n### `unittest`\n\nVCR.py ships built-in helpers for `unittest`:\n\n```python\nimport requests\nfrom vcr.unittest import VCRTestCase\n\nclass TestStatusAPI(VCRTestCase):\n    def test_status(self):\n        response = requests.get(\"https://api.example.com/status\", timeout=10)\n        response.raise_for_status()\n        self.assertEqual(response.status_code, 200)\n```\n\nUse `VCRMixin` if you need to combine VCR.py with another base test class.\n\n### `pytest`\n\nPlain decorators and context managers work fine under `pytest`. If you want markers or fixtures, the official docs point to `pytest-vcr` and `pytest-recording`, but those are separate packages, not built into `vcrpy`.\n\n## Common Pitfalls\n\n- Import `vcr`, not `vcrpy`. The PyPI package name and Python import name differ.\n- `record_mode=\"once\"` is the default. When a request changes and the existing cassette no longer matches, VCR.py raises `CannotOverwriteExistingCassetteException`.\n- `ignore_localhost=True` and `ignore_hosts=[...]` do not mock those requests. They let them bypass VCR.py and hit the real network.\n- If the same recorded interaction must be replayed multiple times in one test, call `cassette.rewind()` or design the test to consume the interaction once.\n- Keep cassette files out of public repos unless you have filtered secrets and sensitive payload fields first.\n- Re-record cassettes when upstream APIs intentionally change response bodies or header shapes. Trying to loosen matchers everywhere usually creates brittle tests later.\n\n## Version-Sensitive Notes\n\n- PyPI currently publishes `8.1.1`, released on January 4, 2026.\n- The official docs root at `https://vcrpy.readthedocs.io/en/latest/` still renders as `8.0.0`. Treat the docs content as the current maintainer guide, but use PyPI metadata for the package version and Python floor.\n- The official 8.0.0 changelog notes two important upgrade constraints that still matter for 8.1.1 users:\n  - Python 3.9 support was dropped; current PyPI metadata requires Python `>=3.10`.\n  - `urllib3 < 2` is no longer supported.\n- The same 8.0.0 release rewrote `httpx` support to patch `httpcore`, which can affect existing test suites when upgrading from older VCR.py releases.\n- `drop_unused_requests` was added in 8.x. Use it if you want stricter cleanup of stale cassette interactions after test changes.\n\n## Official Sources\n\n- Documentation root: `https://vcrpy.readthedocs.io/en/latest/`\n- Configuration and advanced usage: `https://vcrpy.readthedocs.io/en/latest/advanced.html`\n- API reference: `https://vcrpy.readthedocs.io/en/latest/api.html`\n- Changelog: `https://vcrpy.readthedocs.io/en/latest/changelog.html`\n- PyPI metadata: `https://pypi.org/project/vcrpy/`\n"
  },
  {
    "path": "content/vercel/docs/platform/DOC.md",
    "content": "---\nname: platform\ndescription: \"Vercel SDK for deploying, managing, and interacting with the Vercel platform via its official JavaScript/TypeScript API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"1.16.0\"\n  updated-on: \"2026-03-01\"\n  source: maintainer\n  tags: \"vercel,deployment,platform,serverless,edge\"\n---\n\n# Vercel SDK JavaScript/TypeScript Coding Guidelines\n\nYou are a Vercel API coding expert. Help me with writing code using the Vercel API calling the official libraries and SDKs.\n\nYou can find the official SDK documentation and code samples here:\nhttps://vercel.com/docs/rest-api/reference/sdk\n\n## Golden Rule: Use the Correct and Current SDK\n\nAlways use the Vercel SDK to interact with the Vercel platform, which is the official library for all Vercel API interactions. Do not use legacy libraries or unofficial SDKs.\n\n- **Library Name:** Vercel SDK\n- **NPM Package:** `@vercel/sdk`\n- **Legacy Libraries**: Other unofficial packages are not recommended\n\n**Installation:**\n\n- **Correct:** `npm install @vercel/sdk`\n- **Correct:** `pnpm add @vercel/sdk`\n- **Correct:** `yarn add @vercel/sdk`\n\n**APIs and Usage:**\n\n- **Correct:** `import { Vercel } from '@vercel/sdk'`\n- **Correct:** `const vercel = new Vercel({ bearerToken: '...' })`\n- **Correct:** `await vercel.deployments.getDeployments(...)`\n- **Correct:** `await vercel.projects.updateProject(...)`\n- **Incorrect:** `VercelClient` or `VercelAPI`\n- **Incorrect:** Using unofficial REST API wrappers\n\n**Important Notes:**\n\n- This SDK is in beta, and there may be breaking changes between versions without a major version update\n- Recommend pinning usage to a specific package version\n- This is an ES Module (ESM) only package\n- CommonJS users should use `await import(\"@vercel/sdk\")`\n\n## Initialization and API Key\n\nThe `@vercel/sdk` library requires creating a `Vercel` instance for all API calls.\n\n- Always use `const vercel = new Vercel({ bearerToken: '...' })` to create an instance\n- Set the `VERCEL_TOKEN` or `VERCEL_BEARER_TOKEN` environment variable, which will be picked up automatically\n- Access tokens must be created in the Vercel dashboard with appropriate scopes\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\n// Uses environment variable if bearerToken not specified\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\n// Or pass the bearer token directly\n// const vercel = new Vercel({ bearerToken: 'your_token_here' });\n```\n\n### Creating Access Tokens\n\n1. Navigate to your Vercel account settings\n2. Go to the Tokens section\n3. Create a new token with the required scopes\n4. Optionally scope the token to specific teams\n5. Store the token securely as `VERCEL_TOKEN` environment variable\n\n```javascript\n// Example .env file\nVERCEL_TOKEN=your_access_token_here\n```\n\n### Common Authentication Errors\n\nPermission errors (403) may occur due to:\n\n- **Expired tokens** - Verify expiration dates in your dashboard\n- **Insufficient scope access** - Ensure the token has appropriate team or account-level permissions\n- **Feature unavailability** - Some features like AccessGroups require Enterprise plans\n\n## Working with Teams\n\nMany API operations require specifying a team. You can provide team information using either `teamId` or `slug`:\n\n```javascript\n// Using team ID\nconst result = await vercel.projects.getProjects({\n  teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n});\n\n// Using team slug\nconst result = await vercel.projects.getProjects({\n  slug: 'my-team-url-slug',\n});\n```\n\nTo find your team ID:\n\n```javascript\nconst teams = await vercel.teams.listTeams();\nconsole.log(teams.teams);\n```\n\n## Deployments\n\nThe Vercel SDK provides comprehensive deployment management capabilities.\n\n### Listing Deployments\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listDeployments() {\n  const result = await vercel.deployments.getDeployments({\n    limit: 10,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.deployments);\n}\n\nlistDeployments();\n```\n\n### Filter Deployments by Target\n\n```javascript\nconst result = await vercel.deployments.getDeployments({\n  limit: 20,\n  target: 'production',\n  teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n});\n\nconsole.log(result.deployments);\n```\n\n### Filter Deployments by Project\n\n```javascript\nconst result = await vercel.deployments.getDeployments({\n  projectId: 'prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB',\n  teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n});\n\nconsole.log(result.deployments);\n```\n\n### Get a Single Deployment\n\n```javascript\nasync function getDeployment(deploymentId) {\n  const result = await vercel.deployments.getDeployment({\n    idOrUrl: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetDeployment('dpl_abc123xyz');\n```\n\n### Cancel a Deployment\n\n```javascript\nasync function cancelDeployment(deploymentId) {\n  const result = await vercel.deployments.cancelDeployment({\n    id: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Deployment cancelled:', result);\n}\n\ncancelDeployment('dpl_abc123xyz');\n```\n\n### Delete a Deployment\n\n```javascript\nasync function deleteDeployment(deploymentId) {\n  const result = await vercel.deployments.deleteDeployment({\n    id: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Deployment deleted:', result);\n}\n\ndeleteDeployment('dpl_abc123xyz');\n```\n\n### Upload Files for Deployment\n\nBefore creating a deployment, you need to upload the required files:\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\nimport fs from 'fs';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function uploadFile() {\n  const fileContent = fs.readFileSync('./index.html', 'utf-8');\n\n  const result = await vercel.deployments.uploadFile({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      file: fileContent,\n    },\n  });\n\n  console.log('File hash:', result);\n  return result;\n}\n\nuploadFile();\n```\n\n### Create a Deployment\n\n```javascript\nasync function createDeployment() {\n  // First upload files (as shown above), then create deployment\n  const deployment = await vercel.deployments.createDeployment({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'my-project',\n      files: [\n        {\n          file: 'index.html',\n          sha: 'file_sha_from_upload',\n          size: 1234,\n        },\n      ],\n      target: 'production',\n    },\n  });\n\n  console.log('Deployment created:', deployment);\n}\n\ncreateDeployment();\n```\n\n### Get Deployment Files\n\n```javascript\nasync function getDeploymentFiles(deploymentId) {\n  const result = await vercel.deployments.getDeploymentFiles({\n    idOrUrl: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.files);\n}\n\ngetDeploymentFiles('dpl_abc123xyz');\n```\n\n### Get Deployment File Contents\n\n```javascript\nasync function getFileContents(deploymentId, fileId) {\n  const result = await vercel.deployments.getDeploymentFileContents({\n    idOrUrl: deploymentId,\n    fileId: fileId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetFileContents('dpl_abc123xyz', 'file_abc123');\n```\n\n### Get Deployment Events\n\n```javascript\nasync function getDeploymentEvents(deploymentId) {\n  const result = await vercel.deployments.getDeploymentEvents({\n    idOrUrl: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetDeploymentEvents('dpl_abc123xyz');\n```\n\n## Projects\n\nThe SDK provides comprehensive project management capabilities.\n\n### List Projects\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listProjects() {\n  const result = await vercel.projects.getProjects({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.projects);\n}\n\nlistProjects();\n```\n\n### Get a Single Project\n\n```javascript\nasync function getProject(projectName) {\n  const result = await vercel.projects.getProject({\n    idOrName: projectName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetProject('my-project');\n```\n\n### Create a Project\n\n```javascript\nasync function createProject() {\n  const result = await vercel.projects.createProject({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'my-new-project',\n      framework: 'nextjs',\n      buildCommand: 'npm run build',\n      outputDirectory: '.next',\n      installCommand: 'npm install',\n      devCommand: 'npm run dev',\n    },\n  });\n\n  console.log('Project created:', result);\n}\n\ncreateProject();\n```\n\n### Update a Project\n\n```javascript\nasync function updateProject(projectId) {\n  const result = await vercel.projects.updateProject({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'updated-project-name',\n      framework: 'nextjs',\n      buildCommand: 'pnpm build',\n    },\n  });\n\n  console.log('Project updated:', result);\n}\n\nupdateProject('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Delete a Project\n\n```javascript\nasync function deleteProject(projectId) {\n  const result = await vercel.projects.deleteProject({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Project deleted:', result);\n}\n\ndeleteProject('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Link Project to Git Repository\n\n```javascript\nasync function linkGitRepository(projectId) {\n  const result = await vercel.projects.updateProject({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      link: {\n        type: 'github',\n        repo: 'username/repository-name',\n        repoId: 123456789,\n        gitBranch: 'main',\n      },\n    },\n  });\n\n  console.log('Git repository linked:', result);\n}\n\nlinkGitRepository('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n## Domains\n\nManage custom domains for your projects.\n\n### Add a Domain to a Project\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function addDomain(projectId) {\n  const result = await vercel.projects.addProjectDomain({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'www.example.com',\n    },\n  });\n\n  console.log('Domain added:', result);\n}\n\naddDomain('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Add Domain with Redirect\n\n```javascript\nasync function addDomainWithRedirect(projectId) {\n  const result = await vercel.projects.addProjectDomain({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'www.example.com',\n      redirect: 'example.com',\n      redirectStatusCode: 308,\n    },\n  });\n\n  console.log('Domain added with redirect:', result);\n}\n\naddDomainWithRedirect('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Add Domain for Specific Git Branch\n\n```javascript\nasync function addBranchDomain(projectId) {\n  const result = await vercel.projects.addProjectDomain({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'staging.example.com',\n      gitBranch: 'staging',\n    },\n  });\n\n  console.log('Branch domain added:', result);\n}\n\naddBranchDomain('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Get Project Domains\n\n```javascript\nasync function getProjectDomains(projectId) {\n  const result = await vercel.projects.getProjectDomains({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.domains);\n}\n\ngetProjectDomains('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Update a Project Domain\n\n```javascript\nasync function updateProjectDomain(projectId, domainName) {\n  const result = await vercel.projects.updateProjectDomain({\n    idOrName: projectId,\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      redirect: 'new-redirect.com',\n      redirectStatusCode: 307,\n    },\n  });\n\n  console.log('Domain updated:', result);\n}\n\nupdateProjectDomain('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'www.example.com');\n```\n\n### Remove a Domain from a Project\n\n```javascript\nasync function removeDomain(projectId, domainName) {\n  const result = await vercel.projects.removeProjectDomain({\n    idOrName: projectId,\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Domain removed:', result);\n}\n\nremoveDomain('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'www.example.com');\n```\n\n### Verify a Project Domain\n\n```javascript\nasync function verifyDomain(projectId, domainName) {\n  const result = await vercel.projects.verifyProjectDomain({\n    idOrName: projectId,\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Domain verification result:', result);\n}\n\nverifyDomain('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'www.example.com');\n```\n\n### List All Domains\n\n```javascript\nasync function listDomains() {\n  const result = await vercel.domains.listDomains({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.domains);\n}\n\nlistDomains();\n```\n\n### Get Domain Information\n\n```javascript\nasync function getDomain(domainName) {\n  const result = await vercel.domains.getDomain({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetDomain('example.com');\n```\n\n### Buy a Domain\n\n```javascript\nasync function buyDomain() {\n  const result = await vercel.domains.createOrTransferDomain({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'example.com',\n    },\n  });\n\n  console.log('Domain purchased:', result);\n}\n\nbuyDomain();\n```\n\n### Delete a Domain\n\n```javascript\nasync function deleteDomain(domainName) {\n  const result = await vercel.domains.deleteDomain({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Domain deleted:', result);\n}\n\ndeleteDomain('example.com');\n```\n\n## DNS Records\n\nManage DNS records for your domains.\n\n### Get DNS Records\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function getDnsRecords(domainName) {\n  const result = await vercel.dns.getDnsRecords({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.records);\n}\n\ngetDnsRecords('example.com');\n```\n\n### Create a DNS Record\n\n```javascript\nasync function createDnsRecord(domainName) {\n  const result = await vercel.dns.createDnsRecord({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'subdomain',\n      type: 'A',\n      value: '192.0.2.1',\n      ttl: 60,\n    },\n  });\n\n  console.log('DNS record created:', result);\n}\n\ncreateDnsRecord('example.com');\n```\n\n### Create CNAME Record\n\n```javascript\nasync function createCnameRecord(domainName) {\n  const result = await vercel.dns.createDnsRecord({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'www',\n      type: 'CNAME',\n      value: 'example.com',\n      ttl: 60,\n    },\n  });\n\n  console.log('CNAME record created:', result);\n}\n\ncreateCnameRecord('example.com');\n```\n\n### Create MX Record\n\n```javascript\nasync function createMxRecord(domainName) {\n  const result = await vercel.dns.createDnsRecord({\n    domain: domainName,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: '@',\n      type: 'MX',\n      value: 'mail.example.com',\n      mxPriority: 10,\n      ttl: 60,\n    },\n  });\n\n  console.log('MX record created:', result);\n}\n\ncreateMxRecord('example.com');\n```\n\n### Update a DNS Record\n\n```javascript\nasync function updateDnsRecord(domainName, recordId) {\n  const result = await vercel.dns.patchDnsRecord({\n    domain: domainName,\n    recordId: recordId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      value: '192.0.2.2',\n      ttl: 120,\n    },\n  });\n\n  console.log('DNS record updated:', result);\n}\n\nupdateDnsRecord('example.com', 'rec_abc123');\n```\n\n### Delete a DNS Record\n\n```javascript\nasync function deleteDnsRecord(domainName, recordId) {\n  const result = await vercel.dns.deleteDnsRecord({\n    domain: domainName,\n    recordId: recordId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('DNS record deleted:', result);\n}\n\ndeleteDnsRecord('example.com', 'rec_abc123');\n```\n\n## Environment Variables\n\nManage environment variables for your projects.\n\n### Get Project Environment Variables\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function getEnvVars(projectId) {\n  const result = await vercel.projects.getProjectEnvs({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.envs);\n}\n\ngetEnvVars('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Create Environment Variables\n\n```javascript\nasync function createEnvVars(projectId) {\n  const result = await vercel.projects.createProjectEnv({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    upsert: 'true',\n    requestBody: [\n      {\n        key: 'API_KEY',\n        value: 'secret_value',\n        target: ['production', 'preview'],\n        type: 'encrypted',\n      },\n      {\n        key: 'DEBUG',\n        value: 'true',\n        target: ['development'],\n        type: 'plain',\n      },\n    ],\n  });\n\n  console.log('Environment variables created:', result);\n}\n\ncreateEnvVars('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Create Encrypted Environment Variable\n\n```javascript\nasync function createSecretEnvVar(projectId) {\n  const result = await vercel.projects.createProjectEnv({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: [\n      {\n        key: 'DATABASE_URL',\n        value: 'postgresql://user:pass@host:5432/db',\n        target: ['production'],\n        type: 'encrypted',\n      },\n    ],\n  });\n\n  console.log('Secret environment variable created:', result);\n}\n\ncreateSecretEnvVar('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Create Multi-Environment Variable\n\n```javascript\nasync function createMultiEnvVar(projectId) {\n  const result = await vercel.projects.createProjectEnv({\n    idOrName: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: [\n      {\n        key: 'API_URL',\n        value: 'https://api.example.com',\n        target: ['production', 'preview', 'development'],\n        type: 'plain',\n      },\n    ],\n  });\n\n  console.log('Multi-environment variable created:', result);\n}\n\ncreateMultiEnvVar('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Get a Single Environment Variable\n\n```javascript\nasync function getEnvVar(projectId, envId) {\n  const result = await vercel.projects.getProjectEnv({\n    idOrName: projectId,\n    id: envId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetEnvVar('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'env_abc123');\n```\n\n### Edit an Environment Variable\n\n```javascript\nasync function editEnvVar(projectId, envId) {\n  const result = await vercel.projects.editProjectEnv({\n    idOrName: projectId,\n    id: envId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      value: 'new_value',\n      target: ['production', 'preview'],\n    },\n  });\n\n  console.log('Environment variable updated:', result);\n}\n\neditEnvVar('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'env_abc123');\n```\n\n### Delete an Environment Variable\n\n```javascript\nasync function deleteEnvVar(projectId, envId) {\n  const result = await vercel.projects.deleteProjectEnv({\n    idOrName: projectId,\n    id: envId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Environment variable deleted:', result);\n}\n\ndeleteEnvVar('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB', 'env_abc123');\n```\n\n## Teams\n\nManage teams and team members.\n\n### List Teams\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listTeams() {\n  const result = await vercel.teams.listTeams();\n  console.log(result.teams);\n}\n\nlistTeams();\n```\n\n### Get Team Information\n\n```javascript\nasync function getTeam(teamId) {\n  const result = await vercel.teams.getTeam({\n    teamId: teamId,\n  });\n\n  console.log(result);\n}\n\ngetTeam('team_1a2b3c4d5e6f7g8h9i0j1k2l');\n```\n\n### Create a Team\n\n```javascript\nasync function createTeam() {\n  const result = await vercel.teams.createTeam({\n    requestBody: {\n      name: 'My New Team',\n      slug: 'my-new-team',\n    },\n  });\n\n  console.log('Team created:', result);\n}\n\ncreateTeam();\n```\n\n### Update Team Settings\n\n```javascript\nasync function updateTeam(teamId) {\n  const result = await vercel.teams.updateTeam({\n    teamId: teamId,\n    requestBody: {\n      name: 'Updated Team Name',\n      description: 'This is my team description',\n    },\n  });\n\n  console.log('Team updated:', result);\n}\n\nupdateTeam('team_1a2b3c4d5e6f7g8h9i0j1k2l');\n```\n\n### Delete a Team\n\n```javascript\nasync function deleteTeam(teamId) {\n  const result = await vercel.teams.deleteTeam({\n    teamId: teamId,\n  });\n\n  console.log('Team deleted:', result);\n}\n\ndeleteTeam('team_1a2b3c4d5e6f7g8h9i0j1k2l');\n```\n\n### List Team Members\n\n```javascript\nasync function listTeamMembers(teamId) {\n  const result = await vercel.teams.getTeamMembers({\n    teamId: teamId,\n  });\n\n  console.log(result.members);\n}\n\nlistTeamMembers('team_1a2b3c4d5e6f7g8h9i0j1k2l');\n```\n\n### Invite Member to Team\n\n```javascript\nasync function inviteTeamMember(teamId) {\n  const result = await vercel.teams.inviteUserToTeam({\n    teamId: teamId,\n    requestBody: {\n      email: 'user@example.com',\n      role: 'MEMBER',\n    },\n  });\n\n  console.log('Team member invited:', result);\n}\n\ninviteTeamMember('team_1a2b3c4d5e6f7g8h9i0j1k2l');\n```\n\n### Update Team Member Role\n\n```javascript\nasync function updateMemberRole(teamId, memberId) {\n  const result = await vercel.teams.updateTeamMember({\n    teamId: teamId,\n    memberId: memberId,\n    requestBody: {\n      role: 'OWNER',\n    },\n  });\n\n  console.log('Member role updated:', result);\n}\n\nupdateMemberRole('team_1a2b3c4d5e6f7g8h9i0j1k2l', 'member_abc123');\n```\n\n### Remove Team Member\n\n```javascript\nasync function removeTeamMember(teamId, memberId) {\n  const result = await vercel.teams.deleteTeamMember({\n    teamId: teamId,\n    memberId: memberId,\n  });\n\n  console.log('Member removed:', result);\n}\n\nremoveTeamMember('team_1a2b3c4d5e6f7g8h9i0j1k2l', 'member_abc123');\n```\n\n## Access Groups (Enterprise)\n\nAccess Groups is an Enterprise-only feature for advanced team management.\n\n### List Access Groups\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listAccessGroups() {\n  const result = await vercel.accessGroups.listAccessGroups({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.accessGroups);\n}\n\nlistAccessGroups();\n```\n\n### Filter Access Groups by Project\n\n```javascript\nasync function getProjectAccessGroups(projectId) {\n  const result = await vercel.accessGroups.listAccessGroups({\n    projectId: projectId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.accessGroups);\n}\n\ngetProjectAccessGroups('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Search Access Groups\n\n```javascript\nasync function searchAccessGroups(searchTerm) {\n  const result = await vercel.accessGroups.listAccessGroups({\n    search: searchTerm,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.accessGroups);\n}\n\nsearchAccessGroups('engineering');\n```\n\n### Create Access Group\n\n```javascript\nasync function createAccessGroup() {\n  const result = await vercel.accessGroups.createAccessGroup({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'Engineering Team',\n      projects: ['prj_abc123', 'prj_def456'],\n      members: ['member_123', 'member_456'],\n    },\n  });\n\n  console.log('Access group created:', result);\n}\n\ncreateAccessGroup();\n```\n\n### Update Access Group\n\n```javascript\nasync function updateAccessGroup(groupId) {\n  const result = await vercel.accessGroups.updateAccessGroup({\n    idOrName: groupId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'Updated Engineering Team',\n      projects: ['prj_abc123', 'prj_def456', 'prj_ghi789'],\n    },\n  });\n\n  console.log('Access group updated:', result);\n}\n\nupdateAccessGroup('ag_abc123');\n```\n\n### Delete Access Group\n\n```javascript\nasync function deleteAccessGroup(groupId) {\n  const result = await vercel.accessGroups.deleteAccessGroup({\n    idOrName: groupId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Access group deleted:', result);\n}\n\ndeleteAccessGroup('ag_abc123');\n```\n\n## Webhooks\n\nSet up webhooks to receive notifications about events in your Vercel projects.\n\n### List Webhooks\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listWebhooks() {\n  const result = await vercel.webhooks.listWebhooks({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.webhooks);\n}\n\nlistWebhooks();\n```\n\n### Create a Webhook\n\n```javascript\nasync function createWebhook() {\n  const result = await vercel.webhooks.createWebhook({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      url: 'https://example.com/webhook',\n      events: ['deployment.created', 'deployment.succeeded'],\n    },\n  });\n\n  console.log('Webhook created:', result);\n}\n\ncreateWebhook();\n```\n\n### Create Project-Specific Webhook\n\n```javascript\nasync function createProjectWebhook(projectId) {\n  const result = await vercel.webhooks.createWebhook({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      url: 'https://example.com/webhook',\n      events: ['deployment.created', 'deployment.succeeded', 'deployment.failed'],\n      projectIds: [projectId],\n    },\n  });\n\n  console.log('Project webhook created:', result);\n}\n\ncreateProjectWebhook('prj_12HKQaOmR5t5Uy6vdcQsNIiZgHGB');\n```\n\n### Get Webhook Details\n\n```javascript\nasync function getWebhook(webhookId) {\n  const result = await vercel.webhooks.getWebhook({\n    id: webhookId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetWebhook('hook_abc123');\n```\n\n### Delete a Webhook\n\n```javascript\nasync function deleteWebhook(webhookId) {\n  const result = await vercel.webhooks.deleteWebhook({\n    id: webhookId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Webhook deleted:', result);\n}\n\ndeleteWebhook('hook_abc123');\n```\n\n## Artifacts (Remote Caching)\n\nManage artifact caching for build optimization.\n\n### Record Artifact Cache Events\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function recordCacheEvents() {\n  const result = await vercel.artifacts.recordEvents({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: [\n      {\n        sessionId: 'session_abc123',\n        source: 'REMOTE',\n        event: 'HIT',\n        hash: 'hash_def456',\n        duration: 123,\n      },\n      {\n        sessionId: 'session_abc123',\n        source: 'LOCAL',\n        event: 'MISS',\n        hash: 'hash_ghi789',\n        duration: 456,\n      },\n    ],\n  });\n\n  console.log('Cache events recorded:', result);\n}\n\nrecordCacheEvents();\n```\n\n### Get Artifact Status\n\n```javascript\nasync function getArtifactStatus(hash) {\n  const result = await vercel.artifacts.artifactExists({\n    hash: hash,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Artifact exists:', result);\n}\n\ngetArtifactStatus('hash_abc123');\n```\n\n### Upload Artifact\n\n```javascript\nimport fs from 'fs';\n\nasync function uploadArtifact() {\n  const fileContent = fs.readFileSync('./artifact.tar.gz');\n\n  const result = await vercel.artifacts.uploadArtifact({\n    hash: 'hash_abc123',\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: fileContent,\n  });\n\n  console.log('Artifact uploaded:', result);\n}\n\nuploadArtifact();\n```\n\n### Download Artifact\n\n```javascript\nasync function downloadArtifact(hash) {\n  const result = await vercel.artifacts.downloadArtifact({\n    hash: hash,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Artifact downloaded:', result);\n}\n\ndownloadArtifact('hash_abc123');\n```\n\n## Checks\n\nManage deployment checks and integration actions.\n\n### Get Deployment Checks\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function getDeploymentChecks(deploymentId) {\n  const result = await vercel.checks.listChecks({\n    deploymentId: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.checks);\n}\n\ngetDeploymentChecks('dpl_abc123xyz');\n```\n\n### Create a Check\n\n```javascript\nasync function createCheck(deploymentId) {\n  const result = await vercel.checks.createCheck({\n    deploymentId: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'Security Scan',\n      path: '/',\n      status: 'running',\n      blocking: true,\n    },\n  });\n\n  console.log('Check created:', result);\n}\n\ncreateCheck('dpl_abc123xyz');\n```\n\n### Update a Check\n\n```javascript\nasync function updateCheck(deploymentId, checkId) {\n  const result = await vercel.checks.updateCheck({\n    deploymentId: deploymentId,\n    checkId: checkId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      status: 'completed',\n      conclusion: 'succeeded',\n      output: {\n        summary: 'Security scan passed',\n      },\n    },\n  });\n\n  console.log('Check updated:', result);\n}\n\nupdateCheck('dpl_abc123xyz', 'check_abc123');\n```\n\n### Rerequest a Check\n\n```javascript\nasync function rerequestCheck(deploymentId, checkId) {\n  const result = await vercel.checks.rerequestCheck({\n    deploymentId: deploymentId,\n    checkId: checkId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Check rerequested:', result);\n}\n\nrerequestCheck('dpl_abc123xyz', 'check_abc123');\n```\n\n## Logs\n\nAccess deployment and build logs.\n\n### Get Deployment Logs\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function getDeploymentLogs(deploymentId) {\n  const result = await vercel.logs.getDeploymentLogs({\n    id: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetDeploymentLogs('dpl_abc123xyz');\n```\n\n### Get Build Logs\n\n```javascript\nasync function getBuildLogs(deploymentId) {\n  const result = await vercel.logs.getDeploymentLogs({\n    id: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    direction: 'forward',\n    limit: 100,\n  });\n\n  console.log(result);\n}\n\ngetBuildLogs('dpl_abc123xyz');\n```\n\n### Filter Logs by Time\n\n```javascript\nasync function getLogsInTimeRange(deploymentId, since, until) {\n  const result = await vercel.logs.getDeploymentLogs({\n    id: deploymentId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    since: since,\n    until: until,\n  });\n\n  console.log(result);\n}\n\ngetLogsInTimeRange('dpl_abc123xyz', 1609459200000, 1609545600000);\n```\n\n## Aliases\n\nManage deployment aliases.\n\n### List Aliases\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listAliases() {\n  const result = await vercel.aliases.listAliases({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.aliases);\n}\n\nlistAliases();\n```\n\n### Assign Alias to Deployment\n\n```javascript\nasync function assignAlias(deploymentId, alias) {\n  const result = await vercel.aliases.assignAlias({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      alias: alias,\n      deploymentId: deploymentId,\n    },\n  });\n\n  console.log('Alias assigned:', result);\n}\n\nassignAlias('dpl_abc123xyz', 'my-app.example.com');\n```\n\n### Get Alias Information\n\n```javascript\nasync function getAlias(aliasId) {\n  const result = await vercel.aliases.getAlias({\n    id: aliasId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetAlias('alias_abc123');\n```\n\n### Delete an Alias\n\n```javascript\nasync function deleteAlias(aliasId) {\n  const result = await vercel.aliases.deleteAlias({\n    id: aliasId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Alias deleted:', result);\n}\n\ndeleteAlias('alias_abc123');\n```\n\n## Authentication\n\nManage authentication tokens and settings.\n\n### Get Current User\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function getCurrentUser() {\n  const result = await vercel.user.getAuthUser();\n  console.log(result);\n}\n\ngetCurrentUser();\n```\n\n### List Access Tokens\n\n```javascript\nasync function listTokens() {\n  const result = await vercel.authentication.listTokens({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.tokens);\n}\n\nlistTokens();\n```\n\n### Delete an Access Token\n\n```javascript\nasync function deleteToken(tokenId) {\n  const result = await vercel.authentication.deleteToken({\n    id: tokenId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Token deleted:', result);\n}\n\ndeleteToken('token_abc123');\n```\n\n## Edge Config\n\nManage Edge Config stores for ultra-low latency global data.\n\n### List Edge Configs\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function listEdgeConfigs() {\n  const result = await vercel.edgeConfig.getEdgeConfigs({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result.edgeConfigs);\n}\n\nlistEdgeConfigs();\n```\n\n### Create Edge Config\n\n```javascript\nasync function createEdgeConfig() {\n  const result = await vercel.edgeConfig.createEdgeConfig({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      name: 'my-edge-config',\n    },\n  });\n\n  console.log('Edge Config created:', result);\n}\n\ncreateEdgeConfig();\n```\n\n### Get Edge Config\n\n```javascript\nasync function getEdgeConfig(edgeConfigId) {\n  const result = await vercel.edgeConfig.getEdgeConfig({\n    edgeConfigId: edgeConfigId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log(result);\n}\n\ngetEdgeConfig('ecfg_abc123');\n```\n\n### Update Edge Config Items\n\n```javascript\nasync function updateEdgeConfigItems(edgeConfigId) {\n  const result = await vercel.edgeConfig.updateEdgeConfigItems({\n    edgeConfigId: edgeConfigId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    requestBody: {\n      items: [\n        {\n          operation: 'upsert',\n          key: 'feature_flag_new_ui',\n          value: true,\n        },\n        {\n          operation: 'upsert',\n          key: 'welcome_message',\n          value: 'Hello from Edge Config!',\n        },\n      ],\n    },\n  });\n\n  console.log('Edge Config items updated:', result);\n}\n\nupdateEdgeConfigItems('ecfg_abc123');\n```\n\n### Delete Edge Config\n\n```javascript\nasync function deleteEdgeConfig(edgeConfigId) {\n  const result = await vercel.edgeConfig.deleteEdgeConfig({\n    edgeConfigId: edgeConfigId,\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n\n  console.log('Edge Config deleted:', result);\n}\n\ndeleteEdgeConfig('ecfg_abc123');\n```\n\n## Error Handling\n\nThe SDK provides comprehensive error handling capabilities.\n\n### Basic Error Handling\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\ntry {\n  const result = await vercel.projects.getProject({\n    idOrName: 'my-project',\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n  });\n  console.log(result);\n} catch (error) {\n  if (error.statusCode === 404) {\n    console.error('Project not found');\n  } else if (error.statusCode === 403) {\n    console.error('Permission denied - check token scopes');\n  } else if (error.statusCode === 401) {\n    console.error('Authentication failed - check your token');\n  } else {\n    console.error('Error:', error.message);\n  }\n}\n```\n\n### Advanced Error Handling\n\n```javascript\nasync function safeApiCall() {\n  try {\n    const result = await vercel.deployments.getDeployments({\n      teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    });\n    return result;\n  } catch (error) {\n    if (error.statusCode >= 500) {\n      console.error('Server error - retry later');\n    } else if (error.statusCode === 429) {\n      console.error('Rate limit exceeded - wait before retrying');\n    } else if (error.statusCode >= 400 && error.statusCode < 500) {\n      console.error('Client error:', error.message);\n    }\n    throw error;\n  }\n}\n```\n\n## Advanced Configuration\n\n### Custom HTTP Client Options\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n  serverURL: 'https://api.vercel.com',\n  retryConfig: {\n    strategy: 'backoff',\n    backoff: {\n      initialInterval: 500,\n      maxInterval: 60000,\n      exponent: 1.5,\n      maxElapsedTime: 3600000,\n    },\n    retryConnectionErrors: true,\n  },\n});\n```\n\n### Setting Timeouts\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n  timeoutMs: 30000, // 30 seconds\n});\n```\n\n### Debug Mode\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n  debugLogger: {\n    log: (message) => console.log('[DEBUG]', message),\n  },\n});\n```\n\n## Pagination\n\nMany API endpoints support pagination for handling large result sets.\n\n### Manual Pagination\n\n```javascript\nasync function getAllProjects() {\n  let allProjects = [];\n  let limit = 20;\n  let until = undefined;\n\n  while (true) {\n    const result = await vercel.projects.getProjects({\n      teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n      limit: limit,\n      until: until,\n    });\n\n    allProjects.push(...result.projects);\n\n    if (!result.pagination || !result.pagination.next) {\n      break;\n    }\n\n    until = result.pagination.next;\n  }\n\n  return allProjects;\n}\n```\n\n### Pagination with Limit\n\n```javascript\nasync function getRecentDeployments(maxResults = 100) {\n  const result = await vercel.deployments.getDeployments({\n    teamId: 'team_1a2b3c4d5e6f7g8h9i0j1k2l',\n    limit: Math.min(maxResults, 100),\n  });\n\n  return result.deployments.slice(0, maxResults);\n}\n```\n\n## Complete Example: Deploy a Project\n\nHere's a complete example showing how to create a project, upload files, and create a deployment:\n\n```javascript\nimport { Vercel } from '@vercel/sdk';\nimport fs from 'fs';\nimport path from 'path';\n\nconst vercel = new Vercel({\n  bearerToken: process.env.VERCEL_TOKEN,\n});\n\nasync function deployProject() {\n  try {\n    // 1. Create a project\n    const project = await vercel.projects.createProject({\n      teamId: process.env.VERCEL_TEAM_ID,\n      requestBody: {\n        name: 'my-app',\n        framework: 'nextjs',\n      },\n    });\n    console.log('Project created:', project.id);\n\n    // 2. Upload files\n    const files = [\n      { path: 'index.html', content: '<html><body>Hello World</body></html>' },\n      { path: 'package.json', content: '{\"name\":\"my-app\",\"version\":\"1.0.0\"}' },\n    ];\n\n    const uploadedFiles = [];\n    for (const file of files) {\n      const hash = await vercel.deployments.uploadFile({\n        teamId: process.env.VERCEL_TEAM_ID,\n        requestBody: {\n          file: file.content,\n        },\n      });\n      uploadedFiles.push({\n        file: file.path,\n        sha: hash,\n        size: file.content.length,\n      });\n    }\n    console.log('Files uploaded');\n\n    // 3. Create deployment\n    const deployment = await vercel.deployments.createDeployment({\n      teamId: process.env.VERCEL_TEAM_ID,\n      requestBody: {\n        name: 'my-app',\n        files: uploadedFiles,\n        projectSettings: {\n          framework: 'nextjs',\n        },\n        target: 'production',\n      },\n    });\n    console.log('Deployment created:', deployment.url);\n\n    // 4. Wait for deployment to complete\n    let status = 'BUILDING';\n    while (status === 'BUILDING' || status === 'QUEUED') {\n      await new Promise((resolve) => setTimeout(resolve, 5000));\n      const deploymentStatus = await vercel.deployments.getDeployment({\n        idOrUrl: deployment.id,\n        teamId: process.env.VERCEL_TEAM_ID,\n      });\n      status = deploymentStatus.readyState;\n      console.log('Deployment status:', status);\n    }\n\n    if (status === 'READY') {\n      console.log('Deployment successful:', `https://${deployment.url}`);\n    } else {\n      console.error('Deployment failed:', status);\n    }\n  } catch (error) {\n    console.error('Error:', error.message);\n  }\n}\n\ndeployProject();\n```\n\n## Useful Links\n\n- Documentation: https://vercel.com/docs\n- API Reference: https://vercel.com/docs/rest-api/reference\n- SDK Documentation: https://vercel.com/docs/rest-api/reference/sdk\n- GitHub Repository: https://github.com/vercel/sdk\n- Support: https://vercel.com/support\n"
  },
  {
    "path": "content/vine/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"vine Python package guide for promises, errbacks, barriers, and promise-aware callback utilities\"\nmetadata:\n  languages: \"python\"\n  versions: \"5.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"vine,python,promise,deferred,callbacks,celery\"\n---\n\n# vine Python Package Guide\n\n## Golden Rule\n\nUse `vine` as a small in-process promise/deferred library. It helps you chain callbacks, attach errbacks, and adapt callback-style code into promise-aware flows. It is not an event loop, network client, or task queue by itself, so there are no service credentials or client objects to configure.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"vine==5.1.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"vine==5.1.0\"\npoetry add \"vine==5.1.0\"\n```\n\nPyPI metadata for `5.1.0` requires Python `>=3.6`.\n\n## Setup And Import Patterns\n\n`vine` is a local utility package:\n\n- Environment variables: none\n- Authentication: none\n- Client initialization: none\n\nImport the helpers you actually use:\n\n```python\nfrom vine import barrier, maybe_promise, promise, transform, wrap\n```\n\nThe main object is `promise`. You resolve it by calling it like a function, and you reject it with `.throw(...)`.\n\n## Core Workflows\n\n### Resolve a promise and chain callbacks\n\n`promise(fun)` wraps a callback. `.then(...)` attaches the next callback and returns another promise in the chain.\n\n```python\nfrom vine import promise\n\ndef load_order(order_id: str) -> dict:\n    return {\"id\": order_id, \"status\": \"packed\"}\n\ndef notify(order: dict) -> None:\n    print(f\"order {order['id']} is {order['status']}\")\n\npipeline = promise(load_order).then(notify)\npipeline(\"A-100\")\n```\n\nFor callback registration without an initial function, start with `promise()`:\n\n```python\nfrom vine import promise\n\nready = promise()\nready.then(lambda value: print(f\"received: {value}\"))\nready(\"shipment-ready\")\n```\n\n### Attach errbacks and reject explicitly\n\nUse `on_error=` with `.then(...)` for the common success/error split. Reject a promise by calling `.throw(...)`.\n\n```python\nfrom vine import promise\n\ndef handle_success(value: str) -> None:\n    print(f\"ok: {value}\")\n\ndef handle_error(exc_type, exc, tb) -> None:\n    print(f\"failed: {exc!r}\")\n\nstep = promise().then(handle_success, on_error=handle_error)\n\nstep(\"done\")\nstep.throw(ValueError(\"bad input\"))\n```\n\nInside an `except` block, `throw()` with no arguments forwards the current exception:\n\n```python\nfrom vine import promise\n\nresult = promise().then(\n    lambda value: print(f\"parsed: {value}\"),\n    on_error=lambda exc_type, exc, tb: print(f\"error: {exc!r}\"),\n)\n\ntry:\n    value = int(\"not-a-number\")\nexcept ValueError:\n    result.throw()\nelse:\n    result(value)\n```\n\n### Normalize plain values and thenables with `maybe_promise`\n\n`maybe_promise(obj)` returns `obj` unchanged when it is already promise-like, otherwise it wraps the value in a ready promise. Use it when a function may return either a direct value or a promise.\n\n```python\nfrom vine import maybe_promise, promise\n\ncached_value = {\"source\": \"cache\"}\n\npending = promise()\npending({\"source\": \"backend\"})\n\nmaybe_promise(cached_value).then(print)\nmaybe_promise(pending).then(print)\n```\n\n### Adapt callback-style code with `wrap`\n\n`wrap(p)` returns a function that resolves `p` when called normally and rejects `p` when you call `.throw()` on the wrapper.\n\n```python\nfrom vine import promise, wrap\n\nresult = promise().then(\n    lambda value: print(f\"value: {value}\"),\n    on_error=lambda exc_type, exc, tb: print(f\"failed: {exc!r}\"),\n)\n\ndone = wrap(result)\n\ntry:\n    done(int(\"42\"))\nexcept ValueError:\n    done.throw()\n```\n\nThis is useful when integrating `vine` into code that already has separate success and exception paths.\n\n### Derive a second promise with `transform`\n\nUse `transform(p, callback)` when you want a new promise whose value is computed from another promise.\n\n```python\nfrom vine import promise, transform\n\nsource = promise()\nuppercase = transform(source, lambda text: text.upper())\n\nuppercase.then(print)\nsource(\"ready\")\n```\n\n### Wait for multiple promises with `barrier`\n\n`barrier()` lets you join several promises and run one callback when all of them are resolved. If you create an empty barrier and add promises later, call `.finalize()` after registration.\n\n```python\nfrom vine import barrier, promise\n\nfirst = promise()\nsecond = promise()\n\njoined = barrier([first, second])\njoined.then(lambda values: print(f\"all done: {values}\"))\n\nfirst(\"alpha\")\nsecond(\"beta\")\n```\n\n## Configuration Notes\n\n- Use `weak=True` when you attach bound methods from long-lived objects and you do not want the promise chain to keep those instances alive.\n- `promise.cancel()` stops future callback dispatch for that promise chain; use it when a result should no longer be delivered.\n- `vine` is synchronous at the library level. It can model deferred completion, but it does not schedule work for you.\n\n## Common Pitfalls\n\n- Calling `promise()` resolves it. New users often expect a separate `.set()` or `.resolve()` method.\n- `throw()` is the rejection path. If you catch an exception and then call the promise normally, errbacks will not run.\n- Errbacks run with exception info shaped like `sys.exc_info()`, so handlers should accept `(exc_type, exc, tb)` or `*exc_info`.\n- `maybe_promise()` only normalizes values into promise-like objects; it does not execute background work.\n- `barrier()` created with no initial promises is immediately ready unless you add promises and call `.finalize()`.\n- The public Read the Docs pages are older than the current PyPI release. Keep generated code close to the stable top-level helpers in this guide and confirm unusual internals against the repository source.\n\n## Version-Sensitive Notes For `5.1.0`\n\n- PyPI lists `vine 5.1.0` as the current release as of March 13, 2026.\n- The package metadata for `5.1.0` requires Python `>=3.6`.\n- The official API reference site still serves older `0.9.0` pages, but the core top-level helpers documented there, such as `promise`, `maybe_promise`, `wrap`, `transform`, and `barrier`, are also present in the maintained repository source.\n\n## Official Sources\n\n- Repository: https://github.com/celery/vine\n- PyPI package page: https://pypi.org/project/vine/\n- PyPI release page for `5.1.0`: https://pypi.org/project/vine/5.1.0/\n- API reference: https://vine.readthedocs.io/en/latest/reference/vine.promises.html\n- Top-level API index: https://vine.readthedocs.io/en/latest/internals/reference/vine.html\n- Promise source: https://github.com/celery/vine/blob/master/vine/promises.py\n- Barrier source: https://github.com/celery/vine/blob/master/vine/synchronization.py\n"
  },
  {
    "path": "content/virtualenv/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"virtualenv package guide for creating isolated Python environments with the official virtualenv docs\"\nmetadata:\n  languages: \"python\"\n  versions: \"21.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"virtualenv,python,packaging,environments,venv,pip\"\n---\n\n# virtualenv Python Package Guide\n\n## Golden Rule\n\nUse `virtualenv` when you need a fast, configurable environment creator beyond the stdlib `venv` defaults, and create environments against an explicit interpreter whenever the Python version matters.\n\nFor this entry, the version used here `21.2.0` matches the live upstream release on PyPI dated March 9, 2026.\n\n## Install\n\nPreferred install via `pipx` so the tool stays isolated from project environments:\n\n```bash\npipx install virtualenv\nvirtualenv --help\n```\n\nPin the exact package version when reproducibility matters:\n\n```bash\npython -m pip install --user \"virtualenv==21.2.0\"\npython -m virtualenv --help\n```\n\nUse the published zipapp if you need a no-install path:\n\n```bash\ncurl -LO https://bootstrap.pypa.io/virtualenv.pyz\npython virtualenv.pyz --help\n```\n\n## Create Environments\n\nBasic creation:\n\n```bash\npython -m virtualenv .venv\n```\n\nUse an explicit interpreter path for stable builds:\n\n```bash\n/opt/python/3.12/bin/python -m virtualenv .venv\n```\n\nUse interpreter discovery rules when you want `virtualenv` to search:\n\n```bash\nvirtualenv --python=3.12 .venv\nvirtualenv --python=\">=3.12\" .venv\nvirtualenv --python=cpython3.12-64-arm64 .venv\n```\n\nIf your machine has version-manager shims or multiple candidates, use `--try-first-with` as a hint before the normal search:\n\n```bash\nvirtualenv --python=3.12 --try-first-with ~/.pyenv/versions/3.12.9/bin/python .venv\n```\n\n## Activate Or Use Directly\n\nActivation is optional. You can always call the environment's binaries directly.\n\nPOSIX shells:\n\n```bash\nsource .venv/bin/activate\npython --version\npython -m pip install -U pip\ndeactivate\n```\n\nWindows `cmd.exe`:\n\n```bat\n.\\.venv\\Scripts\\activate\npython --version\n```\n\nPowerShell:\n\n```powershell\n.\\.venv\\Scripts\\Activate.ps1\n```\n\nIf PowerShell blocks activation scripts, the upstream docs recommend:\n\n```powershell\nSet-ExecutionPolicy RemoteSigned\n```\n\n## Core Options You Will Actually Use\n\nCreate an env that can still see global packages:\n\n```bash\nvirtualenv --system-site-packages .venv\n```\n\nForce copies instead of symlinks:\n\n```bash\nvirtualenv --copies .venv\n```\n\nBlow away and recreate an existing destination:\n\n```bash\nvirtualenv --clear .venv\n```\n\nSkip VCS ignore generation:\n\n```bash\nvirtualenv --no-vcs-ignore .venv\n```\n\nCreate a bare environment without seeded package installers:\n\n```bash\nvirtualenv --no-seed .venv\n```\n\nControl which activation scripts are generated and the prompt prefix:\n\n```bash\nvirtualenv --activators bash,powershell --prompt . .venv\n```\n\nThe default activators cover `bash`, `batch`, `cshell`, `fish`, `nushell`, `powershell`, and `python`.\n\n## Seeding, Caches, And Offline-ish Setups\n\n`virtualenv` creates environments in two phases:\n\n1. Discover the base interpreter.\n2. Build the environment, seed packages, install activators, and create VCS ignore files.\n\nFor seeding, the default method is `app-data`, which caches install images and makes repeat environment creation much faster than invoking `pip` from scratch every time.\n\nUseful flags:\n\n```bash\nvirtualenv --download .venv\nvirtualenv --no-periodic-update .venv\nvirtualenv --extra-search-dir /srv/wheels --extra-search-dir /opt/wheels .venv\nvirtualenv --upgrade-embed-wheels\n```\n\nImportant defaults in current docs:\n\n- `--seeder app-data`\n- `--no-download` is the default\n- `--pip bundle`\n- `--setuptools none`\n\nThat last point matters on modern Python: upstream docs say `setuptools` is disabled by default for Python 3.12+ environments, and `wheel` is only installed by default on Python 3.8.\n\n## Config And Authentication\n\nThere is no service authentication layer in `virtualenv`. Configuration is local: CLI flags, environment variables, and `virtualenv.ini`.\n\nThe docs say `virtualenv` looks for a standard `virtualenv.ini` unless `VIRTUALENV_CONFIG_FILE` overrides the path. Run `virtualenv --help` to print the active config-file location.\n\nUseful environment variables:\n\n```bash\nexport VIRTUALENV_PYTHON=/opt/python-3.12/bin/python\nexport VIRTUALENV_EXTRA_SEARCH_DIR=/srv/wheels,/opt/wheels\nexport VIRTUALENV_OVERRIDE_APP_DATA=/var/cache/virtualenv\n```\n\nNotes:\n\n- Environment variable names mirror long CLI options with a `VIRTUALENV_` prefix.\n- Options that accept multiple values, such as `VIRTUALENV_PYTHON` and `VIRTUALENV_EXTRA_SEARCH_DIR`, can use comma-separated or newline-separated values.\n- The app-data directory is the seed cache. Override it when you need a shared or deterministic cache location in CI or managed build images.\n\n## Use From Python\n\nThe supported Python API is CLI-shaped. Use `cli_run()` to create an environment and `session_via_cli()` if you only need the resolved session data.\n\n```python\nfrom virtualenv import cli_run, session_via_cli\n\nsession = cli_run([\"--python=3.12\", \".venv\"])\nprint(session.interpreter)\n\npreview = session_via_cli([\"--python=3.12\", \".venv\"])\nprint(preview.creator)\n```\n\nThe returned session object is documented as experimental. Treat it as inspection data, not a stable long-term interface.\n\n## Common Pitfalls\n\n- Do not rely on a generic launcher like `python3 -m virtualenv .venv` if your system updates `/usr/bin/python3` under you. Use an exact interpreter path or an explicit specifier.\n- Activation is not required. In automation, calling `.venv/bin/python` or `.venv/Scripts/python.exe` is usually cleaner and less shell-dependent.\n- `--system-site-packages` breaks isolation by design. Only use it when your toolchain truly expects global packages.\n- If builds need internet-free seeding, populate wheel locations up front and use `--extra-search-dir`; `--download` is off by default.\n- PowerShell activation can fail because of execution policy, not because the environment is broken.\n- If your tooling imports `virtualenv.discovery.*` internals directly, that is now a migration target, not a stable contract.\n\n## Version-Sensitive Notes For 21.2.0\n\n- `21.2.0` was released on March 9, 2026.\n- `21.2.0` fixes `--no-vcs-ignore` being ignored on the subprocess `venv` path for Python 3.13+.\n- `21.2.0` fixes bash activation relocation fallback by using `BASH_SOURCE[0]`, which matters if the activate script is sourced from a different working directory.\n- `21.1.0` adds inline type annotations and ships `py.typed`, so static type checkers now recognize `virtualenv` as a typed package.\n- `21.0.0` extracts Python discovery into the separate `python-discovery` dependency. If older code imports `virtualenv.discovery.py_info.PythonInfo` or similar internals, switch to `python_discovery` instead of depending on compatibility shims.\n- `20.38.0` moved app-data storage to the OS cache directory and migrates existing cache data on first use. If your CI or container image pinned the old cache path, update that assumption.\n\n## Official Sources\n\n- Stable docs: https://virtualenv.pypa.io/en/stable/\n- Installation: https://virtualenv.pypa.io/en/stable/installation.html\n- User guide: https://virtualenv.pypa.io/en/stable/user_guide.html\n- CLI reference: https://virtualenv.pypa.io/en/stable/cli_interface.html\n- Release history: https://virtualenv.pypa.io/en/stable/changelog.html\n- PyPI release page: https://pypi.org/project/virtualenv/21.2.0/\n"
  },
  {
    "path": "content/vite/docs/vite/javascript/DOC.md",
    "content": "---\nname: vite\ndescription: \"Vite build tool for JavaScript projects, including local development, production builds, environment handling, configuration, and the Node.js API.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.3.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"vite,javascript,build,dev-server,bundler,frontend\"\n---\n\n# Vite JavaScript Guide\n\n## Install\n\nVite is local build tooling for frontend apps and custom dev/build pipelines. It does not require API keys or service authentication.\n\n`vite@7.3.1` requires Node.js `^20.19.0 || >=22.12.0`.\n\nInstall it as a development dependency:\n\n```bash\nnpm install --save-dev vite\nnpx vite --version\n```\n\nAdd the standard scripts to `package.json`:\n\n```json\n{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\"\n  }\n}\n```\n\nIf your package is not using ESM, keep the scripts the same and name the config file `vite.config.mjs` instead of `vite.config.js`.\n\n## Minimal Project Setup\n\nVite serves an HTML entry file in development and uses it as the build entry by default.\n\n`index.html`\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vite App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n```\n\n`src/main.js`\n\n```js\nconst app = document.querySelector(\"#app\");\n\napp.textContent = \"Hello from Vite\";\n```\n\n`vite.config.js`\n\n```js\nimport { defineConfig } from \"vite\";\n\nexport default defineConfig({\n  base: \"/\",\n  server: {\n    host: \"127.0.0.1\",\n    port: 5173,\n    strictPort: true,\n  },\n  preview: {\n    host: \"127.0.0.1\",\n    port: 4173,\n    strictPort: true,\n  },\n  build: {\n    outDir: \"dist\",\n    sourcemap: true,\n  },\n});\n```\n\nStart local development:\n\n```bash\nnpm run dev\n```\n\n## Environment Variables and Config\n\nVite reads env files from `envDir`, which defaults to the project root. Variables whose names start with `envPrefix` are exposed to client code through `import.meta.env`; the default prefix is `VITE_`.\n\n`.env`\n\n```dotenv\nVITE_API_BASE_URL=https://api.example.com\nAPP_PORT=5173\n```\n\n`src/api.js`\n\n```js\nexport const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;\n```\n\nIf you need env values while generating the config, use `loadEnv()`:\n\n```js\nimport { defineConfig, loadEnv } from \"vite\";\n\nexport default defineConfig(({ mode }) => {\n  const env = loadEnv(mode, process.cwd(), \"\");\n\n  return {\n    server: {\n      port: Number(env.APP_PORT || 5173),\n      strictPort: true,\n    },\n    define: {\n      __API_BASE_URL__: JSON.stringify(env.VITE_API_BASE_URL),\n    },\n  };\n});\n```\n\nUse `loadEnv()` for config-time decisions. Use `import.meta.env` inside app code.\n\n## Common CLI Workflows\n\nRun the dev server:\n\n```bash\nnpm run dev -- --host 127.0.0.1 --port 5173 --strictPort\n```\n\nExpose the dev server on all interfaces only when you need LAN access:\n\n```bash\nnpm run dev -- --host 0.0.0.0\n```\n\nBuild for production with source maps and a manifest:\n\n```bash\nnpm run build -- --sourcemap --manifest\n```\n\nPreview the built output locally:\n\n```bash\nnpm run preview -- --host 127.0.0.1 --port 4173 --strictPort\n```\n\nThe build manifest is written to `.vite/manifest.json` under the output directory when manifest mode is enabled. Use it when a backend or server-rendered app needs to map entry names to emitted asset files.\n\n## Node.js API\n\nVite also exposes a programmatic API from the `vite` package.\n\n### Start a dev server\n\n```js\nimport { createServer } from \"vite\";\n\nconst server = await createServer({\n  root: process.cwd(),\n  server: {\n    host: \"127.0.0.1\",\n    port: 5173,\n    strictPort: true,\n  },\n});\n\nawait server.listen();\nserver.printUrls();\n\nprocess.on(\"SIGINT\", async () => {\n  await server.close();\n  process.exit(0);\n});\n```\n\n### Run a production build\n\n```js\nimport { build } from \"vite\";\n\nawait build({\n  root: process.cwd(),\n  build: {\n    outDir: \"dist\",\n    sourcemap: true,\n    manifest: true,\n  },\n});\n```\n\n### Preview the production build\n\n```js\nimport { preview } from \"vite\";\n\nconst previewServer = await preview({\n  root: process.cwd(),\n  preview: {\n    host: \"127.0.0.1\",\n    port: 4173,\n    strictPort: true,\n  },\n});\n\npreviewServer.printUrls();\n```\n\n`preview()` starts a local server for an already-built app. Run `build()` first if `dist/` does not exist yet.\n\n### Mount Vite in an existing Node server\n\nUse middleware mode when another HTTP server owns the request lifecycle.\n\n```js\nimport http from \"node:http\";\nimport { createServer as createViteServer } from \"vite\";\n\nconst app = http.createServer();\n\nconst vite = await createViteServer({\n  appType: \"custom\",\n  server: {\n    middlewareMode: { server: app },\n  },\n});\n\napp.on(\"request\", vite.middlewares);\n\napp.listen(3000, () => {\n  console.log(\"Custom server listening on http://127.0.0.1:3000\");\n});\n```\n\nSet `appType: \"custom\"` when your host app, not Vite, is responsible for HTML routing and responses.\n\n## Monorepos and Files Outside Root\n\n`server.fs.allow` accepts absolute paths or paths relative to the project root. By default, Vite searches upward for the nearest workspace root.\n\nWhen your app needs to serve files from sibling packages, make the allowed paths explicit:\n\n```js\nimport { defineConfig, searchForWorkspaceRoot } from \"vite\";\n\nexport default defineConfig({\n  server: {\n    fs: {\n      allow: [searchForWorkspaceRoot(process.cwd()), \"../shared\"],\n    },\n  },\n});\n```\n\n## Important Pitfalls\n\n- `vite@7.3.1` does not support older Node.js releases; check the engine requirement before debugging odd startup failures.\n- Keep client-visible env values under the `VITE_` prefix by default. Values exposed through `import.meta.env` should be treated as public browser config.\n- `server.host: \"0.0.0.0\"` listens on all addresses. Use it only when you intentionally want LAN or public reachability.\n- Avoid `server.allowedHosts: true` unless you understand the DNS rebinding risk; Vite documents that setting as not recommended.\n- `server.cors: true` allows all origins. Prefer a specific CORS configuration instead of a blanket enable.\n- `vite preview` and `preview()` are for inspecting a production build locally. Your real deployment should serve the generated output directory with your production web server or hosting platform.\n- If you use a non-root deployment path, set `base` explicitly so generated asset URLs match the deployed location.\n\n## Version-Sensitive Notes\n\n- This guide targets `vite@7.3.1`.\n- The current package exports the main JavaScript helpers from `vite`, including `defineConfig`, `loadEnv`, `mergeConfig`, `createServer`, `build`, `preview`, `normalizePath`, and `searchForWorkspaceRoot`.\n- The CLI for this version exposes `vite`, `vite build`, and `vite preview`, with `optimize` still present but marked deprecated because dependency pre-bundling now runs automatically.\n- The default client env prefix in this version is `VITE_`.\n\n## Official Sources\n\n- https://vite.dev/guide/\n- https://vite.dev/guide/api-javascript.html\n- https://vite.dev/guide/cli\n- https://vite.dev/guide/env-and-mode\n- https://vite.dev/config/\n- https://vite.dev/config/shared-options\n- https://vite.dev/config/server-options\n- https://vite.dev/config/build-options\n- https://www.npmjs.com/package/vite\n- https://github.com/vitejs/vite/tree/main/packages/vite\n"
  },
  {
    "path": "content/vitest/docs/vitest/javascript/DOC.md",
    "content": "---\nname: vitest\ndescription: \"Vitest 4 for JavaScript projects: install it, configure test environments, write tests, mock modules, and run coverage from the CLI\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.18\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"vitest,testing,unit-test,mocking,vite\"\n---\n\n# Vitest for JavaScript\n\nVitest is a test runner for JavaScript and TypeScript projects. In `4.0.18`, the package requires Node.js `^20.0.0 || ^22.0.0 || >=24.0.0`.\n\n## Install\n\nInstall Vitest as a dev dependency:\n\n```bash\nnpm install -D vitest\n```\n\nOptional packages you add only when you use those features:\n\n```bash\nnpm install -D jsdom\nnpm install -D happy-dom\nnpm install -D @vitest/ui\n```\n\n- Install `jsdom` or `happy-dom` when you run DOM-style tests.\n- Install `@vitest/ui` when you use `vitest --ui`.\n\nAdd scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"test:ui\": \"vitest --ui\"\n  }\n}\n```\n\n## Basic configuration\n\nCreate `vitest.config.js`:\n\n```js\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  test: {\n    environment: 'node',\n    globals: false,\n    setupFiles: ['./test/setup.js'],\n    restoreMocks: true,\n    unstubEnvs: true,\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'html'],\n    },\n  },\n})\n```\n\nNotes:\n\n- The `test` block can live in `vitest.config.js` or in `vite.config.js`.\n- The default environment is `node`.\n- `globals` defaults to `false`, so import `describe`, `it`, `expect`, and `vi` from `vitest` unless you enable globals.\n- The default coverage provider is `v8`.\n- Vitest's default test file pattern is `**/*.{test,spec}.?(c|m)[jt]s?(x)`.\n\nIf you want global test APIs instead of explicit imports:\n\n```js\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  test: {\n    globals: true,\n  },\n})\n```\n\n## Write and run tests\n\nExample source file:\n\n```js\nexport function sum(a, b) {\n  return a + b\n}\n```\n\nExample test file `src/sum.test.js`:\n\n```js\nimport { describe, expect, it } from 'vitest'\nimport { sum } from './sum.js'\n\ndescribe('sum', () => {\n  it('adds two numbers', () => {\n    expect(sum(2, 3)).toBe(5)\n  })\n\n  it('supports async assertions', async () => {\n    await expect(Promise.resolve('ok')).resolves.toBe('ok')\n  })\n})\n```\n\nRun common workflows from the CLI:\n\n```bash\nnpx vitest\nnpx vitest run\nnpx vitest run src/sum.test.js\nnpx vitest run -t \"adds two numbers\"\nnpx vitest related src/sum.js\nnpx vitest list\n```\n\n- `vitest` starts in watch/dev mode.\n- `vitest run` disables watch mode.\n- `-t` filters by test name.\n- `related` runs tests related to changed source files.\n- `list` is useful when Vitest is not picking up the files you expected.\n\n## Setup files\n\nUse `setupFiles` for test-wide initialization.\n\nExample `test/setup.js`:\n\n```js\nimport { afterEach, vi } from 'vitest'\n\nafterEach(() => {\n  vi.restoreAllMocks()\n  vi.unstubAllEnvs()\n})\n```\n\nIf you already set `restoreMocks: true` and `unstubEnvs: true` in config, you do not need to repeat that cleanup manually.\n\n## Mock functions, spies, and modules\n\nUse `vi.fn()` for stand-alone mocks and `vi.spyOn()` for existing objects.\n\n```js\nimport { expect, it, vi } from 'vitest'\n\nit('spies on an existing method', () => {\n  const math = {\n    random() {\n      return Math.random()\n    },\n  }\n\n  const spy = vi.spyOn(math, 'random').mockReturnValue(0.5)\n\n  expect(math.random()).toBe(0.5)\n  expect(spy).toHaveBeenCalledTimes(1)\n})\n```\n\nMock an imported module with `vi.mock()`:\n\n```js\nimport { beforeEach, expect, it, vi } from 'vitest'\nimport * as api from '../src/api.js'\nimport { loadUser } from '../src/load-user.js'\n\nvi.mock('../src/api.js', () => ({\n  fetchUser: vi.fn(),\n}))\n\nbeforeEach(() => {\n  vi.resetAllMocks()\n})\n\nit('uses the mocked module', async () => {\n  vi.mocked(api.fetchUser).mockResolvedValue({ id: 'u_123', name: 'Ada' })\n\n  await expect(loadUser('u_123')).resolves.toEqual({\n    id: 'u_123',\n    name: 'Ada',\n  })\n})\n```\n\nImportant behavior:\n\n- `vi.mock()` is hoisted to the top of the file.\n- If the mock depends on runtime values, use `vi.doMock()` or `vi.hoisted()` instead of relying on later variables in module scope.\n- `vi.clearAllMocks()`, `vi.resetAllMocks()`, and `vi.restoreAllMocks()` do different things; `restoreAllMocks()` is the safest default for spies between tests.\n\n## Stub environment variables\n\nVitest exposes `vi.stubEnv()` and `vi.unstubAllEnvs()` for `process.env` and `import.meta.env` values.\n\n```js\nimport { afterEach, expect, it, vi } from 'vitest'\n\nafterEach(() => {\n  vi.unstubAllEnvs()\n})\n\nit('stubs an environment variable', () => {\n  vi.stubEnv('API_BASE_URL', 'https://example.test')\n\n  expect(process.env.API_BASE_URL).toBe('https://example.test')\n})\n```\n\nFor repeated use across the suite, set `unstubEnvs: true` in config.\n\n## DOM tests\n\nVitest's default environment is `node`. For tests that touch `document`, `window`, or browser APIs, switch to a DOM environment and install the matching package.\n\nUsing `jsdom` in config:\n\n```bash\nnpm install -D jsdom\n```\n\n```js\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  test: {\n    environment: 'jsdom',\n  },\n})\n```\n\nExample DOM test:\n\n```js\nimport { beforeEach, expect, it } from 'vitest'\n\nfunction renderGreeting(name) {\n  document.querySelector('#app').textContent = `Hello ${name}`\n}\n\nbeforeEach(() => {\n  document.body.innerHTML = '<div id=\"app\"></div>'\n})\n\nit('renders into the document', () => {\n  renderGreeting('Ada')\n  expect(document.querySelector('#app').textContent).toBe('Hello Ada')\n})\n```\n\nFor a quick DOM-style run with `happy-dom`, Vitest also supports:\n\n```bash\nnpm install -D happy-dom\nnpx vitest --dom\n```\n\n## Snapshots and coverage\n\nSnapshot example:\n\n```js\nimport { expect, it } from 'vitest'\n\nit('matches a snapshot', () => {\n  expect({ status: 'ok', items: [1, 2, 3] }).toMatchSnapshot()\n})\n```\n\nUpdate stored snapshots:\n\n```bash\nnpx vitest run -u\n```\n\nRun coverage:\n\n```bash\nnpx vitest run --coverage\n```\n\nUseful coverage flags:\n\n```bash\nnpx vitest run --coverage.provider=v8\nnpx vitest run --coverage.reporter=text --coverage.reporter=html\nnpx vitest run --coverage.thresholds.lines=90\n```\n\nIn `4.0.18`, the built-in coverage defaults are:\n\n- `provider: 'v8'`\n- `reportsDirectory: './coverage'`\n- reporters: `text`, `html`, `clover`, and `json`\n\n## Typecheck and UI workflows\n\nRun tests with typechecking enabled:\n\n```bash\nnpx vitest run --typecheck\n```\n\nVitest's CLI exposes `tsc` and `vue-tsc` as built-in typechecker options:\n\n```bash\nnpx vitest run --typecheck --typecheck.checker=tsc\n```\n\nRun the UI:\n\n```bash\nnpm install -D @vitest/ui\nnpx vitest --ui\n```\n\n## High-value pitfalls\n\n- Vitest `4.0.18` does not support Node 18; use Node 20, 22, or 24+.\n- If your test files are not discovered, either match the default glob `**/*.{test,spec}.?(c|m)[jt]s?(x)` or set `test.include` explicitly.\n- If `describe`, `it`, or `expect` are undefined, either import them from `vitest` or enable `test.globals`.\n- If DOM globals like `document` are missing, install `jsdom` or `happy-dom` and set the environment.\n- `vi.mock()` is hoisted, so runtime-dependent mocks should use `vi.doMock()` or `vi.hoisted()`.\n- `vitest --ui` requires `@vitest/ui`; it is not bundled into the base `vitest` package.\n\n## Official docs\n\n- API reference: `https://vitest.dev/api/`\n- Config reference: `https://vitest.dev/config/`\n- Coverage guide: `https://vitest.dev/guide/coverage`\n"
  },
  {
    "path": "content/vllm/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"vLLM Python package guide for high-throughput LLM inference and OpenAI-compatible serving\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.17.1\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"vllm,llm,inference,serving,openai-compatible,huggingface,gpu\"\n---\n\n# vLLM Python Package Guide\n\n## What It Covers\n\n`vllm` is a Python package for high-throughput LLM inference. In practice you use it in one of two ways:\n\n- embed it in Python with `LLM(...)` for local or service-side generation\n- run `vllm serve ...` to expose an OpenAI-compatible HTTP API\n\nThis guide targets PyPI package version `0.17.1`.\n\n## Installation\n\nOfficial docs list Python `3.10` through `3.13` as supported.\n\n```bash\npip install \"vllm==0.17.1\"\n```\n\nIf you use `uv`, the install docs recommend:\n\n```bash\nuv pip install --torch-backend=auto vllm\n```\n\nImportant backend note:\n\n- `pip install vllm` currently installs the default wheel for Linux `x86_64` with CUDA `12.8` and PyTorch `2.7.1`\n- if you need CPU, AMD ROCm, Intel XPU, TPU, or a different CUDA stack, use the backend-specific install pages from the official docs instead of assuming the default wheel is correct\n\n## Setup And Model Access\n\nChoose a Hugging Face model ID that vLLM supports, for example `Qwen/Qwen2.5-1.5B-Instruct`.\n\nModel downloads are cached in the Hugging Face cache directory. By default that is:\n\n```bash\n~/.cache/huggingface\n```\n\nSet `HF_HOME` if you need the cache elsewhere:\n\n```bash\nexport HF_HOME=/mnt/models/hf\n```\n\nOnly enable remote model code when the upstream repository is trusted:\n\n```python\nllm = LLM(model=\"some/model\", trust_remote_code=True)\n```\n\nThe CLI/server equivalent is `--trust-remote-code`.\n\n## Embedded Python Usage\n\n```python\nfrom vllm import LLM, SamplingParams\n\nprompts = [\n    \"Name three practical uses for speculative decoding.\",\n    \"Write a two-line summary of vLLM.\",\n]\n\nsampling_params = SamplingParams(\n    temperature=0.7,\n    top_p=0.95,\n    max_tokens=128,\n)\n\nllm = LLM(model=\"Qwen/Qwen2.5-1.5B-Instruct\")\noutputs = llm.generate(prompts, sampling_params)\n\nfor output in outputs:\n    print(output.prompt)\n    print(output.outputs[0].text)\n```\n\nUse this path when your Python process owns model lifecycle and inference directly.\n\n## OpenAI-Compatible Server\n\nStart the server:\n\n```bash\nvllm serve Qwen/Qwen2.5-1.5B-Instruct --api-key token-abc123\n```\n\nThen call it with the OpenAI Python client:\n\n```bash\npip install openai\n```\n\n```python\nfrom openai import OpenAI\n\nclient = OpenAI(\n    base_url=\"http://localhost:8000/v1\",\n    api_key=\"token-abc123\",\n)\n\ncompletion = client.chat.completions.create(\n    model=\"Qwen/Qwen2.5-1.5B-Instruct\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are a concise assistant.\"},\n        {\"role\": \"user\", \"content\": \"Explain tensor parallelism in one paragraph.\"},\n    ],\n)\n\nprint(completion.choices[0].message.content)\n```\n\nAuth and access control:\n\n- server auth can be set with `--api-key` or `VLLM_API_KEY`\n- the HTTP surface is OpenAI-compatible, but you still need to secure the process, host, and network boundary yourself\n\n## Common Configuration Notes\n\n- Prefer passing an explicit model ID everywhere instead of relying on examples copied from unrelated model families.\n- For multimodal or audio models, install the matching extras when the official model docs require them, for example:\n\n```bash\npip install \"vllm[audio]==0.17.1\"\n```\n\n- Keep an eye on local disk usage. vLLM commonly pulls multi-GB model weights into the Hugging Face cache.\n\n## Common Pitfalls\n\n- The official docs URL for this package is `/en/latest/`, so some install details can move ahead of the exact package version in your environment.\n- The OpenAI-compatible server uses a model repository's `generation_config.json` by default. If you want vLLM defaults instead, start the server with:\n\n```bash\nvllm serve Qwen/Qwen2.5-1.5B-Instruct --generation-config vllm\n```\n\n- Do not enable `trust_remote_code` unless the model repository is trusted; it allows execution of model-provided Python code.\n- Do not assume the default `pip install vllm` wheel matches your accelerator stack. Backend-specific install docs matter for non-default environments.\n\n## Version-Sensitive Notes For `0.17.1`\n\n- PyPI package version covered here: `0.17.1`\n- Official install docs currently state Python `3.10` to `3.13`\n- Official latest install docs currently state the default pre-built wheel targets Linux `x86_64`, CUDA `12.8`, and PyTorch `2.7.1`\n- Because the docs root is `latest`, verify backend and deployment details again if you are debugging behavior on a different `vllm` minor release\n\n## Official Sources\n\n- Docs root: https://docs.vllm.ai/en/latest/\n- Quickstart: https://docs.vllm.ai/en/latest/getting_started/quickstart.html\n- Installation overview: https://docs.vllm.ai/en/latest/getting_started/installation/index.html\n- OpenAI-compatible server: https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html\n- Supported models: https://docs.vllm.ai/en/latest/models/supported_models.html\n- PyPI: https://pypi.org/project/vllm/\n"
  },
  {
    "path": "content/voila/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"voila package guide for turning Jupyter notebooks into standalone web apps and dashboards\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.5.11\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"voila,jupyter,ipywidgets,notebook,dashboard,webapp\"\n---\n\n# voila Python Package Guide\n\n## Golden Rule\n\nUse `voila` to serve notebooks, not as a generic Python web framework. Keep the notebook, widget libraries, and the Voilà server in the same environment, choose either standalone CLI mode or Jupyter server extension mode deliberately, and configure auth plus reverse-proxy behavior explicitly before exposing the app outside local development.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI and the upstream GitHub releases page both show `0.5.11` as the latest published release.\n- The docs URL points at `en/stable`, but some stable pages still render as `0.5.8`. For package-level work, prefer `https://voila.readthedocs.io/en/latest/` until the stable alias is refreshed upstream.\n- `0.5.11` adds `extra_labextensions_path` support and fixes server-extension local config merging.\n- `0.5.8` added `progressive_rendering`, ipywidgets 7 compatibility, and `page_config_hook`.\n- `0.5.0` was the major frontend transition: Voilà moved to a JupyterLab 4 based frontend, gained token auth support with `jupyter-server` 2, and changed tree-page/template behavior. Old blog posts written for `0.3.x` or early `0.4.x` are often misleading now.\n- The `classic` template is deprecated and upstream says it will be removed in Voilà `1.0.0`.\n\n## Install\n\nUse an isolated environment unless the notebook server is already isolated:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"voila==0.5.11\"\n```\n\nConda and mamba are first-class upstream install paths:\n\n```bash\nmamba install -c conda-forge voila\nconda install -c conda-forge voila\n```\n\nBasic verification:\n\n```bash\nvoila --help\npython -m pip show voila\n```\n\nImportant install notes:\n\n- `pip install voila` is enough for the CLI itself.\n- The notebook's runtime dependencies must also be installed in the same environment as the kernel that Voilà will launch.\n- The PyPI project description says the JupyterLab preview extension is automatically installed after `pip install voila` starting with JupyterLab 3.0.\n\n## Create A Minimal Notebook App\n\nCreate a notebook such as `hello.ipynb` with a widget-driven cell:\n\n```python\nimport ipywidgets as widgets\nfrom IPython.display import display\n\nname = widgets.Text(description=\"Name\", value=\"Voila\")\nout = widgets.Output()\n\ndef render(change=None):\n    with out:\n        out.clear_output()\n        print(f\"Hello, {name.value}!\")\n\nname.observe(render, names=\"value\")\ndisplay(name, out)\nrender()\n```\n\nRun it locally:\n\n```bash\nvoila hello.ipynb\n```\n\nBy default, Voilà serves the app on `http://localhost:8866` and hides code cells in the rendered output.\n\n## Core Usage Patterns\n\n### Serve one notebook directly\n\n```bash\nvoila hello.ipynb --no-browser\n```\n\nUse `--no-browser` for remote machines, containers, CI smoke tests, and production launch scripts.\n\n### Serve a notebook directory\n\nIf you run `voila` with no notebook argument, it serves the current directory as a notebook picker:\n\n```bash\ncd notebooks\nvoila\n```\n\nEach notebook launch gets its own kernel, which is important for memory planning and per-user state isolation.\n\n### Use Voilà from JupyterLab or Jupyter Server\n\nStart your server normally and open the `/voila` route:\n\n```bash\njupyter lab\n# then browse to http://localhost:8888/voila\n```\n\nIf the endpoint is missing in an older or unusual environment, the upstream README still documents enabling the extension explicitly:\n\n```bash\njupyter serverextension enable voila\njupyter server extension enable voila\n```\n\n### Show notebook source intentionally\n\nBy default, Voilà strips notebook inputs from the rendered page. If you actually want readers to see source code, set `strip_sources=False` in your config instead of assuming notebook cells will appear automatically.\n\n### Programmatic startup exists, but prefer the CLI first\n\nThe docs show an embedding path through `voila.app.Voila` and `voila.config.VoilaConfiguration`, mainly for advanced hook-based customization. For most agent-generated work, the CLI is simpler and less error-prone than constructing the application object manually.\n\n## Configuration, Hooks, And Auth\n\nVoilà configuration is spread across CLI flags, `voila.py`, `voila.json`, and Jupyter Server startup flags.\n\n### Pass config through the CLI\n\nExamples:\n\n```bash\nvoila hello.ipynb --theme=dark --template=gridstack\nvoila hello.ipynb --VoilaConfiguration.file_allowlist=\"['.*\\\\.(png|jpg|svg)']\"\nvoila --MappingKernelManager.cull_interval=60 --MappingKernelManager.cull_idle_timeout=120 hello.ipynb\n```\n\n### Configure Voilà inside a Jupyter Server launch\n\nWhen serving through JupyterLab or Notebook, pass Voilà config through the Jupyter command:\n\n```bash\njupyter lab --VoilaConfiguration.template=distill\n```\n\n### `voila.py` for Python hook functions\n\nThe official docs place `voila.py` in the directory where you start Voilà. Use it when you need Python hooks such as:\n\n- `prelaunch_hook` to inspect the Tornado request or mutate the notebook before execution\n- `page_config_hook` to adjust frontend `page_config`, static URLs, or extension config\n\nUse hooks sparingly. They are powerful, but they make notebook rendering behavior harder to reason about.\n\n### `voila.json` for structured config\n\nThe docs use `voila.json` in the launch directory for kernel-pool settings and other nontrivial config, especially:\n\n- preheated kernel pools\n- kernel environment variables\n- notebook-level preheat deny lists\n\n### Token authentication\n\nVoilà supports token auth when using `jupyter-server` 2, but upstream says it is disabled by default.\n\nUse an explicit token for anything beyond local testing:\n\n```bash\nvoila hello.ipynb --token=my-secret-token\n```\n\nDo not assume that a reverse proxy alone gives you acceptable access control.\n\n### Static files are restricted by default\n\nUnlike JupyterLab, Voilà does not serve every file next to the notebook. It only serves files that match the allowlist and do not match the denylist. This is a common source of broken images, CSS, or downloadable assets when moving from notebook development to deployment.\n\n## Performance And Deployment\n\n### Cull idle kernels\n\nVoilà starts a new kernel for each rendered notebook. If multiple users or repeated refreshes matter, configure culling:\n\n```bash\nvoila hello.ipynb \\\n  --MappingKernelManager.cull_interval=60 \\\n  --MappingKernelManager.cull_idle_timeout=120\n```\n\nThis is one of the simplest ways to prevent memory growth in multi-user or demo deployments.\n\n### Preheated kernels\n\nFor heavy notebooks with slow first render times:\n\n```bash\nvoila hello.ipynb --preheat_kernel=True --pool_size=5\n```\n\nImportant limitations:\n\n- `preheated kernels` are incompatible with `prelaunch_hook`\n- cached pre-rendered HTML only works when request conditions still match the pre-rendered theme/template expectations\n- if you use request-derived data, you may need `voila.utils.wait_for_request()` in the notebook\n\n### Public hosting patterns\n\nThe official deploy docs cover Binder, Railway, Google App Engine flexible, private servers behind nginx, Apache reverse proxy, ngrok, and other hosted paths.\n\nPractical deployment rules:\n\n- include every notebook dependency in `requirements.txt` or `environment.yml`\n- public deployments need websocket support\n- for container or service launches, use `--no-browser`\n- for hosted services, bind to `0.0.0.0` when the platform expects it, for example `voila --port=$PORT --Voila.ip=0.0.0.0 --no-browser`\n- if serving under a subpath or reverse proxy, configure the base URL correctly and forward websocket traffic\n\n## Common Pitfalls\n\n- Installing `voila` without installing the notebook's widget and data dependencies.\n- Running Voilà from a different environment than the Jupyter kernel, then assuming missing widgets are a Voilà bug.\n- Starting from the stale `en/stable` docs pages and copying old template or frontend guidance.\n- Forgetting that code cells are hidden by default and then debugging the wrong thing.\n- Expecting arbitrary local files to be served without adjusting `file_allowlist`, `file_denylist`, or `static_root`.\n- Using `prelaunch_hook` and `preheat_kernel` together. Upstream documents them as incompatible.\n- Assuming tree-page templates still apply to the default tree view. Since `0.5.0`, the default tree page is JupyterLab-based; old tree templates require `--classic-tree`.\n- Treating public sharing as safe because execute requests are blocked. The app can still expose notebook data and business logic.\n- Deploying to environments without websocket support. The official Google App Engine docs explicitly require the flexible environment for this reason.\n- Using plain `.py` scripts as if they were notebooks without configuring `extension_language_mapping` or using Jupytext.\n\n## Official Source URLs\n\n- `https://voila.readthedocs.io/en/latest/`\n- `https://voila.readthedocs.io/en/latest/install.html`\n- `https://voila.readthedocs.io/en/latest/using.html`\n- `https://voila.readthedocs.io/en/latest/customize.html`\n- `https://voila.readthedocs.io/en/latest/deploy.html`\n- `https://voila.readthedocs.io/en/latest/changelog.html`\n- `https://pypi.org/project/voila/`\n- `https://github.com/voila-dashboards/voila`\n- `https://github.com/voila-dashboards/voila/releases`\n"
  },
  {
    "path": "content/vue/docs/vue/javascript/DOC.md",
    "content": "---\nname: vue\ndescription: \"Vue 3 runtime for building reactive component UIs in JavaScript with the Composition API, single-file components, and app-level configuration.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.5.30\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"vue,javascript,ui,components,reactivity,composition-api\"\n---\n\n# Vue Guide (JavaScript)\n\n## Golden Rule\n\nUse `vue` for application creation, components, reactivity, lifecycle hooks, and app-level configuration.\n\nVue does not require API keys, auth configuration, or package-level environment variables. If your app uses environment variables, they come from your bundler or framework rather than from `vue` itself.\n\nThis guide assumes a modern ESM app. If you import `.vue` single-file components, your toolchain must compile them.\n\n## Install\n\nInstall the runtime package:\n\n```bash\nnpm install vue\n```\n\nFor a typical browser app, mount Vue onto an existing DOM element and let your bundler load `src/main.js`.\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vue App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n```\n\n## Initialize an App\n\nCreate the app with `createApp(...)`, configure it, then call `mount(...)`.\n\n```javascript\n// src/main.js\nimport { createApp } from \"vue\";\nimport App from \"./App.vue\";\n\nconst app = createApp(App);\n\napp.mount(\"#app\");\n```\n\n```vue\n<!-- src/App.vue -->\n<script setup>\nimport { ref } from \"vue\";\n\nconst count = ref(0);\n</script>\n\n<template>\n  <main>\n    <h1>Hello, Vue</h1>\n    <button type=\"button\" @click=\"count += 1\">\n      Clicked {{ count }} times\n    </button>\n  </main>\n</template>\n```\n\nIf you need SSR hydration instead of a fresh client mount, create the app with `createSSRApp(...)` instead of `createApp(...)`.\n\n## Common Workflows\n\n### Manage local state with `ref()` and `reactive()`\n\nUse `ref()` for primitive values and `reactive()` for object-shaped state.\n\n```vue\n<script setup>\nimport { reactive, ref } from \"vue\";\n\nconst isSaving = ref(false);\n\nconst form = reactive({\n  email: \"\",\n  marketing: false,\n});\n\nasync function submit() {\n  isSaving.value = true;\n\n  try {\n    console.log(\"Submitting\", {\n      email: form.email,\n      marketing: form.marketing,\n    });\n  } finally {\n    isSaving.value = false;\n  }\n}\n</script>\n\n<template>\n  <form @submit.prevent=\"submit\">\n    <label>\n      Email\n      <input v-model=\"form.email\" type=\"email\" required />\n    </label>\n\n    <label>\n      <input v-model=\"form.marketing\" type=\"checkbox\" />\n      Receive product updates\n    </label>\n\n    <button type=\"submit\" :disabled=\"isSaving\">\n      {{ isSaving ? \"Saving...\" : \"Save preferences\" }}\n    </button>\n  </form>\n</template>\n```\n\n### Derive values with `computed()` and react to changes with `watch()`\n\nUse `computed()` for derived state and `watch()` for side effects triggered by a specific source.\n\n```vue\n<script setup>\nimport { computed, reactive, watch } from \"vue\";\n\nconst filters = reactive({\n  query: \"\",\n  inStockOnly: false,\n});\n\nconst normalizedQuery = computed(() => filters.query.trim().toLowerCase());\n\nwatch(\n  () => filters.query,\n  (query, previousQuery) => {\n    console.log(\"Search changed\", {\n      previousQuery,\n      query,\n    });\n  },\n);\n</script>\n\n<template>\n  <section>\n    <input\n      v-model=\"filters.query\"\n      type=\"search\"\n      placeholder=\"Search products\"\n    />\n\n    <label>\n      <input v-model=\"filters.inStockOnly\" type=\"checkbox\" />\n      In stock only\n    </label>\n\n    <p>Normalized query: {{ normalizedQuery || \"all products\" }}</p>\n  </section>\n</template>\n```\n\n### Accept props and emit events in `<script setup>`\n\nUse `defineProps()` to declare the public input contract and `defineEmits()` to publish events upward.\n\n```vue\n<!-- components/SubmitButton.vue -->\n<script setup>\nconst props = defineProps({\n  disabled: {\n    type: Boolean,\n    default: false,\n  },\n  label: {\n    type: String,\n    required: true,\n  },\n});\n\nconst emit = defineEmits([\"submit\"]);\n\nfunction handleClick() {\n  emit(\"submit\");\n}\n</script>\n\n<template>\n  <button type=\"button\" :disabled=\"props.disabled\" @click=\"handleClick\">\n    {{ props.label }}\n  </button>\n</template>\n```\n\n```vue\n<!-- Parent component -->\n<script setup>\nimport SubmitButton from \"./components/SubmitButton.vue\";\n\nfunction save() {\n  console.log(\"Save requested\");\n}\n</script>\n\n<template>\n  <SubmitButton label=\"Save\" @submit=\"save\" />\n</template>\n```\n\n### Share app-level values with `provide()` and `inject()`\n\nProvide a value near the top of the tree and read it in descendants without prop drilling.\n\n```javascript\n// src/main.js\nimport { createApp } from \"vue\";\nimport App from \"./App.vue\";\n\nconst app = createApp(App);\n\napp.provide(\"apiBaseUrl\", \"/api\");\napp.mount(\"#app\");\n```\n\n```vue\n<!-- components/ApiBanner.vue -->\n<script setup>\nimport { inject } from \"vue\";\n\nconst apiBaseUrl = inject(\"apiBaseUrl\");\n\nif (!apiBaseUrl) {\n  throw new Error(\"Missing apiBaseUrl provider\");\n}\n</script>\n\n<template>\n  <p>Sending requests to {{ apiBaseUrl }}</p>\n</template>\n```\n\n### Access DOM elements with template refs\n\nIn Vue 3.5, `useTemplateRef()` provides a concise way to read a template ref from `<script setup>`.\n\n```vue\n<script setup>\nimport { onMounted, useTemplateRef } from \"vue\";\n\nconst searchInput = useTemplateRef(\"searchInput\");\n\nonMounted(() => {\n  searchInput.value?.focus();\n});\n</script>\n\n<template>\n  <input ref=\"searchInput\" type=\"search\" placeholder=\"Search\" />\n</template>\n```\n\n## Important Pitfalls\n\n- `ref` values use `.value` in JavaScript. Inside templates, Vue automatically unwraps them.\n- When you watch part of a reactive object, pass a getter such as `() => filters.query` instead of the raw property value.\n- Call `app.use()`, `app.component()`, `app.directive()`, and `app.provide()` before `app.mount()`.\n- `defineProps()` and `defineEmits()` are compiler macros for `<script setup>`. Do not import them from `vue`.\n- Lifecycle hooks such as `onMounted()` must run synchronously during `setup()` or `<script setup>`.\n- The `vue` package exposes the runtime APIs, but `.vue` single-file components still need compiler support from your toolchain.\n\n## Version-Sensitive Notes\n\n- This guide targets `vue==3.5.30`.\n- `useTemplateRef()` is part of the Vue 3.5 API. Older Vue 3 code often uses `const el = ref(null)` for the same job.\n- Use `createSSRApp()` rather than `createApp()` when hydrating HTML that was rendered on the server.\n\n## Official Sources\n\n- Vue package page: https://www.npmjs.com/package/vue\n- Vue API index: https://vuejs.org/api/\n- Quick Start: https://vuejs.org/guide/quick-start.html\n- Application API: https://vuejs.org/api/application.html\n- Reactivity Core API: https://vuejs.org/api/reactivity-core.html\n- Lifecycle Hooks API: https://vuejs.org/api/composition-api-lifecycle.html\n- Dependency Injection API: https://vuejs.org/api/composition-api-dependency-injection.html\n- `<script setup>` macros: https://vuejs.org/api/sfc-script-setup.html\n- Template refs guide: https://vuejs.org/guide/essentials/template-refs.html\n"
  },
  {
    "path": "content/wand/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Wand Python bindings for ImageMagick image loading, transforms, format conversion, metadata inspection, and multi-frame image processing\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.6.13\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"wand,imagemagick,image-processing,python,graphics\"\n---\n\n# Wand Python Package Guide\n\n## Golden Rule\n\n`Wand` is a Python binding around a locally installed ImageMagick stack. Install the native image library first, then install the Python package, and treat the linked native library as part of your runtime contract.\n\nAs of March 13, 2026, PyPI publishes `Wand 0.6.13`, while `https://docs.wand-py.org/en/latest/` is the development docs for `0.7.0`. This guide targets the published `0.6.13` package and calls out the version drift where it matters.\n\n## Install\n\nCreate a virtual environment and install the pinned package version:\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install \"Wand==0.6.13\"\n```\n\nInstall ImageMagick development libraries first. The maintainer docs show these common package names:\n\n```bash\n# Debian / Ubuntu\nsudo apt-get install libmagickwand-dev\n\n# macOS with Homebrew\nbrew install imagemagick\n```\n\nIf Wand cannot find your ImageMagick install, set `MAGICK_HOME` before importing `wand`. If your system uses nonstandard shared-library suffixes, the install guide also documents `WAND_MAGICK_LIBRARY_SUFFIX`.\n\n```bash\nexport MAGICK_HOME=/opt/local\nexport WAND_MAGICK_LIBRARY_SUFFIX=\"-7.Q32;-7.Q32HDRI;.Q32HDRI;.Q32\"\n```\n\n## Verify The Linked Image Library\n\nThe Python package version does not tell you which codecs, delegates, or resource policies are available. Check the linked native library in the environment where your app will run:\n\n```bash\npython -m wand.version\npython -m wand.version --verbose\n```\n\nYou can also inspect it in code:\n\n```python\nfrom wand.version import VERSION, MAGICK_VERSION, formats\n\nprint(\"Wand:\", VERSION)\nprint(\"ImageMagick:\", MAGICK_VERSION)\nprint(\"JPEG available:\", \"JPEG\" in formats(\"*\"))\n```\n\n## Open Images And Read Metadata\n\nUse `Image.ping()` when you only need metadata such as dimensions or format. It avoids decoding the full image payload.\n\n```python\nfrom wand.image import Image\n\nwith Image.ping(filename=\"input.jpg\") as img:\n    print(img.format)\n    print(img.width, img.height)\n```\n\nUse `Image(...)` when you need to decode and modify pixels:\n\n```python\nfrom wand.image import Image\n\nwith Image(filename=\"input.jpg\") as img:\n    print(img.format)\n    print(img.size)\n```\n\n## Transform And Save An Image\n\n`Image` objects are context managers. Keep operations inside the `with` block so file handles and native resources are released promptly.\n\n```python\nfrom wand.image import Image\n\nwith Image(filename=\"input.jpg\") as img:\n    img.auto_orient()\n    img.resize(width=1200)\n    img.strip()\n    img.format = \"jpeg\"\n    img.save(filename=\"output.jpg\")\n```\n\nUseful details:\n\n- `auto_orient()` applies EXIF orientation before you write the image back out.\n- `resize()` changes pixel dimensions.\n- `strip()` removes profiles and comments from the image payload before saving.\n\n## Convert Bytes In Memory\n\nWhen you are working with uploads or blobs from another API, open the image from bytes and emit bytes again. Pass `format=` when the blob header is ambiguous or you want to force a coder.\n\n```python\nfrom wand.image import Image\n\ndef png_bytes_to_jpeg(data: bytes) -> bytes:\n    with Image(blob=data, format=\"png\") as img:\n        img.format = \"jpeg\"\n        return img.make_blob()\n```\n\nThe constructor also accepts `resolution=` for formats such as PDF or SVG where rasterization density matters.\n\n## Work With Multi-Frame Images\n\nAnimated GIFs, TIFFs, and PDFs can contain multiple frames. Modify frames through the sequence API and use a context manager for the frame object so the changes are written back.\n\n```python\nfrom wand.image import Image\n\nwith Image(filename=\"animation.gif\") as img:\n    print(\"frames:\", len(img.sequence))\n\n    with img.sequence[0] as frame:\n        frame.negate()\n\n    img.save(filename=\"animation-out.gif\")\n```\n\nDo not call mutating methods directly on `img.sequence[index]` without the nested `with` block. The maintainer docs note that sequence items must be synced back to the parent image.\n\n## Handle Untrusted Input Carefully\n\nWand exposes the underlying ImageMagick coders, delegates, and resource limits. For user-supplied files, set explicit limits in your process and narrow the allowed coder when possible.\n\n```python\nfrom wand.exceptions import PolicyError, ResourceLimitError\nfrom wand.image import Image\nfrom wand.resource import limits\n\nlimits[\"memory\"] = 256 * 1024 * 1024\nlimits[\"map\"] = 512 * 1024 * 1024\nlimits[\"width\"] = 8000\nlimits[\"height\"] = 8000\n\ndef read_user_png(path: str) -> tuple[int, int]:\n    try:\n        with Image(filename=f\"png:{path}\") as img:\n            return img.width, img.height\n    except (PolicyError, ResourceLimitError) as exc:\n        raise ValueError(\"Rejected image\") from exc\n```\n\nAlso review the system ImageMagick `policy.xml` on hosts that process user uploads. The security guide explicitly recommends limiting memory, disk, width, height, and execution time for untrusted input.\n\n## Common Pitfalls\n\n- Installing `Wand` without ImageMagick headers and libraries is the most common setup failure.\n- The codecs you can read and write depend on the linked ImageMagick build, not just the Python wheel. Verify formats in the target runtime.\n- `Image.ping()` is for metadata only. Use `Image(...)` for pixel edits.\n- Sequence frames need the nested context-manager pattern shown above or your edits may not propagate back to the parent image.\n- Avoid processing untrusted images inline in a public request path. Isolate the work, set resource limits, and restrict allowed coders where possible.\n\n## Version-Sensitive Notes\n\n- `docs.wand-py.org/en/latest/` currently documents the unreleased `0.7.0` line. PyPI still publishes `0.6.13`.\n- The `0.7.0` \"What's New\" page documents changes such as `evaluate_images()` and dropped Python 2 support. Do not assume those changes exist in an environment pinned to `0.6.13`.\n- Newer image operations can depend on the linked ImageMagick major version. Check `python -m wand.version --verbose` before relying on methods documented only for newer native builds.\n\n## Official Sources\n\n- Maintainer docs root: https://docs.wand-py.org/en/latest/\n- Stable docs index for `0.6.13`: https://docs.wand-py.org/en/0.6.13/\n- Stable install guide: https://docs.wand-py.org/en/0.6.13/guide/install.html\n- Stable image guide: https://docs.wand-py.org/en/0.6.13/wand/image.html\n- Security guide: https://docs.wand-py.org/en/0.6.13/guide/security.html\n- 0.7.0 what's new: https://docs.wand-py.org/en/latest/wand/version.html#what-s-new-in-wand-0-7-0\n- PyPI package page: https://pypi.org/project/wand/\n"
  },
  {
    "path": "content/wandb/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"wandb package guide for Python experiment tracking, model logging, and W&B run management\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.25.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"wandb,weights-and-biases,python,ml,experiment-tracking,artifacts,training\"\n---\n\n# wandb Python Package Guide\n\n## What It Is\n\n`wandb` is the Python SDK for Weights & Biases. Use it to:\n\n- create and manage experiment runs\n- log scalar metrics, media, tables, and config\n- store model checkpoints and datasets as artifacts\n- query or automate runs later through the W&B API\n\nFor most coding tasks, the core flow is: authenticate, `wandb.init(...)`, `run.log(...)`, optionally `run.log_artifact(...)`, then `run.finish()`.\n\n## Installation\n\nInstall the exact version covered here:\n\n```bash\npython -m pip install wandb==0.25.1\n```\n\nCommon package managers:\n\n```bash\nuv add wandb==0.25.1\npoetry add wandb==0.25.1\n```\n\nIf the project already pins `wandb`, match that version instead of forcing `0.25.1`.\n\n## Authentication And Setup\n\nW&B can authenticate interactively or from an API key.\n\n### Typical environment variables\n\n```bash\nexport WANDB_API_KEY=\"...\"\nexport WANDB_ENTITY=\"your-team-or-user\"\nexport WANDB_PROJECT=\"my-project\"\n```\n\nIn Python:\n\n```python\nimport os\nimport wandb\n\nwandb.login(key=os.environ[\"WANDB_API_KEY\"])\n```\n\nFor a self-hosted W&B instance, set the base URL before logging in:\n\n```bash\nexport WANDB_BASE_URL=\"https://wandb.example.com\"\n```\n\n```python\nimport os\nimport wandb\n\nwandb.login(\n    key=os.environ[\"WANDB_API_KEY\"],\n    host=os.environ[\"WANDB_BASE_URL\"],\n)\n```\n\nUseful runtime configuration:\n\n- `WANDB_PROJECT`: default project name\n- `WANDB_ENTITY`: default team or user namespace\n- `WANDB_DIR`: local directory for generated run files\n- `WANDB_MODE`: runtime mode such as `online`, `offline`, or `disabled`\n- `WANDB_BASE_URL`: API host for self-managed deployments\n\n## Initialize A Run\n\nPrefer keeping the returned run object instead of relying on the module-global current run.\n\n```python\nimport os\nimport wandb\n\nwandb.login(key=os.environ[\"WANDB_API_KEY\"])\n\nrun = wandb.init(\n    project=os.getenv(\"WANDB_PROJECT\", \"demo-project\"),\n    entity=os.getenv(\"WANDB_ENTITY\"),\n    config={\n        \"learning_rate\": 1e-3,\n        \"batch_size\": 32,\n        \"epochs\": 5,\n    },\n    tags=[\"baseline\"],\n    mode=os.getenv(\"WANDB_MODE\", \"online\"),\n)\n```\n\nImportant `wandb.init()` parameters for agents:\n\n- `project`: logical destination for the run\n- `entity`: user or team namespace\n- `config`: hyperparameters and other structured metadata\n- `dir`: where local run data should be written\n- `tags`: labels for filtering in the UI\n- `mode`: `online`, `offline`, or `disabled`\n- `id` plus `resume`: use when resuming a known run instead of creating a new one\n- `reinit`: relevant when the same Python process intentionally creates multiple runs\n\n## Core Usage\n\n### Log Metrics\n\nUse `run.log()` or `wandb.log()` only after a run exists. If you control the run handle, prefer `run.log()`.\n\n```python\nimport random\nimport wandb\n\nrun = wandb.init(project=\"demo-project\", config={\"epochs\": 3})\n\nfor step in range(run.config[\"epochs\"]):\n    train_loss = 1.0 / (step + 1) + random.random() * 0.01\n    val_accuracy = 0.7 + step * 0.1\n\n    run.log(\n        {\n            \"train/loss\": train_loss,\n            \"val/accuracy\": val_accuracy,\n            \"epoch\": step,\n        },\n        step=step,\n    )\n\nrun.finish()\n```\n\nThe reference docs call out that custom `step` values must be monotonically increasing. If you omit `step`, W&B manages the internal step counter for you.\n\n### Update Run Config\n\nUse the run config for values you will want to filter or compare later.\n\n```python\nimport wandb\n\nrun = wandb.init(project=\"demo-project\", config={\"optimizer\": \"adam\"})\nrun.config.update({\"dropout\": 0.2, \"seed\": 42})\nrun.finish()\n```\n\n### Log Artifacts\n\nArtifacts are the right abstraction for model files, evaluation outputs, and reusable datasets.\n\n```python\nfrom pathlib import Path\nimport wandb\n\nrun = wandb.init(project=\"demo-project\")\n\ncheckpoint = Path(\"checkpoints/model.pt\")\n\nartifact = wandb.Artifact(\n    name=\"mnist-model\",\n    type=\"model\",\n    metadata={\"framework\": \"pytorch\"},\n)\nartifact.add_file(checkpoint)\n\nrun.log_artifact(artifact)\nrun.finish()\n```\n\nFor directories, use `artifact.add_dir(...)`. For later consumption, use the Artifact APIs rather than treating saved files as anonymous blobs.\n\n### Offline Or Disabled Modes\n\nFor disconnected environments:\n\n```python\nimport wandb\n\nrun = wandb.init(project=\"demo-project\", mode=\"offline\")\nrun.log({\"loss\": 0.42})\nrun.finish()\n```\n\nUse `mode=\"offline\"` when you still want local run data and plan to sync later. Use `mode=\"disabled\"` for tests or code paths where W&B should become a no-op.\n\n## Config And Auth Guidance\n\n- Prefer environment variables for secrets and defaults instead of hard-coding API keys, project names, or team names.\n- In CI, set `WANDB_API_KEY`, `WANDB_ENTITY`, and `WANDB_PROJECT` explicitly.\n- In containers or ephemeral jobs, set `WANDB_DIR` to a writable persistent location if you need local run files after process exit.\n- For self-hosted W&B, keep `WANDB_BASE_URL` and the `host=` argument consistent across login and later API use.\n- If you resume runs, keep the run `id` stable and use the documented `resume` mode intentionally; otherwise W&B may create a new run instead of continuing the old one.\n\n## Common Pitfalls\n\n- Docs version mismatch: the reference landing page still shows `0.25.0`, but PyPI is `0.25.1`. Use PyPI for package-version truth and the current reference pages for API shapes.\n- Logging before initialization: call `wandb.init()` first. Keep the returned `run` object and log through it.\n- Multiple runs in one process: finish the current run before starting another. If the program intentionally creates multiple runs, configure `reinit` instead of relying on implicit behavior.\n- Non-monotonic steps: if you pass `step=...`, it must only move forward.\n- Wrong runtime mode: `offline` still writes local run data, while `disabled` suppresses tracking. Pick the mode that matches the environment.\n- Missing local write permissions: W&B writes local run metadata and artifact staging files. Set `WANDB_DIR` when the default working directory is not appropriate.\n- Self-hosted auth drift: if the API key belongs to a different W&B host than `WANDB_BASE_URL`, login and later API calls will fail in confusing ways.\n\n## Version-Sensitive Notes\n\n- This doc targets `wandb` `0.25.1` from PyPI.\n- PyPI currently lists `Requires: Python >=3.9` for `0.25.1`.\n- The docs URL `https://docs.wandb.ai/ref/python/` is still useful as a landing page, but current detailed reference pages are under `https://docs.wandb.ai/models/ref/python/`.\n- Because the landing page version badge still shows `0.25.0`, avoid using the docs site title as the package-version source of truth during automation.\n\n## Practical Guidance For Agents\n\n1. Start with explicit environment configuration: `WANDB_API_KEY`, `WANDB_PROJECT`, and optionally `WANDB_ENTITY`.\n2. Keep `run = wandb.init(...)` in a variable and use `run.log(...)` and `run.log_artifact(...)` rather than relying on implicit global state.\n3. Put hyperparameters and fixed metadata in `config`, and stream time-series values through `run.log(...)`.\n4. Use artifacts for checkpoints, model bundles, datasets, and evaluation outputs you need to version or reuse later.\n5. In tests, use `mode=\"disabled\"`. In disconnected training jobs, use `mode=\"offline\"` and sync later if needed.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/wandb/`\n- PyPI JSON metadata: `https://pypi.org/pypi/wandb/json`\n- Python reference landing page: `https://docs.wandb.ai/ref/python/`\n- `wandb.login()` reference: `https://docs.wandb.ai/models/ref/python/functions/login`\n- `wandb.init()` reference: `https://docs.wandb.ai/models/ref/python/functions/init`\n- `Run` reference: `https://docs.wandb.ai/models/ref/python/experiments/run`\n- `Artifact` reference: `https://docs.wandb.ai/models/ref/python/experiments/artifact`\n- Environment variables: `https://docs.wandb.ai/models/track/environment-variables`\n"
  },
  {
    "path": "content/watchdog/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"watchdog Python package guide for filesystem event monitoring with Observer, event handlers, and watchmedo\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.0.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"watchdog,python,filesystem,events,observer,watchmedo\"\n---\n\n# watchdog Python Package Guide\n\n## Golden Rule\n\nUse `watchdog` for cross-platform filesystem watching in Python, start from the `Observer` plus an event handler, and always stop and `join()` the observer cleanly. For `6.0.0`, trust PyPI and maintainer source for version-specific behavior: the public Read the Docs site still serves old `2.1.5` pages and should be treated as a general guide, not as the exact `6.0.0` API reference.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"watchdog==6.0.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"watchdog==6.0.0\"\npoetry add \"watchdog==6.0.0\"\n```\n\nInstall the optional `watchmedo` CLI extras when you need command-line monitoring helpers or trick-based automation:\n\n```bash\npython -m pip install \"watchdog[watchmedo]==6.0.0\"\n```\n\n## Initialization\n\nThe common pattern is:\n\n1. Create an event handler.\n2. Create an `Observer`.\n3. Schedule a path to watch.\n4. Start the observer.\n5. Keep the process alive.\n6. Stop and `join()` on shutdown.\n\nMinimal example:\n\n```python\nimport time\n\nfrom watchdog.events import FileSystemEventHandler\nfrom watchdog.observers import Observer\n\nclass PrintEvents(FileSystemEventHandler):\n    def on_any_event(self, event):\n        print(event.event_type, event.src_path, \"directory=\" + str(event.is_directory))\n\npath = \".\"\nevent_handler = PrintEvents()\nobserver = Observer()\nobserver.schedule(event_handler, path, recursive=True)\nobserver.start()\n\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    observer.stop()\nfinally:\n    observer.join()\n```\n\nNotes:\n\n- `recursive=False` is the default. Set `recursive=True` explicitly when you need subtree monitoring.\n- `observer.start()` runs worker threads. If your process exits immediately, you will miss events.\n- Always call both `stop()` and `join()`. Stopping without `join()` can leave background threads unfinished.\n\n## Core Usage\n\n### Subclass `FileSystemEventHandler`\n\nOverride only the callbacks you need:\n\n```python\nfrom watchdog.events import FileSystemEventHandler\n\nclass BuildHandler(FileSystemEventHandler):\n    def on_created(self, event):\n        if not event.is_directory:\n            print(\"created:\", event.src_path)\n\n    def on_modified(self, event):\n        if not event.is_directory:\n            print(\"modified:\", event.src_path)\n\n    def on_moved(self, event):\n        print(\"moved:\", event.src_path, \"->\", event.dest_path)\n\n    def on_deleted(self, event):\n        print(\"deleted:\", event.src_path)\n```\n\nUseful callbacks in modern `watchdog` include:\n\n- `on_created`\n- `on_deleted`\n- `on_modified`\n- `on_moved`\n- `on_opened`\n- `on_closed`\n- `on_closed_no_write`\n- `on_any_event`\n\n### Filter with `PatternMatchingEventHandler`\n\nUse the built-in filtering handler instead of hand-rolling glob checks in every callback:\n\n```python\nimport time\n\nfrom watchdog.events import PatternMatchingEventHandler\nfrom watchdog.observers import Observer\n\nclass PythonOnlyHandler(PatternMatchingEventHandler):\n    def __init__(self):\n        super().__init__(\n            patterns=[\"**/*.py\"],\n            ignore_patterns=[\"**/.venv/**\", \"**/__pycache__/**\"],\n            ignore_directories=True,\n            case_sensitive=False,\n        )\n\n    def on_modified(self, event):\n        print(\"python file changed:\", event.src_path)\n\nobserver = Observer()\nobserver.schedule(PythonOnlyHandler(), \".\", recursive=True)\nobserver.start()\n\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    observer.stop()\nfinally:\n    observer.join()\n```\n\nIn `6.0.0`, handlers like `PatternMatchingEventHandler` use keyword-only constructor arguments in the maintainer source. Older blog posts that pass patterns positionally are a migration risk.\n\n### Choose polling explicitly for network filesystems\n\nUse the polling backend when native events are unreliable, especially on CIFS/SMB mounts, some virtualized filesystems, or unusual container bind mounts:\n\n```python\nimport time\n\nfrom watchdog.events import FileSystemEventHandler\nfrom watchdog.observers.polling import PollingObserver\n\nclass Handler(FileSystemEventHandler):\n    def on_any_event(self, event):\n        print(event.event_type, event.src_path)\n\nobserver = PollingObserver(timeout=1.0)\nobserver.schedule(Handler(), \"/mnt/shared\", recursive=True)\nobserver.start()\n\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    observer.stop()\nfinally:\n    observer.join()\n```\n\nPrefer the default `Observer` first, but switch to `PollingObserver` when native backend behavior is inconsistent.\n\n### Use `watchmedo` for local automation\n\n`watchmedo` is the bundled CLI for quick monitoring and shell-command workflows.\n\nExamples:\n\n```bash\nwatchmedo log .\nwatchmedo shell-command --patterns=\"*.py\" --recursive --command='pytest -q' .\n```\n\nThis is useful for local development tasks, but application code should usually use the Python API directly.\n\n## Configuration Notes\n\n`watchdog` does not use API credentials or service authentication. The important configuration is runtime and OS behavior:\n\n- Watch root: schedule the narrowest directory tree that satisfies the task.\n- Recursion: set `recursive=True` only when needed; it increases the watch surface.\n- Filtering: prefer built-in pattern and regex handlers to reduce noisy callbacks.\n- Backend choice: default `Observer` uses a native platform backend when available; `PollingObserver` trades efficiency for portability.\n- Process lifetime: a watcher needs a long-running process or thread owner.\n\nBackend expectations from maintainer docs and repository guidance:\n\n- Linux: inotify\n- macOS: FSEvents or kqueue depending on backend availability\n- BSD: kqueue\n- Windows: `ReadDirectoryChangesW`\n- Fallback: polling\n\n## Common Pitfalls\n\n- Do not trust the version banner on `python-watchdog.readthedocs.io/en/stable/` for `6.0.0`; it currently exposes old `2.1.5` content.\n- Do not forget `observer.join()` after `observer.stop()`.\n- `recursive` is not implied. Missing subtree events usually means you forgot `recursive=True`.\n- File-save behavior varies by editor. Many editors write via temp-file rename, so you may see `created` plus `moved` instead of a simple `modified`.\n- Network shares and mounted volumes may miss native events. Use `PollingObserver` when reproducibility matters more than efficiency.\n- On Linux, large watch trees can hit the inotify watch limit. If you see `OSError: inotify watch limit reached`, raise `fs.inotify.max_user_watches`.\n- On kqueue-based systems, deeply recursive monitoring can consume many file descriptors. Raise `ulimit -n` when needed.\n- Ignore noisy paths like `.git`, `.venv`, `node_modules`, build outputs, and caches unless the task explicitly depends on them.\n\n## Version-Sensitive Notes For `6.0.0`\n\n- PyPI `6.0.0` requires Python `>=3.9`. The older Read the Docs pages still mention older Python support; treat that as historical information.\n- The `6.0.0` release notes drop Python 3.8 support and add support for Python 3.13.\n- If you are migrating from pre-5.x examples, re-check constructor signatures and keyword usage against current maintainer source before copying code.\n- Pattern-filter behavior is version-sensitive across major lines. Keep glob patterns explicit and test them instead of assuming older examples still match the same files.\n\n## Official Sources\n\n- PyPI package page: `https://pypi.org/project/watchdog/`\n- Maintainer docs root: `https://python-watchdog.readthedocs.io/en/stable/`\n- Maintainer repository: `https://github.com/gorakhargosh/watchdog`\n- Maintainer changelog for `6.0.0`: `https://github.com/gorakhargosh/watchdog/blob/v6.0.0/changelog.rst`\n"
  },
  {
    "path": "content/weasyprint/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"WeasyPrint Python package for rendering HTML and CSS documents to PDF\"\nmetadata:\n  languages: \"python\"\n  versions: \"68.1\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"weasyprint,python,pdf,html,css,rendering\"\n---\n\n# WeasyPrint Python Package Guide\n\n## Golden Rule\n\nUse `weasyprint` when you need standards-oriented HTML and CSS rendered to PDF from Python. Start with `HTML(...).write_pdf(...)` for the common case, switch to `HTML(...).render(...)` when you need page inspection or post-processing, always set `base_url` when your HTML contains relative asset paths, and regression-test visual output after upgrades because the maintainers explicitly warn that rendering can change across major releases.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"weasyprint==68.1\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"weasyprint==68.1\"\npoetry add \"weasyprint==68.1\"\n```\n\nWeasyPrint is not just a pure-Python install. The official installation guide requires native rendering libraries such as Pango and related dependencies.\n\nTypical system setup from the upstream install guide:\n\n```bash\n# Debian or Ubuntu\nsudo apt install python3-pip libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz-subset0\npython -m pip install \"weasyprint==68.1\"\n```\n\n```bash\n# macOS\nbrew install python pango libffi\npython -m pip install \"weasyprint==68.1\"\n```\n\nWindows is supported, but the maintainers recommend using the official executable unless you specifically need the Python library in your environment.\n\n## Initialize And Render A PDF\n\nThe smallest useful example renders an HTML string directly to a PDF file:\n\n```python\nfrom weasyprint import HTML\n\nHTML(string=\"<h1>Hello PDF</h1>\").write_pdf(\"report.pdf\")\n```\n\nIf your HTML references local files or relative URLs, pass `base_url` or those assets will not resolve:\n\n```python\nfrom pathlib import Path\n\nfrom weasyprint import HTML\n\nproject_root = Path(__file__).resolve().parent\nhtml = \"\"\"\n<html>\n  <body>\n    <h1>Quarterly Report</h1>\n    <img src=\"assets/logo.png\" alt=\"Logo\">\n  </body>\n</html>\n\"\"\"\n\nHTML(string=html, base_url=project_root).write_pdf(\"report.pdf\")\n```\n\nRender from an existing HTML file:\n\n```python\nfrom weasyprint import HTML\n\nHTML(filename=\"templates/invoice.html\").write_pdf(\"invoice.pdf\")\n```\n\nRender from a URL:\n\n```python\nfrom weasyprint import HTML\n\nHTML(url=\"https://example.com/invoice/123\").write_pdf(\"invoice.pdf\")\n```\n\n## Apply CSS And Fonts\n\nPass stylesheet objects through the `stylesheets` argument. Use a shared `FontConfiguration` when your CSS contains `@font-face`.\n\n```python\nfrom pathlib import Path\n\nfrom weasyprint import CSS, HTML\nfrom weasyprint.text.fonts import FontConfiguration\n\nroot = Path(__file__).resolve().parent\nfont_config = FontConfiguration()\n\nHTML(\n    string=\"\"\"\n    <h1 class=\"title\">Invoice</h1>\n    <p class=\"body\">Rendered with WeasyPrint.</p>\n    \"\"\",\n    base_url=root,\n).write_pdf(\n    \"invoice.pdf\",\n    stylesheets=[CSS(filename=root / \"print.css\", font_config=font_config)],\n    font_config=font_config,\n)\n```\n\nWeasyPrint targets print output, not browser screen rendering. If your CSS has both screen and print assumptions, test the printed result explicitly.\n\n## Use `render()` When You Need Document Metadata\n\n`write_pdf()` is the one-shot path. `render()` returns a `Document` that exposes pages and metadata before you write output.\n\n```python\nfrom weasyprint import HTML\n\ndocument = HTML(filename=\"invoice.html\").render()\n\nprint(len(document.pages))\n\nfirst_page = document.copy(document.pages[:1])\nfirst_page.write_pdf(\"invoice-cover.pdf\")\n\ndocument.write_pdf(\"invoice-full.pdf\")\n```\n\nThis is the right path when you need page counts, subsets, attachments, or further processing before the final PDF is written.\n\n## Template-Driven Usage\n\nWeasyPrint is often paired with Jinja2 or a web framework that renders HTML first and then hands the final HTML string to WeasyPrint.\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\nfrom weasyprint import HTML\n\nenv = Environment(loader=FileSystemLoader(\"templates\"))\ntemplate = env.get_template(\"invoice.html\")\n\nhtml = template.render(\n    invoice_number=\"INV-2026-001\",\n    customer_name=\"Ada Lovelace\",\n    total=\"$125.00\",\n)\n\nHTML(string=html, base_url=\"templates\").write_pdf(\"invoice.pdf\")\n```\n\nMake sure the `base_url` points at the directory that contains any relative CSS, images, or font files referenced by the rendered template.\n\n## Resource Fetching, Auth, And Custom Inputs\n\nWeasyPrint can fetch external resources while resolving images, stylesheets, fonts, and linked attachments. There is no built-in auth layer for your application, so authenticated resources usually require a custom fetcher.\n\nIn the 68.x line, the maintainers introduced the `weasyprint.URLFetcher` class and deprecated the older `default_url_fetcher` function. Use the class-based approach for new code.\n\nExample with a bearer token for protected assets:\n\n```python\nfrom weasyprint import HTML\nfrom weasyprint.urls import URLFetcher\n\nclass AuthFetcher(URLFetcher):\n    def __init__(self, token: str) -> None:\n        super().__init__(timeout=20)\n        self.token = token\n\n    def fetch(self, url, headers=None):\n        request_headers = dict(headers or {})\n        request_headers[\"Authorization\"] = f\"Bearer {self.token}\"\n        return super().fetch(url, headers=request_headers)\n\nfetcher = AuthFetcher(token=\"secret-token\")\n\nHTML(\n    string='<img src=\"https://internal.example.com/logo.png\">',\n    url_fetcher=fetcher,\n).write_pdf(\"secured-assets.pdf\")\n```\n\nTypical reasons to provide a custom fetcher:\n\n- add HTTP headers, cookies, or bearer tokens for protected assets\n- block outbound network access and only allow local or approved URLs\n- rewrite application-specific URLs before WeasyPrint fetches them\n- inject a shared cache or custom timeout policy\n\nIf you accept untrusted HTML or CSS, do not allow arbitrary network or filesystem access through resource URLs. The security guide calls out risks around untrusted input, infinite requests, local file access, and SVG handling.\n\n## CLI Usage\n\nThe command-line tool is useful for debugging the same rendering stack outside your app:\n\n```bash\nweasyprint input.html output.pdf\n```\n\nThis is useful when you want to distinguish \"template generation is wrong\" from \"WeasyPrint rendering is wrong\".\n\n## Common Pitfalls\n\n- Relative assets break silently unless you pass `base_url`.\n- Missing native libraries cause import or rendering failures even when `pip install` succeeds.\n- WeasyPrint logs unsupported CSS and recoverable issues; check logs instead of assuming the PDF is faithful.\n- Browser layout expectations do not always match paged-media output. Test page breaks, counters, headers, and print CSS directly.\n- Remote resources can make rendering slow or non-deterministic. Prefer local assets or a controlled fetcher in production.\n- If you use `@font-face`, pass the same `FontConfiguration` to both `CSS(...)` and `write_pdf(...)`.\n- Rendering untrusted HTML, CSS, or SVG without sandboxing is risky. Restrict network and filesystem access and cap input size and render time.\n\n## Version-Sensitive Notes For 68.1\n\n- PyPI currently lists `68.1`, and the stable docs are aligned with that release.\n- The stable changelog notes a security fix in `68.0` for a vulnerability involving SVG `use` tags and another fix related to attachments. Treat pre-68.0 deployments as higher risk if they process untrusted content.\n- `68.0` deprecated `default_url_fetcher` in favor of `weasyprint.URLFetcher`. New integrations should adopt the class-based fetcher rather than building new code on the deprecated function.\n- The maintainers explicitly state that each major version can change PDF rendering, even when the public API stays mostly stable. Always regression-test generated PDFs before rolling out a major upgrade.\n\n## Official Source URLs\n\n- Stable docs: `https://doc.courtbouillon.org/weasyprint/stable/`\n- First steps: `https://doc.courtbouillon.org/weasyprint/stable/first_steps.html`\n- Installation: `https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation`\n- API reference: `https://doc.courtbouillon.org/weasyprint/stable/api_reference.html`\n- Changelog: `https://doc.courtbouillon.org/weasyprint/stable/changelog.html`\n- Security guide: `https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#security`\n- PyPI: `https://pypi.org/project/weasyprint/`\n"
  },
  {
    "path": "content/weaviate/docs/vector-db/javascript/DOC.md",
    "content": "---\nname: vector-db\ndescription: \"Weaviate TypeScript/JavaScript SDK (v3) for vector database operations and semantic search\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"3.9.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"weaviate,vector-db,search,embeddings,ai\"\n---\n\n# Weaviate TypeScript/JavaScript SDK (v3)\n\n## Golden Rule\n\n**ALWAYS use the official `weaviate-client` package (v3.x).**\n\n```bash\nnpm install weaviate-client\n```\n\n**NEVER use:**\n- `weaviate-ts-client` (deprecated)\n- The v2 client (deprecated as of 2024)\n- Unofficial or outdated packages\n\nThe v3 client uses gRPC for 60-80% faster performance, first-class TypeScript support, and modern ES Modules.\n\n---\n\n## Installation\n\n### Install the Client\n\n```bash\nnpm install weaviate-client\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```env\nWEAVIATE_URL=https://your-instance.weaviate.network\nWEAVIATE_API_KEY=your-api-key-here\nOPENAI_API_KEY=your-openai-key-here\n```\n\n---\n\n## Initialization\n\n### Connect to Weaviate Cloud\n\n```typescript\nimport weaviate, { WeaviateClient } from 'weaviate-client';\n\nconst client: WeaviateClient = await weaviate.connectToWeaviateCloud(\n  process.env.WEAVIATE_URL!,\n  {\n    authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY!),\n    headers: {\n      'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY!,\n    }\n  }\n);\n\nconsole.log('Connected to Weaviate');\n```\n\n### Connect to Local Instance\n\n```typescript\nimport weaviate from 'weaviate-client';\n\nconst client = await weaviate.connectToLocal({\n  host: 'localhost',\n  port: 8080,\n  grpcPort: 50051,\n  headers: {\n    'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY!,\n  }\n});\n```\n\n### Custom Connection\n\n```typescript\nimport weaviate from 'weaviate-client';\n\nconst client = await weaviate.connectToCustom({\n  httpHost: 'weaviate.example.com',\n  httpPort: 443,\n  httpSecure: true,\n  grpcHost: 'grpc.weaviate.example.com',\n  grpcPort: 443,\n  grpcSecure: true,\n  authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY!),\n  headers: {\n    'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY!,\n  }\n});\n```\n\n### Close Connection\n\n```typescript\nawait client.close();\n```\n\n---\n\n## Collections\n\n### Create a Collection\n\n#### Basic Collection\n\n```typescript\nimport { dataType } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n    { name: 'author', dataType: dataType.TEXT },\n    { name: 'publishDate', dataType: dataType.DATE },\n    { name: 'viewCount', dataType: dataType.INT },\n  ],\n});\n```\n\n#### Collection with Vectorizer\n\n```typescript\nimport { configure, dataType } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  vectorizers: configure.vectorizer.text2VecOpenAI({\n    model: 'text-embedding-3-small',\n  }),\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n    { name: 'author', dataType: dataType.TEXT },\n  ],\n});\n```\n\n#### Collection with Multiple Named Vectors\n\n```typescript\nimport { configure, dataType } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'MultiModalArticle',\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n    { name: 'image', dataType: dataType.BLOB },\n  ],\n  vectorizers: [\n    configure.namedVectors.text2VecOpenAI('text_vector', {\n      sourceProperties: ['title', 'body'],\n    }),\n    configure.namedVectors.multi2VecClip('image_vector', {\n      imageFields: ['image'],\n    }),\n  ],\n});\n```\n\n#### Collection with Generative Module\n\n```typescript\nimport { configure, dataType } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  vectorizers: configure.vectorizer.text2VecOpenAI(),\n  generative: configure.generative.openAI({\n    model: 'gpt-4',\n  }),\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n  ],\n});\n```\n\n### List All Collections\n\n```typescript\nconst collections = await client.collections.listAll();\nconsole.log(collections);\n```\n\n### Get a Collection Reference\n\n```typescript\nconst articles = client.collections.get('Article');\n```\n\n### Delete a Collection\n\n```typescript\nawait client.collections.delete('Article');\n```\n\n### Check if Collection Exists\n\n```typescript\nconst exists = await client.collections.exists('Article');\nconsole.log(`Collection exists: ${exists}`);\n```\n\n---\n\n## Data Types\n\n### Available Data Types\n\n```typescript\nimport { dataType } from 'weaviate-client';\n\n// Text types\ndataType.TEXT          // Single text value\ndataType.TEXT_ARRAY    // Array of text values\n\n// Numeric types\ndataType.NUMBER        // Float/double\ndataType.INT           // Integer\ndataType.INT_ARRAY     // Array of integers\ndataType.NUMBER_ARRAY  // Array of numbers\n\n// Boolean\ndataType.BOOLEAN       // True/false\ndataType.BOOLEAN_ARRAY // Array of booleans\n\n// Date and UUID\ndataType.DATE          // ISO 8601 date-time\ndataType.DATE_ARRAY    // Array of dates\ndataType.UUID          // UUID\ndataType.UUID_ARRAY    // Array of UUIDs\n\n// Binary data\ndataType.BLOB          // Base64 encoded binary data\ndataType.BLOB_ARRAY    // Array of blobs\n\n// Geolocation\ndataType.GEO_COORDINATES // { latitude: number, longitude: number }\n\n// Object reference\ndataType.OBJECT        // Nested object\ndataType.OBJECT_ARRAY  // Array of nested objects\n```\n\n---\n\n## Insert Data\n\n### Insert Single Object\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst uuid = await articles.data.insert({\n  title: 'Weaviate is Amazing',\n  body: 'A comprehensive guide to vector databases',\n  author: 'John Doe',\n  publishDate: new Date('2024-01-15').toISOString(),\n  viewCount: 1250,\n});\n\nconsole.log(`Inserted object with UUID: ${uuid}`);\n```\n\n### Insert with Custom UUID\n\n```typescript\nimport { generateUuid5 } from 'weaviate-client';\n\nconst myUuid = generateUuid5('my-unique-id');\n\nawait articles.data.insert({\n  title: 'Custom UUID Article',\n  body: 'Article with custom UUID',\n}, { uuid: myUuid });\n```\n\n### Insert with Vector\n\n```typescript\nconst uuid = await articles.data.insert({\n  title: 'Manual Vector Article',\n  body: 'Article with manually provided vector',\n}, {\n  vector: [0.1, 0.2, 0.3, ...], // Your embedding vector\n});\n```\n\n### Batch Insert (insertMany)\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst dataObjects = [\n  {\n    title: 'First Article',\n    body: 'Content of first article',\n    author: 'Jane Smith',\n  },\n  {\n    title: 'Second Article',\n    body: 'Content of second article',\n    author: 'Bob Johnson',\n  },\n  {\n    title: 'Third Article',\n    body: 'Content of third article',\n    author: 'Alice Williams',\n  },\n];\n\nconst response = await articles.data.insertMany(dataObjects);\n\nconsole.log(`Inserted ${response.uuids.length} objects`);\nconsole.log('UUIDs:', response.uuids);\n\n// Check for errors\nif (response.hasErrors) {\n  console.error('Errors occurred:', response.errors);\n}\n```\n\n### Batch Insert with Vectors\n\n```typescript\nconst dataWithVectors = [\n  {\n    title: 'Article 1',\n    body: 'Content 1',\n    vector: [0.1, 0.2, 0.3],\n  },\n  {\n    title: 'Article 2',\n    body: 'Content 2',\n    vector: [0.4, 0.5, 0.6],\n  },\n];\n\nawait articles.data.insertMany(dataWithVectors);\n```\n\n---\n\n## Query Data\n\n### Fetch Objects (No Search)\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst result = await articles.query.fetchObjects({\n  limit: 10,\n  offset: 0,\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n  console.log(`UUID: ${object.uuid}`);\n}\n```\n\n### Fetch by ID\n\n```typescript\nconst object = await articles.query.fetchObjectById(uuid);\nconsole.log(object?.properties);\n```\n\n### Fetch with Filters\n\n```typescript\nconst result = await articles.query.fetchObjects({\n  filters: articles.filter.byProperty('viewCount').greaterThan(1000),\n  limit: 5,\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n---\n\n## Vector Search\n\n### nearText Search\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst result = await articles.query.nearText('vector databases', {\n  limit: 5,\n  returnMetadata: ['distance', 'score'],\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n  console.log(`Distance: ${object.metadata?.distance}`);\n  console.log(`Score: ${object.metadata?.score}`);\n}\n```\n\n### nearText with Filters\n\n```typescript\nconst result = await articles.query.nearText('machine learning', {\n  limit: 3,\n  filters: articles.filter.byProperty('author').equal('John Doe'),\n  returnMetadata: ['distance'],\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n### nearVector Search\n\n```typescript\nconst queryVector = [0.1, 0.2, 0.3, ...]; // Your query vector\n\nconst result = await articles.query.nearVector(queryVector, {\n  limit: 5,\n  returnMetadata: ['distance'],\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n### nearObject Search\n\n```typescript\nconst result = await articles.query.nearObject(existingUuid, {\n  limit: 5,\n  returnMetadata: ['distance'],\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n---\n\n## Hybrid Search\n\nHybrid search combines keyword (BM25) and vector search.\n\n### Basic Hybrid Search\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst result = await articles.query.hybrid('artificial intelligence', {\n  limit: 10,\n  alpha: 0.5, // 0 = pure keyword, 1 = pure vector, 0.5 = balanced\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n### Hybrid Search with Filters\n\n```typescript\nconst result = await articles.query.hybrid('deep learning', {\n  limit: 5,\n  alpha: 0.75,\n  filters: articles.filter.byProperty('publishDate').greaterThan(\n    new Date('2024-01-01').toISOString()\n  ),\n  returnMetadata: ['score'],\n});\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n  console.log(`Score: ${object.metadata?.score}`);\n}\n```\n\n### Hybrid Search with Vector\n\n```typescript\nconst result = await articles.query.hybrid('machine learning', {\n  limit: 5,\n  alpha: 0.5,\n  vector: [0.1, 0.2, 0.3, ...], // Optional manual vector\n});\n```\n\n---\n\n## Filters\n\n### Basic Filters\n\n```typescript\nconst articles = client.collections.get('Article');\n\n// Equal\narticles.filter.byProperty('author').equal('John Doe')\n\n// Not Equal\narticles.filter.byProperty('author').notEqual('Jane Smith')\n\n// Greater Than\narticles.filter.byProperty('viewCount').greaterThan(1000)\n\n// Greater Than or Equal\narticles.filter.byProperty('viewCount').greaterOrEqual(500)\n\n// Less Than\narticles.filter.byProperty('viewCount').lessThan(2000)\n\n// Less Than or Equal\narticles.filter.byProperty('viewCount').lessOrEqual(1500)\n\n// Like (text contains)\narticles.filter.byProperty('title').like('*vector*')\n\n// Contains Any\narticles.filter.byProperty('author').containsAny(['John Doe', 'Jane Smith'])\n\n// Is Null\narticles.filter.byProperty('author').isNull(true)\n```\n\n### Combining Filters (AND)\n\n```typescript\nconst result = await articles.query.fetchObjects({\n  filters: articles.filter\n    .byProperty('viewCount').greaterThan(1000)\n    .and()\n    .byProperty('author').equal('John Doe'),\n  limit: 10,\n});\n```\n\n### Combining Filters (OR)\n\n```typescript\nconst result = await articles.query.fetchObjects({\n  filters: articles.filter\n    .byProperty('author').equal('John Doe')\n    .or()\n    .byProperty('author').equal('Jane Smith'),\n  limit: 10,\n});\n```\n\n### Complex Filter Combinations\n\n```typescript\nconst result = await articles.query.fetchObjects({\n  filters: articles.filter\n    .byProperty('viewCount').greaterThan(500)\n    .and()\n    .byProperty('publishDate').greaterThan(new Date('2024-01-01').toISOString())\n    .or()\n    .byProperty('author').equal('John Doe'),\n  limit: 10,\n});\n```\n\n---\n\n## Generative Search (RAG)\n\nGenerative search pipes search results through an LLM.\n\n### Single Result Generation\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst result = await articles.generate.nearText('AI trends', {\n  singlePrompt: 'Summarize this article in one sentence: {title} - {body}',\n  limit: 5,\n});\n\nfor (const object of result.objects) {\n  console.log('Article:', object.properties);\n  console.log('Generated:', object.generated);\n}\n```\n\n### Grouped Task Generation\n\n```typescript\nconst result = await articles.generate.nearText('machine learning', {\n  groupedTask: 'Write a brief overview summarizing these articles about machine learning',\n  limit: 5,\n});\n\nconsole.log('Generated summary:', result.generated);\n\nfor (const object of result.objects) {\n  console.log('Source article:', object.properties.title);\n}\n```\n\n### Both Single and Grouped\n\n```typescript\nconst result = await articles.generate.nearText('neural networks', {\n  singlePrompt: 'Explain this in simple terms: {body}',\n  groupedTask: 'Create a comprehensive guide based on all these articles',\n  limit: 5,\n});\n\nfor (const object of result.objects) {\n  console.log('Article:', object.properties.title);\n  console.log('Individual generation:', object.generated);\n}\n\nconsole.log('Grouped generation:', result.generated);\n```\n\n### Generative Search with Filters\n\n```typescript\nconst result = await articles.generate.nearText('databases', {\n  singlePrompt: 'Summarize: {title}',\n  limit: 3,\n  filters: articles.filter.byProperty('author').equal('John Doe'),\n});\n```\n\n### Generate with nearVector\n\n```typescript\nconst queryVector = [0.1, 0.2, 0.3, ...];\n\nconst result = await articles.generate.nearVector(queryVector, {\n  groupedTask: 'Create a summary of these related articles',\n  limit: 5,\n});\n\nconsole.log(result.generated);\n```\n\n---\n\n## Update Data\n\n### Update Object\n\n```typescript\nconst articles = client.collections.get('Article');\n\nawait articles.data.update({\n  id: uuid,\n  properties: {\n    viewCount: 2000,\n    title: 'Updated Title',\n  },\n});\n```\n\n### Replace Object\n\nReplace replaces the entire object (not a merge).\n\n```typescript\nawait articles.data.replace({\n  id: uuid,\n  properties: {\n    title: 'Completely New Title',\n    body: 'Completely new body',\n    author: 'New Author',\n    publishDate: new Date().toISOString(),\n    viewCount: 0,\n  },\n});\n```\n\n---\n\n## Delete Data\n\n### Delete by ID\n\n```typescript\nconst articles = client.collections.get('Article');\n\nawait articles.data.deleteById(uuid);\nconsole.log('Object deleted');\n```\n\n### Delete Many by Filter\n\n```typescript\nconst response = await articles.data.deleteMany(\n  articles.filter.byProperty('viewCount').lessThan(100)\n);\n\nconsole.log(`Deleted ${response.successful} objects`);\nconsole.log(`Failed: ${response.failed}`);\n```\n\n### Delete All Objects in Collection\n\n```typescript\nawait articles.data.deleteMany(\n  articles.filter.byProperty('title').like('*')\n);\n```\n\n---\n\n## Aggregations\n\n### Count Objects\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst result = await articles.aggregate.overAll();\nconsole.log(`Total objects: ${result.totalCount}`);\n```\n\n### Count with Filter\n\n```typescript\nconst result = await articles.aggregate.overAll({\n  filters: articles.filter.byProperty('author').equal('John Doe'),\n});\n\nconsole.log(`Objects by John Doe: ${result.totalCount}`);\n```\n\n### Aggregate Numeric Properties\n\n```typescript\nconst result = await articles.aggregate.overAll({\n  returnMetrics: articles.metrics.number('viewCount').maximum(),\n});\n\nconsole.log(`Max views: ${result.properties.viewCount?.maximum}`);\n```\n\n### Multiple Aggregations\n\n```typescript\nconst result = await articles.aggregate.overAll({\n  returnMetrics: [\n    articles.metrics.number('viewCount').sum(),\n    articles.metrics.number('viewCount').average(),\n    articles.metrics.number('viewCount').minimum(),\n    articles.metrics.number('viewCount').maximum(),\n  ],\n});\n\nconsole.log('View count stats:', result.properties.viewCount);\n```\n\n---\n\n## Multi-Tenancy\n\n### Create Collection with Multi-Tenancy\n\n```typescript\nimport { configure, dataType } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  multiTenancyConfig: configure.multiTenancy({ enabled: true }),\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n  ],\n});\n```\n\n### Add Tenants\n\n```typescript\nconst articles = client.collections.get('Article');\n\nawait articles.tenants.create([\n  { name: 'tenant1' },\n  { name: 'tenant2' },\n  { name: 'tenant3' },\n]);\n```\n\n### Get Tenant Reference\n\n```typescript\nconst tenant1Articles = articles.withTenant('tenant1');\n```\n\n### Insert Data for Tenant\n\n```typescript\nawait tenant1Articles.data.insert({\n  title: 'Tenant 1 Article',\n  body: 'This belongs to tenant 1',\n});\n```\n\n### Query Tenant Data\n\n```typescript\nconst result = await tenant1Articles.query.fetchObjects({ limit: 10 });\n\nfor (const object of result.objects) {\n  console.log(object.properties);\n}\n```\n\n### List Tenants\n\n```typescript\nconst tenants = await articles.tenants.get();\nconsole.log(tenants);\n```\n\n### Remove Tenant\n\n```typescript\nawait articles.tenants.remove(['tenant3']);\n```\n\n---\n\n## Batch Operations\n\n### Batch with Error Handling\n\n```typescript\nconst articles = client.collections.get('Article');\n\nconst data = [\n  { title: 'Article 1', body: 'Content 1', author: 'Author 1' },\n  { title: 'Article 2', body: 'Content 2', author: 'Author 2' },\n  { title: 'Article 3', body: 'Content 3', author: 'Author 3' },\n];\n\nconst response = await articles.data.insertMany(data);\n\nif (response.hasErrors) {\n  console.error('Batch insert had errors:');\n  for (let i = 0; i < response.errors.length; i++) {\n    if (response.errors[i]) {\n      console.error(`Object ${i}: ${response.errors[i]?.message}`);\n    }\n  }\n}\n\nconsole.log(`Successfully inserted: ${response.uuids.length} objects`);\n```\n\n---\n\n## Cross-References\n\n### Define Collection with Reference\n\n```typescript\nimport { dataType } from 'weaviate-client';\n\n// Create Author collection\nawait client.collections.create({\n  name: 'Author',\n  properties: [\n    { name: 'name', dataType: dataType.TEXT },\n    { name: 'bio', dataType: dataType.TEXT },\n  ],\n});\n\n// Create Article collection with reference to Author\nawait client.collections.create({\n  name: 'Article',\n  properties: [\n    { name: 'title', dataType: dataType.TEXT },\n    { name: 'body', dataType: dataType.TEXT },\n  ],\n  references: [\n    {\n      name: 'hasAuthor',\n      targetCollection: 'Author',\n    },\n  ],\n});\n```\n\n### Insert with Reference\n\n```typescript\nconst authors = client.collections.get('Author');\nconst articles = client.collections.get('Article');\n\n// Insert author\nconst authorUuid = await authors.data.insert({\n  name: 'John Doe',\n  bio: 'Expert in AI',\n});\n\n// Insert article with reference\nawait articles.data.insert({\n  title: 'AI Article',\n  body: 'Content about AI',\n}, {\n  references: {\n    hasAuthor: authorUuid,\n  },\n});\n```\n\n### Query with References\n\n```typescript\nconst result = await articles.query.fetchObjects({\n  limit: 10,\n  returnReferences: [{\n    linkOn: 'hasAuthor',\n    returnProperties: ['name', 'bio'],\n  }],\n});\n\nfor (const object of result.objects) {\n  console.log('Article:', object.properties);\n  console.log('Author:', object.references?.hasAuthor);\n}\n```\n\n---\n\n## Advanced Configurations\n\n### Collection with Custom Vectorizer Settings\n\n```typescript\nimport { configure, dataType, vectorDistances } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  vectorizers: configure.vectorizer.text2VecOpenAI({\n    model: 'text-embedding-3-large',\n    dimensions: 1536,\n    vectorizeCollectionName: false,\n  }),\n  vectorIndexConfig: configure.vectorIndex.hnsw({\n    distanceMetric: vectorDistances.COSINE,\n    efConstruction: 128,\n    maxConnections: 64,\n  }),\n  properties: [\n    {\n      name: 'title',\n      dataType: dataType.TEXT,\n      vectorizePropertyName: false,\n      skipVectorization: false,\n    },\n    {\n      name: 'body',\n      dataType: dataType.TEXT,\n    },\n    {\n      name: 'metadata',\n      dataType: dataType.TEXT,\n      skipVectorization: true, // Don't vectorize this property\n    },\n  ],\n});\n```\n\n### Collection with Inverted Index Config\n\n```typescript\nimport { configure, dataType, tokenization } from 'weaviate-client';\n\nawait client.collections.create({\n  name: 'Article',\n  properties: [\n    {\n      name: 'title',\n      dataType: dataType.TEXT,\n      tokenization: tokenization.WORD,\n      indexFilterable: true,\n      indexSearchable: true,\n    },\n    {\n      name: 'sku',\n      dataType: dataType.TEXT,\n      tokenization: tokenization.FIELD, // Exact match only\n      indexFilterable: true,\n      indexSearchable: false,\n    },\n  ],\n  invertedIndexConfig: configure.invertedIndex({\n    indexTimestamps: true,\n    indexNullState: true,\n    indexPropertyLength: true,\n  }),\n});\n```\n\n---\n\n## Error Handling\n\n### Try-Catch Pattern\n\n```typescript\nimport weaviate from 'weaviate-client';\n\ntry {\n  const client = await weaviate.connectToWeaviateCloud(\n    process.env.WEAVIATE_URL!,\n    {\n      authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY!),\n    }\n  );\n\n  const articles = client.collections.get('Article');\n\n  const result = await articles.query.nearText('AI', { limit: 5 });\n\n  for (const object of result.objects) {\n    console.log(object.properties);\n  }\n\n  await client.close();\n} catch (error) {\n  console.error('Error:', error);\n}\n```\n\n### Batch Insert Error Handling\n\n```typescript\nconst response = await articles.data.insertMany(dataObjects);\n\nif (response.hasErrors) {\n  response.errors.forEach((error, index) => {\n    if (error) {\n      console.error(`Error at index ${index}:`, error.message);\n    }\n  });\n}\n\nconsole.log('Successful UUIDs:', response.uuids.filter(uuid => uuid !== null));\n```\n\n---\n\n## Complete Example\n\n```typescript\nimport weaviate, { WeaviateClient, dataType, configure } from 'weaviate-client';\n\nasync function main() {\n  // Connect\n  const client: WeaviateClient = await weaviate.connectToWeaviateCloud(\n    process.env.WEAVIATE_URL!,\n    {\n      authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY!),\n      headers: {\n        'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY!,\n      }\n    }\n  );\n\n  console.log('Connected to Weaviate');\n\n  // Create collection\n  await client.collections.create({\n    name: 'Article',\n    vectorizers: configure.vectorizer.text2VecOpenAI({\n      model: 'text-embedding-3-small',\n    }),\n    generative: configure.generative.openAI({\n      model: 'gpt-4',\n    }),\n    properties: [\n      { name: 'title', dataType: dataType.TEXT },\n      { name: 'body', dataType: dataType.TEXT },\n      { name: 'author', dataType: dataType.TEXT },\n      { name: 'publishDate', dataType: dataType.DATE },\n      { name: 'viewCount', dataType: dataType.INT },\n    ],\n  });\n\n  console.log('Collection created');\n\n  // Get collection reference\n  const articles = client.collections.get('Article');\n\n  // Insert data\n  const dataObjects = [\n    {\n      title: 'Vector Databases Explained',\n      body: 'A comprehensive guide to understanding vector databases and their applications in modern AI systems.',\n      author: 'John Doe',\n      publishDate: new Date('2024-01-15').toISOString(),\n      viewCount: 1250,\n    },\n    {\n      title: 'Machine Learning in Production',\n      body: 'Best practices for deploying machine learning models in production environments.',\n      author: 'Jane Smith',\n      publishDate: new Date('2024-02-20').toISOString(),\n      viewCount: 2100,\n    },\n    {\n      title: 'Introduction to RAG',\n      body: 'Retrieval Augmented Generation combines search with language models for better responses.',\n      author: 'John Doe',\n      publishDate: new Date('2024-03-10').toISOString(),\n      viewCount: 890,\n    },\n  ];\n\n  const insertResponse = await articles.data.insertMany(dataObjects);\n  console.log(`Inserted ${insertResponse.uuids.length} articles`);\n\n  // Vector search\n  console.log('\\n--- Vector Search ---');\n  const searchResult = await articles.query.nearText('AI and databases', {\n    limit: 2,\n    returnMetadata: ['distance', 'score'],\n  });\n\n  for (const object of searchResult.objects) {\n    console.log(`\\nTitle: ${object.properties.title}`);\n    console.log(`Author: ${object.properties.author}`);\n    console.log(`Score: ${object.metadata?.score}`);\n  }\n\n  // Filtered search\n  console.log('\\n--- Filtered Search ---');\n  const filteredResult = await articles.query.nearText('machine learning', {\n    limit: 3,\n    filters: articles.filter.byProperty('viewCount').greaterThan(1000),\n  });\n\n  for (const object of filteredResult.objects) {\n    console.log(`\\nTitle: ${object.properties.title}`);\n    console.log(`Views: ${object.properties.viewCount}`);\n  }\n\n  // Hybrid search\n  console.log('\\n--- Hybrid Search ---');\n  const hybridResult = await articles.query.hybrid('production deployment', {\n    limit: 2,\n    alpha: 0.5,\n  });\n\n  for (const object of hybridResult.objects) {\n    console.log(`\\nTitle: ${object.properties.title}`);\n  }\n\n  // Generative search (RAG)\n  console.log('\\n--- Generative Search ---');\n  const ragResult = await articles.generate.nearText('vector databases', {\n    singlePrompt: 'Summarize this article in one sentence: {title}',\n    groupedTask: 'Write a brief paragraph about these articles',\n    limit: 2,\n  });\n\n  console.log('\\nGrouped generation:');\n  console.log(ragResult.generated);\n\n  for (const object of ragResult.objects) {\n    console.log(`\\n${object.properties.title}`);\n    console.log(`Summary: ${object.generated}`);\n  }\n\n  // Aggregate\n  console.log('\\n--- Aggregations ---');\n  const aggResult = await articles.aggregate.overAll({\n    returnMetrics: [\n      articles.metrics.number('viewCount').sum(),\n      articles.metrics.number('viewCount').average(),\n      articles.metrics.number('viewCount').maximum(),\n    ],\n  });\n\n  console.log(`Total articles: ${aggResult.totalCount}`);\n  console.log(`Total views: ${aggResult.properties.viewCount?.sum}`);\n  console.log(`Average views: ${aggResult.properties.viewCount?.average}`);\n  console.log(`Max views: ${aggResult.properties.viewCount?.maximum}`);\n\n  // Update\n  const firstUuid = insertResponse.uuids[0];\n  await articles.data.update({\n    id: firstUuid,\n    properties: {\n      viewCount: 1500,\n    },\n  });\n  console.log('\\nUpdated first article view count');\n\n  // Delete by filter\n  const deleteResult = await articles.data.deleteMany(\n    articles.filter.byProperty('viewCount').lessThan(900)\n  );\n  console.log(`\\nDeleted ${deleteResult.successful} low-view articles`);\n\n  // Cleanup\n  await client.collections.delete('Article');\n  console.log('\\nCollection deleted');\n\n  await client.close();\n  console.log('Connection closed');\n}\n\nmain().catch(console.error);\n```\n\n---\n\n## TypeScript Types\n\n```typescript\nimport type {\n  WeaviateClient,\n  Collection,\n  QueryReturn,\n  GenerativeReturn,\n} from 'weaviate-client';\n\n// Collection reference type\nconst articles: Collection<{\n  title: string;\n  body: string;\n  author: string;\n  publishDate: string;\n  viewCount: number;\n}> = client.collections.get('Article');\n\n// Query result type\nconst result: QueryReturn<{\n  title: string;\n  body: string;\n  author: string;\n}> = await articles.query.nearText('AI', { limit: 5 });\n\n// Generative result type\nconst genResult: GenerativeReturn<{\n  title: string;\n  body: string;\n}> = await articles.generate.nearText('AI', {\n  singlePrompt: 'Summarize: {title}',\n});\n```\n"
  },
  {
    "path": "content/weaviate/docs/vector-db/python/DOC.md",
    "content": "---\nname: vector-db\ndescription: \"Weaviate Python SDK (v4) — use the official weaviate-client package for vector database operations\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.17.0\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"weaviate,vector-db,search,embeddings,ai\"\n---\n\n# Weaviate Python SDK (v4)\n\n## Golden Rule\n\n**ALWAYS use the official `weaviate-client` package (v4.x).**\n\n```bash\npip install weaviate-client\n```\n\n**NEVER use:**\n- `weaviate-python-client` (deprecated)\n- The v3 client (deprecated as of 2024)\n- Unofficial or outdated packages\n\nThe v4 client uses gRPC for 60-80% faster performance, typed classes with autocomplete, and is only compatible with Weaviate v1.23.6+.\n\n---\n\n## Installation\n\n### Install the Client\n\n```bash\npip install weaviate-client\n```\n\n### Environment Variables\n\nCreate a `.env` file:\n\n```env\nWEAVIATE_URL=https://your-instance.weaviate.network\nWEAVIATE_API_KEY=your-api-key-here\nOPENAI_API_KEY=your-openai-key-here\n```\n\n### Load Environment Variables\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nWEAVIATE_URL = os.getenv(\"WEAVIATE_URL\")\nWEAVIATE_API_KEY = os.getenv(\"WEAVIATE_API_KEY\")\nOPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n```\n\n---\n\n## Initialization\n\n### Connect to Weaviate Cloud\n\n```python\nimport weaviate\nfrom weaviate.classes.init import Auth\n\nclient = weaviate.connect_to_weaviate_cloud(\n    cluster_url=WEAVIATE_URL,\n    auth_credentials=Auth.api_key(WEAVIATE_API_KEY),\n    headers={\n        \"X-OpenAI-Api-Key\": OPENAI_API_KEY\n    }\n)\n\nprint(\"Connected to Weaviate\")\n```\n\n### Connect to Local Instance\n\n```python\nimport weaviate\n\nclient = weaviate.connect_to_local(\n    host=\"localhost\",\n    port=8080,\n    grpc_port=50051,\n    headers={\n        \"X-OpenAI-Api-Key\": OPENAI_API_KEY\n    }\n)\n```\n\n### Custom Connection\n\n```python\nimport weaviate\nfrom weaviate.classes.init import Auth, AdditionalConfig, Timeout\n\nclient = weaviate.connect_to_custom(\n    http_host=\"weaviate.example.com\",\n    http_port=443,\n    http_secure=True,\n    grpc_host=\"grpc.weaviate.example.com\",\n    grpc_port=443,\n    grpc_secure=True,\n    auth_credentials=Auth.api_key(WEAVIATE_API_KEY),\n    headers={\n        \"X-OpenAI-Api-Key\": OPENAI_API_KEY\n    },\n    additional_config=AdditionalConfig(\n        timeout=Timeout(init=30, query=60, insert=120)\n    )\n)\n```\n\n### Context Manager Pattern\n\n```python\nimport weaviate\nfrom weaviate.classes.init import Auth\n\nwith weaviate.connect_to_weaviate_cloud(\n    cluster_url=WEAVIATE_URL,\n    auth_credentials=Auth.api_key(WEAVIATE_API_KEY)\n) as client:\n    # Your code here\n    collections = client.collections.list_all()\n    print(collections)\n# Connection automatically closed\n```\n\n### Close Connection\n\n```python\nclient.close()\n```\n\n---\n\n## Collections\n\n### Create a Collection\n\n#### Basic Collection\n\n```python\nfrom weaviate.classes.config import Property, DataType\n\nclient.collections.create(\n    name=\"Article\",\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n        Property(name=\"author\", data_type=DataType.TEXT),\n        Property(name=\"publish_date\", data_type=DataType.DATE),\n        Property(name=\"view_count\", data_type=DataType.INT),\n    ],\n)\n```\n\n#### Collection with Vectorizer\n\n```python\nfrom weaviate.classes.config import Configure, Property, DataType\n\nclient.collections.create(\n    name=\"Article\",\n    vectorizer_config=Configure.Vectorizer.text2vec_openai(\n        model=\"text-embedding-3-small\"\n    ),\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n        Property(name=\"author\", data_type=DataType.TEXT),\n    ],\n)\n```\n\n#### Collection with Multiple Named Vectors\n\n```python\nfrom weaviate.classes.config import Configure, Property, DataType\n\nclient.collections.create(\n    name=\"MultiModalArticle\",\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n        Property(name=\"image\", data_type=DataType.BLOB),\n    ],\n    vectorizer_config=[\n        Configure.NamedVectors.text2vec_openai(\n            name=\"text_vector\",\n            source_properties=[\"title\", \"body\"],\n        ),\n        Configure.NamedVectors.multi2vec_clip(\n            name=\"image_vector\",\n            image_fields=[\"image\"],\n        ),\n    ],\n)\n```\n\n#### Collection with Generative Module\n\n```python\nfrom weaviate.classes.config import Configure, Property, DataType\n\nclient.collections.create(\n    name=\"Article\",\n    vectorizer_config=Configure.Vectorizer.text2vec_openai(),\n    generative_config=Configure.Generative.openai(\n        model=\"gpt-4\"\n    ),\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n    ],\n)\n```\n\n### List All Collections\n\n```python\ncollections = client.collections.list_all()\nfor collection_name in collections:\n    print(collection_name)\n```\n\n### Get a Collection Reference\n\n```python\narticles = client.collections.get(\"Article\")\n```\n\n### Delete a Collection\n\n```python\nclient.collections.delete(\"Article\")\n```\n\n### Check if Collection Exists\n\n```python\nexists = client.collections.exists(\"Article\")\nprint(f\"Collection exists: {exists}\")\n```\n\n---\n\n## Data Types\n\n### Available Data Types\n\n```python\nfrom weaviate.classes.config import DataType\n\n# Text types\nDataType.TEXT          # Single text value\nDataType.TEXT_ARRAY    # List of text values\n\n# Numeric types\nDataType.NUMBER        # Float/double\nDataType.INT           # Integer\nDataType.INT_ARRAY     # List of integers\nDataType.NUMBER_ARRAY  # List of numbers\n\n# Boolean\nDataType.BOOL          # True/false\nDataType.BOOL_ARRAY    # List of booleans\n\n# Date and UUID\nDataType.DATE          # ISO 8601 date-time\nDataType.DATE_ARRAY    # List of dates\nDataType.UUID          # UUID\nDataType.UUID_ARRAY    # List of UUIDs\n\n# Binary data\nDataType.BLOB          # Base64 encoded binary data\nDataType.BLOB_ARRAY    # List of blobs\n\n# Geolocation\nDataType.GEO_COORDINATES # {\"latitude\": float, \"longitude\": float}\n\n# Object reference\nDataType.OBJECT        # Nested object\nDataType.OBJECT_ARRAY  # List of nested objects\n```\n\n---\n\n## Insert Data\n\n### Insert Single Object\n\n```python\nfrom datetime import datetime\nfrom weaviate.util import generate_uuid5\n\narticles = client.collections.get(\"Article\")\n\nuuid = articles.data.insert(\n    properties={\n        \"title\": \"Weaviate is Amazing\",\n        \"body\": \"A comprehensive guide to vector databases\",\n        \"author\": \"John Doe\",\n        \"publish_date\": datetime(2024, 1, 15).isoformat(),\n        \"view_count\": 1250,\n    }\n)\n\nprint(f\"Inserted object with UUID: {uuid}\")\n```\n\n### Insert with Custom UUID\n\n```python\nfrom weaviate.util import generate_uuid5\n\nmy_uuid = generate_uuid5(\"my-unique-id\")\n\narticles.data.insert(\n    properties={\n        \"title\": \"Custom UUID Article\",\n        \"body\": \"Article with custom UUID\",\n    },\n    uuid=my_uuid\n)\n```\n\n### Insert with Vector\n\n```python\nuuid = articles.data.insert(\n    properties={\n        \"title\": \"Manual Vector Article\",\n        \"body\": \"Article with manually provided vector\",\n    },\n    vector=[0.1, 0.2, 0.3, ...]  # Your embedding vector\n)\n```\n\n### Batch Insert (Dynamic Batching)\n\n```python\narticles = client.collections.get(\"Article\")\n\ndata_objects = [\n    {\n        \"title\": \"First Article\",\n        \"body\": \"Content of first article\",\n        \"author\": \"Jane Smith\",\n    },\n    {\n        \"title\": \"Second Article\",\n        \"body\": \"Content of second article\",\n        \"author\": \"Bob Johnson\",\n    },\n    {\n        \"title\": \"Third Article\",\n        \"body\": \"Content of third article\",\n        \"author\": \"Alice Williams\",\n    },\n]\n\nwith articles.batch.dynamic() as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n\nprint(f\"Batch insert completed\")\n```\n\n### Batch Insert with Error Handling\n\n```python\narticles = client.collections.get(\"Article\")\n\nwith articles.batch.dynamic() as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n\n    # Check for errors within the context\n    if batch.number_errors > 0:\n        print(f\"Errors occurred: {batch.number_errors}\")\n        for failed in batch.failed_objects:\n            print(f\"Failed: {failed}\")\n```\n\n### Batch Insert with Vectors\n\n```python\ndata_with_vectors = [\n    {\"title\": \"Article 1\", \"body\": \"Content 1\"},\n    {\"title\": \"Article 2\", \"body\": \"Content 2\"},\n]\n\nvectors = [\n    [0.1, 0.2, 0.3, ...],\n    [0.4, 0.5, 0.6, ...],\n]\n\nwith articles.batch.dynamic() as batch:\n    for i, data_obj in enumerate(data_with_vectors):\n        batch.add_object(\n            properties=data_obj,\n            vector=vectors[i]\n        )\n```\n\n### Fixed Size Batching\n\n```python\nwith articles.batch.fixed_size(batch_size=100) as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n```\n\n### Rate Limited Batching\n\n```python\nwith articles.batch.rate_limit(requests_per_minute=600) as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n```\n\n---\n\n## Query Data\n\n### Fetch Objects (No Search)\n\n```python\narticles = client.collections.get(\"Article\")\n\nresponse = articles.query.fetch_objects(\n    limit=10,\n    offset=0\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n    print(f\"UUID: {obj.uuid}\")\n```\n\n### Fetch by ID\n\n```python\nobj = articles.query.fetch_object_by_id(uuid)\nif obj:\n    print(obj.properties)\n```\n\n### Fetch with Filters\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.query.fetch_objects(\n    filters=Filter.by_property(\"view_count\").greater_than(1000),\n    limit=5\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n---\n\n## Vector Search\n\n### near_text Search\n\n```python\nfrom weaviate.classes.query import MetadataQuery\n\narticles = client.collections.get(\"Article\")\n\nresponse = articles.query.near_text(\n    query=\"vector databases\",\n    limit=5,\n    return_metadata=MetadataQuery(distance=True, score=True)\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n    print(f\"Distance: {obj.metadata.distance}\")\n    print(f\"Score: {obj.metadata.score}\")\n```\n\n### near_text with Filters\n\n```python\nfrom weaviate.classes.query import Filter, MetadataQuery\n\nresponse = articles.query.near_text(\n    query=\"machine learning\",\n    limit=3,\n    filters=Filter.by_property(\"author\").equal(\"John Doe\"),\n    return_metadata=MetadataQuery(distance=True)\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n### near_vector Search\n\n```python\nfrom weaviate.classes.query import MetadataQuery\n\nquery_vector = [0.1, 0.2, 0.3, ...]  # Your query vector\n\nresponse = articles.query.near_vector(\n    near_vector=query_vector,\n    limit=5,\n    return_metadata=MetadataQuery(distance=True)\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n### near_object Search\n\n```python\nfrom weaviate.classes.query import MetadataQuery\n\nresponse = articles.query.near_object(\n    near_object=existing_uuid,\n    limit=5,\n    return_metadata=MetadataQuery(distance=True)\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n---\n\n## Hybrid Search\n\nHybrid search combines keyword (BM25) and vector search.\n\n### Basic Hybrid Search\n\n```python\narticles = client.collections.get(\"Article\")\n\nresponse = articles.query.hybrid(\n    query=\"artificial intelligence\",\n    limit=10,\n    alpha=0.5  # 0 = pure keyword, 1 = pure vector, 0.5 = balanced\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n### Hybrid Search with Filters\n\n```python\nfrom weaviate.classes.query import Filter, MetadataQuery\nfrom datetime import datetime\n\nresponse = articles.query.hybrid(\n    query=\"deep learning\",\n    limit=5,\n    alpha=0.75,\n    filters=Filter.by_property(\"publish_date\").greater_than(\n        datetime(2024, 1, 1).isoformat()\n    ),\n    return_metadata=MetadataQuery(score=True)\n)\n\nfor obj in response.objects:\n    print(obj.properties)\n    print(f\"Score: {obj.metadata.score}\")\n```\n\n### Hybrid Search with Vector\n\n```python\nresponse = articles.query.hybrid(\n    query=\"machine learning\",\n    limit=5,\n    alpha=0.5,\n    vector=[0.1, 0.2, 0.3, ...]  # Optional manual vector\n)\n```\n\n---\n\n## Filters\n\n### Basic Filters\n\n```python\nfrom weaviate.classes.query import Filter\n\narticles = client.collections.get(\"Article\")\n\n# Equal\nFilter.by_property(\"author\").equal(\"John Doe\")\n\n# Not Equal\nFilter.by_property(\"author\").not_equal(\"Jane Smith\")\n\n# Greater Than\nFilter.by_property(\"view_count\").greater_than(1000)\n\n# Greater Than or Equal\nFilter.by_property(\"view_count\").greater_or_equal(500)\n\n# Less Than\nFilter.by_property(\"view_count\").less_than(2000)\n\n# Less Than or Equal\nFilter.by_property(\"view_count\").less_or_equal(1500)\n\n# Like (text contains)\nFilter.by_property(\"title\").like(\"*vector*\")\n\n# Contains Any\nFilter.by_property(\"author\").contains_any([\"John Doe\", \"Jane Smith\"])\n\n# Is Null\nFilter.by_property(\"author\").is_null(True)\n```\n\n### Combining Filters (AND)\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.query.fetch_objects(\n    filters=(\n        Filter.by_property(\"view_count\").greater_than(1000) &\n        Filter.by_property(\"author\").equal(\"John Doe\")\n    ),\n    limit=10\n)\n```\n\n### Combining Filters (OR)\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.query.fetch_objects(\n    filters=(\n        Filter.by_property(\"author\").equal(\"John Doe\") |\n        Filter.by_property(\"author\").equal(\"Jane Smith\")\n    ),\n    limit=10\n)\n```\n\n### Complex Filter Combinations\n\n```python\nfrom weaviate.classes.query import Filter\nfrom datetime import datetime\n\nresponse = articles.query.fetch_objects(\n    filters=(\n        (\n            Filter.by_property(\"view_count\").greater_than(500) &\n            Filter.by_property(\"publish_date\").greater_than(\n                datetime(2024, 1, 1).isoformat()\n            )\n        ) |\n        Filter.by_property(\"author\").equal(\"John Doe\")\n    ),\n    limit=10\n)\n```\n\n---\n\n## Generative Search (RAG)\n\nGenerative search pipes search results through an LLM.\n\n### Single Result Generation\n\n```python\narticles = client.collections.get(\"Article\")\n\nresponse = articles.generate.near_text(\n    query=\"AI trends\",\n    single_prompt=\"Summarize this article in one sentence: {title} - {body}\",\n    limit=5\n)\n\nfor obj in response.objects:\n    print(\"Article:\", obj.properties)\n    print(\"Generated:\", obj.generated)\n```\n\n### Grouped Task Generation\n\n```python\nresponse = articles.generate.near_text(\n    query=\"machine learning\",\n    grouped_task=\"Write a brief overview summarizing these articles about machine learning\",\n    limit=5\n)\n\nprint(\"Generated summary:\", response.generated)\n\nfor obj in response.objects:\n    print(\"Source article:\", obj.properties[\"title\"])\n```\n\n### Both Single and Grouped\n\n```python\nresponse = articles.generate.near_text(\n    query=\"neural networks\",\n    single_prompt=\"Explain this in simple terms: {body}\",\n    grouped_task=\"Create a comprehensive guide based on all these articles\",\n    limit=5\n)\n\nfor obj in response.objects:\n    print(\"Article:\", obj.properties[\"title\"])\n    print(\"Individual generation:\", obj.generated)\n\nprint(\"\\nGrouped generation:\", response.generated)\n```\n\n### Generative Search with Filters\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.generate.near_text(\n    query=\"databases\",\n    single_prompt=\"Summarize: {title}\",\n    limit=3,\n    filters=Filter.by_property(\"author\").equal(\"John Doe\")\n)\n```\n\n### Generate with near_vector\n\n```python\nquery_vector = [0.1, 0.2, 0.3, ...]\n\nresponse = articles.generate.near_vector(\n    near_vector=query_vector,\n    grouped_task=\"Create a summary of these related articles\",\n    limit=5\n)\n\nprint(response.generated)\n```\n\n---\n\n## Update Data\n\n### Update Object\n\n```python\narticles = client.collections.get(\"Article\")\n\narticles.data.update(\n    uuid=uuid,\n    properties={\n        \"view_count\": 2000,\n        \"title\": \"Updated Title\",\n    }\n)\n```\n\n### Replace Object\n\nReplace replaces the entire object (not a merge).\n\n```python\nfrom datetime import datetime\n\narticles.data.replace(\n    uuid=uuid,\n    properties={\n        \"title\": \"Completely New Title\",\n        \"body\": \"Completely new body\",\n        \"author\": \"New Author\",\n        \"publish_date\": datetime.now().isoformat(),\n        \"view_count\": 0,\n    }\n)\n```\n\n---\n\n## Delete Data\n\n### Delete by ID\n\n```python\narticles = client.collections.get(\"Article\")\n\narticles.data.delete_by_id(uuid)\nprint(\"Object deleted\")\n```\n\n### Delete Many by Filter\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.data.delete_many(\n    where=Filter.by_property(\"view_count\").less_than(100)\n)\n\nprint(f\"Deleted {response.successful} objects\")\nprint(f\"Failed: {response.failed}\")\n```\n\n### Delete All Objects in Collection\n\n```python\nfrom weaviate.classes.query import Filter\n\narticles.data.delete_many(\n    where=Filter.by_property(\"title\").like(\"*\")\n)\n```\n\n---\n\n## Aggregations\n\n### Count Objects\n\n```python\narticles = client.collections.get(\"Article\")\n\nresponse = articles.aggregate.over_all()\nprint(f\"Total objects: {response.total_count}\")\n```\n\n### Count with Filter\n\n```python\nfrom weaviate.classes.query import Filter\n\nresponse = articles.aggregate.over_all(\n    filters=Filter.by_property(\"author\").equal(\"John Doe\")\n)\n\nprint(f\"Objects by John Doe: {response.total_count}\")\n```\n\n### Aggregate Numeric Properties\n\n```python\nfrom weaviate.classes.aggregate import Metrics\n\nresponse = articles.aggregate.over_all(\n    return_metrics=Metrics(\"view_count\").maximum()\n)\n\nprint(f\"Max views: {response.properties['view_count'].maximum}\")\n```\n\n### Multiple Aggregations\n\n```python\nfrom weaviate.classes.aggregate import Metrics\n\nresponse = articles.aggregate.over_all(\n    return_metrics=[\n        Metrics(\"view_count\").sum(),\n        Metrics(\"view_count\").average(),\n        Metrics(\"view_count\").minimum(),\n        Metrics(\"view_count\").maximum(),\n    ]\n)\n\nview_stats = response.properties[\"view_count\"]\nprint(f\"Sum: {view_stats.sum}\")\nprint(f\"Average: {view_stats.average}\")\nprint(f\"Min: {view_stats.minimum}\")\nprint(f\"Max: {view_stats.maximum}\")\n```\n\n---\n\n## Multi-Tenancy\n\n### Create Collection with Multi-Tenancy\n\n```python\nfrom weaviate.classes.config import Configure, Property, DataType\n\nclient.collections.create(\n    name=\"Article\",\n    multi_tenancy_config=Configure.multi_tenancy(enabled=True),\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n    ],\n)\n```\n\n### Add Tenants\n\n```python\nfrom weaviate.classes.tenants import Tenant\n\narticles = client.collections.get(\"Article\")\n\narticles.tenants.create(\n    tenants=[\n        Tenant(name=\"tenant1\"),\n        Tenant(name=\"tenant2\"),\n        Tenant(name=\"tenant3\"),\n    ]\n)\n```\n\n### Get Tenant Reference\n\n```python\ntenant1_articles = articles.with_tenant(\"tenant1\")\n```\n\n### Insert Data for Tenant\n\n```python\ntenant1_articles.data.insert(\n    properties={\n        \"title\": \"Tenant 1 Article\",\n        \"body\": \"This belongs to tenant 1\",\n    }\n)\n```\n\n### Query Tenant Data\n\n```python\nresponse = tenant1_articles.query.fetch_objects(limit=10)\n\nfor obj in response.objects:\n    print(obj.properties)\n```\n\n### List Tenants\n\n```python\ntenants = articles.tenants.get()\nfor tenant in tenants:\n    print(tenant.name)\n```\n\n### Remove Tenant\n\n```python\narticles.tenants.remove([\"tenant3\"])\n```\n\n---\n\n## Cross-References\n\n### Define Collection with Reference\n\n```python\nfrom weaviate.classes.config import Property, DataType, ReferenceProperty\n\n# Create Author collection\nclient.collections.create(\n    name=\"Author\",\n    properties=[\n        Property(name=\"name\", data_type=DataType.TEXT),\n        Property(name=\"bio\", data_type=DataType.TEXT),\n    ],\n)\n\n# Create Article collection with reference to Author\nclient.collections.create(\n    name=\"Article\",\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n    ],\n    references=[\n        ReferenceProperty(\n            name=\"has_author\",\n            target_collection=\"Author\"\n        )\n    ],\n)\n```\n\n### Insert with Reference\n\n```python\nauthors = client.collections.get(\"Author\")\narticles = client.collections.get(\"Article\")\n\n# Insert author\nauthor_uuid = authors.data.insert(\n    properties={\n        \"name\": \"John Doe\",\n        \"bio\": \"Expert in AI\",\n    }\n)\n\n# Insert article with reference\narticles.data.insert(\n    properties={\n        \"title\": \"AI Article\",\n        \"body\": \"Content about AI\",\n    },\n    references={\n        \"has_author\": author_uuid\n    }\n)\n```\n\n### Add Reference to Existing Object\n\n```python\narticles.data.reference_add(\n    from_uuid=article_uuid,\n    from_property=\"has_author\",\n    to=author_uuid\n)\n```\n\n### Query with References\n\n```python\nfrom weaviate.classes.query import QueryReference\n\nresponse = articles.query.fetch_objects(\n    limit=10,\n    return_references=QueryReference(\n        link_on=\"has_author\",\n        return_properties=[\"name\", \"bio\"]\n    )\n)\n\nfor obj in response.objects:\n    print(\"Article:\", obj.properties)\n    if obj.references and \"has_author\" in obj.references:\n        print(\"Author:\", obj.references[\"has_author\"].objects[0].properties)\n```\n\n### Delete Reference\n\n```python\narticles.data.reference_delete(\n    from_uuid=article_uuid,\n    from_property=\"has_author\",\n    to=author_uuid\n)\n```\n\n---\n\n## Advanced Configurations\n\n### Collection with Custom Vectorizer Settings\n\n```python\nfrom weaviate.classes.config import (\n    Configure,\n    Property,\n    DataType,\n    VectorDistances\n)\n\nclient.collections.create(\n    name=\"Article\",\n    vectorizer_config=Configure.Vectorizer.text2vec_openai(\n        model=\"text-embedding-3-large\",\n        dimensions=1536,\n        vectorize_collection_name=False,\n    ),\n    vector_index_config=Configure.VectorIndex.hnsw(\n        distance_metric=VectorDistances.COSINE,\n        ef_construction=128,\n        max_connections=64,\n    ),\n    properties=[\n        Property(\n            name=\"title\",\n            data_type=DataType.TEXT,\n            vectorize_property_name=False,\n            skip_vectorization=False,\n        ),\n        Property(\n            name=\"body\",\n            data_type=DataType.TEXT,\n        ),\n        Property(\n            name=\"metadata\",\n            data_type=DataType.TEXT,\n            skip_vectorization=True,  # Don't vectorize this property\n        ),\n    ],\n)\n```\n\n### Collection with Inverted Index Config\n\n```python\nfrom weaviate.classes.config import Configure, Property, DataType, Tokenization\n\nclient.collections.create(\n    name=\"Article\",\n    properties=[\n        Property(\n            name=\"title\",\n            data_type=DataType.TEXT,\n            tokenization=Tokenization.WORD,\n            index_filterable=True,\n            index_searchable=True,\n        ),\n        Property(\n            name=\"sku\",\n            data_type=DataType.TEXT,\n            tokenization=Tokenization.FIELD,  # Exact match only\n            index_filterable=True,\n            index_searchable=False,\n        ),\n    ],\n    inverted_index_config=Configure.inverted_index(\n        index_timestamps=True,\n        index_null_state=True,\n        index_property_length=True,\n    ),\n)\n```\n\n---\n\n## Error Handling\n\n### Try-Except Pattern\n\n```python\nimport weaviate\nfrom weaviate.classes.init import Auth\n\ntry:\n    client = weaviate.connect_to_weaviate_cloud(\n        cluster_url=WEAVIATE_URL,\n        auth_credentials=Auth.api_key(WEAVIATE_API_KEY)\n    )\n\n    articles = client.collections.get(\"Article\")\n\n    response = articles.query.near_text(\n        query=\"AI\",\n        limit=5\n    )\n\n    for obj in response.objects:\n        print(obj.properties)\n\n    client.close()\n\nexcept Exception as e:\n    print(f\"Error: {e}\")\n```\n\n### Batch Insert Error Handling\n\n```python\narticles = client.collections.get(\"Article\")\n\nwith articles.batch.dynamic() as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n\n    if batch.number_errors > 0:\n        print(f\"Number of errors: {batch.number_errors}\")\n\n        for failed_obj in batch.failed_objects:\n            print(f\"Failed object: {failed_obj.object_}\")\n            print(f\"Error message: {failed_obj.message}\")\n```\n\n---\n\n## Complete Example\n\n```python\nimport weaviate\nfrom weaviate.classes.init import Auth\nfrom weaviate.classes.config import Configure, Property, DataType\nfrom weaviate.classes.query import Filter, MetadataQuery\nfrom weaviate.classes.aggregate import Metrics\nfrom datetime import datetime\nimport os\n\n# Connect\nclient = weaviate.connect_to_weaviate_cloud(\n    cluster_url=os.getenv(\"WEAVIATE_URL\"),\n    auth_credentials=Auth.api_key(os.getenv(\"WEAVIATE_API_KEY\")),\n    headers={\n        \"X-OpenAI-Api-Key\": os.getenv(\"OPENAI_API_KEY\")\n    }\n)\n\nprint(\"Connected to Weaviate\")\n\n# Create collection\nclient.collections.create(\n    name=\"Article\",\n    vectorizer_config=Configure.Vectorizer.text2vec_openai(\n        model=\"text-embedding-3-small\"\n    ),\n    generative_config=Configure.Generative.openai(\n        model=\"gpt-4\"\n    ),\n    properties=[\n        Property(name=\"title\", data_type=DataType.TEXT),\n        Property(name=\"body\", data_type=DataType.TEXT),\n        Property(name=\"author\", data_type=DataType.TEXT),\n        Property(name=\"publish_date\", data_type=DataType.DATE),\n        Property(name=\"view_count\", data_type=DataType.INT),\n    ],\n)\n\nprint(\"Collection created\")\n\n# Get collection reference\narticles = client.collections.get(\"Article\")\n\n# Insert data\ndata_objects = [\n    {\n        \"title\": \"Vector Databases Explained\",\n        \"body\": \"A comprehensive guide to understanding vector databases and their applications in modern AI systems.\",\n        \"author\": \"John Doe\",\n        \"publish_date\": datetime(2024, 1, 15).isoformat(),\n        \"view_count\": 1250,\n    },\n    {\n        \"title\": \"Machine Learning in Production\",\n        \"body\": \"Best practices for deploying machine learning models in production environments.\",\n        \"author\": \"Jane Smith\",\n        \"publish_date\": datetime(2024, 2, 20).isoformat(),\n        \"view_count\": 2100,\n    },\n    {\n        \"title\": \"Introduction to RAG\",\n        \"body\": \"Retrieval Augmented Generation combines search with language models for better responses.\",\n        \"author\": \"John Doe\",\n        \"publish_date\": datetime(2024, 3, 10).isoformat(),\n        \"view_count\": 890,\n    },\n]\n\nwith articles.batch.dynamic() as batch:\n    for data_obj in data_objects:\n        batch.add_object(properties=data_obj)\n\nprint(f\"Batch insert completed\")\n\n# Vector search\nprint(\"\\n--- Vector Search ---\")\nsearch_response = articles.query.near_text(\n    query=\"AI and databases\",\n    limit=2,\n    return_metadata=MetadataQuery(distance=True, score=True)\n)\n\nfor obj in search_response.objects:\n    print(f\"\\nTitle: {obj.properties['title']}\")\n    print(f\"Author: {obj.properties['author']}\")\n    print(f\"Score: {obj.metadata.score}\")\n\n# Filtered search\nprint(\"\\n--- Filtered Search ---\")\nfiltered_response = articles.query.near_text(\n    query=\"machine learning\",\n    limit=3,\n    filters=Filter.by_property(\"view_count\").greater_than(1000)\n)\n\nfor obj in filtered_response.objects:\n    print(f\"\\nTitle: {obj.properties['title']}\")\n    print(f\"Views: {obj.properties['view_count']}\")\n\n# Hybrid search\nprint(\"\\n--- Hybrid Search ---\")\nhybrid_response = articles.query.hybrid(\n    query=\"production deployment\",\n    limit=2,\n    alpha=0.5\n)\n\nfor obj in hybrid_response.objects:\n    print(f\"\\nTitle: {obj.properties['title']}\")\n\n# Generative search (RAG)\nprint(\"\\n--- Generative Search ---\")\nrag_response = articles.generate.near_text(\n    query=\"vector databases\",\n    single_prompt=\"Summarize this article in one sentence: {title}\",\n    grouped_task=\"Write a brief paragraph about these articles\",\n    limit=2\n)\n\nprint(\"\\nGrouped generation:\")\nprint(rag_response.generated)\n\nfor obj in rag_response.objects:\n    print(f\"\\n{obj.properties['title']}\")\n    print(f\"Summary: {obj.generated}\")\n\n# Aggregate\nprint(\"\\n--- Aggregations ---\")\nagg_response = articles.aggregate.over_all(\n    return_metrics=[\n        Metrics(\"view_count\").sum(),\n        Metrics(\"view_count\").average(),\n        Metrics(\"view_count\").maximum(),\n    ]\n)\n\nview_stats = agg_response.properties[\"view_count\"]\nprint(f\"Total articles: {agg_response.total_count}\")\nprint(f\"Total views: {view_stats.sum}\")\nprint(f\"Average views: {view_stats.average}\")\nprint(f\"Max views: {view_stats.maximum}\")\n\n# Update\nresponse = articles.query.fetch_objects(limit=1)\nif response.objects:\n    first_uuid = response.objects[0].uuid\n    articles.data.update(\n        uuid=first_uuid,\n        properties={\"view_count\": 1500}\n    )\n    print(\"\\nUpdated first article view count\")\n\n# Delete by filter\ndelete_response = articles.data.delete_many(\n    where=Filter.by_property(\"view_count\").less_than(900)\n)\nprint(f\"\\nDeleted {delete_response.successful} low-view articles\")\n\n# Cleanup\nclient.collections.delete(\"Article\")\nprint(\"\\nCollection deleted\")\n\nclient.close()\nprint(\"Connection closed\")\n```\n\n---\n\n## Type Hints\n\n```python\nfrom typing import List, Dict, Any\nimport weaviate\nfrom weaviate.collections.collection import Collection\nfrom weaviate.collections.classes.grpc import QueryReturn\n\n# Collection reference with type hint\narticles: Collection = client.collections.get(\"Article\")\n\n# Query result type\nresponse: QueryReturn = articles.query.near_text(\n    query=\"AI\",\n    limit=5\n)\n\n# Iterate with type hints\nfor obj in response.objects:\n    properties: Dict[str, Any] = obj.properties\n    print(properties)\n```\n"
  },
  {
    "path": "content/weaviate-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"weaviate-client for Python - official Weaviate client for connecting, defining collections, ingesting data, and running vector search\"\nmetadata:\n  languages: \"python\"\n  versions: \"4.20.4\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"weaviate,weaviate-client,vector-database,semantic-search,rag,embeddings\"\n---\n\n# weaviate-client Python Package Guide\n\n## What It Is\n\n`weaviate-client` is the official Python client for Weaviate's v4 API. Use it to connect to a local, custom, embedded, or Weaviate Cloud instance, define collections, insert data, and run vector, keyword, hybrid, and generative queries.\n\nFor this entry, the package version is pinned to `4.20.4` from PyPI. The main Weaviate Python client docs currently describe the `4.20.x` line and, at the time of writing, the docs page header still says `v4.20.3`; the API examples below are written to match the documented `4.20.x` surface.\n\n## Install\n\n`4.20.4` requires Python `>=3.10` according to PyPI metadata.\n\n```bash\npip install weaviate-client==4.20.4\n```\n\nIf you use `uv`:\n\n```bash\nuv add weaviate-client==4.20.4\n```\n\nIf you need the optional Agents extra published on PyPI:\n\n```bash\npip install \"weaviate-client[agents]==4.20.4\"\n```\n\n## Version And Server Compatibility\n\n- Use the v4 client, not the deprecated v3 API.\n- The v4 Python client requires Weaviate `1.23.7+`.\n- Weaviate's current compatibility table maps Python client `4.20.x` to Weaviate Database `1.36.x`.\n- The client uses gRPC for many operations. For self-hosted deployments, expose both the HTTP port and the gRPC port.\n\nFor local Docker setups, `8080` and `50051` are the usual defaults.\n\n## Recommended Imports\n\nUse the top-level `weaviate` module for connection helpers, and `weaviate.classes` for typed config/query helpers.\n\n```python\nimport weaviate\nimport weaviate.classes as wvc\nfrom weaviate.classes.init import AdditionalConfig, Auth, Timeout\n```\n\n`import weaviate.classes as wvc` is the recommended style for helper classes. Older patterns that import many classes directly from `weaviate` are deprecated.\n\n## Connection Setup\n\n### Weaviate Cloud\n\nUse API key auth for WCD. OIDC password auth is deprecated in the docs and should not be your default.\n\n```python\nimport os\nimport weaviate\nfrom weaviate.classes.init import AdditionalConfig, Auth, Timeout\n\nclient = weaviate.connect_to_weaviate_cloud(\n    cluster_url=os.environ[\"WEAVIATE_URL\"],\n    auth_credentials=Auth.api_key(os.environ[\"WEAVIATE_API_KEY\"]),\n    headers={\n        \"X-OpenAI-Api-Key\": os.environ[\"OPENAI_API_KEY\"],\n    },\n    additional_config=AdditionalConfig(\n        timeout=Timeout(init=30, query=60, insert=120)\n    ),\n)\n\ntry:\n    if not client.is_ready():\n        raise RuntimeError(\"Weaviate is not ready\")\nfinally:\n    client.close()\n```\n\n### Local Weaviate\n\n```python\nimport os\nimport weaviate\n\nclient = weaviate.connect_to_local(\n    host=\"localhost\",\n    port=8080,\n    grpc_port=50051,\n    headers={\n        \"X-OpenAI-Api-Key\": os.getenv(\"OPENAI_API_KEY\", \"\"),\n    },\n)\n\ntry:\n    print(client.is_ready())\nfinally:\n    client.close()\n```\n\n### Custom Endpoints\n\nUse `connect_to_custom()` when the HTTP and gRPC hosts or ports differ from the defaults:\n\n```python\nimport os\nimport weaviate\nfrom weaviate.classes.init import AdditionalConfig, Auth, Timeout\n\nclient = weaviate.connect_to_custom(\n    http_host=\"weaviate.internal.example\",\n    http_port=443,\n    http_secure=True,\n    grpc_host=\"weaviate.internal.example\",\n    grpc_port=443,\n    grpc_secure=True,\n    auth_credentials=Auth.api_key(os.environ[\"WEAVIATE_API_KEY\"]),\n    headers={\"X-OpenAI-Api-Key\": os.environ[\"OPENAI_API_KEY\"]},\n    additional_config=AdditionalConfig(\n        timeout=Timeout(init=30, query=60, insert=120)\n    ),\n)\n```\n\n### Direct Client Instantiation\n\nIf the helper functions are too limiting, instantiate `weaviate.WeaviateClient(...)` directly. When you do that, you must call `client.connect()` yourself before using it.\n\n## Always Close The Client\n\nSince `v4.4b7`, you must close client connections explicitly. Two safe patterns:\n\n```python\nclient = weaviate.connect_to_local()\ntry:\n    # work\n    pass\nfinally:\n    client.close()\n```\n\n```python\nwith weaviate.connect_to_local() as client:\n    print(client.is_ready())\n```\n\n## Defining A Collection\n\nFor production code, define properties explicitly instead of relying on auto-schema. Weaviate's collection naming conventions also matter:\n\n- collection names should start with an upper-case letter\n- property names should start with a lower-case letter\n\n```python\nimport weaviate\nimport weaviate.classes as wvc\n\nwith weaviate.connect_to_local() as client:\n    if not client.collections.exists(\"Article\"):\n        client.collections.create(\n            \"Article\",\n            vector_config=wvc.config.Configure.Vectors.text2vec_openai(),\n            properties=[\n                wvc.config.Property(\n                    name=\"title\",\n                    data_type=wvc.config.DataType.TEXT,\n                ),\n                wvc.config.Property(\n                    name=\"body\",\n                    data_type=wvc.config.DataType.TEXT,\n                ),\n                wvc.config.Property(\n                    name=\"source\",\n                    data_type=wvc.config.DataType.TEXT,\n                ),\n            ],\n        )\n```\n\nIf you provide your own embeddings instead of using a server-side vectorizer, use `wvc.config.Configure.Vectors.self_provided()`.\n\n## Insert Data\n\n### Insert One Object\n\n```python\nimport weaviate\n\nwith weaviate.connect_to_local() as client:\n    articles = client.collections.use(\"Article\")\n    uuid = articles.data.insert(\n        properties={\n            \"title\": \"Project notes\",\n            \"body\": \"Agents need concise package docs for evolving SDKs.\",\n            \"source\": \"internal\",\n        }\n    )\n    print(uuid)\n```\n\n### Insert One Object With A Known UUID\n\n```python\narticles.data.insert(\n    properties={\n        \"title\": \"Deterministic object\",\n        \"body\": \"Use a stable UUID when you need idempotent upserts.\",\n        \"source\": \"seed\",\n    },\n    uuid=\"12345678-e64f-5d94-90db-c8cfa3fc1234\",\n)\n```\n\n### Insert With A User-Provided Vector\n\n```python\narticles.data.insert(\n    properties={\n        \"title\": \"Pre-embedded object\",\n        \"body\": \"The embedding was computed outside Weaviate.\",\n        \"source\": \"offline-pipeline\",\n    },\n    vector=[0.123] * 1536,\n)\n```\n\n## Batch Import\n\nBatching is a common point of failure when copying older examples. In `4.20.4`:\n\n- batching must use a context manager\n- old manual patterns such as `.create_objects(...)` are obsolete\n- use `dynamic()`, `fixed_size()`, or `rate_limit()`\n- failed writes are collected on `collection.batch.failed_objects` and `failed_references`\n\n```python\nimport weaviate\n\nrows = [\n    {\"title\": \"Doc 1\", \"body\": \"Batch import example\", \"source\": \"seed\"},\n    {\"title\": \"Doc 2\", \"body\": \"Second row\", \"source\": \"seed\"},\n]\n\nwith weaviate.connect_to_local() as client:\n    articles = client.collections.use(\"Article\")\n\n    with articles.batch.fixed_size(batch_size=200) as batch:\n        for row in rows:\n            batch.add_object(properties=row)\n            if batch.number_errors > 10:\n                raise RuntimeError(\"Too many batch errors\")\n\n    if articles.batch.failed_objects:\n        raise RuntimeError(articles.batch.failed_objects[0])\n```\n\nUse `rate_limit()` if your vectorizer or generative provider has strict request-per-minute limits.\n\nThe async Python client does not support batching. Use the sync client for bulk imports.\n\n## Query Data\n\n### Fetch Objects\n\n```python\nwith weaviate.connect_to_local() as client:\n    articles = client.collections.use(\"Article\")\n    response = articles.query.fetch_objects(\n        return_properties=[\"title\", \"source\"],\n        limit=5,\n    )\n\n    for obj in response.objects:\n        print(obj.uuid, obj.properties)\n```\n\n### Vector Search With `near_text`\n\n`near_text` only works when the target collection has a vectorizer configured.\n\n```python\nimport weaviate\nimport weaviate.classes as wvc\n\nwith weaviate.connect_to_local() as client:\n    articles = client.collections.use(\"Article\")\n    response = articles.query.near_text(\n        query=\"package documentation for coding agents\",\n        filters=wvc.query.Filter.by_property(\"source\").equal(\"internal\"),\n        limit=3,\n        return_metadata=wvc.query.MetadataQuery(distance=True),\n    )\n\n    for obj in response.objects:\n        print(obj.properties[\"title\"], obj.metadata.distance)\n```\n\n### Named Vectors\n\nIf the collection uses named vectors, pass `target_vector=\"name\"` to `near_text`, `near_object`, `near_vector`, or hybrid search methods.\n\n### Multi-Tenant Collections\n\nIf a collection is multi-tenant, scope the handle before querying or writing:\n\n```python\ntenant_articles = client.collections.use(\"Article\").with_tenant(\"tenantA\")\n```\n\n## Async Client\n\nAn async API is available through `WeaviateAsyncClient` from `weaviate-client` `v4.7.0+`. Use it when your application is already async, but do not expect batching support there.\n\n## Authentication And Headers\n\n- For Weaviate Cloud, prefer `Auth.api_key(...)`.\n- If you use OpenAI, Cohere, or another provider-backed vectorizer or generative module, pass those credentials through `headers`.\n- Keep secrets in environment variables; do not hard-code them into examples or checked-in source.\n- If you use the lower-level `WeaviateClient(...)` constructor, the equivalent parameter is `additional_headers`.\n\nCommon header examples:\n\n```python\nheaders = {\n    \"X-OpenAI-Api-Key\": os.environ[\"OPENAI_API_KEY\"],\n    \"X-Cohere-Api-Key\": os.environ[\"COHERE_API_KEY\"],\n}\n```\n\n## Timeouts And Network Issues\n\nThe Python client uses gRPC for many operations and is sensitive to network latency. If connection init, queries, or inserts time out, raise the specific timeout bucket instead of blindly retrying everything.\n\n```python\nfrom weaviate.classes.init import AdditionalConfig, Timeout\n\nadditional_config=AdditionalConfig(\n    timeout=Timeout(init=30, query=60, insert=120)\n)\n```\n\nIf `generate` queries are timing out, increase the query timeout first.\n\n## Common Pitfalls\n\n### 1. Forgetting The gRPC Port\n\nIf you can reach HTTP but not gRPC, some operations will fail or behave unexpectedly. For local/self-hosted setups, expose `50051` unless you intentionally changed it.\n\n### 2. Copying Pre-`4.16.0` Collection Config Examples\n\nCurrent `4.20.x` code should use:\n\n- `vector_config`, not `vectorizer_config`\n- `Configure.Vectors` / `Configure.MultiVectors`\n- `Configure.Vectors.self_provided()`, not older `none()` helpers\n\n### 3. Copying Pre-`4.4b7` Batch Or Filter Examples\n\nOutdated snippets often use:\n\n- `client.batch` without a context manager\n- removed manual batch methods\n- older filter syntax instead of `Filter.by_property(...)`\n\n### 4. Leaving Auto-Schema On In Production\n\nAuto-schema is convenient for quick experiments, but the docs recommend manually defining production schemas for predictable behavior.\n\n### 5. Not Closing The Client\n\n`client.close()` is required unless you use a context manager.\n\n### 6. Threading Assumptions\n\nThe docs describe the client as fundamentally designed to be thread-safe, but they also call out limitations due to the `requests` dependency, and batching is not thread-safe. Do not share a single batch workflow across threads.\n\n## Version-Sensitive Notes For `4.20.4`\n\n- PyPI currently publishes `4.20.4` as the latest version, released on `2026-03-10`.\n- The main Python client landing page still presents itself as `v4.20.3`, but its compatibility table already covers `4.20.x`.\n- PyPI metadata for `4.20.4` requires Python `>=3.10`. Some upstream descriptive text still mentions older Python versions; prefer the package metadata when deciding whether an environment is supported.\n- The `4.16.0` to `4.16.3` auto-schema/vectorizer edge case is already fixed in `4.16.4+`, so `4.20.4` is not affected.\n\n## Official Sources\n\n- Weaviate Python client docs: https://docs.weaviate.io/weaviate/client-libraries/python\n- Notes and best practices: https://docs.weaviate.io/weaviate/client-libraries/python/notes-best-practices\n- Weaviate Cloud connection guide: https://docs.weaviate.io/weaviate/connections/connect-cloud\n- Collection operations: https://docs.weaviate.io/weaviate/manage-collections/collection-operations\n- Object creation: https://docs.weaviate.io/weaviate/manage-data/create\n- Batch import: https://docs.weaviate.io/weaviate/manage-objects/import\n- Search basics: https://docs.weaviate.io/weaviate/search/basics\n- Vector similarity search: https://docs.weaviate.io/weaviate/search/similarity\n- PyPI package page: https://pypi.org/project/weaviate-client/\n"
  },
  {
    "path": "content/webpack/docs/compression-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: compression-webpack-plugin\ndescription: \"Webpack plugin that emits precompressed gzip or Brotli assets during builds\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,compression,gzip,brotli,build\"\n---\n\n# compression-webpack-plugin for JavaScript\n\n`compression-webpack-plugin` runs during a webpack build and writes compressed copies of emitted assets. The common use case is generating `.gz` and `.br` files that your CDN or web server can serve directly.\n\nThere is no authentication flow, no runtime client to initialize, and no package-specific environment variables.\n\n## Install\n\nInstall the plugin in the same project as webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli compression-webpack-plugin\n```\n\nIf webpack is already installed, add only the plugin:\n\n```bash\nnpm install --save-dev compression-webpack-plugin\n```\n\n## Minimal setup\n\nAdd the plugin to your webpack config. This example generates gzip copies for text assets and keeps the original files.\n\n```javascript\nconst path = require(\"node:path\");\nconst CompressionPlugin = require(\"compression-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"main.js\",\n    clean: true,\n  },\n  plugins: [\n    new CompressionPlugin({\n      filename: \"[path][base].gz\",\n      algorithm: \"gzip\",\n      test: /\\.(js|css|html|svg)$/i,\n      threshold: 10240,\n      minRatio: 0.8,\n    }),\n  ],\n};\n```\n\nBuild as usual:\n\n```bash\nnpx webpack --mode production\n```\n\nThat produces your normal emitted assets plus matching `.gz` files for assets that pass the filter and compression thresholds.\n\n## Enable only for production\n\nThe plugin is usually only useful for production builds. A common pattern is to branch on `NODE_ENV` in the webpack config.\n\n```javascript\nconst path = require(\"node:path\");\nconst CompressionPlugin = require(\"compression-webpack-plugin\");\n\nmodule.exports = () => {\n  const isProd = process.env.NODE_ENV === \"production\";\n\n  return {\n    mode: isProd ? \"production\" : \"development\",\n    entry: \"./src/index.js\",\n    output: {\n      path: path.resolve(__dirname, \"dist\"),\n      filename: \"main.js\",\n      clean: true,\n    },\n    plugins: [\n      ...(isProd\n        ? [\n            new CompressionPlugin({\n              filename: \"[path][base].gz\",\n              algorithm: \"gzip\",\n              test: /\\.(js|css|html|svg)$/i,\n              threshold: 10240,\n              minRatio: 0.8,\n            }),\n          ]\n        : []),\n    ],\n  };\n};\n```\n\n```bash\nNODE_ENV=production npx webpack --mode production\n```\n\n`NODE_ENV` in this example is an application-level convention, not a requirement of `compression-webpack-plugin` itself.\n\n## Generate Brotli assets\n\nUse a second plugin instance when you want Brotli output alongside gzip output.\n\n```javascript\nconst path = require(\"node:path\");\nconst zlib = require(\"node:zlib\");\nconst CompressionPlugin = require(\"compression-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"main.js\",\n    clean: true,\n  },\n  plugins: [\n    new CompressionPlugin({\n      filename: \"[path][base].gz\",\n      algorithm: \"gzip\",\n      test: /\\.(js|css|html|svg)$/i,\n      threshold: 10240,\n      minRatio: 0.8,\n    }),\n    new CompressionPlugin({\n      filename: \"[path][base].br\",\n      algorithm: \"brotliCompress\",\n      test: /\\.(js|css|html|svg)$/i,\n      compressionOptions: {\n        params: {\n          [zlib.constants.BROTLI_PARAM_QUALITY]: 11,\n        },\n      },\n      threshold: 10240,\n      minRatio: 0.8,\n    }),\n  ],\n};\n```\n\nUse different `filename` patterns for each instance so the outputs do not collide.\n\n## Control which assets are compressed\n\n`test`, `include`, and `exclude` let you limit compression to the assets that benefit from it.\n\n```javascript\nconst CompressionPlugin = require(\"compression-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CompressionPlugin({\n      filename: \"[path][base].gz\",\n      algorithm: \"gzip\",\n      include: /\\.(js|css)$/i,\n      exclude: /vendor\\.[a-f0-9]+\\.js$/i,\n      threshold: 10240,\n    }),\n  ],\n};\n```\n\nFor most applications, compress only text-based assets such as JavaScript, CSS, HTML, SVG, or JSON. Binary formats such as JPEG, PNG, WebP, MP4, and ZIP usually do not benefit much from another compression pass.\n\n## Delete original assets carefully\n\nThe plugin can remove the uncompressed files after writing compressed ones.\n\n```javascript\nconst CompressionPlugin = require(\"compression-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CompressionPlugin({\n      filename: \"[path][base].gz\",\n      algorithm: \"gzip\",\n      test: /\\.(js|css|html|svg)$/i,\n      deleteOriginalAssets: \"keep-source-map\",\n    }),\n  ],\n};\n```\n\nUse this only when your deployment environment serves the compressed assets directly. Keeping source maps while deleting the original compiled assets is safer than removing everything blindly.\n\n## Practical notes and pitfalls\n\n- `compression-webpack-plugin` only generates compressed files. It does not configure your web server, CDN, or object storage to send `Content-Encoding: gzip` or `Content-Encoding: br`.\n- Keep the original assets unless you are sure your host will always serve the compressed variants.\n- Apply the plugin to production builds. Precompressing development output usually slows rebuilds without helping local iteration.\n- If you use multiple plugin instances, give each one a unique `filename` pattern such as `.gz` and `.br`.\n- `threshold` and `minRatio` help avoid generating compressed files for tiny assets or for files that do not compress enough to be worth shipping.\n"
  },
  {
    "path": "content/webpack/docs/copy-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: copy-webpack-plugin\ndescription: \"Copy existing files and directories into webpack output with glob patterns, transforms, and overwrite controls\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"14.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,assets,copy,plugin\"\n---\n\n# copy-webpack-plugin\n\n`copy-webpack-plugin` copies files and directories that already exist in your source tree into webpack's output directory.\n\nThere are no API keys, runtime environment variables, or client objects to initialize. All setup happens in `webpack.config.js`.\n\n## Install\n\nIf webpack is not installed yet:\n\n```bash\nnpm install --save-dev webpack webpack-cli copy-webpack-plugin\n```\n\nIf your project already uses webpack:\n\n```bash\nnpm install --save-dev copy-webpack-plugin\n```\n\n## What it is for\n\nUse this plugin for static assets that are already on disk before the build starts, such as:\n\n- HTML templates\n- icons and images outside your import graph\n- public files like `robots.txt` or `manifest.webmanifest`\n- vendor assets you want copied without bundling\n\nDo not use it to copy files generated during the same webpack build.\n\n## Minimal setup\n\n`webpack.config.js`\n\n```js\nconst path = require(\"node:path\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"public\",\n          to: \"public\",\n        },\n        {\n          from: \"src/index.html\",\n          to: \"index.html\",\n        },\n      ],\n    }),\n  ],\n};\n```\n\n`patterns` is the required top-level option. Each pattern can be a string shorthand or an object, but the object form is easier to maintain because it makes `from`, `to`, and related options explicit.\n\n## `from`: file, directory, or glob\n\nThe `from` field accepts a file path, a directory path, or a glob string.\n\n```js\nconst path = require(\"node:path\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        { from: \"public/favicon.ico\", to: \"favicon.ico\" },\n        { from: \"public/images\", to: \"images\" },\n        { from: \"public/**/*.txt\", to: \"docs/[name][ext]\" },\n        {\n          from: path.posix.join(\n            path.resolve(__dirname, \"public\").replaceAll(\"\\\\\", \"/\"),\n            \"**/*\",\n          ),\n          to: \"assets\",\n        },\n      ],\n    }),\n  ],\n};\n```\n\nImportant rules from the maintainer docs:\n\n- Glob patterns must be strings\n- Use forward slashes in glob patterns, even on Windows\n- If you build an absolute glob on Windows, normalize it to forward slashes first\n\n## `context` and preserving relative paths\n\n`context` defines the base directory that webpack prepends to `from`, and then removes again when it calculates the emitted relative path.\n\nUse it when you want a stable base path for a glob or when you want to move a tree under a new destination root.\n\n```js\nconst path = require(\"node:path\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"**/*\",\n          context: path.resolve(__dirname, \"public\"),\n          to({ context, absoluteFilename }) {\n            const relativePath = path\n              .relative(context, absoluteFilename)\n              .replaceAll(\"\\\\\", \"/\");\n\n            return `static/${relativePath}`;\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nThe `to` option can be either:\n\n- a string destination\n- a function `({ context, absoluteFilename }) => string | Promise<string>`\n\nWhen `to` is a function, return forward-slash paths, not backslash-separated Windows paths.\n\n## Ignore files and use `filter` only for content-aware decisions\n\nFor path-based exclusions, prefer `globOptions.ignore`.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"public/**/*\",\n          globOptions: {\n            ignore: [\n              \"**/*.map\",\n              \"**/.DS_Store\",\n            ],\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nUse `filter` when the decision depends on the file contents or some other runtime check:\n\n```js\nconst fs = require(\"node:fs/promises\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"public/**/*\",\n          async filter(resourcePath) {\n            const content = await fs.readFile(resourcePath, \"utf8\");\n\n            return !content.includes(\"DO_NOT_COPY\");\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nIf some files are optional, set `noErrorOnMissing: true` for that pattern:\n\n```js\nconst path = require(\"node:path\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: path.resolve(__dirname, \"branding\", \"favicon.ico\"),\n          to: \"favicon.ico\",\n          noErrorOnMissing: true,\n        },\n      ],\n    }),\n  ],\n};\n```\n\n## Transform copied files\n\nUse `transform` when you need to rewrite the copied file contents before they are emitted.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"public/app-config.js\",\n          to: \"app-config.js\",\n          transform: {\n            transformer(content) {\n              return content\n                .toString()\n                .replaceAll(\"__APP_VERSION__\", process.env.npm_package_version || \"dev\");\n            },\n            cache: true,\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nNotes:\n\n- The `content` argument is a Node `Buffer`\n- `transform` can be a function or an object with `transformer` and `cache`\n- `cache: true` enables cached transform results between builds\n\n## Combine multiple files into one output\n\nUse `transformAll` when several matched files should produce a single emitted file.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"licenses/**/*.txt\",\n          to: \"THIRD_PARTY_LICENSES.txt\",\n          transformAll(assets) {\n            return assets\n              .map((asset) => `## ${asset.sourceFilename}\\n${asset.data.toString()}`)\n              .join(\"\\n\\n\");\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nFor `transformAll`, the maintainer docs call out one important restriction: `to` must point to a file, and only `[contenthash]` and `[fullhash]` placeholders are allowed in that filename.\n\n## Resolve destination conflicts with `force` and `priority`\n\nIf two patterns emit the same destination filename, use `force: true` plus `priority` to control which one wins.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"branding/default/logo.svg\",\n          to: \"logo.svg\",\n          priority: 5,\n        },\n        {\n          from: \"branding/customer/logo.svg\",\n          to: \"logo.svg\",\n          force: true,\n          priority: 10,\n        },\n      ],\n    }),\n  ],\n};\n```\n\nHigher-priority patterns are copied later. Without `force: true`, the plugin does not overwrite an existing asset in `compilation.assets`.\n\n## Destination type and filename templates\n\nIn most cases the plugin can infer whether `to` is a directory, a file, or a template. Set `toType` manually when the destination is ambiguous.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"config/default.json\",\n          to: \"config.prod\",\n          toType: \"file\",\n        },\n        {\n          from: \"images/**/*\",\n          to: \"[path][name].[contenthash][ext]\",\n          toType: \"template\",\n        },\n      ],\n    }),\n  ],\n};\n```\n\nUse `toType: \"file\"` or `toType: \"dir\"` when a destination looks ambiguous, such as a directory name with an extension-like suffix or a dotfile-style filename.\n\n## Asset metadata\n\nUse `info` to add webpack asset info to copied files.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: \"vendor/**/*.js\",\n          info: { minimized: true },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nThe maintainer docs call out `info: { minimized: true }` as the way to mark copied JavaScript files so a minimizer can skip processing them again.\n\n## Monorepos and hoisted dependencies\n\nIn workspaces and monorepos, relative paths under `node_modules` can break when packages are hoisted. Resolve the package root explicitly with `require.resolve()`.\n\n```js\nconst path = require(\"node:path\");\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nconst packageRoot = path.dirname(require.resolve(\"some-package/package.json\"));\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: `${packageRoot}/assets`,\n          to: \"vendor/some-package\",\n        },\n      ],\n    }),\n  ],\n};\n```\n\n## Common pitfalls\n\n- `copy-webpack-plugin` copies files that already exist; it is not for copying assets generated during the same compilation\n- Glob paths should use `/`, not `\\`\n- Prefer `globOptions.ignore` for path-based exclusions; reserve `filter` for content-aware checks\n- Flattening with `to: \"[name][ext]\"` can create filename collisions when different directories contain the same basename\n- If you expect copied files on disk while using `webpack-dev-server`, remember that development middleware often serves from memory; writing to disk is a separate setting on the dev middleware side\n- If a destination is ambiguous, set `toType` explicitly rather than relying on inference\n\n## Performance knob\n\nThe plugin also accepts `options.concurrency` to limit simultaneous filesystem work. The maintainer docs show a default of `100`.\n\n```js\nconst CopyPlugin = require(\"copy-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        { from: \"public\", to: \"public\" },\n      ],\n      options: {\n        concurrency: 50,\n      },\n    }),\n  ],\n};\n```\n"
  },
  {
    "path": "content/webpack/docs/css-loader/javascript/DOC.md",
    "content": "---\nname: css-loader\ndescription: \"Webpack loader for importing CSS, resolving url() and @import, and enabling CSS Modules\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.1.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,css,loader,build,css-modules\"\n---\n\n# css-loader\n\n`css-loader` lets webpack load CSS from JavaScript, resolves CSS `@import` rules and `url()` references, and can compile CSS Modules or ICSS.\n\nIt is a build-time tool only: there is no client to initialize, no auth flow, and no package-specific environment variables. In practice, the only environment variable most projects use here is `NODE_ENV` to switch between development and production loader stacks.\n\nThe maintainer docs for the current 7.x line require webpack 5.\n\n## Install\n\nFor a typical webpack app that injects styles into the page during development:\n\n```bash\nnpm install --save-dev webpack webpack-cli css-loader style-loader\n```\n\nIf you want extracted `.css` files in production builds, also install:\n\n```bash\nnpm install --save-dev mini-css-extract-plugin\n```\n\nIf you want PostCSS transforms such as autoprefixing, also install:\n\n```bash\nnpm install --save-dev postcss postcss-loader postcss-preset-env\n```\n\n## Basic setup\n\nImport CSS from your application entry:\n\n```javascript\nimport \"./styles.css\";\n```\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\"style-loader\", \"css-loader\"],\n      },\n      {\n        test: /\\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,\n        type: \"asset\",\n      },\n    ],\n  },\n};\n```\n\n`src/styles.css`:\n\n```css\nbody {\n  margin: 0;\n  font-family: system-ui, sans-serif;\n}\n\n.hero {\n  background: url(\"./logo.svg\") no-repeat left center;\n  padding-left: 56px;\n}\n```\n\n`css-loader` resolves both of these CSS features through webpack:\n\n- `@import \"./other.css\"`\n- `url(\"./logo.svg\")`\n\nRun webpack with:\n\n```bash\nnpx webpack --mode development\n```\n\n## Development vs production\n\nThe maintainer docs recommend `style-loader` for development and `mini-css-extract-plugin` for production so CSS can be loaded as separate files.\n\nDo not use `style-loader` and `mini-css-extract-plugin` together on the same rule.\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nconst devMode = process.env.NODE_ENV !== \"production\";\n\nmodule.exports = {\n  mode: devMode ? \"development\" : \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [devMode ? \"style-loader\" : MiniCssExtractPlugin.loader, \"css-loader\"],\n      },\n    ],\n  },\n  plugins: devMode ? [] : [new MiniCssExtractPlugin()],\n};\n```\n\n```bash\nNODE_ENV=production npx webpack --mode production\n```\n\n## CSS Modules\n\nIf you want `.module.css` files to be locally scoped while keeping plain `.css` files global, enable module auto-detection and set the export style explicitly.\n\n`webpack.config.js`:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              modules: {\n                auto: true,\n                namedExport: false,\n                exportLocalsConvention: \"camel-case-only\",\n                localIdentName: \"[name]__[local]--[hash:base64:5]\",\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nWith `modules.auto: true`, the maintainer docs enable CSS Modules for files matching `.module.*` and ICSS for files matching `.icss.*`. Plain `.css` files stay global.\n\n`src/Button.module.css`:\n\n```css\n.primary-button {\n  background: #2563eb;\n  color: white;\n  border: 0;\n  border-radius: 6px;\n}\n```\n\n`src/index.js`:\n\n```javascript\nimport styles from \"./Button.module.css\";\n\nconst button = document.createElement(\"button\");\nbutton.className = styles.primaryButton;\nbutton.textContent = \"Save\";\n\ndocument.body.append(button);\n```\n\nIf you prefer named exports instead of a default mapping object, set `modules.namedExport: true` and import with `import * as styles from \"./Button.module.css\"`.\n\n## PostCSS and imported CSS\n\nWhen loaders run before `css-loader`, set `importLoaders` so those loaders also run for CSS pulled in through `@import`, CSS Modules, and ICSS imports.\n\nFor a CSS + PostCSS stack:\n\n`postcss.config.js`:\n\n```javascript\nmodule.exports = {\n  plugins: [require(\"postcss-preset-env\")()],\n};\n```\n\n`webpack.config.js`:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 1,\n            },\n          },\n          \"postcss-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse these values as the rule of thumb:\n\n- `importLoaders: 0` if nothing should run before `css-loader`\n- `importLoaders: 1` if `postcss-loader` should also process imported CSS\n- `importLoaders: 2` if both `postcss-loader` and `sass-loader` should process imported CSS\n\nWithout `importLoaders`, an `@import`ed stylesheet does not automatically go through the loaders that appear before `css-loader` in the current rule.\n\n## Leave `url()` or `@import` untouched\n\nBy default, `css-loader` resolves CSS `url()` and `@import`. If your CSS already points at a CDN, a server-managed static path, or another pipeline, disable that behavior explicitly.\n\nDisable URL handling:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        loader: \"css-loader\",\n        options: {\n          url: false,\n        },\n      },\n    ],\n  },\n};\n```\n\nDisable `@import` handling:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        loader: \"css-loader\",\n        options: {\n          import: false,\n        },\n      },\n    ],\n  },\n};\n```\n\nThe maintainer docs also support filter objects for `url` and `import` when you only want to skip some paths instead of all of them.\n\n## Server-rendered CSS Modules\n\nIf a server bundle only needs the generated class-name mapping and should not emit or inject CSS, use `exportOnlyLocals`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.module\\.css$/i,\n        loader: \"css-loader\",\n        options: {\n          modules: {\n            exportOnlyLocals: true,\n            namedExport: false,\n          },\n        },\n      },\n    ],\n  },\n};\n```\n\nThis is the documented option for pre-rendering or SSR bundles that need CSS Module identifiers but not browser-side style injection.\n\n## Common pitfalls\n\n- `css-loader` only resolves CSS dependencies; you still need matching webpack rules for images, fonts, and other files referenced from CSS.\n- Use `style-loader` for development and `mini-css-extract-plugin` for production; do not stack both in one `use` array.\n- Set `importLoaders` whenever `postcss-loader`, `sass-loader`, or other loaders should also process CSS that comes from `@import`.\n- `esModule` defaults to `true`; if another part of your toolchain expects CommonJS exports, set `esModule: false` explicitly.\n- If you turn on CSS Modules named exports, a CSS class literally named `.default` is exported as `_default` because `default` is a reserved ESM export name.\n\n## Official docs\n\n- Maintainer docs: `https://webpack.js.org/loaders/css-loader/`\n- Package page: `https://www.npmjs.com/package/css-loader`\n"
  },
  {
    "path": "content/webpack/docs/dotenv-webpack/javascript/DOC.md",
    "content": "---\nname: dotenv-webpack\ndescription: \"JavaScript guide for using dotenv-webpack 9.0.0 to inject `.env` variables into webpack builds with safe mode, custom paths, and common pitfalls.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,env,dotenv,defineplugin,javascript\"\n---\n\n# dotenv-webpack\n\n`dotenv-webpack` loads variables from a `.env` file and wires them into webpack through `DefinePlugin`, so matching references in your bundled source are replaced at build time.\n\nThere is no auth flow, runtime client, or separate CLI. All setup happens in your webpack config, and the values you reference are compiled into the bundle.\n\n## Install\n\nInstall the plugin alongside webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli dotenv-webpack\n```\n\n## Basic setup\n\nCreate a `.env` file at the project root:\n\n```dotenv\nAPI_BASE_URL=https://api.example.com/\nFEATURE_FLAG=true\n```\n\nAdd the plugin to `webpack.config.js`:\n\n```js\nconst path = require(\"node:path\");\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins: [new Dotenv()],\n};\n```\n\nUse the variables in application code through direct property access:\n\n```js\nconst apiBaseUrl = process.env.API_BASE_URL;\nconst featureEnabled = process.env.FEATURE_FLAG === \"true\";\n\nconsole.log(\"API base URL:\", apiBaseUrl);\nconsole.log(\"Feature enabled:\", featureEnabled);\n```\n\nBuild with webpack:\n\n```bash\nnpx webpack --config webpack.config.js --mode production\n```\n\nThe plugin only exposes variables that are actually referenced in the compiled source.\n\n## Load a different env file\n\nUse `path` when your project keeps env files outside the default `./.env` location:\n\n```js\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  plugins: [\n    new Dotenv({\n      path: \"./config/.env.production\",\n    }),\n  ],\n};\n```\n\nThis is useful when your build selects a specific env file per environment.\n\n## Fail the build when required keys are missing\n\nUse `safe: true` to compare your real `.env` file against `.env.example`:\n\n`.env.example`:\n\n```dotenv\nAPI_BASE_URL=\nFEATURE_FLAG=\n```\n\n`webpack.config.js`:\n\n```js\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  plugins: [\n    new Dotenv({\n      safe: true,\n      allowEmptyValues: false,\n    }),\n  ],\n};\n```\n\nWith that configuration, the build fails if a key listed in `.env.example` is missing from the loaded environment.\n\n## Read values from the shell or CI\n\nUse `systemvars: true` when CI or your shell exports variables directly into `process.env`:\n\n```js\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  plugins: [\n    new Dotenv({\n      systemvars: true,\n    }),\n  ],\n};\n```\n\nExample build:\n\n```bash\nAPI_BASE_URL=https://staging.example.com/ npx webpack --mode production\n```\n\nThis pattern is common when secrets or deployment-specific values should come from the environment instead of a committed `.env` file.\n\n## Use a different prefix\n\nBy default, the plugin targets `process.env.` references. Use `prefix` if your codebase reads env values from a different namespace:\n\n```js\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  plugins: [\n    new Dotenv({\n      prefix: \"import.meta.env.\",\n    }),\n  ],\n};\n```\n\nThen reference the variables with the same prefix in your source:\n\n```js\nconst apiBaseUrl = import.meta.env.API_BASE_URL;\n```\n\nKeep the prefix and the source code aligned. `dotenv-webpack` only replaces references that match the configured prefix exactly.\n\n## Important pitfalls\n\n### Use direct property access\n\n`dotenv-webpack` relies on webpack constant replacement. Write:\n\n```js\nconst apiBaseUrl = process.env.API_BASE_URL;\n```\n\nDo not destructure from `process.env`:\n\n```js\nconst { API_BASE_URL } = process.env;\n```\n\nThat pattern does not give webpack a direct expression to replace.\n\n### Values are baked in at build time\n\nChanging `.env` does not update a bundle that was already built. Restart or rebuild webpack after editing env files.\n\n### Do not expose secrets to browser code\n\nIf browser-targeted code references a variable, that value becomes part of the built assets. Only expose values that are safe to ship to the client.\n\n### Be careful with leftover `process.env` usage on webpack 5+\n\nWebpack 5 no longer polyfills Node's `process` object for browser bundles. `dotenv-webpack` documents an automatic stub for remaining `process.env` references, and exposes `ignoreStub` for cases where that behavior gets in the way.\n\nIf your application still crashes on `process is not defined`, audit the bundle for code that reads `process` in a way the plugin cannot replace, and prefer explicit variable references such as `process.env.API_BASE_URL` or a custom `prefix`.\n\n## Minimal production pattern\n\nThis is a compact setup that checks required keys and still allows CI-provided overrides:\n\n```js\nconst path = require(\"node:path\");\nconst Dotenv = require(\"dotenv-webpack\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins: [\n    new Dotenv({\n      safe: true,\n      systemvars: true,\n    }),\n  ],\n};\n```\n\nUse this when your project keeps local defaults in `.env`, tracks required keys in `.env.example`, and lets deployment infrastructure supply the final values.\n"
  },
  {
    "path": "content/webpack/docs/file-loader/javascript/DOC.md",
    "content": "---\nname: file-loader\ndescription: \"Webpack loader that emits imported files and returns their public URL\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,assets,loader,files\"\n---\n\n# file-loader\n\n`file-loader` resolves a file import or `require()` call to a URL string and emits the referenced file into webpack's output directory.\n\nFor `file-loader@6.2.0`, the published package declares:\n\n- Node.js `>= 10.13.0`\n- `webpack` peer dependency `^4.0.0 || ^5.0.0`\n\n`file-loader` has no auth flow, no runtime client to initialize, and no environment variables of its own. The only environment-variable example in this guide is an application-level pattern for choosing a runtime CDN prefix.\n\n## Install\n\nInstall `file-loader` in the same project as webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli file-loader\n```\n\nIf webpack is already installed, add only the loader:\n\n```bash\nnpm install --save-dev file-loader\n```\n\n## Basic setup\n\nImport a file from your application code:\n\n```javascript\nimport logoUrl from \"./assets/logo.png\";\n\nconst image = document.createElement(\"img\");\nimage.src = logoUrl;\nimage.alt = \"Logo\";\n\ndocument.body.append(image);\n```\n\nAdd a webpack rule for the file types you want to emit:\n\n```javascript\nconst path = require(\"path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        use: [\n          {\n            loader: \"file-loader\",\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nWith the default settings, `file-loader` emits the asset using `[contenthash].[ext]` and returns the public URL string for that emitted file.\n\n## Keep source-relative names\n\nUse the `name` option when you want filenames that are easier to inspect during development.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"file-loader\",\n        options: {\n          name: \"[path][name].[ext]\",\n          context: \"src\",\n        },\n      },\n    ],\n  },\n};\n```\n\nThis keeps the asset's relative path under `src/` in the emitted filename. The `context` option controls which part of the original path is considered the base.\n\n## Separate output path from public URL\n\n`outputPath` controls where webpack writes the file on disk. `publicPath` controls the URL string exported back into your bundle.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"file-loader\",\n        options: {\n          name: \"[name].[contenthash].[ext]\",\n          outputPath: \"static/assets\",\n          publicPath: \"/static/assets/\",\n        },\n      },\n    ],\n  },\n};\n```\n\nIn that configuration:\n\n- webpack writes files under `dist/static/assets/`\n- imports receive URLs like `/static/assets/logo.abc123.png`\n\nIf you need per-file routing, both `outputPath` and `publicPath` also accept functions with the signature `(url, resourcePath, context) => string`.\n\n## Preserve query strings for CDN-style URLs\n\nIf you import assets with query parameters and want those query parameters preserved in the exported URL, include `[query]` in `name`.\n\n```javascript\nimport imageUrl from \"./directory/image.png?width=300&height=300\";\n\nconsole.log(imageUrl);\n```\n\n```javascript\nmodule.exports = {\n  output: {\n    publicPath: \"https://cdn.example.com/\",\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif)$/i,\n        use: [\n          {\n            loader: \"file-loader\",\n            options: {\n              name: \"[path][name].[ext][query]\",\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nThat pattern produces a URL like:\n\n```text\nhttps://cdn.example.com/directory/image.png?width=300&height=300\n```\n\n## Use a runtime-controlled public path\n\nIf the CDN host is only known when the app starts, set `__webpack_public_path__` in your entry code and use `postTransformPublicPath` in the loader options.\n\n```javascript\nconst assetPrefixForNamespace = (namespace) => {\n  switch (namespace) {\n    case \"prod\":\n      return \"https://cache.myserver.net/web\";\n    case \"uat\":\n      return \"https://cache-uat.myserver.net/web\";\n    case \"st\":\n      return \"https://cache-st.myserver.net/web\";\n    case \"dev\":\n      return \"https://cache-dev.myserver.net/web\";\n    default:\n      return \"\";\n  }\n};\n\nconst namespace = process.env.NAMESPACE;\n\n__webpack_public_path__ = `${assetPrefixForNamespace(namespace)}/`;\n```\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpg|gif)$/i,\n        loader: \"file-loader\",\n        options: {\n          name: \"[name].[contenthash].[ext]\",\n          outputPath: \"static/assets/\",\n          publicPath: \"static/assets/\",\n          postTransformPublicPath: (publicPath) => `__webpack_public_path__ + ${publicPath}`,\n        },\n      },\n    ],\n  },\n};\n```\n\n`file-loader` does not read `NAMESPACE` itself. Your application code chooses the runtime prefix, and `postTransformPublicPath` tells the loader to build the final exported URL from `__webpack_public_path__` plus the loader-generated path.\n\n## Skip writing files in server builds\n\nSet `emitFile: false` when you want the public URI string but do not want webpack to write the asset to disk. The maintainer docs call this out as useful for server-side packages.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"file-loader\",\n        options: {\n          emitFile: false,\n        },\n      },\n    ],\n  },\n};\n```\n\n## CommonJS interop\n\nBy default, `file-loader` exports ES modules syntax. If another part of your toolchain expects CommonJS output, disable `esModule`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"file-loader\",\n        options: {\n          esModule: false,\n        },\n      },\n    ],\n  },\n};\n```\n\nKeep the default `esModule: true` unless you have a specific compatibility problem.\n\n## Important options at a glance\n\n- `name`: output filename template such as `[contenthash].[ext]` or `[path][name].[ext]`\n- `outputPath`: filesystem directory for emitted files\n- `publicPath`: URL prefix returned to application code\n- `postTransformPublicPath`: last-step transform for runtime-generated public paths\n- `context`: base directory used by path placeholders like `[path]`\n- `emitFile`: disable writing files while still returning the URL\n- `regExp`: capture path segments and reuse them with placeholders like `[1]`\n- `esModule`: switch between ESM export syntax and CommonJS export syntax\n\n## Pitfalls\n\n- `outputPath` and `publicPath` are different: one changes the emitted file location, the other changes the URL your code receives.\n- If you rely on asset query strings, include `[query]` in `name`; otherwise the emitted URL drops the original query portion.\n- `postTransformPublicPath` is the option to use when the final asset prefix depends on a runtime global such as `__webpack_public_path__`.\n- `file-loader` does not expose a CLI and does not initialize anything at runtime; all behavior is configured through webpack loader options.\n"
  },
  {
    "path": "content/webpack/docs/fork-ts-checker-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: fork-ts-checker-webpack-plugin\ndescription: \"JavaScript guide for using fork-ts-checker-webpack-plugin 9.1.0 with webpack and TypeScript, including ts-loader, Babel, blocking CI checks, and common configuration pitfalls.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.1.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,typescript,build,plugin,type-checking,javascript\"\n---\n\n# fork-ts-checker-webpack-plugin\n\n`fork-ts-checker-webpack-plugin` runs TypeScript type checking in a separate process during webpack builds. Use it with a transpiler such as `ts-loader` or `babel-loader`; the plugin reports type errors, but it does not replace your loader and it does not emit JavaScript by itself.\n\nThere are no API keys, runtime environment variables, or client objects to initialize. All setup happens in `webpack.config.js` and `tsconfig.json`.\n\n## Golden Rule\n\nIf you use `ts-loader`, set `transpileOnly: true` and let `fork-ts-checker-webpack-plugin` handle type checking. Otherwise you pay for TypeScript checking twice and builds get slower with little benefit.\n\nIf you transpile TypeScript with Babel, keep a real `tsconfig.json` in the project anyway. The plugin reads TypeScript configuration from that file when it runs checks.\n\n## Install\n\nTypical `ts-loader` setup:\n\n```bash\nnpm install --save-dev webpack webpack-cli typescript ts-loader fork-ts-checker-webpack-plugin\n```\n\nIf you transpile TypeScript with Babel instead of `ts-loader`:\n\n```bash\nnpm install --save-dev webpack webpack-cli typescript babel-loader @babel/core @babel/preset-env @babel/preset-typescript fork-ts-checker-webpack-plugin\n```\n\n## Minimal `tsconfig.json`\n\nThe plugin checks whatever TypeScript sees through `files`, `include`, `exclude`, and project references. Start with a normal project config:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true\n  },\n  \"include\": [\"src\"]\n}\n```\n\nIf a file is not included by TypeScript, the plugin will not check it.\n\n## Basic Webpack Setup With `ts-loader`\n\n`webpack.config.js`:\n\n```js\nconst path = require(\"node:path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  resolve: {\n    extensions: [\".ts\", \".tsx\", \".js\"],\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        exclude: /node_modules/,\n        use: [\n          {\n            loader: \"ts-loader\",\n            options: {\n              transpileOnly: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [new ForkTsCheckerWebpackPlugin()],\n};\n```\n\nAdd a simple build script:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack --config webpack.config.js\",\n    \"watch\": \"webpack --watch --config webpack.config.js\"\n  }\n}\n```\n\nThen run:\n\n```bash\nnpm run build\n```\n\n## Use With Babel\n\nWhen Babel handles transpilation, `fork-ts-checker-webpack-plugin` supplies type checking that Babel does not do.\n\n`babel.config.json`:\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"18\"\n        }\n      }\n    ],\n    \"@babel/preset-typescript\"\n  ]\n}\n```\n\n`webpack.config.js`:\n\n```js\nconst path = require(\"node:path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  resolve: {\n    extensions: [\".ts\", \".tsx\", \".js\"],\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        exclude: /node_modules/,\n        loader: \"babel-loader\",\n      },\n    ],\n  },\n  plugins: [new ForkTsCheckerWebpackPlugin()],\n};\n```\n\nThis is a common pattern when webpack should emit code through Babel but TypeScript should still enforce types.\n\n## Choose A Different TypeScript Config\n\nIf webpack should use a dedicated config file, point the plugin at it explicitly:\n\n```js\nconst path = require(\"node:path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new ForkTsCheckerWebpackPlugin({\n      typescript: {\n        configFile: path.resolve(__dirname, \"tsconfig.webpack.json\"),\n      },\n    }),\n  ],\n};\n```\n\nUse this when your repo has multiple `tsconfig` files or when bundling needs different compiler options than tests or editor tooling.\n\n## Block The Build On Type Errors\n\nIn watch mode and local development, teams often prefer faster feedback even if errors arrive asynchronously. In CI or production builds, set `async: false` so webpack waits for the checker result:\n\n```js\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new ForkTsCheckerWebpackPlugin({\n      async: false,\n    }),\n  ],\n};\n```\n\nUse this for release builds where a type error must fail the command before artifacts are considered done.\n\n## Large Repos And Project References\n\nFor larger codebases, the plugin exposes TypeScript-specific options under `typescript`.\n\nRaise the checker worker memory limit if large builds hit memory pressure:\n\n```js\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new ForkTsCheckerWebpackPlugin({\n      typescript: {\n        memoryLimit: 4096,\n      },\n    }),\n  ],\n};\n```\n\nIf your repo uses TypeScript project references, enable build mode so the checker follows the referenced projects:\n\n```js\nconst path = require(\"node:path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  plugins: [\n    new ForkTsCheckerWebpackPlugin({\n      typescript: {\n        build: true,\n        configFile: path.resolve(__dirname, \"tsconfig.json\"),\n      },\n    }),\n  ],\n};\n```\n\n## Common Pitfalls\n\n- Keep `ts-loader` in `transpileOnly: true` mode when the plugin is enabled, or TypeScript checking runs twice.\n- Make sure every source file is covered by `tsconfig.json` `include`, `files`, or project references. Missing files produce missing diagnostics.\n- If webpack uses path aliases, mirror them in TypeScript with `compilerOptions.baseUrl` and `compilerOptions.paths`. The checker follows TypeScript resolution, not webpack-only aliases.\n- When Babel transpiles TypeScript, remember that Babel removes types but does not type-check them. The plugin still needs a valid local `typescript` dependency and `tsconfig.json`.\n- This plugin reports problems during webpack builds; it is not a replacement for ESLint, unit tests, or declaration publishing workflows.\n\n## Minimal Alias Example\n\nIf your webpack config resolves `@app/*`, mirror that in `tsconfig.json` so the checker agrees with webpack:\n\n```json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@app/*\": [\"src/*\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n```\n\nWithout matching TypeScript path mapping, webpack may bundle successfully while the checker still reports unresolved imports.\n\n## Useful Links\n\n- Maintainer docs: `https://github.com/TypeStrong/fork-ts-checker-webpack-plugin`\n- npm package: `https://www.npmjs.com/package/fork-ts-checker-webpack-plugin`\n"
  },
  {
    "path": "content/webpack/docs/html-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: html-webpack-plugin\ndescription: \"Generate HTML files for webpack bundles with html-webpack-plugin, including templates, multi-page output, head tags, and plugin hooks.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.6.6\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,html,plugin,templates\"\n---\n\n# html-webpack-plugin\n\n`html-webpack-plugin` generates HTML files that reference the JavaScript and CSS files emitted by webpack. Use it when you want webpack to own the final `<script>` and `<link>` tags instead of hard-coding bundle filenames.\n\nFor `html-webpack-plugin@5.6.6`, the published package declares:\n\n- Node.js `>=10.13.0`\n- `webpack` peer dependency `^5.20.0`\n\nThere is no authentication flow, runtime client, or package-specific environment variable. All setup happens in `webpack.config.js`. If you need build-time values in the generated HTML, pass them through `templateParameters`.\n\n## Install\n\nInstall the plugin alongside webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli html-webpack-plugin\n```\n\nIf your build extracts CSS into separate files, install that plugin separately. `html-webpack-plugin` injects emitted CSS files automatically when they exist in the webpack output.\n\n## Minimal setup\n\n`html-webpack-plugin` works without extra configuration. Add it to `plugins` and run webpack normally.\n\n`webpack.config.js`\n\n```javascript\nconst path = require(\"node:path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"assets/[name].[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      title: \"My App\",\n    }),\n  ],\n};\n```\n\n`src/index.js`\n\n```javascript\nimport \"./styles.css\";\n\ndocument.body.innerHTML = '<div id=\"app\">Hello from webpack</div>';\n```\n\nBuild the project:\n\n```bash\nnpx webpack --mode development\nnpx webpack --mode production\n```\n\nThis writes `dist/index.html`. By default the plugin injects scripts into the document and uses `defer` script loading. If webpack emits CSS files, those are added as `<link>` tags in the HTML head.\n\nIf another plugin integrates with `html-webpack-plugin` through its hooks, put `new HtmlWebpackPlugin(...)` before that plugin in the `plugins` array.\n\n## Use a template file\n\nUse `template` when you want a real file in your source tree. The default templating syntax is lodash-style interpolation.\n\n`webpack.config.js`\n\n```javascript\nconst path = require(\"node:path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"assets/[name].[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      title: \"Dashboard\",\n      template: \"./src/index.ejs\",\n    }),\n  ],\n};\n```\n\n`src/index.ejs`\n\n```html\n<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title><%= htmlWebpackPlugin.options.title %></title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n```\n\nIn templates, the plugin makes these values available by default:\n\n- `htmlWebpackPlugin.options` for the options you passed to the plugin\n- `htmlWebpackPlugin.tags.headTags` and `htmlWebpackPlugin.tags.bodyTags` for prepared HTML tags\n- `htmlWebpackPlugin.files` for emitted asset lists such as `js`, `css`, `favicon`, and `publicPath`\n- `webpackConfig` for the webpack config used in the current compilation\n- `compilation` for direct access to webpack compilation data\n\n## Control tag placement and pass template data\n\nWhen you want full control over where tags are rendered, set `inject: false` and print the prepared tags yourself.\n\n`webpack.config.js`\n\n```javascript\nconst path = require(\"node:path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"assets/[name].[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      inject: false,\n      template: \"./src/index.ejs\",\n      templateParameters: {\n        apiBase: process.env.APP_API_BASE ?? \"/api\",\n      },\n    }),\n  ],\n};\n```\n\n`src/index.ejs`\n\n```html\n<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"api-base\" content=\"<%= apiBase %>\" />\n    <%= htmlWebpackPlugin.tags.headTags %>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <%= htmlWebpackPlugin.tags.bodyTags %>\n  </body>\n</html>\n```\n\n`templateParameters` can be an object, `false`, or a function that receives the current compilation, assets, prepared tag groups, and resolved plugin options.\n\n## Generate multiple HTML files\n\nCreate one plugin instance per page. Use `chunks` when each HTML file should include only specific entry bundles.\n\n`webpack.config.js`\n\n```javascript\nconst path = require(\"node:path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: {\n    app: \"./src/app.js\",\n    admin: \"./src/admin.js\",\n  },\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"assets/[name].[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      filename: \"index.html\",\n      chunks: [\"app\"],\n      title: \"App\",\n    }),\n    new HtmlWebpackPlugin({\n      filename: \"admin/index.html\",\n      chunks: [\"admin\"],\n      title: \"Admin\",\n    }),\n  ],\n};\n```\n\nUse `excludeChunks` when you want to start from all entry chunks and remove a few helper bundles instead.\n\n## Configure metadata, base URL, and production output\n\nThe plugin can generate common head tags directly from options.\n\n`webpack.config.js`\n\n```javascript\nnew HtmlWebpackPlugin({\n  filename: \"index.[contenthash].html\",\n  favicon: \"./src/favicon.ico\",\n  scriptLoading: \"module\",\n  meta: {\n    viewport: \"width=device-width, initial-scale=1\",\n    \"theme-color\": \"#111827\",\n    \"Content-Security-Policy\": {\n      \"http-equiv\": \"Content-Security-Policy\",\n      content: \"default-src 'self'\",\n    },\n  },\n  base: {\n    href: \"/\",\n    target: \"_self\",\n  },\n  minify: {\n    collapseWhitespace: true,\n    keepClosingSlash: true,\n    removeComments: true,\n    removeRedundantAttributes: true,\n    removeScriptTypeAttributes: true,\n    removeStyleLinkTypeAttributes: true,\n    useShortDoctype: true,\n  },\n});\n```\n\nNotes for production builds:\n\n- `filename: \"index.[contenthash].html\"` hashes the final HTML output\n- `scriptLoading: \"module\"` adds `type=\"module\"` and implies deferred loading\n- `minify` defaults to production-only behavior when left as `\"auto\"`\n- A custom `minify` object replaces the default production minifier settings; it is not merged with them\n\n## Hook into HTML generation\n\nPlugins can extend `html-webpack-plugin` through compilation hooks. Use `HtmlWebpackPlugin.getCompilationHooks(compilation)` inside your own webpack plugin.\n\n`add-build-hash-plugin.js`\n\n```javascript\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nclass AddBuildHashPlugin {\n  apply(compiler) {\n    compiler.hooks.compilation.tap(\"AddBuildHashPlugin\", (compilation) => {\n      HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapAsync(\n        \"AddBuildHashPlugin\",\n        (data, cb) => {\n          data.html = data.html.replace(\n            \"</head>\",\n            `<meta name=\"build-hash\" content=\"${compilation.hash}\"></head>`,\n          );\n          cb(null, data);\n        },\n      );\n    });\n  }\n}\n\nmodule.exports = AddBuildHashPlugin;\n```\n\n`webpack.config.js`\n\n```javascript\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\nconst AddBuildHashPlugin = require(\"./add-build-hash-plugin\");\n\nmodule.exports = {\n  plugins: [new HtmlWebpackPlugin(), new AddBuildHashPlugin()],\n};\n```\n\nThe documented hook names are:\n\n- `beforeAssetTagGeneration`\n- `alterAssetTags`\n- `alterAssetTagGroups`\n- `afterTemplateExecution`\n- `beforeEmit`\n- `afterEmit`\n\n## Pitfalls\n\n- Put `HtmlWebpackPlugin` before plugins that expect to tap its hooks\n- Use `template` for normal source files; `templateContent` does not use webpack loaders and does not watch for template file changes\n- If your assets are served from a CDN or from a different URL root, set `publicPath` explicitly instead of relying on `\"auto\"`\n- Use `chunks` or `excludeChunks` per plugin instance in multi-page builds so each HTML file gets the right entry bundles\n- If you render `htmlWebpackPlugin.tags.headTags` and `bodyTags` yourself, keep `inject: false` so placement stays under your control\n"
  },
  {
    "path": "content/webpack/docs/less-loader/javascript/DOC.md",
    "content": "---\nname: less-loader\ndescription: \"Webpack loader that compiles Less files to CSS\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"12.3.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,less,css,loader\"\n---\n\n# less-loader\n\n`less-loader` compiles `.less` files during a webpack build.\n\nThis package is build-time only: there is no runtime client to initialize, no auth flow, and no package-specific environment variables. You install it alongside webpack and the `less` compiler, import `.less` from your application code, and configure webpack to run `less-loader` before `css-loader` and `style-loader` or `mini-css-extract-plugin`.\n\nThis guide targets `less-loader@12.3.2`.\n\n## Install\n\nInstall webpack, `less-loader`, the Less compiler, and the CSS loaders you want to use:\n\n```bash\nnpm install --save-dev webpack webpack-cli less-loader less css-loader style-loader\n```\n\nIf you want emitted `.css` files in production builds instead of runtime style injection, also install `mini-css-extract-plugin`:\n\n```bash\nnpm install --save-dev mini-css-extract-plugin\n```\n\n`less-loader` does not bundle the Less compiler. If `less` is missing, webpack cannot compile `.less` files.\n\n## Basic setup\n\nImport a Less entry file from your application code:\n\n```javascript\nimport \"./styles/app.less\";\n```\n\nCreate a stylesheet:\n\n```less\n@brand-color: #2563eb;\n\nbody {\n  color: @brand-color;\n}\n```\n\nConfigure webpack so `less-loader` runs first, then `css-loader`, then `style-loader`:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.less$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          \"less-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nBuild with webpack:\n\n```bash\nnpx webpack --mode development\n```\n\n## Extract CSS in production\n\nUse `style-loader` in development and `mini-css-extract-plugin` in production.\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.less$/i,\n        use: [\n          process.env.NODE_ENV !== \"production\"\n            ? \"style-loader\"\n            : MiniCssExtractPlugin.loader,\n          \"css-loader\",\n          \"less-loader\",\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: \"[name].css\",\n      chunkFilename: \"[id].css\",\n    }),\n  ],\n};\n```\n\nExample production build:\n\n```bash\nNODE_ENV=production npx webpack --mode production\n```\n\n`NODE_ENV` here is an application-level convention for choosing webpack behavior. `less-loader` does not read its own environment variables.\n\n## Pass Less compiler options with `lessOptions`\n\nUse `lessOptions` for compiler-specific settings that should be forwarded to Less.\n\nThis example adds an extra import search path so Less can resolve shared files without long relative paths:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.less$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"less-loader\",\n            options: {\n              lessOptions: {\n                paths: [path.resolve(__dirname, \"src/styles\")],\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nThen a Less file can import from that directory:\n\n```less\n@import \"theme/variables.less\";\n\n.button {\n  color: @brand-color;\n}\n```\n\nKeep Less compiler settings under `lessOptions`; top-level loader options such as `sourceMap` stay at the loader level.\n\n## Inject shared variables with `additionalData`\n\nUse `additionalData` to prepend shared Less before each entry file. This is the usual pattern for build-specific variables that you do not want to duplicate across many stylesheets.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.less$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"less-loader\",\n            options: {\n              additionalData: `@build-env: \"${process.env.NODE_ENV || \"development\"}\";`,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nReference the injected variable from Less:\n\n```less\n.build-banner::before {\n  content: \"@{build-env}\";\n}\n```\n\n## Enable source maps\n\nWhen you need browser devtools to map compiled CSS back to `.less` sources, enable source maps in webpack and in both CSS-related loaders.\n\n```javascript\nmodule.exports = {\n  devtool: \"source-map\",\n  module: {\n    rules: [\n      {\n        test: /\\.less$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n          {\n            loader: \"less-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\n## Important pitfalls\n\n- Install `less` as well as `less-loader`; the loader delegates compilation to the Less package.\n- Keep `less-loader` last in the webpack `use` array so it runs first.\n- Use `lessOptions` for Less compiler settings such as import paths, not top-level loader options.\n- Use `MiniCssExtractPlugin.loader` instead of `style-loader` when you need emitted CSS files for production.\n- `additionalData` is prepended to every compiled Less module, so keep it limited to shared variables, mixins, or imports that should apply everywhere.\n\n## Official Sources\n\n- https://webpack.js.org/loaders/less-loader/\n- https://www.npmjs.com/package/less-loader\n"
  },
  {
    "path": "content/webpack/docs/mini-css-extract-plugin/javascript/DOC.md",
    "content": "---\nname: mini-css-extract-plugin\ndescription: \"Webpack plugin that extracts imported CSS into separate emitted stylesheet files\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.10.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,css,build,plugin,assets\"\n---\n\n# mini-css-extract-plugin for JavaScript\n\n`mini-css-extract-plugin` extracts CSS that your bundle imports and writes it as real `.css` assets instead of injecting styles into JavaScript at runtime.\n\nThere is no authentication flow, no runtime client to initialize, and no package-specific environment variable. The examples below only use `NODE_ENV` as an application-level switch between development and production behavior.\n\n## Install\n\nInstall the plugin with webpack and `css-loader` in the same project:\n\n```bash\nnpm install --save-dev webpack webpack-cli mini-css-extract-plugin css-loader\n```\n\nIf your webpack project already exists, add only the missing dependencies:\n\n```bash\nnpm install --save-dev mini-css-extract-plugin css-loader\n```\n\n## Minimal setup\n\nImport a stylesheet from your application entry:\n\n```javascript\nimport \"./styles.css\";\n```\n\nConfigure webpack to use `MiniCssExtractPlugin.loader` before `css-loader`, then add the plugin instance:\n\n```javascript\nconst path = require(\"node:path\");\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"[name].js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [MiniCssExtractPlugin.loader, \"css-loader\"],\n      },\n    ],\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: \"[name].[contenthash].css\",\n      chunkFilename: \"[id].[contenthash].css\",\n    }),\n  ],\n};\n```\n\nBuild with webpack as usual:\n\n```bash\nnpx webpack --mode production\n```\n\nThat produces JavaScript in `dist/` plus one or more extracted CSS files.\n\n## Use `style-loader` in development and extract in production\n\nThe maintainer docs recommend using `style-loader` for development and `mini-css-extract-plugin` for production. Do not use both loaders in the same rule at the same time.\n\n```bash\nnpm install --save-dev style-loader\n```\n\n```javascript\nconst path = require(\"node:path\");\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nconst isProduction = process.env.NODE_ENV === \"production\";\n\nmodule.exports = {\n  mode: isProduction ? \"production\" : \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"[name].js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [isProduction ? MiniCssExtractPlugin.loader : \"style-loader\", \"css-loader\"],\n      },\n    ],\n  },\n  plugins: isProduction\n    ? [\n        new MiniCssExtractPlugin({\n          filename: \"[name].[contenthash].css\",\n          chunkFilename: \"[id].[contenthash].css\",\n        }),\n      ]\n    : [],\n};\n```\n\nExample scripts:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"NODE_ENV=development webpack --mode development\",\n    \"build\": \"NODE_ENV=production webpack --mode production\"\n  }\n}\n```\n\nIf you do not want to depend on `NODE_ENV` in npm scripts, you can rely on the CLI `--mode` flag alone and keep the same loader split.\n\n## Extract CSS from Sass\n\nTo extract Sass or SCSS, keep `MiniCssExtractPlugin.loader` first and add the preprocessor after `css-loader`.\n\n```bash\nnpm install --save-dev sass sass-loader\n```\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  devtool: \"source-map\",\n  module: {\n    rules: [\n      {\n        test: /\\.(sa|sc|c)ss$/i,\n        use: [\n          MiniCssExtractPlugin.loader,\n          {\n            loader: \"css-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n          {\n            loader: \"sass-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [new MiniCssExtractPlugin()],\n};\n```\n\nThe maintainer docs call out CSS source map support for webpack `devtool` values that emit full source maps, including `source-map`, `nosources-source-map`, `hidden-source-map`, and `hidden-nosources-source-map`.\n\n## Extract shared CSS into a dedicated chunk\n\nWhen multiple entrypoints or lazy chunks share CSS, use webpack `splitChunks` with the plugin's CSS chunk type:\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [MiniCssExtractPlugin.loader, \"css-loader\"],\n      },\n    ],\n  },\n  optimization: {\n    splitChunks: {\n      cacheGroups: {\n        styles: {\n          name: \"styles\",\n          type: \"css/mini-extract\",\n          chunks: \"all\",\n          enforce: true,\n        },\n      },\n    },\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: \"[name].css\",\n    }),\n  ],\n};\n```\n\nUse this when you want one extracted stylesheet for shared CSS instead of separate CSS files per chunk.\n\n## Adjust asset URLs with loader `publicPath`\n\nIf your extracted CSS is emitted into a different directory depth than the assets it references with `url()`, set `publicPath` on the loader.\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader,\n            options: {\n              publicPath: \"../\",\n            },\n          },\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n  plugins: [new MiniCssExtractPlugin({ filename: \"css/[name].css\" })],\n};\n```\n\nThat pattern is useful when CSS lands in `dist/css/` but images or fonts are emitted relative to `dist/`.\n\n## Important pitfalls\n\n- `mini-css-extract-plugin` extracts files; it does not replace the need for `css-loader`.\n- Do not combine `style-loader` and `MiniCssExtractPlugin.loader` in the same loader chain. Pick one for a given build.\n- The plugin handles runtime loading for non-initial CSS chunks, but CSS from initial entry chunks still needs to be linked from HTML. In practice, use `html-webpack-plugin` or add the emitted stylesheet to your HTML template yourself.\n- `ignoreOrder: true` only suppresses CSS order warnings. Use it only when stylesheet order does not affect the rendered result.\n- If order warnings appear, fix inconsistent import order across entries before silencing them.\n\n## Practical default\n\nFor most webpack apps, start with this rule and plugin pair:\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [MiniCssExtractPlugin.loader, \"css-loader\"],\n      },\n    ],\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: \"[name].[contenthash].css\",\n      chunkFilename: \"[id].[contenthash].css\",\n    }),\n  ],\n};\n```\n\nAdd preprocessors, `splitChunks`, or loader `publicPath` only when your build needs them.\n"
  },
  {
    "path": "content/webpack/docs/postcss-loader/javascript/DOC.md",
    "content": "---\nname: postcss-loader\ndescription: \"Webpack loader that runs PostCSS plugins over CSS and preprocessor output\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"8.2.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,postcss,css,loader,build\"\n---\n\n# postcss-loader for JavaScript\n\n`postcss-loader` runs [PostCSS](https://postcss.org/) as part of a webpack CSS pipeline.\n\nThere is no authentication step and no package-specific environment variable. Install it in the same project as `webpack` and `postcss`, then add it to the `module.rules` chain for your CSS files.\n\n## Prerequisites\n\n- `webpack` 5. The maintainer docs say the current loader line requires webpack 5; if you are on webpack 4, use `postcss-loader` v4 instead.\n- `postcss` installed in the same project.\n- At least one PostCSS plugin if you want transforms beyond plain parsing, such as `postcss-preset-env`.\n\n## Install\n\nFor a typical CSS pipeline, install webpack, the CSS loaders, PostCSS, and a plugin preset:\n\n```bash\nnpm install --save-dev webpack webpack-cli style-loader css-loader postcss-loader postcss postcss-preset-env\n```\n\nIf webpack is already set up, add the missing CSS and PostCSS packages only.\n\n## Minimal setup\n\nImport a stylesheet from your application entry:\n\n```javascript\nimport \"./styles.css\";\n```\n\nAdd `postcss-loader` to the webpack rule. Because webpack evaluates loaders right to left, list the loaders in this order:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 1,\n            },\n          },\n          {\n            loader: \"postcss-loader\",\n            options: {\n              postcssOptions: {\n                plugins: [[\"postcss-preset-env\", {}]],\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\n`importLoaders: 1` on `css-loader` is important here: it makes sure CSS loaded through `@import` also runs through `postcss-loader`.\n\nRun webpack with your normal build command:\n\n```bash\nnpx webpack --mode development\n```\n\n## Use a `postcss.config.js` file\n\n`postcss-loader` automatically searches for a PostCSS config file starting from the CSS file's directory and walking upward.\n\nCreate `postcss.config.js`:\n\n```javascript\nmodule.exports = {\n  plugins: [[\"postcss-preset-env\", {}]],\n};\n```\n\nThen keep the webpack rule minimal:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 1,\n            },\n          },\n          \"postcss-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse this pattern when you want one PostCSS config shared across webpack and other tools.\n\n## Inline config and disable config lookup\n\nIf you already know all of your PostCSS plugins in webpack config, you can skip filesystem config lookup and keep everything inline.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 1,\n            },\n          },\n          {\n            loader: \"postcss-loader\",\n            options: {\n              postcssOptions: {\n                config: false,\n                plugins: [[\"postcss-preset-env\", {}]],\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nThe maintainer docs recommend this pattern for larger projects because it avoids repeated config-file lookups during compilation.\n\nIf you need a non-default config location, point `postcssOptions.config` at a specific file path:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        loader: \"postcss-loader\",\n        options: {\n          postcssOptions: {\n            config: path.resolve(__dirname, \"config/postcss.config.js\"),\n          },\n        },\n      },\n    ],\n  },\n};\n```\n\n## Use with Sass or other preprocessors\n\n`postcss-loader` should run after preprocessors such as `sass-loader`, `less-loader`, or `stylus-loader`, but before `css-loader` and `style-loader` in execution order. In a webpack `use` array, that means the preprocessor goes last:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.scss$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 2,\n              sourceMap: true,\n            },\n          },\n          {\n            loader: \"postcss-loader\",\n            options: {\n              sourceMap: true,\n              postcssOptions: {\n                plugins: [[\"postcss-preset-env\", {}]],\n              },\n            },\n          },\n          {\n            loader: \"sass-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse `importLoaders: 2` because imported Sass should pass through both `postcss-loader` and `sass-loader`.\n\n## CSS Modules\n\n`postcss-loader` does not need special options for CSS Modules. Configure modules on `css-loader` and keep `importLoaders` aligned with the number of loaders that should run before `css-loader` finishes.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.module\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              modules: true,\n              importLoaders: 1,\n            },\n          },\n          \"postcss-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\n## Source maps\n\n`postcss-loader` has its own `sourceMap` option. By default it follows webpack's `devtool` behavior; the maintainer docs say source maps are enabled for all `devtool` values except `eval` and `false`.\n\nIf you are chaining a preprocessor, enable source maps consistently across each loader in the chain:\n\n```javascript\nmodule.exports = {\n  devtool: \"source-map\",\n  module: {\n    rules: [\n      {\n        test: /\\.scss$/i,\n        use: [\n          \"style-loader\",\n          { loader: \"css-loader\", options: { sourceMap: true } },\n          { loader: \"postcss-loader\", options: { sourceMap: true } },\n          { loader: \"sass-loader\", options: { sourceMap: true } },\n        ],\n      },\n    ],\n  },\n};\n```\n\nDo not set PostCSS `from`, `to`, or `map` inside `postcssOptions` unless you have a specific reason. The maintainer docs recommend using the loader's `sourceMap` handling instead so source-map paths stay correct.\n\n## CSS-in-JS with `postcss-js`\n\nIf your styles are written in JavaScript, enable execution and switch the parser to `postcss-js`:\n\n```bash\nnpm install --save-dev postcss-js babel-loader\n```\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.style\\.js$/,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              importLoaders: 2,\n            },\n          },\n          {\n            loader: \"postcss-loader\",\n            options: {\n              execute: true,\n              postcssOptions: {\n                parser: \"postcss-js\",\n              },\n            },\n          },\n          \"babel-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse `execute: true` only for CSS-in-JS inputs. It is not needed for normal `.css`, `.scss`, or `.less` files.\n\n## Common pitfalls\n\n- `postcss-loader` does not bundle plugins. Install each plugin explicitly, for example `postcss-preset-env` or `autoprefixer`.\n- Use the array form for `plugins`, such as `[[\"postcss-preset-env\", {}]]`. The object form is documented as deprecated.\n- Keep `importLoaders` in sync with the number of loaders that should also process `@import`ed CSS.\n- `implementation` exists, but the maintainer docs describe it as mainly useful for downstream tooling authors. Most applications should use the default `postcss` implementation.\n"
  },
  {
    "path": "content/webpack/docs/raw-loader/javascript/DOC.md",
    "content": "---\nname: raw-loader\ndescription: \"Webpack loader that imports matched files as raw source strings\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.2\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,loader,assets,text\"\n---\n\n# raw-loader\n\n`raw-loader` imports a matched file as a JavaScript string, so `import template from \"./template.html\"` gives you the file contents instead of an emitted asset URL.\n\nFor webpack 5, the maintainer docs mark `raw-loader` as deprecated in favor of Asset Modules. Use `raw-loader` for legacy configs that still rely on loader-based string imports.\n\n`raw-loader` has no auth flow, no runtime client to initialize, and no package-specific environment variables. All behavior is configured in your webpack rule.\n\n## Install\n\nInstall webpack, the CLI, and `raw-loader` in the same project:\n\n```bash\nnpm install --save-dev webpack webpack-cli raw-loader\n```\n\nRun webpack with:\n\n```bash\nnpx webpack --config webpack.config.js\n```\n\n## Basic setup\n\nImport the text-based file from your application code. The imported value is the full file contents as a string.\n\n```javascript\nimport template from \"./template.html\";\n\nconst app = document.getElementById(\"app\");\n\nif (app) {\n  app.innerHTML = template;\n}\n```\n\nConfigure webpack to use `raw-loader` for the file types you want to read as source text:\n\n```javascript\nconst path = require(\"path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(txt|html)$/i,\n        use: [\n          {\n            loader: \"raw-loader\",\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse this pattern for text-like inputs such as `.txt`, `.html`, `.svg`, `.graphql`, or shader source files when your application needs the literal file contents at runtime.\n\n## Load SVG source as markup\n\n`raw-loader` is useful when you need the SVG markup itself rather than a URL to an emitted file.\n\n```javascript\nimport iconSvg from \"./icons/check.svg\";\n\nconst wrapper = document.createElement(\"div\");\nwrapper.innerHTML = iconSvg;\n\ndocument.body.append(wrapper);\n```\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.svg$/i,\n        loader: \"raw-loader\",\n      },\n    ],\n  },\n};\n```\n\nIf you want a URL for an image tag instead of inline markup, use webpack 5 Asset Modules or a file-emitting loader instead.\n\n## CommonJS interop\n\nBy default, `raw-loader` exports ES module syntax. If another part of your build still expects CommonJS-style loader output, disable `esModule`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(txt|html|svg)$/i,\n        loader: \"raw-loader\",\n        options: {\n          esModule: false,\n        },\n      },\n    ],\n  },\n};\n```\n\nKeep the default `esModule: true` unless you have a specific compatibility issue with older CommonJS-based templates or loaders.\n\n## Migrate to webpack 5 Asset Modules\n\nFor new webpack 5 configs, prefer Asset Modules instead of `raw-loader`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(txt|html|svg)$/i,\n        type: \"asset/source\",\n      },\n    ],\n  },\n};\n```\n\nWith `asset/source`, the application code stays the same:\n\n```javascript\nimport template from \"./template.html\";\nimport iconSvg from \"./icons/check.svg\";\n```\n\nThis covers the same common workflow without an extra loader dependency.\n\n## Important option at a glance\n\n- `esModule`: switch between ESM export syntax and CommonJS export syntax\n\n## Pitfalls\n\n- `raw-loader` is deprecated for webpack 5. Prefer `type: \"asset/source\"` for new work.\n- The imported value is the full file contents, so large inputs increase your JavaScript bundle size.\n- Use `raw-loader` for text-based assets. It is not the right tool when you need a public asset URL or emitted file on disk.\n- `raw-loader` does not expose a runtime API or CLI; all behavior lives in webpack config.\n"
  },
  {
    "path": "content/webpack/docs/sass-loader/javascript/DOC.md",
    "content": "---\nname: sass-loader\ndescription: \"Webpack loader that compiles Sass and SCSS files to CSS\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"16.0.7\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,sass,scss,loader,css\"\n---\n\n# sass-loader\n\n`sass-loader` compiles `.scss`, `.sass`, and `.css` files during a webpack build.\n\nIt has no runtime client, auth flow, or package-specific environment variables. Usage is entirely build-time: import your stylesheet from application code, then configure webpack to run `sass-loader` together with `css-loader` and either `style-loader` or `mini-css-extract-plugin`.\n\n## Install\n\nInstall webpack, the loader, and a Sass implementation. The documented default implementation is `sass` (Dart Sass).\n\n```bash\nnpm install --save-dev webpack webpack-cli sass-loader sass css-loader style-loader\n```\n\nIf you want extracted CSS files in production, also install `mini-css-extract-plugin`:\n\n```bash\nnpm install --save-dev mini-css-extract-plugin\n```\n\nIf you want the faster embedded compiler, add `sass-embedded` as well:\n\n```bash\nnpm install --save-dev sass-embedded\n```\n\nWhen multiple Sass implementations are installed, `sass-loader` resolves them in this order:\n\n1. `sass-embedded`\n2. `sass`\n3. `node-sass`\n\nImportant constraints from the maintainer docs:\n\n- `node-sass` does not support the Sass `@use` rule\n- `node-sass` does not work with Yarn PnP\n- `~` imports are still supported for historical reasons, but they are deprecated\n\n## Basic setup\n\nImport your Sass entry from application code:\n\n```javascript\nimport \"./styles/app.scss\";\n```\n\nCreate a stylesheet:\n\n```scss\n$brand-color: #2563eb;\n\nbody {\n  color: $brand-color;\n}\n```\n\nConfigure webpack. Keep `sass-loader` last in the `use` array so it runs first and compiles Sass to CSS before `css-loader` and `style-loader` handle the result.\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          \"sass-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nBuild with webpack:\n\n```bash\nnpx webpack --mode development\n```\n\n## Pin the Sass implementation\n\nIf you install both `sass` and `sass-embedded`, `sass-loader` prefers `sass-embedded` automatically. If you want to pin a specific implementation, use the `implementation` option.\n\nThis example always uses Dart Sass even if `sass-embedded` is installed:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              implementation: require(\"sass\"),\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nFor `sass-loader` 16, the default API is:\n\n- `modern` for `sass` and `sass-embedded`\n- `legacy` for `node-sass`\n\nIf you use `sass-embedded`, you can opt into the modern compiler API explicitly:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              api: \"modern-compiler\",\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nThe maintainer docs recommend `sass-embedded` or Dart Sass, and note that `modern-compiler` with `sass-embedded` improves performance.\n\n## Extract CSS in production\n\nUse `style-loader` in development and `mini-css-extract-plugin` in production.\n\n```javascript\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          process.env.NODE_ENV !== \"production\"\n            ? \"style-loader\"\n            : MiniCssExtractPlugin.loader,\n          \"css-loader\",\n          \"sass-loader\",\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: \"[name].css\",\n      chunkFilename: \"[id].css\",\n    }),\n  ],\n};\n```\n\nExample production build:\n\n```bash\nNODE_ENV=production npx webpack --mode production\n```\n\nFor version 16, the maintainer docs note that Sass `style` (new API) and `outputStyle` (old API) default to `compressed` in production unless you override them in `sassOptions`.\n\n## Inject shared variables with `additionalData`\n\nUse `additionalData` to prepend Sass before each entry file. This is the usual way to inject environment-specific variables without editing every stylesheet.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              additionalData: `$build-env: ${JSON.stringify(process.env.NODE_ENV || \"development\")};`,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nThen reference the variable from Sass:\n\n```scss\n.build-banner::before {\n  content: $build-env;\n}\n```\n\n`additionalData` can also be a function when you need different values per file:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              additionalData: (content, loaderContext) => {\n                const relativePath = path.relative(loaderContext.rootContext, loaderContext.resourcePath);\n\n                if (relativePath === \"src/styles/admin.scss\") {\n                  return `$panel-padding: 24px;\\n${content}`;\n                }\n\n                return `$panel-padding: 16px;\\n${content}`;\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\n## Configure include paths and source maps\n\nUse `sassOptions` for Sass-specific configuration such as `loadPaths`. Use the loader `sourceMap` option rather than setting Sass source-map fields manually.\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  devtool: \"source-map\",\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n          {\n            loader: \"sass-loader\",\n            options: {\n              sourceMap: true,\n              sassOptions: {\n                loadPaths: [path.resolve(__dirname, \"src/styles\")],\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nNotes from the maintainer docs:\n\n- Source-map generation defaults from webpack `devtool`; all values except `eval` and `false` enable it\n- When `sourceMap: true`, `sass-loader` manages Sass source-map fields automatically\n- The default `syntax` is chosen from the file extension: `scss`, `sass`, or `css`\n- The `charset` option defaults to `true` for Dart Sass and is discouraged to disable because webpack expects UTF-8\n\n## Resolve package imports and asset URLs\n\nYou can import Sass packages directly from `node_modules` without `~`:\n\n```scss\n@use \"bootstrap\";\n```\n\nThe maintainer docs recommend removing `~bootstrap`-style imports. `sass-loader` first tries a relative path, then falls back to webpack module resolution.\n\nSass itself does not rewrite `url(...)` references. If relative asset URLs break after compilation, add `resolve-url-loader` before `sass-loader`:\n\n```bash\nnpm install --save-dev resolve-url-loader\n```\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n          \"resolve-url-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\n## Warnings, debug output, and importer behavior\n\n`@warn` becomes a webpack warning by default. If a dependency is noisy, filter it with webpack's `ignoreWarnings` option.\n\n```javascript\nmodule.exports = {\n  ignoreWarnings: [/Unknown prefix/],\n};\n```\n\nTo see Sass `@debug` output, enable debug logging for the loader:\n\n```javascript\nmodule.exports = {\n  stats: {\n    loggingDebug: [\"sass-loader\"],\n  },\n};\n```\n\n`webpackImporter` defaults to `true`. Setting it to `false` can improve performance, but webpack aliases and `~` imports stop working unless you provide your own importer.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.s[ac]ss$/i,\n        use: [\n          \"style-loader\",\n          \"css-loader\",\n          {\n            loader: \"sass-loader\",\n            options: {\n              webpackImporter: false,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n"
  },
  {
    "path": "content/webpack/docs/source-map-loader/javascript/DOC.md",
    "content": "---\nname: source-map-loader\ndescription: \"Webpack loader that extracts existing JavaScript source maps before other loaders run\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,loader,source-maps,debugging\"\n---\n\n# source-map-loader\n\n`source-map-loader` reads existing `sourceMappingURL` comments from JavaScript files and passes that map data into webpack. Use it when your app depends on libraries that already ship source maps and you want webpack's final bundle to keep accurate debugging information.\n\nFor `source-map-loader@5.0.0`, the published package declares:\n\n- Node.js `>= 18.12.0`\n- `webpack` peer dependency `^5.72.1`\n\n`source-map-loader` has no auth flow, no runtime client to initialize, and no package-specific environment variables. You do not import it in application code; you reference it by loader name in `webpack.config.js`.\n\n## Install\n\nInstall the loader alongside webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli source-map-loader\n```\n\nIf webpack is already present, add only the loader:\n\n```bash\nnpm install --save-dev source-map-loader\n```\n\n## Basic setup\n\nSet webpack to emit source maps, then run `source-map-loader` as a pre-loader for JavaScript files:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  devtool: \"source-map\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        enforce: \"pre\",\n        use: [\"source-map-loader\"],\n      },\n    ],\n  },\n};\n```\n\nAdd a build script and run webpack:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack --config webpack.config.js\"\n  }\n}\n```\n\n```bash\nnpm run build\n```\n\n`source-map-loader` extracts both inline source maps and maps linked by URL. webpack then decides how those maps appear in the final build through `devtool`.\n\n## Limit which files are scanned\n\nThe loader can read source maps from any matching JavaScript file, including files under `node_modules`. Narrow the rule when you only want specific directories or when vendor packages ship broken maps.\n\nProcess only your application source:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        include: /src/,\n        enforce: \"pre\",\n        use: [\"source-map-loader\"],\n      },\n    ],\n  },\n};\n```\n\nExclude a package that produces unusable source-map references:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        enforce: \"pre\",\n        exclude: /node_modules\\/broken-package/,\n        use: [\"source-map-loader\"],\n      },\n    ],\n  },\n};\n```\n\nUse `include` and `exclude` deliberately. The maintainer README notes that this helps keep bundling performance predictable.\n\n## Control `sourceMappingURL` handling\n\n`source-map-loader` exposes one loader option, `filterSourceMappingUrl`, for deciding what to do with each `sourceMappingURL` comment.\n\nThe callback receives `(url, resourcePath)` and can return:\n\n- `true` or `\"consume\"` to consume the source map and remove the comment\n- `false` or `\"remove\"` to ignore the source map and remove the comment\n- `\"skip\"` to ignore the source map and keep the comment in the file\n\nExample:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        enforce: \"pre\",\n        use: [\n          {\n            loader: \"source-map-loader\",\n            options: {\n              filterSourceMappingUrl: (url, resourcePath) => {\n                if (/broker-source-map-url\\.js$/i.test(url)) {\n                  return false;\n                }\n\n                if (/keep-source-mapping-url\\.js$/i.test(resourcePath)) {\n                  return \"skip\";\n                }\n\n                return true;\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse this when one dependency has bad source-map URLs but the rest of your dependency graph should still be processed normally.\n\n## Ignore known bad source-map warnings\n\nSome third-party packages publish `.js` files with missing or malformed source maps. webpack can still build, but it may warn with messages such as `Failed to parse source map`.\n\nIf you have already decided those warnings are safe to ignore, suppress them at the webpack level:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        enforce: \"pre\",\n        use: [\"source-map-loader\"],\n      },\n    ],\n  },\n  ignoreWarnings: [/Failed to parse source map/],\n};\n```\n\nPrefer narrowing the rule with `include`, `exclude`, or `filterSourceMappingUrl` first. Use `ignoreWarnings` when you want a quieter build log but do not want to stop processing the rest of your maps.\n\n## Common pitfalls\n\n- Keep `enforce: \"pre\"` on the rule so the loader runs before normal transforms.\n- Set webpack `devtool` explicitly. `source-map-loader` reads existing maps; it does not choose your final source-map output format.\n- Match JavaScript files. The maintainer docs describe this loader as extracting maps from JavaScript entries and JavaScript files.\n- Expect `node_modules` to be included unless you scope the rule more narrowly.\n- Do not import `source-map-loader` from app code. Configure it in webpack only.\n\n## Version notes for 5.0.0\n\n- The npm metadata for `5.0.0` declares Node.js `>= 18.12.0`.\n- The npm metadata for `5.0.0` declares a `webpack` peer dependency of `^5.72.1`.\n- The public maintainer README for the latest release documents a single loader option: `filterSourceMappingUrl`.\n"
  },
  {
    "path": "content/webpack/docs/style-loader/javascript/DOC.md",
    "content": "---\nname: style-loader\ndescription: \"Webpack loader that injects imported CSS into the browser DOM\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,css,loader,styles\"\n---\n\n# style-loader\n\n`style-loader` injects imported CSS into the DOM at runtime from your webpack bundle.\n\nFor `style-loader@4.0.0`, the published package declares:\n\n- Node.js `>= 18.12.0`\n- `webpack` peer dependency `^5.27.0`\n\n`style-loader` has no auth flow, no runtime client to initialize, and no package-specific environment variables. The only environment variable in this guide is `NODE_ENV`, which is used in the official recommended pattern for switching between development-time style injection and production CSS extraction.\n\n## Install\n\nInstall webpack, the loader, and `css-loader` in the same project:\n\n```bash\nnpm install --save-dev webpack webpack-cli style-loader css-loader\n```\n\nIf webpack is already installed, add only the loaders:\n\n```bash\nnpm install --save-dev style-loader css-loader\n```\n\n## Basic setup\n\nImport a stylesheet from application code:\n\n```js\nimport \"./styles.css\";\n```\n\nConfigure webpack to run `css-loader` first and `style-loader` second:\n\n```js\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\"style-loader\", \"css-loader\"],\n      },\n    ],\n  },\n};\n```\n\nWith the default `injectType: \"styleTag\"`, each imported stylesheet is injected into the page using one or more `<style>` tags.\n\nBuild the bundle with webpack:\n\n```bash\nnpx webpack --mode development\n```\n\n## Use `style-loader` in development, extract CSS in production\n\nThe maintainer docs warn that the default settings are not safe for production environments. The recommended pattern is:\n\n- use `style-loader` in development, including `webpack-dev-server`\n- use `mini-css-extract-plugin` in production so CSS is emitted as separate files\n\nInstall the extraction plugin if you want this production pattern:\n\n```bash\nnpm install --save-dev mini-css-extract-plugin\n```\n\n```js\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\");\n\nconst devMode = process.env.NODE_ENV !== \"production\";\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          devMode ? \"style-loader\" : MiniCssExtractPlugin.loader,\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n  plugins: devMode ? [] : [new MiniCssExtractPlugin()],\n};\n```\n\n```bash\nnpx webpack --mode development\nNODE_ENV=production npx webpack --mode production\n```\n\nDo not apply `style-loader` and `MiniCssExtractPlugin.loader` at the same time in the same loader chain.\n\n## CSS Modules\n\n`style-loader` works with CSS Modules through `css-loader`. For named exports, enable `modules.namedExport` on `css-loader`.\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              modules: {\n                namedExport: true,\n              },\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\n```js\nimport * as styles from \"./button.css\";\n\nconst button = document.createElement(\"button\");\nbutton.className = styles.primary;\nbutton.textContent = \"Save\";\n\ndocument.body.append(button);\n```\n\nWhen you use named exports, avoid JavaScript reserved words in CSS class names.\n\n## Load styles on demand\n\nUse `injectType: \"lazyStyleTag\"` when a stylesheet should be enabled and disabled from code.\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.lazy\\.css$/i,\n        use: [\n          {\n            loader: \"style-loader\",\n            options: {\n              injectType: \"lazyStyleTag\",\n            },\n          },\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\n```js\nimport panelStyles from \"./panel.lazy.css\";\n\ndocument.querySelector(\"#open-panel\").addEventListener(\"click\", () => {\n  panelStyles.use();\n});\n\ndocument.querySelector(\"#close-panel\").addEventListener(\"click\", () => {\n  panelStyles.unuse();\n});\n```\n\nNotes:\n\n- The docs recommend a `.lazy.css` naming convention for lazy-injected styles\n- Do not call `unuse()` more times than `use()`\n- For custom elements and Shadow DOM, the maintainer docs show `lazyStyleTag` together with a custom `insert` function and `styles.use({ target: shadowRoot })`\n\n## Control insertion order and tag attributes\n\nBy default, `style-loader` appends injected `<style>` or `<link>` elements to the end of the style target, which is the document `<head>` unless you override it. That means injected CSS takes priority over CSS already present in that target.\n\nUse `attributes` to add HTML attributes to the generated tag:\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          {\n            loader: \"style-loader\",\n            options: {\n              attributes: {\n                id: \"app-theme\",\n              },\n            },\n          },\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nUse `insert` when styles need to go somewhere other than the default end of `<head>`:\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          {\n            loader: \"style-loader\",\n            options: {\n              insert: \"body\",\n            },\n          },\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nFor custom placement logic, pass `insert: require.resolve(\"./insert-function.js\")`. That function runs in the browser; the maintainer docs recommend ES5-compatible syntax if you need support for older browsers.\n\n## Source maps and CSP nonces\n\n`style-loader` injects source maps automatically when the previous loader emits them. Enable `sourceMap: true` on `css-loader` or another earlier loader:\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          \"style-loader\",\n          {\n            loader: \"css-loader\",\n            options: {\n              sourceMap: true,\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nIf you use `injectType: \"singletonStyleTag\"`, the docs warn that source maps do not work.\n\nIf your application uses a CSP nonce, set it either through loader attributes or through `__webpack_nonce__` before importing CSS:\n\n```js\n__webpack_nonce__ = \"12345678\";\n\nrequire(\"./styles.css\");\n```\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\n          {\n            loader: \"style-loader\",\n            options: {\n              attributes: {\n                nonce: \"12345678\",\n              },\n            },\n          },\n          \"css-loader\",\n        ],\n      },\n    ],\n  },\n};\n```\n\nWhen both are present, `attributes.nonce` takes precedence over `__webpack_nonce__`. The maintainer docs also note that using a nonce weakens CSP protection and recommend avoiding this loader in production when possible.\n\n## Less-common options\n\n- `esModule` defaults to `true`; set `esModule: false` only if you need CommonJS output\n- `base` is mainly a workaround for CSS module ID clashes in `DllPlugin`-based builds\n- `linkTag` injects runtime `<link rel=\"stylesheet\">` tags, but the docs point to `mini-css-extract-plugin` when you want static stylesheet links in production\n"
  },
  {
    "path": "content/webpack/docs/terser-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: terser-webpack-plugin\ndescription: \"Webpack minimizer plugin for JavaScript bundles, with practical setup for webpack 5, source maps, comment extraction, parallel builds, and custom minifier backends.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,minify,terser,javascript\"\n---\n\n# terser-webpack-plugin\n\n`terser-webpack-plugin` plugs into webpack's `optimization.minimizer` pipeline and minifies JavaScript assets.\n\nFor webpack 5, production mode already uses a Terser-based minimizer by default. Install `terser-webpack-plugin` when you need to customize minification behavior such as source maps, comment extraction, parallelism, or the minifier implementation.\n\nThis package has no auth flow, no package-specific environment variables, and no runtime client to initialize. The integration point is your webpack configuration.\n\n## Install\n\nInstall the plugin alongside webpack:\n\n```bash\nnpm install --save-dev webpack webpack-cli terser-webpack-plugin\n```\n\nIf your project already has webpack 5, add only the plugin:\n\n```bash\nnpm install --save-dev terser-webpack-plugin\n```\n\n`terser-webpack-plugin@5.x` is for webpack 5. The upstream docs note that webpack 4 projects should stay on `terser-webpack-plugin` v4.\n\n## Basic setup\n\nAdd the plugin under `optimization.minimizer`.\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  optimization: {\n    minimize: true,\n    minimizer: [new TerserPlugin()],\n  },\n};\n```\n\nAdd a build script and run webpack normally:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack --mode production --config webpack.config.js\"\n  }\n}\n```\n\n```bash\nnpm run build\n```\n\n## Use supported source maps\n\nThe plugin only supports these `devtool` values when you want source maps:\n\n- `source-map`\n- `inline-source-map`\n- `hidden-source-map`\n- `nosources-source-map`\n\nThe upstream docs explicitly call out `eval` and `cheap` variants as unsupported for useful minifier source maps.\n\n```javascript\nconst path = require(\"node:path\");\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  devtool: \"source-map\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  optimization: {\n    minimize: true,\n    minimizer: [new TerserPlugin()],\n  },\n};\n```\n\nUse one of the supported `devtool` values before debugging minified bundles. If you use an `eval`-based or `cheap` source-map mode, the plugin cannot produce the expected mappings.\n\n## Limit which assets are minified\n\nUse `test`, `include`, and `exclude` when only part of your build should go through this minimizer.\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        test: /\\.js(\\?.*)?$/i,\n        include: /src/,\n        exclude: /vendor/,\n      }),\n    ],\n  },\n};\n```\n\nThe documented default `test` value matches JavaScript assets: `/\\.m?js(\\?.*)?$/i`.\n\n## Pass Terser options\n\n`terserOptions` is forwarded to the default Terser minifier. This is the main place to adjust compression, mangling, and comment output.\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        terserOptions: {\n          compress: {},\n          mangle: true,\n          format: {\n            comments: false,\n          },\n          keep_fnames: false,\n        },\n      }),\n    ],\n  },\n};\n```\n\nFrom the published docs:\n\n- `mangle.properties` is `false` by default\n- `format.comments` controls which comments stay in the output bundle\n- `keep_fnames` defaults to `false`\n\nIf you need the full option surface, use the Terser minify options supported by the package's `terserOptions` field.\n\n## Control license and comment extraction\n\n`extractComments` defaults to `true`. By default, the plugin extracts legal comments matching `/^\\**!|@preserve|@license|@cc_on/i` into a separate `*.LICENSE.txt` file and removes the remaining comments.\n\n### Remove comments completely\n\nUse this when you do not want preserved comments in the output bundle and do not want a separate license file.\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        terserOptions: {\n          format: {\n            comments: false,\n          },\n        },\n        extractComments: false,\n      }),\n    ],\n  },\n};\n```\n\n### Preserve license comments in a separate file\n\nUse `extractComments` as an object when you need to control the matching rule, output filename, or banner.\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        terserOptions: {\n          format: {\n            comments: /@license/i,\n          },\n        },\n        extractComments: {\n          condition: /^\\**!|@preserve|@license|@cc_on/i,\n          filename: (fileData) => `${fileData.filename}.LICENSE.txt${fileData.query}`,\n          banner: (licenseFile) => `License information can be found in ${licenseFile}`,\n        },\n      }),\n    ],\n  },\n};\n```\n\nImportant details from the maintainer docs:\n\n- the default extracted filename pattern is `[file].LICENSE.txt[query]`\n- `banner` defaults to `/*! For license information please see ${commentsFile} */`\n- using `.txt` for extracted comments is recommended; `.js`, `.cjs`, and `.mjs` can conflict with emitted assets\n\n## Tune parallelism for CI\n\n`parallel` defaults to `true`, which means the plugin uses multiple worker processes and automatically chooses the available core count minus one.\n\nIn CI environments that report CPU availability incorrectly, the official docs recommend setting an explicit number to avoid `Error: Call retries were exceeded`.\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        parallel: 2,\n      }),\n    ],\n  },\n};\n```\n\nUse `parallel: false` only if you need to disable worker processes entirely.\n\n## Switch to another minifier backend\n\nThe package exposes built-in helper functions for alternative minifiers. Set `minify` to one of the exported helpers and pass that tool's options through `terserOptions`.\n\nFor example, to use `esbuild`:\n\n```bash\nnpm install --save-dev terser-webpack-plugin esbuild\n```\n\n```javascript\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        minify: TerserPlugin.esbuildMinify,\n        terserOptions: {},\n      }),\n    ],\n  },\n};\n```\n\nThe documented built-in helpers are:\n\n- `TerserPlugin.terserMinify`\n- `TerserPlugin.esbuildMinify`\n- `TerserPlugin.swcMinify`\n- `TerserPlugin.uglifyJsMinify`\n\nBackend-specific caveats called out by the maintainer docs:\n\n- `swcMinify` does not support `extractComments`, and comments are removed by default\n- `esbuildMinify` does not support `extractComments`, and legal comments are preserved\n\n## Practical notes\n\n- If you are happy with webpack 5 production defaults, you do not need to configure this plugin explicitly.\n- Add the plugin when you need custom `parallel`, `extractComments`, `terserOptions`, or `minify` behavior.\n- When debugging source maps, start by checking `devtool` first; unsupported source-map modes are a common cause of confusing output.\n"
  },
  {
    "path": "content/webpack/docs/ts-loader/javascript/DOC.md",
    "content": "---\nname: ts-loader\ndescription: \"Webpack loader that compiles TypeScript with your project's tsconfig.json\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"9.5.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,typescript,loader,build,javascript\"\n---\n\n# ts-loader\n\n`ts-loader` runs the TypeScript compiler inside webpack. It uses your local `typescript` installation and the project's `tsconfig.json`, then hands the transpiled output back to webpack for bundling.\n\n`ts-loader@9.5.4` is build-time configuration only: there is no auth flow, no runtime client to initialize, and no package-specific environment variables.\n\n## Install\n\nInstall `ts-loader` in the same project as webpack and TypeScript:\n\n```bash\nnpm install --save-dev webpack webpack-cli typescript ts-loader\n```\n\nTypical scripts:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack\",\n    \"watch\": \"webpack --watch\"\n  }\n}\n```\n\n## Minimal setup\n\n`ts-loader` looks for `tsconfig.json` by default.\n\n`tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es2020\",\n    \"module\": \"esnext\",\n    \"strict\": true,\n    \"sourceMap\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src/**/*\"]\n}\n```\n\n`src/index.ts`:\n\n```typescript\nconst message: string = \"Hello from ts-loader\";\n\ndocument.body.textContent = message;\n```\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.ts\",\n  output: {\n    filename: \"bundle.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  resolve: {\n    extensions: [\".ts\", \".tsx\", \".js\"],\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        exclude: /node_modules/,\n        use: \"ts-loader\",\n      },\n    ],\n  },\n  devtool: \"inline-source-map\",\n};\n```\n\nBuild the bundle:\n\n```bash\nnpm run build\nnpm run watch\n```\n\n## Use a different `tsconfig`\n\nPoint the loader at a dedicated build config when webpack should not use the default `tsconfig.json`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: \"ts-loader\",\n          options: {\n            configFile: \"tsconfig.webpack.json\",\n          },\n        },\n      },\n    ],\n  },\n};\n```\n\nUse this when your repo has separate configs for tests, editors, and bundling.\n\n## Faster builds with `transpileOnly`\n\n`transpileOnly: true` skips full type checking inside the loader and only transpiles each file. Pair it with `fork-ts-checker-webpack-plugin` if you still want TypeScript diagnostics during webpack builds.\n\n```bash\nnpm install --save-dev fork-ts-checker-webpack-plugin\n```\n\n```javascript\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: \"ts-loader\",\n          options: {\n            transpileOnly: true,\n          },\n        },\n      },\n    ],\n  },\n  plugins: [new ForkTsCheckerWebpackPlugin()],\n};\n```\n\nKeep `transpileOnly` off when the webpack build itself must perform normal TypeScript checking and declaration-file emission.\n\n## Source maps\n\nEnable source maps in both TypeScript and webpack:\n\n```json\n{\n  \"compilerOptions\": {\n    \"sourceMap\": true\n  }\n}\n```\n\n```javascript\nmodule.exports = {\n  devtool: \"inline-source-map\",\n};\n```\n\n`compilerOptions.sourceMap` controls TypeScript emit. webpack's `devtool` controls how the final bundle exposes those maps.\n\n## TypeScript path aliases\n\nwebpack does not automatically read `compilerOptions.paths`. If your `tsconfig.json` uses path aliases, add `tsconfig-paths-webpack-plugin` to webpack resolution.\n\n```bash\nnpm install --save-dev tsconfig-paths-webpack-plugin\n```\n\n`tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@app/*\": [\"src/*\"]\n    }\n  }\n}\n```\n\n`webpack.config.js`:\n\n```javascript\nconst TsconfigPathsPlugin = require(\"tsconfig-paths-webpack-plugin\");\n\nmodule.exports = {\n  resolve: {\n    extensions: [\".ts\", \".tsx\", \".js\"],\n    plugins: [new TsconfigPathsPlugin()],\n  },\n};\n```\n\n## ESM-style import specifiers\n\nIf your TypeScript source uses fully qualified `.js`, `.mjs`, or `.cjs` import specifiers, map them back to TypeScript source files with webpack's `resolve.extensionAlias`.\n\n```javascript\nmodule.exports = {\n  resolve: {\n    extensions: [\".ts\", \".tsx\", \".js\", \".mts\", \".cts\"],\n    extensionAlias: {\n      \".js\": [\".js\", \".ts\"],\n      \".mjs\": [\".mjs\", \".mts\"],\n      \".cjs\": [\".cjs\", \".cts\"],\n    },\n  },\n};\n```\n\nThis is useful for projects that keep ESM-compatible import specifiers in source code while authoring in TypeScript.\n\n## Declaration files\n\nIf the webpack build should also emit `.d.ts` files, enable declaration output in `tsconfig.json` and keep `transpileOnly` disabled.\n\n```json\n{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"declarationMap\": true\n  }\n}\n```\n\n## Common pitfalls\n\n- Install `typescript` locally. `ts-loader` relies on your project's TypeScript compiler.\n- Keep `resolve.extensions` aligned with the file types you compile, especially when mixing `.ts`, `.tsx`, `.mts`, or `.cts` files.\n- `transpileOnly: true` improves build speed, but it skips loader-level type checking and declaration-file generation.\n- If TypeScript path aliases work in your editor but fail in webpack, add `TsconfigPathsPlugin`.\n- Source maps need both `compilerOptions.sourceMap` and a webpack `devtool` setting.\n"
  },
  {
    "path": "content/webpack/docs/url-loader/javascript/DOC.md",
    "content": "---\nname: url-loader\ndescription: \"Webpack loader that inlines imported files as data URLs and falls back to emitted files above a size limit\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"4.1.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,build,assets,loader,data-url\"\n---\n\n# url-loader\n\n`url-loader` transforms imported files into `data:` URLs. When you set a `limit`, files smaller than that threshold stay inline and larger files are handed off to a fallback loader, which is typically `file-loader`.\n\nFor webpack 5, the maintainer docs mark `url-loader` as deprecated in favor of Asset Modules. Use `url-loader` for legacy configs that still depend on loader-based asset handling.\n\n`url-loader` has no auth flow, no runtime client to initialize, and no package-specific environment variables. All behavior is configured in your webpack rule.\n\n## Install\n\nInstall webpack, the CLI, `url-loader`, and `file-loader` if you want the usual \"inline small files, emit larger ones\" behavior:\n\n```bash\nnpm install --save-dev webpack webpack-cli url-loader file-loader\n```\n\nRun webpack with:\n\n```bash\nnpx webpack --config webpack.config.js\n```\n\n## Basic setup\n\nImport the asset from your application code. The imported value is always a string:\n\n- a `data:` URL when the file stays inline\n- a public asset URL when the rule falls back to `file-loader`\n\n```javascript\nimport logoUrl from \"./assets/logo.png\";\n\nconst image = document.createElement(\"img\");\nimage.src = logoUrl;\nimage.alt = \"Logo\";\n\ndocument.body.append(image);\n```\n\nConfigure webpack to inline files under `8 KB` and emit larger files through `file-loader`:\n\n```javascript\nconst path = require(\"path\");\n\nconst inlineLimit = Number(process.env.ASSET_INLINE_LIMIT || 8192);\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"bundle.js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        use: [\n          {\n            loader: \"url-loader\",\n            options: {\n              limit: inlineLimit,\n              fallback: \"file-loader\",\n              name: \"static/media/[name].[contenthash].[ext]\",\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n```\n\nNotes:\n\n- `url-loader` does not read `ASSET_INLINE_LIMIT` itself; that environment variable is just an application-level way to tune the webpack config\n- files with size equal to or greater than `limit` use the fallback loader\n- if you omit `limit`, `url-loader` keeps matched files inline instead of emitting them\n\n## Inline everything\n\nIf you want every matched import turned into a `data:` URL, omit `limit` and use `url-loader` directly:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"url-loader\",\n      },\n    ],\n  },\n};\n```\n\nThis is most useful for very small assets. Inlining large files increases bundle size and moves the asset bytes into your JavaScript payload.\n\n## Configure fallback output separately\n\nUse an object form for `fallback` when you want different settings for the emitted-file path or filename:\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"url-loader\",\n        options: {\n          limit: 4096,\n          fallback: {\n            loader: \"file-loader\",\n            options: {\n              name: \"static/assets/[name].[contenthash].[ext]\",\n              publicPath: \"/assets/\",\n            },\n          },\n        },\n      },\n    ],\n  },\n};\n```\n\nThat keeps small files inline and gives large files a predictable emitted URL like `/assets/logo.a1b2c3.png`.\n\n## Optimize SVG data URLs\n\nFor SVG, a custom generator can produce smaller data URLs than default base64 encoding. A common pattern is to use `mini-svg-data-uri`.\n\n```bash\nnpm install --save-dev mini-svg-data-uri\n```\n\n```javascript\nconst svgToMiniDataURI = require(\"mini-svg-data-uri\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.svg$/i,\n        loader: \"url-loader\",\n        options: {\n          limit: 4096,\n          generator: (content) => svgToMiniDataURI(content.toString()),\n        },\n      },\n    ],\n  },\n};\n```\n\nUse this only for assets that should stay inline. Larger SVG files still work better as emitted files or webpack 5 Asset Modules.\n\n## CommonJS interop\n\nBy default, `url-loader` exports ES module syntax. If another part of your build still expects CommonJS-style loader output, disable `esModule`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        loader: \"url-loader\",\n        options: {\n          limit: 8192,\n          esModule: false,\n        },\n      },\n    ],\n  },\n};\n```\n\nKeep the default `esModule: true` unless you have a specific compatibility issue with older templates or loaders.\n\n## Migrate to webpack 5 Asset Modules\n\nFor new webpack 5 configs, prefer Asset Modules instead of `url-loader`.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.(png|jpe?g|gif|svg)$/i,\n        type: \"asset\",\n        parser: {\n          dataUrlCondition: {\n            maxSize: 8 * 1024,\n          },\n        },\n        generator: {\n          filename: \"static/media/[name].[contenthash][ext]\",\n        },\n      },\n    ],\n  },\n};\n```\n\nThat webpack 5 rule covers the same common workflow: small files become inline data URLs and larger files are emitted automatically.\n\n## Important options at a glance\n\n- `limit`: maximum file size in bytes before the loader switches to the fallback\n- `fallback`: loader used when a file is too large to inline; often `file-loader`\n- `mimetype`: override the MIME type used in the generated `data:` URL\n- `encoding`: override the data URL encoding; default output is base64 for normal cases\n- `generator`: build a custom data URL string, which is useful for SVG optimization\n- `esModule`: switch between ESM export syntax and CommonJS-style export syntax\n\n## Pitfalls\n\n- `url-loader` is deprecated for webpack 5. Prefer Asset Modules for new work.\n- `limit` is checked against file size before fallback. Files at or above the threshold are not inlined.\n- If you inline everything, your JavaScript bundle carries the full asset payload.\n- The imported value is always a string URL, but the format changes: `data:` URL for inline assets, normal asset URL for fallback output.\n- `url-loader` does not provide a runtime API or CLI; all behavior lives in webpack config.\n"
  },
  {
    "path": "content/webpack/docs/webpack/javascript/DOC.md",
    "content": "---\nname: webpack\ndescription: \"JavaScript guide for configuring and running webpack 5 builds, including local CLI setup, the Node API, watch mode, and common pitfalls.\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.105.4\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,webpack-cli,bundler,build,javascript,node-api\"\n---\n\n# webpack for JavaScript\n\n`webpack` is the core bundler package. For normal command-line use, install `webpack-cli` alongside it. The `webpack` package publishes the compiler, the Node API, built-in plugins such as `DefinePlugin`, and a `webpack` binary that hands off to `webpack-cli` when the CLI package is installed.\n\nThere is no authentication step and no package-specific environment variable to set.\n\n## Prerequisites\n\n- Node.js. The `webpack` package declares `>=10.13.0`, but use a current Node LTS for modern webpack tooling.\n- `webpack@5.105.4`\n- `webpack-cli` for command-line builds\n\n## Install\n\nMost projects should install both packages locally:\n\n```bash\nnpm install --save-dev webpack webpack-cli\n```\n\nIf you only run webpack through the Node API, `webpack` is the required package and `webpack-cli` is optional.\n\n## Minimal project setup\n\nAdd build scripts in `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack --config webpack.config.js --mode production\",\n    \"watch\": \"webpack --config webpack.config.js --watch --mode development\"\n  }\n}\n```\n\nCreate `webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n};\n```\n\n`output.path` should be an absolute filesystem path, which is why the config uses `path.resolve(...)`.\n\nCreate a matching entry file:\n\n```javascript\n// src/index.js\nconsole.log(\"webpack build is running\");\n```\n\nRun the build:\n\n```bash\nnpm run build\n```\n\n## Run from the CLI\n\nWith `webpack-cli` installed locally, these commands use your project config:\n\n```bash\n# Production build\nnpx webpack --config webpack.config.js --mode production\n\n# Rebuild on file changes\nnpx webpack --config webpack.config.js --watch --mode development\n```\n\nThe `webpack` package ships the `webpack` executable, but that executable delegates real CLI work to `webpack-cli`. If `webpack-cli` is missing, the binary prompts to install it.\n\n## Use the Node API\n\nThe `webpack` module itself exports the compiler factory. Pass one config object to get a `Compiler`, then call `run` and `close`.\n\n```javascript\nconst path = require(\"node:path\");\nconst webpack = require(\"webpack\");\n\nconst config = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n};\n\nconst compiler = webpack(config);\n\ncompiler.run((error, stats) => {\n  if (error) {\n    console.error(error);\n  } else if (stats) {\n    console.log(\n      stats.toString({\n        colors: true,\n        modules: false,\n        chunks: false,\n      }),\n    );\n  }\n\n  compiler.close((closeError) => {\n    if (closeError) {\n      console.error(closeError);\n      process.exitCode = 1;\n    }\n  });\n});\n```\n\nIf you pass an array of configs instead of one config object, `webpack(...)` returns a `MultiCompiler`.\n\n## Watch from Node\n\nUse `compiler.watch(...)` when your app or dev server should manage rebuilds directly.\n\n```javascript\nconst path = require(\"node:path\");\nconst webpack = require(\"webpack\");\n\nconst config = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n  },\n};\n\nconst compiler = webpack(config);\n\nconst watching = compiler.watch({ aggregateTimeout: 300 }, (error, stats) => {\n  if (error) {\n    console.error(error);\n    return;\n  }\n\n  if (stats) {\n    console.log(stats.toString({ colors: true, modules: false, chunks: false }));\n  }\n});\n\nprocess.on(\"SIGINT\", () => {\n  watching.close((closeError) => {\n    if (closeError) {\n      console.error(closeError);\n      process.exitCode = 1;\n    }\n\n    process.exit();\n  });\n});\n```\n\nThe watch handle also exposes `invalidate()` if you need to trigger another rebuild programmatically.\n\n## Use built-in plugins from `webpack`\n\nPlugin constructors are exported from the same package. For example, use `DefinePlugin` to replace compile-time constants:\n\n```javascript\nconst path = require(\"node:path\");\nconst webpack = require(\"webpack\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      __BUILD_TARGET__: JSON.stringify(\"web\"),\n      __FEATURE_FLAG__: JSON.stringify(process.env.FEATURE_FLAG ?? \"off\"),\n    }),\n  ],\n};\n```\n\nThis is ordinary Node configuration code. `FEATURE_FLAG` is an application environment variable in this example, not a webpack-specific one.\n\n## Important pitfalls\n\n- Install `webpack-cli` for CLI-driven builds. The `webpack` package's `webpack` binary forwards to it rather than replacing it.\n- Use an absolute `output.path`.\n- When you use the Node API, call `compiler.close(...)` after `run(...)` finishes.\n- When you use watch mode from Node, keep the returned `Watching` handle and call `watching.close(...)` during shutdown.\n- For browser targets that rely on `import()` or `require.ensure()` in older browsers, load a `Promise` polyfill before your bundle.\n\n## Version notes\n\n- This guide targets `webpack@5.105.4`.\n- The webpack 5 package publishes its own Node API and built-in plugin constructors from the `webpack` module.\n- Command-line workflows in current projects still pair `webpack` with `webpack-cli`.\n\n## Official sources\n\n- https://www.npmjs.com/package/webpack\n- https://github.com/webpack/webpack\n- https://webpack.js.org/guides/getting-started/\n- https://webpack.js.org/concepts/\n- https://webpack.js.org/api/node/\n- https://webpack.js.org/configuration/output/\n- https://webpack.js.org/plugins/define-plugin/\n"
  },
  {
    "path": "content/webpack/docs/webpack-bundle-analyzer/javascript/DOC.md",
    "content": "---\nname: webpack-bundle-analyzer\ndescription: \"Analyze webpack bundle composition with the BundleAnalyzerPlugin or CLI, generate stats files, and export static reports\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,webpack-bundle-analyzer,bundle-analysis,performance,build,javascript\"\n---\n\n# webpack-bundle-analyzer for JavaScript\n\n`webpack-bundle-analyzer` helps you inspect what is inside a webpack build. In practice you use it in one of two ways:\n\n- add `BundleAnalyzerPlugin` to `webpack.config.js`\n- run the `webpack-bundle-analyzer` CLI against a webpack stats file\n\nThere is no authentication step.\n\n## Prerequisites\n\n- a JavaScript project that already builds with webpack\n- a local webpack config you can edit if you want to use `BundleAnalyzerPlugin`\n- emitted bundle files on disk if you want the CLI report to calculate file-based size views from real assets\n\nThis guide targets `webpack-bundle-analyzer@5.2.0`. Examples use a CommonJS `webpack.config.js` in a webpack 5-style project.\n\n## Install\n\n```bash\nnpm install --save-dev webpack-bundle-analyzer\n```\n\nIf webpack is not already installed in the project, install it too:\n\n```bash\nnpm install --save-dev webpack webpack-cli\n```\n\n## Minimal plugin setup\n\nUse the plugin when you want the report generated directly from your normal webpack build.\n\n```javascript\nconst path = require(\"node:path\");\nconst { BundleAnalyzerPlugin } = require(\"webpack-bundle-analyzer\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins: [new BundleAnalyzerPlugin()],\n};\n```\n\nRun a production build:\n\n```bash\nnpx webpack --mode production\n```\n\nThat build runs the analyzer in its default interactive mode and serves a local report for the generated bundle.\n\n## Enable analysis only when requested\n\nIn most projects you do not want the analyzer running on every build. Gate it behind an environment variable and use a static HTML report for CI or one-off checks.\n\n```javascript\nconst path = require(\"node:path\");\nconst { BundleAnalyzerPlugin } = require(\"webpack-bundle-analyzer\");\n\nconst plugins = [];\n\nif (process.env.ANALYZE === \"true\") {\n  plugins.push(\n    new BundleAnalyzerPlugin({\n      analyzerMode: \"static\",\n      openAnalyzer: false,\n      reportFilename: path.resolve(__dirname, \"dist/bundle-report.html\"),\n    })\n  );\n}\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins,\n};\n```\n\nRun it only when needed:\n\n```bash\nANALYZE=true npx webpack --mode production\n```\n\nThis keeps regular builds unchanged and writes a reusable HTML report under `dist/bundle-report.html` when analysis is enabled.\n\n## Generate `stats.json` during a build\n\nIf you want webpack stats without opening the analyzer UI, disable the analyzer UI and ask the plugin to emit a stats file.\n\n```javascript\nconst path = require(\"node:path\");\nconst { BundleAnalyzerPlugin } = require(\"webpack-bundle-analyzer\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n  plugins: [\n    new BundleAnalyzerPlugin({\n      analyzerMode: \"disabled\",\n      generateStatsFile: true,\n      statsFilename: \"stats.json\",\n    }),\n  ],\n};\n```\n\nRun the build normally:\n\n```bash\nnpx webpack --mode production\n```\n\nUse this when another tool or a later step will inspect the stats file.\n\n## Analyze an existing stats file from the CLI\n\nUse the CLI when you already have webpack stats or when you do not want to modify the webpack config.\n\nGenerate a stats file from webpack:\n\n```bash\nnpx webpack --profile --json > stats.json\n```\n\nThen analyze it:\n\n```bash\nnpx webpack-bundle-analyzer stats.json dist/\n```\n\nThe first argument is the webpack stats JSON file. The second argument is the directory containing the emitted bundle files.\n\nPassing the bundle directory is important when you want the report to calculate file-based views from the built assets instead of relying only on the stats payload.\n\n## Common options\n\nThese are the options you will use most often:\n\n- `analyzerMode`: use `\"server\"` for a local interactive report, `\"static\"` for an HTML file, or `\"disabled\"` when you only want `stats.json`\n- `openAnalyzer`: set `false` in CI or headless environments so the build does not try to open a browser\n- `reportFilename`: path for the static HTML report\n- `generateStatsFile`: write webpack stats to disk during the build\n- `statsFilename`: output path for the generated stats file\n- `defaultSizes`: pick the initial size view with `\"stat\"`, `\"parsed\"`, `\"gzip\"`, or `\"brotli\"`\n- `excludeAssets`: hide assets you do not want in the report, such as source maps\n\nExample excluding source maps from the report:\n\n```javascript\nconst { BundleAnalyzerPlugin } = require(\"webpack-bundle-analyzer\");\n\nmodule.exports = {\n  plugins: [\n    new BundleAnalyzerPlugin({\n      excludeAssets: [/\\.map$/],\n    }),\n  ],\n};\n```\n\n## Practical workflow\n\nFor local investigation, this is usually enough:\n\n1. build with `BundleAnalyzerPlugin` enabled\n2. inspect the largest packages and duplicated dependencies in the treemap\n3. switch the initial view with `defaultSizes` if you care about transfer size rather than raw bundle size\n4. rerun the production build after changing imports, split points, or dependency choices\n\nFor CI or shareable output, prefer `analyzerMode: \"static\"` with `openAnalyzer: false` so the build leaves behind an HTML artifact.\n\n## Important pitfalls\n\n- analyze a production build if you care about shipped size; development builds can be much noisier and less representative\n- the CLI expects webpack stats JSON, not a generated `bundle.js` file\n- if you use the CLI without pointing it at the emitted bundle directory, some size views depend on what is available in the stats payload versus the built files on disk\n- source maps and copied assets can dominate the visualization; filter them out with `excludeAssets` if they are not relevant to the question you are answering\n\n## Version notes\n\n- this doc covers `webpack-bundle-analyzer@5.2.0`\n- examples use `require(...)` in `webpack.config.js`; if your webpack config is ESM, import `BundleAnalyzerPlugin` from `webpack-bundle-analyzer` and construct it the same way\n"
  },
  {
    "path": "content/webpack/docs/webpack-cli/javascript/DOC.md",
    "content": "---\nname: webpack-cli\ndescription: \"webpack CLI for local builds, watch mode, dev-server workflows, and configuration management in JavaScript projects\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,webpack-cli,build,bundler,javascript\"\n---\n\n# webpack-cli for JavaScript\n\n`webpack-cli` is the command-line interface for webpack. In normal projects you install it locally, add a `webpack.config.js`, and run it through `webpack` in package scripts or with `npx`.\n\nThere is no authentication step.\n\n## Prerequisites\n\n- Node.js `>=18.12.0`\n- `webpack-cli@6.0.1`\n- `webpack@^5.82.0` because `webpack-cli@6` declares webpack as a peer dependency\n- `webpack-dev-server` if you want to use `webpack serve`\n\n## Install\n\n```bash\nnpm install --save-dev webpack webpack-cli\n\n# Only if you use `webpack serve`\nnpm install --save-dev webpack-dev-server\n```\n\nUse a local install and call it through package scripts or `npx`. The CLI prefers a local project copy by default.\n\n## Minimal project setup\n\nAdd scripts to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"webpack --mode production\",\n    \"dev\": \"webpack serve --mode development\",\n    \"watch\": \"webpack watch --mode development\",\n    \"check:webpack\": \"webpack configtest ./webpack.config.js\",\n    \"webpack:info\": \"webpack info --output markdown\"\n  }\n}\n```\n\nCreate `webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    clean: true,\n  },\n};\n```\n\nRun the build:\n\n```bash\nnpm run build\n```\n\nIf you do not pass `--config`, webpack-cli looks for default config files such as `webpack.config.*` first.\n\n## Build from the CLI\n\nThe default command is `build`, so these are equivalent:\n\n```bash\nnpx webpack\nnpx webpack build\n```\n\nCommon build commands:\n\n```bash\n# Development build\nnpx webpack --mode development\n\n# Production build\nnpx webpack --mode production\n\n# Override the config file path\nnpx webpack --config ./config/webpack.prod.js --mode production\n\n# Write output to an absolute directory path\nnpx webpack ./src/index.js --output-path /absolute/path/to/dist --mode production\n\n# Emit stats JSON to stdout or a file\nnpx webpack --json\nnpx webpack --json ./build-stats.json\n```\n\n`--output-path` expects an absolute path.\n\n## Config functions and `--env`\n\nWhen your config exports a function, webpack-cli calls it with `(env, argv)`. Use `--env` for custom values and `--config-node-env` to set `process.env.NODE_ENV` before the config runs.\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = (env = {}, argv = {}) => {\n  const isProd = argv.mode === \"production\";\n\n  return {\n    mode: argv.mode ?? \"development\",\n    entry: env.entry ?? \"./src/index.js\",\n    output: {\n      filename: env.minify ? \"main.min.js\" : \"main.js\",\n      path: path.resolve(__dirname, \"dist\"),\n      clean: true,\n    },\n    devtool: isProd ? \"source-map\" : \"eval-cheap-module-source-map\",\n  };\n};\n```\n\n```bash\n# Pass flags into the config function\nnpx webpack --env entry=./src/admin.js --env minify --mode production\n\n# Set NODE_ENV for config code\nnpx webpack --config-node-env production --mode production\n```\n\n`--node-env` still exists, but the CLI marks it as deprecated in favor of `--config-node-env`.\n\n## Named and merged configurations\n\nUse `--config-name` when one config file exports multiple named configurations:\n\n```javascript\nconst path = require(\"node:path\");\n\nmodule.exports = [\n  {\n    name: \"client\",\n    entry: \"./src/client.js\",\n    output: {\n      filename: \"client.js\",\n      path: path.resolve(__dirname, \"dist\"),\n    },\n  },\n  {\n    name: \"server\",\n    target: \"node\",\n    entry: \"./src/server.js\",\n    output: {\n      filename: \"server.js\",\n      path: path.resolve(__dirname, \"dist\"),\n    },\n  },\n];\n```\n\n```bash\nnpx webpack --config ./webpack.config.js --config-name client\nnpx webpack --config ./webpack.config.js --config-name client --config-name server\n```\n\nUse `--merge` to combine multiple config files with `webpack-merge`:\n\n```bash\nnpx webpack \\\n  --config ./webpack.common.js \\\n  --config ./webpack.prod.js \\\n  --merge \\\n  --mode production\n```\n\nwebpack-cli also supports an `extends` property inside a config, and a CLI-level `--extends` flag. CLI-provided `--extends` entries take priority over `extends` inside the config file.\n\n## Watch mode and dev server\n\nUse `watch` for rebuilds on file change:\n\n```bash\nnpx webpack watch --mode development\n```\n\nUse `serve` to run `webpack-dev-server`:\n\n```bash\nnpx webpack serve --mode development\n```\n\nYou can branch config behavior by command. webpack-cli passes command flags in the `env` object for function-based configs:\n\n```javascript\nmodule.exports = (env = {}) => ({\n  devServer: env.WEBPACK_SERVE\n    ? {\n        hot: true,\n        port: 3000,\n      }\n    : undefined,\n});\n```\n\nThe CLI documents these command flags:\n\n- `env.WEBPACK_BUILD` for `webpack build`\n- `env.WEBPACK_WATCH` for `webpack watch`\n- `env.WEBPACK_SERVE` for `webpack serve`\n\nDo not combine `webpack watch` or `webpack serve` with `watch: true` in config or `--watch` on the CLI. webpack-cli warns that this combination does not make sense, and `serve` disables `watch` internally.\n\n## Validate and inspect your setup\n\nValidate a config file without running a build:\n\n```bash\nnpx webpack configtest ./webpack.config.js\n```\n\nShow installed versions that matter to webpack:\n\n```bash\nnpx webpack version\n```\n\nCollect environment details for issue reports:\n\n```bash\nnpx webpack info\nnpx webpack info --output markdown\nnpx webpack info --output json --additional-package react\n```\n\n## Useful environment variables\n\nwebpack-cli documents these environment variables:\n\n- `WEBPACK_CLI_SKIP_IMPORT_LOCAL=true` skips the normal behavior of reusing the local project installation of `webpack-cli`\n- `WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG=true` forces ESM config loading\n- `WEBPACK_PACKAGE` points the CLI at a custom webpack package\n- `WEBPACK_DEV_SERVER_PACKAGE` points `serve` at a custom `webpack-dev-server` package\n- `WEBPACK_CLI_HELP_WIDTH` changes the help output width\n\nExample:\n\n```bash\nWEBPACK_CLI_FORCE_LOAD_ESM_CONFIG=true npx webpack --config ./webpack.config.mjs\n```\n\n## Common pitfalls\n\n- Install `webpack` and `webpack-cli` together. `webpack-cli` is not the bundler itself.\n- Install `webpack-dev-server` before using `webpack serve`.\n- Prefer `--config-node-env` over `--node-env`.\n- Pass an absolute path to `--output-path`.\n- If you use a non-JavaScript config format such as TypeScript, webpack-cli relies on loader resolution through `interpret` and `rechoir`; if the required loader is missing, config loading fails before compilation starts.\n\n## Exit codes\n\n- `0`: success\n- `1`: webpack compilation errors\n- `2`: configuration problems, option problems, or internal CLI errors\n"
  },
  {
    "path": "content/webpack/docs/webpack-dev-middleware/javascript/DOC.md",
    "content": "---\nname: webpack-dev-middleware\ndescription: \"Use webpack-dev-middleware to compile with webpack in watch mode and serve emitted assets from memory in a Node development server\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.4.5\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,middleware,development,express,koa,hono\"\n---\n\n# webpack-dev-middleware JavaScript Guide\n\nUse `webpack-dev-middleware` when you want your own Node server to run webpack in development and serve the emitted files directly from an in-memory filesystem.\n\n## Prerequisites\n\n- Node.js `>=18.12.0`\n- `webpack-dev-middleware@7.4.5`\n- `webpack@^5.0.0`\n- No authentication or environment variables are required\n\nInstall the middleware, webpack, and your server framework:\n\n```bash\nnpm install --save-dev webpack webpack-dev-middleware\nnpm install express\n```\n\n## Minimal webpack config\n\n`webpack-dev-middleware` serves files from memory, but your webpack config still needs a real `output.path` and a stable `output.publicPath`.\n\n`webpack.config.js`\n\n```js\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    publicPath: \"/assets/\",\n    clean: true,\n  },\n};\n```\n\n## Express setup\n\nThe maintainer README shows `webpack-dev-middleware` as connect-style middleware. Create a webpack compiler, pass it to `devMiddleware()`, and mount the returned middleware on your app.\n\n`server.js`\n\n```js\nconst express = require(\"express\");\nconst webpack = require(\"webpack\");\nconst devMiddleware = require(\"webpack-dev-middleware\");\nconst webpackConfig = require(\"./webpack.config.js\");\n\nconst compiler = webpack(webpackConfig);\nconst app = express();\n\nconst middleware = devMiddleware(compiler, {\n  publicPath: webpackConfig.output.publicPath,\n  stats: \"minimal\",\n});\n\napp.use(middleware);\n\napp.get(\"/\", (req, res) => {\n  res.send(`<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>webpack-dev-middleware</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"${webpackConfig.output.publicPath}main.js\"></script>\n  </body>\n</html>`);\n});\n\nconst server = app.listen(3000, () => {\n  console.log(\"Listening on http://localhost:3000\");\n});\n\nprocess.on(\"SIGINT\", () => {\n  middleware.close(() => {\n    server.close(() => process.exit(0));\n  });\n});\n```\n\nImportant behavior:\n\n- The browser still reads bundle files from memory, not from `dist/`\n- `publicPath` should normally match `output.publicPath`\n- The middleware accepts `GET` and `HEAD` requests by default\n\n## Common options\n\nUse the middleware options for caching, response headers, and disk writes.\n\n```js\nconst middleware = devMiddleware(compiler, {\n  publicPath: webpackConfig.output.publicPath,\n  stats: \"minimal\",\n  headers: {\n    \"X-Dev-Server\": \"webpack-dev-middleware\",\n  },\n  etag: \"weak\",\n  lastModified: true,\n  cacheControl: false,\n  writeToDisk: (filePath) => filePath.endsWith(\".css\"),\n});\n```\n\nNotes:\n\n- `writeToDisk` defaults to `false`\n- `writeToDisk: true` writes emitted files to disk, but requests are still served from memory\n- `writeToDisk` can be a predicate function to select which files are written\n- `index: false` disables automatic responses for the root URL\n- `cacheImmutable: true` prefers immutable cache headers for hashed assets\n- `outputFileSystem` defaults to `memfs`; only override it if you need webpack to emit to a different filesystem object\n\n## Runtime API\n\nThe middleware instance is also an API object with helper methods.\n\n```js\nconst middleware = devMiddleware(compiler, {\n  publicPath: webpackConfig.output.publicPath,\n});\n\napp.use(middleware);\n\nmiddleware.waitUntilValid((stats) => {\n  if (stats) {\n    console.log(\"Bundle is valid\");\n  }\n});\n\napp.post(\"/__rebuild\", (req, res) => {\n  middleware.invalidate(() => {\n    res.status(202).send(\"Rebuild started\");\n  });\n});\n\napp.get(\"/__asset-path\", (req, res) => {\n  const filename = middleware.getFilenameFromUrl(\"/assets/main.js\");\n\n  if (!filename) {\n    res.status(404).send(\"Asset not ready\");\n    return;\n  }\n\n  res.send(filename);\n});\n```\n\nUse these methods when you need to coordinate your own server with webpack state:\n\n- `waitUntilValid(callback)` runs after the current build becomes valid and runs immediately if the bundle is already valid\n- `invalidate(callback)` tells webpack to rebuild, which is useful after changing compiler configuration or plugins at runtime\n- `getFilenameFromUrl(url)` resolves a served asset URL to the underlying emitted filename\n- `close(callback)` stops file watching\n\n## Server-side rendering\n\n`serverSideRender: true` is documented as experimental. When enabled, the middleware adds webpack build data to `res.locals.webpack.devMiddleware` before calling the next middleware.\n\n```js\nconst path = require(\"node:path\");\n\nfunction normalizeAssets(assets) {\n  if (assets && !Array.isArray(assets) && typeof assets === \"object\") {\n    return Object.values(assets);\n  }\n\n  return Array.isArray(assets) ? assets : [assets];\n}\n\napp.use(\n  devMiddleware(compiler, {\n    publicPath: webpackConfig.output.publicPath,\n    serverSideRender: true,\n  }),\n);\n\napp.get(\"/\", (req, res) => {\n  const { devMiddleware } = res.locals.webpack;\n  const jsonWebpackStats = devMiddleware.stats.toJson();\n  const mainAssets = normalizeAssets(jsonWebpackStats.assetsByChunkName.main).filter(Boolean);\n\n  const styles = mainAssets\n    .filter((asset) => asset.endsWith(\".css\"))\n    .map((asset) =>\n      devMiddleware.outputFileSystem.readFileSync(\n        path.join(jsonWebpackStats.outputPath, asset),\n      ),\n    )\n    .join(\"\\n\");\n\n  const scripts = mainAssets\n    .filter((asset) => asset.endsWith(\".js\"))\n    .map((asset) => `<script src=\"${webpackConfig.output.publicPath}${asset}\"></script>`)\n    .join(\"\\n\");\n\n  res.send(`<!doctype html>\n<html>\n  <head>${styles}</head>\n  <body>\n    <div id=\"app\"></div>\n    ${scripts}\n  </body>\n</html>`);\n});\n```\n\nUse this mode only when you need webpack stats and the in-memory output filesystem inside your own render pipeline.\n\n## Other supported servers\n\nThe package also documents wrappers for several non-Express servers.\n\n### Koa\n\n```js\nconst Koa = require(\"koa\");\nconst webpack = require(\"webpack\");\nconst devMiddleware = require(\"webpack-dev-middleware\");\nconst webpackConfig = require(\"./webpack.config.js\");\n\nconst compiler = webpack(webpackConfig);\nconst app = new Koa();\n\napp.use(\n  devMiddleware.koaWrapper(compiler, {\n    publicPath: webpackConfig.output.publicPath,\n  }),\n);\n\napp.listen(3000);\n```\n\n### Hono\n\n```js\nimport { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport webpack from \"webpack\";\nimport devMiddleware from \"webpack-dev-middleware\";\nimport webpackConfig from \"./webpack.config.js\";\n\nconst compiler = webpack(webpackConfig);\nconst app = new Hono();\n\napp.use(\n  devMiddleware.honoWrapper(compiler, {\n    publicPath: webpackConfig.output.publicPath,\n  }),\n);\n\nserve(app);\n```\n\n### Fastify\n\nFastify integration in the maintainer README requires `@fastify/express` and is described as a stopgap while full Fastify support is worked on.\n\n```js\nconst fastify = require(\"fastify\")();\nconst webpack = require(\"webpack\");\nconst devMiddleware = require(\"webpack-dev-middleware\");\nconst webpackConfig = require(\"./webpack.config.js\");\n\nconst compiler = webpack(webpackConfig);\n\nasync function start() {\n  await fastify.register(require(\"@fastify/express\"));\n  await fastify.use(\n    devMiddleware(compiler, {\n      publicPath: webpackConfig.output.publicPath,\n    }),\n  );\n  await fastify.listen({ port: 3000 });\n}\n\nstart().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n```\n\n## Pitfalls\n\n- If unrelated requests hang while webpack is compiling, do not mount the middleware broadly at the app root; use a dedicated route for webpack assets and make sure your webpack `publicPath` matches the URLs you expect to serve\n- Do not assume emitted files exist on disk unless you explicitly enable `writeToDisk`\n- Do not call `res.end()` or `res.send()` inside `modifyResponseData`; return `{ data, byteLength }` instead\n- `serverSideRender` is experimental and may change\n"
  },
  {
    "path": "content/webpack/docs/webpack-dev-server/javascript/DOC.md",
    "content": "---\nname: webpack-dev-server\ndescription: \"Run webpack in development with a local HTTP server, automatic rebuilds, HMR, static file serving, and browser-side error reporting\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.2.3\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,dev-server,hmr,proxy,development\"\n---\n\n# webpack-dev-server JavaScript Guide\n\n`webpack-dev-server` starts a local development server for a webpack build, serves emitted assets, watches files, and refreshes or hot-updates the browser while you work.\n\nFor `webpack-dev-server@5.2.3`, the published package declares:\n\n- Node.js `>=18.12.0`\n- `webpack` peer dependency `^5.0.0`\n- No authentication flow and no required package-specific environment variables\n\nThe package README recommends installing it locally in your project and using it through `webpack serve`.\n\n## Install\n\nInstall webpack, the CLI, and the dev server together:\n\n```bash\nnpm install --save-dev webpack webpack-cli webpack-dev-server\n```\n\nAdd a development script:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"webpack serve --config ./webpack.config.js --mode development\"\n  }\n}\n```\n\nRun it with:\n\n```bash\nnpm run dev\n```\n\nIf you do not set `host` or `port`, the maintainer README says the server listens on `localhost:8080`.\n\n## Minimal webpack config\n\n`webpack-dev-server` is configured through the `devServer` section of your webpack config.\n\n`webpack.config.js`\n\n```js\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  mode: \"development\",\n  entry: \"./src/index.js\",\n  output: {\n    filename: \"main.js\",\n    path: path.resolve(__dirname, \"dist\"),\n    publicPath: \"/assets/\",\n    clean: true,\n  },\n  devtool: \"eval-source-map\",\n  devServer: {\n    host: \"localhost\",\n    port: 3000,\n    hot: true,\n    open: true,\n    static: {\n      directory: path.resolve(__dirname, \"public\"),\n      publicPath: \"/\",\n    },\n    client: {\n      overlay: true,\n      logging: \"info\",\n    },\n  },\n};\n```\n\nImportant details:\n\n- `output.publicPath` controls where the compiled bundle is served in the browser\n- `devServer.static` serves extra files such as `index.html`, icons, or mock JSON from disk\n- You do not import a separate browser client in application code; the dev server manages its own client unless you disable it with `client: false`\n\nWith the config above, `public/index.html` can reference the bundle like this:\n\n```html\n<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>webpack-dev-server</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/assets/main.js\"></script>\n  </body>\n</html>\n```\n\n## Single-page app routing\n\nIf your application uses client-side routing, enable the history API fallback so deep links resolve to your app entry page instead of returning 404s.\n\n```js\nmodule.exports = {\n  devServer: {\n    historyApiFallback: true,\n  },\n};\n```\n\nUse this for routers that expect `/users/42` or `/settings/profile` to be handled by the browser app, not by static file lookup.\n\n## Proxy a separate backend\n\nUse `proxy` when your frontend runs on webpack-dev-server but your API runs on another local process.\n\n```js\nmodule.exports = {\n  devServer: {\n    proxy: [\n      {\n        context: [\"/api\", \"/auth\"],\n        target: \"http://localhost:4000\",\n        changeOrigin: true,\n      },\n    ],\n  },\n};\n```\n\nThis keeps frontend requests on the same origin during development while forwarding matching paths to the backend server.\n\n## Static files and extra watched files\n\nIf you do not configure `devServer.static`, `5.2.3` normalizes it to `process.cwd()/public` and serves that directory at `/`.\n\nYou can watch additional files outside the webpack module graph and trigger a reload when they change:\n\n```js\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  devServer: {\n    static: {\n      directory: path.resolve(__dirname, \"public\"),\n      watch: true,\n    },\n    watchFiles: [\"src/**/*.html\", \"templates/**/*.njk\"],\n  },\n};\n```\n\nUse `watchFiles` for templates, CMS-generated files, or other assets that webpack itself does not import.\n\n## HTTPS development server\n\nThe server type can be `http`, `https`, `spdy`, or `http2`. For local HTTPS, pass certificate files through `devServer.server.options`.\n\n`webpack.config.js`\n\n```js\nconst fs = require(\"node:fs\");\n\nmodule.exports = {\n  devServer: {\n    server: {\n      type: \"https\",\n      options: {\n        key: fs.readFileSync(\"./certs/localhost-key.pem\"),\n        cert: fs.readFileSync(\"./certs/localhost.pem\"),\n      },\n    },\n  },\n};\n```\n\nThis is the right place to configure local TLS when your app needs secure cookies, service workers, or browser APIs that require HTTPS.\n\n## Reverse proxy or container networking\n\nWhen the browser cannot infer the websocket endpoint correctly, set `client.webSocketURL` explicitly.\n\n```js\nmodule.exports = {\n  devServer: {\n    host: \"0.0.0.0\",\n    port: 3000,\n    client: {\n      webSocketURL: {\n        protocol: \"ws\",\n        hostname: \"localhost\",\n        port: 3000,\n        pathname: \"/ws\",\n      },\n    },\n    webSocketServer: \"ws\",\n  },\n};\n```\n\nThis is useful when you run through Docker, a local reverse proxy, or a forwarded development hostname and the HMR client would otherwise connect to the wrong origin.\n\n## Start the server from Node\n\nThe README recommends the CLI first, but the package also exports a `Server` class. Construct it with a dev-server options object and a webpack compiler, then call `start()`.\n\n`dev-server.js`\n\n```js\nconst webpack = require(\"webpack\");\nconst WebpackDevServer = require(\"webpack-dev-server\");\nconst webpackConfig = require(\"./webpack.config.js\");\n\nasync function main() {\n  const compiler = webpack(webpackConfig);\n  const server = new WebpackDevServer(\n    {\n      host: \"localhost\",\n      port: 3000,\n      hot: true,\n    },\n    compiler,\n  );\n\n  await server.start();\n\n  const close = async () => {\n    await server.stop();\n    process.exit(0);\n  };\n\n  process.on(\"SIGINT\", close);\n  process.on(\"SIGTERM\", close);\n}\n\nmain().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n```\n\nUse the API when you need to embed the dev server in a larger Node process instead of delegating to `webpack serve`.\n\n## TypeScript webpack config typing\n\nIf you write `webpack.config.ts`, type `devServer` explicitly so TypeScript accepts the `Configuration.devServer` property.\n\n```ts\nimport type { Configuration } from \"webpack\";\nimport type { Configuration as DevServerConfiguration } from \"webpack-dev-server\";\n\nconst devServer: DevServerConfiguration = {\n  port: 3000,\n  hot: true,\n};\n\nconst config: Configuration = {\n  mode: \"development\",\n  devServer,\n};\n\nexport default config;\n```\n\n## Common pitfalls\n\n- Install `webpack-cli` if you want to use `webpack serve`; `webpack-dev-server` alone is not the CLI entry point\n- Keep the package local to the project. The maintainer README recommends local installation over global installation\n- Do not add `HotModuleReplacementPlugin` manually just because you set `devServer.hot`; `webpack-dev-server@5.2.3` applies it automatically when HMR is enabled\n- Set `historyApiFallback: true` for browser-router SPAs or deep links will 404\n- Be explicit about `output.publicPath` and `devServer.static.publicPath` so your HTML, emitted bundles, and extra static assets line up\n- Prefer a specific `allowedHosts` list when exposing the dev server through another hostname; `all` is broad and should be used intentionally\n"
  },
  {
    "path": "content/webpack/docs/webpack-merge/javascript/DOC.md",
    "content": "---\nname: webpack-merge\ndescription: \"Utility for composing webpack configuration objects with deep merges, rule-aware overrides, and custom array merge strategies\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.0.1\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,webpack-merge,build,bundler,javascript\"\n---\n\n# webpack-merge for JavaScript\n\n`webpack-merge` helps you split webpack config into small files and combine them into one final config object. Use it for the common pattern of a shared base config plus development- or production-specific overrides.\n\nThere is no authentication, client setup, or required environment variable. Import the merge helper and use it inside your webpack config files.\n\n## Install\n\nInstall `webpack-merge` in the same project as webpack:\n\n```bash\nnpm install --save-dev webpack-merge\n```\n\nCommon import patterns:\n\n```js\nconst { merge, mergeWithRules } = require(\"webpack-merge\");\n\n// or\nimport { merge, mergeWithRules } from \"webpack-merge\";\n```\n\n## Split a base config from environment-specific configs\n\nKeep the shared config in one file and merge in the pieces that change by environment.\n\n`webpack.common.js`:\n\n```js\nconst path = require(\"node:path\");\n\nmodule.exports = {\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"[name].js\",\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/i,\n        use: [\"style-loader\", \"css-loader\"],\n      },\n    ],\n  },\n};\n```\n\n`webpack.dev.js`:\n\n```js\nconst { merge } = require(\"webpack-merge\");\nconst common = require(\"./webpack.common.js\");\n\nmodule.exports = merge(common, {\n  mode: \"development\",\n  devtool: \"inline-source-map\",\n});\n```\n\n`webpack.prod.js`:\n\n```js\nconst { merge } = require(\"webpack-merge\");\nconst common = require(\"./webpack.common.js\");\n\nmodule.exports = merge(common, {\n  mode: \"production\",\n  devtool: \"source-map\",\n  output: {\n    filename: \"[name].[contenthash].js\",\n  },\n});\n```\n\nRun the matching config with webpack-cli:\n\n```bash\nnpx webpack --config webpack.dev.js\nnpx webpack --config webpack.prod.js\n```\n\nBy default, `merge()` deep-merges objects and concatenates arrays. That default works well for many top-level webpack settings.\n\n## Replace parts of matching loader rules with `mergeWithRules`\n\n`module.rules` often needs more control than the default merge because loader arrays are normally appended. Use `mergeWithRules()` when you need to match a specific rule and replace only selected fields.\n\n```js\nconst { mergeWithRules } = require(\"webpack-merge\");\n\nconst mergeCssRules = mergeWithRules({\n  module: {\n    rules: {\n      test: \"match\",\n      use: {\n        loader: \"match\",\n        options: \"replace\",\n      },\n    },\n  },\n});\n\nmodule.exports = mergeCssRules(\n  {\n    module: {\n      rules: [\n        {\n          test: /\\.css$/i,\n          use: [\n            { loader: \"style-loader\" },\n            { loader: \"css-loader\", options: { modules: false } },\n          ],\n        },\n      ],\n    },\n  },\n  {\n    module: {\n      rules: [\n        {\n          test: /\\.css$/i,\n          use: [{ loader: \"css-loader\", options: { modules: true } }],\n        },\n      ],\n    },\n  },\n);\n```\n\nThis pattern keeps the existing CSS rule, matches the `css-loader` entry by `loader`, and replaces only its `options`.\n\n## Prepend or replace selected arrays with `mergeWithCustomize`\n\nWhen the default array concatenation is not what you want, use `mergeWithCustomize()` with the package helpers.\n\n```js\nconst {\n  mergeWithCustomize,\n  customizeArray,\n} = require(\"webpack-merge\");\n\nconst mergeEntries = mergeWithCustomize({\n  customizeArray: customizeArray({\n    \"entry.*\": \"prepend\",\n  }),\n});\n\nmodule.exports = mergeEntries(\n  {\n    entry: {\n      app: [\"./src/index.js\"],\n    },\n  },\n  {\n    entry: {\n      app: [\"./src/polyfills.js\"],\n    },\n  },\n);\n```\n\nUse this kind of customization when a later config should prepend, append, or replace a specific array instead of taking the default behavior everywhere.\n\n## Deduplicate plugin arrays\n\nIf both configs add the same plugin class, the default merge produces two plugin instances. Use the `unique()` helper when only one copy should remain.\n\n```js\nconst webpack = require(\"webpack\");\nconst {\n  mergeWithCustomize,\n  unique,\n} = require(\"webpack-merge\");\n\nconst mergePlugins = mergeWithCustomize({\n  customizeArray: unique(\n    \"plugins\",\n    [\"HotModuleReplacementPlugin\"],\n    (plugin) => plugin.constructor && plugin.constructor.name,\n  ),\n});\n\nmodule.exports = mergePlugins(\n  {\n    plugins: [new webpack.HotModuleReplacementPlugin()],\n  },\n  {\n    plugins: [new webpack.HotModuleReplacementPlugin()],\n  },\n);\n```\n\n## Practical notes\n\n- `webpack-merge` only builds config objects. It does not run webpack by itself.\n- No environment variables are required by the package. If your webpack config reads `process.env`, that is project-specific rather than a `webpack-merge` requirement.\n- Arrays concatenate by default. This is the main reason duplicated loaders or plugins appear after a merge.\n- Use `merge()` for broad config composition and `mergeWithRules()` for `module.rules` where matching and replacement matter.\n- Keep shared settings such as `entry`, `output.path`, and common loader definitions in one base config so later overrides stay small.\n"
  },
  {
    "path": "content/webpack/docs/workbox-webpack-plugin/javascript/DOC.md",
    "content": "---\nname: workbox-webpack-plugin\ndescription: \"Webpack plugin for generating or injecting a Workbox service worker and precache manifest\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"7.4.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"webpack,workbox,service-worker,pwa,build\"\n---\n\n# workbox-webpack-plugin\n\n`workbox-webpack-plugin` integrates Workbox into a webpack build. Use it to either:\n\n- generate a ready-to-use service worker with `GenerateSW`, or\n- compile your own service worker source and inject a precache manifest with `InjectManifest`.\n\nFor `workbox-webpack-plugin@7.4.0`, the published package declares:\n\n- Node.js `>= 20.0.0`\n- webpack peer dependency `^4.4.0 || ^5.91.0`\n\nThis package has no auth flow, no package-specific environment variables, and no runtime client to initialize. It runs inside your webpack build, and you register the emitted service worker from your web app separately.\n\n## Install\n\nInstall webpack and the plugin in the same project:\n\n```bash\nnpm install --save-dev webpack webpack-cli workbox-webpack-plugin\n```\n\nIf you are using `InjectManifest` and your custom service worker imports Workbox runtime modules, add those packages explicitly as well:\n\n```bash\nnpm install --save-dev \\\n  workbox-webpack-plugin \\\n  workbox-core \\\n  workbox-precaching \\\n  workbox-routing \\\n  workbox-strategies\n```\n\n## Choose the plugin mode\n\n### `GenerateSW`\n\nUse `GenerateSW` when you want the plugin to create the service worker file for you.\n\nThis is the simpler option when you only need:\n\n- precaching for webpack assets\n- SPA navigation fallback\n- runtime caching rules for images, API responses, or similar requests\n\n### `InjectManifest`\n\nUse `InjectManifest` when you need to write the service worker yourself.\n\nThis is the better fit when you need custom event handlers, custom routing logic, push handlers, sync handlers, or other service worker code that should live in your own `swSrc` file.\n\n## Generate a service worker with `GenerateSW`\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\nconst { GenerateSW } = require(\"workbox-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"app.[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new GenerateSW({\n      swDest: \"service-worker.js\",\n      cleanupOutdatedCaches: true,\n      clientsClaim: true,\n      skipWaiting: false,\n      navigateFallback: \"/index.html\",\n      navigateFallbackDenylist: [/^\\/api\\//],\n      runtimeCaching: [\n        {\n          urlPattern: ({ request }) => request.destination === \"image\",\n          handler: \"StaleWhileRevalidate\",\n          options: {\n            cacheName: \"images\",\n            expiration: {\n              maxEntries: 60,\n            },\n          },\n        },\n        {\n          urlPattern: ({ url }) => url.origin === \"https://api.example.com\",\n          handler: \"NetworkFirst\",\n          options: {\n            cacheName: \"api\",\n            networkTimeoutSeconds: 3,\n          },\n        },\n      ],\n    }),\n  ],\n};\n```\n\nBuild with webpack:\n\n```bash\nnpx webpack --config webpack.config.js\n```\n\nImportant details in that configuration:\n\n- `swDest` is the emitted service worker asset name. For `GenerateSW`, the default is `service-worker.js`.\n- `navigateFallback` should point at an HTML document that is also present in the precache manifest.\n- `skipWaiting: false` keeps the generated message listener so a waiting worker can be activated via `postMessage({ type: \"SKIP_WAITING\" })`.\n- `clientsClaim: true` lets the new worker start controlling already-open pages after activation.\n\n## Register the emitted service worker\n\nThe plugin writes the service worker file during the webpack build. Your application still needs to register that file in the browser:\n\n```javascript\nif (\"serviceWorker\" in navigator) {\n  window.addEventListener(\"load\", async () => {\n    try {\n      await navigator.serviceWorker.register(\"/service-worker.js\");\n    } catch (error) {\n      console.error(\"Service worker registration failed\", error);\n    }\n  });\n}\n```\n\nRegister the URL that matches where webpack publishes `swDest`.\n\nIf you keep `skipWaiting: false` and want to activate an update immediately, post the generated message type to the waiting worker:\n\n```javascript\nasync function activateWaitingWorker() {\n  const registration = await navigator.serviceWorker.getRegistration();\n\n  if (registration?.waiting) {\n    registration.waiting.postMessage({ type: \"SKIP_WAITING\" });\n  }\n}\n```\n\n## Use `InjectManifest` for a custom service worker\n\nWith `InjectManifest`, webpack compiles your `swSrc` file and replaces `self.__WB_MANIFEST` with the generated precache manifest.\n\n`webpack.config.js`:\n\n```javascript\nconst path = require(\"node:path\");\nconst { InjectManifest } = require(\"workbox-webpack-plugin\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./src/index.js\",\n  output: {\n    path: path.resolve(__dirname, \"dist\"),\n    filename: \"app.[contenthash].js\",\n    clean: true,\n  },\n  plugins: [\n    new InjectManifest({\n      swSrc: \"./src/sw.js\",\n      swDest: \"service-worker.js\",\n      maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,\n    }),\n  ],\n};\n```\n\n`src/sw.js`:\n\n```javascript\nimport { clientsClaim } from \"workbox-core\";\nimport { precacheAndRoute } from \"workbox-precaching\";\nimport { registerRoute } from \"workbox-routing\";\nimport { StaleWhileRevalidate } from \"workbox-strategies\";\n\nself.skipWaiting();\nclientsClaim();\n\nprecacheAndRoute(self.__WB_MANIFEST);\n\nregisterRoute(\n  ({ request }) => request.destination === \"image\",\n  new StaleWhileRevalidate({\n    cacheName: \"images\",\n  }),\n);\n```\n\nKey `InjectManifest` behavior:\n\n- `swSrc` is required.\n- `compileSrc` defaults to `true`, so the source service worker is compiled by webpack.\n- `swDest` is optional, but setting it explicitly keeps the emitted filename predictable.\n- If you set `compileSrc: false`, `webpackCompilationPlugins` cannot be used.\n\n## Common options that matter in real projects\n\n### Control which assets are precached\n\nUse `include`, `exclude`, `chunks`, and `excludeChunks` to control which webpack assets make it into the precache manifest.\n\n```javascript\nnew GenerateSW({\n  include: [/\\.html$/, /\\.js$/, /\\.css$/],\n  exclude: [/\\.map$/, /^server\\//],\n  excludeChunks: [\"admin\"],\n});\n```\n\nThe webpack-specific `exclude` default omits source maps and assets matching `manifest.*.js`.\n\n### Raise the precache size limit when needed\n\nBy default, files over `2097152` bytes are not precached.\n\n```javascript\nnew GenerateSW({\n  maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,\n});\n```\n\nOnly raise this when you intentionally want larger assets in precache storage.\n\n### Avoid extra cache-busting for already-hashed filenames\n\nIf your emitted assets already contain stable hashes in their filenames, set `dontCacheBustURLsMatching` so Workbox can treat those URLs as versioned:\n\n```javascript\nnew GenerateSW({\n  dontCacheBustURLsMatching: /\\.[0-9a-f]{8,}\\./,\n});\n```\n\n### Rewrite manifest URLs when deploy paths differ\n\nUse `modifyURLPrefix` when your build output path and public asset path do not match exactly:\n\n```javascript\nnew GenerateSW({\n  modifyURLPrefix: {\n    \"\": \"/static\",\n  },\n});\n```\n\n### Add extra URLs to the precache manifest\n\nUse `additionalManifestEntries` for URLs that are not emitted by webpack but should still be precached.\n\n```javascript\nnew GenerateSW({\n  additionalManifestEntries: [\n    \"/offline.html\",\n    { url: \"/app-shell\", revision: \"2026-03-13\" },\n  ],\n});\n```\n\n## SPA fallback and navigation preload\n\nFor a single-page app, use `navigateFallback` for navigation requests that are not already precached. Restrict it if parts of the site should never resolve to the app shell:\n\n```javascript\nnew GenerateSW({\n  navigateFallback: \"/index.html\",\n  navigateFallbackAllowlist: [/^\\/app/],\n  navigateFallbackDenylist: [/^\\/api\\//, /^\\/admin\\//],\n});\n```\n\nIf you enable `navigationPreload`, also add a runtime caching route that handles navigation requests.\n\n## Important pitfalls\n\n- Choose exactly one plugin instance for the service worker file you want to emit: `GenerateSW` or `InjectManifest`.\n- `InjectManifest` expects the `injectionPoint` placeholder to exist in `swSrc`; the default placeholder is `self.__WB_MANIFEST`.\n- Keep the placeholder in `swSrc` only where you want the manifest inserted.\n- `navigateFallback` only works for routes where returning the same HTML document is valid.\n- The package generates service worker assets during the build, but it does not register them for you in the browser.\n\n## Minimal decision guide\n\n- Use `GenerateSW` when you want webpack to emit a ready-made service worker from configuration.\n- Use `InjectManifest` when you need custom service worker source code and still want webpack assets precached automatically.\n"
  },
  {
    "path": "content/websocket-client/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"websocket-client package guide for Python synchronous WebSocket connections, callbacks, proxies, and reconnect handling\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.9.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"websocket,python,realtime,networking,client\"\n---\n\n# websocket-client Python Package Guide\n\n## Golden Rule\n\nInstall `websocket-client`, but import `websocket` in code.\n\nThis library is for synchronous WebSocket clients:\n\n- Use `create_connection()` or `websocket.WebSocket()` for short-lived request/response exchanges.\n- Use `websocket.WebSocketApp` for long-lived, callback-driven connections.\n\nIf the project is built around `asyncio`, do not treat `websocket-client` as an asyncio-native client. Upstream explicitly documents compatibility limitations with `asyncio`.\n\n## Install\n\n```bash\npip install websocket-client==1.9.0\n```\n\nOptional extras from upstream:\n\n```bash\npip install \"websocket-client[optional]\"\npip install rel\n```\n\n- `websocket-client[optional]` adds `python-socks` for proxy support and `wsaccel` for a small performance boost.\n- `rel` is useful if you want `WebSocketApp.run_forever(..., reconnect=...)` with automatic reconnect dispatching.\n- Upstream `1.9.0` removes Python `3.8` support. PyPI classifiers for this release cover Python `3.9` through `3.13`.\n\n## Choose The Right API\n\n### Short-lived connection\n\nUse `create_connection()` when you need to connect, send one or a few messages, read responses, then close.\n\n```python\nimport json\nfrom websocket import create_connection\n\nws = create_connection(\n    \"wss://example.com/ws\",\n    timeout=10,\n    header=[\n        \"Authorization: Bearer YOUR_TOKEN\",\n        \"X-Client: my-app\",\n    ],\n    subprotocols=[\"json\"],\n)\n\ntry:\n    ws.send(json.dumps({\"type\": \"ping\"}))\n    reply = ws.recv()\n    print(reply)\nfinally:\n    ws.close()\n```\n\n### Long-lived callback app\n\nUse `WebSocketApp` when the server pushes events and you need callbacks for open, reconnect, messages, errors, and close.\n\n```python\nimport json\nimport os\n\nimport websocket\n\ndef build_headers():\n    return {\n        \"Authorization\": f\"Bearer {os.environ['WS_TOKEN']}\",\n        \"X-Client\": \"my-app\",\n    }\n\ndef on_open(ws):\n    ws.send(json.dumps({\"type\": \"subscribe\", \"channel\": \"updates\"}))\n\ndef on_reconnect(ws):\n    ws.send(json.dumps({\"type\": \"subscribe\", \"channel\": \"updates\"}))\n\ndef on_message(ws, message):\n    print(\"message:\", message)\n\ndef on_error(ws, error):\n    raise error\n\ndef on_close(ws, status_code, message):\n    print(\"closed:\", status_code, message)\n\napp = websocket.WebSocketApp(\n    \"wss://example.com/ws\",\n    header=build_headers,\n    subprotocols=[\"json\"],\n    on_open=on_open,\n    on_reconnect=on_reconnect,\n    on_message=on_message,\n    on_error=on_error,\n    on_close=on_close,\n)\n\napp.run_forever(\n    ping_interval=30,\n    ping_timeout=10,\n)\n```\n\n`WebSocketApp.header` can be a callable in `1.9.0`, which is useful when auth headers depend on fresh state during reconnects.\n\n## Core Operations\n\n### Send and receive binary data\n\nFor higher-level usage, `WebSocket.recv()` gives you the next message as text or bytes. If you need explicit frame metadata, use `send_binary()` and `recv_data()`.\n\n```python\nimport websocket\n\nws = websocket.create_connection(\"wss://example.com/ws\")\n\ntry:\n    ws.send_binary(b\"\\x01\\x02\\x03\")\n    opcode, data = ws.recv_data()\n    print(opcode, data)\nfinally:\n    ws.close()\n```\n\n### Set a global default timeout\n\n`create_connection(..., timeout=...)` sets the socket timeout directly. `WebSocketApp.run_forever()` uses the global default timeout for connection setup, so set one with `websocket.setdefaulttimeout()` if needed.\n\n```python\nimport websocket\n\nwebsocket.setdefaulttimeout(5)\n\napp = websocket.WebSocketApp(\"wss://example.com/ws\")\napp.run_forever()\n```\n\n## Connection Setup And Auth\n\nCommon knobs on `create_connection()` and `WebSocketApp.run_forever()`:\n\n- `header` for custom handshake headers\n- `cookie` for cookie-based sessions\n- `subprotocols` for negotiated subprotocols\n- `origin` or `suppress_origin` to control the Origin header\n- `host` or `suppress_host` to control the Host header\n- `timeout` for socket timeouts\n- `sslopt` for TLS behavior\n- `http_proxy_host`, `http_proxy_port`, `http_proxy_auth`, `http_no_proxy`, `proxy_type` for proxy routing\n- `skip_utf8_validation=True` for performance-sensitive cases\n\n### Header-based auth\n\n```python\nfrom websocket import create_connection\n\nws = create_connection(\n    \"wss://example.com/ws\",\n    header=[\n        \"Authorization: Bearer YOUR_TOKEN\",\n        \"X-API-Key: YOUR_KEY\",\n    ],\n)\n```\n\n### Cookie-based auth\n\n```python\nimport websocket\n\napp = websocket.WebSocketApp(\n    \"wss://example.com/ws\",\n    cookie=\"sessionid=abc123; csrftoken=def456\",\n)\n```\n\n### Subprotocol negotiation\n\n```python\nfrom websocket import create_connection\n\nws = create_connection(\n    \"wss://example.com/ws\",\n    subprotocols=[\"graphql-transport-ws\"],\n)\n```\n\n### Host and Origin overrides\n\nUse `origin`, `suppress_origin`, `host`, or `suppress_host` only when the upstream server or proxy requires them.\n\n```python\nfrom websocket import create_connection\n\nws = create_connection(\n    \"wss://example.com/ws\",\n    origin=\"https://app.example.com\",\n    host=\"backend.example.internal\",\n)\n```\n\n## Reconnect, Ping, And Liveness\n\n`WebSocketApp.run_forever()` is the main long-running loop.\n\nImportant behavior from upstream:\n\n- `ping_interval=0` disables periodic pings.\n- `ping_timeout` must be greater than `0`.\n- If both are set, `ping_interval` must be greater than `ping_timeout`.\n- `reconnect` sets the delay between reconnect attempts.\n- Reconnect behavior is for unexpected disconnects, not graceful server closes.\n- For practical reconnect loops, upstream recommends using a dispatcher such as `rel`.\n\nExample:\n\n```python\nimport rel\nimport websocket\n\ndef on_open(ws):\n    ws.send(\"subscribe\")\n\ndef on_reconnect(ws):\n    ws.send(\"subscribe\")\n\ndef on_message(ws, message):\n    print(message)\n\napp = websocket.WebSocketApp(\n    \"wss://example.com/ws\",\n    on_open=on_open,\n    on_reconnect=on_reconnect,\n    on_message=on_message,\n)\n\napp.run_forever(\n    dispatcher=rel,\n    reconnect=5,\n    ping_interval=30,\n    ping_timeout=10,\n)\nrel.signal(2, rel.abort)\nrel.dispatch()\n```\n\nReconnections create a fresh TCP and WebSocket session. Re-send subscriptions, auth, or resume tokens in `on_open` and `on_reconnect`.\n\n## Proxies And TLS\n\n### Proxy support\n\n`websocket-client` supports:\n\n- `http`\n- `socks4`\n- `socks4a`\n- `socks5`\n- `socks5h`\n\nIf you need DNS resolution through the proxy, use `socks4a` or `socks5h`. Keep `proxy_type` lowercase.\n\n```python\nimport websocket\n\napp = websocket.WebSocketApp(\"wss://example.com/ws\")\napp.run_forever(\n    http_proxy_host=\"127.0.0.1\",\n    http_proxy_port=8080,\n    proxy_type=\"http\",\n    http_proxy_auth=(\"user\", \"pass\"),\n    http_no_proxy=[\"localhost\", \"127.0.0.1\"],\n)\n```\n\nIn `1.9.0`, upstream removed `localhost` and `127.0.0.1` from the default `NO_PROXY` list. If local endpoints should bypass the proxy, pass `http_no_proxy` explicitly or set matching environment variables.\n\n### TLS options\n\nFor local development against self-signed certs, upstream documents:\n\n```python\nimport ssl\nfrom websocket import create_connection\n\nws = create_connection(\n    \"wss://localhost:8443/ws\",\n    sslopt={\"cert_reqs\": ssl.CERT_NONE},\n)\n```\n\nTo disable hostname verification:\n\n```python\nimport websocket\n\nws = websocket.create_connection(\n    \"wss://localhost:8443/ws\",\n    sslopt={\"check_hostname\": False},\n)\n```\n\nTreat both as development-only settings.\n\n## Debugging And Error Handling\n\n### Enable protocol tracing\n\n```python\nimport websocket\n\nwebsocket.enableTrace(True)\n```\n\nThis is the fastest way to inspect the handshake, frames, close status, ping/pong traffic, and proxy behavior.\n\n### Surface callback failures\n\n```python\ndef on_error(ws, err):\n    raise err\n```\n\nIf you hit `WebSocketConnectionClosedException: Connection is already closed.`:\n\n- Stop sending on that socket.\n- Reconnect with `connect()` or `create_connection()`.\n- For `WebSocketApp`, re-enter `run_forever()` or use the reconnect path.\n\n## Common Pitfalls\n\n- `pip install websocket-client` but `import websocket`\n- This is a synchronous client library, not an asyncio-native one\n- The package does not support the `permessage-deflate` compression extension (RFC 7692)\n- `run_forever(reconnect=...)` is not enough by itself; for automatic reconnects you should also supply a dispatcher such as `rel`\n- Reconnects start a fresh connection; they do not resume stream state unless the server has its own resume protocol\n- `keep_running` on `WebSocketApp.__init__` is obsolete and ignored\n- When you instantiate `websocket.WebSocket()` directly and use threads, keep `enable_multithread=True`; that has been the default since `1.1.0`, but older examples on the internet may assume otherwise\n- Some `on_close` timing issues are easier to avoid by closing from a separate thread or timer instead of directly inside the message callback\n- `skip_utf8_validation=True` can improve throughput, but only use it if you trust the server payloads or you are handling binary/text boundaries carefully\n\n## Version-Sensitive Notes\n\n- `1.9.0` removes Python `3.8` support and adds Python `3.13`\n- `1.9.0` removes `localhost` and `127.0.0.1` from the default `NO_PROXY` handling, which can change local dev behavior behind proxies\n- `1.9.0` documents `suppress_host` for both connection setup and `run_forever()`; do not assume that option exists in `1.8.0`\n- `1.8.0` introduced `on_reconnect`; older callback examples may not use it even though it is the right hook for resubscription logic now\n\n## Official Sources\n\n- Docs root: `https://websocket-client.readthedocs.io/en/latest/`\n- Installation: `https://websocket-client.readthedocs.io/en/latest/installation.html`\n- Getting started: `https://websocket-client.readthedocs.io/en/latest/getting_started.html`\n- Examples: `https://websocket-client.readthedocs.io/en/latest/examples.html`\n- Threading: `https://websocket-client.readthedocs.io/en/latest/threading.html`\n- FAQ: `https://websocket-client.readthedocs.io/en/latest/faq.html`\n- `WebSocketApp` API: `https://websocket-client.readthedocs.io/en/latest/app.html`\n- Core API: `https://websocket-client.readthedocs.io/en/latest/core.html`\n- PyPI: `https://pypi.org/project/websocket-client/`\n- PyPI JSON metadata: `https://pypi.org/pypi/websocket-client/json`\n- Upstream changelog: `https://raw.githubusercontent.com/websocket-client/websocket-client/v1.9.0/ChangeLog`\n"
  },
  {
    "path": "content/websockets/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"websockets Python package guide for 16.0 asyncio and threading clients and servers\"\nmetadata:\n  languages: \"python\"\n  versions: \"16.0\"\n  revision: 2\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"websockets,websocket,asyncio,threading,realtime,networking,proxy\"\n---\n\n# websockets Python Package Guide\n\n## What It Is\n\n`websockets` is a focused WebSocket protocol library for Python. Use it when you need:\n\n- an asyncio WebSocket server or client\n- a synchronous threading-based client or server\n- Sans-I/O protocol building blocks for framework integrations\n\nDo not treat it as a full HTTP framework. If you need routing, request parsing, dependency injection, or mixed HTTP and WebSocket application structure, use a framework built on top of it.\n\n## Install\n\nPin the package version when you need the behavior described here:\n\n```bash\npython -m pip install \"websockets==16.0\"\n```\n\n`websockets` has no required runtime dependencies.\n\nIf you need SOCKS proxy support for client connections, install the optional proxy dependency documented upstream:\n\n```bash\npython -m pip install \"python-socks[asyncio]\"\n```\n\n## Choose The Right API Surface\n\nFor new async code, prefer explicit imports from the asyncio implementation:\n\n```python\nfrom websockets.asyncio.client import connect\nfrom websockets.asyncio.server import serve\n```\n\nFor synchronous scripts or worker threads:\n\n```python\nfrom websockets.sync.client import connect\nfrom websockets.sync.server import serve\n```\n\nWhy explicit imports matter:\n\n- `14.0` switched top-level aliases such as `websockets.connect` and `websockets.serve` to the new asyncio implementation.\n- Explicit imports make it clear whether code uses the new asyncio API, the sync API, or older legacy imports.\n\n## Asyncio Quick Start\n\nMinimal echo server:\n\n```python\nimport asyncio\n\nfrom websockets.asyncio.server import serve\n\nasync def echo(websocket):\n    async for message in websocket:\n        await websocket.send(message)\n\nasync def main() -> None:\n    async with serve(echo, \"127.0.0.1\", 8765):\n        await asyncio.get_running_loop().create_future()\n\nasyncio.run(main())\n```\n\nMinimal client:\n\n```python\nimport asyncio\n\nfrom websockets.asyncio.client import connect\n\nasync def main() -> None:\n    async with connect(\"ws://127.0.0.1:8765\") as websocket:\n        await websocket.send(\"hello\")\n        reply = await websocket.recv()\n        print(reply)\n\nasyncio.run(main())\n```\n\nCore behavior:\n\n- `connect()` is an async context manager and closes the connection automatically.\n- `serve()` is an async context manager and closes active connections on shutdown.\n- `async for message in websocket` is the standard receive loop.\n- `recv()` raises `ConnectionClosed` subclasses when the peer closes or the connection fails.\n\n## Reconnect Loops\n\nThe asyncio client supports automatic reconnect loops with `async for`:\n\n```python\nimport asyncio\nimport websockets\nfrom websockets.asyncio.client import connect\n\nasync def main() -> None:\n    async for websocket in connect(\n        \"wss://example.com/ws\",\n        open_timeout=10,\n        ping_interval=20,\n        ping_timeout=20,\n    ):\n        try:\n            await websocket.send(\"ping\")\n            print(await websocket.recv())\n        except websockets.exceptions.ConnectionClosed:\n            continue\n\nasyncio.run(main())\n```\n\nUse this pattern for durable clients that should reconnect after network failures or temporary server outages. Override `process_exception` only if the default retry classification is wrong for your application.\n\n## Sync API Quick Start\n\nUse the threading API when you cannot naturally run an event loop:\n\n```python\nfrom websockets.sync.client import connect\n\ndef main() -> None:\n    with connect(\"ws://127.0.0.1:8765\") as websocket:\n        websocket.send(\"hello\")\n        print(websocket.recv())\n\nif __name__ == \"__main__\":\n    main()\n```\n\nThe sync API is appropriate for CLI tools, background worker threads, and simple blocking integrations. It is not a drop-in replacement for the asyncio API; pick one model and stay consistent inside a component.\n\n## TLS, Headers, Subprotocols, And Proxies\n\nUse `wss://` for production traffic.\n\nClient-side configuration usually starts with `connect(...)`:\n\n```python\nimport asyncio\nimport ssl\n\nfrom websockets.asyncio.client import connect\n\nasync def main() -> None:\n    ssl_context = ssl.create_default_context()\n\n    async with connect(\n        \"wss://example.com/ws\",\n        ssl=ssl_context,\n        additional_headers={\"Authorization\": \"Bearer YOUR_TOKEN\"},\n        subprotocols=[\"chat.v1\"],\n        origin=\"https://app.example.com\",\n        open_timeout=10,\n        proxy=None,\n    ) as websocket:\n        await websocket.send(\"hello\")\n        print(await websocket.recv())\n\nasyncio.run(main())\n```\n\nKey options to know:\n\n- `additional_headers`: custom headers such as `Authorization`\n- `subprotocols`: negotiate application protocols\n- `origin`: send an `Origin` header when the server checks it\n- `open_timeout`: bound slow handshakes\n- `ping_interval` and `ping_timeout`: heartbeat tuning\n- `max_size` and `max_queue`: inbound memory and backpressure controls\n- `compression=None`: disable per-message deflate if you need simpler behavior\n- `proxy`: override proxy behavior; use `None` to disable automatic proxy usage\n\nVersion-sensitive proxy note:\n\n- Since `15.0`, client connections use HTTP or SOCKS proxies automatically when the operating system or environment config says to use one.\n- If upgrading older code, unexpected proxy use is a real behavior change. Set `proxy=None` when direct connections are required.\n\n## Server Setup And Handshake Hooks\n\nTypical server configuration:\n\n```python\nimport asyncio\n\nfrom websockets.asyncio.server import serve\n\nasync def handler(websocket) -> None:\n    async for message in websocket:\n        await websocket.send(message)\n\nasync def main() -> None:\n    async with serve(\n        handler,\n        \"0.0.0.0\",\n        8765,\n        origins=[\"https://app.example.com\"],\n        subprotocols=[\"chat.v1\"],\n        ping_interval=20,\n        ping_timeout=20,\n        max_size=2**20,\n        max_queue=16,\n        server_header=None,\n    ):\n        await asyncio.get_running_loop().create_future()\n\nasyncio.run(main())\n```\n\nUseful server-side hooks:\n\n- `origins`: defend against Cross-Site WebSocket Hijacking by allow-listing browser origins\n- `process_request`: reject or customize the HTTP opening handshake before the WebSocket upgrade\n- `process_response`: customize the HTTP response generated during the handshake\n- `select_subprotocol`: enforce or customize subprotocol negotiation\n- `server_header=None`: remove the default server banner\n\nIf you need simple path-based dispatch, inspect `websocket.request.path` inside the handler or use the routing helpers added in `15.0`.\n\n## Authentication\n\nFor non-browser clients, the usual pattern is an authorization header:\n\n```python\nimport asyncio\n\nfrom websockets.asyncio.client import connect\n\nasync def main() -> None:\n    async with connect(\n        \"wss://example.com/ws\",\n        additional_headers={\"Authorization\": \"Bearer YOUR_TOKEN\"},\n    ) as websocket:\n        await websocket.send(\"hello\")\n\nasyncio.run(main())\n```\n\nFor server-side HTTP Basic authentication, use the built-in helper:\n\n```python\nimport asyncio\n\nfrom websockets.asyncio.server import basic_auth, serve\n\nasync def handler(websocket) -> None:\n    await websocket.send(f\"hello {websocket.username}\")\n\nasync def main() -> None:\n    async with serve(\n        handler,\n        \"127.0.0.1\",\n        8765,\n        process_request=basic_auth(\n            realm=\"example\",\n            credentials=(\"hello\", \"iloveyou\"),\n        ),\n    ):\n        await asyncio.get_running_loop().create_future()\n\nasyncio.run(main())\n```\n\nBrowser authentication tradeoffs from the upstream auth guide:\n\n- first message after connect: simplest application-level token flow when you do not need HTTP 401 responses\n- query parameter: easy but leaks into logs and URLs\n- cookie: workable when the cookie domain arrangement fits your deployment\n- user info in the URI: only for machine-to-machine cases; browser support is poor\n\n## Keepalive, Timeouts, And Memory Controls\n\nThe keepalive guide documents a heartbeat ping every 20 seconds by default and expects a pong within 20 seconds.\n\nImportant controls:\n\n- `ping_interval=None`: disable keepalive entirely\n- `ping_timeout=None`: keep the trickle of ping traffic but disable heartbeat timeouts\n- `max_size`: maximum incoming message size\n- `max_queue`: maximum buffered incoming frames or messages before backpressure applies\n\nVersion-sensitive note:\n\n- Since `15.0`, the threading implementation also enables keepalive.\n- Code written for `14.x` may assume that only asyncio connections sent heartbeat pings.\n\nThe library also supports process-wide environment variables for advanced tuning, including:\n\n- `WEBSOCKETS_BACKOFF_*` for reconnect backoff behavior\n- `WEBSOCKETS_MAX_LOG_SIZE`\n- `WEBSOCKETS_MAX_BODY_SIZE`\n- `WEBSOCKETS_MAX_LINE_LENGTH`\n- `WEBSOCKETS_MAX_NUM_HEADERS`\n- `WEBSOCKETS_MAX_REDIRECTS`\n- `WEBSOCKETS_USER_AGENT`\n- `WEBSOCKETS_SERVER`\n\nUse these only when you need global policy. Prefer explicit per-connection arguments in application code.\n\n## Common Pitfalls\n\n- Use explicit imports from `websockets.asyncio.*` or `websockets.sync.*` when writing new code. Top-level aliases are easy to misread during migrations.\n- If older examples show a handler signature like `handler(websocket, path)`, update it. In current code, inspect `websocket.request.path` instead of relying on a separate `path` argument.\n- If older examples use `extra_headers=`, update them to `additional_headers=` on the new asyncio client.\n- Browser clients do not let you set arbitrary WebSocket handshake headers. Use cookies, query parameters, or an application message instead of assuming `Authorization` is always available from browser JavaScript.\n- Automatic proxy use in `15.x+` can change connection behavior in CI, corporate networks, or container environments. Set `proxy=None` when you need a direct socket.\n- `websockets` is only the protocol layer. Do not expect built-in HTTP routing, REST helpers, sessions, or middleware patterns.\n\n## Upgrade Notes For Older Code\n\nIf you are upgrading code from `13.x` or earlier, check these changes first:\n\n- `14.0`: top-level asyncio aliases now point at the new asyncio implementation\n- `14.0`: several deprecated aliases and legacy argument names were removed from the default import surface\n- `15.0`: routing helpers were added to the asyncio server\n- `15.0`: threading connections gained keepalive\n- `15.0`: client proxy auto-detection became the default\n- `16.0`: current package version requires Python `3.10+`\n\nFor migration-heavy work, read the official upgrade guide before copying older examples from blogs or issue threads.\n\n## Official Sources\n\n- Documentation root: https://websockets.readthedocs.io/en/stable/\n- Quick start: https://websockets.readthedocs.io/en/stable/howto/quickstart.html\n- Asyncio client reference: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html\n- Asyncio server reference: https://websockets.readthedocs.io/en/stable/reference/asyncio/server.html\n- Sync client reference: https://websockets.readthedocs.io/en/stable/reference/sync/client.html\n- Authentication guide: https://websockets.readthedocs.io/en/stable/topics/authentication.html\n- Keepalive guide: https://websockets.readthedocs.io/en/stable/topics/keepalive.html\n- Environment variables: https://websockets.readthedocs.io/en/stable/reference/variables.html\n- Upgrade guide: https://websockets.readthedocs.io/en/stable/howto/upgrade.html\n- Changelog: https://websockets.readthedocs.io/en/stable/project/changelog.html\n- PyPI package page: https://pypi.org/project/websockets/\n"
  },
  {
    "path": "content/werkzeug/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"Werkzeug package guide for Python - WSGI request/response, routing, middleware, and testing\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.1.6\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"werkzeug,wsgi,http,routing,middleware,testing,python\"\n---\n\n# Werkzeug Python Package Guide\n\n## When To Use It\n\nUse `werkzeug` when you need low-level WSGI building blocks without committing to a full framework. It provides:\n\n- request and response wrappers\n- routing via `Map` and `Rule`\n- a local development server\n- middleware such as `ProxyFix`\n- a test client for WSGI apps\n- security helpers such as password hashing and safe path joining\n\nIf you are working inside Flask, remember Flask already uses Werkzeug. Reach for direct Werkzeug APIs when you are writing raw WSGI apps, middleware, request/response utilities, routing logic, or tests around those layers.\n\n## Installation\n\n```bash\npip install Werkzeug==3.1.6\n```\n\nWith the faster file-watching reloader for local development:\n\n```bash\npip install \"Werkzeug[watchdog]==3.1.6\"\n```\n\nOptional upstream notes:\n\n- `watchdog` improves the dev reloader.\n- `colorama` enables colored request logs on Windows.\n- `greenlet>=1.0` is required if you run with `gevent` or `eventlet`.\n\n## Minimal WSGI App\n\n```python\nfrom werkzeug.wrappers import Request, Response\nfrom werkzeug.serving import run_simple\n\n@Request.application\ndef app(request: Request) -> Response:\n    name = request.args.get(\"name\", \"world\")\n    return Response(f\"Hello, {name}!\", mimetype=\"text/plain\")\n\nif __name__ == \"__main__\":\n    run_simple(\"127.0.0.1\", 5000, app, use_reloader=True, use_debugger=True)\n```\n\nNotes:\n\n- `@Request.application` lets you write a function that receives a `Request` and returns a `Response`.\n- `run_simple()` is for local development only.\n- Do not enable the debugger or dev server in production.\n\n## Core Request And Response Usage\n\n```python\nfrom werkzeug.wrappers import Request, Response\n\n@Request.application\ndef app(request: Request) -> Response:\n    if request.method == \"POST\":\n        username = request.form[\"username\"]\n        return Response(f\"created {username}\", status=201)\n\n    page = request.args.get(\"page\", default=1, type=int)\n    return Response(f\"page={page}\", mimetype=\"text/plain\")\n```\n\nUseful request attributes:\n\n- `request.args` for query parameters\n- `request.form` for URL-encoded or multipart form fields\n- `request.files` for uploaded files\n- `request.headers` for request headers\n- `request.cookies` for cookies\n- `request.get_data()` for raw body bytes when you intentionally need the full body in memory\n\nUseful response patterns:\n\n```python\nfrom werkzeug.wrappers import Response\n\nresponse = Response(\"ok\", status=200, mimetype=\"text/plain\")\nresponse.headers[\"X-App-Version\"] = \"1\"\nresponse.set_cookie(\"session\", \"abc123\", httponly=True, samesite=\"Lax\")\n```\n\n## Routing With `Map` And `Rule`\n\nWerkzeug routing is explicit and independent of any framework.\n\n```python\nfrom werkzeug.exceptions import HTTPException\nfrom werkzeug.routing import Map, Rule\nfrom werkzeug.wrappers import Request, Response\n\nurl_map = Map(\n    [\n        Rule(\"/\", endpoint=\"index\"),\n        Rule(\"/users/<int:user_id>\", endpoint=\"user-detail\"),\n    ]\n)\n\n@Request.application\ndef app(request: Request) -> Response:\n    adapter = url_map.bind_to_environ(request.environ)\n\n    try:\n        endpoint, values = adapter.match()\n    except HTTPException as exc:\n        return exc\n\n    if endpoint == \"index\":\n        return Response(\"home\")\n\n    if endpoint == \"user-detail\":\n        return Response(f\"user={values['user_id']}\")\n\n    return Response(\"not found\", status=404)\n```\n\nRouting behaviors to remember:\n\n- `strict_slashes=True` by default, so branch URLs redirect to the trailing-slash form.\n- `merge_slashes=True` by default, so repeated slashes may normalize and redirect.\n- `HEAD` is added automatically when a rule allows `GET`.\n- WebSocket routing exists, but Werkzeug does not provide a full WebSocket stack beyond matching.\n\n## Testing Without Running A Server\n\n```python\nfrom werkzeug.test import Client\nfrom werkzeug.wrappers import Response\n\nclient = Client(app, Response)\n\nresponse = client.get(\"/users/42\")\nassert response.status_code == 200\nassert response.get_data(as_text=True) == \"user=42\"\n```\n\nFor forms and uploads:\n\n```python\nimport io\n\nresponse = client.post(\n    \"/upload\",\n    data={\"title\": \"report\", \"file\": (io.BytesIO(b\"hello\"), \"report.txt\")},\n)\n```\n\nThe test client keeps cookies across requests by default, which is useful for login and session flows.\n\n## Configuration And Security-Relevant Setup\n\nWerkzeug does not impose an application config system. You configure behavior in your own app, request subclass, or middleware stack.\n\n### Reverse Proxy Setup\n\nIf the app is behind Nginx, a load balancer, or a platform proxy, use `ProxyFix` only when you know exactly how many trusted proxies are in front of the app.\n\n```python\nfrom werkzeug.middleware.proxy_fix import ProxyFix\n\napp = ProxyFix(app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1)\n```\n\nDo not blindly copy the counts. Incoming `X-Forwarded-*` headers can be faked, so the wrong `ProxyFix` configuration is a security bug.\n\n### Request Size Limits\n\nFor upload-heavy or public endpoints, set request limits explicitly.\n\n```python\nfrom werkzeug.wrappers import Request, Response\n\nclass AppRequest(Request):\n    max_content_length = 16 * 1024 * 1024  # 16 MiB\n    max_form_memory_size = 500_000\n    max_form_parts = 1_000\n\n@AppRequest.application\ndef app(request: AppRequest) -> Response:\n    return Response(\"ok\")\n```\n\nUse server-level limits too. Werkzeug's request limits are only one protection layer.\n\n### Password Hashing And Basic Auth Helpers\n\nWerkzeug is not an auth framework, but it includes useful primitives:\n\n```python\nfrom werkzeug.security import check_password_hash, generate_password_hash\n\nstored_hash = generate_password_hash(\"correct horse battery staple\")\nassert check_password_hash(stored_hash, \"correct horse battery staple\")\n```\n\nIn `3.1`, the default PBKDF2 work factor increased. Do not hard-code assumptions about hash parameters. Store the full hash string and let Werkzeug verify it.\n\nFor HTTP auth headers, prefer `request.authorization` and other request/header helpers instead of manually splitting the `Authorization` header string.\n\n## File Handling Helpers\n\nFor user-uploaded filenames and user-controlled download paths:\n\n```python\nfrom werkzeug.security import safe_join\nfrom werkzeug.utils import secure_filename\n\nfilename = secure_filename(user_filename)\npath = safe_join(\"/srv/uploads\", filename)\nif path is None:\n    raise ValueError(\"invalid path\")\n```\n\nPrefer `send_from_directory()` for serving user-selected files. Do not pass raw user paths to `send_file()`.\n\n## Production Deployment\n\nDo not use these in production:\n\n- `run_simple()`\n- `use_debugger=True`\n- `DebuggedApplication`\n\nUse a dedicated WSGI server or hosting platform instead. Werkzeug's built-in server, reloader, and debugger are development tools, not production infrastructure.\n\n## Common Pitfalls\n\n- Reading from `wsgi.input` directly can hang or interfere with parsing. Prefer the `Request` object or `parse_form_data()`, not both.\n- Accessing `request.form`, `request.files`, and raw input stream operations in the wrong order can consume the body in surprising ways.\n- `request.get_data()` loads the full body into memory. Set `max_content_length` first for untrusted requests.\n- `ProxyFix` with the wrong proxy counts will trust spoofed headers.\n- `send_file()` assumes the path is trusted. Use `send_from_directory()` for user-controlled names.\n- The interactive debugger can execute arbitrary code. Never expose it publicly.\n- The dev server may appear to work in staging-like environments, but upstream explicitly says it is not secure, stable, or efficient for production.\n\n## Version-Sensitive Notes For `3.1.x`\n\n- `3.1.6` was released on 2026-02-19 and tightens `safe_join()` handling for Windows special device names in multi-segment paths.\n- `3.1.5` and `3.1.4` also contain Windows path safety fixes around `safe_join()` and `send_from_directory()`.\n- `3.1.0` dropped Python `3.8`; `3.1.x` requires Python `3.9+`.\n- `3.1.0` changed `Request.max_form_memory_size` from unlimited to a default of `500 kB`.\n- `3.1.0` increased the default PBKDF2 work factor to `1,000,000`.\n- Older blog posts may still reference removed or deprecated APIs from `2.x` or early `3.0`. Check the upstream change log before copying imports or wrapper patterns.\n\n## Official Sources\n\n- Stable docs: https://werkzeug.palletsprojects.com/en/stable/\n- Installation: https://werkzeug.palletsprojects.com/en/stable/installation/\n- Quickstart: https://werkzeug.palletsprojects.com/en/stable/quickstart/\n- Routing: https://werkzeug.palletsprojects.com/en/stable/routing/\n- Testing: https://werkzeug.palletsprojects.com/en/stable/test/\n- ProxyFix middleware: https://werkzeug.palletsprojects.com/en/stable/middleware/proxy_fix/\n- Request data limits: https://werkzeug.palletsprojects.com/en/stable/request_data/\n- Utilities and security helpers: https://werkzeug.palletsprojects.com/en/stable/utils/\n- Serving and deployment: https://werkzeug.palletsprojects.com/en/stable/serving/ and https://werkzeug.palletsprojects.com/en/stable/deployment/\n- Change log: https://werkzeug.palletsprojects.com/en/stable/changes/\n- PyPI package: https://pypi.org/project/Werkzeug/\n"
  },
  {
    "path": "content/wheel/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"wheel package guide for Python wheel-file tooling and legacy build compatibility\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.46.3\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"wheel,python,packaging,build,pypi\"\n---\n\n# wheel Python Package Guide\n\n## What It Is\n\n`wheel` is the reference implementation of the Python wheel format (PEP 427) and the official command-line tool for manipulating `.whl` files.\n\nFor current Python packaging workflows, treat `wheel` primarily as a CLI utility:\n\n- Use `build` plus `setuptools` to produce wheels for modern projects.\n- Install `wheel` when you need CLI commands such as `convert`, `unpack`, `pack`, or `tags`.\n- Keep `wheel` in legacy build environments only when an older `setuptools`-based `bdist_wheel` flow still depends on it.\n\n## Install\n\nInstall the package when you need the `wheel` command-line tool:\n\n```bash\npython -m pip install wheel==0.46.3\n```\n\nThe upstream docs also note that many system package managers expose it as `python-wheel` or `python3-wheel`.\n\n## Setup\n\nThere is no auth, account setup, or remote service configuration. The main setup decision is whether your project actually needs `wheel` installed.\n\n### Modern project build setup\n\nFor normal builds, use `build` and a current setuptools backend:\n\n```toml\n[build-system]\nrequires = [\"setuptools>=70.1\"]\nbuild-backend = \"setuptools.build_meta\"\n```\n\n```bash\npython -m pip install build\npython -m build --wheel\n```\n\nThis produces `dist/<project>-<version>-<tags>.whl`.\n\n### Legacy setup for old `setuptools`\n\nIf you are forced to keep `setuptools` older than `70.1` and still rely on `bdist_wheel`, add `wheel` to the build environment explicitly:\n\n```toml\n[build-system]\nrequires = [\"setuptools<70.1\", \"wheel==0.46.3\"]\nbuild-backend = \"setuptools.build_meta\"\n```\n\nThat should be treated as compatibility-only. Upstream advises against installing `wheel` just to build wheels in modern projects.\n\n## Core Usage\n\n### Build a wheel for your project\n\nUse `build`, not the `wheel` CLI, for standard package builds:\n\n```bash\npython -m pip install build\npython -m build --wheel\n```\n\n### Convert a legacy egg or wininst artifact\n\n```bash\nwheel convert legacy_package-1.2.3-py3.11.egg\nwheel convert old_installer.exe\nwheel convert --dest-dir dist legacy_package-1.2.3-py3.11.egg\n```\n\nUse this only for migration from old packaging artifacts. `wheel convert` does not build from source.\n\n### Unpack a wheel safely\n\n```bash\nwheel unpack dist/example_pkg-1.0.0-py3-none-any.whl\nwheel unpack -d /tmp/unpacked dist/example_pkg-1.0.0-py3-none-any.whl\n```\n\n`wheel unpack` validates hashes and file sizes against `RECORD`, so it is safer than a plain `unzip` when you need to inspect or modify an existing wheel.\n\n### Repack an unpacked wheel\n\n```bash\nwheel pack example_pkg-1.0.0\nwheel pack --build-number 2 example_pkg-1.0.0\nwheel pack --dest-dir dist example_pkg-1.0.0\n```\n\nThis regenerates `RECORD` for the new archive.\n\n### Adjust compatibility tags on an existing wheel\n\n```bash\nwheel tags \\\n  --python-tag=py3 \\\n  --abi-tag=none \\\n  --platform-tag=any \\\n  dist/example_pkg-1.0.0-cp311-cp311-manylinux_2_28_x86_64.whl\n```\n\nUse `+tag` to append tags and `-tag` to remove tags. `wheel tags` writes a new wheel unless you also pass `--remove`.\n\n## Configuration\n\n### `setup.cfg` options\n\nFor legacy setuptools-based projects, `wheel` still documents a few common config points in `setup.cfg`.\n\nInclude license files in the generated wheel:\n\n```ini\n[metadata]\nlicense_files =\n    LICENSE\n    NOTICE\n    licenses/*.txt\n```\n\nMark a package as universal only for the old pure-Python Python 2/3 compatibility case:\n\n```ini\n[bdist_wheel]\nuniversal = 1\n```\n\nDo not cargo-cult `universal = 1` into Python 3-only or extension-bearing packages.\n\n## Common Pitfalls\n\n- Do not add `wheel` as a normal runtime dependency. It is packaging tooling, not an application library.\n- Do not keep `wheel` in `build-system.requires` by default for current setuptools projects. Build with `build` plus `setuptools>=70.1` instead.\n- Do not import `wheel.cli`, `wheel.metadata`, or `wheel.bdist_wheel` in new code. Upstream made `wheel.cli` private in `0.46.0`, made `wheel.metadata` private, and deprecated the old `wheel.bdist_wheel` path.\n- Do not use `wheel tags` to claim compatibility you have not actually tested. Retagging changes metadata; it does not rebuild binaries.\n- Do not use `wheel convert` for source distributions. It is for old `.egg` files, `.egg` directories, and `bdist_wininst` installers.\n- Prefer `wheel unpack` over `unzip` when auditing a wheel, because it verifies `RECORD` hashes and sizes.\n\n## Version-Sensitive Notes\n\n- `0.46.0` dropped Python 3.8 support.\n- `0.46.0` removed wheel’s own `bdist_wheel` implementation and turned `wheel.bdist_wheel` into a deprecated alias to the setuptools implementation.\n- `0.46.0` also made `wheel.cli` private and `wheel.metadata` private, so code that imported wheel internals is now on a weaker path.\n- `0.46.2` restored `bdist_wheel` command compatibility for `setuptools` older than `70.1` and fixed a `wheel unpack` directory-traversal style issue tracked as `CVE-2026-24049`.\n- `0.46.3` fixed an `ImportError` that could occur with older setuptools during `bdist_wheel`.\n\n## Quick Decision Guide\n\n- Need to build a wheel from source in a modern project: install `build`, not `wheel`.\n- Need to inspect, retag, convert, or repack existing wheel artifacts: install `wheel`.\n- Need `bdist_wheel` with an older setuptools stack: pin `wheel` for compatibility and plan a setuptools upgrade.\n\n## Official Sources\n\n- Documentation: `https://wheel.readthedocs.io/en/stable/`\n- Installation: `https://wheel.readthedocs.io/en/stable/installing.html`\n- User guide: `https://wheel.readthedocs.io/en/stable/user_guide.html`\n- Reference guide: `https://wheel.readthedocs.io/en/stable/reference/index.html`\n- Release notes: `https://wheel.readthedocs.io/en/stable/news.html`\n- PyPI project: `https://pypi.org/project/wheel/`\n"
  },
  {
    "path": "content/whitenoise/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"WhiteNoise static-file serving for Django and WSGI apps with practical setup, compression, caching, and deployment notes\"\nmetadata:\n  languages: \"python\"\n  versions: \"6.12.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"whitenoise,django,wsgi,staticfiles,compression,caching,cdn\"\n---\n\n# WhiteNoise Python Package Guide\n\n## What It Is\n\n`whitenoise` serves static files directly from Python web apps.\n\nThe main supported patterns are:\n\n- Django static file serving through `whitenoise.middleware.WhiteNoiseMiddleware`\n- WSGI wrapping with `from whitenoise import WhiteNoise`\n- Precompressed static assets (`gzip`, optional `brotli`)\n- Cache-friendly immutable asset URLs for CDN deployment\n\nUse it for application static assets. Do not use it for user-uploaded media files.\n\n## Version Covered\n\n- Package: `whitenoise`\n- Ecosystem: `pypi`\n- Version: `6.12.0`\n- Python requirement on PyPI: `>=3.10`\n- Django classifiers on PyPI: `4.2`, `5.0`, `5.1`, `5.2`, `6.0`\n- Registry: https://pypi.org/project/whitenoise/\n- Docs root used for this guide: https://whitenoise.readthedocs.io/en/stable/\n\n## Install\n\nPin the package version explicitly:\n\n```bash\npython -m pip install \"whitenoise==6.12.0\"\n```\n\nIf you want Brotli-compressed assets:\n\n```bash\npython -m pip install \"whitenoise[brotli]==6.12.0\"\n```\n\n## Django Setup\n\nWhiteNoise's primary integration path is Django.\n\nAdd it directly after `SecurityMiddleware`, configure `STATIC_ROOT`, and use the WhiteNoise storage backend:\n\n```python\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent\n\nINSTALLED_APPS = [\n    \"whitenoise.runserver_nostatic\",\n    \"django.contrib.staticfiles\",\n    # ...\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"whitenoise.middleware.WhiteNoiseMiddleware\",\n    # ...\n]\n\nSTATIC_URL = \"/static/\"\nSTATIC_ROOT = BASE_DIR / \"staticfiles\"\n\nSTORAGES = {\n    \"staticfiles\": {\n        \"BACKEND\": \"whitenoise.storage.CompressedManifestStaticFilesStorage\",\n    },\n}\n```\n\nThen build the static tree:\n\n```bash\npython manage.py collectstatic\n```\n\nUse `runserver --nostatic` in development when you want Django to route static requests through WhiteNoise instead of Django's built-in static serving:\n\n```bash\npython manage.py runserver --nostatic\n```\n\n### Storage Backend Choice\n\nUse this in most production Django apps:\n\n```python\n\"whitenoise.storage.CompressedManifestStaticFilesStorage\"\n```\n\nThis gives you:\n\n- hashed asset filenames for long-lived caching\n- gzip output\n- Brotli output when the `brotli` extra is installed\n\nUse this only if you want compression without manifest hashing:\n\n```python\n\"whitenoise.storage.CompressedStaticFilesStorage\"\n```\n\n### Common Django Settings\n\n```python\nWHITENOISE_AUTOREFRESH = DEBUG\nWHITENOISE_USE_FINDERS = DEBUG\nWHITENOISE_KEEP_ONLY_HASHED_FILES = True\nWHITENOISE_MANIFEST_STRICT = True\nWHITENOISE_ROOT = BASE_DIR / \"public\"\n```\n\nWhat matters:\n\n- `WHITENOISE_AUTOREFRESH`: rechecks files on each request; development only\n- `WHITENOISE_USE_FINDERS`: serves from Django finders instead of only `STATIC_ROOT`; useful in development\n- `WHITENOISE_KEEP_ONLY_HASHED_FILES`: keeps only hashed copies to shrink deployment artifacts\n- `WHITENOISE_MANIFEST_STRICT`: raises when referenced manifest entries are missing\n- `WHITENOISE_ROOT`: serves files at site root such as `robots.txt` or `favicon.ico`\n\n### CDN Pattern\n\nThe documented pattern is to prepend an optional static host:\n\n```python\nimport os\n\nSTATIC_HOST = os.environ.get(\"DJANGO_STATIC_HOST\", \"\")\nSTATIC_URL = STATIC_HOST + \"/static/\"\n```\n\nOperational notes:\n\n- WhiteNoise automatically sends cache headers for immutable versioned files\n- `WHITENOISE_ALLOW_ALL_ORIGINS` defaults to `True`, which is useful for fonts and other static assets behind a CDN\n- Browsers only request Brotli over HTTPS\n- Your CDN must preserve and cache on `Accept-Encoding` if you want precompressed assets to work correctly\n\n## WSGI And Flask Setup\n\nFor non-Django WSGI apps, wrap the WSGI application:\n\n```python\nfrom whitenoise import WhiteNoise\n\nfrom myapp import application\n\napplication = WhiteNoise(application, root=\"/absolute/path/to/static\")\n```\n\nAdd more static directories if needed:\n\n```python\napplication.add_files(\"/absolute/path/to/more-static\", prefix=\"assets/\")\n```\n\nImportant behavior:\n\n- WhiteNoise scans static directories at startup\n- matching requests are served directly\n- non-static requests are passed through to the wrapped WSGI app\n\nFor Flask:\n\n```python\nfrom flask import Flask\nfrom whitenoise import WhiteNoise\n\napp = Flask(__name__)\napp.wsgi_app = WhiteNoise(app.wsgi_app, root=\"static/\")\n```\n\nIf you need multiple static roots:\n\n```python\nfrom flask import Flask\nfrom whitenoise import WhiteNoise\n\napp = Flask(__name__)\napp.wsgi_app = WhiteNoise(app.wsgi_app)\n\nfor path in (\"static/one/\", \"static/two/\"):\n    app.wsgi_app.add_files(path)\n```\n\n## Compression And Customization\n\nOutside Django's storage backend, you can precompress files yourself:\n\n```bash\npython -m whitenoise.compress static/\n```\n\nThat generates `.gz` files and, when Brotli support is installed, `.br` files when compression reduces size.\n\nUseful constructor-level customization:\n\n```python\nimport re\nfrom whitenoise import WhiteNoise\n\ndef add_headers(headers, path, url):\n    if path.endswith(\".pdf\"):\n        headers[\"Content-Disposition\"] = \"attachment\"\n\ndef immutable_file_test(path, url):\n    return re.match(r\"^.+\\\\.[0-9a-f]{12}\\\\..+$\", url) is not None\n\napplication = WhiteNoise(\n    application,\n    root=\"/absolute/path/to/static\",\n    add_headers_function=add_headers,\n    immutable_file_test=immutable_file_test,\n)\n```\n\nUseful knobs for WSGI usage:\n\n- `prefix`: URL prefix for mounted static files\n- `index_file`: serve directory indexes such as `index.html`\n- `max_age`: cache lifetime for non-immutable files\n- `autorefresh`: development mode file reloading\n\n## Config And Auth Notes\n\nWhiteNoise does not have an authentication or credential model. Configuration is entirely local:\n\n- Django: settings and storage backend selection\n- WSGI/Flask: `WhiteNoise(...)` constructor options and `add_files(...)`\n- Deployment: CDN host, cache behavior, and optional Brotli support\n\nIf a static route needs access control, enforce that outside WhiteNoise. WhiteNoise itself is designed to serve public static files.\n\n## Common Pitfalls\n\n- Put `WhiteNoiseMiddleware` immediately after Django `SecurityMiddleware`. Middleware ordering is part of the documented setup.\n- Do not skip `collectstatic` in production Django deploys. The manifest storage backend depends on collected assets.\n- Do not hardcode `/static/...` paths in templates. Use Django static helpers so hashed filenames resolve correctly.\n- Do not use WhiteNoise for user-uploaded media. The docs call out media files as a separate concern.\n- Do not leave `WHITENOISE_AUTOREFRESH=True` in production.\n- Do not expect WhiteNoise to serve files created after process startup unless you are deliberately using autorefresh development behavior.\n- If Brotli appears not to work behind a CDN, check HTTPS delivery and `Accept-Encoding` caching behavior first.\n\n## Version-Sensitive Notes For 6.12.0\n\n- `6.12.0` drops Python `3.9` support and adds support for Python `3.14`.\n- `6.12.0` adds support for Django `6.0`.\n- `6.12.0` fixes a security issue in `WHITENOISE_AUTOREFRESH` mode that affected path traversal when a symlink appeared inside a served directory tree. Production deployments are not affected because autorefresh is off by default.\n- The stable docs landing page still includes an older compatibility summary (`Python 3.8 to 3.14`), so for `6.12.0` version support you should trust the changelog and current PyPI metadata instead of that summary line.\n\n## Official Sources\n\n- Docs root: https://whitenoise.readthedocs.io/en/stable/\n- Django guide: https://whitenoise.readthedocs.io/en/stable/django.html\n- WSGI guide: https://whitenoise.readthedocs.io/en/stable/base.html\n- Flask guide: https://whitenoise.readthedocs.io/en/stable/flask.html\n- Changelog: https://whitenoise.readthedocs.io/en/stable/changelog.html\n- Registry: https://pypi.org/project/whitenoise/\n"
  },
  {
    "path": "content/wrapt/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"wrapt package guide for Python decorators, wrappers, monkey patching, and object proxies\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.1.2\"\n  revision: 1\n  updated-on: \"2026-03-11\"\n  source: maintainer\n  tags: \"wrapt,python,decorators,wrappers,proxies,monkey-patching\"\n---\n\n# wrapt Python Package Guide\n\n## What It Is\n\n`wrapt` is a utility library for writing decorators, monkey patches, and object proxies without breaking descriptor binding, signatures, or introspection.\n\nUse it when plain Python decorators are too fragile for methods, class methods, instance-aware wrappers, or transparent proxy objects.\n\n## Version Note\n\n- Package version covered here: `2.1.2`\n- PyPI published `2.1.2` on 2026-03-06.\n- The docs URL points at `https://wrapt.readthedocs.io/en/latest/`, but the `latest` alias is currently stale. For current release notes and API details, rely on the official changelog and docs pages under the upstream docs site plus PyPI metadata.\n\n## Install\n\n```bash\npip install wrapt==2.1.2\n```\n\n```bash\nuv add wrapt==2.1.2\n```\n\n```bash\npoetry add wrapt==2.1.2\n```\n\n## Import Surface\n\nCommon imports:\n\n```python\nimport wrapt\nfrom wrapt import ObjectProxy, BaseObjectProxy, LazyObjectProxy\nfrom wrapt import wrap_function_wrapper, patch_function_wrapper\n```\n\nKey APIs:\n\n- `@wrapt.decorator`: safest starting point for decorators that must work on functions, instance methods, class methods, and classes.\n- `wrap_function_wrapper()` / `patch_function_wrapper()`: patch an existing import target without replacing it by hand.\n- `ObjectProxy`, `BaseObjectProxy`, `LazyObjectProxy`: transparent wrappers around another object.\n\n## Core Decorator Pattern\n\nUse `@wrapt.decorator` and keep the wrapper signature exact:\n\n```python\nimport wrapt\n\n@wrapt.decorator\ndef log_calls(wrapped, instance, args, kwargs):\n    print(f\"calling {wrapped.__name__} with {args=} {kwargs=}\")\n    return wrapped(*args, **kwargs)\n\n@log_calls\ndef add(a: int, b: int) -> int:\n    return a + b\n```\n\nBehavior of wrapper arguments:\n\n- `wrapped`: the original callable or class being wrapped\n- `instance`: bound instance for instance methods, class for class methods, otherwise `None`\n- `args` / `kwargs`: arguments passed by the caller\n\nDo not pass `instance` back into `wrapped()`. Call `wrapped(*args, **kwargs)`.\n\n## Decorators With Arguments\n\nUse a closure around the wrapt decorator:\n\n```python\nimport time\nimport wrapt\n\ndef timed(label: str):\n    @wrapt.decorator\n    def wrapper(wrapped, instance, args, kwargs):\n        start = time.perf_counter()\n        try:\n            return wrapped(*args, **kwargs)\n        finally:\n            elapsed = time.perf_counter() - start\n            print(f\"{label}: {elapsed:.4f}s\")\n\n    return wrapper\n\n@timed(\"query\")\ndef run_query(sql: str) -> str:\n    return sql\n```\n\n## Wrapping Existing Functions\n\nFor monkey patching imported code, prefer the helper APIs instead of assigning raw wrapper functions yourself.\n\n```python\nimport wrapt\nimport requests.sessions\n\ndef record_request(wrapped, instance, args, kwargs):\n    response = wrapped(*args, **kwargs)\n    print(response.status_code)\n    return response\n\nwrapt.wrap_function_wrapper(\n    requests.sessions.Session,\n    \"request\",\n    record_request,\n)\n```\n\nString-based patching is useful when you need to name the import target dynamically:\n\n```python\nimport wrapt\n\ndef record_open(wrapped, instance, args, kwargs):\n    print(\"opening\", args[0])\n    return wrapped(*args, **kwargs)\n\nwrapt.patch_function_wrapper(\"pathlib\", \"Path.open\", record_open)\n```\n\nUse these helpers after the target module is imported. If you need lazy import-time patching, `wrapt` also provides post-import hook support.\n\n## Post-Import Hooks\n\nUse post-import hooks when you must patch a dependency only after it is imported somewhere else:\n\n```python\nfrom wrapt import register_post_import_hook, wrap_function_wrapper\n\ndef apply_patch(module):\n    wrap_function_wrapper(module, \"dangerous_call\", my_wrapper)\n\nregister_post_import_hook(apply_patch, \"some_dependency\")\n```\n\nThis avoids importing and patching modules too early during interpreter startup.\n\n## Object Proxies\n\nUse proxies when you need to wrap an object while preserving most normal behavior:\n\n```python\nfrom wrapt import BaseObjectProxy\n\nclass TracedList(BaseObjectProxy):\n    def append(self, value):\n        print(\"append\", value)\n        return self.__wrapped__.append(value)\n\nitems = TracedList([])\nitems.append(1)\n```\n\nUse `LazyObjectProxy` when constructing the wrapped object is expensive and can be deferred:\n\n```python\nfrom wrapt import LazyObjectProxy\n\nsettings = LazyObjectProxy(lambda: load_settings())\n```\n\n## Config And Environment\n\n`wrapt` does not have service auth, API keys, or network configuration.\n\nRelevant runtime/build configuration:\n\n- `WRAPT_DISABLE_EXTENSIONS=1`: disable use of the C extension at runtime for debugging or compatibility checks.\n- `WRAPT_INSTALL_EXTENSIONS=false`: skip building C extensions at install time.\n\nExample:\n\n```bash\nWRAPT_DISABLE_EXTENSIONS=1 pytest\n```\n\nMost projects should use the default compiled extension when wheels are available.\n\n## Typing\n\n`wrapt` 2.x added improved type annotations and `ParamSpec`-based decorator typing. Keep decorator factories typed explicitly when you want good inference:\n\n```python\nfrom collections.abc import Callable\nfrom typing import ParamSpec, TypeVar\nimport wrapt\n\nP = ParamSpec(\"P\")\nR = TypeVar(\"R\")\n\ndef traced() -> Callable[[Callable[P, R]], Callable[P, R]]:\n    @wrapt.decorator\n    def wrapper(wrapped, instance, args: P.args, kwargs: P.kwargs) -> R:\n        return wrapped(*args, **kwargs)\n\n    return wrapper\n```\n\nIf a type checker still loses the original callable signature through a complex decorator stack, simplify the factory return type or add a targeted cast at the outer boundary.\n\n## Common Pitfalls\n\n- Use `@wrapt.decorator`, not a plain nested decorator, when binding semantics matter.\n- Keep the wrapper signature exactly `(wrapped, instance, args, kwargs)`.\n- Call `wrapped(*args, **kwargs)`, not `wrapped(instance, *args, **kwargs)`.\n- For new proxy types, prefer `BaseObjectProxy` over `ObjectProxy`. `ObjectProxy` includes `__iter__()` unconditionally for backward compatibility, which can make non-iterable proxies look iterable.\n- `AutoObjectProxy` creates a dedicated derived type per instance; use it only when you need automatic special-method coverage and accept the extra memory cost.\n- `LazyObjectProxy` still executes the factory once on first access; keep the factory side effects predictable.\n- When combining with `@classmethod`, put the `wrapt` decorator outside `@classmethod`. The known ordering issue remains relevant because the attempted Python-level fix was later reverted.\n\n## Version-Sensitive Notes For 2.x\n\n- `2.0.0` changed typing support and added `BaseObjectProxy` so new proxy code has a cleaner base class.\n- `2.0.0` also removed the runtime dependency on `setuptools`.\n- `2.1.0` added `py.typed`, widened Python support through 3.13, and improved decorator typing for newer type checkers.\n- `2.1.2` is a packaging/build maintenance release; if examples online still talk about `1.x`, verify proxy-base-class and typing guidance before copying them.\n\n## Practical Rules\n\n1. Start with `@wrapt.decorator` unless you specifically need a proxy class.\n2. Use `wrap_function_wrapper()` or `patch_function_wrapper()` for monkey patching instead of manual reassignment.\n3. Use `BaseObjectProxy` for new custom proxies.\n4. Treat the `en/latest/` docs alias as potentially stale and cross-check with PyPI and the changelog when version details matter.\n\n## Official Sources\n\n- Docs root: https://wrapt.readthedocs.io/en/latest/\n- Current official docs pages: https://wrapt.readthedocs.io/en/master/\n- Changelog: https://wrapt.readthedocs.io/en/master/changes.html\n- PyPI: https://pypi.org/project/wrapt/\n- Repository: https://github.com/GrahamDumpleton/wrapt\n"
  },
  {
    "path": "content/xarray/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"xarray package guide for labeled N-dimensional arrays, datasets, netCDF/Zarr I/O, and chunked scientific workflows in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"2026.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"xarray,python,numpy,pandas,dask,zarr,netcdf,scientific-computing\"\n---\n\n# xarray Python Package Guide\n\n## Golden Rule\n\nUse `xarray` when your arrays have named dimensions, coordinates, or metadata that should survive slicing, alignment, grouping, and serialization. For production code, pass the storage backend and chunking strategy explicitly instead of relying on backend auto-detection.\n\n## Install\n\nPin the package version your project expects:\n\n```bash\npython -m pip install \"xarray==2026.2.0\"\n```\n\nUseful extras from the official install guide:\n\n```bash\npython -m pip install \"xarray[io]==2026.2.0\"\npython -m pip install \"xarray[parallel]==2026.2.0\"\npython -m pip install \"xarray[viz]==2026.2.0\"\npython -m pip install \"xarray[accel]==2026.2.0\"\npython -m pip install \"xarray[complete]==2026.2.0\"\n```\n\nNotes:\n\n- `xarray` itself is lightweight; most real workflows also need optional packages for file formats, parallelism, plotting, or performance.\n- Scientific environments are often easier to provision with conda or mamba when native dependencies like NetCDF or Zarr backends are involved.\n- `2026.2.0` requires newer dependency floors than older blog posts assume, including Python 3.11+, NumPy 1.26+, and pandas 2.2+.\n\n## Initialize And Core Objects\n\nThe two main types are:\n\n- `xr.DataArray`: one labeled array with dimensions, coordinates, and attrs\n- `xr.Dataset`: a dict-like collection of named `DataArray` objects sharing coordinates\n\n### DataArray\n\n```python\nimport numpy as np\nimport pandas as pd\nimport xarray as xr\n\ntimes = pd.date_range(\"2026-01-01\", periods=3, freq=\"D\")\n\ntemperature = xr.DataArray(\n    np.array([15.2, 16.8, 14.9]),\n    dims=[\"time\"],\n    coords={\"time\": times},\n    name=\"temperature_c\",\n    attrs={\"units\": \"degC\"},\n)\n\nprint(temperature.sel(time=\"2026-01-02\").item())\nprint(temperature.mean(dim=\"time\").item())\n```\n\n### Dataset\n\n```python\nimport numpy as np\nimport pandas as pd\nimport xarray as xr\n\ntimes = pd.date_range(\"2026-01-01\", periods=3, freq=\"D\")\n\nds = xr.Dataset(\n    data_vars={\n        \"temperature_c\": (\"time\", [15.2, 16.8, 14.9]),\n        \"humidity_pct\": (\"time\", [70, 65, 80]),\n    },\n    coords={\"time\": times},\n    attrs={\"station\": \"sfo\"},\n)\n\nprint(ds[\"temperature_c\"])\nprint(ds.mean(dim=\"time\"))\n```\n\n## Core Usage\n\n### Indexing And Selection\n\nPrefer label-based indexing when coordinates are meaningful:\n\n```python\nsubset = ds.sel(time=slice(\"2026-01-01\", \"2026-01-02\"))\nfirst_row = ds.isel(time=0)\n```\n\nUse `sel()` for coordinates and `isel()` for positional indexing. xarray aligns operations by coordinate labels, not just by shape.\n\n### Grouping And Resampling\n\n```python\nmonthly = ds.resample(time=\"MS\").mean()\n```\n\nIf your dimension names are semantic, operations stay readable because every reduction and transformation takes `dim=` names instead of positional axes.\n\n### Converting To Pandas\n\n```python\nframe = ds.to_dataframe().reset_index()\n```\n\nUse pandas only when you need row-oriented operations. Keep data in xarray for labeled N-dimensional math, broadcasting, and serialization.\n\n## I/O And Storage Backends\n\n### Open a single dataset\n\n```python\nimport xarray as xr\n\nds = xr.open_dataset(\n    \"data/example.nc\",\n    engine=\"h5netcdf\",\n    chunks=\"auto\",\n    decode_times=True,\n)\n```\n\nImportant parameters for `xr.open_dataset()`:\n\n- `engine=`: choose the backend explicitly for predictable behavior\n- `chunks=`: use `\"auto\"` or a chunk mapping to get dask-backed lazy arrays\n- `cache=`: defaults differ depending on whether dask chunking is enabled\n- `create_default_indexes=`: by default, dimension coordinates are loaded into pandas indexes eagerly\n\n### Open many NetCDF files\n\n```python\nds = xr.open_mfdataset(\n    \"data/daily/*.nc\",\n    combine=\"by_coords\",\n    engine=\"h5netcdf\",\n    chunks=\"auto\",\n)\n```\n\nUse `open_mfdataset()` for collections of files that should combine by coordinates or by nested structure. This is the normal entry point for dask-backed multi-file workflows.\n\n### Open Zarr\n\n```python\nds = xr.open_zarr(\n    \"s3://bucket/path/to/store\",\n    chunks=\"auto\",\n    consolidated=True,\n    zarr_format=3,\n)\n```\n\nUse `open_zarr()` when data already lives in chunked object storage or when cloud-native lazy access matters more than single-file portability.\n\n### Write datasets\n\n```python\nds.to_netcdf(\"output.nc\", engine=\"h5netcdf\")\nds.to_zarr(\"output.zarr\", mode=\"w\", consolidated=True, zarr_format=3)\n```\n\n## Configuration And Environment\n\nxarray itself does not require authentication. Credentials only matter when the storage backend does, for example:\n\n- S3 paths via `fsspec` and `s3fs`\n- GCS paths via `gcsfs`\n- Azure paths via `adlfs`\n\nKeep cloud credentials in the backend’s normal environment variables or SDK config, then pass backend-specific options through `storage_options=` when needed.\n\nExample:\n\n```python\nds = xr.open_zarr(\n    \"s3://my-bucket/forecast.zarr\",\n    storage_options={\"anon\": False},\n    chunks=\"auto\",\n)\n```\n\nProcess-wide options:\n\n```python\nimport xarray as xr\n\nwith xr.set_options(\n    keep_attrs=True,\n    arithmetic_join=\"exact\",\n    netcdf_engine_order=(\"h5netcdf\", \"netcdf4\", \"scipy\"),\n):\n    result = ds1 + ds2\n```\n\nUseful options:\n\n- `keep_attrs=True` preserves metadata through many operations\n- `arithmetic_join=\"exact\"` fails fast if coordinates do not align exactly\n- `netcdf_engine_order=...` makes backend selection deterministic\n\n## Common Pitfalls\n\n- Binary operations align by coordinate labels. Two arrays with the same shape can still produce unexpected `NaN` values or expanded coordinates if labels differ.\n- `open_dataset()` may eagerly create pandas indexes for dimension coordinates even when array data stays lazy. Large coordinate indexes can still consume memory.\n- The default backend for NetCDF is not a safe thing to guess. Official xarray docs currently contain version-era guidance that can differ between API pages and release notes, so pass `engine=` explicitly.\n- Dask chunking is not automatic unless you ask for it. Without `chunks=...`, many reads materialize NumPy arrays eagerly.\n- `open_mfdataset()` assumes the files can be combined coherently. Mismatched coordinates, attrs, or chunking often need explicit `combine=`, `compat=`, or preprocessing.\n- Zarr v2 and v3 have different behavior around fill values and metadata. Be explicit about `zarr_format=` when writing new stores.\n- `attrs` are metadata, not a schema contract. They are easy to drop unless you deliberately preserve them with `xr.set_options(keep_attrs=True)` or operation-specific handling.\n\n## Version-Sensitive Notes For 2026.2.0\n\n- PyPI and the stable docs both identify the current package release as `2026.2.0` on March 12, 2026.\n- `2026.2.0` requires Python 3.11 or later.\n- The `2026.2.0` release notes document newer minimum supported dependency versions than older examples typically assume, including NumPy 1.26+, pandas 2.2+, packaging 24.1+, zarr 2.18+, and cftime 1.6.2+.\n- The Zarr API has moved toward `zarr_format=`; older snippets that still use `zarr_version=` should be updated.\n- The release notes also call out changed default handling for `use_zarr_fill_value_as_mask`: for Zarr v2 the default remains `True`, while for Zarr v3 it defaults to `False`.\n- Backend-selection guidance is version-sensitive right now. If a workflow depends on `netcdf4`, `h5netcdf`, or `scipy` semantics, set `engine=` or `xr.set_options(netcdf_engine_order=...)` explicitly instead of trusting the default.\n\n## Official Sources\n\n- Docs root: https://docs.xarray.dev/en/stable/\n- API reference: https://docs.xarray.dev/en/stable/api.html\n- Installation guide: https://docs.xarray.dev/en/stable/getting-started-guide/installing.html\n- Quick overview: https://docs.xarray.dev/en/stable/getting-started-guide/quick-overview.html\n- Data structures: https://docs.xarray.dev/en/stable/user-guide/data-structures.html\n- Indexing: https://docs.xarray.dev/en/stable/user-guide/indexing.html\n- I/O guide: https://docs.xarray.dev/en/stable/user-guide/io.html\n- `open_dataset()`: https://docs.xarray.dev/en/stable/generated/xarray.open_dataset.html\n- `open_zarr()`: https://docs.xarray.dev/en/stable/generated/xarray.open_zarr.html\n- `set_options()`: https://docs.xarray.dev/en/stable/generated/xarray.set_options.html\n- Release notes: https://docs.xarray.dev/en/stable/whats-new.html\n- PyPI: https://pypi.org/project/xarray/\n"
  },
  {
    "path": "content/xgboost/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"xgboost package guide for python - gradient boosting with native and scikit-learn interfaces\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"xgboost,machine-learning,gradient-boosting,scikit-learn,gpu\"\n---\n\n# xgboost Python Package Guide\n\n## Golden Rule\n\nUse the official `xgboost` Python package and match examples to the installed package version. For this entry, that version is `3.2.0`.\n\n## What XGBoost Exposes In Python\n\nThe Python package has three main interfaces:\n\n- Native interface: `xgb.DMatrix`, `xgb.train`, `xgb.Booster`\n- Scikit-learn interface: `XGBClassifier`, `XGBRegressor`, `XGBRanker`\n- Dask interface: distributed training when you already have a Dask cluster\n\nFor most application code, start with the scikit-learn estimators. Use the native interface when you need lower-level control, cached prediction behavior, or direct `Booster` APIs.\n\n## Installation\n\n```bash\npip install xgboost==3.2.0\n```\n\nIf you just need the CPU-only build on supported `x86_64` Linux or Windows systems:\n\n```bash\npip install xgboost-cpu==3.2.0\n```\n\nAdditional optional extras published on PyPI include `scikit-learn`, `pandas`, `plotting`, `dask`, and `pyspark`.\n\n## Platform And Environment Notes\n\n- Python requirement: `>=3.10`\n- Linux wheels now target `manylinux_2_28`; older distros need a newer base image or a source build\n- Windows requires the Visual C++ Redistributable unless the needed runtime is already present via Visual Studio\n- `pip install xgboost` ships GPU support on supported Linux and Windows wheels\n- macOS wheels are CPU-only\n\n## Verify The Install\n\n```python\nimport xgboost as xgb\n\nprint(xgb.__version__)\n```\n\n## Choosing An Interface\n\n### Use The scikit-learn API By Default\n\nPrefer `XGBClassifier` or `XGBRegressor` when:\n\n- you already use sklearn pipelines, metrics, or model selection\n- you want `fit`, `predict`, `predict_proba`, `score`\n- you want early stopping with `eval_set`\n\n### Use The Native API When You Need Booster-Level Control\n\nPrefer `xgb.train` with `DMatrix` when:\n\n- you want direct control over watchlists and boosting rounds\n- you need `Booster` methods like `predict`, `save_model`, `dump_model`\n- you want cached prediction or lower-level integration behavior\n\n## Quick Start: scikit-learn Interface\n\n```python\nfrom sklearn.datasets import load_breast_cancer\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_auc_score\nimport xgboost as xgb\n\nX, y = load_breast_cancer(return_X_y=True)\nX_train, X_valid, y_train, y_valid = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)\n\nmodel = xgb.XGBClassifier(\n    n_estimators=500,\n    max_depth=6,\n    learning_rate=0.05,\n    subsample=0.8,\n    colsample_bytree=0.8,\n    objective=\"binary:logistic\",\n    eval_metric=\"auc\",\n    tree_method=\"hist\",\n    device=\"cpu\",\n    random_state=42,\n)\n\nmodel.fit(\n    X_train,\n    y_train,\n    eval_set=[(X_valid, y_valid)],\n    verbose=False,\n)\n\nproba = model.predict_proba(X_valid)[:, 1]\nprint(\"AUC:\", roc_auc_score(y_valid, proba))\n\nmodel.save_model(\"model.json\")\n```\n\nNotes:\n\n- `tree_method=\"hist\"` is the usual default choice for new code\n- set `device=\"cuda\"` to use a supported NVIDIA GPU\n- with sklearn estimators, use `n_estimators`; with the native API, use `num_boost_round`\n\n## Quick Start: Native Interface\n\n```python\nimport numpy as np\nimport xgboost as xgb\n\nrng = np.random.default_rng(42)\nX_train = rng.normal(size=(1000, 20))\ny_train = (X_train[:, 0] + X_train[:, 1] > 0).astype(int)\nX_valid = rng.normal(size=(200, 20))\ny_valid = (X_valid[:, 0] + X_valid[:, 1] > 0).astype(int)\n\ndtrain = xgb.DMatrix(X_train, label=y_train)\ndvalid = xgb.DMatrix(X_valid, label=y_valid)\n\nparams = {\n    \"objective\": \"binary:logistic\",\n    \"eval_metric\": \"auc\",\n    \"max_depth\": 6,\n    \"eta\": 0.05,\n    \"subsample\": 0.8,\n    \"colsample_bytree\": 0.8,\n    \"tree_method\": \"hist\",\n    \"device\": \"cpu\",\n}\n\nbst = xgb.train(\n    params=params,\n    dtrain=dtrain,\n    num_boost_round=500,\n    evals=[(dtrain, \"train\"), (dvalid, \"valid\")],\n    early_stopping_rounds=20,\n    verbose_eval=False,\n)\n\npred = bst.predict(dvalid, iteration_range=(0, bst.best_iteration + 1))\nbst.save_model(\"model.ubj\")\n```\n\n## Data Input\n\n`xgboost` accepts a wide range of inputs in Python. Common ones:\n\n- `numpy.ndarray`\n- `scipy.sparse` matrices\n- `pandas.DataFrame`\n- `cudf.DataFrame` and other GPU-backed data structures where supported\n\nUse `DMatrix` directly for native training:\n\n```python\ndtrain = xgb.DMatrix(X, label=y, missing=float(\"nan\"))\n```\n\nIf you pass pandas data to the sklearn API, XGBoost will internally build `DMatrix` or `QuantileDMatrix` depending on the algorithm and input.\n\n## Core Parameters To Reach For First\n\n### Shared Across Most Tree Models\n\n- `objective`: learning task, for example `binary:logistic`, `reg:squarederror`, `multi:softprob`\n- `eval_metric`: validation metric, for example `auc`, `logloss`, `rmse`\n- `max_depth`: tree depth\n- `learning_rate` or `eta`: shrinkage\n- `subsample`: row subsampling\n- `colsample_bytree`: feature subsampling per tree\n- `n_jobs` or `nthread`: CPU parallelism\n\n### Compute And Tree Construction\n\n- `tree_method=\"hist\"`: the usual choice for modern CPU or GPU training\n- `device=\"cpu\"`: explicit CPU training\n- `device=\"cuda\"`: GPU training on supported CUDA environments\n- `validate_parameters=True`: useful when debugging misspelled parameters\n\n## Early Stopping\n\nNative interface behavior:\n\n- `early_stopping_rounds` requires at least one evaluation set\n- if you pass multiple evaluation sets, early stopping uses the last one\n- `xgb.train()` returns the model from the last iteration, not automatically the best checkpoint\n- use `bst.best_iteration` when predicting after early stopping\n\nScikit-learn estimator behavior:\n\n- `predict`, `score`, and `apply` automatically use the best iteration when early stopping is enabled\n- if you need direct low-level prediction caching or full `Booster` behavior, call `model.get_booster()`\n\n## Categorical Features\n\nFor categorical columns, do not one-hot encode by default just because the library is tree-based. XGBoost supports native categorical handling.\n\n```python\nimport pandas as pd\nimport xgboost as xgb\n\nX = pd.DataFrame(\n    {\n        \"city\": [\"ny\", \"sf\", \"ny\", \"la\"],\n        \"age\": [10, 20, 30, 40],\n    }\n)\nX[\"city\"] = X[\"city\"].astype(\"category\")\ny = [0, 1, 0, 1]\n\nclf = xgb.XGBClassifier(\n    tree_method=\"hist\",\n    enable_categorical=True,\n    device=\"cpu\",\n)\nclf.fit(X, y)\nclf.save_model(\"categorical-model.json\")\n```\n\nRules that matter:\n\n- convert categorical columns to pandas or cuDF `category` dtype first\n- set `enable_categorical=True`\n- use `tree_method=\"hist\"` or `tree_method=\"approx\"`\n- save categorical models as `.json` or `.ubj`; older legacy formats lose categorical metadata\n\n## Model Persistence\n\nUse model files for long-term storage and portability:\n\n```python\nmodel.save_model(\"model.json\")\nloaded = xgb.XGBClassifier()\nloaded.load_model(\"model.json\")\n```\n\nFor native boosters:\n\n```python\nbst.save_model(\"model.ubj\")\nrestored = xgb.Booster()\nrestored.load_model(\"model.ubj\")\n```\n\nPrefer `.json` or `.ubj`:\n\n- model files are the stable, backward-compatible format\n- pickled boosters are memory snapshots, not stable interchange artifacts\n- do not rely on `pickle` for long-term archival across XGBoost or Python version changes\n\n## Plotting And Inspection\n\nSome inspection helpers need optional dependencies:\n\n- `xgb.plot_importance(...)` requires `matplotlib`\n- `xgb.plot_tree(...)` requires `matplotlib` and `graphviz`\n- PyPI publishes a `plotting` extra if you want a package-managed install path for plotting helpers\n\n## Common Pitfalls\n\n### Wrong Installation Assumptions\n\n- `pip install xgboost` is not the same as `xgboost-cpu`\n- on older Linux systems, wheel install failures often mean the host is below `glibc 2.28`\n- on Windows, missing runtime DLLs usually means the Visual C++ Redistributable is absent\n\n### Mixing Native And sklearn Parameters\n\n- native API uses `num_boost_round`\n- sklearn estimators use `n_estimators`\n- native examples often show `eta`; sklearn code often uses `learning_rate`\n\n### Early Stopping Confusion\n\n- `xgb.train()` keeps training state from the last round; use `best_iteration` explicitly when predicting\n- sklearn wrappers already use the best iteration for prediction methods when early stopping is active\n\n### Thread Contention\n\n- XGBoost uses all available threads by default\n- if you also run sklearn cross-validation with parallelism, set `n_jobs` deliberately to avoid thread thrashing\n\n### Categorical Serialization Mistakes\n\n- categorical models must be saved as `.json` or `.ubj`\n- if you forget `enable_categorical=True`, XGBoost will not treat category-typed columns as native categorical features\n\n### Booster Methods\n\n- `Booster.update()` and `Booster.boost()` are internal-oriented APIs\n- for normal training, prefer `xgb.train()` instead of manually driving booster updates\n\n## Version-Sensitive Notes For 3.2.0\n\n- PyPI lists `3.2.0` as the latest release on `2026-02-10`\n- PyPI requires Python `>=3.10`\n- the docs for `3.2.0` describe `device` as the main CPU/GPU switch; older code may still use older GPU-only parameter conventions\n- starting with `2.1.0`, XGBoost uses JSON or UBJSON model IO for stable serialization; do not treat pickle snapshots as durable artifacts\n- the categorical data tutorial documents Python auto-recoding support added in `3.1`, so category-handling behavior may differ from older `2.x` examples\n- `3.2.0` adds new global configuration like `use_cuda_async_pool`; treat it as experimental and only use it when you know your CUDA environment and allocator behavior\n\n## No Auth / Service Configuration\n\n`xgboost` is a local library, not a hosted API client:\n\n- no API keys\n- no service endpoint configuration\n- the main environment concerns are Python version, CPU vs GPU availability, system libraries, and optional plotting or dataframe dependencies\n\n## Canonical Upstream Links\n\n- Stable docs: https://xgboost.readthedocs.io/en/stable/\n- Installation guide: https://xgboost.readthedocs.io/en/stable/install.html\n- Python package intro: https://xgboost.readthedocs.io/en/stable/python/python_intro.html\n- sklearn estimator guide: https://xgboost.readthedocs.io/en/stable/python/sklearn_estimator.html\n- Parameters: https://xgboost.readthedocs.io/en/stable/parameter.html\n- Categorical tutorial: https://xgboost.readthedocs.io/en/stable/tutorials/categorical.html\n- Model IO: https://xgboost.readthedocs.io/en/stable/tutorials/saving_model.html\n- Release notes: https://xgboost.readthedocs.io/en/stable/changes/\n- PyPI: https://pypi.org/project/xgboost/\n"
  },
  {
    "path": "content/xlsxwriter/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"XlsxWriter Python package guide for creating Excel .xlsx files with worksheets, formats, charts, and dataframe exports\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.2.9\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n---\n\n# XlsxWriter Python Package Guide\n\n## Golden Rule\n\nUse `xlsxwriter` when you need to generate new Excel `.xlsx` files from Python. It is a write-focused library: create workbooks, worksheets, formats, charts, tables, and dataframe exports, then close the workbook exactly once. It does not read or modify existing Excel files.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"XlsxWriter==3.2.9\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"XlsxWriter==3.2.9\"\npoetry add \"XlsxWriter==3.2.9\"\n```\n\n## Basic Workbook Lifecycle\n\nCreate a workbook, add one or more worksheets, write data, then call `close()` to finalize the file:\n\n```python\nimport xlsxwriter\n\nworkbook = xlsxwriter.Workbook(\"hello.xlsx\")\n\ntry:\n    worksheet = workbook.add_worksheet(\"Summary\")\n    worksheet.write(\"A1\", \"Hello\")\n    worksheet.write(\"B1\", 123)\nfinally:\n    workbook.close()\n```\n\nNotes:\n\n- `close()` writes the final ZIP container and can raise file-creation errors if the destination is open in Excel or the path is invalid.\n- XlsxWriter supports both zero-based row/column indexes and Excel `A1` notation.\n- Use `.xlsx` output paths. XlsxWriter is not an `.xls` writer.\n\n## Core Usage\n\n### Write typed values\n\n`write()` auto-detects many Python values, but the typed methods are clearer when type handling matters:\n\n```python\nfrom datetime import datetime\nimport xlsxwriter\n\nworkbook = xlsxwriter.Workbook(\n    \"report.xlsx\",\n    {\n        \"default_date_format\": \"yyyy-mm-dd\",\n        \"remove_timezone\": True,\n    },\n)\n\ntry:\n    worksheet = workbook.add_worksheet(\"Summary\")\n    header = workbook.add_format({\"bold\": True, \"bg_color\": \"#D9E2F3\"})\n    money = workbook.add_format({\"num_format\": \"$#,##0.00\"})\n    date_fmt = workbook.add_format({\"num_format\": \"yyyy-mm-dd hh:mm\"})\n\n    worksheet.write_row(\"A1\", [\"Item\", \"Amount\", \"Created At\"], header)\n\n    rows = [\n        (\"Books\", 42.50, datetime(2026, 3, 12, 9, 30)),\n        (\"Games\", 19.99, datetime(2026, 3, 12, 11, 15)),\n        (\"Snacks\", 8.25, datetime(2026, 3, 12, 13, 5)),\n    ]\n\n    for row_idx, (item, amount, created_at) in enumerate(rows, start=1):\n        worksheet.write_string(row_idx, 0, item)\n        worksheet.write_number(row_idx, 1, amount, money)\n        worksheet.write_datetime(row_idx, 2, created_at, date_fmt)\n\n    worksheet.write_formula(\"B5\", \"=SUM(B2:B4)\", money)\n    worksheet.autofit()\nfinally:\n    workbook.close()\n```\n\n### Add formatting, charts, and tables\n\n```python\nimport xlsxwriter\n\nworkbook = xlsxwriter.Workbook(\"sales.xlsx\")\n\ntry:\n    worksheet = workbook.add_worksheet(\"Sales\")\n\n    worksheet.write_row(\"A1\", [\"Month\", \"Revenue\"])\n    worksheet.write_column(\"A2\", [\"Jan\", \"Feb\", \"Mar\"])\n    worksheet.write_column(\"B2\", [12000, 15000, 17000])\n\n    worksheet.add_table(\n        \"A1:B4\",\n        {\n            \"style\": \"Table Style Medium 2\",\n            \"columns\": [\n                {\"header\": \"Month\"},\n                {\"header\": \"Revenue\"},\n            ],\n        },\n    )\n\n    chart = workbook.add_chart({\"type\": \"column\"})\n    chart.add_series(\n        {\n            \"name\": \"Revenue\",\n            \"categories\": \"=Sales!$A$2:$A$4\",\n            \"values\": \"=Sales!$B$2:$B$4\",\n        }\n    )\n    chart.set_title({\"name\": \"Quarter Revenue\"})\n\n    worksheet.insert_chart(\"D2\", chart)\nfinally:\n    workbook.close()\n```\n\nUseful worksheet APIs agents commonly need:\n\n- `set_column()` and `set_row()` for sizing and default formats\n- `freeze_panes()` for sticky headers\n- `autofilter()` and `add_table()` for structured sheet output\n- `write_url()`, `insert_image()`, `data_validation()`, and `conditional_format()` for richer reports\n\n## DataFrame Exports\n\n### Pandas\n\nUse the `xlsxwriter` engine when you want pandas output plus workbook-level formatting:\n\n```python\nimport pandas as pd\n\ndf = pd.DataFrame(\n    [\n        {\"name\": \"Ada\", \"score\": 98},\n        {\"name\": \"Linus\", \"score\": 91},\n    ]\n)\n\nwith pd.ExcelWriter(\n    \"scores.xlsx\",\n    engine=\"xlsxwriter\",\n    engine_kwargs={\"options\": {\"strings_to_numbers\": True}},\n) as writer:\n    df.to_excel(writer, sheet_name=\"Scores\", index=False)\n\n    workbook = writer.book\n    worksheet = writer.sheets[\"Scores\"]\n    score_fmt = workbook.add_format({\"num_format\": \"0\"})\n\n    worksheet.set_column(\"A:A\", 18)\n    worksheet.set_column(\"B:B\", 10, score_fmt)\n    worksheet.autofilter(0, 0, len(df), len(df.columns) - 1)\n```\n\n### Polars\n\nThe upstream docs also include dedicated Polars integration guidance through `DataFrame.write_excel()`. Use that when the project already depends on Polars and you want table-style exports without converting through pandas first.\n\n## Configuration Notes\n\nXlsxWriter has no network auth or API credentials. Configuration is local to `Workbook(...)` options and worksheet/workbook methods.\n\nConstructor options that matter in real projects:\n\n- `constant_memory=True`: reduce memory usage for large exports by flushing rows as you go; write in row order and expect some features to be more limited than in normal mode.\n- `in_memory=True`: build the file in memory instead of temp files.\n- `tmpdir=\"/path\"`: control where temporary files are written if the default temp directory is unsuitable.\n- `default_date_format=\"yyyy-mm-dd\"`: set a default Excel number format for date writes.\n- `remove_timezone=True`: strip timezone info from datetimes before writing, which avoids timezone-related Excel write issues.\n- `strings_to_numbers`, `strings_to_formulas`, `strings_to_urls`: control automatic coercion when writing plain strings.\n\n## Exceptions And File Handling\n\nXlsxWriter surfaces library-specific exceptions for workbook creation and integrity problems. The ones agents most often need to handle are:\n\n- `FileCreateError`: output file cannot be created, often because the file is already open in Excel\n- `DuplicateWorksheetName`: duplicate worksheet title in a workbook\n- `InvalidWorksheetName`: worksheet title exceeds Excel rules\n- `OverlappingRange`: merged ranges or tables overlap\n\nExample:\n\n```python\nimport xlsxwriter\nfrom xlsxwriter.exceptions import FileCreateError\n\nworkbook = xlsxwriter.Workbook(\"report.xlsx\")\n\ntry:\n    worksheet = workbook.add_worksheet()\n    worksheet.write(\"A1\", \"ok\")\n    workbook.close()\nexcept FileCreateError as exc:\n    raise RuntimeError(\n        \"Could not write report.xlsx. Close the file in Excel and try again.\"\n    ) from exc\n```\n\n## Common Pitfalls\n\n- XlsxWriter creates new files; it does not load or edit existing workbooks. Use another library if you must modify an existing `.xlsx`.\n- Forgetting `close()` leaves the workbook incomplete or corrupted.\n- Excel stores dates as numbers. Use `write_datetime()` plus a date format instead of writing raw datetime strings if you want Excel date behavior.\n- Worksheet names must be unique and must follow Excel naming rules.\n- Large exports can consume significant memory in default mode; switch to `constant_memory` or a streaming dataframe workflow when row counts are high.\n- Formula strings beginning with `=` are treated as formulas. If a value should stay plain text, write it explicitly with `write_string()`.\n- If an output file already exists and is open in Excel, finalization commonly fails on `close()`, not at workbook creation time.\n\n## Version-Sensitive Notes For 3.2.9\n\n- PyPI lists `XlsxWriter 3.2.9` as the current package version as of 2026-03-12.\n- The upstream change log for `3.2.9` notes a typing-related packaging change: `py.typed` was removed because the package uses `.pyi` stubs. If editor or CI typing behavior changes after upgrading, verify the tool reads the installed stubs correctly.\n- The current PyPI metadata requires Python `>=3.8`. If you are curating or generating code for older runtimes, this version is out of range.\n\n## Official Sources\n\n- Docs root: https://xlsxwriter.readthedocs.io/\n- Tutorial and examples: https://xlsxwriter.readthedocs.io/tutorial01.html\n- Workbook and constructor options: https://xlsxwriter.readthedocs.io/workbook.html\n- Exceptions: https://xlsxwriter.readthedocs.io/exceptions.html\n- Pandas integration: https://xlsxwriter.readthedocs.io/working_with_pandas.html\n- Polars integration: https://xlsxwriter.readthedocs.io/working_with_polars.html\n- Change log: https://xlsxwriter.readthedocs.io/changes.html\n- PyPI metadata: https://pypi.org/project/XlsxWriter/\n"
  },
  {
    "path": "content/yapf/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"YAPF Python formatter guide for configuring styles, formatting files, and using the library API\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.43.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"yapf,formatter,python,code-style,linting,clang-format\"\n---\n\n# YAPF Python Package Guide\n\n## Golden Rule\n\nUse `yapf` when the repository already standardizes on YAPF or needs YAPF-compatible formatting behavior. Put the style in checked-in project config, use diff mode in CI, and do not assume YAPF fully supports newer Python 3.12 syntax.\n\n## Install\n\nPin the version your project expects:\n\n```bash\npython -m pip install \"yapf==0.43.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"yapf==0.43.0\"\npoetry add \"yapf==0.43.0\"\n```\n\nIf you only need the formatter as a checked-in dev tool, keep it in your dev dependency group rather than your runtime dependencies.\n\n## Setup\n\nYAPF reads style settings from these locations in order:\n\n1. `--style` on the command line\n2. `[style]` in `.style.yapf`\n3. `[yapf]` in `setup.cfg`\n4. `[tool.yapf]` in `pyproject.toml`\n5. `[style]` in `~/.config/yapf/style`\n\nIf none of those exist, it falls back to the built-in `pep8` style.\n\nRecommended `pyproject.toml` setup:\n\n```toml\n[tool.yapf]\nbased_on_style = \"pep8\"\ncolumn_limit = 88\nindent_width = 4\nsplit_before_logical_operator = true\n\n[tool.yapfignore]\nignore_patterns = [\n  \"build/**/*.py\",\n  \".venv/**/*.py\",\n]\n```\n\nEquivalent `.style.yapf` setup:\n\n```ini\n[style]\nbased_on_style = pep8\ncolumn_limit = 88\nindent_width = 4\nsplit_before_logical_operator = true\n```\n\nPredefined styles are `pep8`, `google`, `yapf`, and `facebook`.\n\n## Core CLI Usage\n\nPrint formatted output to stdout:\n\n```bash\nyapf path/to/file.py\n```\n\nRewrite a file in place:\n\n```bash\nyapf -i path/to/file.py\n```\n\nFormat a directory recursively and print diffs instead of editing files:\n\n```bash\nyapf -d -r src tests\n```\n\nFormat multiple files in parallel and write changes in place:\n\n```bash\nyapf -i -r -p src tests\n```\n\nFormat only part of a file. Line numbers are 1-based:\n\n```bash\nyapf -i -l 10-40 app/views.py\n```\n\nRun a CI-style check:\n\n```bash\nyapf -d -r .\n```\n\nWith `--diff`, YAPF returns zero only when no reformatting is needed. That makes it suitable for CI enforcement.\n\n## Format Only Changed Lines\n\nUse `yapf-diff` when you want to reformat lines touched by a patch instead of whole files:\n\n```bash\ngit diff -U0 --no-color --relative HEAD^ | yapf-diff -i\n```\n\nIf the diff paths are not relative to your current working directory, use `-p` or run the command from the repository root so the filenames resolve correctly.\n\n## Library API\n\nFormat a code string:\n\n```python\nfrom yapf.yapflib.yapf_api import FormatCode\n\nsource = \"def add ( a, b ):\\n    return a+b\\n\"\nformatted, changed = FormatCode(source, style_config=\"pep8\")\n\nprint(formatted)\nprint(changed)\n```\n\nFormat only selected line ranges:\n\n```python\nfrom yapf.yapflib.yapf_api import FormatCode\n\nsource = \"def f( ):\\n a=1\\n b = 2\\n return a==b\\n\"\nformatted, changed = FormatCode(source, lines=[(1, 1), (2, 3)])\n```\n\nFormat a file:\n\n```python\nfrom yapf.yapflib.yapf_api import FormatFile\n\nformatted, encoding, changed = FormatFile(\"app.py\", style_config=\"pyproject.toml\")\n```\n\nWrite changes back to the file:\n\n```python\nfrom yapf.yapflib.yapf_api import FormatFile\n\n_, encoding, changed = FormatFile(\n    \"app.py\",\n    style_config=\"pyproject.toml\",\n    in_place=True,\n)\n```\n\nUse `print_diff=True` with `FormatCode(...)` when you need a unified diff instead of the rewritten source.\n\n## Config And Auth\n\nYAPF is a local formatter. It does not require an API key, account, or network auth.\n\nThe main configuration choices agents need to get right are:\n\n- whether the repo already has a checked-in YAPF style file\n- whether to use a named base style such as `pep8` or `google`\n- which files to exclude through `.yapfignore` or `[tool.yapfignore]`\n- whether the task should print diffs, edit files in place, or format only selected lines\n\n## Common Pitfalls\n\n- Without `-i`, the `yapf` CLI prints formatted code to stdout and does not modify the file.\n- The config section names are different by file type: `[style]` in `.style.yapf`, `[yapf]` in `setup.cfg`, and `[tool.yapf]` in `pyproject.toml`.\n- Exclude patterns in `pyproject.toml` belong under `[tool.yapfignore]`, not `[tool.yapf]`.\n- The default style is `pep8` if no local config is found, so agents should not assume Black-like output or project-specific settings.\n- `yapf-diff` trusts the filenames in the incoming diff. If paths are wrong relative to the current directory, it will not update the intended files.\n- Line ranges passed through `--lines` or `lines=[...]` are 1-based.\n- YAPF 0.43.0 still documents unsupported Python 3.12 features for PEP 695 type parameter syntax and PEP 701 f-string syntax.\n\n## Version-Sensitive Notes\n\n- As of March 12, 2026, PyPI still lists `0.43.0` as the latest release. It was uploaded on November 14, 2024.\n- The upstream changelog in the GitHub repo is stale relative to PyPI release history. It documents changes through `0.40.2` and still labels `0.41.0` as unreleased, so confirm release status from PyPI when pinning versions.\n- `0.40.2` removed the verification module and removed the public `verify` parameter from the API. Older examples using `verify=` are outdated.\n- `0.40.0` and `0.33.0` were yanked on PyPI. Do not pin those versions.\n- `0.33.0` added default `pyproject.toml` support, and `0.40.2` switched the build to `pyproject.toml`, so current `0.43.0` workflows should prefer `pyproject.toml` over legacy config files when the repo already uses it.\n\n## Official Sources\n\n- Maintainer docs and usage reference: `https://github.com/google/yapf`\n- Maintainer changelog: `https://raw.githubusercontent.com/google/yapf/main/CHANGELOG.md`\n- Package registry and release history: `https://pypi.org/project/yapf/`\n"
  },
  {
    "path": "content/yargs/docs/yargs/javascript/DOC.md",
    "content": "---\nname: yargs\ndescription: \"yargs for JavaScript CLIs with options, subcommands, config files, and environment-variable parsing\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"18.0.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"yargs,javascript,cli,nodejs,arguments,commands\"\n---\n\n# yargs Guide (JavaScript)\n\n`yargs` builds Node.js command-line interfaces by parsing arguments, generating help output, and organizing subcommands.\n\nUse it for local CLIs, build tools, and automation scripts where you want explicit option definitions instead of reading `process.argv` by hand.\n\n## Install\n\n```bash\nnpm install yargs\n```\n\nNo package-specific authentication or service initialization is required.\n\nNo package-specific environment variables are required unless you choose to map options from the environment with `.env(prefix)`.\n\n## Initialize yargs\n\n### ESM\n\n```js\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nconst cli = yargs(hideBin(process.argv));\n```\n\n`hideBin(process.argv)` removes the Node executable and script path before parsing.\n\n### CommonJS\n\n```js\nconst yargs = require(\"yargs\");\nconst { hideBin } = require(\"yargs/helpers\");\n\nconst cli = yargs(hideBin(process.argv));\n```\n\n## Parse Options\n\nDefine each option explicitly, then parse once:\n\n```js\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nconst argv = yargs(hideBin(process.argv))\n  .scriptName(\"imgtool\")\n  .usage(\"$0 --input <file> --format <json|yaml>\")\n  .option(\"input\", {\n    type: \"string\",\n    demandOption: true,\n    describe: \"Path to the source file\",\n  })\n  .option(\"format\", {\n    choices: [\"json\", \"yaml\"],\n    default: \"json\",\n    describe: \"Output format\",\n  })\n  .option(\"watch\", {\n    type: \"boolean\",\n    default: false,\n    describe: \"Rebuild when files change\",\n  })\n  .strict()\n  .help()\n  .parseSync();\n\nconsole.log(argv.input);\nconsole.log(argv.format);\nconsole.log(argv.watch);\n```\n\nUse `.strict()` when you want unknown flags to fail instead of being ignored.\n\nUse `.parseSync()` only when your builders, handlers, and middleware are synchronous.\n\n## Add Commands And Positionals\n\nFor multi-command CLIs, register commands with their own positionals and options:\n\n```js\n#!/usr/bin/env node\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nasync function startServer(port) {\n  console.log(`listening on ${port}`);\n}\n\nawait yargs(hideBin(process.argv))\n  .scriptName(\"devserver\")\n  .command(\n    \"serve [port]\",\n    \"Start the server\",\n    (cli) =>\n      cli\n        .positional(\"port\", {\n          describe: \"Port to bind on\",\n          default: 5000,\n          type: \"number\",\n        })\n        .option(\"verbose\", {\n          alias: \"v\",\n          type: \"boolean\",\n          default: false,\n          describe: \"Enable verbose logging\",\n        }),\n    async (argv) => {\n      if (argv.verbose) {\n        console.info(`starting on :${argv.port}`);\n      }\n\n      await startServer(argv.port);\n    }\n  )\n  .demandCommand(1)\n  .strictCommands()\n  .strictOptions()\n  .recommendCommands()\n  .help()\n  .parseAsync();\n```\n\nUse `.demandCommand(1)` when the CLI should require at least one subcommand.\n\nUse `.recommendCommands()` if you want help output to suggest close matches for mistyped commands.\n\n## Use Async Handlers Correctly\n\nIf any command handler, builder, or middleware is asynchronous, parse with `.parseAsync()`:\n\n```js\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nasync function deploy(target) {\n  console.log(`deploying ${target}`);\n}\n\nawait yargs(hideBin(process.argv))\n  .command(\n    \"deploy <target>\",\n    \"Deploy an environment\",\n    (cli) =>\n      cli.positional(\"target\", {\n        type: \"string\",\n        describe: \"Environment name\",\n      }),\n    async (argv) => {\n      await deploy(argv.target);\n    }\n  )\n  .help()\n  .parseAsync();\n```\n\n`parseSync()` throws if you use it with asynchronous builders, handlers, or middleware.\n\n## Load Values From A JSON Config File And Environment Variables\n\nUse `.config()` for a JSON config file option and `.env()` for prefixed environment variables:\n\n```js\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nconst argv = yargs(hideBin(process.argv))\n  .option(\"region\", {\n    type: \"string\",\n    describe: \"Deployment region\",\n  })\n  .option(\"profile\", {\n    type: \"string\",\n    describe: \"Named credentials profile\",\n  })\n  .config(\"config\")\n  .env(\"DEPLOY\")\n  .strict()\n  .help()\n  .parseSync();\n\nconsole.log(argv.region);\nconsole.log(argv.profile);\n```\n\nExample JSON config file:\n\n```json\n{\n  \"region\": \"us-east-1\",\n  \"profile\": \"prod\"\n}\n```\n\nExample shell invocation:\n\n```bash\nDEPLOY_PROFILE=staging node cli.js --config ./deploy.json\n```\n\nWith `.env(\"DEPLOY\")`, option names map to environment variables such as `DEPLOY_REGION` and `DEPLOY_PROFILE`.\n\n## Validate And Normalize Input\n\nUse yargs validation helpers instead of ad hoc checks after parsing:\n\n```js\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nconst argv = yargs(hideBin(process.argv))\n  .option(\"input\", {\n    type: \"string\",\n    describe: \"Input file\",\n  })\n  .option(\"output\", {\n    type: \"string\",\n    describe: \"Output file\",\n  })\n  .option(\"stdout\", {\n    type: \"boolean\",\n    default: false,\n    describe: \"Write to standard output\",\n  })\n  .option(\"retries\", {\n    type: \"number\",\n    default: 3,\n    describe: \"Retry count\",\n  })\n  .conflicts(\"stdout\", \"output\")\n  .implies(\"output\", \"input\")\n  .coerce(\"retries\", (value) => {\n    if (!Number.isInteger(value) || value < 0) {\n      throw new Error(\"--retries must be a non-negative integer\");\n    }\n\n    return value;\n  })\n  .check((parsedArgv) => {\n    if (!parsedArgv.input && !parsedArgv.stdout) {\n      return \"Provide --input or set --stdout\";\n    }\n\n    return true;\n  })\n  .strict()\n  .help()\n  .parseSync();\n\nconsole.log(argv);\n```\n\nThis keeps validation next to the option definitions, which is usually easier to maintain than validating after parsing.\n\n## Common Pitfalls\n\n- Pass `hideBin(process.argv)` to `yargs()` in Node CLI entrypoints instead of handing raw `process.argv` to the parser.\n- Use `.parseAsync()` whenever any builder, handler, or middleware returns a promise.\n- Add `.strict()`, `.strictCommands()`, or `.strictOptions()` when typos should fail fast.\n- `.config(\"config\")` is documented as a JSON config file option; use that default shape unless you deliberately add a custom parser.\n- Prefer explicit `.parseSync()` or `.parseAsync()` in application code when you want a clear parse point, rather than relying on implicit parsing.\n\n## Official Sources\n\n- https://yargs.js.org/\n- https://yargs.js.org/docs/\n- https://www.npmjs.com/package/yargs\n- https://github.com/yargs/yargs\n"
  },
  {
    "path": "content/yarl/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"yarl package guide for immutable URL parsing and construction in Python\"\nmetadata:\n  languages: \"python\"\n  versions: \"1.23.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"yarl,python,url,querystring,encoding,pydantic\"\n---\n\n# yarl Python Package Guide\n\n## Golden Rule\n\nUse `yarl.URL` when you need an immutable URL value with correct percent-encoding for path, query, fragment, and IDNA host handling. Treat every change as \"create a new URL\", not \"mutate the existing one\".\n\n## Install\n\n`yarl 1.23.0` requires Python 3.10 or newer.\n\n```bash\npython -m pip install \"yarl==1.23.0\"\n```\n\n`yarl` ships wheels for common Linux, macOS, and Windows environments. If your platform falls back to a source build, you need a C compiler and Python headers. To force the slower pure-Python build instead:\n\n```bash\nYARL_NO_EXTENSIONS=1 python -m pip install \"yarl==1.23.0\"\n```\n\n## Initialize URLs\n\nThere is no auth step, client object, or required environment variable. Import `URL` and construct values directly:\n\n```python\nfrom yarl import URL\n\nabsolute_url = URL(\"https://api.example.com/v1/items?limit=10#results\")\nrelative_url = URL(\"/v1/items?page=2\")\n\nprint(absolute_url.host)        # api.example.com\nprint(absolute_url.path)        # /v1/items\nprint(absolute_url.query_string)  # limit=10\nprint(relative_url.is_absolute())  # False\n```\n\n`yarl` stores URL parts in encoded form internally. `str(url)` gives the encoded wire form; `human_repr()` gives a decoded display form.\n\n```python\nfrom yarl import URL\n\nurl = URL(\"https://εxample.com/шлях/這裡\")\n\nprint(str(url))\nprint(url.human_repr())\nprint(url.raw_path)\n```\n\n## Build URLs Safely\n\nUse `URL.build()` when you already have structured pieces such as scheme, host, path, and query parameters:\n\n```python\nfrom yarl import URL\n\nurl = URL.build(\n    scheme=\"https\",\n    host=\"api.example.com\",\n    path=\"/v1/search\",\n    query={\"q\": \"red shoes\", \"page\": 2},\n)\n\nprint(url)\n# https://api.example.com/v1/search?q=red+shoes&page=2\n```\n\nIf you already have a serialized query string, pass `query_string=` instead of `query=`. Do not pass both in the same call.\n\n## Common Mutation Workflows\n\n### Replace or merge query parameters\n\n`with_query()` replaces the full query string, `update_query()` overwrites matching keys while keeping the rest, and `extend_query()` appends new values without removing duplicates.\n\n```python\nfrom yarl import URL\n\nbase = URL(\"https://api.example.com/items?category=books&tag=sale\")\n\nprint(base.with_query(page=2))\nprint(base.update_query(page=2, category=\"games\"))\nprint(base.extend_query(tag=\"featured\"))\n```\n\nUse strings, integers, floats, sequences, or mappings for query values. `bool` is intentionally rejected, so convert it yourself:\n\n```python\nfrom yarl import URL\n\ninclude_archived = True\nurl = URL(\"https://api.example.com/items\").with_query(\n    include_archived=\"true\" if include_archived else \"false\"\n)\n```\n\n### Replace or append path segments\n\nPath helpers return a new URL and normally drop the current query and fragment unless you keep them explicitly.\n\n```python\nfrom yarl import URL\n\nurl = URL(\"https://api.example.com/files/report.csv?download=1#latest\")\n\nprint(url.with_path(\"/files/archive/report.csv\", keep_query=True, keep_fragment=True))\nprint(url.with_name(\"summary.csv\"))\nprint(url.with_suffix(\".json\"))\nprint(url / \"exports\")\nprint(url.joinpath(\"2026\", \"03\"))\n```\n\nIf you already have percent-encoded path segments, `joinpath(..., encoded=True)` skips auto-encoding for the provided pieces.\n\n### Join a relative URL to a base URL\n\nUse `join()` when you have a base URL and a separate relative URL:\n\n```python\nfrom yarl import URL\n\nbase = URL(\"https://docs.example.com/guides/index.html\")\npage = URL(\"python/quickstart.html\")\n\nprint(base.join(page))\n```\n\nUseful derived forms:\n\n```python\nfrom yarl import URL\n\nurl = URL(\"https://user:pass@example.com:8443/path/to/file.txt?download=1#top\")\n\nprint(url.origin())    # https://example.com:8443\nprint(url.relative())  # /path/to/file.txt?download=1#top\n```\n\n## Use In Pydantic Models\n\n`yarl 1.23.0` adds seamless `pydantic` field support for `URL`.\n\n```python\nfrom pydantic import BaseModel\nfrom yarl import URL\n\n\nclass ServiceConfig(BaseModel):\n    base_url: URL\n\n\nconfig = ServiceConfig(base_url=\"https://api.example.com/v1\")\nprint(config.base_url / \"users\")\n```\n\n## Useful Accessors\n\nUse decoded properties for application logic and `raw_` properties when you need the exact encoded form:\n\n```python\nfrom yarl import URL\n\nurl = URL(\"https://xn--n1agdj.xn--d1acufc/%D1%88%D0%BB%D1%8F%D1%85?a=1#frag\")\n\nprint(url.host)        # decoded host\nprint(url.raw_host)    # IDNA form\nprint(url.path)        # decoded path\nprint(url.raw_path)    # encoded path\nprint(url.query)\nprint(url.fragment)\n```\n\n## Common Pitfalls\n\n- `URL` is immutable. Always capture the returned value from `with_query()`, `with_path()`, `join()`, `/`, and similar helpers.\n- `with_path()`, `with_name()`, `with_suffix()`, `/`, and `joinpath()` clean up query and fragment data unless you use the `keep_query` and `keep_fragment` options where supported.\n- Do not pass Python booleans as query values. Convert them to your own string convention such as `\"true\"` or `\"1\"`.\n- `encoded=True` is an escape hatch for already-encoded input. The docs warn that later URL manipulations can still re-quote parts of the URL, so do not assume it freezes every segment forever.\n- `str(url)` is the encoded URL for HTTP requests and storage. Use `human_repr()` for logs or UI when you want readable Unicode.\n- Since `yarl 1.13`, `URL.path` no longer decodes `%2F` into `/`. Do not treat encoded slashes as interchangeable with real path separators.\n\n## Cache Controls\n\n`yarl` caches IDNA conversion and host encoding globally. Most applications should ignore this, but long-running systems with unusual hostname churn can inspect or adjust cache behavior:\n\n```python\nimport yarl\n\nprint(yarl.cache_info())\nyarl.cache_configure(encode_host_size=1024)\n```\n\n## Official Sources\n\n- Docs root: https://yarl.aio-libs.org/en/latest/\n- Public API: https://yarl.aio-libs.org/en/stable/api/\n- Changelog: https://yarl.aio-libs.org/en/stable/changes/\n- PyPI package: https://pypi.org/project/yarl/\n"
  },
  {
    "path": "content/zendesk/docs/support/javascript/DOC.md",
    "content": "---\nname: support\ndescription: \"Zendesk API JavaScript/Node.js SDK (node-zendesk) for helpdesk, tickets, and customer service integration\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"6.0.1\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"zendesk,support,helpdesk,tickets,customer-service\"\n---\n\n# Zendesk API - JavaScript/Node.js SDK (node-zendesk)\n\n## Golden Rule\n\n**ALWAYS use the `node-zendesk` package (version 6.0.1 or later) for Zendesk API integration in JavaScript/Node.js projects.**\n\n```bash\nnpm install node-zendesk\n```\n\n**DO NOT use:**\n- `zendesk-node-api` (community alternative)\n- `zendesk-node` (outdated)\n- `@zendesk/client` (non-existent)\n- Direct HTTP requests to Zendesk API endpoints (use the SDK instead)\n\nThe `node-zendesk` library is the officially recommended and most actively maintained Node.js client for the Zendesk API, with 10+ years of continuous support.\n\n---\n\n## Installation\n\n```bash\nnpm install node-zendesk\n```\n\nFor TypeScript projects, the package includes TypeScript definitions:\n\n```bash\nnpm install node-zendesk\n# TypeScript definitions are included in the package\n```\n\n---\n\n## Authentication & Initialization\n\n### API Token Authentication (Recommended)\n\nThe most common authentication method uses username, API token, and subdomain:\n\n```javascript\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  username: 'your_email@example.com',\n  token: 'your_api_token',\n  subdomain: 'your_subdomain'\n});\n```\n\n**Environment Variables Example:**\n\n```javascript\nrequire('dotenv').config();\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN\n});\n```\n\n**.env file:**\n\n```\nZENDESK_USERNAME=your_email@example.com\nZENDESK_API_TOKEN=your_api_token_here\nZENDESK_SUBDOMAIN=your_company\n```\n\n### OAuth Token Authentication\n\nFor OAuth-based authentication:\n\n```javascript\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  token: 'your_oauth_access_token',\n  oauth: true,\n  subdomain: 'your_subdomain'\n});\n```\n\n**With Environment Variables:**\n\n```javascript\nconst client = zendesk.createClient({\n  token: process.env.ZENDESK_OAUTH_TOKEN,\n  oauth: true,\n  subdomain: process.env.ZENDESK_SUBDOMAIN\n});\n```\n\n### TypeScript/ES6 Import\n\n```typescript\nimport { createClient } from 'node-zendesk';\n\nconst client = createClient({\n  username: process.env.ZENDESK_USERNAME!,\n  token: process.env.ZENDESK_API_TOKEN!,\n  subdomain: process.env.ZENDESK_SUBDOMAIN!\n});\n```\n\n### User Impersonation\n\nMake requests on behalf of end users (requires proper OAuth scopes):\n\n```javascript\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN,\n  asUser: 'end-user@example.com'\n});\n```\n\n### Custom Configuration\n\n```javascript\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN,\n  remoteUri: 'https://custom.zendesk.com/api/v2',  // Custom API endpoint\n  debug: true,  // Enable debug logging\n  disableGlobalState: true,  // Disable global state (for serverless)\n  retry: true,  // Enable automatic retries\n  timeout: 30000  // Request timeout in ms (default: 60000)\n});\n```\n\n---\n\n## Core API Surfaces\n\n### Tickets API\n\n#### List All Tickets\n\n**Basic Example:**\n\n```javascript\n// List all tickets\nclient.tickets.list()\n  .then(tickets => {\n    console.log('Total tickets:', tickets.length);\n    tickets.forEach(ticket => {\n      console.log(`#${ticket.id}: ${ticket.subject}`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example with Pagination:**\n\n```javascript\n// List tickets with pagination\nasync function listAllTickets() {\n  let page = 1;\n  let hasMore = true;\n\n  while (hasMore) {\n    const result = await client.tickets.list(page);\n\n    result.forEach(ticket => {\n      console.log(`Ticket #${ticket.id}: ${ticket.subject}`);\n      console.log(`Status: ${ticket.status}, Priority: ${ticket.priority}`);\n      console.log(`Created: ${ticket.created_at}`);\n      console.log('---');\n    });\n\n    hasMore = result.nextPage !== null;\n    page++;\n  }\n}\n\nlistAllTickets().catch(console.error);\n```\n\n#### Show Single Ticket\n\n**Basic Example:**\n\n```javascript\nconst ticketId = 12345;\n\nclient.tickets.show(ticketId)\n  .then(ticket => {\n    console.log('Subject:', ticket.subject);\n    console.log('Status:', ticket.status);\n    console.log('Requester ID:', ticket.requester_id);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function getTicketDetails(ticketId) {\n  try {\n    const ticket = await client.tickets.show(ticketId);\n\n    console.log('=== Ticket Details ===');\n    console.log(`ID: ${ticket.id}`);\n    console.log(`Subject: ${ticket.subject}`);\n    console.log(`Description: ${ticket.description}`);\n    console.log(`Status: ${ticket.status}`);\n    console.log(`Priority: ${ticket.priority}`);\n    console.log(`Type: ${ticket.type}`);\n    console.log(`Requester ID: ${ticket.requester_id}`);\n    console.log(`Assignee ID: ${ticket.assignee_id}`);\n    console.log(`Group ID: ${ticket.group_id}`);\n    console.log(`Created: ${ticket.created_at}`);\n    console.log(`Updated: ${ticket.updated_at}`);\n    console.log(`Tags: ${ticket.tags.join(', ')}`);\n\n    // Custom fields\n    if (ticket.custom_fields && ticket.custom_fields.length > 0) {\n      console.log('Custom Fields:');\n      ticket.custom_fields.forEach(field => {\n        console.log(`  ${field.id}: ${field.value}`);\n      });\n    }\n\n    return ticket;\n  } catch (error) {\n    console.error('Failed to fetch ticket:', error.message);\n    throw error;\n  }\n}\n\ngetTicketDetails(12345);\n```\n\n#### Create Ticket\n\n**Basic Example:**\n\n```javascript\nconst newTicket = {\n  subject: 'Help with product installation',\n  comment: {\n    body: 'I need assistance installing the product on my system.'\n  },\n  requester: {\n    name: 'John Doe',\n    email: 'john.doe@example.com'\n  },\n  priority: 'normal',\n  status: 'new'\n};\n\nclient.tickets.create(newTicket)\n  .then(ticket => {\n    console.log('Ticket created successfully!');\n    console.log('Ticket ID:', ticket.id);\n    console.log('Subject:', ticket.subject);\n  })\n  .catch(error => {\n    console.error('Error creating ticket:', error.message);\n  });\n```\n\n**Advanced Example with Custom Fields:**\n\n```javascript\nasync function createDetailedTicket() {\n  const ticket = {\n    subject: 'Technical Support Request',\n    comment: {\n      body: 'Detailed description of the issue...\\n\\nSteps to reproduce:\\n1. Step one\\n2. Step two',\n      public: true\n    },\n    requester: {\n      name: 'Jane Smith',\n      email: 'jane.smith@example.com',\n      locale_id: 1  // English (United States)\n    },\n    assignee_id: 67890,\n    group_id: 11111,\n    priority: 'high',\n    status: 'open',\n    type: 'problem',\n    tags: ['technical', 'urgent', 'product-bug'],\n    custom_fields: [\n      { id: 12345, value: 'Custom value 1' },\n      { id: 67890, value: 'Custom value 2' }\n    ],\n    due_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()  // 7 days from now\n  };\n\n  try {\n    const createdTicket = await client.tickets.create(ticket);\n    console.log('Ticket created:', createdTicket.id);\n    return createdTicket;\n  } catch (error) {\n    console.error('Failed to create ticket:', error.message);\n    throw error;\n  }\n}\n\ncreateDetailedTicket();\n```\n\n#### Update Ticket\n\n**Basic Example:**\n\n```javascript\nconst ticketId = 12345;\nconst updates = {\n  status: 'solved',\n  comment: {\n    body: 'This issue has been resolved.',\n    public: true\n  }\n};\n\nclient.tickets.update(ticketId, updates)\n  .then(ticket => {\n    console.log('Ticket updated successfully!');\n    console.log('New status:', ticket.status);\n  })\n  .catch(error => {\n    console.error('Error updating ticket:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function updateTicketWithComment(ticketId) {\n  const updates = {\n    status: 'pending',\n    priority: 'high',\n    assignee_id: 98765,\n    tags: ['escalated', 'requires-attention'],\n    comment: {\n      body: 'This ticket has been escalated to senior support.',\n      author_id: 12345,\n      public: false  // Internal comment\n    },\n    custom_fields: [\n      { id: 11111, value: 'Updated value' }\n    ]\n  };\n\n  try {\n    const updatedTicket = await client.tickets.update(ticketId, updates);\n    console.log('Ticket updated:', updatedTicket.id);\n    console.log('New status:', updatedTicket.status);\n    console.log('New priority:', updatedTicket.priority);\n    return updatedTicket;\n  } catch (error) {\n    console.error('Failed to update ticket:', error.message);\n    throw error;\n  }\n}\n\nupdateTicketWithComment(12345);\n```\n\n#### Delete Ticket\n\n**Basic Example:**\n\n```javascript\nconst ticketId = 12345;\n\nclient.tickets.delete(ticketId)\n  .then(() => {\n    console.log('Ticket deleted successfully');\n  })\n  .catch(error => {\n    console.error('Error deleting ticket:', error.message);\n  });\n```\n\n**Advanced Example with Confirmation:**\n\n```javascript\nasync function deleteTicketSafely(ticketId) {\n  try {\n    // First, verify the ticket exists\n    const ticket = await client.tickets.show(ticketId);\n    console.log(`About to delete ticket #${ticket.id}: ${ticket.subject}`);\n\n    // Delete the ticket\n    await client.tickets.delete(ticketId);\n    console.log('Ticket deleted successfully');\n\n    return true;\n  } catch (error) {\n    if (error.statusCode === 404) {\n      console.log('Ticket not found');\n    } else {\n      console.error('Failed to delete ticket:', error.message);\n    }\n    return false;\n  }\n}\n\ndeleteTicketSafely(12345);\n```\n\n#### List Ticket Comments\n\n**Basic Example:**\n\n```javascript\nconst ticketId = 12345;\n\nclient.tickets.getComments(ticketId)\n  .then(comments => {\n    console.log(`Found ${comments.length} comments`);\n    comments.forEach(comment => {\n      console.log(`Author: ${comment.author_id}`);\n      console.log(`Body: ${comment.body}`);\n      console.log(`Public: ${comment.public}`);\n      console.log('---');\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function analyzeTicketConversation(ticketId) {\n  try {\n    const comments = await client.tickets.getComments(ticketId);\n\n    const publicComments = comments.filter(c => c.public);\n    const privateComments = comments.filter(c => !c.public);\n\n    console.log('=== Ticket Conversation Analysis ===');\n    console.log(`Total comments: ${comments.length}`);\n    console.log(`Public comments: ${publicComments.length}`);\n    console.log(`Private/Internal notes: ${privateComments.length}`);\n\n    console.log('\\n=== Comment History ===');\n    comments.forEach((comment, index) => {\n      console.log(`\\n[Comment ${index + 1}]`);\n      console.log(`ID: ${comment.id}`);\n      console.log(`Author ID: ${comment.author_id}`);\n      console.log(`Created: ${comment.created_at}`);\n      console.log(`Type: ${comment.public ? 'Public' : 'Internal'}`);\n      console.log(`Body: ${comment.body.substring(0, 100)}...`);\n\n      if (comment.attachments && comment.attachments.length > 0) {\n        console.log('Attachments:');\n        comment.attachments.forEach(att => {\n          console.log(`  - ${att.file_name} (${att.size} bytes)`);\n        });\n      }\n    });\n\n    return comments;\n  } catch (error) {\n    console.error('Error fetching comments:', error.message);\n    throw error;\n  }\n}\n\nanalyzeTicketConversation(12345);\n```\n\n---\n\n### Users API\n\n#### List Users\n\n**Basic Example:**\n\n```javascript\nclient.users.list()\n  .then(users => {\n    console.log('Total users:', users.length);\n    users.forEach(user => {\n      console.log(`${user.name} (${user.email})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example with Filtering:**\n\n```javascript\nasync function listActiveAgents() {\n  try {\n    const users = await client.users.list();\n\n    // Filter for active agents\n    const agents = users.filter(user =>\n      user.role === 'agent' && user.active === true\n    );\n\n    console.log(`Found ${agents.length} active agents:`);\n    agents.forEach(agent => {\n      console.log(`\\nName: ${agent.name}`);\n      console.log(`Email: ${agent.email}`);\n      console.log(`Role: ${agent.role}`);\n      console.log(`Timezone: ${agent.time_zone}`);\n      console.log(`Locale: ${agent.locale}`);\n      console.log(`Last Login: ${agent.last_login_at}`);\n    });\n\n    return agents;\n  } catch (error) {\n    console.error('Error fetching users:', error.message);\n    throw error;\n  }\n}\n\nlistActiveAgents();\n```\n\n#### Show User\n\n**Basic Example:**\n\n```javascript\nconst userId = 67890;\n\nclient.users.show(userId)\n  .then(user => {\n    console.log('Name:', user.name);\n    console.log('Email:', user.email);\n    console.log('Role:', user.role);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function getUserProfile(userId) {\n  try {\n    const user = await client.users.show(userId);\n\n    console.log('=== User Profile ===');\n    console.log(`ID: ${user.id}`);\n    console.log(`Name: ${user.name}`);\n    console.log(`Email: ${user.email}`);\n    console.log(`Phone: ${user.phone || 'N/A'}`);\n    console.log(`Role: ${user.role}`);\n    console.log(`Active: ${user.active}`);\n    console.log(`Verified: ${user.verified}`);\n    console.log(`Timezone: ${user.time_zone}`);\n    console.log(`Locale: ${user.locale}`);\n    console.log(`Organization ID: ${user.organization_id}`);\n    console.log(`Created: ${user.created_at}`);\n    console.log(`Updated: ${user.updated_at}`);\n    console.log(`Last Login: ${user.last_login_at}`);\n    console.log(`Tags: ${user.tags.join(', ')}`);\n\n    if (user.user_fields) {\n      console.log('Custom User Fields:', user.user_fields);\n    }\n\n    return user;\n  } catch (error) {\n    console.error('Error fetching user:', error.message);\n    throw error;\n  }\n}\n\ngetUserProfile(67890);\n```\n\n#### Create User\n\n**Basic Example:**\n\n```javascript\nconst newUser = {\n  name: 'John Doe',\n  email: 'john.doe@example.com',\n  role: 'end-user'\n};\n\nclient.users.create(newUser)\n  .then(user => {\n    console.log('User created successfully!');\n    console.log('User ID:', user.id);\n    console.log('Name:', user.name);\n  })\n  .catch(error => {\n    console.error('Error creating user:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function createAgentUser() {\n  const user = {\n    name: 'Sarah Agent',\n    email: 'sarah.agent@company.com',\n    role: 'agent',\n    phone: '+1-555-123-4567',\n    time_zone: 'America/New_York',\n    locale: 'en-US',\n    verified: true,\n    tags: ['support-team', 'tier-2'],\n    user_fields: {\n      department: 'Technical Support',\n      employee_id: 'EMP-12345'\n    },\n    organization_id: 98765\n  };\n\n  try {\n    const createdUser = await client.users.create(user);\n    console.log('Agent created:', createdUser.id);\n    console.log('Name:', createdUser.name);\n    console.log('Email:', createdUser.email);\n    return createdUser;\n  } catch (error) {\n    console.error('Failed to create user:', error.message);\n    throw error;\n  }\n}\n\ncreateAgentUser();\n```\n\n#### Update User\n\n**Basic Example:**\n\n```javascript\nconst userId = 67890;\nconst updates = {\n  name: 'Jane Smith',\n  phone: '+1-555-999-8888'\n};\n\nclient.users.update(userId, updates)\n  .then(user => {\n    console.log('User updated successfully!');\n    console.log('Name:', user.name);\n    console.log('Phone:', user.phone);\n  })\n  .catch(error => {\n    console.error('Error updating user:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function updateUserProfile(userId) {\n  const updates = {\n    name: 'Jane Smith-Johnson',\n    phone: '+1-555-987-6543',\n    time_zone: 'Pacific/Auckland',\n    locale: 'en-GB',\n    tags: ['vip', 'premium-support'],\n    user_fields: {\n      department: 'Engineering',\n      location: 'Remote'\n    },\n    organization_id: 11111\n  };\n\n  try {\n    const updatedUser = await client.users.update(userId, updates);\n    console.log('User updated:', updatedUser.id);\n    console.log('New name:', updatedUser.name);\n    console.log('New timezone:', updatedUser.time_zone);\n    return updatedUser;\n  } catch (error) {\n    console.error('Failed to update user:', error.message);\n    throw error;\n  }\n}\n\nupdateUserProfile(67890);\n```\n\n#### Delete User\n\n**Basic Example:**\n\n```javascript\nconst userId = 67890;\n\nclient.users.delete(userId)\n  .then(() => {\n    console.log('User deleted successfully');\n  })\n  .catch(error => {\n    console.error('Error deleting user:', error.message);\n  });\n```\n\n#### Search Users\n\n**Basic Example:**\n\n```javascript\nclient.users.search({ query: 'john@example.com' })\n  .then(users => {\n    console.log('Found users:', users.length);\n    users.forEach(user => {\n      console.log(`${user.name} - ${user.email}`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function searchUsersByName(searchTerm) {\n  try {\n    const users = await client.users.search({\n      query: `name:${searchTerm}`\n    });\n\n    console.log(`Found ${users.length} users matching \"${searchTerm}\"`);\n\n    users.forEach(user => {\n      console.log('\\n---');\n      console.log(`ID: ${user.id}`);\n      console.log(`Name: ${user.name}`);\n      console.log(`Email: ${user.email}`);\n      console.log(`Role: ${user.role}`);\n      console.log(`Organization: ${user.organization_id}`);\n    });\n\n    return users;\n  } catch (error) {\n    console.error('Search failed:', error.message);\n    throw error;\n  }\n}\n\nsearchUsersByName('John');\n```\n\n#### Get Current User\n\n**Basic Example:**\n\n```javascript\nclient.users.me()\n  .then(user => {\n    console.log('Current user:', user.name);\n    console.log('Email:', user.email);\n    console.log('Role:', user.role);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n---\n\n### Organizations API\n\n#### List Organizations\n\n**Basic Example:**\n\n```javascript\nclient.organizations.list()\n  .then(organizations => {\n    console.log('Total organizations:', organizations.length);\n    organizations.forEach(org => {\n      console.log(`${org.name} (ID: ${org.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function analyzeOrganizations() {\n  try {\n    const organizations = await client.organizations.list();\n\n    console.log(`Total organizations: ${organizations.length}`);\n\n    organizations.forEach(org => {\n      console.log('\\n=== Organization ===');\n      console.log(`ID: ${org.id}`);\n      console.log(`Name: ${org.name}`);\n      console.log(`Domain Names: ${org.domain_names?.join(', ') || 'None'}`);\n      console.log(`Details: ${org.details || 'N/A'}`);\n      console.log(`Notes: ${org.notes || 'N/A'}`);\n      console.log(`Tags: ${org.tags?.join(', ') || 'None'}`);\n      console.log(`Created: ${org.created_at}`);\n\n      if (org.organization_fields) {\n        console.log('Custom Fields:', org.organization_fields);\n      }\n    });\n\n    return organizations;\n  } catch (error) {\n    console.error('Error fetching organizations:', error.message);\n    throw error;\n  }\n}\n\nanalyzeOrganizations();\n```\n\n#### Show Organization\n\n**Basic Example:**\n\n```javascript\nconst orgId = 98765;\n\nclient.organizations.show(orgId)\n  .then(org => {\n    console.log('Name:', org.name);\n    console.log('Details:', org.details);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function getOrganizationDetails(orgId) {\n  try {\n    const org = await client.organizations.show(orgId);\n\n    console.log('=== Organization Details ===');\n    console.log(`ID: ${org.id}`);\n    console.log(`Name: ${org.name}`);\n    console.log(`Domain Names: ${org.domain_names?.join(', ') || 'None'}`);\n    console.log(`Details: ${org.details || 'N/A'}`);\n    console.log(`Notes: ${org.notes || 'N/A'}`);\n    console.log(`Group ID: ${org.group_id || 'N/A'}`);\n    console.log(`Tags: ${org.tags?.join(', ') || 'None'}`);\n    console.log(`Created: ${org.created_at}`);\n    console.log(`Updated: ${org.updated_at}`);\n\n    if (org.organization_fields) {\n      console.log('\\nCustom Organization Fields:');\n      Object.entries(org.organization_fields).forEach(([key, value]) => {\n        console.log(`  ${key}: ${value}`);\n      });\n    }\n\n    return org;\n  } catch (error) {\n    console.error('Error fetching organization:', error.message);\n    throw error;\n  }\n}\n\ngetOrganizationDetails(98765);\n```\n\n#### Create Organization\n\n**Basic Example:**\n\n```javascript\nconst newOrg = {\n  name: 'Acme Corporation',\n  domain_names: ['acme.com']\n};\n\nclient.organizations.create(newOrg)\n  .then(org => {\n    console.log('Organization created!');\n    console.log('ID:', org.id);\n    console.log('Name:', org.name);\n  })\n  .catch(error => {\n    console.error('Error creating organization:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function createOrganization() {\n  const organization = {\n    name: 'TechStart Solutions Inc.',\n    domain_names: ['techstart.com', 'techstart.io'],\n    details: 'Premium enterprise customer',\n    notes: 'VIP support tier, 24/7 coverage',\n    tags: ['enterprise', 'vip', 'priority-support'],\n    group_id: 12345,\n    organization_fields: {\n      industry: 'Technology',\n      account_tier: 'Enterprise',\n      annual_revenue: '10M+'\n    }\n  };\n\n  try {\n    const createdOrg = await client.organizations.create(organization);\n    console.log('Organization created:', createdOrg.id);\n    console.log('Name:', createdOrg.name);\n    console.log('Domains:', createdOrg.domain_names.join(', '));\n    return createdOrg;\n  } catch (error) {\n    console.error('Failed to create organization:', error.message);\n    throw error;\n  }\n}\n\ncreateOrganization();\n```\n\n#### Update Organization\n\n**Basic Example:**\n\n```javascript\nconst orgId = 98765;\nconst updates = {\n  name: 'Acme Corporation Ltd.',\n  details: 'Updated company details'\n};\n\nclient.organizations.update(orgId, updates)\n  .then(org => {\n    console.log('Organization updated!');\n    console.log('Name:', org.name);\n  })\n  .catch(error => {\n    console.error('Error updating organization:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function updateOrganization(orgId) {\n  const updates = {\n    name: 'Acme Global Corporation',\n    domain_names: ['acme.com', 'acme.global', 'acmeglobal.com'],\n    details: 'Global enterprise customer with multiple subsidiaries',\n    notes: 'Upgraded to platinum tier - assign dedicated account manager',\n    tags: ['enterprise', 'platinum', 'global', 'strategic-account'],\n    organization_fields: {\n      account_tier: 'Platinum',\n      contract_renewal: '2025-12-31',\n      dedicated_support: 'yes'\n    }\n  };\n\n  try {\n    const updatedOrg = await client.organizations.update(orgId, updates);\n    console.log('Organization updated:', updatedOrg.id);\n    console.log('New name:', updatedOrg.name);\n    console.log('Tags:', updatedOrg.tags.join(', '));\n    return updatedOrg;\n  } catch (error) {\n    console.error('Failed to update organization:', error.message);\n    throw error;\n  }\n}\n\nupdateOrganization(98765);\n```\n\n#### Delete Organization\n\n**Basic Example:**\n\n```javascript\nconst orgId = 98765;\n\nclient.organizations.delete(orgId)\n  .then(() => {\n    console.log('Organization deleted successfully');\n  })\n  .catch(error => {\n    console.error('Error deleting organization:', error.message);\n  });\n```\n\n---\n\n### Search API\n\n#### Basic Search\n\n**Basic Example:**\n\n```javascript\nclient.search.query('type:ticket status:open')\n  .then(results => {\n    console.log('Found tickets:', results.length);\n    results.forEach(ticket => {\n      console.log(`#${ticket.id}: ${ticket.subject}`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function searchOpenTickets() {\n  try {\n    const query = 'type:ticket status:open priority:high';\n    const results = await client.search.query(query);\n\n    console.log(`Found ${results.length} high-priority open tickets`);\n\n    results.forEach(ticket => {\n      console.log('\\n---');\n      console.log(`Ticket #${ticket.id}`);\n      console.log(`Subject: ${ticket.subject}`);\n      console.log(`Priority: ${ticket.priority}`);\n      console.log(`Status: ${ticket.status}`);\n      console.log(`Created: ${ticket.created_at}`);\n      console.log(`Assignee: ${ticket.assignee_id || 'Unassigned'}`);\n    });\n\n    return results;\n  } catch (error) {\n    console.error('Search failed:', error.message);\n    throw error;\n  }\n}\n\nsearchOpenTickets();\n```\n\n#### Search Tickets\n\n**Basic Example:**\n\n```javascript\nclient.search.query('type:ticket subject:login')\n  .then(tickets => {\n    console.log('Tickets mentioning \"login\":', tickets.length);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example with Multiple Filters:**\n\n```javascript\nasync function advancedTicketSearch() {\n  const searchParams = {\n    type: 'ticket',\n    status: 'open',\n    priority: 'urgent',\n    tags: 'bug',\n    created_at: '>2025-01-01'\n  };\n\n  // Build query string\n  const query = Object.entries(searchParams)\n    .map(([key, value]) => `${key}:${value}`)\n    .join(' ');\n\n  try {\n    const tickets = await client.search.query(query);\n\n    console.log(`Search Query: ${query}`);\n    console.log(`Results: ${tickets.length} tickets\\n`);\n\n    tickets.forEach(ticket => {\n      console.log(`#${ticket.id}: ${ticket.subject}`);\n      console.log(`  Status: ${ticket.status} | Priority: ${ticket.priority}`);\n      console.log(`  Tags: ${ticket.tags.join(', ')}`);\n      console.log(`  Created: ${ticket.created_at}`);\n    });\n\n    return tickets;\n  } catch (error) {\n    console.error('Search error:', error.message);\n    throw error;\n  }\n}\n\nadvancedTicketSearch();\n```\n\n#### Search Users\n\n**Basic Example:**\n\n```javascript\nclient.search.query('type:user email:*@example.com')\n  .then(users => {\n    console.log('Found users:', users.length);\n    users.forEach(user => {\n      console.log(`${user.name} - ${user.email}`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function findAgentsByOrganization(orgId) {\n  const query = `type:user role:agent organization_id:${orgId}`;\n\n  try {\n    const agents = await client.search.query(query);\n\n    console.log(`Found ${agents.length} agents in organization ${orgId}`);\n\n    agents.forEach(agent => {\n      console.log('\\n---');\n      console.log(`Name: ${agent.name}`);\n      console.log(`Email: ${agent.email}`);\n      console.log(`Role: ${agent.role}`);\n      console.log(`Active: ${agent.active}`);\n      console.log(`Last Login: ${agent.last_login_at || 'Never'}`);\n    });\n\n    return agents;\n  } catch (error) {\n    console.error('User search failed:', error.message);\n    throw error;\n  }\n}\n\nfindAgentsByOrganization(98765);\n```\n\n#### Search Organizations\n\n**Basic Example:**\n\n```javascript\nclient.search.query('type:organization name:Acme')\n  .then(orgs => {\n    console.log('Found organizations:', orgs.length);\n    orgs.forEach(org => {\n      console.log(`${org.name} (ID: ${org.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function searchOrganizationsByDomain(domain) {\n  const query = `type:organization ${domain}`;\n\n  try {\n    const organizations = await client.search.query(query);\n\n    console.log(`Found ${organizations.length} organizations with domain \"${domain}\"`);\n\n    organizations.forEach(org => {\n      console.log('\\n=== Organization ===');\n      console.log(`ID: ${org.id}`);\n      console.log(`Name: ${org.name}`);\n      console.log(`Domains: ${org.domain_names?.join(', ') || 'None'}`);\n      console.log(`Details: ${org.details || 'N/A'}`);\n      console.log(`Created: ${org.created_at}`);\n    });\n\n    return organizations;\n  } catch (error) {\n    console.error('Organization search failed:', error.message);\n    throw error;\n  }\n}\n\nsearchOrganizationsByDomain('acme.com');\n```\n\n---\n\n### Groups API\n\n#### List Groups\n\n**Basic Example:**\n\n```javascript\nclient.groups.list()\n  .then(groups => {\n    console.log('Total groups:', groups.length);\n    groups.forEach(group => {\n      console.log(`${group.name} (ID: ${group.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listAllGroups() {\n  try {\n    const groups = await client.groups.list();\n\n    console.log(`Found ${groups.length} groups\\n`);\n\n    groups.forEach(group => {\n      console.log('=== Group ===');\n      console.log(`ID: ${group.id}`);\n      console.log(`Name: ${group.name}`);\n      console.log(`Description: ${group.description || 'N/A'}`);\n      console.log(`Created: ${group.created_at}`);\n      console.log(`Updated: ${group.updated_at}`);\n      console.log('---');\n    });\n\n    return groups;\n  } catch (error) {\n    console.error('Error fetching groups:', error.message);\n    throw error;\n  }\n}\n\nlistAllGroups();\n```\n\n#### Show Group\n\n**Basic Example:**\n\n```javascript\nconst groupId = 12345;\n\nclient.groups.show(groupId)\n  .then(group => {\n    console.log('Group:', group.name);\n    console.log('Description:', group.description);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n#### Create Group\n\n**Basic Example:**\n\n```javascript\nconst newGroup = {\n  name: 'Technical Support Team'\n};\n\nclient.groups.create(newGroup)\n  .then(group => {\n    console.log('Group created!');\n    console.log('ID:', group.id);\n    console.log('Name:', group.name);\n  })\n  .catch(error => {\n    console.error('Error creating group:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function createSupportGroup() {\n  const group = {\n    name: 'Enterprise Support Team',\n    description: 'Dedicated support team for enterprise customers'\n  };\n\n  try {\n    const createdGroup = await client.groups.create(group);\n    console.log('Group created:', createdGroup.id);\n    console.log('Name:', createdGroup.name);\n    console.log('Description:', createdGroup.description);\n    return createdGroup;\n  } catch (error) {\n    console.error('Failed to create group:', error.message);\n    throw error;\n  }\n}\n\ncreateSupportGroup();\n```\n\n#### Update Group\n\n**Basic Example:**\n\n```javascript\nconst groupId = 12345;\nconst updates = {\n  name: 'Updated Group Name',\n  description: 'Updated description'\n};\n\nclient.groups.update(groupId, updates)\n  .then(group => {\n    console.log('Group updated!');\n    console.log('Name:', group.name);\n  })\n  .catch(error => {\n    console.error('Error updating group:', error.message);\n  });\n```\n\n#### Delete Group\n\n**Basic Example:**\n\n```javascript\nconst groupId = 12345;\n\nclient.groups.delete(groupId)\n  .then(() => {\n    console.log('Group deleted successfully');\n  })\n  .catch(error => {\n    console.error('Error deleting group:', error.message);\n  });\n```\n\n---\n\n### Attachments API\n\n#### Upload Attachment\n\n**Basic Example:**\n\n```javascript\nconst fs = require('fs');\nconst path = require('path');\n\nconst filePath = path.resolve('./documents/file.pdf');\n\nclient.attachments.upload(filePath, { filename: 'file.pdf' })\n  .then(upload => {\n    console.log('File uploaded successfully!');\n    console.log('Upload token:', upload.token);\n    console.log('Attachment:', upload.attachment);\n  })\n  .catch(error => {\n    console.error('Error uploading file:', error.message);\n  });\n```\n\n**Advanced Example with Ticket Creation:**\n\n```javascript\nconst fs = require('fs');\nconst path = require('path');\n\nasync function createTicketWithAttachment() {\n  try {\n    // Step 1: Upload the file\n    const filePath = path.resolve('./screenshots/bug-screenshot.png');\n    const upload = await client.attachments.upload(filePath, {\n      filename: 'bug-screenshot.png'\n    });\n\n    console.log('File uploaded. Token:', upload.token);\n\n    // Step 2: Create ticket with attachment\n    const ticket = {\n      subject: 'Bug Report: UI Issue',\n      comment: {\n        body: 'Please see the attached screenshot showing the UI bug.',\n        uploads: [upload.token]  // Reference the upload token\n      },\n      requester: {\n        name: 'Bug Reporter',\n        email: 'reporter@example.com'\n      },\n      priority: 'high',\n      tags: ['bug', 'ui']\n    };\n\n    const createdTicket = await client.tickets.create(ticket);\n\n    console.log('Ticket created with attachment!');\n    console.log('Ticket ID:', createdTicket.id);\n    console.log('Subject:', createdTicket.subject);\n\n    return createdTicket;\n  } catch (error) {\n    console.error('Error:', error.message);\n    throw error;\n  }\n}\n\ncreateTicketWithAttachment();\n```\n\n#### Upload Multiple Attachments\n\n**Advanced Example:**\n\n```javascript\nconst fs = require('fs');\nconst path = require('path');\n\nasync function createTicketWithMultipleAttachments() {\n  try {\n    // Upload multiple files\n    const files = [\n      './documents/report.pdf',\n      './screenshots/screen1.png',\n      './screenshots/screen2.png'\n    ];\n\n    const uploadPromises = files.map(file => {\n      const filePath = path.resolve(file);\n      const filename = path.basename(file);\n      return client.attachments.upload(filePath, { filename });\n    });\n\n    const uploads = await Promise.all(uploadPromises);\n    const tokens = uploads.map(u => u.token);\n\n    console.log(`Uploaded ${tokens.length} files`);\n\n    // Create ticket with all attachments\n    const ticket = {\n      subject: 'Detailed Bug Report',\n      comment: {\n        body: 'Please find the attached report and screenshots.',\n        uploads: tokens\n      },\n      requester: {\n        name: 'QA Tester',\n        email: 'qa@example.com'\n      },\n      priority: 'normal'\n    };\n\n    const createdTicket = await client.tickets.create(ticket);\n\n    console.log('Ticket created with multiple attachments!');\n    console.log('Ticket ID:', createdTicket.id);\n\n    return createdTicket;\n  } catch (error) {\n    console.error('Error:', error.message);\n    throw error;\n  }\n}\n\ncreateTicketWithMultipleAttachments();\n```\n\n#### Show Attachment\n\n**Basic Example:**\n\n```javascript\nconst attachmentId = 123456789;\n\nclient.attachments.show(attachmentId)\n  .then(attachment => {\n    console.log('Filename:', attachment.file_name);\n    console.log('Size:', attachment.size, 'bytes');\n    console.log('Content Type:', attachment.content_type);\n    console.log('URL:', attachment.content_url);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n#### Delete Attachment Upload\n\n**Basic Example:**\n\n```javascript\nconst uploadToken = 'upload_token_here';\n\nclient.attachments.deleteUpload(uploadToken)\n  .then(() => {\n    console.log('Upload deleted successfully');\n  })\n  .catch(error => {\n    console.error('Error deleting upload:', error.message);\n  });\n```\n\n---\n\n### Macros API\n\n#### List Macros\n\n**Basic Example:**\n\n```javascript\nclient.macros.list()\n  .then(macros => {\n    console.log('Total macros:', macros.length);\n    macros.forEach(macro => {\n      console.log(`${macro.title} (ID: ${macro.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listActiveMacros() {\n  try {\n    const macros = await client.macros.list();\n\n    const activeMacros = macros.filter(m => m.active);\n\n    console.log(`Found ${activeMacros.length} active macros\\n`);\n\n    activeMacros.forEach(macro => {\n      console.log('=== Macro ===');\n      console.log(`ID: ${macro.id}`);\n      console.log(`Title: ${macro.title}`);\n      console.log(`Description: ${macro.description || 'N/A'}`);\n      console.log(`Active: ${macro.active}`);\n      console.log(`Created: ${macro.created_at}`);\n      console.log('---');\n    });\n\n    return activeMacros;\n  } catch (error) {\n    console.error('Error fetching macros:', error.message);\n    throw error;\n  }\n}\n\nlistActiveMacros();\n```\n\n#### Show Macro\n\n**Basic Example:**\n\n```javascript\nconst macroId = 54321;\n\nclient.macros.show(macroId)\n  .then(macro => {\n    console.log('Title:', macro.title);\n    console.log('Description:', macro.description);\n    console.log('Actions:', macro.actions);\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n#### Apply Macro to Ticket\n\n**Advanced Example:**\n\n```javascript\nasync function applyMacroToTicket(ticketId, macroId) {\n  try {\n    const result = await client.macros.applyTicket(ticketId, macroId);\n\n    console.log('Macro applied successfully!');\n    console.log('Result:', result);\n\n    // Update the ticket with the macro's changes\n    const updates = result.ticket;\n    const updatedTicket = await client.tickets.update(ticketId, updates);\n\n    console.log('Ticket updated with macro actions');\n    console.log('New status:', updatedTicket.status);\n\n    return updatedTicket;\n  } catch (error) {\n    console.error('Error applying macro:', error.message);\n    throw error;\n  }\n}\n\napplyMacroToTicket(12345, 54321);\n```\n\n---\n\n### Views API\n\n#### List Views\n\n**Basic Example:**\n\n```javascript\nclient.views.list()\n  .then(views => {\n    console.log('Total views:', views.length);\n    views.forEach(view => {\n      console.log(`${view.title} (ID: ${view.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listActiveViews() {\n  try {\n    const views = await client.views.list();\n\n    const activeViews = views.filter(v => v.active);\n\n    console.log(`Found ${activeViews.length} active views\\n`);\n\n    activeViews.forEach(view => {\n      console.log('=== View ===');\n      console.log(`ID: ${view.id}`);\n      console.log(`Title: ${view.title}`);\n      console.log(`Description: ${view.description || 'N/A'}`);\n      console.log(`Active: ${view.active}`);\n      console.log(`Position: ${view.position}`);\n      console.log('---');\n    });\n\n    return activeViews;\n  } catch (error) {\n    console.error('Error fetching views:', error.message);\n    throw error;\n  }\n}\n\nlistActiveViews();\n```\n\n#### Execute View\n\n**Basic Example:**\n\n```javascript\nconst viewId = 11111;\n\nclient.views.execute(viewId)\n  .then(result => {\n    console.log('View executed!');\n    console.log('Tickets:', result.rows.length);\n    result.rows.forEach(ticket => {\n      console.log(`#${ticket.id}: ${ticket.subject}`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function executeViewAndAnalyze(viewId) {\n  try {\n    const result = await client.views.execute(viewId);\n\n    console.log('=== View Execution Results ===');\n    console.log(`Total tickets: ${result.rows.length}`);\n    console.log(`Columns: ${result.columns.map(c => c.title).join(', ')}`);\n\n    // Analyze ticket statuses\n    const statusCounts = {};\n    result.rows.forEach(ticket => {\n      const status = ticket.status;\n      statusCounts[status] = (statusCounts[status] || 0) + 1;\n    });\n\n    console.log('\\n=== Status Distribution ===');\n    Object.entries(statusCounts).forEach(([status, count]) => {\n      console.log(`${status}: ${count}`);\n    });\n\n    // Show first 10 tickets\n    console.log('\\n=== Tickets ===');\n    result.rows.slice(0, 10).forEach(ticket => {\n      console.log(`#${ticket.id}: ${ticket.subject}`);\n      console.log(`  Status: ${ticket.status} | Priority: ${ticket.priority}`);\n    });\n\n    return result;\n  } catch (error) {\n    console.error('Error executing view:', error.message);\n    throw error;\n  }\n}\n\nexecuteViewAndAnalyze(11111);\n```\n\n---\n\n### Triggers API\n\n#### List Triggers\n\n**Basic Example:**\n\n```javascript\nclient.triggers.list()\n  .then(triggers => {\n    console.log('Total triggers:', triggers.length);\n    triggers.forEach(trigger => {\n      console.log(`${trigger.title} (ID: ${trigger.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listActiveTriggers() {\n  try {\n    const triggers = await client.triggers.list();\n\n    const activeTriggers = triggers.filter(t => t.active);\n\n    console.log(`Found ${activeTriggers.length} active triggers\\n`);\n\n    activeTriggers.forEach(trigger => {\n      console.log('=== Trigger ===');\n      console.log(`ID: ${trigger.id}`);\n      console.log(`Title: ${trigger.title}`);\n      console.log(`Description: ${trigger.description || 'N/A'}`);\n      console.log(`Active: ${trigger.active}`);\n      console.log(`Position: ${trigger.position}`);\n      console.log(`Conditions:`, JSON.stringify(trigger.conditions, null, 2));\n      console.log(`Actions:`, JSON.stringify(trigger.actions, null, 2));\n      console.log('---');\n    });\n\n    return activeTriggers;\n  } catch (error) {\n    console.error('Error fetching triggers:', error.message);\n    throw error;\n  }\n}\n\nlistActiveTriggers();\n```\n\n---\n\n### Automations API\n\n#### List Automations\n\n**Basic Example:**\n\n```javascript\nclient.automations.list()\n  .then(automations => {\n    console.log('Total automations:', automations.length);\n    automations.forEach(automation => {\n      console.log(`${automation.title} (ID: ${automation.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listActiveAutomations() {\n  try {\n    const automations = await client.automations.list();\n\n    const activeAutomations = automations.filter(a => a.active);\n\n    console.log(`Found ${activeAutomations.length} active automations\\n`);\n\n    activeAutomations.forEach(automation => {\n      console.log('=== Automation ===');\n      console.log(`ID: ${automation.id}`);\n      console.log(`Title: ${automation.title}`);\n      console.log(`Active: ${automation.active}`);\n      console.log(`Position: ${automation.position}`);\n      console.log(`Conditions:`, JSON.stringify(automation.conditions, null, 2));\n      console.log(`Actions:`, JSON.stringify(automation.actions, null, 2));\n      console.log('---');\n    });\n\n    return activeAutomations;\n  } catch (error) {\n    console.error('Error fetching automations:', error.message);\n    throw error;\n  }\n}\n\nlistActiveAutomations();\n```\n\n---\n\n### Brands API\n\n#### List Brands\n\n**Basic Example:**\n\n```javascript\nclient.brands.list()\n  .then(brands => {\n    console.log('Total brands:', brands.length);\n    brands.forEach(brand => {\n      console.log(`${brand.name} (ID: ${brand.id})`);\n    });\n  })\n  .catch(error => {\n    console.error('Error:', error.message);\n  });\n```\n\n**Advanced Example:**\n\n```javascript\nasync function listAllBrands() {\n  try {\n    const brands = await client.brands.list();\n\n    console.log(`Found ${brands.length} brands\\n`);\n\n    brands.forEach(brand => {\n      console.log('=== Brand ===');\n      console.log(`ID: ${brand.id}`);\n      console.log(`Name: ${brand.name}`);\n      console.log(`Subdomain: ${brand.subdomain}`);\n      console.log(`Host Mapping: ${brand.host_mapping || 'N/A'}`);\n      console.log(`Active: ${brand.active}`);\n      console.log(`Default: ${brand.default}`);\n      console.log(`Created: ${brand.created_at}`);\n      console.log('---');\n    });\n\n    return brands;\n  } catch (error) {\n    console.error('Error fetching brands:', error.message);\n    throw error;\n  }\n}\n\nlistAllBrands();\n```\n\n---\n\n## Error Handling\n\n### Basic Error Handling\n\n```javascript\nclient.tickets.show(99999)\n  .then(ticket => {\n    console.log('Ticket:', ticket.subject);\n  })\n  .catch(error => {\n    console.error('Error occurred:', error.message);\n    console.error('Status code:', error.statusCode);\n  });\n```\n\n### Advanced Error Handling\n\n```javascript\nasync function handleZendeskErrors() {\n  try {\n    const ticket = await client.tickets.show(99999);\n    return ticket;\n  } catch (error) {\n    // Check error type\n    if (error.statusCode === 404) {\n      console.error('Ticket not found');\n    } else if (error.statusCode === 401) {\n      console.error('Authentication failed - check credentials');\n    } else if (error.statusCode === 403) {\n      console.error('Forbidden - insufficient permissions');\n    } else if (error.statusCode === 429) {\n      console.error('Rate limit exceeded - retry after:', error.retry);\n    } else if (error.statusCode >= 500) {\n      console.error('Zendesk server error - try again later');\n    } else {\n      console.error('Unknown error:', error.message);\n    }\n\n    // Log full error details\n    console.error('Error details:', {\n      statusCode: error.statusCode,\n      message: error.message,\n      stack: error.stack\n    });\n\n    throw error;\n  }\n}\n```\n\n### Retry Logic\n\n```javascript\nasync function fetchTicketWithRetry(ticketId, maxRetries = 3) {\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      const ticket = await client.tickets.show(ticketId);\n      return ticket;\n    } catch (error) {\n      if (error.statusCode === 429 && attempt < maxRetries) {\n        // Rate limited - wait and retry\n        const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff\n        console.log(`Rate limited. Retrying in ${waitTime}ms...`);\n        await new Promise(resolve => setTimeout(resolve, waitTime));\n      } else if (attempt === maxRetries) {\n        console.error(`Failed after ${maxRetries} attempts`);\n        throw error;\n      } else if (error.statusCode >= 500 && attempt < maxRetries) {\n        // Server error - retry\n        console.log(`Server error. Attempt ${attempt}/${maxRetries}`);\n        await new Promise(resolve => setTimeout(resolve, 1000));\n      } else {\n        throw error;\n      }\n    }\n  }\n}\n```\n\n---\n\n## Complete Working Examples\n\n### Basic Support Ticket System\n\n```javascript\nrequire('dotenv').config();\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN\n});\n\nasync function createSupportTicket(customerEmail, subject, description) {\n  try {\n    // Check if user exists\n    let user;\n    const users = await client.users.search({ query: customerEmail });\n\n    if (users.length > 0) {\n      user = users[0];\n      console.log('Found existing user:', user.name);\n    } else {\n      // Create new user\n      user = await client.users.create({\n        name: customerEmail.split('@')[0],\n        email: customerEmail,\n        role: 'end-user'\n      });\n      console.log('Created new user:', user.name);\n    }\n\n    // Create ticket\n    const ticket = await client.tickets.create({\n      subject: subject,\n      comment: {\n        body: description\n      },\n      requester_id: user.id,\n      priority: 'normal',\n      status: 'new'\n    });\n\n    console.log('Ticket created successfully!');\n    console.log('Ticket ID:', ticket.id);\n    console.log('Subject:', ticket.subject);\n\n    return ticket;\n  } catch (error) {\n    console.error('Error creating support ticket:', error.message);\n    throw error;\n  }\n}\n\n// Usage\ncreateSupportTicket(\n  'customer@example.com',\n  'Cannot access my account',\n  'I am unable to log into my account. I keep getting an error message.'\n);\n```\n\n### Ticket Management Dashboard\n\n```javascript\nrequire('dotenv').config();\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN\n});\n\nasync function getDashboardStats() {\n  try {\n    // Search for different ticket categories\n    const openTickets = await client.search.query('type:ticket status:open');\n    const pendingTickets = await client.search.query('type:ticket status:pending');\n    const solvedTickets = await client.search.query('type:ticket status:solved created>2025-01-01');\n    const urgentTickets = await client.search.query('type:ticket priority:urgent status<solved');\n\n    console.log('=== Support Dashboard ===');\n    console.log(`Open Tickets: ${openTickets.length}`);\n    console.log(`Pending Tickets: ${pendingTickets.length}`);\n    console.log(`Solved This Year: ${solvedTickets.length}`);\n    console.log(`Urgent Tickets: ${urgentTickets.length}`);\n\n    // List urgent tickets\n    if (urgentTickets.length > 0) {\n      console.log('\\n=== Urgent Tickets Requiring Attention ===');\n      urgentTickets.forEach(ticket => {\n        console.log(`#${ticket.id}: ${ticket.subject}`);\n        console.log(`  Status: ${ticket.status} | Created: ${ticket.created_at}`);\n        console.log(`  Assignee: ${ticket.assignee_id || 'Unassigned'}`);\n      });\n    }\n\n    return {\n      open: openTickets.length,\n      pending: pendingTickets.length,\n      solved: solvedTickets.length,\n      urgent: urgentTickets.length\n    };\n  } catch (error) {\n    console.error('Error fetching dashboard stats:', error.message);\n    throw error;\n  }\n}\n\ngetDashboardStats();\n```\n\n### Bulk Ticket Operations\n\n```javascript\nrequire('dotenv').config();\nconst zendesk = require('node-zendesk');\n\nconst client = zendesk.createClient({\n  username: process.env.ZENDESK_USERNAME,\n  token: process.env.ZENDESK_API_TOKEN,\n  subdomain: process.env.ZENDESK_SUBDOMAIN\n});\n\nasync function bulkUpdateTickets(ticketIds, updates) {\n  try {\n    console.log(`Updating ${ticketIds.length} tickets...`);\n\n    const updatePromises = ticketIds.map(async (ticketId) => {\n      try {\n        const ticket = await client.tickets.update(ticketId, updates);\n        console.log(`✓ Updated ticket #${ticketId}`);\n        return { success: true, ticketId, ticket };\n      } catch (error) {\n        console.error(`✗ Failed to update ticket #${ticketId}:`, error.message);\n        return { success: false, ticketId, error: error.message };\n      }\n    });\n\n    const results = await Promise.all(updatePromises);\n\n    const successful = results.filter(r => r.success).length;\n    const failed = results.filter(r => !r.success).length;\n\n    console.log(`\\n=== Bulk Update Complete ===`);\n    console.log(`Successful: ${successful}`);\n    console.log(`Failed: ${failed}`);\n\n    return results;\n  } catch (error) {\n    console.error('Bulk update error:', error.message);\n    throw error;\n  }\n}\n\n// Usage: Close multiple tickets at once\nconst ticketIds = [12345, 12346, 12347];\nconst updates = {\n  status: 'solved',\n  comment: {\n    body: 'This ticket has been resolved and closed.',\n    public: false\n  }\n};\n\nbulkUpdateTickets(ticketIds, updates);\n```\n"
  },
  {
    "path": "content/zendesk/docs/support/python/DOC.md",
    "content": "---\nname: support\ndescription: \"Zendesk API Python SDK (zenpy) for helpdesk, tickets, and customer service integration\"\nmetadata:\n  languages: \"python\"\n  versions: \"2.0.56\"\n  updated-on: \"2026-03-02\"\n  source: maintainer\n  tags: \"zendesk,support,helpdesk,tickets,customer-service\"\n---\n\n# Zendesk API - Python SDK (zenpy)\n\n## Golden Rule\n\n**ALWAYS use the `zenpy` package (version 2.0.56 or later) for Zendesk API integration in Python projects.**\n\n```bash\npip install zenpy\n```\n\n**DO NOT use:**\n- `zend esk` (typo/incorrect package)\n- `python-zendesk` (outdated)\n- `@zendesk/client` (JavaScript package)\n- Direct HTTP requests to Zendesk API endpoints (use the SDK instead)\n\nThe `zenpy` library is the officially recommended and most actively maintained Python client for the Zendesk API, providing a clean, Pythonic interface for interacting with Zendesk Support, Chat, and Help Center APIs.\n\n---\n\n## Installation\n\n```bash\npip install zenpy\n```\n\nFor development or testing:\n\n```bash\npip install zenpy[dev]\n```\n\nWith requirements.txt:\n\n```txt\nzenpy>=2.0.56\n```\n\nWith Poetry:\n\n```bash\npoetry add zenpy\n```\n\n---\n\n## Authentication & Initialization\n\n### API Token Authentication (Recommended)\n\nThe most common authentication method uses email, API token, and subdomain:\n\n```python\nfrom zenpy import Zenpy\n\n# Credentials dictionary\ncredentials = {\n    'email': 'your_email@example.com',\n    'token': 'your_api_token',\n    'subdomain': 'your_subdomain'\n}\n\n# Create Zenpy client\nzenpy_client = Zenpy(**credentials)\n```\n\n**Environment Variables Example:**\n\n```python\nimport os\nfrom zenpy import Zenpy\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ncredentials = {\n    'email': os.getenv('ZENDESK_EMAIL'),\n    'token': os.getenv('ZENDESK_API_TOKEN'),\n    'subdomain': os.getenv('ZENDESK_SUBDOMAIN')\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n**.env file:**\n\n```\nZENDESK_EMAIL=your_email@example.com\nZENDESK_API_TOKEN=your_api_token_here\nZENDESK_SUBDOMAIN=your_company\n```\n\n### OAuth Token Authentication\n\nFor OAuth-based authentication:\n\n```python\nfrom zenpy import Zenpy\n\ncredentials = {\n    'email': 'your_email@example.com',\n    'oauth_token': 'your_oauth_access_token',\n    'subdomain': 'your_subdomain'\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n**With Environment Variables:**\n\n```python\nimport os\nfrom zenpy import Zenpy\n\ncredentials = {\n    'email': os.getenv('ZENDESK_EMAIL'),\n    'oauth_token': os.getenv('ZENDESK_OAUTH_TOKEN'),\n    'subdomain': os.getenv('ZENDESK_SUBDOMAIN')\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n### Password Authentication (Not Recommended)\n\n```python\nfrom zenpy import Zenpy\n\ncredentials = {\n    'email': 'your_email@example.com',\n    'password': 'your_password',\n    'subdomain': 'your_subdomain'\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n**Note:** Password authentication is deprecated and should be avoided. Use API token or OAuth authentication instead.\n\n### Custom Configuration\n\n```python\nfrom zenpy import Zenpy\n\ncredentials = {\n    'email': 'your_email@example.com',\n    'token': 'your_api_token',\n    'subdomain': 'your_subdomain',\n    'timeout': 60,  # Request timeout in seconds\n    'ratelimit': 700,  # API rate limit (requests per minute)\n    'session': custom_session  # Optional: custom requests.Session object\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n---\n\n## Core API Surfaces\n\n### Tickets API\n\n#### List All Tickets\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\n# Initialize client\nzenpy_client = Zenpy(**credentials)\n\n# List all tickets\nfor ticket in zenpy_client.tickets():\n    print(f\"#{ticket.id}: {ticket.subject}\")\n    print(f\"Status: {ticket.status}, Priority: {ticket.priority}\")\n    print(\"---\")\n```\n\n**Advanced Example with Filtering:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef list_open_tickets():\n    \"\"\"List all open tickets with details\"\"\"\n    open_tickets = []\n\n    for ticket in zenpy_client.tickets():\n        if ticket.status == 'open':\n            print(f\"Ticket #{ticket.id}\")\n            print(f\"Subject: {ticket.subject}\")\n            print(f\"Status: {ticket.status}\")\n            print(f\"Priority: {ticket.priority}\")\n            print(f\"Requester: {ticket.requester.name}\")\n            print(f\"Created: {ticket.created_at}\")\n            print(\"---\")\n            open_tickets.append(ticket)\n\n    print(f\"\\nTotal open tickets: {len(open_tickets)}\")\n    return open_tickets\n\nlist_open_tickets()\n```\n\n#### Show Single Ticket\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a single ticket by ID\nticket_id = 12345\nticket = zenpy_client.tickets(id=ticket_id)\n\nprint(f\"Subject: {ticket.subject}\")\nprint(f\"Status: {ticket.status}\")\nprint(f\"Requester: {ticket.requester.name}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef get_ticket_details(ticket_id):\n    \"\"\"Get comprehensive ticket details\"\"\"\n    try:\n        ticket = zenpy_client.tickets(id=ticket_id)\n\n        print(\"=== Ticket Details ===\")\n        print(f\"ID: {ticket.id}\")\n        print(f\"Subject: {ticket.subject}\")\n        print(f\"Description: {ticket.description}\")\n        print(f\"Status: {ticket.status}\")\n        print(f\"Priority: {ticket.priority}\")\n        print(f\"Type: {ticket.type}\")\n        print(f\"Requester: {ticket.requester.name} ({ticket.requester.email})\")\n\n        if ticket.assignee:\n            print(f\"Assignee: {ticket.assignee.name}\")\n        else:\n            print(\"Assignee: Unassigned\")\n\n        if ticket.group:\n            print(f\"Group: {ticket.group.name}\")\n\n        print(f\"Created: {ticket.created_at}\")\n        print(f\"Updated: {ticket.updated_at}\")\n        print(f\"Tags: {', '.join(ticket.tags)}\")\n\n        # Custom fields\n        if ticket.custom_fields:\n            print(\"\\nCustom Fields:\")\n            for field in ticket.custom_fields:\n                print(f\"  {field.id}: {field.value}\")\n\n        return ticket\n\n    except Exception as e:\n        print(f\"Error fetching ticket: {e}\")\n        return None\n\nget_ticket_details(12345)\n```\n\n#### Create Ticket\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket, Comment\n\nzenpy_client = Zenpy(**credentials)\n\n# Create a new ticket\nticket = Ticket(\n    subject=\"Help with product installation\",\n    description=\"I need assistance installing the product on my system.\"\n)\n\ncreated_ticket = zenpy_client.tickets.create(ticket)\n\nprint(\"Ticket created successfully!\")\nprint(f\"Ticket ID: {created_ticket.id}\")\nprint(f\"Subject: {created_ticket.subject}\")\n```\n\n**Advanced Example with Custom Fields:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket, User, Comment, CustomField\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_detailed_ticket():\n    \"\"\"Create a ticket with all details\"\"\"\n\n    # Create ticket with requester\n    ticket = Ticket(\n        subject=\"Technical Support Request\",\n        description=\"Detailed description of the issue...\\n\\nSteps to reproduce:\\n1. Step one\\n2. Step two\",\n        requester=User(\n            name=\"Jane Smith\",\n            email=\"jane.smith@example.com\"\n        ),\n        priority=\"high\",\n        status=\"open\",\n        type=\"problem\",\n        tags=[\"technical\", \"urgent\", \"product-bug\"],\n        custom_fields=[\n            CustomField(id=12345, value=\"Custom value 1\"),\n            CustomField(id=67890, value=\"Custom value 2\")\n        ]\n    )\n\n    # Create the ticket\n    created_ticket = zenpy_client.tickets.create(ticket)\n\n    print(f\"Ticket created: {created_ticket.id}\")\n    print(f\"Subject: {created_ticket.subject}\")\n    print(f\"Requester: {created_ticket.requester.name}\")\n\n    return created_ticket\n\ncreate_detailed_ticket()\n```\n\n**Create Ticket with Existing User:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_ticket_for_user(user_id, subject, description):\n    \"\"\"Create ticket for an existing user\"\"\"\n\n    ticket = Ticket(\n        subject=subject,\n        description=description,\n        requester_id=user_id,\n        priority=\"normal\",\n        status=\"new\"\n    )\n\n    created_ticket = zenpy_client.tickets.create(ticket)\n    print(f\"Ticket {created_ticket.id} created for user {user_id}\")\n\n    return created_ticket\n\ncreate_ticket_for_user(67890, \"Account Issue\", \"Cannot access account\")\n```\n\n#### Update Ticket\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get the ticket\nticket_id = 12345\nticket = zenpy_client.tickets(id=ticket_id)\n\n# Update ticket status\nticket.status = \"solved\"\nticket.comment = \"This issue has been resolved.\"\n\n# Save changes\nupdated_ticket = zenpy_client.tickets.update(ticket)\n\nprint(\"Ticket updated successfully!\")\nprint(f\"New status: {updated_ticket.status}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Comment\n\nzenpy_client = Zenpy(**credentials)\n\ndef update_ticket_with_comment(ticket_id):\n    \"\"\"Update ticket with detailed changes\"\"\"\n\n    # Get the ticket\n    ticket = zenpy_client.tickets(id=ticket_id)\n\n    # Update multiple fields\n    ticket.status = \"pending\"\n    ticket.priority = \"high\"\n    ticket.tags.extend([\"escalated\", \"requires-attention\"])\n\n    # Add internal comment\n    ticket.comment = Comment(\n        body=\"This ticket has been escalated to senior support.\",\n        public=False\n    )\n\n    # Update custom fields\n    from zenpy.lib.api_objects import CustomField\n    ticket.custom_fields = [\n        CustomField(id=11111, value=\"Updated value\")\n    ]\n\n    # Save changes\n    updated_ticket = zenpy_client.tickets.update(ticket)\n\n    print(f\"Ticket updated: {updated_ticket.id}\")\n    print(f\"New status: {updated_ticket.status}\")\n    print(f\"New priority: {updated_ticket.priority}\")\n\n    return updated_ticket\n\nupdate_ticket_with_comment(12345)\n```\n\n**Update Ticket Status:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef close_ticket(ticket_id):\n    \"\"\"Close a ticket with a resolution comment\"\"\"\n\n    ticket = zenpy_client.tickets(id=ticket_id)\n    ticket.status = \"solved\"\n    ticket.comment = \"This ticket has been resolved and closed.\"\n\n    updated_ticket = zenpy_client.tickets.update(ticket)\n    print(f\"Ticket {ticket_id} closed successfully\")\n\n    return updated_ticket\n\nclose_ticket(12345)\n```\n\n#### Delete Ticket\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Delete a ticket\nticket_id = 12345\nzenpy_client.tickets.delete(ticket_id)\n\nprint(f\"Ticket {ticket_id} deleted successfully\")\n```\n\n**Advanced Example with Confirmation:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef delete_ticket_safely(ticket_id):\n    \"\"\"Delete a ticket with verification\"\"\"\n\n    try:\n        # First, verify the ticket exists\n        ticket = zenpy_client.tickets(id=ticket_id)\n        print(f\"About to delete ticket #{ticket.id}: {ticket.subject}\")\n\n        # Delete the ticket\n        zenpy_client.tickets.delete(ticket_id)\n        print(\"Ticket deleted successfully\")\n\n        return True\n\n    except Exception as e:\n        print(f\"Error deleting ticket: {e}\")\n        return False\n\ndelete_ticket_safely(12345)\n```\n\n#### List Ticket Comments\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get ticket comments\nticket_id = 12345\ncomments = zenpy_client.tickets.comments(ticket_id)\n\nfor comment in comments:\n    print(f\"Author ID: {comment.author_id}\")\n    print(f\"Body: {comment.body}\")\n    print(f\"Public: {comment.public}\")\n    print(\"---\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef analyze_ticket_conversation(ticket_id):\n    \"\"\"Analyze ticket conversation history\"\"\"\n\n    try:\n        comments = list(zenpy_client.tickets.comments(ticket_id))\n\n        public_comments = [c for c in comments if c.public]\n        private_comments = [c for c in comments if not c.public]\n\n        print(\"=== Ticket Conversation Analysis ===\")\n        print(f\"Total comments: {len(comments)}\")\n        print(f\"Public comments: {len(public_comments)}\")\n        print(f\"Private/Internal notes: {len(private_comments)}\")\n\n        print(\"\\n=== Comment History ===\")\n        for i, comment in enumerate(comments, 1):\n            print(f\"\\n[Comment {i}]\")\n            print(f\"ID: {comment.id}\")\n            print(f\"Author ID: {comment.author_id}\")\n            print(f\"Created: {comment.created_at}\")\n            print(f\"Type: {'Public' if comment.public else 'Internal'}\")\n            print(f\"Body: {comment.body[:100]}...\")\n\n            if hasattr(comment, 'attachments') and comment.attachments:\n                print(\"Attachments:\")\n                for att in comment.attachments:\n                    print(f\"  - {att.file_name} ({att.size} bytes)\")\n\n        return comments\n\n    except Exception as e:\n        print(f\"Error fetching comments: {e}\")\n        return None\n\nanalyze_ticket_conversation(12345)\n```\n\n---\n\n### Users API\n\n#### List Users\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# List all users\nfor user in zenpy_client.users():\n    print(f\"{user.name} ({user.email})\")\n```\n\n**Advanced Example with Filtering:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef list_active_agents():\n    \"\"\"List all active agents\"\"\"\n\n    agents = []\n\n    for user in zenpy_client.users():\n        if user.role == 'agent' and user.active:\n            print(f\"\\nName: {user.name}\")\n            print(f\"Email: {user.email}\")\n            print(f\"Role: {user.role}\")\n            print(f\"Timezone: {user.time_zone}\")\n            print(f\"Locale: {user.locale}\")\n\n            if user.last_login_at:\n                print(f\"Last Login: {user.last_login_at}\")\n\n            agents.append(user)\n\n    print(f\"\\nFound {len(agents)} active agents\")\n    return agents\n\nlist_active_agents()\n```\n\n#### Show User\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a single user by ID\nuser_id = 67890\nuser = zenpy_client.users(id=user_id)\n\nprint(f\"Name: {user.name}\")\nprint(f\"Email: {user.email}\")\nprint(f\"Role: {user.role}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef get_user_profile(user_id):\n    \"\"\"Get comprehensive user profile\"\"\"\n\n    try:\n        user = zenpy_client.users(id=user_id)\n\n        print(\"=== User Profile ===\")\n        print(f\"ID: {user.id}\")\n        print(f\"Name: {user.name}\")\n        print(f\"Email: {user.email}\")\n        print(f\"Phone: {user.phone or 'N/A'}\")\n        print(f\"Role: {user.role}\")\n        print(f\"Active: {user.active}\")\n        print(f\"Verified: {user.verified}\")\n        print(f\"Timezone: {user.time_zone}\")\n        print(f\"Locale: {user.locale}\")\n\n        if user.organization_id:\n            print(f\"Organization ID: {user.organization_id}\")\n\n        print(f\"Created: {user.created_at}\")\n        print(f\"Updated: {user.updated_at}\")\n\n        if user.last_login_at:\n            print(f\"Last Login: {user.last_login_at}\")\n\n        if user.tags:\n            print(f\"Tags: {', '.join(user.tags)}\")\n\n        if hasattr(user, 'user_fields') and user.user_fields:\n            print(\"\\nCustom User Fields:\")\n            for key, value in user.user_fields.items():\n                print(f\"  {key}: {value}\")\n\n        return user\n\n    except Exception as e:\n        print(f\"Error fetching user: {e}\")\n        return None\n\nget_user_profile(67890)\n```\n\n#### Create User\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import User\n\nzenpy_client = Zenpy(**credentials)\n\n# Create a new user\nuser = User(\n    name=\"John Doe\",\n    email=\"john.doe@example.com\",\n    role=\"end-user\"\n)\n\ncreated_user = zenpy_client.users.create(user)\n\nprint(\"User created successfully!\")\nprint(f\"User ID: {created_user.id}\")\nprint(f\"Name: {created_user.name}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import User\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_agent_user():\n    \"\"\"Create an agent user with full details\"\"\"\n\n    user = User(\n        name=\"Sarah Agent\",\n        email=\"sarah.agent@company.com\",\n        role=\"agent\",\n        phone=\"+1-555-123-4567\",\n        time_zone=\"America/New_York\",\n        locale=\"en-US\",\n        verified=True,\n        tags=[\"support-team\", \"tier-2\"],\n        user_fields={\n            \"department\": \"Technical Support\",\n            \"employee_id\": \"EMP-12345\"\n        },\n        organization_id=98765\n    )\n\n    try:\n        created_user = zenpy_client.users.create(user)\n        print(f\"Agent created: {created_user.id}\")\n        print(f\"Name: {created_user.name}\")\n        print(f\"Email: {created_user.email}\")\n        return created_user\n\n    except Exception as e:\n        print(f\"Failed to create user: {e}\")\n        return None\n\ncreate_agent_user()\n```\n\n#### Update User\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get the user\nuser_id = 67890\nuser = zenpy_client.users(id=user_id)\n\n# Update user details\nuser.name = \"Jane Smith\"\nuser.phone = \"+1-555-999-8888\"\n\n# Save changes\nupdated_user = zenpy_client.users.update(user)\n\nprint(\"User updated successfully!\")\nprint(f\"Name: {updated_user.name}\")\nprint(f\"Phone: {updated_user.phone}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef update_user_profile(user_id):\n    \"\"\"Update user profile with multiple fields\"\"\"\n\n    try:\n        user = zenpy_client.users(id=user_id)\n\n        # Update multiple fields\n        user.name = \"Jane Smith-Johnson\"\n        user.phone = \"+1-555-987-6543\"\n        user.time_zone = \"Pacific/Auckland\"\n        user.locale = \"en-GB\"\n        user.tags = [\"vip\", \"premium-support\"]\n        user.user_fields = {\n            \"department\": \"Engineering\",\n            \"location\": \"Remote\"\n        }\n        user.organization_id = 11111\n\n        # Save changes\n        updated_user = zenpy_client.users.update(user)\n\n        print(f\"User updated: {updated_user.id}\")\n        print(f\"New name: {updated_user.name}\")\n        print(f\"New timezone: {updated_user.time_zone}\")\n\n        return updated_user\n\n    except Exception as e:\n        print(f\"Failed to update user: {e}\")\n        return None\n\nupdate_user_profile(67890)\n```\n\n#### Delete User\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Delete a user\nuser_id = 67890\nzenpy_client.users.delete(user_id)\n\nprint(f\"User {user_id} deleted successfully\")\n```\n\n#### Search Users\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Search for users by email\nusers = zenpy_client.search('john@example.com', type='user')\n\nfor user in users:\n    print(f\"{user.name} - {user.email}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef search_users_by_name(search_term):\n    \"\"\"Search users by name\"\"\"\n\n    try:\n        users = list(zenpy_client.search(f'name:{search_term}', type='user'))\n\n        print(f\"Found {len(users)} users matching \\\"{search_term}\\\"\")\n\n        for user in users:\n            print(\"\\n---\")\n            print(f\"ID: {user.id}\")\n            print(f\"Name: {user.name}\")\n            print(f\"Email: {user.email}\")\n            print(f\"Role: {user.role}\")\n            print(f\"Organization: {user.organization_id}\")\n\n        return users\n\n    except Exception as e:\n        print(f\"Search failed: {e}\")\n        return []\n\nsearch_users_by_name('John')\n```\n\n#### Get Current User\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get current authenticated user\ncurrent_user = zenpy_client.users.me()\n\nprint(f\"Current user: {current_user.name}\")\nprint(f\"Email: {current_user.email}\")\nprint(f\"Role: {current_user.role}\")\n```\n\n---\n\n### Organizations API\n\n#### List Organizations\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# List all organizations\nfor org in zenpy_client.organizations():\n    print(f\"{org.name} (ID: {org.id})\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef analyze_organizations():\n    \"\"\"Analyze all organizations\"\"\"\n\n    organizations = list(zenpy_client.organizations())\n\n    print(f\"Total organizations: {len(organizations)}\")\n\n    for org in organizations:\n        print(\"\\n=== Organization ===\")\n        print(f\"ID: {org.id}\")\n        print(f\"Name: {org.name}\")\n\n        if hasattr(org, 'domain_names') and org.domain_names:\n            print(f\"Domain Names: {', '.join(org.domain_names)}\")\n        else:\n            print(\"Domain Names: None\")\n\n        print(f\"Details: {org.details or 'N/A'}\")\n        print(f\"Notes: {org.notes or 'N/A'}\")\n\n        if org.tags:\n            print(f\"Tags: {', '.join(org.tags)}\")\n\n        print(f\"Created: {org.created_at}\")\n\n        if hasattr(org, 'organization_fields') and org.organization_fields:\n            print(\"Custom Fields:\", org.organization_fields)\n\n    return organizations\n\nanalyze_organizations()\n```\n\n#### Show Organization\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a single organization by ID\norg_id = 98765\norg = zenpy_client.organizations(id=org_id)\n\nprint(f\"Name: {org.name}\")\nprint(f\"Details: {org.details}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef get_organization_details(org_id):\n    \"\"\"Get comprehensive organization details\"\"\"\n\n    try:\n        org = zenpy_client.organizations(id=org_id)\n\n        print(\"=== Organization Details ===\")\n        print(f\"ID: {org.id}\")\n        print(f\"Name: {org.name}\")\n\n        if hasattr(org, 'domain_names') and org.domain_names:\n            print(f\"Domain Names: {', '.join(org.domain_names)}\")\n        else:\n            print(\"Domain Names: None\")\n\n        print(f\"Details: {org.details or 'N/A'}\")\n        print(f\"Notes: {org.notes or 'N/A'}\")\n\n        if hasattr(org, 'group_id'):\n            print(f\"Group ID: {org.group_id or 'N/A'}\")\n\n        if org.tags:\n            print(f\"Tags: {', '.join(org.tags)}\")\n\n        print(f\"Created: {org.created_at}\")\n        print(f\"Updated: {org.updated_at}\")\n\n        if hasattr(org, 'organization_fields') and org.organization_fields:\n            print(\"\\nCustom Organization Fields:\")\n            for key, value in org.organization_fields.items():\n                print(f\"  {key}: {value}\")\n\n        return org\n\n    except Exception as e:\n        print(f\"Error fetching organization: {e}\")\n        return None\n\nget_organization_details(98765)\n```\n\n#### Create Organization\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Organization\n\nzenpy_client = Zenpy(**credentials)\n\n# Create a new organization\norg = Organization(\n    name=\"Acme Corporation\",\n    domain_names=[\"acme.com\"]\n)\n\ncreated_org = zenpy_client.organizations.create(org)\n\nprint(\"Organization created!\")\nprint(f\"ID: {created_org.id}\")\nprint(f\"Name: {created_org.name}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Organization\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_organization():\n    \"\"\"Create organization with full details\"\"\"\n\n    organization = Organization(\n        name=\"TechStart Solutions Inc.\",\n        domain_names=[\"techstart.com\", \"techstart.io\"],\n        details=\"Premium enterprise customer\",\n        notes=\"VIP support tier, 24/7 coverage\",\n        tags=[\"enterprise\", \"vip\", \"priority-support\"],\n        group_id=12345,\n        organization_fields={\n            \"industry\": \"Technology\",\n            \"account_tier\": \"Enterprise\",\n            \"annual_revenue\": \"10M+\"\n        }\n    )\n\n    try:\n        created_org = zenpy_client.organizations.create(organization)\n        print(f\"Organization created: {created_org.id}\")\n        print(f\"Name: {created_org.name}\")\n\n        if created_org.domain_names:\n            print(f\"Domains: {', '.join(created_org.domain_names)}\")\n\n        return created_org\n\n    except Exception as e:\n        print(f\"Failed to create organization: {e}\")\n        return None\n\ncreate_organization()\n```\n\n#### Update Organization\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get the organization\norg_id = 98765\norg = zenpy_client.organizations(id=org_id)\n\n# Update organization\norg.name = \"Acme Corporation Ltd.\"\norg.details = \"Updated company details\"\n\n# Save changes\nupdated_org = zenpy_client.organizations.update(org)\n\nprint(\"Organization updated!\")\nprint(f\"Name: {updated_org.name}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef update_organization(org_id):\n    \"\"\"Update organization with multiple fields\"\"\"\n\n    try:\n        org = zenpy_client.organizations(id=org_id)\n\n        # Update multiple fields\n        org.name = \"Acme Global Corporation\"\n        org.domain_names = [\"acme.com\", \"acme.global\", \"acmeglobal.com\"]\n        org.details = \"Global enterprise customer with multiple subsidiaries\"\n        org.notes = \"Upgraded to platinum tier - assign dedicated account manager\"\n        org.tags = [\"enterprise\", \"platinum\", \"global\", \"strategic-account\"]\n        org.organization_fields = {\n            \"account_tier\": \"Platinum\",\n            \"contract_renewal\": \"2025-12-31\",\n            \"dedicated_support\": \"yes\"\n        }\n\n        # Save changes\n        updated_org = zenpy_client.organizations.update(org)\n\n        print(f\"Organization updated: {updated_org.id}\")\n        print(f\"New name: {updated_org.name}\")\n\n        if updated_org.tags:\n            print(f\"Tags: {', '.join(updated_org.tags)}\")\n\n        return updated_org\n\n    except Exception as e:\n        print(f\"Failed to update organization: {e}\")\n        return None\n\nupdate_organization(98765)\n```\n\n#### Delete Organization\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Delete an organization\norg_id = 98765\nzenpy_client.organizations.delete(org_id)\n\nprint(f\"Organization {org_id} deleted successfully\")\n```\n\n---\n\n### Search API\n\n#### Basic Search\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Search for open tickets\nresults = zenpy_client.search('status:open', type='ticket')\n\nfor ticket in results:\n    print(f\"#{ticket.id}: {ticket.subject}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef search_open_tickets():\n    \"\"\"Search for high-priority open tickets\"\"\"\n\n    try:\n        results = list(zenpy_client.search('status:open priority:high', type='ticket'))\n\n        print(f\"Found {len(results)} high-priority open tickets\")\n\n        for ticket in results:\n            print(\"\\n---\")\n            print(f\"Ticket #{ticket.id}\")\n            print(f\"Subject: {ticket.subject}\")\n            print(f\"Priority: {ticket.priority}\")\n            print(f\"Status: {ticket.status}\")\n            print(f\"Created: {ticket.created_at}\")\n            print(f\"Assignee: {ticket.assignee_id or 'Unassigned'}\")\n\n        return results\n\n    except Exception as e:\n        print(f\"Search failed: {e}\")\n        return []\n\nsearch_open_tickets()\n```\n\n#### Search Tickets\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Search tickets by subject\ntickets = zenpy_client.search('subject:login', type='ticket')\n\nprint(f\"Tickets mentioning 'login': {len(list(tickets))}\")\n```\n\n**Advanced Example with Multiple Filters:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef advanced_ticket_search():\n    \"\"\"Perform advanced ticket search with multiple filters\"\"\"\n\n    # Build search query\n    query_parts = [\n        'type:ticket',\n        'status:open',\n        'priority:urgent',\n        'tags:bug',\n        'created>2025-01-01'\n    ]\n    query = ' '.join(query_parts)\n\n    try:\n        tickets = list(zenpy_client.search(query))\n\n        print(f\"Search Query: {query}\")\n        print(f\"Results: {len(tickets)} tickets\\n\")\n\n        for ticket in tickets:\n            print(f\"#{ticket.id}: {ticket.subject}\")\n            print(f\"  Status: {ticket.status} | Priority: {ticket.priority}\")\n\n            if ticket.tags:\n                print(f\"  Tags: {', '.join(ticket.tags)}\")\n\n            print(f\"  Created: {ticket.created_at}\")\n\n        return tickets\n\n    except Exception as e:\n        print(f\"Search error: {e}\")\n        return []\n\nadvanced_ticket_search()\n```\n\n#### Search Users\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Search users by email domain\nusers = zenpy_client.search('email:*@example.com', type='user')\n\nfor user in users:\n    print(f\"{user.name} - {user.email}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef find_agents_by_organization(org_id):\n    \"\"\"Find all agents in a specific organization\"\"\"\n\n    query = f'type:user role:agent organization_id:{org_id}'\n\n    try:\n        agents = list(zenpy_client.search(query))\n\n        print(f\"Found {len(agents)} agents in organization {org_id}\")\n\n        for agent in agents:\n            print(\"\\n---\")\n            print(f\"Name: {agent.name}\")\n            print(f\"Email: {agent.email}\")\n            print(f\"Role: {agent.role}\")\n            print(f\"Active: {agent.active}\")\n            print(f\"Last Login: {agent.last_login_at or 'Never'}\")\n\n        return agents\n\n    except Exception as e:\n        print(f\"User search failed: {e}\")\n        return []\n\nfind_agents_by_organization(98765)\n```\n\n#### Search Organizations\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Search organizations by name\norgs = zenpy_client.search('name:Acme', type='organization')\n\nfor org in orgs:\n    print(f\"{org.name} (ID: {org.id})\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef search_organizations_by_domain(domain):\n    \"\"\"Search organizations by domain\"\"\"\n\n    query = f'type:organization {domain}'\n\n    try:\n        organizations = list(zenpy_client.search(query))\n\n        print(f\"Found {len(organizations)} organizations with domain \\\"{domain}\\\"\")\n\n        for org in organizations:\n            print(\"\\n=== Organization ===\")\n            print(f\"ID: {org.id}\")\n            print(f\"Name: {org.name}\")\n\n            if hasattr(org, 'domain_names') and org.domain_names:\n                print(f\"Domains: {', '.join(org.domain_names)}\")\n            else:\n                print(\"Domains: None\")\n\n            print(f\"Details: {org.details or 'N/A'}\")\n            print(f\"Created: {org.created_at}\")\n\n        return organizations\n\n    except Exception as e:\n        print(f\"Organization search failed: {e}\")\n        return []\n\nsearch_organizations_by_domain('acme.com')\n```\n\n#### Search Export (For Large Result Sets)\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef export_all_tickets():\n    \"\"\"Export all tickets using search_export for large datasets\"\"\"\n\n    # search_export is designed for exporting large numbers of tickets\n    # It bypasses the 1000-result limit of regular search\n\n    count = 0\n\n    for ticket in zenpy_client.search_export(type='ticket', status='open'):\n        count += 1\n        print(f\"#{ticket.id}: {ticket.subject}\")\n\n        # Process tickets in batches\n        if count % 100 == 0:\n            print(f\"Processed {count} tickets...\")\n\n    print(f\"\\nTotal tickets exported: {count}\")\n    return count\n\nexport_all_tickets()\n```\n\n---\n\n### Groups API\n\n#### List Groups\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# List all groups\nfor group in zenpy_client.groups():\n    print(f\"{group.name} (ID: {group.id})\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef list_all_groups():\n    \"\"\"List all groups with details\"\"\"\n\n    groups = list(zenpy_client.groups())\n\n    print(f\"Found {len(groups)} groups\\n\")\n\n    for group in groups:\n        print(\"=== Group ===\")\n        print(f\"ID: {group.id}\")\n        print(f\"Name: {group.name}\")\n        print(f\"Description: {group.description or 'N/A'}\")\n        print(f\"Created: {group.created_at}\")\n        print(f\"Updated: {group.updated_at}\")\n        print(\"---\")\n\n    return groups\n\nlist_all_groups()\n```\n\n#### Show Group\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a single group by ID\ngroup_id = 12345\ngroup = zenpy_client.groups(id=group_id)\n\nprint(f\"Group: {group.name}\")\nprint(f\"Description: {group.description}\")\n```\n\n#### Create Group\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Group\n\nzenpy_client = Zenpy(**credentials)\n\n# Create a new group\ngroup = Group(name=\"Technical Support Team\")\n\ncreated_group = zenpy_client.groups.create(group)\n\nprint(\"Group created!\")\nprint(f\"ID: {created_group.id}\")\nprint(f\"Name: {created_group.name}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Group\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_support_group():\n    \"\"\"Create a support group with description\"\"\"\n\n    group = Group(\n        name=\"Enterprise Support Team\",\n        description=\"Dedicated support team for enterprise customers\"\n    )\n\n    try:\n        created_group = zenpy_client.groups.create(group)\n        print(f\"Group created: {created_group.id}\")\n        print(f\"Name: {created_group.name}\")\n        print(f\"Description: {created_group.description}\")\n        return created_group\n\n    except Exception as e:\n        print(f\"Failed to create group: {e}\")\n        return None\n\ncreate_support_group()\n```\n\n#### Update Group\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get the group\ngroup_id = 12345\ngroup = zenpy_client.groups(id=group_id)\n\n# Update group\ngroup.name = \"Updated Group Name\"\ngroup.description = \"Updated description\"\n\n# Save changes\nupdated_group = zenpy_client.groups.update(group)\n\nprint(\"Group updated!\")\nprint(f\"Name: {updated_group.name}\")\n```\n\n#### Delete Group\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Delete a group\ngroup_id = 12345\nzenpy_client.groups.delete(group_id)\n\nprint(f\"Group {group_id} deleted successfully\")\n```\n\n---\n\n### Attachments API\n\n#### Upload Attachment\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Upload a file\nfile_path = './documents/file.pdf'\nupload = zenpy_client.attachments.upload(file_path)\n\nprint(\"File uploaded successfully!\")\nprint(f\"Upload token: {upload.token}\")\nprint(f\"Attachment: {upload.attachment}\")\n```\n\n**Advanced Example with Ticket Creation:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket, User, Comment\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_ticket_with_attachment():\n    \"\"\"Create a ticket with an attached file\"\"\"\n\n    try:\n        # Step 1: Upload the file\n        file_path = './screenshots/bug-screenshot.png'\n        upload = zenpy_client.attachments.upload(file_path)\n\n        print(f\"File uploaded. Token: {upload.token}\")\n\n        # Step 2: Create ticket with attachment\n        ticket = Ticket(\n            subject=\"Bug Report: UI Issue\",\n            comment=Comment(\n                body=\"Please see the attached screenshot showing the UI bug.\",\n                uploads=[upload.token]\n            ),\n            requester=User(\n                name=\"Bug Reporter\",\n                email=\"reporter@example.com\"\n            ),\n            priority=\"high\",\n            tags=[\"bug\", \"ui\"]\n        )\n\n        created_ticket = zenpy_client.tickets.create(ticket)\n\n        print(\"Ticket created with attachment!\")\n        print(f\"Ticket ID: {created_ticket.id}\")\n        print(f\"Subject: {created_ticket.subject}\")\n\n        return created_ticket\n\n    except Exception as e:\n        print(f\"Error: {e}\")\n        return None\n\ncreate_ticket_with_attachment()\n```\n\n#### Upload Multiple Attachments\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket, User, Comment\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_ticket_with_multiple_attachments():\n    \"\"\"Create a ticket with multiple attached files\"\"\"\n\n    try:\n        # Upload multiple files\n        files = [\n            './documents/report.pdf',\n            './screenshots/screen1.png',\n            './screenshots/screen2.png'\n        ]\n\n        upload_tokens = []\n        for file_path in files:\n            upload = zenpy_client.attachments.upload(file_path)\n            upload_tokens.append(upload.token)\n            print(f\"Uploaded: {file_path}\")\n\n        print(f\"Uploaded {len(upload_tokens)} files\")\n\n        # Create ticket with all attachments\n        ticket = Ticket(\n            subject=\"Detailed Bug Report\",\n            comment=Comment(\n                body=\"Please find the attached report and screenshots.\",\n                uploads=upload_tokens\n            ),\n            requester=User(\n                name=\"QA Tester\",\n                email=\"qa@example.com\"\n            ),\n            priority=\"normal\"\n        )\n\n        created_ticket = zenpy_client.tickets.create(ticket)\n\n        print(\"Ticket created with multiple attachments!\")\n        print(f\"Ticket ID: {created_ticket.id}\")\n\n        return created_ticket\n\n    except Exception as e:\n        print(f\"Error: {e}\")\n        return None\n\ncreate_ticket_with_multiple_attachments()\n```\n\n---\n\n### Macros API\n\n#### List Macros\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# List all macros\nfor macro in zenpy_client.macros():\n    print(f\"{macro.title} (ID: {macro.id})\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef list_active_macros():\n    \"\"\"List all active macros\"\"\"\n\n    macros = list(zenpy_client.macros())\n    active_macros = [m for m in macros if m.active]\n\n    print(f\"Found {len(active_macros)} active macros\\n\")\n\n    for macro in active_macros:\n        print(\"=== Macro ===\")\n        print(f\"ID: {macro.id}\")\n        print(f\"Title: {macro.title}\")\n        print(f\"Description: {macro.description or 'N/A'}\")\n        print(f\"Active: {macro.active}\")\n        print(f\"Created: {macro.created_at}\")\n        print(\"---\")\n\n    return active_macros\n\nlist_active_macros()\n```\n\n#### Show Macro\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a single macro by ID\nmacro_id = 54321\nmacro = zenpy_client.macros(id=macro_id)\n\nprint(f\"Title: {macro.title}\")\nprint(f\"Description: {macro.description}\")\nprint(f\"Actions: {macro.actions}\")\n```\n\n#### Apply Macro to Ticket\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef apply_macro_to_ticket(ticket_id, macro_id):\n    \"\"\"Apply a macro to a ticket\"\"\"\n\n    try:\n        # Get the ticket\n        ticket = zenpy_client.tickets(id=ticket_id)\n\n        # Show macro effect\n        result = zenpy_client.tickets.show_macro_effect(ticket, macro_id)\n\n        print(\"Macro applied successfully!\")\n        print(f\"Result: {result}\")\n\n        return result\n\n    except Exception as e:\n        print(f\"Error applying macro: {e}\")\n        return None\n\napply_macro_to_ticket(12345, 54321)\n```\n\n---\n\n### Views API\n\n#### List Views\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# List all views\nfor view in zenpy_client.views():\n    print(f\"{view.title} (ID: {view.id})\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef list_active_views():\n    \"\"\"List all active views\"\"\"\n\n    views = list(zenpy_client.views())\n    active_views = [v for v in views if v.active]\n\n    print(f\"Found {len(active_views)} active views\\n\")\n\n    for view in active_views:\n        print(\"=== View ===\")\n        print(f\"ID: {view.id}\")\n        print(f\"Title: {view.title}\")\n        print(f\"Description: {view.description or 'N/A'}\")\n        print(f\"Active: {view.active}\")\n        print(f\"Position: {view.position}\")\n        print(\"---\")\n\n    return active_views\n\nlist_active_views()\n```\n\n#### Execute View\n\n**Basic Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Execute a view\nview_id = 11111\nresult = zenpy_client.views.execute(view_id)\n\nprint(\"View executed!\")\nfor ticket in result:\n    print(f\"#{ticket.id}: {ticket.subject}\")\n```\n\n**Advanced Example:**\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\ndef execute_view_and_analyze(view_id):\n    \"\"\"Execute a view and analyze results\"\"\"\n\n    try:\n        result = list(zenpy_client.views.execute(view_id))\n\n        print(\"=== View Execution Results ===\")\n        print(f\"Total tickets: {len(result)}\")\n\n        # Analyze ticket statuses\n        status_counts = {}\n        for ticket in result:\n            status = ticket.status\n            status_counts[status] = status_counts.get(status, 0) + 1\n\n        print(\"\\n=== Status Distribution ===\")\n        for status, count in status_counts.items():\n            print(f\"{status}: {count}\")\n\n        # Show first 10 tickets\n        print(\"\\n=== Tickets ===\")\n        for ticket in result[:10]:\n            print(f\"#{ticket.id}: {ticket.subject}\")\n            print(f\"  Status: {ticket.status} | Priority: {ticket.priority}\")\n\n        return result\n\n    except Exception as e:\n        print(f\"Error executing view: {e}\")\n        return []\n\nexecute_view_and_analyze(11111)\n```\n\n---\n\n## Error Handling\n\n### Basic Error Handling\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.exception import ZenpyException\n\nzenpy_client = Zenpy(**credentials)\n\ntry:\n    ticket = zenpy_client.tickets(id=99999)\n    print(f\"Ticket: {ticket.subject}\")\nexcept ZenpyException as e:\n    print(f\"Error occurred: {e}\")\n```\n\n### Advanced Error Handling\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.exception import ZenpyException, RecordNotFoundException, ZenpyRateLimitExceeded\nimport time\n\nzenpy_client = Zenpy(**credentials)\n\ndef handle_zendesk_errors():\n    \"\"\"Demonstrate comprehensive error handling\"\"\"\n\n    try:\n        ticket = zenpy_client.tickets(id=99999)\n        return ticket\n\n    except RecordNotFoundException:\n        print(\"Ticket not found\")\n\n    except ZenpyRateLimitExceeded as e:\n        print(f\"Rate limit exceeded - retry after: {e.retry_after}\")\n        time.sleep(e.retry_after)\n\n    except ZenpyException as e:\n        print(f\"Zenpy error: {e}\")\n\n    except Exception as e:\n        print(f\"Unknown error: {e}\")\n\n    return None\n```\n\n### Retry Logic\n\n```python\nfrom zenpy import Zenpy\nfrom zenpy.lib.exception import ZenpyRateLimitExceeded\nimport time\n\nzenpy_client = Zenpy(**credentials)\n\ndef fetch_ticket_with_retry(ticket_id, max_retries=3):\n    \"\"\"Fetch a ticket with automatic retry logic\"\"\"\n\n    for attempt in range(1, max_retries + 1):\n        try:\n            ticket = zenpy_client.tickets(id=ticket_id)\n            return ticket\n\n        except ZenpyRateLimitExceeded as e:\n            if attempt < max_retries:\n                wait_time = e.retry_after if hasattr(e, 'retry_after') else 2 ** attempt\n                print(f\"Rate limited. Retrying in {wait_time}s...\")\n                time.sleep(wait_time)\n            else:\n                print(f\"Failed after {max_retries} attempts\")\n                raise\n\n        except Exception as e:\n            if attempt < max_retries:\n                print(f\"Error. Attempt {attempt}/{max_retries}\")\n                time.sleep(1)\n            else:\n                raise\n\n    return None\n\nticket = fetch_ticket_with_retry(12345)\n```\n\n---\n\n## Complete Working Examples\n\n### Basic Support Ticket System\n\n```python\nimport os\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Ticket, User\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ncredentials = {\n    'email': os.getenv('ZENDESK_EMAIL'),\n    'token': os.getenv('ZENDESK_API_TOKEN'),\n    'subdomain': os.getenv('ZENDESK_SUBDOMAIN')\n}\n\nzenpy_client = Zenpy(**credentials)\n\ndef create_support_ticket(customer_email, subject, description):\n    \"\"\"Create a support ticket for a customer\"\"\"\n\n    try:\n        # Check if user exists\n        users = list(zenpy_client.search(customer_email, type='user'))\n\n        if users:\n            user = users[0]\n            print(f\"Found existing user: {user.name}\")\n        else:\n            # Create new user\n            user = User(\n                name=customer_email.split('@')[0],\n                email=customer_email,\n                role='end-user'\n            )\n            user = zenpy_client.users.create(user)\n            print(f\"Created new user: {user.name}\")\n\n        # Create ticket\n        ticket = Ticket(\n            subject=subject,\n            description=description,\n            requester_id=user.id,\n            priority='normal',\n            status='new'\n        )\n\n        created_ticket = zenpy_client.tickets.create(ticket)\n\n        print(\"Ticket created successfully!\")\n        print(f\"Ticket ID: {created_ticket.id}\")\n        print(f\"Subject: {created_ticket.subject}\")\n\n        return created_ticket\n\n    except Exception as e:\n        print(f\"Error creating support ticket: {e}\")\n        return None\n\n# Usage\ncreate_support_ticket(\n    'customer@example.com',\n    'Cannot access my account',\n    'I am unable to log into my account. I keep getting an error message.'\n)\n```\n\n### Ticket Management Dashboard\n\n```python\nimport os\nfrom zenpy import Zenpy\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ncredentials = {\n    'email': os.getenv('ZENDESK_EMAIL'),\n    'token': os.getenv('ZENDESK_API_TOKEN'),\n    'subdomain': os.getenv('ZENDESK_SUBDOMAIN')\n}\n\nzenpy_client = Zenpy(**credentials)\n\ndef get_dashboard_stats():\n    \"\"\"Get support dashboard statistics\"\"\"\n\n    try:\n        # Search for different ticket categories\n        open_tickets = list(zenpy_client.search('type:ticket status:open'))\n        pending_tickets = list(zenpy_client.search('type:ticket status:pending'))\n        solved_tickets = list(zenpy_client.search('type:ticket status:solved created>2025-01-01'))\n        urgent_tickets = list(zenpy_client.search('type:ticket priority:urgent status<solved'))\n\n        print(\"=== Support Dashboard ===\")\n        print(f\"Open Tickets: {len(open_tickets)}\")\n        print(f\"Pending Tickets: {len(pending_tickets)}\")\n        print(f\"Solved This Year: {len(solved_tickets)}\")\n        print(f\"Urgent Tickets: {len(urgent_tickets)}\")\n\n        # List urgent tickets\n        if urgent_tickets:\n            print(\"\\n=== Urgent Tickets Requiring Attention ===\")\n            for ticket in urgent_tickets:\n                print(f\"#{ticket.id}: {ticket.subject}\")\n                print(f\"  Status: {ticket.status} | Created: {ticket.created_at}\")\n                print(f\"  Assignee: {ticket.assignee_id or 'Unassigned'}\")\n\n        return {\n            'open': len(open_tickets),\n            'pending': len(pending_tickets),\n            'solved': len(solved_tickets),\n            'urgent': len(urgent_tickets)\n        }\n\n    except Exception as e:\n        print(f\"Error fetching dashboard stats: {e}\")\n        return None\n\nget_dashboard_stats()\n```\n\n### Bulk Ticket Operations\n\n```python\nimport os\nfrom zenpy import Zenpy\nfrom zenpy.lib.api_objects import Comment\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ncredentials = {\n    'email': os.getenv('ZENDESK_EMAIL'),\n    'token': os.getenv('ZENDESK_API_TOKEN'),\n    'subdomain': os.getenv('ZENDESK_SUBDOMAIN')\n}\n\nzenpy_client = Zenpy(**credentials)\n\ndef bulk_update_tickets(ticket_ids, status='solved', comment_text=None):\n    \"\"\"Update multiple tickets at once\"\"\"\n\n    try:\n        print(f\"Updating {len(ticket_ids)} tickets...\")\n\n        results = []\n\n        for ticket_id in ticket_ids:\n            try:\n                ticket = zenpy_client.tickets(id=ticket_id)\n                ticket.status = status\n\n                if comment_text:\n                    ticket.comment = Comment(body=comment_text, public=False)\n\n                updated_ticket = zenpy_client.tickets.update(ticket)\n                print(f\"✓ Updated ticket #{ticket_id}\")\n                results.append({'success': True, 'ticket_id': ticket_id, 'ticket': updated_ticket})\n\n            except Exception as e:\n                print(f\"✗ Failed to update ticket #{ticket_id}: {e}\")\n                results.append({'success': False, 'ticket_id': ticket_id, 'error': str(e)})\n\n        successful = len([r for r in results if r['success']])\n        failed = len([r for r in results if not r['success']])\n\n        print(f\"\\n=== Bulk Update Complete ===\")\n        print(f\"Successful: {successful}\")\n        print(f\"Failed: {failed}\")\n\n        return results\n\n    except Exception as e:\n        print(f\"Bulk update error: {e}\")\n        return None\n\n# Usage: Close multiple tickets at once\nticket_ids = [12345, 12346, 12347]\nbulk_update_tickets(\n    ticket_ids,\n    status='solved',\n    comment_text='This ticket has been resolved and closed.'\n)\n```\n\n---\n\n## Additional Features\n\n### Object Conversion\n\nZenpy provides convenient methods for converting objects:\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a ticket\nticket = zenpy_client.tickets(id=12345)\n\n# Convert to dictionary\nticket_dict = ticket.to_dict()\nprint(ticket_dict)\n\n# Convert to JSON\nticket_json = ticket.to_json()\nprint(ticket_json)\n```\n\n### Lazy Attribute Evaluation\n\nZenpy uses lazy evaluation to minimize API calls:\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# Get a ticket\nticket = zenpy_client.tickets(id=12345)\n\n# Accessing requester automatically fetches the User object\nprint(f\"Requester: {ticket.requester.name}\")  # Only one API call\n\n# Accessing organization\nif ticket.organization:\n    print(f\"Organization: {ticket.organization.name}\")\n```\n\n### Caching\n\nZenpy automatically caches objects to reduce API calls:\n\n```python\nfrom zenpy import Zenpy\n\nzenpy_client = Zenpy(**credentials)\n\n# First access - API call made\nticket1 = zenpy_client.tickets(id=12345)\n\n# Second access - served from cache\nticket2 = zenpy_client.tickets(id=12345)\n\n# Both references point to the same object\nassert ticket1 is ticket2\n```\n\n---\n\n## Best Practices\n\n1. **Always use environment variables for credentials**\n2. **Handle rate limiting with appropriate retry logic**\n3. **Use search_export for large result sets (>1000 items)**\n4. **Leverage lazy evaluation and caching**\n5. **Catch specific Zenpy exceptions for better error handling**\n6. **Use batch operations when updating multiple tickets**\n7. **Validate user input before creating tickets**\n8. **Use custom fields appropriately for your organization**\n9. **Test with a sandbox account before production**\n10. **Monitor API usage to avoid rate limits**\n\n---\n\n## Rate Limits\n\nZendesk enforces rate limits on API requests:\n\n- **Standard**: 700 requests per minute\n- **Enterprise**: 2500+ requests per minute (varies by plan)\n\nZenpy automatically handles rate limiting by:\n- Tracking request counts\n- Sleeping when limits are approached\n- Raising `ZenpyRateLimitExceeded` when exceeded\n\n```python\nfrom zenpy import Zenpy\n\n# Configure custom rate limit\ncredentials = {\n    'email': 'your_email@example.com',\n    'token': 'your_api_token',\n    'subdomain': 'your_subdomain',\n    'ratelimit': 700  # Requests per minute\n}\n\nzenpy_client = Zenpy(**credentials)\n```\n\n---\n\n## Resources\n\n- **GitHub Repository**: https://github.com/facetoe/zenpy\n- **Documentation**: http://docs.facetoe.com.au/zenpy.html\n- **PyPI Package**: https://pypi.org/project/zenpy/\n- **Zendesk API Docs**: https://developer.zendesk.com/api-reference/\n- **Issue Tracker**: https://github.com/facetoe/zenpy/issues\n"
  },
  {
    "path": "content/zenml/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"ZenML package guide for Python projects using pipelines, stacks, and local or remote ZenML servers\"\nmetadata:\n  languages: \"python\"\n  versions: \"0.94.0\"\n  revision: 1\n  updated-on: \"2026-03-12\"\n  source: maintainer\n  tags: \"zenml,mlops,pipelines,orchestration,artifacts\"\n---\n\n# ZenML Python Package Guide\n\n## What It Is\n\n`zenml` is the Python SDK and CLI for defining ML pipelines with `@step` and `@pipeline`, tracking runs and artifacts, and executing them against a configurable ZenML stack.\n\nFor `0.94.0`, treat the package as a client-plus-CLI entry point. Add the right extras depending on whether you want only the client, a local development stack, or a self-hosted server.\n\n## Version Snapshot\n\n- Ecosystem: `pypi`\n- Package: `zenml`\n- Version covered: `0.94.0`\n- Python requirement on PyPI: `>=3.10,<3.14`\n- Docs root: `https://docs.zenml.io/`\n- Reference landing page: `https://docs.zenml.io/reference`\n- Registry page: `https://pypi.org/project/zenml/`\n\n## Install\n\nInstall the exact package version used by the project:\n\n```bash\npip install \"zenml==0.94.0\"\n```\n\nFor the normal local development experience, install the local extra instead of the minimal base package:\n\n```bash\npip install \"zenml[local]==0.94.0\"\n```\n\nIf you need to run a self-hosted ZenML server from the package, use the server extra:\n\n```bash\npip install \"zenml[server]==0.94.0\"\n```\n\n## Initialize A Project\n\nInitialize ZenML once at the repository root:\n\n```bash\nzenml init\n```\n\nThis creates a `.zen` directory and marks the project root as the default source root. That matters because ZenML needs importable pipeline code when it materializes steps, snapshots, and remote runs.\n\nFor local development, start the local ZenML dashboard and API server:\n\n```bash\nzenml up\n```\n\nThe local dashboard defaults to `http://127.0.0.1:8237`.\n\n## Minimal Pipeline\n\n```python\nfrom zenml import pipeline, step\n\n@step\ndef load_values() -> list[int]:\n    return [1, 2, 3]\n\n@step\ndef train(values: list[int]) -> int:\n    return sum(values)\n\n@pipeline\ndef training_pipeline() -> None:\n    train(load_values())\n\nif __name__ == \"__main__\":\n    training_pipeline()\n```\n\nRun the pipeline with normal Python execution:\n\n```bash\npython run_pipeline.py\n```\n\nZenML will register the run, materialize step outputs as artifacts, and show the run in the dashboard if a server is active.\n\n## Core Workflow\n\n1. Install `zenml[local]` for local development unless the project intentionally uses the minimal client-only install.\n2. Run `zenml init` from the repo root once.\n3. Define functions as `@step` and compose them inside a `@pipeline`.\n4. Execute the pipeline from importable project code, not from ad hoc notebook cells that ZenML cannot resolve later.\n5. Use the dashboard or CLI to inspect runs, artifacts, stack configuration, and failures.\n\n## Stacks And Execution\n\nZenML runs pipelines against an active stack. A stack combines components such as an orchestrator and artifact store.\n\nTo switch to a different configured stack:\n\n```bash\nzenml stack set <STACK_NAME>\n```\n\nUse local stack components for local experimentation. For deployed or team workflows, expect to configure non-local components such as a remote artifact store and orchestrator.\n\n## Auth And Server Configuration\n\n### Local server\n\nFor local-only work, `zenml up` is the normal entry point. It starts the local ZenML services and opens or serves the dashboard.\n\n### Remote ZenML server\n\nTo connect the CLI and SDK to a remote ZenML server:\n\n```bash\nzenml login https://<your-zenml-server>\n```\n\nFor service-account or headless authentication, ZenML also supports API-key login:\n\n```bash\nzenml login https://<your-zenml-server> --api-key <YOUR_API_KEY>\n```\n\nIf the project uses ZenML Pro or a team deployment, verify the target server URL, workspace/project, and active stack before launching runs.\n\n## Source Root And Imports\n\nZenML needs stable imports for pipeline code. The safest pattern is:\n\n1. Keep pipeline code inside the repository you initialized with `zenml init`.\n2. Run entry scripts from that repository root.\n3. Avoid relative-import hacks or moving execution to a different working directory after initialization.\n\nIf the project structure is unusual, set or correct the source root explicitly in ZenML instead of relying on whatever current working directory happens to be active.\n\n## Common Pitfalls\n\n- Installing only `zenml` and expecting the full local experience. The base package is intentionally slim; use `zenml[local]` when you need local execution and the local dashboard.\n- Forgetting `zenml init`. Without the `.zen` directory and source-root registration, imports and run materialization often fail later.\n- Treating arbitrary Python inside a pipeline function as a step. Only decorated `@step` functions become first-class ZenML steps with tracked inputs and outputs.\n- Writing step code with unstable or non-serializable outputs. Prefer explicit Python types and deterministic return values so ZenML can materialize artifacts cleanly.\n- Switching to remote orchestration without checking the active stack. Remote runs usually need more than the default local stack, especially a non-local artifact store.\n- Assuming old blog posts still match the current packaging model. The docs and PyPI page now distinguish the minimal base package from extras such as `[local]` and `[server]`.\n- On Apple Silicon, local Docker-based workflows can require `OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` when using `zenml up`.\n\n## Version-Sensitive Notes For 0.94.0\n\n- `0.94.0` is the current ZenML package version on PyPI as of 2026-03-12.\n- The official docs site is mostly versionless. Use `0.94.0` in install commands and verify behavior against the installed package if you are copying examples from older issues, blogs, or screenshots.\n- The slimmer package model introduced in recent ZenML releases still applies here: plain `zenml` is not the same as `zenml[local]`.\n- The docs URL points at the reference area, but the practical setup flow starts from the main docs root and the installation guide.\n\n## Official Sources\n\n- Docs root: https://docs.zenml.io/\n- Installation guide: https://docs.zenml.io/getting-started/installation\n- Pipeline guide: https://docs.zenml.io/user-guides/starter-guide/create-an-ml-pipeline\n- Source root and imports: https://docs.zenml.io/concepts/source-code-management/source-root-and-imports\n- Stacks and components: https://docs.zenml.io/stacks/stack-components\n- Remote login and API keys: https://docs.zenml.io/how-to/manage-zenml-pro/connect-to-zenml-pro\n- Changelog: https://docs.zenml.io/changelog\n- PyPI package: https://pypi.org/project/zenml/\n- GitHub repository: https://github.com/zenml-io/zenml\n"
  },
  {
    "path": "content/zipp/docs/package/python/DOC.md",
    "content": "---\nname: package\ndescription: \"zipp backport for pathlib-style traversal and I/O inside ZIP archives\"\nmetadata:\n  languages: \"python\"\n  versions: \"3.23.0\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"zipp,python,zip,zipfile,pathlib,archives\"\n---\n\n# zipp Python Package Guide\n\n## Golden Rule\n\nUse `zipp.Path` when you need the maintained backport of `zipfile.Path` instead of hand-parsing ZIP member names. The maintainer README describes `zipp` as a backport of the latest `zipfile.Path` functionality, and the API follows the standard-library `zipfile.Path` interface.\n\n## Install\n\n`zipp` 3.23.0 on PyPI requires Python 3.9 or later.\n\n```bash\npython -m pip install \"zipp==3.23.0\"\n```\n\nCommon alternatives:\n\n```bash\nuv add \"zipp==3.23.0\"\npoetry add \"zipp==3.23.0\"\n```\n\n## Environment Variables And Authentication\n\nNone. `zipp` is a local Python library for working with ZIP archives and does not require API keys, tokens, or service configuration.\n\n## Initialize A Path View Of A ZIP Archive\n\nConstruct `Path` from either an archive filename or an existing `zipfile.ZipFile` object.\n\n```python\nfrom zipp import Path\n\nroot = Path(\"example.zip\")\n```\n\n```python\nfrom zipfile import ZipFile\nfrom zipp import Path\n\nwith ZipFile(\"example.zip\") as zf:\n    root = Path(zf)\n    print(root.name)\n```\n\nIf you already know the subdirectory you want inside the archive, pass `at=`:\n\n```python\nfrom zipp import Path\n\nassets = Path(\"example.zip\", at=\"assets/\")\n```\n\n## Common Workflows\n\n### List files and directories\n\n`Path` behaves like a pathlib-style object over the archive contents.\n\n```python\nfrom zipp import Path\n\nroot = Path(\"example.zip\")\n\nfor child in root.iterdir():\n    kind = \"dir\" if child.is_dir() else \"file\"\n    print(kind, child)\n```\n\n### Join paths and read text\n\nUse `/` or `joinpath()` to navigate, then `read_text()` or `open()` to read file contents.\n\n```python\nfrom zipp import Path\n\nroot = Path(\"example.zip\")\nconfig_path = root / \"config\" / \"settings.toml\"\n\nif config_path.exists() and config_path.is_file():\n    text = config_path.read_text(encoding=\"utf-8\")\n    print(text)\n```\n\nEquivalent `joinpath()` form:\n\n```python\nfrom zipp import Path\n\nroot = Path(\"example.zip\")\nreadme = root.joinpath(\"docs\", \"README.txt\")\n\nwith readme.open(\"r\", encoding=\"utf-8\") as fp:\n    print(fp.read())\n```\n\n### Read bytes\n\n```python\nfrom zipp import Path\n\ndata = (Path(\"example.zip\") / \"images\" / \"logo.png\").read_bytes()\nprint(len(data))\n```\n\n### Write a new file into an archive\n\nFor writes, open the archive with `zipfile.ZipFile` in a write-capable mode and then wrap it with `Path`.\n\n```python\nfrom zipfile import ZipFile\nfrom zipp import Path\n\nwith ZipFile(\"output.zip\", mode=\"w\") as zf:\n    root = Path(zf)\n    with (root / \"hello.txt\").open(\"w\", encoding=\"utf-8\") as fp:\n        fp.write(\"hello from zipp\\n\")\n```\n\n### Use pathlib-style metadata helpers\n\nThe standard-library path helpers such as `name`, `suffix`, `stem`, `parent`, `exists()`, `is_dir()`, and `is_file()` are part of the interface.\n\n```python\nfrom zipp import Path\n\npath = Path(\"example.zip\") / \"pkg\" / \"__init__.py\"\n\nprint(path.name)      # __init__.py\nprint(path.suffix)    # .py\nprint(path.stem)      # __init__\nprint(path.parent)    # example.zip/pkg/\n```\n\n## Practical Pitfalls\n\n- `zipp.Path` does not sanitize archive member names. The Python docs explicitly warn that filenames inside a ZIP archive can contain `..` segments or absolute paths. If you turn archive paths into filesystem paths, validate them first with `os.path.abspath()` and `os.path.commonpath()`.\n- Prefer keyword arguments for text encoding: `read_text(encoding=\"utf-8\")` and `open(\"r\", encoding=\"utf-8\")`. The Python docs note that passing `encoding` positionally is not compatible with some earlier Python 3.10 and 3.11 patch releases.\n- Construct `Path` from an already-open `ZipFile` when you need write access. `Path(\"archive.zip\")` is convenient for reads, but write mode depends on how the underlying `ZipFile` was opened.\n\n## Version-Sensitive Notes\n\n- PyPI metadata for `zipp` 3.23.0 requires Python `>=3.9`.\n- The maintainer README includes a compatibility table showing that `zipp` regularly backports `zipfile.Path` improvements from newer CPython releases into older environments. Use the package when you need consistent ZIP-path behavior across Python versions instead of relying on the stdlib version available on a given interpreter.\n\n## Official Sources\n\n- Maintainer repository: https://github.com/jaraco/zipp\n- PyPI package page: https://pypi.org/project/zipp/\n- Python `zipfile.Path` documentation: https://docs.python.org/3/library/zipfile.html#path-objects\n"
  },
  {
    "path": "content/zustand/docs/zustand/javascript/DOC.md",
    "content": "---\nname: zustand\ndescription: \"Zustand state management for JavaScript/TypeScript with React hook stores, vanilla stores, persistence, and middleware\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"5.0.11\"\n  revision: 1\n  updated-on: \"2026-03-13\"\n  source: maintainer\n  tags: \"zustand,state,react,store,javascript\"\n---\n\n# Zustand State Management Guide (JavaScript/TypeScript)\n\nUse the official `zustand` package for both React state and non-React stores. Zustand gives you two main entry points:\n\n- `create` from `zustand` for React hook-based stores\n- `createStore` from `zustand/vanilla` for framework-agnostic stores\n\nThis guide targets `zustand` `5.0.11`.\n\n## Installation and Prerequisites\n\n```bash\nnpm install zustand\n```\n\nZustand does not require API keys, authentication, or environment variables.\n\nFor React usage, create stores with `create` and read them in components. For non-React code, tests, service modules, or custom integrations, use `createStore` from `zustand/vanilla`.\n\n## Create a React Store\n\nCreate a store once at module scope and export the hook.\n\n```javascript\n// stores/counter-store.js\nimport { create } from 'zustand'\n\nexport const useCounterStore = create((set) => ({\n  count: 0,\n  increment: () => set((state) => ({ count: state.count + 1 })),\n  incrementBy: (amount) => set((state) => ({ count: state.count + amount })),\n  reset: () => set({ count: 0 }),\n}))\n```\n\nUse selectors in components so each component subscribes only to the state it needs.\n\n```jsx\n// components/Counter.jsx\nimport { useCounterStore } from '../stores/counter-store'\n\nexport function Counter() {\n  const count = useCounterStore((state) => state.count)\n  const increment = useCounterStore((state) => state.increment)\n  const reset = useCounterStore((state) => state.reset)\n\n  return (\n    <div>\n      <p>{count}</p>\n      <button onClick={increment}>Increment</button>\n      <button onClick={reset}>Reset</button>\n    </div>\n  )\n}\n```\n\nZustand does not require a provider for this basic pattern.\n\n## Read and Update a Store Outside React\n\nStores created with `create` also expose the store API on the returned hook. This is useful for event handlers, non-React modules, or debugging code.\n\n```javascript\nimport { useCounterStore } from './stores/counter-store'\n\nconst unsubscribe = useCounterStore.subscribe((state) => {\n  console.log('count changed:', state.count)\n})\n\nuseCounterStore.getState().increment()\nuseCounterStore.setState({ count: 10 })\n\nunsubscribe()\n```\n\n## Async Actions\n\nAsync actions are regular functions in the store. Fetch data, then call `set` when the result is ready.\n\n```javascript\nimport { create } from 'zustand'\n\nexport const useUserStore = create((set) => ({\n  user: null,\n  loading: false,\n  error: null,\n  loadUser: async (id) => {\n    set({ loading: true, error: null })\n\n    try {\n      const response = await fetch(`/api/users/${id}`)\n\n      if (!response.ok) {\n        throw new Error(`Request failed with ${response.status}`)\n      }\n\n      const user = await response.json()\n      set({ user, loading: false })\n    } catch (error) {\n      set({ error: error instanceof Error ? error.message : String(error), loading: false })\n    }\n  },\n}))\n```\n\nUse it in a component the same way as any other action:\n\n```jsx\nimport { useEffect } from 'react'\nimport { useUserStore } from '../stores/user-store'\n\nexport function UserProfile({ userId }) {\n  const user = useUserStore((state) => state.user)\n  const loading = useUserStore((state) => state.loading)\n  const error = useUserStore((state) => state.error)\n  const loadUser = useUserStore((state) => state.loadUser)\n\n  useEffect(() => {\n    loadUser(userId)\n  }, [loadUser, userId])\n\n  if (loading) return <p>Loading...</p>\n  if (error) return <p>{error}</p>\n  if (!user) return null\n\n  return <pre>{JSON.stringify(user, null, 2)}</pre>\n}\n```\n\n## Persist State\n\nUse `persist` from `zustand/middleware` to save store data to browser storage. If you omit `storage`, `persist` uses `localStorage`.\n\n```javascript\nimport { create } from 'zustand'\nimport { createJSONStorage, persist } from 'zustand/middleware'\n\nexport const useSessionStore = create(\n  persist(\n    (set) => ({\n      token: null,\n      theme: 'light',\n      setToken: (token) => set({ token }),\n      setTheme: (theme) => set({ theme }),\n      clearSession: () => set({ token: null }),\n    }),\n    {\n      name: 'app-session',\n      storage: createJSONStorage(() => sessionStorage),\n      partialize: (state) => ({ token: state.token, theme: state.theme }),\n    },\n  ),\n)\n```\n\nUse `partialize` to persist only the fields that should survive reloads. Do not persist transient flags like in-flight loading state unless you explicitly want that behavior.\n\n## Create a Vanilla Store\n\nFor non-React usage, create a store with `createStore`.\n\n```javascript\n// stores/counter-store.js\nimport { createStore } from 'zustand/vanilla'\n\nexport const counterStore = createStore((set) => ({\n  count: 0,\n  increment: () => set((state) => ({ count: state.count + 1 })),\n  reset: () => set({ count: 0 }),\n}))\n```\n\nRead it directly:\n\n```javascript\nimport { counterStore } from './stores/counter-store'\n\ncounterStore.getState().increment()\n\nconst unsubscribe = counterStore.subscribe((state) => {\n  console.log(state.count)\n})\n\ncounterStore.getState().reset()\nunsubscribe()\n```\n\nBind a vanilla store to React with `useStore`:\n\n```jsx\nimport { useStore } from 'zustand'\nimport { counterStore } from '../stores/counter-store'\n\nexport function Counter() {\n  const count = useStore(counterStore, (state) => state.count)\n  const increment = useStore(counterStore, (state) => state.increment)\n\n  return <button onClick={increment}>{count}</button>\n}\n```\n\n## Common Middleware\n\n### Redux DevTools Integration\n\nUse `devtools` from `zustand/middleware` to inspect actions and state changes in Redux DevTools.\n\n```javascript\nimport { create } from 'zustand'\nimport { devtools } from 'zustand/middleware'\n\nexport const useTodoStore = create(\n  devtools(\n    (set) => ({\n      todos: [],\n      addTodo: (title) =>\n        set(\n          (state) => ({\n            todos: [...state.todos, { id: crypto.randomUUID(), title, done: false }],\n          }),\n          false,\n          'todo/add',\n        ),\n      toggleTodo: (id) =>\n        set(\n          (state) => ({\n            todos: state.todos.map((todo) =>\n              todo.id === id ? { ...todo, done: !todo.done } : todo,\n            ),\n          }),\n          false,\n          'todo/toggle',\n        ),\n    }),\n    { name: 'todo-store' },\n  ),\n)\n```\n\n### Subscribe to a Selected Slice Outside React\n\nIf you need subscriptions with selectors in a vanilla store, wrap the store with `subscribeWithSelector`.\n\n```javascript\nimport { createStore } from 'zustand/vanilla'\nimport { subscribeWithSelector } from 'zustand/middleware'\n\nexport const positionStore = createStore(\n  subscribeWithSelector((set) => ({\n    x: 0,\n    y: 0,\n    setPosition: (x, y) => set({ x, y }),\n  })),\n)\n\nconst unsubscribe = positionStore.subscribe(\n  (state) => state.x,\n  (x, previousX) => {\n    console.log('x changed', { x, previousX })\n  },\n)\n\npositionStore.getState().setPosition(10, 20)\nunsubscribe()\n```\n\n## Split Large Stores into Slices\n\nWhen a store grows, split it into slice creators and compose them into one store.\n\n```javascript\nimport { create } from 'zustand'\n\nconst createBearSlice = (set) => ({\n  bears: 0,\n  addBear: () => set((state) => ({ bears: state.bears + 1 })),\n})\n\nconst createFishSlice = (set) => ({\n  fish: 0,\n  addFish: () => set((state) => ({ fish: state.fish + 1 })),\n})\n\nexport const useZooStore = create((...args) => ({\n  ...createBearSlice(...args),\n  ...createFishSlice(...args),\n}))\n```\n\nThis keeps actions and state grouped without forcing everything into one large initializer function.\n\n## Important Notes and Pitfalls\n\n- `set` shallow-merges object updates by default. For nested objects, copy the nested object yourself.\n- `setState(nextState, true)` replaces the entire state object instead of merging. If you replace state, include everything you need to keep, including action functions.\n- In React components, subscribe to the smallest possible slice. Avoid selecting a large object if a component only needs one field or one action.\n- `persist` uses browser storage. Choose storage intentionally and avoid assuming `localStorage` or `sessionStorage` exists in server-rendered or test environments.\n- In server-rendered React apps, do not share a module-scoped store instance across requests for request-specific data. Create per-request stores or keep request-specific state on the client.\n- If you copy older examples from blogs, issues, or gists, confirm they match Zustand v5 APIs before using them in production code.\n\nNested updates should stay immutable:\n\n```javascript\nset((state) => ({\n  user: {\n    ...state.user,\n    profile: {\n      ...state.user.profile,\n      displayName: 'Ada',\n    },\n  },\n}))\n```\n\n## Useful Links\n\n- GitHub repository: `https://github.com/pmndrs/zustand`\n- Documentation landing page: `https://zustand.docs.pmnd.rs/`\n- `create` API: `https://zustand.docs.pmnd.rs/apis/create`\n- `createStore` API: `https://zustand.docs.pmnd.rs/apis/create-store`\n- Persist middleware: `https://zustand.docs.pmnd.rs/integrations/persisting-store-data`\n- Devtools middleware: `https://zustand.docs.pmnd.rs/middlewares/devtools`\n"
  },
  {
    "path": "docs/byod-guide.md",
    "content": "# Bring Your Own Docs\n\nContext Hub ships with a public registry of community-maintained docs and skills. But your team has internal APIs, proprietary SDKs, and company-specific patterns that will never be in a public registry. Today you paste those docs into chat manually, every session.\n\nYou don't have to. Build your own docs and skills locally, point your config at them, and they work exactly like the public ones.\n\n## Add your own docs\n\nCreate a content directory with your docs:\n\n```\nmy-content/\n  mycompany/\n    docs/\n      internal-api/\n        DOC.md           # frontmatter + LLM-optimized content\n        references/\n          auth.md\n          endpoints.md\n```\n\nThe DOC.md has standard frontmatter:\n\n```yaml\n---\nname: internal-api\ndescription: Our internal REST API\nlanguages: python\nversions: 2.0.0\ntags: internal, rest, api\n---\n# Internal API\n...\n```\n\nBuild it into a registry:\n\n```bash\nchub build my-content/ -o .chub-local/\n```\n\n## Add your own skills\n\nSame idea. Write a SKILL.md with any companion files:\n\n```\nmy-content/\n  mycompany/\n    skills/\n      deploy-staging/\n        SKILL.md\n        deploy.sh\n        config.template.yaml\n```\n\nThe build picks up skills automatically — no language or version fields needed.\n\n## Point your config at it\n\nAdd your local build output as a source in `~/.chub/config.yaml`:\n\n```yaml\nsources:\n  - name: community\n    url: https://cdn.aichub.org/v1\n  - name: internal\n    path: /path/to/.chub-local\n```\n\nNow everything works across both sources:\n\n```bash\nchub search \"api\"                          # searches public + private\nchub get mycompany/internal-api             # fetches your private doc\nchub get mycompany/deploy-staging           # fetches your private skill\n```\n\n## Enterprise use\n\nPut your content directory in a shared git repo or internal CDN. Everyone on the team points their config at it. Company docs and skills are available to every agent on every machine — without publishing anything publicly.\n\nIf a private id collides with a public one, use the `source:` prefix:\n\n```bash\nchub get internal:openai/chat           # your internal version\nchub get community:openai/chat         # the public version\n```\n\nOne CLI, one search, public and private content layered together.\n"
  },
  {
    "path": "docs/cli-reference.md",
    "content": "# CLI Reference\n\nFull command reference for Context Hub (`chub`).\n\n## Global Flags\n\n| Flag | Purpose |\n|------|---------|\n| `--json` | Structured JSON output (for agents and piping) |\n| `--version` | Print CLI version |\n| `--help` | Show help |\n\n## chub search [query]\n\nSearch docs and skills. No query lists all entries.\n\n| Flag | Purpose |\n|------|---------|\n| `--tags <csv>` | Filter by comma-separated tags |\n| `--lang <language>` | Filter by language |\n| `--limit <n>` | Max results (default: 20) |\n\n```bash\nchub search                          # list everything\nchub search \"stripe\"                 # fuzzy search by name/description\nchub search stripe/payments          # exact id — shows full detail\nchub search --tags automation        # filter by tag\n```\n\n**Exact ID match** returns the full entry detail (versions, languages, files). **Fuzzy search** returns a list of matches ranked by relevance.\n\n## chub get \\<ids...\\>\n\nFetch one or more docs or skills by ID. Auto-detects type (doc vs skill). Auto-infers language when only one variant exists.\n\n| Flag | Purpose |\n|------|---------|\n| `--lang <language>` | Language variant (js, py, ts, etc.) |\n| `--version <version>` | Specific doc version |\n| `--full` | Fetch all files, not just the entry point |\n| `--file <paths>` | Fetch specific file(s) by path (comma-separated) |\n| `-o, --output <path>` | Write to file or directory |\n\n```bash\nchub get stripe/api                  # single doc (auto-infers lang)\nchub get openai/chat-api --lang py   # specific language\nchub get pw-community/login-flows    # fetch a skill\nchub get stripe/api openai/chat-api  # multiple entries\nchub get stripe/api -o .context/     # save to file\n```\n\n### Incremental Fetch\n\nWhen a doc has reference files beyond the main entry point, the output includes a footer:\n\n```\n---\nAdditional files available (use --file to fetch):\n  references/advanced.md\n  references/errors.md\nExample: chub get acme/widgets --file references/advanced.md\n```\n\nFetch only what you need:\n\n```bash\nchub get acme/widgets --file references/advanced.md       # one file\nchub get acme/widgets --file advanced.md,errors.md         # multiple\nchub get acme/widgets --full                               # everything\n```\n\nWith `--json`, the response includes an `additionalFiles` array listing available reference files.\n\n### Multi-Language Docs\n\nIf a doc is available in multiple languages and `--lang` is not specified, the CLI lists available languages and asks you to choose.\n\nIf a doc has only one language, `--lang` is not required — it's auto-inferred.\n\n## chub annotate [id] [note]\n\nAttach persistent notes to a doc or skill. See [Feedback and Annotations](feedback-and-annotations.md) for the full guide.\n\n| Flag | Purpose |\n|------|---------|\n| `--clear` | Remove annotation for this entry |\n| `--list` | List all annotations |\n\n```bash\nchub annotate stripe/api \"Use idempotency keys for POST requests\"\nchub annotate stripe/api                   # view current note\nchub annotate stripe/api \"new note\"        # replaces previous\nchub annotate stripe/api --clear           # remove\nchub annotate --list                       # list all\n```\n\n## chub feedback [id] [rating] [comment]\n\nRate a doc or skill. Feedback is sent to the registry for maintainers. See [Feedback and Annotations](feedback-and-annotations.md) for details.\n\n| Flag | Purpose |\n|------|---------|\n| `--label <label>` | Feedback label (repeatable) |\n| `--lang <language>` | Language variant |\n| `--file <file>` | Specific file within the entry |\n| `--agent <name>` | AI tool name |\n| `--model <model>` | LLM model name |\n| `--status` | Show feedback and telemetry status |\n\nValid labels: `accurate`, `well-structured`, `helpful`, `good-examples`, `outdated`, `inaccurate`, `incomplete`, `wrong-examples`, `wrong-version`, `poorly-structured`.\n\n```bash\nchub feedback stripe/api up \"Clear examples, well structured\"\nchub feedback openai/chat down --label outdated --label wrong-examples\n```\n\n## chub update\n\nDownload or refresh the cached registry from remote sources.\n\n| Flag | Purpose |\n|------|---------|\n| `--force` | Re-download even if cache is fresh |\n| `--full` | Download full bundle for offline use |\n\n## chub cache status\\|clear\n\nManage the local cache.\n\n- `cache status` — shows cache info (sources, registries, sizes, last updated)\n- `cache clear` — removes cached content (`--force` to skip confirmation)\n\n## chub build \\<content-dir\\>\n\nBuild a registry from a local content directory. See the [Content Guide](content-guide.md) for how to structure your content.\n\n| Flag | Purpose |\n|------|---------|\n| `-o, --output <path>` | Output directory (default: `<content-dir>/dist`) |\n| `--base-url <url>` | Base URL for remote serving |\n| `--validate-only` | Validate content without building |\n\n```bash\nchub build my-content/                           # build to my-content/dist/\nchub build my-content/ -o dist/                  # custom output dir\nchub build my-content/ --validate-only           # validate only\n```\n\n## Piping Patterns\n\n```bash\n# Search, pick first result, fetch\nID=$(chub search \"stripe\" --json | jq -r '.results[0].id')\nchub get \"$ID\" -o .context/stripe.md\n\n# Fetch multiple docs at once\nchub get openai/chat stripe/api -o .context/\n\n# Check what additional files are available\nchub get acme/widgets --json | jq '.additionalFiles'\n\n# Fetch a specific reference file\nchub get acme/widgets --file references/advanced.md\n\n# List all annotations as JSON\nchub annotate --list --json\n```\n\n## Configuration\n\nConfig lives at `~/.chub/config.yaml`:\n\n```yaml\nsources:\n  - name: community\n    url: https://cdn.aichub.org/v1\n  - name: internal\n    path: /path/to/local/docs\n\nsource: \"official,maintainer,community\"   # trust policy\nrefresh_interval: 86400                   # cache TTL in seconds (24h)\ntelemetry: true                           # anonymous usage analytics (passive)\nfeedback: true                            # allow chub feedback to send ratings (explicit)\n```\n\n### Telemetry\n\nAnonymous usage analytics help improve the registry. No personally identifiable information is collected.\n\nOpt out:\n```yaml\ntelemetry: false\n```\nOr via environment variable: `CHUB_TELEMETRY=0`\n\n### Feedback\n\nThe `chub feedback` command sends doc/skill ratings to maintainers. This is separate from telemetry — you can disable passive analytics while still being able to rate docs.\n\nOpt out:\n```yaml\nfeedback: false\n```\nOr via environment variable: `CHUB_FEEDBACK=0`\n\n### Multi-Source\n\nWhen multiple sources define the same entry ID, prefix with the source name to disambiguate:\n\n```bash\nchub get internal:openai/chat\n```\n"
  },
  {
    "path": "docs/content-guide.md",
    "content": "# Content Guide\n\nHow to create docs and skills for Context Hub.\n\n## Directory Structure\n\nContent is organized by author (vendor/org), then by type (`docs` or `skills`), then by entry name:\n\n```\nmy-content/\n  acme/\n    docs/\n      widgets/\n        DOC.md                    # single-language doc\n        references/\n          advanced.md             # additional reference file\n      client/\n        javascript/\n          DOC.md                  # multi-language: JS variant\n        python/\n          DOC.md                  # multi-language: Python variant\n      api/\n        v1/\n          DOC.md                  # multi-version: v1\n        v2/\n          DOC.md                  # multi-version: v2\n    skills/\n      deploy/\n        SKILL.md                  # a skill\n```\n\n### Single-language docs\n\nPlace `DOC.md` directly in the entry directory:\n\n```\nauthor/docs/entry-name/DOC.md\n```\n\n### Multi-language docs\n\nCreate a subdirectory per language:\n\n```\nauthor/docs/entry-name/javascript/DOC.md\nauthor/docs/entry-name/python/DOC.md\n```\n\n### Multi-version docs\n\nWhen an API has breaking changes across major versions, create a subdirectory per version:\n\n```\nauthor/docs/entry-name/\n  v1/\n    DOC.md                  # versions: \"1.0.0\"\n  v2/\n    DOC.md                  # versions: \"2.0.0\"\n```\n\nBoth DOC.md files must share the same `name` in frontmatter. The build groups them into a single registry entry with multiple versions. The highest version becomes the `recommendedVersion` — what agents get by default.\n\nYou can combine multi-version with multi-language:\n\n```\nauthor/docs/entry-name/\n  v1/\n    javascript/\n      DOC.md\n    python/\n      DOC.md\n  v2/\n    javascript/\n      DOC.md\n    python/\n      DOC.md\n```\n\nAgents request a specific version with `--version`:\n\n```bash\nchub get author/entry-name                    # latest version (recommended)\nchub get author/entry-name --version 1.0.0    # specific version\n```\n\nIf a requested version doesn't exist, the CLI lists available versions.\n\n### Skills\n\nPlace `SKILL.md` in the entry directory:\n\n```\nauthor/skills/entry-name/SKILL.md\n```\n\n### Reference files\n\nAdditional files (examples, advanced topics, error references) go alongside the entry file:\n\n```\nauthor/docs/widgets/\n  DOC.md\n  references/\n    advanced.md\n    errors.md\n```\n\nThese are discoverable via `chub get` (shown in the footer) and fetchable with `--file` or `--full`.\n\n## Frontmatter\n\nEvery `DOC.md` and `SKILL.md` starts with YAML frontmatter.\n\n### DOC.md frontmatter\n\n```yaml\n---\nname: widgets\ndescription: \"Acme widget API for creating and managing widgets\"\nmetadata:\n  languages: \"javascript\"\n  versions: \"2.0.0\"\n  revision: 1\n  updated-on: \"2026-01-01\"\n  source: maintainer\n  tags: \"acme,widgets,api\"\n---\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `name` | Yes | Entry name (used in the ID: `author/name`) |\n| `description` | Yes | Short description for search results |\n| `metadata.languages` | Yes | Language of this doc variant |\n| `metadata.versions` | Yes | Package/SDK version this doc covers (the version on npm or pypi) |\n| `metadata.revision` | Yes | Content revision number (monotonically increasing, starts at 1) |\n| `metadata.updated-on` | Yes | Date this content was last revised |\n| `metadata.source` | Yes | Trust level: `official`, `maintainer`, or `community` |\n| `metadata.tags` | No | Comma-separated tags for filtering |\n\n### SKILL.md frontmatter\n\n```yaml\n---\nname: deploy\ndescription: \"Deployment automation skill for CI/CD pipelines\"\nmetadata:\n  revision: 1\n  updated-on: \"2026-01-01\"\n  source: community\n  tags: \"deploy,ci,automation\"\n---\n```\n\nSkills have the same fields as docs except `languages` and `versions` are not required (skills are language-agnostic).\n\n## Versioning Guide\n\n### Package version vs API version\n\nThe `versions` field always refers to the **package/SDK version** — the version number on npm or pypi. This is what agents can detect from `package.json` or `requirements.txt`.\n\nIf a library has a separate API versioning scheme (like Stripe's dated API versions `2024-12-18.acacia`), document that within the content body. The frontmatter `versions` stays as the package version.\n\n### API-level versioning\n\nWhen an API has fundamentally different versions (different endpoints, different auth, different request/response shapes), use the entry **name** to distinguish them:\n\n```\nstripe/docs/payments-api-v1/DOC.md    # name: payments-api-v1\nstripe/docs/payments-api-v2/DOC.md    # name: payments-api-v2\n```\n\nThese become separate entries in the registry (`stripe/payments-api-v1` and `stripe/payments-api-v2`), each with their own package version tracking.\n\n### Updating content\n\nWhen you improve content for the same package version (fix examples, add details, clarify wording):\n\n1. Bump `revision` (e.g., 1 → 2)\n2. Update `updated-on` to today's date\n3. Keep `versions` the same\n\nTogether, `revision` and `updated-on` give agents a clear signal of content freshness.\n\n## Writing Content\n\nContent is markdown, written for LLM consumption. Keep these in mind:\n\n- **Be direct.** Agents don't need introductions or marketing. Start with what the API does and how to use it.\n- **Show code first.** A working example is worth more than a paragraph of explanation.\n- **Cover the common case.** Don't exhaustively document every option. Cover what agents will actually need 90% of the time.\n- **Use reference files for depth.** Put advanced topics, error handling, and edge cases in separate reference files rather than making the main doc too long.\n\n## Building\n\nUse `chub build` to compile your content directory into a registry:\n\n```bash\nchub build my-content/                           # build to my-content/dist/\nchub build my-content/ -o dist/                  # custom output directory\nchub build my-content/ --validate-only           # validate without building\n```\n\nThe build process:\n1. Discovers all `DOC.md` and `SKILL.md` files\n2. Validates frontmatter (checks required fields)\n3. Generates `registry.json` with entry metadata\n4. Copies content files to the output directory\n\n### Validation\n\nRun `--validate-only` to check your content without building:\n\n```bash\nchub build my-content/ --validate-only\n```\n\nThis reports the number of docs and skills found, and flags any frontmatter errors.\n\n### Using built content locally\n\nPoint your config at the build output to use it alongside the public registry:\n\n```yaml\n# ~/.chub/config.yaml\nsources:\n  - name: community\n    url: https://cdn.aichub.org/v1\n  - name: my-team\n    path: /path/to/my-content/dist\n```\n\nNow `chub search` and `chub get` cover both public and your local content.\n"
  },
  {
    "path": "docs/design.md",
    "content": "# Context Hub (chub) - Design Document\n\n## What is Context Hub?\n\nContext Hub bridges the gap between rapidly evolving APIs and LLM knowledge cutoffs. It's a repository of curated, LLM-optimized documentation and skills that AI agents (and humans) can search and retrieve via a CLI.\n\nThere are two kinds of content, with a fundamental distinction:\n\n- **Docs** (\"what to know\") — API/SDK reference documentation, factual knowledge that fills knowledge cutoff gaps. Large, detailed, fetched on-demand for a specific task.\n- **Skills** (\"how to do it\") — Behavioral instructions, coding patterns, automation playbooks. Smaller, actionable, can be installed into agent skill directories for persistent availability.\n\nEach entry also has a **source** field (`official` | `maintainer` | `community`) for trust/quality signaling. Users control which sources agents see via `~/.chub/config.yaml`.\n\n## Architecture\n\n```\nContent repo (source of truth)\n  ↓ chub build → registry.json + content tree\nCDN (serves registry + individual files + optional full bundle)   ← remote source\n  ↓ CLI fetches from here\n~/.chub/ (local cache)                                            ← cached remote data\n  ↓ CLI reads from here\nAgent/Human (consumes docs via stdout or -o file)\n  ↑ CLI also reads directly from\nLocal folders (private/internal docs)                             ← local source\n```\n\nThe CLI supports **multiple sources** — both remote CDNs and local folders. Entries from all sources are merged.\n\n## Design Decisions & Rationale\n\n### Why separate \"docs\" and \"skills\"?\nWe initially treated all content uniformly — just tags, no rigid types. But docs and skills have fundamentally different access patterns:\n\n| | Docs | Skills |\n|---|---|---|\n| Purpose | Reference knowledge (\"what to know\") | Behavioral instructions (\"how to do it\") |\n| Size | Large (10K-50K+ tokens) | Small (<500 lines entry point) |\n| Lifecycle | Ephemeral, fetched per-task | Can be persistent, installed into agent |\n| Discovery | Agent explicitly searches and fetches | Agent can auto-discover from filesystem |\n| Install target | `.context/` or any file | `.claude/skills/`, `.cursor/skills/`, etc. |\n| Language/version | Yes — per-language, per-version variants | No — skills are typically language-agnostic |\n\nThis distinction drives the registry format split into `docs[]` and `skills[]`. The CLI uses a single `chub get <id>` command that auto-detects the type.\n\n### Why `docs[]` and `skills[]` in the registry (not `entries[]`)?\nThe original format had a single `entries[]` array with a `provides` field to indicate doc/skill. We split it because:\n\n1. **Different schemas**: Docs need `languages[].versions[]` nesting. Skills are flat — no language or version, just `name`, `path`, `files`.\n2. **Array membership IS the type**: No need for a `provides` field. A doc is in `docs[]`, a skill is in `skills[]`.\n3. **Bundled entries**: When a topic has both DOC.md and SKILL.md, they appear as separate items in their respective arrays. Clean separation.\n4. **CLI mapping**: `chub get` searches both arrays and auto-detects type. `chub search` searches both.\n\n### Why skills have no language or version?\nSkills are behavioral instructions (\"how to integrate Stripe\", \"how to write Playwright login flows\"). They're typically language-agnostic or written for a single context. Adding language/version nesting would add complexity without value — a skill author who needs Python and TypeScript variants can create two separate skill entries.\n\nDocs, on the other hand, have fundamentally different content per language (Python SDK vs JavaScript SDK) and evolve with API versions.\n\n### Why a single `get` command (not `get docs` / `get skills`)?\nWe originally had `chub get docs <id>` and `chub get skills <id>` as separate subcommands. We simplified to `chub get <id>` because the CLI can auto-detect the type from the registry (docs have `languages[]`, skills don't). The user shouldn't need to know internal taxonomy to fetch content. `--lang` and `--version` flags apply when the entry is a doc and are silently ignored for skills.\n\n### Why DOC.md and SKILL.md (not just SKILL.md)?\nWe considered using SKILL.md for everything since the Agent Skills spec is the format standard. But calling a 50K API reference \"SKILL.md\" is semantically misleading — agents that scan for skills would load doc descriptions into their system prompt (wasting ~100 tokens per doc entry), and might \"activate\" a doc when the user just wants to write code.\n\n### Why `--lang` flag instead of positional argument?\nOriginally: `chub get openai-chat python`. Changed to: `chub get openai/chat-api --lang python`.\n\nReasons:\n1. Multi-id support (`chub get openai/chat-api stripe/payments`) would make a positional language argument ambiguous\n2. Language can be auto-inferred when an entry has only one — the flag is only needed for disambiguation\n3. Flags are self-documenting; a bare `python` after an id is ambiguous to readers\n\n### Why multi-id support?\nAgents often need multiple entries in one operation. Rather than looping, `chub get openai/chat-api stripe/payments` fetches both. Output is concatenated with `---` separators for stdout, or written as separate files when `-o` points to a directory.\n\n### Why one CLI, not two?\nWe considered separate tools for docs and skills. Rejected because they share the same registry, config, sources, search, and cache infrastructure.\n\n### Why 5+1 commands?\nWe started with 8 commands and trimmed to 5 core + 1 build: `search`, `get`, `update`, `cache`, `feedback`, and `build`. `list` and `info` were merged into `search`. `get docs` and `get skills` were merged into `get` with auto-detection.\n\n### Why `source` field + config-level filtering?\nEach entry has `source: \"official\" | \"maintainer\" | \"community\"`. The human controls trust policy via `~/.chub/config.yaml`. An enterprise can restrict agents to `source: official,maintainer` without the agent needing to know about quality tiers.\n\n### Why tags instead of rigid categories?\nRather than rigid sub-types, entries use free-form tags. This is flexible — new categories emerge without schema changes.\n\n### Why progressive disclosure?\nA monolithic 50K-token doc file wastes context. Each entry is a directory with a small entry point (DOC.md or SKILL.md, ~500 lines max) that links to detailed reference files. The agent reads the overview first, then selectively loads only what it needs.\n\nThe `--full` flag exists for when you want everything. With `-o <dir>`, `--full` writes individual files preserving directory structure so relative links resolve on disk. Without `-o`, it concatenates to stdout with `# FILE:` headers.\n\n### Why hybrid data strategy?\nThree approaches were considered:\n1. **Full bundle** (download everything) — simple but doesn't scale\n2. **Index + on-demand** (fetch individual docs) — lightweight but needs network per doc\n3. **Hybrid** (chosen) — registry-only by default, on-demand doc fetching, optional full bundle\n\n### Why author-prefixed IDs?\nIDs are always `author/name` — e.g., `openai/chat-api`, `stripe/payments`, `playwright-community/login-flows`. The author is the top-level directory name in the content repo; the name comes from frontmatter. This eliminates name collisions by construction — two authors can both have a `chat` entry, but their ids differ (`openai/chat-api` vs `mycompany/chat`). This is the same pattern as npm scopes, Docker images, and GitHub repos.\n\n### Why `source:` prefix (not `source/`) for multi-source?\nWhen multiple sources define the same id, the user disambiguates with a `source:` prefix: `internal:openai/chat-api` vs `community:openai/chat-api`. We use colon instead of slash because ids already contain slashes (`author/name`). Using `source/author/name` would be ambiguous — is `internal` the source or the author?\n\n### Why multi-source?\nTeams often have internal/proprietary docs alongside the public community registry. The CLI supports multiple sources — remote CDNs and local folders. Entries are merged, and IDs are namespaced with `source:` only when there's a collision across sources.\n\n---\n\n## Content Repository & Build Pipeline\n\n### Content repo structure\n\nContent is organized by **author directories**. Each author gets a top-level directory and organizes their docs and skills inside it:\n\n```\ncontent-repo/\n├── stripe/                              # author directory\n│   ├── registry.json                    # OPTIONAL: author manages own index\n│   ├── docs/\n│   │   └── payments/                    # entry directory\n│   │       ├── DOC.md                   # frontmatter: name, description, languages, versions\n│   │       ├── references/\n│   │       │   └── webhooks.md\n│   │       └── examples/\n│   │           └── checkout.py\n│   └── skills/\n│       └── integration/                 # entry directory\n│           ├── SKILL.md\n│           └── scripts/\n│               └── setup.sh\n├── openai/                              # no registry.json → auto-discover\n│   └── docs/\n│       └── chat/\n│           ├── DOC.md                   # languages: \"python,javascript\", versions: \"1.52.0\"\n│           └── references/\n│               └── streaming.md\n└── playwright-community/\n    └── skills/\n        └── login-flows/\n            ├── SKILL.md\n            └── helpers/\n                └── login-util.ts\n```\n\n**Convention**: `<author>/{docs,skills}/<entry-name>/` with DOC.md or SKILL.md at root.\n\n### The entry directory is the unit of content\n\nFollowing the convention established by Anthropic and OpenAI skill repos:\n- SKILL.md (or DOC.md) lives in a directory\n- All other files in that directory are companions — installed together with `--full`\n- References use **relative paths** (e.g., `[Auth](references/auth.md)`)\n- `--full -o <dir>` writes individual files preserving directory structure, so relative links resolve on disk\n- Without `--full`, only the entry point (DOC.md or SKILL.md) is fetched\n\n### Two discovery modes per author\n\n#### 1. Author provides `registry.json`\nIf an author directory contains `registry.json`, the build uses it directly. Same schema as the top-level registry (with `docs[]` and `skills[]`). Paths are prefixed with the author directory name during merge.\n\nThis is for authors with complex organization who want full control over their index.\n\n#### 2. Auto-discovery (no `registry.json`)\nThe build walks the author directory, finds all DOC.md and SKILL.md files, and parses frontmatter to generate registry entries.\n\n**DOC.md frontmatter:**\n```yaml\n---\nname: chat-api\ndescription: OpenAI Chat API - completions, streaming, function calling\nmetadata:\n  languages: \"python,javascript,typescript\"    # comma-separated, multi-lang\n  versions: \"1.52.0\"                           # comma-separated, multi-version\n  updated-on: \"2026-01-15\"\n  source: maintainer\n  tags: \"openai,chat,llm\"\n---\n```\n\n**SKILL.md frontmatter** (no language/version needed):\n```yaml\n---\nname: login-flows\ndescription: Login flow automation patterns for Playwright\nmetadata:\n  updated-on: \"2026-01-15\"\n  source: community\n  tags: \"browser,playwright,automation\"\n---\n```\n\n### Multi-language and multi-version in frontmatter\n\nA single DOC.md can declare multiple languages and versions (comma-separated strings). The build expands this into the registry schema — multiple `languages[]` entries, each with multiple `versions[]`, all pointing to the same directory path.\n\nThis means one doc file can serve Python, JavaScript, and TypeScript users if the content is language-agnostic enough. When content differs per language, authors create separate DOC.md files in separate directories — the build groups them by matching `name`.\n\n### Version-specific docs\n\nWhen an API has breaking changes across versions, the author creates separate DOC.md files:\n\n```\nopenai/\n└── docs/\n    └── chat/\n        ├── v1/\n        │   ├── DOC.md              # versions: \"1.52.0,1.51.0\", languages: \"python,javascript\"\n        │   └── references/\n        │       └── streaming.md\n        └── v2/\n            ├── DOC.md              # versions: \"2.0.0\", languages: \"python,javascript\"\n            └── references/\n                ├── streaming.md\n                └── structured-outputs.md\n```\n\nBoth DOC.md files have `name: chat-api` (under the `openai/` author directory) — they get grouped into `id: openai/chat-api`, into one `docs[]` entry with multiple versions pointing to different paths. `recommendedVersion` is the highest semver. `chub get openai/chat-api` gets the latest; `--version 1.52.0` gets the older docs.\n\n### Language-specific docs\n\nFor different content per language:\n```\nstripe/\n└── docs/\n    └── payments/\n        ├── python/\n        │   └── DOC.md          # languages: \"python\", versions: \"14.0.0\"\n        └── javascript/\n            └── DOC.md          # languages: \"javascript\", versions: \"14.0.0\"\n```\n\nSame `name: payments` under `stripe/` → both contribute to `id: stripe/payments`. Different languages, different paths, different content.\n\n### The `chub build` command\n\n```bash\nchub build <content-dir> [options]\n```\n\nOptions:\n- `-o, --output <dir>` — output directory (default: `<content-dir>/dist`)\n- `--base-url <url>` — set `base_url` in registry (for CDN deployment)\n- `--validate-only` — check frontmatter and structure without writing output\n- `--json` — output build summary as JSON\n\nBuild steps:\n1. List top-level directories in `<content-dir>` (author directories)\n2. For each author directory:\n   - If `registry.json` exists → use it directly, prefix paths\n   - Else → auto-discover DOC.md/SKILL.md, parse frontmatter, group by `name`\n3. Merge all author entries into one registry (ids are `author/name`, so collisions are rare)\n4. Write `registry.json` to output dir\n5. Copy content tree to output dir (preserving structure)\n6. Print summary: N docs, N skills, N warnings\n\n### Validation rules\n\n- DOC.md must have `name`, `description`, `metadata.languages`, `metadata.versions`\n- SKILL.md must have `name`, `description` (no language/version required)\n- Warn on missing `metadata.source` (default: \"community\")\n- Warn on missing `metadata.tags`\n- Error on duplicate id (rare since ids are `author/name`)\n- If both DOC.md and SKILL.md exist in the same directory, `name` must match\n\n### Publishing to CDN\n\nThe build output is a static directory ready to serve:\n```\ndist/\n├── registry.json                              # Generated index\n├── stripe/docs/payments/DOC.md               # Content files (copied)\n├── stripe/docs/payments/references/...\n├── openai/docs/chat-api/DOC.md\n└── playwright-community/skills/login-flows/SKILL.md\n```\n\nUpload `dist/` to any static file host (S3, CloudFlare R2, GitHub Pages). The CLI fetches `registry.json` first, then individual files on demand.\n\n---\n\n## CLI Interface\n\n### Commands\n\n| Command | Purpose | Key Options |\n|---|---|---|\n| `chub search [query]` | Search (no query = list all, exact id = detail) | `--tags`, `--lang`, `--limit`, `--json` |\n| `chub get <ids...>` | Fetch docs or skills (auto-detects type) | `--lang`, `--version`, `--full`, `-o <path>`, `--json` |\n| `chub update` | Refresh cached registry | `--force`, `--full` |\n| `chub cache status\\|clear` | Manage local cache | |\n| `chub build <content-dir>` | Build registry from content | `-o`, `--base-url`, `--validate-only`, `--json` |\n\n### How `search` works\n- `chub search` — lists all entries (replaces `list`)\n- `chub search openai/chat-api` — exact id match shows full detail (replaces `info`)\n- `chub search \"stripe\"` — fuzzy search across id, name, description, tags\n- `chub search --tags browser` — filtered listing\n- Results show `[doc]` or `[skill]` type labels\n\n### How `get` works\n- `chub get openai/chat-api --lang python` — auto-detects doc, fetches DOC.md\n- `chub get openai/chat-api --full` — fetch all files in the entry\n- `chub get openai/chat-api --full -o .context/openai/` — write individual files preserving structure\n- `chub get openai/chat-api stripe/payments --lang js` — fetch multiple entries at once\n- `chub get pw-community/login-flows` — auto-detects skill, fetches SKILL.md\n- `chub get nonexistent/thing` → error: `Entry \"nonexistent/thing\" not found.`\n\n### Language inference\n- Entry has one language → auto-selected, no `--lang` needed\n- Entry has multiple languages, no `--lang` → error with suggestion\n- `--lang` applies to all ids in a multi-id command\n- `--lang` and `--version` apply to doc entries, silently ignored for skills\n\n### Output modes\n- **Default**: Human-friendly, colored terminal output\n- **`--json`**: Structured JSON to stdout (no color escapes)\n- **`-o <path>`**: Write content to file, print short confirmation to stderr\n- **`-o <dir>/`**: Write each entry as separate file when fetching multiple\n- **`--full -o <dir>`**: Write individual files preserving directory structure\n\n### Agent piping patterns\n```bash\n# Get the top search result's id\nchub search \"stripe payments\" --json | jq -r '.results[0].id'\n\n# Full pipeline: search → pick best → fetch → write to file\nID=$(chub search \"stripe payments\" --json | jq -r '.results[0].id')\nchub get \"$ID\" --lang js -o .context/stripe.md\n\n# Fetch top 3 results\nchub search \"stripe\" --json | jq -r '.results[:3][].id' | xargs chub get -o .context/\n\n# Fetch multiple at once\nchub get openai/chat-api stripe/payments -o .context/\n\n# Install a skill into Claude Code's skill directory\nchub get pw-community/login-flows -o .claude/skills/login-flows/SKILL.md\n\n# Install a skill with all companion files\nchub get pw-community/login-flows --full -o .claude/skills/login-flows/\n\n# Multi-source: disambiguate with source: prefix\nchub get internal:openai/chat-api\n```\n\n---\n\n## Data Strategy\n\n### Content format: Agent Skills compatible\n\nAll content follows the [Agent Skills spec](https://agentskills.io/specification). Both DOC.md and SKILL.md use the standard's frontmatter format (`name`, `description`, optional `metadata`). This makes chub content interoperable with Claude Code, Cursor, Codex, OpenCode, and 30+ agents.\n\n### What the CDN serves\n```\ncdn.aichub.org/v1/\n├── registry.json                                        # Index (~100KB)\n├── bundle.tar.gz                                        # Full bundle (optional)\n├── stripe/docs/payments/DOC.md                         # Entry point\n├── stripe/docs/payments/references/webhooks.md         # Supporting file\n└── playwright-community/skills/login-flows/SKILL.md    # Skill\n```\n\n### How the CLI uses it\n1. `chub update` → fetches `registry.json` only (~100KB), caches locally\n2. `chub search` → searches local registry (no network)\n3. `chub get <id>` → auto-detects type, fetches entry point (DOC.md or SKILL.md), checks cache first\n4. `chub get <id> --full` → fetches all files listed in registry\n6. `chub update --full` → downloads entire `bundle.tar.gz` for offline use\n\n### Local cache layout\n```\n~/.chub/\n├── config.yaml              # User config (optional, created manually)\n└── sources/                 # Per-source cache (remote sources only)\n    ├── community/\n    │   ├── registry.json    # Cached index for this source\n    │   ├── meta.json        # { lastUpdated, registryHash }\n    │   └── data/            # Cached content (on-demand or full bundle)\n    └── another-remote/\n        └── ...\n```\n\nLocal path sources are **not cached** — the CLI reads directly from the configured `path`.\n\n---\n\n## Schemas\n\n### Registry (`registry.json`)\n```json\n{\n  \"version\": \"1.0.0\",\n  \"base_url\": \"https://cdn.aichub.org/v1\",\n  \"generated\": \"2026-02-02T00:00:00.000Z\",\n  \"docs\": [\n    {\n      \"id\": \"openai/chat-api\",\n      \"name\": \"chat-api\",\n      \"description\": \"Chat completions with GPT models\",\n      \"source\": \"maintainer\",\n      \"tags\": [\"openai\", \"chat\", \"llm\"],\n      \"languages\": [\n        {\n          \"language\": \"python\",\n          \"versions\": [\n            {\n              \"version\": \"1.52.0\",\n              \"path\": \"openai/docs/chat-api/v1\",\n              \"files\": [\"DOC.md\", \"references/streaming.md\"],\n              \"size\": 42000,\n              \"lastUpdated\": \"2026-01-15\"\n            }\n          ],\n          \"recommendedVersion\": \"1.52.0\"\n        }\n      ]\n    }\n  ],\n  \"skills\": [\n    {\n      \"id\": \"playwright-community/login-flows\",\n      \"name\": \"login-flows\",\n      \"description\": \"Login flow automation patterns for Playwright\",\n      \"source\": \"community\",\n      \"tags\": [\"browser\", \"playwright\"],\n      \"path\": \"playwright-community/skills/login-flows\",\n      \"files\": [\"SKILL.md\", \"helpers/login-util.ts\"],\n      \"size\": 12000,\n      \"lastUpdated\": \"2026-01-15\"\n    }\n  ]\n}\n```\n\n**Doc entry fields:**\n- `id` — unique identifier in `author/name` format, used by `chub get <id>`\n- `name` — short name from frontmatter (the part after the author prefix)\n- `description` — short description for search results\n- `source` — `official` (library author), `maintainer` (context-hub team), `community`\n- `tags` — free-form tags for filtering\n- `languages[]` — per-language grouping\n  - `versions[]` — per-version, each with `path`, `files`, `size`, `lastUpdated`\n  - `recommendedVersion` — default version to fetch\n\n**Skill entry fields:**\n- `name`, `description`, `source`, `tags` — same as docs\n- `path` — directory path (relative to `base_url` or source root)\n- `files` — all files in the entry directory\n- `size`, `lastUpdated` — flat, no language/version nesting\n\n### Config (`~/.chub/config.yaml`)\n```yaml\n# Multi-source (recommended)\nsources:\n  - name: community\n    url: https://cdn.aichub.org/v1       # Remote CDN\n  - name: internal\n    path: /path/to/local/docs                # Local folder (build output)\n\n# Trust policy: which entry sources to show\nsource: \"official,maintainer,community\"\n\n# Optional\nrefresh_interval: 86400                       # Cache TTL in seconds (24h)\n```\n\n**Backward compat:** If no `sources` array, falls back to single `cdn_url` field (or `CHUB_BUNDLE_URL` env var) as a source named \"default\".\n\n**Local source:** Can be either a raw content repo or a `chub build` output directory — both must contain `registry.json` at root with the standard schema.\n\n---\n\n## Agent Skills Compatibility\n\nContent follows the [Agent Skills open standard](https://agentskills.io/specification), supported by Claude Code, Cursor, Codex, OpenCode, and 30+ agents.\n\n### How chub relates to the Agent Skills ecosystem\n\n| Layer | Agent Skills spec | npx skills (Vercel) | chub |\n|---|---|---|---|\n| Format | SKILL.md with frontmatter | SKILL.md | SKILL.md + DOC.md |\n| Discovery | Local filesystem scan | `npx skills search` (git repos) | `chub search` (registry index) |\n| Distribution | None (copy files) | Git repos | CDN + local folders |\n| Versioning | None | None | Per-entry, per-language (docs) |\n| Multi-language | None | None | Yes (docs) |\n| Trust/quality | None | None | `source` field + config filtering |\n| Build pipeline | None | None | `chub build` |\n\n### Why adopt the standard?\nMakes chub content interoperable with the broader agent ecosystem. A skill fetched via `chub get` can be piped directly into any agent's skill directory and discovered natively.\n\n### How chub extends it\n- Registry-based search and discovery over network\n- Multi-source aggregation (CDN + local folders)\n- Trust/quality filtering via `source` field\n- Progressive disclosure with `--full` flag\n- DOC.md for reference knowledge (uses same frontmatter format)\n- Build pipeline to generate registry from content directories\n\n---\n\n## Project Structure\n\n```\nchub-first-draft/\n├── cli/\n│   ├── package.json              # npm package with bin entry\n│   ├── bin/chub                  # #!/usr/bin/env node entry point\n│   ├── src/\n│   │   ├── index.js              # Commander setup, global --json, preAction cache hook\n│   │   ├── commands/\n│   │   │   ├── search.js         # search / list / info (all in one)\n│   │   │   ├── get.js            # get command (auto-detects doc/skill)\n│   │   │   ├── build.js          # build registry from content directory\n│   │   │   ├── update.js         # refresh registry / full bundle\n│   │   │   └── cache.js          # cache status / clear\n│   │   └── lib/\n│   │       ├── config.js         # Load config.yaml, merge env vars, defaults\n│   │       ├── cache.js          # Registry fetch, on-demand doc fetch, bundle extract\n│   │       ├── registry.js       # Load registry, search/filter/query, resolve paths\n│   │       ├── frontmatter.js    # YAML frontmatter parser\n│   │       ├── output.js         # Dual-mode output (human with chalk / JSON)\n│   │       └── normalize.js      # Language aliases (js→javascript, py→python)\n├── plans-for-reference/          # Archived design plans\n├── NARRATIVE.md                  # Product pitch\n├── DESIGN.md                     # This file\n├── .gitignore\n└── package.json                  # Root workspace\n```\n\n## Dependencies\n\n- `commander` ^12 — CLI framework\n- `chalk` ^5 — Terminal colors\n- `yaml` ^2 — Config + frontmatter parsing\n- `tar` ^7 — Bundle extraction (for `--full` mode)\n- Node.js >= 18 (built-in `fetch`, no `node-fetch` needed)\n\n## Future considerations\n\n- **`skills_dir` / `docs_dir` config** — default output directories for skills and docs\n- **Agent detection** — auto-detect installed agents and write to the right skill directory\n- **`chub install`** — dedicated install command if the piping pattern proves too verbose\n- **Usage telemetry** — agents report which docs/skills they used, enabling quality signals\n- **CI/CD integration** — GitHub Action that runs `chub build` and publishes to CDN on push\n\n## Reference\n\n- Agent Skills specification: https://agentskills.io/specification\n- Vercel Skills CLI: https://github.com/vercel-labs/skills\n"
  },
  {
    "path": "docs/features/agent-annotations.md",
    "content": "# Feature: Agent Annotations\n\n## Overview\n\nAgents can annotate docs and skills with gotchas, tips, and experiences learned while building with them. Two workflows:\n\n1. **Private annotations** — stored locally in `~/.chub/annotations/`, automatically included when the agent fetches the same doc/skill again. Personal knowledge base that improves with use.\n2. **Suggest to author** (future) — push annotations upstream as structured feedback. Mechanism TBD (author dashboard, GitHub issue, etc.). For now, just ensure the annotation format is structured enough to be submittable later.\n\n## Annotation format\n\nStored as markdown files at `~/.chub/annotations/<id>.md` (e.g. `~/.chub/annotations/openai/chat.md`):\n\n```markdown\n---\ndoc_id: openai/chat\ncreated: 2026-02-02\nupdated: 2026-02-02\n---\n\n## Gotcha: streaming requires explicit close\n\nWhen using streaming with function calling, you must explicitly close the stream\nafter the final function call response. The doc doesn't mention this — if you\ndon't close it, the connection hangs for 30 seconds before timing out.\n\n## Tip: batch function calls\n\nYou can pass multiple function definitions and the model will call them in\nparallel. Much faster than sequential calls for independent operations.\n```\n\nEach annotation is a `##` section. Agents append new sections. The frontmatter tracks which doc it's for and when it was last updated.\n\n## CLI commands\n\n### `chub annotate <id> <message>`\n\nAdd an annotation to a doc or skill.\n\n```bash\n# Agent adds a gotcha after encountering an issue\nchub annotate openai/chat \"streaming requires explicit close when using function calling\"\n\n# Add with a type prefix\nchub annotate openai/chat --type gotcha \"streaming requires explicit close...\"\nchub annotate openai/chat --type tip \"batch function calls for parallel execution\"\n```\n\n- Creates `~/.chub/annotations/openai/chat.md` if it doesn't exist\n- Appends a new `## Gotcha:` or `## Tip:` section\n- Updates the `updated` timestamp in frontmatter\n\n### `chub get <id>` — automatically includes annotations\n\nWhen fetching a doc, check if annotations exist for that id. If so, append them after the doc content under a `# Annotations` heading.\n\n```bash\nchub get openai/chat\n# Returns: doc content + \"# Annotations\\n## Gotcha: streaming requires...\"\n\nchub get openai/chat --no-annotations\n# Returns: doc content only\n```\n\n### `chub annotations list`\n\nList all annotated docs/skills.\n\n```bash\nchub annotations list\n# openai/chat     2 annotations   updated 2026-02-02\n# stripe/payments 1 annotation    updated 2026-01-28\n```\n\n### `chub annotations show <id>`\n\nShow annotations for a specific doc/skill.\n\n### `chub annotations clear <id>`\n\nRemove annotations for a doc/skill.\n\n## Files to create/modify\n\n### New: `cli/src/lib/annotations.js`\n- `getAnnotationPath(id)` — returns `~/.chub/annotations/<id>.md`\n- `readAnnotations(id)` — returns parsed annotation content or null\n- `addAnnotation(id, message, type)` — appends annotation to file\n- `listAnnotations()` — lists all annotated ids with counts\n- `clearAnnotations(id)` — removes annotation file\n\n### New: `cli/src/commands/annotate.js`\n- `chub annotate <id> <message>` command\n- `chub annotations list|show|clear` subcommands\n\n### Modify: `cli/src/commands/get.js`\n- After fetching doc/skill content, check for annotations\n- Append annotations to output unless `--no-annotations`\n\n### Modify: `cli/src/index.js`\n- Register annotate command\n- Add `annotate` to SKIP_REGISTRY (annotations are local, don't need registry)\n\n## Verification\n\n1. `chub annotate openai/chat \"streaming needs explicit close\"` — creates annotation file\n2. `chub annotate openai/chat --type tip \"batch function calls\"` — appends to file\n3. `chub annotations list` — shows openai/chat with 2 annotations\n4. `chub annotations show openai/chat` — shows both annotations\n5. `chub get openai/chat` — doc content + annotations appended\n6. `chub get openai/chat --no-annotations` — doc content only\n7. `chub annotations clear openai/chat` — removes annotation file\n"
  },
  {
    "path": "docs/features/search-ranking.md",
    "content": "# Feature: Search Ranking\n\n## Overview\n\nImprove search result ranking with a three-layer scoring model inspired by Amazon product search: term matching, description quality scoring, and source authority boosting. Future layer: agent upvote/downvote signals.\n\n## Current state\n\n`searchEntries()` in `cli/src/lib/registry.js` uses a simple scoring model:\n\n- Exact id match: +100\n- Id contains query: +50\n- Exact name match: +80\n- Name contains query: +40\n- Per query word: +10 (id), +10 (name), +5 (description), +15 (tag)\n\nAll entries are scored equally regardless of source type or description quality.\n\n## Proposed ranking model\n\n### Layer 1: Term relevance (match)\n\nReplace substring matching with BM25-style term frequency scoring across fields. Each field has a weight:\n\n| Field | Weight | Rationale |\n|---|---|---|\n| `id` | 3.0 | Exact identifier — strongest signal |\n| `name` | 2.5 | Short name, high specificity |\n| `tags` | 2.0 | Curated keywords, high intent |\n| `description` | 1.0 | Longer text, more noise |\n\nScoring per field:\n- Exact match (full field = query): field_weight * 10\n- Full query appears as substring: field_weight * 5\n- Per query term present: field_weight * 1, with IDF-like boost for rare terms (terms that appear in fewer entries score higher)\n\nThis replaces the current flat point system with weighted, field-aware scoring.\n\n### Layer 2: Description quality score\n\nA deterministic rubric computed at **build time** and stored in the registry as `_qualityScore` (0-10):\n\n| Signal | Points | How to detect |\n|---|---|---|\n| Description length > 20 chars | +2 | `description.length > 20` |\n| Description mentions specific features | +2 | Contains terms like \"streaming\", \"auth\", \"webhook\", etc. (not generic filler) |\n| Has 3+ tags | +1 | `tags.length >= 3` |\n| Has code examples in DOC.md | +2 | Frontmatter or content scan for fenced code blocks |\n| Covers multiple sections | +1 | Count of `##` headings in DOC.md |\n| Has companion files | +1 | `files.length > 1` |\n| Description word count 10-50 | +1 | Not too short, not too long |\n\nThe quality score acts as a multiplier on the relevance score: `relevance * (1 + qualityScore / 20)`. A perfect quality score (10) gives a 1.5x boost. A zero score gives no boost.\n\n### Layer 3: Source authority boost\n\nMultiplier based on who wrote the doc:\n\n| Source | Multiplier |\n|---|---|\n| `maintainer` (library author) | 1.3 |\n| `official` | 1.2 |\n| `community` | 1.0 |\n\n### Layer 4 (future): Agent votes\n\nTrack upvote/downvote signals from agents that fetch and use docs. Store as `_voteScore` in a local file (`~/.chub/votes.json`). Applied as: `score * (1 + voteScore * 0.1)`. Not implemented in v1.\n\n### Final formula\n\n```\nfinal_score = term_relevance * (1 + qualityScore / 20) * source_boost\n```\n\nAll factors are transparent and documented. No opaque numbers.\n\n## Implementation plan\n\n### 1. Add quality scoring to build (`cli/src/commands/build.js`)\n\n- After discovering each doc/skill entry, compute `_qualityScore` from the rubric\n- Store it in the registry entry (alongside `id`, `name`, `description`, etc.)\n- For docs: scan DOC.md content for code blocks, headings, companion files\n- For skills: scan SKILL.md similarly\n\n### 2. Rewrite `searchEntries()` in `cli/src/lib/registry.js`\n\n- Replace flat point system with weighted field scoring\n- Add IDF-like term rarity boost: `Math.log(totalEntries / entriesContainingTerm)`\n- Apply quality multiplier: `* (1 + (entry._qualityScore || 0) / 20)`\n- Apply source boost: `* SOURCE_BOOST[entry.source] || 1.0`\n- Keep exact-id shortcut (score 1000) so exact matches always win\n\n### 3. Show ranking signals in search output (`cli/src/commands/search.js`)\n\n- `--json` output includes `_score`, `_qualityScore`, `source` for transparency\n- Human output: no change (ranked order speaks for itself)\n- `chub search <exact-id>` detail view: show quality score and source\n\n### 4. Update sample-registry.json\n\n- Add `_qualityScore` to sample entries\n\n### 5. Rebuild test content\n\n- `chub build /tmp/chub-test-local -o /tmp/chub-build-output` — verify quality scores are computed\n- Search for various queries and verify ranking order makes sense\n\n## Files to modify\n\n- `cli/src/commands/build.js` — add quality scoring after discovery\n- `cli/src/lib/registry.js` — rewrite `searchEntries()`\n- `cli/src/commands/search.js` — show quality score in detail view\n- `sample-registry.json` — add `_qualityScore` fields\n\n## Verification\n\n1. `chub build /tmp/chub-test-local -o /tmp/chub-build-output` — registry entries have `_qualityScore`\n2. `chub search \"api\"` — results ranked by relevance * quality * source boost\n3. `chub search \"api\" --json` — JSON includes `_score`, `_qualityScore`\n4. `chub search \"internal-api\"` — exact id match still wins\n5. A maintainer doc with good description ranks above a community doc with vague description for the same query\n"
  },
  {
    "path": "docs/feedback-and-annotations.md",
    "content": "# Feedback and Annotations\n\nContext Hub has two mechanisms for agents to improve over time: **annotations** (local, for your agent) and **feedback** (about the overall quality of the docs with pre-labels).\n\n## Annotations\n\nAnnotations are local notes that agents attach to docs or skills. They persist across sessions and appear automatically on future `chub get` calls.\n\n### Why annotate?\n\nWhen an agent uses a doc to complete a task, it sometimes discovers things that aren't in the doc itself — environment-specific gotchas, version quirks, project-specific context. Without annotations, that knowledge is lost when the session ends. The agent makes the same discovery again next time.\n\nAnnotations close this gap. The agent saves what it learned, and next time it fetches the same doc, the note is right there.\n\n### Usage\n\n```bash\n# Set an annotation\nchub annotate stripe/api \"Webhook verification requires raw body — do not parse JSON before verifying\"\n\n# View current annotation\nchub annotate stripe/api\n\n# Replace with a new note\nchub annotate stripe/api \"Updated: use the v2 webhook endpoint for new integrations\"\n\n# Remove an annotation\nchub annotate stripe/api --clear\n\n# List all annotations\nchub annotate --list\n```\n\n### How annotations appear\n\nWhen an annotation exists, `chub get` appends it after the doc content:\n\n```\n# Stripe API\n...doc content...\n\n---\n[Agent note — 2025-01-15T10:30:00Z]\nWebhook verification requires raw body — do not parse JSON before verifying\n```\n\nWith `--json`, the annotation is included in the response:\n\n```json\n{\n  \"id\": \"stripe/api\",\n  \"type\": \"doc\",\n  \"content\": \"...\",\n  \"annotation\": {\n    \"id\": \"stripe/api\",\n    \"note\": \"Webhook verification requires raw body...\",\n    \"updatedAt\": \"2025-01-15T10:30:00.000Z\"\n  }\n}\n```\n\n### What to annotate\n\nGood annotations capture knowledge that isn't obvious from the doc:\n\n- **Environment-specific gotchas** — \"Requires raw body for webhook verification\"\n- **Version-specific notes** — \"v3 API requires different auth header format\"\n- **Project-specific context** — \"We use the batch endpoint, not individual calls\"\n- **Error resolutions** — \"Rate limit errors need exponential backoff with jitter\"\n\nDon't annotate information that's already clearly stated in the doc.\n\n### Storage\n\nAnnotations are stored locally at `~/.chub/annotations/` as JSON files. They are specific to your machine and are not shared or synced. Each entry gets one annotation — setting a new note replaces the previous one.\n\n## Feedback\n\nFeedback helps maintainers understand what's working and what needs improvement.\n\n### Usage\n\n```bash\n# Simple up/down rating\nchub feedback stripe/api up\nchub feedback stripe/api down\n\n# With labels for specific issues\nchub feedback openai/chat down --label outdated --label wrong-examples\n\n# Target a specific file within a doc\nchub feedback acme/widgets down --file references/advanced.md --label incomplete\n\n# Include agent context\nchub feedback stripe/api up --agent \"claude-code\" --model \"claude-sonnet-4\"\n```\n\n### Labels\n\nLabels help authors pinpoint specific issues:\n\n**Positive:** `accurate`, `well-structured`, `helpful`, `good-examples`\n\n**Negative:** `outdated`, `inaccurate`, `incomplete`, `wrong-examples`, `wrong-version`, `poorly-structured`\n\n### Disabling Feedback\n\n```yaml\n# ~/.chub/config.yaml\nfeedback: false\n```\n\nOr via environment variable: `CHUB_FEEDBACK=0`. Check status with `chub feedback --status`.\n\n## Annotations vs Feedback\n\n| | Annotations | Feedback |\n|---|---|---|\n| **For whom** | Your agent, locally | Doc authors, via registry |\n| **Persists** | On your machine | In the registry |\n| **Purpose** | Don't repeat mistakes | Improve the content |\n| **Visible to** | You only | Maintainers |\n| **Effect** | Shows on future fetches | Authors update the doc |\n\nBoth matter. Annotations help your agent today. Feedback helps everyone tomorrow.\n"
  },
  {
    "path": "docs/private-content.md",
    "content": "# Private Content Repo\n\n> **Coming Soon**\n\n## The Problem\n\nTeams have internal documentation that agents need: private API references, deployment playbooks, coding conventions, auth patterns. This content doesn't belong in a public registry, but agents should be able to search and fetch it just as easily as public docs.\n\nToday, you can build local content with `chub build` and point your config at it. But distributing that content across a team — keeping it in sync, versioned, and accessible to every developer's agent — is a manual process.\n\nWe're working on making private content repos easy to set up, distribute, and keep current across your team.\n\n## What we're solving for\n\n- **Team-wide conventions** — Every agent on your team should follow the same patterns. Write them once, distribute everywhere.\n- **Internal API docs** — Your private APIs need the same quality docs as public ones. Agents shouldn't have to guess.\n- **Seamless search** — `chub search` should cover both public and private content without extra steps.\n- **Easy distribution** — Adding a new team member's agent to the private repo should be simple.\n\n## Enterprise\n\nFor enterprise use cases, reach out at info@tbd-domain.com.\n"
  },
  {
    "path": "llms.txt",
    "content": "# Context Hub (chub)\n\n> CLI tool for searching and fetching LLM-optimized documentation and skills. Install: npm install -g @aisuite/chub\n\n## Content Types\n\n- doc: API/SDK reference documentation. Versioned, language-specific. Entry file: DOC.md\n- skill: Task recipes, automation patterns, coding playbooks. Standalone. Entry file: SKILL.md\n\n## Commands\n\n### chub search [query]\nSearch docs and skills. No query lists all entries.\n\nFlags:\n  --tags <csv>        Filter by tags (comma-separated)\n  --json              JSON output with { total, results[] }\n\nExamples:\n  chub search                         # list everything\n  chub search \"stripe\"                # fuzzy search by name/description\n  chub search stripe/payments         # exact id returns full detail\n  chub search --tags automation       # filter by tag\n\n### chub get <ids...>\nFetch one or more docs or skills by ID. Auto-detects type (doc vs skill). Auto-infers language when only one is available.\n\nFlags:\n  --lang <language>   Language variant (js, py, ts, etc.)\n  --version <version> Specific doc version\n  --full              Fetch all files, not just the entry point\n  --file <paths>      Fetch specific file(s) by path (comma-separated)\n  -o, --output <path> Write to file or directory\n  --json              JSON output with { id, type, content, path, additionalFiles?, annotation? }\n\nExamples:\n  chub get stripe/api                           # single doc (auto-infers lang if only one)\n  chub get openai/chat-api --lang py            # specific language\n  chub get pw-community/login-flows             # fetch a skill\n  chub get stripe/api openai/chat-api           # multiple entries\n  chub get acme/widgets --file references/advanced.md   # specific reference file\n  chub get acme/widgets --full                  # all files\n  chub get stripe/api -o .context/stripe.md     # save to file\n\nBehavior:\n  - When additional reference files exist beyond the entry point, output includes a footer listing them\n  - Use --file to fetch specific reference files without fetching everything\n  - If an annotation exists for the entry, it is appended after the content\n\n### chub annotate [id] [note]\nAttach persistent notes to a doc or skill. Notes appear on future `chub get` calls.\n\nFlags:\n  --clear             Remove annotation for this entry\n  --list              List all annotations\n  --json              JSON output\n\nExamples:\n  chub annotate stripe/api \"Use idempotency keys for POST requests\"   # set note\n  chub annotate stripe/api                     # view current note\n  chub annotate stripe/api \"Updated note\"      # replaces previous note\n  chub annotate stripe/api --clear             # remove note\n  chub annotate --list                         # list all annotations\n\nStorage: ~/.chub/annotations/ (local, per-machine)\n\n### chub feedback [id] [rating] [comment]\nRate a doc or skill (up/down). Sent to the registry for maintainers.\n\nFlags:\n  --label <label>     Feedback label (repeatable). Valid: accurate, well-structured, helpful, good-examples, outdated, inaccurate, incomplete, wrong-examples, wrong-version, poorly-structured\n  --lang <language>   Language variant\n  --file <file>       Specific file within the entry\n  --agent <name>      AI tool name\n  --model <model>     LLM model name\n  --status            Show telemetry status\n  --json              JSON output\n\nExamples:\n  chub feedback stripe/api up \"Clear examples\"\n  chub feedback openai/chat down --label outdated --label wrong-examples\n\n### chub update\nDownload or refresh the cached registry.\n\n### chub cache status|clear\nManage the local cache. `status` shows cache info, `clear` removes cached content.\n\n### chub build <content-dir>\nBuild a registry from a local content directory.\n\nFlags:\n  -o, --output <path>     Output directory (default: <content-dir>/dist)\n  --base-url <url>        Base URL for remote serving\n  --validate-only         Validate without building\n  --json                  JSON output\n\n## Agent Workflow\n\nRecommended pattern for AI agents using Context Hub:\n\n1. SEARCH: Find relevant documentation\n   chub search \"stripe payments\" --json | jq -r '.results[0].id'\n\n2. FETCH: Get the documentation\n   chub get stripe/api --lang js\n\n3. USE: Read the content, write code based on it\n\n4. ANNOTATE: Record what you learned for future sessions\n   chub annotate stripe/api \"Webhook verification requires raw body, not parsed JSON\"\n\n5. NEXT SESSION: Fetch again — your annotation appears automatically\n   chub get stripe/api --lang js\n   # Content is followed by your previous annotation\n\nThis loop means agents improve over time. Annotations persist across sessions.\n\n## Annotation Best Practices\n\nAfter using a doc to complete a task, annotate what you learned that wasn't obvious from the doc itself:\n- Environment-specific gotchas (\"requires raw body for webhook verification\")\n- Version-specific notes (\"v3 API requires different auth header format\")\n- Project-specific context (\"we use the batch endpoint, not individual calls\")\n- Error resolutions (\"rate limit errors need exponential backoff with jitter\")\n\nDo NOT annotate information that's already clearly stated in the doc.\n\n## Piping Patterns\n\n# Search, pick first result, fetch\nID=$(chub search \"stripe\" --json | jq -r '.results[0].id')\nchub get \"$ID\" --lang js -o .context/stripe.md\n\n# Fetch multiple docs at once\nchub get openai/chat stripe/api -o .context/\n\n# Check what additional files are available\nchub get acme/widgets --json | jq '.additionalFiles'\n\n# Fetch a specific reference file\nchub get acme/widgets --file references/advanced.md\n\n# List all your annotations\nchub annotate --list --json\n\n## Key Behaviors\n\n- Auto-detect type: `chub get` works for both docs and skills. No need to specify type.\n- Auto-infer language: If a doc has only one language variant, --lang is not required.\n- Multi-language prompt: If a doc has multiple languages and --lang is not specified, the CLI lists available languages.\n- Incremental fetch: Default fetch returns only the entry file. A footer lists additional reference files. Use --file for selective fetch, --full for everything.\n- Annotations on fetch: If an annotation exists for an entry, it appears at the end of `chub get` output in both human and JSON modes.\n- Multi-source: Config supports multiple sources (URLs and local paths). On ID collision, prefix with source name: `chub get internal:openai/chat`.\n- JSON everywhere: All commands support --json for structured output.\n\n## Configuration\n\nFile: ~/.chub/config.yaml\n\nsources:\n  - name: community\n    url: https://cdn.aichub.org/v1\n  - name: internal\n    path: /path/to/local/docs\n\nsource: \"official,maintainer,community\"   # trust policy\nrefresh_interval: 86400                   # cache TTL in seconds\ntelemetry: true                           # anonymous analytics (opt out: false or CHUB_TELEMETRY=0)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"context-hub\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"workspaces\": [\n    \"cli\"\n  ]\n}\n"
  }
]